From 67cf906bedfa4446c25afbd204dc6accb935c0ff Mon Sep 17 00:00:00 2001 From: Niels Weber Date: Mon, 12 Sep 2022 08:52:23 +0000 Subject: [PATCH 0001/1447] Initial empty repository From e3e8edada42007af4b783641f4ff5551f06ebd2e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Sep 2022 13:42:26 +0200 Subject: [PATCH 0002/1447] Initial commit Change-Id: I90b3bb6f443fffd69f50428b0059f1a1773c4038 Reviewed-by: hjk --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000000..df44f43aeb3 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ + +# QtCreator/Axivion Integration Plug-in + +This plug-in integrates Axivion Tools handling into Qt Creator. + +This plug-in is only available as part of the commercial Qt offering. + From 433a7c4c7e15634a53e2701b5aa57234b0b7d5ff Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 28 Nov 2022 09:48:11 +0100 Subject: [PATCH 0003/1447] Initial plugin skeleton Change-Id: Ibb2c950d07280479ec3e00b7b9abef872d6ed131 Reviewed-by: hjk --- plugins/axivion/Axivion.json.in | 17 ++++ plugins/axivion/CMakeLists.txt | 21 +++++ plugins/axivion/axivion.qbs | 25 ++++++ plugins/axivion/axivion.qrc | 6 ++ plugins/axivion/axivionoutputpane.cpp | 107 ++++++++++++++++++++++++ plugins/axivion/axivionoutputpane.h | 55 ++++++++++++ plugins/axivion/axivionplugin.cpp | 64 ++++++++++++++ plugins/axivion/axivionplugin.h | 42 ++++++++++ plugins/axivion/axivionsettings.cpp | 41 +++++++++ plugins/axivion/axivionsettings.h | 35 ++++++++ plugins/axivion/axivionsettingspage.cpp | 69 +++++++++++++++ plugins/axivion/axivionsettingspage.h | 40 +++++++++ plugins/axivion/axiviontr.h | 30 +++++++ plugins/axivion/images/axivion.png | Bin 0 -> 293 bytes plugins/axivion/images/axivion@2x.png | Bin 0 -> 545 bytes 15 files changed, 552 insertions(+) create mode 100644 plugins/axivion/Axivion.json.in create mode 100644 plugins/axivion/CMakeLists.txt create mode 100644 plugins/axivion/axivion.qbs create mode 100644 plugins/axivion/axivion.qrc create mode 100644 plugins/axivion/axivionoutputpane.cpp create mode 100644 plugins/axivion/axivionoutputpane.h create mode 100644 plugins/axivion/axivionplugin.cpp create mode 100644 plugins/axivion/axivionplugin.h create mode 100644 plugins/axivion/axivionsettings.cpp create mode 100644 plugins/axivion/axivionsettings.h create mode 100644 plugins/axivion/axivionsettingspage.cpp create mode 100644 plugins/axivion/axivionsettingspage.h create mode 100644 plugins/axivion/axiviontr.h create mode 100644 plugins/axivion/images/axivion.png create mode 100644 plugins/axivion/images/axivion@2x.png diff --git a/plugins/axivion/Axivion.json.in b/plugins/axivion/Axivion.json.in new file mode 100644 index 00000000000..7f28cffd1d5 --- /dev/null +++ b/plugins/axivion/Axivion.json.in @@ -0,0 +1,17 @@ +{ + \"Name\" : \"Axivion\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"Revision\" : \"$$QTC_PLUGIN_REVISION\", + \"Experimental\" : true, + \"Vendor\" : \"The Qt Company Ltd\", + \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Enterprise licenses may use this plugin in accordance with the Qt Enterprise License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\" + ], + \"Category\" : \"Code Analyzer\", + \"Description\" : \"Integration of the axivion dashboard.\", + \"Url\" : \"http://www.qt-project.org\", + $$dependencyList +} diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt new file mode 100644 index 00000000000..3f1633251f5 --- /dev/null +++ b/plugins/axivion/CMakeLists.txt @@ -0,0 +1,21 @@ +find_package(QtCreator COMPONENTS Core REQUIRED) +find_package(Qt5 COMPONENTS Network Widgets REQUIRED) + +find_package(QtCreatorLicenseChecker QUIET) +if (TARGET QtCreator::LicenseChecker) + set(LICENSECHECKER_DEPENDS QtCreator::LicenseChecker) +endif() + +add_qtc_plugin(Axivion + PLUGIN_DEPENDS + QtCreator::Core QtCreator::ProjectExplorer + ${LICENSECHECKER_DEPENDS} + DEPENDS Qt5::Network Qt5::Widgets QtCreator::ExtensionSystem QtCreator::Utils + SOURCES + axivion.qrc + axivionoutputpane.cpp axivionoutputpane.h + axivionplugin.cpp axivionplugin.h + axivionsettings.cpp axivionsettings.h + axivionsettingspage.cpp axivionsettingspage.h + axiviontr.h +) diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs new file mode 100644 index 00000000000..d73031f89b0 --- /dev/null +++ b/plugins/axivion/axivion.qbs @@ -0,0 +1,25 @@ +import qbs + +QtcCommercialPlugin { + name: "Axivion" + + Depends { name: "Core" } + Depends { name: "ProjectExplorer" } + Depends { name: "ExtensionSystem" } + Depends { name: "Utils" } + Depends { name: "Qt.widgets" } + Depends { name: "Qt.network" } + + files: [ + "axivion.qrc", + "axivionoutputpane.cpp", + "axivionoutputpane.h", + "axivionplugin.cpp", + "axivionplugin.h", + "axivionsettings.cpp", + "axivionsettings.h", + "axivionsettingspage.cpp", + "axivionsettingspage.h", + "axiviontr.h", + ] +} diff --git a/plugins/axivion/axivion.qrc b/plugins/axivion/axivion.qrc new file mode 100644 index 00000000000..13d0b616c91 --- /dev/null +++ b/plugins/axivion/axivion.qrc @@ -0,0 +1,6 @@ + + + images/axivion.png + images/axivion@2x.png + + diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp new file mode 100644 index 00000000000..4bc51cefbe4 --- /dev/null +++ b/plugins/axivion/axivionoutputpane.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionoutputpane.h" + +#include "axiviontr.h" + +#include + +#include + +namespace Axivion::Internal { + +AxivionOutputPane::AxivionOutputPane(QObject *parent) + : Core::IOutputPane(parent) +{ + m_outputWidget = new QStackedWidget; +} + +AxivionOutputPane::~AxivionOutputPane() +{ + if (!m_outputWidget->parent()) + delete m_outputWidget; +} + +QWidget *AxivionOutputPane::outputWidget(QWidget *parent) +{ + if (m_outputWidget) + m_outputWidget->setParent(parent); + else + QTC_CHECK(false); + return m_outputWidget; +} + +QList AxivionOutputPane::toolBarWidgets() const +{ + QList buttons; + return buttons; +} + +QString AxivionOutputPane::displayName() const +{ + return Tr::tr("Axivion"); +} + +int AxivionOutputPane::priorityInStatusBar() const +{ + return -1; +} + +void AxivionOutputPane::clearContents() +{ +} + +void AxivionOutputPane::setFocus() +{ +} + +bool AxivionOutputPane::hasFocus() const +{ + return false; +} + +bool AxivionOutputPane::canFocus() const +{ + return true; +} + +bool AxivionOutputPane::canNavigate() const +{ + return true; +} + +bool AxivionOutputPane::canNext() const +{ + return false; +} + +bool AxivionOutputPane::canPrevious() const +{ + return false; +} + +void AxivionOutputPane::goToNext() +{ +} + +void AxivionOutputPane::goToPrev() +{ +} + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h new file mode 100644 index 00000000000..352a885e205 --- /dev/null +++ b/plugins/axivion/axivionoutputpane.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +QT_BEGIN_NAMESPACE +class QStackedWidget; +QT_END_NAMESPACE + +namespace Axivion::Internal { + +class AxivionOutputPane : public Core::IOutputPane +{ + Q_OBJECT +public: + explicit AxivionOutputPane(QObject *parent = nullptr); + ~AxivionOutputPane(); + + // IOutputPane interface + QWidget *outputWidget(QWidget *parent) override; + QList toolBarWidgets() const override; + QString displayName() const override; + int priorityInStatusBar() const override; + void clearContents() override; + void setFocus() override; + bool hasFocus() const override; + bool canFocus() const override; + bool canNavigate() const override; + bool canNext() const override; + bool canPrevious() const override; + void goToNext() override; + void goToPrev() override; + +private: + QStackedWidget *m_outputWidget = nullptr; +}; + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp new file mode 100644 index 00000000000..d11e39ef303 --- /dev/null +++ b/plugins/axivion/axivionplugin.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionplugin.h" + +#include "axivionoutputpane.h" +#include "axivionsettings.h" +#include "axivionsettingspage.h" + + +#ifdef LICENSECHECKER +# include +#endif + +#include + +namespace Axivion::Internal { + +class AxivionPluginPrivate +{ +public: + AxivionSettings axivionSettings; + AxivionSettingsPage axivionSettingsPage{&axivionSettings}; + AxivionOutputPane axivionOutputPane; +}; + +AxivionPlugin::~AxivionPlugin() +{ + delete d; +} + +bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessage) +{ + Q_UNUSED(arguments) + Q_UNUSED(errorMessage) + +#ifdef LICENSECHECKER + LicenseChecker::LicenseCheckerPlugin *licenseChecker + = ExtensionSystem::PluginManager::getObject(); + + if (!licenseChecker || !licenseChecker->hasValidLicense() || !licenseChecker->enterpriseFeatures()) + return true; +#endif // LICENSECHECKER + + d = new AxivionPluginPrivate; + return true; +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h new file mode 100644 index 00000000000..6fec8944695 --- /dev/null +++ b/plugins/axivion/axivionplugin.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +namespace Axivion::Internal { + +class AxivionPlugin final : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Axivion.json") + +public: + AxivionPlugin() = default; + ~AxivionPlugin() final; + +private: + bool initialize(const QStringList &arguments, QString *errorMessage) final; + void extensionsInitialized() final {} + + class AxivionPluginPrivate *d = nullptr; +}; + +} // namespace Axivion::Internal + diff --git a/plugins/axivion/axivionsettings.cpp b/plugins/axivion/axivionsettings.cpp new file mode 100644 index 00000000000..56fe191561d --- /dev/null +++ b/plugins/axivion/axivionsettings.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionsettings.h" + +#include + +namespace Axivion::Internal { + +AxivionSettings::AxivionSettings() +{ +} + +void AxivionSettings::toSettings(QSettings *s) const +{ + s->beginGroup("Axivion"); + s->endGroup(); +} + +void AxivionSettings::fromSettings(QSettings *s) +{ + s->beginGroup("Axivion"); + s->endGroup(); +} + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionsettings.h b/plugins/axivion/axivionsettings.h new file mode 100644 index 00000000000..e4a63a66d3c --- /dev/null +++ b/plugins/axivion/axivionsettings.h @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +QT_BEGIN_NAMESPACE +class QSettings; +QT_END_NAMESPACE + +namespace Axivion::Internal { + +class AxivionSettings +{ +public: + AxivionSettings(); + void toSettings(QSettings *s) const; + void fromSettings(QSettings *s); +}; + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp new file mode 100644 index 00000000000..5f2cec3d13f --- /dev/null +++ b/plugins/axivion/axivionsettingspage.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionsettingspage.h" + +#include "axivionsettings.h" +#include "axiviontr.h" + +#include +#include + +#include +#include + +namespace Axivion::Internal { + +class AxivionSettingsWidget : public Core::IOptionsPageWidget +{ +public: + explicit AxivionSettingsWidget(AxivionSettings *settings); + + void apply() override; +private: + AxivionSettings *m_settings; +}; + +AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) + : m_settings(settings) +{ + using namespace Utils::Layouting; + + auto label = new QLabel(Tr::tr("...Placeholder...")); + Row { + Column { label, st } + }.attachTo(this); +} + +void AxivionSettingsWidget::apply() +{ + // set m_settings from widget + m_settings->toSettings(Core::ICore::settings()); +} + +AxivionSettingsPage::AxivionSettingsPage(AxivionSettings *settings) +{ + setId("Axivion.Settings.General"); + setDisplayName(Tr::tr("General")); + setCategory("XY.Axivion"); + setDisplayCategory(Tr::tr("Axivion")); + setCategoryIconPath(":/axivion/images/axivion.png"); + setWidgetCreator([this] { return new AxivionSettingsWidget(m_settings); }); +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h new file mode 100644 index 00000000000..64c0c01f9eb --- /dev/null +++ b/plugins/axivion/axivionsettingspage.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +#include + +namespace Axivion::Internal { + +class AxivionSettings; +class AxivionSettingsWidget; + +class AxivionSettingsPage : public Core::IOptionsPage +{ + Q_OBJECT +public: + explicit AxivionSettingsPage(AxivionSettings *settings); + +private: + AxivionSettings *m_settings; +}; + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axiviontr.h b/plugins/axivion/axiviontr.h new file mode 100644 index 00000000000..062dd6b9598 --- /dev/null +++ b/plugins/axivion/axiviontr.h @@ -0,0 +1,30 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +namespace Axivion { + +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(Axivion) +}; + +} // namespace Axivion diff --git a/plugins/axivion/images/axivion.png b/plugins/axivion/images/axivion.png new file mode 100644 index 0000000000000000000000000000000000000000..647f5972ce24886687e9e9f0bbbdc345e2c282d1 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4h9AWhNCh`Dhvz^Z#-QbLo_BHy|~wlIZ))t z$KOrqyl>2!T60(Jv}=mhNxI+_kW=FNXqmyf&K&}OG)%NIl*KaNnD7e(2*1DoNX#rM z{nSs<;s+N0I%gaE=x>Yqy`Eunpw9k$=DzK_X5Mt-+&p)xb;E?$0>_iX*1t1fW7a18 zQ?X@R$ioDaM*q!r7pBU$DX;t`>;I-fWA-J>2QzZ?)u+vT%CKF4zZCi6M114n+qV{EsZDeCf90(4M8D8xNm^Q(WxVcJ w2B(FLe8--?yLY+pBagiK$8R5u{=5I3D}Pu0TU>UIl^w|cp00i_>zopr0Dy#k1ONa4 literal 0 HcmV?d00001 diff --git a/plugins/axivion/images/axivion@2x.png b/plugins/axivion/images/axivion@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..15bac95f52ccb37024001078617d7ccb8d117928 GIT binary patch literal 545 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4h9AWhN8@6(F_cXFFaiwLp(a)PKnfK4istl z&Aznk`9@%eve?RS+ic4UHhTFP5rgsj$ zI#uh|z^DAc{?Q(}BUd&jO)ZIDma6|SRk`PwNsaLrfydKb`THAdU%UBhus9fL@lSl; z^O>`_!ucTYriZtg7q@?0)4|ecRk(P?i8g^XH{PcHQCiU?cQk(6ek+YO_h-5fE7w>Z zXSw_-*3XsUmVd>WW)&F`t>y_V3lh8MGkfmPzfdO@@%YGYW$wEiS9#ASrKnCZIi$Vn z#&WW^$d8@J8qL;oXWY{K6-jQw}XT+I&%6k}vzc zyv5^5Et=<=4X*8U@LATnH~XT;E?pnvy0*X5d4eSzPJ{;Ee{gonw$iqb!hcS(S Date: Wed, 30 Nov 2022 12:05:53 +0100 Subject: [PATCH 0004/1447] Tweak cmake files Preparation for integration into super repository. Change-Id: I9e932466a63d4ea4943dae147a0a928918fb6c96 Reviewed-by: hjk --- CMakeLists.txt | 11 +++++++++++ plugins/axivion/CMakeLists.txt | 1 + 2 files changed, 12 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000000..7a3dd57ae3c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.16) + +project(Axivion) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_CXX_STANDARD 17) + +add_subdirectory(plugins/axivion) + diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 3f1633251f5..c5dd9dcf6f3 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -7,6 +7,7 @@ if (TARGET QtCreator::LicenseChecker) endif() add_qtc_plugin(Axivion + BUILD_DEFAULT OFF PLUGIN_DEPENDS QtCreator::Core QtCreator::ProjectExplorer ${LICENSECHECKER_DEPENDS} From 37a4aceaded4702a9c14f44edb6a5042971d4be5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 7 Dec 2022 12:04:05 +0100 Subject: [PATCH 0005/1447] Build plugin with cmake also by default Partially reverts bba09b7152. Change-Id: I781569340a97160eeaffb544de33123cecc041d1 Reviewed-by: hjk --- plugins/axivion/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index c5dd9dcf6f3..3f1633251f5 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -7,7 +7,6 @@ if (TARGET QtCreator::LicenseChecker) endif() add_qtc_plugin(Axivion - BUILD_DEFAULT OFF PLUGIN_DEPENDS QtCreator::Core QtCreator::ProjectExplorer ${LICENSECHECKER_DEPENDS} From 0cb28bb969598e20a924972b1282eead168eb737 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 8 Dec 2022 08:25:49 +0100 Subject: [PATCH 0006/1447] Fix compile on Linux Change-Id: I1971951d64cc971c8b4cf9a480e3f705eee0d33f Reviewed-by: David Schulz --- plugins/axivion/axivionsettings.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/axivion/axivionsettings.h b/plugins/axivion/axivionsettings.h index e4a63a66d3c..bfd4315de4f 100644 --- a/plugins/axivion/axivionsettings.h +++ b/plugins/axivion/axivionsettings.h @@ -18,6 +18,8 @@ #pragma once +#include + QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE From 5a468556d7a3c9b03890c97b63d44cd05564d170 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 8 Dec 2022 08:32:22 +0100 Subject: [PATCH 0007/1447] Fix passing settings Change-Id: I6473138391f6e7c44f2815049649300df828add7 Reviewed-by: David Schulz --- plugins/axivion/axivionsettingspage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index 5f2cec3d13f..aa9269392a4 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -57,6 +57,7 @@ void AxivionSettingsWidget::apply() } AxivionSettingsPage::AxivionSettingsPage(AxivionSettings *settings) + : m_settings(settings) { setId("Axivion.Settings.General"); setDisplayName(Tr::tr("General")); From ffc9eff670b4dc30c251a6280bc861f471f3bc3f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 12 Dec 2022 16:45:31 +0100 Subject: [PATCH 0008/1447] Provide minimal settings to work with Change-Id: I73d09612ac2bb66c4f359ecfffc01650d56359ee Reviewed-by: David Schulz Reviewed-by: hjk --- plugins/axivion/axivionoutputpane.cpp | 21 +-- plugins/axivion/axivionoutputpane.h | 21 +-- plugins/axivion/axivionplugin.cpp | 24 +--- plugins/axivion/axivionplugin.h | 21 +-- plugins/axivion/axivionsettings.cpp | 126 ++++++++++++++--- plugins/axivion/axivionsettings.h | 50 ++++--- plugins/axivion/axivionsettingspage.cpp | 181 +++++++++++++++++++++--- plugins/axivion/axivionsettingspage.h | 49 ++++--- plugins/axivion/axiviontr.h | 21 +-- 9 files changed, 346 insertions(+), 168 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index 4bc51cefbe4..d7896e02d0f 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionoutputpane.h" @@ -104,4 +89,4 @@ void AxivionOutputPane::goToPrev() { } -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h index 352a885e205..63ec48097ec 100644 --- a/plugins/axivion/axivionoutputpane.h +++ b/plugins/axivion/axivionoutputpane.h @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once @@ -52,4 +37,4 @@ private: QStackedWidget *m_outputWidget = nullptr; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index d11e39ef303..639ff50b465 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionplugin.h" @@ -22,13 +7,13 @@ #include "axivionsettings.h" #include "axivionsettingspage.h" +#include +#include #ifdef LICENSECHECKER # include #endif -#include - namespace Axivion::Internal { class AxivionPluginPrivate @@ -58,6 +43,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa #endif // LICENSECHECKER d = new AxivionPluginPrivate; + d->axivionSettings.fromSettings(Core::ICore::settings()); return true; } diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index 6fec8944695..f22f2823e19 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once @@ -38,5 +23,5 @@ private: class AxivionPluginPrivate *d = nullptr; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettings.cpp b/plugins/axivion/axivionsettings.cpp index 56fe191561d..2f827f9e750 100644 --- a/plugins/axivion/axivionsettings.cpp +++ b/plugins/axivion/axivionsettings.cpp @@ -1,41 +1,131 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionsettings.h" +#include + +#include +#include #include +#include namespace Axivion::Internal { +const char curlKeyC[] = "Curl"; + +AxivionServer::AxivionServer(const Utils::Id &id, const QString &dashboard, + const QString &description, const QString &token) + : id(id) + , dashboard(dashboard) + , description(description) + , token(token) +{ +} + +bool AxivionServer::operator==(const AxivionServer &other) const +{ + return id == other.id && dashboard == other.dashboard + && description == other.description && token == other.token; +} + +bool AxivionServer::operator!=(const AxivionServer &other) const +{ + return !(*this == other); +} + +QJsonObject AxivionServer::toJson() const +{ + QJsonObject result; + result.insert("id", id.toString()); + result.insert("dashboard", dashboard); + result.insert("description", description); + result.insert("token", token); + return result; +} + +AxivionServer AxivionServer::fromJson(const QJsonObject &json) +{ + const AxivionServer invalidServer; + const QJsonValue id = json.value("id"); + if (id == QJsonValue::Undefined) + return invalidServer; + const QJsonValue dashboard = json.value("dashboard"); + if (dashboard == QJsonValue::Undefined) + return invalidServer; + const QJsonValue description = json.value("description"); + if (description == QJsonValue::Undefined) + return invalidServer; + const QJsonValue token = json.value("token"); + if (token == QJsonValue::Undefined) + return invalidServer; + return { Utils::Id::fromString(id.toString()), dashboard.toString(), + description.toString(), token.toString() }; +} + +QStringList AxivionServer::curlArguments() const +{ + QStringList args { "-sS" }; // silent, but show error + if (dashboard.startsWith("https://") && !validateCert) + args << "-k"; + return args; +} + AxivionSettings::AxivionSettings() { } +static Utils::FilePath tokensFilePath(const QSettings *s) +{ + return Utils::FilePath::fromString(s->fileName()).parentDir() + .pathAppended("qtcreator/axivion.json"); +} + +static void writeTokenFile(const Utils::FilePath &filePath, const AxivionServer &server) +{ + QJsonDocument doc; + doc.setObject(server.toJson()); + // FIXME error handling? + filePath.writeFileContents(doc.toJson()); + filePath.setPermissions(QFile::ReadUser | QFile::WriteUser); +} + +static AxivionServer readTokenFile(const Utils::FilePath &filePath) +{ + if (!filePath.exists()) + return {}; + Utils::expected_str contents = filePath.fileContents(); + if (!contents) + return {}; + const QJsonDocument doc = QJsonDocument::fromJson(*contents); + if (!doc.isObject()) + return {}; + return AxivionServer::fromJson(doc.object()); +} + void AxivionSettings::toSettings(QSettings *s) const { + writeTokenFile(tokensFilePath(s), server); + s->beginGroup("Axivion"); + s->setValue(curlKeyC, curl.toVariant()); s->endGroup(); } void AxivionSettings::fromSettings(QSettings *s) { s->beginGroup("Axivion"); + curl = Utils::FilePath::fromVariant(curlKeyC); s->endGroup(); + + server = readTokenFile(tokensFilePath(s)); + + if (curl.isEmpty() || !curl.exists()) { + const QString curlPath = QStandardPaths::findExecutable( + Utils::HostOsInfo::withExecutableSuffix("curl")); + if (!curlPath.isEmpty()) + curl = Utils::FilePath::fromString(curlPath); + } } -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettings.h b/plugins/axivion/axivionsettings.h index bfd4315de4f..20763bee9ee 100644 --- a/plugins/axivion/axivionsettings.h +++ b/plugins/axivion/axivionsettings.h @@ -1,37 +1,51 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once +#include +#include + #include QT_BEGIN_NAMESPACE +class QJsonObject; class QSettings; QT_END_NAMESPACE namespace Axivion::Internal { +class AxivionServer +{ +public: + AxivionServer() = default; + AxivionServer(const Utils::Id &id, const QString &dashboardUrl, + const QString &description, const QString &token); + + bool operator==(const AxivionServer &other) const; + bool operator!=(const AxivionServer &other) const; + + QJsonObject toJson() const; + static AxivionServer fromJson(const QJsonObject &json); + QStringList curlArguments() const; + + Utils::Id id; + QString dashboard; + QString description; + QString token; + + bool validateCert = true; +}; + class AxivionSettings { public: AxivionSettings(); void toSettings(QSettings *s) const; void fromSettings(QSettings *s); + + AxivionServer server; // shall we have more than one? + Utils::FilePath curl; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index aa9269392a4..ffe5122442e 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionsettingspage.h" @@ -23,12 +8,115 @@ #include #include +#include +#include +#include #include -#include +#include +#include +#include +#include + +using namespace Utils; namespace Axivion::Internal { +// may allow some invalid, but does some minimal check for legality +static bool hostValid(const QString &host) +{ + static const QRegularExpression ip(R"(^(\d+).(\d+).(\d+).(\d+)$)"); + static const QRegularExpression dn(R"(^([a-zA-Z0-9][a-zA-Z0-9-]+\.)+[a-zA-Z0-9][a-zA-Z0-9-]+$)"); + const QRegularExpressionMatch match = ip.match(host); + if (match.hasMatch()) { + for (int i = 1; i < 5; ++i) { + int val = match.captured(i).toInt(); + if (val < 0 || val > 255) + return false; + } + return true; + } + return (host == "localhost") || dn.match(host).hasMatch(); +} + +static bool isUrlValid(const QString &in) +{ + const QUrl url(in); + return hostValid(url.host()) && url.scheme() == "https" || url.scheme() == "http"; +} + +DashboardWidget::DashboardWidget(Mode mode, QWidget *parent) + : QWidget(parent) + , m_mode(mode) +{ + auto labelStyle = mode == Display ? StringAspect::LabelDisplay : StringAspect::LineEditDisplay; + m_dashboardUrl.setLabelText(Tr::tr("Dashboard URL:")); + m_dashboardUrl.setDisplayStyle(labelStyle); + m_dashboardUrl.setValidationFunction([](FancyLineEdit *edit, QString *){ + return isUrlValid(edit->text()); + }); + m_description.setLabelText(Tr::tr("Description:")); + m_description.setDisplayStyle(labelStyle); + m_description.setPlaceHolderText(Tr::tr("Non-empty description")); + + m_token.setLabelText(Tr::tr("Access token:")); + m_token.setDisplayStyle(labelStyle); + m_token.setPlaceHolderText(Tr::tr("IDE Access Token")); + m_token.setVisible(mode == Edit); + + using namespace Layouting; + + Row { + Form { + m_dashboardUrl, + m_description, + m_token + } + }.attachTo(this, mode == Edit ? WithMargins : WithoutMargins); + + auto checkValidity = [this](){ + bool old = m_valid; + m_valid = isValid(); + if (old != m_valid) + emit validChanged(m_valid); + }; + if (mode == Edit) { + connect(&m_dashboardUrl, &StringAspect::valueChanged, + this, checkValidity); + connect(&m_description, &StringAspect::valueChanged, + this, checkValidity); + connect(&m_token, &StringAspect::valueChanged, + this, checkValidity); + } +} + +AxivionServer DashboardWidget::dashboardServer() const +{ + AxivionServer result; + if (m_id.isValid()) + result.id = m_id; + else + result.id = m_mode == Edit ? Utils::Id::fromName(QUuid::createUuid().toByteArray()) : m_id; + result.dashboard = m_dashboardUrl.value(); + result.description = m_description.value(); + result.token = m_token.value(); + return result; +} + +void DashboardWidget::setDashboardServer(const AxivionServer &server) +{ + m_id = server.id; + m_dashboardUrl.setValue(server.dashboard); + m_description.setValue(server.description); + m_token.setValue(server.token); +} + +bool DashboardWidget::isValid() const +{ + return !m_token.value().isEmpty() && !m_description.value().isEmpty() + && isUrlValid(m_dashboardUrl.value()); +} + class AxivionSettingsWidget : public Core::IOptionsPageWidget { public: @@ -36,26 +124,73 @@ public: void apply() override; private: + void showEditServerDialog(); + AxivionSettings *m_settings; + + Utils::StringAspect m_curlPC; + DashboardWidget *m_dashboardDisplay = nullptr; + QPushButton *m_edit = nullptr; }; AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) : m_settings(settings) { - using namespace Utils::Layouting; + using namespace Layouting; - auto label = new QLabel(Tr::tr("...Placeholder...")); - Row { - Column { label, st } + m_dashboardDisplay = new DashboardWidget(DashboardWidget::Display, this); + m_dashboardDisplay->setDashboardServer(m_settings->server); + m_edit = new QPushButton(Tr::tr("Edit..."), this); + m_curlPC.setLabelText(Tr::tr("curl:")); + m_curlPC.setDisplayStyle(StringAspect::PathChooserDisplay); + m_curlPC.setExpectedKind(PathChooser::ExistingCommand); + m_curlPC.setFilePath(m_settings->curl); + Grid { + Form { + m_dashboardDisplay, br, + m_curlPC, br, + }, Column { m_edit, st } }.attachTo(this); + + connect(m_edit, &QPushButton::clicked, this, &AxivionSettingsWidget::showEditServerDialog); } void AxivionSettingsWidget::apply() { - // set m_settings from widget + m_settings->server = m_dashboardDisplay->dashboardServer(); + m_settings->curl = m_curlPC.filePath(); m_settings->toSettings(Core::ICore::settings()); } +void AxivionSettingsWidget::showEditServerDialog() +{ + const AxivionServer old = m_dashboardDisplay->dashboardServer(); + QDialog d; + d.setWindowTitle(Tr::tr("Edit Dashboard Configuration")); + QVBoxLayout *layout = new QVBoxLayout; + DashboardWidget *dashboardWidget = new DashboardWidget(DashboardWidget::Edit, this); + dashboardWidget->setDashboardServer(old); + layout->addWidget(dashboardWidget); + auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel, this); + auto modify = buttons->addButton(Tr::tr("Modify"), QDialogButtonBox::AcceptRole); + modify->setEnabled(m_dashboardDisplay->isValid()); + connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, &d, &QDialog::reject); + connect(modify, &QPushButton::clicked, &d, &QDialog::accept); + connect(dashboardWidget, &DashboardWidget::validChanged, + modify, &QPushButton::setEnabled); + layout->addWidget(buttons); + d.setLayout(layout); + d.resize(500, 200); + + if (d.exec() != QDialog::Accepted) + return; + if (dashboardWidget->isValid()) { + const AxivionServer server = dashboardWidget->dashboardServer(); + if (server != old) + m_dashboardDisplay->setDashboardServer(server); + } +} + AxivionSettingsPage::AxivionSettingsPage(AxivionSettings *settings) : m_settings(settings) { diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h index 64c0c01f9eb..02cfb81ffa9 100644 --- a/plugins/axivion/axivionsettingspage.h +++ b/plugins/axivion/axivionsettingspage.h @@ -1,32 +1,45 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once #include +#include +#include #include +#include namespace Axivion::Internal { +class AxivionServer; class AxivionSettings; class AxivionSettingsWidget; +class DashboardWidget : public QWidget +{ + Q_OBJECT +public: + enum Mode { Display, Edit }; + explicit DashboardWidget(Mode m = Display, QWidget *parent = nullptr); + + AxivionServer dashboardServer() const; + void setDashboardServer(const AxivionServer &server); + + bool isValid() const; + +signals: + void validChanged(bool valid); +private: + Mode m_mode = Display; + Utils::Id m_id; + Utils::StringAspect m_dashboardUrl; + Utils::StringAspect m_description; + Utils::StringAspect m_token; + bool m_valid = false; +}; + + class AxivionSettingsPage : public Core::IOptionsPage { Q_OBJECT @@ -37,4 +50,4 @@ private: AxivionSettings *m_settings; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axiviontr.h b/plugins/axivion/axiviontr.h index 062dd6b9598..5a8398730a1 100644 --- a/plugins/axivion/axiviontr.h +++ b/plugins/axivion/axiviontr.h @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once @@ -27,4 +12,4 @@ struct Tr Q_DECLARE_TR_FUNCTIONS(Axivion) }; -} // namespace Axivion +} // Axivion From 1df3f216a27cdf79a9d05054473500f31209b904 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 13 Dec 2022 11:17:12 +0100 Subject: [PATCH 0009/1447] Provide project settings Currently incomplete due to missing underlying infrastructure which will be added separately. Change-Id: Ied6d09e9a0834370afca5f7be9c2fbd2da210a2e Reviewed-by: David Schulz --- plugins/axivion/CMakeLists.txt | 1 + plugins/axivion/axivion.qbs | 2 + plugins/axivion/axivionplugin.cpp | 44 +++++++- plugins/axivion/axivionplugin.h | 10 +- plugins/axivion/axivionprojectsettings.cpp | 124 +++++++++++++++++++++ plugins/axivion/axivionprojectsettings.h | 61 ++++++++++ 6 files changed, 237 insertions(+), 5 deletions(-) create mode 100644 plugins/axivion/axivionprojectsettings.cpp create mode 100644 plugins/axivion/axivionprojectsettings.h diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 3f1633251f5..e5b4045b628 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -15,6 +15,7 @@ add_qtc_plugin(Axivion axivion.qrc axivionoutputpane.cpp axivionoutputpane.h axivionplugin.cpp axivionplugin.h + axivionprojectsettings.h axivionprojectsettings.cpp axivionsettings.cpp axivionsettings.h axivionsettingspage.cpp axivionsettingspage.h axiviontr.h diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs index d73031f89b0..3e28ee0903b 100644 --- a/plugins/axivion/axivion.qbs +++ b/plugins/axivion/axivion.qbs @@ -16,6 +16,8 @@ QtcCommercialPlugin { "axivionoutputpane.h", "axivionplugin.cpp", "axivionplugin.h", + "axivionprojectsettings.h", + "axivionprojectsettings.cpp", "axivionsettings.cpp", "axivionsettings.h", "axivionsettingspage.cpp", diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 639ff50b465..7156ad66566 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -4,11 +4,16 @@ #include "axivionplugin.h" #include "axivionoutputpane.h" +#include "axivionprojectsettings.h" #include "axivionsettings.h" #include "axivionsettingspage.h" +#include "axiviontr.h" #include #include +#include +#include +#include #ifdef LICENSECHECKER # include @@ -22,11 +27,19 @@ public: AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; AxivionOutputPane axivionOutputPane; + QHash projectSettings; }; +static AxivionPluginPrivate *dd = nullptr; + AxivionPlugin::~AxivionPlugin() { - delete d; + if (!dd->projectSettings.isEmpty()) { + qDeleteAll(dd->projectSettings); + dd->projectSettings.clear(); + } + delete dd; + dd = nullptr; } bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessage) @@ -42,9 +55,34 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return true; #endif // LICENSECHECKER - d = new AxivionPluginPrivate; - d->axivionSettings.fromSettings(Core::ICore::settings()); + dd = new AxivionPluginPrivate; + dd->axivionSettings.fromSettings(Core::ICore::settings()); + + auto panelFactory = new ProjectExplorer::ProjectPanelFactory; + panelFactory->setPriority(250); + panelFactory->setDisplayName(Tr::tr("Axivion")); + panelFactory->setCreateWidgetFunction([](ProjectExplorer::Project *project){ + return new AxivionProjectSettingsWidget(project); + }); + ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); return true; } +AxivionSettings *AxivionPlugin::settings() +{ + QTC_ASSERT(dd, return nullptr); + return &dd->axivionSettings; +} + +AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project *project) +{ + QTC_ASSERT(project, return nullptr); + QTC_ASSERT(dd, return nullptr); + + auto &settings = dd->projectSettings[project]; + if (!settings) + settings = new AxivionProjectSettings(project); + return settings; +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index f22f2823e19..a9d49b37e15 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -5,8 +5,13 @@ #include +namespace ProjectExplorer { class Project; } + namespace Axivion::Internal { +class AxivionSettings; +class AxivionProjectSettings; + class AxivionPlugin final : public ExtensionSystem::IPlugin { Q_OBJECT @@ -16,11 +21,12 @@ public: AxivionPlugin() = default; ~AxivionPlugin() final; + static AxivionSettings *settings(); + static AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); + private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} - - class AxivionPluginPrivate *d = nullptr; }; } // Axivion::Internal diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp new file mode 100644 index 00000000000..2d1bb3efa95 --- /dev/null +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -0,0 +1,124 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#include "axivionprojectsettings.h" + +#include "axivionplugin.h" +#include "axivionsettings.h" +#include "axiviontr.h" + +#include +#include + +#include +#include +#include + +namespace Axivion::Internal { + +const char PSK_PROJECTNAME[] = "Axivion.ProjectName"; + +AxivionProjectSettings::AxivionProjectSettings(ProjectExplorer::Project *project) + : m_project{project} +{ + load(); + connect(project, &ProjectExplorer::Project::settingsLoaded, + this, &AxivionProjectSettings::load); + connect(project, &ProjectExplorer::Project::aboutToSaveSettings, + this, &AxivionProjectSettings::save); +} + +void AxivionProjectSettings::load() +{ + m_dashboardProjectName = m_project->namedSettings(PSK_PROJECTNAME).toString(); +} + +void AxivionProjectSettings::save() +{ + m_project->setNamedSettings(PSK_PROJECTNAME, m_dashboardProjectName); +} + +AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Project *project, + QWidget *parent) + : ProjectExplorer::ProjectSettingsWidget{parent} + , m_projectSettings(AxivionPlugin::projectSettings(project)) + , m_globalSettings(AxivionPlugin::settings()) +{ + setUseGlobalSettingsCheckBoxVisible(false); + setUseGlobalSettingsLabelVisible(true); + setGlobalSettingsId("Axivion.Settings.General"); // FIXME move id to constants + // setup ui + auto verticalLayout = new QVBoxLayout(this); + verticalLayout->setContentsMargins(0, 0, 0, 0); + + m_linkedProject = new QLabel(this); + verticalLayout->addWidget(m_linkedProject); + + m_dashboardProjects = new QTreeWidget(this); + m_dashboardProjects->setHeaderHidden(true); + m_dashboardProjects->setRootIsDecorated(false); + verticalLayout->addWidget(new QLabel(Tr::tr("Dashboard projects:"))); + verticalLayout->addWidget(m_dashboardProjects); + + m_infoLabel = new Utils::InfoLabel(this); + m_infoLabel->setVisible(false); + verticalLayout->addWidget(m_infoLabel); + + auto horizontalLayout = new QHBoxLayout; + horizontalLayout->setContentsMargins(0, 0, 0, 0); + m_fetchProjects = new QPushButton(Tr::tr("Fetch Projects")); + horizontalLayout->addWidget(m_fetchProjects); + m_link = new QPushButton(Tr::tr("Link Project")); + m_link->setEnabled(false); + horizontalLayout->addWidget(m_link); + m_unlink = new QPushButton(Tr::tr("Unlink Project")); + m_unlink->setEnabled(false); + horizontalLayout->addWidget(m_unlink); + verticalLayout->addLayout(horizontalLayout); + + connect(m_dashboardProjects, &QTreeWidget::itemSelectionChanged, + this, &AxivionProjectSettingsWidget::updateEnabledStates); + connect(m_fetchProjects, &QPushButton::clicked, + this, &AxivionProjectSettingsWidget::fetchProjects); + + updateUi(); +} + +void AxivionProjectSettingsWidget::fetchProjects() +{ + m_dashboardProjects->clear(); + m_fetchProjects->setEnabled(false); + // TODO perform query and populate m_dashboardProjects +} + +void AxivionProjectSettingsWidget::updateUi() +{ + const QString projectName = m_projectSettings->dashboardProjectName(); + if (projectName.isEmpty()) + m_linkedProject->setText(Tr::tr("This project is not linked to a dashboard project.")); + else + m_linkedProject->setText(Tr::tr("This project is linked to \"%1\".").arg(projectName)); + updateEnabledStates(); +} + +void AxivionProjectSettingsWidget::updateEnabledStates() +{ + const bool hasDashboardSettings = m_globalSettings->curl.isExecutableFile() + && !m_globalSettings->server.dashboard.isEmpty() + && !m_globalSettings->server.token.isEmpty(); + const bool linked = !m_projectSettings->dashboardProjectName().isEmpty(); + const bool linkable = m_dashboardProjects->topLevelItemCount() + && !m_dashboardProjects->selectedItems().isEmpty(); + + m_fetchProjects->setEnabled(hasDashboardSettings); + m_link->setEnabled(!linked && linkable); + m_unlink->setEnabled(linked); + + if (!hasDashboardSettings) { + m_infoLabel->setText(Tr::tr("Incomplete or misconfigured settings.")); + m_infoLabel->setType(Utils::InfoLabel::NotOk); + m_infoLabel->setVisible(true); + } +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionprojectsettings.h b/plugins/axivion/axivionprojectsettings.h new file mode 100644 index 00000000000..9501494c5fd --- /dev/null +++ b/plugins/axivion/axivionprojectsettings.h @@ -0,0 +1,61 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#pragma once + +#include "axivionsettings.h" + +#include + +#include + +QT_BEGIN_NAMESPACE +class QLabel; +class QPushButton; +class QTreeWidget; +QT_END_NAMESPACE + +namespace ProjectExplorer { class Project; } + +namespace Utils { class InfoLabel; } + +namespace Axivion::Internal { + +class AxivionProjectSettings : public QObject +{ +public: + explicit AxivionProjectSettings(ProjectExplorer::Project *project); + + void setDashboardProjectName(const QString &name) { m_dashboardProjectName = name; } + QString dashboardProjectName() const { return m_dashboardProjectName; } + +private: + void load(); + void save(); + + ProjectExplorer::Project *m_project = nullptr; + QString m_dashboardProjectName; +}; + +class AxivionProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget +{ +public: + explicit AxivionProjectSettingsWidget(ProjectExplorer::Project *project, + QWidget *parent = nullptr); + +private: + void fetchProjects(); + void updateUi(); + void updateEnabledStates(); + + AxivionProjectSettings *m_projectSettings = nullptr; + AxivionSettings *m_globalSettings; + QLabel *m_linkedProject = nullptr; + QTreeWidget *m_dashboardProjects = nullptr; + QPushButton *m_fetchProjects = nullptr; + QPushButton *m_link = nullptr; + QPushButton *m_unlink = nullptr; + Utils::InfoLabel *m_infoLabel = nullptr; +}; + +} // Axivion::Internal From 82bd1de9364f593211b5d141787a82789d6b4bae Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 13 Dec 2022 15:13:13 +0100 Subject: [PATCH 0010/1447] Provide first query mechanism Allow to link current project to a dashboard project. Change-Id: If73caab0e26b4b5151dbab1a6c9db72857fddacc Reviewed-by: David Schulz --- plugins/axivion/CMakeLists.txt | 2 + plugins/axivion/axivion.qbs | 4 ++ plugins/axivion/axivionplugin.cpp | 31 +++++++++ plugins/axivion/axivionplugin.h | 8 ++- plugins/axivion/axivionprojectsettings.cpp | 61 +++++++++++++++++ plugins/axivion/axivionprojectsettings.h | 6 ++ plugins/axivion/axivionquery.cpp | 79 ++++++++++++++++++++++ plugins/axivion/axivionquery.h | 40 +++++++++++ plugins/axivion/axivionresultparser.cpp | 62 +++++++++++++++++ plugins/axivion/axivionresultparser.h | 36 ++++++++++ plugins/axivion/axivionsettingspage.cpp | 2 + 11 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 plugins/axivion/axivionquery.cpp create mode 100644 plugins/axivion/axivionquery.h create mode 100644 plugins/axivion/axivionresultparser.cpp create mode 100644 plugins/axivion/axivionresultparser.h diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index e5b4045b628..61ad3c7857a 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -16,6 +16,8 @@ add_qtc_plugin(Axivion axivionoutputpane.cpp axivionoutputpane.h axivionplugin.cpp axivionplugin.h axivionprojectsettings.h axivionprojectsettings.cpp + axivionquery.h axivionquery.cpp + axivionresultparser.h axivionresultparser.cpp axivionsettings.cpp axivionsettings.h axivionsettingspage.cpp axivionsettingspage.h axiviontr.h diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs index 3e28ee0903b..1e437bb357a 100644 --- a/plugins/axivion/axivion.qbs +++ b/plugins/axivion/axivion.qbs @@ -18,6 +18,10 @@ QtcCommercialPlugin { "axivionplugin.h", "axivionprojectsettings.h", "axivionprojectsettings.cpp", + "axivionquery.h", + "axivionquery.cpp", + "axivionresultparser.h", + "axivionresultparser.cpp", "axivionsettings.cpp", "axivionsettings.h", "axivionsettingspage.cpp", diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 7156ad66566..62f4fa081be 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -19,6 +19,8 @@ # include #endif +#include + namespace Axivion::Internal { class AxivionPluginPrivate @@ -30,8 +32,14 @@ public: QHash projectSettings; }; +static AxivionPlugin *s_instance = nullptr; static AxivionPluginPrivate *dd = nullptr; +AxivionPlugin::AxivionPlugin() +{ + s_instance = this; +} + AxivionPlugin::~AxivionPlugin() { if (!dd->projectSettings.isEmpty()) { @@ -42,6 +50,11 @@ AxivionPlugin::~AxivionPlugin() dd = nullptr; } +AxivionPlugin *AxivionPlugin::instance() +{ + return s_instance; +} + bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Q_UNUSED(arguments) @@ -85,4 +98,22 @@ AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project return settings; } +bool AxivionPlugin::handleCertificateIssue() +{ + QTC_ASSERT(dd, return false); + + const QString serverHost = QUrl(dd->axivionSettings.server.dashboard).host(); + if (QMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Certificate Error"), + Tr::tr("Server certificate for %1 cannot be authenticated.\n" + "Do you want to disable SSL verification for this server?\n" + "Note: This can expose you to man-in-the-middle attack.") + .arg(serverHost)) + != QMessageBox::Yes) { + return false; + } + dd->axivionSettings.server.validateCert = false; + emit s_instance->settingsChanged(); + return true; +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index a9d49b37e15..0d71d005b96 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -18,12 +18,18 @@ class AxivionPlugin final : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Axivion.json") public: - AxivionPlugin() = default; + AxivionPlugin(); ~AxivionPlugin() final; + static AxivionPlugin *instance(); static AxivionSettings *settings(); static AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); + static bool handleCertificateIssue(); + +signals: + void settingsChanged(); + private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 2d1bb3efa95..7e8dc7dfc87 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -4,11 +4,14 @@ #include "axivionprojectsettings.h" #include "axivionplugin.h" +#include "axivionquery.h" +#include "axivionresultparser.h" #include "axivionsettings.h" #include "axiviontr.h" #include #include +#include #include #include @@ -80,6 +83,12 @@ AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Proj this, &AxivionProjectSettingsWidget::updateEnabledStates); connect(m_fetchProjects, &QPushButton::clicked, this, &AxivionProjectSettingsWidget::fetchProjects); + connect(m_link, &QPushButton::clicked, + this, &AxivionProjectSettingsWidget::linkProject); + connect(m_unlink, &QPushButton::clicked, + this, &AxivionProjectSettingsWidget::unlinkProject); + connect(AxivionPlugin::instance(), &AxivionPlugin::settingsChanged, + this, &AxivionProjectSettingsWidget::onSettingsChanged); updateUi(); } @@ -88,7 +97,59 @@ void AxivionProjectSettingsWidget::fetchProjects() { m_dashboardProjects->clear(); m_fetchProjects->setEnabled(false); + m_infoLabel->setVisible(false); // TODO perform query and populate m_dashboardProjects + const AxivionQuery query(AxivionQuery::DashboardInfo); + AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); + connect(runner, &AxivionQueryRunner::resultRetrieved, + this, [this](const QByteArray &result){ + onDashboardInfoReceived(ResultParser::parseDashboardInfo(result)); + }); + connect(runner, &AxivionQueryRunner::finished, this, [runner]{ runner->deleteLater(); }); + runner->start(); +} + +void AxivionProjectSettingsWidget::onDashboardInfoReceived(const DashboardInfo &info) +{ + if (!info.error.isEmpty()) { + if (info.error.contains("credentials")) { + m_infoLabel->setText("Authentication failed. Check credentials settings."); + m_infoLabel->setType(Utils::InfoLabel::Error); + m_infoLabel->setVisible(true); + } + // send error to general message and discard results + // FIXME currently we do not get all errors - e.g. wrong curl calls + updateEnabledStates(); + return; + } + + for (const Project &project : info.projects) + new QTreeWidgetItem(m_dashboardProjects, {project.name}); + updateEnabledStates(); +} + +void AxivionProjectSettingsWidget::onSettingsChanged() +{ + m_dashboardProjects->clear(); + m_infoLabel->setVisible(false); + updateUi(); +} + +void AxivionProjectSettingsWidget::linkProject() +{ + const QList selected = m_dashboardProjects->selectedItems(); + QTC_ASSERT(selected.size() == 1, return); + + m_projectSettings->setDashboardProjectName(selected.first()->text(0)); + updateUi(); +} + +void AxivionProjectSettingsWidget::unlinkProject() +{ + QTC_ASSERT(!m_projectSettings->dashboardProjectName().isEmpty(), return); + + m_projectSettings->setDashboardProjectName({}); + updateUi(); } void AxivionProjectSettingsWidget::updateUi() diff --git a/plugins/axivion/axivionprojectsettings.h b/plugins/axivion/axivionprojectsettings.h index 9501494c5fd..c9bf147a51d 100644 --- a/plugins/axivion/axivionprojectsettings.h +++ b/plugins/axivion/axivionprojectsettings.h @@ -21,6 +21,8 @@ namespace Utils { class InfoLabel; } namespace Axivion::Internal { +class DashboardInfo; + class AxivionProjectSettings : public QObject { public: @@ -45,6 +47,10 @@ public: private: void fetchProjects(); + void onDashboardInfoReceived(const DashboardInfo &info); + void onSettingsChanged(); + void linkProject(); + void unlinkProject(); void updateUi(); void updateEnabledStates(); diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp new file mode 100644 index 00000000000..bff033fc125 --- /dev/null +++ b/plugins/axivion/axivionquery.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#include "axivionquery.h" + +#include "axivionplugin.h" +#include "axivionsettings.h" + +#include +#include + +using namespace Utils; + +namespace Axivion::Internal { + +AxivionQuery::AxivionQuery(QueryType type, const QStringList ¶meters) + : m_type(type) + , m_parameters(parameters) +{ +} + +QString AxivionQuery::toString() const +{ + QString query = "/api"; // common for all + switch (m_type) { + case NoQuery: + return {}; + case DashboardInfo: + return query; + } + + return {}; +} + +AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *parent) + : QObject(parent) +{ + const AxivionSettings *settings = AxivionPlugin::settings(); + const AxivionServer server = settings->server; + + QStringList args = server.curlArguments(); + // TODO handle paginated results + args << "--header" << "Authorization: AxToken " + server.token; + + QString url = server.dashboard; + while (url.endsWith('/')) url.chop(1); + url += query.toString(); + args << url; + + m_process.setCommand({settings->curl, args}); + connect(&m_process, &QtcProcess::done, this, [this]{ + if (m_process.result() != ProcessResult::FinishedWithSuccess) { + const int exitCode = m_process.exitCode(); + if (m_process.exitStatus() == QProcess::NormalExit + && (exitCode == 35 || exitCode == 60) + && AxivionPlugin::handleCertificateIssue()) { + // prepend -k for re-requesting same query + CommandLine cmdline = m_process.commandLine(); + cmdline.prependArgs({"-k"}); + m_process.close(); + m_process.setCommand(cmdline); + start(); + return; + } + // output error to general message + } else { + emit resultRetrieved(m_process.readAllStandardOutput()); + } + emit finished(); + }); +} + +void AxivionQueryRunner::start() +{ + QTC_ASSERT(!m_process.isRunning(), return); + m_process.start(); +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h new file mode 100644 index 00000000000..85721b07033 --- /dev/null +++ b/plugins/axivion/axivionquery.h @@ -0,0 +1,40 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#pragma once + +#include + +#include + +namespace Axivion::Internal { + +class AxivionQuery +{ +public: + enum QueryType {NoQuery, DashboardInfo}; + explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); + + QString toString() const; + +private: + QueryType m_type = NoQuery; + QStringList m_parameters; +}; + +class AxivionQueryRunner : public QObject +{ + Q_OBJECT +public: + explicit AxivionQueryRunner(const AxivionQuery &query, QObject *parent = nullptr); + void start(); + +signals: + void finished(); + void resultRetrieved(const QByteArray &json); + +private: + Utils::QtcProcess m_process; +}; + +} // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp new file mode 100644 index 00000000000..59f90854d37 --- /dev/null +++ b/plugins/axivion/axivionresultparser.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#include "axivionresultparser.h" + +#include +#include +#include + +namespace Axivion::Internal { + + +namespace ResultParser { + +DashboardInfo parseDashboardInfo(const QByteArray &input) +{ + DashboardInfo result; + + QJsonParseError error; + const QJsonDocument doc = QJsonDocument::fromJson(input, &error); + if (error.error != QJsonParseError::NoError) { + if (input.startsWith("Authentication failed:")) + result.error = QString::fromUtf8(input); + else + result.error = error.errorString(); + return result; + } + + if (!doc.isObject()) { + result.error = "Not an object."; + return result; + } + const QJsonObject object = doc.object(); + result.mainUrl = object.value("mainUrl").toString(); + + if (!object.contains("projects")) { + result.error = "Missing projects information."; + return result; + } + const QJsonValue projects = object.value("projects"); + if (!projects.isArray()) { + result.error = "Projects information not an array."; + return result; + } + const QJsonArray array = projects.toArray(); + for (const QJsonValue &val : array) { + if (!val.isObject()) + continue; + const QJsonObject projectObject = val.toObject(); + Project project; + project.name = projectObject.value("name").toString(); + project.url = projectObject.value("url").toString(); + if (project.name.isEmpty() || project.url.isEmpty()) + continue; + result.projects.append(project); + } + return result; +} + +} // ResultParser + +} // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h new file mode 100644 index 00000000000..57a0127cc02 --- /dev/null +++ b/plugins/axivion/axivionresultparser.h @@ -0,0 +1,36 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#pragma once + +#include + +namespace Axivion::Internal { + +class BaseResult +{ +public: + QString error; +}; + +class Project : public BaseResult +{ +public: + QString name; + QString url; +}; + +class DashboardInfo : public BaseResult +{ +public: + QString mainUrl; + QList projects; +}; + +namespace ResultParser { + +DashboardInfo parseDashboardInfo(const QByteArray &input); + +} // ResultParser + +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index ffe5122442e..bd0ddee04c9 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -3,6 +3,7 @@ #include "axivionsettingspage.h" +#include "axivionplugin.h" #include "axivionsettings.h" #include "axiviontr.h" @@ -160,6 +161,7 @@ void AxivionSettingsWidget::apply() m_settings->server = m_dashboardDisplay->dashboardServer(); m_settings->curl = m_curlPC.filePath(); m_settings->toSettings(Core::ICore::settings()); + emit AxivionPlugin::instance()->settingsChanged(); } void AxivionSettingsWidget::showEditServerDialog() From cc0b392e873b28c38b0cea93d1a8e7f698c7efa5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 08:55:20 +0100 Subject: [PATCH 0011/1447] Tweak error handling a bit Always get http headers of the response to be able to handle issues more explicitly. These headers also contain additional information we will need later on. Change-Id: I062e97726a473c16b29cd84be0aa37260bac4ed8 Reviewed-by: David Schulz --- plugins/axivion/axivionprojectsettings.cpp | 10 +-- plugins/axivion/axivionquery.cpp | 4 +- plugins/axivion/axivionresultparser.cpp | 76 ++++++++++++++++++---- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 7e8dc7dfc87..3d8b11c70dc 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -112,13 +112,9 @@ void AxivionProjectSettingsWidget::fetchProjects() void AxivionProjectSettingsWidget::onDashboardInfoReceived(const DashboardInfo &info) { if (!info.error.isEmpty()) { - if (info.error.contains("credentials")) { - m_infoLabel->setText("Authentication failed. Check credentials settings."); - m_infoLabel->setType(Utils::InfoLabel::Error); - m_infoLabel->setVisible(true); - } - // send error to general message and discard results - // FIXME currently we do not get all errors - e.g. wrong curl calls + m_infoLabel->setText(info.error); + m_infoLabel->setType(Utils::InfoLabel::Error); + m_infoLabel->setVisible(true); updateEnabledStates(); return; } diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index bff033fc125..8b8cf48938f 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -39,7 +39,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren const AxivionServer server = settings->server; QStringList args = server.curlArguments(); - // TODO handle paginated results + args << "-i"; args << "--header" << "Authorization: AxToken " + server.token; QString url = server.dashboard; @@ -62,7 +62,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren start(); return; } - // output error to general message + emit resultRetrieved(m_process.readAllStandardError()); } else { emit resultRetrieved(m_process.readAllStandardOutput()); } diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 59f90854d37..5ef89a1cce1 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -6,9 +6,69 @@ #include #include #include +#include + +#include namespace Axivion::Internal { +static std::pair splitHeaderAndBody(const QByteArray &input) +{ + QByteArray header; + QByteArray json; + int emptyLine = input.indexOf("\r\n\r\n"); // we always get \r\n as line separator + if (emptyLine != -1) { + header = input.left(emptyLine); + json = input.mid(emptyLine + 4); + } else { + json = input; + } + return {header, json}; +} + +static int httpStatus(const QByteArray &header) +{ + int firstHeaderEnd = header.indexOf("\r\n"); + if (firstHeaderEnd == -1) + return 600; // unexpected header + const QString firstLine = QString::fromUtf8(header.first(firstHeaderEnd)); + static const QRegularExpression regex(R"(^HTTP/\d\.\d (\d{3}) .*$)"); + const QRegularExpressionMatch match = regex.match(firstLine); + return match.hasMatch() ? match.captured(1).toInt() : 601; +} + +static std::pair prehandleHeaderAndBody(const QByteArray &header, + const QByteArray &body) +{ + BaseResult result; + if (header.isEmpty()) { + result.error = QString::fromUtf8(body); // we likely had a curl problem + return {result, {}}; + } + int status = httpStatus(header); + if ((status > 399) || (status > 299 && body.isEmpty())) { // FIXME handle some explicitly? + const QString statusStr = QString::number(status); + if (body.isEmpty() || body.startsWith('<')) // likely an html response or redirect + result.error = QLatin1String("(%1)").arg(statusStr); + else + result.error = QLatin1String("%1 (%2)").arg(QString::fromUtf8(body)).arg(statusStr); + return {result, {}}; + } + + QJsonParseError error; + const QJsonDocument doc = QJsonDocument::fromJson(body, &error); + if (error.error != QJsonParseError::NoError) { + result.error = error.errorString(); + return {result, doc}; + } + + if (!doc.isObject()) { + result.error = "Not an object."; + return {result, {}}; + } + + return {result, doc}; +} namespace ResultParser { @@ -16,18 +76,10 @@ DashboardInfo parseDashboardInfo(const QByteArray &input) { DashboardInfo result; - QJsonParseError error; - const QJsonDocument doc = QJsonDocument::fromJson(input, &error); - if (error.error != QJsonParseError::NoError) { - if (input.startsWith("Authentication failed:")) - result.error = QString::fromUtf8(input); - else - result.error = error.errorString(); - return result; - } - - if (!doc.isObject()) { - result.error = "Not an object."; + auto [header, body] = splitHeaderAndBody(input); + auto [error, doc] = prehandleHeaderAndBody(header, body); + if (!error.error.isEmpty()) { + result.error = error.error; return result; } const QJsonObject object = doc.object(); From b741b2eeebca2e99187a4a7fe92b01a7eddd9d62 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 14 Dec 2022 12:11:03 +0100 Subject: [PATCH 0012/1447] Provide functionality for fetching project information Change-Id: Id0968c08eb3017eb6f902c3cea3a363bc3f0c35c Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 5 + plugins/axivion/axivionoutputpane.h | 1 + plugins/axivion/axivionplugin.cpp | 69 ++++++++- plugins/axivion/axivionplugin.h | 2 + plugins/axivion/axivionprojectsettings.cpp | 4 +- plugins/axivion/axivionquery.cpp | 6 + plugins/axivion/axivionquery.h | 2 +- plugins/axivion/axivionresultparser.cpp | 155 +++++++++++++++++++++ plugins/axivion/axivionresultparser.h | 44 ++++++ 9 files changed, 285 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index d7896e02d0f..81df73cbc4f 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -89,4 +89,9 @@ void AxivionOutputPane::goToPrev() { } +void AxivionOutputPane::updateDashboard() +{ + +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h index 63ec48097ec..81b1647154c 100644 --- a/plugins/axivion/axivionoutputpane.h +++ b/plugins/axivion/axivionoutputpane.h @@ -33,6 +33,7 @@ public: void goToNext() override; void goToPrev() override; + void updateDashboard(); private: QStackedWidget *m_outputWidget = nullptr; }; diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 62f4fa081be..f3e6cd8c184 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -5,14 +5,18 @@ #include "axivionoutputpane.h" #include "axivionprojectsettings.h" +#include "axivionquery.h" +#include "axivionresultparser.h" #include "axivionsettings.h" #include "axivionsettingspage.h" #include "axiviontr.h" #include +#include #include #include #include +#include #include #ifdef LICENSECHECKER @@ -20,16 +24,22 @@ #endif #include +#include namespace Axivion::Internal { -class AxivionPluginPrivate +class AxivionPluginPrivate : public QObject { public: + void fetchProjectInfo(const QString &projectName); + void handleProjectInfo(const ProjectInfo &info); + AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; AxivionOutputPane axivionOutputPane; QHash projectSettings; + ProjectInfo currentProjectInfo; + bool runningQuery = false; }; static AxivionPlugin *s_instance = nullptr; @@ -78,9 +88,26 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return new AxivionProjectSettingsWidget(project); }); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, + this, &AxivionPlugin::onStartupProjectChanged); return true; } +void AxivionPlugin::onStartupProjectChanged() +{ + QTC_ASSERT(dd, return); + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!project) { + dd->currentProjectInfo = ProjectInfo(); + dd->axivionOutputPane.updateDashboard(); + return; + } + + const AxivionProjectSettings *projSettings = projectSettings(project); + dd->fetchProjectInfo(projSettings->dashboardProjectName()); +} + AxivionSettings *AxivionPlugin::settings() { QTC_ASSERT(dd, return nullptr); @@ -116,4 +143,44 @@ bool AxivionPlugin::handleCertificateIssue() return true; } +void AxivionPlugin::fetchProjectInfo(const QString &projectName) +{ + QTC_ASSERT(dd, return); + dd->fetchProjectInfo(projectName); +} + +void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) +{ + if (runningQuery) { // re-schedule + QTimer::singleShot(3000, [this, projectName]{ fetchProjectInfo(projectName); }); + return; + } + if (projectName.isEmpty()) { + currentProjectInfo = ProjectInfo(); + axivionOutputPane.updateDashboard(); + return; + } + runningQuery = true; + + AxivionQuery query(AxivionQuery::ProjectInfo, {projectName}); + AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); + connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ + handleProjectInfo(ResultParser::parseProjectInfo(result)); + }); + connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); }); + runner->start(); +} + +void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) +{ + runningQuery = false; + if (!info.error.isEmpty()) { + Core::MessageManager::writeFlashing("Axivion: " + info.error); + return; + } + + currentProjectInfo = info; + axivionOutputPane.updateDashboard(); +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index 0d71d005b96..fb0da44cbd0 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -26,6 +26,7 @@ public: static AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); static bool handleCertificateIssue(); + static void fetchProjectInfo(const QString &projectName); signals: void settingsChanged(); @@ -33,6 +34,7 @@ signals: private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} + void onStartupProjectChanged(); }; } // Axivion::Internal diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 3d8b11c70dc..00844d10746 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -136,8 +136,10 @@ void AxivionProjectSettingsWidget::linkProject() const QList selected = m_dashboardProjects->selectedItems(); QTC_ASSERT(selected.size() == 1, return); - m_projectSettings->setDashboardProjectName(selected.first()->text(0)); + const QString projectName = selected.first()->text(0); + m_projectSettings->setDashboardProjectName(projectName); updateUi(); + AxivionPlugin::fetchProjectInfo(projectName); } void AxivionProjectSettingsWidget::unlinkProject() diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 8b8cf48938f..4885b74ff46 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -9,6 +9,8 @@ #include #include +#include + using namespace Utils; namespace Axivion::Internal { @@ -27,6 +29,10 @@ QString AxivionQuery::toString() const return {}; case DashboardInfo: return query; + case ProjectInfo: + QTC_ASSERT(m_parameters.size() == 1, return {}); + query += "/projects/" + QUrl::toPercentEncoding(m_parameters.first()); + return query; } return {}; diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 85721b07033..721700ab3c2 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -12,7 +12,7 @@ namespace Axivion::Internal { class AxivionQuery { public: - enum QueryType {NoQuery, DashboardInfo}; + enum QueryType {NoQuery, DashboardInfo, ProjectInfo}; explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); QString toString() const; diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 5ef89a1cce1..4d765331623 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -70,6 +70,124 @@ static std::pair prehandleHeaderAndBody(const QByteAr return {result, doc}; } +static User::UserType userTypeForString(const QString &type) +{ + if (type == "DASHBOARD_USER") + return User::Dashboard; + if (type == "VIRTUAL_USER") + return User::Virtual; + return User::Unknown; +} + +static User userFromJson(const QJsonObject &object) +{ + User result; + if (object.isEmpty()) { + result.error = "Not a user object."; + return result; + } + result.name = object.value("name").toString(); + result.displayName = object.value("displayName").toString(); + result.type = userTypeForString(object.value("type").toString()); + return result; +} + +static QList usersFromJson(const QJsonArray &array) +{ + QList result; + for (const QJsonValue &value : array) { + User user = userFromJson(value.toObject()); + if (!user.error.isEmpty()) // add this error to result.error? + continue; + result.append(user); + } + return result; +} + +static IssueCount issueCountFromJson(const QJsonObject &object) +{ + IssueCount result; + if (object.isEmpty()) { + result.error = "Not an issue count object."; + return result; + } + result.added = object.value("Added").toInt(); + result.removed = object.value("Removed").toInt(); + result.total = object.value("Total").toInt(); + return result; +} + +static QList issueCountsFromJson(const QJsonObject &object) +{ + QList result; + + const QStringList keys = object.keys(); + for (const QString &k : keys) { + IssueCount issue = issueCountFromJson(object.value(k).toObject()); + if (!issue.error.isEmpty()) // add this error to result.error? + continue; + issue.issueKind = k; + result.append(issue); + } + return result; +} + +static ResultVersion versionFromJson(const QJsonObject &object) +{ + ResultVersion result; + if (object.isEmpty()) { + result.error = "Not a version object."; + return result; + } + const QJsonValue issuesValue = object.value("issueCounts"); + if (!issuesValue.isObject()) { + result.error = "Not an object (issueCounts)."; + return result; + } + result.issueCounts = issueCountsFromJson(issuesValue.toObject()); + result.timeStamp = object.value("date").toString(); + result.name = object.value("name").toString(); + result.linesOfCode = object.value("linesOfCode").toInt(); + return result; +} + +static QList versionsFromJson(const QJsonArray &array) +{ + QList result; + for (const QJsonValue &value : array) { + ResultVersion version = versionFromJson(value.toObject()); + if (!version.error.isEmpty()) // add this error to result.error? + continue; + result.append(version); + } + return result; +} + +static IssueKind issueKindFromJson(const QJsonObject &object) +{ + IssueKind result; + if (object.isEmpty()) { + result.error = "Not an issue kind object."; + return result; + } + result.prefix = object.value("prefix").toString(); + result.niceSingular = object.value("niceSingularName").toString(); + result.nicePlural = object.value("nicePluralName").toString(); + return result; +} + +static QList issueKindsFromJson(const QJsonArray &array) +{ + QList result; + for (const QJsonValue &value : array) { + IssueKind kind = issueKindFromJson(value.toObject()); + if (!kind.error.isEmpty()) // add this error to result.error? + continue; + result.append(kind); + } + return result; +} + namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input) @@ -109,6 +227,43 @@ DashboardInfo parseDashboardInfo(const QByteArray &input) return result; } +ProjectInfo parseProjectInfo(const QByteArray &input) +{ + ProjectInfo result; + + auto [header, body] = splitHeaderAndBody(input); + auto [error, doc] = prehandleHeaderAndBody(header, body); + if (!error.error.isEmpty()) { + result.error = error.error; + return result; + } + + const QJsonObject object = doc.object(); + result.name = object.value("name").toString(); + + const QJsonValue usersValue = object.value("users"); + if (!usersValue.isArray()) { + result.error = "Malformed json response (users)."; + return result; + } + result.users = usersFromJson(usersValue.toArray()); + + const QJsonValue versionsValue = object.value("versions"); + if (!versionsValue.isArray()) { + result.error = "Malformed json response (versions)."; + return result; + } + result.versions = versionsFromJson(versionsValue.toArray()); + + const QJsonValue issueKindsValue = object.value("issueKinds"); + if (!issueKindsValue.isArray()) { + result.error = "Malformed json response (issueKinds)."; + return result; + } + result.issueKinds = issueKindsFromJson(issueKindsValue.toArray()); + return result; +} + } // ResultParser } // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index 57a0127cc02..9a308f9950e 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -27,9 +27,53 @@ public: QList projects; }; +class User : public BaseResult +{ +public: + QString name; + QString displayName; + enum UserType { Dashboard, Virtual, Unknown } type; +}; + +class IssueKind : public BaseResult +{ +public: + QString prefix; + QString niceSingular; + QString nicePlural; +}; + +class IssueCount : public BaseResult +{ +public: + QString issueKind; + int total = 0; + int added = 0; + int removed = 0; +}; + +class ResultVersion : public BaseResult +{ +public: + QString name; + QString timeStamp; + QList issueCounts; + int linesOfCode = 0; +}; + +class ProjectInfo : public BaseResult +{ +public: + QString name; + QList users; + QList versions; + QList issueKinds; +}; + namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input); +ProjectInfo parseProjectInfo(const QByteArray &input); } // ResultParser From 5ac1629976a4b7a33fc873fd8c1a03185be00fa2 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 14 Dec 2022 13:53:00 +0100 Subject: [PATCH 0013/1447] Provide some minimal project dashboard widget Some placeholder which is populated if the current project is linked to a dashboard project to have something to continue work. Ui is likely to change over time. Change-Id: I28e7df95006e5db551fcfe38adf68e5dae7c094d Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 85 +++++++++++++++++++++- plugins/axivion/axivionplugin.cpp | 6 ++ plugins/axivion/axivionplugin.h | 3 +- plugins/axivion/axivionprojectsettings.cpp | 1 + 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index 81df73cbc4f..b1b4ec98a1b 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -3,18 +3,96 @@ #include "axivionoutputpane.h" +#include "axivionplugin.h" +#include "axivionresultparser.h" #include "axiviontr.h" #include +#include +#include #include namespace Axivion::Internal { +class DashboardWidget : public QWidget +{ +public: + explicit DashboardWidget(QWidget *parent = nullptr); + void updateUi(); + bool hasProject() const { return !m_project->text().isEmpty(); } +private: + QLabel *m_project = nullptr; + QLabel *m_loc = nullptr; + QFormLayout *m_formLayout = nullptr; +}; + +DashboardWidget::DashboardWidget(QWidget *parent) + : QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + QFormLayout *projectLayout = new QFormLayout; + m_project = new QLabel(this); + projectLayout->addRow(Tr::tr("Project:"), m_project); + m_loc = new QLabel(this); + projectLayout->addRow(Tr::tr("Lines of Code:"), m_loc); + layout->addLayout(projectLayout); + m_formLayout = new QFormLayout; + layout->addLayout(m_formLayout); +} + +void DashboardWidget::updateUi() +{ + const ProjectInfo &info = AxivionPlugin::projectInfo(); + m_project->setText(info.name); + m_loc->setText({}); + while (m_formLayout->rowCount()) + m_formLayout->removeRow(0); + + if (info.versions.isEmpty()) + return; + + const ResultVersion &last = info.versions.last(); + m_loc->setText(QString::number(last.linesOfCode)); + + const QString tmpl("%1 %2 +%3 / -%4"); + auto apply = [&tmpl](int t, int a, int r){ + QChar tr = (a == r ? '=' : (a < r ? '^' : 'v')); + return tmpl.arg(t, 10, 10, QLatin1Char(' ')).arg(tr).arg(a, 5, 10, QLatin1Char(' ')) + .arg(r, 5, 10, QLatin1Char(' ')); + }; + const QList &issueKinds = info.issueKinds; + auto toolTip = [issueKinds](const QString &prefix){ + for (const IssueKind &kind : issueKinds) { + if (kind.prefix == prefix) + return kind.nicePlural; + } + return QString(); + }; + int allTotal = 0, allAdded = 0, allRemoved = 0; + for (auto issueCount : std::as_const(last.issueCounts)) { + allTotal += issueCount.total; + allAdded += issueCount.added; + allRemoved += issueCount.removed; + const QString txt = apply(issueCount.total, issueCount.added, issueCount.removed); + const QString currentToolTip = toolTip(issueCount.issueKind); + QLabel *label = new QLabel(issueCount.issueKind, this); + label->setToolTip(currentToolTip); + QLabel *values = new QLabel(txt, this); + values->setToolTip(currentToolTip); + m_formLayout->addRow(label, values); + } + + QLabel *label = new QLabel(apply(allTotal, allAdded, allRemoved), this); + m_formLayout->addRow(Tr::tr("Total:"), label); +} + AxivionOutputPane::AxivionOutputPane(QObject *parent) : Core::IOutputPane(parent) { m_outputWidget = new QStackedWidget; + DashboardWidget *dashboardWidget = new DashboardWidget(m_outputWidget); + m_outputWidget->addWidget(dashboardWidget); } AxivionOutputPane::~AxivionOutputPane() @@ -91,7 +169,12 @@ void AxivionOutputPane::goToPrev() void AxivionOutputPane::updateDashboard() { - + if (auto dashboard = static_cast(m_outputWidget->widget(0))) { + dashboard->updateUi(); + m_outputWidget->setCurrentIndex(0); + if (dashboard->hasProject()) + flash(); + } } } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index f3e6cd8c184..75186c30390 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -149,6 +149,12 @@ void AxivionPlugin::fetchProjectInfo(const QString &projectName) dd->fetchProjectInfo(projectName); } +ProjectInfo AxivionPlugin::projectInfo() +{ + QTC_ASSERT(dd, return {}); + return dd->currentProjectInfo; +} + void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) { if (runningQuery) { // re-schedule diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index fb0da44cbd0..86f23ee5923 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -11,6 +11,7 @@ namespace Axivion::Internal { class AxivionSettings; class AxivionProjectSettings; +class ProjectInfo; class AxivionPlugin final : public ExtensionSystem::IPlugin { @@ -27,7 +28,7 @@ public: static bool handleCertificateIssue(); static void fetchProjectInfo(const QString &projectName); - + static ProjectInfo projectInfo(); signals: void settingsChanged(); diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 00844d10746..74fa66fcdcf 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -148,6 +148,7 @@ void AxivionProjectSettingsWidget::unlinkProject() m_projectSettings->setDashboardProjectName({}); updateUi(); + AxivionPlugin::fetchProjectInfo({}); } void AxivionProjectSettingsWidget::updateUi() From 3503efff551aad7bb0e944bc323df2ce436ae116 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 23:11:46 +0100 Subject: [PATCH 0014/1447] Perform style violation query on file open Enable style violation queries on files and create some annotations for the results. This is just a first step to have visible results, but will need further tweaking and improvements at several areas. Change-Id: Icead2c5232194e7c3beb027d3f7975c90ecadeb5 Reviewed-by: David Schulz --- plugins/axivion/CMakeLists.txt | 2 +- plugins/axivion/axivion.qbs | 1 + plugins/axivion/axivionplugin.cpp | 74 ++++++++++++++++++++++++ plugins/axivion/axivionquery.cpp | 7 +++ plugins/axivion/axivionquery.h | 2 +- plugins/axivion/axivionresultparser.cpp | 76 +++++++++++++++++++++++-- plugins/axivion/axivionresultparser.h | 19 +++++++ 7 files changed, 175 insertions(+), 6 deletions(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 61ad3c7857a..f904cf308f9 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -8,7 +8,7 @@ endif() add_qtc_plugin(Axivion PLUGIN_DEPENDS - QtCreator::Core QtCreator::ProjectExplorer + QtCreator::Core QtCreator::ProjectExplorer QtCreator::TextEditor ${LICENSECHECKER_DEPENDS} DEPENDS Qt5::Network Qt5::Widgets QtCreator::ExtensionSystem QtCreator::Utils SOURCES diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs index 1e437bb357a..4e20de194ba 100644 --- a/plugins/axivion/axivion.qbs +++ b/plugins/axivion/axivion.qbs @@ -5,6 +5,7 @@ QtcCommercialPlugin { Depends { name: "Core" } Depends { name: "ProjectExplorer" } + Depends { name: "TextEditor" } Depends { name: "ExtensionSystem" } Depends { name: "Utils" } Depends { name: "Qt.widgets" } diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 75186c30390..81accb47c58 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -11,12 +11,16 @@ #include "axivionsettingspage.h" #include "axiviontr.h" +#include #include #include #include #include #include #include +#include +#include +#include #include #ifdef LICENSECHECKER @@ -33,6 +37,9 @@ class AxivionPluginPrivate : public QObject public: void fetchProjectInfo(const QString &projectName); void handleProjectInfo(const ProjectInfo &info); + void onDocumentOpened(Core::IDocument *doc); + void onDocumentClosed(Core::IDocument * doc); + void handleIssuesForFile(const IssuesList &issues); AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; @@ -91,6 +98,10 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::startupProjectChanged, this, &AxivionPlugin::onStartupProjectChanged); + connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, + dd, &AxivionPluginPrivate::onDocumentOpened); + connect(Core::EditorManager::instance(), &Core::EditorManager::documentClosed, + dd, &AxivionPluginPrivate::onDocumentClosed); return true; } @@ -187,6 +198,69 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) currentProjectInfo = info; axivionOutputPane.updateDashboard(); + + if (currentProjectInfo.name.isEmpty()) + return; + // FIXME handle already opened documents +} + +void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) +{ + if (currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) + return; + + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!doc || !project->isKnownFile(doc->filePath())) + return; + + Utils::FilePath relative = doc->filePath().relativeChildPath(project->projectDirectory()); + // for now only style violations + AxivionQuery query(AxivionQuery::IssuesForFileList, {currentProjectInfo.name, "SV", + relative.path() } ); + AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); + connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ + handleIssuesForFile(ResultParser::parseIssuesList(result)); + }); + connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); }); + runner->start(); +} + +void AxivionPluginPrivate::onDocumentClosed(Core::IDocument *doc) +{ + const auto document = qobject_cast(doc); + if (!document) + return; + + const TextEditor::TextMarks marks = document->marks(); + auto axivionId = Utils::Id("AxivionTextMark"); + for (auto m : marks) { + if (m->category() == axivionId) + delete m; + } +} + +void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) +{ + if (issues.issues.isEmpty()) + return; + + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!project) + return; + + const Utils::FilePath filePath = project->projectDirectory() + .pathAppended(issues.issues.first().filePath); + + auto axivionId = Utils::Id("AxivionTextMark"); + for (const ShortIssue &issue : std::as_const(issues.issues)) { + // FIXME the line location can be wrong (even the whole issue could be wrong) + // depending on whether this line has been changed since the last axivion run and the + // current state of the file - some magic has to happen here + auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, axivionId); + mark->setToolTip(issue.errorNumber + " " + issue.entity + ": " + issue.message); + mark->setPriority(TextEditor::TextMark::NormalPriority); + mark->setLineAnnotation(issue.errorNumber); + } } } // Axivion::Internal diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 4885b74ff46..4fa49bf75a3 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -33,6 +33,13 @@ QString AxivionQuery::toString() const QTC_ASSERT(m_parameters.size() == 1, return {}); query += "/projects/" + QUrl::toPercentEncoding(m_parameters.first()); return query; + case IssuesForFileList: + QTC_ASSERT(m_parameters.size() == 3, return {}); + // FIXME shall we validate the kind? (some kinds do not support path filter) + query += "/projects/" + QUrl::toPercentEncoding(m_parameters.first()) + + "/issues?kind=" + m_parameters.at(1) + "&filter_path=" + + QUrl::toPercentEncoding(m_parameters.at(2)) + "&format=csv"; + return query; } return {}; diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 721700ab3c2..6cf5ac07ae3 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -12,7 +12,7 @@ namespace Axivion::Internal { class AxivionQuery { public: - enum QueryType {NoQuery, DashboardInfo, ProjectInfo}; + enum QueryType {NoQuery, DashboardInfo, ProjectInfo, IssuesForFileList}; explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); QString toString() const; diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 4d765331623..9c7da845883 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -3,6 +3,8 @@ #include "axivionresultparser.h" +#include + #include #include #include @@ -37,13 +39,12 @@ static int httpStatus(const QByteArray &header) return match.hasMatch() ? match.captured(1).toInt() : 601; } -static std::pair prehandleHeaderAndBody(const QByteArray &header, - const QByteArray &body) +static BaseResult prehandleHeader(const QByteArray &header, const QByteArray &body) { BaseResult result; if (header.isEmpty()) { result.error = QString::fromUtf8(body); // we likely had a curl problem - return {result, {}}; + return result; } int status = httpStatus(header); if ((status > 399) || (status > 299 && body.isEmpty())) { // FIXME handle some explicitly? @@ -52,8 +53,16 @@ static std::pair prehandleHeaderAndBody(const QByteAr result.error = QLatin1String("(%1)").arg(statusStr); else result.error = QLatin1String("%1 (%2)").arg(QString::fromUtf8(body)).arg(statusStr); - return {result, {}}; } + return result; +} + +static std::pair prehandleHeaderAndBody(const QByteArray &header, + const QByteArray &body) +{ + BaseResult result = prehandleHeader(header, body); + if (!result.error.isEmpty()) + return {result, {}}; QJsonParseError error; const QJsonDocument doc = QJsonDocument::fromJson(body, &error); @@ -264,6 +273,65 @@ ProjectInfo parseProjectInfo(const QByteArray &input) return result; } +static QRegularExpression issueCsvLineRegex(const QByteArray &firstCsvLine) +{ + QString pattern = "^"; + for (const QByteArray &part : firstCsvLine.split(',')) { + const QString cleaned = QString::fromUtf8(part).remove(' ').chopped(1).mid(1); + pattern.append(QString("\"(?<" + cleaned + ">.*)\",")); + } + pattern.chop(1); // remove last comma + pattern.append('$'); + const QRegularExpression regex(pattern); + QTC_ASSERT(regex.isValid(), return {}); + return regex; +} + +static void parseCsvIssue(const QByteArray &csv, QList *issues) +{ + QTC_ASSERT(issues, return); + + bool first = true; + std::optional regex; + for (auto &line : csv.split('\n')) { + if (first) { + regex.emplace(issueCsvLineRegex(line)); + first = false; + if (regex.value().pattern().isEmpty()) + return; + continue; + } + if (line.isEmpty()) + continue; + const QRegularExpressionMatch match = regex->match(QString::fromUtf8(line)); + QTC_ASSERT(match.hasMatch(), continue); + // FIXME: some of these are not present for all issue kinds! Limited to SV for now + ShortIssue issue; + issue.state = match.captured("State"); + issue.errorNumber = match.captured("ErrorNumber"); + issue.message = match.captured("Message"); + issue.entity = match.captured("Entity"); + issue.filePath = match.captured("Path"); + issue.severity = match.captured("Severity"); + issue.lineNumber = match.captured("Line").toInt(); + issues->append(issue); + } +} + +IssuesList parseIssuesList(const QByteArray &input) +{ + IssuesList result; + + auto [header, body] = splitHeaderAndBody(input); + BaseResult headerResult = prehandleHeader(header, body); + if (!headerResult.error.isEmpty()) { + result.error = headerResult.error; + return result; + } + parseCsvIssue(body, &result.issues); + return result; +} + } // ResultParser } // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index 9a308f9950e..b187a23afaf 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -70,10 +70,29 @@ public: QList issueKinds; }; +class ShortIssue : public BaseResult +{ +public: + QString state; + QString errorNumber; + QString message; + QString entity; + QString filePath; + QString severity; + int lineNumber = 0; +}; + +class IssuesList : public BaseResult +{ +public: + QList issues; +}; + namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input); ProjectInfo parseProjectInfo(const QByteArray &input); +IssuesList parseIssuesList(const QByteArray &input); } // ResultParser From fff125db97a95116699599d5ca3686fab9116d36 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 15:12:39 +0100 Subject: [PATCH 0015/1447] Handle opened documents when ProjectInfo is update When we receive a new project info we should update issues for documents that are opened already. As we do this only for files that are known to the current project we may need to postpone this until the project has been parsed for the first time. Change-Id: I4241efa9f8a51c1d79fa91e7265bdf359e3d5826 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 81accb47c58..cc17006976f 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -11,10 +11,12 @@ #include "axivionsettingspage.h" #include "axiviontr.h" +#include #include #include #include #include +#include #include #include #include @@ -37,6 +39,7 @@ class AxivionPluginPrivate : public QObject public: void fetchProjectInfo(const QString &projectName); void handleProjectInfo(const ProjectInfo &info); + void handleOpenedDocs(ProjectExplorer::Project *project); void onDocumentOpened(Core::IDocument *doc); void onDocumentClosed(Core::IDocument * doc); void handleIssuesForFile(const IssuesList &issues); @@ -188,6 +191,19 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) runner->start(); } +void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) +{ + if (project && ProjectExplorer::SessionManager::startupProject() != project) + return; + const QList openDocuments = Core::DocumentModel::openedDocuments(); + for (Core::IDocument *doc : openDocuments) + onDocumentOpened(doc); + if (project) + disconnect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::projectFinishedParsing, + this, &AxivionPluginPrivate::handleOpenedDocs); +} + void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) { runningQuery = false; @@ -201,7 +217,15 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) if (currentProjectInfo.name.isEmpty()) return; - // FIXME handle already opened documents + + // handle already opened documents + if (!ProjectExplorer::SessionManager::startupBuildSystem()->isParsing()) { + handleOpenedDocs(nullptr); + } else { + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::projectFinishedParsing, + this, &AxivionPluginPrivate::handleOpenedDocs); + } } void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) From 02b094fc97ad01baab9388a01e1613532501dbd0 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 22:34:56 +0100 Subject: [PATCH 0016/1447] Clear existing marks When unlinking a project or if the current startup project changes remove all existing marks to avoid showing outdated marks. Change-Id: I6578a0a145222191f5ec4228e9aeef924f70edf5 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index cc17006976f..9d4c3ff648b 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -42,6 +42,7 @@ public: void handleOpenedDocs(ProjectExplorer::Project *project); void onDocumentOpened(Core::IDocument *doc); void onDocumentClosed(Core::IDocument * doc); + void clearAllMarks(); void handleIssuesForFile(const IssuesList &issues); AxivionSettings axivionSettings; @@ -113,6 +114,7 @@ void AxivionPlugin::onStartupProjectChanged() QTC_ASSERT(dd, return); ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project) { + dd->clearAllMarks(); dd->currentProjectInfo = ProjectInfo(); dd->axivionOutputPane.updateDashboard(); return; @@ -175,6 +177,7 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) QTimer::singleShot(3000, [this, projectName]{ fetchProjectInfo(projectName); }); return; } + clearAllMarks(); if (projectName.isEmpty()) { currentProjectInfo = ProjectInfo(); axivionOutputPane.updateDashboard(); @@ -204,6 +207,13 @@ void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) this, &AxivionPluginPrivate::handleOpenedDocs); } +void AxivionPluginPrivate::clearAllMarks() +{ + const QList openDocuments = Core::DocumentModel::openedDocuments(); + for (Core::IDocument *doc : openDocuments) + onDocumentClosed(doc); +} + void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) { runningQuery = false; From cef8339785a20f31af96f0973b7d6f4ca62607d4 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 23:01:01 +0100 Subject: [PATCH 0017/1447] Move function into plugin private Change-Id: Ia69c39cf4dccefc5d712153628aaaeae3a075c5e Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 54 +++++++++++++++++-------------- plugins/axivion/axivionplugin.h | 1 - 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 9d4c3ff648b..0d7496729c3 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -37,6 +37,8 @@ namespace Axivion::Internal { class AxivionPluginPrivate : public QObject { public: + AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); + void onStartupProjectChanged(); void fetchProjectInfo(const QString &projectName); void handleProjectInfo(const ProjectInfo &info); void handleOpenedDocs(ProjectExplorer::Project *project); @@ -48,7 +50,7 @@ public: AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; AxivionOutputPane axivionOutputPane; - QHash projectSettings; + QHash axivionProjectSettings; ProjectInfo currentProjectInfo; bool runningQuery = false; }; @@ -63,9 +65,9 @@ AxivionPlugin::AxivionPlugin() AxivionPlugin::~AxivionPlugin() { - if (!dd->projectSettings.isEmpty()) { - qDeleteAll(dd->projectSettings); - dd->projectSettings.clear(); + if (!dd->axivionProjectSettings.isEmpty()) { + qDeleteAll(dd->axivionProjectSettings); + dd->axivionProjectSettings.clear(); } delete dd; dd = nullptr; @@ -101,7 +103,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::startupProjectChanged, - this, &AxivionPlugin::onStartupProjectChanged); + dd, &AxivionPluginPrivate::onStartupProjectChanged); connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, dd, &AxivionPluginPrivate::onDocumentOpened); connect(Core::EditorManager::instance(), &Core::EditorManager::documentClosed, @@ -109,21 +111,6 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return true; } -void AxivionPlugin::onStartupProjectChanged() -{ - QTC_ASSERT(dd, return); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); - if (!project) { - dd->clearAllMarks(); - dd->currentProjectInfo = ProjectInfo(); - dd->axivionOutputPane.updateDashboard(); - return; - } - - const AxivionProjectSettings *projSettings = projectSettings(project); - dd->fetchProjectInfo(projSettings->dashboardProjectName()); -} - AxivionSettings *AxivionPlugin::settings() { QTC_ASSERT(dd, return nullptr); @@ -135,10 +122,7 @@ AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project QTC_ASSERT(project, return nullptr); QTC_ASSERT(dd, return nullptr); - auto &settings = dd->projectSettings[project]; - if (!settings) - settings = new AxivionProjectSettings(project); - return settings; + return dd->projectSettings(project); } bool AxivionPlugin::handleCertificateIssue() @@ -171,6 +155,28 @@ ProjectInfo AxivionPlugin::projectInfo() return dd->currentProjectInfo; } +AxivionProjectSettings *AxivionPluginPrivate::projectSettings(ProjectExplorer::Project *project) +{ + auto &settings = axivionProjectSettings[project]; + if (!settings) + settings = new AxivionProjectSettings(project); + return settings; +} + +void AxivionPluginPrivate::onStartupProjectChanged() +{ + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!project) { + clearAllMarks(); + currentProjectInfo = ProjectInfo(); + axivionOutputPane.updateDashboard(); + return; + } + + const AxivionProjectSettings *projSettings = projectSettings(project); + fetchProjectInfo(projSettings->dashboardProjectName()); +} + void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) { if (runningQuery) { // re-schedule diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index 86f23ee5923..1cd33d0e99b 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -35,7 +35,6 @@ signals: private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} - void onStartupProjectChanged(); }; } // Axivion::Internal From ac532cb324aa8649b667dc140a6f1e5308f01d36 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 5 Jan 2023 10:08:15 +0100 Subject: [PATCH 0018/1447] Server config dialog button "Modify" -> "Ok" Change-Id: Ia0cd0e54de573ac408309caa9721ffbc33b0816f Reviewed-by: David Schulz Reviewed-by: Christian Stenger --- plugins/axivion/axivionsettingspage.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index bd0ddee04c9..bcbced865c9 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -173,13 +173,13 @@ void AxivionSettingsWidget::showEditServerDialog() DashboardWidget *dashboardWidget = new DashboardWidget(DashboardWidget::Edit, this); dashboardWidget->setDashboardServer(old); layout->addWidget(dashboardWidget); - auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel, this); - auto modify = buttons->addButton(Tr::tr("Modify"), QDialogButtonBox::AcceptRole); - modify->setEnabled(m_dashboardDisplay->isValid()); + auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, this); + auto ok = buttons->button(QDialogButtonBox::Ok); + ok->setEnabled(m_dashboardDisplay->isValid()); connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, &d, &QDialog::reject); - connect(modify, &QPushButton::clicked, &d, &QDialog::accept); + connect(ok, &QPushButton::clicked, &d, &QDialog::accept); connect(dashboardWidget, &DashboardWidget::validChanged, - modify, &QPushButton::setEnabled); + ok, &QPushButton::setEnabled); layout->addWidget(buttons); d.setLayout(layout); d.resize(500, 200); From 76212ed1321fdd4b73b75f54e2a5405c7f5aea5c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 23 Dec 2022 14:26:26 +0100 Subject: [PATCH 0019/1447] Build: Use version-less Qt targets Since we do not support Qt < 5.15 anymore. Change-Id: I2585427f4095ffc8507f5de63b6866e1a308b3dd Reviewed-by: Christian Stenger --- plugins/axivion/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index f904cf308f9..594740d8fc3 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -10,7 +10,7 @@ add_qtc_plugin(Axivion PLUGIN_DEPENDS QtCreator::Core QtCreator::ProjectExplorer QtCreator::TextEditor ${LICENSECHECKER_DEPENDS} - DEPENDS Qt5::Network Qt5::Widgets QtCreator::ExtensionSystem QtCreator::Utils + DEPENDS Qt::Network Qt::Widgets QtCreator::ExtensionSystem QtCreator::Utils SOURCES axivion.qrc axivionoutputpane.cpp axivionoutputpane.h From 633e1bb73100fd6dc532222409987772112cdcca Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 6 Jan 2023 15:51:59 +0100 Subject: [PATCH 0020/1447] Make line annotations more descriptive Change-Id: I7c8936cebbf944640af90c1b19f7b9294c0edbed Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 0d7496729c3..c06bf1d40c3 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -297,9 +297,11 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) // depending on whether this line has been changed since the last axivion run and the // current state of the file - some magic has to happen here auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, axivionId); - mark->setToolTip(issue.errorNumber + " " + issue.entity + ": " + issue.message); + const QString markText = issue.entity.isEmpty() ? issue.message + : issue.entity + ": " + issue.message; + mark->setToolTip(issue.errorNumber + " " + markText); mark->setPriority(TextEditor::TextMark::NormalPriority); - mark->setLineAnnotation(issue.errorNumber); + mark->setLineAnnotation(markText); } } From 22df847631158ccc01d9a98ba0d45f33bd005843 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 9 Jan 2023 07:31:50 +0100 Subject: [PATCH 0021/1447] Use static variable for text mark id Change-Id: I4a928f14d8e1efc34b70d92a4f71d354c02c7fb7 Reviewed-by: Christian Stenger --- plugins/axivion/axivionplugin.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index c06bf1d40c3..bb2284e1532 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -32,6 +32,8 @@ #include #include +constexpr char AxivionTextMarkId[] = "AxivionTextMark"; + namespace Axivion::Internal { class AxivionPluginPrivate : public QObject @@ -272,9 +274,8 @@ void AxivionPluginPrivate::onDocumentClosed(Core::IDocument *doc) return; const TextEditor::TextMarks marks = document->marks(); - auto axivionId = Utils::Id("AxivionTextMark"); for (auto m : marks) { - if (m->category() == axivionId) + if (m->category() == AxivionTextMarkId) delete m; } } @@ -291,7 +292,7 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) const Utils::FilePath filePath = project->projectDirectory() .pathAppended(issues.issues.first().filePath); - auto axivionId = Utils::Id("AxivionTextMark"); + const Utils::Id axivionId(AxivionTextMarkId); for (const ShortIssue &issue : std::as_const(issues.issues)) { // FIXME the line location can be wrong (even the whole issue could be wrong) // depending on whether this line has been changed since the last axivion run and the From 96bbd32edfba97999f64523f741c85c95910e2c1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 9 Jan 2023 07:41:22 +0100 Subject: [PATCH 0022/1447] Use common member style Change-Id: I9a71c4906a56ae65f21bc271220c783d8056e748 Reviewed-by: Christian Stenger --- plugins/axivion/axivionplugin.cpp | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index bb2284e1532..a12f4a010cf 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -49,12 +49,12 @@ public: void clearAllMarks(); void handleIssuesForFile(const IssuesList &issues); - AxivionSettings axivionSettings; - AxivionSettingsPage axivionSettingsPage{&axivionSettings}; - AxivionOutputPane axivionOutputPane; - QHash axivionProjectSettings; - ProjectInfo currentProjectInfo; - bool runningQuery = false; + AxivionSettings m_axivionSettings; + AxivionSettingsPage m_axivionSettingsPage{&m_axivionSettings}; + AxivionOutputPane m_axivionOutputPane; + QHash m_axivionProjectSettings; + ProjectInfo m_currentProjectInfo; + bool m_runningQuery = false; }; static AxivionPlugin *s_instance = nullptr; @@ -67,9 +67,9 @@ AxivionPlugin::AxivionPlugin() AxivionPlugin::~AxivionPlugin() { - if (!dd->axivionProjectSettings.isEmpty()) { - qDeleteAll(dd->axivionProjectSettings); - dd->axivionProjectSettings.clear(); + if (!dd->m_axivionProjectSettings.isEmpty()) { + qDeleteAll(dd->m_axivionProjectSettings); + dd->m_axivionProjectSettings.clear(); } delete dd; dd = nullptr; @@ -94,7 +94,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa #endif // LICENSECHECKER dd = new AxivionPluginPrivate; - dd->axivionSettings.fromSettings(Core::ICore::settings()); + dd->m_axivionSettings.fromSettings(Core::ICore::settings()); auto panelFactory = new ProjectExplorer::ProjectPanelFactory; panelFactory->setPriority(250); @@ -116,7 +116,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa AxivionSettings *AxivionPlugin::settings() { QTC_ASSERT(dd, return nullptr); - return &dd->axivionSettings; + return &dd->m_axivionSettings; } AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project *project) @@ -131,7 +131,7 @@ bool AxivionPlugin::handleCertificateIssue() { QTC_ASSERT(dd, return false); - const QString serverHost = QUrl(dd->axivionSettings.server.dashboard).host(); + const QString serverHost = QUrl(dd->m_axivionSettings.server.dashboard).host(); if (QMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Certificate Error"), Tr::tr("Server certificate for %1 cannot be authenticated.\n" "Do you want to disable SSL verification for this server?\n" @@ -140,7 +140,7 @@ bool AxivionPlugin::handleCertificateIssue() != QMessageBox::Yes) { return false; } - dd->axivionSettings.server.validateCert = false; + dd->m_axivionSettings.server.validateCert = false; emit s_instance->settingsChanged(); return true; } @@ -154,12 +154,12 @@ void AxivionPlugin::fetchProjectInfo(const QString &projectName) ProjectInfo AxivionPlugin::projectInfo() { QTC_ASSERT(dd, return {}); - return dd->currentProjectInfo; + return dd->m_currentProjectInfo; } AxivionProjectSettings *AxivionPluginPrivate::projectSettings(ProjectExplorer::Project *project) { - auto &settings = axivionProjectSettings[project]; + auto &settings = m_axivionProjectSettings[project]; if (!settings) settings = new AxivionProjectSettings(project); return settings; @@ -170,8 +170,8 @@ void AxivionPluginPrivate::onStartupProjectChanged() ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project) { clearAllMarks(); - currentProjectInfo = ProjectInfo(); - axivionOutputPane.updateDashboard(); + m_currentProjectInfo = ProjectInfo(); + m_axivionOutputPane.updateDashboard(); return; } @@ -181,17 +181,17 @@ void AxivionPluginPrivate::onStartupProjectChanged() void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) { - if (runningQuery) { // re-schedule + if (m_runningQuery) { // re-schedule QTimer::singleShot(3000, [this, projectName]{ fetchProjectInfo(projectName); }); return; } clearAllMarks(); if (projectName.isEmpty()) { - currentProjectInfo = ProjectInfo(); - axivionOutputPane.updateDashboard(); + m_currentProjectInfo = ProjectInfo(); + m_axivionOutputPane.updateDashboard(); return; } - runningQuery = true; + m_runningQuery = true; AxivionQuery query(AxivionQuery::ProjectInfo, {projectName}); AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); @@ -224,16 +224,16 @@ void AxivionPluginPrivate::clearAllMarks() void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) { - runningQuery = false; + m_runningQuery = false; if (!info.error.isEmpty()) { Core::MessageManager::writeFlashing("Axivion: " + info.error); return; } - currentProjectInfo = info; - axivionOutputPane.updateDashboard(); + m_currentProjectInfo = info; + m_axivionOutputPane.updateDashboard(); - if (currentProjectInfo.name.isEmpty()) + if (m_currentProjectInfo.name.isEmpty()) return; // handle already opened documents @@ -248,7 +248,7 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) { - if (currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) + if (m_currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) return; ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); @@ -257,7 +257,7 @@ void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) Utils::FilePath relative = doc->filePath().relativeChildPath(project->projectDirectory()); // for now only style violations - AxivionQuery query(AxivionQuery::IssuesForFileList, {currentProjectInfo.name, "SV", + AxivionQuery query(AxivionQuery::IssuesForFileList, {m_currentProjectInfo.name, "SV", relative.path() } ); AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ From f994d27bf5efd33ffdc89e707d75aa9e331a7b64 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 11 Jan 2023 10:04:24 +0100 Subject: [PATCH 0023/1447] Adapt to upstream change Change-Id: Ib86208aa4209580854b98971e436a521020211f6 Reviewed-by: hjk --- plugins/axivion/axivionquery.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 4fa49bf75a3..090b5c7194a 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -75,9 +75,9 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren start(); return; } - emit resultRetrieved(m_process.readAllStandardError()); + emit resultRetrieved(m_process.readAllRawStandardError()); } else { - emit resultRetrieved(m_process.readAllStandardOutput()); + emit resultRetrieved(m_process.readAllRawStandardOutput()); } emit finished(); }); From 6221871b2f0feb7bb66aa6a229d1bbe81b95946c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 12 Jan 2023 09:45:41 +0100 Subject: [PATCH 0024/1447] Rename one of the DashboardWidgets This is confusing on and even led to crashes on macOS. Change-Id: I4227a091f2b2ac90405494a1a8b206c4ea672030 Reviewed-by: David Schulz --- plugins/axivion/axivionsettingspage.cpp | 16 ++++++++-------- plugins/axivion/axivionsettingspage.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index bcbced865c9..57c258c7e08 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -46,7 +46,7 @@ static bool isUrlValid(const QString &in) return hostValid(url.host()) && url.scheme() == "https" || url.scheme() == "http"; } -DashboardWidget::DashboardWidget(Mode mode, QWidget *parent) +DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) : QWidget(parent) , m_mode(mode) { @@ -91,7 +91,7 @@ DashboardWidget::DashboardWidget(Mode mode, QWidget *parent) } } -AxivionServer DashboardWidget::dashboardServer() const +AxivionServer DashboardSettingsWidget::dashboardServer() const { AxivionServer result; if (m_id.isValid()) @@ -104,7 +104,7 @@ AxivionServer DashboardWidget::dashboardServer() const return result; } -void DashboardWidget::setDashboardServer(const AxivionServer &server) +void DashboardSettingsWidget::setDashboardServer(const AxivionServer &server) { m_id = server.id; m_dashboardUrl.setValue(server.dashboard); @@ -112,7 +112,7 @@ void DashboardWidget::setDashboardServer(const AxivionServer &server) m_token.setValue(server.token); } -bool DashboardWidget::isValid() const +bool DashboardSettingsWidget::isValid() const { return !m_token.value().isEmpty() && !m_description.value().isEmpty() && isUrlValid(m_dashboardUrl.value()); @@ -130,7 +130,7 @@ private: AxivionSettings *m_settings; Utils::StringAspect m_curlPC; - DashboardWidget *m_dashboardDisplay = nullptr; + DashboardSettingsWidget *m_dashboardDisplay = nullptr; QPushButton *m_edit = nullptr; }; @@ -139,7 +139,7 @@ AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) { using namespace Layouting; - m_dashboardDisplay = new DashboardWidget(DashboardWidget::Display, this); + m_dashboardDisplay = new DashboardSettingsWidget(DashboardSettingsWidget::Display, this); m_dashboardDisplay->setDashboardServer(m_settings->server); m_edit = new QPushButton(Tr::tr("Edit..."), this); m_curlPC.setLabelText(Tr::tr("curl:")); @@ -170,7 +170,7 @@ void AxivionSettingsWidget::showEditServerDialog() QDialog d; d.setWindowTitle(Tr::tr("Edit Dashboard Configuration")); QVBoxLayout *layout = new QVBoxLayout; - DashboardWidget *dashboardWidget = new DashboardWidget(DashboardWidget::Edit, this); + DashboardSettingsWidget *dashboardWidget = new DashboardSettingsWidget(DashboardSettingsWidget::Edit, this); dashboardWidget->setDashboardServer(old); layout->addWidget(dashboardWidget); auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, this); @@ -178,7 +178,7 @@ void AxivionSettingsWidget::showEditServerDialog() ok->setEnabled(m_dashboardDisplay->isValid()); connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, &d, &QDialog::reject); connect(ok, &QPushButton::clicked, &d, &QDialog::accept); - connect(dashboardWidget, &DashboardWidget::validChanged, + connect(dashboardWidget, &DashboardSettingsWidget::validChanged, ok, &QPushButton::setEnabled); layout->addWidget(buttons); d.setLayout(layout); diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h index 02cfb81ffa9..5d1fc9c8b8d 100644 --- a/plugins/axivion/axivionsettingspage.h +++ b/plugins/axivion/axivionsettingspage.h @@ -16,12 +16,12 @@ class AxivionServer; class AxivionSettings; class AxivionSettingsWidget; -class DashboardWidget : public QWidget +class DashboardSettingsWidget : public QWidget { Q_OBJECT public: enum Mode { Display, Edit }; - explicit DashboardWidget(Mode m = Display, QWidget *parent = nullptr); + explicit DashboardSettingsWidget(Mode m = Display, QWidget *parent = nullptr); AxivionServer dashboardServer() const; void setDashboardServer(const AxivionServer &server); From 0056df7584ab272b53ddc872f19e47054ba27aad Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 12 Jan 2023 09:52:24 +0100 Subject: [PATCH 0025/1447] Fix possible nullptr access Change-Id: I89555a9ac6cd06f7c902893f40e1e3757b14f971 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index a12f4a010cf..bc2f6bed1a7 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -237,7 +237,8 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) return; // handle already opened documents - if (!ProjectExplorer::SessionManager::startupBuildSystem()->isParsing()) { + if (auto buildSystem = ProjectExplorer::SessionManager::startupBuildSystem(); + !buildSystem || !buildSystem->isParsing()) { handleOpenedDocs(nullptr); } else { connect(ProjectExplorer::SessionManager::instance(), From 2dc03f41d0adb9ee7277130c1df7625291b7e5d7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 11 Jan 2023 14:44:27 +0100 Subject: [PATCH 0026/1447] Make dashboard widget scrollable Change-Id: I81a58f52edeaec150d7210b3154d055e4751784e Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index b1b4ec98a1b..c48326863f4 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -11,11 +11,12 @@ #include #include +#include #include namespace Axivion::Internal { -class DashboardWidget : public QWidget +class DashboardWidget : public QScrollArea { public: explicit DashboardWidget(QWidget *parent = nullptr); @@ -28,9 +29,10 @@ private: }; DashboardWidget::DashboardWidget(QWidget *parent) - : QWidget(parent) + : QScrollArea(parent) { - QVBoxLayout *layout = new QVBoxLayout(this); + QWidget *widget = new QWidget(this); + QVBoxLayout *layout = new QVBoxLayout(widget); QFormLayout *projectLayout = new QFormLayout; m_project = new QLabel(this); projectLayout->addRow(Tr::tr("Project:"), m_project); @@ -39,6 +41,9 @@ DashboardWidget::DashboardWidget(QWidget *parent) layout->addLayout(projectLayout); m_formLayout = new QFormLayout; layout->addLayout(m_formLayout); + setWidget(widget); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setWidgetResizable(true); } void DashboardWidget::updateUi() From becd66a4fc6030cc7c21050fa3e26a54aad6cf03 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 12 Jan 2023 12:01:51 +0100 Subject: [PATCH 0027/1447] Adapt to upstream change Change-Id: Ibfa287e1df09d3984b572569bd3fdfa9f2fd9497 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index bc2f6bed1a7..ced5d37597c 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -276,7 +276,7 @@ void AxivionPluginPrivate::onDocumentClosed(Core::IDocument *doc) const TextEditor::TextMarks marks = document->marks(); for (auto m : marks) { - if (m->category() == AxivionTextMarkId) + if (m->category().id == AxivionTextMarkId) delete m; } } @@ -298,7 +298,8 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) // FIXME the line location can be wrong (even the whole issue could be wrong) // depending on whether this line has been changed since the last axivion run and the // current state of the file - some magic has to happen here - auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, axivionId); + auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, + {Tr::tr("Axivion"), axivionId}); const QString markText = issue.entity.isEmpty() ? issue.message : issue.entity + ": " + issue.message; mark->setToolTip(issue.errorNumber + " " + markText); From 4b3f5a04e2a9b96a71ba6f24a88e998804e0ff45 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 13 Jan 2023 13:43:07 +0100 Subject: [PATCH 0028/1447] Fix operator precedence problem Change-Id: Id3af6e4a88cba97072053b28d8b7a7f65f76f91c Reviewed-by: Christian Stenger --- plugins/axivion/axivionsettingspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index 57c258c7e08..cb144371d9e 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -43,7 +43,7 @@ static bool hostValid(const QString &host) static bool isUrlValid(const QString &in) { const QUrl url(in); - return hostValid(url.host()) && url.scheme() == "https" || url.scheme() == "http"; + return hostValid(url.host()) && (url.scheme() == "https" || url.scheme() == "http"); } DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) From 134b71a45a14dfb4e3c1d9bd47ac59bf836b5f4d Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 13 Jan 2023 13:49:40 +0100 Subject: [PATCH 0029/1447] Extract text mark functionality into own class Enhance issue information by id of the issue to be able to retrieve further details later. Change-Id: Ia6ff5c8a0064c45b50f9c712a05f6271f356e59a Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 28 ++++++++++++++++++------- plugins/axivion/axivionresultparser.cpp | 1 + plugins/axivion/axivionresultparser.h | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index ced5d37597c..c431af66e7a 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -60,6 +60,26 @@ public: static AxivionPlugin *s_instance = nullptr; static AxivionPluginPrivate *dd = nullptr; +class AxivionTextMark : public TextEditor::TextMark +{ +public: + AxivionTextMark(const Utils::FilePath &filePath, const ShortIssue &issue); + +private: + QString m_id; +}; + +AxivionTextMark::AxivionTextMark(const Utils::FilePath &filePath, const ShortIssue &issue) + : TextEditor::TextMark(filePath, issue.lineNumber, {Tr::tr("Axivion"), AxivionTextMarkId}) + , m_id(issue.id) +{ + const QString markText = issue.entity.isEmpty() ? issue.message + : issue.entity + ": " + issue.message; + setToolTip(issue.errorNumber + " " + markText); + setPriority(TextEditor::TextMark::NormalPriority); + setLineAnnotation(markText); +} + AxivionPlugin::AxivionPlugin() { s_instance = this; @@ -298,13 +318,7 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) // FIXME the line location can be wrong (even the whole issue could be wrong) // depending on whether this line has been changed since the last axivion run and the // current state of the file - some magic has to happen here - auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, - {Tr::tr("Axivion"), axivionId}); - const QString markText = issue.entity.isEmpty() ? issue.message - : issue.entity + ": " + issue.message; - mark->setToolTip(issue.errorNumber + " " + markText); - mark->setPriority(TextEditor::TextMark::NormalPriority); - mark->setLineAnnotation(markText); + new AxivionTextMark(filePath, issue); } } diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 9c7da845883..e2b9713f576 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -307,6 +307,7 @@ static void parseCsvIssue(const QByteArray &csv, QList *issues) QTC_ASSERT(match.hasMatch(), continue); // FIXME: some of these are not present for all issue kinds! Limited to SV for now ShortIssue issue; + issue.id = match.captured("Id"); issue.state = match.captured("State"); issue.errorNumber = match.captured("ErrorNumber"); issue.message = match.captured("Message"); diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index b187a23afaf..c4b0c376f75 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -73,6 +73,7 @@ public: class ShortIssue : public BaseResult { public: + QString id; QString state; QString errorNumber; QString message; From 5fb06bdeb9f883b95be66e86561611616411fcb7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 13 Jan 2023 14:38:39 +0100 Subject: [PATCH 0030/1447] Add possibility to fetch rule details for issues Allows to fetch further information of an issue and display it inside the output pane. Change-Id: I94ec27b9c060dca9f9523d763b8628a2fce7ca59 Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 14 +++++++++++ plugins/axivion/axivionoutputpane.h | 1 + plugins/axivion/axivionplugin.cpp | 31 +++++++++++++++++++++++++ plugins/axivion/axivionquery.cpp | 7 +++++- plugins/axivion/axivionquery.h | 2 +- plugins/axivion/axivionresultparser.cpp | 9 +++++++ plugins/axivion/axivionresultparser.h | 1 + 7 files changed, 63 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index c48326863f4..0021f03dc40 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace Axivion::Internal { @@ -98,6 +99,8 @@ AxivionOutputPane::AxivionOutputPane(QObject *parent) m_outputWidget = new QStackedWidget; DashboardWidget *dashboardWidget = new DashboardWidget(m_outputWidget); m_outputWidget->addWidget(dashboardWidget); + QTextBrowser *browser = new QTextBrowser(m_outputWidget); + m_outputWidget->addWidget(browser); } AxivionOutputPane::~AxivionOutputPane() @@ -182,4 +185,15 @@ void AxivionOutputPane::updateDashboard() } } +void AxivionOutputPane::updateAndShowRule(const QString &ruleHtml) +{ + if (auto browser = static_cast(m_outputWidget->widget(1))) { + browser->setText(ruleHtml); + if (!ruleHtml.isEmpty()) { + m_outputWidget->setCurrentIndex(1); + popup(Core::IOutputPane::NoModeSwitch); + } + } +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h index 81b1647154c..aea4354e02e 100644 --- a/plugins/axivion/axivionoutputpane.h +++ b/plugins/axivion/axivionoutputpane.h @@ -34,6 +34,7 @@ public: void goToPrev() override; void updateDashboard(); + void updateAndShowRule(const QString &ruleHtml); private: QStackedWidget *m_outputWidget = nullptr; }; diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index c431af66e7a..9f626656437 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -24,11 +24,13 @@ #include #include #include +#include #ifdef LICENSECHECKER # include #endif +#include #include #include @@ -48,6 +50,7 @@ public: void onDocumentClosed(Core::IDocument * doc); void clearAllMarks(); void handleIssuesForFile(const IssuesList &issues); + void fetchRuleInfo(const QString &id); AxivionSettings m_axivionSettings; AxivionSettingsPage m_axivionSettingsPage{&m_axivionSettings}; @@ -78,6 +81,14 @@ AxivionTextMark::AxivionTextMark(const Utils::FilePath &filePath, const ShortIss setToolTip(issue.errorNumber + " " + markText); setPriority(TextEditor::TextMark::NormalPriority); setLineAnnotation(markText); + setActionsProvider([this]{ + auto action = new QAction; + action->setIcon(Utils::Icons::INFO.icon()); + action->setToolTip(Tr::tr("Show rule details")); + QObject::connect(action, &QAction::triggered, + dd, [this]{ dd->fetchRuleInfo(m_id); }); + return QList{action}; + }); } AxivionPlugin::AxivionPlugin() @@ -222,6 +233,26 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) runner->start(); } +void AxivionPluginPrivate::fetchRuleInfo(const QString &id) +{ + if (m_runningQuery) { + QTimer::singleShot(3000, [this, id]{ fetchRuleInfo(id); }); + return; + } + + const QStringList args = id.split(':'); + QTC_ASSERT(args.size() == 2, return); + m_runningQuery = true; + AxivionQuery query(AxivionQuery::RuleInfo, args); + AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); + connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ + m_runningQuery = false; + m_axivionOutputPane.updateAndShowRule(ResultParser::parseRuleInfo(result)); + }); + connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); }); + runner->start(); +} + void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) { if (project && ProjectExplorer::SessionManager::startupProject() != project) diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 090b5c7194a..fbf0ec61936 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -23,7 +23,7 @@ AxivionQuery::AxivionQuery(QueryType type, const QStringList ¶meters) QString AxivionQuery::toString() const { - QString query = "/api"; // common for all + QString query = "/api"; // common for all except RuleInfo switch (m_type) { case NoQuery: return {}; @@ -40,6 +40,11 @@ QString AxivionQuery::toString() const + "/issues?kind=" + m_parameters.at(1) + "&filter_path=" + QUrl::toPercentEncoding(m_parameters.at(2)) + "&format=csv"; return query; + case RuleInfo: + QTC_ASSERT(m_parameters.size() == 2, return {}); + query = "/projects/" + QUrl::toPercentEncoding(m_parameters.first()) + + "/issues/" + m_parameters.at(1) + "/rule"; + return query; } return {}; diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 6cf5ac07ae3..63b64a52f9b 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -12,7 +12,7 @@ namespace Axivion::Internal { class AxivionQuery { public: - enum QueryType {NoQuery, DashboardInfo, ProjectInfo, IssuesForFileList}; + enum QueryType {NoQuery, DashboardInfo, ProjectInfo, IssuesForFileList, RuleInfo}; explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); QString toString() const; diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index e2b9713f576..ba483e8f72e 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -333,6 +333,15 @@ IssuesList parseIssuesList(const QByteArray &input) return result; } +QString parseRuleInfo(const QByteArray &input) // html result! +{ + auto [header, body] = splitHeaderAndBody(input); + BaseResult headerResult = prehandleHeader(header, body); + if (!headerResult.error.isEmpty()) + return QString(); + return QString::fromLocal8Bit(body); +} + } // ResultParser } // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index c4b0c376f75..090b05d10af 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -94,6 +94,7 @@ namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input); ProjectInfo parseProjectInfo(const QByteArray &input); IssuesList parseIssuesList(const QByteArray &input); +QString parseRuleInfo(const QByteArray &input); } // ResultParser From 935d04e9ac173f4c95e7087252a477dab42961e9 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 13 Jan 2023 15:43:01 +0100 Subject: [PATCH 0031/1447] Allow to switch to the main view Change-Id: Idd75b9c161d701898690681bf8141d3a8508ce7a Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index 0021f03dc40..5f3f8c16161 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -8,12 +8,14 @@ #include "axiviontr.h" #include +#include #include #include #include #include #include +#include namespace Axivion::Internal { @@ -121,6 +123,14 @@ QWidget *AxivionOutputPane::outputWidget(QWidget *parent) QList AxivionOutputPane::toolBarWidgets() const { QList buttons; + auto showDashboard = new QToolButton(m_outputWidget); + showDashboard->setIcon(Utils::Icons::ONLINE_TOOLBAR.icon()); + showDashboard->setToolTip(Tr::tr("Show dashboard")); + connect(showDashboard, &QToolButton::clicked, this, [this]{ + QTC_ASSERT(m_outputWidget, return); + m_outputWidget->setCurrentIndex(0); + }); + buttons.append(showDashboard); return buttons; } From d208ef3e9ad89a6ce0cc8433aa631a76535ab3da Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 23 Jan 2023 14:10:52 +0100 Subject: [PATCH 0032/1447] Build: Don't rely on FindQt5.cmake We only support Qt 6 nowadays. Change-Id: Id797467f03afeaaf36f33100461a7163ad27c0fa Reviewed-by: Christian Stenger --- plugins/axivion/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 594740d8fc3..8f311a885b8 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -1,5 +1,5 @@ find_package(QtCreator COMPONENTS Core REQUIRED) -find_package(Qt5 COMPONENTS Network Widgets REQUIRED) +find_package(Qt6 COMPONENTS Network Widgets REQUIRED) find_package(QtCreatorLicenseChecker QUIET) if (TARGET QtCreator::LicenseChecker) From 4e02fba933684b3f069b0e6a4bbaee1ac164aa15 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 26 Jan 2023 15:19:46 +0100 Subject: [PATCH 0033/1447] TextEditor: add inline suggestions Change-Id: I8c670a2aee17e461da1e3882d5b642da935b3d7a Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/textdocument.cpp | 13 +++ src/plugins/texteditor/textdocument.h | 2 + src/plugins/texteditor/textdocumentlayout.cpp | 55 ++++++++- src/plugins/texteditor/textdocumentlayout.h | 7 ++ src/plugins/texteditor/texteditor.cpp | 104 +++++++++++++++++- src/plugins/texteditor/texteditor.h | 3 + 6 files changed, 181 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 61c3b319b36..51fba77eb88 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -373,6 +373,13 @@ QAction *TextDocument::createDiffAgainstCurrentFileAction( return diffAction; } +void TextDocument::insertSuggestion(const QString text, const QTextBlock &block) +{ + TextDocumentLayout::userData(block)->setReplacement(block.text() + text); + TextDocumentLayout::updateReplacmentFormats(block, fontSettings()); + updateLayout(); +} + #ifdef WITH_TESTS void TextDocument::setSilentReload() { @@ -419,6 +426,12 @@ IAssistProvider *TextDocument::quickFixAssistProvider() const void TextDocument::applyFontSettings() { d->m_fontSettingsNeedsApply = false; + QTextBlock block = document()->firstBlock(); + while (block.isValid()) { + TextDocumentLayout::updateReplacmentFormats(block, fontSettings()); + block = block.next(); + } + updateLayout(); if (d->m_highlighter) { d->m_highlighter->setFontSettings(d->m_fontSettings); d->m_highlighter->rehighlight(); diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index dc52e1e9a8e..7a5797b7ca5 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -144,6 +144,8 @@ public: static QAction *createDiffAgainstCurrentFileAction(QObject *parent, const std::function &filePath); + void insertSuggestion(const QString text, const QTextBlock &block); + #ifdef WITH_TESTS void setSilentReload(); #endif diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index 1f26530dbb0..c160204e2f3 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -345,6 +345,13 @@ void TextBlockUserData::setCodeFormatterData(CodeFormatterData *data) m_codeFormatterData = data; } +void TextBlockUserData::setReplacement(const QString replacement) +{ + m_replacement.reset(new QTextDocument(replacement)); + m_replacement->setDocumentLayout(new TextDocumentLayout(m_replacement.get())); + m_replacement->setDocumentMargin(0); +} + void TextBlockUserData::addMark(TextMark *mark) { int i = 0; @@ -355,7 +362,6 @@ void TextBlockUserData::addMark(TextMark *mark) m_marks.insert(i, mark); } - TextDocumentLayout::TextDocumentLayout(QTextDocument *doc) : QPlainTextDocumentLayout(doc) {} @@ -519,6 +525,33 @@ QByteArray TextDocumentLayout::expectedRawStringSuffix(const QTextBlock &block) return {}; } +void TextDocumentLayout::updateReplacmentFormats(const QTextBlock &block, + const FontSettings &fontSettings) +{ + if (TextBlockUserData *userData = textUserData(block)) { + if (QTextDocument *replacement = userData->replacement()) { + const QTextCharFormat replacementFormat = fontSettings.toTextCharFormat( + TextStyles{C_TEXT, {C_DISABLED_CODE}}); + QTextCursor cursor(replacement); + cursor.select(QTextCursor::Document); + cursor.setCharFormat(fontSettings.toTextCharFormat(C_TEXT)); + cursor.setPosition(block.length() - 1); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + cursor.setCharFormat(replacementFormat); + replacement->firstBlock().layout()->setFormats(block.layout()->formats()); + } + } +} + +QString TextDocumentLayout::replacement(const QTextBlock &block) +{ + if (TextBlockUserData *userData = textUserData(block)) { + if (QTextDocument *replacement = userData->replacement()) + return replacement->toPlainText().mid(block.length() - 1); + } + return {}; +} + void TextDocumentLayout::requestExtraAreaUpdate() { emit updateExtraArea(); @@ -632,8 +665,28 @@ void TextDocumentLayout::requestUpdateNow() requestUpdate(); } +static QRectF replacementBoundingRect(const QTextDocument *replacement) +{ + QTC_ASSERT(replacement, return {}); + auto *layout = static_cast(replacement->documentLayout()); + QRectF boundingRect; + QTextBlock block = replacement->firstBlock(); + while (block.isValid()) { + const QRectF blockBoundingRect = layout->blockBoundingRect(block); + boundingRect.setWidth(std::max(boundingRect.width(), blockBoundingRect.width())); + boundingRect.setHeight(boundingRect.height() + blockBoundingRect.height()); + block = block.next(); + } + return boundingRect; +} + QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const { + if (TextBlockUserData *userData = textUserData(block)) { + if (auto replacement = userData->replacement()) + return replacementBoundingRect(replacement); + } + QRectF boundingRect = QPlainTextDocumentLayout::blockBoundingRect(block); if (TextEditorSettings::fontSettings().relativeLineSpacing() != 100) { diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index ba31398db7b..5da2dd8f997 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -126,6 +126,10 @@ public: QByteArray expectedRawStringSuffix() { return m_expectedRawStringSuffix; } void setExpectedRawStringSuffix(const QByteArray &suffix) { m_expectedRawStringSuffix = suffix; } + void setReplacement(const QString replacement); + void clearReplacement() { m_replacement.reset(); } + QTextDocument *replacement() const { return m_replacement.get(); } + private: TextMarks m_marks; int m_foldingIndent : 16; @@ -139,6 +143,7 @@ private: CodeFormatterData *m_codeFormatterData; KSyntaxHighlighting::State m_syntaxState; QByteArray m_expectedRawStringSuffix; // A bit C++-specific, but let's be pragmatic. + std::unique_ptr m_replacement; }; @@ -172,6 +177,8 @@ public: static void setFolded(const QTextBlock &block, bool folded); static void setExpectedRawStringSuffix(const QTextBlock &block, const QByteArray &suffix); static QByteArray expectedRawStringSuffix(const QTextBlock &block); + static void updateReplacmentFormats(const QTextBlock &block, const FontSettings &fontSettings); + static QString replacement(const QTextBlock &block); class TEXTEDITOR_EXPORT FoldValidator { diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 9c4b54c20f3..ca0ba9268c9 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -819,6 +819,10 @@ public: QStack m_undoCursorStack; QList m_visualIndentCache; int m_visualIndentOffset = 0; + + void insertSuggestion(const QString &suggestion, const QTextBlock &block); + void clearCurrentSuggestion(); + QTextBlock m_suggestionBlock; }; class TextEditorWidgetFind : public BaseTextFind @@ -1646,6 +1650,26 @@ void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperatio q->setMultiTextCursor(MultiTextCursor(cursors)); } +void TextEditorWidgetPrivate::insertSuggestion(const QString &suggestion, const QTextBlock &block) +{ + clearCurrentSuggestion(); + m_suggestionBlock = block; + m_document->insertSuggestion(suggestion, block); + auto cursor = q->textCursor(); + cursor.setPosition(block.position()); + cursor.movePosition(QTextCursor::EndOfBlock); + q->setTextCursor(cursor); +} + +void TextEditorWidgetPrivate::clearCurrentSuggestion() +{ + if (TextBlockUserData *userData = TextDocumentLayout::textUserData(m_suggestionBlock)) { + userData->clearReplacement(); + m_document->updateLayout(); + } + m_suggestionBlock = QTextBlock(); +} + void TextEditorWidget::selectEncoding() { TextDocument *doc = d->m_document.data(); @@ -1828,6 +1852,17 @@ TextEditorWidget *TextEditorWidget::fromEditor(const IEditor *editor) void TextEditorWidgetPrivate::editorContentsChange(int position, int charsRemoved, int charsAdded) { + if (m_suggestionBlock.isValid()) { + if (TextBlockUserData *data = TextDocumentLayout::textUserData(m_suggestionBlock)) { + if (auto replacementDocument = data->replacement()) { + if (replacementDocument->firstBlock().text().startsWith(m_suggestionBlock.text())) + TextDocumentLayout::updateReplacmentFormats(m_suggestionBlock, m_document->fontSettings()); + else + clearCurrentSuggestion(); + } + } + } + if (m_bracketsAnimator) m_bracketsAnimator->finish(); @@ -2506,6 +2541,11 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) d->m_maybeFakeTooltipEvent = false; if (e->key() == Qt::Key_Escape ) { TextEditorWidgetFind::cancelCurrentSelectAll(); + if (d->m_suggestionBlock.isValid()) { + d->clearCurrentSuggestion(); + e->accept(); + return; + } if (d->m_snippetOverlay->isVisible()) { e->accept(); d->m_snippetOverlay->accept(); @@ -2639,6 +2679,14 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) case Qt::Key_Tab: case Qt::Key_Backtab: { if (ro) break; + if (d->m_suggestionBlock.isValid()) { + QTextCursor cursor(d->m_suggestionBlock); + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.insertText(TextDocumentLayout::replacement(d->m_suggestionBlock)); + setTextCursor(cursor); + e->accept(); + return; + } if (d->m_snippetOverlay->isVisible() && !d->m_snippetOverlay->isEmpty()) { d->snippetTabOrBacktab(e->key() == Qt::Key_Tab); e->accept(); @@ -2684,6 +2732,8 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) | Qt::AltModifier | Qt::MetaModifier)) == Qt::NoModifier) { e->accept(); + if (d->m_suggestionBlock.isValid()) + d->clearCurrentSuggestion(); if (cursor.hasSelection()) { cursor.removeSelectedText(); setMultiTextCursor(cursor); @@ -2944,6 +2994,8 @@ void TextEditorWidgetPrivate::universalHelper() { // Test function for development. Place your new fangled experiment here to // give it proper scrutiny before pushing it onto others. + + insertSuggestion("Teste\nWeste\nBeste", q->textCursor().block()); } void TextEditorWidget::doSetTextCursor(const QTextCursor &cursor, bool keepMultiSelection) @@ -3105,7 +3157,9 @@ bool TextEditorWidget::event(QEvent *e) case QEvent::ShortcutOverride: { auto ke = static_cast(e); if (ke->key() == Qt::Key_Escape - && (d->m_snippetOverlay->isVisible() || multiTextCursor().hasMultipleCursors())) { + && (d->m_snippetOverlay->isVisible() + || multiTextCursor().hasMultipleCursors() + || d->m_suggestionBlock.isValid())) { e->accept(); } else { // hack copied from QInputControl::isCommonTextEditShortcut @@ -4394,7 +4448,22 @@ void TextEditorWidgetPrivate::paintAdditionalVisualWhitespaces(PaintEventData &d visualArrow); } if (!nextBlockIsValid) { // paint EOF symbol - QTextLine line = layout->lineAt(lineCount-1); + if (m_suggestionBlock.isValid() && data.block == m_suggestionBlock) { + if (TextBlockUserData *userData = TextDocumentLayout::textUserData( + m_suggestionBlock)) { + if (QTextDocument *replacement = userData->replacement()) { + const QTextBlock lastReplacementBlock = replacement->lastBlock(); + for (QTextBlock block = replacement->firstBlock(); + block != lastReplacementBlock && block.isValid(); + block = block.next()) { + top += replacement->documentLayout()->blockBoundingRect(block).height(); + } + layout = lastReplacementBlock.layout(); + lineCount = layout->lineCount(); + } + } + } + QTextLine line = layout->lineAt(lineCount - 1); QRectF lineRect = line.naturalTextRect().translated(data.offset.x(), top); int h = 4; lineRect.adjust(0, 0, -1, -1); @@ -4868,6 +4937,21 @@ void TextEditorWidget::paintBlock(QPainter *painter, const QVector &selections, const QRect &clipRect) const { + if (TextBlockUserData *userData = TextDocumentLayout::textUserData(block)) { + if (QTextDocument *replacement = userData->replacement()) { + QTextBlock replacementBlock = replacement->firstBlock(); + QPointF replacementOffset = offset; + replacementOffset.rx() += document()->documentMargin(); + while (replacementBlock.isValid()) { + replacementBlock.layout()->draw(painter, replacementOffset, selections, clipRect); + replacementOffset.ry() + += replacement->documentLayout()->blockBoundingRect(replacementBlock).height(); + replacementBlock = replacementBlock.next(); + } + return; + } + } + block.layout()->draw(painter, offset, selections, clipRect); } @@ -5405,6 +5489,12 @@ void TextEditorWidget::slotCursorPositionChanged() if (EditorManager::currentEditor() && EditorManager::currentEditor()->widget() == this) EditorManager::setLastEditLocation(EditorManager::currentEditor()); } + if (d->m_suggestionBlock.isValid()) { + if (textCursor().position() + != d->m_suggestionBlock.position() + d->m_suggestionBlock.length() - 1) { + d->clearCurrentSuggestion(); + } + } MultiTextCursor cursor = multiTextCursor(); cursor.replaceMainCursor(textCursor()); setMultiTextCursor(cursor); @@ -5849,6 +5939,16 @@ void TextEditorWidget::removeHoverHandler(BaseHoverHandler *handler) d->m_hoverHandlerRunner.handlerRemoved(handler); } +void TextEditorWidget::insertSuggestion(const QString &suggestion) +{ + d->insertSuggestion(suggestion, textCursor().block()); +} + +void TextEditorWidget::clearSuggestion() +{ + d->clearCurrentSuggestion(); +} + #ifdef WITH_TESTS void TextEditorWidget::processTooltipRequest(const QTextCursor &c) { diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index dc492eca21b..db20e0beb5f 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -469,6 +469,9 @@ public: void addHoverHandler(BaseHoverHandler *handler); void removeHoverHandler(BaseHoverHandler *handler); + void insertSuggestion(const QString &suggestion); + void clearSuggestion(); + #ifdef WITH_TESTS void processTooltipRequest(const QTextCursor &c); #endif From 6908130c83557ae9b7f27d2dee6f0cf9002d5b0c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 1 Feb 2023 14:21:51 +0100 Subject: [PATCH 0034/1447] Editor: Add replacement helper to document layout More inline with the other text block user data members and cleaner on the client side. Additionally add some & for const arguments and remove test function call. Change-Id: I19e646aa204eedf447c02a2f76b89c3430280169 Reviewed-by: hjk --- src/plugins/texteditor/textdocument.cpp | 2 +- src/plugins/texteditor/textdocument.h | 2 +- src/plugins/texteditor/textdocumentlayout.cpp | 42 ++++++------- src/plugins/texteditor/textdocumentlayout.h | 3 +- src/plugins/texteditor/texteditor.cpp | 60 +++++++++---------- 5 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 51fba77eb88..b6851411693 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -373,7 +373,7 @@ QAction *TextDocument::createDiffAgainstCurrentFileAction( return diffAction; } -void TextDocument::insertSuggestion(const QString text, const QTextBlock &block) +void TextDocument::insertSuggestion(const QString &text, const QTextBlock &block) { TextDocumentLayout::userData(block)->setReplacement(block.text() + text); TextDocumentLayout::updateReplacmentFormats(block, fontSettings()); diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 7a5797b7ca5..8ddfe9effb1 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -144,7 +144,7 @@ public: static QAction *createDiffAgainstCurrentFileAction(QObject *parent, const std::function &filePath); - void insertSuggestion(const QString text, const QTextBlock &block); + void insertSuggestion(const QString &text, const QTextBlock &block); #ifdef WITH_TESTS void setSilentReload(); diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index c160204e2f3..8738f43bd15 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -345,7 +345,7 @@ void TextBlockUserData::setCodeFormatterData(CodeFormatterData *data) m_codeFormatterData = data; } -void TextBlockUserData::setReplacement(const QString replacement) +void TextBlockUserData::setReplacement(const QString &replacement) { m_replacement.reset(new QTextDocument(replacement)); m_replacement->setDocumentLayout(new TextDocumentLayout(m_replacement.get())); @@ -528,30 +528,32 @@ QByteArray TextDocumentLayout::expectedRawStringSuffix(const QTextBlock &block) void TextDocumentLayout::updateReplacmentFormats(const QTextBlock &block, const FontSettings &fontSettings) { - if (TextBlockUserData *userData = textUserData(block)) { - if (QTextDocument *replacement = userData->replacement()) { - const QTextCharFormat replacementFormat = fontSettings.toTextCharFormat( - TextStyles{C_TEXT, {C_DISABLED_CODE}}); - QTextCursor cursor(replacement); - cursor.select(QTextCursor::Document); - cursor.setCharFormat(fontSettings.toTextCharFormat(C_TEXT)); - cursor.setPosition(block.length() - 1); - cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); - cursor.setCharFormat(replacementFormat); - replacement->firstBlock().layout()->setFormats(block.layout()->formats()); - } + if (QTextDocument *replacement = replacementDocument(block)) { + const QTextCharFormat replacementFormat = fontSettings.toTextCharFormat( + TextStyles{C_TEXT, {C_DISABLED_CODE}}); + QTextCursor cursor(replacement); + cursor.select(QTextCursor::Document); + cursor.setCharFormat(fontSettings.toTextCharFormat(C_TEXT)); + cursor.setPosition(block.length() - 1); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + cursor.setCharFormat(replacementFormat); + replacement->firstBlock().layout()->setFormats(block.layout()->formats()); } } QString TextDocumentLayout::replacement(const QTextBlock &block) { - if (TextBlockUserData *userData = textUserData(block)) { - if (QTextDocument *replacement = userData->replacement()) - return replacement->toPlainText().mid(block.length() - 1); - } + if (QTextDocument *replacement = replacementDocument(block)) + return replacement->toPlainText().mid(block.length() - 1); return {}; } +QTextDocument *TextDocumentLayout::replacementDocument(const QTextBlock &block) +{ + TextBlockUserData *userData = textUserData(block); + return userData ? userData->replacement() : nullptr; +} + void TextDocumentLayout::requestExtraAreaUpdate() { emit updateExtraArea(); @@ -682,10 +684,8 @@ static QRectF replacementBoundingRect(const QTextDocument *replacement) QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const { - if (TextBlockUserData *userData = textUserData(block)) { - if (auto replacement = userData->replacement()) - return replacementBoundingRect(replacement); - } + if (QTextDocument *replacement = replacementDocument(block)) + return replacementBoundingRect(replacement); QRectF boundingRect = QPlainTextDocumentLayout::blockBoundingRect(block); diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 5da2dd8f997..7a2e7e948e9 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -126,7 +126,7 @@ public: QByteArray expectedRawStringSuffix() { return m_expectedRawStringSuffix; } void setExpectedRawStringSuffix(const QByteArray &suffix) { m_expectedRawStringSuffix = suffix; } - void setReplacement(const QString replacement); + void setReplacement(const QString &replacement); void clearReplacement() { m_replacement.reset(); } QTextDocument *replacement() const { return m_replacement.get(); } @@ -179,6 +179,7 @@ public: static QByteArray expectedRawStringSuffix(const QTextBlock &block); static void updateReplacmentFormats(const QTextBlock &block, const FontSettings &fontSettings); static QString replacement(const QTextBlock &block); + static QTextDocument *replacementDocument(const QTextBlock &block); class TEXTEDITOR_EXPORT FoldValidator { diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index ca0ba9268c9..71bb7e639ad 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1853,13 +1853,13 @@ TextEditorWidget *TextEditorWidget::fromEditor(const IEditor *editor) void TextEditorWidgetPrivate::editorContentsChange(int position, int charsRemoved, int charsAdded) { if (m_suggestionBlock.isValid()) { - if (TextBlockUserData *data = TextDocumentLayout::textUserData(m_suggestionBlock)) { - if (auto replacementDocument = data->replacement()) { - if (replacementDocument->firstBlock().text().startsWith(m_suggestionBlock.text())) - TextDocumentLayout::updateReplacmentFormats(m_suggestionBlock, m_document->fontSettings()); - else - clearCurrentSuggestion(); - } + if (QTextDocument *replacementDocument = TextDocumentLayout::replacementDocument( + m_suggestionBlock)) { + if (replacementDocument->firstBlock().text().startsWith(m_suggestionBlock.text())) + TextDocumentLayout::updateReplacmentFormats(m_suggestionBlock, + m_document->fontSettings()); + else + clearCurrentSuggestion(); } } @@ -2994,8 +2994,6 @@ void TextEditorWidgetPrivate::universalHelper() { // Test function for development. Place your new fangled experiment here to // give it proper scrutiny before pushing it onto others. - - insertSuggestion("Teste\nWeste\nBeste", q->textCursor().block()); } void TextEditorWidget::doSetTextCursor(const QTextCursor &cursor, bool keepMultiSelection) @@ -4449,18 +4447,16 @@ void TextEditorWidgetPrivate::paintAdditionalVisualWhitespaces(PaintEventData &d } if (!nextBlockIsValid) { // paint EOF symbol if (m_suggestionBlock.isValid() && data.block == m_suggestionBlock) { - if (TextBlockUserData *userData = TextDocumentLayout::textUserData( + if (QTextDocument *replacement = TextDocumentLayout::replacementDocument( m_suggestionBlock)) { - if (QTextDocument *replacement = userData->replacement()) { - const QTextBlock lastReplacementBlock = replacement->lastBlock(); - for (QTextBlock block = replacement->firstBlock(); - block != lastReplacementBlock && block.isValid(); - block = block.next()) { - top += replacement->documentLayout()->blockBoundingRect(block).height(); - } - layout = lastReplacementBlock.layout(); - lineCount = layout->lineCount(); + const QTextBlock lastReplacementBlock = replacement->lastBlock(); + for (QTextBlock block = replacement->firstBlock(); + block != lastReplacementBlock && block.isValid(); + block = block.next()) { + top += replacement->documentLayout()->blockBoundingRect(block).height(); } + layout = lastReplacementBlock.layout(); + lineCount = layout->lineCount(); } } QTextLine line = layout->lineAt(lineCount - 1); @@ -4468,10 +4464,10 @@ void TextEditorWidgetPrivate::paintAdditionalVisualWhitespaces(PaintEventData &d int h = 4; lineRect.adjust(0, 0, -1, -1); QPainterPath path; - QPointF pos(lineRect.topRight() + QPointF(h+4, line.ascent())); + QPointF pos(lineRect.topRight() + QPointF(h + 4, line.ascent())); path.moveTo(pos); path.lineTo(pos + QPointF(-h, -h)); - path.lineTo(pos + QPointF(0, -2*h)); + path.lineTo(pos + QPointF(0, -2 * h)); path.lineTo(pos + QPointF(h, -h)); path.closeSubpath(); painter.setBrush(painter.pen().color()); @@ -4937,19 +4933,17 @@ void TextEditorWidget::paintBlock(QPainter *painter, const QVector &selections, const QRect &clipRect) const { - if (TextBlockUserData *userData = TextDocumentLayout::textUserData(block)) { - if (QTextDocument *replacement = userData->replacement()) { - QTextBlock replacementBlock = replacement->firstBlock(); - QPointF replacementOffset = offset; - replacementOffset.rx() += document()->documentMargin(); - while (replacementBlock.isValid()) { - replacementBlock.layout()->draw(painter, replacementOffset, selections, clipRect); - replacementOffset.ry() - += replacement->documentLayout()->blockBoundingRect(replacementBlock).height(); - replacementBlock = replacementBlock.next(); - } - return; + if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(block)) { + QTextBlock replacementBlock = replacement->firstBlock(); + QPointF replacementOffset = offset; + replacementOffset.rx() += document()->documentMargin(); + while (replacementBlock.isValid()) { + replacementBlock.layout()->draw(painter, replacementOffset, selections, clipRect); + replacementOffset.ry() + += replacement->documentLayout()->blockBoundingRect(replacementBlock).height(); + replacementBlock = replacementBlock.next(); } + return; } block.layout()->draw(painter, offset, selections, clipRect); From 4f70aa705234f425a03153c0d36ab9c9d7e72054 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 17 Jan 2023 00:45:50 +0100 Subject: [PATCH 0035/1447] TestRunner: Reuse TaskTree Get rid of QFutureInterface argument from ITestConfiguration::createOutputReader() and from TestOutputReader c'tor. The fine-grained progress reporting was broken anyway: 1. The assumption was that testCaseCount was meant to be the total number of test functions executed. It didn't include the initTestCase() and cleanupTestCase(), while those were reported on runtime apparently (and exceeding the max progress by 2). 2. In case of tst_qtcprocess, when the whole test was run, the testCaseCount reported 41, while the real number of functions was 26 (+2 = 28 for init/cleanup). 3. While the max progress was set to testCaseCount initially, the corresponding FutureProgress rendered the progress always in 0-100 range, what didn't match the reality. Instead, rely on TaskTree progress, which resolution is per test as a whole. So, when executing a series of tests this should scale fine. In addition, the progress advances fluently according to the expected run time - with 10 seconds hardcoded. The original code locations, where progress was bumped, are left with a TODO comment for any possible future tweaks. Like in case of result reporting, fine-grained progress reporting may be implemented by providing additional signal, so there is no need for QFutureInterface inside TestOutputReader. Change-Id: Idc11d55e3a49dac8d1788948b9a82f68199203c6 Reviewed-by: Reviewed-by: Christian Stenger --- .../autotest/boost/boosttestconfiguration.cpp | 6 +- .../autotest/boost/boosttestconfiguration.h | 3 +- .../autotest/boost/boosttestoutputreader.cpp | 6 +- .../autotest/boost/boosttestoutputreader.h | 3 +- .../autotest/catch/catchconfiguration.cpp | 8 +- .../autotest/catch/catchconfiguration.h | 3 +- .../autotest/catch/catchoutputreader.cpp | 9 +- .../autotest/catch/catchoutputreader.h | 3 +- .../autotest/ctest/ctestconfiguration.cpp | 5 +- .../autotest/ctest/ctestconfiguration.h | 3 +- .../autotest/ctest/ctestoutputreader.cpp | 7 +- .../autotest/ctest/ctestoutputreader.h | 3 +- .../autotest/gtest/gtestconfiguration.cpp | 7 +- .../autotest/gtest/gtestconfiguration.h | 3 +- .../autotest/gtest/gtestoutputreader.cpp | 9 +- .../autotest/gtest/gtestoutputreader.h | 3 +- .../autotest/qtest/qttestconfiguration.cpp | 9 +- .../autotest/qtest/qttestconfiguration.h | 3 +- .../autotest/qtest/qttestoutputreader.cpp | 18 +- .../autotest/qtest/qttestoutputreader.h | 6 +- .../autotest/quick/quicktestconfiguration.cpp | 14 +- .../autotest/quick/quicktestconfiguration.h | 3 +- src/plugins/autotest/testconfiguration.cpp | 10 +- src/plugins/autotest/testconfiguration.h | 4 +- src/plugins/autotest/testoutputreader.cpp | 17 +- src/plugins/autotest/testoutputreader.h | 6 +- src/plugins/autotest/testrunner.cpp | 371 +++++++----------- src/plugins/autotest/testrunner.h | 28 +- 28 files changed, 219 insertions(+), 351 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestconfiguration.cpp b/src/plugins/autotest/boost/boosttestconfiguration.cpp index 50d8a863f4a..d680699c36e 100644 --- a/src/plugins/autotest/boost/boosttestconfiguration.cpp +++ b/src/plugins/autotest/boost/boosttestconfiguration.cpp @@ -11,18 +11,16 @@ #include "../testsettings.h" #include -#include using namespace Utils; namespace Autotest { namespace Internal { -TestOutputReader *BoostTestConfiguration::createOutputReader( - const QFutureInterface &fi, QtcProcess *app) const +TestOutputReader *BoostTestConfiguration::createOutputReader(QtcProcess *app) const { auto settings = static_cast(framework()->testSettings()); - return new BoostTestOutputReader(fi, app, buildDirectory(), projectFile(), + return new BoostTestOutputReader(app, buildDirectory(), projectFile(), LogLevel(settings->logLevel.value()), ReportLevel(settings->reportLevel.value())); } diff --git a/src/plugins/autotest/boost/boosttestconfiguration.h b/src/plugins/autotest/boost/boosttestconfiguration.h index 8afb74049fd..5a764dd8662 100644 --- a/src/plugins/autotest/boost/boosttestconfiguration.h +++ b/src/plugins/autotest/boost/boosttestconfiguration.h @@ -13,8 +13,7 @@ class BoostTestConfiguration : public DebuggableTestConfiguration public: explicit BoostTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp index 5f549cca320..3ac49d2aa46 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.cpp +++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp @@ -5,6 +5,7 @@ #include "boosttestsettings.h" #include "boosttestresult.h" + #include "../autotesttr.h" #include "../testtreeitem.h" @@ -21,12 +22,11 @@ namespace Internal { static Q_LOGGING_CATEGORY(orLog, "qtc.autotest.boost.outputreader", QtWarningMsg) -BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface &futureInterface, - QtcProcess *testApplication, +BoostTestOutputReader::BoostTestOutputReader(QtcProcess *testApplication, const FilePath &buildDirectory, const FilePath &projectFile, LogLevel log, ReportLevel report) - : TestOutputReader(futureInterface, testApplication, buildDirectory) + : TestOutputReader(testApplication, buildDirectory) , m_projectFile(projectFile) , m_logLevel(log) , m_reportLevel(report) diff --git a/src/plugins/autotest/boost/boosttestoutputreader.h b/src/plugins/autotest/boost/boosttestoutputreader.h index 8449a0708ab..ff2066f7d45 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.h +++ b/src/plugins/autotest/boost/boosttestoutputreader.h @@ -15,8 +15,7 @@ class BoostTestOutputReader : public TestOutputReader { Q_OBJECT public: - BoostTestOutputReader(const QFutureInterface &futureInterface, - Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + BoostTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, LogLevel log, ReportLevel report); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/catch/catchconfiguration.cpp b/src/plugins/autotest/catch/catchconfiguration.cpp index c08f7ac82b6..593acc589e7 100644 --- a/src/plugins/autotest/catch/catchconfiguration.cpp +++ b/src/plugins/autotest/catch/catchconfiguration.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "catchconfiguration.h" + #include "catchoutputreader.h" #include "catchtestsettings.h" @@ -9,17 +10,14 @@ #include "../itestframework.h" #include "../testsettings.h" -#include - using namespace Utils; namespace Autotest { namespace Internal { -TestOutputReader *CatchConfiguration::createOutputReader(const QFutureInterface &fi, - QtcProcess *app) const +TestOutputReader *CatchConfiguration::createOutputReader(QtcProcess *app) const { - return new CatchOutputReader(fi, app, buildDirectory(), projectFile()); + return new CatchOutputReader(app, buildDirectory(), projectFile()); } static QStringList filterInterfering(const QStringList &provided, QStringList *omitted) diff --git a/src/plugins/autotest/catch/catchconfiguration.h b/src/plugins/autotest/catch/catchconfiguration.h index bfa37f01644..90b9b09dceb 100644 --- a/src/plugins/autotest/catch/catchconfiguration.h +++ b/src/plugins/autotest/catch/catchconfiguration.h @@ -12,8 +12,7 @@ class CatchConfiguration : public DebuggableTestConfiguration { public: CatchConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/catch/catchoutputreader.cpp b/src/plugins/autotest/catch/catchoutputreader.cpp index 95e437fdc4b..9bcb3778058 100644 --- a/src/plugins/autotest/catch/catchoutputreader.cpp +++ b/src/plugins/autotest/catch/catchoutputreader.cpp @@ -2,13 +2,11 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "catchoutputreader.h" + #include "catchresult.h" #include "../autotesttr.h" -#include -#include - using namespace Utils; namespace Autotest { @@ -31,11 +29,10 @@ namespace CatchXml { const char TestCaseResultElement[] = "OverallResult"; } -CatchOutputReader::CatchOutputReader(const QFutureInterface &futureInterface, - QtcProcess *testApplication, +CatchOutputReader::CatchOutputReader(QtcProcess *testApplication, const FilePath &buildDirectory, const FilePath &projectFile) - : TestOutputReader (futureInterface, testApplication, buildDirectory) + : TestOutputReader(testApplication, buildDirectory) , m_projectFile(projectFile) { } diff --git a/src/plugins/autotest/catch/catchoutputreader.h b/src/plugins/autotest/catch/catchoutputreader.h index 51e8c1e3389..d65ebd7650f 100644 --- a/src/plugins/autotest/catch/catchoutputreader.h +++ b/src/plugins/autotest/catch/catchoutputreader.h @@ -14,8 +14,7 @@ namespace Internal { class CatchOutputReader : public TestOutputReader { public: - CatchOutputReader(const QFutureInterface &futureInterface, - Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + CatchOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile); protected: diff --git a/src/plugins/autotest/ctest/ctestconfiguration.cpp b/src/plugins/autotest/ctest/ctestconfiguration.cpp index 9208888033e..183d7874e86 100644 --- a/src/plugins/autotest/ctest/ctestconfiguration.cpp +++ b/src/plugins/autotest/ctest/ctestconfiguration.cpp @@ -13,10 +13,9 @@ CTestConfiguration::CTestConfiguration(ITestBase *testBase) setDisplayName("CTest"); } -TestOutputReader *CTestConfiguration::createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const +TestOutputReader *CTestConfiguration::createOutputReader(Utils::QtcProcess *app) const { - return new CTestOutputReader(fi, app, workingDirectory()); + return new CTestOutputReader(app, workingDirectory()); } } // namespace Internal diff --git a/src/plugins/autotest/ctest/ctestconfiguration.h b/src/plugins/autotest/ctest/ctestconfiguration.h index db0efb17173..4496fb4aaf5 100644 --- a/src/plugins/autotest/ctest/ctestconfiguration.h +++ b/src/plugins/autotest/ctest/ctestconfiguration.h @@ -13,8 +13,7 @@ class CTestConfiguration final : public Autotest::TestToolConfiguration public: explicit CTestConfiguration(ITestBase *testBase); - TestOutputReader *createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const final; + TestOutputReader *createOutputReader(Utils::QtcProcess *app) const final; }; } // namespace Internal diff --git a/src/plugins/autotest/ctest/ctestoutputreader.cpp b/src/plugins/autotest/ctest/ctestoutputreader.cpp index 70ec5f0659b..9a6259d8c0d 100644 --- a/src/plugins/autotest/ctest/ctestoutputreader.cpp +++ b/src/plugins/autotest/ctest/ctestoutputreader.cpp @@ -5,13 +5,11 @@ #include "../autotesttr.h" #include "../testframeworkmanager.h" -#include "../testresult.h" #include "../testtreeitem.h" #include #include -#include #include @@ -52,10 +50,9 @@ public: {} }; -CTestOutputReader::CTestOutputReader(const QFutureInterface &futureInterface, - QtcProcess *testApplication, +CTestOutputReader::CTestOutputReader(QtcProcess *testApplication, const FilePath &buildDirectory) - : TestOutputReader(futureInterface, testApplication, buildDirectory) + : TestOutputReader(testApplication, buildDirectory) { } diff --git a/src/plugins/autotest/ctest/ctestoutputreader.h b/src/plugins/autotest/ctest/ctestoutputreader.h index 8a6e1f124e4..896f17ba245 100644 --- a/src/plugins/autotest/ctest/ctestoutputreader.h +++ b/src/plugins/autotest/ctest/ctestoutputreader.h @@ -13,8 +13,7 @@ namespace Internal { class CTestOutputReader final : public Autotest::TestOutputReader { public: - CTestOutputReader(const QFutureInterface &futureInterface, - Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); + CTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); protected: void processOutputLine(const QByteArray &outputLineWithNewLine) final; diff --git a/src/plugins/autotest/gtest/gtestconfiguration.cpp b/src/plugins/autotest/gtest/gtestconfiguration.cpp index d2f869d7645..1da1d212e4c 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.cpp +++ b/src/plugins/autotest/gtest/gtestconfiguration.cpp @@ -5,22 +5,21 @@ #include "gtestoutputreader.h" #include "gtestsettings.h" + #include "../autotestplugin.h" #include "../itestframework.h" #include "../testsettings.h" #include -#include using namespace Utils; namespace Autotest { namespace Internal { -TestOutputReader *GTestConfiguration::createOutputReader(const QFutureInterface &fi, - QtcProcess *app) const +TestOutputReader *GTestConfiguration::createOutputReader(QtcProcess *app) const { - return new GTestOutputReader(fi, app, buildDirectory(), projectFile()); + return new GTestOutputReader(app, buildDirectory(), projectFile()); } QStringList filterInterfering(const QStringList &provided, QStringList *omitted) diff --git a/src/plugins/autotest/gtest/gtestconfiguration.h b/src/plugins/autotest/gtest/gtestconfiguration.h index 97bcbd654fc..a68a1f9674d 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.h +++ b/src/plugins/autotest/gtest/gtestconfiguration.h @@ -14,8 +14,7 @@ public: explicit GTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 4ad273063e9..9dea510cdde 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -17,11 +17,10 @@ using namespace Utils; namespace Autotest { namespace Internal { -GTestOutputReader::GTestOutputReader(const QFutureInterface &futureInterface, - QtcProcess *testApplication, +GTestOutputReader::GTestOutputReader(QtcProcess *testApplication, const FilePath &buildDirectory, const FilePath &projectFile) - : TestOutputReader(futureInterface, testApplication, buildDirectory) + : TestOutputReader(testApplication, buildDirectory) , m_projectFile(projectFile) { if (testApplication) { @@ -121,7 +120,7 @@ void GTestOutputReader::processOutputLine(const QByteArray &outputLine) testResult.setResult(ResultType::MessageInternal); testResult.setDescription(Tr::tr("Execution took %1.").arg(match.captured(2))); reportResult(testResult); - m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1); + // TODO: bump progress? } else if (ExactMatch match = testSetFail.match(line)) { m_testSetStarted = false; TestResult testResult = createDefaultResult(); @@ -132,7 +131,7 @@ void GTestOutputReader::processOutputLine(const QByteArray &outputLine) testResult.setResult(ResultType::MessageInternal); testResult.setDescription(Tr::tr("Execution took %1.").arg(match.captured(2))); reportResult(testResult); - m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1); + // TODO: bump progress? } else if (ExactMatch match = testSetSkipped.match(line)) { if (!m_testSetStarted) // ignore SKIPPED at summary return; diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h index e73ab0e8236..a8ced858dd2 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.h +++ b/src/plugins/autotest/gtest/gtestoutputreader.h @@ -11,8 +11,7 @@ namespace Internal { class GTestOutputReader : public TestOutputReader { public: - GTestOutputReader(const QFutureInterface &futureInterface, - Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + GTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp index 8a77f305e34..9210a9685f1 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.cpp +++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp @@ -2,16 +2,16 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qttestconfiguration.h" -#include "qttestconstants.h" + #include "qttestoutputreader.h" #include "qttestsettings.h" #include "qttest_utils.h" + #include "../autotestplugin.h" #include "../itestframework.h" #include "../testsettings.h" #include -#include using namespace Utils; @@ -28,14 +28,13 @@ static QStringList quoteIfNeeded(const QStringList &testCases, bool debugMode) }); } -TestOutputReader *QtTestConfiguration::createOutputReader(const QFutureInterface &fi, - QtcProcess *app) const +TestOutputReader *QtTestConfiguration::createOutputReader(QtcProcess *app) const { auto qtSettings = static_cast(framework()->testSettings()); const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() ? QtTestOutputReader::XML : QtTestOutputReader::PlainText; - return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(), mode, TestType::QtTest); + return new QtTestOutputReader(app, buildDirectory(), projectFile(), mode, TestType::QtTest); } QStringList QtTestConfiguration::argumentsForTestRunner(QStringList *omitted) const diff --git a/src/plugins/autotest/qtest/qttestconfiguration.h b/src/plugins/autotest/qtest/qttestconfiguration.h index a99c93f0b75..f370f97c786 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.h +++ b/src/plugins/autotest/qtest/qttestconfiguration.h @@ -13,8 +13,7 @@ class QtTestConfiguration : public DebuggableTestConfiguration public: explicit QtTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index a93e74eea42..f7746b2f291 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -12,8 +12,6 @@ #include -#include - using namespace Utils; namespace Autotest { @@ -99,18 +97,15 @@ static QString constructBenchmarkInformation(const QString &metric, double value else if (metric == "CPUCycles") // -perf metricsText = "CPU cycles"; return Tr::tr("%1 %2 per iteration (total: %3, iterations: %4)") - .arg(formatResult(value)) - .arg(metricsText) - .arg(formatResult(value * double(iterations))) + .arg(formatResult(value), metricsText, formatResult(value * double(iterations))) .arg(iterations); } -QtTestOutputReader::QtTestOutputReader(const QFutureInterface &futureInterface, - QtcProcess *testApplication, +QtTestOutputReader::QtTestOutputReader(QtcProcess *testApplication, const FilePath &buildDirectory, const FilePath &projectFile, OutputMode mode, TestType type) - : TestOutputReader(futureInterface, testApplication, buildDirectory) + : TestOutputReader(testApplication, buildDirectory) , m_projectFile(projectFile) , m_mode(mode) , m_testType(type) @@ -177,8 +172,6 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine) m_xmlReader.addData("\n"); m_xmlReader.addData(QString::fromUtf8(outputLine)); while (!m_xmlReader.atEnd()) { - if (m_futureInterface.isCanceled()) - return; QXmlStreamReader::TokenType token = m_xmlReader.readNext(); switch (token) { case QXmlStreamReader::StartDocument: @@ -277,7 +270,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine) const QStringView currentTag = m_xmlReader.name(); if (currentTag == QStringLiteral("TestFunction")) { sendFinishMessage(true); - m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1); + // TODO: bump progress? m_dataTag.clear(); m_formerTestCase = m_testCase; m_testCase.clear(); @@ -347,9 +340,6 @@ void QtTestOutputReader::processPlainTextOutput(const QByteArray &outputLine) static const QRegularExpression locationUnix(QT_TEST_FAIL_UNIX_REGEXP); static const QRegularExpression locationWin(QT_TEST_FAIL_WIN_REGEXP); - if (m_futureInterface.isCanceled()) - return; - const QString line = QString::fromUtf8(outputLine); QRegularExpressionMatch match; diff --git a/src/plugins/autotest/qtest/qttestoutputreader.h b/src/plugins/autotest/qtest/qttestoutputreader.h index 6db9aa87810..a730d540dd5 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.h +++ b/src/plugins/autotest/qtest/qttestoutputreader.h @@ -3,9 +3,10 @@ #pragma once -#include "qttestconstants.h" #include "../testoutputreader.h" +#include "qttestconstants.h" + #include namespace Autotest { @@ -22,8 +23,7 @@ public: PlainText }; - QtTestOutputReader(const QFutureInterface &futureInterface, - Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + QtTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, OutputMode mode, TestType type); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/quick/quicktestconfiguration.cpp b/src/plugins/autotest/quick/quicktestconfiguration.cpp index c7cce31acf1..1d00c48c201 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.cpp +++ b/src/plugins/autotest/quick/quicktestconfiguration.cpp @@ -2,16 +2,14 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "quicktestconfiguration.h" -#include "../qtest/qttestconstants.h" + +#include "../autotestplugin.h" +#include "../itestframework.h" #include "../qtest/qttestoutputreader.h" #include "../qtest/qttestsettings.h" #include "../qtest/qttest_utils.h" -#include "../autotestplugin.h" -#include "../itestframework.h" #include "../testsettings.h" -#include - using namespace Utils; namespace Autotest { @@ -23,15 +21,13 @@ QuickTestConfiguration::QuickTestConfiguration(ITestFramework *framework) setMixedDebugging(true); } -TestOutputReader *QuickTestConfiguration::createOutputReader( - const QFutureInterface &fi, QtcProcess *app) const +TestOutputReader *QuickTestConfiguration::createOutputReader(QtcProcess *app) const { auto qtSettings = static_cast(framework()->testSettings()); const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() ? QtTestOutputReader::XML : QtTestOutputReader::PlainText; - return new QtTestOutputReader(fi, app, buildDirectory(), projectFile(), - mode, TestType::QuickTest); + return new QtTestOutputReader(app, buildDirectory(), projectFile(), mode, TestType::QuickTest); } QStringList QuickTestConfiguration::argumentsForTestRunner(QStringList *omitted) const diff --git a/src/plugins/autotest/quick/quicktestconfiguration.h b/src/plugins/autotest/quick/quicktestconfiguration.h index 84e374ebe8a..6739f848256 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.h +++ b/src/plugins/autotest/quick/quicktestconfiguration.h @@ -12,8 +12,7 @@ class QuickTestConfiguration : public DebuggableTestConfiguration { public: explicit QuickTestConfiguration(ITestFramework *framework); - TestOutputReader *createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp index 764ede697d1..00bf521b88a 100644 --- a/src/plugins/autotest/testconfiguration.cpp +++ b/src/plugins/autotest/testconfiguration.cpp @@ -4,22 +4,19 @@ #include "testconfiguration.h" #include "itestframework.h" -#include "testoutputreader.h" #include "testrunconfiguration.h" -#include -#include - #include #include #include #include -#include #include #include #include #include +#include + #include static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.testconfiguration", QtWarningMsg) @@ -29,7 +26,6 @@ using namespace Utils; namespace Autotest { - ITestConfiguration::ITestConfiguration(ITestBase *testBase) : m_testBase(testBase) { @@ -94,7 +90,7 @@ static FilePath ensureExeEnding(const FilePath &file) return file.withExecutableSuffix(); } -void TestConfiguration::completeTestInformation(ProjectExplorer::RunConfiguration *rc, +void TestConfiguration::completeTestInformation(RunConfiguration *rc, TestRunMode runMode) { QTC_ASSERT(rc, return); diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h index d57416d0164..492509605cf 100644 --- a/src/plugins/autotest/testconfiguration.h +++ b/src/plugins/autotest/testconfiguration.h @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -40,8 +39,7 @@ public: Utils::FilePath executableFilePath() const; virtual Utils::FilePath testExecutable() const { return executableFilePath(); }; - virtual TestOutputReader *createOutputReader(const QFutureInterface &fi, - Utils::QtcProcess *app) const = 0; + virtual TestOutputReader *createOutputReader(Utils::QtcProcess *app) const = 0; virtual Utils::Environment filteredEnvironment(const Utils::Environment &original) const; ITestBase *testBase() const { return m_testBase; } diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp index 2f1dc75e485..e05fe8fdddb 100644 --- a/src/plugins/autotest/testoutputreader.cpp +++ b/src/plugins/autotest/testoutputreader.cpp @@ -4,17 +4,12 @@ #include "testoutputreader.h" #include "autotesttr.h" -#include "testresult.h" -#include "testresultspane.h" #include "testtreeitem.h" #include #include -#include -#include -#include -#include +#include using namespace Utils; @@ -26,11 +21,8 @@ FilePath TestOutputReader::constructSourceFilePath(const FilePath &path, const Q return filePath.isReadableFile() ? filePath : FilePath(); } -TestOutputReader::TestOutputReader(const QFutureInterface &futureInterface, - QtcProcess *testApplication, const FilePath &buildDirectory) - : m_futureInterface(futureInterface) - , m_buildDir(buildDirectory) - , m_id(testApplication ? testApplication->commandLine().executable().toUserOutput() : QString()) +TestOutputReader::TestOutputReader(QtcProcess *testApplication, const FilePath &buildDirectory) + : m_buildDir(buildDirectory) { auto chopLineBreak = [](QByteArray line) { if (line.endsWith('\n')) @@ -41,6 +33,9 @@ TestOutputReader::TestOutputReader(const QFutureInterface &futureInt }; if (testApplication) { + connect(testApplication, &QtcProcess::started, this, [this, testApplication] { + m_id = testApplication->commandLine().executable().toUserOutput(); + }); testApplication->setStdOutLineCallback([this, &chopLineBreak](const QString &line) { processStdOutput(chopLineBreak(line.toUtf8())); }); diff --git a/src/plugins/autotest/testoutputreader.h b/src/plugins/autotest/testoutputreader.h index 55c645d87c4..7011070b44a 100644 --- a/src/plugins/autotest/testoutputreader.h +++ b/src/plugins/autotest/testoutputreader.h @@ -5,9 +5,7 @@ #include "testresult.h" -#include #include -#include namespace Utils { class QtcProcess; } @@ -17,8 +15,7 @@ class TestOutputReader : public QObject { Q_OBJECT public: - TestOutputReader(const QFutureInterface &futureInterface, - Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); + TestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); virtual ~TestOutputReader(); void processStdOutput(const QByteArray &outputLine); virtual void processStdError(const QByteArray &outputLine); @@ -46,7 +43,6 @@ protected: void sendAndResetSanitizerResult(); void reportResult(const TestResult &result); - QFutureInterface m_futureInterface; Utils::FilePath m_buildDir; QString m_id; QHash m_summary; diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 76138a8ea4b..ff7911dd432 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -6,18 +6,15 @@ #include "autotestconstants.h" #include "autotestplugin.h" #include "autotesttr.h" -#include "itestframework.h" #include "testoutputreader.h" #include "testprojectsettings.h" #include "testresultspane.h" #include "testrunconfiguration.h" -#include "testsettings.h" #include "testtreeitem.h" #include "testtreemodel.h" #include -#include -#include +#include #include #include @@ -47,10 +44,9 @@ #include #include #include -#include #include -#include +using namespace Core; using namespace ProjectExplorer; using namespace Utils; @@ -72,14 +68,7 @@ TestRunner::TestRunner() m_cancelTimer.setSingleShot(true); connect(&m_cancelTimer, &QTimer::timeout, this, [this] { cancelCurrent(Timeout); }); - connect(&m_futureWatcher, &QFutureWatcher::finished, - this, &TestRunner::onFinished); - connect(this, &TestRunner::requestStopTestRun, - &m_futureWatcher, &QFutureWatcher::cancel); - connect(&m_futureWatcher, &QFutureWatcher::canceled, this, [this] { - cancelCurrent(UserCanceled); - reportResult(ResultType::MessageFatal, Tr::tr("Test run canceled by user.")); - }); + connect(this, &TestRunner::requestStopTestRun, this, [this] { cancelCurrent(UserCanceled); }); connect(BuildManager::instance(), &BuildManager::buildQueueFinished, this, &TestRunner::onBuildQueueFinished); } @@ -93,7 +82,7 @@ TestRunner::~TestRunner() void TestRunner::runTest(TestRunMode mode, const ITestTreeItem *item) { - QTC_ASSERT(!m_executingTests, return); + QTC_ASSERT(!isTestRunning(), return); ITestConfiguration *configuration = item->asConfiguration(mode); if (configuration) @@ -144,180 +133,21 @@ static QString constructOmittedVariablesDetailsString(const EnvironmentItems &di + '\n' + removedVars.join('\n'); } -bool TestRunner::currentConfigValid() -{ - const FilePath commandFilePath = m_currentConfig->testExecutable(); - if (!commandFilePath.isEmpty()) - return true; - - reportResult(ResultType::MessageFatal, - Tr::tr("Executable path is empty. (%1)").arg(m_currentConfig->displayName())); - delete m_currentConfig; - m_currentConfig = nullptr; - if (m_selectedTests.isEmpty()) { - if (m_fakeFutureInterface) - m_fakeFutureInterface->reportFinished(); - onFinished(); - } else { - onProcessDone(); - } - return false; -} - -void TestRunner::setUpProcessEnv() -{ - CommandLine command = m_currentProcess->commandLine(); - if (m_currentConfig->testBase()->type() == ITestBase::Framework) { - TestConfiguration *current = static_cast(m_currentConfig); - - QStringList omitted; - command.addArgs(current->argumentsForTestRunner(&omitted).join(' '), CommandLine::Raw); - if (!omitted.isEmpty()) { - const QString &details = constructOmittedDetailsString(omitted); - reportResult(ResultType::MessageWarn, details.arg(current->displayName())); - } - } else { - TestToolConfiguration *current = static_cast(m_currentConfig); - command.setArguments(current->commandLine().arguments()); - } - m_currentProcess->setCommand(command); - - m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory()); - const Environment &original = m_currentConfig->environment(); - Environment environment = m_currentConfig->filteredEnvironment(original); - const EnvironmentItems removedVariables = Utils::filtered( - original.diff(environment), [](const EnvironmentItem &it) { - return it.operation == EnvironmentItem::Unset; - }); - if (!removedVariables.isEmpty()) { - const QString &details = constructOmittedVariablesDetailsString(removedVariables) - .arg(m_currentConfig->displayName()); - reportResult(ResultType::MessageWarn, details); - } - m_currentProcess->setEnvironment(environment); -} - -void TestRunner::scheduleNext() -{ - QTC_ASSERT(!m_selectedTests.isEmpty(), onFinished(); return); - QTC_ASSERT(!m_currentConfig && !m_currentProcess, resetInternalPointers()); - QTC_ASSERT(m_fakeFutureInterface, onFinished(); return); - QTC_ASSERT(!m_canceled, onFinished(); return); - - m_currentConfig = m_selectedTests.takeFirst(); - - if (!currentConfigValid()) - return; - - if (!m_currentConfig->project()) - onProcessDone(); - - m_currentProcess = new QtcProcess; - m_currentProcess->setCommand({m_currentConfig->testExecutable(), {}}); - - QTC_ASSERT(!m_currentOutputReader, delete m_currentOutputReader); - m_currentOutputReader = m_currentConfig->createOutputReader(*m_fakeFutureInterface, m_currentProcess); - QTC_ASSERT(m_currentOutputReader, onProcessDone(); return); - connect(m_currentOutputReader, &TestOutputReader::newResult, this, &TestRunner::testResultReady); - connect(m_currentOutputReader, &TestOutputReader::newOutputLineAvailable, - TestResultsPane::instance(), &TestResultsPane::addOutputLine); - - setUpProcessEnv(); - - connect(m_currentProcess, &QtcProcess::done, this, &TestRunner::onProcessDone); - const int timeout = AutotestPlugin::settings()->timeout; - m_cancelTimer.setInterval(timeout); - m_cancelTimer.start(); - - qCInfo(runnerLog) << "Command:" << m_currentProcess->commandLine().executable(); - qCInfo(runnerLog) << "Arguments:" << m_currentProcess->commandLine().arguments(); - qCInfo(runnerLog) << "Working directory:" << m_currentProcess->workingDirectory(); - qCDebug(runnerLog) << "Environment:" << m_currentProcess->environment().toStringList(); - - m_currentProcess->start(); -} - void TestRunner::cancelCurrent(TestRunner::CancelReason reason) { - m_canceled = true; - - if (m_fakeFutureInterface) - m_fakeFutureInterface->reportCanceled(); - if (reason == KitChanged) reportResult(ResultType::MessageWarn, Tr::tr("Current kit has changed. Canceling test run.")); else if (reason == Timeout) reportResult(ResultType::MessageFatal, Tr::tr("Test case canceled due to timeout.\nMaybe raise the timeout?")); - - // if user or timeout cancels the current run ensure to kill the running process - if (m_currentProcess && m_currentProcess->state() != QProcess::NotRunning) { - m_currentProcess->kill(); - m_currentProcess->waitForFinished(); - } -} - -void TestRunner::onProcessDone() -{ - if (m_currentProcess->result() == ProcessResult::StartFailed) { - reportResult(ResultType::MessageFatal, - Tr::tr("Failed to start test for project \"%1\".").arg(m_currentConfig->displayName()) - + processInformation(m_currentProcess) + rcInfo(m_currentConfig)); - } - - if (m_executingTests && m_currentConfig) { - QTC_CHECK(m_fakeFutureInterface); - m_fakeFutureInterface->setProgressValue(m_fakeFutureInterface->progressValue() - + m_currentConfig->testCaseCount()); - if (m_currentProcess && !m_fakeFutureInterface->isCanceled()) { - if (m_currentProcess->exitStatus() == QProcess::CrashExit) { - if (m_currentOutputReader) - m_currentOutputReader->reportCrash(); - reportResult(ResultType::MessageFatal, - Tr::tr("Test for project \"%1\" crashed.").arg(m_currentConfig->displayName()) - + processInformation(m_currentProcess) + rcInfo(m_currentConfig)); - } else if (m_currentOutputReader && !m_currentOutputReader->hadValidOutput()) { - reportResult(ResultType::MessageFatal, - Tr::tr("Test for project \"%1\" did not produce any expected output.") - .arg(m_currentConfig->displayName()) + processInformation(m_currentProcess) - + rcInfo(m_currentConfig)); - } - } - } - if (m_currentOutputReader) { - const int disabled = m_currentOutputReader->disabledTests(); - if (disabled > 0) - emit hadDisabledTests(disabled); - if (m_currentOutputReader->hasSummary()) - emit reportSummary(m_currentOutputReader->id(), m_currentOutputReader->summary()); - - m_currentOutputReader->resetCommandlineColor(); - } - resetInternalPointers(); - - if (!m_fakeFutureInterface) { - QTC_ASSERT(!m_executingTests, m_executingTests = false); - return; - } - if (!m_selectedTests.isEmpty() && !m_fakeFutureInterface->isCanceled()) - scheduleNext(); - else - m_fakeFutureInterface->reportFinished(); -} - -void TestRunner::resetInternalPointers() -{ - delete m_currentOutputReader; - if (m_currentProcess) - m_currentProcess->deleteLater(); - delete m_currentConfig; - m_currentOutputReader = nullptr; - m_currentProcess = nullptr; - m_currentConfig = nullptr; + else if (reason == UserCanceled) + reportResult(ResultType::MessageFatal, Tr::tr("Test run canceled by user.")); + m_taskTree.reset(); + onFinished(); } void TestRunner::runTests(TestRunMode mode, const QList &selectedTests) { - QTC_ASSERT(!m_executingTests, return); + QTC_ASSERT(!isTestRunning(), return); qDeleteAll(m_selectedTests); m_selectedTests = selectedTests; @@ -332,8 +162,6 @@ void TestRunner::runTests(TestRunMode mode, const QList &s return; } - m_executingTests = true; - m_canceled = false; emit testRunStarted(); // clear old log and output pane @@ -411,7 +239,7 @@ static RunConfiguration *getRunConfiguration(const QString &buildTargetKey) if (runConfigurations.size() == 1) return runConfigurations.first(); - RunConfigurationSelectionDialog dialog(buildTargetKey, Core::ICore::dialogParent()); + RunConfigurationSelectionDialog dialog(buildTargetKey, ICore::dialogParent()); if (dialog.exec() == QDialog::Accepted) { const QString dName = dialog.displayName(); if (dName.isEmpty()) @@ -513,19 +341,136 @@ void TestRunner::runTestsHelper() return; } - int testCaseCount = precheckTestConfigurations(); + const int testCaseCount = precheckTestConfigurations(); + Q_UNUSED(testCaseCount) // TODO: may be useful for fine-grained progress reporting, when fixed - // Fake future interface - destruction will be handled by QFuture/QFutureWatcher - m_fakeFutureInterface = new QFutureInterface(QFutureInterfaceBase::Running); - QFuture future = m_fakeFutureInterface->future(); - m_fakeFutureInterface->setProgressRange(0, testCaseCount); - m_fakeFutureInterface->setProgressValue(0); - m_futureWatcher.setFuture(future); + struct TestStorage { + std::unique_ptr m_outputReader; + }; + + using namespace Tasking; + QList tasks{optional}; + + for (ITestConfiguration *config : m_selectedTests) { + QTC_ASSERT(config, continue); + const TreeStorage storage; + + const auto onGroupSetup = [this, config] { + if (!config->project()) + return TaskAction::StopWithDone; + if (config->testExecutable().isEmpty()) { + reportResult(ResultType::MessageFatal, + Tr::tr("Executable path is empty. (%1)").arg(config->displayName())); + return TaskAction::StopWithDone; + } + return TaskAction::Continue; + }; + const auto onSetup = [this, config, storage](QtcProcess &process) { + TestStorage *testStorage = storage.activeStorage(); + QTC_ASSERT(testStorage, return); + testStorage->m_outputReader.reset(config->createOutputReader(&process)); + QTC_ASSERT(testStorage->m_outputReader, return); + connect(testStorage->m_outputReader.get(), &TestOutputReader::newResult, + this, &TestRunner::testResultReady); + connect(testStorage->m_outputReader.get(), &TestOutputReader::newOutputLineAvailable, + TestResultsPane::instance(), &TestResultsPane::addOutputLine); + + CommandLine command{config->testExecutable(), {}}; + if (config->testBase()->type() == ITestBase::Framework) { + TestConfiguration *current = static_cast(config); + QStringList omitted; + command.addArgs(current->argumentsForTestRunner(&omitted).join(' '), CommandLine::Raw); + if (!omitted.isEmpty()) { + const QString &details = constructOmittedDetailsString(omitted); + reportResult(ResultType::MessageWarn, details.arg(current->displayName())); + } + } else { + TestToolConfiguration *current = static_cast(config); + command.setArguments(current->commandLine().arguments()); + } + process.setCommand(command); + + process.setWorkingDirectory(config->workingDirectory()); + const Environment &original = config->environment(); + Environment environment = config->filteredEnvironment(original); + const EnvironmentItems removedVariables = Utils::filtered( + original.diff(environment), [](const EnvironmentItem &it) { + return it.operation == EnvironmentItem::Unset; + }); + if (!removedVariables.isEmpty()) { + const QString &details = constructOmittedVariablesDetailsString(removedVariables) + .arg(config->displayName()); + reportResult(ResultType::MessageWarn, details); + } + process.setEnvironment(environment); + + m_cancelTimer.setInterval(AutotestPlugin::settings()->timeout); + m_cancelTimer.start(); + + qCInfo(runnerLog) << "Command:" << process.commandLine().executable(); + qCInfo(runnerLog) << "Arguments:" << process.commandLine().arguments(); + qCInfo(runnerLog) << "Working directory:" << process.workingDirectory(); + qCDebug(runnerLog) << "Environment:" << process.environment().toStringList(); + }; + const auto onDone = [this, config, storage](const QtcProcess &process) { + TestStorage *testStorage = storage.activeStorage(); + QTC_ASSERT(testStorage, return); + if (process.result() == ProcessResult::StartFailed) { + reportResult(ResultType::MessageFatal, + Tr::tr("Failed to start test for project \"%1\".").arg(config->displayName()) + + processInformation(&process) + rcInfo(config)); + } + + if (process.exitStatus() == QProcess::CrashExit) { + if (testStorage->m_outputReader) + testStorage->m_outputReader->reportCrash(); + reportResult(ResultType::MessageFatal, + Tr::tr("Test for project \"%1\" crashed.").arg(config->displayName()) + + processInformation(&process) + rcInfo(config)); + } else if (testStorage->m_outputReader && !testStorage->m_outputReader->hadValidOutput()) { + reportResult(ResultType::MessageFatal, + Tr::tr("Test for project \"%1\" did not produce any expected output.") + .arg(config->displayName()) + processInformation(&process) + + rcInfo(config)); + } + if (testStorage->m_outputReader) { + const int disabled = testStorage->m_outputReader->disabledTests(); + if (disabled > 0) + emit hadDisabledTests(disabled); + if (testStorage->m_outputReader->hasSummary()) + emit reportSummary(testStorage->m_outputReader->id(), testStorage->m_outputReader->summary()); + + testStorage->m_outputReader->resetCommandlineColor(); + } + }; + const Group group { + optional, + Storage(storage), + OnGroupSetup(onGroupSetup), + Process(onSetup, onDone, onDone) + }; + tasks.append(group); + } + + m_taskTree.reset(new TaskTree(tasks)); + connect(m_taskTree.get(), &TaskTree::done, this, &TestRunner::onFinished); + connect(m_taskTree.get(), &TaskTree::errorOccurred, this, &TestRunner::onFinished); + + auto progress = new TaskProgress(m_taskTree.get()); + progress->setDisplayName(tr("Running Tests")); + progress->setAutoStopOnCancel(false); + progress->setHalfLifeTimePerTask(10000); // 10 seconds + connect(progress, &TaskProgress::canceled, this, [this, progress] { + // progress was a child of task tree which is going to be deleted directly. Unwind properly. + progress->setParent(nullptr); + progress->deleteLater(); + cancelCurrent(UserCanceled); + }); - Core::ProgressManager::addTask(future, Tr::tr("Running Tests"), Autotest::Constants::TASK_INDEX); if (AutotestPlugin::settings()->popupOnStart) AutotestPlugin::popupResultsPane(); - scheduleNext(); + + m_taskTree->start(); } static void processOutput(TestOutputReader *outputreader, const QString &msg, OutputFormat format) @@ -626,13 +571,8 @@ void TestRunner::debugTests() } } - // We need a fake QFuture for the results. TODO: replace with QtConcurrent::run - QFutureInterface *futureInterface - = new QFutureInterface(QFutureInterfaceBase::Running); - m_futureWatcher.setFuture(futureInterface->future()); - if (useOutputProcessor) { - TestOutputReader *outputreader = config->createOutputReader(*futureInterface, nullptr); + TestOutputReader *outputreader = config->createOutputReader(nullptr); connect(outputreader, &TestOutputReader::newResult, this, &TestRunner::testResultReady); outputreader->setId(inferior.command.executable().toString()); connect(outputreader, &TestOutputReader::newOutputLineAvailable, @@ -641,9 +581,7 @@ void TestRunner::debugTests() this, [outputreader](const QString &msg, OutputFormat format) { processOutput(outputreader, msg, format); }); - - connect(runControl, &RunControl::stopped, - outputreader, &QObject::deleteLater); + connect(runControl, &RunControl::stopped, outputreader, &QObject::deleteLater); } m_stopDebugConnect = connect(this, &TestRunner::requestStopTestRun, @@ -671,7 +609,7 @@ void TestRunner::runOrDebugTests() if (!m_skipTargetsCheck) { if (executablesEmpty()) { m_skipTargetsCheck = true; - Target * target = SessionManager::startupTarget(); + Target *target = SessionManager::startupTarget(); QTimer::singleShot(5000, this, [this, target = QPointer(target)] { if (target) { disconnect(target, &Target::buildSystemUpdated, @@ -706,8 +644,7 @@ void TestRunner::buildProject(Project *project) BuildManager *buildManager = BuildManager::instance(); m_buildConnect = connect(this, &TestRunner::requestStopTestRun, buildManager, &BuildManager::cancel); - connect(buildManager, &BuildManager::buildQueueFinished, - this, &TestRunner::buildFinished); + connect(buildManager, &BuildManager::buildQueueFinished, this, &TestRunner::buildFinished); BuildManager::buildProjectWithDependencies(project); if (!BuildManager::isBuilding()) buildFinished(false); @@ -717,18 +654,14 @@ void TestRunner::buildFinished(bool success) { disconnect(m_buildConnect); BuildManager *buildManager = BuildManager::instance(); - disconnect(buildManager, &BuildManager::buildQueueFinished, - this, &TestRunner::buildFinished); + disconnect(buildManager, &BuildManager::buildQueueFinished, this, &TestRunner::buildFinished); if (success) { - if (!m_canceled) - runOrDebugTests(); - else if (m_executingTests) - onFinished(); - } else { - reportResult(ResultType::MessageFatal, Tr::tr("Build failed. Canceling test run.")); - onFinished(); + runOrDebugTests(); + return; } + reportResult(ResultType::MessageFatal, Tr::tr("Build failed. Canceling test run.")); + onFinished(); } static RunAfterBuildMode runAfterBuild() @@ -747,7 +680,7 @@ static RunAfterBuildMode runAfterBuild() void TestRunner::onBuildQueueFinished(bool success) { - if (m_executingTests || !m_selectedTests.isEmpty()) // paranoia! + if (isTestRunning() || !m_selectedTests.isEmpty()) // paranoia! return; if (!success || m_runMode != TestRunMode::None) @@ -768,17 +701,15 @@ void TestRunner::onBuildQueueFinished(bool success) void TestRunner::onFinished() { - m_cancelTimer.stop(); - // if we've been canceled and we still have test configurations queued just throw them away - qDeleteAll(m_selectedTests); - m_selectedTests.clear(); - + if (m_taskTree) + m_taskTree.release()->deleteLater(); disconnect(m_stopDebugConnect); disconnect(m_finishDebugConnect); disconnect(m_targetConnect); - m_fakeFutureInterface = nullptr; + qDeleteAll(m_selectedTests); + m_selectedTests.clear(); + m_cancelTimer.stop(); m_runMode = TestRunMode::None; - m_executingTests = false; emit testRunFinished(); } diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h index c96af56075f..f361d7297a8 100644 --- a/src/plugins/autotest/testrunner.h +++ b/src/plugins/autotest/testrunner.h @@ -4,12 +4,11 @@ #pragma once #include "autotest_global.h" -#include "testresult.h" + +#include "autotestconstants.h" #include -#include #include -#include #include QT_BEGIN_NAMESPACE @@ -20,13 +19,14 @@ class QLabel; QT_END_NAMESPACE namespace ProjectExplorer { class Project; } -namespace Utils { class QtcProcess; } +namespace Utils { class TaskTree; } namespace Autotest { -enum class TestRunMode; class ITestConfiguration; -class TestOutputReader; +class ITestTreeItem; +class TestResult; +enum class ResultType; namespace Internal { @@ -44,7 +44,7 @@ public: void runTests(TestRunMode mode, const QList &selectedTests); void runTest(TestRunMode mode, const ITestTreeItem *item); - bool isTestRunning() const { return m_executingTests; } + bool isTestRunning() const { return m_buildConnect || m_stopDebugConnect || m_taskTree.get(); } signals: void testRunStarted(); @@ -61,12 +61,7 @@ private: void onFinished(); int precheckTestConfigurations(); - bool currentConfigValid(); - void setUpProcessEnv(); - void scheduleNext(); void cancelCurrent(CancelReason reason); - void onProcessDone(); - void resetInternalPointers(); void runTestsHelper(); void debugTests(); @@ -75,14 +70,9 @@ private: bool postponeTestRunWithEmptyExecutable(ProjectExplorer::Project *project); void onBuildSystemUpdated(); - QFutureWatcher m_futureWatcher; - QFutureInterface *m_fakeFutureInterface = nullptr; + std::unique_ptr m_taskTree; + QList m_selectedTests; - bool m_executingTests = false; - bool m_canceled = false; - ITestConfiguration *m_currentConfig = nullptr; - Utils::QtcProcess *m_currentProcess = nullptr; - TestOutputReader *m_currentOutputReader = nullptr; TestRunMode m_runMode = TestRunMode::None; // temporarily used if building before running is necessary From 23309b5977af5e2a8d3cce5d8e823442f55c7465 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 27 Jan 2023 01:56:55 +0100 Subject: [PATCH 0036/1447] TestCodeParser: Reuse TaskTree Change-Id: Idf42f2c732151d32d70db9d2344bb18664119857 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/autotest/testcodeparser.cpp | 93 +++++++++++++------------ src/plugins/autotest/testcodeparser.h | 21 +++--- 2 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index edf126f8d42..69e90e9ac97 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -7,25 +7,21 @@ #include "autotesttr.h" #include "testtreemodel.h" -#include -#include #include +#include #include #include #include #include #include -#include #include -#include +#include #include -#include -#include -#include #include +using namespace Core; using namespace Utils; namespace Autotest { @@ -45,25 +41,20 @@ TestCodeParser::TestCodeParser() : m_threadPool(new QThreadPool(this)) { // connect to ProgressManager to postpone test parsing when CppModelManager is parsing - auto progressManager = qobject_cast(Core::ProgressManager::instance()); - connect(progressManager, &Core::ProgressManager::taskStarted, + ProgressManager *progressManager = ProgressManager::instance(); + connect(progressManager, &ProgressManager::taskStarted, this, &TestCodeParser::onTaskStarted); - connect(progressManager, &Core::ProgressManager::allTasksFinished, + connect(progressManager, &ProgressManager::allTasksFinished, this, &TestCodeParser::onAllTasksFinished); - connect(&m_futureWatcher, &QFutureWatcher::started, - this, &TestCodeParser::parsingStarted); - connect(&m_futureWatcher, &QFutureWatcher::finished, - this, &TestCodeParser::onFinished); - connect(&m_futureWatcher, &QFutureWatcher::resultReadyAt, - this, [this](int index) { - emit testParseResultReady(m_futureWatcher.resultAt(index)); - }); connect(this, &TestCodeParser::parsingFinished, this, &TestCodeParser::releaseParserInternals); m_reparseTimer.setSingleShot(true); connect(&m_reparseTimer, &QTimer::timeout, this, &TestCodeParser::parsePostponedFiles); m_threadPool->setMaxThreadCount(std::max(QThread::idealThreadCount()/4, 1)); + m_futureSynchronizer.setCancelOnWait(true); } +TestCodeParser::~TestCodeParser() = default; + void TestCodeParser::setState(State state) { if (m_parserState == Shutdown) @@ -100,7 +91,7 @@ void TestCodeParser::syncTestFrameworks(const QList &parsers) // there's a running parse m_postponedUpdateType = UpdateType::NoUpdate; m_postponedFiles.clear(); - Core::ProgressManager::cancelTasks(Constants::TASK_PARSE); + ProgressManager::cancelTasks(Constants::TASK_PARSE); } qCDebug(LOG) << "Setting" << parsers << "as current parsers"; m_testCodeParsers = parsers; @@ -185,7 +176,7 @@ void TestCodeParser::onStartupProjectChanged(Project *project) { if (m_parserState == FullParse || m_parserState == PartialParse) { qCDebug(LOG) << "Canceling scanForTest (startup project changed)"; - Core::ProgressManager::cancelTasks(Constants::TASK_PARSE); + ProgressManager::cancelTasks(Constants::TASK_PARSE); } emit aboutToPerformFullParse(); if (project) @@ -205,12 +196,9 @@ void TestCodeParser::onProjectPartsUpdated(Project *project) void TestCodeParser::aboutToShutdown() { qCDebug(LOG) << "Disabling (immediately) - shutting down"; - State oldState = m_parserState; m_parserState = Shutdown; - if (oldState == PartialParse || oldState == FullParse) { - m_futureWatcher.cancel(); - m_futureWatcher.waitForFinished(); - } + m_taskTree.reset(); + m_futureSynchronizer.waitForFinished(); } bool TestCodeParser::postponed(const FilePaths &fileList) @@ -249,7 +237,7 @@ bool TestCodeParser::postponed(const FilePaths &fileList) m_postponedFiles.clear(); m_postponedUpdateType = UpdateType::FullUpdate; qCDebug(LOG) << "Canceling scanForTest (full parse triggered while running a scan)"; - Core::ProgressManager::cancelTasks(Constants::TASK_PARSE); + ProgressManager::cancelTasks(Constants::TASK_PARSE); } else { // partial parse triggered, but full parse is postponed already, ignoring this if (m_postponedUpdateType == UpdateType::FullUpdate) @@ -266,9 +254,8 @@ bool TestCodeParser::postponed(const FilePaths &fileList) QTC_ASSERT(false, return false); // should not happen at all } -static void parseFileForTests(const QList &parsers, - QFutureInterface &futureInterface, - const FilePath &fileName) +static void parseFileForTests(QFutureInterface &futureInterface, + const QList &parsers, const FilePath &fileName) { for (ITestParser *parser : parsers) { if (futureInterface.isCanceled()) @@ -339,7 +326,7 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList codeParsers = parsers.isEmpty() ? m_testCodeParsers : parsers; @@ -367,18 +354,35 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList future = Utils::map(filteredList, - [codeParsers](QFutureInterface &fi, const FilePath &file) { - parseFileForTests(codeParsers, fi, file); - }, - MapReduceOption::Unordered, - m_threadPool, - QThread::LowestPriority); - m_futureWatcher.setFuture(future); - if (filteredList.size() > 5) { - Core::ProgressManager::addTask(future, Tr::tr("Scanning for Tests"), - Autotest::Constants::TASK_PARSE); + using namespace Tasking; + + QList tasks{parallel}; // TODO: use ParallelLimit(N) and add to settings? + for (const FilePath &file : filteredList) { + const auto setup = [this, codeParsers, file](AsyncTask &async) { + async.setAsyncCallData(parseFileForTests, codeParsers, file); + async.setThreadPool(m_threadPool); + async.setPriority(QThread::LowestPriority); + async.setFutureSynchronizer(&m_futureSynchronizer); + }; + const auto onDone = [this](const AsyncTask &async) { + const QList results = async.results(); + for (const TestParseResultPtr &result : results) + emit testParseResultReady(result); + }; + tasks.append(Async(setup, onDone)); } + m_taskTree.reset(new TaskTree{tasks}); + const auto onDone = [this] { m_taskTree.release()->deleteLater(); onFinished(true); }; + const auto onError = [this] { m_taskTree.release()->deleteLater(); onFinished(false); }; + connect(m_taskTree.get(), &TaskTree::started, this, &TestCodeParser::parsingStarted); + connect(m_taskTree.get(), &TaskTree::done, this, onDone); + connect(m_taskTree.get(), &TaskTree::errorOccurred, this, onError); + if (filteredList.size() > 5) { + auto progress = new TaskProgress(m_taskTree.get()); + progress->setDisplayName(Tr::tr("Scanning for Tests")); + progress->setId(Constants::TASK_PARSE); + } + m_taskTree->start(); } void TestCodeParser::onTaskStarted(Id type) @@ -390,7 +394,7 @@ void TestCodeParser::onTaskStarted(Id type) ? UpdateType::FullUpdate : UpdateType::PartialUpdate; qCDebug(LOG) << "Canceling scan for test (CppModelParsing started)"; m_parsingHasFailed = true; - Core::ProgressManager::cancelTasks(Constants::TASK_PARSE); + ProgressManager::cancelTasks(Constants::TASK_PARSE); } } } @@ -410,10 +414,9 @@ void TestCodeParser::onAllTasksFinished(Id type) setState(Idle); } -void TestCodeParser::onFinished() +void TestCodeParser::onFinished(bool success) { - if (m_futureWatcher.isCanceled()) - m_parsingHasFailed = true; + m_parsingHasFailed = !success; switch (m_parserState) { case PartialParse: qCDebug(LOG) << "setting state to Idle (onFinished, PartialParse)"; diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index efd0d602e4a..b9b8ef044b6 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -6,10 +6,10 @@ #include "itestparser.h" #include + +#include #include -#include -#include #include #include @@ -18,9 +18,9 @@ class QThreadPool; QT_END_NAMESPACE namespace ProjectExplorer { class Project; } +namespace Utils { class TaskTree; } namespace Autotest { - namespace Internal { class TestCodeParser : public QObject @@ -35,6 +35,7 @@ public: }; TestCodeParser(); + ~TestCodeParser(); void setState(State state); State state() const { return m_parserState; } @@ -48,7 +49,7 @@ public: signals: void aboutToPerformFullParse(); - void testParseResultReady(const TestParseResultPtr result); + void testParseResultReady(const TestParseResultPtr result); // TODO: pass list of results? void parsingStarted(); void parsingFinished(); void parsingFailed(); @@ -73,7 +74,7 @@ private: void onDocumentUpdated(const Utils::FilePath &fileName, bool isQmlFile = false); void onTaskStarted(Utils::Id type); void onAllTasksFinished(Utils::Id type); - void onFinished(); + void onFinished(bool success); void onPartialParsingFinished(); void parsePostponedFiles(); void releaseParserInternals(); @@ -83,21 +84,19 @@ private: bool m_parsingHasFailed = false; bool m_codeModelParsing = false; - enum class UpdateType { - NoUpdate, - PartialUpdate, - FullUpdate - } m_postponedUpdateType = UpdateType::NoUpdate; + enum class UpdateType { NoUpdate, PartialUpdate, FullUpdate }; + UpdateType m_postponedUpdateType = UpdateType::NoUpdate; bool m_dirty = false; bool m_singleShotScheduled = false; bool m_reparseTimerTimedOut = false; QSet m_postponedFiles; State m_parserState = Idle; - QFutureWatcher m_futureWatcher; QList m_testCodeParsers; // ptrs are still owned by TestFrameworkManager QTimer m_reparseTimer; QSet m_updateParsers; QThreadPool *m_threadPool = nullptr; + Utils::FutureSynchronizer m_futureSynchronizer; + std::unique_ptr m_taskTree; }; } // namespace Internal From cc52478a93e1b75f7fd3f34f0faf0bc2115ef542 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 3 Feb 2023 14:46:00 +0100 Subject: [PATCH 0037/1447] LanguageClient: Export LanguageClientOutlineItem To enable more customizations by specialized clients. Change-Id: I0ad92e248e931389c3fa239df424df8883e1d86e Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz --- src/libs/languageserverprotocol/lsptypes.h | 1 - src/plugins/clangcodemodel/clangdclient.cpp | 22 +++- src/plugins/clangcodemodel/clangdclient.h | 2 + src/plugins/languageclient/client.cpp | 18 ++- src/plugins/languageclient/client.h | 6 +- .../languageclient/languageclientoutline.cpp | 109 +++++++----------- .../languageclient/languageclientoutline.h | 36 ++++++ 7 files changed, 110 insertions(+), 84 deletions(-) diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index 239d40f6622..4adc35aa105 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -556,7 +556,6 @@ enum class SymbolKind { TypeParameter = 26, LastSymbolKind = TypeParameter, }; -using SymbolStringifier = std::function; namespace CompletionItemKind { enum Kind { diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 2c3f722617b..fb097b5aac2 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,20 @@ public: : Request("textDocument/symbolInfo", params) {} }; +class ClangdOutlineItem : public LanguageClientOutlineItem +{ + using LanguageClientOutlineItem::LanguageClientOutlineItem; +private: + QVariant data(int column, int role) const override + { + if (role == Qt::DisplayRole) { + return ClangdClient::displayNameFromDocumentSymbol( + static_cast(type()), name(), detail()); + } + return LanguageClientOutlineItem::data(column, role); + } +}; + void setupClangdConfigFile() { const Utils::FilePath targetConfigFile = CppEditor::ClangdSettings::clangdUserConfigFilePath(); @@ -427,7 +442,6 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c }); setCurrentProject(project); setDocumentChangeUpdateThreshold(d->settings.documentUpdateThreshold); - setSymbolStringifier(displayNameFromDocumentSymbol); setSemanticTokensHandler([this](TextDocument *doc, const QList &tokens, int version, bool force) { d->handleSemanticTokens(doc, tokens, version, force); @@ -661,6 +675,12 @@ DiagnosticManager *ClangdClient::createDiagnosticManager() return diagnosticManager; } +LanguageClientOutlineItem *ClangdClient::createOutlineItem( + const LanguageServerProtocol::DocumentSymbol &symbol) +{ + return new ClangdOutlineItem(this, symbol); +} + bool ClangdClient::referencesShadowFile(const TextEditor::TextDocument *doc, const Utils::FilePath &candidate) { diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 772920b2776..3c9e603b843 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -137,6 +137,8 @@ private: const CustomInspectorTabs createCustomInspectorTabs() override; TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const override; LanguageClient::DiagnosticManager *createDiagnosticManager() override; + LanguageClient::LanguageClientOutlineItem *createOutlineItem( + const LanguageServerProtocol::DocumentSymbol &symbol) override; bool referencesShadowFile(const TextEditor::TextDocument *doc, const Utils::FilePath &candidate) override; bool fileBelongsToProject(const Utils::FilePath &filePath) const override; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 0efaacd3500..23c086c8b2e 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -11,6 +11,7 @@ #include "languageclienthoverhandler.h" #include "languageclientinterface.h" #include "languageclientmanager.h" +#include "languageclientoutline.h" #include "languageclientquickfix.h" #include "languageclientsymbolsupport.h" #include "languageclientutils.h" @@ -325,7 +326,6 @@ public: SemanticTokenSupport m_tokenSupport; QString m_serverName; QString m_serverVersion; - LanguageServerProtocol::SymbolStringifier m_symbolStringifier; Client::LogTarget m_logTarget = Client::LogTarget::Ui; bool m_locatorsEnabled = true; bool m_autoRequestCodeActions = true; @@ -1484,16 +1484,6 @@ void Client::setSemanticTokensHandler(const SemanticTokensHandler &handler) d->m_tokenSupport.setTokensHandler(handler); } -void Client::setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier) -{ - d->m_symbolStringifier = stringifier; -} - -SymbolStringifier Client::symbolStringifier() const -{ - return d->m_symbolStringifier; -} - void Client::setSnippetsGroup(const QString &group) { if (const auto provider = qobject_cast( @@ -2089,6 +2079,12 @@ bool Client::fileBelongsToProject(const Utils::FilePath &filePath) const return project() && project()->isKnownFile(filePath); } +LanguageClientOutlineItem *Client::createOutlineItem( + const LanguageServerProtocol::DocumentSymbol &symbol) +{ + return new LanguageClientOutlineItem(this, symbol); +} + FilePath toHostPath(const FilePath serverDeviceTemplate, const FilePath localClientPath) { const FilePath onDevice = serverDeviceTemplate.withNewPath(localClientPath.path()); diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 525739d7a63..51f72cc7d4a 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -31,7 +31,6 @@ class Unregistration; } // namespace LanguageServerProtocol namespace LanguageClient { - class BaseClientInterface; class ClientPrivate; class DiagnosticManager; @@ -40,6 +39,7 @@ class DynamicCapabilities; class HoverHandler; class InterfaceController; class LanguageClientCompletionAssistProvider; +class LanguageClientOutlineItem; class LanguageClientQuickFixProvider; class LanguageFilter; class ProgressManager; @@ -160,13 +160,13 @@ public: const LanguageServerProtocol::Diagnostic &diag) const; bool hasDiagnostics(const TextEditor::TextDocument *document) const; void setSemanticTokensHandler(const SemanticTokensHandler &handler); - void setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier); - LanguageServerProtocol::SymbolStringifier symbolStringifier() const; void setSnippetsGroup(const QString &group); void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider); void setQuickFixAssistProvider(LanguageClientQuickFixProvider *provider); virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const; virtual bool fileBelongsToProject(const Utils::FilePath &filePath) const; + virtual LanguageClientOutlineItem *createOutlineItem( + const LanguageServerProtocol::DocumentSymbol &symbol); LanguageServerProtocol::DocumentUri::PathMapper hostPathMapper() const; Utils::FilePath serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const; diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 9ab057de62f..6d0596780ea 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -41,67 +41,10 @@ const QList sortedSymbols(const QList &symbols) }); } -class LanguageClientOutlineItem : public Utils::TypedTreeItem -{ -public: - LanguageClientOutlineItem() = default; - LanguageClientOutlineItem(const SymbolInformation &info) - : m_name(info.name()) - , m_range(info.location().range()) - , m_type(info.kind()) - { } - - LanguageClientOutlineItem(const DocumentSymbol &info, const SymbolStringifier &stringifier) - : m_name(info.name()) - , m_detail(info.detail().value_or(QString())) - , m_range(info.range()) - , m_symbolStringifier(stringifier) - , m_type(info.kind()) - { - const QList children = sortedSymbols( - info.children().value_or(QList())); - for (const DocumentSymbol &child : children) - appendChild(new LanguageClientOutlineItem(child, stringifier)); - } - - // TreeItem interface - QVariant data(int column, int role) const override - { - switch (role) { - case Qt::DecorationRole: - return symbolIcon(m_type); - case Qt::DisplayRole: - return m_symbolStringifier - ? m_symbolStringifier(static_cast(m_type), m_name, m_detail) - : m_name; - default: - return Utils::TreeItem::data(column, role); - } - } - - Qt::ItemFlags flags(int column) const override - { - Q_UNUSED(column) - return Utils::TypedTreeItem::flags(column) - | Qt::ItemIsDragEnabled; - } - - Range range() const { return m_range; } - Position pos() const { return m_range.start(); } - bool contains(const Position &pos) const { return m_range.contains(pos); } - -private: - QString m_name; - QString m_detail; - Range m_range; - SymbolStringifier m_symbolStringifier; - int m_type = -1; -}; - class LanguageClientOutlineModel : public Utils::TreeModel { public: - using Utils::TreeModel::TreeModel; + LanguageClientOutlineModel(Client *client) : m_client(client) {} void setFilePath(const Utils::FilePath &filePath) { m_filePath = filePath; } void setInfo(const QList &info) @@ -114,12 +57,7 @@ public: { clear(); for (const DocumentSymbol &symbol : sortedSymbols(info)) - rootItem()->appendChild(new LanguageClientOutlineItem(symbol, m_symbolStringifier)); - } - - void setSymbolStringifier(const SymbolStringifier &stringifier) - { - m_symbolStringifier = stringifier; + rootItem()->appendChild(m_client->createOutlineItem(symbol)); } Qt::DropActions supportedDragActions() const override @@ -145,7 +83,7 @@ public: } private: - SymbolStringifier m_symbolStringifier; + Client * const m_client; Utils::FilePath m_filePath; }; @@ -194,6 +132,7 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, TextEditor::BaseTextEditor *editor) : m_client(client) , m_editor(editor) + , m_model(client) , m_view(this) , m_uri(m_client->hostPathToServerUri(editor->textDocument()->filePath())) { @@ -213,7 +152,6 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, layout->setSpacing(0); layout->addWidget(Core::ItemViewFind::createSearchableWrapper(&m_view)); setLayout(layout); - m_model.setSymbolStringifier(m_client->symbolStringifier()); m_model.setFilePath(editor->textDocument()->filePath()); m_proxyModel.setSourceModel(&m_model); m_view.setModel(&m_proxyModel); @@ -372,11 +310,11 @@ Utils::TreeViewComboBox *LanguageClientOutlineWidgetFactory::createComboBox( } OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor) - : m_client(client) + : m_model(client) + , m_client(client) , m_editorWidget(editor->editorWidget()) , m_uri(m_client->hostPathToServerUri(editor->document()->filePath())) { - m_model.setSymbolStringifier(client->symbolStringifier()); m_proxyModel.setSourceModel(&m_model); const bool sorted = LanguageClientSettings::outlineComboBoxIsSorted(); m_proxyModel.sort(sorted ? 0 : -1); @@ -455,4 +393,39 @@ void OutlineComboBox::setSorted(bool sorted) m_proxyModel.sort(sorted ? 0 : -1); } +LanguageClientOutlineItem::LanguageClientOutlineItem(const SymbolInformation &info) + : m_name(info.name()) + , m_range(info.location().range()) + , m_type(info.kind()) +{ } + +LanguageClientOutlineItem::LanguageClientOutlineItem(Client *client, const DocumentSymbol &info) + : m_client(client) + , m_name(info.name()) + , m_detail(info.detail().value_or(QString())) + , m_range(info.range()) + , m_type(info.kind()) +{ + const QList children = sortedSymbols( + info.children().value_or(QList())); + for (const DocumentSymbol &child : children) + appendChild(m_client->createOutlineItem(child)); +} + +QVariant LanguageClientOutlineItem::data(int column, int role) const +{ + switch (role) { + case Qt::DecorationRole: + return symbolIcon(m_type); + case Qt::DisplayRole: + return m_name; + default: + return Utils::TreeItem::data(column, role); + } +} +Qt::ItemFlags LanguageClientOutlineItem::flags(int column) const +{ + Q_UNUSED(column) + return Utils::TypedTreeItem::flags(column) | Qt::ItemIsDragEnabled; +} } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientoutline.h b/src/plugins/languageclient/languageclientoutline.h index e333563dc2d..1dc73dd4c9a 100644 --- a/src/plugins/languageclient/languageclientoutline.h +++ b/src/plugins/languageclient/languageclientoutline.h @@ -3,7 +3,11 @@ #pragma once +#include "languageclient_global.h" + +#include #include +#include namespace TextEditor { class TextDocument; @@ -12,6 +16,38 @@ class BaseTextEditor; namespace Utils { class TreeViewComboBox; } namespace LanguageClient { +class Client; + +class LANGUAGECLIENT_EXPORT LanguageClientOutlineItem + : public Utils::TypedTreeItem +{ +public: + LanguageClientOutlineItem() = default; + LanguageClientOutlineItem(const LanguageServerProtocol::SymbolInformation &info); + LanguageClientOutlineItem(Client *client, const LanguageServerProtocol::DocumentSymbol &info); + + LanguageServerProtocol::Range range() const { return m_range; } + LanguageServerProtocol::Position pos() const { return m_range.start(); } + bool contains(const LanguageServerProtocol::Position &pos) const { + return m_range.contains(pos); + } + +protected: + // TreeItem interface + QVariant data(int column, int role) const override; + Qt::ItemFlags flags(int column) const override; + + QString name() const { return m_name; } + QString detail() const { return m_detail; } + int type() const { return m_type; } + +private: + Client * const m_client = nullptr; + QString m_name; + QString m_detail; + LanguageServerProtocol::Range m_range; + int m_type = -1; +}; class Client; From dbe411ca4c3d5073072159b0bc28673d0b5cb251 Mon Sep 17 00:00:00 2001 From: Knut Petter Svendsen Date: Wed, 8 Feb 2023 10:56:01 +0100 Subject: [PATCH 0038/1447] GenericProjectManager: Fix outdated comment Change-Id: I9295380515c64da90a23f4fd95eae67273924d19 Reviewed-by: hjk --- src/plugins/genericprojectmanager/genericproject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index b0dc38ae7c7..38f72d14cb6 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -96,7 +96,7 @@ private: //////////////////////////////////////////////////////////////////////////////////// // -// GenericProjectNode +// GenericBuildSystem // //////////////////////////////////////////////////////////////////////////////////// From a811afaeab63275c96e27037f1b875770d495f64 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 3 Feb 2023 15:29:12 +0100 Subject: [PATCH 0039/1447] CppEditor: Render forward decls less prominently in outline Fixes: QTCREATORBUG-312 Change-Id: I9bb77add24737881eeee008620941b55118ee0e5 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 10 +++++++++- src/plugins/cppeditor/cppoutlinemodel.cpp | 19 +++++++++++++++++++ .../languageclient/languageclientoutline.cpp | 1 + .../languageclient/languageclientoutline.h | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index fb097b5aac2..9cb30726b0c 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -135,9 +136,16 @@ class ClangdOutlineItem : public LanguageClientOutlineItem private: QVariant data(int column, int role) const override { - if (role == Qt::DisplayRole) { + switch (role) { + case Qt::DisplayRole: return ClangdClient::displayNameFromDocumentSymbol( static_cast(type()), name(), detail()); + case Qt::ForegroundRole: + if ((detail().endsWith("class") || detail().endsWith("struct")) + && range().end() == selectionRange().end()) { + return creatorTheme()->color(Theme::TextColorDisabled); + } + break; } return LanguageClientOutlineItem::data(column, role); } diff --git a/src/plugins/cppeditor/cppoutlinemodel.cpp b/src/plugins/cppeditor/cppoutlinemodel.cpp index bbf3610ebf4..967c3987792 100644 --- a/src/plugins/cppeditor/cppoutlinemodel.cpp +++ b/src/plugins/cppeditor/cppoutlinemodel.cpp @@ -11,6 +11,7 @@ #include #include +#include #include @@ -103,6 +104,24 @@ public: return name; } + case Qt::ForegroundRole: { + const auto isFwdDecl = [&] { + const FullySpecifiedType type = symbol->type(); + if (type->asForwardClassDeclarationType()) + return true; + if (const Template * const tmpl = type->asTemplateType()) + return tmpl->declaration() && tmpl->declaration()->asForwardClassDeclaration(); + if (type->asObjCForwardClassDeclarationType()) + return true; + if (type->asObjCForwardProtocolDeclarationType()) + return true; + return false; + }; + if (isFwdDecl()) + return Utils::creatorTheme()->color(Utils::Theme::TextColorDisabled); + return TreeItem::data(column, role); + } + case Qt::DecorationRole: return Icons::iconForSymbol(symbol); diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 6d0596780ea..bfa56b24174 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -404,6 +404,7 @@ LanguageClientOutlineItem::LanguageClientOutlineItem(Client *client, const Docum , m_name(info.name()) , m_detail(info.detail().value_or(QString())) , m_range(info.range()) + , m_selectionRange(info.selectionRange()) , m_type(info.kind()) { const QList children = sortedSymbols( diff --git a/src/plugins/languageclient/languageclientoutline.h b/src/plugins/languageclient/languageclientoutline.h index 1dc73dd4c9a..4ddc9c79c08 100644 --- a/src/plugins/languageclient/languageclientoutline.h +++ b/src/plugins/languageclient/languageclientoutline.h @@ -27,6 +27,7 @@ public: LanguageClientOutlineItem(Client *client, const LanguageServerProtocol::DocumentSymbol &info); LanguageServerProtocol::Range range() const { return m_range; } + LanguageServerProtocol::Range selectionRange() const { return m_selectionRange; } LanguageServerProtocol::Position pos() const { return m_range.start(); } bool contains(const LanguageServerProtocol::Position &pos) const { return m_range.contains(pos); @@ -46,6 +47,7 @@ private: QString m_name; QString m_detail; LanguageServerProtocol::Range m_range; + LanguageServerProtocol::Range m_selectionRange; int m_type = -1; }; From bb9e49274526a9b37207497af4f39b22132fa08f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 8 Feb 2023 11:13:51 +0100 Subject: [PATCH 0040/1447] CppEditor: Prevent duplicate symbols in document-scope locator If declaration and definition of a symbol are present, offer only the definition, as in the function and class locators. Fixes: QTCREATORBUG-13894 Change-Id: I6794607c4c45831df53b022bbdad9db7205a890b Reviewed-by: David Schulz --- .../clangcodemodel/clangdlocatorfilters.cpp | 70 ++++++++++++++++++- .../cppeditor/cppcurrentdocumentfilter.cpp | 33 ++++++++- .../cppeditor/cpplocatorfilter_test.cpp | 5 -- src/plugins/cppeditor/indexitem.cpp | 4 +- src/plugins/cppeditor/indexitem.h | 5 +- src/plugins/cppeditor/searchsymbols.cpp | 3 +- 6 files changed, 109 insertions(+), 11 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index d06920acc6a..5034056d997 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -14,7 +14,9 @@ #include #include #include +#include +#include #include #include @@ -219,6 +221,11 @@ public: } private: + void prepareSearch(const QString &) override + { + m_content = TextEditor::TextDocument::currentTextDocument()->plainText(); + } + Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info, const Core::LocatorFilterEntry &parent) override { @@ -227,8 +234,7 @@ private: entry.displayName = ClangdClient::displayNameFromDocumentSymbol( static_cast(info.kind()), info.name(), info.detail().value_or(QString())); - const Position &pos = info.range().start(); - entry.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character())); + entry.internalData = QVariant::fromValue(info); entry.extraInfo = parent.extraInfo; if (!entry.extraInfo.isEmpty()) entry.extraInfo.append("::"); @@ -239,6 +245,66 @@ private: return entry; } + + // Filter out declarations for which a definition is also present. + QList matchesFor(QFutureInterface &future, + const QString &entry) override + { + QList allMatches + = DocumentLocatorFilter::matchesFor(future, entry); + QHash> possibleDuplicates; + for (const Core::LocatorFilterEntry &e : std::as_const(allMatches)) + possibleDuplicates[e.displayName + e.extraInfo] << e; + const QTextDocument doc(m_content); + for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { + const QList &duplicates = it.value(); + if (duplicates.size() == 1) + continue; + QList declarations; + QList definitions; + for (const Core::LocatorFilterEntry &candidate : duplicates) { + const auto symbol = qvariant_cast(candidate.internalData); + const SymbolKind kind = static_cast(symbol.kind()); + if (kind != SymbolKind::Class && kind != SymbolKind::Function) + break; + const Range range = symbol.range(); + const Range selectionRange = symbol.selectionRange(); + if (kind == SymbolKind::Class) { + if (range.end() == selectionRange.end()) + declarations << candidate; + else + definitions << candidate; + continue; + } + const int startPos = selectionRange.end().toPositionInDocument(&doc); + const int endPos = range.end().toPositionInDocument(&doc); + const QString functionBody = m_content.mid(startPos, endPos - startPos); + + // Hacky, but I don't see anything better. + if (functionBody.contains('{') && functionBody.contains('}')) + definitions << candidate; + else + declarations << candidate; + } + if (definitions.size() == 1 + && declarations.size() + definitions.size() == duplicates.size()) { + for (const Core::LocatorFilterEntry &decl : std::as_const(declarations)) + Utils::erase(allMatches, [&decl](const Core::LocatorFilterEntry &e) { + return e.internalData == decl.internalData; + }); + } + } + + // The base implementation expects the position in the internal data. + for (Core::LocatorFilterEntry &e : allMatches) { + const Position pos = qvariant_cast(e.internalData).range().start(); + e.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character())); + } + + return allMatches; + } + + QString m_content; }; class ClangdCurrentDocumentFilter::Private diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index 6c7c4448069..d17df20717f 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -9,7 +9,9 @@ #include #include #include +#include +#include #include using namespace CPlusPlus; @@ -100,8 +102,37 @@ QList CppCurrentDocumentFilter::matchesFor( } // entries are unsorted by design! - betterEntries += goodEntries; + + QHash> possibleDuplicates; + for (const Core::LocatorFilterEntry &e : std::as_const(betterEntries)) { + const IndexItem::Ptr info = qvariant_cast(e.internalData); + possibleDuplicates[info->scopedSymbolName() + info->symbolType()] << e; + } + for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { + const QList &duplicates = it.value(); + if (duplicates.size() == 1) + continue; + QList declarations; + QList definitions; + for (const Core::LocatorFilterEntry &candidate : duplicates) { + const IndexItem::Ptr info = qvariant_cast(candidate.internalData); + if (info->type() != IndexItem::Function) + break; + if (info->isFunctionDefinition()) + definitions << candidate; + else + declarations << candidate; + } + if (definitions.size() == 1 + && declarations.size() + definitions.size() == duplicates.size()) { + for (const Core::LocatorFilterEntry &decl : std::as_const(declarations)) + Utils::erase(betterEntries, [&decl](const Core::LocatorFilterEntry &e) { + return e.internalData == decl.internalData; + }); + } + } + return betterEntries; } diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index 598a6e85640..5b443ad42ce 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -319,7 +319,6 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("functionDeclaredOnly()", "MyClass"), ResultData("functionDefinedInClass(bool, int)", "MyClass"), ResultData("functionDefinedOutSideClass(char)", "MyClass"), - ResultData("functionDefinedOutSideClass(char)", "MyClass"), ResultData("int myVariable", "MyNamespace"), ResultData("myFunction(bool, int)", "MyNamespace"), ResultData("MyEnum", "MyNamespace"), @@ -330,9 +329,6 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("functionDeclaredOnly()", "MyNamespace::MyClass"), ResultData("functionDefinedInClass(bool, int)", "MyNamespace::MyClass"), ResultData("functionDefinedOutSideClass(char)", "MyNamespace::MyClass"), - ResultData("functionDefinedOutSideClassAndNamespace(float)", - "MyNamespace::MyClass"), - ResultData("functionDefinedOutSideClass(char)", "MyNamespace::MyClass"), ResultData("functionDefinedOutSideClassAndNamespace(float)", "MyNamespace::MyClass"), ResultData("int myVariable", ""), @@ -345,7 +341,6 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("functionDeclaredOnly()", "::MyClass"), ResultData("functionDefinedInClass(bool, int)", "::MyClass"), ResultData("functionDefinedOutSideClass(char)", "::MyClass"), - ResultData("functionDefinedOutSideClass(char)", "::MyClass"), ResultData("main()", ""), }; diff --git a/src/plugins/cppeditor/indexitem.cpp b/src/plugins/cppeditor/indexitem.cpp index 3094c9d4945..879625263e2 100644 --- a/src/plugins/cppeditor/indexitem.cpp +++ b/src/plugins/cppeditor/indexitem.cpp @@ -9,7 +9,8 @@ namespace CppEditor { IndexItem::Ptr IndexItem::create(const QString &symbolName, const QString &symbolType, const QString &symbolScope, IndexItem::ItemType type, - const QString &fileName, int line, int column, const QIcon &icon) + const QString &fileName, int line, int column, const QIcon &icon, + bool isFunctionDefinition) { Ptr ptr(new IndexItem); @@ -21,6 +22,7 @@ IndexItem::Ptr IndexItem::create(const QString &symbolName, const QString &symbo ptr->m_line = line; ptr->m_column = column; ptr->m_icon = icon; + ptr->m_isFuncDef = isFunctionDefinition; return ptr; } diff --git a/src/plugins/cppeditor/indexitem.h b/src/plugins/cppeditor/indexitem.h index eda023394df..135bd60adcd 100644 --- a/src/plugins/cppeditor/indexitem.h +++ b/src/plugins/cppeditor/indexitem.h @@ -40,7 +40,8 @@ public: const QString &fileName, int line, int column, - const QIcon &icon); + const QIcon &icon, + bool isFunctionDefinition); static Ptr create(const QString &fileName, int sizeHint); QString scopedSymbolName() const @@ -64,6 +65,7 @@ public: ItemType type() const { return m_type; } int line() const { return m_line; } int column() const { return m_column; } + bool isFunctionDefinition() const { return m_isFuncDef; } void addChild(IndexItem::Ptr childItem) { m_children.append(childItem); } void squeeze(); @@ -106,6 +108,7 @@ private: ItemType m_type = All; int m_line = 0; int m_column = 0; + bool m_isFuncDef = false; QVector m_children; }; diff --git a/src/plugins/cppeditor/searchsymbols.cpp b/src/plugins/cppeditor/searchsymbols.cpp index 22e0c281975..2aea7f8e1bf 100644 --- a/src/plugins/cppeditor/searchsymbols.cpp +++ b/src/plugins/cppeditor/searchsymbols.cpp @@ -285,7 +285,8 @@ IndexItem::Ptr SearchSymbols::addChildItem(const QString &symbolName, const QStr StringTable::insert(path), symbol->line(), symbol->column() - 1, // 1-based vs 0-based column - icon); + icon, + symbol->asFunction()); _parent->addChild(newItem); return newItem; } From 207f2b216c5937c737f46bf2aacebaef93c3ffb3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 8 Feb 2023 17:18:13 +0100 Subject: [PATCH 0041/1447] CPlusPlus: Add lexer support for new C++20 keywords Change-Id: I2b83deb0502ebf2cdca2af774fbb2ce26e947c11 Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/Keywords.cpp | 104 +++++++++++++++++- src/libs/3rdparty/cplusplus/Keywords.kwgen | 10 ++ src/libs/3rdparty/cplusplus/Token.cpp | 8 ++ src/libs/3rdparty/cplusplus/Token.h | 8 ++ src/libs/cplusplus/cplusplus.qbs | 1 + .../cppeditor/cppcodemodelinspectordumper.cpp | 8 ++ src/plugins/cppeditor/cppcompletion_test.cpp | 12 +- tests/auto/cplusplus/lexer/tst_lexer.cpp | 33 ++++++ 8 files changed, 174 insertions(+), 10 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/Keywords.cpp b/src/libs/3rdparty/cplusplus/Keywords.cpp index 1637333b420..a60ec24aec9 100644 --- a/src/libs/3rdparty/cplusplus/Keywords.cpp +++ b/src/libs/3rdparty/cplusplus/Keywords.cpp @@ -603,6 +603,34 @@ static inline int classify7(const char *s, LanguageFeatures features) } } } + else if (features.cxx20Enabled && s[0] == 'c') { + if (s[1] == 'h') { + if (s[2] == 'a') { + if (s[3] == 'r') { + if (s[4] == '8') { + if (s[5] == '_') { + if (s[6] == 't') { + return T_CHAR8_T; + } + } + } + } + } + } + else if (s[1] == 'o') { + if (s[2] == 'n') { + if (s[3] == 'c') { + if (s[4] == 'e') { + if (s[5] == 'p') { + if (s[6] == 't') { + return T_CONCEPT; + } + } + } + } + } + } + } else if (s[0] == 'd') { if (s[1] == 'e') { if (s[2] == 'f') { @@ -847,7 +875,31 @@ static inline int classify8(const char *s, LanguageFeatures features) } } else if (s[1] == 'o') { - if (s[2] == 'n') { + if (features.cxx20Enabled && s[2] == '_') { + if (s[3] == 'a') { + if (s[4] == 'w') { + if (s[5] == 'a') { + if (s[6] == 'i') { + if (s[7] == 't') { + return T_CO_AWAIT; + } + } + } + } + } + else if (s[3] == 'y') { + if (s[4] == 'i') { + if (s[5] == 'e') { + if (s[6] == 'l') { + if (s[7] == 'd') { + return T_CO_YIELD; + } + } + } + } + } + } + else if (s[2] == 'n') { if (s[3] == 't') { if (s[4] == 'i') { if (s[5] == 'n') { @@ -945,6 +997,19 @@ static inline int classify8(const char *s, LanguageFeatures features) } } } + else if (features.cxx20Enabled && s[2] == 'q') { + if (s[3] == 'u') { + if (s[4] == 'i') { + if (s[5] == 'r') { + if (s[6] == 'e') { + if (s[7] == 's') { + return T_REQUIRES; + } + } + } + } + } + } } } else if (features.cxxEnabled && s[0] == 't') { @@ -1097,13 +1162,35 @@ static inline int classify9(const char *s, LanguageFeatures features) } } } - else if (features.cxx11Enabled && s[0] == 'c') { + else if (s[0] == 'c') { if (s[1] == 'o') { - if (s[2] == 'n') { + if (features.cxx20Enabled && s[2] == '_') { + if (s[3] == 'r') { + if (s[4] == 'e') { + if (s[5] == 't') { + if (s[6] == 'u') { + if (s[7] == 'r') { + if (s[8] == 'n') { + return T_CO_RETURN; + } + } + } + } + } + } + } + else if (s[2] == 'n') { if (s[3] == 's') { if (s[4] == 't') { if (s[5] == 'e') { - if (s[6] == 'x') { + if (features.cxx20Enabled && s[6] == 'v') { + if (s[7] == 'a') { + if (s[8] == 'l') { + return T_CONSTEVAL; + } + } + } + else if (features.cxx11Enabled && s[6] == 'x') { if (s[7] == 'p') { if (s[8] == 'r') { return T_CONSTEXPR; @@ -1111,6 +1198,15 @@ static inline int classify9(const char *s, LanguageFeatures features) } } } + else if (features.cxx20Enabled && s[5] == 'i') { + if (s[6] == 'n') { + if (s[7] == 'i') { + if (s[8] == 't') { + return T_CONSTINIT; + } + } + } + } } } } diff --git a/src/libs/3rdparty/cplusplus/Keywords.kwgen b/src/libs/3rdparty/cplusplus/Keywords.kwgen index 36300a87766..70deeb648d8 100644 --- a/src/libs/3rdparty/cplusplus/Keywords.kwgen +++ b/src/libs/3rdparty/cplusplus/Keywords.kwgen @@ -128,6 +128,16 @@ nullptr static_assert thread_local +%pre-check=features.cxx20Enabled +char8_t +concept +consteval +constinit +co_await +co_return +co_yield +requires + %pre-check=features.qtKeywordsEnabled emit foreach diff --git a/src/libs/3rdparty/cplusplus/Token.cpp b/src/libs/3rdparty/cplusplus/Token.cpp index 31fdb2036c2..2e8a0ce7f24 100644 --- a/src/libs/3rdparty/cplusplus/Token.cpp +++ b/src/libs/3rdparty/cplusplus/Token.cpp @@ -120,9 +120,15 @@ const char *token_names[] = { ("case"), ("catch"), ("class"), + ("co_await"), + ("co_return"), + ("co_yield"), + ("concept"), ("const"), ("const_cast"), + ("consteval"), ("constexpr"), + ("constinit"), ("continue"), ("decltype"), ("default"), @@ -151,6 +157,7 @@ const char *token_names[] = { ("public"), ("register"), ("reinterpret_cast"), + ("requires"), ("return"), ("sizeof"), ("static"), @@ -210,6 +217,7 @@ const char *token_names[] = { // Primitive types ("bool"), ("char"), + ("char8_t"), ("char16_t"), ("char32_t"), ("double"), diff --git a/src/libs/3rdparty/cplusplus/Token.h b/src/libs/3rdparty/cplusplus/Token.h index 3a04a44a86a..204096893ad 100644 --- a/src/libs/3rdparty/cplusplus/Token.h +++ b/src/libs/3rdparty/cplusplus/Token.h @@ -130,9 +130,15 @@ enum Kind { T_CASE, T_CATCH, T_CLASS, + T_CO_AWAIT, + T_CO_RETURN, + T_CO_YIELD, + T_CONCEPT, T_CONST, T_CONST_CAST, + T_CONSTEVAL, T_CONSTEXPR, + T_CONSTINIT, T_CONTINUE, T_DECLTYPE, T_DEFAULT, @@ -161,6 +167,7 @@ enum Kind { T_PUBLIC, T_REGISTER, T_REINTERPRET_CAST, + T_REQUIRES, T_RETURN, T_SIZEOF, T_STATIC, @@ -223,6 +230,7 @@ enum Kind { T_FIRST_PRIMITIVE, T_BOOL = T_FIRST_PRIMITIVE, T_CHAR, + T_CHAR8_T, T_CHAR16_T, T_CHAR32_T, T_DOUBLE, diff --git a/src/libs/cplusplus/cplusplus.qbs b/src/libs/cplusplus/cplusplus.qbs index 80c6174ba22..0aed0ab438f 100644 --- a/src/libs/cplusplus/cplusplus.qbs +++ b/src/libs/cplusplus/cplusplus.qbs @@ -41,6 +41,7 @@ Project { "FullySpecifiedType.cpp", "FullySpecifiedType.h", "Keywords.cpp", + "Keywords.kwgen", "Lexer.cpp", "Lexer.h", "LiteralTable.h", diff --git a/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp b/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp index 45de8f30539..2a6dfb6e1e8 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp @@ -254,12 +254,19 @@ QString Utils::toString(CPlusPlus::Kind kind) TOKEN(T_CASE); TOKEN(T_CATCH); TOKEN(T_CHAR); + TOKEN(T_CHAR8_T); TOKEN(T_CHAR16_T); TOKEN(T_CHAR32_T); TOKEN(T_CLASS); + TOKEN(T_CO_AWAIT); + TOKEN(T_CO_RETURN); + TOKEN(T_CO_YIELD); + TOKEN(T_CONCEPT); TOKEN_AND_ALIASES(T_CONST, T___CONST/T___CONST__); TOKEN(T_CONST_CAST); TOKEN(T_CONSTEXPR); + TOKEN(T_CONSTEVAL); + TOKEN(T_CONSTINIT); TOKEN(T_CONTINUE); TOKEN_AND_ALIASES(T_DECLTYPE, T___DECLTYPE); TOKEN(T_DEFAULT); @@ -292,6 +299,7 @@ QString Utils::toString(CPlusPlus::Kind kind) TOKEN(T_PUBLIC); TOKEN(T_REGISTER); TOKEN(T_REINTERPRET_CAST); + TOKEN(T_REQUIRES); TOKEN(T_RETURN); TOKEN(T_SHORT); TOKEN(T_SIGNED); diff --git a/src/plugins/cppeditor/cppcompletion_test.cpp b/src/plugins/cppeditor/cppcompletion_test.cpp index 78407d59599..56e4987af6a 100644 --- a/src/plugins/cppeditor/cppcompletion_test.cpp +++ b/src/plugins/cppeditor/cppcompletion_test.cpp @@ -409,16 +409,16 @@ static void enumTestCase(const QByteArray &tag, const QByteArray &source, const QByteArray &prefix = QByteArray()) { QByteArray fullSource = source; - fullSource.replace('$', "enum E { val1, val2, val3 };"); - QTest::newRow(tag) << fullSource << (prefix + "val") - << QStringList({"val1", "val2", "val3"}); + fullSource.replace('$', "enum E { value1, value2, value3 };"); + QTest::newRow(tag) << fullSource << (prefix + "value") + << QStringList({"value1", "value2", "value3"}); QTest::newRow(QByteArray{tag + "_cxx11"}) << fullSource << QByteArray{prefix + "E::"} - << QStringList({"E", "val1", "val2", "val3"}); + << QStringList({"E", "value1", "value2", "value3"}); fullSource.replace("enum E ", "enum "); - QTest::newRow(QByteArray{tag + "_anon"}) << fullSource << QByteArray{prefix + "val"} - << QStringList({"val1", "val2", "val3"}); + QTest::newRow(QByteArray{tag + "_anon"}) << fullSource << QByteArray{prefix + "value"} + << QStringList({"value1", "value2", "value3"}); } void CompletionTest::testCompletion_data() diff --git a/tests/auto/cplusplus/lexer/tst_lexer.cpp b/tests/auto/cplusplus/lexer/tst_lexer.cpp index 641b62f248c..09a474504ee 100644 --- a/tests/auto/cplusplus/lexer/tst_lexer.cpp +++ b/tests/auto/cplusplus/lexer/tst_lexer.cpp @@ -43,6 +43,7 @@ public: private slots: void basic(); void basic_data(); + void cxx20(); void incremental(); void incremental_data(); void literals(); @@ -250,6 +251,38 @@ void tst_SimpleLexer::basic_data() QTest::newRow(source) << source << expectedTokenKindList; } +void tst_SimpleLexer::cxx20() +{ + LanguageFeatures features; + features.cxxEnabled = features.cxx11Enabled = features.cxx14Enabled + = features.cxx20Enabled = true; + const QString source = R"( +template concept IsPointer = requires(T p) { *p; }; +SomeType coroutine() +{ + constinit const char8_t = 'c'; + if consteval {} else {} + co_await std::suspend_always{}; + co_yield 1; + co_return; +} +)"; + const TokenKindList expectedTokens = { + T_TEMPLATE, T_LESS, T_TYPENAME, T_IDENTIFIER, T_GREATER, T_CONCEPT, T_IDENTIFIER, T_EQUAL, + T_REQUIRES, T_LPAREN, T_IDENTIFIER, T_IDENTIFIER, T_RPAREN, T_LBRACE, T_STAR, T_IDENTIFIER, + T_SEMICOLON, T_RBRACE, T_SEMICOLON, + T_IDENTIFIER, T_IDENTIFIER, T_LPAREN, T_RPAREN, + T_LBRACE, + T_CONSTINIT, T_CONST, T_CHAR8_T, T_EQUAL, T_CHAR_LITERAL, T_SEMICOLON, + T_IF, T_CONSTEVAL, T_LBRACE, T_RBRACE, T_ELSE, T_LBRACE, T_RBRACE, + T_CO_AWAIT, T_IDENTIFIER, T_COLON_COLON, T_IDENTIFIER, T_LBRACE, T_RBRACE, T_SEMICOLON, + T_CO_YIELD, T_NUMERIC_LITERAL, T_SEMICOLON, + T_CO_RETURN, T_SEMICOLON, + T_RBRACE + }; + run(source.toUtf8(), toTokens(expectedTokens), false, CompareKind, false, features); +} + void tst_SimpleLexer::literals() { QFETCH(QByteArray, source); From 0edcbd8853d15f478b66f38a9fefa630d9ec6146 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 9 Feb 2023 07:45:04 +0100 Subject: [PATCH 0042/1447] CPlusPlus: Always build the tools There is no advantage to excluding the tools by default that outweighs the risk for them to get out of sync with the rest of the codebase. Change-Id: I3ad292aa5648a4448babdf5d06c84b3f5ec94482 Reviewed-by: Christian Stenger --- src/tools/CMakeLists.txt | 13 +++++-------- src/tools/cplusplus-shared/CPlusPlusTool.qbs | 1 + src/tools/cplusplustools.qbs | 1 - 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 1bee7cccfbc..75ca1590b00 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,10 +1,9 @@ add_subdirectory(3rdparty) add_subdirectory(buildoutputparser) -option(BUILD_CPLUSPLUS_TOOLS "Build CPlusPlus tools" OFF) - function(add_qtc_cpp_tool name) add_qtc_executable(${name} + SKIP_INSTALL DEFINES PATH_PREPROCESSOR_CONFIG=\"${CMAKE_CURRENT_SOURCE_DIR}/cplusplus-shared/pp-configuration.inc\" ${ARGN} @@ -17,12 +16,10 @@ function(add_qtc_cpp_tool name) ) endfunction() -if (BUILD_CPLUSPLUS_TOOLS) - add_qtc_cpp_tool(cplusplus-ast2png "") - add_qtc_cpp_tool(cplusplus-frontend "") - add_qtc_cpp_tool(cplusplus-mkvisitor PATH_AST_H=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus/AST.h\") - add_qtc_cpp_tool(cplusplus-update-frontend PATH_CPP_FRONTEND=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus\" PATH_DUMPERS_FILE=\"${CMAKE_CURRENT_SOURCE_DIR}/cplusplus-ast2png/dumpers.inc\") -endif() +add_qtc_cpp_tool(cplusplus-ast2png "") +add_qtc_cpp_tool(cplusplus-frontend "") +add_qtc_cpp_tool(cplusplus-mkvisitor PATH_AST_H=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus/AST.h\") +add_qtc_cpp_tool(cplusplus-update-frontend PATH_CPP_FRONTEND=\"${CMAKE_CURRENT_SOURCE_DIR}/../libs/3rdparty/cplusplus\" PATH_DUMPERS_FILE=\"${CMAKE_CURRENT_SOURCE_DIR}/cplusplus-ast2png/dumpers.inc\") if (APPLE) add_subdirectory(disclaim) diff --git a/src/tools/cplusplus-shared/CPlusPlusTool.qbs b/src/tools/cplusplus-shared/CPlusPlusTool.qbs index 55c4aff9409..63313e2462f 100644 --- a/src/tools/cplusplus-shared/CPlusPlusTool.qbs +++ b/src/tools/cplusplus-shared/CPlusPlusTool.qbs @@ -1,6 +1,7 @@ import qbs 1.0 QtcTool { + install: false Depends { name: "Qt"; submodules: ["core", "widgets"]; } Depends { name: "CPlusPlus" } Depends { name: "Utils" } diff --git a/src/tools/cplusplustools.qbs b/src/tools/cplusplustools.qbs index d67d5583309..ab3aa517072 100644 --- a/src/tools/cplusplustools.qbs +++ b/src/tools/cplusplustools.qbs @@ -3,7 +3,6 @@ import qbs.Environment Project { name: "CPlusPlus Tools" - condition: Environment.getEnv("BUILD_CPLUSPLUS_TOOLS") references: [ "3rdparty/cplusplus-keywordgen/cplusplus-keywordgen.qbs", "cplusplus-ast2png/cplusplus-ast2png.qbs", From db720d271da982470f444ec93beb7ca4d938f490 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Fri, 3 Feb 2023 13:18:59 +0100 Subject: [PATCH 0043/1447] MultiTextCursor: Optimize multitextcursor - Use map for merging intervals instead 2 times list iteration. - Time complexity O(nlogn) instead O(n^2) Change-Id: If65391999e1ff191752447935602fcc9847243fe Reviewed-by: David Schulz --- src/libs/utils/multitextcursor.cpp | 417 +++++++++++++++----------- src/libs/utils/multitextcursor.h | 28 +- src/plugins/texteditor/texteditor.cpp | 5 +- 3 files changed, 256 insertions(+), 194 deletions(-) diff --git a/src/libs/utils/multitextcursor.cpp b/src/libs/utils/multitextcursor.cpp index 2f598066eeb..934ca17ed37 100644 --- a/src/libs/utils/multitextcursor.cpp +++ b/src/libs/utils/multitextcursor.cpp @@ -16,187 +16,42 @@ namespace Utils { MultiTextCursor::MultiTextCursor() {} MultiTextCursor::MultiTextCursor(const QList &cursors) - : m_cursors(cursors) { - mergeCursors(); + setCursors(cursors); } -void MultiTextCursor::addCursor(const QTextCursor &cursor) +void MultiTextCursor::fillMapWithList() { - QTC_ASSERT(!cursor.isNull(), return); - m_cursors.append(cursor); - mergeCursors(); + m_cursorMap.clear(); + for (auto it = m_cursorList.begin(); it != m_cursorList.end(); ++it) + m_cursorMap[it->selectionStart()] = it; } -void MultiTextCursor::addCursors(const QList &cursors) +MultiTextCursor& MultiTextCursor::operator=(const MultiTextCursor &multiCursor) { - m_cursors.append(cursors); - mergeCursors(); + m_cursorList = multiCursor.m_cursorList; + fillMapWithList(); + return *this; } -void MultiTextCursor::setCursors(const QList &cursors) +MultiTextCursor::MultiTextCursor(const MultiTextCursor &multiCursor) { - m_cursors = cursors; - mergeCursors(); + *this = multiCursor; } -const QList MultiTextCursor::cursors() const +MultiTextCursor& MultiTextCursor::operator=(const MultiTextCursor &&multiCursor) { - return m_cursors; + m_cursorList = std::move(multiCursor.m_cursorList); + fillMapWithList(); + return *this; } -void MultiTextCursor::replaceMainCursor(const QTextCursor &cursor) +MultiTextCursor::MultiTextCursor(const MultiTextCursor &&multiCursor) { - QTC_ASSERT(!cursor.isNull(), return); - takeMainCursor(); - addCursor(cursor); + *this = std::move(multiCursor); } -QTextCursor MultiTextCursor::mainCursor() const -{ - if (m_cursors.isEmpty()) - return {}; - return m_cursors.last(); -} - -QTextCursor MultiTextCursor::takeMainCursor() -{ - if (m_cursors.isEmpty()) - return {}; - return m_cursors.takeLast(); -} - -void MultiTextCursor::beginEditBlock() -{ - QTC_ASSERT(!m_cursors.empty(), return); - m_cursors.last().beginEditBlock(); -} - -void MultiTextCursor::endEditBlock() -{ - QTC_ASSERT(!m_cursors.empty(), return); - m_cursors.last().endEditBlock(); -} - -bool MultiTextCursor::isNull() const -{ - return m_cursors.isEmpty(); -} - -bool MultiTextCursor::hasMultipleCursors() const -{ - return m_cursors.size() > 1; -} - -int MultiTextCursor::cursorCount() const -{ - return m_cursors.size(); -} - -void MultiTextCursor::movePosition(QTextCursor::MoveOperation operation, - QTextCursor::MoveMode mode, - int n) -{ - for (QTextCursor &cursor : m_cursors) - cursor.movePosition(operation, mode, n); - mergeCursors(); -} - -bool MultiTextCursor::hasSelection() const -{ - return Utils::anyOf(m_cursors, &QTextCursor::hasSelection); -} - -QString MultiTextCursor::selectedText() const -{ - QString text; - const QList cursors = Utils::sorted(m_cursors); - for (const QTextCursor &cursor : cursors) { - const QString &cursorText = cursor.selectedText(); - if (cursorText.isEmpty()) - continue; - if (!text.isEmpty()) { - if (text.endsWith(QChar::ParagraphSeparator)) - text.chop(1); - text.append('\n'); - } - text.append(cursorText); - } - return text; -} - -void MultiTextCursor::removeSelectedText() -{ - beginEditBlock(); - for (QTextCursor &c : m_cursors) - c.removeSelectedText(); - endEditBlock(); - mergeCursors(); -} - -static void insertAndSelect(QTextCursor &cursor, const QString &text, bool selectNewText) -{ - if (selectNewText) { - const int anchor = cursor.position(); - cursor.insertText(text); - const int pos = cursor.position(); - cursor.setPosition(anchor); - cursor.setPosition(pos, QTextCursor::KeepAnchor); - } else { - cursor.insertText(text); - } -} - -void MultiTextCursor::insertText(const QString &text, bool selectNewText) -{ - if (m_cursors.isEmpty()) - return; - m_cursors.last().beginEditBlock(); - if (hasMultipleCursors()) { - QStringList lines = text.split('\n'); - if (!lines.isEmpty() && lines.last().isEmpty()) - lines.pop_back(); - int index = 0; - if (lines.count() == m_cursors.count()) { - QList cursors = Utils::sorted(m_cursors); - for (QTextCursor &cursor : cursors) - insertAndSelect(cursor, lines.at(index++), selectNewText); - m_cursors.last().endEditBlock(); - return; - } - } - for (QTextCursor &cursor : m_cursors) - insertAndSelect(cursor, text, selectNewText); - m_cursors.last().endEditBlock(); -} - -bool equalCursors(const QTextCursor &lhs, const QTextCursor &rhs) -{ - return lhs == rhs && lhs.anchor() == rhs.anchor(); -} - -bool MultiTextCursor::operator==(const MultiTextCursor &other) const -{ - if (m_cursors.size() != other.m_cursors.size()) - return false; - if (m_cursors.isEmpty()) - return true; - QList thisCursors = m_cursors; - QList otherCursors = other.m_cursors; - if (!equalCursors(thisCursors.takeLast(), otherCursors.takeLast())) - return false; - for (const QTextCursor &oc : otherCursors) { - auto compare = [oc](const QTextCursor &c) { return equalCursors(oc, c); }; - if (!Utils::contains(thisCursors, compare)) - return false; - } - return true; -} - -bool MultiTextCursor::operator!=(const MultiTextCursor &other) const -{ - return !operator==(other); -} +MultiTextCursor::~MultiTextCursor() = default; static bool cursorsOverlap(const QTextCursor &c1, const QTextCursor &c2) { @@ -243,25 +98,221 @@ static void mergeCursors(QTextCursor &c1, const QTextCursor &c2) } } -void MultiTextCursor::mergeCursors() +void MultiTextCursor::addCursor(const QTextCursor &cursor) { - std::list cursors(m_cursors.begin(), m_cursors.end()); - cursors = Utils::filtered(cursors, [](const QTextCursor &c){ - return !c.isNull(); - }); - for (auto it = cursors.begin(); it != cursors.end(); ++it) { - QTextCursor &c1 = *it; - for (auto other = std::next(it); other != cursors.end();) { - const QTextCursor &c2 = *other; - if (cursorsOverlap(c1, c2)) { - Utils::mergeCursors(c1, c2); - other = cursors.erase(other); - continue; + QTC_ASSERT(!cursor.isNull(), return); + + QTextCursor c1 = cursor; + const int pos = c1.selectionStart(); + + auto found = m_cursorMap.lower_bound(pos); + if (found != m_cursorMap.begin()) + --found; + + for (; !m_cursorMap.empty() && found != m_cursorMap.end() + && found->second->selectionStart() <= cursor.selectionEnd();) { + const QTextCursor &c2 = *found->second; + if (cursorsOverlap(c1, c2)) { + Utils::mergeCursors(c1, c2); + m_cursorList.erase(found->second); + found = m_cursorMap.erase(found); + continue; + } + ++found; + } + + m_cursorMap[pos] = m_cursorList.insert(m_cursorList.end(), c1); +} + +void MultiTextCursor::addCursors(const QList &cursors) +{ + for (const QTextCursor &c : cursors) + addCursor(c); +} + +void MultiTextCursor::setCursors(const QList &cursors) +{ + m_cursorList.clear(); + m_cursorMap.clear(); + addCursors(cursors); +} + +const QList MultiTextCursor::cursors() const +{ + return QList(m_cursorList.begin(), m_cursorList.end()); +} + +void MultiTextCursor::replaceMainCursor(const QTextCursor &cursor) +{ + QTC_ASSERT(!cursor.isNull(), return); + takeMainCursor(); + addCursor(cursor); +} + +QTextCursor MultiTextCursor::mainCursor() const +{ + if (m_cursorList.empty()) + return {}; + return m_cursorList.back(); +} + +QTextCursor MultiTextCursor::takeMainCursor() +{ + if (m_cursorList.empty()) + return {}; + + QTextCursor cursor = m_cursorList.back(); + auto it = m_cursorList.end(); + --it; + m_cursorMap.erase(it->selectionStart()); + m_cursorList.erase(it); + + return cursor; +} + +void MultiTextCursor::beginEditBlock() +{ + QTC_ASSERT(!m_cursorList.empty(), return); + m_cursorList.back().beginEditBlock(); +} + +void MultiTextCursor::endEditBlock() +{ + QTC_ASSERT(!m_cursorList.empty(), return); + m_cursorList.back().endEditBlock(); +} + +bool MultiTextCursor::isNull() const +{ + return m_cursorList.empty(); +} + +bool MultiTextCursor::hasMultipleCursors() const +{ + return m_cursorList.size() > 1; +} + +int MultiTextCursor::cursorCount() const +{ + return m_cursorList.size(); +} + +void MultiTextCursor::movePosition(QTextCursor::MoveOperation operation, + QTextCursor::MoveMode mode, + int n) +{ + for (auto &cursor : m_cursorList) + cursor.movePosition(operation, mode, n); + + mergeCursors(); +} + +bool MultiTextCursor::hasSelection() const +{ + return Utils::anyOf(m_cursorList, &QTextCursor::hasSelection); +} + +QString MultiTextCursor::selectedText() const +{ + QString text; + for (const auto &element : std::as_const(m_cursorMap)) { + const QTextCursor &cursor = *element.second; + const QString &cursorText = cursor.selectedText(); + if (cursorText.isEmpty()) + continue; + if (!text.isEmpty()) { + if (text.endsWith(QChar::ParagraphSeparator)) + text.chop(1); + text.append('\n'); + } + text.append(cursorText); + } + return text; +} + +void MultiTextCursor::removeSelectedText() +{ + beginEditBlock(); + for (auto cursor = m_cursorList.begin(); cursor != m_cursorList.end(); ++cursor) + cursor->removeSelectedText(); + endEditBlock(); + mergeCursors(); +} + +static void insertAndSelect(QTextCursor &cursor, const QString &text, bool selectNewText) +{ + if (selectNewText) { + const int anchor = cursor.position(); + cursor.insertText(text); + const int pos = cursor.position(); + cursor.setPosition(anchor); + cursor.setPosition(pos, QTextCursor::KeepAnchor); + } else { + cursor.insertText(text); + } +} + +void MultiTextCursor::insertText(const QString &text, bool selectNewText) +{ + if (m_cursorList.empty()) + return; + + m_cursorList.back().beginEditBlock(); + if (hasMultipleCursors()) { + QStringList lines = text.split('\n'); + if (!lines.isEmpty() && lines.last().isEmpty()) + lines.pop_back(); + int index = 0; + if (static_cast(lines.count()) == m_cursorList.size()) { + for (const auto &element : std::as_const(m_cursorMap)) { + QTextCursor &cursor = *element.second; + insertAndSelect(cursor, lines.at(index++), selectNewText); } - ++other; + m_cursorList.back().endEditBlock(); + return; } } - m_cursors = QList(cursors.begin(), cursors.end()); + for (auto cursor = m_cursorList.begin(); cursor != m_cursorList.end(); ++cursor) + insertAndSelect(*cursor, text, selectNewText); + m_cursorList.back().endEditBlock(); +} + +bool equalCursors(const QTextCursor &lhs, const QTextCursor &rhs) +{ + return lhs == rhs && lhs.anchor() == rhs.anchor(); +} + +bool MultiTextCursor::operator==(const MultiTextCursor &other) const +{ + if (m_cursorList.size() != other.m_cursorList.size()) + return false; + if (m_cursorList.empty()) + return true; + + if (!equalCursors(m_cursorList.back(), other.m_cursorList.back())) + return false; + + auto it = m_cursorMap.begin(); + auto otherIt = other.m_cursorMap.begin(); + for (;it != m_cursorMap.end() && otherIt != other.m_cursorMap.end(); ++it, ++otherIt) { + const QTextCursor &cursor = *it->second; + const QTextCursor &otherCursor = *otherIt->second; + if (it->first != otherIt->first || cursor != otherCursor + || cursor.anchor() != otherCursor.anchor()) + return false; + } + return true; +} + +bool MultiTextCursor::operator!=(const MultiTextCursor &other) const +{ + return !operator==(other); +} + +void MultiTextCursor::mergeCursors() +{ + QList cursors(m_cursorList.begin(), m_cursorList.end()); + setCursors(cursors); } // could go into QTextCursor... @@ -321,7 +372,7 @@ bool MultiTextCursor::handleMoveKeyEvent(QKeyEvent *e, return false; } - const QList cursors = m_cursors; + const std::list cursors = m_cursorList; for (QTextCursor cursor : cursors) { if (camelCaseNavigationEnabled && op == QTextCursor::WordRight) CamelCaseCursor::right(&cursor, edit, QTextCursor::MoveAnchor); @@ -329,14 +380,14 @@ bool MultiTextCursor::handleMoveKeyEvent(QKeyEvent *e, CamelCaseCursor::left(&cursor, edit, QTextCursor::MoveAnchor); else cursor.movePosition(op, QTextCursor::MoveAnchor); - m_cursors << cursor; - } - mergeCursors(); + addCursor(cursor); + } return true; } - for (QTextCursor &cursor : m_cursors) { + for (auto it = m_cursorList.begin(); it != m_cursorList.end(); ++it) { + QTextCursor &cursor = *it; QTextCursor::MoveMode mode = QTextCursor::MoveAnchor; QTextCursor::MoveOperation op = QTextCursor::NoMove; diff --git a/src/libs/utils/multitextcursor.h b/src/libs/utils/multitextcursor.h index 390082e63ad..edb4f5f1fd6 100644 --- a/src/libs/utils/multitextcursor.h +++ b/src/libs/utils/multitextcursor.h @@ -21,6 +21,13 @@ public: MultiTextCursor(); explicit MultiTextCursor(const QList &cursors); + MultiTextCursor(const MultiTextCursor &multiCursor); + MultiTextCursor &operator=(const MultiTextCursor &multiCursor); + MultiTextCursor(const MultiTextCursor &&multiCursor); + MultiTextCursor &operator=(const MultiTextCursor &&multiCursor); + + ~MultiTextCursor(); + /// replace all cursors with \param cursors and the last one will be the new main cursors void setCursors(const QList &cursors); const QList cursors() const; @@ -69,20 +76,23 @@ public: bool operator==(const MultiTextCursor &other) const; bool operator!=(const MultiTextCursor &other) const; - using iterator = QList::iterator; - using const_iterator = QList::const_iterator; + using iterator = std::list::iterator; + using const_iterator = std::list::const_iterator; - iterator begin() { return m_cursors.begin(); } - iterator end() { return m_cursors.end(); } - const_iterator begin() const { return m_cursors.begin(); } - const_iterator end() const { return m_cursors.end(); } - const_iterator constBegin() const { return m_cursors.constBegin(); } - const_iterator constEnd() const { return m_cursors.constEnd(); } + iterator begin() { return m_cursorList.begin(); } + iterator end() { return m_cursorList.end(); } + const_iterator begin() const { return m_cursorList.begin(); } + const_iterator end() const { return m_cursorList.end(); } + const_iterator constBegin() const { return m_cursorList.cbegin(); } + const_iterator constEnd() const { return m_cursorList.cend(); } static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey); private: - QList m_cursors; + std::list m_cursorList; + std::map::iterator> m_cursorMap; + + void fillMapWithList(); }; } // namespace Utils diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 71bb7e639ad..fcf11ecb090 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -6736,10 +6736,11 @@ MultiTextCursor TextEditorWidget::multiTextCursor() const void TextEditorWidget::setMultiTextCursor(const Utils::MultiTextCursor &cursor) { + if (cursor == d->m_cursors) + return; + const MultiTextCursor oldCursor = d->m_cursors; const_cast(d->m_cursors) = cursor; - if (oldCursor == d->m_cursors) - return; doSetTextCursor(d->m_cursors.mainCursor(), /*keepMultiSelection*/ true); QRect updateRect = d->cursorUpdateRect(oldCursor); if (d->m_highlightCurrentLine) From 06dda40ccc1a44675706aa93dbf83ea88a8763a6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 6 Feb 2023 20:27:59 +0100 Subject: [PATCH 0044/1447] TaskTree: Add synchronous invocation (Tasking::Sync) Make it possible to mix synchronous and asynchronous calls inside task tree. Basically, it's a shortcut for: bool syncMethod(); Group { OnGroupSetup([syncMethod] { return syncMethod() ? TaskAction::StopWithDone : TaskAction::StopWithError; }) } Please note: similarly to Group, Sync isn't counted as a task inside taskCount() and doesn't emit TaskTree::progressValueChanged() when finished. It's being considered as a simple handler that doesn't last long and shouldn't block the GUI thread. Otherwise, use AsyncTask instead. Change-Id: If71c5da2f9b202a69c41a555cc93d314476952f4 Reviewed-by: Eike Ziller --- src/libs/utils/tasktree.h | 10 +++ tests/auto/utils/tasktree/tst_tasktree.cpp | 86 +++++++++++++++++++++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 54a0cfda534..b90e10c7c15 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -244,6 +244,16 @@ public: OnGroupError(const GroupEndHandler &handler) : TaskItem({{}, {}, handler}) {} }; +// Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() +class QTCREATOR_UTILS_EXPORT Sync : public Group +{ +public: + using SynchronousMethod = std::function; + Sync(const SynchronousMethod &sync) + : Group({OnGroupSetup([sync] { return sync() ? TaskAction::StopWithDone + : TaskAction::StopWithError; })}) {} +}; + QTCREATOR_UTILS_EXPORT extern ParallelLimit sequential; QTCREATOR_UTILS_EXPORT extern ParallelLimit parallel; QTCREATOR_UTILS_EXPORT extern Workflow stopOnError; diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 3e5c67050f5..ca43a74ddd6 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -19,7 +19,8 @@ enum class Handler { Error, GroupSetup, GroupDone, - GroupError + GroupError, + Sync }; using Log = QList>; @@ -172,6 +173,9 @@ void tst_TaskTree::processTree_data() const auto groupError = [storage](int groupId) { return [=] { storage->m_log.append({groupId, Handler::GroupError}); }; }; + const auto setupSync = [storage](int syncId, bool success) { + return [=] { storage->m_log.append({syncId, Handler::Sync}); return success; }; + }; const auto constructSimpleSequence = [=](const Workflow &policy) { return Group { @@ -988,6 +992,86 @@ void tst_TaskTree::processTree_data() QTest::newRow("DeeplyNestedParallelError") << TestData{storage, root, log, 5, OnStart::Running, OnDone::Failure}; } + + { + const Group root { + Storage(storage), + Sync(setupSync(1, true)), + Sync(setupSync(2, true)), + Sync(setupSync(3, true)), + Sync(setupSync(4, true)), + Sync(setupSync(5, true)) + }; + const Log log { + {1, Handler::Sync}, + {2, Handler::Sync}, + {3, Handler::Sync}, + {4, Handler::Sync}, + {5, Handler::Sync} + }; + QTest::newRow("SyncSequential") + << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; + } + + { + const Group root { + Storage(storage), + parallel, + Sync(setupSync(1, true)), + Sync(setupSync(2, true)), + Sync(setupSync(3, true)), + Sync(setupSync(4, true)), + Sync(setupSync(5, true)) + }; + const Log log { + {1, Handler::Sync}, + {2, Handler::Sync}, + {3, Handler::Sync}, + {4, Handler::Sync}, + {5, Handler::Sync} + }; + QTest::newRow("SyncParallel") + << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; + } + + { + const Group root { + Storage(storage), + parallel, + Sync(setupSync(1, true)), + Sync(setupSync(2, true)), + Sync(setupSync(3, false)), + Sync(setupSync(4, true)), + Sync(setupSync(5, true)) + }; + const Log log { + {1, Handler::Sync}, + {2, Handler::Sync}, + {3, Handler::Sync} + }; + QTest::newRow("SyncError") + << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Failure}; + } + + const Group root { + Storage(storage), + Sync(setupSync(1, true)), + Process(setupProcess(2)), + Sync(setupSync(3, true)), + Process(setupProcess(4)), + Sync(setupSync(5, true)), + OnGroupDone(groupDone(0)) + }; + const Log log { + {1, Handler::Sync}, + {2, Handler::Setup}, + {3, Handler::Sync}, + {4, Handler::Setup}, + {5, Handler::Sync}, + {0, Handler::GroupDone} + }; + QTest::newRow("SyncAndAsync") + << TestData{storage, root, log, 2, OnStart::Running, OnDone::Success}; } void tst_TaskTree::processTree() From 6383146b0e8cfb1ba4230f4f730543ee4ad78b4c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 13 Feb 2023 09:23:23 +0100 Subject: [PATCH 0045/1447] AutoTest: Avoid crash Do not queue signals of parse results. In case of a shutdown these signals could be received too late and the item cache of the treemodel might have been destroyed already. Fixes: QTCREATORBUG-28797 Change-Id: I6daa2b2464dbfb123af3b1e708794b2dbf897bff Reviewed-by: Jarek Kobus --- src/plugins/autotest/testtreemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index 8842734f0c5..f21e9349c32 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -38,7 +38,7 @@ TestTreeModel::TestTreeModel(TestCodeParser *parser) : connect(m_parser, &TestCodeParser::aboutToPerformFullParse, this, &TestTreeModel::removeAllTestItems, Qt::QueuedConnection); connect(m_parser, &TestCodeParser::testParseResultReady, - this, &TestTreeModel::onParseResultReady, Qt::QueuedConnection); + this, &TestTreeModel::onParseResultReady); connect(m_parser, &TestCodeParser::parsingFinished, this, &TestTreeModel::sweep, Qt::QueuedConnection); connect(m_parser, &TestCodeParser::parsingFailed, From d20f543619efbac8a1c248cf97a13bf3875cd4dd Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sat, 11 Feb 2023 20:58:18 +0200 Subject: [PATCH 0046/1447] Git: Reduce sync processes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I5d83636d4a018464ba6f248aa818fb8f840df9fc Reviewed-by: André Hartmann Reviewed-by: Jarek Kobus --- src/plugins/git/branchmodel.cpp | 108 +++++++++++++++++--------- src/plugins/git/branchmodel.h | 3 +- src/plugins/git/branchview.cpp | 70 +++++++++++++---- src/plugins/git/branchview.h | 3 +- src/plugins/git/gitclient.cpp | 40 +++++----- src/plugins/git/gitclient.h | 6 +- src/plugins/vcsbase/vcsbaseclient.cpp | 11 +++ src/plugins/vcsbase/vcsbaseclient.h | 8 ++ 8 files changed, 172 insertions(+), 77 deletions(-) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 3c4971fa734..7b57df0739d 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -229,6 +229,7 @@ public: QString currentSha; QDateTime currentDateTime; QStringList obsoleteLocalBranches; + std::unique_ptr refreshTask; bool oldBranchesIncluded = false; struct OldEntry @@ -399,50 +400,83 @@ void BranchModel::clear() d->obsoleteLocalBranches.clear(); } -bool BranchModel::refresh(const FilePath &workingDirectory, QString *errorMessage) +void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) { + if (d->refreshTask) { + endResetModel(); // for the running task tree. + d->refreshTask.reset(); // old running tree is reset, no handlers are being called + } beginResetModel(); clear(); if (workingDirectory.isEmpty()) { endResetModel(); - return true; + return; } - d->currentSha = d->client->synchronousTopRevision(workingDirectory, &d->currentDateTime); - QStringList args = {"--format=%(objectname)\t%(refname)\t%(upstream:short)\t" - "%(*objectname)\t%(committerdate:raw)\t%(*committerdate:raw)", - "refs/heads/**", - "refs/remotes/**"}; - if (d->client->settings().showTags.value()) - args << "refs/tags/**"; - QString output; - if (!d->client->synchronousForEachRefCmd(workingDirectory, args, &output, errorMessage)) { + using namespace Tasking; + const Process topRevisionProc = + d->client->topRevision(workingDirectory, + [=](const QString &ref, const QDateTime &dateTime) { + d->currentSha = ref; + d->currentDateTime = dateTime; + }); + + const auto setupForEachRef = [=](QtcProcess &process) { + d->workingDirectory = workingDirectory; + QStringList args = {"for-each-ref", + "--format=%(objectname)\t%(refname)\t%(upstream:short)\t" + "%(*objectname)\t%(committerdate:raw)\t%(*committerdate:raw)", + "refs/heads/**", + "refs/remotes/**"}; + if (d->client->settings().showTags.value()) + args << "refs/tags/**"; + d->client->setupCommand(process, workingDirectory, args); + }; + + const auto forEachRefDone = [=](const QtcProcess &process) { + const QString output = process.stdOut(); + const QStringList lines = output.split('\n'); + for (const QString &l : lines) + d->parseOutputLine(l); + d->flushOldEntries(); + + d->updateAllUpstreamStatus(d->rootNode->children.at(LocalBranches)); + if (d->currentBranch) { + if (d->currentBranch->isLocal()) + d->currentBranch = nullptr; + setCurrentBranch(); + } + if (!d->currentBranch) { + BranchNode *local = d->rootNode->children.at(LocalBranches); + d->currentBranch = d->headNode = new BranchNode( + Tr::tr("Detached HEAD"), "HEAD", {}, d->currentDateTime); + local->prepend(d->headNode); + } + }; + + const auto forEachRefError = [=](const QtcProcess &process) { + if (showError == ShowError::No) + return; + const QString message = Tr::tr("Cannot run \"%1\" in \"%2\": %3") + .arg("git for-each-ref") + .arg(workingDirectory.toUserOutput()) + .arg(process.cleanedStdErr()); + VcsBase::VcsOutputWindow::appendError(message); + }; + + const auto finalize = [this] { endResetModel(); - return false; - } + d->refreshTask.release()->deleteLater(); + }; - d->workingDirectory = workingDirectory; - const QStringList lines = output.split('\n'); - for (const QString &l : lines) - d->parseOutputLine(l); - d->flushOldEntries(); - - d->updateAllUpstreamStatus(d->rootNode->children.at(LocalBranches)); - if (d->currentBranch) { - if (d->currentBranch->isLocal()) - d->currentBranch = nullptr; - setCurrentBranch(); - } - if (!d->currentBranch) { - BranchNode *local = d->rootNode->children.at(LocalBranches); - d->currentBranch = d->headNode = new BranchNode(Tr::tr("Detached HEAD"), "HEAD", QString(), - d->currentDateTime); - local->prepend(d->headNode); - } - - endResetModel(); - - return true; + const Group root { + topRevisionProc, + Process(setupForEachRef, forEachRefDone, forEachRefError), + OnGroupDone(finalize), + OnGroupError(finalize) + }; + d->refreshTask.reset(new TaskTree(root)); + d->refreshTask->start(); } void BranchModel::setCurrentBranch() @@ -469,7 +503,7 @@ void BranchModel::renameBranch(const QString &oldName, const QString &newName) &output, &errorMessage)) VcsOutputWindow::appendError(errorMessage); else - refresh(d->workingDirectory, &errorMessage); + refresh(d->workingDirectory); } void BranchModel::renameTag(const QString &oldName, const QString &newName) @@ -482,7 +516,7 @@ void BranchModel::renameTag(const QString &oldName, const QString &newName) &output, &errorMessage)) { VcsOutputWindow::appendError(errorMessage); } else { - refresh(d->workingDirectory, &errorMessage); + refresh(d->workingDirectory); } } diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h index 580af612985..de126e9a5eb 100644 --- a/src/plugins/git/branchmodel.h +++ b/src/plugins/git/branchmodel.h @@ -34,7 +34,8 @@ public: Qt::ItemFlags flags(const QModelIndex &index) const override; void clear(); - bool refresh(const Utils::FilePath &workingDirectory, QString *errorMessage); + enum class ShowError { No, Yes }; + void refresh(const Utils::FilePath &workingDirectory, ShowError showError = ShowError::No); void renameBranch(const QString &oldName, const QString &newName); void renameTag(const QString &oldName, const QString &newName); diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index 528ec288f97..df9c255c587 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -160,9 +160,7 @@ void BranchView::refresh(const FilePath &repository, bool force) if (!isVisible()) return; - QString errorMessage; - if (!m_model->refresh(m_repository, &errorMessage)) - VcsBase::VcsOutputWindow::appendError(errorMessage); + m_model->refresh(m_repository, BranchModel::ShowError::Yes); } void BranchView::refreshCurrentBranch() @@ -225,6 +223,7 @@ void BranchView::slotCustomContextMenu(const QPoint &point) const bool isTag = m_model->isTag(index); const bool hasActions = m_model->isLeaf(index); const bool currentLocal = m_model->isLocal(currentBranch); + std::unique_ptr taskTree; QMenu contextMenu; contextMenu.addAction(Tr::tr("&Add..."), this, &BranchView::add); @@ -268,19 +267,19 @@ void BranchView::slotCustomContextMenu(const QPoint &point) resetMenu->addAction(Tr::tr("&Mixed"), this, [this] { reset("mixed"); }); resetMenu->addAction(Tr::tr("&Soft"), this, [this] { reset("soft"); }); contextMenu.addMenu(resetMenu); - QString mergeTitle; - if (isFastForwardMerge()) { - contextMenu.addAction(Tr::tr("&Merge \"%1\" into \"%2\" (Fast-Forward)") - .arg(indexName, currentName), - this, [this] { merge(true); }); - mergeTitle = Tr::tr("Merge \"%1\" into \"%2\" (No &Fast-Forward)") - .arg(indexName, currentName); - } else { - mergeTitle = Tr::tr("&Merge \"%1\" into \"%2\"") - .arg(indexName, currentName); - } + QAction *mergeAction = contextMenu.addAction(Tr::tr("&Merge \"%1\" into \"%2\"") + .arg(indexName, currentName), + this, + [this] { merge(false); }); + taskTree.reset(onFastForwardMerge([&] { + auto ffMerge = new QAction( + Tr::tr("&Merge \"%1\" into \"%2\" (Fast-Forward)").arg(indexName, currentName)); + connect(ffMerge, &QAction::triggered, this, [this] { merge(true); }); + contextMenu.insertAction(mergeAction, ffMerge); + mergeAction->setText(Tr::tr("Merge \"%1\" into \"%2\" (No &Fast-Forward)") + .arg(indexName, currentName)); + })); - contextMenu.addAction(mergeTitle, this, [this] { merge(false); }); contextMenu.addAction(Tr::tr("&Rebase \"%1\" on \"%2\"") .arg(currentName, indexName), this, &BranchView::rebase); @@ -523,13 +522,50 @@ bool BranchView::reset(const QByteArray &resetType) return false; } -bool BranchView::isFastForwardMerge() +TaskTree *BranchView::onFastForwardMerge(const std::function &callback) { + using namespace Tasking; + const QModelIndex selected = selectedIndex(); QTC_CHECK(selected != m_model->currentBranch()); const QString branch = m_model->fullName(selected, true); - return GitClient::instance()->isFastForwardMerge(m_repository, branch); + + struct FastForwardStorage + { + QString mergeBase; + QString topRevision; + }; + + const TreeStorage storage; + + GitClient *client = GitClient::instance(); + const auto setupMergeBase = [=](QtcProcess &process) { + client->setupCommand(process, m_repository, {"merge-base", "HEAD", branch}); + }; + const auto onMergeBaseDone = [storage](const QtcProcess &process) { + storage->mergeBase = process.cleanedStdOut().trimmed(); + }; + + const Process topRevisionProc = client->topRevision( + m_repository, + [storage](const QString &revision, const QDateTime &) { + storage->topRevision = revision; + }); + + const Group root { + Storage(storage), + parallel, + Process(setupMergeBase, onMergeBaseDone), + topRevisionProc, + OnGroupDone([storage, callback] { + if (storage->mergeBase == storage->topRevision) + callback(); + }) + }; + auto taskTree = new TaskTree(root); + taskTree->start(); + return taskTree; } bool BranchView::merge(bool allowFastForward) diff --git a/src/plugins/git/branchview.h b/src/plugins/git/branchview.h index 9a1a3c1e455..c1ac77c82be 100644 --- a/src/plugins/git/branchview.h +++ b/src/plugins/git/branchview.h @@ -20,6 +20,7 @@ QT_END_NAMESPACE; namespace Utils { class ElidingLabel; class NavigationTreeView; +class TaskTree; } // Utils namespace Git::Internal { @@ -54,7 +55,7 @@ private: bool remove(); bool rename(); bool reset(const QByteArray &resetType); - bool isFastForwardMerge(); + Utils::TaskTree *onFastForwardMerge(const std::function &callback); bool merge(bool allowFastForward); void rebase(); bool cherryPick(); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 395ce703eca..ab24e0cb1b4 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -1730,19 +1730,28 @@ bool GitClient::synchronousRevParseCmd(const FilePath &workingDirectory, const Q } // Retrieve head revision -QString GitClient::synchronousTopRevision(const FilePath &workingDirectory, QDateTime *dateTime) +Utils::Tasking::Process GitClient::topRevision( + const FilePath &workingDirectory, + const std::function &callback) { - const QStringList arguments = {"show", "-s", "--pretty=format:%H:%ct", HEAD}; - const CommandResult result = vcsSynchronousExec(workingDirectory, arguments, RunFlags::NoOutput); - if (result.result() != ProcessResult::FinishedWithSuccess) - return QString(); - const QStringList output = result.cleanedStdOut().trimmed().split(':'); - if (dateTime && output.size() > 1) { - bool ok = false; - const qint64 timeT = output.at(1).toLongLong(&ok); - *dateTime = ok ? QDateTime::fromSecsSinceEpoch(timeT) : QDateTime(); - } - return output.first(); + using namespace Tasking; + + const auto setupProcess = [=](QtcProcess &process) { + setupCommand(process, workingDirectory, {"show", "-s", "--pretty=format:%H:%ct", HEAD}); + }; + const auto onProcessDone = [=](const QtcProcess &process) { + const QStringList output = process.cleanedStdOut().trimmed().split(':'); + QDateTime dateTime; + if (output.size() > 1) { + bool ok = false; + const qint64 timeT = output.at(1).toLongLong(&ok); + if (ok) + dateTime = QDateTime::fromSecsSinceEpoch(timeT); + } + callback(output.first(), dateTime); + }; + + return Process(setupProcess, onProcessDone); } bool GitClient::isRemoteCommit(const FilePath &workingDirectory, const QString &commit) @@ -1752,13 +1761,6 @@ bool GitClient::isRemoteCommit(const FilePath &workingDirectory, const QString & return !result.rawStdOut().isEmpty(); } -bool GitClient::isFastForwardMerge(const FilePath &workingDirectory, const QString &branch) -{ - const CommandResult result = vcsSynchronousExec(workingDirectory, - {"merge-base", HEAD, branch}, RunFlags::NoOutput); - return result.cleanedStdOut().trimmed() == synchronousTopRevision(workingDirectory); -} - // Format an entry in a one-liner for selection list using git log. QString GitClient::synchronousShortDescription(const FilePath &workingDirectory, const QString &revision, const QString &format) const diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 2dfd6ddaaa1..5709a53b862 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -241,9 +242,10 @@ public: QString synchronousTopic(const Utils::FilePath &workingDirectory) const; bool synchronousRevParseCmd(const Utils::FilePath &workingDirectory, const QString &ref, QString *output, QString *errorMessage = nullptr) const; - QString synchronousTopRevision(const Utils::FilePath &workingDirectory, QDateTime *dateTime = nullptr); + Utils::Tasking::Process topRevision( + const Utils::FilePath &workingDirectory, + const std::function &callback); bool isRemoteCommit(const Utils::FilePath &workingDirectory, const QString &commit); - bool isFastForwardMerge(const Utils::FilePath &workingDirectory, const QString &branch); void fetch(const Utils::FilePath &workingDirectory, const QString &remote); void pull(const Utils::FilePath &workingDirectory, bool rebase); diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index c51b1292f9a..a73758b15ea 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,16 @@ VcsCommand *VcsBaseClientImpl::createCommand(const FilePath &workingDirectory, return cmd; } +void VcsBaseClientImpl::setupCommand(Utils::QtcProcess &process, + const FilePath &workingDirectory, + const QStringList &args) const +{ + process.setEnvironment(processEnvironment()); + process.setWorkingDirectory(workingDirectory); + process.setCommand({vcsBinary(), args}); + process.setUseCtrlCStub(true); +} + void VcsBaseClientImpl::enqueueJob(VcsCommand *cmd, const QStringList &args, const ExitCodeInterpreter &interpreter) const { diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index 6703495c37f..4e5bf91d5ff 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -23,6 +23,10 @@ class QTextCodec; class QToolBar; QT_END_NAMESPACE +namespace Utils { +class QtcProcess; +} + namespace VcsBase { class CommandResult; @@ -56,6 +60,10 @@ public: VcsCommand *createCommand(const Utils::FilePath &workingDirectory, VcsBaseEditorWidget *editor = nullptr) const; + void setupCommand(Utils::QtcProcess &process, + const Utils::FilePath &workingDirectory, + const QStringList &args) const; + void enqueueJob(VcsCommand *cmd, const QStringList &args, const Utils::ExitCodeInterpreter &interpreter = {}) const; From fc73324c506b1950ee413d9ab3b0844c5a4b1549 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 9 Feb 2023 13:05:49 +0100 Subject: [PATCH 0047/1447] Utils: Remove old Qt 5.4 workaround see QTBUG-40449. Change-Id: I0c347e81f8791f042c28200844d9102d84151b3c Reviewed-by: hjk Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/utils/dropsupport.cpp | 4 ---- src/libs/utils/fileutils_mac.h | 1 - src/libs/utils/fileutils_mac.mm | 11 ----------- 3 files changed, 16 deletions(-) diff --git a/src/libs/utils/dropsupport.cpp b/src/libs/utils/dropsupport.cpp index 9d914e0f084..6def3fd1aff 100644 --- a/src/libs/utils/dropsupport.cpp +++ b/src/libs/utils/dropsupport.cpp @@ -40,10 +40,6 @@ static bool isFileDropMime(const QMimeData *d, QList *fil const QList::const_iterator cend = urls.constEnd(); for (QList::const_iterator it = urls.constBegin(); it != cend; ++it) { QUrl url = *it; -#ifdef Q_OS_OSX - // for file drops from Finder, working around QTBUG-40449 - url = Internal::filePathUrl(url); -#endif const QString fileName = url.toLocalFile(); if (!fileName.isEmpty()) { hasFiles = true; diff --git a/src/libs/utils/fileutils_mac.h b/src/libs/utils/fileutils_mac.h index 4c9e7557e10..c7ddd0d2cdc 100644 --- a/src/libs/utils/fileutils_mac.h +++ b/src/libs/utils/fileutils_mac.h @@ -8,7 +8,6 @@ namespace Utils { namespace Internal { -QUrl filePathUrl(const QUrl &url); QString normalizePathName(const QString &filePath); } // Internal diff --git a/src/libs/utils/fileutils_mac.mm b/src/libs/utils/fileutils_mac.mm index e7ff062f66b..c3d494991d4 100644 --- a/src/libs/utils/fileutils_mac.mm +++ b/src/libs/utils/fileutils_mac.mm @@ -14,17 +14,6 @@ namespace Utils { namespace Internal { -QUrl filePathUrl(const QUrl &url) -{ - QUrl ret = url; - @autoreleasepool { - NSURL *nsurl = url.toNSURL(); - if ([nsurl isFileReferenceURL]) - ret = QUrl::fromNSURL([nsurl filePathURL]); - } - return ret; -} - QString normalizePathName(const QString &filePath) { QString result; From 8257369b73ec4911d53034165d3f10fb2c062c48 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 13 Jan 2023 15:54:51 +0100 Subject: [PATCH 0048/1447] ClangCodeModel: Remove unneeded code This was liblclang-specific. Change-Id: I3fe8a8d2d49b1c7b92a54a90864e4ead7152e4ae Reviewed-by: Cristian Adam --- src/plugins/clangcodemodel/CMakeLists.txt | 1 - src/plugins/clangcodemodel/clangcodemodel.qbs | 2 - .../clangcodemodel/clangcodemodelplugin.cpp | 20 - .../clangcodemodel/clangcodemodelplugin.h | 2 - .../test/clangbatchfileprocessor.cpp | 729 ------------------ .../test/clangbatchfileprocessor.h | 16 - .../clangcodemodel/test/clangdtests.cpp | 22 +- 7 files changed, 21 insertions(+), 771 deletions(-) delete mode 100644 src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp delete mode 100644 src/plugins/clangcodemodel/test/clangbatchfileprocessor.h diff --git a/src/plugins/clangcodemodel/CMakeLists.txt b/src/plugins/clangcodemodel/CMakeLists.txt index 50007413e15..dbfba36ee06 100644 --- a/src/plugins/clangcodemodel/CMakeLists.txt +++ b/src/plugins/clangcodemodel/CMakeLists.txt @@ -50,7 +50,6 @@ extend_qtc_plugin(ClangCodeModel CONDITION WITH_TESTS SOURCES test/activationsequenceprocessortest.cpp test/activationsequenceprocessortest.h - test/clangbatchfileprocessor.cpp test/clangbatchfileprocessor.h test/clangdtests.cpp test/clangdtests.h test/clangfixittest.cpp test/clangfixittest.h test/data/clangtestdata.qrc diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index 45a6abc347d..b4a1bc93a53 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -101,8 +101,6 @@ QtcPlugin { files: [ "activationsequenceprocessortest.cpp", "activationsequenceprocessortest.h", - "clangbatchfileprocessor.cpp", - "clangbatchfileprocessor.h", "clangdtests.cpp", "clangdtests.h", "clangfixittest.cpp", diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index e974152584e..0c5379ccecf 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -10,7 +10,6 @@ #ifdef WITH_TESTS # include "test/activationsequenceprocessortest.h" -# include "test/clangbatchfileprocessor.h" # include "test/clangdtests.h" # include "test/clangfixittest.h" #endif @@ -80,15 +79,8 @@ void ClangCodeModelPlugin::initialize() { TaskHub::addCategory(Constants::TASK_CATEGORY_DIAGNOSTICS, Tr::tr("Clang Code Model")); - - connect(ProjectExplorerPlugin::instance(), - &ProjectExplorerPlugin::finishedInitialization, - this, - &ClangCodeModelPlugin::maybeHandleBatchFileAndExit); - CppEditor::CppModelManager::instance()->activateClangCodeModel( std::make_unique()); - createCompilationDBAction(); } @@ -166,18 +158,6 @@ void ClangCodeModelPlugin::createCompilationDBAction() }); } -// For e.g. creation of profile-guided optimization builds. -void ClangCodeModelPlugin::maybeHandleBatchFileAndExit() const -{ -#ifdef WITH_TESTS - const QString batchFilePath = qtcEnvironmentVariable("QTC_CLANG_BATCH"); - if (!batchFilePath.isEmpty() && QTC_GUARD(QFileInfo::exists(batchFilePath))) { - const bool runSucceeded = runClangBatchFile(batchFilePath); - QCoreApplication::exit(!runSucceeded); - } -#endif -} - #ifdef WITH_TESTS QVector ClangCodeModelPlugin::createTestObjects() const { diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.h b/src/plugins/clangcodemodel/clangcodemodelplugin.h index 6f4d9af6533..b03f49c77a7 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.h +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.h @@ -24,8 +24,6 @@ public: void initialize() override; private: - void maybeHandleBatchFileAndExit() const; - void generateCompilationDB(); void createCompilationDBAction(); diff --git a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp b/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp deleted file mode 100644 index 1f0219df997..00000000000 --- a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp +++ /dev/null @@ -1,729 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "clangbatchfileprocessor.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace ProjectExplorer; - -namespace ClangCodeModel { -namespace Internal { - -static Q_LOGGING_CATEGORY(debug, "qtc.clangcodemodel.batch", QtWarningMsg); - -static int timeOutFromEnvironmentVariable() -{ - bool isConversionOk = false; - const int intervalAsInt = Utils::qtcEnvironmentVariableIntValue("QTC_CLANG_BATCH_TIMEOUT", - &isConversionOk); - if (!isConversionOk) { - qCDebug(debug, "Environment variable QTC_CLANG_BATCH_TIMEOUT is not set, assuming 30000."); - return 30000; - } - - return intervalAsInt; -} - -int timeOutInMs() -{ - static int timeOut = timeOutFromEnvironmentVariable(); - return timeOut; -} - -namespace { - -class BatchFileLineTokenizer -{ -public: - BatchFileLineTokenizer(const QString &line); - - QString nextToken(); - -private: - const QChar *advanceToTokenBegin(); - const QChar *advanceToTokenEnd(); - - bool atEnd() const; - bool atWhiteSpace() const; - bool atQuotationMark() const; - -private: - bool m_isWithinQuotation = false; - QString m_line; - const QChar *m_currentChar; -}; - -BatchFileLineTokenizer::BatchFileLineTokenizer(const QString &line) - : m_line(line) - , m_currentChar(m_line.unicode()) -{ -} - -QString BatchFileLineTokenizer::nextToken() -{ - if (const QChar *tokenBegin = advanceToTokenBegin()) { - if (const QChar *tokenEnd = advanceToTokenEnd()) { - const int length = tokenEnd - tokenBegin; - return QString(tokenBegin, length); - } - } - - return QString(); -} - -const QChar *BatchFileLineTokenizer::advanceToTokenBegin() -{ - m_isWithinQuotation = false; - - forever { - if (atEnd()) - return nullptr; - - if (atQuotationMark()) { - m_isWithinQuotation = true; - ++m_currentChar; - return m_currentChar; - } - - if (!atWhiteSpace()) - return m_currentChar; - - ++m_currentChar; - } -} - -const QChar *BatchFileLineTokenizer::advanceToTokenEnd() -{ - forever { - if (m_isWithinQuotation) { - if (atEnd()) { - qWarning("ClangBatchFileProcessor: error: unfinished quotation."); - return nullptr; - } - - if (atQuotationMark()) - return m_currentChar++; - - } else if (atWhiteSpace() || atEnd()) { - return m_currentChar; - } - - ++m_currentChar; - } -} - -bool BatchFileLineTokenizer::atEnd() const -{ - return *m_currentChar == QLatin1Char('\0'); -} - -bool BatchFileLineTokenizer::atWhiteSpace() const -{ - return *m_currentChar == ' ' - || *m_currentChar == '\t' - || *m_currentChar == '\n'; -} - -bool BatchFileLineTokenizer::atQuotationMark() const -{ - return *m_currentChar == '"'; -} - -struct CommandContext { - QString filePath; - int lineNumber = -1; -}; - -class Command -{ -public: - using Ptr = QSharedPointer; - -public: - Command(const CommandContext &context) : m_commandContext(context) {} - virtual ~Command() = default; - - const CommandContext &context() const { return m_commandContext; } - virtual bool run() { return true; } - -private: - const CommandContext m_commandContext; -}; - -class OpenProjectCommand : public Command -{ -public: - OpenProjectCommand(const CommandContext &context, - const QString &projectFilePath); - - bool run() override; - - static Command::Ptr parse(BatchFileLineTokenizer &arguments, - const CommandContext &context); - -private: - QString m_projectFilePath; -}; - -OpenProjectCommand::OpenProjectCommand(const CommandContext &context, - const QString &projectFilePath) - : Command(context) - , m_projectFilePath(projectFilePath) -{ -} - -bool OpenProjectCommand::run() -{ - qCDebug(debug) << "line" << context().lineNumber << "OpenProjectCommand" << m_projectFilePath; - - const ProjectExplorerPlugin::OpenProjectResult openProjectSucceeded - = ProjectExplorerPlugin::openProject(Utils::FilePath::fromString(m_projectFilePath)); - QTC_ASSERT(openProjectSucceeded, return false); - - Project *project = openProjectSucceeded.project(); - project->configureAsExampleProject(nullptr); - - return CppEditor::Tests::TestCase::waitUntilProjectIsFullyOpened(project, timeOutInMs()); -} - -Command::Ptr OpenProjectCommand::parse(BatchFileLineTokenizer &arguments, - const CommandContext &context) -{ - const QString projectFilePath = arguments.nextToken(); - if (projectFilePath.isEmpty()) { - qWarning("%s:%d: error: No project file path given.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - const QString absoluteProjectFilePath = QFileInfo(projectFilePath).absoluteFilePath(); - - return Command::Ptr(new OpenProjectCommand(context, absoluteProjectFilePath)); -} - -class OpenDocumentCommand : public Command -{ -public: - OpenDocumentCommand(const CommandContext &context, - const QString &documentFilePath); - - bool run() override; - - static Command::Ptr parse(BatchFileLineTokenizer &arguments, const CommandContext &context); - -private: - Utils::FilePath m_documentFilePath; -}; - -OpenDocumentCommand::OpenDocumentCommand(const CommandContext &context, - const QString &documentFilePath) - : Command(context) - , m_documentFilePath(Utils::FilePath::fromString(documentFilePath)) -{ -} - -class WaitForUpdatedCodeWarnings : public QObject -{ -public: - WaitForUpdatedCodeWarnings(ClangEditorDocumentProcessor *processor); - - bool wait(int timeOutInMs) const; - -private: - void onCodeWarningsUpdated() { m_gotResults = true; } - -private: - - bool m_gotResults = false; -}; - -WaitForUpdatedCodeWarnings::WaitForUpdatedCodeWarnings(ClangEditorDocumentProcessor *processor) -{ - connect(processor, - &ClangEditorDocumentProcessor::codeWarningsUpdated, - this, &WaitForUpdatedCodeWarnings::onCodeWarningsUpdated); -} - -bool WaitForUpdatedCodeWarnings::wait(int timeOutInMs) const -{ - QElapsedTimer time; - time.start(); - - forever { - if (time.elapsed() > timeOutInMs) { - qWarning("WaitForUpdatedCodeWarnings: timeout of %d ms reached.", timeOutInMs); - return false; - } - - if (m_gotResults) - return true; - - QCoreApplication::processEvents(); - QThread::msleep(20); - } -} - -bool OpenDocumentCommand::run() -{ - qCDebug(debug) << "line" << context().lineNumber << "OpenDocumentCommand" << m_documentFilePath; - - const bool openEditorSucceeded = Core::EditorManager::openEditor(m_documentFilePath); - QTC_ASSERT(openEditorSucceeded, return false); - - auto *processor = ClangEditorDocumentProcessor::get(m_documentFilePath); - QTC_ASSERT(processor, return false); - - WaitForUpdatedCodeWarnings waiter(processor); - return waiter.wait(timeOutInMs()); -} - -Command::Ptr OpenDocumentCommand::parse(BatchFileLineTokenizer &arguments, - const CommandContext &context) -{ - const QString documentFilePath = arguments.nextToken(); - if (documentFilePath.isEmpty()) { - qWarning("%s:%d: error: No document file path given.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - const QString absoluteDocumentFilePath = QFileInfo(documentFilePath).absoluteFilePath(); - - return Command::Ptr(new OpenDocumentCommand(context, absoluteDocumentFilePath)); -} - -class CloseAllDocuments : public Command -{ -public: - CloseAllDocuments(const CommandContext &context); - - bool run() override; - - static Command::Ptr parse(BatchFileLineTokenizer &arguments, const CommandContext &context); -}; - -CloseAllDocuments::CloseAllDocuments(const CommandContext &context) - : Command(context) -{ -} - -bool CloseAllDocuments::run() -{ - qCDebug(debug) << "line" << context().lineNumber << "CloseAllDocuments"; - - return Core::EditorManager::closeAllEditors(/*askAboutModifiedEditors=*/ false); -} - -Command::Ptr CloseAllDocuments::parse(BatchFileLineTokenizer &arguments, - const CommandContext &context) -{ - const QString argument = arguments.nextToken(); - if (!argument.isEmpty()) { - qWarning("%s:%d: error: Unexpected argument.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - return Command::Ptr(new CloseAllDocuments(context)); -} - -class InsertTextCommand : public Command -{ -public: - // line and column are 1-based - InsertTextCommand(const CommandContext &context, const QString &text); - - bool run() override; - - static Command::Ptr parse(BatchFileLineTokenizer &arguments, - const CommandContext &context); - -private: - const QString m_textToInsert; -}; - -InsertTextCommand::InsertTextCommand(const CommandContext &context, const QString &text) - : Command(context) - , m_textToInsert(text) -{ -} - -TextEditor::BaseTextEditor *currentTextEditor() -{ - return qobject_cast(Core::EditorManager::currentEditor()); -} - -bool InsertTextCommand::run() -{ - qCDebug(debug) << "line" << context().lineNumber << "InsertTextCommand" << m_textToInsert; - - TextEditor::BaseTextEditor *editor = currentTextEditor(); - QTC_ASSERT(editor, return false); - const Utils::FilePath documentFilePath = editor->document()->filePath(); - auto processor = ClangEditorDocumentProcessor::get(documentFilePath); - QTC_ASSERT(processor, return false); - - editor->insert(m_textToInsert); - - WaitForUpdatedCodeWarnings waiter(processor); - return waiter.wait(timeOutInMs()); -} - -Command::Ptr InsertTextCommand::parse(BatchFileLineTokenizer &arguments, - const CommandContext &context) -{ - const QString textToInsert = arguments.nextToken(); - if (textToInsert.isEmpty()) { - qWarning("%s:%d: error: No text to insert given.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - return Command::Ptr(new InsertTextCommand(context, textToInsert)); -} - -class SetCursorCommand : public Command -{ -public: - // line and column are 1-based - SetCursorCommand(const CommandContext &context, int line, int column); - - bool run() override; - - static Command::Ptr parse(BatchFileLineTokenizer &arguments, - const CommandContext &context); - -private: - int m_line; - int m_column; -}; - -SetCursorCommand::SetCursorCommand(const CommandContext &context, int line, int column) - : Command(context) - , m_line(line) - , m_column(column) -{ -} - -bool SetCursorCommand::run() -{ - qCDebug(debug) << "line" << context().lineNumber << "SetCursorCommand" << m_line << m_column; - - TextEditor::BaseTextEditor *editor = currentTextEditor(); - QTC_ASSERT(editor, return false); - - editor->gotoLine(m_line, m_column - 1); - - return true; -} - -Command::Ptr SetCursorCommand::parse(BatchFileLineTokenizer &arguments, - const CommandContext &context) -{ - // Process line - const QString line = arguments.nextToken(); - if (line.isEmpty()) { - qWarning("%s:%d: error: No line number given.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - bool converted = false; - const int lineNumber = line.toInt(&converted); - if (!converted) { - qWarning("%s:%d: error: Invalid line number.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - // Process column - const QString column = arguments.nextToken(); - if (column.isEmpty()) { - qWarning("%s:%d: error: No column number given.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - converted = false; - const int columnNumber = column.toInt(&converted); - if (!converted) { - qWarning("%s:%d: error: Invalid column number.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - return Command::Ptr(new SetCursorCommand(context, lineNumber, columnNumber)); -} - -class ProcessEventsCommand : public Command -{ -public: - ProcessEventsCommand(const CommandContext &context, int durationInMs); - - bool run() override; - - static Command::Ptr parse(BatchFileLineTokenizer &arguments, - const CommandContext &context); - -private: - int m_durationInMs; -}; - -ProcessEventsCommand::ProcessEventsCommand(const CommandContext &context, - int durationInMs) - : Command(context) - , m_durationInMs(durationInMs) -{ -} - -bool ProcessEventsCommand::run() -{ - qCDebug(debug) << "line" << context().lineNumber << "ProcessEventsCommand" << m_durationInMs; - - QElapsedTimer time; - time.start(); - - forever { - if (time.elapsed() > m_durationInMs) - return true; - - QCoreApplication::processEvents(); - QThread::msleep(20); - } -} - -Command::Ptr ProcessEventsCommand::parse(BatchFileLineTokenizer &arguments, - const CommandContext &context) -{ - const QString durationInMsText = arguments.nextToken(); - if (durationInMsText.isEmpty()) { - qWarning("%s:%d: error: No duration given.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - bool converted = false; - const int durationInMs = durationInMsText.toInt(&converted); - if (!converted) { - qWarning("%s:%d: error: Invalid duration given.", - qPrintable(context.filePath), - context.lineNumber); - return Command::Ptr(); - } - - return Command::Ptr(new ProcessEventsCommand(context, durationInMs)); -} - -class BatchFileReader -{ -public: - BatchFileReader(const QString &filePath); - - bool isFilePathValid() const; - - QString read() const; - -private: - const QString m_batchFilePath; -}; - -BatchFileReader::BatchFileReader(const QString &filePath) - : m_batchFilePath(filePath) -{ -} - -bool BatchFileReader::isFilePathValid() const -{ - QFileInfo fileInfo(m_batchFilePath); - - return !m_batchFilePath.isEmpty() - && fileInfo.isFile() - && fileInfo.isReadable(); -} - -QString BatchFileReader::read() const -{ - QFile file(m_batchFilePath); - QTC_CHECK(file.open(QFile::ReadOnly | QFile::Text)); - - return QString::fromLocal8Bit(file.readAll()); -} - -class BatchFileParser -{ -public: - BatchFileParser(const QString &filePath, - const QString &commands); - - bool parse(); - QVector commands() const; - -private: - bool advanceLine(); - QString currentLine() const; - bool parseLine(const QString &line); - -private: - using ParseFunction = Command::Ptr (*)(BatchFileLineTokenizer &, const CommandContext &); - using CommandToParseFunction = QHash; - CommandToParseFunction m_commandParsers; - - int m_currentLineIndex = -1; - CommandContext m_context; - QStringList m_lines; - QVector m_commands; -}; - -BatchFileParser::BatchFileParser(const QString &filePath, - const QString &commands) - : m_lines(commands.split('\n')) -{ - m_context.filePath = filePath; - - m_commandParsers.insert("openProject", &OpenProjectCommand::parse); - m_commandParsers.insert("openDocument", &OpenDocumentCommand::parse); - m_commandParsers.insert("closeAllDocuments", &CloseAllDocuments::parse); - m_commandParsers.insert("setCursor", &SetCursorCommand::parse); - m_commandParsers.insert("insertText", &InsertTextCommand::parse); - m_commandParsers.insert("processEvents", &ProcessEventsCommand::parse); -} - -bool BatchFileParser::parse() -{ - while (advanceLine()) { - const QString line = currentLine().trimmed(); - if (line.isEmpty() || line.startsWith('#')) - continue; - - if (!parseLine(line)) - return false; - } - - return true; -} - -QVector BatchFileParser::commands() const -{ - return m_commands; -} - -bool BatchFileParser::advanceLine() -{ - ++m_currentLineIndex; - m_context.lineNumber = m_currentLineIndex + 1; - return m_currentLineIndex < m_lines.size(); -} - -QString BatchFileParser::currentLine() const -{ - return m_lines[m_currentLineIndex]; -} - -bool BatchFileParser::parseLine(const QString &line) -{ - BatchFileLineTokenizer tokenizer(line); - QString command = tokenizer.nextToken(); - QTC_CHECK(!command.isEmpty()); - - if (const ParseFunction parseFunction = m_commandParsers.value(command)) { - if (Command::Ptr cmd = parseFunction(tokenizer, m_context)) { - m_commands.append(cmd); - return true; - } - - return false; - } - - qWarning("%s:%d: error: Unknown command \"%s\".", - qPrintable(m_context.filePath), - m_context.lineNumber, - qPrintable(command)); - - return false; -} - -} // anonymous namespace - -static QString applySubstitutions(const QString &filePath, const QString &text) -{ - const QString dirPath = QFileInfo(filePath).absolutePath(); - - QString result = text; - result.replace("${PWD}", dirPath); - - return result; -} - -bool runClangBatchFile(const QString &filePath) -{ - qWarning("ClangBatchFileProcessor: Running \"%s\".", qPrintable(filePath)); - - BatchFileReader reader(filePath); - QTC_ASSERT(reader.isFilePathValid(), return false); - const QString fileContent = reader.read(); - const QString fileContentWithSubstitutionsApplied = applySubstitutions(filePath, fileContent); - - BatchFileParser parser(filePath, fileContentWithSubstitutionsApplied); - QTC_ASSERT(parser.parse(), return false); - const QVector commands = parser.commands(); - - Utils::ExecuteOnDestruction closeAllEditors([] { - qWarning("ClangBatchFileProcessor: Finished, closing all documents."); - QTC_CHECK(Core::EditorManager::closeAllEditors(/*askAboutModifiedEditors=*/ false)); - }); - - for (const Command::Ptr &command : commands) { - const bool runSucceeded = command->run(); - QCoreApplication::processEvents(); // Update GUI - - if (!runSucceeded) { - const CommandContext context = command->context(); - qWarning("%s:%d: Failed to run.", - qPrintable(context.filePath), - context.lineNumber); - return false; - } - } - - return true; -} - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.h b/src/plugins/clangcodemodel/test/clangbatchfileprocessor.h deleted file mode 100644 index 942269b3648..00000000000 --- a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace ClangCodeModel { -namespace Internal { - -int timeOutInMs(); - -bool runClangBatchFile(const QString &filePath); - -} // namespace Internal -} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index cf94865098c..a87061ef70f 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -3,7 +3,6 @@ #include "clangdtests.h" -#include "clangbatchfileprocessor.h" #include "../clangdclient.h" #include "../clangmodelmanagersupport.h" @@ -69,6 +68,27 @@ static QString qrcPath(const QString &relativeFilePath) return ":/unittests/ClangCodeModel/" + relativeFilePath; } +static Q_LOGGING_CATEGORY(debug, "qtc.clangcodemodel.batch", QtWarningMsg); + +static int timeOutFromEnvironmentVariable() +{ + bool isConversionOk = false; + const int intervalAsInt = Utils::qtcEnvironmentVariableIntValue("QTC_CLANG_BATCH_TIMEOUT", + &isConversionOk); + if (!isConversionOk) { + qCDebug(debug, "Environment variable QTC_CLANG_BATCH_TIMEOUT is not set, assuming 30000."); + return 30000; + } + + return intervalAsInt; +} + +int timeOutInMs() +{ + static int timeOut = timeOutFromEnvironmentVariable(); + return timeOut; +} + ClangdTest::~ClangdTest() { EditorManager::closeAllEditors(false); From 227e66b62c767f282302b07f8e642da230c52eb5 Mon Sep 17 00:00:00 2001 From: Yixue Wang Date: Mon, 30 Jan 2023 11:45:51 +0800 Subject: [PATCH 0049/1447] ClangFormat: Correct .clang-format .clang-format contains some disallowed values for some fields. These fields are corrected according to ClangFormatStyleOptions. Change-Id: I32a40cdfeabee550ebf23f6c9cb3d1fafc3b764b Reviewed-by: Eike Ziller --- .clang-format | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.clang-format b/.clang-format index 1b9871712f1..0a0df0c152d 100644 --- a/.clang-format +++ b/.clang-format @@ -23,19 +23,19 @@ AlignEscapedNewlines: DontAlign AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: false +AllowShortBlocksOnASingleLine: Never AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: true +AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BraceWrapping: AfterClass: true - AfterControlStatement: false + AfterControlStatement: Never AfterEnum: false AfterFunction: true AfterNamespace: false @@ -99,7 +99,7 @@ PenaltyExcessCharacter: 50 PenaltyReturnTypeOnItsOwnLine: 300 PointerAlignment: Right ReflowComments: false -SortIncludes: true +SortIncludes: CaseSensitive SortUsingDeclarations: true SpaceAfterCStyleCast: true SpaceAfterTemplateKeyword: false @@ -112,6 +112,6 @@ SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp11 +Standard: c++11 TabWidth: 4 UseTab: Never From a382be045417cd1403d1e593613f34ee74091936 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Feb 2023 16:11:17 +0100 Subject: [PATCH 0050/1447] Help: Merge helpmode.{h,cpp} into helpplugin.cpp Never re-used and tiny. Not worth a file pair. Change-Id: Idc5b2f4080b7140dee4f32fd834f4c76a7abc4b4 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/help/CMakeLists.txt | 1 - src/plugins/help/help.qbs | 1 - src/plugins/help/helpmode.cpp | 24 ------------- src/plugins/help/helpmode.h | 21 ------------ src/plugins/help/helpplugin.cpp | 60 ++++++++++++++++++--------------- 5 files changed, 33 insertions(+), 74 deletions(-) delete mode 100644 src/plugins/help/helpmode.cpp delete mode 100644 src/plugins/help/helpmode.h diff --git a/src/plugins/help/CMakeLists.txt b/src/plugins/help/CMakeLists.txt index 76a680c7595..c25f0b6cd5b 100644 --- a/src/plugins/help/CMakeLists.txt +++ b/src/plugins/help/CMakeLists.txt @@ -12,7 +12,6 @@ add_qtc_plugin(Help helpfindsupport.cpp helpfindsupport.h helpindexfilter.cpp helpindexfilter.h helpmanager.cpp helpmanager.h - helpmode.cpp helpmode.h helpplugin.cpp helpplugin.h helpviewer.cpp helpviewer.h helpwidget.cpp helpwidget.h diff --git a/src/plugins/help/help.qbs b/src/plugins/help/help.qbs index 25d85bdc37e..d96cfa154e7 100644 --- a/src/plugins/help/help.qbs +++ b/src/plugins/help/help.qbs @@ -43,7 +43,6 @@ Project { "helpfindsupport.cpp", "helpfindsupport.h", "helpindexfilter.cpp", "helpindexfilter.h", "helpmanager.cpp", "helpmanager.h", - "helpmode.cpp", "helpmode.h", "helpplugin.cpp", "helpplugin.h", "helpviewer.cpp", "helpviewer.h", "helpwidget.cpp", "helpwidget.h", diff --git a/src/plugins/help/helpmode.cpp b/src/plugins/help/helpmode.cpp deleted file mode 100644 index 2e2ee468939..00000000000 --- a/src/plugins/help/helpmode.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "helpmode.h" -#include "helpconstants.h" -#include "helpicons.h" -#include "helptr.h" - -#include - -using namespace Help; -using namespace Help::Internal; - -HelpMode::HelpMode(QObject *parent) - : Core::IMode(parent) -{ - setObjectName("HelpMode"); - setContext(Core::Context(Constants::C_MODE_HELP)); - setIcon(Utils::Icon::modeIcon(Icons::MODE_HELP_CLASSIC, - Icons::MODE_HELP_FLAT, Icons::MODE_HELP_FLAT_ACTIVE)); - setDisplayName(Tr::tr("Help")); - setPriority(Constants::P_MODE_HELP); - setId(Constants::ID_MODE_HELP); -} diff --git a/src/plugins/help/helpmode.h b/src/plugins/help/helpmode.h deleted file mode 100644 index fbe69f08bca..00000000000 --- a/src/plugins/help/helpmode.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include -#include - -namespace Help { -namespace Internal { - -class HelpMode : public Core::IMode -{ -public: - explicit HelpMode(QObject *parent = nullptr); -}; - -} // namespace Internal -} // namespace Help diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 56126372476..de055889edb 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -4,7 +4,6 @@ #include "helpplugin.h" #include "bookmarkmanager.h" -#include "contentwindow.h" #include "docsettingspage.h" #include "filtersettingspage.h" #include "generalsettingspage.h" @@ -13,11 +12,9 @@ #include "helpicons.h" #include "helpindexfilter.h" #include "helpmanager.h" -#include "helpmode.h" #include "helptr.h" #include "helpviewer.h" #include "helpwidget.h" -#include "indexwindow.h" #include "localhelpmanager.h" #include "openpagesmanager.h" #include "searchtaskhandler.h" @@ -35,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -52,38 +50,47 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include +#include #include #include -#include -#include -#include - +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -static const char kExternalWindowStateKey[] = "Help/ExternalWindowState"; -static const char kToolTipHelpContext[] = "Help.ToolTip"; - using namespace Core; using namespace Utils; -namespace Help { -namespace Internal { +namespace Help::Internal { + +const char kExternalWindowStateKey[] = "Help/ExternalWindowState"; +const char kToolTipHelpContext[] = "Help.ToolTip"; + +class HelpMode : public IMode +{ +public: + HelpMode() + { + setObjectName("HelpMode"); + setContext(Core::Context(Constants::C_MODE_HELP)); + setIcon(Icon::modeIcon(Icons::MODE_HELP_CLASSIC, + Icons::MODE_HELP_FLAT, Icons::MODE_HELP_FLAT_ACTIVE)); + setDisplayName(Tr::tr("Help")); + setPriority(Constants::P_MODE_HELP); + setId(Constants::ID_MODE_HELP); + } +}; class HelpPluginPrivate : public QObject { @@ -641,5 +648,4 @@ void HelpPluginPrivate::doSetupIfNeeded() } } -} // Internal -} // Help +} // Help::Internal From 0bb9798c30b3e590c02c467652e548eb45f21c96 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Feb 2023 16:32:44 +0100 Subject: [PATCH 0051/1447] Core: Drop Q_OBJECT in PresentationModeHandler Not needed. Change-Id: Ia6416071f303fd456dc4094aabfeb63acbb226c2 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/coreplugin/actionmanager/actionmanager.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp index 3d0a200283c..54e58dc217a 100644 --- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp +++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp @@ -34,8 +34,6 @@ namespace Core::Internal { class PresentationModeHandler : public QObject { - Q_OBJECT - public: void connectCommand(Command *command); @@ -520,5 +518,3 @@ void ActionManagerPrivate::saveSettings() saveSettings(j.value()); } } - -#include "actionmanager.moc" From 8b70e59cdbd5f205ebced66c9c48f11dac69ac43 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Mon, 27 Jan 2020 17:35:38 +0900 Subject: [PATCH 0052/1447] Add markdown viewer plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QTCREATORBUG-27883 Change-Id: Ie4099b8a322797d300bc15a80333bcb361ecafc3 Reviewed-by: André Hartmann --- src/plugins/CMakeLists.txt | 1 + src/plugins/markdownviewer/CMakeLists.txt | 12 +++ .../markdownviewer/MarkdownViewer.json.in | 18 ++++ .../markdownviewer/markdownbrowser.cpp | 32 +++++++ src/plugins/markdownviewer/markdownbrowser.h | 24 ++++++ .../markdownviewer/markdowndocument.cpp | 18 ++++ src/plugins/markdownviewer/markdowndocument.h | 19 ++++ src/plugins/markdownviewer/markdowneditor.cpp | 28 ++++++ src/plugins/markdownviewer/markdowneditor.h | 19 ++++ src/plugins/markdownviewer/markdownviewer.cpp | 86 +++++++++++++++++++ src/plugins/markdownviewer/markdownviewer.h | 30 +++++++ src/plugins/markdownviewer/markdownviewer.qbs | 27 ++++++ .../markdownviewer/markdownviewerconstants.h | 17 ++++ .../markdownviewer/markdownviewerfactory.cpp | 22 +++++ .../markdownviewer/markdownviewerfactory.h | 18 ++++ .../markdownviewer/markdownviewerplugin.cpp | 25 ++++++ .../markdownviewer/markdownviewerplugin.h | 26 ++++++ .../markdownviewer/markdownviewerwidget.cpp | 58 +++++++++++++ .../markdownviewer/markdownviewerwidget.h | 37 ++++++++ src/plugins/plugins.qbs | 1 + 20 files changed, 518 insertions(+) create mode 100644 src/plugins/markdownviewer/CMakeLists.txt create mode 100644 src/plugins/markdownviewer/MarkdownViewer.json.in create mode 100644 src/plugins/markdownviewer/markdownbrowser.cpp create mode 100644 src/plugins/markdownviewer/markdownbrowser.h create mode 100644 src/plugins/markdownviewer/markdowndocument.cpp create mode 100644 src/plugins/markdownviewer/markdowndocument.h create mode 100644 src/plugins/markdownviewer/markdowneditor.cpp create mode 100644 src/plugins/markdownviewer/markdowneditor.h create mode 100644 src/plugins/markdownviewer/markdownviewer.cpp create mode 100644 src/plugins/markdownviewer/markdownviewer.h create mode 100644 src/plugins/markdownviewer/markdownviewer.qbs create mode 100644 src/plugins/markdownviewer/markdownviewerconstants.h create mode 100644 src/plugins/markdownviewer/markdownviewerfactory.cpp create mode 100644 src/plugins/markdownviewer/markdownviewerfactory.h create mode 100644 src/plugins/markdownviewer/markdownviewerplugin.cpp create mode 100644 src/plugins/markdownviewer/markdownviewerplugin.h create mode 100644 src/plugins/markdownviewer/markdownviewerwidget.cpp create mode 100644 src/plugins/markdownviewer/markdownviewerwidget.h diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 8c4f2e2bb68..4f224e73482 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(texteditor) add_subdirectory(serialterminal) add_subdirectory(helloworld) add_subdirectory(imageviewer) +add_subdirectory(markdownviewer) add_subdirectory(marketplace) add_subdirectory(updateinfo) add_subdirectory(welcome) diff --git a/src/plugins/markdownviewer/CMakeLists.txt b/src/plugins/markdownviewer/CMakeLists.txt new file mode 100644 index 00000000000..c7f9d507857 --- /dev/null +++ b/src/plugins/markdownviewer/CMakeLists.txt @@ -0,0 +1,12 @@ +add_qtc_plugin(MarkdownViewer + PLUGIN_DEPENDS Core TextEditor + SOURCES + markdownbrowser.cpp markdownbrowser.h + markdowndocument.cpp markdowndocument.h + markdowneditor.cpp markdowneditor.h + markdownviewer.cpp markdownviewer.h + markdownviewerconstants.h + markdownviewerfactory.cpp markdownviewerfactory.h + markdownviewerplugin.cpp markdownviewerplugin.h + markdownviewerwidget.cpp markdownviewerwidget.h +) diff --git a/src/plugins/markdownviewer/MarkdownViewer.json.in b/src/plugins/markdownviewer/MarkdownViewer.json.in new file mode 100644 index 00000000000..4894a4bb8ba --- /dev/null +++ b/src/plugins/markdownviewer/MarkdownViewer.json.in @@ -0,0 +1,18 @@ +{ + \"Name\" : \"MarkdownViewer\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"Vendor\" : \"Signal Slot Inc.\", + \"Copyright\" : \"(C) 2023 Tasuku Suzuki\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", + \"\", + \"GNU General Public License Usage\", + \"\", + \"Alternatively, this plugin 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 plugin. 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.\" + ], + \"Description\" : \"Markdown Viewer component.\", + \"Url\" : \"https://signal-slot.co.jp/\", + $$dependencyList +} diff --git a/src/plugins/markdownviewer/markdownbrowser.cpp b/src/plugins/markdownviewer/markdownbrowser.cpp new file mode 100644 index 00000000000..43f10e27ada --- /dev/null +++ b/src/plugins/markdownviewer/markdownbrowser.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdownbrowser.h" + +#include + +namespace Markdown { +namespace Internal { + +MarkdownBrowser::MarkdownBrowser(QWidget *parent) + : QTextBrowser(parent) +{} + +void MarkdownBrowser::setMarkdown(const QString &markdown) +{ + QHash positions; + const auto scrollBars = findChildren(); + + // save scroll positions + for (const auto scrollBar : scrollBars) + positions.insert(scrollBar, scrollBar->value()); + + QTextBrowser::setMarkdown(markdown); + + // restore scroll positions + for (auto scrollBar : scrollBars) + scrollBar->setValue(positions.value(scrollBar)); +} + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownbrowser.h b/src/plugins/markdownviewer/markdownbrowser.h new file mode 100644 index 00000000000..6b71dcc533f --- /dev/null +++ b/src/plugins/markdownviewer/markdownbrowser.h @@ -0,0 +1,24 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Core { class IDocument; } + +namespace Markdown { +namespace Internal { + +class MarkdownBrowser : public QTextBrowser +{ + Q_OBJECT +public: + explicit MarkdownBrowser(QWidget *parent = nullptr); + +public slots: + void setMarkdown(const QString &markdown); +}; + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowndocument.cpp b/src/plugins/markdownviewer/markdowndocument.cpp new file mode 100644 index 00000000000..20e5334b1b7 --- /dev/null +++ b/src/plugins/markdownviewer/markdowndocument.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdowndocument.h" +#include "markdownviewerconstants.h" + +namespace Markdown { +namespace Internal { + +MarkdownDocument::MarkdownDocument() +{ + setId(Constants::MARKDOWNVIEWER_ID); + setMimeType(QLatin1String(Constants::MARKDOWNVIEWER_MIME_TYPE)); + connect(this, &MarkdownDocument::mimeTypeChanged, this, &MarkdownDocument::changed); +} + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowndocument.h b/src/plugins/markdownviewer/markdowndocument.h new file mode 100644 index 00000000000..76a2bd8136b --- /dev/null +++ b/src/plugins/markdownviewer/markdowndocument.h @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Markdown { +namespace Internal { + +class MarkdownDocument : public TextEditor::TextDocument +{ + Q_OBJECT +public: + MarkdownDocument(); +}; + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowneditor.cpp b/src/plugins/markdownviewer/markdowneditor.cpp new file mode 100644 index 00000000000..f908add50e6 --- /dev/null +++ b/src/plugins/markdownviewer/markdowneditor.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdowneditor.h" +#include "markdownviewerconstants.h" +#include "markdowndocument.h" + +#include +#include + +namespace Markdown { +namespace Internal { + +MarkdownEditor::MarkdownEditor(QWidget *parent) + : TextEditor::TextEditorWidget(parent) +{ + setTextDocument(TextEditor::TextDocumentPtr(new MarkdownDocument)); + setupGenericHighlighter(); + setMarksVisible(false); + + auto context = new Core::IContext(this); + context->setWidget(this); + context->setContext(Core::Context(Constants::MARKDOWNVIEWER_EDITOR_CONTEXT)); + Core::ICore::addContextObject(context); +} + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowneditor.h b/src/plugins/markdownviewer/markdowneditor.h new file mode 100644 index 00000000000..f378309a6b7 --- /dev/null +++ b/src/plugins/markdownviewer/markdowneditor.h @@ -0,0 +1,19 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Markdown { +namespace Internal { + +class MarkdownEditor : public TextEditor::TextEditorWidget +{ + Q_OBJECT +public: + MarkdownEditor(QWidget *parent = nullptr); +}; + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewer.cpp b/src/plugins/markdownviewer/markdownviewer.cpp new file mode 100644 index 00000000000..b3e21ce40fa --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewer.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdownviewer.h" +#include "markdownviewerconstants.h" +#include "markdownviewerwidget.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace Markdown { +namespace Internal { + +struct MarkdownViewerPrivate +{ + MarkdownViewerWidget *widget; + QWidget *toolbar; + QToolButton *toggleEditorVisible; +}; + +MarkdownViewer::MarkdownViewer() + : d(new MarkdownViewerPrivate) +{ + ctor(); +} + +void MarkdownViewer::ctor() +{ + d->widget = new MarkdownViewerWidget; + + setContext(Core::Context(Constants::MARKDOWNVIEWER_ID)); + setWidget(d->widget); + + d->toolbar = new QWidget; + auto layout = new QHBoxLayout; + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + layout->addStretch(); + + d->toggleEditorVisible = new QToolButton; + d->toggleEditorVisible->setText(tr("Hide Editor")); + d->toggleEditorVisible->setCheckable(true); + d->toggleEditorVisible->setChecked(true); + layout->addWidget(d->toggleEditorVisible); + + d->toolbar->setLayout(layout); + + // connections + connect(d->toggleEditorVisible, &QToolButton::toggled, d->widget, &MarkdownViewerWidget::setEditorVisible); + connect(d->widget, &MarkdownViewerWidget::editorVisibleChanged, this, [this](bool editorVisible) { + d->toggleEditorVisible->setText(editorVisible ? tr("Hide Editor") : tr("Show Editor")); + }); +} + +MarkdownViewer::~MarkdownViewer() +{ + delete d->widget; + delete d->toolbar; + delete d; +} + +Core::IDocument *MarkdownViewer::document() const +{ + return d->widget->document(); +} + +QWidget *MarkdownViewer::toolBar() +{ + return d->toolbar; +} + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewer.h b/src/plugins/markdownviewer/markdownviewer.h new file mode 100644 index 00000000000..a29089a1e3f --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewer.h @@ -0,0 +1,30 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace Markdown { +namespace Internal { +class MarkdownDocument; + +class MarkdownViewer : public Core::IEditor +{ + Q_OBJECT +public: + explicit MarkdownViewer(); + ~MarkdownViewer() override; + + Core::IDocument *document() const override; + QWidget *toolBar() override; + +private: + void ctor(); + + struct MarkdownViewerPrivate *d; +}; + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewer.qbs b/src/plugins/markdownviewer/markdownviewer.qbs new file mode 100644 index 00000000000..1a5bdbb7cd1 --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewer.qbs @@ -0,0 +1,27 @@ +import qbs 1.0 + +QtcPlugin { + name: "MarkdownViewer" + + Depends { name: "Qt.widgets" } + Depends { name: "Core" } + Depends { name: "TextEditor" } + + files: [ + "markdownbrowser.cpp", + "markdownbrowser.h", + "markdowndocument.cpp", + "markdowndocument.h", + "markdowneditor.cpp", + "markdowneditor.h", + "markdownviewer.cpp", + "markdownviewer.h", + "markdownviewerconstants.h", + "markdownviewerfactory.cpp", + "markdownviewerfactory.h", + "markdownviewerplugin.cpp", + "markdownviewerplugin.h", + "markdownviewerwidget.cpp", + "markdownviewerwidget.h", + ] +} diff --git a/src/plugins/markdownviewer/markdownviewerconstants.h b/src/plugins/markdownviewer/markdownviewerconstants.h new file mode 100644 index 00000000000..45111743912 --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewerconstants.h @@ -0,0 +1,17 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Markdown { +namespace Constants { + +const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; +const char MARKDOWNVIEWER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Markdown Viewer"); +const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown"; +const char MARKDOWNVIEWER_EDITOR_CONTEXT[] = "Editors.MarkdownViewer.Id"; + +} // namespace Constants +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerfactory.cpp b/src/plugins/markdownviewer/markdownviewerfactory.cpp new file mode 100644 index 00000000000..0e157b2ce6a --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewerfactory.cpp @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdownviewerfactory.h" +#include "markdownviewerconstants.h" +#include "markdownviewer.h" + +#include + +namespace Markdown { +namespace Internal { + +MarkdownViewerFactory::MarkdownViewerFactory() +{ + setId(Constants::MARKDOWNVIEWER_ID); + setDisplayName(QCoreApplication::translate("OpenWith::Editors", Constants::MARKDOWNVIEWER_DISPLAY_NAME)); + addMimeType(Constants::MARKDOWNVIEWER_MIME_TYPE); + setEditorCreator([] { return new MarkdownViewer(); }); +} + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerfactory.h b/src/plugins/markdownviewer/markdownviewerfactory.h new file mode 100644 index 00000000000..294014945e7 --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewerfactory.h @@ -0,0 +1,18 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Markdown { +namespace Internal { + +class MarkdownViewerFactory final : public Core::IEditorFactory +{ +public: + MarkdownViewerFactory(); +}; + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerplugin.cpp b/src/plugins/markdownviewer/markdownviewerplugin.cpp new file mode 100644 index 00000000000..db2c4965b31 --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewerplugin.cpp @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdownviewerplugin.h" +#include "markdownviewerfactory.h" + +#include + +using namespace Core; + +namespace Markdown { +namespace Internal { + +bool MarkdownViewerPlugin::initialize(const QStringList &arguments, QString *errorMessage) +{ + Q_UNUSED(arguments) + Q_UNUSED(errorMessage) + + ExtensionSystem::PluginManager::addObject(new MarkdownViewerFactory); + + return true; +} + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerplugin.h b/src/plugins/markdownviewer/markdownviewerplugin.h new file mode 100644 index 00000000000..f5d0305b0cd --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewerplugin.h @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Markdown { +namespace Internal { + +class MarkdownViewerPlugin : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "MarkdownViewer.json") + +public: + MarkdownViewerPlugin() = default; + ~MarkdownViewerPlugin() = default; + +private: + bool initialize(const QStringList &arguments, QString *errorMessage) final; + void extensionsInitialized() final {} +}; + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerwidget.cpp b/src/plugins/markdownviewer/markdownviewerwidget.cpp new file mode 100644 index 00000000000..8148be75908 --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewerwidget.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdownviewerwidget.h" +#include "markdowneditor.h" +#include "markdownbrowser.h" + +#include + +namespace Markdown { +namespace Internal { + +struct MarkdownViewerWidgetPrivate +{ + MarkdownBrowser *browser; + MarkdownEditor *editor; +}; + +MarkdownViewerWidget::MarkdownViewerWidget() + : d(new MarkdownViewerWidgetPrivate) +{ + d->browser = new MarkdownBrowser(this); + d->browser->setOpenExternalLinks(true); + d->browser->setFrameShape(QFrame::NoFrame); + d->editor = new MarkdownEditor(this); + + connect(d->editor->document(), &QTextDocument::contentsChanged, + this, [this]() { + const auto plainText = d->editor->textDocument()->plainText(); + d->browser->setMarkdown(plainText); + }); +} + +MarkdownViewerWidget::~MarkdownViewerWidget() +{ + delete d; +} + +Core::IDocument *MarkdownViewerWidget::document() const +{ + return d->editor->textDocument(); +} + +bool MarkdownViewerWidget::isEditorVisible() const +{ + return d->editor->isVisible(); +} + +void MarkdownViewerWidget::setEditorVisible(bool editorVisible) +{ + if (d->editor->isVisible() == editorVisible) + return; + d->editor->setVisible(editorVisible); + emit editorVisibleChanged(editorVisible); +} + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerwidget.h b/src/plugins/markdownviewer/markdownviewerwidget.h new file mode 100644 index 00000000000..16581c6cb54 --- /dev/null +++ b/src/plugins/markdownviewer/markdownviewerwidget.h @@ -0,0 +1,37 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace Core { class IDocument; } + +namespace Markdown { +namespace Internal { + +class MarkdownViewerWidget : public Core::MiniSplitter +{ + Q_OBJECT + Q_PROPERTY(bool editorVisible READ isEditorVisible WRITE setEditorVisible NOTIFY editorVisibleChanged) +public: + explicit MarkdownViewerWidget(); + ~MarkdownViewerWidget() override; + + Core::IDocument *document() const; + + bool isEditorVisible() const; + +public slots: + void setEditorVisible(bool editorVisible); + +signals: + void editorVisibleChanged(bool editorVisible); + +private: + struct MarkdownViewerWidgetPrivate *d; +}; + +} // namespace Internal +} // namespace Markdown diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index b878e76c3e3..f4c6060aaeb 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -50,6 +50,7 @@ Project { "ios/ios.qbs", "languageclient/languageclient.qbs", "macros/macros.qbs", + "markdownviewer/markdownviewer.qbs", "marketplace/marketplace.qbs", "mcusupport/mcusupport.qbs", "mercurial/mercurial.qbs", From 7fe93633952671277c2204beb3298ee19becf237 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 15 Feb 2023 12:11:56 +0100 Subject: [PATCH 0053/1447] CPlusPlus: Use categorized logging in lexer Not suprisingly, the #ifdef-based debugging produced uncompilable code when enabled. Change-Id: I4a6646bfa98a8500491be4892d464ec88512bec7 Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/cplusplus/pp-engine.cpp | 63 ++++++++++++-------------------- src/libs/cplusplus/pp-engine.h | 1 + 2 files changed, 25 insertions(+), 39 deletions(-) diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index d8221b151f6..ef27d9eace8 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -37,20 +37,17 @@ #include #include #include +#include #include #include #include +#include #include #include -#define NO_DEBUG - -#ifndef NO_DEBUG -# include -#endif // NO_DEBUG - -#include +// FIXME: This is used for errors that should appear in the editor. +static Q_LOGGING_CATEGORY(lexerLog, "qtc.cpp.lexer", QtWarningMsg) using namespace Utils; @@ -119,13 +116,6 @@ static bool isQtReservedWord(const char *name, int size) return false; } -static void nestingTooDeep() -{ -#ifndef NO_DEBUG - std::cerr << "*** WARNING #if / #ifdef nesting exceeded the max level " << MAX_LEVEL << std::endl; -#endif -} - } // anonymous namespace namespace CPlusPlus { @@ -1680,10 +1670,7 @@ void Preprocessor::handleIncludeDirective(PPToken *tk, bool includeNext) GuardLocker depthLocker(m_includeDepthGuard); if (m_includeDepthGuard.lockCount() > MAX_INCLUDE_DEPTH) { - // FIXME: Categorized logging! -#ifndef NO_DEBUG - std::cerr << "Maximum include depth exceeded" << m_state.m_currentFileName << std::endl; -#endif + qCWarning(lexerLog) << "Maximum include depth exceeded" << m_state.m_currentFileName; return; } @@ -1929,10 +1916,8 @@ void Preprocessor::handleIfDirective(PPToken *tk) Value result; const PPToken lastExpressionToken = evalExpression(tk, result); - if (m_state.m_ifLevel >= MAX_LEVEL - 1) { - nestingTooDeep(); + if (!checkConditionalNesting()) return; - } const bool value = !result.is_zero(); @@ -1953,7 +1938,7 @@ void Preprocessor::handleIfDirective(PPToken *tk) void Preprocessor::handleElifDirective(PPToken *tk, const PPToken £Token) { if (m_state.m_ifLevel == 0) { -// std::cerr << "*** WARNING #elif without #if" << std::endl; + qCWarning(lexerLog) << "#elif without #if"; handleIfDirective(tk); } else { lex(tk); // consume "elif" token @@ -2000,22 +1985,18 @@ void Preprocessor::handleElseDirective(PPToken *tk, const PPToken £Token) else if (m_client && !wasSkipping && startSkipping) startSkippingBlocks(poundToken); } -#ifndef NO_DEBUG } else { - std::cerr << "*** WARNING #else without #if" << std::endl; -#endif // NO_DEBUG + qCWarning(lexerLog) << "#else without #if"; } } void Preprocessor::handleEndIfDirective(PPToken *tk, const PPToken £Token) { if (m_state.m_ifLevel == 0) { -#ifndef NO_DEBUG - std::cerr << "*** WARNING #endif without #if"; + qCWarning(lexerLog) << "#endif without #if"; if (!tk->generated()) - std::cerr << " on line " << tk->lineno << " of file " << m_state.m_currentFileName.toUtf8().constData(); - std::cerr << std::endl; -#endif // NO_DEBUG + qCWarning(lexerLog) << "on line" << tk->lineno << "of file" + << m_state.m_currentFileName.toUtf8().constData(); } else { bool wasSkipping = m_state.m_skipping[m_state.m_ifLevel]; m_state.m_skipping[m_state.m_ifLevel] = false; @@ -2061,22 +2042,18 @@ void Preprocessor::handleIfDefDirective(bool checkUndefined, PPToken *tk) const bool wasSkipping = m_state.m_skipping[m_state.m_ifLevel]; - if (m_state.m_ifLevel < MAX_LEVEL - 1) { + if (checkConditionalNesting()) { ++m_state.m_ifLevel; m_state.m_trueTest[m_state.m_ifLevel] = value; m_state.m_skipping[m_state.m_ifLevel] = wasSkipping ? wasSkipping : !value; if (m_client && !wasSkipping && !value) startSkippingBlocks(*tk); - } else { - nestingTooDeep(); } lex(tk); // consume the identifier -#ifndef NO_DEBUG } else { - std::cerr << "*** WARNING #ifdef without identifier" << std::endl; -#endif // NO_DEBUG + qCWarning(lexerLog) << "#ifdef without identifier"; } } @@ -2103,10 +2080,8 @@ void Preprocessor::handleUndefDirective(PPToken *tk) m_client->macroAdded(*macro); } lex(tk); // consume macro name -#ifndef NO_DEBUG } else { - std::cerr << "*** WARNING #undef without identifier" << std::endl; -#endif // NO_DEBUG + qCWarning(lexerLog) << "#undef without identifier"; } } @@ -2203,4 +2178,14 @@ void Preprocessor::maybeStartOutputLine() buffer.append('\n'); } +bool Preprocessor::checkConditionalNesting() const +{ + if (m_state.m_ifLevel >= MAX_LEVEL - 1) { + qCWarning(lexerLog) << "#if/#ifdef nesting exceeding maximum level" << MAX_LEVEL; + return false; + } + return true; +} + + } // namespace CPlusPlus diff --git a/src/libs/cplusplus/pp-engine.h b/src/libs/cplusplus/pp-engine.h index c888e8775d6..2163380dea2 100644 --- a/src/libs/cplusplus/pp-engine.h +++ b/src/libs/cplusplus/pp-engine.h @@ -237,6 +237,7 @@ private: PPToken generateConcatenated(const PPToken &leftTk, const PPToken &rightTk); void startSkippingBlocks(const PPToken &tk) const; + bool checkConditionalNesting() const; private: Client *m_client; From efc4a0f1af0fb644cab0055e40ccd0b7d51c43f2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 11 Feb 2023 18:43:19 +0100 Subject: [PATCH 0054/1447] AsyncTask: Make it possible to run with promise Using QtConcurrent API. Adapt asynctask tests according to new API. The old API in going to be removed, soon. Change-Id: I3cf163e9492526f0b49bd162c27e6c55a98ace7a Reviewed-by: Eike Ziller --- src/libs/utils/asynctask.cpp | 20 +++ src/libs/utils/asynctask.h | 44 +++++- tests/auto/utils/asynctask/tst_asynctask.cpp | 150 +++++++++++-------- 3 files changed, 152 insertions(+), 62 deletions(-) diff --git a/src/libs/utils/asynctask.cpp b/src/libs/utils/asynctask.cpp index 3576ad804c4..73217318a92 100644 --- a/src/libs/utils/asynctask.cpp +++ b/src/libs/utils/asynctask.cpp @@ -3,6 +3,26 @@ #include "asynctask.h" +#include + namespace Utils { +static int s_maxThreadCount = INT_MAX; + +class AsyncThreadPool : public QThreadPool +{ +public: + AsyncThreadPool() { + setMaxThreadCount(s_maxThreadCount); + moveToThread(qApp->thread()); + } +}; + +Q_GLOBAL_STATIC(AsyncThreadPool, s_asyncThreadPool); + +QThreadPool *asyncThreadPool() +{ + return s_asyncThreadPool; +} + } // namespace Utils diff --git a/src/libs/utils/asynctask.h b/src/libs/utils/asynctask.h index 1a6ae7d1b6a..84cf1ee838c 100644 --- a/src/libs/utils/asynctask.h +++ b/src/libs/utils/asynctask.h @@ -11,9 +11,12 @@ #include "tasktree.h" #include +#include namespace Utils { +QTCREATOR_UTILS_EXPORT QThreadPool *asyncThreadPool(); + class QTCREATOR_UTILS_EXPORT AsyncTaskBase : public QObject { Q_OBJECT @@ -38,7 +41,11 @@ public: m_watcher.waitForFinished(); } - using StartHandler = std::function()>; + template + void setConcurrentCallData(Function &&function, Args &&...args) + { + return wrapConcurrent(std::forward(function), std::forward(args)...); + } template void setAsyncCallData(const Function &function, const Args &...args) @@ -69,6 +76,41 @@ public: bool isResultAvailable() const { return future().resultCount(); } private: + template + void wrapConcurrent(Function &&function, Args &&...args) + { + m_startHandler = [=] { + return callConcurrent(function, args...); + }; + } + + template + void wrapConcurrent(std::reference_wrapper &&wrapper, Args &&...args) + { + m_startHandler = [=] { + return callConcurrent(std::forward(wrapper.get()), args...); + }; + } + + template + auto callConcurrent(Function &&function, Args &&...args) + { + // Notice: we can't just call: + // + // return QtConcurrent::run(function, args...); + // + // since there is no way of passing m_priority there. + // There is an overload with thread pool, however, there is no overload with priority. + // + // Below implementation copied from QtConcurrent::run(): + QThreadPool *threadPool = m_threadPool ? m_threadPool : asyncThreadPool(); + QtConcurrent::DecayedTuple + tuple{std::forward(function), std::forward(args)...}; + return QtConcurrent::TaskResolver, std::decay_t...> + ::run(std::move(tuple), QtConcurrent::TaskStartParameters{threadPool, m_priority}); + } + + using StartHandler = std::function()>; StartHandler m_startHandler; FutureSynchronizer *m_synchronizer = nullptr; QThreadPool *m_threadPool = nullptr; diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/asynctask/tst_asynctask.cpp index 83b3c82aed9..9ca972973cc 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/asynctask/tst_asynctask.cpp @@ -24,78 +24,109 @@ private: QThreadPool m_threadPool; }; -void report3(QFutureInterface &fi) +void report3(QPromise &promise) { - fi.reportResults({0, 2, 1}); + promise.addResult(0); + promise.addResult(2); + promise.addResult(1); } -void reportN(QFutureInterface &fi, int n) +void reportN(QPromise &promise, int n) { - fi.reportResults(QVector(n, 0)); + for (int i = 0; i < n; ++i) + promise.addResult(0); } -void reportString1(QFutureInterface &fi, const QString &s) +void reportString1(QPromise &promise, const QString &s) { - fi.reportResult(s); + promise.addResult(s); } -void reportString2(QFutureInterface &fi, QString s) +void reportString2(QPromise &promise, QString s) { - fi.reportResult(s); + promise.addResult(s); } class Callable { public: - void operator()(QFutureInterface &fi, int n) const + void operator()(QPromise &promise, int n) const { - fi.reportResults(QVector(n, 0)); + for (int i = 0; i < n; ++i) + promise.addResult(0); } }; class MyObject { public: - static void staticMember0(QFutureInterface &fi) + static void staticMember0(QPromise &promise) { - fi.reportResults({0, 2, 1}); + promise.addResult(0); + promise.addResult(2); + promise.addResult(1); } - static void staticMember1(QFutureInterface &fi, int n) + static void staticMember1(QPromise &promise, int n) { - fi.reportResults(QVector(n, 0)); + for (int i = 0; i < n; ++i) + promise.addResult(0); } - void member0(QFutureInterface &fi) const + void member0(QPromise &promise) const { - fi.reportResults({0, 2, 1}); + promise.addResult(0); + promise.addResult(2); + promise.addResult(1); } - void member1(QFutureInterface &fi, int n) const + void member1(QPromise &promise, int n) const { - fi.reportResults(QVector(n, 0)); + for (int i = 0; i < n; ++i) + promise.addResult(0); } - void memberString1(QFutureInterface &fi, const QString &s) const + void memberString1(QPromise &promise, const QString &s) const { - fi.reportResult(s); + promise.addResult(s); } - void memberString2(QFutureInterface &fi, QString s) const + void memberString2(QPromise &promise, QString s) const { - fi.reportResult(s); + promise.addResult(s); } - void nonConstMember(QFutureInterface &fi) + void nonConstMember(QPromise &promise) { - fi.reportResults({0, 2, 1}); + promise.addResult(0); + promise.addResult(2); + promise.addResult(1); } }; +template +struct FutureArgType; + +template +struct FutureArgType> +{ + using Type = Arg; +}; + +template +struct ConcurrentResultType; + +template +struct ConcurrentResultType +{ + using Type = typename FutureArgType(), std::declval()...))>::Type; +}; + template ::type> -std::shared_ptr> createAsyncTask(const Function &function, const Args &...args) + typename ResultType = typename ConcurrentResultType::Type> +std::shared_ptr> createAsyncTask(Function &&function, Args &&...args) { auto asyncTask = std::make_shared>(); - asyncTask->setAsyncCallData(function, args...); + asyncTask->setConcurrentCallData(std::forward(function), std::forward(args)...); asyncTask->start(); return asyncTask; } @@ -136,14 +167,16 @@ void tst_AsyncTask::runAsync() QList({QString(QLatin1String("rvalue"))})); // lambda - QCOMPARE(createAsyncTask([](QFutureInterface &fi, int n) { - fi.reportResults(QVector(n, 0)); + QCOMPARE(createAsyncTask([](QPromise &promise, int n) { + for (int i = 0; i < n; ++i) + promise.addResult(0); }, 3)->results(), QList({0, 0, 0})); // std::function - const std::function&,int)> fun = [](QFutureInterface &fi, int n) { - fi.reportResults(QVector(n, 0)); + const std::function&,int)> fun = [](QPromise &promise, int n) { + for (int i = 0; i < n; ++i) + promise.addResult(0); }; QCOMPARE(createAsyncTask(fun, 2)->results(), QList({0, 0})); @@ -190,51 +223,46 @@ void tst_AsyncTask::runAsync() void tst_AsyncTask::crefFunction() { - // free function pointer with future interface + // free function pointer with promise auto fun = &report3; QCOMPARE(createAsyncTask(std::cref(fun))->results(), QList({0, 2, 1})); - // lambda with future interface - auto lambda = [](QFutureInterface &fi, int n) { - fi.reportResults(QVector(n, 0)); + // lambda with promise + auto lambda = [](QPromise &promise, int n) { + for (int i = 0; i < n; ++i) + promise.addResult(0); }; QCOMPARE(createAsyncTask(std::cref(lambda), 3)->results(), QList({0, 0, 0})); - // std::function with future interface - const std::function&,int)> funObj = [](QFutureInterface &fi, int n) { - fi.reportResults(QVector(n, 0)); + // std::function with promise + const std::function&,int)> funObj = [](QPromise &promise, int n) { + for (int i = 0; i < n; ++i) + promise.addResult(0); }; QCOMPARE(createAsyncTask(std::cref(funObj), 2)->results(), QList({0, 0})); - // callable with future interface + // callable with promise const Callable c{}; QCOMPARE(createAsyncTask(std::cref(c), 2)->results(), QList({0, 0})); - // member functions with future interface + // member functions with promise auto member = &MyObject::member0; const MyObject obj{}; QCOMPARE(createAsyncTask(std::cref(member), &obj)->results(), QList({0, 2, 1})); } -template ::type> -typename AsyncTask::StartHandler startHandler(const Function &function, const Args &...args) -{ - return [=] { return Utils::runAsync(function, args...); }; -} - void tst_AsyncTask::futureSynchonizer() { - auto lambda = [](QFutureInterface &fi) { + auto lambda = [](QPromise &promise) { while (true) { - if (fi.isCanceled()) { - fi.reportCanceled(); - fi.reportFinished(); + if (promise.isCanceled()) { + promise.future().cancel(); + promise.finish(); return; } QThread::msleep(100); @@ -244,7 +272,7 @@ void tst_AsyncTask::futureSynchonizer() FutureSynchronizer synchronizer; { AsyncTask task; - task.setAsyncCallData(lambda); + task.setConcurrentCallData(lambda); task.setFutureSynchronizer(&synchronizer); task.start(); QThread::msleep(10); @@ -257,7 +285,7 @@ void tst_AsyncTask::futureSynchonizer() // The destructor of synchronizer should wait for about 90 ms for worker thread to be canceled } -void multiplyBy2(QFutureInterface &fi, int input) { fi.reportResult(input * 2); } +void multiplyBy2(QPromise &promise, int input) { promise.addResult(input * 2); } void tst_AsyncTask::taskTree() { @@ -266,7 +294,7 @@ void tst_AsyncTask::taskTree() int value = 1; const auto setupIntAsync = [&](AsyncTask &task) { - task.setAsyncCallData(multiplyBy2, value); + task.setConcurrentCallData(multiplyBy2, value); }; const auto handleIntAsync = [&](const AsyncTask &task) { value = task.result(); @@ -294,9 +322,9 @@ static int returnxx(int x) return x * x; } -static void returnxxWithFI(QFutureInterface &fi, int x) +static void returnxxWithPromise(QPromise &promise, int x) { - fi.reportResult(x * x); + promise.addResult(x * x); } static double s_sum = 0; @@ -315,13 +343,13 @@ void tst_AsyncTask::mapReduce_data() s_results.append(s_sum); }; const auto setupAsync = [](AsyncTask &task, int input) { - task.setAsyncCallData(returnxx, input); + task.setConcurrentCallData(returnxx, input); }; const auto setupAsyncWithFI = [](AsyncTask &task, int input) { - task.setAsyncCallData(returnxxWithFI, input); + task.setConcurrentCallData(returnxxWithPromise, input); }; const auto setupAsyncWithTP = [this](AsyncTask &task, int input) { - task.setAsyncCallData(returnxx, input); + task.setConcurrentCallData(returnxx, input); task.setThreadPool(&m_threadPool); }; const auto handleAsync = [](const AsyncTask &task) { @@ -377,7 +405,7 @@ void tst_AsyncTask::mapReduce_data() QTest::newRow("SequentialWithThreadPool") << sequentialRootWithTP << defaultSum << defaultResult; const auto setupSimpleAsync = [](AsyncTask &task, int input) { - task.setAsyncCallData([](int input) { return input * 2; }, input); + task.setConcurrentCallData([](int input) { return input * 2; }, input); }; const auto handleSimpleAsync = [](const AsyncTask &task) { s_sum += task.result() / 4.; @@ -393,7 +421,7 @@ void tst_AsyncTask::mapReduce_data() QTest::newRow("Simple") << simpleRoot << 3.0 << QList({.5, 1.5, 3.}); const auto setupStringAsync = [](AsyncTask &task, const QString &input) { - task.setAsyncCallData([](const QString &input) -> int { return input.size(); }, input); + task.setConcurrentCallData([](const QString &input) -> int { return input.size(); }, input); }; const auto handleStringAsync = [](const AsyncTask &task) { s_sum /= task.result(); From dce702596965735a5bc2bbf3adcf5e1c50f7b55f Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 20 Feb 2023 08:56:33 +0100 Subject: [PATCH 0055/1447] MarkdownView: Merge into TextEditor Make it a bit more compact, too. Change-Id: I448164371c5a1d6969a292feba17caa2826f58c3 Reviewed-by: Tasuku Suzuki Reviewed-by: Reviewed-by: David Schulz --- src/plugins/CMakeLists.txt | 1 - src/plugins/markdownviewer/CMakeLists.txt | 12 -- .../markdownviewer/MarkdownViewer.json.in | 18 --- .../markdownviewer/markdownbrowser.cpp | 32 ----- src/plugins/markdownviewer/markdownbrowser.h | 24 ---- .../markdownviewer/markdowndocument.cpp | 18 --- src/plugins/markdownviewer/markdowndocument.h | 19 --- src/plugins/markdownviewer/markdowneditor.cpp | 28 ----- src/plugins/markdownviewer/markdowneditor.h | 19 --- src/plugins/markdownviewer/markdownviewer.cpp | 86 -------------- src/plugins/markdownviewer/markdownviewer.h | 30 ----- src/plugins/markdownviewer/markdownviewer.qbs | 27 ----- .../markdownviewer/markdownviewerconstants.h | 17 --- .../markdownviewer/markdownviewerfactory.cpp | 22 ---- .../markdownviewer/markdownviewerplugin.cpp | 25 ---- .../markdownviewer/markdownviewerplugin.h | 26 ----- .../markdownviewer/markdownviewerwidget.cpp | 58 ---------- .../markdownviewer/markdownviewerwidget.h | 37 ------ src/plugins/plugins.qbs | 1 - src/plugins/texteditor/CMakeLists.txt | 1 + src/plugins/texteditor/markdowneditor.cpp | 109 ++++++++++++++++++ .../markdowneditor.h} | 10 +- src/plugins/texteditor/texteditor.qbs | 2 + src/plugins/texteditor/texteditorplugin.cpp | 2 + 24 files changed, 118 insertions(+), 506 deletions(-) delete mode 100644 src/plugins/markdownviewer/CMakeLists.txt delete mode 100644 src/plugins/markdownviewer/MarkdownViewer.json.in delete mode 100644 src/plugins/markdownviewer/markdownbrowser.cpp delete mode 100644 src/plugins/markdownviewer/markdownbrowser.h delete mode 100644 src/plugins/markdownviewer/markdowndocument.cpp delete mode 100644 src/plugins/markdownviewer/markdowndocument.h delete mode 100644 src/plugins/markdownviewer/markdowneditor.cpp delete mode 100644 src/plugins/markdownviewer/markdowneditor.h delete mode 100644 src/plugins/markdownviewer/markdownviewer.cpp delete mode 100644 src/plugins/markdownviewer/markdownviewer.h delete mode 100644 src/plugins/markdownviewer/markdownviewer.qbs delete mode 100644 src/plugins/markdownviewer/markdownviewerconstants.h delete mode 100644 src/plugins/markdownviewer/markdownviewerfactory.cpp delete mode 100644 src/plugins/markdownviewer/markdownviewerplugin.cpp delete mode 100644 src/plugins/markdownviewer/markdownviewerplugin.h delete mode 100644 src/plugins/markdownviewer/markdownviewerwidget.cpp delete mode 100644 src/plugins/markdownviewer/markdownviewerwidget.h create mode 100644 src/plugins/texteditor/markdowneditor.cpp rename src/plugins/{markdownviewer/markdownviewerfactory.h => texteditor/markdowneditor.h} (54%) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 4f224e73482..8c4f2e2bb68 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -6,7 +6,6 @@ add_subdirectory(texteditor) add_subdirectory(serialterminal) add_subdirectory(helloworld) add_subdirectory(imageviewer) -add_subdirectory(markdownviewer) add_subdirectory(marketplace) add_subdirectory(updateinfo) add_subdirectory(welcome) diff --git a/src/plugins/markdownviewer/CMakeLists.txt b/src/plugins/markdownviewer/CMakeLists.txt deleted file mode 100644 index c7f9d507857..00000000000 --- a/src/plugins/markdownviewer/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_qtc_plugin(MarkdownViewer - PLUGIN_DEPENDS Core TextEditor - SOURCES - markdownbrowser.cpp markdownbrowser.h - markdowndocument.cpp markdowndocument.h - markdowneditor.cpp markdowneditor.h - markdownviewer.cpp markdownviewer.h - markdownviewerconstants.h - markdownviewerfactory.cpp markdownviewerfactory.h - markdownviewerplugin.cpp markdownviewerplugin.h - markdownviewerwidget.cpp markdownviewerwidget.h -) diff --git a/src/plugins/markdownviewer/MarkdownViewer.json.in b/src/plugins/markdownviewer/MarkdownViewer.json.in deleted file mode 100644 index 4894a4bb8ba..00000000000 --- a/src/plugins/markdownviewer/MarkdownViewer.json.in +++ /dev/null @@ -1,18 +0,0 @@ -{ - \"Name\" : \"MarkdownViewer\", - \"Version\" : \"$$QTCREATOR_VERSION\", - \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", - \"Vendor\" : \"Signal Slot Inc.\", - \"Copyright\" : \"(C) 2023 Tasuku Suzuki\", - \"License\" : [ \"Commercial Usage\", - \"\", - \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", - \"\", - \"GNU General Public License Usage\", - \"\", - \"Alternatively, this plugin 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 plugin. 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.\" - ], - \"Description\" : \"Markdown Viewer component.\", - \"Url\" : \"https://signal-slot.co.jp/\", - $$dependencyList -} diff --git a/src/plugins/markdownviewer/markdownbrowser.cpp b/src/plugins/markdownviewer/markdownbrowser.cpp deleted file mode 100644 index 43f10e27ada..00000000000 --- a/src/plugins/markdownviewer/markdownbrowser.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "markdownbrowser.h" - -#include - -namespace Markdown { -namespace Internal { - -MarkdownBrowser::MarkdownBrowser(QWidget *parent) - : QTextBrowser(parent) -{} - -void MarkdownBrowser::setMarkdown(const QString &markdown) -{ - QHash positions; - const auto scrollBars = findChildren(); - - // save scroll positions - for (const auto scrollBar : scrollBars) - positions.insert(scrollBar, scrollBar->value()); - - QTextBrowser::setMarkdown(markdown); - - // restore scroll positions - for (auto scrollBar : scrollBars) - scrollBar->setValue(positions.value(scrollBar)); -} - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownbrowser.h b/src/plugins/markdownviewer/markdownbrowser.h deleted file mode 100644 index 6b71dcc533f..00000000000 --- a/src/plugins/markdownviewer/markdownbrowser.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Core { class IDocument; } - -namespace Markdown { -namespace Internal { - -class MarkdownBrowser : public QTextBrowser -{ - Q_OBJECT -public: - explicit MarkdownBrowser(QWidget *parent = nullptr); - -public slots: - void setMarkdown(const QString &markdown); -}; - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowndocument.cpp b/src/plugins/markdownviewer/markdowndocument.cpp deleted file mode 100644 index 20e5334b1b7..00000000000 --- a/src/plugins/markdownviewer/markdowndocument.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "markdowndocument.h" -#include "markdownviewerconstants.h" - -namespace Markdown { -namespace Internal { - -MarkdownDocument::MarkdownDocument() -{ - setId(Constants::MARKDOWNVIEWER_ID); - setMimeType(QLatin1String(Constants::MARKDOWNVIEWER_MIME_TYPE)); - connect(this, &MarkdownDocument::mimeTypeChanged, this, &MarkdownDocument::changed); -} - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowndocument.h b/src/plugins/markdownviewer/markdowndocument.h deleted file mode 100644 index 76a2bd8136b..00000000000 --- a/src/plugins/markdownviewer/markdowndocument.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Markdown { -namespace Internal { - -class MarkdownDocument : public TextEditor::TextDocument -{ - Q_OBJECT -public: - MarkdownDocument(); -}; - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowneditor.cpp b/src/plugins/markdownviewer/markdowneditor.cpp deleted file mode 100644 index f908add50e6..00000000000 --- a/src/plugins/markdownviewer/markdowneditor.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "markdowneditor.h" -#include "markdownviewerconstants.h" -#include "markdowndocument.h" - -#include -#include - -namespace Markdown { -namespace Internal { - -MarkdownEditor::MarkdownEditor(QWidget *parent) - : TextEditor::TextEditorWidget(parent) -{ - setTextDocument(TextEditor::TextDocumentPtr(new MarkdownDocument)); - setupGenericHighlighter(); - setMarksVisible(false); - - auto context = new Core::IContext(this); - context->setWidget(this); - context->setContext(Core::Context(Constants::MARKDOWNVIEWER_EDITOR_CONTEXT)); - Core::ICore::addContextObject(context); -} - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdowneditor.h b/src/plugins/markdownviewer/markdowneditor.h deleted file mode 100644 index f378309a6b7..00000000000 --- a/src/plugins/markdownviewer/markdowneditor.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Markdown { -namespace Internal { - -class MarkdownEditor : public TextEditor::TextEditorWidget -{ - Q_OBJECT -public: - MarkdownEditor(QWidget *parent = nullptr); -}; - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewer.cpp b/src/plugins/markdownviewer/markdownviewer.cpp deleted file mode 100644 index b3e21ce40fa..00000000000 --- a/src/plugins/markdownviewer/markdownviewer.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "markdownviewer.h" -#include "markdownviewerconstants.h" -#include "markdownviewerwidget.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace Markdown { -namespace Internal { - -struct MarkdownViewerPrivate -{ - MarkdownViewerWidget *widget; - QWidget *toolbar; - QToolButton *toggleEditorVisible; -}; - -MarkdownViewer::MarkdownViewer() - : d(new MarkdownViewerPrivate) -{ - ctor(); -} - -void MarkdownViewer::ctor() -{ - d->widget = new MarkdownViewerWidget; - - setContext(Core::Context(Constants::MARKDOWNVIEWER_ID)); - setWidget(d->widget); - - d->toolbar = new QWidget; - auto layout = new QHBoxLayout; - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - layout->addStretch(); - - d->toggleEditorVisible = new QToolButton; - d->toggleEditorVisible->setText(tr("Hide Editor")); - d->toggleEditorVisible->setCheckable(true); - d->toggleEditorVisible->setChecked(true); - layout->addWidget(d->toggleEditorVisible); - - d->toolbar->setLayout(layout); - - // connections - connect(d->toggleEditorVisible, &QToolButton::toggled, d->widget, &MarkdownViewerWidget::setEditorVisible); - connect(d->widget, &MarkdownViewerWidget::editorVisibleChanged, this, [this](bool editorVisible) { - d->toggleEditorVisible->setText(editorVisible ? tr("Hide Editor") : tr("Show Editor")); - }); -} - -MarkdownViewer::~MarkdownViewer() -{ - delete d->widget; - delete d->toolbar; - delete d; -} - -Core::IDocument *MarkdownViewer::document() const -{ - return d->widget->document(); -} - -QWidget *MarkdownViewer::toolBar() -{ - return d->toolbar; -} - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewer.h b/src/plugins/markdownviewer/markdownviewer.h deleted file mode 100644 index a29089a1e3f..00000000000 --- a/src/plugins/markdownviewer/markdownviewer.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include - -namespace Markdown { -namespace Internal { -class MarkdownDocument; - -class MarkdownViewer : public Core::IEditor -{ - Q_OBJECT -public: - explicit MarkdownViewer(); - ~MarkdownViewer() override; - - Core::IDocument *document() const override; - QWidget *toolBar() override; - -private: - void ctor(); - - struct MarkdownViewerPrivate *d; -}; - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewer.qbs b/src/plugins/markdownviewer/markdownviewer.qbs deleted file mode 100644 index 1a5bdbb7cd1..00000000000 --- a/src/plugins/markdownviewer/markdownviewer.qbs +++ /dev/null @@ -1,27 +0,0 @@ -import qbs 1.0 - -QtcPlugin { - name: "MarkdownViewer" - - Depends { name: "Qt.widgets" } - Depends { name: "Core" } - Depends { name: "TextEditor" } - - files: [ - "markdownbrowser.cpp", - "markdownbrowser.h", - "markdowndocument.cpp", - "markdowndocument.h", - "markdowneditor.cpp", - "markdowneditor.h", - "markdownviewer.cpp", - "markdownviewer.h", - "markdownviewerconstants.h", - "markdownviewerfactory.cpp", - "markdownviewerfactory.h", - "markdownviewerplugin.cpp", - "markdownviewerplugin.h", - "markdownviewerwidget.cpp", - "markdownviewerwidget.h", - ] -} diff --git a/src/plugins/markdownviewer/markdownviewerconstants.h b/src/plugins/markdownviewer/markdownviewerconstants.h deleted file mode 100644 index 45111743912..00000000000 --- a/src/plugins/markdownviewer/markdownviewerconstants.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Markdown { -namespace Constants { - -const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; -const char MARKDOWNVIEWER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Markdown Viewer"); -const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown"; -const char MARKDOWNVIEWER_EDITOR_CONTEXT[] = "Editors.MarkdownViewer.Id"; - -} // namespace Constants -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerfactory.cpp b/src/plugins/markdownviewer/markdownviewerfactory.cpp deleted file mode 100644 index 0e157b2ce6a..00000000000 --- a/src/plugins/markdownviewer/markdownviewerfactory.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "markdownviewerfactory.h" -#include "markdownviewerconstants.h" -#include "markdownviewer.h" - -#include - -namespace Markdown { -namespace Internal { - -MarkdownViewerFactory::MarkdownViewerFactory() -{ - setId(Constants::MARKDOWNVIEWER_ID); - setDisplayName(QCoreApplication::translate("OpenWith::Editors", Constants::MARKDOWNVIEWER_DISPLAY_NAME)); - addMimeType(Constants::MARKDOWNVIEWER_MIME_TYPE); - setEditorCreator([] { return new MarkdownViewer(); }); -} - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerplugin.cpp b/src/plugins/markdownviewer/markdownviewerplugin.cpp deleted file mode 100644 index db2c4965b31..00000000000 --- a/src/plugins/markdownviewer/markdownviewerplugin.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "markdownviewerplugin.h" -#include "markdownviewerfactory.h" - -#include - -using namespace Core; - -namespace Markdown { -namespace Internal { - -bool MarkdownViewerPlugin::initialize(const QStringList &arguments, QString *errorMessage) -{ - Q_UNUSED(arguments) - Q_UNUSED(errorMessage) - - ExtensionSystem::PluginManager::addObject(new MarkdownViewerFactory); - - return true; -} - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerplugin.h b/src/plugins/markdownviewer/markdownviewerplugin.h deleted file mode 100644 index f5d0305b0cd..00000000000 --- a/src/plugins/markdownviewer/markdownviewerplugin.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Markdown { -namespace Internal { - -class MarkdownViewerPlugin : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "MarkdownViewer.json") - -public: - MarkdownViewerPlugin() = default; - ~MarkdownViewerPlugin() = default; - -private: - bool initialize(const QStringList &arguments, QString *errorMessage) final; - void extensionsInitialized() final {} -}; - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerwidget.cpp b/src/plugins/markdownviewer/markdownviewerwidget.cpp deleted file mode 100644 index 8148be75908..00000000000 --- a/src/plugins/markdownviewer/markdownviewerwidget.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "markdownviewerwidget.h" -#include "markdowneditor.h" -#include "markdownbrowser.h" - -#include - -namespace Markdown { -namespace Internal { - -struct MarkdownViewerWidgetPrivate -{ - MarkdownBrowser *browser; - MarkdownEditor *editor; -}; - -MarkdownViewerWidget::MarkdownViewerWidget() - : d(new MarkdownViewerWidgetPrivate) -{ - d->browser = new MarkdownBrowser(this); - d->browser->setOpenExternalLinks(true); - d->browser->setFrameShape(QFrame::NoFrame); - d->editor = new MarkdownEditor(this); - - connect(d->editor->document(), &QTextDocument::contentsChanged, - this, [this]() { - const auto plainText = d->editor->textDocument()->plainText(); - d->browser->setMarkdown(plainText); - }); -} - -MarkdownViewerWidget::~MarkdownViewerWidget() -{ - delete d; -} - -Core::IDocument *MarkdownViewerWidget::document() const -{ - return d->editor->textDocument(); -} - -bool MarkdownViewerWidget::isEditorVisible() const -{ - return d->editor->isVisible(); -} - -void MarkdownViewerWidget::setEditorVisible(bool editorVisible) -{ - if (d->editor->isVisible() == editorVisible) - return; - d->editor->setVisible(editorVisible); - emit editorVisibleChanged(editorVisible); -} - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/markdownviewer/markdownviewerwidget.h b/src/plugins/markdownviewer/markdownviewerwidget.h deleted file mode 100644 index 16581c6cb54..00000000000 --- a/src/plugins/markdownviewer/markdownviewerwidget.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2023 Tasuku Suzuki -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include - -namespace Core { class IDocument; } - -namespace Markdown { -namespace Internal { - -class MarkdownViewerWidget : public Core::MiniSplitter -{ - Q_OBJECT - Q_PROPERTY(bool editorVisible READ isEditorVisible WRITE setEditorVisible NOTIFY editorVisibleChanged) -public: - explicit MarkdownViewerWidget(); - ~MarkdownViewerWidget() override; - - Core::IDocument *document() const; - - bool isEditorVisible() const; - -public slots: - void setEditorVisible(bool editorVisible); - -signals: - void editorVisibleChanged(bool editorVisible); - -private: - struct MarkdownViewerWidgetPrivate *d; -}; - -} // namespace Internal -} // namespace Markdown diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index f4c6060aaeb..b878e76c3e3 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -50,7 +50,6 @@ Project { "ios/ios.qbs", "languageclient/languageclient.qbs", "macros/macros.qbs", - "markdownviewer/markdownviewer.qbs", "marketplace/marketplace.qbs", "mcusupport/mcusupport.qbs", "mercurial/mercurial.qbs", diff --git a/src/plugins/texteditor/CMakeLists.txt b/src/plugins/texteditor/CMakeLists.txt index 01636fe7544..eebe8bf0bed 100644 --- a/src/plugins/texteditor/CMakeLists.txt +++ b/src/plugins/texteditor/CMakeLists.txt @@ -70,6 +70,7 @@ add_qtc_plugin(TextEditor ioutlinewidget.h linenumberfilter.cpp linenumberfilter.h marginsettings.cpp marginsettings.h + markdowneditor.cpp markdowneditor.h outlinefactory.cpp outlinefactory.h plaintexteditorfactory.cpp plaintexteditorfactory.h quickfix.cpp quickfix.h diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp new file mode 100644 index 00000000000..2778ecd3de8 --- /dev/null +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2023 Tasuku Suzuki +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "markdowneditor.h" + +#include "textdocument.h" +#include "texteditor.h" +#include "texteditortr.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace TextEditor::Internal { + +const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; +const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown"; +const char MARKDOWNVIEWER_EDITOR_CONTEXT[] = "Editors.MarkdownViewer.Id"; + +class MarkdownEditor : public Core::IEditor +{ +public: + MarkdownEditor() + : m_document(new TextDocument(MARKDOWNVIEWER_ID)) + { + m_document->setMimeType(MARKDOWNVIEWER_MIME_TYPE); + + // Left side + auto browser = new QTextBrowser(&m_widget); + browser->setOpenExternalLinks(true); + browser->setFrameShape(QFrame::NoFrame); + + // Right side (hidable) + auto editor = new TextEditorWidget(&m_widget); + editor->setTextDocument(m_document); + editor->setupGenericHighlighter(); + editor->setMarksVisible(false); + + auto context = new Core::IContext(this); + context->setWidget(editor); + context->setContext(Core::Context(MARKDOWNVIEWER_EDITOR_CONTEXT)); + Core::ICore::addContextObject(context); + + setContext(Core::Context(MARKDOWNVIEWER_ID)); + setWidget(&m_widget); + + auto toggleEditorVisible = new QToolButton; + toggleEditorVisible->setText(Tr::tr("Hide Editor")); + toggleEditorVisible->setCheckable(true); + toggleEditorVisible->setChecked(true); + + auto layout = new QHBoxLayout(&m_toolbar); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + layout->addStretch(); + layout->addWidget(toggleEditorVisible); + + connect(m_document.data(), &TextDocument::mimeTypeChanged, + m_document.data(), &TextDocument::changed); + + connect(toggleEditorVisible, &QToolButton::toggled, + editor, [editor, toggleEditorVisible](bool editorVisible) { + if (editor->isVisible() == editorVisible) + return; + editor->setVisible(editorVisible); + toggleEditorVisible->setText(editorVisible ? Tr::tr("Hide Editor") : Tr::tr("Show Editor")); + }); + + connect(m_document->document(), &QTextDocument::contentsChanged, this, [this, browser] { + QHash positions; + const auto scrollBars = findChildren(); + + // save scroll positions + for (QScrollBar *scrollBar : scrollBars) + positions.insert(scrollBar, scrollBar->value()); + + browser->setMarkdown(m_document->plainText()); + + // restore scroll positions + for (QScrollBar *scrollBar : scrollBars) + scrollBar->setValue(positions.value(scrollBar)); + }); + } + + QWidget *toolBar() override { return &m_toolbar; } + + Core::IDocument *document() const override { return m_document.data(); } + +private: + Core::MiniSplitter m_widget; + TextDocumentPtr m_document; + QWidget m_toolbar; +}; + +MarkdownEditorFactory::MarkdownEditorFactory() +{ + setId(MARKDOWNVIEWER_ID); + setDisplayName(::Core::Tr::tr("Markdown Viewer")); + addMimeType(MARKDOWNVIEWER_MIME_TYPE); + setEditorCreator([] { return new MarkdownEditor; }); +} + +} // TextEditor::Internal diff --git a/src/plugins/markdownviewer/markdownviewerfactory.h b/src/plugins/texteditor/markdowneditor.h similarity index 54% rename from src/plugins/markdownviewer/markdownviewerfactory.h rename to src/plugins/texteditor/markdowneditor.h index 294014945e7..21944657bc4 100644 --- a/src/plugins/markdownviewer/markdownviewerfactory.h +++ b/src/plugins/texteditor/markdowneditor.h @@ -5,14 +5,12 @@ #include -namespace Markdown { -namespace Internal { +namespace TextEditor::Internal { -class MarkdownViewerFactory final : public Core::IEditorFactory +class MarkdownEditorFactory final : public Core::IEditorFactory { public: - MarkdownViewerFactory(); + MarkdownEditorFactory(); }; -} // namespace Internal -} // namespace Markdown +} // TextEditor::Internal diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index 971ef31faee..2aacf5d3736 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -94,6 +94,8 @@ Project { "linenumberfilter.h", "marginsettings.cpp", "marginsettings.h", + "markdowneditor.cpp", + "markdowneditor.h", "outlinefactory.cpp", "outlinefactory.h", "plaintexteditorfactory.cpp", diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index e97453addae..a66ddf23c32 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -10,6 +10,7 @@ #include "highlighter.h" #include "icodestylepreferences.h" #include "linenumberfilter.h" +#include "markdowneditor.h" #include "outlinefactory.h" #include "plaintexteditorfactory.h" #include "snippets/snippetprovider.h" @@ -66,6 +67,7 @@ public: FindInOpenFiles findInOpenFilesFilter; PlainTextEditorFactory plainTextEditorFactory; + MarkdownEditorFactory markdownEditorFactory; }; static TextEditorPlugin *m_instance = nullptr; From 69ec9c43618f021a0146a1f23b13f18b827893d1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 20 Feb 2023 20:58:38 +0100 Subject: [PATCH 0056/1447] TaskTree: Add TreeStorage::operator*() Reuse it in some places. Change-Id: I335f38fa0384ea17bd8e981d743f835c3f05b731 Reviewed-by: Reviewed-by: hjk --- src/libs/utils/tasktree.h | 1 + src/plugins/clangtools/clangtoolrunner.cpp | 24 ++++++++++----------- src/plugins/diffeditor/diffeditorplugin.cpp | 2 +- src/plugins/git/gitclient.cpp | 6 +++--- src/plugins/mercurial/mercurialclient.cpp | 2 +- src/plugins/subversion/subversionclient.cpp | 2 +- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index b90e10c7c15..db1798affee 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -74,6 +74,7 @@ class TreeStorage : public TreeStorageBase { public: TreeStorage() : TreeStorageBase(TreeStorage::ctor(), TreeStorage::dtor()) {} + StorageStruct &operator*() const noexcept { return *activeStorage(); } StorageStruct *operator->() const noexcept { return activeStorage(); } StorageStruct *activeStorage() const { return static_cast(activeStorageVoid()); diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index f5c955c50e7..90bfe51ca30 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -111,11 +111,10 @@ TaskItem clangToolTask(const AnalyzeInputData &input, }; const TreeStorage storage; - const auto mainToolArguments = [=](const ClangToolStorage *data) - { + const auto mainToolArguments = [=](const ClangToolStorage &data) { QStringList result; - result << "-export-fixes=" + data->outputFilePath.nativePath(); - if (!input.overlayFilePath.isEmpty() && isVFSOverlaySupported(data->executable)) + result << "-export-fixes=" + data.outputFilePath.nativePath(); + if (!input.overlayFilePath.isEmpty() && isVFSOverlaySupported(data.executable)) result << "--vfsoverlay=" + input.overlayFilePath; result << input.unit.file.nativePath(); return result; @@ -147,13 +146,13 @@ TaskItem clangToolTask(const AnalyzeInputData &input, process.setLowPriority(); process.setWorkingDirectory(input.outputDirPath); // Current clang-cl puts log file into working dir. - const ClangToolStorage *data = storage.activeStorage(); + const ClangToolStorage &data = *storage; const QStringList args = checksArguments(input.tool, input.config) + mainToolArguments(data) + QStringList{"--"} + clangArguments(input.config, input.unit.arguments); - const CommandLine commandLine = {data->executable, args}; + const CommandLine commandLine = {data.executable, args}; qCDebug(LOG).noquote() << "Starting" << commandLine.toUserOutput(); process.setCommand(commandLine); @@ -162,8 +161,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, qCDebug(LOG).noquote() << "Output:\n" << process.cleanedStdOut(); if (!outputHandler) return; - const ClangToolStorage *data = storage.activeStorage(); - outputHandler({true, input.unit.file, data->outputFilePath, input.tool}); + outputHandler({true, input.unit.file, storage->outputFilePath, input.tool}); }; const auto onProcessError = [=](const QtcProcess &process) { if (!outputHandler) @@ -172,15 +170,15 @@ TaskItem clangToolTask(const AnalyzeInputData &input, .arg(process.commandLine().toUserOutput()) .arg(process.error()) .arg(process.cleanedStdOut()); - const ClangToolStorage *data = storage.activeStorage(); + const ClangToolStorage &data = *storage; QString message; if (process.result() == ProcessResult::StartFailed) - message = Tr::tr("An error occurred with the %1 process.").arg(data->name); + message = Tr::tr("An error occurred with the %1 process.").arg(data.name); else if (process.result() == ProcessResult::FinishedWithError) - message = Tr::tr("%1 finished with exit code: %2.").arg(data->name).arg(process.exitCode()); + message = Tr::tr("%1 finished with exit code: %2.").arg(data.name).arg(process.exitCode()); else - message = Tr::tr("%1 crashed.").arg(data->name); - outputHandler({false, input.unit.file, data->outputFilePath, input.tool, message, details}); + message = Tr::tr("%1 crashed.").arg(data.name); + outputHandler({false, input.unit.file, data.outputFilePath, input.tool, message, details}); }; const Group group { diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 2a813206657..29020755ea7 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -135,7 +135,7 @@ DiffFilesController::DiffFilesController(IDocument *document) taskTree.setupRoot(tasks); }; const auto onTreeDone = [this, storage] { - const QList> &results = *storage.activeStorage(); + const QList> &results = *storage; QList finalList; for (const std::optional &result : results) { if (result.has_value()) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index b25cc9af2f6..66f03aa974f 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -171,7 +171,7 @@ GitDiffEditorController::GitDiffEditorController(IDocument *document, VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); }; const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { - *diffInputStorage.activeStorage() = process.cleanedStdOut(); + *diffInputStorage = process.cleanedStdOut(); }; const Group root { @@ -258,7 +258,7 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin }; const auto onStagingDone = [storage, diffInputStorage] { - *diffInputStorage.activeStorage() = storage->m_stagedOutput + storage->m_unstagedOutput; + *diffInputStorage = storage->m_stagedOutput + storage->m_unstagedOutput; }; const Group root { @@ -455,7 +455,7 @@ ShowController::ShowController(IDocument *document, const QString &id) VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); }; const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { - *diffInputStorage.activeStorage() = process.cleanedStdOut(); + *diffInputStorage = process.cleanedStdOut(); }; const Group root { diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 43f942a1675..fd03bd2b2b6 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -60,7 +60,7 @@ MercurialDiffEditorController::MercurialDiffEditorController(IDocument *document VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); }; const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { - *diffInputStorage.activeStorage() = process.cleanedStdOut(); + *diffInputStorage = process.cleanedStdOut(); }; const Group root { diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index f496054da67..3602e1f4b83 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -203,7 +203,7 @@ SubversionDiffEditorController::SubversionDiffEditorController(IDocument *docume process.setCommand(command); }; const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { - *diffInputStorage.activeStorage() = process.cleanedStdOut(); + *diffInputStorage = process.cleanedStdOut(); }; const Group root { From 31fa792b5bc66f295e301c46825fe7d4d4fc0709 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 20 Feb 2023 20:33:59 +0100 Subject: [PATCH 0057/1447] TaskTree: Update inline comments Change-Id: I8a34eb0757fc6d6bf7589ced7a714bb6e564fd09 Reviewed-by: hjk --- src/libs/utils/tasktree.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index db1798affee..8a44b8a5b0e 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -87,20 +87,21 @@ private: } }; -// 4 policies: +// WorkflowPolicy: // 1. When all children finished with done -> report done, otherwise: // a) Report error on first error and stop executing other children (including their subtree) -// b) On first error - wait for all children to be finished and report error afterwards +// b) On first error - continue executing all children and report error afterwards // 2. When all children finished with error -> report error, otherwise: // a) Report done on first done and stop executing other children (including their subtree) -// b) On first done - wait for all children to be finished and report done afterwards +// b) On first done - continue executing all children and report done afterwards +// 3. Always run all children, ignore their result and report done afterwards enum class WorkflowPolicy { - StopOnError, // 1a - Will report error on any child error, otherwise done (if all children were done) - ContinueOnError, // 1b - the same. When no children it reports done. - StopOnDone, // 2a - Will report done on any child done, otherwise error (if all children were error) - ContinueOnDone, // 2b - the same. When no children it reports done. (?) - Optional // Returns always done after all children finished + StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done) + ContinueOnError, // 1b - The same, but children execution continues. When no children it reports done. + StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error) + ContinueOnDone, // 2b - The same, but children execution continues. When no children it reports done. (?) + Optional // 3 - Always reports done after all children finished }; enum class TaskAction From 625f0ef7262192ef9618740c2eeeebc4beedc463 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 20 Jan 2023 07:09:01 +0100 Subject: [PATCH 0058/1447] Copilot: Add LSP plugin for Copilot Fixes: QTCREATORBUG-27771 Change-Id: I1249b9a4492427208a70b3e21bf20ac668fc3c50 Reviewed-by: hjk --- src/plugins/CMakeLists.txt | 1 + src/plugins/copilot/CMakeLists.txt | 17 ++ src/plugins/copilot/Copilot.json.in | 19 ++ src/plugins/copilot/authwidget.cpp | 163 ++++++++++++++++++ src/plugins/copilot/authwidget.h | 44 +++++ src/plugins/copilot/copilot.qbs | 30 ++++ src/plugins/copilot/copilotclient.cpp | 133 ++++++++++++++ src/plugins/copilot/copilotclient.h | 53 ++++++ src/plugins/copilot/copilotoptionspage.cpp | 46 +++++ src/plugins/copilot/copilotoptionspage.h | 25 +++ .../copilot/copilotoptionspagewidget.cpp | 36 ++++ .../copilot/copilotoptionspagewidget.h | 16 ++ src/plugins/copilot/copilotplugin.cpp | 37 ++++ src/plugins/copilot/copilotplugin.h | 30 ++++ src/plugins/copilot/copilotsettings.cpp | 65 +++++++ src/plugins/copilot/copilotsettings.h | 21 +++ src/plugins/copilot/copilottr.h | 15 ++ src/plugins/copilot/documentwatcher.cpp | 92 ++++++++++ src/plugins/copilot/documentwatcher.h | 31 ++++ src/plugins/copilot/requests/checkstatus.h | 54 ++++++ src/plugins/copilot/requests/getcompletions.h | 120 +++++++++++++ src/plugins/copilot/requests/signinconfirm.h | 36 ++++ src/plugins/copilot/requests/signininitiate.h | 43 +++++ src/plugins/copilot/requests/signout.h | 26 +++ src/plugins/plugins.qbs | 1 + 25 files changed, 1154 insertions(+) create mode 100644 src/plugins/copilot/CMakeLists.txt create mode 100644 src/plugins/copilot/Copilot.json.in create mode 100644 src/plugins/copilot/authwidget.cpp create mode 100644 src/plugins/copilot/authwidget.h create mode 100644 src/plugins/copilot/copilot.qbs create mode 100644 src/plugins/copilot/copilotclient.cpp create mode 100644 src/plugins/copilot/copilotclient.h create mode 100644 src/plugins/copilot/copilotoptionspage.cpp create mode 100644 src/plugins/copilot/copilotoptionspage.h create mode 100644 src/plugins/copilot/copilotoptionspagewidget.cpp create mode 100644 src/plugins/copilot/copilotoptionspagewidget.h create mode 100644 src/plugins/copilot/copilotplugin.cpp create mode 100644 src/plugins/copilot/copilotplugin.h create mode 100644 src/plugins/copilot/copilotsettings.cpp create mode 100644 src/plugins/copilot/copilotsettings.h create mode 100644 src/plugins/copilot/copilottr.h create mode 100644 src/plugins/copilot/documentwatcher.cpp create mode 100644 src/plugins/copilot/documentwatcher.h create mode 100644 src/plugins/copilot/requests/checkstatus.h create mode 100644 src/plugins/copilot/requests/getcompletions.h create mode 100644 src/plugins/copilot/requests/signinconfirm.h create mode 100644 src/plugins/copilot/requests/signininitiate.h create mode 100644 src/plugins/copilot/requests/signout.h diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 8c4f2e2bb68..dc92077f0c1 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -100,3 +100,4 @@ add_subdirectory(qnx) add_subdirectory(webassembly) add_subdirectory(mcusupport) add_subdirectory(saferenderer) +add_subdirectory(copilot) diff --git a/src/plugins/copilot/CMakeLists.txt b/src/plugins/copilot/CMakeLists.txt new file mode 100644 index 00000000000..81e0cd34934 --- /dev/null +++ b/src/plugins/copilot/CMakeLists.txt @@ -0,0 +1,17 @@ +add_qtc_plugin(Copilot + SKIP_TRANSLATION + PLUGIN_DEPENDS Core LanguageClient + SOURCES + authwidget.cpp authwidget.h + copilotplugin.cpp copilotplugin.h + copilotclient.cpp copilotclient.h + copilotsettings.cpp copilotsettings.h + copilotoptionspage.cpp copilotoptionspage.h + copilotoptionspagewidget.cpp copilotoptionspagewidget.h + documentwatcher.cpp documentwatcher.h + requests/getcompletions.h + requests/checkstatus.h + requests/signout.h + requests/signininitiate.h + requests/signinconfirm.h +) diff --git a/src/plugins/copilot/Copilot.json.in b/src/plugins/copilot/Copilot.json.in new file mode 100644 index 00000000000..55ff6f6bf42 --- /dev/null +++ b/src/plugins/copilot/Copilot.json.in @@ -0,0 +1,19 @@ +{ + \"Name\" : \"Copilot\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"Experimental\" : true, + \"Vendor\" : \"The Qt Company Ltd\", + \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", + \"\", + \"GNU General Public License Usage\", + \"\", + \"Alternatively, this plugin 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 plugin. 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.\" + ], + \"Description\" : \"Copilot support\", + \"Url\" : \"http://www.qt.io\", + $$dependencyList +} diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp new file mode 100644 index 00000000000..9298bc66138 --- /dev/null +++ b/src/plugins/copilot/authwidget.cpp @@ -0,0 +1,163 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "authwidget.h" + +#include "copilotclient.h" +#include "copilottr.h" + +#include +#include + +#include + +#include +#include + +using namespace LanguageClient; + +namespace Copilot { + +bool isCopilotClient(Client *client) +{ + return dynamic_cast(client) != nullptr; +} + +Internal::CopilotClient *coPilotClient(Client *client) +{ + return static_cast(client); +} + +Internal::CopilotClient *findClient() +{ + return Internal::CopilotClient::instance(); +} + +AuthWidget::AuthWidget(QWidget *parent) + : QWidget(parent) +{ + using namespace Utils::Layouting; + + m_button = new QPushButton(); + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Small); + m_statusLabel = new QLabel(); + + // clang-format off + Column { + Row { + m_button, m_progressIndicator, st + }, + m_statusLabel + }.attachTo(this); + // clang-format on + + setState("Checking status ...", true); + + connect(LanguageClientManager::instance(), + &LanguageClientManager::clientAdded, + this, + &AuthWidget::onClientAdded); + + connect(m_button, &QPushButton::clicked, this, [this]() { + if (m_status == Status::SignedIn) + signOut(); + else if (m_status == Status::SignedOut) + signIn(); + }); + + auto client = findClient(); + + if (client) + checkStatus(client); +} + +void AuthWidget::setState(const QString &buttonText, bool working) +{ + m_button->setText(buttonText); + m_progressIndicator->setVisible(working); + m_statusLabel->setVisible(!m_statusLabel->text().isEmpty()); + m_button->setEnabled(!working); +} + +void AuthWidget::onClientAdded(LanguageClient::Client *client) +{ + if (isCopilotClient(client)) { + checkStatus(coPilotClient(client)); + } +} + +void AuthWidget::checkStatus(Internal::CopilotClient *client) +{ + client->requestCheckStatus(false, [this](const CheckStatusRequest::Response &response) { + if (response.error()) { + setState("failed: " + response.error()->message(), false); + return; + } + const CheckStatusResponse result = *response.result(); + + if (result.user().isEmpty()) { + setState("Sign in", false); + m_status = Status::SignedOut; + return; + } + + setState("Sign out " + result.user(), false); + m_status = Status::SignedIn; + }); +} + +void AuthWidget::signIn() +{ + qCritical() << "Not implemented"; + auto client = findClient(); + QTC_ASSERT(client, return); + + setState("Signing in ...", true); + + client->requestSignInInitiate([this, client](const SignInInitiateRequest::Response &response) { + QTC_ASSERT(!response.error(), return); + + Utils::setClipboardAndSelection(response.result()->userCode()); + + QDesktopServices::openUrl(QUrl(response.result()->verificationUri())); + + m_statusLabel->setText(Tr::tr("A browser window will open, enter the code %1 when " + "asked.\nThe code has been copied to your clipboard.") + .arg(response.result()->userCode())); + m_statusLabel->setVisible(true); + + client->requestSignInConfirm(response.result()->userCode(), + [this](const SignInConfirmRequest::Response &response) { + m_statusLabel->setText(""); + + if (response.error()) { + QMessageBox::critical(this, + Tr::tr("Login failed"), + Tr::tr( + "The login request failed: ") + + response.error()->message()); + setState("Sign in", false); + return; + } + + setState("Sign Out " + response.result()->user(), false); + }); + }); +} + +void AuthWidget::signOut() +{ + auto client = findClient(); + QTC_ASSERT(client, return); + + setState("Signing out ...", true); + + client->requestSignOut([this, client](const SignOutRequest::Response &response) { + QTC_ASSERT(!response.error(), return); + QTC_ASSERT(response.result()->status() == "NotSignedIn", return); + + checkStatus(client); + }); +} + +} // namespace Copilot diff --git a/src/plugins/copilot/authwidget.h b/src/plugins/copilot/authwidget.h new file mode 100644 index 00000000000..9d0f8fdbbcf --- /dev/null +++ b/src/plugins/copilot/authwidget.h @@ -0,0 +1,44 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "copilotclient.h" + +#include + +#include +#include +#include + +namespace LanguageClient { +class Client; +} + +namespace Copilot { + +class AuthWidget : public QWidget +{ + Q_OBJECT + + enum class Status { SignedIn, SignedOut, Unknown }; + +public: + explicit AuthWidget(QWidget *parent = nullptr); + +private: + void onClientAdded(LanguageClient::Client *client); + void setState(const QString &buttonText, bool working); + void checkStatus(Internal::CopilotClient *client); + + void signIn(); + void signOut(); + +private: + Status m_status = Status::Unknown; + QPushButton *m_button = nullptr; + QLabel *m_statusLabel = nullptr; + Utils::ProgressIndicator *m_progressIndicator = nullptr; +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs new file mode 100644 index 00000000000..fecc4be4997 --- /dev/null +++ b/src/plugins/copilot/copilot.qbs @@ -0,0 +1,30 @@ +import qbs 1.0 + +QtcPlugin { + name: "Copilot" + + Depends { name: "Core" } + Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] } + + files: [ + "authwidget.cpp", + "authwidget.h", + "copilotplugin.cpp", + "copilotplugin.h", + "copilotclient.cpp", + "copilotclient.h", + "copilotsettings.cpp", + "copilotsettings.h", + "copilotoptionspage.cpp", + "copilotoptionspage.h", + "copilotoptionspagewidget.cpp", + "copilotoptionspagewidget.h", + "documentwatcher.cpp", + "documentwatcher.h", + "requests/getcompletions.h", + "requests/checkstatus.h", + "requests/signout.h", + "requests/signininitiate.h", + "requests/signinconfirm.h", + ] +} diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp new file mode 100644 index 00000000000..de4653fcbd5 --- /dev/null +++ b/src/plugins/copilot/copilotclient.cpp @@ -0,0 +1,133 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "copilotclient.h" + +#include "copilotsettings.h" +#include "documentwatcher.h" + +#include +#include +#include + +#include + +#include + +using namespace Utils; + +namespace Copilot::Internal { + +static LanguageClient::BaseClientInterface *clientInterface() +{ + const FilePath nodePath = CopilotSettings::instance().nodeJsPath.filePath(); + const FilePath distPath = CopilotSettings::instance().distPath.filePath(); + + CommandLine cmd{nodePath, {distPath.toFSPathString()}}; + + const auto interface = new LanguageClient::StdIOClientInterface; + interface->setCommandLine(cmd); + return interface; +} + +static CopilotClient *currentInstance = nullptr; + +CopilotClient *CopilotClient::instance() +{ + return currentInstance; +} + +CopilotClient::CopilotClient() + : LanguageClient::Client(clientInterface()) +{ + setName("Copilot"); + LanguageClient::LanguageFilter langFilter; + + langFilter.filePattern = {"*"}; + + setSupportedLanguage(langFilter); + start(); + + connect(Core::EditorManager::instance(), + &Core::EditorManager::documentOpened, + this, + [this](Core::IDocument *document) { + TextEditor::TextDocument *textDocument = qobject_cast( + document); + if (!textDocument) + return; + + openDocument(textDocument); + + m_documentWatchers.emplace(textDocument->filePath(), + std::make_unique(this, textDocument)); + }); + + connect(Core::EditorManager::instance(), + &Core::EditorManager::documentClosed, + this, + [this](Core::IDocument *document) { + auto textDocument = qobject_cast(document); + if (!textDocument) + return; + + closeDocument(textDocument); + m_documentWatchers.erase(textDocument->filePath()); + }); + + currentInstance = this; +} + +void CopilotClient::requestCompletion( + const Utils::FilePath &path, + int version, + LanguageServerProtocol::Position position, + std::function callback) +{ + GetCompletionRequest request{ + {LanguageServerProtocol::TextDocumentIdentifier(hostPathToServerUri(path)), + version, + position}}; + request.setResponseCallback(callback); + + sendMessage(request); +} + +void CopilotClient::requestCheckStatus( + bool localChecksOnly, std::function callback) +{ + CheckStatusRequest request{localChecksOnly}; + request.setResponseCallback(callback); + + sendMessage(request); +} + +void CopilotClient::requestSignOut( + std::function callback) +{ + SignOutRequest request; + request.setResponseCallback(callback); + + sendMessage(request); +} + +void CopilotClient::requestSignInInitiate( + std::function callback) +{ + SignInInitiateRequest request; + request.setResponseCallback(callback); + + sendMessage(request); +} + +void CopilotClient::requestSignInConfirm( + const QString &userCode, + std::function callback) +{ + SignInConfirmRequest request(userCode); + request.setResponseCallback(callback); + + sendMessage(request); +} + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h new file mode 100644 index 00000000000..7521fc73b7b --- /dev/null +++ b/src/plugins/copilot/copilotclient.h @@ -0,0 +1,53 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "requests/checkstatus.h" +#include "requests/getcompletions.h" +#include "requests/signinconfirm.h" +#include "requests/signininitiate.h" +#include "requests/signout.h" + +#include + +#include + +#include +#include + +namespace Copilot::Internal { + +class DocumentWatcher; + +class CopilotClient : public LanguageClient::Client +{ +public: + explicit CopilotClient(); + + static CopilotClient *instance(); + + void requestCompletion( + const Utils::FilePath &path, + int version, + LanguageServerProtocol::Position position, + std::function callback); + + void requestCheckStatus( + bool localChecksOnly, + std::function callback); + + void requestSignOut(std::function callback); + + void requestSignInInitiate( + std::function callback); + + void requestSignInConfirm( + const QString &userCode, + std::function callback); + +private: + std::map> m_documentWatchers; +}; + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp new file mode 100644 index 00000000000..67866fe8794 --- /dev/null +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "copilotoptionspage.h" + +#include "copilotoptionspagewidget.h" +#include "copilotsettings.h" + +#include + +namespace Copilot { + +CopilotOptionsPage::CopilotOptionsPage() +{ + setId("Copilot.General"); + setDisplayName("Copilot"); + setCategory("ZY.Copilot"); + setDisplayCategory("Copilot"); + + setCategoryIconPath(":/languageclient/images/settingscategory_languageclient.png"); +} + +CopilotOptionsPage::~CopilotOptionsPage() {} + +void CopilotOptionsPage::init() {} + +QWidget *CopilotOptionsPage::widget() +{ + return new CopilotOptionsPageWidget(); +} + +void CopilotOptionsPage::apply() +{ + CopilotSettings::instance().apply(); + CopilotSettings::instance().writeSettings(Core::ICore::settings()); +} + +void CopilotOptionsPage::finish() {} + +CopilotOptionsPage &CopilotOptionsPage::instance() +{ + static CopilotOptionsPage settingsPage; + return settingsPage; +} + +} // namespace Copilot diff --git a/src/plugins/copilot/copilotoptionspage.h b/src/plugins/copilot/copilotoptionspage.h new file mode 100644 index 00000000000..1124f74dea6 --- /dev/null +++ b/src/plugins/copilot/copilotoptionspage.h @@ -0,0 +1,25 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Copilot { + +class CopilotOptionsPage : public Core::IOptionsPage +{ +public: + CopilotOptionsPage(); + ~CopilotOptionsPage() override; + + static CopilotOptionsPage &instance(); + + void init(); + + QWidget *widget() override; + void apply() override; + void finish() override; +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/copilotoptionspagewidget.cpp b/src/plugins/copilot/copilotoptionspagewidget.cpp new file mode 100644 index 00000000000..549ea7f9ec6 --- /dev/null +++ b/src/plugins/copilot/copilotoptionspagewidget.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "copilotoptionspagewidget.h" + +#include "authwidget.h" +#include "copilotsettings.h" + +#include +#include + +using namespace Utils; +using namespace LanguageClient; + +namespace Copilot { + +CopilotOptionsPageWidget::CopilotOptionsPageWidget(QWidget *parent) + : QWidget(parent) +{ + using namespace Layouting; + + auto authWdgt = new AuthWidget(); + + // clang-format off + Column { + authWdgt, br, + CopilotSettings::instance().nodeJsPath, br, + CopilotSettings::instance().distPath, br, + st + }.attachTo(this); + // clang-format on +} + +CopilotOptionsPageWidget::~CopilotOptionsPageWidget() = default; + +} // namespace Copilot diff --git a/src/plugins/copilot/copilotoptionspagewidget.h b/src/plugins/copilot/copilotoptionspagewidget.h new file mode 100644 index 00000000000..37c51e68d3c --- /dev/null +++ b/src/plugins/copilot/copilotoptionspagewidget.h @@ -0,0 +1,16 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Copilot { +class CopilotOptionsPageWidget : public QWidget +{ + Q_OBJECT +public: + CopilotOptionsPageWidget(QWidget *parent = nullptr); + ~CopilotOptionsPageWidget() override; +}; +} // namespace Copilot diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp new file mode 100644 index 00000000000..ff2c449088f --- /dev/null +++ b/src/plugins/copilot/copilotplugin.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "copilotplugin.h" + +#include "copilotclient.h" +#include "copilotoptionspage.h" +#include "copilotsettings.h" + +#include + +using namespace Utils; + +namespace Copilot { +namespace Internal { + +void CopilotPlugin::initialize() +{ + CopilotSettings::instance().readSettings(Core::ICore::settings()); + + m_client = new CopilotClient(); + + connect(&CopilotSettings::instance(), &CopilotSettings::applied, this, [this]() { + if (m_client) + m_client->shutdown(); + m_client = nullptr; + m_client = new CopilotClient(); + }); +} + +void CopilotPlugin::extensionsInitialized() +{ + CopilotOptionsPage::instance().init(); +} + +} // namespace Internal +} // namespace Copilot diff --git a/src/plugins/copilot/copilotplugin.h b/src/plugins/copilot/copilotplugin.h new file mode 100644 index 00000000000..62f1d21f753 --- /dev/null +++ b/src/plugins/copilot/copilotplugin.h @@ -0,0 +1,30 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "copilotclient.h" + +#include + +namespace Copilot { +namespace Internal { + +class CopilotPlugin : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Copilot.json") + +public: + CopilotPlugin() {} + ~CopilotPlugin() override {} + + void initialize() override; + void extensionsInitialized() override; + +private: + CopilotClient *m_client; +}; + +} // namespace Internal +} // namespace Copilot diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp new file mode 100644 index 00000000000..ed298a0ab78 --- /dev/null +++ b/src/plugins/copilot/copilotsettings.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "copilotsettings.h" +#include "copilottr.h" + +#include +#include + +using namespace Utils; + +namespace Copilot { + +CopilotSettings &CopilotSettings::instance() +{ + static CopilotSettings settings; + return settings; +} + +CopilotSettings::CopilotSettings() +{ + setAutoApply(false); + + const FilePath nodeFromPath = FilePath("node").searchInPath(); + + const FilePaths searchDirs + = {FilePath::fromUserInput("~/.vim/pack/github/start/copilot.vim/copilot/dist/agent.js"), + FilePath::fromUserInput( + "~/.config/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js"), + FilePath::fromUserInput( + "~/vimfiles/pack/github/start/copilot.vim/copilot/dist/agent.js"), + FilePath::fromUserInput( + "~/AppData/Local/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js")}; + + const FilePath distFromVim = Utils::findOrDefault(searchDirs, [](const FilePath &fp) { + return fp.exists(); + }); + + nodeJsPath.setExpectedKind(PathChooser::ExistingCommand); + nodeJsPath.setDefaultFilePath(nodeFromPath); + nodeJsPath.setSettingsKey("Copilot.NodeJsPath"); + nodeJsPath.setDisplayStyle(StringAspect::PathChooserDisplay); + nodeJsPath.setLabelText(Tr::tr("Node.js path:")); + nodeJsPath.setHistoryCompleter("Copilot.NodePath.History"); + nodeJsPath.setDisplayName(Tr::tr("Node.js Path")); + nodeJsPath.setToolTip( + Tr::tr("Select path to node.js executable. See https://nodejs.org/de/download/" + "for installation instructions.")); + + distPath.setExpectedKind(PathChooser::File); + distPath.setDefaultFilePath(distFromVim); + distPath.setSettingsKey("Copilot.DistPath"); + distPath.setDisplayStyle(StringAspect::PathChooserDisplay); + distPath.setLabelText(Tr::tr("Path to agent.js:")); + distPath.setToolTip(Tr::tr( + "Select path to agent.js in copilot neovim plugin. See " + "https://github.com/github/copilot.vim#getting-started for installation instructions.")); + distPath.setHistoryCompleter("Copilot.DistPath.History"); + distPath.setDisplayName(Tr::tr("Agent.js path")); + + registerAspect(&nodeJsPath); + registerAspect(&distPath); +} + +} // namespace Copilot diff --git a/src/plugins/copilot/copilotsettings.h b/src/plugins/copilot/copilotsettings.h new file mode 100644 index 00000000000..d089410216b --- /dev/null +++ b/src/plugins/copilot/copilotsettings.h @@ -0,0 +1,21 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Copilot { + +class CopilotSettings : public Utils::AspectContainer +{ +public: + CopilotSettings(); + + static CopilotSettings &instance(); + + Utils::StringAspect nodeJsPath; + Utils::StringAspect distPath; +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/copilottr.h b/src/plugins/copilot/copilottr.h new file mode 100644 index 00000000000..a25a534f0d3 --- /dev/null +++ b/src/plugins/copilot/copilottr.h @@ -0,0 +1,15 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Copilot { + +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(::Copilot) +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/documentwatcher.cpp b/src/plugins/copilot/documentwatcher.cpp new file mode 100644 index 00000000000..f216826b44e --- /dev/null +++ b/src/plugins/copilot/documentwatcher.cpp @@ -0,0 +1,92 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "documentwatcher.h" + +#include + +#include + +#include + +using namespace LanguageServerProtocol; +using namespace TextEditor; + +namespace Copilot::Internal { + +DocumentWatcher::DocumentWatcher(CopilotClient *client, TextDocument *textDocument) + : m_client(client) + , m_textDocument(textDocument) +{ + m_lastContentSize = m_textDocument->document()->characterCount(); //toPlainText().size(); + m_debounceTimer.setInterval(500); + m_debounceTimer.setSingleShot(true); + + connect(textDocument, &TextDocument::contentsChanged, this, [this]() { + if (!m_isEditing) { + const int newSize = m_textDocument->document()->characterCount(); + if (m_lastContentSize < newSize) { + m_debounceTimer.start(); + } + m_lastContentSize = newSize; + } + }); + + connect(&m_debounceTimer, &QTimer::timeout, this, [this]() { getSuggestion(); }); +} + +void DocumentWatcher::getSuggestion() +{ + auto editor = Core::EditorManager::instance()->activateEditorForDocument(m_textDocument); + auto textEditorWidget = qobject_cast(editor->widget()); + if (!editor || !textEditorWidget) + return; + + auto cursor = textEditorWidget->multiTextCursor(); + if (cursor.hasMultipleCursors() || cursor.hasSelection()) + return; + + const int currentCursorPos = cursor.cursors().first().position(); + + m_client->requestCompletion( + m_textDocument->filePath(), + m_client->documentVersion(m_textDocument->filePath()), + Position(editor->currentLine() - 1, editor->currentColumn() - 1), + [this, textEditorWidget, currentCursorPos](const GetCompletionRequest::Response &response) { + if (response.error()) { + qDebug() << "ERROR:" << *response.error(); + return; + } + + const std::optional result = response.result(); + QTC_ASSERT(result, return); + + const auto list = result->completions().toList(); + + if (list.isEmpty()) + return; + + auto cursor = textEditorWidget->multiTextCursor(); + if (cursor.hasMultipleCursors() || cursor.hasSelection()) + return; + if (cursor.cursors().first().position() != currentCursorPos) + return; + + const auto firstCompletion = list.first(); + const QString content = firstCompletion.text().mid( + firstCompletion.position().character()); + + m_isEditing = true; + textEditorWidget->insertSuggestion(content); + m_isEditing = false; + /* + m_isEditing = true; + const auto &block = m_textDocument->document()->findBlockByLineNumber( + firstCompletion.position().line()); + m_textDocument->insertSuggestion(content, block); + m_isEditing = false; + */ + }); +} + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/documentwatcher.h b/src/plugins/copilot/documentwatcher.h new file mode 100644 index 00000000000..868be7956d4 --- /dev/null +++ b/src/plugins/copilot/documentwatcher.h @@ -0,0 +1,31 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "copilotclient.h" + +#include + +#include + +namespace Copilot::Internal { + +class DocumentWatcher : public QObject +{ + Q_OBJECT +public: + explicit DocumentWatcher(CopilotClient *client, TextEditor::TextDocument *textDocument); + + void getSuggestion(); + +private: + CopilotClient *m_client; + TextEditor::TextDocument *m_textDocument; + + QTimer m_debounceTimer; + bool m_isEditing = false; + int m_lastContentSize = 0; +}; + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/requests/checkstatus.h b/src/plugins/copilot/requests/checkstatus.h new file mode 100644 index 00000000000..20e77eb1457 --- /dev/null +++ b/src/plugins/copilot/requests/checkstatus.h @@ -0,0 +1,54 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace Copilot { + +class CheckStatusParams : public LanguageServerProtocol::JsonObject +{ + static constexpr char16_t optionsKey[] = u"options"; + static constexpr char16_t localChecksOnlyKey[] = u"options"; + +public: + using JsonObject::JsonObject; + + CheckStatusParams(bool localChecksOnly = false) { setLocalChecksOnly(localChecksOnly); } + + void setLocalChecksOnly(bool localChecksOnly) + { + QJsonObject options; + options.insert(localChecksOnlyKey, localChecksOnly); + setOptions(options); + } + + void setOptions(QJsonObject options) { insert(optionsKey, options); } +}; + +class CheckStatusResponse : public LanguageServerProtocol::JsonObject +{ + static constexpr char16_t userKey[] = u"user"; + static constexpr char16_t statusKey[] = u"status"; + +public: + using JsonObject::JsonObject; + + QString status() const { return typedValue(statusKey); } + QString user() const { return typedValue(userKey); } +}; + +class CheckStatusRequest + : public LanguageServerProtocol::Request +{ +public: + explicit CheckStatusRequest(const CheckStatusParams ¶ms) + : Request(methodName, params) + {} + using Request::Request; + constexpr static const char methodName[] = "checkStatus"; +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/requests/getcompletions.h b/src/plugins/copilot/requests/getcompletions.h new file mode 100644 index 00000000000..6a503071d8a --- /dev/null +++ b/src/plugins/copilot/requests/getcompletions.h @@ -0,0 +1,120 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include +#include + +namespace Copilot { + +class Completion : public LanguageServerProtocol::JsonObject +{ + static constexpr char16_t displayTextKey[] = u"displayText"; + static constexpr char16_t uuidKey[] = u"uuid"; + +public: + using JsonObject::JsonObject; + + QString displayText() const { return typedValue(displayTextKey); } + LanguageServerProtocol::Position position() const + { + return typedValue(LanguageServerProtocol::positionKey); + } + LanguageServerProtocol::Range range() const + { + return typedValue(LanguageServerProtocol::rangeKey); + } + QString text() const { return typedValue(LanguageServerProtocol::textKey); } + QString uuid() const { return typedValue(uuidKey); } + + bool isValid() const override + { + return contains(LanguageServerProtocol::textKey) + && contains(LanguageServerProtocol::rangeKey) + && contains(LanguageServerProtocol::positionKey); + } +}; + +class GetCompletionParams : public LanguageServerProtocol::JsonObject +{ +public: + static constexpr char16_t docKey[] = u"doc"; + + GetCompletionParams(); + GetCompletionParams(const LanguageServerProtocol::TextDocumentIdentifier &document, + int version, + const LanguageServerProtocol::Position &position) + { + setTextDocument(document); + setVersion(version); + setPosition(position); + } + using JsonObject::JsonObject; + + // The text document. + LanguageServerProtocol::TextDocumentIdentifier textDocument() const + { + return typedValue(docKey); + } + void setTextDocument(const LanguageServerProtocol::TextDocumentIdentifier &id) + { + insert(docKey, id); + } + + // The position inside the text document. + LanguageServerProtocol::Position position() const + { + return LanguageServerProtocol::fromJsonValue( + value(docKey).toObject().value(LanguageServerProtocol::positionKey)); + } + void setPosition(const LanguageServerProtocol::Position &position) + { + QJsonObject result = value(docKey).toObject(); + result[LanguageServerProtocol::positionKey] = (QJsonObject) position; + insert(docKey, result); + } + + // The version + int version() const { return typedValue(LanguageServerProtocol::versionKey); } + void setVersion(int version) + { + QJsonObject result = value(docKey).toObject(); + result[LanguageServerProtocol::versionKey] = version; + insert(docKey, result); + } + + bool isValid() const override + { + return contains(docKey) + && value(docKey).toObject().contains(LanguageServerProtocol::positionKey) + && value(docKey).toObject().contains(LanguageServerProtocol::versionKey); + } +}; + +class GetCompletionResponse : public LanguageServerProtocol::JsonObject +{ + static constexpr char16_t completionKey[] = u"completions"; + +public: + using JsonObject::JsonObject; + + LanguageServerProtocol::LanguageClientArray completions() const + { + return clientArray(completionKey); + } +}; + +class GetCompletionRequest + : public LanguageServerProtocol::Request +{ +public: + explicit GetCompletionRequest(const GetCompletionParams ¶ms) + : Request(methodName, params) + {} + using Request::Request; + constexpr static const char methodName[] = "getCompletionsCycling"; +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/requests/signinconfirm.h b/src/plugins/copilot/requests/signinconfirm.h new file mode 100644 index 00000000000..64f4ce7d53d --- /dev/null +++ b/src/plugins/copilot/requests/signinconfirm.h @@ -0,0 +1,36 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "checkstatus.h" + +#include +#include + +namespace Copilot { + +class SignInConfirmParams : public LanguageServerProtocol::JsonObject +{ + static constexpr char16_t userCodeKey[] = u"userCode"; + +public: + using JsonObject::JsonObject; + + SignInConfirmParams(const QString &userCode) { setUserCode(userCode); } + + void setUserCode(const QString &userCode) { insert(userCodeKey, userCode); } +}; + +class SignInConfirmRequest + : public LanguageServerProtocol::Request +{ +public: + explicit SignInConfirmRequest(const QString &userCode) + : Request(methodName, {userCode}) + {} + using Request::Request; + constexpr static const char methodName[] = "signInConfirm"; +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/requests/signininitiate.h b/src/plugins/copilot/requests/signininitiate.h new file mode 100644 index 00000000000..005205e6e01 --- /dev/null +++ b/src/plugins/copilot/requests/signininitiate.h @@ -0,0 +1,43 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace Copilot { + +using SignInInitiateParams = LanguageServerProtocol::JsonObject; + +class SignInInitiateResponse : public LanguageServerProtocol::JsonObject +{ + static constexpr char16_t verificationUriKey[] = u"verificationUri"; + static constexpr char16_t userCodeKey[] = u"userCode"; + +public: + using JsonObject::JsonObject; + +public: + QString verificationUri() const { return typedValue(verificationUriKey); } + QString userCode() const { return typedValue(userCodeKey); } +}; + +class SignInInitiateRequest : public LanguageServerProtocol::Request +{ +public: + explicit SignInInitiateRequest() + : Request(methodName, {}) + {} + using Request::Request; + constexpr static const char methodName[] = "signInInitiate"; +}; + +} // namespace Copilot diff --git a/src/plugins/copilot/requests/signout.h b/src/plugins/copilot/requests/signout.h new file mode 100644 index 00000000000..944c10d414b --- /dev/null +++ b/src/plugins/copilot/requests/signout.h @@ -0,0 +1,26 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "checkstatus.h" + +#include +#include + +namespace Copilot { + +using SignOutParams = LanguageServerProtocol::JsonObject; + +class SignOutRequest + : public LanguageServerProtocol::Request +{ +public: + explicit SignOutRequest() + : Request(methodName, {}) + {} + using Request::Request; + constexpr static const char methodName[] = "signOut"; +}; + +} // namespace Copilot diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index b878e76c3e3..c38d0d8123c 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -85,5 +85,6 @@ Project { "vcsbase/vcsbase.qbs", "webassembly/webassembly.qbs", "welcome/welcome.qbs" + "copilot/copilot.qbs" ].concat(project.additionalPlugins) } From 607118f8ae8e0def62af3f410db29801a69a15d6 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 21 Feb 2023 11:08:07 +0100 Subject: [PATCH 0059/1447] QmakeProjectManager: Remove unused declaration Change-Id: I187538270bdcb9288d63e7ae73944101552e3485 Reviewed-by: Marcus Tillmanns --- src/plugins/qmakeprojectmanager/qmakenodes.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 778f84b64fd..7dc1133fd0c 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -12,7 +12,6 @@ namespace QmakeProjectManager { class QmakeProFileNode; -class QmakeProject; // Implements ProjectNode for qmake .pri files class QMAKEPROJECTMANAGER_EXPORT QmakePriFileNode : public ProjectExplorer::ProjectNode From 84ab58dfefb26b98d44e281d16ff82594bbfe2b3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 21 Feb 2023 13:03:37 +0100 Subject: [PATCH 0060/1447] Fix qbs build Change-Id: I44e6c9318dcc591ae08f0958bd4b659e0f79fa75 Reviewed-by: Christian Stenger --- src/plugins/plugins.qbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index c38d0d8123c..5ce3a8fa9a1 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -23,6 +23,7 @@ Project { "coco/coco.qbs", "compilationdatabaseprojectmanager/compilationdatabaseprojectmanager.qbs", "conan/conan.qbs", + "copilot/copilot.qbs", "coreplugin/coreplugin.qbs", "coreplugin/images/logo/logo.qbs", "cpaster/cpaster.qbs", @@ -84,7 +85,6 @@ Project { "valgrind/valgrind.qbs", "vcsbase/vcsbase.qbs", "webassembly/webassembly.qbs", - "welcome/welcome.qbs" - "copilot/copilot.qbs" + "welcome/welcome.qbs", ].concat(project.additionalPlugins) } From 60a8ecd1b0fd1bd9b8956e7037eb39f9471863e2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Feb 2023 01:00:58 +0100 Subject: [PATCH 0061/1447] ExtraCompiler: Use QPromise for async calls Change-Id: I810603da8ccee4618ca02f29682fa5f8abe9d33e Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- src/plugins/projectexplorer/extracompiler.cpp | 62 +++++++++---------- src/plugins/projectexplorer/extracompiler.h | 4 +- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index ab72d3608ff..ffa0c494e9c 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -17,11 +17,11 @@ #include #include -#include #include #include #include +using namespace Core; using namespace Utils; namespace ProjectExplorer { @@ -37,10 +37,10 @@ public: FilePath source; FileNameToContentsHash contents; QDateTime compileTime; - Core::IEditor *lastEditor = nullptr; + IEditor *lastEditor = nullptr; QMetaObject::Connection activeBuildConfigConnection; QMetaObject::Connection activeEnvironmentConnection; - Utils::Guard lock; + Guard lock; bool dirty = false; QTimer timer; @@ -69,10 +69,10 @@ ExtraCompiler::ExtraCompiler(const Project *project, const FilePath &source, deleteLater(); }); - Core::EditorManager *editorManager = Core::EditorManager::instance(); - connect(editorManager, &Core::EditorManager::currentEditorChanged, + EditorManager *editorManager = EditorManager::instance(); + connect(editorManager, &EditorManager::currentEditorChanged, this, &ExtraCompiler::onEditorChanged); - connect(editorManager, &Core::EditorManager::editorAboutToClose, + connect(editorManager, &EditorManager::editorAboutToClose, this, &ExtraCompiler::onEditorAboutToClose); // Use existing target files, where possible. Otherwise run the compiler. @@ -228,12 +228,12 @@ void ExtraCompiler::onTargetsBuilt(Project *project) }); } -void ExtraCompiler::onEditorChanged(Core::IEditor *editor) +void ExtraCompiler::onEditorChanged(IEditor *editor) { // Handle old editor if (d->lastEditor) { - Core::IDocument *doc = d->lastEditor->document(); - disconnect(doc, &Core::IDocument::contentsChanged, + IDocument *doc = d->lastEditor->document(); + disconnect(doc, &IDocument::contentsChanged, this, &ExtraCompiler::setDirty); if (d->dirty) { @@ -246,7 +246,7 @@ void ExtraCompiler::onEditorChanged(Core::IEditor *editor) d->lastEditor = editor; // Handle new editor - connect(d->lastEditor->document(), &Core::IDocument::contentsChanged, + connect(d->lastEditor->document(), &IDocument::contentsChanged, this, &ExtraCompiler::setDirty); } else { d->lastEditor = nullptr; @@ -259,15 +259,15 @@ void ExtraCompiler::setDirty() d->timer.start(1000); } -void ExtraCompiler::onEditorAboutToClose(Core::IEditor *editor) +void ExtraCompiler::onEditorAboutToClose(IEditor *editor) { if (d->lastEditor != editor) return; // Oh no our editor is going to be closed // get the content first - Core::IDocument *doc = d->lastEditor->document(); - disconnect(doc, &Core::IDocument::contentsChanged, + IDocument *doc = d->lastEditor->document(); + disconnect(doc, &IDocument::contentsChanged, this, &ExtraCompiler::setDirty); if (d->dirty) { d->dirty = false; @@ -278,22 +278,20 @@ void ExtraCompiler::onEditorAboutToClose(Core::IEditor *editor) Environment ExtraCompiler::buildEnvironment() const { - if (Target *target = project()->activeTarget()) { - if (BuildConfiguration *bc = target->activeBuildConfiguration()) { - return bc->environment(); - } else { - EnvironmentItems changes = - EnvironmentKitAspect::environmentChanges(target->kit()); - Environment env = Environment::systemEnvironment(); - env.modify(changes); - return env; - } - } + Target *target = project()->activeTarget(); + if (!target) + return Environment::systemEnvironment(); - return Environment::systemEnvironment(); + if (BuildConfiguration *bc = target->activeBuildConfiguration()) + return bc->environment(); + + const EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(target->kit()); + Environment env = Environment::systemEnvironment(); + env.modify(changes); + return env; } -Utils::FutureSynchronizer *ExtraCompiler::futureSynchronizer() const +FutureSynchronizer *ExtraCompiler::futureSynchronizer() const { return &d->m_futureSynchronizer; } @@ -335,8 +333,8 @@ Tasking::TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &prov { const auto setupTask = [=](AsyncTask &async) { async.setThreadPool(extraCompilerThreadPool()); - async.setAsyncCallData(&ProcessExtraCompiler::runInThread, this, command(), - workingDirectory(), arguments(), provider, buildEnvironment()); + async.setConcurrentCallData(&ProcessExtraCompiler::runInThread, this, command(), + workingDirectory(), arguments(), provider, buildEnvironment()); async.setFutureSynchronizer(futureSynchronizer()); }; const auto taskDone = [=](const AsyncTask &async) { @@ -374,7 +372,7 @@ Tasks ProcessExtraCompiler::parseIssues(const QByteArray &stdErr) return {}; } -void ProcessExtraCompiler::runInThread(QFutureInterface &futureInterface, +void ProcessExtraCompiler::runInThread(QPromise &promise, const FilePath &cmd, const FilePath &workDir, const QStringList &args, const ContentProvider &provider, const Environment &env) @@ -397,15 +395,15 @@ void ProcessExtraCompiler::runInThread(QFutureInterface if (!process.waitForStarted()) return; - while (!futureInterface.isCanceled()) { + while (!promise.isCanceled()) { if (process.waitForFinished(200)) break; } - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; - futureInterface.reportResult(handleProcessFinished(&process)); + promise.addResult(handleProcessFinished(&process)); } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h index 34993f39406..4f0e6da47b3 100644 --- a/src/plugins/projectexplorer/extracompiler.h +++ b/src/plugins/projectexplorer/extracompiler.h @@ -21,7 +21,7 @@ QT_BEGIN_NAMESPACE template -class QFutureInterface; +class QPromise; class QThreadPool; QT_END_NAMESPACE @@ -106,7 +106,7 @@ protected: private: Utils::Tasking::TaskItem taskItemImpl(const ContentProvider &provider) final; - void runInThread(QFutureInterface &futureInterface, + void runInThread(QPromise &promise, const Utils::FilePath &cmd, const Utils::FilePath &workDir, const QStringList &args, const ContentProvider &provider, const Utils::Environment &env); From 5b6ef231ba94c3fe0dbe0fdbb80c12855fcd0c57 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 22 Feb 2023 07:13:30 +0100 Subject: [PATCH 0062/1447] Copilot: Fix Qbs build Change-Id: Id5e40971981846867fd3e16a5a255d553a15610c Reviewed-by: hjk --- src/plugins/copilot/copilot.qbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs index fecc4be4997..e6a537a387e 100644 --- a/src/plugins/copilot/copilot.qbs +++ b/src/plugins/copilot/copilot.qbs @@ -4,6 +4,8 @@ QtcPlugin { name: "Copilot" Depends { name: "Core" } + Depends { name: "LanguageClient" } + Depends { name: "TextEditor" } Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] } files: [ From 0cb52651039c8479a2c37e90e4aaf59ffa1f7aed Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 22 Feb 2023 14:29:58 +0100 Subject: [PATCH 0063/1447] Add missing include guards Change-Id: I47b751edf86e33560f1cabb4930926efb1fb2ff4 Reviewed-by: Eike Ziller --- src/shared/qtsingleapplication/qtlocalpeer.h | 2 ++ src/shared/qtsingleapplication/qtsingleapplication.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/shared/qtsingleapplication/qtlocalpeer.h b/src/shared/qtsingleapplication/qtlocalpeer.h index bd7f6e9dce0..67a0d42e2c9 100644 --- a/src/shared/qtsingleapplication/qtlocalpeer.h +++ b/src/shared/qtsingleapplication/qtlocalpeer.h @@ -1,6 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#pragma once + #include #include diff --git a/src/shared/qtsingleapplication/qtsingleapplication.h b/src/shared/qtsingleapplication/qtsingleapplication.h index 3d8e140bb4b..2adbe185426 100644 --- a/src/shared/qtsingleapplication/qtsingleapplication.h +++ b/src/shared/qtsingleapplication/qtsingleapplication.h @@ -1,6 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#pragma once + #include QT_FORWARD_DECLARE_CLASS(QSharedMemory) From 37ec527e6d74d4bc816e1868919a97ac8a398cae Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 22 Feb 2023 11:58:17 +0100 Subject: [PATCH 0064/1447] Fix tilde expansion in FilePath::fromUserInput It was not working for just "~/" without additional path component. Change-Id: I559a7771fc09d2e604f567548585a668e8809729 Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/libs/utils/filepath.cpp | 8 ++++---- tests/auto/utils/fileutils/tst_fileutils.cpp | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index db8008182f5..0e46b61c7d8 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1038,10 +1038,10 @@ FilePath FilePath::fromStringWithExtension(const QString &filepath, const QStrin */ FilePath FilePath::fromUserInput(const QString &filePath) { - QString clean = doCleanPath(filePath); - if (clean.startsWith(QLatin1String("~/"))) - return FileUtils::homePath().pathAppended(clean.mid(2)); - return FilePath::fromString(clean); + const QString expandedPath = filePath.startsWith("~/") + ? (QDir::homePath() + "/" + filePath.mid(2)) + : filePath; + return FilePath::fromString(doCleanPath(expandedPath)); } /*! diff --git a/tests/auto/utils/fileutils/tst_fileutils.cpp b/tests/auto/utils/fileutils/tst_fileutils.cpp index 033cf680bea..334a7c99e36 100644 --- a/tests/auto/utils/fileutils/tst_fileutils.cpp +++ b/tests/auto/utils/fileutils/tst_fileutils.cpp @@ -654,6 +654,9 @@ void tst_fileutils::fromUserInput_data() QTest::newRow("relative") << D("./rel", "", "", "rel"); QTest::newRow("qrc") << D(":/test.txt", "", "", ":/test.txt"); QTest::newRow("qrc-no-slash") << D(":test.txt", "", "", ":test.txt"); + QTest::newRow("tilde") << D("~/", "", "", QDir::homePath()); + QTest::newRow("tilde-with-path") << D("~/foo", "", "", QDir::homePath() + "/foo"); + QTest::newRow("tilde-only") << D("~", "", "", "~"); QTest::newRow("unc-incomplete") << D("//", "", "", "//"); QTest::newRow("unc-incomplete-only-server") << D("//server", "", "", "//server"); From 66d4e12a586509c7ff903bae633f4fa2ebdcc0ce Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 23 Jan 2023 17:11:34 +0100 Subject: [PATCH 0065/1447] Build: Remove FindQt5.cmake No longer needed, since we generally only support building with Qt 6 nowadays, and the parts that still do support building with Qt 5 handle that manually. Change-Id: I72381589ca3ab7bf1af88d9f185cad7f0cdf149c Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Cristian Adam --- CMakeLists.txt | 6 +- cmake/FindQt5.cmake | 103 ------------------ cmake/QtCreatorAPIInternal.cmake | 2 +- cmake/QtCreatorDocumentation.cmake | 4 +- cmake/QtCreatorTranslations.cmake | 2 +- src/CMakeLists.txt | 9 +- src/libs/extensionsystem/CMakeLists.txt | 2 +- src/libs/utils/CMakeLists.txt | 2 +- .../exported-diagnostics/CMakeLists.txt | 2 +- src/plugins/haskell/CMakeLists.txt | 1 - src/plugins/help/CMakeLists.txt | 2 +- src/plugins/imageviewer/CMakeLists.txt | 2 +- tests/auto/debugger/CMakeLists.txt | 2 +- tests/unit/CMakeLists.txt | 2 +- tests/unit/unittest/CMakeLists.txt | 2 +- 15 files changed, 17 insertions(+), 126 deletions(-) delete mode 100644 cmake/FindQt5.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d70dab026ce..f474b952155 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ if(MSVC) add_compile_options(/wd4573) endif() -find_package(Qt5 +find_package(Qt6 ${IDE_QT_VERSION_MIN} COMPONENTS Concurrent Core Gui Network PrintSupport Qml Sql Widgets Xml Core5Compat ${QT_TEST_COMPONENT} REQUIRED @@ -82,8 +82,8 @@ if (MSVC AND QT_FEATURE_static_runtime) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() -find_package(Qt5 COMPONENTS LinguistTools QUIET) -find_package(Qt5 COMPONENTS Quick QuickWidgets Designer DesignerComponents Help SerialPort Svg Tools QUIET) +find_package(Qt6 OPTIONAL_COMPONENTS Quick QuickWidgets Designer DesignerComponentsPrivate + Help SerialPort Svg Tools LinguistTools QUIET) find_package(Threads) find_package(Clang QUIET) diff --git a/cmake/FindQt5.cmake b/cmake/FindQt5.cmake deleted file mode 100644 index fc16ec17237..00000000000 --- a/cmake/FindQt5.cmake +++ /dev/null @@ -1,103 +0,0 @@ -#.rst: -# FindQt5 -# ------- -# -# Qt5 wrapper around Qt6 CMake code. -# - -unset(__arguments) -if (Qt5_FIND_QUIETLY) - list(APPEND __arguments QUIET) -endif() -if (Qt5_FIND_REQUIRED) - list(APPEND __arguments REQUIRED) -endif() - -if (Qt5_FIND_COMPONENTS) - # for some reason QUIET doesn't really work when passed to the arguments list - if (Qt5_FIND_QUIETLY) - list(APPEND __arguments OPTIONAL_COMPONENTS) - else() - list(APPEND __arguments COMPONENTS) - endif() -endif() - -find_package(Qt6 ${Qt5_FIND_VERSION} CONFIG COMPONENTS Core QUIET) -if (NOT Qt6_FOUND) - # remove Core5Compat from components to find in Qt5, but add a dummy target, - # which unfortunately cannot start with "Qt6::" - # also remove Tools, where some tools have moved in Qt6, e.g. from Help - list(REMOVE_ITEM Qt5_FIND_COMPONENTS Core5Compat) - list(REMOVE_ITEM Qt5_FIND_COMPONENTS Tools) - find_package(Qt5 ${Qt5_FIND_VERSION} CONFIG ${__arguments} ${Qt5_FIND_COMPONENTS}) - if (NOT TARGET Qt6Core5Compat) - add_library(Qt6Core5Compat INTERFACE) - endif() - - # Remove Qt6 from the not found packages in Qt5 mode - get_property(not_found_packages GLOBAL PROPERTY "PACKAGES_NOT_FOUND") - if(not_found_packages) - list(REMOVE_ITEM not_found_packages Qt6) - set_property(GLOBAL PROPERTY "PACKAGES_NOT_FOUND" "${not_found_packages}") - endif() - return() -else() - # since Qt 6.2 some components are renamed to *Private - foreach(possible_private_libs DesignerComponents QmlDebug) - list(FIND Qt5_FIND_COMPONENTS ${possible_private_libs} dcIndex) - if(dcIndex GREATER_EQUAL 0) - find_package(Qt6${possible_private_libs}Private CONFIG QUIET) - if(TARGET Qt6::${possible_private_libs}Private) - set_property(TARGET Qt6::${possible_private_libs}Private PROPERTY IMPORTED_GLOBAL TRUE) - add_library(Qt5::${possible_private_libs} ALIAS Qt6::${possible_private_libs}Private) - list(REMOVE_AT Qt5_FIND_COMPONENTS ${dcIndex}) - endif() - endif() - endforeach() - find_package(Qt6 CONFIG ${__arguments} ${Qt5_FIND_COMPONENTS}) -endif() - -set(__additional_imported_components ATSPI2_nolink) # Work around QTBUG-97023 -foreach(comp IN LISTS Qt5_FIND_COMPONENTS __additional_imported_components) - if(TARGET Qt6::${comp}) - if (NOT TARGET Qt5::${comp}) - if (NOT QT_FEATURE_static) - set_property(TARGET Qt6::${comp} PROPERTY IMPORTED_GLOBAL TRUE) - endif() - add_library(Qt5::${comp} ALIAS Qt6::${comp}) - endif() - if (TARGET Qt6::${comp}Private AND NOT TARGET Qt5::${comp}Private) - if (NOT QT_FEATURE_static) - set_property(TARGET Qt6::${comp}Private PROPERTY IMPORTED_GLOBAL TRUE) - endif() - add_library(Qt5::${comp}Private ALIAS Qt6::${comp}Private) - endif() - endif() -endforeach() - -# alias Qt6::Core5Compat to Qt6Core5Compat to make consistent with Qt5 path -if (TARGET Qt6::Core5Compat AND NOT TARGET Qt6Core5Compat) - add_library(Qt6Core5Compat ALIAS Qt6::Core5Compat) -endif() - -set(Qt5_FOUND ${Qt6_FOUND}) -set(Qt5_VERSION ${Qt6_VERSION}) - -foreach(tool qmake lrelease lupdate moc rcc qhelpgenerator) - if (TARGET Qt6::${tool} AND NOT TARGET Qt5::${tool}) - add_executable(Qt5::${tool} IMPORTED GLOBAL) - get_target_property(imported_location Qt6::${tool} IMPORTED_LOCATION) - # handle separate tools for each configuration - if (NOT imported_location) - get_target_property(imported_location Qt6::${tool} IMPORTED_LOCATION_RELEASE) - endif() - set_target_properties(Qt5::${tool} PROPERTIES IMPORTED_LOCATION "${imported_location}") - endif() -endforeach() - -if (NOT DEFINED qt5_wrap_cpp) - function(qt5_wrap_cpp outfiles) - qt6_wrap_cpp(${outfiles} ${ARGN}) - set(${outfiles} ${${outfiles}} PARENT_SCOPE) - endfunction() -endif() diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index efe7efd9ce7..e0e513c9d29 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -224,7 +224,7 @@ function(set_explicit_moc target_name file) set(file_dependencies DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.json") endif() set_property(SOURCE "${file}" PROPERTY SKIP_AUTOMOC ON) - qt5_wrap_cpp(file_moc "${file}" ${file_dependencies}) + qt_wrap_cpp(file_moc "${file}" ${file_dependencies}) target_sources(${target_name} PRIVATE "${file_moc}") endfunction() diff --git a/cmake/QtCreatorDocumentation.cmake b/cmake/QtCreatorDocumentation.cmake index 0dbd46f47a0..3c66ae0947b 100644 --- a/cmake/QtCreatorDocumentation.cmake +++ b/cmake/QtCreatorDocumentation.cmake @@ -10,7 +10,7 @@ add_feature_info("Build online documentation" WITH_ONLINE_DOCS "") # Used for QT_INSTALL_DOCS function(qt5_query_qmake) if (NOT TARGET Qt::qmake) - message(FATAL_ERROR "Qmake was not found. Add find_package(Qt5 COMPONENTS Core) to CMake to enable.") + message(FATAL_ERROR "Qmake was not found. Add find_package(Qt6 COMPONENTS Core) to CMake to enable.") endif() # dummy check for if we already queried qmake if (QT_INSTALL_BINS) @@ -154,7 +154,7 @@ function(_setup_qhelpgenerator_targets _qdocconf_file _html_outputdir) endif() if (NOT TARGET Qt::qhelpgenerator) - message(WARNING "qhelpgenerator missing: No QCH documentation targets were generated. Add find_package(Qt5 COMPONENTS Help) to CMake to enable.") + message(WARNING "qhelpgenerator missing: No QCH documentation targets were generated. Add find_package(Qt6 COMPONENTS Help) to CMake to enable.") return() endif() diff --git a/cmake/QtCreatorTranslations.cmake b/cmake/QtCreatorTranslations.cmake index 80286602ad3..0c1e2e35c5a 100644 --- a/cmake/QtCreatorTranslations.cmake +++ b/cmake/QtCreatorTranslations.cmake @@ -126,7 +126,7 @@ endfunction() function(add_translation_targets file_prefix) if (NOT TARGET Qt::lrelease OR NOT TARGET Qt::lupdate) # No Qt translation tools were found: Skip this directory - message(WARNING "No Qt translation tools found, skipping translation targets. Add find_package(Qt5 COMPONENTS LinguistTools) to CMake to enable.") + message(WARNING "No Qt translation tools found, skipping translation targets. Add find_package(Qt6 COMPONENTS LinguistTools) to CMake to enable.") return() endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b567bbe120e..792b3012f27 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,9 +36,6 @@ install(EXPORT QtCreator ) file(WRITE ${CMAKE_BINARY_DIR}/cmake/QtCreatorConfig.cmake " -\# add module path for special FindQt5.cmake that considers Qt6 too -list(APPEND CMAKE_MODULE_PATH \${CMAKE_CURRENT_LIST_DIR}) - \# force plugins to same path naming conventions as Qt Creator \# otherwise plugins will not be found if(UNIX AND NOT APPLE) @@ -50,10 +47,10 @@ if(UNIX AND NOT APPLE) endif() include(CMakeFindDependencyMacro) -find_dependency(Qt5 ${IDE_QT_VERSION_MIN} +find_dependency(Qt6 ${IDE_QT_VERSION_MIN} COMPONENTS Concurrent Core Gui Widgets Core5Compat Network PrintSupport Qml Sql REQUIRED ) -find_dependency(Qt5 COMPONENTS Quick QuickWidgets QUIET) +find_dependency(Qt6 COMPONENTS Quick QuickWidgets QUIET) if (NOT IDE_VERSION) include(\${CMAKE_CURRENT_LIST_DIR}/QtCreatorIDEBranding.cmake) @@ -87,7 +84,6 @@ file(COPY ${PROJECT_SOURCE_DIR}/cmake/QtCreatorDocumentation.cmake ${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPI.cmake ${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPIInternal.cmake - ${PROJECT_SOURCE_DIR}/cmake/FindQt5.cmake ${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in ${PROJECT_SOURCE_DIR}/cmake/QtcSeparateDebugInfo.cmake ${PROJECT_SOURCE_DIR}/cmake/QtcSeparateDebugInfo.Info.plist.in @@ -102,7 +98,6 @@ install( ${PROJECT_SOURCE_DIR}/cmake/QtCreatorDocumentation.cmake ${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPI.cmake ${PROJECT_SOURCE_DIR}/cmake/QtCreatorAPIInternal.cmake - ${PROJECT_SOURCE_DIR}/cmake/FindQt5.cmake ${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in ${PROJECT_SOURCE_DIR}/cmake/QtcSeparateDebugInfo.cmake ${PROJECT_SOURCE_DIR}/cmake/QtcSeparateDebugInfo.Info.plist.in diff --git a/src/libs/extensionsystem/CMakeLists.txt b/src/libs/extensionsystem/CMakeLists.txt index ea7cb60beb0..0e4e6607a55 100644 --- a/src/libs/extensionsystem/CMakeLists.txt +++ b/src/libs/extensionsystem/CMakeLists.txt @@ -19,7 +19,7 @@ add_qtc_library(ExtensionSystem SKIP_AUTOMOC pluginmanager.cpp ) -find_package(Qt5 COMPONENTS Test QUIET) +find_package(Qt6 COMPONENTS Test QUIET) extend_qtc_library(ExtensionSystem CONDITION TARGET Qt::Test diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 76f4e8a314a..34b24ff78c7 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -2,7 +2,7 @@ add_qtc_library(Utils DEPENDS Qt::Qml Qt::Xml PUBLIC_DEPENDS Qt::Concurrent Qt::Core Qt::Network Qt::Gui Qt::Widgets - Qt6Core5Compat + Qt::Core5Compat SOURCES ../3rdparty/span/span.hpp ../3rdparty/tl_expected/include/tl/expected.hpp diff --git a/src/plugins/clangtools/unit-tests/exported-diagnostics/CMakeLists.txt b/src/plugins/clangtools/unit-tests/exported-diagnostics/CMakeLists.txt index 30efc996911..98f9833492d 100644 --- a/src/plugins/clangtools/unit-tests/exported-diagnostics/CMakeLists.txt +++ b/src/plugins/clangtools/unit-tests/exported-diagnostics/CMakeLists.txt @@ -11,7 +11,7 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) -find_package(Qt5 COMPONENTS Widgets REQUIRED) +find_package(Qt6 COMPONENTS Widgets REQUIRED) add_executable(clangtools main.cpp diff --git a/src/plugins/haskell/CMakeLists.txt b/src/plugins/haskell/CMakeLists.txt index 8f6cc4f1d85..dcc4bdb4a81 100644 --- a/src/plugins/haskell/CMakeLists.txt +++ b/src/plugins/haskell/CMakeLists.txt @@ -1,7 +1,6 @@ add_qtc_plugin(Haskell PLUGIN_DEPENDS QtCreator::Core QtCreator::TextEditor QtCreator::ProjectExplorer - DEPENDS Qt5::Widgets SOURCES haskell.qrc haskell_global.h diff --git a/src/plugins/help/CMakeLists.txt b/src/plugins/help/CMakeLists.txt index c25f0b6cd5b..d329b2a10aa 100644 --- a/src/plugins/help/CMakeLists.txt +++ b/src/plugins/help/CMakeLists.txt @@ -45,7 +45,7 @@ extend_qtc_plugin(Help ) option(BUILD_HELPVIEWERBACKEND_QTWEBENGINE "Build QtWebEngine based help viewer backend." YES) -find_package(Qt5 COMPONENTS WebEngineWidgets QUIET) +find_package(Qt6 COMPONENTS WebEngineWidgets QUIET) extend_qtc_plugin(Help CONDITION BUILD_HELPVIEWERBACKEND_QTWEBENGINE AND TARGET Qt::WebEngineWidgets FEATURE_INFO "QtWebEngine help viewer" diff --git a/src/plugins/imageviewer/CMakeLists.txt b/src/plugins/imageviewer/CMakeLists.txt index 5c6f0ca98b6..5c027bbd38c 100644 --- a/src/plugins/imageviewer/CMakeLists.txt +++ b/src/plugins/imageviewer/CMakeLists.txt @@ -1,4 +1,4 @@ -find_package(Qt5 COMPONENTS SvgWidgets QUIET) +find_package(Qt6 COMPONENTS SvgWidgets QUIET) if (TARGET Qt::SvgWidgets) set(SVG_WIDGETS Qt::SvgWidgets) endif() diff --git a/tests/auto/debugger/CMakeLists.txt b/tests/auto/debugger/CMakeLists.txt index 5ed44a94d2f..4abe98c05e8 100644 --- a/tests/auto/debugger/CMakeLists.txt +++ b/tests/auto/debugger/CMakeLists.txt @@ -27,7 +27,7 @@ if (NOT QT_CREATOR_API_DEFINED) set(WITH_TESTS ON) - find_package(Qt5 + find_package(Qt6 COMPONENTS Gui Core Core5Compat Widgets Network Qml Concurrent Test Xml MODULE) find_package(Threads) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 3a36658ae4f..7baf81f84bd 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -30,7 +30,7 @@ if (NOT QT_CREATOR_API_DEFINED) set(GOOGLETEST_DIR ${CMAKE_CURRENT_LIST_DIR}/unittest/3rdparty/googletest) find_package(Clang MODULE) - find_package(Qt5 + find_package(Qt6 COMPONENTS Gui Core Core5Compat Widgets Network Qml Concurrent Test Xml MODULE) find_package(Threads) diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index fd73f4cb124..e05c8d3995b 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -24,7 +24,7 @@ add_qtc_test(unittest GTEST DEPENDS Qt::Core Qt::Network Qt::Widgets Qt::Xml Qt::Concurrent Qt::Qml Qt::Gui - Qt6Core5Compat QmlJS Sqlite SqliteC + Qt::Core5Compat QmlJS Sqlite SqliteC Googletest DEFINES QT_NO_CAST_TO_ASCII From c90423eb05709e199e4d165c0764a0052588b7ee Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 22 Feb 2023 16:47:34 +0100 Subject: [PATCH 0066/1447] Markdown: Remove unneeded context Change-Id: I5b574f33d335a1a52792aad4520e5abc16ec2645 Reviewed-by: hjk --- src/plugins/texteditor/markdowneditor.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 2778ecd3de8..8ec3c445be8 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -21,7 +21,6 @@ namespace TextEditor::Internal { const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown"; -const char MARKDOWNVIEWER_EDITOR_CONTEXT[] = "Editors.MarkdownViewer.Id"; class MarkdownEditor : public Core::IEditor { @@ -42,11 +41,6 @@ public: editor->setupGenericHighlighter(); editor->setMarksVisible(false); - auto context = new Core::IContext(this); - context->setWidget(editor); - context->setContext(Core::Context(MARKDOWNVIEWER_EDITOR_CONTEXT)); - Core::ICore::addContextObject(context); - setContext(Core::Context(MARKDOWNVIEWER_ID)); setWidget(&m_widget); From 9027758b89a73ad395bf1486b8f2c1da43e9b045 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 22 Feb 2023 16:47:55 +0100 Subject: [PATCH 0067/1447] Markdown: Fix keeping scroll position when text is edited Change-Id: I1812f2835cc0e9bc23aeb1237363b82af1acc479 Reviewed-by: hjk Reviewed-by: --- src/plugins/texteditor/markdowneditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 8ec3c445be8..4041a0069e9 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -68,7 +68,7 @@ public: connect(m_document->document(), &QTextDocument::contentsChanged, this, [this, browser] { QHash positions; - const auto scrollBars = findChildren(); + const auto scrollBars = browser->findChildren(); // save scroll positions for (QScrollBar *scrollBar : scrollBars) From a4fa08f1379ac0205512d29d7628c64e9383d3b7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 22 Feb 2023 19:21:28 +0100 Subject: [PATCH 0068/1447] EditorManger: Move BaseFileFilter::openEditor into EditorManager Change-Id: I68e41ea041583a5dfbf4a76517af07ecac065039 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Eike Ziller --- .../coreplugin/editormanager/editormanager.cpp | 12 ++++++++++++ src/plugins/coreplugin/editormanager/editormanager.h | 10 ++++++---- src/plugins/coreplugin/locator/basefilefilter.cpp | 11 +---------- src/plugins/coreplugin/locator/basefilefilter.h | 1 - src/plugins/coreplugin/locator/filesystemfilter.cpp | 3 +-- src/plugins/coreplugin/locator/ilocatorfilter.h | 3 ++- .../coreplugin/locator/opendocumentsfilter.cpp | 4 ++-- 7 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 2953a833b70..f84465303fb 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -28,6 +28,7 @@ #include "../findplaceholder.h" #include "../icore.h" #include "../iversioncontrol.h" +#include "../locator/ilocatorfilter.h" #include "../modemanager.h" #include "../outputpane.h" #include "../outputpanemanager.h" @@ -3157,6 +3158,17 @@ IEditor *EditorManager::openEditorAt(const Link &link, newEditor); } +IEditor *EditorManager::openEditor(const LocatorFilterEntry &entry) +{ + const OpenEditorFlags defaultFlags = EditorManager::AllowExternalEditor; + if (entry.linkForEditor) + return EditorManager::openEditorAt(*entry.linkForEditor, {}, defaultFlags); + else if (!entry.filePath.isEmpty()) + return EditorManager::openEditor(entry.filePath, {}, defaultFlags); + return nullptr; +} + + /*! Opens the document at the position of the search result \a item using the editor type \a editorId and the specified \a flags. diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index c1c4c4644c3..f73142a933e 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -18,15 +18,16 @@ #include -QT_FORWARD_DECLARE_CLASS(QMenu) +QT_BEGIN_NAMESPACE +class QMenu; +QT_END_NAMESPACE -namespace Utils { -class MimeType; -} +namespace Utils { class MimeType; } namespace Core { class IDocument; +class LocatorFilterEntry; class SearchResultItem; namespace Internal { @@ -76,6 +77,7 @@ public: Utils::Id editorId = {}, OpenEditorFlags flags = NoFlags, bool *newEditor = nullptr); + static IEditor *openEditor(const LocatorFilterEntry &entry); static void openEditorAtSearchResult(const SearchResultItem &item, Utils::Id editorId = {}, diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 9ce27cc0528..823b5d7fb58 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -201,16 +201,7 @@ void BaseFileFilter::accept(const LocatorFilterEntry &selection, Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) - openEditorAt(selection); -} - -void BaseFileFilter::openEditorAt(const LocatorFilterEntry &entry) -{ - if (entry.linkForEditor) { - EditorManager::openEditorAt(*entry.linkForEditor, {}, EditorManager::AllowExternalEditor); - return; - } - EditorManager::openEditor(entry.filePath, {}, EditorManager::AllowExternalEditor); + EditorManager::openEditor(selection); } /*! diff --git a/src/plugins/coreplugin/locator/basefilefilter.h b/src/plugins/coreplugin/locator/basefilefilter.h index 710cd21edf4..47754dc08f5 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.h +++ b/src/plugins/coreplugin/locator/basefilefilter.h @@ -48,7 +48,6 @@ public: const QString &entry) override; void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; - static void openEditorAt(const LocatorFilterEntry &entry); protected: void setFileIterator(Iterator *iterator); diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 17c54c748dc..148852b1b09 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -3,7 +3,6 @@ #include "filesystemfilter.h" -#include "basefilefilter.h" #include "../coreplugintr.h" #include "../documentmanager.h" #include "../editormanager/editormanager.h" @@ -192,7 +191,7 @@ void FileSystemFilter::accept(const LocatorFilterEntry &selection, file.close(); VcsManager::promptToAdd(selection.filePath.absolutePath(), {selection.filePath}); } - BaseFileFilter::openEditorAt(selection); + EditorManager::openEditor(selection); }, Qt::QueuedConnection); } } diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index e6b49ab5e9c..1e0a2fcf4b4 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -21,8 +21,9 @@ namespace Core { class ILocatorFilter; -struct LocatorFilterEntry +class LocatorFilterEntry { +public: struct HighlightInfo { enum DataType { DisplayName, diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index f8febc69f30..5a9042ce430 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -3,8 +3,8 @@ #include "opendocumentsfilter.h" -#include "basefilefilter.h" #include "../coreplugintr.h" +#include "../editormanager/editormanager.h" #include #include @@ -123,7 +123,7 @@ void OpenDocumentsFilter::accept(const LocatorFilterEntry &selection, Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) - BaseFileFilter::openEditorAt(selection); + EditorManager::openEditor(selection); } } // Core::Internal From b364e4a9cd9caad81abb88e431e6f105f9ff9379 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 22 Feb 2023 19:21:28 +0100 Subject: [PATCH 0069/1447] LocatorFilter classes: Use Core namespace Change-Id: I4fd1b1ed6aa9d844ed49123e80bfb066b9fa7af2 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../clangcodemodel/clangdlocatorfilters.cpp | 55 ++-- .../cmakelocatorfilter.cpp | 23 +- .../cppeditor/cppcurrentdocumentfilter.cpp | 44 ++-- src/plugins/cppeditor/cpplocatorfilter.cpp | 35 +-- src/plugins/cppeditor/cppmodelmanager.cpp | 247 +++++++++--------- src/plugins/languageclient/locatorfilter.cpp | 80 +++--- src/plugins/modeleditor/elementtasks.cpp | 22 +- .../qmljstools/qmljsfunctionfilter.cpp | 21 +- 8 files changed, 259 insertions(+), 268 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 6cc0632234b..194e6466464 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -21,6 +21,7 @@ #include #include +using namespace Core; using namespace LanguageClient; using namespace LanguageServerProtocol; using namespace Utils; @@ -148,11 +149,11 @@ void ClangGlobalSymbolFilter::prepareSearch(const QString &entry) m_lspFilter->prepareSearch(entry, clients); } -QList ClangGlobalSymbolFilter::matchesFor( - QFutureInterface &future, const QString &entry) +QList ClangGlobalSymbolFilter::matchesFor( + QFutureInterface &future, const QString &entry) { - QList matches = m_cppFilter->matchesFor(future, entry); - const QList lspMatches = m_lspFilter->matchesFor(future, entry); + QList matches = m_cppFilter->matchesFor(future, entry); + const QList lspMatches = m_lspFilter->matchesFor(future, entry); if (!lspMatches.isEmpty()) { std::set> locations; for (const auto &entry : std::as_const(matches)) { @@ -174,7 +175,7 @@ QList ClangGlobalSymbolFilter::matchesFor( return matches; } -void ClangGlobalSymbolFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, +void ClangGlobalSymbolFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { if (qvariant_cast(selection.internalData)) @@ -221,10 +222,10 @@ private: m_content = TextEditor::TextDocument::currentTextDocument()->plainText(); } - Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info, - const Core::LocatorFilterEntry &parent) override + LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info, + const LocatorFilterEntry &parent) override { - Core::LocatorFilterEntry entry; + LocatorFilterEntry entry; entry.filter = this; entry.displayName = ClangdClient::displayNameFromDocumentSymbol( static_cast(info.kind()), info.name(), @@ -242,22 +243,22 @@ private: } // Filter out declarations for which a definition is also present. - QList matchesFor(QFutureInterface &future, - const QString &entry) override + QList matchesFor(QFutureInterface &future, + const QString &entry) override { - QList allMatches + QList allMatches = DocumentLocatorFilter::matchesFor(future, entry); - QHash> possibleDuplicates; - for (const Core::LocatorFilterEntry &e : std::as_const(allMatches)) + QHash> possibleDuplicates; + for (const LocatorFilterEntry &e : std::as_const(allMatches)) possibleDuplicates[e.displayName + e.extraInfo] << e; const QTextDocument doc(m_content); for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { - const QList &duplicates = it.value(); + const QList &duplicates = it.value(); if (duplicates.size() == 1) continue; - QList declarations; - QList definitions; - for (const Core::LocatorFilterEntry &candidate : duplicates) { + QList declarations; + QList definitions; + for (const LocatorFilterEntry &candidate : duplicates) { const auto symbol = qvariant_cast(candidate.internalData); const SymbolKind kind = static_cast(symbol.kind()); if (kind != SymbolKind::Class && kind != SymbolKind::Function) @@ -283,15 +284,15 @@ private: } if (definitions.size() == 1 && declarations.size() + definitions.size() == duplicates.size()) { - for (const Core::LocatorFilterEntry &decl : std::as_const(declarations)) - Utils::erase(allMatches, [&decl](const Core::LocatorFilterEntry &e) { + for (const LocatorFilterEntry &decl : std::as_const(declarations)) + Utils::erase(allMatches, [&decl](const LocatorFilterEntry &e) { return e.internalData == decl.internalData; }); } } // The base implementation expects the position in the internal data. - for (Core::LocatorFilterEntry &e : allMatches) { + for (LocatorFilterEntry &e : allMatches) { const Position pos = qvariant_cast(e.internalData).range().start(); e.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character())); } @@ -307,10 +308,10 @@ class ClangdCurrentDocumentFilter::Private public: ~Private() { delete cppFilter; } - Core::ILocatorFilter * const cppFilter + ILocatorFilter * const cppFilter = CppEditor::CppModelManager::createAuxiliaryCurrentDocumentFilter(); LspCurrentDocumentFilter lspFilter; - Core::ILocatorFilter *activeFilter = nullptr; + ILocatorFilter *activeFilter = nullptr; }; @@ -322,8 +323,8 @@ ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private) setPriority(High); setDefaultIncludedByDefault(false); setEnabled(false); - connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, - this, [this](const Core::IEditor *editor) { setEnabled(editor); }); + connect(EditorManager::instance(), &EditorManager::currentEditorChanged, + this, [this](const IEditor *editor) { setEnabled(editor); }); } ClangdCurrentDocumentFilter::~ClangdCurrentDocumentFilter() { delete d; } @@ -346,14 +347,14 @@ void ClangdCurrentDocumentFilter::prepareSearch(const QString &entry) d->activeFilter->prepareSearch(entry); } -QList ClangdCurrentDocumentFilter::matchesFor( - QFutureInterface &future, const QString &entry) +QList ClangdCurrentDocumentFilter::matchesFor( + QFutureInterface &future, const QString &entry) { QTC_ASSERT(d->activeFilter, return {}); return d->activeFilter->matchesFor(future, entry); } -void ClangdCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, +void ClangdCurrentDocumentFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { QTC_ASSERT(d->activeFilter, return); diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index ab646d1fa69..225217490cb 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -17,6 +17,7 @@ #include +using namespace Core; using namespace ProjectExplorer; using namespace Utils; @@ -64,7 +65,7 @@ void CMakeTargetLocatorFilter::prepareSearch(const QString &entry) extraData.insert("line", line); extraData.insert("file", path.toString()); - Core::LocatorFilterEntry filterEntry(this, target.title, extraData); + LocatorFilterEntry filterEntry(this, target.title, extraData); filterEntry.extraInfo = path.shortNativePath(); filterEntry.highlightInfo = {index, int(entry.length())}; filterEntry.filePath = path; @@ -75,7 +76,8 @@ void CMakeTargetLocatorFilter::prepareSearch(const QString &entry) } } -QList CMakeTargetLocatorFilter::matchesFor(QFutureInterface &future, const QString &entry) +QList CMakeTargetLocatorFilter::matchesFor( + QFutureInterface &future, const QString &entry) { Q_UNUSED(future) Q_UNUSED(entry) @@ -85,7 +87,8 @@ QList CMakeTargetLocatorFilter::matchesFor(QFutureInte void CMakeTargetLocatorFilter::projectListUpdated() { // Enable the filter if there's at least one CMake project - setEnabled(Utils::contains(SessionManager::projects(), [](Project *p) { return qobject_cast(p); })); + setEnabled(Utils::contains(SessionManager::projects(), + [](Project *p) { return qobject_cast(p); })); } // -------------------------------------------------------------------- @@ -101,10 +104,8 @@ BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() setPriority(High); } -void BuildCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const +void BuildCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, QString *newText, + int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) Q_UNUSED(selectionStart) @@ -151,7 +152,7 @@ OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter() setPriority(Medium); } -void OpenCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &selection, +void OpenCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const @@ -165,11 +166,9 @@ void OpenCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &select const auto file = FilePath::fromVariant(extraData.value("file")); if (line >= 0) - Core::EditorManager::openEditorAt({file, line}, - {}, - Core::EditorManager::AllowExternalEditor); + EditorManager::openEditorAt({file, line}, {}, EditorManager::AllowExternalEditor); else - Core::EditorManager::openEditor(file, {}, Core::EditorManager::AllowExternalEditor); + EditorManager::openEditor(file, {}, EditorManager::AllowExternalEditor); } } // CMakeProjectManager::Internal diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index d6687284588..a52edbfce52 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -15,6 +15,7 @@ #include #include +using namespace Core; using namespace CPlusPlus; namespace CppEditor::Internal { @@ -35,9 +36,9 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppModelManager *manager) connect(manager, &CppModelManager::documentUpdated, this, &CppCurrentDocumentFilter::onDocumentUpdated); - connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, + connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, &CppCurrentDocumentFilter::onCurrentEditorChanged); - connect(Core::EditorManager::instance(), &Core::EditorManager::editorAboutToClose, + connect(EditorManager::instance(), &EditorManager::editorAboutToClose, this, &CppCurrentDocumentFilter::onEditorAboutToClose); } @@ -50,11 +51,11 @@ void CppCurrentDocumentFilter::makeAuxiliary() setHidden(true); } -QList CppCurrentDocumentFilter::matchesFor( - QFutureInterface &future, const QString & entry) +QList CppCurrentDocumentFilter::matchesFor( + QFutureInterface &future, const QString & entry) { - QList goodEntries; - QList betterEntries; + QList goodEntries; + QList betterEntries; const QRegularExpression regexp = createRegExp(entry); if (!regexp.isValid()) @@ -84,14 +85,14 @@ QList CppCurrentDocumentFilter::matchesFor( } } - Core::LocatorFilterEntry filterEntry(this, name, id, info->icon()); + LocatorFilterEntry filterEntry(this, name, id, info->icon()); filterEntry.extraInfo = extraInfo; if (match.hasMatch()) { filterEntry.highlightInfo = highlightInfo(match); } else { match = regexp.match(extraInfo); filterEntry.highlightInfo = - highlightInfo(match, Core::LocatorFilterEntry::HighlightInfo::ExtraInfo); + highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo); } if (betterMatch) @@ -104,18 +105,18 @@ QList CppCurrentDocumentFilter::matchesFor( // entries are unsorted by design! betterEntries += goodEntries; - QHash> possibleDuplicates; - for (const Core::LocatorFilterEntry &e : std::as_const(betterEntries)) { + QHash> possibleDuplicates; + for (const LocatorFilterEntry &e : std::as_const(betterEntries)) { const IndexItem::Ptr info = qvariant_cast(e.internalData); possibleDuplicates[info->scopedSymbolName() + info->symbolType()] << e; } for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { - const QList &duplicates = it.value(); + const QList &duplicates = it.value(); if (duplicates.size() == 1) continue; - QList declarations; - QList definitions; - for (const Core::LocatorFilterEntry &candidate : duplicates) { + QList declarations; + QList definitions; + for (const LocatorFilterEntry &candidate : duplicates) { const IndexItem::Ptr info = qvariant_cast(candidate.internalData); if (info->type() != IndexItem::Function) break; @@ -126,8 +127,8 @@ QList CppCurrentDocumentFilter::matchesFor( } if (definitions.size() == 1 && declarations.size() + definitions.size() == duplicates.size()) { - for (const Core::LocatorFilterEntry &decl : std::as_const(declarations)) - Utils::erase(betterEntries, [&decl](const Core::LocatorFilterEntry &e) { + for (const LocatorFilterEntry &decl : std::as_const(declarations)) + Utils::erase(betterEntries, [&decl](const LocatorFilterEntry &e) { return e.internalData == decl.internalData; }); } @@ -136,15 +137,14 @@ QList CppCurrentDocumentFilter::matchesFor( return betterEntries; } -void CppCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, - int *selectionLength) const +void CppCurrentDocumentFilter::accept(const LocatorFilterEntry &selection, QString *newText, + int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) IndexItem::Ptr info = qvariant_cast(selection.internalData); - Core::EditorManager::openEditorAt({info->filePath(), info->line(), info->column()}); + EditorManager::openEditorAt({info->filePath(), info->line(), info->column()}); } void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc) @@ -154,7 +154,7 @@ void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc) m_itemsOfCurrentDoc.clear(); } -void CppCurrentDocumentFilter::onCurrentEditorChanged(Core::IEditor *currentEditor) +void CppCurrentDocumentFilter::onCurrentEditorChanged(IEditor *currentEditor) { QMutexLocker locker(&m_mutex); if (currentEditor) @@ -164,7 +164,7 @@ void CppCurrentDocumentFilter::onCurrentEditorChanged(Core::IEditor *currentEdit m_itemsOfCurrentDoc.clear(); } -void CppCurrentDocumentFilter::onEditorAboutToClose(Core::IEditor *editorAboutToClose) +void CppCurrentDocumentFilter::onEditorAboutToClose(IEditor *editorAboutToClose) { if (!editorAboutToClose) return; diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 083c5df1b2f..c6567165910 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -14,6 +14,8 @@ #include #include +using namespace Core; + namespace CppEditor { CppLocatorFilter::CppLocatorFilter(CppLocatorData *locatorData) @@ -27,10 +29,10 @@ CppLocatorFilter::CppLocatorFilter(CppLocatorData *locatorData) CppLocatorFilter::~CppLocatorFilter() = default; -Core::LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) +LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { const QVariant id = QVariant::fromValue(info); - Core::LocatorFilterEntry filterEntry(this, info->scopedSymbolName(), id, info->icon()); + LocatorFilterEntry filterEntry(this, info->scopedSymbolName(), id, info->icon()); if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) filterEntry.extraInfo = info->shortNativeFilePath(); else @@ -39,10 +41,10 @@ Core::LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::P return filterEntry; } -QList CppLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) +QList CppLocatorFilter::matchesFor( + QFutureInterface &future, const QString &entry) { - QList entries[int(MatchLevel::Count)]; + QList entries[int(MatchLevel::Count)]; const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); const IndexItem::ItemType wanted = matchTypes(); @@ -70,7 +72,7 @@ QList CppLocatorFilter::matchesFor( } if (match.hasMatch()) { - Core::LocatorFilterEntry filterEntry = filterEntryFromIndexItem(info); + LocatorFilterEntry filterEntry = filterEntryFromIndexItem(info); // Highlight the matched characters, therefore it may be necessary // to update the match if the displayName is different from matchString @@ -82,7 +84,7 @@ QList CppLocatorFilter::matchesFor( if (matchInParameterList && filterEntry.highlightInfo.startsDisplay.isEmpty()) { match = regexp.match(filterEntry.extraInfo); filterEntry.highlightInfo - = highlightInfo(match, Core::LocatorFilterEntry::HighlightInfo::ExtraInfo); + = highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo); } else if (matchOffset > 0) { for (int &start : filterEntry.highlightInfo.startsDisplay) start -= matchOffset; @@ -107,22 +109,21 @@ QList CppLocatorFilter::matchesFor( for (auto &entry : entries) { if (entry.size() < 1000) - Utils::sort(entry, Core::LocatorFilterEntry::compareLexigraphically); + Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); } - return std::accumulate(std::begin(entries), std::end(entries), QList()); + return std::accumulate(std::begin(entries), std::end(entries), QList()); } -void CppLocatorFilter::accept(const Core::LocatorFilterEntry &selection, +void CppLocatorFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) IndexItem::Ptr info = qvariant_cast(selection.internalData); - Core::EditorManager::openEditorAt({info->filePath(), info->line(), info->column()}, - {}, - Core::EditorManager::AllowExternalEditor); + EditorManager::openEditorAt({info->filePath(), info->line(), info->column()}, {}, + EditorManager::AllowExternalEditor); } CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData) @@ -136,10 +137,10 @@ CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData) CppClassesFilter::~CppClassesFilter() = default; -Core::LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) +LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { const QVariant id = QVariant::fromValue(info); - Core::LocatorFilterEntry filterEntry(this, info->symbolName(), id, info->icon()); + LocatorFilterEntry filterEntry(this, info->symbolName(), id, info->icon()); filterEntry.extraInfo = info->symbolScope().isEmpty() ? info->shortNativeFilePath() : info->symbolScope(); @@ -158,7 +159,7 @@ CppFunctionsFilter::CppFunctionsFilter(CppLocatorData *locatorData) CppFunctionsFilter::~CppFunctionsFilter() = default; -Core::LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr info) +LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { const QVariant id = QVariant::fromValue(info); @@ -171,7 +172,7 @@ Core::LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem: extraInfo.append(" (" + info->filePath().fileName() + ')'); } - Core::LocatorFilterEntry filterEntry(this, name + info->symbolType(), id, info->icon()); + LocatorFilterEntry filterEntry(this, name + info->symbolType(), id, info->icon()); filterEntry.extraInfo = extraInfo; return filterEntry; diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 8fc44622ab2..373773786a9 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -90,6 +90,7 @@ #include #endif +using namespace Core; using namespace CPlusPlus; using namespace ProjectExplorer; using namespace Utils; @@ -155,7 +156,7 @@ public: class CppModelManagerPrivate { public: - void setupWatcher(const QFuture &future, ProjectExplorer::Project *project, + void setupWatcher(const QFuture &future, Project *project, ProjectData *projectData, CppModelManager *q); // Snapshot @@ -164,15 +165,15 @@ public: // Project integration QReadWriteLock m_projectLock; - QHash m_projectData; - QMap > m_fileToProjectParts; + QHash m_projectData; + QMap > m_fileToProjectParts; QMap m_projectPartIdToProjectProjectPart; // The members below are cached/(re)calculated from the projects and/or their project parts bool m_dirty; - Utils::FilePaths m_projectFiles; - ProjectExplorer::HeaderPaths m_headerPaths; - ProjectExplorer::Macros m_definedMacros; + FilePaths m_projectFiles; + HeaderPaths m_headerPaths; + Macros m_definedMacros; // Editor integration mutable QMutex m_cppEditorDocumentsMutex; @@ -201,12 +202,12 @@ public: QTimer m_fallbackProjectPartTimer; CppLocatorData m_locatorData; - std::unique_ptr m_locatorFilter; - std::unique_ptr m_classesFilter; - std::unique_ptr m_includesFilter; - std::unique_ptr m_functionsFilter; - std::unique_ptr m_symbolsFindFilter; - std::unique_ptr m_currentDocumentFilter; + std::unique_ptr m_locatorFilter; + std::unique_ptr m_classesFilter; + std::unique_ptr m_includesFilter; + std::unique_ptr m_functionsFilter; + std::unique_ptr m_symbolsFindFilter; + std::unique_ptr m_currentDocumentFilter; QList m_diagnosticMessages; }; @@ -338,7 +339,7 @@ void CppModelManager::findUsages(const CursorInEditor &data, Backend backend) void CppModelManager::switchHeaderSource(bool inNextSplit, Backend backend) { - const Core::IDocument *currentDocument = Core::EditorManager::currentDocument(); + const IDocument *currentDocument = EditorManager::currentDocument(); QTC_ASSERT(currentDocument, return); instance()->modelManagerSupport(backend)->switchHeaderSource(currentDocument->filePath(), inNextSplit); @@ -346,16 +347,16 @@ void CppModelManager::switchHeaderSource(bool inNextSplit, Backend backend) void CppModelManager::showPreprocessedFile(bool inNextSplit) { - const Core::IDocument *doc = Core::EditorManager::currentDocument(); + const IDocument *doc = EditorManager::currentDocument(); QTC_ASSERT(doc, return); static const auto showError = [](const QString &reason) { - Core::MessageManager::writeFlashing(Tr::tr("Cannot show preprocessed file: %1") - .arg(reason)); + MessageManager::writeFlashing(Tr::tr("Cannot show preprocessed file: %1") + .arg(reason)); }; static const auto showFallbackWarning = [](const QString &reason) { - Core::MessageManager::writeSilently( - Tr::tr("Falling back to built-in preprocessor: %1").arg(reason)); + MessageManager::writeSilently(Tr::tr("Falling back to built-in preprocessor: %1") + .arg(reason)); }; static const auto saveAndOpen = [](const FilePath &filePath, const QByteArray &contents, bool inNextSplit) { @@ -469,24 +470,24 @@ class FindUnusedActionsEnabledSwitcher { public: FindUnusedActionsEnabledSwitcher() - : actions{Core::ActionManager::command("CppTools.FindUnusedFunctions"), - Core::ActionManager::command("CppTools.FindUnusedFunctionsInSubProject")} + : actions{ActionManager::command("CppTools.FindUnusedFunctions"), + ActionManager::command("CppTools.FindUnusedFunctionsInSubProject")} { - for (Core::Command * const action : actions) + for (Command * const action : actions) action->action()->setEnabled(false); } ~FindUnusedActionsEnabledSwitcher() { - for (Core::Command * const action : actions) + for (Command * const action : actions) action->action()->setEnabled(true); } private: - const QList actions; + const QList actions; }; using FindUnusedActionsEnabledSwitcherPtr = std::shared_ptr; static void checkNextFunctionForUnused( - const QPointer &search, + const QPointer &search, const std::shared_ptr> &findRefsFuture, const FindUnusedActionsEnabledSwitcherPtr &actionsSwitcher) { @@ -531,30 +532,28 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) const auto actionsSwitcher = std::make_shared(); // Step 1: Employ locator to find all functions - Core::ILocatorFilter *const functionsFilter - = Utils::findOrDefault(Core::ILocatorFilter::allLocatorFilters(), - Utils::equal(&Core::ILocatorFilter::id, + ILocatorFilter *const functionsFilter + = Utils::findOrDefault(ILocatorFilter::allLocatorFilters(), + Utils::equal(&ILocatorFilter::id, Id(Constants::FUNCTIONS_FILTER_ID))); QTC_ASSERT(functionsFilter, return); - const QPointer search - = Core::SearchResultWindow::instance() - ->startNewSearch(Tr::tr("Find Unused Functions"), + const QPointer search + = SearchResultWindow::instance()->startNewSearch(Tr::tr("Find Unused Functions"), {}, {}, - Core::SearchResultWindow::SearchOnly, - Core::SearchResultWindow::PreserveCaseDisabled, + SearchResultWindow::SearchOnly, + SearchResultWindow::PreserveCaseDisabled, "CppEditor"); - connect(search, &Core::SearchResult::activated, [](const Core::SearchResultItem &item) { - Core::EditorManager::openEditorAtSearchResult(item); + connect(search, &SearchResult::activated, [](const SearchResultItem &item) { + EditorManager::openEditorAtSearchResult(item); }); - Core::SearchResultWindow::instance()->popup(Core::IOutputPane::ModeSwitch - | Core::IOutputPane::WithFocus); - const auto locatorWatcher = new QFutureWatcher(search); + SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); + const auto locatorWatcher = new QFutureWatcher(search); functionsFilter->prepareSearch({}); - connect(search, &Core::SearchResult::canceled, locatorWatcher, [locatorWatcher] { + connect(search, &SearchResult::canceled, locatorWatcher, [locatorWatcher] { locatorWatcher->cancel(); }); - connect(locatorWatcher, &QFutureWatcher::finished, search, + connect(locatorWatcher, &QFutureWatcher::finished, search, [locatorWatcher, search, folder, actionsSwitcher] { locatorWatcher->deleteLater(); if (locatorWatcher->isCanceled()) { @@ -563,7 +562,7 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) } Links links; for (int i = 0; i < locatorWatcher->future().resultCount(); ++i) { - const Core::LocatorFilterEntry &entry = locatorWatcher->resultAt(i); + const LocatorFilterEntry &entry = locatorWatcher->resultAt(i); static const QStringList prefixBlacklist{"main(", "~", "qHash(", "begin()", "end()", "cbegin()", "cend()", "constBegin()", "constEnd()"}; if (Utils::anyOf(prefixBlacklist, [&entry](const QString &prefix) { @@ -593,12 +592,11 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) })); search->setUserData(remainingAndActiveLinks); const auto findRefsFuture = std::make_shared>(); - Core::FutureProgress *const progress - = Core::ProgressManager::addTask(findRefsFuture->future(), - Tr::tr("Finding Unused Functions"), - "CppEditor.FindUnusedFunctions"); + FutureProgress *const progress = ProgressManager::addTask(findRefsFuture->future(), + Tr::tr("Finding Unused Functions"), + "CppEditor.FindUnusedFunctions"); connect(progress, - &Core::FutureProgress::canceled, + &FutureProgress::canceled, search, [search, future = std::weak_ptr>(findRefsFuture)] { search->finishSearch(true); @@ -608,7 +606,7 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) } }); findRefsFuture->setProgressRange(0, links.size()); - connect(search, &Core::SearchResult::canceled, [findRefsFuture] { + connect(search, &SearchResult::canceled, [findRefsFuture] { findRefsFuture->cancel(); findRefsFuture->reportFinished(); }); @@ -620,12 +618,12 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) checkNextFunctionForUnused(search, findRefsFuture, actionsSwitcher); }); locatorWatcher->setFuture( - Utils::runAsync([functionsFilter](QFutureInterface &future) { + Utils::runAsync([functionsFilter](QFutureInterface &future) { future.reportResults(functionsFilter->matchesFor(future, {})); })); } -void CppModelManager::checkForUnusedSymbol(Core::SearchResult *search, +void CppModelManager::checkForUnusedSymbol(SearchResult *search, const Link &link, CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context, @@ -785,62 +783,62 @@ static void setFilter(std::unique_ptr &filter, filter = std::move(newFilter); } -void CppModelManager::setLocatorFilter(std::unique_ptr &&filter) +void CppModelManager::setLocatorFilter(std::unique_ptr &&filter) { setFilter(d->m_locatorFilter, std::move(filter)); } -void CppModelManager::setClassesFilter(std::unique_ptr &&filter) +void CppModelManager::setClassesFilter(std::unique_ptr &&filter) { setFilter(d->m_classesFilter, std::move(filter)); } -void CppModelManager::setIncludesFilter(std::unique_ptr &&filter) +void CppModelManager::setIncludesFilter(std::unique_ptr &&filter) { setFilter(d->m_includesFilter, std::move(filter)); } -void CppModelManager::setFunctionsFilter(std::unique_ptr &&filter) +void CppModelManager::setFunctionsFilter(std::unique_ptr &&filter) { setFilter(d->m_functionsFilter, std::move(filter)); } -void CppModelManager::setSymbolsFindFilter(std::unique_ptr &&filter) +void CppModelManager::setSymbolsFindFilter(std::unique_ptr &&filter) { setFilter(d->m_symbolsFindFilter, std::move(filter)); } -void CppModelManager::setCurrentDocumentFilter(std::unique_ptr &&filter) +void CppModelManager::setCurrentDocumentFilter(std::unique_ptr &&filter) { setFilter(d->m_currentDocumentFilter, std::move(filter)); } -Core::ILocatorFilter *CppModelManager::locatorFilter() const +ILocatorFilter *CppModelManager::locatorFilter() const { return d->m_locatorFilter.get(); } -Core::ILocatorFilter *CppModelManager::classesFilter() const +ILocatorFilter *CppModelManager::classesFilter() const { return d->m_classesFilter.get(); } -Core::ILocatorFilter *CppModelManager::includesFilter() const +ILocatorFilter *CppModelManager::includesFilter() const { return d->m_includesFilter.get(); } -Core::ILocatorFilter *CppModelManager::functionsFilter() const +ILocatorFilter *CppModelManager::functionsFilter() const { return d->m_functionsFilter.get(); } -Core::IFindFilter *CppModelManager::symbolsFindFilter() const +IFindFilter *CppModelManager::symbolsFindFilter() const { return d->m_symbolsFindFilter.get(); } -Core::ILocatorFilter *CppModelManager::currentDocumentFilter() const +ILocatorFilter *CppModelManager::currentDocumentFilter() const { return d->m_currentDocumentFilter.get(); } @@ -880,7 +878,7 @@ CppModelManager *CppModelManager::instance() void CppModelManager::registerJsExtension() { - Core::JsExpander::registerGlobalObject("Cpp", [this] { + JsExpander::registerGlobalObject("Cpp", [this] { return new CppToolsJsExtension(&d->m_locatorData); }); } @@ -888,9 +886,9 @@ void CppModelManager::registerJsExtension() void CppModelManager::initCppTools() { // Objects - connect(Core::VcsManager::instance(), &Core::VcsManager::repositoryChanged, + connect(VcsManager::instance(), &VcsManager::repositoryChanged, this, &CppModelManager::updateModifiedSourceFiles); - connect(Core::DocumentManager::instance(), &Core::DocumentManager::filesChangedInternally, + connect(DocumentManager::instance(), &DocumentManager::filesChangedInternally, [this](const FilePaths &filePaths) { updateSourceFiles(toSet(filePaths)); }); @@ -924,7 +922,7 @@ CppModelManager::CppModelManager() d->m_enableGC = true; // Visual C++ has 1MiB, macOSX has 512KiB - if (Utils::HostOsInfo::isWindowsHost() || Utils::HostOsInfo::isMacHost()) + if (HostOsInfo::isWindowsHost() || HostOsInfo::isMacHost()) d->m_threadPool.setStackSize(2 * 1024 * 1024); qRegisterMetaType >(); @@ -940,23 +938,23 @@ CppModelManager::CppModelManager() d->m_delayedGcTimer.setSingleShot(true); connect(&d->m_delayedGcTimer, &QTimer::timeout, this, &CppModelManager::GC); - auto sessionManager = ProjectExplorer::SessionManager::instance(); - connect(sessionManager, &ProjectExplorer::SessionManager::projectAdded, + auto sessionManager = SessionManager::instance(); + connect(sessionManager, &SessionManager::projectAdded, this, &CppModelManager::onProjectAdded); - connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject, + connect(sessionManager, &SessionManager::aboutToRemoveProject, this, &CppModelManager::onAboutToRemoveProject); - connect(sessionManager, &ProjectExplorer::SessionManager::aboutToLoadSession, + connect(sessionManager, &SessionManager::aboutToLoadSession, this, &CppModelManager::onAboutToLoadSession); - connect(sessionManager, &ProjectExplorer::SessionManager::startupProjectChanged, + connect(sessionManager, &SessionManager::startupProjectChanged, this, &CppModelManager::onActiveProjectChanged); - connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, + connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, &CppModelManager::onCurrentEditorChanged); - connect(Core::DocumentManager::instance(), &Core::DocumentManager::allDocumentsRenamed, + connect(DocumentManager::instance(), &DocumentManager::allDocumentsRenamed, this, &CppModelManager::renameIncludes); - connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, + connect(ICore::instance(), &ICore::coreAboutToClose, this, &CppModelManager::onCoreAboutToClose); d->m_fallbackProjectPartTimer.setSingleShot(true); @@ -1041,13 +1039,13 @@ FilePaths CppModelManager::internalProjectFiles() const return files; } -ProjectExplorer::HeaderPaths CppModelManager::internalHeaderPaths() const +HeaderPaths CppModelManager::internalHeaderPaths() const { - ProjectExplorer::HeaderPaths headerPaths; + HeaderPaths headerPaths; for (const ProjectData &projectData: std::as_const(d->m_projectData)) { for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) { - for (const ProjectExplorer::HeaderPath &path : part->headerPaths) { - ProjectExplorer::HeaderPath hp(QDir::cleanPath(path.path), path.type); + for (const HeaderPath &path : part->headerPaths) { + HeaderPath hp(QDir::cleanPath(path.path), path.type); if (!headerPaths.contains(hp)) headerPaths.push_back(std::move(hp)); } @@ -1056,8 +1054,7 @@ ProjectExplorer::HeaderPaths CppModelManager::internalHeaderPaths() const return headerPaths; } -static void addUnique(const ProjectExplorer::Macros &newMacros, - ProjectExplorer::Macros ¯os, +static void addUnique(const Macros &newMacros, Macros ¯os, QSet &alreadyIn) { for (const ProjectExplorer::Macro ¯o : newMacros) { @@ -1068,9 +1065,9 @@ static void addUnique(const ProjectExplorer::Macros &newMacros, } } -ProjectExplorer::Macros CppModelManager::internalDefinedMacros() const +Macros CppModelManager::internalDefinedMacros() const { - ProjectExplorer::Macros macros; + Macros macros; QSet alreadyIn; for (const ProjectData &projectData : std::as_const(d->m_projectData)) { for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) { @@ -1093,7 +1090,7 @@ void CppModelManager::dumpModelManagerConfiguration(const QString &logFileId) dumper.dumpSnapshot(globalSnapshot, globalSnapshotTitle, /*isGlobalSnapshot=*/ true); dumper.dumpWorkingCopy(workingCopy()); dumper.dumpMergedEntities(headerPaths(), - ProjectExplorer:: Macro::toByteArray(definedMacros())); + ProjectExplorer::Macro::toByteArray(definedMacros())); } QSet CppModelManager::abstractEditorSupports() const @@ -1268,8 +1265,8 @@ static QSet filteredFilesRemoved(const QSet &files, int fileSi const QString msg = Tr::tr("C++ Indexer: Skipping file \"%1\" " "because its path matches the ignore pattern.") .arg(filePath.displayName()); - QMetaObject::invokeMethod(Core::MessageManager::instance(), - [msg]() { Core::MessageManager::writeSilently(msg); }); + QMetaObject::invokeMethod(MessageManager::instance(), + [msg] { MessageManager::writeSilently(msg); }); skip = true; break; } @@ -1304,7 +1301,7 @@ ProjectInfoList CppModelManager::projectInfos() const [](const ProjectData &d) { return d.projectInfo; }); } -ProjectInfo::ConstPtr CppModelManager::projectInfo(ProjectExplorer::Project *project) const +ProjectInfo::ConstPtr CppModelManager::projectInfo(Project *project) const { QReadLocker locker(&d->m_projectLock); return d->m_projectData.value(project).projectInfo; @@ -1424,8 +1421,7 @@ void CppModelManager::recalculateProjectPartMappings() d->m_symbolFinder.clearCache(); } -void CppModelManagerPrivate::setupWatcher(const QFuture &future, - ProjectExplorer::Project *project, +void CppModelManagerPrivate::setupWatcher(const QFuture &future, Project *project, ProjectData *projectData, CppModelManager *q) { projectData->indexer = new QFutureWatcher(q); @@ -1446,10 +1442,10 @@ void CppModelManagerPrivate::setupWatcher(const QFuture &future, void CppModelManager::updateCppEditorDocuments(bool projectsUpdated) const { // Refresh visible documents - QSet visibleCppEditorDocuments; - const QList editors = Core::EditorManager::visibleEditors(); - for (Core::IEditor *editor: editors) { - if (Core::IDocument *document = editor->document()) { + QSet visibleCppEditorDocuments; + const QList editors = EditorManager::visibleEditors(); + for (IEditor *editor: editors) { + if (IDocument *document = editor->document()) { const FilePath filePath = document->filePath(); if (CppEditorDocumentHandle *theCppEditorDocument = cppEditorDocument(filePath)) { visibleCppEditorDocuments.insert(document); @@ -1459,10 +1455,10 @@ void CppModelManager::updateCppEditorDocuments(bool projectsUpdated) const } // Mark invisible documents dirty - QSet invisibleCppEditorDocuments - = Utils::toSet(Core::DocumentModel::openedDocuments()); + QSet invisibleCppEditorDocuments + = Utils::toSet(DocumentModel::openedDocuments()); invisibleCppEditorDocuments.subtract(visibleCppEditorDocuments); - for (Core::IDocument *document : std::as_const(invisibleCppEditorDocuments)) { + for (IDocument *document : std::as_const(invisibleCppEditorDocuments)) { const FilePath filePath = document->filePath(); if (CppEditorDocumentHandle *theCppEditorDocument = cppEditorDocument(filePath)) { const CppEditorDocumentHandle::RefreshReason refreshReason = projectsUpdated @@ -1483,7 +1479,7 @@ QFuture CppModelManager::updateProjectInfo(const ProjectInfo::ConstPtr &ne QStringList removedProjectParts; bool filesRemoved = false; - ProjectExplorer::Project * const project = projectForProjectInfo(*newProjectInfo); + Project * const project = projectForProjectInfo(*newProjectInfo); if (!project) return {}; @@ -1589,20 +1585,20 @@ ProjectPart::ConstPtr CppModelManager::projectPartForId(const QString &projectPa return d->m_projectPartIdToProjectProjectPart.value(projectPartId); } -QList CppModelManager::projectPart(const Utils::FilePath &fileName) const +QList CppModelManager::projectPart(const FilePath &fileName) const { QReadLocker locker(&d->m_projectLock); return d->m_fileToProjectParts.value(fileName.canonicalPath()); } QList CppModelManager::projectPartFromDependencies( - const Utils::FilePath &fileName) const + const FilePath &fileName) const { QSet parts; - const Utils::FilePaths deps = snapshot().filesDependingOn(fileName); + const FilePaths deps = snapshot().filesDependingOn(fileName); QReadLocker locker(&d->m_projectLock); - for (const Utils::FilePath &dep : deps) + for (const FilePath &dep : deps) parts.unite(Utils::toSet(d->m_fileToProjectParts.value(dep.canonicalPath()))); return parts.values(); @@ -1614,7 +1610,7 @@ ProjectPart::ConstPtr CppModelManager::fallbackProjectPart() return d->m_fallbackProjectPart; } -bool CppModelManager::isCppEditor(Core::IEditor *editor) +bool CppModelManager::isCppEditor(IEditor *editor) { return editor->context().contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID); } @@ -1647,7 +1643,7 @@ void CppModelManager::emitAbstractEditorSupportRemoved(const QString &filePath) emit abstractEditorSupportRemoved(filePath); } -void CppModelManager::onProjectAdded(ProjectExplorer::Project *) +void CppModelManager::onProjectAdded(Project *) { QWriteLocker locker(&d->m_projectLock); d->m_dirty = true; @@ -1667,7 +1663,7 @@ static QStringList removedProjectParts(const QStringList &before, const QStringL return Utils::toList(b); } -void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project) +void CppModelManager::onAboutToRemoveProject(Project *project) { QStringList idsOfRemovedProjectParts; @@ -1689,7 +1685,7 @@ void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project) delayedGC(); } -void CppModelManager::onActiveProjectChanged(ProjectExplorer::Project *project) +void CppModelManager::onActiveProjectChanged(Project *project) { if (!project) return; // Last project closed. @@ -1711,7 +1707,7 @@ void CppModelManager::onSourceFilesRefreshed() const } } -void CppModelManager::onCurrentEditorChanged(Core::IEditor *editor) +void CppModelManager::onCurrentEditorChanged(IEditor *editor) { if (!editor || !editor->document()) return; @@ -1752,7 +1748,7 @@ QSet CppModelManager::dependingInternalTargets(const FilePath &file) co return result; } -QSet CppModelManager::internalTargets(const Utils::FilePath &filePath) const +QSet CppModelManager::internalTargets(const FilePath &filePath) const { const QList projectParts = projectPart(filePath); // if we have no project parts it's most likely a header with declarations only and CMake based @@ -1761,14 +1757,13 @@ QSet CppModelManager::internalTargets(const Utils::FilePath &filePath) QSet targets; for (const ProjectPart::ConstPtr &part : projectParts) { targets.insert(part->buildSystemTarget); - if (part->buildTargetType != ProjectExplorer::BuildTargetType::Executable) + if (part->buildTargetType != BuildTargetType::Executable) targets.unite(dependingInternalTargets(filePath)); } return targets; } -void CppModelManager::renameIncludes(const Utils::FilePath &oldFilePath, - const Utils::FilePath &newFilePath) +void CppModelManager::renameIncludes(const FilePath &oldFilePath, const FilePath &newFilePath) { if (oldFilePath.isEmpty() || newFilePath.isEmpty()) return; @@ -1815,7 +1810,7 @@ void CppModelManager::renameIncludes(const Utils::FilePath &oldFilePath, const QTextBlock &block = file->document()->findBlockByNumber(loc.second - 1); const int replaceStart = block.text().indexOf(oldFileName); if (replaceStart > -1) { - Utils::ChangeSet changeSet; + ChangeSet changeSet; changeSet.replace(block.position() + replaceStart, block.position() + replaceStart + oldFileName.length(), newFileName); @@ -1843,13 +1838,13 @@ static const char *belongingClassName(const Function *function) return nullptr; } -QSet CppModelManager::symbolsInFiles(const QSet &files) const +QSet CppModelManager::symbolsInFiles(const QSet &files) const { QSet uniqueSymbols; const Snapshot cppSnapShot = snapshot(); // Iterate over the files and get interesting symbols - for (const Utils::FilePath &file : files) { + for (const FilePath &file : files) { // Add symbols from the C++ code model const CPlusPlus::Document::Ptr doc = cppSnapShot.document(file); if (!doc.isNull() && doc->control()) { @@ -1881,7 +1876,7 @@ QSet CppModelManager::symbolsInFiles(const QSet &files void CppModelManager::onCoreAboutToClose() { - Core::ProgressManager::cancelTasks(Constants::TASK_INDEX); + ProgressManager::cancelTasks(Constants::TASK_INDEX); d->m_enableGC = false; } @@ -1891,27 +1886,27 @@ void CppModelManager::setupFallbackProjectPart() RawProjectPart rpp; rpp.setMacros(definedMacros()); rpp.setHeaderPaths(headerPaths()); - rpp.setQtVersion(Utils::QtMajorVersion::Qt5); + rpp.setQtVersion(QtMajorVersion::Qt5); // Do not activate ObjectiveCExtensions since this will lead to the // "objective-c++" language option for a project-less *.cpp file. - Utils::LanguageExtensions langExtensions = Utils::LanguageExtension::All; - langExtensions &= ~Utils::LanguageExtensions(Utils::LanguageExtension::ObjectiveC); + LanguageExtensions langExtensions = LanguageExtension::All; + langExtensions &= ~LanguageExtensions(LanguageExtension::ObjectiveC); // TODO: Use different fallback toolchain for different kinds of files? const Kit * const defaultKit = KitManager::isLoaded() ? KitManager::defaultKit() : nullptr; const ToolChain * const defaultTc = defaultKit ? ToolChainKitAspect::cxxToolChain(defaultKit) : nullptr; if (defaultKit && defaultTc) { - Utils::FilePath sysroot = SysRootKitAspect::sysRoot(defaultKit); + FilePath sysroot = SysRootKitAspect::sysRoot(defaultKit); if (sysroot.isEmpty()) - sysroot = Utils::FilePath::fromString(defaultTc->sysRoot()); + sysroot = FilePath::fromString(defaultTc->sysRoot()); Utils::Environment env = defaultKit->buildEnvironment(); tcInfo = ToolChainInfo(defaultTc, sysroot, env); const auto macroInspectionWrapper = [runner = tcInfo.macroInspectionRunner]( const QStringList &flags) { ToolChain::MacroInspectionReport report = runner(flags); - report.languageVersion = Utils::LanguageVersion::LatestCxx; + report.languageVersion = LanguageVersion::LatestCxx; return report; }; tcInfo.macroInspectionRunner = macroInspectionWrapper; @@ -1941,7 +1936,7 @@ void CppModelManager::GC() filesInEditorSupports << abstractEditorSupport->filePath(); Snapshot currentSnapshot = snapshot(); - QSet reachableFiles; + QSet reachableFiles; // The configuration file is part of the project files, which is just fine. // If single files are open, without any project, then there is no need to // keep the configuration file around. @@ -1964,7 +1959,7 @@ void CppModelManager::GC() QStringList notReachableFiles; Snapshot newSnapshot; for (Snapshot::const_iterator it = currentSnapshot.begin(); it != currentSnapshot.end(); ++it) { - const Utils::FilePath &fileName = it.key(); + const FilePath &fileName = it.key(); if (reachableFiles.contains(fileName)) newSnapshot.insert(it.value()); @@ -2001,7 +1996,7 @@ TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const } void CppModelManager::followSymbol(const CursorInEditor &data, - const Utils::LinkHandler &processLinkCallback, + const LinkHandler &processLinkCallback, bool resolveTarget, bool inNextSplit, Backend backend) { instance()->modelManagerSupport(backend)->followSymbol(data, processLinkCallback, @@ -2009,7 +2004,7 @@ void CppModelManager::followSymbol(const CursorInEditor &data, } void CppModelManager::followSymbolToType(const CursorInEditor &data, - const Utils::LinkHandler &processLinkCallback, + const LinkHandler &processLinkCallback, bool inNextSplit, Backend backend) { instance()->modelManagerSupport(backend)->followSymbolToType(data, processLinkCallback, @@ -2017,13 +2012,13 @@ void CppModelManager::followSymbolToType(const CursorInEditor &data, } void CppModelManager::switchDeclDef(const CursorInEditor &data, - const Utils::LinkHandler &processLinkCallback, + const LinkHandler &processLinkCallback, Backend backend) { instance()->modelManagerSupport(backend)->switchDeclDef(data, processLinkCallback); } -Core::ILocatorFilter *CppModelManager::createAuxiliaryCurrentDocumentFilter() +ILocatorFilter *CppModelManager::createAuxiliaryCurrentDocumentFilter() { const auto filter = new Internal::CppCurrentDocumentFilter(instance()); filter->makeAuxiliary(); @@ -2049,7 +2044,7 @@ FilePaths CppModelManager::projectFiles() return d->m_projectFiles; } -ProjectExplorer::HeaderPaths CppModelManager::headerPaths() +HeaderPaths CppModelManager::headerPaths() { QWriteLocker locker(&d->m_projectLock); ensureUpdated(); @@ -2057,13 +2052,13 @@ ProjectExplorer::HeaderPaths CppModelManager::headerPaths() return d->m_headerPaths; } -void CppModelManager::setHeaderPaths(const ProjectExplorer::HeaderPaths &headerPaths) +void CppModelManager::setHeaderPaths(const HeaderPaths &headerPaths) { QWriteLocker locker(&d->m_projectLock); d->m_headerPaths = headerPaths; } -ProjectExplorer::Macros CppModelManager::definedMacros() +Macros CppModelManager::definedMacros() { QWriteLocker locker(&d->m_projectLock); ensureUpdated(); diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 2c933c12204..2b0eca3a578 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -23,6 +23,7 @@ #include #include +using namespace Core; using namespace LanguageServerProtocol; namespace LanguageClient { @@ -36,7 +37,7 @@ DocumentLocatorFilter::DocumentLocatorFilter() setDefaultShortcutString("."); setDefaultIncludedByDefault(false); setPriority(ILocatorFilter::Low); - connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, + connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, &DocumentLocatorFilter::updateCurrentClient); } @@ -56,7 +57,7 @@ void DocumentLocatorFilter::updateCurrentClient() m_updateSymbolsConnection = connect(m_symbolCache, &DocumentSymbolCache::gotSymbols, this, &DocumentLocatorFilter::updateSymbols); } - m_resetSymbolsConnection = connect(document, &Core::IDocument::contentsChanged, + m_resetSymbolsConnection = connect(document, &IDocument::contentsChanged, this, &DocumentLocatorFilter::resetSymbols); m_currentUri = client->hostPathToServerUri(document->filePath()); m_pathMapper = client->hostPathMapper(); @@ -85,11 +86,11 @@ void DocumentLocatorFilter::resetSymbols() m_currentSymbols.reset(); } -static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, - Core::ILocatorFilter *filter, - DocumentUri::PathMapper pathMapper) +static LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, + ILocatorFilter *filter, + DocumentUri::PathMapper pathMapper) { - Core::LocatorFilterEntry entry; + LocatorFilterEntry entry; entry.filter = filter; entry.displayName = info.name(); if (std::optional container = info.containerName()) @@ -99,15 +100,15 @@ static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &in return entry; } -Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info) +LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info) { QTC_ASSERT(m_pathMapper, return {}); return LanguageClient::generateLocatorEntry(info, this, m_pathMapper); } -QList DocumentLocatorFilter::generateLocatorEntries( +QList DocumentLocatorFilter::generateLocatorEntries( const SymbolInformation &info, const QRegularExpression ®exp, - const Core::LocatorFilterEntry &parent) + const LocatorFilterEntry &parent) { Q_UNUSED(parent) if (regexp.match(info.name()).hasMatch()) @@ -115,12 +116,11 @@ QList DocumentLocatorFilter::generateLocatorEntries( return {}; } -Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry( - const DocumentSymbol &info, - const Core::LocatorFilterEntry &parent) +LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const DocumentSymbol &info, + const LocatorFilterEntry &parent) { Q_UNUSED(parent) - Core::LocatorFilterEntry entry; + LocatorFilterEntry entry; entry.filter = this; entry.displayName = info.name(); if (std::optional detail = info.detail()) @@ -131,14 +131,14 @@ Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry( return entry; } -QList DocumentLocatorFilter::generateLocatorEntries( +QList DocumentLocatorFilter::generateLocatorEntries( const DocumentSymbol &info, const QRegularExpression ®exp, - const Core::LocatorFilterEntry &parent) + const LocatorFilterEntry &parent) { - QList entries; + QList entries; const QList children = info.children().value_or(QList()); const bool hasMatch = regexp.match(info.name()).hasMatch(); - Core::LocatorFilterEntry entry; + LocatorFilterEntry entry; if (hasMatch || !children.isEmpty()) entry = generateLocatorEntry(info, parent); if (hasMatch) @@ -149,10 +149,10 @@ QList DocumentLocatorFilter::generateLocatorEntries( } template -QList DocumentLocatorFilter::generateEntries(const QList &list, +QList DocumentLocatorFilter::generateEntries(const QList &list, const QString &filter) { - QList entries; + QList entries; FuzzyMatcher::CaseSensitivity caseSensitivity = ILocatorFilter::caseSensitivity(filter) == Qt::CaseSensitive ? FuzzyMatcher::CaseSensitivity::CaseSensitive @@ -175,20 +175,17 @@ void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) } } -QList DocumentLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) +QList DocumentLocatorFilter::matchesFor( + QFutureInterface &future, const QString &entry) { QMutexLocker locker(&m_mutex); if (!m_symbolCache) return {}; if (!m_currentSymbols.has_value()) { QEventLoop loop; - connect(this, &DocumentLocatorFilter::symbolsUpToDate, &loop, [&]() { loop.exit(1); }); - QFutureWatcher watcher; - connect(&watcher, - &QFutureWatcher::canceled, - &loop, - &QEventLoop::quit); + connect(this, &DocumentLocatorFilter::symbolsUpToDate, &loop, [&] { loop.exit(1); }); + QFutureWatcher watcher; + connect(&watcher, &QFutureWatcher::canceled, &loop, &QEventLoop::quit); watcher.setFuture(future.future()); locker.unlock(); if (!loop.exec()) @@ -206,7 +203,7 @@ QList DocumentLocatorFilter::matchesFor( return {}; } -void DocumentLocatorFilter::accept(const Core::LocatorFilterEntry &selection, +void DocumentLocatorFilter::accept(const LocatorFilterEntry &selection, QString * /*newText*/, int * /*selectionStart*/, int * /*selectionLength*/) const @@ -217,11 +214,10 @@ void DocumentLocatorFilter::accept(const Core::LocatorFilterEntry &selection, const Utils::Link link(m_currentUri.toFilePath(m_pathMapper), lineColumn.line + 1, lineColumn.column); - Core::EditorManager::openEditorAt(link, {}, Core::EditorManager::AllowExternalEditor); + EditorManager::openEditorAt(link, {}, EditorManager::AllowExternalEditor); } else if (selection.internalData.canConvert()) { - Core::EditorManager::openEditorAt(qvariant_cast(selection.internalData), - {}, - Core::EditorManager::AllowExternalEditor); + EditorManager::openEditorAt(qvariant_cast(selection.internalData), {}, + EditorManager::AllowExternalEditor); } } @@ -283,16 +279,16 @@ void WorkspaceLocatorFilter::prepareSearch(const QString &entry, } } -QList WorkspaceLocatorFilter::matchesFor( - QFutureInterface &future, const QString & /*entry*/) +QList WorkspaceLocatorFilter::matchesFor( + QFutureInterface &future, const QString & /*entry*/) { QMutexLocker locker(&m_mutex); if (!m_pendingRequests.isEmpty()) { QEventLoop loop; - connect(this, &WorkspaceLocatorFilter::allRequestsFinished, &loop, [&]() { loop.exit(1); }); - QFutureWatcher watcher; + connect(this, &WorkspaceLocatorFilter::allRequestsFinished, &loop, [&] { loop.exit(1); }); + QFutureWatcher watcher; connect(&watcher, - &QFutureWatcher::canceled, + &QFutureWatcher::canceled, &loop, &QEventLoop::quit); watcher.setFuture(future.future()); @@ -315,15 +311,15 @@ QList WorkspaceLocatorFilter::matchesFor( return Utils::transform(m_results, generateEntry).toList(); } -void WorkspaceLocatorFilter::accept(const Core::LocatorFilterEntry &selection, +void WorkspaceLocatorFilter::accept(const LocatorFilterEntry &selection, QString * /*newText*/, int * /*selectionStart*/, int * /*selectionLength*/) const { - if (selection.internalData.canConvert()) - Core::EditorManager::openEditorAt(qvariant_cast(selection.internalData), - {}, - Core::EditorManager::AllowExternalEditor); + if (selection.internalData.canConvert()) { + EditorManager::openEditorAt(qvariant_cast(selection.internalData), {}, + EditorManager::AllowExternalEditor); + } } void WorkspaceLocatorFilter::handleResponse(Client *client, diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp index e0efd6914a6..6702344db5c 100644 --- a/src/plugins/modeleditor/elementtasks.cpp +++ b/src/plugins/modeleditor/elementtasks.cpp @@ -33,6 +33,8 @@ #include +using namespace Core; + namespace ModelEditor { namespace Internal { @@ -87,15 +89,14 @@ bool ElementTasks::hasClassDefinition(const qmt::MElement *element) const ? klass->name() : klass->umlNamespace() + "::" + klass->name(); - Core::ILocatorFilter *classesFilter - = CppEditor::CppModelManager::instance()->classesFilter(); + ILocatorFilter *classesFilter = CppEditor::CppModelManager::instance()->classesFilter(); if (!classesFilter) return false; - QFutureInterface dummyInterface; - const QList matches + QFutureInterface dummyInterface; + const QList matches = classesFilter->matchesFor(dummyInterface, qualifiedClassName); - for (const Core::LocatorFilterEntry &entry : matches) { + for (const LocatorFilterEntry &entry : matches) { CppEditor::IndexItem::Ptr info = qvariant_cast(entry.internalData); if (info->scopedSymbolName() != qualifiedClassName) continue; @@ -124,19 +125,18 @@ void ElementTasks::openClassDefinition(const qmt::MElement *element) ? klass->name() : klass->umlNamespace() + "::" + klass->name(); - Core::ILocatorFilter *classesFilter - = CppEditor::CppModelManager::instance()->classesFilter(); + ILocatorFilter *classesFilter = CppEditor::CppModelManager::instance()->classesFilter(); if (!classesFilter) return; - QFutureInterface dummyInterface; - const QList matches + QFutureInterface dummyInterface; + const QList matches = classesFilter->matchesFor(dummyInterface, qualifiedClassName); - for (const Core::LocatorFilterEntry &entry : matches) { + for (const LocatorFilterEntry &entry : matches) { CppEditor::IndexItem::Ptr info = qvariant_cast(entry.internalData); if (info->scopedSymbolName() != qualifiedClassName) continue; - if (Core::EditorManager::instance()->openEditorAt( + if (EditorManager::instance()->openEditorAt( {info->filePath(), info->line(), info->column()})) { return; } diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 4d4ce05fb72..7ce42af1149 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -12,12 +12,13 @@ #include +using namespace Core; using namespace QmlJSTools::Internal; Q_DECLARE_METATYPE(LocatorData::Entry) FunctionFilter::FunctionFilter(LocatorData *data, QObject *parent) - : Core::ILocatorFilter(parent) + : ILocatorFilter(parent) , m_data(data) { setId("Functions"); @@ -28,11 +29,10 @@ FunctionFilter::FunctionFilter(LocatorData *data, QObject *parent) FunctionFilter::~FunctionFilter() = default; -QList FunctionFilter::matchesFor( - QFutureInterface &future, - const QString &entry) +QList FunctionFilter::matchesFor(QFutureInterface &future, + const QString &entry) { - QList entries[int(MatchLevel::Count)]; + QList entries[int(MatchLevel::Count)]; const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); const QRegularExpression regexp = createRegExp(entry); @@ -51,7 +51,7 @@ QList FunctionFilter::matchesFor( const QRegularExpressionMatch match = regexp.match(info.symbolName); if (match.hasMatch()) { QVariant id = QVariant::fromValue(info); - Core::LocatorFilterEntry filterEntry(this, info.displayName, id/*, info.icon*/); + LocatorFilterEntry filterEntry(this, info.displayName, id/*, info.icon*/); filterEntry.extraInfo = info.extraInfo; filterEntry.highlightInfo = highlightInfo(match); @@ -67,18 +67,17 @@ QList FunctionFilter::matchesFor( for (auto &entry : entries) { if (entry.size() < 1000) - Utils::sort(entry, Core::LocatorFilterEntry::compareLexigraphically); + Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); } - - return std::accumulate(std::begin(entries), std::end(entries), QList()); + return std::accumulate(std::begin(entries), std::end(entries), QList()); } -void FunctionFilter::accept(const Core::LocatorFilterEntry &selection, +void FunctionFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) const LocatorData::Entry entry = qvariant_cast(selection.internalData); - Core::EditorManager::openEditorAt({entry.fileName, entry.line, entry.column}); + EditorManager::openEditorAt({entry.fileName, entry.line, entry.column}); } From d44126c300a20790a4be183cd98dc5be6da24d70 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 23 Feb 2023 10:03:39 +0100 Subject: [PATCH 0070/1447] Unittest: Drop unneeded dependencies to coreplugin files Amends baa83725f640419bc2c17cd28b91e1604255a3dc Change-Id: I82b472585dc30b0466eace15897f5d96fc7e9fd9 Reviewed-by: Eike Ziller --- tests/unit/unittest/CMakeLists.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index e05c8d3995b..ad7858ac912 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -310,15 +310,6 @@ endif() extend_qtc_test(unittest DEPENDS Utils CPlusPlus) -extend_qtc_test(unittest - SOURCES_PREFIX ../../../src/plugins/coreplugin - DEFINES CORE_STATIC_LIBRARY - SOURCES - coreicons.cpp coreicons.h - find/ifindfilter.cpp find/ifindfilter.h - locator/ilocatorfilter.cpp locator/ilocatorfilter.h -) - extend_qtc_test(unittest CONDITION TARGET qmldomlib DEPENDS qmldomlib From 00fd4c8feadbfe354b8c7f93038f60bec86b5554 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 22 Feb 2023 15:58:18 +0100 Subject: [PATCH 0071/1447] Utils: Fix diriterator for scheme folders Previously the "fileName" of every device inside a scheme subfolder would be empty. Therefore QDirIterator would skip them. Change-Id: Ifa46859aadbd8a81364a1fe0a72b9a50a7a396ca Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/utils/filepath.cpp | 6 ++++ src/libs/utils/fsengine/diriterator.h | 3 ++ tests/auto/utils/fileutils/tst_fileutils.cpp | 34 ++++++++++++++++---- tests/auto/utils/fsengine/tst_fsengine.cpp | 4 +++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 0e46b61c7d8..8c0832df585 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -233,6 +233,9 @@ QString FilePath::toString() const if (!needsDevice()) return path(); + if (pathView().isEmpty()) + return scheme() + "://" + encodedHost(); + if (isRelativePath()) return scheme() + "://" + encodedHost() + "/./" + pathView(); return scheme() + "://" + encodedHost() + pathView(); @@ -255,6 +258,9 @@ QString FilePath::toFSPathString() const if (scheme().isEmpty()) return path(); + if (pathView().isEmpty()) + return specialRootPath() + '/' + scheme() + '/' + encodedHost(); + if (isRelativePath()) return specialRootPath() + '/' + scheme() + '/' + encodedHost() + "/./" + pathView(); return specialRootPath() + '/' + scheme() + '/' + encodedHost() + pathView(); diff --git a/src/libs/utils/fsengine/diriterator.h b/src/libs/utils/fsengine/diriterator.h index 9daebbebaaa..54e9d5d2dd3 100644 --- a/src/libs/utils/fsengine/diriterator.h +++ b/src/libs/utils/fsengine/diriterator.h @@ -39,6 +39,9 @@ public: QString currentFileName() const override { const QString result = it->fileName(); + if (result.isEmpty() && !it->host().isEmpty()) { + return it->host().toString(); + } return chopIfEndsWith(result, '/'); } diff --git a/tests/auto/utils/fileutils/tst_fileutils.cpp b/tests/auto/utils/fileutils/tst_fileutils.cpp index 334a7c99e36..46461072e97 100644 --- a/tests/auto/utils/fileutils/tst_fileutils.cpp +++ b/tests/auto/utils/fileutils/tst_fileutils.cpp @@ -473,8 +473,16 @@ void tst_fileutils::toString_data() QTest::addColumn("userResult"); QTest::newRow("empty") << "" << "" << "" << "" << ""; - QTest::newRow("scheme") << "http" << "" << "" << "http:///./" << "http:///./"; - QTest::newRow("scheme-and-host") << "http" << "127.0.0.1" << "" << "http://127.0.0.1/./" << "http://127.0.0.1/./"; + QTest::newRow("scheme") << "http" + << "" + << "" + << "http://" + << "http://"; + QTest::newRow("scheme-and-host") << "http" + << "127.0.0.1" + << "" + << "http://127.0.0.1" + << "http://127.0.0.1"; QTest::newRow("root") << "http" << "127.0.0.1" << "/" << "http://127.0.0.1/" << "http://127.0.0.1/"; QTest::newRow("root-folder") << "" << "" << "/" << "/" << "/"; @@ -483,7 +491,11 @@ void tst_fileutils::toString_data() QTest::newRow("qtc-dev-type-root-folder-linux") << "" << "" << "/__qtc_devices__/docker" << "/__qtc_devices__/docker" << "/__qtc_devices__/docker"; QTest::newRow("qtc-dev-type-root-folder-win") << "" << "" << "c:/__qtc_devices__/docker" << "c:/__qtc_devices__/docker" << "c:/__qtc_devices__/docker"; QTest::newRow("qtc-root-folder") << "docker" << "alpine:latest" << "/" << "docker://alpine:latest/" << "docker://alpine:latest/"; - QTest::newRow("qtc-root-folder-rel") << "docker" << "alpine:latest" << "" << "docker://alpine:latest/./" << "docker://alpine:latest/./"; + QTest::newRow("qtc-root-folder-rel") << "docker" + << "alpine:latest" + << "" + << "docker://alpine:latest" + << "docker://alpine:latest"; } void tst_fileutils::toString() @@ -509,15 +521,25 @@ void tst_fileutils::toFSPathString_data() QTest::addColumn("userResult"); QTest::newRow("empty") << "" << "" << "" << "" << ""; - QTest::newRow("scheme") << "http" << "" << "" << QDir::rootPath() + "__qtc_devices__/http//./" << "http:///./"; - QTest::newRow("scheme-and-host") << "http" << "127.0.0.1" << "" << QDir::rootPath() + "__qtc_devices__/http/127.0.0.1/./" << "http://127.0.0.1/./"; + QTest::newRow("scheme") << "http" + << "" + << "" << QDir::rootPath() + "__qtc_devices__/http/" + << "http://"; + QTest::newRow("scheme-and-host") << "http" + << "127.0.0.1" + << "" << QDir::rootPath() + "__qtc_devices__/http/127.0.0.1" + << "http://127.0.0.1"; QTest::newRow("root") << "http" << "127.0.0.1" << "/" << QDir::rootPath() + "__qtc_devices__/http/127.0.0.1/" << "http://127.0.0.1/"; QTest::newRow("root-folder") << "" << "" << "/" << "/" << "/"; QTest::newRow("qtc-dev-root-folder") << "" << "" << QDir::rootPath() + "__qtc_devices__" << QDir::rootPath() + "__qtc_devices__" << QDir::rootPath() + "__qtc_devices__"; QTest::newRow("qtc-dev-type-root-folder") << "" << "" << QDir::rootPath() + "__qtc_devices__/docker" << QDir::rootPath() + "__qtc_devices__/docker" << QDir::rootPath() + "__qtc_devices__/docker"; QTest::newRow("qtc-root-folder") << "docker" << "alpine:latest" << "/" << QDir::rootPath() + "__qtc_devices__/docker/alpine:latest/" << "docker://alpine:latest/"; - QTest::newRow("qtc-root-folder-rel") << "docker" << "alpine:latest" << "" << QDir::rootPath() + "__qtc_devices__/docker/alpine:latest/./" << "docker://alpine:latest/./"; + QTest::newRow("qtc-root-folder-rel") + << "docker" + << "alpine:latest" + << "" << QDir::rootPath() + "__qtc_devices__/docker/alpine:latest" + << "docker://alpine:latest"; } void tst_fileutils::toFSPathString() diff --git a/tests/auto/utils/fsengine/tst_fsengine.cpp b/tests/auto/utils/fsengine/tst_fsengine.cpp index 8b0cdfc1b45..d350a981808 100644 --- a/tests/auto/utils/fsengine/tst_fsengine.cpp +++ b/tests/auto/utils/fsengine/tst_fsengine.cpp @@ -93,6 +93,10 @@ void tst_fsengine::testRootPathContainsFakeDir() const QStringList schemeList = schemes.entryList(); QVERIFY(schemeList.contains("device")); + QDir devices(FilePath::specialDeviceRootPath()); + const QStringList deviceList = devices.entryList(); + QVERIFY(deviceList.contains("test")); + QDir deviceRoot(FilePath::specialDeviceRootPath() + "/test" + startWithSlash(QDir::rootPath())); const QStringList deviceRootList = deviceRoot.entryList(); QVERIFY(!deviceRootList.isEmpty()); From 7e7509744761cf8b42bdfbb5f6f849d432a3ec9f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 21 Feb 2023 14:11:40 +0100 Subject: [PATCH 0072/1447] Move examples manifest parser in separate function and file. To make it auto-testable. Change-Id: I19d263bf080a0089eb9a4ec0f379c52446771c0a Reviewed-by: David Schulz --- src/plugins/qtsupport/CMakeLists.txt | 2 + src/plugins/qtsupport/exampleslistmodel.cpp | 230 ++------------- src/plugins/qtsupport/exampleslistmodel.h | 25 -- src/plugins/qtsupport/examplesparser.cpp | 270 ++++++++++++++++++ src/plugins/qtsupport/examplesparser.h | 38 +++ .../qtsupport/gettingstartedwelcomepage.cpp | 1 + src/plugins/qtsupport/qtsupport.qbs | 2 + 7 files changed, 330 insertions(+), 238 deletions(-) create mode 100644 src/plugins/qtsupport/examplesparser.cpp create mode 100644 src/plugins/qtsupport/examplesparser.h diff --git a/src/plugins/qtsupport/CMakeLists.txt b/src/plugins/qtsupport/CMakeLists.txt index 30fe2fb32bf..5d69a7fc38a 100644 --- a/src/plugins/qtsupport/CMakeLists.txt +++ b/src/plugins/qtsupport/CMakeLists.txt @@ -8,6 +8,8 @@ add_qtc_plugin(QtSupport codegensettings.cpp codegensettings.h codegensettingspage.cpp codegensettingspage.h exampleslistmodel.cpp exampleslistmodel.h + examplesparser.cpp + examplesparser.h externaleditors.cpp externaleditors.h gettingstartedwelcomepage.cpp gettingstartedwelcomepage.h profilereader.cpp profilereader.h diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 26af348ca76..700248e1f97 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -3,6 +3,7 @@ #include "exampleslistmodel.h" +#include "examplesparser.h" #include "qtsupporttr.h" #include @@ -288,38 +289,11 @@ ExamplesViewController::ExamplesViewController(ExampleSetModel *exampleSetModel, updateExamples(); } -static QString fixStringForTags(const QString &string) -{ - QString returnString = string; - returnString.remove(QLatin1String("")); - returnString.remove(QLatin1String("")); - returnString.remove(QLatin1String("")); - returnString.remove(QLatin1String("")); - return returnString; -} - -static QStringList trimStringList(const QStringList &stringlist) -{ - return Utils::transform(stringlist, [](const QString &str) { return str.trimmed(); }); -} - -static QString relativeOrInstallPath(const QString &path, const QString &manifestPath, - const QString &installPath) -{ - const QChar slash = QLatin1Char('/'); - const QString relativeResolvedPath = manifestPath + slash + path; - const QString installResolvedPath = installPath + slash + path; - if (QFile::exists(relativeResolvedPath)) - return relativeResolvedPath; - if (QFile::exists(installResolvedPath)) - return installResolvedPath; - // doesn't exist, just return relative - return relativeResolvedPath; -} - static bool isValidExampleOrDemo(ExampleItem *item) { QTC_ASSERT(item, return false); + if (item->type == Tutorial) + return true; static QString invalidPrefix = QLatin1String("qthelp:////"); /* means that the qthelp url doesn't have any namespace */ QString reason; @@ -345,158 +319,6 @@ static bool isValidExampleOrDemo(ExampleItem *item) return ok || debugExamples(); } -static QList parseExamples(QXmlStreamReader *reader, - const QString &projectsOffset, - const QString &examplesInstallPath) -{ - QList result; - std::unique_ptr item; - const QChar slash = QLatin1Char('/'); - while (!reader->atEnd()) { - switch (reader->readNext()) { - case QXmlStreamReader::StartElement: - if (reader->name() == QLatin1String("example")) { - item = std::make_unique(); - item->type = Example; - QXmlStreamAttributes attributes = reader->attributes(); - item->name = attributes.value(QLatin1String("name")).toString(); - item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); - item->hasSourceCode = !item->projectPath.isEmpty(); - item->projectPath = relativeOrInstallPath(item->projectPath, projectsOffset, examplesInstallPath); - item->imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); - QPixmapCache::remove(item->imageUrl); - item->docUrl = attributes.value(QLatin1String("docUrl")).toString(); - item->isHighlighted = attributes.value(QLatin1String("isHighlighted")).toString() == QLatin1String("true"); - - } else if (reader->name() == QLatin1String("fileToOpen")) { - const QString mainFileAttribute = reader->attributes().value( - QLatin1String("mainFile")).toString(); - const QString filePath = relativeOrInstallPath( - reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement), - projectsOffset, examplesInstallPath); - item->filesToOpen.append(filePath); - if (mainFileAttribute.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0) - item->mainFile = filePath; - } else if (reader->name() == QLatin1String("description")) { - item->description = fixStringForTags(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); - } else if (reader->name() == QLatin1String("dependency")) { - item->dependencies.append(projectsOffset + slash + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); - } else if (reader->name() == QLatin1String("tags")) { - item->tags = trimStringList(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).split(QLatin1Char(','), Qt::SkipEmptyParts)); - } else if (reader->name() == QLatin1String("platforms")) { - item->platforms = trimStringList(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).split(QLatin1Char(','), Qt::SkipEmptyParts)); - } - break; - case QXmlStreamReader::EndElement: - if (reader->name() == QLatin1String("example")) { - if (isValidExampleOrDemo(item.get())) - result.push_back(item.release()); - } else if (reader->name() == QLatin1String("examples")) { - return result; - } - break; - default: // nothing - break; - } - } - return result; -} - -static QList parseDemos(QXmlStreamReader *reader, - const QString &projectsOffset, - const QString &demosInstallPath) -{ - QList result; - std::unique_ptr item; - const QChar slash = QLatin1Char('/'); - while (!reader->atEnd()) { - switch (reader->readNext()) { - case QXmlStreamReader::StartElement: - if (reader->name() == QLatin1String("demo")) { - item = std::make_unique(); - item->type = Demo; - QXmlStreamAttributes attributes = reader->attributes(); - item->name = attributes.value(QLatin1String("name")).toString(); - item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); - item->hasSourceCode = !item->projectPath.isEmpty(); - item->projectPath = relativeOrInstallPath(item->projectPath, projectsOffset, demosInstallPath); - item->imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); - QPixmapCache::remove(item->imageUrl); - item->docUrl = attributes.value(QLatin1String("docUrl")).toString(); - item->isHighlighted = attributes.value(QLatin1String("isHighlighted")).toString() == QLatin1String("true"); - } else if (reader->name() == QLatin1String("fileToOpen")) { - item->filesToOpen.append(relativeOrInstallPath(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement), - projectsOffset, demosInstallPath)); - } else if (reader->name() == QLatin1String("description")) { - item->description = fixStringForTags(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); - } else if (reader->name() == QLatin1String("dependency")) { - item->dependencies.append(projectsOffset + slash + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); - } else if (reader->name() == QLatin1String("tags")) { - item->tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).split(QLatin1Char(',')); - } - break; - case QXmlStreamReader::EndElement: - if (reader->name() == QLatin1String("demo")) { - if (isValidExampleOrDemo(item.get())) - result.push_back(item.release()); - } else if (reader->name() == QLatin1String("demos")) { - return result; - } - break; - default: // nothing - break; - } - } - return result; -} - -static QList parseTutorials(QXmlStreamReader *reader, const QString &projectsOffset) -{ - QList result; - std::unique_ptr item = std::make_unique(); - const QChar slash = QLatin1Char('/'); - while (!reader->atEnd()) { - switch (reader->readNext()) { - case QXmlStreamReader::StartElement: - if (reader->name() == QLatin1String("tutorial")) { - item = std::make_unique(); - item->type = Tutorial; - QXmlStreamAttributes attributes = reader->attributes(); - item->name = attributes.value(QLatin1String("name")).toString(); - item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); - item->hasSourceCode = !item->projectPath.isEmpty(); - item->projectPath.prepend(slash); - item->projectPath.prepend(projectsOffset); - item->imageUrl = Utils::StyleHelper::dpiSpecificImageFile( - attributes.value(QLatin1String("imageUrl")).toString()); - QPixmapCache::remove(item->imageUrl); - item->docUrl = attributes.value(QLatin1String("docUrl")).toString(); - item->isVideo = attributes.value(QLatin1String("isVideo")).toString() == QLatin1String("true"); - item->videoUrl = attributes.value(QLatin1String("videoUrl")).toString(); - item->videoLength = attributes.value(QLatin1String("videoLength")).toString(); - } else if (reader->name() == QLatin1String("fileToOpen")) { - item->filesToOpen.append(projectsOffset + slash + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); - } else if (reader->name() == QLatin1String("description")) { - item->description = fixStringForTags(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); - } else if (reader->name() == QLatin1String("dependency")) { - item->dependencies.append(projectsOffset + slash + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); - } else if (reader->name() == QLatin1String("tags")) { - item->tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).split(QLatin1Char(',')); - } - break; - case QXmlStreamReader::EndElement: - if (reader->name() == QLatin1String("tutorial")) - result.push_back(item.release()); - else if (reader->name() == QLatin1String("tutorials")) - return result; - break; - default: // nothing - break; - } - } - return result; -} - void ExamplesViewController::updateExamples() { QString examplesInstallPath; @@ -509,41 +331,23 @@ void ExamplesViewController::updateExamples() QList items; for (const QString &exampleSource : sources) { - QFile exampleFile(exampleSource); - if (!exampleFile.open(QIODevice::ReadOnly)) { - if (debugExamples()) - qWarning() << "ERROR: Could not open file" << exampleSource; + if (debugExamples()) { + qWarning() << QString::fromLatin1("Reading file \"%1\"...") + .arg(QFileInfo(exampleSource).absoluteFilePath()); + } + + const expected_str> result + = parseExamples(exampleSource, examplesInstallPath, demosInstallPath, m_isExamples); + if (!result) { + if (debugExamples()) { + qWarning() << "ERROR: Could not read examples from" << exampleSource << ":" + << result.error(); + } continue; } - - QFileInfo fi(exampleSource); - QString offsetPath = fi.path(); - QDir examplesDir(offsetPath); - QDir demosDir(offsetPath); - - if (debugExamples()) - qWarning() << QString::fromLatin1("Reading file \"%1\"...").arg(fi.absoluteFilePath()); - QXmlStreamReader reader(&exampleFile); - while (!reader.atEnd()) - switch (reader.readNext()) { - case QXmlStreamReader::StartElement: - if (m_isExamples && reader.name() == QLatin1String("examples")) - items += parseExamples(&reader, examplesDir.path(), examplesInstallPath); - else if (m_isExamples && reader.name() == QLatin1String("demos")) - items += parseDemos(&reader, demosDir.path(), demosInstallPath); - else if (!m_isExamples && reader.name() == QLatin1String("tutorials")) - items += parseTutorials(&reader, examplesDir.path()); - break; - default: // nothing - break; - } - - if (reader.hasError() && debugExamples()) { - qWarning().noquote().nospace() << "ERROR: Could not parse file as XML document (" - << exampleSource << "):" << reader.lineNumber() << ':' << reader.columnNumber() - << ": " << reader.errorString(); - } + items += filtered(*result, isValidExampleOrDemo); } + if (m_isExamples) { if (m_exampleSetModel->selectedQtSupports(Android::Constants::ANDROID_DEVICE_TYPE)) { items = Utils::filtered(items, [](ExampleItem *item) { diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h index a4e8fe9eba6..0047bf45e3e 100644 --- a/src/plugins/qtsupport/exampleslistmodel.h +++ b/src/plugins/qtsupport/exampleslistmodel.h @@ -77,29 +77,6 @@ private: bool m_initalized = false; }; -enum InstructionalType -{ - Example = 0, Demo, Tutorial -}; - -class ExampleItem : public Core::ListItem -{ -public: - QString projectPath; - QString docUrl; - QStringList filesToOpen; - QString mainFile; /* file to be visible after opening filesToOpen */ - QStringList dependencies; - InstructionalType type; - int difficulty = 0; - bool hasSourceCode = false; - bool isVideo = false; - bool isHighlighted = false; - QString videoUrl; - QString videoLength; - QStringList platforms; -}; - class ExamplesViewController : public QObject { Q_OBJECT @@ -119,5 +96,3 @@ private: } // namespace Internal } // namespace QtSupport - -Q_DECLARE_METATYPE(QtSupport::Internal::ExampleItem *) diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp new file mode 100644 index 00000000000..2bd50bf8102 --- /dev/null +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -0,0 +1,270 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "examplesparser.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace Utils; + +namespace QtSupport::Internal { + +static QString relativeOrInstallPath(const QString &path, + const QString &manifestPath, + const QString &installPath) +{ + const QChar slash = QLatin1Char('/'); + const QString relativeResolvedPath = manifestPath + slash + path; + const QString installResolvedPath = installPath + slash + path; + if (QFile::exists(relativeResolvedPath)) + return relativeResolvedPath; + if (QFile::exists(installResolvedPath)) + return installResolvedPath; + // doesn't exist, just return relative + return relativeResolvedPath; +} + +static QString fixStringForTags(const QString &string) +{ + QString returnString = string; + returnString.remove(QLatin1String("")); + returnString.remove(QLatin1String("")); + returnString.remove(QLatin1String("")); + returnString.remove(QLatin1String("")); + return returnString; +} + +static QStringList trimStringList(const QStringList &stringlist) +{ + return Utils::transform(stringlist, [](const QString &str) { return str.trimmed(); }); +} + +static QList parseExamples(QXmlStreamReader *reader, + const QString &projectsOffset, + const QString &examplesInstallPath) +{ + QList result; + std::unique_ptr item; + const QChar slash = QLatin1Char('/'); + while (!reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: + if (reader->name() == QLatin1String("example")) { + item = std::make_unique(); + item->type = Example; + QXmlStreamAttributes attributes = reader->attributes(); + item->name = attributes.value(QLatin1String("name")).toString(); + item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item->hasSourceCode = !item->projectPath.isEmpty(); + item->projectPath = relativeOrInstallPath(item->projectPath, + projectsOffset, + examplesInstallPath); + item->imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); + QPixmapCache::remove(item->imageUrl); + item->docUrl = attributes.value(QLatin1String("docUrl")).toString(); + item->isHighlighted = attributes.value(QLatin1String("isHighlighted")).toString() + == QLatin1String("true"); + + } else if (reader->name() == QLatin1String("fileToOpen")) { + const QString mainFileAttribute + = reader->attributes().value(QLatin1String("mainFile")).toString(); + const QString filePath + = relativeOrInstallPath(reader->readElementText( + QXmlStreamReader::ErrorOnUnexpectedElement), + projectsOffset, + examplesInstallPath); + item->filesToOpen.append(filePath); + if (mainFileAttribute.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0) + item->mainFile = filePath; + } else if (reader->name() == QLatin1String("description")) { + item->description = fixStringForTags( + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("dependency")) { + item->dependencies.append( + projectsOffset + slash + + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("tags")) { + item->tags = trimStringList( + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) + .split(QLatin1Char(','), Qt::SkipEmptyParts)); + } else if (reader->name() == QLatin1String("platforms")) { + item->platforms = trimStringList( + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) + .split(QLatin1Char(','), Qt::SkipEmptyParts)); + } + break; + case QXmlStreamReader::EndElement: + if (reader->name() == QLatin1String("example")) { + result.push_back(item.release()); + } else if (reader->name() == QLatin1String("examples")) { + return result; + } + break; + default: // nothing + break; + } + } + return result; +} + +static QList parseDemos(QXmlStreamReader *reader, + const QString &projectsOffset, + const QString &demosInstallPath) +{ + QList result; + std::unique_ptr item; + const QChar slash = QLatin1Char('/'); + while (!reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: + if (reader->name() == QLatin1String("demo")) { + item = std::make_unique(); + item->type = Demo; + QXmlStreamAttributes attributes = reader->attributes(); + item->name = attributes.value(QLatin1String("name")).toString(); + item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item->hasSourceCode = !item->projectPath.isEmpty(); + item->projectPath = relativeOrInstallPath(item->projectPath, + projectsOffset, + demosInstallPath); + item->imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); + QPixmapCache::remove(item->imageUrl); + item->docUrl = attributes.value(QLatin1String("docUrl")).toString(); + item->isHighlighted = attributes.value(QLatin1String("isHighlighted")).toString() + == QLatin1String("true"); + } else if (reader->name() == QLatin1String("fileToOpen")) { + item->filesToOpen.append( + relativeOrInstallPath(reader->readElementText( + QXmlStreamReader::ErrorOnUnexpectedElement), + projectsOffset, + demosInstallPath)); + } else if (reader->name() == QLatin1String("description")) { + item->description = fixStringForTags( + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("dependency")) { + item->dependencies.append( + projectsOffset + slash + + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("tags")) { + item->tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) + .split(QLatin1Char(',')); + } + break; + case QXmlStreamReader::EndElement: + if (reader->name() == QLatin1String("demo")) { + result.push_back(item.release()); + } else if (reader->name() == QLatin1String("demos")) { + return result; + } + break; + default: // nothing + break; + } + } + return result; +} + +static QList parseTutorials(QXmlStreamReader *reader, const QString &projectsOffset) +{ + QList result; + std::unique_ptr item = std::make_unique(); + const QChar slash = QLatin1Char('/'); + while (!reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: + if (reader->name() == QLatin1String("tutorial")) { + item = std::make_unique(); + item->type = Tutorial; + QXmlStreamAttributes attributes = reader->attributes(); + item->name = attributes.value(QLatin1String("name")).toString(); + item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item->hasSourceCode = !item->projectPath.isEmpty(); + item->projectPath.prepend(slash); + item->projectPath.prepend(projectsOffset); + item->imageUrl = Utils::StyleHelper::dpiSpecificImageFile( + attributes.value(QLatin1String("imageUrl")).toString()); + QPixmapCache::remove(item->imageUrl); + item->docUrl = attributes.value(QLatin1String("docUrl")).toString(); + item->isVideo = attributes.value(QLatin1String("isVideo")).toString() + == QLatin1String("true"); + item->videoUrl = attributes.value(QLatin1String("videoUrl")).toString(); + item->videoLength = attributes.value(QLatin1String("videoLength")).toString(); + } else if (reader->name() == QLatin1String("fileToOpen")) { + item->filesToOpen.append( + projectsOffset + slash + + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("description")) { + item->description = fixStringForTags( + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("dependency")) { + item->dependencies.append( + projectsOffset + slash + + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("tags")) { + item->tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) + .split(QLatin1Char(',')); + } + break; + case QXmlStreamReader::EndElement: + if (reader->name() == QLatin1String("tutorial")) + result.push_back(item.release()); + else if (reader->name() == QLatin1String("tutorials")) + return result; + break; + default: // nothing + break; + } + } + return result; +} + +expected_str> parseExamples(const QString &manifest, + const QString &examplesInstallPath, + const QString &demosInstallPath, + const bool examples) +{ + QFile exampleFile(manifest); + if (!exampleFile.open(QIODevice::ReadOnly)) + return make_unexpected(QString("Could not open file \"%1\"").arg(manifest)); + + QFileInfo fi(manifest); + QString offsetPath = fi.path(); + QDir examplesDir(offsetPath); + QDir demosDir(offsetPath); + + QList items; + QXmlStreamReader reader(&exampleFile); + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement: + if (examples && reader.name() == QLatin1String("examples")) + items += parseExamples(&reader, examplesDir.path(), examplesInstallPath); + else if (examples && reader.name() == QLatin1String("demos")) + items += parseDemos(&reader, demosDir.path(), demosInstallPath); + else if (!examples && reader.name() == QLatin1String("tutorials")) + items += parseTutorials(&reader, examplesDir.path()); + break; + default: // nothing + break; + } + } + + if (reader.hasError()) { + qDeleteAll(items); + return make_unexpected(QString("Could not parse file \"%1\" as XML document: %2:%3: %4") + .arg(manifest) + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString())); + } + return items; +} + +} // namespace QtSupport::Internal diff --git a/src/plugins/qtsupport/examplesparser.h b/src/plugins/qtsupport/examplesparser.h new file mode 100644 index 00000000000..d08a8da11bc --- /dev/null +++ b/src/plugins/qtsupport/examplesparser.h @@ -0,0 +1,38 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace QtSupport::Internal { + +enum InstructionalType { Example = 0, Demo, Tutorial }; + +class ExampleItem : public Core::ListItem +{ +public: + QString projectPath; + QString docUrl; + QStringList filesToOpen; + QString mainFile; /* file to be visible after opening filesToOpen */ + QStringList dependencies; + InstructionalType type; + int difficulty = 0; + bool hasSourceCode = false; + bool isVideo = false; + bool isHighlighted = false; + QString videoUrl; + QString videoLength; + QStringList platforms; +}; + +Utils::expected_str> parseExamples(const QString &manifest, + const QString &examplesInstallPath, + const QString &demosInstallPath, + bool examples); + +} // namespace QtSupport::Internal + +Q_DECLARE_METATYPE(QtSupport::Internal::ExampleItem *) diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index 36bbcfb902b..fea56880356 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -4,6 +4,7 @@ #include "gettingstartedwelcomepage.h" #include "exampleslistmodel.h" +#include "examplesparser.h" #include "qtsupporttr.h" #include diff --git a/src/plugins/qtsupport/qtsupport.qbs b/src/plugins/qtsupport/qtsupport.qbs index 58f0ea61c3b..526cf4a24fe 100644 --- a/src/plugins/qtsupport/qtsupport.qbs +++ b/src/plugins/qtsupport/qtsupport.qbs @@ -77,6 +77,8 @@ Project { "qtsupport.qrc", "exampleslistmodel.cpp", "exampleslistmodel.h", + "examplesparser.cpp", + "examplesparser.h", "profilereader.cpp", "profilereader.h", "qscxmlcgenerator.cpp", From 255afd45bf614f20b5c0ccee092dcf28c50a1827 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 22 Feb 2023 10:17:19 +0100 Subject: [PATCH 0073/1447] Convert Examples model to FilePath Change-Id: I56219d2f9516662b32d45fd9b2108a0ad34113cc Reviewed-by: David Schulz --- src/plugins/qtsupport/exampleslistmodel.cpp | 15 ++- src/plugins/qtsupport/examplesparser.cpp | 96 +++++++++---------- src/plugins/qtsupport/examplesparser.h | 15 +-- .../qtsupport/gettingstartedwelcomepage.cpp | 73 +++++++------- .../qtsupport/gettingstartedwelcomepage.h | 9 +- 5 files changed, 101 insertions(+), 107 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 700248e1f97..40196934d46 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -298,14 +298,15 @@ static bool isValidExampleOrDemo(ExampleItem *item) doesn't have any namespace */ QString reason; bool ok = true; - if (!item->hasSourceCode || !QFileInfo::exists(item->projectPath)) { + if (!item->hasSourceCode || !item->projectPath.exists()) { ok = false; - reason = QString::fromLatin1("projectPath \"%1\" empty or does not exist").arg(item->projectPath); + reason = QString::fromLatin1("projectPath \"%1\" empty or does not exist") + .arg(item->projectPath.toUserOutput()); } else if (item->imageUrl.startsWith(invalidPrefix) || !QUrl(item->imageUrl).isValid()) { ok = false; reason = QString::fromLatin1("imageUrl \"%1\" not valid").arg(item->imageUrl); } else if (!item->docUrl.isEmpty() - && (item->docUrl.startsWith(invalidPrefix) || !QUrl(item->docUrl).isValid())) { + && (item->docUrl.startsWith(invalidPrefix) || !QUrl(item->docUrl).isValid())) { ok = false; reason = QString::fromLatin1("docUrl \"%1\" non-empty but not valid").arg(item->docUrl); } @@ -331,13 +332,17 @@ void ExamplesViewController::updateExamples() QList items; for (const QString &exampleSource : sources) { + const auto manifest = FilePath::fromUserInput(exampleSource); if (debugExamples()) { qWarning() << QString::fromLatin1("Reading file \"%1\"...") - .arg(QFileInfo(exampleSource).absoluteFilePath()); + .arg(manifest.absoluteFilePath().toUserOutput()); } const expected_str> result - = parseExamples(exampleSource, examplesInstallPath, demosInstallPath, m_isExamples); + = parseExamples(manifest, + FilePath::fromUserInput(examplesInstallPath), + FilePath::fromUserInput(demosInstallPath), + m_isExamples); if (!result) { if (debugExamples()) { qWarning() << "ERROR: Could not read examples from" << exampleSource << ":" diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index 2bd50bf8102..1d7211b6367 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -4,11 +4,9 @@ #include "examplesparser.h" #include +#include #include -#include -#include -#include #include #include @@ -16,16 +14,15 @@ using namespace Utils; namespace QtSupport::Internal { -static QString relativeOrInstallPath(const QString &path, - const QString &manifestPath, - const QString &installPath) +static FilePath relativeOrInstallPath(const FilePath &path, + const FilePath &manifestPath, + const FilePath &installPath) { - const QChar slash = QLatin1Char('/'); - const QString relativeResolvedPath = manifestPath + slash + path; - const QString installResolvedPath = installPath + slash + path; - if (QFile::exists(relativeResolvedPath)) + const FilePath relativeResolvedPath = manifestPath.resolvePath(path); + const FilePath installResolvedPath = installPath.resolvePath(path); + if (relativeResolvedPath.exists()) return relativeResolvedPath; - if (QFile::exists(installResolvedPath)) + if (installResolvedPath.exists()) return installResolvedPath; // doesn't exist, just return relative return relativeResolvedPath; @@ -47,12 +44,11 @@ static QStringList trimStringList(const QStringList &stringlist) } static QList parseExamples(QXmlStreamReader *reader, - const QString &projectsOffset, - const QString &examplesInstallPath) + const FilePath &projectsOffset, + const FilePath &examplesInstallPath) { QList result; std::unique_ptr item; - const QChar slash = QLatin1Char('/'); while (!reader->atEnd()) { switch (reader->readNext()) { case QXmlStreamReader::StartElement: @@ -61,7 +57,8 @@ static QList parseExamples(QXmlStreamReader *reader, item->type = Example; QXmlStreamAttributes attributes = reader->attributes(); item->name = attributes.value(QLatin1String("name")).toString(); - item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item->projectPath = FilePath::fromUserInput( + attributes.value(QLatin1String("projectPath")).toString()); item->hasSourceCode = !item->projectPath.isEmpty(); item->projectPath = relativeOrInstallPath(item->projectPath, projectsOffset, @@ -75,9 +72,9 @@ static QList parseExamples(QXmlStreamReader *reader, } else if (reader->name() == QLatin1String("fileToOpen")) { const QString mainFileAttribute = reader->attributes().value(QLatin1String("mainFile")).toString(); - const QString filePath - = relativeOrInstallPath(reader->readElementText( - QXmlStreamReader::ErrorOnUnexpectedElement), + const FilePath filePath + = relativeOrInstallPath(FilePath::fromUserInput(reader->readElementText( + QXmlStreamReader::ErrorOnUnexpectedElement)), projectsOffset, examplesInstallPath); item->filesToOpen.append(filePath); @@ -88,8 +85,8 @@ static QList parseExamples(QXmlStreamReader *reader, reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); } else if (reader->name() == QLatin1String("dependency")) { item->dependencies.append( - projectsOffset + slash - + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + projectsOffset + / reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); } else if (reader->name() == QLatin1String("tags")) { item->tags = trimStringList( reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) @@ -115,12 +112,11 @@ static QList parseExamples(QXmlStreamReader *reader, } static QList parseDemos(QXmlStreamReader *reader, - const QString &projectsOffset, - const QString &demosInstallPath) + const FilePath &projectsOffset, + const FilePath &demosInstallPath) { QList result; std::unique_ptr item; - const QChar slash = QLatin1Char('/'); while (!reader->atEnd()) { switch (reader->readNext()) { case QXmlStreamReader::StartElement: @@ -129,7 +125,8 @@ static QList parseDemos(QXmlStreamReader *reader, item->type = Demo; QXmlStreamAttributes attributes = reader->attributes(); item->name = attributes.value(QLatin1String("name")).toString(); - item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item->projectPath = FilePath::fromUserInput( + attributes.value(QLatin1String("projectPath")).toString()); item->hasSourceCode = !item->projectPath.isEmpty(); item->projectPath = relativeOrInstallPath(item->projectPath, projectsOffset, @@ -141,8 +138,8 @@ static QList parseDemos(QXmlStreamReader *reader, == QLatin1String("true"); } else if (reader->name() == QLatin1String("fileToOpen")) { item->filesToOpen.append( - relativeOrInstallPath(reader->readElementText( - QXmlStreamReader::ErrorOnUnexpectedElement), + relativeOrInstallPath(FilePath::fromUserInput(reader->readElementText( + QXmlStreamReader::ErrorOnUnexpectedElement)), projectsOffset, demosInstallPath)); } else if (reader->name() == QLatin1String("description")) { @@ -150,8 +147,8 @@ static QList parseDemos(QXmlStreamReader *reader, reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); } else if (reader->name() == QLatin1String("dependency")) { item->dependencies.append( - projectsOffset + slash - + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + projectsOffset + / reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); } else if (reader->name() == QLatin1String("tags")) { item->tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) .split(QLatin1Char(',')); @@ -171,11 +168,10 @@ static QList parseDemos(QXmlStreamReader *reader, return result; } -static QList parseTutorials(QXmlStreamReader *reader, const QString &projectsOffset) +static QList parseTutorials(QXmlStreamReader *reader, const FilePath &projectsOffset) { QList result; std::unique_ptr item = std::make_unique(); - const QChar slash = QLatin1Char('/'); while (!reader->atEnd()) { switch (reader->readNext()) { case QXmlStreamReader::StartElement: @@ -184,10 +180,9 @@ static QList parseTutorials(QXmlStreamReader *reader, const QStri item->type = Tutorial; QXmlStreamAttributes attributes = reader->attributes(); item->name = attributes.value(QLatin1String("name")).toString(); - item->projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item->projectPath = projectsOffset + / attributes.value(QLatin1String("projectPath")).toString(); item->hasSourceCode = !item->projectPath.isEmpty(); - item->projectPath.prepend(slash); - item->projectPath.prepend(projectsOffset); item->imageUrl = Utils::StyleHelper::dpiSpecificImageFile( attributes.value(QLatin1String("imageUrl")).toString()); QPixmapCache::remove(item->imageUrl); @@ -198,15 +193,15 @@ static QList parseTutorials(QXmlStreamReader *reader, const QStri item->videoLength = attributes.value(QLatin1String("videoLength")).toString(); } else if (reader->name() == QLatin1String("fileToOpen")) { item->filesToOpen.append( - projectsOffset + slash - + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + projectsOffset + / reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); } else if (reader->name() == QLatin1String("description")) { item->description = fixStringForTags( reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); } else if (reader->name() == QLatin1String("dependency")) { item->dependencies.append( - projectsOffset + slash - + reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + projectsOffset + / reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); } else if (reader->name() == QLatin1String("tags")) { item->tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) .split(QLatin1Char(',')); @@ -225,31 +220,28 @@ static QList parseTutorials(QXmlStreamReader *reader, const QStri return result; } -expected_str> parseExamples(const QString &manifest, - const QString &examplesInstallPath, - const QString &demosInstallPath, +expected_str> parseExamples(const FilePath &manifest, + const FilePath &examplesInstallPath, + const FilePath &demosInstallPath, const bool examples) { - QFile exampleFile(manifest); - if (!exampleFile.open(QIODevice::ReadOnly)) - return make_unexpected(QString("Could not open file \"%1\"").arg(manifest)); + const expected_str contents = manifest.fileContents(); + if (!contents) + return make_unexpected(contents.error()); - QFileInfo fi(manifest); - QString offsetPath = fi.path(); - QDir examplesDir(offsetPath); - QDir demosDir(offsetPath); + const FilePath path = manifest.parentDir(); QList items; - QXmlStreamReader reader(&exampleFile); + QXmlStreamReader reader(*contents); while (!reader.atEnd()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement: if (examples && reader.name() == QLatin1String("examples")) - items += parseExamples(&reader, examplesDir.path(), examplesInstallPath); + items += parseExamples(&reader, path, examplesInstallPath); else if (examples && reader.name() == QLatin1String("demos")) - items += parseDemos(&reader, demosDir.path(), demosInstallPath); + items += parseDemos(&reader, path, demosInstallPath); else if (!examples && reader.name() == QLatin1String("tutorials")) - items += parseTutorials(&reader, examplesDir.path()); + items += parseTutorials(&reader, path); break; default: // nothing break; @@ -259,7 +251,7 @@ expected_str> parseExamples(const QString &manifest, if (reader.hasError()) { qDeleteAll(items); return make_unexpected(QString("Could not parse file \"%1\" as XML document: %2:%3: %4") - .arg(manifest) + .arg(manifest.toUserOutput()) .arg(reader.lineNumber()) .arg(reader.columnNumber()) .arg(reader.errorString())); diff --git a/src/plugins/qtsupport/examplesparser.h b/src/plugins/qtsupport/examplesparser.h index d08a8da11bc..494a42b1473 100644 --- a/src/plugins/qtsupport/examplesparser.h +++ b/src/plugins/qtsupport/examplesparser.h @@ -5,6 +5,7 @@ #include #include +#include namespace QtSupport::Internal { @@ -13,11 +14,11 @@ enum InstructionalType { Example = 0, Demo, Tutorial }; class ExampleItem : public Core::ListItem { public: - QString projectPath; + Utils::FilePath projectPath; QString docUrl; - QStringList filesToOpen; - QString mainFile; /* file to be visible after opening filesToOpen */ - QStringList dependencies; + Utils::FilePaths filesToOpen; + Utils::FilePath mainFile; /* file to be visible after opening filesToOpen */ + Utils::FilePaths dependencies; InstructionalType type; int difficulty = 0; bool hasSourceCode = false; @@ -28,9 +29,9 @@ public: QStringList platforms; }; -Utils::expected_str> parseExamples(const QString &manifest, - const QString &examplesInstallPath, - const QString &demosInstallPath, +Utils::expected_str> parseExamples(const Utils::FilePath &manifest, + const Utils::FilePath &examplesInstallPath, + const Utils::FilePath &demosInstallPath, bool examples); } // namespace QtSupport::Internal diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index fea56880356..bf19233c211 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -69,16 +69,18 @@ Id ExamplesWelcomePage::id() const return m_showExamples ? "Examples" : "Tutorials"; } -QString ExamplesWelcomePage::copyToAlternativeLocation(const QFileInfo& proFileInfo, QStringList &filesToOpen, const QStringList& dependencies) +FilePath ExamplesWelcomePage::copyToAlternativeLocation(const FilePath &proFile, + FilePaths &filesToOpen, + const FilePaths &dependencies) { - const QString projectDir = proFileInfo.canonicalPath(); + const FilePath projectDir = proFile.canonicalPath().parentDir(); QDialog d(ICore::dialogParent()); auto lay = new QGridLayout(&d); auto descrLbl = new QLabel; d.setWindowTitle(Tr::tr("Copy Project to writable Location?")); descrLbl->setTextFormat(Qt::RichText); descrLbl->setWordWrap(false); - const QString nativeProjectDir = QDir::toNativeSeparators(projectDir); + const QString nativeProjectDir = projectDir.toUserOutput(); descrLbl->setText(QString::fromLatin1("
%1
").arg(nativeProjectDir)); descrLbl->setMinimumWidth(descrLbl->sizeHint().width()); descrLbl->setWordWrap(true); @@ -95,9 +97,10 @@ QString ExamplesWelcomePage::copyToAlternativeLocation(const QFileInfo& proFileI txt->setBuddy(chooser); chooser->setExpectedKind(PathChooser::ExistingDirectory); chooser->setHistoryCompleter(QLatin1String("Qt.WritableExamplesDir.History")); - const QString defaultRootDirectory = DocumentManager::projectsDirectory().toString(); + const FilePath defaultRootDirectory = DocumentManager::projectsDirectory(); QtcSettings *settings = ICore::settings(); - chooser->setFilePath(FilePath::fromSettings(settings->value(C_FALLBACK_ROOT, defaultRootDirectory))); + chooser->setFilePath( + FilePath::fromSettings(settings->value(C_FALLBACK_ROOT, defaultRootDirectory.toVariant()))); lay->addWidget(txt, 1, 0); lay->addWidget(chooser, 1, 1); enum { Copy = QDialog::Accepted + 1, Keep = QDialog::Accepted + 2 }; @@ -111,35 +114,32 @@ QString ExamplesWelcomePage::copyToAlternativeLocation(const QFileInfo& proFileI connect(chooser, &PathChooser::validChanged, copyBtn, &QWidget::setEnabled); int code = d.exec(); if (code == Copy) { - QString exampleDirName = proFileInfo.dir().dirName(); - QString destBaseDir = chooser->filePath().toString(); + const QString exampleDirName = projectDir.fileName(); + const FilePath destBaseDir = chooser->filePath(); settings->setValueWithDefault(C_FALLBACK_ROOT, destBaseDir, defaultRootDirectory); - QDir toDirWithExamplesDir(destBaseDir); - if (toDirWithExamplesDir.cd(exampleDirName)) { - toDirWithExamplesDir.cdUp(); // step out, just to not be in the way + const FilePath targetDir = destBaseDir / exampleDirName; + if (targetDir.exists()) { QMessageBox::warning(ICore::dialogParent(), Tr::tr("Cannot Use Location"), Tr::tr("The specified location already exists. " "Please specify a valid location."), QMessageBox::Ok, QMessageBox::NoButton); - return QString(); + return {}; } else { - QString targetDir = destBaseDir + QLatin1Char('/') + exampleDirName; - - expected_str result - = FilePath::fromString(projectDir).copyRecursively(FilePath::fromString(targetDir)); + expected_str result = projectDir.copyRecursively(targetDir); if (result) { // set vars to new location - const QStringList::Iterator end = filesToOpen.end(); - for (QStringList::Iterator it = filesToOpen.begin(); it != end; ++it) - it->replace(projectDir, targetDir); + const FilePaths::Iterator end = filesToOpen.end(); + for (FilePaths::Iterator it = filesToOpen.begin(); it != end; ++it) { + const FilePath relativePath = it->relativeChildPath(projectDir); + *it = targetDir.resolvePath(relativePath); + } - for (const QString &dependency : dependencies) { - const FilePath targetFile = FilePath::fromString(targetDir) - .pathAppended(QDir(dependency).dirName()); - result = FilePath::fromString(dependency).copyRecursively(targetFile); + for (const FilePath &dependency : dependencies) { + const FilePath targetFile = targetDir.pathAppended(dependency.fileName()); + result = dependency.copyRecursively(targetFile); if (!result) { QMessageBox::warning(ICore::dialogParent(), Tr::tr("Cannot Copy Project"), @@ -148,7 +148,7 @@ QString ExamplesWelcomePage::copyToAlternativeLocation(const QFileInfo& proFileI } } - return targetDir + QLatin1Char('/') + proFileInfo.fileName(); + return targetDir / proFile.fileName(); } else { QMessageBox::warning(ICore::dialogParent(), Tr::tr("Cannot Copy Project"), @@ -157,46 +157,43 @@ QString ExamplesWelcomePage::copyToAlternativeLocation(const QFileInfo& proFileI } } if (code == Keep) - return proFileInfo.absoluteFilePath(); - return QString(); + return proFile.absoluteFilePath(); + return {}; } void ExamplesWelcomePage::openProject(const ExampleItem *item) { using namespace ProjectExplorer; - QString proFile = item->projectPath; + FilePath proFile = item->projectPath; if (proFile.isEmpty()) return; - QStringList filesToOpen = item->filesToOpen; + FilePaths filesToOpen = item->filesToOpen; if (!item->mainFile.isEmpty()) { // ensure that the main file is opened on top (i.e. opened last) filesToOpen.removeAll(item->mainFile); filesToOpen.append(item->mainFile); } - QFileInfo proFileInfo(proFile); - if (!proFileInfo.exists()) + if (!proFile.exists()) return; // If the Qt is a distro Qt on Linux, it will not be writable, hence compilation will fail // Same if it is installed in non-writable location for other reasons - const bool needsCopy = withNtfsPermissions([proFileInfo] { - QFileInfo pathInfo(proFileInfo.path()); - return !proFileInfo.isWritable() - || !pathInfo.isWritable() /* path of .pro file */ - || !QFileInfo(pathInfo.path()).isWritable() /* shadow build directory */; + const bool needsCopy = withNtfsPermissions([proFile] { + return !proFile.isWritableFile() + || !proFile.parentDir().isWritableDir() /* path of project file */ + || !proFile.parentDir().parentDir().isWritableDir() /* shadow build directory */; }); if (needsCopy) - proFile = copyToAlternativeLocation(proFileInfo, filesToOpen, item->dependencies); + proFile = copyToAlternativeLocation(proFile, filesToOpen, item->dependencies); // don't try to load help and files if loading the help request is being cancelled if (proFile.isEmpty()) return; - ProjectExplorerPlugin::OpenProjectResult result = - ProjectExplorerPlugin::openProject(FilePath::fromString(proFile)); + ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProject(proFile); if (result) { - ICore::openFiles(FileUtils::toFilePathList(filesToOpen)); + ICore::openFiles(filesToOpen); ModeManager::activateMode(Core::Constants::MODE_EDIT); QUrl docUrl = QUrl::fromUserInput(item->docUrl); if (docUrl.isValid()) diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.h b/src/plugins/qtsupport/gettingstartedwelcomepage.h index 2781666a923..aa07f669167 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.h +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.h @@ -4,10 +4,7 @@ #pragma once #include - -QT_BEGIN_NAMESPACE -class QFileInfo; -QT_END_NAMESPACE +#include namespace QtSupport { namespace Internal { @@ -29,7 +26,9 @@ public: static void openProject(const ExampleItem *item); private: - static QString copyToAlternativeLocation(const QFileInfo &fileInfo, QStringList &filesToOpen, const QStringList &dependencies); + static Utils::FilePath copyToAlternativeLocation(const Utils::FilePath &fileInfo, + Utils::FilePaths &filesToOpen, + const Utils::FilePaths &dependencies); const bool m_showExamples; }; From 61c09bcefbadac12d332e3bef52bef49c649f5bf Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 14 Feb 2023 10:26:36 +0100 Subject: [PATCH 0074/1447] ProjectExplorer: Do not expand the current entry in the issues pane The expansion of the current item makes for a "jumpy" user experience and also runs into a nasty Qt bug when navigating via keyboard. Instead, we now show all items the same way and provide the details in a tool tip. As a side effect, build issues in text marks are now linkified. Fixes: QTCREATORBUG-26128 Fixes: QTCREATORBUG-27006 Fixes: QTCREATORBUG-27506 Task-number: QTBUG-100309 Change-Id: Id9078c6f798fad31781bb645e06bbc92fc73fba5 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/projectexplorer/task.cpp | 28 +++ src/plugins/projectexplorer/task.h | 1 + src/plugins/projectexplorer/taskhub.cpp | 9 +- src/plugins/projectexplorer/taskwindow.cpp | 259 +++++---------------- src/plugins/texteditor/textmark.cpp | 11 +- 5 files changed, 101 insertions(+), 207 deletions(-) diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index dab4c7ed17d..c2937e76ed4 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -120,6 +120,34 @@ QIcon Task::icon() const return m_icon; } +QString Task::toolTip(const QString &extraHeading) const +{ + if (isNull()) + return {}; + + QString text = description(); + static const QString linkTagStartPlaceholder("__QTC_LINK_TAG_START__"); + static const QString linkTagEndPlaceholder("__QTC_LINK_TAG_END__"); + static const QString linkEndPlaceholder("__QTC_LINK_END__"); + for (auto formatRange = formats.crbegin(); formatRange != formats.crend(); ++formatRange) { + if (!formatRange->format.isAnchor()) + continue; + text.insert(formatRange->start + formatRange->length, linkEndPlaceholder); + text.insert(formatRange->start, QString::fromLatin1("%1%2%3").arg( + linkTagStartPlaceholder, formatRange->format.anchorHref(), linkTagEndPlaceholder)); + } + text = text.toHtmlEscaped(); + text.replace(linkEndPlaceholder, ""); + text.replace(linkTagStartPlaceholder, ""); + const QString htmlExtraHeading = extraHeading.isEmpty() + ? QString() + : QString::fromUtf8("%1
").arg(extraHeading); + return QString::fromUtf8("%1" + "%2") + .arg(htmlExtraHeading, text); +} + // // functions // diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h index f38302f90f9..27adeebf039 100644 --- a/src/plugins/projectexplorer/task.h +++ b/src/plugins/projectexplorer/task.h @@ -51,6 +51,7 @@ public: void setFile(const Utils::FilePath &file); QString description() const; QIcon icon() const; + QString toolTip(const QString &extraHeading = {}) const; friend PROJECTEXPLORER_EXPORT bool operator==(const Task &t1, const Task &t2); friend PROJECTEXPLORER_EXPORT bool operator<(const Task &a, const Task &b); diff --git a/src/plugins/projectexplorer/taskhub.cpp b/src/plugins/projectexplorer/taskhub.cpp index da839e89f19..7c1cff54542 100644 --- a/src/plugins/projectexplorer/taskhub.cpp +++ b/src/plugins/projectexplorer/taskhub.cpp @@ -51,13 +51,8 @@ public: : Tr::tr("Warning")); setPriority(task.type == Task::Error ? TextEditor::TextMark::NormalPriority : TextEditor::TextMark::LowPriority); - if (task.category == Constants::TASK_CATEGORY_COMPILE) { - setToolTip("" + Tr::tr("Build Issue") - + "
" - + task.description().toHtmlEscaped() + ""); - } else { - setToolTip(task.description()); - } + setToolTip(task.toolTip(task.category == Constants::TASK_CATEGORY_COMPILE + ? Tr::tr("Build Issue") : QString())); setIcon(task.icon()); setVisible(!task.icon().isNull()); } diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 52e3899d654..db8dbf7d5ba 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -27,14 +27,17 @@ #include #include #include +#include #include #include -#include -#include +#include #include -#include +#include #include +#include +#include +#include using namespace Utils; @@ -92,14 +95,10 @@ public: private: void resizeEvent(QResizeEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; + void keyReleaseEvent(QKeyEvent *e) override; + bool event(QEvent *e) override; - Link locationForPos(const QPoint &pos); - - bool m_linksActive = true; - Qt::MouseButton m_mouseButtonPressed = Qt::NoButton; + void showToolTip(const Task &task, const QPoint &pos); }; class TaskDelegate : public QStyledItemDelegate @@ -117,28 +116,16 @@ public: // TaskView uses this method if the size of the taskview changes void emitSizeHintChanged(const QModelIndex &index); - void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); - - QString hrefForPos(const QPointF &pos); - private: void generateGradientPixmap(int width, int height, QColor color, bool selected) const; mutable int m_cachedHeight = 0; mutable QFont m_cachedFont; - mutable QList> m_hrefs; /* - Collapsed: - +----------------------------------------------------------------------------------------------------+ - | TASKICONAREA TEXTAREA FILEAREA LINEAREA | - +----------------------------------------------------------------------------------------------------+ - - Expanded: - +----------------------------------------------------------------------------------------------------+ - | TASKICONICON TEXTAREA FILEAREA LINEAREA | - | more text -------------------------------------------------------------------------> | - +----------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------+ + | TASKICONAREA TEXTAREA FILEAREA LINEAREA | + +------------------------------------------------------------------------------------------+ */ class Positions { @@ -205,8 +192,8 @@ TaskView::TaskView(QWidget *parent) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - setMouseTracking(true); setAutoScroll(false); // QTCREATORBUG-25101 + setUniformItemSizes(true); QFontMetrics fm(font()); int vStepSize = fm.height() + 3; @@ -224,54 +211,49 @@ void TaskView::resizeEvent(QResizeEvent *e) static_cast(itemDelegate())->emitSizeHintChanged(selectionModel()->currentIndex()); } -void TaskView::mousePressEvent(QMouseEvent *e) +void TaskView::keyReleaseEvent(QKeyEvent *e) { - m_mouseButtonPressed = e->button(); - ListView::mousePressEvent(e); -} - -void TaskView::mouseReleaseEvent(QMouseEvent *e) -{ - if (m_linksActive && m_mouseButtonPressed == Qt::LeftButton) { - const Link loc = locationForPos(e->pos()); - if (!loc.targetFilePath.isEmpty()) { - Core::EditorManager::openEditorAt(loc, {}, - Core::EditorManager::SwitchSplitIfAlreadyVisible); + ListView::keyReleaseEvent(e); + if (e->key() == Qt::Key_Space) { + const Task task = static_cast(model())->task(currentIndex()); + if (!task.isNull()) { + const QPoint toolTipPos = mapToGlobal(visualRect(currentIndex()).topLeft()); + QMetaObject::invokeMethod(this, [this, task, toolTipPos] { + showToolTip(task, toolTipPos); }, Qt::QueuedConnection); } } - - // Mouse was released, activate links again - m_linksActive = true; - m_mouseButtonPressed = Qt::NoButton; - ListView::mouseReleaseEvent(e); } -void TaskView::mouseMoveEvent(QMouseEvent *e) +bool TaskView::event(QEvent *e) { - // Cursor was dragged, deactivate links - if (m_mouseButtonPressed != Qt::NoButton) - m_linksActive = false; + if (e->type() != QEvent::ToolTip) + return QListView::event(e); - viewport()->setCursor(m_linksActive && !locationForPos(e->pos()).targetFilePath.isEmpty() - ? Qt::PointingHandCursor : Qt::ArrowCursor); - ListView::mouseMoveEvent(e); + const auto helpEvent = static_cast(e); + const Task task = static_cast(model())->task(indexAt(helpEvent->pos())); + if (task.isNull()) + return QListView::event(e); + showToolTip(task, helpEvent->globalPos()); + e->accept(); + return true; } -Link TaskView::locationForPos(const QPoint &pos) +void TaskView::showToolTip(const Task &task, const QPoint &pos) { - const auto delegate = qobject_cast(itemDelegate(indexAt(pos))); - if (!delegate) - return {}; - OutputFormatter formatter; - Link loc; - connect(&formatter, &OutputFormatter::openInEditorRequested, this, [&loc](const Link &link) { - loc = link; - }); - - const QString href = delegate->hrefForPos(pos); - if (!href.isEmpty()) - formatter.handleLink(href); - return loc; + const QString toolTip = task.toolTip(); + if (!toolTip.isEmpty()) { + const auto label = new QLabel(toolTip); + connect(label, &QLabel::linkActivated, [](const QString &link) { + Core::EditorManager::openEditorAt(OutputLineParser::parseLinkTarget(link), {}, + Core::EditorManager::SwitchSplitIfAlreadyVisible); + }); + const auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(label); + ToolTip::show(pos, layout); + } else { + ToolTip::hideImmediately(); + } } ///// @@ -339,8 +321,6 @@ TaskWindow::TaskWindow() : d(std::make_unique()) d->m_taskWindowContext->setContext(Core::Context(Core::Constants::C_PROBLEM_PANE)); Core::ICore::addContextObject(d->m_taskWindowContext); - connect(d->m_listview->selectionModel(), &QItemSelectionModel::currentChanged, - tld, &TaskDelegate::currentChanged); connect(d->m_listview->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex &index) { d->m_listview->scrollTo(index); }); connect(d->m_listview, &QAbstractItemView::activated, @@ -764,54 +744,19 @@ QSize TaskDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelInd QStyleOptionViewItem opt = option; initStyleOption(&opt, index); - auto view = qobject_cast(opt.widget); - const bool current = view->selectionModel()->currentIndex() == index; QSize s; s.setWidth(option.rect.width()); - if (!current && option.font == m_cachedFont && m_cachedHeight > 0) { + if (option.font == m_cachedFont && m_cachedHeight > 0) { s.setHeight(m_cachedHeight); return s; } - QFontMetrics fm(option.font); - int fontHeight = fm.height(); - int fontLeading = fm.leading(); - - auto model = static_cast(view->model())->taskModel(); - Positions positions(option, model); - - if (current) { - QString description = index.data(TaskModel::Description).toString(); - // Layout the description - int leading = fontLeading; - int height = 0; - description.replace(QLatin1Char('\n'), QChar::LineSeparator); - QTextLayout tl(description); - tl.setFormats(index.data(TaskModel::Task_t).value().formats); - tl.beginLayout(); - while (true) { - QTextLine line = tl.createLine(); - if (!line.isValid()) - break; - line.setLineWidth(positions.textAreaWidth()); - height += leading; - line.setPosition(QPoint(0, height)); - height += static_cast(line.height()); - } - tl.endLayout(); - - s.setHeight(height + leading + fontHeight + 3); - } else { - s.setHeight(fontHeight + 3); - } + s.setHeight(option.fontMetrics.height() + 3); if (s.height() < Positions::minimumHeight()) s.setHeight(Positions::minimumHeight()); - - if (!current) { - m_cachedHeight = s.height(); - m_cachedFont = option.font; - } + m_cachedHeight = s.height(); + m_cachedFont = option.font; return s; } @@ -821,22 +766,6 @@ void TaskDelegate::emitSizeHintChanged(const QModelIndex &index) emit sizeHintChanged(index); } -void TaskDelegate::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) -{ - m_hrefs.clear(); - emit sizeHintChanged(current); - emit sizeHintChanged(previous); -} - -QString TaskDelegate::hrefForPos(const QPointF &pos) -{ - for (const auto &link : std::as_const(m_hrefs)) { - if (link.first.contains(pos)) - return link.second; - } - return {}; -} - void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; @@ -849,7 +778,6 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, auto view = qobject_cast(opt.widget); const bool selected = view->selectionModel()->isSelected(index); - const bool current = view->selectionModel()->currentIndex() == index; if (selected) { painter->setBrush(opt.palette.highlight().color()); @@ -878,84 +806,17 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, icon.pixmap(Positions::taskIconWidth(), Positions::taskIconHeight())); // Paint TextArea: - if (!current) { - // in small mode we lay out differently - QString bottom = index.data(TaskModel::Description).toString().split(QLatin1Char('\n')).first(); - painter->setClipRect(positions.textArea()); - painter->drawText(positions.textAreaLeft(), positions.top() + fm.ascent(), bottom); - if (fm.horizontalAdvance(bottom) > positions.textAreaWidth()) { - // draw a gradient to mask the text - int gradientStart = positions.textAreaRight() - ELLIPSIS_GRADIENT_WIDTH + 1; - QLinearGradient lg(gradientStart, 0, gradientStart + ELLIPSIS_GRADIENT_WIDTH, 0); - lg.setColorAt(0, Qt::transparent); - lg.setColorAt(1, backgroundColor); - painter->fillRect(gradientStart, positions.top(), ELLIPSIS_GRADIENT_WIDTH, positions.firstLineHeight(), lg); - } - } else { - // Description - QString description = index.data(TaskModel::Description).toString(); - // Layout the description - int leading = fm.leading(); - int height = 0; - description.replace(QLatin1Char('\n'), QChar::LineSeparator); - QTextLayout tl(description); - QVector formats = index.data(TaskModel::Task_t).value().formats; - for (QTextLayout::FormatRange &format : formats) - format.format.setForeground(textColor); - tl.setFormats(formats); - tl.beginLayout(); - while (true) { - QTextLine line = tl.createLine(); - if (!line.isValid()) - break; - line.setLineWidth(positions.textAreaWidth()); - height += leading; - line.setPosition(QPoint(0, height)); - height += static_cast(line.height()); - } - tl.endLayout(); - const QPoint indexPos = view->visualRect(index).topLeft(); - tl.draw(painter, QPoint(positions.textAreaLeft(), positions.top())); - m_hrefs.clear(); - for (const auto &range : tl.formats()) { - if (!range.format.isAnchor()) - continue; - const QTextLine &firstLinkLine = tl.lineForTextPosition(range.start); - const QTextLine &lastLinkLine = tl.lineForTextPosition(range.start + range.length - 1); - for (int i = firstLinkLine.lineNumber(); i <= lastLinkLine.lineNumber(); ++i) { - const QTextLine &linkLine = tl.lineAt(i); - if (!linkLine.isValid()) - break; - const QPointF linePos = linkLine.position(); - const int linkStartPos = i == firstLinkLine.lineNumber() - ? range.start : linkLine.textStart(); - const qreal startOffset = linkLine.cursorToX(linkStartPos); - const int linkEndPos = i == lastLinkLine.lineNumber() - ? range.start + range.length - : linkLine.textStart() + linkLine.textLength(); - const qreal endOffset = linkLine.cursorToX(linkEndPos); - const QPointF linkPos(indexPos.x() + positions.textAreaLeft() + linePos.x() - + startOffset, positions.top() + linePos.y()); - const QSize linkSize(endOffset - startOffset, linkLine.height()); - const QRectF linkRect(linkPos, linkSize); - m_hrefs.push_back({linkRect, range.format.anchorHref()}); - } - } - - const QColor mix = StyleHelper::mergedColors(textColor, backgroundColor, 70); - const QString directory = QDir::toNativeSeparators(index.data(TaskModel::File).toString()); - int secondBaseLine = positions.top() + fm.ascent() + height + leading; - if (index.data(TaskModel::FileNotFound).toBool() && !directory.isEmpty()) { - const QString fileNotFound = Tr::tr("File not found: %1").arg(directory); - const QColor errorColor = selected ? mix : creatorTheme()->color(Theme::TextColorError); - painter->setPen(errorColor); - painter->drawText(positions.textAreaLeft(), secondBaseLine, fileNotFound); - } else { - painter->setPen(mix); - painter->drawText(positions.textAreaLeft(), secondBaseLine, directory); - } + QString bottom = index.data(TaskModel::Description).toString().split(QLatin1Char('\n')).first(); + painter->setClipRect(positions.textArea()); + painter->drawText(positions.textAreaLeft(), positions.top() + fm.ascent(), bottom); + if (fm.horizontalAdvance(bottom) > positions.textAreaWidth()) { + // draw a gradient to mask the text + int gradientStart = positions.textAreaRight() - ELLIPSIS_GRADIENT_WIDTH + 1; + QLinearGradient lg(gradientStart, 0, gradientStart + ELLIPSIS_GRADIENT_WIDTH, 0); + lg.setColorAt(0, Qt::transparent); + lg.setColorAt(1, backgroundColor); + painter->fillRect(gradientStart, positions.top(), ELLIPSIS_GRADIENT_WIDTH, positions.firstLineHeight(), lg); } - painter->setPen(textColor); // Paint FileArea QString file = index.data(TaskModel::File).toString(); diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index 63e339ca8b2..01746390ffe 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -12,11 +12,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -338,11 +340,18 @@ bool TextMark::addToolTipContent(QLayout *target) const } auto textLabel = new QLabel; - textLabel->setOpenExternalLinks(true); textLabel->setText(text); // Differentiate between tool tips that where explicitly set and default tool tips. textLabel->setDisabled(useDefaultToolTip); target->addWidget(textLabel); + QObject::connect(textLabel, &QLabel::linkActivated, [](const QString &link) { + if (OutputLineParser::isLinkTarget(link)) { + Core::EditorManager::openEditorAt(OutputLineParser::parseLinkTarget(link), {}, + Core::EditorManager::SwitchSplitIfAlreadyVisible); + } else { + QDesktopServices::openUrl(link); + } + }); return true; } From 82194d7e9cd8dbc18ef2fae33d87c3d0ce144059 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Feb 2023 12:45:15 +0100 Subject: [PATCH 0075/1447] Terminal: Add required 3rdparty libraries Change-Id: Ic477e305f78632f5c454cd639dfc7e41fb643fe1 Reviewed-by: Leena Miettinen Reviewed-by: hjk --- README.md | 92 + .../overview/creator-acknowledgements.qdoc | 44 + src/libs/3rdparty/CMakeLists.txt | 6 + src/libs/3rdparty/libptyqt/CMakeLists.txt | 28 + src/libs/3rdparty/libptyqt/LICENSE | 21 + src/libs/3rdparty/libptyqt/conptyprocess.cpp | 346 +++ src/libs/3rdparty/libptyqt/conptyprocess.h | 167 ++ src/libs/3rdparty/libptyqt/iptyprocess.h | 56 + src/libs/3rdparty/libptyqt/ptyqt.cpp | 45 + src/libs/3rdparty/libptyqt/ptyqt.h | 12 + src/libs/3rdparty/libptyqt/ptyqt.qbs | 45 + src/libs/3rdparty/libptyqt/unixptyprocess.cpp | 376 +++ src/libs/3rdparty/libptyqt/unixptyprocess.h | 66 + src/libs/3rdparty/libptyqt/winptyprocess.cpp | 275 ++ src/libs/3rdparty/libptyqt/winptyprocess.h | 42 + src/libs/3rdparty/libvterm/CMakeLists.txt | 25 + src/libs/3rdparty/libvterm/CONTRIBUTING | 22 + src/libs/3rdparty/libvterm/LICENSE | 23 + src/libs/3rdparty/libvterm/include/vterm.h | 635 +++++ .../libvterm/include/vterm_keycodes.h | 61 + src/libs/3rdparty/libvterm/src/encoding.c | 230 ++ .../libvterm/src/encoding/DECdrawing.inc | 36 + .../3rdparty/libvterm/src/encoding/uk.inc | 6 + src/libs/3rdparty/libvterm/src/fullwidth.inc | 111 + src/libs/3rdparty/libvterm/src/keyboard.c | 226 ++ src/libs/3rdparty/libvterm/src/mouse.c | 99 + src/libs/3rdparty/libvterm/src/parser.c | 402 +++ src/libs/3rdparty/libvterm/src/pen.c | 607 +++++ src/libs/3rdparty/libvterm/src/rect.h | 56 + src/libs/3rdparty/libvterm/src/screen.c | 1183 +++++++++ src/libs/3rdparty/libvterm/src/state.c | 2315 +++++++++++++++++ src/libs/3rdparty/libvterm/src/unicode.c | 313 +++ src/libs/3rdparty/libvterm/src/utf8.h | 39 + src/libs/3rdparty/libvterm/src/vterm.c | 429 +++ .../3rdparty/libvterm/src/vterm_internal.h | 296 +++ src/libs/3rdparty/libvterm/vterm.pc.in | 8 + src/libs/3rdparty/libvterm/vterm.qbs | 33 + src/libs/3rdparty/winpty/.gitattributes | 19 + src/libs/3rdparty/winpty/.gitignore | 16 + src/libs/3rdparty/winpty/CMakeLists.txt | 1 + src/libs/3rdparty/winpty/LICENSE | 21 + src/libs/3rdparty/winpty/README.md | 151 ++ src/libs/3rdparty/winpty/RELEASES.md | 280 ++ src/libs/3rdparty/winpty/VERSION.txt | 1 + src/libs/3rdparty/winpty/appveyor.yml | 16 + src/libs/3rdparty/winpty/configure | 167 ++ src/libs/3rdparty/winpty/misc/.gitignore | 2 + .../3rdparty/winpty/misc/BufferResizeTests.cc | 90 + .../winpty/misc/ChangeScreenBuffer.cc | 53 + src/libs/3rdparty/winpty/misc/ClearConsole.cc | 72 + src/libs/3rdparty/winpty/misc/ConinMode.cc | 117 + src/libs/3rdparty/winpty/misc/ConinMode.ps1 | 116 + src/libs/3rdparty/winpty/misc/ConoutMode.cc | 113 + src/libs/3rdparty/winpty/misc/DebugClient.py | 42 + src/libs/3rdparty/winpty/misc/DebugServer.py | 63 + src/libs/3rdparty/winpty/misc/DumpLines.py | 5 + .../winpty/misc/EnableExtendedFlags.txt | 46 + .../Font-Report-June2016/CP437-Consolas.txt | 528 ++++ .../Font-Report-June2016/CP437-Lucida.txt | 633 +++++ .../misc/Font-Report-June2016/CP932.txt | 630 +++++ .../misc/Font-Report-June2016/CP936.txt | 630 +++++ .../misc/Font-Report-June2016/CP949.txt | 630 +++++ .../misc/Font-Report-June2016/CP950.txt | 630 +++++ .../MinimumWindowWidths.txt | 16 + .../misc/Font-Report-June2016/Results.txt | 4 + .../Windows10SetFontBugginess.txt | 144 + src/libs/3rdparty/winpty/misc/FontSurvey.cc | 100 + src/libs/3rdparty/winpty/misc/FormatChar.h | 21 + .../3rdparty/winpty/misc/FreezePerfTest.cc | 62 + src/libs/3rdparty/winpty/misc/GetCh.cc | 20 + .../3rdparty/winpty/misc/GetConsolePos.cc | 41 + src/libs/3rdparty/winpty/misc/GetFont.cc | 261 ++ .../winpty/misc/IdentifyConsoleWindow.ps1 | 51 + src/libs/3rdparty/winpty/misc/IsNewConsole.cc | 87 + .../3rdparty/winpty/misc/MouseInputNotes.txt | 90 + .../3rdparty/winpty/misc/MoveConsoleWindow.cc | 34 + src/libs/3rdparty/winpty/misc/Notes.txt | 219 ++ src/libs/3rdparty/winpty/misc/OSVersion.cc | 27 + .../winpty/misc/ScreenBufferFreezeInactive.cc | 101 + .../3rdparty/winpty/misc/ScreenBufferTest.cc | 671 +++++ .../3rdparty/winpty/misc/ScreenBufferTest2.cc | 151 ++ .../3rdparty/winpty/misc/SelectAllTest.cc | 45 + src/libs/3rdparty/winpty/misc/SetBufInfo.cc | 90 + .../3rdparty/winpty/misc/SetBufferSize.cc | 32 + src/libs/3rdparty/winpty/misc/SetCursorPos.cc | 10 + src/libs/3rdparty/winpty/misc/SetFont.cc | 145 ++ .../3rdparty/winpty/misc/SetWindowRect.cc | 36 + src/libs/3rdparty/winpty/misc/ShowArgv.cc | 12 + .../3rdparty/winpty/misc/ShowConsoleInput.cc | 40 + src/libs/3rdparty/winpty/misc/Spew.py | 5 + src/libs/3rdparty/winpty/misc/TestUtil.cc | 172 ++ .../winpty/misc/UnicodeDoubleWidthTest.cc | 102 + .../3rdparty/winpty/misc/UnicodeWideTest1.cc | 246 ++ .../3rdparty/winpty/misc/UnicodeWideTest2.cc | 130 + src/libs/3rdparty/winpty/misc/UnixEcho.cc | 89 + src/libs/3rdparty/winpty/misc/Utf16Echo.cc | 46 + .../3rdparty/winpty/misc/VeryLargeRead.cc | 122 + src/libs/3rdparty/winpty/misc/VkEscapeTest.cc | 56 + .../winpty/misc/Win10ResizeWhileFrozen.cc | 52 + .../3rdparty/winpty/misc/Win10WrapTest1.cc | 57 + .../3rdparty/winpty/misc/Win10WrapTest2.cc | 30 + src/libs/3rdparty/winpty/misc/Win32Echo1.cc | 26 + src/libs/3rdparty/winpty/misc/Win32Echo2.cc | 19 + src/libs/3rdparty/winpty/misc/Win32Test1.cc | 46 + src/libs/3rdparty/winpty/misc/Win32Test2.cc | 70 + src/libs/3rdparty/winpty/misc/Win32Test3.cc | 78 + src/libs/3rdparty/winpty/misc/Win32Write1.cc | 44 + .../winpty/misc/WindowsBugCrashReader.cc | 27 + src/libs/3rdparty/winpty/misc/WriteConsole.cc | 106 + src/libs/3rdparty/winpty/misc/build32.sh | 9 + src/libs/3rdparty/winpty/misc/build64.sh | 9 + src/libs/3rdparty/winpty/misc/color-test.sh | 212 ++ src/libs/3rdparty/winpty/misc/font-notes.txt | 300 +++ src/libs/3rdparty/winpty/misc/winbug-15048.cc | 201 ++ .../winpty/ship/build-pty4j-libpty.bat | 36 + src/libs/3rdparty/winpty/ship/common_ship.py | 89 + .../3rdparty/winpty/ship/make_msvc_package.py | 163 ++ src/libs/3rdparty/winpty/ship/ship.py | 104 + src/libs/3rdparty/winpty/src/CMakeLists.txt | 112 + src/libs/3rdparty/winpty/src/agent/Agent.cc | 612 +++++ src/libs/3rdparty/winpty/src/agent/Agent.h | 103 + .../winpty/src/agent/AgentCreateDesktop.cc | 84 + .../winpty/src/agent/AgentCreateDesktop.h | 28 + .../3rdparty/winpty/src/agent/ConsoleFont.cc | 698 +++++ .../3rdparty/winpty/src/agent/ConsoleFont.h | 28 + .../3rdparty/winpty/src/agent/ConsoleInput.cc | 852 ++++++ .../3rdparty/winpty/src/agent/ConsoleInput.h | 109 + .../src/agent/ConsoleInputReencoding.cc | 121 + .../winpty/src/agent/ConsoleInputReencoding.h | 36 + .../3rdparty/winpty/src/agent/ConsoleLine.cc | 152 ++ .../3rdparty/winpty/src/agent/ConsoleLine.h | 41 + src/libs/3rdparty/winpty/src/agent/Coord.h | 87 + .../winpty/src/agent/DebugShowInput.cc | 239 ++ .../winpty/src/agent/DebugShowInput.h | 32 + .../winpty/src/agent/DefaultInputMap.cc | 422 +++ .../winpty/src/agent/DefaultInputMap.h | 28 + .../3rdparty/winpty/src/agent/DsrSender.h | 30 + .../3rdparty/winpty/src/agent/EventLoop.cc | 99 + .../3rdparty/winpty/src/agent/EventLoop.h | 47 + .../3rdparty/winpty/src/agent/InputMap.cc | 246 ++ src/libs/3rdparty/winpty/src/agent/InputMap.h | 114 + .../winpty/src/agent/LargeConsoleRead.cc | 71 + .../winpty/src/agent/LargeConsoleRead.h | 68 + .../3rdparty/winpty/src/agent/NamedPipe.cc | 378 +++ .../3rdparty/winpty/src/agent/NamedPipe.h | 125 + src/libs/3rdparty/winpty/src/agent/Scraper.cc | 699 +++++ src/libs/3rdparty/winpty/src/agent/Scraper.h | 103 + .../3rdparty/winpty/src/agent/SimplePool.h | 75 + .../3rdparty/winpty/src/agent/SmallRect.h | 143 + .../3rdparty/winpty/src/agent/Terminal.cc | 535 ++++ src/libs/3rdparty/winpty/src/agent/Terminal.h | 69 + .../winpty/src/agent/UnicodeEncoding.h | 157 ++ .../winpty/src/agent/UnicodeEncodingTest.cc | 189 ++ .../3rdparty/winpty/src/agent/Win32Console.cc | 107 + .../3rdparty/winpty/src/agent/Win32Console.h | 67 + .../winpty/src/agent/Win32ConsoleBuffer.cc | 193 ++ .../winpty/src/agent/Win32ConsoleBuffer.h | 99 + src/libs/3rdparty/winpty/src/agent/main.cc | 120 + src/libs/3rdparty/winpty/src/agent/subdir.mk | 61 + .../3rdparty/winpty/src/configurations.gypi | 60 + .../winpty/src/debugserver/DebugServer.cc | 117 + .../3rdparty/winpty/src/debugserver/subdir.mk | 41 + src/libs/3rdparty/winpty/src/include/winpty.h | 242 ++ .../winpty/src/include/winpty_constants.h | 131 + .../winpty/src/libwinpty/AgentLocation.cc | 75 + .../winpty/src/libwinpty/AgentLocation.h | 28 + .../winpty/src/libwinpty/LibWinptyException.h | 54 + .../winpty/src/libwinpty/WinptyInternal.h | 72 + .../3rdparty/winpty/src/libwinpty/subdir.mk | 46 + .../3rdparty/winpty/src/libwinpty/winpty.cc | 970 +++++++ .../3rdparty/winpty/src/shared/AgentMsg.h | 38 + .../winpty/src/shared/BackgroundDesktop.cc | 122 + .../winpty/src/shared/BackgroundDesktop.h | 73 + src/libs/3rdparty/winpty/src/shared/Buffer.cc | 103 + src/libs/3rdparty/winpty/src/shared/Buffer.h | 102 + .../3rdparty/winpty/src/shared/DebugClient.cc | 187 ++ .../3rdparty/winpty/src/shared/DebugClient.h | 38 + .../3rdparty/winpty/src/shared/GenRandom.cc | 138 + .../3rdparty/winpty/src/shared/GenRandom.h | 55 + .../winpty/src/shared/GetCommitHash.bat | 13 + src/libs/3rdparty/winpty/src/shared/Mutex.h | 54 + .../3rdparty/winpty/src/shared/OsModule.h | 63 + .../3rdparty/winpty/src/shared/OwnedHandle.cc | 36 + .../3rdparty/winpty/src/shared/OwnedHandle.h | 45 + .../winpty/src/shared/PrecompiledHeader.h | 43 + .../winpty/src/shared/StringBuilder.h | 227 ++ .../winpty/src/shared/StringBuilderTest.cc | 114 + .../3rdparty/winpty/src/shared/StringUtil.cc | 55 + .../3rdparty/winpty/src/shared/StringUtil.h | 80 + .../winpty/src/shared/TimeMeasurement.h | 63 + .../winpty/src/shared/UnixCtrlChars.h | 45 + .../winpty/src/shared/UpdateGenVersion.bat | 20 + .../winpty/src/shared/WindowsSecurity.cc | 460 ++++ .../winpty/src/shared/WindowsSecurity.h | 104 + .../winpty/src/shared/WindowsVersion.cc | 252 ++ .../winpty/src/shared/WindowsVersion.h | 29 + .../winpty/src/shared/WinptyAssert.cc | 55 + .../3rdparty/winpty/src/shared/WinptyAssert.h | 64 + .../winpty/src/shared/WinptyException.cc | 57 + .../winpty/src/shared/WinptyException.h | 43 + .../winpty/src/shared/WinptyVersion.cc | 42 + .../winpty/src/shared/WinptyVersion.h | 27 + .../winpty/src/shared/winpty_snprintf.h | 99 + src/libs/3rdparty/winpty/src/subdir.mk | 5 + src/libs/3rdparty/winpty/src/tests/subdir.mk | 28 + .../3rdparty/winpty/src/tests/trivial_test.cc | 158 ++ .../winpty/src/unix-adapter/InputHandler.cc | 114 + .../winpty/src/unix-adapter/InputHandler.h | 56 + .../winpty/src/unix-adapter/OutputHandler.cc | 80 + .../winpty/src/unix-adapter/OutputHandler.h | 53 + .../3rdparty/winpty/src/unix-adapter/Util.cc | 86 + .../3rdparty/winpty/src/unix-adapter/Util.h | 31 + .../winpty/src/unix-adapter/WakeupFd.cc | 70 + .../winpty/src/unix-adapter/WakeupFd.h | 42 + .../3rdparty/winpty/src/unix-adapter/main.cc | 729 ++++++ .../winpty/src/unix-adapter/subdir.mk | 41 + src/libs/3rdparty/winpty/src/winpty.gyp | 206 ++ src/libs/3rdparty/winpty/vcbuild.bat | 83 + src/libs/3rdparty/winpty/winpty.qbs | 207 ++ src/libs/libs.qbs | 3 + src/libs/qlitehtml | 2 +- src/shared/qbs | 2 +- 222 files changed, 33359 insertions(+), 2 deletions(-) create mode 100644 src/libs/3rdparty/libptyqt/CMakeLists.txt create mode 100644 src/libs/3rdparty/libptyqt/LICENSE create mode 100644 src/libs/3rdparty/libptyqt/conptyprocess.cpp create mode 100644 src/libs/3rdparty/libptyqt/conptyprocess.h create mode 100644 src/libs/3rdparty/libptyqt/iptyprocess.h create mode 100644 src/libs/3rdparty/libptyqt/ptyqt.cpp create mode 100644 src/libs/3rdparty/libptyqt/ptyqt.h create mode 100644 src/libs/3rdparty/libptyqt/ptyqt.qbs create mode 100644 src/libs/3rdparty/libptyqt/unixptyprocess.cpp create mode 100644 src/libs/3rdparty/libptyqt/unixptyprocess.h create mode 100644 src/libs/3rdparty/libptyqt/winptyprocess.cpp create mode 100644 src/libs/3rdparty/libptyqt/winptyprocess.h create mode 100644 src/libs/3rdparty/libvterm/CMakeLists.txt create mode 100644 src/libs/3rdparty/libvterm/CONTRIBUTING create mode 100644 src/libs/3rdparty/libvterm/LICENSE create mode 100644 src/libs/3rdparty/libvterm/include/vterm.h create mode 100644 src/libs/3rdparty/libvterm/include/vterm_keycodes.h create mode 100644 src/libs/3rdparty/libvterm/src/encoding.c create mode 100644 src/libs/3rdparty/libvterm/src/encoding/DECdrawing.inc create mode 100644 src/libs/3rdparty/libvterm/src/encoding/uk.inc create mode 100644 src/libs/3rdparty/libvterm/src/fullwidth.inc create mode 100644 src/libs/3rdparty/libvterm/src/keyboard.c create mode 100644 src/libs/3rdparty/libvterm/src/mouse.c create mode 100644 src/libs/3rdparty/libvterm/src/parser.c create mode 100644 src/libs/3rdparty/libvterm/src/pen.c create mode 100644 src/libs/3rdparty/libvterm/src/rect.h create mode 100644 src/libs/3rdparty/libvterm/src/screen.c create mode 100644 src/libs/3rdparty/libvterm/src/state.c create mode 100644 src/libs/3rdparty/libvterm/src/unicode.c create mode 100644 src/libs/3rdparty/libvterm/src/utf8.h create mode 100644 src/libs/3rdparty/libvterm/src/vterm.c create mode 100644 src/libs/3rdparty/libvterm/src/vterm_internal.h create mode 100644 src/libs/3rdparty/libvterm/vterm.pc.in create mode 100644 src/libs/3rdparty/libvterm/vterm.qbs create mode 100644 src/libs/3rdparty/winpty/.gitattributes create mode 100644 src/libs/3rdparty/winpty/.gitignore create mode 100644 src/libs/3rdparty/winpty/CMakeLists.txt create mode 100644 src/libs/3rdparty/winpty/LICENSE create mode 100644 src/libs/3rdparty/winpty/README.md create mode 100644 src/libs/3rdparty/winpty/RELEASES.md create mode 100644 src/libs/3rdparty/winpty/VERSION.txt create mode 100644 src/libs/3rdparty/winpty/appveyor.yml create mode 100644 src/libs/3rdparty/winpty/configure create mode 100644 src/libs/3rdparty/winpty/misc/.gitignore create mode 100644 src/libs/3rdparty/winpty/misc/BufferResizeTests.cc create mode 100644 src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc create mode 100644 src/libs/3rdparty/winpty/misc/ClearConsole.cc create mode 100644 src/libs/3rdparty/winpty/misc/ConinMode.cc create mode 100644 src/libs/3rdparty/winpty/misc/ConinMode.ps1 create mode 100644 src/libs/3rdparty/winpty/misc/ConoutMode.cc create mode 100644 src/libs/3rdparty/winpty/misc/DebugClient.py create mode 100644 src/libs/3rdparty/winpty/misc/DebugServer.py create mode 100644 src/libs/3rdparty/winpty/misc/DumpLines.py create mode 100644 src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt create mode 100644 src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt create mode 100644 src/libs/3rdparty/winpty/misc/FontSurvey.cc create mode 100644 src/libs/3rdparty/winpty/misc/FormatChar.h create mode 100644 src/libs/3rdparty/winpty/misc/FreezePerfTest.cc create mode 100644 src/libs/3rdparty/winpty/misc/GetCh.cc create mode 100644 src/libs/3rdparty/winpty/misc/GetConsolePos.cc create mode 100644 src/libs/3rdparty/winpty/misc/GetFont.cc create mode 100644 src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps1 create mode 100644 src/libs/3rdparty/winpty/misc/IsNewConsole.cc create mode 100644 src/libs/3rdparty/winpty/misc/MouseInputNotes.txt create mode 100644 src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc create mode 100644 src/libs/3rdparty/winpty/misc/Notes.txt create mode 100644 src/libs/3rdparty/winpty/misc/OSVersion.cc create mode 100644 src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc create mode 100644 src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc create mode 100644 src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc create mode 100644 src/libs/3rdparty/winpty/misc/SelectAllTest.cc create mode 100644 src/libs/3rdparty/winpty/misc/SetBufInfo.cc create mode 100644 src/libs/3rdparty/winpty/misc/SetBufferSize.cc create mode 100644 src/libs/3rdparty/winpty/misc/SetCursorPos.cc create mode 100644 src/libs/3rdparty/winpty/misc/SetFont.cc create mode 100644 src/libs/3rdparty/winpty/misc/SetWindowRect.cc create mode 100644 src/libs/3rdparty/winpty/misc/ShowArgv.cc create mode 100644 src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc create mode 100644 src/libs/3rdparty/winpty/misc/Spew.py create mode 100644 src/libs/3rdparty/winpty/misc/TestUtil.cc create mode 100644 src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc create mode 100644 src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc create mode 100644 src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc create mode 100644 src/libs/3rdparty/winpty/misc/UnixEcho.cc create mode 100644 src/libs/3rdparty/winpty/misc/Utf16Echo.cc create mode 100644 src/libs/3rdparty/winpty/misc/VeryLargeRead.cc create mode 100644 src/libs/3rdparty/winpty/misc/VkEscapeTest.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win32Echo1.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win32Echo2.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win32Test1.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win32Test2.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win32Test3.cc create mode 100644 src/libs/3rdparty/winpty/misc/Win32Write1.cc create mode 100644 src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc create mode 100644 src/libs/3rdparty/winpty/misc/WriteConsole.cc create mode 100644 src/libs/3rdparty/winpty/misc/build32.sh create mode 100644 src/libs/3rdparty/winpty/misc/build64.sh create mode 100644 src/libs/3rdparty/winpty/misc/color-test.sh create mode 100644 src/libs/3rdparty/winpty/misc/font-notes.txt create mode 100644 src/libs/3rdparty/winpty/misc/winbug-15048.cc create mode 100644 src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat create mode 100644 src/libs/3rdparty/winpty/ship/common_ship.py create mode 100644 src/libs/3rdparty/winpty/ship/make_msvc_package.py create mode 100644 src/libs/3rdparty/winpty/ship/ship.py create mode 100644 src/libs/3rdparty/winpty/src/CMakeLists.txt create mode 100644 src/libs/3rdparty/winpty/src/agent/Agent.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/Agent.h create mode 100644 src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleFont.h create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleInput.h create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/ConsoleLine.h create mode 100644 src/libs/3rdparty/winpty/src/agent/Coord.h create mode 100644 src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/DebugShowInput.h create mode 100644 src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h create mode 100644 src/libs/3rdparty/winpty/src/agent/DsrSender.h create mode 100644 src/libs/3rdparty/winpty/src/agent/EventLoop.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/EventLoop.h create mode 100644 src/libs/3rdparty/winpty/src/agent/InputMap.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/InputMap.h create mode 100644 src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h create mode 100644 src/libs/3rdparty/winpty/src/agent/NamedPipe.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/NamedPipe.h create mode 100644 src/libs/3rdparty/winpty/src/agent/Scraper.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/Scraper.h create mode 100644 src/libs/3rdparty/winpty/src/agent/SimplePool.h create mode 100644 src/libs/3rdparty/winpty/src/agent/SmallRect.h create mode 100644 src/libs/3rdparty/winpty/src/agent/Terminal.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/Terminal.h create mode 100644 src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h create mode 100644 src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/Win32Console.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/Win32Console.h create mode 100644 src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h create mode 100644 src/libs/3rdparty/winpty/src/agent/main.cc create mode 100644 src/libs/3rdparty/winpty/src/agent/subdir.mk create mode 100644 src/libs/3rdparty/winpty/src/configurations.gypi create mode 100644 src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc create mode 100644 src/libs/3rdparty/winpty/src/debugserver/subdir.mk create mode 100644 src/libs/3rdparty/winpty/src/include/winpty.h create mode 100644 src/libs/3rdparty/winpty/src/include/winpty_constants.h create mode 100644 src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc create mode 100644 src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h create mode 100644 src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h create mode 100644 src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h create mode 100644 src/libs/3rdparty/winpty/src/libwinpty/subdir.mk create mode 100644 src/libs/3rdparty/winpty/src/libwinpty/winpty.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/AgentMsg.h create mode 100644 src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h create mode 100644 src/libs/3rdparty/winpty/src/shared/Buffer.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/Buffer.h create mode 100644 src/libs/3rdparty/winpty/src/shared/DebugClient.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/DebugClient.h create mode 100644 src/libs/3rdparty/winpty/src/shared/GenRandom.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/GenRandom.h create mode 100644 src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat create mode 100644 src/libs/3rdparty/winpty/src/shared/Mutex.h create mode 100644 src/libs/3rdparty/winpty/src/shared/OsModule.h create mode 100644 src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/OwnedHandle.h create mode 100644 src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h create mode 100644 src/libs/3rdparty/winpty/src/shared/StringBuilder.h create mode 100644 src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/StringUtil.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/StringUtil.h create mode 100644 src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h create mode 100644 src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h create mode 100644 src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat create mode 100644 src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h create mode 100644 src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/WindowsVersion.h create mode 100644 src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/WinptyAssert.h create mode 100644 src/libs/3rdparty/winpty/src/shared/WinptyException.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/WinptyException.h create mode 100644 src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc create mode 100644 src/libs/3rdparty/winpty/src/shared/WinptyVersion.h create mode 100644 src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h create mode 100644 src/libs/3rdparty/winpty/src/subdir.mk create mode 100644 src/libs/3rdparty/winpty/src/tests/subdir.mk create mode 100644 src/libs/3rdparty/winpty/src/tests/trivial_test.cc create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/Util.cc create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/Util.h create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/main.cc create mode 100644 src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk create mode 100644 src/libs/3rdparty/winpty/src/winpty.gyp create mode 100644 src/libs/3rdparty/winpty/vcbuild.bat create mode 100644 src/libs/3rdparty/winpty/winpty.qbs diff --git a/README.md b/README.md index 73963e434ad..c58acc13f83 100644 --- a/README.md +++ b/README.md @@ -721,3 +721,95 @@ SQLite (https://www.sqlite.org) is in the Public Domain. public domain worldwide. This software is distributed without any warranty. http://creativecommons.org/publicdomain/zero/1.0/ + +### WinPty + + Implementation of a pseudo terminal for Windows. + + https://github.com/rprichard/winpty + + The MIT License (MIT) + + Copyright (c) 2011-2016 Ryan Prichard + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + + +### ptyqt + + Pty-Qt is small library for access to console applications by pseudo-terminal interface on Mac, + Linux and Windows. On Mac and Linux it uses standard PseudoTerminal API and on Windows it uses + WinPty(prefer) or ConPty. + + https://github.com/kafeg/ptyqt + + MIT License + + Copyright (c) 2019 Vitaly Petrov, v31337@gmail.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +### libvterm + + + An abstract C99 library which implements a VT220 or xterm-like terminal emulator. + It doesn't use any particular graphics toolkit or output system, instead it invokes callback + function pointers that its embedding program should provide it to draw on its behalf. + It avoids calling malloc() during normal running state, allowing it to be used in embedded kernel + situations. + + https://www.leonerd.org.uk/code/libvterm/ + + The MIT License + + Copyright (c) 2008 Paul Evans + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc index 2ef5125bab2..29b006985d1 100644 --- a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc +++ b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc @@ -1002,5 +1002,49 @@ https://creativecommons.org/publicdomain/zero/1.0/ + \li \b WinPty + + Implementation of a pseudo terminal for Windows. + + The sources can be found in: + \list + \li \l https://github.com/rprichard/winpty + \endlist + + Distributed under the MIT license. + + \include license-mit.qdocinc + + \li \b ptyqt + + Pty-Qt is small library for access to console applications by a + pseudo-terminal interface on \macos, Linux and Windows. On \macos and + Linux it uses standard PseudoTerminal API and on Windows it uses + WinPty or ConPty. + + \list + \li \l https://github.com/kafeg/ptyqt + \endlist + + Distributed under the MIT license. + + \include license-mit.qdocinc + + \li \b libvterm + + An abstract C99 library, which implements a VT220 or xterm-like terminal + emulator. It doesn't use any particular graphics toolkit or output + system. Instead it invokes callback function pointers that its embedding + program should provide to draw on its behalf. It avoids calling malloc() + during normal running state, allowing it to be used in embedded kernels. + + \list + \li \l https://www.leonerd.org.uk/code/libvterm/ + \endlist + + Distributed under the MIT license. + + \include license-mit.qdocinc + \endlist */ diff --git a/src/libs/3rdparty/CMakeLists.txt b/src/libs/3rdparty/CMakeLists.txt index 7cf97ab87fc..0cf9818ed54 100644 --- a/src/libs/3rdparty/CMakeLists.txt +++ b/src/libs/3rdparty/CMakeLists.txt @@ -1,2 +1,8 @@ add_subdirectory(cplusplus) add_subdirectory(syntax-highlighting) +add_subdirectory(libvterm) +add_subdirectory(libptyqt) + +if(WIN32) + add_subdirectory(winpty) +endif() diff --git a/src/libs/3rdparty/libptyqt/CMakeLists.txt b/src/libs/3rdparty/libptyqt/CMakeLists.txt new file mode 100644 index 00000000000..c6e8b745737 --- /dev/null +++ b/src/libs/3rdparty/libptyqt/CMakeLists.txt @@ -0,0 +1,28 @@ +set(SOURCES + iptyprocess.h + ptyqt.cpp ptyqt.h +) + +if (WIN32) + list(APPEND SOURCES + winptyprocess.cpp winptyprocess.h + conptyprocess.cpp conptyprocess.h + ) +else() + list(APPEND SOURCES unixptyprocess.cpp unixptyprocess.h) +endif() + +add_library(ptyqt STATIC ${SOURCES}) +target_link_libraries(ptyqt PUBLIC Qt::Core) + +if (WIN32) + target_link_libraries(ptyqt PRIVATE winpty Qt::Network) + #target_compile_definitions(ptyqt PRIVATE PTYQT_DEBUG) +endif() + +set_target_properties(ptyqt + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} + QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON + POSITION_INDEPENDENT_CODE ON +) diff --git a/src/libs/3rdparty/libptyqt/LICENSE b/src/libs/3rdparty/libptyqt/LICENSE new file mode 100644 index 00000000000..73996c7c90e --- /dev/null +++ b/src/libs/3rdparty/libptyqt/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Vitaly Petrov, v31337@gmail.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.cpp b/src/libs/3rdparty/libptyqt/conptyprocess.cpp new file mode 100644 index 00000000000..b50f319ebf1 --- /dev/null +++ b/src/libs/3rdparty/libptyqt/conptyprocess.cpp @@ -0,0 +1,346 @@ +#include "conptyprocess.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +#define READ_INTERVAL_MSEC 500 + +HRESULT ConPtyProcess::createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows) +{ + HRESULT hr{ E_UNEXPECTED }; + HANDLE hPipePTYIn{ INVALID_HANDLE_VALUE }; + HANDLE hPipePTYOut{ INVALID_HANDLE_VALUE }; + + // Create the pipes to which the ConPTY will connect + if (CreatePipe(&hPipePTYIn, phPipeOut, NULL, 0) && + CreatePipe(phPipeIn, &hPipePTYOut, NULL, 0)) + { + // Create the Pseudo Console of the required size, attached to the PTY-end of the pipes + hr = m_winContext.createPseudoConsole({cols, rows}, hPipePTYIn, hPipePTYOut, 0, phPC); + + // Note: We can close the handles to the PTY-end of the pipes here + // because the handles are dup'ed into the ConHost and will be released + // when the ConPTY is destroyed. + if (INVALID_HANDLE_VALUE != hPipePTYOut) CloseHandle(hPipePTYOut); + if (INVALID_HANDLE_VALUE != hPipePTYIn) CloseHandle(hPipePTYIn); + } + + return hr; +} + +// Initializes the specified startup info struct with the required properties and +// updates its thread attribute list with the specified ConPTY handle +HRESULT ConPtyProcess::initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC) +{ + HRESULT hr{ E_UNEXPECTED }; + + if (pStartupInfo) + { + SIZE_T attrListSize{}; + + pStartupInfo->StartupInfo.hStdInput = m_hPipeIn; + pStartupInfo->StartupInfo.hStdError = m_hPipeOut; + pStartupInfo->StartupInfo.hStdOutput = m_hPipeOut; + pStartupInfo->StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + + pStartupInfo->StartupInfo.cb = sizeof(STARTUPINFOEX); + + // Get the size of the thread attribute list. + InitializeProcThreadAttributeList(NULL, 1, 0, &attrListSize); + + // Allocate a thread attribute list of the correct size + pStartupInfo->lpAttributeList = reinterpret_cast( + HeapAlloc(GetProcessHeap(), 0, attrListSize)); + + // Initialize thread attribute list + if (pStartupInfo->lpAttributeList + && InitializeProcThreadAttributeList(pStartupInfo->lpAttributeList, 1, 0, &attrListSize)) + { + // Set Pseudo Console attribute + hr = UpdateProcThreadAttribute( + pStartupInfo->lpAttributeList, + 0, + PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + hPC, + sizeof(HPCON), + NULL, + NULL) + ? S_OK + : HRESULT_FROM_WIN32(GetLastError()); + } + else + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + } + return hr; +} + +ConPtyProcess::ConPtyProcess() + : IPtyProcess() + , m_ptyHandler { INVALID_HANDLE_VALUE } + , m_hPipeIn { INVALID_HANDLE_VALUE } + , m_hPipeOut { INVALID_HANDLE_VALUE } + , m_readThread(nullptr) +{ + +} + +ConPtyProcess::~ConPtyProcess() +{ + kill(); +} + +bool ConPtyProcess::startProcess(const QString &executable, + const QStringList &arguments, + const QString &workingDir, + QStringList environment, + qint16 cols, + qint16 rows) +{ + if (!isAvailable()) + { + m_lastError = m_winContext.lastError(); + return false; + } + + //already running + if (m_ptyHandler != INVALID_HANDLE_VALUE) + return false; + + QFileInfo fi(executable); + if (fi.isRelative() || !QFile::exists(executable)) { + //todo add auto-find executable in PATH env var + m_lastError = QString("ConPty Error: shell file path '%1' must be absolute").arg(executable); + return false; + } + + m_shellPath = executable; + m_size = QPair(cols, rows); + + //env + std::wstringstream envBlock; + for (const QString &line: std::as_const(environment)) + { + envBlock << line.toStdWString() << L'\0'; + } + envBlock << L'\0'; + std::wstring env = envBlock.str(); + LPWSTR envArg = env.empty() ? nullptr : env.data(); + + QStringList exeAndArgs = arguments; + exeAndArgs.prepend(m_shellPath); + + std::wstring cmdArg = exeAndArgs.join(" ").toStdWString(); + + HRESULT hr{ E_UNEXPECTED }; + + // Create the Pseudo Console and pipes to it + hr = createPseudoConsoleAndPipes(&m_ptyHandler, &m_hPipeIn, &m_hPipeOut, cols, rows); + + if (S_OK != hr) + { + m_lastError = QString("ConPty Error: CreatePseudoConsoleAndPipes fail"); + return false; + } + + // Initialize the necessary startup info struct + if (S_OK != initializeStartupInfoAttachedToPseudoConsole(&m_shellStartupInfo, m_ptyHandler)) + { + m_lastError = QString("ConPty Error: InitializeStartupInfoAttachedToPseudoConsole fail"); + return false; + } + + hr = CreateProcess(NULL, // No module name - use Command Line + cmdArg.data(), // Command Line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + FALSE, // Inherit handles + EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // Creation flags + envArg, // Environment block + workingDir.toStdWString().c_str(), // Use parent's starting directory + &m_shellStartupInfo.StartupInfo, // Pointer to STARTUPINFO + &m_shellProcessInformation) // Pointer to PROCESS_INFORMATION + ? S_OK + : GetLastError(); + + if (S_OK != hr) + { + m_lastError = QString("ConPty Error: Cannot create process -> %1").arg(hr); + return false; + } + + m_pid = m_shellProcessInformation.dwProcessId; + + // Notify when the shell process has been terminated + RegisterWaitForSingleObject( + &m_shellCloseWaitHandle, + m_shellProcessInformation.hProcess, + [](PVOID data, BOOLEAN) { + auto self = static_cast(data); + DWORD exitCode = 0; + GetExitCodeProcess(self->m_shellProcessInformation.hProcess, &exitCode); + self->m_exitCode = exitCode; + // Do not respawn if the object is about to be destructed + if (!self->m_aboutToDestruct) + emit self->notifier()->aboutToClose(); + }, + this, + INFINITE, + WT_EXECUTEONLYONCE); + + //this code runned in separate thread + m_readThread = QThread::create([this]() + { + //buffers + const DWORD BUFF_SIZE{ 1024 }; + char szBuffer[BUFF_SIZE]{}; + + forever + { + DWORD dwBytesRead{}; + + // Read from the pipe + BOOL result = ReadFile(m_hPipeIn, szBuffer, BUFF_SIZE, &dwBytesRead, NULL); + + const bool needMoreData = !result && GetLastError() == ERROR_MORE_DATA; + if (result || needMoreData) { + QMutexLocker locker(&m_bufferMutex); + m_buffer.m_readBuffer.append(szBuffer, dwBytesRead); + m_buffer.emitReadyRead(); + } + + const bool brokenPipe = !result && GetLastError() == ERROR_BROKEN_PIPE; + if (QThread::currentThread()->isInterruptionRequested() || brokenPipe) + break; + } + }); + + //start read thread + m_readThread->start(); + + return true; +} + +bool ConPtyProcess::resize(qint16 cols, qint16 rows) +{ + if (m_ptyHandler == nullptr) + { + return false; + } + + bool res = SUCCEEDED(m_winContext.resizePseudoConsole(m_ptyHandler, {cols, rows})); + + if (res) + { + m_size = QPair(cols, rows); + } + + return res; + + return true; +} + +bool ConPtyProcess::kill() +{ + bool exitCode = false; + + if (m_ptyHandler != INVALID_HANDLE_VALUE) { + m_aboutToDestruct = true; + + // Close ConPTY - this will terminate client process if running + m_winContext.closePseudoConsole(m_ptyHandler); + + // Clean-up the pipes + if (INVALID_HANDLE_VALUE != m_hPipeOut) + CloseHandle(m_hPipeOut); + if (INVALID_HANDLE_VALUE != m_hPipeIn) + CloseHandle(m_hPipeIn); + + m_readThread->requestInterruption(); + if (!m_readThread->wait(1000)) + m_readThread->terminate(); + m_readThread->deleteLater(); + m_readThread = nullptr; + + m_pid = 0; + m_ptyHandler = INVALID_HANDLE_VALUE; + m_hPipeIn = INVALID_HANDLE_VALUE; + m_hPipeOut = INVALID_HANDLE_VALUE; + + CloseHandle(m_shellProcessInformation.hThread); + CloseHandle(m_shellProcessInformation.hProcess); + UnregisterWait(m_shellCloseWaitHandle); + + // Cleanup attribute list + if (m_shellStartupInfo.lpAttributeList) { + DeleteProcThreadAttributeList(m_shellStartupInfo.lpAttributeList); + HeapFree(GetProcessHeap(), 0, m_shellStartupInfo.lpAttributeList); + } + + exitCode = true; + } + + return exitCode; +} + +IPtyProcess::PtyType ConPtyProcess::type() +{ + return PtyType::ConPty; +} + +QString ConPtyProcess::dumpDebugInfo() +{ +#ifdef PTYQT_DEBUG + return QString("PID: %1, Type: %2, Cols: %3, Rows: %4") + .arg(m_pid).arg(type()) + .arg(m_size.first).arg(m_size.second); +#else + return QString("Nothing..."); +#endif +} + +QIODevice *ConPtyProcess::notifier() +{ + return &m_buffer; +} + +QByteArray ConPtyProcess::readAll() +{ + QByteArray result; + { + QMutexLocker locker(&m_bufferMutex); + result.swap(m_buffer.m_readBuffer); + } + return result; +} + +qint64 ConPtyProcess::write(const QByteArray &byteArray) +{ + DWORD dwBytesWritten{}; + WriteFile(m_hPipeOut, byteArray.data(), byteArray.size(), &dwBytesWritten, NULL); + return dwBytesWritten; +} + +bool ConPtyProcess::isAvailable() +{ +#ifdef TOO_OLD_WINSDK + return false; //very importnant! ConPty can be built, but it doesn't work if built with old sdk and Win10 < 1903 +#endif + + qint32 buildNumber = QSysInfo::kernelVersion().split(".").last().toInt(); + if (buildNumber < CONPTY_MINIMAL_WINDOWS_VERSION) + return false; + return m_winContext.init(); +} + +void ConPtyProcess::moveToThread(QThread *targetThread) +{ + //nothing for now... +} diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.h b/src/libs/3rdparty/libptyqt/conptyprocess.h new file mode 100644 index 00000000000..b3f77664c26 --- /dev/null +++ b/src/libs/3rdparty/libptyqt/conptyprocess.h @@ -0,0 +1,167 @@ +#ifndef CONPTYPROCESS_H +#define CONPTYPROCESS_H + +#include "iptyprocess.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +//Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17733 +//Just for compile, ConPty doesn't work with Windows SDK < 17733 +#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE +#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE \ + ProcThreadAttributeValue(22, FALSE, TRUE, FALSE) + +typedef VOID* HPCON; + +#define TOO_OLD_WINSDK +#endif + +template +std::vector vectorFromString(const std::basic_string &str) +{ + return std::vector(str.begin(), str.end()); +} + +//ConPTY available only on Windows 10 releazed after 1903 (19H1) Windows release +class WindowsContext +{ +public: + typedef HRESULT (*CreatePseudoConsolePtr)( + COORD size, // ConPty Dimensions + HANDLE hInput, // ConPty Input + HANDLE hOutput, // ConPty Output + DWORD dwFlags, // ConPty Flags + HPCON* phPC); // ConPty Reference + + typedef HRESULT (*ResizePseudoConsolePtr)(HPCON hPC, COORD size); + + typedef VOID (*ClosePseudoConsolePtr)(HPCON hPC); + + WindowsContext() + : createPseudoConsole(nullptr) + , resizePseudoConsole(nullptr) + , closePseudoConsole(nullptr) + { + + } + + bool init() + { + //already initialized + if (createPseudoConsole) + return true; + + //try to load symbols from library + //if it fails -> we can't use ConPty API + HANDLE kernel32Handle = LoadLibraryExW(L"kernel32.dll", 0, 0); + + if (kernel32Handle != nullptr) + { + createPseudoConsole = (CreatePseudoConsolePtr)GetProcAddress((HMODULE)kernel32Handle, "CreatePseudoConsole"); + resizePseudoConsole = (ResizePseudoConsolePtr)GetProcAddress((HMODULE)kernel32Handle, "ResizePseudoConsole"); + closePseudoConsole = (ClosePseudoConsolePtr)GetProcAddress((HMODULE)kernel32Handle, "ClosePseudoConsole"); + if (createPseudoConsole == NULL || resizePseudoConsole == NULL || closePseudoConsole == NULL) + { + m_lastError = QString("WindowsContext/ConPty error: %1").arg("Invalid on load API functions"); + return false; + } + } + else + { + m_lastError = QString("WindowsContext/ConPty error: %1").arg("Unable to load kernel32"); + return false; + } + + return true; + } + + QString lastError() + { + return m_lastError; + } + +public: + //vars + CreatePseudoConsolePtr createPseudoConsole; + ResizePseudoConsolePtr resizePseudoConsole; + ClosePseudoConsolePtr closePseudoConsole; + +private: + QString m_lastError; +}; + +class PtyBuffer : public QIODevice +{ + friend class ConPtyProcess; + Q_OBJECT +public: + + //just empty realization, we need only 'readyRead' signal of this class + qint64 readData(char *data, qint64 maxlen) { return 0; } + qint64 writeData(const char *data, qint64 len) { return 0; } + + bool isSequential() const { return true; } + qint64 bytesAvailable() const { return m_readBuffer.size(); } + qint64 size() const { return m_readBuffer.size(); } + + void emitReadyRead() + { + //for emit signal from PtyBuffer own thread + QTimer::singleShot(1, this, [this]() + { + emit readyRead(); + }); + } + +private: + QByteArray m_readBuffer; +}; + +class ConPtyProcess : public IPtyProcess +{ +public: + ConPtyProcess(); + ~ConPtyProcess(); + + bool startProcess(const QString &executable, + const QStringList &arguments, + const QString &workingDir, + QStringList environment, + qint16 cols, + qint16 rows); + bool resize(qint16 cols, qint16 rows); + bool kill(); + PtyType type(); + QString dumpDebugInfo(); + virtual QIODevice *notifier(); + virtual QByteArray readAll(); + virtual qint64 write(const QByteArray &byteArray); + bool isAvailable(); + void moveToThread(QThread *targetThread); + +private: + HRESULT createPseudoConsoleAndPipes(HPCON* phPC, HANDLE* phPipeIn, HANDLE* phPipeOut, qint16 cols, qint16 rows); + HRESULT initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX* pStartupInfo, HPCON hPC); + +private: + WindowsContext m_winContext; + HPCON m_ptyHandler; + HANDLE m_hPipeIn, m_hPipeOut; + + QThread *m_readThread; + QMutex m_bufferMutex; + PtyBuffer m_buffer; + bool m_aboutToDestruct{false}; + PROCESS_INFORMATION m_shellProcessInformation{}; + HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE}; + STARTUPINFOEX m_shellStartupInfo{}; +}; + +#endif // CONPTYPROCESS_H diff --git a/src/libs/3rdparty/libptyqt/iptyprocess.h b/src/libs/3rdparty/libptyqt/iptyprocess.h new file mode 100644 index 00000000000..3d974908c86 --- /dev/null +++ b/src/libs/3rdparty/libptyqt/iptyprocess.h @@ -0,0 +1,56 @@ +#ifndef IPTYPROCESS_H +#define IPTYPROCESS_H + +#include +#include +#include + +#define CONPTY_MINIMAL_WINDOWS_VERSION 18309 + +class IPtyProcess +{ +public: + enum PtyType { UnixPty = 0, WinPty = 1, ConPty = 2, AutoPty = 3 }; + + IPtyProcess() = default; + IPtyProcess(const IPtyProcess &) = delete; + IPtyProcess &operator=(const IPtyProcess &) = delete; + + virtual ~IPtyProcess() {} + + virtual bool startProcess(const QString &executable, + const QStringList &arguments, + const QString &workingDir, + QStringList environment, + qint16 cols, + qint16 rows) + = 0; + virtual bool resize(qint16 cols, qint16 rows) = 0; + virtual bool kill() = 0; + virtual PtyType type() = 0; + virtual QString dumpDebugInfo() = 0; + virtual QIODevice *notifier() = 0; + virtual QByteArray readAll() = 0; + virtual qint64 write(const QByteArray &byteArray) = 0; + virtual bool isAvailable() = 0; + virtual void moveToThread(QThread *targetThread) = 0; + qint64 pid() { return m_pid; } + QPair size() { return m_size; } + const QString lastError() { return m_lastError; } + int exitCode() { return m_exitCode; } + bool toggleTrace() + { + m_trace = !m_trace; + return m_trace; + } + +protected: + QString m_shellPath; + QString m_lastError; + qint64 m_pid{0}; + int m_exitCode{0}; + QPair m_size; //cols / rows + bool m_trace{false}; +}; + +#endif // IPTYPROCESS_H diff --git a/src/libs/3rdparty/libptyqt/ptyqt.cpp b/src/libs/3rdparty/libptyqt/ptyqt.cpp new file mode 100644 index 00000000000..3883395e22d --- /dev/null +++ b/src/libs/3rdparty/libptyqt/ptyqt.cpp @@ -0,0 +1,45 @@ +#include "ptyqt.h" +#include + +#ifdef Q_OS_WIN +#include "winptyprocess.h" +#include "conptyprocess.h" +#endif + +#ifdef Q_OS_UNIX +#include "unixptyprocess.h" +#endif + + +IPtyProcess *PtyQt::createPtyProcess(IPtyProcess::PtyType ptyType) +{ + switch (ptyType) + { +#ifdef Q_OS_WIN + case IPtyProcess::PtyType::WinPty: + return new WinPtyProcess(); + break; + case IPtyProcess::PtyType::ConPty: + return new ConPtyProcess(); + break; +#endif +#ifdef Q_OS_UNIX + case IPtyProcess::PtyType::UnixPty: + return new UnixPtyProcess(); + break; +#endif + case IPtyProcess::PtyType::AutoPty: + default: + break; + } + +#ifdef Q_OS_WIN + if (ConPtyProcess().isAvailable()) + return new ConPtyProcess(); + else + return new WinPtyProcess(); +#endif +#ifdef Q_OS_UNIX + return new UnixPtyProcess(); +#endif +} diff --git a/src/libs/3rdparty/libptyqt/ptyqt.h b/src/libs/3rdparty/libptyqt/ptyqt.h new file mode 100644 index 00000000000..23b80d346bb --- /dev/null +++ b/src/libs/3rdparty/libptyqt/ptyqt.h @@ -0,0 +1,12 @@ +#ifndef PTYQT_H +#define PTYQT_H + +#include "iptyprocess.h" + +class PtyQt +{ +public: + static IPtyProcess *createPtyProcess(IPtyProcess::PtyType ptyType); +}; + +#endif // PTYQT_H diff --git a/src/libs/3rdparty/libptyqt/ptyqt.qbs b/src/libs/3rdparty/libptyqt/ptyqt.qbs new file mode 100644 index 00000000000..7ff4da9f560 --- /dev/null +++ b/src/libs/3rdparty/libptyqt/ptyqt.qbs @@ -0,0 +1,45 @@ +import qbs + +Project { + name: "ptyqt" + + QtcLibrary { + Depends { name: "Qt.core" } + Depends { name: "Qt.network"; condition: qbs.targetOS.contains("windows") } + Depends { name: "winpty"; condition: qbs.targetOS.contains("windows") } + + type: "staticlibrary" + + files: [ + "iptyprocess.h", + "ptyqt.cpp", + "ptyqt.h", + ] + + Group { + name: "ptyqt UNIX files" + condition: qbs.targetOS.contains("unix") + files: [ + "unixptyprocess.cpp", + "unixptyprocess.h", + ] + } + + Group { + name: "ptyqt Windows files" + condition: qbs.targetOS.contains("windows") + files: [ + "conptyprocess.cpp", + "conptyprocess.h", + "winptyprocess.cpp", + "winptyprocess.h", + ] + } + + Export { + Depends { name: "cpp" } + Depends { name: "winpty"; condition: qbs.targetOS.contains("windows") } + cpp.includePaths: base.concat(exportingProduct.sourceDirectory) + } + } +} diff --git a/src/libs/3rdparty/libptyqt/unixptyprocess.cpp b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp new file mode 100644 index 00000000000..a9167e7696d --- /dev/null +++ b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp @@ -0,0 +1,376 @@ +#include "unixptyprocess.h" +#include + +#include +#include +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_FREEBSD) +#include +#endif +#include +#include +#include +#include +#include +#include + +UnixPtyProcess::UnixPtyProcess() + : IPtyProcess() + , m_readMasterNotify(0) +{ + m_shellProcess.setWorkingDirectory( + QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); +} + +UnixPtyProcess::~UnixPtyProcess() +{ + kill(); +} + +bool UnixPtyProcess::startProcess(const QString &shellPath, + const QStringList &arguments, + const QString &workingDir, + QStringList environment, + qint16 cols, + qint16 rows) +{ + if (!isAvailable()) { + m_lastError = QString("UnixPty Error: unavailable"); + return false; + } + + if (m_shellProcess.state() == QProcess::Running) + return false; + + QFileInfo fi(shellPath); + if (fi.isRelative() || !QFile::exists(shellPath)) { + //todo add auto-find executable in PATH env var + m_lastError = QString("UnixPty Error: shell file path must be absolute"); + return false; + } + + m_shellPath = shellPath; + m_size = QPair(cols, rows); + + int rc = 0; + + m_shellProcess.m_handleMaster = ::posix_openpt(O_RDWR | O_NOCTTY); + if (m_shellProcess.m_handleMaster <= 0) { + m_lastError = QString("UnixPty Error: unable to open master -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + m_shellProcess.m_handleSlaveName = QLatin1String(ptsname(m_shellProcess.m_handleMaster)); + if (m_shellProcess.m_handleSlaveName.isEmpty()) { + m_lastError = QString("UnixPty Error: unable to get slave name -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + rc = grantpt(m_shellProcess.m_handleMaster); + if (rc != 0) { + m_lastError + = QString("UnixPty Error: unable to change perms for slave -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + rc = unlockpt(m_shellProcess.m_handleMaster); + if (rc != 0) { + m_lastError = QString("UnixPty Error: unable to unlock slave -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + m_shellProcess.m_handleSlave = ::open(m_shellProcess.m_handleSlaveName.toLatin1().data(), + O_RDWR | O_NOCTTY); + if (m_shellProcess.m_handleSlave < 0) { + m_lastError = QString("UnixPty Error: unable to open slave -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + rc = fcntl(m_shellProcess.m_handleMaster, F_SETFD, FD_CLOEXEC); + if (rc == -1) { + m_lastError + = QString("UnixPty Error: unable to set flags for master -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + rc = fcntl(m_shellProcess.m_handleSlave, F_SETFD, FD_CLOEXEC); + if (rc == -1) { + m_lastError + = QString("UnixPty Error: unable to set flags for slave -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + struct ::termios ttmode; + rc = tcgetattr(m_shellProcess.m_handleMaster, &ttmode); + if (rc != 0) { + m_lastError = QString("UnixPty Error: termios fail -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + ttmode.c_iflag = ICRNL | IXON | IXANY | IMAXBEL | BRKINT; +#if defined(IUTF8) + ttmode.c_iflag |= IUTF8; +#endif + + ttmode.c_oflag = OPOST | ONLCR; + ttmode.c_cflag = CREAD | CS8 | HUPCL; + ttmode.c_lflag = ICANON | ISIG | IEXTEN | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL; + + ttmode.c_cc[VEOF] = 4; + ttmode.c_cc[VEOL] = -1; + ttmode.c_cc[VEOL2] = -1; + ttmode.c_cc[VERASE] = 0x7f; + ttmode.c_cc[VWERASE] = 23; + ttmode.c_cc[VKILL] = 21; + ttmode.c_cc[VREPRINT] = 18; + ttmode.c_cc[VINTR] = 3; + ttmode.c_cc[VQUIT] = 0x1c; + ttmode.c_cc[VSUSP] = 26; + ttmode.c_cc[VSTART] = 17; + ttmode.c_cc[VSTOP] = 19; + ttmode.c_cc[VLNEXT] = 22; + ttmode.c_cc[VDISCARD] = 15; + ttmode.c_cc[VMIN] = 1; + ttmode.c_cc[VTIME] = 0; + +#if (__APPLE__) + ttmode.c_cc[VDSUSP] = 25; + ttmode.c_cc[VSTATUS] = 20; +#endif + + cfsetispeed(&ttmode, B38400); + cfsetospeed(&ttmode, B38400); + + rc = tcsetattr(m_shellProcess.m_handleMaster, TCSANOW, &ttmode); + if (rc != 0) { + m_lastError + = QString("UnixPty Error: unabble to set associated params -> %1").arg(QLatin1String(strerror(errno))); + kill(); + return false; + } + + m_readMasterNotify = new QSocketNotifier(m_shellProcess.m_handleMaster, + QSocketNotifier::Read, + &m_shellProcess); + m_readMasterNotify->setEnabled(true); + m_readMasterNotify->moveToThread(m_shellProcess.thread()); + QObject::connect(m_readMasterNotify, &QSocketNotifier::activated, [this](int socket) { + Q_UNUSED(socket) + + QByteArray buffer; + int size = 1025; + int readSize = 1024; + QByteArray data; + do { + char nativeBuffer[size]; + int len = ::read(m_shellProcess.m_handleMaster, nativeBuffer, readSize); + data = QByteArray(nativeBuffer, len); + buffer.append(data); + } while (data.size() == readSize); //last data block always < readSize + + m_shellReadBuffer.append(buffer); + m_shellProcess.emitReadyRead(); + }); + + QObject::connect(&m_shellProcess, &QProcess::finished, &m_shellProcess, [this](int exitCode) { + m_exitCode = exitCode; + emit m_shellProcess.aboutToClose(); + }); + + QStringList defaultVars; + + defaultVars.append("TERM=xterm-256color"); + defaultVars.append("ITERM_PROFILE=Default"); + defaultVars.append("XPC_FLAGS=0x0"); + defaultVars.append("XPC_SERVICE_NAME=0"); + defaultVars.append("LANG=en_US.UTF-8"); + defaultVars.append("LC_ALL=en_US.UTF-8"); + defaultVars.append("LC_CTYPE=UTF-8"); + defaultVars.append("INIT_CWD=" + QCoreApplication::applicationDirPath()); + defaultVars.append("COMMAND_MODE=unix2003"); + defaultVars.append("COLORTERM=truecolor"); + + QStringList varNames; + foreach (QString line, environment) { + varNames.append(line.split("=").first()); + } + + //append default env vars only if they don't exists in current env + foreach (QString defVar, defaultVars) { + if (!varNames.contains(defVar.split("=").first())) + environment.append(defVar); + } + + QProcessEnvironment envFormat; + foreach (QString line, environment) { + envFormat.insert(line.split("=").first(), line.split("=").last()); + } + m_shellProcess.setWorkingDirectory(workingDir); + m_shellProcess.setProcessEnvironment(envFormat); + m_shellProcess.setReadChannel(QProcess::StandardOutput); + m_shellProcess.start(m_shellPath, arguments); + m_shellProcess.waitForStarted(); + + m_pid = m_shellProcess.processId(); + + resize(cols, rows); + + return true; +} + +bool UnixPtyProcess::resize(qint16 cols, qint16 rows) +{ + struct winsize winp; + winp.ws_col = cols; + winp.ws_row = rows; + winp.ws_xpixel = 0; + winp.ws_ypixel = 0; + + bool res = ((ioctl(m_shellProcess.m_handleMaster, TIOCSWINSZ, &winp) != -1) + && (ioctl(m_shellProcess.m_handleSlave, TIOCSWINSZ, &winp) != -1)); + + if (res) { + m_size = QPair(cols, rows); + } + + return res; +} + +bool UnixPtyProcess::kill() +{ + m_shellProcess.m_handleSlaveName = QString(); + if (m_shellProcess.m_handleSlave >= 0) { + ::close(m_shellProcess.m_handleSlave); + m_shellProcess.m_handleSlave = -1; + } + if (m_shellProcess.m_handleMaster >= 0) { + ::close(m_shellProcess.m_handleMaster); + m_shellProcess.m_handleMaster = -1; + } + + if (m_shellProcess.state() == QProcess::Running) { + m_readMasterNotify->disconnect(); + m_readMasterNotify->deleteLater(); + + m_shellProcess.terminate(); + m_shellProcess.waitForFinished(1000); + + if (m_shellProcess.state() == QProcess::Running) { + QProcess::startDetached(QString("kill -9 %1").arg(pid())); + m_shellProcess.kill(); + m_shellProcess.waitForFinished(1000); + } + + return (m_shellProcess.state() == QProcess::NotRunning); + } + return false; +} + +IPtyProcess::PtyType UnixPtyProcess::type() +{ + return IPtyProcess::UnixPty; +} + +QString UnixPtyProcess::dumpDebugInfo() +{ +#ifdef PTYQT_DEBUG + return QString("PID: %1, In: %2, Out: %3, Type: %4, Cols: %5, Rows: %6, IsRunning: %7, Shell: " + "%8, SlaveName: %9") + .arg(m_pid) + .arg(m_shellProcess.m_handleMaster) + .arg(m_shellProcess.m_handleSlave) + .arg(type()) + .arg(m_size.first) + .arg(m_size.second) + .arg(m_shellProcess.state() == QProcess::Running) + .arg(m_shellPath) + .arg(m_shellProcess.m_handleSlaveName); +#else + return QString("Nothing..."); +#endif +} + +QIODevice *UnixPtyProcess::notifier() +{ + return &m_shellProcess; +} + +QByteArray UnixPtyProcess::readAll() +{ + QByteArray tmpBuffer = m_shellReadBuffer; + m_shellReadBuffer.clear(); + return tmpBuffer; +} + +qint64 UnixPtyProcess::write(const QByteArray &byteArray) +{ + int result = ::write(m_shellProcess.m_handleMaster, byteArray.constData(), byteArray.size()); + Q_UNUSED(result) + + return byteArray.size(); +} + +bool UnixPtyProcess::isAvailable() +{ + //todo check something more if required + return true; +} + +void UnixPtyProcess::moveToThread(QThread *targetThread) +{ + m_shellProcess.moveToThread(targetThread); +} + +void ShellProcess::configChildProcess() +{ + dup2(m_handleSlave, STDIN_FILENO); + dup2(m_handleSlave, STDOUT_FILENO); + dup2(m_handleSlave, STDERR_FILENO); + + pid_t sid = setsid(); + ioctl(m_handleSlave, TIOCSCTTY, 0); + tcsetpgrp(m_handleSlave, sid); + +#if !defined(Q_OS_ANDROID) && !defined(Q_OS_FREEBSD) + // on Android imposible to put record to the 'utmp' file + struct utmpx utmpxInfo; + memset(&utmpxInfo, 0, sizeof(utmpxInfo)); + + strncpy(utmpxInfo.ut_user, qgetenv("USER"), sizeof(utmpxInfo.ut_user)); + + QString device(m_handleSlaveName); + if (device.startsWith("/dev/")) + device = device.mid(5); + + const char *d = device.toLatin1().constData(); + + strncpy(utmpxInfo.ut_line, d, sizeof(utmpxInfo.ut_line)); + + strncpy(utmpxInfo.ut_id, d + strlen(d) - sizeof(utmpxInfo.ut_id), sizeof(utmpxInfo.ut_id)); + + struct timeval tv; + gettimeofday(&tv, 0); + utmpxInfo.ut_tv.tv_sec = tv.tv_sec; + utmpxInfo.ut_tv.tv_usec = tv.tv_usec; + + utmpxInfo.ut_type = USER_PROCESS; + utmpxInfo.ut_pid = getpid(); + + utmpxname(_PATH_UTMPX); + setutxent(); + pututxline(&utmpxInfo); + endutxent(); + +#if !defined(Q_OS_UNIX) + updwtmpx(_PATH_UTMPX, &loginInfo); +#endif + +#endif +} diff --git a/src/libs/3rdparty/libptyqt/unixptyprocess.h b/src/libs/3rdparty/libptyqt/unixptyprocess.h new file mode 100644 index 00000000000..e4df0d2f74d --- /dev/null +++ b/src/libs/3rdparty/libptyqt/unixptyprocess.h @@ -0,0 +1,66 @@ +#ifndef UNIXPTYPROCESS_H +#define UNIXPTYPROCESS_H + +#include "iptyprocess.h" +#include +#include + +// support for build with MUSL on Alpine Linux +#ifndef _PATH_UTMPX +#include +#define _PATH_UTMPX "/var/log/utmp" +#endif + +class ShellProcess : public QProcess +{ + friend class UnixPtyProcess; + Q_OBJECT +public: + ShellProcess() + : QProcess() + , m_handleMaster(-1) + , m_handleSlave(-1) + { + setProcessChannelMode(QProcess::SeparateChannels); + setChildProcessModifier([this]() { configChildProcess(); }); + } + + void emitReadyRead() { emit readyRead(); } + +protected: + void configChildProcess(); + +private: + int m_handleMaster, m_handleSlave; + QString m_handleSlaveName; +}; + +class UnixPtyProcess : public IPtyProcess +{ +public: + UnixPtyProcess(); + virtual ~UnixPtyProcess(); + + virtual bool startProcess(const QString &executable, + const QStringList &arguments, + const QString &workingDir, + QStringList environment, + qint16 cols, + qint16 rows); + virtual bool resize(qint16 cols, qint16 rows); + virtual bool kill(); + virtual PtyType type(); + virtual QString dumpDebugInfo(); + virtual QIODevice *notifier(); + virtual QByteArray readAll(); + virtual qint64 write(const QByteArray &byteArray); + virtual bool isAvailable(); + void moveToThread(QThread *targetThread); + +private: + ShellProcess m_shellProcess; + QSocketNotifier *m_readMasterNotify; + QByteArray m_shellReadBuffer; +}; + +#endif // UNIXPTYPROCESS_H diff --git a/src/libs/3rdparty/libptyqt/winptyprocess.cpp b/src/libs/3rdparty/libptyqt/winptyprocess.cpp new file mode 100644 index 00000000000..90ac139b9c3 --- /dev/null +++ b/src/libs/3rdparty/libptyqt/winptyprocess.cpp @@ -0,0 +1,275 @@ +#include "winptyprocess.h" +#include +#include +#include +#include + +#define DEBUG_VAR_LEGACY "WINPTYDBG" +#define DEBUG_VAR_ACTUAL "WINPTY_DEBUG" +#define SHOW_CONSOLE_VAR "WINPTY_SHOW_CONSOLE" +#define WINPTY_AGENT_NAME "winpty-agent.exe" +#define WINPTY_DLL_NAME "winpty.dll" + +QString castErrorToString(winpty_error_ptr_t error_ptr) +{ + return QString::fromStdWString(winpty_error_msg(error_ptr)); +} + +WinPtyProcess::WinPtyProcess() + : IPtyProcess() + , m_ptyHandler(nullptr) + , m_innerHandle(nullptr) + , m_inSocket(nullptr) + , m_outSocket(nullptr) +{ +#ifdef PTYQT_DEBUG + m_trace = true; +#endif +} + +WinPtyProcess::~WinPtyProcess() +{ + kill(); +} + +bool WinPtyProcess::startProcess(const QString &executable, + const QStringList &arguments, + const QString &workingDir, + QStringList environment, + qint16 cols, + qint16 rows) +{ + if (!isAvailable()) + { + m_lastError = QString("WinPty Error: winpty-agent.exe or winpty.dll not found!"); + return false; + } + + //already running + if (m_ptyHandler != nullptr) + return false; + + QFileInfo fi(executable); + if (fi.isRelative() || !QFile::exists(executable)) + { + //todo add auto-find executable in PATH env var + m_lastError = QString("WinPty Error: shell file path must be absolute"); + return false; + } + + m_shellPath = executable; + m_size = QPair(cols, rows); + +#ifdef PTYQT_DEBUG + if (m_trace) + { + environment.append(QString("%1=1").arg(DEBUG_VAR_LEGACY)); + environment.append(QString("%1=trace").arg(DEBUG_VAR_ACTUAL)); + environment.append(QString("%1=1").arg(SHOW_CONSOLE_VAR)); + SetEnvironmentVariableA(DEBUG_VAR_LEGACY, "1"); + SetEnvironmentVariableA(DEBUG_VAR_ACTUAL, "trace"); + SetEnvironmentVariableA(SHOW_CONSOLE_VAR, "1"); + } +#endif + + //env + std::wstringstream envBlock; + foreach (QString line, environment) + { + envBlock << line.toStdWString() << L'\0'; + } + std::wstring env = envBlock.str(); + + //create start config + winpty_error_ptr_t errorPtr = nullptr; + winpty_config_t* startConfig = winpty_config_new(0, &errorPtr); + if (startConfig == nullptr) + { + m_lastError = QString("WinPty Error: create start config -> %1").arg(castErrorToString(errorPtr)); + return false; + } + winpty_error_free(errorPtr); + + //set params + winpty_config_set_initial_size(startConfig, cols, rows); + winpty_config_set_mouse_mode(startConfig, WINPTY_MOUSE_MODE_AUTO); + //winpty_config_set_agent_timeout(); + + //start agent + m_ptyHandler = winpty_open(startConfig, &errorPtr); + winpty_config_free(startConfig); //start config is local var, free it after use + + if (m_ptyHandler == nullptr) + { + m_lastError = QString("WinPty Error: start agent -> %1").arg(castErrorToString(errorPtr)); + return false; + } + winpty_error_free(errorPtr); + + //create spawn config + winpty_spawn_config_t* spawnConfig = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, m_shellPath.toStdWString().c_str(), + //commandLine.toStdWString().c_str(), cwd.toStdWString().c_str(), + arguments.join(" ").toStdWString().c_str(), workingDir.toStdWString().c_str(), + env.c_str(), + &errorPtr); + + if (spawnConfig == nullptr) + { + m_lastError = QString("WinPty Error: create spawn config -> %1").arg(castErrorToString(errorPtr)); + return false; + } + winpty_error_free(errorPtr); + + //spawn the new process + BOOL spawnSuccess = winpty_spawn(m_ptyHandler, spawnConfig, &m_innerHandle, nullptr, nullptr, &errorPtr); + winpty_spawn_config_free(spawnConfig); //spawn config is local var, free it after use + if (!spawnSuccess) + { + m_lastError = QString("WinPty Error: start terminal process -> %1").arg(castErrorToString(errorPtr)); + return false; + } + winpty_error_free(errorPtr); + + m_pid = (int)GetProcessId(m_innerHandle); + + // Notify when the shell process has been terminated + RegisterWaitForSingleObject( + &m_shellCloseWaitHandle, + m_innerHandle, + [](PVOID data, BOOLEAN) { + auto self = static_cast(data); + // Do not respawn if the object is about to be destructed + DWORD exitCode = 0; + GetExitCodeProcess(self->m_innerHandle, &exitCode); + self->m_exitCode = exitCode; + if (!self->m_aboutToDestruct) + emit self->notifier()->aboutToClose(); + }, + this, + INFINITE, + WT_EXECUTEONLYONCE); + + //get pipe names + LPCWSTR conInPipeName = winpty_conin_name(m_ptyHandler); + m_conInName = QString::fromStdWString(std::wstring(conInPipeName)); + m_inSocket = new QLocalSocket(); + m_inSocket->connectToServer(m_conInName, QIODevice::WriteOnly); + m_inSocket->waitForConnected(); + + LPCWSTR conOutPipeName = winpty_conout_name(m_ptyHandler); + m_conOutName = QString::fromStdWString(std::wstring(conOutPipeName)); + m_outSocket = new QLocalSocket(); + m_outSocket->connectToServer(m_conOutName, QIODevice::ReadOnly); + m_outSocket->waitForConnected(); + + if (m_inSocket->state() != QLocalSocket::ConnectedState && m_outSocket->state() != QLocalSocket::ConnectedState) + { + m_lastError = QString("WinPty Error: Unable to connect local sockets -> %1 / %2").arg(m_inSocket->errorString()).arg(m_outSocket->errorString()); + m_inSocket->deleteLater(); + m_outSocket->deleteLater(); + m_inSocket = nullptr; + m_outSocket = nullptr; + return false; + } + + return true; +} + +bool WinPtyProcess::resize(qint16 cols, qint16 rows) +{ + if (m_ptyHandler == nullptr) + { + return false; + } + + bool res = winpty_set_size(m_ptyHandler, cols, rows, nullptr); + + if (res) + { + m_size = QPair(cols, rows); + } + + return res; +} + +bool WinPtyProcess::kill() +{ + bool exitCode = false; + if (m_innerHandle != nullptr && m_ptyHandler != nullptr) { + m_aboutToDestruct = true; + //disconnect all signals (readyRead, ...) + m_inSocket->disconnect(); + m_outSocket->disconnect(); + + //disconnect for server + m_inSocket->disconnectFromServer(); + m_outSocket->disconnectFromServer(); + + m_inSocket->deleteLater(); + m_outSocket->deleteLater(); + + m_inSocket = nullptr; + m_outSocket = nullptr; + + winpty_free(m_ptyHandler); + exitCode = CloseHandle(m_innerHandle); + + UnregisterWait(m_shellCloseWaitHandle); + + m_ptyHandler = nullptr; + m_innerHandle = nullptr; + m_conInName = QString(); + m_conOutName = QString(); + m_pid = 0; + } + return exitCode; +} + +IPtyProcess::PtyType WinPtyProcess::type() +{ + return PtyType::WinPty; +} + +QString WinPtyProcess::dumpDebugInfo() +{ +#ifdef PTYQT_DEBUG + return QString("PID: %1, ConIn: %2, ConOut: %3, Type: %4, Cols: %5, Rows: %6, IsRunning: %7, Shell: %8") + .arg(m_pid).arg(m_conInName).arg(m_conOutName).arg(type()) + .arg(m_size.first).arg(m_size.second).arg(m_ptyHandler != nullptr) + .arg(m_shellPath); +#else + return QString("Nothing..."); +#endif +} + +QIODevice *WinPtyProcess::notifier() +{ + return m_outSocket; +} + +QByteArray WinPtyProcess::readAll() +{ + return m_outSocket->readAll(); +} + +qint64 WinPtyProcess::write(const QByteArray &byteArray) +{ + return m_inSocket->write(byteArray); +} + +bool WinPtyProcess::isAvailable() +{ +#ifdef PTYQT_BUILD_STATIC + return QFile::exists(QCoreApplication::applicationDirPath() + "/" + WINPTY_AGENT_NAME); +#elif PTYQT_BUILD_DYNAMIC + return QFile::exists(QCoreApplication::applicationDirPath() + "/" + WINPTY_AGENT_NAME) + && QFile::exists(QCoreApplication::applicationDirPath() + "/" + WINPTY_DLL_NAME); +#endif + return true; +} + +void WinPtyProcess::moveToThread(QThread *targetThread) +{ + m_inSocket->moveToThread(targetThread); + m_outSocket->moveToThread(targetThread); +} diff --git a/src/libs/3rdparty/libptyqt/winptyprocess.h b/src/libs/3rdparty/libptyqt/winptyprocess.h new file mode 100644 index 00000000000..547bcf7c97a --- /dev/null +++ b/src/libs/3rdparty/libptyqt/winptyprocess.h @@ -0,0 +1,42 @@ +#ifndef WINPTYPROCESS_H +#define WINPTYPROCESS_H + +#include "iptyprocess.h" +#include "winpty.h" + +#include + +class WinPtyProcess : public IPtyProcess +{ +public: + WinPtyProcess(); + ~WinPtyProcess(); + + bool startProcess(const QString &executable, + const QStringList &arguments, + const QString &workingDir, + QStringList environment, + qint16 cols, + qint16 rows); + bool resize(qint16 cols, qint16 rows); + bool kill(); + PtyType type(); + QString dumpDebugInfo(); + QIODevice *notifier(); + QByteArray readAll(); + qint64 write(const QByteArray &byteArray); + bool isAvailable(); + void moveToThread(QThread *targetThread); + +private: + winpty_t *m_ptyHandler; + HANDLE m_innerHandle; + QString m_conInName; + QString m_conOutName; + QLocalSocket *m_inSocket; + QLocalSocket *m_outSocket; + bool m_aboutToDestruct{false}; + HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE}; +}; + +#endif // WINPTYPROCESS_H diff --git a/src/libs/3rdparty/libvterm/CMakeLists.txt b/src/libs/3rdparty/libvterm/CMakeLists.txt new file mode 100644 index 00000000000..4a0ede6f0f4 --- /dev/null +++ b/src/libs/3rdparty/libvterm/CMakeLists.txt @@ -0,0 +1,25 @@ +add_library(libvterm STATIC + src/encoding.c + src/fullwidth.inc + src/keyboard.c + src/mouse.c + src/parser.c + src/pen.c + src/rect.h + src/screen.c + src/state.c + src/unicode.c + src/utf8.h + src/vterm.c + src/vterm_internal.h +) + +target_include_directories(libvterm PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +set_target_properties(libvterm + PROPERTIES + QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON + POSITION_INDEPENDENT_CODE ON  +) diff --git a/src/libs/3rdparty/libvterm/CONTRIBUTING b/src/libs/3rdparty/libvterm/CONTRIBUTING new file mode 100644 index 00000000000..e9a8f0c3315 --- /dev/null +++ b/src/libs/3rdparty/libvterm/CONTRIBUTING @@ -0,0 +1,22 @@ +How to Contribute +----------------- + +The main resources for this library are: + + Launchpad + https://launchpad.net/libvterm + + IRC: + ##tty or #tickit on irc.libera.chat + + Email: + Paul "LeoNerd" Evans + + +Bug reports and feature requests can be sent to any of the above resources. + +New features, bug patches, etc.. should in the first instance be discussed via +any of the resources listed above, before starting work on the actual code. +There may be future plans or development already in-progress that could be +affected so it is better to discuss the ideas first before starting work +actually writing any code. diff --git a/src/libs/3rdparty/libvterm/LICENSE b/src/libs/3rdparty/libvterm/LICENSE new file mode 100644 index 00000000000..0d051634b28 --- /dev/null +++ b/src/libs/3rdparty/libvterm/LICENSE @@ -0,0 +1,23 @@ + + +The MIT License + +Copyright (c) 2008 Paul Evans + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/libs/3rdparty/libvterm/include/vterm.h b/src/libs/3rdparty/libvterm/include/vterm.h new file mode 100644 index 00000000000..c0f008776ba --- /dev/null +++ b/src/libs/3rdparty/libvterm/include/vterm.h @@ -0,0 +1,635 @@ +#ifndef __VTERM_H__ +#define __VTERM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "vterm_keycodes.h" + +#define VTERM_VERSION_MAJOR 0 +#define VTERM_VERSION_MINOR 3 + +#define VTERM_CHECK_VERSION \ + vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) + +/* Any cell can contain at most one basic printing character and 5 combining + * characters. This number could be changed but will be ABI-incompatible if + * you do */ +#define VTERM_MAX_CHARS_PER_CELL 6 + +typedef struct VTerm VTerm; +typedef struct VTermState VTermState; +typedef struct VTermScreen VTermScreen; + +typedef struct { + int row; + int col; +} VTermPos; + +/* some small utility functions; we can just keep these static here */ + +/* order points by on-screen flow order */ +static inline int vterm_pos_cmp(VTermPos a, VTermPos b) +{ + return (a.row == b.row) ? a.col - b.col : a.row - b.row; +} + +typedef struct { + int start_row; + int end_row; + int start_col; + int end_col; +} VTermRect; + +/* true if the rect contains the point */ +static inline int vterm_rect_contains(VTermRect r, VTermPos p) +{ + return p.row >= r.start_row && p.row < r.end_row && + p.col >= r.start_col && p.col < r.end_col; +} + +/* move a rect */ +static inline void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta) +{ + rect->start_row += row_delta; rect->end_row += row_delta; + rect->start_col += col_delta; rect->end_col += col_delta; +} + +/** + * Bit-field describing the content of the tagged union `VTermColor`. + */ +typedef enum { + /** + * If the lower bit of `type` is not set, the colour is 24-bit RGB. + */ + VTERM_COLOR_RGB = 0x00, + + /** + * The colour is an index into a palette of 256 colours. + */ + VTERM_COLOR_INDEXED = 0x01, + + /** + * Mask that can be used to extract the RGB/Indexed bit. + */ + VTERM_COLOR_TYPE_MASK = 0x01, + + /** + * If set, indicates that this colour should be the default foreground + * color, i.e. there was no SGR request for another colour. When + * rendering this colour it is possible to ignore "idx" and just use a + * colour that is not in the palette. + */ + VTERM_COLOR_DEFAULT_FG = 0x02, + + /** + * If set, indicates that this colour should be the default background + * color, i.e. there was no SGR request for another colour. A common + * option when rendering this colour is to not render a background at + * all, for example by rendering the window transparently at this spot. + */ + VTERM_COLOR_DEFAULT_BG = 0x04, + + /** + * Mask that can be used to extract the default foreground/background bit. + */ + VTERM_COLOR_DEFAULT_MASK = 0x06 +} VTermColorType; + +/** + * Returns true if the VTERM_COLOR_RGB `type` flag is set, indicating that the + * given VTermColor instance is an indexed colour. + */ +#define VTERM_COLOR_IS_INDEXED(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_INDEXED) + +/** + * Returns true if the VTERM_COLOR_INDEXED `type` flag is set, indicating that + * the given VTermColor instance is an rgb colour. + */ +#define VTERM_COLOR_IS_RGB(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_FG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default foreground + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_FG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_FG)) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_BG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default background + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_BG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_BG)) + +/** + * Tagged union storing either an RGB color or an index into a colour palette. + * In order to convert indexed colours to RGB, you may use the + * vterm_state_convert_color_to_rgb() or vterm_screen_convert_color_to_rgb() + * functions which lookup the RGB colour from the palette maintained by a + * VTermState or VTermScreen instance. + */ +typedef union { + /** + * Tag indicating which union member is actually valid. This variable + * coincides with the `type` member of the `rgb` and the `indexed` struct + * in memory. Please use the `VTERM_COLOR_IS_*` test macros to check whether + * a particular type flag is set. + */ + uint8_t type; + + /** + * Valid if `VTERM_COLOR_IS_RGB(type)` is true. Holds the RGB colour values. + */ + struct { + /** + * Same as the top-level `type` member stored in VTermColor. + */ + uint8_t type; + + /** + * The actual 8-bit red, green, blue colour values. + */ + uint8_t red, green, blue; + } rgb; + + /** + * If `VTERM_COLOR_IS_INDEXED(type)` is true, this member holds the index into + * the colour palette. + */ + struct { + /** + * Same as the top-level `type` member stored in VTermColor. + */ + uint8_t type; + + /** + * Index into the colour map. + */ + uint8_t idx; + } indexed; +} VTermColor; + +/** + * Constructs a new VTermColor instance representing the given RGB values. + */ +static inline void vterm_color_rgb(VTermColor *col, uint8_t red, uint8_t green, + uint8_t blue) +{ + col->type = VTERM_COLOR_RGB; + col->rgb.red = red; + col->rgb.green = green; + col->rgb.blue = blue; +} + +/** + * Construct a new VTermColor instance representing an indexed color with the + * given index. + */ +static inline void vterm_color_indexed(VTermColor *col, uint8_t idx) +{ + col->type = VTERM_COLOR_INDEXED; + col->indexed.idx = idx; +} + +/** + * Compares two colours. Returns true if the colors are equal, false otherwise. + */ +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b); + +typedef enum { + /* VTERM_VALUETYPE_NONE = 0 */ + VTERM_VALUETYPE_BOOL = 1, + VTERM_VALUETYPE_INT, + VTERM_VALUETYPE_STRING, + VTERM_VALUETYPE_COLOR, + + VTERM_N_VALUETYPES +} VTermValueType; + +typedef struct { + const char *str; + size_t len : 30; + bool initial : 1; + bool final : 1; +} VTermStringFragment; + +typedef union { + int boolean; + int number; + VTermStringFragment string; + VTermColor color; +} VTermValue; + +typedef enum { + /* VTERM_ATTR_NONE = 0 */ + VTERM_ATTR_BOLD = 1, // bool: 1, 22 + VTERM_ATTR_UNDERLINE, // number: 4, 21, 24 + VTERM_ATTR_ITALIC, // bool: 3, 23 + VTERM_ATTR_BLINK, // bool: 5, 25 + VTERM_ATTR_REVERSE, // bool: 7, 27 + VTERM_ATTR_CONCEAL, // bool: 8, 28 + VTERM_ATTR_STRIKE, // bool: 9, 29 + VTERM_ATTR_FONT, // number: 10-19 + VTERM_ATTR_FOREGROUND, // color: 30-39 90-97 + VTERM_ATTR_BACKGROUND, // color: 40-49 100-107 + VTERM_ATTR_SMALL, // bool: 73, 74, 75 + VTERM_ATTR_BASELINE, // number: 73, 74, 75 + + VTERM_N_ATTRS +} VTermAttr; + +typedef enum { + /* VTERM_PROP_NONE = 0 */ + VTERM_PROP_CURSORVISIBLE = 1, // bool + VTERM_PROP_CURSORBLINK, // bool + VTERM_PROP_ALTSCREEN, // bool + VTERM_PROP_TITLE, // string + VTERM_PROP_ICONNAME, // string + VTERM_PROP_REVERSE, // bool + VTERM_PROP_CURSORSHAPE, // number + VTERM_PROP_MOUSE, // number + + VTERM_N_PROPS +} VTermProp; + +enum { + VTERM_PROP_CURSORSHAPE_BLOCK = 1, + VTERM_PROP_CURSORSHAPE_UNDERLINE, + VTERM_PROP_CURSORSHAPE_BAR_LEFT, + + VTERM_N_PROP_CURSORSHAPES +}; + +enum { + VTERM_PROP_MOUSE_NONE = 0, + VTERM_PROP_MOUSE_CLICK, + VTERM_PROP_MOUSE_DRAG, + VTERM_PROP_MOUSE_MOVE, + + VTERM_N_PROP_MOUSES +}; + +typedef enum { + VTERM_SELECTION_CLIPBOARD = (1<<0), + VTERM_SELECTION_PRIMARY = (1<<1), + VTERM_SELECTION_SECONDARY = (1<<2), + VTERM_SELECTION_SELECT = (1<<3), + VTERM_SELECTION_CUT0 = (1<<4), /* also CUT1 .. CUT7 by bitshifting */ +} VTermSelectionMask; + +typedef struct { + const uint32_t *chars; + int width; + unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */ + unsigned int dwl:1; /* DECDWL or DECDHL double-width line */ + unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */ +} VTermGlyphInfo; + +typedef struct { + unsigned int doublewidth:1; /* DECDWL or DECDHL line */ + unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */ + unsigned int continuation:1; /* Line is a flow continuation of the previous */ +} VTermLineInfo; + +/* Copies of VTermState fields that the 'resize' callback might have reason to + * edit. 'resize' callback gets total control of these fields and may + * free-and-reallocate them if required. They will be copied back from the + * struct after the callback has returned. + */ +typedef struct { + VTermPos pos; /* current cursor position */ + VTermLineInfo *lineinfos[2]; /* [1] may be NULL */ +} VTermStateFields; + +typedef struct { + /* libvterm relies on this memory to be zeroed out before it is returned + * by the allocator. */ + void *(*malloc)(size_t size, void *allocdata); + void (*free)(void *ptr, void *allocdata); +} VTermAllocatorFunctions; + +void vterm_check_version(int major, int minor); + +struct VTermBuilder { + int ver; /* currently unused but reserved for some sort of ABI version flag */ + + int rows, cols; + + const VTermAllocatorFunctions *allocator; + void *allocdata; + + /* Override default sizes for various structures */ + size_t outbuffer_len; /* default: 4096 */ + size_t tmpbuffer_len; /* default: 4096 */ +}; + +VTerm *vterm_build(const struct VTermBuilder *builder); + +/* A convenient shortcut for default cases */ +VTerm *vterm_new(int rows, int cols); +/* This shortcuts are generally discouraged in favour of just using vterm_build() */ +VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata); + +void vterm_free(VTerm* vt); + +void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp); +void vterm_set_size(VTerm *vt, int rows, int cols); + +int vterm_get_utf8(const VTerm *vt); +void vterm_set_utf8(VTerm *vt, int is_utf8); + +size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len); + +/* Setting output callback will override the buffer logic */ +typedef void VTermOutputCallback(const char *s, size_t len, void *user); +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user); + +/* These buffer functions only work if output callback is NOT set + * These are deprecated and will be removed in a later version */ +size_t vterm_output_get_buffer_size(const VTerm *vt); +size_t vterm_output_get_buffer_current(const VTerm *vt); +size_t vterm_output_get_buffer_remaining(const VTerm *vt); + +/* This too */ +size_t vterm_output_read(VTerm *vt, char *buffer, size_t len); + +void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod); +void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod); + +void vterm_keyboard_start_paste(VTerm *vt); +void vterm_keyboard_end_paste(VTerm *vt); + +void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod); +void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod); + +// ------------ +// Parser layer +// ------------ + +/* Flag to indicate non-final subparameters in a single CSI parameter. + * Consider + * CSI 1;2:3:4;5a + * 1 4 and 5 are final. + * 2 and 3 are non-final and will have this bit set + * + * Don't confuse this with the final byte of the CSI escape; 'a' in this case. + */ +#define CSI_ARG_FLAG_MORE (1U<<31) +#define CSI_ARG_MASK (~(1U<<31)) + +#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE) +#define CSI_ARG(a) ((a) & CSI_ARG_MASK) + +/* Can't use -1 to indicate a missing argument; use this instead */ +#define CSI_ARG_MISSING ((1UL<<31)-1) + +#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING) +#define CSI_ARG_OR(a,def) (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a)) +#define CSI_ARG_COUNT(a) (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a)) + +typedef struct { + int (*text)(const char *bytes, size_t len, void *user); + int (*control)(unsigned char control, void *user); + int (*escape)(const char *bytes, size_t len, void *user); + int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); + int (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); + int (*apc)(VTermStringFragment frag, void *user); + int (*pm)(VTermStringFragment frag, void *user); + int (*sos)(VTermStringFragment frag, void *user); + int (*resize)(int rows, int cols, void *user); +} VTermParserCallbacks; + +void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user); +void *vterm_parser_get_cbdata(VTerm *vt); + +/* Normally NUL, CAN, SUB and DEL are ignored. Setting this true causes them + * to be emitted by the 'control' callback + */ +void vterm_parser_set_emit_nul(VTerm *vt, bool emit); + +// ----------- +// State layer +// ----------- + +typedef struct { + int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user); + int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); + int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user); + int (*moverect)(VTermRect dest, VTermRect src, void *user); + int (*erase)(VTermRect rect, int selective, void *user); + int (*initpen)(void *user); + int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user); + int (*settermprop)(VTermProp prop, VTermValue *val, void *user); + int (*bell)(void *user); + int (*resize)(int rows, int cols, VTermStateFields *fields, void *user); + int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user); + int (*sb_clear)(void *user); +} VTermStateCallbacks; + +typedef struct { + int (*control)(unsigned char control, void *user); + int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); + int (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); + int (*apc)(VTermStringFragment frag, void *user); + int (*pm)(VTermStringFragment frag, void *user); + int (*sos)(VTermStringFragment frag, void *user); +} VTermStateFallbacks; + +typedef struct { + int (*set)(VTermSelectionMask mask, VTermStringFragment frag, void *user); + int (*query)(VTermSelectionMask mask, void *user); +} VTermSelectionCallbacks; + +VTermState *vterm_obtain_state(VTerm *vt); + +void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user); +void *vterm_state_get_cbdata(VTermState *state); + +void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user); +void *vterm_state_get_unrecognised_fbdata(VTermState *state); + +void vterm_state_reset(VTermState *state, int hard); +void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos); +void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg); +void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col); +void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg); +void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col); +void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright); +int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val); +int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val); +void vterm_state_focus_in(VTermState *state); +void vterm_state_focus_out(VTermState *state); +const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row); + +/** + * Makes sure that the given color `col` is indeed an RGB colour. After this + * function returns, VTERM_COLOR_IS_RGB(col) will return true, while all other + * flags stored in `col->type` will have been reset. + * + * @param state is the VTermState instance from which the colour palette should + * be extracted. + * @param col is a pointer at the VTermColor instance that should be converted + * to an RGB colour. + */ +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col); + +void vterm_state_set_selection_callbacks(VTermState *state, const VTermSelectionCallbacks *callbacks, void *user, + char *buffer, size_t buflen); + +void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTermStringFragment frag); + +// ------------ +// Screen layer +// ------------ + +typedef struct { + unsigned int bold : 1; + unsigned int underline : 2; + unsigned int italic : 1; + unsigned int blink : 1; + unsigned int reverse : 1; + unsigned int conceal : 1; + unsigned int strike : 1; + unsigned int font : 4; /* 0 to 9 */ + unsigned int dwl : 1; /* On a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */ + unsigned int small : 1; + unsigned int baseline : 2; +} VTermScreenCellAttrs; + +enum { + VTERM_UNDERLINE_OFF, + VTERM_UNDERLINE_SINGLE, + VTERM_UNDERLINE_DOUBLE, + VTERM_UNDERLINE_CURLY, +}; + +enum { + VTERM_BASELINE_NORMAL, + VTERM_BASELINE_RAISE, + VTERM_BASELINE_LOWER, +}; + +typedef struct { + uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; + char width; + VTermScreenCellAttrs attrs; + VTermColor fg, bg; +} VTermScreenCell; + +typedef struct { + int (*damage)(VTermRect rect, void *user); + int (*moverect)(VTermRect dest, VTermRect src, void *user); + int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); + int (*settermprop)(VTermProp prop, VTermValue *val, void *user); + int (*bell)(void *user); + int (*resize)(int rows, int cols, void *user); + int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user); + int (*sb_popline)(int cols, VTermScreenCell *cells, void *user); + int (*sb_clear)(void* user); +} VTermScreenCallbacks; + +VTermScreen *vterm_obtain_screen(VTerm *vt); + +void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user); +void *vterm_screen_get_cbdata(VTermScreen *screen); + +void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user); +void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); + +void vterm_screen_enable_reflow(VTermScreen *screen, bool reflow); + +// Back-compat alias for the brief time it was in 0.3-RC1 +#define vterm_screen_set_reflow vterm_screen_enable_reflow + +void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen); + +typedef enum { + VTERM_DAMAGE_CELL, /* every cell */ + VTERM_DAMAGE_ROW, /* entire rows */ + VTERM_DAMAGE_SCREEN, /* entire screen */ + VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */ + + VTERM_N_DAMAGES +} VTermDamageSize; + +void vterm_screen_flush_damage(VTermScreen *screen); +void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size); + +void vterm_screen_reset(VTermScreen *screen, int hard); + +/* Neither of these functions NUL-terminate the buffer */ +size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect); +size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect); + +typedef enum { + VTERM_ATTR_BOLD_MASK = 1 << 0, + VTERM_ATTR_UNDERLINE_MASK = 1 << 1, + VTERM_ATTR_ITALIC_MASK = 1 << 2, + VTERM_ATTR_BLINK_MASK = 1 << 3, + VTERM_ATTR_REVERSE_MASK = 1 << 4, + VTERM_ATTR_STRIKE_MASK = 1 << 5, + VTERM_ATTR_FONT_MASK = 1 << 6, + VTERM_ATTR_FOREGROUND_MASK = 1 << 7, + VTERM_ATTR_BACKGROUND_MASK = 1 << 8, + VTERM_ATTR_CONCEAL_MASK = 1 << 9, + VTERM_ATTR_SMALL_MASK = 1 << 10, + VTERM_ATTR_BASELINE_MASK = 1 << 11, + + VTERM_ALL_ATTRS_MASK = (1 << 12) - 1 +} VTermAttrMask; + +int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); + +int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell); + +int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos); + +/** + * Same as vterm_state_convert_color_to_rgb(), but takes a `screen` instead of a `state` + * instance. + */ +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col); + +/** + * Similar to vterm_state_set_default_colors(), but also resets colours in the + * screen buffer(s) + */ +void vterm_screen_set_default_colors(VTermScreen *screen, const VTermColor *default_fg, const VTermColor *default_bg); + +// --------- +// Utilities +// --------- + +VTermValueType vterm_get_attr_type(VTermAttr attr); +VTermValueType vterm_get_prop_type(VTermProp prop); + +void vterm_scroll_rect(VTermRect rect, + int downward, + int rightward, + int (*moverect)(VTermRect src, VTermRect dest, void *user), + int (*eraserect)(VTermRect rect, int selective, void *user), + void *user); + +void vterm_copy_cells(VTermRect dest, + VTermRect src, + void (*copycell)(VTermPos dest, VTermPos src, void *user), + void *user); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libs/3rdparty/libvterm/include/vterm_keycodes.h b/src/libs/3rdparty/libvterm/include/vterm_keycodes.h new file mode 100644 index 00000000000..661759febd4 --- /dev/null +++ b/src/libs/3rdparty/libvterm/include/vterm_keycodes.h @@ -0,0 +1,61 @@ +#ifndef __VTERM_INPUT_H__ +#define __VTERM_INPUT_H__ + +typedef enum { + VTERM_MOD_NONE = 0x00, + VTERM_MOD_SHIFT = 0x01, + VTERM_MOD_ALT = 0x02, + VTERM_MOD_CTRL = 0x04, + + VTERM_ALL_MODS_MASK = 0x07 +} VTermModifier; + +typedef enum { + VTERM_KEY_NONE, + + VTERM_KEY_ENTER, + VTERM_KEY_TAB, + VTERM_KEY_BACKSPACE, + VTERM_KEY_ESCAPE, + + VTERM_KEY_UP, + VTERM_KEY_DOWN, + VTERM_KEY_LEFT, + VTERM_KEY_RIGHT, + + VTERM_KEY_INS, + VTERM_KEY_DEL, + VTERM_KEY_HOME, + VTERM_KEY_END, + VTERM_KEY_PAGEUP, + VTERM_KEY_PAGEDOWN, + + VTERM_KEY_FUNCTION_0 = 256, + VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255, + + VTERM_KEY_KP_0, + VTERM_KEY_KP_1, + VTERM_KEY_KP_2, + VTERM_KEY_KP_3, + VTERM_KEY_KP_4, + VTERM_KEY_KP_5, + VTERM_KEY_KP_6, + VTERM_KEY_KP_7, + VTERM_KEY_KP_8, + VTERM_KEY_KP_9, + VTERM_KEY_KP_MULT, + VTERM_KEY_KP_PLUS, + VTERM_KEY_KP_COMMA, + VTERM_KEY_KP_MINUS, + VTERM_KEY_KP_PERIOD, + VTERM_KEY_KP_DIVIDE, + VTERM_KEY_KP_ENTER, + VTERM_KEY_KP_EQUAL, + + VTERM_KEY_MAX, // Must be last + VTERM_N_KEYS = VTERM_KEY_MAX +} VTermKey; + +#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n)) + +#endif diff --git a/src/libs/3rdparty/libvterm/src/encoding.c b/src/libs/3rdparty/libvterm/src/encoding.c new file mode 100644 index 00000000000..434ac3f99b7 --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/encoding.c @@ -0,0 +1,230 @@ +#include "vterm_internal.h" + +#define UNICODE_INVALID 0xFFFD + +#if defined(DEBUG) && DEBUG > 1 +# define DEBUG_PRINT_UTF8 +#endif + +struct UTF8DecoderData { + // number of bytes remaining in this codepoint + int bytes_remaining; + + // number of bytes total in this codepoint once it's finished + // (for detecting overlongs) + int bytes_total; + + int this_cp; +}; + +static void init_utf8(VTermEncoding *enc, void *data_) +{ + struct UTF8DecoderData *data = data_; + + data->bytes_remaining = 0; + data->bytes_total = 0; +} + +static void decode_utf8(VTermEncoding *enc, void *data_, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) +{ + struct UTF8DecoderData *data = data_; + +#ifdef DEBUG_PRINT_UTF8 + printf("BEGIN UTF-8\n"); +#endif + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos]; + +#ifdef DEBUG_PRINT_UTF8 + printf(" pos=%zd c=%02x rem=%d\n", *pos, c, data->bytes_remaining); +#endif + + if(c < 0x20) // C0 + return; + + else if(c >= 0x20 && c < 0x7f) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + cp[(*cpi)++] = c; +#ifdef DEBUG_PRINT_UTF8 + printf(" UTF-8 char: U+%04x\n", c); +#endif + data->bytes_remaining = 0; + } + + else if(c == 0x7f) // DEL + return; + + else if(c >= 0x80 && c < 0xc0) { + if(!data->bytes_remaining) { + cp[(*cpi)++] = UNICODE_INVALID; + continue; + } + + data->this_cp <<= 6; + data->this_cp |= c & 0x3f; + data->bytes_remaining--; + + if(!data->bytes_remaining) { +#ifdef DEBUG_PRINT_UTF8 + printf(" UTF-8 raw char U+%04x bytelen=%d ", data->this_cp, data->bytes_total); +#endif + // Check for overlong sequences + switch(data->bytes_total) { + case 2: + if(data->this_cp < 0x0080) data->this_cp = UNICODE_INVALID; + break; + case 3: + if(data->this_cp < 0x0800) data->this_cp = UNICODE_INVALID; + break; + case 4: + if(data->this_cp < 0x10000) data->this_cp = UNICODE_INVALID; + break; + case 5: + if(data->this_cp < 0x200000) data->this_cp = UNICODE_INVALID; + break; + case 6: + if(data->this_cp < 0x4000000) data->this_cp = UNICODE_INVALID; + break; + } + // Now look for plain invalid ones + if((data->this_cp >= 0xD800 && data->this_cp <= 0xDFFF) || + data->this_cp == 0xFFFE || + data->this_cp == 0xFFFF) + data->this_cp = UNICODE_INVALID; +#ifdef DEBUG_PRINT_UTF8 + printf(" char: U+%04x\n", data->this_cp); +#endif + cp[(*cpi)++] = data->this_cp; + } + } + + else if(c >= 0xc0 && c < 0xe0) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x1f; + data->bytes_total = 2; + data->bytes_remaining = 1; + } + + else if(c >= 0xe0 && c < 0xf0) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x0f; + data->bytes_total = 3; + data->bytes_remaining = 2; + } + + else if(c >= 0xf0 && c < 0xf8) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x07; + data->bytes_total = 4; + data->bytes_remaining = 3; + } + + else if(c >= 0xf8 && c < 0xfc) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x03; + data->bytes_total = 5; + data->bytes_remaining = 4; + } + + else if(c >= 0xfc && c < 0xfe) { + if(data->bytes_remaining) + cp[(*cpi)++] = UNICODE_INVALID; + + data->this_cp = c & 0x01; + data->bytes_total = 6; + data->bytes_remaining = 5; + } + + else { + cp[(*cpi)++] = UNICODE_INVALID; + } + } +} + +static VTermEncoding encoding_utf8 = { + .init = &init_utf8, + .decode = &decode_utf8, +}; + +static void decode_usascii(VTermEncoding *enc, void *data, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) +{ + int is_gr = bytes[*pos] & 0x80; + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos] ^ is_gr; + + if(c < 0x20 || c == 0x7f || c >= 0x80) + return; + + cp[(*cpi)++] = c; + } +} + +static VTermEncoding encoding_usascii = { + .decode = &decode_usascii, +}; + +struct StaticTableEncoding { + const VTermEncoding enc; + const uint32_t chars[128]; +}; + +static void decode_table(VTermEncoding *enc, void *data, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t bytelen) +{ + struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc; + int is_gr = bytes[*pos] & 0x80; + + for(; *pos < bytelen && *cpi < cplen; (*pos)++) { + unsigned char c = bytes[*pos] ^ is_gr; + + if(c < 0x20 || c == 0x7f || c >= 0x80) + return; + + if(table->chars[c]) + cp[(*cpi)++] = table->chars[c]; + else + cp[(*cpi)++] = c; + } +} + +#include "encoding/DECdrawing.inc" +#include "encoding/uk.inc" + +static struct { + VTermEncodingType type; + char designation; + VTermEncoding *enc; +} +encodings[] = { + { ENC_UTF8, 'u', &encoding_utf8 }, + { ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing }, + { ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk }, + { ENC_SINGLE_94, 'B', &encoding_usascii }, + { 0 }, +}; + +/* This ought to be INTERNAL but isn't because it's used by unit testing */ +VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation) +{ + for(int i = 0; encodings[i].designation; i++) + if(encodings[i].type == type && encodings[i].designation == designation) + return encodings[i].enc; + return NULL; +} diff --git a/src/libs/3rdparty/libvterm/src/encoding/DECdrawing.inc b/src/libs/3rdparty/libvterm/src/encoding/DECdrawing.inc new file mode 100644 index 00000000000..47093ed0a81 --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/encoding/DECdrawing.inc @@ -0,0 +1,36 @@ +static const struct StaticTableEncoding encoding_DECdrawing = { + { .decode = &decode_table }, + { + [0x60] = 0x25C6, + [0x61] = 0x2592, + [0x62] = 0x2409, + [0x63] = 0x240C, + [0x64] = 0x240D, + [0x65] = 0x240A, + [0x66] = 0x00B0, + [0x67] = 0x00B1, + [0x68] = 0x2424, + [0x69] = 0x240B, + [0x6a] = 0x2518, + [0x6b] = 0x2510, + [0x6c] = 0x250C, + [0x6d] = 0x2514, + [0x6e] = 0x253C, + [0x6f] = 0x23BA, + [0x70] = 0x23BB, + [0x71] = 0x2500, + [0x72] = 0x23BC, + [0x73] = 0x23BD, + [0x74] = 0x251C, + [0x75] = 0x2524, + [0x76] = 0x2534, + [0x77] = 0x252C, + [0x78] = 0x2502, + [0x79] = 0x2A7D, + [0x7a] = 0x2A7E, + [0x7b] = 0x03C0, + [0x7c] = 0x2260, + [0x7d] = 0x00A3, + [0x7e] = 0x00B7, + } +}; diff --git a/src/libs/3rdparty/libvterm/src/encoding/uk.inc b/src/libs/3rdparty/libvterm/src/encoding/uk.inc new file mode 100644 index 00000000000..da1445decaf --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/encoding/uk.inc @@ -0,0 +1,6 @@ +static const struct StaticTableEncoding encoding_uk = { + { .decode = &decode_table }, + { + [0x23] = 0x00a3, + } +}; diff --git a/src/libs/3rdparty/libvterm/src/fullwidth.inc b/src/libs/3rdparty/libvterm/src/fullwidth.inc new file mode 100644 index 00000000000..a703529a76d --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/fullwidth.inc @@ -0,0 +1,111 @@ + { 0x1100, 0x115f }, + { 0x231a, 0x231b }, + { 0x2329, 0x232a }, + { 0x23e9, 0x23ec }, + { 0x23f0, 0x23f0 }, + { 0x23f3, 0x23f3 }, + { 0x25fd, 0x25fe }, + { 0x2614, 0x2615 }, + { 0x2648, 0x2653 }, + { 0x267f, 0x267f }, + { 0x2693, 0x2693 }, + { 0x26a1, 0x26a1 }, + { 0x26aa, 0x26ab }, + { 0x26bd, 0x26be }, + { 0x26c4, 0x26c5 }, + { 0x26ce, 0x26ce }, + { 0x26d4, 0x26d4 }, + { 0x26ea, 0x26ea }, + { 0x26f2, 0x26f3 }, + { 0x26f5, 0x26f5 }, + { 0x26fa, 0x26fa }, + { 0x26fd, 0x26fd }, + { 0x2705, 0x2705 }, + { 0x270a, 0x270b }, + { 0x2728, 0x2728 }, + { 0x274c, 0x274c }, + { 0x274e, 0x274e }, + { 0x2753, 0x2755 }, + { 0x2757, 0x2757 }, + { 0x2795, 0x2797 }, + { 0x27b0, 0x27b0 }, + { 0x27bf, 0x27bf }, + { 0x2b1b, 0x2b1c }, + { 0x2b50, 0x2b50 }, + { 0x2b55, 0x2b55 }, + { 0x2e80, 0x2e99 }, + { 0x2e9b, 0x2ef3 }, + { 0x2f00, 0x2fd5 }, + { 0x2ff0, 0x2ffb }, + { 0x3000, 0x303e }, + { 0x3041, 0x3096 }, + { 0x3099, 0x30ff }, + { 0x3105, 0x312f }, + { 0x3131, 0x318e }, + { 0x3190, 0x31ba }, + { 0x31c0, 0x31e3 }, + { 0x31f0, 0x321e }, + { 0x3220, 0x3247 }, + { 0x3250, 0x4dbf }, + { 0x4e00, 0xa48c }, + { 0xa490, 0xa4c6 }, + { 0xa960, 0xa97c }, + { 0xac00, 0xd7a3 }, + { 0xf900, 0xfaff }, + { 0xfe10, 0xfe19 }, + { 0xfe30, 0xfe52 }, + { 0xfe54, 0xfe66 }, + { 0xfe68, 0xfe6b }, + { 0xff01, 0xff60 }, + { 0xffe0, 0xffe6 }, + { 0x16fe0, 0x16fe3 }, + { 0x17000, 0x187f7 }, + { 0x18800, 0x18af2 }, + { 0x1b000, 0x1b11e }, + { 0x1b150, 0x1b152 }, + { 0x1b164, 0x1b167 }, + { 0x1b170, 0x1b2fb }, + { 0x1f004, 0x1f004 }, + { 0x1f0cf, 0x1f0cf }, + { 0x1f18e, 0x1f18e }, + { 0x1f191, 0x1f19a }, + { 0x1f200, 0x1f202 }, + { 0x1f210, 0x1f23b }, + { 0x1f240, 0x1f248 }, + { 0x1f250, 0x1f251 }, + { 0x1f260, 0x1f265 }, + { 0x1f300, 0x1f320 }, + { 0x1f32d, 0x1f335 }, + { 0x1f337, 0x1f37c }, + { 0x1f37e, 0x1f393 }, + { 0x1f3a0, 0x1f3ca }, + { 0x1f3cf, 0x1f3d3 }, + { 0x1f3e0, 0x1f3f0 }, + { 0x1f3f4, 0x1f3f4 }, + { 0x1f3f8, 0x1f43e }, + { 0x1f440, 0x1f440 }, + { 0x1f442, 0x1f4fc }, + { 0x1f4ff, 0x1f53d }, + { 0x1f54b, 0x1f54e }, + { 0x1f550, 0x1f567 }, + { 0x1f57a, 0x1f57a }, + { 0x1f595, 0x1f596 }, + { 0x1f5a4, 0x1f5a4 }, + { 0x1f5fb, 0x1f64f }, + { 0x1f680, 0x1f6c5 }, + { 0x1f6cc, 0x1f6cc }, + { 0x1f6d0, 0x1f6d2 }, + { 0x1f6d5, 0x1f6d5 }, + { 0x1f6eb, 0x1f6ec }, + { 0x1f6f4, 0x1f6fa }, + { 0x1f7e0, 0x1f7eb }, + { 0x1f90d, 0x1f971 }, + { 0x1f973, 0x1f976 }, + { 0x1f97a, 0x1f9a2 }, + { 0x1f9a5, 0x1f9aa }, + { 0x1f9ae, 0x1f9ca }, + { 0x1f9cd, 0x1f9ff }, + { 0x1fa70, 0x1fa73 }, + { 0x1fa78, 0x1fa7a }, + { 0x1fa80, 0x1fa82 }, + { 0x1fa90, 0x1fa95 }, diff --git a/src/libs/3rdparty/libvterm/src/keyboard.c b/src/libs/3rdparty/libvterm/src/keyboard.c new file mode 100644 index 00000000000..d31c8be12d3 --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/keyboard.c @@ -0,0 +1,226 @@ +#include "vterm_internal.h" + +#include + +#include "utf8.h" + +void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) +{ + /* The shift modifier is never important for Unicode characters + * apart from Space + */ + if(c != ' ') + mod &= ~VTERM_MOD_SHIFT; + + if(mod == 0) { + // Normal text - ignore just shift + char str[6]; + int seqlen = fill_utf8(c, str); + vterm_push_output_bytes(vt, str, seqlen); + return; + } + + int needs_CSIu; + switch(c) { + /* Special Ctrl- letters that can't be represented elsewise */ + case 'i': case 'j': case 'm': case '[': + needs_CSIu = 1; + break; + /* Ctrl-\ ] ^ _ don't need CSUu */ + case '\\': case ']': case '^': case '_': + needs_CSIu = 0; + break; + /* Shift-space needs CSIu */ + case ' ': + needs_CSIu = !!(mod & VTERM_MOD_SHIFT); + break; + /* All other characters needs CSIu except for letters a-z */ + default: + needs_CSIu = (c < 'a' || c > 'z'); + } + + /* ALT we can just prefix with ESC; anything else requires CSI u */ + if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) { + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1); + return; + } + + if(mod & VTERM_MOD_CTRL) + c &= 0x1f; + + vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c); +} + +typedef struct { + enum { + KEYCODE_NONE, + KEYCODE_LITERAL, + KEYCODE_TAB, + KEYCODE_ENTER, + KEYCODE_SS3, + KEYCODE_CSI, + KEYCODE_CSI_CURSOR, + KEYCODE_CSINUM, + KEYCODE_KEYPAD, + } type; + char literal; + int csinum; +} keycodes_s; + +static keycodes_s keycodes[] = { + { KEYCODE_NONE }, // NONE + + { KEYCODE_ENTER, '\r' }, // ENTER + { KEYCODE_TAB, '\t' }, // TAB + { KEYCODE_LITERAL, '\x7f' }, // BACKSPACE == ASCII DEL + { KEYCODE_LITERAL, '\x1b' }, // ESCAPE + + { KEYCODE_CSI_CURSOR, 'A' }, // UP + { KEYCODE_CSI_CURSOR, 'B' }, // DOWN + { KEYCODE_CSI_CURSOR, 'D' }, // LEFT + { KEYCODE_CSI_CURSOR, 'C' }, // RIGHT + + { KEYCODE_CSINUM, '~', 2 }, // INS + { KEYCODE_CSINUM, '~', 3 }, // DEL + { KEYCODE_CSI_CURSOR, 'H' }, // HOME + { KEYCODE_CSI_CURSOR, 'F' }, // END + { KEYCODE_CSINUM, '~', 5 }, // PAGEUP + { KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN +}; + +static keycodes_s keycodes_fn[] = { + { KEYCODE_NONE }, // F0 - shouldn't happen + { KEYCODE_SS3, 'P' }, // F1 + { KEYCODE_SS3, 'Q' }, // F2 + { KEYCODE_SS3, 'R' }, // F3 + { KEYCODE_SS3, 'S' }, // F4 + { KEYCODE_CSINUM, '~', 15 }, // F5 + { KEYCODE_CSINUM, '~', 17 }, // F6 + { KEYCODE_CSINUM, '~', 18 }, // F7 + { KEYCODE_CSINUM, '~', 19 }, // F8 + { KEYCODE_CSINUM, '~', 20 }, // F9 + { KEYCODE_CSINUM, '~', 21 }, // F10 + { KEYCODE_CSINUM, '~', 23 }, // F11 + { KEYCODE_CSINUM, '~', 24 }, // F12 +}; + +static keycodes_s keycodes_kp[] = { + { KEYCODE_KEYPAD, '0', 'p' }, // KP_0 + { KEYCODE_KEYPAD, '1', 'q' }, // KP_1 + { KEYCODE_KEYPAD, '2', 'r' }, // KP_2 + { KEYCODE_KEYPAD, '3', 's' }, // KP_3 + { KEYCODE_KEYPAD, '4', 't' }, // KP_4 + { KEYCODE_KEYPAD, '5', 'u' }, // KP_5 + { KEYCODE_KEYPAD, '6', 'v' }, // KP_6 + { KEYCODE_KEYPAD, '7', 'w' }, // KP_7 + { KEYCODE_KEYPAD, '8', 'x' }, // KP_8 + { KEYCODE_KEYPAD, '9', 'y' }, // KP_9 + { KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT + { KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS + { KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA + { KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS + { KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD + { KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE + { KEYCODE_KEYPAD, '\n', 'M' }, // KP_ENTER + { KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL +}; + +void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) +{ + if(key == VTERM_KEY_NONE) + return; + + keycodes_s k; + if(key < VTERM_KEY_FUNCTION_0) { + if(key >= sizeof(keycodes)/sizeof(keycodes[0])) + return; + k = keycodes[key]; + } + else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) { + if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0])) + return; + k = keycodes_fn[key - VTERM_KEY_FUNCTION_0]; + } + else if(key >= VTERM_KEY_KP_0) { + if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0])) + return; + k = keycodes_kp[key - VTERM_KEY_KP_0]; + } + + switch(k.type) { + case KEYCODE_NONE: + break; + + case KEYCODE_TAB: + /* Shift-Tab is CSI Z but plain Tab is 0x09 */ + if(mod == VTERM_MOD_SHIFT) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z"); + else if(mod & VTERM_MOD_SHIFT) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1); + else + goto case_LITERAL; + break; + + case KEYCODE_ENTER: + /* Enter is CRLF in newline mode, but just LF in linefeed */ + if(vt->state->mode.newline) + vterm_push_output_sprintf(vt, "\r\n"); + else + goto case_LITERAL; + break; + + case KEYCODE_LITERAL: case_LITERAL: + if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL)) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1); + else + vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal); + break; + + case KEYCODE_SS3: case_SS3: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal); + else + goto case_CSI; + break; + + case KEYCODE_CSI: case_CSI: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal); + else + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal); + break; + + case KEYCODE_CSINUM: + if(mod == 0) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal); + else + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal); + break; + + case KEYCODE_CSI_CURSOR: + if(vt->state->mode.cursor) + goto case_SS3; + else + goto case_CSI; + + case KEYCODE_KEYPAD: + if(vt->state->mode.keypad) { + k.literal = k.csinum; + goto case_SS3; + } + else + goto case_LITERAL; + } +} + +void vterm_keyboard_start_paste(VTerm *vt) +{ + if(vt->state->mode.bracketpaste) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~"); +} + +void vterm_keyboard_end_paste(VTerm *vt) +{ + if(vt->state->mode.bracketpaste) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~"); +} diff --git a/src/libs/3rdparty/libvterm/src/mouse.c b/src/libs/3rdparty/libvterm/src/mouse.c new file mode 100644 index 00000000000..bd713f8106a --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/mouse.c @@ -0,0 +1,99 @@ +#include "vterm_internal.h" + +#include "utf8.h" + +static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row) +{ + modifiers <<= 2; + + switch(state->mouse_protocol) { + case MOUSE_X10: + if(col + 0x21 > 0xff) + col = 0xff - 0x21; + if(row + 0x21 > 0xff) + row = 0xff - 0x21; + + if(!pressed) + code = 3; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c", + (code | modifiers) + 0x20, col + 0x21, row + 0x21); + break; + + case MOUSE_UTF8: + { + char utf8[18]; size_t len = 0; + + if(!pressed) + code = 3; + + len += fill_utf8((code | modifiers) + 0x20, utf8 + len); + len += fill_utf8(col + 0x21, utf8 + len); + len += fill_utf8(row + 0x21, utf8 + len); + utf8[len] = 0; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8); + } + break; + + case MOUSE_SGR: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c", + code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm'); + break; + + case MOUSE_RXVT: + if(!pressed) + code = 3; + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM", + code | modifiers, col + 1, row + 1); + break; + } +} + +void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod) +{ + VTermState *state = vt->state; + + if(col == state->mouse_col && row == state->mouse_row) + return; + + state->mouse_col = col; + state->mouse_row = row; + + if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) || + (state->mouse_flags & MOUSE_WANT_MOVE)) { + int button = state->mouse_buttons & 0x01 ? 1 : + state->mouse_buttons & 0x02 ? 2 : + state->mouse_buttons & 0x04 ? 3 : 4; + output_mouse(state, button-1 + 0x20, 1, mod, col, row); + } +} + +void vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod) +{ + VTermState *state = vt->state; + + int old_buttons = state->mouse_buttons; + + if(button > 0 && button <= 3) { + if(pressed) + state->mouse_buttons |= (1 << (button-1)); + else + state->mouse_buttons &= ~(1 << (button-1)); + } + + /* Most of the time we don't get button releases from 4/5 */ + if(state->mouse_buttons == old_buttons && button < 4) + return; + + if(!state->mouse_flags) + return; + + if(button < 4) { + output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row); + } + else if(button < 6) { + output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row); + } +} diff --git a/src/libs/3rdparty/libvterm/src/parser.c b/src/libs/3rdparty/libvterm/src/parser.c new file mode 100644 index 00000000000..b43a549cefc --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/parser.c @@ -0,0 +1,402 @@ +#include "vterm_internal.h" + +#include +#include + +#undef DEBUG_PARSER + +static bool is_intermed(unsigned char c) +{ + return c >= 0x20 && c <= 0x2f; +} + +static void do_control(VTerm *vt, unsigned char control) +{ + if(vt->parser.callbacks && vt->parser.callbacks->control) + if((*vt->parser.callbacks->control)(control, vt->parser.cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled control 0x%02x\n", control); +} + +static void do_csi(VTerm *vt, char command) +{ +#ifdef DEBUG_PARSER + printf("Parsed CSI args as:\n", arglen, args); + printf(" leader: %s\n", vt->parser.v.csi.leader); + for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) { + printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi])); + if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi])) + printf("\n"); + printf(" intermed: %s\n", vt->parser.intermed); + } +#endif + + if(vt->parser.callbacks && vt->parser.callbacks->csi) + if((*vt->parser.callbacks->csi)( + vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL, + vt->parser.v.csi.args, + vt->parser.v.csi.argi, + vt->parser.intermedlen ? vt->parser.intermed : NULL, + command, + vt->parser.cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled CSI %c\n", command); +} + +static void do_escape(VTerm *vt, char command) +{ + char seq[INTERMED_MAX+1]; + + size_t len = vt->parser.intermedlen; + strncpy(seq, vt->parser.intermed, len); + seq[len++] = command; + seq[len] = 0; + + if(vt->parser.callbacks && vt->parser.callbacks->escape) + if((*vt->parser.callbacks->escape)(seq, len, vt->parser.cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled escape ESC 0x%02x\n", command); +} + +static void string_fragment(VTerm *vt, const char *str, size_t len, bool final) +{ + VTermStringFragment frag = { + .str = str, + .len = len, + .initial = vt->parser.string_initial, + .final = final, + }; + + switch(vt->parser.state) { + case OSC: + if(vt->parser.callbacks && vt->parser.callbacks->osc) + (*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata); + break; + + case DCS: + if(vt->parser.callbacks && vt->parser.callbacks->dcs) + (*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata); + break; + + case APC: + if(vt->parser.callbacks && vt->parser.callbacks->apc) + (*vt->parser.callbacks->apc)(frag, vt->parser.cbdata); + break; + + case PM: + if(vt->parser.callbacks && vt->parser.callbacks->pm) + (*vt->parser.callbacks->pm)(frag, vt->parser.cbdata); + break; + + case SOS: + if(vt->parser.callbacks && vt->parser.callbacks->sos) + (*vt->parser.callbacks->sos)(frag, vt->parser.cbdata); + break; + + case NORMAL: + case CSI_LEADER: + case CSI_ARGS: + case CSI_INTERMED: + case OSC_COMMAND: + case DCS_COMMAND: + break; + } + + vt->parser.string_initial = false; +} + +size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) +{ + size_t pos = 0; + const char *string_start; + + switch(vt->parser.state) { + case NORMAL: + case CSI_LEADER: + case CSI_ARGS: + case CSI_INTERMED: + case OSC_COMMAND: + case DCS_COMMAND: + string_start = NULL; + break; + case OSC: + case DCS: + case APC: + case PM: + case SOS: + string_start = bytes; + break; + } + +#define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0) +#define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL) + +#define IS_STRING_STATE() (vt->parser.state >= OSC_COMMAND) + + for( ; pos < len; pos++) { + unsigned char c = bytes[pos]; + bool c1_allowed = !vt->mode.utf8; + + if(c == 0x00 || c == 0x7f) { // NUL, DEL + if(IS_STRING_STATE()) { + string_fragment(vt, string_start, bytes + pos - string_start, false); + string_start = bytes + pos + 1; + } + if(vt->parser.emit_nul) + do_control(vt, c); + continue; + } + if(c == 0x18 || c == 0x1a) { // CAN, SUB + vt->parser.in_esc = false; + ENTER_NORMAL_STATE(); + if(vt->parser.emit_nul) + do_control(vt, c); + continue; + } + else if(c == 0x1b) { // ESC + vt->parser.intermedlen = 0; + if(!IS_STRING_STATE()) + vt->parser.state = NORMAL; + vt->parser.in_esc = true; + continue; + } + else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state + IS_STRING_STATE()) { + // fallthrough + } + else if(c < 0x20) { // other C0 + if(vt->parser.state == SOS) + continue; // All other C0s permitted in SOS + + if(IS_STRING_STATE()) + string_fragment(vt, string_start, bytes + pos - string_start, false); + do_control(vt, c); + if(IS_STRING_STATE()) + string_start = bytes + pos + 1; + continue; + } + // else fallthrough + + size_t string_len = bytes + pos - string_start; + + if(vt->parser.in_esc) { + // Hoist an ESC letter into a C1 if we're not in a string mode + // Always accept ESC \ == ST even in string mode + if(!vt->parser.intermedlen && + c >= 0x40 && c < 0x60 && + ((!IS_STRING_STATE() || c == 0x5c))) { + c += 0x40; + c1_allowed = true; + if(string_len) + string_len -= 1; + vt->parser.in_esc = false; + } + else { + string_start = NULL; + vt->parser.state = NORMAL; + } + } + + switch(vt->parser.state) { + case CSI_LEADER: + /* Extract leader bytes 0x3c to 0x3f */ + if(c >= 0x3c && c <= 0x3f) { + if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1) + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c; + break; + } + + /* else fallthrough */ + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0; + + vt->parser.v.csi.argi = 0; + vt->parser.v.csi.args[0] = CSI_ARG_MISSING; + vt->parser.state = CSI_ARGS; + + /* fallthrough */ + case CSI_ARGS: + /* Numerical value of argument */ + if(c >= '0' && c <= '9') { + if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING) + vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0; + vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10; + vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0'; + break; + } + if(c == ':') { + vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE; + c = ';'; + } + if(c == ';') { + vt->parser.v.csi.argi++; + vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING; + break; + } + + /* else fallthrough */ + vt->parser.v.csi.argi++; + vt->parser.intermedlen = 0; + vt->parser.state = CSI_INTERMED; + case CSI_INTERMED: + if(is_intermed(c)) { + if(vt->parser.intermedlen < INTERMED_MAX-1) + vt->parser.intermed[vt->parser.intermedlen++] = c; + break; + } + else if(c == 0x1b) { + /* ESC in CSI cancels */ + } + else if(c >= 0x40 && c <= 0x7e) { + vt->parser.intermed[vt->parser.intermedlen] = 0; + do_csi(vt, c); + } + /* else was invalid CSI */ + + ENTER_NORMAL_STATE(); + break; + + case OSC_COMMAND: + /* Numerical value of command */ + if(c >= '0' && c <= '9') { + if(vt->parser.v.osc.command == -1) + vt->parser.v.osc.command = 0; + else + vt->parser.v.osc.command *= 10; + vt->parser.v.osc.command += c - '0'; + break; + } + if(c == ';') { + vt->parser.state = OSC; + string_start = bytes + pos + 1; + break; + } + + /* else fallthrough */ + string_start = bytes + pos; + string_len = 0; + vt->parser.state = OSC; + goto string_state; + + case DCS_COMMAND: + if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX) + vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c; + + if(c >= 0x40 && c<= 0x7e) { + string_start = bytes + pos + 1; + vt->parser.state = DCS; + } + break; + +string_state: + case OSC: + case DCS: + case APC: + case PM: + case SOS: + if(c == 0x07 || (c1_allowed && c == 0x9c)) { + string_fragment(vt, string_start, string_len, true); + ENTER_NORMAL_STATE(); + } + break; + + case NORMAL: + if(vt->parser.in_esc) { + if(is_intermed(c)) { + if(vt->parser.intermedlen < INTERMED_MAX-1) + vt->parser.intermed[vt->parser.intermedlen++] = c; + } + else if(c >= 0x30 && c < 0x7f) { + do_escape(vt, c); + vt->parser.in_esc = 0; + ENTER_NORMAL_STATE(); + } + else { + DEBUG_LOG("TODO: Unhandled byte %02x in Escape\n", c); + } + break; + } + if(c1_allowed && c >= 0x80 && c < 0xa0) { + switch(c) { + case 0x90: // DCS + vt->parser.string_initial = true; + vt->parser.v.dcs.commandlen = 0; + ENTER_STATE(DCS_COMMAND); + break; + case 0x98: // SOS + vt->parser.string_initial = true; + ENTER_STATE(SOS); + string_start = bytes + pos + 1; + string_len = 0; + break; + case 0x9b: // CSI + vt->parser.v.csi.leaderlen = 0; + ENTER_STATE(CSI_LEADER); + break; + case 0x9d: // OSC + vt->parser.v.osc.command = -1; + vt->parser.string_initial = true; + string_start = bytes + pos + 1; + ENTER_STATE(OSC_COMMAND); + break; + case 0x9e: // PM + vt->parser.string_initial = true; + ENTER_STATE(PM); + string_start = bytes + pos + 1; + string_len = 0; + break; + case 0x9f: // APC + vt->parser.string_initial = true; + ENTER_STATE(APC); + string_start = bytes + pos + 1; + string_len = 0; + break; + default: + do_control(vt, c); + break; + } + } + else { + size_t eaten = 0; + if(vt->parser.callbacks && vt->parser.callbacks->text) + eaten = (*vt->parser.callbacks->text)(bytes + pos, len - pos, vt->parser.cbdata); + + if(!eaten) { + DEBUG_LOG("libvterm: Text callback did not consume any input\n"); + /* force it to make progress */ + eaten = 1; + } + + pos += (eaten - 1); // we'll ++ it again in a moment + } + break; + } + } + + if(string_start) { + size_t string_len = bytes + pos - string_start; + if(vt->parser.in_esc) + string_len -= 1; + string_fragment(vt, string_start, string_len, false); + } + + return len; +} + +void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user) +{ + vt->parser.callbacks = callbacks; + vt->parser.cbdata = user; +} + +void *vterm_parser_get_cbdata(VTerm *vt) +{ + return vt->parser.cbdata; +} + +void vterm_parser_set_emit_nul(VTerm *vt, bool emit) +{ + vt->parser.emit_nul = emit; +} diff --git a/src/libs/3rdparty/libvterm/src/pen.c b/src/libs/3rdparty/libvterm/src/pen.c new file mode 100644 index 00000000000..2227a6fcd33 --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/pen.c @@ -0,0 +1,607 @@ +#include "vterm_internal.h" + +#include + +/** + * Structure used to store RGB triples without the additional metadata stored in + * VTermColor. + */ +typedef struct { + uint8_t red, green, blue; +} VTermRGB; + +static const VTermRGB ansi_colors[] = { + /* R G B */ + { 0, 0, 0 }, // black + { 224, 0, 0 }, // red + { 0, 224, 0 }, // green + { 224, 224, 0 }, // yellow + { 0, 0, 224 }, // blue + { 224, 0, 224 }, // magenta + { 0, 224, 224 }, // cyan + { 224, 224, 224 }, // white == light grey + + // high intensity + { 128, 128, 128 }, // black + { 255, 64, 64 }, // red + { 64, 255, 64 }, // green + { 255, 255, 64 }, // yellow + { 64, 64, 255 }, // blue + { 255, 64, 255 }, // magenta + { 64, 255, 255 }, // cyan + { 255, 255, 255 }, // white for real +}; + +static int ramp6[] = { + 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF, +}; + +static int ramp24[] = { + 0x00, 0x0B, 0x16, 0x21, 0x2C, 0x37, 0x42, 0x4D, 0x58, 0x63, 0x6E, 0x79, + 0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF, +}; + +static void lookup_default_colour_ansi(long idx, VTermColor *col) +{ + if (idx >= 0 && idx < 16) { + vterm_color_rgb( + col, + ansi_colors[idx].red, ansi_colors[idx].green, ansi_colors[idx].blue); + } +} + +static bool lookup_colour_ansi(const VTermState *state, long index, VTermColor *col) +{ + if(index >= 0 && index < 16) { + *col = state->colors[index]; + return true; + } + + return false; +} + +static bool lookup_colour_palette(const VTermState *state, long index, VTermColor *col) +{ + if(index >= 0 && index < 16) { + // Normal 8 colours or high intensity - parse as palette 0 + return lookup_colour_ansi(state, index, col); + } + else if(index >= 16 && index < 232) { + // 216-colour cube + index -= 16; + + vterm_color_rgb(col, ramp6[index/6/6 % 6], + ramp6[index/6 % 6], + ramp6[index % 6]); + + return true; + } + else if(index >= 232 && index < 256) { + // 24 greyscales + index -= 232; + + vterm_color_rgb(col, ramp24[index], ramp24[index], ramp24[index]); + + return true; + } + + return false; +} + +static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col) +{ + switch(palette) { + case 2: // RGB mode - 3 args contain colour values directly + if(argcount < 3) + return argcount; + + vterm_color_rgb(col, CSI_ARG(args[0]), CSI_ARG(args[1]), CSI_ARG(args[2])); + + return 3; + + case 5: // XTerm 256-colour mode + if (!argcount || CSI_ARG_IS_MISSING(args[0])) { + return argcount ? 1 : 0; + } + + vterm_color_indexed(col, args[0]); + + return argcount ? 1 : 0; + + default: + DEBUG_LOG("Unrecognised colour palette %d\n", palette); + return 0; + } +} + +// Some conveniences + +static void setpenattr(VTermState *state, VTermAttr attr, VTermValueType type, VTermValue *val) +{ +#ifdef DEBUG + if(type != vterm_get_attr_type(attr)) { + DEBUG_LOG("Cannot set attr %d as it has type %d, not type %d\n", + attr, vterm_get_attr_type(attr), type); + return; + } +#endif + if(state->callbacks && state->callbacks->setpenattr) + (*state->callbacks->setpenattr)(attr, val, state->cbdata); +} + +static void setpenattr_bool(VTermState *state, VTermAttr attr, int boolean) +{ + VTermValue val = { .boolean = boolean }; + setpenattr(state, attr, VTERM_VALUETYPE_BOOL, &val); +} + +static void setpenattr_int(VTermState *state, VTermAttr attr, int number) +{ + VTermValue val = { .number = number }; + setpenattr(state, attr, VTERM_VALUETYPE_INT, &val); +} + +static void setpenattr_col(VTermState *state, VTermAttr attr, VTermColor color) +{ + VTermValue val = { .color = color }; + setpenattr(state, attr, VTERM_VALUETYPE_COLOR, &val); +} + +static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col) +{ + VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg; + + vterm_color_indexed(colp, col); + + setpenattr_col(state, attr, *colp); +} + +INTERNAL void vterm_state_newpen(VTermState *state) +{ + // 90% grey so that pure white is brighter + vterm_color_rgb(&state->default_fg, 240, 240, 240); + vterm_color_rgb(&state->default_bg, 0, 0, 0); + vterm_state_set_default_colors(state, &state->default_fg, &state->default_bg); + + for(int col = 0; col < 16; col++) + lookup_default_colour_ansi(col, &state->colors[col]); +} + +INTERNAL void vterm_state_resetpen(VTermState *state) +{ + state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0); + state->pen.underline = 0; setpenattr_int (state, VTERM_ATTR_UNDERLINE, 0); + state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); + state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0); + state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); + state->pen.conceal = 0; setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); + state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); + state->pen.font = 0; setpenattr_int (state, VTERM_ATTR_FONT, 0); + state->pen.small = 0; setpenattr_bool(state, VTERM_ATTR_SMALL, 0); + state->pen.baseline = 0; setpenattr_int (state, VTERM_ATTR_BASELINE, 0); + + state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg); + state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg); +} + +INTERNAL void vterm_state_savepen(VTermState *state, int save) +{ + if(save) { + state->saved.pen = state->pen; + } + else { + state->pen = state->saved.pen; + + setpenattr_bool(state, VTERM_ATTR_BOLD, state->pen.bold); + setpenattr_int (state, VTERM_ATTR_UNDERLINE, state->pen.underline); + setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic); + setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink); + setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse); + setpenattr_bool(state, VTERM_ATTR_CONCEAL, state->pen.conceal); + setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike); + setpenattr_int (state, VTERM_ATTR_FONT, state->pen.font); + setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small); + setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline); + + setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg); + setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg); + } +} + +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b) +{ + /* First make sure that the two colours are of the same type (RGB/Indexed) */ + if (a->type != b->type) { + return false; + } + + /* Depending on the type inspect the corresponding members */ + if (VTERM_COLOR_IS_INDEXED(a)) { + return a->indexed.idx == b->indexed.idx; + } + else if (VTERM_COLOR_IS_RGB(a)) { + return (a->rgb.red == b->rgb.red) + && (a->rgb.green == b->rgb.green) + && (a->rgb.blue == b->rgb.blue); + } + + return 0; +} + +void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg) +{ + *default_fg = state->default_fg; + *default_bg = state->default_bg; +} + +void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col) +{ + lookup_colour_palette(state, index, col); +} + +void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg) +{ + if(default_fg) { + state->default_fg = *default_fg; + state->default_fg.type = (state->default_fg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_FG; + } + + if(default_bg) { + state->default_bg = *default_bg; + state->default_bg.type = (state->default_bg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_BG; + } +} + +void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col) +{ + if(index >= 0 && index < 16) + state->colors[index] = *col; +} + +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col) +{ + if (VTERM_COLOR_IS_INDEXED(col)) { /* Convert indexed colors to RGB */ + lookup_colour_palette(state, col->indexed.idx, col); + } + col->type &= VTERM_COLOR_TYPE_MASK; /* Reset any metadata but the type */ +} + +void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright) +{ + state->bold_is_highbright = bold_is_highbright; +} + +INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount) +{ + // SGR - ECMA-48 8.3.117 + + int argi = 0; + int value; + + while(argi < argcount) { + // This logic is easier to do 'done' backwards; set it true, and make it + // false again in the 'default' case + int done = 1; + + long arg; + switch(arg = CSI_ARG(args[argi])) { + case CSI_ARG_MISSING: + case 0: // Reset + vterm_state_resetpen(state); + break; + + case 1: { // Bold on + const VTermColor *fg = &state->pen.fg; + state->pen.bold = 1; + setpenattr_bool(state, VTERM_ATTR_BOLD, 1); + if(!VTERM_COLOR_IS_DEFAULT_FG(fg) && VTERM_COLOR_IS_INDEXED(fg) && fg->indexed.idx < 8 && state->bold_is_highbright) + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, fg->indexed.idx + (state->pen.bold ? 8 : 0)); + break; + } + + case 3: // Italic on + state->pen.italic = 1; + setpenattr_bool(state, VTERM_ATTR_ITALIC, 1); + break; + + case 4: // Underline + state->pen.underline = VTERM_UNDERLINE_SINGLE; + if(CSI_ARG_HAS_MORE(args[argi])) { + argi++; + switch(CSI_ARG(args[argi])) { + case 0: + state->pen.underline = 0; + break; + case 1: + state->pen.underline = VTERM_UNDERLINE_SINGLE; + break; + case 2: + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + break; + case 3: + state->pen.underline = VTERM_UNDERLINE_CURLY; + break; + } + } + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); + break; + + case 5: // Blink + state->pen.blink = 1; + setpenattr_bool(state, VTERM_ATTR_BLINK, 1); + break; + + case 7: // Reverse on + state->pen.reverse = 1; + setpenattr_bool(state, VTERM_ATTR_REVERSE, 1); + break; + + case 8: // Conceal on + state->pen.conceal = 1; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 1); + break; + + case 9: // Strikethrough on + state->pen.strike = 1; + setpenattr_bool(state, VTERM_ATTR_STRIKE, 1); + break; + + case 10: case 11: case 12: case 13: case 14: + case 15: case 16: case 17: case 18: case 19: // Select font + state->pen.font = CSI_ARG(args[argi]) - 10; + setpenattr_int(state, VTERM_ATTR_FONT, state->pen.font); + break; + + case 21: // Underline double + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); + break; + + case 22: // Bold off + state->pen.bold = 0; + setpenattr_bool(state, VTERM_ATTR_BOLD, 0); + break; + + case 23: // Italic and Gothic (currently unsupported) off + state->pen.italic = 0; + setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); + break; + + case 24: // Underline off + state->pen.underline = 0; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, 0); + break; + + case 25: // Blink off + state->pen.blink = 0; + setpenattr_bool(state, VTERM_ATTR_BLINK, 0); + break; + + case 27: // Reverse off + state->pen.reverse = 0; + setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); + break; + + case 28: // Conceal off (Reveal) + state->pen.conceal = 0; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); + break; + + case 29: // Strikethrough off + state->pen.strike = 0; + setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); + break; + + case 30: case 31: case 32: case 33: + case 34: case 35: case 36: case 37: // Foreground colour palette + value = CSI_ARG(args[argi]) - 30; + if(state->pen.bold && state->bold_is_highbright) + value += 8; + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); + break; + + case 38: // Foreground colour alternative palette + if(argcount - argi < 1) + return; + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg); + setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); + break; + + case 39: // Foreground colour default + state->pen.fg = state->default_fg; + setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); + break; + + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: // Background colour palette + value = CSI_ARG(args[argi]) - 40; + set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); + break; + + case 48: // Background colour alternative palette + if(argcount - argi < 1) + return; + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg); + setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); + break; + + case 49: // Default background + state->pen.bg = state->default_bg; + setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); + break; + + case 73: // Superscript + case 74: // Subscript + case 75: // Superscript/subscript off + state->pen.small = (arg != 75); + state->pen.baseline = + (arg == 73) ? VTERM_BASELINE_RAISE : + (arg == 74) ? VTERM_BASELINE_LOWER : + VTERM_BASELINE_NORMAL; + setpenattr_bool(state, VTERM_ATTR_SMALL, state->pen.small); + setpenattr_int (state, VTERM_ATTR_BASELINE, state->pen.baseline); + break; + + case 90: case 91: case 92: case 93: + case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette + value = CSI_ARG(args[argi]) - 90 + 8; + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); + break; + + case 100: case 101: case 102: case 103: + case 104: case 105: case 106: case 107: // Background colour high-intensity palette + value = CSI_ARG(args[argi]) - 100 + 8; + set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); + break; + + default: + done = 0; + break; + } + + if(!done) + DEBUG_LOG("libvterm: Unhandled CSI SGR %ld\n", arg); + + while(CSI_ARG_HAS_MORE(args[argi++])); + } +} + +static int vterm_state_getpen_color(const VTermColor *col, int argi, long args[], int fg) +{ + /* Do nothing if the given color is the default color */ + if (( fg && VTERM_COLOR_IS_DEFAULT_FG(col)) || + (!fg && VTERM_COLOR_IS_DEFAULT_BG(col))) { + return argi; + } + + /* Decide whether to send an indexed color or an RGB color */ + if (VTERM_COLOR_IS_INDEXED(col)) { + const uint8_t idx = col->indexed.idx; + if (idx < 8) { + args[argi++] = (idx + (fg ? 30 : 40)); + } + else if (idx < 16) { + args[argi++] = (idx - 8 + (fg ? 90 : 100)); + } + else { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 5; + args[argi++] = idx; + } + } + else if (VTERM_COLOR_IS_RGB(col)) { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 2; + args[argi++] = CSI_ARG_FLAG_MORE | col->rgb.red; + args[argi++] = CSI_ARG_FLAG_MORE | col->rgb.green; + args[argi++] = col->rgb.blue; + } + return argi; +} + +INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount) +{ + int argi = 0; + + if(state->pen.bold) + args[argi++] = 1; + + if(state->pen.italic) + args[argi++] = 3; + + if(state->pen.underline == VTERM_UNDERLINE_SINGLE) + args[argi++] = 4; + if(state->pen.underline == VTERM_UNDERLINE_CURLY) + args[argi++] = 4 | CSI_ARG_FLAG_MORE, args[argi++] = 3; + + if(state->pen.blink) + args[argi++] = 5; + + if(state->pen.reverse) + args[argi++] = 7; + + if(state->pen.conceal) + args[argi++] = 8; + + if(state->pen.strike) + args[argi++] = 9; + + if(state->pen.font) + args[argi++] = 10 + state->pen.font; + + if(state->pen.underline == VTERM_UNDERLINE_DOUBLE) + args[argi++] = 21; + + argi = vterm_state_getpen_color(&state->pen.fg, argi, args, true); + + argi = vterm_state_getpen_color(&state->pen.bg, argi, args, false); + + if(state->pen.small) { + if(state->pen.baseline == VTERM_BASELINE_RAISE) + args[argi++] = 73; + else if(state->pen.baseline == VTERM_BASELINE_LOWER) + args[argi++] = 74; + } + + return argi; +} + +int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val) +{ + switch(attr) { + case VTERM_ATTR_BOLD: + val->boolean = state->pen.bold; + return 1; + + case VTERM_ATTR_UNDERLINE: + val->number = state->pen.underline; + return 1; + + case VTERM_ATTR_ITALIC: + val->boolean = state->pen.italic; + return 1; + + case VTERM_ATTR_BLINK: + val->boolean = state->pen.blink; + return 1; + + case VTERM_ATTR_REVERSE: + val->boolean = state->pen.reverse; + return 1; + + case VTERM_ATTR_CONCEAL: + val->boolean = state->pen.conceal; + return 1; + + case VTERM_ATTR_STRIKE: + val->boolean = state->pen.strike; + return 1; + + case VTERM_ATTR_FONT: + val->number = state->pen.font; + return 1; + + case VTERM_ATTR_FOREGROUND: + val->color = state->pen.fg; + return 1; + + case VTERM_ATTR_BACKGROUND: + val->color = state->pen.bg; + return 1; + + case VTERM_ATTR_SMALL: + val->boolean = state->pen.small; + return 1; + + case VTERM_ATTR_BASELINE: + val->number = state->pen.baseline; + return 1; + + case VTERM_N_ATTRS: + return 0; + } + + return 0; +} diff --git a/src/libs/3rdparty/libvterm/src/rect.h b/src/libs/3rdparty/libvterm/src/rect.h new file mode 100644 index 00000000000..2114f24c1be --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/rect.h @@ -0,0 +1,56 @@ +/* + * Some utility functions on VTermRect structures + */ + +#define STRFrect "(%d,%d-%d,%d)" +#define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col + +/* Expand dst to contain src as well */ +static void rect_expand(VTermRect *dst, VTermRect *src) +{ + if(dst->start_row > src->start_row) dst->start_row = src->start_row; + if(dst->start_col > src->start_col) dst->start_col = src->start_col; + if(dst->end_row < src->end_row) dst->end_row = src->end_row; + if(dst->end_col < src->end_col) dst->end_col = src->end_col; +} + +/* Clip the dst to ensure it does not step outside of bounds */ +static void rect_clip(VTermRect *dst, VTermRect *bounds) +{ + if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row; + if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col; + if(dst->end_row > bounds->end_row) dst->end_row = bounds->end_row; + if(dst->end_col > bounds->end_col) dst->end_col = bounds->end_col; + /* Ensure it doesn't end up negatively-sized */ + if(dst->end_row < dst->start_row) dst->end_row = dst->start_row; + if(dst->end_col < dst->start_col) dst->end_col = dst->start_col; +} + +/* True if the two rectangles are equal */ +static int rect_equal(VTermRect *a, VTermRect *b) +{ + return (a->start_row == b->start_row) && + (a->start_col == b->start_col) && + (a->end_row == b->end_row) && + (a->end_col == b->end_col); +} + +/* True if small is contained entirely within big */ +static int rect_contains(VTermRect *big, VTermRect *small) +{ + if(small->start_row < big->start_row) return 0; + if(small->start_col < big->start_col) return 0; + if(small->end_row > big->end_row) return 0; + if(small->end_col > big->end_col) return 0; + return 1; +} + +/* True if the rectangles overlap at all */ +static int rect_intersects(VTermRect *a, VTermRect *b) +{ + if(a->start_row > b->end_row || b->start_row > a->end_row) + return 0; + if(a->start_col > b->end_col || b->start_col > a->end_col) + return 0; + return 1; +} diff --git a/src/libs/3rdparty/libvterm/src/screen.c b/src/libs/3rdparty/libvterm/src/screen.c new file mode 100644 index 00000000000..51c7f99e74a --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/screen.c @@ -0,0 +1,1183 @@ +#include "vterm_internal.h" + +#include +#include + +#include "rect.h" +#include "utf8.h" + +#define UNICODE_SPACE 0x20 +#define UNICODE_LINEFEED 0x0a + +#undef DEBUG_REFLOW + +/* State of the pen at some moment in time, also used in a cell */ +typedef struct +{ + /* After the bitfield */ + VTermColor fg, bg; + + unsigned int bold : 1; + unsigned int underline : 2; + unsigned int italic : 1; + unsigned int blink : 1; + unsigned int reverse : 1; + unsigned int conceal : 1; + unsigned int strike : 1; + unsigned int font : 4; /* 0 to 9 */ + unsigned int small : 1; + unsigned int baseline : 2; + + /* Extra state storage that isn't strictly pen-related */ + unsigned int protected_cell : 1; + unsigned int dwl : 1; /* on a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */ +} ScreenPen; + +/* Internal representation of a screen cell */ +typedef struct +{ + uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; + ScreenPen pen; +} ScreenCell; + +struct VTermScreen +{ + VTerm *vt; + VTermState *state; + + const VTermScreenCallbacks *callbacks; + void *cbdata; + + VTermDamageSize damage_merge; + /* start_row == -1 => no damage */ + VTermRect damaged; + VTermRect pending_scrollrect; + int pending_scroll_downward, pending_scroll_rightward; + + int rows; + int cols; + + unsigned int global_reverse : 1; + unsigned int reflow : 1; + + /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ + ScreenCell *buffers[2]; + + /* buffer will == buffers[0] or buffers[1], depending on altscreen */ + ScreenCell *buffer; + + /* buffer for a single screen row used in scrollback storage callbacks */ + VTermScreenCell *sb_buffer; + + ScreenPen pen; +}; + +static inline void clearcell(const VTermScreen *screen, ScreenCell *cell) +{ + cell->chars[0] = 0; + cell->pen = screen->pen; +} + +static inline ScreenCell *getcell(const VTermScreen *screen, int row, int col) +{ + if(row < 0 || row >= screen->rows) + return NULL; + if(col < 0 || col >= screen->cols) + return NULL; + return screen->buffer + (screen->cols * row) + col; +} + +static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) +{ + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); + + for(int row = 0; row < rows; row++) { + for(int col = 0; col < cols; col++) { + clearcell(screen, &new_buffer[row * cols + col]); + } + } + + return new_buffer; +} + +static void damagerect(VTermScreen *screen, VTermRect rect) +{ + VTermRect emit; + + switch(screen->damage_merge) { + case VTERM_DAMAGE_CELL: + /* Always emit damage event */ + emit = rect; + break; + + case VTERM_DAMAGE_ROW: + /* Emit damage longer than one row. Try to merge with existing damage in + * the same row */ + if(rect.end_row > rect.start_row + 1) { + // Bigger than 1 line - flush existing, emit this + vterm_screen_flush_damage(screen); + emit = rect; + } + else if(screen->damaged.start_row == -1) { + // None stored yet + screen->damaged = rect; + return; + } + else if(rect.start_row == screen->damaged.start_row) { + // Merge with the stored line + if(screen->damaged.start_col > rect.start_col) + screen->damaged.start_col = rect.start_col; + if(screen->damaged.end_col < rect.end_col) + screen->damaged.end_col = rect.end_col; + return; + } + else { + // Emit the currently stored line, store a new one + emit = screen->damaged; + screen->damaged = rect; + } + break; + + case VTERM_DAMAGE_SCREEN: + case VTERM_DAMAGE_SCROLL: + /* Never emit damage event */ + if(screen->damaged.start_row == -1) + screen->damaged = rect; + else { + rect_expand(&screen->damaged, &rect); + } + return; + + default: + DEBUG_LOG("TODO: Maybe merge damage for level %d\n", screen->damage_merge); + return; + } + + if(screen->callbacks && screen->callbacks->damage) + (*screen->callbacks->damage)(emit, screen->cbdata); +} + +static void damagescreen(VTermScreen *screen) +{ + VTermRect rect = { + .start_row = 0, + .end_row = screen->rows, + .start_col = 0, + .end_col = screen->cols, + }; + + damagerect(screen, rect); +} + +static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) +{ + VTermScreen *screen = user; + ScreenCell *cell = getcell(screen, pos.row, pos.col); + + if(!cell) + return 0; + + int i; + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { + cell->chars[i] = info->chars[i]; + cell->pen = screen->pen; + } + if(i < VTERM_MAX_CHARS_PER_CELL) + cell->chars[i] = 0; + + for(int col = 1; col < info->width; col++) + getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1; + + VTermRect rect = { + .start_row = pos.row, + .end_row = pos.row+1, + .start_col = pos.col, + .end_col = pos.col+info->width, + }; + + cell->pen.protected_cell = info->protected_cell; + cell->pen.dwl = info->dwl; + cell->pen.dhl = info->dhl; + + damagerect(screen, rect); + + return 1; +} + +static void sb_pushline_from_row(VTermScreen *screen, int row) +{ + VTermPos pos = { .row = row }; + for(pos.col = 0; pos.col < screen->cols; pos.col++) + vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); + + (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); +} + +static int moverect_internal(VTermRect dest, VTermRect src, void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->sb_pushline && + dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner + dest.end_col == screen->cols && // full width + screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen + for(int row = 0; row < src.start_row; row++) + sb_pushline_from_row(screen, row); + } + + int cols = src.end_col - src.start_col; + int downward = src.start_row - dest.start_row; + + int init_row, test_row, inc_row; + if(downward < 0) { + init_row = dest.end_row - 1; + test_row = dest.start_row - 1; + inc_row = -1; + } + else { + init_row = dest.start_row; + test_row = dest.end_row; + inc_row = +1; + } + + for(int row = init_row; row != test_row; row += inc_row) + memmove(getcell(screen, row, dest.start_col), + getcell(screen, row + downward, src.start_col), + cols * sizeof(ScreenCell)); + + return 1; +} + +static int moverect_user(VTermRect dest, VTermRect src, void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->moverect) { + if(screen->damage_merge != VTERM_DAMAGE_SCROLL) + // Avoid an infinite loop + vterm_screen_flush_damage(screen); + + if((*screen->callbacks->moverect)(dest, src, screen->cbdata)) + return 1; + } + + damagerect(screen, dest); + + return 1; +} + +static int erase_internal(VTermRect rect, int selective, void *user) +{ + VTermScreen *screen = user; + + for(int row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) { + const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); + + for(int col = rect.start_col; col < rect.end_col; col++) { + ScreenCell *cell = getcell(screen, row, col); + + if(selective && cell->pen.protected_cell) + continue; + + cell->chars[0] = 0; + cell->pen = (ScreenPen){ + /* Only copy .fg and .bg; leave things like rv in reset state */ + .fg = screen->pen.fg, + .bg = screen->pen.bg, + }; + cell->pen.dwl = info->doublewidth; + cell->pen.dhl = info->doubleheight; + } + } + + return 1; +} + +static int erase_user(VTermRect rect, int selective, void *user) +{ + VTermScreen *screen = user; + + damagerect(screen, rect); + + return 1; +} + +static int erase(VTermRect rect, int selective, void *user) +{ + erase_internal(rect, selective, user); + return erase_user(rect, 0, user); +} + +static int scrollrect(VTermRect rect, int downward, int rightward, void *user) +{ + VTermScreen *screen = user; + + if(screen->damage_merge != VTERM_DAMAGE_SCROLL) { + vterm_scroll_rect(rect, downward, rightward, + moverect_internal, erase_internal, screen); + + vterm_screen_flush_damage(screen); + + vterm_scroll_rect(rect, downward, rightward, + moverect_user, erase_user, screen); + + return 1; + } + + if(screen->damaged.start_row != -1 && + !rect_intersects(&rect, &screen->damaged)) { + vterm_screen_flush_damage(screen); + } + + if(screen->pending_scrollrect.start_row == -1) { + screen->pending_scrollrect = rect; + screen->pending_scroll_downward = downward; + screen->pending_scroll_rightward = rightward; + } + else if(rect_equal(&screen->pending_scrollrect, &rect) && + ((screen->pending_scroll_downward == 0 && downward == 0) || + (screen->pending_scroll_rightward == 0 && rightward == 0))) { + screen->pending_scroll_downward += downward; + screen->pending_scroll_rightward += rightward; + } + else { + vterm_screen_flush_damage(screen); + + screen->pending_scrollrect = rect; + screen->pending_scroll_downward = downward; + screen->pending_scroll_rightward = rightward; + } + + vterm_scroll_rect(rect, downward, rightward, + moverect_internal, erase_internal, screen); + + if(screen->damaged.start_row == -1) + return 1; + + if(rect_contains(&rect, &screen->damaged)) { + /* Scroll region entirely contains the damage; just move it */ + vterm_rect_move(&screen->damaged, -downward, -rightward); + rect_clip(&screen->damaged, &rect); + } + /* There are a number of possible cases here, but lets restrict this to only + * the common case where we might actually gain some performance by + * optimising it. Namely, a vertical scroll that neatly cuts the damage + * region in half. + */ + else if(rect.start_col <= screen->damaged.start_col && + rect.end_col >= screen->damaged.end_col && + rightward == 0) { + if(screen->damaged.start_row >= rect.start_row && + screen->damaged.start_row < rect.end_row) { + screen->damaged.start_row -= downward; + if(screen->damaged.start_row < rect.start_row) + screen->damaged.start_row = rect.start_row; + if(screen->damaged.start_row > rect.end_row) + screen->damaged.start_row = rect.end_row; + } + if(screen->damaged.end_row >= rect.start_row && + screen->damaged.end_row < rect.end_row) { + screen->damaged.end_row -= downward; + if(screen->damaged.end_row < rect.start_row) + screen->damaged.end_row = rect.start_row; + if(screen->damaged.end_row > rect.end_row) + screen->damaged.end_row = rect.end_row; + } + } + else { + DEBUG_LOG("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n", + ARGSrect(screen->damaged), ARGSrect(rect)); + } + + return 1; +} + +static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->movecursor) + return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata); + + return 0; +} + +static int setpenattr(VTermAttr attr, VTermValue *val, void *user) +{ + VTermScreen *screen = user; + + switch(attr) { + case VTERM_ATTR_BOLD: + screen->pen.bold = val->boolean; + return 1; + case VTERM_ATTR_UNDERLINE: + screen->pen.underline = val->number; + return 1; + case VTERM_ATTR_ITALIC: + screen->pen.italic = val->boolean; + return 1; + case VTERM_ATTR_BLINK: + screen->pen.blink = val->boolean; + return 1; + case VTERM_ATTR_REVERSE: + screen->pen.reverse = val->boolean; + return 1; + case VTERM_ATTR_CONCEAL: + screen->pen.conceal = val->boolean; + return 1; + case VTERM_ATTR_STRIKE: + screen->pen.strike = val->boolean; + return 1; + case VTERM_ATTR_FONT: + screen->pen.font = val->number; + return 1; + case VTERM_ATTR_FOREGROUND: + screen->pen.fg = val->color; + return 1; + case VTERM_ATTR_BACKGROUND: + screen->pen.bg = val->color; + return 1; + case VTERM_ATTR_SMALL: + screen->pen.small = val->boolean; + return 1; + case VTERM_ATTR_BASELINE: + screen->pen.baseline = val->number; + return 1; + + case VTERM_N_ATTRS: + return 0; + } + + return 0; +} + +static int settermprop(VTermProp prop, VTermValue *val, void *user) +{ + VTermScreen *screen = user; + + switch(prop) { + case VTERM_PROP_ALTSCREEN: + if(val->boolean && !screen->buffers[BUFIDX_ALTSCREEN]) + return 0; + + screen->buffer = val->boolean ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; + /* only send a damage event on disable; because during enable there's an + * erase that sends a damage anyway + */ + if(!val->boolean) + damagescreen(screen); + break; + case VTERM_PROP_REVERSE: + screen->global_reverse = val->boolean; + damagescreen(screen); + break; + default: + ; /* ignore */ + } + + if(screen->callbacks && screen->callbacks->settermprop) + return (*screen->callbacks->settermprop)(prop, val, screen->cbdata); + + return 1; +} + +static int bell(void *user) +{ + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->bell) + return (*screen->callbacks->bell)(screen->cbdata); + + return 0; +} + +/* How many cells are non-blank + * Returns the position of the first blank cell in the trailing blank end */ +static int line_popcount(ScreenCell *buffer, int row, int rows, int cols) +{ + int col = cols - 1; + while(col >= 0 && buffer[row * cols + col].chars[0] == 0) + col--; + return col + 1; +} + +#define REFLOW (screen->reflow) + +static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, bool active, VTermStateFields *statefields) +{ + int old_rows = screen->rows; + int old_cols = screen->cols; + + ScreenCell *old_buffer = screen->buffers[bufidx]; + VTermLineInfo *old_lineinfo = statefields->lineinfos[bufidx]; + + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); + VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); + + int old_row = old_rows - 1; + int new_row = new_rows - 1; + + VTermPos old_cursor = statefields->pos; + VTermPos new_cursor = { -1, -1 }; + +#ifdef DEBUG_REFLOW + fprintf(stderr, "Resizing from %dx%d to %dx%d; cursor was at (%d,%d)\n", + old_cols, old_rows, new_cols, new_rows, old_cursor.col, old_cursor.row); +#endif + + /* Keep track of the final row that is knonw to be blank, so we know what + * spare space we have for scrolling into + */ + int final_blank_row = new_rows; + + while(old_row >= 0) { + int old_row_end = old_row; + /* TODO: Stop if dwl or dhl */ + while(REFLOW && old_lineinfo && old_row >= 0 && old_lineinfo[old_row].continuation) + old_row--; + int old_row_start = old_row; + + int width = 0; + for(int row = old_row_start; row <= old_row_end; row++) { + if(REFLOW && row < (old_rows - 1) && old_lineinfo[row + 1].continuation) + width += old_cols; + else + width += line_popcount(old_buffer, row, old_rows, old_cols); + } + + if(final_blank_row == (new_row + 1) && width == 0) + final_blank_row = new_row; + + int new_height = REFLOW + ? width ? (width + new_cols - 1) / new_cols : 1 + : 1; + + int new_row_end = new_row; + int new_row_start = new_row - new_height + 1; + + old_row = old_row_start; + int old_col = 0; + + int spare_rows = new_rows - final_blank_row; + + if(new_row_start < 0 && /* we'd fall off the top */ + spare_rows >= 0 && /* we actually have spare rows */ + (!active || new_cursor.row == -1 || (new_cursor.row - new_row_start) < new_rows)) + { + /* Attempt to scroll content down into the blank rows at the bottom to + * make it fit + */ + int downwards = -new_row_start; + if(downwards > spare_rows) + downwards = spare_rows; + int rowcount = new_rows - downwards; + +#ifdef DEBUG_REFLOW + fprintf(stderr, " scroll %d rows +%d downwards\n", rowcount, downwards); +#endif + + memmove(&new_buffer[downwards * new_cols], &new_buffer[0], rowcount * new_cols * sizeof(ScreenCell)); + memmove(&new_lineinfo[downwards], &new_lineinfo[0], rowcount * sizeof(new_lineinfo[0])); + + new_row += downwards; + new_row_start += downwards; + new_row_end += downwards; + + if(new_cursor.row >= 0) + new_cursor.row += downwards; + + final_blank_row += downwards; + } + +#ifdef DEBUG_REFLOW + fprintf(stderr, " rows [%d..%d] <- [%d..%d] width=%d\n", + new_row_start, new_row_end, old_row_start, old_row_end, width); +#endif + + if(new_row_start < 0) + break; + + for(new_row = new_row_start, old_row = old_row_start; new_row <= new_row_end; new_row++) { + int count = width >= new_cols ? new_cols : width; + width -= count; + + int new_col = 0; + + while(count) { + /* TODO: This could surely be done a lot faster by memcpy()'ing the entire range */ + new_buffer[new_row * new_cols + new_col] = old_buffer[old_row * old_cols + old_col]; + + if(old_cursor.row == old_row && old_cursor.col == old_col) + new_cursor.row = new_row, new_cursor.col = new_col; + + old_col++; + if(old_col == old_cols) { + old_row++; + + if(!REFLOW) { + new_col++; + break; + } + old_col = 0; + } + + new_col++; + count--; + } + + if(old_cursor.row == old_row && old_cursor.col >= old_col) { + new_cursor.row = new_row, new_cursor.col = (old_cursor.col - old_col + new_col); + if(new_cursor.col >= new_cols) + new_cursor.col = new_cols-1; + } + + while(new_col < new_cols) { + clearcell(screen, &new_buffer[new_row * new_cols + new_col]); + new_col++; + } + + new_lineinfo[new_row].continuation = (new_row > new_row_start); + } + + old_row = old_row_start - 1; + new_row = new_row_start - 1; + } + + if(old_cursor.row <= old_row) { + /* cursor would have moved entirely off the top of the screen; lets just + * bring it within range */ + new_cursor.row = 0, new_cursor.col = old_cursor.col; + if(new_cursor.col >= new_cols) + new_cursor.col = new_cols-1; + } + + /* We really expect the cursor position to be set by now */ + if(active && (new_cursor.row == -1 || new_cursor.col == -1)) { + fprintf(stderr, "screen_resize failed to update cursor position\n"); + abort(); + } + + if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { + /* Push spare lines to scrollback buffer */ + for(int row = 0; row <= old_row; row++) + sb_pushline_from_row(screen, row); + if(active) + statefields->pos.row -= (old_row + 1); + } + if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && + screen->callbacks && screen->callbacks->sb_popline) { + /* Try to backfill rows by popping scrollback buffer */ + while(new_row >= 0) { + if(!(screen->callbacks->sb_popline(old_cols, screen->sb_buffer, screen->cbdata))) + break; + + VTermPos pos = { .row = new_row }; + for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { + VTermScreenCell *src = &screen->sb_buffer[pos.col]; + ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; + + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { + dst->chars[i] = src->chars[i]; + if(!src->chars[i]) + break; + } + + dst->pen.bold = src->attrs.bold; + dst->pen.underline = src->attrs.underline; + dst->pen.italic = src->attrs.italic; + dst->pen.blink = src->attrs.blink; + dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; + dst->pen.conceal = src->attrs.conceal; + dst->pen.strike = src->attrs.strike; + dst->pen.font = src->attrs.font; + dst->pen.small = src->attrs.small; + dst->pen.baseline = src->attrs.baseline; + + dst->pen.fg = src->fg; + dst->pen.bg = src->bg; + + if(src->width == 2 && pos.col < (new_cols-1)) + (dst + 1)->chars[0] = (uint32_t) -1; + } + for( ; pos.col < new_cols; pos.col++) + clearcell(screen, &new_buffer[pos.row * new_cols + pos.col]); + new_row--; + + if(active) + statefields->pos.row++; + } + } + if(new_row >= 0) { + /* Scroll new rows back up to the top and fill in blanks at the bottom */ + int moverows = new_rows - new_row - 1; + memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); + memmove(&new_lineinfo[0], &new_lineinfo[new_row + 1], moverows * sizeof(new_lineinfo[0])); + + new_cursor.row -= (new_row + 1); + + for(new_row = moverows; new_row < new_rows; new_row++) { + for(int col = 0; col < new_cols; col++) + clearcell(screen, &new_buffer[new_row * new_cols + col]); + new_lineinfo[new_row] = (VTermLineInfo){ 0 }; + } + } + + vterm_allocator_free(screen->vt, old_buffer); + screen->buffers[bufidx] = new_buffer; + + vterm_allocator_free(screen->vt, old_lineinfo); + statefields->lineinfos[bufidx] = new_lineinfo; + + if(active) + statefields->pos = new_cursor; + + return; +} + +static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) +{ + VTermScreen *screen = user; + + int altscreen_active = (screen->buffers[BUFIDX_ALTSCREEN] && screen->buffer == screen->buffers[BUFIDX_ALTSCREEN]); + + int old_rows = screen->rows; + int old_cols = screen->cols; + + if(new_cols > old_cols) { + /* Ensure that ->sb_buffer is large enough for a new or and old row */ + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); + } + + resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, fields); + if(screen->buffers[BUFIDX_ALTSCREEN]) + resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, fields); + else if(new_rows != old_rows) { + /* We don't need a full resize of the altscreen because it isn't enabled + * but we should at least keep the lineinfo the right size */ + vterm_allocator_free(screen->vt, fields->lineinfos[BUFIDX_ALTSCREEN]); + + VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); + for(int row = 0; row < new_rows; row++) + new_lineinfo[row] = (VTermLineInfo){ 0 }; + + fields->lineinfos[BUFIDX_ALTSCREEN] = new_lineinfo; + } + + screen->buffer = altscreen_active ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; + + screen->rows = new_rows; + screen->cols = new_cols; + + if(new_cols <= old_cols) { + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); + } + + /* TODO: Maaaaybe we can optimise this if there's no reflow happening */ + damagescreen(screen); + + if(screen->callbacks && screen->callbacks->resize) + return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata); + + return 1; +} + +static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) +{ + VTermScreen *screen = user; + + if(newinfo->doublewidth != oldinfo->doublewidth || + newinfo->doubleheight != oldinfo->doubleheight) { + for(int col = 0; col < screen->cols; col++) { + ScreenCell *cell = getcell(screen, row, col); + cell->pen.dwl = newinfo->doublewidth; + cell->pen.dhl = newinfo->doubleheight; + } + + VTermRect rect = { + .start_row = row, + .end_row = row + 1, + .start_col = 0, + .end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols, + }; + damagerect(screen, rect); + + if(newinfo->doublewidth) { + rect.start_col = screen->cols / 2; + rect.end_col = screen->cols; + + erase_internal(rect, 0, user); + } + } + + return 1; +} + +static int sb_clear(void *user) { + VTermScreen *screen = user; + + if(screen->callbacks && screen->callbacks->sb_clear) + if((*screen->callbacks->sb_clear)(screen->cbdata)) + return 1; + + return 0; +} + +static VTermStateCallbacks state_cbs = { + .putglyph = &putglyph, + .movecursor = &movecursor, + .scrollrect = &scrollrect, + .erase = &erase, + .setpenattr = &setpenattr, + .settermprop = &settermprop, + .bell = &bell, + .resize = &resize, + .setlineinfo = &setlineinfo, + .sb_clear = &sb_clear, +}; + +static VTermScreen *screen_new(VTerm *vt) +{ + VTermState *state = vterm_obtain_state(vt); + if(!state) + return NULL; + + VTermScreen *screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); + int rows, cols; + + vterm_get_size(vt, &rows, &cols); + + screen->vt = vt; + screen->state = state; + + screen->damage_merge = VTERM_DAMAGE_CELL; + screen->damaged.start_row = -1; + screen->pending_scrollrect.start_row = -1; + + screen->rows = rows; + screen->cols = cols; + + screen->global_reverse = false; + screen->reflow = false; + + screen->callbacks = NULL; + screen->cbdata = NULL; + + screen->buffers[BUFIDX_PRIMARY] = alloc_buffer(screen, rows, cols); + + screen->buffer = screen->buffers[BUFIDX_PRIMARY]; + + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols); + + vterm_state_set_callbacks(screen->state, &state_cbs, screen); + + return screen; +} + +INTERNAL void vterm_screen_free(VTermScreen *screen) +{ + vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_PRIMARY]); + if(screen->buffers[BUFIDX_ALTSCREEN]) + vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_ALTSCREEN]); + + vterm_allocator_free(screen->vt, screen->sb_buffer); + + vterm_allocator_free(screen->vt, screen); +} + +void vterm_screen_reset(VTermScreen *screen, int hard) +{ + screen->damaged.start_row = -1; + screen->pending_scrollrect.start_row = -1; + vterm_state_reset(screen->state, hard); + vterm_screen_flush_damage(screen); +} + +static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect) +{ + size_t outpos = 0; + int padding = 0; + +#define PUT(c) \ + if(utf8) { \ + size_t thislen = utf8_seqlen(c); \ + if(buffer && outpos + thislen <= len) \ + outpos += fill_utf8((c), (char *)buffer + outpos); \ + else \ + outpos += thislen; \ + } \ + else { \ + if(buffer && outpos + 1 <= len) \ + ((uint32_t*)buffer)[outpos++] = (c); \ + else \ + outpos++; \ + } + + for(int row = rect.start_row; row < rect.end_row; row++) { + for(int col = rect.start_col; col < rect.end_col; col++) { + ScreenCell *cell = getcell(screen, row, col); + + if(cell->chars[0] == 0) + // Erased cell, might need a space + padding++; + else if(cell->chars[0] == (uint32_t)-1) + // Gap behind a double-width char, do nothing + ; + else { + while(padding) { + PUT(UNICODE_SPACE); + padding--; + } + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { + PUT(cell->chars[i]); + } + } + } + + if(row < rect.end_row - 1) { + PUT(UNICODE_LINEFEED); + padding = 0; + } + } + + return outpos; +} + +size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect) +{ + return _get_chars(screen, 0, chars, len, rect); +} + +size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect) +{ + return _get_chars(screen, 1, str, len, rect); +} + +/* Copy internal to external representation of a screen cell */ +int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) +{ + ScreenCell *intcell = getcell(screen, pos.row, pos.col); + if(!intcell) + return 0; + + for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { + cell->chars[i] = intcell->chars[i]; + if(!intcell->chars[i]) + break; + } + + cell->attrs.bold = intcell->pen.bold; + cell->attrs.underline = intcell->pen.underline; + cell->attrs.italic = intcell->pen.italic; + cell->attrs.blink = intcell->pen.blink; + cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse; + cell->attrs.conceal = intcell->pen.conceal; + cell->attrs.strike = intcell->pen.strike; + cell->attrs.font = intcell->pen.font; + cell->attrs.small = intcell->pen.small; + cell->attrs.baseline = intcell->pen.baseline; + + cell->attrs.dwl = intcell->pen.dwl; + cell->attrs.dhl = intcell->pen.dhl; + + cell->fg = intcell->pen.fg; + cell->bg = intcell->pen.bg; + + if(pos.col < (screen->cols - 1) && + getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) + cell->width = 2; + else + cell->width = 1; + + return 1; +} + +int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos) +{ + /* This cell is EOL if this and every cell to the right is black */ + for(; pos.col < screen->cols; pos.col++) { + ScreenCell *cell = getcell(screen, pos.row, pos.col); + if(cell->chars[0] != 0) + return 0; + } + + return 1; +} + +VTermScreen *vterm_obtain_screen(VTerm *vt) +{ + if(vt->screen) + return vt->screen; + + VTermScreen *screen = screen_new(vt); + vt->screen = screen; + + return screen; +} + +void vterm_screen_enable_reflow(VTermScreen *screen, bool reflow) +{ + screen->reflow = reflow; +} + +#undef vterm_screen_set_reflow +void vterm_screen_set_reflow(VTermScreen *screen, bool reflow) +{ + vterm_screen_enable_reflow(screen, reflow); +} + +void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) +{ + if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { + int rows, cols; + vterm_get_size(screen->vt, &rows, &cols); + + screen->buffers[BUFIDX_ALTSCREEN] = alloc_buffer(screen, rows, cols); + } +} + +void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user) +{ + screen->callbacks = callbacks; + screen->cbdata = user; +} + +void *vterm_screen_get_cbdata(VTermScreen *screen) +{ + return screen->cbdata; +} + +void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user) +{ + vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user); +} + +void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen) +{ + return vterm_state_get_unrecognised_fbdata(screen->state); +} + +void vterm_screen_flush_damage(VTermScreen *screen) +{ + if(screen->pending_scrollrect.start_row != -1) { + vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward, + moverect_user, erase_user, screen); + + screen->pending_scrollrect.start_row = -1; + } + + if(screen->damaged.start_row != -1) { + if(screen->callbacks && screen->callbacks->damage) + (*screen->callbacks->damage)(screen->damaged, screen->cbdata); + + screen->damaged.start_row = -1; + } +} + +void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size) +{ + vterm_screen_flush_damage(screen); + screen->damage_merge = size; +} + +static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b) +{ + if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold)) + return 1; + if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline)) + return 1; + if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic)) + return 1; + if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink)) + return 1; + if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse)) + return 1; + if((attrs & VTERM_ATTR_CONCEAL_MASK) && (a->pen.conceal != b->pen.conceal)) + return 1; + if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike)) + return 1; + if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font)) + return 1; + if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_is_equal(&a->pen.fg, &b->pen.fg)) + return 1; + if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) + return 1; + if((attrs & VTERM_ATTR_SMALL_MASK) && (a->pen.small != b->pen.small)) + return 1; + if((attrs & VTERM_ATTR_BASELINE_MASK) && (a->pen.baseline != b->pen.baseline)) + return 1; + + return 0; +} + +int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs) +{ + ScreenCell *target = getcell(screen, pos.row, pos.col); + + // TODO: bounds check + extent->start_row = pos.row; + extent->end_row = pos.row + 1; + + if(extent->start_col < 0) + extent->start_col = 0; + if(extent->end_col < 0) + extent->end_col = screen->cols; + + int col; + + for(col = pos.col - 1; col >= extent->start_col; col--) + if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) + break; + extent->start_col = col + 1; + + for(col = pos.col + 1; col < extent->end_col; col++) + if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) + break; + extent->end_col = col - 1; + + return 1; +} + +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col) +{ + vterm_state_convert_color_to_rgb(screen->state, col); +} + +static void reset_default_colours(VTermScreen *screen, ScreenCell *buffer) +{ + for(int row = 0; row <= screen->rows - 1; row++) + for(int col = 0; col <= screen->cols - 1; col++) { + ScreenCell *cell = &buffer[row * screen->cols + col]; + if(VTERM_COLOR_IS_DEFAULT_FG(&cell->pen.fg)) + cell->pen.fg = screen->pen.fg; + if(VTERM_COLOR_IS_DEFAULT_BG(&cell->pen.bg)) + cell->pen.bg = screen->pen.bg; + } +} + +void vterm_screen_set_default_colors(VTermScreen *screen, const VTermColor *default_fg, const VTermColor *default_bg) +{ + vterm_state_set_default_colors(screen->state, default_fg, default_bg); + + if(default_fg && VTERM_COLOR_IS_DEFAULT_FG(&screen->pen.fg)) { + screen->pen.fg = *default_fg; + screen->pen.fg.type = (screen->pen.fg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_FG; + } + + if(default_bg && VTERM_COLOR_IS_DEFAULT_BG(&screen->pen.bg)) { + screen->pen.bg = *default_bg; + screen->pen.bg.type = (screen->pen.bg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_BG; + } + + reset_default_colours(screen, screen->buffers[0]); + if(screen->buffers[1]) + reset_default_colours(screen, screen->buffers[1]); +} diff --git a/src/libs/3rdparty/libvterm/src/state.c b/src/libs/3rdparty/libvterm/src/state.c new file mode 100644 index 00000000000..b22fba706b6 --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/state.c @@ -0,0 +1,2315 @@ +#include "vterm_internal.h" + +#include +#include + +#define strneq(a,b,n) (strncmp(a,b,n)==0) + +#if defined(DEBUG) && DEBUG > 1 +# define DEBUG_GLYPH_COMBINE +#endif + +/* Some convenient wrappers to make callback functions easier */ + +static void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos) +{ + VTermGlyphInfo info = { + .chars = chars, + .width = width, + .protected_cell = state->protected_cell, + .dwl = state->lineinfo[pos.row].doublewidth, + .dhl = state->lineinfo[pos.row].doubleheight, + }; + + if(state->callbacks && state->callbacks->putglyph) + if((*state->callbacks->putglyph)(&info, pos, state->cbdata)) + return; + + DEBUG_LOG("libvterm: Unhandled putglyph U+%04x at (%d,%d)\n", chars[0], pos.col, pos.row); +} + +static void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom) +{ + if(state->pos.col == oldpos->col && state->pos.row == oldpos->row) + return; + + if(cancel_phantom) + state->at_phantom = 0; + + if(state->callbacks && state->callbacks->movecursor) + if((*state->callbacks->movecursor)(state->pos, *oldpos, state->mode.cursor_visible, state->cbdata)) + return; +} + +static void erase(VTermState *state, VTermRect rect, int selective) +{ + if(rect.end_col == state->cols) { + /* If we're erasing the final cells of any lines, cancel the continuation + * marker on the subsequent line + */ + for(int row = rect.start_row + 1; row < rect.end_row + 1 && row < state->rows; row++) + state->lineinfo[row].continuation = 0; + } + + if(state->callbacks && state->callbacks->erase) + if((*state->callbacks->erase)(rect, selective, state->cbdata)) + return; +} + +static VTermState *vterm_state_new(VTerm *vt) +{ + VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState)); + + state->vt = vt; + + state->rows = vt->rows; + state->cols = vt->cols; + + state->mouse_col = 0; + state->mouse_row = 0; + state->mouse_buttons = 0; + + state->mouse_protocol = MOUSE_X10; + + state->callbacks = NULL; + state->cbdata = NULL; + + state->selection.callbacks = NULL; + state->selection.user = NULL; + state->selection.buffer = NULL; + + vterm_state_newpen(state); + + state->bold_is_highbright = 0; + + state->combine_chars_size = 16; + state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0])); + + state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); + + state->lineinfos[BUFIDX_PRIMARY] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + /* TODO: Make an 'enable' function */ + state->lineinfos[BUFIDX_ALTSCREEN] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + state->lineinfo = state->lineinfos[BUFIDX_PRIMARY]; + + state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); + if(*state->encoding_utf8.enc->init) + (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); + + return state; +} + +INTERNAL void vterm_state_free(VTermState *state) +{ + vterm_allocator_free(state->vt, state->tabstops); + vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_PRIMARY]); + if(state->lineinfos[BUFIDX_ALTSCREEN]) + vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_ALTSCREEN]); + vterm_allocator_free(state->vt, state->combine_chars); + vterm_allocator_free(state->vt, state); +} + +static void scroll(VTermState *state, VTermRect rect, int downward, int rightward) +{ + if(!downward && !rightward) + return; + + int rows = rect.end_row - rect.start_row; + if(downward > rows) + downward = rows; + else if(downward < -rows) + downward = -rows; + + int cols = rect.end_col - rect.start_col; + if(rightward > cols) + rightward = cols; + else if(rightward < -cols) + rightward = -cols; + + // Update lineinfo if full line + if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) { + int height = rect.end_row - rect.start_row - abs(downward); + + if(downward > 0) { + memmove(state->lineinfo + rect.start_row, + state->lineinfo + rect.start_row + downward, + height * sizeof(state->lineinfo[0])); + for(int row = rect.end_row - downward; row < rect.end_row; row++) + state->lineinfo[row] = (VTermLineInfo){ 0 }; + } + else { + memmove(state->lineinfo + rect.start_row - downward, + state->lineinfo + rect.start_row, + height * sizeof(state->lineinfo[0])); + for(int row = rect.start_row; row < rect.start_row - downward; row++) + state->lineinfo[row] = (VTermLineInfo){ 0 }; + } + } + + if(state->callbacks && state->callbacks->scrollrect) + if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata)) + return; + + if(state->callbacks) + vterm_scroll_rect(rect, downward, rightward, + state->callbacks->moverect, state->callbacks->erase, state->cbdata); +} + +static void linefeed(VTermState *state) +{ + if(state->pos.row == SCROLLREGION_BOTTOM(state) - 1) { + VTermRect rect = { + .start_row = state->scrollregion_top, + .end_row = SCROLLREGION_BOTTOM(state), + .start_col = SCROLLREGION_LEFT(state), + .end_col = SCROLLREGION_RIGHT(state), + }; + + scroll(state, rect, 1, 0); + } + else if(state->pos.row < state->rows-1) + state->pos.row++; +} + +static void grow_combine_buffer(VTermState *state) +{ + size_t new_size = state->combine_chars_size * 2; + uint32_t *new_chars = vterm_allocator_malloc(state->vt, new_size * sizeof(new_chars[0])); + + memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0])); + + vterm_allocator_free(state->vt, state->combine_chars); + + state->combine_chars = new_chars; + state->combine_chars_size = new_size; +} + +static void set_col_tabstop(VTermState *state, int col) +{ + unsigned char mask = 1 << (col & 7); + state->tabstops[col >> 3] |= mask; +} + +static void clear_col_tabstop(VTermState *state, int col) +{ + unsigned char mask = 1 << (col & 7); + state->tabstops[col >> 3] &= ~mask; +} + +static int is_col_tabstop(VTermState *state, int col) +{ + unsigned char mask = 1 << (col & 7); + return state->tabstops[col >> 3] & mask; +} + +static int is_cursor_in_scrollregion(const VTermState *state) +{ + if(state->pos.row < state->scrollregion_top || + state->pos.row >= SCROLLREGION_BOTTOM(state)) + return 0; + if(state->pos.col < SCROLLREGION_LEFT(state) || + state->pos.col >= SCROLLREGION_RIGHT(state)) + return 0; + + return 1; +} + +static void tab(VTermState *state, int count, int direction) +{ + while(count > 0) { + if(direction > 0) { + if(state->pos.col >= THISROWWIDTH(state)-1) + return; + + state->pos.col++; + } + else if(direction < 0) { + if(state->pos.col < 1) + return; + + state->pos.col--; + } + + if(is_col_tabstop(state, state->pos.col)) + count--; + } +} + +#define NO_FORCE 0 +#define FORCE 1 + +#define DWL_OFF 0 +#define DWL_ON 1 + +#define DHL_OFF 0 +#define DHL_TOP 1 +#define DHL_BOTTOM 2 + +static void set_lineinfo(VTermState *state, int row, int force, int dwl, int dhl) +{ + VTermLineInfo info = state->lineinfo[row]; + + if(dwl == DWL_OFF) + info.doublewidth = DWL_OFF; + else if(dwl == DWL_ON) + info.doublewidth = DWL_ON; + // else -1 to ignore + + if(dhl == DHL_OFF) + info.doubleheight = DHL_OFF; + else if(dhl == DHL_TOP) + info.doubleheight = DHL_TOP; + else if(dhl == DHL_BOTTOM) + info.doubleheight = DHL_BOTTOM; + + if((state->callbacks && + state->callbacks->setlineinfo && + (*state->callbacks->setlineinfo)(row, &info, state->lineinfo + row, state->cbdata)) + || force) + state->lineinfo[row] = info; +} + +static int on_text(const char bytes[], size_t len, void *user) +{ + VTermState *state = user; + + VTermPos oldpos = state->pos; + + uint32_t *codepoints = (uint32_t *)(state->vt->tmpbuffer); + size_t maxpoints = (state->vt->tmpbuffer_len) / sizeof(uint32_t); + + int npoints = 0; + size_t eaten = 0; + + VTermEncodingInstance *encoding = + state->gsingle_set ? &state->encoding[state->gsingle_set] : + !(bytes[eaten] & 0x80) ? &state->encoding[state->gl_set] : + state->vt->mode.utf8 ? &state->encoding_utf8 : + &state->encoding[state->gr_set]; + + (*encoding->enc->decode)(encoding->enc, encoding->data, + codepoints, &npoints, state->gsingle_set ? 1 : maxpoints, + bytes, &eaten, len); + + /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet + * for even a single codepoint + */ + if(!npoints) + return eaten; + + if(state->gsingle_set && npoints) + state->gsingle_set = 0; + + int i = 0; + + /* This is a combining char. that needs to be merged with the previous + * glyph output */ + if(vterm_unicode_is_combining(codepoints[i])) { + /* See if the cursor has moved since */ + if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) { +#ifdef DEBUG_GLYPH_COMBINE + int printpos; + printf("DEBUG: COMBINING SPLIT GLYPH of chars {"); + for(printpos = 0; state->combine_chars[printpos]; printpos++) + printf("U+%04x ", state->combine_chars[printpos]); + printf("} + {"); +#endif + + /* Find where we need to append these combining chars */ + int saved_i = 0; + while(state->combine_chars[saved_i]) + saved_i++; + + /* Add extra ones */ + while(i < npoints && vterm_unicode_is_combining(codepoints[i])) { + if(saved_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[saved_i++] = codepoints[i++]; + } + if(saved_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[saved_i] = 0; + +#ifdef DEBUG_GLYPH_COMBINE + for(; state->combine_chars[printpos]; printpos++) + printf("U+%04x ", state->combine_chars[printpos]); + printf("}\n"); +#endif + + /* Now render it */ + putglyph(state, state->combine_chars, state->combine_width, state->combine_pos); + } + else { + DEBUG_LOG("libvterm: TODO: Skip over split char+combining\n"); + } + } + + for(; i < npoints; i++) { + // Try to find combining characters following this + int glyph_starts = i; + int glyph_ends; + for(glyph_ends = i + 1; + (glyph_ends < npoints) && (glyph_ends < glyph_starts + VTERM_MAX_CHARS_PER_CELL); + glyph_ends++) + if(!vterm_unicode_is_combining(codepoints[glyph_ends])) + break; + + int width = 0; + + uint32_t chars[VTERM_MAX_CHARS_PER_CELL + 1]; + + for( ; i < glyph_ends; i++) { + chars[i - glyph_starts] = codepoints[i]; + int this_width = vterm_unicode_width(codepoints[i]); +#ifdef DEBUG + if(this_width < 0) { + fprintf(stderr, "Text with negative-width codepoint U+%04x\n", codepoints[i]); + abort(); + } +#endif + width += this_width; + } + + while(i < npoints && vterm_unicode_is_combining(codepoints[i])) + i++; + + chars[glyph_ends - glyph_starts] = 0; + i--; + +#ifdef DEBUG_GLYPH_COMBINE + int printpos; + printf("DEBUG: COMBINED GLYPH of %d chars {", glyph_ends - glyph_starts); + for(printpos = 0; printpos < glyph_ends - glyph_starts; printpos++) + printf("U+%04x ", chars[printpos]); + printf("}, onscreen width %d\n", width); +#endif + + if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) { + linefeed(state); + state->pos.col = 0; + state->at_phantom = 0; + state->lineinfo[state->pos.row].continuation = 1; + } + + if(state->mode.insert) { + /* TODO: This will be a little inefficient for large bodies of text, as + * it'll have to 'ICH' effectively before every glyph. We should scan + * ahead and ICH as many times as required + */ + VTermRect rect = { + .start_row = state->pos.row, + .end_row = state->pos.row + 1, + .start_col = state->pos.col, + .end_col = THISROWWIDTH(state), + }; + scroll(state, rect, 0, -1); + } + + putglyph(state, chars, width, state->pos); + + if(i == npoints - 1) { + /* End of the buffer. Save the chars in case we have to combine with + * more on the next call */ + int save_i; + for(save_i = 0; chars[save_i]; save_i++) { + if(save_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[save_i] = chars[save_i]; + } + if(save_i >= state->combine_chars_size) + grow_combine_buffer(state); + state->combine_chars[save_i] = 0; + state->combine_width = width; + state->combine_pos = state->pos; + } + + if(state->pos.col + width >= THISROWWIDTH(state)) { + if(state->mode.autowrap) + state->at_phantom = 1; + } + else { + state->pos.col += width; + } + } + + updatecursor(state, &oldpos, 0); + +#ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after text: (%d,%d)\n", + state->pos.row, state->pos.col); + abort(); + } +#endif + + return eaten; +} + +static int on_control(unsigned char control, void *user) +{ + VTermState *state = user; + + VTermPos oldpos = state->pos; + + switch(control) { + case 0x07: // BEL - ECMA-48 8.3.3 + if(state->callbacks && state->callbacks->bell) + (*state->callbacks->bell)(state->cbdata); + break; + + case 0x08: // BS - ECMA-48 8.3.5 + if(state->pos.col > 0) + state->pos.col--; + break; + + case 0x09: // HT - ECMA-48 8.3.60 + tab(state, 1, +1); + break; + + case 0x0a: // LF - ECMA-48 8.3.74 + case 0x0b: // VT + case 0x0c: // FF + linefeed(state); + if(state->mode.newline) + state->pos.col = 0; + break; + + case 0x0d: // CR - ECMA-48 8.3.15 + state->pos.col = 0; + break; + + case 0x0e: // LS1 - ECMA-48 8.3.76 + state->gl_set = 1; + break; + + case 0x0f: // LS0 - ECMA-48 8.3.75 + state->gl_set = 0; + break; + + case 0x84: // IND - DEPRECATED but implemented for completeness + linefeed(state); + break; + + case 0x85: // NEL - ECMA-48 8.3.86 + linefeed(state); + state->pos.col = 0; + break; + + case 0x88: // HTS - ECMA-48 8.3.62 + set_col_tabstop(state, state->pos.col); + break; + + case 0x8d: // RI - ECMA-48 8.3.104 + if(state->pos.row == state->scrollregion_top) { + VTermRect rect = { + .start_row = state->scrollregion_top, + .end_row = SCROLLREGION_BOTTOM(state), + .start_col = SCROLLREGION_LEFT(state), + .end_col = SCROLLREGION_RIGHT(state), + }; + + scroll(state, rect, -1, 0); + } + else if(state->pos.row > 0) + state->pos.row--; + break; + + case 0x8e: // SS2 - ECMA-48 8.3.141 + state->gsingle_set = 2; + break; + + case 0x8f: // SS3 - ECMA-48 8.3.142 + state->gsingle_set = 3; + break; + + default: + if(state->fallbacks && state->fallbacks->control) + if((*state->fallbacks->control)(control, state->fbdata)) + return 1; + + return 0; + } + + updatecursor(state, &oldpos, 1); + +#ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after Ctrl %02x: (%d,%d)\n", + control, state->pos.row, state->pos.col); + abort(); + } +#endif + + return 1; +} + +static int settermprop_bool(VTermState *state, VTermProp prop, int v) +{ + VTermValue val = { .boolean = v }; + return vterm_state_set_termprop(state, prop, &val); +} + +static int settermprop_int(VTermState *state, VTermProp prop, int v) +{ + VTermValue val = { .number = v }; + return vterm_state_set_termprop(state, prop, &val); +} + +static int settermprop_string(VTermState *state, VTermProp prop, VTermStringFragment frag) +{ + VTermValue val = { .string = frag }; + return vterm_state_set_termprop(state, prop, &val); +} + +static void savecursor(VTermState *state, int save) +{ + if(save) { + state->saved.pos = state->pos; + state->saved.mode.cursor_visible = state->mode.cursor_visible; + state->saved.mode.cursor_blink = state->mode.cursor_blink; + state->saved.mode.cursor_shape = state->mode.cursor_shape; + + vterm_state_savepen(state, 1); + } + else { + VTermPos oldpos = state->pos; + + state->pos = state->saved.pos; + + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, state->saved.mode.cursor_visible); + settermprop_bool(state, VTERM_PROP_CURSORBLINK, state->saved.mode.cursor_blink); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, state->saved.mode.cursor_shape); + + vterm_state_savepen(state, 0); + + updatecursor(state, &oldpos, 1); + } +} + +static int on_escape(const char *bytes, size_t len, void *user) +{ + VTermState *state = user; + + /* Easier to decode this from the first byte, even though the final + * byte terminates it + */ + switch(bytes[0]) { + case ' ': + if(len != 2) + return 0; + + switch(bytes[1]) { + case 'F': // S7C1T + state->vt->mode.ctrl8bit = 0; + break; + + case 'G': // S8C1T + state->vt->mode.ctrl8bit = 1; + break; + + default: + return 0; + } + return 2; + + case '#': + if(len != 2) + return 0; + + switch(bytes[1]) { + case '3': // DECDHL top + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_TOP); + break; + + case '4': // DECDHL bottom + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_BOTTOM); + break; + + case '5': // DECSWL + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_OFF, DHL_OFF); + break; + + case '6': // DECDWL + if(state->mode.leftrightmargin) + break; + set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_OFF); + break; + + case '8': // DECALN + { + VTermPos pos; + uint32_t E[] = { 'E', 0 }; + for(pos.row = 0; pos.row < state->rows; pos.row++) + for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++) + putglyph(state, E, 1, pos); + break; + } + + default: + return 0; + } + return 2; + + case '(': case ')': case '*': case '+': // SCS + if(len != 2) + return 0; + + { + int setnum = bytes[0] - 0x28; + VTermEncoding *newenc = vterm_lookup_encoding(ENC_SINGLE_94, bytes[1]); + + if(newenc) { + state->encoding[setnum].enc = newenc; + + if(newenc->init) + (*newenc->init)(newenc, state->encoding[setnum].data); + } + } + + return 2; + + case '7': // DECSC + savecursor(state, 1); + return 1; + + case '8': // DECRC + savecursor(state, 0); + return 1; + + case '<': // Ignored by VT100. Used in VT52 mode to switch up to VT100 + return 1; + + case '=': // DECKPAM + state->mode.keypad = 1; + return 1; + + case '>': // DECKPNM + state->mode.keypad = 0; + return 1; + + case 'c': // RIS - ECMA-48 8.3.105 + { + VTermPos oldpos = state->pos; + vterm_state_reset(state, 1); + if(state->callbacks && state->callbacks->movecursor) + (*state->callbacks->movecursor)(state->pos, oldpos, state->mode.cursor_visible, state->cbdata); + return 1; + } + + case 'n': // LS2 - ECMA-48 8.3.78 + state->gl_set = 2; + return 1; + + case 'o': // LS3 - ECMA-48 8.3.80 + state->gl_set = 3; + return 1; + + case '~': // LS1R - ECMA-48 8.3.77 + state->gr_set = 1; + return 1; + + case '}': // LS2R - ECMA-48 8.3.79 + state->gr_set = 2; + return 1; + + case '|': // LS3R - ECMA-48 8.3.81 + state->gr_set = 3; + return 1; + + default: + return 0; + } +} + +static void set_mode(VTermState *state, int num, int val) +{ + switch(num) { + case 4: // IRM - ECMA-48 7.2.10 + state->mode.insert = val; + break; + + case 20: // LNM - ANSI X3.4-1977 + state->mode.newline = val; + break; + + default: + DEBUG_LOG("libvterm: Unknown mode %d\n", num); + return; + } +} + +static void set_dec_mode(VTermState *state, int num, int val) +{ + switch(num) { + case 1: + state->mode.cursor = val; + break; + + case 5: // DECSCNM - screen mode + settermprop_bool(state, VTERM_PROP_REVERSE, val); + break; + + case 6: // DECOM - origin mode + { + VTermPos oldpos = state->pos; + state->mode.origin = val; + state->pos.row = state->mode.origin ? state->scrollregion_top : 0; + state->pos.col = state->mode.origin ? SCROLLREGION_LEFT(state) : 0; + updatecursor(state, &oldpos, 1); + } + break; + + case 7: + state->mode.autowrap = val; + break; + + case 12: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, val); + break; + + case 25: + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, val); + break; + + case 69: // DECVSSM - vertical split screen mode + // DECLRMM - left/right margin mode + state->mode.leftrightmargin = val; + if(val) { + // Setting DECVSSM must clear doublewidth/doubleheight state of every line + for(int row = 0; row < state->rows; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + } + + break; + + case 1000: + case 1002: + case 1003: + settermprop_int(state, VTERM_PROP_MOUSE, + !val ? VTERM_PROP_MOUSE_NONE : + (num == 1000) ? VTERM_PROP_MOUSE_CLICK : + (num == 1002) ? VTERM_PROP_MOUSE_DRAG : + VTERM_PROP_MOUSE_MOVE); + break; + + case 1004: + state->mode.report_focus = val; + break; + + case 1005: + state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10; + break; + + case 1006: + state->mouse_protocol = val ? MOUSE_SGR : MOUSE_X10; + break; + + case 1015: + state->mouse_protocol = val ? MOUSE_RXVT : MOUSE_X10; + break; + + case 1047: + settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); + break; + + case 1048: + savecursor(state, val); + break; + + case 1049: + settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); + savecursor(state, val); + break; + + case 2004: + state->mode.bracketpaste = val; + break; + + default: + DEBUG_LOG("libvterm: Unknown DEC mode %d\n", num); + return; + } +} + +static void request_dec_mode(VTermState *state, int num) +{ + int reply; + + switch(num) { + case 1: + reply = state->mode.cursor; + break; + + case 5: + reply = state->mode.screen; + break; + + case 6: + reply = state->mode.origin; + break; + + case 7: + reply = state->mode.autowrap; + break; + + case 12: + reply = state->mode.cursor_blink; + break; + + case 25: + reply = state->mode.cursor_visible; + break; + + case 69: + reply = state->mode.leftrightmargin; + break; + + case 1000: + reply = state->mouse_flags == MOUSE_WANT_CLICK; + break; + + case 1002: + reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_DRAG); + break; + + case 1003: + reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE); + break; + + case 1004: + reply = state->mode.report_focus; + break; + + case 1005: + reply = state->mouse_protocol == MOUSE_UTF8; + break; + + case 1006: + reply = state->mouse_protocol == MOUSE_SGR; + break; + + case 1015: + reply = state->mouse_protocol == MOUSE_RXVT; + break; + + case 1047: + reply = state->mode.alt_screen; + break; + + case 2004: + reply = state->mode.bracketpaste; + break; + + default: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, 0); + return; + } + + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, reply ? 1 : 2); +} + +static void request_version_string(VTermState *state) +{ + vterm_push_output_sprintf_str(state->vt, C1_DCS, true, ">|libvterm(%d.%d)", + VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR); +} + +static int on_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) +{ + VTermState *state = user; + int leader_byte = 0; + int intermed_byte = 0; + int cancel_phantom = 1; + + if(leader && leader[0]) { + if(leader[1]) // longer than 1 char + return 0; + + switch(leader[0]) { + case '?': + case '>': + leader_byte = leader[0]; + break; + default: + return 0; + } + } + + if(intermed && intermed[0]) { + if(intermed[1]) // longer than 1 char + return 0; + + switch(intermed[0]) { + case ' ': + case '"': + case '$': + case '\'': + intermed_byte = intermed[0]; + break; + default: + return 0; + } + } + + VTermPos oldpos = state->pos; + + // Some temporaries for later code + int count, val; + int row, col; + VTermRect rect; + int selective; + +#define LBOUND(v,min) if((v) < (min)) (v) = (min) +#define UBOUND(v,max) if((v) > (max)) (v) = (max) + +#define LEADER(l,b) ((l << 8) | b) +#define INTERMED(i,b) ((i << 16) | b) + + switch(intermed_byte << 16 | leader_byte << 8 | command) { + case 0x40: // ICH - ECMA-48 8.3.64 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + if(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); + + scroll(state, rect, 0, -count); + + break; + + case 0x41: // CUU - ECMA-48 8.3.22 + count = CSI_ARG_COUNT(args[0]); + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x42: // CUD - ECMA-48 8.3.19 + count = CSI_ARG_COUNT(args[0]); + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x43: // CUF - ECMA-48 8.3.20 + count = CSI_ARG_COUNT(args[0]); + state->pos.col += count; + state->at_phantom = 0; + break; + + case 0x44: // CUB - ECMA-48 8.3.18 + count = CSI_ARG_COUNT(args[0]); + state->pos.col -= count; + state->at_phantom = 0; + break; + + case 0x45: // CNL - ECMA-48 8.3.12 + count = CSI_ARG_COUNT(args[0]); + state->pos.col = 0; + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x46: // CPL - ECMA-48 8.3.13 + count = CSI_ARG_COUNT(args[0]); + state->pos.col = 0; + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x47: // CHA - ECMA-48 8.3.9 + val = CSI_ARG_OR(args[0], 1); + state->pos.col = val-1; + state->at_phantom = 0; + break; + + case 0x48: // CUP - ECMA-48 8.3.21 + row = CSI_ARG_OR(args[0], 1); + col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); + // zero-based + state->pos.row = row-1; + state->pos.col = col-1; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + state->at_phantom = 0; + break; + + case 0x49: // CHT - ECMA-48 8.3.10 + count = CSI_ARG_COUNT(args[0]); + tab(state, count, +1); + break; + + case 0x4a: // ED - ECMA-48 8.3.39 + case LEADER('?', 0x4a): // DECSED - Selective Erase in Display + selective = (leader_byte == '?'); + switch(CSI_ARG(args[0])) { + case CSI_ARG_MISSING: + case 0: + rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; rect.end_col = state->cols; + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + rect.start_row = state->pos.row + 1; rect.end_row = state->rows; + rect.start_col = 0; + for(int row = rect.start_row; row < rect.end_row; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + if(rect.end_row > rect.start_row) + erase(state, rect, selective); + break; + + case 1: + rect.start_row = 0; rect.end_row = state->pos.row; + rect.start_col = 0; rect.end_col = state->cols; + for(int row = rect.start_row; row < rect.end_row; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; + rect.end_col = state->pos.col + 1; + if(rect.end_row > rect.start_row) + erase(state, rect, selective); + break; + + case 2: + rect.start_row = 0; rect.end_row = state->rows; + rect.start_col = 0; rect.end_col = state->cols; + for(int row = rect.start_row; row < rect.end_row; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + erase(state, rect, selective); + break; + + case 3: + if(state->callbacks && state->callbacks->sb_clear) + if((*state->callbacks->sb_clear)(state->cbdata)) + return 1; + break; + } + break; + + case 0x4b: // EL - ECMA-48 8.3.41 + case LEADER('?', 0x4b): // DECSEL - Selective Erase in Line + selective = (leader_byte == '?'); + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + + switch(CSI_ARG(args[0])) { + case CSI_ARG_MISSING: + case 0: + rect.start_col = state->pos.col; rect.end_col = THISROWWIDTH(state); break; + case 1: + rect.start_col = 0; rect.end_col = state->pos.col + 1; break; + case 2: + rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break; + default: + return 0; + } + + if(rect.end_col > rect.start_col) + erase(state, rect, selective); + + break; + + case 0x4c: // IL - ECMA-48 8.3.67 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, -count, 0); + + break; + + case 0x4d: // DL - ECMA-48 8.3.32 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, count, 0); + + break; + + case 0x50: // DCH - ECMA-48 8.3.26 + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + if(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); + + scroll(state, rect, 0, count); + + break; + + case 0x53: // SU - ECMA-48 8.3.147 + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, count, 0); + + break; + + case 0x54: // SD - ECMA-48 8.3.113 + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = SCROLLREGION_LEFT(state); + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, -count, 0); + + break; + + case 0x58: // ECH - ECMA-48 8.3.38 + count = CSI_ARG_COUNT(args[0]); + + rect.start_row = state->pos.row; + rect.end_row = state->pos.row + 1; + rect.start_col = state->pos.col; + rect.end_col = state->pos.col + count; + UBOUND(rect.end_col, THISROWWIDTH(state)); + + erase(state, rect, 0); + break; + + case 0x5a: // CBT - ECMA-48 8.3.7 + count = CSI_ARG_COUNT(args[0]); + tab(state, count, -1); + break; + + case 0x60: // HPA - ECMA-48 8.3.57 + col = CSI_ARG_OR(args[0], 1); + state->pos.col = col-1; + state->at_phantom = 0; + break; + + case 0x61: // HPR - ECMA-48 8.3.59 + count = CSI_ARG_COUNT(args[0]); + state->pos.col += count; + state->at_phantom = 0; + break; + + case 0x62: { // REP - ECMA-48 8.3.103 + const int row_width = THISROWWIDTH(state); + count = CSI_ARG_COUNT(args[0]); + col = state->pos.col + count; + UBOUND(col, row_width); + while (state->pos.col < col) { + putglyph(state, state->combine_chars, state->combine_width, state->pos); + state->pos.col += state->combine_width; + } + if (state->pos.col + state->combine_width >= row_width) { + if (state->mode.autowrap) { + state->at_phantom = 1; + cancel_phantom = 0; + } + } + break; + } + + case 0x63: // DA - ECMA-48 8.3.24 + val = CSI_ARG_OR(args[0], 0); + if(val == 0) + // DEC VT100 response + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?1;2c"); + break; + + case LEADER('>', 0x63): // DEC secondary Device Attributes + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, ">%d;%d;%dc", 0, 100, 0); + break; + + case 0x64: // VPA - ECMA-48 8.3.158 + row = CSI_ARG_OR(args[0], 1); + state->pos.row = row-1; + if(state->mode.origin) + state->pos.row += state->scrollregion_top; + state->at_phantom = 0; + break; + + case 0x65: // VPR - ECMA-48 8.3.160 + count = CSI_ARG_COUNT(args[0]); + state->pos.row += count; + state->at_phantom = 0; + break; + + case 0x66: // HVP - ECMA-48 8.3.63 + row = CSI_ARG_OR(args[0], 1); + col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); + // zero-based + state->pos.row = row-1; + state->pos.col = col-1; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + state->at_phantom = 0; + break; + + case 0x67: // TBC - ECMA-48 8.3.154 + val = CSI_ARG_OR(args[0], 0); + + switch(val) { + case 0: + clear_col_tabstop(state, state->pos.col); + break; + case 3: + case 5: + for(col = 0; col < state->cols; col++) + clear_col_tabstop(state, col); + break; + case 1: + case 2: + case 4: + break; + /* TODO: 1, 2 and 4 aren't meaningful yet without line tab stops */ + default: + return 0; + } + break; + + case 0x68: // SM - ECMA-48 8.3.125 + if(!CSI_ARG_IS_MISSING(args[0])) + set_mode(state, CSI_ARG(args[0]), 1); + break; + + case LEADER('?', 0x68): // DEC private mode set + if(!CSI_ARG_IS_MISSING(args[0])) + set_dec_mode(state, CSI_ARG(args[0]), 1); + break; + + case 0x6a: // HPB - ECMA-48 8.3.58 + count = CSI_ARG_COUNT(args[0]); + state->pos.col -= count; + state->at_phantom = 0; + break; + + case 0x6b: // VPB - ECMA-48 8.3.159 + count = CSI_ARG_COUNT(args[0]); + state->pos.row -= count; + state->at_phantom = 0; + break; + + case 0x6c: // RM - ECMA-48 8.3.106 + if(!CSI_ARG_IS_MISSING(args[0])) + set_mode(state, CSI_ARG(args[0]), 0); + break; + + case LEADER('?', 0x6c): // DEC private mode reset + if(!CSI_ARG_IS_MISSING(args[0])) + set_dec_mode(state, CSI_ARG(args[0]), 0); + break; + + case 0x6d: // SGR - ECMA-48 8.3.117 + vterm_state_setpen(state, args, argcount); + break; + + case LEADER('?', 0x6d): // DECSGR + /* No actual DEC terminal recognised these, but some printers did. These + * are alternative ways to request subscript/superscript/off + */ + for(int argi = 0; argi < argcount; argi++) { + long arg; + switch(arg = CSI_ARG(args[argi])) { + case 4: // Superscript on + arg = 73; + vterm_state_setpen(state, &arg, 1); + break; + case 5: // Subscript on + arg = 74; + vterm_state_setpen(state, &arg, 1); + break; + case 24: // Super+subscript off + arg = 75; + vterm_state_setpen(state, &arg, 1); + break; + } + } + break; + + case 0x6e: // DSR - ECMA-48 8.3.35 + case LEADER('?', 0x6e): // DECDSR + val = CSI_ARG_OR(args[0], 0); + + { + char *qmark = (leader_byte == '?') ? "?" : ""; + + switch(val) { + case 0: case 1: case 2: case 3: case 4: + // ignore - these are replies + break; + case 5: + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s0n", qmark); + break; + case 6: // CPR - cursor position report + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%s%d;%dR", qmark, state->pos.row + 1, state->pos.col + 1); + break; + } + } + break; + + + case LEADER('!', 0x70): // DECSTR - DEC soft terminal reset + vterm_state_reset(state, 0); + break; + + case LEADER('?', INTERMED('$', 0x70)): + request_dec_mode(state, CSI_ARG(args[0])); + break; + + case LEADER('>', 0x71): // XTVERSION - xterm query version string + request_version_string(state); + break; + + case INTERMED(' ', 0x71): // DECSCUSR - DEC set cursor shape + val = CSI_ARG_OR(args[0], 1); + + switch(val) { + case 0: case 1: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + break; + case 2: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + break; + case 3: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE); + break; + case 4: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE); + break; + case 5: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT); + break; + case 6: + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT); + break; + } + + break; + + case INTERMED('"', 0x71): // DECSCA - DEC select character protection attribute + val = CSI_ARG_OR(args[0], 0); + + switch(val) { + case 0: case 2: + state->protected_cell = 0; + break; + case 1: + state->protected_cell = 1; + break; + } + + break; + + case 0x72: // DECSTBM - DEC custom + state->scrollregion_top = CSI_ARG_OR(args[0], 1) - 1; + state->scrollregion_bottom = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_top, 0); + UBOUND(state->scrollregion_top, state->rows); + LBOUND(state->scrollregion_bottom, -1); + if(state->scrollregion_top == 0 && state->scrollregion_bottom == state->rows) + state->scrollregion_bottom = -1; + else + UBOUND(state->scrollregion_bottom, state->rows); + + if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) { + // Invalid + state->scrollregion_top = 0; + state->scrollregion_bottom = -1; + } + + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + + break; + + case 0x73: // DECSLRM - DEC custom + // Always allow setting these margins, just they won't take effect without DECVSSM + state->scrollregion_left = CSI_ARG_OR(args[0], 1) - 1; + state->scrollregion_right = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_left, 0); + UBOUND(state->scrollregion_left, state->cols); + LBOUND(state->scrollregion_right, -1); + if(state->scrollregion_left == 0 && state->scrollregion_right == state->cols) + state->scrollregion_right = -1; + else + UBOUND(state->scrollregion_right, state->cols); + + if(state->scrollregion_right > -1 && + state->scrollregion_right <= state->scrollregion_left) { + // Invalid + state->scrollregion_left = 0; + state->scrollregion_right = -1; + } + + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + + break; + + case INTERMED('\'', 0x7D): // DECIC + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = state->pos.col; + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, 0, -count); + + break; + + case INTERMED('\'', 0x7E): // DECDC + count = CSI_ARG_COUNT(args[0]); + + if(!is_cursor_in_scrollregion(state)) + break; + + rect.start_row = state->scrollregion_top; + rect.end_row = SCROLLREGION_BOTTOM(state); + rect.start_col = state->pos.col; + rect.end_col = SCROLLREGION_RIGHT(state); + + scroll(state, rect, 0, count); + + break; + + default: + if(state->fallbacks && state->fallbacks->csi) + if((*state->fallbacks->csi)(leader, args, argcount, intermed, command, state->fbdata)) + return 1; + + return 0; + } + + if(state->mode.origin) { + LBOUND(state->pos.row, state->scrollregion_top); + UBOUND(state->pos.row, SCROLLREGION_BOTTOM(state)-1); + LBOUND(state->pos.col, SCROLLREGION_LEFT(state)); + UBOUND(state->pos.col, SCROLLREGION_RIGHT(state)-1); + } + else { + LBOUND(state->pos.row, 0); + UBOUND(state->pos.row, state->rows-1); + LBOUND(state->pos.col, 0); + UBOUND(state->pos.col, THISROWWIDTH(state)-1); + } + + updatecursor(state, &oldpos, cancel_phantom); + +#ifdef DEBUG + if(state->pos.row < 0 || state->pos.row >= state->rows || + state->pos.col < 0 || state->pos.col >= state->cols) { + fprintf(stderr, "Position out of bounds after CSI %c: (%d,%d)\n", + command, state->pos.row, state->pos.col); + abort(); + } + + if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) { + fprintf(stderr, "Scroll region height out of bounds after CSI %c: %d <= %d\n", + command, SCROLLREGION_BOTTOM(state), state->scrollregion_top); + abort(); + } + + if(SCROLLREGION_RIGHT(state) <= SCROLLREGION_LEFT(state)) { + fprintf(stderr, "Scroll region width out of bounds after CSI %c: %d <= %d\n", + command, SCROLLREGION_RIGHT(state), SCROLLREGION_LEFT(state)); + abort(); + } +#endif + + return 1; +} + +static char base64_one(uint8_t b) +{ + if(b < 26) + return 'A' + b; + else if(b < 52) + return 'a' + b - 26; + else if(b < 62) + return '0' + b - 52; + else if(b == 62) + return '+'; + else if(b == 63) + return '/'; + return 0; +} + +static uint8_t unbase64one(char c) +{ + if(c >= 'A' && c <= 'Z') + return c - 'A'; + else if(c >= 'a' && c <= 'z') + return c - 'a' + 26; + else if(c >= '0' && c <= '9') + return c - '0' + 52; + else if(c == '+') + return 62; + else if(c == '/') + return 63; + + return 0xFF; +} + +static void osc_selection(VTermState *state, VTermStringFragment frag) +{ + if(frag.initial) { + state->tmp.selection.mask = 0; + state->tmp.selection.state = SELECTION_INITIAL; + } + + while(!state->tmp.selection.state && frag.len) { + /* Parse selection parameter */ + switch(frag.str[0]) { + case 'c': + state->tmp.selection.mask |= VTERM_SELECTION_CLIPBOARD; + break; + case 'p': + state->tmp.selection.mask |= VTERM_SELECTION_PRIMARY; + break; + case 'q': + state->tmp.selection.mask |= VTERM_SELECTION_SECONDARY; + break; + case 's': + state->tmp.selection.mask |= VTERM_SELECTION_SELECT; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + state->tmp.selection.mask |= (VTERM_SELECTION_CUT0 << (frag.str[0] - '0')); + break; + + case ';': + state->tmp.selection.state = SELECTION_SELECTED; + if(!state->tmp.selection.mask) + state->tmp.selection.mask = VTERM_SELECTION_SELECT|VTERM_SELECTION_CUT0; + break; + } + + frag.str++; + frag.len--; + } + + if(!frag.len) + return; + + if(state->tmp.selection.state == SELECTION_SELECTED) { + if(frag.str[0] == '?') { + state->tmp.selection.state = SELECTION_QUERY; + } + else { + state->tmp.selection.state = SELECTION_SET_INITIAL; + state->tmp.selection.recvpartial = 0; + } + } + + if(state->tmp.selection.state == SELECTION_QUERY) { + if(state->selection.callbacks->query) + (*state->selection.callbacks->query)(state->tmp.selection.mask, state->selection.user); + return; + } + + if(state->selection.callbacks->set) { + size_t bufcur = 0; + char *buffer = state->selection.buffer; + + uint32_t x = 0; /* Current decoding value */ + int n = 0; /* Number of sextets consumed */ + + if(state->tmp.selection.recvpartial) { + n = state->tmp.selection.recvpartial >> 24; + x = state->tmp.selection.recvpartial & 0x03FFFF; /* could be up to 18 bits of state in here */ + + state->tmp.selection.recvpartial = 0; + } + + while((state->selection.buflen - bufcur) >= 3 && frag.len) { + if(frag.str[0] == '=') { + if(n == 2) { + buffer[0] = (x >> 4) & 0xFF; + buffer += 1, bufcur += 1; + } + if(n == 3) { + buffer[0] = (x >> 10) & 0xFF; + buffer[1] = (x >> 2) & 0xFF; + buffer += 2, bufcur += 2; + } + + while(frag.len && frag.str[0] == '=') + frag.str++, frag.len--; + + n = 0; + } + else { + uint8_t b = unbase64one(frag.str[0]); + if(b == 0xFF) { + DEBUG_LOG("base64decode bad input %02X\n", (uint8_t)frag.str[0]); + } + else { + x = (x << 6) | b; + n++; + } + frag.str++, frag.len--; + + if(n == 4) { + buffer[0] = (x >> 16) & 0xFF; + buffer[1] = (x >> 8) & 0xFF; + buffer[2] = (x >> 0) & 0xFF; + + buffer += 3, bufcur += 3; + x = 0; + n = 0; + } + } + + if(!frag.len || (state->selection.buflen - bufcur) < 3) { + if(bufcur) { + (*state->selection.callbacks->set)(state->tmp.selection.mask, (VTermStringFragment){ + .str = state->selection.buffer, + .len = bufcur, + .initial = state->tmp.selection.state == SELECTION_SET_INITIAL, + .final = frag.final, + }, state->selection.user); + state->tmp.selection.state = SELECTION_SET; + } + + buffer = state->selection.buffer; + bufcur = 0; + } + } + + if(n) + state->tmp.selection.recvpartial = (n << 24) | x; + } +} + +static int on_osc(int command, VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + switch(command) { + case 0: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + settermprop_string(state, VTERM_PROP_TITLE, frag); + return 1; + + case 1: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + return 1; + + case 2: + settermprop_string(state, VTERM_PROP_TITLE, frag); + return 1; + + case 52: + if(state->selection.callbacks) + osc_selection(state, frag); + + return 1; + + default: + if(state->fallbacks && state->fallbacks->osc) + if((*state->fallbacks->osc)(command, frag, state->fbdata)) + return 1; + } + + return 0; +} + +static void request_status_string(VTermState *state, VTermStringFragment frag) +{ + VTerm *vt = state->vt; + + char *tmp = state->tmp.decrqss; + + if(frag.initial) + tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; + + int i = 0; + while(i < sizeof(state->tmp.decrqss)-1 && tmp[i]) + i++; + while(i < sizeof(state->tmp.decrqss)-1 && frag.len--) + tmp[i++] = (frag.str++)[0]; + tmp[i] = 0; + + if(!frag.final) + return; + + switch(tmp[0] | tmp[1]<<8 | tmp[2]<<16) { + case 'm': { + // Query SGR + long args[20]; + int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); + size_t cur = 0; + + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... + if(cur >= vt->tmpbuffer_len) + return; + + for(int argi = 0; argi < argc; argi++) { + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + argi == argc - 1 ? "%ld" : + CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : + "%ld;", + CSI_ARG(args[argi])); + if(cur >= vt->tmpbuffer_len) + return; + } + + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST + if(cur >= vt->tmpbuffer_len) + return; + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); + return; + } + + case 'r': + // Query DECSTBM + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); + return; + + case 's': + // Query DECSLRM + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); + return; + + case ' '|('q'<<8): { + // Query DECSCUSR + int reply; + switch(state->mode.cursor_shape) { + case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break; + case VTERM_PROP_CURSORSHAPE_UNDERLINE: reply = 4; break; + case VTERM_PROP_CURSORSHAPE_BAR_LEFT: reply = 6; break; + } + if(state->mode.cursor_blink) + reply--; + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d q", reply); + return; + } + + case '\"'|('q'<<8): + // Query DECSCA + vterm_push_output_sprintf_str(vt, C1_DCS, true, + "1$r%d\"q", state->protected_cell ? 1 : 2); + return; + } + + vterm_push_output_sprintf_str(state->vt, C1_DCS, true, "0$r"); +} + +static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(commandlen == 2 && strneq(command, "$q", 2)) { + request_status_string(state, frag); + return 1; + } + else if(state->fallbacks && state->fallbacks->dcs) + if((*state->fallbacks->dcs)(command, commandlen, frag, state->fbdata)) + return 1; + + DEBUG_LOG("libvterm: Unhandled DCS %.*s\n", (int)commandlen, command); + return 0; +} + +static int on_apc(VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(state->fallbacks && state->fallbacks->apc) + if((*state->fallbacks->apc)(frag, state->fbdata)) + return 1; + + /* No DEBUG_LOG because all APCs are unhandled */ + return 0; +} + +static int on_pm(VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(state->fallbacks && state->fallbacks->pm) + if((*state->fallbacks->pm)(frag, state->fbdata)) + return 1; + + /* No DEBUG_LOG because all PMs are unhandled */ + return 0; +} + +static int on_sos(VTermStringFragment frag, void *user) +{ + VTermState *state = user; + + if(state->fallbacks && state->fallbacks->sos) + if((*state->fallbacks->sos)(frag, state->fbdata)) + return 1; + + /* No DEBUG_LOG because all SOSs are unhandled */ + return 0; +} + +static int on_resize(int rows, int cols, void *user) +{ + VTermState *state = user; + VTermPos oldpos = state->pos; + + if(cols != state->cols) { + unsigned char *newtabstops = vterm_allocator_malloc(state->vt, (cols + 7) / 8); + + /* TODO: This can all be done much more efficiently bytewise */ + int col; + for(col = 0; col < state->cols && col < cols; col++) { + unsigned char mask = 1 << (col & 7); + if(state->tabstops[col >> 3] & mask) + newtabstops[col >> 3] |= mask; + else + newtabstops[col >> 3] &= ~mask; + } + + for( ; col < cols; col++) { + unsigned char mask = 1 << (col & 7); + if(col % 8 == 0) + newtabstops[col >> 3] |= mask; + else + newtabstops[col >> 3] &= ~mask; + } + + vterm_allocator_free(state->vt, state->tabstops); + state->tabstops = newtabstops; + } + + state->rows = rows; + state->cols = cols; + + if(state->scrollregion_bottom > -1) + UBOUND(state->scrollregion_bottom, state->rows); + if(state->scrollregion_right > -1) + UBOUND(state->scrollregion_right, state->cols); + + VTermStateFields fields = { + .pos = state->pos, + .lineinfos = { [0] = state->lineinfos[0], [1] = state->lineinfos[1] }, + }; + + if(state->callbacks && state->callbacks->resize) { + (*state->callbacks->resize)(rows, cols, &fields, state->cbdata); + state->pos = fields.pos; + + state->lineinfos[0] = fields.lineinfos[0]; + state->lineinfos[1] = fields.lineinfos[1]; + } + else { + if(rows != state->rows) { + for(int bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { + VTermLineInfo *oldlineinfo = state->lineinfos[bufidx]; + if(!oldlineinfo) + continue; + + VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + + int row; + for(row = 0; row < state->rows && row < rows; row++) { + newlineinfo[row] = oldlineinfo[row]; + } + + for( ; row < rows; row++) { + newlineinfo[row] = (VTermLineInfo){ + .doublewidth = 0, + }; + } + + vterm_allocator_free(state->vt, state->lineinfos[bufidx]); + state->lineinfos[bufidx] = newlineinfo; + } + } + } + + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; + + if(state->at_phantom && state->pos.col < cols-1) { + state->at_phantom = 0; + state->pos.col++; + } + + if(state->pos.row < 0) + state->pos.row = 0; + if(state->pos.row >= rows) + state->pos.row = rows - 1; + if(state->pos.col < 0) + state->pos.col = 0; + if(state->pos.col >= cols) + state->pos.col = cols - 1; + + updatecursor(state, &oldpos, 1); + + return 1; +} + +static const VTermParserCallbacks parser_callbacks = { + .text = on_text, + .control = on_control, + .escape = on_escape, + .csi = on_csi, + .osc = on_osc, + .dcs = on_dcs, + .apc = on_apc, + .pm = on_pm, + .sos = on_sos, + .resize = on_resize, +}; + +VTermState *vterm_obtain_state(VTerm *vt) +{ + if(vt->state) + return vt->state; + + VTermState *state = vterm_state_new(vt); + vt->state = state; + + vterm_parser_set_callbacks(vt, &parser_callbacks, state); + + return state; +} + +void vterm_state_reset(VTermState *state, int hard) +{ + state->scrollregion_top = 0; + state->scrollregion_bottom = -1; + state->scrollregion_left = 0; + state->scrollregion_right = -1; + + state->mode.keypad = 0; + state->mode.cursor = 0; + state->mode.autowrap = 1; + state->mode.insert = 0; + state->mode.newline = 0; + state->mode.alt_screen = 0; + state->mode.origin = 0; + state->mode.leftrightmargin = 0; + state->mode.bracketpaste = 0; + state->mode.report_focus = 0; + + state->mouse_flags = 0; + + state->vt->mode.ctrl8bit = 0; + + for(int col = 0; col < state->cols; col++) + if(col % 8 == 0) + set_col_tabstop(state, col); + else + clear_col_tabstop(state, col); + + for(int row = 0; row < state->rows; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + + if(state->callbacks && state->callbacks->initpen) + (*state->callbacks->initpen)(state->cbdata); + + vterm_state_resetpen(state); + + VTermEncoding *default_enc = state->vt->mode.utf8 ? + vterm_lookup_encoding(ENC_UTF8, 'u') : + vterm_lookup_encoding(ENC_SINGLE_94, 'B'); + + for(int i = 0; i < 4; i++) { + state->encoding[i].enc = default_enc; + if(default_enc->init) + (*default_enc->init)(default_enc, state->encoding[i].data); + } + + state->gl_set = 0; + state->gr_set = 1; + state->gsingle_set = 0; + + state->protected_cell = 0; + + // Initialise the props + settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, 1); + settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1); + settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK); + + if(hard) { + state->pos.row = 0; + state->pos.col = 0; + state->at_phantom = 0; + + VTermRect rect = { 0, state->rows, 0, state->cols }; + erase(state, rect, 0); + } +} + +void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos) +{ + *cursorpos = state->pos; +} + +void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user) +{ + if(callbacks) { + state->callbacks = callbacks; + state->cbdata = user; + + if(state->callbacks && state->callbacks->initpen) + (*state->callbacks->initpen)(state->cbdata); + } + else { + state->callbacks = NULL; + state->cbdata = NULL; + } +} + +void *vterm_state_get_cbdata(VTermState *state) +{ + return state->cbdata; +} + +void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user) +{ + if(fallbacks) { + state->fallbacks = fallbacks; + state->fbdata = user; + } + else { + state->fallbacks = NULL; + state->fbdata = NULL; + } +} + +void *vterm_state_get_unrecognised_fbdata(VTermState *state) +{ + return state->fbdata; +} + +int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) +{ + /* Only store the new value of the property if usercode said it was happy. + * This is especially important for altscreen switching */ + if(state->callbacks && state->callbacks->settermprop) + if(!(*state->callbacks->settermprop)(prop, val, state->cbdata)) + return 0; + + switch(prop) { + case VTERM_PROP_TITLE: + case VTERM_PROP_ICONNAME: + // we don't store these, just transparently pass through + return 1; + case VTERM_PROP_CURSORVISIBLE: + state->mode.cursor_visible = val->boolean; + return 1; + case VTERM_PROP_CURSORBLINK: + state->mode.cursor_blink = val->boolean; + return 1; + case VTERM_PROP_CURSORSHAPE: + state->mode.cursor_shape = val->number; + return 1; + case VTERM_PROP_REVERSE: + state->mode.screen = val->boolean; + return 1; + case VTERM_PROP_ALTSCREEN: + state->mode.alt_screen = val->boolean; + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; + if(state->mode.alt_screen) { + VTermRect rect = { + .start_row = 0, + .start_col = 0, + .end_row = state->rows, + .end_col = state->cols, + }; + erase(state, rect, 0); + } + return 1; + case VTERM_PROP_MOUSE: + state->mouse_flags = 0; + if(val->number) + state->mouse_flags |= MOUSE_WANT_CLICK; + if(val->number == VTERM_PROP_MOUSE_DRAG) + state->mouse_flags |= MOUSE_WANT_DRAG; + if(val->number == VTERM_PROP_MOUSE_MOVE) + state->mouse_flags |= MOUSE_WANT_MOVE; + return 1; + + case VTERM_N_PROPS: + return 0; + } + + return 0; +} + +void vterm_state_focus_in(VTermState *state) +{ + if(state->mode.report_focus) + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "I"); +} + +void vterm_state_focus_out(VTermState *state) +{ + if(state->mode.report_focus) + vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "O"); +} + +const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row) +{ + return state->lineinfo + row; +} + +void vterm_state_set_selection_callbacks(VTermState *state, const VTermSelectionCallbacks *callbacks, void *user, + char *buffer, size_t buflen) +{ + if(buflen && !buffer) + buffer = vterm_allocator_malloc(state->vt, buflen); + + state->selection.callbacks = callbacks; + state->selection.user = user; + state->selection.buffer = buffer; + state->selection.buflen = buflen; +} + +void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTermStringFragment frag) +{ + VTerm *vt = state->vt; + + if(frag.initial) { + /* TODO: support sending more than one mask bit */ + const static char selection_chars[] = "cpqs"; + int idx; + for(idx = 0; idx < 4; idx++) + if(mask & (1 << idx)) + break; + + vterm_push_output_sprintf_str(vt, C1_OSC, false, "52;%c;", selection_chars[idx]); + + state->tmp.selection.sendpartial = 0; + } + + if(frag.len) { + size_t bufcur = 0; + char *buffer = state->selection.buffer; + + uint32_t x = 0; + int n = 0; + + if(state->tmp.selection.sendpartial) { + n = state->tmp.selection.sendpartial >> 24; + x = state->tmp.selection.sendpartial & 0xFFFFFF; + + state->tmp.selection.sendpartial = 0; + } + + while((state->selection.buflen - bufcur) >= 4 && frag.len) { + x = (x << 8) | frag.str[0]; + n++; + frag.str++, frag.len--; + + if(n == 3) { + buffer[0] = base64_one((x >> 18) & 0x3F); + buffer[1] = base64_one((x >> 12) & 0x3F); + buffer[2] = base64_one((x >> 6) & 0x3F); + buffer[3] = base64_one((x >> 0) & 0x3F); + + buffer += 4, bufcur += 4; + x = 0; + n = 0; + } + + if(!frag.len || (state->selection.buflen - bufcur) < 4) { + if(bufcur) + vterm_push_output_bytes(vt, state->selection.buffer, bufcur); + + buffer = state->selection.buffer; + bufcur = 0; + } + } + + if(n) + state->tmp.selection.sendpartial = (n << 24) | x; + } + + if(frag.final) { + if(state->tmp.selection.sendpartial) { + int n = state->tmp.selection.sendpartial >> 24; + uint32_t x = state->tmp.selection.sendpartial & 0xFFFFFF; + char *buffer = state->selection.buffer; + + /* n is either 1 or 2 now */ + x <<= (n == 1) ? 16 : 8; + + buffer[0] = base64_one((x >> 18) & 0x3F); + buffer[1] = base64_one((x >> 12) & 0x3F); + buffer[2] = (n == 1) ? '=' : base64_one((x >> 6) & 0x3F); + buffer[3] = '='; + + vterm_push_output_sprintf_str(vt, 0, true, "%.*s", 4, buffer); + } + else + vterm_push_output_sprintf_str(vt, 0, true, ""); + } +} diff --git a/src/libs/3rdparty/libvterm/src/unicode.c b/src/libs/3rdparty/libvterm/src/unicode.c new file mode 100644 index 00000000000..269244ff6b9 --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/unicode.c @@ -0,0 +1,313 @@ +#include "vterm_internal.h" + +// ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c +// With modifications: +// made functions static +// moved 'combining' table to file scope, so other functions can see it +// ################################################################### + +/* + * This is an implementation of wcwidth() and wcswidth() (defined in + * IEEE Std 1002.1-2001) for Unicode. + * + * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html + * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html + * + * In fixed-width output devices, Latin characters all occupy a single + * "cell" position of equal width, whereas ideographic CJK characters + * occupy two such cells. Interoperability between terminal-line + * applications and (teletype-style) character terminals using the + * UTF-8 encoding requires agreement on which character should advance + * the cursor by how many cell positions. No established formal + * standards exist at present on which Unicode character shall occupy + * how many cell positions on character terminals. These routines are + * a first attempt of defining such behavior based on simple rules + * applied to data provided by the Unicode Consortium. + * + * For some graphical characters, the Unicode standard explicitly + * defines a character-cell width via the definition of the East Asian + * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. + * In all these cases, there is no ambiguity about which width a + * terminal shall use. For characters in the East Asian Ambiguous (A) + * class, the width choice depends purely on a preference of backward + * compatibility with either historic CJK or Western practice. + * Choosing single-width for these characters is easy to justify as + * the appropriate long-term solution, as the CJK practice of + * displaying these characters as double-width comes from historic + * implementation simplicity (8-bit encoded characters were displayed + * single-width and 16-bit ones double-width, even for Greek, + * Cyrillic, etc.) and not any typographic considerations. + * + * Much less clear is the choice of width for the Not East Asian + * (Neutral) class. Existing practice does not dictate a width for any + * of these characters. It would nevertheless make sense + * typographically to allocate two character cells to characters such + * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be + * represented adequately with a single-width glyph. The following + * routines at present merely assign a single-cell width to all + * neutral characters, in the interest of simplicity. This is not + * entirely satisfactory and should be reconsidered before + * establishing a formal standard in this area. At the moment, the + * decision which Not East Asian (Neutral) characters should be + * represented by double-width glyphs cannot yet be answered by + * applying a simple rule from the Unicode database content. Setting + * up a proper standard for the behavior of UTF-8 character terminals + * will require a careful analysis not only of each Unicode character, + * but also of each presentation form, something the author of these + * routines has avoided to do so far. + * + * http://www.unicode.org/unicode/reports/tr11/ + * + * Markus Kuhn -- 2007-05-26 (Unicode 5.0) + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted. The author + * disclaims all warranties with regard to this software. + * + * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ + +struct interval { + int first; + int last; +}; + +/* sorted list of non-overlapping intervals of non-spacing characters */ +/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ +static const struct interval combining[] = { + { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, + { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, + { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, + { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, + { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, + { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, + { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, + { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, + { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, + { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, + { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, + { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, + { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, + { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, + { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, + { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, + { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, + { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, + { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, + { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, + { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, + { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, + { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, + { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, + { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, + { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, + { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, + { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, + { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, + { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, + { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, + { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, + { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, + { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, + { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, + { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, + { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, + { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, + { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, + { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, + { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, + { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, + { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, + { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, + { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, + { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, + { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, + { 0xE0100, 0xE01EF } +}; + + +/* auxiliary function for binary search in interval table */ +static int bisearch(uint32_t ucs, const struct interval *table, int max) { + int min = 0; + int mid; + + if (ucs < table[0].first || ucs > table[max].last) + return 0; + while (max >= min) { + mid = (min + max) / 2; + if (ucs > table[mid].last) + min = mid + 1; + else if (ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + + return 0; +} + + +/* The following two functions define the column width of an ISO 10646 + * character as follows: + * + * - The null character (U+0000) has a column width of 0. + * + * - Other C0/C1 control characters and DEL will lead to a return + * value of -1. + * + * - Non-spacing and enclosing combining characters (general + * category code Mn or Me in the Unicode database) have a + * column width of 0. + * + * - SOFT HYPHEN (U+00AD) has a column width of 1. + * + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. + * + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * + * - Spacing characters in the East Asian Wide (W) or East Asian + * Full-width (F) category as defined in Unicode Technical + * Report #11 have a column width of 2. + * + * - All remaining characters (including all printable + * ISO 8859-1 and WGL4 characters, Unicode control characters, + * etc.) have a column width of 1. + * + * This implementation assumes that uint32_t characters are encoded + * in ISO 10646. + */ + + +static int mk_wcwidth(uint32_t ucs) +{ + /* test for 8-bit control characters */ + if (ucs == 0) + return 0; + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) + return -1; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, combining, + sizeof(combining) / sizeof(struct interval) - 1)) + return 0; + + /* if we arrive here, ucs is not a combining or C0/C1 control character */ + + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || /* Hangul Jamo init. consonants */ + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && + ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); +} + + +#ifdef USE_MK_WCWIDTH_CJK + +/* + * The following functions are the same as mk_wcwidth() and + * mk_wcswidth(), except that spacing characters in the East Asian + * Ambiguous (A) category as defined in Unicode Technical Report #11 + * have a column width of 2. This variant might be useful for users of + * CJK legacy encodings who want to migrate to UCS without changing + * the traditional terminal character-width behaviour. It is not + * otherwise recommended for general use. + */ +static int mk_wcwidth_cjk(uint32_t ucs) +{ + /* sorted list of non-overlapping intervals of East Asian Ambiguous + * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ + static const struct interval ambiguous[] = { + { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, + { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, + { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, + { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, + { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, + { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, + { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, + { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, + { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, + { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, + { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, + { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, + { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, + { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, + { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, + { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, + { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, + { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, + { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, + { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, + { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, + { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, + { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, + { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, + { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, + { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, + { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, + { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, + { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, + { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, + { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, + { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, + { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, + { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, + { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, + { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, + { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, + { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, + { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, + { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, + { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, + { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, + { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, + { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, + { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, + { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, + { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, + { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, + { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, + { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, + { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, + { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } + }; + + /* binary search in table of non-spacing characters */ + if (bisearch(ucs, ambiguous, + sizeof(ambiguous) / sizeof(struct interval) - 1)) + return 2; + + return mk_wcwidth(ucs); +} + +#endif + +// ################################ +// ### The rest added by Paul Evans + +static const struct interval fullwidth[] = { +#include "fullwidth.inc" +}; + +INTERNAL int vterm_unicode_width(uint32_t codepoint) +{ + if(bisearch(codepoint, fullwidth, sizeof(fullwidth) / sizeof(fullwidth[0]) - 1)) + return 2; + + return mk_wcwidth(codepoint); +} + +INTERNAL int vterm_unicode_is_combining(uint32_t codepoint) +{ + return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1); +} diff --git a/src/libs/3rdparty/libvterm/src/utf8.h b/src/libs/3rdparty/libvterm/src/utf8.h new file mode 100644 index 00000000000..9a336d357ff --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/utf8.h @@ -0,0 +1,39 @@ +/* The following functions copied and adapted from libtermkey + * + * http://www.leonerd.org.uk/code/libtermkey/ + */ +static inline unsigned int utf8_seqlen(long codepoint) +{ + if(codepoint < 0x0000080) return 1; + if(codepoint < 0x0000800) return 2; + if(codepoint < 0x0010000) return 3; + if(codepoint < 0x0200000) return 4; + if(codepoint < 0x4000000) return 5; + return 6; +} + +/* Does NOT NUL-terminate the buffer */ +static int fill_utf8(long codepoint, char *str) +{ + int nbytes = utf8_seqlen(codepoint); + + // This is easier done backwards + int b = nbytes; + while(b > 1) { + b--; + str[b] = 0x80 | (codepoint & 0x3f); + codepoint >>= 6; + } + + switch(nbytes) { + case 1: str[0] = (codepoint & 0x7f); break; + case 2: str[0] = 0xc0 | (codepoint & 0x1f); break; + case 3: str[0] = 0xe0 | (codepoint & 0x0f); break; + case 4: str[0] = 0xf0 | (codepoint & 0x07); break; + case 5: str[0] = 0xf8 | (codepoint & 0x03); break; + case 6: str[0] = 0xfc | (codepoint & 0x01); break; + } + + return nbytes; +} +/* end copy */ diff --git a/src/libs/3rdparty/libvterm/src/vterm.c b/src/libs/3rdparty/libvterm/src/vterm.c new file mode 100644 index 00000000000..0997887f5fb --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/vterm.c @@ -0,0 +1,429 @@ +#include "vterm_internal.h" + +#include +#include +#include +#include + +/***************** + * API functions * + *****************/ + +static void *default_malloc(size_t size, void *allocdata) +{ + void *ptr = malloc(size); + if(ptr) + memset(ptr, 0, size); + return ptr; +} + +static void default_free(void *ptr, void *allocdata) +{ + free(ptr); +} + +static VTermAllocatorFunctions default_allocator = { + .malloc = &default_malloc, + .free = &default_free, +}; + +VTerm *vterm_new(int rows, int cols) +{ + return vterm_build(&(const struct VTermBuilder){ + .rows = rows, + .cols = cols, + }); +} + +VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata) +{ + return vterm_build(&(const struct VTermBuilder){ + .rows = rows, + .cols = cols, + .allocator = funcs, + .allocdata = allocdata, + }); +} + +/* A handy macro for defaulting values out of builder fields */ +#define DEFAULT(v, def) ((v) ? (v) : (def)) + +VTerm *vterm_build(const struct VTermBuilder *builder) +{ + const VTermAllocatorFunctions *allocator = DEFAULT(builder->allocator, &default_allocator); + + /* Need to bootstrap using the allocator function directly */ + VTerm *vt = (*allocator->malloc)(sizeof(VTerm), builder->allocdata); + + vt->allocator = allocator; + vt->allocdata = builder->allocdata; + + vt->rows = builder->rows; + vt->cols = builder->cols; + + vt->parser.state = NORMAL; + + vt->parser.callbacks = NULL; + vt->parser.cbdata = NULL; + + vt->parser.emit_nul = false; + + vt->outfunc = NULL; + vt->outdata = NULL; + + vt->outbuffer_len = DEFAULT(builder->outbuffer_len, 4096); + vt->outbuffer_cur = 0; + vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len); + + vt->tmpbuffer_len = DEFAULT(builder->tmpbuffer_len, 4096); + vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len); + + return vt; +} + +void vterm_free(VTerm *vt) +{ + if(vt->screen) + vterm_screen_free(vt->screen); + + if(vt->state) + vterm_state_free(vt->state); + + vterm_allocator_free(vt, vt->outbuffer); + vterm_allocator_free(vt, vt->tmpbuffer); + + vterm_allocator_free(vt, vt); +} + +INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size) +{ + return (*vt->allocator->malloc)(size, vt->allocdata); +} + +INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr) +{ + (*vt->allocator->free)(ptr, vt->allocdata); +} + +void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp) +{ + if(rowsp) + *rowsp = vt->rows; + if(colsp) + *colsp = vt->cols; +} + +void vterm_set_size(VTerm *vt, int rows, int cols) +{ + if(rows < 1 || cols < 1) + return; + + vt->rows = rows; + vt->cols = cols; + + if(vt->parser.callbacks && vt->parser.callbacks->resize) + (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata); +} + +int vterm_get_utf8(const VTerm *vt) +{ + return vt->mode.utf8; +} + +void vterm_set_utf8(VTerm *vt, int is_utf8) +{ + vt->mode.utf8 = is_utf8; +} + +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user) +{ + vt->outfunc = func; + vt->outdata = user; +} + +INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) +{ + if(vt->outfunc) { + (vt->outfunc)(bytes, len, vt->outdata); + return; + } + + if(len > vt->outbuffer_len - vt->outbuffer_cur) + return; + + memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len); + vt->outbuffer_cur += len; +} + +INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) +{ + size_t len = vsnprintf(vt->tmpbuffer, vt->tmpbuffer_len, + format, args); + + vterm_push_output_bytes(vt, vt->tmpbuffer, len); +} + +INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) +{ + va_list args; + va_start(args, format); + vterm_push_output_vsprintf(vt, format, args); + va_end(args); +} + +INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) +{ + size_t cur; + + if(ctrl >= 0x80 && !vt->mode.ctrl8bit) + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", ctrl - 0x40); + else + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", ctrl); + + if(cur >= vt->tmpbuffer_len) + return; + + va_list args; + va_start(args, fmt); + cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + fmt, args); + va_end(args); + + if(cur >= vt->tmpbuffer_len) + return; + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); +} + +INTERNAL void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, bool term, const char *fmt, ...) +{ + size_t cur = 0; + + if(ctrl) { + if(ctrl >= 0x80 && !vt->mode.ctrl8bit) + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", ctrl - 0x40); + else + cur = snprintf(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", ctrl); + + if(cur >= vt->tmpbuffer_len) + return; + } + + va_list args; + va_start(args, fmt); + cur += vsnprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + fmt, args); + va_end(args); + + if(cur >= vt->tmpbuffer_len) + return; + + if(term) { + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST + + if(cur >= vt->tmpbuffer_len) + return; + } + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); +} + +size_t vterm_output_get_buffer_size(const VTerm *vt) +{ + return vt->outbuffer_len; +} + +size_t vterm_output_get_buffer_current(const VTerm *vt) +{ + return vt->outbuffer_cur; +} + +size_t vterm_output_get_buffer_remaining(const VTerm *vt) +{ + return vt->outbuffer_len - vt->outbuffer_cur; +} + +size_t vterm_output_read(VTerm *vt, char *buffer, size_t len) +{ + if(len > vt->outbuffer_cur) + len = vt->outbuffer_cur; + + memcpy(buffer, vt->outbuffer, len); + + if(len < vt->outbuffer_cur) + memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len); + + vt->outbuffer_cur -= len; + + return len; +} + +VTermValueType vterm_get_attr_type(VTermAttr attr) +{ + switch(attr) { + case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT; + case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_CONCEAL: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT; + case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR; + case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR; + case VTERM_ATTR_SMALL: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_BASELINE: return VTERM_VALUETYPE_INT; + + case VTERM_N_ATTRS: return 0; + } + return 0; /* UNREACHABLE */ +} + +VTermValueType vterm_get_prop_type(VTermProp prop) +{ + switch(prop) { + case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING; + case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING; + case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL; + case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT; + case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT; + + case VTERM_N_PROPS: return 0; + } + return 0; /* UNREACHABLE */ +} + +void vterm_scroll_rect(VTermRect rect, + int downward, + int rightward, + int (*moverect)(VTermRect src, VTermRect dest, void *user), + int (*eraserect)(VTermRect rect, int selective, void *user), + void *user) +{ + VTermRect src; + VTermRect dest; + + if(abs(downward) >= rect.end_row - rect.start_row || + abs(rightward) >= rect.end_col - rect.start_col) { + /* Scroll more than area; just erase the lot */ + (*eraserect)(rect, 0, user); + return; + } + + if(rightward >= 0) { + /* rect: [XXX................] + * src: [----------------] + * dest: [----------------] + */ + dest.start_col = rect.start_col; + dest.end_col = rect.end_col - rightward; + src.start_col = rect.start_col + rightward; + src.end_col = rect.end_col; + } + else { + /* rect: [................XXX] + * src: [----------------] + * dest: [----------------] + */ + int leftward = -rightward; + dest.start_col = rect.start_col + leftward; + dest.end_col = rect.end_col; + src.start_col = rect.start_col; + src.end_col = rect.end_col - leftward; + } + + if(downward >= 0) { + dest.start_row = rect.start_row; + dest.end_row = rect.end_row - downward; + src.start_row = rect.start_row + downward; + src.end_row = rect.end_row; + } + else { + int upward = -downward; + dest.start_row = rect.start_row + upward; + dest.end_row = rect.end_row; + src.start_row = rect.start_row; + src.end_row = rect.end_row - upward; + } + + if(moverect) + (*moverect)(dest, src, user); + + if(downward > 0) + rect.start_row = rect.end_row - downward; + else if(downward < 0) + rect.end_row = rect.start_row - downward; + + if(rightward > 0) + rect.start_col = rect.end_col - rightward; + else if(rightward < 0) + rect.end_col = rect.start_col - rightward; + + (*eraserect)(rect, 0, user); +} + +void vterm_copy_cells(VTermRect dest, + VTermRect src, + void (*copycell)(VTermPos dest, VTermPos src, void *user), + void *user) +{ + int downward = src.start_row - dest.start_row; + int rightward = src.start_col - dest.start_col; + + int init_row, test_row, init_col, test_col; + int inc_row, inc_col; + + if(downward < 0) { + init_row = dest.end_row - 1; + test_row = dest.start_row - 1; + inc_row = -1; + } + else /* downward >= 0 */ { + init_row = dest.start_row; + test_row = dest.end_row; + inc_row = +1; + } + + if(rightward < 0) { + init_col = dest.end_col - 1; + test_col = dest.start_col - 1; + inc_col = -1; + } + else /* rightward >= 0 */ { + init_col = dest.start_col; + test_col = dest.end_col; + inc_col = +1; + } + + VTermPos pos; + for(pos.row = init_row; pos.row != test_row; pos.row += inc_row) + for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) { + VTermPos srcpos = { pos.row + downward, pos.col + rightward }; + (*copycell)(pos, srcpos, user); + } +} + +void vterm_check_version(int major, int minor) +{ + if(major != VTERM_VERSION_MAJOR) { + fprintf(stderr, "libvterm major version mismatch; %d (wants) != %d (library)\n", + major, VTERM_VERSION_MAJOR); + exit(1); + } + + if(minor > VTERM_VERSION_MINOR) { + fprintf(stderr, "libvterm minor version mismatch; %d (wants) > %d (library)\n", + minor, VTERM_VERSION_MINOR); + exit(1); + } + + // Happy +} diff --git a/src/libs/3rdparty/libvterm/src/vterm_internal.h b/src/libs/3rdparty/libvterm/src/vterm_internal.h new file mode 100644 index 00000000000..df9495c6786 --- /dev/null +++ b/src/libs/3rdparty/libvterm/src/vterm_internal.h @@ -0,0 +1,296 @@ +#ifndef __VTERM_INTERNAL_H__ +#define __VTERM_INTERNAL_H__ + +#include "vterm.h" + +#include + +#if defined(__GNUC__) +# define INTERNAL __attribute__((visibility("internal"))) +#else +# define INTERNAL +#endif + +#ifdef DEBUG +# define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__) +#else +# define DEBUG_LOG(...) +#endif + +#define ESC_S "\x1b" + +#define INTERMED_MAX 16 + +#define CSI_ARGS_MAX 16 +#define CSI_LEADER_MAX 16 + +#define BUFIDX_PRIMARY 0 +#define BUFIDX_ALTSCREEN 1 + +typedef struct VTermEncoding VTermEncoding; + +typedef struct { + VTermEncoding *enc; + + // This size should be increased if required by other stateful encodings + char data[4*sizeof(uint32_t)]; +} VTermEncodingInstance; + +struct VTermPen +{ + VTermColor fg; + VTermColor bg; + unsigned int bold:1; + unsigned int underline:2; + unsigned int italic:1; + unsigned int blink:1; + unsigned int reverse:1; + unsigned int conceal:1; + unsigned int strike:1; + unsigned int font:4; /* To store 0-9 */ + unsigned int small:1; + unsigned int baseline:2; +}; + +struct VTermState +{ + VTerm *vt; + + const VTermStateCallbacks *callbacks; + void *cbdata; + + const VTermStateFallbacks *fallbacks; + void *fbdata; + + int rows; + int cols; + + /* Current cursor position */ + VTermPos pos; + + int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */ + + int scrollregion_top; + int scrollregion_bottom; /* -1 means unbounded */ +#define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows) + int scrollregion_left; +#define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0) + int scrollregion_right; /* -1 means unbounded */ +#define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols) + + /* Bitvector of tab stops */ + unsigned char *tabstops; + + /* Primary and Altscreen; lineinfos[1] is lazily allocated as needed */ + VTermLineInfo *lineinfos[2]; + + /* lineinfo will == lineinfos[0] or lineinfos[1], depending on altscreen */ + VTermLineInfo *lineinfo; +#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols) +#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row) + + /* Mouse state */ + int mouse_col, mouse_row; + int mouse_buttons; + int mouse_flags; +#define MOUSE_WANT_CLICK 0x01 +#define MOUSE_WANT_DRAG 0x02 +#define MOUSE_WANT_MOVE 0x04 + + enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol; + + /* Last glyph output, for Unicode recombining purposes */ + uint32_t *combine_chars; + size_t combine_chars_size; // Number of ELEMENTS in the above + int combine_width; // The width of the glyph above + VTermPos combine_pos; // Position before movement + + struct { + unsigned int keypad:1; + unsigned int cursor:1; + unsigned int autowrap:1; + unsigned int insert:1; + unsigned int newline:1; + unsigned int cursor_visible:1; + unsigned int cursor_blink:1; + unsigned int cursor_shape:2; + unsigned int alt_screen:1; + unsigned int origin:1; + unsigned int screen:1; + unsigned int leftrightmargin:1; + unsigned int bracketpaste:1; + unsigned int report_focus:1; + } mode; + + VTermEncodingInstance encoding[4], encoding_utf8; + int gl_set, gr_set, gsingle_set; + + struct VTermPen pen; + + VTermColor default_fg; + VTermColor default_bg; + VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only + + int bold_is_highbright; + + unsigned int protected_cell : 1; + + /* Saved state under DEC mode 1048/1049 */ + struct { + VTermPos pos; + struct VTermPen pen; + + struct { + unsigned int cursor_visible:1; + unsigned int cursor_blink:1; + unsigned int cursor_shape:2; + } mode; + } saved; + + /* Temporary state for DECRQSS parsing */ + union { + char decrqss[4]; + struct { + uint16_t mask; + enum { + SELECTION_INITIAL, + SELECTION_SELECTED, + SELECTION_QUERY, + SELECTION_SET_INITIAL, + SELECTION_SET, + } state : 8; + uint32_t recvpartial; + uint32_t sendpartial; + } selection; + } tmp; + + struct { + const VTermSelectionCallbacks *callbacks; + void *user; + char *buffer; + size_t buflen; + } selection; +}; + +struct VTerm +{ + const VTermAllocatorFunctions *allocator; + void *allocdata; + + int rows; + int cols; + + struct { + unsigned int utf8:1; + unsigned int ctrl8bit:1; + } mode; + + struct { + enum VTermParserState { + NORMAL, + CSI_LEADER, + CSI_ARGS, + CSI_INTERMED, + DCS_COMMAND, + /* below here are the "string states" */ + OSC_COMMAND, + OSC, + DCS, + APC, + PM, + SOS, + } state; + + bool in_esc : 1; + + int intermedlen; + char intermed[INTERMED_MAX]; + + union { + struct { + int leaderlen; + char leader[CSI_LEADER_MAX]; + + int argi; + long args[CSI_ARGS_MAX]; + } csi; + struct { + int command; + } osc; + struct { + int commandlen; + char command[CSI_LEADER_MAX]; + } dcs; + } v; + + const VTermParserCallbacks *callbacks; + void *cbdata; + + bool string_initial; + + bool emit_nul; + } parser; + + /* len == malloc()ed size; cur == number of valid bytes */ + + VTermOutputCallback *outfunc; + void *outdata; + + char *outbuffer; + size_t outbuffer_len; + size_t outbuffer_cur; + + char *tmpbuffer; + size_t tmpbuffer_len; + + VTermState *state; + VTermScreen *screen; +}; + +struct VTermEncoding { + void (*init) (VTermEncoding *enc, void *data); + void (*decode)(VTermEncoding *enc, void *data, + uint32_t cp[], int *cpi, int cplen, + const char bytes[], size_t *pos, size_t len); +}; + +typedef enum { + ENC_UTF8, + ENC_SINGLE_94 +} VTermEncodingType; + +void *vterm_allocator_malloc(VTerm *vt, size_t size); +void vterm_allocator_free(VTerm *vt, void *ptr); + +void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len); +void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args); +void vterm_push_output_sprintf(VTerm *vt, const char *format, ...); +void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...); +void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, bool term, const char *fmt, ...); + +void vterm_state_free(VTermState *state); + +void vterm_state_newpen(VTermState *state); +void vterm_state_resetpen(VTermState *state); +void vterm_state_setpen(VTermState *state, const long args[], int argcount); +int vterm_state_getpen(VTermState *state, long args[], int argcount); +void vterm_state_savepen(VTermState *state, int save); + +enum { + C1_SS3 = 0x8f, + C1_DCS = 0x90, + C1_CSI = 0x9b, + C1_ST = 0x9c, + C1_OSC = 0x9d, +}; + +void vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...); + +void vterm_screen_free(VTermScreen *screen); + +VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation); + +int vterm_unicode_width(uint32_t codepoint); +int vterm_unicode_is_combining(uint32_t codepoint); + +#endif diff --git a/src/libs/3rdparty/libvterm/vterm.pc.in b/src/libs/3rdparty/libvterm/vterm.pc.in new file mode 100644 index 00000000000..681a270d513 --- /dev/null +++ b/src/libs/3rdparty/libvterm/vterm.pc.in @@ -0,0 +1,8 @@ +libdir=@LIBDIR@ +includedir=@INCDIR@ + +Name: vterm +Description: Abstract VT220/Xterm/ECMA-48 emulation library +Version: 0.3.1 +Libs: -L${libdir} -lvterm +Cflags: -I${includedir} diff --git a/src/libs/3rdparty/libvterm/vterm.qbs b/src/libs/3rdparty/libvterm/vterm.qbs new file mode 100644 index 00000000000..274e3a46d6c --- /dev/null +++ b/src/libs/3rdparty/libvterm/vterm.qbs @@ -0,0 +1,33 @@ +Project { + QtcLibrary { + name: "vterm" + type: "staticlibrary" + + Depends { name: "cpp" } + cpp.includePaths: base.concat("include") + + Group { + prefix: "src/" + files: [ + "encoding.c", + "fullwidth.inc", + "keyboard.c", + "mouse.c", + "parser.c", + "pen.c", + "rect.h", + "screen.c", + "state.c", + "unicode.c", + "utf8.h", + "vterm.c", + "vterm_internal.h", + ] + } + + Export { + Depends { name: "cpp" } + cpp.includePaths: base.concat("include") + } + } +} diff --git a/src/libs/3rdparty/winpty/.gitattributes b/src/libs/3rdparty/winpty/.gitattributes new file mode 100644 index 00000000000..36d4c60f1a7 --- /dev/null +++ b/src/libs/3rdparty/winpty/.gitattributes @@ -0,0 +1,19 @@ +* text=auto +*.bat text eol=crlf +*.c text +*.cc text +*.gyp text +*.gypi text +*.h text +*.ps1 text eol=crlf +*.rst text +*.sh text +*.txt text +.gitignore text +.gitattributes text +Makefile text +configure text + +*.sh eol=lf +configure eol=lf +VERSION.txt eol=lf diff --git a/src/libs/3rdparty/winpty/.gitignore b/src/libs/3rdparty/winpty/.gitignore new file mode 100644 index 00000000000..68c6b47fb3d --- /dev/null +++ b/src/libs/3rdparty/winpty/.gitignore @@ -0,0 +1,16 @@ +*.sln +*.suo +*.vcxproj +*.vcxproj.filters +*.pyc +winpty.sdf +winpty.opensdf +/config.mk +/build +/build-gyp +/build-libpty +/ship/packages +/ship/tmp +/src/Default +/src/Release +/src/gen diff --git a/src/libs/3rdparty/winpty/CMakeLists.txt b/src/libs/3rdparty/winpty/CMakeLists.txt new file mode 100644 index 00000000000..febd4f0ab6f --- /dev/null +++ b/src/libs/3rdparty/winpty/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/src/libs/3rdparty/winpty/LICENSE b/src/libs/3rdparty/winpty/LICENSE new file mode 100644 index 00000000000..246fbe01135 --- /dev/null +++ b/src/libs/3rdparty/winpty/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2011-2016 Ryan Prichard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/src/libs/3rdparty/winpty/README.md b/src/libs/3rdparty/winpty/README.md new file mode 100644 index 00000000000..bc8e7d6e5f4 --- /dev/null +++ b/src/libs/3rdparty/winpty/README.md @@ -0,0 +1,151 @@ +# winpty + +[![Build Status](https://ci.appveyor.com/api/projects/status/69tb9gylsph1ee1x/branch/master?svg=true)](https://ci.appveyor.com/project/rprichard/winpty/branch/master) + +winpty is a Windows software package providing an interface similar to a Unix +pty-master for communicating with Windows console programs. The package +consists of a library (libwinpty) and a tool for Cygwin and MSYS for running +Windows console programs in a Cygwin/MSYS pty. + +The software works by starting the `winpty-agent.exe` process with a new, +hidden console window, which bridges between the console API and terminal +input/output escape codes. It polls the hidden console's screen buffer for +changes and generates a corresponding stream of output. + +The Unix adapter allows running Windows console programs (e.g. CMD, PowerShell, +IronPython, etc.) under `mintty` or Cygwin's `sshd` with +properly-functioning input (e.g. arrow and function keys) and output (e.g. line +buffering). The library could be also useful for writing a non-Cygwin SSH +server. + +## Supported Windows versions + +winpty runs on Windows XP through Windows 10, including server versions. It +can be compiled into either 32-bit or 64-bit binaries. + +## Cygwin/MSYS adapter (`winpty.exe`) + +### Prerequisites + +You need the following to build winpty: + +* A Cygwin or MSYS installation +* GNU make +* A MinGW g++ toolchain capable of compiling C++11 code to build `winpty.dll` + and `winpty-agent.exe` +* A g++ toolchain targeting Cygwin or MSYS to build `winpty.exe` + +Winpty requires two g++ toolchains as it is split into two parts. The +`winpty.dll` and `winpty-agent.exe` binaries interface with the native +Windows command prompt window so they are compiled with the native MinGW +toolchain. The `winpty.exe` binary interfaces with the MSYS/Cygwin terminal so +it is compiled with the MSYS/Cygwin toolchain. + +MinGW appears to be split into two distributions -- MinGW (creates 32-bit +binaries) and MinGW-w64 (creates both 32-bit and 64-bit binaries). Either +one is generally acceptable. + +#### Cygwin packages + +The default g++ compiler for Cygwin targets Cygwin itself, but Cygwin also +packages MinGW-w64 compilers. As of this writing, the necessary packages are: + +* Either `mingw64-i686-gcc-g++` or `mingw64-x86_64-gcc-g++`. Select the + appropriate compiler for your CPU architecture. +* `gcc-g++` +* `make` + +As of this writing (2016-01-23), only the MinGW-w64 compiler is acceptable. +The MinGW compiler (e.g. from the `mingw-gcc-g++` package) is no longer +maintained and is too buggy. + +#### MSYS packages + +For the original MSYS, use the `mingw-get` tool (MinGW Installation Manager), +and select at least these components: + +* `mingw-developer-toolkit` +* `mingw32-base` +* `mingw32-gcc-g++` +* `msys-base` +* `msys-system-builder` + +When running `./configure`, make sure that `mingw32-g++` is in your +`PATH`. It will be in the `C:\MinGW\bin` directory. + +#### MSYS2 packages + +For MSYS2, use `pacman` and install at least these packages: + +* `msys/gcc` +* `mingw32/mingw-w64-i686-gcc` or `mingw64/mingw-w64-x86_64-gcc`. Select + the appropriate compiler for your CPU architecture. +* `make` + +MSYS2 provides three start menu shortcuts for starting MSYS2: + +* MinGW-w64 Win32 Shell +* MinGW-w64 Win64 Shell +* MSYS2 Shell + +To build winpty, use the MinGW-w64 {Win32,Win64} shortcut of the architecture +matching MSYS2. These shortcuts will put the g++ compiler from the +`{mingw32,mingw64}/mingw-w64-{i686,x86_64}-gcc` packages into the `PATH`. + +Alternatively, instead of installing `mingw32/mingw-w64-i686-gcc` or +`mingw64/mingw-w64-x86_64-gcc`, install the `mingw-w64-cross-gcc` and +`mingw-w64-cross-crt-git` packages. These packages install cross-compilers +into `/opt/bin`, and then any of the three shortcuts will work. + +### Building the Unix adapter + +In the project directory, run `./configure`, then `make`, then `make install`. +By default, winpty is installed into `/usr/local`. Pass `PREFIX=` to +`make install` to override this default. + +### Using the Unix adapter + +To run a Windows console program in `mintty` or Cygwin `sshd`, prepend +`winpty` to the command-line: + + $ winpty powershell + Windows PowerShell + Copyright (C) 2009 Microsoft Corporation. All rights reserved. + + PS C:\rprichard\proj\winpty> 10 + 20 + 30 + PS C:\rprichard\proj\winpty> exit + +## Embedding winpty / MSVC compilation + +See `src/include/winpty.h` for the prototypes of functions exported by +`winpty.dll`. + +Only the `winpty.exe` binary uses Cygwin; all the other binaries work without +it and can be compiled with either MinGW or MSVC. To compile using MSVC, +download gyp and run `gyp -I configurations.gypi` in the `src` subdirectory. +This will generate a `winpty.sln` and associated project files. See the +`src/winpty.gyp` and `src/configurations.gypi` files for notes on dealing with +MSVC versions and different architectures. + +Compiling winpty with MSVC currently requires MSVC 2013 or newer. + +## Debugging winpty + +winpty comes with a tool for collecting timestamped debugging output. To use +it: + +1. Run `winpty-debugserver.exe` on the same computer as winpty. +2. Set the `WINPTY_DEBUG` environment variable to `trace` for the + `winpty.exe` process and/or the process using `libwinpty.dll`. + +winpty also recognizes a `WINPTY_SHOW_CONSOLE` environment variable. Set it +to 1 to prevent winpty from hiding the console window. + +## Copyright + +This project is distributed under the MIT license (see the `LICENSE` file in +the project root). + +By submitting a pull request for this project, you agree to license your +contribution under the MIT license to this project. diff --git a/src/libs/3rdparty/winpty/RELEASES.md b/src/libs/3rdparty/winpty/RELEASES.md new file mode 100644 index 00000000000..768cdf90e36 --- /dev/null +++ b/src/libs/3rdparty/winpty/RELEASES.md @@ -0,0 +1,280 @@ +# Next Version + +Input handling changes: + + * Improve Ctrl-C handling with programs that use unprocessed input. (e.g. + Ctrl-C now cancels input with PowerShell on Windows 10.) + [#116](https://github.com/rprichard/winpty/issues/116) + * Fix a theoretical issue with input event ordering. + [#117](https://github.com/rprichard/winpty/issues/117) + * Ctrl/Shift+{Arrow,Home,End} keys now work with IntelliJ. + [#118](https://github.com/rprichard/winpty/issues/118) + +# Version 0.4.3 (2017-05-17) + +Input handling changes: + + * winpty sets `ENHANCED_KEY` for arrow and navigation keys. This fixes an + issue with the Ruby REPL. + [#99](https://github.com/rprichard/winpty/issues/99) + * AltGr keys are handled better now. + [#109](https://github.com/rprichard/winpty/issues/109) + * In `ENABLE_VIRTUAL_TERMINAL_INPUT` mode, when typing Home/End with a + modifier (e.g. Ctrl), winpty now generates an H/F escape sequence like + `^[[1;5F` rather than a 1/4 escape like `^[[4;5~`. + [#114](https://github.com/rprichard/winpty/issues/114) + +Resizing and scraping fixes: + + * winpty now synthesizes a `WINDOW_BUFFER_SIZE_EVENT` event after resizing + the console to better propagate window size changes to console programs. + In particular, this affects WSL and Cygwin. + [#110](https://github.com/rprichard/winpty/issues/110) + * Better handling of resizing for certain full-screen programs, like + WSL less. + [#112](https://github.com/rprichard/winpty/issues/112) + * Hide the cursor if it's currently outside the console window. This change + fixes an issue with Far Manager. + [#113](https://github.com/rprichard/winpty/issues/113) + * winpty now avoids using console fonts smaller than 5px high to improve + half-vs-full-width character handling. See + https://github.com/Microsoft/vscode/issues/19665. + [b4db322010](https://github.com/rprichard/winpty/commit/b4db322010d2d897e6c496fefc4f0ecc9b84c2f3) + +Cygwin/MSYS adapter fix: + + * The way the `winpty` Cygwin/MSYS2 adapter searches for the program to + launch changed. It now resolves symlinks and searches the PATH explicitly. + [#81](https://github.com/rprichard/winpty/issues/81) + [#98](https://github.com/rprichard/winpty/issues/98) + +This release does not include binaries for the old MSYS1 project anymore. +MSYS2 will continue to be supported. See +https://github.com/rprichard/winpty/issues/97. + +# Version 0.4.2 (2017-01-18) + +This release improves WSL support (i.e. Bash-on-Windows): + + * winpty generates more correct input escape sequences for WSL programs that + enable an alternate input mode using DECCKM. This bug affected arrow keys + and Home/End in WSL programs such as `vim`, `mc`, and `less`. + [#90](https://github.com/rprichard/winpty/issues/90) + * winpty now recognizes the `COMMON_LVB_REVERSE_VIDEO` and + `COMMON_LVB_UNDERSCORE` text attributes. The Windows console uses these + attributes to implement the SGR.4(Underline) and SGR.7(Negative) modes in + its VT handling. This change affects WSL pager status bars, man pages, etc. + +The build system no longer has a "version suffix" mechanism, so passing +`VERSION_SUFFIX=` to make or `-D VERSION_SUFFIX=` to gyp now +has no effect. AFAIK, the mechanism was never used publicly. +[67a34b6c03](https://github.com/rprichard/winpty/commit/67a34b6c03557a5c2e0a2bdd502c2210921d8f3e) + +# Version 0.4.1 (2017-01-03) + +Bug fixes: + + * This version fixes a bug where the `winpty-agent.exe` process could read + past the end of a buffer. + [#94](https://github.com/rprichard/winpty/issues/94) + +# Version 0.4.0 (2016-06-28) + +The winpty library has a new API that should be easier for embedding. +[880c00c69e](https://github.com/rprichard/winpty/commit/880c00c69eeca73643ddb576f02c5badbec81f56) + +User-visible changes: + + * winpty now automatically puts the terminal into mouse mode when it detects + that the console has left QuickEdit mode. The `--mouse` option still forces + the terminal into mouse mode. In principle, an option could be added to + suppress terminal mode, but hopefully it won't be necessary. There is a + script in the `misc` subdirectory, `misc/ConinMode.ps1`, that can change + the QuickEdit mode from the command-line. + * winpty now passes keyboard escapes to `bash.exe` in the Windows Subsystem + for Linux. + [#82](https://github.com/rprichard/winpty/issues/82) + +Bug fixes: + + * By default, `winpty.dll` avoids calling `SetProcessWindowStation` within + the calling process. + [#58](https://github.com/rprichard/winpty/issues/58) + * Fixed an uninitialized memory bug that could have crashed winpty. + [#80](https://github.com/rprichard/winpty/issues/80) + * winpty now works better with very large and very small terminal windows. + It resizes the console font according to the number of columns. + [#61](https://github.com/rprichard/winpty/issues/61) + * winpty no longer uses Mark to freeze the console on Windows 10. The Mark + command could interfere with the cursor position, corrupting the data in + the screen buffer. + [#79](https://github.com/rprichard/winpty/issues/79) + +# Version 0.3.0 (2016-05-20) + +User-visible changes: + + * The UNIX adapter is renamed from `console.exe` to `winpty.exe` to be + consistent with MSYS2. The name `winpty.exe` is less likely to conflict + with another program and is easier to search for online (e.g. for someone + unfamiliar with winpty). + * The UNIX adapter now clears the `TERM` variable. + [#43](https://github.com/rprichard/winpty/issues/43) + * An escape character appearing in a console screen buffer cell is converted + to a '?'. + [#47](https://github.com/rprichard/winpty/issues/47) + +Bug fixes: + + * A major bug affecting XP users was fixed. + [#67](https://github.com/rprichard/winpty/issues/67) + * Fixed an incompatibility with ConEmu where winpty hung if ConEmu's + "Process 'start'" feature was enabled. + [#70](https://github.com/rprichard/winpty/issues/70) + * Fixed a bug where `cmd.exe` sometimes printed the message, + `Not enough storage is available to process this command.`. + [#74](https://github.com/rprichard/winpty/issues/74) + +Many changes internally: + + * The codebase is switched from C++03 to C++11 and uses exceptions internally. + No exceptions are thrown across the C APIs defined in `winpty.h`. + * This version drops support for the original MinGW compiler packaged with + Cygwin (`i686-pc-mingw32-g++`). The MinGW-w64 compiler is still supported, + as is the MinGW distributed at mingw.org. Compiling with MSVC now requires + MSVC 2013 or newer. Windows XP is still supported. + [ec3eae8df5](https://github.com/rprichard/winpty/commit/ec3eae8df5bbbb36d7628d168b0815638d122f37) + * Pipe security is improved. winpty works harder to produce unique pipe names + and includes a random component in the name. winpty secures pipes with a + DACL that prevents arbitrary users from connecting to its pipes. winpty now + passes `PIPE_REJECT_REMOTE_CLIENTS` on Vista and up, and it verifies that + the pipe client PID is correct, again on Vista and up. When connecting to a + named pipe, winpty uses the `SECURITY_IDENTIFICATION` flag to restrict + impersonation. Previous versions *should* still be secure. + * `winpty-debugserver.exe` now has an `--everyone` flag that allows capturing + debug output from other users. + * The code now compiles cleanly with MSVC's "Security Development Lifecycle" + (`/SDL`) checks enabled. + +# Version 0.2.2 (2016-02-25) + +Minor bug fixes and enhancements: + + * Fix a bug that generated spurious mouse input records when an incomplete + mouse escape sequence was seen. + * Fix a buffer overflow bug in `winpty-debugserver.exe` affecting messages of + exactly 4096 bytes. + * For MSVC builds, add a `src/configurations.gypi` file that can be included + on the gyp command-line to enable 32-bit and 64-bit builds. + * `winpty-agent --show-input` mode: Flush stdout after each line. + * Makefile builds: generate a `build/winpty.lib` import library to accompany + `build/winpty.dll`. + +# Version 0.2.1 (2015-12-19) + + * The main project source was moved into a `src` directory for better code + organization and to fix + [#51](https://github.com/rprichard/winpty/issues/51). + * winpty recognizes many more escape sequences, including: + * putty/rxvt's F1-F4 keys + [#40](https://github.com/rprichard/winpty/issues/40) + * the Linux virtual console's F1-F5 keys + * the "application numpad" keys (e.g. enabled with DECPAM) + * Fixed handling of Shift-Alt-O and Alt-[. + * Added support for mouse input. The UNIX adapter has a `--mouse` argument + that puts the terminal into mouse mode, but the agent recognizes mouse + input even without the argument. The agent recognizes double-clicks using + Windows' double-click interval setting (i.e. GetDoubleClickTime). + [#57](https://github.com/rprichard/winpty/issues/57) + +Changes to debugging interfaces: + + * The `WINPTY_DEBUG` variable is now a comma-separated list. The old + behavior (i.e. tracing) is enabled with `WINPTY_DEBUG=trace`. + * The UNIX adapter program now has a `--showkey` argument that dumps input + bytes. + * The `winpty-agent.exe` program has a `--show-input` argument that dumps + `INPUT_RECORD` records. (It omits mouse events unless `--with-mouse` is + also specified.) The agent also responds to `WINPTY_DEBUG=trace,input`, + which logs input bytes and synthesized console events, and it responds to + `WINPTY_DEBUG=trace,dump_input_map`, which dumps the internal table of + escape sequences. + +# Version 0.2.0 (2015-11-13) + +No changes to the API, but many small changes to the implementation. The big +changes include: + + * Support for 64-bit Cygwin and MSYS2 + * Support for Windows 10 + * Better Unicode support (especially East Asian languages) + +Details: + + * The `configure` script recognizes 64-bit Cygwin and MSYS2 environments and + selects the appropriate compiler. + * winpty works much better with the upgraded console in Windows 10. The + `conhost.exe` hang can still occur, but only with certain programs, and + is much less likely to occur. With the new console, use Mark instead of + SelectAll, for better performance. + [#31](https://github.com/rprichard/winpty/issues/31) + [#30](https://github.com/rprichard/winpty/issues/30) + [#53](https://github.com/rprichard/winpty/issues/53) + * The UNIX adapter now calls `setlocale(LC_ALL, "")` to set the locale. + * Improved Unicode support. When a console is started with an East Asian code + page, winpty now chooses an East Asian font rather than Consolas / Lucida + Console. Selecting the right font helps synchronize character widths + between the console and terminal. (It's not perfect, though.) + [#41](https://github.com/rprichard/winpty/issues/41) + * winpty now more-or-less works with programs that change the screen buffer + or resize the original screen buffer. If the screen buffer height changes, + winpty switches to a "direct mode", where it makes no effort to track + scrolling. In direct mode, it merely syncs snapshots of the console to the + terminal. Caveats: + * Changing the screen buffer (i.e. `SetConsoleActiveScreenBuffer`) + breaks winpty on Windows 7. This problem can eventually be mitigated, + but never completely fixed, due to Windows 7 bugginess. + * Resizing the original screen buffer can hang `conhost.exe` on Windows 10. + Enabling the legacy console is a workaround. + * If a program changes the screen buffer and then exits, relying on the OS + to restore the original screen buffer, that restoration probably will not + happen with winpty. winpty's behavior can probably be improved here. + * Improved color handling: + * DkGray-on-Black text was previously hiddenly completely. Now it is + output as DkGray, with a fallback to LtGray on terminals that don't + recognize the intense colors. + [#39](https://github.com/rprichard/winpty/issues/39). + * The console is always initialized to LtGray-on-Black, regardless of the + user setting, which matches the console color heuristic, which translates + LtGray-on-Black to "reset SGR parameters." + * Shift-Tab is recognized correctly now. + [#19](https://github.com/rprichard/winpty/issues/19) + * Add a `--version` argument to `winpty-agent.exe` and the UNIX adapter. The + argument reports the nominal version (i.e. the `VERSION.txt`) file, with a + "VERSION_SUFFIX" appended (defaulted to `-dev`), and a git commit hash, if + the `git` command successfully reports a hash during the build. The `git` + command is invoked by either `make` or `gyp`. + * The agent now combines `ReadConsoleOutputW` calls when it polls the console + buffer for changes, which may slightly reduce its CPU overhead. + [#44](https://github.com/rprichard/winpty/issues/44). + * A `gyp` file is added to help compile with MSVC. + * The code can now be compiled as C++11 code, though it isn't by default. + [bde8922e08](https://github.com/rprichard/winpty/commit/bde8922e08c3638e01ecc7b581b676c314163e3c) + * If winpty can't create a new window station, it charges ahead rather than + aborting. This situation might happen if winpty were started from an SSH + session. + * Debugging improvements: + * `WINPTYDBG` is renamed to `WINPTY_DEBUG`, and a new `WINPTY_SHOW_CONSOLE` + variable keeps the underlying console visible. + * A `winpty-debugserver.exe` program is built and shipped by default. It + collects the trace output enabled with `WINPTY_DEBUG`. + * The `Makefile` build of winpty now compiles `winpty-agent.exe` and + `winpty.dll` with -O2. + +# Version 0.1.1 (2012-07-28) + +Minor bugfix release. + +# Version 0.1 (2012-04-17) + +Initial release. diff --git a/src/libs/3rdparty/winpty/VERSION.txt b/src/libs/3rdparty/winpty/VERSION.txt new file mode 100644 index 00000000000..5d47ff8c45a --- /dev/null +++ b/src/libs/3rdparty/winpty/VERSION.txt @@ -0,0 +1 @@ +0.4.4-dev diff --git a/src/libs/3rdparty/winpty/appveyor.yml b/src/libs/3rdparty/winpty/appveyor.yml new file mode 100644 index 00000000000..a9e8726fc13 --- /dev/null +++ b/src/libs/3rdparty/winpty/appveyor.yml @@ -0,0 +1,16 @@ +image: Visual Studio 2015 + +init: + - C:\msys64\usr\bin\bash --login -c "pacman -S --needed --noconfirm --noprogressbar msys/make msys/tar msys/gcc mingw-w64-cross-toolchain" + - C:\cygwin\setup-x86 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make + - C:\cygwin64\setup-x86_64 -q -P mingw64-i686-gcc-g++,mingw64-x86_64-gcc-g++,make + +build_script: + - C:\Python27-x64\python.exe ship\ship.py --kind msys2 --arch x64 --syspath C:\msys64 + - C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch ia32 --syspath C:\cygwin + - C:\Python27-x64\python.exe ship\ship.py --kind cygwin --arch x64 --syspath C:\cygwin64 + - C:\Python27-x64\python.exe ship\make_msvc_package.py + +artifacts: + - path: ship\packages\*.tar.gz + - path: ship\packages\*.zip diff --git a/src/libs/3rdparty/winpty/configure b/src/libs/3rdparty/winpty/configure new file mode 100644 index 00000000000..6d37d65b091 --- /dev/null +++ b/src/libs/3rdparty/winpty/configure @@ -0,0 +1,167 @@ +#!/bin/bash +# +# Copyright (c) 2011-2015 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# +# findTool(desc, commandList) +# +# Searches commandLine for the first command in the PATH and returns it. +# Prints an error and aborts the script if no match is found. +# +FINDTOOL_OUT="" +function findTool { + DESC=$1 + OPTIONS=$2 + for CMD in ${OPTIONS}; do + if (which $CMD &>/dev/null) then + echo "Found $DESC: $CMD" + FINDTOOL_OUT="$CMD" + return + fi + done + echo "Error: could not find $DESC. One of these should be in your PATH:" + for CMD in ${OPTIONS}; do + echo " * $CMD" + done + exit 1 +} + +IS_CYGWIN=0 +IS_MSYS1=0 +IS_MSYS2=0 + +# Link parts of the Cygwin binary statically to aid in redistribution? The +# binary still links dynamically against the main DLL. The MinGW binaries are +# also statically linked and therefore depend only on Windows DLLs. I started +# linking the Cygwin/MSYS binary statically, because G++ 4.7 changed the +# Windows C++ ABI. +UNIX_LDFLAGS_STATIC='-static -static-libgcc -static-libstdc++' + +# Detect the environment -- Cygwin or MSYS. +case $(uname -s) in + CYGWIN*) + echo 'uname -s identifies a Cygwin environment.' + IS_CYGWIN=1 + case $(uname -m) in + i686) + echo 'uname -m identifies an i686 environment.' + UNIX_CXX=i686-pc-cygwin-g++ + MINGW_CXX=i686-w64-mingw32-g++ + ;; + x86_64) + echo 'uname -m identifies an x86_64 environment.' + UNIX_CXX=x86_64-pc-cygwin-g++ + MINGW_CXX=x86_64-w64-mingw32-g++ + ;; + *) + echo 'Error: uname -m did not match either i686 or x86_64.' + exit 1 + ;; + esac + ;; + MSYS*|MINGW*) + # MSYS2 notes: + # - MSYS2 offers two shortcuts to open an environment: + # - MinGW-w64 Win32 Shell. This env reports a `uname -s` of + # MINGW32_NT-6.1 on 32-bit Win7. The MinGW-w64 compiler + # (i686-w64-mingw32-g++.exe) is in the PATH. + # - MSYS2 Shell. `uname -s` instead reports MSYS_NT-6.1. + # The i686-w64-mingw32-g++ compiler is not in the PATH. + # - MSYS2 appears to use MinGW-w64, not the older mingw.org. + # MSYS notes: + # - `uname -s` is always MINGW32_NT-6.1 on Win7. + echo 'uname -s identifies an MSYS/MSYS2 environment.' + case $(uname -m) in + i686) + echo 'uname -m identifies an i686 environment.' + UNIX_CXX=i686-pc-msys-g++ + if echo "$(uname -r)" | grep '^1[.]' > /dev/null; then + # The MSYS-targeting compiler for the original 32-bit-only + # MSYS does not recognize the -static-libstdc++ flag, and + # it does not work with -static, because it tries to link + # statically with the core MSYS library and fails. + # + # Distinguish between the two using the major version + # number of `uname -r`: + # + # MSYS uname -r: 1.0.18(0.48/3/2) + # MSYS2 uname -r: 2.0.0(0.284/5/3) + # + # This is suboptimal because MSYS2 is not actually the + # second version of MSYS--it's a brand-new fork of Cygwin. + # + IS_MSYS1=1 + UNIX_LDFLAGS_STATIC= + MINGW_CXX=mingw32-g++ + else + IS_MSYS2=1 + MINGW_CXX=i686-w64-mingw32-g++.exe + fi + ;; + x86_64) + echo 'uname -m identifies an x86_64 environment.' + IS_MSYS2=1 + UNIX_CXX=x86_64-pc-msys-g++ + MINGW_CXX=x86_64-w64-mingw32-g++ + ;; + *) + echo 'Error: uname -m did not match either i686 or x86_64.' + exit 1 + ;; + esac + ;; + *) + echo 'Error: uname -s did not match either CYGWIN* or MINGW*.' + exit 1 + ;; +esac + +# Search the PATH and pick the first match. +findTool "Cygwin/MSYS G++ compiler" "$UNIX_CXX" +UNIX_CXX=$FINDTOOL_OUT +findTool "MinGW G++ compiler" "$MINGW_CXX" +MINGW_CXX=$FINDTOOL_OUT + +# Write config files. +echo Writing config.mk +echo UNIX_CXX=$UNIX_CXX > config.mk +echo UNIX_LDFLAGS_STATIC=$UNIX_LDFLAGS_STATIC >> config.mk +echo MINGW_CXX=$MINGW_CXX >> config.mk + +if test $IS_MSYS1 = 1; then + echo UNIX_CXXFLAGS += -DWINPTY_TARGET_MSYS1 >> config.mk + # The MSYS1 MinGW compiler has a bug that prevents inclusion of algorithm + # and math.h in normal C++11 mode. The workaround is to enable the gnu++11 + # mode instead. The bug was fixed on 2015-07-31, but as of 2016-02-26, the + # fix apparently hasn't been released. See + # http://ehc.ac/p/mingw/bugs/2250/. + echo MINGW_ENABLE_CXX11_FLAG := -std=gnu++11 >> config.mk +fi + +if test -d .git -a -f .git/HEAD -a -f .git/index && git rev-parse HEAD >&/dev/null; then + echo "Commit info: git" + echo 'COMMIT_HASH = $(shell git rev-parse HEAD)' >> config.mk + echo 'COMMIT_HASH_DEP := config.mk .git/HEAD .git/index' >> config.mk +else + echo "Commit info: none" + echo 'COMMIT_HASH := none' >> config.mk + echo 'COMMIT_HASH_DEP := config.mk' >> config.mk +fi diff --git a/src/libs/3rdparty/winpty/misc/.gitignore b/src/libs/3rdparty/winpty/misc/.gitignore new file mode 100644 index 00000000000..23751645fa1 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/.gitignore @@ -0,0 +1,2 @@ +*.exe +UnixEcho \ No newline at end of file diff --git a/src/libs/3rdparty/winpty/misc/BufferResizeTests.cc b/src/libs/3rdparty/winpty/misc/BufferResizeTests.cc new file mode 100644 index 00000000000..a5bb074826f --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/BufferResizeTests.cc @@ -0,0 +1,90 @@ +#include +#include + +#include "TestUtil.cc" + +void dumpInfoToTrace() { + CONSOLE_SCREEN_BUFFER_INFO info; + assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)); + trace("win=(%d,%d,%d,%d)", + (int)info.srWindow.Left, + (int)info.srWindow.Top, + (int)info.srWindow.Right, + (int)info.srWindow.Bottom); + trace("buf=(%d,%d)", + (int)info.dwSize.X, + (int)info.dwSize.Y); + trace("cur=(%d,%d)", + (int)info.dwCursorPosition.X, + (int)info.dwCursorPosition.Y); +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + setWindowPos(0, 0, 1, 1); + + if (false) { + // Reducing the buffer height can move the window up. + setBufferSize(80, 25); + setWindowPos(0, 20, 80, 5); + Sleep(2000); + setBufferSize(80, 10); + } + + if (false) { + // Reducing the buffer height moves the window up and the buffer + // contents up too. + setBufferSize(80, 25); + setWindowPos(0, 20, 80, 5); + setCursorPos(0, 20); + printf("TEST1\nTEST2\nTEST3\nTEST4\n"); + fflush(stdout); + Sleep(2000); + setBufferSize(80, 10); + } + + if (false) { + // Reducing the buffer width can move the window left. + setBufferSize(80, 25); + setWindowPos(40, 0, 40, 25); + Sleep(2000); + setBufferSize(60, 25); + } + + if (false) { + // Sometimes the buffer contents are shifted up; sometimes they're + // shifted down. It seems to depend on the cursor position? + + // setBufferSize(80, 25); + // setWindowPos(0, 20, 80, 5); + // setCursorPos(0, 20); + // printf("TESTa\nTESTb\nTESTc\nTESTd\nTESTe"); + // fflush(stdout); + // setCursorPos(0, 0); + // printf("TEST1\nTEST2\nTEST3\nTEST4\nTEST5"); + // fflush(stdout); + // setCursorPos(0, 24); + // Sleep(5000); + // setBufferSize(80, 24); + + setBufferSize(80, 20); + setWindowPos(0, 10, 80, 10); + setCursorPos(0, 18); + + printf("TEST1\nTEST2"); + fflush(stdout); + setCursorPos(0, 18); + + Sleep(2000); + setBufferSize(80, 18); + } + + dumpInfoToTrace(); + Sleep(30000); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc b/src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc new file mode 100644 index 00000000000..701a2cb4a3c --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ChangeScreenBuffer.cc @@ -0,0 +1,53 @@ +// A test program for CreateConsoleScreenBuffer / SetConsoleActiveScreenBuffer +// + +#include +#include +#include +#include +#include + +#include "TestUtil.cc" + +int main() +{ + HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE childBuffer = CreateConsoleScreenBuffer( + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + + SetConsoleActiveScreenBuffer(childBuffer); + + while (true) { + char buf[1024]; + CONSOLE_SCREEN_BUFFER_INFO info; + + assert(GetConsoleScreenBufferInfo(origBuffer, &info)); + trace("child.size=(%d,%d)", (int)info.dwSize.X, (int)info.dwSize.Y); + trace("child.cursor=(%d,%d)", (int)info.dwCursorPosition.X, (int)info.dwCursorPosition.Y); + trace("child.window=(%d,%d,%d,%d)", + (int)info.srWindow.Left, (int)info.srWindow.Top, + (int)info.srWindow.Right, (int)info.srWindow.Bottom); + trace("child.maxSize=(%d,%d)", (int)info.dwMaximumWindowSize.X, (int)info.dwMaximumWindowSize.Y); + + int ch = getch(); + sprintf(buf, "%02x\n", ch); + DWORD actual = 0; + WriteFile(childBuffer, buf, strlen(buf), &actual, NULL); + if (ch == 0x1b/*ESC*/ || ch == 0x03/*CTRL-C*/) + break; + + if (ch == 'b') { + setBufferSize(origBuffer, 40, 25); + } else if (ch == 'w') { + setWindowPos(origBuffer, 1, 1, 38, 23); + } else if (ch == 'c') { + setCursorPos(origBuffer, 10, 10); + } + } + + SetConsoleActiveScreenBuffer(origBuffer); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ClearConsole.cc b/src/libs/3rdparty/winpty/misc/ClearConsole.cc new file mode 100644 index 00000000000..f95f8c84caa --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ClearConsole.cc @@ -0,0 +1,72 @@ +/* + * Demonstrates that console clearing sets each cell's character to SP, not + * NUL, and it sets the attribute of each cell to the current text attribute. + * + * This confirms the MSDN instruction in the "Clearing the Screen" article. + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682022(v=vs.85).aspx + * It advises using GetConsoleScreenBufferInfo to get the current text + * attribute, then FillConsoleOutputCharacter and FillConsoleOutputAttribute to + * write to the console buffer. + */ + +#include + +#include +#include +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + + SetConsoleTextAttribute(conout, 0x24); + system("cls"); + + setWindowPos(0, 0, 1, 1); + setBufferSize(80, 25); + setWindowPos(0, 0, 80, 25); + + CHAR_INFO buf; + COORD bufSize = { 1, 1 }; + COORD bufCoord = { 0, 0 }; + SMALL_RECT rect = { 5, 5, 5, 5 }; + BOOL ret; + DWORD actual; + COORD writeCoord = { 5, 5 }; + + // After cls, each cell's character is a space, and its attributes are the + // default text attributes. + ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); + assert(ret && buf.Char.UnicodeChar == L' ' && buf.Attributes == 0x24); + + // Nevertheless, it is possible to change a cell to NUL. + ret = FillConsoleOutputCharacterW(conout, L'\0', 1, writeCoord, &actual); + assert(ret && actual == 1); + ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); + assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0x24); + + // As well as a 0 attribute. (As one would expect, the cell is + // black-on-black.) + ret = FillConsoleOutputAttribute(conout, 0, 1, writeCoord, &actual); + assert(ret && actual == 1); + ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); + assert(ret && buf.Char.UnicodeChar == L'\0' && buf.Attributes == 0); + ret = FillConsoleOutputCharacterW(conout, L'X', 1, writeCoord, &actual); + assert(ret && actual == 1); + ret = ReadConsoleOutputW(conout, &buf, bufSize, bufCoord, &rect); + assert(ret && buf.Char.UnicodeChar == L'X' && buf.Attributes == 0); + + // The 'X' is invisible. + countDown(3); + + ret = FillConsoleOutputAttribute(conout, 0x42, 1, writeCoord, &actual); + assert(ret && actual == 1); + + countDown(5); +} diff --git a/src/libs/3rdparty/winpty/misc/ConinMode.cc b/src/libs/3rdparty/winpty/misc/ConinMode.cc new file mode 100644 index 00000000000..1e1428d8b0c --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ConinMode.cc @@ -0,0 +1,117 @@ +#include + +#include +#include +#include + +#include +#include + +static HANDLE getConin() { + HANDLE conin = GetStdHandle(STD_INPUT_HANDLE); + if (conin == INVALID_HANDLE_VALUE) { + fprintf(stderr, "error: cannot get stdin\n"); + exit(1); + } + return conin; +} + +static DWORD getConsoleMode() { + DWORD mode = 0; + if (!GetConsoleMode(getConin(), &mode)) { + fprintf(stderr, "error: GetConsoleMode failed (is stdin a console?)\n"); + exit(1); + } + return mode; +} + +static void setConsoleMode(DWORD mode) { + if (!SetConsoleMode(getConin(), mode)) { + fprintf(stderr, "error: SetConsoleMode failed (is stdin a console?)\n"); + exit(1); + } +} + +static long parseInt(const std::string &s) { + errno = 0; + char *endptr = nullptr; + long result = strtol(s.c_str(), &endptr, 0); + if (errno != 0 || !endptr || *endptr != '\0') { + fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str()); + exit(1); + } + return result; +} + +static void usage() { + printf("Usage: ConinMode [verb] [options]\n"); + printf("Verbs:\n"); + printf(" [info] Dumps info about mode flags.\n"); + printf(" get Prints the mode DWORD.\n"); + printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n"); + printf(" set VALUE MASK\n"); + printf(" Same as `set VALUE`, but only alters the bits in MASK.\n"); + exit(1); +} + +struct { + const char *name; + DWORD value; +} kInputFlags[] = { + "ENABLE_PROCESSED_INPUT", ENABLE_PROCESSED_INPUT, // 0x0001 + "ENABLE_LINE_INPUT", ENABLE_LINE_INPUT, // 0x0002 + "ENABLE_ECHO_INPUT", ENABLE_ECHO_INPUT, // 0x0004 + "ENABLE_WINDOW_INPUT", ENABLE_WINDOW_INPUT, // 0x0008 + "ENABLE_MOUSE_INPUT", ENABLE_MOUSE_INPUT, // 0x0010 + "ENABLE_INSERT_MODE", ENABLE_INSERT_MODE, // 0x0020 + "ENABLE_QUICK_EDIT_MODE", ENABLE_QUICK_EDIT_MODE, // 0x0040 + "ENABLE_EXTENDED_FLAGS", ENABLE_EXTENDED_FLAGS, // 0x0080 + "ENABLE_VIRTUAL_TERMINAL_INPUT", 0x0200/*ENABLE_VIRTUAL_TERMINAL_INPUT*/, // 0x0200 +}; + +int main(int argc, char *argv[]) { + std::vector args; + for (size_t i = 1; i < argc; ++i) { + args.push_back(argv[i]); + } + + if (args.empty() || args.size() == 1 && args[0] == "info") { + DWORD mode = getConsoleMode(); + printf("mode: 0x%lx\n", mode); + for (const auto &flag : kInputFlags) { + printf("%-29s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off"); + mode &= ~flag.value; + } + for (int i = 0; i < 32; ++i) { + if (mode & (1u << i)) { + printf("Unrecognized flag: %04x\n", (1u << i)); + } + } + return 0; + } + + const auto verb = args[0]; + + if (verb == "set") { + if (args.size() == 2) { + const DWORD newMode = parseInt(args[1]); + setConsoleMode(newMode); + } else if (args.size() == 3) { + const DWORD mode = parseInt(args[1]); + const DWORD mask = parseInt(args[2]); + const int newMode = (getConsoleMode() & ~mask) | (mode & mask); + setConsoleMode(newMode); + } else { + usage(); + } + } else if (verb == "get") { + if (args.size() != 1) { + usage(); + } + printf("0x%lx\n", getConsoleMode()); + } else { + usage(); + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ConinMode.ps1 b/src/libs/3rdparty/winpty/misc/ConinMode.ps1 new file mode 100644 index 00000000000..ecfe8f039e4 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ConinMode.ps1 @@ -0,0 +1,116 @@ +# +# PowerShell script for controlling the console QuickEdit and InsertMode flags. +# +# Turn QuickEdit off to interact with mouse-driven console programs. +# +# Usage: +# +# powershell .\ConinMode.ps1 [Options] +# +# Options: +# -QuickEdit [on/off] +# -InsertMode [on/off] +# -Mode [integer] +# + +param ( + [ValidateSet("on", "off")][string] $QuickEdit, + [ValidateSet("on", "off")][string] $InsertMode, + [int] $Mode +) + +$signature = @' +[DllImport("kernel32.dll", SetLastError = true)] +public static extern IntPtr GetStdHandle(int nStdHandle); + +[DllImport("kernel32.dll", SetLastError = true)] +public static extern uint GetConsoleMode( + IntPtr hConsoleHandle, + out uint lpMode); + +[DllImport("kernel32.dll", SetLastError = true)] +public static extern uint SetConsoleMode( + IntPtr hConsoleHandle, + uint dwMode); + +public const int STD_INPUT_HANDLE = -10; +public const int ENABLE_INSERT_MODE = 0x0020; +public const int ENABLE_QUICK_EDIT_MODE = 0x0040; +public const int ENABLE_EXTENDED_FLAGS = 0x0080; +'@ + +$WinAPI = Add-Type -MemberDefinition $signature ` + -Name WinAPI -Namespace ConinModeScript ` + -PassThru + +function GetConIn { + $ret = $WinAPI::GetStdHandle($WinAPI::STD_INPUT_HANDLE) + if ($ret -eq -1) { + throw "error: cannot get stdin" + } + return $ret +} + +function GetConsoleMode { + $conin = GetConIn + $mode = 0 + $ret = $WinAPI::GetConsoleMode($conin, [ref]$mode) + if ($ret -eq 0) { + throw "GetConsoleMode failed (is stdin a console?)" + } + return $mode +} + +function SetConsoleMode($mode) { + $conin = GetConIn + $ret = $WinAPI::SetConsoleMode($conin, $mode) + if ($ret -eq 0) { + throw "SetConsoleMode failed (is stdin a console?)" + } +} + +$oldMode = GetConsoleMode +$newMode = $oldMode +$doingSomething = $false + +if ($PSBoundParameters.ContainsKey("Mode")) { + $newMode = $Mode + $doingSomething = $true +} + +if ($QuickEdit + $InsertMode -ne "") { + if (!($newMode -band $WinAPI::ENABLE_EXTENDED_FLAGS)) { + # We can't enable an extended flag without overwriting the existing + # QuickEdit/InsertMode flags. AFAICT, there is no way to query their + # existing values, so at least we can choose sensible defaults. + $newMode = $newMode -bor $WinAPI::ENABLE_EXTENDED_FLAGS + $newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE + $newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE + $doingSomething = $true + } +} + +if ($QuickEdit -eq "on") { + $newMode = $newMode -bor $WinAPI::ENABLE_QUICK_EDIT_MODE + $doingSomething = $true +} elseif ($QuickEdit -eq "off") { + $newMode = $newMode -band (-bnot $WinAPI::ENABLE_QUICK_EDIT_MODE) + $doingSomething = $true +} + +if ($InsertMode -eq "on") { + $newMode = $newMode -bor $WinAPI::ENABLE_INSERT_MODE + $doingSomething = $true +} elseif ($InsertMode -eq "off") { + $newMode = $newMode -band (-bnot $WinAPI::ENABLE_INSERT_MODE) + $doingSomething = $true +} + +if ($doingSomething) { + echo "old mode: $oldMode" + SetConsoleMode $newMode + $newMode = GetConsoleMode + echo "new mode: $newMode" +} else { + echo "mode: $oldMode" +} diff --git a/src/libs/3rdparty/winpty/misc/ConoutMode.cc b/src/libs/3rdparty/winpty/misc/ConoutMode.cc new file mode 100644 index 00000000000..100e0c7bea9 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ConoutMode.cc @@ -0,0 +1,113 @@ +#include + +#include +#include +#include + +#include +#include + +static HANDLE getConout() { + HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + if (conout == INVALID_HANDLE_VALUE) { + fprintf(stderr, "error: cannot get stdout\n"); + exit(1); + } + return conout; +} + +static DWORD getConsoleMode() { + DWORD mode = 0; + if (!GetConsoleMode(getConout(), &mode)) { + fprintf(stderr, "error: GetConsoleMode failed (is stdout a console?)\n"); + exit(1); + } + return mode; +} + +static void setConsoleMode(DWORD mode) { + if (!SetConsoleMode(getConout(), mode)) { + fprintf(stderr, "error: SetConsoleMode failed (is stdout a console?)\n"); + exit(1); + } +} + +static long parseInt(const std::string &s) { + errno = 0; + char *endptr = nullptr; + long result = strtol(s.c_str(), &endptr, 0); + if (errno != 0 || !endptr || *endptr != '\0') { + fprintf(stderr, "error: could not parse integral argument '%s'\n", s.c_str()); + exit(1); + } + return result; +} + +static void usage() { + printf("Usage: ConoutMode [verb] [options]\n"); + printf("Verbs:\n"); + printf(" [info] Dumps info about mode flags.\n"); + printf(" get Prints the mode DWORD.\n"); + printf(" set VALUE Sets the mode to VALUE, which can be decimal, hex, or octal.\n"); + printf(" set VALUE MASK\n"); + printf(" Same as `set VALUE`, but only alters the bits in MASK.\n"); + exit(1); +} + +struct { + const char *name; + DWORD value; +} kOutputFlags[] = { + "ENABLE_PROCESSED_OUTPUT", ENABLE_PROCESSED_OUTPUT, // 0x0001 + "ENABLE_WRAP_AT_EOL_OUTPUT", ENABLE_WRAP_AT_EOL_OUTPUT, // 0x0002 + "ENABLE_VIRTUAL_TERMINAL_PROCESSING", 0x0004/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/, // 0x0004 + "DISABLE_NEWLINE_AUTO_RETURN", 0x0008/*DISABLE_NEWLINE_AUTO_RETURN*/, // 0x0008 + "ENABLE_LVB_GRID_WORLDWIDE", 0x0010/*ENABLE_LVB_GRID_WORLDWIDE*/, //0x0010 +}; + +int main(int argc, char *argv[]) { + std::vector args; + for (size_t i = 1; i < argc; ++i) { + args.push_back(argv[i]); + } + + if (args.empty() || args.size() == 1 && args[0] == "info") { + DWORD mode = getConsoleMode(); + printf("mode: 0x%lx\n", mode); + for (const auto &flag : kOutputFlags) { + printf("%-34s 0x%04lx %s\n", flag.name, flag.value, flag.value & mode ? "ON" : "off"); + mode &= ~flag.value; + } + for (int i = 0; i < 32; ++i) { + if (mode & (1u << i)) { + printf("Unrecognized flag: %04x\n", (1u << i)); + } + } + return 0; + } + + const auto verb = args[0]; + + if (verb == "set") { + if (args.size() == 2) { + const DWORD newMode = parseInt(args[1]); + setConsoleMode(newMode); + } else if (args.size() == 3) { + const DWORD mode = parseInt(args[1]); + const DWORD mask = parseInt(args[2]); + const int newMode = (getConsoleMode() & ~mask) | (mode & mask); + setConsoleMode(newMode); + } else { + usage(); + } + } else if (verb == "get") { + if (args.size() != 1) { + usage(); + } + printf("0x%lx\n", getConsoleMode()); + } else { + usage(); + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/DebugClient.py b/src/libs/3rdparty/winpty/misc/DebugClient.py new file mode 100644 index 00000000000..cd12df8924a --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/DebugClient.py @@ -0,0 +1,42 @@ +#!python +# Run with native CPython. Needs pywin32 extensions. + +# Copyright (c) 2011-2012 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import winerror +import win32pipe +import win32file +import win32api +import sys +import pywintypes +import time + +if len(sys.argv) != 2: + print("Usage: %s message" % sys.argv[0]) + sys.exit(1) + +message = "[%05.3f %s]: %s" % (time.time() % 100000, sys.argv[0], sys.argv[1]) + +win32pipe.CallNamedPipe( + "\\\\.\\pipe\\DebugServer", + message.encode(), + 16, + win32pipe.NMPWAIT_WAIT_FOREVER) diff --git a/src/libs/3rdparty/winpty/misc/DebugServer.py b/src/libs/3rdparty/winpty/misc/DebugServer.py new file mode 100644 index 00000000000..3fc068bae70 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/DebugServer.py @@ -0,0 +1,63 @@ +#!python +# +# Run with native CPython. Needs pywin32 extensions. + +# Copyright (c) 2011-2012 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import win32pipe +import win32api +import win32file +import time +import threading +import sys + +# A message may not be larger than this size. +MSG_SIZE=4096 + +serverPipe = win32pipe.CreateNamedPipe( + "\\\\.\\pipe\\DebugServer", + win32pipe.PIPE_ACCESS_DUPLEX, + win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE, + win32pipe.PIPE_UNLIMITED_INSTANCES, + MSG_SIZE, + MSG_SIZE, + 10 * 1000, + None) +while True: + win32pipe.ConnectNamedPipe(serverPipe, None) + (ret, data) = win32file.ReadFile(serverPipe, MSG_SIZE) + print(data.decode()) + sys.stdout.flush() + + # The client uses CallNamedPipe to send its message. CallNamedPipe waits + # for a reply message. If I send a reply, however, using WriteFile, then + # sometimes WriteFile fails with: + # pywintypes.error: (232, 'WriteFile', 'The pipe is being closed.') + # I can't figure out how to write a strictly correct pipe server, but if + # I comment out the WriteFile line, then everything seems to work. I + # think the DisconnectNamedPipe call aborts the client's CallNamedPipe + # call normally. + + try: + win32file.WriteFile(serverPipe, b'OK') + except: + pass + win32pipe.DisconnectNamedPipe(serverPipe) diff --git a/src/libs/3rdparty/winpty/misc/DumpLines.py b/src/libs/3rdparty/winpty/misc/DumpLines.py new file mode 100644 index 00000000000..40049961b5c --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/DumpLines.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +import sys + +for i in range(1, int(sys.argv[1]) + 1): + print i, "X" * 78 diff --git a/src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt b/src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt new file mode 100644 index 00000000000..37914dac268 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/EnableExtendedFlags.txt @@ -0,0 +1,46 @@ +Note regarding ENABLE_EXTENDED_FLAGS (2016-05-30) + +There is a complicated interaction between the ENABLE_EXTENDED_FLAGS flag +and the ENABLE_QUICK_EDIT_MODE and ENABLE_INSERT_MODE flags (presumably for +backwards compatibility?). I studied the behavior on Windows 7 and Windows +10, with both the old and new consoles, and I didn't see any differences +between versions. Here's what I seemed to observe: + + - The console has three flags internally: + - QuickEdit + - InsertMode + - ExtendedFlags + + - SetConsoleMode psuedocode: + void SetConsoleMode(..., DWORD mode) { + ExtendedFlags = (mode & (ENABLE_EXTENDED_FLAGS + | ENABLE_QUICK_EDIT_MODE + | ENABLE_INSERT_MODE )) != 0; + if (ExtendedFlags) { + QuickEdit = (mode & ENABLE_QUICK_EDIT_MODE) != 0; + InsertMode = (mode & ENABLE_INSERT_MODE) != 0; + } + } + + - Setting QuickEdit or InsertMode from the properties dialog GUI does not + affect the ExtendedFlags setting -- it simply toggles the one flag. + + - GetConsoleMode psuedocode: + GetConsoleMode(..., DWORD *result) { + if (ExtendedFlags) { + *result |= ENABLE_EXTENDED_FLAGS; + if (QuickEdit) { *result |= ENABLE_QUICK_EDIT_MODE; } + if (InsertMode) { *result |= ENABLE_INSERT_MODE; } + } + } + +Effectively, the ExtendedFlags flags controls whether the other two flags +are visible/controlled by the user application. If they aren't visible, +though, there is no way for the user application to make them visible, +except by overwriting their values! Calling SetConsoleMode with just +ENABLE_EXTENDED_FLAGS would clear the extended flags we want to read. + +Consequently, if a program temporarily alters the QuickEdit flag (e.g. to +enable mouse input), it cannot restore the original values of the QuickEdit +and InsertMode flags, UNLESS every other console program cooperates by +keeping the ExtendedFlags flag set. diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt new file mode 100644 index 00000000000..067bd3824a8 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Consolas.txt @@ -0,0 +1,528 @@ +================================== +Code Page 437, Consolas font +================================== + +Options: -face "Consolas" -family 0x36 +Chars: A2 A3 2014 3044 30FC 4000 + +FontSurvey "-face \"Consolas\" -family 0x36" + +Windows 7 +--------- + +Size 1: 1,3 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 1,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 2,5 BAD (HHHHHH) +Size 6: 3,6 BAD (HHHHHH) +Size 7: 3,6 BAD (HHHHHH) +Size 8: 4,8 BAD (HHHHHH) +Size 9: 4,9 BAD (HHHHHH) +Size 10: 5,10 BAD (HHHHHH) +Size 11: 5,11 BAD (HHHHHH) +Size 12: 6,12 BAD (HHHHHH) +Size 13: 6,13 BAD (HHHHHH) +Size 14: 7,14 BAD (HHHHHH) +Size 15: 7,15 BAD (HHHHHH) +Size 16: 8,16 BAD (HHHHHH) +Size 17: 8,17 BAD (HHHHHH) +Size 18: 8,18 BAD (HHHHHH) +Size 19: 9,19 BAD (HHHHHH) +Size 20: 9,20 BAD (HHHHHH) +Size 21: 10,22 BAD (HHHHHH) +Size 22: 10,22 BAD (HHHHHH) +Size 23: 11,23 BAD (HHHHHH) +Size 24: 11,24 BAD (HHHHHH) +Size 25: 12,25 BAD (HHHHHH) +Size 26: 12,26 BAD (HHHHHH) +Size 27: 13,27 BAD (HHHHHH) +Size 28: 13,28 BAD (HHHHHH) +Size 29: 14,29 BAD (HHHHHH) +Size 30: 14,30 BAD (HHHHHH) +Size 31: 15,31 BAD (HHHHHH) +Size 32: 15,32 BAD (HHHHHH) +Size 33: 15,33 BAD (HHHHHH) +Size 34: 16,34 BAD (HHHHHH) +Size 35: 16,36 BAD (HHHHHH) +Size 36: 17,36 BAD (HHHHHH) +Size 37: 17,37 BAD (HHHHHH) +Size 38: 18,38 BAD (HHHHHH) +Size 39: 18,39 BAD (HHHHHH) +Size 40: 19,40 BAD (HHHHHH) +Size 41: 19,41 BAD (HHHHHH) +Size 42: 20,42 BAD (HHHHHH) +Size 43: 20,43 BAD (HHHHHH) +Size 44: 21,44 BAD (HHHHHH) +Size 45: 21,45 BAD (HHHHHH) +Size 46: 22,46 BAD (HHHHHH) +Size 47: 22,47 BAD (HHHHHH) +Size 48: 23,48 BAD (HHHHHH) +Size 49: 23,49 BAD (HHHHHH) +Size 50: 23,50 BAD (HHHHHH) +Size 51: 24,51 BAD (HHHHHH) +Size 52: 24,52 BAD (HHHHHH) +Size 53: 25,53 BAD (HHHHHH) +Size 54: 25,54 BAD (HHHHHH) +Size 55: 26,55 BAD (HHHHHH) +Size 56: 26,56 BAD (HHHHHH) +Size 57: 27,57 BAD (HHHHHH) +Size 58: 27,58 BAD (HHHHHH) +Size 59: 28,59 BAD (HHHHHH) +Size 60: 28,60 BAD (HHHHHH) +Size 61: 29,61 BAD (HHHHHH) +Size 62: 29,62 BAD (HHHHHH) +Size 63: 30,64 BAD (HHHHHH) +Size 64: 30,64 BAD (HHHHHH) +Size 65: 31,65 BAD (HHHHHH) +Size 66: 31,66 BAD (HHHHHH) +Size 67: 31,67 BAD (HHHHHH) +Size 68: 32,68 BAD (HHHHHH) +Size 69: 32,69 BAD (HHHHHH) +Size 70: 33,70 BAD (HHHHHH) +Size 71: 33,71 BAD (HHHHHH) +Size 72: 34,72 BAD (HHHHHH) +Size 73: 34,73 BAD (HHHHHH) +Size 74: 35,74 BAD (HHHHHH) +Size 75: 35,75 BAD (HHHHHH) +Size 76: 36,76 BAD (HHHHHH) +Size 77: 36,77 BAD (HHHHHH) +Size 78: 37,78 BAD (HHHHHH) +Size 79: 37,79 BAD (HHHHHH) +Size 80: 38,80 BAD (HHHHHH) +Size 81: 38,81 BAD (HHHHHH) +Size 82: 39,82 BAD (HHHHHH) +Size 83: 39,83 BAD (HHHHHH) +Size 84: 39,84 BAD (HHHHHH) +Size 85: 40,85 BAD (HHHHHH) +Size 86: 40,86 BAD (HHHHHH) +Size 87: 41,87 BAD (HHHHHH) +Size 88: 41,88 BAD (HHHHHH) +Size 89: 42,89 BAD (HHHHHH) +Size 90: 42,90 BAD (HHHHHH) +Size 91: 43,91 BAD (HHHHHH) +Size 92: 43,92 BAD (HHHHHH) +Size 93: 44,93 BAD (HHHHHH) +Size 94: 44,94 BAD (HHHHHH) +Size 95: 45,95 BAD (HHHHHH) +Size 96: 45,96 BAD (HHHHHH) +Size 97: 46,97 BAD (HHHHHH) +Size 98: 46,98 BAD (HHHHHH) +Size 99: 46,99 BAD (HHHHHH) +Size 100: 47,100 BAD (HHHHHH) + +Windows 8 +--------- + +Size 1: 1,3 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 1,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 2,5 BAD (HHHHHH) +Size 6: 3,6 BAD (HHHHHH) +Size 7: 3,6 BAD (HHHHHH) +Size 8: 4,8 BAD (HHHHHH) +Size 9: 4,9 BAD (HHHHHH) +Size 10: 5,10 BAD (HHHHHH) +Size 11: 5,11 BAD (HHHHHH) +Size 12: 6,12 BAD (HHHHHH) +Size 13: 6,13 BAD (HHHHHH) +Size 14: 7,14 BAD (HHHHHH) +Size 15: 7,15 BAD (HHHHHH) +Size 16: 8,16 BAD (HHHHHH) +Size 17: 8,17 BAD (HHHHHH) +Size 18: 8,18 BAD (HHHHHH) +Size 19: 9,19 BAD (HHHHHH) +Size 20: 9,20 BAD (HHHHHH) +Size 21: 10,22 BAD (HHHHHH) +Size 22: 10,22 BAD (HHHHHH) +Size 23: 11,23 BAD (HHHHHH) +Size 24: 11,24 BAD (HHHHHH) +Size 25: 12,25 BAD (HHHHHH) +Size 26: 12,26 BAD (HHHHHH) +Size 27: 13,27 BAD (HHHHHH) +Size 28: 13,28 BAD (HHHHHH) +Size 29: 14,29 BAD (HHHHHH) +Size 30: 14,30 BAD (HHHHHH) +Size 31: 15,31 BAD (HHHHHH) +Size 32: 15,32 BAD (HHHHHH) +Size 33: 15,33 BAD (HHHHHH) +Size 34: 16,34 BAD (HHHHHH) +Size 35: 16,36 BAD (HHHHHH) +Size 36: 17,36 BAD (HHHHHH) +Size 37: 17,37 BAD (HHHHHH) +Size 38: 18,38 BAD (HHHHHH) +Size 39: 18,39 BAD (HHHHHH) +Size 40: 19,40 BAD (HHHHHH) +Size 41: 19,41 BAD (HHHHHH) +Size 42: 20,42 BAD (HHHHHH) +Size 43: 20,43 BAD (HHHHHH) +Size 44: 21,44 BAD (HHHHHH) +Size 45: 21,45 BAD (HHHHHH) +Size 46: 22,46 BAD (HHHHHH) +Size 47: 22,47 BAD (HHHHHH) +Size 48: 23,48 BAD (HHHHHH) +Size 49: 23,49 BAD (HHHHHH) +Size 50: 23,50 BAD (HHHHHH) +Size 51: 24,51 BAD (HHHHHH) +Size 52: 24,52 BAD (HHHHHH) +Size 53: 25,53 BAD (HHHHHH) +Size 54: 25,54 BAD (HHHHHH) +Size 55: 26,55 BAD (HHHHHH) +Size 56: 26,56 BAD (HHHHHH) +Size 57: 27,57 BAD (HHHHHH) +Size 58: 27,58 BAD (HHHHHH) +Size 59: 28,59 BAD (HHHHHH) +Size 60: 28,60 BAD (HHHHHH) +Size 61: 29,61 BAD (HHHHHH) +Size 62: 29,62 BAD (HHHHHH) +Size 63: 30,64 BAD (HHHHHH) +Size 64: 30,64 BAD (HHHHHH) +Size 65: 31,65 BAD (HHHHHH) +Size 66: 31,66 BAD (HHHHHH) +Size 67: 31,67 BAD (HHHHHH) +Size 68: 32,68 BAD (HHHHHH) +Size 69: 32,69 BAD (HHHHHH) +Size 70: 33,70 BAD (HHHHHH) +Size 71: 33,71 BAD (HHHHHH) +Size 72: 34,72 BAD (HHHHHH) +Size 73: 34,73 BAD (HHHHHH) +Size 74: 35,74 BAD (HHHHHH) +Size 75: 35,75 BAD (HHHHHH) +Size 76: 36,76 BAD (HHHHHH) +Size 77: 36,77 BAD (HHHHHH) +Size 78: 37,78 BAD (HHHHHH) +Size 79: 37,79 BAD (HHHHHH) +Size 80: 38,80 BAD (HHHHHH) +Size 81: 38,81 BAD (HHHHHH) +Size 82: 39,82 BAD (HHHHHH) +Size 83: 39,83 BAD (HHHHHH) +Size 84: 39,84 BAD (HHHHHH) +Size 85: 40,85 BAD (HHHHHH) +Size 86: 40,86 BAD (HHHHHH) +Size 87: 41,87 BAD (HHHHHH) +Size 88: 41,88 BAD (HHHHHH) +Size 89: 42,89 BAD (HHHHHH) +Size 90: 42,90 BAD (HHHHHH) +Size 91: 43,91 BAD (HHHHHH) +Size 92: 43,92 BAD (HHHHHH) +Size 93: 44,93 BAD (HHHHHH) +Size 94: 44,94 BAD (HHHHHH) +Size 95: 45,95 BAD (HHHHHH) +Size 96: 45,96 BAD (HHHHHH) +Size 97: 46,97 BAD (HHHHHH) +Size 98: 46,98 BAD (HHHHHH) +Size 99: 46,99 BAD (HHHHHH) +Size 100: 47,100 BAD (HHHHHH) + +Windows 8.1 +----------- + +Size 1: 1,3 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 1,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 2,5 BAD (HHHHHH) +Size 6: 3,6 BAD (HHHHHH) +Size 7: 3,6 BAD (HHHHHH) +Size 8: 4,8 BAD (HHHHHH) +Size 9: 4,9 BAD (HHHHHH) +Size 10: 5,10 BAD (HHHHHH) +Size 11: 5,11 BAD (HHHHHH) +Size 12: 6,12 BAD (HHHHHH) +Size 13: 6,13 BAD (HHHHHH) +Size 14: 7,14 BAD (HHHHHH) +Size 15: 7,15 BAD (HHHHHH) +Size 16: 8,16 BAD (HHHHHH) +Size 17: 8,17 BAD (HHHHHH) +Size 18: 8,18 BAD (HHHHHH) +Size 19: 9,19 BAD (HHHHHH) +Size 20: 9,20 BAD (HHHHHH) +Size 21: 10,22 BAD (HHHHHH) +Size 22: 10,22 BAD (HHHHHH) +Size 23: 11,23 BAD (HHHHHH) +Size 24: 11,24 BAD (HHHHHH) +Size 25: 12,25 BAD (HHHHHH) +Size 26: 12,26 BAD (HHHHHH) +Size 27: 13,27 BAD (HHHHHH) +Size 28: 13,28 BAD (HHHHHH) +Size 29: 14,29 BAD (HHHHHH) +Size 30: 14,30 BAD (HHHHHH) +Size 31: 15,31 BAD (HHHHHH) +Size 32: 15,32 BAD (HHHHHH) +Size 33: 15,33 BAD (HHHHHH) +Size 34: 16,34 BAD (HHHHHH) +Size 35: 16,36 BAD (HHHHHH) +Size 36: 17,36 BAD (HHHHHH) +Size 37: 17,37 BAD (HHHHHH) +Size 38: 18,38 BAD (HHHHHH) +Size 39: 18,39 BAD (HHHHHH) +Size 40: 19,40 BAD (HHHHHH) +Size 41: 19,41 BAD (HHHHHH) +Size 42: 20,42 BAD (HHHHHH) +Size 43: 20,43 BAD (HHHHHH) +Size 44: 21,44 BAD (HHHHHH) +Size 45: 21,45 BAD (HHHHHH) +Size 46: 22,46 BAD (HHHHHH) +Size 47: 22,47 BAD (HHHHHH) +Size 48: 23,48 BAD (HHHHHH) +Size 49: 23,49 BAD (HHHHHH) +Size 50: 23,50 BAD (HHHHHH) +Size 51: 24,51 BAD (HHHHHH) +Size 52: 24,52 BAD (HHHHHH) +Size 53: 25,53 BAD (HHHHHH) +Size 54: 25,54 BAD (HHHHHH) +Size 55: 26,55 BAD (HHHHHH) +Size 56: 26,56 BAD (HHHHHH) +Size 57: 27,57 BAD (HHHHHH) +Size 58: 27,58 BAD (HHHHHH) +Size 59: 28,59 BAD (HHHHHH) +Size 60: 28,60 BAD (HHHHHH) +Size 61: 29,61 BAD (HHHHHH) +Size 62: 29,62 BAD (HHHHHH) +Size 63: 30,64 BAD (HHHHHH) +Size 64: 30,64 BAD (HHHHHH) +Size 65: 31,65 BAD (HHHHHH) +Size 66: 31,66 BAD (HHHHHH) +Size 67: 31,67 BAD (HHHHHH) +Size 68: 32,68 BAD (HHHHHH) +Size 69: 32,69 BAD (HHHHHH) +Size 70: 33,70 BAD (HHHHHH) +Size 71: 33,71 BAD (HHHHHH) +Size 72: 34,72 BAD (HHHHHH) +Size 73: 34,73 BAD (HHHHHH) +Size 74: 35,74 BAD (HHHHHH) +Size 75: 35,75 BAD (HHHHHH) +Size 76: 36,76 BAD (HHHHHH) +Size 77: 36,77 BAD (HHHHHH) +Size 78: 37,78 BAD (HHHHHH) +Size 79: 37,79 BAD (HHHHHH) +Size 80: 38,80 BAD (HHHHHH) +Size 81: 38,81 BAD (HHHHHH) +Size 82: 39,82 BAD (HHHHHH) +Size 83: 39,83 BAD (HHHHHH) +Size 84: 39,84 BAD (HHHHHH) +Size 85: 40,85 BAD (HHHHHH) +Size 86: 40,86 BAD (HHHHHH) +Size 87: 41,87 BAD (HHHHHH) +Size 88: 41,88 BAD (HHHHHH) +Size 89: 42,89 BAD (HHHHHH) +Size 90: 42,90 BAD (HHHHHH) +Size 91: 43,91 BAD (HHHHHH) +Size 92: 43,92 BAD (HHHHHH) +Size 93: 44,93 BAD (HHHHHH) +Size 94: 44,94 BAD (HHHHHH) +Size 95: 45,95 BAD (HHHHHH) +Size 96: 45,96 BAD (HHHHHH) +Size 97: 46,97 BAD (HHHHHH) +Size 98: 46,98 BAD (HHHHHH) +Size 99: 46,99 BAD (HHHHHH) +Size 100: 47,100 BAD (HHHHHH) + +Windows 10 14342 Old Console +---------------------------- + +Size 1: 1,3 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 1,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 2,5 BAD (HHHHHH) +Size 6: 3,6 BAD (HHHHHH) +Size 7: 3,6 BAD (HHHHHH) +Size 8: 4,8 BAD (HHHHHH) +Size 9: 4,9 BAD (HHHHHH) +Size 10: 5,10 BAD (HHHHHH) +Size 11: 5,11 BAD (HHHHHH) +Size 12: 6,12 BAD (HHHHHH) +Size 13: 6,13 BAD (HHHHHH) +Size 14: 7,14 BAD (HHHHHH) +Size 15: 7,15 BAD (HHHHHH) +Size 16: 8,16 BAD (HHHHHH) +Size 17: 8,17 BAD (HHHHHH) +Size 18: 8,18 BAD (HHHHHH) +Size 19: 9,19 BAD (HHHHHH) +Size 20: 9,20 BAD (HHHHHH) +Size 21: 10,22 BAD (HHHHHH) +Size 22: 10,22 BAD (HHHHHH) +Size 23: 11,23 BAD (HHHHHH) +Size 24: 11,24 BAD (HHHHHH) +Size 25: 12,25 BAD (HHHHHH) +Size 26: 12,26 BAD (HHHHHH) +Size 27: 13,27 BAD (HHHHHH) +Size 28: 13,28 BAD (HHHHHH) +Size 29: 14,29 BAD (HHHHHH) +Size 30: 14,30 BAD (HHHHHH) +Size 31: 15,31 BAD (HHHHHH) +Size 32: 15,32 BAD (HHHHHH) +Size 33: 15,33 BAD (HHHHHH) +Size 34: 16,34 BAD (HHHHHH) +Size 35: 16,36 BAD (HHHHHH) +Size 36: 17,36 BAD (HHHHHH) +Size 37: 17,37 BAD (HHHHHH) +Size 38: 18,38 BAD (HHHHHH) +Size 39: 18,39 BAD (HHHHHH) +Size 40: 19,40 BAD (HHHHHH) +Size 41: 19,41 BAD (HHHHHH) +Size 42: 20,42 BAD (HHHHHH) +Size 43: 20,43 BAD (HHHHHH) +Size 44: 21,44 BAD (HHHHHH) +Size 45: 21,45 BAD (HHHHHH) +Size 46: 22,46 BAD (HHHHHH) +Size 47: 22,47 BAD (HHHHHH) +Size 48: 23,48 BAD (HHHHHH) +Size 49: 23,49 BAD (HHHHHH) +Size 50: 23,50 BAD (HHHHHH) +Size 51: 24,51 BAD (HHHHHH) +Size 52: 24,52 BAD (HHHHHH) +Size 53: 25,53 BAD (HHHHHH) +Size 54: 25,54 BAD (HHHHHH) +Size 55: 26,55 BAD (HHHHHH) +Size 56: 26,56 BAD (HHHHHH) +Size 57: 27,57 BAD (HHHHHH) +Size 58: 27,58 BAD (HHHHHH) +Size 59: 28,59 BAD (HHHHHH) +Size 60: 28,60 BAD (HHHHHH) +Size 61: 29,61 BAD (HHHHHH) +Size 62: 29,62 BAD (HHHHHH) +Size 63: 30,64 BAD (HHHHHH) +Size 64: 30,64 BAD (HHHHHH) +Size 65: 31,65 BAD (HHHHHH) +Size 66: 31,66 BAD (HHHHHH) +Size 67: 31,67 BAD (HHHHHH) +Size 68: 32,68 BAD (HHHHHH) +Size 69: 32,69 BAD (HHHHHH) +Size 70: 33,70 BAD (HHHHHH) +Size 71: 33,71 BAD (HHHHHH) +Size 72: 34,72 BAD (HHHHHH) +Size 73: 34,73 BAD (HHHHHH) +Size 74: 35,74 BAD (HHHHHH) +Size 75: 35,75 BAD (HHHHHH) +Size 76: 36,76 BAD (HHHHHH) +Size 77: 36,77 BAD (HHHHHH) +Size 78: 37,78 BAD (HHHHHH) +Size 79: 37,79 BAD (HHHHHH) +Size 80: 38,80 BAD (HHHHHH) +Size 81: 38,81 BAD (HHHHHH) +Size 82: 39,82 BAD (HHHHHH) +Size 83: 39,83 BAD (HHHHHH) +Size 84: 39,84 BAD (HHHHHH) +Size 85: 40,85 BAD (HHHHHH) +Size 86: 40,86 BAD (HHHHHH) +Size 87: 41,87 BAD (HHHHHH) +Size 88: 41,88 BAD (HHHHHH) +Size 89: 42,89 BAD (HHHHHH) +Size 90: 42,90 BAD (HHHHHH) +Size 91: 43,91 BAD (HHHHHH) +Size 92: 43,92 BAD (HHHHHH) +Size 93: 44,93 BAD (HHHHHH) +Size 94: 44,94 BAD (HHHHHH) +Size 95: 45,95 BAD (HHHHHH) +Size 96: 45,96 BAD (HHHHHH) +Size 97: 46,97 BAD (HHHHHH) +Size 98: 46,98 BAD (HHHHHH) +Size 99: 46,99 BAD (HHHHHH) +Size 100: 47,100 BAD (HHHHHH) + +Windows 10 14342 New Console +---------------------------- + +Size 1: 1,1 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 1,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 2,5 BAD (HHHHHH) +Size 6: 3,6 BAD (HHHHHH) +Size 7: 3,7 BAD (HHHHHH) +Size 8: 4,8 BAD (HHHHHH) +Size 9: 4,9 BAD (HHHHHH) +Size 10: 5,10 BAD (HHHHHH) +Size 11: 5,11 BAD (HHHHHH) +Size 12: 6,12 BAD (HHHHHH) +Size 13: 6,13 BAD (HHHHHH) +Size 14: 7,14 BAD (HHHHHH) +Size 15: 7,15 BAD (HHHHHH) +Size 16: 8,16 BAD (HHHHHH) +Size 17: 8,17 BAD (HHHHHH) +Size 18: 8,18 BAD (HHHHHH) +Size 19: 9,19 BAD (HHHHHH) +Size 20: 9,20 BAD (HHHHHH) +Size 21: 10,21 BAD (HHHHHH) +Size 22: 10,22 BAD (HHHHHH) +Size 23: 11,23 BAD (HHHHHH) +Size 24: 11,24 BAD (HHHHHH) +Size 25: 12,25 BAD (HHHHHH) +Size 26: 12,26 BAD (HHHHHH) +Size 27: 13,27 BAD (HHHHHH) +Size 28: 13,28 BAD (HHHHHH) +Size 29: 14,29 BAD (HHHHHH) +Size 30: 14,30 BAD (HHHHHH) +Size 31: 15,31 BAD (HHHHHH) +Size 32: 15,32 BAD (HHHHHH) +Size 33: 15,33 BAD (HHHHHH) +Size 34: 16,34 BAD (HHHHHH) +Size 35: 16,35 BAD (HHHHHH) +Size 36: 17,36 BAD (HHHHHH) +Size 37: 17,37 BAD (HHHHHH) +Size 38: 18,38 BAD (HHHHHH) +Size 39: 18,39 BAD (HHHHHH) +Size 40: 19,40 BAD (HHHHHH) +Size 41: 19,41 BAD (HHHHHH) +Size 42: 20,42 BAD (HHHHHH) +Size 43: 20,43 BAD (HHHHHH) +Size 44: 21,44 BAD (HHHHHH) +Size 45: 21,45 BAD (HHHHHH) +Size 46: 22,46 BAD (HHHHHH) +Size 47: 22,47 BAD (HHHHHH) +Size 48: 23,48 BAD (HHHHHH) +Size 49: 23,49 BAD (HHHHHH) +Size 50: 23,50 BAD (HHHHHH) +Size 51: 24,51 BAD (HHHHHH) +Size 52: 24,52 BAD (HHHHHH) +Size 53: 25,53 BAD (HHHHHH) +Size 54: 25,54 BAD (HHHHHH) +Size 55: 26,55 BAD (HHHHHH) +Size 56: 26,56 BAD (HHHHHH) +Size 57: 27,57 BAD (HHHHHH) +Size 58: 27,58 BAD (HHHHHH) +Size 59: 28,59 BAD (HHHHHH) +Size 60: 28,60 BAD (HHHHHH) +Size 61: 29,61 BAD (HHHHHH) +Size 62: 29,62 BAD (HHHHHH) +Size 63: 30,63 BAD (HHHHHH) +Size 64: 30,64 BAD (HHHHHH) +Size 65: 31,65 BAD (HHHHHH) +Size 66: 31,66 BAD (HHHHHH) +Size 67: 31,67 BAD (HHHHHH) +Size 68: 32,68 BAD (HHHHHH) +Size 69: 32,69 BAD (HHHHHH) +Size 70: 33,70 BAD (HHHHHH) +Size 71: 33,71 BAD (HHHHHH) +Size 72: 34,72 BAD (HHHHHH) +Size 73: 34,73 BAD (HHHHHH) +Size 74: 35,74 BAD (HHHHHH) +Size 75: 35,75 BAD (HHHHHH) +Size 76: 36,76 BAD (HHHHHH) +Size 77: 36,77 BAD (HHHHHH) +Size 78: 37,78 BAD (HHHHHH) +Size 79: 37,79 BAD (HHHHHH) +Size 80: 38,80 BAD (HHHHHH) +Size 81: 38,81 BAD (HHHHHH) +Size 82: 39,82 BAD (HHHHHH) +Size 83: 39,83 BAD (HHHHHH) +Size 84: 39,84 BAD (HHHHHH) +Size 85: 40,85 BAD (HHHHHH) +Size 86: 40,86 BAD (HHHHHH) +Size 87: 41,87 BAD (HHHHHH) +Size 88: 41,88 BAD (HHHHHH) +Size 89: 42,89 BAD (HHHHHH) +Size 90: 42,90 BAD (HHHHHH) +Size 91: 43,91 BAD (HHHHHH) +Size 92: 43,92 BAD (HHHHHH) +Size 93: 44,93 BAD (HHHHHH) +Size 94: 44,94 BAD (HHHHHH) +Size 95: 45,95 BAD (HHHHHH) +Size 96: 45,96 BAD (HHHHHH) +Size 97: 46,97 BAD (HHHHHH) +Size 98: 46,98 BAD (HHHHHH) +Size 99: 46,99 BAD (HHHHHH) +Size 100: 47,100 BAD (HHHHHH) diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt new file mode 100644 index 00000000000..0eed93ad989 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP437-Lucida.txt @@ -0,0 +1,633 @@ +================================== +Code Page 437, Lucida Console font +================================== + +Options: -face "Lucida Console" -family 0x36 +Chars: A2 A3 2014 3044 30FC 4000 + +FontSurvey "-face \"Lucida Console\" -family 0x36" + +Vista +----- + +Size 1: 1,2 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 2,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 3,5 BAD (HHHHHH) +Size 6: 4,6 BAD (HHHHHH) +Size 7: 4,7 BAD (HHHHHH) +Size 8: 5,8 BAD (HHHHHH) +Size 9: 5,9 BAD (HHHHHH) +Size 10: 6,10 BAD (HHHHHH) +Size 11: 7,11 BAD (HHHHHH) +Size 12: 7,12 BAD (HHHHHH) +Size 13: 8,13 BAD (HHHHHH) +Size 14: 8,14 BAD (HHHHHH) +Size 15: 9,15 BAD (HHHHHH) +Size 16: 10,16 BAD (HHHHHH) +Size 17: 10,17 BAD (HHHHHH) +Size 18: 11,18 BAD (HHHHHH) +Size 19: 11,19 BAD (HHHHHH) +Size 20: 12,20 BAD (HHHHHH) +Size 21: 13,21 BAD (HHHHHH) +Size 22: 13,22 BAD (HHHHHH) +Size 23: 14,23 BAD (HHHHHH) +Size 24: 14,24 BAD (HHHHHH) +Size 25: 15,25 BAD (HHHHHH) +Size 26: 16,26 BAD (HHHHHH) +Size 27: 16,27 BAD (HHHHHH) +Size 28: 17,28 BAD (HHHHHH) +Size 29: 17,29 BAD (HHHHHH) +Size 30: 18,30 BAD (HHHHHH) +Size 31: 19,31 BAD (HHHHHH) +Size 32: 19,32 BAD (HHHHHH) +Size 33: 20,33 BAD (HHHHHH) +Size 34: 20,34 BAD (HHHHHH) +Size 35: 21,35 BAD (HHHHHH) +Size 36: 22,36 BAD (HHHHHH) +Size 37: 22,37 BAD (HHHHHH) +Size 38: 23,38 BAD (HHHHHH) +Size 39: 23,39 BAD (HHHHHH) +Size 40: 24,40 BAD (HHHHHH) +Size 41: 25,41 BAD (HHHHHH) +Size 42: 25,42 BAD (HHHHHH) +Size 43: 26,43 BAD (HHHHHH) +Size 44: 27,44 BAD (HHHHHH) +Size 45: 27,45 BAD (HHHHHH) +Size 46: 28,46 BAD (HHHHHH) +Size 47: 28,47 BAD (HHHHHH) +Size 48: 29,48 BAD (HHHHHH) +Size 49: 30,49 BAD (HHHHHH) +Size 50: 30,50 BAD (HHHHHH) +Size 51: 31,51 BAD (HHHHHH) +Size 52: 31,52 BAD (HHHHHH) +Size 53: 32,53 BAD (HHHHHH) +Size 54: 33,54 BAD (HHHHHH) +Size 55: 33,55 BAD (HHHHHH) +Size 56: 34,56 BAD (HHHHHH) +Size 57: 34,57 BAD (HHHHHH) +Size 58: 35,58 BAD (HHHHHH) +Size 59: 36,59 BAD (HHHHHH) +Size 60: 36,60 BAD (HHHHHH) +Size 61: 37,61 BAD (HHHHHH) +Size 62: 37,62 BAD (HHHHHH) +Size 63: 38,63 BAD (HHHHHH) +Size 64: 39,65 BAD (HHHHHH) +Size 65: 39,65 BAD (HHHHHH) +Size 66: 40,66 BAD (HHHHHH) +Size 67: 40,67 BAD (HHHHHH) +Size 68: 41,68 BAD (HHHHHH) +Size 69: 42,69 BAD (HHHHHH) +Size 70: 42,70 BAD (HHHHHH) +Size 71: 43,71 BAD (HHHHHH) +Size 72: 43,72 BAD (HHHHHH) +Size 73: 44,73 BAD (HHHHHH) +Size 74: 45,74 BAD (HHHHHH) +Size 75: 45,75 BAD (HHHHHH) +Size 76: 46,76 BAD (HHHHHH) +Size 77: 46,77 BAD (HHHHHH) +Size 78: 47,78 BAD (HHHHHH) +Size 79: 48,79 BAD (HHHHHH) +Size 80: 48,80 BAD (HHHHHH) +Size 81: 49,81 BAD (HHHHHH) +Size 82: 49,82 BAD (HHHHHH) +Size 83: 50,83 BAD (HHHHHH) +Size 84: 51,84 BAD (HHHHHH) +Size 85: 51,85 BAD (HHHHHH) +Size 86: 52,86 BAD (HHHHHH) +Size 87: 52,87 BAD (HHHHHH) +Size 88: 53,88 BAD (HHHHHH) +Size 89: 54,89 BAD (HHHHHH) +Size 90: 54,90 BAD (HHHHHH) +Size 91: 55,91 BAD (HHHHHH) +Size 92: 55,92 BAD (HHHHHH) +Size 93: 56,93 BAD (HHHHHH) +Size 94: 57,94 BAD (HHHHHH) +Size 95: 57,95 BAD (HHHHHH) +Size 96: 58,96 BAD (HHHHHH) +Size 97: 58,97 BAD (HHHHHH) +Size 98: 59,98 BAD (HHHHHH) +Size 99: 60,99 BAD (HHHHHH) +Size 100: 60,100 BAD (HHHHHH) + + +Windows 7 +--------- + +Size 1: 1,2 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 2,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 3,5 BAD (HHHHHH) +Size 6: 4,6 BAD (HHHHHH) +Size 7: 4,7 BAD (HHHHHH) +Size 8: 5,8 BAD (HHHHHH) +Size 9: 5,9 BAD (HHHHHH) +Size 10: 6,10 BAD (HHHHHH) +Size 11: 7,11 BAD (HHHHHH) +Size 12: 7,12 BAD (HHHHHH) +Size 13: 8,13 BAD (HHHHHH) +Size 14: 8,14 BAD (HHHHHH) +Size 15: 9,15 BAD (HHHHHH) +Size 16: 10,16 BAD (HHHHHH) +Size 17: 10,17 BAD (HHHHHH) +Size 18: 11,18 BAD (HHHHHH) +Size 19: 11,19 BAD (HHHHHH) +Size 20: 12,20 BAD (HHHHHH) +Size 21: 13,21 BAD (HHHHHH) +Size 22: 13,22 BAD (HHHHHH) +Size 23: 14,23 BAD (HHHHHH) +Size 24: 14,24 BAD (HHHHHH) +Size 25: 15,25 BAD (HHHHHH) +Size 26: 16,26 BAD (HHHHHH) +Size 27: 16,27 BAD (HHHHHH) +Size 28: 17,28 BAD (HHHHHH) +Size 29: 17,29 BAD (HHHHHH) +Size 30: 18,30 BAD (HHHHHH) +Size 31: 19,31 BAD (HHHHHH) +Size 32: 19,32 BAD (HHHHHH) +Size 33: 20,33 BAD (HHHHHH) +Size 34: 20,34 BAD (HHHHHH) +Size 35: 21,35 BAD (HHHHHH) +Size 36: 22,36 BAD (HHHHHH) +Size 37: 22,37 BAD (HHHHHH) +Size 38: 23,38 BAD (HHHHHH) +Size 39: 23,39 BAD (HHHHHH) +Size 40: 24,40 BAD (HHHHHH) +Size 41: 25,41 BAD (HHHHHH) +Size 42: 25,42 BAD (HHHHHH) +Size 43: 26,43 BAD (HHHHHH) +Size 44: 27,44 BAD (HHHHHH) +Size 45: 27,45 BAD (HHHHHH) +Size 46: 28,46 BAD (HHHHHH) +Size 47: 28,47 BAD (HHHHHH) +Size 48: 29,48 BAD (HHHHHH) +Size 49: 30,49 BAD (HHHHHH) +Size 50: 30,50 BAD (HHHHHH) +Size 51: 31,51 BAD (HHHHHH) +Size 52: 31,52 BAD (HHHHHH) +Size 53: 32,53 BAD (HHHHHH) +Size 54: 33,54 BAD (HHHHHH) +Size 55: 33,55 BAD (HHHHHH) +Size 56: 34,56 BAD (HHHHHH) +Size 57: 34,57 BAD (HHHHHH) +Size 58: 35,58 BAD (HHHHHH) +Size 59: 36,59 BAD (HHHHHH) +Size 60: 36,60 BAD (HHHHHH) +Size 61: 37,61 BAD (HHHHHH) +Size 62: 37,62 BAD (HHHHHH) +Size 63: 38,63 BAD (HHHHHH) +Size 64: 39,65 BAD (HHHHHH) +Size 65: 39,65 BAD (HHHHHH) +Size 66: 40,66 BAD (HHHHHH) +Size 67: 40,67 BAD (HHHHHH) +Size 68: 41,68 BAD (HHHHHH) +Size 69: 42,69 BAD (HHHHHH) +Size 70: 42,70 BAD (HHHHHH) +Size 71: 43,71 BAD (HHHHHH) +Size 72: 43,72 BAD (HHHHHH) +Size 73: 44,73 BAD (HHHHHH) +Size 74: 45,74 BAD (HHHHHH) +Size 75: 45,75 BAD (HHHHHH) +Size 76: 46,76 BAD (HHHHHH) +Size 77: 46,77 BAD (HHHHHH) +Size 78: 47,78 BAD (HHHHHH) +Size 79: 48,79 BAD (HHHHHH) +Size 80: 48,80 BAD (HHHHHH) +Size 81: 49,81 BAD (HHHHHH) +Size 82: 49,82 BAD (HHHHHH) +Size 83: 50,83 BAD (HHHHHH) +Size 84: 51,84 BAD (HHHHHH) +Size 85: 51,85 BAD (HHHHHH) +Size 86: 52,86 BAD (HHHHHH) +Size 87: 52,87 BAD (HHHHHH) +Size 88: 53,88 BAD (HHHHHH) +Size 89: 54,89 BAD (HHHHHH) +Size 90: 54,90 BAD (HHHHHH) +Size 91: 55,91 BAD (HHHHHH) +Size 92: 55,92 BAD (HHHHHH) +Size 93: 56,93 BAD (HHHHHH) +Size 94: 57,94 BAD (HHHHHH) +Size 95: 57,95 BAD (HHHHHH) +Size 96: 58,96 BAD (HHHHHH) +Size 97: 58,97 BAD (HHHHHH) +Size 98: 59,98 BAD (HHHHHH) +Size 99: 60,99 BAD (HHHHHH) +Size 100: 60,100 BAD (HHHHHH) + +Windows 8 +--------- + +Size 1: 1,2 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 2,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 3,5 BAD (HHHHHH) +Size 6: 4,6 BAD (HHHHHH) +Size 7: 4,7 BAD (HHHHHH) +Size 8: 5,8 BAD (HHHHHH) +Size 9: 5,9 BAD (HHHHHH) +Size 10: 6,10 BAD (HHHHHH) +Size 11: 7,11 BAD (HHHHHH) +Size 12: 7,12 BAD (HHHHHH) +Size 13: 8,13 BAD (HHHHHH) +Size 14: 8,14 BAD (HHHHHH) +Size 15: 9,15 BAD (HHHHHH) +Size 16: 10,16 BAD (HHHHHH) +Size 17: 10,17 BAD (HHHHHH) +Size 18: 11,18 BAD (HHHHHH) +Size 19: 11,19 BAD (HHHHHH) +Size 20: 12,20 BAD (HHHHHH) +Size 21: 13,21 BAD (HHHHHH) +Size 22: 13,22 BAD (HHHHHH) +Size 23: 14,23 BAD (HHHHHH) +Size 24: 14,24 BAD (HHHHHH) +Size 25: 15,25 BAD (HHHHHH) +Size 26: 16,26 BAD (HHHHHH) +Size 27: 16,27 BAD (HHHHHH) +Size 28: 17,28 BAD (HHHHHH) +Size 29: 17,29 BAD (HHHHHH) +Size 30: 18,30 BAD (HHHHHH) +Size 31: 19,31 BAD (HHHHHH) +Size 32: 19,32 BAD (HHHHHH) +Size 33: 20,33 BAD (HHHHHH) +Size 34: 20,34 BAD (HHHHHH) +Size 35: 21,35 BAD (HHHHHH) +Size 36: 22,36 BAD (HHHHHH) +Size 37: 22,37 BAD (HHHHHH) +Size 38: 23,38 BAD (HHHHHH) +Size 39: 23,39 BAD (HHHHHH) +Size 40: 24,40 BAD (HHHHHH) +Size 41: 25,41 BAD (HHHHHH) +Size 42: 25,42 BAD (HHHHHH) +Size 43: 26,43 BAD (HHHHHH) +Size 44: 27,44 BAD (HHHHHH) +Size 45: 27,45 BAD (HHHHHH) +Size 46: 28,46 BAD (HHHHHH) +Size 47: 28,47 BAD (HHHHHH) +Size 48: 29,48 BAD (HHHHHH) +Size 49: 30,49 BAD (HHHHHH) +Size 50: 30,50 BAD (HHHHHH) +Size 51: 31,51 BAD (HHHHHH) +Size 52: 31,52 BAD (HHHHHH) +Size 53: 32,53 BAD (HHHHHH) +Size 54: 33,54 BAD (HHHHHH) +Size 55: 33,55 BAD (HHHHHH) +Size 56: 34,56 BAD (HHHHHH) +Size 57: 34,57 BAD (HHHHHH) +Size 58: 35,58 BAD (HHHHHH) +Size 59: 36,59 BAD (HHHHHH) +Size 60: 36,60 BAD (HHHHHH) +Size 61: 37,61 BAD (HHHHHH) +Size 62: 37,62 BAD (HHHHHH) +Size 63: 38,63 BAD (HHHHHH) +Size 64: 39,65 BAD (HHHHHH) +Size 65: 39,65 BAD (HHHHHH) +Size 66: 40,66 BAD (HHHHHH) +Size 67: 40,67 BAD (HHHHHH) +Size 68: 41,68 BAD (HHHHHH) +Size 69: 42,69 BAD (HHHHHH) +Size 70: 42,70 BAD (HHHHHH) +Size 71: 43,71 BAD (HHHHHH) +Size 72: 43,72 BAD (HHHHHH) +Size 73: 44,73 BAD (HHHHHH) +Size 74: 45,74 BAD (HHHHHH) +Size 75: 45,75 BAD (HHHHHH) +Size 76: 46,76 BAD (HHHHHH) +Size 77: 46,77 BAD (HHHHHH) +Size 78: 47,78 BAD (HHHHHH) +Size 79: 48,79 BAD (HHHHHH) +Size 80: 48,80 BAD (HHHHHH) +Size 81: 49,81 BAD (HHHHHH) +Size 82: 49,82 BAD (HHHHHH) +Size 83: 50,83 BAD (HHHHHH) +Size 84: 51,84 BAD (HHHHHH) +Size 85: 51,85 BAD (HHHHHH) +Size 86: 52,86 BAD (HHHHHH) +Size 87: 52,87 BAD (HHHHHH) +Size 88: 53,88 BAD (HHHHHH) +Size 89: 54,89 BAD (HHHHHH) +Size 90: 54,90 BAD (HHHHHH) +Size 91: 55,91 BAD (HHHHHH) +Size 92: 55,92 BAD (HHHHHH) +Size 93: 56,93 BAD (HHHHHH) +Size 94: 57,94 BAD (HHHHHH) +Size 95: 57,95 BAD (HHHHHH) +Size 96: 58,96 BAD (HHHHHH) +Size 97: 58,97 BAD (HHHHHH) +Size 98: 59,98 BAD (HHHHHH) +Size 99: 60,99 BAD (HHHHHH) +Size 100: 60,100 BAD (HHHHHH) + +Windows 8.1 +----------- + +Size 1: 1,2 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 2,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 3,5 BAD (HHHHHH) +Size 6: 4,6 BAD (HHHHHH) +Size 7: 4,7 BAD (HHHHHH) +Size 8: 5,8 BAD (HHHHHH) +Size 9: 5,9 BAD (HHHHHH) +Size 10: 6,10 BAD (HHHHHH) +Size 11: 7,11 BAD (HHHHHH) +Size 12: 7,12 BAD (HHHHHH) +Size 13: 8,13 BAD (HHHHHH) +Size 14: 8,14 BAD (HHHHHH) +Size 15: 9,15 BAD (HHHHHH) +Size 16: 10,16 BAD (HHHHHH) +Size 17: 10,17 BAD (HHHHHH) +Size 18: 11,18 BAD (HHHHHH) +Size 19: 11,19 BAD (HHHHHH) +Size 20: 12,20 BAD (HHHHHH) +Size 21: 13,21 BAD (HHHHHH) +Size 22: 13,22 BAD (HHHHHH) +Size 23: 14,23 BAD (HHHHHH) +Size 24: 14,24 BAD (HHHHHH) +Size 25: 15,25 BAD (HHHHHH) +Size 26: 16,26 BAD (HHHHHH) +Size 27: 16,27 BAD (HHHHHH) +Size 28: 17,28 BAD (HHHHHH) +Size 29: 17,29 BAD (HHHHHH) +Size 30: 18,30 BAD (HHHHHH) +Size 31: 19,31 BAD (HHHHHH) +Size 32: 19,32 BAD (HHHHHH) +Size 33: 20,33 BAD (HHHHHH) +Size 34: 20,34 BAD (HHHHHH) +Size 35: 21,35 BAD (HHHHHH) +Size 36: 22,36 BAD (HHHHHH) +Size 37: 22,37 BAD (HHHHHH) +Size 38: 23,38 BAD (HHHHHH) +Size 39: 23,39 BAD (HHHHHH) +Size 40: 24,40 BAD (HHHHHH) +Size 41: 25,41 BAD (HHHHHH) +Size 42: 25,42 BAD (HHHHHH) +Size 43: 26,43 BAD (HHHHHH) +Size 44: 27,44 BAD (HHHHHH) +Size 45: 27,45 BAD (HHHHHH) +Size 46: 28,46 BAD (HHHHHH) +Size 47: 28,47 BAD (HHHHHH) +Size 48: 29,48 BAD (HHHHHH) +Size 49: 30,49 BAD (HHHHHH) +Size 50: 30,50 BAD (HHHHHH) +Size 51: 31,51 BAD (HHHHHH) +Size 52: 31,52 BAD (HHHHHH) +Size 53: 32,53 BAD (HHHHHH) +Size 54: 33,54 BAD (HHHHHH) +Size 55: 33,55 BAD (HHHHHH) +Size 56: 34,56 BAD (HHHHHH) +Size 57: 34,57 BAD (HHHHHH) +Size 58: 35,58 BAD (HHHHHH) +Size 59: 36,59 BAD (HHHHHH) +Size 60: 36,60 BAD (HHHHHH) +Size 61: 37,61 BAD (HHHHHH) +Size 62: 37,62 BAD (HHHHHH) +Size 63: 38,63 BAD (HHHHHH) +Size 64: 39,65 BAD (HHHHHH) +Size 65: 39,65 BAD (HHHHHH) +Size 66: 40,66 BAD (HHHHHH) +Size 67: 40,67 BAD (HHHHHH) +Size 68: 41,68 BAD (HHHHHH) +Size 69: 42,69 BAD (HHHHHH) +Size 70: 42,70 BAD (HHHHHH) +Size 71: 43,71 BAD (HHHHHH) +Size 72: 43,72 BAD (HHHHHH) +Size 73: 44,73 BAD (HHHHHH) +Size 74: 45,74 BAD (HHHHHH) +Size 75: 45,75 BAD (HHHHHH) +Size 76: 46,76 BAD (HHHHHH) +Size 77: 46,77 BAD (HHHHHH) +Size 78: 47,78 BAD (HHHHHH) +Size 79: 48,79 BAD (HHHHHH) +Size 80: 48,80 BAD (HHHHHH) +Size 81: 49,81 BAD (HHHHHH) +Size 82: 49,82 BAD (HHHHHH) +Size 83: 50,83 BAD (HHHHHH) +Size 84: 51,84 BAD (HHHHHH) +Size 85: 51,85 BAD (HHHHHH) +Size 86: 52,86 BAD (HHHHHH) +Size 87: 52,87 BAD (HHHHHH) +Size 88: 53,88 BAD (HHHHHH) +Size 89: 54,89 BAD (HHHHHH) +Size 90: 54,90 BAD (HHHHHH) +Size 91: 55,91 BAD (HHHHHH) +Size 92: 55,92 BAD (HHHHHH) +Size 93: 56,93 BAD (HHHHHH) +Size 94: 57,94 BAD (HHHHHH) +Size 95: 57,95 BAD (HHHHHH) +Size 96: 58,96 BAD (HHHHHH) +Size 97: 58,97 BAD (HHHHHH) +Size 98: 59,98 BAD (HHHHHH) +Size 99: 60,99 BAD (HHHHHH) +Size 100: 60,100 BAD (HHHHHH) + +Windows 10 14342 Old Console +---------------------------- + +Size 1: 1,2 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 2,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 3,5 BAD (HHHHHH) +Size 6: 4,6 BAD (HHHHHH) +Size 7: 4,7 BAD (HHHHHH) +Size 8: 5,8 BAD (HHHHHH) +Size 9: 5,9 BAD (HHHHHH) +Size 10: 6,10 BAD (HHHHHH) +Size 11: 7,11 BAD (HHHHHH) +Size 12: 7,12 BAD (HHHHHH) +Size 13: 8,13 BAD (HHHHHH) +Size 14: 8,14 BAD (HHHHHH) +Size 15: 9,15 BAD (HHHHHH) +Size 16: 10,16 BAD (HHHHHH) +Size 17: 10,17 BAD (HHHHHH) +Size 18: 11,18 BAD (HHHHHH) +Size 19: 11,19 BAD (HHHHHH) +Size 20: 12,20 BAD (HHHHHH) +Size 21: 13,21 BAD (HHHHHH) +Size 22: 13,22 BAD (HHHHHH) +Size 23: 14,23 BAD (HHHHHH) +Size 24: 14,24 BAD (HHHHHH) +Size 25: 15,25 BAD (HHHHHH) +Size 26: 16,26 BAD (HHHHHH) +Size 27: 16,27 BAD (HHHHHH) +Size 28: 17,28 BAD (HHHHHH) +Size 29: 17,29 BAD (HHHHHH) +Size 30: 18,30 BAD (HHHHHH) +Size 31: 19,31 BAD (HHHHHH) +Size 32: 19,32 BAD (HHHHHH) +Size 33: 20,33 BAD (HHHHHH) +Size 34: 20,34 BAD (HHHHHH) +Size 35: 21,35 BAD (HHHHHH) +Size 36: 22,36 BAD (HHHHHH) +Size 37: 22,37 BAD (HHHHHH) +Size 38: 23,38 BAD (HHHHHH) +Size 39: 23,39 BAD (HHHHHH) +Size 40: 24,40 BAD (HHHHHH) +Size 41: 25,41 BAD (HHHHHH) +Size 42: 25,42 BAD (HHHHHH) +Size 43: 26,43 BAD (HHHHHH) +Size 44: 27,44 BAD (HHHHHH) +Size 45: 27,45 BAD (HHHHHH) +Size 46: 28,46 BAD (HHHHHH) +Size 47: 28,47 BAD (HHHHHH) +Size 48: 29,48 BAD (HHHHHH) +Size 49: 30,49 BAD (HHHHHH) +Size 50: 30,50 BAD (HHHHHH) +Size 51: 31,51 BAD (HHHHHH) +Size 52: 31,52 BAD (HHHHHH) +Size 53: 32,53 BAD (HHHHHH) +Size 54: 33,54 BAD (HHHHHH) +Size 55: 33,55 BAD (HHHHHH) +Size 56: 34,56 BAD (HHHHHH) +Size 57: 34,57 BAD (HHHHHH) +Size 58: 35,58 BAD (HHHHHH) +Size 59: 36,59 BAD (HHHHHH) +Size 60: 36,60 BAD (HHHHHH) +Size 61: 37,61 BAD (HHHHHH) +Size 62: 37,62 BAD (HHHHHH) +Size 63: 38,63 BAD (HHHHHH) +Size 64: 39,65 BAD (HHHHHH) +Size 65: 39,65 BAD (HHHHHH) +Size 66: 40,66 BAD (HHHHHH) +Size 67: 40,67 BAD (HHHHHH) +Size 68: 41,68 BAD (HHHHHH) +Size 69: 42,69 BAD (HHHHHH) +Size 70: 42,70 BAD (HHHHHH) +Size 71: 43,71 BAD (HHHHHH) +Size 72: 43,72 BAD (HHHHHH) +Size 73: 44,73 BAD (HHHHHH) +Size 74: 45,74 BAD (HHHHHH) +Size 75: 45,75 BAD (HHHHHH) +Size 76: 46,76 BAD (HHHHHH) +Size 77: 46,77 BAD (HHHHHH) +Size 78: 47,78 BAD (HHHHHH) +Size 79: 48,79 BAD (HHHHHH) +Size 80: 48,80 BAD (HHHHHH) +Size 81: 49,81 BAD (HHHHHH) +Size 82: 49,82 BAD (HHHHHH) +Size 83: 50,83 BAD (HHHHHH) +Size 84: 51,84 BAD (HHHHHH) +Size 85: 51,85 BAD (HHHHHH) +Size 86: 52,86 BAD (HHHHHH) +Size 87: 52,87 BAD (HHHHHH) +Size 88: 53,88 BAD (HHHHHH) +Size 89: 54,89 BAD (HHHHHH) +Size 90: 54,90 BAD (HHHHHH) +Size 91: 55,91 BAD (HHHHHH) +Size 92: 55,92 BAD (HHHHHH) +Size 93: 56,93 BAD (HHHHHH) +Size 94: 57,94 BAD (HHHHHH) +Size 95: 57,95 BAD (HHHHHH) +Size 96: 58,96 BAD (HHHHHH) +Size 97: 58,97 BAD (HHHHHH) +Size 98: 59,98 BAD (HHHHHH) +Size 99: 60,99 BAD (HHHHHH) +Size 100: 60,100 BAD (HHHHHH) + +Windows 10 14342 New Console +---------------------------- + +Size 1: 1,1 BAD (HHHHHH) +Size 2: 1,2 BAD (HHHHHH) +Size 3: 2,3 BAD (HHHHHH) +Size 4: 2,4 BAD (HHHHHH) +Size 5: 3,5 BAD (HHHHHH) +Size 6: 4,6 BAD (HHHHHH) +Size 7: 4,7 BAD (HHHHHH) +Size 8: 5,8 BAD (HHHHHH) +Size 9: 5,9 BAD (HHHHHH) +Size 10: 6,10 BAD (HHHHHH) +Size 11: 7,11 BAD (HHHHHH) +Size 12: 7,12 BAD (HHHHHH) +Size 13: 8,13 BAD (HHHHHH) +Size 14: 8,14 BAD (HHHHHH) +Size 15: 9,15 BAD (HHHHHH) +Size 16: 10,16 BAD (HHHHHH) +Size 17: 10,17 BAD (HHHHHH) +Size 18: 11,18 BAD (HHHHHH) +Size 19: 11,19 BAD (HHHHHH) +Size 20: 12,20 BAD (HHHHHH) +Size 21: 13,21 BAD (HHHHHH) +Size 22: 13,22 BAD (HHHHHH) +Size 23: 14,23 BAD (HHHHHH) +Size 24: 14,24 BAD (HHHHHH) +Size 25: 15,25 BAD (HHHHHH) +Size 26: 16,26 BAD (HHHHHH) +Size 27: 16,27 BAD (HHHHHH) +Size 28: 17,28 BAD (HHHHHH) +Size 29: 17,29 BAD (HHHHHH) +Size 30: 18,30 BAD (HHHHHH) +Size 31: 19,31 BAD (HHHHHH) +Size 32: 19,32 BAD (HHHHHH) +Size 33: 20,33 BAD (HHHHHH) +Size 34: 20,34 BAD (HHHHHH) +Size 35: 21,35 BAD (HHHHHH) +Size 36: 22,36 BAD (HHHHHH) +Size 37: 22,37 BAD (HHHHHH) +Size 38: 23,38 BAD (HHHHHH) +Size 39: 23,39 BAD (HHHHHH) +Size 40: 24,40 BAD (HHHHHH) +Size 41: 25,41 BAD (HHHHHH) +Size 42: 25,42 BAD (HHHHHH) +Size 43: 26,43 BAD (HHHHHH) +Size 44: 27,44 BAD (HHHHHH) +Size 45: 27,45 BAD (HHHHHH) +Size 46: 28,46 BAD (HHHHHH) +Size 47: 28,47 BAD (HHHHHH) +Size 48: 29,48 BAD (HHHHHH) +Size 49: 30,49 BAD (HHHHHH) +Size 50: 30,50 BAD (HHHHHH) +Size 51: 31,51 BAD (HHHHHH) +Size 52: 31,52 BAD (HHHHHH) +Size 53: 32,53 BAD (HHHHHH) +Size 54: 33,54 BAD (HHHHHH) +Size 55: 33,55 BAD (HHHHHH) +Size 56: 34,56 BAD (HHHHHH) +Size 57: 34,57 BAD (HHHHHH) +Size 58: 35,58 BAD (HHHHHH) +Size 59: 36,59 BAD (HHHHHH) +Size 60: 36,60 BAD (HHHHHH) +Size 61: 37,61 BAD (HHHHHH) +Size 62: 37,62 BAD (HHHHHH) +Size 63: 38,63 BAD (HHHHHH) +Size 64: 39,64 BAD (HHHHHH) +Size 65: 39,65 BAD (HHHHHH) +Size 66: 40,66 BAD (HHHHHH) +Size 67: 40,67 BAD (HHHHHH) +Size 68: 41,68 BAD (HHHHHH) +Size 69: 42,69 BAD (HHHHHH) +Size 70: 42,70 BAD (HHHHHH) +Size 71: 43,71 BAD (HHHHHH) +Size 72: 43,72 BAD (HHHHHH) +Size 73: 44,73 BAD (HHHHHH) +Size 74: 45,74 BAD (HHHHHH) +Size 75: 45,75 BAD (HHHHHH) +Size 76: 46,76 BAD (HHHHHH) +Size 77: 46,77 BAD (HHHHHH) +Size 78: 47,78 BAD (HHHHHH) +Size 79: 48,79 BAD (HHHHHH) +Size 80: 48,80 BAD (HHHHHH) +Size 81: 49,81 BAD (HHHHHH) +Size 82: 49,82 BAD (HHHHHH) +Size 83: 50,83 BAD (HHHHHH) +Size 84: 51,84 BAD (HHHHHH) +Size 85: 51,85 BAD (HHHHHH) +Size 86: 52,86 BAD (HHHHHH) +Size 87: 52,87 BAD (HHHHHH) +Size 88: 53,88 BAD (HHHHHH) +Size 89: 54,89 BAD (HHHHHH) +Size 90: 54,90 BAD (HHHHHH) +Size 91: 55,91 BAD (HHHHHH) +Size 92: 55,92 BAD (HHHHHH) +Size 93: 56,93 BAD (HHHHHH) +Size 94: 57,94 BAD (HHHHHH) +Size 95: 57,95 BAD (HHHHHH) +Size 96: 58,96 BAD (HHHHHH) +Size 97: 58,97 BAD (HHHHHH) +Size 98: 59,98 BAD (HHHHHH) +Size 99: 60,99 BAD (HHHHHH) +Size 100: 60,100 BAD (HHHHHH) diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt new file mode 100644 index 00000000000..ed3637eac1f --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP932.txt @@ -0,0 +1,630 @@ +======================================= +Code Page 932, Japanese, MS Gothic font +======================================= + +Options: -face-gothic -family 0x36 +Chars: A2 A3 2014 3044 30FC 4000 + +Vista +----- + +Size 1: 1,2 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 BAD (FFFFHH) +Size 4: 2,4 OK (HHHFFF) +Size 5: 3,5 OK (HHHFFF) +Size 6: 3,6 OK (HHHFFF) +Size 7: 4,7 OK (HHHFFF) +Size 8: 4,8 OK (HHHFFF) +Size 9: 5,9 OK (HHHFFF) +Size 10: 5,10 OK (HHHFFF) +Size 11: 6,11 OK (HHHFFF) +Size 12: 6,12 OK (HHHFFF) +Size 13: 7,13 OK (HHHFFF) +Size 14: 7,14 BAD (HHHFHH) +Size 15: 8,15 OK (HHHFFF) +Size 16: 8,16 BAD (HHHFHH) +Size 17: 9,17 OK (HHHFFF) +Size 18: 9,18 BAD (HHHFHH) +Size 19: 10,19 OK (HHHFFF) +Size 20: 10,20 BAD (HHHFHH) +Size 21: 11,21 OK (HHHFFF) +Size 22: 11,22 BAD (HHHFHH) +Size 23: 12,23 BAD (HHHFHH) +Size 24: 12,24 BAD (HHHFHH) +Size 25: 13,25 BAD (HHHFHH) +Size 26: 13,26 BAD (HHHFHH) +Size 27: 14,27 BAD (HHHFHH) +Size 28: 14,28 BAD (HHHFHH) +Size 29: 15,29 BAD (HHHFHH) +Size 30: 15,30 BAD (HHHFHH) +Size 31: 16,31 BAD (HHHFHH) +Size 32: 16,33 BAD (HHHFHH) +Size 33: 17,33 BAD (HHHFHH) +Size 34: 17,34 BAD (HHHFHH) +Size 35: 18,35 BAD (HHHFHH) +Size 36: 18,36 BAD (HHHFHH) +Size 37: 19,37 BAD (HHHFHH) +Size 38: 19,38 BAD (HHHFHH) +Size 39: 20,39 BAD (HHHFHH) +Size 40: 20,40 BAD (HHHFHH) +Size 41: 21,41 BAD (HHHFHH) +Size 42: 21,42 BAD (HHHFHH) +Size 43: 22,43 BAD (HHHFHH) +Size 44: 22,44 BAD (HHHFHH) +Size 45: 23,45 BAD (HHHFHH) +Size 46: 23,46 BAD (HHHFHH) +Size 47: 24,47 BAD (HHHFHH) +Size 48: 24,48 BAD (HHHFHH) +Size 49: 25,49 BAD (HHHFHH) +Size 50: 25,50 BAD (HHHFHH) +Size 51: 26,51 BAD (HHHFHH) +Size 52: 26,52 BAD (HHHFHH) +Size 53: 27,53 BAD (HHHFHH) +Size 54: 27,54 BAD (HHHFHH) +Size 55: 28,55 BAD (HHHFHH) +Size 56: 28,56 BAD (HHHFHH) +Size 57: 29,57 BAD (HHHFHH) +Size 58: 29,58 BAD (HHHFHH) +Size 59: 30,59 BAD (HHHFHH) +Size 60: 30,60 BAD (HHHFHH) +Size 61: 31,61 BAD (HHHFHH) +Size 62: 31,62 BAD (HHHFHH) +Size 63: 32,63 BAD (HHHFHH) +Size 64: 32,64 BAD (HHHFHH) +Size 65: 33,65 BAD (HHHFHH) +Size 66: 33,66 BAD (HHHFHH) +Size 67: 34,67 BAD (HHHFHH) +Size 68: 34,68 BAD (HHHFHH) +Size 69: 35,69 BAD (HHHFHH) +Size 70: 35,70 BAD (HHHFHH) +Size 71: 36,71 BAD (HHHFHH) +Size 72: 36,72 BAD (HHHFHH) +Size 73: 37,73 BAD (HHHFHH) +Size 74: 37,74 BAD (HHHFHH) +Size 75: 38,75 BAD (HHHFHH) +Size 76: 38,76 BAD (HHHFHH) +Size 77: 39,77 BAD (HHHFHH) +Size 78: 39,78 BAD (HHHFHH) +Size 79: 40,79 BAD (HHHFHH) +Size 80: 40,80 BAD (HHHFHH) +Size 81: 41,81 BAD (HHHFHH) +Size 82: 41,82 BAD (HHHFHH) +Size 83: 42,83 BAD (HHHFHH) +Size 84: 42,84 BAD (HHHFHH) +Size 85: 43,85 BAD (HHHFHH) +Size 86: 43,86 BAD (HHHFHH) +Size 87: 44,87 BAD (HHHFHH) +Size 88: 44,88 BAD (HHHFHH) +Size 89: 45,89 BAD (HHHFHH) +Size 90: 45,90 BAD (HHHFHH) +Size 91: 46,91 BAD (HHHFHH) +Size 92: 46,92 BAD (HHHFHH) +Size 93: 47,93 BAD (HHHFHH) +Size 94: 47,94 BAD (HHHFHH) +Size 95: 48,95 BAD (HHHFHH) +Size 96: 48,97 BAD (HHHFHH) +Size 97: 49,97 BAD (HHHFHH) +Size 98: 49,98 BAD (HHHFHH) +Size 99: 50,99 BAD (HHHFHH) +Size 100: 50,100 BAD (HHHFHH) + +Windows 7 +--------- + +Size 1: 1,2 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 BAD (FFFFHH) +Size 4: 2,4 OK (HHHFFF) +Size 5: 3,5 OK (HHHFFF) +Size 6: 3,6 OK (HHHFFF) +Size 7: 4,7 OK (HHHFFF) +Size 8: 4,8 OK (HHHFFF) +Size 9: 5,9 OK (HHHFFF) +Size 10: 5,10 OK (HHHFFF) +Size 11: 6,11 OK (HHHFFF) +Size 12: 6,12 OK (HHHFFF) +Size 13: 7,13 OK (HHHFFF) +Size 14: 7,14 BAD (FFFFFF) +Size 15: 8,15 OK (HHHFFF) +Size 16: 8,16 BAD (FFFFFF) +Size 17: 9,17 OK (HHHFFF) +Size 18: 9,18 BAD (FFFFFF) +Size 19: 10,19 OK (HHHFFF) +Size 20: 10,20 BAD (FFFFFF) +Size 21: 11,21 OK (HHHFFF) +Size 22: 11,22 BAD (FFFFFF) +Size 23: 12,23 BAD (FFFFFF) +Size 24: 12,24 BAD (FFFFFF) +Size 25: 13,25 BAD (FFFFFF) +Size 26: 13,26 BAD (FFFFFF) +Size 27: 14,27 BAD (FFFFFF) +Size 28: 14,28 BAD (FFFFFF) +Size 29: 15,29 BAD (FFFFFF) +Size 30: 15,30 BAD (FFFFFF) +Size 31: 16,31 BAD (FFFFFF) +Size 32: 16,33 BAD (FFFFFF) +Size 33: 17,33 BAD (FFFFFF) +Size 34: 17,34 BAD (FFFFFF) +Size 35: 18,35 BAD (FFFFFF) +Size 36: 18,36 BAD (FFFFFF) +Size 37: 19,37 BAD (FFFFFF) +Size 38: 19,38 BAD (FFFFFF) +Size 39: 20,39 BAD (FFFFFF) +Size 40: 20,40 BAD (FFFFFF) +Size 41: 21,41 BAD (FFFFFF) +Size 42: 21,42 BAD (FFFFFF) +Size 43: 22,43 BAD (FFFFFF) +Size 44: 22,44 BAD (FFFFFF) +Size 45: 23,45 BAD (FFFFFF) +Size 46: 23,46 BAD (FFFFFF) +Size 47: 24,47 BAD (FFFFFF) +Size 48: 24,48 BAD (FFFFFF) +Size 49: 25,49 BAD (FFFFFF) +Size 50: 25,50 BAD (FFFFFF) +Size 51: 26,51 BAD (FFFFFF) +Size 52: 26,52 BAD (FFFFFF) +Size 53: 27,53 BAD (FFFFFF) +Size 54: 27,54 BAD (FFFFFF) +Size 55: 28,55 BAD (FFFFFF) +Size 56: 28,56 BAD (FFFFFF) +Size 57: 29,57 BAD (FFFFFF) +Size 58: 29,58 BAD (FFFFFF) +Size 59: 30,59 BAD (FFFFFF) +Size 60: 30,60 BAD (FFFFFF) +Size 61: 31,61 BAD (FFFFFF) +Size 62: 31,62 BAD (FFFFFF) +Size 63: 32,63 BAD (FFFFFF) +Size 64: 32,64 BAD (FFFFFF) +Size 65: 33,65 BAD (FFFFFF) +Size 66: 33,66 BAD (FFFFFF) +Size 67: 34,67 BAD (FFFFFF) +Size 68: 34,68 BAD (FFFFFF) +Size 69: 35,69 BAD (FFFFFF) +Size 70: 35,70 BAD (FFFFFF) +Size 71: 36,71 BAD (FFFFFF) +Size 72: 36,72 BAD (FFFFFF) +Size 73: 37,73 BAD (FFFFFF) +Size 74: 37,74 BAD (FFFFFF) +Size 75: 38,75 BAD (FFFFFF) +Size 76: 38,76 BAD (FFFFFF) +Size 77: 39,77 BAD (FFFFFF) +Size 78: 39,78 BAD (FFFFFF) +Size 79: 40,79 BAD (FFFFFF) +Size 80: 40,80 BAD (FFFFFF) +Size 81: 41,81 BAD (FFFFFF) +Size 82: 41,82 BAD (FFFFFF) +Size 83: 42,83 BAD (FFFFFF) +Size 84: 42,84 BAD (FFFFFF) +Size 85: 43,85 BAD (FFFFFF) +Size 86: 43,86 BAD (FFFFFF) +Size 87: 44,87 BAD (FFFFFF) +Size 88: 44,88 BAD (FFFFFF) +Size 89: 45,89 BAD (FFFFFF) +Size 90: 45,90 BAD (FFFFFF) +Size 91: 46,91 BAD (FFFFFF) +Size 92: 46,92 BAD (FFFFFF) +Size 93: 47,93 BAD (FFFFFF) +Size 94: 47,94 BAD (FFFFFF) +Size 95: 48,95 BAD (FFFFFF) +Size 96: 48,97 BAD (FFFFFF) +Size 97: 49,97 BAD (FFFFFF) +Size 98: 49,98 BAD (FFFFFF) +Size 99: 50,99 BAD (FFFFFF) +Size 100: 50,100 BAD (FFFFFF) + +Windows 8 +--------- + +Size 1: 1,2 BAD (FFFFHH) +Size 2: 1,2 BAD (FFFFHH) +Size 3: 2,3 BAD (FFFFFF) +Size 4: 2,4 BAD (FFFFHH) +Size 5: 3,5 BAD (FFFFFF) +Size 6: 3,6 BAD (FFFFHH) +Size 7: 4,7 BAD (FFFFFF) +Size 8: 4,8 BAD (FFFFHH) +Size 9: 5,9 BAD (FFFFFF) +Size 10: 5,10 BAD (FFFFHH) +Size 11: 6,11 BAD (FFFFFF) +Size 12: 6,12 BAD (FFFFHH) +Size 13: 7,13 BAD (FFFFFF) +Size 14: 7,14 BAD (FFFFHH) +Size 15: 8,15 BAD (FFFFFF) +Size 16: 8,16 BAD (FFFFHH) +Size 17: 9,17 BAD (FFFFFF) +Size 18: 9,18 BAD (FFFFHH) +Size 19: 10,19 BAD (FFFFFF) +Size 20: 10,20 BAD (FFFFFF) +Size 21: 11,21 BAD (FFFFFF) +Size 22: 11,22 BAD (FFFFFF) +Size 23: 12,23 BAD (FFFFFF) +Size 24: 12,24 BAD (FFFFFF) +Size 25: 13,25 BAD (FFFFFF) +Size 26: 13,26 BAD (FFFFFF) +Size 27: 14,27 BAD (FFFFFF) +Size 28: 14,28 BAD (FFFFFF) +Size 29: 15,29 BAD (FFFFFF) +Size 30: 15,30 BAD (FFFFFF) +Size 31: 16,31 BAD (FFFFFF) +Size 32: 16,33 BAD (FFFFFF) +Size 33: 17,33 BAD (FFFFFF) +Size 34: 17,34 BAD (FFFFFF) +Size 35: 18,35 BAD (FFFFFF) +Size 36: 18,36 BAD (FFFFFF) +Size 37: 19,37 BAD (FFFFFF) +Size 38: 19,38 BAD (FFFFFF) +Size 39: 20,39 BAD (FFFFFF) +Size 40: 20,40 BAD (FFFFFF) +Size 41: 21,41 BAD (FFFFFF) +Size 42: 21,42 BAD (FFFFFF) +Size 43: 22,43 BAD (FFFFFF) +Size 44: 22,44 BAD (FFFFFF) +Size 45: 23,45 BAD (FFFFFF) +Size 46: 23,46 BAD (FFFFFF) +Size 47: 24,47 BAD (FFFFFF) +Size 48: 24,48 BAD (FFFFFF) +Size 49: 25,49 BAD (FFFFFF) +Size 50: 25,50 BAD (FFFFFF) +Size 51: 26,51 BAD (FFFFFF) +Size 52: 26,52 BAD (FFFFFF) +Size 53: 27,53 BAD (FFFFFF) +Size 54: 27,54 BAD (FFFFFF) +Size 55: 28,55 BAD (FFFFFF) +Size 56: 28,56 BAD (FFFFFF) +Size 57: 29,57 BAD (FFFFFF) +Size 58: 29,58 BAD (FFFFFF) +Size 59: 30,59 BAD (FFFFFF) +Size 60: 30,60 BAD (FFFFFF) +Size 61: 31,61 BAD (FFFFFF) +Size 62: 31,62 BAD (FFFFFF) +Size 63: 32,63 BAD (FFFFFF) +Size 64: 32,64 BAD (FFFFFF) +Size 65: 33,65 BAD (FFFFFF) +Size 66: 33,66 BAD (FFFFFF) +Size 67: 34,67 BAD (FFFFFF) +Size 68: 34,68 BAD (FFFFFF) +Size 69: 35,69 BAD (FFFFFF) +Size 70: 35,70 BAD (FFFFFF) +Size 71: 36,71 BAD (FFFFFF) +Size 72: 36,72 BAD (FFFFFF) +Size 73: 37,73 BAD (FFFFFF) +Size 74: 37,74 BAD (FFFFFF) +Size 75: 38,75 BAD (FFFFFF) +Size 76: 38,76 BAD (FFFFFF) +Size 77: 39,77 BAD (FFFFFF) +Size 78: 39,78 BAD (FFFFFF) +Size 79: 40,79 BAD (FFFFFF) +Size 80: 40,80 BAD (FFFFFF) +Size 81: 41,81 BAD (FFFFFF) +Size 82: 41,82 BAD (FFFFFF) +Size 83: 42,83 BAD (FFFFFF) +Size 84: 42,84 BAD (FFFFFF) +Size 85: 43,85 BAD (FFFFFF) +Size 86: 43,86 BAD (FFFFFF) +Size 87: 44,87 BAD (FFFFFF) +Size 88: 44,88 BAD (FFFFFF) +Size 89: 45,89 BAD (FFFFFF) +Size 90: 45,90 BAD (FFFFFF) +Size 91: 46,91 BAD (FFFFFF) +Size 92: 46,92 BAD (FFFFFF) +Size 93: 47,93 BAD (FFFFFF) +Size 94: 47,94 BAD (FFFFFF) +Size 95: 48,95 BAD (FFFFFF) +Size 96: 48,97 BAD (FFFFFF) +Size 97: 49,97 BAD (FFFFFF) +Size 98: 49,98 BAD (FFFFFF) +Size 99: 50,99 BAD (FFFFFF) +Size 100: 50,100 BAD (FFFFFF) + +Windows 8.1 +----------- + +Size 1: 1,2 BAD (FFFFHH) +Size 2: 1,2 BAD (FFFFHH) +Size 3: 2,3 BAD (FFFFFF) +Size 4: 2,4 BAD (FFFFHH) +Size 5: 3,5 BAD (FFFFFF) +Size 6: 3,6 BAD (FFFFHH) +Size 7: 4,7 BAD (FFFFFF) +Size 8: 4,8 BAD (FFFFHH) +Size 9: 5,9 BAD (FFFFFF) +Size 10: 5,10 BAD (FFFFHH) +Size 11: 6,11 BAD (FFFFFF) +Size 12: 6,12 BAD (FFFFHH) +Size 13: 7,13 BAD (FFFFFF) +Size 14: 7,14 BAD (FFFFHH) +Size 15: 8,15 BAD (FFFFFF) +Size 16: 8,16 BAD (FFFFHH) +Size 17: 9,17 BAD (FFFFFF) +Size 18: 9,18 BAD (FFFFHH) +Size 19: 10,19 BAD (FFFFFF) +Size 20: 10,20 BAD (FFFFFF) +Size 21: 11,21 BAD (FFFFFF) +Size 22: 11,22 BAD (FFFFFF) +Size 23: 12,23 BAD (FFFFFF) +Size 24: 12,24 BAD (FFFFFF) +Size 25: 13,25 BAD (FFFFFF) +Size 26: 13,26 BAD (FFFFFF) +Size 27: 14,27 BAD (FFFFFF) +Size 28: 14,28 BAD (FFFFFF) +Size 29: 15,29 BAD (FFFFFF) +Size 30: 15,30 BAD (FFFFFF) +Size 31: 16,31 BAD (FFFFFF) +Size 32: 16,33 BAD (FFFFFF) +Size 33: 17,33 BAD (FFFFFF) +Size 34: 17,34 BAD (FFFFFF) +Size 35: 18,35 BAD (FFFFFF) +Size 36: 18,36 BAD (FFFFFF) +Size 37: 19,37 BAD (FFFFFF) +Size 38: 19,38 BAD (FFFFFF) +Size 39: 20,39 BAD (FFFFFF) +Size 40: 20,40 BAD (FFFFFF) +Size 41: 21,41 BAD (FFFFFF) +Size 42: 21,42 BAD (FFFFFF) +Size 43: 22,43 BAD (FFFFFF) +Size 44: 22,44 BAD (FFFFFF) +Size 45: 23,45 BAD (FFFFFF) +Size 46: 23,46 BAD (FFFFFF) +Size 47: 24,47 BAD (FFFFFF) +Size 48: 24,48 BAD (FFFFFF) +Size 49: 25,49 BAD (FFFFFF) +Size 50: 25,50 BAD (FFFFFF) +Size 51: 26,51 BAD (FFFFFF) +Size 52: 26,52 BAD (FFFFFF) +Size 53: 27,53 BAD (FFFFFF) +Size 54: 27,54 BAD (FFFFFF) +Size 55: 28,55 BAD (FFFFFF) +Size 56: 28,56 BAD (FFFFFF) +Size 57: 29,57 BAD (FFFFFF) +Size 58: 29,58 BAD (FFFFFF) +Size 59: 30,59 BAD (FFFFFF) +Size 60: 30,60 BAD (FFFFFF) +Size 61: 31,61 BAD (FFFFFF) +Size 62: 31,62 BAD (FFFFFF) +Size 63: 32,63 BAD (FFFFFF) +Size 64: 32,64 BAD (FFFFFF) +Size 65: 33,65 BAD (FFFFFF) +Size 66: 33,66 BAD (FFFFFF) +Size 67: 34,67 BAD (FFFFFF) +Size 68: 34,68 BAD (FFFFFF) +Size 69: 35,69 BAD (FFFFFF) +Size 70: 35,70 BAD (FFFFFF) +Size 71: 36,71 BAD (FFFFFF) +Size 72: 36,72 BAD (FFFFFF) +Size 73: 37,73 BAD (FFFFFF) +Size 74: 37,74 BAD (FFFFFF) +Size 75: 38,75 BAD (FFFFFF) +Size 76: 38,76 BAD (FFFFFF) +Size 77: 39,77 BAD (FFFFFF) +Size 78: 39,78 BAD (FFFFFF) +Size 79: 40,79 BAD (FFFFFF) +Size 80: 40,80 BAD (FFFFFF) +Size 81: 41,81 BAD (FFFFFF) +Size 82: 41,82 BAD (FFFFFF) +Size 83: 42,83 BAD (FFFFFF) +Size 84: 42,84 BAD (FFFFFF) +Size 85: 43,85 BAD (FFFFFF) +Size 86: 43,86 BAD (FFFFFF) +Size 87: 44,87 BAD (FFFFFF) +Size 88: 44,88 BAD (FFFFFF) +Size 89: 45,89 BAD (FFFFFF) +Size 90: 45,90 BAD (FFFFFF) +Size 91: 46,91 BAD (FFFFFF) +Size 92: 46,92 BAD (FFFFFF) +Size 93: 47,93 BAD (FFFFFF) +Size 94: 47,94 BAD (FFFFFF) +Size 95: 48,95 BAD (FFFFFF) +Size 96: 48,97 BAD (FFFFFF) +Size 97: 49,97 BAD (FFFFFF) +Size 98: 49,98 BAD (FFFFFF) +Size 99: 50,99 BAD (FFFFFF) +Size 100: 50,100 BAD (FFFFFF) + +Windows 10 14342 Old Console +---------------------------- + +Size 1: 1,2 BAD (FFFFHH) +Size 2: 1,2 BAD (FFFFHH) +Size 3: 2,3 BAD (FFFFFF) +Size 4: 2,4 BAD (FFFFHH) +Size 5: 3,5 BAD (FFFFFF) +Size 6: 3,6 BAD (FFFFHH) +Size 7: 4,7 BAD (FFFFFF) +Size 8: 4,8 BAD (FFFFHH) +Size 9: 5,9 BAD (FFFFFF) +Size 10: 5,10 BAD (FFFFHH) +Size 11: 6,11 BAD (FFFFFF) +Size 12: 6,12 BAD (FFFFHH) +Size 13: 7,13 BAD (FFFFFF) +Size 14: 7,14 BAD (FFFFHH) +Size 15: 8,15 BAD (FFFFFF) +Size 16: 8,16 BAD (FFFFHH) +Size 17: 9,17 BAD (FFFFFF) +Size 18: 9,18 BAD (FFFFHH) +Size 19: 10,19 BAD (FFFFFF) +Size 20: 10,20 BAD (FFFFFF) +Size 21: 11,21 BAD (FFFFFF) +Size 22: 11,22 BAD (FFFFFF) +Size 23: 12,23 BAD (FFFFFF) +Size 24: 12,24 BAD (FFFFFF) +Size 25: 13,25 BAD (FFFFFF) +Size 26: 13,26 BAD (FFFFFF) +Size 27: 14,27 BAD (FFFFFF) +Size 28: 14,28 BAD (FFFFFF) +Size 29: 15,29 BAD (FFFFFF) +Size 30: 15,30 BAD (FFFFFF) +Size 31: 16,31 BAD (FFFFFF) +Size 32: 16,33 BAD (FFFFFF) +Size 33: 17,33 BAD (FFFFFF) +Size 34: 17,34 BAD (FFFFFF) +Size 35: 18,35 BAD (FFFFFF) +Size 36: 18,36 BAD (FFFFFF) +Size 37: 19,37 BAD (FFFFFF) +Size 38: 19,38 BAD (FFFFFF) +Size 39: 20,39 BAD (FFFFFF) +Size 40: 20,40 BAD (FFFFFF) +Size 41: 21,41 BAD (FFFFFF) +Size 42: 21,42 BAD (FFFFFF) +Size 43: 22,43 BAD (FFFFFF) +Size 44: 22,44 BAD (FFFFFF) +Size 45: 23,45 BAD (FFFFFF) +Size 46: 23,46 BAD (FFFFFF) +Size 47: 24,47 BAD (FFFFFF) +Size 48: 24,48 BAD (FFFFFF) +Size 49: 25,49 BAD (FFFFFF) +Size 50: 25,50 BAD (FFFFFF) +Size 51: 26,51 BAD (FFFFFF) +Size 52: 26,52 BAD (FFFFFF) +Size 53: 27,53 BAD (FFFFFF) +Size 54: 27,54 BAD (FFFFFF) +Size 55: 28,55 BAD (FFFFFF) +Size 56: 28,56 BAD (FFFFFF) +Size 57: 29,57 BAD (FFFFFF) +Size 58: 29,58 BAD (FFFFFF) +Size 59: 30,59 BAD (FFFFFF) +Size 60: 30,60 BAD (FFFFFF) +Size 61: 31,61 BAD (FFFFFF) +Size 62: 31,62 BAD (FFFFFF) +Size 63: 32,63 BAD (FFFFFF) +Size 64: 32,64 BAD (FFFFFF) +Size 65: 33,65 BAD (FFFFFF) +Size 66: 33,66 BAD (FFFFFF) +Size 67: 34,67 BAD (FFFFFF) +Size 68: 34,68 BAD (FFFFFF) +Size 69: 35,69 BAD (FFFFFF) +Size 70: 35,70 BAD (FFFFFF) +Size 71: 36,71 BAD (FFFFFF) +Size 72: 36,72 BAD (FFFFFF) +Size 73: 37,73 BAD (FFFFFF) +Size 74: 37,74 BAD (FFFFFF) +Size 75: 38,75 BAD (FFFFFF) +Size 76: 38,76 BAD (FFFFFF) +Size 77: 39,77 BAD (FFFFFF) +Size 78: 39,78 BAD (FFFFFF) +Size 79: 40,79 BAD (FFFFFF) +Size 80: 40,80 BAD (FFFFFF) +Size 81: 41,81 BAD (FFFFFF) +Size 82: 41,82 BAD (FFFFFF) +Size 83: 42,83 BAD (FFFFFF) +Size 84: 42,84 BAD (FFFFFF) +Size 85: 43,85 BAD (FFFFFF) +Size 86: 43,86 BAD (FFFFFF) +Size 87: 44,87 BAD (FFFFFF) +Size 88: 44,88 BAD (FFFFFF) +Size 89: 45,89 BAD (FFFFFF) +Size 90: 45,90 BAD (FFFFFF) +Size 91: 46,91 BAD (FFFFFF) +Size 92: 46,92 BAD (FFFFFF) +Size 93: 47,93 BAD (FFFFFF) +Size 94: 47,94 BAD (FFFFFF) +Size 95: 48,95 BAD (FFFFFF) +Size 96: 48,97 BAD (FFFFFF) +Size 97: 49,97 BAD (FFFFFF) +Size 98: 49,98 BAD (FFFFFF) +Size 99: 50,99 BAD (FFFFFF) +Size 100: 50,100 BAD (FFFFFF) + +Windows 10 14342 New Console +---------------------------- + +Size 1: 1,1 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 OK (HHHFFF) +Size 4: 2,4 OK (HHHFFF) +Size 5: 3,5 OK (HHHFFF) +Size 6: 3,6 OK (HHHFFF) +Size 7: 4,7 OK (HHHFFF) +Size 8: 4,8 OK (HHHFFF) +Size 9: 5,9 OK (HHHFFF) +Size 10: 5,10 OK (HHHFFF) +Size 11: 6,11 OK (HHHFFF) +Size 12: 6,12 OK (HHHFFF) +Size 13: 7,13 OK (HHHFFF) +Size 14: 7,14 OK (HHHFFF) +Size 15: 8,15 OK (HHHFFF) +Size 16: 8,16 OK (HHHFFF) +Size 17: 9,17 OK (HHHFFF) +Size 18: 9,18 OK (HHHFFF) +Size 19: 10,19 OK (HHHFFF) +Size 20: 10,20 OK (HHHFFF) +Size 21: 11,21 OK (HHHFFF) +Size 22: 11,22 OK (HHHFFF) +Size 23: 12,23 OK (HHHFFF) +Size 24: 12,24 OK (HHHFFF) +Size 25: 13,25 OK (HHHFFF) +Size 26: 13,26 OK (HHHFFF) +Size 27: 14,27 OK (HHHFFF) +Size 28: 14,28 OK (HHHFFF) +Size 29: 15,29 OK (HHHFFF) +Size 30: 15,30 OK (HHHFFF) +Size 31: 16,31 OK (HHHFFF) +Size 32: 16,32 OK (HHHFFF) +Size 33: 17,33 OK (HHHFFF) +Size 34: 17,34 OK (HHHFFF) +Size 35: 18,35 OK (HHHFFF) +Size 36: 18,36 OK (HHHFFF) +Size 37: 19,37 OK (HHHFFF) +Size 38: 19,38 OK (HHHFFF) +Size 39: 20,39 OK (HHHFFF) +Size 40: 20,40 OK (HHHFFF) +Size 41: 21,41 OK (HHHFFF) +Size 42: 21,42 OK (HHHFFF) +Size 43: 22,43 OK (HHHFFF) +Size 44: 22,44 OK (HHHFFF) +Size 45: 23,45 OK (HHHFFF) +Size 46: 23,46 OK (HHHFFF) +Size 47: 24,47 OK (HHHFFF) +Size 48: 24,48 OK (HHHFFF) +Size 49: 25,49 OK (HHHFFF) +Size 50: 25,50 OK (HHHFFF) +Size 51: 26,51 OK (HHHFFF) +Size 52: 26,52 OK (HHHFFF) +Size 53: 27,53 OK (HHHFFF) +Size 54: 27,54 OK (HHHFFF) +Size 55: 28,55 OK (HHHFFF) +Size 56: 28,56 OK (HHHFFF) +Size 57: 29,57 OK (HHHFFF) +Size 58: 29,58 OK (HHHFFF) +Size 59: 30,59 OK (HHHFFF) +Size 60: 30,60 OK (HHHFFF) +Size 61: 31,61 OK (HHHFFF) +Size 62: 31,62 OK (HHHFFF) +Size 63: 32,63 OK (HHHFFF) +Size 64: 32,64 OK (HHHFFF) +Size 65: 33,65 OK (HHHFFF) +Size 66: 33,66 OK (HHHFFF) +Size 67: 34,67 OK (HHHFFF) +Size 68: 34,68 OK (HHHFFF) +Size 69: 35,69 OK (HHHFFF) +Size 70: 35,70 OK (HHHFFF) +Size 71: 36,71 OK (HHHFFF) +Size 72: 36,72 OK (HHHFFF) +Size 73: 37,73 OK (HHHFFF) +Size 74: 37,74 OK (HHHFFF) +Size 75: 38,75 OK (HHHFFF) +Size 76: 38,76 OK (HHHFFF) +Size 77: 39,77 OK (HHHFFF) +Size 78: 39,78 OK (HHHFFF) +Size 79: 40,79 OK (HHHFFF) +Size 80: 40,80 OK (HHHFFF) +Size 81: 41,81 OK (HHHFFF) +Size 82: 41,82 OK (HHHFFF) +Size 83: 42,83 OK (HHHFFF) +Size 84: 42,84 OK (HHHFFF) +Size 85: 43,85 OK (HHHFFF) +Size 86: 43,86 OK (HHHFFF) +Size 87: 44,87 OK (HHHFFF) +Size 88: 44,88 OK (HHHFFF) +Size 89: 45,89 OK (HHHFFF) +Size 90: 45,90 OK (HHHFFF) +Size 91: 46,91 OK (HHHFFF) +Size 92: 46,92 OK (HHHFFF) +Size 93: 47,93 OK (HHHFFF) +Size 94: 47,94 OK (HHHFFF) +Size 95: 48,95 OK (HHHFFF) +Size 96: 48,96 OK (HHHFFF) +Size 97: 49,97 OK (HHHFFF) +Size 98: 49,98 OK (HHHFFF) +Size 99: 50,99 OK (HHHFFF) +Size 100: 50,100 OK (HHHFFF) diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt new file mode 100644 index 00000000000..43210dac518 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP936.txt @@ -0,0 +1,630 @@ +========================================================== +Code Page 936, Chinese Simplified (China/PRC), SimSun font +========================================================== + +Options: -face-simsun -family 0x36 +Chars: A2 A3 2014 3044 30FC 4000 + +Vista +----- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,3 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (HHHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (HHHFHH) +Size 8: 4,9 GOOD (HHFFFF) +Size 9: 5,10 BAD (HHHFHH) +Size 10: 5,11 GOOD (HHFFFF) +Size 11: 6,13 BAD (HHHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,15 BAD (HHHFHH) +Size 14: 7,16 GOOD (HHFFFF) +Size 15: 8,17 BAD (HHHFHH) +Size 16: 8,18 GOOD (HHFFFF) +Size 17: 9,19 BAD (HHHFHH) +Size 18: 9,21 GOOD (HHFFFF) +Size 19: 10,22 BAD (HHHFHH) +Size 20: 10,23 GOOD (HHFFFF) +Size 21: 11,24 BAD (HHHFHH) +Size 22: 11,25 GOOD (HHFFFF) +Size 23: 12,26 BAD (HHHFHH) +Size 24: 12,27 GOOD (HHFFFF) +Size 25: 13,29 BAD (HHHFHH) +Size 26: 13,30 GOOD (HHFFFF) +Size 27: 14,31 BAD (HHHFHH) +Size 28: 14,32 GOOD (HHFFFF) +Size 29: 15,33 BAD (HHHFHH) +Size 30: 15,34 GOOD (HHFFFF) +Size 31: 16,35 BAD (HHHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,38 BAD (HHHFHH) +Size 34: 17,39 GOOD (HHFFFF) +Size 35: 18,40 BAD (HHHFHH) +Size 36: 18,41 GOOD (HHFFFF) +Size 37: 19,42 BAD (HHHFHH) +Size 38: 19,43 GOOD (HHFFFF) +Size 39: 20,44 BAD (HHHFHH) +Size 40: 20,46 GOOD (HHFFFF) +Size 41: 21,47 BAD (HHHFHH) +Size 42: 21,48 GOOD (HHFFFF) +Size 43: 22,49 BAD (HHHFHH) +Size 44: 22,50 GOOD (HHFFFF) +Size 45: 23,51 BAD (HHHFHH) +Size 46: 23,52 GOOD (HHFFFF) +Size 47: 24,54 BAD (HHHFHH) +Size 48: 24,55 GOOD (HHFFFF) +Size 49: 25,56 BAD (HHHFHH) +Size 50: 25,57 GOOD (HHFFFF) +Size 51: 26,58 BAD (HHHFHH) +Size 52: 26,59 GOOD (HHFFFF) +Size 53: 27,60 BAD (HHHFHH) +Size 54: 27,62 GOOD (HHFFFF) +Size 55: 28,63 BAD (HHHFHH) +Size 56: 28,64 GOOD (HHFFFF) +Size 57: 29,65 BAD (HHHFHH) +Size 58: 29,66 GOOD (HHFFFF) +Size 59: 30,67 BAD (HHHFHH) +Size 60: 30,68 GOOD (HHFFFF) +Size 61: 31,70 BAD (HHHFHH) +Size 62: 31,71 GOOD (HHFFFF) +Size 63: 32,72 BAD (HHHFHH) +Size 64: 32,73 GOOD (HHFFFF) +Size 65: 33,74 GOOD (HHFFFF) +Size 66: 33,75 GOOD (HHFFFF) +Size 67: 34,76 GOOD (HHFFFF) +Size 68: 34,78 GOOD (HHFFFF) +Size 69: 35,79 GOOD (HHFFFF) +Size 70: 35,80 GOOD (HHFFFF) +Size 71: 36,81 GOOD (HHFFFF) +Size 72: 36,82 GOOD (HHFFFF) +Size 73: 37,83 GOOD (HHFFFF) +Size 74: 37,84 GOOD (HHFFFF) +Size 75: 38,86 GOOD (HHFFFF) +Size 76: 38,87 GOOD (HHFFFF) +Size 77: 39,88 GOOD (HHFFFF) +Size 78: 39,89 GOOD (HHFFFF) +Size 79: 40,90 GOOD (HHFFFF) +Size 80: 40,91 GOOD (HHFFFF) +Size 81: 41,92 GOOD (HHFFFF) +Size 82: 41,94 GOOD (HHFFFF) +Size 83: 42,95 GOOD (HHFFFF) +Size 84: 42,96 GOOD (HHFFFF) +Size 85: 43,97 GOOD (HHFFFF) +Size 86: 43,98 GOOD (HHFFFF) +Size 87: 44,99 GOOD (HHFFFF) +Size 88: 44,100 GOOD (HHFFFF) +Size 89: 45,102 GOOD (HHFFFF) +Size 90: 45,103 GOOD (HHFFFF) +Size 91: 46,104 GOOD (HHFFFF) +Size 92: 46,105 GOOD (HHFFFF) +Size 93: 47,106 GOOD (HHFFFF) +Size 94: 47,107 GOOD (HHFFFF) +Size 95: 48,108 GOOD (HHFFFF) +Size 96: 48,111 GOOD (HHFFFF) +Size 97: 49,111 GOOD (HHFFFF) +Size 98: 49,112 GOOD (HHFFFF) +Size 99: 50,113 GOOD (HHFFFF) +Size 100: 50,114 GOOD (HHFFFF) + +Windows 7 +--------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,3 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,9 GOOD (HHFFFF) +Size 9: 5,10 BAD (FFHFHH) +Size 10: 5,11 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,15 BAD (FFHFHH) +Size 14: 7,16 GOOD (HHFFFF) +Size 15: 8,17 BAD (FFHFHH) +Size 16: 8,18 GOOD (HHFFFF) +Size 17: 9,19 BAD (FFHFHH) +Size 18: 9,21 GOOD (HHFFFF) +Size 19: 10,22 BAD (FFHFHH) +Size 20: 10,23 GOOD (HHFFFF) +Size 21: 11,24 BAD (FFHFHH) +Size 22: 11,25 GOOD (HHFFFF) +Size 23: 12,26 BAD (FFHFHH) +Size 24: 12,27 GOOD (HHFFFF) +Size 25: 13,29 BAD (FFHFHH) +Size 26: 13,30 GOOD (HHFFFF) +Size 27: 14,31 BAD (FFHFHH) +Size 28: 14,32 GOOD (HHFFFF) +Size 29: 15,33 BAD (FFHFHH) +Size 30: 15,34 GOOD (HHFFFF) +Size 31: 16,35 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,38 BAD (FFHFHH) +Size 34: 17,39 GOOD (HHFFFF) +Size 35: 18,40 BAD (FFHFHH) +Size 36: 18,41 GOOD (HHFFFF) +Size 37: 19,42 BAD (FFHFHH) +Size 38: 19,43 GOOD (HHFFFF) +Size 39: 20,44 BAD (FFHFHH) +Size 40: 20,46 GOOD (HHFFFF) +Size 41: 21,47 BAD (FFHFHH) +Size 42: 21,48 GOOD (HHFFFF) +Size 43: 22,49 BAD (FFHFHH) +Size 44: 22,50 GOOD (HHFFFF) +Size 45: 23,51 BAD (FFHFHH) +Size 46: 23,52 GOOD (HHFFFF) +Size 47: 24,54 BAD (FFHFHH) +Size 48: 24,55 GOOD (HHFFFF) +Size 49: 25,56 BAD (FFHFHH) +Size 50: 25,57 GOOD (HHFFFF) +Size 51: 26,58 BAD (FFHFHH) +Size 52: 26,59 GOOD (HHFFFF) +Size 53: 27,60 BAD (FFHFHH) +Size 54: 27,62 GOOD (HHFFFF) +Size 55: 28,63 BAD (FFHFHH) +Size 56: 28,64 GOOD (HHFFFF) +Size 57: 29,65 BAD (FFHFHH) +Size 58: 29,66 GOOD (HHFFFF) +Size 59: 30,67 BAD (FFHFHH) +Size 60: 30,68 GOOD (HHFFFF) +Size 61: 31,70 BAD (FFHFHH) +Size 62: 31,71 GOOD (HHFFFF) +Size 63: 32,72 BAD (FFHFHH) +Size 64: 32,73 GOOD (HHFFFF) +Size 65: 33,74 GOOD (HHFFFF) +Size 66: 33,75 GOOD (HHFFFF) +Size 67: 34,76 GOOD (HHFFFF) +Size 68: 34,78 GOOD (HHFFFF) +Size 69: 35,79 GOOD (HHFFFF) +Size 70: 35,80 GOOD (HHFFFF) +Size 71: 36,81 GOOD (HHFFFF) +Size 72: 36,82 GOOD (HHFFFF) +Size 73: 37,83 GOOD (HHFFFF) +Size 74: 37,84 GOOD (HHFFFF) +Size 75: 38,86 GOOD (HHFFFF) +Size 76: 38,87 GOOD (HHFFFF) +Size 77: 39,88 GOOD (HHFFFF) +Size 78: 39,89 GOOD (HHFFFF) +Size 79: 40,90 GOOD (HHFFFF) +Size 80: 40,91 GOOD (HHFFFF) +Size 81: 41,92 GOOD (HHFFFF) +Size 82: 41,94 GOOD (HHFFFF) +Size 83: 42,95 GOOD (HHFFFF) +Size 84: 42,96 GOOD (HHFFFF) +Size 85: 43,97 GOOD (HHFFFF) +Size 86: 43,98 GOOD (HHFFFF) +Size 87: 44,99 GOOD (HHFFFF) +Size 88: 44,100 GOOD (HHFFFF) +Size 89: 45,102 GOOD (HHFFFF) +Size 90: 45,103 GOOD (HHFFFF) +Size 91: 46,104 GOOD (HHFFFF) +Size 92: 46,105 GOOD (HHFFFF) +Size 93: 47,106 GOOD (HHFFFF) +Size 94: 47,107 GOOD (HHFFFF) +Size 95: 48,108 GOOD (HHFFFF) +Size 96: 48,111 GOOD (HHFFFF) +Size 97: 49,111 GOOD (HHFFFF) +Size 98: 49,112 GOOD (HHFFFF) +Size 99: 50,113 GOOD (HHFFFF) +Size 100: 50,114 GOOD (HHFFFF) + +Windows 8 +--------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,3 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,9 GOOD (HHFFFF) +Size 9: 5,10 BAD (FFHFHH) +Size 10: 5,11 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,15 BAD (FFHFHH) +Size 14: 7,16 GOOD (HHFFFF) +Size 15: 8,17 BAD (FFHFHH) +Size 16: 8,18 GOOD (HHFFFF) +Size 17: 9,19 BAD (FFHFHH) +Size 18: 9,21 GOOD (HHFFFF) +Size 19: 10,22 BAD (FFHFHH) +Size 20: 10,23 GOOD (HHFFFF) +Size 21: 11,24 BAD (FFHFHH) +Size 22: 11,25 GOOD (HHFFFF) +Size 23: 12,26 BAD (FFHFHH) +Size 24: 12,27 GOOD (HHFFFF) +Size 25: 13,29 BAD (FFHFHH) +Size 26: 13,30 GOOD (HHFFFF) +Size 27: 14,31 BAD (FFHFHH) +Size 28: 14,32 GOOD (HHFFFF) +Size 29: 15,33 BAD (FFHFHH) +Size 30: 15,34 GOOD (HHFFFF) +Size 31: 16,35 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,38 BAD (FFHFHH) +Size 34: 17,39 GOOD (HHFFFF) +Size 35: 18,40 BAD (FFHFHH) +Size 36: 18,41 GOOD (HHFFFF) +Size 37: 19,42 BAD (FFHFHH) +Size 38: 19,43 GOOD (HHFFFF) +Size 39: 20,44 BAD (FFHFHH) +Size 40: 20,46 GOOD (HHFFFF) +Size 41: 21,47 BAD (FFHFHH) +Size 42: 21,48 GOOD (HHFFFF) +Size 43: 22,49 BAD (FFHFHH) +Size 44: 22,50 GOOD (HHFFFF) +Size 45: 23,51 BAD (FFHFHH) +Size 46: 23,52 GOOD (HHFFFF) +Size 47: 24,54 BAD (FFHFHH) +Size 48: 24,55 GOOD (HHFFFF) +Size 49: 25,56 BAD (FFHFHH) +Size 50: 25,57 GOOD (HHFFFF) +Size 51: 26,58 BAD (FFHFHH) +Size 52: 26,59 GOOD (HHFFFF) +Size 53: 27,60 BAD (FFHFHH) +Size 54: 27,62 GOOD (HHFFFF) +Size 55: 28,63 BAD (FFHFHH) +Size 56: 28,64 GOOD (HHFFFF) +Size 57: 29,65 BAD (FFHFHH) +Size 58: 29,66 GOOD (HHFFFF) +Size 59: 30,67 BAD (FFHFHH) +Size 60: 30,68 GOOD (HHFFFF) +Size 61: 31,70 BAD (FFHFHH) +Size 62: 31,71 GOOD (HHFFFF) +Size 63: 32,72 BAD (FFHFHH) +Size 64: 32,73 GOOD (HHFFFF) +Size 65: 33,74 GOOD (HHFFFF) +Size 66: 33,75 GOOD (HHFFFF) +Size 67: 34,76 GOOD (HHFFFF) +Size 68: 34,78 GOOD (HHFFFF) +Size 69: 35,79 GOOD (HHFFFF) +Size 70: 35,80 GOOD (HHFFFF) +Size 71: 36,81 GOOD (HHFFFF) +Size 72: 36,82 GOOD (HHFFFF) +Size 73: 37,83 GOOD (HHFFFF) +Size 74: 37,84 GOOD (HHFFFF) +Size 75: 38,86 GOOD (HHFFFF) +Size 76: 38,87 GOOD (HHFFFF) +Size 77: 39,88 GOOD (HHFFFF) +Size 78: 39,89 GOOD (HHFFFF) +Size 79: 40,90 GOOD (HHFFFF) +Size 80: 40,91 GOOD (HHFFFF) +Size 81: 41,92 GOOD (HHFFFF) +Size 82: 41,94 GOOD (HHFFFF) +Size 83: 42,95 GOOD (HHFFFF) +Size 84: 42,96 GOOD (HHFFFF) +Size 85: 43,97 GOOD (HHFFFF) +Size 86: 43,98 GOOD (HHFFFF) +Size 87: 44,99 GOOD (HHFFFF) +Size 88: 44,100 GOOD (HHFFFF) +Size 89: 45,102 GOOD (HHFFFF) +Size 90: 45,103 GOOD (HHFFFF) +Size 91: 46,104 GOOD (HHFFFF) +Size 92: 46,105 GOOD (HHFFFF) +Size 93: 47,106 GOOD (HHFFFF) +Size 94: 47,107 GOOD (HHFFFF) +Size 95: 48,108 GOOD (HHFFFF) +Size 96: 48,111 GOOD (HHFFFF) +Size 97: 49,111 GOOD (HHFFFF) +Size 98: 49,112 GOOD (HHFFFF) +Size 99: 50,113 GOOD (HHFFFF) +Size 100: 50,114 GOOD (HHFFFF) + +Windows 8.1 +----------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,3 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,9 GOOD (HHFFFF) +Size 9: 5,10 BAD (FFHFHH) +Size 10: 5,11 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,15 BAD (FFHFHH) +Size 14: 7,16 GOOD (HHFFFF) +Size 15: 8,17 BAD (FFHFHH) +Size 16: 8,18 GOOD (HHFFFF) +Size 17: 9,19 BAD (FFHFHH) +Size 18: 9,21 GOOD (HHFFFF) +Size 19: 10,22 BAD (FFHFHH) +Size 20: 10,23 GOOD (HHFFFF) +Size 21: 11,24 BAD (FFHFHH) +Size 22: 11,25 GOOD (HHFFFF) +Size 23: 12,26 BAD (FFHFHH) +Size 24: 12,27 GOOD (HHFFFF) +Size 25: 13,29 BAD (FFHFHH) +Size 26: 13,30 GOOD (HHFFFF) +Size 27: 14,31 BAD (FFHFHH) +Size 28: 14,32 GOOD (HHFFFF) +Size 29: 15,33 BAD (FFHFHH) +Size 30: 15,34 GOOD (HHFFFF) +Size 31: 16,35 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,38 BAD (FFHFHH) +Size 34: 17,39 GOOD (HHFFFF) +Size 35: 18,40 BAD (FFHFHH) +Size 36: 18,41 GOOD (HHFFFF) +Size 37: 19,42 BAD (FFHFHH) +Size 38: 19,43 GOOD (HHFFFF) +Size 39: 20,44 BAD (FFHFHH) +Size 40: 20,46 GOOD (HHFFFF) +Size 41: 21,47 BAD (FFHFHH) +Size 42: 21,48 GOOD (HHFFFF) +Size 43: 22,49 BAD (FFHFHH) +Size 44: 22,50 GOOD (HHFFFF) +Size 45: 23,51 BAD (FFHFHH) +Size 46: 23,52 GOOD (HHFFFF) +Size 47: 24,54 BAD (FFHFHH) +Size 48: 24,55 GOOD (HHFFFF) +Size 49: 25,56 BAD (FFHFHH) +Size 50: 25,57 GOOD (HHFFFF) +Size 51: 26,58 BAD (FFHFHH) +Size 52: 26,59 GOOD (HHFFFF) +Size 53: 27,60 BAD (FFHFHH) +Size 54: 27,62 GOOD (HHFFFF) +Size 55: 28,63 BAD (FFHFHH) +Size 56: 28,64 GOOD (HHFFFF) +Size 57: 29,65 BAD (FFHFHH) +Size 58: 29,66 GOOD (HHFFFF) +Size 59: 30,67 BAD (FFHFHH) +Size 60: 30,68 GOOD (HHFFFF) +Size 61: 31,70 BAD (FFHFHH) +Size 62: 31,71 GOOD (HHFFFF) +Size 63: 32,72 BAD (FFHFHH) +Size 64: 32,73 GOOD (HHFFFF) +Size 65: 33,74 GOOD (HHFFFF) +Size 66: 33,75 GOOD (HHFFFF) +Size 67: 34,76 GOOD (HHFFFF) +Size 68: 34,78 GOOD (HHFFFF) +Size 69: 35,79 GOOD (HHFFFF) +Size 70: 35,80 GOOD (HHFFFF) +Size 71: 36,81 GOOD (HHFFFF) +Size 72: 36,82 GOOD (HHFFFF) +Size 73: 37,83 GOOD (HHFFFF) +Size 74: 37,84 GOOD (HHFFFF) +Size 75: 38,86 GOOD (HHFFFF) +Size 76: 38,87 GOOD (HHFFFF) +Size 77: 39,88 GOOD (HHFFFF) +Size 78: 39,89 GOOD (HHFFFF) +Size 79: 40,90 GOOD (HHFFFF) +Size 80: 40,91 GOOD (HHFFFF) +Size 81: 41,92 GOOD (HHFFFF) +Size 82: 41,94 GOOD (HHFFFF) +Size 83: 42,95 GOOD (HHFFFF) +Size 84: 42,96 GOOD (HHFFFF) +Size 85: 43,97 GOOD (HHFFFF) +Size 86: 43,98 GOOD (HHFFFF) +Size 87: 44,99 GOOD (HHFFFF) +Size 88: 44,100 GOOD (HHFFFF) +Size 89: 45,102 GOOD (HHFFFF) +Size 90: 45,103 GOOD (HHFFFF) +Size 91: 46,104 GOOD (HHFFFF) +Size 92: 46,105 GOOD (HHFFFF) +Size 93: 47,106 GOOD (HHFFFF) +Size 94: 47,107 GOOD (HHFFFF) +Size 95: 48,108 GOOD (HHFFFF) +Size 96: 48,111 GOOD (HHFFFF) +Size 97: 49,111 GOOD (HHFFFF) +Size 98: 49,112 GOOD (HHFFFF) +Size 99: 50,113 GOOD (HHFFFF) +Size 100: 50,114 GOOD (HHFFFF) + +Windows 10 14342 Old Console +---------------------------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,3 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,9 GOOD (HHFFFF) +Size 9: 5,10 BAD (FFHFHH) +Size 10: 5,11 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,15 BAD (FFHFHH) +Size 14: 7,16 GOOD (HHFFFF) +Size 15: 8,17 BAD (FFHFHH) +Size 16: 8,18 GOOD (HHFFFF) +Size 17: 9,19 BAD (FFHFHH) +Size 18: 9,21 GOOD (HHFFFF) +Size 19: 10,22 BAD (FFHFHH) +Size 20: 10,23 GOOD (HHFFFF) +Size 21: 11,24 BAD (FFHFHH) +Size 22: 11,25 GOOD (HHFFFF) +Size 23: 12,26 BAD (FFHFHH) +Size 24: 12,27 GOOD (HHFFFF) +Size 25: 13,29 BAD (FFHFHH) +Size 26: 13,30 GOOD (HHFFFF) +Size 27: 14,31 BAD (FFHFHH) +Size 28: 14,32 GOOD (HHFFFF) +Size 29: 15,33 BAD (FFHFHH) +Size 30: 15,34 GOOD (HHFFFF) +Size 31: 16,35 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,38 BAD (FFHFHH) +Size 34: 17,39 GOOD (HHFFFF) +Size 35: 18,40 BAD (FFHFHH) +Size 36: 18,41 GOOD (HHFFFF) +Size 37: 19,42 BAD (FFHFHH) +Size 38: 19,43 GOOD (HHFFFF) +Size 39: 20,44 BAD (FFHFHH) +Size 40: 20,46 GOOD (HHFFFF) +Size 41: 21,47 BAD (FFHFHH) +Size 42: 21,48 GOOD (HHFFFF) +Size 43: 22,49 BAD (FFHFHH) +Size 44: 22,50 GOOD (HHFFFF) +Size 45: 23,51 BAD (FFHFHH) +Size 46: 23,52 GOOD (HHFFFF) +Size 47: 24,54 BAD (FFHFHH) +Size 48: 24,55 GOOD (HHFFFF) +Size 49: 25,56 BAD (FFHFHH) +Size 50: 25,57 GOOD (HHFFFF) +Size 51: 26,58 BAD (FFHFHH) +Size 52: 26,59 GOOD (HHFFFF) +Size 53: 27,60 BAD (FFHFHH) +Size 54: 27,62 GOOD (HHFFFF) +Size 55: 28,63 BAD (FFHFHH) +Size 56: 28,64 GOOD (HHFFFF) +Size 57: 29,65 BAD (FFHFHH) +Size 58: 29,66 GOOD (HHFFFF) +Size 59: 30,67 BAD (FFHFHH) +Size 60: 30,68 GOOD (HHFFFF) +Size 61: 31,70 BAD (FFHFHH) +Size 62: 31,71 GOOD (HHFFFF) +Size 63: 32,72 BAD (FFHFHH) +Size 64: 32,73 GOOD (HHFFFF) +Size 65: 33,74 GOOD (HHFFFF) +Size 66: 33,75 GOOD (HHFFFF) +Size 67: 34,76 GOOD (HHFFFF) +Size 68: 34,78 GOOD (HHFFFF) +Size 69: 35,79 GOOD (HHFFFF) +Size 70: 35,80 GOOD (HHFFFF) +Size 71: 36,81 GOOD (HHFFFF) +Size 72: 36,82 GOOD (HHFFFF) +Size 73: 37,83 GOOD (HHFFFF) +Size 74: 37,84 GOOD (HHFFFF) +Size 75: 38,86 GOOD (HHFFFF) +Size 76: 38,87 GOOD (HHFFFF) +Size 77: 39,88 GOOD (HHFFFF) +Size 78: 39,89 GOOD (HHFFFF) +Size 79: 40,90 GOOD (HHFFFF) +Size 80: 40,91 GOOD (HHFFFF) +Size 81: 41,92 GOOD (HHFFFF) +Size 82: 41,94 GOOD (HHFFFF) +Size 83: 42,95 GOOD (HHFFFF) +Size 84: 42,96 GOOD (HHFFFF) +Size 85: 43,97 GOOD (HHFFFF) +Size 86: 43,98 GOOD (HHFFFF) +Size 87: 44,99 GOOD (HHFFFF) +Size 88: 44,100 GOOD (HHFFFF) +Size 89: 45,102 GOOD (HHFFFF) +Size 90: 45,103 GOOD (HHFFFF) +Size 91: 46,104 GOOD (HHFFFF) +Size 92: 46,105 GOOD (HHFFFF) +Size 93: 47,106 GOOD (HHFFFF) +Size 94: 47,107 GOOD (HHFFFF) +Size 95: 48,108 GOOD (HHFFFF) +Size 96: 48,111 GOOD (HHFFFF) +Size 97: 49,111 GOOD (HHFFFF) +Size 98: 49,112 GOOD (HHFFFF) +Size 99: 50,113 GOOD (HHFFFF) +Size 100: 50,114 GOOD (HHFFFF) + +Windows 10 14342 New Console +---------------------------- + +Size 1: 1,1 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,3 GOOD (HHFFFF) +Size 4: 2,4 GOOD (HHFFFF) +Size 5: 3,5 GOOD (HHFFFF) +Size 6: 3,6 GOOD (HHFFFF) +Size 7: 4,7 GOOD (HHFFFF) +Size 8: 4,8 GOOD (HHFFFF) +Size 9: 5,9 GOOD (HHFFFF) +Size 10: 5,10 GOOD (HHFFFF) +Size 11: 6,11 GOOD (HHFFFF) +Size 12: 6,12 GOOD (HHFFFF) +Size 13: 7,13 GOOD (HHFFFF) +Size 14: 7,14 GOOD (HHFFFF) +Size 15: 8,15 GOOD (HHFFFF) +Size 16: 8,16 GOOD (HHFFFF) +Size 17: 9,17 GOOD (HHFFFF) +Size 18: 9,18 GOOD (HHFFFF) +Size 19: 10,19 GOOD (HHFFFF) +Size 20: 10,20 GOOD (HHFFFF) +Size 21: 11,21 GOOD (HHFFFF) +Size 22: 11,22 GOOD (HHFFFF) +Size 23: 12,23 GOOD (HHFFFF) +Size 24: 12,24 GOOD (HHFFFF) +Size 25: 13,25 GOOD (HHFFFF) +Size 26: 13,26 GOOD (HHFFFF) +Size 27: 14,27 GOOD (HHFFFF) +Size 28: 14,28 GOOD (HHFFFF) +Size 29: 15,29 GOOD (HHFFFF) +Size 30: 15,30 GOOD (HHFFFF) +Size 31: 16,31 GOOD (HHFFFF) +Size 32: 16,32 GOOD (HHFFFF) +Size 33: 17,33 GOOD (HHFFFF) +Size 34: 17,34 GOOD (HHFFFF) +Size 35: 18,35 GOOD (HHFFFF) +Size 36: 18,36 GOOD (HHFFFF) +Size 37: 19,37 GOOD (HHFFFF) +Size 38: 19,38 GOOD (HHFFFF) +Size 39: 20,39 GOOD (HHFFFF) +Size 40: 20,40 GOOD (HHFFFF) +Size 41: 21,41 GOOD (HHFFFF) +Size 42: 21,42 GOOD (HHFFFF) +Size 43: 22,43 GOOD (HHFFFF) +Size 44: 22,44 GOOD (HHFFFF) +Size 45: 23,45 GOOD (HHFFFF) +Size 46: 23,46 GOOD (HHFFFF) +Size 47: 24,47 GOOD (HHFFFF) +Size 48: 24,48 GOOD (HHFFFF) +Size 49: 25,49 GOOD (HHFFFF) +Size 50: 25,50 GOOD (HHFFFF) +Size 51: 26,51 GOOD (HHFFFF) +Size 52: 26,52 GOOD (HHFFFF) +Size 53: 27,53 GOOD (HHFFFF) +Size 54: 27,54 GOOD (HHFFFF) +Size 55: 28,55 GOOD (HHFFFF) +Size 56: 28,56 GOOD (HHFFFF) +Size 57: 29,57 GOOD (HHFFFF) +Size 58: 29,58 GOOD (HHFFFF) +Size 59: 30,59 GOOD (HHFFFF) +Size 60: 30,60 GOOD (HHFFFF) +Size 61: 31,61 GOOD (HHFFFF) +Size 62: 31,62 GOOD (HHFFFF) +Size 63: 32,63 GOOD (HHFFFF) +Size 64: 32,64 GOOD (HHFFFF) +Size 65: 33,65 GOOD (HHFFFF) +Size 66: 33,66 GOOD (HHFFFF) +Size 67: 34,67 GOOD (HHFFFF) +Size 68: 34,68 GOOD (HHFFFF) +Size 69: 35,69 GOOD (HHFFFF) +Size 70: 35,70 GOOD (HHFFFF) +Size 71: 36,71 GOOD (HHFFFF) +Size 72: 36,72 GOOD (HHFFFF) +Size 73: 37,73 GOOD (HHFFFF) +Size 74: 37,74 GOOD (HHFFFF) +Size 75: 38,75 GOOD (HHFFFF) +Size 76: 38,76 GOOD (HHFFFF) +Size 77: 39,77 GOOD (HHFFFF) +Size 78: 39,78 GOOD (HHFFFF) +Size 79: 40,79 GOOD (HHFFFF) +Size 80: 40,80 GOOD (HHFFFF) +Size 81: 41,81 GOOD (HHFFFF) +Size 82: 41,82 GOOD (HHFFFF) +Size 83: 42,83 GOOD (HHFFFF) +Size 84: 42,84 GOOD (HHFFFF) +Size 85: 43,85 GOOD (HHFFFF) +Size 86: 43,86 GOOD (HHFFFF) +Size 87: 44,87 GOOD (HHFFFF) +Size 88: 44,88 GOOD (HHFFFF) +Size 89: 45,89 GOOD (HHFFFF) +Size 90: 45,90 GOOD (HHFFFF) +Size 91: 46,91 GOOD (HHFFFF) +Size 92: 46,92 GOOD (HHFFFF) +Size 93: 47,93 GOOD (HHFFFF) +Size 94: 47,94 GOOD (HHFFFF) +Size 95: 48,95 GOOD (HHFFFF) +Size 96: 48,96 GOOD (HHFFFF) +Size 97: 49,97 GOOD (HHFFFF) +Size 98: 49,98 GOOD (HHFFFF) +Size 99: 50,99 GOOD (HHFFFF) +Size 100: 50,100 GOOD (HHFFFF) diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt new file mode 100644 index 00000000000..2f0ea1e7c2e --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP949.txt @@ -0,0 +1,630 @@ +===================================== +Code Page 949, Korean, GulimChe font +===================================== + +Options: -face-gulimche -family 0x36 +Chars: A2 A3 2014 3044 30FC 4000 + +Vista +----- + +Size 1: 1,2 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 BAD (FFFFHH) +Size 4: 2,5 OK (HHHFFF) +Size 5: 3,6 BAD (HHHFHH) +Size 6: 3,7 OK (HHHFFF) +Size 7: 4,8 BAD (HHHFHH) +Size 8: 4,9 OK (HHHFFF) +Size 9: 5,10 BAD (HHHFHH) +Size 10: 5,11 OK (HHHFFF) +Size 11: 6,13 BAD (HHHFHH) +Size 12: 6,14 OK (HHHFFF) +Size 13: 7,15 BAD (HHHFHH) +Size 14: 7,16 OK (HHHFFF) +Size 15: 8,17 BAD (HHHFHH) +Size 16: 8,18 OK (HHHFFF) +Size 17: 9,20 BAD (HHHFHH) +Size 18: 9,21 OK (HHHFFF) +Size 19: 10,22 BAD (HHHFHH) +Size 20: 10,23 OK (HHHFFF) +Size 21: 11,24 BAD (HHHFHH) +Size 22: 11,25 OK (HHHFFF) +Size 23: 12,26 BAD (HHHFHH) +Size 24: 12,28 OK (HHHFFF) +Size 25: 13,29 BAD (HHHFHH) +Size 26: 13,30 OK (HHHFFF) +Size 27: 14,31 BAD (HHHFHH) +Size 28: 14,32 OK (HHHFFF) +Size 29: 15,33 BAD (HHHFHH) +Size 30: 15,34 OK (HHHFFF) +Size 31: 16,36 BAD (HHHFHH) +Size 32: 16,37 OK (HHHFFF) +Size 33: 17,38 BAD (HHHFHH) +Size 34: 17,39 OK (HHHFFF) +Size 35: 18,40 BAD (HHHFHH) +Size 36: 18,41 OK (HHHFFF) +Size 37: 19,42 BAD (HHHFHH) +Size 38: 19,44 OK (HHHFFF) +Size 39: 20,45 BAD (HHHFHH) +Size 40: 20,46 OK (HHHFFF) +Size 41: 21,47 BAD (HHHFHH) +Size 42: 21,48 OK (HHHFFF) +Size 43: 22,49 BAD (HHHFHH) +Size 44: 22,51 OK (HHHFFF) +Size 45: 23,52 BAD (HHHFHH) +Size 46: 23,53 OK (HHHFFF) +Size 47: 24,54 BAD (HHHFHH) +Size 48: 24,55 OK (HHHFFF) +Size 49: 25,56 BAD (HHHFHH) +Size 50: 25,57 OK (HHHFFF) +Size 51: 26,59 BAD (HHHFHH) +Size 52: 26,60 OK (HHHFFF) +Size 53: 27,61 BAD (HHHFHH) +Size 54: 27,62 OK (HHHFFF) +Size 55: 28,63 BAD (HHHFHH) +Size 56: 28,64 OK (HHHFFF) +Size 57: 29,65 BAD (HHHFHH) +Size 58: 29,67 OK (HHHFFF) +Size 59: 30,68 BAD (HHHFHH) +Size 60: 30,69 OK (HHHFFF) +Size 61: 31,70 BAD (HHHFHH) +Size 62: 31,71 OK (HHHFFF) +Size 63: 32,72 BAD (HHHFHH) +Size 64: 32,74 OK (HHHFFF) +Size 65: 33,75 BAD (HHHFHH) +Size 66: 33,76 OK (HHHFFF) +Size 67: 34,77 BAD (HHHFHH) +Size 68: 34,78 OK (HHHFFF) +Size 69: 35,79 BAD (HHHFHH) +Size 70: 35,80 OK (HHHFFF) +Size 71: 36,82 BAD (HHHFHH) +Size 72: 36,83 OK (HHHFFF) +Size 73: 37,84 BAD (HHHFHH) +Size 74: 37,85 OK (HHHFFF) +Size 75: 38,86 BAD (HHHFHH) +Size 76: 38,87 OK (HHHFFF) +Size 77: 39,88 BAD (HHHFHH) +Size 78: 39,90 OK (HHHFFF) +Size 79: 40,91 BAD (HHHFHH) +Size 80: 40,92 OK (HHHFFF) +Size 81: 41,93 BAD (HHHFHH) +Size 82: 41,94 OK (HHHFFF) +Size 83: 42,95 BAD (HHHFHH) +Size 84: 42,96 OK (HHHFFF) +Size 85: 43,98 BAD (HHHFHH) +Size 86: 43,99 OK (HHHFFF) +Size 87: 44,100 BAD (HHHFHH) +Size 88: 44,101 OK (HHHFFF) +Size 89: 45,102 BAD (HHHFHH) +Size 90: 45,103 OK (HHHFFF) +Size 91: 46,105 BAD (HHHFHH) +Size 92: 46,106 OK (HHHFFF) +Size 93: 47,107 BAD (HHHFHH) +Size 94: 47,108 OK (HHHFFF) +Size 95: 48,109 BAD (HHHFHH) +Size 96: 48,110 OK (HHHFFF) +Size 97: 49,111 BAD (HHHFHH) +Size 98: 49,113 OK (HHHFFF) +Size 99: 50,114 BAD (HHHFHH) +Size 100: 50,115 OK (HHHFFF) + +Windows 7 +--------- + +Size 1: 1,2 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 BAD (FFFFHH) +Size 4: 2,5 OK (HHHFFF) +Size 5: 3,6 BAD (FFFFHH) +Size 6: 3,7 OK (HHHFFF) +Size 7: 4,8 BAD (FFFFHH) +Size 8: 4,9 OK (HHHFFF) +Size 9: 5,10 BAD (FFFFHH) +Size 10: 5,11 OK (HHHFFF) +Size 11: 6,13 BAD (FFFFHH) +Size 12: 6,14 OK (HHHFFF) +Size 13: 7,15 BAD (FFFFHH) +Size 14: 7,16 OK (HHHFFF) +Size 15: 8,17 BAD (FFFFHH) +Size 16: 8,18 OK (HHHFFF) +Size 17: 9,20 BAD (FFFFHH) +Size 18: 9,21 OK (HHHFFF) +Size 19: 10,22 BAD (FFFFHH) +Size 20: 10,23 OK (HHHFFF) +Size 21: 11,24 BAD (FFFFHH) +Size 22: 11,25 OK (HHHFFF) +Size 23: 12,26 BAD (FFFFHH) +Size 24: 12,28 OK (HHHFFF) +Size 25: 13,29 BAD (FFFFHH) +Size 26: 13,30 OK (HHHFFF) +Size 27: 14,31 BAD (FFFFHH) +Size 28: 14,32 OK (HHHFFF) +Size 29: 15,33 BAD (FFFFHH) +Size 30: 15,34 OK (HHHFFF) +Size 31: 16,36 BAD (FFFFHH) +Size 32: 16,37 OK (HHHFFF) +Size 33: 17,38 BAD (FFFFHH) +Size 34: 17,39 OK (HHHFFF) +Size 35: 18,40 BAD (FFFFHH) +Size 36: 18,41 OK (HHHFFF) +Size 37: 19,42 BAD (FFFFHH) +Size 38: 19,44 OK (HHHFFF) +Size 39: 20,45 BAD (FFFFHH) +Size 40: 20,46 OK (HHHFFF) +Size 41: 21,47 BAD (FFFFHH) +Size 42: 21,48 OK (HHHFFF) +Size 43: 22,49 BAD (FFFFHH) +Size 44: 22,51 OK (HHHFFF) +Size 45: 23,52 BAD (FFFFHH) +Size 46: 23,53 OK (HHHFFF) +Size 47: 24,54 BAD (FFFFHH) +Size 48: 24,55 OK (HHHFFF) +Size 49: 25,56 BAD (FFFFHH) +Size 50: 25,57 OK (HHHFFF) +Size 51: 26,59 BAD (FFFFHH) +Size 52: 26,60 OK (HHHFFF) +Size 53: 27,61 BAD (FFFFHH) +Size 54: 27,62 OK (HHHFFF) +Size 55: 28,63 BAD (FFFFHH) +Size 56: 28,64 OK (HHHFFF) +Size 57: 29,65 BAD (FFFFHH) +Size 58: 29,67 OK (HHHFFF) +Size 59: 30,68 BAD (FFFFHH) +Size 60: 30,69 OK (HHHFFF) +Size 61: 31,70 BAD (FFFFHH) +Size 62: 31,71 OK (HHHFFF) +Size 63: 32,72 BAD (FFFFHH) +Size 64: 32,74 OK (HHHFFF) +Size 65: 33,75 BAD (FFFFHH) +Size 66: 33,76 OK (HHHFFF) +Size 67: 34,77 BAD (FFFFHH) +Size 68: 34,78 OK (HHHFFF) +Size 69: 35,79 BAD (FFFFHH) +Size 70: 35,80 OK (HHHFFF) +Size 71: 36,82 BAD (FFFFHH) +Size 72: 36,83 OK (HHHFFF) +Size 73: 37,84 BAD (FFFFHH) +Size 74: 37,85 OK (HHHFFF) +Size 75: 38,86 BAD (FFFFHH) +Size 76: 38,87 OK (HHHFFF) +Size 77: 39,88 BAD (FFFFHH) +Size 78: 39,90 OK (HHHFFF) +Size 79: 40,91 BAD (FFFFHH) +Size 80: 40,92 OK (HHHFFF) +Size 81: 41,93 BAD (FFFFHH) +Size 82: 41,94 OK (HHHFFF) +Size 83: 42,95 BAD (FFFFHH) +Size 84: 42,96 OK (HHHFFF) +Size 85: 43,98 BAD (FFFFHH) +Size 86: 43,99 OK (HHHFFF) +Size 87: 44,100 BAD (FFFFHH) +Size 88: 44,101 OK (HHHFFF) +Size 89: 45,102 BAD (FFFFHH) +Size 90: 45,103 OK (HHHFFF) +Size 91: 46,105 BAD (FFFFHH) +Size 92: 46,106 OK (HHHFFF) +Size 93: 47,107 BAD (FFFFHH) +Size 94: 47,108 OK (HHHFFF) +Size 95: 48,109 BAD (FFFFHH) +Size 96: 48,110 OK (HHHFFF) +Size 97: 49,111 BAD (FFFFHH) +Size 98: 49,113 OK (HHHFFF) +Size 99: 50,114 BAD (FFFFHH) +Size 100: 50,115 OK (HHHFFF) + +Windows 8 +--------- + +Size 1: 1,2 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 BAD (FFFFHH) +Size 4: 2,5 OK (HHHFFF) +Size 5: 3,6 BAD (FFFFHH) +Size 6: 3,7 OK (HHHFFF) +Size 7: 4,8 BAD (FFFFHH) +Size 8: 4,9 OK (HHHFFF) +Size 9: 5,10 BAD (FFFFHH) +Size 10: 5,11 OK (HHHFFF) +Size 11: 6,13 BAD (FFFFHH) +Size 12: 6,14 OK (HHHFFF) +Size 13: 7,15 BAD (FFFFHH) +Size 14: 7,16 OK (HHHFFF) +Size 15: 8,17 BAD (FFFFHH) +Size 16: 8,18 OK (HHHFFF) +Size 17: 9,20 BAD (FFFFHH) +Size 18: 9,21 OK (HHHFFF) +Size 19: 10,22 BAD (FFFFHH) +Size 20: 10,23 OK (HHHFFF) +Size 21: 11,24 BAD (FFFFHH) +Size 22: 11,25 OK (HHHFFF) +Size 23: 12,26 BAD (FFFFHH) +Size 24: 12,28 OK (HHHFFF) +Size 25: 13,29 BAD (FFFFHH) +Size 26: 13,30 OK (HHHFFF) +Size 27: 14,31 BAD (FFFFHH) +Size 28: 14,32 OK (HHHFFF) +Size 29: 15,33 BAD (FFFFHH) +Size 30: 15,34 OK (HHHFFF) +Size 31: 16,36 BAD (FFFFHH) +Size 32: 16,37 OK (HHHFFF) +Size 33: 17,38 BAD (FFFFHH) +Size 34: 17,39 OK (HHHFFF) +Size 35: 18,40 BAD (FFFFHH) +Size 36: 18,41 OK (HHHFFF) +Size 37: 19,42 BAD (FFFFHH) +Size 38: 19,44 OK (HHHFFF) +Size 39: 20,45 BAD (FFFFHH) +Size 40: 20,46 OK (HHHFFF) +Size 41: 21,47 BAD (FFFFHH) +Size 42: 21,48 OK (HHHFFF) +Size 43: 22,49 BAD (FFFFHH) +Size 44: 22,51 OK (HHHFFF) +Size 45: 23,52 BAD (FFFFHH) +Size 46: 23,53 OK (HHHFFF) +Size 47: 24,54 BAD (FFFFHH) +Size 48: 24,55 OK (HHHFFF) +Size 49: 25,56 BAD (FFFFHH) +Size 50: 25,57 OK (HHHFFF) +Size 51: 26,59 BAD (FFFFHH) +Size 52: 26,60 OK (HHHFFF) +Size 53: 27,61 BAD (FFFFHH) +Size 54: 27,62 OK (HHHFFF) +Size 55: 28,63 BAD (FFFFHH) +Size 56: 28,64 OK (HHHFFF) +Size 57: 29,65 BAD (FFFFHH) +Size 58: 29,67 OK (HHHFFF) +Size 59: 30,68 BAD (FFFFHH) +Size 60: 30,69 OK (HHHFFF) +Size 61: 31,70 BAD (FFFFHH) +Size 62: 31,71 OK (HHHFFF) +Size 63: 32,72 BAD (FFFFHH) +Size 64: 32,74 OK (HHHFFF) +Size 65: 33,75 BAD (FFFFHH) +Size 66: 33,76 OK (HHHFFF) +Size 67: 34,77 BAD (FFFFHH) +Size 68: 34,78 OK (HHHFFF) +Size 69: 35,79 BAD (FFFFHH) +Size 70: 35,80 OK (HHHFFF) +Size 71: 36,82 BAD (FFFFHH) +Size 72: 36,83 OK (HHHFFF) +Size 73: 37,84 BAD (FFFFHH) +Size 74: 37,85 OK (HHHFFF) +Size 75: 38,86 BAD (FFFFHH) +Size 76: 38,87 OK (HHHFFF) +Size 77: 39,88 BAD (FFFFHH) +Size 78: 39,90 OK (HHHFFF) +Size 79: 40,91 BAD (FFFFHH) +Size 80: 40,92 OK (HHHFFF) +Size 81: 41,93 BAD (FFFFHH) +Size 82: 41,94 OK (HHHFFF) +Size 83: 42,95 BAD (FFFFHH) +Size 84: 42,96 OK (HHHFFF) +Size 85: 43,98 BAD (FFFFHH) +Size 86: 43,99 OK (HHHFFF) +Size 87: 44,100 BAD (FFFFHH) +Size 88: 44,101 OK (HHHFFF) +Size 89: 45,102 BAD (FFFFHH) +Size 90: 45,103 OK (HHHFFF) +Size 91: 46,105 BAD (FFFFHH) +Size 92: 46,106 OK (HHHFFF) +Size 93: 47,107 BAD (FFFFHH) +Size 94: 47,108 OK (HHHFFF) +Size 95: 48,109 BAD (FFFFHH) +Size 96: 48,110 OK (HHHFFF) +Size 97: 49,111 BAD (FFFFHH) +Size 98: 49,113 OK (HHHFFF) +Size 99: 50,114 BAD (FFFFHH) +Size 100: 50,115 OK (HHHFFF) + +Windows 8.1 +----------- + +Size 1: 1,2 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 BAD (FFFFHH) +Size 4: 2,5 OK (HHHFFF) +Size 5: 3,6 BAD (FFFFHH) +Size 6: 3,7 OK (HHHFFF) +Size 7: 4,8 BAD (FFFFHH) +Size 8: 4,9 OK (HHHFFF) +Size 9: 5,10 BAD (FFFFHH) +Size 10: 5,11 OK (HHHFFF) +Size 11: 6,13 BAD (FFFFHH) +Size 12: 6,14 OK (HHHFFF) +Size 13: 7,15 BAD (FFFFHH) +Size 14: 7,16 OK (HHHFFF) +Size 15: 8,17 BAD (FFFFHH) +Size 16: 8,18 OK (HHHFFF) +Size 17: 9,20 BAD (FFFFHH) +Size 18: 9,21 OK (HHHFFF) +Size 19: 10,22 BAD (FFFFHH) +Size 20: 10,23 OK (HHHFFF) +Size 21: 11,24 BAD (FFFFHH) +Size 22: 11,25 OK (HHHFFF) +Size 23: 12,26 BAD (FFFFHH) +Size 24: 12,28 OK (HHHFFF) +Size 25: 13,29 BAD (FFFFHH) +Size 26: 13,30 OK (HHHFFF) +Size 27: 14,31 BAD (FFFFHH) +Size 28: 14,32 OK (HHHFFF) +Size 29: 15,33 BAD (FFFFHH) +Size 30: 15,34 OK (HHHFFF) +Size 31: 16,36 BAD (FFFFHH) +Size 32: 16,37 OK (HHHFFF) +Size 33: 17,38 BAD (FFFFHH) +Size 34: 17,39 OK (HHHFFF) +Size 35: 18,40 BAD (FFFFHH) +Size 36: 18,41 OK (HHHFFF) +Size 37: 19,42 BAD (FFFFHH) +Size 38: 19,44 OK (HHHFFF) +Size 39: 20,45 BAD (FFFFHH) +Size 40: 20,46 OK (HHHFFF) +Size 41: 21,47 BAD (FFFFHH) +Size 42: 21,48 OK (HHHFFF) +Size 43: 22,49 BAD (FFFFHH) +Size 44: 22,51 OK (HHHFFF) +Size 45: 23,52 BAD (FFFFHH) +Size 46: 23,53 OK (HHHFFF) +Size 47: 24,54 BAD (FFFFHH) +Size 48: 24,55 OK (HHHFFF) +Size 49: 25,56 BAD (FFFFHH) +Size 50: 25,57 OK (HHHFFF) +Size 51: 26,59 BAD (FFFFHH) +Size 52: 26,60 OK (HHHFFF) +Size 53: 27,61 BAD (FFFFHH) +Size 54: 27,62 OK (HHHFFF) +Size 55: 28,63 BAD (FFFFHH) +Size 56: 28,64 OK (HHHFFF) +Size 57: 29,65 BAD (FFFFHH) +Size 58: 29,67 OK (HHHFFF) +Size 59: 30,68 BAD (FFFFHH) +Size 60: 30,69 OK (HHHFFF) +Size 61: 31,70 BAD (FFFFHH) +Size 62: 31,71 OK (HHHFFF) +Size 63: 32,72 BAD (FFFFHH) +Size 64: 32,74 OK (HHHFFF) +Size 65: 33,75 BAD (FFFFHH) +Size 66: 33,76 OK (HHHFFF) +Size 67: 34,77 BAD (FFFFHH) +Size 68: 34,78 OK (HHHFFF) +Size 69: 35,79 BAD (FFFFHH) +Size 70: 35,80 OK (HHHFFF) +Size 71: 36,82 BAD (FFFFHH) +Size 72: 36,83 OK (HHHFFF) +Size 73: 37,84 BAD (FFFFHH) +Size 74: 37,85 OK (HHHFFF) +Size 75: 38,86 BAD (FFFFHH) +Size 76: 38,87 OK (HHHFFF) +Size 77: 39,88 BAD (FFFFHH) +Size 78: 39,90 OK (HHHFFF) +Size 79: 40,91 BAD (FFFFHH) +Size 80: 40,92 OK (HHHFFF) +Size 81: 41,93 BAD (FFFFHH) +Size 82: 41,94 OK (HHHFFF) +Size 83: 42,95 BAD (FFFFHH) +Size 84: 42,96 OK (HHHFFF) +Size 85: 43,98 BAD (FFFFHH) +Size 86: 43,99 OK (HHHFFF) +Size 87: 44,100 BAD (FFFFHH) +Size 88: 44,101 OK (HHHFFF) +Size 89: 45,102 BAD (FFFFHH) +Size 90: 45,103 OK (HHHFFF) +Size 91: 46,105 BAD (FFFFHH) +Size 92: 46,106 OK (HHHFFF) +Size 93: 47,107 BAD (FFFFHH) +Size 94: 47,108 OK (HHHFFF) +Size 95: 48,109 BAD (FFFFHH) +Size 96: 48,110 OK (HHHFFF) +Size 97: 49,111 BAD (FFFFHH) +Size 98: 49,113 OK (HHHFFF) +Size 99: 50,114 BAD (FFFFHH) +Size 100: 50,115 OK (HHHFFF) + +Windows 10 14342 Old Console +---------------------------- + +Size 1: 1,2 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 BAD (FFFFHH) +Size 4: 2,5 OK (HHHFFF) +Size 5: 3,6 BAD (FFFFHH) +Size 6: 3,7 OK (HHHFFF) +Size 7: 4,8 BAD (FFFFHH) +Size 8: 4,9 OK (HHHFFF) +Size 9: 5,10 BAD (FFFFHH) +Size 10: 5,11 OK (HHHFFF) +Size 11: 6,13 BAD (FFFFHH) +Size 12: 6,14 OK (HHHFFF) +Size 13: 7,15 BAD (FFFFHH) +Size 14: 7,16 OK (HHHFFF) +Size 15: 8,17 BAD (FFFFHH) +Size 16: 8,18 OK (HHHFFF) +Size 17: 9,20 BAD (FFFFHH) +Size 18: 9,21 OK (HHHFFF) +Size 19: 10,22 BAD (FFFFHH) +Size 20: 10,23 OK (HHHFFF) +Size 21: 11,24 BAD (FFFFHH) +Size 22: 11,25 OK (HHHFFF) +Size 23: 12,26 BAD (FFFFHH) +Size 24: 12,28 OK (HHHFFF) +Size 25: 13,29 BAD (FFFFHH) +Size 26: 13,30 OK (HHHFFF) +Size 27: 14,31 BAD (FFFFHH) +Size 28: 14,32 OK (HHHFFF) +Size 29: 15,33 BAD (FFFFHH) +Size 30: 15,34 OK (HHHFFF) +Size 31: 16,36 BAD (FFFFHH) +Size 32: 16,37 OK (HHHFFF) +Size 33: 17,38 BAD (FFFFHH) +Size 34: 17,39 OK (HHHFFF) +Size 35: 18,40 BAD (FFFFHH) +Size 36: 18,41 OK (HHHFFF) +Size 37: 19,42 BAD (FFFFHH) +Size 38: 19,44 OK (HHHFFF) +Size 39: 20,45 BAD (FFFFHH) +Size 40: 20,46 OK (HHHFFF) +Size 41: 21,47 BAD (FFFFHH) +Size 42: 21,48 OK (HHHFFF) +Size 43: 22,49 BAD (FFFFHH) +Size 44: 22,51 OK (HHHFFF) +Size 45: 23,52 BAD (FFFFHH) +Size 46: 23,53 OK (HHHFFF) +Size 47: 24,54 BAD (FFFFHH) +Size 48: 24,55 OK (HHHFFF) +Size 49: 25,56 BAD (FFFFHH) +Size 50: 25,57 OK (HHHFFF) +Size 51: 26,59 BAD (FFFFHH) +Size 52: 26,60 OK (HHHFFF) +Size 53: 27,61 BAD (FFFFHH) +Size 54: 27,62 OK (HHHFFF) +Size 55: 28,63 BAD (FFFFHH) +Size 56: 28,64 OK (HHHFFF) +Size 57: 29,65 BAD (FFFFHH) +Size 58: 29,67 OK (HHHFFF) +Size 59: 30,68 BAD (FFFFHH) +Size 60: 30,69 OK (HHHFFF) +Size 61: 31,70 BAD (FFFFHH) +Size 62: 31,71 OK (HHHFFF) +Size 63: 32,72 BAD (FFFFHH) +Size 64: 32,74 OK (HHHFFF) +Size 65: 33,75 BAD (FFFFHH) +Size 66: 33,76 OK (HHHFFF) +Size 67: 34,77 BAD (FFFFHH) +Size 68: 34,78 OK (HHHFFF) +Size 69: 35,79 BAD (FFFFHH) +Size 70: 35,80 OK (HHHFFF) +Size 71: 36,82 BAD (FFFFHH) +Size 72: 36,83 OK (HHHFFF) +Size 73: 37,84 BAD (FFFFHH) +Size 74: 37,85 OK (HHHFFF) +Size 75: 38,86 BAD (FFFFHH) +Size 76: 38,87 OK (HHHFFF) +Size 77: 39,88 BAD (FFFFHH) +Size 78: 39,90 OK (HHHFFF) +Size 79: 40,91 BAD (FFFFHH) +Size 80: 40,92 OK (HHHFFF) +Size 81: 41,93 BAD (FFFFHH) +Size 82: 41,94 OK (HHHFFF) +Size 83: 42,95 BAD (FFFFHH) +Size 84: 42,96 OK (HHHFFF) +Size 85: 43,98 BAD (FFFFHH) +Size 86: 43,99 OK (HHHFFF) +Size 87: 44,100 BAD (FFFFHH) +Size 88: 44,101 OK (HHHFFF) +Size 89: 45,102 BAD (FFFFHH) +Size 90: 45,103 OK (HHHFFF) +Size 91: 46,105 BAD (FFFFHH) +Size 92: 46,106 OK (HHHFFF) +Size 93: 47,107 BAD (FFFFHH) +Size 94: 47,108 OK (HHHFFF) +Size 95: 48,109 BAD (FFFFHH) +Size 96: 48,110 OK (HHHFFF) +Size 97: 49,111 BAD (FFFFHH) +Size 98: 49,113 OK (HHHFFF) +Size 99: 50,114 BAD (FFFFHH) +Size 100: 50,115 OK (HHHFFF) + +Windows 10 14342 New Console +---------------------------- + +Size 1: 1,1 OK (HHHFFF) +Size 2: 1,2 OK (HHHFFF) +Size 3: 2,3 OK (HHHFFF) +Size 4: 2,4 OK (HHHFFF) +Size 5: 3,5 OK (HHHFFF) +Size 6: 3,6 OK (HHHFFF) +Size 7: 4,7 OK (HHHFFF) +Size 8: 4,8 OK (HHHFFF) +Size 9: 5,9 OK (HHHFFF) +Size 10: 5,10 OK (HHHFFF) +Size 11: 6,11 OK (HHHFFF) +Size 12: 6,12 OK (HHHFFF) +Size 13: 7,13 OK (HHHFFF) +Size 14: 7,14 OK (HHHFFF) +Size 15: 8,15 OK (HHHFFF) +Size 16: 8,16 OK (HHHFFF) +Size 17: 9,17 OK (HHHFFF) +Size 18: 9,18 OK (HHHFFF) +Size 19: 10,19 OK (HHHFFF) +Size 20: 10,20 OK (HHHFFF) +Size 21: 11,21 OK (HHHFFF) +Size 22: 11,22 OK (HHHFFF) +Size 23: 12,23 OK (HHHFFF) +Size 24: 12,24 OK (HHHFFF) +Size 25: 13,25 OK (HHHFFF) +Size 26: 13,26 OK (HHHFFF) +Size 27: 14,27 OK (HHHFFF) +Size 28: 14,28 OK (HHHFFF) +Size 29: 15,29 OK (HHHFFF) +Size 30: 15,30 OK (HHHFFF) +Size 31: 16,31 OK (HHHFFF) +Size 32: 16,32 OK (HHHFFF) +Size 33: 17,33 OK (HHHFFF) +Size 34: 17,34 OK (HHHFFF) +Size 35: 18,35 OK (HHHFFF) +Size 36: 18,36 OK (HHHFFF) +Size 37: 19,37 OK (HHHFFF) +Size 38: 19,38 OK (HHHFFF) +Size 39: 20,39 OK (HHHFFF) +Size 40: 20,40 OK (HHHFFF) +Size 41: 21,41 OK (HHHFFF) +Size 42: 21,42 OK (HHHFFF) +Size 43: 22,43 OK (HHHFFF) +Size 44: 22,44 OK (HHHFFF) +Size 45: 23,45 OK (HHHFFF) +Size 46: 23,46 OK (HHHFFF) +Size 47: 24,47 OK (HHHFFF) +Size 48: 24,48 OK (HHHFFF) +Size 49: 25,49 OK (HHHFFF) +Size 50: 25,50 OK (HHHFFF) +Size 51: 26,51 OK (HHHFFF) +Size 52: 26,52 OK (HHHFFF) +Size 53: 27,53 OK (HHHFFF) +Size 54: 27,54 OK (HHHFFF) +Size 55: 28,55 OK (HHHFFF) +Size 56: 28,56 OK (HHHFFF) +Size 57: 29,57 OK (HHHFFF) +Size 58: 29,58 OK (HHHFFF) +Size 59: 30,59 OK (HHHFFF) +Size 60: 30,60 OK (HHHFFF) +Size 61: 31,61 OK (HHHFFF) +Size 62: 31,62 OK (HHHFFF) +Size 63: 32,63 OK (HHHFFF) +Size 64: 32,64 OK (HHHFFF) +Size 65: 33,65 OK (HHHFFF) +Size 66: 33,66 OK (HHHFFF) +Size 67: 34,67 OK (HHHFFF) +Size 68: 34,68 OK (HHHFFF) +Size 69: 35,69 OK (HHHFFF) +Size 70: 35,70 OK (HHHFFF) +Size 71: 36,71 OK (HHHFFF) +Size 72: 36,72 OK (HHHFFF) +Size 73: 37,73 OK (HHHFFF) +Size 74: 37,74 OK (HHHFFF) +Size 75: 38,75 OK (HHHFFF) +Size 76: 38,76 OK (HHHFFF) +Size 77: 39,77 OK (HHHFFF) +Size 78: 39,78 OK (HHHFFF) +Size 79: 40,79 OK (HHHFFF) +Size 80: 40,80 OK (HHHFFF) +Size 81: 41,81 OK (HHHFFF) +Size 82: 41,82 OK (HHHFFF) +Size 83: 42,83 OK (HHHFFF) +Size 84: 42,84 OK (HHHFFF) +Size 85: 43,85 OK (HHHFFF) +Size 86: 43,86 OK (HHHFFF) +Size 87: 44,87 OK (HHHFFF) +Size 88: 44,88 OK (HHHFFF) +Size 89: 45,89 OK (HHHFFF) +Size 90: 45,90 OK (HHHFFF) +Size 91: 46,91 OK (HHHFFF) +Size 92: 46,92 OK (HHHFFF) +Size 93: 47,93 OK (HHHFFF) +Size 94: 47,94 OK (HHHFFF) +Size 95: 48,95 OK (HHHFFF) +Size 96: 48,96 OK (HHHFFF) +Size 97: 49,97 OK (HHHFFF) +Size 98: 49,98 OK (HHHFFF) +Size 99: 50,99 OK (HHHFFF) +Size 100: 50,100 OK (HHHFFF) diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt new file mode 100644 index 00000000000..0dbade504db --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/CP950.txt @@ -0,0 +1,630 @@ +=========================================================== +Code Page 950, Chinese Traditional (Taiwan), MingLight font +=========================================================== + +Options: -face-minglight -family 0x36 +Chars: A2 A3 2014 3044 30FC 4000 + +Vista +----- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,4 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (HHHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (HHHFHH) +Size 8: 4,10 GOOD (HHFFFF) +Size 9: 5,11 BAD (HHHFHH) +Size 10: 5,12 GOOD (HHFFFF) +Size 11: 6,13 BAD (HHHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,16 BAD (HHHFHH) +Size 14: 7,17 GOOD (HHFFFF) +Size 15: 8,18 BAD (HHHFHH) +Size 16: 8,19 GOOD (HHFFFF) +Size 17: 9,20 BAD (HHHFHH) +Size 18: 9,22 GOOD (HHFFFF) +Size 19: 10,23 BAD (HHHFHH) +Size 20: 10,24 GOOD (HHFFFF) +Size 21: 11,25 BAD (HHHFHH) +Size 22: 11,26 GOOD (HHFFFF) +Size 23: 12,28 BAD (HHHFHH) +Size 24: 12,29 GOOD (HHFFFF) +Size 25: 13,30 BAD (HHHFHH) +Size 26: 13,31 GOOD (HHFFFF) +Size 27: 14,32 BAD (HHHFHH) +Size 28: 14,34 GOOD (HHFFFF) +Size 29: 15,35 BAD (HHHFHH) +Size 30: 15,36 GOOD (HHFFFF) +Size 31: 16,37 BAD (HHHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,40 BAD (HHHFHH) +Size 34: 17,41 GOOD (HHFFFF) +Size 35: 18,42 BAD (HHHFHH) +Size 36: 18,43 GOOD (HHFFFF) +Size 37: 19,44 BAD (HHHFHH) +Size 38: 19,46 GOOD (HHFFFF) +Size 39: 20,47 BAD (HHHFHH) +Size 40: 20,48 GOOD (HHFFFF) +Size 41: 21,49 BAD (HHHFHH) +Size 42: 21,50 GOOD (HHFFFF) +Size 43: 22,52 BAD (HHHFHH) +Size 44: 22,53 GOOD (HHFFFF) +Size 45: 23,54 BAD (HHHFHH) +Size 46: 23,55 GOOD (HHFFFF) +Size 47: 24,56 BAD (HHHFHH) +Size 48: 24,58 GOOD (HHFFFF) +Size 49: 25,59 BAD (HHHFHH) +Size 50: 25,60 GOOD (HHFFFF) +Size 51: 26,61 BAD (HHHFHH) +Size 52: 26,62 GOOD (HHFFFF) +Size 53: 27,64 BAD (HHHFHH) +Size 54: 27,65 GOOD (HHFFFF) +Size 55: 28,66 BAD (HHHFHH) +Size 56: 28,67 GOOD (HHFFFF) +Size 57: 29,68 BAD (HHHFHH) +Size 58: 29,70 GOOD (HHFFFF) +Size 59: 30,71 BAD (HHHFHH) +Size 60: 30,72 GOOD (HHFFFF) +Size 61: 31,73 BAD (HHHFHH) +Size 62: 31,74 GOOD (HHFFFF) +Size 63: 32,76 BAD (HHHFHH) +Size 64: 32,77 GOOD (HHFFFF) +Size 65: 33,78 BAD (HHHFHH) +Size 66: 33,79 GOOD (HHFFFF) +Size 67: 34,80 BAD (HHHFHH) +Size 68: 34,82 GOOD (HHFFFF) +Size 69: 35,83 BAD (HHHFHH) +Size 70: 35,84 GOOD (HHFFFF) +Size 71: 36,85 BAD (HHHFHH) +Size 72: 36,86 GOOD (HHFFFF) +Size 73: 37,88 BAD (HHHFHH) +Size 74: 37,89 GOOD (HHFFFF) +Size 75: 38,90 BAD (HHHFHH) +Size 76: 38,91 GOOD (HHFFFF) +Size 77: 39,92 BAD (HHHFHH) +Size 78: 39,94 GOOD (HHFFFF) +Size 79: 40,95 BAD (HHHFHH) +Size 80: 40,96 GOOD (HHFFFF) +Size 81: 41,97 BAD (HHHFHH) +Size 82: 41,98 GOOD (HHFFFF) +Size 83: 42,100 BAD (HHHFHH) +Size 84: 42,101 GOOD (HHFFFF) +Size 85: 43,102 BAD (HHHFHH) +Size 86: 43,103 GOOD (HHFFFF) +Size 87: 44,104 BAD (HHHFHH) +Size 88: 44,106 GOOD (HHFFFF) +Size 89: 45,107 BAD (HHHFHH) +Size 90: 45,108 GOOD (HHFFFF) +Size 91: 46,109 BAD (HHHFHH) +Size 92: 46,110 GOOD (HHFFFF) +Size 93: 47,112 BAD (HHHFHH) +Size 94: 47,113 GOOD (HHFFFF) +Size 95: 48,114 BAD (HHHFHH) +Size 96: 48,115 GOOD (HHFFFF) +Size 97: 49,116 BAD (HHHFHH) +Size 98: 49,118 GOOD (HHFFFF) +Size 99: 50,119 BAD (HHHFHH) +Size 100: 50,120 GOOD (HHFFFF) + +Windows 7 +--------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,4 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,10 GOOD (HHFFFF) +Size 9: 5,11 BAD (FFHFHH) +Size 10: 5,12 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,16 BAD (FFHFHH) +Size 14: 7,17 GOOD (HHFFFF) +Size 15: 8,18 BAD (FFHFHH) +Size 16: 8,19 GOOD (HHFFFF) +Size 17: 9,20 BAD (FFHFHH) +Size 18: 9,22 GOOD (HHFFFF) +Size 19: 10,23 BAD (FFHFHH) +Size 20: 10,24 GOOD (HHFFFF) +Size 21: 11,25 BAD (FFHFHH) +Size 22: 11,26 GOOD (HHFFFF) +Size 23: 12,28 BAD (FFHFHH) +Size 24: 12,29 GOOD (HHFFFF) +Size 25: 13,30 BAD (FFHFHH) +Size 26: 13,31 GOOD (HHFFFF) +Size 27: 14,32 BAD (FFHFHH) +Size 28: 14,34 GOOD (HHFFFF) +Size 29: 15,35 BAD (FFHFHH) +Size 30: 15,36 GOOD (HHFFFF) +Size 31: 16,37 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,40 BAD (FFHFHH) +Size 34: 17,41 GOOD (HHFFFF) +Size 35: 18,42 BAD (FFHFHH) +Size 36: 18,43 GOOD (HHFFFF) +Size 37: 19,44 BAD (FFHFHH) +Size 38: 19,46 GOOD (HHFFFF) +Size 39: 20,47 BAD (FFHFHH) +Size 40: 20,48 GOOD (HHFFFF) +Size 41: 21,49 BAD (FFHFHH) +Size 42: 21,50 GOOD (HHFFFF) +Size 43: 22,52 BAD (FFHFHH) +Size 44: 22,53 GOOD (HHFFFF) +Size 45: 23,54 BAD (FFHFHH) +Size 46: 23,55 GOOD (HHFFFF) +Size 47: 24,56 BAD (FFHFHH) +Size 48: 24,58 GOOD (HHFFFF) +Size 49: 25,59 BAD (FFHFHH) +Size 50: 25,60 GOOD (HHFFFF) +Size 51: 26,61 BAD (FFHFHH) +Size 52: 26,62 GOOD (HHFFFF) +Size 53: 27,64 BAD (FFHFHH) +Size 54: 27,65 GOOD (HHFFFF) +Size 55: 28,66 BAD (FFHFHH) +Size 56: 28,67 GOOD (HHFFFF) +Size 57: 29,68 BAD (FFHFHH) +Size 58: 29,70 GOOD (HHFFFF) +Size 59: 30,71 BAD (FFHFHH) +Size 60: 30,72 GOOD (HHFFFF) +Size 61: 31,73 BAD (FFHFHH) +Size 62: 31,74 GOOD (HHFFFF) +Size 63: 32,76 BAD (FFHFHH) +Size 64: 32,77 GOOD (HHFFFF) +Size 65: 33,78 BAD (FFHFHH) +Size 66: 33,79 GOOD (HHFFFF) +Size 67: 34,80 BAD (FFHFHH) +Size 68: 34,82 GOOD (HHFFFF) +Size 69: 35,83 BAD (FFHFHH) +Size 70: 35,84 GOOD (HHFFFF) +Size 71: 36,85 BAD (FFHFHH) +Size 72: 36,86 GOOD (HHFFFF) +Size 73: 37,88 BAD (FFHFHH) +Size 74: 37,89 GOOD (HHFFFF) +Size 75: 38,90 BAD (FFHFHH) +Size 76: 38,91 GOOD (HHFFFF) +Size 77: 39,92 BAD (FFHFHH) +Size 78: 39,94 GOOD (HHFFFF) +Size 79: 40,95 BAD (FFHFHH) +Size 80: 40,96 GOOD (HHFFFF) +Size 81: 41,97 BAD (FFHFHH) +Size 82: 41,98 GOOD (HHFFFF) +Size 83: 42,100 BAD (FFHFHH) +Size 84: 42,101 GOOD (HHFFFF) +Size 85: 43,102 BAD (FFHFHH) +Size 86: 43,103 GOOD (HHFFFF) +Size 87: 44,104 BAD (FFHFHH) +Size 88: 44,106 GOOD (HHFFFF) +Size 89: 45,107 BAD (FFHFHH) +Size 90: 45,108 GOOD (HHFFFF) +Size 91: 46,109 BAD (FFHFHH) +Size 92: 46,110 GOOD (HHFFFF) +Size 93: 47,112 BAD (FFHFHH) +Size 94: 47,113 GOOD (HHFFFF) +Size 95: 48,114 BAD (FFHFHH) +Size 96: 48,115 GOOD (HHFFFF) +Size 97: 49,116 BAD (FFHFHH) +Size 98: 49,118 GOOD (HHFFFF) +Size 99: 50,119 BAD (FFHFHH) +Size 100: 50,120 GOOD (HHFFFF) + +Windows 8 +--------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,4 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,10 GOOD (HHFFFF) +Size 9: 5,11 BAD (FFHFHH) +Size 10: 5,12 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,16 BAD (FFHFHH) +Size 14: 7,17 GOOD (HHFFFF) +Size 15: 8,18 BAD (FFHFHH) +Size 16: 8,19 GOOD (HHFFFF) +Size 17: 9,20 BAD (FFHFHH) +Size 18: 9,22 GOOD (HHFFFF) +Size 19: 10,23 BAD (FFHFHH) +Size 20: 10,24 GOOD (HHFFFF) +Size 21: 11,25 BAD (FFHFHH) +Size 22: 11,26 GOOD (HHFFFF) +Size 23: 12,28 BAD (FFHFHH) +Size 24: 12,29 GOOD (HHFFFF) +Size 25: 13,30 BAD (FFHFHH) +Size 26: 13,31 GOOD (HHFFFF) +Size 27: 14,32 BAD (FFHFHH) +Size 28: 14,34 GOOD (HHFFFF) +Size 29: 15,35 BAD (FFHFHH) +Size 30: 15,36 GOOD (HHFFFF) +Size 31: 16,37 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,40 BAD (FFHFHH) +Size 34: 17,41 GOOD (HHFFFF) +Size 35: 18,42 BAD (FFHFHH) +Size 36: 18,43 GOOD (HHFFFF) +Size 37: 19,44 BAD (FFHFHH) +Size 38: 19,46 GOOD (HHFFFF) +Size 39: 20,47 BAD (FFHFHH) +Size 40: 20,48 GOOD (HHFFFF) +Size 41: 21,49 BAD (FFHFHH) +Size 42: 21,50 GOOD (HHFFFF) +Size 43: 22,52 BAD (FFHFHH) +Size 44: 22,53 GOOD (HHFFFF) +Size 45: 23,54 BAD (FFHFHH) +Size 46: 23,55 GOOD (HHFFFF) +Size 47: 24,56 BAD (FFHFHH) +Size 48: 24,58 GOOD (HHFFFF) +Size 49: 25,59 BAD (FFHFHH) +Size 50: 25,60 GOOD (HHFFFF) +Size 51: 26,61 BAD (FFHFHH) +Size 52: 26,62 GOOD (HHFFFF) +Size 53: 27,64 BAD (FFHFHH) +Size 54: 27,65 GOOD (HHFFFF) +Size 55: 28,66 BAD (FFHFHH) +Size 56: 28,67 GOOD (HHFFFF) +Size 57: 29,68 BAD (FFHFHH) +Size 58: 29,70 GOOD (HHFFFF) +Size 59: 30,71 BAD (FFHFHH) +Size 60: 30,72 GOOD (HHFFFF) +Size 61: 31,73 BAD (FFHFHH) +Size 62: 31,74 GOOD (HHFFFF) +Size 63: 32,76 BAD (FFHFHH) +Size 64: 32,77 GOOD (HHFFFF) +Size 65: 33,78 BAD (FFHFHH) +Size 66: 33,79 GOOD (HHFFFF) +Size 67: 34,80 BAD (FFHFHH) +Size 68: 34,82 GOOD (HHFFFF) +Size 69: 35,83 BAD (FFHFHH) +Size 70: 35,84 GOOD (HHFFFF) +Size 71: 36,85 BAD (FFHFHH) +Size 72: 36,86 GOOD (HHFFFF) +Size 73: 37,88 BAD (FFHFHH) +Size 74: 37,89 GOOD (HHFFFF) +Size 75: 38,90 BAD (FFHFHH) +Size 76: 38,91 GOOD (HHFFFF) +Size 77: 39,92 BAD (FFHFHH) +Size 78: 39,94 GOOD (HHFFFF) +Size 79: 40,95 BAD (FFHFHH) +Size 80: 40,96 GOOD (HHFFFF) +Size 81: 41,97 BAD (FFHFHH) +Size 82: 41,98 GOOD (HHFFFF) +Size 83: 42,100 BAD (FFHFHH) +Size 84: 42,101 GOOD (HHFFFF) +Size 85: 43,102 BAD (FFHFHH) +Size 86: 43,103 GOOD (HHFFFF) +Size 87: 44,104 BAD (FFHFHH) +Size 88: 44,106 GOOD (HHFFFF) +Size 89: 45,107 BAD (FFHFHH) +Size 90: 45,108 GOOD (HHFFFF) +Size 91: 46,109 BAD (FFHFHH) +Size 92: 46,110 GOOD (HHFFFF) +Size 93: 47,112 BAD (FFHFHH) +Size 94: 47,113 GOOD (HHFFFF) +Size 95: 48,114 BAD (FFHFHH) +Size 96: 48,115 GOOD (HHFFFF) +Size 97: 49,116 BAD (FFHFHH) +Size 98: 49,118 GOOD (HHFFFF) +Size 99: 50,119 BAD (FFHFHH) +Size 100: 50,120 GOOD (HHFFFF) + +Windows 8.1 +----------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,4 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,10 GOOD (HHFFFF) +Size 9: 5,11 BAD (FFHFHH) +Size 10: 5,12 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,16 BAD (FFHFHH) +Size 14: 7,17 GOOD (HHFFFF) +Size 15: 8,18 BAD (FFHFHH) +Size 16: 8,19 GOOD (HHFFFF) +Size 17: 9,20 BAD (FFHFHH) +Size 18: 9,22 GOOD (HHFFFF) +Size 19: 10,23 BAD (FFHFHH) +Size 20: 10,24 GOOD (HHFFFF) +Size 21: 11,25 BAD (FFHFHH) +Size 22: 11,26 GOOD (HHFFFF) +Size 23: 12,28 BAD (FFHFHH) +Size 24: 12,29 GOOD (HHFFFF) +Size 25: 13,30 BAD (FFHFHH) +Size 26: 13,31 GOOD (HHFFFF) +Size 27: 14,32 BAD (FFHFHH) +Size 28: 14,34 GOOD (HHFFFF) +Size 29: 15,35 BAD (FFHFHH) +Size 30: 15,36 GOOD (HHFFFF) +Size 31: 16,37 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,40 BAD (FFHFHH) +Size 34: 17,41 GOOD (HHFFFF) +Size 35: 18,42 BAD (FFHFHH) +Size 36: 18,43 GOOD (HHFFFF) +Size 37: 19,44 BAD (FFHFHH) +Size 38: 19,46 GOOD (HHFFFF) +Size 39: 20,47 BAD (FFHFHH) +Size 40: 20,48 GOOD (HHFFFF) +Size 41: 21,49 BAD (FFHFHH) +Size 42: 21,50 GOOD (HHFFFF) +Size 43: 22,52 BAD (FFHFHH) +Size 44: 22,53 GOOD (HHFFFF) +Size 45: 23,54 BAD (FFHFHH) +Size 46: 23,55 GOOD (HHFFFF) +Size 47: 24,56 BAD (FFHFHH) +Size 48: 24,58 GOOD (HHFFFF) +Size 49: 25,59 BAD (FFHFHH) +Size 50: 25,60 GOOD (HHFFFF) +Size 51: 26,61 BAD (FFHFHH) +Size 52: 26,62 GOOD (HHFFFF) +Size 53: 27,64 BAD (FFHFHH) +Size 54: 27,65 GOOD (HHFFFF) +Size 55: 28,66 BAD (FFHFHH) +Size 56: 28,67 GOOD (HHFFFF) +Size 57: 29,68 BAD (FFHFHH) +Size 58: 29,70 GOOD (HHFFFF) +Size 59: 30,71 BAD (FFHFHH) +Size 60: 30,72 GOOD (HHFFFF) +Size 61: 31,73 BAD (FFHFHH) +Size 62: 31,74 GOOD (HHFFFF) +Size 63: 32,76 BAD (FFHFHH) +Size 64: 32,77 GOOD (HHFFFF) +Size 65: 33,78 BAD (FFHFHH) +Size 66: 33,79 GOOD (HHFFFF) +Size 67: 34,80 BAD (FFHFHH) +Size 68: 34,82 GOOD (HHFFFF) +Size 69: 35,83 BAD (FFHFHH) +Size 70: 35,84 GOOD (HHFFFF) +Size 71: 36,85 BAD (FFHFHH) +Size 72: 36,86 GOOD (HHFFFF) +Size 73: 37,88 BAD (FFHFHH) +Size 74: 37,89 GOOD (HHFFFF) +Size 75: 38,90 BAD (FFHFHH) +Size 76: 38,91 GOOD (HHFFFF) +Size 77: 39,92 BAD (FFHFHH) +Size 78: 39,94 GOOD (HHFFFF) +Size 79: 40,95 BAD (FFHFHH) +Size 80: 40,96 GOOD (HHFFFF) +Size 81: 41,97 BAD (FFHFHH) +Size 82: 41,98 GOOD (HHFFFF) +Size 83: 42,100 BAD (FFHFHH) +Size 84: 42,101 GOOD (HHFFFF) +Size 85: 43,102 BAD (FFHFHH) +Size 86: 43,103 GOOD (HHFFFF) +Size 87: 44,104 BAD (FFHFHH) +Size 88: 44,106 GOOD (HHFFFF) +Size 89: 45,107 BAD (FFHFHH) +Size 90: 45,108 GOOD (HHFFFF) +Size 91: 46,109 BAD (FFHFHH) +Size 92: 46,110 GOOD (HHFFFF) +Size 93: 47,112 BAD (FFHFHH) +Size 94: 47,113 GOOD (HHFFFF) +Size 95: 48,114 BAD (FFHFHH) +Size 96: 48,115 GOOD (HHFFFF) +Size 97: 49,116 BAD (FFHFHH) +Size 98: 49,118 GOOD (HHFFFF) +Size 99: 50,119 BAD (FFHFHH) +Size 100: 50,120 GOOD (HHFFFF) + +Windows 10 14342 Old Console +---------------------------- + +Size 1: 1,2 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,4 BAD (FFHFHH) +Size 4: 2,5 GOOD (HHFFFF) +Size 5: 3,6 BAD (FFHFHH) +Size 6: 3,7 GOOD (HHFFFF) +Size 7: 4,8 BAD (FFHFHH) +Size 8: 4,10 GOOD (HHFFFF) +Size 9: 5,11 BAD (FFHFHH) +Size 10: 5,12 GOOD (HHFFFF) +Size 11: 6,13 BAD (FFHFHH) +Size 12: 6,14 GOOD (HHFFFF) +Size 13: 7,16 BAD (FFHFHH) +Size 14: 7,17 GOOD (HHFFFF) +Size 15: 8,18 BAD (FFHFHH) +Size 16: 8,19 GOOD (HHFFFF) +Size 17: 9,20 BAD (FFHFHH) +Size 18: 9,22 GOOD (HHFFFF) +Size 19: 10,23 BAD (FFHFHH) +Size 20: 10,24 GOOD (HHFFFF) +Size 21: 11,25 BAD (FFHFHH) +Size 22: 11,26 GOOD (HHFFFF) +Size 23: 12,28 BAD (FFHFHH) +Size 24: 12,29 GOOD (HHFFFF) +Size 25: 13,30 BAD (FFHFHH) +Size 26: 13,31 GOOD (HHFFFF) +Size 27: 14,32 BAD (FFHFHH) +Size 28: 14,34 GOOD (HHFFFF) +Size 29: 15,35 BAD (FFHFHH) +Size 30: 15,36 GOOD (HHFFFF) +Size 31: 16,37 BAD (FFHFHH) +Size 32: 16,38 GOOD (HHFFFF) +Size 33: 17,40 BAD (FFHFHH) +Size 34: 17,41 GOOD (HHFFFF) +Size 35: 18,42 BAD (FFHFHH) +Size 36: 18,43 GOOD (HHFFFF) +Size 37: 19,44 BAD (FFHFHH) +Size 38: 19,46 GOOD (HHFFFF) +Size 39: 20,47 BAD (FFHFHH) +Size 40: 20,48 GOOD (HHFFFF) +Size 41: 21,49 BAD (FFHFHH) +Size 42: 21,50 GOOD (HHFFFF) +Size 43: 22,52 BAD (FFHFHH) +Size 44: 22,53 GOOD (HHFFFF) +Size 45: 23,54 BAD (FFHFHH) +Size 46: 23,55 GOOD (HHFFFF) +Size 47: 24,56 BAD (FFHFHH) +Size 48: 24,58 GOOD (HHFFFF) +Size 49: 25,59 BAD (FFHFHH) +Size 50: 25,60 GOOD (HHFFFF) +Size 51: 26,61 BAD (FFHFHH) +Size 52: 26,62 GOOD (HHFFFF) +Size 53: 27,64 BAD (FFHFHH) +Size 54: 27,65 GOOD (HHFFFF) +Size 55: 28,66 BAD (FFHFHH) +Size 56: 28,67 GOOD (HHFFFF) +Size 57: 29,68 BAD (FFHFHH) +Size 58: 29,70 GOOD (HHFFFF) +Size 59: 30,71 BAD (FFHFHH) +Size 60: 30,72 GOOD (HHFFFF) +Size 61: 31,73 BAD (FFHFHH) +Size 62: 31,74 GOOD (HHFFFF) +Size 63: 32,76 BAD (FFHFHH) +Size 64: 32,77 GOOD (HHFFFF) +Size 65: 33,78 BAD (FFHFHH) +Size 66: 33,79 GOOD (HHFFFF) +Size 67: 34,80 BAD (FFHFHH) +Size 68: 34,82 GOOD (HHFFFF) +Size 69: 35,83 BAD (FFHFHH) +Size 70: 35,84 GOOD (HHFFFF) +Size 71: 36,85 BAD (FFHFHH) +Size 72: 36,86 GOOD (HHFFFF) +Size 73: 37,88 BAD (FFHFHH) +Size 74: 37,89 GOOD (HHFFFF) +Size 75: 38,90 BAD (FFHFHH) +Size 76: 38,91 GOOD (HHFFFF) +Size 77: 39,92 BAD (FFHFHH) +Size 78: 39,94 GOOD (HHFFFF) +Size 79: 40,95 BAD (FFHFHH) +Size 80: 40,96 GOOD (HHFFFF) +Size 81: 41,97 BAD (FFHFHH) +Size 82: 41,98 GOOD (HHFFFF) +Size 83: 42,100 BAD (FFHFHH) +Size 84: 42,101 GOOD (HHFFFF) +Size 85: 43,102 BAD (FFHFHH) +Size 86: 43,103 GOOD (HHFFFF) +Size 87: 44,104 BAD (FFHFHH) +Size 88: 44,106 GOOD (HHFFFF) +Size 89: 45,107 BAD (FFHFHH) +Size 90: 45,108 GOOD (HHFFFF) +Size 91: 46,109 BAD (FFHFHH) +Size 92: 46,110 GOOD (HHFFFF) +Size 93: 47,112 BAD (FFHFHH) +Size 94: 47,113 GOOD (HHFFFF) +Size 95: 48,114 BAD (FFHFHH) +Size 96: 48,115 GOOD (HHFFFF) +Size 97: 49,116 BAD (FFHFHH) +Size 98: 49,118 GOOD (HHFFFF) +Size 99: 50,119 BAD (FFHFHH) +Size 100: 50,120 GOOD (HHFFFF) + +Windows 10 14342 New Console +---------------------------- + +Size 1: 1,1 GOOD (HHFFFF) +Size 2: 1,2 GOOD (HHFFFF) +Size 3: 2,3 GOOD (HHFFFF) +Size 4: 2,4 GOOD (HHFFFF) +Size 5: 3,5 GOOD (HHFFFF) +Size 6: 3,6 GOOD (HHFFFF) +Size 7: 4,7 GOOD (HHFFFF) +Size 8: 4,8 GOOD (HHFFFF) +Size 9: 5,9 GOOD (HHFFFF) +Size 10: 5,10 GOOD (HHFFFF) +Size 11: 6,11 GOOD (HHFFFF) +Size 12: 6,12 GOOD (HHFFFF) +Size 13: 7,13 GOOD (HHFFFF) +Size 14: 7,14 GOOD (HHFFFF) +Size 15: 8,15 GOOD (HHFFFF) +Size 16: 8,16 GOOD (HHFFFF) +Size 17: 9,17 GOOD (HHFFFF) +Size 18: 9,18 GOOD (HHFFFF) +Size 19: 10,19 GOOD (HHFFFF) +Size 20: 10,20 GOOD (HHFFFF) +Size 21: 11,21 GOOD (HHFFFF) +Size 22: 11,22 GOOD (HHFFFF) +Size 23: 12,23 GOOD (HHFFFF) +Size 24: 12,24 GOOD (HHFFFF) +Size 25: 13,25 GOOD (HHFFFF) +Size 26: 13,26 GOOD (HHFFFF) +Size 27: 14,27 GOOD (HHFFFF) +Size 28: 14,28 GOOD (HHFFFF) +Size 29: 15,29 GOOD (HHFFFF) +Size 30: 15,30 GOOD (HHFFFF) +Size 31: 16,31 GOOD (HHFFFF) +Size 32: 16,32 GOOD (HHFFFF) +Size 33: 17,33 GOOD (HHFFFF) +Size 34: 17,34 GOOD (HHFFFF) +Size 35: 18,35 GOOD (HHFFFF) +Size 36: 18,36 GOOD (HHFFFF) +Size 37: 19,37 GOOD (HHFFFF) +Size 38: 19,38 GOOD (HHFFFF) +Size 39: 20,39 GOOD (HHFFFF) +Size 40: 20,40 GOOD (HHFFFF) +Size 41: 21,41 GOOD (HHFFFF) +Size 42: 21,42 GOOD (HHFFFF) +Size 43: 22,43 GOOD (HHFFFF) +Size 44: 22,44 GOOD (HHFFFF) +Size 45: 23,45 GOOD (HHFFFF) +Size 46: 23,46 GOOD (HHFFFF) +Size 47: 24,47 GOOD (HHFFFF) +Size 48: 24,48 GOOD (HHFFFF) +Size 49: 25,49 GOOD (HHFFFF) +Size 50: 25,50 GOOD (HHFFFF) +Size 51: 26,51 GOOD (HHFFFF) +Size 52: 26,52 GOOD (HHFFFF) +Size 53: 27,53 GOOD (HHFFFF) +Size 54: 27,54 GOOD (HHFFFF) +Size 55: 28,55 GOOD (HHFFFF) +Size 56: 28,56 GOOD (HHFFFF) +Size 57: 29,57 GOOD (HHFFFF) +Size 58: 29,58 GOOD (HHFFFF) +Size 59: 30,59 GOOD (HHFFFF) +Size 60: 30,60 GOOD (HHFFFF) +Size 61: 31,61 GOOD (HHFFFF) +Size 62: 31,62 GOOD (HHFFFF) +Size 63: 32,63 GOOD (HHFFFF) +Size 64: 32,64 GOOD (HHFFFF) +Size 65: 33,65 GOOD (HHFFFF) +Size 66: 33,66 GOOD (HHFFFF) +Size 67: 34,67 GOOD (HHFFFF) +Size 68: 34,68 GOOD (HHFFFF) +Size 69: 35,69 GOOD (HHFFFF) +Size 70: 35,70 GOOD (HHFFFF) +Size 71: 36,71 GOOD (HHFFFF) +Size 72: 36,72 GOOD (HHFFFF) +Size 73: 37,73 GOOD (HHFFFF) +Size 74: 37,74 GOOD (HHFFFF) +Size 75: 38,75 GOOD (HHFFFF) +Size 76: 38,76 GOOD (HHFFFF) +Size 77: 39,77 GOOD (HHFFFF) +Size 78: 39,78 GOOD (HHFFFF) +Size 79: 40,79 GOOD (HHFFFF) +Size 80: 40,80 GOOD (HHFFFF) +Size 81: 41,81 GOOD (HHFFFF) +Size 82: 41,82 GOOD (HHFFFF) +Size 83: 42,83 GOOD (HHFFFF) +Size 84: 42,84 GOOD (HHFFFF) +Size 85: 43,85 GOOD (HHFFFF) +Size 86: 43,86 GOOD (HHFFFF) +Size 87: 44,87 GOOD (HHFFFF) +Size 88: 44,88 GOOD (HHFFFF) +Size 89: 45,89 GOOD (HHFFFF) +Size 90: 45,90 GOOD (HHFFFF) +Size 91: 46,91 GOOD (HHFFFF) +Size 92: 46,92 GOOD (HHFFFF) +Size 93: 47,93 GOOD (HHFFFF) +Size 94: 47,94 GOOD (HHFFFF) +Size 95: 48,95 GOOD (HHFFFF) +Size 96: 48,96 GOOD (HHFFFF) +Size 97: 49,97 GOOD (HHFFFF) +Size 98: 49,98 GOOD (HHFFFF) +Size 99: 50,99 GOOD (HHFFFF) +Size 100: 50,100 GOOD (HHFFFF) diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt new file mode 100644 index 00000000000..d5261d8db39 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt @@ -0,0 +1,16 @@ +The narrowest allowed console window, in pixels, on a conventional (~96dpi) +monitor: + +(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 1 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12 + +(mode con: cols=40 lines=40) && SetFont.exe -face "Lucida Console" -h 16 && (ping -n 4 127.0.0.1 > NUL) && cls && GetConsolePos.exe && SetFont.exe -face "Lucida Console" -h 12 + + sz1:px sz1:col sz16:px sz16:col +Vista: 124 104 137 10 +Windows 7: 132 112 147 11 +Windows 8: 140 120 147 11 +Windows 8.1: 140 120 147 11 +Windows 10 OLD: 136 116 147 11 +Windows 10 NEW: 136 103 136 10 + +I used build 14342 to test Windows 10. diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt new file mode 100644 index 00000000000..15a825cb51b --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Results.txt @@ -0,0 +1,4 @@ +As before, avoid odd sizes in favor of even sizes. + +It's curious that the Japanese font is handled so poorly, especially with +Windows 8 and later. diff --git a/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt new file mode 100644 index 00000000000..fef397a1e34 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt @@ -0,0 +1,144 @@ +Issues: + + - Starting with the 14342 build, changing the font using + SetCurrentConsoleFontEx does not affect the window size. e.g. The content + itself will resize/redraw, but the window neither shrinks nor expands. + Presumably this is an oversight? It's almost a convenience; if a program + is going to resize the window anyway, then it's nice that the window size + contraints don't get in the way. Ordinarily, changing the font doesn't just + change the window size in pixels--it can also change the size as measured in + rows and columns. + + - (Aside: in the 14342 build, there is also a bug with wmic.exe. Open a console + with more than 300 lines of screen buffer, then fill those lines with, e.g., + dir /s. Then run wmic.exe. You won't be able to see the wmic.exe prompt. + If you query the screen buffer info somehow, you'll notice that the srWindow + is not contained within the dwSize. This breaks winpty's scraping, because + it's invalid.) + + - In build 14316, with the Japanese locale, with the 437 code page, attempting + to set the Consolas font instead sets the Terminal (raster) font. It seems + to pick an appropriate vertical size. + + - It seems necessary to specify "-family 0x36" for maximum reliability. + Setting the family to 0 almost always works, and specifying just -tt rarely + works. + +Win7 + English locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 932 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt unreliable + SetFont.exe -face Consolas -h 16 -family 0x36 works + +Win10 Build 10586 + New console + Japanese locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + +Win10 Build 14316 + Old console + English locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 932 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selected very small Consolas font + SetFont.exe -face Consolas -h 16 -family 0x36 works + New console + English locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt works + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 932 code page: + SetFont.exe -face Consolas -h 16 selects gothic instead + SetFont.exe -face Consolas -h 16 -tt selects gothic instead + SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead + Japanese locale / 437 code page: + SetFont.exe -face Consolas -h 16 selects Terminal font instead + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36(*) selects Terminal font instead + +Win10 Build 14342 + Old Console + English locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 932 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt selects Terminal font instead + SetFont.exe -face Consolas -h 16 -family 0x36 works + New console + English locale / 437 code page: + SetFont.exe -face Consolas -h 16 works + SetFont.exe -face Consolas -h 16 -tt works + SetFont.exe -face Consolas -h 16 -family 0x36 works + Japanese locale / 932 code page: + SetFont.exe -face Consolas -h 16 selects gothic instead + SetFont.exe -face Consolas -h 16 -tt selects gothic instead + SetFont.exe -face Consolas -h 16 -family 0x36 selects gothic instead + Japanese locale / 437 code page: + SetFont.exe -face Consolas -h 16 selects Terminal font instead + SetFont.exe -face Consolas -h 16 -tt works + SetFont.exe -face Consolas -h 16 -family 0x36 works + +(*) I was trying to figure out whether the inconsistency was at when I stumbled +onto this completely unexpected bug. Here's more detail: + + F:\>SetFont.exe -face Consolas -h 16 -family 0x36 -weight normal -w 8 + Setting to: nFont=0 dwFontSize=(8,16) FontFamily=0x36 FontWeight=400 FaceName="Consolas" + SetCurrentConsoleFontEx returned 1 + + F:\>GetFont.exe + largestConsoleWindowSize=(96,50) + maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C) + maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C) + 00-00: 12x16 + GetNumberOfConsoleFonts returned 0 + CP=437 OutputCP=437 + + F:\>SetFont.exe -face "Lucida Console" -h 16 -family 0x36 -weight normal + Setting to: nFont=0 dwFontSize=(0,16) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console" + SetCurrentConsoleFontEx returned 1 + + F:\>GetFont.exe + largestConsoleWindowSize=(96,50) + maxWnd=0: nFont=0 dwFontSize=(12,16) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C) + maxWnd=1: nFont=0 dwFontSize=(96,25) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C) + 00-00: 12x16 + GetNumberOfConsoleFonts returned 0 + CP=437 OutputCP=437 + + F:\>SetFont.exe -face "Lucida Console" -h 12 -family 0x36 -weight normal + Setting to: nFont=0 dwFontSize=(0,12) FontFamily=0x36 FontWeight=400 FaceName="Lucida Console" + SetCurrentConsoleFontEx returned 1 + + F:\>GetFont.exe + largestConsoleWindowSize=(230,66) + maxWnd=0: nFont=0 dwFontSize=(5,12) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C) + maxWnd=1: nFont=0 dwFontSize=(116,36) FontFamily=0x30 FontWeight=400 FaceName=Terminal (54 65 72 6D 69 6E 61 6C) + 00-00: 5x12 + GetNumberOfConsoleFonts returned 0 + CP=437 OutputCP=437 + +Even attempting to set to a Lucida Console / Consolas font from the Console +properties dialog fails. diff --git a/src/libs/3rdparty/winpty/misc/FontSurvey.cc b/src/libs/3rdparty/winpty/misc/FontSurvey.cc new file mode 100644 index 00000000000..254bcc81a60 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/FontSurvey.cc @@ -0,0 +1,100 @@ +#include + +#include +#include +#include + +#include + +#include "TestUtil.cc" + +#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0])) + +// See https://en.wikipedia.org/wiki/List_of_CJK_fonts +const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese +const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese +const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese +const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean + +std::vector condense(const std::vector &buf) { + std::vector ret; + size_t i = 0; + while (i < buf.size()) { + if (buf[i].Char.UnicodeChar == L' ' && + ((buf[i].Attributes & 0x300) == 0)) { + // end of line + break; + } else if (i + 1 < buf.size() && + ((buf[i].Attributes & 0x300) == 0x100) && + ((buf[i + 1].Attributes & 0x300) == 0x200) && + buf[i].Char.UnicodeChar != L' ' && + buf[i].Char.UnicodeChar == buf[i + 1].Char.UnicodeChar) { + // double-width + ret.push_back(true); + i += 2; + } else if ((buf[i].Attributes & 0x300) == 0) { + // single-width + ret.push_back(false); + i++; + } else { + ASSERT(false && "unexpected output"); + } + } + return ret; +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + printf("Usage: %s \"arguments for SetFont.exe\"\n", argv[0]); + return 1; + } + + const char *setFontArgs = argv[1]; + + const wchar_t testLine[] = { 0xA2, 0xA3, 0x2014, 0x3044, 0x30FC, 0x4000, 0 }; + const HANDLE conout = openConout(); + + char setFontCmd[1024]; + for (int h = 1; h <= 100; ++h) { + sprintf(setFontCmd, ".\\SetFont.exe %s -h %d && cls", setFontArgs, h); + system(setFontCmd); + + CONSOLE_FONT_INFOEX infoex = {}; + infoex.cbSize = sizeof(infoex); + BOOL success = GetCurrentConsoleFontEx(conout, FALSE, &infoex); + ASSERT(success && "GetCurrentConsoleFontEx failed"); + + DWORD actual = 0; + success = WriteConsoleW(conout, testLine, wcslen(testLine), &actual, nullptr); + ASSERT(success && actual == wcslen(testLine)); + + std::vector readBuf(14); + const SMALL_RECT readRegion = {0, 0, static_cast(readBuf.size() - 1), 0}; + SMALL_RECT readRegion2 = readRegion; + success = ReadConsoleOutputW( + conout, readBuf.data(), + {static_cast(readBuf.size()), 1}, + {0, 0}, + &readRegion2); + ASSERT(success && !memcmp(&readRegion, &readRegion2, sizeof(readRegion))); + + const auto widths = condense(readBuf); + std::string widthsStr; + for (bool width : widths) { + widthsStr.append(width ? "F" : "H"); + } + char size[16]; + sprintf(size, "%d,%d", infoex.dwFontSize.X, infoex.dwFontSize.Y); + const char *status = ""; + if (widthsStr == "HHFFFF") { + status = "GOOD"; + } else if (widthsStr == "HHHFFF") { + status = "OK"; + } else { + status = "BAD"; + } + trace("Size %3d: %-7s %-4s (%s)", h, size, status, widthsStr.c_str()); + } + sprintf(setFontCmd, ".\\SetFont.exe %s -h 14", setFontArgs); + system(setFontCmd); +} diff --git a/src/libs/3rdparty/winpty/misc/FormatChar.h b/src/libs/3rdparty/winpty/misc/FormatChar.h new file mode 100644 index 00000000000..aade488f9e2 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/FormatChar.h @@ -0,0 +1,21 @@ +#include +#include +#include + +static inline void formatChar(char *str, char ch) +{ + // Print some common control codes. + switch (ch) { + case '\r': strcpy(str, "CR "); break; + case '\n': strcpy(str, "LF "); break; + case ' ': strcpy(str, "SP "); break; + case 27: strcpy(str, "^[ "); break; + case 3: strcpy(str, "^C "); break; + default: + if (isgraph(ch)) + sprintf(str, "%c ", ch); + else + sprintf(str, "%02x ", ch); + break; + } +} diff --git a/src/libs/3rdparty/winpty/misc/FreezePerfTest.cc b/src/libs/3rdparty/winpty/misc/FreezePerfTest.cc new file mode 100644 index 00000000000..2c0b0086a14 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/FreezePerfTest.cc @@ -0,0 +1,62 @@ +#include + +#include "TestUtil.cc" + +const int SC_CONSOLE_MARK = 0xFFF2; +const int SC_CONSOLE_SELECT_ALL = 0xFFF5; + +int main(int argc, char *argv[0]) { + + if (argc != 2) { + printf("Usage: %s (mark|selectall|read)\n", argv[0]); + return 1; + } + + enum class Test { Mark, SelectAll, Read } test; + if (!strcmp(argv[1], "mark")) { + test = Test::Mark; + } else if (!strcmp(argv[1], "selectall")) { + test = Test::SelectAll; + } else if (!strcmp(argv[1], "read")) { + test = Test::Read; + } else { + printf("Invalid test: %s\n", argv[1]); + return 1; + } + + HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + TimeMeasurement tm; + HWND hwnd = GetConsoleWindow(); + + setWindowPos(0, 0, 1, 1); + setBufferSize(100, 3000); + system("cls"); + setWindowPos(0, 2975, 100, 25); + setCursorPos(0, 2999); + + ShowWindow(hwnd, SW_HIDE); + + for (int i = 0; i < 1000; ++i) { + // CONSOLE_SCREEN_BUFFER_INFO info = {}; + // GetConsoleScreenBufferInfo(conout, &info); + + if (test == Test::Mark) { + SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); + SendMessage(hwnd, WM_CHAR, 27, 0x00010001); + } else if (test == Test::SelectAll) { + SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0); + SendMessage(hwnd, WM_CHAR, 27, 0x00010001); + } else if (test == Test::Read) { + static CHAR_INFO buffer[100 * 3000]; + const SMALL_RECT readRegion = {0, 0, 99, 2999}; + SMALL_RECT tmp = readRegion; + BOOL ret = ReadConsoleOutput(conout, buffer, {100, 3000}, {0, 0}, &tmp); + ASSERT(ret && !memcmp(&tmp, &readRegion, sizeof(tmp))); + } + } + + ShowWindow(hwnd, SW_SHOW); + + printf("elapsed: %f\n", tm.elapsed()); + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/GetCh.cc b/src/libs/3rdparty/winpty/misc/GetCh.cc new file mode 100644 index 00000000000..cd6ed1943ad --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/GetCh.cc @@ -0,0 +1,20 @@ +#include +#include +#include + +int main() { + printf("\nPress any keys -- Ctrl-D exits\n\n"); + + while (true) { + const int ch = getch(); + printf("0x%x", ch); + if (isgraph(ch)) { + printf(" '%c'", ch); + } + printf("\n"); + if (ch == 0x4) { // Ctrl-D + break; + } + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/GetConsolePos.cc b/src/libs/3rdparty/winpty/misc/GetConsolePos.cc new file mode 100644 index 00000000000..1f3cc5316f1 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/GetConsolePos.cc @@ -0,0 +1,41 @@ +#include + +#include + +#include "TestUtil.cc" + +int main() { + const HANDLE conout = openConout(); + + CONSOLE_SCREEN_BUFFER_INFO info = {}; + BOOL ret = GetConsoleScreenBufferInfo(conout, &info); + ASSERT(ret && "GetConsoleScreenBufferInfo failed"); + + trace("cursor=%d,%d", info.dwCursorPosition.X, info.dwCursorPosition.Y); + printf("cursor=%d,%d\n", info.dwCursorPosition.X, info.dwCursorPosition.Y); + + trace("srWindow={L=%d,T=%d,R=%d,B=%d}", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom); + printf("srWindow={L=%d,T=%d,R=%d,B=%d}\n", info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom); + + trace("dwSize=%d,%d", info.dwSize.X, info.dwSize.Y); + printf("dwSize=%d,%d\n", info.dwSize.X, info.dwSize.Y); + + const HWND hwnd = GetConsoleWindow(); + if (hwnd != NULL) { + RECT r = {}; + if (GetWindowRect(hwnd, &r)) { + const int w = r.right - r.left; + const int h = r.bottom - r.top; + trace("hwnd: pos=(%d,%d) size=(%d,%d)", r.left, r.top, w, h); + printf("hwnd: pos=(%d,%d) size=(%d,%d)\n", r.left, r.top, w, h); + } else { + trace("GetWindowRect failed"); + printf("GetWindowRect failed\n"); + } + } else { + trace("GetConsoleWindow returned NULL"); + printf("GetConsoleWindow returned NULL\n"); + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/GetFont.cc b/src/libs/3rdparty/winpty/misc/GetFont.cc new file mode 100644 index 00000000000..38625317ab2 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/GetFont.cc @@ -0,0 +1,261 @@ +#include +#include +#include +#include + +#include "../src/shared/OsModule.h" +#include "../src/shared/StringUtil.h" + +#include "TestUtil.cc" +#include "../src/shared/StringUtil.cc" + +#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) + +// Some of these types and functions are missing from the MinGW headers. +// Others are undocumented. + +struct AGENT_CONSOLE_FONT_INFO { + DWORD nFont; + COORD dwFontSize; +}; + +struct AGENT_CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +}; + +// undocumented XP API +typedef BOOL WINAPI SetConsoleFont_t( + HANDLE hOutput, + DWORD dwFontIndex); + +// undocumented XP API +typedef DWORD WINAPI GetNumberOfConsoleFonts_t(); + +// XP and up +typedef BOOL WINAPI GetCurrentConsoleFont_t( + HANDLE hOutput, + BOOL bMaximumWindow, + AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont); + +// XP and up +typedef COORD WINAPI GetConsoleFontSize_t( + HANDLE hConsoleOutput, + DWORD nFont); + +// Vista and up +typedef BOOL WINAPI GetCurrentConsoleFontEx_t( + HANDLE hConsoleOutput, + BOOL bMaximumWindow, + AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); + +// Vista and up +typedef BOOL WINAPI SetCurrentConsoleFontEx_t( + HANDLE hConsoleOutput, + BOOL bMaximumWindow, + AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); + +#define GET_MODULE_PROC(mod, funcName) \ + m_##funcName = reinterpret_cast((mod).proc(#funcName)); \ + +#define DEFINE_ACCESSOR(funcName) \ + funcName##_t &funcName() const { \ + ASSERT(valid()); \ + return *m_##funcName; \ + } + +class XPFontAPI { +public: + XPFontAPI() : m_kernel32(L"kernel32.dll") { + GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont); + GET_MODULE_PROC(m_kernel32, GetConsoleFontSize); + } + + bool valid() const { + return m_GetCurrentConsoleFont != NULL && + m_GetConsoleFontSize != NULL; + } + + DEFINE_ACCESSOR(GetCurrentConsoleFont) + DEFINE_ACCESSOR(GetConsoleFontSize) + +private: + OsModule m_kernel32; + GetCurrentConsoleFont_t *m_GetCurrentConsoleFont; + GetConsoleFontSize_t *m_GetConsoleFontSize; +}; + +class UndocumentedXPFontAPI : public XPFontAPI { +public: + UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") { + GET_MODULE_PROC(m_kernel32, SetConsoleFont); + GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts); + } + + bool valid() const { + return this->XPFontAPI::valid() && + m_SetConsoleFont != NULL && + m_GetNumberOfConsoleFonts != NULL; + } + + DEFINE_ACCESSOR(SetConsoleFont) + DEFINE_ACCESSOR(GetNumberOfConsoleFonts) + +private: + OsModule m_kernel32; + SetConsoleFont_t *m_SetConsoleFont; + GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts; +}; + +class VistaFontAPI : public XPFontAPI { +public: + VistaFontAPI() : m_kernel32(L"kernel32.dll") { + GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx); + GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx); + } + + bool valid() const { + return this->XPFontAPI::valid() && + m_GetCurrentConsoleFontEx != NULL && + m_SetCurrentConsoleFontEx != NULL; + } + + DEFINE_ACCESSOR(GetCurrentConsoleFontEx) + DEFINE_ACCESSOR(SetCurrentConsoleFontEx) + +private: + OsModule m_kernel32; + GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx; + SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx; +}; + +static std::vector > readFontTable( + XPFontAPI &api, HANDLE conout, DWORD maxCount) { + std::vector > ret; + for (DWORD i = 0; i < maxCount; ++i) { + COORD size = api.GetConsoleFontSize()(conout, i); + if (size.X == 0 && size.Y == 0) { + break; + } + ret.push_back(std::make_pair(i, size)); + } + return ret; +} + +static void dumpFontTable(HANDLE conout) { + const int kMaxCount = 1000; + XPFontAPI api; + if (!api.valid()) { + printf("dumpFontTable: cannot dump font table -- missing APIs\n"); + return; + } + std::vector > table = + readFontTable(api, conout, kMaxCount); + std::string line; + char tmp[128]; + size_t first = 0; + while (first < table.size()) { + size_t last = std::min(table.size() - 1, first + 10 - 1); + winpty_snprintf(tmp, "%02u-%02u:", + static_cast(first), static_cast(last)); + line = tmp; + for (size_t i = first; i <= last; ++i) { + if (i % 10 == 5) { + line += " - "; + } + winpty_snprintf(tmp, " %2dx%-2d", + table[i].second.X, table[i].second.Y); + line += tmp; + } + printf("%s\n", line.c_str()); + first = last + 1; + } + if (table.size() == kMaxCount) { + printf("... stopped reading at %d fonts ...\n", kMaxCount); + } +} + +static std::string stringToCodePoints(const std::wstring &str) { + std::string ret = "("; + for (size_t i = 0; i < str.size(); ++i) { + char tmp[32]; + winpty_snprintf(tmp, "%X", str[i]); + if (ret.size() > 1) { + ret.push_back(' '); + } + ret += tmp; + } + ret.push_back(')'); + return ret; +} + +static void dumpFontInfoEx( + const AGENT_CONSOLE_FONT_INFOEX &infoex) { + std::wstring faceName(infoex.FaceName, + winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName))); + cprintf(L"nFont=%u dwFontSize=(%d,%d) " + "FontFamily=0x%x FontWeight=%u FaceName=%ls %hs\n", + static_cast(infoex.nFont), + infoex.dwFontSize.X, infoex.dwFontSize.Y, + infoex.FontFamily, infoex.FontWeight, faceName.c_str(), + stringToCodePoints(faceName).c_str()); +} + +static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, BOOL maxWindow) { + AGENT_CONSOLE_FONT_INFOEX infoex = {0}; + infoex.cbSize = sizeof(infoex); + if (!api.GetCurrentConsoleFontEx()(conout, maxWindow, &infoex)) { + printf("GetCurrentConsoleFontEx call failed\n"); + return; + } + dumpFontInfoEx(infoex); +} + +static void dumpXPFont(XPFontAPI &api, HANDLE conout, BOOL maxWindow) { + AGENT_CONSOLE_FONT_INFO info = {0}; + if (!api.GetCurrentConsoleFont()(conout, maxWindow, &info)) { + printf("GetCurrentConsoleFont call failed\n"); + return; + } + printf("nFont=%u dwFontSize=(%d,%d)\n", + static_cast(info.nFont), + info.dwFontSize.X, info.dwFontSize.Y); +} + +static void dumpFontAndTable(HANDLE conout) { + VistaFontAPI vista; + if (vista.valid()) { + printf("maxWnd=0: "); dumpVistaFont(vista, conout, FALSE); + printf("maxWnd=1: "); dumpVistaFont(vista, conout, TRUE); + dumpFontTable(conout); + return; + } + UndocumentedXPFontAPI xp; + if (xp.valid()) { + printf("maxWnd=0: "); dumpXPFont(xp, conout, FALSE); + printf("maxWnd=1: "); dumpXPFont(xp, conout, TRUE); + dumpFontTable(conout); + return; + } + printf("setSmallFont: neither Vista nor XP APIs detected -- giving up\n"); + dumpFontTable(conout); +} + +int main() { + const HANDLE conout = openConout(); + const COORD largest = GetLargestConsoleWindowSize(conout); + printf("largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y); + dumpFontAndTable(conout); + UndocumentedXPFontAPI xp; + if (xp.valid()) { + printf("GetNumberOfConsoleFonts returned %u\n", xp.GetNumberOfConsoleFonts()()); + } else { + printf("The GetNumberOfConsoleFonts API was missing\n"); + } + printf("CP=%u OutputCP=%u\n", GetConsoleCP(), GetConsoleOutputCP()); + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps1 b/src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps1 new file mode 100644 index 00000000000..0c488597bd2 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/IdentifyConsoleWindow.ps1 @@ -0,0 +1,51 @@ +# +# Usage: powershell \IdentifyConsoleWindow.ps1 +# +# This script determines whether the process has a console attached, whether +# that console has a non-NULL window (e.g. HWND), and whether the window is on +# the current window station. +# + +$signature = @' +[DllImport("kernel32.dll", SetLastError=true)] +public static extern IntPtr GetConsoleWindow(); + +[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)] +public static extern bool SetConsoleTitle(String title); + +[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)] +public static extern int GetWindowText(IntPtr hWnd, + System.Text.StringBuilder lpString, + int nMaxCount); +'@ + +$WinAPI = Add-Type -MemberDefinition $signature ` + -Name WinAPI -Namespace IdentifyConsoleWindow -PassThru + +if (!$WinAPI::SetConsoleTitle("ConsoleWindowScript")) { + echo "error: could not change console title -- is a console attached?" + exit 1 +} else { + echo "note: successfully set console title to ""ConsoleWindowScript""." +} + +$hwnd = $WinAPI::GetConsoleWindow() +if ($hwnd -eq 0) { + echo "note: GetConsoleWindow returned NULL." +} else { + echo "note: GetConsoleWindow returned 0x$($hwnd.ToString("X"))." + $sb = New-Object System.Text.StringBuilder -ArgumentList 4096 + if ($WinAPI::GetWindowText($hwnd, $sb, $sb.Capacity)) { + $title = $sb.ToString() + echo "note: GetWindowText returned ""${title}""." + if ($title -eq "ConsoleWindowScript") { + echo "success!" + } else { + echo "error: expected to see ""ConsoleWindowScript""." + echo " (Perhaps the console window is on a different window station?)" + } + } else { + echo "error: GetWindowText could not read the window title." + echo " (Perhaps the console window is on a different window station?)" + } +} diff --git a/src/libs/3rdparty/winpty/misc/IsNewConsole.cc b/src/libs/3rdparty/winpty/misc/IsNewConsole.cc new file mode 100644 index 00000000000..2b554c72c9f --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/IsNewConsole.cc @@ -0,0 +1,87 @@ +// Determines whether this is a new console by testing whether MARK moves the +// cursor. +// +// WARNING: This test program may behave erratically if run under winpty. +// + +#include + +#include +#include + +#include "TestUtil.cc" + +const int SC_CONSOLE_MARK = 0xFFF2; +const int SC_CONSOLE_SELECT_ALL = 0xFFF5; + +static COORD getWindowPos(HANDLE conout) { + CONSOLE_SCREEN_BUFFER_INFO info = {}; + BOOL ret = GetConsoleScreenBufferInfo(conout, &info); + ASSERT(ret && "GetConsoleScreenBufferInfo failed"); + return { info.srWindow.Left, info.srWindow.Top }; +} + +static COORD getWindowSize(HANDLE conout) { + CONSOLE_SCREEN_BUFFER_INFO info = {}; + BOOL ret = GetConsoleScreenBufferInfo(conout, &info); + ASSERT(ret && "GetConsoleScreenBufferInfo failed"); + return { + static_cast(info.srWindow.Right - info.srWindow.Left + 1), + static_cast(info.srWindow.Bottom - info.srWindow.Top + 1) + }; +} + +static COORD getCursorPos(HANDLE conout) { + CONSOLE_SCREEN_BUFFER_INFO info = {}; + BOOL ret = GetConsoleScreenBufferInfo(conout, &info); + ASSERT(ret && "GetConsoleScreenBufferInfo failed"); + return info.dwCursorPosition; +} + +static void setCursorPos(HANDLE conout, COORD pos) { + BOOL ret = SetConsoleCursorPosition(conout, pos); + ASSERT(ret && "SetConsoleCursorPosition failed"); +} + +int main() { + const HANDLE conout = openConout(); + const HWND hwnd = GetConsoleWindow(); + ASSERT(hwnd != NULL && "GetConsoleWindow() returned NULL"); + + // With the legacy console, the Mark command moves the the cursor to the + // top-left cell of the visible console window. Determine whether this + // is the new console by seeing if the cursor moves. + + const auto windowSize = getWindowSize(conout); + if (windowSize.X <= 1) { + printf("Error: console window must be at least 2 columns wide\n"); + trace("Error: console window must be at least 2 columns wide"); + return 1; + } + + bool cursorMoved = false; + const auto initialPos = getCursorPos(conout); + + const auto windowPos = getWindowPos(conout); + setCursorPos(conout, { static_cast(windowPos.X + 1), windowPos.Y }); + + { + const auto posA = getCursorPos(conout); + SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); + const auto posB = getCursorPos(conout); + cursorMoved = memcmp(&posA, &posB, sizeof(posA)) != 0; + SendMessage(hwnd, WM_CHAR, 27, 0x00010001); // Send ESCAPE + } + + setCursorPos(conout, initialPos); + + if (cursorMoved) { + printf("Legacy console (i.e. MARK moved cursor)\n"); + trace("Legacy console (i.e. MARK moved cursor)"); + } else { + printf("Windows 10 new console (i.e MARK did not move cursor)\n"); + trace("Windows 10 new console (i.e MARK did not move cursor)"); + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/MouseInputNotes.txt b/src/libs/3rdparty/winpty/misc/MouseInputNotes.txt new file mode 100644 index 00000000000..18460c6861e --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/MouseInputNotes.txt @@ -0,0 +1,90 @@ +Introduction +============ + +The only specification I could find describing mouse input escape sequences +was the /usr/share/doc/xterm/ctlseqs.txt.gz file installed on my Ubuntu +machine. + +Here are the relevant escape sequences: + + * [ON] CSI '?' M 'h' Enable mouse input mode M + * [OFF] CSI '?' M 'l' Disable mouse input mode M + * [EVT] CSI 'M' F X Y Mouse event (default or mode 1005) + * [EVT6] CSI '<' F ';' X ';' Y 'M' Mouse event with mode 1006 + * [EVT6] CSI '<' F ';' X ';' Y 'm' Mouse event with mode 1006 (up) + * [EVT15] CSI F ';' X ';' Y 'M' Mouse event with mode 1015 + +The first batch of modes affect what events are reported: + + * 9: Presses only (not as well-supported as the other modes) + * 1000: Presses and releases + * 1002: Presses, releases, and moves-while-pressed + * 1003: Presses, releases, and all moves + +The next batch of modes affect the encoding of the mouse events: + + * 1005: The X and Y coordinates are UTF-8 codepoints rather than bytes. + * 1006: Use the EVT6 sequences instead of EVT + * 1015: Use the EVT15 sequence instead of EVT (aka URVXT-mode) + +Support for modes in existing terminals +======================================= + + | 9 1000 1002 1003 | 1004 | overflow | defhi | 1005 1006 1015 +---------------------------------+---------------------+------+--------------+-------+---------------- +Eclipse TM Terminal (Neon) | _ _ _ _ | _ | n/a | n/a | _ _ _ +gnome-terminal 3.6.2 | X X X X | _ | suppressed*b | 0x07 | _ X X +iTerm2 2.1.4 | _ X X X | OI | wrap*z | n/a | X X X +jediterm/IntelliJ | _ X X X | _ | ch='?' | 0xff | X X X +Konsole 2.13.2 | _ X X *a | _ | suppressed | 0xff | X X X +mintty 2.2.2 | X X X X | OI | ch='\0' | 0xff | X X X +putty 0.66 | _ X X _ | _ | suppressed | 0xff | _ X X +rxvt 2.7.10 | X X _ _ | _ | wrap*z | n/a | _ _ _ +screen(under xterm) | X X X X | _ | suppressed | 0xff | _ _ _ +urxvt 9.21 | X X X X | _ | wrap*z | n/a | X _ X +xfce4-terminal 0.6.3 (GTK2 VTE) | X X X X | _ | wrap | n/a | _ _ _ +xterm | X X X X | OI | ch='\0' | 0xff | X X X + +*a: Mode 1003 is handled the same way as 1002. +*b: The coordinate wraps from 0xff to 0x00, then maxs out at 0x07. I'm + guessing this behavior is a bug? I'm using the Xubuntu 14.04 + gnome-terminal. +*z: These terminals have a bug where column 224 (and row 224, presumably) + yields a truncated escape sequence. 224 + 32 is 0, so it would normally + yield `CSI 'M' F '\0' Y`, but the '\0' is interpreted as a NUL-terminator. + +Problem 1: How do these flags work? +=================================== + +Terminals accept the OFF sequence with any of the input modes. This makes +little sense--there are two multi-value settings, not seven independent flags! + +All the terminals handle Granularity the same way. ON-Granularity sets +Granularity to the specified value, and OFF-Granularity sets Granularity to +OFF. + +Terminals vary in how they handle the Encoding modes. For example: + + * xterm. ON-Encoding sets Encoding. OFF-Encoding with a non-active Encoding + has no effect. OFF-Encoding otherwise resets Encoding to Default. + + * mintty (tested 2.2.2), iTerm2 2.1.4, and jediterm. ON-Encoding sets + Encoding. OFF-Encoding resets Encoding to Default. + + * Konsole (tested 2.13.2) seems to configure each encoding method + independently. The effective Encoding is the first enabled encoding in this + list: + - Mode 1006 + - Mode 1015 + - Mode 1005 + - Default + + * gnome-terminal (tested 3.6.2) also configures each encoding method + independently. The effective Encoding is the first enabled encoding in + this list: + - Mode 1006 + - Mode 1015 + - Default + Mode 1005 is not supported. + + * xfce4 terminal 0.6.3 (GTK2 VTE) always outputs the default encoding method. diff --git a/src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc b/src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc new file mode 100644 index 00000000000..7d9684fe94e --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/MoveConsoleWindow.cc @@ -0,0 +1,34 @@ +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + if (argc != 3 && argc != 5) { + printf("Usage: %s x y\n", argv[0]); + printf("Usage: %s x y width height\n", argv[0]); + return 1; + } + + HWND hwnd = GetConsoleWindow(); + + const int x = atoi(argv[1]); + const int y = atoi(argv[2]); + + int w = 0, h = 0; + if (argc == 3) { + RECT r = {}; + BOOL ret = GetWindowRect(hwnd, &r); + ASSERT(ret && "GetWindowRect failed on console window"); + w = r.right - r.left; + h = r.bottom - r.top; + } else { + w = atoi(argv[3]); + h = atoi(argv[4]); + } + + BOOL ret = MoveWindow(hwnd, x, y, w, h, TRUE); + trace("MoveWindow: ret=%d", ret); + printf("MoveWindow: ret=%d\n", ret); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Notes.txt b/src/libs/3rdparty/winpty/misc/Notes.txt new file mode 100644 index 00000000000..410e1841986 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Notes.txt @@ -0,0 +1,219 @@ +Test programs +------------- + +Cygwin + emacs + vim + mc (Midnight Commander) + lynx + links + less + more + wget + +Capturing the console output +---------------------------- + +Initial idea: + +In the agent, keep track of the remote terminal state for N lines of +(window+history). Also keep track of the terminal size. Regularly poll for +changes to the console screen buffer, then use some number of edits to bring +the remote terminal into sync with the console. + +This idea seems to have trouble when a Unix terminal is resized. When the +server receives a resize notification, it can have a hard time figuring out +what the terminal did. Race conditions might also be a problem. + +The behavior of the terminal can be tricky: + + - When the window is expanded by one line, does the terminal add a blank line + to the bottom or move a line from the history into the top? + + - When the window is shrunk by one line, does the terminal delete the topmost + or the bottommost line? Can it delete the line with the cursor? + +Some popular behaviors for expanding: + - [all] If there are no history lines, then add a line at the bottom. + - [konsole] Always add a line at the bottom. + - [putty,xterm,rxvt] Pull in a history line from the top. + - [g-t] I can't tell. It seems to add a blank line, until the program writes + to stdout or until I click the scroll bar, then the output "snaps" back down, + pulling lines out of the history. I thought I saw different behavior + between Ubuntu 10.10 and 11.10, so maybe GNOME 3 changed something. Avoid + using "bash" to test this behavior because "bash" apparently always writes + the prompt after terminal resize. + +Some popular behaviors for shrinking: + - [konsole,putty,xterm,rxvt] If the line at the bottom is blank, then delete + it. Otherwise, move the topmost line into history. + - [g-t] If the line at the bottom has not been touched, then delete it. + Otherwise, move the topmost line into history. + +(TODO: I need to test my theories about the terminal behavior better still. +It's interesting to see how g-t handles clear differently than every other +terminal.) + +There is an ANSI escape sequence (DSR) that sends the current cursor location +to the terminal's input. One idea I had was to use this code to figure out how +the terminal had handled a resize. I currently think this idea won't work due +to race conditions. + +Newer idea: + +Keep track of the last N lines that have been sent to the remote terminal. +Poll for changes to console output. When the output changes, send just the +changed content to the terminal. In particular: + - Don't send a cursor position (CUP) code. Instead, if the line that's 3 + steps up from the latest line changes, send a relative cursor up (CUU) + code. It's OK to send an absolute column number code (CHA). + - At least in general, don't try to send complete screenshots of the current + console window. + +The idea is that sending just the changes should have good behavior for streams +of output, even when those streams modify the output (e.g. an archiver, or +maybe a downloader/packager/wget). I need to think about whether this works +for full-screen programs (e.g. emacs, less, lynx, the above list of programs). + +I noticed that console programs don't typically modify the window or buffer +coordinates. edit.com is an exception. + +I tested the pager in native Python (more?), and I verified that ENTER and SPACE +both paid no attention to the location of the console window within the screen +buffer. This makes sense -- why would they care? The Cygwin less, on the other +hand, does care. If I scroll the window up, then Cygwin less will write to a +position within the window. I didn't really expect this behavior, but it +doesn't seem to be a problem. + +Setting up a TestNetServer service +---------------------------------- + +First run the deploy.sh script to copy files into deploy. Make sure +TestNetServer.exe will run in a bare environment (no MinGW or Qt in the path). + +Install the Windows Server 2003 Resource Kit. It will have two programs in it, +instsrv and srvany. + +Run: + + InstSrv TestNetServer \srvany.exe + +This creates a service named "TestNetServer" that uses the Microsoft service +wrapper. To configure the new service to run TestNetServer, set a registry +value: + + [HKLM\SYSTEM\CurrentControlSet\Services\TestNetServer\Parameters] + Application=\TestNetServer.exe + +Also see http://www.iopus.com/guides/srvany.htm. + +To remove the service, run: + + InstSrv TestNetServer REMOVE + +TODO +---- + +Agent: When resizing the console, consider whether to add lines to the top +or bottom. I remember thinking the current behavior was wrong for some +application, but I forgot which one. + +Make the font as small as possible. The console window dimensions are limited by +the screen size, so making the font small reduces an unnecessary limitation on the +PseudoConsole size. There's a documented Vista/Win7 API for this +(SetCurrentConsoleFontEx), and apparently WinXP has an undocumented API +(SetConsoleFont): + http://blogs.microsoft.co.il/blogs/pavely/archive/2009/07/23/changing-console-fonts.aspx + +Make the agent work with DOS programs like edit and qbasic. + - Detect that the terminal program has resized the window/buffer and enter a + simple just-scrape-and-dont-resize mode. Track the client window size and + send the intersection of the console and the agent's client. + - I also need to generate keyboard scan codes. + - Solve the NTVDM.EXE console shutdown problem, probably by ignoring NTVDM.EXE + when it appears on the GetConsoleProcessList list. + +Rename the agent? Is the term "proxy" more accurate? + +Optimize the polling. e.g. Use a longer poll interval when the console is idle. +Do a minimal poll that checks whether the sync marker or window has moved. + +Increase the console buffer size to ~9000 lines. Beware making it so big that +reading the sync column exhausts the 32KB conhost<->agent heap. + +Reduce the memory overhead of the agent. The agent's m_bufferData array can +be small (a few hundred lines?) relative to the console buffer size. + +Try to handle console background color better. + Unix terminal emulators have a user-configurable foreground and background +color, and for best results, the agent really needs to avoid changing the colors, +especially the background color. It's undesirable/ugly to SSH into a machine +and see the command prompt change the colors. It's especially ugly that the +terminal retains its original colors and only drawn cells get the new colors. +(e.g. Resizing the window to the right uses the local terminal colors rather +than the remote colors.) It's especially ugly in gnome-terminal, which draws +user-configurable black as black, but VT100 black as dark-gray. + If there were a way to query the terminal emulator's colors, then I could +match the console's colors to the terminal and everything would just work. As +far as I know, that's not possible. + I thought of a kludge that might work. Instead of translating console white +and black to VT/100 white and black, I would translate them to "reset" and +"invert". I'd translate other colors normally. This approach should produce +ideal results for command-line work and tolerable results for full-screen +programs without configuration. Configuring the agent for black-on-white or +white-on-black would produce ideal results in all situations. + This kludge only really applies to the SSH application. For a Win32 Konsole +application, it should be easy to get the colors right all the time. + +Try using the screen reader API: + - To eliminate polling. + - To detect when a line wraps. When a line wraps, it'd be nice not to send a + CRLF to the terminal emulator so copy-and-paste works better. + - To detect hard tabs with Cygwin. + +Implement VT100/ANSI escape sequence recognition for input. Decide where this +functionality belongs. PseudoConsole.dll? Disambiguating ESC from an escape +sequence might be tricky. For the SSH server, I was thinking that when a small +SSH payload ended with an ESC character, I could assume the character was really +an ESC keypress, on the assumption that if it were an escape sequence, the +payload would probably contain the whole sequence. I'm not sure this works, +especially if there's a lot of other traffic multiplexed on the SSH socket. + +Support Unicode. + - Some DOS programs draw using line/box characters. Can these characters be + translated to the Unicode equivalents? + +Create automated tests. + +Experiment with the Terminator emulator, an emulator that doesn't wrap lines. +How many columns does it report having? What column does it report the cursor +in as it's writing past the right end of the window? Will Terminator be a +problem if I implement line wrapping detection in the agent? + +BUG: After the unix-adapter/pconsole.exe program exits, the blinking cursor is +replaced with a hidden cursor. + +Fix assert() in the agent. If it fails, the failure message needs to be +reported somewhere. Pop up a dialog box? Maybe switch the active desktop, +then show a dialog box? + +TODO: There's already a pconsole project on GitHub. Maybe rename this project +to something else? winpty? + +TODO: Can the DebugServer system be replaced with OutputDebugString? How +do we decide whose processes' output to collect? + +TODO: Three executables: + build/winpty-agent.exe + build/winpty.dll + build/console.exe + +BUG: Run the pconsole.exe inside another console. As I type dir, I see this: + D:\rprichard\pconsole> + D:\rprichard\pconsole>d + D:\rprichard\pconsole>di + D:\rprichard\pconsole>dir + In the output of "dir", every other line is blank. + There was a bug in Terminal::sendLine that was causing this to happen + frequently. Now that I fixed it, this bug should only manifest on lines + whose last column is not a space (i.e. a full line). diff --git a/src/libs/3rdparty/winpty/misc/OSVersion.cc b/src/libs/3rdparty/winpty/misc/OSVersion.cc new file mode 100644 index 00000000000..456708f05b1 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/OSVersion.cc @@ -0,0 +1,27 @@ +#include + +#include +#include +#include + +#include + +int main() { + setlocale(LC_ALL, ""); + + OSVERSIONINFOEXW info = {0}; + info.dwOSVersionInfoSize = sizeof(info); + assert(GetVersionExW((OSVERSIONINFOW*)&info)); + + printf("dwMajorVersion = %d\n", (int)info.dwMajorVersion); + printf("dwMinorVersion = %d\n", (int)info.dwMinorVersion); + printf("dwBuildNumber = %d\n", (int)info.dwBuildNumber); + printf("dwPlatformId = %d\n", (int)info.dwPlatformId); + printf("szCSDVersion = %ls\n", info.szCSDVersion); + printf("wServicePackMajor = %d\n", info.wServicePackMajor); + printf("wServicePackMinor = %d\n", info.wServicePackMinor); + printf("wSuiteMask = 0x%x\n", (unsigned int)info.wSuiteMask); + printf("wProductType = 0x%x\n", (unsigned int)info.wProductType); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc b/src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc new file mode 100644 index 00000000000..656d4f126df --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ScreenBufferFreezeInactive.cc @@ -0,0 +1,101 @@ +// +// Verify that console selection blocks writes to an inactive console screen +// buffer. Writes TEST PASSED or TEST FAILED to the popup console window. +// + +#include +#include + +#include + +#include "TestUtil.cc" + +const int SC_CONSOLE_MARK = 0xFFF2; +const int SC_CONSOLE_SELECT_ALL = 0xFFF5; + +bool g_useMark = false; + +CALLBACK DWORD pausingThread(LPVOID dummy) +{ + HWND hwnd = GetConsoleWindow(); + trace("Sending selection to freeze"); + SendMessage(hwnd, WM_SYSCOMMAND, + g_useMark ? SC_CONSOLE_MARK : + SC_CONSOLE_SELECT_ALL, + 0); + Sleep(1000); + trace("Sending escape WM_CHAR to unfreeze"); + SendMessage(hwnd, WM_CHAR, 27, 0x00010001); + Sleep(1000); +} + +static HANDLE createBuffer() { + HANDLE buf = CreateConsoleScreenBuffer( + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CONSOLE_TEXTMODE_BUFFER, + NULL); + ASSERT(buf != INVALID_HANDLE_VALUE); + return buf; +} + +static void runTest(bool useMark, bool createEarly) { + trace("======================================="); + trace("useMark=%d createEarly=%d", useMark, createEarly); + g_useMark = useMark; + HANDLE buf = INVALID_HANDLE_VALUE; + + if (createEarly) { + buf = createBuffer(); + } + + CreateThread(NULL, 0, + pausingThread, NULL, + 0, NULL); + Sleep(500); + + if (!createEarly) { + trace("Creating buffer"); + TimeMeasurement tm1; + buf = createBuffer(); + const double elapsed1 = tm1.elapsed(); + if (elapsed1 >= 0.250) { + printf("!!! TEST FAILED !!!\n"); + Sleep(2000); + return; + } + } + + trace("Writing to aux buffer"); + TimeMeasurement tm2; + DWORD actual = 0; + BOOL ret = WriteConsoleW(buf, L"HI", 2, &actual, NULL); + const double elapsed2 = tm2.elapsed(); + trace("Writing to aux buffer: finished: ret=%d actual=%d (elapsed=%1.3f)", ret, actual, elapsed2); + if (elapsed2 < 0.250) { + printf("!!! TEST FAILED !!!\n"); + } else { + printf("TEST PASSED\n"); + } + Sleep(2000); +} + +int main(int argc, char **argv) { + if (argc == 1) { + startChildProcess(L"child"); + return 0; + } + + std::string arg = argv[1]; + if (arg == "child") { + for (int useMark = 0; useMark <= 1; useMark++) { + for (int createEarly = 0; createEarly <= 1; createEarly++) { + runTest(useMark, createEarly); + } + } + printf("done...\n"); + Sleep(1000); + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc b/src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc new file mode 100644 index 00000000000..fa584b9fae9 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ScreenBufferTest.cc @@ -0,0 +1,671 @@ +// +// Windows versions tested +// +// Vista Enterprise SP2 32-bit +// - ver reports [Version 6.0.6002] +// - kernel32.dll product/file versions are 6.0.6002.19381 +// +// Windows 7 Ultimate SP1 32-bit +// - ver reports [Version 6.1.7601] +// - conhost.exe product/file versions are 6.1.7601.18847 +// - kernel32.dll product/file versions are 6.1.7601.18847 +// +// Windows Server 2008 R2 Datacenter SP1 64-bit +// - ver reports [Version 6.1.7601] +// - conhost.exe product/file versions are 6.1.7601.23153 +// - kernel32.dll product/file versions are 6.1.7601.23153 +// +// Windows 8 Enterprise 32-bit +// - ver reports [Version 6.2.9200] +// - conhost.exe product/file versions are 6.2.9200.16578 +// - kernel32.dll product/file versions are 6.2.9200.16859 +// + +// +// Specific version details on working Server 2008 R2: +// +// dwMajorVersion = 6 +// dwMinorVersion = 1 +// dwBuildNumber = 7601 +// dwPlatformId = 2 +// szCSDVersion = Service Pack 1 +// wServicePackMajor = 1 +// wServicePackMinor = 0 +// wSuiteMask = 0x190 +// wProductType = 0x3 +// +// Specific version details on broken Win7: +// +// dwMajorVersion = 6 +// dwMinorVersion = 1 +// dwBuildNumber = 7601 +// dwPlatformId = 2 +// szCSDVersion = Service Pack 1 +// wServicePackMajor = 1 +// wServicePackMinor = 0 +// wSuiteMask = 0x100 +// wProductType = 0x1 +// + +#include +#include +#include + +#include "TestUtil.cc" + +const char *g_prefix = ""; + +static void dumpHandles() { + trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x", + g_prefix, + (long long)GetStdHandle(STD_INPUT_HANDLE), + (long long)GetStdHandle(STD_OUTPUT_HANDLE), + (long long)GetStdHandle(STD_ERROR_HANDLE)); +} + +static const char *successOrFail(BOOL ret) { + return ret ? "ok" : "FAILED"; +} + +static void startChildInSameConsole(const wchar_t *args, BOOL + bInheritHandles=FALSE) { + wchar_t program[1024]; + wchar_t cmdline[1024]; + GetModuleFileNameW(NULL, program, 1024); + swprintf(cmdline, L"\"%ls\" %ls", program, args); + + STARTUPINFOW sui; + PROCESS_INFORMATION pi; + memset(&sui, 0, sizeof(sui)); + memset(&pi, 0, sizeof(pi)); + sui.cb = sizeof(sui); + + CreateProcessW(program, cmdline, + NULL, NULL, + /*bInheritHandles=*/bInheritHandles, + /*dwCreationFlags=*/0, + NULL, NULL, + &sui, &pi); +} + +static void closeHandle(HANDLE h) { + trace("%sClosing handle 0x%I64x...", g_prefix, (long long)h); + trace("%sClosing handle 0x%I64x... %s", g_prefix, (long long)h, successOrFail(CloseHandle(h))); +} + +static HANDLE createBuffer() { + + // If sa isn't provided, the handle defaults to not-inheritable. + SECURITY_ATTRIBUTES sa = {0}; + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + trace("%sCreating a new buffer...", g_prefix); + HANDLE conout = CreateConsoleScreenBuffer( + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + CONSOLE_TEXTMODE_BUFFER, NULL); + + trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout); + return conout; +} + +static HANDLE openConout() { + + // If sa isn't provided, the handle defaults to not-inheritable. + SECURITY_ATTRIBUTES sa = {0}; + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + trace("%sOpening CONOUT...", g_prefix); + HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + OPEN_EXISTING, 0, NULL); + trace("%sOpening CONOUT... 0x%I64x", g_prefix, (long long)conout); + return conout; +} + +static void setConsoleActiveScreenBuffer(HANDLE conout) { + trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...", + g_prefix, (long long)conout); + trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s", + g_prefix, (long long)conout, + successOrFail(SetConsoleActiveScreenBuffer(conout))); +} + +static void writeTest(HANDLE conout, const char *msg) { + char writeData[256]; + sprintf(writeData, "%s%s\n", g_prefix, msg); + + trace("%sWriting to 0x%I64x: '%s'...", + g_prefix, (long long)conout, msg); + DWORD actual = 0; + BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL); + trace("%sWriting to 0x%I64x: '%s'... %s", + g_prefix, (long long)conout, msg, + successOrFail(ret && actual == strlen(writeData))); +} + +static void writeTest(const char *msg) { + writeTest(GetStdHandle(STD_OUTPUT_HANDLE), msg); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// TEST 1 -- create new buffer, activate it, and close the handle. The console +// automatically switches the screen buffer back to the original. +// +// This test passes everywhere. +// + +static void test1(int argc, char *argv[]) { + if (!strcmp(argv[1], "1")) { + startChildProcess(L"1:child"); + return; + } + + HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); + writeTest(origBuffer, "<-- origBuffer -->"); + + HANDLE newBuffer = createBuffer(); + writeTest(newBuffer, "<-- newBuffer -->"); + setConsoleActiveScreenBuffer(newBuffer); + Sleep(2000); + + writeTest(origBuffer, "TEST PASSED!"); + + // Closing the handle w/o switching the active screen buffer automatically + // switches the console back to the original buffer. + closeHandle(newBuffer); + + while (true) { + Sleep(1000); + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// TEST 2 -- Test program that creates and activates newBuffer, starts a child +// process, then closes its newBuffer handle. newBuffer remains activated, +// because the child keeps it active. (Also see TEST D.) +// + +static void test2(int argc, char *argv[]) { + if (!strcmp(argv[1], "2")) { + startChildProcess(L"2:parent"); + return; + } + + if (!strcmp(argv[1], "2:parent")) { + g_prefix = "parent: "; + dumpHandles(); + HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); + writeTest(origBuffer, "<-- origBuffer -->"); + + HANDLE newBuffer = createBuffer(); + writeTest(newBuffer, "<-- newBuffer -->"); + setConsoleActiveScreenBuffer(newBuffer); + + Sleep(1000); + writeTest(newBuffer, "bInheritHandles=FALSE:"); + startChildInSameConsole(L"2:child", FALSE); + Sleep(1000); + writeTest(newBuffer, "bInheritHandles=TRUE:"); + startChildInSameConsole(L"2:child", TRUE); + + Sleep(1000); + trace("parent:----"); + + // Close the new buffer. The active screen buffer doesn't automatically + // switch back to origBuffer, because the child process has a handle open + // to the original buffer. + closeHandle(newBuffer); + + Sleep(600 * 1000); + return; + } + + if (!strcmp(argv[1], "2:child")) { + g_prefix = "child: "; + dumpHandles(); + // The child's output isn't visible, because it's still writing to + // origBuffer. + trace("child:----"); + writeTest("writing to STDOUT"); + + // Handle inheritability is curious. The console handles this program + // creates are inheritable, but CreateProcess is called with both + // bInheritHandles=TRUE and bInheritHandles=FALSE. + // + // Vista and Windows 7: bInheritHandles has no effect. The child and + // parent processes have the same STDIN/STDOUT/STDERR handles: + // 0x3, 0x7, and 0xB. The parent has a 0xF handle for newBuffer. + // The child can only write to 0x7, 0xB, and 0xF. Only the writes to + // 0xF are visible (i.e. they touch newBuffer). + // + // Windows 8 or Windows 10 (legacy or non-legacy): the lowest 2 bits of + // the HANDLE to WriteConsole seem to be ignored. The new process' + // console handles always refer to the buffer that was active when they + // started, but the values of the handles depend upon bInheritHandles. + // With bInheritHandles=TRUE, the child has the same + // STDIN/STDOUT/STDERR/newBuffer handles as the parent, and the three + // output handles all work, though their output is all visible. With + // bInheritHandles=FALSE, the child has different STDIN/STDOUT/STDERR + // handles, and only the new STDOUT/STDERR handles work. + // + for (unsigned int i = 0x1; i <= 0xB0; ++i) { + char msg[256]; + sprintf(msg, "Write to handle 0x%x", i); + HANDLE h = reinterpret_cast(i); + writeTest(h, msg); + } + + Sleep(600 * 1000); + return; + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// TEST A -- demonstrate an apparent Windows bug with screen buffers +// +// Steps: +// - The parent starts a child process. +// - The child process creates and activates newBuffer +// - The parent opens CONOUT$ and writes to it. +// - The parent closes CONOUT$. +// - At this point, broken Windows reactivates origBuffer. +// - The child writes to newBuffer again. +// - The child activates origBuffer again, then closes newBuffer. +// +// Test passes if the message "TEST PASSED!" is visible. +// Test commonly fails if conhost.exe crashes. +// +// Results: +// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes +// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS +// - Windows 8 Enterprise 32-bit: PASS +// - Windows 10 64-bit (legacy and non-legacy): PASS +// + +static void testA_parentWork() { + // Open an extra CONOUT$ handle so that the HANDLE values in parent and + // child don't collide. I think it's OK if they collide, but since we're + // trying to track down a Windows bug, it's best to avoid unnecessary + // complication. + HANDLE dummy = openConout(); + + Sleep(3000); + + // Step 2: Open CONOUT$ in the parent. This opens the active buffer, which + // was just created in the child. It's handle 0x13. Write to it. + + HANDLE newBuffer = openConout(); + writeTest(newBuffer, "step2: writing to newBuffer"); + + Sleep(3000); + + // Step 3: Close handle 0x13. With Windows 7, the console switches back to + // origBuffer, and (unless I'm missing something) it shouldn't. + + closeHandle(newBuffer); +} + +static void testA_childWork() { + HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); + + // + // Step 1: Create the new screen buffer in the child process and make it + // active. (Typically, it's handle 0x0F.) + // + + HANDLE newBuffer = createBuffer(); + + setConsoleActiveScreenBuffer(newBuffer); + writeTest(newBuffer, "<-- newBuffer -->"); + + Sleep(9000); + trace("child:----"); + + // Step 4: write to the newBuffer again. + writeTest(newBuffer, "TEST PASSED!"); + + // + // Step 5: Switch back to the original screen buffer and close the new + // buffer. The switch call succeeds, but the CloseHandle call freezes for + // several seconds, because conhost.exe crashes. + // + Sleep(3000); + + setConsoleActiveScreenBuffer(origBuffer); + writeTest(origBuffer, "writing to origBuffer"); + + closeHandle(newBuffer); + + // The console HWND is NULL. + trace("child: console HWND=0x%I64x", (long long)GetConsoleWindow()); + + // At this point, the console window has closed, but the parent/child + // processes are still running. Calling AllocConsole would fail, but + // calling FreeConsole followed by AllocConsole would both succeed, and a + // new console would appear. +} + +static void testA(int argc, char *argv[]) { + + if (!strcmp(argv[1], "A")) { + startChildProcess(L"A:parent"); + return; + } + + if (!strcmp(argv[1], "A:parent")) { + g_prefix = "parent: "; + trace("parent:----"); + dumpHandles(); + writeTest("<-- origBuffer -->"); + startChildInSameConsole(L"A:child"); + testA_parentWork(); + Sleep(120000); + return; + } + + if (!strcmp(argv[1], "A:child")) { + g_prefix = "child: "; + dumpHandles(); + testA_childWork(); + Sleep(120000); + return; + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// TEST B -- invert TEST A -- also crashes conhost on Windows 7 +// +// Test passes if the message "TEST PASSED!" is visible. +// Test commonly fails if conhost.exe crashes. +// +// Results: +// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes +// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS +// - Windows 8 Enterprise 32-bit: PASS +// - Windows 10 64-bit (legacy and non-legacy): PASS +// + +static void testB(int argc, char *argv[]) { + if (!strcmp(argv[1], "B")) { + startChildProcess(L"B:parent"); + return; + } + + if (!strcmp(argv[1], "B:parent")) { + g_prefix = "parent: "; + startChildInSameConsole(L"B:child"); + writeTest("<-- origBuffer -->"); + HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); + + // + // Step 1: Create the new buffer and make it active. + // + trace("%s----", g_prefix); + HANDLE newBuffer = createBuffer(); + setConsoleActiveScreenBuffer(newBuffer); + writeTest(newBuffer, "<-- newBuffer -->"); + + // + // Step 4: Attempt to write again to the new buffer. + // + Sleep(9000); + trace("%s----", g_prefix); + writeTest(newBuffer, "TEST PASSED!"); + + // + // Step 5: Switch back to the original buffer. + // + Sleep(3000); + trace("%s----", g_prefix); + setConsoleActiveScreenBuffer(origBuffer); + closeHandle(newBuffer); + writeTest(origBuffer, "writing to the initial buffer"); + + Sleep(60000); + return; + } + + if (!strcmp(argv[1], "B:child")) { + g_prefix = "child: "; + Sleep(3000); + trace("%s----", g_prefix); + + // + // Step 2: Open the newly active buffer and write to it. + // + HANDLE newBuffer = openConout(); + writeTest(newBuffer, "writing to newBuffer"); + + // + // Step 3: Close the newly active buffer. + // + Sleep(3000); + closeHandle(newBuffer); + + Sleep(60000); + return; + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// TEST C -- Interleaving open/close of console handles also seems to break on +// Windows 7. +// +// Test: +// - child creates and activates newBuf1 +// - parent opens newBuf1 +// - child creates and activates newBuf2 +// - parent opens newBuf2, then closes newBuf1 +// - child switches back to newBuf1 +// * At this point, the console starts malfunctioning. +// - parent and child close newBuf2 +// - child closes newBuf1 +// +// Test passes if the message "TEST PASSED!" is visible. +// Test commonly fails if conhost.exe crashes. +// +// Results: +// - Windows 7 Ultimate SP1 32-bit: conhost.exe crashes +// - Windows Server 2008 R2 Datacenter SP1 64-bit: PASS +// - Windows 8 Enterprise 32-bit: PASS +// - Windows 10 64-bit (legacy and non-legacy): PASS +// + +static void testC(int argc, char *argv[]) { + if (!strcmp(argv[1], "C")) { + startChildProcess(L"C:parent"); + return; + } + + if (!strcmp(argv[1], "C:parent")) { + startChildInSameConsole(L"C:child"); + writeTest("<-- origBuffer -->"); + g_prefix = "parent: "; + + // At time=4, open newBuffer1. + Sleep(4000); + trace("%s---- t=4", g_prefix); + const HANDLE newBuffer1 = openConout(); + + // At time=8, open newBuffer2, and close newBuffer1. + Sleep(4000); + trace("%s---- t=8", g_prefix); + const HANDLE newBuffer2 = openConout(); + closeHandle(newBuffer1); + + // At time=25, cleanup of newBuffer2. + Sleep(17000); + trace("%s---- t=25", g_prefix); + closeHandle(newBuffer2); + + Sleep(240000); + return; + } + + if (!strcmp(argv[1], "C:child")) { + g_prefix = "child: "; + + // At time=2, create newBuffer1 and activate it. + Sleep(2000); + trace("%s---- t=2", g_prefix); + const HANDLE newBuffer1 = createBuffer(); + setConsoleActiveScreenBuffer(newBuffer1); + writeTest(newBuffer1, "<-- newBuffer1 -->"); + + // At time=6, create newBuffer2 and activate it. + Sleep(4000); + trace("%s---- t=6", g_prefix); + const HANDLE newBuffer2 = createBuffer(); + setConsoleActiveScreenBuffer(newBuffer2); + writeTest(newBuffer2, "<-- newBuffer2 -->"); + + // At time=10, attempt to switch back to newBuffer1. The parent process + // has opened and closed its handle to newBuffer1, so does it still exist? + Sleep(4000); + trace("%s---- t=10", g_prefix); + setConsoleActiveScreenBuffer(newBuffer1); + writeTest(newBuffer1, "write to newBuffer1: TEST PASSED!"); + + // At time=25, cleanup of newBuffer2. + Sleep(15000); + trace("%s---- t=25", g_prefix); + closeHandle(newBuffer2); + + // At time=35, cleanup of newBuffer1. The console should switch to the + // initial buffer again. + Sleep(10000); + trace("%s---- t=35", g_prefix); + closeHandle(newBuffer1); + + Sleep(240000); + return; + } +} + + + +/////////////////////////////////////////////////////////////////////////////// +// TEST D -- parent creates a new buffer, child launches, writes, +// closes it output handle, then parent writes again. (Also see TEST 2.) +// +// On success, this will appear: +// +// parent: <-- newBuffer --> +// child: writing to newBuffer +// parent: TEST PASSED! +// +// If this appears, it indicates that the child's closing its output handle did +// not destroy newBuffer. +// +// Results: +// - Windows 7 Ultimate SP1 32-bit: PASS +// - Windows 8 Enterprise 32-bit: PASS +// - Windows 10 64-bit (legacy and non-legacy): PASS +// + +static void testD(int argc, char *argv[]) { + if (!strcmp(argv[1], "D")) { + startChildProcess(L"D:parent"); + return; + } + + if (!strcmp(argv[1], "D:parent")) { + g_prefix = "parent: "; + HANDLE origBuffer = GetStdHandle(STD_OUTPUT_HANDLE); + writeTest(origBuffer, "<-- origBuffer -->"); + + HANDLE newBuffer = createBuffer(); + writeTest(newBuffer, "<-- newBuffer -->"); + setConsoleActiveScreenBuffer(newBuffer); + + // At t=2, start a child process, explicitly forcing it to use + // newBuffer for its standard handles. These calls are apparently + // redundant on Windows 8 and up. + Sleep(2000); + trace("parent:----"); + trace("parent: starting child process"); + SetStdHandle(STD_OUTPUT_HANDLE, newBuffer); + SetStdHandle(STD_ERROR_HANDLE, newBuffer); + startChildInSameConsole(L"D:child"); + SetStdHandle(STD_OUTPUT_HANDLE, origBuffer); + SetStdHandle(STD_ERROR_HANDLE, origBuffer); + + // At t=6, write again to newBuffer. + Sleep(4000); + trace("parent:----"); + writeTest(newBuffer, "TEST PASSED!"); + + // At t=8, close the newBuffer. In earlier versions of windows + // (including Server 2008 R2), the console then switches back to + // origBuffer. As of Windows 8, it doesn't, because somehow the child + // process is keeping the console on newBuffer, even though the child + // process closed its STDIN/STDOUT/STDERR handles. Killing the child + // process by hand after the test finishes *does* force the console + // back to origBuffer. + Sleep(2000); + closeHandle(newBuffer); + + Sleep(120000); + return; + } + + if (!strcmp(argv[1], "D:child")) { + g_prefix = "child: "; + // At t=2, the child starts. + trace("child:----"); + dumpHandles(); + writeTest("writing to newBuffer"); + + // At t=4, the child explicitly closes its handle. + Sleep(2000); + trace("child:----"); + if (GetStdHandle(STD_ERROR_HANDLE) != GetStdHandle(STD_OUTPUT_HANDLE)) { + closeHandle(GetStdHandle(STD_ERROR_HANDLE)); + } + closeHandle(GetStdHandle(STD_OUTPUT_HANDLE)); + closeHandle(GetStdHandle(STD_INPUT_HANDLE)); + + Sleep(120000); + return; + } +} + + + +int main(int argc, char *argv[]) { + if (argc == 1) { + printf("USAGE: %s testnum\n", argv[0]); + return 0; + } + + if (argv[1][0] == '1') { + test1(argc, argv); + } else if (argv[1][0] == '2') { + test2(argc, argv); + } else if (argv[1][0] == 'A') { + testA(argc, argv); + } else if (argv[1][0] == 'B') { + testB(argc, argv); + } else if (argv[1][0] == 'C') { + testC(argc, argv); + } else if (argv[1][0] == 'D') { + testD(argc, argv); + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc b/src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc new file mode 100644 index 00000000000..2b648c94093 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ScreenBufferTest2.cc @@ -0,0 +1,151 @@ +#include + +#include "TestUtil.cc" + +const char *g_prefix = ""; + +static void dumpHandles() { + trace("%sSTDIN=0x%I64x STDOUT=0x%I64x STDERR=0x%I64x", + g_prefix, + (long long)GetStdHandle(STD_INPUT_HANDLE), + (long long)GetStdHandle(STD_OUTPUT_HANDLE), + (long long)GetStdHandle(STD_ERROR_HANDLE)); +} + +static HANDLE createBuffer() { + + // If sa isn't provided, the handle defaults to not-inheritable. + SECURITY_ATTRIBUTES sa = {0}; + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + trace("%sCreating a new buffer...", g_prefix); + HANDLE conout = CreateConsoleScreenBuffer( + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + CONSOLE_TEXTMODE_BUFFER, NULL); + + trace("%sCreating a new buffer... 0x%I64x", g_prefix, (long long)conout); + return conout; +} + +static const char *successOrFail(BOOL ret) { + return ret ? "ok" : "FAILED"; +} + +static void setConsoleActiveScreenBuffer(HANDLE conout) { + trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called...", + g_prefix, (long long)conout); + trace("%sSetConsoleActiveScreenBuffer(0x%I64x) called... %s", + g_prefix, (long long)conout, + successOrFail(SetConsoleActiveScreenBuffer(conout))); +} + +static void writeTest(HANDLE conout, const char *msg) { + char writeData[256]; + sprintf(writeData, "%s%s\n", g_prefix, msg); + + trace("%sWriting to 0x%I64x: '%s'...", + g_prefix, (long long)conout, msg); + DWORD actual = 0; + BOOL ret = WriteConsoleA(conout, writeData, strlen(writeData), &actual, NULL); + trace("%sWriting to 0x%I64x: '%s'... %s", + g_prefix, (long long)conout, msg, + successOrFail(ret && actual == strlen(writeData))); +} + +static HANDLE startChildInSameConsole(const wchar_t *args, BOOL + bInheritHandles=FALSE) { + wchar_t program[1024]; + wchar_t cmdline[1024]; + GetModuleFileNameW(NULL, program, 1024); + swprintf(cmdline, L"\"%ls\" %ls", program, args); + + STARTUPINFOW sui; + PROCESS_INFORMATION pi; + memset(&sui, 0, sizeof(sui)); + memset(&pi, 0, sizeof(pi)); + sui.cb = sizeof(sui); + + CreateProcessW(program, cmdline, + NULL, NULL, + /*bInheritHandles=*/bInheritHandles, + /*dwCreationFlags=*/0, + NULL, NULL, + &sui, &pi); + + return pi.hProcess; +} + +static HANDLE dup(HANDLE h, HANDLE targetProcess) { + HANDLE h2 = INVALID_HANDLE_VALUE; + BOOL ret = DuplicateHandle( + GetCurrentProcess(), h, + targetProcess, &h2, + 0, TRUE, DUPLICATE_SAME_ACCESS); + trace("dup(0x%I64x) to process 0x%I64x... %s, 0x%I64x", + (long long)h, + (long long)targetProcess, + successOrFail(ret), + (long long)h2); + return h2; +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"parent"); + return 0; + } + + if (!strcmp(argv[1], "parent")) { + g_prefix = "parent: "; + dumpHandles(); + HANDLE hChild = startChildInSameConsole(L"child"); + + // Windows 10. + HANDLE orig1 = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE new1 = createBuffer(); + + Sleep(2000); + setConsoleActiveScreenBuffer(new1); + + // Handle duplication results to child process in same console: + // - Windows XP: fails + // - Windows 7 Ultimate SP1 32-bit: fails + // - Windows Server 2008 R2 Datacenter SP1 64-bit: fails + // - Windows 8 Enterprise 32-bit: succeeds + // - Windows 10: succeeds + HANDLE orig2 = dup(orig1, GetCurrentProcess()); + HANDLE new2 = dup(new1, GetCurrentProcess()); + + dup(orig1, hChild); + dup(new1, hChild); + + // The writes to orig1/orig2 are invisible. The writes to new1/new2 + // are visible. + writeTest(orig1, "write to orig1"); + writeTest(orig2, "write to orig2"); + writeTest(new1, "write to new1"); + writeTest(new2, "write to new2"); + + Sleep(120000); + return 0; + } + + if (!strcmp(argv[1], "child")) { + g_prefix = "child: "; + dumpHandles(); + Sleep(4000); + for (unsigned int i = 0x1; i <= 0xB0; ++i) { + char msg[256]; + sprintf(msg, "Write to handle 0x%x", i); + HANDLE h = reinterpret_cast(i); + writeTest(h, msg); + } + Sleep(120000); + return 0; + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/SelectAllTest.cc b/src/libs/3rdparty/winpty/misc/SelectAllTest.cc new file mode 100644 index 00000000000..a6c27739d80 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/SelectAllTest.cc @@ -0,0 +1,45 @@ +#define _WIN32_WINNT 0x0501 +#include +#include + +#include "../src/shared/DebugClient.cc" + +const int SC_CONSOLE_MARK = 0xFFF2; +const int SC_CONSOLE_SELECT_ALL = 0xFFF5; + +CALLBACK DWORD pausingThread(LPVOID dummy) +{ + HWND hwnd = GetConsoleWindow(); + while (true) { + SendMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0); + Sleep(1000); + SendMessage(hwnd, WM_CHAR, 27, 0x00010001); + Sleep(1000); + } +} + +int main() +{ + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO info; + + GetConsoleScreenBufferInfo(out, &info); + COORD initial = info.dwCursorPosition; + + CreateThread(NULL, 0, + pausingThread, NULL, + 0, NULL); + + for (int i = 0; i < 30; ++i) { + Sleep(100); + GetConsoleScreenBufferInfo(out, &info); + if (memcmp(&info.dwCursorPosition, &initial, sizeof(COORD)) != 0) { + trace("cursor moved to [%d,%d]", + info.dwCursorPosition.X, + info.dwCursorPosition.Y); + } else { + trace("cursor in expected position"); + } + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/SetBufInfo.cc b/src/libs/3rdparty/winpty/misc/SetBufInfo.cc new file mode 100644 index 00000000000..f37c31bdf72 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/SetBufInfo.cc @@ -0,0 +1,90 @@ +#include + +#include +#include +#include + +#include "TestUtil.cc" + +static void usage() { + printf("usage: SetBufInfo [-set] [-buf W H] [-win W H] [-pos X Y]\n"); +} + +int main(int argc, char *argv[]) { + const HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + ASSERT(conout != INVALID_HANDLE_VALUE); + + bool change = false; + BOOL success; + CONSOLE_SCREEN_BUFFER_INFOEX info = {}; + info.cbSize = sizeof(info); + + success = GetConsoleScreenBufferInfoEx(conout, &info); + ASSERT(success && "GetConsoleScreenBufferInfoEx failed"); + + for (int i = 1; i < argc; ) { + std::string arg = argv[i]; + if (arg == "-buf" && (i + 2) < argc) { + info.dwSize.X = atoi(argv[i + 1]); + info.dwSize.Y = atoi(argv[i + 2]); + i += 3; + change = true; + } else if (arg == "-pos" && (i + 2) < argc) { + int dx = info.srWindow.Right - info.srWindow.Left; + int dy = info.srWindow.Bottom - info.srWindow.Top; + info.srWindow.Left = atoi(argv[i + 1]); + info.srWindow.Top = atoi(argv[i + 2]); + i += 3; + info.srWindow.Right = info.srWindow.Left + dx; + info.srWindow.Bottom = info.srWindow.Top + dy; + change = true; + } else if (arg == "-win" && (i + 2) < argc) { + info.srWindow.Right = info.srWindow.Left + atoi(argv[i + 1]) - 1; + info.srWindow.Bottom = info.srWindow.Top + atoi(argv[i + 2]) - 1; + i += 3; + change = true; + } else if (arg == "-set") { + change = true; + ++i; + } else if (arg == "--help" || arg == "-help") { + usage(); + exit(0); + } else { + fprintf(stderr, "error: unrecognized argument: %s\n", arg.c_str()); + usage(); + exit(1); + } + } + + if (change) { + success = SetConsoleScreenBufferInfoEx(conout, &info); + if (success) { + printf("success\n"); + } else { + printf("SetConsoleScreenBufferInfoEx call failed\n"); + } + success = GetConsoleScreenBufferInfoEx(conout, &info); + ASSERT(success && "GetConsoleScreenBufferInfoEx failed"); + } + + auto dump = [](const char *fmt, ...) { + char msg[256]; + va_list ap; + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + va_end(ap); + trace("%s", msg); + printf("%s\n", msg); + }; + + dump("buffer-size: %d x %d", info.dwSize.X, info.dwSize.Y); + dump("window-size: %d x %d", + info.srWindow.Right - info.srWindow.Left + 1, + info.srWindow.Bottom - info.srWindow.Top + 1); + dump("window-pos: %d, %d", info.srWindow.Left, info.srWindow.Top); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/SetBufferSize.cc b/src/libs/3rdparty/winpty/misc/SetBufferSize.cc new file mode 100644 index 00000000000..b50a1f8dc36 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/SetBufferSize.cc @@ -0,0 +1,32 @@ +#include + +#include +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + if (argc != 3) { + printf("Usage: %s x y width height\n", argv[0]); + return 1; + } + + const HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + ASSERT(conout != INVALID_HANDLE_VALUE); + + COORD size = { + (short)atoi(argv[1]), + (short)atoi(argv[2]), + }; + + BOOL ret = SetConsoleScreenBufferSize(conout, size); + const unsigned lastError = GetLastError(); + const char *const retStr = ret ? "OK" : "failed"; + trace("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)", retStr, lastError); + printf("SetConsoleScreenBufferSize ret: %s (LastError=0x%x)\n", retStr, lastError); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/SetCursorPos.cc b/src/libs/3rdparty/winpty/misc/SetCursorPos.cc new file mode 100644 index 00000000000..d20fdbdfc0d --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/SetCursorPos.cc @@ -0,0 +1,10 @@ +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + int col = atoi(argv[1]); + int row = atoi(argv[2]); + setCursorPos(col, row); + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/SetFont.cc b/src/libs/3rdparty/winpty/misc/SetFont.cc new file mode 100644 index 00000000000..9bcd4b4cc97 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/SetFont.cc @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include + +#include "TestUtil.cc" + +#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0])) + +// See https://en.wikipedia.org/wiki/List_of_CJK_fonts +const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese +const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese +const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese +const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean + +int main() { + setlocale(LC_ALL, ""); + wchar_t *cmdline = GetCommandLineW(); + int argc = 0; + wchar_t **argv = CommandLineToArgvW(cmdline, &argc); + const HANDLE conout = openConout(); + + if (argc == 1) { + cprintf(L"Usage:\n"); + cprintf(L" SetFont \n"); + cprintf(L" SetFont options\n"); + cprintf(L"\n"); + cprintf(L"Options for SetCurrentConsoleFontEx:\n"); + cprintf(L" -idx INDEX\n"); + cprintf(L" -w WIDTH\n"); + cprintf(L" -h HEIGHT\n"); + cprintf(L" -family (0xNN|NN)\n"); + cprintf(L" -weight (normal|bold|NNN)\n"); + cprintf(L" -face FACENAME\n"); + cprintf(L" -face-{gothic|simsun|minglight|gulimche) [JP,CN-sim,CN-tra,KR]\n"); + cprintf(L" -tt\n"); + cprintf(L" -vec\n"); + cprintf(L" -vp\n"); + cprintf(L" -dev\n"); + cprintf(L" -roman\n"); + cprintf(L" -swiss\n"); + cprintf(L" -modern\n"); + cprintf(L" -script\n"); + cprintf(L" -decorative\n"); + return 0; + } + + if (isdigit(argv[1][0])) { + int index = _wtoi(argv[1]); + HMODULE kernel32 = LoadLibraryW(L"kernel32.dll"); + FARPROC proc = GetProcAddress(kernel32, "SetConsoleFont"); + if (proc == NULL) { + cprintf(L"Couldn't get address of SetConsoleFont\n"); + } else { + BOOL ret = reinterpret_cast(proc)( + conout, index); + cprintf(L"SetFont returned %d\n", ret); + } + return 0; + } + + CONSOLE_FONT_INFOEX fontex = {0}; + fontex.cbSize = sizeof(fontex); + + for (int i = 1; i < argc; ++i) { + std::wstring arg = argv[i]; + if (i + 1 < argc) { + std::wstring next = argv[i + 1]; + if (arg == L"-idx") { + fontex.nFont = _wtoi(next.c_str()); + ++i; continue; + } else if (arg == L"-w") { + fontex.dwFontSize.X = _wtoi(next.c_str()); + ++i; continue; + } else if (arg == L"-h") { + fontex.dwFontSize.Y = _wtoi(next.c_str()); + ++i; continue; + } else if (arg == L"-weight") { + if (next == L"normal") { + fontex.FontWeight = 400; + } else if (next == L"bold") { + fontex.FontWeight = 700; + } else { + fontex.FontWeight = _wtoi(next.c_str()); + } + ++i; continue; + } else if (arg == L"-face") { + wcsncpy(fontex.FaceName, next.c_str(), COUNT_OF(fontex.FaceName)); + ++i; continue; + } else if (arg == L"-family") { + fontex.FontFamily = strtol(narrowString(next).c_str(), nullptr, 0); + ++i; continue; + } + } + if (arg == L"-tt") { + fontex.FontFamily |= TMPF_TRUETYPE; + } else if (arg == L"-vec") { + fontex.FontFamily |= TMPF_VECTOR; + } else if (arg == L"-vp") { + // Setting the TMPF_FIXED_PITCH bit actually indicates variable + // pitch. + fontex.FontFamily |= TMPF_FIXED_PITCH; + } else if (arg == L"-dev") { + fontex.FontFamily |= TMPF_DEVICE; + } else if (arg == L"-roman") { + fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_ROMAN; + } else if (arg == L"-swiss") { + fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_SWISS; + } else if (arg == L"-modern") { + fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_MODERN; + } else if (arg == L"-script") { + fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_SCRIPT; + } else if (arg == L"-decorative") { + fontex.FontFamily = (fontex.FontFamily & ~0xF0) | FF_DECORATIVE; + } else if (arg == L"-face-gothic") { + wcsncpy(fontex.FaceName, kMSGothic, COUNT_OF(fontex.FaceName)); + } else if (arg == L"-face-simsun") { + wcsncpy(fontex.FaceName, kNSimSun, COUNT_OF(fontex.FaceName)); + } else if (arg == L"-face-minglight") { + wcsncpy(fontex.FaceName, kMingLight, COUNT_OF(fontex.FaceName)); + } else if (arg == L"-face-gulimche") { + wcsncpy(fontex.FaceName, kGulimChe, COUNT_OF(fontex.FaceName)); + } else { + cprintf(L"Unrecognized argument: %ls\n", arg.c_str()); + exit(1); + } + } + + cprintf(L"Setting to: nFont=%u dwFontSize=(%d,%d) " + L"FontFamily=0x%x FontWeight=%u " + L"FaceName=\"%ls\"\n", + static_cast(fontex.nFont), + fontex.dwFontSize.X, fontex.dwFontSize.Y, + fontex.FontFamily, fontex.FontWeight, + fontex.FaceName); + + BOOL ret = SetCurrentConsoleFontEx( + conout, + FALSE, + &fontex); + cprintf(L"SetCurrentConsoleFontEx returned %d\n", ret); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/SetWindowRect.cc b/src/libs/3rdparty/winpty/misc/SetWindowRect.cc new file mode 100644 index 00000000000..6291dd67459 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/SetWindowRect.cc @@ -0,0 +1,36 @@ +#include + +#include +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + if (argc != 5) { + printf("Usage: %s x y width height\n", argv[0]); + return 1; + } + + const HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + ASSERT(conout != INVALID_HANDLE_VALUE); + + SMALL_RECT sr = { + (short)atoi(argv[1]), + (short)atoi(argv[2]), + (short)(atoi(argv[1]) + atoi(argv[3]) - 1), + (short)(atoi(argv[2]) + atoi(argv[4]) - 1), + }; + + trace("Calling SetConsoleWindowInfo with {L=%d,T=%d,R=%d,B=%d}", + sr.Left, sr.Top, sr.Right, sr.Bottom); + BOOL ret = SetConsoleWindowInfo(conout, TRUE, &sr); + const unsigned lastError = GetLastError(); + const char *const retStr = ret ? "OK" : "failed"; + trace("SetConsoleWindowInfo ret: %s (LastError=0x%x)", retStr, lastError); + printf("SetConsoleWindowInfo ret: %s (LastError=0x%x)\n", retStr, lastError); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ShowArgv.cc b/src/libs/3rdparty/winpty/misc/ShowArgv.cc new file mode 100644 index 00000000000..29a0f091316 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ShowArgv.cc @@ -0,0 +1,12 @@ +// This test program is useful for studying commandline<->argv conversion. + +#include +#include + +int main(int argc, char **argv) +{ + printf("cmdline = [%s]\n", GetCommandLine()); + for (int i = 0; i < argc; ++i) + printf("[%s]\n", argv[i]); + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc b/src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc new file mode 100644 index 00000000000..75fbfb81f10 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/ShowConsoleInput.cc @@ -0,0 +1,40 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + static int escCount = 0; + + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + while (true) { + DWORD count; + INPUT_RECORD ir; + if (!ReadConsoleInput(hStdin, &ir, 1, &count)) { + printf("ReadConsoleInput failed\n"); + return 1; + } + + if (true) { + DWORD mode; + GetConsoleMode(hStdin, &mode); + SetConsoleMode(hStdin, mode & ~ENABLE_PROCESSED_INPUT); + } + + if (ir.EventType == KEY_EVENT) { + const KEY_EVENT_RECORD &ker = ir.Event.KeyEvent; + printf("%s", ker.bKeyDown ? "dn" : "up"); + printf(" ch="); + if (isprint(ker.uChar.AsciiChar)) + printf("'%c'", ker.uChar.AsciiChar); + printf("%d", ker.uChar.AsciiChar); + printf(" vk=%#x", ker.wVirtualKeyCode); + printf(" scan=%#x", ker.wVirtualScanCode); + printf(" state=%#x", (int)ker.dwControlKeyState); + printf(" repeat=%d", ker.wRepeatCount); + printf("\n"); + if (ker.uChar.AsciiChar == 27 && ++escCount == 6) + break; + } + } +} diff --git a/src/libs/3rdparty/winpty/misc/Spew.py b/src/libs/3rdparty/winpty/misc/Spew.py new file mode 100644 index 00000000000..9d1796af375 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Spew.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +i = 0; +while True: + i += 1 + print(i) diff --git a/src/libs/3rdparty/winpty/misc/TestUtil.cc b/src/libs/3rdparty/winpty/misc/TestUtil.cc new file mode 100644 index 00000000000..c832a12b858 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/TestUtil.cc @@ -0,0 +1,172 @@ +// This file is included into test programs using #include + +#include +#include +#include +#include +#include +#include +#include + +#include "../src/shared/DebugClient.h" +#include "../src/shared/TimeMeasurement.h" + +#include "../src/shared/DebugClient.cc" +#include "../src/shared/WinptyAssert.cc" +#include "../src/shared/WinptyException.cc" + +// Launch this test program again, in a new console that we will destroy. +static void startChildProcess(const wchar_t *args) { + wchar_t program[1024]; + wchar_t cmdline[1024]; + GetModuleFileNameW(NULL, program, 1024); + swprintf(cmdline, L"\"%ls\" %ls", program, args); + + STARTUPINFOW sui; + PROCESS_INFORMATION pi; + memset(&sui, 0, sizeof(sui)); + memset(&pi, 0, sizeof(pi)); + sui.cb = sizeof(sui); + + CreateProcessW(program, cmdline, + NULL, NULL, + /*bInheritHandles=*/FALSE, + /*dwCreationFlags=*/CREATE_NEW_CONSOLE, + NULL, NULL, + &sui, &pi); +} + +static void setBufferSize(HANDLE conout, int x, int y) { + COORD size = { static_cast(x), static_cast(y) }; + BOOL success = SetConsoleScreenBufferSize(conout, size); + trace("setBufferSize: (%d,%d), result=%d", x, y, success); +} + +static void setWindowPos(HANDLE conout, int x, int y, int w, int h) { + SMALL_RECT r = { + static_cast(x), static_cast(y), + static_cast(x + w - 1), + static_cast(y + h - 1) + }; + BOOL success = SetConsoleWindowInfo(conout, /*bAbsolute=*/TRUE, &r); + trace("setWindowPos: (%d,%d,%d,%d), result=%d", x, y, w, h, success); +} + +static void setCursorPos(HANDLE conout, int x, int y) { + COORD coord = { static_cast(x), static_cast(y) }; + SetConsoleCursorPosition(conout, coord); +} + +static void setBufferSize(int x, int y) { + setBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), x, y); +} + +static void setWindowPos(int x, int y, int w, int h) { + setWindowPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y, w, h); +} + +static void setCursorPos(int x, int y) { + setCursorPos(GetStdHandle(STD_OUTPUT_HANDLE), x, y); +} + +static void countDown(int sec) { + for (int i = sec; i > 0; --i) { + printf("%d.. ", i); + fflush(stdout); + Sleep(1000); + } + printf("\n"); +} + +static void writeBox(int x, int y, int w, int h, char ch, int attributes=7) { + CHAR_INFO info = { 0 }; + info.Char.AsciiChar = ch; + info.Attributes = attributes; + std::vector buf(w * h, info); + HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + COORD bufSize = { static_cast(w), static_cast(h) }; + COORD bufCoord = { 0, 0 }; + SMALL_RECT writeRegion = { + static_cast(x), + static_cast(y), + static_cast(x + w - 1), + static_cast(y + h - 1) + }; + WriteConsoleOutputA(conout, buf.data(), bufSize, bufCoord, &writeRegion); +} + +static void setChar(int x, int y, char ch, int attributes=7) { + writeBox(x, y, 1, 1, ch, attributes); +} + +static void fillChar(int x, int y, int repeat, char ch) { + COORD coord = { static_cast(x), static_cast(y) }; + DWORD actual = 0; + FillConsoleOutputCharacterA( + GetStdHandle(STD_OUTPUT_HANDLE), + ch, repeat, coord, &actual); +} + +static void repeatChar(int count, char ch) { + for (int i = 0; i < count; ++i) { + putchar(ch); + } + fflush(stdout); +} + +// I don't know why, but wprintf fails to print this face name, +// "MS ゴシック" (aka MS Gothic). It helps to use wprintf instead of printf, and +// it helps to call `setlocale(LC_ALL, "")`, but the Japanese symbols are +// ultimately converted to `?` symbols, even though MS Gothic is able to +// display its own name, and the current code page is 932 (Shift-JIS). +static void cvfprintf(HANDLE conout, const wchar_t *fmt, va_list ap) { + wchar_t buffer[256]; + vswprintf(buffer, 256 - 1, fmt, ap); + buffer[255] = L'\0'; + DWORD actual = 0; + if (!WriteConsoleW(conout, buffer, wcslen(buffer), &actual, NULL)) { + wprintf(L"WriteConsoleW call failed!\n"); + } +} + +static void cfprintf(HANDLE conout, const wchar_t *fmt, ...) { + va_list ap; + va_start(ap, fmt); + cvfprintf(conout, fmt, ap); + va_end(ap); +} + +static void cprintf(const wchar_t *fmt, ...) { + va_list ap; + va_start(ap, fmt); + cvfprintf(GetStdHandle(STD_OUTPUT_HANDLE), fmt, ap); + va_end(ap); +} + +static std::string narrowString(const std::wstring &input) +{ + int mblen = WideCharToMultiByte( + CP_UTF8, 0, + input.data(), input.size(), + NULL, 0, NULL, NULL); + if (mblen <= 0) { + return std::string(); + } + std::vector tmp(mblen); + int mblen2 = WideCharToMultiByte( + CP_UTF8, 0, + input.data(), input.size(), + tmp.data(), tmp.size(), + NULL, NULL); + assert(mblen2 == mblen); + return std::string(tmp.data(), tmp.size()); +} + +HANDLE openConout() { + const HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + ASSERT(conout != INVALID_HANDLE_VALUE); + return conout; +} diff --git a/src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc b/src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc new file mode 100644 index 00000000000..7210d410323 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/UnicodeDoubleWidthTest.cc @@ -0,0 +1,102 @@ +// Demonstrates how U+30FC is sometimes handled as a single-width character +// when it should be handled as a double-width character. +// +// It only runs on computers where 932 is a valid code page. Set the system +// local to "Japanese (Japan)" to ensure this. +// +// The problem seems to happen when U+30FC is printed in a console using the +// Lucida Console font, and only when that font is at certain sizes. +// + +#include +#include +#include +#include +#include +#include + +#include "TestUtil.cc" + +#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) + +static void setFont(const wchar_t *faceName, int pxSize) { + CONSOLE_FONT_INFOEX infoex = {0}; + infoex.cbSize = sizeof(infoex); + infoex.dwFontSize.Y = pxSize; + wcsncpy(infoex.FaceName, faceName, COUNT_OF(infoex.FaceName)); + BOOL ret = SetCurrentConsoleFontEx( + GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &infoex); + assert(ret); +} + +static bool performTest(const wchar_t testChar) { + const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + + SetConsoleTextAttribute(conout, 7); + + system("cls"); + DWORD actual = 0; + BOOL ret = WriteConsoleW(conout, &testChar, 1, &actual, NULL); + assert(ret && actual == 1); + + CHAR_INFO verify[2]; + COORD bufSize = {2, 1}; + COORD bufCoord = {0, 0}; + const SMALL_RECT readRegion = {0, 0, 1, 0}; + SMALL_RECT actualRegion = readRegion; + ret = ReadConsoleOutputW(conout, verify, bufSize, bufCoord, &actualRegion); + assert(ret && !memcmp(&readRegion, &actualRegion, sizeof(readRegion))); + assert(verify[0].Char.UnicodeChar == testChar); + + if (verify[1].Char.UnicodeChar == testChar) { + // Typical double-width behavior with a TrueType font. Pass. + assert(verify[0].Attributes == 0x107); + assert(verify[1].Attributes == 0x207); + return true; + } else if (verify[1].Char.UnicodeChar == 0) { + // Typical double-width behavior with a Raster Font. Pass. + assert(verify[0].Attributes == 7); + assert(verify[1].Attributes == 0); + return true; + } else if (verify[1].Char.UnicodeChar == L' ') { + // Single-width behavior. Fail. + assert(verify[0].Attributes == 7); + assert(verify[1].Attributes == 7); + return false; + } else { + // Unexpected output. + assert(false); + } +} + +int main(int argc, char *argv[]) { + setlocale(LC_ALL, ""); + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + assert(SetConsoleCP(932)); + assert(SetConsoleOutputCP(932)); + + const wchar_t testChar = 0x30FC; + const wchar_t *const faceNames[] = { + L"Lucida Console", + L"Consolas", + L"MS ゴシック", + }; + + trace("Test started"); + + for (auto faceName : faceNames) { + for (int px = 1; px <= 50; ++px) { + setFont(faceName, px); + if (!performTest(testChar)) { + trace("FAILURE: %s %dpx", narrowString(faceName).c_str(), px); + } + } + } + + trace("Test complete"); + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc b/src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc new file mode 100644 index 00000000000..a8d798e70dd --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/UnicodeWideTest1.cc @@ -0,0 +1,246 @@ +#include + +#include +#include + +#include "TestUtil.cc" + +#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) + + +CHAR_INFO ci(wchar_t ch, WORD attributes) { + CHAR_INFO ret; + ret.Char.UnicodeChar = ch; + ret.Attributes = attributes; + return ret; +} + +CHAR_INFO ci(wchar_t ch) { + return ci(ch, 7); +} + +CHAR_INFO ci() { + return ci(L' '); +} + +bool operator==(SMALL_RECT x, SMALL_RECT y) { + return !memcmp(&x, &y, sizeof(x)); +} + +SMALL_RECT sr(COORD pt, COORD size) { + return { + pt.X, pt.Y, + static_cast(pt.X + size.X - 1), + static_cast(pt.Y + size.Y - 1) + }; +} + +static void set( + const COORD pt, + const COORD size, + const std::vector &data) { + assert(data.size() == size.X * size.Y); + SMALL_RECT writeRegion = sr(pt, size); + BOOL ret = WriteConsoleOutputW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), size, {0, 0}, &writeRegion); + assert(ret && writeRegion == sr(pt, size)); +} + +static void set( + const COORD pt, + const std::vector &data) { + set(pt, {static_cast(data.size()), 1}, data); +} + +static void writeAttrsAt( + const COORD pt, + const std::vector &data) { + DWORD actual = 0; + BOOL ret = WriteConsoleOutputAttribute( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), pt, &actual); + assert(ret && actual == data.size()); +} + +static void writeCharsAt( + const COORD pt, + const std::vector &data) { + DWORD actual = 0; + BOOL ret = WriteConsoleOutputCharacterW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), pt, &actual); + assert(ret && actual == data.size()); +} + +static void writeChars( + const std::vector &data) { + DWORD actual = 0; + BOOL ret = WriteConsoleW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), &actual, NULL); + assert(ret && actual == data.size()); +} + +std::vector get( + const COORD pt, + const COORD size) { + std::vector data(size.X * size.Y); + SMALL_RECT readRegion = sr(pt, size); + BOOL ret = ReadConsoleOutputW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), size, {0, 0}, &readRegion); + assert(ret && readRegion == sr(pt, size)); + return data; +} + +std::vector readCharsAt( + const COORD pt, + int size) { + std::vector data(size); + DWORD actual = 0; + BOOL ret = ReadConsoleOutputCharacterW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), pt, &actual); + assert(ret); + data.resize(actual); // With double-width chars, we can read fewer than `size`. + return data; +} + +static void dump(const COORD pt, const COORD size) { + for (CHAR_INFO ci : get(pt, size)) { + printf("%04X %04X\n", ci.Char.UnicodeChar, ci.Attributes); + } +} + +static void dumpCharsAt(const COORD pt, int size) { + for (wchar_t ch : readCharsAt(pt, size)) { + printf("%04X\n", ch); + } +} + +static COORD getCursorPos() { + CONSOLE_SCREEN_BUFFER_INFO info = { sizeof(info) }; + assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)); + return info.dwCursorPosition; +} + +static void test1() { + // We write "䀀䀀", then write "䀁" in the middle of the two. The second + // write turns the first and last cells into spaces. The LEADING/TRAILING + // flags retain consistency. + printf("test1 - overlap full-width char with full-width char\n"); + writeCharsAt({1,0}, {0x4000, 0x4000}); + dump({0,0}, {6,1}); + printf("\n"); + writeCharsAt({2,0}, {0x4001}); + dump({0,0}, {6,1}); + printf("\n"); +} + +static void test2() { + // Like `test1`, but use a lower-level API to do the write. Consistency is + // preserved here too -- the first and last cells are replaced with spaces. + printf("test2 - overlap full-width char with full-width char (lowlevel)\n"); + writeCharsAt({1,0}, {0x4000, 0x4000}); + dump({0,0}, {6,1}); + printf("\n"); + set({2,0}, {ci(0x4001,0x107), ci(0x4001,0x207)}); + dump({0,0}, {6,1}); + printf("\n"); +} + +static void test3() { + // However, the lower-level API can break the LEADING/TRAILING invariant + // explicitly: + printf("test3 - explicitly violate LEADING/TRAILING using lowlevel API\n"); + set({1,0}, { + ci(0x4000, 0x207), + ci(0x4001, 0x107), + ci(0x3044, 7), + ci(L'X', 0x107), + ci(L'X', 0x207), + }); + dump({0,0}, {7,1}); +} + +static void test4() { + // It is possible for the two cells of a double-width character to have two + // colors. + printf("test4 - use lowlevel to assign two colors to one full-width char\n"); + set({0,0}, { + ci(0x4000, 0x142), + ci(0x4000, 0x224), + }); + dump({0,0}, {2,1}); +} + +static void test5() { + // WriteConsoleOutputAttribute doesn't seem to affect the LEADING/TRAILING + // flags. + printf("test5 - WriteConsoleOutputAttribute cannot affect LEADING/TRAILING\n"); + + // Trying to clear the flags doesn't work... + writeCharsAt({0,0}, {0x4000}); + dump({0,0}, {2,1}); + writeAttrsAt({0,0}, {0x42, 0x24}); + printf("\n"); + dump({0,0}, {2,1}); + + // ... and trying to add them also doesn't work. + writeCharsAt({0,1}, {'A', ' '}); + writeAttrsAt({0,1}, {0x107, 0x207}); + printf("\n"); + dump({0,1}, {2,1}); +} + +static void test6() { + // The cursor position may be on either cell of a double-width character. + // Visually, the cursor appears under both cells, regardless of which + // specific one has the cursor. + printf("test6 - cursor can be either left or right cell of full-width char\n"); + + writeCharsAt({2,1}, {0x4000}); + + setCursorPos(2, 1); + auto pos1 = getCursorPos(); + Sleep(1000); + + setCursorPos(3, 1); + auto pos2 = getCursorPos(); + Sleep(1000); + + setCursorPos(0, 15); + printf("%d,%d\n", pos1.X, pos1.Y); + printf("%d,%d\n", pos2.X, pos2.Y); +} + +static void runTest(void (&test)()) { + system("cls"); + setCursorPos(0, 14); + test(); + system("pause"); +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + setWindowPos(0, 0, 1, 1); + setBufferSize(80, 40); + setWindowPos(0, 0, 80, 40); + + auto cp = GetConsoleOutputCP(); + assert(cp == 932 || cp == 936 || cp == 949 || cp == 950); + + runTest(test1); + runTest(test2); + runTest(test3); + runTest(test4); + runTest(test5); + runTest(test6); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc b/src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc new file mode 100644 index 00000000000..05f80f70bd1 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/UnicodeWideTest2.cc @@ -0,0 +1,130 @@ +// +// Test half-width vs full-width characters. +// + +#include +#include +#include +#include + +#include "TestUtil.cc" + +static void writeChars(const wchar_t *text) { + wcslen(text); + const int len = wcslen(text); + DWORD actual = 0; + BOOL ret = WriteConsoleW( + GetStdHandle(STD_OUTPUT_HANDLE), + text, len, &actual, NULL); + trace("writeChars: ret=%d, actual=%lld", ret, (long long)actual); +} + +static void dumpChars(int x, int y, int w, int h) { + BOOL ret; + const COORD bufSize = {w, h}; + const COORD bufCoord = {0, 0}; + const SMALL_RECT topLeft = {x, y, x + w - 1, y + h - 1}; + CHAR_INFO mbcsData[w * h]; + CHAR_INFO unicodeData[w * h]; + SMALL_RECT readRegion; + readRegion = topLeft; + ret = ReadConsoleOutputW(GetStdHandle(STD_OUTPUT_HANDLE), unicodeData, + bufSize, bufCoord, &readRegion); + assert(ret); + readRegion = topLeft; + ret = ReadConsoleOutputA(GetStdHandle(STD_OUTPUT_HANDLE), mbcsData, + bufSize, bufCoord, &readRegion); + assert(ret); + + printf("\n"); + for (int i = 0; i < w * h; ++i) { + printf("(%02d,%02d) CHAR: %04x %4x -- %02x %4x\n", + x + i % w, y + i / w, + (unsigned short)unicodeData[i].Char.UnicodeChar, + (unsigned short)unicodeData[i].Attributes, + (unsigned char)mbcsData[i].Char.AsciiChar, + (unsigned short)mbcsData[i].Attributes); + } +} + +int main(int argc, char *argv[]) { + system("cls"); + setWindowPos(0, 0, 1, 1); + setBufferSize(80, 38); + setWindowPos(0, 0, 80, 38); + + // Write text. + const wchar_t text1[] = { + 0x3044, // U+3044 (HIRAGANA LETTER I) + 0x2014, // U+2014 (EM DASH) + 0x3044, // U+3044 (HIRAGANA LETTER I) + 0xFF2D, // U+FF2D (FULLWIDTH LATIN CAPITAL LETTER M) + 0x30FC, // U+30FC (KATAKANA-HIRAGANA PROLONGED SOUND MARK) + 0x0031, // U+3031 (DIGIT ONE) + 0x2014, // U+2014 (EM DASH) + 0x0032, // U+0032 (DIGIT TWO) + 0x005C, // U+005C (REVERSE SOLIDUS) + 0x3044, // U+3044 (HIRAGANA LETTER I) + 0 + }; + setCursorPos(0, 0); + writeChars(text1); + + setCursorPos(78, 1); + writeChars(L"<>"); + + const wchar_t text2[] = { + 0x0032, // U+3032 (DIGIT TWO) + 0x3044, // U+3044 (HIRAGANA LETTER I) + 0, + }; + setCursorPos(78, 1); + writeChars(text2); + + system("pause"); + + dumpChars(0, 0, 17, 1); + dumpChars(2, 0, 2, 1); + dumpChars(2, 0, 1, 1); + dumpChars(3, 0, 1, 1); + dumpChars(78, 1, 2, 1); + dumpChars(0, 2, 2, 1); + + system("pause"); + system("cls"); + + const wchar_t text3[] = { + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 1 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 2 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 3 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 4 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 5 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 6 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 7 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 8 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 9 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 10 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 11 + 0x30FC, 0x30FC, 0x30FC, 0xFF2D, // 12 + L'\r', '\n', + L'\r', '\n', + 0 + }; + writeChars(text3); + system("pause"); + { + const COORD bufSize = {80, 2}; + const COORD bufCoord = {0, 0}; + SMALL_RECT readRegion = {0, 0, 79, 1}; + CHAR_INFO unicodeData[160]; + BOOL ret = ReadConsoleOutputW(GetStdHandle(STD_OUTPUT_HANDLE), unicodeData, + bufSize, bufCoord, &readRegion); + assert(ret); + for (int i = 0; i < 96; ++i) { + printf("%04x ", unicodeData[i].Char.UnicodeChar); + } + printf("\n"); + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/UnixEcho.cc b/src/libs/3rdparty/winpty/misc/UnixEcho.cc new file mode 100644 index 00000000000..372e0451574 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/UnixEcho.cc @@ -0,0 +1,89 @@ +/* + * Unix test code that puts the terminal into raw mode, then echos typed + * characters to stdout. Derived from sample code in the Stevens book, posted + * online at http://www.lafn.org/~dave/linux/terminalIO.html. + */ + +#include +#include +#include +#include +#include "FormatChar.h" + +static struct termios save_termios; +static int term_saved; + +/* RAW! mode */ +int tty_raw(int fd) +{ + struct termios buf; + + if (tcgetattr(fd, &save_termios) < 0) /* get the original state */ + return -1; + + buf = save_termios; + + /* echo off, canonical mode off, extended input + processing off, signal chars off */ + buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + + /* no SIGINT on BREAK, CR-to-NL off, input parity + check off, don't strip the 8th bit on input, + ouput flow control off */ + buf.c_iflag &= ~(BRKINT | ICRNL | ISTRIP | IXON); + + /* clear size bits, parity checking off */ + buf.c_cflag &= ~(CSIZE | PARENB); + + /* set 8 bits/char */ + buf.c_cflag |= CS8; + + /* output processing off */ + buf.c_oflag &= ~(OPOST); + + buf.c_cc[VMIN] = 1; /* 1 byte at a time */ + buf.c_cc[VTIME] = 0; /* no timer on input */ + + if (tcsetattr(fd, TCSAFLUSH, &buf) < 0) + return -1; + + term_saved = 1; + + return 0; +} + + +/* set it to normal! */ +int tty_reset(int fd) +{ + if (term_saved) + if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0) + return -1; + + return 0; +} + + +int main() +{ + tty_raw(0); + + int count = 0; + while (true) { + char ch; + char buf[16]; + int actual = read(0, &ch, 1); + if (actual != 1) { + perror("read error"); + break; + } + formatChar(buf, ch); + fputs(buf, stdout); + fflush(stdout); + if (ch == 3) // Ctrl-C + break; + } + + tty_reset(0); + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Utf16Echo.cc b/src/libs/3rdparty/winpty/misc/Utf16Echo.cc new file mode 100644 index 00000000000..ef5f302de47 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Utf16Echo.cc @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +#include +#include + +int main(int argc, char *argv[]) { + system("cls"); + + if (argc == 1) { + printf("Usage: %s hhhh\n", argv[0]); + return 0; + } + + std::wstring dataToWrite; + for (int i = 1; i < argc; ++i) { + wchar_t ch = strtol(argv[i], NULL, 16); + dataToWrite.push_back(ch); + } + + DWORD actual = 0; + BOOL ret = WriteConsoleW( + GetStdHandle(STD_OUTPUT_HANDLE), + dataToWrite.data(), dataToWrite.size(), &actual, NULL); + assert(ret && actual == dataToWrite.size()); + + // Read it back. + std::vector readBuffer(dataToWrite.size() * 2); + COORD bufSize = {static_cast(readBuffer.size()), 1}; + COORD bufCoord = {0, 0}; + SMALL_RECT topLeft = {0, 0, static_cast(readBuffer.size() - 1), 0}; + ret = ReadConsoleOutputW( + GetStdHandle(STD_OUTPUT_HANDLE), readBuffer.data(), + bufSize, bufCoord, &topLeft); + assert(ret); + + printf("\n"); + for (int i = 0; i < readBuffer.size(); ++i) { + printf("CHAR: %04x %04x\n", + readBuffer[i].Char.UnicodeChar, + readBuffer[i].Attributes); + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/VeryLargeRead.cc b/src/libs/3rdparty/winpty/misc/VeryLargeRead.cc new file mode 100644 index 00000000000..58f0897022e --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/VeryLargeRead.cc @@ -0,0 +1,122 @@ +// +// 2015-09-25 +// I measured these limits on the size of a single ReadConsoleOutputW call. +// The limit seems to more-or-less disppear with Windows 8, which is the first +// OS to stop using ALPCs for console I/O. My guess is that the new I/O +// method does not use the 64KiB shared memory buffer that the ALPC method +// uses. +// +// I'm guessing the remaining difference between Windows 8/8.1 and Windows 10 +// might be related to the 32-vs-64-bitness. +// +// Client OSs +// +// Windows XP 32-bit VM ==> up to 13304 characters +// - 13304x1 works, but 13305x1 fails instantly +// Windows 7 32-bit VM ==> between 16-17 thousand characters +// - 16000x1 works, 17000x1 fails instantly +// - 163x100 *crashes* conhost.exe but leaves VeryLargeRead.exe running +// Windows 8 32-bit VM ==> between 240-250 million characters +// - 10000x24000 works, but 10000x25000 does not +// Windows 8.1 32-bit VM ==> between 240-250 million characters +// - 10000x24000 works, but 10000x25000 does not +// Windows 10 64-bit VM ==> no limit (tested to 576 million characters) +// - 24000x24000 works +// - `ver` reports [Version 10.0.10240], conhost.exe and ConhostV1.dll are +// 10.0.10240.16384 for file and product version. ConhostV2.dll is +// 10.0.10240.16391 for file and product version. +// +// Server OSs +// +// Windows Server 2008 64-bit VM ==> 14300-14400 characters +// - 14300x1 works, 14400x1 fails instantly +// - This OS does not have conhost.exe. +// - `ver` reports [Version 6.0.6002] +// Windows Server 2008 R2 64-bit VM ==> 15600-15700 characters +// - 15600x1 works, 15700x1 fails instantly +// - This OS has conhost.exe, and procexp.exe reveals console ALPC ports in +// use in conhost.exe. +// - `ver` reports [Version 6.1.7601], conhost.exe is 6.1.7601.23153 for file +// and product version. +// Windows Server 2012 64-bit VM ==> at least 100 million characters +// - 10000x10000 works (VM had only 1GiB of RAM, so I skipped larger tests) +// - This OS has Windows 8's task manager and procexp.exe reveals the same +// lack of ALPC ports and the same \Device\ConDrv\* files as Windows 8. +// - `ver` reports [Version 6.2.9200], conhost.exe is 6.2.9200.16579 for file +// and product version. +// +// To summarize: +// +// client-OS server-OS notes +// --------------------------------------------------------------------------- +// XP Server 2008 CSRSS, small reads +// 7 Server 2008 R2 ALPC-to-conhost, small reads +// 8, 8.1 Server 2012 new I/O interface, large reads allowed +// 10 enhanced console w/rewrapping +// +// (Presumably, Win2K, Vista, and Win2K3 behave the same as XP. conhost.exe +// was announced as a Win7 feature.) +// + +#include +#include +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + long long width = 9000; + long long height = 9000; + + assert(argc >= 1); + if (argc == 4) { + width = atoi(argv[2]); + height = atoi(argv[3]); + } else { + if (argc == 3) { + width = atoi(argv[1]); + height = atoi(argv[2]); + } + wchar_t args[1024]; + swprintf(args, 1024, L"CHILD %lld %lld", width, height); + startChildProcess(args); + return 0; + } + + const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + + setWindowPos(0, 0, 1, 1); + setBufferSize(width, height); + setWindowPos(0, 0, std::min(80LL, width), std::min(50LL, height)); + + setCursorPos(0, 0); + printf("A"); + fflush(stdout); + setCursorPos(width - 2, height - 1); + printf("B"); + fflush(stdout); + + trace("sizeof(CHAR_INFO) = %d", (int)sizeof(CHAR_INFO)); + + trace("Allocating buffer..."); + CHAR_INFO *buffer = new CHAR_INFO[width * height]; + assert(buffer != NULL); + memset(&buffer[0], 0, sizeof(CHAR_INFO)); + memset(&buffer[width * height - 2], 0, sizeof(CHAR_INFO)); + + COORD bufSize = { width, height }; + COORD bufCoord = { 0, 0 }; + SMALL_RECT readRegion = { 0, 0, width - 1, height - 1 }; + trace("ReadConsoleOutputW: calling..."); + BOOL success = ReadConsoleOutputW(conout, buffer, bufSize, bufCoord, &readRegion); + trace("ReadConsoleOutputW: success=%d", success); + + assert(buffer[0].Char.UnicodeChar == L'A'); + assert(buffer[width * height - 2].Char.UnicodeChar == L'B'); + trace("Top-left and bottom-right characters read successfully!"); + + Sleep(30000); + + delete [] buffer; + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/VkEscapeTest.cc b/src/libs/3rdparty/winpty/misc/VkEscapeTest.cc new file mode 100644 index 00000000000..97bf59f998b --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/VkEscapeTest.cc @@ -0,0 +1,56 @@ +/* + * Sending VK_PAUSE to the console window almost works as a mechanism for + * pausing it, but it doesn't because the console could turn off the + * ENABLE_LINE_INPUT console mode flag. + */ + +#define _WIN32_WINNT 0x0501 +#include +#include +#include + +CALLBACK DWORD pausingThread(LPVOID dummy) +{ + if (1) { + Sleep(1000); + HWND hwnd = GetConsoleWindow(); + SendMessage(hwnd, WM_KEYDOWN, VK_PAUSE, 1); + Sleep(1000); + SendMessage(hwnd, WM_KEYDOWN, VK_ESCAPE, 1); + } + + if (0) { + INPUT_RECORD ir; + memset(&ir, 0, sizeof(ir)); + ir.EventType = KEY_EVENT; + ir.Event.KeyEvent.bKeyDown = TRUE; + ir.Event.KeyEvent.wVirtualKeyCode = VK_PAUSE; + ir.Event.KeyEvent.wRepeatCount = 1; + } + + return 0; +} + +int main() +{ + HANDLE hin = GetStdHandle(STD_INPUT_HANDLE); + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + COORD c = { 0, 0 }; + + DWORD mode; + GetConsoleMode(hin, &mode); + SetConsoleMode(hin, mode & + ~(ENABLE_LINE_INPUT)); + + CreateThread(NULL, 0, + pausingThread, NULL, + 0, NULL); + + int i = 0; + while (true) { + Sleep(100); + printf("%d\n", ++i); + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc b/src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc new file mode 100644 index 00000000000..82feaf3c501 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win10ResizeWhileFrozen.cc @@ -0,0 +1,52 @@ +/* + * Demonstrates a conhost hang that occurs when widening the console buffer + * while selection is in progress. The problem affects the new Windows 10 + * console, not the "legacy" console mode that Windows 10 also includes. + * + * First tested with: + * - Windows 10.0.10240 + * - conhost.exe version 10.0.10240.16384 + * - ConhostV1.dll version 10.0.10240.16384 + * - ConhostV2.dll version 10.0.10240.16391 + */ + +#include +#include +#include +#include + +#include "TestUtil.cc" + +const int SC_CONSOLE_MARK = 0xFFF2; +const int SC_CONSOLE_SELECT_ALL = 0xFFF5; + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + setWindowPos(0, 0, 1, 1); + setBufferSize(80, 25); + setWindowPos(0, 0, 80, 25); + + countDown(5); + + SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, SC_CONSOLE_SELECT_ALL, 0); + Sleep(2000); + + // This API call does not return. In the console window, the "Select All" + // operation appears to end. The console window becomes non-responsive, + // and the conhost.exe process must be killed from the Task Manager. + // (Killing this test program or closing the console window is not + // sufficient.) + // + // The same hang occurs whether line resizing is off or on. It happens + // with both "Mark" and "Select All". Calling setBufferSize with the + // existing buffer size does not hang, but calling it with only a changed + // buffer height *does* hang. Calling setWindowPos does not hang. + setBufferSize(120, 25); + + printf("Done...\n"); + Sleep(2000); +} diff --git a/src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc b/src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc new file mode 100644 index 00000000000..645fa95d542 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win10WrapTest1.cc @@ -0,0 +1,57 @@ +/* + * Demonstrates some wrapping behaviors of the new Windows 10 console. + */ + +#include +#include +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + setWindowPos(0, 0, 1, 1); + setBufferSize(40, 20); + setWindowPos(0, 0, 40, 20); + + system("cls"); + + repeatChar(39, 'A'); repeatChar(1, ' '); + repeatChar(39, 'B'); repeatChar(1, ' '); + printf("\n"); + + repeatChar(39, 'C'); repeatChar(1, ' '); + repeatChar(39, 'D'); repeatChar(1, ' '); + printf("\n"); + + repeatChar(40, 'E'); + repeatChar(40, 'F'); + printf("\n"); + + repeatChar(39, 'G'); repeatChar(1, ' '); + repeatChar(39, 'H'); repeatChar(1, ' '); + printf("\n"); + + Sleep(2000); + + setChar(39, 0, '*', 0x24); + setChar(39, 1, '*', 0x24); + + setChar(39, 3, ' ', 0x24); + setChar(39, 4, ' ', 0x24); + + setChar(38, 6, ' ', 0x24); + setChar(38, 7, ' ', 0x24); + + Sleep(2000); + setWindowPos(0, 0, 35, 20); + setBufferSize(35, 20); + trace("DONE"); + + printf("Sleeping forever...\n"); + while(true) { Sleep(1000); } +} diff --git a/src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc b/src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc new file mode 100644 index 00000000000..50615fc8c79 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win10WrapTest2.cc @@ -0,0 +1,30 @@ +#include + +#include "TestUtil.cc" + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + const int WIDTH = 25; + + setWindowPos(0, 0, 1, 1); + setBufferSize(WIDTH, 40); + setWindowPos(0, 0, WIDTH, 20); + + system("cls"); + + for (int i = 0; i < 100; ++i) { + printf("FOO(%d)\n", i); + } + + repeatChar(5, '\n'); + repeatChar(WIDTH * 5, '.'); + repeatChar(10, '\n'); + setWindowPos(0, 20, WIDTH, 20); + writeBox(0, 5, 1, 10, '|'); + + Sleep(120000); +} diff --git a/src/libs/3rdparty/winpty/misc/Win32Echo1.cc b/src/libs/3rdparty/winpty/misc/Win32Echo1.cc new file mode 100644 index 00000000000..06fc79f7945 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win32Echo1.cc @@ -0,0 +1,26 @@ +/* + * A Win32 program that reads raw console input with ReadFile and echos + * it to stdout. + */ + +#include +#include +#include + +int main() +{ + int count = 0; + HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleMode(hStdIn, 0); + + while (true) { + DWORD actual; + char ch; + ReadFile(hStdIn, &ch, 1, &actual, NULL); + printf("%02x ", ch); + if (++count == 50) + break; + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Win32Echo2.cc b/src/libs/3rdparty/winpty/misc/Win32Echo2.cc new file mode 100644 index 00000000000..b2ea2ad1c5d --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win32Echo2.cc @@ -0,0 +1,19 @@ +/* + * A Win32 program that reads raw console input with getch and echos + * it to stdout. + */ + +#include +#include + +int main() +{ + int count = 0; + while (true) { + int ch = getch(); + printf("%02x ", ch); + if (++count == 50) + break; + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Win32Test1.cc b/src/libs/3rdparty/winpty/misc/Win32Test1.cc new file mode 100644 index 00000000000..a40d318a98c --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win32Test1.cc @@ -0,0 +1,46 @@ +#define _WIN32_WINNT 0x0501 +#include "../src/shared/DebugClient.cc" +#include +#include + +const int SC_CONSOLE_MARK = 0xFFF2; + +CALLBACK DWORD writerThread(void*) +{ + while (true) { + Sleep(1000); + trace("writing"); + printf("X\n"); + trace("written"); + } +} + +int main() +{ + CreateThread(NULL, 0, writerThread, NULL, 0, NULL); + trace("marking console"); + HWND hwnd = GetConsoleWindow(); + PostMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); + + Sleep(2000); + + trace("reading output"); + CHAR_INFO buf[1]; + COORD bufSize = { 1, 1 }; + COORD zeroCoord = { 0, 0 }; + SMALL_RECT readRect = { 0, 0, 0, 0 }; + ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), + buf, + bufSize, + zeroCoord, + &readRect); + trace("done reading output"); + + Sleep(2000); + + PostMessage(hwnd, WM_CHAR, 27, 0x00010001); + + Sleep(1100); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Win32Test2.cc b/src/libs/3rdparty/winpty/misc/Win32Test2.cc new file mode 100644 index 00000000000..2777bad4562 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win32Test2.cc @@ -0,0 +1,70 @@ +/* + * This test demonstrates that putting a console into selection mode does not + * block the low-level console APIs, even though it blocks WriteFile. + */ + +#define _WIN32_WINNT 0x0501 +#include "../src/shared/DebugClient.cc" +#include +#include + +const int SC_CONSOLE_MARK = 0xFFF2; + +CALLBACK DWORD writerThread(void*) +{ + CHAR_INFO xChar, fillChar; + memset(&xChar, 0, sizeof(xChar)); + xChar.Char.AsciiChar = 'X'; + xChar.Attributes = 7; + memset(&fillChar, 0, sizeof(fillChar)); + fillChar.Char.AsciiChar = ' '; + fillChar.Attributes = 7; + COORD oneCoord = { 1, 1 }; + COORD zeroCoord = { 0, 0 }; + + while (true) { + SMALL_RECT writeRegion = { 5, 5, 5, 5 }; + WriteConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), + &xChar, oneCoord, + zeroCoord, + &writeRegion); + Sleep(500); + SMALL_RECT scrollRect = { 1, 1, 20, 20 }; + COORD destCoord = { 0, 0 }; + ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE), + &scrollRect, + NULL, + destCoord, + &fillChar); + } +} + +int main() +{ + CreateThread(NULL, 0, writerThread, NULL, 0, NULL); + trace("marking console"); + HWND hwnd = GetConsoleWindow(); + PostMessage(hwnd, WM_SYSCOMMAND, SC_CONSOLE_MARK, 0); + + Sleep(2000); + + trace("reading output"); + CHAR_INFO buf[1]; + COORD bufSize = { 1, 1 }; + COORD zeroCoord = { 0, 0 }; + SMALL_RECT readRect = { 0, 0, 0, 0 }; + ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), + buf, + bufSize, + zeroCoord, + &readRect); + trace("done reading output"); + + Sleep(2000); + + PostMessage(hwnd, WM_CHAR, 27, 0x00010001); + + Sleep(1100); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Win32Test3.cc b/src/libs/3rdparty/winpty/misc/Win32Test3.cc new file mode 100644 index 00000000000..1fb92aff3df --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win32Test3.cc @@ -0,0 +1,78 @@ +/* + * Creates a window station and starts a process under it. The new process + * also gets a new console. + */ + +#include +#include +#include + +int main() +{ + BOOL success; + + SECURITY_ATTRIBUTES sa; + memset(&sa, 0, sizeof(sa)); + sa.bInheritHandle = TRUE; + + HWINSTA originalStation = GetProcessWindowStation(); + printf("originalStation == 0x%x\n", originalStation); + HWINSTA station = CreateWindowStation(NULL, + 0, + WINSTA_ALL_ACCESS, + &sa); + printf("station == 0x%x\n", station); + if (!SetProcessWindowStation(station)) + printf("SetWindowStation failed!\n"); + HDESK desktop = CreateDesktop("Default", NULL, NULL, + /*dwFlags=*/0, GENERIC_ALL, + &sa); + printf("desktop = 0x%x\n", desktop); + + char stationName[256]; + stationName[0] = '\0'; + success = GetUserObjectInformation(station, UOI_NAME, + stationName, sizeof(stationName), + NULL); + printf("stationName = [%s]\n", stationName); + + char startupDesktop[256]; + sprintf(startupDesktop, "%s\\Default", stationName); + + STARTUPINFO sui; + PROCESS_INFORMATION pi; + memset(&sui, 0, sizeof(sui)); + memset(&pi, 0, sizeof(pi)); + sui.cb = sizeof(STARTUPINFO); + sui.lpDesktop = startupDesktop; + + // Start a cmd subprocess, and have it start its own cmd subprocess. + // Both subprocesses will connect to the same non-interactive window + // station. + + const char program[] = "c:\\windows\\system32\\cmd.exe"; + char cmdline[256]; + sprintf(cmdline, "%s /c cmd", program); + success = CreateProcess(program, + cmdline, + NULL, + NULL, + /*bInheritHandles=*/FALSE, + /*dwCreationFlags=*/CREATE_NEW_CONSOLE, + NULL, NULL, + &sui, + &pi); + + printf("pid == %d\n", pi.dwProcessId); + + // This sleep is necessary. We must give the child enough time to + // connect to the specified window station. + Sleep(5000); + + SetProcessWindowStation(originalStation); + CloseWindowStation(station); + CloseDesktop(desktop); + Sleep(5000); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/Win32Write1.cc b/src/libs/3rdparty/winpty/misc/Win32Write1.cc new file mode 100644 index 00000000000..6e5bf966822 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/Win32Write1.cc @@ -0,0 +1,44 @@ +/* + * A Win32 program that scrolls and writes to the console using the ioctl-like + * interface. + */ + +#include +#include + +int main() +{ + HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + + for (int i = 0; i < 80; ++i) { + + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(conout, &info); + + SMALL_RECT src = { 0, 1, info.dwSize.X - 1, info.dwSize.Y - 1 }; + COORD destOrigin = { 0, 0 }; + CHAR_INFO fillCharInfo = { 0 }; + fillCharInfo.Char.AsciiChar = ' '; + fillCharInfo.Attributes = 7; + ScrollConsoleScreenBuffer(conout, + &src, + NULL, + destOrigin, + &fillCharInfo); + + CHAR_INFO buffer = { 0 }; + buffer.Char.AsciiChar = 'X'; + buffer.Attributes = 7; + COORD bufferSize = { 1, 1 }; + COORD bufferCoord = { 0, 0 }; + SMALL_RECT writeRegion = { 0, 0, 0, 0 }; + writeRegion.Left = writeRegion.Right = i; + writeRegion.Top = writeRegion.Bottom = 5; + WriteConsoleOutput(conout, + &buffer, bufferSize, bufferCoord, + &writeRegion); + + Sleep(250); + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc b/src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc new file mode 100644 index 00000000000..e6d9558df63 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/WindowsBugCrashReader.cc @@ -0,0 +1,27 @@ +// I noticed this on the ConEmu web site: +// +// https://social.msdn.microsoft.com/Forums/en-US/40c8e395-cca9-45c8-b9b8-2fbe6782ac2b/readconsoleoutput-cause-access-violation-writing-location-exception +// https://conemu.github.io/en/MicrosoftBugs.html +// +// In Windows 7, 8, and 8.1, a ReadConsoleOutputW with an out-of-bounds read +// region crashes the application. I have reproduced the problem on Windows 8 +// and 8.1, but not on Windows 7. +// + +#include + +#include "TestUtil.cc" + +int main() { + setWindowPos(0, 0, 1, 1); + setBufferSize(80, 25); + setWindowPos(0, 0, 80, 25); + + const HANDLE conout = openConout(); + static CHAR_INFO lineBuf[80]; + SMALL_RECT readRegion = { 0, 999, 79, 999 }; + const BOOL ret = ReadConsoleOutputW(conout, lineBuf, {80, 1}, {0, 0}, &readRegion); + ASSERT(!ret && "ReadConsoleOutputW should have failed"); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/WriteConsole.cc b/src/libs/3rdparty/winpty/misc/WriteConsole.cc new file mode 100644 index 00000000000..a03670ca929 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/WriteConsole.cc @@ -0,0 +1,106 @@ +#include + +#include +#include +#include + +#include +#include + +static std::wstring mbsToWcs(const std::string &s) { + const size_t len = mbstowcs(nullptr, s.c_str(), 0); + if (len == static_cast(-1)) { + assert(false && "mbsToWcs: invalid string"); + } + std::wstring ret; + ret.resize(len); + const size_t len2 = mbstowcs(&ret[0], s.c_str(), len); + assert(len == len2); + return ret; +} + +uint32_t parseHex(wchar_t ch, bool &invalid) { + if (ch >= L'0' && ch <= L'9') { + return ch - L'0'; + } else if (ch >= L'a' && ch <= L'f') { + return ch - L'a' + 10; + } else if (ch >= L'A' && ch <= L'F') { + return ch - L'A' + 10; + } else { + invalid = true; + return 0; + } +} + +int main(int argc, char *argv[]) { + std::vector args; + for (int i = 1; i < argc; ++i) { + args.push_back(mbsToWcs(argv[i])); + } + + std::wstring out; + for (const auto &arg : args) { + if (!out.empty()) { + out.push_back(L' '); + } + for (size_t i = 0; i < arg.size(); ++i) { + wchar_t ch = arg[i]; + wchar_t nch = i + 1 < arg.size() ? arg[i + 1] : L'\0'; + if (ch == L'\\') { + switch (nch) { + case L'a': ch = L'\a'; ++i; break; + case L'b': ch = L'\b'; ++i; break; + case L'e': ch = L'\x1b'; ++i; break; + case L'f': ch = L'\f'; ++i; break; + case L'n': ch = L'\n'; ++i; break; + case L'r': ch = L'\r'; ++i; break; + case L't': ch = L'\t'; ++i; break; + case L'v': ch = L'\v'; ++i; break; + case L'\\': ch = L'\\'; ++i; break; + case L'\'': ch = L'\''; ++i; break; + case L'\"': ch = L'\"'; ++i; break; + case L'\?': ch = L'\?'; ++i; break; + case L'x': + if (i + 3 < arg.size()) { + bool invalid = false; + uint32_t d1 = parseHex(arg[i + 2], invalid); + uint32_t d2 = parseHex(arg[i + 3], invalid); + if (!invalid) { + i += 3; + ch = (d1 << 4) | d2; + } + } + break; + case L'u': + if (i + 5 < arg.size()) { + bool invalid = false; + uint32_t d1 = parseHex(arg[i + 2], invalid); + uint32_t d2 = parseHex(arg[i + 3], invalid); + uint32_t d3 = parseHex(arg[i + 4], invalid); + uint32_t d4 = parseHex(arg[i + 5], invalid); + if (!invalid) { + i += 5; + ch = (d1 << 24) | (d2 << 16) | (d3 << 8) | d4; + } + } + break; + default: break; + } + } + out.push_back(ch); + } + } + + DWORD actual = 0; + if (!WriteConsoleW( + GetStdHandle(STD_OUTPUT_HANDLE), + out.c_str(), + out.size(), + &actual, + nullptr)) { + fprintf(stderr, "WriteConsole failed (is stdout a console?)\n"); + exit(1); + } + + return 0; +} diff --git a/src/libs/3rdparty/winpty/misc/build32.sh b/src/libs/3rdparty/winpty/misc/build32.sh new file mode 100644 index 00000000000..162993ce337 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/build32.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e +name=$1 +name=${name%.} +name=${name%.cc} +name=${name%.exe} +echo Compiling $name.cc to $name.exe +i686-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe +i686-w64-mingw32-strip $name.exe diff --git a/src/libs/3rdparty/winpty/misc/build64.sh b/src/libs/3rdparty/winpty/misc/build64.sh new file mode 100644 index 00000000000..67579676847 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/build64.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e +name=$1 +name=${name%.} +name=${name%.cc} +name=${name%.exe} +echo Compiling $name.cc to $name.exe +x86_64-w64-mingw32-g++.exe -static -std=c++11 $name.cc -o $name.exe +x86_64-w64-mingw32-strip $name.exe diff --git a/src/libs/3rdparty/winpty/misc/color-test.sh b/src/libs/3rdparty/winpty/misc/color-test.sh new file mode 100644 index 00000000000..065c8094e29 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/color-test.sh @@ -0,0 +1,212 @@ +#!/bin/bash + +FORE=$1 +BACK=$2 +FILL=$3 + +if [ "$FORE" = "" ]; then + FORE=DefaultFore +fi +if [ "$BACK" = "" ]; then + BACK=DefaultBack +fi + +# To detect color changes, we want a character that fills the whole cell +# if possible. U+2588 is perfect, except that it becomes invisible in the +# original xterm, when bolded. For that terminal, use something else, like +# "#" or "@". +if [ "$FILL" = "" ]; then + FILL="█" +fi + +# SGR (Select Graphic Rendition) +s() { + printf '\033[0m' + while [ "$1" != "" ]; do + printf '\033['"$1"'m' + shift + done +} + +# Print +p() { + echo -n "$@" +} + +# Print with newline +pn() { + echo "$@" +} + +# For practical reasons, sandwich black and white in-between the other colors. +FORE_COLORS="31 30 37 32 33 34 35 36" +BACK_COLORS="41 40 47 42 43 44 45 46" + + + +### Test order of Invert(7) -- it does not matter what order it appears in. + +# The Red color setting here (31) is shadowed by the green setting (32). The +# Reverse flag does not cause (32) to alter the background color immediately; +# instead, the Reverse flag is applied once to determine the final effective +# Fore/Back colors. +s 7 31 32; p " -- Should be: $BACK-on-green -- "; s; pn +s 31 7 32; p " -- Should be: $BACK-on-green -- "; s; pn +s 31 32 7; p " -- Should be: $BACK-on-green -- "; s; pn + +# As above, but for the background color. +s 7 41 42; p " -- Should be: green-on-$FORE -- "; s; pn +s 41 7 42; p " -- Should be: green-on-$FORE -- "; s; pn +s 41 42 7; p " -- Should be: green-on-$FORE -- "; s; pn + +# One last, related test +s 7; p "Invert text"; s 7 1; p " with some words bold"; s; pn; +s 0; p "Normal text"; s 0 1; p " with some words bold"; s; pn; + +pn + + + +### Test effect of Bold(1) on color, with and without Invert(7). + +# The Bold flag does not affect the background color when Reverse is missing. +# There should always be 8 colored boxes. +p " " +for x in $BACK_COLORS; do + s $x; p "-"; s $x 1; p "-" +done +s; pn " Bold should not affect background" + +# On some terminals, Bold affects color, and on some it doesn't. If there +# are only 8 colored boxes, then the next two tests will also show 8 colored +# boxes. If there are 16 boxes, then exactly one of the next two tests will +# also have 16 boxes. +p " " +for x in $FORE_COLORS; do + s $x; p "$FILL"; s $x 1; p "$FILL" +done +s; pn " Does bold affect foreground color?" + +# On some terminals, Bold+Invert highlights the final Background color. +p " " +for x in $FORE_COLORS; do + s $x 7; p "-"; s $x 7 1; p "-" +done +s; pn " Test if Bold+Invert affects background color" + +# On some terminals, Bold+Invert highlights the final Foreground color. +p " " +for x in $BACK_COLORS; do + s $x 7; p "$FILL"; s $x 7 1; p "$FILL" +done +s; pn " Test if Bold+Invert affects foreground color" + +pn + + + +### Test for support of ForeHi and BackHi properties. + +# ForeHi +p " " +for x in $FORE_COLORS; do + hi=$(( $x + 60 )) + s $x; p "$FILL"; s $hi; p "$FILL" +done +s; pn " Test for support of ForeHi colors" +p " " +for x in $FORE_COLORS; do + hi=$(( $x + 60 )) + s $x; p "$FILL"; s $x $hi; p "$FILL" +done +s; pn " Test for support of ForeHi colors (w/compat)" + +# BackHi +p " " +for x in $BACK_COLORS; do + hi=$(( $x + 60 )) + s $x; p "-"; s $hi; p "-" +done +s; pn " Test for support of BackHi colors" +p " " +for x in $BACK_COLORS; do + hi=$(( $x + 60 )) + s $x; p "-"; s $x $hi; p "-" +done +s; pn " Test for support of BackHi colors (w/compat)" + +pn + + + +### Identify the default fore and back colors. + +pn "Match default fore and back colors against 16-color palette" +pn " ==fore== ==back==" +for fore in $FORE_COLORS; do + forehi=$(( $fore + 60 )) + back=$(( $fore + 10 )) + backhi=$(( $back + 60 )) + p " " + s $fore; p "$FILL"; s; p "$FILL"; s $fore; p "$FILL"; s; p " " + s $forehi; p "$FILL"; s; p "$FILL"; s $forehi; p "$FILL"; s; p " " + s $back; p "-"; s; p "-"; s $back; p "-"; s; p " " + s $backhi; p "-"; s; p "-"; s $backhi; p "-"; s; p " " + pn " $fore $forehi $back $backhi" +done + +pn + + + +### Test coloring of rest-of-line. + +# +# When a new line is scrolled in, every cell in the line receives the +# current background color, which can be the default/transparent color. +# + +p "Newline with red background: usually no red -->"; s 41; pn +s; pn "This text is plain, but rest is red if scrolled -->" +s; p " "; s 41; printf '\033[1K'; s; printf '\033[1C'; pn "<-- red Erase-in-Line to beginning" +s; p "red Erase-in-Line to end -->"; s 41; printf '\033[0K'; s; pn +pn + + + +### Moving the cursor around does not change colors of anything. + +pn "Test modifying uncolored lines with a colored SGR:" +pn "aaaa" +pn +pn "____e" +s 31 42; printf '\033[4C\033[3A'; pn "bb" +pn "cccc" +pn "dddd" +s; pn + +pn "Test modifying colored+inverted+bold line with plain text:" +s 42 31 7 1; printf 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r'; +s; pn "This text is plain and followed by green-on-red -->" +pn + + + +### Full-width character overwriting + +pn 'Overwrite part of a full-width char with a half-width char' +p 'initial U+4000 ideographs -->'; s 31 42; p '䀀䀀'; s; pn +p 'write X to index #1 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[24G'; p X; s; pn +p 'write X to index #2 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[25G'; p X; s; pn +p 'write X to index #3 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[26G'; p X; s; pn +p 'write X to index #4 -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[27G'; p X; s; pn +pn + +pn 'Verify that Erase-in-Line can "fix" last char in line' +p 'original -->'; s 31 42; p '䀀䀀'; s; pn +p 'overwrite -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[30G'; p 'XXX'; s; pn +p 'overwrite + Erase-in-Line -->'; s 31 42; p '䀀䀀'; s 35 44; printf '\033[30G'; p 'XXX'; s; printf '\033[0K'; pn +p 'original -->'; s 31 42; p 'X䀀䀀'; s; pn +p 'overwrite -->'; s 31 42; p 'X䀀䀀'; s 35 44; printf '\033[30G'; p 'ーー'; s; pn +p 'overwrite + Erase-in-Line -->'; s 31 42; p 'X䀀䀀'; s 35 44; printf '\033[30G'; p 'ーー'; s; printf '\033[0K'; pn +pn diff --git a/src/libs/3rdparty/winpty/misc/font-notes.txt b/src/libs/3rdparty/winpty/misc/font-notes.txt new file mode 100644 index 00000000000..d4e36d8e25d --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/font-notes.txt @@ -0,0 +1,300 @@ +================================================================== +Notes regarding fonts, code pages, and East Asian character widths +================================================================== + + +Registry settings +================= + + * There are console registry settings in `HKCU\Console`. That key has many + default settings (e.g. the default font settings) and also per-app subkeys + for app-specific overrides. + + * It is possible to override the code page with an app-specific setting. + + * There are registry settings in + `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console`. In particular, + the `TrueTypeFont` subkey has a list of suitable font names associated with + various CJK code pages, as well as default font names. + + * There are two values in `HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage` + that specify the current code pages -- `OEMCP` and `ACP`. Setting the + system locale via the Control Panel's "Region" or "Language" dialogs seems + to change these code page values. + + +Console fonts +============= + + * The `FontFamily` field of `CONSOLE_FONT_INFOEX` has two parts: + - The high four bits can be exactly one of the `FF_xxxx` font families: + FF_DONTCARE(0x00) + FF_ROMAN(0x10) + FF_SWISS(0x20) + FF_MODERN(0x30) + FF_SCRIPT(0x40) + FF_DECORATIVE(0x50) + - The low four bits are a bitmask: + TMPF_FIXED_PITCH(1) -- actually means variable pitch + TMPF_VECTOR(2) + TMPF_TRUETYPE(4) + TMPF_DEVICE(8) + + * Each console has its own independent console font table. The current font + is identified with an index into this table. The size of the table is + returned by the undocumented `GetNumberOfConsoleFonts` API. It is apparently + possible to get the table size without this API, by instead calling + `GetConsoleFontSize` on each nonnegative index starting with 0 until the API + fails by returning (0, 0). + + * The font table grows dynamically. Each time the console is configured with + a previously-unused (FaceName, Size) combination, two entries are added to + the font table -- one with normal weight and one with bold weight. Fonts + added this way are always TrueType fonts. + + * Initially, the font table appears to contain only raster fonts. For + example, on an English Windows 8 installation, here is the initial font + table: + font 0: 4x6 + font 1: 6x8 + font 2: 8x8 + font 3: 16x8 + font 4: 5x12 + font 5: 7x12 + font 6: 8x12 -- the current font + font 7: 16x12 + font 8: 12x16 + font 9: 10x18 + `GetNumberOfConsoleFonts` returns 10, and this table matches the raster font + sizes according to the console properties dialog. + + * With a Japanese or Chinese locale, the initial font table appears to contain + the sizes applicable to both the East Asian raster font, as well as the + sizes for the CP437/CP1252 raster font. + + * The index passed to `SetCurrentConsoleFontEx` apparently has no effect. + The undocumented `SetConsoleFont` API, however, accepts *only* a font index, + and on Windows 8 English, it switches between all 10 fonts, even font index + #0. + + * If the index passed to `SetConsoleFont` identifies a Raster Font + incompatible with the current code page, then another Raster Font is + activated. + + * Passing "Terminal" to `SetCurrentConsoleFontEx` seems to have no effect. + Perhaps relatedly, `SetCurrentConsoleFontEx` does not fail if it is given a + bogus `FaceName`. Some font is still chosen and activated. Passing a face + name and height seems to work reliably, modulo the CP936 issue described + below. + + +Console fonts and code pages +============================ + + * On an English Windows installation, the default code page is 437, and it + cannot be set to 932 (Shift-JIS). (The API call fails.) Changing the + system locale to "Japanese (Japan)" using the Region/Language dialog + changes the default CP to 932 and permits changing the console CP between + 437 and 932. + + * A console has both an input code page and an output code page + (`{Get,Set}ConsoleCP` and `{Get,Set}ConsoleOutputCP`). I'm not going to + distinguish between the two for this document; presumably only the output + CP matters. The code page can change while the console is open, e.g. + by running `mode con: cp select={932,437,1252}` or by calling + `SetConsoleOutputCP`. + + * The current code page restricts which TrueType fonts and which Raster Font + sizes are available in the console properties dialog. This can change + while the console is open. + + * Changing the code page almost(?) always changes the current console font. + So far, I don't know how the new font is chosen. + + * With a CP of 932, the only TrueType font available in the console properties + dialog is "MS Gothic", displayed as "MS ゴシック". It is still possible to + use the English-default TrueType console fonts, Lucida Console and Consolas, + via `SetCurrentConsoleFontEx`. + + * When using a Raster Font and CP437 or CP1252, writing a UTF-16 codepoint not + representable in the code page instead writes a question mark ('?') to the + console. This conversion does not apply with a TrueType font, nor with the + Raster Font for CP932 or CP936. + + +ReadConsoleOutput and double-width characters +============================================== + + * With a Raster Font active, when `ReadConsoleOutputW` reads two cells of a + double-width character, it fills only a single `CHAR_INFO` structure. The + unused trailing `CHAR_INFO` structures are zero-filled. With a TrueType + font active, `ReadConsoleOutputW` instead fills two `CHAR_INFO` structures, + the first marked with `COMMON_LVB_LEADING_BYTE` and the second marked with + `COMMON_LVB_TRAILING_BYTE`. The flag is a misnomer--there aren't two + *bytes*, but two cells, and they have equal `CHAR_INFO.Char.UnicodeChar` + values. + + * `ReadConsoleOutputA`, on the other hand, reads two `CHAR_INFO` cells, and + if the UTF-16 value can be represented as two bytes in the ANSI/OEM CP, then + the two bytes are placed in the two `CHAR_INFO.Char.AsciiChar` values, and + the `COMMON_LVB_{LEADING,TRAILING}_BYTE` values are also used. If the + codepoint isn't representable, I don't remember what happens -- I think the + `AsciiChar` values take on an invalid marker. + + * Reading only one cell of a double-width character reads a space (U+0020) + instead. Raster-vs-TrueType and wide-vs-ANSI do not matter. + - XXX: what about attributes? Can a double-width character have mismatched + color attributes? + - XXX: what happens when writing to just one cell of a double-width + character? + + +Default Windows fonts for East Asian languages +============================================== +CP932 / Japanese: "MS ゴシック" (MS Gothic) +CP936 / Chinese Simplified: "新宋体" (SimSun) + + +Unreliable character width (half-width vs full-width) +===================================================== + +The half-width vs full-width status of a codepoint depends on at least these variables: + * OS version (Win10 legacy and new modes are different versions) + * system locale (English vs Japanese vs Chinese Simplified vs Chinese Traditional, etc) + * code page (437 vs 932 vs 936, etc) + * raster vs TrueType (Terminal vs MS Gothic vs SimSun, etc) + * font size + * rendered-vs-model (rendered width can be larger or smaller than model width) + +Example 1: U+2014 (EM DASH): East_Asian_Width: Ambiguous +-------------------------------------------------------- + rendered modeled +CP932: Win7/8 Raster Fonts half half +CP932: Win7/8 Gothic 14/15px half full +CP932: Win7/8 Consolas 14/15px half full +CP932: Win7/8 Lucida Console 14px half full +CP932: Win7/8 Lucida Console 15px half half +CP932: Win10New Raster Fonts half half +CP932: Win10New Gothic 14/15px half half +CP932: Win10New Consolas 14/15px half half +CP932: Win10New Lucida Console 14/15px half half + +CP936: Win7/8 Raster Fonts full full +CP936: Win7/8 SimSun 14px full full +CP936: Win7/8 SimSun 15px full half +CP936: Win7/8 Consolas 14/15px half full +CP936: Win10New Raster Fonts full full +CP936: Win10New SimSum 14/15px full full +CP936: Win10New Consolas 14/15px half half + +Example 2: U+3044 (HIRAGANA LETTER I): East_Asian_Width: Wide +------------------------------------------------------------- + rendered modeled +CP932: Win7/8/10N Raster Fonts full full +CP932: Win7/8/10N Gothic 14/15px full full +CP932: Win7/8/10N Consolas 14/15px half(*2) full +CP932: Win7/8/10N Lucida Console 14/15px half(*3) full + +CP936: Win7/8/10N Raster Fonts full full +CP936: Win7/8/10N SimSun 14/15px full full +CP936: Win7/8/10N Consolas 14/15px full full + +Example 3: U+30FC (KATAKANA-HIRAGANA PROLONGED SOUND MARK): East_Asian_Width: Wide +---------------------------------------------------------------------------------- + rendered modeled +CP932: Win7 Raster Fonts full full +CP932: Win7 Gothic 14/15px full full +CP932: Win7 Consolas 14/15px half(*2) full +CP932: Win7 Lucida Console 14px half(*3) full +CP932: Win7 Lucida Console 15px half(*3) half +CP932: Win8 Raster Fonts full full +CP932: Win8 Gothic 14px full half +CP932: Win8 Gothic 15px full full +CP932: Win8 Consolas 14/15px half(*2) full +CP932: Win8 Lucida Console 14px half(*3) full +CP932: Win8 Lucida Console 15px half(*3) half +CP932: Win10New Raster Fonts full full +CP932: Win10New Gothic 14/15px full full +CP932: Win10New Consolas 14/15px half(*2) half +CP932: Win10New Lucida Console 14/15px half(*2) half + +CP936: Win7/8 Raster Fonts full full +CP936: Win7/8 SimSun 14px full full +CP936: Win7/8 SimSun 15px full half +CP936: Win7/8 Consolas 14px full full +CP936: Win7/8 Consolas 15px full half +CP936: Win10New Raster Fonts full full +CP936: Win10New SimSum 14/15px full full +CP936: Win10New Consolas 14/15px full full + +Example 4: U+4000 (CJK UNIFIED IDEOGRAPH-4000): East_Asian_Width: Wide +---------------------------------------------------------------------- + rendered modeled +CP932: Win7 Raster Fonts half(*1) half +CP932: Win7 Gothic 14/15px full full +CP932: Win7 Consolas 14/15px half(*2) full +CP932: Win7 Lucida Console 14px half(*3) full +CP932: Win7 Lucida Console 15px half(*3) half +CP932: Win8 Raster Fonts half(*1) half +CP932: Win8 Gothic 14px full half +CP932: Win8 Gothic 15px full full +CP932: Win8 Consolas 14/15px half(*2) full +CP932: Win8 Lucida Console 14px half(*3) full +CP932: Win8 Lucida Console 15px half(*3) half +CP932: Win10New Raster Fonts half(*1) half +CP932: Win10New Gothic 14/15px full full +CP932: Win10New Consolas 14/15px half(*2) half +CP932: Win10New Lucida Console 14/15px half(*2) half + +CP936: Win7/8 Raster Fonts full full +CP936: Win7/8 SimSun 14px full full +CP936: Win7/8 SimSun 15px full half +CP936: Win7/8 Consolas 14px full full +CP936: Win7/8 Consolas 15px full half +CP936: Win10New Raster Fonts full full +CP936: Win10New SimSum 14/15px full full +CP936: Win10New Consolas 14/15px full full + +(*1) Rendered as a half-width filled white box +(*2) Rendered as a half-width box with a question mark inside +(*3) Rendered as a half-width empty box +(!!) One of the only places in Win10New where rendered and modeled width disagree + + +Windows quirk: unreliable font heights with CP936 / Chinese Simplified +====================================================================== + +When I set the font to 新宋体 17px, using either the properties dialog or +`SetCurrentConsoleFontEx`, the height reported by `GetCurrentConsoleFontEx` is +not 17, but is instead 19. The same problem does not affect Raster Fonts, +nor have I seen the problem in the English or Japanese locales. I observed +this with Windows 7 and Windows 10 new mode. + +If I set the font using the facename, width, *and* height, then the +`SetCurrentConsoleFontEx` and `GetCurrentConsoleFontEx` values agree. If I +set the font using *only* the facename and height, then the two values +disagree. + + +Windows bug: GetCurrentConsoleFontEx is initially invalid +========================================================= + + - Assume there is no configured console font name in the registry. In this + case, the console defaults to a raster font. + - Open a new console and call the `GetCurrentConsoleFontEx` API. + - The `FaceName` field of the returned `CONSOLE_FONT_INFOEX` data + structure is incorrect. On Windows 7, 8, and 10, I observed that the + field was blank. On Windows 8, occasionally, it instead contained: + U+AE72 U+75BE U+0001 + The other fields of the structure all appeared correct: + nFont=6 dwFontSize=(8,12) FontFamily=0x30 FontWeight=400 + - The `FaceName` field becomes initialized easily: + - Open the console properties dialog and click OK. (Cancel is not + sufficient.) + - Call the undocumented `SetConsoleFont` with the current font table + index, which is 6 in the example above. + - It seems that the console uncritically accepts whatever string is + stored in the registry, including a blank string, and passes it on the + the `GetCurrentConsoleFontEx` caller. It is possible to get the console + to *write* a blank setting into the registry -- simply open the console + (default or app-specific) properties and click OK. diff --git a/src/libs/3rdparty/winpty/misc/winbug-15048.cc b/src/libs/3rdparty/winpty/misc/winbug-15048.cc new file mode 100644 index 00000000000..0e98d648c54 --- /dev/null +++ b/src/libs/3rdparty/winpty/misc/winbug-15048.cc @@ -0,0 +1,201 @@ +/* + +Test program demonstrating a problem in Windows 15048's ReadConsoleOutput API. + +To compile: + + cl /nologo /EHsc winbug-15048.cc shell32.lib + +Example of regressed input: + +Case 1: + + > chcp 932 + > winbug-15048 -face-gothic 3044 + + Correct output: + + 1**34 (nb: U+3044 replaced with '**' to avoid MSVC encoding warning) + 5678 + + ReadConsoleOutputW (both rows, 3 cols) + row 0: U+0031(0007) U+3044(0107) U+3044(0207) U+0033(0007) + row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) + + ReadConsoleOutputW (both rows, 4 cols) + row 0: U+0031(0007) U+3044(0107) U+3044(0207) U+0033(0007) U+0034(0007) + row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007) + + ReadConsoleOutputW (second row) + row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007) + + ... + + Win10 15048 bad output: + + 1**34 + 5678 + + ReadConsoleOutputW (both rows, 3 cols) + row 0: U+0031(0007) U+3044(0007) U+0033(0007) U+0035(0007) + row 1: U+0036(0007) U+0037(0007) U+0038(0007) U+0000(0000) + + ReadConsoleOutputW (both rows, 4 cols) + row 0: U+0031(0007) U+3044(0007) U+0033(0007) U+0034(0007) U+0035(0007) + row 1: U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007) U+0000(0000) + + ReadConsoleOutputW (second row) + row 1: U+0035(0007) U+0036(0007) U+0037(0007) U+0038(0007) U+0020(0007) + + ... + + The U+3044 character (HIRAGANA LETTER I) occupies two columns, but it only + fills one record in the ReadConsoleOutput output buffer, which has the + effect of shifting the first cell of the second row into the last cell of + the first row. Ordinarily, the first and second cells would also have the + COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE attributes set, which + allows winpty to detect the double-column character. + +Case 2: + + > chcp 437 + > winbug-15048 -face "Lucida Console" -h 4 221A + + The same issue happens with U+221A (SQUARE ROOT), but only in certain + fonts. The console seems to think this character occupies two columns + if the font is sufficiently small. The Windows console properties dialog + doesn't allow fonts below 5 pt, but winpty tries to use 2pt and 4pt Lucida + Console to allow very large console windows. + +Case 3: + + > chcp 437 + > winbug-15048 -face "Lucida Console" -h 12 FF12 + + The console selection system thinks U+FF12 (FULLWIDTH DIGIT TWO) occupies + two columns, which happens to be correct, but it's displayed as a single + column unrecognized character. It otherwise behaves the same as the other + cases. + +*/ + +#include +#include +#include +#include +#include +#include + +#include + +#define COUNT_OF(array) (sizeof(array) / sizeof((array)[0])) + +// See https://en.wikipedia.org/wiki/List_of_CJK_fonts +const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // Japanese +const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // Simplified Chinese +const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // Traditional Chinese +const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // Korean + +static void set_font(const wchar_t *name, int size) { + const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_FONT_INFOEX fontex {}; + fontex.cbSize = sizeof(fontex); + fontex.dwFontSize.Y = size; + fontex.FontWeight = 400; + fontex.FontFamily = 0x36; + wcsncpy(fontex.FaceName, name, COUNT_OF(fontex.FaceName)); + assert(SetCurrentConsoleFontEx(conout, FALSE, &fontex)); +} + +static void usage(const wchar_t *prog) { + printf("Usage: %ls [options]\n", prog); + printf(" -h HEIGHT\n"); + printf(" -face FACENAME\n"); + printf(" -face-{gothic|simsun|minglight|gulimche) [JP,CN-sim,CN-tra,KR]\n"); + printf(" hhhh -- print U+hhhh\n"); + exit(1); +} + +static void dump_region(SMALL_RECT region, const char *name) { + const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + + CHAR_INFO buf[1000]; + memset(buf, 0xcc, sizeof(buf)); + + const int w = region.Right - region.Left + 1; + const int h = region.Bottom - region.Top + 1; + + assert(ReadConsoleOutputW( + conout, buf, { (short)w, (short)h }, { 0, 0 }, + ®ion)); + + printf("\n"); + printf("ReadConsoleOutputW (%s)\n", name); + for (int y = 0; y < h; ++y) { + printf("row %d: ", region.Top + y); + for (int i = 0; i < region.Left * 13; ++i) { + printf(" "); + } + for (int x = 0; x < w; ++x) { + const int i = y * w + x; + printf("U+%04x(%04x) ", buf[i].Char.UnicodeChar, buf[i].Attributes); + } + printf("\n"); + } +} + +int main() { + wchar_t *cmdline = GetCommandLineW(); + int argc = 0; + wchar_t **argv = CommandLineToArgvW(cmdline, &argc); + const wchar_t *font_name = L"Lucida Console"; + int font_height = 8; + int test_ch = 0xff12; // U+FF12 FULLWIDTH DIGIT TWO + + for (int i = 1; i < argc; ++i) { + const std::wstring arg = argv[i]; + const std::wstring next = i + 1 < argc ? argv[i + 1] : L""; + if (arg == L"-face" && i + 1 < argc) { + font_name = argv[i + 1]; + i++; + } else if (arg == L"-face-gothic") { + font_name = kMSGothic; + } else if (arg == L"-face-simsun") { + font_name = kNSimSun; + } else if (arg == L"-face-minglight") { + font_name = kMingLight; + } else if (arg == L"-face-gulimche") { + font_name = kGulimChe; + } else if (arg == L"-h" && i + 1 < argc) { + font_height = _wtoi(next.c_str()); + i++; + } else if (arg.c_str()[0] != '-') { + test_ch = wcstol(arg.c_str(), NULL, 16); + } else { + printf("Unrecognized argument: %ls\n", arg.c_str()); + usage(argv[0]); + } + } + + const HANDLE conout = GetStdHandle(STD_OUTPUT_HANDLE); + + set_font(font_name, font_height); + + system("cls"); + DWORD actual = 0; + wchar_t output[] = L"1234\n5678\n"; + output[1] = test_ch; + WriteConsoleW(conout, output, 10, &actual, nullptr); + + dump_region({ 0, 0, 3, 1 }, "both rows, 3 cols"); + dump_region({ 0, 0, 4, 1 }, "both rows, 4 cols"); + dump_region({ 0, 1, 4, 1 }, "second row"); + dump_region({ 0, 0, 4, 0 }, "first row"); + dump_region({ 1, 0, 4, 0 }, "first row, skip 1"); + dump_region({ 2, 0, 4, 0 }, "first row, skip 2"); + dump_region({ 3, 0, 4, 0 }, "first row, skip 3"); + + set_font(font_name, 14); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat b/src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat new file mode 100644 index 00000000000..b6bca7b0793 --- /dev/null +++ b/src/libs/3rdparty/winpty/ship/build-pty4j-libpty.bat @@ -0,0 +1,36 @@ +@echo off + +setlocal +cd %~dp0.. +set Path=C:\Python27;C:\Program Files\Git\cmd;%Path% + +call "%VS140COMNTOOLS%\VsDevCmd.bat" || goto :fail + +rmdir /s/q build-libpty 2>NUL +mkdir build-libpty\win +mkdir build-libpty\win\x86 +mkdir build-libpty\win\x86_64 +mkdir build-libpty\win\xp + +rmdir /s/q src\Release 2>NUL +rmdir /s/q src\.vs 2>NUL +del src\*.vcxproj src\*.vcxproj.filters src\*.sln src\*.sdf 2>NUL + +call vcbuild.bat --msvc-platform Win32 --gyp-msvs-version 2015 --toolset v140_xp || goto :fail +copy src\Release\Win32\winpty.dll build-libpty\win\xp || goto :fail +copy src\Release\Win32\winpty-agent.exe build-libpty\win\xp || goto :fail + +call vcbuild.bat --msvc-platform Win32 --gyp-msvs-version 2015 || goto :fail +copy src\Release\Win32\winpty.dll build-libpty\win\x86 || goto :fail +copy src\Release\Win32\winpty-agent.exe build-libpty\win\x86 || goto :fail + +call vcbuild.bat --msvc-platform x64 --gyp-msvs-version 2015 || goto :fail +copy src\Release\x64\winpty.dll build-libpty\win\x86_64 || goto :fail +copy src\Release\x64\winpty-agent.exe build-libpty\win\x86_64 || goto :fail + +echo success +goto :EOF + +:fail +echo error: build failed +exit /b 1 diff --git a/src/libs/3rdparty/winpty/ship/common_ship.py b/src/libs/3rdparty/winpty/ship/common_ship.py new file mode 100644 index 00000000000..b587ac7ce11 --- /dev/null +++ b/src/libs/3rdparty/winpty/ship/common_ship.py @@ -0,0 +1,89 @@ +import os +import sys + +# These scripts need to continue using Python 2 rather than 3, because +# make_msvc_package.py puts the current Python interpreter on the PATH for the +# sake of gyp, and gyp doesn't work with Python 3 yet. +# https://bugs.chromium.org/p/gyp/issues/detail?id=36 +if os.name != "nt": + sys.exit("Error: ship scripts require native Python 2.7. (wrong os.name)") +if sys.version_info[0:2] != (2,7): + sys.exit("Error: ship scripts require native Python 2.7. (wrong version)") + +import glob +import hashlib +import shutil +import subprocess +from distutils.spawn import find_executable + +topDir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + +with open(topDir + "/VERSION.txt", "rt") as f: + winptyVersion = f.read().strip() + +def rmrf(patterns): + for pattern in patterns: + for path in glob.glob(pattern): + if os.path.isdir(path) and not os.path.islink(path): + print("+ rm -r " + path) + sys.stdout.flush() + shutil.rmtree(path) + elif os.path.isfile(path): + print("+ rm " + path) + sys.stdout.flush() + os.remove(path) + +def mkdir(path): + if not os.path.isdir(path): + os.makedirs(path) + +def requireExe(name, guesses): + if find_executable(name) is None: + for guess in guesses: + if os.path.exists(guess): + newDir = os.path.dirname(guess) + print("Adding " + newDir + " to Path to provide " + name) + os.environ["Path"] = newDir + ";" + os.environ["Path"] + ret = find_executable(name) + if ret is None: + sys.exit("Error: required EXE is missing from Path: " + name) + return ret + +class ModifyEnv: + def __init__(self, **kwargs): + self._changes = dict(kwargs) + self._original = dict() + + def __enter__(self): + for var, val in self._changes.items(): + self._original[var] = os.environ[var] + os.environ[var] = val + + def __exit__(self, type, value, traceback): + for var, val in self._original.items(): + os.environ[var] = val + +def sha256(path): + with open(path, "rb") as fp: + return hashlib.sha256(fp.read()).hexdigest() + +def checkSha256(path, expected): + actual = sha256(path) + if actual != expected: + sys.exit("error: sha256 hash mismatch on {}: expected {}, found {}".format( + path, expected, actual)) + +requireExe("git.exe", [ + "C:\\Program Files\\Git\\cmd\\git.exe", + "C:\\Program Files (x86)\\Git\\cmd\\git.exe" +]) + +commitHash = subprocess.check_output(["git.exe", "rev-parse", "HEAD"]).strip() +defaultPathEnviron = "C:\\Windows\\System32;C:\\Windows" + +ZIP_TOOL = requireExe("7z.exe", [ + "C:\\Program Files\\7-Zip\\7z.exe", + "C:\\Program Files (x86)\\7-Zip\\7z.exe", +]) + +requireExe("curl.exe", []) diff --git a/src/libs/3rdparty/winpty/ship/make_msvc_package.py b/src/libs/3rdparty/winpty/ship/make_msvc_package.py new file mode 100644 index 00000000000..2d10aac7878 --- /dev/null +++ b/src/libs/3rdparty/winpty/ship/make_msvc_package.py @@ -0,0 +1,163 @@ +#!python + +# Copyright (c) 2016 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# +# Run with native CPython 2.7. +# +# This script looks for MSVC using a version-specific environment variable, +# such as VS140COMNTOOLS for MSVC 2015. +# + +import common_ship + +import argparse +import os +import shutil +import subprocess +import sys + +os.chdir(common_ship.topDir) + +MSVC_VERSION_TABLE = { + "2015" : { + "package_name" : "msvc2015", + "gyp_version" : "2015", + "common_tools_env" : "VS140COMNTOOLS", + "xp_toolset" : "v140_xp", + }, + "2013" : { + "package_name" : "msvc2013", + "gyp_version" : "2013", + "common_tools_env" : "VS120COMNTOOLS", + "xp_toolset" : "v120_xp", + }, +} + +ARCH_TABLE = { + "x64" : { + "msvc_platform" : "x64", + }, + "ia32" : { + "msvc_platform" : "Win32", + }, +} + +def readArguments(): + parser = argparse.ArgumentParser() + parser.add_argument("--msvc-version", default="2015") + ret = parser.parse_args() + if ret.msvc_version not in MSVC_VERSION_TABLE: + sys.exit("Error: unrecognized version: " + ret.msvc_version + ". " + + "Versions: " + " ".join(sorted(MSVC_VERSION_TABLE.keys()))) + return ret + +ARGS = readArguments() + +def checkoutGyp(): + if os.path.isdir("build-gyp"): + return + subprocess.check_call([ + "git.exe", + "clone", + "https://chromium.googlesource.com/external/gyp", + "build-gyp" + ]) + +def cleanMsvc(): + common_ship.rmrf(""" + src/Release src/.vs src/gen + src/*.vcxproj src/*.vcxproj.filters src/*.sln src/*.sdf + """.split()) + +def build(arch, packageDir, xp=False): + archInfo = ARCH_TABLE[arch] + versionInfo = MSVC_VERSION_TABLE[ARGS.msvc_version] + + devCmdPath = os.path.join(os.environ[versionInfo["common_tools_env"]], "VsDevCmd.bat") + if not os.path.isfile(devCmdPath): + sys.exit("Error: MSVC environment script missing: " + devCmdPath) + + toolsetArgument = " --toolset {}".format(versionInfo["xp_toolset"]) if xp else "" + newEnv = os.environ.copy() + newEnv["PATH"] = os.path.dirname(sys.executable) + ";" + common_ship.defaultPathEnviron + commandLine = ( + '"' + devCmdPath + '" && ' + + " vcbuild.bat" + + " --gyp-msvs-version " + versionInfo["gyp_version"] + + " --msvc-platform " + archInfo["msvc_platform"] + + " --commit-hash " + common_ship.commitHash + + toolsetArgument + ) + + subprocess.check_call(commandLine, shell=True, env=newEnv) + + archPackageDir = os.path.join(packageDir, arch) + if xp: + archPackageDir += "_xp" + + common_ship.mkdir(archPackageDir + "/bin") + common_ship.mkdir(archPackageDir + "/lib") + + binSrc = os.path.join(common_ship.topDir, "src/Release", archInfo["msvc_platform"]) + + shutil.copy(binSrc + "/winpty.dll", archPackageDir + "/bin") + shutil.copy(binSrc + "/winpty-agent.exe", archPackageDir + "/bin") + shutil.copy(binSrc + "/winpty-debugserver.exe", archPackageDir + "/bin") + shutil.copy(binSrc + "/winpty.lib", archPackageDir + "/lib") + +def buildPackage(): + versionInfo = MSVC_VERSION_TABLE[ARGS.msvc_version] + + packageName = "winpty-%s-%s" % ( + common_ship.winptyVersion, + versionInfo["package_name"], + ) + + packageRoot = os.path.join(common_ship.topDir, "ship/packages") + packageDir = os.path.join(packageRoot, packageName) + packageFile = packageDir + ".zip" + + common_ship.rmrf([packageDir]) + common_ship.rmrf([packageFile]) + common_ship.mkdir(packageDir) + + checkoutGyp() + cleanMsvc() + build("ia32", packageDir, True) + build("x64", packageDir, True) + cleanMsvc() + build("ia32", packageDir) + build("x64", packageDir) + + topDir = common_ship.topDir + + common_ship.mkdir(packageDir + "/include") + shutil.copy(topDir + "/src/include/winpty.h", packageDir + "/include") + shutil.copy(topDir + "/src/include/winpty_constants.h", packageDir + "/include") + shutil.copy(topDir + "/LICENSE", packageDir) + shutil.copy(topDir + "/README.md", packageDir) + shutil.copy(topDir + "/RELEASES.md", packageDir) + + subprocess.check_call([common_ship.ZIP_TOOL, "a", packageFile, "."], cwd=packageDir) + +if __name__ == "__main__": + buildPackage() diff --git a/src/libs/3rdparty/winpty/ship/ship.py b/src/libs/3rdparty/winpty/ship/ship.py new file mode 100644 index 00000000000..44f5862e3eb --- /dev/null +++ b/src/libs/3rdparty/winpty/ship/ship.py @@ -0,0 +1,104 @@ +#!python + +# Copyright (c) 2015 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# +# Run with native CPython 2.7 on a 64-bit computer. +# + +import common_ship + +from optparse import OptionParser +import multiprocessing +import os +import shutil +import subprocess +import sys + + +def dllVersion(path): + version = subprocess.check_output( + ["powershell.exe", + "[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"" + path + "\").FileVersion"]) + return version.strip() + + +os.chdir(common_ship.topDir) + + +# Determine other build parameters. +BUILD_KINDS = { + "cygwin": { + "path": ["bin"], + "dll": "bin\\cygwin1.dll", + }, + "msys2": { + "path": ["opt\\bin", "usr\\bin"], + "dll": "usr\\bin\\msys-2.0.dll", + }, +} + + +def buildTarget(kind, syspath, arch): + + binPaths = [os.path.join(syspath, p) for p in BUILD_KINDS[kind]["path"]] + binPaths += common_ship.defaultPathEnviron.split(";") + newPath = ";".join(binPaths) + + dllver = dllVersion(os.path.join(syspath, BUILD_KINDS[kind]["dll"])) + packageName = "winpty-{}-{}-{}-{}".format(common_ship.winptyVersion, kind, dllver, arch) + if os.path.exists("ship\\packages\\" + packageName): + shutil.rmtree("ship\\packages\\" + packageName) + + print("+ Setting PATH to: {}".format(newPath)) + with common_ship.ModifyEnv(PATH=newPath): + subprocess.check_call(["sh.exe", "configure"]) + subprocess.check_call(["make.exe", "clean"]) + makeBaseCmd = [ + "make.exe", + "COMMIT_HASH=" + common_ship.commitHash, + "PREFIX=ship/packages/" + packageName + ] + subprocess.check_call(makeBaseCmd + ["all", "tests", "-j%d" % multiprocessing.cpu_count()]) + subprocess.check_call(["build\\trivial_test.exe"]) + subprocess.check_call(makeBaseCmd + ["install"]) + subprocess.check_call(["tar.exe", "cvfz", + packageName + ".tar.gz", + packageName], cwd=os.path.join(os.getcwd(), "ship", "packages")) + + +def main(): + parser = OptionParser() + parser.add_option("--kind", type="choice", choices=["cygwin", "msys2"]) + parser.add_option("--syspath") + parser.add_option("--arch", type="choice", choices=["ia32", "x64"]) + (args, extra) = parser.parse_args() + + args.kind or parser.error("--kind must be specified") + args.arch or parser.error("--arch must be specified") + args.syspath or parser.error("--syspath must be specified") + extra and parser.error("unexpected positional argument(s)") + + buildTarget(args.kind, args.syspath, args.arch) + + +if __name__ == "__main__": + main() diff --git a/src/libs/3rdparty/winpty/src/CMakeLists.txt b/src/libs/3rdparty/winpty/src/CMakeLists.txt new file mode 100644 index 00000000000..5763955e8d0 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/CMakeLists.txt @@ -0,0 +1,112 @@ +if (MSVC) + add_compile_definitions(NOMINMAX UNICODE _UNICODE) +endif() + +file(WRITE ${CMAKE_BINARY_DIR}/GenVersion.h.in [=[ +const char GenVersion_Version[] = "@VERSION@"; +const char GenVersion_Commit[] = "@COMMIT_HASH@"; +]=]) + +file(READ ../VERSION.txt VERSION) +string(REPLACE "\n" "" VERSION "${VERSION}") +configure_file(${CMAKE_BINARY_DIR}/GenVersion.h.in ${CMAKE_BINARY_DIR}/GenVersion.h @ONLY) + +set(shared_sources + shared/AgentMsg.h + shared/BackgroundDesktop.h + shared/BackgroundDesktop.cc + shared/Buffer.h + shared/Buffer.cc + shared/DebugClient.h + shared/DebugClient.cc + shared/GenRandom.h + shared/GenRandom.cc + shared/OsModule.h + shared/OwnedHandle.h + shared/OwnedHandle.cc + shared/StringBuilder.h + shared/StringUtil.cc + shared/StringUtil.h + shared/UnixCtrlChars.h + shared/WindowsSecurity.cc + shared/WindowsSecurity.h + shared/WindowsVersion.h + shared/WindowsVersion.cc + shared/WinptyAssert.h + shared/WinptyAssert.cc + shared/WinptyException.h + shared/WinptyException.cc + shared/WinptyVersion.h + shared/WinptyVersion.cc + shared/winpty_snprintf.h +) + +# +# winpty-agent +# + +add_qtc_executable(winpty-agent + DESTINATION ${IDE_PLUGIN_PATH} + INCLUDES + include ${CMAKE_BINARY_DIR} + DEFINES WINPTY_AGENT_ASSERT + PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON + SOURCES + agent/Agent.h + agent/Agent.cc + agent/AgentCreateDesktop.h + agent/AgentCreateDesktop.cc + agent/ConsoleFont.cc + agent/ConsoleFont.h + agent/ConsoleInput.cc + agent/ConsoleInput.h + agent/ConsoleInputReencoding.cc + agent/ConsoleInputReencoding.h + agent/ConsoleLine.cc + agent/ConsoleLine.h + agent/Coord.h + agent/DebugShowInput.h + agent/DebugShowInput.cc + agent/DefaultInputMap.h + agent/DefaultInputMap.cc + agent/DsrSender.h + agent/EventLoop.h + agent/EventLoop.cc + agent/InputMap.h + agent/InputMap.cc + agent/LargeConsoleRead.h + agent/LargeConsoleRead.cc + agent/NamedPipe.h + agent/NamedPipe.cc + agent/Scraper.h + agent/Scraper.cc + agent/SimplePool.h + agent/SmallRect.h + agent/Terminal.h + agent/Terminal.cc + agent/UnicodeEncoding.h + agent/Win32Console.cc + agent/Win32Console.h + agent/Win32ConsoleBuffer.cc + agent/Win32ConsoleBuffer.h + agent/main.cc + ${shared_sources} +) + +# +# libwinpty +# + +add_qtc_library(winpty STATIC + INCLUDES ${CMAKE_BINARY_DIR} + PUBLIC_DEFINES COMPILING_WINPTY_DLL + PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON + SOURCES + libwinpty/AgentLocation.cc + libwinpty/AgentLocation.h + libwinpty/winpty.cc + ${shared_sources} +) + +target_include_directories(winpty + PUBLIC $) diff --git a/src/libs/3rdparty/winpty/src/agent/Agent.cc b/src/libs/3rdparty/winpty/src/agent/Agent.cc new file mode 100644 index 00000000000..986edead133 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Agent.cc @@ -0,0 +1,612 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "Agent.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../include/winpty_constants.h" + +#include "../shared/AgentMsg.h" +#include "../shared/Buffer.h" +#include "../shared/DebugClient.h" +#include "../shared/GenRandom.h" +#include "../shared/StringBuilder.h" +#include "../shared/StringUtil.h" +#include "../shared/WindowsVersion.h" +#include "../shared/WinptyAssert.h" + +#include "ConsoleFont.h" +#include "ConsoleInput.h" +#include "NamedPipe.h" +#include "Scraper.h" +#include "Terminal.h" +#include "Win32ConsoleBuffer.h" + +namespace { + +static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) +{ + if (dwCtrlType == CTRL_C_EVENT) { + // Do nothing and claim to have handled the event. + return TRUE; + } + return FALSE; +} + +// We can detect the new Windows 10 console by observing the effect of the +// Mark command. In older consoles, Mark temporarily moves the cursor to the +// top-left of the console window. In the new console, the cursor isn't +// initially moved. +// +// We might like to use Mark to freeze the console, but we can't, because when +// the Mark command ends, the console moves the cursor back to its starting +// point, even if the console application has moved it in the meantime. +static void detectNewWindows10Console( + Win32Console &console, Win32ConsoleBuffer &buffer) +{ + if (!isAtLeastWindows8()) { + return; + } + + ConsoleScreenBufferInfo info = buffer.bufferInfo(); + + // Make sure the window isn't 1x1. AFAIK, this should never happen + // accidentally. It is difficult to make it happen deliberately. + if (info.srWindow.Left == info.srWindow.Right && + info.srWindow.Top == info.srWindow.Bottom) { + trace("detectNewWindows10Console: Initial console window was 1x1 -- " + "expanding for test"); + setSmallFont(buffer.conout(), 400, false); + buffer.moveWindow(SmallRect(0, 0, 1, 1)); + buffer.resizeBuffer(Coord(400, 1)); + buffer.moveWindow(SmallRect(0, 0, 2, 1)); + // This use of GetLargestConsoleWindowSize ought to be unnecessary + // given the behavior I've seen from moveWindow(0, 0, 1, 1), but + // I'd like to be especially sure, considering that this code will + // rarely be tested. + const auto largest = GetLargestConsoleWindowSize(buffer.conout()); + buffer.moveWindow( + SmallRect(0, 0, std::min(largest.X, buffer.bufferSize().X), 1)); + info = buffer.bufferInfo(); + ASSERT(info.srWindow.Right > info.srWindow.Left && + "Could not expand console window from 1x1"); + } + + // Test whether MARK moves the cursor. + const Coord initialPosition(info.srWindow.Right, info.srWindow.Bottom); + buffer.setCursorPosition(initialPosition); + ASSERT(!console.frozen()); + console.setFreezeUsesMark(true); + console.setFrozen(true); + const bool isNewW10 = (buffer.cursorPosition() == initialPosition); + console.setFrozen(false); + buffer.setCursorPosition(Coord(0, 0)); + + trace("Attempting to detect new Windows 10 console using MARK: %s", + isNewW10 ? "detected" : "not detected"); + console.setFreezeUsesMark(false); + console.setNewW10(isNewW10); +} + +static inline WriteBuffer newPacket() { + WriteBuffer packet; + packet.putRawValue(0); // Reserve space for size. + return packet; +} + +static HANDLE duplicateHandle(HANDLE h) { + HANDLE ret = nullptr; + if (!DuplicateHandle( + GetCurrentProcess(), h, + GetCurrentProcess(), &ret, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + ASSERT(false && "DuplicateHandle failed!"); + } + return ret; +} + +// It's safe to truncate a handle from 64-bits to 32-bits, or to sign-extend it +// back to 64-bits. See the MSDN article, "Interprocess Communication Between +// 32-bit and 64-bit Applications". +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203.aspx +static int64_t int64FromHandle(HANDLE h) { + return static_cast(reinterpret_cast(h)); +} + +} // anonymous namespace + +Agent::Agent(LPCWSTR controlPipeName, + uint64_t agentFlags, + int mouseMode, + int initialCols, + int initialRows) : + m_useConerr((agentFlags & WINPTY_FLAG_CONERR) != 0), + m_plainMode((agentFlags & WINPTY_FLAG_PLAIN_OUTPUT) != 0), + m_mouseMode(mouseMode) +{ + trace("Agent::Agent entered"); + + ASSERT(initialCols >= 1 && initialRows >= 1); + initialCols = std::min(initialCols, MAX_CONSOLE_WIDTH); + initialRows = std::min(initialRows, MAX_CONSOLE_HEIGHT); + + const bool outputColor = + !m_plainMode || (agentFlags & WINPTY_FLAG_COLOR_ESCAPES); + const Coord initialSize(initialCols, initialRows); + + auto primaryBuffer = openPrimaryBuffer(); + if (m_useConerr) { + m_errorBuffer = Win32ConsoleBuffer::createErrorBuffer(); + } + + detectNewWindows10Console(m_console, *primaryBuffer); + + m_controlPipe = &connectToControlPipe(controlPipeName); + m_coninPipe = &createDataServerPipe(false, L"conin"); + m_conoutPipe = &createDataServerPipe(true, L"conout"); + if (m_useConerr) { + m_conerrPipe = &createDataServerPipe(true, L"conerr"); + } + + // Send an initial response packet to winpty.dll containing pipe names. + { + auto setupPacket = newPacket(); + setupPacket.putWString(m_coninPipe->name()); + setupPacket.putWString(m_conoutPipe->name()); + if (m_useConerr) { + setupPacket.putWString(m_conerrPipe->name()); + } + writePacket(setupPacket); + } + + std::unique_ptr primaryTerminal; + primaryTerminal.reset(new Terminal(*m_conoutPipe, + m_plainMode, + outputColor)); + m_primaryScraper.reset(new Scraper(m_console, + *primaryBuffer, + std::move(primaryTerminal), + initialSize)); + if (m_useConerr) { + std::unique_ptr errorTerminal; + errorTerminal.reset(new Terminal(*m_conerrPipe, + m_plainMode, + outputColor)); + m_errorScraper.reset(new Scraper(m_console, + *m_errorBuffer, + std::move(errorTerminal), + initialSize)); + } + + m_console.setTitle(m_currentTitle); + + const HANDLE conin = GetStdHandle(STD_INPUT_HANDLE); + m_consoleInput.reset( + new ConsoleInput(conin, m_mouseMode, *this, m_console)); + + // Setup Ctrl-C handling. First restore default handling of Ctrl-C. This + // attribute is inherited by child processes. Then register a custom + // Ctrl-C handler that does nothing. The handler will be called when the + // agent calls GenerateConsoleCtrlEvent. + SetConsoleCtrlHandler(NULL, FALSE); + SetConsoleCtrlHandler(consoleCtrlHandler, TRUE); + + setPollInterval(25); +} + +Agent::~Agent() +{ + trace("Agent::~Agent entered"); + agentShutdown(); + if (m_childProcess != NULL) { + CloseHandle(m_childProcess); + } +} + +// Write a "Device Status Report" command to the terminal. The terminal will +// reply with a row+col escape sequence. Presumably, the DSR reply will not +// split a keypress escape sequence, so it should be safe to assume that the +// bytes before it are complete keypresses. +void Agent::sendDsr() +{ + if (!m_plainMode && !m_conoutPipe->isClosed()) { + m_conoutPipe->write("\x1B[6n"); + } +} + +NamedPipe &Agent::connectToControlPipe(LPCWSTR pipeName) +{ + NamedPipe &pipe = createNamedPipe(); + pipe.connectToServer(pipeName, NamedPipe::OpenMode::Duplex); + pipe.setReadBufferSize(64 * 1024); + return pipe; +} + +// Returns a new server named pipe. It has not yet been connected. +NamedPipe &Agent::createDataServerPipe(bool write, const wchar_t *kind) +{ + const auto name = + (WStringBuilder(128) + << L"\\\\.\\pipe\\winpty-" + << kind << L'-' + << GenRandom().uniqueName()).str_moved(); + NamedPipe &pipe = createNamedPipe(); + pipe.openServerPipe( + name.c_str(), + write ? NamedPipe::OpenMode::Writing + : NamedPipe::OpenMode::Reading, + write ? 8192 : 0, + write ? 0 : 256); + if (!write) { + pipe.setReadBufferSize(64 * 1024); + } + return pipe; +} + +void Agent::onPipeIo(NamedPipe &namedPipe) +{ + if (&namedPipe == m_conoutPipe || &namedPipe == m_conerrPipe) { + autoClosePipesForShutdown(); + } else if (&namedPipe == m_coninPipe) { + pollConinPipe(); + } else if (&namedPipe == m_controlPipe) { + pollControlPipe(); + } +} + +void Agent::pollControlPipe() +{ + if (m_controlPipe->isClosed()) { + trace("Agent exiting (control pipe is closed)"); + shutdown(); + return; + } + + while (true) { + uint64_t packetSize = 0; + const auto amt1 = + m_controlPipe->peek(&packetSize, sizeof(packetSize)); + if (amt1 < sizeof(packetSize)) { + break; + } + ASSERT(packetSize >= sizeof(packetSize) && packetSize <= SIZE_MAX); + if (m_controlPipe->bytesAvailable() < packetSize) { + if (m_controlPipe->readBufferSize() < packetSize) { + m_controlPipe->setReadBufferSize(packetSize); + } + break; + } + std::vector packetData; + packetData.resize(packetSize); + const auto amt2 = m_controlPipe->read(packetData.data(), packetSize); + ASSERT(amt2 == packetSize); + try { + ReadBuffer buffer(std::move(packetData)); + buffer.getRawValue(); // Discard the size. + handlePacket(buffer); + } catch (const ReadBuffer::DecodeError&) { + ASSERT(false && "Decode error"); + } + } +} + +void Agent::handlePacket(ReadBuffer &packet) +{ + const int type = packet.getInt32(); + switch (type) { + case AgentMsg::StartProcess: + handleStartProcessPacket(packet); + break; + case AgentMsg::SetSize: + // TODO: I think it might make sense to collapse consecutive SetSize + // messages. i.e. The terminal process can probably generate SetSize + // messages faster than they can be processed, and some GUIs might + // generate a flood of them, so if we can read multiple SetSize packets + // at once, we can ignore the early ones. + handleSetSizePacket(packet); + break; + case AgentMsg::GetConsoleProcessList: + handleGetConsoleProcessListPacket(packet); + break; + default: + trace("Unrecognized message, id:%d", type); + } +} + +void Agent::writePacket(WriteBuffer &packet) +{ + const auto &bytes = packet.buf(); + packet.replaceRawValue(0, bytes.size()); + m_controlPipe->write(bytes.data(), bytes.size()); +} + +void Agent::handleStartProcessPacket(ReadBuffer &packet) +{ + ASSERT(m_childProcess == nullptr); + ASSERT(!m_closingOutputPipes); + + const uint64_t spawnFlags = packet.getInt64(); + const bool wantProcessHandle = packet.getInt32() != 0; + const bool wantThreadHandle = packet.getInt32() != 0; + const auto program = packet.getWString(); + const auto cmdline = packet.getWString(); + const auto cwd = packet.getWString(); + const auto env = packet.getWString(); + const auto desktop = packet.getWString(); + packet.assertEof(); + + auto cmdlineV = vectorWithNulFromString(cmdline); + auto desktopV = vectorWithNulFromString(desktop); + auto envV = vectorFromString(env); + + LPCWSTR programArg = program.empty() ? nullptr : program.c_str(); + LPWSTR cmdlineArg = cmdline.empty() ? nullptr : cmdlineV.data(); + LPCWSTR cwdArg = cwd.empty() ? nullptr : cwd.c_str(); + LPWSTR envArg = env.empty() ? nullptr : envV.data(); + + STARTUPINFOW sui = {}; + PROCESS_INFORMATION pi = {}; + sui.cb = sizeof(sui); + sui.lpDesktop = desktop.empty() ? nullptr : desktopV.data(); + BOOL inheritHandles = FALSE; + if (m_useConerr) { + inheritHandles = TRUE; + sui.dwFlags |= STARTF_USESTDHANDLES; + sui.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + sui.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + sui.hStdError = m_errorBuffer->conout(); + } + + const BOOL success = + CreateProcessW(programArg, cmdlineArg, nullptr, nullptr, + /*bInheritHandles=*/inheritHandles, + /*dwCreationFlags=*/CREATE_UNICODE_ENVIRONMENT, + envArg, cwdArg, &sui, &pi); + const int lastError = success ? 0 : GetLastError(); + + trace("CreateProcess: %s %u", + (success ? "success" : "fail"), + static_cast(pi.dwProcessId)); + + auto reply = newPacket(); + if (success) { + int64_t replyProcess = 0; + int64_t replyThread = 0; + if (wantProcessHandle) { + replyProcess = int64FromHandle(duplicateHandle(pi.hProcess)); + } + if (wantThreadHandle) { + replyThread = int64FromHandle(duplicateHandle(pi.hThread)); + } + CloseHandle(pi.hThread); + m_childProcess = pi.hProcess; + m_autoShutdown = (spawnFlags & WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN) != 0; + m_exitAfterShutdown = (spawnFlags & WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN) != 0; + reply.putInt32(static_cast(StartProcessResult::ProcessCreated)); + reply.putInt64(replyProcess); + reply.putInt64(replyThread); + } else { + reply.putInt32(static_cast(StartProcessResult::CreateProcessFailed)); + reply.putInt32(lastError); + } + writePacket(reply); +} + +void Agent::handleSetSizePacket(ReadBuffer &packet) +{ + const int cols = packet.getInt32(); + const int rows = packet.getInt32(); + packet.assertEof(); + resizeWindow(cols, rows); + auto reply = newPacket(); + writePacket(reply); +} + +void Agent::handleGetConsoleProcessListPacket(ReadBuffer &packet) +{ + packet.assertEof(); + + auto processList = std::vector(64); + auto processCount = GetConsoleProcessList(&processList[0], processList.size()); + + // The process list can change while we're trying to read it + while (processList.size() < processCount) { + // Multiplying by two caps the number of iterations + const auto newSize = std::max(processList.size() * 2, processCount); + processList.resize(newSize); + processCount = GetConsoleProcessList(&processList[0], processList.size()); + } + + if (processCount == 0) { + trace("GetConsoleProcessList failed"); + } + + auto reply = newPacket(); + reply.putInt32(processCount); + for (DWORD i = 0; i < processCount; i++) { + reply.putInt32(processList[i]); + } + writePacket(reply); +} + +void Agent::pollConinPipe() +{ + const std::string newData = m_coninPipe->readAllToString(); + if (hasDebugFlag("input_separated_bytes")) { + // This debug flag is intended to help with testing incomplete escape + // sequences and multibyte UTF-8 encodings. (I wonder if the normal + // code path ought to advance a state machine one byte at a time.) + for (size_t i = 0; i < newData.size(); ++i) { + m_consoleInput->writeInput(newData.substr(i, 1)); + } + } else { + m_consoleInput->writeInput(newData); + } +} + +void Agent::onPollTimeout() +{ + m_consoleInput->updateInputFlags(); + const bool enableMouseMode = m_consoleInput->shouldActivateTerminalMouse(); + + // Give the ConsoleInput object a chance to flush input from an incomplete + // escape sequence (e.g. pressing ESC). + m_consoleInput->flushIncompleteEscapeCode(); + + const bool shouldScrapeContent = !m_closingOutputPipes; + + // Check if the child process has exited. + if (m_autoShutdown && + m_childProcess != nullptr && + WaitForSingleObject(m_childProcess, 0) == WAIT_OBJECT_0) { + CloseHandle(m_childProcess); + m_childProcess = nullptr; + + // Close the data socket to signal to the client that the child + // process has exited. If there's any data left to send, send it + // before closing the socket. + m_closingOutputPipes = true; + } + + // Scrape for output *after* the above exit-check to ensure that we collect + // the child process's final output. + if (shouldScrapeContent) { + syncConsoleTitle(); + scrapeBuffers(); + } + + // We must ensure that we disable mouse mode before closing the CONOUT + // pipe, so update the mouse mode here. + m_primaryScraper->terminal().enableMouseMode( + enableMouseMode && !m_closingOutputPipes); + + autoClosePipesForShutdown(); +} + +void Agent::autoClosePipesForShutdown() +{ + if (m_closingOutputPipes) { + // We don't want to close a pipe before it's connected! If we do, the + // libwinpty client may try to connect to a non-existent pipe. This + // case is important for short-lived programs. + if (m_conoutPipe->isConnected() && + m_conoutPipe->bytesToSend() == 0) { + trace("Closing CONOUT pipe (auto-shutdown)"); + m_conoutPipe->closePipe(); + } + if (m_conerrPipe != nullptr && + m_conerrPipe->isConnected() && + m_conerrPipe->bytesToSend() == 0) { + trace("Closing CONERR pipe (auto-shutdown)"); + m_conerrPipe->closePipe(); + } + if (m_exitAfterShutdown && + m_conoutPipe->isClosed() && + (m_conerrPipe == nullptr || m_conerrPipe->isClosed())) { + trace("Agent exiting (exit-after-shutdown)"); + shutdown(); + } + } +} + +std::unique_ptr Agent::openPrimaryBuffer() +{ + // If we're using a separate buffer for stderr, and a program were to + // activate the stderr buffer, then we could accidentally scrape the same + // buffer twice. That probably shouldn't happen in ordinary use, but it + // can be avoided anyway by using the original console screen buffer in + // that mode. + if (!m_useConerr) { + return Win32ConsoleBuffer::openConout(); + } else { + return Win32ConsoleBuffer::openStdout(); + } +} + +void Agent::resizeWindow(int cols, int rows) +{ + ASSERT(cols >= 1 && rows >= 1); + cols = std::min(cols, MAX_CONSOLE_WIDTH); + rows = std::min(rows, MAX_CONSOLE_HEIGHT); + + Win32Console::FreezeGuard guard(m_console, m_console.frozen()); + const Coord newSize(cols, rows); + ConsoleScreenBufferInfo info; + auto primaryBuffer = openPrimaryBuffer(); + m_primaryScraper->resizeWindow(*primaryBuffer, newSize, info); + m_consoleInput->setMouseWindowRect(info.windowRect()); + if (m_errorScraper) { + m_errorScraper->resizeWindow(*m_errorBuffer, newSize, info); + } + + // Synthesize a WINDOW_BUFFER_SIZE_EVENT event. Normally, Windows + // generates this event only when the buffer size changes, not when the + // window size changes. This behavior is undesirable in two ways: + // - When winpty expands the window horizontally, it must expand the + // buffer first, then the window. At least some programs (e.g. the WSL + // bash.exe wrapper) use the window width rather than the buffer width, + // so there is a short timespan during which they can read the wrong + // value. + // - If the window's vertical size is changed, no event is generated, + // even though a typical well-behaved console program cares about the + // *window* height, not the *buffer* height. + // This synthesization works around a design flaw in the console. It's probably + // harmless. See https://github.com/rprichard/winpty/issues/110. + INPUT_RECORD sizeEvent {}; + sizeEvent.EventType = WINDOW_BUFFER_SIZE_EVENT; + sizeEvent.Event.WindowBufferSizeEvent.dwSize = primaryBuffer->bufferSize(); + DWORD actual {}; + WriteConsoleInputW(GetStdHandle(STD_INPUT_HANDLE), &sizeEvent, 1, &actual); +} + +void Agent::scrapeBuffers() +{ + Win32Console::FreezeGuard guard(m_console, m_console.frozen()); + ConsoleScreenBufferInfo info; + m_primaryScraper->scrapeBuffer(*openPrimaryBuffer(), info); + m_consoleInput->setMouseWindowRect(info.windowRect()); + if (m_errorScraper) { + m_errorScraper->scrapeBuffer(*m_errorBuffer, info); + } +} + +void Agent::syncConsoleTitle() +{ + std::wstring newTitle = m_console.title(); + if (newTitle != m_currentTitle) { + if (!m_plainMode && !m_conoutPipe->isClosed()) { + std::string command = std::string("\x1b]0;") + + utf8FromWide(newTitle) + "\x07"; + m_conoutPipe->write(command.c_str()); + } + m_currentTitle = newTitle; + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/Agent.h b/src/libs/3rdparty/winpty/src/agent/Agent.h new file mode 100644 index 00000000000..1dde48fe4ab --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Agent.h @@ -0,0 +1,103 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef AGENT_H +#define AGENT_H + +#include +#include + +#include +#include + +#include "DsrSender.h" +#include "EventLoop.h" +#include "Win32Console.h" + +class ConsoleInput; +class NamedPipe; +class ReadBuffer; +class Scraper; +class WriteBuffer; +class Win32ConsoleBuffer; + +class Agent : public EventLoop, public DsrSender +{ +public: + Agent(LPCWSTR controlPipeName, + uint64_t agentFlags, + int mouseMode, + int initialCols, + int initialRows); + virtual ~Agent(); + void sendDsr() override; + +private: + NamedPipe &connectToControlPipe(LPCWSTR pipeName); + NamedPipe &createDataServerPipe(bool write, const wchar_t *kind); + +private: + void pollControlPipe(); + void handlePacket(ReadBuffer &packet); + void writePacket(WriteBuffer &packet); + void handleStartProcessPacket(ReadBuffer &packet); + void handleSetSizePacket(ReadBuffer &packet); + void handleGetConsoleProcessListPacket(ReadBuffer &packet); + void pollConinPipe(); + +protected: + virtual void onPollTimeout() override; + virtual void onPipeIo(NamedPipe &namedPipe) override; + +private: + void autoClosePipesForShutdown(); + std::unique_ptr openPrimaryBuffer(); + void resizeWindow(int cols, int rows); + void scrapeBuffers(); + void syncConsoleTitle(); + +private: + const bool m_useConerr; + const bool m_plainMode; + const int m_mouseMode; + Win32Console m_console; + std::unique_ptr m_primaryScraper; + std::unique_ptr m_errorScraper; + std::unique_ptr m_errorBuffer; + NamedPipe *m_controlPipe = nullptr; + NamedPipe *m_coninPipe = nullptr; + NamedPipe *m_conoutPipe = nullptr; + NamedPipe *m_conerrPipe = nullptr; + bool m_autoShutdown = false; + bool m_exitAfterShutdown = false; + bool m_closingOutputPipes = false; + std::unique_ptr m_consoleInput; + HANDLE m_childProcess = nullptr; + + // If the title is initialized to the empty string, then cmd.exe will + // sometimes print this error: + // Not enough storage is available to process this command. + // It happens on Windows 7 when logged into a Cygwin SSH session, for + // example. Using a title of a single space character avoids the problem. + // See https://github.com/rprichard/winpty/issues/74. + std::wstring m_currentTitle = L" "; +}; + +#endif // AGENT_H diff --git a/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc new file mode 100644 index 00000000000..9ad6503b1c5 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "AgentCreateDesktop.h" + +#include "../shared/BackgroundDesktop.h" +#include "../shared/Buffer.h" +#include "../shared/DebugClient.h" +#include "../shared/StringUtil.h" + +#include "EventLoop.h" +#include "NamedPipe.h" + +namespace { + +static inline WriteBuffer newPacket() { + WriteBuffer packet; + packet.putRawValue(0); // Reserve space for size. + return packet; +} + +class CreateDesktopLoop : public EventLoop { +public: + CreateDesktopLoop(LPCWSTR controlPipeName); + +protected: + virtual void onPipeIo(NamedPipe &namedPipe) override; + +private: + void writePacket(WriteBuffer &packet); + + BackgroundDesktop m_desktop; + NamedPipe &m_pipe; +}; + +CreateDesktopLoop::CreateDesktopLoop(LPCWSTR controlPipeName) : + m_pipe(createNamedPipe()) { + m_pipe.connectToServer(controlPipeName, NamedPipe::OpenMode::Duplex); + auto packet = newPacket(); + packet.putWString(m_desktop.desktopName()); + writePacket(packet); +} + +void CreateDesktopLoop::writePacket(WriteBuffer &packet) { + const auto &bytes = packet.buf(); + packet.replaceRawValue(0, bytes.size()); + m_pipe.write(bytes.data(), bytes.size()); +} + +void CreateDesktopLoop::onPipeIo(NamedPipe &namedPipe) { + if (m_pipe.isClosed()) { + shutdown(); + } +} + +} // anonymous namespace + +void handleCreateDesktop(LPCWSTR controlPipeName) { + try { + CreateDesktopLoop loop(controlPipeName); + loop.run(); + trace("Agent exiting..."); + } catch (const WinptyException &e) { + trace("handleCreateDesktop: internal error: %s", + utf8FromWide(e.what()).c_str()); + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h new file mode 100644 index 00000000000..2ae539c7faa --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/AgentCreateDesktop.h @@ -0,0 +1,28 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef AGENT_CREATE_DESKTOP_H +#define AGENT_CREATE_DESKTOP_H + +#include + +void handleCreateDesktop(LPCWSTR controlPipeName); + +#endif // AGENT_CREATE_DESKTOP_H diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc new file mode 100644 index 00000000000..aa1f7876d38 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.cc @@ -0,0 +1,698 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "ConsoleFont.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../shared/DebugClient.h" +#include "../shared/OsModule.h" +#include "../shared/StringUtil.h" +#include "../shared/WindowsVersion.h" +#include "../shared/WinptyAssert.h" +#include "../shared/winpty_snprintf.h" + +namespace { + +#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) + +// See https://en.wikipedia.org/wiki/List_of_CJK_fonts +const wchar_t kLucidaConsole[] = L"Lucida Console"; +const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // 932, Japanese +const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // 936, Chinese Simplified +const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // 949, Korean +const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // 950, Chinese Traditional + +struct FontSize { + short size; + int width; +}; + +struct Font { + const wchar_t *faceName; + unsigned int family; + short size; +}; + +// Ideographs in East Asian languages take two columns rather than one. +// In the console screen buffer, a "full-width" character will occupy two +// cells of the buffer, the first with attribute 0x100 and the second with +// attribute 0x200. +// +// Windows does not correctly identify code points as double-width in all +// configurations. It depends heavily on the code page, the font facename, +// and (somehow) even the font size. In the 437 code page (MS-DOS), for +// example, no codepoints are interpreted as double-width. When the console +// is in an East Asian code page (932, 936, 949, or 950), then sometimes +// selecting a "Western" facename like "Lucida Console" or "Consolas" doesn't +// register, or if the font *can* be chosen, then the console doesn't handle +// double-width correctly. I tested the double-width handling by writing +// several code points with WriteConsole and checking whether one or two cells +// were filled. +// +// In the Japanese code page (932), Microsoft's default font is MS Gothic. +// MS Gothic double-width handling seems to be broken with console versions +// prior to Windows 10 (including Windows 10's legacy mode), and it's +// especially broken in Windows 8 and 8.1. +// +// Test by running: misc/Utf16Echo A2 A3 2014 3044 30FC 4000 +// +// The first three codepoints are always rendered as half-width with the +// Windows Japanese fonts. (Of these, the first two must be half-width, +// but U+2014 could be either.) The last three are rendered as full-width, +// and they are East_Asian_Width=Wide. +// +// Windows 7 fails by modeling all codepoints as full-width with font +// sizes 22 and above. +// +// Windows 8 gets U+00A2, U+00A3, U+2014, U+30FC, and U+4000 wrong, but +// using a point size not listed in the console properties dialog +// (e.g. "9") is less wrong: +// +// | code point | +// font | 00A2 00A3 2014 3044 30FC 4000 | cell size +// ------------+---------------------------------+---------- +// 8 | F F F F H H | 4x8 +// 9 | F F F F F F | 5x9 +// 16 | F F F F H H | 8x16 +// raster 6x13 | H H H F F H(*) | 6x13 +// +// (*) The Raster Font renders U+4000 as a white box (i.e. an unsupported +// character). +// + +// See: +// - misc/Font-Report-June2016 directory for per-size details +// - misc/font-notes.txt +// - misc/Utf16Echo.cc, misc/FontSurvey.cc, misc/SetFont.cc, misc/GetFont.cc + +const FontSize kLucidaFontSizes[] = { + { 5, 3 }, + { 6, 4 }, + { 8, 5 }, + { 10, 6 }, + { 12, 7 }, + { 14, 8 }, + { 16, 10 }, + { 18, 11 }, + { 20, 12 }, + { 36, 22 }, + { 48, 29 }, + { 60, 36 }, + { 72, 43 }, +}; + +// Japanese. Used on Vista and Windows 7. +const FontSize k932GothicVista[] = { + { 6, 3 }, + { 8, 4 }, + { 10, 5 }, + { 12, 6 }, + { 13, 7 }, + { 15, 8 }, + { 17, 9 }, + { 19, 10 }, + { 21, 11 }, + // All larger fonts are more broken w.r.t. full-size East Asian characters. +}; + +// Japanese. Used on Windows 8, 8.1, and the legacy 10 console. +const FontSize k932GothicWin8[] = { + // All of these characters are broken w.r.t. full-size East Asian + // characters, but they're equally broken. + { 5, 3 }, + { 7, 4 }, + { 9, 5 }, + { 11, 6 }, + { 13, 7 }, + { 15, 8 }, + { 17, 9 }, + { 20, 10 }, + { 22, 11 }, + { 24, 12 }, + // include extra-large fonts for small terminals + { 36, 18 }, + { 48, 24 }, + { 60, 30 }, + { 72, 36 }, +}; + +// Japanese. Used on the new Windows 10 console. +const FontSize k932GothicWin10[] = { + { 6, 3 }, + { 8, 4 }, + { 10, 5 }, + { 12, 6 }, + { 14, 7 }, + { 16, 8 }, + { 18, 9 }, + { 20, 10 }, + { 22, 11 }, + { 24, 12 }, + // include extra-large fonts for small terminals + { 36, 18 }, + { 48, 24 }, + { 60, 30 }, + { 72, 36 }, +}; + +// Chinese Simplified. +const FontSize k936SimSun[] = { + { 6, 3 }, + { 8, 4 }, + { 10, 5 }, + { 12, 6 }, + { 14, 7 }, + { 16, 8 }, + { 18, 9 }, + { 20, 10 }, + { 22, 11 }, + { 24, 12 }, + // include extra-large fonts for small terminals + { 36, 18 }, + { 48, 24 }, + { 60, 30 }, + { 72, 36 }, +}; + +// Korean. +const FontSize k949GulimChe[] = { + { 6, 3 }, + { 8, 4 }, + { 10, 5 }, + { 12, 6 }, + { 14, 7 }, + { 16, 8 }, + { 18, 9 }, + { 20, 10 }, + { 22, 11 }, + { 24, 12 }, + // include extra-large fonts for small terminals + { 36, 18 }, + { 48, 24 }, + { 60, 30 }, + { 72, 36 }, +}; + +// Chinese Traditional. +const FontSize k950MingLight[] = { + { 6, 3 }, + { 8, 4 }, + { 10, 5 }, + { 12, 6 }, + { 14, 7 }, + { 16, 8 }, + { 18, 9 }, + { 20, 10 }, + { 22, 11 }, + { 24, 12 }, + // include extra-large fonts for small terminals + { 36, 18 }, + { 48, 24 }, + { 60, 30 }, + { 72, 36 }, +}; + +// Some of these types and functions are missing from the MinGW headers. +// Others are undocumented. + +struct AGENT_CONSOLE_FONT_INFO { + DWORD nFont; + COORD dwFontSize; +}; + +struct AGENT_CONSOLE_FONT_INFOEX { + ULONG cbSize; + DWORD nFont; + COORD dwFontSize; + UINT FontFamily; + UINT FontWeight; + WCHAR FaceName[LF_FACESIZE]; +}; + +// undocumented XP API +typedef BOOL WINAPI SetConsoleFont_t( + HANDLE hOutput, + DWORD dwFontIndex); + +// undocumented XP API +typedef DWORD WINAPI GetNumberOfConsoleFonts_t(); + +// XP and up +typedef BOOL WINAPI GetCurrentConsoleFont_t( + HANDLE hOutput, + BOOL bMaximumWindow, + AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont); + +// XP and up +typedef COORD WINAPI GetConsoleFontSize_t( + HANDLE hConsoleOutput, + DWORD nFont); + +// Vista and up +typedef BOOL WINAPI GetCurrentConsoleFontEx_t( + HANDLE hConsoleOutput, + BOOL bMaximumWindow, + AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); + +// Vista and up +typedef BOOL WINAPI SetCurrentConsoleFontEx_t( + HANDLE hConsoleOutput, + BOOL bMaximumWindow, + AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); + +#define GET_MODULE_PROC(mod, funcName) \ + m_##funcName = reinterpret_cast((mod).proc(#funcName)); \ + +#define DEFINE_ACCESSOR(funcName) \ + funcName##_t &funcName() const { \ + ASSERT(valid()); \ + return *m_##funcName; \ + } + +class XPFontAPI { +public: + XPFontAPI() : m_kernel32(L"kernel32.dll") { + GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont); + GET_MODULE_PROC(m_kernel32, GetConsoleFontSize); + } + + bool valid() const { + return m_GetCurrentConsoleFont != NULL && + m_GetConsoleFontSize != NULL; + } + + DEFINE_ACCESSOR(GetCurrentConsoleFont) + DEFINE_ACCESSOR(GetConsoleFontSize) + +private: + OsModule m_kernel32; + GetCurrentConsoleFont_t *m_GetCurrentConsoleFont; + GetConsoleFontSize_t *m_GetConsoleFontSize; +}; + +class UndocumentedXPFontAPI : public XPFontAPI { +public: + UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") { + GET_MODULE_PROC(m_kernel32, SetConsoleFont); + GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts); + } + + bool valid() const { + return this->XPFontAPI::valid() && + m_SetConsoleFont != NULL && + m_GetNumberOfConsoleFonts != NULL; + } + + DEFINE_ACCESSOR(SetConsoleFont) + DEFINE_ACCESSOR(GetNumberOfConsoleFonts) + +private: + OsModule m_kernel32; + SetConsoleFont_t *m_SetConsoleFont; + GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts; +}; + +class VistaFontAPI : public XPFontAPI { +public: + VistaFontAPI() : m_kernel32(L"kernel32.dll") { + GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx); + GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx); + } + + bool valid() const { + return this->XPFontAPI::valid() && + m_GetCurrentConsoleFontEx != NULL && + m_SetCurrentConsoleFontEx != NULL; + } + + DEFINE_ACCESSOR(GetCurrentConsoleFontEx) + DEFINE_ACCESSOR(SetCurrentConsoleFontEx) + +private: + OsModule m_kernel32; + GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx; + SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx; +}; + +static std::vector > readFontTable( + XPFontAPI &api, HANDLE conout, DWORD maxCount) { + std::vector > ret; + for (DWORD i = 0; i < maxCount; ++i) { + COORD size = api.GetConsoleFontSize()(conout, i); + if (size.X == 0 && size.Y == 0) { + break; + } + ret.push_back(std::make_pair(i, size)); + } + return ret; +} + +static void dumpFontTable(HANDLE conout, const char *prefix) { + const int kMaxCount = 1000; + if (!isTracingEnabled()) { + return; + } + XPFontAPI api; + if (!api.valid()) { + trace("dumpFontTable: cannot dump font table -- missing APIs"); + return; + } + std::vector > table = + readFontTable(api, conout, kMaxCount); + std::string line; + char tmp[128]; + size_t first = 0; + while (first < table.size()) { + size_t last = std::min(table.size() - 1, first + 10 - 1); + winpty_snprintf(tmp, "%sfonts %02u-%02u:", + prefix, static_cast(first), static_cast(last)); + line = tmp; + for (size_t i = first; i <= last; ++i) { + if (i % 10 == 5) { + line += " - "; + } + winpty_snprintf(tmp, " %2dx%-2d", + table[i].second.X, table[i].second.Y); + line += tmp; + } + trace("%s", line.c_str()); + first = last + 1; + } + if (table.size() == kMaxCount) { + trace("%sfonts: ... stopped reading at %d fonts ...", + prefix, kMaxCount); + } +} + +static std::string stringToCodePoints(const std::wstring &str) { + std::string ret = "("; + for (size_t i = 0; i < str.size(); ++i) { + char tmp[32]; + winpty_snprintf(tmp, "%X", str[i]); + if (ret.size() > 1) { + ret.push_back(' '); + } + ret += tmp; + } + ret.push_back(')'); + return ret; +} + +static void dumpFontInfoEx( + const AGENT_CONSOLE_FONT_INFOEX &infoex, + const char *prefix) { + if (!isTracingEnabled()) { + return; + } + std::wstring faceName(infoex.FaceName, + winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName))); + trace("%snFont=%u dwFontSize=(%d,%d) " + "FontFamily=0x%x FontWeight=%u FaceName=%s %s", + prefix, + static_cast(infoex.nFont), + infoex.dwFontSize.X, infoex.dwFontSize.Y, + infoex.FontFamily, infoex.FontWeight, utf8FromWide(faceName).c_str(), + stringToCodePoints(faceName).c_str()); +} + +static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, const char *prefix) { + if (!isTracingEnabled()) { + return; + } + AGENT_CONSOLE_FONT_INFOEX infoex = {0}; + infoex.cbSize = sizeof(infoex); + if (!api.GetCurrentConsoleFontEx()(conout, FALSE, &infoex)) { + trace("GetCurrentConsoleFontEx call failed"); + return; + } + dumpFontInfoEx(infoex, prefix); +} + +static void dumpXPFont(XPFontAPI &api, HANDLE conout, const char *prefix) { + if (!isTracingEnabled()) { + return; + } + AGENT_CONSOLE_FONT_INFO info = {0}; + if (!api.GetCurrentConsoleFont()(conout, FALSE, &info)) { + trace("GetCurrentConsoleFont call failed"); + return; + } + trace("%snFont=%u dwFontSize=(%d,%d)", + prefix, + static_cast(info.nFont), + info.dwFontSize.X, info.dwFontSize.Y); +} + +static bool setFontVista( + VistaFontAPI &api, + HANDLE conout, + const Font &font) { + AGENT_CONSOLE_FONT_INFOEX infoex = {}; + infoex.cbSize = sizeof(AGENT_CONSOLE_FONT_INFOEX); + infoex.dwFontSize.Y = font.size; + infoex.FontFamily = font.family; + infoex.FontWeight = 400; + winpty_wcsncpy_nul(infoex.FaceName, font.faceName); + dumpFontInfoEx(infoex, "setFontVista: setting font to: "); + if (!api.SetCurrentConsoleFontEx()(conout, FALSE, &infoex)) { + trace("setFontVista: SetCurrentConsoleFontEx call failed"); + return false; + } + memset(&infoex, 0, sizeof(infoex)); + infoex.cbSize = sizeof(infoex); + if (!api.GetCurrentConsoleFontEx()(conout, FALSE, &infoex)) { + trace("setFontVista: GetCurrentConsoleFontEx call failed"); + return false; + } + if (wcsncmp(infoex.FaceName, font.faceName, + COUNT_OF(infoex.FaceName)) != 0) { + trace("setFontVista: face name was not set"); + dumpFontInfoEx(infoex, "setFontVista: post-call font: "); + return false; + } + // We'd like to verify that the new font size is correct, but we can't + // predict what it will be, even though we just set it to `pxSize` through + // an apprently symmetric interface. For the Chinese and Korean fonts, the + // new `infoex.dwFontSize.Y` value can be slightly larger than the height + // we specified. + return true; +} + +static Font selectSmallFont(int codePage, int columns, bool isNewW10) { + // Iterate over a set of font sizes according to the code page, and select + // one. + + const wchar_t *faceName = nullptr; + unsigned int fontFamily = 0; + const FontSize *table = nullptr; + size_t tableSize = 0; + + switch (codePage) { + case 932: // Japanese + faceName = kMSGothic; + fontFamily = 0x36; + if (isNewW10) { + table = k932GothicWin10; + tableSize = COUNT_OF(k932GothicWin10); + } else if (isAtLeastWindows8()) { + table = k932GothicWin8; + tableSize = COUNT_OF(k932GothicWin8); + } else { + table = k932GothicVista; + tableSize = COUNT_OF(k932GothicVista); + } + break; + case 936: // Chinese Simplified + faceName = kNSimSun; + fontFamily = 0x36; + table = k936SimSun; + tableSize = COUNT_OF(k936SimSun); + break; + case 949: // Korean + faceName = kGulimChe; + fontFamily = 0x36; + table = k949GulimChe; + tableSize = COUNT_OF(k949GulimChe); + break; + case 950: // Chinese Traditional + faceName = kMingLight; + fontFamily = 0x36; + table = k950MingLight; + tableSize = COUNT_OF(k950MingLight); + break; + default: + faceName = kLucidaConsole; + fontFamily = 0x36; + table = kLucidaFontSizes; + tableSize = COUNT_OF(kLucidaFontSizes); + break; + } + + size_t bestIndex = static_cast(-1); + std::tuple bestScore = std::make_tuple(-1, -1); + + // We might want to pick the smallest possible font, because we don't know + // how large the monitor is (and the monitor size can change). We might + // want to pick a larger font to accommodate console programs that resize + // the console on their own, like DOS edit.com, which tends to resize the + // console to 80 columns. + + for (size_t i = 0; i < tableSize; ++i) { + const int width = table[i].width * columns; + + // In general, we'd like to pick a font size where cutting the number + // of columns in half doesn't immediately violate the minimum width + // constraint. (e.g. To run DOS edit.com, a user might resize their + // terminal to ~100 columns so it's big enough to show the 80 columns + // post-resize.) To achieve this, give priority to fonts that allow + // this halving. We don't want to encourage *very* large fonts, + // though, so disable the effect as the number of columns scales from + // 80 to 40. + const int halfColumns = std::min(columns, std::max(40, columns / 2)); + const int halfWidth = table[i].width * halfColumns; + + std::tuple thisScore = std::make_tuple(-1, -1); + if (width >= 160 && halfWidth >= 160) { + // Both sizes are good. Prefer the smaller fonts. + thisScore = std::make_tuple(2, -width); + } else if (width >= 160) { + // Prefer the smaller fonts. + thisScore = std::make_tuple(1, -width); + } else { + // Otherwise, prefer the largest font in our table. + thisScore = std::make_tuple(0, width); + } + if (thisScore > bestScore) { + bestIndex = i; + bestScore = thisScore; + } + } + + ASSERT(bestIndex != static_cast(-1)); + return Font { faceName, fontFamily, table[bestIndex].size }; +} + +static void setSmallFontVista(VistaFontAPI &api, HANDLE conout, + int columns, bool isNewW10) { + int codePage = GetConsoleOutputCP(); + const auto font = selectSmallFont(codePage, columns, isNewW10); + if (setFontVista(api, conout, font)) { + trace("setSmallFontVista: success"); + return; + } + if (codePage == 932 || codePage == 936 || + codePage == 949 || codePage == 950) { + trace("setSmallFontVista: falling back to default codepage font instead"); + const auto fontFB = selectSmallFont(0, columns, isNewW10); + if (setFontVista(api, conout, fontFB)) { + trace("setSmallFontVista: fallback was successful"); + return; + } + } + trace("setSmallFontVista: failure"); +} + +struct FontSizeComparator { + bool operator()(const std::pair &obj1, + const std::pair &obj2) const { + int score1 = obj1.second.X + obj1.second.Y; + int score2 = obj2.second.X + obj2.second.Y; + return score1 < score2; + } +}; + +static void setSmallFontXP(UndocumentedXPFontAPI &api, HANDLE conout) { + // Read the console font table and sort it from smallest to largest. + const DWORD fontCount = api.GetNumberOfConsoleFonts()(); + trace("setSmallFontXP: number of console fonts: %u", + static_cast(fontCount)); + std::vector > table = + readFontTable(api, conout, fontCount); + std::sort(table.begin(), table.end(), FontSizeComparator()); + for (size_t i = 0; i < table.size(); ++i) { + // Skip especially narrow fonts to permit narrower terminals. + if (table[i].second.X < 4) { + continue; + } + trace("setSmallFontXP: setting font to %u", + static_cast(table[i].first)); + if (!api.SetConsoleFont()(conout, table[i].first)) { + trace("setSmallFontXP: SetConsoleFont call failed"); + continue; + } + AGENT_CONSOLE_FONT_INFO info; + if (!api.GetCurrentConsoleFont()(conout, FALSE, &info)) { + trace("setSmallFontXP: GetCurrentConsoleFont call failed"); + return; + } + if (info.nFont != table[i].first) { + trace("setSmallFontXP: font was not set"); + dumpXPFont(api, conout, "setSmallFontXP: post-call font: "); + continue; + } + trace("setSmallFontXP: success"); + return; + } + trace("setSmallFontXP: failure"); +} + +} // anonymous namespace + +// A Windows console window can never be larger than the desktop window. To +// maximize the possible size of the console in rows*cols, try to configure +// the console with a small font. Unfortunately, we cannot make the font *too* +// small, because there is also a minimum window size in pixels. +void setSmallFont(HANDLE conout, int columns, bool isNewW10) { + trace("setSmallFont: attempting to set a small font for %d columns " + "(CP=%u OutputCP=%u)", + columns, + static_cast(GetConsoleCP()), + static_cast(GetConsoleOutputCP())); + VistaFontAPI vista; + if (vista.valid()) { + dumpVistaFont(vista, conout, "previous font: "); + dumpFontTable(conout, "previous font table: "); + setSmallFontVista(vista, conout, columns, isNewW10); + dumpVistaFont(vista, conout, "new font: "); + dumpFontTable(conout, "new font table: "); + return; + } + UndocumentedXPFontAPI xp; + if (xp.valid()) { + dumpXPFont(xp, conout, "previous font: "); + dumpFontTable(conout, "previous font table: "); + setSmallFontXP(xp, conout); + dumpXPFont(xp, conout, "new font: "); + dumpFontTable(conout, "new font table: "); + return; + } + trace("setSmallFont: neither Vista nor XP APIs detected -- giving up"); + dumpFontTable(conout, "font table: "); +} diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleFont.h b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.h new file mode 100644 index 00000000000..99cb10698d9 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleFont.h @@ -0,0 +1,28 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef CONSOLEFONT_H +#define CONSOLEFONT_H + +#include + +void setSmallFont(HANDLE conout, int columns, bool isNewW10); + +#endif // CONSOLEFONT_H diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc new file mode 100644 index 00000000000..192cac2a298 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.cc @@ -0,0 +1,852 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "ConsoleInput.h" + +#include +#include + +#include +#include + +#include "../include/winpty_constants.h" + +#include "../shared/DebugClient.h" +#include "../shared/StringBuilder.h" +#include "../shared/UnixCtrlChars.h" + +#include "ConsoleInputReencoding.h" +#include "DebugShowInput.h" +#include "DefaultInputMap.h" +#include "DsrSender.h" +#include "UnicodeEncoding.h" +#include "Win32Console.h" + +// MAPVK_VK_TO_VSC isn't defined by the old MinGW. +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC 0 +#endif + +namespace { + +struct MouseRecord { + bool release; + int flags; + COORD coord; + + std::string toString() const; +}; + +std::string MouseRecord::toString() const { + StringBuilder sb(40); + sb << "pos=" << coord.X << ',' << coord.Y + << " flags=0x" << hexOfInt(flags); + if (release) { + sb << " release"; + } + return sb.str_moved(); +} + +const unsigned int kIncompleteEscapeTimeoutMs = 1000u; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { return 0; } \ + } while(0) + +#define ADVANCE() \ + do { \ + pch++; \ + if (pch == stop) { return -1; } \ + } while(0) + +#define SCAN_INT(out, maxLen) \ + do { \ + (out) = 0; \ + CHECK(isdigit(*pch)); \ + const char *begin = pch; \ + do { \ + CHECK(pch - begin + 1 < maxLen); \ + (out) = (out) * 10 + *pch - '0'; \ + ADVANCE(); \ + } while (isdigit(*pch)); \ + } while(0) + +#define SCAN_SIGNED_INT(out, maxLen) \ + do { \ + bool negative = false; \ + if (*pch == '-') { \ + negative = true; \ + ADVANCE(); \ + } \ + SCAN_INT(out, maxLen); \ + if (negative) { \ + (out) = -(out); \ + } \ + } while(0) + +// Match the Device Status Report console input: ESC [ nn ; mm R +// Returns: +// 0 no match +// >0 match, returns length of match +// -1 incomplete match +static int matchDsr(const char *input, int inputSize) +{ + int32_t dummy = 0; + const char *pch = input; + const char *stop = input + inputSize; + CHECK(*pch == '\x1B'); ADVANCE(); + CHECK(*pch == '['); ADVANCE(); + SCAN_INT(dummy, 8); + CHECK(*pch == ';'); ADVANCE(); + SCAN_INT(dummy, 8); + CHECK(*pch == 'R'); + return pch - input + 1; +} + +static int matchMouseDefault(const char *input, int inputSize, + MouseRecord &out) +{ + const char *pch = input; + const char *stop = input + inputSize; + CHECK(*pch == '\x1B'); ADVANCE(); + CHECK(*pch == '['); ADVANCE(); + CHECK(*pch == 'M'); ADVANCE(); + out.flags = (*pch - 32) & 0xFF; ADVANCE(); + out.coord.X = (*pch - '!') & 0xFF; + ADVANCE(); + out.coord.Y = (*pch - '!') & 0xFF; + out.release = false; + return pch - input + 1; +} + +static int matchMouse1006(const char *input, int inputSize, MouseRecord &out) +{ + const char *pch = input; + const char *stop = input + inputSize; + int32_t temp; + CHECK(*pch == '\x1B'); ADVANCE(); + CHECK(*pch == '['); ADVANCE(); + CHECK(*pch == '<'); ADVANCE(); + SCAN_INT(out.flags, 8); + CHECK(*pch == ';'); ADVANCE(); + SCAN_SIGNED_INT(temp, 8); out.coord.X = temp - 1; + CHECK(*pch == ';'); ADVANCE(); + SCAN_SIGNED_INT(temp, 8); out.coord.Y = temp - 1; + CHECK(*pch == 'M' || *pch == 'm'); + out.release = (*pch == 'm'); + return pch - input + 1; +} + +static int matchMouse1015(const char *input, int inputSize, MouseRecord &out) +{ + const char *pch = input; + const char *stop = input + inputSize; + int32_t temp; + CHECK(*pch == '\x1B'); ADVANCE(); + CHECK(*pch == '['); ADVANCE(); + SCAN_INT(out.flags, 8); out.flags -= 32; + CHECK(*pch == ';'); ADVANCE(); + SCAN_SIGNED_INT(temp, 8); out.coord.X = temp - 1; + CHECK(*pch == ';'); ADVANCE(); + SCAN_SIGNED_INT(temp, 8); out.coord.Y = temp - 1; + CHECK(*pch == 'M'); + out.release = false; + return pch - input + 1; +} + +// Match a mouse input escape sequence of any kind. +// 0 no match +// >0 match, returns length of match +// -1 incomplete match +static int matchMouseRecord(const char *input, int inputSize, MouseRecord &out) +{ + memset(&out, 0, sizeof(out)); + int ret; + if ((ret = matchMouse1006(input, inputSize, out)) != 0) { return ret; } + if ((ret = matchMouse1015(input, inputSize, out)) != 0) { return ret; } + if ((ret = matchMouseDefault(input, inputSize, out)) != 0) { return ret; } + return 0; +} + +#undef CHECK +#undef ADVANCE +#undef SCAN_INT + +} // anonymous namespace + +ConsoleInput::ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender, + Win32Console &console) : + m_console(console), + m_conin(conin), + m_mouseMode(mouseMode), + m_dsrSender(dsrSender) +{ + addDefaultEntriesToInputMap(m_inputMap); + if (hasDebugFlag("dump_input_map")) { + m_inputMap.dumpInputMap(); + } + + // Configure Quick Edit mode according to the mouse mode. Enable + // InsertMode for two reasons: + // - If it's OFF, it's difficult for the user to turn it ON. The + // properties dialog is inaccesible. winpty still faithfully handles + // the Insert key, which toggles between the insertion and overwrite + // modes. + // - When we modify the QuickEdit setting, if ExtendedFlags is OFF, + // then we must choose the InsertMode setting. I don't *think* this + // case happens, though, because a new console always has ExtendedFlags + // ON. + // See misc/EnableExtendedFlags.txt. + DWORD mode = 0; + if (!GetConsoleMode(conin, &mode)) { + trace("Agent startup: GetConsoleMode failed"); + } else { + mode |= ENABLE_EXTENDED_FLAGS; + mode |= ENABLE_INSERT_MODE; + if (m_mouseMode == WINPTY_MOUSE_MODE_AUTO) { + mode |= ENABLE_QUICK_EDIT_MODE; + } else { + mode &= ~ENABLE_QUICK_EDIT_MODE; + } + if (!SetConsoleMode(conin, mode)) { + trace("Agent startup: SetConsoleMode failed"); + } + } + + updateInputFlags(true); +} + +void ConsoleInput::writeInput(const std::string &input) +{ + if (input.size() == 0) { + return; + } + + if (isTracingEnabled()) { + static bool debugInput = hasDebugFlag("input"); + if (debugInput) { + std::string dumpString; + for (size_t i = 0; i < input.size(); ++i) { + const char ch = input[i]; + const char ctrl = decodeUnixCtrlChar(ch); + if (ctrl != '\0') { + dumpString += '^'; + dumpString += ctrl; + } else { + dumpString += ch; + } + } + dumpString += " ("; + for (size_t i = 0; i < input.size(); ++i) { + if (i > 0) { + dumpString += ' '; + } + const unsigned char uch = input[i]; + char buf[32]; + winpty_snprintf(buf, "%02X", uch); + dumpString += buf; + } + dumpString += ')'; + trace("input chars: %s", dumpString.c_str()); + } + } + + m_byteQueue.append(input); + doWrite(false); + if (!m_byteQueue.empty() && !m_dsrSent) { + trace("send DSR"); + m_dsrSender.sendDsr(); + m_dsrSent = true; + } + m_lastWriteTick = GetTickCount(); +} + +void ConsoleInput::flushIncompleteEscapeCode() +{ + if (!m_byteQueue.empty() && + (GetTickCount() - m_lastWriteTick) > kIncompleteEscapeTimeoutMs) { + doWrite(true); + m_byteQueue.clear(); + } +} + +void ConsoleInput::updateInputFlags(bool forceTrace) +{ + const DWORD mode = inputConsoleMode(); + const bool newFlagEE = (mode & ENABLE_EXTENDED_FLAGS) != 0; + const bool newFlagMI = (mode & ENABLE_MOUSE_INPUT) != 0; + const bool newFlagQE = (mode & ENABLE_QUICK_EDIT_MODE) != 0; + const bool newFlagEI = (mode & 0x200) != 0; + if (forceTrace || + newFlagEE != m_enableExtendedEnabled || + newFlagMI != m_mouseInputEnabled || + newFlagQE != m_quickEditEnabled || + newFlagEI != m_escapeInputEnabled) { + trace("CONIN modes: Extended=%s, MouseInput=%s QuickEdit=%s EscapeInput=%s", + newFlagEE ? "on" : "off", + newFlagMI ? "on" : "off", + newFlagQE ? "on" : "off", + newFlagEI ? "on" : "off"); + } + m_enableExtendedEnabled = newFlagEE; + m_mouseInputEnabled = newFlagMI; + m_quickEditEnabled = newFlagQE; + m_escapeInputEnabled = newFlagEI; +} + +bool ConsoleInput::shouldActivateTerminalMouse() +{ + // Return whether the agent should activate the terminal's mouse mode. + if (m_mouseMode == WINPTY_MOUSE_MODE_AUTO) { + // Some programs (e.g. Cygwin command-line programs like bash.exe and + // python2.7.exe) turn off ENABLE_EXTENDED_FLAGS and turn on + // ENABLE_MOUSE_INPUT, but do not turn off QuickEdit mode and do not + // actually care about mouse input. Only enable the terminal mouse + // mode if ENABLE_EXTENDED_FLAGS is on. See + // misc/EnableExtendedFlags.txt. + return m_mouseInputEnabled && !m_quickEditEnabled && + m_enableExtendedEnabled; + } else if (m_mouseMode == WINPTY_MOUSE_MODE_FORCE) { + return true; + } else { + return false; + } +} + +void ConsoleInput::doWrite(bool isEof) +{ + const char *data = m_byteQueue.c_str(); + std::vector records; + size_t idx = 0; + while (idx < m_byteQueue.size()) { + int charSize = scanInput(records, &data[idx], m_byteQueue.size() - idx, isEof); + if (charSize == -1) + break; + idx += charSize; + } + m_byteQueue.erase(0, idx); + flushInputRecords(records); +} + +void ConsoleInput::flushInputRecords(std::vector &records) +{ + if (records.size() == 0) { + return; + } + DWORD actual = 0; + if (!WriteConsoleInputW(m_conin, records.data(), records.size(), &actual)) { + trace("WriteConsoleInputW failed"); + } + records.clear(); +} + +// This behavior isn't strictly correct, because the keypresses (probably?) +// adopt the keyboard state (e.g. Ctrl/Alt/Shift modifiers) of the current +// window station's keyboard, which has no necessary relationship to the winpty +// instance. It's unlikely to be an issue in practice, but it's conceivable. +// (Imagine a foreground SSH server, where the local user holds down Ctrl, +// while the remote user tries to use WSL navigation keys.) I suspect using +// the BackgroundDesktop mechanism in winpty would fix the problem. +// +// https://github.com/rprichard/winpty/issues/116 +static void sendKeyMessage(HWND hwnd, bool isKeyDown, uint16_t virtualKey) +{ + uint32_t scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC); + if (scanCode > 255) { + scanCode = 0; + } + SendMessage(hwnd, isKeyDown ? WM_KEYDOWN : WM_KEYUP, virtualKey, + (scanCode << 16) | 1u | (isKeyDown ? 0u : 0xc0000000u)); +} + +int ConsoleInput::scanInput(std::vector &records, + const char *input, + int inputSize, + bool isEof) +{ + ASSERT(inputSize >= 1); + + // Ctrl-C. + // + // In processed mode, use GenerateConsoleCtrlEvent so that Ctrl-C handlers + // are called. GenerateConsoleCtrlEvent unfortunately doesn't interrupt + // ReadConsole calls[1]. Using WM_KEYDOWN/UP fixes the ReadConsole + // problem, but breaks in background window stations/desktops. + // + // In unprocessed mode, there's an entry for Ctrl-C in the SimpleEncoding + // table in DefaultInputMap. + // + // [1] https://github.com/rprichard/winpty/issues/116 + if (input[0] == '\x03' && (inputConsoleMode() & ENABLE_PROCESSED_INPUT)) { + flushInputRecords(records); + trace("Ctrl-C"); + const BOOL ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + trace("GenerateConsoleCtrlEvent: %d", ret); + return 1; + } + + if (input[0] == '\x1B') { + // Attempt to match the Device Status Report (DSR) reply. + int dsrLen = matchDsr(input, inputSize); + if (dsrLen > 0) { + trace("Received a DSR reply"); + m_dsrSent = false; + return dsrLen; + } else if (!isEof && dsrLen == -1) { + // Incomplete DSR match. + trace("Incomplete DSR match"); + return -1; + } + + int mouseLen = scanMouseInput(records, input, inputSize); + if (mouseLen > 0 || (!isEof && mouseLen == -1)) { + return mouseLen; + } + } + + // Search the input map. + InputMap::Key match; + bool incomplete; + int matchLen = m_inputMap.lookupKey(input, inputSize, match, incomplete); + if (!isEof && incomplete) { + // Incomplete match -- need more characters (or wait for a + // timeout to signify flushed input). + trace("Incomplete escape sequence"); + return -1; + } else if (matchLen > 0) { + uint32_t winCodePointDn = match.unicodeChar; + if ((match.keyState & LEFT_CTRL_PRESSED) && (match.keyState & LEFT_ALT_PRESSED)) { + winCodePointDn = '\0'; + } + uint32_t winCodePointUp = winCodePointDn; + if (match.keyState & LEFT_ALT_PRESSED) { + winCodePointUp = '\0'; + } + appendKeyPress(records, match.virtualKey, + winCodePointDn, winCodePointUp, match.keyState, + match.unicodeChar, match.keyState); + return matchLen; + } + + // Recognize Alt-. + // + // This code doesn't match Alt-ESC, which is encoded as `ESC ESC`, but + // maybe it should. I was concerned that pressing ESC rapidly enough could + // accidentally trigger Alt-ESC. (e.g. The user would have to be faster + // than the DSR flushing mechanism or use a decrepit terminal. The user + // might be on a slow network connection.) + if (input[0] == '\x1B' && inputSize >= 2 && input[1] != '\x1B') { + const int len = utf8CharLength(input[1]); + if (len > 0) { + if (1 + len > inputSize) { + // Incomplete character. + trace("Incomplete UTF-8 character in Alt-"); + return -1; + } + appendUtf8Char(records, &input[1], len, true); + return 1 + len; + } + } + + // A UTF-8 character. + const int len = utf8CharLength(input[0]); + if (len == 0) { + static bool debugInput = isTracingEnabled() && hasDebugFlag("input"); + if (debugInput) { + trace("Discarding invalid input byte: %02X", + static_cast(input[0])); + } + return 1; + } + if (len > inputSize) { + // Incomplete character. + trace("Incomplete UTF-8 character"); + return -1; + } + appendUtf8Char(records, &input[0], len, false); + return len; +} + +int ConsoleInput::scanMouseInput(std::vector &records, + const char *input, + int inputSize) +{ + MouseRecord record; + const int len = matchMouseRecord(input, inputSize, record); + if (len <= 0) { + return len; + } + + if (isTracingEnabled()) { + static bool debugInput = hasDebugFlag("input"); + if (debugInput) { + trace("mouse input: %s", record.toString().c_str()); + } + } + + const int button = record.flags & 0x03; + INPUT_RECORD newRecord = {0}; + newRecord.EventType = MOUSE_EVENT; + MOUSE_EVENT_RECORD &mer = newRecord.Event.MouseEvent; + + mer.dwMousePosition.X = + m_mouseWindowRect.Left + + std::max(0, std::min(record.coord.X, + m_mouseWindowRect.width() - 1)); + + mer.dwMousePosition.Y = + m_mouseWindowRect.Top + + std::max(0, std::min(record.coord.Y, + m_mouseWindowRect.height() - 1)); + + // The modifier state is neatly independent of everything else. + if (record.flags & 0x04) { mer.dwControlKeyState |= SHIFT_PRESSED; } + if (record.flags & 0x08) { mer.dwControlKeyState |= LEFT_ALT_PRESSED; } + if (record.flags & 0x10) { mer.dwControlKeyState |= LEFT_CTRL_PRESSED; } + + if (record.flags & 0x40) { + // Mouse wheel + mer.dwEventFlags |= MOUSE_WHEELED; + if (button == 0) { + // up + mer.dwButtonState |= 0x00780000; + } else if (button == 1) { + // down + mer.dwButtonState |= 0xff880000; + } else { + // Invalid -- do nothing + return len; + } + } else { + // Ordinary mouse event + if (record.flags & 0x20) { mer.dwEventFlags |= MOUSE_MOVED; } + if (button == 3) { + m_mouseButtonState = 0; + // Potentially advance double-click detection. + m_doubleClick.released = true; + } else { + const DWORD relevantFlag = + (button == 0) ? FROM_LEFT_1ST_BUTTON_PRESSED : + (button == 1) ? FROM_LEFT_2ND_BUTTON_PRESSED : + (button == 2) ? RIGHTMOST_BUTTON_PRESSED : + 0; + ASSERT(relevantFlag != 0); + if (record.release) { + m_mouseButtonState &= ~relevantFlag; + if (relevantFlag == m_doubleClick.button) { + // Potentially advance double-click detection. + m_doubleClick.released = true; + } else { + // End double-click detection. + m_doubleClick = DoubleClickDetection(); + } + } else if ((m_mouseButtonState & relevantFlag) == 0) { + // The button has been newly pressed. + m_mouseButtonState |= relevantFlag; + // Detect a double-click. This code looks for an exact + // coordinate match, which is stricter than what Windows does, + // but Windows has pixel coordinates, and we only have terminal + // coordinates. + if (m_doubleClick.button == relevantFlag && + m_doubleClick.pos == record.coord && + (GetTickCount() - m_doubleClick.tick < + GetDoubleClickTime())) { + // Record a double-click and end double-click detection. + mer.dwEventFlags |= DOUBLE_CLICK; + m_doubleClick = DoubleClickDetection(); + } else { + // Begin double-click detection. + m_doubleClick.button = relevantFlag; + m_doubleClick.pos = record.coord; + m_doubleClick.tick = GetTickCount(); + } + } + } + } + + mer.dwButtonState |= m_mouseButtonState; + + if (m_mouseInputEnabled && !m_quickEditEnabled) { + if (isTracingEnabled()) { + static bool debugInput = hasDebugFlag("input"); + if (debugInput) { + trace("mouse event: %s", mouseEventToString(mer).c_str()); + } + } + + records.push_back(newRecord); + } + + return len; +} + +void ConsoleInput::appendUtf8Char(std::vector &records, + const char *charBuffer, + const int charLen, + const bool terminalAltEscape) +{ + const uint32_t codePoint = decodeUtf8(charBuffer); + if (codePoint == static_cast(-1)) { + static bool debugInput = isTracingEnabled() && hasDebugFlag("input"); + if (debugInput) { + StringBuilder error(64); + error << "Discarding invalid UTF-8 sequence:"; + for (int i = 0; i < charLen; ++i) { + error << ' '; + error << hexOfInt(charBuffer[i]); + } + trace("%s", error.c_str()); + } + return; + } + + const short charScan = codePoint > 0xFFFF ? -1 : VkKeyScan(codePoint); + uint16_t virtualKey = 0; + uint16_t winKeyState = 0; + uint32_t winCodePointDn = codePoint; + uint32_t winCodePointUp = codePoint; + uint16_t vtKeyState = 0; + + if (charScan != -1) { + virtualKey = charScan & 0xFF; + if (charScan & 0x100) { + winKeyState |= SHIFT_PRESSED; + } + if (charScan & 0x200) { + winKeyState |= LEFT_CTRL_PRESSED; + } + if (charScan & 0x400) { + winKeyState |= RIGHT_ALT_PRESSED; + } + if (terminalAltEscape && (winKeyState & LEFT_CTRL_PRESSED)) { + // If the terminal escapes a Ctrl- with Alt, then set the + // codepoint to 0. On the other hand, if a character requires + // AltGr (like U+00B2 on a German layout), then VkKeyScan will + // report both Ctrl and Alt pressed, and we should keep the + // codepoint. See https://github.com/rprichard/winpty/issues/109. + winCodePointDn = 0; + winCodePointUp = 0; + } + } + if (terminalAltEscape) { + winCodePointUp = 0; + winKeyState |= LEFT_ALT_PRESSED; + vtKeyState |= LEFT_ALT_PRESSED; + } + + appendKeyPress(records, virtualKey, + winCodePointDn, winCodePointUp, winKeyState, + codePoint, vtKeyState); +} + +void ConsoleInput::appendKeyPress(std::vector &records, + const uint16_t virtualKey, + const uint32_t winCodePointDn, + const uint32_t winCodePointUp, + const uint16_t winKeyState, + const uint32_t vtCodePoint, + const uint16_t vtKeyState) +{ + const bool ctrl = (winKeyState & LEFT_CTRL_PRESSED) != 0; + const bool leftAlt = (winKeyState & LEFT_ALT_PRESSED) != 0; + const bool rightAlt = (winKeyState & RIGHT_ALT_PRESSED) != 0; + const bool shift = (winKeyState & SHIFT_PRESSED) != 0; + const bool enhanced = (winKeyState & ENHANCED_KEY) != 0; + bool hasDebugInput = false; + + if (isTracingEnabled()) { + static bool debugInput = hasDebugFlag("input"); + if (debugInput) { + hasDebugInput = true; + InputMap::Key key = { virtualKey, winCodePointDn, winKeyState }; + trace("keypress: %s", key.toString().c_str()); + } + } + + if (m_escapeInputEnabled && + (virtualKey == VK_UP || + virtualKey == VK_DOWN || + virtualKey == VK_LEFT || + virtualKey == VK_RIGHT || + virtualKey == VK_HOME || + virtualKey == VK_END) && + !ctrl && !leftAlt && !rightAlt && !shift) { + flushInputRecords(records); + if (hasDebugInput) { + trace("sending keypress to console HWND"); + } + sendKeyMessage(m_console.hwnd(), true, virtualKey); + sendKeyMessage(m_console.hwnd(), false, virtualKey); + return; + } + + uint16_t stepKeyState = 0; + if (ctrl) { + stepKeyState |= LEFT_CTRL_PRESSED; + appendInputRecord(records, TRUE, VK_CONTROL, 0, stepKeyState); + } + if (leftAlt) { + stepKeyState |= LEFT_ALT_PRESSED; + appendInputRecord(records, TRUE, VK_MENU, 0, stepKeyState); + } + if (rightAlt) { + stepKeyState |= RIGHT_ALT_PRESSED; + appendInputRecord(records, TRUE, VK_MENU, 0, stepKeyState | ENHANCED_KEY); + } + if (shift) { + stepKeyState |= SHIFT_PRESSED; + appendInputRecord(records, TRUE, VK_SHIFT, 0, stepKeyState); + } + if (enhanced) { + stepKeyState |= ENHANCED_KEY; + } + if (m_escapeInputEnabled) { + reencodeEscapedKeyPress(records, virtualKey, vtCodePoint, vtKeyState); + } else { + appendCPInputRecords(records, TRUE, virtualKey, winCodePointDn, stepKeyState); + } + appendCPInputRecords(records, FALSE, virtualKey, winCodePointUp, stepKeyState); + if (enhanced) { + stepKeyState &= ~ENHANCED_KEY; + } + if (shift) { + stepKeyState &= ~SHIFT_PRESSED; + appendInputRecord(records, FALSE, VK_SHIFT, 0, stepKeyState); + } + if (rightAlt) { + stepKeyState &= ~RIGHT_ALT_PRESSED; + appendInputRecord(records, FALSE, VK_MENU, 0, stepKeyState | ENHANCED_KEY); + } + if (leftAlt) { + stepKeyState &= ~LEFT_ALT_PRESSED; + appendInputRecord(records, FALSE, VK_MENU, 0, stepKeyState); + } + if (ctrl) { + stepKeyState &= ~LEFT_CTRL_PRESSED; + appendInputRecord(records, FALSE, VK_CONTROL, 0, stepKeyState); + } +} + +void ConsoleInput::appendCPInputRecords(std::vector &records, + BOOL keyDown, + uint16_t virtualKey, + uint32_t codePoint, + uint16_t keyState) +{ + // This behavior really doesn't match that of the Windows console (in + // normal, non-escape-mode). Judging by the copy-and-paste behavior, + // Windows apparently handles everything outside of the keyboard layout by + // first sending a sequence of Alt+KeyPad events, then finally a key-up + // event whose UnicodeChar has the appropriate value. For U+00A2 (CENT + // SIGN): + // + // key: dn rpt=1 scn=56 LAlt-MENU ch=0 + // key: dn rpt=1 scn=79 LAlt-NUMPAD1 ch=0 + // key: up rpt=1 scn=79 LAlt-NUMPAD1 ch=0 + // key: dn rpt=1 scn=76 LAlt-NUMPAD5 ch=0 + // key: up rpt=1 scn=76 LAlt-NUMPAD5 ch=0 + // key: dn rpt=1 scn=76 LAlt-NUMPAD5 ch=0 + // key: up rpt=1 scn=76 LAlt-NUMPAD5 ch=0 + // key: up rpt=1 scn=56 MENU ch=0xa2 + // + // The Alt+155 value matches the encoding of U+00A2 in CP-437. Curiously, + // if I use "chcp 1252" to change the encoding, then copy-and-pasting + // produces Alt+162 instead. (U+00A2 is 162 in CP-1252.) However, typing + // Alt+155 or Alt+162 produce the same characters regardless of console + // code page. (That is, they use CP-437 and yield U+00A2 and U+00F3.) + // + // For characters outside the BMP, Windows repeats the process for both + // UTF-16 code units, e.g, for U+1F300 (CYCLONE): + // + // key: dn rpt=1 scn=56 LAlt-MENU ch=0 + // key: dn rpt=1 scn=77 LAlt-NUMPAD6 ch=0 + // key: up rpt=1 scn=77 LAlt-NUMPAD6 ch=0 + // key: dn rpt=1 scn=81 LAlt-NUMPAD3 ch=0 + // key: up rpt=1 scn=81 LAlt-NUMPAD3 ch=0 + // key: up rpt=1 scn=56 MENU ch=0xd83c + // key: dn rpt=1 scn=56 LAlt-MENU ch=0 + // key: dn rpt=1 scn=77 LAlt-NUMPAD6 ch=0 + // key: up rpt=1 scn=77 LAlt-NUMPAD6 ch=0 + // key: dn rpt=1 scn=81 LAlt-NUMPAD3 ch=0 + // key: up rpt=1 scn=81 LAlt-NUMPAD3 ch=0 + // key: up rpt=1 scn=56 MENU ch=0xdf00 + // + // In this case, it sends Alt+63 twice, which signifies '?'. Apparently + // CMD and Cygwin bash are both able to decode this. + // + // Also note that typing Alt+NNN still works if NumLock is off, e.g.: + // + // key: dn rpt=1 scn=56 LAlt-MENU ch=0 + // key: dn rpt=1 scn=79 LAlt-END ch=0 + // key: up rpt=1 scn=79 LAlt-END ch=0 + // key: dn rpt=1 scn=76 LAlt-CLEAR ch=0 + // key: up rpt=1 scn=76 LAlt-CLEAR ch=0 + // key: dn rpt=1 scn=76 LAlt-CLEAR ch=0 + // key: up rpt=1 scn=76 LAlt-CLEAR ch=0 + // key: up rpt=1 scn=56 MENU ch=0xa2 + // + // Evidently, the Alt+NNN key events are not intended to be decoded to a + // character. Maybe programs are looking for a key-up ALT/MENU event with + // a non-zero character? + + wchar_t ws[2]; + const int wslen = encodeUtf16(ws, codePoint); + + if (wslen == 1) { + appendInputRecord(records, keyDown, virtualKey, ws[0], keyState); + } else if (wslen == 2) { + appendInputRecord(records, keyDown, virtualKey, ws[0], keyState); + appendInputRecord(records, keyDown, virtualKey, ws[1], keyState); + } else { + // This situation isn't that bad, but it should never happen, + // because invalid codepoints shouldn't reach this point. + trace("INTERNAL ERROR: appendInputRecordCP: invalid codePoint: " + "U+%04X", codePoint); + } +} + +void ConsoleInput::appendInputRecord(std::vector &records, + BOOL keyDown, + uint16_t virtualKey, + wchar_t utf16Char, + uint16_t keyState) +{ + INPUT_RECORD ir = {}; + ir.EventType = KEY_EVENT; + ir.Event.KeyEvent.bKeyDown = keyDown; + ir.Event.KeyEvent.wRepeatCount = 1; + ir.Event.KeyEvent.wVirtualKeyCode = virtualKey; + ir.Event.KeyEvent.wVirtualScanCode = + MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC); + ir.Event.KeyEvent.uChar.UnicodeChar = utf16Char; + ir.Event.KeyEvent.dwControlKeyState = keyState; + records.push_back(ir); +} + +DWORD ConsoleInput::inputConsoleMode() +{ + DWORD mode = 0; + if (!GetConsoleMode(m_conin, &mode)) { + trace("GetConsoleMode failed"); + return 0; + } + return mode; +} diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInput.h b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.h new file mode 100644 index 00000000000..e807d973ba5 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInput.h @@ -0,0 +1,109 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef CONSOLEINPUT_H +#define CONSOLEINPUT_H + +#include +#include + +#include +#include +#include + +#include "Coord.h" +#include "InputMap.h" +#include "SmallRect.h" + +class Win32Console; +class DsrSender; + +class ConsoleInput +{ +public: + ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender, + Win32Console &console); + void writeInput(const std::string &input); + void flushIncompleteEscapeCode(); + void setMouseWindowRect(SmallRect val) { m_mouseWindowRect = val; } + void updateInputFlags(bool forceTrace=false); + bool shouldActivateTerminalMouse(); + +private: + void doWrite(bool isEof); + void flushInputRecords(std::vector &records); + int scanInput(std::vector &records, + const char *input, + int inputSize, + bool isEof); + int scanMouseInput(std::vector &records, + const char *input, + int inputSize); + void appendUtf8Char(std::vector &records, + const char *charBuffer, + int charLen, + bool terminalAltEscape); + void appendKeyPress(std::vector &records, + uint16_t virtualKey, + uint32_t winCodePointDn, + uint32_t winCodePointUp, + uint16_t winKeyState, + uint32_t vtCodePoint, + uint16_t vtKeyState); + +public: + static void appendCPInputRecords(std::vector &records, + BOOL keyDown, + uint16_t virtualKey, + uint32_t codePoint, + uint16_t keyState); + static void appendInputRecord(std::vector &records, + BOOL keyDown, + uint16_t virtualKey, + wchar_t utf16Char, + uint16_t keyState); + +private: + DWORD inputConsoleMode(); + +private: + Win32Console &m_console; + HANDLE m_conin = nullptr; + int m_mouseMode = 0; + DsrSender &m_dsrSender; + bool m_dsrSent = false; + std::string m_byteQueue; + InputMap m_inputMap; + DWORD m_lastWriteTick = 0; + DWORD m_mouseButtonState = 0; + struct DoubleClickDetection { + DWORD button = 0; + Coord pos; + DWORD tick = 0; + bool released = false; + } m_doubleClick; + bool m_enableExtendedEnabled = false; + bool m_mouseInputEnabled = false; + bool m_quickEditEnabled = false; + bool m_escapeInputEnabled = false; + SmallRect m_mouseWindowRect; +}; + +#endif // CONSOLEINPUT_H diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc new file mode 100644 index 00000000000..b79545eea9c --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "ConsoleInputReencoding.h" + +#include "ConsoleInput.h" + +namespace { + +static void outch(std::vector &out, wchar_t ch) { + ConsoleInput::appendInputRecord(out, TRUE, 0, ch, 0); +} + +} // anonymous namespace + +void reencodeEscapedKeyPress( + std::vector &out, + uint16_t virtualKey, + uint32_t codePoint, + uint16_t keyState) { + + struct EscapedKey { + enum { None, Numeric, Letter } kind; + wchar_t content[2]; + }; + + EscapedKey escapeCode = {}; + switch (virtualKey) { + case VK_UP: escapeCode = { EscapedKey::Letter, {'A'} }; break; + case VK_DOWN: escapeCode = { EscapedKey::Letter, {'B'} }; break; + case VK_RIGHT: escapeCode = { EscapedKey::Letter, {'C'} }; break; + case VK_LEFT: escapeCode = { EscapedKey::Letter, {'D'} }; break; + case VK_CLEAR: escapeCode = { EscapedKey::Letter, {'E'} }; break; + case VK_F1: escapeCode = { EscapedKey::Numeric, {'1', '1'} }; break; + case VK_F2: escapeCode = { EscapedKey::Numeric, {'1', '2'} }; break; + case VK_F3: escapeCode = { EscapedKey::Numeric, {'1', '3'} }; break; + case VK_F4: escapeCode = { EscapedKey::Numeric, {'1', '4'} }; break; + case VK_F5: escapeCode = { EscapedKey::Numeric, {'1', '5'} }; break; + case VK_F6: escapeCode = { EscapedKey::Numeric, {'1', '7'} }; break; + case VK_F7: escapeCode = { EscapedKey::Numeric, {'1', '8'} }; break; + case VK_F8: escapeCode = { EscapedKey::Numeric, {'1', '9'} }; break; + case VK_F9: escapeCode = { EscapedKey::Numeric, {'2', '0'} }; break; + case VK_F10: escapeCode = { EscapedKey::Numeric, {'2', '1'} }; break; + case VK_F11: escapeCode = { EscapedKey::Numeric, {'2', '3'} }; break; + case VK_F12: escapeCode = { EscapedKey::Numeric, {'2', '4'} }; break; + case VK_HOME: escapeCode = { EscapedKey::Letter, {'H'} }; break; + case VK_INSERT: escapeCode = { EscapedKey::Numeric, {'2'} }; break; + case VK_DELETE: escapeCode = { EscapedKey::Numeric, {'3'} }; break; + case VK_END: escapeCode = { EscapedKey::Letter, {'F'} }; break; + case VK_PRIOR: escapeCode = { EscapedKey::Numeric, {'5'} }; break; + case VK_NEXT: escapeCode = { EscapedKey::Numeric, {'6'} }; break; + } + if (escapeCode.kind != EscapedKey::None) { + int flags = 0; + if (keyState & SHIFT_PRESSED) { flags |= 0x1; } + if (keyState & LEFT_ALT_PRESSED) { flags |= 0x2; } + if (keyState & LEFT_CTRL_PRESSED) { flags |= 0x4; } + outch(out, L'\x1b'); + outch(out, L'['); + if (escapeCode.kind == EscapedKey::Numeric) { + for (wchar_t ch : escapeCode.content) { + if (ch != L'\0') { + outch(out, ch); + } + } + } else if (flags != 0) { + outch(out, L'1'); + } + if (flags != 0) { + outch(out, L';'); + outch(out, L'1' + flags); + } + if (escapeCode.kind == EscapedKey::Numeric) { + outch(out, L'~'); + } else { + outch(out, escapeCode.content[0]); + } + return; + } + + switch (virtualKey) { + case VK_BACK: + if (keyState & LEFT_ALT_PRESSED) { + outch(out, L'\x1b'); + } + outch(out, L'\x7f'); + return; + case VK_TAB: + if (keyState & SHIFT_PRESSED) { + outch(out, L'\x1b'); + outch(out, L'['); + outch(out, L'Z'); + return; + } + break; + } + + if (codePoint != 0) { + if (keyState & LEFT_ALT_PRESSED) { + outch(out, L'\x1b'); + } + ConsoleInput::appendCPInputRecords(out, TRUE, 0, codePoint, 0); + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h new file mode 100644 index 00000000000..63bc006b5a7 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleInputReencoding.h @@ -0,0 +1,36 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef AGENT_CONSOLE_INPUT_REENCODING_H +#define AGENT_CONSOLE_INPUT_REENCODING_H + +#include + +#include + +#include + +void reencodeEscapedKeyPress( + std::vector &records, + uint16_t virtualKey, + uint32_t codePoint, + uint16_t keyState); + +#endif // AGENT_CONSOLE_INPUT_REENCODING_H diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc new file mode 100644 index 00000000000..1d2bcb76859 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// +// ConsoleLine +// +// This data structure keep tracks of the previous CHAR_INFO content of an +// output line and determines when a line has changed. Detecting line changes +// is made complicated by terminal resizing. +// + +#include "ConsoleLine.h" + +#include + +#include "../shared/WinptyAssert.h" + +static CHAR_INFO blankChar(WORD attributes) +{ + // N.B.: As long as we write to UnicodeChar rather than AsciiChar, there + // are no padding bytes that could contain uninitialized bytes. This fact + // is important for efficient comparison. + CHAR_INFO ret; + ret.Attributes = attributes; + ret.Char.UnicodeChar = L' '; + return ret; +} + +static bool isLineBlank(const CHAR_INFO *line, int length, WORD attributes) +{ + for (int col = 0; col < length; ++col) { + if (line[col].Attributes != attributes || + line[col].Char.UnicodeChar != L' ') { + return false; + } + } + return true; +} + +static inline bool areLinesEqual( + const CHAR_INFO *line1, + const CHAR_INFO *line2, + int length) +{ + return memcmp(line1, line2, sizeof(CHAR_INFO) * length) == 0; +} + +ConsoleLine::ConsoleLine() : m_prevLength(0) +{ +} + +void ConsoleLine::reset() +{ + m_prevLength = 0; + m_prevData.clear(); +} + +// Determines whether the given line is sufficiently different from the +// previously seen line as to justify reoutputting the line. The function +// also sets the `ConsoleLine` to the given line, exactly as if `setLine` had +// been called. +bool ConsoleLine::detectChangeAndSetLine(const CHAR_INFO *const line, const int newLength) +{ + ASSERT(newLength >= 1); + ASSERT(m_prevLength <= static_cast(m_prevData.size())); + + if (newLength == m_prevLength) { + bool equalLines = areLinesEqual(m_prevData.data(), line, newLength); + if (!equalLines) { + setLine(line, newLength); + } + return !equalLines; + } else { + if (m_prevLength == 0) { + setLine(line, newLength); + return true; + } + + ASSERT(m_prevLength >= 1); + const WORD prevBlank = m_prevData[m_prevLength - 1].Attributes; + const WORD newBlank = line[newLength - 1].Attributes; + + bool equalLines = false; + if (newLength < m_prevLength) { + // The line has become shorter. The lines are equal if the common + // part is equal, and if the newly truncated characters were blank. + equalLines = + areLinesEqual(m_prevData.data(), line, newLength) && + isLineBlank(m_prevData.data() + newLength, + m_prevLength - newLength, + newBlank); + } else { + // + // The line has become longer. The lines are equal if the common + // part is equal, and if both the extra characters and any + // potentially reexposed characters are blank. + // + // Two of the most relevant terminals for winpty--mintty and + // jediterm--don't (currently) erase the obscured content when a + // line is cleared, so we should anticipate its existence when + // making a terminal wider and reoutput the line. See: + // + // * https://github.com/mintty/mintty/issues/480 + // * https://github.com/JetBrains/jediterm/issues/118 + // + ASSERT(newLength > m_prevLength); + equalLines = + areLinesEqual(m_prevData.data(), line, m_prevLength) && + isLineBlank(m_prevData.data() + m_prevLength, + std::min(m_prevData.size(), newLength) - m_prevLength, + prevBlank) && + isLineBlank(line + m_prevLength, + newLength - m_prevLength, + prevBlank); + } + setLine(line, newLength); + return !equalLines; + } +} + +void ConsoleLine::setLine(const CHAR_INFO *const line, const int newLength) +{ + if (static_cast(m_prevData.size()) < newLength) { + m_prevData.resize(newLength); + } + memcpy(m_prevData.data(), line, sizeof(CHAR_INFO) * newLength); + m_prevLength = newLength; +} + +void ConsoleLine::blank(WORD attributes) +{ + m_prevData.resize(1); + m_prevData[0] = blankChar(attributes); + m_prevLength = 1; +} diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleLine.h b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.h new file mode 100644 index 00000000000..802c189c756 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.h @@ -0,0 +1,41 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef CONSOLE_LINE_H +#define CONSOLE_LINE_H + +#include + +#include + +class ConsoleLine +{ +public: + ConsoleLine(); + void reset(); + bool detectChangeAndSetLine(const CHAR_INFO *line, int newLength); + void setLine(const CHAR_INFO *line, int newLength); + void blank(WORD attributes); +private: + int m_prevLength; + std::vector m_prevData; +}; + +#endif // CONSOLE_LINE_H diff --git a/src/libs/3rdparty/winpty/src/agent/Coord.h b/src/libs/3rdparty/winpty/src/agent/Coord.h new file mode 100644 index 00000000000..74c98addac6 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Coord.h @@ -0,0 +1,87 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef COORD_H +#define COORD_H + +#include + +#include + +#include "../shared/winpty_snprintf.h" + +struct Coord : COORD { + Coord() + { + X = 0; + Y = 0; + } + + Coord(SHORT x, SHORT y) + { + X = x; + Y = y; + } + + Coord(COORD other) + { + *(COORD*)this = other; + } + + Coord(const Coord &other) + { + *(COORD*)this = *(const COORD*)&other; + } + + Coord &operator=(const Coord &other) + { + *(COORD*)this = *(const COORD*)&other; + return *this; + } + + bool operator==(const Coord &other) const + { + return X == other.X && Y == other.Y; + } + + bool operator!=(const Coord &other) const + { + return !(*this == other); + } + + Coord operator+(const Coord &other) const + { + return Coord(X + other.X, Y + other.Y); + } + + bool isEmpty() const + { + return X <= 0 || Y <= 0; + } + + std::string toString() const + { + char ret[32]; + winpty_snprintf(ret, "(%d,%d)", X, Y); + return std::string(ret); + } +}; + +#endif // COORD_H diff --git a/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc new file mode 100644 index 00000000000..191b2e1466a --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc @@ -0,0 +1,239 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "DebugShowInput.h" + +#include +#include +#include +#include + +#include + +#include "../shared/StringBuilder.h" +#include "InputMap.h" + +namespace { + +struct Flag { + DWORD value; + const char *text; +}; + +static const Flag kButtonStates[] = { + { FROM_LEFT_1ST_BUTTON_PRESSED, "1" }, + { FROM_LEFT_2ND_BUTTON_PRESSED, "2" }, + { FROM_LEFT_3RD_BUTTON_PRESSED, "3" }, + { FROM_LEFT_4TH_BUTTON_PRESSED, "4" }, + { RIGHTMOST_BUTTON_PRESSED, "R" }, +}; + +static const Flag kControlKeyStates[] = { + { CAPSLOCK_ON, "CapsLock" }, + { ENHANCED_KEY, "Enhanced" }, + { LEFT_ALT_PRESSED, "LAlt" }, + { LEFT_CTRL_PRESSED, "LCtrl" }, + { NUMLOCK_ON, "NumLock" }, + { RIGHT_ALT_PRESSED, "RAlt" }, + { RIGHT_CTRL_PRESSED, "RCtrl" }, + { SCROLLLOCK_ON, "ScrollLock" }, + { SHIFT_PRESSED, "Shift" }, +}; + +static const Flag kMouseEventFlags[] = { + { DOUBLE_CLICK, "Double" }, + { 8/*MOUSE_HWHEELED*/, "HWheel" }, + { MOUSE_MOVED, "Move" }, + { MOUSE_WHEELED, "Wheel" }, +}; + +static void writeFlags(StringBuilder &out, DWORD flags, + const char *remainderName, + const Flag *table, size_t tableSize, + char pre, char sep, char post) { + DWORD remaining = flags; + bool wroteSomething = false; + for (size_t i = 0; i < tableSize; ++i) { + const Flag &f = table[i]; + if ((f.value & flags) == f.value) { + if (!wroteSomething && pre != '\0') { + out << pre; + } else if (wroteSomething && sep != '\0') { + out << sep; + } + out << f.text; + wroteSomething = true; + remaining &= ~f.value; + } + } + if (remaining != 0) { + if (!wroteSomething && pre != '\0') { + out << pre; + } else if (wroteSomething && sep != '\0') { + out << sep; + } + out << remainderName << "(0x" << hexOfInt(remaining) << ')'; + wroteSomething = true; + } + if (wroteSomething && post != '\0') { + out << post; + } +} + +template +static void writeFlags(StringBuilder &out, DWORD flags, + const char *remainderName, + const Flag (&table)[n], + char pre, char sep, char post) { + writeFlags(out, flags, remainderName, table, n, pre, sep, post); +} + +} // anonymous namespace + +std::string controlKeyStatePrefix(DWORD controlKeyState) { + StringBuilder sb; + writeFlags(sb, controlKeyState, + "keyState", kControlKeyStates, '\0', '-', '-'); + return sb.str_moved(); +} + +std::string mouseEventToString(const MOUSE_EVENT_RECORD &mer) { + const uint16_t buttons = mer.dwButtonState & 0xFFFF; + const int16_t wheel = mer.dwButtonState >> 16; + StringBuilder sb; + sb << "pos=" << mer.dwMousePosition.X << ',' + << mer.dwMousePosition.Y; + writeFlags(sb, mer.dwControlKeyState, "keyState", kControlKeyStates, ' ', ' ', '\0'); + writeFlags(sb, mer.dwEventFlags, "flags", kMouseEventFlags, ' ', ' ', '\0'); + writeFlags(sb, buttons, "buttons", kButtonStates, ' ', ' ', '\0'); + if (wheel != 0) { + sb << " wheel=" << wheel; + } + return sb.str_moved(); +} + +void debugShowInput(bool enableMouse, bool escapeInput) { + HANDLE conin = GetStdHandle(STD_INPUT_HANDLE); + DWORD origConsoleMode = 0; + if (!GetConsoleMode(conin, &origConsoleMode)) { + fprintf(stderr, "Error: could not read console mode -- " + "is STDIN a console handle?\n"); + exit(1); + } + DWORD restoreConsoleMode = origConsoleMode; + if (enableMouse && !(restoreConsoleMode & ENABLE_EXTENDED_FLAGS)) { + // We need to disable QuickEdit mode, because it blocks mouse events. + // If ENABLE_EXTENDED_FLAGS wasn't originally in the console mode, then + // we have no way of knowning whether QuickEdit or InsertMode are + // currently enabled. Enable them both (eventually), because they're + // sensible defaults. This case shouldn't happen typically. See + // misc/EnableExtendedFlags.txt. + restoreConsoleMode |= ENABLE_EXTENDED_FLAGS; + restoreConsoleMode |= ENABLE_QUICK_EDIT_MODE; + restoreConsoleMode |= ENABLE_INSERT_MODE; + } + DWORD newConsoleMode = restoreConsoleMode; + newConsoleMode &= ~ENABLE_PROCESSED_INPUT; + newConsoleMode &= ~ENABLE_LINE_INPUT; + newConsoleMode &= ~ENABLE_ECHO_INPUT; + newConsoleMode |= ENABLE_WINDOW_INPUT; + if (enableMouse) { + newConsoleMode |= ENABLE_MOUSE_INPUT; + newConsoleMode &= ~ENABLE_QUICK_EDIT_MODE; + } else { + newConsoleMode &= ~ENABLE_MOUSE_INPUT; + } + if (escapeInput) { + // As of this writing (2016-06-05), Microsoft has shipped two preview + // builds of Windows 10 (14316 and 14342) that include a new "Windows + // Subsystem for Linux" that runs Ubuntu in a new subsystem. Running + // bash in this subsystem requires the non-legacy console mode, and the + // console input buffer is put into a special mode where escape + // sequences are written into the console input buffer. This mode is + // enabled with the 0x200 flag, which is as-yet undocumented. + // See https://github.com/rprichard/winpty/issues/82. + newConsoleMode |= 0x200; + } + if (!SetConsoleMode(conin, newConsoleMode)) { + fprintf(stderr, "Error: could not set console mode " + "(0x%x -> 0x%x -> 0x%x)\n", + static_cast(origConsoleMode), + static_cast(newConsoleMode), + static_cast(restoreConsoleMode)); + exit(1); + } + printf("\nPress any keys -- Ctrl-D exits\n\n"); + INPUT_RECORD records[32]; + DWORD actual = 0; + bool finished = false; + while (!finished && + ReadConsoleInputW(conin, records, 32, &actual) && actual >= 1) { + StringBuilder sb; + for (DWORD i = 0; i < actual; ++i) { + const INPUT_RECORD &record = records[i]; + if (record.EventType == KEY_EVENT) { + const KEY_EVENT_RECORD &ker = record.Event.KeyEvent; + InputMap::Key key = { + ker.wVirtualKeyCode, + ker.uChar.UnicodeChar, + static_cast(ker.dwControlKeyState), + }; + sb << "key: " << (ker.bKeyDown ? "dn" : "up") + << " rpt=" << ker.wRepeatCount + << " scn=" << (ker.wVirtualScanCode ? "0x" : "") << hexOfInt(ker.wVirtualScanCode) + << ' ' << key.toString() << '\n'; + if ((ker.dwControlKeyState & + (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) && + ker.wVirtualKeyCode == 'D') { + finished = true; + break; + } else if (ker.wVirtualKeyCode == 0 && + ker.wVirtualScanCode == 0 && + ker.uChar.UnicodeChar == 4) { + // Also look for a zeroed-out Ctrl-D record generated for + // ENABLE_VIRTUAL_TERMINAL_INPUT. + finished = true; + break; + } + } else if (record.EventType == MOUSE_EVENT) { + const MOUSE_EVENT_RECORD &mer = record.Event.MouseEvent; + sb << "mouse: " << mouseEventToString(mer) << '\n'; + } else if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) { + const WINDOW_BUFFER_SIZE_RECORD &wbsr = + record.Event.WindowBufferSizeEvent; + sb << "buffer-resized: dwSize=(" + << wbsr.dwSize.X << ',' + << wbsr.dwSize.Y << ")\n"; + } else if (record.EventType == MENU_EVENT) { + const MENU_EVENT_RECORD &mer = record.Event.MenuEvent; + sb << "menu-event: commandId=0x" + << hexOfInt(mer.dwCommandId) << '\n'; + } else if (record.EventType == FOCUS_EVENT) { + const FOCUS_EVENT_RECORD &fer = record.Event.FocusEvent; + sb << "focus: " << (fer.bSetFocus ? "gained" : "lost") << '\n'; + } + } + + const auto str = sb.str_moved(); + fwrite(str.data(), 1, str.size(), stdout); + fflush(stdout); + } + SetConsoleMode(conin, restoreConsoleMode); +} diff --git a/src/libs/3rdparty/winpty/src/agent/DebugShowInput.h b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.h new file mode 100644 index 00000000000..4fa13604bd4 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.h @@ -0,0 +1,32 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef AGENT_DEBUG_SHOW_INPUT_H +#define AGENT_DEBUG_SHOW_INPUT_H + +#include + +#include + +std::string controlKeyStatePrefix(DWORD controlKeyState); +std::string mouseEventToString(const MOUSE_EVENT_RECORD &mer); +void debugShowInput(bool enableMouse, bool escapeInput); + +#endif // AGENT_DEBUG_SHOW_INPUT_H diff --git a/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc new file mode 100644 index 00000000000..5e29d98e4ec --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.cc @@ -0,0 +1,422 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "DefaultInputMap.h" + +#include +#include + +#include + +#include "../shared/StringBuilder.h" +#include "../shared/WinptyAssert.h" +#include "InputMap.h" + +#define ESC "\x1B" +#define DIM(x) (sizeof(x) / sizeof((x)[0])) + +namespace { + +struct EscapeEncoding { + bool alt_prefix_allowed; + char prefix; + char id; + int modifiers; + InputMap::Key key; +}; + +// Modifiers. A "modifier" is an integer from 2 to 8 that conveys the status +// of Shift(1), Alt(2), and Ctrl(4). The value is constructed by OR'ing the +// appropriate value for each active modifier, then adding 1. +// +// Details: +// - kBare: expands to: ESC +// - kSemiMod: expands to: ESC ; +// - kBareMod: expands to: ESC +const int kBare = 0x01; +const int kSemiMod = 0x02; +const int kBareMod = 0x04; + +// Numeric escape sequences suffixes: +// - with no flag: accept: ~ +// - kSuffixCtrl: accept: ~ ^ +// - kSuffixShift: accept: ~ $ +// - kSuffixBoth: accept: ~ ^ $ @ +const int kSuffixCtrl = 0x08; +const int kSuffixShift = 0x10; +const int kSuffixBoth = kSuffixCtrl | kSuffixShift; + +static const EscapeEncoding escapeLetterEncodings[] = { + // Conventional arrow keys + // kBareMod: Ubuntu /etc/inputrc and IntelliJ/JediTerm use escapes like: ESC [ n ABCD + { true, '[', 'A', kBare | kBareMod | kSemiMod, { VK_UP, '\0', 0 } }, + { true, '[', 'B', kBare | kBareMod | kSemiMod, { VK_DOWN, '\0', 0 } }, + { true, '[', 'C', kBare | kBareMod | kSemiMod, { VK_RIGHT, '\0', 0 } }, + { true, '[', 'D', kBare | kBareMod | kSemiMod, { VK_LEFT, '\0', 0 } }, + + // putty. putty uses this sequence for Ctrl-Arrow, Shift-Arrow, and + // Ctrl-Shift-Arrow, but I can only decode to one choice, so I'm just + // leaving the modifier off altogether. + { true, 'O', 'A', kBare, { VK_UP, '\0', 0 } }, + { true, 'O', 'B', kBare, { VK_DOWN, '\0', 0 } }, + { true, 'O', 'C', kBare, { VK_RIGHT, '\0', 0 } }, + { true, 'O', 'D', kBare, { VK_LEFT, '\0', 0 } }, + + // rxvt, rxvt-unicode + // Shift-Ctrl-Arrow can't be identified. It's the same as Shift-Arrow. + { true, '[', 'a', kBare, { VK_UP, '\0', SHIFT_PRESSED } }, + { true, '[', 'b', kBare, { VK_DOWN, '\0', SHIFT_PRESSED } }, + { true, '[', 'c', kBare, { VK_RIGHT, '\0', SHIFT_PRESSED } }, + { true, '[', 'd', kBare, { VK_LEFT, '\0', SHIFT_PRESSED } }, + { true, 'O', 'a', kBare, { VK_UP, '\0', LEFT_CTRL_PRESSED } }, + { true, 'O', 'b', kBare, { VK_DOWN, '\0', LEFT_CTRL_PRESSED } }, + { true, 'O', 'c', kBare, { VK_RIGHT, '\0', LEFT_CTRL_PRESSED } }, + { true, 'O', 'd', kBare, { VK_LEFT, '\0', LEFT_CTRL_PRESSED } }, + + // Numpad 5 with NumLock off + // * xterm, mintty, and gnome-terminal use `ESC [ E`. + // * putty, TERM=cygwin, TERM=linux all use `ESC [ G` for 5 + // * putty uses `ESC O G` for Ctrl-5 and Shift-5. Omit the modifier + // as with putty's arrow keys. + // * I never saw modifiers inserted into these escapes, but I think + // it should be completely OK with the CSI escapes. + { true, '[', 'E', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } }, + { true, '[', 'G', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } }, + { true, 'O', 'G', kBare, { VK_CLEAR, '\0', 0 } }, + + // Home/End, letter version + // * gnome-terminal uses `ESC O [HF]`. I never saw it modified. + // kBareMod: IntelliJ/JediTerm uses escapes like: ESC [ n HF + { true, '[', 'H', kBare | kBareMod | kSemiMod, { VK_HOME, '\0', 0 } }, + { true, '[', 'F', kBare | kBareMod | kSemiMod, { VK_END, '\0', 0 } }, + { true, 'O', 'H', kBare, { VK_HOME, '\0', 0 } }, + { true, 'O', 'F', kBare, { VK_END, '\0', 0 } }, + + // F1-F4, letter version (xterm, VTE, konsole) + { true, '[', 'P', kSemiMod, { VK_F1, '\0', 0 } }, + { true, '[', 'Q', kSemiMod, { VK_F2, '\0', 0 } }, + { true, '[', 'R', kSemiMod, { VK_F3, '\0', 0 } }, + { true, '[', 'S', kSemiMod, { VK_F4, '\0', 0 } }, + + // GNOME VTE and Konsole have special encodings for modified F1-F4: + // * [VTE] ESC O 1 ; n [PQRS] + // * [Konsole] ESC O n [PQRS] + { false, 'O', 'P', kBare | kBareMod | kSemiMod, { VK_F1, '\0', 0 } }, + { false, 'O', 'Q', kBare | kBareMod | kSemiMod, { VK_F2, '\0', 0 } }, + { false, 'O', 'R', kBare | kBareMod | kSemiMod, { VK_F3, '\0', 0 } }, + { false, 'O', 'S', kBare | kBareMod | kSemiMod, { VK_F4, '\0', 0 } }, + + // Handle the "application numpad" escape sequences. + // + // Terminals output these codes under various circumstances: + // * rxvt-unicode: numpad, hold down SHIFT + // * rxvt: numpad, by default + // * xterm: numpad, after enabling app-mode using DECPAM (`ESC =`). xterm + // generates `ESC O ` for modified numpad presses, + // necessitating kBareMod. + // * mintty: by combining Ctrl with various keys such as '1' or ','. + // Handling those keys is difficult, because mintty is generating the + // same sequence for Ctrl-1 and Ctrl-NumPadEnd -- should the virtualKey + // be '1' or VK_HOME? + + { true, 'O', 'M', kBare | kBareMod, { VK_RETURN, '\r', 0 } }, + { true, 'O', 'j', kBare | kBareMod, { VK_MULTIPLY, '*', 0 } }, + { true, 'O', 'k', kBare | kBareMod, { VK_ADD, '+', 0 } }, + { true, 'O', 'm', kBare | kBareMod, { VK_SUBTRACT, '-', 0 } }, + { true, 'O', 'n', kBare | kBareMod, { VK_DELETE, '\0', 0 } }, + { true, 'O', 'o', kBare | kBareMod, { VK_DIVIDE, '/', 0 } }, + { true, 'O', 'p', kBare | kBareMod, { VK_INSERT, '\0', 0 } }, + { true, 'O', 'q', kBare | kBareMod, { VK_END, '\0', 0 } }, + { true, 'O', 'r', kBare | kBareMod, { VK_DOWN, '\0', 0 } }, + { true, 'O', 's', kBare | kBareMod, { VK_NEXT, '\0', 0 } }, + { true, 'O', 't', kBare | kBareMod, { VK_LEFT, '\0', 0 } }, + { true, 'O', 'u', kBare | kBareMod, { VK_CLEAR, '\0', 0 } }, + { true, 'O', 'v', kBare | kBareMod, { VK_RIGHT, '\0', 0 } }, + { true, 'O', 'w', kBare | kBareMod, { VK_HOME, '\0', 0 } }, + { true, 'O', 'x', kBare | kBareMod, { VK_UP, '\0', 0 } }, + { true, 'O', 'y', kBare | kBareMod, { VK_PRIOR, '\0', 0 } }, + + { true, '[', 'M', kBare | kSemiMod, { VK_RETURN, '\r', 0 } }, + { true, '[', 'j', kBare | kSemiMod, { VK_MULTIPLY, '*', 0 } }, + { true, '[', 'k', kBare | kSemiMod, { VK_ADD, '+', 0 } }, + { true, '[', 'm', kBare | kSemiMod, { VK_SUBTRACT, '-', 0 } }, + { true, '[', 'n', kBare | kSemiMod, { VK_DELETE, '\0', 0 } }, + { true, '[', 'o', kBare | kSemiMod, { VK_DIVIDE, '/', 0 } }, + { true, '[', 'p', kBare | kSemiMod, { VK_INSERT, '\0', 0 } }, + { true, '[', 'q', kBare | kSemiMod, { VK_END, '\0', 0 } }, + { true, '[', 'r', kBare | kSemiMod, { VK_DOWN, '\0', 0 } }, + { true, '[', 's', kBare | kSemiMod, { VK_NEXT, '\0', 0 } }, + { true, '[', 't', kBare | kSemiMod, { VK_LEFT, '\0', 0 } }, + { true, '[', 'u', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } }, + { true, '[', 'v', kBare | kSemiMod, { VK_RIGHT, '\0', 0 } }, + { true, '[', 'w', kBare | kSemiMod, { VK_HOME, '\0', 0 } }, + { true, '[', 'x', kBare | kSemiMod, { VK_UP, '\0', 0 } }, + { true, '[', 'y', kBare | kSemiMod, { VK_PRIOR, '\0', 0 } }, + + { false, '[', 'Z', kBare, { VK_TAB, '\t', SHIFT_PRESSED } }, +}; + +static const EscapeEncoding escapeNumericEncodings[] = { + { true, '[', 1, kBare | kSemiMod | kSuffixBoth, { VK_HOME, '\0', 0 } }, + { true, '[', 2, kBare | kSemiMod | kSuffixBoth, { VK_INSERT, '\0', 0 } }, + { true, '[', 3, kBare | kSemiMod | kSuffixBoth, { VK_DELETE, '\0', 0 } }, + { true, '[', 4, kBare | kSemiMod | kSuffixBoth, { VK_END, '\0', 0 } }, + { true, '[', 5, kBare | kSemiMod | kSuffixBoth, { VK_PRIOR, '\0', 0 } }, + { true, '[', 6, kBare | kSemiMod | kSuffixBoth, { VK_NEXT, '\0', 0 } }, + { true, '[', 7, kBare | kSemiMod | kSuffixBoth, { VK_HOME, '\0', 0 } }, + { true, '[', 8, kBare | kSemiMod | kSuffixBoth, { VK_END, '\0', 0 } }, + { true, '[', 11, kBare | kSemiMod | kSuffixBoth, { VK_F1, '\0', 0 } }, + { true, '[', 12, kBare | kSemiMod | kSuffixBoth, { VK_F2, '\0', 0 } }, + { true, '[', 13, kBare | kSemiMod | kSuffixBoth, { VK_F3, '\0', 0 } }, + { true, '[', 14, kBare | kSemiMod | kSuffixBoth, { VK_F4, '\0', 0 } }, + { true, '[', 15, kBare | kSemiMod | kSuffixBoth, { VK_F5, '\0', 0 } }, + { true, '[', 17, kBare | kSemiMod | kSuffixBoth, { VK_F6, '\0', 0 } }, + { true, '[', 18, kBare | kSemiMod | kSuffixBoth, { VK_F7, '\0', 0 } }, + { true, '[', 19, kBare | kSemiMod | kSuffixBoth, { VK_F8, '\0', 0 } }, + { true, '[', 20, kBare | kSemiMod | kSuffixBoth, { VK_F9, '\0', 0 } }, + { true, '[', 21, kBare | kSemiMod | kSuffixBoth, { VK_F10, '\0', 0 } }, + { true, '[', 23, kBare | kSemiMod | kSuffixBoth, { VK_F11, '\0', 0 } }, + { true, '[', 24, kBare | kSemiMod | kSuffixBoth, { VK_F12, '\0', 0 } }, + { true, '[', 25, kBare | kSemiMod | kSuffixBoth, { VK_F3, '\0', SHIFT_PRESSED } }, + { true, '[', 26, kBare | kSemiMod | kSuffixBoth, { VK_F4, '\0', SHIFT_PRESSED } }, + { true, '[', 28, kBare | kSemiMod | kSuffixBoth, { VK_F5, '\0', SHIFT_PRESSED } }, + { true, '[', 29, kBare | kSemiMod | kSuffixBoth, { VK_F6, '\0', SHIFT_PRESSED } }, + { true, '[', 31, kBare | kSemiMod | kSuffixBoth, { VK_F7, '\0', SHIFT_PRESSED } }, + { true, '[', 32, kBare | kSemiMod | kSuffixBoth, { VK_F8, '\0', SHIFT_PRESSED } }, + { true, '[', 33, kBare | kSemiMod | kSuffixBoth, { VK_F9, '\0', SHIFT_PRESSED } }, + { true, '[', 34, kBare | kSemiMod | kSuffixBoth, { VK_F10, '\0', SHIFT_PRESSED } }, +}; + +const int kCsiShiftModifier = 1; +const int kCsiAltModifier = 2; +const int kCsiCtrlModifier = 4; + +static inline bool useEnhancedForVirtualKey(uint16_t vk) { + switch (vk) { + case VK_UP: + case VK_DOWN: + case VK_LEFT: + case VK_RIGHT: + case VK_INSERT: + case VK_DELETE: + case VK_HOME: + case VK_END: + case VK_PRIOR: + case VK_NEXT: + return true; + default: + return false; + } +} + +static void addSimpleEntries(InputMap &inputMap) { + struct SimpleEncoding { + const char *encoding; + InputMap::Key key; + }; + + static const SimpleEncoding simpleEncodings[] = { + // Ctrl- seems to be handled OK by the default code path. + + { "\x7F", { VK_BACK, '\x08', 0, } }, + { ESC "\x7F", { VK_BACK, '\x08', LEFT_ALT_PRESSED, } }, + { "\x03", { 'C', '\x03', LEFT_CTRL_PRESSED, } }, + + // Handle special F1-F5 for TERM=linux and TERM=cygwin. + { ESC "[[A", { VK_F1, '\0', 0 } }, + { ESC "[[B", { VK_F2, '\0', 0 } }, + { ESC "[[C", { VK_F3, '\0', 0 } }, + { ESC "[[D", { VK_F4, '\0', 0 } }, + { ESC "[[E", { VK_F5, '\0', 0 } }, + + { ESC ESC "[[A", { VK_F1, '\0', LEFT_ALT_PRESSED } }, + { ESC ESC "[[B", { VK_F2, '\0', LEFT_ALT_PRESSED } }, + { ESC ESC "[[C", { VK_F3, '\0', LEFT_ALT_PRESSED } }, + { ESC ESC "[[D", { VK_F4, '\0', LEFT_ALT_PRESSED } }, + { ESC ESC "[[E", { VK_F5, '\0', LEFT_ALT_PRESSED } }, + }; + + for (size_t i = 0; i < DIM(simpleEncodings); ++i) { + auto k = simpleEncodings[i].key; + if (useEnhancedForVirtualKey(k.virtualKey)) { + k.keyState |= ENHANCED_KEY; + } + inputMap.set(simpleEncodings[i].encoding, + strlen(simpleEncodings[i].encoding), + k); + } +} + +struct ExpandContext { + InputMap &inputMap; + const EscapeEncoding &e; + char *buffer; + char *bufferEnd; +}; + +static inline void setEncoding(const ExpandContext &ctx, char *end, + uint16_t extraKeyState) { + InputMap::Key k = ctx.e.key; + k.keyState |= extraKeyState; + if (k.keyState & LEFT_CTRL_PRESSED) { + switch (k.virtualKey) { + case VK_ADD: + case VK_DIVIDE: + case VK_MULTIPLY: + case VK_SUBTRACT: + k.unicodeChar = '\0'; + break; + case VK_RETURN: + k.unicodeChar = '\n'; + break; + } + } + if (useEnhancedForVirtualKey(k.virtualKey)) { + k.keyState |= ENHANCED_KEY; + } + ctx.inputMap.set(ctx.buffer, end - ctx.buffer, k); +} + +static inline uint16_t keyStateForMod(int mod) { + int ret = 0; + if ((mod - 1) & kCsiShiftModifier) ret |= SHIFT_PRESSED; + if ((mod - 1) & kCsiAltModifier) ret |= LEFT_ALT_PRESSED; + if ((mod - 1) & kCsiCtrlModifier) ret |= LEFT_CTRL_PRESSED; + return ret; +} + +static void expandNumericEncodingSuffix(const ExpandContext &ctx, char *p, + uint16_t extraKeyState) { + ASSERT(p <= ctx.bufferEnd - 1); + { + char *q = p; + *q++ = '~'; + setEncoding(ctx, q, extraKeyState); + } + if (ctx.e.modifiers & kSuffixShift) { + char *q = p; + *q++ = '$'; + setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED); + } + if (ctx.e.modifiers & kSuffixCtrl) { + char *q = p; + *q++ = '^'; + setEncoding(ctx, q, extraKeyState | LEFT_CTRL_PRESSED); + } + if (ctx.e.modifiers & (kSuffixCtrl | kSuffixShift)) { + char *q = p; + *q++ = '@'; + setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED | LEFT_CTRL_PRESSED); + } +} + +template +static inline void expandEncodingAfterAltPrefix( + const ExpandContext &ctx, char *p, uint16_t extraKeyState) { + auto appendId = [&](char *&ptr) { + const auto idstr = decOfInt(ctx.e.id); + ASSERT(ptr <= ctx.bufferEnd - idstr.size()); + std::copy(idstr.data(), idstr.data() + idstr.size(), ptr); + ptr += idstr.size(); + }; + ASSERT(p <= ctx.bufferEnd - 2); + *p++ = '\x1b'; + *p++ = ctx.e.prefix; + if (ctx.e.modifiers & kBare) { + char *q = p; + if (is_numeric) { + appendId(q); + expandNumericEncodingSuffix(ctx, q, extraKeyState); + } else { + ASSERT(q <= ctx.bufferEnd - 1); + *q++ = ctx.e.id; + setEncoding(ctx, q, extraKeyState); + } + } + if (ctx.e.modifiers & kBareMod) { + ASSERT(!is_numeric && "kBareMod is invalid with numeric sequences"); + for (int mod = 2; mod <= 8; ++mod) { + char *q = p; + ASSERT(q <= ctx.bufferEnd - 2); + *q++ = '0' + mod; + *q++ = ctx.e.id; + setEncoding(ctx, q, extraKeyState | keyStateForMod(mod)); + } + } + if (ctx.e.modifiers & kSemiMod) { + for (int mod = 2; mod <= 8; ++mod) { + char *q = p; + if (is_numeric) { + appendId(q); + ASSERT(q <= ctx.bufferEnd - 2); + *q++ = ';'; + *q++ = '0' + mod; + expandNumericEncodingSuffix( + ctx, q, extraKeyState | keyStateForMod(mod)); + } else { + ASSERT(q <= ctx.bufferEnd - 4); + *q++ = '1'; + *q++ = ';'; + *q++ = '0' + mod; + *q++ = ctx.e.id; + setEncoding(ctx, q, extraKeyState | keyStateForMod(mod)); + } + } + } +} + +template +static inline void expandEncoding(const ExpandContext &ctx) { + if (ctx.e.alt_prefix_allowed) { + // For better or for worse, this code expands all of: + // * ESC [ -- + // * ESC ESC [ -- Alt- + // * ESC [ 1 ; 3 -- Alt- + // * ESC ESC [ 1 ; 3 -- Alt- specified twice + // I suspect no terminal actually emits the last one (i.e. specifying + // the Alt modifier using both methods), but I have seen a terminal + // that emitted a prefix ESC for Alt and a non-Alt modifier. + char *p = ctx.buffer; + ASSERT(p <= ctx.bufferEnd - 1); + *p++ = '\x1b'; + expandEncodingAfterAltPrefix(ctx, p, LEFT_ALT_PRESSED); + } + expandEncodingAfterAltPrefix(ctx, ctx.buffer, 0); +} + +template +static void addEscapes(InputMap &inputMap, const EscapeEncoding (&encodings)[N]) { + char buffer[32]; + for (size_t i = 0; i < DIM(encodings); ++i) { + ExpandContext ctx = { + inputMap, encodings[i], + buffer, buffer + sizeof(buffer) + }; + expandEncoding(ctx); + } +} + +} // anonymous namespace + +void addDefaultEntriesToInputMap(InputMap &inputMap) { + addEscapes(inputMap, escapeLetterEncodings); + addEscapes(inputMap, escapeNumericEncodings); + addSimpleEntries(inputMap); +} diff --git a/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h new file mode 100644 index 00000000000..c4b90836788 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/DefaultInputMap.h @@ -0,0 +1,28 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef DEFAULT_INPUT_MAP_H +#define DEFAULT_INPUT_MAP_H + +class InputMap; + +void addDefaultEntriesToInputMap(InputMap &inputMap); + +#endif // DEFAULT_INPUT_MAP_H diff --git a/src/libs/3rdparty/winpty/src/agent/DsrSender.h b/src/libs/3rdparty/winpty/src/agent/DsrSender.h new file mode 100644 index 00000000000..1ec0a97d2e2 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/DsrSender.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef DSRSENDER_H +#define DSRSENDER_H + +class DsrSender +{ +public: + virtual void sendDsr() = 0; +}; + +#endif // DSRSENDER_H diff --git a/src/libs/3rdparty/winpty/src/agent/EventLoop.cc b/src/libs/3rdparty/winpty/src/agent/EventLoop.cc new file mode 100644 index 00000000000..ba5cf18cc8a --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/EventLoop.cc @@ -0,0 +1,99 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "EventLoop.h" + +#include + +#include "NamedPipe.h" +#include "../shared/DebugClient.h" +#include "../shared/WinptyAssert.h" + +EventLoop::~EventLoop() { + for (NamedPipe *pipe : m_pipes) { + delete pipe; + } + m_pipes.clear(); +} + +// Enter the event loop. Runs until the I/O or timeout handler calls exit(). +void EventLoop::run() +{ + std::vector waitHandles; + DWORD lastTime = GetTickCount(); + while (!m_exiting) { + bool didSomething = false; + + // Attempt to make progress with the pipes. + waitHandles.clear(); + for (size_t i = 0; i < m_pipes.size(); ++i) { + if (m_pipes[i]->serviceIo(&waitHandles)) { + onPipeIo(*m_pipes[i]); + didSomething = true; + } + } + + // Call the timeout if enough time has elapsed. + if (m_pollInterval > 0) { + int elapsed = GetTickCount() - lastTime; + if (elapsed >= m_pollInterval) { + onPollTimeout(); + lastTime = GetTickCount(); + didSomething = true; + } + } + + if (didSomething) + continue; + + // If there's nothing to do, wait. + DWORD timeout = INFINITE; + if (m_pollInterval > 0) + timeout = std::max(0, (int)(lastTime + m_pollInterval - GetTickCount())); + if (waitHandles.size() == 0) { + ASSERT(timeout != INFINITE); + if (timeout > 0) + Sleep(timeout); + } else { + DWORD result = WaitForMultipleObjects(waitHandles.size(), + waitHandles.data(), + FALSE, + timeout); + ASSERT(result != WAIT_FAILED); + } + } +} + +NamedPipe &EventLoop::createNamedPipe() +{ + NamedPipe *ret = new NamedPipe(); + m_pipes.push_back(ret); + return *ret; +} + +void EventLoop::setPollInterval(int ms) +{ + m_pollInterval = ms; +} + +void EventLoop::shutdown() +{ + m_exiting = true; +} diff --git a/src/libs/3rdparty/winpty/src/agent/EventLoop.h b/src/libs/3rdparty/winpty/src/agent/EventLoop.h new file mode 100644 index 00000000000..eddb0f62679 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/EventLoop.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef EVENTLOOP_H +#define EVENTLOOP_H + +#include + +class NamedPipe; + +class EventLoop +{ +public: + virtual ~EventLoop(); + void run(); + +protected: + NamedPipe &createNamedPipe(); + void setPollInterval(int ms); + void shutdown(); + virtual void onPollTimeout() {} + virtual void onPipeIo(NamedPipe &namedPipe) {} + +private: + bool m_exiting = false; + std::vector m_pipes; + int m_pollInterval = 0; +}; + +#endif // EVENTLOOP_H diff --git a/src/libs/3rdparty/winpty/src/agent/InputMap.cc b/src/libs/3rdparty/winpty/src/agent/InputMap.cc new file mode 100644 index 00000000000..b1fbfc2e306 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/InputMap.cc @@ -0,0 +1,246 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "InputMap.h" + +#include +#include +#include +#include + +#include "DebugShowInput.h" +#include "SimplePool.h" +#include "../shared/DebugClient.h" +#include "../shared/UnixCtrlChars.h" +#include "../shared/WinptyAssert.h" +#include "../shared/winpty_snprintf.h" + +namespace { + +static const char *getVirtualKeyString(int virtualKey) +{ + switch (virtualKey) { +#define WINPTY_GVKS_KEY(x) case VK_##x: return #x; + WINPTY_GVKS_KEY(RBUTTON) WINPTY_GVKS_KEY(F9) + WINPTY_GVKS_KEY(CANCEL) WINPTY_GVKS_KEY(F10) + WINPTY_GVKS_KEY(MBUTTON) WINPTY_GVKS_KEY(F11) + WINPTY_GVKS_KEY(XBUTTON1) WINPTY_GVKS_KEY(F12) + WINPTY_GVKS_KEY(XBUTTON2) WINPTY_GVKS_KEY(F13) + WINPTY_GVKS_KEY(BACK) WINPTY_GVKS_KEY(F14) + WINPTY_GVKS_KEY(TAB) WINPTY_GVKS_KEY(F15) + WINPTY_GVKS_KEY(CLEAR) WINPTY_GVKS_KEY(F16) + WINPTY_GVKS_KEY(RETURN) WINPTY_GVKS_KEY(F17) + WINPTY_GVKS_KEY(SHIFT) WINPTY_GVKS_KEY(F18) + WINPTY_GVKS_KEY(CONTROL) WINPTY_GVKS_KEY(F19) + WINPTY_GVKS_KEY(MENU) WINPTY_GVKS_KEY(F20) + WINPTY_GVKS_KEY(PAUSE) WINPTY_GVKS_KEY(F21) + WINPTY_GVKS_KEY(CAPITAL) WINPTY_GVKS_KEY(F22) + WINPTY_GVKS_KEY(HANGUL) WINPTY_GVKS_KEY(F23) + WINPTY_GVKS_KEY(JUNJA) WINPTY_GVKS_KEY(F24) + WINPTY_GVKS_KEY(FINAL) WINPTY_GVKS_KEY(NUMLOCK) + WINPTY_GVKS_KEY(KANJI) WINPTY_GVKS_KEY(SCROLL) + WINPTY_GVKS_KEY(ESCAPE) WINPTY_GVKS_KEY(LSHIFT) + WINPTY_GVKS_KEY(CONVERT) WINPTY_GVKS_KEY(RSHIFT) + WINPTY_GVKS_KEY(NONCONVERT) WINPTY_GVKS_KEY(LCONTROL) + WINPTY_GVKS_KEY(ACCEPT) WINPTY_GVKS_KEY(RCONTROL) + WINPTY_GVKS_KEY(MODECHANGE) WINPTY_GVKS_KEY(LMENU) + WINPTY_GVKS_KEY(SPACE) WINPTY_GVKS_KEY(RMENU) + WINPTY_GVKS_KEY(PRIOR) WINPTY_GVKS_KEY(BROWSER_BACK) + WINPTY_GVKS_KEY(NEXT) WINPTY_GVKS_KEY(BROWSER_FORWARD) + WINPTY_GVKS_KEY(END) WINPTY_GVKS_KEY(BROWSER_REFRESH) + WINPTY_GVKS_KEY(HOME) WINPTY_GVKS_KEY(BROWSER_STOP) + WINPTY_GVKS_KEY(LEFT) WINPTY_GVKS_KEY(BROWSER_SEARCH) + WINPTY_GVKS_KEY(UP) WINPTY_GVKS_KEY(BROWSER_FAVORITES) + WINPTY_GVKS_KEY(RIGHT) WINPTY_GVKS_KEY(BROWSER_HOME) + WINPTY_GVKS_KEY(DOWN) WINPTY_GVKS_KEY(VOLUME_MUTE) + WINPTY_GVKS_KEY(SELECT) WINPTY_GVKS_KEY(VOLUME_DOWN) + WINPTY_GVKS_KEY(PRINT) WINPTY_GVKS_KEY(VOLUME_UP) + WINPTY_GVKS_KEY(EXECUTE) WINPTY_GVKS_KEY(MEDIA_NEXT_TRACK) + WINPTY_GVKS_KEY(SNAPSHOT) WINPTY_GVKS_KEY(MEDIA_PREV_TRACK) + WINPTY_GVKS_KEY(INSERT) WINPTY_GVKS_KEY(MEDIA_STOP) + WINPTY_GVKS_KEY(DELETE) WINPTY_GVKS_KEY(MEDIA_PLAY_PAUSE) + WINPTY_GVKS_KEY(HELP) WINPTY_GVKS_KEY(LAUNCH_MAIL) + WINPTY_GVKS_KEY(LWIN) WINPTY_GVKS_KEY(LAUNCH_MEDIA_SELECT) + WINPTY_GVKS_KEY(RWIN) WINPTY_GVKS_KEY(LAUNCH_APP1) + WINPTY_GVKS_KEY(APPS) WINPTY_GVKS_KEY(LAUNCH_APP2) + WINPTY_GVKS_KEY(SLEEP) WINPTY_GVKS_KEY(OEM_1) + WINPTY_GVKS_KEY(NUMPAD0) WINPTY_GVKS_KEY(OEM_PLUS) + WINPTY_GVKS_KEY(NUMPAD1) WINPTY_GVKS_KEY(OEM_COMMA) + WINPTY_GVKS_KEY(NUMPAD2) WINPTY_GVKS_KEY(OEM_MINUS) + WINPTY_GVKS_KEY(NUMPAD3) WINPTY_GVKS_KEY(OEM_PERIOD) + WINPTY_GVKS_KEY(NUMPAD4) WINPTY_GVKS_KEY(OEM_2) + WINPTY_GVKS_KEY(NUMPAD5) WINPTY_GVKS_KEY(OEM_3) + WINPTY_GVKS_KEY(NUMPAD6) WINPTY_GVKS_KEY(OEM_4) + WINPTY_GVKS_KEY(NUMPAD7) WINPTY_GVKS_KEY(OEM_5) + WINPTY_GVKS_KEY(NUMPAD8) WINPTY_GVKS_KEY(OEM_6) + WINPTY_GVKS_KEY(NUMPAD9) WINPTY_GVKS_KEY(OEM_7) + WINPTY_GVKS_KEY(MULTIPLY) WINPTY_GVKS_KEY(OEM_8) + WINPTY_GVKS_KEY(ADD) WINPTY_GVKS_KEY(OEM_102) + WINPTY_GVKS_KEY(SEPARATOR) WINPTY_GVKS_KEY(PROCESSKEY) + WINPTY_GVKS_KEY(SUBTRACT) WINPTY_GVKS_KEY(PACKET) + WINPTY_GVKS_KEY(DECIMAL) WINPTY_GVKS_KEY(ATTN) + WINPTY_GVKS_KEY(DIVIDE) WINPTY_GVKS_KEY(CRSEL) + WINPTY_GVKS_KEY(F1) WINPTY_GVKS_KEY(EXSEL) + WINPTY_GVKS_KEY(F2) WINPTY_GVKS_KEY(EREOF) + WINPTY_GVKS_KEY(F3) WINPTY_GVKS_KEY(PLAY) + WINPTY_GVKS_KEY(F4) WINPTY_GVKS_KEY(ZOOM) + WINPTY_GVKS_KEY(F5) WINPTY_GVKS_KEY(NONAME) + WINPTY_GVKS_KEY(F6) WINPTY_GVKS_KEY(PA1) + WINPTY_GVKS_KEY(F7) WINPTY_GVKS_KEY(OEM_CLEAR) + WINPTY_GVKS_KEY(F8) +#undef WINPTY_GVKS_KEY + default: return NULL; + } +} + +} // anonymous namespace + +std::string InputMap::Key::toString() const { + std::string ret; + ret += controlKeyStatePrefix(keyState); + char buf[256]; + const char *vkString = getVirtualKeyString(virtualKey); + if (vkString != NULL) { + ret += vkString; + } else if ((virtualKey >= 'A' && virtualKey <= 'Z') || + (virtualKey >= '0' && virtualKey <= '9')) { + ret += static_cast(virtualKey); + } else { + winpty_snprintf(buf, "%#x", virtualKey); + ret += buf; + } + if (unicodeChar >= 32 && unicodeChar <= 126) { + winpty_snprintf(buf, " ch='%c'", + static_cast(unicodeChar)); + } else { + winpty_snprintf(buf, " ch=%#x", + static_cast(unicodeChar)); + } + ret += buf; + return ret; +} + +void InputMap::set(const char *encoding, int encodingLen, const Key &key) { + ASSERT(encodingLen > 0); + setHelper(m_root, encoding, encodingLen, key); +} + +void InputMap::setHelper(Node &node, const char *encoding, int encodingLen, const Key &key) { + if (encodingLen == 0) { + node.key = key; + } else { + setHelper(getOrCreateChild(node, encoding[0]), encoding + 1, encodingLen - 1, key); + } +} + +InputMap::Node &InputMap::getOrCreateChild(Node &node, unsigned char ch) { + Node *ret = getChild(node, ch); + if (ret != NULL) { + return *ret; + } + if (node.childCount < Node::kTinyCount) { + // Maintain sorted order for the sake of the InputMap dumping. + int insertIndex = node.childCount; + for (int i = 0; i < node.childCount; ++i) { + if (ch < node.u.tiny.values[i]) { + insertIndex = i; + break; + } + } + for (int j = node.childCount; j > insertIndex; --j) { + node.u.tiny.values[j] = node.u.tiny.values[j - 1]; + node.u.tiny.children[j] = node.u.tiny.children[j - 1]; + } + node.u.tiny.values[insertIndex] = ch; + node.u.tiny.children[insertIndex] = ret = m_nodePool.alloc(); + ++node.childCount; + return *ret; + } + if (node.childCount == Node::kTinyCount) { + Branch *branch = m_branchPool.alloc(); + for (int i = 0; i < node.childCount; ++i) { + branch->children[node.u.tiny.values[i]] = node.u.tiny.children[i]; + } + node.u.branch = branch; + } + node.u.branch->children[ch] = ret = m_nodePool.alloc(); + ++node.childCount; + return *ret; +} + +// Find the longest matching key and node. +int InputMap::lookupKey(const char *input, int inputSize, + Key &keyOut, bool &incompleteOut) const { + keyOut = kKeyZero; + incompleteOut = false; + + const Node *node = &m_root; + InputMap::Key longestMatch = kKeyZero; + int longestMatchLen = 0; + + for (int i = 0; i < inputSize; ++i) { + unsigned char ch = input[i]; + node = getChild(*node, ch); + if (node == NULL) { + keyOut = longestMatch; + return longestMatchLen; + } else if (node->hasKey()) { + longestMatchLen = i + 1; + longestMatch = node->key; + } + } + keyOut = longestMatch; + incompleteOut = node->childCount > 0; + return longestMatchLen; +} + +void InputMap::dumpInputMap() const { + std::string encoding; + dumpInputMapHelper(m_root, encoding); +} + +void InputMap::dumpInputMapHelper( + const Node &node, std::string &encoding) const { + if (node.hasKey()) { + trace("%s -> %s", + encoding.c_str(), + node.key.toString().c_str()); + } + for (int i = 0; i < 256; ++i) { + const Node *child = getChild(node, i); + if (child != NULL) { + size_t oldSize = encoding.size(); + if (!encoding.empty()) { + encoding.push_back(' '); + } + char ctrlChar = decodeUnixCtrlChar(i); + if (ctrlChar != '\0') { + encoding.push_back('^'); + encoding.push_back(static_cast(ctrlChar)); + } else if (i == ' ') { + encoding.append("' '"); + } else { + encoding.push_back(static_cast(i)); + } + dumpInputMapHelper(*child, encoding); + encoding.resize(oldSize); + } + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/InputMap.h b/src/libs/3rdparty/winpty/src/agent/InputMap.h new file mode 100644 index 00000000000..9a666c79762 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/InputMap.h @@ -0,0 +1,114 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef INPUT_MAP_H +#define INPUT_MAP_H + +#include +#include +#include + +#include + +#include "SimplePool.h" +#include "../shared/WinptyAssert.h" + +class InputMap { +public: + struct Key { + uint16_t virtualKey; + uint32_t unicodeChar; + uint16_t keyState; + + std::string toString() const; + }; + +private: + struct Node; + + struct Branch { + Branch() { + memset(&children, 0, sizeof(children)); + } + + Node *children[256]; + }; + + struct Node { + Node() : childCount(0) { + Key zeroKey = { 0, 0, 0 }; + key = zeroKey; + } + + Key key; + int childCount; + enum { kTinyCount = 8 }; + union { + Branch *branch; + struct { + unsigned char values[kTinyCount]; + Node *children[kTinyCount]; + } tiny; + } u; + + bool hasKey() const { + return key.virtualKey != 0 || key.unicodeChar != 0; + } + }; + +private: + SimplePool m_nodePool; + SimplePool m_branchPool; + Node m_root; + +public: + void set(const char *encoding, int encodingLen, const Key &key); + int lookupKey(const char *input, int inputSize, + Key &keyOut, bool &incompleteOut) const; + void dumpInputMap() const; + +private: + Node *getChild(Node &node, unsigned char ch) { + return const_cast(getChild(static_cast(node), ch)); + } + + const Node *getChild(const Node &node, unsigned char ch) const { + if (node.childCount <= Node::kTinyCount) { + for (int i = 0; i < node.childCount; ++i) { + if (node.u.tiny.values[i] == ch) { + return node.u.tiny.children[i]; + } + } + return NULL; + } else { + return node.u.branch->children[ch]; + } + } + + void setHelper(Node &node, const char *encoding, int encodingLen, const Key &key); + Node &getOrCreateChild(Node &node, unsigned char ch); + void dumpInputMapHelper(const Node &node, std::string &encoding) const; +}; + +const InputMap::Key kKeyZero = { 0, 0, 0 }; + +void dumpInputMap(InputMap &inputMap); + +#endif // INPUT_MAP_H diff --git a/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc new file mode 100644 index 00000000000..80ac640e488 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "LargeConsoleRead.h" + +#include + +#include "../shared/WindowsVersion.h" +#include "Scraper.h" +#include "Win32ConsoleBuffer.h" + +LargeConsoleReadBuffer::LargeConsoleReadBuffer() : + m_rect(0, 0, 0, 0), m_rectWidth(0) +{ +} + +void largeConsoleRead(LargeConsoleReadBuffer &out, + Win32ConsoleBuffer &buffer, + const SmallRect &readArea, + WORD attributesMask) { + ASSERT(readArea.Left >= 0 && + readArea.Top >= 0 && + readArea.Right >= readArea.Left && + readArea.Bottom >= readArea.Top && + readArea.width() <= MAX_CONSOLE_WIDTH); + const size_t count = readArea.width() * readArea.height(); + if (out.m_data.size() < count) { + out.m_data.resize(count); + } + out.m_rect = readArea; + out.m_rectWidth = readArea.width(); + + static const bool useLargeReads = isAtLeastWindows8(); + if (useLargeReads) { + buffer.read(readArea, out.m_data.data()); + } else { + const int maxReadLines = std::max(1, MAX_CONSOLE_WIDTH / readArea.width()); + int curLine = readArea.Top; + while (curLine <= readArea.Bottom) { + const SmallRect subReadArea( + readArea.Left, + curLine, + readArea.width(), + std::min(maxReadLines, readArea.Bottom + 1 - curLine)); + buffer.read(subReadArea, out.lineDataMut(curLine)); + curLine = subReadArea.Bottom + 1; + } + } + if (attributesMask != static_cast(~0)) { + for (size_t i = 0; i < count; ++i) { + out.m_data[i].Attributes &= attributesMask; + } + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h new file mode 100644 index 00000000000..1bcf2c0232b --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/LargeConsoleRead.h @@ -0,0 +1,68 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef LARGE_CONSOLE_READ_H +#define LARGE_CONSOLE_READ_H + +#include +#include + +#include + +#include "SmallRect.h" +#include "../shared/DebugClient.h" +#include "../shared/WinptyAssert.h" + +class Win32ConsoleBuffer; + +class LargeConsoleReadBuffer { +public: + LargeConsoleReadBuffer(); + const SmallRect &rect() const { return m_rect; } + const CHAR_INFO *lineData(int line) const { + validateLineNumber(line); + return &m_data[(line - m_rect.Top) * m_rectWidth]; + } + +private: + CHAR_INFO *lineDataMut(int line) { + validateLineNumber(line); + return &m_data[(line - m_rect.Top) * m_rectWidth]; + } + + void validateLineNumber(int line) const { + if (line < m_rect.Top || line > m_rect.Bottom) { + trace("Fatal error: LargeConsoleReadBuffer: invalid line %d for " + "read rect %s", line, m_rect.toString().c_str()); + abort(); + } + } + + SmallRect m_rect; + int m_rectWidth; + std::vector m_data; + + friend void largeConsoleRead(LargeConsoleReadBuffer &out, + Win32ConsoleBuffer &buffer, + const SmallRect &readArea, + WORD attributesMask); +}; + +#endif // LARGE_CONSOLE_READ_H diff --git a/src/libs/3rdparty/winpty/src/agent/NamedPipe.cc b/src/libs/3rdparty/winpty/src/agent/NamedPipe.cc new file mode 100644 index 00000000000..64044e6e5d2 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/NamedPipe.cc @@ -0,0 +1,378 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include + +#include + +#include "EventLoop.h" +#include "NamedPipe.h" +#include "../shared/DebugClient.h" +#include "../shared/StringUtil.h" +#include "../shared/WindowsSecurity.h" +#include "../shared/WinptyAssert.h" + +// Returns true if anything happens (data received, data sent, pipe error). +bool NamedPipe::serviceIo(std::vector *waitHandles) +{ + bool justConnected = false; + const auto kError = ServiceResult::Error; + const auto kProgress = ServiceResult::Progress; + const auto kNoProgress = ServiceResult::NoProgress; + if (m_handle == NULL) { + return false; + } + if (m_connectEvent.get() != nullptr) { + // We're still connecting this server pipe. Check whether the pipe is + // now connected. If it isn't, add the pipe to the list of handles to + // wait on. + DWORD actual = 0; + BOOL success = + GetOverlappedResult(m_handle, &m_connectOver, &actual, FALSE); + if (!success && GetLastError() == ERROR_PIPE_CONNECTED) { + // I'm not sure this can happen, but it's easy to handle if it + // does. + success = TRUE; + } + if (!success) { + ASSERT(GetLastError() == ERROR_IO_INCOMPLETE && + "Pended ConnectNamedPipe call failed"); + waitHandles->push_back(m_connectEvent.get()); + } else { + TRACE("Server pipe [%s] connected", + utf8FromWide(m_name).c_str()); + m_connectEvent.dispose(); + startPipeWorkers(); + justConnected = true; + } + } + const auto readProgress = m_inputWorker ? m_inputWorker->service() : kNoProgress; + const auto writeProgress = m_outputWorker ? m_outputWorker->service() : kNoProgress; + if (readProgress == kError || writeProgress == kError) { + closePipe(); + return true; + } + if (m_inputWorker && m_inputWorker->getWaitEvent() != nullptr) { + waitHandles->push_back(m_inputWorker->getWaitEvent()); + } + if (m_outputWorker && m_outputWorker->getWaitEvent() != nullptr) { + waitHandles->push_back(m_outputWorker->getWaitEvent()); + } + return justConnected + || readProgress == kProgress + || writeProgress == kProgress; +} + +// manual reset, initially unset +static OwnedHandle createEvent() { + HANDLE ret = CreateEventW(nullptr, TRUE, FALSE, nullptr); + ASSERT(ret != nullptr && "CreateEventW failed"); + return OwnedHandle(ret); +} + +NamedPipe::IoWorker::IoWorker(NamedPipe &namedPipe) : + m_namedPipe(namedPipe), + m_event(createEvent()) +{ +} + +NamedPipe::ServiceResult NamedPipe::IoWorker::service() +{ + ServiceResult progress = ServiceResult::NoProgress; + if (m_pending) { + DWORD actual = 0; + BOOL ret = GetOverlappedResult(m_namedPipe.m_handle, &m_over, &actual, FALSE); + if (!ret) { + if (GetLastError() == ERROR_IO_INCOMPLETE) { + // There is a pending I/O. + return progress; + } else { + // Pipe error. + return ServiceResult::Error; + } + } + ResetEvent(m_event.get()); + m_pending = false; + completeIo(actual); + m_currentIoSize = 0; + progress = ServiceResult::Progress; + } + DWORD nextSize = 0; + bool isRead = false; + while (shouldIssueIo(&nextSize, &isRead)) { + m_currentIoSize = nextSize; + DWORD actual = 0; + memset(&m_over, 0, sizeof(m_over)); + m_over.hEvent = m_event.get(); + BOOL ret = isRead + ? ReadFile(m_namedPipe.m_handle, m_buffer, nextSize, &actual, &m_over) + : WriteFile(m_namedPipe.m_handle, m_buffer, nextSize, &actual, &m_over); + if (!ret) { + if (GetLastError() == ERROR_IO_PENDING) { + // There is a pending I/O. + m_pending = true; + return progress; + } else { + // Pipe error. + return ServiceResult::Error; + } + } + ResetEvent(m_event.get()); + completeIo(actual); + m_currentIoSize = 0; + progress = ServiceResult::Progress; + } + return progress; +} + +// This function is called after CancelIo has returned. We need to block until +// the I/O operations have completed, which should happen very quickly. +// https://blogs.msdn.microsoft.com/oldnewthing/20110202-00/?p=11613 +void NamedPipe::IoWorker::waitForCanceledIo() +{ + if (m_pending) { + DWORD actual = 0; + GetOverlappedResult(m_namedPipe.m_handle, &m_over, &actual, TRUE); + m_pending = false; + } +} + +HANDLE NamedPipe::IoWorker::getWaitEvent() +{ + return m_pending ? m_event.get() : NULL; +} + +void NamedPipe::InputWorker::completeIo(DWORD size) +{ + m_namedPipe.m_inQueue.append(m_buffer, size); +} + +bool NamedPipe::InputWorker::shouldIssueIo(DWORD *size, bool *isRead) +{ + *isRead = true; + ASSERT(!m_namedPipe.isConnecting()); + if (m_namedPipe.isClosed()) { + return false; + } else if (m_namedPipe.m_inQueue.size() < m_namedPipe.readBufferSize()) { + *size = kIoSize; + return true; + } else { + return false; + } +} + +void NamedPipe::OutputWorker::completeIo(DWORD size) +{ + ASSERT(size == m_currentIoSize); +} + +bool NamedPipe::OutputWorker::shouldIssueIo(DWORD *size, bool *isRead) +{ + *isRead = false; + if (!m_namedPipe.m_outQueue.empty()) { + auto &out = m_namedPipe.m_outQueue; + const DWORD writeSize = std::min(out.size(), kIoSize); + std::copy(&out[0], &out[writeSize], m_buffer); + out.erase(0, writeSize); + *size = writeSize; + return true; + } else { + return false; + } +} + +DWORD NamedPipe::OutputWorker::getPendingIoSize() +{ + return m_pending ? m_currentIoSize : 0; +} + +void NamedPipe::openServerPipe(LPCWSTR pipeName, OpenMode::t openMode, + int outBufferSize, int inBufferSize) { + ASSERT(isClosed()); + ASSERT((openMode & OpenMode::Duplex) != 0); + const DWORD winOpenMode = + ((openMode & OpenMode::Reading) ? PIPE_ACCESS_INBOUND : 0) + | ((openMode & OpenMode::Writing) ? PIPE_ACCESS_OUTBOUND : 0) + | FILE_FLAG_FIRST_PIPE_INSTANCE + | FILE_FLAG_OVERLAPPED; + const auto sd = createPipeSecurityDescriptorOwnerFullControl(); + ASSERT(sd && "error creating data pipe SECURITY_DESCRIPTOR"); + SECURITY_ATTRIBUTES sa = {}; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = sd.get(); + HANDLE handle = CreateNamedPipeW( + pipeName, + /*dwOpenMode=*/winOpenMode, + /*dwPipeMode=*/rejectRemoteClientsPipeFlag(), + /*nMaxInstances=*/1, + /*nOutBufferSize=*/outBufferSize, + /*nInBufferSize=*/inBufferSize, + /*nDefaultTimeOut=*/30000, + &sa); + TRACE("opened server pipe [%s], handle == %p", + utf8FromWide(pipeName).c_str(), handle); + ASSERT(handle != INVALID_HANDLE_VALUE && "Could not open server pipe"); + m_name = pipeName; + m_handle = handle; + m_openMode = openMode; + + // Start an asynchronous connection attempt. + m_connectEvent = createEvent(); + memset(&m_connectOver, 0, sizeof(m_connectOver)); + m_connectOver.hEvent = m_connectEvent.get(); + BOOL success = ConnectNamedPipe(m_handle, &m_connectOver); + const auto err = GetLastError(); + if (!success && err == ERROR_PIPE_CONNECTED) { + success = TRUE; + } + if (success) { + TRACE("Server pipe [%s] connected", utf8FromWide(pipeName).c_str()); + m_connectEvent.dispose(); + startPipeWorkers(); + } else if (err != ERROR_IO_PENDING) { + ASSERT(false && "ConnectNamedPipe call failed"); + } +} + +void NamedPipe::connectToServer(LPCWSTR pipeName, OpenMode::t openMode) +{ + ASSERT(isClosed()); + ASSERT((openMode & OpenMode::Duplex) != 0); + HANDLE handle = CreateFileW( + pipeName, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION | FILE_FLAG_OVERLAPPED, + NULL); + TRACE("connected to [%s], handle == %p", + utf8FromWide(pipeName).c_str(), handle); + ASSERT(handle != INVALID_HANDLE_VALUE && "Could not connect to pipe"); + m_name = pipeName; + m_handle = handle; + m_openMode = openMode; + startPipeWorkers(); +} + +void NamedPipe::startPipeWorkers() +{ + if (m_openMode & OpenMode::Reading) { + m_inputWorker.reset(new InputWorker(*this)); + } + if (m_openMode & OpenMode::Writing) { + m_outputWorker.reset(new OutputWorker(*this)); + } +} + +size_t NamedPipe::bytesToSend() +{ + ASSERT(m_openMode & OpenMode::Writing); + auto ret = m_outQueue.size(); + if (m_outputWorker != NULL) { + ret += m_outputWorker->getPendingIoSize(); + } + return ret; +} + +void NamedPipe::write(const void *data, size_t size) +{ + ASSERT(m_openMode & OpenMode::Writing); + m_outQueue.append(reinterpret_cast(data), size); +} + +void NamedPipe::write(const char *text) +{ + write(text, strlen(text)); +} + +size_t NamedPipe::readBufferSize() +{ + ASSERT(m_openMode & OpenMode::Reading); + return m_readBufferSize; +} + +void NamedPipe::setReadBufferSize(size_t size) +{ + ASSERT(m_openMode & OpenMode::Reading); + m_readBufferSize = size; +} + +size_t NamedPipe::bytesAvailable() +{ + ASSERT(m_openMode & OpenMode::Reading); + return m_inQueue.size(); +} + +size_t NamedPipe::peek(void *data, size_t size) +{ + ASSERT(m_openMode & OpenMode::Reading); + const auto out = reinterpret_cast(data); + const size_t ret = std::min(size, m_inQueue.size()); + std::copy(&m_inQueue[0], &m_inQueue[ret], out); + return ret; +} + +size_t NamedPipe::read(void *data, size_t size) +{ + size_t ret = peek(data, size); + m_inQueue.erase(0, ret); + return ret; +} + +std::string NamedPipe::readToString(size_t size) +{ + ASSERT(m_openMode & OpenMode::Reading); + size_t retSize = std::min(size, m_inQueue.size()); + std::string ret = m_inQueue.substr(0, retSize); + m_inQueue.erase(0, retSize); + return ret; +} + +std::string NamedPipe::readAllToString() +{ + ASSERT(m_openMode & OpenMode::Reading); + std::string ret = m_inQueue; + m_inQueue.clear(); + return ret; +} + +void NamedPipe::closePipe() +{ + if (m_handle == NULL) { + return; + } + CancelIo(m_handle); + if (m_connectEvent.get() != nullptr) { + DWORD actual = 0; + GetOverlappedResult(m_handle, &m_connectOver, &actual, TRUE); + m_connectEvent.dispose(); + } + if (m_inputWorker) { + m_inputWorker->waitForCanceledIo(); + m_inputWorker.reset(); + } + if (m_outputWorker) { + m_outputWorker->waitForCanceledIo(); + m_outputWorker.reset(); + } + CloseHandle(m_handle); + m_handle = NULL; +} diff --git a/src/libs/3rdparty/winpty/src/agent/NamedPipe.h b/src/libs/3rdparty/winpty/src/agent/NamedPipe.h new file mode 100644 index 00000000000..0a4d8b0c75a --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/NamedPipe.h @@ -0,0 +1,125 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef NAMEDPIPE_H +#define NAMEDPIPE_H + +#include + +#include +#include +#include + +#include "../shared/OwnedHandle.h" + +class EventLoop; + +class NamedPipe +{ +private: + // The EventLoop uses these private members. + friend class EventLoop; + NamedPipe() {} + ~NamedPipe() { closePipe(); } + bool serviceIo(std::vector *waitHandles); + void startPipeWorkers(); + + enum class ServiceResult { NoProgress, Error, Progress }; + +private: + class IoWorker + { + public: + IoWorker(NamedPipe &namedPipe); + virtual ~IoWorker() {} + ServiceResult service(); + void waitForCanceledIo(); + HANDLE getWaitEvent(); + protected: + NamedPipe &m_namedPipe; + bool m_pending = false; + DWORD m_currentIoSize = 0; + OwnedHandle m_event; + OVERLAPPED m_over = {}; + enum { kIoSize = 64 * 1024 }; + char m_buffer[kIoSize]; + virtual void completeIo(DWORD size) = 0; + virtual bool shouldIssueIo(DWORD *size, bool *isRead) = 0; + }; + + class InputWorker : public IoWorker + { + public: + InputWorker(NamedPipe &namedPipe) : IoWorker(namedPipe) {} + protected: + virtual void completeIo(DWORD size) override; + virtual bool shouldIssueIo(DWORD *size, bool *isRead) override; + }; + + class OutputWorker : public IoWorker + { + public: + OutputWorker(NamedPipe &namedPipe) : IoWorker(namedPipe) {} + DWORD getPendingIoSize(); + protected: + virtual void completeIo(DWORD size) override; + virtual bool shouldIssueIo(DWORD *size, bool *isRead) override; + }; + +public: + struct OpenMode { + typedef int t; + enum { None = 0, Reading = 1, Writing = 2, Duplex = 3 }; + }; + + std::wstring name() const { return m_name; } + void openServerPipe(LPCWSTR pipeName, OpenMode::t openMode, + int outBufferSize, int inBufferSize); + void connectToServer(LPCWSTR pipeName, OpenMode::t openMode); + size_t bytesToSend(); + void write(const void *data, size_t size); + void write(const char *text); + size_t readBufferSize(); + void setReadBufferSize(size_t size); + size_t bytesAvailable(); + size_t peek(void *data, size_t size); + size_t read(void *data, size_t size); + std::string readToString(size_t size); + std::string readAllToString(); + void closePipe(); + bool isClosed() { return m_handle == nullptr; } + bool isConnected() { return !isClosed() && !isConnecting(); } + bool isConnecting() { return m_connectEvent.get() != nullptr; } + +private: + // Input/output buffers + std::wstring m_name; + OVERLAPPED m_connectOver = {}; + OwnedHandle m_connectEvent; + OpenMode::t m_openMode = OpenMode::None; + size_t m_readBufferSize = 64 * 1024; + std::string m_inQueue; + std::string m_outQueue; + HANDLE m_handle = nullptr; + std::unique_ptr m_inputWorker; + std::unique_ptr m_outputWorker; +}; + +#endif // NAMEDPIPE_H diff --git a/src/libs/3rdparty/winpty/src/agent/Scraper.cc b/src/libs/3rdparty/winpty/src/agent/Scraper.cc new file mode 100644 index 00000000000..21f9c67104e --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Scraper.cc @@ -0,0 +1,699 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "Scraper.h" + +#include + +#include + +#include +#include + +#include "../shared/WinptyAssert.h" +#include "../shared/winpty_snprintf.h" + +#include "ConsoleFont.h" +#include "Win32Console.h" +#include "Win32ConsoleBuffer.h" + +namespace { + +template +T constrained(T min, T val, T max) { + ASSERT(min <= max); + return std::min(std::max(min, val), max); +} + +} // anonymous namespace + +Scraper::Scraper( + Win32Console &console, + Win32ConsoleBuffer &buffer, + std::unique_ptr terminal, + Coord initialSize) : + m_console(console), + m_terminal(std::move(terminal)), + m_ptySize(initialSize) +{ + m_consoleBuffer = &buffer; + + resetConsoleTracking(Terminal::OmitClear, buffer.windowRect().top()); + + m_bufferData.resize(BUFFER_LINE_COUNT); + + // Setup the initial screen buffer and window size. + // + // Use SetConsoleWindowInfo to shrink the console window as much as + // possible -- to a 1x1 cell at the top-left. This call always succeeds. + // Prior to the new Windows 10 console, it also actually resizes the GUI + // window to 1x1 cell. Nevertheless, even though the GUI window can + // therefore be narrower than its minimum, calling + // SetConsoleScreenBufferSize with a 1x1 size still fails. + // + // While the small font intends to support large buffers, a user could + // still hit a limit imposed by their monitor width, so cap the new window + // size to GetLargestConsoleWindowSize(). + setSmallFont(buffer.conout(), initialSize.X, m_console.isNewW10()); + buffer.moveWindow(SmallRect(0, 0, 1, 1)); + buffer.resizeBufferRange(Coord(initialSize.X, BUFFER_LINE_COUNT)); + const auto largest = GetLargestConsoleWindowSize(buffer.conout()); + buffer.moveWindow(SmallRect( + 0, 0, + std::min(initialSize.X, largest.X), + std::min(initialSize.Y, largest.Y))); + buffer.setCursorPosition(Coord(0, 0)); + + // For the sake of the color translation heuristic, set the console color + // to LtGray-on-Black. + buffer.setTextAttribute(Win32ConsoleBuffer::kDefaultAttributes); + buffer.clearAllLines(m_consoleBuffer->bufferInfo()); + + m_consoleBuffer = nullptr; +} + +Scraper::~Scraper() +{ +} + +// Whether or not the agent is frozen on entry, it will be frozen on exit. +void Scraper::resizeWindow(Win32ConsoleBuffer &buffer, + Coord newSize, + ConsoleScreenBufferInfo &finalInfoOut) +{ + m_consoleBuffer = &buffer; + m_ptySize = newSize; + syncConsoleContentAndSize(true, finalInfoOut); + m_consoleBuffer = nullptr; +} + +// This function may freeze the agent, but it will not unfreeze it. +void Scraper::scrapeBuffer(Win32ConsoleBuffer &buffer, + ConsoleScreenBufferInfo &finalInfoOut) +{ + m_consoleBuffer = &buffer; + syncConsoleContentAndSize(false, finalInfoOut); + m_consoleBuffer = nullptr; +} + +void Scraper::resetConsoleTracking( + Terminal::SendClearFlag sendClear, int64_t scrapedLineCount) +{ + for (ConsoleLine &line : m_bufferData) { + line.reset(); + } + m_syncRow = -1; + m_scrapedLineCount = scrapedLineCount; + m_scrolledCount = 0; + m_maxBufferedLine = -1; + m_dirtyWindowTop = -1; + m_dirtyLineCount = 0; + m_terminal->reset(sendClear, m_scrapedLineCount); +} + +// Detect window movement. If the window moves down (presumably as a +// result of scrolling), then assume that all screen buffer lines down to +// the bottom of the window are dirty. +void Scraper::markEntireWindowDirty(const SmallRect &windowRect) +{ + m_dirtyLineCount = std::max(m_dirtyLineCount, + windowRect.top() + windowRect.height()); +} + +// Scan the screen buffer and advance the dirty line count when we find +// non-empty lines. +void Scraper::scanForDirtyLines(const SmallRect &windowRect) +{ + const int w = m_readBuffer.rect().width(); + ASSERT(m_dirtyLineCount >= 1); + const CHAR_INFO *const prevLine = + m_readBuffer.lineData(m_dirtyLineCount - 1); + WORD prevLineAttr = prevLine[w - 1].Attributes; + const int stopLine = windowRect.top() + windowRect.height(); + + for (int line = m_dirtyLineCount; line < stopLine; ++line) { + const CHAR_INFO *lineData = m_readBuffer.lineData(line); + for (int col = 0; col < w; ++col) { + const WORD colAttr = lineData[col].Attributes; + if (lineData[col].Char.UnicodeChar != L' ' || + colAttr != prevLineAttr) { + m_dirtyLineCount = line + 1; + break; + } + } + prevLineAttr = lineData[w - 1].Attributes; + } +} + +// Clear lines in the line buffer. The `firstRow` parameter is in +// screen-buffer coordinates. +void Scraper::clearBufferLines( + const int firstRow, + const int count) +{ + ASSERT(!m_directMode); + for (int row = firstRow; row < firstRow + count; ++row) { + const int64_t bufLine = row + m_scrolledCount; + m_maxBufferedLine = std::max(m_maxBufferedLine, bufLine); + m_bufferData[bufLine % BUFFER_LINE_COUNT].blank( + Win32ConsoleBuffer::kDefaultAttributes); + } +} + +static bool cursorInWindow(const ConsoleScreenBufferInfo &info) +{ + return info.dwCursorPosition.Y >= info.srWindow.Top && + info.dwCursorPosition.Y <= info.srWindow.Bottom; +} + +void Scraper::resizeImpl(const ConsoleScreenBufferInfo &origInfo) +{ + ASSERT(m_console.frozen()); + const int cols = m_ptySize.X; + const int rows = m_ptySize.Y; + Coord finalBufferSize; + + { + // + // To accommodate Windows 10, erase all lines up to the top of the + // visible window. It's hard to tell whether this is strictly + // necessary. It ensures that the sync marker won't move downward, + // and it ensures that we won't repeat lines that have already scrolled + // up into the scrollback. + // + // It *is* possible for these blank lines to reappear in the visible + // window (e.g. if the window is made taller), but because we blanked + // the lines in the line buffer, we still don't output them again. + // + const Coord origBufferSize = origInfo.bufferSize(); + const SmallRect origWindowRect = origInfo.windowRect(); + + if (m_directMode) { + for (ConsoleLine &line : m_bufferData) { + line.reset(); + } + } else { + m_consoleBuffer->clearLines(0, origWindowRect.Top, origInfo); + clearBufferLines(0, origWindowRect.Top); + if (m_syncRow != -1) { + createSyncMarker(std::min( + m_syncRow, + BUFFER_LINE_COUNT - rows + - SYNC_MARKER_LEN + - SYNC_MARKER_MARGIN)); + } + } + + finalBufferSize = Coord( + cols, + // If there was previously no scrollback (e.g. a full-screen app + // in direct mode) and we're reducing the window height, then + // reduce the console buffer's height too. + (origWindowRect.height() == origBufferSize.Y) + ? rows + : std::max(rows, origBufferSize.Y)); + + // Reset the console font size. We need to do this before shrinking + // the window, because we might need to make the font bigger to permit + // a smaller window width. Making the font smaller could expand the + // screen buffer, which would hang the conhost process in the + // Windows 10 (10240 build) if the console selection is in progress, so + // unfreeze it first. + m_console.setFrozen(false); + setSmallFont(m_consoleBuffer->conout(), cols, m_console.isNewW10()); + } + + // We try to make the font small enough so that the entire screen buffer + // fits on the monitor, but it can't be guaranteed. + const auto largest = + GetLargestConsoleWindowSize(m_consoleBuffer->conout()); + const short visibleCols = std::min(cols, largest.X); + const short visibleRows = std::min(rows, largest.Y); + + { + // Make the window small enough. We want the console frozen during + // this step so we don't accidentally move the window above the cursor. + m_console.setFrozen(true); + const auto info = m_consoleBuffer->bufferInfo(); + const auto &bufferSize = info.dwSize; + const int tmpWindowWidth = std::min(bufferSize.X, visibleCols); + const int tmpWindowHeight = std::min(bufferSize.Y, visibleRows); + SmallRect tmpWindowRect( + 0, + std::min(bufferSize.Y - tmpWindowHeight, + info.windowRect().Top), + tmpWindowWidth, + tmpWindowHeight); + if (cursorInWindow(info)) { + tmpWindowRect = tmpWindowRect.ensureLineIncluded( + info.cursorPosition().Y); + } + m_consoleBuffer->moveWindow(tmpWindowRect); + } + + { + // Resize the buffer to the final desired size. + m_console.setFrozen(false); + m_consoleBuffer->resizeBufferRange(finalBufferSize); + } + + { + // Expand the window to its full size. + m_console.setFrozen(true); + const ConsoleScreenBufferInfo info = m_consoleBuffer->bufferInfo(); + + SmallRect finalWindowRect( + 0, + std::min(info.bufferSize().Y - visibleRows, + info.windowRect().Top), + visibleCols, + visibleRows); + + // + // Once a line in the screen buffer is "dirty", it should stay visible + // in the console window, so that we continue to update its content in + // the terminal. This code is particularly (only?) necessary on + // Windows 10, where making the buffer wider can rewrap lines and move + // the console window upward. + // + if (!m_directMode && m_dirtyLineCount > finalWindowRect.Bottom + 1) { + // In theory, we avoid ensureLineIncluded, because, a massive + // amount of output could have occurred while the console was + // unfrozen, so that the *top* of the window is now below the + // dirtiest tracked line. + finalWindowRect = SmallRect( + 0, m_dirtyLineCount - visibleRows, + visibleCols, visibleRows); + } + + // Highest priority constraint: ensure that the cursor remains visible. + if (cursorInWindow(info)) { + finalWindowRect = finalWindowRect.ensureLineIncluded( + info.cursorPosition().Y); + } + + m_consoleBuffer->moveWindow(finalWindowRect); + m_dirtyWindowTop = finalWindowRect.Top; + } + + ASSERT(m_console.frozen()); +} + +void Scraper::syncConsoleContentAndSize( + bool forceResize, + ConsoleScreenBufferInfo &finalInfoOut) +{ + // We'll try to avoid freezing the console by reading large chunks (or + // all!) of the screen buffer without otherwise attempting to synchronize + // with the console application. We can only do this on Windows 10 and up + // because: + // - Prior to Windows 8, the size of a ReadConsoleOutputW call was limited + // by the ~32KB RPC buffer. + // - Prior to Windows 10, an out-of-range read region crashes the caller. + // (See misc/WindowsBugCrashReader.cc.) + // + if (!m_console.isNewW10() || forceResize) { + m_console.setFrozen(true); + } + + const ConsoleScreenBufferInfo info = m_consoleBuffer->bufferInfo(); + bool cursorVisible = true; + CONSOLE_CURSOR_INFO cursorInfo = {}; + if (!GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo)) { + trace("GetConsoleCursorInfo failed"); + } else { + cursorVisible = cursorInfo.bVisible != 0; + } + + // If an app resizes the buffer height, then we enter "direct mode", where + // we stop trying to track incremental console changes. + const bool newDirectMode = (info.bufferSize().Y != BUFFER_LINE_COUNT); + if (newDirectMode != m_directMode) { + trace("Entering %s mode", newDirectMode ? "direct" : "scrolling"); + resetConsoleTracking(Terminal::SendClear, + newDirectMode ? 0 : info.windowRect().top()); + m_directMode = newDirectMode; + + // When we switch from direct->scrolling mode, make sure the console is + // the right size. + if (!m_directMode) { + m_console.setFrozen(true); + forceResize = true; + } + } + + if (m_directMode) { + // In direct-mode, resizing the console redraws the terminal, so do it + // before scraping. + if (forceResize) { + resizeImpl(info); + } + directScrapeOutput(info, cursorVisible); + } else { + if (!m_console.frozen()) { + if (!scrollingScrapeOutput(info, cursorVisible, true)) { + m_console.setFrozen(true); + } + } + if (m_console.frozen()) { + scrollingScrapeOutput(info, cursorVisible, false); + } + // In scrolling mode, we want to scrape before resizing, because we'll + // erase everything in the console buffer up to the top of the console + // window. + if (forceResize) { + resizeImpl(info); + } + } + + finalInfoOut = forceResize ? m_consoleBuffer->bufferInfo() : info; +} + +// Try to match Windows' behavior w.r.t. to the LVB attribute flags. In some +// situations, Windows ignores the LVB flags on a character cell because of +// backwards compatibility -- apparently some programs set the flags without +// intending to enable reverse-video or underscores. +// +// [rprichard 2017-01-15] I haven't actually noticed any old programs that need +// this treatment -- the motivation for this function comes from the MSDN +// documentation for SetConsoleMode and ENABLE_LVB_GRID_WORLDWIDE. +WORD Scraper::attributesMask() +{ + const auto WINPTY_ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4u; + const auto WINPTY_ENABLE_LVB_GRID_WORLDWIDE = 0x10u; + const auto WINPTY_COMMON_LVB_REVERSE_VIDEO = 0x4000u; + const auto WINPTY_COMMON_LVB_UNDERSCORE = 0x8000u; + + const auto cp = GetConsoleOutputCP(); + const auto isCjk = (cp == 932 || cp == 936 || cp == 949 || cp == 950); + + const DWORD outputMode = [this]{ + ASSERT(this->m_consoleBuffer != nullptr); + DWORD mode = 0; + if (!GetConsoleMode(this->m_consoleBuffer->conout(), &mode)) { + mode = 0; + } + return mode; + }(); + const bool hasEnableLvbGridWorldwide = + (outputMode & WINPTY_ENABLE_LVB_GRID_WORLDWIDE) != 0; + const bool hasEnableVtProcessing = + (outputMode & WINPTY_ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0; + + // The new Windows 10 console (as of 14393) seems to respect + // COMMON_LVB_REVERSE_VIDEO even in CP437 w/o the other enabling modes, so + // try to match that behavior. + const auto isReverseSupported = + isCjk || hasEnableLvbGridWorldwide || hasEnableVtProcessing || m_console.isNewW10(); + const auto isUnderscoreSupported = + isCjk || hasEnableLvbGridWorldwide || hasEnableVtProcessing; + + WORD mask = ~0; + if (!isReverseSupported) { mask &= ~WINPTY_COMMON_LVB_REVERSE_VIDEO; } + if (!isUnderscoreSupported) { mask &= ~WINPTY_COMMON_LVB_UNDERSCORE; } + return mask; +} + +void Scraper::directScrapeOutput(const ConsoleScreenBufferInfo &info, + bool consoleCursorVisible) +{ + const SmallRect windowRect = info.windowRect(); + + const SmallRect scrapeRect( + windowRect.left(), windowRect.top(), + std::min(std::min(windowRect.width(), m_ptySize.X), + MAX_CONSOLE_WIDTH), + std::min(std::min(windowRect.height(), m_ptySize.Y), + BUFFER_LINE_COUNT)); + const int w = scrapeRect.width(); + const int h = scrapeRect.height(); + + const Coord cursor = info.cursorPosition(); + const bool showTerminalCursor = + consoleCursorVisible && scrapeRect.contains(cursor); + const int cursorColumn = !showTerminalCursor ? -1 : cursor.X - scrapeRect.Left; + const int cursorLine = !showTerminalCursor ? -1 : cursor.Y - scrapeRect.Top; + + if (!showTerminalCursor) { + m_terminal->hideTerminalCursor(); + } + + largeConsoleRead(m_readBuffer, *m_consoleBuffer, scrapeRect, attributesMask()); + + for (int line = 0; line < h; ++line) { + const CHAR_INFO *const curLine = + m_readBuffer.lineData(scrapeRect.top() + line); + ConsoleLine &bufLine = m_bufferData[line]; + if (bufLine.detectChangeAndSetLine(curLine, w)) { + const int lineCursorColumn = + line == cursorLine ? cursorColumn : -1; + m_terminal->sendLine(line, curLine, w, lineCursorColumn); + } + } + + if (showTerminalCursor) { + m_terminal->showTerminalCursor(cursorColumn, cursorLine); + } +} + +bool Scraper::scrollingScrapeOutput(const ConsoleScreenBufferInfo &info, + bool consoleCursorVisible, + bool tentative) +{ + const Coord cursor = info.cursorPosition(); + const SmallRect windowRect = info.windowRect(); + + if (m_syncRow != -1) { + // If a synchronizing marker was placed into the history, look for it + // and adjust the scroll count. + const int markerRow = findSyncMarker(); + if (markerRow == -1) { + if (tentative) { + // I *think* it's possible to keep going, but it's simple to + // bail out. + return false; + } + // Something has happened. Reset the terminal. + trace("Sync marker has disappeared -- resetting the terminal" + " (m_syncCounter=%u)", + m_syncCounter); + resetConsoleTracking(Terminal::SendClear, windowRect.top()); + } else if (markerRow != m_syncRow) { + ASSERT(markerRow < m_syncRow); + m_scrolledCount += (m_syncRow - markerRow); + m_syncRow = markerRow; + // If the buffer has scrolled, then the entire window is dirty. + markEntireWindowDirty(windowRect); + } + } + + // Creating a new sync row requires clearing part of the console buffer, so + // avoid doing it if there's already a sync row that's good enough. + const int newSyncRow = + static_cast(windowRect.top()) - SYNC_MARKER_LEN - SYNC_MARKER_MARGIN; + const bool shouldCreateSyncRow = + newSyncRow >= m_syncRow + SYNC_MARKER_LEN + SYNC_MARKER_MARGIN; + if (tentative && shouldCreateSyncRow) { + // It's difficult even in principle to put down a new marker if the + // console can scroll an arbitrarily amount while we're writing. + return false; + } + + // Update the dirty line count: + // - If the window has moved, the entire window is dirty. + // - Everything up to the cursor is dirty. + // - All lines above the window are dirty. + // - Any non-blank lines are dirty. + if (m_dirtyWindowTop != -1) { + if (windowRect.top() > m_dirtyWindowTop) { + // The window has moved down, presumably as a result of scrolling. + markEntireWindowDirty(windowRect); + } else if (windowRect.top() < m_dirtyWindowTop) { + if (tentative) { + // I *think* it's possible to keep going, but it's simple to + // bail out. + return false; + } + // The window has moved upward. This is generally not expected to + // happen, but the CMD/PowerShell CLS command will move the window + // to the top as part of clearing everything else in the console. + trace("Window moved upward -- resetting the terminal" + " (m_syncCounter=%u)", + m_syncCounter); + resetConsoleTracking(Terminal::SendClear, windowRect.top()); + } + } + m_dirtyWindowTop = windowRect.top(); + m_dirtyLineCount = std::max(m_dirtyLineCount, cursor.Y + 1); + m_dirtyLineCount = std::max(m_dirtyLineCount, (int)windowRect.top()); + + // There will be at least one dirty line, because there is a cursor. + ASSERT(m_dirtyLineCount >= 1); + + // The first line to scrape, in virtual line coordinates. + const int64_t firstVirtLine = std::min(m_scrapedLineCount, + windowRect.top() + m_scrolledCount); + + // Read all the data we will need from the console. Start reading with the + // first line to scrape, but adjust the the read area upward to account for + // scanForDirtyLines' need to read the previous attribute. Read to the + // bottom of the window. (It's not clear to me whether the + // m_dirtyLineCount adjustment here is strictly necessary. It isn't + // necessary so long as the cursor is inside the current window.) + const int firstReadLine = std::min(firstVirtLine - m_scrolledCount, + m_dirtyLineCount - 1); + const int stopReadLine = std::max(windowRect.top() + windowRect.height(), + m_dirtyLineCount); + ASSERT(firstReadLine >= 0 && stopReadLine > firstReadLine); + largeConsoleRead(m_readBuffer, + *m_consoleBuffer, + SmallRect(0, firstReadLine, + std::min(info.bufferSize().X, + MAX_CONSOLE_WIDTH), + stopReadLine - firstReadLine), + attributesMask()); + + // If we're scraping the buffer without freezing it, we have to query the + // buffer position data separately from the buffer content, so the two + // could easily be out-of-sync. If they *are* out-of-sync, abort the + // scrape operation and restart it frozen. (We may have updated the + // dirty-line high-water-mark, but that should be OK.) + if (tentative) { + const auto infoCheck = m_consoleBuffer->bufferInfo(); + if (info.bufferSize() != infoCheck.bufferSize() || + info.windowRect() != infoCheck.windowRect() || + info.cursorPosition() != infoCheck.cursorPosition()) { + return false; + } + if (m_syncRow != -1 && m_syncRow != findSyncMarker()) { + return false; + } + } + + if (shouldCreateSyncRow) { + ASSERT(!tentative); + createSyncMarker(newSyncRow); + } + + // At this point, we're finished interacting (reading or writing) the + // console, and we just need to convert our collected data into terminal + // output. + + scanForDirtyLines(windowRect); + + // Note that it's possible for all the lines on the current window to + // be non-dirty. + + // The line to stop scraping at, in virtual line coordinates. + const int64_t stopVirtLine = + std::min(m_dirtyLineCount, windowRect.top() + windowRect.height()) + + m_scrolledCount; + + const bool showTerminalCursor = + consoleCursorVisible && windowRect.contains(cursor); + const int64_t cursorLine = !showTerminalCursor ? -1 : cursor.Y + m_scrolledCount; + const int cursorColumn = !showTerminalCursor ? -1 : cursor.X; + + if (!showTerminalCursor) { + m_terminal->hideTerminalCursor(); + } + + bool sawModifiedLine = false; + + const int w = m_readBuffer.rect().width(); + for (int64_t line = firstVirtLine; line < stopVirtLine; ++line) { + const CHAR_INFO *curLine = + m_readBuffer.lineData(line - m_scrolledCount); + ConsoleLine &bufLine = m_bufferData[line % BUFFER_LINE_COUNT]; + if (line > m_maxBufferedLine) { + m_maxBufferedLine = line; + sawModifiedLine = true; + } + if (sawModifiedLine) { + bufLine.setLine(curLine, w); + } else { + sawModifiedLine = bufLine.detectChangeAndSetLine(curLine, w); + } + if (sawModifiedLine) { + const int lineCursorColumn = + line == cursorLine ? cursorColumn : -1; + m_terminal->sendLine(line, curLine, w, lineCursorColumn); + } + } + + m_scrapedLineCount = windowRect.top() + m_scrolledCount; + + if (showTerminalCursor) { + m_terminal->showTerminalCursor(cursorColumn, cursorLine); + } + + return true; +} + +void Scraper::syncMarkerText(CHAR_INFO (&output)[SYNC_MARKER_LEN]) +{ + // XXX: The marker text generated here could easily collide with ordinary + // console output. Does it make sense to try to avoid the collision? + char str[SYNC_MARKER_LEN + 1]; + winpty_snprintf(str, "S*Y*N*C*%08x", m_syncCounter); + for (int i = 0; i < SYNC_MARKER_LEN; ++i) { + output[i].Char.UnicodeChar = str[i]; + output[i].Attributes = 7; + } +} + +int Scraper::findSyncMarker() +{ + ASSERT(m_syncRow >= 0); + CHAR_INFO marker[SYNC_MARKER_LEN]; + CHAR_INFO column[BUFFER_LINE_COUNT]; + syncMarkerText(marker); + SmallRect rect(0, 0, 1, m_syncRow + SYNC_MARKER_LEN); + m_consoleBuffer->read(rect, column); + int i; + for (i = m_syncRow; i >= 0; --i) { + int j; + for (j = 0; j < SYNC_MARKER_LEN; ++j) { + if (column[i + j].Char.UnicodeChar != marker[j].Char.UnicodeChar) + break; + } + if (j == SYNC_MARKER_LEN) + return i; + } + return -1; +} + +void Scraper::createSyncMarker(int row) +{ + ASSERT(row >= 1); + + // Clear the lines around the marker to ensure that Windows 10's rewrapping + // does not affect the marker. + m_consoleBuffer->clearLines(row - 1, SYNC_MARKER_LEN + 1, + m_consoleBuffer->bufferInfo()); + + // Write a new marker. + m_syncCounter++; + CHAR_INFO marker[SYNC_MARKER_LEN]; + syncMarkerText(marker); + m_syncRow = row; + SmallRect markerRect(0, m_syncRow, 1, SYNC_MARKER_LEN); + m_consoleBuffer->write(markerRect, marker); +} diff --git a/src/libs/3rdparty/winpty/src/agent/Scraper.h b/src/libs/3rdparty/winpty/src/agent/Scraper.h new file mode 100644 index 00000000000..9c10d80aedc --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Scraper.h @@ -0,0 +1,103 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef AGENT_SCRAPER_H +#define AGENT_SCRAPER_H + +#include + +#include + +#include +#include + +#include "ConsoleLine.h" +#include "Coord.h" +#include "LargeConsoleRead.h" +#include "SmallRect.h" +#include "Terminal.h" + +class ConsoleScreenBufferInfo; +class Win32Console; +class Win32ConsoleBuffer; + +// We must be able to issue a single ReadConsoleOutputW call of +// MAX_CONSOLE_WIDTH characters, and a single read of approximately several +// hundred fewer characters than BUFFER_LINE_COUNT. +const int BUFFER_LINE_COUNT = 3000; +const int MAX_CONSOLE_WIDTH = 2500; +const int MAX_CONSOLE_HEIGHT = 2000; +const int SYNC_MARKER_LEN = 16; +const int SYNC_MARKER_MARGIN = 200; + +class Scraper { +public: + Scraper( + Win32Console &console, + Win32ConsoleBuffer &buffer, + std::unique_ptr terminal, + Coord initialSize); + ~Scraper(); + void resizeWindow(Win32ConsoleBuffer &buffer, + Coord newSize, + ConsoleScreenBufferInfo &finalInfoOut); + void scrapeBuffer(Win32ConsoleBuffer &buffer, + ConsoleScreenBufferInfo &finalInfoOut); + Terminal &terminal() { return *m_terminal; } + +private: + void resetConsoleTracking( + Terminal::SendClearFlag sendClear, int64_t scrapedLineCount); + void markEntireWindowDirty(const SmallRect &windowRect); + void scanForDirtyLines(const SmallRect &windowRect); + void clearBufferLines(int firstRow, int count); + void resizeImpl(const ConsoleScreenBufferInfo &origInfo); + void syncConsoleContentAndSize(bool forceResize, + ConsoleScreenBufferInfo &finalInfoOut); + WORD attributesMask(); + void directScrapeOutput(const ConsoleScreenBufferInfo &info, + bool consoleCursorVisible); + bool scrollingScrapeOutput(const ConsoleScreenBufferInfo &info, + bool consoleCursorVisible, + bool tentative); + void syncMarkerText(CHAR_INFO (&output)[SYNC_MARKER_LEN]); + int findSyncMarker(); + void createSyncMarker(int row); + +private: + Win32Console &m_console; + Win32ConsoleBuffer *m_consoleBuffer = nullptr; + std::unique_ptr m_terminal; + + int m_syncRow = -1; + unsigned int m_syncCounter = 0; + + bool m_directMode = false; + Coord m_ptySize; + int64_t m_scrapedLineCount = 0; + int64_t m_scrolledCount = 0; + int64_t m_maxBufferedLine = -1; + LargeConsoleReadBuffer m_readBuffer; + std::vector m_bufferData; + int m_dirtyWindowTop = -1; + int m_dirtyLineCount = 0; +}; + +#endif // AGENT_SCRAPER_H diff --git a/src/libs/3rdparty/winpty/src/agent/SimplePool.h b/src/libs/3rdparty/winpty/src/agent/SimplePool.h new file mode 100644 index 00000000000..41ff94a90de --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/SimplePool.h @@ -0,0 +1,75 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef SIMPLE_POOL_H +#define SIMPLE_POOL_H + +#include + +#include + +#include "../shared/WinptyAssert.h" + +template +class SimplePool { +public: + ~SimplePool(); + T *alloc(); + void clear(); +private: + struct Chunk { + size_t count; + T *data; + }; + std::vector m_chunks; +}; + +template +SimplePool::~SimplePool() { + clear(); +} + +template +void SimplePool::clear() { + for (size_t ci = 0; ci < m_chunks.size(); ++ci) { + Chunk &chunk = m_chunks[ci]; + for (size_t ti = 0; ti < chunk.count; ++ti) { + chunk.data[ti].~T(); + } + free(chunk.data); + } + m_chunks.clear(); +} + +template +T *SimplePool::alloc() { + if (m_chunks.empty() || m_chunks.back().count == chunkSize) { + T *newData = reinterpret_cast(malloc(sizeof(T) * chunkSize)); + ASSERT(newData != NULL); + Chunk newChunk = { 0, newData }; + m_chunks.push_back(newChunk); + } + Chunk &chunk = m_chunks.back(); + T *ret = &chunk.data[chunk.count++]; + new (ret) T(); + return ret; +} + +#endif // SIMPLE_POOL_H diff --git a/src/libs/3rdparty/winpty/src/agent/SmallRect.h b/src/libs/3rdparty/winpty/src/agent/SmallRect.h new file mode 100644 index 00000000000..bad0b88683a --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/SmallRect.h @@ -0,0 +1,143 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef SMALLRECT_H +#define SMALLRECT_H + +#include + +#include +#include + +#include "../shared/winpty_snprintf.h" +#include "Coord.h" + +struct SmallRect : SMALL_RECT +{ + SmallRect() + { + Left = Right = Top = Bottom = 0; + } + + SmallRect(SHORT x, SHORT y, SHORT width, SHORT height) + { + Left = x; + Top = y; + Right = x + width - 1; + Bottom = y + height - 1; + } + + SmallRect(const COORD &topLeft, const COORD &size) + { + Left = topLeft.X; + Top = topLeft.Y; + Right = Left + size.X - 1; + Bottom = Top + size.Y - 1; + } + + SmallRect(const SMALL_RECT &other) + { + *(SMALL_RECT*)this = other; + } + + SmallRect(const SmallRect &other) + { + *(SMALL_RECT*)this = *(const SMALL_RECT*)&other; + } + + SmallRect &operator=(const SmallRect &other) + { + *(SMALL_RECT*)this = *(const SMALL_RECT*)&other; + return *this; + } + + bool contains(const SmallRect &other) const + { + return other.Left >= Left && + other.Right <= Right && + other.Top >= Top && + other.Bottom <= Bottom; + } + + bool contains(const Coord &other) const + { + return other.X >= Left && + other.X <= Right && + other.Y >= Top && + other.Y <= Bottom; + } + + SmallRect intersected(const SmallRect &other) const + { + int x1 = std::max(Left, other.Left); + int x2 = std::min(Right, other.Right); + int y1 = std::max(Top, other.Top); + int y2 = std::min(Bottom, other.Bottom); + return SmallRect(x1, + y1, + std::max(0, x2 - x1 + 1), + std::max(0, y2 - y1 + 1)); + } + + SmallRect ensureLineIncluded(SHORT line) const + { + const SHORT h = height(); + if (line < Top) { + return SmallRect(Left, line, width(), h); + } else if (line > Bottom) { + return SmallRect(Left, line - h + 1, width(), h); + } else { + return *this; + } + } + + SHORT top() const { return Top; } + SHORT left() const { return Left; } + SHORT width() const { return Right - Left + 1; } + SHORT height() const { return Bottom - Top + 1; } + void setTop(SHORT top) { Top = top; } + void setLeft(SHORT left) { Left = left; } + void setWidth(SHORT width) { Right = Left + width - 1; } + void setHeight(SHORT height) { Bottom = Top + height - 1; } + Coord size() const { return Coord(width(), height()); } + + bool operator==(const SmallRect &other) const + { + return Left == other.Left && + Right == other.Right && + Top == other.Top && + Bottom == other.Bottom; + } + + bool operator!=(const SmallRect &other) const + { + return !(*this == other); + } + + std::string toString() const + { + char ret[64]; + winpty_snprintf(ret, "(x=%d,y=%d,w=%d,h=%d)", + Left, Top, width(), height()); + return std::string(ret); + } +}; + +#endif // SMALLRECT_H diff --git a/src/libs/3rdparty/winpty/src/agent/Terminal.cc b/src/libs/3rdparty/winpty/src/agent/Terminal.cc new file mode 100644 index 00000000000..afa0a362600 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Terminal.cc @@ -0,0 +1,535 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "Terminal.h" + +#include +#include +#include + +#include + +#include "NamedPipe.h" +#include "UnicodeEncoding.h" +#include "../shared/DebugClient.h" +#include "../shared/WinptyAssert.h" +#include "../shared/winpty_snprintf.h" + +#define CSI "\x1b[" + +// Work around the old MinGW, which lacks COMMON_LVB_LEADING_BYTE and +// COMMON_LVB_TRAILING_BYTE. +const int WINPTY_COMMON_LVB_LEADING_BYTE = 0x100; +const int WINPTY_COMMON_LVB_TRAILING_BYTE = 0x200; +const int WINPTY_COMMON_LVB_REVERSE_VIDEO = 0x4000; +const int WINPTY_COMMON_LVB_UNDERSCORE = 0x8000; + +const int COLOR_ATTRIBUTE_MASK = + FOREGROUND_BLUE | + FOREGROUND_GREEN | + FOREGROUND_RED | + FOREGROUND_INTENSITY | + BACKGROUND_BLUE | + BACKGROUND_GREEN | + BACKGROUND_RED | + BACKGROUND_INTENSITY | + WINPTY_COMMON_LVB_REVERSE_VIDEO | + WINPTY_COMMON_LVB_UNDERSCORE; + +const int FLAG_RED = 1; +const int FLAG_GREEN = 2; +const int FLAG_BLUE = 4; +const int FLAG_BRIGHT = 8; + +const int BLACK = 0; +const int DKGRAY = BLACK | FLAG_BRIGHT; +const int LTGRAY = FLAG_RED | FLAG_GREEN | FLAG_BLUE; +const int WHITE = LTGRAY | FLAG_BRIGHT; + +// SGR parameters (Select Graphic Rendition) +const int SGR_FORE = 30; +const int SGR_FORE_HI = 90; +const int SGR_BACK = 40; +const int SGR_BACK_HI = 100; + +namespace { + +static void outUInt(std::string &out, unsigned int n) +{ + char buf[32]; + char *pbuf = &buf[32]; + *(--pbuf) = '\0'; + do { + *(--pbuf) = '0' + n % 10; + n /= 10; + } while (n != 0); + out.append(pbuf); +} + +static void outputSetColorSgrParams(std::string &out, bool isFore, int color) +{ + out.push_back(';'); + const int sgrBase = isFore ? SGR_FORE : SGR_BACK; + if (color & FLAG_BRIGHT) { + // Some terminals don't support the 9X/10X "intensive" color parameters + // (e.g. the Eclipse TM terminal as of this writing). Those terminals + // will quietly ignore a 9X/10X code, and the other terminals will + // ignore a 3X/4X code if it's followed by a 9X/10X code. Therefore, + // output a 3X/4X code as a fallback, then override it. + const int colorBase = color & ~FLAG_BRIGHT; + outUInt(out, sgrBase + colorBase); + out.push_back(';'); + outUInt(out, sgrBase + (SGR_FORE_HI - SGR_FORE) + colorBase); + } else { + outUInt(out, sgrBase + color); + } +} + +static void outputSetColor(std::string &out, int color) +{ + int fore = 0; + int back = 0; + if (color & FOREGROUND_RED) fore |= FLAG_RED; + if (color & FOREGROUND_GREEN) fore |= FLAG_GREEN; + if (color & FOREGROUND_BLUE) fore |= FLAG_BLUE; + if (color & FOREGROUND_INTENSITY) fore |= FLAG_BRIGHT; + if (color & BACKGROUND_RED) back |= FLAG_RED; + if (color & BACKGROUND_GREEN) back |= FLAG_GREEN; + if (color & BACKGROUND_BLUE) back |= FLAG_BLUE; + if (color & BACKGROUND_INTENSITY) back |= FLAG_BRIGHT; + + if (color & WINPTY_COMMON_LVB_REVERSE_VIDEO) { + // n.b.: The COMMON_LVB_REVERSE_VIDEO flag also swaps + // FOREGROUND_INTENSITY and BACKGROUND_INTENSITY. Tested on + // Windows 10 v14393. + std::swap(fore, back); + } + + // Translate the fore/back colors into terminal escape codes using + // a heuristic that works OK with common white-on-black or + // black-on-white color schemes. We don't know which color scheme + // the terminal is using. It is ugly to force white-on-black text + // on a black-on-white terminal, and it's even ugly to force the + // matching scheme. It's probably relevant that the default + // fore/back terminal colors frequently do not match any of the 16 + // palette colors. + + // Typical default terminal color schemes (according to palette, + // when possible): + // - mintty: LtGray-on-Black(A) + // - putty: LtGray-on-Black(A) + // - xterm: LtGray-on-Black(A) + // - Konsole: LtGray-on-Black(A) + // - JediTerm/JetBrains: Black-on-White(B) + // - rxvt: Black-on-White(B) + + // If the background is the default color (black), then it will + // map to Black(A) or White(B). If we translate White to White, + // then a Black background and a White background in the console + // are both White with (B). Therefore, we should translate White + // using SGR 7 (Invert). The typical finished mapping table for + // background grayscale colors is: + // + // (A) White => LtGray(fore) + // (A) Black => Black(back) + // (A) LtGray => LtGray + // (A) DkGray => DkGray + // + // (B) White => Black(fore) + // (B) Black => White(back) + // (B) LtGray => LtGray + // (B) DkGray => DkGray + // + + out.append(CSI "0"); + if (back == BLACK) { + if (fore == LTGRAY) { + // The "default" foreground color. Use the terminal's + // default colors. + } else if (fore == WHITE) { + // Sending the literal color white would behave poorly if + // the terminal were black-on-white. Sending Bold is not + // guaranteed to alter the color, but it will make the text + // visually distinct, so do that instead. + out.append(";1"); + } else if (fore == DKGRAY) { + // Set the foreground color to DkGray(90) with a fallback + // of LtGray(37) for terminals that don't handle the 9X SGR + // parameters (e.g. Eclipse's TM Terminal as of this + // writing). + out.append(";37;90"); + } else { + outputSetColorSgrParams(out, true, fore); + } + } else if (back == WHITE) { + // Set the background color using Invert on the default + // foreground color, and set the foreground color by setting a + // background color. + + // Use the terminal's inverted colors. + out.append(";7"); + if (fore == LTGRAY || fore == BLACK) { + // We're likely mapping Console White to terminal LtGray or + // Black. If they are the Console foreground color, then + // don't set a terminal foreground color to avoid creating + // invisible text. + } else { + outputSetColorSgrParams(out, false, fore); + } + } else { + // Set the foreground and background to match exactly that in + // the Windows console. + outputSetColorSgrParams(out, true, fore); + outputSetColorSgrParams(out, false, back); + } + if (fore == back) { + // The foreground and background colors are exactly equal, so + // attempt to hide the text using the Conceal SGR parameter, + // which some terminals support. + out.append(";8"); + } + if (color & WINPTY_COMMON_LVB_UNDERSCORE) { + out.append(";4"); + } + out.push_back('m'); +} + +static inline unsigned int fixSpecialCharacters(unsigned int ch) +{ + if (ch <= 0x1b) { + switch (ch) { + // The Windows Console has a popup window (e.g. that appears with + // F7) that is sometimes bordered with box-drawing characters. + // With the Japanese and Korean system locales (CP932 and CP949), + // the UnicodeChar values for the box-drawing characters are 1 + // through 6. Detect this and map the values to the correct + // Unicode values. + // + // N.B. In the English locale, the UnicodeChar values are correct, + // and they identify single-line characters rather than + // double-line. In the Chinese Simplified and Traditional locales, + // the popups use ASCII characters instead. + case 1: return 0x2554; // BOX DRAWINGS DOUBLE DOWN AND RIGHT + case 2: return 0x2557; // BOX DRAWINGS DOUBLE DOWN AND LEFT + case 3: return 0x255A; // BOX DRAWINGS DOUBLE UP AND RIGHT + case 4: return 0x255D; // BOX DRAWINGS DOUBLE UP AND LEFT + case 5: return 0x2551; // BOX DRAWINGS DOUBLE VERTICAL + case 6: return 0x2550; // BOX DRAWINGS DOUBLE HORIZONTAL + + // Convert an escape character to some other character. This + // conversion only applies to console cells containing an escape + // character. In newer versions of Windows 10 (e.g. 10.0.10586), + // the non-legacy console recognizes escape sequences in + // WriteConsole and interprets them without writing them to the + // cells of the screen buffer. In that case, the conversion here + // does not apply. + case 0x1b: return '?'; + } + } + return ch; +} + +static inline bool isFullWidthCharacter(const CHAR_INFO *data, int width) +{ + if (width < 2) { + return false; + } + return + (data[0].Attributes & WINPTY_COMMON_LVB_LEADING_BYTE) && + (data[1].Attributes & WINPTY_COMMON_LVB_TRAILING_BYTE) && + data[0].Char.UnicodeChar == data[1].Char.UnicodeChar; +} + +// Scan to find a single Unicode Scalar Value. Full-width characters occupy +// two console cells, and this code also tries to handle UTF-16 surrogate +// pairs. +// +// Windows expands at least some wide characters outside the Basic +// Multilingual Plane into four cells, such as U+20000: +// 1. 0xD840, attr=0x107 +// 2. 0xD840, attr=0x207 +// 3. 0xDC00, attr=0x107 +// 4. 0xDC00, attr=0x207 +// Even in the Traditional Chinese locale on Windows 10, this text is rendered +// as two boxes, but if those boxes are copied-and-pasted, the character is +// copied correctly. +static inline void scanUnicodeScalarValue( + const CHAR_INFO *data, int width, + int &outCellCount, unsigned int &outCharValue) +{ + ASSERT(width >= 1); + + const int w1 = isFullWidthCharacter(data, width) ? 2 : 1; + const wchar_t c1 = data[0].Char.UnicodeChar; + + if ((c1 & 0xF800) == 0xD800) { + // The first cell is either a leading or trailing surrogate pair. + if ((c1 & 0xFC00) != 0xD800 || + width <= w1 || + ((data[w1].Char.UnicodeChar & 0xFC00) != 0xDC00)) { + // Invalid surrogate pair + outCellCount = w1; + outCharValue = '?'; + } else { + // Valid surrogate pair + outCellCount = w1 + (isFullWidthCharacter(&data[w1], width - w1) ? 2 : 1); + outCharValue = decodeSurrogatePair(c1, data[w1].Char.UnicodeChar); + } + } else { + outCellCount = w1; + outCharValue = c1; + } +} + +} // anonymous namespace + +void Terminal::reset(SendClearFlag sendClearFirst, int64_t newLine) +{ + if (sendClearFirst == SendClear && !m_plainMode) { + // 0m ==> reset SGR parameters + // 1;1H ==> move cursor to top-left position + // 2J ==> clear the entire screen + m_output.write(CSI "0m" CSI "1;1H" CSI "2J"); + } + m_remoteLine = newLine; + m_remoteColumn = 0; + m_lineData.clear(); + m_cursorHidden = false; + m_remoteColor = -1; +} + +void Terminal::sendLine(int64_t line, const CHAR_INFO *lineData, int width, + int cursorColumn) +{ + ASSERT(width >= 1); + + moveTerminalToLine(line); + + // If possible, see if we can append to what we've already output for this + // line. + if (m_lineDataValid) { + ASSERT(m_lineData.size() == static_cast(m_remoteColumn)); + if (m_remoteColumn > 0) { + // In normal mode, if m_lineData.size() equals `width`, then we + // will have trouble outputing the "erase rest of line" command, + // which must be output before reaching the end of the line. In + // plain mode, we don't output that command, so we're OK with a + // full line. + bool okWidth = false; + if (m_plainMode) { + okWidth = static_cast(width) >= m_lineData.size(); + } else { + okWidth = static_cast(width) > m_lineData.size(); + } + if (!okWidth || + memcmp(m_lineData.data(), lineData, + sizeof(CHAR_INFO) * m_lineData.size()) != 0) { + m_lineDataValid = false; + } + } + } + if (!m_lineDataValid) { + // We can't reuse, so we must reset this line. + hideTerminalCursor(); + if (m_plainMode) { + // We can't backtrack, so repeat this line. + m_output.write("\r\n"); + } else { + m_output.write("\r"); + } + m_lineDataValid = true; + m_lineData.clear(); + m_remoteColumn = 0; + } + + std::string &termLine = m_termLineWorkingBuffer; + termLine.clear(); + size_t trimmedLineLength = 0; + int trimmedCellCount = m_lineData.size(); + bool alreadyErasedLine = false; + + int cellCount = 1; + for (int i = m_lineData.size(); i < width; i += cellCount) { + if (m_outputColor) { + int color = lineData[i].Attributes & COLOR_ATTRIBUTE_MASK; + if (color != m_remoteColor) { + outputSetColor(termLine, color); + trimmedLineLength = termLine.size(); + m_remoteColor = color; + + // All the cells just up to this color change will be output. + trimmedCellCount = i; + } + } + unsigned int ch; + scanUnicodeScalarValue(&lineData[i], width - i, cellCount, ch); + if (ch == ' ') { + // Tentatively add this space character. We'll only output it if + // we see something interesting after it. + termLine.push_back(' '); + } else { + if (i + cellCount == width) { + // We'd like to erase the line after outputting all non-blank + // characters, but this doesn't work if the last cell in the + // line is non-blank. At the point, the cursor is positioned + // just past the end of the line, but in many terminals, + // issuing a CSI 0K at that point also erases the last cell in + // the line. Work around this behavior by issuing the erase + // one character early in that case. + if (!m_plainMode) { + termLine.append(CSI "0K"); // Erase from cursor to EOL + } + alreadyErasedLine = true; + } + ch = fixSpecialCharacters(ch); + char enc[4]; + int enclen = encodeUtf8(enc, ch); + if (enclen == 0) { + enc[0] = '?'; + enclen = 1; + } + termLine.append(enc, enclen); + trimmedLineLength = termLine.size(); + + // All the cells up to and including this cell will be output. + trimmedCellCount = i + cellCount; + } + } + + if (cursorColumn != -1 && trimmedCellCount > cursorColumn) { + // The line content would run past the cursor, so hide it before we + // output. + hideTerminalCursor(); + } + + m_output.write(termLine.data(), trimmedLineLength); + if (!alreadyErasedLine && !m_plainMode) { + m_output.write(CSI "0K"); // Erase from cursor to EOL + } + + ASSERT(trimmedCellCount <= width); + m_lineData.insert(m_lineData.end(), + &lineData[m_lineData.size()], + &lineData[trimmedCellCount]); + m_remoteColumn = trimmedCellCount; +} + +void Terminal::showTerminalCursor(int column, int64_t line) +{ + moveTerminalToLine(line); + if (!m_plainMode) { + if (m_remoteColumn != column) { + char buffer[32]; + winpty_snprintf(buffer, CSI "%dG", column + 1); + m_output.write(buffer); + m_lineDataValid = (column == 0); + m_lineData.clear(); + m_remoteColumn = column; + } + if (m_cursorHidden) { + m_output.write(CSI "?25h"); + m_cursorHidden = false; + } + } +} + +void Terminal::hideTerminalCursor() +{ + if (!m_plainMode) { + if (m_cursorHidden) { + return; + } + m_output.write(CSI "?25l"); + m_cursorHidden = true; + } +} + +void Terminal::moveTerminalToLine(int64_t line) +{ + if (line == m_remoteLine) { + return; + } + + // Do not use CPL or CNL. Konsole 2.5.4 does not support Cursor Previous + // Line (CPL) -- there are "Undecodable sequence" errors. gnome-terminal + // 2.32.0 does handle it. Cursor Next Line (CNL) does nothing if the + // cursor is on the last line already. + + hideTerminalCursor(); + + if (line < m_remoteLine) { + if (m_plainMode) { + // We can't backtrack, so instead repeat the lines again. + m_output.write("\r\n"); + m_remoteLine = line; + } else { + // Backtrack and overwrite previous lines. + // CUrsor Up (CUU) + char buffer[32]; + winpty_snprintf(buffer, "\r" CSI "%uA", + static_cast(m_remoteLine - line)); + m_output.write(buffer); + m_remoteLine = line; + } + } else if (line > m_remoteLine) { + while (line > m_remoteLine) { + m_output.write("\r\n"); + m_remoteLine++; + } + } + + m_lineDataValid = true; + m_lineData.clear(); + m_remoteColumn = 0; +} + +void Terminal::enableMouseMode(bool enabled) +{ + if (m_mouseModeEnabled == enabled || m_plainMode) { + return; + } + m_mouseModeEnabled = enabled; + if (enabled) { + // Start by disabling UTF-8 coordinate mode (1005), just in case we + // have a terminal that does not support 1006/1015 modes, and 1005 + // happens to be enabled. The UTF-8 coordinates can't be unambiguously + // decoded. + // + // Enable basic mouse support first (1000), then try to switch to + // button-move mode (1002), then try full mouse-move mode (1003). + // Terminals that don't support a mode will be stuck at the highest + // mode they do support. + // + // Enable encoding mode 1015 first, then try to switch to 1006. On + // some terminals, both modes will be enabled, but 1006 will have + // priority. On other terminals, 1006 wins because it's listed last. + // + // See misc/MouseInputNotes.txt for details. + m_output.write( + CSI "?1005l" + CSI "?1000h" CSI "?1002h" CSI "?1003h" CSI "?1015h" CSI "?1006h"); + } else { + // Resetting both encoding modes (1006 and 1015) is necessary, but + // apparently we only need to use reset on one of the 100[023] modes. + // Doing both doesn't hurt. + m_output.write( + CSI "?1006l" CSI "?1015l" CSI "?1003l" CSI "?1002l" CSI "?1000l"); + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/Terminal.h b/src/libs/3rdparty/winpty/src/agent/Terminal.h new file mode 100644 index 00000000000..058eb2650e7 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Terminal.h @@ -0,0 +1,69 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef TERMINAL_H +#define TERMINAL_H + +#include +#include + +#include +#include + +#include "Coord.h" + +class NamedPipe; + +class Terminal +{ +public: + explicit Terminal(NamedPipe &output, bool plainMode, bool outputColor) + : m_output(output), m_plainMode(plainMode), m_outputColor(outputColor) + { + } + + enum SendClearFlag { OmitClear, SendClear }; + void reset(SendClearFlag sendClearFirst, int64_t newLine); + void sendLine(int64_t line, const CHAR_INFO *lineData, int width, + int cursorColumn); + void showTerminalCursor(int column, int64_t line); + void hideTerminalCursor(); + +private: + void moveTerminalToLine(int64_t line); + +public: + void enableMouseMode(bool enabled); + +private: + NamedPipe &m_output; + int64_t m_remoteLine = 0; + int m_remoteColumn = 0; + bool m_lineDataValid = true; + std::vector m_lineData; + bool m_cursorHidden = false; + int m_remoteColor = -1; + std::string m_termLineWorkingBuffer; + bool m_plainMode = false; + bool m_outputColor = true; + bool m_mouseModeEnabled = false; +}; + +#endif // TERMINAL_H diff --git a/src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h b/src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h new file mode 100644 index 00000000000..6b0de3eff9f --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/UnicodeEncoding.h @@ -0,0 +1,157 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNICODE_ENCODING_H +#define UNICODE_ENCODING_H + +#include + +// Encode the Unicode codepoint with UTF-8. The buffer must be at least 4 +// bytes in size. +static inline int encodeUtf8(char *out, uint32_t code) { + if (code < 0x80) { + out[0] = code; + return 1; + } else if (code < 0x800) { + out[0] = ((code >> 6) & 0x1F) | 0xC0; + out[1] = ((code >> 0) & 0x3F) | 0x80; + return 2; + } else if (code < 0x10000) { + if (code >= 0xD800 && code <= 0xDFFF) { + // The code points 0xD800 to 0xDFFF are reserved for UTF-16 + // surrogate pairs and do not have an encoding in UTF-8. + return 0; + } + out[0] = ((code >> 12) & 0x0F) | 0xE0; + out[1] = ((code >> 6) & 0x3F) | 0x80; + out[2] = ((code >> 0) & 0x3F) | 0x80; + return 3; + } else if (code < 0x110000) { + out[0] = ((code >> 18) & 0x07) | 0xF0; + out[1] = ((code >> 12) & 0x3F) | 0x80; + out[2] = ((code >> 6) & 0x3F) | 0x80; + out[3] = ((code >> 0) & 0x3F) | 0x80; + return 4; + } else { + // Encoding error + return 0; + } +} + +// Encode the Unicode codepoint with UTF-16. The buffer must be large enough +// to hold the output -- either 1 or 2 elements. +static inline int encodeUtf16(wchar_t *out, uint32_t code) { + if (code < 0x10000) { + if (code >= 0xD800 && code <= 0xDFFF) { + // The code points 0xD800 to 0xDFFF are reserved for UTF-16 + // surrogate pairs and do not have an encoding in UTF-16. + return 0; + } + out[0] = code; + return 1; + } else if (code < 0x110000) { + code -= 0x10000; + out[0] = 0xD800 | (code >> 10); + out[1] = 0xDC00 | (code & 0x3FF); + return 2; + } else { + // Encoding error + return 0; + } +} + +// Return the byte size of a UTF-8 character using the value of the first +// byte. +static inline int utf8CharLength(char firstByte) { + // This code would probably be faster if it used __builtin_clz. + if ((firstByte & 0x80) == 0) { + return 1; + } else if ((firstByte & 0xE0) == 0xC0) { + return 2; + } else if ((firstByte & 0xF0) == 0xE0) { + return 3; + } else if ((firstByte & 0xF8) == 0xF0) { + return 4; + } else { + // Malformed UTF-8. + return 0; + } +} + +// The pointer must point to 1-4 bytes, as indicated by the first byte. +// Returns -1 on decoding error. +static inline uint32_t decodeUtf8(const char *in) { + const uint32_t kInvalid = static_cast(-1); + switch (utf8CharLength(in[0])) { + case 1: { + return in[0]; + } + case 2: { + if ((in[1] & 0xC0) != 0x80) { + return kInvalid; + } + uint32_t tmp = 0; + tmp = (in[0] & 0x1F) << 6; + tmp |= (in[1] & 0x3F); + return tmp <= 0x7F ? kInvalid : tmp; + } + case 3: { + if ((in[1] & 0xC0) != 0x80 || + (in[2] & 0xC0) != 0x80) { + return kInvalid; + } + uint32_t tmp = 0; + tmp = (in[0] & 0x0F) << 12; + tmp |= (in[1] & 0x3F) << 6; + tmp |= (in[2] & 0x3F); + if (tmp <= 0x07FF || (tmp >= 0xD800 && tmp <= 0xDFFF)) { + return kInvalid; + } else { + return tmp; + } + } + case 4: { + if ((in[1] & 0xC0) != 0x80 || + (in[2] & 0xC0) != 0x80 || + (in[3] & 0xC0) != 0x80) { + return kInvalid; + } + uint32_t tmp = 0; + tmp = (in[0] & 0x07) << 18; + tmp |= (in[1] & 0x3F) << 12; + tmp |= (in[2] & 0x3F) << 6; + tmp |= (in[3] & 0x3F); + if (tmp <= 0xFFFF || tmp > 0x10FFFF) { + return kInvalid; + } else { + return tmp; + } + } + default: { + return kInvalid; + } + } +} + +static inline uint32_t decodeSurrogatePair(wchar_t ch1, wchar_t ch2) { + return ((ch1 - 0xD800) << 10) + (ch2 - 0xDC00) + 0x10000; +} + +#endif // UNICODE_ENCODING_H diff --git a/src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc b/src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc new file mode 100644 index 00000000000..cd4abeb1916 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/UnicodeEncodingTest.cc @@ -0,0 +1,189 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Encode every code-point using this module and verify that it matches the +// encoding generated using Windows WideCharToMultiByte. + +#include "UnicodeEncoding.h" + +#include +#include +#include +#include +#include + +static void correctnessByCode() +{ + char mbstr1[4]; + char mbstr2[4]; + wchar_t wch[2]; + for (unsigned int code = 0; code < 0x110000; ++code) { + + // Surrogate pair reserved region. + const bool isReserved = (code >= 0xD800 && code <= 0xDFFF); + + int mblen1 = encodeUtf8(mbstr1, code); + if (isReserved ? mblen1 != 0 : mblen1 <= 0) { + printf("Error: 0x%04X: mblen1=%d\n", code, mblen1); + continue; + } + + int wlen = encodeUtf16(wch, code); + if (isReserved ? wlen != 0 : wlen <= 0) { + printf("Error: 0x%04X: wlen=%d\n", code, wlen); + continue; + } + + if (isReserved) { + continue; + } + + if (mblen1 != utf8CharLength(mbstr1[0])) { + printf("Error: 0x%04X: mblen1=%d, utf8CharLength(mbstr1[0])=%d\n", + code, mblen1, utf8CharLength(mbstr1[0])); + continue; + } + + if (code != decodeUtf8(mbstr1)) { + printf("Error: 0x%04X: decodeUtf8(mbstr1)=%u\n", + code, decodeUtf8(mbstr1)); + continue; + } + + int mblen2 = WideCharToMultiByte(CP_UTF8, 0, wch, wlen, mbstr2, 4, NULL, NULL); + if (mblen1 != mblen2) { + printf("Error: 0x%04X: mblen1=%d, mblen2=%d\n", code, mblen1, mblen2); + continue; + } + + if (memcmp(mbstr1, mbstr2, mblen1) != 0) { + printf("Error: 0x%04x: encodings are different\n", code); + continue; + } + } +} + +static const char *encodingStr(char (&output)[128], char (&buf)[4]) +{ + sprintf(output, "Encoding %02X %02X %02X %02X", + static_cast(buf[0]), + static_cast(buf[1]), + static_cast(buf[2]), + static_cast(buf[3])); + return output; +} + +// This test can take a couple of minutes to run. +static void correctnessByUtf8Encoding() +{ + for (uint64_t encoding = 0; encoding <= 0xFFFFFFFF; ++encoding) { + + char mb[4]; + mb[0] = encoding; + mb[1] = encoding >> 8; + mb[2] = encoding >> 16; + mb[3] = encoding >> 24; + + const int mblen = utf8CharLength(mb[0]); + if (mblen == 0) { + continue; + } + + // Test this module. + const uint32_t code1 = decodeUtf8(mb); + wchar_t ws1[2] = {}; + const int wslen1 = encodeUtf16(ws1, code1); + + // Test using Windows. We can't decode a codepoint directly; we have + // to do UTF8->UTF16, then decode the surrogate pair. + wchar_t ws2[2] = {}; + const int wslen2 = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, mb, mblen, ws2, 2); + const uint32_t code2 = + (wslen2 == 1 ? ws2[0] : + wslen2 == 2 ? decodeSurrogatePair(ws2[0], ws2[1]) : + static_cast(-1)); + + // Verify that the two implementations match. + char prefix[128]; + if (code1 != code2) { + printf("%s: code1=0x%04x code2=0x%04x\n", + encodingStr(prefix, mb), + code1, code2); + continue; + } + if (wslen1 != wslen2) { + printf("%s: wslen1=%d wslen2=%d\n", + encodingStr(prefix, mb), + wslen1, wslen2); + continue; + } + if (memcmp(ws1, ws2, wslen1 * sizeof(wchar_t)) != 0) { + printf("%s: ws1 != ws2\n", encodingStr(prefix, mb)); + continue; + } + } +} + +wchar_t g_wch_TEST[] = { 0xD840, 0xDC00 }; +char g_ch_TEST[4]; +wchar_t *volatile g_pwch = g_wch_TEST; +char *volatile g_pch = g_ch_TEST; +unsigned int volatile g_code = 0xA2000; + +static void performance() +{ + { + clock_t start = clock(); + for (long long i = 0; i < 250000000LL; ++i) { + int mblen = WideCharToMultiByte(CP_UTF8, 0, g_pwch, 2, g_pch, 4, NULL, NULL); + assert(mblen == 4); + } + clock_t stop = clock(); + printf("%.3fns per char\n", (double)(stop - start) / CLOCKS_PER_SEC * 4.0); + } + + { + clock_t start = clock(); + for (long long i = 0; i < 3000000000LL; ++i) { + int mblen = encodeUtf8(g_pch, g_code); + assert(mblen == 4); + } + clock_t stop = clock(); + printf("%.3fns per char\n", (double)(stop - start) / CLOCKS_PER_SEC / 3.0); + } +} + +int main() +{ + printf("Testing correctnessByCode...\n"); + fflush(stdout); + correctnessByCode(); + + printf("Testing correctnessByUtf8Encoding... (may take a couple minutes)\n"); + fflush(stdout); + correctnessByUtf8Encoding(); + + printf("Testing performance...\n"); + fflush(stdout); + performance(); + + return 0; +} diff --git a/src/libs/3rdparty/winpty/src/agent/Win32Console.cc b/src/libs/3rdparty/winpty/src/agent/Win32Console.cc new file mode 100644 index 00000000000..d53de021f5a --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Win32Console.cc @@ -0,0 +1,107 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "Win32Console.h" + +#include +#include + +#include + +#include "../shared/DebugClient.h" +#include "../shared/WinptyAssert.h" + +Win32Console::Win32Console() : m_titleWorkBuf(16) +{ + // The console window must be non-NULL. It is used for two purposes: + // (1) "Freezing" the console to detect the exact number of lines that + // have scrolled. + // (2) Killing processes attached to the console, by posting a WM_CLOSE + // message to the console window. + m_hwnd = GetConsoleWindow(); + ASSERT(m_hwnd != nullptr); +} + +std::wstring Win32Console::title() +{ + while (true) { + // Calling GetConsoleTitleW is tricky, because its behavior changed + // from XP->Vista, then again from Win7->Win8. The Vista+Win7 behavior + // is especially broken. + // + // The MSDN documentation documents nSize as the "size of the buffer + // pointed to by the lpConsoleTitle parameter, in characters" and the + // successful return value as "the length of the console window's + // title, in characters." + // + // On XP, the function returns the title length, AFTER truncation + // (excluding the NUL terminator). If the title is blank, the API + // returns 0 and does not NUL-terminate the buffer. To accommodate + // XP, the function must: + // * Terminate the buffer itself. + // * Double the size of the title buffer in a loop. + // + // On Vista and up, the function returns the non-truncated title + // length (excluding the NUL terminator). + // + // On Vista and Windows 7, there is a bug where the buffer size is + // interpreted as a byte count rather than a wchar_t count. To + // work around this, we must pass GetConsoleTitleW a buffer that is + // twice as large as what is actually needed. + // + // See misc/*/Test_GetConsoleTitleW.cc for tests demonstrating Windows' + // behavior. + + DWORD count = GetConsoleTitleW(m_titleWorkBuf.data(), + m_titleWorkBuf.size()); + const size_t needed = (count + 1) * sizeof(wchar_t); + if (m_titleWorkBuf.size() < needed) { + m_titleWorkBuf.resize(needed); + continue; + } + m_titleWorkBuf[count] = L'\0'; + return m_titleWorkBuf.data(); + } +} + +void Win32Console::setTitle(const std::wstring &title) +{ + if (!SetConsoleTitleW(title.c_str())) { + trace("SetConsoleTitleW failed"); + } +} + +void Win32Console::setFrozen(bool frozen) { + const int SC_CONSOLE_MARK = 0xFFF2; + const int SC_CONSOLE_SELECT_ALL = 0xFFF5; + if (frozen == m_frozen) { + // Do nothing. + } else if (frozen) { + // Enter selection mode by activating either Mark or SelectAll. + const int command = m_freezeUsesMark ? SC_CONSOLE_MARK + : SC_CONSOLE_SELECT_ALL; + SendMessage(m_hwnd, WM_SYSCOMMAND, command, 0); + m_frozen = true; + } else { + // Send Escape to cancel the selection. + SendMessage(m_hwnd, WM_CHAR, 27, 0x00010001); + m_frozen = false; + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/Win32Console.h b/src/libs/3rdparty/winpty/src/agent/Win32Console.h new file mode 100644 index 00000000000..ed83877e993 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Win32Console.h @@ -0,0 +1,67 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef AGENT_WIN32_CONSOLE_H +#define AGENT_WIN32_CONSOLE_H + +#include + +#include +#include + +class Win32Console +{ +public: + class FreezeGuard { + public: + FreezeGuard(Win32Console &console, bool frozen) : + m_console(console), m_previous(console.frozen()) { + m_console.setFrozen(frozen); + } + ~FreezeGuard() { + m_console.setFrozen(m_previous); + } + FreezeGuard(const FreezeGuard &other) = delete; + FreezeGuard &operator=(const FreezeGuard &other) = delete; + private: + Win32Console &m_console; + bool m_previous; + }; + + Win32Console(); + + HWND hwnd() { return m_hwnd; } + std::wstring title(); + void setTitle(const std::wstring &title); + void setFreezeUsesMark(bool useMark) { m_freezeUsesMark = useMark; } + void setNewW10(bool isNewW10) { m_isNewW10 = isNewW10; } + bool isNewW10() { return m_isNewW10; } + void setFrozen(bool frozen=true); + bool frozen() { return m_frozen; } + +private: + HWND m_hwnd = nullptr; + bool m_frozen = false; + bool m_freezeUsesMark = false; + bool m_isNewW10 = false; + std::vector m_titleWorkBuf; +}; + +#endif // AGENT_WIN32_CONSOLE_H diff --git a/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc new file mode 100644 index 00000000000..ed93f4081f8 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.cc @@ -0,0 +1,193 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "Win32ConsoleBuffer.h" + +#include + +#include "../shared/DebugClient.h" +#include "../shared/StringBuilder.h" +#include "../shared/WinptyAssert.h" + +std::unique_ptr Win32ConsoleBuffer::openStdout() { + return std::unique_ptr( + new Win32ConsoleBuffer(GetStdHandle(STD_OUTPUT_HANDLE), false)); +} + +std::unique_ptr Win32ConsoleBuffer::openConout() { + const HANDLE conout = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + ASSERT(conout != INVALID_HANDLE_VALUE); + return std::unique_ptr( + new Win32ConsoleBuffer(conout, true)); +} + +std::unique_ptr Win32ConsoleBuffer::createErrorBuffer() { + SECURITY_ATTRIBUTES sa = {}; + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + const HANDLE conout = + CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + CONSOLE_TEXTMODE_BUFFER, + nullptr); + ASSERT(conout != INVALID_HANDLE_VALUE); + return std::unique_ptr( + new Win32ConsoleBuffer(conout, true)); +} + +HANDLE Win32ConsoleBuffer::conout() { + return m_conout; +} + +void Win32ConsoleBuffer::clearLines( + int row, + int count, + const ConsoleScreenBufferInfo &info) { + // TODO: error handling + const int width = info.bufferSize().X; + DWORD actual = 0; + if (!FillConsoleOutputCharacterW( + m_conout, L' ', width * count, Coord(0, row), + &actual) || static_cast(actual) != width * count) { + trace("FillConsoleOutputCharacterW failed"); + } + if (!FillConsoleOutputAttribute( + m_conout, kDefaultAttributes, width * count, Coord(0, row), + &actual) || static_cast(actual) != width * count) { + trace("FillConsoleOutputAttribute failed"); + } +} + +void Win32ConsoleBuffer::clearAllLines(const ConsoleScreenBufferInfo &info) { + clearLines(0, info.bufferSize().Y, info); +} + +ConsoleScreenBufferInfo Win32ConsoleBuffer::bufferInfo() { + // TODO: error handling + ConsoleScreenBufferInfo info; + if (!GetConsoleScreenBufferInfo(m_conout, &info)) { + trace("GetConsoleScreenBufferInfo failed"); + } + return info; +} + +Coord Win32ConsoleBuffer::bufferSize() { + return bufferInfo().bufferSize(); +} + +SmallRect Win32ConsoleBuffer::windowRect() { + return bufferInfo().windowRect(); +} + +bool Win32ConsoleBuffer::resizeBufferRange(const Coord &initialSize, + Coord &finalSize) { + if (SetConsoleScreenBufferSize(m_conout, initialSize)) { + finalSize = initialSize; + return true; + } + // The font might be too small to accommodate a very narrow console window. + // In that case, rather than simply give up, it's better to try wider + // buffer sizes until the call succeeds. + Coord size = initialSize; + while (size.X < 20) { + size.X++; + if (SetConsoleScreenBufferSize(m_conout, size)) { + finalSize = size; + trace("SetConsoleScreenBufferSize: initial size (%d,%d) failed, " + "but wider size (%d,%d) succeeded", + initialSize.X, initialSize.Y, + finalSize.X, finalSize.Y); + return true; + } + } + trace("SetConsoleScreenBufferSize failed: " + "tried (%d,%d) through (%d,%d)", + initialSize.X, initialSize.Y, + size.X, size.Y); + return false; +} + +void Win32ConsoleBuffer::resizeBuffer(const Coord &size) { + // TODO: error handling + if (!SetConsoleScreenBufferSize(m_conout, size)) { + trace("SetConsoleScreenBufferSize failed: size=(%d,%d)", + size.X, size.Y); + } +} + +void Win32ConsoleBuffer::moveWindow(const SmallRect &rect) { + // TODO: error handling + if (!SetConsoleWindowInfo(m_conout, TRUE, &rect)) { + trace("SetConsoleWindowInfo failed"); + } +} + +Coord Win32ConsoleBuffer::cursorPosition() { + return bufferInfo().dwCursorPosition; +} + +void Win32ConsoleBuffer::setCursorPosition(const Coord &coord) { + // TODO: error handling + if (!SetConsoleCursorPosition(m_conout, coord)) { + trace("SetConsoleCursorPosition failed"); + } +} + +void Win32ConsoleBuffer::read(const SmallRect &rect, CHAR_INFO *data) { + // TODO: error handling + SmallRect tmp(rect); + if (!ReadConsoleOutputW(m_conout, data, rect.size(), Coord(), &tmp) && + isTracingEnabled()) { + StringBuilder sb(256); + auto outStruct = [&](const SMALL_RECT &sr) { + sb << "{L=" << sr.Left << ",T=" << sr.Top + << ",R=" << sr.Right << ",B=" << sr.Bottom << '}'; + }; + sb << "Win32ConsoleBuffer::read: ReadConsoleOutput failed: readRegion="; + outStruct(rect); + CONSOLE_SCREEN_BUFFER_INFO info = {}; + if (GetConsoleScreenBufferInfo(m_conout, &info)) { + sb << ", dwSize=(" << info.dwSize.X << ',' << info.dwSize.Y + << "), srWindow="; + outStruct(info.srWindow); + } else { + sb << ", GetConsoleScreenBufferInfo also failed"; + } + trace("%s", sb.c_str()); + } +} + +void Win32ConsoleBuffer::write(const SmallRect &rect, const CHAR_INFO *data) { + // TODO: error handling + SmallRect tmp(rect); + if (!WriteConsoleOutputW(m_conout, data, rect.size(), Coord(), &tmp)) { + trace("WriteConsoleOutput failed"); + } +} + +void Win32ConsoleBuffer::setTextAttribute(WORD attributes) { + if (!SetConsoleTextAttribute(m_conout, attributes)) { + trace("SetConsoleTextAttribute failed"); + } +} diff --git a/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h new file mode 100644 index 00000000000..a68d8d304fd --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/Win32ConsoleBuffer.h @@ -0,0 +1,99 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef AGENT_WIN32_CONSOLE_BUFFER_H +#define AGENT_WIN32_CONSOLE_BUFFER_H + +#include + +#include + +#include + +#include "Coord.h" +#include "SmallRect.h" + +class ConsoleScreenBufferInfo : public CONSOLE_SCREEN_BUFFER_INFO { +public: + ConsoleScreenBufferInfo() + { + memset(this, 0, sizeof(*this)); + } + + Coord bufferSize() const { return dwSize; } + SmallRect windowRect() const { return srWindow; } + Coord cursorPosition() const { return dwCursorPosition; } +}; + +class Win32ConsoleBuffer { +private: + Win32ConsoleBuffer(HANDLE conout, bool owned) : + m_conout(conout), m_owned(owned) + { + } + +public: + static const int kDefaultAttributes = 7; + + ~Win32ConsoleBuffer() { + if (m_owned) { + CloseHandle(m_conout); + } + } + + static std::unique_ptr openStdout(); + static std::unique_ptr openConout(); + static std::unique_ptr createErrorBuffer(); + + Win32ConsoleBuffer(const Win32ConsoleBuffer &other) = delete; + Win32ConsoleBuffer &operator=(const Win32ConsoleBuffer &other) = delete; + + HANDLE conout(); + void clearLines(int row, int count, const ConsoleScreenBufferInfo &info); + void clearAllLines(const ConsoleScreenBufferInfo &info); + + // Buffer and window sizes. + ConsoleScreenBufferInfo bufferInfo(); + Coord bufferSize(); + SmallRect windowRect(); + void resizeBuffer(const Coord &size); + bool resizeBufferRange(const Coord &initialSize, Coord &finalSize); + bool resizeBufferRange(const Coord &initialSize) { + Coord dummy; + return resizeBufferRange(initialSize, dummy); + } + void moveWindow(const SmallRect &rect); + + // Cursor. + Coord cursorPosition(); + void setCursorPosition(const Coord &point); + + // Screen content. + void read(const SmallRect &rect, CHAR_INFO *data); + void write(const SmallRect &rect, const CHAR_INFO *data); + + void setTextAttribute(WORD attributes); + +private: + HANDLE m_conout = nullptr; + bool m_owned = false; +}; + +#endif // AGENT_WIN32_CONSOLE_BUFFER_H diff --git a/src/libs/3rdparty/winpty/src/agent/main.cc b/src/libs/3rdparty/winpty/src/agent/main.cc new file mode 100644 index 00000000000..427cb3a3aa1 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/main.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include +#include +#include + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include + +#include "../shared/StringUtil.h" +#include "../shared/WindowsVersion.h" +#include "../shared/WinptyAssert.h" +#include "../shared/WinptyVersion.h" + +#include "Agent.h" +#include "AgentCreateDesktop.h" +#include "DebugShowInput.h" + +const char USAGE[] = +"Usage: %ls controlPipeName flags mouseMode cols rows\n" +"Usage: %ls controlPipeName --create-desktop\n" +"\n" +"Ordinarily, this program is launched by winpty.dll and is not directly\n" +"useful to winpty users. However, it also has options intended for\n" +"debugging winpty.\n" +"\n" +"Usage: %ls [options]\n" +"\n" +"Options:\n" +" --show-input [--with-mouse] [--escape-input]\n" +" Dump INPUT_RECORDs from the console input buffer\n" +" --with-mouse: Include MOUSE_INPUT_RECORDs in the dump\n" +" output\n" +" --escape-input: Direct the new Windows 10 console to use\n" +" escape sequences for input\n" +" --version Print the winpty version\n"; + +static uint64_t winpty_atoi64(const char *str) { + return strtoll(str, NULL, 10); +} + +int main() { + dumpWindowsVersion(); + dumpVersionToTrace(); + + // Technically, we should free the CommandLineToArgvW return value using + // a single call to LocalFree, but the call will never actually happen in + // the normal case. + int argc = 0; + wchar_t *cmdline = GetCommandLineW(); + ASSERT(cmdline != nullptr && "GetCommandLineW returned NULL"); + wchar_t **argv = CommandLineToArgvW(cmdline, &argc); + ASSERT(argv != nullptr && "CommandLineToArgvW returned NULL"); + + if (argc == 2 && !wcscmp(argv[1], L"--version")) { + dumpVersionToStdout(); + return 0; + } + + if (argc >= 2 && !wcscmp(argv[1], L"--show-input")) { + bool withMouse = false; + bool escapeInput = false; + for (int i = 2; i < argc; ++i) { + if (!wcscmp(argv[i], L"--with-mouse")) { + withMouse = true; + } else if (!wcscmp(argv[i], L"--escape-input")) { + escapeInput = true; + } else { + fprintf(stderr, "Unrecognized --show-input option: %ls\n", + argv[i]); + return 1; + } + } + debugShowInput(withMouse, escapeInput); + return 0; + } + + if (argc == 3 && !wcscmp(argv[2], L"--create-desktop")) { + handleCreateDesktop(argv[1]); + return 0; + } + + if (argc != 6) { + fprintf(stderr, USAGE, argv[0], argv[0], argv[0]); + return 1; + } + + Agent agent(argv[1], + winpty_atoi64(utf8FromWide(argv[2]).c_str()), + atoi(utf8FromWide(argv[3]).c_str()), + atoi(utf8FromWide(argv[4]).c_str()), + atoi(utf8FromWide(argv[5]).c_str())); + agent.run(); + + // The Agent destructor shouldn't return, but if it does, exit + // unsuccessfully. + return 1; +} diff --git a/src/libs/3rdparty/winpty/src/agent/subdir.mk b/src/libs/3rdparty/winpty/src/agent/subdir.mk new file mode 100644 index 00000000000..1c7d37e3e53 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/agent/subdir.mk @@ -0,0 +1,61 @@ +# Copyright (c) 2011-2015 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +ALL_TARGETS += build/winpty-agent.exe + +$(eval $(call def_mingw_target,agent,-DWINPTY_AGENT_ASSERT)) + +AGENT_OBJECTS = \ + build/agent/agent/Agent.o \ + build/agent/agent/AgentCreateDesktop.o \ + build/agent/agent/ConsoleFont.o \ + build/agent/agent/ConsoleInput.o \ + build/agent/agent/ConsoleInputReencoding.o \ + build/agent/agent/ConsoleLine.o \ + build/agent/agent/DebugShowInput.o \ + build/agent/agent/DefaultInputMap.o \ + build/agent/agent/EventLoop.o \ + build/agent/agent/InputMap.o \ + build/agent/agent/LargeConsoleRead.o \ + build/agent/agent/NamedPipe.o \ + build/agent/agent/Scraper.o \ + build/agent/agent/Terminal.o \ + build/agent/agent/Win32Console.o \ + build/agent/agent/Win32ConsoleBuffer.o \ + build/agent/agent/main.o \ + build/agent/shared/BackgroundDesktop.o \ + build/agent/shared/Buffer.o \ + build/agent/shared/DebugClient.o \ + build/agent/shared/GenRandom.o \ + build/agent/shared/OwnedHandle.o \ + build/agent/shared/StringUtil.o \ + build/agent/shared/WindowsSecurity.o \ + build/agent/shared/WindowsVersion.o \ + build/agent/shared/WinptyAssert.o \ + build/agent/shared/WinptyException.o \ + build/agent/shared/WinptyVersion.o + +build/agent/shared/WinptyVersion.o : build/gen/GenVersion.h + +build/winpty-agent.exe : $(AGENT_OBJECTS) + $(info Linking $@) + @$(MINGW_CXX) $(MINGW_LDFLAGS) -o $@ $^ + +-include $(AGENT_OBJECTS:.o=.d) diff --git a/src/libs/3rdparty/winpty/src/configurations.gypi b/src/libs/3rdparty/winpty/src/configurations.gypi new file mode 100644 index 00000000000..e990a60338e --- /dev/null +++ b/src/libs/3rdparty/winpty/src/configurations.gypi @@ -0,0 +1,60 @@ +# By default gyp/msbuild build for 32-bit Windows. This gyp include file +# defines configurations for both 32-bit and 64-bit Windows. To use it, run: +# +# C:\...\winpty\src>gyp -I configurations.gypi +# +# This command generates Visual Studio project files with a Release +# configuration and two Platforms--Win32 and x64. Both can be built: +# +# C:\...\winpty\src>msbuild winpty.sln /p:Platform=Win32 +# C:\...\winpty\src>msbuild winpty.sln /p:Platform=x64 +# +# The output is placed in: +# +# C:\...\winpty\src\Release\Win32 +# C:\...\winpty\src\Release\x64 +# +# Windows XP note: By default, the project files will use the default "toolset" +# for the given MSVC version. For MSVC 2013 and MSVC 2015, the default toolset +# generates binaries that do not run on Windows XP. To target Windows XP, +# select the XP-specific toolset by passing +# -D WINPTY_MSBUILD_TOOLSET={v120_xp,v140_xp} to gyp (v120_xp == MSVC 2013, +# v140_xp == MSVC 2015). Unfortunately, it isn't possible to have a single +# project file with configurations for both XP and post-XP. This seems to be a +# limitation of the MSVC project file format. +# +# This file is not included by default, because I suspect it would interfere +# with node-gyp, which has a different system for building 32-vs-64-bit +# binaries. It uses a common.gypi, and the project files it generates can only +# build a single architecture, the output paths are not differentiated by +# architecture. + +{ + 'variables': { + 'WINPTY_MSBUILD_TOOLSET%': '', + }, + 'target_defaults': { + 'default_configuration': 'Release_Win32', + 'configurations': { + 'Release_Win32': { + 'msvs_configuration_platform': 'Win32', + }, + 'Release_x64': { + 'msvs_configuration_platform': 'x64', + }, + }, + 'msvs_configuration_attributes': { + 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)\\$(Platform)', + 'IntermediateDirectory': '$(ConfigurationName)\\$(Platform)\\obj\\$(ProjectName)', + }, + 'msvs_settings': { + 'VCLinkerTool': { + 'SubSystem': '1', # /SUBSYSTEM:CONSOLE + }, + 'VCCLCompilerTool': { + 'RuntimeLibrary': '0', # MultiThreaded (/MT) + }, + }, + 'msbuild_toolset' : '<(WINPTY_MSBUILD_TOOLSET)', + } +} diff --git a/src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc b/src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc new file mode 100644 index 00000000000..353d31c1c6e --- /dev/null +++ b/src/libs/3rdparty/winpty/src/debugserver/DebugServer.cc @@ -0,0 +1,117 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include +#include + +#include + +#include "../shared/WindowsSecurity.h" +#include "../shared/WinptyException.h" + +const wchar_t *kPipeName = L"\\\\.\\pipe\\DebugServer"; + +// A message may not be larger than this size. +const int MSG_SIZE = 4096; + +static void usage(const char *program, int code) { + printf("Usage: %s [--everyone]\n" + "\n" + "Creates the named pipe %ls and reads messages. Prints each\n" + "message to stdout. By default, only the current user can send messages.\n" + "Pass --everyone to let anyone send a message.\n" + "\n" + "Use the WINPTY_DEBUG environment variable to enable winpty trace output.\n" + "(e.g. WINPTY_DEBUG=trace for the default trace output.) Set WINPTYDBG=1\n" + "to enable trace with older winpty versions.\n", + program, kPipeName); + exit(code); +} + +int main(int argc, char *argv[]) { + bool everyone = false; + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "--everyone") { + everyone = true; + } else if (arg == "-h" || arg == "--help") { + usage(argv[0], 0); + } else { + usage(argv[0], 1); + } + } + + SecurityDescriptor sd; + PSECURITY_ATTRIBUTES psa = nullptr; + SECURITY_ATTRIBUTES sa = {}; + if (everyone) { + try { + sd = createPipeSecurityDescriptorOwnerFullControlEveryoneWrite(); + } catch (const WinptyException &e) { + fprintf(stderr, + "error creating security descriptor: %ls\n", e.what()); + exit(1); + } + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = sd.get(); + psa = &sa; + } + + HANDLE serverPipe = CreateNamedPipeW( + kPipeName, + /*dwOpenMode=*/PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, + /*dwPipeMode=*/PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | + rejectRemoteClientsPipeFlag(), + /*nMaxInstances=*/1, + /*nOutBufferSize=*/MSG_SIZE, + /*nInBufferSize=*/MSG_SIZE, + /*nDefaultTimeOut=*/10 * 1000, + psa); + + if (serverPipe == INVALID_HANDLE_VALUE) { + fprintf(stderr, "error: could not create %ls pipe: error %u\n", + kPipeName, static_cast(GetLastError())); + exit(1); + } + + char msgBuffer[MSG_SIZE + 1]; + + while (true) { + if (!ConnectNamedPipe(serverPipe, nullptr)) { + fprintf(stderr, "error: ConnectNamedPipe failed\n"); + fflush(stderr); + exit(1); + } + DWORD bytesRead = 0; + if (!ReadFile(serverPipe, msgBuffer, MSG_SIZE, &bytesRead, nullptr)) { + fprintf(stderr, "error: ReadFile on pipe failed\n"); + fflush(stderr); + DisconnectNamedPipe(serverPipe); + continue; + } + msgBuffer[bytesRead] = '\n'; + fwrite(msgBuffer, 1, bytesRead + 1, stdout); + fflush(stdout); + + DWORD bytesWritten = 0; + WriteFile(serverPipe, "OK", 2, &bytesWritten, nullptr); + DisconnectNamedPipe(serverPipe); + } +} diff --git a/src/libs/3rdparty/winpty/src/debugserver/subdir.mk b/src/libs/3rdparty/winpty/src/debugserver/subdir.mk new file mode 100644 index 00000000000..beed1bd597d --- /dev/null +++ b/src/libs/3rdparty/winpty/src/debugserver/subdir.mk @@ -0,0 +1,41 @@ +# Copyright (c) 2015 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +ALL_TARGETS += build/winpty-debugserver.exe + +$(eval $(call def_mingw_target,debugserver,)) + +DEBUGSERVER_OBJECTS = \ + build/debugserver/debugserver/DebugServer.o \ + build/debugserver/shared/DebugClient.o \ + build/debugserver/shared/OwnedHandle.o \ + build/debugserver/shared/StringUtil.o \ + build/debugserver/shared/WindowsSecurity.o \ + build/debugserver/shared/WindowsVersion.o \ + build/debugserver/shared/WinptyAssert.o \ + build/debugserver/shared/WinptyException.o + +build/debugserver/shared/WindowsVersion.o : build/gen/GenVersion.h + +build/winpty-debugserver.exe : $(DEBUGSERVER_OBJECTS) + $(info Linking $@) + @$(MINGW_CXX) $(MINGW_LDFLAGS) -o $@ $^ + +-include $(DEBUGSERVER_OBJECTS:.o=.d) diff --git a/src/libs/3rdparty/winpty/src/include/winpty.h b/src/libs/3rdparty/winpty/src/include/winpty.h new file mode 100644 index 00000000000..fdfe4bca21d --- /dev/null +++ b/src/libs/3rdparty/winpty/src/include/winpty.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2011-2016 Ryan Prichard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef WINPTY_H +#define WINPTY_H + +#include + +#include "winpty_constants.h" + +/* On 32-bit Windows, winpty functions have the default __cdecl (not __stdcall) + * calling convention. (64-bit Windows has only a single calling convention.) + * When compiled with __declspec(dllexport), with either MinGW or MSVC, the + * winpty functions are unadorned--no underscore prefix or '@nn' suffix--so + * GetProcAddress can be used easily. */ +#ifdef COMPILING_WINPTY_DLL +#define WINPTY_API __declspec(dllexport) +#else +#define WINPTY_API __declspec(dllimport) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The winpty API uses wide characters, instead of UTF-8, to avoid conversion + * complications related to surrogates. Windows generally tolerates unpaired + * surrogates in text, which makes conversion to and from UTF-8 ambiguous and + * complicated. (There are different UTF-8 variants that deal with UTF-16 + * surrogates differently.) */ + + + +/***************************************************************************** + * Error handling. */ + +/* All the APIs have an optional winpty_error_t output parameter. If a + * non-NULL argument is specified, then either the API writes NULL to the + * value (on success) or writes a newly allocated winpty_error_t object. The + * object must be freed using winpty_error_free. */ + +/* An error object. */ +typedef struct winpty_error_s winpty_error_t; +typedef winpty_error_t *winpty_error_ptr_t; + +/* An error code -- one of WINPTY_ERROR_xxx. */ +typedef DWORD winpty_result_t; + +/* Gets the error code from the error object. */ +WINPTY_API winpty_result_t winpty_error_code(winpty_error_ptr_t err); + +/* Returns a textual representation of the error. The string is freed when + * the error is freed. */ +WINPTY_API LPCWSTR winpty_error_msg(winpty_error_ptr_t err); + +/* Free the error object. Every error returned from the winpty API must be + * freed. */ +WINPTY_API void winpty_error_free(winpty_error_ptr_t err); + + + +/***************************************************************************** + * Configuration of a new agent. */ + +/* The winpty_config_t object is not thread-safe. */ +typedef struct winpty_config_s winpty_config_t; + +/* Allocate a winpty_config_t value. Returns NULL on error. There are no + * required settings -- the object may immediately be used. agentFlags is a + * set of zero or more WINPTY_FLAG_xxx values. An unrecognized flag results + * in an assertion failure. */ +WINPTY_API winpty_config_t * +winpty_config_new(UINT64 agentFlags, winpty_error_ptr_t *err /*OPTIONAL*/); + +/* Free the cfg object after passing it to winpty_open. */ +WINPTY_API void winpty_config_free(winpty_config_t *cfg); + +WINPTY_API void +winpty_config_set_initial_size(winpty_config_t *cfg, int cols, int rows); + +/* Set the mouse mode to one of the WINPTY_MOUSE_MODE_xxx constants. */ +WINPTY_API void +winpty_config_set_mouse_mode(winpty_config_t *cfg, int mouseMode); + +/* Amount of time to wait for the agent to startup and to wait for any given + * agent RPC request. Must be greater than 0. Can be INFINITE. */ +WINPTY_API void +winpty_config_set_agent_timeout(winpty_config_t *cfg, DWORD timeoutMs); + + + +/***************************************************************************** + * Start the agent. */ + +/* The winpty_t object is thread-safe. */ +typedef struct winpty_s winpty_t; + +/* Starts the agent. Returns NULL on error. This process will connect to the + * agent over a control pipe, and the agent will open data pipes (e.g. CONIN + * and CONOUT). */ +WINPTY_API winpty_t * +winpty_open(const winpty_config_t *cfg, + winpty_error_ptr_t *err /*OPTIONAL*/); + +/* A handle to the agent process. This value is valid for the lifetime of the + * winpty_t object. Do not close it. */ +WINPTY_API HANDLE winpty_agent_process(winpty_t *wp); + + + +/***************************************************************************** + * I/O pipes. */ + +/* Returns the names of named pipes used for terminal I/O. Each input or + * output direction uses a different half-duplex pipe. The agent creates + * these pipes, and the client can connect to them using ordinary I/O methods. + * The strings are freed when the winpty_t object is freed. + * + * winpty_conerr_name returns NULL unless WINPTY_FLAG_CONERR is specified. + * + * N.B.: CreateFile does not block when connecting to a local server pipe. If + * the server pipe does not exist or is already connected, then it fails + * instantly. */ +WINPTY_API LPCWSTR winpty_conin_name(winpty_t *wp); +WINPTY_API LPCWSTR winpty_conout_name(winpty_t *wp); +WINPTY_API LPCWSTR winpty_conerr_name(winpty_t *wp); + + + +/***************************************************************************** + * winpty agent RPC call: process creation. */ + +/* The winpty_spawn_config_t object is not thread-safe. */ +typedef struct winpty_spawn_config_s winpty_spawn_config_t; + +/* winpty_spawn_config strings do not need to live as long as the config + * object. They are copied. Returns NULL on error. spawnFlags is a set of + * zero or more WINPTY_SPAWN_FLAG_xxx values. An unrecognized flag results in + * an assertion failure. + * + * env is a a pointer to an environment block like that passed to + * CreateProcess--a contiguous array of NUL-terminated "VAR=VAL" strings + * followed by a final NUL terminator. + * + * N.B.: If you want to gather all of the child's output, you may want the + * WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN flag. + */ +WINPTY_API winpty_spawn_config_t * +winpty_spawn_config_new(UINT64 spawnFlags, + LPCWSTR appname /*OPTIONAL*/, + LPCWSTR cmdline /*OPTIONAL*/, + LPCWSTR cwd /*OPTIONAL*/, + LPCWSTR env /*OPTIONAL*/, + winpty_error_ptr_t *err /*OPTIONAL*/); + +/* Free the cfg object after passing it to winpty_spawn. */ +WINPTY_API void winpty_spawn_config_free(winpty_spawn_config_t *cfg); + +/* + * Spawns the new process. + * + * The function initializes all output parameters to zero or NULL. + * + * On success, the function returns TRUE. For each of process_handle and + * thread_handle that is non-NULL, the HANDLE returned from CreateProcess is + * duplicated from the agent and returned to the winpty client. The client is + * responsible for closing these HANDLES. + * + * On failure, the function returns FALSE, and if err is non-NULL, then *err + * is set to an error object. + * + * If the agent's CreateProcess call failed, then *create_process_error is set + * to GetLastError(), and the WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED error + * is returned. + * + * winpty_spawn can only be called once per winpty_t object. If it is called + * before the output data pipe(s) is/are connected, then collected output is + * buffered until the pipes are connected, rather than being discarded. + * + * N.B.: GetProcessId works even if the process has exited. The PID is not + * recycled until the NT process object is freed. + * (https://blogs.msdn.microsoft.com/oldnewthing/20110107-00/?p=11803) + */ +WINPTY_API BOOL +winpty_spawn(winpty_t *wp, + const winpty_spawn_config_t *cfg, + HANDLE *process_handle /*OPTIONAL*/, + HANDLE *thread_handle /*OPTIONAL*/, + DWORD *create_process_error /*OPTIONAL*/, + winpty_error_ptr_t *err /*OPTIONAL*/); + + + +/***************************************************************************** + * winpty agent RPC calls: everything else */ + +/* Change the size of the Windows console window. */ +WINPTY_API BOOL +winpty_set_size(winpty_t *wp, int cols, int rows, + winpty_error_ptr_t *err /*OPTIONAL*/); + +/* Gets a list of processes attached to the console. */ +WINPTY_API int +winpty_get_console_process_list(winpty_t *wp, int *processList, const int processCount, + winpty_error_ptr_t *err /*OPTIONAL*/); + +/* Frees the winpty_t object and the OS resources contained in it. This + * call breaks the connection with the agent, which should then close its + * console, terminating the processes attached to it. + * + * This function must not be called if any other threads are using the + * winpty_t object. Undefined behavior results. */ +WINPTY_API void winpty_free(winpty_t *wp); + + + +/****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* WINPTY_H */ diff --git a/src/libs/3rdparty/winpty/src/include/winpty_constants.h b/src/libs/3rdparty/winpty/src/include/winpty_constants.h new file mode 100644 index 00000000000..11e34cf171c --- /dev/null +++ b/src/libs/3rdparty/winpty/src/include/winpty_constants.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016 Ryan Prichard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef WINPTY_CONSTANTS_H +#define WINPTY_CONSTANTS_H + +/* + * You may want to include winpty.h instead, which includes this header. + * + * This file is split out from winpty.h so that the agent can access the + * winpty flags without also declaring the libwinpty APIs. + */ + +/***************************************************************************** + * Error codes. */ + +#define WINPTY_ERROR_SUCCESS 0 +#define WINPTY_ERROR_OUT_OF_MEMORY 1 +#define WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED 2 +#define WINPTY_ERROR_LOST_CONNECTION 3 +#define WINPTY_ERROR_AGENT_EXE_MISSING 4 +#define WINPTY_ERROR_UNSPECIFIED 5 +#define WINPTY_ERROR_AGENT_DIED 6 +#define WINPTY_ERROR_AGENT_TIMEOUT 7 +#define WINPTY_ERROR_AGENT_CREATION_FAILED 8 + + + +/***************************************************************************** + * Configuration of a new agent. */ + +/* Create a new screen buffer (connected to the "conerr" terminal pipe) and + * pass it to child processes as the STDERR handle. This flag also prevents + * the agent from reopening CONOUT$ when it polls -- regardless of whether the + * active screen buffer changes, winpty continues to monitor the original + * primary screen buffer. */ +#define WINPTY_FLAG_CONERR 0x1ull + +/* Don't output escape sequences. */ +#define WINPTY_FLAG_PLAIN_OUTPUT 0x2ull + +/* Do output color escape sequences. These escapes are output by default, but + * are suppressed with WINPTY_FLAG_PLAIN_OUTPUT. Use this flag to reenable + * them. */ +#define WINPTY_FLAG_COLOR_ESCAPES 0x4ull + +/* On XP and Vista, winpty needs to put the hidden console on a desktop in a + * service window station so that its polling does not interfere with other + * (visible) console windows. To create this desktop, it must change the + * process' window station (i.e. SetProcessWindowStation) for the duration of + * the winpty_open call. In theory, this change could interfere with the + * winpty client (e.g. other threads, spawning children), so winpty by default + * spawns a special agent process to create the hidden desktop. Spawning + * processes on Windows is slow, though, so if + * WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION is set, winpty changes this + * process' window station instead. + * See https://github.com/rprichard/winpty/issues/58. */ +#define WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION 0x8ull + +#define WINPTY_FLAG_MASK (0ull \ + | WINPTY_FLAG_CONERR \ + | WINPTY_FLAG_PLAIN_OUTPUT \ + | WINPTY_FLAG_COLOR_ESCAPES \ + | WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION \ +) + +/* QuickEdit mode is initially disabled, and the agent does not send mouse + * mode sequences to the terminal. If it receives mouse input, though, it + * still writes MOUSE_EVENT_RECORD values into CONIN. */ +#define WINPTY_MOUSE_MODE_NONE 0 + +/* QuickEdit mode is initially enabled. As CONIN enters or leaves mouse + * input mode (i.e. where ENABLE_MOUSE_INPUT is on and ENABLE_QUICK_EDIT_MODE + * is off), the agent enables or disables mouse input on the terminal. + * + * This is the default mode. */ +#define WINPTY_MOUSE_MODE_AUTO 1 + +/* QuickEdit mode is initially disabled, and the agent enables the terminal's + * mouse input mode. It does not disable terminal mouse mode (until exit). */ +#define WINPTY_MOUSE_MODE_FORCE 2 + + + +/***************************************************************************** + * winpty agent RPC call: process creation. */ + +/* If the spawn is marked "auto-shutdown", then the agent shuts down console + * output once the process exits. The agent stops polling for new console + * output, and once all pending data has been written to the output pipe, the + * agent closes the pipe. (At that point, the pipe may still have data in it, + * which the client may read. Once all the data has been read, further reads + * return EOF.) */ +#define WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN 1ull + +/* After the agent shuts down output, and after all output has been written + * into the pipe(s), exit the agent by closing the console. If there any + * surviving processes still attached to the console, they are killed. + * + * Note: With this flag, an RPC call (e.g. winpty_set_size) issued after the + * agent exits will fail with an I/O or dead-agent error. */ +#define WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN 2ull + +/* All the spawn flags. */ +#define WINPTY_SPAWN_FLAG_MASK (0ull \ + | WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN \ + | WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN \ +) + + + +#endif /* WINPTY_CONSTANTS_H */ diff --git a/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc new file mode 100644 index 00000000000..82d00b2da2d --- /dev/null +++ b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "AgentLocation.h" + +#include + +#include + +#include "../shared/WinptyAssert.h" + +#include "LibWinptyException.h" + +#define AGENT_EXE L"winpty-agent.exe" + +static HMODULE getCurrentModule() { + HMODULE module; + if (!GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(getCurrentModule), + &module)) { + ASSERT(false && "GetModuleHandleEx failed"); + } + return module; +} + +static std::wstring getModuleFileName(HMODULE module) { + const int bufsize = 4096; + wchar_t path[bufsize]; + int size = GetModuleFileNameW(module, path, bufsize); + ASSERT(size != 0 && size != bufsize); + return std::wstring(path); +} + +static std::wstring dirname(const std::wstring &path) { + std::wstring::size_type pos = path.find_last_of(L"\\/"); + if (pos == std::wstring::npos) { + return L""; + } else { + return path.substr(0, pos); + } +} + +static bool pathExists(const std::wstring &path) { + return GetFileAttributesW(path.c_str()) != 0xFFFFFFFF; +} + +std::wstring findAgentProgram() { + std::wstring progDir = dirname(getModuleFileName(getCurrentModule())); + std::wstring ret = progDir + (L"\\" AGENT_EXE); + if (!pathExists(ret)) { + throw LibWinptyException( + WINPTY_ERROR_AGENT_EXE_MISSING, + (L"agent executable does not exist: '" + ret + L"'").c_str()); + } + return ret; +} diff --git a/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h new file mode 100644 index 00000000000..a96b854cd2a --- /dev/null +++ b/src/libs/3rdparty/winpty/src/libwinpty/AgentLocation.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef LIBWINPTY_AGENT_LOCATION_H +#define LIBWINPTY_AGENT_LOCATION_H + +#include + +std::wstring findAgentProgram(); + +#endif // LIBWINPTY_AGENT_LOCATION_H diff --git a/src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h b/src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h new file mode 100644 index 00000000000..2274798d238 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/libwinpty/LibWinptyException.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef LIB_WINPTY_EXCEPTION_H +#define LIB_WINPTY_EXCEPTION_H + +#include "../include/winpty.h" + +#include "../shared/WinptyException.h" + +#include +#include + +class LibWinptyException : public WinptyException { +public: + LibWinptyException(winpty_result_t code, const wchar_t *what) : + m_code(code), m_what(std::make_shared(what)) {} + + winpty_result_t code() const WINPTY_NOEXCEPT { + return m_code; + } + + const wchar_t *what() const WINPTY_NOEXCEPT override { + return m_what->c_str(); + } + + std::shared_ptr whatSharedStr() const WINPTY_NOEXCEPT { + return m_what; + } + +private: + winpty_result_t m_code; + // Using a shared_ptr ensures that copying the object raises no exception. + std::shared_ptr m_what; +}; + +#endif // LIB_WINPTY_EXCEPTION_H diff --git a/src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h b/src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h new file mode 100644 index 00000000000..93e992d5c55 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/libwinpty/WinptyInternal.h @@ -0,0 +1,72 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef LIBWINPTY_WINPTY_INTERNAL_H +#define LIBWINPTY_WINPTY_INTERNAL_H + +#include +#include + +#include "../include/winpty.h" + +#include "../shared/Mutex.h" +#include "../shared/OwnedHandle.h" + +// The structures in this header are not intended to be accessed directly by +// client programs. + +struct winpty_error_s { + winpty_result_t code; + const wchar_t *msgStatic; + // Use a pointer to a std::shared_ptr so that the struct remains simple + // enough to statically initialize, for the benefit of static error + // objects like kOutOfMemory. + std::shared_ptr *msgDynamic; +}; + +struct winpty_config_s { + uint64_t flags = 0; + int cols = 80; + int rows = 25; + int mouseMode = WINPTY_MOUSE_MODE_AUTO; + DWORD timeoutMs = 30000; +}; + +struct winpty_s { + Mutex mutex; + OwnedHandle agentProcess; + OwnedHandle controlPipe; + DWORD agentTimeoutMs = 0; + OwnedHandle ioEvent; + std::wstring spawnDesktopName; + std::wstring coninPipeName; + std::wstring conoutPipeName; + std::wstring conerrPipeName; +}; + +struct winpty_spawn_config_s { + uint64_t winptyFlags = 0; + std::wstring appname; + std::wstring cmdline; + std::wstring cwd; + std::wstring env; +}; + +#endif // LIBWINPTY_WINPTY_INTERNAL_H diff --git a/src/libs/3rdparty/winpty/src/libwinpty/subdir.mk b/src/libs/3rdparty/winpty/src/libwinpty/subdir.mk new file mode 100644 index 00000000000..ba32bad6e64 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/libwinpty/subdir.mk @@ -0,0 +1,46 @@ +# Copyright (c) 2011-2015 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +ALL_TARGETS += build/winpty.dll + +$(eval $(call def_mingw_target,libwinpty,-DCOMPILING_WINPTY_DLL)) + +LIBWINPTY_OBJECTS = \ + build/libwinpty/libwinpty/AgentLocation.o \ + build/libwinpty/libwinpty/winpty.o \ + build/libwinpty/shared/BackgroundDesktop.o \ + build/libwinpty/shared/Buffer.o \ + build/libwinpty/shared/DebugClient.o \ + build/libwinpty/shared/GenRandom.o \ + build/libwinpty/shared/OwnedHandle.o \ + build/libwinpty/shared/StringUtil.o \ + build/libwinpty/shared/WindowsSecurity.o \ + build/libwinpty/shared/WindowsVersion.o \ + build/libwinpty/shared/WinptyAssert.o \ + build/libwinpty/shared/WinptyException.o \ + build/libwinpty/shared/WinptyVersion.o + +build/libwinpty/shared/WinptyVersion.o : build/gen/GenVersion.h + +build/winpty.dll : $(LIBWINPTY_OBJECTS) + $(info Linking $@) + @$(MINGW_CXX) $(MINGW_LDFLAGS) -shared -o $@ $^ -Wl,--out-implib,build/winpty.lib + +-include $(LIBWINPTY_OBJECTS:.o=.d) diff --git a/src/libs/3rdparty/winpty/src/libwinpty/winpty.cc b/src/libs/3rdparty/winpty/src/libwinpty/winpty.cc new file mode 100644 index 00000000000..3d977498ef9 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/libwinpty/winpty.cc @@ -0,0 +1,970 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include + +#include +#include +#include + +#include +#include +#include + +#include "../include/winpty.h" + +#include "../shared/AgentMsg.h" +#include "../shared/BackgroundDesktop.h" +#include "../shared/Buffer.h" +#include "../shared/DebugClient.h" +#include "../shared/GenRandom.h" +#include "../shared/OwnedHandle.h" +#include "../shared/StringBuilder.h" +#include "../shared/StringUtil.h" +#include "../shared/WindowsSecurity.h" +#include "../shared/WindowsVersion.h" +#include "../shared/WinptyAssert.h" +#include "../shared/WinptyException.h" +#include "../shared/WinptyVersion.h" + +#include "AgentLocation.h" +#include "LibWinptyException.h" +#include "WinptyInternal.h" + + + +/***************************************************************************** + * Error handling -- translate C++ exceptions to an optional error object + * output and log the result. */ + +static const winpty_error_s kOutOfMemory = { + WINPTY_ERROR_OUT_OF_MEMORY, + L"Out of memory", + nullptr +}; + +static const winpty_error_s kBadRpcPacket = { + WINPTY_ERROR_UNSPECIFIED, + L"Bad RPC packet", + nullptr +}; + +static const winpty_error_s kUncaughtException = { + WINPTY_ERROR_UNSPECIFIED, + L"Uncaught C++ exception", + nullptr +}; + +/* Gets the error code from the error object. */ +WINPTY_API winpty_result_t winpty_error_code(winpty_error_ptr_t err) { + return err != nullptr ? err->code : WINPTY_ERROR_SUCCESS; +} + +/* Returns a textual representation of the error. The string is freed when + * the error is freed. */ +WINPTY_API LPCWSTR winpty_error_msg(winpty_error_ptr_t err) { + if (err != nullptr) { + if (err->msgStatic != nullptr) { + return err->msgStatic; + } else { + ASSERT(err->msgDynamic != nullptr); + std::wstring *msgPtr = err->msgDynamic->get(); + ASSERT(msgPtr != nullptr); + return msgPtr->c_str(); + } + } else { + return L"Success"; + } +} + +/* Free the error object. Every error returned from the winpty API must be + * freed. */ +WINPTY_API void winpty_error_free(winpty_error_ptr_t err) { + if (err != nullptr && err->msgDynamic != nullptr) { + delete err->msgDynamic; + delete err; + } +} + +static void translateException(winpty_error_ptr_t *&err) { + winpty_error_ptr_t ret = nullptr; + try { + try { + throw; + } catch (const ReadBuffer::DecodeError&) { + ret = const_cast(&kBadRpcPacket); + } catch (const LibWinptyException &e) { + std::unique_ptr obj(new winpty_error_t); + obj->code = e.code(); + obj->msgStatic = nullptr; + obj->msgDynamic = + new std::shared_ptr(e.whatSharedStr()); + ret = obj.release(); + } catch (const WinptyException &e) { + std::unique_ptr obj(new winpty_error_t); + std::shared_ptr msg(new std::wstring(e.what())); + obj->code = WINPTY_ERROR_UNSPECIFIED; + obj->msgStatic = nullptr; + obj->msgDynamic = new std::shared_ptr(msg); + ret = obj.release(); + } + } catch (const std::bad_alloc&) { + ret = const_cast(&kOutOfMemory); + } catch (...) { + ret = const_cast(&kUncaughtException); + } + trace("libwinpty error: code=%u msg='%s'", + static_cast(ret->code), + utf8FromWide(winpty_error_msg(ret)).c_str()); + if (err != nullptr) { + *err = ret; + } else { + winpty_error_free(ret); + } +} + +#define API_TRY \ + if (err != nullptr) { *err = nullptr; } \ + try + +#define API_CATCH(ret) \ + catch (...) { translateException(err); return (ret); } + + + +/***************************************************************************** + * Configuration of a new agent. */ + +WINPTY_API winpty_config_t * +winpty_config_new(UINT64 flags, winpty_error_ptr_t *err /*OPTIONAL*/) { + API_TRY { + ASSERT((flags & WINPTY_FLAG_MASK) == flags); + std::unique_ptr ret(new winpty_config_t); + ret->flags = flags; + return ret.release(); + } API_CATCH(nullptr) +} + +WINPTY_API void winpty_config_free(winpty_config_t *cfg) { + delete cfg; +} + +WINPTY_API void +winpty_config_set_initial_size(winpty_config_t *cfg, int cols, int rows) { + ASSERT(cfg != nullptr && cols > 0 && rows > 0); + cfg->cols = cols; + cfg->rows = rows; +} + +WINPTY_API void +winpty_config_set_mouse_mode(winpty_config_t *cfg, int mouseMode) { + ASSERT(cfg != nullptr && + mouseMode >= WINPTY_MOUSE_MODE_NONE && + mouseMode <= WINPTY_MOUSE_MODE_FORCE); + cfg->mouseMode = mouseMode; +} + +WINPTY_API void +winpty_config_set_agent_timeout(winpty_config_t *cfg, DWORD timeoutMs) { + ASSERT(cfg != nullptr && timeoutMs > 0); + cfg->timeoutMs = timeoutMs; +} + + + +/***************************************************************************** + * Agent I/O. */ + +namespace { + +// Once an I/O operation fails with ERROR_IO_PENDING, the caller *must* wait +// for it to complete, even after calling CancelIo on it! See +// https://blogs.msdn.microsoft.com/oldnewthing/20110202-00/?p=11613. This +// class enforces that requirement. +class PendingIo { + HANDLE m_file; + OVERLAPPED &m_over; + bool m_finished; +public: + // The file handle and OVERLAPPED object must live as long as the PendingIo + // object. + PendingIo(HANDLE file, OVERLAPPED &over) : + m_file(file), m_over(over), m_finished(false) {} + ~PendingIo() { + if (!m_finished) { + // We're not usually that interested in CancelIo's return value. + // In any case, we must not throw an exception in this dtor. + CancelIo(m_file); + waitForCompletion(); + } + } + std::tuple waitForCompletion(DWORD &actual) WINPTY_NOEXCEPT { + m_finished = true; + const BOOL success = + GetOverlappedResult(m_file, &m_over, &actual, TRUE); + return std::make_tuple(success, GetLastError()); + } + std::tuple waitForCompletion() WINPTY_NOEXCEPT { + DWORD actual = 0; + return waitForCompletion(actual); + } +}; + +} // anonymous namespace + +static void handlePendingIo(winpty_t &wp, OVERLAPPED &over, BOOL &success, + DWORD &lastError, DWORD &actual) { + if (!success && lastError == ERROR_IO_PENDING) { + PendingIo io(wp.controlPipe.get(), over); + const HANDLE waitHandles[2] = { wp.ioEvent.get(), + wp.agentProcess.get() }; + DWORD waitRet = WaitForMultipleObjects( + 2, waitHandles, FALSE, wp.agentTimeoutMs); + if (waitRet != WAIT_OBJECT_0) { + // The I/O is still pending. Cancel it, close the I/O event, and + // throw an exception. + if (waitRet == WAIT_OBJECT_0 + 1) { + throw LibWinptyException(WINPTY_ERROR_AGENT_DIED, L"agent died"); + } else if (waitRet == WAIT_TIMEOUT) { + throw LibWinptyException(WINPTY_ERROR_AGENT_TIMEOUT, + L"agent timed out"); + } else if (waitRet == WAIT_FAILED) { + throwWindowsError(L"WaitForMultipleObjects failed"); + } else { + ASSERT(false && + "unexpected WaitForMultipleObjects return value"); + } + } + std::tie(success, lastError) = io.waitForCompletion(actual); + } +} + +static void handlePendingIo(winpty_t &wp, OVERLAPPED &over, BOOL &success, + DWORD &lastError) { + DWORD actual = 0; + handlePendingIo(wp, over, success, lastError, actual); +} + +static void handleReadWriteErrors(winpty_t &wp, BOOL success, DWORD lastError, + const wchar_t *genericErrMsg) { + if (!success) { + // If the pipe connection is broken after it's been connected, then + // later I/O operations fail with ERROR_BROKEN_PIPE (reads) or + // ERROR_NO_DATA (writes). With Wine, they may also fail with + // ERROR_PIPE_NOT_CONNECTED. See this gist[1]. + // + // [1] https://gist.github.com/rprichard/8dd8ca134b39534b7da2733994aa07ba + if (lastError == ERROR_BROKEN_PIPE || lastError == ERROR_NO_DATA || + lastError == ERROR_PIPE_NOT_CONNECTED) { + throw LibWinptyException(WINPTY_ERROR_LOST_CONNECTION, + L"lost connection to agent"); + } else { + throwWindowsError(genericErrMsg, lastError); + } + } +} + +// Calls ConnectNamedPipe to wait until the agent connects to the control pipe. +static void +connectControlPipe(winpty_t &wp) { + OVERLAPPED over = {}; + over.hEvent = wp.ioEvent.get(); + BOOL success = ConnectNamedPipe(wp.controlPipe.get(), &over); + DWORD lastError = GetLastError(); + handlePendingIo(wp, over, success, lastError); + if (!success && lastError == ERROR_PIPE_CONNECTED) { + success = TRUE; + } + if (!success) { + throwWindowsError(L"ConnectNamedPipe failed", lastError); + } +} + +static void writeData(winpty_t &wp, const void *data, size_t amount) { + // Perform a single pipe write. + DWORD actual = 0; + OVERLAPPED over = {}; + over.hEvent = wp.ioEvent.get(); + BOOL success = WriteFile(wp.controlPipe.get(), data, amount, + &actual, &over); + DWORD lastError = GetLastError(); + if (!success) { + handlePendingIo(wp, over, success, lastError, actual); + handleReadWriteErrors(wp, success, lastError, L"WriteFile failed"); + ASSERT(success); + } + // TODO: Can a partial write actually happen somehow? + ASSERT(actual == amount && "WriteFile wrote fewer bytes than requested"); +} + +static inline WriteBuffer newPacket() { + WriteBuffer packet; + packet.putRawValue(0); // Reserve space for size. + return packet; +} + +static void writePacket(winpty_t &wp, WriteBuffer &packet) { + const auto &buf = packet.buf(); + packet.replaceRawValue(0, buf.size()); + writeData(wp, buf.data(), buf.size()); +} + +static size_t readData(winpty_t &wp, void *data, size_t amount) { + DWORD actual = 0; + OVERLAPPED over = {}; + over.hEvent = wp.ioEvent.get(); + BOOL success = ReadFile(wp.controlPipe.get(), data, amount, + &actual, &over); + DWORD lastError = GetLastError(); + if (!success) { + handlePendingIo(wp, over, success, lastError, actual); + handleReadWriteErrors(wp, success, lastError, L"ReadFile failed"); + } + return actual; +} + +static void readAll(winpty_t &wp, void *data, size_t amount) { + while (amount > 0) { + const size_t chunk = readData(wp, data, amount); + ASSERT(chunk <= amount && "readData result is larger than amount"); + data = reinterpret_cast(data) + chunk; + amount -= chunk; + } +} + +static uint64_t readUInt64(winpty_t &wp) { + uint64_t ret = 0; + readAll(wp, &ret, sizeof(ret)); + return ret; +} + +// Returns a reply packet's payload. +static ReadBuffer readPacket(winpty_t &wp) { + const uint64_t packetSize = readUInt64(wp); + if (packetSize < sizeof(packetSize) || packetSize > SIZE_MAX) { + throwWinptyException(L"Agent RPC error: invalid packet size"); + } + const size_t payloadSize = packetSize - sizeof(packetSize); + std::vector bytes(payloadSize); + readAll(wp, bytes.data(), bytes.size()); + return ReadBuffer(std::move(bytes)); +} + +static OwnedHandle createControlPipe(const std::wstring &name) { + const auto sd = createPipeSecurityDescriptorOwnerFullControl(); + if (!sd) { + throwWinptyException( + L"could not create the control pipe's SECURITY_DESCRIPTOR"); + } + SECURITY_ATTRIBUTES sa = {}; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = sd.get(); + HANDLE ret = CreateNamedPipeW(name.c_str(), + /*dwOpenMode=*/ + PIPE_ACCESS_DUPLEX | + FILE_FLAG_FIRST_PIPE_INSTANCE | + FILE_FLAG_OVERLAPPED, + /*dwPipeMode=*/rejectRemoteClientsPipeFlag(), + /*nMaxInstances=*/1, + /*nOutBufferSize=*/8192, + /*nInBufferSize=*/256, + /*nDefaultTimeOut=*/30000, + &sa); + if (ret == INVALID_HANDLE_VALUE) { + throwWindowsError(L"CreateNamedPipeW failed"); + } + return OwnedHandle(ret); +} + + + +/***************************************************************************** + * Start the agent. */ + +static OwnedHandle createEvent() { + // manual reset, initially unset + HANDLE h = CreateEventW(nullptr, TRUE, FALSE, nullptr); + if (h == nullptr) { + throwWindowsError(L"CreateEventW failed"); + } + return OwnedHandle(h); +} + +// For debugging purposes, provide a way to keep the console on the main window +// station, visible. +static bool shouldShowConsoleWindow() { + char buf[32]; + return GetEnvironmentVariableA("WINPTY_SHOW_CONSOLE", buf, sizeof(buf)) > 0; +} + +static bool shouldCreateBackgroundDesktop(bool &createUsingAgent) { + // Prior to Windows 7, winpty's repeated selection-deselection loop + // prevented the user from interacting with their *visible* console + // windows, unless we placed the console onto a background desktop. + // The SetProcessWindowStation call interferes with the clipboard and + // isn't thread-safe, though[1]. The call should perhaps occur in a + // special agent subprocess. Spawning a process in a background desktop + // also breaks ConEmu, but marking the process SW_HIDE seems to correct + // that[2]. + // + // Windows 7 moved a lot of console handling out of csrss.exe and into + // a per-console conhost.exe process, which may explain why it isn't + // affected. + // + // This is a somewhat risky change, so there are low-level flags to + // assist in debugging if there are issues. + // + // [1] https://github.com/rprichard/winpty/issues/58 + // [2] https://github.com/rprichard/winpty/issues/70 + bool ret = !shouldShowConsoleWindow() && !isAtLeastWindows7(); + const bool force = hasDebugFlag("force_desktop"); + const bool force_spawn = hasDebugFlag("force_desktop_spawn"); + const bool force_curproc = hasDebugFlag("force_desktop_curproc"); + const bool suppress = hasDebugFlag("no_desktop"); + if (force + force_spawn + force_curproc + suppress > 1) { + trace("error: Only one of force_desktop, force_desktop_spawn, " + "force_desktop_curproc, and no_desktop may be set"); + } else if (force) { + ret = true; + } else if (force_spawn) { + ret = true; + createUsingAgent = true; + } else if (force_curproc) { + ret = true; + createUsingAgent = false; + } else if (suppress) { + ret = false; + } + return ret; +} + +static bool shouldSpecifyHideFlag() { + const bool force = hasDebugFlag("force_sw_hide"); + const bool suppress = hasDebugFlag("no_sw_hide"); + bool ret = !shouldShowConsoleWindow(); + if (force && suppress) { + trace("error: Both the force_sw_hide and no_sw_hide flags are set"); + } else if (force) { + ret = true; + } else if (suppress) { + ret = false; + } + return ret; +} + +static OwnedHandle startAgentProcess( + const std::wstring &desktop, + const std::wstring &controlPipeName, + const std::wstring ¶ms, + DWORD creationFlags, + DWORD &agentPid) { + const std::wstring exePath = findAgentProgram(); + const std::wstring cmdline = + (WStringBuilder(256) + << L"\"" << exePath << L"\" " + << controlPipeName << L' ' + << params).str_moved(); + + auto cmdlineV = vectorWithNulFromString(cmdline); + auto desktopV = vectorWithNulFromString(desktop); + + // Start the agent. + STARTUPINFOW sui = {}; + sui.cb = sizeof(sui); + sui.lpDesktop = desktop.empty() ? nullptr : desktopV.data(); + + if (shouldSpecifyHideFlag()) { + sui.dwFlags |= STARTF_USESHOWWINDOW; + sui.wShowWindow = SW_HIDE; + } + PROCESS_INFORMATION pi = {}; + const BOOL success = + CreateProcessW(exePath.c_str(), + cmdlineV.data(), + nullptr, nullptr, + /*bInheritHandles=*/FALSE, + /*dwCreationFlags=*/creationFlags, + nullptr, nullptr, + &sui, &pi); + if (!success) { + const DWORD lastError = GetLastError(); + const auto errStr = + (WStringBuilder(256) + << L"winpty-agent CreateProcess failed: cmdline='" << cmdline + << L"' err=0x" << whexOfInt(lastError)).str_moved(); + throw LibWinptyException( + WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str()); + } + CloseHandle(pi.hThread); + TRACE("Created agent successfully, pid=%u, cmdline=%s", + static_cast(pi.dwProcessId), + utf8FromWide(cmdline).c_str()); + agentPid = pi.dwProcessId; + return OwnedHandle(pi.hProcess); +} + +static void verifyPipeClientPid(HANDLE serverPipe, DWORD agentPid) { + const auto client = getNamedPipeClientProcessId(serverPipe); + const auto success = std::get<0>(client); + const auto lastError = std::get<2>(client); + if (success == GetNamedPipeClientProcessId_Result::Success) { + const auto clientPid = std::get<1>(client); + if (clientPid != agentPid) { + WStringBuilder errMsg; + errMsg << L"Security check failed: pipe client pid (" << clientPid + << L") does not match agent pid (" << agentPid << L")"; + throwWinptyException(errMsg.c_str()); + } + } else if (success == GetNamedPipeClientProcessId_Result::UnsupportedOs) { + trace("Pipe client PID security check skipped: " + "GetNamedPipeClientProcessId unsupported on this OS version"); + } else { + throwWindowsError(L"GetNamedPipeClientProcessId failed", lastError); + } +} + +static std::unique_ptr +createAgentSession(const winpty_config_t *cfg, + const std::wstring &desktop, + const std::wstring ¶ms, + DWORD creationFlags) { + std::unique_ptr wp(new winpty_t); + wp->agentTimeoutMs = cfg->timeoutMs; + wp->ioEvent = createEvent(); + + // Create control server pipe. + const auto pipeName = + L"\\\\.\\pipe\\winpty-control-" + GenRandom().uniqueName(); + wp->controlPipe = createControlPipe(pipeName); + + DWORD agentPid = 0; + wp->agentProcess = startAgentProcess( + desktop, pipeName, params, creationFlags, agentPid); + connectControlPipe(*wp.get()); + verifyPipeClientPid(wp->controlPipe.get(), agentPid); + + return std::move(wp); +} + +namespace { + +class AgentDesktop { +public: + virtual std::wstring name() = 0; + virtual ~AgentDesktop() {} +}; + +class AgentDesktopDirect : public AgentDesktop { +public: + AgentDesktopDirect(BackgroundDesktop &&desktop) : + m_desktop(std::move(desktop)) + { + } + std::wstring name() override { return m_desktop.desktopName(); } +private: + BackgroundDesktop m_desktop; +}; + +class AgentDesktopIndirect : public AgentDesktop { +public: + AgentDesktopIndirect(std::unique_ptr &&wp, + std::wstring &&desktopName) : + m_wp(std::move(wp)), + m_desktopName(std::move(desktopName)) + { + } + std::wstring name() override { return m_desktopName; } +private: + std::unique_ptr m_wp; + std::wstring m_desktopName; +}; + +} // anonymous namespace + +std::unique_ptr +setupBackgroundDesktop(const winpty_config_t *cfg) { + bool useDesktopAgent = + !(cfg->flags & WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION); + const bool useDesktop = shouldCreateBackgroundDesktop(useDesktopAgent); + + if (!useDesktop) { + return std::unique_ptr(); + } + + if (useDesktopAgent) { + auto wp = createAgentSession( + cfg, std::wstring(), L"--create-desktop", DETACHED_PROCESS); + + // Read the desktop name. + auto packet = readPacket(*wp.get()); + auto desktopName = packet.getWString(); + packet.assertEof(); + + if (desktopName.empty()) { + return std::unique_ptr(); + } else { + return std::unique_ptr( + new AgentDesktopIndirect(std::move(wp), + std::move(desktopName))); + } + } else { + try { + BackgroundDesktop desktop; + return std::unique_ptr(new AgentDesktopDirect( + std::move(desktop))); + } catch (const WinptyException &e) { + trace("Error: failed to create background desktop, " + "using original desktop instead: %s", + utf8FromWide(e.what()).c_str()); + return std::unique_ptr(); + } + } +} + +WINPTY_API winpty_t * +winpty_open(const winpty_config_t *cfg, + winpty_error_ptr_t *err /*OPTIONAL*/) { + API_TRY { + ASSERT(cfg != nullptr); + dumpWindowsVersion(); + dumpVersionToTrace(); + + // Setup a background desktop for the agent. + auto desktop = setupBackgroundDesktop(cfg); + const auto desktopName = desktop ? desktop->name() : std::wstring(); + + // Start the primary agent session. + const auto params = + (WStringBuilder(128) + << cfg->flags << L' ' + << cfg->mouseMode << L' ' + << cfg->cols << L' ' + << cfg->rows).str_moved(); + auto wp = createAgentSession(cfg, desktopName, params, + CREATE_NEW_CONSOLE); + + // Close handles to the background desktop and restore the original + // window station. This must wait until we know the agent is running + // -- if we close these handles too soon, then the desktop and + // windowstation will be destroyed before the agent can connect with + // them. + // + // If we used a separate agent process to create the desktop, we + // disconnect from that process here, allowing it to exit. + desktop.reset(); + + // If we ran the agent process on a background desktop, then when we + // spawn a child process from the agent, it will need to be explicitly + // placed back onto the original desktop. + if (!desktopName.empty()) { + wp->spawnDesktopName = getCurrentDesktopName(); + } + + // Get the CONIN/CONOUT pipe names. + auto packet = readPacket(*wp.get()); + wp->coninPipeName = packet.getWString(); + wp->conoutPipeName = packet.getWString(); + if (cfg->flags & WINPTY_FLAG_CONERR) { + wp->conerrPipeName = packet.getWString(); + } + packet.assertEof(); + + return wp.release(); + } API_CATCH(nullptr) +} + +WINPTY_API HANDLE winpty_agent_process(winpty_t *wp) { + ASSERT(wp != nullptr); + return wp->agentProcess.get(); +} + + + +/***************************************************************************** + * I/O pipes. */ + +static const wchar_t *cstrFromWStringOrNull(const std::wstring &str) { + try { + return str.c_str(); + } catch (const std::bad_alloc&) { + return nullptr; + } +} + +WINPTY_API LPCWSTR winpty_conin_name(winpty_t *wp) { + ASSERT(wp != nullptr); + return cstrFromWStringOrNull(wp->coninPipeName); +} + +WINPTY_API LPCWSTR winpty_conout_name(winpty_t *wp) { + ASSERT(wp != nullptr); + return cstrFromWStringOrNull(wp->conoutPipeName); +} + +WINPTY_API LPCWSTR winpty_conerr_name(winpty_t *wp) { + ASSERT(wp != nullptr); + if (wp->conerrPipeName.empty()) { + return nullptr; + } else { + return cstrFromWStringOrNull(wp->conerrPipeName); + } +} + + + +/***************************************************************************** + * winpty agent RPC calls. */ + +namespace { + +// Close the control pipe if something goes wrong with the pipe communication, +// which could leave the control pipe in an inconsistent state. +class RpcOperation { +public: + RpcOperation(winpty_t &wp) : m_wp(wp) { + if (m_wp.controlPipe.get() == nullptr) { + throwWinptyException(L"Agent shutdown due to RPC failure"); + } + } + ~RpcOperation() { + if (!m_success) { + trace("~RpcOperation: Closing control pipe"); + m_wp.controlPipe.dispose(true); + } + } + void success() { m_success = true; } +private: + winpty_t &m_wp; + bool m_success = false; +}; + +} // anonymous namespace + + + +/***************************************************************************** + * winpty agent RPC call: process creation. */ + +// Return a std::wstring containing every character of the environment block. +// Typically, the block is non-empty, so the std::wstring returned ends with +// two NUL terminators. (These two terminators are counted in size(), so +// calling c_str() produces a triply-terminated string.) +static std::wstring wstringFromEnvBlock(const wchar_t *env) { + std::wstring envStr; + if (env != NULL) { + const wchar_t *p = env; + while (*p != L'\0') { + p += wcslen(p) + 1; + } + p++; + envStr.assign(env, p); + + // Assuming the environment was non-empty, envStr now ends with two NUL + // terminators. + // + // If the environment were empty, though, then envStr would only be + // singly terminated, but the MSDN documentation thinks an env block is + // always doubly-terminated, so add an extra NUL just in case it + // matters. + const auto envStrSz = envStr.size(); + if (envStrSz == 1) { + ASSERT(envStr[0] == L'\0'); + envStr.push_back(L'\0'); + } else { + ASSERT(envStrSz >= 3); + ASSERT(envStr[envStrSz - 3] != L'\0'); + ASSERT(envStr[envStrSz - 2] == L'\0'); + ASSERT(envStr[envStrSz - 1] == L'\0'); + } + } + return envStr; +} + +WINPTY_API winpty_spawn_config_t * +winpty_spawn_config_new(UINT64 winptyFlags, + LPCWSTR appname /*OPTIONAL*/, + LPCWSTR cmdline /*OPTIONAL*/, + LPCWSTR cwd /*OPTIONAL*/, + LPCWSTR env /*OPTIONAL*/, + winpty_error_ptr_t *err /*OPTIONAL*/) { + API_TRY { + ASSERT((winptyFlags & WINPTY_SPAWN_FLAG_MASK) == winptyFlags); + std::unique_ptr cfg(new winpty_spawn_config_t); + cfg->winptyFlags = winptyFlags; + if (appname != nullptr) { cfg->appname = appname; } + if (cmdline != nullptr) { cfg->cmdline = cmdline; } + if (cwd != nullptr) { cfg->cwd = cwd; } + if (env != nullptr) { cfg->env = wstringFromEnvBlock(env); } + return cfg.release(); + } API_CATCH(nullptr) +} + +WINPTY_API void winpty_spawn_config_free(winpty_spawn_config_t *cfg) { + delete cfg; +} + +// It's safe to truncate a handle from 64-bits to 32-bits, or to sign-extend it +// back to 64-bits. See the MSDN article, "Interprocess Communication Between +// 32-bit and 64-bit Applications". +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203.aspx +static inline HANDLE handleFromInt64(int64_t i) { + return reinterpret_cast(static_cast(i)); +} + +// Given a process and a handle in that process, duplicate the handle into the +// current process and close it in the originating process. +static inline OwnedHandle stealHandle(HANDLE process, HANDLE handle) { + HANDLE result = nullptr; + if (!DuplicateHandle(process, handle, + GetCurrentProcess(), + &result, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + throwWindowsError(L"DuplicateHandle of process handle"); + } + return OwnedHandle(result); +} + +WINPTY_API BOOL +winpty_spawn(winpty_t *wp, + const winpty_spawn_config_t *cfg, + HANDLE *process_handle /*OPTIONAL*/, + HANDLE *thread_handle /*OPTIONAL*/, + DWORD *create_process_error /*OPTIONAL*/, + winpty_error_ptr_t *err /*OPTIONAL*/) { + API_TRY { + ASSERT(wp != nullptr && cfg != nullptr); + + if (process_handle != nullptr) { *process_handle = nullptr; } + if (thread_handle != nullptr) { *thread_handle = nullptr; } + if (create_process_error != nullptr) { *create_process_error = 0; } + + LockGuard lock(wp->mutex); + RpcOperation rpc(*wp); + + // Send spawn request. + auto packet = newPacket(); + packet.putInt32(AgentMsg::StartProcess); + packet.putInt64(cfg->winptyFlags); + packet.putInt32(process_handle != nullptr); + packet.putInt32(thread_handle != nullptr); + packet.putWString(cfg->appname); + packet.putWString(cfg->cmdline); + packet.putWString(cfg->cwd); + packet.putWString(cfg->env); + packet.putWString(wp->spawnDesktopName); + writePacket(*wp, packet); + + // Receive reply. + auto reply = readPacket(*wp); + const auto result = static_cast(reply.getInt32()); + if (result == StartProcessResult::CreateProcessFailed) { + const DWORD lastError = reply.getInt32(); + reply.assertEof(); + if (create_process_error != nullptr) { + *create_process_error = lastError; + } + rpc.success(); + throw LibWinptyException(WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED, + L"CreateProcess failed"); + } else if (result == StartProcessResult::ProcessCreated) { + const HANDLE remoteProcess = handleFromInt64(reply.getInt64()); + const HANDLE remoteThread = handleFromInt64(reply.getInt64()); + reply.assertEof(); + OwnedHandle localProcess; + OwnedHandle localThread; + if (remoteProcess != nullptr) { + localProcess = + stealHandle(wp->agentProcess.get(), remoteProcess); + } + if (remoteThread != nullptr) { + localThread = + stealHandle(wp->agentProcess.get(), remoteThread); + } + if (process_handle != nullptr) { + *process_handle = localProcess.release(); + } + if (thread_handle != nullptr) { + *thread_handle = localThread.release(); + } + rpc.success(); + } else { + throwWinptyException( + L"Agent RPC error: invalid StartProcessResult"); + } + return TRUE; + } API_CATCH(FALSE) +} + + + +/***************************************************************************** + * winpty agent RPC calls: everything else */ + +WINPTY_API BOOL +winpty_set_size(winpty_t *wp, int cols, int rows, + winpty_error_ptr_t *err /*OPTIONAL*/) { + API_TRY { + ASSERT(wp != nullptr && cols > 0 && rows > 0); + LockGuard lock(wp->mutex); + RpcOperation rpc(*wp); + auto packet = newPacket(); + packet.putInt32(AgentMsg::SetSize); + packet.putInt32(cols); + packet.putInt32(rows); + writePacket(*wp, packet); + readPacket(*wp).assertEof(); + rpc.success(); + return TRUE; + } API_CATCH(FALSE) +} + +WINPTY_API int +winpty_get_console_process_list(winpty_t *wp, int *processList, const int processCount, + winpty_error_ptr_t *err /*OPTIONAL*/) { + API_TRY { + ASSERT(wp != nullptr); + ASSERT(processList != nullptr); + LockGuard lock(wp->mutex); + RpcOperation rpc(*wp); + auto packet = newPacket(); + packet.putInt32(AgentMsg::GetConsoleProcessList); + writePacket(*wp, packet); + auto reply = readPacket(*wp); + + auto actualProcessCount = reply.getInt32(); + + if (actualProcessCount <= processCount) { + for (auto i = 0; i < actualProcessCount; i++) { + processList[i] = reply.getInt32(); + } + } + + reply.assertEof(); + rpc.success(); + return actualProcessCount; + } API_CATCH(0) +} + +WINPTY_API void winpty_free(winpty_t *wp) { + // At least in principle, CloseHandle can fail, so this deletion can + // fail. It won't throw an exception, but maybe there's an error that + // should be propagated? + delete wp; +} diff --git a/src/libs/3rdparty/winpty/src/shared/AgentMsg.h b/src/libs/3rdparty/winpty/src/shared/AgentMsg.h new file mode 100644 index 00000000000..ab60c6b9619 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/AgentMsg.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SHARED_AGENT_MSG_H +#define WINPTY_SHARED_AGENT_MSG_H + +struct AgentMsg +{ + enum Type { + StartProcess, + SetSize, + GetConsoleProcessList, + }; +}; + +enum class StartProcessResult { + CreateProcessFailed, + ProcessCreated, +}; + +#endif // WINPTY_SHARED_AGENT_MSG_H diff --git a/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc new file mode 100644 index 00000000000..1bea7e53dd4 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "BackgroundDesktop.h" + +#include + +#include "DebugClient.h" +#include "StringUtil.h" +#include "WinptyException.h" + +namespace { + +static std::wstring getObjectName(HANDLE object) { + BOOL success; + DWORD lengthNeeded = 0; + GetUserObjectInformationW(object, UOI_NAME, + nullptr, 0, + &lengthNeeded); + ASSERT(lengthNeeded % sizeof(wchar_t) == 0); + std::unique_ptr tmp( + new wchar_t[lengthNeeded / sizeof(wchar_t)]); + success = GetUserObjectInformationW(object, UOI_NAME, + tmp.get(), lengthNeeded, + nullptr); + if (!success) { + throwWindowsError(L"GetUserObjectInformationW failed"); + } + return std::wstring(tmp.get()); +} + +static std::wstring getDesktopName(HWINSTA winsta, HDESK desk) { + return getObjectName(winsta) + L"\\" + getObjectName(desk); +} + +} // anonymous namespace + +// Get a non-interactive window station for the agent. +// TODO: review security w.r.t. windowstation and desktop. +BackgroundDesktop::BackgroundDesktop() { + try { + m_originalStation = GetProcessWindowStation(); + if (m_originalStation == nullptr) { + throwWindowsError( + L"BackgroundDesktop ctor: " + L"GetProcessWindowStation returned NULL"); + } + m_newStation = + CreateWindowStationW(nullptr, 0, WINSTA_ALL_ACCESS, nullptr); + if (m_newStation == nullptr) { + throwWindowsError( + L"BackgroundDesktop ctor: CreateWindowStationW returned NULL"); + } + if (!SetProcessWindowStation(m_newStation)) { + throwWindowsError( + L"BackgroundDesktop ctor: SetProcessWindowStation failed"); + } + m_newDesktop = CreateDesktopW( + L"Default", nullptr, nullptr, 0, GENERIC_ALL, nullptr); + if (m_newDesktop == nullptr) { + throwWindowsError( + L"BackgroundDesktop ctor: CreateDesktopW failed"); + } + m_newDesktopName = getDesktopName(m_newStation, m_newDesktop); + TRACE("Created background desktop: %s", + utf8FromWide(m_newDesktopName).c_str()); + } catch (...) { + dispose(); + throw; + } +} + +void BackgroundDesktop::dispose() WINPTY_NOEXCEPT { + if (m_originalStation != nullptr) { + SetProcessWindowStation(m_originalStation); + m_originalStation = nullptr; + } + if (m_newDesktop != nullptr) { + CloseDesktop(m_newDesktop); + m_newDesktop = nullptr; + } + if (m_newStation != nullptr) { + CloseWindowStation(m_newStation); + m_newStation = nullptr; + } +} + +std::wstring getCurrentDesktopName() { + // MSDN says that the handles returned by GetProcessWindowStation and + // GetThreadDesktop do not need to be passed to CloseWindowStation and + // CloseDesktop, respectively. + const HWINSTA winsta = GetProcessWindowStation(); + if (winsta == nullptr) { + throwWindowsError( + L"getCurrentDesktopName: " + L"GetProcessWindowStation returned NULL"); + } + const HDESK desk = GetThreadDesktop(GetCurrentThreadId()); + if (desk == nullptr) { + throwWindowsError( + L"getCurrentDesktopName: " + L"GetThreadDesktop returned NULL"); + } + return getDesktopName(winsta, desk); +} diff --git a/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h new file mode 100644 index 00000000000..c692e57dc49 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/BackgroundDesktop.h @@ -0,0 +1,73 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SHARED_BACKGROUND_DESKTOP_H +#define WINPTY_SHARED_BACKGROUND_DESKTOP_H + +#include + +#include + +#include "WinptyException.h" + +class BackgroundDesktop { +public: + BackgroundDesktop(); + ~BackgroundDesktop() { dispose(); } + void dispose() WINPTY_NOEXCEPT; + const std::wstring &desktopName() const { return m_newDesktopName; } + + BackgroundDesktop(const BackgroundDesktop &other) = delete; + BackgroundDesktop &operator=(const BackgroundDesktop &other) = delete; + + // We can't default the move constructor and assignment operator with + // MSVC 2013. We *could* if we required at least MSVC 2015 to build. + + BackgroundDesktop(BackgroundDesktop &&other) : + m_originalStation(other.m_originalStation), + m_newStation(other.m_newStation), + m_newDesktop(other.m_newDesktop), + m_newDesktopName(std::move(other.m_newDesktopName)) { + other.m_originalStation = nullptr; + other.m_newStation = nullptr; + other.m_newDesktop = nullptr; + } + BackgroundDesktop &operator=(BackgroundDesktop &&other) { + dispose(); + m_originalStation = other.m_originalStation; + m_newStation = other.m_newStation; + m_newDesktop = other.m_newDesktop; + m_newDesktopName = std::move(other.m_newDesktopName); + other.m_originalStation = nullptr; + other.m_newStation = nullptr; + other.m_newDesktop = nullptr; + return *this; + } + +private: + HWINSTA m_originalStation = nullptr; + HWINSTA m_newStation = nullptr; + HDESK m_newDesktop = nullptr; + std::wstring m_newDesktopName; +}; + +std::wstring getCurrentDesktopName(); + +#endif // WINPTY_SHARED_BACKGROUND_DESKTOP_H diff --git a/src/libs/3rdparty/winpty/src/shared/Buffer.cc b/src/libs/3rdparty/winpty/src/shared/Buffer.cc new file mode 100644 index 00000000000..158a629d564 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/Buffer.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "Buffer.h" + +#include + +#include "DebugClient.h" +#include "WinptyAssert.h" + +// Define the READ_BUFFER_CHECK() macro. It *must* evaluate its condition, +// exactly once. +#define READ_BUFFER_CHECK(cond) \ + do { \ + if (!(cond)) { \ + trace("decode error: %s", #cond); \ + throw DecodeError(); \ + } \ + } while (false) + +enum class Piece : uint8_t { Int32, Int64, WString }; + +void WriteBuffer::putRawData(const void *data, size_t len) { + const auto p = reinterpret_cast(data); + m_buf.insert(m_buf.end(), p, p + len); +} + +void WriteBuffer::replaceRawData(size_t pos, const void *data, size_t len) { + ASSERT(pos <= m_buf.size() && len <= m_buf.size() - pos); + const auto p = reinterpret_cast(data); + std::copy(p, p + len, &m_buf[pos]); +} + +void WriteBuffer::putInt32(int32_t i) { + putRawValue(Piece::Int32); + putRawValue(i); +} + +void WriteBuffer::putInt64(int64_t i) { + putRawValue(Piece::Int64); + putRawValue(i); +} + +// len is in characters, excluding NUL, i.e. the number of wchar_t elements +void WriteBuffer::putWString(const wchar_t *str, size_t len) { + putRawValue(Piece::WString); + putRawValue(static_cast(len)); + putRawData(str, sizeof(wchar_t) * len); +} + +void ReadBuffer::getRawData(void *data, size_t len) { + ASSERT(m_off <= m_buf.size()); + READ_BUFFER_CHECK(len <= m_buf.size() - m_off); + const char *const inp = &m_buf[m_off]; + std::copy(inp, inp + len, reinterpret_cast(data)); + m_off += len; +} + +int32_t ReadBuffer::getInt32() { + READ_BUFFER_CHECK(getRawValue() == Piece::Int32); + return getRawValue(); +} + +int64_t ReadBuffer::getInt64() { + READ_BUFFER_CHECK(getRawValue() == Piece::Int64); + return getRawValue(); +} + +std::wstring ReadBuffer::getWString() { + READ_BUFFER_CHECK(getRawValue() == Piece::WString); + const uint64_t charLen = getRawValue(); + READ_BUFFER_CHECK(charLen <= SIZE_MAX / sizeof(wchar_t)); + // To be strictly conforming, we can't use the convenient wstring + // constructor, because the string in m_buf mightn't be aligned. + std::wstring ret; + if (charLen > 0) { + const size_t byteLen = charLen * sizeof(wchar_t); + ret.resize(charLen); + getRawData(&ret[0], byteLen); + } + return ret; +} + +void ReadBuffer::assertEof() { + READ_BUFFER_CHECK(m_off == m_buf.size()); +} diff --git a/src/libs/3rdparty/winpty/src/shared/Buffer.h b/src/libs/3rdparty/winpty/src/shared/Buffer.h new file mode 100644 index 00000000000..c2dd382e5b2 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/Buffer.h @@ -0,0 +1,102 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SHARED_BUFFER_H +#define WINPTY_SHARED_BUFFER_H + +#include +#include + +#include +#include +#include +#include + +#include "WinptyException.h" + +class WriteBuffer { +private: + std::vector m_buf; + +public: + WriteBuffer() {} + + template void putRawValue(const T &t) { + putRawData(&t, sizeof(t)); + } + template void replaceRawValue(size_t pos, const T &t) { + replaceRawData(pos, &t, sizeof(t)); + } + + void putRawData(const void *data, size_t len); + void replaceRawData(size_t pos, const void *data, size_t len); + void putInt32(int32_t i); + void putInt64(int64_t i); + void putWString(const wchar_t *str, size_t len); + void putWString(const wchar_t *str) { putWString(str, wcslen(str)); } + void putWString(const std::wstring &str) { putWString(str.data(), str.size()); } + std::vector &buf() { return m_buf; } + + // MSVC 2013 does not generate these automatically, so help it out. + WriteBuffer(WriteBuffer &&other) : m_buf(std::move(other.m_buf)) {} + WriteBuffer &operator=(WriteBuffer &&other) { + m_buf = std::move(other.m_buf); + return *this; + } +}; + +class ReadBuffer { +public: + class DecodeError : public WinptyException { + virtual const wchar_t *what() const WINPTY_NOEXCEPT override { + return L"DecodeError: RPC message decoding error"; + } + }; + +private: + std::vector m_buf; + size_t m_off = 0; + +public: + explicit ReadBuffer(std::vector &&buf) : m_buf(std::move(buf)) {} + + template T getRawValue() { + T ret = {}; + getRawData(&ret, sizeof(ret)); + return ret; + } + + void getRawData(void *data, size_t len); + int32_t getInt32(); + int64_t getInt64(); + std::wstring getWString(); + void assertEof(); + + // MSVC 2013 does not generate these automatically, so help it out. + ReadBuffer(ReadBuffer &&other) : + m_buf(std::move(other.m_buf)), m_off(other.m_off) {} + ReadBuffer &operator=(ReadBuffer &&other) { + m_buf = std::move(other.m_buf); + m_off = other.m_off; + return *this; + } +}; + +#endif // WINPTY_SHARED_BUFFER_H diff --git a/src/libs/3rdparty/winpty/src/shared/DebugClient.cc b/src/libs/3rdparty/winpty/src/shared/DebugClient.cc new file mode 100644 index 00000000000..bafe0c89541 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/DebugClient.cc @@ -0,0 +1,187 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "DebugClient.h" + +#include +#include +#include +#include + +#include +#include + +#include "winpty_snprintf.h" + +const wchar_t *const kPipeName = L"\\\\.\\pipe\\DebugServer"; + +void *volatile g_debugConfig; + +namespace { + +// It would be easy to accidentally trample on the Windows LastError value +// by adding logging/debugging code. Ensure that can't happen by saving and +// restoring the value. This saving and restoring doesn't happen along the +// fast path. +class PreserveLastError { +public: + PreserveLastError() : m_lastError(GetLastError()) {} + ~PreserveLastError() { SetLastError(m_lastError); } +private: + DWORD m_lastError; +}; + +} // anonymous namespace + +static void sendToDebugServer(const char *message) +{ + HANDLE tracePipe = INVALID_HANDLE_VALUE; + + do { + // The default impersonation level is SECURITY_IMPERSONATION, which allows + // a sufficiently authorized named pipe server to impersonate the client. + // There's no need for impersonation in this debugging system, so reduce + // the impersonation level to SECURITY_IDENTIFICATION, which allows a + // server to merely identify us. + tracePipe = CreateFileW( + kPipeName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, + SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, + NULL); + } while (tracePipe == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_PIPE_BUSY && + WaitNamedPipeW(kPipeName, NMPWAIT_WAIT_FOREVER)); + + if (tracePipe != INVALID_HANDLE_VALUE) { + DWORD newMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState(tracePipe, &newMode, NULL, NULL); + char response[16]; + DWORD actual = 0; + TransactNamedPipe(tracePipe, + const_cast(message), strlen(message), + response, sizeof(response), &actual, NULL); + CloseHandle(tracePipe); + } +} + +// Get the current UTC time as milliseconds from the epoch (ignoring leap +// seconds). Use the Unix epoch for consistency with DebugClient.py. There +// are 134774 days between 1601-01-01 (the Win32 epoch) and 1970-01-01 (the +// Unix epoch). +static long long unixTimeMillis() +{ + FILETIME fileTime; + GetSystemTimeAsFileTime(&fileTime); + long long msTime = (((long long)fileTime.dwHighDateTime << 32) + + fileTime.dwLowDateTime) / 10000; + return msTime - 134774LL * 24 * 3600 * 1000; +} + +static const char *getDebugConfig() +{ + if (g_debugConfig == NULL) { + PreserveLastError preserve; + const int bufSize = 256; + char buf[bufSize]; + DWORD actualSize = + GetEnvironmentVariableA("WINPTY_DEBUG", buf, bufSize); + if (actualSize == 0 || actualSize >= static_cast(bufSize)) { + buf[0] = '\0'; + } + const size_t len = strlen(buf) + 1; + char *newConfig = new char[len]; + std::copy(buf, buf + len, newConfig); + void *oldValue = InterlockedCompareExchangePointer( + &g_debugConfig, newConfig, NULL); + if (oldValue != NULL) { + delete [] newConfig; + } + } + return static_cast(g_debugConfig); +} + +bool isTracingEnabled() +{ + static bool disabled, enabled; + if (disabled) { + return false; + } else if (enabled) { + return true; + } else { + // Recognize WINPTY_DEBUG=1 for backwards compatibility. + PreserveLastError preserve; + bool value = hasDebugFlag("trace") || hasDebugFlag("1"); + disabled = !value; + enabled = value; + return value; + } +} + +bool hasDebugFlag(const char *flag) +{ + if (strchr(flag, ',') != NULL) { + trace("INTERNAL ERROR: hasDebugFlag flag has comma: '%s'", flag); + abort(); + } + const char *const configCStr = getDebugConfig(); + if (configCStr[0] == '\0') { + return false; + } + PreserveLastError preserve; + std::string config(configCStr); + std::string flagStr(flag); + config = "," + config + ","; + flagStr = "," + flagStr + ","; + return config.find(flagStr) != std::string::npos; +} + +void trace(const char *format, ...) +{ + if (!isTracingEnabled()) + return; + + PreserveLastError preserve; + char message[1024]; + + va_list ap; + va_start(ap, format); + winpty_vsnprintf(message, format, ap); + message[sizeof(message) - 1] = '\0'; + va_end(ap); + + const int currentTime = (int)(unixTimeMillis() % (100000 * 1000)); + + char moduleName[1024]; + moduleName[0] = '\0'; + GetModuleFileNameA(NULL, moduleName, sizeof(moduleName)); + const char *baseName = strrchr(moduleName, '\\'); + baseName = (baseName != NULL) ? baseName + 1 : moduleName; + + char fullMessage[1024]; + winpty_snprintf(fullMessage, + "[%05d.%03d %s,p%04d,t%04d]: %s", + currentTime / 1000, currentTime % 1000, + baseName, (int)GetCurrentProcessId(), (int)GetCurrentThreadId(), + message); + fullMessage[sizeof(fullMessage) - 1] = '\0'; + + sendToDebugServer(fullMessage); +} diff --git a/src/libs/3rdparty/winpty/src/shared/DebugClient.h b/src/libs/3rdparty/winpty/src/shared/DebugClient.h new file mode 100644 index 00000000000..b1260711301 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/DebugClient.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011-2012 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef DEBUGCLIENT_H +#define DEBUGCLIENT_H + +#include "winpty_snprintf.h" + +bool isTracingEnabled(); +bool hasDebugFlag(const char *flag); +void trace(const char *format, ...) WINPTY_SNPRINTF_FORMAT(1, 2); + +// This macro calls trace without evaluating the arguments. +#define TRACE(format, ...) \ + do { \ + if (isTracingEnabled()) { \ + trace((format), ## __VA_ARGS__); \ + } \ + } while (false) + +#endif // DEBUGCLIENT_H diff --git a/src/libs/3rdparty/winpty/src/shared/GenRandom.cc b/src/libs/3rdparty/winpty/src/shared/GenRandom.cc new file mode 100644 index 00000000000..6d7920643af --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/GenRandom.cc @@ -0,0 +1,138 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "GenRandom.h" + +#include +#include + +#include "DebugClient.h" +#include "StringBuilder.h" + +static volatile LONG g_pipeCounter; + +GenRandom::GenRandom() : m_advapi32(L"advapi32.dll") { + // First try to use the pseudo-documented RtlGenRandom function from + // advapi32.dll. Creating a CryptoAPI context is slow, and RtlGenRandom + // avoids the overhead. It's documented in this blog post[1] and on + // MSDN[2] with a disclaimer about future breakage. This technique is + // apparently built-in into the MSVC CRT, though, for the rand_s function, + // so perhaps it is stable enough. + // + // [1] http://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx + // [2] https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx + // + // Both RtlGenRandom and the Crypto API functions exist in XP and up. + m_rtlGenRandom = reinterpret_cast( + m_advapi32.proc("SystemFunction036")); + // The OsModule class logs an error message if the proc is nullptr. + if (m_rtlGenRandom != nullptr) { + return; + } + + // Fall back to the crypto API. + m_cryptProvIsValid = + CryptAcquireContext(&m_cryptProv, nullptr, nullptr, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) != 0; + if (!m_cryptProvIsValid) { + trace("GenRandom: CryptAcquireContext failed: %u", + static_cast(GetLastError())); + } +} + +GenRandom::~GenRandom() { + if (m_cryptProvIsValid) { + CryptReleaseContext(m_cryptProv, 0); + } +} + +// Returns false if the context is invalid or the generation fails. +bool GenRandom::fillBuffer(void *buffer, size_t size) { + memset(buffer, 0, size); + bool success = false; + if (m_rtlGenRandom != nullptr) { + success = m_rtlGenRandom(buffer, size) != 0; + if (!success) { + trace("GenRandom: RtlGenRandom/SystemFunction036 failed: %u", + static_cast(GetLastError())); + } + } else if (m_cryptProvIsValid) { + success = + CryptGenRandom(m_cryptProv, size, + reinterpret_cast(buffer)) != 0; + if (!success) { + trace("GenRandom: CryptGenRandom failed, size=%d, lasterror=%u", + static_cast(size), + static_cast(GetLastError())); + } + } + return success; +} + +// Returns an empty string if either of CryptAcquireContext or CryptGenRandom +// fail. +std::string GenRandom::randomBytes(size_t numBytes) { + std::string ret(numBytes, '\0'); + if (!fillBuffer(&ret[0], numBytes)) { + return std::string(); + } + return ret; +} + +std::wstring GenRandom::randomHexString(size_t numBytes) { + const std::string bytes = randomBytes(numBytes); + std::wstring ret(bytes.size() * 2, L'\0'); + for (size_t i = 0; i < bytes.size(); ++i) { + static const wchar_t hex[] = L"0123456789abcdef"; + ret[i * 2] = hex[static_cast(bytes[i]) >> 4]; + ret[i * 2 + 1] = hex[static_cast(bytes[i]) & 0xF]; + } + return ret; +} + +// Returns a 64-bit value representing the number of 100-nanosecond intervals +// since January 1, 1601. +static uint64_t systemTimeAsUInt64() { + FILETIME monotonicTime = {}; + GetSystemTimeAsFileTime(&monotonicTime); + return (static_cast(monotonicTime.dwHighDateTime) << 32) | + static_cast(monotonicTime.dwLowDateTime); +} + +// Generates a unique and hard-to-guess case-insensitive string suitable for +// use in a pipe filename or a Windows object name. +std::wstring GenRandom::uniqueName() { + // First include enough information to avoid collisions assuming + // cooperative software. This code assumes that a process won't die and + // be replaced with a recycled PID within a single GetSystemTimeAsFileTime + // interval. + WStringBuilder sb(64); + sb << GetCurrentProcessId() + << L'-' << InterlockedIncrement(&g_pipeCounter) + << L'-' << whexOfInt(systemTimeAsUInt64()); + // It isn't clear to me how the crypto APIs would fail. It *probably* + // doesn't matter that much anyway? In principle, a predictable pipe name + // is subject to a local denial-of-service attack. + auto random = randomHexString(16); + if (!random.empty()) { + sb << L'-' << random; + } + return sb.str_moved(); +} diff --git a/src/libs/3rdparty/winpty/src/shared/GenRandom.h b/src/libs/3rdparty/winpty/src/shared/GenRandom.h new file mode 100644 index 00000000000..746cb1ecf70 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/GenRandom.h @@ -0,0 +1,55 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_GEN_RANDOM_H +#define WINPTY_GEN_RANDOM_H + +// The original MinGW requires that we include wincrypt.h. With MinGW-w64 and +// MSVC, including windows.h is sufficient. +#include +#include + +#include + +#include "OsModule.h" + +class GenRandom { + typedef BOOLEAN WINAPI RtlGenRandom_t(PVOID, ULONG); + + OsModule m_advapi32; + RtlGenRandom_t *m_rtlGenRandom = nullptr; + bool m_cryptProvIsValid = false; + HCRYPTPROV m_cryptProv = 0; + +public: + GenRandom(); + ~GenRandom(); + bool fillBuffer(void *buffer, size_t size); + std::string randomBytes(size_t numBytes); + std::wstring randomHexString(size_t numBytes); + std::wstring uniqueName(); + + // Return true if the crypto context was successfully initialized. + bool valid() const { + return m_rtlGenRandom != nullptr || m_cryptProvIsValid; + } +}; + +#endif // WINPTY_GEN_RANDOM_H diff --git a/src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat b/src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat new file mode 100644 index 00000000000..a9f8e9cef0f --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/GetCommitHash.bat @@ -0,0 +1,13 @@ +@echo off + +REM -- Echo the git commit hash. If git isn't available for some reason, +REM -- output nothing instead. + +git rev-parse HEAD >NUL 2>NUL && ( + git rev-parse HEAD +) || ( + echo none +) + +REM -- Set ERRORLEVEL to 0 using this cryptic syntax. +(call ) diff --git a/src/libs/3rdparty/winpty/src/shared/Mutex.h b/src/libs/3rdparty/winpty/src/shared/Mutex.h new file mode 100644 index 00000000000..98215365ad2 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/Mutex.h @@ -0,0 +1,54 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Recent 4.x MinGW and MinGW-w64 gcc compilers lack std::mutex and +// std::lock_guard. I have a 5.2.0 MinGW-w64 compiler packaged through MSYS2 +// that *is* new enough, but that's one compiler against several deficient +// ones. Wrap CRITICAL_SECTION instead. + +#ifndef WINPTY_SHARED_MUTEX_H +#define WINPTY_SHARED_MUTEX_H + +#include + +class Mutex { + CRITICAL_SECTION m_mutex; +public: + Mutex() { InitializeCriticalSection(&m_mutex); } + ~Mutex() { DeleteCriticalSection(&m_mutex); } + void lock() { EnterCriticalSection(&m_mutex); } + void unlock() { LeaveCriticalSection(&m_mutex); } + + Mutex(const Mutex &other) = delete; + Mutex &operator=(const Mutex &other) = delete; +}; + +template +class LockGuard { + T &m_lock; +public: + LockGuard(T &lock) : m_lock(lock) { m_lock.lock(); } + ~LockGuard() { m_lock.unlock(); } + + LockGuard(const LockGuard &other) = delete; + LockGuard &operator=(const LockGuard &other) = delete; +}; + +#endif // WINPTY_SHARED_MUTEX_H diff --git a/src/libs/3rdparty/winpty/src/shared/OsModule.h b/src/libs/3rdparty/winpty/src/shared/OsModule.h new file mode 100644 index 00000000000..9713fa2b2dd --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/OsModule.h @@ -0,0 +1,63 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SHARED_OS_MODULE_H +#define WINPTY_SHARED_OS_MODULE_H + +#include + +#include + +#include "DebugClient.h" +#include "WinptyAssert.h" +#include "WinptyException.h" + +class OsModule { + HMODULE m_module; +public: + enum class LoadErrorBehavior { Abort, Throw }; + OsModule(const wchar_t *fileName, + LoadErrorBehavior behavior=LoadErrorBehavior::Abort) { + m_module = LoadLibraryW(fileName); + if (behavior == LoadErrorBehavior::Abort) { + ASSERT(m_module != NULL); + } else { + if (m_module == nullptr) { + const auto err = GetLastError(); + throwWindowsError( + (L"LoadLibraryW error: " + std::wstring(fileName)).c_str(), + err); + } + } + } + ~OsModule() { + FreeLibrary(m_module); + } + HMODULE handle() const { return m_module; } + FARPROC proc(const char *funcName) { + FARPROC ret = GetProcAddress(m_module, funcName); + if (ret == NULL) { + trace("GetProcAddress: %s is missing", funcName); + } + return ret; + } +}; + +#endif // WINPTY_SHARED_OS_MODULE_H diff --git a/src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc new file mode 100644 index 00000000000..7b173536e6b --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "OwnedHandle.h" + +#include "DebugClient.h" +#include "WinptyException.h" + +void OwnedHandle::dispose(bool nothrow) { + if (m_h != nullptr && m_h != INVALID_HANDLE_VALUE) { + if (!CloseHandle(m_h)) { + trace("CloseHandle(%p) failed", m_h); + if (!nothrow) { + throwWindowsError(L"CloseHandle failed"); + } + } + } + m_h = nullptr; +} diff --git a/src/libs/3rdparty/winpty/src/shared/OwnedHandle.h b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.h new file mode 100644 index 00000000000..70a8d6163a9 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/OwnedHandle.h @@ -0,0 +1,45 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SHARED_OWNED_HANDLE_H +#define WINPTY_SHARED_OWNED_HANDLE_H + +#include + +class OwnedHandle { + HANDLE m_h; +public: + OwnedHandle() : m_h(nullptr) {} + explicit OwnedHandle(HANDLE h) : m_h(h) {} + ~OwnedHandle() { dispose(true); } + void dispose(bool nothrow=false); + HANDLE get() const { return m_h; } + HANDLE release() { HANDLE ret = m_h; m_h = nullptr; return ret; } + OwnedHandle(const OwnedHandle &other) = delete; + OwnedHandle(OwnedHandle &&other) : m_h(other.release()) {} + OwnedHandle &operator=(const OwnedHandle &other) = delete; + OwnedHandle &operator=(OwnedHandle &&other) { + dispose(); + m_h = other.release(); + return *this; + } +}; + +#endif // WINPTY_SHARED_OWNED_HANDLE_H diff --git a/src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h b/src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h new file mode 100644 index 00000000000..7d9b8f8b4af --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/PrecompiledHeader.h @@ -0,0 +1,43 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_PRECOMPILED_HEADER_H +#define WINPTY_PRECOMPILED_HEADER_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // WINPTY_PRECOMPILED_HEADER_H diff --git a/src/libs/3rdparty/winpty/src/shared/StringBuilder.h b/src/libs/3rdparty/winpty/src/shared/StringBuilder.h new file mode 100644 index 00000000000..f3155bdd29e --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/StringBuilder.h @@ -0,0 +1,227 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Efficient integer->string conversion and string concatenation. The +// hexadecimal conversion may optionally have leading zeros. Other ways to +// convert integers to strings in C++ suffer these drawbacks: +// +// * std::stringstream: Inefficient, even more so than stdio. +// +// * std::to_string: No hexadecimal output, tends to use heap allocation, not +// supported on Cygwin. +// +// * stdio routines: Requires parsing a format string (inefficient). The +// caller *must* know how large the content is for correctness. The +// string-printf functions are extremely inconsistent on Windows. In +// particular, 64-bit integers, wide strings, and return values are +// problem areas. +// +// StringBuilderTest.cc is a standalone program that tests this header. + +#ifndef WINPTY_STRING_BUILDER_H +#define WINPTY_STRING_BUILDER_H + +#include +#include +#include + +#ifdef STRING_BUILDER_TESTING +#include +#define STRING_BUILDER_CHECK(cond) assert(cond) +#else +#define STRING_BUILDER_CHECK(cond) +#endif // STRING_BUILDER_TESTING + +#include "WinptyAssert.h" + +template +struct ValueString { + std::array m_array; + size_t m_offset; + size_t m_size; + + const C *c_str() const { return m_array.data() + m_offset; } + const C *data() const { return m_array.data() + m_offset; } + size_t size() const { return m_size; } + std::basic_string str() const { + return std::basic_string(data(), m_size); + } +}; + +#ifdef _MSC_VER +// Disable an MSVC /SDL error that forbids unsigned negation. Signed negation +// invokes undefined behavior for INTxx_MIN, so unsigned negation is simpler to +// reason about. (We assume twos-complement in any case.) +#define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) \ + ( \ + __pragma(warning(push)) \ + __pragma(warning(disable:4146)) \ + (x) \ + __pragma(warning(pop)) \ + ) +#else +#define STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(x) (x) +#endif + +// Formats an integer as decimal without leading zeros. +template +ValueString gdecOfInt(const I value) { + typedef typename std::make_unsigned::type U; + auto unsValue = static_cast(value); + const bool isNegative = (value < 0); + if (isNegative) { + unsValue = STRING_BUILDER_ALLOW_UNSIGNED_NEGATE(-unsValue); + } + decltype(gdecOfInt(value)) out; + auto &arr = out.m_array; + C *const endp = arr.data() + arr.size(); + C *outp = endp; + *(--outp) = '\0'; + STRING_BUILDER_CHECK(outp >= arr.data()); + do { + const int digit = unsValue % 10; + unsValue /= 10; + *(--outp) = '0' + digit; + STRING_BUILDER_CHECK(outp >= arr.data()); + } while (unsValue != 0); + if (isNegative) { + *(--outp) = '-'; + STRING_BUILDER_CHECK(outp >= arr.data()); + } + out.m_offset = outp - arr.data(); + out.m_size = endp - outp - 1; + return out; +} + +template decltype(gdecOfInt(0)) decOfInt(I i) { + return gdecOfInt(i); +} + +template decltype(gdecOfInt(0)) wdecOfInt(I i) { + return gdecOfInt(i); +} + +// Formats an integer as hexadecimal, with or without leading zeros. +template +ValueString ghexOfInt(const I value) { + typedef typename std::make_unsigned::type U; + const auto unsValue = static_cast(value); + static const C hex[16] = {'0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f'}; + decltype(ghexOfInt(value)) out; + auto &arr = out.m_array; + C *outp = arr.data(); + int inIndex = 0; + int shift = sizeof(I) * 8 - 4; + const int len = sizeof(I) * 2; + if (!leadingZeros) { + for (; inIndex < len - 1; ++inIndex, shift -= 4) { + STRING_BUILDER_CHECK(shift >= 0 && shift < sizeof(unsValue) * 8); + const int digit = (unsValue >> shift) & 0xF; + if (digit != 0) { + break; + } + } + } + for (; inIndex < len; ++inIndex, shift -= 4) { + const int digit = (unsValue >> shift) & 0xF; + *(outp++) = hex[digit]; + STRING_BUILDER_CHECK(outp <= arr.data() + arr.size()); + } + *(outp++) = '\0'; + STRING_BUILDER_CHECK(outp <= arr.data() + arr.size()); + out.m_offset = 0; + out.m_size = outp - arr.data() - 1; + return out; +} + +template +decltype(ghexOfInt(0)) hexOfInt(I i) { + return ghexOfInt(i); +} + +template +decltype(ghexOfInt(0)) whexOfInt(I i) { + return ghexOfInt(i); +} + +template +class GStringBuilder { +public: + typedef std::basic_string StringType; + + GStringBuilder() {} + GStringBuilder(size_t capacity) { + m_out.reserve(capacity); + } + + GStringBuilder &operator<<(C ch) { m_out.push_back(ch); return *this; } + GStringBuilder &operator<<(const C *str) { m_out.append(str); return *this; } + GStringBuilder &operator<<(const StringType &str) { m_out.append(str); return *this; } + + template + GStringBuilder &operator<<(const ValueString &str) { + m_out.append(str.data(), str.size()); + return *this; + } + +private: + // Forbid output of char/wchar_t for GStringBuilder if the type doesn't + // exactly match the builder element type. The code still allows + // signed char and unsigned char, but I'm a little worried about what + // happens if a user tries to output int8_t or uint8_t. + template + typename std::enable_if< + (std::is_same::value || std::is_same::value) && + !std::is_same::value, GStringBuilder&>::type + operator<<(P ch) { + ASSERT(false && "Method was not supposed to be reachable."); + return *this; + } + +public: + GStringBuilder &operator<<(short i) { return *this << gdecOfInt(i); } + GStringBuilder &operator<<(unsigned short i) { return *this << gdecOfInt(i); } + GStringBuilder &operator<<(int i) { return *this << gdecOfInt(i); } + GStringBuilder &operator<<(unsigned int i) { return *this << gdecOfInt(i); } + GStringBuilder &operator<<(long i) { return *this << gdecOfInt(i); } + GStringBuilder &operator<<(unsigned long i) { return *this << gdecOfInt(i); } + GStringBuilder &operator<<(long long i) { return *this << gdecOfInt(i); } + GStringBuilder &operator<<(unsigned long long i) { return *this << gdecOfInt(i); } + + GStringBuilder &operator<<(const void *p) { + m_out.push_back(static_cast('0')); + m_out.push_back(static_cast('x')); + *this << ghexOfInt(reinterpret_cast(p)); + return *this; + } + + StringType str() { return m_out; } + StringType str_moved() { return std::move(m_out); } + const C *c_str() const { return m_out.c_str(); } + +private: + StringType m_out; +}; + +typedef GStringBuilder StringBuilder; +typedef GStringBuilder WStringBuilder; + +#endif // WINPTY_STRING_BUILDER_H diff --git a/src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc b/src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc new file mode 100644 index 00000000000..e6c2d3138c8 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/StringBuilderTest.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#define STRING_BUILDER_TESTING + +#include "StringBuilder.h" + +#include +#include + +#include +#include + +void display(const std::string &str) { fprintf(stderr, "%s", str.c_str()); } +void display(const std::wstring &str) { fprintf(stderr, "%ls", str.c_str()); } + +#define CHECK_EQ(x, y) \ + do { \ + const auto xval = (x); \ + const auto yval = (y); \ + if (xval != yval) { \ + fprintf(stderr, "error: %s:%d: %s != %s: ", \ + __FILE__, __LINE__, #x, #y); \ + display(xval); \ + fprintf(stderr, " != "); \ + display(yval); \ + fprintf(stderr, "\n"); \ + } \ + } while(0) + +template +std::basic_string decOfIntSS(const I value) { + // std::to_string and std::to_wstring are missing in Cygwin as of this + // writing (early 2016). + std::basic_stringstream ss; + ss << +value; // We must promote char to print it as an integer. + return ss.str(); +} + + +template +std::basic_string hexOfIntSS(const I value) { + typedef typename std::make_unsigned::type U; + const unsigned long long u64Value = value & static_cast(~0); + std::basic_stringstream ss; + if (leadingZeros) { + ss << std::setfill(static_cast('0')) << std::setw(sizeof(I) * 2); + } + ss << std::hex << u64Value; + return ss.str(); +} + +template +void testValue(I value) { + CHECK_EQ(decOfInt(value).str(), (decOfIntSS(value))); + CHECK_EQ(wdecOfInt(value).str(), (decOfIntSS(value))); + CHECK_EQ((hexOfInt(value).str()), (hexOfIntSS(value))); + CHECK_EQ((hexOfInt(value).str()), (hexOfIntSS(value))); + CHECK_EQ((whexOfInt(value).str()), (hexOfIntSS(value))); + CHECK_EQ((whexOfInt(value).str()), (hexOfIntSS(value))); +} + +template +void testType() { + typedef typename std::make_unsigned::type U; + const U quarter = static_cast(1) << (sizeof(U) * 8 - 2); + for (unsigned quarterIndex = 0; quarterIndex < 4; ++quarterIndex) { + for (int offset = -18; offset <= 18; ++offset) { + const I value = quarter * quarterIndex + static_cast(offset); + testValue(value); + } + } + testValue(static_cast(42)); + testValue(static_cast(123456)); + testValue(static_cast(0xdeadfacecafebeefull)); +} + +int main() { + testType(); + + testType(); + testType(); + testType(); + testType(); + testType(); + + testType(); + testType(); + testType(); + testType(); + testType(); + + StringBuilder() << static_cast("TEST"); + WStringBuilder() << static_cast("TEST"); + + fprintf(stderr, "All tests completed!\n"); +} diff --git a/src/libs/3rdparty/winpty/src/shared/StringUtil.cc b/src/libs/3rdparty/winpty/src/shared/StringUtil.cc new file mode 100644 index 00000000000..3a85a3ec941 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/StringUtil.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "StringUtil.h" + +#include + +#include "WinptyAssert.h" + +// Workaround. MinGW (from mingw.org) does not have wcsnlen. MinGW-w64 *does* +// have wcsnlen, but use this function for consistency. +size_t winpty_wcsnlen(const wchar_t *s, size_t maxlen) { + ASSERT(s != NULL); + for (size_t i = 0; i < maxlen; ++i) { + if (s[i] == L'\0') { + return i; + } + } + return maxlen; +} + +std::string utf8FromWide(const std::wstring &input) { + int mblen = WideCharToMultiByte( + CP_UTF8, 0, + input.data(), input.size(), + NULL, 0, NULL, NULL); + if (mblen <= 0) { + return std::string(); + } + std::vector tmp(mblen); + int mblen2 = WideCharToMultiByte( + CP_UTF8, 0, + input.data(), input.size(), + tmp.data(), tmp.size(), + NULL, NULL); + ASSERT(mblen2 == mblen); + return std::string(tmp.data(), tmp.size()); +} diff --git a/src/libs/3rdparty/winpty/src/shared/StringUtil.h b/src/libs/3rdparty/winpty/src/shared/StringUtil.h new file mode 100644 index 00000000000..e4bf3c91212 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/StringUtil.h @@ -0,0 +1,80 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SHARED_STRING_UTIL_H +#define WINPTY_SHARED_STRING_UTIL_H + +#include +#include +#include + +#include +#include +#include + +#include "WinptyAssert.h" + +size_t winpty_wcsnlen(const wchar_t *s, size_t maxlen); +std::string utf8FromWide(const std::wstring &input); + +// Return a vector containing each character in the string. +template +std::vector vectorFromString(const std::basic_string &str) { + return std::vector(str.begin(), str.end()); +} + +// Return a vector containing each character in the string, followed by a +// NUL terminator. +template +std::vector vectorWithNulFromString(const std::basic_string &str) { + std::vector ret; + ret.reserve(str.size() + 1); + ret.insert(ret.begin(), str.begin(), str.end()); + ret.push_back('\0'); + return ret; +} + +// A safer(?) version of wcsncpy that is accepted by MSVC's /SDL mode. +template +wchar_t *winpty_wcsncpy(wchar_t (&d)[N], const wchar_t *s) { + ASSERT(s != nullptr); + size_t i = 0; + for (; i < N; ++i) { + if (s[i] == L'\0') { + break; + } + d[i] = s[i]; + } + for (; i < N; ++i) { + d[i] = L'\0'; + } + return d; +} + +// Like wcsncpy, but ensure that the destination buffer is NUL-terminated. +template +wchar_t *winpty_wcsncpy_nul(wchar_t (&d)[N], const wchar_t *s) { + static_assert(N > 0, "array cannot be 0-size"); + winpty_wcsncpy(d, s); + d[N - 1] = L'\0'; + return d; +} + +#endif // WINPTY_SHARED_STRING_UTIL_H diff --git a/src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h b/src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h new file mode 100644 index 00000000000..716a027fcbd --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/TimeMeasurement.h @@ -0,0 +1,63 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// Convenience header library for using the high-resolution performance counter +// to measure how long some process takes. + +#ifndef TIME_MEASUREMENT_H +#define TIME_MEASUREMENT_H + +#include +#include +#include + +class TimeMeasurement { +public: + TimeMeasurement() { + static double freq = static_cast(getFrequency()); + m_freq = freq; + m_start = value(); + } + + double elapsed() { + uint64_t elapsedTicks = value() - m_start; + return static_cast(elapsedTicks) / m_freq; + } + +private: + uint64_t getFrequency() { + LARGE_INTEGER freq; + BOOL success = QueryPerformanceFrequency(&freq); + assert(success && "QueryPerformanceFrequency failed"); + return freq.QuadPart; + } + + uint64_t value() { + LARGE_INTEGER ret; + BOOL success = QueryPerformanceCounter(&ret); + assert(success && "QueryPerformanceCounter failed"); + return ret.QuadPart; + } + + uint64_t m_start; + double m_freq; +}; + +#endif // TIME_MEASUREMENT_H diff --git a/src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h b/src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h new file mode 100644 index 00000000000..39dfa62ec9f --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/UnixCtrlChars.h @@ -0,0 +1,45 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNIX_CTRL_CHARS_H +#define UNIX_CTRL_CHARS_H + +inline char decodeUnixCtrlChar(char ch) { + const char ctrlKeys[] = { + /* 0x00 */ '@', /* 0x01 */ 'A', /* 0x02 */ 'B', /* 0x03 */ 'C', + /* 0x04 */ 'D', /* 0x05 */ 'E', /* 0x06 */ 'F', /* 0x07 */ 'G', + /* 0x08 */ 'H', /* 0x09 */ 'I', /* 0x0A */ 'J', /* 0x0B */ 'K', + /* 0x0C */ 'L', /* 0x0D */ 'M', /* 0x0E */ 'N', /* 0x0F */ 'O', + /* 0x10 */ 'P', /* 0x11 */ 'Q', /* 0x12 */ 'R', /* 0x13 */ 'S', + /* 0x14 */ 'T', /* 0x15 */ 'U', /* 0x16 */ 'V', /* 0x17 */ 'W', + /* 0x18 */ 'X', /* 0x19 */ 'Y', /* 0x1A */ 'Z', /* 0x1B */ '[', + /* 0x1C */ '\\', /* 0x1D */ ']', /* 0x1E */ '^', /* 0x1F */ '_', + }; + unsigned char uch = ch; + if (uch < 32) { + return ctrlKeys[uch]; + } else if (uch == 127) { + return '?'; + } else { + return '\0'; + } +} + +#endif // UNIX_CTRL_CHARS_H diff --git a/src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat b/src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat new file mode 100644 index 00000000000..ea2a7d64ed5 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/UpdateGenVersion.bat @@ -0,0 +1,20 @@ +@echo off + +rem -- Echo the git commit hash. If git isn't available for some reason, +rem -- output nothing instead. + +mkdir ..\gen 2>nul + +set /p VERSION=<..\..\VERSION.txt +set COMMIT=%1 + +echo // AUTO-GENERATED BY %0 %*>..\gen\GenVersion.h +echo const char GenVersion_Version[] = "%VERSION%";>>..\gen\GenVersion.h +echo const char GenVersion_Commit[] = "%COMMIT%";>>..\gen\GenVersion.h + +rem -- The winpty.gyp file expects the script to output the include directory, +rem -- relative to src. +echo gen + +rem -- Set ERRORLEVEL to 0 using this cryptic syntax. +(call ) diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc new file mode 100644 index 00000000000..711a8637c8c --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.cc @@ -0,0 +1,460 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "WindowsSecurity.h" + +#include + +#include "DebugClient.h" +#include "OsModule.h" +#include "OwnedHandle.h" +#include "StringBuilder.h" +#include "WindowsVersion.h" +#include "WinptyAssert.h" +#include "WinptyException.h" + +namespace { + +struct LocalFreer { + void operator()(void *ptr) { + if (ptr != nullptr) { + LocalFree(reinterpret_cast(ptr)); + } + } +}; + +typedef std::unique_ptr PointerLocal; + +template +SecurityItem localItem(typename T::type v) { + typedef typename T::type P; + struct Impl : SecurityItem::Impl { + P m_v; + Impl(P v) : m_v(v) {} + virtual ~Impl() { + LocalFree(reinterpret_cast(m_v)); + } + }; + return SecurityItem(v, std::unique_ptr(new Impl { v })); +} + +Sid allocatedSid(PSID v) { + struct Impl : Sid::Impl { + PSID m_v; + Impl(PSID v) : m_v(v) {} + virtual ~Impl() { + if (m_v != nullptr) { + FreeSid(m_v); + } + } + }; + return Sid(v, std::unique_ptr(new Impl { v })); +} + +} // anonymous namespace + +// Returns a handle to the thread's effective security token. If the thread +// is impersonating another user, its token is returned, and otherwise, the +// process' security token is opened. The handle is opened with TOKEN_QUERY. +static OwnedHandle openSecurityTokenForQuery() { + HANDLE token = nullptr; + // It is unclear to me whether OpenAsSelf matters for winpty, or what the + // most appropriate value is. + if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, + /*OpenAsSelf=*/FALSE, &token)) { + if (GetLastError() != ERROR_NO_TOKEN) { + throwWindowsError(L"OpenThreadToken failed"); + } + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { + throwWindowsError(L"OpenProcessToken failed"); + } + } + ASSERT(token != nullptr && + "OpenThreadToken/OpenProcessToken token is NULL"); + return OwnedHandle(token); +} + +// Returns the TokenOwner of the thread's effective security token. +Sid getOwnerSid() { + struct Impl : Sid::Impl { + std::unique_ptr buffer; + }; + + OwnedHandle token = openSecurityTokenForQuery(); + DWORD actual = 0; + BOOL success; + success = GetTokenInformation(token.get(), TokenOwner, + nullptr, 0, &actual); + if (success) { + throwWinptyException(L"getOwnerSid: GetTokenInformation: " + L"expected ERROR_INSUFFICIENT_BUFFER"); + } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + throwWindowsError(L"getOwnerSid: GetTokenInformation: " + L"expected ERROR_INSUFFICIENT_BUFFER"); + } + std::unique_ptr impl(new Impl); + impl->buffer = std::unique_ptr(new char[actual]); + success = GetTokenInformation(token.get(), TokenOwner, + impl->buffer.get(), actual, &actual); + if (!success) { + throwWindowsError(L"getOwnerSid: GetTokenInformation"); + } + TOKEN_OWNER tmp; + ASSERT(actual >= sizeof(tmp)); + std::copy( + impl->buffer.get(), + impl->buffer.get() + sizeof(tmp), + reinterpret_cast(&tmp)); + return Sid(tmp.Owner, std::move(impl)); +} + +Sid wellKnownSid( + const wchar_t *debuggingName, + SID_IDENTIFIER_AUTHORITY authority, + BYTE authorityCount, + DWORD subAuthority0/*=0*/, + DWORD subAuthority1/*=0*/) { + PSID psid = nullptr; + if (!AllocateAndInitializeSid(&authority, authorityCount, + subAuthority0, + subAuthority1, + 0, 0, 0, 0, 0, 0, + &psid)) { + const auto err = GetLastError(); + const auto msg = + std::wstring(L"wellKnownSid: error getting ") + + debuggingName + L" SID"; + throwWindowsError(msg.c_str(), err); + } + return allocatedSid(psid); +} + +Sid builtinAdminsSid() { + // S-1-5-32-544 + SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY }; + return wellKnownSid(L"BUILTIN\\Administrators group", + authority, 2, + SECURITY_BUILTIN_DOMAIN_RID, // 32 + DOMAIN_ALIAS_RID_ADMINS); // 544 +} + +Sid localSystemSid() { + // S-1-5-18 + SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY }; + return wellKnownSid(L"LocalSystem account", + authority, 1, + SECURITY_LOCAL_SYSTEM_RID); // 18 +} + +Sid everyoneSid() { + // S-1-1-0 + SID_IDENTIFIER_AUTHORITY authority = { SECURITY_WORLD_SID_AUTHORITY }; + return wellKnownSid(L"Everyone account", + authority, 1, + SECURITY_WORLD_RID); // 0 +} + +static SecurityDescriptor finishSecurityDescriptor( + size_t daclEntryCount, + EXPLICIT_ACCESSW *daclEntries, + Acl &outAcl) { + { + PACL aclRaw = nullptr; + DWORD aclError = + SetEntriesInAclW(daclEntryCount, + daclEntries, + nullptr, &aclRaw); + if (aclError != ERROR_SUCCESS) { + WStringBuilder sb(64); + sb << L"finishSecurityDescriptor: " + << L"SetEntriesInAcl failed: " << aclError; + throwWinptyException(sb.c_str()); + } + outAcl = localItem(aclRaw); + } + + const PSECURITY_DESCRIPTOR sdRaw = + reinterpret_cast( + LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)); + if (sdRaw == nullptr) { + throwWinptyException(L"finishSecurityDescriptor: LocalAlloc failed"); + } + SecurityDescriptor sd = localItem(sdRaw); + if (!InitializeSecurityDescriptor(sdRaw, SECURITY_DESCRIPTOR_REVISION)) { + throwWindowsError( + L"finishSecurityDescriptor: InitializeSecurityDescriptor"); + } + if (!SetSecurityDescriptorDacl(sdRaw, TRUE, outAcl.get(), FALSE)) { + throwWindowsError( + L"finishSecurityDescriptor: SetSecurityDescriptorDacl"); + } + + return std::move(sd); +} + +// Create a security descriptor that grants full control to the local system +// account, built-in administrators, and the owner. +SecurityDescriptor +createPipeSecurityDescriptorOwnerFullControl() { + + struct Impl : SecurityDescriptor::Impl { + Sid localSystem; + Sid builtinAdmins; + Sid owner; + std::array daclEntries = {}; + Acl dacl; + SecurityDescriptor value; + }; + + std::unique_ptr impl(new Impl); + impl->localSystem = localSystemSid(); + impl->builtinAdmins = builtinAdminsSid(); + impl->owner = getOwnerSid(); + + for (auto &ea : impl->daclEntries) { + ea.grfAccessPermissions = GENERIC_ALL; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + } + impl->daclEntries[0].Trustee.ptstrName = + reinterpret_cast(impl->localSystem.get()); + impl->daclEntries[1].Trustee.ptstrName = + reinterpret_cast(impl->builtinAdmins.get()); + impl->daclEntries[2].Trustee.ptstrName = + reinterpret_cast(impl->owner.get()); + + impl->value = finishSecurityDescriptor( + impl->daclEntries.size(), + impl->daclEntries.data(), + impl->dacl); + + const auto retValue = impl->value.get(); + return SecurityDescriptor(retValue, std::move(impl)); +} + +SecurityDescriptor +createPipeSecurityDescriptorOwnerFullControlEveryoneWrite() { + + struct Impl : SecurityDescriptor::Impl { + Sid localSystem; + Sid builtinAdmins; + Sid owner; + Sid everyone; + std::array daclEntries = {}; + Acl dacl; + SecurityDescriptor value; + }; + + std::unique_ptr impl(new Impl); + impl->localSystem = localSystemSid(); + impl->builtinAdmins = builtinAdminsSid(); + impl->owner = getOwnerSid(); + impl->everyone = everyoneSid(); + + for (auto &ea : impl->daclEntries) { + ea.grfAccessPermissions = GENERIC_ALL; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + } + impl->daclEntries[0].Trustee.ptstrName = + reinterpret_cast(impl->localSystem.get()); + impl->daclEntries[1].Trustee.ptstrName = + reinterpret_cast(impl->builtinAdmins.get()); + impl->daclEntries[2].Trustee.ptstrName = + reinterpret_cast(impl->owner.get()); + impl->daclEntries[3].Trustee.ptstrName = + reinterpret_cast(impl->everyone.get()); + // Avoid using FILE_GENERIC_WRITE because it includes FILE_APPEND_DATA, + // which is equal to FILE_CREATE_PIPE_INSTANCE. Instead, include all the + // flags that comprise FILE_GENERIC_WRITE, except for the one. + impl->daclEntries[3].grfAccessPermissions = + FILE_GENERIC_READ | + FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA | + STANDARD_RIGHTS_WRITE | SYNCHRONIZE; + + impl->value = finishSecurityDescriptor( + impl->daclEntries.size(), + impl->daclEntries.data(), + impl->dacl); + + const auto retValue = impl->value.get(); + return SecurityDescriptor(retValue, std::move(impl)); +} + +SecurityDescriptor getObjectSecurityDescriptor(HANDLE handle) { + PACL dacl = nullptr; + PSECURITY_DESCRIPTOR sd = nullptr; + const DWORD errCode = GetSecurityInfo(handle, SE_KERNEL_OBJECT, + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION, + nullptr, nullptr, &dacl, nullptr, &sd); + if (errCode != ERROR_SUCCESS) { + throwWindowsError(L"GetSecurityInfo failed"); + } + return localItem(sd); +} + +// The (SID/SD)<->string conversion APIs are useful for testing/debugging, so +// create convenient accessor functions for them. They're too slow for +// ordinary use. The APIs exist in XP and up, but the MinGW headers only +// declare the SID<->string APIs, not the SD APIs. MinGW also gets the +// prototype wrong for ConvertStringSidToSidW (LPWSTR instead of LPCWSTR) and +// requires WINVER to be defined. MSVC and MinGW-w64 get everything right, but +// for consistency, use LoadLibrary/GetProcAddress for all four APIs. + +typedef BOOL WINAPI ConvertStringSidToSidW_t( + LPCWSTR StringSid, + PSID *Sid); + +typedef BOOL WINAPI ConvertSidToStringSidW_t( + PSID Sid, + LPWSTR *StringSid); + +typedef BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW_t( + LPCWSTR StringSecurityDescriptor, + DWORD StringSDRevision, + PSECURITY_DESCRIPTOR *SecurityDescriptor, + PULONG SecurityDescriptorSize); + +typedef BOOL WINAPI ConvertSecurityDescriptorToStringSecurityDescriptorW_t( + PSECURITY_DESCRIPTOR SecurityDescriptor, + DWORD RequestedStringSDRevision, + SECURITY_INFORMATION SecurityInformation, + LPWSTR *StringSecurityDescriptor, + PULONG StringSecurityDescriptorLen); + +#define GET_MODULE_PROC(mod, funcName) \ + const auto p##funcName = \ + reinterpret_cast( \ + mod.proc(#funcName)); \ + if (p##funcName == nullptr) { \ + throwWinptyException( \ + L"" L ## #funcName L" API is missing from ADVAPI32.DLL"); \ + } + +const DWORD kSDDL_REVISION_1 = 1; + +std::wstring sidToString(PSID sid) { + OsModule advapi32(L"advapi32.dll"); + GET_MODULE_PROC(advapi32, ConvertSidToStringSidW); + wchar_t *sidString = NULL; + BOOL success = pConvertSidToStringSidW(sid, &sidString); + if (!success) { + throwWindowsError(L"ConvertSidToStringSidW failed"); + } + PointerLocal freer(sidString); + return std::wstring(sidString); +} + +Sid stringToSid(const std::wstring &str) { + // Cast the string from const wchar_t* to LPWSTR because the function is + // incorrectly prototyped in the MinGW sddl.h header. The API does not + // modify the string -- it is correctly prototyped as taking LPCWSTR in + // MinGW-w64, MSVC, and MSDN. + OsModule advapi32(L"advapi32.dll"); + GET_MODULE_PROC(advapi32, ConvertStringSidToSidW); + PSID psid = nullptr; + BOOL success = pConvertStringSidToSidW(const_cast(str.c_str()), + &psid); + if (!success) { + const auto err = GetLastError(); + throwWindowsError( + (std::wstring(L"ConvertStringSidToSidW failed on \"") + + str + L'"').c_str(), + err); + } + return localItem(psid); +} + +SecurityDescriptor stringToSd(const std::wstring &str) { + OsModule advapi32(L"advapi32.dll"); + GET_MODULE_PROC(advapi32, ConvertStringSecurityDescriptorToSecurityDescriptorW); + PSECURITY_DESCRIPTOR desc = nullptr; + if (!pConvertStringSecurityDescriptorToSecurityDescriptorW( + str.c_str(), kSDDL_REVISION_1, &desc, nullptr)) { + const auto err = GetLastError(); + throwWindowsError( + (std::wstring(L"ConvertStringSecurityDescriptorToSecurityDescriptorW failed on \"") + + str + L'"').c_str(), + err); + } + return localItem(desc); +} + +std::wstring sdToString(PSECURITY_DESCRIPTOR sd) { + OsModule advapi32(L"advapi32.dll"); + GET_MODULE_PROC(advapi32, ConvertSecurityDescriptorToStringSecurityDescriptorW); + wchar_t *sdString = nullptr; + if (!pConvertSecurityDescriptorToStringSecurityDescriptorW( + sd, + kSDDL_REVISION_1, + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION, + &sdString, + nullptr)) { + throwWindowsError( + L"ConvertSecurityDescriptorToStringSecurityDescriptor failed"); + } + PointerLocal freer(sdString); + return std::wstring(sdString); +} + +// Vista added a useful flag to CreateNamedPipe, PIPE_REJECT_REMOTE_CLIENTS, +// that rejects remote connections. Return this flag on Vista, or return 0 +// otherwise. +DWORD rejectRemoteClientsPipeFlag() { + if (isAtLeastWindowsVista()) { + // MinGW lacks this flag; MinGW-w64 has it. + const DWORD kPIPE_REJECT_REMOTE_CLIENTS = 8; + return kPIPE_REJECT_REMOTE_CLIENTS; + } else { + trace("Omitting PIPE_REJECT_REMOTE_CLIENTS on pre-Vista OS"); + return 0; + } +} + +typedef BOOL WINAPI GetNamedPipeClientProcessId_t( + HANDLE Pipe, + PULONG ClientProcessId); + +std::tuple +getNamedPipeClientProcessId(HANDLE serverPipe) { + OsModule kernel32(L"kernel32.dll"); + const auto pGetNamedPipeClientProcessId = + reinterpret_cast( + kernel32.proc("GetNamedPipeClientProcessId")); + if (pGetNamedPipeClientProcessId == nullptr) { + return std::make_tuple( + GetNamedPipeClientProcessId_Result::UnsupportedOs, 0, 0); + } + ULONG pid = 0; + if (!pGetNamedPipeClientProcessId(serverPipe, &pid)) { + return std::make_tuple( + GetNamedPipeClientProcessId_Result::Failure, 0, GetLastError()); + } + return std::make_tuple( + GetNamedPipeClientProcessId_Result::Success, + static_cast(pid), + 0); +} diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h new file mode 100644 index 00000000000..5f9d53aff6d --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WindowsSecurity.h @@ -0,0 +1,104 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_WINDOWS_SECURITY_H +#define WINPTY_WINDOWS_SECURITY_H + +#include +#include + +#include +#include +#include +#include + +// PSID and PSECURITY_DESCRIPTOR are both pointers to void, but we want +// Sid and SecurityDescriptor to be different types. +struct SidTag { typedef PSID type; }; +struct AclTag { typedef PACL type; }; +struct SecurityDescriptorTag { typedef PSECURITY_DESCRIPTOR type; }; + +template +class SecurityItem { +public: + struct Impl { + virtual ~Impl() {} + }; + +private: + typedef typename T::type P; + P m_v; + std::unique_ptr m_pimpl; + +public: + P get() const { return m_v; } + operator bool() const { return m_v != nullptr; } + + SecurityItem() : m_v(nullptr) {} + SecurityItem(P v, std::unique_ptr &&pimpl) : + m_v(v), m_pimpl(std::move(pimpl)) {} + SecurityItem(SecurityItem &&other) : + m_v(other.m_v), m_pimpl(std::move(other.m_pimpl)) { + other.m_v = nullptr; + } + SecurityItem &operator=(SecurityItem &&other) { + m_v = other.m_v; + other.m_v = nullptr; + m_pimpl = std::move(other.m_pimpl); + return *this; + } +}; + +typedef SecurityItem Sid; +typedef SecurityItem Acl; +typedef SecurityItem SecurityDescriptor; + +Sid getOwnerSid(); +Sid wellKnownSid( + const wchar_t *debuggingName, + SID_IDENTIFIER_AUTHORITY authority, + BYTE authorityCount, + DWORD subAuthority0=0, + DWORD subAuthority1=0); +Sid builtinAdminsSid(); +Sid localSystemSid(); +Sid everyoneSid(); + +SecurityDescriptor createPipeSecurityDescriptorOwnerFullControl(); +SecurityDescriptor createPipeSecurityDescriptorOwnerFullControlEveryoneWrite(); +SecurityDescriptor getObjectSecurityDescriptor(HANDLE handle); + +std::wstring sidToString(PSID sid); +Sid stringToSid(const std::wstring &str); +SecurityDescriptor stringToSd(const std::wstring &str); +std::wstring sdToString(PSECURITY_DESCRIPTOR sd); + +DWORD rejectRemoteClientsPipeFlag(); + +enum class GetNamedPipeClientProcessId_Result { + Success, + Failure, + UnsupportedOs, +}; + +std::tuple +getNamedPipeClientProcessId(HANDLE serverPipe); + +#endif // WINPTY_WINDOWS_SECURITY_H diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc new file mode 100644 index 00000000000..d89b00d8382 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.cc @@ -0,0 +1,252 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "WindowsVersion.h" + +#include +#include + +#include +#include +#include + +#include "DebugClient.h" +#include "OsModule.h" +#include "StringBuilder.h" +#include "StringUtil.h" +#include "WinptyAssert.h" +#include "WinptyException.h" + +namespace { + +typedef std::tuple Version; + +// This function can only return a version up to 6.2 unless the executable is +// manifested for a newer version of Windows. See the MSDN documentation for +// GetVersionEx. +OSVERSIONINFOEX getWindowsVersionInfo() { + // Allow use of deprecated functions (i.e. GetVersionEx). We need to use + // GetVersionEx for the old MinGW toolchain and with MSVC when it targets XP. + // Having two code paths makes code harder to test, and it's not obvious how + // to detect the presence of a new enough SDK. (Including ntverp.h and + // examining VER_PRODUCTBUILD apparently works, but even then, MinGW-w64 and + // MSVC seem to use different version numbers.) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4996) +#endif + OSVERSIONINFOEX info = {}; + info.dwOSVersionInfoSize = sizeof(info); + const auto success = GetVersionEx(reinterpret_cast(&info)); + ASSERT(success && "GetVersionEx failed"); + return info; +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} + +Version getWindowsVersion() { + const auto info = getWindowsVersionInfo(); + return Version(info.dwMajorVersion, info.dwMinorVersion); +} + +struct ModuleNotFound : WinptyException { + virtual const wchar_t *what() const WINPTY_NOEXCEPT override { + return L"ModuleNotFound"; + } +}; + +// Throws WinptyException on error. +std::wstring getSystemDirectory() { + wchar_t systemDirectory[MAX_PATH]; + const UINT size = GetSystemDirectoryW(systemDirectory, MAX_PATH); + if (size == 0) { + throwWindowsError(L"GetSystemDirectory failed"); + } else if (size >= MAX_PATH) { + throwWinptyException( + L"GetSystemDirectory: path is longer than MAX_PATH"); + } + return systemDirectory; +} + +#define GET_VERSION_DLL_API(name) \ + const auto p ## name = \ + reinterpret_cast( \ + versionDll.proc(#name)); \ + if (p ## name == nullptr) { \ + throwWinptyException(L ## #name L" is missing"); \ + } + +// Throws WinptyException on error. +VS_FIXEDFILEINFO getFixedFileInfo(const std::wstring &path) { + // version.dll is not a conventional KnownDll, so if we link to it, there's + // a danger of accidentally loading a malicious DLL. In a more typical + // application, perhaps we'd guard against this security issue by + // controlling which directories this code runs in (e.g. *not* the + // "Downloads" directory), but that's harder for the winpty library. + OsModule versionDll( + (getSystemDirectory() + L"\\version.dll").c_str(), + OsModule::LoadErrorBehavior::Throw); + GET_VERSION_DLL_API(GetFileVersionInfoSizeW); + GET_VERSION_DLL_API(GetFileVersionInfoW); + GET_VERSION_DLL_API(VerQueryValueW); + DWORD size = pGetFileVersionInfoSizeW(path.c_str(), nullptr); + if (!size) { + // I see ERROR_FILE_NOT_FOUND on Win7 and + // ERROR_RESOURCE_DATA_NOT_FOUND on WinXP. + if (GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND) { + throw ModuleNotFound(); + } else { + throwWindowsError( + (L"GetFileVersionInfoSizeW failed on " + path).c_str()); + } + } + std::unique_ptr versionBuffer(new char[size]); + if (!pGetFileVersionInfoW(path.c_str(), 0, size, versionBuffer.get())) { + throwWindowsError((L"GetFileVersionInfoW failed on " + path).c_str()); + } + VS_FIXEDFILEINFO *versionInfo = nullptr; + UINT versionInfoSize = 0; + if (!pVerQueryValueW( + versionBuffer.get(), L"\\", + reinterpret_cast(&versionInfo), &versionInfoSize) || + versionInfo == nullptr || + versionInfoSize != sizeof(VS_FIXEDFILEINFO) || + versionInfo->dwSignature != 0xFEEF04BD) { + throwWinptyException((L"VerQueryValueW failed on " + path).c_str()); + } + return *versionInfo; +} + +uint64_t productVersionFromInfo(const VS_FIXEDFILEINFO &info) { + return (static_cast(info.dwProductVersionMS) << 32) | + (static_cast(info.dwProductVersionLS)); +} + +uint64_t fileVersionFromInfo(const VS_FIXEDFILEINFO &info) { + return (static_cast(info.dwFileVersionMS) << 32) | + (static_cast(info.dwFileVersionLS)); +} + +std::string versionToString(uint64_t version) { + StringBuilder b(32); + b << ((uint16_t)(version >> 48)); + b << '.'; + b << ((uint16_t)(version >> 32)); + b << '.'; + b << ((uint16_t)(version >> 16)); + b << '.'; + b << ((uint16_t)(version >> 0)); + return b.str_moved(); +} + +} // anonymous namespace + +// Returns true for Windows Vista (or Windows Server 2008) or newer. +bool isAtLeastWindowsVista() { + return getWindowsVersion() >= Version(6, 0); +} + +// Returns true for Windows 7 (or Windows Server 2008 R2) or newer. +bool isAtLeastWindows7() { + return getWindowsVersion() >= Version(6, 1); +} + +// Returns true for Windows 8 (or Windows Server 2012) or newer. +bool isAtLeastWindows8() { + return getWindowsVersion() >= Version(6, 2); +} + +#define WINPTY_IA32 1 +#define WINPTY_X64 2 + +#if defined(_M_IX86) || defined(__i386__) +#define WINPTY_ARCH WINPTY_IA32 +#elif defined(_M_X64) || defined(__x86_64__) +#define WINPTY_ARCH WINPTY_X64 +#endif + +typedef BOOL WINAPI IsWow64Process_t(HANDLE hProcess, PBOOL Wow64Process); + +void dumpWindowsVersion() { + if (!isTracingEnabled()) { + return; + } + const auto info = getWindowsVersionInfo(); + StringBuilder b; + b << info.dwMajorVersion << '.' << info.dwMinorVersion + << '.' << info.dwBuildNumber << ' ' + << "SP" << info.wServicePackMajor << '.' << info.wServicePackMinor + << ' '; + switch (info.wProductType) { + case VER_NT_WORKSTATION: b << "Client"; break; + case VER_NT_DOMAIN_CONTROLLER: b << "DomainController"; break; + case VER_NT_SERVER: b << "Server"; break; + default: + b << "product=" << info.wProductType; break; + } + b << ' '; +#if WINPTY_ARCH == WINPTY_IA32 + b << "IA32"; + OsModule kernel32(L"kernel32.dll"); + IsWow64Process_t *pIsWow64Process = + reinterpret_cast( + kernel32.proc("IsWow64Process")); + if (pIsWow64Process != nullptr) { + BOOL result = false; + const BOOL success = pIsWow64Process(GetCurrentProcess(), &result); + if (!success) { + b << " WOW64:error"; + } else if (success && result) { + b << " WOW64"; + } + } else { + b << " WOW64:missingapi"; + } +#elif WINPTY_ARCH == WINPTY_X64 + b << "X64"; +#endif + const auto dllVersion = [](const wchar_t *dllPath) -> std::string { + try { + const auto info = getFixedFileInfo(dllPath); + StringBuilder fb(64); + fb << utf8FromWide(dllPath) << ':'; + fb << "F:" << versionToString(fileVersionFromInfo(info)) << '/' + << "P:" << versionToString(productVersionFromInfo(info)); + return fb.str_moved(); + } catch (const ModuleNotFound&) { + return utf8FromWide(dllPath) + ":none"; + } catch (const WinptyException &e) { + trace("Error getting %s version: %s", + utf8FromWide(dllPath).c_str(), utf8FromWide(e.what()).c_str()); + return utf8FromWide(dllPath) + ":error"; + } + }; + b << ' ' << dllVersion(L"kernel32.dll"); + // ConEmu provides a DLL that hooks many Windows APIs, especially console + // APIs. Its existence and version number could be useful in debugging. +#if WINPTY_ARCH == WINPTY_IA32 + b << ' ' << dllVersion(L"ConEmuHk.dll"); +#elif WINPTY_ARCH == WINPTY_X64 + b << ' ' << dllVersion(L"ConEmuHk64.dll"); +#endif + trace("Windows version: %s", b.c_str()); +} diff --git a/src/libs/3rdparty/winpty/src/shared/WindowsVersion.h b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.h new file mode 100644 index 00000000000..a80798417eb --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WindowsVersion.h @@ -0,0 +1,29 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SHARED_WINDOWS_VERSION_H +#define WINPTY_SHARED_WINDOWS_VERSION_H + +bool isAtLeastWindowsVista(); +bool isAtLeastWindows7(); +bool isAtLeastWindows8(); +void dumpWindowsVersion(); + +#endif // WINPTY_SHARED_WINDOWS_VERSION_H diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc new file mode 100644 index 00000000000..1ff0de475ab --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "WinptyAssert.h" + +#include +#include + +#include "DebugClient.h" + +void assertTrace(const char *file, int line, const char *cond) { + trace("Assertion failed: %s, file %s, line %d", + cond, file, line); +} + +#ifdef WINPTY_AGENT_ASSERT + +void agentShutdown() { + HWND hwnd = GetConsoleWindow(); + if (hwnd != NULL) { + PostMessage(hwnd, WM_CLOSE, 0, 0); + Sleep(30000); + trace("Agent shutdown: WM_CLOSE did not end agent process"); + } else { + trace("Agent shutdown: GetConsoleWindow() is NULL"); + } + // abort() prints a message to the console, and if it is frozen, then the + // process would hang, so instead use exit(). (We shouldn't ever get here, + // though, because the WM_CLOSE message should have ended this process.) + exit(1); +} + +void agentAssertFail(const char *file, int line, const char *cond) { + assertTrace(file, line, cond); + agentShutdown(); +} + +#endif diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyAssert.h b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.h new file mode 100644 index 00000000000..b2b8b5e64c6 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WinptyAssert.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011-2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_ASSERT_H +#define WINPTY_ASSERT_H + +#ifdef WINPTY_AGENT_ASSERT + +void agentShutdown(); +void agentAssertFail(const char *file, int line, const char *cond); + +// Calling the standard assert() function does not work in the agent because +// the error message would be printed to the console, and the only way the +// user can see the console is via a working agent! Moreover, the console may +// be frozen, so attempting to write to it would block forever. This custom +// assert function instead sends the message to the DebugServer, then attempts +// to close the console, then quietly exits. +#define ASSERT(cond) \ + do { \ + if (!(cond)) { \ + agentAssertFail(__FILE__, __LINE__, #cond); \ + } \ + } while(0) + +#else + +void assertTrace(const char *file, int line, const char *cond); + +// In the other targets, log the assert failure to the debugserver, then fail +// using the ordinary assert mechanism. In case assert is compiled out, fail +// using abort. The amount of code inlined is unfortunate, but asserts aren't +// used much outside the agent. +#include +#include +#define ASSERT_CONDITION(cond) (false && (cond)) +#define ASSERT(cond) \ + do { \ + if (!(cond)) { \ + assertTrace(__FILE__, __LINE__, #cond); \ + assert(ASSERT_CONDITION(#cond)); \ + abort(); \ + } \ + } while(0) + +#endif + +#endif // WINPTY_ASSERT_H diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyException.cc b/src/libs/3rdparty/winpty/src/shared/WinptyException.cc new file mode 100644 index 00000000000..d0d48823d22 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WinptyException.cc @@ -0,0 +1,57 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "WinptyException.h" + +#include +#include + +#include "StringBuilder.h" + +namespace { + +class ExceptionImpl : public WinptyException { +public: + ExceptionImpl(const wchar_t *what) : + m_what(std::make_shared(what)) {} + virtual const wchar_t *what() const WINPTY_NOEXCEPT override { + return m_what->c_str(); + } +private: + // Using a shared_ptr ensures that copying the object raises no exception. + std::shared_ptr m_what; +}; + +} // anonymous namespace + +void throwWinptyException(const wchar_t *what) { + throw ExceptionImpl(what); +} + +void throwWindowsError(const wchar_t *prefix, DWORD errorCode) { + WStringBuilder sb(64); + if (prefix != nullptr) { + sb << prefix << L": "; + } + // It might make sense to use FormatMessage here, but IIRC, its API is hard + // to figure out. + sb << L"Windows error " << errorCode; + throwWinptyException(sb.c_str()); +} diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyException.h b/src/libs/3rdparty/winpty/src/shared/WinptyException.h new file mode 100644 index 00000000000..ec353369e5b --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WinptyException.h @@ -0,0 +1,43 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_EXCEPTION_H +#define WINPTY_EXCEPTION_H + +#include + +#if defined(__GNUC__) +#define WINPTY_NOEXCEPT noexcept +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +#define WINPTY_NOEXCEPT noexcept +#else +#define WINPTY_NOEXCEPT +#endif + +class WinptyException { +public: + virtual const wchar_t *what() const WINPTY_NOEXCEPT = 0; + virtual ~WinptyException() {} +}; + +void throwWinptyException(const wchar_t *what); +void throwWindowsError(const wchar_t *prefix, DWORD error=GetLastError()); + +#endif // WINPTY_EXCEPTION_H diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc new file mode 100644 index 00000000000..76bb8a584d2 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "WinptyVersion.h" + +#include +#include + +#include "DebugClient.h" + +// This header is auto-generated by either the Makefile (Unix) or +// UpdateGenVersion.bat (gyp). It is placed in a 'gen' directory, which is +// added to the search path. +#include "GenVersion.h" + +void dumpVersionToStdout() { + printf("winpty version %s\n", GenVersion_Version); + printf("commit %s\n", GenVersion_Commit); +} + +void dumpVersionToTrace() { + trace("winpty version %s (commit %s)", + GenVersion_Version, + GenVersion_Commit); +} diff --git a/src/libs/3rdparty/winpty/src/shared/WinptyVersion.h b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.h new file mode 100644 index 00000000000..e6224d7b847 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/WinptyVersion.h @@ -0,0 +1,27 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_VERSION_H +#define WINPTY_VERSION_H + +void dumpVersionToStdout(); +void dumpVersionToTrace(); + +#endif // WINPTY_VERSION_H diff --git a/src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h b/src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h new file mode 100644 index 00000000000..e716f245e8c --- /dev/null +++ b/src/libs/3rdparty/winpty/src/shared/winpty_snprintf.h @@ -0,0 +1,99 @@ +// Copyright (c) 2016 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef WINPTY_SNPRINTF_H +#define WINPTY_SNPRINTF_H + +#include +#include +#include + +#include "WinptyAssert.h" + +#if defined(__CYGWIN__) || defined(__MSYS__) +#define WINPTY_SNPRINTF_FORMAT(fmtarg, vararg) \ + __attribute__((format(printf, (fmtarg), ((vararg))))) +#elif defined(__GNUC__) +#define WINPTY_SNPRINTF_FORMAT(fmtarg, vararg) \ + __attribute__((format(ms_printf, (fmtarg), ((vararg))))) +#else +#define WINPTY_SNPRINTF_FORMAT(fmtarg, vararg) +#endif + +// Returns a value between 0 and size - 1 (inclusive) on success. Returns -1 +// on failure (including truncation). The output buffer is always +// NUL-terminated. +inline int +winpty_vsnprintf(char *out, size_t size, const char *fmt, va_list ap) { + ASSERT(size > 0); + out[0] = '\0'; +#if defined(_MSC_VER) && _MSC_VER < 1900 + // MSVC 2015 added a C99-conforming vsnprintf. + int count = _vsnprintf_s(out, size, _TRUNCATE, fmt, ap); +#else + // MinGW configurations frequently provide a vsnprintf function that simply + // calls one of the MS _vsnprintf* functions, which are not C99 conformant. + int count = vsnprintf(out, size, fmt, ap); +#endif + if (count < 0 || static_cast(count) >= size) { + // On truncation, some *printf* implementations return the + // non-truncated size, but other implementations returns -1. Return + // -1 for consistency. + count = -1; + // Guarantee NUL termination. + out[size - 1] = '\0'; + } else { + // Guarantee NUL termination. + out[count] = '\0'; + } + return count; +} + +// Wraps winpty_vsnprintf. +inline int winpty_snprintf(char *out, size_t size, const char *fmt, ...) + WINPTY_SNPRINTF_FORMAT(3, 4); +inline int winpty_snprintf(char *out, size_t size, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + const int count = winpty_vsnprintf(out, size, fmt, ap); + va_end(ap); + return count; +} + +// Wraps winpty_vsnprintf with automatic size determination. +template +int winpty_vsnprintf(char (&out)[size], const char *fmt, va_list ap) { + return winpty_vsnprintf(out, size, fmt, ap); +} + +// Wraps winpty_vsnprintf with automatic size determination. +template +int winpty_snprintf(char (&out)[size], const char *fmt, ...) + WINPTY_SNPRINTF_FORMAT(2, 3); +template +int winpty_snprintf(char (&out)[size], const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + const int count = winpty_vsnprintf(out, size, fmt, ap); + va_end(ap); + return count; +} + +#endif // WINPTY_SNPRINTF_H diff --git a/src/libs/3rdparty/winpty/src/subdir.mk b/src/libs/3rdparty/winpty/src/subdir.mk new file mode 100644 index 00000000000..9ae8031b084 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/subdir.mk @@ -0,0 +1,5 @@ +include src/agent/subdir.mk +include src/debugserver/subdir.mk +include src/libwinpty/subdir.mk +include src/tests/subdir.mk +include src/unix-adapter/subdir.mk diff --git a/src/libs/3rdparty/winpty/src/tests/subdir.mk b/src/libs/3rdparty/winpty/src/tests/subdir.mk new file mode 100644 index 00000000000..18799c4a5a0 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/tests/subdir.mk @@ -0,0 +1,28 @@ +# Copyright (c) 2015 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +build/%.exe : src/tests/%.cc build/winpty.dll + $(info Building $@) + @$(MINGW_CXX) $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS) -o $@ $^ + +TEST_PROGRAMS = \ + build/trivial_test.exe + +-include $(TEST_PROGRAMS:.exe=.d) diff --git a/src/libs/3rdparty/winpty/src/tests/trivial_test.cc b/src/libs/3rdparty/winpty/src/tests/trivial_test.cc new file mode 100644 index 00000000000..2188a4befb1 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/tests/trivial_test.cc @@ -0,0 +1,158 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include + +#include +#include +#include +#include +#include +#include + +#include "../include/winpty.h" +#include "../shared/DebugClient.h" + +static std::vector filterContent( + const std::vector &content) { + std::vector result; + auto it = content.begin(); + const auto itEnd = content.end(); + while (it < itEnd) { + if (*it == '\r') { + // Filter out carriage returns. Sometimes the output starts with + // a single CR; other times, it has multiple CRs. + it++; + } else if (*it == '\x1b' && (it + 1) < itEnd && *(it + 1) == '[') { + // Filter out escape sequences. They have no interior letters and + // end with a single letter. + it += 2; + while (it < itEnd && !isalpha(*it)) { + it++; + } + it++; + } else { + // Let everything else through. + result.push_back(*it); + it++; + } + } + return result; +} + +// Read bytes from the non-overlapped file handle until the file is closed or +// until an I/O error occurs. +static std::vector readAll(HANDLE handle) { + unsigned char buf[1024]; + std::vector result; + while (true) { + DWORD amount = 0; + BOOL ret = ReadFile(handle, buf, sizeof(buf), &amount, nullptr); + if (!ret || amount == 0) { + break; + } + result.insert(result.end(), buf, buf + amount); + } + return result; +} + +static void parentTest() { + wchar_t program[1024]; + wchar_t cmdline[1024]; + GetModuleFileNameW(nullptr, program, 1024); + + { + // XXX: We'd like to use swprintf, which is part of C99 and takes a + // size_t maxlen argument. MinGW-w64 has this function, as does MSVC. + // The old MinGW doesn't, though -- instead, it apparently provides an + // swprintf taking no maxlen argument. This *might* be a regression? + // (There is also no swnprintf, but that function is obsolescent with a + // correct swprintf, and it isn't in POSIX or ISO C.) + // + // Visual C++ 6 also provided this non-conformant swprintf, and I'm + // guessing MSVCRT.DLL does too. (My impression is that the old MinGW + // prefers to rely on MSVCRT.DLL for convenience?) + // + // I could compile differently for old MinGW, but what if it fixes its + // function later? Instead, use a workaround. It's starting to make + // sense to drop MinGW support in favor of MinGW-w64. This is too + // annoying. + // + // grepbait: OLD-MINGW / WINPTY_TARGET_MSYS1 + cmdline[0] = L'\0'; + wcscat(cmdline, L"\""); + wcscat(cmdline, program); + wcscat(cmdline, L"\" CHILD"); + } + // swnprintf(cmdline, sizeof(cmdline) / sizeof(cmdline[0]), + // L"\"%ls\" CHILD", program); + + auto agentCfg = winpty_config_new(0, nullptr); + assert(agentCfg != nullptr); + auto pty = winpty_open(agentCfg, nullptr); + assert(pty != nullptr); + winpty_config_free(agentCfg); + + HANDLE conin = CreateFileW( + winpty_conin_name(pty), + GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); + HANDLE conout = CreateFileW( + winpty_conout_name(pty), + GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr); + assert(conin != INVALID_HANDLE_VALUE); + assert(conout != INVALID_HANDLE_VALUE); + + auto spawnCfg = winpty_spawn_config_new( + WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, program, cmdline, + nullptr, nullptr, nullptr); + assert(spawnCfg != nullptr); + HANDLE process = nullptr; + BOOL spawnSuccess = winpty_spawn( + pty, spawnCfg, &process, nullptr, nullptr, nullptr); + assert(spawnSuccess && process != nullptr); + + auto content = readAll(conout); + content = filterContent(content); + + std::vector expectedContent = { + 'H', 'I', '\n', 'X', 'Y', '\n' + }; + DWORD exitCode = 0; + assert(GetExitCodeProcess(process, &exitCode) && exitCode == 42); + CloseHandle(process); + CloseHandle(conin); + CloseHandle(conout); + assert(content == expectedContent); + winpty_free(pty); +} + +static void childTest() { + printf("HI\nXY\n"); + exit(42); +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + parentTest(); + } else { + childTest(); + } + return 0; +} diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc new file mode 100644 index 00000000000..39f1e096850 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "InputHandler.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "../shared/DebugClient.h" +#include "Util.h" +#include "WakeupFd.h" + +InputHandler::InputHandler( + HANDLE conin, int inputfd, WakeupFd &completionWakeup) : + m_conin(conin), + m_inputfd(inputfd), + m_completionWakeup(completionWakeup), + m_threadHasBeenJoined(false), + m_shouldShutdown(0), + m_threadCompleted(0) +{ + pthread_create(&m_thread, NULL, InputHandler::threadProcS, this); +} + +void InputHandler::shutdown() { + startShutdown(); + if (!m_threadHasBeenJoined) { + int ret = pthread_join(m_thread, NULL); + assert(ret == 0 && "pthread_join failed"); + m_threadHasBeenJoined = true; + } +} + +void InputHandler::threadProc() { + std::vector buffer(4096); + fd_set readfds; + FD_ZERO(&readfds); + while (true) { + // Handle shutdown. + m_wakeup.reset(); + if (m_shouldShutdown) { + trace("InputHandler: shutting down"); + break; + } + + // Block until data arrives. + { + const int max_fd = std::max(m_inputfd, m_wakeup.fd()); + FD_SET(m_inputfd, &readfds); + FD_SET(m_wakeup.fd(), &readfds); + selectWrapper("InputHandler", max_fd + 1, &readfds); + if (!FD_ISSET(m_inputfd, &readfds)) { + continue; + } + } + + const int numRead = read(m_inputfd, &buffer[0], buffer.size()); + if (numRead == -1 && errno == EINTR) { + // Apparently, this read is interrupted on Cygwin 1.7 by a SIGWINCH + // signal even though I set the SA_RESTART flag on the handler. + continue; + } + + // tty is closed, or the read failed for some unexpected reason. + if (numRead <= 0) { + trace("InputHandler: tty read failed: numRead=%d", numRead); + break; + } + + DWORD written = 0; + BOOL ret = WriteFile(m_conin, + &buffer[0], numRead, + &written, NULL); + if (!ret || written != static_cast(numRead)) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("InputHandler: pipe closed: written=%u", + static_cast(written)); + } else { + trace("InputHandler: write failed: " + "ret=%d lastError=0x%x numRead=%d written=%u", + ret, + static_cast(GetLastError()), + numRead, + static_cast(written)); + } + break; + } + } + m_threadCompleted = 1; + m_completionWakeup.set(); +} diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h new file mode 100644 index 00000000000..9c3f540d634 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/InputHandler.h @@ -0,0 +1,56 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNIX_ADAPTER_INPUT_HANDLER_H +#define UNIX_ADAPTER_INPUT_HANDLER_H + +#include +#include +#include + +#include "WakeupFd.h" + +// Connect a Cygwin blocking fd to winpty CONIN. +class InputHandler { +public: + InputHandler(HANDLE conin, int inputfd, WakeupFd &completionWakeup); + ~InputHandler() { shutdown(); } + bool isComplete() { return m_threadCompleted; } + void startShutdown() { m_shouldShutdown = 1; m_wakeup.set(); } + void shutdown(); + +private: + static void *threadProcS(void *pvthis) { + reinterpret_cast(pvthis)->threadProc(); + return NULL; + } + void threadProc(); + + HANDLE m_conin; + int m_inputfd; + pthread_t m_thread; + WakeupFd &m_completionWakeup; + WakeupFd m_wakeup; + bool m_threadHasBeenJoined; + volatile sig_atomic_t m_shouldShutdown; + volatile sig_atomic_t m_threadCompleted; +}; + +#endif // UNIX_ADAPTER_INPUT_HANDLER_H diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc new file mode 100644 index 00000000000..573b8adced3 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.cc @@ -0,0 +1,80 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "OutputHandler.h" + +#include +#include +#include +#include + +#include +#include + +#include "../shared/DebugClient.h" +#include "Util.h" +#include "WakeupFd.h" + +OutputHandler::OutputHandler( + HANDLE conout, int outputfd, WakeupFd &completionWakeup) : + m_conout(conout), + m_outputfd(outputfd), + m_completionWakeup(completionWakeup), + m_threadHasBeenJoined(false), + m_threadCompleted(0) +{ + pthread_create(&m_thread, NULL, OutputHandler::threadProcS, this); +} + +void OutputHandler::shutdown() { + if (!m_threadHasBeenJoined) { + int ret = pthread_join(m_thread, NULL); + assert(ret == 0 && "pthread_join failed"); + m_threadHasBeenJoined = true; + } +} + +void OutputHandler::threadProc() { + std::vector buffer(4096); + while (true) { + DWORD numRead = 0; + BOOL ret = ReadFile(m_conout, + &buffer[0], buffer.size(), + &numRead, NULL); + if (!ret || numRead == 0) { + if (!ret && GetLastError() == ERROR_BROKEN_PIPE) { + trace("OutputHandler: pipe closed: numRead=%u", + static_cast(numRead)); + } else { + trace("OutputHandler: read failed: " + "ret=%d lastError=0x%x numRead=%u", + ret, + static_cast(GetLastError()), + static_cast(numRead)); + } + break; + } + if (!writeAll(m_outputfd, &buffer[0], numRead)) { + break; + } + } + m_threadCompleted = 1; + m_completionWakeup.set(); +} diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h new file mode 100644 index 00000000000..48241c55387 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/OutputHandler.h @@ -0,0 +1,53 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNIX_ADAPTER_OUTPUT_HANDLER_H +#define UNIX_ADAPTER_OUTPUT_HANDLER_H + +#include +#include +#include + +#include "WakeupFd.h" + +// Connect winpty CONOUT/CONERR to a Cygwin blocking fd. +class OutputHandler { +public: + OutputHandler(HANDLE conout, int outputfd, WakeupFd &completionWakeup); + ~OutputHandler() { shutdown(); } + bool isComplete() { return m_threadCompleted; } + void shutdown(); + +private: + static void *threadProcS(void *pvthis) { + reinterpret_cast(pvthis)->threadProc(); + return NULL; + } + void threadProc(); + + HANDLE m_conout; + int m_outputfd; + pthread_t m_thread; + WakeupFd &m_completionWakeup; + bool m_threadHasBeenJoined; + volatile sig_atomic_t m_threadCompleted; +}; + +#endif // UNIX_ADAPTER_OUTPUT_HANDLER_H diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/Util.cc b/src/libs/3rdparty/winpty/src/unix-adapter/Util.cc new file mode 100644 index 00000000000..e13f84a5299 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/Util.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "Util.h" + +#include +#include +#include +#include +#include + +#include "../shared/DebugClient.h" + +// Write the entire buffer, restarting it as necessary. +bool writeAll(int fd, const void *buffer, size_t size) { + size_t written = 0; + while (written < size) { + int ret = write(fd, + reinterpret_cast(buffer) + written, + size - written); + if (ret == -1 && errno == EINTR) { + continue; + } + if (ret <= 0) { + trace("write failed: " + "fd=%d errno=%d size=%u written=%d ret=%d", + fd, + errno, + static_cast(size), + static_cast(written), + ret); + return false; + } + assert(static_cast(ret) <= size - written); + written += ret; + } + assert(written == size); + return true; +} + +bool writeStr(int fd, const char *str) { + return writeAll(fd, str, strlen(str)); +} + +void selectWrapper(const char *diagName, int nfds, fd_set *readfds) { + int ret = select(nfds, readfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EINTR) { + FD_ZERO(readfds); + return; + } +#ifdef WINPTY_TARGET_MSYS1 + // The select system call sometimes fails with EAGAIN instead of EINTR. + // This apparantly only happens with the old Cygwin fork "MSYS" used in + // the mingw.org project. select is not supposed to fail with EAGAIN, + // and EAGAIN does not make much sense as an error code. (The whole + // point of select is to block.) + if (errno == EAGAIN) { + trace("%s select returned EAGAIN: interpreting like EINTR", + diagName); + FD_ZERO(readfds); + return; + } +#endif + fprintf(stderr, "Internal error: %s select failed: " + "error %d", diagName, errno); + abort(); + } +} diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/Util.h b/src/libs/3rdparty/winpty/src/unix-adapter/Util.h new file mode 100644 index 00000000000..cadb4c82a96 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/Util.h @@ -0,0 +1,31 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNIX_ADAPTER_UTIL_H +#define UNIX_ADAPTER_UTIL_H + +#include +#include + +bool writeAll(int fd, const void *buffer, size_t size); +bool writeStr(int fd, const char *str); +void selectWrapper(const char *diagName, int nfds, fd_set *readfds); + +#endif // UNIX_ADAPTER_UTIL_H diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc new file mode 100644 index 00000000000..6b473790153 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "WakeupFd.h" + +#include +#include +#include +#include +#include + +static void setFdNonBlock(int fd) { + int status = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, status | O_NONBLOCK); +} + +WakeupFd::WakeupFd() { + int pipeFd[2]; + if (pipe(pipeFd) != 0) { + perror("Could not create internal wakeup pipe"); + abort(); + } + m_pipeReadFd = pipeFd[0]; + m_pipeWriteFd = pipeFd[1]; + setFdNonBlock(m_pipeReadFd); + setFdNonBlock(m_pipeWriteFd); +} + +WakeupFd::~WakeupFd() { + close(m_pipeReadFd); + close(m_pipeWriteFd); +} + +void WakeupFd::set() { + char dummy = 0; + int ret; + do { + ret = write(m_pipeWriteFd, &dummy, 1); + } while (ret < 0 && errno == EINTR); +} + +void WakeupFd::reset() { + char tmpBuf[256]; + while (true) { + int amount = read(m_pipeReadFd, tmpBuf, sizeof(tmpBuf)); + if (amount < 0 && errno == EAGAIN) { + break; + } else if (amount <= 0) { + perror("error reading from internal wakeup pipe"); + abort(); + } + } +} diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h new file mode 100644 index 00000000000..dd8d362aa10 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/WakeupFd.h @@ -0,0 +1,42 @@ +// Copyright (c) 2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef UNIX_ADAPTER_WAKEUP_FD_H +#define UNIX_ADAPTER_WAKEUP_FD_H + +class WakeupFd { +public: + WakeupFd(); + ~WakeupFd(); + int fd() { return m_pipeReadFd; } + void set(); + void reset(); + +private: + // Do not allow copying the WakeupFd object. + WakeupFd(const WakeupFd &other); + WakeupFd &operator=(const WakeupFd &other); + +private: + int m_pipeReadFd; + int m_pipeWriteFd; +}; + +#endif // UNIX_ADAPTER_WAKEUP_FD_H diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/main.cc b/src/libs/3rdparty/winpty/src/unix-adapter/main.cc new file mode 100644 index 00000000000..992cb70e449 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/main.cc @@ -0,0 +1,729 @@ +// Copyright (c) 2011-2015 Ryan Prichard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// MSYS's sys/cygwin.h header only declares cygwin_internal if WINVER is +// defined, which is defined in windows.h. Therefore, include windows.h early. +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "../shared/DebugClient.h" +#include "../shared/UnixCtrlChars.h" +#include "../shared/WinptyVersion.h" +#include "InputHandler.h" +#include "OutputHandler.h" +#include "Util.h" +#include "WakeupFd.h" + +#define CSI "\x1b[" + +static WakeupFd *g_mainWakeup = NULL; + +static WakeupFd &mainWakeup() +{ + if (g_mainWakeup == NULL) { + static const char msg[] = "Internal error: g_mainWakeup is NULL\r\n"; + write(STDERR_FILENO, msg, sizeof(msg) - 1); + abort(); + } + return *g_mainWakeup; +} + +struct SavedTermiosMode { + int count; + bool valid[3]; + termios mode[3]; +}; + +// Put the input terminal into non-canonical mode. +static SavedTermiosMode setRawTerminalMode( + bool allowNonTtys, bool setStdout, bool setStderr) +{ + SavedTermiosMode ret; + const char *const kNames[3] = { "stdin", "stdout", "stderr" }; + + ret.valid[0] = true; + ret.valid[1] = setStdout; + ret.valid[2] = setStderr; + + for (int i = 0; i < 3; ++i) { + if (!ret.valid[i]) { + continue; + } + if (!isatty(i)) { + ret.valid[i] = false; + if (!allowNonTtys) { + fprintf(stderr, "%s is not a tty\n", kNames[i]); + exit(1); + } + } else { + ret.valid[i] = true; + if (tcgetattr(i, &ret.mode[i]) < 0) { + perror("tcgetattr failed"); + exit(1); + } + } + } + + if (ret.valid[STDIN_FILENO]) { + termios buf; + if (tcgetattr(STDIN_FILENO, &buf) < 0) { + perror("tcgetattr failed"); + exit(1); + } + buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + buf.c_cflag &= ~(CSIZE | PARENB); + buf.c_cflag |= CS8; + buf.c_cc[VMIN] = 1; // blocking read + buf.c_cc[VTIME] = 0; + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &buf) < 0) { + fprintf(stderr, "tcsetattr failed\n"); + exit(1); + } + } + + for (int i = STDOUT_FILENO; i <= STDERR_FILENO; ++i) { + if (!ret.valid[i]) { + continue; + } + termios buf; + if (tcgetattr(i, &buf) < 0) { + perror("tcgetattr failed"); + exit(1); + } + buf.c_cflag &= ~(CSIZE | PARENB); + buf.c_cflag |= CS8; + buf.c_oflag &= ~OPOST; + if (tcsetattr(i, TCSAFLUSH, &buf) < 0) { + fprintf(stderr, "tcsetattr failed\n"); + exit(1); + } + } + + return ret; +} + +static void restoreTerminalMode(const SavedTermiosMode &original) +{ + for (int i = 0; i < 3; ++i) { + if (!original.valid[i]) { + continue; + } + if (tcsetattr(i, TCSAFLUSH, &original.mode[i]) < 0) { + perror("error restoring terminal mode"); + exit(1); + } + } +} + +static void debugShowKey(bool allowNonTtys) +{ + printf("\nPress any keys -- Ctrl-D exits\n\n"); + const SavedTermiosMode saved = + setRawTerminalMode(allowNonTtys, false, false); + char buf[128]; + while (true) { + const ssize_t len = read(STDIN_FILENO, buf, sizeof(buf)); + if (len <= 0) { + break; + } + for (int i = 0; i < len; ++i) { + char ctrl = decodeUnixCtrlChar(buf[i]); + if (ctrl == '\0') { + putchar(buf[i]); + } else { + putchar('^'); + putchar(ctrl); + } + } + for (int i = 0; i < len; ++i) { + unsigned char uch = buf[i]; + printf("\t%3d %04o 0x%02x\n", uch, uch, uch); + fflush(stdout); + } + if (buf[0] == 4) { + // Ctrl-D + break; + } + } + restoreTerminalMode(saved); +} + +static void terminalResized(int signo) +{ + mainWakeup().set(); +} + +static void registerResizeSignalHandler() +{ + struct sigaction resizeSigAct; + memset(&resizeSigAct, 0, sizeof(resizeSigAct)); + resizeSigAct.sa_handler = terminalResized; + resizeSigAct.sa_flags = SA_RESTART; + sigaction(SIGWINCH, &resizeSigAct, NULL); +} + +// Convert the path to a Win32 path if it is a POSIX path, and convert slashes +// to backslashes. +static std::string convertPosixPathToWin(const std::string &path) +{ + char *tmp; +#if defined(CYGWIN_VERSION_CYGWIN_CONV) && \ + CYGWIN_VERSION_API_MINOR >= CYGWIN_VERSION_CYGWIN_CONV + // MSYS2 and versions of Cygwin released after 2009 or so use this API. + // The original MSYS still lacks this API. + ssize_t newSize = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, + path.c_str(), NULL, 0); + assert(newSize >= 0); + tmp = new char[newSize + 1]; + ssize_t success = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, + path.c_str(), tmp, newSize + 1); + assert(success == 0); +#else + // In the current Cygwin header file, this API is documented as deprecated + // because it's restricted to paths of MAX_PATH length. In the CVS version + // of MSYS, the newer API doesn't exist, and this older API is implemented + // using msys_p2w, which seems like it would handle paths larger than + // MAX_PATH, but there's no way to query how large the new path is. + // Hopefully, this is large enough. + tmp = new char[MAX_PATH + path.size()]; + cygwin_conv_to_win32_path(path.c_str(), tmp); +#endif + for (int i = 0; tmp[i] != '\0'; ++i) { + if (tmp[i] == '/') + tmp[i] = '\\'; + } + std::string ret(tmp); + delete [] tmp; + return ret; +} + +static std::string resolvePath(const std::string &path) +{ + char ret[PATH_MAX]; + ret[0] = '\0'; + if (realpath(path.c_str(), ret) != ret) { + return std::string(); + } + return ret; +} + +template +static bool endsWith(const std::string &path, const char (&suf)[N]) +{ + const size_t suffixLen = N - 1; + char actualSuf[N]; + if (path.size() < suffixLen) { + return false; + } + strcpy(actualSuf, &path.c_str()[path.size() - suffixLen]); + for (size_t i = 0; i < suffixLen; ++i) { + actualSuf[i] = tolower(actualSuf[i]); + } + return !strcmp(actualSuf, suf); +} + +static std::string findProgram( + const char *winptyProgName, + const std::string &prog) +{ + std::string candidate; + if (prog.find('/') == std::string::npos && + prog.find('\\') == std::string::npos) { + // XXX: It would be nice to use a lambda here (once/if old MSYS support + // is dropped). + // Search the PATH. + const char *const pathVar = getenv("PATH"); + const std::string pathList(pathVar ? pathVar : ""); + size_t elpos = 0; + while (true) { + const size_t elend = pathList.find(':', elpos); + candidate = pathList.substr(elpos, elend - elpos); + if (!candidate.empty() && *(candidate.end() - 1) != '/') { + candidate += '/'; + } + candidate += prog; + candidate = resolvePath(candidate); + if (!candidate.empty()) { + int perm = X_OK; + if (endsWith(candidate, ".bat") || endsWith(candidate, ".cmd")) { +#ifdef __MSYS__ + // In MSYS/MSYS2, batch files don't have the execute bit + // set, so just check that they're readable. + perm = R_OK; +#endif + } else if (endsWith(candidate, ".com") || endsWith(candidate, ".exe")) { + // Do nothing. + } else { + // Make the exe extension explicit so that we don't try to + // run shell scripts with CreateProcess/winpty_spawn. + candidate += ".exe"; + } + if (!access(candidate.c_str(), perm)) { + break; + } + } + if (elend == std::string::npos) { + fprintf(stderr, "%s: error: cannot start '%s': Not found in PATH\n", + winptyProgName, prog.c_str()); + exit(1); + } else { + elpos = elend + 1; + } + } + } else { + candidate = resolvePath(prog); + if (candidate.empty()) { + std::string errstr(strerror(errno)); + fprintf(stderr, "%s: error: cannot start '%s': %s\n", + winptyProgName, prog.c_str(), errstr.c_str()); + exit(1); + } + } + return convertPosixPathToWin(candidate); +} + +// Convert argc/argv into a Win32 command-line following the escaping convention +// documented on MSDN. (e.g. see CommandLineToArgvW documentation) +static std::string argvToCommandLine(const std::vector &argv) +{ + std::string result; + for (size_t argIndex = 0; argIndex < argv.size(); ++argIndex) { + if (argIndex > 0) + result.push_back(' '); + const char *arg = argv[argIndex].c_str(); + const bool quote = + strchr(arg, ' ') != NULL || + strchr(arg, '\t') != NULL || + *arg == '\0'; + if (quote) + result.push_back('\"'); + int bsCount = 0; + for (const char *p = arg; *p != '\0'; ++p) { + if (*p == '\\') { + bsCount++; + } else if (*p == '\"') { + result.append(bsCount * 2 + 1, '\\'); + result.push_back('\"'); + bsCount = 0; + } else { + result.append(bsCount, '\\'); + bsCount = 0; + result.push_back(*p); + } + } + if (quote) { + result.append(bsCount * 2, '\\'); + result.push_back('\"'); + } else { + result.append(bsCount, '\\'); + } + } + return result; +} + +static wchar_t *heapMbsToWcs(const char *text) +{ + // Calling mbstowcs with a NULL first argument seems to be broken on MSYS. + // Instead of returning the size of the converted string, it returns 0. + // Using strlen(text) * 2 is probably big enough. + size_t maxLen = strlen(text) * 2 + 1; + wchar_t *ret = new wchar_t[maxLen]; + size_t len = mbstowcs(ret, text, maxLen); + assert(len != (size_t)-1 && len < maxLen); + return ret; +} + +static char *heapWcsToMbs(const wchar_t *text) +{ + // Calling wcstombs with a NULL first argument seems to be broken on MSYS. + // Instead of returning the size of the converted string, it returns 0. + // Using wcslen(text) * 3 is big enough for UTF-8 and probably other + // encodings. For UTF-8, codepoints that fit in a single wchar + // (U+0000 to U+FFFF) are encoded using 1-3 bytes. The remaining code + // points needs two wchar's and are encoded using 4 bytes. + size_t maxLen = wcslen(text) * 3 + 1; + char *ret = new char[maxLen]; + size_t len = wcstombs(ret, text, maxLen); + if (len == (size_t)-1 || len >= maxLen) { + delete [] ret; + return NULL; + } else { + return ret; + } +} + +static std::string wcsToMbs(const wchar_t *text) +{ + std::string ret; + const char *ptr = heapWcsToMbs(text); + if (ptr != NULL) { + ret = ptr; + delete [] ptr; + } + return ret; +} + +void setupWin32Environment() +{ + std::map varsToCopy; + const char *vars[] = { + "WINPTY_DEBUG", + "WINPTY_SHOW_CONSOLE", + NULL + }; + for (int i = 0; vars[i] != NULL; ++i) { + const char *cstr = getenv(vars[i]); + if (cstr != NULL && cstr[0] != '\0') { + varsToCopy[vars[i]] = cstr; + } + } + +#if defined(__MSYS__) && CYGWIN_VERSION_API_MINOR >= 48 || \ + !defined(__MSYS__) && CYGWIN_VERSION_API_MINOR >= 153 + // Use CW_SYNC_WINENV to copy the Unix environment to the Win32 + // environment. The command performs special translation on some variables + // (such as PATH and TMP). It also copies the debugging environment + // variables. + // + // Note that the API minor versions have diverged in Cygwin and MSYS. + // CW_SYNC_WINENV was added to Cygwin in version 153. (Cygwin's + // include/cygwin/version.h says that CW_SETUP_WINENV was added in 153. + // The flag was renamed 8 days after it was added, but the API docs weren't + // updated.) The flag was added to MSYS in version 48. + // + // Also, in my limited testing, this call seems to be necessary with Cygwin + // but unnecessary with MSYS. Perhaps MSYS is automatically syncing the + // Unix environment with the Win32 environment before starting console.exe? + // It shouldn't hurt to call it for MSYS. + cygwin_internal(CW_SYNC_WINENV); +#endif + + // Copy debugging environment variables from the Cygwin environment + // to the Win32 environment so the agent will inherit it. + for (std::map::iterator it = varsToCopy.begin(); + it != varsToCopy.end(); + ++it) { + wchar_t *nameW = heapMbsToWcs(it->first.c_str()); + wchar_t *valueW = heapMbsToWcs(it->second.c_str()); + SetEnvironmentVariableW(nameW, valueW); + delete [] nameW; + delete [] valueW; + } + + // Clear the TERM variable. The child process's immediate console/terminal + // environment is a Windows console, not the terminal that winpty is + // communicating with. Leaving the TERM variable set can break programs in + // various ways. (e.g. arrows keys broken in Cygwin less, IronPython's + // help(...) function doesn't start, misc programs decide they should + // output color escape codes on pre-Win10). See + // https://github.com/rprichard/winpty/issues/43. + SetEnvironmentVariableW(L"TERM", NULL); +} + +static void usage(const char *program, int exitCode) +{ + printf("Usage: %s [options] [--] program [args]\n", program); + printf("\n"); + printf("Options:\n"); + printf(" -h, --help Show this help message\n"); + printf(" --mouse Enable terminal mouse input\n"); + printf(" --showkey Dump STDIN escape sequences\n"); + printf(" --version Show the winpty version number\n"); + exit(exitCode); +} + +struct Arguments { + std::vector childArgv; + bool mouseInput; + bool testAllowNonTtys; + bool testConerr; + bool testPlainOutput; + bool testColorEscapes; +}; + +static void parseArguments(int argc, char *argv[], Arguments &out) +{ + out.mouseInput = false; + out.testAllowNonTtys = false; + out.testConerr = false; + out.testPlainOutput = false; + out.testColorEscapes = false; + bool doShowKeys = false; + const char *const program = argc >= 1 ? argv[0] : ""; + int argi = 1; + while (argi < argc) { + std::string arg(argv[argi++]); + if (arg.size() >= 1 && arg[0] == '-') { + if (arg == "-h" || arg == "--help") { + usage(program, 0); + } else if (arg == "--mouse") { + out.mouseInput = true; + } else if (arg == "--showkey") { + doShowKeys = true; + } else if (arg == "--version") { + dumpVersionToStdout(); + exit(0); + } else if (arg == "-Xallow-non-tty") { + out.testAllowNonTtys = true; + } else if (arg == "-Xconerr") { + out.testConerr = true; + } else if (arg == "-Xplain") { + out.testPlainOutput = true; + } else if (arg == "-Xcolor") { + out.testColorEscapes = true; + } else if (arg == "--") { + break; + } else { + fprintf(stderr, "Error: unrecognized option: '%s'\n", + arg.c_str()); + exit(1); + } + } else { + out.childArgv.push_back(arg); + break; + } + } + for (; argi < argc; ++argi) { + out.childArgv.push_back(argv[argi]); + } + if (doShowKeys) { + debugShowKey(out.testAllowNonTtys); + exit(0); + } + if (out.childArgv.size() == 0) { + usage(program, 1); + } +} + +static std::string errorMessageToString(DWORD err) +{ + // Use FormatMessageW rather than FormatMessageA, because we want to use + // wcstombs to convert to the Cygwin locale, which might not match the + // codepage FormatMessageA would use. We need to convert using wcstombs, + // rather than print using %ls, because %ls doesn't work in the original + // MSYS. + wchar_t *wideMsgPtr = NULL; + const DWORD formatRet = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&wideMsgPtr), + 0, + NULL); + if (formatRet == 0 || wideMsgPtr == NULL) { + return std::string(); + } + std::string msg = wcsToMbs(wideMsgPtr); + LocalFree(wideMsgPtr); + const size_t pos = msg.find_last_not_of(" \r\n\t"); + if (pos == std::string::npos) { + msg.clear(); + } else { + msg.erase(pos + 1); + } + return msg; +} + +static std::string formatErrorMessage(DWORD err) +{ + char buf[64]; + sprintf(buf, "error %#x", static_cast(err)); + std::string ret = errorMessageToString(err); + if (ret.empty()) { + ret += buf; + } else { + ret += " ("; + ret += buf; + ret += ")"; + } + return ret; +} + +int main(int argc, char *argv[]) +{ + setlocale(LC_ALL, ""); + + g_mainWakeup = new WakeupFd(); + + Arguments args; + parseArguments(argc, argv, args); + + setupWin32Environment(); + + winsize sz = { 0 }; + sz.ws_col = 80; + sz.ws_row = 25; + ioctl(STDIN_FILENO, TIOCGWINSZ, &sz); + + DWORD agentFlags = WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION; + if (args.testConerr) { agentFlags |= WINPTY_FLAG_CONERR; } + if (args.testPlainOutput) { agentFlags |= WINPTY_FLAG_PLAIN_OUTPUT; } + if (args.testColorEscapes) { agentFlags |= WINPTY_FLAG_COLOR_ESCAPES; } + winpty_config_t *agentCfg = winpty_config_new(agentFlags, NULL); + assert(agentCfg != NULL); + winpty_config_set_initial_size(agentCfg, sz.ws_col, sz.ws_row); + if (args.mouseInput) { + winpty_config_set_mouse_mode(agentCfg, WINPTY_MOUSE_MODE_FORCE); + } + + winpty_error_ptr_t openErr = NULL; + winpty_t *wp = winpty_open(agentCfg, &openErr); + if (wp == NULL) { + fprintf(stderr, "Error creating winpty: %s\n", + wcsToMbs(winpty_error_msg(openErr)).c_str()); + exit(1); + } + winpty_config_free(agentCfg); + winpty_error_free(openErr); + + HANDLE conin = CreateFileW(winpty_conin_name(wp), GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + HANDLE conout = CreateFileW(winpty_conout_name(wp), GENERIC_READ, 0, NULL, + OPEN_EXISTING, 0, NULL); + assert(conin != INVALID_HANDLE_VALUE); + assert(conout != INVALID_HANDLE_VALUE); + HANDLE conerr = NULL; + if (args.testConerr) { + conerr = CreateFileW(winpty_conerr_name(wp), GENERIC_READ, 0, NULL, + OPEN_EXISTING, 0, NULL); + assert(conerr != INVALID_HANDLE_VALUE); + } + + HANDLE childHandle = NULL; + + { + // Start the child process under the console. + args.childArgv[0] = findProgram(argv[0], args.childArgv[0]); + std::string cmdLine = argvToCommandLine(args.childArgv); + wchar_t *cmdLineW = heapMbsToWcs(cmdLine.c_str()); + + winpty_spawn_config_t *spawnCfg = winpty_spawn_config_new( + WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, + NULL, cmdLineW, NULL, NULL, NULL); + assert(spawnCfg != NULL); + + winpty_error_ptr_t spawnErr = NULL; + DWORD lastError = 0; + BOOL spawnRet = winpty_spawn(wp, spawnCfg, &childHandle, NULL, + &lastError, &spawnErr); + winpty_spawn_config_free(spawnCfg); + + if (!spawnRet) { + winpty_result_t spawnCode = winpty_error_code(spawnErr); + if (spawnCode == WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED) { + fprintf(stderr, "%s: error: cannot start '%s': %s\n", + argv[0], + cmdLine.c_str(), + formatErrorMessage(lastError).c_str()); + } else { + fprintf(stderr, "%s: error: cannot start '%s': internal error: %s\n", + argv[0], + cmdLine.c_str(), + wcsToMbs(winpty_error_msg(spawnErr)).c_str()); + } + exit(1); + } + winpty_error_free(spawnErr); + delete [] cmdLineW; + } + + registerResizeSignalHandler(); + SavedTermiosMode mode = + setRawTerminalMode(args.testAllowNonTtys, true, args.testConerr); + + InputHandler inputHandler(conin, STDIN_FILENO, mainWakeup()); + OutputHandler outputHandler(conout, STDOUT_FILENO, mainWakeup()); + OutputHandler *errorHandler = NULL; + if (args.testConerr) { + errorHandler = new OutputHandler(conerr, STDERR_FILENO, mainWakeup()); + } + + while (true) { + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(mainWakeup().fd(), &readfds); + selectWrapper("main thread", mainWakeup().fd() + 1, &readfds); + mainWakeup().reset(); + + // Check for terminal resize. + { + winsize sz2; + ioctl(STDIN_FILENO, TIOCGWINSZ, &sz2); + if (memcmp(&sz, &sz2, sizeof(sz)) != 0) { + sz = sz2; + winpty_set_size(wp, sz.ws_col, sz.ws_row, NULL); + } + } + + // Check for an I/O handler shutting down (possibly indicating that the + // child process has exited). + if (inputHandler.isComplete() || outputHandler.isComplete() || + (errorHandler != NULL && errorHandler->isComplete())) { + break; + } + } + + // Kill the agent connection. This will kill the agent, closing the CONIN + // and CONOUT pipes on the agent pipe, prompting our I/O handler to shut + // down. + winpty_free(wp); + + inputHandler.shutdown(); + outputHandler.shutdown(); + CloseHandle(conin); + CloseHandle(conout); + + if (errorHandler != NULL) { + errorHandler->shutdown(); + delete errorHandler; + CloseHandle(conerr); + } + + restoreTerminalMode(mode); + + DWORD exitCode = 0; + if (!GetExitCodeProcess(childHandle, &exitCode)) { + exitCode = 1; + } + CloseHandle(childHandle); + return exitCode; +} diff --git a/src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk b/src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk new file mode 100644 index 00000000000..200193a1b15 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/unix-adapter/subdir.mk @@ -0,0 +1,41 @@ +# Copyright (c) 2011-2015 Ryan Prichard +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +ALL_TARGETS += build/$(UNIX_ADAPTER_EXE) + +$(eval $(call def_unix_target,unix-adapter,)) + +UNIX_ADAPTER_OBJECTS = \ + build/unix-adapter/unix-adapter/InputHandler.o \ + build/unix-adapter/unix-adapter/OutputHandler.o \ + build/unix-adapter/unix-adapter/Util.o \ + build/unix-adapter/unix-adapter/WakeupFd.o \ + build/unix-adapter/unix-adapter/main.o \ + build/unix-adapter/shared/DebugClient.o \ + build/unix-adapter/shared/WinptyAssert.o \ + build/unix-adapter/shared/WinptyVersion.o + +build/unix-adapter/shared/WinptyVersion.o : build/gen/GenVersion.h + +build/$(UNIX_ADAPTER_EXE) : $(UNIX_ADAPTER_OBJECTS) build/winpty.dll + $(info Linking $@) + @$(UNIX_CXX) $(UNIX_LDFLAGS) -o $@ $^ + +-include $(UNIX_ADAPTER_OBJECTS:.o=.d) diff --git a/src/libs/3rdparty/winpty/src/winpty.gyp b/src/libs/3rdparty/winpty/src/winpty.gyp new file mode 100644 index 00000000000..7ee68d55e60 --- /dev/null +++ b/src/libs/3rdparty/winpty/src/winpty.gyp @@ -0,0 +1,206 @@ +{ + # The MSVC generator is the default. Select the compiler version by + # passing -G msvs_version= to gyp. is a string like 2013e. + # See gyp\pylib\gyp\MSVSVersion.py for sample version strings. You + # can also pass configurations.gypi to gyp for 32-bit and 64-bit builds. + # See that file for details. + # + # Pass --format=make to gyp to generate a Makefile instead. The Makefile + # can be configured by passing variables to make, e.g.: + # make -j4 CXX=i686-w64-mingw32-g++ LDFLAGS="-static -static-libgcc -static-libstdc++" + + 'variables': { + 'WINPTY_COMMIT_HASH%': ' Date: Wed, 22 Feb 2023 14:35:18 +0100 Subject: [PATCH 0076/1447] Copilot: Merge copilotoptionspagewidget.{h,cpp} into copilotoptionspage.cpp Too small to be worth a translation unit. Also drop unnecessary Q_OBJECT. Change-Id: Ife1bce6498eae81e2979c2798f8d4f19da16a11d Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/CMakeLists.txt | 1 - src/plugins/copilot/copilot.qbs | 2 -- src/plugins/copilot/copilotoptionspage.cpp | 30 +++++++++++++++- .../copilot/copilotoptionspagewidget.cpp | 36 ------------------- .../copilot/copilotoptionspagewidget.h | 16 --------- 5 files changed, 29 insertions(+), 56 deletions(-) delete mode 100644 src/plugins/copilot/copilotoptionspagewidget.cpp delete mode 100644 src/plugins/copilot/copilotoptionspagewidget.h diff --git a/src/plugins/copilot/CMakeLists.txt b/src/plugins/copilot/CMakeLists.txt index 81e0cd34934..2f4cfd3007b 100644 --- a/src/plugins/copilot/CMakeLists.txt +++ b/src/plugins/copilot/CMakeLists.txt @@ -7,7 +7,6 @@ add_qtc_plugin(Copilot copilotclient.cpp copilotclient.h copilotsettings.cpp copilotsettings.h copilotoptionspage.cpp copilotoptionspage.h - copilotoptionspagewidget.cpp copilotoptionspagewidget.h documentwatcher.cpp documentwatcher.h requests/getcompletions.h requests/checkstatus.h diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs index e6a537a387e..e8813607ac6 100644 --- a/src/plugins/copilot/copilot.qbs +++ b/src/plugins/copilot/copilot.qbs @@ -19,8 +19,6 @@ QtcPlugin { "copilotsettings.h", "copilotoptionspage.cpp", "copilotoptionspage.h", - "copilotoptionspagewidget.cpp", - "copilotoptionspagewidget.h", "documentwatcher.cpp", "documentwatcher.h", "requests/getcompletions.h", diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index 67866fe8794..6fb49ef43c8 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -3,13 +3,41 @@ #include "copilotoptionspage.h" -#include "copilotoptionspagewidget.h" +#include "authwidget.h" +#include "copilotsettings.h" #include "copilotsettings.h" #include +#include +#include + +using namespace Utils; +using namespace LanguageClient; + namespace Copilot { +class CopilotOptionsPageWidget : public QWidget +{ +public: + CopilotOptionsPageWidget(QWidget *parent = nullptr) + : QWidget(parent) + { + using namespace Layouting; + + auto authWidget = new AuthWidget(); + + // clang-format off + Column { + authWidget, br, + CopilotSettings::instance().nodeJsPath, br, + CopilotSettings::instance().distPath, br, + st + }.attachTo(this); + // clang-format on + } +}; + CopilotOptionsPage::CopilotOptionsPage() { setId("Copilot.General"); diff --git a/src/plugins/copilot/copilotoptionspagewidget.cpp b/src/plugins/copilot/copilotoptionspagewidget.cpp deleted file mode 100644 index 549ea7f9ec6..00000000000 --- a/src/plugins/copilot/copilotoptionspagewidget.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#include "copilotoptionspagewidget.h" - -#include "authwidget.h" -#include "copilotsettings.h" - -#include -#include - -using namespace Utils; -using namespace LanguageClient; - -namespace Copilot { - -CopilotOptionsPageWidget::CopilotOptionsPageWidget(QWidget *parent) - : QWidget(parent) -{ - using namespace Layouting; - - auto authWdgt = new AuthWidget(); - - // clang-format off - Column { - authWdgt, br, - CopilotSettings::instance().nodeJsPath, br, - CopilotSettings::instance().distPath, br, - st - }.attachTo(this); - // clang-format on -} - -CopilotOptionsPageWidget::~CopilotOptionsPageWidget() = default; - -} // namespace Copilot diff --git a/src/plugins/copilot/copilotoptionspagewidget.h b/src/plugins/copilot/copilotoptionspagewidget.h deleted file mode 100644 index 37c51e68d3c..00000000000 --- a/src/plugins/copilot/copilotoptionspagewidget.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Copilot { -class CopilotOptionsPageWidget : public QWidget -{ - Q_OBJECT -public: - CopilotOptionsPageWidget(QWidget *parent = nullptr); - ~CopilotOptionsPageWidget() override; -}; -} // namespace Copilot From ebb3b90dce090ceee42ebd38ca1bbc96aec38427 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 22 Feb 2023 14:29:18 +0100 Subject: [PATCH 0077/1447] ADS: Use only one logging category Change-Id: I0366338d5605fea7b4b096605577e90dfa79c389 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- src/libs/advanceddockingsystem/ads_globals_p.h | 8 ++++++++ src/libs/advanceddockingsystem/dockareatabbar.cpp | 3 +-- src/libs/advanceddockingsystem/dockareatitlebar.cpp | 3 +-- src/libs/advanceddockingsystem/dockareawidget.cpp | 3 +-- src/libs/advanceddockingsystem/dockcontainerwidget.cpp | 3 +-- src/libs/advanceddockingsystem/dockmanager.cpp | 3 ++- src/libs/advanceddockingsystem/docksplitter.cpp | 3 +-- src/libs/advanceddockingsystem/dockwidget.cpp | 3 +-- src/libs/advanceddockingsystem/dockwidgettab.cpp | 3 +-- src/libs/advanceddockingsystem/floatingdockcontainer.cpp | 3 +-- src/libs/advanceddockingsystem/floatingdragpreview.cpp | 3 +-- 11 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 src/libs/advanceddockingsystem/ads_globals_p.h diff --git a/src/libs/advanceddockingsystem/ads_globals_p.h b/src/libs/advanceddockingsystem/ads_globals_p.h new file mode 100644 index 00000000000..e4b32eb2015 --- /dev/null +++ b/src/libs/advanceddockingsystem/ads_globals_p.h @@ -0,0 +1,8 @@ +// Copyright (C) 2023 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later + +#pragma once + +#include + +Q_DECLARE_LOGGING_CATEGORY(adsLog) diff --git a/src/libs/advanceddockingsystem/dockareatabbar.cpp b/src/libs/advanceddockingsystem/dockareatabbar.cpp index ec1bf782ff0..62f0b80b499 100644 --- a/src/libs/advanceddockingsystem/dockareatabbar.cpp +++ b/src/libs/advanceddockingsystem/dockareatabbar.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later #include "dockareatabbar.h" +#include "ads_globals_p.h" #include "dockareawidget.h" #include "dockwidget.h" @@ -16,8 +17,6 @@ #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { /** diff --git a/src/libs/advanceddockingsystem/dockareatitlebar.cpp b/src/libs/advanceddockingsystem/dockareatitlebar.cpp index ed1d76b67ad..178170777d5 100644 --- a/src/libs/advanceddockingsystem/dockareatitlebar.cpp +++ b/src/libs/advanceddockingsystem/dockareatitlebar.cpp @@ -4,6 +4,7 @@ #include "dockareatitlebar.h" #include "ads_globals.h" +#include "ads_globals_p.h" #include "advanceddockingsystemtr.h" #include "dockareatabbar.h" #include "dockareawidget.h" @@ -26,8 +27,6 @@ #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { /** diff --git a/src/libs/advanceddockingsystem/dockareawidget.cpp b/src/libs/advanceddockingsystem/dockareawidget.cpp index b4c21f71198..522b6b985ee 100644 --- a/src/libs/advanceddockingsystem/dockareawidget.cpp +++ b/src/libs/advanceddockingsystem/dockareawidget.cpp @@ -3,6 +3,7 @@ #include "dockareawidget.h" +#include "ads_globals_p.h" #include "dockareatabbar.h" #include "dockareatitlebar.h" #include "dockcomponentsfactory.h" @@ -29,8 +30,6 @@ #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { static const char *const INDEX_PROPERTY = "index"; diff --git a/src/libs/advanceddockingsystem/dockcontainerwidget.cpp b/src/libs/advanceddockingsystem/dockcontainerwidget.cpp index 80393a46713..253937c4d17 100644 --- a/src/libs/advanceddockingsystem/dockcontainerwidget.cpp +++ b/src/libs/advanceddockingsystem/dockcontainerwidget.cpp @@ -4,6 +4,7 @@ #include "dockcontainerwidget.h" #include "ads_globals.h" +#include "ads_globals_p.h" #include "dockareawidget.h" #include "dockingstatereader.h" #include "dockmanager.h" @@ -25,8 +26,6 @@ #include #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { static unsigned int zOrderCounter = 0; diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp index 59fc2f64fc3..2694f2986ea 100644 --- a/src/libs/advanceddockingsystem/dockmanager.cpp +++ b/src/libs/advanceddockingsystem/dockmanager.cpp @@ -4,6 +4,7 @@ #include "dockmanager.h" #include "ads_globals.h" +#include "ads_globals_p.h" #include "dockareawidget.h" #include "dockfocuscontroller.h" #include "dockingstatereader.h" @@ -38,7 +39,7 @@ #include #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg); +Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg); using namespace Utils; diff --git a/src/libs/advanceddockingsystem/docksplitter.cpp b/src/libs/advanceddockingsystem/docksplitter.cpp index e8537dbd775..22efb632040 100644 --- a/src/libs/advanceddockingsystem/docksplitter.cpp +++ b/src/libs/advanceddockingsystem/docksplitter.cpp @@ -3,14 +3,13 @@ #include "docksplitter.h" +#include "ads_globals_p.h" #include "dockareawidget.h" #include #include #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { /** diff --git a/src/libs/advanceddockingsystem/dockwidget.cpp b/src/libs/advanceddockingsystem/dockwidget.cpp index b39c58f4c2d..64269ebfdb3 100644 --- a/src/libs/advanceddockingsystem/dockwidget.cpp +++ b/src/libs/advanceddockingsystem/dockwidget.cpp @@ -4,6 +4,7 @@ #include "dockwidget.h" #include "ads_globals.h" +#include "ads_globals_p.h" #include "dockareawidget.h" #include "dockcomponentsfactory.h" #include "dockcontainerwidget.h" @@ -25,8 +26,6 @@ #include #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { /** diff --git a/src/libs/advanceddockingsystem/dockwidgettab.cpp b/src/libs/advanceddockingsystem/dockwidgettab.cpp index 67754784975..4531e0da2da 100644 --- a/src/libs/advanceddockingsystem/dockwidgettab.cpp +++ b/src/libs/advanceddockingsystem/dockwidgettab.cpp @@ -4,6 +4,7 @@ #include "dockwidgettab.h" #include "ads_globals.h" +#include "ads_globals_p.h" #include "advanceddockingsystemtr.h" #include "dockareawidget.h" #include "dockmanager.h" @@ -32,8 +33,6 @@ #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { using TabLabelType = ElidingLabel; diff --git a/src/libs/advanceddockingsystem/floatingdockcontainer.cpp b/src/libs/advanceddockingsystem/floatingdockcontainer.cpp index 4b8ae0913dd..c99044a3d5a 100644 --- a/src/libs/advanceddockingsystem/floatingdockcontainer.cpp +++ b/src/libs/advanceddockingsystem/floatingdockcontainer.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later #include "floatingdockcontainer.h" +#include "ads_globals_p.h" #include "dockareawidget.h" #include "dockcontainerwidget.h" @@ -29,8 +30,6 @@ #include #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { #ifdef Q_OS_WIN diff --git a/src/libs/advanceddockingsystem/floatingdragpreview.cpp b/src/libs/advanceddockingsystem/floatingdragpreview.cpp index f427ab85edf..3111e46c6bd 100644 --- a/src/libs/advanceddockingsystem/floatingdragpreview.cpp +++ b/src/libs/advanceddockingsystem/floatingdragpreview.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later #include "floatingdragpreview.h" +#include "ads_globals_p.h" #include "dockareawidget.h" #include "dockcontainerwidget.h" @@ -19,8 +20,6 @@ #include -static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg) - namespace ADS { /** From a8d62298985329c5d2a3ba923664372bc9938a0e Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Feb 2023 09:34:28 +0100 Subject: [PATCH 0078/1447] Terminal: Fix libvterm -fPIC Change-Id: Iac8a9a0ec01058edd00399c3de0746d97de6fec3 Reviewed-by: hjk --- src/libs/3rdparty/libvterm/CMakeLists.txt | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/libs/3rdparty/libvterm/CMakeLists.txt b/src/libs/3rdparty/libvterm/CMakeLists.txt index 4a0ede6f0f4..232217d9f58 100644 --- a/src/libs/3rdparty/libvterm/CMakeLists.txt +++ b/src/libs/3rdparty/libvterm/CMakeLists.txt @@ -1,4 +1,7 @@ -add_library(libvterm STATIC +add_qtc_library(libvterm STATIC + PUBLIC_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include + PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON + SOURCES src/encoding.c src/fullwidth.inc src/keyboard.c @@ -13,13 +16,3 @@ add_library(libvterm STATIC src/vterm.c src/vterm_internal.h ) - -target_include_directories(libvterm PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include -) - -set_target_properties(libvterm - PROPERTIES - QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON - POSITION_INDEPENDENT_CODE ON  -) From d5a9e28a968d13f9c437033d647b5da8eaf09dc9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 9 Feb 2023 13:58:01 +0100 Subject: [PATCH 0079/1447] Utils: Add tst_filepath Moves all tests that are applicable only to FilePath over from tst_fileutils. Change-Id: Ic331e1470a7479ee2f8ba38baec84124982a000a Reviewed-by: Christian Stenger --- src/libs/utils/filepath.cpp | 283 ++- src/libs/utils/filepath.h | 3 + src/libs/utils/fileutils.cpp | 2 +- src/libs/utils/fileutils.h | 4 - tests/auto/utils/CMakeLists.txt | 1 + tests/auto/utils/filepath/CMakeLists.txt | 4 + tests/auto/utils/filepath/filepath.qbs | 11 + tests/auto/utils/filepath/tst_filepath.cpp | 1622 ++++++++++++++++++ tests/auto/utils/fileutils/tst_fileutils.cpp | 1316 +------------- tests/auto/utils/utils.qbs | 1 + 10 files changed, 1820 insertions(+), 1427 deletions(-) create mode 100644 tests/auto/utils/filepath/CMakeLists.txt create mode 100644 tests/auto/utils/filepath/filepath.qbs create mode 100644 tests/auto/utils/filepath/tst_filepath.cpp diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 8c0832df585..7e61ac0d376 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -780,6 +780,146 @@ int FilePath::schemeAndHostLength(const QStringView path) return pos + 1; // scheme://host/ plus something } +static QString normalizePathSegmentHelper(const QString &name) +{ + const int len = name.length(); + + if (len == 0 || name.contains("%{")) + return name; + + int i = len - 1; + QVarLengthArray outVector(len); + int used = len; + char16_t *out = outVector.data(); + const ushort *p = reinterpret_cast(name.data()); + const ushort *prefix = p; + int up = 0; + + const int prefixLength = name.at(0) == u'/' ? 1 : 0; + + p += prefixLength; + i -= prefixLength; + + // replicate trailing slash (i > 0 checks for emptiness of input string p) + // except for remote paths because there can be /../ or /./ ending + if (i > 0 && p[i] == '/') { + out[--used] = '/'; + --i; + } + + while (i >= 0) { + if (p[i] == '/') { + --i; + continue; + } + + // remove current directory + if (p[i] == '.' && (i == 0 || p[i - 1] == '/')) { + --i; + continue; + } + + // detect up dir + if (i >= 1 && p[i] == '.' && p[i - 1] == '.' && (i < 2 || p[i - 2] == '/')) { + ++up; + i -= i >= 2 ? 3 : 2; + continue; + } + + // prepend a slash before copying when not empty + if (!up && used != len && out[used] != '/') + out[--used] = '/'; + + // skip or copy + while (i >= 0) { + if (p[i] == '/') { + --i; + break; + } + + // actual copy + if (!up) + out[--used] = p[i]; + --i; + } + + // decrement up after copying/skipping + if (up) + --up; + } + + // Indicate failure when ".." are left over for an absolute path. + // if (ok) + // *ok = prefixLength == 0 || up == 0; + + // add remaining '..' + while (up) { + if (used != len && out[used] != '/') // is not empty and there isn't already a '/' + out[--used] = '/'; + out[--used] = '.'; + out[--used] = '.'; + --up; + } + + bool isEmpty = used == len; + + if (prefixLength) { + if (!isEmpty && out[used] == '/') { + // Even though there is a prefix the out string is a slash. This happens, if the input + // string only consists of a prefix followed by one or more slashes. Just skip the slash. + ++used; + } + for (int i = prefixLength - 1; i >= 0; --i) + out[--used] = prefix[i]; + } else { + if (isEmpty) { + // After resolving the input path, the resulting string is empty (e.g. "foo/.."). Return + // a dot in that case. + out[--used] = '.'; + } else if (out[used] == '/') { + // After parsing the input string, out only contains a slash. That happens whenever all + // parts are resolved and there is a trailing slash ("./" or "foo/../" for example). + // Prepend a dot to have the correct return value. + out[--used] = '.'; + } + } + + // If path was not modified return the original value + if (used == 0) + return name; + return QString::fromUtf16(out + used, len - used); +} + +QString doCleanPath(const QString &input_) +{ + QString input = input_; + if (input.contains('\\')) + input.replace('\\', '/'); + + if (input.startsWith("//?/")) { + input = input.mid(4); + if (input.startsWith("UNC/")) + input = '/' + input.mid(3); // trick it into reporting two slashs at start + } + + int prefixLen = 0; + const int shLen = FilePath::schemeAndHostLength(input); + if (shLen > 0) { + prefixLen = shLen + FilePath::rootLength(input.mid(shLen)); + } else { + prefixLen = FilePath::rootLength(input); + if (prefixLen > 0 && input.at(prefixLen - 1) == '/') + --prefixLen; + } + + QString path = normalizePathSegmentHelper(input.mid(prefixLen)); + + // Strip away last slash except for root directories + if (path.size() > 1 && path.endsWith(u'/')) + path.chop(1); + + return input.left(prefixLen) + path; +} /*! Find the parent directory of a given directory. @@ -1788,150 +1928,7 @@ QTextStream &operator<<(QTextStream &s, const FilePath &fn) return s << fn.toString(); } -static QString normalizePathSegmentHelper(const QString &name) -{ - const int len = name.length(); - - if (len == 0 || name.contains("%{")) - return name; - - int i = len - 1; - QVarLengthArray outVector(len); - int used = len; - char16_t *out = outVector.data(); - const ushort *p = reinterpret_cast(name.data()); - const ushort *prefix = p; - int up = 0; - - const int prefixLength = name.at(0) == u'/' ? 1 : 0; - - p += prefixLength; - i -= prefixLength; - - // replicate trailing slash (i > 0 checks for emptiness of input string p) - // except for remote paths because there can be /../ or /./ ending - if (i > 0 && p[i] == '/') { - out[--used] = '/'; - --i; - } - - while (i >= 0) { - if (p[i] == '/') { - --i; - continue; - } - - // remove current directory - if (p[i] == '.' && (i == 0 || p[i-1] == '/')) { - --i; - continue; - } - - // detect up dir - if (i >= 1 && p[i] == '.' && p[i-1] == '.' && (i < 2 || p[i - 2] == '/')) { - ++up; - i -= i >= 2 ? 3 : 2; - continue; - } - - // prepend a slash before copying when not empty - if (!up && used != len && out[used] != '/') - out[--used] = '/'; - - // skip or copy - while (i >= 0) { - if (p[i] == '/') { - --i; - break; - } - - // actual copy - if (!up) - out[--used] = p[i]; - --i; - } - - // decrement up after copying/skipping - if (up) - --up; - } - - // Indicate failure when ".." are left over for an absolute path. -// if (ok) -// *ok = prefixLength == 0 || up == 0; - - // add remaining '..' - while (up) { - if (used != len && out[used] != '/') // is not empty and there isn't already a '/' - out[--used] = '/'; - out[--used] = '.'; - out[--used] = '.'; - --up; - } - - bool isEmpty = used == len; - - if (prefixLength) { - if (!isEmpty && out[used] == '/') { - // Even though there is a prefix the out string is a slash. This happens, if the input - // string only consists of a prefix followed by one or more slashes. Just skip the slash. - ++used; - } - for (int i = prefixLength - 1; i >= 0; --i) - out[--used] = prefix[i]; - } else { - if (isEmpty) { - // After resolving the input path, the resulting string is empty (e.g. "foo/.."). Return - // a dot in that case. - out[--used] = '.'; - } else if (out[used] == '/') { - // After parsing the input string, out only contains a slash. That happens whenever all - // parts are resolved and there is a trailing slash ("./" or "foo/../" for example). - // Prepend a dot to have the correct return value. - out[--used] = '.'; - } - } - - // If path was not modified return the original value - if (used == 0) - return name; - return QString::fromUtf16(out + used, len - used); -} - -QString doCleanPath(const QString &input_) -{ - QString input = input_; - if (input.contains('\\')) - input.replace('\\', '/'); - - if (input.startsWith("//?/")) { - input = input.mid(4); - if (input.startsWith("UNC/")) - input = '/' + input.mid(3); // trick it into reporting two slashs at start - } - - int prefixLen = 0; - const int shLen = FilePath::schemeAndHostLength(input); - if (shLen > 0) { - prefixLen = shLen + FilePath::rootLength(input.mid(shLen)); - } else { - prefixLen = FilePath::rootLength(input); - if (prefixLen > 0 && input.at(prefixLen - 1) == '/') - --prefixLen; - } - - QString path = normalizePathSegmentHelper(input.mid(prefixLen)); - - // Strip away last slash except for root directories - if (path.size() > 1 && path.endsWith(u'/')) - path.chop(1); - - return input.left(prefixLen) + path; -} - - // FileFilter - FileFilter::FileFilter(const QStringList &nameFilters, const QDir::Filters fileFilters, const QDirIterator::IteratorFlags flags) diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 4c61786eba4..8aa59eb5d98 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -293,6 +293,9 @@ public: std::function openTerminal; }; +// For testing +QTCREATOR_UTILS_EXPORT QString doCleanPath(const QString &input); + } // Utils Q_DECLARE_METATYPE(Utils::FilePath) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 69c31729149..d128f219742 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -802,7 +802,7 @@ FilePath FileUtils::commonPath(const FilePath &oldCommonPath, const FilePath &fi FilePath FileUtils::homePath() { - return FilePath::fromString(doCleanPath(QDir::homePath())); + return FilePath::fromUserInput(QDir::homePath()); } FilePaths FileUtils::toFilePathList(const QStringList &paths) { diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index f34206d8b77..ec3de7a5ba4 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -232,9 +232,5 @@ QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &f bool isRelativePathHelper(const QString &path, OsType osType); -// For testing -QTCREATOR_UTILS_EXPORT QString doCleanPath(const QString &input); -QTCREATOR_UTILS_EXPORT QString cleanPathHelper(const QString &path); - } // namespace Utils diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index 29548a5680f..65f47fc73f7 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(asynctask) add_subdirectory(commandline) add_subdirectory(deviceshell) add_subdirectory(expected) +add_subdirectory(filepath) add_subdirectory(fileutils) add_subdirectory(fsengine) add_subdirectory(fuzzymatcher) diff --git a/tests/auto/utils/filepath/CMakeLists.txt b/tests/auto/utils/filepath/CMakeLists.txt new file mode 100644 index 00000000000..3d85eb0c64e --- /dev/null +++ b/tests/auto/utils/filepath/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_utils_filepath + DEPENDS Utils + SOURCES tst_filepath.cpp +) diff --git a/tests/auto/utils/filepath/filepath.qbs b/tests/auto/utils/filepath/filepath.qbs new file mode 100644 index 00000000000..73c106b2e8c --- /dev/null +++ b/tests/auto/utils/filepath/filepath.qbs @@ -0,0 +1,11 @@ +import qbs + +QtcAutotest { + name: "FilePath autotest" + Depends { name: "Utils" } + Properties { + condition: qbs.toolchain.contains("gcc") + cpp.cxxFlags: base.concat(["-Wno-trigraphs"]) + } + files: "tst_filepath.cpp" +} diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp new file mode 100644 index 00000000000..7303e7d9197 --- /dev/null +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -0,0 +1,1622 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include +#include + +#include +#include +#include + +using namespace Utils; + +namespace QTest { +template<> +char *toString(const FilePath &filePath) +{ + return qstrdup(filePath.toString().toLocal8Bit().constData()); +} +} // namespace QTest + +class tst_filepath : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void isEmpty_data(); + void isEmpty(); + + void parentDir_data(); + void parentDir(); + + void isChildOf_data(); + void isChildOf(); + + void fileName_data(); + void fileName(); + + void calcRelativePath_data(); + void calcRelativePath(); + + void relativePath_specials(); + void relativePath_data(); + void relativePath(); + + void absolute_data(); + void absolute(); + + void fromToString_data(); + void fromToString(); + + void fromString_data(); + void fromString(); + + void fromUserInput_data(); + void fromUserInput(); + + void toString_data(); + void toString(); + + void toFSPathString_data(); + void toFSPathString(); + + void comparison_data(); + void comparison(); + + void linkFromString_data(); + void linkFromString(); + + void pathAppended_data(); + void pathAppended(); + + void resolvePath_data(); + void resolvePath(); + + void relativeChildPath_data(); + void relativeChildPath(); + + void rootLength_data(); + void rootLength(); + + void schemeAndHostLength_data(); + void schemeAndHostLength(); + + void asyncLocalCopy(); + void startsWithDriveLetter(); + void startsWithDriveLetter_data(); + + void onDevice_data(); + void onDevice(); + + void stringAppended(); + void stringAppended_data(); + void url(); + void url_data(); + + void cleanPath_data(); + void cleanPath(); + + void isSameFile_data(); + void isSameFile(); + + void hostSpecialChars_data(); + void hostSpecialChars(); + + void tmp(); + void tmp_data(); + +private: + QTemporaryDir tempDir; + QString rootPath; +}; + +static void touch(const QDir &dir, const QString &filename, bool fill) +{ + QFile file(dir.absoluteFilePath(filename)); + file.open(QIODevice::WriteOnly); + if (fill) { + QRandomGenerator *random = QRandomGenerator::global(); + for (int i = 0; i < 10; ++i) + file.write(QString::number(random->generate(), 16).toUtf8()); + } + file.close(); +} + +void tst_filepath::initTestCase() +{ + // initialize test for tst_fileutiles::relativePath*() + QVERIFY(tempDir.isValid()); + rootPath = tempDir.path(); + QDir dir(rootPath); + dir.mkpath("a/b/c/d"); + dir.mkpath("a/x/y/z"); + dir.mkpath("a/b/x/y/z"); + dir.mkpath("x/y/z"); + touch(dir, "a/b/c/d/file1.txt", false); + touch(dir, "a/x/y/z/file2.txt", false); + touch(dir, "a/file3.txt", false); + touch(dir, "x/y/file4.txt", false); + + // initialize test for tst_filepath::asyncLocalCopy() + touch(dir, "x/y/fileToCopy.txt", true); +} + +void tst_filepath::isEmpty_data() +{ + QTest::addColumn("path"); + QTest::addColumn("result"); + + QTest::newRow("empty path") << "" << true; + QTest::newRow("root only") << "/" << false; + QTest::newRow("//") << "//" << false; + QTest::newRow("scheme://host") << "scheme://host" << true; // Intentional (for now?) + QTest::newRow("scheme://host/") << "scheme://host/" << false; + QTest::newRow("scheme://host/a") << "scheme://host/a" << false; + QTest::newRow("scheme://host/.") << "scheme://host/." << false; +} + +void tst_filepath::isEmpty() +{ + QFETCH(QString, path); + QFETCH(bool, result); + + FilePath filePath = FilePath::fromString(path); + QCOMPARE(filePath.isEmpty(), result); +} + +void tst_filepath::parentDir_data() +{ + QTest::addColumn("path"); + QTest::addColumn("parentPath"); + QTest::addColumn("expectFailMessage"); + + QTest::newRow("empty path") << "" + << "" + << ""; + QTest::newRow("root only") << "/" + << "" + << ""; + QTest::newRow("//") << "//" + << "" + << ""; + QTest::newRow("/tmp/dir") << "/tmp/dir" + << "/tmp" + << ""; + QTest::newRow("relative/path") << "relative/path" + << "relative" + << ""; + QTest::newRow("relativepath") << "relativepath" + << "." + << ""; + + // Windows stuff: + QTest::newRow("C:/data") << "C:/data" + << "C:/" + << ""; + QTest::newRow("C:/") << "C:/" + << "" + << ""; + QTest::newRow("//./com1") << "//./com1" + << "//./" + << ""; + QTest::newRow("//?/path") << "//?/path" + << "/" + << "Qt 4 cannot handle this path."; + QTest::newRow("/Global?\?/UNC/host") << "/Global?\?/UNC/host" + << "/Global?\?/UNC/host" + << "Qt 4 cannot handle this path."; + QTest::newRow("//server/directory/file") << "//server/directory/file" + << "//server/directory" + << ""; + QTest::newRow("//server/directory") << "//server/directory" + << "//server/" + << ""; + QTest::newRow("//server") << "//server" + << "" + << ""; + + QTest::newRow("qrc") << ":/foo/bar.txt" + << ":/foo" + << ""; +} + +void tst_filepath::parentDir() +{ + QFETCH(QString, path); + QFETCH(QString, parentPath); + QFETCH(QString, expectFailMessage); + + FilePath result = FilePath::fromUserInput(path).parentDir(); + if (!expectFailMessage.isEmpty()) + QEXPECT_FAIL("", expectFailMessage.toUtf8().constData(), Continue); + QCOMPARE(result.toString(), parentPath); +} + +void tst_filepath::isChildOf_data() +{ + QTest::addColumn("path"); + QTest::addColumn("childPath"); + QTest::addColumn("result"); + + QTest::newRow("empty path") << "" + << "/tmp" << false; + QTest::newRow("root only") << "/" + << "/tmp" << true; + QTest::newRow("/tmp/dir") << "/tmp" + << "/tmp/dir" << true; + QTest::newRow("relative/path") << "relative" + << "relative/path" << true; + QTest::newRow("/tmpdir") << "/tmp" + << "/tmpdir" << false; + QTest::newRow("same") << "/tmp/dir" + << "/tmp/dir" << false; + + // Windows stuff: + QTest::newRow("C:/data") << "C:/" + << "C:/data" << true; + QTest::newRow("C:/") << "" + << "C:/" << false; + QTest::newRow("com-port") << "//./" + << "//./com1" << true; + QTest::newRow("extended-length-path") << "\\\\?\\C:\\" + << "\\\\?\\C:\\path" << true; + QTest::newRow("/Global?\?/UNC/host") << "/Global?\?/UNC/host" + << "/Global?\?/UNC/host/file" << true; + QTest::newRow("//server/directory/file") << "//server/directory" + << "//server/directory/file" << true; + QTest::newRow("//server/directory") << "//server" + << "//server/directory" << true; + + QTest::newRow("qrc") << ":/foo/bar" + << ":/foo/bar/blah" << true; +} + +void tst_filepath::isChildOf() +{ + QFETCH(QString, path); + QFETCH(QString, childPath); + QFETCH(bool, result); + + const FilePath child = FilePath::fromUserInput(childPath); + const FilePath parent = FilePath::fromUserInput(path); + + QCOMPARE(child.isChildOf(parent), result); +} + +void tst_filepath::fileName_data() +{ + QTest::addColumn("path"); + QTest::addColumn("components"); + QTest::addColumn("result"); + + QTest::newRow("empty 1") << "" << 0 << ""; + QTest::newRow("empty 2") << "" << 1 << ""; + QTest::newRow("basic") << "/foo/bar/baz" << 0 << "baz"; + QTest::newRow("2 parts") << "/foo/bar/baz" << 1 << "bar/baz"; + QTest::newRow("root no depth") << "/foo" << 0 << "foo"; + QTest::newRow("root full") << "/foo" << 1 << "/foo"; + QTest::newRow("root included") << "/foo/bar/baz" << 2 << "/foo/bar/baz"; + QTest::newRow("too many parts") << "/foo/bar/baz" << 5 << "/foo/bar/baz"; + QTest::newRow("windows root") << "C:/foo/bar/baz" << 2 << "C:/foo/bar/baz"; + QTest::newRow("smb share") << "//server/share/file" << 2 << "//server/share/file"; + QTest::newRow("no slashes") << "foobar" << 0 << "foobar"; + QTest::newRow("no slashes with depth") << "foobar" << 1 << "foobar"; + QTest::newRow("multiple slashes 1") << "/foo/bar////baz" << 0 << "baz"; + QTest::newRow("multiple slashes 2") << "/foo/bar////baz" << 1 << "bar////baz"; + QTest::newRow("multiple slashes 3") << "/foo////bar/baz" << 2 << "/foo////bar/baz"; + QTest::newRow("single char 1") << "/a/b/c" << 0 << "c"; + QTest::newRow("single char 2") << "/a/b/c" << 1 << "b/c"; + QTest::newRow("single char 3") << "/a/b/c" << 2 << "/a/b/c"; + QTest::newRow("slash at end 1") << "/a/b/" << 0 << ""; + QTest::newRow("slash at end 2") << "/a/b/" << 1 << "b/"; + QTest::newRow("slashes at end 1") << "/a/b//" << 0 << ""; + QTest::newRow("slashes at end 2") << "/a/b//" << 1 << "b//"; + QTest::newRow("root only 1") << "/" << 0 << ""; + QTest::newRow("root only 2") << "/" << 1 << "/"; + QTest::newRow("qrc 0") << ":/foo/bar" << 0 << "bar"; + QTest::newRow("qrc with root") << ":/foo/bar" << 1 << ":/foo/bar"; +} + +void tst_filepath::fileName() +{ + QFETCH(QString, path); + QFETCH(int, components); + QFETCH(QString, result); + QCOMPARE(FilePath::fromString(path).fileNameWithPathComponents(components), result); +} + +void tst_filepath::calcRelativePath_data() +{ + QTest::addColumn("absolutePath"); + QTest::addColumn("anchorPath"); + QTest::addColumn("result"); + + QTest::newRow("empty") << "" + << "" + << ""; + QTest::newRow("leftempty") << "" + << "/" + << ""; + QTest::newRow("rightempty") << "/" + << "" + << ""; + QTest::newRow("root") << "/" + << "/" + << "."; + QTest::newRow("simple1") << "/a" + << "/" + << "a"; + QTest::newRow("simple2") << "/" + << "/a" + << ".."; + QTest::newRow("simple3") << "/a" + << "/a" + << "."; + QTest::newRow("extraslash1") << "/a/b/c" + << "/a/b/c" + << "."; + QTest::newRow("extraslash2") << "/a/b/c" + << "/a/b/c/" + << "."; + QTest::newRow("extraslash3") << "/a/b/c/" + << "/a/b/c" + << "."; + QTest::newRow("normal1") << "/a/b/c" + << "/a/x" + << "../b/c"; + QTest::newRow("normal2") << "/a/b/c" + << "/a/x/y" + << "../../b/c"; + QTest::newRow("normal3") << "/a/b/c" + << "/x/y" + << "../../a/b/c"; +} + +void tst_filepath::calcRelativePath() +{ + QFETCH(QString, absolutePath); + QFETCH(QString, anchorPath); + QFETCH(QString, result); + QString relativePath = Utils::FilePath::calcRelativePath(absolutePath, anchorPath); + QCOMPARE(relativePath, result); +} + +void tst_filepath::relativePath_specials() +{ + QString path = FilePath("").relativePathFrom("").toString(); + QCOMPARE(path, ""); +} + +void tst_filepath::relativePath_data() +{ + QTest::addColumn("relative"); + QTest::addColumn("anchor"); + QTest::addColumn("result"); + + QTest::newRow("samedir") << "/" + << "/" + << "."; + QTest::newRow("samedir_but_file") << "a/b/c/d/file1.txt" + << "a/b/c/d" + << "file1.txt"; + QTest::newRow("samedir_but_file2") << "a/b/c/d" + << "a/b/c/d/file1.txt" + << "."; + QTest::newRow("dir2dir_1") << "a/b/c/d" + << "a/x/y/z" + << "../../../b/c/d"; + QTest::newRow("dir2dir_2") << "a/b" + << "a/b/c" + << ".."; + QTest::newRow("file2file_1") << "a/b/c/d/file1.txt" + << "a/file3.txt" + << "b/c/d/file1.txt"; + QTest::newRow("dir2file_1") << "a/b/c" + << "a/x/y/z/file2.txt" + << "../../../b/c"; + QTest::newRow("file2dir_1") << "a/b/c/d/file1.txt" + << "x/y" + << "../../a/b/c/d/file1.txt"; +} + +void tst_filepath::relativePath() +{ + QFETCH(QString, relative); + QFETCH(QString, anchor); + QFETCH(QString, result); + FilePath actualPath = FilePath::fromString(rootPath + "/" + relative) + .relativePathFrom(FilePath::fromString(rootPath + "/" + anchor)); + QCOMPARE(actualPath.toString(), result); +} + +void tst_filepath::rootLength_data() +{ + QTest::addColumn("path"); + QTest::addColumn("result"); + + QTest::newRow("empty") << "" << 0; + QTest::newRow("slash") << "/" << 1; + QTest::newRow("slash-rest") << "/abc" << 1; + QTest::newRow("rest") << "abc" << 0; + QTest::newRow("drive-slash") << "x:/" << 3; + QTest::newRow("drive-rest") << "x:abc" << 0; + QTest::newRow("drive-slash-rest") << "x:/abc" << 3; + + QTest::newRow("unc-root") << "//" << 2; + QTest::newRow("unc-localhost-unfinished") << "//localhost" << 11; + QTest::newRow("unc-localhost") << "//localhost/" << 12; + QTest::newRow("unc-localhost-rest") << "//localhost/abs" << 12; + QTest::newRow("unc-localhost-drive") << "//localhost/c$" << 12; + QTest::newRow("unc-localhost-drive-slash") << "//localhost//c$/" << 12; + QTest::newRow("unc-localhost-drive-slash-rest") << "//localhost//c$/x" << 12; +} + +void tst_filepath::rootLength() +{ + QFETCH(QString, path); + QFETCH(int, result); + + int actual = FilePath::rootLength(path); + QCOMPARE(actual, result); +} + +void tst_filepath::schemeAndHostLength_data() +{ + QTest::addColumn("path"); + QTest::addColumn("result"); + + QTest::newRow("empty") << "" << 0; + QTest::newRow("drive-slash-rest") << "x:/abc" << 0; + QTest::newRow("rest") << "abc" << 0; + QTest::newRow("slash-rest") << "/abc" << 0; + QTest::newRow("dev-empty") << "dev://" << 6; + QTest::newRow("dev-localhost-unfinished") << "dev://localhost" << 15; + QTest::newRow("dev-localhost") << "dev://localhost/" << 16; + QTest::newRow("dev-localhost-rest") << "dev://localhost/abs" << 16; + QTest::newRow("dev-localhost-drive") << "dev://localhost/c$" << 16; + QTest::newRow("dev-localhost-drive-slash") << "dev://localhost//c$/" << 16; + QTest::newRow("dev-localhost-drive-slash-rest") << "dev://localhost//c$/x" << 16; +} + +void tst_filepath::schemeAndHostLength() +{ + QFETCH(QString, path); + QFETCH(int, result); + + int actual = FilePath::schemeAndHostLength(path); + QCOMPARE(actual, result); +} + +void tst_filepath::absolute_data() +{ + QTest::addColumn("path"); + QTest::addColumn("absoluteFilePath"); + QTest::addColumn("absolutePath"); + + QTest::newRow("absolute1") << FilePath::fromString("/") << FilePath::fromString("/") + << FilePath::fromString("/"); + QTest::newRow("absolute2") << FilePath::fromString("C:/a/b") << FilePath::fromString("C:/a/b") + << FilePath::fromString("C:/a"); + QTest::newRow("absolute3") << FilePath::fromString("/a/b") << FilePath::fromString("/a/b") + << FilePath::fromString("/a"); + QTest::newRow("absolute4") << FilePath::fromString("/a/b/..") << FilePath::fromString("/a") + << FilePath::fromString("/"); + QTest::newRow("absolute5") << FilePath::fromString("/a/b/c/../d") + << FilePath::fromString("/a/b/d") << FilePath::fromString("/a/b"); + QTest::newRow("absolute6") << FilePath::fromString("/a/../b/c/d") + << FilePath::fromString("/b/c/d") << FilePath::fromString("/b/c"); + QTest::newRow("default-constructed") << FilePath() << FilePath() << FilePath(); + QTest::newRow("relative") << FilePath::fromString("a/b") + << FilePath::fromString(QDir::currentPath() + "/a/b") + << FilePath::fromString(QDir::currentPath() + "/a"); + QTest::newRow("qrc") << FilePath::fromString(":/foo/bar.txt") + << FilePath::fromString(":/foo/bar.txt") << FilePath::fromString(":/foo"); +} + +void tst_filepath::absolute() +{ + QFETCH(FilePath, path); + QFETCH(FilePath, absoluteFilePath); + QFETCH(FilePath, absolutePath); + QCOMPARE(path.absoluteFilePath(), absoluteFilePath); + QCOMPARE(path.absolutePath(), absolutePath); +} + +void tst_filepath::toString_data() +{ + QTest::addColumn("scheme"); + QTest::addColumn("host"); + QTest::addColumn("path"); + QTest::addColumn("result"); + QTest::addColumn("userResult"); + + QTest::newRow("empty") << "" + << "" + << "" + << "" + << ""; + QTest::newRow("scheme") << "http" + << "" + << "" + << "http://" + << "http://"; + QTest::newRow("scheme-and-host") << "http" + << "127.0.0.1" + << "" + << "http://127.0.0.1" + << "http://127.0.0.1"; + QTest::newRow("root") << "http" + << "127.0.0.1" + << "/" + << "http://127.0.0.1/" + << "http://127.0.0.1/"; + + QTest::newRow("root-folder") << "" + << "" + << "/" + << "/" + << "/"; + QTest::newRow("qtc-dev-root-folder-linux") << "" + << "" + << "/__qtc_devices__" + << "/__qtc_devices__" + << "/__qtc_devices__"; + QTest::newRow("qtc-dev-root-folder-win") << "" + << "" + << "c:/__qtc_devices__" + << "c:/__qtc_devices__" + << "c:/__qtc_devices__"; + QTest::newRow("qtc-dev-type-root-folder-linux") << "" + << "" + << "/__qtc_devices__/docker" + << "/__qtc_devices__/docker" + << "/__qtc_devices__/docker"; + QTest::newRow("qtc-dev-type-root-folder-win") << "" + << "" + << "c:/__qtc_devices__/docker" + << "c:/__qtc_devices__/docker" + << "c:/__qtc_devices__/docker"; + QTest::newRow("qtc-root-folder") << "docker" + << "alpine:latest" + << "/" + << "docker://alpine:latest/" + << "docker://alpine:latest/"; + QTest::newRow("qtc-root-folder-rel") << "docker" + << "alpine:latest" + << "" + << "docker://alpine:latest" + << "docker://alpine:latest"; +} + +void tst_filepath::toString() +{ + QFETCH(QString, scheme); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(QString, result); + QFETCH(QString, userResult); + + FilePath filePath = FilePath::fromParts(scheme, host, path); + QCOMPARE(filePath.toString(), result); + QString cleanedOutput = filePath.needsDevice() ? filePath.toUserOutput() + : QDir::cleanPath(filePath.toUserOutput()); + QCOMPARE(cleanedOutput, userResult); +} + +void tst_filepath::toFSPathString_data() +{ + QTest::addColumn("scheme"); + QTest::addColumn("host"); + QTest::addColumn("path"); + QTest::addColumn("result"); + QTest::addColumn("userResult"); + + QTest::newRow("empty") << "" + << "" + << "" + << "" + << ""; + QTest::newRow("scheme") << "http" + << "" + << "" << QDir::rootPath() + "__qtc_devices__/http/" + << "http://"; + QTest::newRow("scheme-and-host") << "http" + << "127.0.0.1" + << "" << QDir::rootPath() + "__qtc_devices__/http/127.0.0.1" + << "http://127.0.0.1"; + QTest::newRow("root") << "http" + << "127.0.0.1" + << "/" << QDir::rootPath() + "__qtc_devices__/http/127.0.0.1/" + << "http://127.0.0.1/"; + + QTest::newRow("root-folder") << "" + << "" + << "/" + << "/" + << "/"; + QTest::newRow("qtc-dev-root-folder") + << "" + << "" << QDir::rootPath() + "__qtc_devices__" << QDir::rootPath() + "__qtc_devices__" + << QDir::rootPath() + "__qtc_devices__"; + QTest::newRow("qtc-dev-type-root-folder") << "" + << "" << QDir::rootPath() + "__qtc_devices__/docker" + << QDir::rootPath() + "__qtc_devices__/docker" + << QDir::rootPath() + "__qtc_devices__/docker"; + QTest::newRow("qtc-root-folder") + << "docker" + << "alpine:latest" + << "/" << QDir::rootPath() + "__qtc_devices__/docker/alpine:latest/" + << "docker://alpine:latest/"; + QTest::newRow("qtc-root-folder-rel") + << "docker" + << "alpine:latest" + << "" << QDir::rootPath() + "__qtc_devices__/docker/alpine:latest" + << "docker://alpine:latest"; +} + +void tst_filepath::toFSPathString() +{ + QFETCH(QString, scheme); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(QString, result); + QFETCH(QString, userResult); + + FilePath filePath = FilePath::fromParts(scheme, host, path); + QCOMPARE(filePath.toFSPathString(), result); + QString cleanedOutput = filePath.needsDevice() ? filePath.toUserOutput() + : QDir::cleanPath(filePath.toUserOutput()); + QCOMPARE(cleanedOutput, userResult); +} + +enum ExpectedPass { PassEverywhere = 0, FailOnWindows = 1, FailOnLinux = 2, FailEverywhere = 3 }; + +class FromStringData +{ +public: + FromStringData(const QString &input, + const QString &scheme, + const QString &host, + const QString &path, + ExpectedPass expectedPass = PassEverywhere) + : input(input) + , scheme(scheme) + , host(host) + , path(path) + , expectedPass(expectedPass) + {} + + QString input; + QString scheme; + QString host; + QString path; + ExpectedPass expectedPass = PassEverywhere; +}; + +Q_DECLARE_METATYPE(FromStringData); + +void tst_filepath::fromString_data() +{ + using D = FromStringData; + QTest::addColumn("data"); + + QTest::newRow("empty") << D("", "", "", ""); + QTest::newRow("single-colon") << D(":", "", "", ":"); + QTest::newRow("single-slash") << D("/", "", "", "/"); + QTest::newRow("single-char") << D("a", "", "", "a"); + QTest::newRow("relative") << D("./rel", "", "", "./rel"); + QTest::newRow("qrc") << D(":/test.txt", "", "", ":/test.txt"); + QTest::newRow("qrc-no-slash") << D(":test.txt", "", "", ":test.txt"); + + QTest::newRow("unc-incomplete") << D("//", "", "", "//"); + QTest::newRow("unc-incomplete-only-server") << D("//server", "", "", "//server"); + QTest::newRow("unc-incomplete-only-server-2") << D("//server/", "", "", "//server/"); + QTest::newRow("unc-server-and-share") << D("//server/share", "", "", "//server/share"); + QTest::newRow("unc-server-and-share-2") << D("//server/share/", "", "", "//server/share/"); + QTest::newRow("unc-full") << D("//server/share/test.txt", "", "", "//server/share/test.txt"); + + QTest::newRow("unix-root") << D("/", "", "", "/"); + QTest::newRow("unix-folder") << D("/tmp", "", "", "/tmp"); + QTest::newRow("unix-folder-with-trailing-slash") << D("/tmp/", "", "", "/tmp/"); + + QTest::newRow("windows-root") << D("c:", "", "", "c:"); + QTest::newRow("windows-folder") << D("c:/Windows", "", "", "c:/Windows"); + QTest::newRow("windows-folder-with-trailing-slash") << D("c:/Windows/", "", "", "c:/Windows/"); + QTest::newRow("windows-folder-slash") << D("C:/Windows", "", "", "C:/Windows"); + + QTest::newRow("docker-root-url") << D("docker://1234/", "docker", "1234", "/"); + QTest::newRow("docker-root-url-special-linux") + << D("/__qtc_devices__/docker/1234/", "docker", "1234", "/"); + QTest::newRow("docker-root-url-special-win") + << D("c:/__qtc_devices__/docker/1234/", "docker", "1234", "/"); + QTest::newRow("docker-relative-path") << D("docker://1234/./rel", "docker", "1234", "rel"); + + QTest::newRow("qtc-dev-linux") << D("/__qtc_devices__", "", "", "/__qtc_devices__"); + QTest::newRow("qtc-dev-win") << D("c:/__qtc_devices__", "", "", "c:/__qtc_devices__"); + QTest::newRow("qtc-dev-type-linux") + << D("/__qtc_devices__/docker", "", "", "/__qtc_devices__/docker"); + QTest::newRow("qtc-dev-type-win") + << D("c:/__qtc_devices__/docker", "", "", "c:/__qtc_devices__/docker"); + QTest::newRow("qtc-dev-type-dev-linux") + << D("/__qtc_devices__/docker/1234", "docker", "1234", "/"); + QTest::newRow("qtc-dev-type-dev-win") + << D("c:/__qtc_devices__/docker/1234", "docker", "1234", "/"); + + // "Remote Windows" is currently truly not supported. + QTest::newRow("cross-os-linux") << D("/__qtc_devices__/docker/1234/c:/test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + QTest::newRow("cross-os-win") << D("c:/__qtc_devices__/docker/1234/c:/test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + QTest::newRow("cross-os-unclean-linux") << D("/__qtc_devices__/docker/1234/c:\\test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + QTest::newRow("cross-os-unclean-win") << D("c:/__qtc_devices__/docker/1234/c:\\test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + + QTest::newRow("unc-full-in-docker-linux") + << D("/__qtc_devices__/docker/1234//server/share/test.txt", + "docker", + "1234", + "//server/share/test.txt"); + QTest::newRow("unc-full-in-docker-win") + << D("c:/__qtc_devices__/docker/1234//server/share/test.txt", + "docker", + "1234", + "//server/share/test.txt"); + + QTest::newRow("unc-dos-1") << D("//?/c:", "", "", "//?/c:"); + QTest::newRow("unc-dos-com") << D("//./com1", "", "", "//./com1"); +} + +void tst_filepath::fromString() +{ + QFETCH(FromStringData, data); + + FilePath filePath = FilePath::fromString(data.input); + + bool expectFail = ((data.expectedPass & FailOnLinux) && !HostOsInfo::isWindowsHost()) + || ((data.expectedPass & FailOnWindows) && HostOsInfo::isWindowsHost()); + + if (expectFail) { + QString actual = filePath.scheme() + '|' + filePath.host() + '|' + filePath.path(); + QString expected = data.scheme + '|' + data.host + '|' + data.path; + QEXPECT_FAIL("", "", Continue); + QCOMPARE(actual, expected); + return; + } + + QCOMPARE(filePath.scheme(), data.scheme); + QCOMPARE(filePath.host(), data.host); + QCOMPARE(filePath.path(), data.path); +} + +void tst_filepath::fromUserInput_data() +{ + using D = FromStringData; + QTest::addColumn("data"); + + QTest::newRow("empty") << D("", "", "", ""); + QTest::newRow("single-colon") << D(":", "", "", ":"); + QTest::newRow("single-slash") << D("/", "", "", "/"); + QTest::newRow("single-char") << D("a", "", "", "a"); + QTest::newRow("relative") << D("./rel", "", "", "rel"); + QTest::newRow("qrc") << D(":/test.txt", "", "", ":/test.txt"); + QTest::newRow("qrc-no-slash") << D(":test.txt", "", "", ":test.txt"); + QTest::newRow("tilde") << D("~/", "", "", QDir::homePath()); + QTest::newRow("tilde-with-path") << D("~/foo", "", "", QDir::homePath() + "/foo"); + QTest::newRow("tilde-only") << D("~", "", "", "~"); + + QTest::newRow("unc-incomplete") << D("//", "", "", "//"); + QTest::newRow("unc-incomplete-only-server") << D("//server", "", "", "//server"); + QTest::newRow("unc-incomplete-only-server-2") << D("//server/", "", "", "//server/"); + QTest::newRow("unc-server-and-share") << D("//server/share", "", "", "//server/share"); + QTest::newRow("unc-server-and-share-2") << D("//server/share/", "", "", "//server/share"); + QTest::newRow("unc-full") << D("//server/share/test.txt", "", "", "//server/share/test.txt"); + + QTest::newRow("unix-root") << D("/", "", "", "/"); + QTest::newRow("unix-folder") << D("/tmp", "", "", "/tmp"); + QTest::newRow("unix-folder-with-trailing-slash") << D("/tmp/", "", "", "/tmp"); + + QTest::newRow("windows-root") << D("c:", "", "", "c:"); + QTest::newRow("windows-folder") << D("c:/Windows", "", "", "c:/Windows"); + QTest::newRow("windows-folder-with-trailing-slash") << D("c:\\Windows\\", "", "", "c:/Windows"); + QTest::newRow("windows-folder-slash") << D("C:/Windows", "", "", "C:/Windows"); + + QTest::newRow("docker-root-url") << D("docker://1234/", "docker", "1234", "/"); + QTest::newRow("docker-root-url-special-linux") + << D("/__qtc_devices__/docker/1234/", "docker", "1234", "/"); + QTest::newRow("docker-root-url-special-win") + << D("c:/__qtc_devices__/docker/1234/", "docker", "1234", "/"); + QTest::newRow("docker-relative-path") + << D("docker://1234/./rel", "docker", "1234", "rel", FailEverywhere); + + QTest::newRow("qtc-dev-linux") << D("/__qtc_devices__", "", "", "/__qtc_devices__"); + QTest::newRow("qtc-dev-win") << D("c:/__qtc_devices__", "", "", "c:/__qtc_devices__"); + QTest::newRow("qtc-dev-type-linux") + << D("/__qtc_devices__/docker", "", "", "/__qtc_devices__/docker"); + QTest::newRow("qtc-dev-type-win") + << D("c:/__qtc_devices__/docker", "", "", "c:/__qtc_devices__/docker"); + QTest::newRow("qtc-dev-type-dev-linux") + << D("/__qtc_devices__/docker/1234", "docker", "1234", "/"); + QTest::newRow("qtc-dev-type-dev-win") + << D("c:/__qtc_devices__/docker/1234", "docker", "1234", "/"); + + // "Remote Windows" is currently truly not supported. + QTest::newRow("cross-os-linux") << D("/__qtc_devices__/docker/1234/c:/test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + QTest::newRow("cross-os-win") << D("c:/__qtc_devices__/docker/1234/c:/test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + QTest::newRow("cross-os-unclean-linux") << D("/__qtc_devices__/docker/1234/c:\\test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + QTest::newRow("cross-os-unclean-win") << D("c:/__qtc_devices__/docker/1234/c:\\test.txt", + "docker", + "1234", + "c:/test.txt", + FailEverywhere); + + QTest::newRow("unc-full-in-docker-linux") + << D("/__qtc_devices__/docker/1234//server/share/test.txt", + "docker", + "1234", + "//server/share/test.txt", + FailEverywhere); + QTest::newRow("unc-full-in-docker-win") + << D("c:/__qtc_devices__/docker/1234//server/share/test.txt", + "docker", + "1234", + "//server/share/test.txt", + FailEverywhere); + + QTest::newRow("unc-dos-1") << D("//?/c:", "", "", "c:"); + QTest::newRow("unc-dos-com") << D("//./com1", "", "", "//./com1"); +} + +void tst_filepath::fromUserInput() +{ + QFETCH(FromStringData, data); + + FilePath filePath = FilePath::fromUserInput(data.input); + + bool expectFail = ((data.expectedPass & FailOnLinux) && !HostOsInfo::isWindowsHost()) + || ((data.expectedPass & FailOnWindows) && HostOsInfo::isWindowsHost()); + + if (expectFail) { + QString actual = filePath.scheme() + '|' + filePath.host() + '|' + filePath.path(); + QString expected = data.scheme + '|' + data.host + '|' + data.path; + QEXPECT_FAIL("", "", Continue); + QCOMPARE(actual, expected); + return; + } + + QCOMPARE(filePath.scheme(), data.scheme); + QCOMPARE(filePath.host(), data.host); + QCOMPARE(filePath.path(), data.path); +} + +void tst_filepath::fromToString_data() +{ + QTest::addColumn("scheme"); + QTest::addColumn("host"); + QTest::addColumn("path"); + QTest::addColumn("full"); + + QTest::newRow("s0") << "" + << "" + << "" + << ""; + QTest::newRow("s1") << "" + << "" + << "/" + << "/"; + QTest::newRow("s2") << "" + << "" + << "a/b/c/d" + << "a/b/c/d"; + QTest::newRow("s3") << "" + << "" + << "/a/b" + << "/a/b"; + + QTest::newRow("s4") << "docker" + << "1234abcdef" + << "/bin/ls" + << "docker://1234abcdef/bin/ls"; + QTest::newRow("s5") << "docker" + << "1234" + << "/bin/ls" + << "docker://1234/bin/ls"; + + // This is not a proper URL. + QTest::newRow("s6") << "docker" + << "1234" + << "somefile" + << "docker://1234/./somefile"; + + // Local Windows paths: + QTest::newRow("w1") << "" + << "" + << "C:/data" + << "C:/data"; + QTest::newRow("w2") << "" + << "" + << "C:/" + << "C:/"; + QTest::newRow("w3") << "" + << "" + << "/Global?\?/UNC/host" + << "/Global?\?/UNC/host"; + QTest::newRow("w4") << "" + << "" + << "//server/dir/file" + << "//server/dir/file"; +} + +void tst_filepath::fromToString() +{ + QFETCH(QString, full); + QFETCH(QString, scheme); + QFETCH(QString, host); + QFETCH(QString, path); + + FilePath filePath = FilePath::fromString(full); + + QCOMPARE(filePath.toString(), full); + + QCOMPARE(filePath.scheme(), scheme); + QCOMPARE(filePath.host(), host); + QCOMPARE(filePath.path(), path); + + FilePath copy = FilePath::fromParts(scheme, host, path); + QCOMPARE(copy.toString(), full); +} + +void tst_filepath::comparison() +{ + QFETCH(QString, left); + QFETCH(QString, right); + QFETCH(bool, hostSensitive); + QFETCH(bool, expected); + + HostOsInfo::setOverrideFileNameCaseSensitivity(hostSensitive ? Qt::CaseSensitive + : Qt::CaseInsensitive); + + FilePath l = FilePath::fromUserInput(left); + FilePath r = FilePath::fromUserInput(right); + QCOMPARE(l == r, expected); +} + +void tst_filepath::comparison_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("hostSensitive"); + QTest::addColumn("expected"); + + QTest::newRow("r1") << "Abc" + << "abc" << true << false; + QTest::newRow("r2") << "Abc" + << "abc" << false << true; + QTest::newRow("r3") << "x://y/Abc" + << "x://y/abc" << true << false; + QTest::newRow("r4") << "x://y/Abc" + << "x://y/abc" << false << false; + + QTest::newRow("s1") << "abc" + << "abc" << true << true; + QTest::newRow("s2") << "abc" + << "abc" << false << true; + QTest::newRow("s3") << "x://y/abc" + << "x://y/abc" << true << true; + QTest::newRow("s4") << "x://y/abc" + << "x://y/abc" << false << true; +} + +void tst_filepath::linkFromString() +{ + QFETCH(QString, testFile); + QFETCH(Utils::FilePath, filePath); + QFETCH(int, line); + QFETCH(int, column); + const Link link = Link::fromString(testFile, true); + QCOMPARE(link.targetFilePath, filePath); + QCOMPARE(link.targetLine, line); + QCOMPARE(link.targetColumn, column); +} + +void tst_filepath::linkFromString_data() +{ + QTest::addColumn("testFile"); + QTest::addColumn("filePath"); + QTest::addColumn("line"); + QTest::addColumn("column"); + + QTest::newRow("no-line-no-column") + << QString("someFile.txt") << FilePath("someFile.txt") << -1 << -1; + QTest::newRow(": at end") << QString::fromLatin1("someFile.txt:") << FilePath("someFile.txt") + << 0 << -1; + QTest::newRow("+ at end") << QString::fromLatin1("someFile.txt+") << FilePath("someFile.txt") + << 0 << -1; + QTest::newRow(": for column") << QString::fromLatin1("someFile.txt:10:") + << FilePath("someFile.txt") << 10 << -1; + QTest::newRow("+ for column") << QString::fromLatin1("someFile.txt:10+") + << FilePath("someFile.txt") << 10 << -1; + QTest::newRow(": and + at end") + << QString::fromLatin1("someFile.txt:+") << FilePath("someFile.txt") << 0 << -1; + QTest::newRow("empty line") << QString::fromLatin1("someFile.txt:+10") + << FilePath("someFile.txt") << 0 << 9; + QTest::newRow(":line-no-column") << QString::fromLatin1("/some/path/file.txt:42") + << FilePath("/some/path/file.txt") << 42 << -1; + QTest::newRow("+line-no-column") << QString::fromLatin1("/some/path/file.txt+42") + << FilePath("/some/path/file.txt") << 42 << -1; + QTest::newRow(":line-:column") << QString::fromLatin1("/some/path/file.txt:42:3") + << FilePath("/some/path/file.txt") << 42 << 2; + QTest::newRow(":line-+column") << QString::fromLatin1("/some/path/file.txt:42+33") + << FilePath("/some/path/file.txt") << 42 << 32; + QTest::newRow("+line-:column") << QString::fromLatin1("/some/path/file.txt+142:30") + << FilePath("/some/path/file.txt") << 142 << 29; + QTest::newRow("+line-+column") << QString::fromLatin1("/some/path/file.txt+142+33") + << FilePath("/some/path/file.txt") << 142 << 32; + QTest::newRow("( at end") << QString::fromLatin1("/some/path/file.txt(") + << FilePath("/some/path/file.txt") << -1 << -1; + QTest::newRow("(42 at end") << QString::fromLatin1("/some/path/file.txt(42") + << FilePath("/some/path/file.txt") << 42 << -1; + QTest::newRow("(42) at end") << QString::fromLatin1("/some/path/file.txt(42)") + << FilePath("/some/path/file.txt") << 42 << -1; +} + +void tst_filepath::pathAppended() +{ + QFETCH(QString, left); + QFETCH(QString, right); + QFETCH(QString, expected); + + const FilePath fleft = FilePath::fromString(left); + const FilePath fexpected = FilePath::fromString(expected); + + const FilePath result = fleft.pathAppended(right); + + QCOMPARE(result, fexpected); +} + +void tst_filepath::pathAppended_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("expected"); + + QTest::newRow("p0") << "" + << "" + << ""; + QTest::newRow("p1") << "" + << "/" + << "/"; + QTest::newRow("p2") << "" + << "c/" + << "c/"; + QTest::newRow("p3") << "" + << "/d" + << "/d"; + QTest::newRow("p4") << "" + << "c/d" + << "c/d"; + + QTest::newRow("r0") << "/" + << "" + << "/"; + QTest::newRow("r1") << "/" + << "/" + << "/"; + QTest::newRow("r2") << "/" + << "c/" + << "/c/"; + QTest::newRow("r3") << "/" + << "/d" + << "/d"; + QTest::newRow("r4") << "/" + << "c/d" + << "/c/d"; + + QTest::newRow("s0") << "/b" + << "" + << "/b"; + QTest::newRow("s1") << "/b" + << "/" + << "/b/"; + QTest::newRow("s2") << "/b" + << "c/" + << "/b/c/"; + QTest::newRow("s3") << "/b" + << "/d" + << "/b/d"; + QTest::newRow("s4") << "/b" + << "c/d" + << "/b/c/d"; + + QTest::newRow("t0") << "a/" + << "" + << "a/"; + QTest::newRow("t1") << "a/" + << "/" + << "a/"; + QTest::newRow("t2") << "a/" + << "c/" + << "a/c/"; + QTest::newRow("t3") << "a/" + << "/d" + << "a/d"; + QTest::newRow("t4") << "a/" + << "c/d" + << "a/c/d"; + + QTest::newRow("u0") << "a/b" + << "" + << "a/b"; + QTest::newRow("u1") << "a/b" + << "/" + << "a/b/"; + QTest::newRow("u2") << "a/b" + << "c/" + << "a/b/c/"; + QTest::newRow("u3") << "a/b" + << "/d" + << "a/b/d"; + QTest::newRow("u4") << "a/b" + << "c/d" + << "a/b/c/d"; + + if (HostOsInfo::isWindowsHost()) { + QTest::newRow("win-1") << "c:" + << "/a/b" + << "c:/a/b"; + QTest::newRow("win-2") << "c:/" + << "/a/b" + << "c:/a/b"; + QTest::newRow("win-3") << "c:/" + << "a/b" + << "c:/a/b"; + } +} + +void tst_filepath::resolvePath_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << FilePath() << FilePath() << FilePath(); + QTest::newRow("s0") << FilePath("/") << FilePath("b") << FilePath("/b"); + QTest::newRow("s1") << FilePath() << FilePath("b") << FilePath("b"); + QTest::newRow("s2") << FilePath("a") << FilePath() << FilePath("a"); + QTest::newRow("s3") << FilePath("a") << FilePath("b") << FilePath("a/b"); + QTest::newRow("s4") << FilePath("/a") << FilePath("/b") << FilePath("/b"); + QTest::newRow("s5") << FilePath("a") << FilePath("/b") << FilePath("/b"); + QTest::newRow("s6") << FilePath("/a") << FilePath("b") << FilePath("/a/b"); + QTest::newRow("s7") << FilePath("/a") << FilePath(".") << FilePath("/a"); + QTest::newRow("s8") << FilePath("/a") << FilePath("./b") << FilePath("/a/b"); +} + +void tst_filepath::resolvePath() +{ + QFETCH(FilePath, left); + QFETCH(FilePath, right); + QFETCH(FilePath, expected); + + const FilePath result = left.resolvePath(right); + + QCOMPARE(result, expected); +} + +void tst_filepath::relativeChildPath_data() +{ + QTest::addColumn("parent"); + QTest::addColumn("child"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << FilePath() << FilePath() << FilePath(); + + QTest::newRow("simple-0") << FilePath("/a") << FilePath("/a/b") << FilePath("b"); + QTest::newRow("simple-1") << FilePath("/a/") << FilePath("/a/b") << FilePath("b"); + QTest::newRow("simple-2") << FilePath("/a") << FilePath("/a/b/c/d/e/f") + << FilePath("b/c/d/e/f"); + + QTest::newRow("not-0") << FilePath("/x") << FilePath("/a/b") << FilePath(); + QTest::newRow("not-1") << FilePath("/a/b/c") << FilePath("/a/b") << FilePath(); +} + +void tst_filepath::relativeChildPath() +{ + QFETCH(FilePath, parent); + QFETCH(FilePath, child); + QFETCH(FilePath, expected); + + const FilePath result = child.relativeChildPath(parent); + + QCOMPARE(result, expected); +} + +void tst_filepath::asyncLocalCopy() +{ + const FilePath orig = FilePath::fromString(rootPath).pathAppended("x/y/fileToCopy.txt"); + QVERIFY(orig.exists()); + const FilePath dest = FilePath::fromString(rootPath).pathAppended("x/fileToCopyDest.txt"); + bool wasCalled = false; + auto afterCopy = [&orig, &dest, &wasCalled](expected_str result) { + QVERIFY(result); + // check existence, size and content + QVERIFY(dest.exists()); + QCOMPARE(dest.fileSize(), orig.fileSize()); + QCOMPARE(dest.fileContents(), orig.fileContents()); + wasCalled = true; + }; + orig.asyncCopyFile(afterCopy, dest); + QCOMPARE(wasCalled, true); +} + +void tst_filepath::startsWithDriveLetter_data() +{ + QTest::addColumn("path"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << FilePath() << false; + QTest::newRow("simple-win") << FilePath::fromString("c:/a") << true; + QTest::newRow("simple-linux") << FilePath::fromString("/c:/a") << false; + QTest::newRow("relative") << FilePath("a/b") << false; +} + +void tst_filepath::startsWithDriveLetter() +{ + QFETCH(FilePath, path); + QFETCH(bool, expected); + + QCOMPARE(path.startsWithDriveLetter(), expected); +} + +void tst_filepath::onDevice_data() +{ + QTest::addColumn("path"); + QTest::addColumn("templatePath"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << FilePath() << FilePath() << FilePath(); + QTest::newRow("same-local") << FilePath("/a/b") << FilePath("/a/b") << FilePath("/a/b"); + QTest::newRow("same-docker") << FilePath("docker://1234/a/b") << FilePath("docker://1234/e") + << FilePath("docker://1234/a/b"); + + QTest::newRow("docker-to-local") + << FilePath("docker://1234/a/b") << FilePath("/c/d") << FilePath("/a/b"); + QTest::newRow("local-to-docker") + << FilePath("/a/b") << FilePath("docker://1234/c/d") << FilePath("docker://1234/a/b"); +} + +void tst_filepath::onDevice() +{ + QFETCH(FilePath, path); + QFETCH(FilePath, templatePath); + QFETCH(FilePath, expected); + + QCOMPARE(path.onDevice(templatePath), expected); +} + +void tst_filepath::stringAppended_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << FilePath() << QString() << FilePath(); + QTest::newRow("empty-left") << FilePath() << "a" << FilePath("a"); + QTest::newRow("empty-right") << FilePath("a") << QString() << FilePath("a"); + QTest::newRow("add-root") << FilePath() << QString("/") << FilePath("/"); + QTest::newRow("add-root-and-more") + << FilePath() << QString("/test/blah") << FilePath("/test/blah"); + QTest::newRow("add-extension") + << FilePath::fromString("/a") << QString(".txt") << FilePath("/a.txt"); + QTest::newRow("trailing-slash") + << FilePath::fromString("/a") << QString("b/") << FilePath("/ab/"); + QTest::newRow("slash-trailing-slash") + << FilePath::fromString("/a/") << QString("b/") << FilePath("/a/b/"); +} + +void tst_filepath::stringAppended() +{ + QFETCH(FilePath, left); + QFETCH(QString, right); + QFETCH(FilePath, expected); + + const FilePath result = left.stringAppended(right); + + QCOMPARE(expected, result); +} + +void tst_filepath::url() +{ + QFETCH(QString, url); + QFETCH(QString, expectedScheme); + QFETCH(QString, expectedHost); + QFETCH(QString, expectedPath); + + const FilePath result = FilePath::fromString(url); + QCOMPARE(result.scheme(), expectedScheme); + QCOMPARE(result.host(), expectedHost); + QCOMPARE(result.path(), expectedPath); +} + +void tst_filepath::url_data() +{ + QTest::addColumn("url"); + QTest::addColumn("expectedScheme"); + QTest::addColumn("expectedHost"); + QTest::addColumn("expectedPath"); + QTest::newRow("empty") << QString() << QString() << QString() << QString(); + QTest::newRow("simple-file") << QString("file:///a/b") << QString("file") << QString() + << QString("/a/b"); + QTest::newRow("simple-file-root") + << QString("file:///") << QString("file") << QString() << QString("/"); + QTest::newRow("simple-docker") + << QString("docker://1234/a/b") << QString("docker") << QString("1234") << QString("/a/b"); + QTest::newRow("simple-ssh") << QString("ssh://user@host/a/b") << QString("ssh") + << QString("user@host") << QString("/a/b"); + QTest::newRow("simple-ssh-with-port") << QString("ssh://user@host:1234/a/b") << QString("ssh") + << QString("user@host:1234") << QString("/a/b"); + QTest::newRow("http-qt.io") << QString("http://qt.io") << QString("http") << QString("qt.io") + << QString(); + QTest::newRow("http-qt.io-index.html") << QString("http://qt.io/index.html") << QString("http") + << QString("qt.io") << QString("/index.html"); +} + +void tst_filepath::cleanPath_data() +{ + QTest::addColumn("path"); + QTest::addColumn("expected"); + + QTest::newRow("data0") << "/Users/sam/troll/qt4.0//.." + << "/Users/sam/troll"; + QTest::newRow("data1") << "/Users/sam////troll/qt4.0//.." + << "/Users/sam/troll"; + QTest::newRow("data2") << "/" + << "/"; + QTest::newRow("data2-up") << "/path/.." + << "/"; + QTest::newRow("data2-above-root") << "/.." + << "/.."; + QTest::newRow("data3") << QDir::cleanPath("../.") << ".."; + QTest::newRow("data4") << QDir::cleanPath("../..") << "../.."; + QTest::newRow("data5") << "d:\\a\\bc\\def\\.." + << "d:/a/bc"; // QDir/Linux had: "d:\\a\\bc\\def\\.." + QTest::newRow("data6") << "d:\\a\\bc\\def\\../../.." + << "d:/"; // QDir/Linux had: ".." + QTest::newRow("data7") << ".//file1.txt" + << "file1.txt"; + QTest::newRow("data8") << "/foo/bar/..//file1.txt" + << "/foo/file1.txt"; + QTest::newRow("data9") << "//" + << "//"; // QDir had: "/" + QTest::newRow("data10w") << "c:\\" + << "c:/"; + QTest::newRow("data10l") << "/:/" + << "/:"; + QTest::newRow("data11") << "//foo//bar" + << "//foo/bar"; // QDir/Win had: "//foo/bar" + QTest::newRow("data12") << "ab/a/" + << "ab/a"; // Path item with length of 2 + QTest::newRow("data13w") << "c:/" + << "c:/"; + QTest::newRow("data13w2") << "c:\\" + << "c:/"; + //QTest::newRow("data13l") << "c://" << "c:"; + + // QTest::newRow("data14") << "c://foo" << "c:/foo"; + QTest::newRow("data15") << "//c:/foo" + << "//c:/foo"; // QDir/Lin had: "/c:/foo"; + QTest::newRow("drive-up") << "A:/path/.." + << "A:/"; + QTest::newRow("drive-above-root") << "A:/.." + << "A:/.."; + QTest::newRow("unc-server-up") << "//server/path/.." + << "//server/"; + QTest::newRow("unc-server-above-root") << "//server/.." + << "//server/.."; + + QTest::newRow("longpath") << "\\\\?\\d:\\" + << "d:/"; + QTest::newRow("longpath-slash") << "//?/d:/" + << "d:/"; + QTest::newRow("longpath-mixed-slashes") << "//?/d:\\" + << "d:/"; + QTest::newRow("longpath-mixed-slashes-2") << "\\\\?\\d:/" + << "d:/"; + + QTest::newRow("unc-network-share") << "\\\\?\\UNC\\localhost\\c$\\tmp.txt" + << "//localhost/c$/tmp.txt"; + QTest::newRow("unc-network-share-slash") << "//?/UNC/localhost/c$/tmp.txt" + << "//localhost/c$/tmp.txt"; + QTest::newRow("unc-network-share-mixed-slashes") << "//?/UNC/localhost\\c$\\tmp.txt" + << "//localhost/c$/tmp.txt"; + QTest::newRow("unc-network-share-mixed-slashes-2") << "\\\\?\\UNC\\localhost/c$/tmp.txt" + << "//localhost/c$/tmp.txt"; + + QTest::newRow("QTBUG-23892_0") << "foo/.." + << "."; + QTest::newRow("QTBUG-23892_1") << "foo/../" + << "."; + + QTest::newRow("QTBUG-3472_0") << "/foo/./bar" + << "/foo/bar"; + QTest::newRow("QTBUG-3472_1") << "./foo/.." + << "."; + QTest::newRow("QTBUG-3472_2") << "./foo/../" + << "."; + + QTest::newRow("resource0") << ":/prefix/foo.bar" + << ":/prefix/foo.bar"; + QTest::newRow("resource1") << ":/prefix/..//prefix/foo.bar" + << ":/prefix/foo.bar"; + + QTest::newRow("ssh") << "ssh://host/prefix/../foo.bar" + << "ssh://host/foo.bar"; + QTest::newRow("ssh2") << "ssh://host/../foo.bar" + << "ssh://host/../foo.bar"; +} + +void tst_filepath::cleanPath() +{ + QFETCH(QString, path); + QFETCH(QString, expected); + QString cleaned = doCleanPath(path); + QCOMPARE(cleaned, expected); +} + +void tst_filepath::isSameFile_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("shouldBeEqual"); + + QTest::addRow("/==/") << FilePath::fromString("/") << FilePath::fromString("/") << true; + QTest::addRow("/!=tmp") << FilePath::fromString("/") << FilePath::fromString(tempDir.path()) + << false; + + QDir dir(tempDir.path()); + touch(dir, "target-file", false); + + QFile file(dir.absoluteFilePath("target-file")); + if (file.link(dir.absoluteFilePath("source-file"))) { + QTest::addRow("real==link") + << FilePath::fromString(file.fileName()) + << FilePath::fromString(dir.absoluteFilePath("target-file")) << true; + } + + QTest::addRow("/!=non-existing") + << FilePath::fromString("/") << FilePath::fromString("/this-path/does-not-exist") << false; + + QTest::addRow("two-devices") << FilePath::fromString( + "docker://boot2qt-raspberrypi4-64:6.5.0/opt/toolchain/sysroots/aarch64-pokysdk-linux/usr/" + "bin/aarch64-poky-linux/aarch64-poky-linux-g++") + << FilePath::fromString("docker://qt-linux:6/usr/bin/g++") + << false; +} + +void tst_filepath::isSameFile() +{ + QFETCH(FilePath, left); + QFETCH(FilePath, right); + QFETCH(bool, shouldBeEqual); + + QCOMPARE(left.isSameFile(right), shouldBeEqual); +} + +void tst_filepath::hostSpecialChars_data() +{ + QTest::addColumn("scheme"); + QTest::addColumn("host"); + QTest::addColumn("path"); + QTest::addColumn("expected"); + + QTest::addRow("slash-in-host") << "device" + << "host/name" + << "/" << FilePath::fromString("device://host%2fname/"); + QTest::addRow("percent-in-host") << "device" + << "host%name" + << "/" << FilePath::fromString("device://host%25name/"); + QTest::addRow("percent-and-slash-in-host") + << "device" + << "host/%name" + << "/" << FilePath::fromString("device://host%2f%25name/"); + QTest::addRow("qtc-dev-slash-in-host-linux") + << "device" + << "host/name" + << "/" << FilePath::fromString("/__qtc_devices__/device/host%2fname/"); + QTest::addRow("qtc-dev-slash-in-host-windows") + << "device" + << "host/name" + << "/" << FilePath::fromString("c:/__qtc_devices__/device/host%2fname/"); +} + +void tst_filepath::hostSpecialChars() +{ + QFETCH(QString, scheme); + QFETCH(QString, host); + QFETCH(QString, path); + QFETCH(FilePath, expected); + + FilePath fp; + fp.setParts(scheme, host, path); + + // Check that setParts and fromString give the same result + QCOMPARE(fp, expected); + QCOMPARE(fp.host(), expected.host()); + QCOMPARE(fp.host(), host); + QCOMPARE(expected.host(), host); + + QString toStringExpected = expected.toString(); + QString toStringActual = fp.toString(); + + // Check that toString gives the same result + QCOMPARE(toStringActual, toStringExpected); + + // Check that fromString => toString => fromString gives the same result + FilePath toFromExpected = FilePath::fromString(expected.toString()); + QCOMPARE(toFromExpected, expected); + QCOMPARE(toFromExpected, fp); + + // Check that setParts => toString => fromString gives the same result + FilePath toFromActual = FilePath::fromString(fp.toString()); + QCOMPARE(toFromActual, fp); + QCOMPARE(toFromExpected, expected); +} + +void tst_filepath::tmp_data() +{ + QTest::addColumn("templatepath"); + QTest::addColumn("expected"); + + QTest::addRow("empty") << "" << true; + QTest::addRow("no-template") << "foo" << true; + QTest::addRow("realtive-template") << "my-file-XXXXXXXX" << true; + QTest::addRow("absolute-template") << QDir::tempPath() + "/my-file-XXXXXXXX" << true; + QTest::addRow("non-existing-dir") << "/this/path/does/not/exist/my-file-XXXXXXXX" << false; + + QTest::addRow("on-device") << "device://test/./my-file-XXXXXXXX" << true; +} + +void tst_filepath::tmp() +{ + QFETCH(QString, templatepath); + QFETCH(bool, expected); + + FilePath fp = FilePath::fromString(templatepath); + + const auto result = fp.createTempFile(); + QCOMPARE(result.has_value(), expected); + + if (result.has_value()) { + QVERIFY(result->exists()); + QVERIFY(result->removeFile()); + } +} + +QTEST_GUILESS_MAIN(tst_filepath) + +#include "tst_filepath.moc" diff --git a/tests/auto/utils/fileutils/tst_fileutils.cpp b/tests/auto/utils/fileutils/tst_fileutils.cpp index 46461072e97..c4553eac645 100644 --- a/tests/auto/utils/fileutils/tst_fileutils.cpp +++ b/tests/auto/utils/fileutils/tst_fileutils.cpp @@ -1,13 +1,10 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include -#include #include #include #include -#include //TESTED_COMPONENT=src/libs/utils using namespace Utils; @@ -24,973 +21,20 @@ class tst_fileutils : public QObject { Q_OBJECT -signals: - void asyncTestDone(); // test internal helper signal - private slots: void initTestCase(); - void isEmpty_data(); - void isEmpty(); - - void parentDir_data(); - void parentDir(); - - void isChildOf_data(); - void isChildOf(); - - void fileName_data(); - void fileName(); - - void calcRelativePath_data(); - void calcRelativePath(); - - void relativePath_specials(); - void relativePath_data(); - void relativePath(); - - void absolute_data(); - void absolute(); - - void fromToString_data(); - void fromToString(); - - void fromString_data(); - void fromString(); - - void fromUserInput_data(); - void fromUserInput(); - - void toString_data(); - void toString(); - - void toFSPathString_data(); - void toFSPathString(); - - void comparison_data(); - void comparison(); - - void linkFromString_data(); - void linkFromString(); - - void pathAppended_data(); - void pathAppended(); - void commonPath_data(); void commonPath(); - void resolvePath_data(); - void resolvePath(); - - void relativeChildPath_data(); - void relativeChildPath(); - void bytesAvailableFromDF_data(); void bytesAvailableFromDF(); - void rootLength_data(); - void rootLength(); - - void schemeAndHostLength_data(); - void schemeAndHostLength(); - - void asyncLocalCopy(); - void startsWithDriveLetter(); - void startsWithDriveLetter_data(); - - void onDevice_data(); - void onDevice(); - - void stringAppended(); - void stringAppended_data(); - void url(); - void url_data(); - - void cleanPath_data(); - void cleanPath(); - - void isSameFile_data(); - void isSameFile(); - - void hostSpecialChars_data(); - void hostSpecialChars(); - - void tmp_data(); - void tmp(); - void filePathInfoFromTriple_data(); void filePathInfoFromTriple(); - -private: - QTemporaryDir tempDir; - QString rootPath; }; -static void touch(const QDir &dir, const QString &filename, bool fill) -{ - QFile file(dir.absoluteFilePath(filename)); - file.open(QIODevice::WriteOnly); - if (fill) { - QRandomGenerator *random = QRandomGenerator::global(); - for (int i = 0; i < 10; ++i) - file.write(QString::number(random->generate(), 16).toUtf8()); - } - file.close(); -} - -void tst_fileutils::initTestCase() -{ - // initialize test for tst_fileutiles::relativePath*() - QVERIFY(tempDir.isValid()); - rootPath = tempDir.path(); - QDir dir(rootPath); - dir.mkpath("a/b/c/d"); - dir.mkpath("a/x/y/z"); - dir.mkpath("a/b/x/y/z"); - dir.mkpath("x/y/z"); - touch(dir, "a/b/c/d/file1.txt", false); - touch(dir, "a/x/y/z/file2.txt", false); - touch(dir, "a/file3.txt", false); - touch(dir, "x/y/file4.txt", false); - - // initialize test for tst_fileutils::asyncLocalCopy() - touch(dir, "x/y/fileToCopy.txt", true); -} - -void tst_fileutils::isEmpty_data() -{ - QTest::addColumn("path"); - QTest::addColumn("result"); - - QTest::newRow("empty path") << "" << true; - QTest::newRow("root only") << "/" << false; - QTest::newRow("//") << "//" << false; - QTest::newRow("scheme://host") << "scheme://host" << true; // Intentional (for now?) - QTest::newRow("scheme://host/") << "scheme://host/" << false; - QTest::newRow("scheme://host/a") << "scheme://host/a" << false; - QTest::newRow("scheme://host/.") << "scheme://host/." << false; -} - -void tst_fileutils::isEmpty() -{ - QFETCH(QString, path); - QFETCH(bool, result); - - FilePath filePath = FilePath::fromString(path); - QCOMPARE(filePath.isEmpty(), result); -} - -void tst_fileutils::parentDir_data() -{ - QTest::addColumn("path"); - QTest::addColumn("parentPath"); - QTest::addColumn("expectFailMessage"); - - QTest::newRow("empty path") << "" << "" << ""; - QTest::newRow("root only") << "/" << "" << ""; - QTest::newRow("//") << "//" << "" << ""; - QTest::newRow("/tmp/dir") << "/tmp/dir" << "/tmp" << ""; - QTest::newRow("relative/path") << "relative/path" << "relative" << ""; - QTest::newRow("relativepath") << "relativepath" << "." << ""; - - // Windows stuff: - QTest::newRow("C:/data") << "C:/data" << "C:/" << ""; - QTest::newRow("C:/") << "C:/" << "" << ""; - QTest::newRow("//./com1") << "//./com1" << "//./" << ""; - QTest::newRow("//?/path") << "//?/path" << "/" << "Qt 4 cannot handle this path."; - QTest::newRow("/Global?\?/UNC/host") << "/Global?\?/UNC/host" << "/Global?\?/UNC/host" - << "Qt 4 cannot handle this path."; - QTest::newRow("//server/directory/file") - << "//server/directory/file" << "//server/directory" << ""; - QTest::newRow("//server/directory") << "//server/directory" << "//server/" << ""; - QTest::newRow("//server") << "//server" << "" << ""; - - QTest::newRow("qrc") << ":/foo/bar.txt" << ":/foo" << ""; -} - -void tst_fileutils::parentDir() -{ - QFETCH(QString, path); - QFETCH(QString, parentPath); - QFETCH(QString, expectFailMessage); - - FilePath result = FilePath::fromUserInput(path).parentDir(); - if (!expectFailMessage.isEmpty()) - QEXPECT_FAIL("", expectFailMessage.toUtf8().constData(), Continue); - QCOMPARE(result.toString(), parentPath); -} - -void tst_fileutils::isChildOf_data() -{ - QTest::addColumn("path"); - QTest::addColumn("childPath"); - QTest::addColumn("result"); - - QTest::newRow("empty path") << "" << "/tmp" << false; - QTest::newRow("root only") << "/" << "/tmp" << true; - QTest::newRow("/tmp/dir") << "/tmp" << "/tmp/dir" << true; - QTest::newRow("relative/path") << "relative" << "relative/path" << true; - QTest::newRow("/tmpdir") << "/tmp" << "/tmpdir" << false; - QTest::newRow("same") << "/tmp/dir" << "/tmp/dir" << false; - - // Windows stuff: - QTest::newRow("C:/data") << "C:/" << "C:/data" << true; - QTest::newRow("C:/") << "" << "C:/" << false; - QTest::newRow("com-port") << "//./" << "//./com1" << true; - QTest::newRow("extended-length-path") << "\\\\?\\C:\\" << "\\\\?\\C:\\path" << true; - QTest::newRow("/Global?\?/UNC/host") << "/Global?\?/UNC/host" - << "/Global?\?/UNC/host/file" << true; - QTest::newRow("//server/directory/file") - << "//server/directory" << "//server/directory/file" << true; - QTest::newRow("//server/directory") - << "//server" << "//server/directory" << true; - - QTest::newRow("qrc") << ":/foo/bar" << ":/foo/bar/blah" << true; -} - -void tst_fileutils::isChildOf() -{ - QFETCH(QString, path); - QFETCH(QString, childPath); - QFETCH(bool, result); - - const FilePath child = FilePath::fromUserInput(childPath); - const FilePath parent = FilePath::fromUserInput(path); - - QCOMPARE(child.isChildOf(parent), result); -} - -void tst_fileutils::fileName_data() -{ - QTest::addColumn("path"); - QTest::addColumn("components"); - QTest::addColumn("result"); - - QTest::newRow("empty 1") << "" << 0 << ""; - QTest::newRow("empty 2") << "" << 1 << ""; - QTest::newRow("basic") << "/foo/bar/baz" << 0 << "baz"; - QTest::newRow("2 parts") << "/foo/bar/baz" << 1 << "bar/baz"; - QTest::newRow("root no depth") << "/foo" << 0 << "foo"; - QTest::newRow("root full") << "/foo" << 1 << "/foo"; - QTest::newRow("root included") << "/foo/bar/baz" << 2 << "/foo/bar/baz"; - QTest::newRow("too many parts") << "/foo/bar/baz" << 5 << "/foo/bar/baz"; - QTest::newRow("windows root") << "C:/foo/bar/baz" << 2 << "C:/foo/bar/baz"; - QTest::newRow("smb share") << "//server/share/file" << 2 << "//server/share/file"; - QTest::newRow("no slashes") << "foobar" << 0 << "foobar"; - QTest::newRow("no slashes with depth") << "foobar" << 1 << "foobar"; - QTest::newRow("multiple slashes 1") << "/foo/bar////baz" << 0 << "baz"; - QTest::newRow("multiple slashes 2") << "/foo/bar////baz" << 1 << "bar////baz"; - QTest::newRow("multiple slashes 3") << "/foo////bar/baz" << 2 << "/foo////bar/baz"; - QTest::newRow("single char 1") << "/a/b/c" << 0 << "c"; - QTest::newRow("single char 2") << "/a/b/c" << 1 << "b/c"; - QTest::newRow("single char 3") << "/a/b/c" << 2 << "/a/b/c"; - QTest::newRow("slash at end 1") << "/a/b/" << 0 << ""; - QTest::newRow("slash at end 2") << "/a/b/" << 1 << "b/"; - QTest::newRow("slashes at end 1") << "/a/b//" << 0 << ""; - QTest::newRow("slashes at end 2") << "/a/b//" << 1 << "b//"; - QTest::newRow("root only 1") << "/" << 0 << ""; - QTest::newRow("root only 2") << "/" << 1 << "/"; - QTest::newRow("qrc 0") << ":/foo/bar" << 0 << "bar"; - QTest::newRow("qrc with root") << ":/foo/bar" << 1 << ":/foo/bar"; -} - -void tst_fileutils::fileName() -{ - QFETCH(QString, path); - QFETCH(int, components); - QFETCH(QString, result); - QCOMPARE(FilePath::fromString(path).fileNameWithPathComponents(components), result); -} - -void tst_fileutils::calcRelativePath_data() -{ - QTest::addColumn("absolutePath"); - QTest::addColumn("anchorPath"); - QTest::addColumn("result"); - - QTest::newRow("empty") << "" << "" << ""; - QTest::newRow("leftempty") << "" << "/" << ""; - QTest::newRow("rightempty") << "/" << "" << ""; - QTest::newRow("root") << "/" << "/" << "."; - QTest::newRow("simple1") << "/a" << "/" << "a"; - QTest::newRow("simple2") << "/" << "/a" << ".."; - QTest::newRow("simple3") << "/a" << "/a" << "."; - QTest::newRow("extraslash1") << "/a/b/c" << "/a/b/c" << "."; - QTest::newRow("extraslash2") << "/a/b/c" << "/a/b/c/" << "."; - QTest::newRow("extraslash3") << "/a/b/c/" << "/a/b/c" << "."; - QTest::newRow("normal1") << "/a/b/c" << "/a/x" << "../b/c"; - QTest::newRow("normal2") << "/a/b/c" << "/a/x/y" << "../../b/c"; - QTest::newRow("normal3") << "/a/b/c" << "/x/y" << "../../a/b/c"; -} - -void tst_fileutils::calcRelativePath() -{ - QFETCH(QString, absolutePath); - QFETCH(QString, anchorPath); - QFETCH(QString, result); - QString relativePath = Utils::FilePath::calcRelativePath(absolutePath, anchorPath); - QCOMPARE(relativePath, result); -} - -void tst_fileutils::relativePath_specials() -{ - QString path = FilePath("").relativePathFrom("").toString(); - QCOMPARE(path, ""); -} - -void tst_fileutils::relativePath_data() -{ - QTest::addColumn("relative"); - QTest::addColumn("anchor"); - QTest::addColumn("result"); - - QTest::newRow("samedir") << "/" << "/" << "."; - QTest::newRow("samedir_but_file") << "a/b/c/d/file1.txt" << "a/b/c/d" << "file1.txt"; - QTest::newRow("samedir_but_file2") << "a/b/c/d" << "a/b/c/d/file1.txt" << "."; - QTest::newRow("dir2dir_1") << "a/b/c/d" << "a/x/y/z" << "../../../b/c/d"; - QTest::newRow("dir2dir_2") << "a/b" <<"a/b/c" << ".."; - QTest::newRow("file2file_1") << "a/b/c/d/file1.txt" << "a/file3.txt" << "b/c/d/file1.txt"; - QTest::newRow("dir2file_1") << "a/b/c" << "a/x/y/z/file2.txt" << "../../../b/c"; - QTest::newRow("file2dir_1") << "a/b/c/d/file1.txt" << "x/y" << "../../a/b/c/d/file1.txt"; -} - -void tst_fileutils::relativePath() -{ - QFETCH(QString, relative); - QFETCH(QString, anchor); - QFETCH(QString, result); - FilePath actualPath = FilePath::fromString(rootPath + "/" + relative) - .relativePathFrom(FilePath::fromString(rootPath + "/" + anchor)); - QCOMPARE(actualPath.toString(), result); -} - -void tst_fileutils::rootLength_data() -{ - QTest::addColumn("path"); - QTest::addColumn("result"); - - QTest::newRow("empty") << "" << 0; - QTest::newRow("slash") << "/" << 1; - QTest::newRow("slash-rest") << "/abc" << 1; - QTest::newRow("rest") << "abc" << 0; - QTest::newRow("drive-slash") << "x:/" << 3; - QTest::newRow("drive-rest") << "x:abc" << 0; - QTest::newRow("drive-slash-rest") << "x:/abc" << 3; - - QTest::newRow("unc-root") << "//" << 2; - QTest::newRow("unc-localhost-unfinished") << "//localhost" << 11; - QTest::newRow("unc-localhost") << "//localhost/" << 12; - QTest::newRow("unc-localhost-rest") << "//localhost/abs" << 12; - QTest::newRow("unc-localhost-drive") << "//localhost/c$" << 12; - QTest::newRow("unc-localhost-drive-slash") << "//localhost//c$/" << 12; - QTest::newRow("unc-localhost-drive-slash-rest") << "//localhost//c$/x" << 12; -} - -void tst_fileutils::rootLength() -{ - QFETCH(QString, path); - QFETCH(int, result); - - int actual = FilePath::rootLength(path); - QCOMPARE(actual, result); -} - -void tst_fileutils::schemeAndHostLength_data() -{ - QTest::addColumn("path"); - QTest::addColumn("result"); - - QTest::newRow("empty") << "" << 0; - QTest::newRow("drive-slash-rest") << "x:/abc" << 0; - QTest::newRow("rest") << "abc" << 0; - QTest::newRow("slash-rest") << "/abc" << 0; - QTest::newRow("dev-empty") << "dev://" << 6; - QTest::newRow("dev-localhost-unfinished") << "dev://localhost" << 15; - QTest::newRow("dev-localhost") << "dev://localhost/" << 16; - QTest::newRow("dev-localhost-rest") << "dev://localhost/abs" << 16; - QTest::newRow("dev-localhost-drive") << "dev://localhost/c$" << 16; - QTest::newRow("dev-localhost-drive-slash") << "dev://localhost//c$/" << 16; - QTest::newRow("dev-localhost-drive-slash-rest") << "dev://localhost//c$/x" << 16; -} - -void tst_fileutils::schemeAndHostLength() -{ - QFETCH(QString, path); - QFETCH(int, result); - - int actual = FilePath::schemeAndHostLength(path); - QCOMPARE(actual, result); -} - -void tst_fileutils::absolute_data() -{ - QTest::addColumn("path"); - QTest::addColumn("absoluteFilePath"); - QTest::addColumn("absolutePath"); - - QTest::newRow("absolute1") << FilePath::fromString("/") - << FilePath::fromString("/") - << FilePath::fromString("/"); - QTest::newRow("absolute2") << FilePath::fromString("C:/a/b") - << FilePath::fromString("C:/a/b") - << FilePath::fromString("C:/a"); - QTest::newRow("absolute3") << FilePath::fromString("/a/b") - << FilePath::fromString("/a/b") - << FilePath::fromString("/a"); - QTest::newRow("absolute4") << FilePath::fromString("/a/b/..") - << FilePath::fromString("/a") - << FilePath::fromString("/"); - QTest::newRow("absolute5") << FilePath::fromString("/a/b/c/../d") - << FilePath::fromString("/a/b/d") - << FilePath::fromString("/a/b"); - QTest::newRow("absolute6") << FilePath::fromString("/a/../b/c/d") - << FilePath::fromString("/b/c/d") - << FilePath::fromString("/b/c"); - QTest::newRow("default-constructed") << FilePath() << FilePath() << FilePath(); - QTest::newRow("relative") << FilePath::fromString("a/b") - << FilePath::fromString(QDir::currentPath() + "/a/b") - << FilePath::fromString(QDir::currentPath() + "/a"); - QTest::newRow("qrc") << FilePath::fromString(":/foo/bar.txt") - << FilePath::fromString(":/foo/bar.txt") - << FilePath::fromString(":/foo"); -} - -void tst_fileutils::absolute() -{ - QFETCH(FilePath, path); - QFETCH(FilePath, absoluteFilePath); - QFETCH(FilePath, absolutePath); - QCOMPARE(path.absoluteFilePath(), absoluteFilePath); - QCOMPARE(path.absolutePath(), absolutePath); -} - -void tst_fileutils::toString_data() -{ - QTest::addColumn("scheme"); - QTest::addColumn("host"); - QTest::addColumn("path"); - QTest::addColumn("result"); - QTest::addColumn("userResult"); - - QTest::newRow("empty") << "" << "" << "" << "" << ""; - QTest::newRow("scheme") << "http" - << "" - << "" - << "http://" - << "http://"; - QTest::newRow("scheme-and-host") << "http" - << "127.0.0.1" - << "" - << "http://127.0.0.1" - << "http://127.0.0.1"; - QTest::newRow("root") << "http" << "127.0.0.1" << "/" << "http://127.0.0.1/" << "http://127.0.0.1/"; - - QTest::newRow("root-folder") << "" << "" << "/" << "/" << "/"; - QTest::newRow("qtc-dev-root-folder-linux") << "" << "" << "/__qtc_devices__" << "/__qtc_devices__" << "/__qtc_devices__"; - QTest::newRow("qtc-dev-root-folder-win") << "" << "" << "c:/__qtc_devices__" << "c:/__qtc_devices__" << "c:/__qtc_devices__"; - QTest::newRow("qtc-dev-type-root-folder-linux") << "" << "" << "/__qtc_devices__/docker" << "/__qtc_devices__/docker" << "/__qtc_devices__/docker"; - QTest::newRow("qtc-dev-type-root-folder-win") << "" << "" << "c:/__qtc_devices__/docker" << "c:/__qtc_devices__/docker" << "c:/__qtc_devices__/docker"; - QTest::newRow("qtc-root-folder") << "docker" << "alpine:latest" << "/" << "docker://alpine:latest/" << "docker://alpine:latest/"; - QTest::newRow("qtc-root-folder-rel") << "docker" - << "alpine:latest" - << "" - << "docker://alpine:latest" - << "docker://alpine:latest"; -} - -void tst_fileutils::toString() -{ - QFETCH(QString, scheme); - QFETCH(QString, host); - QFETCH(QString, path); - QFETCH(QString, result); - QFETCH(QString, userResult); - - FilePath filePath = FilePath::fromParts(scheme, host, path); - QCOMPARE(filePath.toString(), result); - QString cleanedOutput = filePath.needsDevice() ? filePath.toUserOutput() : QDir::cleanPath(filePath.toUserOutput()); - QCOMPARE(cleanedOutput, userResult); -} - -void tst_fileutils::toFSPathString_data() -{ - QTest::addColumn("scheme"); - QTest::addColumn("host"); - QTest::addColumn("path"); - QTest::addColumn("result"); - QTest::addColumn("userResult"); - - QTest::newRow("empty") << "" << "" << "" << "" << ""; - QTest::newRow("scheme") << "http" - << "" - << "" << QDir::rootPath() + "__qtc_devices__/http/" - << "http://"; - QTest::newRow("scheme-and-host") << "http" - << "127.0.0.1" - << "" << QDir::rootPath() + "__qtc_devices__/http/127.0.0.1" - << "http://127.0.0.1"; - QTest::newRow("root") << "http" << "127.0.0.1" << "/" << QDir::rootPath() + "__qtc_devices__/http/127.0.0.1/" << "http://127.0.0.1/"; - - QTest::newRow("root-folder") << "" << "" << "/" << "/" << "/"; - QTest::newRow("qtc-dev-root-folder") << "" << "" << QDir::rootPath() + "__qtc_devices__" << QDir::rootPath() + "__qtc_devices__" << QDir::rootPath() + "__qtc_devices__"; - QTest::newRow("qtc-dev-type-root-folder") << "" << "" << QDir::rootPath() + "__qtc_devices__/docker" << QDir::rootPath() + "__qtc_devices__/docker" << QDir::rootPath() + "__qtc_devices__/docker"; - QTest::newRow("qtc-root-folder") << "docker" << "alpine:latest" << "/" << QDir::rootPath() + "__qtc_devices__/docker/alpine:latest/" << "docker://alpine:latest/"; - QTest::newRow("qtc-root-folder-rel") - << "docker" - << "alpine:latest" - << "" << QDir::rootPath() + "__qtc_devices__/docker/alpine:latest" - << "docker://alpine:latest"; -} - -void tst_fileutils::toFSPathString() -{ - QFETCH(QString, scheme); - QFETCH(QString, host); - QFETCH(QString, path); - QFETCH(QString, result); - QFETCH(QString, userResult); - - FilePath filePath = FilePath::fromParts(scheme, host, path); - QCOMPARE(filePath.toFSPathString(), result); - QString cleanedOutput = filePath.needsDevice() ? filePath.toUserOutput() : QDir::cleanPath(filePath.toUserOutput()); - QCOMPARE(cleanedOutput, userResult); -} - -enum ExpectedPass -{ - PassEverywhere = 0, - FailOnWindows = 1, - FailOnLinux = 2, - FailEverywhere = 3 -}; - -class FromStringData -{ -public: - FromStringData(const QString &input, const QString &scheme, const QString &host, - const QString &path, ExpectedPass expectedPass = PassEverywhere) - : input(input), scheme(scheme), host(host), - path(path), expectedPass(expectedPass) - {} - - QString input; - QString scheme; - QString host; - QString path; - ExpectedPass expectedPass = PassEverywhere; -}; - -Q_DECLARE_METATYPE(FromStringData); - -void tst_fileutils::fromString_data() -{ - using D = FromStringData; - QTest::addColumn("data"); - - QTest::newRow("empty") << D("", "", "", ""); - QTest::newRow("single-colon") << D(":", "", "", ":"); - QTest::newRow("single-slash") << D("/", "", "", "/"); - QTest::newRow("single-char") << D("a", "", "", "a"); - QTest::newRow("relative") << D("./rel", "", "", "./rel"); - QTest::newRow("qrc") << D(":/test.txt", "", "", ":/test.txt"); - QTest::newRow("qrc-no-slash") << D(":test.txt", "", "", ":test.txt"); - - QTest::newRow("unc-incomplete") << D("//", "", "", "//"); - QTest::newRow("unc-incomplete-only-server") << D("//server", "", "", "//server"); - QTest::newRow("unc-incomplete-only-server-2") << D("//server/", "", "", "//server/"); - QTest::newRow("unc-server-and-share") << D("//server/share", "", "", "//server/share"); - QTest::newRow("unc-server-and-share-2") << D("//server/share/", "", "", "//server/share/"); - QTest::newRow("unc-full") << D("//server/share/test.txt", "", "", "//server/share/test.txt"); - - QTest::newRow("unix-root") << D("/", "", "", "/"); - QTest::newRow("unix-folder") << D("/tmp", "", "", "/tmp"); - QTest::newRow("unix-folder-with-trailing-slash") << D("/tmp/", "", "", "/tmp/"); - - QTest::newRow("windows-root") << D("c:", "", "", "c:"); - QTest::newRow("windows-folder") << D("c:/Windows", "", "", "c:/Windows"); - QTest::newRow("windows-folder-with-trailing-slash") << D("c:/Windows/", "", "", "c:/Windows/"); - QTest::newRow("windows-folder-slash") << D("C:/Windows", "", "", "C:/Windows"); - - QTest::newRow("docker-root-url") << D("docker://1234/", "docker", "1234", "/"); - QTest::newRow("docker-root-url-special-linux") << D("/__qtc_devices__/docker/1234/", "docker", "1234", "/"); - QTest::newRow("docker-root-url-special-win") << D("c:/__qtc_devices__/docker/1234/", "docker", "1234", "/"); - QTest::newRow("docker-relative-path") << D("docker://1234/./rel", "docker", "1234", "rel"); - - QTest::newRow("qtc-dev-linux") << D("/__qtc_devices__", "", "", "/__qtc_devices__"); - QTest::newRow("qtc-dev-win") << D("c:/__qtc_devices__", "", "", "c:/__qtc_devices__"); - QTest::newRow("qtc-dev-type-linux") << D("/__qtc_devices__/docker", "", "", "/__qtc_devices__/docker"); - QTest::newRow("qtc-dev-type-win") << D("c:/__qtc_devices__/docker", "", "", "c:/__qtc_devices__/docker"); - QTest::newRow("qtc-dev-type-dev-linux") << D("/__qtc_devices__/docker/1234", "docker", "1234", "/"); - QTest::newRow("qtc-dev-type-dev-win") << D("c:/__qtc_devices__/docker/1234", "docker", "1234", "/"); - - // "Remote Windows" is currently truly not supported. - QTest::newRow("cross-os-linux") - << D("/__qtc_devices__/docker/1234/c:/test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - QTest::newRow("cross-os-win") - << D("c:/__qtc_devices__/docker/1234/c:/test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - QTest::newRow("cross-os-unclean-linux") - << D("/__qtc_devices__/docker/1234/c:\\test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - QTest::newRow("cross-os-unclean-win") - << D("c:/__qtc_devices__/docker/1234/c:\\test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - - QTest::newRow("unc-full-in-docker-linux") - << D("/__qtc_devices__/docker/1234//server/share/test.txt", "docker", "1234", "//server/share/test.txt"); - QTest::newRow("unc-full-in-docker-win") - << D("c:/__qtc_devices__/docker/1234//server/share/test.txt", "docker", "1234", "//server/share/test.txt"); - - QTest::newRow("unc-dos-1") << D("//?/c:", "", "", "//?/c:"); - QTest::newRow("unc-dos-com") << D("//./com1", "", "", "//./com1"); -} - -void tst_fileutils::fromString() -{ - QFETCH(FromStringData, data); - - FilePath filePath = FilePath::fromString(data.input); - - bool expectFail = ((data.expectedPass & FailOnLinux) && !HostOsInfo::isWindowsHost()) - || ((data.expectedPass & FailOnWindows) && HostOsInfo::isWindowsHost()); - - if (expectFail) { - QString actual = filePath.scheme() + '|' + filePath.host() + '|' + filePath.path(); - QString expected = data.scheme + '|' + data.host + '|' + data.path; - QEXPECT_FAIL("", "", Continue); - QCOMPARE(actual, expected); - return; - } - - QCOMPARE(filePath.scheme(), data.scheme); - QCOMPARE(filePath.host(), data.host); - QCOMPARE(filePath.path(), data.path); -} - -void tst_fileutils::fromUserInput_data() -{ - using D = FromStringData; - QTest::addColumn("data"); - - QTest::newRow("empty") << D("", "", "", ""); - QTest::newRow("single-colon") << D(":", "", "", ":"); - QTest::newRow("single-slash") << D("/", "", "", "/"); - QTest::newRow("single-char") << D("a", "", "", "a"); - QTest::newRow("relative") << D("./rel", "", "", "rel"); - QTest::newRow("qrc") << D(":/test.txt", "", "", ":/test.txt"); - QTest::newRow("qrc-no-slash") << D(":test.txt", "", "", ":test.txt"); - QTest::newRow("tilde") << D("~/", "", "", QDir::homePath()); - QTest::newRow("tilde-with-path") << D("~/foo", "", "", QDir::homePath() + "/foo"); - QTest::newRow("tilde-only") << D("~", "", "", "~"); - - QTest::newRow("unc-incomplete") << D("//", "", "", "//"); - QTest::newRow("unc-incomplete-only-server") << D("//server", "", "", "//server"); - QTest::newRow("unc-incomplete-only-server-2") << D("//server/", "", "", "//server/"); - QTest::newRow("unc-server-and-share") << D("//server/share", "", "", "//server/share"); - QTest::newRow("unc-server-and-share-2") << D("//server/share/", "", "", "//server/share"); - QTest::newRow("unc-full") << D("//server/share/test.txt", "", "", "//server/share/test.txt"); - - QTest::newRow("unix-root") << D("/", "", "", "/"); - QTest::newRow("unix-folder") << D("/tmp", "", "", "/tmp"); - QTest::newRow("unix-folder-with-trailing-slash") << D("/tmp/", "", "", "/tmp"); - - QTest::newRow("windows-root") << D("c:", "", "", "c:"); - QTest::newRow("windows-folder") << D("c:/Windows", "", "", "c:/Windows"); - QTest::newRow("windows-folder-with-trailing-slash") << D("c:\\Windows\\", "", "", "c:/Windows"); - QTest::newRow("windows-folder-slash") << D("C:/Windows", "", "", "C:/Windows"); - - QTest::newRow("docker-root-url") << D("docker://1234/", "docker", "1234", "/"); - QTest::newRow("docker-root-url-special-linux") << D("/__qtc_devices__/docker/1234/", "docker", "1234", "/"); - QTest::newRow("docker-root-url-special-win") << D("c:/__qtc_devices__/docker/1234/", "docker", "1234", "/"); - QTest::newRow("docker-relative-path") << D("docker://1234/./rel", "docker", "1234", "rel", FailEverywhere); - - QTest::newRow("qtc-dev-linux") << D("/__qtc_devices__", "", "", "/__qtc_devices__"); - QTest::newRow("qtc-dev-win") << D("c:/__qtc_devices__", "", "", "c:/__qtc_devices__"); - QTest::newRow("qtc-dev-type-linux") << D("/__qtc_devices__/docker", "", "", "/__qtc_devices__/docker"); - QTest::newRow("qtc-dev-type-win") << D("c:/__qtc_devices__/docker", "", "", "c:/__qtc_devices__/docker"); - QTest::newRow("qtc-dev-type-dev-linux") << D("/__qtc_devices__/docker/1234", "docker", "1234", "/"); - QTest::newRow("qtc-dev-type-dev-win") << D("c:/__qtc_devices__/docker/1234", "docker", "1234", "/"); - - // "Remote Windows" is currently truly not supported. - QTest::newRow("cross-os-linux") - << D("/__qtc_devices__/docker/1234/c:/test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - QTest::newRow("cross-os-win") - << D("c:/__qtc_devices__/docker/1234/c:/test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - QTest::newRow("cross-os-unclean-linux") - << D("/__qtc_devices__/docker/1234/c:\\test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - QTest::newRow("cross-os-unclean-win") - << D("c:/__qtc_devices__/docker/1234/c:\\test.txt", "docker", "1234", "c:/test.txt", FailEverywhere); - - QTest::newRow("unc-full-in-docker-linux") - << D("/__qtc_devices__/docker/1234//server/share/test.txt", "docker", "1234", "//server/share/test.txt", FailEverywhere); - QTest::newRow("unc-full-in-docker-win") - << D("c:/__qtc_devices__/docker/1234//server/share/test.txt", "docker", "1234", "//server/share/test.txt", FailEverywhere); - - QTest::newRow("unc-dos-1") << D("//?/c:", "", "", "c:"); - QTest::newRow("unc-dos-com") << D("//./com1", "", "", "//./com1"); -} - -void tst_fileutils::fromUserInput() -{ - QFETCH(FromStringData, data); - - FilePath filePath = FilePath::fromUserInput(data.input); - - bool expectFail = ((data.expectedPass & FailOnLinux) && !HostOsInfo::isWindowsHost()) - || ((data.expectedPass & FailOnWindows) && HostOsInfo::isWindowsHost()); - - if (expectFail) { - QString actual = filePath.scheme() + '|' + filePath.host() + '|' + filePath.path(); - QString expected = data.scheme + '|' + data.host + '|' + data.path; - QEXPECT_FAIL("", "", Continue); - QCOMPARE(actual, expected); - return; - } - - QCOMPARE(filePath.scheme(), data.scheme); - QCOMPARE(filePath.host(), data.host); - QCOMPARE(filePath.path(), data.path); -} - -void tst_fileutils::fromToString_data() -{ - QTest::addColumn("scheme"); - QTest::addColumn("host"); - QTest::addColumn("path"); - QTest::addColumn("full"); - - QTest::newRow("s0") << "" << "" << "" << ""; - QTest::newRow("s1") << "" << "" << "/" << "/"; - QTest::newRow("s2") << "" << "" << "a/b/c/d" << "a/b/c/d"; - QTest::newRow("s3") << "" << "" << "/a/b" << "/a/b"; - - QTest::newRow("s4") << "docker" << "1234abcdef" << "/bin/ls" << "docker://1234abcdef/bin/ls"; - QTest::newRow("s5") << "docker" << "1234" << "/bin/ls" << "docker://1234/bin/ls"; - - // This is not a proper URL. - QTest::newRow("s6") << "docker" << "1234" << "somefile" << "docker://1234/./somefile"; - - // Local Windows paths: - QTest::newRow("w1") << "" << "" << "C:/data" << "C:/data"; - QTest::newRow("w2") << "" << "" << "C:/" << "C:/"; - QTest::newRow("w3") << "" << "" << "/Global?\?/UNC/host" << "/Global?\?/UNC/host"; - QTest::newRow("w4") << "" << "" << "//server/dir/file" << "//server/dir/file"; -} - -void tst_fileutils::fromToString() -{ - QFETCH(QString, full); - QFETCH(QString, scheme); - QFETCH(QString, host); - QFETCH(QString, path); - - FilePath filePath = FilePath::fromString(full); - - QCOMPARE(filePath.toString(), full); - - QCOMPARE(filePath.scheme(), scheme); - QCOMPARE(filePath.host(), host); - QCOMPARE(filePath.path(), path); - - FilePath copy = FilePath::fromParts(scheme, host, path); - QCOMPARE(copy.toString(), full); -} - -void tst_fileutils::comparison() -{ - QFETCH(QString, left); - QFETCH(QString, right); - QFETCH(bool, hostSensitive); - QFETCH(bool, expected); - - HostOsInfo::setOverrideFileNameCaseSensitivity( - hostSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive); - - FilePath l = FilePath::fromUserInput(left); - FilePath r = FilePath::fromUserInput(right); - QCOMPARE(l == r, expected); -} - -void tst_fileutils::comparison_data() -{ - QTest::addColumn("left"); - QTest::addColumn("right"); - QTest::addColumn("hostSensitive"); - QTest::addColumn("expected"); - - QTest::newRow("r1") << "Abc" << "abc" << true << false; - QTest::newRow("r2") << "Abc" << "abc" << false << true; - QTest::newRow("r3") << "x://y/Abc" << "x://y/abc" << true << false; - QTest::newRow("r4") << "x://y/Abc" << "x://y/abc" << false << false; - - QTest::newRow("s1") << "abc" << "abc" << true << true; - QTest::newRow("s2") << "abc" << "abc" << false << true; - QTest::newRow("s3") << "x://y/abc" << "x://y/abc" << true << true; - QTest::newRow("s4") << "x://y/abc" << "x://y/abc" << false << true; -} - -void tst_fileutils::linkFromString() -{ - QFETCH(QString, testFile); - QFETCH(Utils::FilePath, filePath); - QFETCH(int, line); - QFETCH(int, column); - const Link link = Link::fromString(testFile, true); - QCOMPARE(link.targetFilePath, filePath); - QCOMPARE(link.targetLine, line); - QCOMPARE(link.targetColumn, column); -} - -void tst_fileutils::linkFromString_data() -{ - QTest::addColumn("testFile"); - QTest::addColumn("filePath"); - QTest::addColumn("line"); - QTest::addColumn("column"); - - QTest::newRow("no-line-no-column") << QString("someFile.txt") - << FilePath("someFile.txt") << -1 << -1; - QTest::newRow(": at end") << QString::fromLatin1("someFile.txt:") - << FilePath("someFile.txt") << 0 << -1; - QTest::newRow("+ at end") << QString::fromLatin1("someFile.txt+") - << FilePath("someFile.txt") << 0 << -1; - QTest::newRow(": for column") << QString::fromLatin1("someFile.txt:10:") - << FilePath("someFile.txt") << 10 << -1; - QTest::newRow("+ for column") << QString::fromLatin1("someFile.txt:10+") - << FilePath("someFile.txt") << 10 << -1; - QTest::newRow(": and + at end") << QString::fromLatin1("someFile.txt:+") - << FilePath("someFile.txt") << 0 << -1; - QTest::newRow("empty line") << QString::fromLatin1("someFile.txt:+10") - << FilePath("someFile.txt") << 0 << 9; - QTest::newRow(":line-no-column") << QString::fromLatin1("/some/path/file.txt:42") - << FilePath("/some/path/file.txt") << 42 << -1; - QTest::newRow("+line-no-column") << QString::fromLatin1("/some/path/file.txt+42") - << FilePath("/some/path/file.txt") << 42 << -1; - QTest::newRow(":line-:column") << QString::fromLatin1("/some/path/file.txt:42:3") - << FilePath("/some/path/file.txt") << 42 << 2; - QTest::newRow(":line-+column") << QString::fromLatin1("/some/path/file.txt:42+33") - << FilePath("/some/path/file.txt") << 42 << 32; - QTest::newRow("+line-:column") << QString::fromLatin1("/some/path/file.txt+142:30") - << FilePath("/some/path/file.txt") << 142 << 29; - QTest::newRow("+line-+column") << QString::fromLatin1("/some/path/file.txt+142+33") - << FilePath("/some/path/file.txt") << 142 << 32; - QTest::newRow("( at end") << QString::fromLatin1("/some/path/file.txt(") - << FilePath("/some/path/file.txt") << -1 << -1; - QTest::newRow("(42 at end") << QString::fromLatin1("/some/path/file.txt(42") - << FilePath("/some/path/file.txt") << 42 << -1; - QTest::newRow("(42) at end") << QString::fromLatin1("/some/path/file.txt(42)") - << FilePath("/some/path/file.txt") << 42 << -1; -} - -void tst_fileutils::pathAppended() -{ - QFETCH(QString, left); - QFETCH(QString, right); - QFETCH(QString, expected); - - const FilePath fleft = FilePath::fromString(left); - const FilePath fexpected = FilePath::fromString(expected); - const FilePath result = fleft.pathAppended(right); - - QCOMPARE(result, fexpected); -} - -void tst_fileutils::pathAppended_data() -{ - QTest::addColumn("left"); - QTest::addColumn("right"); - QTest::addColumn("expected"); - - QTest::newRow("p0") << "" << "" << ""; - QTest::newRow("p1") << "" << "/" << "/"; - QTest::newRow("p2") << "" << "c/" << "c/"; - QTest::newRow("p3") << "" << "/d" << "/d"; - QTest::newRow("p4") << "" << "c/d" << "c/d"; - - QTest::newRow("r0") << "/" << "" << "/"; - QTest::newRow("r1") << "/" << "/" << "/"; - QTest::newRow("r2") << "/" << "c/" << "/c/"; - QTest::newRow("r3") << "/" << "/d" << "/d"; - QTest::newRow("r4") << "/" << "c/d" << "/c/d"; - - QTest::newRow("s0") << "/b" << "" << "/b"; - QTest::newRow("s1") << "/b" << "/" << "/b/"; - QTest::newRow("s2") << "/b" << "c/" << "/b/c/"; - QTest::newRow("s3") << "/b" << "/d" << "/b/d"; - QTest::newRow("s4") << "/b" << "c/d" << "/b/c/d"; - - QTest::newRow("t0") << "a/" << "" << "a/"; - QTest::newRow("t1") << "a/" << "/" << "a/"; - QTest::newRow("t2") << "a/" << "c/" << "a/c/"; - QTest::newRow("t3") << "a/" << "/d" << "a/d"; - QTest::newRow("t4") << "a/" << "c/d" << "a/c/d"; - - QTest::newRow("u0") << "a/b" << "" << "a/b"; - QTest::newRow("u1") << "a/b" << "/" << "a/b/"; - QTest::newRow("u2") << "a/b" << "c/" << "a/b/c/"; - QTest::newRow("u3") << "a/b" << "/d" << "a/b/d"; - QTest::newRow("u4") << "a/b" << "c/d" << "a/b/c/d"; - - if (HostOsInfo::isWindowsHost()) { - QTest::newRow("win-1") << "c:" << "/a/b" << "c:/a/b"; - QTest::newRow("win-2") << "c:/" << "/a/b" << "c:/a/b"; - QTest::newRow("win-3") << "c:/" << "a/b" << "c:/a/b"; - } -} - -void tst_fileutils::resolvePath_data() -{ - QTest::addColumn("left"); - QTest::addColumn("right"); - QTest::addColumn("expected"); - - QTest::newRow("empty") << FilePath() << FilePath() << FilePath(); - QTest::newRow("s0") << FilePath("/") << FilePath("b") << FilePath("/b"); - QTest::newRow("s1") << FilePath() << FilePath("b") << FilePath("b"); - QTest::newRow("s2") << FilePath("a") << FilePath() << FilePath("a"); - QTest::newRow("s3") << FilePath("a") << FilePath("b") << FilePath("a/b"); - QTest::newRow("s4") << FilePath("/a") << FilePath("/b") << FilePath("/b"); - QTest::newRow("s5") << FilePath("a") << FilePath("/b") << FilePath("/b"); - QTest::newRow("s6") << FilePath("/a") << FilePath("b") << FilePath("/a/b"); - QTest::newRow("s7") << FilePath("/a") << FilePath(".") << FilePath("/a"); - QTest::newRow("s8") << FilePath("/a") << FilePath("./b") << FilePath("/a/b"); -} - -void tst_fileutils::resolvePath() -{ - QFETCH(FilePath, left); - QFETCH(FilePath, right); - QFETCH(FilePath, expected); - - const FilePath result = left.resolvePath(right); - - QCOMPARE(result, expected); -} - -void tst_fileutils::relativeChildPath_data() -{ - QTest::addColumn("parent"); - QTest::addColumn("child"); - QTest::addColumn("expected"); - - QTest::newRow("empty") << FilePath() << FilePath() << FilePath(); - - QTest::newRow("simple-0") << FilePath("/a") << FilePath("/a/b") << FilePath("b"); - QTest::newRow("simple-1") << FilePath("/a/") << FilePath("/a/b") << FilePath("b"); - QTest::newRow("simple-2") << FilePath("/a") << FilePath("/a/b/c/d/e/f") << FilePath("b/c/d/e/f"); - - QTest::newRow("not-0") << FilePath("/x") << FilePath("/a/b") << FilePath(); - QTest::newRow("not-1") << FilePath("/a/b/c") << FilePath("/a/b") << FilePath(); - -} - -void tst_fileutils::relativeChildPath() -{ - QFETCH(FilePath, parent); - QFETCH(FilePath, child); - QFETCH(FilePath, expected); - - const FilePath result = child.relativeChildPath(parent); - - QCOMPARE(result, expected); -} +void tst_fileutils::initTestCase() {} void tst_fileutils::commonPath() { @@ -1021,133 +65,15 @@ void tst_fileutils::commonPath_data() const FilePath url6 = FilePath::fromString("http:///./"); QTest::newRow("Zero paths") << FilePaths{} << FilePath(); - QTest::newRow("Single path") << FilePaths{ p1 } << p1; - QTest::newRow("3 identical paths") << FilePaths{ p1, p1, p1 } << p1; - QTest::newRow("3 paths, common path") << FilePaths{ p1, p2, p3 } << p1; - QTest::newRow("3 paths, no common path") << FilePaths{ p1, p2, p4 } << p5; - QTest::newRow("3 paths, first is part of second") << FilePaths{ p4, p1, p3 } << p5; - QTest::newRow("Common scheme") << FilePaths{ url1, url3 } << url6; - QTest::newRow("Different scheme") << FilePaths{ url1, url2 } << FilePath(); - QTest::newRow("Common host") << FilePaths{ url4, url5 } << url4; - QTest::newRow("Different host") << FilePaths{ url1, url3 } << url6; -} - -void tst_fileutils::asyncLocalCopy() -{ - const FilePath orig = FilePath::fromString(rootPath).pathAppended("x/y/fileToCopy.txt"); - QVERIFY(orig.exists()); - const FilePath dest = FilePath::fromString(rootPath).pathAppended("x/fileToCopyDest.txt"); - auto afterCopy = [&orig, &dest, this](expected_str result) { - QVERIFY(result); - // check existence, size and content - QVERIFY(dest.exists()); - QCOMPARE(dest.fileSize(), orig.fileSize()); - QCOMPARE(dest.fileContents(), orig.fileContents()); - emit asyncTestDone(); - }; - QSignalSpy spy(this, &tst_fileutils::asyncTestDone); - orig.asyncCopyFile(afterCopy, dest); - // we usually have already received the signal, but if it fails wait 3s - QVERIFY(spy.count() == 1 || spy.wait(3000)); -} - -void tst_fileutils::startsWithDriveLetter_data() -{ - QTest::addColumn("path"); - QTest::addColumn("expected"); - - QTest::newRow("empty") << FilePath() << false; - QTest::newRow("simple-win") << FilePath::fromString("c:/a") << true; - QTest::newRow("simple-linux") << FilePath::fromString("/c:/a") << false; - QTest::newRow("relative") << FilePath("a/b") << false; -} - -void tst_fileutils::startsWithDriveLetter() -{ - QFETCH(FilePath, path); - QFETCH(bool, expected); - - QCOMPARE(path.startsWithDriveLetter(), expected); -} - -void tst_fileutils::onDevice_data() -{ - QTest::addColumn("path"); - QTest::addColumn("templatePath"); - QTest::addColumn("expected"); - - QTest::newRow("empty") << FilePath() << FilePath() << FilePath(); - QTest::newRow("same-local") << FilePath("/a/b") << FilePath("/a/b") << FilePath("/a/b"); - QTest::newRow("same-docker") << FilePath("docker://1234/a/b") << FilePath("docker://1234/e") << FilePath("docker://1234/a/b"); - - QTest::newRow("docker-to-local") << FilePath("docker://1234/a/b") << FilePath("/c/d") << FilePath("/a/b"); - QTest::newRow("local-to-docker") << FilePath("/a/b") << FilePath("docker://1234/c/d") << FilePath("docker://1234/a/b"); - -} - -void tst_fileutils::onDevice() -{ - QFETCH(FilePath, path); - QFETCH(FilePath, templatePath); - QFETCH(FilePath, expected); - - QCOMPARE(path.onDevice(templatePath), expected); -} - -void tst_fileutils::stringAppended_data() -{ - QTest::addColumn("left"); - QTest::addColumn("right"); - QTest::addColumn("expected"); - - QTest::newRow("empty") << FilePath() << QString() << FilePath(); - QTest::newRow("empty-left") << FilePath() << "a" << FilePath("a"); - QTest::newRow("empty-right") << FilePath("a") << QString() << FilePath("a"); - QTest::newRow("add-root") << FilePath() << QString("/") << FilePath("/"); - QTest::newRow("add-root-and-more") << FilePath() << QString("/test/blah") << FilePath("/test/blah"); - QTest::newRow("add-extension") << FilePath::fromString("/a") << QString(".txt") << FilePath("/a.txt"); - QTest::newRow("trailing-slash") << FilePath::fromString("/a") << QString("b/") << FilePath("/ab/"); - QTest::newRow("slash-trailing-slash") << FilePath::fromString("/a/") << QString("b/") << FilePath("/a/b/"); -} - -void tst_fileutils::stringAppended() -{ - QFETCH(FilePath, left); - QFETCH(QString, right); - QFETCH(FilePath, expected); - - const FilePath result = left.stringAppended(right); - - QCOMPARE(expected, result); -} - -void tst_fileutils::url() -{ - QFETCH(QString, url); - QFETCH(QString, expectedScheme); - QFETCH(QString, expectedHost); - QFETCH(QString, expectedPath); - - const FilePath result = FilePath::fromString(url); - QCOMPARE(result.scheme(), expectedScheme); - QCOMPARE(result.host(), expectedHost); - QCOMPARE(result.path(), expectedPath); -} - -void tst_fileutils::url_data() -{ - QTest::addColumn("url"); - QTest::addColumn("expectedScheme"); - QTest::addColumn("expectedHost"); - QTest::addColumn("expectedPath"); - QTest::newRow("empty") << QString() << QString() << QString() << QString(); - QTest::newRow("simple-file") << QString("file:///a/b") << QString("file") << QString() << QString("/a/b"); - QTest::newRow("simple-file-root") << QString("file:///") << QString("file") << QString() << QString("/"); - QTest::newRow("simple-docker") << QString("docker://1234/a/b") << QString("docker") << QString("1234") << QString("/a/b"); - QTest::newRow("simple-ssh") << QString("ssh://user@host/a/b") << QString("ssh") << QString("user@host") << QString("/a/b"); - QTest::newRow("simple-ssh-with-port") << QString("ssh://user@host:1234/a/b") << QString("ssh") << QString("user@host:1234") << QString("/a/b"); - QTest::newRow("http-qt.io") << QString("http://qt.io") << QString("http") << QString("qt.io") << QString(); - QTest::newRow("http-qt.io-index.html") << QString("http://qt.io/index.html") << QString("http") << QString("qt.io") << QString("/index.html"); + QTest::newRow("Single path") << FilePaths{p1} << p1; + QTest::newRow("3 identical paths") << FilePaths{p1, p1, p1} << p1; + QTest::newRow("3 paths, common path") << FilePaths{p1, p2, p3} << p1; + QTest::newRow("3 paths, no common path") << FilePaths{p1, p2, p4} << p5; + QTest::newRow("3 paths, first is part of second") << FilePaths{p4, p1, p3} << p5; + QTest::newRow("Common scheme") << FilePaths{url1, url3} << url6; + QTest::newRow("Different scheme") << FilePaths{url1, url2} << FilePath(); + QTest::newRow("Common host") << FilePaths{url4, url5} << url4; + QTest::newRow("Different host") << FilePaths{url1, url3} << url6; } void tst_fileutils::bytesAvailableFromDF_data() @@ -1156,13 +82,33 @@ void tst_fileutils::bytesAvailableFromDF_data() QTest::addColumn("expected"); QTest::newRow("empty") << QByteArray("") << qint64(-1); - QTest::newRow("mac") << QByteArray("Filesystem 1024-blocks Used Available Capacity iused ifree %iused Mounted on\n/dev/disk3s5 971350180 610014564 342672532 65% 4246780 3426725320 0% /System/Volumes/Data\n") << qint64(342672532); - QTest::newRow("alpine") << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\noverlay 569466448 163526072 376983360 30% /\n") << qint64(376983360); - QTest::newRow("alpine-no-trailing-br") << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\noverlay 569466448 163526072 376983360 30% /") << qint64(376983360); - QTest::newRow("alpine-missing-line") << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\n") << qint64(-1); - QTest::newRow("wrong-header") << QByteArray("Filesystem 1K-blocks Used avail Use% Mounted on\noverlay 569466448 163526072 376983360 30% /\n") << qint64(-1); - QTest::newRow("not-enough-fields") << QByteArray("Filesystem 1K-blocks Used avail Use% Mounted on\noverlay 569466448\n") << qint64(-1); - QTest::newRow("not-enough-header-fields") << QByteArray("Filesystem 1K-blocks Used \noverlay 569466448 163526072 376983360 30% /\n") << qint64(-1); + QTest::newRow("mac") << QByteArray( + "Filesystem 1024-blocks Used Available Capacity iused ifree %iused Mounted " + "on\n/dev/disk3s5 971350180 610014564 342672532 65% 4246780 3426725320 0% " + "/System/Volumes/Data\n") + << qint64(342672532); + QTest::newRow("alpine") << QByteArray( + "Filesystem 1K-blocks Used Available Use% Mounted on\noverlay " + "569466448 163526072 376983360 30% /\n") + << qint64(376983360); + QTest::newRow("alpine-no-trailing-br") + << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\noverlay " + " 569466448 163526072 376983360 30% /") + << qint64(376983360); + QTest::newRow("alpine-missing-line") + << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\n") + << qint64(-1); + QTest::newRow("wrong-header") << QByteArray( + "Filesystem 1K-blocks Used avail Use% Mounted on\noverlay " + "569466448 163526072 376983360 30% /\n") + << qint64(-1); + QTest::newRow("not-enough-fields") << QByteArray( + "Filesystem 1K-blocks Used avail Use% Mounted on\noverlay 569466448\n") + << qint64(-1); + QTest::newRow("not-enough-header-fields") + << QByteArray("Filesystem 1K-blocks Used \noverlay 569466448 " + "163526072 376983360 30% /\n") + << qint64(-1); } void tst_fileutils::bytesAvailableFromDF() @@ -1177,194 +123,6 @@ void tst_fileutils::bytesAvailableFromDF() QCOMPARE(result, expected); } -void tst_fileutils::cleanPath_data() -{ - QTest::addColumn("path"); - QTest::addColumn("expected"); - - QTest::newRow("data0") << "/Users/sam/troll/qt4.0//.." << "/Users/sam/troll"; - QTest::newRow("data1") << "/Users/sam////troll/qt4.0//.." << "/Users/sam/troll"; - QTest::newRow("data2") << "/" << "/"; - QTest::newRow("data2-up") << "/path/.." << "/"; - QTest::newRow("data2-above-root") << "/.." << "/.."; - QTest::newRow("data3") << QDir::cleanPath("../.") << ".."; - QTest::newRow("data4") << QDir::cleanPath("../..") << "../.."; - QTest::newRow("data5") << "d:\\a\\bc\\def\\.." << "d:/a/bc"; // QDir/Linux had: "d:\\a\\bc\\def\\.." - QTest::newRow("data6") << "d:\\a\\bc\\def\\../../.." << "d:/"; // QDir/Linux had: ".." - QTest::newRow("data7") << ".//file1.txt" << "file1.txt"; - QTest::newRow("data8") << "/foo/bar/..//file1.txt" << "/foo/file1.txt"; - QTest::newRow("data9") << "//" << "//"; // QDir had: "/" - QTest::newRow("data10w") << "c:\\" << "c:/"; - QTest::newRow("data10l") << "/:/" << "/:"; - QTest::newRow("data11") << "//foo//bar" << "//foo/bar"; // QDir/Win had: "//foo/bar" - QTest::newRow("data12") << "ab/a/" << "ab/a"; // Path item with length of 2 - QTest::newRow("data13w") << "c:/" << "c:/"; - QTest::newRow("data13w2") << "c:\\" << "c:/"; - //QTest::newRow("data13l") << "c://" << "c:"; - -// QTest::newRow("data14") << "c://foo" << "c:/foo"; - QTest::newRow("data15") << "//c:/foo" << "//c:/foo"; // QDir/Lin had: "/c:/foo"; - QTest::newRow("drive-up") << "A:/path/.." << "A:/"; - QTest::newRow("drive-above-root") << "A:/.." << "A:/.."; - QTest::newRow("unc-server-up") << "//server/path/.." << "//server/"; - QTest::newRow("unc-server-above-root") << "//server/.." << "//server/.."; - - QTest::newRow("longpath") << "\\\\?\\d:\\" << "d:/"; - QTest::newRow("longpath-slash") << "//?/d:/" << "d:/"; - QTest::newRow("longpath-mixed-slashes") << "//?/d:\\" << "d:/"; - QTest::newRow("longpath-mixed-slashes-2") << "\\\\?\\d:/" << "d:/"; - - QTest::newRow("unc-network-share") << "\\\\?\\UNC\\localhost\\c$\\tmp.txt" - << "//localhost/c$/tmp.txt"; - QTest::newRow("unc-network-share-slash") << "//?/UNC/localhost/c$/tmp.txt" - << "//localhost/c$/tmp.txt"; - QTest::newRow("unc-network-share-mixed-slashes") << "//?/UNC/localhost\\c$\\tmp.txt" - << "//localhost/c$/tmp.txt"; - QTest::newRow("unc-network-share-mixed-slashes-2") << "\\\\?\\UNC\\localhost/c$/tmp.txt" - << "//localhost/c$/tmp.txt"; - - QTest::newRow("QTBUG-23892_0") << "foo/.." << "."; - QTest::newRow("QTBUG-23892_1") << "foo/../" << "."; - - QTest::newRow("QTBUG-3472_0") << "/foo/./bar" << "/foo/bar"; - QTest::newRow("QTBUG-3472_1") << "./foo/.." << "."; - QTest::newRow("QTBUG-3472_2") << "./foo/../" << "."; - - QTest::newRow("resource0") << ":/prefix/foo.bar" << ":/prefix/foo.bar"; - QTest::newRow("resource1") << ":/prefix/..//prefix/foo.bar" << ":/prefix/foo.bar"; - - QTest::newRow("ssh") << "ssh://host/prefix/../foo.bar" << "ssh://host/foo.bar"; - QTest::newRow("ssh2") << "ssh://host/../foo.bar" << "ssh://host/../foo.bar"; -} - -void tst_fileutils::cleanPath() -{ - QFETCH(QString, path); - QFETCH(QString, expected); - QString cleaned = doCleanPath(path); - QCOMPARE(cleaned, expected); -} - -void tst_fileutils::isSameFile_data() -{ - QTest::addColumn("left"); - QTest::addColumn("right"); - QTest::addColumn("shouldBeEqual"); - - QTest::addRow("/==/") - << FilePath::fromString("/") << FilePath::fromString("/") << true; - QTest::addRow("/!=tmp") - << FilePath::fromString("/") << FilePath::fromString(tempDir.path()) << false; - - - QDir dir(tempDir.path()); - touch(dir, "target-file", false); - - QFile file(dir.absoluteFilePath("target-file")); - if (file.link(dir.absoluteFilePath("source-file"))) { - QTest::addRow("real==link") - << FilePath::fromString(file.fileName()) - << FilePath::fromString(dir.absoluteFilePath("target-file")) - << true; - } - - QTest::addRow("/!=non-existing") - << FilePath::fromString("/") << FilePath::fromString("/this-path/does-not-exist") << false; - - QTest::addRow("two-devices") << FilePath::fromString( - "docker://boot2qt-raspberrypi4-64:6.5.0/opt/toolchain/sysroots/aarch64-pokysdk-linux/usr/" - "bin/aarch64-poky-linux/aarch64-poky-linux-g++") - << FilePath::fromString("docker://qt-linux:6/usr/bin/g++") - << false; -} - -void tst_fileutils::isSameFile() -{ - QFETCH(FilePath, left); - QFETCH(FilePath, right); - QFETCH(bool, shouldBeEqual); - - QCOMPARE(left.isSameFile(right), shouldBeEqual); -} - -void tst_fileutils::hostSpecialChars_data() -{ - QTest::addColumn("scheme"); - QTest::addColumn("host"); - QTest::addColumn("path"); - QTest::addColumn("expected"); - - QTest::addRow("slash-in-host") << "device" << "host/name" << "/" << FilePath::fromString("device://host%2fname/"); - QTest::addRow("percent-in-host") << "device" << "host%name" << "/" << FilePath::fromString("device://host%25name/"); - QTest::addRow("percent-and-slash-in-host") << "device" << "host/%name" << "/" << FilePath::fromString("device://host%2f%25name/"); - QTest::addRow("qtc-dev-slash-in-host-linux") << "device" << "host/name" << "/" << FilePath::fromString("/__qtc_devices__/device/host%2fname/"); - QTest::addRow("qtc-dev-slash-in-host-windows") << "device" << "host/name" << "/" << FilePath::fromString("c:/__qtc_devices__/device/host%2fname/"); - -} - -void tst_fileutils::hostSpecialChars() -{ - QFETCH(QString, scheme); - QFETCH(QString, host); - QFETCH(QString, path); - QFETCH(FilePath, expected); - - FilePath fp; - fp.setParts(scheme, host, path); - - // Check that setParts and fromString give the same result - QCOMPARE(fp, expected); - QCOMPARE(fp.host(), expected.host()); - QCOMPARE(fp.host(), host); - QCOMPARE(expected.host(), host); - - QString toStringExpected = expected.toString(); - QString toStringActual = fp.toString(); - - // Check that toString gives the same result - QCOMPARE(toStringActual, toStringExpected); - - // Check that fromString => toString => fromString gives the same result - FilePath toFromExpected = FilePath::fromString(expected.toString()); - QCOMPARE(toFromExpected, expected); - QCOMPARE(toFromExpected, fp); - - // Check that setParts => toString => fromString gives the same result - FilePath toFromActual = FilePath::fromString(fp.toString()); - QCOMPARE(toFromActual, fp); - QCOMPARE(toFromExpected, expected); -} - -void tst_fileutils::tmp_data() -{ - QTest::addColumn("templatepath"); - QTest::addColumn("expected"); - - QTest::addRow("empty") << "" << true; - QTest::addRow("no-template") << "foo" << true; - QTest::addRow("realtive-template") << "my-file-XXXXXXXX" << true; - QTest::addRow("absolute-template") << QDir::tempPath() + "/my-file-XXXXXXXX" << true; - QTest::addRow("non-existing-dir") << "/this/path/does/not/exist/my-file-XXXXXXXX" << false; - - QTest::addRow("on-device") << "device://test/./my-file-XXXXXXXX" << true; -} - -void tst_fileutils::tmp() -{ - QFETCH(QString, templatepath); - QFETCH(bool, expected); - - FilePath fp = FilePath::fromString(templatepath); - - const auto result = fp.createTempFile(); - QCOMPARE(result.has_value(), expected); - - if (result.has_value()) { - QVERIFY(result->exists()); - QVERIFY(result->removeFile()); - } -} - void tst_fileutils::filePathInfoFromTriple_data() { QTest::addColumn("statoutput"); diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index eea36644236..d8d0a58b4b8 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -8,6 +8,7 @@ Project { "commandline/commandline.qbs", "deviceshell/deviceshell.qbs", "expected/expected.qbs", + "filepath/filepath.qbs", "fileutils/fileutils.qbs", "fsengine/fsengine.qbs", "fuzzymatcher/fuzzymatcher.qbs", From 682ef157d8561cb9648be8efcf45bdc8d0e47ea7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Feb 2023 12:47:39 +0100 Subject: [PATCH 0080/1447] Terminal: Add Terminal plugin Adds a new Terminal plugin that provides a Terminal pane inside Qt Creator. Fixes: QTCREATORBUG-8511 Change-Id: I7eacb3efa2463d7df9f383ae3fc33254fb9019a9 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/aspects.cpp | 71 ++ src/libs/utils/aspects.h | 26 + src/libs/utils/qtcprocess.cpp | 3 +- src/libs/utils/terminalhooks.cpp | 48 + src/libs/utils/terminalhooks.h | 70 ++ src/libs/utils/utils.qbs | 2 + src/plugins/CMakeLists.txt | 1 + src/plugins/coreplugin/fileutils.cpp | 4 +- src/plugins/docker/dockerdevice.cpp | 62 +- src/plugins/docker/dockerdevice.h | 3 + src/plugins/plugins.qbs | 1 + .../projectexplorer/devicesupport/idevice.cpp | 9 + .../projectexplorer/devicesupport/idevice.h | 3 + .../projectexplorer/projectexplorer.cpp | 29 +- src/plugins/terminal/CMakeLists.txt | 17 + src/plugins/terminal/Terminal.json.in | 19 + src/plugins/terminal/celllayout.cpp | 120 +++ src/plugins/terminal/celllayout.h | 27 + src/plugins/terminal/keys.cpp | 83 ++ src/plugins/terminal/keys.h | 15 + src/plugins/terminal/scrollback.cpp | 93 ++ src/plugins/terminal/scrollback.h | 66 ++ src/plugins/terminal/terminal.qbs | 32 + src/plugins/terminal/terminalpane.cpp | 176 ++++ src/plugins/terminal/terminalpane.h | 57 ++ src/plugins/terminal/terminalplugin.cpp | 58 ++ src/plugins/terminal/terminalplugin.h | 29 + .../terminal/terminalprocessinterface.cpp | 47 + .../terminal/terminalprocessinterface.h | 49 + src/plugins/terminal/terminalsettings.cpp | 120 +++ src/plugins/terminal/terminalsettings.h | 26 + src/plugins/terminal/terminalsettingspage.cpp | 96 ++ src/plugins/terminal/terminalsettingspage.h | 22 + src/plugins/terminal/terminaltr.h | 15 + src/plugins/terminal/terminalwidget.cpp | 942 ++++++++++++++++++ src/plugins/terminal/terminalwidget.h | 164 +++ 37 files changed, 2582 insertions(+), 24 deletions(-) create mode 100644 src/libs/utils/terminalhooks.cpp create mode 100644 src/libs/utils/terminalhooks.h create mode 100644 src/plugins/terminal/CMakeLists.txt create mode 100644 src/plugins/terminal/Terminal.json.in create mode 100644 src/plugins/terminal/celllayout.cpp create mode 100644 src/plugins/terminal/celllayout.h create mode 100644 src/plugins/terminal/keys.cpp create mode 100644 src/plugins/terminal/keys.h create mode 100644 src/plugins/terminal/scrollback.cpp create mode 100644 src/plugins/terminal/scrollback.h create mode 100644 src/plugins/terminal/terminal.qbs create mode 100644 src/plugins/terminal/terminalpane.cpp create mode 100644 src/plugins/terminal/terminalpane.h create mode 100644 src/plugins/terminal/terminalplugin.cpp create mode 100644 src/plugins/terminal/terminalplugin.h create mode 100644 src/plugins/terminal/terminalprocessinterface.cpp create mode 100644 src/plugins/terminal/terminalprocessinterface.h create mode 100644 src/plugins/terminal/terminalsettings.cpp create mode 100644 src/plugins/terminal/terminalsettings.h create mode 100644 src/plugins/terminal/terminalsettingspage.cpp create mode 100644 src/plugins/terminal/terminalsettingspage.h create mode 100644 src/plugins/terminal/terminaltr.h create mode 100644 src/plugins/terminal/terminalwidget.cpp create mode 100644 src/plugins/terminal/terminalwidget.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 34b24ff78c7..04f475afb7c 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -170,6 +170,7 @@ add_qtc_library(Utils temporarydirectory.cpp temporarydirectory.h temporaryfile.cpp temporaryfile.h terminalcommand.cpp terminalcommand.h + terminalhooks.cpp terminalhooks.h terminalprocess.cpp terminalprocess_p.h textfieldcheckbox.cpp textfieldcheckbox.h textfieldcombobox.cpp textfieldcombobox.h diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 72e667d76a6..51be951a8fe 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -9,6 +9,7 @@ #include "layoutbuilder.h" #include "pathchooser.h" #include "qtcassert.h" +#include "qtcolorbutton.h" #include "qtcsettings.h" #include "utilstr.h" #include "variablechooser.h" @@ -579,6 +580,12 @@ public: QPointer m_groupBox; // For BoolAspects handling GroupBox check boxes }; +class ColorAspectPrivate +{ +public: + QPointer m_colorButton; // Owned by configuration widget +}; + class SelectionAspectPrivate { public: @@ -1287,6 +1294,70 @@ void StringAspect::makeCheckable(CheckBoxPlacement checkBoxPlacement, update(); } +/*! + \class Utils::ColorAspect + \inmodule QtCreator + + \brief A color aspect is a color property of some object, together with + a description of its behavior for common operations like visualizing or + persisting. + + The color aspect is displayed using a QtColorButton. +*/ + +ColorAspect::ColorAspect(const QString &settingsKey) + : d(new Internal::ColorAspectPrivate) +{ + setDefaultValue(QColor::fromRgb(0, 0, 0)); + setSettingsKey(settingsKey); + setSpan(1, 1); + + addDataExtractor(this, &ColorAspect::value, &Data::value); +} + +ColorAspect::~ColorAspect() = default; + +void ColorAspect::addToLayout(Layouting::LayoutBuilder &builder) +{ + QTC_CHECK(!d->m_colorButton); + d->m_colorButton = createSubWidget(); + builder.addItem(d->m_colorButton.data()); + d->m_colorButton->setColor(value()); + if (isAutoApply()) { + connect(d->m_colorButton.data(), + &QtColorButton::colorChanged, + this, + [this](const QColor &color) { setValue(color); }); + } +} + +QColor ColorAspect::value() const +{ + return BaseAspect::value().value(); +} + +void ColorAspect::setValue(const QColor &value) +{ + if (BaseAspect::setValueQuietly(value)) + emit changed(); +} + +QVariant ColorAspect::volatileValue() const +{ + QTC_CHECK(!isAutoApply()); + if (d->m_colorButton) + return d->m_colorButton->color(); + QTC_CHECK(false); + return {}; +} + +void ColorAspect::setVolatileValue(const QVariant &val) +{ + QTC_CHECK(!isAutoApply()); + if (d->m_colorButton) + d->m_colorButton->setColor(val.value()); +} + /*! \class Utils::BoolAspect \inmodule QtCreator diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 413a17e6245..1aaaca3f299 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -31,6 +31,7 @@ namespace Internal { class AspectContainerPrivate; class BaseAspectPrivate; class BoolAspectPrivate; +class ColorAspectPrivate; class DoubleAspectPrivate; class IntegerAspectPrivate; class MultiSelectionAspectPrivate; @@ -245,6 +246,31 @@ private: std::unique_ptr d; }; +class QTCREATOR_UTILS_EXPORT ColorAspect : public BaseAspect +{ + Q_OBJECT + +public: + explicit ColorAspect(const QString &settingsKey = QString()); + ~ColorAspect() override; + + struct Data : BaseAspect::Data + { + QColor value; + }; + + void addToLayout(Layouting::LayoutBuilder &builder) override; + + QColor value() const; + void setValue(const QColor &val); + + QVariant volatileValue() const override; + void setVolatileValue(const QVariant &val) override; + +private: + std::unique_ptr d; +}; + class QTCREATOR_UTILS_EXPORT SelectionAspect : public BaseAspect { Q_OBJECT diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 74bd28560b3..096f6445617 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -12,6 +12,7 @@ #include "processreaper.h" #include "processutils.h" #include "stringutils.h" +#include "terminalhooks.h" #include "terminalprocess_p.h" #include "threadutils.h" #include "utilstr.h" @@ -630,7 +631,7 @@ public: ProcessInterface *createProcessInterface() { if (m_setup.m_terminalMode != TerminalMode::Off) - return new TerminalImpl(); + return Terminal::Hooks::instance().createTerminalProcessInterfaceHook()(); const ProcessImpl impl = m_setup.m_processImpl == ProcessImpl::Default ? defaultProcessImpl() : m_setup.m_processImpl; diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp new file mode 100644 index 00000000000..d0b48075683 --- /dev/null +++ b/src/libs/utils/terminalhooks.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalhooks.h" + +#include "filepath.h" +#include "terminalprocess_p.h" + +namespace Utils::Terminal { + +struct HooksPrivate +{ + HooksPrivate() + : m_openTerminalHook([](const OpenTerminalParameters ¶meters) { + DeviceFileHooks::instance().openTerminal(parameters.workingDirectory.value_or( + FilePath{}), + parameters.environment.value_or(Environment{})); + }) + , m_createTerminalProcessInterfaceHook( + []() -> ProcessInterface * { return new Internal::TerminalImpl(); }) + {} + + Hooks::OpenTerminalHook m_openTerminalHook; + Hooks::CreateTerminalProcessInterfaceHook m_createTerminalProcessInterfaceHook; +}; + +Hooks &Hooks::instance() +{ + static Hooks manager; + return manager; +} + +Hooks::Hooks() + : d(new HooksPrivate()) +{} + +Hooks::~Hooks() = default; + +Hooks::OpenTerminalHook &Hooks::openTerminalHook() +{ + return d->m_openTerminalHook; +} +Hooks::CreateTerminalProcessInterfaceHook &Hooks::createTerminalProcessInterfaceHook() +{ + return d->m_createTerminalProcessInterfaceHook; +} + +} // namespace Utils::Terminal diff --git a/src/libs/utils/terminalhooks.h b/src/libs/utils/terminalhooks.h new file mode 100644 index 00000000000..57012afc903 --- /dev/null +++ b/src/libs/utils/terminalhooks.h @@ -0,0 +1,70 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "commandline.h" +#include "environment.h" +#include "filepath.h" + +#include +#include + +namespace Utils { +class ProcessInterface; + +template +class Hook +{ +public: + using Callback = std::function; + +public: + Hook() = delete; + Hook(const Hook &other) = delete; + Hook(Hook &&other) = delete; + Hook &operator=(const Hook &other) = delete; + Hook &operator=(Hook &&other) = delete; + + explicit Hook(Callback defaultCallback) { set(defaultCallback); } + + void set(Callback cb) { m_callback = cb; } + R operator()(Params &&...params) { return m_callback(std::forward(params)...); } + +private: + Callback m_callback; +}; + +namespace Terminal { +struct HooksPrivate; + +enum class ExitBehavior { Close, Restart, Keep }; + +struct OpenTerminalParameters +{ + std::optional shellCommand; + std::optional workingDirectory; + std::optional environment; + ExitBehavior m_exitBehavior{ExitBehavior::Close}; +}; + +class QTCREATOR_UTILS_EXPORT Hooks +{ +public: + using OpenTerminalHook = Hook; + using CreateTerminalProcessInterfaceHook = Hook; + +public: + static Hooks &instance(); + + OpenTerminalHook &openTerminalHook(); + CreateTerminalProcessInterfaceHook &createTerminalProcessInterfaceHook(); + + ~Hooks(); +private: + Hooks(); + std::unique_ptr d; +}; + +} // namespace Terminal +} // namespace Utils diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 11c0e342826..a1b3415e719 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -307,6 +307,8 @@ Project { "temporaryfile.h", "terminalcommand.cpp", "terminalcommand.h", + "terminalhooks.cpp", + "terminalhooks.h", "terminalprocess.cpp", "terminalprocess_p.h", "textfieldcheckbox.cpp", diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index dc92077f0c1..5e3ff9bb18a 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -101,3 +101,4 @@ add_subdirectory(webassembly) add_subdirectory(mcusupport) add_subdirectory(saferenderer) add_subdirectory(copilot) +add_subdirectory(terminal) diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 6c783488971..116fe244f2f 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -104,8 +105,7 @@ void FileUtils::showInFileSystemView(const FilePath &path) void FileUtils::openTerminal(const FilePath &path, const Environment &env) { - QTC_ASSERT(DeviceFileHooks::instance().openTerminal, return); - DeviceFileHooks::instance().openTerminal(path, env); + Terminal::Hooks::instance().openTerminalHook()({std::nullopt, path, env}); } QString FileUtils::msgFindInDirectory() diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 2a955f131fe..d9ec143a9e3 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -160,9 +160,11 @@ public: Environment environment(); CommandLine withDockerExecCmd(const CommandLine &cmd, - Environment *env = nullptr, - FilePath *workDir = nullptr, - bool interactive = false); + const std::optional &env = std::nullopt, + const std::optional &workDir = std::nullopt, + bool interactive = false, + bool includeMarker = true, + bool withPty = false); bool prepareForBuild(const Target *target); Tasks validateMounts() const; @@ -294,11 +296,11 @@ void DockerProcessImpl::start() const bool interactive = m_setup.m_processMode == ProcessMode::Writer || !m_setup.m_writeData.isEmpty(); - const CommandLine fullCommandLine = m_devicePrivate - ->withDockerExecCmd(m_setup.m_commandLine, - &m_setup.m_environment, - &m_setup.m_workingDirectory, - interactive); + const CommandLine fullCommandLine + = m_devicePrivate->withDockerExecCmd(m_setup.m_commandLine, + m_setup.m_environment, + m_setup.m_workingDirectory, + interactive); m_process.setCommand(fullCommandLine); m_process.start(); @@ -446,9 +448,11 @@ void DockerDevice::updateContainerAccess() const } CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, - Environment *env, - FilePath *workDir, - bool interactive) + const std::optional &env, + const std::optional &workDir, + bool interactive, + bool includeMarker, + bool withPty) { if (!m_settings) return {}; @@ -460,6 +464,9 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, if (interactive) dockerCmd.addArg("-i"); + if (withPty) + dockerCmd.addArg("-t"); + if (env) { for (auto it = env->constBegin(); it != env->constEnd(); ++it) { dockerCmd.addArg("-e"); @@ -468,19 +475,24 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, } if (workDir && !workDir->isEmpty()) - dockerCmd.addArgs({"-w", workDir->path()}); + dockerCmd.addArgs({"-w", workDir->onDevice(q->rootPath()).nativePath()}); dockerCmd.addArg(m_container); - dockerCmd.addArgs({"/bin/sh", "-c"}); - CommandLine exec("exec"); - exec.addCommandLineAsArgs(cmd); + if (includeMarker) { + dockerCmd.addArgs({"/bin/sh", "-c"}); - CommandLine echo("echo"); - echo.addArgs("__qtc$$qtc__", CommandLine::Raw); - echo.addCommandLineWithAnd(exec); + CommandLine exec("exec"); + exec.addCommandLineAsArgs(cmd); - dockerCmd.addCommandLineAsSingleArg(echo); + CommandLine echo("echo"); + echo.addArgs("__qtc$$qtc__", CommandLine::Raw); + echo.addCommandLineWithAnd(exec); + + dockerCmd.addCommandLineAsSingleArg(echo); + } else { + dockerCmd.addCommandLineAsArgs(cmd); + } return dockerCmd; } @@ -1222,4 +1234,16 @@ std::optional DockerDevice::clangdExecutable() const return d->clangdExecutable(); } +std::optional DockerDevice::terminalCommand(const FilePath &workDir, + const Environment &env) const +{ + const QString shell = d->environment().value_or("SHELL", "/bin/sh"); + return d->withDockerExecCmd({FilePath::fromUserInput(shell), {}}, + std::nullopt, + workDir, + true, + false, + true); +} + } // namespace Docker::Internal diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 3ecc0118d49..0a1a77f947b 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -101,6 +101,9 @@ public: bool prepareForBuild(const ProjectExplorer::Target *target) override; std::optional clangdExecutable() const override; + std::optional terminalCommand(const Utils::FilePath &workDir, + const Utils::Environment &env) const override; + protected: void fromMap(const QVariantMap &map) final; QVariantMap toMap() const final; diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 5ce3a8fa9a1..d28aeb05f17 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -79,6 +79,7 @@ Project { "squish/squish.qbs", "studiowelcome/studiowelcome.qbs", "subversion/subversion.qbs", + "terminal/terminal.qbs", "texteditor/texteditor.qbs", "todo/todo.qbs", "updateinfo/updateinfo.qbs", diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index b884237b3b2..c615a89badc 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -180,6 +181,14 @@ void IDevice::openTerminal(const Environment &env, const FilePath &workingDir) c d->openTerminal(env, workingDir); } +std::optional IDevice::terminalCommand(const FilePath &workDir, const Environment &env) const +{ + Q_UNUSED(workDir); + Q_UNUSED(env); + + return std::nullopt; +} + bool IDevice::isEmptyCommandAllowed() const { return d->emptyCommandAllowed; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 6323b8589bb..c4759a7d327 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -193,6 +193,9 @@ public: bool canOpenTerminal() const; void openTerminal(const Utils::Environment &env, const Utils::FilePath &workingDir) const; + virtual std::optional terminalCommand(const Utils::FilePath &workDir, + const Utils::Environment &env) const; + bool isEmptyCommandAllowed() const; void setAllowEmptyCommand(bool allow); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index d2fee3f2bda..86f93307147 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -127,6 +127,7 @@ #include #include #include +#include #include #include @@ -3794,6 +3795,13 @@ void ProjectExplorerPluginPrivate::showInFileSystemPane() Core::FileUtils::showInFileSystemView(currentNode->filePath()); } +static BuildConfiguration *activeBuildConfiguration(Project *project) +{ + if (!project || !project->activeTarget() || !project->activeTarget()->activeBuildConfiguration()) + return {}; + return project->activeTarget()->activeBuildConfiguration(); +} + void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env) { const Node *currentNode = ProjectTree::currentNode(); @@ -3803,7 +3811,21 @@ void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env if (!environment) return; - Core::FileUtils::openTerminal(currentNode->directory(), environment.value()); + BuildConfiguration *bc = activeBuildConfiguration(ProjectTree::projectForNode(currentNode)); + if (!bc) + Terminal::Hooks::instance().openTerminalHook()({{}, currentNode->directory(), environment}); + + IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(bc->target()->kit()); + + if (!buildDevice) + return; + + FilePath workingDir = currentNode->directory(); + if (!buildDevice->ensureReachable(workingDir)) + workingDir.clear(); + + const auto cmd = buildDevice->terminalCommand(workingDir, *environment); + Terminal::Hooks::instance().openTerminalHook()({cmd, workingDir, environment}); } void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() @@ -3824,9 +3846,12 @@ void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() if (!device) device = DeviceKitAspect::device(target->kit()); QTC_ASSERT(device && device->canOpenTerminal(), return); + const FilePath workingDir = device->type() == Constants::DESKTOP_DEVICE_TYPE ? currentNode->directory() : runnable.workingDirectory; - device->openTerminal(runnable.environment, workingDir); + + const auto cmd = device->terminalCommand(workingDir, runnable.environment); + Terminal::Hooks::instance().openTerminalHook()({cmd, workingDir, runnable.environment}); } void ProjectExplorerPluginPrivate::removeFile() diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt new file mode 100644 index 00000000000..14f6d844b36 --- /dev/null +++ b/src/plugins/terminal/CMakeLists.txt @@ -0,0 +1,17 @@ + +add_qtc_plugin(Terminal + SKIP_TRANSLATION + PLUGIN_DEPENDS Core + DEPENDS libvterm ptyqt + SOURCES + celllayout.cpp celllayout.h + terminalplugin.cpp terminalplugin.h + terminaltr.h + terminalpane.cpp terminalpane.h + terminalwidget.cpp terminalwidget.h + terminalprocessinterface.cpp terminalprocessinterface.h + terminalsettings.cpp terminalsettings.h + terminalsettingspage.cpp terminalsettingspage.h + scrollback.h scrollback.cpp + keys.cpp keys.h +) diff --git a/src/plugins/terminal/Terminal.json.in b/src/plugins/terminal/Terminal.json.in new file mode 100644 index 00000000000..3715f77fa31 --- /dev/null +++ b/src/plugins/terminal/Terminal.json.in @@ -0,0 +1,19 @@ +{ + \"Name\" : \"Terminal\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"DisabledByDefault\" : true, + \"Vendor\" : \"The Qt Company Ltd\", + \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", + \"\", + \"GNU General Public License Usage\", + \"\", + \"Alternatively, this plugin 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 plugin. 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.\" + ], + \"Description\" : \"Terminal window.\", + \"Url\" : \"http://www.qt.io\", + $$dependencyList +} diff --git a/src/plugins/terminal/celllayout.cpp b/src/plugins/terminal/celllayout.cpp new file mode 100644 index 00000000000..f9034dccce6 --- /dev/null +++ b/src/plugins/terminal/celllayout.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "celllayout.h" + +#include + +namespace Terminal::Internal { + +QColor toQColor(const VTermColor &c) +{ + return QColor(qRgb(c.rgb.red, c.rgb.green, c.rgb.blue)); +}; + +void createTextLayout(QTextLayout &textLayout, + QString &resultText, + VTermColor defaultBg, + QRect cellRect, + qreal lineSpacing, + std::function fetchCell) +{ + QList formats; + + QTextCharFormat currentFormat; + int currentFormatStart = 0; + currentFormat.setForeground(QColor(0xff, 0xff, 0xff)); + currentFormat.clearBackground(); + + resultText.clear(); + + for (int y = cellRect.y(); y < cellRect.bottom() + 1; y++) { + QTextCharFormat format; + + const auto setNewFormat = [&formats, ¤tFormatStart, &resultText, ¤tFormat]( + const QTextCharFormat &format) { + if (resultText.size() != currentFormatStart) { + QTextLayout::FormatRange fr; + fr.start = currentFormatStart; + fr.length = resultText.size() - currentFormatStart; + fr.format = currentFormat; + formats.append(fr); + + currentFormat = format; + currentFormatStart = resultText.size(); + } else { + currentFormat = format; + } + }; + + for (int x = cellRect.x(); x < cellRect.right() + 1; x++) { + const VTermScreenCell *cell = fetchCell(x, y); + + const VTermColor *bg = &cell->bg; + const VTermColor *fg = &cell->fg; + + if (static_cast(cell->attrs.reverse)) { + bg = &cell->fg; + fg = &cell->bg; + } + + format = QTextCharFormat(); + format.setForeground(toQColor(*fg)); + + if (!vterm_color_is_equal(bg, &defaultBg)) + format.setBackground(toQColor(*bg)); + else + format.clearBackground(); + + if (cell->attrs.bold) + format.setFontWeight(QFont::Bold); + if (cell->attrs.underline) + format.setFontUnderline(true); + if (cell->attrs.italic) + format.setFontItalic(true); + if (cell->attrs.strike) + format.setFontStrikeOut(true); + + if (format != currentFormat) + setNewFormat(format); + + if (cell->chars[0] != 0xFFFFFFFF) { + QString ch = QString::fromUcs4(cell->chars); + if (ch.size() > 0) { + resultText += ch; + } else { + resultText += QChar::Nbsp; + } + } + } // for x + setNewFormat(format); + if (y != cellRect.bottom()) + resultText.append(QChar::LineSeparator); + } // for y + + QTextLayout::FormatRange fr; + fr.start = currentFormatStart; + fr.length = (resultText.size() - 1) - currentFormatStart; + fr.format = currentFormat; + formats.append(fr); + + textLayout.setText(resultText); + textLayout.setFormats(formats); + + qreal height = 0; + textLayout.beginLayout(); + while (1) { + QTextLine line = textLayout.createLine(); + if (!line.isValid()) + break; + + // Just give it a number that is definitely larger than + // the number of columns in a line. + line.setNumColumns(std::numeric_limits::max()); + line.setPosition(QPointF(0, height)); + height += lineSpacing; + } + textLayout.endLayout(); +} + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/celllayout.h b/src/plugins/terminal/celllayout.h new file mode 100644 index 00000000000..286ed8944fb --- /dev/null +++ b/src/plugins/terminal/celllayout.h @@ -0,0 +1,27 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include + +namespace Terminal::Internal { + +QColor toQColor(const VTermColor &c); + +void createTextLayout(QTextLayout &textLayout, + QString &resultText, + VTermColor defaultBg, + QRect cellRect, + qreal lineSpacing, + std::function fetchCell); + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/keys.cpp b/src/plugins/terminal/keys.cpp new file mode 100644 index 00000000000..f6a7a91b13d --- /dev/null +++ b/src/plugins/terminal/keys.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "keys.h" + +namespace Terminal::Internal { + +VTermModifier qtModifierToVTerm(Qt::KeyboardModifiers mod) +{ + int ret = VTERM_MOD_NONE; + + if (mod & Qt::ShiftModifier) + ret |= VTERM_MOD_SHIFT; + + if (mod & Qt::AltModifier) + ret |= VTERM_MOD_ALT; + +#ifdef Q_OS_DARWIN + if (mod & Qt::MetaModifier) + ret |= VTERM_MOD_CTRL; +#else + if (mod & Qt::ControlModifier) + ret |= VTERM_MOD_CTRL; +#endif + + return static_cast(ret); +} + +VTermKey qtKeyToVTerm(Qt::Key key, bool keypad) +{ + if (key >= Qt::Key_F1 && key <= Qt::Key_F35) + return static_cast(VTERM_KEY_FUNCTION_0 + key - Qt::Key_F1 + 1); + + switch (key) { + case Qt::Key_Return: + return VTERM_KEY_ENTER; + case Qt::Key_Tab: + return VTERM_KEY_TAB; + case Qt::Key_Backspace: + return VTERM_KEY_BACKSPACE; + case Qt::Key_Escape: + return VTERM_KEY_ESCAPE; + case Qt::Key_Up: + return VTERM_KEY_UP; + case Qt::Key_Down: + return VTERM_KEY_DOWN; + case Qt::Key_Left: + return VTERM_KEY_LEFT; + case Qt::Key_Right: + return VTERM_KEY_RIGHT; + case Qt::Key_Insert: + return VTERM_KEY_INS; + case Qt::Key_Delete: + return VTERM_KEY_DEL; + case Qt::Key_Home: + return VTERM_KEY_HOME; + case Qt::Key_End: + return VTERM_KEY_END; + case Qt::Key_PageUp: + return VTERM_KEY_PAGEUP; + case Qt::Key_PageDown: + return VTERM_KEY_PAGEDOWN; + case Qt::Key_multiply: + return keypad ? VTERM_KEY_KP_MULT : VTERM_KEY_NONE; + case Qt::Key_Plus: + return keypad ? VTERM_KEY_KP_PLUS : VTERM_KEY_NONE; + case Qt::Key_Comma: + return keypad ? VTERM_KEY_KP_COMMA : VTERM_KEY_NONE; + case Qt::Key_Minus: + return keypad ? VTERM_KEY_KP_MINUS : VTERM_KEY_NONE; + case Qt::Key_Period: + return keypad ? VTERM_KEY_KP_PERIOD : VTERM_KEY_NONE; + case Qt::Key_Slash: + return keypad ? VTERM_KEY_KP_DIVIDE : VTERM_KEY_NONE; + case Qt::Key_Enter: + return keypad ? VTERM_KEY_KP_ENTER : VTERM_KEY_NONE; + case Qt::Key_Equal: + return keypad ? VTERM_KEY_KP_EQUAL : VTERM_KEY_NONE; + default: + return VTERM_KEY_NONE; + } +} +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/keys.h b/src/plugins/terminal/keys.h new file mode 100644 index 00000000000..f3df9330013 --- /dev/null +++ b/src/plugins/terminal/keys.h @@ -0,0 +1,15 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include + +namespace Terminal::Internal { + +VTermKey qtKeyToVTerm(Qt::Key key, bool keypad); +VTermModifier qtModifierToVTerm(Qt::KeyboardModifiers mod); + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/scrollback.cpp b/src/plugins/terminal/scrollback.cpp new file mode 100644 index 00000000000..8a07c700f8d --- /dev/null +++ b/src/plugins/terminal/scrollback.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2020, Justin Bronder +// Copied and modified from: https://github.com/jsbronder/sff +// SPDX-License-Identifier: BSD-3-Clause + +#include "scrollback.h" +#include "celllayout.h" + +#include +#include + +namespace Terminal::Internal { + +Scrollback::Line::Line(int cols, const VTermScreenCell *cells, VTermState *vts) + : m_cols(cols) + , m_cells(std::make_unique(cols)) + +{ + memcpy(m_cells.get(), cells, cols * sizeof(cells[0])); + for (int i = 0; i < cols; ++i) { + vterm_state_convert_color_to_rgb(vts, &m_cells[i].fg); + vterm_state_convert_color_to_rgb(vts, &m_cells[i].bg); + } + m_layout = std::make_unique(); +} + +const VTermScreenCell *Scrollback::Line::cell(int i) const +{ + assert(i >= 0 && i < m_cols); + return &m_cells[i]; +} + +const QTextLayout &Scrollback::Line::layout(int version, const QFont &font, qreal lineSpacing) const +{ + if (m_layoutVersion != version) { + QString text; + VTermColor defaultBg; + defaultBg.type = VTERM_COLOR_DEFAULT_BG; + m_layout->clearLayout(); + m_layout->setFont(font); + createTextLayout(*m_layout, + text, + defaultBg, + QRect(0, 0, m_cols, 1), + lineSpacing, + [this](int x, int) { return &m_cells[x]; }); + m_layoutVersion = version; + } + return *m_layout; +} + +Scrollback::Scrollback(size_t capacity) + : m_capacity(capacity) +{} + +void Scrollback::emplace(int cols, const VTermScreenCell *cells, VTermState *vts) +{ + m_deque.emplace_front(cols, cells, vts); + while (m_deque.size() > m_capacity) + m_deque.pop_back(); +} + +void Scrollback::popto(int cols, VTermScreenCell *cells) +{ + const Line &sbl = m_deque.front(); + + int ncells = cols; + if (ncells > sbl.cols()) + ncells = sbl.cols(); + + memcpy(cells, sbl.cells(), sizeof(cells[0]) * ncells); + for (size_t i = ncells; i < static_cast(cols); ++i) { + cells[i].chars[0] = '\0'; + cells[i].width = 1; + cells[i].bg = cells[ncells - 1].bg; + } + + m_deque.pop_front(); +} + +size_t Scrollback::scroll(int delta) +{ + m_offset = std::min(std::max(0, static_cast(m_offset) + delta), + static_cast(m_deque.size())); + return m_offset; +} + +void Scrollback::clear() +{ + m_offset = 0; + m_deque.clear(); +} + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/scrollback.h b/src/plugins/terminal/scrollback.h new file mode 100644 index 00000000000..63c18772b93 --- /dev/null +++ b/src/plugins/terminal/scrollback.h @@ -0,0 +1,66 @@ +// Copyright (c) 2020, Justin Bronder +// Copied and modified from: https://github.com/jsbronder/sff +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace Terminal::Internal { + +class Scrollback +{ +public: + class Line + { + public: + Line(int cols, const VTermScreenCell *cells, VTermState *vts); + Line(Line &&other) = default; + Line() = delete; + + int cols() const { return m_cols; }; + const VTermScreenCell *cell(int i) const; + const VTermScreenCell *cells() const { return &m_cells[0]; }; + + const QTextLayout &layout(int version, const QFont &font, qreal lineSpacing) const; + + private: + int m_cols; + std::unique_ptr m_cells; + std::unique_ptr m_layout; + mutable int m_layoutVersion{-1}; + }; + +public: + Scrollback(size_t capacity); + Scrollback() = delete; + + size_t capacity() const { return m_capacity; }; + size_t size() const { return m_deque.size(); }; + size_t offset() const { return m_offset; }; + + const Line &line(size_t index) const { return m_deque.at(index); }; + const std::deque &lines() const { return m_deque; }; + + void emplace(int cols, + const VTermScreenCell *cells, + VTermState *vts); + void popto(int cols, VTermScreenCell *cells); + size_t scroll(int delta); + void unscroll() { m_offset = 0; }; + + void clear(); + +private: + size_t m_capacity; + size_t m_offset{0}; + std::deque m_deque; +}; + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs new file mode 100644 index 00000000000..54743641107 --- /dev/null +++ b/src/plugins/terminal/terminal.qbs @@ -0,0 +1,32 @@ +import qbs 1.0 + +QtcPlugin { + name: "Terminal" + + Depends { name: "Core" } + Depends { name: "vterm" } + Depends { name: "ptyqt" } + + files: [ + "celllayout.cpp", + "celllayout.h", + "keys.cpp", + "keys.h", + "scrollback.cpp", + "scrollback.h", + "terminalpane.cpp", + "terminalpane.h", + "terminalplugin.cpp", + "terminalplugin.h", + "terminalprocessinterface.cpp", + "terminalprocessinterface.h", + "terminalsettings.cpp", + "terminalsettings.h", + "terminalsettingspage.cpp", + "terminalsettingspage.h", + "terminaltr.h", + "terminalwidget.cpp", + "terminalwidget.h", + ] +} + diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp new file mode 100644 index 00000000000..5e57317c0fc --- /dev/null +++ b/src/plugins/terminal/terminalpane.cpp @@ -0,0 +1,176 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalpane.h" + +#include "terminaltr.h" +#include "terminalwidget.h" + +#include +#include + +#include + +namespace Terminal { + +TerminalPane::TerminalPane(QObject *parent) + : Core::IOutputPane(parent) +{ + Core::Context context("Terminal.Window"); + + m_newTerminal.setIcon(Utils::Icons::PLUS_TOOLBAR.icon()); + m_newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); + + connect(&m_newTerminal, &QAction::triggered, this, [this] { + m_tabWidget->setCurrentIndex( + m_tabWidget->addTab(new TerminalWidget(m_tabWidget), Tr::tr("Terminal"))); + + m_closeTerminal.setEnabled(m_tabWidget->count() > 1); + emit navigateStateUpdate(); + }); + + m_closeTerminal.setIcon(Utils::Icons::CLOSE_TOOLBAR.icon()); + m_closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); + m_closeTerminal.setEnabled(false); + + connect(&m_closeTerminal, &QAction::triggered, this, [this] { + removeTab(m_tabWidget->currentIndex()); + }); + + //Core::Command *cmd = Core::ActionManager::registerAction(m_newTerminal, Constants::STOP); + //cmd->setDescription(m_newTerminal->toolTip()); + + m_newTerminalButton = new QToolButton(); + m_newTerminalButton->setDefaultAction(&m_newTerminal); + + m_closeTerminalButton = new QToolButton(); + m_closeTerminalButton->setDefaultAction(&m_closeTerminal); +} + +void TerminalPane::openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters) +{ + showPage(0); + m_tabWidget->setCurrentIndex( + m_tabWidget->addTab(new TerminalWidget(m_tabWidget, parameters), Tr::tr("Terminal"))); + + m_closeTerminal.setEnabled(m_tabWidget->count() > 1); + emit navigateStateUpdate(); +} + +void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) +{ + showPage(0); + m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminal, title)); + + m_closeTerminal.setEnabled(m_tabWidget->count() > 1); + emit navigateStateUpdate(); +} + +QWidget *TerminalPane::outputWidget(QWidget *parent) +{ + if (!m_tabWidget) { + m_tabWidget = new QTabWidget(parent); + + m_tabWidget->setTabBarAutoHide(true); + m_tabWidget->setDocumentMode(true); + m_tabWidget->setTabsClosable(true); + m_tabWidget->setMovable(true); + + connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int index) { + removeTab(index); + }); + + m_tabWidget->addTab(new TerminalWidget(parent), Tr::tr("Terminal")); + } + + return m_tabWidget; +} + +TerminalWidget *TerminalPane::currentTerminal() const +{ + QWidget *activeWidget = m_tabWidget->currentWidget(); + return static_cast(activeWidget); +} + +void TerminalPane::removeTab(int index) +{ + if (m_tabWidget->count() > 1) + delete m_tabWidget->widget(index); + + m_closeTerminal.setEnabled(m_tabWidget->count() > 1); + emit navigateStateUpdate(); +} + +QList TerminalPane::toolBarWidgets() const +{ + return {m_newTerminalButton, m_closeTerminalButton}; +} + +QString TerminalPane::displayName() const +{ + return Tr::tr("Terminal"); +} + +int TerminalPane::priorityInStatusBar() const +{ + return 50; +} + +void TerminalPane::clearContents() +{ + if (const auto t = currentTerminal()) + t->clearContents(); +} + +void TerminalPane::visibilityChanged(bool visible) +{ + Q_UNUSED(visible); +} + +void TerminalPane::setFocus() +{ + if (const auto t = currentTerminal()) + t->setFocus(); +} + +bool TerminalPane::hasFocus() const +{ + if (const auto t = currentTerminal()) + t->hasFocus(); + + return false; +} + +bool TerminalPane::canFocus() const +{ + return true; +} + +bool TerminalPane::canNavigate() const +{ + return true; +} + +bool TerminalPane::canNext() const +{ + return m_tabWidget->count() > 1 && m_tabWidget->currentIndex() < m_tabWidget->count() - 1; +} + +bool TerminalPane::canPrevious() const +{ + return m_tabWidget->count() > 1 && m_tabWidget->currentIndex() > 0; +} + +void TerminalPane::goToNext() +{ + m_tabWidget->setCurrentIndex(m_tabWidget->currentIndex() + 1); + emit navigateStateUpdate(); +} + +void TerminalPane::goToPrev() +{ + m_tabWidget->setCurrentIndex(m_tabWidget->currentIndex() - 1); + emit navigateStateUpdate(); +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h new file mode 100644 index 00000000000..3dea1c84142 --- /dev/null +++ b/src/plugins/terminal/terminalpane.h @@ -0,0 +1,57 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include + +#include +#include +#include + +namespace Terminal { + +class TerminalWidget; + +class TerminalPane : public Core::IOutputPane +{ + Q_OBJECT +public: + TerminalPane(QObject *parent = nullptr); + + virtual QWidget *outputWidget(QWidget *parent); + virtual QList toolBarWidgets() const; + virtual QString displayName() const; + virtual int priorityInStatusBar() const; + virtual void clearContents(); + virtual void visibilityChanged(bool visible); + virtual void setFocus(); + virtual bool hasFocus() const; + virtual bool canFocus() const; + virtual bool canNavigate() const; + virtual bool canNext() const; + virtual bool canPrevious() const; + virtual void goToNext(); + virtual void goToPrev(); + + void openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters); + void addTerminal(TerminalWidget *terminal, const QString &title); + +private: + TerminalWidget *currentTerminal() const; + + void removeTab(int index); + +private: + QTabWidget *m_tabWidget{nullptr}; + + QToolButton *m_newTerminalButton{nullptr}; + QToolButton *m_closeTerminalButton{nullptr}; + + QAction m_newTerminal; + QAction m_closeTerminal; +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp new file mode 100644 index 00000000000..ce196441182 --- /dev/null +++ b/src/plugins/terminal/terminalplugin.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "terminalplugin.h" + +#include "terminalpane.h" +#include "terminalprocessinterface.h" +#include "terminalsettings.h" +#include "terminalsettingspage.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace Terminal { +namespace Internal { + +TerminalPlugin::TerminalPlugin() {} + +TerminalPlugin::~TerminalPlugin() +{ + ExtensionSystem::PluginManager::instance()->removeObject(m_terminalPane); + delete m_terminalPane; + m_terminalPane = nullptr; +} + +void TerminalPlugin::extensionsInitialized() +{ + TerminalSettingsPage::instance().init(); + TerminalSettings::instance().readSettings(Core::ICore::settings()); + + m_terminalPane = new TerminalPane(); + ExtensionSystem::PluginManager::instance()->addObject(m_terminalPane); + + Utils::Terminal::Hooks::instance().openTerminalHook().set( + [this](const Utils::Terminal::OpenTerminalParameters &p) { + m_terminalPane->openTerminal(p); + }); + + /*Utils::Terminal::Hooks::instance().createTerminalProcessInterfaceHook().set( + [this]() -> Utils::ProcessInterface * { + return new TerminalProcessInterface(m_terminalPane); + });*/ +} + +} // namespace Internal +} // namespace Terminal diff --git a/src/plugins/terminal/terminalplugin.h b/src/plugins/terminal/terminalplugin.h new file mode 100644 index 00000000000..5e39dded711 --- /dev/null +++ b/src/plugins/terminal/terminalplugin.h @@ -0,0 +1,29 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Terminal { + +class TerminalPane; +namespace Internal { + +class TerminalPlugin : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Terminal.json") + +public: + TerminalPlugin(); + ~TerminalPlugin() override; + + void extensionsInitialized() override; + +private: + TerminalPane *m_terminalPane{nullptr}; +}; + +} // namespace Internal +} // namespace Terminal diff --git a/src/plugins/terminal/terminalprocessinterface.cpp b/src/plugins/terminal/terminalprocessinterface.cpp new file mode 100644 index 00000000000..75f56338146 --- /dev/null +++ b/src/plugins/terminal/terminalprocessinterface.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalprocessinterface.h" +#include "terminalwidget.h" + +namespace Terminal { + +TerminalProcessInterface::TerminalProcessInterface(TerminalPane *terminalPane) + : m_terminalPane(terminalPane) +{} + +// It's being called only in Starting state. Just before this method is being called, +// the process transitions from NotRunning into Starting state. +void TerminalProcessInterface::start() +{ + QTC_ASSERT(!m_setup.m_commandLine.executable().needsDevice(), return); + + TerminalWidget *terminal = new TerminalWidget(nullptr, + {m_setup.m_commandLine, + m_setup.m_workingDirectory, + m_setup.m_environment, + Utils::Terminal::ExitBehavior::Keep}); + + connect(terminal, &TerminalWidget::started, this, [this](qint64 pid) { emit started(pid); }); + + connect(terminal, &QObject::destroyed, this, [this]() { + emit done(Utils::ProcessResultData{}); + }); + + m_terminalPane->addTerminal(terminal, "App"); +} + +// It's being called only in Running state. +qint64 TerminalProcessInterface::write(const QByteArray &data) +{ + Q_UNUSED(data); + return 0; +} + +// It's being called in Starting or Running state. +void TerminalProcessInterface::sendControlSignal(Utils::ControlSignal controlSignal) +{ + Q_UNUSED(controlSignal); +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalprocessinterface.h b/src/plugins/terminal/terminalprocessinterface.h new file mode 100644 index 00000000000..55dc7be3f80 --- /dev/null +++ b/src/plugins/terminal/terminalprocessinterface.h @@ -0,0 +1,49 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "terminalpane.h" + +#include + +namespace Terminal { + +class TerminalProcessInterface : public Utils::ProcessInterface +{ + Q_OBJECT + +public: + TerminalProcessInterface(TerminalPane *terminalPane); + + /* + // This should be emitted when being in Starting state only. + // After emitting this signal the process enters Running state. + void started(qint64 processId, qint64 applicationMainThreadId = 0); + + // This should be emitted when being in Running state only. + void readyRead(const QByteArray &outputData, const QByteArray &errorData); + + // This should be emitted when being in Starting or Running state. + // When being in Starting state, the resultData should set error to FailedToStart. + // After emitting this signal the process enters NotRunning state. + void done(const Utils::ProcessResultData &resultData); +*/ +private: + // It's being called only in Starting state. Just before this method is being called, + // the process transitions from NotRunning into Starting state. + void start() override; + + // It's being called only in Running state. + qint64 write(const QByteArray &data) override; + + // It's being called in Starting or Running state. + void sendControlSignal(Utils::ControlSignal controlSignal) override; + + //Utils::ProcessBlockingInterface *processBlockingInterface() const { return nullptr; } + +private: + TerminalPane *m_terminalPane; +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp new file mode 100644 index 00000000000..a69a1e56810 --- /dev/null +++ b/src/plugins/terminal/terminalsettings.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalsettings.h" + +#include "terminaltr.h" + +#include +#include + +using namespace Utils; + +namespace Terminal { + +static QString defaultFontFamily() +{ + if (HostOsInfo::isMacHost()) + return QLatin1String("Menlo"); + + if (Utils::HostOsInfo::isAnyUnixHost()) + return QLatin1String("Monospace"); + + return QLatin1String("Consolas"); +} + +static int defaultFontSize() +{ + if (Utils::HostOsInfo::isMacHost()) + return 12; + if (Utils::HostOsInfo::isAnyUnixHost()) + return 9; + return 10; +} + +static QString defaultShell() +{ + if (Utils::HostOsInfo::isMacHost()) + return "/bin/zsh"; + if (Utils::HostOsInfo::isAnyUnixHost()) + return "/bin/bash"; + return qtcEnvironmentVariable("COMSPEC"); +} + +TerminalSettings &TerminalSettings::instance() +{ + static TerminalSettings settings; + return settings; +} + +void setupColor(ColorAspect &color, const QString &label, const QColor &defaultColor) +{ + color.setSettingsKey(label); + color.setDefaultValue(defaultColor); + color.setToolTip(Tr::tr("The color used for %1.").arg(label)); +} + +TerminalSettings::TerminalSettings() +{ + setAutoApply(false); + setSettingsGroup("Terminal"); + + font.setSettingsKey("FontFamily"); + font.setLabelText(Tr::tr("Family:")); + font.setHistoryCompleter("Terminal.Fonts.History"); + font.setToolTip(Tr::tr("The font family used in the terminal.")); + font.setDefaultValue(defaultFontFamily()); + + fontSize.setSettingsKey("FontSize"); + fontSize.setLabelText(Tr::tr("Size:")); + fontSize.setToolTip(Tr::tr("The font size used in the terminal. (in points)")); + fontSize.setDefaultValue(defaultFontSize()); + fontSize.setRange(1, 100); + + shell.setSettingsKey("ShellPath"); + shell.setLabelText(Tr::tr("Shell path:")); + shell.setExpectedKind(PathChooser::ExistingCommand); + shell.setDisplayStyle(StringAspect::PathChooserDisplay); + shell.setHistoryCompleter("Terminal.Shell.History"); + shell.setToolTip(Tr::tr("The shell executable to be started as terminal")); + shell.setDefaultValue(defaultShell()); + + setupColor(foregroundColor, "Foreground", QColor::fromRgb(0xff, 0xff, 0xff)); + setupColor(backgroundColor, "Background", QColor::fromRgb(0x0, 0x0, 0x0)); + + setupColor(colors[0], "0", QColor::fromRgb(0x00, 0x00, 0x00)); + setupColor(colors[8], "8", QColor::fromRgb(102, 102, 102)); + + setupColor(colors[1], "1", QColor::fromRgb(139, 27, 16)); + setupColor(colors[9], "9", QColor::fromRgb(210, 45, 31)); + + setupColor(colors[2], "2", QColor::fromRgb(74, 163, 46)); + setupColor(colors[10], "10", QColor::fromRgb(98, 214, 63)); + + setupColor(colors[3], "3", QColor::fromRgb(154, 154, 47)); + setupColor(colors[11], "11", QColor::fromRgb(229, 229, 75)); + + setupColor(colors[4], "4", QColor::fromRgb(0, 0, 171)); + setupColor(colors[12], "12", QColor::fromRgb(0, 0, 254)); + + setupColor(colors[5], "5", QColor::fromRgb(163, 32, 172)); + setupColor(colors[13], "13", QColor::fromRgb(210, 45, 222)); + + setupColor(colors[6], "6", QColor::fromRgb(73, 163, 176)); + setupColor(colors[14], "14", QColor::fromRgb(105, 226, 228)); + + setupColor(colors[7], "7", QColor::fromRgb(191, 191, 191)); + setupColor(colors[15], "15", QColor::fromRgb(229, 229, 230)); + + registerAspect(&font); + registerAspect(&fontSize); + registerAspect(&shell); + + registerAspect(&foregroundColor); + registerAspect(&backgroundColor); + + for (auto &color : colors) + registerAspect(&color); +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h new file mode 100644 index 00000000000..82557b207c1 --- /dev/null +++ b/src/plugins/terminal/terminalsettings.h @@ -0,0 +1,26 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Terminal { +class TerminalSettings : public Utils::AspectContainer +{ +public: + TerminalSettings(); + + static TerminalSettings &instance(); + + Utils::StringAspect font; + Utils::IntegerAspect fontSize; + Utils::StringAspect shell; + + Utils::ColorAspect foregroundColor; + Utils::ColorAspect backgroundColor; + + Utils::ColorAspect colors[16]; +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp new file mode 100644 index 00000000000..b85b4a1321b --- /dev/null +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -0,0 +1,96 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalsettingspage.h" + +#include "terminalsettings.h" +#include "terminaltr.h" + +#include + +#include +#include + +#include + +using namespace Utils; + +namespace Terminal { + +TerminalSettingsPage::TerminalSettingsPage() +{ + setId("Terminal.General"); + setDisplayName("Terminal"); + setCategory("ZY.Terminal"); + setDisplayCategory("Terminal"); + setSettings(&TerminalSettings::instance()); + + // TODO: Add real icon! + setCategoryIconPath(":/texteditor/images/settingscategory_texteditor.png"); +} + +void TerminalSettingsPage::init() {} + +QWidget *TerminalSettingsPage::widget() +{ + QWidget *widget = new QWidget; + + using namespace Layouting; + + QFontComboBox *fontComboBox = new QFontComboBox(widget); + fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts); + fontComboBox->setCurrentFont(TerminalSettings::instance().font.value()); + + connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [](const QFont &f) { + TerminalSettings::instance().font.setValue(f.family()); + }); + + TerminalSettings &settings = TerminalSettings::instance(); + + // clang-format off + Column { + Group { + title(Tr::tr("Font")), + Row { + settings.font.labelText(), fontComboBox, Space(20), + settings.fontSize, st, + }, + }, + Group { + title(Tr::tr("Colors")), + Column { + Row { + Tr::tr("Foreground"), settings.foregroundColor, st, + Tr::tr("Background"), settings.backgroundColor, st, + }, + Row { + settings.colors[0], settings.colors[1], + settings.colors[2], settings.colors[3], + settings.colors[4], settings.colors[5], + settings.colors[6], settings.colors[7] + }, + Row { + settings.colors[8], settings.colors[9], + settings.colors[10], settings.colors[11], + settings.colors[12], settings.colors[13], + settings.colors[14], settings.colors[15] + }, + } + }, + Row { + settings.shell, + }, + st, + }.attachTo(widget); + // clang-format on + + return widget; +} + +TerminalSettingsPage &TerminalSettingsPage::instance() +{ + static TerminalSettingsPage settingsPage; + return settingsPage; +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalsettingspage.h b/src/plugins/terminal/terminalsettingspage.h new file mode 100644 index 00000000000..4c12697b13f --- /dev/null +++ b/src/plugins/terminal/terminalsettingspage.h @@ -0,0 +1,22 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Terminal { + +class TerminalSettingsPage : public Core::IOptionsPage +{ +public: + TerminalSettingsPage(); + + static TerminalSettingsPage &instance(); + + void init(); + + QWidget *widget() override; +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminaltr.h b/src/plugins/terminal/terminaltr.h new file mode 100644 index 00000000000..711e0e82000 --- /dev/null +++ b/src/plugins/terminal/terminaltr.h @@ -0,0 +1,15 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Terminal { + +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(::Terminal) +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp new file mode 100644 index 00000000000..a6169846291 --- /dev/null +++ b/src/plugins/terminal/terminalwidget.cpp @@ -0,0 +1,942 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalwidget.h" +#include "celllayout.h" +#include "keys.h" +#include "terminalsettings.h" +#include "terminaltr.h" + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(terminalLog, "qtc.terminal", QtWarningMsg) + +using namespace Utils; +using namespace Utils::Terminal; + +namespace Terminal { + +TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &openParameters) + : QAbstractScrollArea(parent) + , m_vterm(vterm_new(size().height(), size().width()), vterm_free) + , m_vtermScreen(vterm_obtain_screen(m_vterm.get())) + , m_scrollback(std::make_unique(5000)) + , m_copyAction(Tr::tr("Copy")) + , m_pasteAction(Tr::tr("Paste")) + , m_clearSelectionAction(Tr::tr("Clear Selection")) + , m_zoomInAction(Tr::tr("Zoom In")) + , m_zoomOutAction(Tr::tr("Zoom Out")) + , m_openParameters(openParameters) +{ + setupVTerm(); + setupFont(); + setupColors(); + + setAttribute(Qt::WA_InputMethodEnabled); + setAttribute(Qt::WA_MouseTracking); + + setCursor(Qt::IBeamCursor); + + m_textLayout.setCacheEnabled(true); + + setFocus(); + setFocusPolicy(Qt::StrongFocus); + + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + // setFrameStyle(QFrame::NoFrame); + setAttribute(Qt::WA_OpaquePaintEvent); + + m_readDelayTimer.setSingleShot(true); + m_readDelayTimer.setInterval(10); + + connect(&m_readDelayTimer, &QTimer::timeout, this, [this]() { + m_readDelayRestarts = 0; + onReadyRead(); + }); + + connect(&m_copyAction, &QAction::triggered, this, &TerminalWidget::copyToClipboard); + connect(&m_pasteAction, &QAction::triggered, this, &TerminalWidget::pasteFromClipboard); + connect(&m_clearSelectionAction, &QAction::triggered, this, &TerminalWidget::clearSelection); + connect(&m_zoomInAction, &QAction::triggered, this, &TerminalWidget::zoomIn); + connect(&m_zoomOutAction, &QAction::triggered, this, &TerminalWidget::zoomOut); + + connect(&TerminalSettings::instance(), &AspectContainer::applied, this, [this]() { + m_layoutVersion++; + // Setup colors first, as setupFont will redraw the screen. + setupColors(); + setupFont(); + }); +} + +void TerminalWidget::setupPty() +{ + m_ptyProcess.reset(PtyQt::createPtyProcess(IPtyProcess::PtyType::AutoPty)); + + Environment env = m_openParameters.environment.value_or(Environment::systemEnvironment()); + // Why? + env.appendOrSetPath(TerminalSettings::instance().shell.filePath().parentDir()); + + CommandLine shellCommand = m_openParameters.shellCommand.value_or( + CommandLine{TerminalSettings::instance().shell.filePath(), {}}); + + QStringList envList = filtered(env.toStringList(), [](const QString &envPair) { + return envPair != "CLINK_NOAUTORUN=1"; + }); + + m_ptyProcess->startProcess(shellCommand.executable().nativePath(), + shellCommand.splitArguments(), + m_openParameters.workingDirectory + .value_or(FilePath::fromString(QDir::homePath())) + .nativePath(), + envList, + m_vtermSize.width(), + m_vtermSize.height()); + + emit started(m_ptyProcess->pid()); + + if (!m_ptyProcess->lastError().isEmpty()) { + qCWarning(terminalLog) << m_ptyProcess->lastError(); + m_ptyProcess.reset(); + return; + } + + connect(m_ptyProcess->notifier(), &QIODevice::readyRead, this, [this]() { + if (m_readDelayTimer.isActive()) + m_readDelayRestarts++; + + if (m_readDelayRestarts > 100) + return; + + m_readDelayTimer.start(); + }); + + connect(m_ptyProcess->notifier(), &QIODevice::aboutToClose, this, [this]() { + m_cursor.visible = false; + if (m_ptyProcess) { + onReadyRead(); + + if (m_ptyProcess->exitCode() != 0) { + QByteArray msg = QString("\r\n\033[31mProcess exited with code: %1") + .arg(m_ptyProcess->exitCode()) + .toUtf8(); + + vterm_input_write(m_vterm.get(), msg.constData(), msg.size()); + vterm_screen_flush_damage(m_vtermScreen); + + return; + } + } + + if (m_openParameters.m_exitBehavior == ExitBehavior::Restart) { + QMetaObject::invokeMethod( + this, + [this]() { + m_ptyProcess.reset(); + setupPty(); + }, + Qt::QueuedConnection); + } + + if (m_openParameters.m_exitBehavior == ExitBehavior::Close) + deleteLater(); + + if (m_openParameters.m_exitBehavior == ExitBehavior::Keep) { + QByteArray msg = QString("\r\nProcess exited with code: %1") + .arg(m_ptyProcess ? m_ptyProcess->exitCode() : -1) + .toUtf8(); + + vterm_input_write(m_vterm.get(), msg.constData(), msg.size()); + vterm_screen_flush_damage(m_vtermScreen); + } + }); +} + +void TerminalWidget::setupFont() +{ + QFont f; + f.setFixedPitch(true); + f.setFamily(TerminalSettings::instance().font.value()); + f.setPointSize(TerminalSettings::instance().fontSize.value()); + + setFont(f); +} + +void TerminalWidget::setupColors() +{ + // Check if the colors have changed. + std::array newColors; + for (int i = 0; i < 16; ++i) { + newColors[i] = TerminalSettings::instance().colors[i].value(); + } + newColors[16] = TerminalSettings::instance().foregroundColor.value(); + newColors[17] = TerminalSettings::instance().backgroundColor.value(); + + if (m_currentColors == newColors) + return; + + m_currentColors = newColors; + + VTermState *vts = vterm_obtain_state(m_vterm.get()); + + auto setColor = [vts](int index, uint8_t r, uint8_t g, uint8_t b) { + VTermColor col; + vterm_color_rgb(&col, r, g, b); + vterm_state_set_palette_color(vts, index, &col); + }; + + for (int i = 0; i < 16; ++i) { + QColor c = TerminalSettings::instance().colors[i].value(); + setColor(i, c.red(), c.green(), c.blue()); + } + + VTermColor fg; + VTermColor bg; + + vterm_color_rgb(&fg, + TerminalSettings::instance().foregroundColor.value().red(), + TerminalSettings::instance().foregroundColor.value().green(), + TerminalSettings::instance().foregroundColor.value().blue()); + vterm_color_rgb(&bg, + TerminalSettings::instance().backgroundColor.value().red(), + TerminalSettings::instance().backgroundColor.value().green(), + TerminalSettings::instance().backgroundColor.value().blue()); + + vterm_state_set_default_colors(vts, &fg, &bg); + + clearContents(); +} + +void TerminalWidget::writeToPty(const QByteArray &data) +{ + if (m_ptyProcess) + m_ptyProcess->write(data); +} + +void TerminalWidget::setupVTerm() +{ + vterm_set_utf8(m_vterm.get(), true); + + static auto writeToPty = [](const char *s, size_t len, void *user) { + auto p = static_cast(user); + p->writeToPty(QByteArray(s, static_cast(len))); + }; + + vterm_output_set_callback(m_vterm.get(), writeToPty, this); + + memset(&m_vtermScreenCallbacks, 0, sizeof(m_vtermScreenCallbacks)); + + m_vtermScreenCallbacks.damage = [](VTermRect rect, void *user) { + auto p = static_cast(user); + p->invalidate(rect); + return 1; + }; + m_vtermScreenCallbacks.sb_pushline = [](int cols, const VTermScreenCell *cells, void *user) { + auto p = static_cast(user); + return p->sb_pushline(cols, cells); + }; + m_vtermScreenCallbacks.sb_popline = [](int cols, VTermScreenCell *cells, void *user) { + auto p = static_cast(user); + return p->sb_popline(cols, cells); + }; + m_vtermScreenCallbacks.settermprop = [](VTermProp prop, VTermValue *val, void *user) { + auto p = static_cast(user); + return p->setTerminalProperties(prop, val); + }; + m_vtermScreenCallbacks.movecursor = [](VTermPos pos, VTermPos oldpos, int visible, void *user) { + auto p = static_cast(user); + return p->movecursor(pos, oldpos, visible); + }; + + m_vtermScreenCallbacks.sb_clear = [](void *user) { + auto p = static_cast(user); + return p->sb_clear(); + }; + + vterm_screen_set_callbacks(m_vtermScreen, &m_vtermScreenCallbacks, this); + vterm_screen_set_damage_merge(m_vtermScreen, VTERM_DAMAGE_SCROLL); + vterm_screen_enable_altscreen(m_vtermScreen, true); + + VTermState *vts = vterm_obtain_state(m_vterm.get()); + vterm_state_set_bold_highbright(vts, true); + + vterm_screen_reset(m_vtermScreen, 1); +} + +void TerminalWidget::setFont(const QFont &font) +{ + m_font = font; + + //QRawFont rawFont = QRawFont::fromFont(m_font); + m_textLayout.setFont(m_font); + + QFontMetricsF qfm{m_font}; + const auto w = [qfm]() -> qreal { + if (HostOsInfo::isMacHost()) + return qfm.maxWidth(); + return qfm.averageCharWidth(); + }(); + + qCInfo(terminalLog) << font.family() << font.pointSize() << w << size(); + + m_cellSize = {w, qfm.height()}; + m_cellBaseline = qfm.ascent(); + m_lineSpacing = qfm.height(); + + QAbstractScrollArea::setFont(m_font); + + if (m_ptyProcess) { + applySizeChange(); + } +} + +QAction &TerminalWidget::copyAction() +{ + return m_copyAction; +} + +QAction &TerminalWidget::pasteAction() +{ + return m_pasteAction; +} + +QAction &TerminalWidget::clearSelectionAction() +{ + return m_clearSelectionAction; +} + +QAction &TerminalWidget::zoomInAction() +{ + return m_zoomInAction; +} + +QAction &TerminalWidget::zoomOutAction() +{ + return m_zoomOutAction; +} + +void TerminalWidget::copyToClipboard() const +{ + if (m_selection) { + const size_t startLine = qFloor(m_selection->start.y() / m_lineSpacing); + const size_t endLine = qFloor(m_selection->end.y() / m_lineSpacing); + + QString selectedText; + size_t row = startLine; + for (; row < m_scrollback->size(); row++) { + const Internal::Scrollback::Line &line = m_scrollback->line((m_scrollback->size() - 1) + - row); + if (row > endLine) + break; + + const QTextLayout &layout = line.layout(m_layoutVersion, m_font, m_lineSpacing); + const std::optional range + = selectionToFormatRange(*m_selection, layout, row); + if (range) + selectedText.append(line.layout(m_layoutVersion, m_font, m_lineSpacing) + .text() + .mid(range->start, range->length) + .trimmed()); + + if (endLine > row) + selectedText.append(QChar::LineFeed); + } + + if (row <= endLine) { + const std::optional range + = selectionToFormatRange(*m_selection, m_textLayout, m_scrollback->size()); + if (range) + selectedText.append(m_textLayout.text() + .mid(range->start, range->length) + .replace(QChar::LineSeparator, QChar::LineFeed) + .trimmed()); + } + + setClipboardAndSelection(selectedText); + } +} +void TerminalWidget::pasteFromClipboard() +{ + QClipboard *clipboard = QApplication::clipboard(); + const QString clipboardText = clipboard->text(QClipboard::Clipboard); + + if (clipboardText.isEmpty()) + return; + + vterm_keyboard_start_paste(m_vterm.get()); + for (unsigned int ch : clipboardText.toUcs4()) + vterm_keyboard_unichar(m_vterm.get(), ch, VTERM_MOD_NONE); + vterm_keyboard_end_paste(m_vterm.get()); + + if (!m_altscreen && m_scrollback->offset()) { + m_scrollback->unscroll(); + viewport()->update(); + } +} + +void TerminalWidget::clearSelection() +{ + m_selection.reset(); + update(); +} +void TerminalWidget::zoomIn() +{ + m_layoutVersion++; + m_font.setPointSize(m_font.pointSize() + 1); + setFont(m_font); +} +void TerminalWidget::zoomOut() +{ + m_layoutVersion++; + m_font.setPointSize(qMax(m_font.pointSize() - 1, 1)); + setFont(m_font); +} + +void TerminalWidget::clearContents() +{ + // Fake a scrollback clearing + QByteArray data{"\x1b[3J"}; + vterm_input_write(m_vterm.get(), data.constData(), data.size()); + vterm_screen_flush_damage(m_vtermScreen); + + // Send Ctrl+L which will clear the screen + writeToPty(QByteArray("\f")); +} + +void TerminalWidget::onReadyRead() +{ + QByteArray data = m_ptyProcess->readAll(); + vterm_input_write(m_vterm.get(), data.constData(), data.size()); + vterm_screen_flush_damage(m_vtermScreen); +} + +const VTermScreenCell *TerminalWidget::fetchCell(int x, int y) const +{ + QTC_ASSERT(y >= 0, return nullptr); + QTC_ASSERT(y < m_vtermSize.height(), return nullptr); + + static VTermScreenCell refCell{}; + VTermPos vtp{y, x}; + vterm_screen_get_cell(m_vtermScreen, vtp, &refCell); + vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.fg); + vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.bg); + return &refCell; +}; + +QPoint TerminalWidget::viewportToGlobal(QPoint p) const +{ + int y = p.y() - topMargin(); + const double offset = (m_scrollback->size() - m_scrollback->offset()) * m_lineSpacing; + y += offset; + + return {p.x(), y}; +} + +void TerminalWidget::createTextLayout() +{ + QElapsedTimer t; + t.start(); + + VTermColor defaultBg; + if (!m_altscreen) { + VTermColor defaultFg; + vterm_state_get_default_colors(vterm_obtain_state(m_vterm.get()), &defaultFg, &defaultBg); + // We want to compare the cell bg against this later and cells don't + // set DEFAULT_BG + defaultBg.type = VTERM_COLOR_RGB; + } else { + // This is a slightly better guess when in an altscreen + const VTermScreenCell *cell = fetchCell(0, 0); + defaultBg = cell->bg; + } + + m_textLayout.clearLayout(); + + QString allText; + + Internal::createTextLayout(m_textLayout, + allText, + defaultBg, + QRect({0, 0}, m_vtermSize), + m_lineSpacing, + [this](int x, int y) { return fetchCell(x, y); }); + + qCInfo(terminalLog) << "createTextLayout took:" << t.elapsed() << "ms"; +} + +qreal TerminalWidget::topMargin() const +{ + return size().height() - (m_vtermSize.height() * m_lineSpacing); +} + +std::optional TerminalWidget::selectionToFormatRange( + TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const +{ + int selectionStartLine = qFloor(selection.start.y() / m_lineSpacing) - rowOffset; + int selectionEndLine = qFloor(selection.end.y() / m_lineSpacing) - rowOffset; + + int nRows = layout.lineCount(); + + if (selectionStartLine < nRows && selectionEndLine >= 0) { + QTextLine lStart = layout.lineAt(qMax(0, qMin(selectionStartLine, nRows))); + QTextLine lEnd = layout.lineAt(qMin(nRows - 1, qMax(0, selectionEndLine))); + + int startPos = 0; + int endPos = lEnd.textLength(); + + if (selectionStartLine >= 0) + startPos = lStart.xToCursor(selection.start.x()); + if (selectionEndLine < (nRows)) + endPos = lEnd.xToCursor(selection.end.x()); + + QTextLayout::FormatRange range; + range.start = startPos; + range.length = endPos - startPos; + range.format.setBackground(QColor::fromRgbF(1.0, 1.0, 1.0, 0.5)); + return range; + } + + return {}; +} + +void TerminalWidget::paintEvent(QPaintEvent *event) +{ + event->accept(); + QPainter p(viewport()); + + p.setCompositionMode(QPainter::CompositionMode_Source); + + VTermColor defaultBg; + if (!m_altscreen) { + VTermColor defaultFg; + vterm_state_get_default_colors(vterm_obtain_state(m_vterm.get()), &defaultFg, &defaultBg); + // We want to compare the cell bg against this later and cells don't + // set DEFAULT_BG + defaultBg.type = VTERM_COLOR_RGB; + } else { + // This is a slightly better guess when in an altscreen + const VTermScreenCell *cell = fetchCell(0, 0); + defaultBg = cell->bg; + } + + p.fillRect(event->rect(), Internal::toQColor(defaultBg)); + + unsigned long off = m_scrollback->size() - m_scrollback->offset(); + + // transform painter according to scroll offsets + QPointF offset{0, -(off * m_lineSpacing)}; + + qreal margin = topMargin(); + qreal y = offset.y() + margin; + + size_t row = qFloor((offset.y() * -1) / m_lineSpacing); + y += row * m_lineSpacing; + for (; row < m_scrollback->size(); row++) { + if (y >= 0 && y < viewport()->height()) { + const Internal::Scrollback::Line &line = m_scrollback->line((m_scrollback->size() - 1) + - row); + + QList selections; + + if (m_selection) { + const std::optional range + = selectionToFormatRange(m_selection.value(), + line.layout(m_layoutVersion, m_font, m_lineSpacing), + row); + if (range) { + selections.append(range.value()); + } + } + line.layout(m_layoutVersion, m_font, m_lineSpacing).draw(&p, {0.0, y}, selections); + } + + y += m_lineSpacing; + } + + // Draw the live part + if (y < m_vtermSize.height() * m_lineSpacing) { + QList selections; + + if (m_selection) { + const std::optional range + = selectionToFormatRange(m_selection.value(), m_textLayout, row); + if (range) { + selections.append(range.value()); + } + } + + m_textLayout.draw(&p, {0.0, y}, selections); + + if (m_cursor.visible && m_preEditString.isEmpty()) { + p.setPen(QColor::fromRgb(0xFF, 0xFF, 0xFF)); + if (m_textLayout.lineCount() > m_cursor.row) { + QTextLine cursorLine = m_textLayout.lineAt(m_cursor.row); + if (cursorLine.isValid()) { + QFontMetricsF fm(m_font); + const QString text = m_textLayout.text(); + const QList asUcs4 = text.toUcs4(); + const int textStart = cursorLine.textStart(); + const int cPos = textStart + m_cursor.col; + if (cPos >= 0 && cPos < asUcs4.size()) { + const unsigned int ch = asUcs4.at(cPos); + const qreal br = fm.horizontalAdvance(QString::fromUcs4(&ch, 1)); + const qreal xCursor = cursorLine.cursorToX(cPos); + const double yCursor = cursorLine.y() + y; + const QRectF cursorRect = QRectF{xCursor, yCursor, br, m_lineSpacing}; + if (hasFocus()) { + QPainter::CompositionMode oldMode = p.compositionMode(); + p.setCompositionMode(QPainter::RasterOp_NotDestination); + p.fillRect(cursorRect, p.pen().brush()); + p.setCompositionMode(oldMode); + } else { + p.drawRect(cursorRect); + } + } + } + } + } + + if (!m_preEditString.isEmpty()) { + // TODO: Use QTextLayout::setPreeditArea() instead ? + QTextLine cursorLine = m_textLayout.lineAt(m_cursor.row); + if (cursorLine.isValid()) { + int pos = cursorLine.textStart() + m_cursor.col; + QPointF displayPos = QPointF{cursorLine.cursorToX(pos), cursorLine.y()}; + + p.fillRect(QRectF{displayPos.toPoint(), m_cellSize}, QColor::fromRgb(0, 0, 0)); + p.setPen(Qt::white); + displayPos.setY(displayPos.y() + m_cellBaseline); + p.drawText(displayPos, m_preEditString); + } + } + } + + p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), margin}}, Internal::toQColor(defaultBg)); +} + +void TerminalWidget::keyPressEvent(QKeyEvent *event) +{ + event->accept(); + + if (event->modifiers() == Qt::NoModifier && event->key() == Qt::Key_Escape && m_selection) { + clearSelectionAction().trigger(); + return; + } + + if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Plus) { + zoomInAction().trigger(); + return; + } + + if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Minus) { + zoomOutAction().trigger(); + return; + } + + if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_C) { + copyAction().trigger(); + return; + } + + if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_V) { + pasteAction().trigger(); + return; + } + + bool keypad = event->modifiers() & Qt::KeypadModifier; + VTermModifier mod = Internal::qtModifierToVTerm(event->modifiers()); + VTermKey key = Internal::qtKeyToVTerm(Qt::Key(event->key()), keypad); + + if (key != VTERM_KEY_NONE) { + if (mod == VTERM_MOD_SHIFT && (key == VTERM_KEY_ESCAPE || key == VTERM_KEY_BACKSPACE)) + mod = VTERM_MOD_NONE; + + vterm_keyboard_key(m_vterm.get(), key, mod); + } else if (event->text().length() == 1) { + // This maps to delete word and is way to easy to mistakenly type + // if (event->key() == Qt::Key_Space && mod == VTERM_MOD_SHIFT) + // mod = VTERM_MOD_NONE; + + // Per https://github.com/justinmk/neovim/commit/317d5ca7b0f92ef42de989b3556ca9503f0a3bf6 + // libvterm prefers we send the full keycode rather than sending the + // ctrl modifier. This helps with ncurses applications which otherwise + // do not recognize ctrl+ and in the shell for getting common control characters + // like ctrl+i for tab or ctrl+j for newline. + vterm_keyboard_unichar(m_vterm.get(), + event->text().toUcs4()[0], + static_cast(mod & ~VTERM_MOD_CTRL)); + } else if (mod != VTERM_MOD_NONE && event->key() == Qt::Key_C) { + vterm_keyboard_unichar(m_vterm.get(), 'c', mod); + } +} + +void TerminalWidget::applySizeChange() +{ + m_vtermSize = { + qFloor((qreal) size().width() / (qreal) m_cellSize.width()), + qFloor((qreal) size().height() / m_lineSpacing), + }; + + if (m_vtermSize.height() <= 0) + m_vtermSize.setHeight(1); + + if (m_vtermSize.width() <= 0) + m_vtermSize.setWidth(1); + + if (m_ptyProcess) + m_ptyProcess->resize(m_vtermSize.width(), m_vtermSize.height()); + + vterm_set_size(m_vterm.get(), m_vtermSize.height(), m_vtermSize.width()); + vterm_screen_flush_damage(m_vtermScreen); +} + +void TerminalWidget::updateScrollBars() +{ + verticalScrollBar()->setRange(0, static_cast(m_scrollback->size())); + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); +} + +void TerminalWidget::resizeEvent(QResizeEvent *event) +{ + event->accept(); + + // If increasing in size, we'll trigger libvterm to call sb_popline in + // order to pull lines out of the history. This will cause the scrollback + // to decrease in size which reduces the size of the verticalScrollBar. + // That will trigger a scroll offset increase which we want to ignore. + m_ignoreScroll = true; + + applySizeChange(); + + m_selection.reset(); + m_ignoreScroll = false; +} + +void TerminalWidget::invalidate(VTermRect rect) +{ + Q_UNUSED(rect); + createTextLayout(); + + viewport()->update(); +} + +int TerminalWidget::sb_pushline(int cols, const VTermScreenCell *cells) +{ + m_scrollback->emplace(cols, cells, vterm_obtain_state(m_vterm.get())); + + updateScrollBars(); + + return 1; +} + +int TerminalWidget::sb_popline(int cols, VTermScreenCell *cells) +{ + if (m_scrollback->size() == 0) + return 0; + + m_scrollback->popto(cols, cells); + + updateScrollBars(); + + return 1; +} + +int TerminalWidget::sb_clear() +{ + m_scrollback->clear(); + updateScrollBars(); + + return 1; +} + +void TerminalWidget::wheelEvent(QWheelEvent *event) +{ + event->accept(); + + QPoint delta = event->angleDelta(); + scrollContentsBy(0, delta.y() / 24); +} + +void TerminalWidget::focusInEvent(QFocusEvent *) +{ + viewport()->update(); +} +void TerminalWidget::focusOutEvent(QFocusEvent *) +{ + viewport()->update(); +} + +void TerminalWidget::inputMethodEvent(QInputMethodEvent *event) +{ + m_preEditString = event->preeditString(); + + if (event->commitString().isEmpty()) { + viewport()->update(); + return; + } + + for (const unsigned int ch : event->commitString().toUcs4()) { + vterm_keyboard_unichar(m_vterm.get(), ch, VTERM_MOD_NONE); + } +} + +void TerminalWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + m_selectionStartPos = event->pos(); + + QPoint pos = viewportToGlobal(event->pos()); + m_selection = Selection{pos, pos}; + viewport()->update(); + } +} +void TerminalWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (m_selection && event->buttons() & Qt::LeftButton) { + QPoint start = viewportToGlobal(m_selectionStartPos); + QPoint newEnd = viewportToGlobal(event->pos()); + + if (start.y() > newEnd.y() || (start.y() == newEnd.y() && start.x() > newEnd.x())) + std::swap(start, newEnd); + + m_selection->start = start; + m_selection->end = newEnd; + + viewport()->update(); + } +} + +void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) +{ + if (m_selection && event->button() != Qt::LeftButton) { + if ((m_selectionStartPos - event->pos()).manhattanLength() < 2) { + m_selection.reset(); + viewport()->update(); + } + } +} + +void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + // TODO :( + Q_UNUSED(event); + viewport()->update(); +} + +void TerminalWidget::scrollContentsBy(int dx, int dy) +{ + Q_UNUSED(dx); + + if (m_ignoreScroll) + return; + + if (m_altscreen) + return; + + size_t orig = m_scrollback->offset(); + size_t offset = m_scrollback->scroll(dy); + if (orig == offset) + return; + + m_cursor.visible = (offset == 0); + viewport()->update(); +} + +void TerminalWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event); + + if (!m_ptyProcess) + setupPty(); + + QAbstractScrollArea::showEvent(event); +} + +bool TerminalWidget::event(QEvent *event) +{ + if (event->type() == QEvent::ShortcutOverride) { + if (hasFocus()) { + event->accept(); + return true; + } + } + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *k = (QKeyEvent *) event; + keyPressEvent(k); + return true; + } + if (event->type() == QEvent::KeyRelease) { + QKeyEvent *k = (QKeyEvent *) event; + keyReleaseEvent(k); + return true; + } + + return QAbstractScrollArea::event(event); +} + +int TerminalWidget::setTerminalProperties(VTermProp prop, VTermValue *val) +{ + switch (prop) { + case VTERM_PROP_CURSORVISIBLE: + m_cursor.visible = val->boolean; + break; + case VTERM_PROP_CURSORBLINK: + qCDebug(terminalLog) << "Ignoring VTERM_PROP_CURSORBLINK" << val->boolean; + break; + case VTERM_PROP_CURSORSHAPE: + qCDebug(terminalLog) << "Ignoring VTERM_PROP_CURSORSHAPE" << val->number; + break; + case VTERM_PROP_ICONNAME: + //emit iconTextChanged(val->string); + break; + case VTERM_PROP_TITLE: + //emit titleChanged(val->string); + setWindowTitle(QString::fromUtf8(val->string.str, val->string.len)); + break; + case VTERM_PROP_ALTSCREEN: + m_altscreen = val->boolean; + m_selection.reset(); + break; + case VTERM_PROP_MOUSE: + qCDebug(terminalLog) << "Ignoring VTERM_PROP_MOUSE" << val->number; + break; + case VTERM_PROP_REVERSE: + qCDebug(terminalLog) << "Ignoring VTERM_PROP_REVERSE" << val->boolean; + break; + case VTERM_N_PROPS: + break; + } + return 1; +} + +int TerminalWidget::movecursor(VTermPos pos, VTermPos oldpos, int visible) +{ + Q_UNUSED(oldpos); + viewport()->update(); + m_cursor.row = pos.row; + m_cursor.col = pos.col; + m_cursor.visible = visible; + + return 1; +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h new file mode 100644 index 00000000000..3f1590dfaaf --- /dev/null +++ b/src/plugins/terminal/terminalwidget.h @@ -0,0 +1,164 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "scrollback.h" + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +namespace Terminal { + +class TerminalWidget : public QAbstractScrollArea +{ + Q_OBJECT +public: + TerminalWidget(QWidget *parent = nullptr, + const Utils::Terminal::OpenTerminalParameters &openParameters = {}); + + void setFont(const QFont &font); + + QAction ©Action(); + QAction &pasteAction(); + + QAction &clearSelectionAction(); + + QAction &zoomInAction(); + QAction &zoomOutAction(); + + void copyToClipboard() const; + void pasteFromClipboard(); + + void clearSelection(); + + void zoomIn(); + void zoomOut(); + + void clearContents(); + + struct Selection + { + QPoint start; + QPoint end; + }; + +signals: + void started(qint64 pid); + +protected: + void paintEvent(QPaintEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + void inputMethodEvent(QInputMethodEvent *event) override; + + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + + void scrollContentsBy(int dx, int dy) override; + + void showEvent(QShowEvent *event) override; + + bool event(QEvent *event) override; + +protected: + void onReadyRead(); + void setupVTerm(); + void setupFont(); + void setupPty(); + void setupColors(); + + void writeToPty(const QByteArray &data); + + void createTextLayout(); + + // Callbacks from vterm + void invalidate(VTermRect rect); + int sb_pushline(int cols, const VTermScreenCell *cells); + int sb_popline(int cols, VTermScreenCell *cells); + int sb_clear(); + int setTerminalProperties(VTermProp prop, VTermValue *val); + int movecursor(VTermPos pos, VTermPos oldpos, int visible); + + const VTermScreenCell *fetchCell(int x, int y) const; + + qreal topMargin() const; + + QPoint viewportToGlobal(QPoint p) const; + + int textLineFromPixel(int y) const; + std::optional textPosFromPoint(const QTextLayout &textLayout, QPoint p) const; + + std::optional selectionToFormatRange( + TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const; + + void applySizeChange(); + + void updateScrollBars(); + +private: + std::unique_ptr m_ptyProcess; + + std::unique_ptr m_vterm; + VTermScreen *m_vtermScreen; + QSize m_vtermSize; + + QFont m_font; + QSizeF m_cellSize; + qreal m_cellBaseline; + qreal m_lineSpacing; + + bool m_altscreen{false}; + bool m_ignoreScroll{false}; + + QString m_preEditString; + + std::optional m_selection; + QPoint m_selectionStartPos; + + std::unique_ptr m_scrollback; + + QTextLayout m_textLayout; + + struct + { + int row{0}; + int col{0}; + bool visible{false}; + } m_cursor; + + VTermScreenCallbacks m_vtermScreenCallbacks; + + QAction m_copyAction; + QAction m_pasteAction; + + QAction m_clearSelectionAction; + + QAction m_zoomInAction; + QAction m_zoomOutAction; + + QTimer m_readDelayTimer; + int m_readDelayRestarts{0}; + + int m_layoutVersion{0}; + + std::array m_currentColors; + + Utils::Terminal::OpenTerminalParameters m_openParameters; +}; + +} // namespace Terminal From beabb534228c3d39c245c60486342f95847262d7 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 23 Feb 2023 16:21:29 +0100 Subject: [PATCH 0081/1447] sdktool: Fix CMake configuration on Qt6 within Qt Creator Change-Id: I9028ad7aa6018b63c5afedb65add6ce765660bb7 Reviewed-by: Marcus Tillmanns Reviewed-by: Cristian Adam --- src/tools/sdktool/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/sdktool/CMakeLists.txt b/src/tools/sdktool/CMakeLists.txt index 4adf618b845..39c7a1b5446 100644 --- a/src/tools/sdktool/CMakeLists.txt +++ b/src/tools/sdktool/CMakeLists.txt @@ -120,7 +120,7 @@ add_qtc_executable(sdktool main.cpp ) -if (MSVC AND TARGET sdktool AND Qt5_VERSION VERSION_LESS 6.0.0) +if (MSVC AND TARGET sdktool AND TARGET Qt5::Core) # find out if Qt is static and set /MT if so get_target_property(_input_type Qt5::Core TYPE) if (${_input_type} STREQUAL "STATIC_LIBRARY") From 58abb397e702b74bf63a90063548685bfcfae1df Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Feb 2023 02:12:54 +0100 Subject: [PATCH 0082/1447] AttachCoreDialog: Use QPromise for async calls Change-Id: Ib0dd9ceb21711a786dc84acc815d1a5afb557de7 Reviewed-by: hjk Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/debugger/loadcoredialog.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index 86c9c738dc3..85a81a9418d 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -243,18 +243,18 @@ void AttachCoreDialog::accepted() using ResultType = expected_str; - const auto copyFileAsync = [=](QFutureInterface &fi, const FilePath &srcPath) { - fi.reportResult(copyFile(srcPath)); + const auto copyFileAsync = [=](QPromise &promise, const FilePath &srcPath) { + promise.addResult(copyFile(srcPath)); }; const Group root = { parallel, Async{[=](auto &task) { - task.setAsyncCallData(copyFileAsync, this->coreFile()); + task.setConcurrentCallData(copyFileAsync, this->coreFile()); }, [=](const auto &task) { d->coreFileResult = task.result(); }}, Async{[=](auto &task) { - task.setAsyncCallData(copyFileAsync, this->symbolFile()); + task.setConcurrentCallData(copyFileAsync, this->symbolFile()); }, [=](const auto &task) { d->symbolFileResult = task.result(); }}, }; From c6dc54b34366c98273bf1992e0f54da5e085ca05 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Feb 2023 15:21:26 +0100 Subject: [PATCH 0083/1447] Terminal: Add Shell option menu Change-Id: I08ea3c52ed28ab65f2dc902051bab9e6975e6a7e Reviewed-by: Cristian Adam --- src/plugins/coreplugin/manhattanstyle.cpp | 6 ++ src/plugins/terminal/terminalpane.cpp | 93 +++++++++++++++++++++-- src/plugins/terminal/terminalwidget.cpp | 5 +- 3 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 3ec83405535..7cf4746f951 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -189,6 +189,12 @@ int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, int retval = 0; retval = QProxyStyle::pixelMetric(metric, option, widget); switch (metric) { +#ifdef Q_OS_MACOS + case PM_MenuButtonIndicator: + if (widget && option->type == QStyleOption::SO_ToolButton) + return 12; + break; +#endif case PM_SplitterWidth: if (widget && widget->property("minisplitter").toBool()) retval = 1; diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 5e57317c0fc..a355ca02725 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -9,10 +9,71 @@ #include #include +#include +#include #include +#include +#include +#include + namespace Terminal { +using namespace Utils; + +FilePaths availableShells() +{ + if (Utils::HostOsInfo::isWindowsHost()) { + FilePaths shells; + + FilePath comspec = FilePath::fromUserInput(qtcEnvironmentVariable("COMSPEC")); + shells << comspec; + + if (comspec.fileName() != "cmd.exe") { + FilePath cmd = FilePath::fromUserInput(QStandardPaths::findExecutable("cmd.exe")); + shells << cmd; + } + + FilePath powershell = FilePath::fromUserInput( + QStandardPaths::findExecutable("powershell.exe")); + if (powershell.exists()) + shells << powershell; + + FilePath bash = FilePath::fromUserInput(QStandardPaths::findExecutable("bash.exe")); + if (bash.exists()) + shells << bash; + + FilePath git_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("git.exe")); + if (git_bash.exists()) + shells << git_bash.parentDir().parentDir().pathAppended("usr/bin/bash.exe"); + + FilePath msys2_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("msys2.exe")); + if (msys2_bash.exists()) + shells << msys2_bash.parentDir().pathAppended("usr/bin/bash.exe"); + + return shells; + } else { + FilePath shellsFile = FilePath::fromString("/etc/shells"); + const auto shellFileContent = shellsFile.fileContents(); + QTC_ASSERT_EXPECTED(shellFileContent, return {}); + + QString shellFileContentString = QString::fromUtf8(*shellFileContent); + + // Filter out comments ... + const QStringList lines + = Utils::filtered(shellFileContentString.split('\n', Qt::SkipEmptyParts), + [](const QString &line) { return !line.trimmed().startsWith('#'); }); + + // Convert lines to file paths ... + const FilePaths shells = Utils::transform(lines, [](const QString &line) { + return FilePath::fromUserInput(line.trimmed()); + }); + + // ... and filter out non-existing shells. + return Utils::filtered(shells, [](const FilePath &shell) { return shell.exists(); }); + } +} + TerminalPane::TerminalPane(QObject *parent) : Core::IOutputPane(parent) { @@ -21,13 +82,7 @@ TerminalPane::TerminalPane(QObject *parent) m_newTerminal.setIcon(Utils::Icons::PLUS_TOOLBAR.icon()); m_newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); - connect(&m_newTerminal, &QAction::triggered, this, [this] { - m_tabWidget->setCurrentIndex( - m_tabWidget->addTab(new TerminalWidget(m_tabWidget), Tr::tr("Terminal"))); - - m_closeTerminal.setEnabled(m_tabWidget->count() > 1); - emit navigateStateUpdate(); - }); + connect(&m_newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); m_closeTerminal.setIcon(Utils::Icons::CLOSE_TOOLBAR.icon()); m_closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); @@ -41,6 +96,30 @@ TerminalPane::TerminalPane(QObject *parent) //cmd->setDescription(m_newTerminal->toolTip()); m_newTerminalButton = new QToolButton(); + + QMenu *shellMenu = new QMenu(m_newTerminalButton); + + const FilePaths shells = availableShells(); + + QFileIconProvider iconProvider; + + // Create an action for each available shell ... + for (const FilePath &shell : shells) { + const QIcon icon = iconProvider.icon(shell.toFileInfo()); + + QAction *action = new QAction(icon, shell.toUserOutput(), shellMenu); + action->setData(shell.toVariant()); + shellMenu->addAction(action); + } + connect(shellMenu, &QMenu::triggered, this, [this](QAction *action) { + openTerminal( + Utils::Terminal::OpenTerminalParameters{CommandLine{FilePath::fromVariant(action->data()), {}}, + std::nullopt, + std::nullopt, + Utils::Terminal::ExitBehavior::Close}); + }); + m_newTerminal.setMenu(shellMenu); + m_newTerminalButton->setDefaultAction(&m_newTerminal); m_closeTerminalButton = new QToolButton(); diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index a6169846291..a4bf0ae37a9 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -92,12 +92,13 @@ void TerminalWidget::setupPty() m_ptyProcess.reset(PtyQt::createPtyProcess(IPtyProcess::PtyType::AutoPty)); Environment env = m_openParameters.environment.value_or(Environment::systemEnvironment()); - // Why? - env.appendOrSetPath(TerminalSettings::instance().shell.filePath().parentDir()); CommandLine shellCommand = m_openParameters.shellCommand.value_or( CommandLine{TerminalSettings::instance().shell.filePath(), {}}); + // For git bash on Windows + env.prependOrSetPath(shellCommand.executable().parentDir()); + QStringList envList = filtered(env.toStringList(), [](const QString &envPair) { return envPair != "CLINK_NOAUTORUN=1"; }); From a62c5cf89a1bf2bd16af4462bfb56635e8e34867 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 9 Feb 2023 14:41:59 +0100 Subject: [PATCH 0084/1447] Utils: Cleanup searchInX functions Also move some often used types into new file "utiltypes.h" Change-Id: I3f152d1dc2f96ba0259ad6c098d9ac5ee03a59f1 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/environment.cpp | 169 ++++++++++-------- src/libs/utils/environment.h | 8 +- src/libs/utils/filepath.cpp | 4 +- src/libs/utils/filepath.h | 7 +- src/libs/utils/filesearch.cpp | 4 +- src/libs/utils/utiltypes.h | 14 ++ .../buildsettingspropertiespage.cpp | 2 +- tests/auto/utils/filepath/tst_filepath.cpp | 42 ++++- 8 files changed, 156 insertions(+), 94 deletions(-) create mode 100644 src/libs/utils/utiltypes.h diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index c99293329c1..96e7ea17758 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -4,6 +4,7 @@ #include "environment.h" #include "algorithm.h" +#include "filepath.h" #include "qtcassert.h" #include @@ -130,36 +131,44 @@ void Environment::setupEnglishOutput() m_dict.set("LANGUAGE", "en_US:en"); } -static FilePath searchInDirectory(const QStringList &execs, - const FilePath &directory, - QSet &alreadyChecked) +using SearchResultCallback = std::function; + +static IterationPolicy searchInDirectory(const SearchResultCallback &resultCallback, + const FilePaths &execs, + const FilePath &directory, + QSet &alreadyCheckedDirectories, + const FilePathPredicate &filter = {}) { - const int checkedCount = alreadyChecked.count(); - alreadyChecked.insert(directory); + // Compare the initial size of the set with the size after insertion to check if the directory + // was already checked. + const int initialCount = alreadyCheckedDirectories.count(); + alreadyCheckedDirectories.insert(directory); + const bool wasAlreadyChecked = alreadyCheckedDirectories.count() == initialCount; - if (directory.isEmpty() || alreadyChecked.count() == checkedCount) - return FilePath(); + if (directory.isEmpty() || wasAlreadyChecked) + return IterationPolicy::Continue; - for (const QString &exec : execs) { - const FilePath filePath = directory.pathAppended(exec); - if (filePath.isExecutableFile()) - return filePath; + for (const FilePath &exec : execs) { + const FilePath filePath = directory / exec.path(); + if (filePath.isExecutableFile() && (!filter || filter(filePath))) { + if (resultCallback(filePath) == IterationPolicy::Stop) + return IterationPolicy::Stop; + } } - return FilePath(); + return IterationPolicy::Continue; } -static QStringList appendExeExtensions(const Environment &env, const QString &executable) +static FilePaths appendExeExtensions(const Environment &env, const FilePath &executable) { - QStringList execs(executable); + FilePaths execs{executable}; if (env.osType() == OsTypeWindows) { - const QFileInfo fi(executable); // Check all the executable extensions on windows: // PATHEXT is only used if the executable has no extension - if (fi.suffix().isEmpty()) { + if (executable.suffix().isEmpty()) { const QStringList extensions = env.expandedValueForKey("PATHEXT").split(';'); for (const QString &ext : extensions) - execs << executable + ext.toLower(); + execs << executable.stringAppended(ext.toLower()); } } return execs; @@ -170,99 +179,101 @@ QString Environment::expandedValueForKey(const QString &key) const return expandVariables(m_dict.value(key)); } -static FilePath searchInDirectoriesHelper(const Environment &env, - const QString &executable, - const FilePaths &dirs, - const Environment::PathFilter &func, - bool usePath) +static void searchInDirectoriesHelper(const SearchResultCallback &resultCallback, + const Environment &env, + const QString &executable, + const FilePaths &dirs, + const FilePathPredicate &func, + bool usePath) { if (executable.isEmpty()) - return FilePath(); + return; - const QString exec = QDir::cleanPath(env.expandVariables(executable)); - const QFileInfo fi(exec); + const FilePath exec = FilePath::fromUserInput(QDir::cleanPath(env.expandVariables(executable))); + const FilePaths execs = appendExeExtensions(env, exec); - const QStringList execs = appendExeExtensions(env, exec); - - if (fi.isAbsolute()) { - for (const QString &path : execs) { - QFileInfo pfi = QFileInfo(path); - if (pfi.isFile() && pfi.isExecutable()) - return FilePath::fromString(path); + if (exec.isAbsolutePath()) { + for (const FilePath &path : execs) { + if (path.isExecutableFile() && (!func || func(path))) + if (resultCallback(path) == IterationPolicy::Stop) + return; } - return FilePath::fromString(exec); + return; } - QSet alreadyChecked; + QSet alreadyCheckedDirectories; for (const FilePath &dir : dirs) { - FilePath tmp = searchInDirectory(execs, dir, alreadyChecked); - if (!tmp.isEmpty() && (!func || func(tmp))) - return tmp; + if (searchInDirectory(resultCallback, execs, dir, alreadyCheckedDirectories, func) + == IterationPolicy::Stop) + return; } if (usePath) { - if (executable.contains('/')) - return FilePath(); + QTC_ASSERT(!executable.contains('/'), return); for (const FilePath &p : env.path()) { - FilePath tmp = searchInDirectory(execs, p, alreadyChecked); - if (!tmp.isEmpty() && (!func || func(tmp))) - return tmp; + if (searchInDirectory(resultCallback, execs, p, alreadyCheckedDirectories, func) + == IterationPolicy::Stop) + return; } } - return FilePath(); + return; } FilePath Environment::searchInDirectories(const QString &executable, const FilePaths &dirs, - const PathFilter &func) const + const FilePathPredicate &func) const { - return searchInDirectoriesHelper(*this, executable, dirs, func, false); + FilePath result; + searchInDirectoriesHelper( + [&result](const FilePath &path) { + result = path; + return IterationPolicy::Stop; + }, + *this, + executable, + dirs, + func, + false); + + return result; } FilePath Environment::searchInPath(const QString &executable, const FilePaths &additionalDirs, - const PathFilter &func) const + const FilePathPredicate &func) const { - return searchInDirectoriesHelper(*this, executable, additionalDirs, func, true); + FilePath result; + searchInDirectoriesHelper( + [&result](const FilePath &path) { + result = path; + return IterationPolicy::Stop; + }, + *this, + executable, + additionalDirs, + func, + true); + + return result; } FilePaths Environment::findAllInPath(const QString &executable, - const FilePaths &additionalDirs, - const Environment::PathFilter &func) const + const FilePaths &additionalDirs, + const FilePathPredicate &func) const { - if (executable.isEmpty()) - return {}; - - const QString exec = QDir::cleanPath(expandVariables(executable)); - const QFileInfo fi(exec); - - const QStringList execs = appendExeExtensions(*this, exec); - - if (fi.isAbsolute()) { - for (const QString &path : execs) { - QFileInfo pfi = QFileInfo(path); - if (pfi.isFile() && pfi.isExecutable()) - return {FilePath::fromString(path)}; - } - return {FilePath::fromString(exec)}; - } - QSet result; - QSet alreadyChecked; - for (const FilePath &dir : additionalDirs) { - FilePath tmp = searchInDirectory(execs, dir, alreadyChecked); - if (!tmp.isEmpty() && (!func || func(tmp))) - result << tmp; - } + searchInDirectoriesHelper( + [&result](const FilePath &path) { + result.insert(path); + return IterationPolicy::Continue; + }, + *this, + executable, + additionalDirs, + func, + true); - if (!executable.contains('/')) { - for (const FilePath &p : path()) { - FilePath tmp = searchInDirectory(execs, p, alreadyChecked); - if (!tmp.isEmpty() && (!func || func(tmp))) - result << tmp; - } - } return result.values(); } diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 2671e972cf3..e6bf46b32dd 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -8,6 +8,7 @@ #include "environmentfwd.h" #include "filepath.h" #include "namevaluedictionary.h" +#include "utiltypes.h" #include #include @@ -56,16 +57,15 @@ public: void setupEnglishOutput(); - using PathFilter = std::function; FilePath searchInPath(const QString &executable, const FilePaths &additionalDirs = FilePaths(), - const PathFilter &func = PathFilter()) const; + const FilePathPredicate &func = {}) const; FilePath searchInDirectories(const QString &executable, const FilePaths &dirs, - const PathFilter &func = {}) const; + const FilePathPredicate &func = {}) const; FilePaths findAllInPath(const QString &executable, const FilePaths &additionalDirs = {}, - const PathFilter &func = {}) const; + const FilePathPredicate &func = {}) const; FilePaths path() const; FilePaths pathListValue(const QString &varName) const; diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 7e61ac0d376..7d2b07f8c22 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1451,7 +1451,7 @@ FilePath FilePath::withNewPath(const QString &newPath) const assert(fullPath == FilePath::fromUrl("docker://123/usr/bin/make")) \endcode */ -FilePath FilePath::searchInDirectories(const FilePaths &dirs, const PathFilter &filter) const +FilePath FilePath::searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter) const { if (isAbsolutePath()) return *this; @@ -1460,7 +1460,7 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs, const PathFilter & FilePath FilePath::searchInPath(const FilePaths &additionalDirs, PathAmending amending, - const PathFilter &filter) const + const FilePathPredicate &filter) const { if (isAbsolutePath()) return *this; diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 8aa59eb5d98..77a3b84382b 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -8,6 +8,7 @@ #include "expected.h" #include "filepathinfo.h" #include "osspecificaspects.h" +#include "utiltypes.h" #include #include @@ -51,8 +52,6 @@ public: using FilePaths = QList; -enum class IterationPolicy { Stop, Continue }; - class QTCREATOR_UTILS_EXPORT FilePath { public: @@ -159,7 +158,7 @@ public: [[nodiscard]] FilePath relativeChildPath(const FilePath &parent) const; [[nodiscard]] FilePath relativePathFrom(const FilePath &anchor) const; [[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs, - const PathFilter &filter = {}) const; + const FilePathPredicate &filter = {}) const; [[nodiscard]] Environment deviceEnvironment() const; [[nodiscard]] FilePath onDevice(const FilePath &deviceTemplate) const; [[nodiscard]] FilePath withNewPath(const QString &newPath) const; @@ -182,7 +181,7 @@ public: enum PathAmending { AppendToPath, PrependToPath }; [[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {}, PathAmending = AppendToPath, - const PathFilter &filter = {}) const; + const FilePathPredicate &filter = {}) const; enum MatchScope { ExactMatchOnly, WithExeSuffix, WithBatSuffix, WithExeOrBatSuffix, WithAnySuffix }; diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index ccbcfbfb9f9..d0fa1c71c3a 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -9,6 +9,7 @@ #include "qtcassert.h" #include "stringutils.h" #include "utilstr.h" +#include "utiltypes.h" #include #include @@ -496,8 +497,7 @@ static bool isFileIncluded(const QList &filterRegs, return isIncluded && (exclusionRegs.isEmpty() || !matches(exclusionRegs, filePath)); } -std::function filterFileFunction(const QStringList &filters, - const QStringList &exclusionFilters) +FilePathPredicate filterFileFunction(const QStringList &filters, const QStringList &exclusionFilters) { const QList filterRegs = filtersToRegExps(filters); const QList exclusionRegs = filtersToRegExps(exclusionFilters); diff --git a/src/libs/utils/utiltypes.h b/src/libs/utils/utiltypes.h new file mode 100644 index 00000000000..967eecb5a5f --- /dev/null +++ b/src/libs/utils/utiltypes.h @@ -0,0 +1,14 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Utils { +class FilePath; + +enum class IterationPolicy { Stop, Continue }; + +using FilePathPredicate = std::function; +} // namespace Utils diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index 67cb4806709..9bf59d6bba8 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -283,7 +283,7 @@ void BuildSettingsWidget::cloneConfiguration() bc->setDisplayName(name); const FilePath buildDirectory = bc->buildDirectory(); if (buildDirectory != m_target->project()->projectDirectory()) { - const std::function isBuildDirOk = [this](const FilePath &candidate) { + const FilePathPredicate isBuildDirOk = [this](const FilePath &candidate) { if (candidate.exists()) return false; return !anyOf(m_target->buildConfigurations(), [&candidate](const BuildConfiguration *bc) { diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index 7303e7d9197..fed266d80b7 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -107,15 +107,21 @@ private slots: void tmp(); void tmp_data(); + void searchInWithFilter(); + private: QTemporaryDir tempDir; QString rootPath; + QString exeExt; }; -static void touch(const QDir &dir, const QString &filename, bool fill) +static void touch(const QDir &dir, const QString &filename, bool fill, bool executable = false) { QFile file(dir.absoluteFilePath(filename)); file.open(QIODevice::WriteOnly); + if (executable) + file.setPermissions(file.permissions() | QFileDevice::ExeUser); + if (fill) { QRandomGenerator *random = QRandomGenerator::global(); for (int i = 0; i < 10; ++i) @@ -126,7 +132,7 @@ static void touch(const QDir &dir, const QString &filename, bool fill) void tst_filepath::initTestCase() { - // initialize test for tst_fileutiles::relativePath*() + // initialize test for tst_filepath::relativePath*() QVERIFY(tempDir.isValid()); rootPath = tempDir.path(); QDir dir(rootPath); @@ -141,6 +147,38 @@ void tst_filepath::initTestCase() // initialize test for tst_filepath::asyncLocalCopy() touch(dir, "x/y/fileToCopy.txt", true); + +// initialize test for tst_filepath::searchIn() +#ifdef Q_OS_WIN + exeExt = ".exe"; +#endif + + dir.mkpath("s/1"); + dir.mkpath("s/2"); + touch(dir, "s/1/testexe" + exeExt, false, true); + touch(dir, "s/2/testexe" + exeExt, false, true); +} + +void tst_filepath::searchInWithFilter() +{ + const FilePaths dirs = {FilePath::fromUserInput(rootPath) / "s" / "1", + FilePath::fromUserInput(rootPath) / "s" / "2"}; + + FilePath exe = FilePath::fromUserInput("testexe" + exeExt) + .searchInDirectories(dirs, [](const FilePath &path) { + return path.path().contains("/2/"); + }); + + QVERIFY(!exe.path().endsWith("/1/testexe" + exeExt) + && exe.path().endsWith("/2/testexe" + exeExt)); + + FilePath exe2 = FilePath::fromUserInput("testexe" + exeExt) + .searchInDirectories(dirs, [](const FilePath &path) { + return path.path().contains("/1/"); + }); + + QVERIFY(!exe2.path().endsWith("/2/testexe" + exeExt) + && exe2.path().endsWith("/1/testexe" + exeExt)); } void tst_filepath::isEmpty_data() From c41d30711a03ada34091c40499a41ffdb0da3d84 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Feb 2023 15:34:05 +0100 Subject: [PATCH 0085/1447] Utils: Make UnixDeviceFileAccess macOS compatible "stat" on macOS has slightly different formatting options. Also adds unittests for UnixDeviceFileAccess Task-number: QTCREATORBUG-28142 Change-Id: Ib42fc1c22ef2771365e915df34f2286e2c705568 Reviewed-by: hjk Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/utils/devicefileaccess.cpp | 94 +++++++++++++------ src/libs/utils/devicefileaccess.h | 10 ++ src/libs/utils/fileutils.cpp | 9 +- src/libs/utils/fileutils.h | 2 +- tests/auto/utils/CMakeLists.txt | 1 + tests/auto/utils/fileutils/tst_fileutils.cpp | 2 +- .../utils/unixdevicefileaccess/CMakeLists.txt | 4 + .../tst_unixdevicefileaccess.cpp | 84 +++++++++++++++++ .../unixdevicefileaccess.qbs | 11 +++ tests/auto/utils/utils.qbs | 1 + 10 files changed, 184 insertions(+), 34 deletions(-) create mode 100644 tests/auto/utils/unixdevicefileaccess/CMakeLists.txt create mode 100644 tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp create mode 100644 tests/auto/utils/unixdevicefileaccess/unixdevicefileaccess.qbs diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 3d8354d7a0f..c50f3b145cb 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -8,6 +8,7 @@ #include "environment.h" #include "expected.h" #include "hostosinfo.h" +#include "osspecificaspects.h" #include "qtcassert.h" #include "utilstr.h" @@ -820,7 +821,7 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const OsType DesktopDeviceFileAccess::osType(const FilePath &filePath) const { - Q_UNUSED(filePath); + Q_UNUSED(filePath) return HostOsInfo::hostOs(); } @@ -1054,10 +1055,28 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file return newPath; } +OsType UnixDeviceFileAccess::osType() const +{ + if (m_osType) + return *m_osType; + + const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); + QTC_ASSERT(result.exitCode == 0, return OsTypeLinux); + const QString osName = QString::fromUtf8(result.stdOut).trimmed(); + if (osName == "Darwin") + m_osType = OsTypeMac; + else if (osName == "Linux") + m_osType = OsTypeLinux; + else + m_osType = OsTypeOtherUnix; + + return *m_osType; +} + OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const { - Q_UNUSED(filePath) - return OsTypeLinux; + Q_UNUSED(filePath); + return osType(); } QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const @@ -1069,10 +1088,19 @@ QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const return dt; } +QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, + const QString &linuxFormat, + const QString &macFormat) const +{ + return (osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) + << "-L" << filePath.path(); +} + QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const { - const RunResult result = runInShell( - {"stat", {"-L", "-c", "%a", filePath.path()}, OsType::OsTypeLinux}); + QStringList args = statArgs(filePath, "%a", "%p"); + + const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); const uint bits = result.stdOut.toUInt(nullptr, 8); QFileDevice::Permissions perm = {}; #define BIT(n, p) \ @@ -1100,8 +1128,8 @@ bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permi qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const { - const RunResult result = runInShell( - {"stat", {"-L", "-c", "%s", filePath.path()}, OsType::OsTypeLinux}); + const QStringList args = statArgs(filePath, "%s", "%z"); + const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong(); } @@ -1113,8 +1141,9 @@ qint64 UnixDeviceFileAccess::bytesAvailable(const FilePath &filePath) const QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const { - const RunResult result = runInShell( - {"stat", {"-L", "-c", "%D:%i", filePath.path()}, OsType::OsTypeLinux}); + const QStringList args = statArgs(filePath, "%D:%i", "%d:%i"); + + const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); if (result.exitCode != 0) return {}; @@ -1136,9 +1165,12 @@ FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const return r; } - const RunResult stat = runInShell( - {"stat", {"-L", "-c", "%f %Y %s", filePath.path()}, OsType::OsTypeLinux}); - return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut)); + + const QStringList args = statArgs(filePath, "%f %Y %s", "%p %m %z"); + + const RunResult stat = runInShell({"stat", args, OsType::OsTypeLinux}); + return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut), + osType() != OsTypeMac); } // returns whether 'find' could be used. @@ -1152,8 +1184,13 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, // TODO: Using stat -L will always return the link target, not the link itself. // We may wan't to add the information that it is a link at some point. + + const QString statFormat = osType() == OsTypeMac + ? QLatin1String("-f \"%p %m %z\"") : QLatin1String("-c \"%f %Y %s\""); + if (callBack.index() == 1) - cmdLine.addArgs(R"(-exec echo -n \"{}\"" " \; -exec stat -L -c "%f %Y %s" "{}" \;)", + cmdLine.addArgs(QString(R"(-exec echo -n \"{}\"" " \; -exec stat -L %1 "{}" \;)") + .arg(statFormat), CommandLine::Raw); const RunResult result = runInShell(cmdLine); @@ -1175,23 +1212,26 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, if (entries.isEmpty()) return true; - const auto toFilePath = [&filePath, &callBack](const QString &entry) { - if (callBack.index() == 0) - return std::get<0>(callBack)(filePath.withNewPath(entry)); + const int modeBase = osType() == OsTypeMac ? 8 : 16; - const QString fileName = entry.mid(1, entry.lastIndexOf('\"') - 1); - const QString infos = entry.mid(fileName.length() + 3); + const auto toFilePath = + [&filePath, &callBack, modeBase](const QString &entry) { + if (callBack.index() == 0) + return std::get<0>(callBack)(filePath.withNewPath(entry)); - const FilePathInfo fi = FileUtils::filePathInfoFromTriple(infos); - if (!fi.fileFlags) - return IterationPolicy::Continue; + const QString fileName = entry.mid(1, entry.lastIndexOf('\"') - 1); + const QString infos = entry.mid(fileName.length() + 3); - const FilePath fp = filePath.withNewPath(fileName); - // Do not return the entry for the directory we are searching in. - if (fp.path() == filePath.path()) - return IterationPolicy::Continue; - return std::get<1>(callBack)(fp, fi); - }; + const FilePathInfo fi = FileUtils::filePathInfoFromTriple(infos, modeBase); + if (!fi.fileFlags) + return IterationPolicy::Continue; + + const FilePath fp = filePath.withNewPath(fileName); + // Do not return the entry for the directory we are searching in. + if (fp.path() == filePath.path()) + return IterationPolicy::Continue; + return std::get<1>(callBack)(fp, fi); + }; // Remove the first line, this can be the directory we are searching in. // as long as we do not specify "mindepth > 0" diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 8fe8201e088..238bab5e777 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -3,10 +3,13 @@ #pragma once +#include "hostosinfo.h" #include "utils_global.h" #include "fileutils.h" +class tst_unixdevicefileaccess; // For testing. + namespace Utils { // Base class including dummy implementation usable as fallback. @@ -19,6 +22,7 @@ public: protected: friend class FilePath; + friend class ::tst_unixdevicefileaccess; // For testing. virtual QString mapToDevicePath(const QString &hostPath) const; @@ -204,8 +208,14 @@ private: const FileFilter &filter, QStringList *found) const; + Utils::OsType osType() const; + QStringList statArgs(const FilePath &filePath, + const QString &linuxFormat, + const QString &macFormat) const; + mutable bool m_tryUseFind = true; mutable std::optional m_hasMkTemp; + mutable std::optional m_osType; }; } // Utils diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index d128f219742..c0a574f9c34 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -586,8 +586,7 @@ FilePaths FileUtils::getOpenFilePaths(QWidget *parent, #endif // QT_WIDGETS_LIB -// Converts a hex string of the st_mode field of a stat structure to FileFlags. -FilePathInfo::FileFlags fileInfoFlagsfromStatRawModeHex(const QString &hexString) +FilePathInfo::FileFlags fileInfoFlagsfromStatMode(const QString &hexString, int modeBase) { // Copied from stat.h enum st_mode { @@ -617,7 +616,7 @@ FilePathInfo::FileFlags fileInfoFlagsfromStatRawModeHex(const QString &hexString }; bool ok = false; - uint mode = hexString.toUInt(&ok, 16); + uint mode = hexString.toUInt(&ok, modeBase); QTC_ASSERT(ok, return {}); @@ -657,13 +656,13 @@ FilePathInfo::FileFlags fileInfoFlagsfromStatRawModeHex(const QString &hexString return result; } -FilePathInfo FileUtils::filePathInfoFromTriple(const QString &infos) +FilePathInfo FileUtils::filePathInfoFromTriple(const QString &infos, int modeBase) { const QStringList parts = infos.split(' ', Qt::SkipEmptyParts); if (parts.size() != 3) return {}; - FilePathInfo::FileFlags flags = fileInfoFlagsfromStatRawModeHex(parts[0]); + FilePathInfo::FileFlags flags = fileInfoFlagsfromStatMode(parts[0], modeBase); const QDateTime dt = QDateTime::fromSecsSinceEpoch(parts[1].toLongLong(), Qt::UTC); qint64 size = parts[2].toLongLong(); diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index ec3de7a5ba4..19f17a6d719 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -83,7 +83,7 @@ public: static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput); - static FilePathInfo filePathInfoFromTriple(const QString &infos); + static FilePathInfo filePathInfoFromTriple(const QString &infos, int modeBase); #ifdef QT_WIDGETS_LIB static void setDialogParentGetter(const std::function &getter); diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index 65f47fc73f7..74fed43c104 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -17,3 +17,4 @@ add_subdirectory(stringutils) add_subdirectory(tasktree) add_subdirectory(templateengine) add_subdirectory(treemodel) +add_subdirectory(unixdevicefileaccess) diff --git a/tests/auto/utils/fileutils/tst_fileutils.cpp b/tests/auto/utils/fileutils/tst_fileutils.cpp index c4553eac645..f4596cb1a5c 100644 --- a/tests/auto/utils/fileutils/tst_fileutils.cpp +++ b/tests/auto/utils/fileutils/tst_fileutils.cpp @@ -172,7 +172,7 @@ void tst_fileutils::filePathInfoFromTriple() QFETCH(QString, statoutput); QFETCH(FilePathInfo, expected); - const FilePathInfo result = FileUtils::filePathInfoFromTriple(statoutput); + const FilePathInfo result = FileUtils::filePathInfoFromTriple(statoutput, 16); QCOMPARE(result, expected); } diff --git a/tests/auto/utils/unixdevicefileaccess/CMakeLists.txt b/tests/auto/utils/unixdevicefileaccess/CMakeLists.txt new file mode 100644 index 00000000000..0cf8d43c712 --- /dev/null +++ b/tests/auto/utils/unixdevicefileaccess/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_utils_unixdevicefileaccess + DEPENDS Utils + SOURCES tst_unixdevicefileaccess.cpp +) diff --git a/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp b/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp new file mode 100644 index 00000000000..8aa9609057c --- /dev/null +++ b/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include +#include +#include +#include + +#include +#include +#include +#include + +//TESTED_COMPONENT=src/libs/utils +using namespace Utils; + +namespace QTest { +template<> +char *toString(const FilePath &filePath) +{ + return qstrdup(filePath.toString().toLocal8Bit().constData()); +} +} // namespace QTest + +class TestDFA : public UnixDeviceFileAccess +{ +public: + using UnixDeviceFileAccess::UnixDeviceFileAccess; + + virtual RunResult runInShell(const CommandLine &cmdLine, + const QByteArray &inputData = {}) const override + { + QProcess p; + p.setProgram(cmdLine.executable().toString()); + p.setArguments(cmdLine.splitArguments()); + p.setProcessChannelMode(QProcess::SeparateChannels); + + p.start(); + p.waitForStarted(); + if (inputData.size() > 0) { + p.write(inputData); + p.closeWriteChannel(); + } + p.waitForFinished(); + return {p.exitCode(), p.readAllStandardOutput(), p.readAllStandardError()}; + } +}; + +class tst_unixdevicefileaccess : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase() + { + if (HostOsInfo::isWindowsHost()) + QSKIP("This test is only for Unix hosts"); + + m_fileSizeTestFile.writeFileContents(QByteArray(1024, 'a')); + } + + void osType() + { + const auto osType = m_dfaPtr->osType({}); + QCOMPARE(osType, HostOsInfo::hostOs()); + } + + void fileSize() + { + const auto size = m_dfaPtr->fileSize(m_fileSizeTestFile); + QCOMPARE(size, 1024); + } + +private: + TestDFA m_dfa; + DeviceFileAccess *m_dfaPtr = &m_dfa; + + QTemporaryDir m_tempDir; + FilePath m_fileSizeTestFile = FilePath::fromString(m_tempDir.filePath("size-test")); +}; + +QTEST_GUILESS_MAIN(tst_unixdevicefileaccess) + +#include "tst_unixdevicefileaccess.moc" diff --git a/tests/auto/utils/unixdevicefileaccess/unixdevicefileaccess.qbs b/tests/auto/utils/unixdevicefileaccess/unixdevicefileaccess.qbs new file mode 100644 index 00000000000..1776ef4a6ee --- /dev/null +++ b/tests/auto/utils/unixdevicefileaccess/unixdevicefileaccess.qbs @@ -0,0 +1,11 @@ +import qbs + +QtcAutotest { + name: "UnixDeviceFileAccess autotest" + Depends { name: "Utils" } + Properties { + condition: qbs.toolchain.contains("gcc") + cpp.cxxFlags: base.concat(["-Wno-trigraphs"]) + } + files: "tst_unixdevicefileaccess.cpp" +} diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index d8d0a58b4b8..5f4d0439201 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -22,5 +22,6 @@ Project { "tasktree/tasktree.qbs", "templateengine/templateengine.qbs", "treemodel/treemodel.qbs", + "unixdevicefileaccess/unixdevicefileaccess.qbs", ] } From f172dbca9c9c255b3ae4014461f60ced2c172d19 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Feb 2023 14:13:29 +0100 Subject: [PATCH 0086/1447] CMake: Fix warning about fPic not being the same Change-Id: I2a2f85c039471e2ad00551bec925cf37ca261b12 Reviewed-by: Qt CI Bot Reviewed-by: Cristian Adam --- cmake/QtCreatorAPIInternal.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index e0e513c9d29..479a6fb179b 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -413,6 +413,7 @@ function(enable_pch target) CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON CXX_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ON ) target_link_libraries(${pch_target} PRIVATE ${pch_dependency}) endif() From 8ecd8692bf42ab074e8ca074e7cf578491b9ff5c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 27 Feb 2023 08:33:17 +0100 Subject: [PATCH 0087/1447] Copilot: Enable translations Change-Id: I97bce412eb94bc1ac731205955e9a007199627fa Reviewed-by: Eike Ziller --- src/plugins/copilot/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/copilot/CMakeLists.txt b/src/plugins/copilot/CMakeLists.txt index 2f4cfd3007b..4cca0e8d215 100644 --- a/src/plugins/copilot/CMakeLists.txt +++ b/src/plugins/copilot/CMakeLists.txt @@ -1,5 +1,4 @@ add_qtc_plugin(Copilot - SKIP_TRANSLATION PLUGIN_DEPENDS Core LanguageClient SOURCES authwidget.cpp authwidget.h From 5169469911cf34c178a1741dc9b1199235f17775 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 21 Feb 2023 15:32:13 +0100 Subject: [PATCH 0088/1447] Debugger: add functionality to array dumper Change-Id: Ib44748fa3218788ca20a99b0a0f4cd85716dde06 Reviewed-by: hjk --- share/qtcreator/debugger/dumper.py | 16 ++++--- share/qtcreator/debugger/lldbbridge.py | 2 +- share/qtcreator/debugger/pdbbridge.py | 2 +- src/plugins/debugger/debuggerengine.cpp | 9 ++-- src/plugins/debugger/qml/qmlengine.cpp | 3 +- src/plugins/debugger/watchdata.cpp | 14 ++++++ src/plugins/debugger/watchdata.h | 2 + src/plugins/debugger/watchhandler.cpp | 60 ++++++++++++++++--------- src/plugins/debugger/watchhandler.h | 1 + tests/auto/debugger/tst_dumpers.cpp | 10 +++-- 10 files changed, 82 insertions(+), 37 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index f72ea04b38d..1fe048ea984 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -106,7 +106,7 @@ class Children(): self.d.putNumChild(0) if self.d.currentMaxNumChild is not None: if self.d.currentMaxNumChild < self.d.currentNumChild: - self.d.put('{name="",value="",type="",numchild="0"},') + self.d.put('{name="",value="",type="",numchild="1"},') self.d.currentChildType = self.savedChildType self.d.currentChildNumChild = self.savedChildNumChild self.d.currentNumChild = self.savedNumChild @@ -214,7 +214,7 @@ class DumperBase(): def setVariableFetchingOptions(self, args): self.resultVarName = args.get('resultvarname', '') - self.expandedINames = set(args.get('expanded', [])) + self.expandedINames = args.get('expanded', {}) self.stringCutOff = int(args.get('stringcutoff', 10000)) self.displayStringLimit = int(args.get('displaystringlimit', 100)) self.typeformats = args.get('typeformats', {}) @@ -297,6 +297,11 @@ class DumperBase(): return range(0, self.currentNumChild) return range(min(self.currentMaxNumChild, self.currentNumChild)) + def maxArrayCount(self): + if self.currentIName in self.expandedINames: + return self.expandedINames[self.currentIName] + return 100 + def enterSubItem(self, item): if self.useTimeStamps: item.startTime = time.time() @@ -2232,7 +2237,7 @@ class DumperBase(): res = self.currentValue return res # The 'short' display. - def putArrayData(self, base, n, innerType, childNumChild=None, maxNumChild=10000): + def putArrayData(self, base, n, innerType, childNumChild=None): self.checkIntType(base) self.checkIntType(n) addrBase = base @@ -2240,6 +2245,7 @@ class DumperBase(): self.putNumChild(n) #DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) enc = innerType.simpleEncoding() + maxNumChild = self.maxArrayCount() if enc: self.put('childtype="%s",' % innerType.name) self.put('addrbase="0x%x",' % addrBase) @@ -2247,7 +2253,7 @@ class DumperBase(): self.put('arrayencoding="%s",' % enc) self.put('endian="%s",' % self.packCode) if n > maxNumChild: - self.put('childrenelided="%s",' % n) # FIXME: Act on that in frontend + self.put('childrenelided="%s",' % n) n = maxNumChild self.put('arraydata="') self.put(self.readMemory(addrBase, n * innerSize)) @@ -2281,7 +2287,7 @@ class DumperBase(): def putPlotData(self, base, n, innerType, maxNumChild=1000 * 1000): self.putPlotDataHelper(base, n, innerType, maxNumChild=maxNumChild) if self.isExpanded(): - self.putArrayData(base, n, innerType, maxNumChild=maxNumChild) + self.putArrayData(base, n, innerType) def putSpecialArgv(self, value): """ diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index c14bf30286f..8a97e642970 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -2120,7 +2120,7 @@ class SummaryDumper(Dumper, LogMixin): # Expand variable if we need synthetic children oldExpanded = self.expandedINames - self.expandedINames = [value.name] if expanded else [] + self.expandedINames = {value.name: 100} if expanded else {} savedOutput = self.output self.output = [] diff --git a/share/qtcreator/debugger/pdbbridge.py b/share/qtcreator/debugger/pdbbridge.py index e91c56e7163..228f4c8c1fc 100644 --- a/share/qtcreator/debugger/pdbbridge.py +++ b/share/qtcreator/debugger/pdbbridge.py @@ -1445,7 +1445,7 @@ class QtcInternalDumper(): self.updateData(args) def updateData(self, args): - self.expandedINames = __builtins__.set(args.get('expanded', [])) + self.expandedINames = args.get('expanded', {}) self.typeformats = args.get('typeformats', {}) self.formats = args.get('formats', {}) self.output = '' diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 14cab127508..a9609584c6e 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -471,7 +471,7 @@ public: QString m_qtNamespace; // Safety net to avoid infinite lookups. - QSet m_lookupRequests; // FIXME: Integrate properly. + QHash m_lookupRequests; // FIXME: Integrate properly. QPointer m_alertBox; QPointer m_breakView; @@ -2360,9 +2360,10 @@ bool DebuggerEngine::canHandleToolTip(const DebuggerToolTipContext &context) con void DebuggerEngine::updateItem(const QString &iname) { - if (d->m_lookupRequests.contains(iname)) { + WatchHandler *handler = watchHandler(); + const int maxArrayCount = handler->maxArrayCount(iname); + if (d->m_lookupRequests.value(iname, -1) == maxArrayCount) { showMessage(QString("IGNORING REPEATED REQUEST TO EXPAND " + iname)); - WatchHandler *handler = watchHandler(); WatchItem *item = handler->findItem(iname); QTC_CHECK(item); WatchModelBase *model = handler->model(); @@ -2382,7 +2383,7 @@ void DebuggerEngine::updateItem(const QString &iname) } // We could legitimately end up here after expanding + closing + re-expaning an item. } - d->m_lookupRequests.insert(iname); + d->m_lookupRequests[iname] = maxArrayCount; UpdateParameters params; params.partialVariable = iname; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 204d6c4437c..c0cf98cfb4a 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -2321,7 +2321,6 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro QTC_ASSERT(parent, return); LookupItems itemsToLookup; - const QSet expandedINames = engine->watchHandler()->expandedINames(); for (const QVariant &property : properties) { QmlV8ObjectData propertyData = extractData(property); std::unique_ptr item(new WatchItem); @@ -2343,7 +2342,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro item->id = propertyData.handle; item->type = propertyData.type; item->value = propertyData.value.toString(); - if (item->type.isEmpty() || expandedINames.contains(item->iname)) + if (item->type.isEmpty() || engine->watchHandler()->isExpandedIName(item->iname)) itemsToLookup.insert(propertyData.handle, {item->iname, item->name, item->exp}); setWatchItemHasChildren(item.get(), propertyData.hasChildren()); parent->appendChild(item.release()); diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 4b64248e2f7..d42e8331ca9 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -212,6 +212,13 @@ public: child->valueEditable = true; item->appendChild(child); } + if (childrenElided) { + auto child = new WatchItem; + child->name = WatchItem::loadMoreName; + child->iname = item->iname + "." + WatchItem::loadMoreName; + child->wantsChildren = true; + item->appendChild(child); + } } void decode() @@ -260,6 +267,7 @@ public: QString rawData; QString childType; DebuggerEncoding encoding; + int childrenElided; quint64 addrbase; quint64 addrstep; Endian endian; @@ -375,6 +383,7 @@ void WatchItem::parseHelper(const GdbMi &input, bool maySort) decoder.item = this; decoder.rawData = mi.data(); decoder.childType = input["childtype"].data(); + decoder.childrenElided = input["childrenelided"].toInt(); decoder.addrbase = input["addrbase"].toAddress(); decoder.addrstep = input["addrstep"].toAddress(); decoder.endian = input["endian"].data() == ">" ? Endian::Big : Endian::Little; @@ -500,6 +509,11 @@ QString WatchItem::toToolTip() const return res; } +bool WatchItem::isLoadMore() const +{ + return name == loadMoreName; +} + bool WatchItem::isLocal() const { if (arrayIndex >= 0) diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index c25e1962f9c..15ccdf019b8 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -36,8 +36,10 @@ public: int editType() const; static const qint64 InvalidId = -1; + constexpr static char loadMoreName[] = ""; void setHasChildren(bool c) { wantsChildren = c; } + bool isLoadMore() const; bool isValid() const { return !iname.isEmpty(); } bool isVTablePointer() const; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 83ff13b71b8..144ef1d9a0c 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -402,6 +402,7 @@ public: WatchModel(WatchHandler *handler, DebuggerEngine *engine); static QString nameForFormat(int format); + constexpr static int defaultMaxArrayCount = 100; QVariant data(const QModelIndex &idx, int role) const override; bool setData(const QModelIndex &idx, const QVariant &value, int role) override; @@ -410,6 +411,7 @@ public: bool hasChildren(const QModelIndex &idx) const override; bool canFetchMore(const QModelIndex &idx) const override; void fetchMore(const QModelIndex &idx) override; + void expand(WatchItem *item, bool requestEngineUpdate); QString displayForAutoTest(const QByteArray &iname) const; void reinitialize(bool includeInspectData = false); @@ -468,6 +470,7 @@ public: SeparatedView *m_separatedView; // Not owned. QSet m_expandedINames; + QHash m_maxArrayCount; QTimer m_requestUpdateTimer; QHash m_reportedTypeInfo; @@ -1210,7 +1213,8 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role if (value.toBool()) { // Should already have been triggered by fetchMore() //QTC_CHECK(m_expandedINames.contains(item->iname)); - m_expandedINames.insert(item->iname); + if (!item->isLoadMore()) + m_expandedINames.insert(item->iname); } else { m_expandedINames.remove(item->iname); } @@ -1320,13 +1324,22 @@ bool WatchModel::canFetchMore(const QModelIndex &idx) const void WatchModel::fetchMore(const QModelIndex &idx) { - if (!idx.isValid()) - return; + if (idx.isValid()) + expand(nonRootItemForIndex(idx), true); +} - WatchItem *item = nonRootItemForIndex(idx); - if (item) { +void WatchModel::expand(WatchItem *item, bool requestEngineUpdate) +{ + if (!item) + return; + if (item->isLoadMore()) { + item = item->parent(); + m_maxArrayCount[item->iname] = m_maxArrayCount.value(item->iname, defaultMaxArrayCount) * 10; + if (requestEngineUpdate) + m_engine->updateItem(item->iname); + } else { m_expandedINames.insert(item->iname); - if (item->childCount() == 0) + if (requestEngineUpdate && item->childCount() == 0) m_engine->expandItem(item->iname); } } @@ -1749,10 +1762,14 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) menu->addSeparator(); addAction(this, menu, Tr::tr("Expand All Children"), item, [this, name = item ? item->iname : QString()] { - m_expandedINames.insert(name); - if (auto item = findItem(name)) { - item->forFirstLevelChildren( - [this](WatchItem *child) { m_expandedINames.insert(child->iname); }); + if (name.isEmpty()) + return; + if (WatchItem *item = findItem(name)) { + expand(item, false); + item->forFirstLevelChildren([this](WatchItem *child) { + if (!child->isLoadMore()) + expand(child, false); + }); m_engine->updateLocals(); } }); @@ -2210,7 +2227,7 @@ bool WatchHandler::insertItem(WatchItem *item) void WatchModel::reexpandItems() { - for (const QString &iname : std::as_const(m_expandedINames)) { + for (const QString &iname: m_expandedINames) { if (WatchItem *item = findItem(iname)) { emit itemIsExpanded(indexForItem(item)); emit inameIsExpanded(iname); @@ -2292,7 +2309,8 @@ void WatchHandler::notifyUpdateFinished() m_model->destroyItem(item); m_model->forAllItems([this](WatchItem *item) { - if (item->wantsChildren && isExpandedIName(item->iname)) { + if (item->wantsChildren && isExpandedIName(item->iname) + && item->name != WatchItem::loadMoreName) { m_model->m_engine->showMessage(QString("ADJUSTING CHILD EXPECTATION FOR " + item->iname)); item->wantsChildren = false; } @@ -2593,11 +2611,8 @@ const WatchItem *WatchHandler::watchItem(const QModelIndex &idx) const void WatchHandler::fetchMore(const QString &iname) const { - if (WatchItem *item = m_model->findItem(iname)) { - m_model->m_expandedINames.insert(iname); - if (item->childCount() == 0) - m_model->m_engine->expandItem(iname); - } + if (WatchItem *item = m_model->findItem(iname)) + m_model->expand(item, true); } WatchItem *WatchHandler::findItem(const QString &iname) const @@ -2711,9 +2726,9 @@ QString WatchHandler::individualFormatRequests() const void WatchHandler::appendFormatRequests(DebuggerCommand *cmd) const { - QJsonArray expanded; - for (const QString &name : std::as_const(m_model->m_expandedINames)) - expanded.append(name); + QJsonObject expanded; + for (const QString &iname : std::as_const(m_model->m_expandedINames)) + expanded.insert(iname, maxArrayCount(iname)); cmd->arg("expanded", expanded); @@ -2817,6 +2832,11 @@ QSet WatchHandler::expandedINames() const return m_model->m_expandedINames; } +int WatchHandler::maxArrayCount(const QString &iname) const +{ + return m_model->m_maxArrayCount.value(iname, WatchModel::defaultMaxArrayCount); +} + void WatchHandler::recordTypeInfo(const GdbMi &typeInfo) { if (typeInfo.type() == GdbMi::List) { diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 0683d73ce94..58a64cea4a4 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -60,6 +60,7 @@ public: bool isExpandedIName(const QString &iname) const; QSet expandedINames() const; + int maxArrayCount(const QString &iname) const; static QStringList watchedExpressions(); static QMap watcherNames(); diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 1e563d0a35b..d67e8de1f4b 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1736,7 +1736,8 @@ void tst_Dumpers::dumper() expandedq.append(','); } expanded += iname; - expandedq += '\'' + iname + '\''; + expandedq += '\'' + iname + "':"; + expandedq += data.bigArray ? "10000" : "100"; } QString exe = m_debuggerBinary; @@ -1769,7 +1770,7 @@ void tst_Dumpers::dumper() "'token':2,'fancy':1,'forcens':1," "'autoderef':1,'dyntype':1,'passexceptions':1," "'testing':1,'qobjectnames':1," - "'expanded':[" + expandedq + "]})\n"; + "'expanded':{" + expandedq + "}})\n"; cmds += "quit\n"; @@ -1792,7 +1793,7 @@ void tst_Dumpers::dumper() "'token':2,'fancy':1,'forcens':1," "'autoderef':1,'dyntype':1,'passexceptions':0," "'testing':1,'qobjectnames':1," - "'expanded':[" + expandedq + "]})\n" + "'expanded':{" + expandedq + "}})\n" "q\n"; } else if (m_debuggerEngine == LldbEngine) { QFile fullLldb(t->buildPath + "/lldbcommand.txt"); @@ -1808,7 +1809,7 @@ void tst_Dumpers::dumper() "'fancy':1,'forcens':1," "'autoderef':1,'dyntype':1,'passexceptions':1," "'testing':1,'qobjectnames':1," - "'expanded':[" + expandedq + "]})\n" + "'expanded':{" + expandedq + "}})\n" "quit\n"; fullLldb.write(cmds.toUtf8()); @@ -5310,6 +5311,7 @@ void tst_Dumpers::dumper_data() "&v0, &v1, &v2, &v3, &v4, &v5, &b0, &b1, &b2, &b3") + Cxx11Profile() + + BigArrayProfile() + Check("v0", "<0 items>", "std::valarray") + Check("v1", "<3 items>", "std::valarray") From eec0ea06078447beeb37b142bf60e53bdce211f0 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 24 Feb 2023 15:20:36 +0100 Subject: [PATCH 0089/1447] Fix build with qbs as submodule and CMake < 3.18 Broke with 66d4e12a586509c7ff903bae633f4fa2ebdcc0ce. Change-Id: I71bf156b8bba27b3285aab39db56f2ec055bff0c Reviewed-by: Eike Ziller --- CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f474b952155..d52a1c8b65b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,19 @@ find_package(Qt6 COMPONENTS Concurrent Core Gui Network PrintSupport Qml Sql Widgets Xml Core5Compat ${QT_TEST_COMPONENT} REQUIRED ) +# hack for Qbs which still supports Qt5 and Qt6 +if (TARGET Qt6::Core5CompatPrivate) + if (CMAKE_VERSION VERSION_LESS 3.18) + set_property(TARGET Qt6::Core5CompatPrivate PROPERTY IMPORTED_GLOBAL TRUE) + endif() + add_library(Qt6Core5CompatPrivate ALIAS Qt6::Core5CompatPrivate) +endif() +if (TARGET Qt6::Core5Compat) + if (CMAKE_VERSION VERSION_LESS 3.18) + set_property(TARGET Qt6::Core5Compat PROPERTY IMPORTED_GLOBAL TRUE) + endif() + add_library(Qt6Core5Compat ALIAS Qt6::Core5Compat) +endif() # Common intermediate directory for QML modules which are defined via qt_add_qml_module() set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml_modules") From 558e9f4b16ac9fe769a761e9b93080803f200b8d Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 25 Feb 2023 11:13:09 +0100 Subject: [PATCH 0090/1447] Terminal: Add selection color setting Change-Id: I66f94c3bd729975046ea72aca3bc23bb5024ced0 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalsettings.cpp | 1 + src/plugins/terminal/terminalsettings.h | 2 ++ src/plugins/terminal/terminalsettingspage.cpp | 1 + src/plugins/terminal/terminalwidget.cpp | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index a69a1e56810..d19b488f3e2 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -81,6 +81,7 @@ TerminalSettings::TerminalSettings() setupColor(foregroundColor, "Foreground", QColor::fromRgb(0xff, 0xff, 0xff)); setupColor(backgroundColor, "Background", QColor::fromRgb(0x0, 0x0, 0x0)); + setupColor(selectionColor, "Selection", QColor::fromRgb(0xFF, 0xFF, 0xFF, 0x7F)); setupColor(colors[0], "0", QColor::fromRgb(0x00, 0x00, 0x00)); setupColor(colors[8], "8", QColor::fromRgb(102, 102, 102)); diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index 82557b207c1..3f92f1aa7aa 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -20,6 +20,8 @@ public: Utils::ColorAspect foregroundColor; Utils::ColorAspect backgroundColor; + Utils::ColorAspect selectionColor; + Utils::ColorAspect colors[16]; }; diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index b85b4a1321b..f48360b0be0 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -62,6 +62,7 @@ QWidget *TerminalSettingsPage::widget() Row { Tr::tr("Foreground"), settings.foregroundColor, st, Tr::tr("Background"), settings.backgroundColor, st, + Tr::tr("Selection"), settings.selectionColor, st, }, Row { settings.colors[0], settings.colors[1], diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index a4bf0ae37a9..be20d623711 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -511,7 +511,7 @@ std::optional TerminalWidget::selectionToFormatRange( QTextLayout::FormatRange range; range.start = startPos; range.length = endPos - startPos; - range.format.setBackground(QColor::fromRgbF(1.0, 1.0, 1.0, 0.5)); + range.format.setBackground(TerminalSettings::instance().selectionColor.value()); return range; } From a21a5249de7acb71df44a0eb7e2248692c830350 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 25 Feb 2023 11:53:26 +0100 Subject: [PATCH 0091/1447] Terminal: Fix Background painting Change-Id: I62d9e10b8e7e79985dc7a9b68d6a05db1e743261 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalwidget.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index be20d623711..e45375c3b9b 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -56,14 +56,14 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op setCursor(Qt::IBeamCursor); + setViewportMargins(1, 1, 1, 1); + m_textLayout.setCacheEnabled(true); setFocus(); setFocusPolicy(Qt::StrongFocus); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - // setFrameStyle(QFrame::NoFrame); - setAttribute(Qt::WA_OpaquePaintEvent); m_readDelayTimer.setSingleShot(true); m_readDelayTimer.setInterval(10); @@ -296,7 +296,7 @@ void TerminalWidget::setFont(const QFont &font) return qfm.averageCharWidth(); }(); - qCInfo(terminalLog) << font.family() << font.pointSize() << w << size(); + qCInfo(terminalLog) << font.family() << font.pointSize() << w << viewport()->size(); m_cellSize = {w, qfm.height()}; m_cellBaseline = qfm.ascent(); @@ -485,7 +485,7 @@ void TerminalWidget::createTextLayout() qreal TerminalWidget::topMargin() const { - return size().height() - (m_vtermSize.height() * m_lineSpacing); + return (qreal) viewport()->size().height() - ((qreal) m_vtermSize.height() * m_lineSpacing); } std::optional TerminalWidget::selectionToFormatRange( @@ -601,7 +601,8 @@ void TerminalWidget::paintEvent(QPaintEvent *event) const qreal br = fm.horizontalAdvance(QString::fromUcs4(&ch, 1)); const qreal xCursor = cursorLine.cursorToX(cPos); const double yCursor = cursorLine.y() + y; - const QRectF cursorRect = QRectF{xCursor, yCursor, br, m_lineSpacing}; + const QRectF cursorRect + = QRectF{xCursor, yCursor + 1, br, m_lineSpacing - 2}; if (hasFocus()) { QPainter::CompositionMode oldMode = p.compositionMode(); p.setCompositionMode(QPainter::RasterOp_NotDestination); @@ -692,8 +693,8 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) void TerminalWidget::applySizeChange() { m_vtermSize = { - qFloor((qreal) size().width() / (qreal) m_cellSize.width()), - qFloor((qreal) size().height() / m_lineSpacing), + qFloor((qreal) (viewport()->size().width()) / (qreal) m_cellSize.width()), + qFloor((qreal) (viewport()->size().height()) / m_lineSpacing), }; if (m_vtermSize.height() <= 0) @@ -891,6 +892,13 @@ bool TerminalWidget::event(QEvent *event) return true; } + if (event->type() == QEvent::Paint) { + QPainter p(this); + p.fillRect(QRect(QPoint(0, 0), size()), + TerminalSettings::instance().backgroundColor.value()); + return true; + } + return QAbstractScrollArea::event(event); } From d3b4159b23c00b2ce18f0e28763b9ce4a66daf35 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 25 Feb 2023 11:20:26 +0100 Subject: [PATCH 0092/1447] Terminal: Fix preedit area position Change-Id: I8667a84e12154ca34517af25648a0983f918fc48 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalwidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index e45375c3b9b..2118c7b7488 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -617,11 +617,10 @@ void TerminalWidget::paintEvent(QPaintEvent *event) } if (!m_preEditString.isEmpty()) { - // TODO: Use QTextLayout::setPreeditArea() instead ? QTextLine cursorLine = m_textLayout.lineAt(m_cursor.row); if (cursorLine.isValid()) { int pos = cursorLine.textStart() + m_cursor.col; - QPointF displayPos = QPointF{cursorLine.cursorToX(pos), cursorLine.y()}; + QPointF displayPos = QPointF{cursorLine.cursorToX(pos), cursorLine.y() + y}; p.fillRect(QRectF{displayPos.toPoint(), m_cellSize}, QColor::fromRgb(0, 0, 0)); p.setPen(Qt::white); From 1381bd096376b2ba76362670046e8276d3391844 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 25 Feb 2023 11:53:09 +0100 Subject: [PATCH 0093/1447] Terminal: Fix \ on German mac keyboard Change-Id: I87d4299c1e41f4a553b5ecc9690b2fd332b7b3e8 Reviewed-by: Burak Hancerli Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 2118c7b7488..64566acc1fc 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -681,6 +681,12 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) // ctrl modifier. This helps with ncurses applications which otherwise // do not recognize ctrl+ and in the shell for getting common control characters // like ctrl+i for tab or ctrl+j for newline. + + // Workaround for "ALT+SHIFT+/" (\ on german mac keyboards) + if (mod == (VTERM_MOD_SHIFT | VTERM_MOD_ALT) && event->key() == Qt::Key_Slash) { + mod = VTERM_MOD_NONE; + } + vterm_keyboard_unichar(m_vterm.get(), event->text().toUcs4()[0], static_cast(mod & ~VTERM_MOD_CTRL)); From d4ac8aeaa6063554fdef51c81a752417b0fd0de7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 25 Feb 2023 10:47:21 +0100 Subject: [PATCH 0094/1447] Terminal: Add remote devices to shell selection Change-Id: Id28471aaf3e91ef493f48ab28207230f3fb513c2 Reviewed-by: Cristian Adam --- src/libs/utils/terminalhooks.cpp | 8 ++ src/libs/utils/terminalhooks.h | 10 +- .../devicesupport/devicemanager.cpp | 14 +++ src/plugins/terminal/CMakeLists.txt | 2 +- src/plugins/terminal/shellmodel.cpp | 111 ++++++++++++++++++ src/plugins/terminal/shellmodel.h | 37 ++++++ src/plugins/terminal/terminalpane.cpp | 91 +++----------- 7 files changed, 199 insertions(+), 74 deletions(-) create mode 100644 src/plugins/terminal/shellmodel.cpp create mode 100644 src/plugins/terminal/shellmodel.h diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index d0b48075683..df27e0404b9 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -18,10 +18,12 @@ struct HooksPrivate }) , m_createTerminalProcessInterfaceHook( []() -> ProcessInterface * { return new Internal::TerminalImpl(); }) + , m_getTerminalCommandsForDevicesHook([]() -> QList { return {}; }) {} Hooks::OpenTerminalHook m_openTerminalHook; Hooks::CreateTerminalProcessInterfaceHook m_createTerminalProcessInterfaceHook; + Hooks::GetTerminalCommandsForDevicesHook m_getTerminalCommandsForDevicesHook; }; Hooks &Hooks::instance() @@ -40,9 +42,15 @@ Hooks::OpenTerminalHook &Hooks::openTerminalHook() { return d->m_openTerminalHook; } + Hooks::CreateTerminalProcessInterfaceHook &Hooks::createTerminalProcessInterfaceHook() { return d->m_createTerminalProcessInterfaceHook; } +Hooks::GetTerminalCommandsForDevicesHook &Hooks::getTerminalCommandsForDevicesHook() +{ + return d->m_getTerminalCommandsForDevicesHook; +} + } // namespace Utils::Terminal diff --git a/src/libs/utils/terminalhooks.h b/src/libs/utils/terminalhooks.h index 57012afc903..492c53da81f 100644 --- a/src/libs/utils/terminalhooks.h +++ b/src/libs/utils/terminalhooks.h @@ -48,19 +48,27 @@ struct OpenTerminalParameters ExitBehavior m_exitBehavior{ExitBehavior::Close}; }; +struct NameAndCommandLine +{ + QString name; + CommandLine commandLine; +}; + class QTCREATOR_UTILS_EXPORT Hooks { public: using OpenTerminalHook = Hook; using CreateTerminalProcessInterfaceHook = Hook; + using GetTerminalCommandsForDevicesHook = Hook>; public: static Hooks &instance(); + ~Hooks(); OpenTerminalHook &openTerminalHook(); CreateTerminalProcessInterfaceHook &createTerminalProcessInterfaceHook(); + GetTerminalCommandsForDevicesHook &getTerminalCommandsForDevicesHook(); - ~Hooks(); private: Hooks(); std::unique_ptr d; diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 9f8e0594fd8..c254afcd7e7 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -457,6 +458,19 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique QList { + QList result; + for (const IDevice::ConstPtr device : d->devices) { + if (device->type() == Constants::DESKTOP_DEVICE_TYPE) + continue; + const std::optional terminalCommand = device->terminalCommand({}, {}); + if (terminalCommand) + result << Terminal::NameAndCommandLine{device->displayName(), *terminalCommand}; + } + return result; + }); } DeviceManager::~DeviceManager() diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index 14f6d844b36..8303fdc1770 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -1,6 +1,5 @@ add_qtc_plugin(Terminal - SKIP_TRANSLATION PLUGIN_DEPENDS Core DEPENDS libvterm ptyqt SOURCES @@ -13,5 +12,6 @@ add_qtc_plugin(Terminal terminalsettings.cpp terminalsettings.h terminalsettingspage.cpp terminalsettingspage.h scrollback.h scrollback.cpp + shellmodel.cpp shellmodel.h keys.cpp keys.h ) diff --git a/src/plugins/terminal/shellmodel.cpp b/src/plugins/terminal/shellmodel.cpp new file mode 100644 index 00000000000..cd901fbb6e8 --- /dev/null +++ b/src/plugins/terminal/shellmodel.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "shellmodel.h" + +#include +#include +#include + +#include +#include + +namespace Terminal::Internal { + +using namespace Utils; + +FilePaths availableShells() +{ + if (Utils::HostOsInfo::isWindowsHost()) { + FilePaths shells; + + FilePath comspec = FilePath::fromUserInput(qtcEnvironmentVariable("COMSPEC")); + shells << comspec; + + if (comspec.fileName() != "cmd.exe") { + FilePath cmd = FilePath::fromUserInput(QStandardPaths::findExecutable("cmd.exe")); + shells << cmd; + } + + FilePath powershell = FilePath::fromUserInput( + QStandardPaths::findExecutable("powershell.exe")); + if (powershell.exists()) + shells << powershell; + + FilePath bash = FilePath::fromUserInput(QStandardPaths::findExecutable("bash.exe")); + if (bash.exists()) + shells << bash; + + FilePath git_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("git.exe")); + if (git_bash.exists()) + shells << git_bash.parentDir().parentDir().pathAppended("usr/bin/bash.exe"); + + FilePath msys2_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("msys2.exe")); + if (msys2_bash.exists()) + shells << msys2_bash.parentDir().pathAppended("usr/bin/bash.exe"); + + return shells; + } else { + FilePath shellsFile = FilePath::fromString("/etc/shells"); + const auto shellFileContent = shellsFile.fileContents(); + QTC_ASSERT_EXPECTED(shellFileContent, return {}); + + QString shellFileContentString = QString::fromUtf8(*shellFileContent); + + // Filter out comments ... + const QStringList lines + = Utils::filtered(shellFileContentString.split('\n', Qt::SkipEmptyParts), + [](const QString &line) { return !line.trimmed().startsWith('#'); }); + + // Convert lines to file paths ... + const FilePaths shells = Utils::transform(lines, [](const QString &line) { + return FilePath::fromUserInput(line.trimmed()); + }); + + // ... and filter out non-existing shells. + return Utils::filtered(shells, [](const FilePath &shell) { return shell.exists(); }); + } +} + +struct ShellModelPrivate +{ + QList localShells; +}; + +ShellModel::ShellModel(QObject *parent) + : QObject(parent) + , d(new ShellModelPrivate()) +{ + QFileIconProvider iconProvider; + + const FilePaths shells = availableShells(); + for (const FilePath &shell : shells) { + ShellModelItem item; + item.icon = iconProvider.icon(shell.toFileInfo()); + item.name = shell.toUserOutput(); + item.openParameters.shellCommand = {shell, {}}; + d->localShells << item; + } +} + +ShellModel::~ShellModel() = default; + +QList ShellModel::local() const +{ + return d->localShells; +} + +QList ShellModel::remote() const +{ + const auto deviceCmds = Utils::Terminal::Hooks::instance().getTerminalCommandsForDevicesHook()(); + + const QList deviceItems + = Utils::transform(deviceCmds, + [](const Utils::Terminal::NameAndCommandLine &item) -> ShellModelItem { + return ShellModelItem{item.name, {}, {item.commandLine, {}, {}}}; + }); + + return deviceItems; +} + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/shellmodel.h b/src/plugins/terminal/shellmodel.h new file mode 100644 index 00000000000..272f3fcd394 --- /dev/null +++ b/src/plugins/terminal/shellmodel.h @@ -0,0 +1,37 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include +#include +#include + +#include + +namespace Terminal::Internal { +struct ShellModelPrivate; + +struct ShellModelItem +{ + QString name; + QIcon icon; + Utils::Terminal::OpenTerminalParameters openParameters; +}; + +class ShellModel : public QObject +{ +public: + ShellModel(QObject *parent = nullptr); + ~ShellModel(); + + QList local() const; + QList remote() const; + +private: + std::unique_ptr d; +}; + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index a355ca02725..f66e6a51715 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -3,6 +3,7 @@ #include "terminalpane.h" +#include "shellmodel.h" #include "terminaltr.h" #include "terminalwidget.h" @@ -13,7 +14,6 @@ #include #include -#include #include #include @@ -21,59 +21,6 @@ namespace Terminal { using namespace Utils; -FilePaths availableShells() -{ - if (Utils::HostOsInfo::isWindowsHost()) { - FilePaths shells; - - FilePath comspec = FilePath::fromUserInput(qtcEnvironmentVariable("COMSPEC")); - shells << comspec; - - if (comspec.fileName() != "cmd.exe") { - FilePath cmd = FilePath::fromUserInput(QStandardPaths::findExecutable("cmd.exe")); - shells << cmd; - } - - FilePath powershell = FilePath::fromUserInput( - QStandardPaths::findExecutable("powershell.exe")); - if (powershell.exists()) - shells << powershell; - - FilePath bash = FilePath::fromUserInput(QStandardPaths::findExecutable("bash.exe")); - if (bash.exists()) - shells << bash; - - FilePath git_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("git.exe")); - if (git_bash.exists()) - shells << git_bash.parentDir().parentDir().pathAppended("usr/bin/bash.exe"); - - FilePath msys2_bash = FilePath::fromUserInput(QStandardPaths::findExecutable("msys2.exe")); - if (msys2_bash.exists()) - shells << msys2_bash.parentDir().pathAppended("usr/bin/bash.exe"); - - return shells; - } else { - FilePath shellsFile = FilePath::fromString("/etc/shells"); - const auto shellFileContent = shellsFile.fileContents(); - QTC_ASSERT_EXPECTED(shellFileContent, return {}); - - QString shellFileContentString = QString::fromUtf8(*shellFileContent); - - // Filter out comments ... - const QStringList lines - = Utils::filtered(shellFileContentString.split('\n', Qt::SkipEmptyParts), - [](const QString &line) { return !line.trimmed().startsWith('#'); }); - - // Convert lines to file paths ... - const FilePaths shells = Utils::transform(lines, [](const QString &line) { - return FilePath::fromUserInput(line.trimmed()); - }); - - // ... and filter out non-existing shells. - return Utils::filtered(shells, [](const FilePath &shell) { return shell.exists(); }); - } -} - TerminalPane::TerminalPane(QObject *parent) : Core::IOutputPane(parent) { @@ -92,32 +39,30 @@ TerminalPane::TerminalPane(QObject *parent) removeTab(m_tabWidget->currentIndex()); }); - //Core::Command *cmd = Core::ActionManager::registerAction(m_newTerminal, Constants::STOP); - //cmd->setDescription(m_newTerminal->toolTip()); - m_newTerminalButton = new QToolButton(); QMenu *shellMenu = new QMenu(m_newTerminalButton); + Internal::ShellModel *shellModel = new Internal::ShellModel(shellMenu); + connect(shellMenu, &QMenu::aboutToShow, shellMenu, [shellMenu, shellModel, pane = this] { + shellMenu->clear(); - const FilePaths shells = availableShells(); + const auto addItems = [shellMenu, pane](const QList &items) { + for (const Internal::ShellModelItem &item : items) { + QAction *action = new QAction(item.icon, item.name, shellMenu); - QFileIconProvider iconProvider; + connect(action, &QAction::triggered, action, [item, pane]() { + pane->openTerminal(item.openParameters); + }); - // Create an action for each available shell ... - for (const FilePath &shell : shells) { - const QIcon icon = iconProvider.icon(shell.toFileInfo()); + shellMenu->addAction(action); + } + }; - QAction *action = new QAction(icon, shell.toUserOutput(), shellMenu); - action->setData(shell.toVariant()); - shellMenu->addAction(action); - } - connect(shellMenu, &QMenu::triggered, this, [this](QAction *action) { - openTerminal( - Utils::Terminal::OpenTerminalParameters{CommandLine{FilePath::fromVariant(action->data()), {}}, - std::nullopt, - std::nullopt, - Utils::Terminal::ExitBehavior::Close}); + addItems(shellModel->local()); + shellMenu->addSection(Tr::tr("Devices")); + addItems(shellModel->remote()); }); + m_newTerminal.setMenu(shellMenu); m_newTerminalButton->setDefaultAction(&m_newTerminal); @@ -132,6 +77,8 @@ void TerminalPane::openTerminal(const Utils::Terminal::OpenTerminalParameters &p m_tabWidget->setCurrentIndex( m_tabWidget->addTab(new TerminalWidget(m_tabWidget, parameters), Tr::tr("Terminal"))); + m_tabWidget->currentWidget()->setFocus(); + m_closeTerminal.setEnabled(m_tabWidget->count() > 1); emit navigateStateUpdate(); } From 3e73fe302e65af7860f47ec22153e2c0479f99ff Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 27 Feb 2023 11:06:14 +0100 Subject: [PATCH 0095/1447] Terminal: Coverity warning fixes Change-Id: If96291ff6df97f7e85840eb0951cc3f4abfab0f6 Reviewed-by: Eike Ziller --- src/libs/3rdparty/libptyqt/unixptyprocess.cpp | 7 ++++--- src/libs/3rdparty/libvterm/src/state.c | 2 +- src/plugins/projectexplorer/projectexplorer.cpp | 4 +++- src/plugins/terminal/terminalpane.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libs/3rdparty/libptyqt/unixptyprocess.cpp b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp index a9167e7696d..7cb8237a605 100644 --- a/src/libs/3rdparty/libptyqt/unixptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp @@ -343,15 +343,16 @@ void ShellProcess::configChildProcess() struct utmpx utmpxInfo; memset(&utmpxInfo, 0, sizeof(utmpxInfo)); - strncpy(utmpxInfo.ut_user, qgetenv("USER"), sizeof(utmpxInfo.ut_user)); + strncpy(utmpxInfo.ut_user, qgetenv("USER"), sizeof(utmpxInfo.ut_user) - 1); QString device(m_handleSlaveName); if (device.startsWith("/dev/")) device = device.mid(5); - const char *d = device.toLatin1().constData(); + const auto deviceAsLatin1 = device.toLatin1(); + const char *d = deviceAsLatin1.constData(); - strncpy(utmpxInfo.ut_line, d, sizeof(utmpxInfo.ut_line)); + strncpy(utmpxInfo.ut_line, d, sizeof(utmpxInfo.ut_line) - 1); strncpy(utmpxInfo.ut_id, d + strlen(d) - sizeof(utmpxInfo.ut_id), sizeof(utmpxInfo.ut_id)); diff --git a/src/libs/3rdparty/libvterm/src/state.c b/src/libs/3rdparty/libvterm/src/state.c index b22fba706b6..313e746e77c 100644 --- a/src/libs/3rdparty/libvterm/src/state.c +++ b/src/libs/3rdparty/libvterm/src/state.c @@ -1842,7 +1842,7 @@ static void request_status_string(VTermState *state, VTermStringFragment frag) case ' '|('q'<<8): { // Query DECSCUSR - int reply; + int reply = 2; switch(state->mode.cursor_shape) { case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break; case VTERM_PROP_CURSORSHAPE_UNDERLINE: reply = 4; break; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 2402a8004c5..a260d211ab2 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3813,8 +3813,10 @@ void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env return; BuildConfiguration *bc = activeBuildConfiguration(ProjectTree::projectForNode(currentNode)); - if (!bc) + if (!bc) { Terminal::Hooks::instance().openTerminalHook()({{}, currentNode->directory(), environment}); + return; + } IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(bc->target()->kit()); diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index f66e6a51715..260924a1b17 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -162,7 +162,7 @@ void TerminalPane::setFocus() bool TerminalPane::hasFocus() const { if (const auto t = currentTerminal()) - t->hasFocus(); + return t->hasFocus(); return false; } From 4c251486e1b4f3a4fb87b51b519ef1abc30de1eb Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 27 Feb 2023 11:11:02 +0100 Subject: [PATCH 0096/1447] Copilot: Various coverity warning fixes Change-Id: I5d86606611369f4bc11f9f21e308139bba700eb0 Reviewed-by: Eike Ziller --- src/plugins/copilot/copilotplugin.cpp | 10 ++++++++++ src/plugins/copilot/copilotplugin.h | 5 ++--- src/plugins/copilot/documentwatcher.cpp | 25 +++++++++++-------------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index ff2c449088f..910bfa33b7b 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -14,12 +14,22 @@ using namespace Utils; namespace Copilot { namespace Internal { +CopilotPlugin::~CopilotPlugin() +{ + if (m_client) + m_client->shutdown(); + + m_client = nullptr; +} + void CopilotPlugin::initialize() { CopilotSettings::instance().readSettings(Core::ICore::settings()); m_client = new CopilotClient(); + connect(m_client, &CopilotClient::finished, this, [this]() { m_client = nullptr; }); + connect(&CopilotSettings::instance(), &CopilotSettings::applied, this, [this]() { if (m_client) m_client->shutdown(); diff --git a/src/plugins/copilot/copilotplugin.h b/src/plugins/copilot/copilotplugin.h index 62f1d21f753..d81d2e86282 100644 --- a/src/plugins/copilot/copilotplugin.h +++ b/src/plugins/copilot/copilotplugin.h @@ -16,14 +16,13 @@ class CopilotPlugin : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Copilot.json") public: - CopilotPlugin() {} - ~CopilotPlugin() override {} + ~CopilotPlugin(); void initialize() override; void extensionsInitialized() override; private: - CopilotClient *m_client; + CopilotClient *m_client{nullptr}; }; } // namespace Internal diff --git a/src/plugins/copilot/documentwatcher.cpp b/src/plugins/copilot/documentwatcher.cpp index f216826b44e..a11ff8bbec3 100644 --- a/src/plugins/copilot/documentwatcher.cpp +++ b/src/plugins/copilot/documentwatcher.cpp @@ -37,12 +37,16 @@ DocumentWatcher::DocumentWatcher(CopilotClient *client, TextDocument *textDocume void DocumentWatcher::getSuggestion() { - auto editor = Core::EditorManager::instance()->activateEditorForDocument(m_textDocument); - auto textEditorWidget = qobject_cast(editor->widget()); - if (!editor || !textEditorWidget) + Core::IEditor *editor = Core::EditorManager::instance()->activateEditorForDocument( + m_textDocument); + if (!editor) + return; + TextEditor::TextEditorWidget *textEditorWidget = qobject_cast( + editor->widget()); + if (!textEditorWidget) return; - auto cursor = textEditorWidget->multiTextCursor(); + Utils::MultiTextCursor cursor = textEditorWidget->multiTextCursor(); if (cursor.hasMultipleCursors() || cursor.hasSelection()) return; @@ -61,31 +65,24 @@ void DocumentWatcher::getSuggestion() const std::optional result = response.result(); QTC_ASSERT(result, return); - const auto list = result->completions().toList(); + const QList list = result->completions().toList(); if (list.isEmpty()) return; - auto cursor = textEditorWidget->multiTextCursor(); + Utils::MultiTextCursor cursor = textEditorWidget->multiTextCursor(); if (cursor.hasMultipleCursors() || cursor.hasSelection()) return; if (cursor.cursors().first().position() != currentCursorPos) return; - const auto firstCompletion = list.first(); + const Completion firstCompletion = list.first(); const QString content = firstCompletion.text().mid( firstCompletion.position().character()); m_isEditing = true; textEditorWidget->insertSuggestion(content); m_isEditing = false; - /* - m_isEditing = true; - const auto &block = m_textDocument->document()->findBlockByLineNumber( - firstCompletion.position().line()); - m_textDocument->insertSuggestion(content, block); - m_isEditing = false; - */ }); } From d249e77f77128ec2d9eed03b4ca9f95e7b5f6d7c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 27 Feb 2023 12:46:00 +0100 Subject: [PATCH 0097/1447] DockerDevice: Fix compile warning Amends 682ef157d8561cb9648be8efcf45bdc8d0e47ea7 Change-Id: I2ee639aac5d6b2ba55e96d322a6d5818ca0d6735 Reviewed-by: Marcus Tillmanns --- src/plugins/docker/dockerdevice.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index d9ec143a9e3..a464c49abb4 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1237,6 +1237,7 @@ std::optional DockerDevice::clangdExecutable() const std::optional DockerDevice::terminalCommand(const FilePath &workDir, const Environment &env) const { + Q_UNUSED(env) const QString shell = d->environment().value_or("SHELL", "/bin/sh"); return d->withDockerExecCmd({FilePath::fromUserInput(shell), {}}, std::nullopt, From ea64bb9d361ff9f81dfdfc7430bcf2c13dac2c87 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 27 Feb 2023 13:15:15 +0100 Subject: [PATCH 0098/1447] Terminal: Fix scroll behavior Change-Id: I357a5d04baab881cf89c57fdf3336bd1e0077976 Reviewed-by: Burak Hancerli Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 64566acc1fc..5f6b8f079b0 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -776,10 +776,7 @@ int TerminalWidget::sb_clear() void TerminalWidget::wheelEvent(QWheelEvent *event) { - event->accept(); - - QPoint delta = event->angleDelta(); - scrollContentsBy(0, delta.y() / 24); + verticalScrollBar()->event(event); } void TerminalWidget::focusInEvent(QFocusEvent *) From 10a97e1f0e9f6ffab9fd2bc4c30a516bba807f68 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 22 Feb 2023 17:58:48 +0100 Subject: [PATCH 0099/1447] Various Tests: Use typed connections in QSignalSpy Change-Id: I0965916f5ce302e9bdcb47ae7126262327f63613 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/autotest/autotestunittests.cpp | 16 ++++---- .../clangtoolspreconfiguredsessiontests.cpp | 2 +- .../tests/qmlprofilerclientmanager_test.cpp | 40 +++++++++---------- .../pluginmanager/tst_pluginmanager.cpp | 6 +-- tests/auto/filesearch/tst_filesearch.cpp | 2 +- .../tst_timelineabstractrenderer.cpp | 10 ++--- .../timelinemodel/tst_timelinemodel.cpp | 36 +++++++++-------- .../tst_timelinemodelaggregator.cpp | 30 +++++++------- .../tst_timelinenotesmodel.cpp | 4 +- .../tst_timelinezoomcontrol.cpp | 29 +++++++------- 10 files changed, 90 insertions(+), 85 deletions(-) diff --git a/src/plugins/autotest/autotestunittests.cpp b/src/plugins/autotest/autotestunittests.cpp index e72cc0cbbb7..50d0b496c21 100644 --- a/src/plugins/autotest/autotestunittests.cpp +++ b/src/plugins/autotest/autotestunittests.cpp @@ -99,8 +99,8 @@ void AutoTestUnitTests::testCodeParser() CppEditor::Tests::ProjectOpenerAndCloser projectManager; QVERIFY(projectManager.open(projectFilePath, true, m_kit)); - QSignalSpy parserSpy(m_model->parser(), SIGNAL(parsingFinished())); - QSignalSpy modelUpdateSpy(m_model, SIGNAL(sweepingDone())); + QSignalSpy parserSpy(m_model->parser(), &TestCodeParser::parsingFinished); + QSignalSpy modelUpdateSpy(m_model, &TestTreeModel::sweepingDone); QVERIFY(parserSpy.wait(20000)); QVERIFY(modelUpdateSpy.wait()); @@ -149,8 +149,8 @@ void AutoTestUnitTests::testCodeParserSwitchStartup() qDebug() << "Opening project" << projectFilePaths.at(i); QVERIFY(projectManager.open(projectFilePaths.at(i), true, m_kit)); - QSignalSpy parserSpy(m_model->parser(), SIGNAL(parsingFinished())); - QSignalSpy modelUpdateSpy(m_model, SIGNAL(sweepingDone())); + QSignalSpy parserSpy(m_model->parser(), &TestCodeParser::parsingFinished); + QSignalSpy modelUpdateSpy(m_model, &TestTreeModel::sweepingDone); QVERIFY(parserSpy.wait(20000)); QVERIFY(modelUpdateSpy.wait()); @@ -199,8 +199,8 @@ void AutoTestUnitTests::testCodeParserGTest() CppEditor::Tests::ProjectOpenerAndCloser projectManager; QVERIFY(projectManager.open(projectFilePath, true, m_kit)); - QSignalSpy parserSpy(m_model->parser(), SIGNAL(parsingFinished())); - QSignalSpy modelUpdateSpy(m_model, SIGNAL(sweepingDone())); + QSignalSpy parserSpy(m_model->parser(), &TestCodeParser::parsingFinished); + QSignalSpy modelUpdateSpy(m_model, &TestTreeModel::sweepingDone); QVERIFY(parserSpy.wait(20000)); QVERIFY(modelUpdateSpy.wait()); @@ -250,8 +250,8 @@ void AutoTestUnitTests::testCodeParserBoostTest() = projectManager.open(projectFilePath, true, m_kit); QVERIFY(projectInfo); - QSignalSpy parserSpy(m_model->parser(), SIGNAL(parsingFinished())); - QSignalSpy modelUpdateSpy(m_model, SIGNAL(sweepingDone())); + QSignalSpy parserSpy(m_model->parser(), &TestCodeParser::parsingFinished); + QSignalSpy modelUpdateSpy(m_model, &TestTreeModel::sweepingDone); QVERIFY(parserSpy.wait(20000)); QVERIFY(modelUpdateSpy.wait()); diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index 5041dc4dacc..4b43fbc3e0d 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -102,7 +102,7 @@ void PreconfiguredSessionTests::testPreconfiguredSession() for (ClangTool * const tool : {ClangTidyTool::instance(), ClazyTool::instance()}) { tool->startTool(ClangTool::FileSelectionType::AllFiles); - QSignalSpy waitUntilAnalyzerFinished(tool, SIGNAL(finished(bool))); + QSignalSpy waitUntilAnalyzerFinished(tool, &ClangTool::finished); QVERIFY(waitUntilAnalyzerFinished.wait(30000)); const QList arguments = waitUntilAnalyzerFinished.takeFirst(); const bool analyzerFinishedSuccessfully = arguments.first().toBool(); diff --git a/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp b/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp index b14b4962e7f..366a6028bb4 100644 --- a/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp +++ b/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp @@ -105,9 +105,9 @@ void QmlProfilerClientManagerTest::testConnectionFailure() QFETCH(QmlProfilerStateManager *, stateManager); QFETCH(QUrl, serverUrl); - QSignalSpy openedSpy(&clientManager, SIGNAL(connectionOpened())); - QSignalSpy closedSpy(&clientManager, SIGNAL(connectionClosed())); - QSignalSpy failedSpy(&clientManager, SIGNAL(connectionFailed())); + QSignalSpy openedSpy(&clientManager, &QmlProfilerClientManager::connectionOpened); + QSignalSpy closedSpy(&clientManager, &QmlProfilerClientManager::connectionClosed); + QSignalSpy failedSpy(&clientManager, &QmlProfilerClientManager::connectionFailed); QVERIFY(!clientManager.isConnected()); @@ -137,9 +137,9 @@ void QmlProfilerClientManagerTest::testConnectionFailure() void QmlProfilerClientManagerTest::testUnresponsiveTcp() { - QSignalSpy openedSpy(&clientManager, SIGNAL(connectionOpened())); - QSignalSpy closedSpy(&clientManager, SIGNAL(connectionClosed())); - QSignalSpy failedSpy(&clientManager, SIGNAL(connectionFailed())); + QSignalSpy openedSpy(&clientManager, &QmlProfilerClientManager::connectionOpened); + QSignalSpy closedSpy(&clientManager, &QmlProfilerClientManager::connectionClosed); + QSignalSpy failedSpy(&clientManager, &QmlProfilerClientManager::connectionFailed); QVERIFY(!clientManager.isConnected()); @@ -150,7 +150,7 @@ void QmlProfilerClientManagerTest::testUnresponsiveTcp() QTcpServer server; server.listen(QHostAddress(serverUrl.host()), serverUrl.port()); - QSignalSpy connectionSpy(&server, SIGNAL(newConnection())); + QSignalSpy connectionSpy(&server, &QTcpServer::newConnection); clientManager.connectToServer(serverUrl); @@ -165,9 +165,9 @@ void QmlProfilerClientManagerTest::testUnresponsiveTcp() void QmlProfilerClientManagerTest::testUnresponsiveLocal() { - QSignalSpy openedSpy(&clientManager, SIGNAL(connectionOpened())); - QSignalSpy closedSpy(&clientManager, SIGNAL(connectionClosed())); - QSignalSpy failedSpy(&clientManager, SIGNAL(connectionFailed())); + QSignalSpy openedSpy(&clientManager, &QmlProfilerClientManager::connectionOpened); + QSignalSpy closedSpy(&clientManager, &QmlProfilerClientManager::connectionClosed); + QSignalSpy failedSpy(&clientManager, &QmlProfilerClientManager::connectionFailed); QVERIFY(!clientManager.isConnected()); @@ -176,7 +176,7 @@ void QmlProfilerClientManagerTest::testUnresponsiveLocal() QUrl socketUrl = Utils::urlFromLocalSocket(); QLocalSocket socket; - QSignalSpy connectionSpy(&socket, SIGNAL(connected())); + QSignalSpy connectionSpy(&socket, &QLocalSocket::connected); clientManager.connectToServer(socketUrl); @@ -209,8 +209,8 @@ void QmlProfilerClientManagerTest::testResponsiveTcp() QUrl serverUrl = Utils::urlFromLocalHostAndFreePort(); - QSignalSpy openedSpy(&clientManager, SIGNAL(connectionOpened())); - QSignalSpy closedSpy(&clientManager, SIGNAL(connectionClosed())); + QSignalSpy openedSpy(&clientManager, &QmlProfilerClientManager::connectionOpened); + QSignalSpy closedSpy(&clientManager, &QmlProfilerClientManager::connectionClosed); QVERIFY(!clientManager.isConnected()); @@ -267,8 +267,8 @@ void QmlProfilerClientManagerTest::testResponsiveLocal() QUrl socketUrl = Utils::urlFromLocalSocket(); - QSignalSpy openedSpy(&clientManager, SIGNAL(connectionOpened())); - QSignalSpy closedSpy(&clientManager, SIGNAL(connectionClosed())); + QSignalSpy openedSpy(&clientManager, &QmlProfilerClientManager::connectionOpened); + QSignalSpy closedSpy(&clientManager, &QmlProfilerClientManager::connectionClosed); QVERIFY(!clientManager.isConnected()); @@ -320,9 +320,9 @@ void QmlProfilerClientManagerTest::testInvalidData() MessageHandler handler(&invalidHelloMessageHandler); Q_UNUSED(handler) - QSignalSpy openedSpy(&clientManager, SIGNAL(connectionOpened())); - QSignalSpy closedSpy(&clientManager, SIGNAL(connectionClosed())); - QSignalSpy failedSpy(&clientManager, SIGNAL(connectionFailed())); + QSignalSpy openedSpy(&clientManager, &QmlProfilerClientManager::connectionOpened); + QSignalSpy closedSpy(&clientManager, &QmlProfilerClientManager::connectionClosed); + QSignalSpy failedSpy(&clientManager, &QmlProfilerClientManager::connectionFailed); QVERIFY(!clientManager.isConnected()); @@ -365,8 +365,8 @@ void QmlProfilerClientManagerTest::testStopRecording() QmlProfilerClientManager clientManager; clientManager.setRetryInterval(10); clientManager.setMaximumRetries(10); - QSignalSpy openedSpy(&clientManager, SIGNAL(connectionOpened())); - QSignalSpy closedSpy(&clientManager, SIGNAL(connectionClosed())); + QSignalSpy openedSpy(&clientManager, &QmlProfilerClientManager::connectionOpened); + QSignalSpy closedSpy(&clientManager, &QmlProfilerClientManager::connectionClosed); QVERIFY(!clientManager.isConnected()); diff --git a/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp b/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp index 96657471459..e57e71c533e 100644 --- a/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp +++ b/tests/auto/extensionsystem/pluginmanager/tst_pluginmanager.cpp @@ -57,9 +57,9 @@ void tst_PluginManager::init() m_pm = new PluginManager; PluginManager::setSettings(new Utils::QtcSettings); PluginManager::setPluginIID(QLatin1String("plugin")); - m_objectAdded = new QSignalSpy(m_pm, SIGNAL(objectAdded(QObject*))); - m_aboutToRemoveObject = new QSignalSpy(m_pm, SIGNAL(aboutToRemoveObject(QObject*))); - m_pluginsChanged = new QSignalSpy(m_pm, SIGNAL(pluginsChanged())); + m_objectAdded = new QSignalSpy(m_pm, &PluginManager::objectAdded); + m_aboutToRemoveObject = new QSignalSpy(m_pm, &PluginManager::aboutToRemoveObject); + m_pluginsChanged = new QSignalSpy(m_pm, &PluginManager::pluginsChanged); } void tst_PluginManager::cleanup() diff --git a/tests/auto/filesearch/tst_filesearch.cpp b/tests/auto/filesearch/tst_filesearch.cpp index 51f7d5a8bfe..d900175bf9d 100644 --- a/tests/auto/filesearch/tst_filesearch.cpp +++ b/tests/auto/filesearch/tst_filesearch.cpp @@ -36,7 +36,7 @@ namespace { QList() << QTextCodec::codecForLocale()); QFutureWatcher watcher; - QSignalSpy ready(&watcher, SIGNAL(resultsReadyAt(int,int))); + QSignalSpy ready(&watcher, &QFutureWatcherBase::resultsReadyAt); if (regexp == tst_FileSearch::NoRegExp) watcher.setFuture(Utils::findInFiles(term, it, flags)); else diff --git a/tests/auto/tracing/timelineabstractrenderer/tst_timelineabstractrenderer.cpp b/tests/auto/tracing/timelineabstractrenderer/tst_timelineabstractrenderer.cpp index 0da3dd1f6a7..66ec7f67098 100644 --- a/tests/auto/tracing/timelineabstractrenderer/tst_timelineabstractrenderer.cpp +++ b/tests/auto/tracing/timelineabstractrenderer/tst_timelineabstractrenderer.cpp @@ -36,7 +36,7 @@ void tst_TimelineAbstractRenderer::privateCtor() void tst_TimelineAbstractRenderer::selectionLocked() { TimelineAbstractRenderer renderer; - QSignalSpy spy(&renderer, SIGNAL(selectionLockedChanged(bool))); + QSignalSpy spy(&renderer, &TimelineAbstractRenderer::selectionLockedChanged); QCOMPARE(spy.count(), 0); QVERIFY(renderer.selectionLocked()); renderer.setSelectionLocked(false); @@ -50,7 +50,7 @@ void tst_TimelineAbstractRenderer::selectionLocked() void tst_TimelineAbstractRenderer::selectedItem() { TimelineAbstractRenderer renderer; - QSignalSpy spy(&renderer, SIGNAL(selectedItemChanged(int))); + QSignalSpy spy(&renderer, &TimelineAbstractRenderer::selectedItemChanged); QCOMPARE(spy.count(), 0); QCOMPARE(renderer.selectedItem(), -1); renderer.setSelectedItem(12); @@ -62,7 +62,7 @@ void tst_TimelineAbstractRenderer::model() { TimelineAbstractRenderer renderer; TimelineModelAggregator aggregator; - QSignalSpy spy(&renderer, SIGNAL(modelChanged(TimelineModel*))); + QSignalSpy spy(&renderer, &TimelineAbstractRenderer::modelChanged); QVERIFY(!renderer.modelDirty()); QCOMPARE(spy.count(), 0); TimelineModel model(&aggregator); @@ -80,7 +80,7 @@ void tst_TimelineAbstractRenderer::model() void tst_TimelineAbstractRenderer::notes() { TimelineAbstractRenderer renderer; - QSignalSpy spy(&renderer, SIGNAL(notesChanged(TimelineNotesModel*))); + QSignalSpy spy(&renderer, &TimelineAbstractRenderer::notesChanged); QVERIFY(!renderer.notesDirty()); QCOMPARE(spy.count(), 0); TimelineNotesModel notes; @@ -98,7 +98,7 @@ void tst_TimelineAbstractRenderer::notes() void tst_TimelineAbstractRenderer::zoomer() { TimelineAbstractRenderer renderer; - QSignalSpy spy(&renderer, SIGNAL(zoomerChanged(TimelineZoomControl*))); + QSignalSpy spy(&renderer, &TimelineAbstractRenderer::zoomerChanged); QCOMPARE(spy.count(), 0); TimelineZoomControl zoomer; QCOMPARE(renderer.zoomer(), static_cast(0)); diff --git a/tests/auto/tracing/timelinemodel/tst_timelinemodel.cpp b/tests/auto/tracing/timelinemodel/tst_timelinemodel.cpp index 27b457ce3fd..559b827de2e 100644 --- a/tests/auto/tracing/timelinemodel/tst_timelinemodel.cpp +++ b/tests/auto/tracing/timelinemodel/tst_timelinemodel.cpp @@ -6,17 +6,19 @@ #include #include +using namespace Timeline; + static const int NumItems = 32; static const qint64 ItemDuration = 1 << 19; static const qint64 ItemSpacing = 1 << 20; -class DummyModel : public Timeline::TimelineModel +class DummyModel : public TimelineModel { Q_OBJECT friend class tst_TimelineModel; public: - DummyModel(Timeline::TimelineModelAggregator *parent); - DummyModel(QString displayName, Timeline::TimelineModelAggregator *parent); + DummyModel(TimelineModelAggregator *parent); + DummyModel(QString displayName, TimelineModelAggregator *parent); int expandedRow(int) const { return 2; } int collapsedRow(int) const { return 1; } @@ -57,15 +59,15 @@ private slots: void parentingOfEqualStarts(); private: - Timeline::TimelineModelAggregator aggregator; + TimelineModelAggregator aggregator; }; -DummyModel::DummyModel(Timeline::TimelineModelAggregator *parent) : - Timeline::TimelineModel(parent) +DummyModel::DummyModel(TimelineModelAggregator *parent) : + TimelineModel(parent) { } -DummyModel::DummyModel(QString displayName, Timeline::TimelineModelAggregator *parent) : +DummyModel::DummyModel(QString displayName, TimelineModelAggregator *parent) : TimelineModel(parent) { setDisplayName(displayName); @@ -90,7 +92,7 @@ void DummyModel::loadData() } tst_TimelineModel::tst_TimelineModel() : - DefaultRowHeight(Timeline::TimelineModel::defaultRowHeight()) + DefaultRowHeight(TimelineModel::defaultRowHeight()) { } @@ -147,7 +149,7 @@ void tst_TimelineModel::rowHeight() QCOMPARE(dummy.rowHeight(0), 100); QCOMPARE(dummy.rowHeight(1), 50); - QSignalSpy expandedSpy(&dummy, SIGNAL(expandedRowHeightChanged(int,int))); + QSignalSpy expandedSpy(&dummy, &TimelineModel::expandedRowHeightChanged); dummy.clear(); QCOMPARE(expandedSpy.count(), 1); } @@ -194,7 +196,7 @@ void tst_TimelineModel::height() DummyModel dummy(&aggregator); int heightAfterLastSignal = 0; int heightChangedSignals = 0; - connect(&dummy, &Timeline::TimelineModel::heightChanged, [&](){ + connect(&dummy, &TimelineModel::heightChanged, [&] { ++heightChangedSignals; heightAfterLastSignal = dummy.height(); }); @@ -237,7 +239,7 @@ void tst_TimelineModel::count() QCOMPARE(dummy.count(), 0); dummy.loadData(); QCOMPARE(dummy.count(), NumItems); - QSignalSpy emptySpy(&dummy, SIGNAL(contentChanged())); + QSignalSpy emptySpy(&dummy, &TimelineModel::contentChanged); dummy.clear(); QCOMPARE(emptySpy.count(), 1); QCOMPARE(dummy.count(), 0); @@ -283,7 +285,7 @@ void tst_TimelineModel::firstLast() void tst_TimelineModel::expand() { DummyModel dummy(&aggregator); - QSignalSpy spy(&dummy, SIGNAL(expandedChanged())); + QSignalSpy spy(&dummy, &TimelineModel::expandedChanged); QVERIFY(!dummy.expanded()); dummy.setExpanded(true); QVERIFY(dummy.expanded()); @@ -302,7 +304,7 @@ void tst_TimelineModel::expand() void tst_TimelineModel::hide() { DummyModel dummy(&aggregator); - QSignalSpy spy(&dummy, SIGNAL(hiddenChanged())); + QSignalSpy spy(&dummy, &TimelineModel::hiddenChanged); QVERIFY(!dummy.hidden()); dummy.setHidden(true); QVERIFY(dummy.hidden()); @@ -322,7 +324,7 @@ void tst_TimelineModel::displayName() { QLatin1String name("testest"); DummyModel dummy(name, &aggregator); - QSignalSpy spy(&dummy, SIGNAL(displayNameChanged())); + QSignalSpy spy(&dummy, &TimelineModel::displayNameChanged); QCOMPARE(dummy.displayName(), name); QCOMPARE(spy.count(), 0); dummy.setDisplayName(name); @@ -336,7 +338,7 @@ void tst_TimelineModel::displayName() void tst_TimelineModel::defaultValues() { - Timeline::TimelineModel dummy(&aggregator); + TimelineModel dummy(&aggregator); QCOMPARE(dummy.location(0), QVariantMap()); QCOMPARE(dummy.handlesTypeId(0), false); QCOMPARE(dummy.relativeHeight(0), 1.0); @@ -361,7 +363,7 @@ void tst_TimelineModel::row() void tst_TimelineModel::colorByHue() { - Timeline::TimelineModelAggregator aggregator; + TimelineModelAggregator aggregator; DummyModel dummy(&aggregator); QCOMPARE(dummy.colorByHue(10), QColor::fromHsl(10, 150, 166).rgb()); QCOMPARE(dummy.colorByHue(500), QColor::fromHsl(140, 150, 166).rgb()); @@ -410,7 +412,7 @@ void tst_TimelineModel::insertStartEnd() void tst_TimelineModel::rowCount() { DummyModel dummy(&aggregator); - QSignalSpy contentSpy(&dummy, SIGNAL(contentChanged())); + QSignalSpy contentSpy(&dummy, &TimelineModel::contentChanged); QCOMPARE(dummy.rowCount(), 1); dummy.setExpanded(true); QCOMPARE(dummy.rowCount(), 1); diff --git a/tests/auto/tracing/timelinemodelaggregator/tst_timelinemodelaggregator.cpp b/tests/auto/tracing/timelinemodelaggregator/tst_timelinemodelaggregator.cpp index 77c9c155e58..ac30ff0ad32 100644 --- a/tests/auto/tracing/timelinemodelaggregator/tst_timelinemodelaggregator.cpp +++ b/tests/auto/tracing/timelinemodelaggregator/tst_timelinemodelaggregator.cpp @@ -4,6 +4,8 @@ #include #include +using namespace Timeline; + class tst_TimelineModelAggregator : public QObject { Q_OBJECT @@ -14,9 +16,9 @@ private slots: void prevNext(); }; -class HeightTestModel : public Timeline::TimelineModel { +class HeightTestModel : public TimelineModel { public: - HeightTestModel(Timeline::TimelineModelAggregator *parent) : TimelineModel(parent) + HeightTestModel(TimelineModelAggregator *parent) : TimelineModel(parent) { insert(0, 1, 1); } @@ -24,11 +26,11 @@ public: void tst_TimelineModelAggregator::height() { - Timeline::TimelineModelAggregator aggregator; + TimelineModelAggregator aggregator; QCOMPARE(aggregator.height(), 0); - QSignalSpy heightSpy(&aggregator, SIGNAL(heightChanged())); - Timeline::TimelineModel *model = new Timeline::TimelineModel(&aggregator); + QSignalSpy heightSpy(&aggregator, &TimelineModelAggregator::heightChanged); + TimelineModel *model = new TimelineModel(&aggregator); aggregator.addModel(model); QCOMPARE(aggregator.height(), 0); QCOMPARE(heightSpy.count(), 0); @@ -42,15 +44,15 @@ void tst_TimelineModelAggregator::height() void tst_TimelineModelAggregator::addRemoveModel() { - Timeline::TimelineNotesModel notes; - Timeline::TimelineModelAggregator aggregator; + TimelineNotesModel notes; + TimelineModelAggregator aggregator; aggregator.setNotes(¬es); - QSignalSpy spy(&aggregator, SIGNAL(modelsChanged())); + QSignalSpy spy(&aggregator, &TimelineModelAggregator::modelsChanged); QCOMPARE(aggregator.notes(), ¬es); - Timeline::TimelineModel *model1 = new Timeline::TimelineModel(&aggregator); - Timeline::TimelineModel *model2 = new Timeline::TimelineModel(&aggregator); + TimelineModel *model1 = new TimelineModel(&aggregator); + TimelineModel *model2 = new TimelineModel(&aggregator); aggregator.addModel(model1); QCOMPARE(spy.count(), 1); QCOMPARE(aggregator.modelCount(), 1); @@ -75,10 +77,10 @@ void tst_TimelineModelAggregator::addRemoveModel() QCOMPARE(aggregator.modelCount(), 0); } -class PrevNextTestModel : public Timeline::TimelineModel +class PrevNextTestModel : public TimelineModel { public: - PrevNextTestModel(Timeline::TimelineModelAggregator *parent) : TimelineModel(parent) + PrevNextTestModel(TimelineModelAggregator *parent) : TimelineModel(parent) { for (int i = 0; i < 20; ++i) insert(i + modelId(), i * modelId(), modelId()); @@ -87,14 +89,14 @@ public: void tst_TimelineModelAggregator::prevNext() { - Timeline::TimelineModelAggregator aggregator; + TimelineModelAggregator aggregator; aggregator.generateModelId(); // start modelIds at 1 aggregator.addModel(new PrevNextTestModel(&aggregator)); aggregator.addModel(new PrevNextTestModel(&aggregator)); aggregator.addModel(new PrevNextTestModel(&aggregator)); // Add an empty model to trigger the special code paths that skip it - aggregator.addModel(new Timeline::TimelineModel(&aggregator)); + aggregator.addModel(new TimelineModel(&aggregator)); QLatin1String item("item"); QLatin1String model("model"); QVariantMap result; diff --git a/tests/auto/tracing/timelinenotesmodel/tst_timelinenotesmodel.cpp b/tests/auto/tracing/timelinenotesmodel/tst_timelinenotesmodel.cpp index d01db8f12e6..d00ba47154e 100644 --- a/tests/auto/tracing/timelinenotesmodel/tst_timelinenotesmodel.cpp +++ b/tests/auto/tracing/timelinenotesmodel/tst_timelinenotesmodel.cpp @@ -63,7 +63,7 @@ void tst_TimelineNotesModel::addRemove() TestModel model(&aggregator); notes.addTimelineModel(&model); - QSignalSpy spy(¬es, SIGNAL(changed(int,int,int))); + QSignalSpy spy(¬es, &TestNotesModel::changed); int id = notes.add(model.modelId(), 0, QLatin1String("xyz")); QCOMPARE(spy.count(), 1); QCOMPARE(notes.isModified(), true); @@ -129,7 +129,7 @@ void tst_TimelineNotesModel::modify() TestNotesModel notes; TestModel model(&aggregator); notes.addTimelineModel(&model); - QSignalSpy spy(¬es, SIGNAL(changed(int,int,int))); + QSignalSpy spy(¬es, &TestNotesModel::changed); int id = notes.add(model.modelId(), 0, QLatin1String("a")); QCOMPARE(spy.count(), 1); notes.resetModified(); diff --git a/tests/auto/tracing/timelinezoomcontrol/tst_timelinezoomcontrol.cpp b/tests/auto/tracing/timelinezoomcontrol/tst_timelinezoomcontrol.cpp index 4e00fc26d5d..3e1c936c0d5 100644 --- a/tests/auto/tracing/timelinezoomcontrol/tst_timelinezoomcontrol.cpp +++ b/tests/auto/tracing/timelinezoomcontrol/tst_timelinezoomcontrol.cpp @@ -5,11 +5,13 @@ #include #include +using namespace Timeline; + class tst_TimelineZoomControl : public QObject { Q_OBJECT private: - void verifyWindow(const Timeline::TimelineZoomControl &zoomControl); + void verifyWindow(const TimelineZoomControl &zoomControl); private slots: void trace(); @@ -18,7 +20,7 @@ private slots: void selection(); }; -void tst_TimelineZoomControl::verifyWindow(const Timeline::TimelineZoomControl &zoomControl) +void tst_TimelineZoomControl::verifyWindow(const TimelineZoomControl &zoomControl) { QVERIFY(zoomControl.windowStart() <= zoomControl.rangeStart()); QVERIFY(zoomControl.windowEnd() >= zoomControl.rangeEnd()); @@ -28,8 +30,8 @@ void tst_TimelineZoomControl::verifyWindow(const Timeline::TimelineZoomControl & void tst_TimelineZoomControl::trace() { - Timeline::TimelineZoomControl zoomControl; - QSignalSpy spy(&zoomControl, SIGNAL(traceChanged(qint64,qint64))); + TimelineZoomControl zoomControl; + QSignalSpy spy(&zoomControl, &TimelineZoomControl::traceChanged); QCOMPARE(zoomControl.traceStart(), -1); QCOMPARE(zoomControl.traceEnd(), -1); QCOMPARE(zoomControl.traceDuration(), 0); @@ -49,18 +51,18 @@ void tst_TimelineZoomControl::trace() void tst_TimelineZoomControl::window() { - Timeline::TimelineZoomControl zoomControl; + TimelineZoomControl zoomControl; QTimer timer; timer.setSingleShot(true); - connect(&timer, &QTimer::timeout, [&](){ + connect(&timer, &QTimer::timeout, [&] { QVERIFY(zoomControl.windowLocked()); zoomControl.setWindowLocked(false); }); int numWindowChanges = 0; - connect(&zoomControl, &Timeline::TimelineZoomControl::windowChanged, + connect(&zoomControl, &TimelineZoomControl::windowChanged, [&](qint64, qint64) { verifyWindow(zoomControl); @@ -98,8 +100,7 @@ void tst_TimelineZoomControl::window() zoomControl.setRange(152000, 152005); // move right QMetaObject::Connection connection = connect( - &zoomControl, &Timeline::TimelineZoomControl::windowMovingChanged, - [&](bool moving) { + &zoomControl, &TimelineZoomControl::windowMovingChanged, [&](bool moving) { if (moving) return; @@ -129,7 +130,7 @@ void tst_TimelineZoomControl::window() disconnect(connection); bool stopDetected = false; - connect(&zoomControl, &Timeline::TimelineZoomControl::windowMovingChanged, [&](bool moving) { + connect(&zoomControl, &TimelineZoomControl::windowMovingChanged, [&](bool moving) { if (!moving) { QCOMPARE(stopDetected, false); stopDetected = true; @@ -148,8 +149,8 @@ void tst_TimelineZoomControl::window() void tst_TimelineZoomControl::range() { - Timeline::TimelineZoomControl zoomControl; - QSignalSpy spy(&zoomControl, SIGNAL(rangeChanged(qint64,qint64))); + TimelineZoomControl zoomControl; + QSignalSpy spy(&zoomControl, &TimelineZoomControl::rangeChanged); QCOMPARE(zoomControl.rangeStart(), -1); QCOMPARE(zoomControl.rangeEnd(), -1); QCOMPARE(zoomControl.rangeDuration(), 0); @@ -175,8 +176,8 @@ void tst_TimelineZoomControl::range() void tst_TimelineZoomControl::selection() { - Timeline::TimelineZoomControl zoomControl; - QSignalSpy spy(&zoomControl, SIGNAL(selectionChanged(qint64,qint64))); + TimelineZoomControl zoomControl; + QSignalSpy spy(&zoomControl, &TimelineZoomControl::selectionChanged); QCOMPARE(zoomControl.selectionStart(), -1); QCOMPARE(zoomControl.selectionEnd(), -1); QCOMPARE(zoomControl.selectionDuration(), 0); From 8285c857251977a8ff6c9b44bbeac794ff1dfa2e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Feb 2023 01:31:47 +0100 Subject: [PATCH 0100/1447] Autotest: Use QPromise for async calls Change-Id: I57d2feed36eeb1871b2b00cf7720c48f6a0e81b5 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot Reviewed-by: --- .../autotest/boost/boosttestparser.cpp | 4 ++-- src/plugins/autotest/boost/boosttestparser.h | 2 +- .../autotest/catch/catchtestparser.cpp | 4 ++-- src/plugins/autotest/catch/catchtestparser.h | 2 +- src/plugins/autotest/gtest/gtestparser.cpp | 4 ++-- src/plugins/autotest/gtest/gtestparser.h | 2 +- src/plugins/autotest/itestparser.h | 6 +++--- src/plugins/autotest/qtest/qttestparser.cpp | 4 ++-- src/plugins/autotest/qtest/qttestparser.h | 2 +- .../autotest/quick/quicktestparser.cpp | 21 ++++++++----------- src/plugins/autotest/quick/quicktestparser.h | 4 ++-- src/plugins/autotest/testcodeparser.cpp | 8 +++---- 12 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestparser.cpp b/src/plugins/autotest/boost/boosttestparser.cpp index bbf6dfd56ce..74c463244b9 100644 --- a/src/plugins/autotest/boost/boosttestparser.cpp +++ b/src/plugins/autotest/boost/boosttestparser.cpp @@ -96,7 +96,7 @@ static BoostTestParseResult *createParseResult(const QString &name, const FilePa } -bool BoostTestParser::processDocument(QFutureInterface &futureInterface, +bool BoostTestParser::processDocument(QPromise &promise, const FilePath &fileName) { CPlusPlus::Document::Ptr doc = document(fileName); @@ -148,7 +148,7 @@ bool BoostTestParser::processDocument(QFutureInterface &futu locationAndType.m_type, tmpInfo); currentSuite->children.append(funcResult); - futureInterface.reportResult(TestParseResultPtr(topLevelSuite)); + promise.addResult(TestParseResultPtr(topLevelSuite)); } } return true; diff --git a/src/plugins/autotest/boost/boosttestparser.h b/src/plugins/autotest/boost/boosttestparser.h index 049f42d0c93..3ea67815c95 100644 --- a/src/plugins/autotest/boost/boosttestparser.h +++ b/src/plugins/autotest/boost/boosttestparser.h @@ -22,7 +22,7 @@ class BoostTestParser : public CppParser { public: explicit BoostTestParser(ITestFramework *framework) : CppParser(framework) {} - bool processDocument(QFutureInterface &futureInterface, + bool processDocument(QPromise &promise, const Utils::FilePath &fileName) override; }; diff --git a/src/plugins/autotest/catch/catchtestparser.cpp b/src/plugins/autotest/catch/catchtestparser.cpp index dd01c01c90b..9198e41342b 100644 --- a/src/plugins/autotest/catch/catchtestparser.cpp +++ b/src/plugins/autotest/catch/catchtestparser.cpp @@ -91,7 +91,7 @@ static bool hasCatchNames(const CPlusPlus::Document::Ptr &document) return false; } -bool CatchTestParser::processDocument(QFutureInterface &futureInterface, +bool CatchTestParser::processDocument(QPromise &promise, const FilePath &fileName) { CPlusPlus::Document::Ptr doc = document(fileName); @@ -144,7 +144,7 @@ bool CatchTestParser::processDocument(QFutureInterface &futu parseResult->children.append(testCase); } - futureInterface.reportResult(TestParseResultPtr(parseResult)); + promise.addResult(TestParseResultPtr(parseResult)); return !foundTests.isEmpty(); } diff --git a/src/plugins/autotest/catch/catchtestparser.h b/src/plugins/autotest/catch/catchtestparser.h index 6159ff58133..8b72073204b 100644 --- a/src/plugins/autotest/catch/catchtestparser.h +++ b/src/plugins/autotest/catch/catchtestparser.h @@ -23,7 +23,7 @@ class CatchTestParser : public CppParser public: CatchTestParser(ITestFramework *framework) : CppParser(framework) {} - bool processDocument(QFutureInterface &futureInterface, + bool processDocument(QPromise &promise, const Utils::FilePath &fileName) override; }; diff --git a/src/plugins/autotest/gtest/gtestparser.cpp b/src/plugins/autotest/gtest/gtestparser.cpp index aa59bb94c2e..7e3f987905b 100644 --- a/src/plugins/autotest/gtest/gtestparser.cpp +++ b/src/plugins/autotest/gtest/gtestparser.cpp @@ -70,7 +70,7 @@ static bool hasGTestNames(const CPlusPlus::Document::Ptr &document) return false; } -bool GTestParser::processDocument(QFutureInterface &futureInterface, +bool GTestParser::processDocument(QPromise &promise, const FilePath &fileName) { CPlusPlus::Document::Ptr doc = document(fileName); @@ -124,7 +124,7 @@ bool GTestParser::processDocument(QFutureInterface &futureIn parseResult->children.append(testSet); } - futureInterface.reportResult(TestParseResultPtr(parseResult)); + promise.addResult(TestParseResultPtr(parseResult)); } return !result.isEmpty(); } diff --git a/src/plugins/autotest/gtest/gtestparser.h b/src/plugins/autotest/gtest/gtestparser.h index 665a8a496c2..52febe6b890 100644 --- a/src/plugins/autotest/gtest/gtestparser.h +++ b/src/plugins/autotest/gtest/gtestparser.h @@ -22,7 +22,7 @@ class GTestParser : public CppParser { public: explicit GTestParser(ITestFramework *framework) : CppParser(framework) {} - bool processDocument(QFutureInterface &futureInterface, + bool processDocument(QPromise &futureInterface, const Utils::FilePath &fileName) override; }; diff --git a/src/plugins/autotest/itestparser.h b/src/plugins/autotest/itestparser.h index 7e16a61b90d..24b132c610c 100644 --- a/src/plugins/autotest/itestparser.h +++ b/src/plugins/autotest/itestparser.h @@ -9,9 +9,9 @@ #include #include -#include - QT_BEGIN_NAMESPACE +template +class QPromise; class QRegularExpression; QT_END_NAMESPACE @@ -46,7 +46,7 @@ public: explicit ITestParser(ITestFramework *framework) : m_framework(framework) {} virtual ~ITestParser() { } virtual void init(const Utils::FilePaths &filesToParse, bool fullParse) = 0; - virtual bool processDocument(QFutureInterface &futureInterface, + virtual bool processDocument(QPromise &futureInterface, const Utils::FilePath &fileName) = 0; virtual QStringList supportedExtensions() const { return {}; } diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp index 2b13133f03f..ece94f82474 100644 --- a/src/plugins/autotest/qtest/qttestparser.cpp +++ b/src/plugins/autotest/qtest/qttestparser.cpp @@ -292,7 +292,7 @@ static bool isQObject(const CPlusPlus::Document::Ptr &declaringDoc) || file.endsWith("QtCore/qobject.h") || file.endsWith("kernel/qobject.h"); } -bool QtTestParser::processDocument(QFutureInterface &futureInterface, +bool QtTestParser::processDocument(QPromise &promise, const FilePath &fileName) { CPlusPlus::Document::Ptr doc = document(fileName); @@ -325,7 +325,7 @@ bool QtTestParser::processDocument(QFutureInterface &futureI data.multipleTestCases = testCase.multipleTestCases; QtTestParseResult *parseResult = createParseResult(testCase.name, data, projectParts.first()->projectFile); - futureInterface.reportResult(TestParseResultPtr(parseResult)); + promise.addResult(TestParseResultPtr(parseResult)); reported = true; } } diff --git a/src/plugins/autotest/qtest/qttestparser.h b/src/plugins/autotest/qtest/qttestparser.h index db677929ec8..9dafcdc77e1 100644 --- a/src/plugins/autotest/qtest/qttestparser.h +++ b/src/plugins/autotest/qtest/qttestparser.h @@ -36,7 +36,7 @@ public: void init(const Utils::FilePaths &filesToParse, bool fullParse) override; void release() override; - bool processDocument(QFutureInterface &futureInterface, + bool processDocument(QPromise &promise, const Utils::FilePath &fileName) override; private: diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index 2c72cdf3f1a..f5b79d8075c 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -196,7 +196,7 @@ QList QuickTestParser::scanDirectoryForQuickTestQmlFiles(const Fi return foundDocs; } -static bool checkQmlDocumentForQuickTestCode(QFutureInterface &futureInterface, +static bool checkQmlDocumentForQuickTestCode(QPromise &promise, const Document::Ptr &qmlJSDoc, ITestFramework *framework, const FilePath &proFile = {}, @@ -240,12 +240,12 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterfacechildren.append(funcResult); } - futureInterface.reportResult(TestParseResultPtr(parseResult)); + promise.addResult(TestParseResultPtr(parseResult)); } return true; } -bool QuickTestParser::handleQtQuickTest(QFutureInterface &futureInterface, +bool QuickTestParser::handleQtQuickTest(QPromise &promise, CPlusPlus::Document::Ptr document, ITestFramework *framework) { @@ -263,17 +263,14 @@ bool QuickTestParser::handleQtQuickTest(QFutureInterface &fu if (srcDir.isEmpty()) return false; - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return false; const QList qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir); bool result = false; for (const Document::Ptr &qmlJSDoc : qmlDocs) { - if (futureInterface.isCanceled()) + if (promise.isCanceled()) break; - result |= checkQmlDocumentForQuickTestCode(futureInterface, - qmlJSDoc, - framework, - proFile, + result |= checkQmlDocumentForQuickTestCode(promise, qmlJSDoc, framework, proFile, m_checkForDerivedTests); } return result; @@ -370,7 +367,7 @@ void QuickTestParser::release() CppParser::release(); } -bool QuickTestParser::processDocument(QFutureInterface &futureInterface, +bool QuickTestParser::processDocument(QPromise &promise, const FilePath &fileName) { if (fileName.endsWith(".qml")) { @@ -378,7 +375,7 @@ bool QuickTestParser::processDocument(QFutureInterface &futu if (proFile.isEmpty()) return false; Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName); - return checkQmlDocumentForQuickTestCode(futureInterface, + return checkQmlDocumentForQuickTestCode(promise, qmlJSDoc, framework(), proFile, @@ -389,7 +386,7 @@ bool QuickTestParser::processDocument(QFutureInterface &futu if (cppdoc.isNull() || !includesQtQuickTest(cppdoc, m_cppSnapshot)) return false; - return handleQtQuickTest(futureInterface, cppdoc, framework()); + return handleQtQuickTest(promise, cppdoc, framework()); } FilePath QuickTestParser::projectFileForMainCppFile(const FilePath &fileName) const diff --git a/src/plugins/autotest/quick/quicktestparser.h b/src/plugins/autotest/quick/quicktestparser.h index c0fbc5a3e83..bf3727feca3 100644 --- a/src/plugins/autotest/quick/quicktestparser.h +++ b/src/plugins/autotest/quick/quicktestparser.h @@ -26,13 +26,13 @@ public: explicit QuickTestParser(ITestFramework *framework); void init(const Utils::FilePaths &filesToParse, bool fullParse) override; void release() override; - bool processDocument(QFutureInterface &futureInterface, + bool processDocument(QPromise &promise, const Utils::FilePath &fileName) override; Utils::FilePath projectFileForMainCppFile(const Utils::FilePath &fileName) const; QStringList supportedExtensions() const override { return {"qml"}; }; private: - bool handleQtQuickTest(QFutureInterface &futureInterface, + bool handleQtQuickTest(QPromise &promise, CPlusPlus::Document::Ptr document, ITestFramework *framework); void handleDirectoryChanged(const QString &directory); diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 69e90e9ac97..a42f3aa77d4 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -254,13 +254,13 @@ bool TestCodeParser::postponed(const FilePaths &fileList) QTC_ASSERT(false, return false); // should not happen at all } -static void parseFileForTests(QFutureInterface &futureInterface, +static void parseFileForTests(QPromise &promise, const QList &parsers, const FilePath &fileName) { for (ITestParser *parser : parsers) { - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; - if (parser->processDocument(futureInterface, fileName)) + if (parser->processDocument(promise, fileName)) break; } } @@ -359,7 +359,7 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList tasks{parallel}; // TODO: use ParallelLimit(N) and add to settings? for (const FilePath &file : filteredList) { const auto setup = [this, codeParsers, file](AsyncTask &async) { - async.setAsyncCallData(parseFileForTests, codeParsers, file); + async.setConcurrentCallData(parseFileForTests, codeParsers, file); async.setThreadPool(m_threadPool); async.setPriority(QThread::LowestPriority); async.setFutureSynchronizer(&m_futureSynchronizer); From 11ecf3c86b7f0264b7bbbcbf9003707ecf56cde6 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 27 Feb 2023 20:52:41 +0100 Subject: [PATCH 0101/1447] Nim: Center the settingscategory icon Was off-by-one towards the left. Change-Id: Ib17ddf750729fad102065776603c4a12b5d7431f Reviewed-by: Alessandro Portale --- src/plugins/nim/images/settingscategory_nim.png | Bin 245 -> 245 bytes .../nim/images/settingscategory_nim@2x.png | Bin 511 -> 511 bytes src/tools/icons/qtcreatoricons.svg | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/nim/images/settingscategory_nim.png b/src/plugins/nim/images/settingscategory_nim.png index 016c570eb4929657a77882d1b19d154bc342de86..bee1123cff8a3f16382d60ed4f2c00f798fc4a06 100644 GIT binary patch delta 76 zcmey$_?2;jA!Fo3BPXWFUlYq*t&Z$Jy6eB|w+GuZmUdp>U$@sTQ1h2`RD`T&$kRtb izBWbyg06E|7}$N@%lf4x&SGF-VDNPHb6Mw<&;$TE i)#M~sbSMQeG3@AiFZ*rT$4&+Y1_n=8KbLh*2~7Y?3L%yN diff --git a/src/plugins/nim/images/settingscategory_nim@2x.png b/src/plugins/nim/images/settingscategory_nim@2x.png index 4fb9c101887058e14cda2b5219cb20b16ddbed9f..2cbe6cfdc1ba416148cb829eee56236cc9d55754 100644 GIT binary patch delta 297 zcmey*{GWM(G2@H~5u~98r=xQ1Ot5!(KU);n%FE8ZDLHOi#EvqXVQPCj9AHGMR@_ zuim51%}=U}r=5GIgg{@TMNi|(FB;8C*S3Tln(*O&Qk#|fo!t)Wi&v$`{h5CtpeyvS zt=Tj08%vEed3Ey4K8=oUll|=e{QCOvq^IM767k>j91M$3 z^m9%uo$-fHI8e`aj(E1l>7%OIBIf@eW)#}5YAlmtXyV>8mAk1xpMima!PC{xWt~$( F69Dr^g!KRb delta 297 zcmey*{GWM(G2@(xCT&6Y_Rn6U@MyMyi47}fvEQ$DxsLy8g-t2*lG-MzFf(7z%Q38; zFul={%X`Bw0|S=>N90^OI$doVJ|2>s@R#R0!xz)jfgGQwv78VU+P=VS!-5}@>n8Is z>eXx1xvB8FwjFNu;o&&$Aam?MNYxZa!R#olM2{c!hR$<^-^DJtZh6&M|DS(?#?e&| z<)lBW<{Yf*ocY%7+m%_z7kuUo{u?gaW+QX*_inl7!|6O<^LV1-3!k=2PvQ|P54d`N zTf&4rjn>R}rzAhftZ03(KkGr-gx#I`{`>nGmmOH(=BX}U_xIO_CrcC(c6HbKFPLHZ znJVl!^D_ej1B0ilpUXO@ GgeCx!Qi%Tm diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 8e6a6baa2d9..979e8cff985 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -2965,7 +2965,7 @@ Date: Mon, 27 Feb 2023 16:07:34 +0100 Subject: [PATCH 0102/1447] Terminal: Settings/options icon Change-Id: I35729d46fc8013e7af8ba262842a32b61936ad63 Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/CMakeLists.txt | 1 + .../images/settingscategory_terminal.png | Bin 0 -> 164 bytes .../images/settingscategory_terminal@2x.png | Bin 0 -> 193 bytes src/plugins/terminal/terminal.qbs | 1 + src/plugins/terminal/terminal.qrc | 6 +++++ src/plugins/terminal/terminalsettingspage.cpp | 4 +-- src/tools/icons/qtcreatoricons.svg | 23 ++++++++++++++++++ 7 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/plugins/terminal/images/settingscategory_terminal.png create mode 100644 src/plugins/terminal/images/settingscategory_terminal@2x.png create mode 100644 src/plugins/terminal/terminal.qrc diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index 8303fdc1770..a970b467e19 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(Terminal DEPENDS libvterm ptyqt SOURCES celllayout.cpp celllayout.h + terminal.qrc terminalplugin.cpp terminalplugin.h terminaltr.h terminalpane.cpp terminalpane.h diff --git a/src/plugins/terminal/images/settingscategory_terminal.png b/src/plugins/terminal/images/settingscategory_terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..6e8c7167787b7c0c097dd0329c404d5abd75e422 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|7G?$p2BAoW(+ms@Dgizrt_%zeqN1W=Vq&JI zrd?fKd-v|$zkmOsLx&C@KK%Lf=Rbe`{Qv)-x9;6X1_lOePZ!4!iK)pqdRZh+JT`D( zoN;)sl+GT;GY^fN9~GFpDi?0^P%7+NRQNJ-ZzJQuo4q>DGVDilMShDgGTdq0b-HJ< Sv^WC;1B0ilpUXO@geCwiwmek; literal 0 HcmV?d00001 diff --git a/src/plugins/terminal/images/settingscategory_terminal@2x.png b/src/plugins/terminal/images/settingscategory_terminal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..71e292d8bc163b2e3e47c6cfc3a873ed047baf14 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-7G?$phNU`BwlFX-s08?gxH2#>XlQ8Y=;-L` z>ekoScXV_-d-m-4^XD&LzI^rS)t4_{{{R2Kz3K6C1_p)*PZ!4!i_^(BdYKJ+I5^o% z99me+f)$SF#R&D?yrEjAnepI);Y>s6-ADYG4c`duo;_oi=j0oi3Vo+PWeLrdj_9@a wSkT!1PRmBf!p35WiicmgvN``G6-I{e+poJmS$+#(U|?YIboFyt=akR{0IK>(&;S4c literal 0 HcmV?d00001 diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 54743641107..eb72c89494e 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -14,6 +14,7 @@ QtcPlugin { "keys.h", "scrollback.cpp", "scrollback.h", + "terminal.qrc", "terminalpane.cpp", "terminalpane.h", "terminalplugin.cpp", diff --git a/src/plugins/terminal/terminal.qrc b/src/plugins/terminal/terminal.qrc new file mode 100644 index 00000000000..a4fece92fce --- /dev/null +++ b/src/plugins/terminal/terminal.qrc @@ -0,0 +1,6 @@ + + + images/settingscategory_terminal.png + images/settingscategory_terminal@2x.png + + diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index f48360b0be0..f3986878380 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -24,9 +24,7 @@ TerminalSettingsPage::TerminalSettingsPage() setCategory("ZY.Terminal"); setDisplayCategory("Terminal"); setSettings(&TerminalSettings::instance()); - - // TODO: Add real icon! - setCategoryIconPath(":/texteditor/images/settingscategory_texteditor.png"); + setCategoryIconPath(":/terminal/images/settingscategory_terminal.png"); } void TerminalSettingsPage::init() {} diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 979e8cff985..83ba7039a09 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -3147,6 +3147,29 @@ d="m 1078,478.85469 1.189,13.30208 m -4.1861,-1.62746 L 1086.5,495 m -17,0 9.272,-7.52758" sodipodi:nodetypes="cccccc" /> + + + + + From 61de69ea907bfd5e7d0b6eb97975194352c9c5f3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 9 Feb 2023 15:11:14 +0100 Subject: [PATCH 0103/1447] CPlusPlus: Handle C++20 concepts in parser Change-Id: I8c6b8b1ba3f36b83cd1d667bec9830271147b1ac Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.cpp | 30 +++ src/libs/3rdparty/cplusplus/AST.h | 93 ++++++++++ src/libs/3rdparty/cplusplus/ASTClone.cpp | 54 ++++++ src/libs/3rdparty/cplusplus/ASTMatch0.cpp | 30 +++ src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 66 +++++++ src/libs/3rdparty/cplusplus/ASTMatcher.h | 4 + src/libs/3rdparty/cplusplus/ASTVisit.cpp | 34 ++++ src/libs/3rdparty/cplusplus/ASTVisitor.h | 8 + src/libs/3rdparty/cplusplus/ASTfwd.h | 4 + src/libs/3rdparty/cplusplus/Bind.cpp | 5 + src/libs/3rdparty/cplusplus/Bind.h | 1 + src/libs/3rdparty/cplusplus/Parser.cpp | 185 ++++++++++++++++++- src/libs/3rdparty/cplusplus/Parser.h | 5 + src/plugins/cppeditor/cppcompletion_test.cpp | 4 + tests/auto/cplusplus/cxx11/tst_cxx11.cpp | 25 +++ 15 files changed, 547 insertions(+), 1 deletion(-) diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 5d7c9e2a90c..260b3582713 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -4634,3 +4634,33 @@ int NoExceptOperatorExpressionAST::lastToken() const return noexcept_token + 1; return 1; } + +int TypeConstraintAST::firstToken() const +{ + if (nestedName) + return nestedName->firstToken(); + return conceptName->firstToken(); +} + +int TypeConstraintAST::lastToken() const +{ + if (greaterToken) + return greaterToken + 1; + return conceptName->lastToken(); +} + +int PlaceholderTypeSpecifierAST::firstToken() const +{ + if (typeConstraint) + return typeConstraint->firstToken(); + if (declTypetoken) + return declTypetoken; + return autoToken; +} + +int PlaceholderTypeSpecifierAST::lastToken() const +{ + if (rparenToken) + return rparenToken + 1; + return autoToken + 1; +} diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 9aa81ccdf66..9288725edd3 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -290,6 +290,7 @@ public: virtual OperatorFunctionIdAST *asOperatorFunctionId() { return nullptr; } virtual ParameterDeclarationAST *asParameterDeclaration() { return nullptr; } virtual ParameterDeclarationClauseAST *asParameterDeclarationClause() { return nullptr; } + virtual PlaceholderTypeSpecifierAST *asPlaceholderTypeSpecifier() { return nullptr; } virtual PointerAST *asPointer() { return nullptr; } virtual PointerLiteralAST *asPointerLiteral() { return nullptr; } virtual PointerToMemberAST *asPointerToMember() { return nullptr; } @@ -322,6 +323,7 @@ public: virtual StringLiteralAST *asStringLiteral() { return nullptr; } virtual SwitchStatementAST *asSwitchStatement() { return nullptr; } virtual TemplateDeclarationAST *asTemplateDeclaration() { return nullptr; } + virtual ConceptDeclarationAST *asConceptDeclaration() { return nullptr; } virtual TemplateIdAST *asTemplateId() { return nullptr; } virtual TemplateTypeParameterAST *asTemplateTypeParameter() { return nullptr; } virtual ThisExpressionAST *asThisExpression() { return nullptr; } @@ -329,6 +331,7 @@ public: virtual TrailingReturnTypeAST *asTrailingReturnType() { return nullptr; } virtual TranslationUnitAST *asTranslationUnit() { return nullptr; } virtual TryBlockStatementAST *asTryBlockStatement() { return nullptr; } + virtual TypeConstraintAST *asTypeConstraint() { return nullptr; } virtual TypeConstructorCallAST *asTypeConstructorCall() { return nullptr; } virtual TypeIdAST *asTypeId() { return nullptr; } virtual TypeidExpressionAST *asTypeidExpression() { return nullptr; } @@ -336,6 +339,7 @@ public: virtual TypenameTypeParameterAST *asTypenameTypeParameter() { return nullptr; } virtual TypeofSpecifierAST *asTypeofSpecifier() { return nullptr; } virtual UnaryExpressionAST *asUnaryExpression() { return nullptr; } + virtual RequiresExpressionAST *asRequiresExpression() { return nullptr; } virtual UsingAST *asUsing() { return nullptr; } virtual UsingDirectiveAST *asUsingDirective() { return nullptr; } virtual WhileStatementAST *asWhileStatement() { return nullptr; } @@ -636,6 +640,49 @@ protected: bool match0(AST *, ASTMatcher *) override; }; +class CPLUSPLUS_EXPORT TypeConstraintAST: public AST +{ +public: + NestedNameSpecifierListAST *nestedName = nullptr; + NameAST *conceptName = nullptr; + int lessToken = 0; + ExpressionListAST *templateArgs = nullptr; + int greaterToken = 0; + + TypeConstraintAST *asTypeConstraint() override { return this; } + + int firstToken() const override; + int lastToken() const override; + + TypeConstraintAST *clone(MemoryPool *pool) const override; + + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + +class CPLUSPLUS_EXPORT PlaceholderTypeSpecifierAST: public SpecifierAST +{ +public: + TypeConstraintAST *typeConstraint = nullptr; + int declTypetoken = 0; + int lparenToken = 0; + int decltypeToken = 0; + int autoToken = 0; + int rparenToken = 0; + +public: + PlaceholderTypeSpecifierAST *asPlaceholderTypeSpecifier() override { return this; } + + int firstToken() const override; + int lastToken() const override; + + PlaceholderTypeSpecifierAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + class CPLUSPLUS_EXPORT DeclaratorAST: public AST { public: @@ -2734,6 +2781,29 @@ protected: bool match0(AST *, ASTMatcher *) override; }; +class CPLUSPLUS_EXPORT ConceptDeclarationAST: public DeclarationAST +{ +public: + int concept_token = 0; + NameAST *name = nullptr; + SpecifierListAST *attributes = nullptr; + int equals_token = 0; + ExpressionAST *constraint = nullptr; + int semicolon_token = 0; + +public: + ConceptDeclarationAST *asConceptDeclaration() override { return this; } + + int firstToken() const override { return concept_token; } + int lastToken() const override { return semicolon_token + 1; } + + ConceptDeclarationAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + class CPLUSPLUS_EXPORT ThrowExpressionAST: public ExpressionAST { public: @@ -2927,6 +2997,29 @@ protected: bool match0(AST *, ASTMatcher *) override; }; +class CPLUSPLUS_EXPORT RequiresExpressionAST: public ExpressionAST +{ +public: + int requires_token = 0; + int lparen_token = 0; + ParameterDeclarationClauseAST *parameters = nullptr; + int rparen_token = 0; + int lbrace_token = 0; + int rbrace_token = 0; + +public: + RequiresExpressionAST *asRequiresExpression() override { return this; } + + int firstToken() const override { return requires_token; } + int lastToken() const override { return rbrace_token + 1; } + + RequiresExpressionAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + class CPLUSPLUS_EXPORT UsingAST: public DeclarationAST { public: diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 9e5a773bdb6..4e4cda40f9f 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -141,6 +141,32 @@ DecltypeSpecifierAST *DecltypeSpecifierAST::clone(MemoryPool *pool) const return ast; } +TypeConstraintAST *TypeConstraintAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) TypeConstraintAST; + for (NestedNameSpecifierListAST *iter = nestedName, **ast_iter = &ast->nestedName; iter; + iter = iter->next, ast_iter = &(*ast_iter)->next) + *ast_iter = new (pool) NestedNameSpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); + ast->lessToken = lessToken; + for (ExpressionListAST *iter = templateArgs, **ast_iter = &ast->templateArgs; + iter; iter = iter->next, ast_iter = &(*ast_iter)->next) + *ast_iter = new (pool) ExpressionListAST((iter->value) ? iter->value->clone(pool) : nullptr); + ast->greaterToken = greaterToken; + return ast; +} + +PlaceholderTypeSpecifierAST *PlaceholderTypeSpecifierAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) PlaceholderTypeSpecifierAST; + if (typeConstraint) + ast->typeConstraint = typeConstraint->clone(pool); + ast->lparenToken = lparenToken; + ast->declTypetoken = declTypetoken; + ast->autoToken = autoToken; + ast->rparenToken = rparenToken; + return ast; +} + DeclaratorAST *DeclaratorAST::clone(MemoryPool *pool) const { DeclaratorAST *ast = new (pool) DeclaratorAST; @@ -1284,6 +1310,34 @@ TemplateDeclarationAST *TemplateDeclarationAST::clone(MemoryPool *pool) const return ast; } +ConceptDeclarationAST *ConceptDeclarationAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) ConceptDeclarationAST; + ast->concept_token = concept_token; + ast->name = name->clone(pool); + ast->equals_token = equals_token; + ast->semicolon_token = semicolon_token; + for (SpecifierListAST *iter = attributes, **ast_iter = &ast->attributes; + iter; iter = iter->next, ast_iter = &(*ast_iter)->next) { + *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); + } + ast->constraint = constraint->clone(pool); + return ast; +} + +RequiresExpressionAST *RequiresExpressionAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) RequiresExpressionAST; + ast->requires_token = requires_token; + ast->lparen_token = lparen_token; + if (parameters) + ast->parameters = parameters->clone(pool); + ast->rparen_token = rparen_token; + ast->lbrace_token = lbrace_token; + ast->rbrace_token = rbrace_token; + return ast; +} + ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const { ThrowExpressionAST *ast = new (pool) ThrowExpressionAST; diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index 4105ec3c52e..afe94aba06f 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -112,6 +112,21 @@ bool DecltypeSpecifierAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool TypeConstraintAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto _other = pattern->asTypeConstraint()) + return matcher->match(this, _other); + + return false; +} + +bool PlaceholderTypeSpecifierAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto _other = pattern->asPlaceholderTypeSpecifier()) + return matcher->match(this, _other); + return false; +} + bool DeclaratorAST::match0(AST *pattern, ASTMatcher *matcher) { if (DeclaratorAST *_other = pattern->asDeclarator()) @@ -896,6 +911,21 @@ bool TemplateDeclarationAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool ConceptDeclarationAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (ConceptDeclarationAST *_other = pattern->asConceptDeclaration()) + return matcher->match(this, _other); + + return false; +} + +bool RequiresExpressionAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto other = pattern->asRequiresExpression()) + return matcher->match(this, other); + return false; +} + bool ThrowExpressionAST::match0(AST *pattern, ASTMatcher *matcher) { if (ThrowExpressionAST *_other = pattern->asThrowExpression()) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index fcfe86ab571..ccf41dbae2f 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -216,6 +216,25 @@ bool ASTMatcher::match(DecltypeSpecifierAST *node, DecltypeSpecifierAST *pattern return true; } +bool ASTMatcher::match(TypeConstraintAST *node, TypeConstraintAST *pattern) +{ + if (!pattern->nestedName) + pattern->nestedName = node->nestedName; + else if (!AST::match(node->nestedName, pattern->nestedName, this)) + return false; + if (!pattern->conceptName) + pattern->conceptName = node->conceptName; + else if (!AST::match(node->conceptName, pattern->conceptName, this)) + return false; + pattern->lessToken = node->lessToken; + if (!pattern->templateArgs) + pattern->templateArgs = node->templateArgs; + else if (!AST::match(node->templateArgs, pattern->templateArgs, this)) + return false; + pattern->greaterToken = node->greaterToken; + return true; +} + bool ASTMatcher::match(DeclaratorAST *node, DeclaratorAST *pattern) { (void) node; @@ -1749,6 +1768,19 @@ bool ASTMatcher::match(ParameterDeclarationClauseAST *node, ParameterDeclaration return true; } +bool ASTMatcher::match(PlaceholderTypeSpecifierAST *node, PlaceholderTypeSpecifierAST *pattern) +{ + if (!pattern->typeConstraint) + pattern->typeConstraint = node->typeConstraint; + else if (!AST::match(node->typeConstraint, pattern->typeConstraint, this)) + return false; + pattern->declTypetoken = node->declTypetoken; + pattern->lparenToken = node->lparenToken; + pattern->autoToken = node->autoToken; + pattern->rparenToken = node->rparenToken; + return true; +} + bool ASTMatcher::match(CallAST *node, CallAST *pattern) { (void) node; @@ -2181,6 +2213,40 @@ bool ASTMatcher::match(TemplateDeclarationAST *node, TemplateDeclarationAST *pat return true; } +bool ASTMatcher::match(ConceptDeclarationAST *node, ConceptDeclarationAST *pattern) +{ + pattern->concept_token = node->concept_token; + pattern->equals_token = node->equals_token; + pattern->semicolon_token = node->semicolon_token; + + if (!pattern->attributes) + pattern->attributes = node->attributes; + else if (!AST::match(node->attributes, pattern->attributes, this)) + return false; + + if (!pattern->constraint) + pattern->constraint = node->constraint; + else if (! AST::match(node->constraint, pattern->constraint, this)) + return false; + + return true; +} + +bool ASTMatcher::match(RequiresExpressionAST *node, RequiresExpressionAST *pattern) +{ + pattern->requires_token = node->requires_token; + pattern->lparen_token = node->lparen_token; + pattern->lbrace_token = node->lbrace_token; + pattern->rbrace_token = node->rbrace_token; + + if (!pattern->parameters) + pattern->parameters = node->parameters; + else if (!AST::match(node->parameters, pattern->parameters, this)) + return false; + + return true; +} + bool ASTMatcher::match(ThrowExpressionAST *node, ThrowExpressionAST *pattern) { (void) node; diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index c243e18b7bb..214c37a283b 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -54,6 +54,7 @@ public: virtual bool match(CompoundExpressionAST *node, CompoundExpressionAST *pattern); virtual bool match(CompoundLiteralAST *node, CompoundLiteralAST *pattern); virtual bool match(CompoundStatementAST *node, CompoundStatementAST *pattern); + virtual bool match(ConceptDeclarationAST *node, ConceptDeclarationAST *pattern); virtual bool match(ConditionAST *node, ConditionAST *pattern); virtual bool match(ConditionalExpressionAST *node, ConditionalExpressionAST *pattern); virtual bool match(ContinueStatementAST *node, ContinueStatementAST *pattern); @@ -139,6 +140,7 @@ public: virtual bool match(OperatorFunctionIdAST *node, OperatorFunctionIdAST *pattern); virtual bool match(ParameterDeclarationAST *node, ParameterDeclarationAST *pattern); virtual bool match(ParameterDeclarationClauseAST *node, ParameterDeclarationClauseAST *pattern); + virtual bool match(PlaceholderTypeSpecifierAST *node, PlaceholderTypeSpecifierAST *pattern); virtual bool match(PointerAST *node, PointerAST *pattern); virtual bool match(PointerLiteralAST *node, PointerLiteralAST *pattern); virtual bool match(PointerToMemberAST *node, PointerToMemberAST *pattern); @@ -156,6 +158,7 @@ public: virtual bool match(QualifiedNameAST *node, QualifiedNameAST *pattern); virtual bool match(RangeBasedForStatementAST *node, RangeBasedForStatementAST *pattern); virtual bool match(ReferenceAST *node, ReferenceAST *pattern); + virtual bool match(RequiresExpressionAST *node, RequiresExpressionAST *pattern); virtual bool match(ReturnStatementAST *node, ReturnStatementAST *pattern); virtual bool match(SimpleDeclarationAST *node, SimpleDeclarationAST *pattern); virtual bool match(SimpleNameAST *node, SimpleNameAST *pattern); @@ -173,6 +176,7 @@ public: virtual bool match(TrailingReturnTypeAST *node, TrailingReturnTypeAST *pattern); virtual bool match(TranslationUnitAST *node, TranslationUnitAST *pattern); virtual bool match(TryBlockStatementAST *node, TryBlockStatementAST *pattern); + virtual bool match(TypeConstraintAST *node, TypeConstraintAST *pattern); virtual bool match(TypeConstructorCallAST *node, TypeConstructorCallAST *pattern); virtual bool match(TypeIdAST *node, TypeIdAST *pattern); virtual bool match(TypeidExpressionAST *node, TypeidExpressionAST *pattern); diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 2248f51a501..cb05dbde62b 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -110,6 +110,23 @@ void DecltypeSpecifierAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void TypeConstraintAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) { + accept(nestedName, visitor); + accept(conceptName, visitor); + accept(templateArgs, visitor); + } + visitor->endVisit(this); +} + +void PlaceholderTypeSpecifierAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) + accept(typeConstraint, visitor); + visitor->endVisit(this); +} + void DeclaratorAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { @@ -946,6 +963,23 @@ void TemplateDeclarationAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void ConceptDeclarationAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) { + accept(name, visitor); + accept(attributes, visitor); + accept(constraint, visitor); + } + visitor->endVisit(this); +} + +void RequiresExpressionAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) + accept(parameters, visitor); + visitor->endVisit(this); +} + void ThrowExpressionAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index 691b57e9ac5..455936f9842 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -96,6 +96,7 @@ public: virtual bool visit(CompoundExpressionAST *) { return true; } virtual bool visit(CompoundLiteralAST *) { return true; } virtual bool visit(CompoundStatementAST *) { return true; } + virtual bool visit(ConceptDeclarationAST *) { return true; } virtual bool visit(ConditionAST *) { return true; } virtual bool visit(ConditionalExpressionAST *) { return true; } virtual bool visit(ContinueStatementAST *) { return true; } @@ -181,6 +182,7 @@ public: virtual bool visit(OperatorFunctionIdAST *) { return true; } virtual bool visit(ParameterDeclarationAST *) { return true; } virtual bool visit(ParameterDeclarationClauseAST *) { return true; } + virtual bool visit(PlaceholderTypeSpecifierAST *) { return true; } virtual bool visit(PointerAST *) { return true; } virtual bool visit(PointerLiteralAST *) { return true; } virtual bool visit(PointerToMemberAST *) { return true; } @@ -198,6 +200,7 @@ public: virtual bool visit(QualifiedNameAST *) { return true; } virtual bool visit(RangeBasedForStatementAST *) { return true; } virtual bool visit(ReferenceAST *) { return true; } + virtual bool visit(RequiresExpressionAST *) { return true; } virtual bool visit(ReturnStatementAST *) { return true; } virtual bool visit(SimpleDeclarationAST *) { return true; } virtual bool visit(SimpleNameAST *) { return true; } @@ -215,6 +218,7 @@ public: virtual bool visit(TrailingReturnTypeAST *) { return true; } virtual bool visit(TranslationUnitAST *) { return true; } virtual bool visit(TryBlockStatementAST *) { return true; } + virtual bool visit(TypeConstraintAST *) { return true; } virtual bool visit(TypeConstructorCallAST *) { return true; } virtual bool visit(TypeIdAST *) { return true; } virtual bool visit(TypeidExpressionAST *) { return true; } @@ -250,6 +254,7 @@ public: virtual void endVisit(CompoundExpressionAST *) {} virtual void endVisit(CompoundLiteralAST *) {} virtual void endVisit(CompoundStatementAST *) {} + virtual void endVisit(ConceptDeclarationAST *) {} virtual void endVisit(ConditionAST *) {} virtual void endVisit(ConditionalExpressionAST *) {} virtual void endVisit(ContinueStatementAST *) {} @@ -335,6 +340,7 @@ public: virtual void endVisit(OperatorFunctionIdAST *) {} virtual void endVisit(ParameterDeclarationAST *) {} virtual void endVisit(ParameterDeclarationClauseAST *) {} + virtual void endVisit(PlaceholderTypeSpecifierAST *) {} virtual void endVisit(PointerAST *) {} virtual void endVisit(PointerLiteralAST *) {} virtual void endVisit(PointerToMemberAST *) {} @@ -352,6 +358,7 @@ public: virtual void endVisit(QualifiedNameAST *) {} virtual void endVisit(RangeBasedForStatementAST *) {} virtual void endVisit(ReferenceAST *) {} + virtual void endVisit(RequiresExpressionAST *) {} virtual void endVisit(ReturnStatementAST *) {} virtual void endVisit(SimpleDeclarationAST *) {} virtual void endVisit(SimpleNameAST *) {} @@ -369,6 +376,7 @@ public: virtual void endVisit(TrailingReturnTypeAST *) {} virtual void endVisit(TranslationUnitAST *) {} virtual void endVisit(TryBlockStatementAST *) {} + virtual void endVisit(TypeConstraintAST *) {} virtual void endVisit(TypeConstructorCallAST *) {} virtual void endVisit(TypeIdAST *) {} virtual void endVisit(TypeidExpressionAST *) {} diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index 4b31aaf5902..f0899b2e1c8 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -146,6 +146,7 @@ class OperatorAST; class OperatorFunctionIdAST; class ParameterDeclarationAST; class ParameterDeclarationClauseAST; +class PlaceholderTypeSpecifierAST; class PointerAST; class PointerLiteralAST; class PointerToMemberAST; @@ -166,6 +167,7 @@ class QtPropertyDeclarationItemAST; class QualifiedNameAST; class RangeBasedForStatementAST; class ReferenceAST; +class RequiresExpressionAST; class ReturnStatementAST; class SimpleDeclarationAST; class SimpleNameAST; @@ -178,6 +180,7 @@ class StdAttributeSpecifierAST; class StringLiteralAST; class SwitchStatementAST; class TemplateDeclarationAST; +class ConceptDeclarationAST; class TemplateIdAST; class TemplateTypeParameterAST; class ThisExpressionAST; @@ -185,6 +188,7 @@ class ThrowExpressionAST; class TrailingReturnTypeAST; class TranslationUnitAST; class TryBlockStatementAST; +class TypeConstraintAST; class TypeConstructorCallAST; class TypeIdAST; class TypeidExpressionAST; diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 7f10c79428c..6293d732e05 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -933,6 +933,11 @@ bool Bind::visit(ParameterDeclarationClauseAST *ast) return false; } +bool Bind::visit(RequiresExpressionAST *) +{ + return false; +} + void Bind::parameterDeclarationClause(ParameterDeclarationClauseAST *ast, int lparen_token, Function *fun) { if (! ast) diff --git a/src/libs/3rdparty/cplusplus/Bind.h b/src/libs/3rdparty/cplusplus/Bind.h index 3947e57026d..4d12beee86d 100644 --- a/src/libs/3rdparty/cplusplus/Bind.h +++ b/src/libs/3rdparty/cplusplus/Bind.h @@ -128,6 +128,7 @@ protected: bool visit(NewTypeIdAST *ast) override; bool visit(OperatorAST *ast) override; bool visit(ParameterDeclarationClauseAST *ast) override; + bool visit(RequiresExpressionAST *ast) override; bool visit(TranslationUnitAST *ast) override; bool visit(ObjCProtocolRefsAST *ast) override; bool visit(ObjCMessageArgumentAST *ast) override; diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index cb7bfa3a1b6..ed023b15f03 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -1255,6 +1255,8 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) ast->declaration = nullptr; if (parseDeclaration(ast->declaration)) break; + if (parseConceptDeclaration(ast->declaration)) + break; error(start_declaration, "expected a declaration"); rewind(start_declaration + 1); @@ -1265,6 +1267,173 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) return true; } +bool Parser::parseConceptDeclaration(DeclarationAST *&node) +{ + if (!_languageFeatures.cxx20Enabled) + return false; + if (LA() != T_CONCEPT) + return false; + + const auto ast = new (_pool) ConceptDeclarationAST; + ast->concept_token = consumeToken(); + if (!parseName(ast->name)) + return false; + parseAttributeSpecifier(ast->attributes); + if (LA() != T_EQUAL) + return false; + ast->equals_token = consumeToken(); + if (!parseLogicalOrExpression(ast->constraint)) + return false; + if (LA() != T_SEMICOLON) + return false; + ast->semicolon_token = consumeToken(); + node = ast; + return true; +} + +bool Parser::parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node) +{ + if ((lookAtBuiltinTypeSpecifier() || _translationUnit->tokenAt(_tokenIndex).isKeyword()) + && (LA() != T_AUTO && LA() != T_DECLTYPE)) { + return false; + } + + TypeConstraintAST *typeConstraint = nullptr; + const int savedCursor = cursor(); + parseTypeConstraint(typeConstraint); + if (LA() != T_AUTO && (LA() != T_DECLTYPE || LA(1) != T_LPAREN || LA(2) != T_AUTO)) { + rewind(savedCursor); + return false; + } + const auto spec = new (_pool) PlaceholderTypeSpecifierAST; + spec->typeConstraint = typeConstraint; + if (LA() == T_DECLTYPE) { + spec->declTypetoken = consumeToken(); + if (LA() != T_LPAREN) + return false; + spec->lparenToken = consumeToken(); + if (LA() != T_AUTO) + return false; + spec->autoToken = consumeToken(); + if (LA() != T_RPAREN) + return false; + spec->rparenToken = consumeToken(); + } else { + spec->autoToken = consumeToken(); + } + node = spec; + return true; +} + +bool Parser::parseTypeConstraint(TypeConstraintAST *&node) +{ + NestedNameSpecifierListAST *nestedName = nullptr; + parseNestedNameSpecifierOpt(nestedName, true); + NameAST *conceptName = nullptr; + if (!parseUnqualifiedName(conceptName, true)) + return false; + const auto typeConstraint = new (_pool) TypeConstraintAST; + typeConstraint->nestedName = nestedName; + typeConstraint->conceptName = conceptName; + if (LA() != T_LESS) + return true; + typeConstraint->lessToken = consumeToken(); + if (LA() != T_GREATER) { + if (!parseTemplateArgumentList(typeConstraint->templateArgs)) + return false; + } + if (LA() != T_GREATER) + return false; + typeConstraint->greaterToken = consumeToken(); + node = typeConstraint; + return true; +} + +bool Parser::parseRequirement() +{ + if (LA() == T_TYPENAME) { // type-requirement + consumeToken(); + NameAST *name = nullptr; + if (!parseName(name, true)) + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; + } + if (LA() == T_LBRACE) { // compound-requirement + consumeToken(); + ExpressionAST *expr = nullptr; + if (!parseExpression(expr)) + return false; + if (LA() != T_RBRACE) + return false; + consumeToken(); + if (LA() == T_NOEXCEPT) + consumeToken(); + if (LA() == T_SEMICOLON) { + consumeToken(); + return true; + } + TypeConstraintAST *typeConstraint = nullptr; + if (!parseTypeConstraint(typeConstraint)) + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; + } + if (LA() == T_REQUIRES) { // nested-requirement + consumeToken(); + ExpressionAST *constraintExpr = nullptr; + if (!parseLogicalOrExpression(constraintExpr)) + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; + } + ExpressionAST *simpleExpr; + if (!parseExpression(simpleExpr)) // simple-requirement + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; +} + +bool Parser::parseRequiresExpression(ExpressionAST *&node) +{ + if (!_languageFeatures.cxx20Enabled) + return false; + if (LA() != T_REQUIRES) + return false; + + const auto ast = new (_pool) RequiresExpressionAST; + ast->requires_token = consumeToken(); + if (LA() == T_LPAREN) { + ast->lparen_token = consumeToken(); + if (!parseParameterDeclarationClause(ast->parameters)) + return false; + if (LA() != T_RPAREN) + return false; + ast->rparen_token = consumeToken(); + } + if (LA() != T_LBRACE) + return false; + ast->lbrace_token = consumeToken(); + if (!parseRequirement()) + return false; + while (LA() != T_RBRACE) { + if (!parseRequirement()) + return false; + } + ast->rbrace_token = consumeToken(); + + node = ast; + return true; +} + bool Parser::parseOperator(OperatorAST *&node) // ### FIXME { DEBUG_THIS_RULE(); @@ -1500,6 +1669,14 @@ bool Parser::parseDeclSpecifierSeq(SpecifierListAST *&decl_specifier_seq, NameAST *named_type_specifier = nullptr; SpecifierListAST **decl_specifier_seq_ptr = &decl_specifier_seq; for (;;) { + PlaceholderTypeSpecifierAST *placeholderSpec = nullptr; + // A simple auto is also technically a placeholder-type-specifier, but for historical + // reasons, it is handled further below. + if (LA() != T_AUTO && parsePlaceholderTypeSpecifier(placeholderSpec)) { + *decl_specifier_seq_ptr = new (_pool) SpecifierListAST(placeholderSpec); + decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next; + continue; + } if (! noStorageSpecifiers && ! onlySimpleTypeSpecifiers && lookAtStorageClassSpecifier()) { // storage-class-specifier SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST; @@ -1550,8 +1727,9 @@ bool Parser::parseDeclSpecifierSeq(SpecifierListAST *&decl_specifier_seq, } decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next; has_type_specifier = true; - } else + } else { break; + } } return decl_specifier_seq != nullptr; @@ -1694,6 +1872,8 @@ bool Parser::hasAuto(SpecifierListAST *decl_specifier_list) const if (_translationUnit->tokenKind(simpleSpec->specifier_token) == T_AUTO) return true; } + if (spec->asPlaceholderTypeSpecifier()) + return true; } return false; } @@ -4731,6 +4911,9 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node) case T_AT_SELECTOR: return parseObjCExpression(node); + case T_REQUIRES: + return parseRequiresExpression(node); + default: { NameAST *name = nullptr; if (parseNameId(name)) { diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index ba101ccd46e..dbbb5630971 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -143,6 +143,11 @@ public: bool parseTemplateArgument(ExpressionAST *&node); bool parseTemplateArgumentList(ExpressionListAST *&node); bool parseTemplateDeclaration(DeclarationAST *&node); + bool parseConceptDeclaration(DeclarationAST *&node); + bool parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node); + bool parseTypeConstraint(TypeConstraintAST *&node); + bool parseRequirement(); + bool parseRequiresExpression(ExpressionAST *&node); bool parseTemplateParameter(DeclarationAST *&node); bool parseTemplateParameterList(DeclarationListAST *&node); bool parseThrowExpression(ExpressionAST *&node); diff --git a/src/plugins/cppeditor/cppcompletion_test.cpp b/src/plugins/cppeditor/cppcompletion_test.cpp index 56e4987af6a..1e212dde609 100644 --- a/src/plugins/cppeditor/cppcompletion_test.cpp +++ b/src/plugins/cppeditor/cppcompletion_test.cpp @@ -70,6 +70,10 @@ public: // Get Document const Document::Ptr document = waitForFileInGlobalSnapshot(filePath); QVERIFY(document); + if (!document->diagnosticMessages().isEmpty()) { + for (const Document::DiagnosticMessage &m : document->diagnosticMessages()) + qDebug().noquote() << m.text(); + } QVERIFY(document->diagnosticMessages().isEmpty()); m_snapshot.insert(document); diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index 0dc6484ff44..f626c402230 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -145,6 +145,8 @@ private Q_SLOTS: void lambdaType_data(); void lambdaType(); + + void concepts(); }; @@ -293,5 +295,28 @@ void tst_cxx11::lambdaType() QCOMPARE(oo.prettyType(function->type()), expectedType); } +void tst_cxx11::concepts() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx20Enabled = true; + + const QString source = R"( +template concept IsPointer = requires(T p) { *p; }; +template void* func(T p) { return p; } +void *func2(IsPointer auto p) +{ + return p; +} +)"; + QByteArray errors; + Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile")); + processDocument(doc, source.toUtf8(), features, &errors); + const bool hasErrors = !errors.isEmpty(); + if (hasErrors) + qDebug() << errors; + QVERIFY(!hasErrors); +} + QTEST_APPLESS_MAIN(tst_cxx11) #include "tst_cxx11.moc" From 29f634a8caf69a374edb00df7a19146352a14d6f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 20 Feb 2023 21:32:00 +0100 Subject: [PATCH 0104/1447] TaskTree: Introduce WaitFor, Condition and ConditionActivator WaitFor(condition) Group element enables postponing Group's children execution until the condition is met. Use ConditionActivator::activate() method to signal that the condition is met. A call to ConditionActivator::activate() schedules a request to the TaskTree instructing it to resume execution of awaiting condition. The Group containing the WaitFor element is started itself, and its setup handler is being called. If setup handler returned TaskAction::Continue, the children execution is being postponed. Otherwise, when StopWithDone or StopWithError is returned, the Group finishes and WaitFor element is no-op in this context. This functionality is going to be used when some part of the task tree may continue only after some data has been collected, and data collection took place not from inside start or done handlers. The example is running debugger for already started process - the debugger may run after the process already started, delivered its PID and it's still running. In this way we may start a debugger process in parallel in right point of time. This patch implements the 5th point inside QTCREATORBUG-28741. Task-number: QTCREATORBUG-28741 Change-Id: I4afaedb0b34fe0383c16a6d1f74bf07f74cc088a Reviewed-by: Christian Kandeler Reviewed-by: hjk Reviewed-by: --- src/libs/utils/tasktree.cpp | 514 +++++++++++++++------ src/libs/utils/tasktree.h | 63 ++- tests/auto/utils/tasktree/tst_tasktree.cpp | 81 +++- 3 files changed, 482 insertions(+), 176 deletions(-) diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 90e4073e033..8ea51369322 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -74,6 +74,54 @@ void TreeStorageBase::activateStorage(int id) const m_storageData->m_activeStorage = id; } +Condition::Condition() + : m_conditionData(new ConditionData()) {} + +Condition::ConditionData::~ConditionData() +{ + QTC_CHECK(m_activatorHash.isEmpty()); + qDeleteAll(m_activatorHash); +} + +ConditionActivator *Condition::activator() const +{ + QTC_ASSERT(m_conditionData->m_activeActivator, return nullptr); + const auto it = m_conditionData->m_activatorHash.constFind(m_conditionData->m_activeActivator); + QTC_ASSERT(it != m_conditionData->m_activatorHash.constEnd(), return nullptr); + return it.value(); +} + +int Condition::createActivator(TaskNode *node) const +{ + QTC_ASSERT(m_conditionData->m_activeActivator == 0, return 0); // TODO: should be allowed? + const int newId = ++m_conditionData->m_activatorCounter; + m_conditionData->m_activatorHash.insert(newId, new ConditionActivator(node)); + return newId; +} + +void Condition::deleteActivator(int id) const +{ + QTC_ASSERT(m_conditionData->m_activeActivator == 0, return); // TODO: should be allowed? + const auto it = m_conditionData->m_activatorHash.constFind(id); + QTC_ASSERT(it != m_conditionData->m_activatorHash.constEnd(), return); + delete it.value(); + m_conditionData->m_activatorHash.erase(it); +} + +// passing 0 deactivates currently active condition +void Condition::activateActivator(int id) const +{ + if (id == 0) { + QTC_ASSERT(m_conditionData->m_activeActivator, return); + m_conditionData->m_activeActivator = 0; + return; + } + QTC_ASSERT(m_conditionData->m_activeActivator == 0, return); + const auto it = m_conditionData->m_activatorHash.find(id); + QTC_ASSERT(it != m_conditionData->m_activatorHash.end(), return); + m_conditionData->m_activeActivator = id; +} + ParallelLimit sequential(1); ParallelLimit parallel(0); Workflow stopOnError(WorkflowPolicy::StopOnError); @@ -84,20 +132,21 @@ Workflow optional(WorkflowPolicy::Optional); void TaskItem::addChildren(const QList &children) { - QTC_ASSERT(m_type == Type::Group, qWarning("Only Task may have children, skipping..."); return); + QTC_ASSERT(m_type == Type::Group, qWarning("Only Group may have children, skipping..."); + return); for (const TaskItem &child : children) { switch (child.m_type) { case Type::Group: m_children.append(child); break; case Type::Limit: - QTC_ASSERT(m_type == Type::Group, - qWarning("Mode may only be a child of Group, skipping..."); return); + QTC_ASSERT(m_type == Type::Group, qWarning("Execution Mode may only be a child of a " + "Group, skipping..."); return); m_parallelLimit = child.m_parallelLimit; // TODO: Assert on redefinition? break; case Type::Policy: - QTC_ASSERT(m_type == Type::Group, - qWarning("Workflow Policy may only be a child of Group, skipping..."); return); + QTC_ASSERT(m_type == Type::Group, qWarning("Workflow Policy may only be a child of a " + "Group, skipping..."); return); m_workflowPolicy = child.m_workflowPolicy; // TODO: Assert on redefinition? break; case Type::TaskHandler: @@ -109,7 +158,7 @@ void TaskItem::addChildren(const QList &children) break; case Type::GroupHandler: QTC_ASSERT(m_type == Type::Group, qWarning("Group Handler may only be a " - "child of Group, skipping..."); break); + "child of a Group, skipping..."); break); QTC_ASSERT(!child.m_groupHandler.m_setupHandler || !m_groupHandler.m_setupHandler, qWarning("Group Setup Handler redefinition, overriding...")); @@ -126,6 +175,12 @@ void TaskItem::addChildren(const QList &children) if (child.m_groupHandler.m_errorHandler) m_groupHandler.m_errorHandler = child.m_groupHandler.m_errorHandler; break; + case Type::Condition: + QTC_ASSERT(m_type == Type::Group, qWarning("WaitFor may only be a child of a Group, " + "skipping..."); break); + QTC_ASSERT(!m_condition, qWarning("WaitFor redefinition, overriding...")); + m_condition = child.m_condition; + break; case Type::Storage: m_storageList.append(child.m_storageList); break; @@ -140,147 +195,25 @@ using namespace Tasking; class TaskTreePrivate; class TaskNode; -class TaskContainer -{ -public: - TaskContainer(TaskTreePrivate *taskTreePrivate, const TaskItem &task, - TaskContainer *parentContainer) - : m_constData(taskTreePrivate, task, parentContainer, this) {} - TaskAction start(); - TaskAction continueStart(TaskAction startAction, int nextChild); - TaskAction startChildren(int nextChild); - TaskAction childDone(bool success); - void stop(); - void invokeEndHandler(); - bool isRunning() const { return m_runtimeData.has_value(); } - bool isStarting() const { return isRunning() && m_runtimeData->m_startGuard.isLocked(); } - - struct ConstData { - ConstData(TaskTreePrivate *taskTreePrivate, const TaskItem &task, - TaskContainer *parentContainer, TaskContainer *thisContainer); - ~ConstData() { qDeleteAll(m_children); } - TaskTreePrivate * const m_taskTreePrivate = nullptr; - TaskContainer * const m_parentContainer = nullptr; - - const int m_parallelLimit = 1; - const WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError; - const TaskItem::GroupHandler m_groupHandler; - const QList m_storageList; - const QList m_children; - const int m_taskCount = 0; - }; - - struct RuntimeData { - RuntimeData(const ConstData &constData); - ~RuntimeData(); - - static QList createStorages(const TaskContainer::ConstData &constData); - void callStorageDoneHandlers(); - bool updateSuccessBit(bool success); - int currentLimit() const; - - const ConstData &m_constData; - const QList m_storageIdList; - int m_doneCount = 0; - bool m_successBit = true; - Guard m_startGuard; - }; - - const ConstData m_constData; - std::optional m_runtimeData; -}; - -class TaskNode : public QObject -{ -public: - TaskNode(TaskTreePrivate *taskTreePrivate, const TaskItem &task, - TaskContainer *parentContainer) - : m_taskHandler(task.taskHandler()) - , m_container(taskTreePrivate, task, parentContainer) - {} - - // If returned value != Continue, childDone() needs to be called in parent container (in caller) - // in order to unwind properly. - TaskAction start(); - void stop(); - void invokeEndHandler(bool success); - bool isRunning() const { return m_task || m_container.isRunning(); } - bool isTask() const { return m_taskHandler.m_createHandler && m_taskHandler.m_setupHandler; } - int taskCount() const { return isTask() ? 1 : m_container.m_constData.m_taskCount; } - TaskContainer *parentContainer() const { return m_container.m_constData.m_parentContainer; } - -private: - const TaskItem::TaskHandler m_taskHandler; - TaskContainer m_container; - std::unique_ptr m_task; -}; - class TaskTreePrivate { public: TaskTreePrivate(TaskTree *taskTree) : q(taskTree) {} - void start() { - QTC_ASSERT(m_root, return); - m_progressValue = 0; - emitStartedAndProgress(); - // TODO: check storage handlers for not existing storages in tree - for (auto it = m_storageHandlers.cbegin(); it != m_storageHandlers.cend(); ++it) { - QTC_ASSERT(m_storages.contains(it.key()), qWarning("The registered storage doesn't " - "exist in task tree. Its handlers will never be called.")); - } - m_root->start(); - } - void stop() { - QTC_ASSERT(m_root, return); - if (!m_root->isRunning()) - return; - // TODO: should we have canceled flag (passed to handler)? - // Just one done handler with result flag: - // FinishedWithSuccess, FinishedWithError, Canceled, TimedOut. - // Canceled either directly by user, or by workflow policy - doesn't matter, in both - // cases canceled from outside. - m_root->stop(); - emitError(); - } - void advanceProgress(int byValue) { - if (byValue == 0) - return; - QTC_CHECK(byValue > 0); - QTC_CHECK(m_progressValue + byValue <= m_root->taskCount()); - m_progressValue += byValue; - emitProgress(); - } - void emitStartedAndProgress() { - GuardLocker locker(m_guard); - emit q->started(); - emit q->progressValueChanged(m_progressValue); - } - void emitProgress() { - GuardLocker locker(m_guard); - emit q->progressValueChanged(m_progressValue); - } - void emitDone() { - QTC_CHECK(m_progressValue == m_root->taskCount()); - GuardLocker locker(m_guard); - emit q->done(); - } - void emitError() { - QTC_CHECK(m_progressValue == m_root->taskCount()); - GuardLocker locker(m_guard); - emit q->errorOccurred(); - } - QList addStorages(const QList &storages) { - QList addedStorages; - for (const TreeStorageBase &storage : storages) { - QTC_ASSERT(!m_storages.contains(storage), qWarning("Can't add the same storage into " - "one TaskTree twice, skipping..."); continue); - addedStorages << storage; - m_storages << storage; - } - return addedStorages; - } + void start(); + void stop(); + void advanceProgress(int byValue); + void emitStartedAndProgress(); + void emitProgress(); + void emitDone(); + void emitError(); + bool addCondition(const TaskItem &task, TaskContainer *container); + void createConditionActivators(); + void deleteConditionActivators(); + void activateConditions(); + void deactivateConditions(); + QList addStorages(const QList &storages); void callSetupHandler(TreeStorageBase storage, int storageId) { callStorageHandler(storage, storageId, &StorageHandler::m_setupHandler); } @@ -308,36 +241,252 @@ public: TaskTree *q = nullptr; Guard m_guard; int m_progressValue = 0; + QHash m_conditions; QSet m_storages; QHash m_storageHandlers; std::unique_ptr m_root = nullptr; // Keep me last in order to destruct first }; -class StorageActivator +class TaskContainer { public: - StorageActivator(TaskContainer *container) - : m_container(container) { activateStorages(m_container); } - ~StorageActivator() { deactivateStorages(m_container); } + TaskContainer(TaskTreePrivate *taskTreePrivate, const TaskItem &task, + TaskNode *parentNode, TaskContainer *parentContainer) + : m_constData(taskTreePrivate, task, parentNode, parentContainer, this) + , m_conditionData(taskTreePrivate->addCondition(task, this) + ? ConditionData() : std::optional()) {} + TaskAction start(); + TaskAction continueStart(TaskAction startAction, int nextChild); + TaskAction startChildren(int nextChild); + TaskAction childDone(bool success); + void activateCondition(); + void stop(); + void invokeEndHandler(); + bool isRunning() const { return m_runtimeData.has_value(); } + bool isStarting() const { return isRunning() && m_runtimeData->m_startGuard.isLocked(); } + + struct ConstData { + ConstData(TaskTreePrivate *taskTreePrivate, const TaskItem &task, TaskNode *parentNode, + TaskContainer *parentContainer, TaskContainer *thisContainer); + ~ConstData() { qDeleteAll(m_children); } + TaskTreePrivate * const m_taskTreePrivate = nullptr; + TaskNode * const m_parentNode = nullptr; + TaskContainer * const m_parentContainer = nullptr; + + const int m_parallelLimit = 1; + const WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError; + const TaskItem::GroupHandler m_groupHandler; + const QList m_storageList; + const QList m_children; + const int m_taskCount = 0; + }; + + struct ConditionData { + bool m_activated = false; + int m_conditionId = 0; + }; + + struct RuntimeData { + RuntimeData(const ConstData &constData); + ~RuntimeData(); + + static QList createStorages(const TaskContainer::ConstData &constData); + void callStorageDoneHandlers(); + bool updateSuccessBit(bool success); + int currentLimit() const; + + const ConstData &m_constData; + const QList m_storageIdList; + int m_doneCount = 0; + bool m_successBit = true; + Guard m_startGuard; + }; + + const ConstData m_constData; + std::optional m_conditionData; + std::optional m_runtimeData; +}; + +class TaskNode : public QObject +{ +public: + TaskNode(TaskTreePrivate *taskTreePrivate, const TaskItem &task, + TaskContainer *parentContainer) + : m_taskHandler(task.taskHandler()) + , m_container(taskTreePrivate, task, this, parentContainer) + {} + + // If returned value != Continue, childDone() needs to be called in parent container (in caller) + // in order to unwind properly. + TaskAction start(); + void stop(); + void invokeEndHandler(bool success); + bool isRunning() const { return m_task || m_container.isRunning(); } + bool isTask() const { return m_taskHandler.m_createHandler && m_taskHandler.m_setupHandler; } + int taskCount() const { return isTask() ? 1 : m_container.m_constData.m_taskCount; } + TaskContainer *parentContainer() const { return m_container.m_constData.m_parentContainer; } + void activateCondition(); private: - static void activateStorages(TaskContainer *container) + const TaskItem::TaskHandler m_taskHandler; + TaskContainer m_container; + std::unique_ptr m_task; +}; + +void TaskTreePrivate::start() +{ + QTC_ASSERT(m_root, return); + m_progressValue = 0; + emitStartedAndProgress(); + // TODO: check storage handlers for not existing storages in tree + for (auto it = m_storageHandlers.cbegin(); it != m_storageHandlers.cend(); ++it) { + QTC_ASSERT(m_storages.contains(it.key()), qWarning("The registered storage doesn't " + "exist in task tree. Its handlers will never be called.")); + } + createConditionActivators(); + m_root->start(); +} + +void TaskTreePrivate::stop() +{ + QTC_ASSERT(m_root, return); + if (!m_root->isRunning()) + return; + // TODO: should we have canceled flag (passed to handler)? + // Just one done handler with result flag: + // FinishedWithSuccess, FinishedWithError, Canceled, TimedOut. + // Canceled either directly by user, or by workflow policy - doesn't matter, in both + // cases canceled from outside. + m_root->stop(); + emitError(); +} + +void TaskTreePrivate::advanceProgress(int byValue) +{ + if (byValue == 0) + return; + QTC_CHECK(byValue > 0); + QTC_CHECK(m_progressValue + byValue <= m_root->taskCount()); + m_progressValue += byValue; + emitProgress(); +} + +void TaskTreePrivate::emitStartedAndProgress() +{ + GuardLocker locker(m_guard); + emit q->started(); + emit q->progressValueChanged(m_progressValue); +} + +void TaskTreePrivate::emitProgress() +{ + GuardLocker locker(m_guard); + emit q->progressValueChanged(m_progressValue); +} + +void TaskTreePrivate::emitDone() +{ + deleteConditionActivators(); + QTC_CHECK(m_progressValue == m_root->taskCount()); + GuardLocker locker(m_guard); + emit q->done(); +} + +void TaskTreePrivate::emitError() +{ + deleteConditionActivators(); + QTC_CHECK(m_progressValue == m_root->taskCount()); + GuardLocker locker(m_guard); + emit q->errorOccurred(); +} + +bool TaskTreePrivate::addCondition(const TaskItem &task, TaskContainer *container) +{ + if (!task.condition()) + return false; + QTC_ASSERT(!m_conditions.contains(*task.condition()), qWarning("Can't add the same condition " + "into one TaskTree twice, skipping..."); return false); + m_conditions.insert(*task.condition(), container); + return true; +} + +void TaskTreePrivate::createConditionActivators() +{ + for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) { + Condition condition = it.key(); + TaskContainer *container = it.value(); + container->m_conditionData->m_conditionId + = condition.createActivator(container->m_constData.m_parentNode); + } +} + +void TaskTreePrivate::deleteConditionActivators() +{ + for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) { + Condition condition = it.key(); + TaskContainer *container = it.value(); + condition.deleteActivator(container->m_conditionData->m_conditionId); + container->m_conditionData = TaskContainer::ConditionData(); + } +} + +void TaskTreePrivate::activateConditions() +{ + for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) { + Condition condition = it.key(); + TaskContainer *container = it.value(); + condition.activateActivator(container->m_conditionData->m_conditionId); + } +} + +void TaskTreePrivate::deactivateConditions() +{ + for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) + it.key().activateActivator(0); +} + +QList TaskTreePrivate::addStorages(const QList &storages) +{ + QList addedStorages; + for (const TreeStorageBase &storage : storages) { + QTC_ASSERT(!m_storages.contains(storage), qWarning("Can't add the same storage into " + "one TaskTree twice, skipping..."); continue); + addedStorages << storage; + m_storages << storage; + } + return addedStorages; +} + +// TODO: Activate/deactivate Conditions +class ExecutionContextActivator +{ +public: + ExecutionContextActivator(TaskContainer *container) + : m_container(container) { activateContext(m_container); } + ~ExecutionContextActivator() { deactivateContext(m_container); } + +private: + static void activateContext(TaskContainer *container) { QTC_ASSERT(container && container->isRunning(), return); const TaskContainer::ConstData &constData = container->m_constData; if (constData.m_parentContainer) - activateStorages(constData.m_parentContainer); + activateContext(constData.m_parentContainer); + else + constData.m_taskTreePrivate->activateConditions(); for (int i = 0; i < constData.m_storageList.size(); ++i) constData.m_storageList[i].activateStorage(container->m_runtimeData->m_storageIdList.value(i)); } - static void deactivateStorages(TaskContainer *container) + static void deactivateContext(TaskContainer *container) { QTC_ASSERT(container && container->isRunning(), return); const TaskContainer::ConstData &constData = container->m_constData; for (int i = constData.m_storageList.size() - 1; i >= 0; --i) // iterate in reverse order constData.m_storageList[i].activateStorage(0); if (constData.m_parentContainer) - deactivateStorages(constData.m_parentContainer); + deactivateContext(constData.m_parentContainer); + else + constData.m_taskTreePrivate->deactivateConditions(); } TaskContainer *m_container = nullptr; }; @@ -346,7 +495,7 @@ template > ReturnType invokeHandler(TaskContainer *container, Handler &&handler, Args &&...args) { - StorageActivator activator(container); + ExecutionContextActivator activator(container); GuardLocker locker(container->m_constData.m_taskTreePrivate->m_guard); return std::invoke(std::forward(handler), std::forward(args)...); } @@ -362,8 +511,10 @@ static QList createChildren(TaskTreePrivate *taskTreePrivate, TaskCo } TaskContainer::ConstData::ConstData(TaskTreePrivate *taskTreePrivate, const TaskItem &task, - TaskContainer *parentContainer, TaskContainer *thisContainer) + TaskNode *parentNode, TaskContainer *parentContainer, + TaskContainer *thisContainer) : m_taskTreePrivate(taskTreePrivate) + , m_parentNode(parentNode) , m_parentContainer(parentContainer) , m_parallelLimit(task.parallelLimit()) , m_workflowPolicy(task.workflowPolicy()) @@ -440,8 +591,12 @@ TaskAction TaskContainer::start() if (startAction != TaskAction::Continue) m_constData.m_taskTreePrivate->advanceProgress(m_constData.m_taskCount); } - if (m_constData.m_children.isEmpty() && startAction == TaskAction::Continue) - startAction = TaskAction::StopWithDone; + if (startAction == TaskAction::Continue) { + if (m_conditionData && !m_conditionData->m_activated) // Group has condition and it wasn't activated yet + return TaskAction::Continue; + if (m_constData.m_children.isEmpty()) + startAction = TaskAction::StopWithDone; + } return continueStart(startAction, 0); } @@ -513,6 +668,35 @@ TaskAction TaskContainer::childDone(bool success) return continueStart(startAction, limit); } +void ConditionActivator::activate() +{ + m_node->activateCondition(); +} + +void TaskContainer::activateCondition() +{ + QTC_ASSERT(m_conditionData, return); + if (!m_constData.m_taskTreePrivate->m_root->isRunning()) + return; + + if (!isRunning()) + return; // Condition not run yet or group already skipped or stopped + + if (!m_conditionData->m_activated) + return; // May it happen that scheduled call is coming from previous TaskTree's start? + + if (m_runtimeData->m_doneCount != 0) + return; // In meantime the group was started + + for (TaskNode *child : m_constData.m_children) { + if (child->isRunning()) + return; // In meantime the group was started + } + const TaskAction startAction = m_constData.m_children.isEmpty() ? TaskAction::StopWithDone + : TaskAction::Continue; + continueStart(startAction, 0); +} + void TaskContainer::stop() { if (!isRunning()) @@ -597,6 +781,26 @@ void TaskNode::invokeEndHandler(bool success) m_container.m_constData.m_taskTreePrivate->advanceProgress(1); } +void TaskNode::activateCondition() +{ + QTC_ASSERT(m_container.m_conditionData, return); + QTC_ASSERT(m_container.m_constData.m_taskTreePrivate->m_root->isRunning(), return); + + if (m_container.m_conditionData->m_activated) + return; // Was already activated + + m_container.m_conditionData->m_activated = true; + if (!isRunning()) + return; // Condition not run yet or group already skipped or stopped + + QTC_CHECK(m_container.m_runtimeData->m_doneCount == 0); + for (TaskNode *child : m_container.m_constData.m_children) + QTC_CHECK(!child->isRunning()); + + QMetaObject::invokeMethod(this, [this] { m_container.activateCondition(); }, + Qt::QueuedConnection); +} + /*! \class Utils::TaskTree \inheaderfile utils/tasktree.h @@ -1324,6 +1528,9 @@ TaskTree::~TaskTree() { QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting TaskTree instance directly from " "one of its handlers will lead to crash!")); + if (isRunning()) + d->deleteConditionActivators(); + // TODO: delete storages explicitly here? delete d; } @@ -1332,6 +1539,7 @@ void TaskTree::setupRoot(const Tasking::Group &root) QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return); QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The setupRoot() is called from one of the" "TaskTree handlers, ingoring..."); return); + d->m_conditions.clear(); d->m_storages.clear(); d->m_root.reset(new TaskNode(d, root, nullptr)); } diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 8a44b8a5b0e..8e9c0a6c17b 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -11,8 +11,9 @@ namespace Utils { -class StorageActivator; +class ExecutionContextActivator; class TaskContainer; +class TaskNode; class TaskTreePrivate; namespace Tasking { @@ -66,7 +67,7 @@ private: QSharedPointer m_storageData; friend TaskContainer; friend TaskTreePrivate; - friend StorageActivator; + friend ExecutionContextActivator; }; template @@ -87,6 +88,50 @@ private: } }; +class QTCREATOR_UTILS_EXPORT ConditionActivator +{ +public: + void activate(); + +private: + ConditionActivator(TaskNode *container) : m_node(container) {} + TaskNode *m_node = nullptr; + friend class Condition; +}; + +class QTCREATOR_UTILS_EXPORT Condition +{ +public: + Condition(); + ConditionActivator &operator*() const noexcept { return *activator(); } + ConditionActivator *operator->() const noexcept { return activator(); } + ConditionActivator *activator() const; + +private: + int createActivator(TaskNode *node) const; + void deleteActivator(int id) const; + void activateActivator(int id) const; + + friend bool operator==(const Condition &first, const Condition &second) + { return first.m_conditionData == second.m_conditionData; } + + friend bool operator!=(const Condition &first, const Condition &second) + { return first.m_conditionData != second.m_conditionData; } + + friend size_t qHash(const Condition &storage, uint seed = 0) + { return size_t(storage.m_conditionData.get()) ^ seed; } + + struct ConditionData { + ~ConditionData(); + QHash m_activatorHash = {}; + int m_activeActivator = 0; // 0 means no active activator + int m_activatorCounter = 0; + }; + QSharedPointer m_conditionData; + friend TaskTreePrivate; + friend ExecutionContextActivator; +}; + // WorkflowPolicy: // 1. When all children finished with done -> report done, otherwise: // a) Report error on first error and stop executing other children (including their subtree) @@ -143,11 +188,13 @@ public: TaskHandler taskHandler() const { return m_taskHandler; } GroupHandler groupHandler() const { return m_groupHandler; } QList children() const { return m_children; } + std::optional condition() const { return m_condition; } QList storageList() const { return m_storageList; } protected: enum class Type { Group, + Condition, Storage, Limit, Policy, @@ -168,6 +215,9 @@ protected: TaskItem(const GroupHandler &handler) : m_type(Type::GroupHandler) , m_groupHandler(handler) {} + TaskItem(const Condition &condition) + : m_type(Type::Condition) + , m_condition{condition} {} TaskItem(const TreeStorageBase &storage) : m_type(Type::Storage) , m_storageList{storage} {} @@ -179,6 +229,7 @@ private: WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError; TaskHandler m_taskHandler; GroupHandler m_groupHandler; + std::optional m_condition; QList m_storageList; QList m_children; }; @@ -196,6 +247,12 @@ public: Storage(const TreeStorageBase &storage) : TaskItem(storage) { } }; +class QTCREATOR_UTILS_EXPORT WaitFor : public TaskItem +{ +public: + WaitFor(const Condition &condition) : TaskItem(condition) { } +}; + class QTCREATOR_UTILS_EXPORT ParallelLimit : public TaskItem { public: @@ -321,7 +378,7 @@ private: class TaskTreePrivate; -class QTCREATOR_UTILS_EXPORT TaskTree : public QObject +class QTCREATOR_UTILS_EXPORT TaskTree final : public QObject { Q_OBJECT diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 90ea043a11a..37bbe498d7f 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -20,7 +20,8 @@ enum class Handler { GroupSetup, GroupDone, GroupError, - Sync + Sync, + Activator, }; using Log = QList>; @@ -1053,25 +1054,65 @@ void tst_TaskTree::processTree_data() << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Failure}; } - const Group root { - Storage(storage), - Sync(setupSync(1, true)), - Process(setupProcess(2)), - Sync(setupSync(3, true)), - Process(setupProcess(4)), - Sync(setupSync(5, true)), - OnGroupDone(groupDone(0)) - }; - const Log log { - {1, Handler::Sync}, - {2, Handler::Setup}, - {3, Handler::Sync}, - {4, Handler::Setup}, - {5, Handler::Sync}, - {0, Handler::GroupDone} - }; - QTest::newRow("SyncAndAsync") - << TestData{storage, root, log, 2, OnStart::Running, OnDone::Success}; + { + const Group root { + Storage(storage), + Sync(setupSync(1, true)), + Process(setupProcess(2)), + Sync(setupSync(3, true)), + Process(setupProcess(4)), + Sync(setupSync(5, true)), + OnGroupDone(groupDone(0)) + }; + const Log log { + {1, Handler::Sync}, + {2, Handler::Setup}, + {3, Handler::Sync}, + {4, Handler::Setup}, + {5, Handler::Sync}, + {0, Handler::GroupDone} + }; + QTest::newRow("SyncAndAsync") + << TestData{storage, root, log, 2, OnStart::Running, OnDone::Success}; + } + + { + Condition condition; + + const auto setupProcessWithCondition + = [storage, condition, setupProcessHelper](int processId) { + return [storage, condition, setupProcessHelper, processId](QtcProcess &process) { + setupProcessHelper(process, {"-return", "0"}, processId); + CustomStorage *currentStorage = storage.activeStorage(); + ConditionActivator *currentActivator = condition.activator(); + connect(&process, &QtcProcess::started, [currentStorage, currentActivator, processId] { + currentStorage->m_log.append({processId, Handler::Activator}); + currentActivator->activate(); + }); + }; + }; + + const Group root { + parallel, + Storage(storage), + Process(setupProcessWithCondition(1)), + Group { + OnGroupSetup(groupSetup(2)), + WaitFor(condition), + Process(setupProcess(2)), + Process(setupProcess(3)) + } + }; + const Log log { + {1, Handler::Setup}, + {2, Handler::GroupSetup}, + {1, Handler::Activator}, + {2, Handler::Setup}, + {3, Handler::Setup} + }; + QTest::newRow("WaitFor") + << TestData{storage, root, log, 3, OnStart::Running, OnDone::Success}; + } } void tst_TaskTree::processTree() From b6f2ff8705f5efa4244d5d4ad13946887faf7d0a Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Feb 2023 11:31:24 +0100 Subject: [PATCH 0105/1447] Utils: Fix handling of "/somedir/.." in FSEngine The change 249d613a60aa6a1347ebc1c29902049247b93324 in qtbase makes it so that QFileInfo::fileName() actually calls the underlying FSEngine now. Paths which resolve to "Root" like "/somedir/.." would return "" as their filename since they were immediately cleaned and therefore converted to "/" which does not have a filename. The same issue did exists for paths such as "/__qtc_devices__/ssh/.." and "/__qtc_devices__/ssh/devicename/.." This patch makes it so that the incoming filename is kept "unclean" until it is actually used. Change-Id: Id5b7d1105e2d59d776aa1df5bbf6273a9fcb5d27 Reviewed-by: hjk --- .../fsengine/fileiteratordevicesappender.h | 5 +++- src/libs/utils/fsengine/fixedlistfsengine.h | 2 ++ src/libs/utils/fsengine/fsengine_impl.cpp | 2 ++ src/libs/utils/fsengine/fsenginehandler.cpp | 11 ++++--- tests/auto/utils/fsengine/tst_fsengine.cpp | 30 +++++++++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/fsengine/fileiteratordevicesappender.h b/src/libs/utils/fsengine/fileiteratordevicesappender.h index c08c6cb3f70..9aec917d6b7 100644 --- a/src/libs/utils/fsengine/fileiteratordevicesappender.h +++ b/src/libs/utils/fsengine/fileiteratordevicesappender.h @@ -93,7 +93,10 @@ private: void setPath() const { if (!m_hasSetPath) { - const QString p = path(); + // path() can be "/somedir/.." so we need to clean it first. + // We only need QDir::cleanPath here, as the path is always + // a fs engine path and will not contain scheme:// etc. + const QString p = QDir::cleanPath(path()); if (p.compare(QDir::rootPath(), Qt::CaseInsensitive) == 0) m_status = State::IteratingRoot; diff --git a/src/libs/utils/fsengine/fixedlistfsengine.h b/src/libs/utils/fsengine/fixedlistfsengine.h index 991bc08b1bf..3518b5d0b5a 100644 --- a/src/libs/utils/fsengine/fixedlistfsengine.h +++ b/src/libs/utils/fsengine/fixedlistfsengine.h @@ -43,6 +43,8 @@ public: return chopIfEndsWith(m_filePath.toString(), '/'); break; case QAbstractFileEngine::BaseName: + if (m_filePath.fileName().isEmpty()) + return m_filePath.host().toString(); return m_filePath.fileName(); break; case QAbstractFileEngine::PathName: diff --git a/src/libs/utils/fsengine/fsengine_impl.cpp b/src/libs/utils/fsengine/fsengine_impl.cpp index 6654e741ace..ade8236d5e1 100644 --- a/src/libs/utils/fsengine/fsengine_impl.cpp +++ b/src/libs/utils/fsengine/fsengine_impl.cpp @@ -238,6 +238,8 @@ QString FSEngineImpl::fileName(FileName file) const return m_filePath.toFSPathString(); break; case QAbstractFileEngine::BaseName: + if (m_filePath.fileName().isEmpty()) + return m_filePath.host().toString(); return m_filePath.fileName(); break; case QAbstractFileEngine::PathName: diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp index a713315ae39..81e063971bb 100644 --- a/src/libs/utils/fsengine/fsenginehandler.cpp +++ b/src/libs/utils/fsengine/fsenginehandler.cpp @@ -29,7 +29,8 @@ QAbstractFileEngine *FSEngineHandler::create(const QString &fileName) const return rootFilePath.pathAppended(scheme); }); - return new FixedListFSEngine(rootFilePath, paths); + // We need to use fromString() here so the path is not cleaned + return new FixedListFSEngine(FilePath::fromString(fileName), paths); } if (fixedFileName.startsWith(rootPath)) { @@ -41,17 +42,19 @@ QAbstractFileEngine *FSEngineHandler::create(const QString &fileName) const return root.scheme() == scheme; }); - return new FixedListFSEngine(rootFilePath.pathAppended(scheme), filteredRoots); + // We need to use fromString() here so the path is not cleaned + return new FixedListFSEngine(FilePath::fromString(fileName), filteredRoots); } } - FilePath filePath = FilePath::fromString(fixedFileName); + // We need to use fromString() here so the path is not cleaned + FilePath filePath = FilePath::fromString(fileName); if (filePath.needsDevice()) return new FSEngineImpl(filePath); } if (fixedFileName.compare(QDir::rootPath(), Qt::CaseInsensitive) == 0) - return new RootInjectFSEngine(fixedFileName); + return new RootInjectFSEngine(fileName); return nullptr; } diff --git a/tests/auto/utils/fsengine/tst_fsengine.cpp b/tests/auto/utils/fsengine/tst_fsengine.cpp index d350a981808..1168cd494db 100644 --- a/tests/auto/utils/fsengine/tst_fsengine.cpp +++ b/tests/auto/utils/fsengine/tst_fsengine.cpp @@ -31,6 +31,7 @@ private slots: void testBrokenWindowsPath(); void testRead(); void testWrite(); + void testRootFromDotDot(); private: QString makeTestPath(QString path, bool asUrl = false); @@ -213,5 +214,34 @@ void tst_fsengine::testWrite() QCOMPARE(f.readAll(), data); } +void tst_fsengine::testRootFromDotDot() +{ + const QString path = QDir::rootPath() + "some-folder/.."; + QFileInfo fInfo(path); + + QCOMPARE(fInfo.fileName(), QString("..")); + + QDir dRoot(path); + const auto dRootEntryList = dRoot.entryList(); + QVERIFY(dRootEntryList.contains(FilePath::specialRootName())); + + QFileInfo fInfo2(FilePath::specialRootPath() + "/xyz/.."); + QCOMPARE(fInfo2.fileName(), ".."); + + QDir schemesWithDotDot(FilePath::specialRootPath() + "/xyz/.."); + const QStringList schemeWithDotDotList = schemesWithDotDot.entryList(); + QVERIFY(schemeWithDotDotList.contains("device")); + + QFileInfo fInfo3(FilePath::specialDeviceRootPath() + "/xyz/.."); + QCOMPARE(fInfo3.fileName(), ".."); + + QDir devicesWithDotDot(FilePath::specialDeviceRootPath() + "/test/.."); + const QStringList deviceListWithDotDot = devicesWithDotDot.entryList(); + QVERIFY(deviceListWithDotDot.contains("test")); + + QFileInfo fInfo4(FilePath::specialDeviceRootPath() + "/test/tmp/.."); + QCOMPARE(fInfo4.fileName(), ".."); +} + QTEST_GUILESS_MAIN(tst_fsengine) #include "tst_fsengine.moc" From cf71aed9a8ba9157e2881335826595513af8241e Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 28 Feb 2023 06:49:57 +0100 Subject: [PATCH 0106/1447] Terminal: Fix qbs build Amends d4ac8aeaa6063554fde. Change-Id: I91e96faefc81de365f6b170aaccb266019b6c25b Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminal.qbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index eb72c89494e..4eb3b621fc2 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -14,6 +14,8 @@ QtcPlugin { "keys.h", "scrollback.cpp", "scrollback.h", + "shellmodel.cpp", + "shellmodel.h", "terminal.qrc", "terminalpane.cpp", "terminalpane.h", From 43bc61a148febeb327cd3ac8bb30dff1f2135e4e Mon Sep 17 00:00:00 2001 From: Martin Delille Date: Tue, 28 Feb 2023 10:34:38 +0100 Subject: [PATCH 0107/1447] [conan plugin] Add conan install step as first step Change-Id: Ic3d1f9f312aab78135cff5f14655fcfedc8dad7a Reviewed-by: Cristian Adam --- src/plugins/conan/conanplugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/conan/conanplugin.cpp b/src/plugins/conan/conanplugin.cpp index a1a78acca33..ef42d348f86 100644 --- a/src/plugins/conan/conanplugin.cpp +++ b/src/plugins/conan/conanplugin.cpp @@ -48,12 +48,12 @@ static void connectTarget(Project *project, Target *target) if (!ConanPlugin::conanFilePath(project).isEmpty()) { const QList buildConfigurations = target->buildConfigurations(); for (BuildConfiguration *buildConfiguration : buildConfigurations) - buildConfiguration->buildSteps()->appendStep(Constants::INSTALL_STEP); + buildConfiguration->buildSteps()->insertStep(0, Constants::INSTALL_STEP); } QObject::connect(target, &Target::addedBuildConfiguration, target, [project] (BuildConfiguration *buildConfiguration) { if (!ConanPlugin::conanFilePath(project).isEmpty()) - buildConfiguration->buildSteps()->appendStep(Constants::INSTALL_STEP); + buildConfiguration->buildSteps()->insertStep(0, Constants::INSTALL_STEP); }); } From a69ff75357d98258502dc1b802d4d066d8b426b0 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 27 Feb 2023 18:22:57 +0100 Subject: [PATCH 0108/1447] Copilot: Settings/options icon Exclusive placeholder. While we figure out the legalities around the original Copilot icon. Change-Id: Iaacebbd8e8a46614659368a4ec7a98b03297e204 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/CMakeLists.txt | 1 + src/plugins/copilot/copilot.qbs | 1 + src/plugins/copilot/copilot.qrc | 6 ++++++ src/plugins/copilot/copilotoptionspage.cpp | 3 +-- .../copilot/images/settingscategory_copilot.png | Bin 0 -> 219 bytes .../images/settingscategory_copilot@2x.png | Bin 0 -> 404 bytes src/tools/icons/qtcreatoricons.svg | 14 ++++++++++++++ 7 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/plugins/copilot/copilot.qrc create mode 100644 src/plugins/copilot/images/settingscategory_copilot.png create mode 100644 src/plugins/copilot/images/settingscategory_copilot@2x.png diff --git a/src/plugins/copilot/CMakeLists.txt b/src/plugins/copilot/CMakeLists.txt index 4cca0e8d215..f0e29df2cf9 100644 --- a/src/plugins/copilot/CMakeLists.txt +++ b/src/plugins/copilot/CMakeLists.txt @@ -2,6 +2,7 @@ add_qtc_plugin(Copilot PLUGIN_DEPENDS Core LanguageClient SOURCES authwidget.cpp authwidget.h + copilot.qrc copilotplugin.cpp copilotplugin.h copilotclient.cpp copilotclient.h copilotsettings.cpp copilotsettings.h diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs index e8813607ac6..24b1d01bf5d 100644 --- a/src/plugins/copilot/copilot.qbs +++ b/src/plugins/copilot/copilot.qbs @@ -11,6 +11,7 @@ QtcPlugin { files: [ "authwidget.cpp", "authwidget.h", + "copilot.qrc", "copilotplugin.cpp", "copilotplugin.h", "copilotclient.cpp", diff --git a/src/plugins/copilot/copilot.qrc b/src/plugins/copilot/copilot.qrc new file mode 100644 index 00000000000..2071a381011 --- /dev/null +++ b/src/plugins/copilot/copilot.qrc @@ -0,0 +1,6 @@ + + + images/settingscategory_copilot.png + images/settingscategory_copilot@2x.png + + diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index 6fb49ef43c8..6934999a77e 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -44,8 +44,7 @@ CopilotOptionsPage::CopilotOptionsPage() setDisplayName("Copilot"); setCategory("ZY.Copilot"); setDisplayCategory("Copilot"); - - setCategoryIconPath(":/languageclient/images/settingscategory_languageclient.png"); + setCategoryIconPath(":/copilot/images/settingscategory_copilot.png"); } CopilotOptionsPage::~CopilotOptionsPage() {} diff --git a/src/plugins/copilot/images/settingscategory_copilot.png b/src/plugins/copilot/images/settingscategory_copilot.png new file mode 100644 index 0000000000000000000000000000000000000000..674fece4c51d97e21bbdcba147703f4a1359a645 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4h9AWhNCh`Dhvz^i#%N%Lp07O|LA8n;9={W zAFj9W=l}oTcbC7fQ}C|QfByJEO3#n_rpCs`qu+R(lp=~g-~Ye8k5Tnr&0YzGKfG!i zXFs%Xu@89k|Gzj-b%M~#WB(_r#2L#pd0MC_dfM=W{^6bO(df>)H$NxjK10C9yiUl)ilve%sUT|%9JzJO}70J zms7?NaAAW^=CqJgR@;TA9azE675k1WL4%j!Y`@rpORQU0&!41pdERXi4qJQo{#w%u ziEN!}FMj*vTW~+0wB);(g-N663(r$R8REx$76=}nnsb2rOInk3##Gsg_J2Mb*o?O& z$S*TKsKWB*!1ne>uYC;omS1~Nx0bKXH(9oMgJekPbSuU^g^?jv2FwgyyO_jwKWVo# z{*e2Q)qkJP^!Ge_wgqou`dBn){Z0nnLm7SwK~2fF;tN7GBz8 + + + + From f19eff5dcb5b9cf94e05829e9443163b1725dd18 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Feb 2023 11:27:24 +0100 Subject: [PATCH 0109/1447] Copilot: Add explanatory text to settings Change-Id: Ie45d20d77b064e99fbd4cf26f0794a336b02c51a Reviewed-by: hjk --- src/plugins/copilot/copilotoptionspage.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index 6934999a77e..b74597dcec6 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -5,7 +5,7 @@ #include "authwidget.h" #include "copilotsettings.h" -#include "copilotsettings.h" +#include "copilottr.h" #include @@ -27,11 +27,30 @@ public: auto authWidget = new AuthWidget(); + QLabel *helpLabel = new QLabel(); + helpLabel->setTextFormat(Qt::MarkdownText); + helpLabel->setWordWrap(true); + helpLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse + | Qt::LinksAccessibleByKeyboard); + helpLabel->setOpenExternalLinks(true); + // clang-format off + helpLabel->setText(Tr::tr(R"( +The Copilot plugin requires node.js and the Copilot neovim plugin. +If you install the neovim plugin as described in the +[README.md](https://github.com/github/copilot.vim), +the plugin will find the agent.js file automatically. + +Otherwise you need to specify the path to the +[agent.js](https://github.com/github/copilot.vim/tree/release/copilot/dist) +file from the Copilot neovim plugin. + )", "Markdown text for the copilot instruction label")); + Column { authWidget, br, CopilotSettings::instance().nodeJsPath, br, CopilotSettings::instance().distPath, br, + helpLabel, br, st }.attachTo(this); // clang-format on From d14834ad45e0c8bee0ff960606f1764bf1ad3588 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Feb 2023 13:49:08 +0100 Subject: [PATCH 0110/1447] Utils: Fix handling of multi slash in fsengine Change-Id: Iaf525423f5ea0933b202f23042173c51edb3d4b0 Reviewed-by: hjk --- src/libs/utils/fsengine/fsenginehandler.cpp | 34 ++++++++++++++++----- tests/auto/utils/fsengine/tst_fsengine.cpp | 19 +++++++++++- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp index 81e063971bb..c5fa71e7861 100644 --- a/src/libs/utils/fsengine/fsenginehandler.cpp +++ b/src/libs/utils/fsengine/fsenginehandler.cpp @@ -13,6 +13,26 @@ namespace Utils::Internal { +static FilePath removeDoubleSlash(const QString &fileName) +{ + // Reduce every two or more slashes to a single slash. + QString result; + const QChar slash = QChar('/'); + bool lastWasSlash = false; + for (const QChar &ch : fileName) { + if (ch == slash) { + if (!lastWasSlash) + result.append(ch); + lastWasSlash = true; + } else { + result.append(ch); + lastWasSlash = false; + } + } + // We use fromString() here to not normalize / clean the path anymore. + return FilePath::fromString(result); +} + QAbstractFileEngine *FSEngineHandler::create(const QString &fileName) const { if (fileName.startsWith(':')) @@ -29,8 +49,7 @@ QAbstractFileEngine *FSEngineHandler::create(const QString &fileName) const return rootFilePath.pathAppended(scheme); }); - // We need to use fromString() here so the path is not cleaned - return new FixedListFSEngine(FilePath::fromString(fileName), paths); + return new FixedListFSEngine(removeDoubleSlash(fileName), paths); } if (fixedFileName.startsWith(rootPath)) { @@ -42,15 +61,14 @@ QAbstractFileEngine *FSEngineHandler::create(const QString &fileName) const return root.scheme() == scheme; }); - // We need to use fromString() here so the path is not cleaned - return new FixedListFSEngine(FilePath::fromString(fileName), filteredRoots); + return new FixedListFSEngine(removeDoubleSlash(fileName), filteredRoots); } } - // We need to use fromString() here so the path is not cleaned - FilePath filePath = FilePath::fromString(fileName); - if (filePath.needsDevice()) - return new FSEngineImpl(filePath); + FilePath fixedPath = FilePath::fromString(fixedFileName); + + if (fixedPath.needsDevice()) + return new FSEngineImpl(removeDoubleSlash(fileName)); } if (fixedFileName.compare(QDir::rootPath(), Qt::CaseInsensitive) == 0) diff --git a/tests/auto/utils/fsengine/tst_fsengine.cpp b/tests/auto/utils/fsengine/tst_fsengine.cpp index 1168cd494db..d516bda8c21 100644 --- a/tests/auto/utils/fsengine/tst_fsengine.cpp +++ b/tests/auto/utils/fsengine/tst_fsengine.cpp @@ -32,6 +32,7 @@ private slots: void testRead(); void testWrite(); void testRootFromDotDot(); + void testDirtyPaths(); private: QString makeTestPath(QString path, bool asUrl = false); @@ -134,7 +135,8 @@ QString tst_fsengine::makeTestPath(QString path, bool asUrl) return QString("device://test%1/tst_fsengine/%2").arg(tempFolder, path); return QString(FilePath::specialDeviceRootPath() + "/test%1/tst_fsengine/%2") - .arg(startWithSlash(tempFolder), path); + .arg(startWithSlash(tempFolder)) + .arg(path); } void tst_fsengine::testListDir() @@ -243,5 +245,20 @@ void tst_fsengine::testRootFromDotDot() QCOMPARE(fInfo4.fileName(), ".."); } +void tst_fsengine::testDirtyPaths() +{ + // "//__qtc_devices" + QVERIFY(QFileInfo("/" + FilePath::specialRootPath()).exists()); + + // "///__qtc_devices/device" + QVERIFY(QFileInfo("//" + FilePath::specialDeviceRootPath()).exists()); + + // "////__qtc_devices/device////test" + QVERIFY(QFileInfo("///" + FilePath::specialDeviceRootPath() + "////test").exists()); + + // "/////__qtc_devices/device/test/..." + QVERIFY(QFileInfo("////" + makeTestPath("")).exists()); +} + QTEST_GUILESS_MAIN(tst_fsengine) #include "tst_fsengine.moc" From e538e8f2e7080561daa3c6058c25c5792fb1e032 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 1 Mar 2023 09:04:52 +0100 Subject: [PATCH 0111/1447] Qt Designer Custom Widget wizard: Remove remains of Qt 4 Clean the .pro files and use Qt 5 plugin metadata instead of old exports. Change-Id: I24c96d90f5dc45ecd20064159eb175e0e0475a34 Reviewed-by: hjk --- .../customwidgetwizard/tpl_collection.cpp | 2 -- .../qt4project/customwidgetwizard/tpl_plugin.pro | 6 +----- .../qt4project/customwidgetwizard/tpl_single.cpp | 1 - .../customwidgetwizard/plugingenerator.cpp | 15 ++------------- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.cpp b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.cpp index 7e64374bab7..c5438f45ca2 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.cpp +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.cpp @@ -10,5 +10,3 @@ QList @COLLECTION_PLUGIN_CLASS@::customWidgets( { return m_widgets; } - -@COLLECTION_PLUGIN_EXPORT@ diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_plugin.pro b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_plugin.pro index 53d12b7397f..ab125bfb499 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_plugin.pro +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_plugin.pro @@ -7,11 +7,7 @@ SOURCES =@PLUGIN_SOURCES@ RESOURCES = @PLUGIN_RESOURCES@ LIBS += -L. @WIDGET_LIBS@ -greaterThan(QT_MAJOR_VERSION, 4) { - QT += designer -} else { - CONFIG += designer -} +QT += designer target.path = $$[QT_INSTALL_PLUGINS]/designer INSTALLS += target diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp index 6ffc8481da2..06dce7128a9 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp @@ -68,4 +68,3 @@ QString @PLUGIN_CLASS@::includeFile() const { return QLatin1String("@WIDGET_HEADER@"); } -@SINGLE_PLUGIN_EXPORT@ diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp index ab3f59d8518..4f0d4604835 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp @@ -49,17 +49,10 @@ static Core::GeneratedFile generateIconFile(const FilePath &source, return rc; } -static QString qt4PluginExport(const QString &pluginName, const QString &pluginClassName) -{ - return QLatin1String("#if QT_VERSION < 0x050000\nQ_EXPORT_PLUGIN2(") - + pluginName + QLatin1String(", ") + pluginClassName - + QLatin1String(")\n#endif // QT_VERSION < 0x050000"); -} - static QString qt5PluginMetaData(const QString &interfaceName) { - return QLatin1String("#if QT_VERSION >= 0x050000\n Q_PLUGIN_METADATA(IID \"org.qt-project.Qt.") - + interfaceName + QLatin1String("\")\n#endif // QT_VERSION >= 0x050000"); + return QLatin1String(" Q_PLUGIN_METADATA(IID \"org.qt-project.Qt.") + + interfaceName + QLatin1String("\")"); } QList PluginGenerator::generatePlugin(const GenerationParameters& p, const PluginOptions &options, @@ -122,9 +115,6 @@ QList PluginGenerator::generatePlugin(const GenerationPara sm.insert(QLatin1String("WIDGET_WHATSTHIS"), cStringQuote(wo.whatsThis)); sm.insert(QLatin1String("WIDGET_ISCONTAINER"), wo.isContainer ? QLatin1String("true") : QLatin1String("false")); sm.insert(QLatin1String("WIDGET_DOMXML"), cStringQuote(wo.domXml)); - sm.insert(QLatin1String("SINGLE_PLUGIN_EXPORT"), - options.widgetOptions.count() == 1 ? - qt4PluginExport(options.pluginName, wo.pluginClassName) : QString()); const QString pluginSourceContents = processTemplate(p.templatePath + QLatin1String("/tpl_single.cpp"), sm, errorMessage); if (pluginSourceContents.isEmpty()) @@ -239,7 +229,6 @@ QList PluginGenerator::generatePlugin(const GenerationPara options.collectionHeaderFile + QLatin1String("\"")); sm.insert(QLatin1String("PLUGIN_ADDITIONS"), pluginAdditions); - sm.insert(QLatin1String("COLLECTION_PLUGIN_EXPORT"), qt4PluginExport(options.pluginName, options.collectionClassName)); const QString collectionSourceFileContents = processTemplate(p.templatePath + QLatin1String("/tpl_collection.cpp"), sm, errorMessage); if (collectionSourceFileContents.isEmpty()) return QList(); From 745de1b34d27e44bc9a2792456ea057981ddbc7d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 1 Mar 2023 09:08:56 +0100 Subject: [PATCH 0112/1447] Qt Designer Custom Widget wizard: Update code templates - Introduce nullptr, member initialization, override. Change-Id: I1088e124bf554050f71f002e6af31a2432479f99 Reviewed-by: hjk --- .../customwidgetwizard/tpl_collection.h | 4 +-- .../customwidgetwizard/tpl_single.cpp | 1 - .../customwidgetwizard/tpl_single.h | 26 +++++++++---------- .../customwidgetwizard/tpl_widget.h | 2 +- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.h b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.h index f9a898e6a8a..e8e792915bb 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.h +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_collection.h @@ -15,9 +15,9 @@ class @COLLECTION_PLUGIN_CLASS@ : public QObject, public QDesignerCustomWidgetCo @COLLECTION_PLUGIN_METADATA@ public: - explicit @COLLECTION_PLUGIN_CLASS@(QObject *parent = 0); + explicit @COLLECTION_PLUGIN_CLASS@(QObject *parent = nullptr); - virtual QList customWidgets() const; + QList customWidgets() const override; private: QList m_widgets; diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp index 06dce7128a9..8afff94d745 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp @@ -6,7 +6,6 @@ @PLUGIN_CLASS@::@PLUGIN_CLASS@(QObject *parent) : QObject(parent) { - m_initialized = false; } void @PLUGIN_CLASS@::initialize(QDesignerFormEditorInterface * /* core */) diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.h b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.h index 0767c0581df..2402458092e 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.h +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.h @@ -14,22 +14,22 @@ class @PLUGIN_CLASS@ : public QObject, public QDesignerCustomWidgetInterface @SINGLE_PLUGIN_METADATA@ public: - @PLUGIN_CLASS@(QObject *parent = 0); + explicit @PLUGIN_CLASS@(QObject *parent = nullptr); - bool isContainer() const; - bool isInitialized() const; - QIcon icon() const; - QString domXml() const; - QString group() const; - QString includeFile() const; - QString name() const; - QString toolTip() const; - QString whatsThis() const; - QWidget *createWidget(QWidget *parent); - void initialize(QDesignerFormEditorInterface *core); + bool isContainer() const override; + bool isInitialized() const override; + QIcon icon() const override; + QString domXml() const override; + QString group() const override; + QString includeFile() const override; + QString name() const override; + QString toolTip() const override; + QString whatsThis() const override; + QWidget *createWidget(QWidget *parent) override; + void initialize(QDesignerFormEditorInterface *core) override; private: - bool m_initialized; + bool m_initialized = false; }; @if ! '%{Cpp:PragmaOnce}' diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_widget.h b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_widget.h index 50256c5ff54..3ec192c6d31 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_widget.h +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_widget.h @@ -12,7 +12,7 @@ class @WIDGET_CLASS@ : public @WIDGET_BASE_CLASS@ Q_OBJECT public: - @WIDGET_CLASS@(QWidget *parent = 0); + explicit @WIDGET_CLASS@(QWidget *parent = nullptr); }; @if ! '%{Cpp:PragmaOnce}' From 03e1c18f78c1103e149d7daee76ec070c8b001cf Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 1 Mar 2023 09:47:48 +0100 Subject: [PATCH 0113/1447] Qt Designer Custom Widget wizard: Generate XML as raw string literal It makes it easier to customize it later on. Change-Id: Ie4ac7830a5544746d621b5ba34d174b3f8e3676a Reviewed-by: hjk --- .../templates/qt4project/customwidgetwizard/tpl_single.cpp | 2 +- .../qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp index 8afff94d745..06790ac5478 100644 --- a/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp +++ b/share/qtcreator/templates/qt4project/customwidgetwizard/tpl_single.cpp @@ -60,7 +60,7 @@ bool @PLUGIN_CLASS@::isContainer() const QString @PLUGIN_CLASS@::domXml() const { - return QLatin1String("@WIDGET_DOMXML@"); + return QLatin1String(@WIDGET_DOMXML@); } QString @PLUGIN_CLASS@::includeFile() const diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp index 4f0d4604835..28e67ec3ece 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp @@ -114,7 +114,8 @@ QList PluginGenerator::generatePlugin(const GenerationPara sm.insert(QLatin1String("WIDGET_TOOLTIP"), cStringQuote(wo.toolTip)); sm.insert(QLatin1String("WIDGET_WHATSTHIS"), cStringQuote(wo.whatsThis)); sm.insert(QLatin1String("WIDGET_ISCONTAINER"), wo.isContainer ? QLatin1String("true") : QLatin1String("false")); - sm.insert(QLatin1String("WIDGET_DOMXML"), cStringQuote(wo.domXml)); + sm.insert(QLatin1String("WIDGET_DOMXML"), QLatin1String("R\"(") + + wo.domXml.trimmed() + QLatin1String(")\"")); const QString pluginSourceContents = processTemplate(p.templatePath + QLatin1String("/tpl_single.cpp"), sm, errorMessage); if (pluginSourceContents.isEmpty()) From 3e7d93c788773c7f8194a5465ee0f46961432d76 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Feb 2023 15:47:22 +0100 Subject: [PATCH 0114/1447] ProjectExplorer: Move some not-fully-session related bits ... out of SessionManager. The idea is to later move SessionManager into the Core plugin, which both is sensible conceptually and also prerequisite to merge the Bookmark plugin into TextEditor plugin. Currently, only the interface is split, as the load/save implemetations are non-mechanical to disentangle. Change-Id: I31631db3094ea192825a2ccaa6add6188662940b Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/android/androidconfigurations.cpp | 2 +- src/plugins/android/androiddevice.cpp | 2 +- src/plugins/android/androidmanager.cpp | 2 +- .../android/androidmanifesteditorwidget.cpp | 4 +- src/plugins/android/androidplugin.cpp | 2 +- src/plugins/autotest/autotestplugin.cpp | 18 +- .../autotest/boost/boosttesttreeitem.cpp | 10 +- src/plugins/autotest/catch/catchtreeitem.cpp | 16 +- src/plugins/autotest/ctest/ctesttreeitem.cpp | 6 +- src/plugins/autotest/gtest/gtesttreeitem.cpp | 14 +- src/plugins/autotest/qtest/qttesttreeitem.cpp | 16 +- .../autotest/quick/quicktestparser.cpp | 9 +- .../autotest/quick/quicktesttreeitem.cpp | 14 +- src/plugins/autotest/testcodeparser.cpp | 14 +- src/plugins/autotest/testconfiguration.cpp | 6 +- src/plugins/autotest/testnavigationwidget.cpp | 8 +- src/plugins/autotest/testprojectsettings.cpp | 2 +- src/plugins/autotest/testrunner.cpp | 16 +- src/plugins/autotest/testtreemodel.cpp | 16 +- .../baremetal/debugservers/uvsc/uvproject.cpp | 2 +- src/plugins/bookmarks/bookmarkmanager.cpp | 3 +- .../clangcodemodel/clangcodemodelplugin.cpp | 19 +- src/plugins/clangcodemodel/clangdclient.cpp | 4 +- .../clangcodemodel/clangdfindreferences.cpp | 5 +- .../clangcodemodel/clangdlocatorfilters.cpp | 8 +- .../clangmodelmanagersupport.cpp | 33 +- .../clangformat/clangformatbaseindenter.cpp | 4 +- .../clangformat/clangformatindenter.cpp | 2 +- src/plugins/clangformat/clangformatutils.cpp | 8 +- src/plugins/clangtools/clangtool.cpp | 8 +- .../clangtools/clangtoolsdiagnosticmodel.cpp | 8 +- .../clangtoolspreconfiguredsessiontests.cpp | 24 +- .../clangtools/clangtoolsprojectsettings.cpp | 2 +- .../clangtools/diagnosticconfigswidget.cpp | 4 +- .../clangtools/documentclangtoolrunner.cpp | 6 +- src/plugins/classview/classviewmanager.cpp | 13 +- .../classview/classviewparsertreeitem.cpp | 8 +- src/plugins/clearcase/clearcaseplugin.cpp | 6 +- .../cmakebuildconfiguration.cpp | 2 +- .../cmakefilecompletionassist.cpp | 5 +- .../cmakelocatorfilter.cpp | 12 +- .../cmakeprojectmanager.cpp | 12 +- ...ompilationdatabaseprojectmanagerplugin.cpp | 4 +- src/plugins/conan/conanplugin.cpp | 4 +- src/plugins/cppcheck/cppcheckplugin.cpp | 11 +- src/plugins/cppcheck/cppchecktrigger.cpp | 4 +- .../cppeditor/baseeditordocumentprocessor.cpp | 5 +- .../cppeditor/cppcodemodelsettings.cpp | 1 + src/plugins/cppeditor/cppeditorwidget.cpp | 6 +- src/plugins/cppeditor/cppfindreferences.cpp | 14 +- src/plugins/cppeditor/cppincludesfilter.cpp | 8 +- src/plugins/cppeditor/cppmodelmanager.cpp | 15 +- .../cppeditor/cppmodelmanager_test.cpp | 2 +- src/plugins/cppeditor/cppquickfixes.cpp | 4 +- src/plugins/cppeditor/cpptoolsjsextension.cpp | 5 +- src/plugins/cppeditor/cpptoolsreuse.cpp | 9 +- src/plugins/cppeditor/cpptoolstestcase.cpp | 8 +- .../cppeditor/generatedcodemodelsupport.cpp | 2 +- .../cppeditor/modelmanagertesthelper.cpp | 6 +- src/plugins/cppeditor/symbolsfindfilter.cpp | 5 +- src/plugins/debugger/debuggerplugin.cpp | 17 +- src/plugins/debugger/debuggerruncontrol.cpp | 7 +- src/plugins/designer/codemodelhelpers.cpp | 4 +- src/plugins/designer/qtcreatorintegration.cpp | 16 +- src/plugins/designer/resourcehandler.cpp | 15 +- src/plugins/gitlab/gitlabdialog.cpp | 4 +- src/plugins/gitlab/gitlabplugin.cpp | 18 +- src/plugins/languageclient/client.cpp | 8 +- .../languageclient/languageclientmanager.cpp | 10 +- .../languageclient/languageclientsettings.cpp | 2 +- .../languageclientsymbolsupport.cpp | 4 +- src/plugins/mcusupport/mcusupportplugin.cpp | 6 +- .../modeleditor/componentviewcontroller.cpp | 6 +- src/plugins/modeleditor/modelindexer.cpp | 6 +- .../editor/nimcompletionassistprovider.cpp | 2 +- src/plugins/perfprofiler/perfdatareader.cpp | 2 +- src/plugins/perfprofiler/perfloaddialog.cpp | 4 +- src/plugins/perfprofiler/perfprofilertool.cpp | 8 +- .../perfprofiler/perftracepointdialog.cpp | 4 +- .../projectexplorer/allprojectsfilter.cpp | 6 +- .../projectexplorer/allprojectsfind.cpp | 6 +- .../projectexplorer/buildconfiguration.cpp | 4 +- src/plugins/projectexplorer/buildmanager.cpp | 12 +- .../buildsettingspropertiespage.cpp | 6 +- src/plugins/projectexplorer/buildsystem.cpp | 4 +- .../projectexplorer/currentprojectfind.cpp | 8 +- .../projectexplorer/dependenciespanel.cpp | 22 +- .../projectexplorer/editorconfiguration.cpp | 8 +- src/plugins/projectexplorer/extracompiler.cpp | 4 +- .../projectexplorer/fileinsessionfinder.cpp | 12 +- .../filesinallprojectsfind.cpp | 4 +- .../jsonwizard/jsonsummarypage.cpp | 4 +- src/plugins/projectexplorer/kitchooser.cpp | 4 +- .../miniprojecttargetselector.cpp | 56 +-- src/plugins/projectexplorer/project.cpp | 46 +- src/plugins/projectexplorer/project.h | 5 +- .../projectexplorer/projectexplorer.cpp | 171 +++---- .../projectfilewizardextension.cpp | 5 +- src/plugins/projectexplorer/projectmanager.h | 74 ++- src/plugins/projectexplorer/projectmodels.cpp | 20 +- src/plugins/projectexplorer/projecttree.cpp | 22 +- .../projectexplorer/projecttreewidget.cpp | 4 +- .../projectexplorer/projectwelcomepage.cpp | 5 +- src/plugins/projectexplorer/projectwindow.cpp | 22 +- .../projectexplorer/projectwizardpage.cpp | 4 +- .../projectexplorer/runconfiguration.cpp | 5 +- .../runsettingspropertiespage.cpp | 9 +- src/plugins/projectexplorer/session.cpp | 448 ++++++++---------- src/plugins/projectexplorer/session.h | 73 +-- src/plugins/projectexplorer/sessionmodel.cpp | 7 +- src/plugins/projectexplorer/target.cpp | 79 ++- src/plugins/projectexplorer/target.h | 7 +- .../projectexplorer/targetsettingspanel.cpp | 14 +- .../projectexplorer/targetsetuppage.cpp | 2 +- src/plugins/python/pipsupport.cpp | 2 +- src/plugins/python/pythoneditor.cpp | 6 +- src/plugins/python/pythonlanguageclient.cpp | 2 +- src/plugins/python/pythonutils.cpp | 10 +- .../qbsprojectmanagerplugin.cpp | 18 +- .../librarydetailscontroller.cpp | 11 +- .../qmakeprojectmanager/profileeditor.cpp | 10 +- .../qmakeprojectmanagerplugin.cpp | 12 +- .../assetexporterplugin/assetexportdialog.cpp | 4 +- .../assetexporterplugin/assetexporter.cpp | 4 +- .../assetexporterplugin.cpp | 12 +- .../assetslibrary/assetslibraryview.cpp | 2 +- .../componentcore/changestyleaction.cpp | 4 +- .../contentlibrary/contentlibraryview.cpp | 4 +- .../components/eventlist/eventlist.cpp | 4 +- .../components/integration/designdocument.cpp | 8 +- .../itemlibraryassetimportdialog.cpp | 6 +- .../itemlibrary/itemlibrarymodel.cpp | 4 +- .../itemlibrary/itemlibraryview.cpp | 2 +- .../components/navigator/navigatorview.cpp | 6 +- .../propertyeditor/fileresourcesmodel.cpp | 4 +- src/plugins/qmldesigner/documentmanager.cpp | 13 +- src/plugins/qmldesigner/generateresource.cpp | 22 +- .../qmldesignerexternaldependencies.cpp | 8 +- src/plugins/qmldesigner/qmldesignerplugin.cpp | 6 +- .../qmldesigner/qmldesignerprojectmanager.cpp | 16 +- .../qmlpreviewplugin/qmlpreviewactions.cpp | 8 +- src/plugins/qmljstools/qmljslocatordata.cpp | 6 +- src/plugins/qmljstools/qmljsmodelmanager.cpp | 9 +- src/plugins/qmlpreview/qmlpreviewplugin.cpp | 10 +- .../qmlpreview/qmlpreviewruncontrol.cpp | 2 +- .../qmlprofilerdetailsrewriter.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 4 +- .../tests/qmlprofilerdetailsrewriter_test.cpp | 25 +- .../cmakegen/cmakeprojectconverter.cpp | 13 +- .../cmakegen/generatecmakelists.cpp | 21 +- .../projectfilecontenttools.cpp | 2 +- .../projectfilecontenttools.h | 2 +- .../qmlmultilanguageaspect.cpp | 4 +- src/plugins/qmlprojectmanager/qmlproject.cpp | 4 +- .../qmlprojectmanager/qmlprojectplugin.cpp | 6 +- .../qmlprojectrunconfiguration.cpp | 4 +- src/plugins/qnx/qnxdebugsupport.cpp | 4 +- src/plugins/qtsupport/baseqtversion.cpp | 7 +- src/plugins/qtsupport/externaleditors.cpp | 4 +- src/plugins/qtsupport/qtsupportplugin.cpp | 6 +- .../scxmleditor/scxmleditordocument.cpp | 2 +- src/plugins/squish/squishfilehandler.cpp | 5 +- src/plugins/todo/todoitemsprovider.cpp | 7 +- src/plugins/valgrind/callgrindtool.cpp | 4 +- src/plugins/valgrind/memcheckerrorview.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 10 +- src/plugins/valgrind/suppressiondialog.cpp | 8 +- src/plugins/vcsbase/vcsbaseeditor.cpp | 4 +- src/plugins/vcsbase/vcsbaseplugin.cpp | 14 +- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 4 +- 170 files changed, 1176 insertions(+), 1040 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 5477bf14bfe..530a0bb6bd4 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 252e4ee1fba..1902631fd6b 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index e4d47be7337..e77c38ea26a 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp index 009a0219430..9c6a616abe3 100644 --- a/src/plugins/android/androidmanifesteditorwidget.cpp +++ b/src/plugins/android/androidmanifesteditorwidget.cpp @@ -19,8 +19,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -73,7 +73,7 @@ static bool checkPackageName(const QString &packageName) static Target *androidTarget(const FilePath &fileName) { - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { if (Target *target = project->activeTarget()) { Kit *kit = target->kit(); if (DeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index b8ff5dbe0b8..0eeb890f821 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp index 98b804b16d3..28475f3870b 100644 --- a/src/plugins/autotest/autotestplugin.cpp +++ b/src/plugins/autotest/autotestplugin.cpp @@ -32,22 +32,28 @@ #include #include #include + #include #include #include + #include #include + #include + #include #include #include #include +#include #include #include -#include #include + #include #include + #include #include #include @@ -148,11 +154,11 @@ AutotestPluginPrivate::AutotestPluginPrivate() m_testTreeModel.synchronizeTestFrameworks(); m_testTreeModel.synchronizeTestTools(); - auto sessionManager = ProjectExplorer::SessionManager::instance(); - connect(sessionManager, &ProjectExplorer::SessionManager::startupProjectChanged, + auto sessionManager = ProjectExplorer::ProjectManager::instance(); + connect(sessionManager, &ProjectExplorer::ProjectManager::startupProjectChanged, this, [this] { m_runconfigCache.clear(); }); - connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject, + connect(sessionManager, &ProjectExplorer::ProjectManager::aboutToRemoveProject, this, [](ProjectExplorer::Project *project) { const auto it = s_projectSettings.constFind(project); if (it != s_projectSettings.constEnd()) { @@ -471,7 +477,7 @@ void AutotestPluginPrivate::onRunUnderCursorTriggered(TestRunMode mode) TestFrameworks AutotestPlugin::activeTestFrameworks() { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); TestFrameworks sorted; if (!project || projectSettings(project)->useGlobalSettings()) { sorted = Utils::filtered(TestFrameworkManager::registeredFrameworks(), @@ -489,7 +495,7 @@ TestFrameworks AutotestPlugin::activeTestFrameworks() void AutotestPlugin::updateMenuItemsEnabledState() { - const ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); const ProjectExplorer::Target *target = project ? project->activeTarget() : nullptr; const bool canScan = !dd->m_testRunner.isTestRunning() && dd->m_testCodeParser.state() == TestCodeParser::Idle; diff --git a/src/plugins/autotest/boost/boosttesttreeitem.cpp b/src/plugins/autotest/boost/boosttesttreeitem.cpp index 4b53d92754e..957ff73021a 100644 --- a/src/plugins/autotest/boost/boosttesttreeitem.cpp +++ b/src/plugins/autotest/boost/boosttesttreeitem.cpp @@ -11,7 +11,9 @@ #include "../itestframework.h" #include -#include + +#include + #include #include @@ -156,7 +158,7 @@ static QString handleSpecialFunctionNames(const QString &name) QList BoostTestTreeItem::getAllTestConfigurations() const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -200,7 +202,7 @@ QList BoostTestTreeItem::getTestConfigurations( std::function predicate) const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -261,7 +263,7 @@ QList BoostTestTreeItem::getFailedTestConfigurations() con ITestConfiguration *BoostTestTreeItem::testConfiguration() const { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(project, return nullptr); const auto cppMM = CppEditor::CppModelManager::instance(); QTC_ASSERT(cppMM, return nullptr); diff --git a/src/plugins/autotest/catch/catchtreeitem.cpp b/src/plugins/autotest/catch/catchtreeitem.cpp index fe69fece87e..034c7ab1d04 100644 --- a/src/plugins/autotest/catch/catchtreeitem.cpp +++ b/src/plugins/autotest/catch/catchtreeitem.cpp @@ -10,8 +10,10 @@ #include "../itestframework.h" #include + #include -#include +#include + #include using namespace Utils; @@ -30,7 +32,7 @@ static QString nonRootDisplayName(const CatchTreeItem *it) { if (it->type() != TestTreeItem::TestSuite) return it->name(); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) return it->name(); TestTreeItem *parent = it->parentItem(); @@ -141,7 +143,7 @@ bool CatchTreeItem::canProvideDebugConfiguration() const ITestConfiguration *CatchTreeItem::testConfiguration() const { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(project, return nullptr); const auto cppMM = CppEditor::CppModelManager::instance(); QTC_ASSERT(cppMM, return nullptr); @@ -244,7 +246,7 @@ QList CatchTreeItem::getSelectedTestConfigurations() const QList CatchTreeItem::getFailedTestConfigurations() const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -271,7 +273,7 @@ QList CatchTreeItem::getTestConfigurationsForFile(const Fi const auto cppMM = CppEditor::CppModelManager::instance(); QTC_ASSERT(cppMM, return result); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -293,7 +295,7 @@ QList CatchTreeItem::getTestConfigurationsForFile(const Fi testConfig = new CatchConfiguration(framework()); testConfig->setTestCases(testCases); testConfig->setProjectFile(item->proFile()); - testConfig->setProject(ProjectExplorer::SessionManager::startupProject()); + testConfig->setProject(ProjectExplorer::ProjectManager::startupProject()); testConfig->setInternalTargets(cppMM->internalTargets(item->filePath())); result << testConfig; } @@ -314,7 +316,7 @@ QString CatchTreeItem::stateSuffix() const QList CatchTreeItem::getTestConfigurations(bool ignoreCheckState) const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; diff --git a/src/plugins/autotest/ctest/ctesttreeitem.cpp b/src/plugins/autotest/ctest/ctesttreeitem.cpp index 3e59c2db81c..dac1b6da008 100644 --- a/src/plugins/autotest/ctest/ctesttreeitem.cpp +++ b/src/plugins/autotest/ctest/ctesttreeitem.cpp @@ -14,11 +14,11 @@ #include #include #include -#include +#include #include #include -#include +#include using namespace Utils; @@ -79,7 +79,7 @@ QVariant CTestTreeItem::data(int column, int role) const QList CTestTreeItem::testConfigurationsFor(const QStringList &selected) const { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) return {}; diff --git a/src/plugins/autotest/gtest/gtesttreeitem.cpp b/src/plugins/autotest/gtest/gtesttreeitem.cpp index c79ae93d1b9..f91b68f0e38 100644 --- a/src/plugins/autotest/gtest/gtesttreeitem.cpp +++ b/src/plugins/autotest/gtest/gtesttreeitem.cpp @@ -10,7 +10,9 @@ #include "../autotesttr.h" #include -#include + +#include +#include #include #include @@ -146,7 +148,7 @@ QVariant GTestTreeItem::data(int column, int role) const ITestConfiguration *GTestTreeItem::testConfiguration() const { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(project, return nullptr); GTestConfiguration *config = nullptr; @@ -252,7 +254,7 @@ static void collectFailedTestInfo(const GTestTreeItem *item, QList GTestTreeItem::getTestConfigurations(bool ignoreCheckState) const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -291,7 +293,7 @@ QList GTestTreeItem::getSelectedTestConfigurations() const QList GTestTreeItem::getFailedTestConfigurations() const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -316,7 +318,7 @@ QList GTestTreeItem::getFailedTestConfigurations() const QList GTestTreeItem::getTestConfigurationsForFile(const FilePath &fileName) const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -503,7 +505,7 @@ QSet internalTargets(const TestTreeItem &item) { QSet result; const auto cppMM = CppEditor::CppModelManager::instance(); - const auto projectInfo = cppMM->projectInfo(ProjectExplorer::SessionManager::startupProject()); + const auto projectInfo = cppMM->projectInfo(ProjectExplorer::ProjectManager::startupProject()); if (!projectInfo) return {}; const FilePath filePath = item.filePath(); diff --git a/src/plugins/autotest/qtest/qttesttreeitem.cpp b/src/plugins/autotest/qtest/qttesttreeitem.cpp index 2f846372822..81f95c17752 100644 --- a/src/plugins/autotest/qtest/qttesttreeitem.cpp +++ b/src/plugins/autotest/qtest/qttesttreeitem.cpp @@ -9,7 +9,9 @@ #include "../itestframework.h" #include -#include + +#include + #include using namespace Utils; @@ -116,7 +118,7 @@ bool QtTestTreeItem::canProvideDebugConfiguration() const ITestConfiguration *QtTestTreeItem::testConfiguration() const { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(project, return nullptr); const auto cppMM = CppEditor::CppModelManager::instance(); QTC_ASSERT(cppMM, return nullptr); @@ -195,7 +197,7 @@ static void fillTestConfigurationsFromCheckState(const TestTreeItem *item, testConfig = new QtTestConfiguration(item->framework()); testConfig->setTestCases(testCases); testConfig->setProjectFile(item->proFile()); - testConfig->setProject(ProjectExplorer::SessionManager::startupProject()); + testConfig->setProject(ProjectExplorer::ProjectManager::startupProject()); testConfig->setInternalTargets(cppMM->internalTargets(item->filePath())); testConfigurations << testConfig; } @@ -229,7 +231,7 @@ static void collectFailedTestInfo(TestTreeItem *item, QListframework()); testConfig->setTestCases(testCases); testConfig->setProjectFile(item->proFile()); - testConfig->setProject(ProjectExplorer::SessionManager::startupProject()); + testConfig->setProject(ProjectExplorer::ProjectManager::startupProject()); testConfig->setInternalTargets(cppMM->internalTargets(item->filePath())); testConfigs << testConfig; } @@ -246,7 +248,7 @@ QList QtTestTreeItem::getAllTestConfigurations() const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -269,7 +271,7 @@ QList QtTestTreeItem::getAllTestConfigurations() const QList QtTestTreeItem::getSelectedTestConfigurations() const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -292,7 +294,7 @@ QList QtTestTreeItem::getTestConfigurationsForFile(const F { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index f5b79d8075c..b8035f11a7a 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -12,10 +12,13 @@ #include #include -#include + +#include + #include #include #include + #include #include #include @@ -324,8 +327,8 @@ void QuickTestParser::doUpdateWatchPaths(const QStringList &directories) QuickTestParser::QuickTestParser(ITestFramework *framework) : CppParser(framework) { - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, this, [this] { + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, this, [this] { const QStringList &dirs = m_directoryWatcher.directories(); if (!dirs.isEmpty()) m_directoryWatcher.removePaths(dirs); diff --git a/src/plugins/autotest/quick/quicktesttreeitem.cpp b/src/plugins/autotest/quick/quicktesttreeitem.cpp index 49358f49ebd..a7d6e330ea4 100644 --- a/src/plugins/autotest/quick/quicktesttreeitem.cpp +++ b/src/plugins/autotest/quick/quicktesttreeitem.cpp @@ -9,7 +9,9 @@ #include "../itestframework.h" #include -#include + +#include + #include using namespace Utils; @@ -108,7 +110,7 @@ bool QuickTestTreeItem::canProvideDebugConfiguration() const ITestConfiguration *QuickTestTreeItem::testConfiguration() const { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(project, return nullptr); QuickTestConfiguration *config = nullptr; @@ -147,7 +149,7 @@ static QList testConfigurationsFor( const TestTreeItem *rootNode, const std::function &predicate) { QTC_ASSERT(rootNode, return {}); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || rootNode->type() != TestTreeItem::Root) return {}; @@ -171,7 +173,7 @@ static QList testConfigurationsFor( if (it == configurationForProFiles.end()) { auto tc = new QuickTestConfiguration(treeItem->framework()); tc->setProjectFile(treeItem->proFile()); - tc->setProject(ProjectExplorer::SessionManager::startupProject()); + tc->setProject(ProjectExplorer::ProjectManager::startupProject()); tc->setInternalTargets(internalTargets(treeItem->proFile())); it = configurationForProFiles.insert(treeItem->proFile(), tc); } @@ -206,7 +208,7 @@ QList QuickTestTreeItem::getAllTestConfigurations() const { QList result; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project || type() != Root) return result; @@ -369,7 +371,7 @@ QSet internalTargets(const FilePath &proFile) { QSet result; const auto cppMM = CppEditor::CppModelManager::instance(); - const auto projectInfo = cppMM->projectInfo(ProjectExplorer::SessionManager::startupProject()); + const auto projectInfo = cppMM->projectInfo(ProjectExplorer::ProjectManager::startupProject()); if (!projectInfo) return {}; for (const CppEditor::ProjectPart::ConstPtr &projectPart : projectInfo->projectParts()) { diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index a42f3aa77d4..3b9c396fedf 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -33,7 +33,7 @@ using namespace ProjectExplorer; static bool isProjectParsing() { - const BuildSystem *bs = SessionManager::startupBuildSystem(); + const BuildSystem *bs = ProjectManager::startupBuildSystem(); return bs && bs->isParsing(); } @@ -73,7 +73,7 @@ void TestCodeParser::setState(State state) } m_parserState = state; - if (m_parserState == Idle && SessionManager::startupProject()) { + if (m_parserState == Idle && ProjectManager::startupProject()) { if (m_postponedUpdateType == UpdateType::FullUpdate || m_dirty) { emitUpdateTestTree(); } else if (m_postponedUpdateType == UpdateType::PartialUpdate) { @@ -130,7 +130,7 @@ void TestCodeParser::updateTestTree(const QSet &parsers) return; } - if (!SessionManager::startupProject()) + if (!ProjectManager::startupProject()) return; m_postponedUpdateType = UpdateType::NoUpdate; @@ -149,7 +149,7 @@ void TestCodeParser::onDocumentUpdated(const FilePath &fileName, bool isQmlFile) if (isProjectParsing() || m_codeModelParsing || m_postponedUpdateType == UpdateType::FullUpdate) return; - Project *project = SessionManager::startupProject(); + Project *project = ProjectManager::startupProject(); if (!project) return; // Quick tests: qml files aren't necessarily listed inside project files @@ -185,7 +185,7 @@ void TestCodeParser::onStartupProjectChanged(Project *project) void TestCodeParser::onProjectPartsUpdated(Project *project) { - if (project != SessionManager::startupProject()) + if (project != ProjectManager::startupProject()) return; if (isProjectParsing() || m_codeModelParsing) m_postponedUpdateType = UpdateType::FullUpdate; @@ -277,7 +277,7 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList #include #include -#include +#include #include #include @@ -100,7 +100,7 @@ void TestConfiguration::completeTestInformation(RunConfiguration *rc, qCDebug(LOG) << "Executable has been set already - not completing configuration again."; return; } - Project *startupProject = SessionManager::startupProject(); + Project *startupProject = ProjectManager::startupProject(); if (!startupProject || startupProject != project()) return; @@ -145,7 +145,7 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode) } qCDebug(LOG) << "Failed to complete - using 'normal' way."; } - Project *startupProject = SessionManager::startupProject(); + Project *startupProject = ProjectManager::startupProject(); if (!startupProject || startupProject != project()) { setProject(nullptr); return; diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp index 100eed89ed9..95defb21ec4 100644 --- a/src/plugins/autotest/testnavigationwidget.cpp +++ b/src/plugins/autotest/testnavigationwidget.cpp @@ -18,9 +18,11 @@ #include #include #include + #include #include -#include +#include + #include #include #include @@ -87,8 +89,8 @@ TestNavigationWidget::TestNavigationWidget(QWidget *parent) : connect(m_model, &TestTreeModel::updatedActiveFrameworks, this, [this](int numberOfActive) { m_missingFrameworksWidget->setVisible(numberOfActive == 0); }); - ProjectExplorer::SessionManager *sm = ProjectExplorer::SessionManager::instance(); - connect(sm, &ProjectExplorer::SessionManager::startupProjectChanged, + ProjectExplorer::ProjectManager *sm = ProjectExplorer::ProjectManager::instance(); + connect(sm, &ProjectExplorer::ProjectManager::startupProjectChanged, this, [this](ProjectExplorer::Project * /*project*/) { m_expandedStateCache.clear(); }); diff --git a/src/plugins/autotest/testprojectsettings.cpp b/src/plugins/autotest/testprojectsettings.cpp index 862fc8a24f4..5f745637db8 100644 --- a/src/plugins/autotest/testprojectsettings.cpp +++ b/src/plugins/autotest/testprojectsettings.cpp @@ -7,7 +7,7 @@ #include "testframeworkmanager.h" #include -#include +#include #include #include diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 1f83ff56c11..26ef727fd36 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include @@ -213,7 +213,7 @@ static QString firstNonEmptyTestCaseTarget(const TestConfiguration *config) static RunConfiguration *getRunConfiguration(const QString &buildTargetKey) { - const Project *project = SessionManager::startupProject(); + const Project *project = ProjectManager::startupProject(); if (!project) return nullptr; const Target *target = project->activeTarget(); @@ -295,7 +295,7 @@ int TestRunner::precheckTestConfigurations() void TestRunner::onBuildSystemUpdated() { - Target *target = SessionManager::startupTarget(); + Target *target = ProjectManager::startupTarget(); if (QTC_GUARD(target)) disconnect(target, &Target::buildSystemUpdated, this, &TestRunner::onBuildSystemUpdated); if (!m_skipTargetsCheck) { @@ -310,7 +310,7 @@ void TestRunner::runTestsHelper() bool projectChanged = false; for (ITestConfiguration *itc : std::as_const(m_selectedTests)) { if (itc->testBase()->type() == ITestBase::Tool) { - if (itc->project() != SessionManager::startupProject()) { + if (itc->project() != ProjectManager::startupProject()) { projectChanged = true; toBeRemoved.append(itc); } @@ -596,7 +596,7 @@ void TestRunner::debugTests() static bool executablesEmpty() { - Target *target = SessionManager::startupTarget(); + Target *target = ProjectManager::startupTarget(); const QList configs = target->runConfigurations(); QTC_ASSERT(!configs.isEmpty(), return false); if (auto execAspect = configs.first()->aspect()) @@ -609,7 +609,7 @@ void TestRunner::runOrDebugTests() if (!m_skipTargetsCheck) { if (executablesEmpty()) { m_skipTargetsCheck = true; - Target *target = SessionManager::startupTarget(); + Target *target = ProjectManager::startupTarget(); QTimer::singleShot(5000, this, [this, target = QPointer(target)] { if (target) { disconnect(target, &Target::buildSystemUpdated, @@ -666,7 +666,7 @@ void TestRunner::buildFinished(bool success) static RunAfterBuildMode runAfterBuild() { - Project *project = SessionManager::startupProject(); + Project *project = ProjectManager::startupProject(); if (!project) return RunAfterBuildMode::None; @@ -786,7 +786,7 @@ void RunConfigurationSelectionDialog::populate() { m_rcCombo->addItem({}, QStringList{{}, {}, {}}); // empty default - if (auto project = SessionManager::startupProject()) { + if (auto project = ProjectManager::startupProject()) { if (auto target = project->activeTarget()) { for (RunConfiguration *rc : target->runConfigurations()) { auto runnable = rc->runnable(); diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index f21e9349c32..4e3d010ad45 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -10,12 +10,16 @@ #include "testprojectsettings.h" #include + #include #include -#include +#include #include + #include + #include + #include #include #include @@ -70,8 +74,8 @@ void TestTreeModel::setupParsingConnections() m_parser->setDirty(); m_parser->setState(TestCodeParser::Idle); - SessionManager *sm = SessionManager::instance(); - connect(sm, &SessionManager::startupProjectChanged, this, [this, sm](Project *project) { + ProjectManager *sm = ProjectManager::instance(); + connect(sm, &ProjectManager::startupProjectChanged, this, [this, sm](Project *project) { synchronizeTestFrameworks(); // we might have project settings m_parser->onStartupProjectChanged(project); removeAllTestToolItems(); @@ -226,7 +230,7 @@ static QList testItemsByName(TestTreeItem *root, const QString void TestTreeModel::onTargetChanged(Target *target) { if (target && target->buildSystem()) { - const Target *topLevelTarget = SessionManager::startupProject()->targets().first(); + const Target *topLevelTarget = ProjectManager::startupProject()->targets().first(); connect(topLevelTarget->buildSystem(), &BuildSystem::testInformationUpdated, this, &TestTreeModel::onBuildSystemTestsUpdated, Qt::UniqueConnection); disconnect(target->project(), &Project::activeTargetChanged, @@ -236,7 +240,7 @@ void TestTreeModel::onTargetChanged(Target *target) void TestTreeModel::onBuildSystemTestsUpdated() { - const BuildSystem *bs = SessionManager::startupBuildSystem(); + const BuildSystem *bs = ProjectManager::startupBuildSystem(); if (!bs || !bs->project()) return; @@ -333,7 +337,7 @@ void TestTreeModel::synchronizeTestFrameworks() void TestTreeModel::synchronizeTestTools() { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); TestTools tools; if (!project || AutotestPlugin::projectSettings(project)->useGlobalSettings()) { tools = Utils::filtered(TestFrameworkManager::registeredTestTools(), diff --git a/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp b/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp index 773ec410666..faa32fea086 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvproject.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp index e7c5a4e388e..4e98648147a 100644 --- a/src/plugins/bookmarks/bookmarkmanager.cpp +++ b/src/plugins/bookmarks/bookmarkmanager.cpp @@ -12,8 +12,10 @@ #include #include #include + #include #include + #include #include #include @@ -29,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index 0f7d8d96627..b0250bf819a 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include #include #include @@ -48,7 +49,7 @@ void ClangCodeModelPlugin::generateCompilationDB() { using namespace CppEditor; - Target *target = SessionManager::startupTarget(); + Target *target = ProjectManager::startupTarget(); if (!target) return; @@ -101,7 +102,7 @@ void ClangCodeModelPlugin::createCompilationDBAction() Tr::tr("Generate Compilation Database"), Tr::tr("Generate Compilation Database for \"%1\""), ParameterAction::AlwaysEnabled, this); - Project *startupProject = SessionManager::startupProject(); + Project *startupProject = ProjectManager::startupProject(); if (startupProject) m_generateCompilationDBAction->setParameter(startupProject->displayName()); Command *command = ActionManager::registerAction(m_generateCompilationDBAction, @@ -128,7 +129,7 @@ void ClangCodeModelPlugin::createCompilationDBAction() "Generator is already running."); return; } - Project * const project = SessionManager::startupProject(); + Project * const project = ProjectManager::startupProject(); if (!project) { MessageManager::writeDisrupting("Cannot generate compilation database: " "No active project."); @@ -146,21 +147,21 @@ void ClangCodeModelPlugin::createCompilationDBAction() }); connect(CppEditor::CppModelManager::instance(), &CppEditor::CppModelManager::projectPartsUpdated, this, [this](Project *project) { - if (project != SessionManager::startupProject()) + if (project != ProjectManager::startupProject()) return; m_generateCompilationDBAction->setParameter(project->displayName()); }); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, [this](Project *project) { m_generateCompilationDBAction->setParameter(project ? project->displayName() : ""); }); - connect(SessionManager::instance(), &SessionManager::projectDisplayNameChanged, + connect(ProjectManager::instance(), &ProjectManager::projectDisplayNameChanged, this, [this](Project *project) { - if (project != SessionManager::startupProject()) + if (project != ProjectManager::startupProject()) return; m_generateCompilationDBAction->setParameter(project->displayName()); }); - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this](Project *project) { project->registerGenerator(Constants::GENERATE_COMPILATION_DB, m_generateCompilationDBAction->text(), diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 8a7d48173d6..238b46a09b4 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include @@ -701,7 +701,7 @@ bool ClangdClient::fileBelongsToProject(const Utils::FilePath &filePath) const { if (CppEditor::ClangdSettings::instance().granularity() == CppEditor::ClangdSettings::Granularity::Session) { - return SessionManager::projectForFile(filePath); + return ProjectManager::projectForFile(filePath); } return Client::fileBelongsToProject(filePath); } diff --git a/src/plugins/clangcodemodel/clangdfindreferences.cpp b/src/plugins/clangcodemodel/clangdfindreferences.cpp index 8a2d3faaeff..2130587a2d5 100644 --- a/src/plugins/clangcodemodel/clangdfindreferences.cpp +++ b/src/plugins/clangcodemodel/clangdfindreferences.cpp @@ -21,9 +21,10 @@ #include #include +#include #include #include -#include +#include #include @@ -451,7 +452,7 @@ void ClangdFindReferences::Private::addSearchResultsForFile(const FilePath &file item.setContainingFunctionName(getContainingFunction(astPath, range).detail()); if (search->supportsReplace()) { - const bool fileInSession = SessionManager::projectForFile(file); + const bool fileInSession = ProjectManager::projectForFile(file); item.setSelectForReplacement(fileInSession); if (fileInSession && file.baseName().compare(replacementData->oldSymbolName, Qt::CaseInsensitive) == 0) { diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 194e6466464..9a6dee28eca 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -11,13 +11,17 @@ #include #include #include + #include #include -#include + +#include + #include #include #include + #include #include @@ -141,7 +145,7 @@ void ClangGlobalSymbolFilter::prepareSearch(const QString &entry) { m_cppFilter->prepareSearch(entry); QList clients; - for (ProjectExplorer::Project * const project : ProjectExplorer::SessionManager::projects()) { + for (ProjectExplorer::Project * const project : ProjectExplorer::ProjectManager::projects()) { if (Client * const client = ClangModelManagerSupport::clientForProject(project)) clients << client; } diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 64a8dac7bdf..5e3a84c46ef 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ using namespace CppEditor; using namespace LanguageClient; +using namespace ProjectExplorer; using namespace Utils; namespace ClangCodeModel::Internal { @@ -66,7 +68,7 @@ static ProjectExplorer::Project *fallbackProject() { if (ProjectExplorer::Project * const p = ProjectExplorer::ProjectTree::currentProject()) return p; - return ProjectExplorer::SessionManager::startupProject(); + return ProjectExplorer::ProjectManager::startupProject(); } static bool sessionModeEnabled() @@ -87,7 +89,7 @@ static const QList projectsForClient(const Client *c { QList projects; if (sessionModeEnabled()) { - for (ProjectExplorer::Project * const p : ProjectExplorer::SessionManager::projects()) { + for (ProjectExplorer::Project * const p : ProjectExplorer::ProjectManager::projects()) { if (ClangdProjectSettings(p).settings().useClangd) projects << p; } @@ -228,14 +230,13 @@ ClangModelManagerSupport::ClangModelManagerSupport() } }); - auto *sessionManager = ProjectExplorer::SessionManager::instance(); - connect(sessionManager, &ProjectExplorer::SessionManager::projectRemoved, + auto projectManager = ProjectExplorer::ProjectManager::instance(); + connect(projectManager, &ProjectExplorer::ProjectManager::projectRemoved, this, [this] { if (!sessionModeEnabled()) claimNonProjectSources(clientForProject(fallbackProject())); }); - connect(sessionManager, &ProjectExplorer::SessionManager::sessionLoaded, - this, [this] { + connect(SessionManager::instance(), &SessionManager::sessionLoaded, this, [this] { if (sessionModeEnabled()) onClangdSettingsChanged(); }); @@ -357,7 +358,7 @@ void ClangModelManagerSupport::checkUnused(const Link &link, Core::SearchResult const LinkHandler &callback) { if (const ProjectExplorer::Project * const project - = ProjectExplorer::SessionManager::projectForFile(link.targetFilePath)) { + = ProjectExplorer::ProjectManager::projectForFile(link.targetFilePath)) { if (ClangdClient * const client = clientWithProject(project); client && client->isFullyIndexed()) { client->checkUnused(link, search, callback); @@ -435,7 +436,7 @@ static bool isProjectDataUpToDate( ProjectExplorer::Project *project, ProjectInfoList projectInfo, const FilePath &jsonDbDir) { - if (project && !ProjectExplorer::SessionManager::hasProject(project)) + if (project && !ProjectExplorer::ProjectManager::hasProject(project)) return false; const ClangdSettings settings(ClangdProjectSettings(project).settings()); if (!settings.useClangd()) @@ -531,7 +532,7 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr hasDocuments = true; continue; } - const Project * const docProject = SessionManager::projectForFile(doc->filePath()); + const Project * const docProject = ProjectManager::projectForFile(doc->filePath()); if (currentClient && currentClient->project() && currentClient->project() != project && currentClient->project() == docProject) { @@ -571,8 +572,8 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr ProjectNode *rootNode = nullptr; if (project) rootNode = project->rootProjectNode(); - else if (SessionManager::startupProject()) - rootNode = SessionManager::startupProject()->rootProjectNode(); + else if (ProjectManager::startupProject()) + rootNode = ProjectManager::startupProject()->rootProjectNode(); if (!rootNode) return; const Node * const cxxNode = rootNode->findNode([](Node *n) { @@ -647,7 +648,7 @@ void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *client) } if (!ClangdSettings::instance().sizeIsOkay(doc->filePath())) continue; - if (ProjectExplorer::SessionManager::projectForFile(doc->filePath())) + if (ProjectExplorer::ProjectManager::projectForFile(doc->filePath())) continue; if (client->project() && !ProjectFile::isHeader(doc->filePath())) continue; @@ -672,7 +673,7 @@ void ClangModelManagerSupport::watchForExternalChanges() if (!ProjectFile::isSource(kind) && !ProjectFile::isHeader(kind)) continue; ProjectExplorer::Project * const project - = ProjectExplorer::SessionManager::projectForFile(file); + = ProjectExplorer::ProjectManager::projectForFile(file); if (!project) continue; @@ -698,7 +699,7 @@ void ClangModelManagerSupport::watchForInternalChanges() if (!ProjectFile::isSource(kind) && !ProjectFile::isHeader(kind)) continue; ProjectExplorer::Project * const project - = ProjectExplorer::SessionManager::projectForFile(fp); + = ProjectExplorer::ProjectManager::projectForFile(fp); if (!project) continue; if (ClangdClient * const client = clientForProject(project); @@ -735,7 +736,7 @@ void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor) connectToWidgetsMarkContextMenuRequested(editor->widget()); ProjectExplorer::Project * project - = ProjectExplorer::SessionManager::projectForFile(document->filePath()); + = ProjectExplorer::ProjectManager::projectForFile(document->filePath()); const ClangdSettings settings(ClangdProjectSettings(project).settings()); if (!settings.sizeIsOkay(textDocument->filePath())) return; @@ -855,7 +856,7 @@ void ClangModelManagerSupport::onClangdSettingsChanged() { const bool sessionMode = sessionModeEnabled(); - for (ProjectExplorer::Project * const project : ProjectExplorer::SessionManager::projects()) { + for (ProjectExplorer::Project * const project : ProjectExplorer::ProjectManager::projects()) { const CppEditor::ClangdSettings settings( CppEditor::ClangdProjectSettings(project).settings()); ClangdClient * const client = clientWithProject(project); diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index affabfec671..9ab44472304 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -744,7 +744,7 @@ void ClangFormatBaseIndenter::autoIndent(const QTextCursor &cursor, clang::format::FormatStyle overrideStyle(const Utils::FilePath &fileName) { const ProjectExplorer::Project *projectForFile - = ProjectExplorer::SessionManager::projectForFile(fileName); + = ProjectExplorer::ProjectManager::projectForFile(fileName); const TextEditor::ICodeStylePreferences *preferences = projectForFile diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 94e0fafd8e0..67d5171b010 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index d1d6bee684b..a7a766768eb 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include @@ -211,7 +211,7 @@ bool getProjectOverriddenSettings(const ProjectExplorer::Project *project) bool getCurrentOverriddenSettings(const Utils::FilePath &filePath) { - const ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( + const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile( filePath); return getProjectUseGlobalSettings(project) @@ -233,7 +233,7 @@ ClangFormatSettings::Mode getProjectIndentationOrFormattingSettings( ClangFormatSettings::Mode getCurrentIndentationOrFormattingSettings(const Utils::FilePath &filePath) { - const ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( + const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile( filePath); return getProjectUseGlobalSettings(project) @@ -264,7 +264,7 @@ Utils::FilePath configForFile(const Utils::FilePath &fileName) return findConfig(fileName); const ProjectExplorer::Project *projectForFile - = ProjectExplorer::SessionManager::projectForFile(fileName); + = ProjectExplorer::ProjectManager::projectForFile(fileName); const TextEditor::ICodeStylePreferences *preferences = projectForFile diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index afe60be7dc8..bf13622b590 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -342,7 +342,7 @@ static FileInfos sortedFileInfos(const QVector static RunSettings runSettings() { - if (Project *project = SessionManager::startupProject()) { + if (Project *project = ProjectManager::startupProject()) { const auto projectSettings = ClangToolsProjectSettings::getSettings(project); if (!projectSettings->useGlobalSettings()) return projectSettings->runSettings(); @@ -611,7 +611,7 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection, const RunSettings &runSettings, const CppEditor::ClangDiagnosticConfig &diagnosticConfig) { - Project *project = SessionManager::startupProject(); + Project *project = ProjectManager::startupProject(); QTC_ASSERT(project, return); QTC_ASSERT(project->activeTarget(), return); @@ -870,7 +870,7 @@ static CheckResult canAnalyze() Tr::tr("Set a valid Clazy-Standalone executable.")}; } - if (Project *project = SessionManager::startupProject()) { + if (Project *project = ProjectManager::startupProject()) { if (!canAnalyzeProject(project)) { return {CheckResult::ProjectNotSuitable, Tr::tr("Project \"%1\" is not a C/C++ project.") diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp index 39329c79f14..e0b797a1e0a 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp @@ -10,14 +10,14 @@ #include "diagnosticmark.h" #include -#include +#include + #include #include #include #include -#include #include #include @@ -484,8 +484,8 @@ DiagnosticFilterModel::DiagnosticFilterModel(QObject *parent) { // So that when a user closes and re-opens a project and *then* clicks "Suppress", // we enter that information into the project settings. - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::projectAdded, this, + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectAdded, this, [this](ProjectExplorer::Project *project) { if (!m_project && project->projectDirectory() == m_lastProjectDirectory) setProject(project); diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index 4b43fbc3e0d..4d4b34c1ef8 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -5,15 +5,17 @@ #include "clangtool.h" #include "clangtoolsdiagnostic.h" -#include "clangtoolsutils.h" #include + #include #include + #include #include #include #include +#include #include #include #include @@ -55,8 +57,8 @@ public: WaitForParsedProjects(const FilePaths &projects) : m_projectsToWaitFor(projects) { - connect(SessionManager::instance(), - &ProjectExplorer::SessionManager::projectFinishedParsing, + connect(ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing, this, &WaitForParsedProjects::onProjectFinishedParsing); } @@ -87,9 +89,9 @@ void PreconfiguredSessionTests::initTestCase() QSKIP("Session must not be already active."); // Load session - const FilePaths projects = SessionManager::projectsForSessionName(preconfiguredSessionName); + const FilePaths projects = ProjectManager::projectsForSessionName(preconfiguredSessionName); WaitForParsedProjects waitForParsedProjects(projects); - QVERIFY(SessionManager::loadSession(preconfiguredSessionName)); + QVERIFY(ProjectManager::loadSession(preconfiguredSessionName)); QVERIFY(waitForParsedProjects.wait()); } @@ -175,7 +177,7 @@ void PreconfiguredSessionTests::testPreconfiguredSession_data() bool hasAddedTestData = false; - for (Project *project : validProjects(SessionManager::projects())) { + for (Project *project : validProjects(ProjectManager::projects())) { for (Target *target : validTargets(project)) { hasAddedTestData = true; QTest::newRow(dataTagName(project, target)) << project << target; @@ -189,17 +191,17 @@ void PreconfiguredSessionTests::testPreconfiguredSession_data() bool PreconfiguredSessionTests::switchToProjectAndTarget(Project *project, Target *target) { - Project * const activeProject = SessionManager::startupProject(); + Project * const activeProject = ProjectManager::startupProject(); if (project == activeProject && target == activeProject->activeTarget()) return true; // OK, desired project/target already active. if (project != activeProject) - SessionManager::setStartupProject(project); + ProjectManager::setStartupProject(project); if (target != project->activeTarget()) { - QSignalSpy spyFinishedParsing(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::projectFinishedParsing); - SessionManager::setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade); + QSignalSpy spyFinishedParsing(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing); + project->setActiveTarget(target, ProjectExplorer::SetActive::NoCascade); QTC_ASSERT(spyFinishedParsing.wait(30000), return false); const QVariant projectArgument = spyFinishedParsing.takeFirst().constFirst(); diff --git a/src/plugins/clangtools/clangtoolsprojectsettings.cpp b/src/plugins/clangtools/clangtoolsprojectsettings.cpp index cde1731acbd..581a8ca57b6 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettings.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettings.cpp @@ -4,7 +4,7 @@ #include "clangtoolsprojectsettings.h" #include "clangtoolsdiagnostic.h" -#include +#include #include #include diff --git a/src/plugins/clangtools/diagnosticconfigswidget.cpp b/src/plugins/clangtools/diagnosticconfigswidget.cpp index 1d160befa22..a2b55be1b4b 100644 --- a/src/plugins/clangtools/diagnosticconfigswidget.cpp +++ b/src/plugins/clangtools/diagnosticconfigswidget.cpp @@ -14,8 +14,8 @@ #include #include +#include #include -#include #include #include @@ -1294,7 +1294,7 @@ void disableChecks(const QList &diagnostics) Utils::Id activeConfigId = settings->runSettings().diagnosticConfigId(); ClangToolsProjectSettings::ClangToolsProjectSettingsPtr projectSettings; - if (ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( + if (ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile( diagnostics.first().location.filePath)) { projectSettings = ClangToolsProjectSettings::getSettings(project); if (!projectSettings->useGlobalSettings()) diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index 81a7e8f5444..6a08b579f18 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -97,8 +97,8 @@ void DocumentClangToolRunner::scheduleRun() static Project *findProject(const FilePath &file) { - Project *project = SessionManager::projectForFile(file); - return project ? project : SessionManager::startupProject(); + Project *project = ProjectManager::projectForFile(file); + return project ? project : ProjectManager::startupProject(); } static VirtualFileSystemOverlay &vfso() diff --git a/src/plugins/classview/classviewmanager.cpp b/src/plugins/classview/classviewmanager.cpp index a98cec70442..7f4eeb955c6 100644 --- a/src/plugins/classview/classviewmanager.cpp +++ b/src/plugins/classview/classviewmanager.cpp @@ -8,8 +8,11 @@ #include #include + #include -#include + +#include + #include #include @@ -90,7 +93,7 @@ void ManagerPrivate::resetParser() cancelScheduledUpdate(); QHash> projectData; - for (const Project *project : SessionManager::projects()) { + for (const Project *project : ProjectManager::projects()) { projectData.insert(project->projectFilePath(), {project->displayName(), project->files(Project::SourceFiles)}); } @@ -201,8 +204,8 @@ void Manager::initialize() d->m_timer.setSingleShot(true); // connections to enable/disable navi widget factory - SessionManager *sessionManager = SessionManager::instance(); - connect(sessionManager, &SessionManager::projectAdded, + ProjectManager *sessionManager = ProjectManager::instance(); + connect(sessionManager, &ProjectManager::projectAdded, this, [this](Project *project) { const FilePath projectPath = project->projectFilePath(); const QString projectName = project->displayName(); @@ -211,7 +214,7 @@ void Manager::initialize() d->m_parser->addProject(projectPath, projectName, projectFiles); }, Qt::QueuedConnection); }); - connect(sessionManager, &SessionManager::projectRemoved, + connect(sessionManager, &ProjectManager::projectRemoved, this, [this](Project *project) { const FilePath projectPath = project->projectFilePath(); QMetaObject::invokeMethod(d->m_parser, [this, projectPath]() { diff --git a/src/plugins/classview/classviewparsertreeitem.cpp b/src/plugins/classview/classviewparsertreeitem.cpp index 1d97d0c013b..787b63b3c84 100644 --- a/src/plugins/classview/classviewparsertreeitem.cpp +++ b/src/plugins/classview/classviewparsertreeitem.cpp @@ -7,9 +7,11 @@ #include #include + #include +#include #include -#include +#include #include #include @@ -261,7 +263,7 @@ bool ParserTreeItem::canFetchMore(QStandardItem *item) const */ void ParserTreeItem::fetchMore(QStandardItem *item) const { - using ProjectExplorer::SessionManager; + using ProjectExplorer::ProjectManager; if (!item) return; @@ -283,7 +285,7 @@ void ParserTreeItem::fetchMore(QStandardItem *item) const // icon const Utils::FilePath &filePath = ptr->projectFilePath(); if (!filePath.isEmpty()) { - ProjectExplorer::Project *project = SessionManager::projectForFile(filePath); + ProjectExplorer::Project *project = ProjectManager::projectForFile(filePath); if (project) add->setIcon(project->containerNode()->icon()); } diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index de884452be6..83db3d6919e 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -595,7 +595,7 @@ ClearCasePluginPrivate::ClearCasePluginPrivate() m_settings.fromSettings(ICore::settings()); // update view name when changing active project - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &ClearCasePluginPrivate::projectChanged); const QString description = QLatin1String("ClearCase"); @@ -2124,7 +2124,7 @@ void ClearCasePluginPrivate::updateIndex() { QTC_ASSERT(currentState().hasTopLevel(), return); ProgressManager::cancelTasks(ClearCase::Constants::TASK_INDEX); - Project *project = SessionManager::startupProject(); + Project *project = ProjectManager::startupProject(); if (!project) return; m_checkInAllAction->setEnabled(false); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 7c0f6227ff9..459abb122ea 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp index 325a6012a53..01fbeaa2329 100644 --- a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp +++ b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp @@ -8,8 +8,9 @@ #include "cmaketool.h" #include -#include +#include #include + #include #include @@ -39,7 +40,7 @@ IAssistProposal *CMakeFileCompletionAssist::performAsync() Keywords kw; const Utils::FilePath &filePath = interface()->filePath(); if (!filePath.isEmpty() && filePath.toFileInfo().isFile()) { - Project *p = SessionManager::projectForFile(filePath); + Project *p = ProjectManager::projectForFile(filePath); if (p && p->activeTarget()) { CMakeTool *cmake = CMakeKitAspect::cmakeTool(p->activeTarget()->kit()); if (cmake && cmake->isValid()) diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 225217490cb..65b179cdf00 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include @@ -29,9 +29,9 @@ namespace CMakeProjectManager::Internal { CMakeTargetLocatorFilter::CMakeTargetLocatorFilter() { - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, &CMakeTargetLocatorFilter::projectListUpdated); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, &CMakeTargetLocatorFilter::projectListUpdated); // Initialize the filter @@ -41,7 +41,7 @@ CMakeTargetLocatorFilter::CMakeTargetLocatorFilter() void CMakeTargetLocatorFilter::prepareSearch(const QString &entry) { m_result.clear(); - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); for (Project *p : projects) { auto cmakeProject = qobject_cast(p); if (!cmakeProject || !cmakeProject->activeTarget()) @@ -87,7 +87,7 @@ QList CMakeTargetLocatorFilter::matchesFor( void CMakeTargetLocatorFilter::projectListUpdated() { // Enable the filter if there's at least one CMake project - setEnabled(Utils::contains(SessionManager::projects(), + setEnabled(Utils::contains(ProjectManager::projects(), [](Project *p) { return qobject_cast(p); })); } @@ -116,7 +116,7 @@ void BuildCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, // Get the project containing the target selected const auto cmakeProject = qobject_cast( - Utils::findOrDefault(SessionManager::projects(), [projectPath](Project *p) { + Utils::findOrDefault(ProjectManager::projects(), [projectPath](Project *p) { return p->projectFilePath() == projectPath; })); if (!cmakeProject || !cmakeProject->activeTarget() diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index e05e155cf6f..95baccee1e9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -16,12 +16,14 @@ #include #include #include + #include + #include #include #include +#include #include -#include #include #include @@ -59,7 +61,7 @@ CMakeManager::CMakeManager() command->setAttribute(Core::Command::CA_Hide); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD); connect(m_runCMakeAction, &QAction::triggered, this, [this] { - runCMake(SessionManager::startupBuildSystem()); + runCMake(ProjectManager::startupBuildSystem()); }); command = Core::ActionManager::registerAction(m_clearCMakeCacheAction, @@ -68,7 +70,7 @@ CMakeManager::CMakeManager() command->setAttribute(Core::Command::CA_Hide); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD); connect(m_clearCMakeCacheAction, &QAction::triggered, this, [this] { - clearCMakeCache(SessionManager::startupBuildSystem()); + clearCMakeCache(ProjectManager::startupBuildSystem()); }); command = Core::ActionManager::registerAction(m_runCMakeActionContextMenu, @@ -111,7 +113,7 @@ CMakeManager::CMakeManager() mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD); connect(m_buildFileAction, &QAction::triggered, this, [this] { buildFile(); }); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, this, [this] { + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, [this] { updateCmakeActions(ProjectTree::currentNode()); }); connect(BuildManager::instance(), &BuildManager::buildStateChanged, this, [this] { @@ -127,7 +129,7 @@ CMakeManager::CMakeManager() void CMakeManager::updateCmakeActions(Node *node) { - auto project = qobject_cast(SessionManager::startupProject()); + auto project = qobject_cast(ProjectManager::startupProject()); const bool visible = project && !BuildManager::isBuilding(project); m_runCMakeAction->setVisible(visible); m_runCMakeActionContextMenu->setEnabled(visible); diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp index fc1da70ca75..13f03c0ed31 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -72,7 +72,7 @@ void CompilationDatabaseProjectManagerPlugin::initialize() d->changeRootAction.setEnabled(currentProject); }; - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, onProjectChanged); connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, diff --git a/src/plugins/conan/conanplugin.cpp b/src/plugins/conan/conanplugin.cpp index ef42d348f86..3844b2983bd 100644 --- a/src/plugins/conan/conanplugin.cpp +++ b/src/plugins/conan/conanplugin.cpp @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include using namespace Core; @@ -39,7 +39,7 @@ void ConanPlugin::initialize() d = new ConanPluginPrivate; conanSettings()->readSettings(ICore::settings()); - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, &ConanPlugin::projectAdded); } diff --git a/src/plugins/cppcheck/cppcheckplugin.cpp b/src/plugins/cppcheck/cppcheckplugin.cpp index 5dd09a1820b..8d44f0dda56 100644 --- a/src/plugins/cppcheck/cppcheckplugin.cpp +++ b/src/plugins/cppcheck/cppcheckplugin.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -97,8 +97,9 @@ CppcheckPluginPrivate::CppcheckPluginPrivate() } } -void CppcheckPluginPrivate::startManualRun() { - auto project = ProjectExplorer::SessionManager::startupProject(); +void CppcheckPluginPrivate::startManualRun() +{ + auto project = ProjectExplorer::ProjectManager::startupProject(); if (!project) return; @@ -121,8 +122,8 @@ void CppcheckPluginPrivate::startManualRun() { void CppcheckPluginPrivate::updateManualRunAction() { using namespace ProjectExplorer; - const Project *project = SessionManager::startupProject(); - const Target *target = SessionManager::startupTarget(); + const Project *project = ProjectManager::startupProject(); + const Target *target = ProjectManager::startupTarget(); const Utils::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID; const bool canRun = target && project->projectLanguages().contains(cxx) && ToolChainKitAspect::cxxToolChain(target->kit()); diff --git a/src/plugins/cppcheck/cppchecktrigger.cpp b/src/plugins/cppcheck/cppchecktrigger.cpp index 55b1cf7ac01..8be098df558 100644 --- a/src/plugins/cppcheck/cppchecktrigger.cpp +++ b/src/plugins/cppcheck/cppchecktrigger.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include using namespace Core; using namespace ProjectExplorer; @@ -34,7 +34,7 @@ CppcheckTrigger::CppcheckTrigger(CppcheckTextMarkManager &marks, CppcheckTool &t connect(EditorManager::instance(), &EditorManager::aboutToSave, this, &CppcheckTrigger::checkChangedDocument); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &CppcheckTrigger::changeCurrentProject); connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated, diff --git a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp index ca344aa6c7c..98784a1fb94 100644 --- a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp @@ -8,7 +8,8 @@ #include "cpptoolsreuse.h" #include "editordocumenthandle.h" -#include +#include + #include namespace CppEditor { @@ -37,7 +38,7 @@ void BaseEditorDocumentProcessor::run(bool projectsUpdated) : Utils::Language::Cxx; runImpl({CppModelManager::instance()->workingCopy(), - ProjectExplorer::SessionManager::startupProject(), + ProjectExplorer::ProjectManager::startupProject(), languagePreference, projectsUpdated}); } diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index e4b567b7326..b871010a0a4 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -9,6 +9,7 @@ #include "cpptoolsreuse.h" #include + #include #include diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 20fe8e6254b..44f9e01a017 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -30,9 +30,9 @@ #include #include +#include #include #include -#include #include #include @@ -755,7 +755,7 @@ void CppEditorWidget::showRenameWarningIfFileIsGenerated(const Utils::FilePath & { if (filePath.isEmpty()) return; - for (const Project * const project : SessionManager::projects()) { + for (const Project * const project : ProjectManager::projects()) { const Node * const node = project->nodeForFilePath(filePath); if (!node) continue; @@ -989,7 +989,7 @@ void CppEditorWidget::findLinkAt(const QTextCursor &cursor, const QString fileName = filePath.fileName(); if (fileName.startsWith("ui_") && fileName.endsWith(".h")) { const QString uiFileName = fileName.mid(3, fileName.length() - 4) + "ui"; - for (const Project * const project : SessionManager::projects()) { + for (const Project * const project : ProjectManager::projects()) { const auto nodeMatcher = [uiFileName](Node *n) { return n->filePath().fileName() == uiFileName; }; diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index 940eb358e93..c553a5124b5 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -10,14 +10,18 @@ #include "cpptoolsreuse.h" #include "cppworkingcopy.h" +#include + #include #include #include #include + #include +#include #include #include -#include + #include #include @@ -25,10 +29,8 @@ #include #include -#include #include #include -#include #include #include @@ -577,7 +579,7 @@ static void displayResults(SearchResult *search, item.setStyle(colorStyleForUsageType(result.tags)); item.setUseTextEditorFont(true); if (search->supportsReplace()) - item.setSelectForReplacement(SessionManager::projectForFile(result.path)); + item.setSelectForReplacement(ProjectManager::projectForFile(result.path)); search->addResult(item); if (parameters.prettySymbolName.isEmpty()) @@ -586,7 +588,7 @@ static void displayResults(SearchResult *search, if (parameters.filesToRename.contains(result.path)) continue; - if (!SessionManager::projectForFile(result.path)) + if (!ProjectManager::projectForFile(result.path)) continue; if (result.path.baseName().compare(parameters.prettySymbolName, Qt::CaseInsensitive) == 0) @@ -766,7 +768,7 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro ¯o, const QStri item.setMainRange(macro.line(), column, macro.nameToQString().length()); item.setUseTextEditorFont(true); if (search->supportsReplace()) - item.setSelectForReplacement(SessionManager::projectForFile(filePath)); + item.setSelectForReplacement(ProjectManager::projectForFile(filePath)); search->addResult(item); } diff --git a/src/plugins/cppeditor/cppincludesfilter.cpp b/src/plugins/cppeditor/cppincludesfilter.cpp index 9f637f6582b..970e179fc00 100644 --- a/src/plugins/cppeditor/cppincludesfilter.cpp +++ b/src/plugins/cppeditor/cppincludesfilter.cpp @@ -7,11 +7,13 @@ #include "cppeditortr.h" #include "cppmodelmanager.h" -#include #include + +#include + #include #include -#include +#include using namespace Core; using namespace ProjectExplorer; @@ -128,7 +130,7 @@ void CppIncludesFilter::prepareSearch(const QString &entry) if (m_needsUpdate) { m_needsUpdate = false; QSet seedPaths; - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { const FilePaths allFiles = project->files(Project::SourceFiles); for (const FilePath &filePath : allFiles ) seedPaths.insert(filePath); diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 373773786a9..36d70882920 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -37,9 +37,11 @@ #include #include #include + #include #include #include + #include #include @@ -49,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -577,7 +580,7 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) if (link.hasValidTarget() && link.targetFilePath.isReadableFile() && (folder.isEmpty() || link.targetFilePath.isChildOf(folder)) - && SessionManager::projectForFile(link.targetFilePath)) { + && ProjectManager::projectForFile(link.targetFilePath)) { links << link; } } @@ -938,14 +941,14 @@ CppModelManager::CppModelManager() d->m_delayedGcTimer.setSingleShot(true); connect(&d->m_delayedGcTimer, &QTimer::timeout, this, &CppModelManager::GC); - auto sessionManager = SessionManager::instance(); - connect(sessionManager, &SessionManager::projectAdded, + auto projectManager = ProjectManager::instance(); + connect(projectManager, &ProjectManager::projectAdded, this, &CppModelManager::onProjectAdded); - connect(sessionManager, &SessionManager::aboutToRemoveProject, + connect(projectManager, &ProjectManager::aboutToRemoveProject, this, &CppModelManager::onAboutToRemoveProject); - connect(sessionManager, &SessionManager::aboutToLoadSession, + connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, this, &CppModelManager::onAboutToLoadSession); - connect(sessionManager, &SessionManager::startupProjectChanged, + connect(projectManager, &ProjectManager::startupProjectChanged, this, &CppModelManager::onActiveProjectChanged); connect(EditorManager::instance(), &EditorManager::currentEditorChanged, diff --git a/src/plugins/cppeditor/cppmodelmanager_test.cpp b/src/plugins/cppeditor/cppmodelmanager_test.cpp index 97d13d0704c..eaa2ef142d8 100644 --- a/src/plugins/cppeditor/cppmodelmanager_test.cpp +++ b/src/plugins/cppeditor/cppmodelmanager_test.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 3dae225cea3..8ae20d1c5a0 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include @@ -7986,7 +7986,7 @@ private: } }; - if (const Project *project = SessionManager::projectForFile(filePath())) { + if (const Project *project = ProjectManager::projectForFile(filePath())) { const FilePaths files = project->files(ProjectExplorer::Project::SourceFiles); QSet projectFiles(files.begin(), files.end()); for (const auto &file : files) { diff --git a/src/plugins/cppeditor/cpptoolsjsextension.cpp b/src/plugins/cppeditor/cpptoolsjsextension.cpp index a3cbfe12041..b70328601ee 100644 --- a/src/plugins/cppeditor/cpptoolsjsextension.cpp +++ b/src/plugins/cppeditor/cpptoolsjsextension.cpp @@ -10,12 +10,13 @@ #include #include +#include #include -#include #include #include #include + #include #include @@ -234,7 +235,7 @@ QString CppToolsJsExtension::includeStatement( } return false; }; - for (const Project * const p : SessionManager::projects()) { + for (const Project * const p : ProjectManager::projects()) { const Node *theNode = p->rootProjectNode()->findNode(nodeMatchesFileName); if (theNode) { const bool sameDir = pathOfIncludingFile == theNode->filePath().toFileInfo().path(); diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp index 7d17e30e4bc..912902c0c9c 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.cpp +++ b/src/plugins/cppeditor/cpptoolsreuse.cpp @@ -21,7 +21,9 @@ #include #include #include -#include + +#include + #include #include @@ -29,6 +31,7 @@ #include #include #include + #include #include #include @@ -596,12 +599,12 @@ NamespaceAST *NSCheckerVisitor::currentNamespace() ProjectExplorer::Project *projectForProjectPart(const ProjectPart &part) { - return ProjectExplorer::SessionManager::projectWithProjectFilePath(part.topLevelProject); + return ProjectExplorer::ProjectManager::projectWithProjectFilePath(part.topLevelProject); } ProjectExplorer::Project *projectForProjectInfo(const ProjectInfo &info) { - return ProjectExplorer::SessionManager::projectWithProjectFilePath(info.projectFilePath()); + return ProjectExplorer::ProjectManager::projectWithProjectFilePath(info.projectFilePath()); } void openEditor(const Utils::FilePath &filePath, bool inNextSplit, Utils::Id editorId) diff --git a/src/plugins/cppeditor/cpptoolstestcase.cpp b/src/plugins/cppeditor/cpptoolstestcase.cpp index b7124b01ca4..2d149b3ff5d 100644 --- a/src/plugins/cppeditor/cpptoolstestcase.cpp +++ b/src/plugins/cppeditor/cpptoolstestcase.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -348,8 +348,8 @@ bool TestCase::waitUntilProjectIsFullyOpened(Project *project, int timeOutInMs) return QTest::qWaitFor( [project]() { - return SessionManager::startupBuildSystem() - && !SessionManager::startupBuildSystem()->isParsing() + return ProjectManager::startupBuildSystem() + && !ProjectManager::startupBuildSystem()->isParsing() && CppModelManager::instance()->projectInfo(project); }, timeOutInMs); @@ -367,7 +367,7 @@ bool TestCase::writeFile(const FilePath &filePath, const QByteArray &contents) ProjectOpenerAndCloser::ProjectOpenerAndCloser() { - QVERIFY(!SessionManager::hasProjects()); + QVERIFY(!ProjectManager::hasProjects()); } ProjectOpenerAndCloser::~ProjectOpenerAndCloser() diff --git a/src/plugins/cppeditor/generatedcodemodelsupport.cpp b/src/plugins/cppeditor/generatedcodemodelsupport.cpp index 400e77fb378..22a9b2735eb 100644 --- a/src/plugins/cppeditor/generatedcodemodelsupport.cpp +++ b/src/plugins/cppeditor/generatedcodemodelsupport.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/modelmanagertesthelper.cpp b/src/plugins/cppeditor/modelmanagertesthelper.cpp index f4114c33b27..a133ac7fef2 100644 --- a/src/plugins/cppeditor/modelmanagertesthelper.cpp +++ b/src/plugins/cppeditor/modelmanagertesthelper.cpp @@ -6,7 +6,7 @@ #include "cpptoolstestcase.h" #include "projectinfo.h" -#include +#include #include @@ -59,7 +59,7 @@ void ModelManagerTestHelper::cleanup() CppModelManager *mm = CppModelManager::instance(); QList pies = mm->projectInfos(); for (Project * const p : std::as_const(m_projects)) { - ProjectExplorer::SessionManager::removeProject(p); + ProjectExplorer::ProjectManager::removeProject(p); emit aboutToRemoveProject(p); } @@ -72,7 +72,7 @@ ModelManagerTestHelper::Project *ModelManagerTestHelper::createProject( { auto tp = new TestProject(name, this, filePath); m_projects.push_back(tp); - ProjectExplorer::SessionManager::addProject(tp); + ProjectExplorer::ProjectManager::addProject(tp); emit projectAdded(tp); return tp; } diff --git a/src/plugins/cppeditor/symbolsfindfilter.cpp b/src/plugins/cppeditor/symbolsfindfilter.cpp index 3b901715b2c..0317d0ee98d 100644 --- a/src/plugins/cppeditor/symbolsfindfilter.cpp +++ b/src/plugins/cppeditor/symbolsfindfilter.cpp @@ -12,9 +12,10 @@ #include #include #include + #include #include -#include +#include #include #include @@ -108,7 +109,7 @@ void SymbolsFindFilter::startSearch(SearchResult *search) SymbolSearcher::Parameters parameters = search->userData().value(); QSet projectFileNames; if (parameters.scope == SymbolSearcher::SearchProjectsOnly) { - for (ProjectExplorer::Project *project : ProjectExplorer::SessionManager::projects()) + for (ProjectExplorer::Project *project : ProjectExplorer::ProjectManager::projects()) projectFileNames += Utils::transform(project->files(ProjectExplorer::Project::AllFiles), &Utils::FilePath::toString); } diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 8ab67c0bc54..e8c14d4dccf 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -67,9 +67,10 @@ #include #include #include +#include #include #include -#include +#include #include #include #include @@ -1187,7 +1188,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) setInitialState(); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &DebuggerPluginPrivate::onStartupProjectChanged); connect(EngineManager::instance(), &EngineManager::engineStateChanged, this, &DebuggerPluginPrivate::updatePresetState); @@ -1394,8 +1395,8 @@ void DebuggerPluginPrivate::updatePresetState() if (m_shuttingDown) return; - Project *startupProject = SessionManager::startupProject(); - RunConfiguration *startupRunConfig = SessionManager::startupRunConfiguration(); + Project *startupProject = ProjectManager::startupProject(); + RunConfiguration *startupRunConfig = ProjectManager::startupRunConfiguration(); DebuggerEngine *currentEngine = EngineManager::currentEngine(); QString whyNot; @@ -1997,7 +1998,7 @@ void DebuggerPluginPrivate::aboutToShutdown() { m_shuttingDown = true; - disconnect(SessionManager::instance(), &SessionManager::startupProjectChanged, this, nullptr); + disconnect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, nullptr); m_shutdownTimer.setInterval(0); m_shutdownTimer.setSingleShot(true); @@ -2165,7 +2166,7 @@ static bool buildTypeAccepted(QFlags toolMode, BuildConfiguration::Bui static BuildConfiguration::BuildType startupBuildType() { BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown; - if (RunConfiguration *runConfig = SessionManager::startupRunConfiguration()) { + if (RunConfiguration *runConfig = ProjectManager::startupRunConfiguration()) { if (const BuildConfiguration *buildConfig = runConfig->target()->activeBuildConfiguration()) buildType = buildConfig->buildType(); } @@ -2335,12 +2336,12 @@ void DebuggerUnitTests::testStateMachine() QEventLoop loop; connect(BuildManager::instance(), &BuildManager::buildQueueFinished, &loop, &QEventLoop::quit); - BuildManager::buildProjectWithDependencies(SessionManager::startupProject()); + BuildManager::buildProjectWithDependencies(ProjectManager::startupProject()); loop.exec(); ExecuteOnDestruction guard([] { EditorManager::closeAllEditors(false); }); - RunConfiguration *rc = SessionManager::startupRunConfiguration(); + RunConfiguration *rc = ProjectManager::startupRunConfiguration(); QVERIFY(rc); auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 8b6ac29c995..3a5d84d3b6b 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -23,8 +23,9 @@ #include #include #include +#include #include -#include +#include #include #include #include @@ -182,8 +183,8 @@ void DebuggerRunTool::setStartMode(DebuggerStartMode startMode) // FIXME: This is horribly wrong. // get files from all the projects in the session - QList projects = SessionManager::projects(); - if (Project *startupProject = SessionManager::startupProject()) { + QList projects = ProjectManager::projects(); + if (Project *startupProject = ProjectManager::startupProject()) { // startup project first projects.removeOne(startupProject); projects.insert(0, startupProject); diff --git a/src/plugins/designer/codemodelhelpers.cpp b/src/plugins/designer/codemodelhelpers.cpp index beddb3714e6..8428fd98171 100644 --- a/src/plugins/designer/codemodelhelpers.cpp +++ b/src/plugins/designer/codemodelhelpers.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -30,7 +30,7 @@ static const char setupUiC[] = "setupUi"; // Find the generated "ui_form.h" header of the form via project. static FilePath generatedHeaderOf(const FilePath &uiFileName) { - if (const Project *uiProject = SessionManager::projectForFile(uiFileName)) { + if (const Project *uiProject = ProjectManager::projectForFile(uiFileName)) { if (Target *t = uiProject->activeTarget()) { if (BuildSystem *bs = t->buildSystem()) { FilePaths files = bs->filesGeneratedFrom(uiFileName); diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp index db96523c360..02f01a5d091 100644 --- a/src/plugins/designer/qtcreatorintegration.cpp +++ b/src/plugins/designer/qtcreatorintegration.cpp @@ -16,20 +16,24 @@ #include #include #include + #include #include + #include #include #include -#include -#include + #include #include #include +#include #include -#include #include +#include +#include + #include #include #include @@ -493,10 +497,10 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName, // Retrieve code model snapshot restricted to project of ui file or the working copy. Snapshot docTable = CppEditor::CppModelManager::instance()->snapshot(); Snapshot newDocTable; - const Project *uiProject = SessionManager::projectForFile(currentUiFile); + const Project *uiProject = ProjectManager::projectForFile(currentUiFile); if (uiProject) { for (Snapshot::const_iterator i = docTable.begin(), ei = docTable.end(); i != ei; ++i) { - const Project *project = SessionManager::projectForFile(i.key()); + const Project *project = ProjectManager::projectForFile(i.key()); if (project == uiProject) newDocTable.insert(i.value()); } @@ -639,7 +643,7 @@ void QtCreatorIntegration::handleSymbolRenameStage1( return; // Get ExtraCompiler. - const Project * const project = SessionManager::projectForFile(uiFile); + const Project * const project = ProjectManager::projectForFile(uiFile); if (!project) { return reportRenamingError(oldName, Designer::Tr::tr("File \"%1\" not found in project.") .arg(uiFile.toUserOutput())); diff --git a/src/plugins/designer/resourcehandler.cpp b/src/plugins/designer/resourcehandler.cpp index 29838283d5c..fe2cdd28c60 100644 --- a/src/plugins/designer/resourcehandler.cpp +++ b/src/plugins/designer/resourcehandler.cpp @@ -2,13 +2,16 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "resourcehandler.h" + #include "designerconstants.h" -#include -#include #include -#include +#include +#include +#include + #include + #include #include @@ -42,10 +45,10 @@ void ResourceHandler::ensureInitialized() Qt::QueuedConnection); }; - for (Project *p : SessionManager::projects()) + for (Project *p : ProjectManager::projects()) connector(p); - connect(SessionManager::instance(), &SessionManager::projectAdded, this, connector); + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, connector); m_originalUiQrcPaths = m_form->activeResourceFilePaths(); if (Designer::Constants::Internal::debug) @@ -68,7 +71,7 @@ void ResourceHandler::updateResourcesHelper(bool updateProjectResources) qDebug() << "ResourceHandler::updateResources()" << fileName; // Filename could change in the meantime. - Project *project = SessionManager::projectForFile(Utils::FilePath::fromUserInput(fileName)); + Project *project = ProjectManager::projectForFile(Utils::FilePath::fromUserInput(fileName)); const bool dirty = m_form->property("_q_resourcepathchanged").toBool(); if (dirty) m_form->setDirty(true); diff --git a/src/plugins/gitlab/gitlabdialog.cpp b/src/plugins/gitlab/gitlabdialog.cpp index 97d57e42651..22c362788a8 100644 --- a/src/plugins/gitlab/gitlabdialog.cpp +++ b/src/plugins/gitlab/gitlabdialog.cpp @@ -9,7 +9,7 @@ #include "gitlabprojectsettings.h" #include "gitlabtr.h" -#include +#include #include #include @@ -188,7 +188,7 @@ void GitLabDialog::requestMainViewUpdate() bool linked = false; m_currentServerId = Id(); - if (auto project = ProjectExplorer::SessionManager::startupProject()) { + if (auto project = ProjectExplorer::ProjectManager::startupProject()) { GitLabProjectSettings *projSettings = GitLabPlugin::projectSettings(project); if (projSettings->isLinked()) { m_currentServerId = projSettings->currentServer(); diff --git a/src/plugins/gitlab/gitlabplugin.cpp b/src/plugins/gitlab/gitlabplugin.cpp index 2059ae4d84b..9427aa1d44b 100644 --- a/src/plugins/gitlab/gitlabplugin.cpp +++ b/src/plugins/gitlab/gitlabplugin.cpp @@ -14,11 +14,15 @@ #include #include #include + #include + #include #include -#include +#include + #include + #include #include @@ -89,8 +93,8 @@ void GitLabPlugin::initialize() if (dd->dialog) dd->dialog->updateRemotes(); }); - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, this, &GitLabPlugin::onStartupProjectChanged); } @@ -121,7 +125,7 @@ void GitLabPlugin::onStartupProjectChanged() { QTC_ASSERT(dd, return); disconnect(&dd->notificationTimer); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) { dd->notificationTimer.stop(); return; @@ -147,7 +151,7 @@ void GitLabPluginPrivate::setupNotificationTimer() void GitLabPluginPrivate::fetchEvents() { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(project, return); if (runningQuery) @@ -218,7 +222,7 @@ void GitLabPluginPrivate::handleEvents(const Events &events, const QDateTime &ti { runningQuery = false; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(project, return); GitLabProjectSettings *projSettings = GitLabPlugin::projectSettings(project); @@ -311,7 +315,7 @@ void GitLabPlugin::linkedStateChanged(bool enabled) { QTC_ASSERT(dd, return); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (project) { const GitLabProjectSettings *pSettings = projectSettings(project); dd->serverId = pSettings->currentServer(); diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 23c086c8b2e..1a20d60541c 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include @@ -156,7 +156,7 @@ public: m_documentUpdateTimer.setInterval(500); connect(&m_documentUpdateTimer, &QTimer::timeout, this, [this] { sendPostponedDocumentUpdates(Schedule::Now); }); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, q, &Client::projectClosed); QTC_ASSERT(clientInterface, return); @@ -509,7 +509,7 @@ void Client::initialize() params.setRootUri(hostPathToServerUri(d->m_project->projectDirectory())); const QList workspaces - = Utils::transform(SessionManager::projects(), [this](Project *pro) { + = Utils::transform(ProjectManager::projects(), [this](Project *pro) { return WorkSpaceFolder(hostPathToServerUri(pro->projectDirectory()), pro->displayName()); }); @@ -1862,7 +1862,7 @@ void ClientPrivate::handleMethod(const QString &method, const MessageId &id, con } else if (method == WorkSpaceFolderRequest::methodName) { WorkSpaceFolderRequest::Response response(id); const QList projects - = ProjectExplorer::SessionManager::projects(); + = ProjectExplorer::ProjectManager::projects(); if (projects.isEmpty()) { response.setResult(nullptr); } else { diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index a41c4f01d6a..2b1255f25ca 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -55,9 +55,9 @@ LanguageClientManager::LanguageClientManager(QObject *parent) this, &LanguageClientManager::documentContentsSaved); connect(EditorManager::instance(), &EditorManager::aboutToSave, this, &LanguageClientManager::documentWillSave); - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, &LanguageClientManager::projectAdded); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, [&](Project *project) { project->disconnect(this); }); } @@ -317,7 +317,7 @@ void LanguageClientManager::applySettings() continue; const Utils::FilePath filePath = textDocument->filePath(); for (ProjectExplorer::Project *project : - ProjectExplorer::SessionManager::projects()) { + ProjectExplorer::ProjectManager::projects()) { if (project->isKnownFile(filePath)) { Client *client = clientForProject[project]; if (!client) { @@ -494,7 +494,7 @@ void LanguageClientManager::documentOpened(Core::IDocument *document) if (setting->m_startBehavior == BaseSettings::RequiresProject) { const Utils::FilePath &filePath = document->filePath(); for (ProjectExplorer::Project *project : - ProjectExplorer::SessionManager::projects()) { + ProjectExplorer::ProjectManager::projects()) { // check whether file is part of this project if (!project->isKnownFile(filePath)) continue; diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 6f2cf7dafe5..5b15c7c218d 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp index 995ca770f3d..1de3bede6d4 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.cpp +++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include @@ -237,7 +237,7 @@ QList generateSearchResultItems( item.setFilePath(filePath); item.setUseTextEditorFont(true); if (renaming && limitToProjects) { - const bool fileBelongsToProject = ProjectExplorer::SessionManager::projectForFile( + const bool fileBelongsToProject = ProjectExplorer::ProjectManager::projectForFile( filePath); item.setSelectForReplacement(fileBelongsToProject); if (fileBelongsToProject diff --git a/src/plugins/mcusupport/mcusupportplugin.cpp b/src/plugins/mcusupport/mcusupportplugin.cpp index 2c3dfdb28b0..7be98fb005b 100644 --- a/src/plugins/mcusupport/mcusupportplugin.cpp +++ b/src/plugins/mcusupport/mcusupportplugin.cpp @@ -27,8 +27,8 @@ #include #include #include +#include #include -#include #include #include @@ -115,8 +115,8 @@ void McuSupportPlugin::initialize() setObjectName("McuSupportPlugin"); dd = new McuSupportPluginPrivate; - connect(SessionManager::instance(), - &SessionManager::projectFinishedParsing, + connect(ProjectManager::instance(), + &ProjectManager::projectFinishedParsing, updateMCUProjectTree); dd->m_options.registerQchFiles(); diff --git a/src/plugins/modeleditor/componentviewcontroller.cpp b/src/plugins/modeleditor/componentviewcontroller.cpp index 4ce7cc16caf..75495c6684e 100644 --- a/src/plugins/modeleditor/componentviewcontroller.cpp +++ b/src/plugins/modeleditor/componentviewcontroller.cpp @@ -18,9 +18,9 @@ #include #include -#include -#include #include +#include +#include #include @@ -136,7 +136,7 @@ void UpdateIncludeDependenciesVisitor::setModelUtilities(ModelUtilities *modelUt void UpdateIncludeDependenciesVisitor::updateFilePaths() { m_filePaths.clear(); - for (const ProjectExplorer::Project *project : ProjectExplorer::SessionManager::projects()) { + for (const ProjectExplorer::Project *project : ProjectExplorer::ProjectManager::projects()) { ProjectExplorer::ProjectNode *projectNode = project->rootProjectNode(); if (projectNode) collectElementPaths(projectNode, &m_filePaths); diff --git a/src/plugins/modeleditor/modelindexer.cpp b/src/plugins/modeleditor/modelindexer.cpp index c6ace660248..9923782ac72 100644 --- a/src/plugins/modeleditor/modelindexer.cpp +++ b/src/plugins/modeleditor/modelindexer.cpp @@ -18,7 +18,7 @@ #include "qmt/tasks/findrootdiagramvisitor.h" #include -#include +#include #include #include @@ -308,9 +308,9 @@ ModelIndexer::ModelIndexer(QObject *parent) connect(this, &ModelIndexer::filesQueued, d->indexerThread, &ModelIndexer::IndexerThread::onFilesQueued); d->indexerThread->start(); - connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::projectAdded, + connect(ProjectExplorer::ProjectManager::instance(), &ProjectExplorer::ProjectManager::projectAdded, this, &ModelIndexer::onProjectAdded); - connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::aboutToRemoveProject, + connect(ProjectExplorer::ProjectManager::instance(), &ProjectExplorer::ProjectManager::aboutToRemoveProject, this, &ModelIndexer::onAboutToRemoveProject); } diff --git a/src/plugins/nim/editor/nimcompletionassistprovider.cpp b/src/plugins/nim/editor/nimcompletionassistprovider.cpp index 7179a8a64ec..c94001b348f 100644 --- a/src/plugins/nim/editor/nimcompletionassistprovider.cpp +++ b/src/plugins/nim/editor/nimcompletionassistprovider.cpp @@ -5,7 +5,7 @@ #include "suggest/nimsuggestcache.h" #include "suggest/nimsuggest.h" -#include +#include #include #include #include diff --git a/src/plugins/perfprofiler/perfdatareader.cpp b/src/plugins/perfprofiler/perfdatareader.cpp index 603d2ad016b..a545dff913e 100644 --- a/src/plugins/perfprofiler/perfdatareader.cpp +++ b/src/plugins/perfprofiler/perfdatareader.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/perfprofiler/perfloaddialog.cpp b/src/plugins/perfprofiler/perfloaddialog.cpp index 8bf34316fe6..8f162ed5969 100644 --- a/src/plugins/perfprofiler/perfloaddialog.cpp +++ b/src/plugins/perfprofiler/perfloaddialog.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -109,7 +109,7 @@ void PerfLoadDialog::on_browseExecutableDirButton_pressed() void PerfLoadDialog::chooseDefaults() { - ProjectExplorer::Target *target = ProjectExplorer::SessionManager::startupTarget(); + ProjectExplorer::Target *target = ProjectExplorer::ProjectManager::startupTarget(); if (!target) return; diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index d4515f79b85..8362ccc4ed8 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -224,7 +224,7 @@ void PerfProfilerTool::createViews() connect(recordMenu, &QMenu::aboutToShow, recordMenu, [recordMenu] { recordMenu->hide(); PerfSettings *settings = nullptr; - Target *target = SessionManager::startupTarget(); + Target *target = ProjectManager::startupTarget(); if (target) { if (auto runConfig = target->activeRunConfiguration()) settings = runConfig->currentSettings(Constants::PerfSettingsId); @@ -572,7 +572,7 @@ static Utils::FilePaths sourceFiles(const Project *currentProject = nullptr) if (currentProject) sourceFiles.append(currentProject->files(Project::SourceFiles)); - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); for (const Project *project : projects) { if (project != currentProject) sourceFiles.append(project->files(Project::SourceFiles)); @@ -609,7 +609,7 @@ void PerfProfilerTool::showLoadTraceDialog() startLoading(); - const Project *currentProject = SessionManager::startupProject(); + const Project *currentProject = ProjectManager::startupProject(); const Target *target = currentProject ? currentProject->activeTarget() : nullptr; const Kit *kit = target ? target->kit() : nullptr; populateFileFinder(currentProject, kit); diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index da3b4c38c32..f276431ab5e 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -51,7 +51,7 @@ PerfTracePointDialog::PerfTracePointDialog() m_buttonBox, }.attachTo(this); - if (const Target *target = SessionManager::startupTarget()) { + if (const Target *target = ProjectManager::startupTarget()) { const Kit *kit = target->kit(); QTC_ASSERT(kit, return); diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index ea4d86dba7d..fddbceccb1c 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -3,10 +3,10 @@ #include "allprojectsfilter.h" +#include "project.h" #include "projectexplorer.h" #include "projectexplorertr.h" -#include "session.h" -#include "project.h" +#include "projectmanager.h" #include @@ -38,7 +38,7 @@ void AllProjectsFilter::prepareSearch(const QString &entry) Q_UNUSED(entry) if (!fileIterator()) { Utils::FilePaths paths; - for (Project *project : SessionManager::projects()) + for (Project *project : ProjectManager::projects()) paths.append(project->files(Project::SourceFiles)); Utils::sort(paths); setFileIterator(new BaseFileFilter::ListIterator(paths)); diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index ac4afc1d6e2..d61b1560523 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -7,7 +7,7 @@ #include "project.h" #include "projectexplorer.h" #include "projectexplorertr.h" -#include "session.h" +#include "projectmanager.h" #include @@ -44,7 +44,7 @@ QString AllProjectsFind::displayName() const bool AllProjectsFind::isEnabled() const { - return BaseFileFind::isEnabled() && SessionManager::hasProjects(); + return BaseFileFind::isEnabled() && ProjectManager::hasProjects(); } FileIterator *AllProjectsFind::files(const QStringList &nameFilters, @@ -52,7 +52,7 @@ FileIterator *AllProjectsFind::files(const QStringList &nameFilters, const QVariant &additionalParameters) const { Q_UNUSED(additionalParameters) - return filesForProjects(nameFilters, exclusionFilters, SessionManager::projects()); + return filesForProjects(nameFilters, exclusionFilters, ProjectManager::projects()); } FileIterator *AllProjectsFind::filesForProjects(const QStringList &nameFilters, diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index ff14b7ab07b..fc8967aaa0b 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -17,8 +17,8 @@ #include "projectexplorer.h" #include "projectexplorertr.h" #include "project.h" +#include "projectmanager.h" #include "projecttree.h" -#include "session.h" #include "target.h" #include @@ -209,7 +209,7 @@ BuildConfiguration::BuildConfiguration(Target *target, Utils::Id id) connect(target, &Target::parsingStarted, this, &BuildConfiguration::enabledChanged); connect(target, &Target::parsingFinished, this, &BuildConfiguration::enabledChanged); connect(this, &BuildConfiguration::enabledChanged, this, [this] { - if (isActive() && project() == SessionManager::startupProject()) { + if (isActive() && project() == ProjectManager::startupProject()) { ProjectExplorerPlugin::updateActions(); ProjectExplorerPlugin::updateRunActions(); } diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index 57bfde6e46a..6284a960417 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -16,8 +16,8 @@ #include "projectexplorerconstants.h" #include "projectexplorersettings.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "runcontrol.h" -#include "session.h" #include "target.h" #include "task.h" #include "taskhub.h" @@ -258,7 +258,7 @@ BuildManager::BuildManager(QObject *parent, QAction *cancelBuildAction) m_instance = this; d = new BuildManagerPrivate; - connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject, + connect(ProjectManager::instance(), &ProjectManager::aboutToRemoveProject, this, &BuildManager::aboutToRemoveProject); d->m_outputWindow = new Internal::CompileOutputWindow(cancelBuildAction); @@ -318,19 +318,19 @@ void BuildManager::rebuildProjectWithoutDependencies(Project *project) void BuildManager::buildProjectWithDependencies(Project *project, ConfigSelection configSelection) { - queue(SessionManager::projectOrder(project), {Id(Constants::BUILDSTEPS_BUILD)}, + queue(ProjectManager::projectOrder(project), {Id(Constants::BUILDSTEPS_BUILD)}, configSelection); } void BuildManager::cleanProjectWithDependencies(Project *project, ConfigSelection configSelection) { - queue(SessionManager::projectOrder(project), {Id(Constants::BUILDSTEPS_CLEAN)}, + queue(ProjectManager::projectOrder(project), {Id(Constants::BUILDSTEPS_CLEAN)}, configSelection); } void BuildManager::rebuildProjectWithDependencies(Project *project, ConfigSelection configSelection) { - queue(SessionManager::projectOrder(project), + queue(ProjectManager::projectOrder(project), {Id(Constants::BUILDSTEPS_CLEAN), Id(Constants::BUILDSTEPS_BUILD)}, configSelection); } @@ -384,7 +384,7 @@ BuildForRunConfigStatus BuildManager::potentiallyBuildForRunConfig(RunConfigurat } Project * const pro = rc->target()->project(); - const int queueCount = queue(SessionManager::projectOrder(pro), stepIds, + const int queueCount = queue(ProjectManager::projectOrder(pro), stepIds, ConfigSelection::Active, rc); if (rc->target()->activeBuildConfiguration()) rc->target()->activeBuildConfiguration()->restrictNextBuild(nullptr); diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index 9bf59d6bba8..18f89b5968a 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -185,7 +185,7 @@ void BuildSettingsWidget::currentIndexChanged(int index) { auto buildConfiguration = qobject_cast( m_target->buildConfigurationModel()->projectConfigurationAt(index)); - SessionManager::setActiveBuildConfiguration(m_target, buildConfiguration, SetActive::Cascade); + m_target->setActiveBuildConfiguration(buildConfiguration, SetActive::Cascade); } void BuildSettingsWidget::updateActiveConfiguration() @@ -222,7 +222,7 @@ void BuildSettingsWidget::createConfiguration(const BuildInfo &info_) return; m_target->addBuildConfiguration(bc); - SessionManager::setActiveBuildConfiguration(m_target, bc, SetActive::Cascade); + m_target->setActiveBuildConfiguration(bc, SetActive::Cascade); } QString BuildSettingsWidget::uniqueName(const QString & name) @@ -292,7 +292,7 @@ void BuildSettingsWidget::cloneConfiguration() bc->setBuildDirectory(makeUniquelyNumbered(buildDirectory, isBuildDirOk)); } m_target->addBuildConfiguration(bc); - SessionManager::setActiveBuildConfiguration(m_target, bc, SetActive::Cascade); + m_target->setActiveBuildConfiguration(bc, SetActive::Cascade); } void BuildSettingsWidget::deleteConfiguration(BuildConfiguration *deleteConfiguration) diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 0a2c2f3a85d..4316bba9102 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -7,9 +7,9 @@ #include "extracompiler.h" #include "projectexplorer.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "runconfiguration.h" #include "runcontrol.h" -#include "session.h" #include "target.h" #include @@ -64,7 +64,7 @@ BuildSystem::BuildSystem(Target *target) connect(&d->m_delayedParsingTimer, &QTimer::timeout, this, [this] { - if (SessionManager::hasProject(project())) + if (ProjectManager::hasProject(project())) triggerParsing(); else requestDelayedParse(); diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index 7ecbd990697..fb9b8f44d66 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -5,8 +5,8 @@ #include "project.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projecttree.h" -#include "session.h" #include #include @@ -23,7 +23,7 @@ CurrentProjectFind::CurrentProjectFind() { connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &CurrentProjectFind::handleProjectChanged); - connect(SessionManager::instance(), &SessionManager::projectDisplayNameChanged, + connect(ProjectManager::instance(), &ProjectManager::projectDisplayNameChanged, this, [this](ProjectExplorer::Project *p) { if (p == ProjectTree::currentProject()) emit displayNameChanged(); @@ -64,7 +64,7 @@ FileIterator *CurrentProjectFind::files(const QStringList &nameFilters, QTC_ASSERT(additionalParameters.isValid(), return new FileListIterator(FilePaths(), QList())); const FilePath projectFile = FilePath::fromVariant(additionalParameters); - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { if (project && projectFile == project->projectFilePath()) return filesForProjects(nameFilters, exclusionFilters, {project}); } @@ -87,7 +87,7 @@ void CurrentProjectFind::handleProjectChanged() void CurrentProjectFind::recheckEnabled(Core::SearchResult *search) { const FilePath projectFile = FilePath::fromVariant(getAdditionalParameters(search)); - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { if (projectFile == project->projectFilePath()) { search->setSearchAgainEnabled(true); return; diff --git a/src/plugins/projectexplorer/dependenciespanel.cpp b/src/plugins/projectexplorer/dependenciespanel.cpp index 1799126a5b9..c08ae7b523b 100644 --- a/src/plugins/projectexplorer/dependenciespanel.cpp +++ b/src/plugins/projectexplorer/dependenciespanel.cpp @@ -5,6 +5,7 @@ #include "project.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "session.h" #include @@ -32,19 +33,18 @@ DependenciesModel::DependenciesModel(Project *project, QObject *parent) { resetModel(); - SessionManager *sessionManager = SessionManager::instance(); - connect(sessionManager, &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, &DependenciesModel::resetModel); - connect(sessionManager, &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, &DependenciesModel::resetModel); - connect(sessionManager, &SessionManager::sessionLoaded, + connect(SessionManager::instance(), &SessionManager::sessionLoaded, this, &DependenciesModel::resetModel); } void DependenciesModel::resetModel() { beginResetModel(); - m_projects = SessionManager::projects(); + m_projects = ProjectManager::projects(); m_projects.removeAll(m_project); Utils::sort(m_projects, [](Project *a, Project *b) { return a->displayName() < b->displayName(); @@ -77,7 +77,7 @@ QVariant DependenciesModel::data(const QModelIndex &index, int role) const case Qt::ToolTipRole: return p->projectFilePath().toUserOutput(); case Qt::CheckStateRole: - return SessionManager::hasDependency(m_project, p) ? Qt::Checked : Qt::Unchecked; + return ProjectManager::hasDependency(m_project, p) ? Qt::Checked : Qt::Unchecked; case Qt::DecorationRole: return Utils::FileIconProvider::icon(p->projectFilePath()); default: @@ -92,7 +92,7 @@ bool DependenciesModel::setData(const QModelIndex &index, const QVariant &value, const auto c = static_cast(value.toInt()); if (c == Qt::Checked) { - if (SessionManager::addDependency(m_project, p)) { + if (ProjectManager::addDependency(m_project, p)) { emit dataChanged(index, index); return true; } else { @@ -100,8 +100,8 @@ bool DependenciesModel::setData(const QModelIndex &index, const QVariant &value, Tr::tr("This would create a circular dependency.")); } } else if (c == Qt::Unchecked) { - if (SessionManager::hasDependency(m_project, p)) { - SessionManager::removeDependency(m_project, p); + if (ProjectManager::hasDependency(m_project, p)) { + ProjectManager::removeDependency(m_project, p); emit dataChanged(index, index); return true; } @@ -215,9 +215,9 @@ DependenciesWidget::DependenciesWidget(Project *project, QWidget *parent) : Proj m_cascadeSetActiveCheckBox = new QCheckBox; m_cascadeSetActiveCheckBox->setText(Tr::tr("Synchronize configuration")); m_cascadeSetActiveCheckBox->setToolTip(Tr::tr("Synchronize active kit, build, and deploy configuration between projects.")); - m_cascadeSetActiveCheckBox->setChecked(SessionManager::isProjectConfigurationCascading()); + m_cascadeSetActiveCheckBox->setChecked(ProjectManager::isProjectConfigurationCascading()); connect(m_cascadeSetActiveCheckBox, &QCheckBox::toggled, - SessionManager::instance(), &SessionManager::setProjectConfigurationCascading); + ProjectManager::instance(), &ProjectManager::setProjectConfigurationCascading); layout->addWidget(m_cascadeSetActiveCheckBox, 1, 0, 2, 1); } diff --git a/src/plugins/projectexplorer/editorconfiguration.cpp b/src/plugins/projectexplorer/editorconfiguration.cpp index fc3933d7344..ff99bc25e83 100644 --- a/src/plugins/projectexplorer/editorconfiguration.cpp +++ b/src/plugins/projectexplorer/editorconfiguration.cpp @@ -5,7 +5,7 @@ #include "project.h" #include "projectexplorertr.h" -#include "session.h" +#include "projectmanager.h" #include @@ -88,7 +88,7 @@ EditorConfiguration::EditorConfiguration() : d(std::make_uniquem_defaultCodeStyle->setCurrentDelegate(TextEditorSettings::codeStyle()); - connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject, + connect(ProjectManager::instance(), &ProjectManager::aboutToRemoveProject, this, &EditorConfiguration::slotAboutToRemoveProject); } @@ -263,7 +263,7 @@ void EditorConfiguration::setUseGlobalSettings(bool use) const QList editors = Core::DocumentModel::editorsForOpenedDocuments(); for (Core::IEditor *editor : editors) { if (auto widget = TextEditorWidget::fromEditor(editor)) { - Project *project = SessionManager::projectForFile(editor->document()->filePath()); + Project *project = ProjectManager::projectForFile(editor->document()->filePath()); if (project && project->editorConfiguration() == this) switchSettings(widget); } @@ -399,7 +399,7 @@ TabSettings actualTabSettings(const Utils::FilePath &file, { if (baseTextdocument) return baseTextdocument->tabSettings(); - if (Project *project = SessionManager::projectForFile(file)) + if (Project *project = ProjectManager::projectForFile(file)) return project->editorConfiguration()->codeStyle()->tabSettings(); return TextEditorSettings::codeStyle()->tabSettings(); } diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index ffa0c494e9c..ccf2971774c 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -5,7 +5,7 @@ #include "buildmanager.h" #include "kitinformation.h" -#include "session.h" +#include "projectmanager.h" #include "target.h" #include @@ -63,7 +63,7 @@ ExtraCompiler::ExtraCompiler(const Project *project, const FilePath &source, connect(BuildManager::instance(), &BuildManager::buildStateChanged, this, &ExtraCompiler::onTargetsBuilt); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, [this](Project *project) { if (project == d->project) deleteLater(); diff --git a/src/plugins/projectexplorer/fileinsessionfinder.cpp b/src/plugins/projectexplorer/fileinsessionfinder.cpp index 78f75ce1d52..d8df6c74306 100644 --- a/src/plugins/projectexplorer/fileinsessionfinder.cpp +++ b/src/plugins/projectexplorer/fileinsessionfinder.cpp @@ -4,7 +4,7 @@ #include "fileinsessionfinder.h" #include "project.h" -#include "session.h" +#include "projectmanager.h" #include @@ -30,12 +30,12 @@ private: FileInSessionFinder::FileInSessionFinder() { - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this](const Project *p) { invalidateFinder(); connect(p, &Project::fileListChanged, this, &FileInSessionFinder::invalidateFinder); }); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, [this](const Project *p) { invalidateFinder(); p->disconnect(this); @@ -45,11 +45,11 @@ FileInSessionFinder::FileInSessionFinder() FilePaths FileInSessionFinder::doFindFile(const FilePath &filePath) { if (!m_finderIsUpToDate) { - m_finder.setProjectDirectory(SessionManager::startupProject() - ? SessionManager::startupProject()->projectDirectory() + m_finder.setProjectDirectory(ProjectManager::startupProject() + ? ProjectManager::startupProject()->projectDirectory() : FilePath()); FilePaths allFiles; - for (const Project * const p : SessionManager::projects()) + for (const Project * const p : ProjectManager::projects()) allFiles << p->files(Project::SourceFiles); m_finder.setProjectFiles(allFiles); m_finderIsUpToDate = true; diff --git a/src/plugins/projectexplorer/filesinallprojectsfind.cpp b/src/plugins/projectexplorer/filesinallprojectsfind.cpp index 720cfbabae8..0f9d6c40e25 100644 --- a/src/plugins/projectexplorer/filesinallprojectsfind.cpp +++ b/src/plugins/projectexplorer/filesinallprojectsfind.cpp @@ -5,7 +5,7 @@ #include "project.h" #include "projectexplorertr.h" -#include "session.h" +#include "projectmanager.h" #include #include @@ -52,7 +52,7 @@ Utils::FileIterator *FilesInAllProjectsFind::files(const QStringList &nameFilter const QVariant &additionalParameters) const { Q_UNUSED(additionalParameters) - const QSet dirs = Utils::transform(SessionManager::projects(), [](Project *p) { + const QSet dirs = Utils::transform(ProjectManager::projects(), [](Project *p) { return p->projectFilePath().parentDir(); }); return new SubDirFileIterator(FilePaths(dirs.constBegin(), dirs.constEnd()), diff --git a/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp index 024044d7a0a..ec55e3218fd 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonsummarypage.cpp @@ -8,8 +8,8 @@ #include "../projectexplorerconstants.h" #include "../projectexplorertr.h" #include "../projectnodes.h" +#include "../projectmanager.h" #include "../projecttree.h" -#include "../session.h" #include #include @@ -209,7 +209,7 @@ Node *JsonSummaryPage::findWizardContextNode(Node *contextNode) const // Static cast from void * to avoid qobject_cast (which needs a valid object) in value(). auto project = static_cast(m_wizard->value(Constants::PROJECT_POINTER).value()); - if (SessionManager::projects().contains(project) && project->rootProjectNode()) { + if (ProjectManager::projects().contains(project) && project->rootProjectNode()) { const FilePath path = FilePath::fromVariant(m_wizard->value(Constants::PREFERRED_PROJECT_NODE_PATH)); contextNode = project->rootProjectNode()->findNode([path](const Node *n) { return path == n->filePath(); diff --git a/src/plugins/projectexplorer/kitchooser.cpp b/src/plugins/projectexplorer/kitchooser.cpp index 14c848da740..9e45cacd7dd 100644 --- a/src/plugins/projectexplorer/kitchooser.cpp +++ b/src/plugins/projectexplorer/kitchooser.cpp @@ -6,7 +6,7 @@ #include "kitmanager.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" -#include "session.h" +#include "projectmanager.h" #include "target.h" #include @@ -88,7 +88,7 @@ void KitChooser::populate() const Id lastKit = Id::fromSetting(ICore::settings()->value(lastKitKey)); bool didActivate = false; - if (Target *target = SessionManager::startupTarget()) { + if (Target *target = ProjectManager::startupTarget()) { Kit *kit = target->kit(); if (m_kitPredicate(kit)) { QString display = Tr::tr("Kit of Active Project: %1").arg(kitText(kit)); diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index b169697cd8c..af9fdf5c50b 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -13,8 +13,8 @@ #include "projectexplorerconstants.h" #include "projectexplorericons.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "runconfiguration.h" -#include "session.h" #include "target.h" #include @@ -253,9 +253,9 @@ public: explicit ProjectListView(QWidget *parent = nullptr) : SelectorView(parent) { const auto model = new GenericModel(this); - model->rebuild(transform>(SessionManager::projects(), + model->rebuild(transform>(ProjectManager::projects(), [](Project *p) { return p; })); - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this, model](Project *project) { const GenericItem *projectItem = model->addItemForObject(project); QFontMetrics fn(font()); @@ -264,7 +264,7 @@ public: setOptimalWidth(width); restoreCurrentIndex(); }); - connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject, + connect(ProjectManager::instance(), &ProjectManager::aboutToRemoveProject, this, [this, model](const Project *project) { GenericItem * const item = model->itemForObject(project); if (!item) @@ -272,7 +272,7 @@ public: model->destroyItem(item); resetOptimalWidth(); }); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, [this, model](const Project *project) { const GenericItem * const item = model->itemForObject(project); if (item) @@ -288,7 +288,7 @@ public: this, [model](const QModelIndex &index) { const GenericItem * const item = model->itemForIndex(index); if (item && item->object()) - SessionManager::setStartupProject(qobject_cast(item->object())); + ProjectManager::setStartupProject(qobject_cast(item->object())); }); } @@ -296,7 +296,7 @@ private: void restoreCurrentIndex() { const GenericItem * const itemForStartupProject - = theModel()->itemForObject(SessionManager::startupProject()); + = theModel()->itemForObject(ProjectManager::startupProject()); if (itemForStartupProject) setCurrentIndex(theModel()->indexForItem(itemForStartupProject)); } @@ -696,22 +696,22 @@ MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorActi m_listWidgets[RUN]->viewport()->setAttribute(Qt::WA_Hover); // Validate state: At this point the session is still empty! - Project *startup = SessionManager::startupProject(); + Project *startup = ProjectManager::startupProject(); QTC_CHECK(!startup); - QTC_CHECK(SessionManager::projects().isEmpty()); + QTC_CHECK(ProjectManager::projects().isEmpty()); connect(m_summaryLabel, &QLabel::linkActivated, this, &MiniProjectTargetSelector::switchToProjectsMode); - SessionManager *sessionManager = SessionManager::instance(); - connect(sessionManager, &SessionManager::startupProjectChanged, + ProjectManager *sessionManager = ProjectManager::instance(); + connect(sessionManager, &ProjectManager::startupProjectChanged, this, &MiniProjectTargetSelector::changeStartupProject); - connect(sessionManager, &SessionManager::projectAdded, + connect(sessionManager, &ProjectManager::projectAdded, this, &MiniProjectTargetSelector::projectAdded); - connect(sessionManager, &SessionManager::projectRemoved, + connect(sessionManager, &ProjectManager::projectRemoved, this, &MiniProjectTargetSelector::projectRemoved); - connect(sessionManager, &SessionManager::projectDisplayNameChanged, + connect(sessionManager, &ProjectManager::projectDisplayNameChanged, this, &MiniProjectTargetSelector::updateActionAndSummary); // for icon changes: @@ -720,17 +720,17 @@ MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorActi connect(m_listWidgets[TARGET], &GenericListWidget::changeActiveProjectConfiguration, this, [this](QObject *pc) { - SessionManager::setActiveTarget(m_project, static_cast(pc), SetActive::Cascade); + m_project->setActiveTarget(static_cast(pc), SetActive::Cascade); }); connect(m_listWidgets[BUILD], &GenericListWidget::changeActiveProjectConfiguration, this, [this](QObject *pc) { - SessionManager::setActiveBuildConfiguration(m_project->activeTarget(), - static_cast(pc), SetActive::Cascade); + m_project->activeTarget()->setActiveBuildConfiguration( + static_cast(pc), SetActive::Cascade); }); connect(m_listWidgets[DEPLOY], &GenericListWidget::changeActiveProjectConfiguration, this, [this](QObject *pc) { - SessionManager::setActiveDeployConfiguration(m_project->activeTarget(), - static_cast(pc), SetActive::Cascade); + m_project->activeTarget()->setActiveDeployConfiguration( + static_cast(pc), SetActive::Cascade); }); connect(m_listWidgets[RUN], &GenericListWidget::changeActiveProjectConfiguration, this, [this](QObject *pc) { @@ -881,7 +881,7 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) onlySummary = true; } else { if (visibleLineCount < 3) { - if (Utils::anyOf(SessionManager::projects(), &Project::needsConfiguration)) + if (Utils::anyOf(ProjectManager::projects(), &Project::needsConfiguration)) visibleLineCount = 3; } if (visibleLineCount) @@ -1126,7 +1126,7 @@ void MiniProjectTargetSelector::removedRunConfiguration(RunConfiguration *rc, bo void MiniProjectTargetSelector::updateProjectListVisible() { - int count = SessionManager::projects().size(); + int count = ProjectManager::projects().size(); bool visible = count > 1; m_projectListWidget->setVisible(visible); @@ -1139,7 +1139,7 @@ void MiniProjectTargetSelector::updateProjectListVisible() void MiniProjectTargetSelector::updateTargetListVisible() { int maxCount = 0; - for (Project *p : SessionManager::projects()) + for (Project *p : ProjectManager::projects()) maxCount = qMax(p->targets().size(), maxCount); bool visible = maxCount > 1; @@ -1152,7 +1152,7 @@ void MiniProjectTargetSelector::updateTargetListVisible() void MiniProjectTargetSelector::updateBuildListVisible() { int maxCount = 0; - for (Project *p : SessionManager::projects()) { + for (Project *p : ProjectManager::projects()) { const QList targets = p->targets(); for (Target *t : targets) maxCount = qMax(t->buildConfigurations().size(), maxCount); @@ -1168,7 +1168,7 @@ void MiniProjectTargetSelector::updateBuildListVisible() void MiniProjectTargetSelector::updateDeployListVisible() { int maxCount = 0; - for (Project *p : SessionManager::projects()) { + for (Project *p : ProjectManager::projects()) { const QList targets = p->targets(); for (Target *t : targets) maxCount = qMax(t->deployConfigurations().size(), maxCount); @@ -1184,7 +1184,7 @@ void MiniProjectTargetSelector::updateDeployListVisible() void MiniProjectTargetSelector::updateRunListVisible() { int maxCount = 0; - for (Project *p : SessionManager::projects()) { + for (Project *p : ProjectManager::projects()) { const QList targets = p->targets(); for (Target *t : targets) maxCount = qMax(t->runConfigurations().size(), maxCount); @@ -1460,10 +1460,10 @@ void MiniProjectTargetSelector::updateActionAndSummary() ? Icons::DESKTOP_DEVICE.icon() : style()->standardIcon(QStyle::SP_ComputerIcon); - Project *project = SessionManager::startupProject(); + Project *project = ProjectManager::startupProject(); if (project) { projectName = project->displayName(); - for (Project *p : SessionManager::projects()) { + for (Project *p : ProjectManager::projects()) { if (p != project && p->displayName() == projectName) { fileName = project->projectFilePath().toUserOutput(); break; @@ -1515,7 +1515,7 @@ void MiniProjectTargetSelector::updateActionAndSummary() void MiniProjectTargetSelector::updateSummary() { QString summary; - if (Project *startupProject = SessionManager::startupProject()) { + if (Project *startupProject = ProjectManager::startupProject()) { if (!m_projectListWidget->isVisibleTo(this)) summary.append(Tr::tr("Project: %1
").arg(startupProject->displayName())); if (Target *activeTarget = startupProject->activeTarget()) { diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index fbd4f9e28fd..84f5363cd11 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -14,10 +14,10 @@ #include "projectexplorer.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectnodes.h" #include "runconfiguration.h" #include "runconfigurationaspects.h" -#include "session.h" #include "target.h" #include "taskhub.h" #include "userfileaccessor.h" @@ -273,7 +273,7 @@ void Project::addTarget(std::unique_ptr &&t) // check activeTarget: if (!activeTarget()) - SessionManager::setActiveTarget(this, pointer, SetActive::Cascade); + setActiveTarget(pointer, SetActive::Cascade); } Target *Project::addTargetForDefaultKit() @@ -309,7 +309,7 @@ bool Project::removeTarget(Target *target) auto keep = take(d->m_targets, target); if (target == d->m_activeTarget) { Target *newActiveTarget = (d->m_targets.size() == 0 ? nullptr : d->m_targets.at(0).get()); - SessionManager::setActiveTarget(this, newActiveTarget, SetActive::Cascade); + setActiveTarget(newActiveTarget, SetActive::Cascade); } emit removedTarget(target); @@ -326,7 +326,7 @@ Target *Project::activeTarget() const return d->m_activeTarget; } -void Project::setActiveTarget(Target *target) +void Project::setActiveTargetHelper(Target *target) { if (d->m_activeTarget == target) return; @@ -414,6 +414,29 @@ Target *Project::target(Kit *k) const return findOrDefault(d->m_targets, equal(&Target::kit, k)); } +void Project::setActiveTarget(Target *target, SetActive cascade) +{ + if (isShuttingDown()) + return; + + setActiveTargetHelper(target); + + if (!target) // never cascade setting no target + return; + + if (cascade != SetActive::Cascade || !ProjectManager::isProjectConfigurationCascading()) + return; + + Utils::Id kitId = target->kit()->id(); + for (Project *otherProject : ProjectManager::projects()) { + if (otherProject == this) + continue; + if (Target *otherTarget = Utils::findOrDefault(otherProject->targets(), + [kitId](Target *t) { return t->kit()->id() == kitId; })) + otherProject->setActiveTargetHelper(otherTarget); + } +} + Tasks Project::projectIssues(const Kit *k) const { Tasks result; @@ -445,12 +468,12 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget) sourceBc->buildSystem()->name())); newTarget->addBuildConfiguration(newBc); if (sourceTarget->activeBuildConfiguration() == sourceBc) - SessionManager::setActiveBuildConfiguration(newTarget, newBc, SetActive::NoCascade); + newTarget->setActiveBuildConfiguration(newBc, SetActive::NoCascade); } if (!newTarget->activeBuildConfiguration()) { QList bcs = newTarget->buildConfigurations(); if (!bcs.isEmpty()) - SessionManager::setActiveBuildConfiguration(newTarget, bcs.first(), SetActive::NoCascade); + newTarget->setActiveBuildConfiguration(bcs.first(), SetActive::NoCascade); } for (DeployConfiguration *sourceDc : sourceTarget->deployConfigurations()) { @@ -462,12 +485,12 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget) newDc->setDisplayName(sourceDc->displayName()); newTarget->addDeployConfiguration(newDc); if (sourceTarget->activeDeployConfiguration() == sourceDc) - SessionManager::setActiveDeployConfiguration(newTarget, newDc, SetActive::NoCascade); + newTarget->setActiveDeployConfiguration(newDc, SetActive::NoCascade); } if (!newTarget->activeBuildConfiguration()) { QList dcs = newTarget->deployConfigurations(); if (!dcs.isEmpty()) - SessionManager::setActiveDeployConfiguration(newTarget, dcs.first(), SetActive::NoCascade); + newTarget->setActiveDeployConfiguration(dcs.first(), SetActive::NoCascade); } for (RunConfiguration *sourceRc : sourceTarget->runConfigurations()) { @@ -1435,8 +1458,7 @@ void ProjectExplorerPlugin::testProject_multipleBuildConfigs() Target * const target = theProject.project()->activeTarget(); QVERIFY(target); QCOMPARE(target->buildConfigurations().size(), 6); - SessionManager::setActiveBuildConfiguration(target, target->buildConfigurations().at(1), - SetActive::Cascade); + target->setActiveBuildConfiguration(target->buildConfigurations().at(1), SetActive::Cascade); BuildSystem * const bs = theProject.project()->activeTarget()->buildSystem(); QVERIFY(bs); QCOMPARE(bs, target->activeBuildConfiguration()->buildSystem()); @@ -1452,12 +1474,12 @@ void ProjectExplorerPlugin::testProject_multipleBuildConfigs() } QVERIFY(!bs->isWaitingForParse() && !bs->isParsing()); - QCOMPARE(SessionManager::startupProject(), theProject.project()); + QCOMPARE(ProjectManager::startupProject(), theProject.project()); QCOMPARE(ProjectTree::currentProject(), theProject.project()); QVERIFY(EditorManager::openEditor(projectDir.pathAppended("main.cpp"))); QVERIFY(ProjectTree::currentNode()); ProjectTree::instance()->expandAll(); - SessionManager::closeAllProjects(); // QTCREATORBUG-25655 + ProjectManager::closeAllProjects(); // QTCREATORBUG-25655 } #endif // WITH_TESTS diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index ed336b5f7f3..ebf38a688d4 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -36,6 +36,7 @@ class ProjectImporter; class ProjectNode; class ProjectPrivate; class Target; +enum class SetActive : int; // Documentation inside. class PROJECTEXPLORER_EXPORT Project : public QObject @@ -89,6 +90,8 @@ public: Target *activeTarget() const; Target *target(Utils::Id id) const; Target *target(Kit *k) const; + void setActiveTarget(Target *target, SetActive cascade); + virtual Tasks projectIssues(const Kit *k) const; static bool copySteps(Target *sourceTarget, Target *newTarget); @@ -226,7 +229,7 @@ private: void removeProjectLanguage(Utils::Id id); void handleSubTreeChanged(FolderNode *node); - void setActiveTarget(Target *target); + void setActiveTargetHelper(Target *target); friend class ContainerNode; ProjectPrivate *d; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index a260d211ab2..8842b1f1cab 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -338,7 +338,7 @@ static BuildConfiguration *currentBuildConfiguration() static Target *activeTarget() { - const Project * const project = SessionManager::startupProject(); + const Project * const project = ProjectManager::startupProject(); return project ? project->activeTarget() : nullptr; } @@ -668,7 +668,8 @@ public: RemoveTaskHandler m_removeTaskHandler; ConfigTaskHandler m_configTaskHandler{Task::compilerMissingTask(), Constants::KITS_SETTINGS_PAGE_ID}; - SessionManager m_sessionManager; + SessionManager m_sessionBase; + ProjectManager m_sessionManager; AppOutputPane m_outputPane; ProjectTree m_projectTree; @@ -835,33 +836,33 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(&dd->m_welcomePage, &ProjectWelcomePage::manageSessions, dd, &ProjectExplorerPluginPrivate::showSessionManager); - SessionManager *sessionManager = &dd->m_sessionManager; - connect(sessionManager, &SessionManager::projectAdded, + ProjectManager *sessionManager = &dd->m_sessionManager; + connect(sessionManager, &ProjectManager::projectAdded, this, &ProjectExplorerPlugin::fileListChanged); - connect(sessionManager, &SessionManager::aboutToRemoveProject, + connect(sessionManager, &ProjectManager::aboutToRemoveProject, dd, &ProjectExplorerPluginPrivate::invalidateProject); - connect(sessionManager, &SessionManager::projectRemoved, + connect(sessionManager, &ProjectManager::projectRemoved, this, &ProjectExplorerPlugin::fileListChanged); - connect(sessionManager, &SessionManager::projectAdded, + connect(sessionManager, &ProjectManager::projectAdded, dd, &ProjectExplorerPluginPrivate::projectAdded); - connect(sessionManager, &SessionManager::projectRemoved, + connect(sessionManager, &ProjectManager::projectRemoved, dd, &ProjectExplorerPluginPrivate::projectRemoved); - connect(sessionManager, &SessionManager::projectDisplayNameChanged, + connect(sessionManager, &ProjectManager::projectDisplayNameChanged, dd, &ProjectExplorerPluginPrivate::projectDisplayNameChanged); - connect(sessionManager, &SessionManager::dependencyChanged, + connect(sessionManager, &ProjectManager::dependencyChanged, dd, &ProjectExplorerPluginPrivate::updateActions); - connect(sessionManager, &SessionManager::sessionLoaded, + connect(SessionManager::instance(), &SessionManager::sessionLoaded, dd, &ProjectExplorerPluginPrivate::updateActions); - connect(sessionManager, &SessionManager::sessionLoaded, + connect(SessionManager::instance(), &SessionManager::sessionLoaded, dd, &ProjectExplorerPluginPrivate::updateWelcomePage); - connect(sessionManager, &SessionManager::sessionLoaded, + connect(SessionManager::instance(), &SessionManager::sessionLoaded, dd, &ProjectExplorerPluginPrivate::loadSesssionTasks); - connect(sessionManager, &SessionManager::projectAdded, dd, [](ProjectExplorer::Project *project) { + connect(sessionManager, &ProjectManager::projectAdded, dd, [](ProjectExplorer::Project *project) { dd->m_allProjectDirectoriesFilter.addDirectory(project->projectDirectory()); }); connect(sessionManager, - &SessionManager::projectRemoved, + &ProjectManager::projectRemoved, dd, [](ProjectExplorer::Project *project) { dd->m_allProjectDirectoriesFilter.removeDirectory(project->projectDirectory()); @@ -904,7 +905,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er ICore::addPreCloseListener([]() -> bool { return coreAboutToClose(); }); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, &dd->m_outputPane, &AppOutputPane::projectRemoved); // ProjectPanelFactories @@ -1346,7 +1347,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er // without a project loaded. connect(generatorContainer->menu(), &QMenu::aboutToShow, [menu = generatorContainer->menu()] { menu->clear(); - if (Project * const project = SessionManager::startupProject()) { + if (Project * const project = ProjectManager::startupProject()) { for (const auto &generator : project->allGenerators()) { menu->addAction(generator.second, [project, id = generator.first] { project->runGenerator(id); @@ -1660,7 +1661,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd, &ProjectExplorerPluginPrivate::savePersistentSettings); connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] { if (!dd->m_shuttingDown && !SessionManager::loadingSession()) - SessionManager::save(); + ProjectManager::save(); }); connect(qApp, &QApplication::applicationStateChanged, this, [](Qt::ApplicationState state) { if (!dd->m_shuttingDown && state == Qt::ApplicationActive) @@ -1765,20 +1766,20 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(dd->m_loadAction, &QAction::triggered, dd, &ProjectExplorerPluginPrivate::loadAction); connect(dd->m_buildProjectOnlyAction, &QAction::triggered, dd, [] { - BuildManager::buildProjectWithoutDependencies(SessionManager::startupProject()); + BuildManager::buildProjectWithoutDependencies(ProjectManager::startupProject()); }); connect(dd->m_buildAction, &QAction::triggered, dd, [] { - BuildManager::buildProjectWithDependencies(SessionManager::startupProject()); + BuildManager::buildProjectWithDependencies(ProjectManager::startupProject()); }); connect(dd->m_buildProjectForAllConfigsAction, &QAction::triggered, dd, [] { - BuildManager::buildProjectWithDependencies(SessionManager::startupProject(), + BuildManager::buildProjectWithDependencies(ProjectManager::startupProject(), ConfigSelection::All); }); connect(dd->m_buildActionContextMenu, &QAction::triggered, dd, [] { BuildManager::buildProjectWithoutDependencies(ProjectTree::currentProject()); }); connect(dd->m_buildForRunConfigAction, &QAction::triggered, dd, [] { - const Project * const project = SessionManager::startupProject(); + const Project * const project = ProjectManager::startupProject(); QTC_ASSERT(project, return); const Target * const target = project->activeTarget(); QTC_ASSERT(target, return); @@ -1793,20 +1794,20 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er BuildManager::buildProjectWithDependencies(ProjectTree::currentProject()); }); connect(dd->m_buildSessionAction, &QAction::triggered, dd, [] { - BuildManager::buildProjects(SessionManager::projectOrder(), ConfigSelection::Active); + BuildManager::buildProjects(ProjectManager::projectOrder(), ConfigSelection::Active); }); connect(dd->m_buildSessionForAllConfigsAction, &QAction::triggered, dd, [] { - BuildManager::buildProjects(SessionManager::projectOrder(), ConfigSelection::All); + BuildManager::buildProjects(ProjectManager::projectOrder(), ConfigSelection::All); }); connect(dd->m_rebuildProjectOnlyAction, &QAction::triggered, dd, [] { - BuildManager::rebuildProjectWithoutDependencies(SessionManager::startupProject()); + BuildManager::rebuildProjectWithoutDependencies(ProjectManager::startupProject()); }); connect(dd->m_rebuildAction, &QAction::triggered, dd, [] { - BuildManager::rebuildProjectWithDependencies(SessionManager::startupProject(), + BuildManager::rebuildProjectWithDependencies(ProjectManager::startupProject(), ConfigSelection::Active); }); connect(dd->m_rebuildProjectForAllConfigsAction, &QAction::triggered, dd, [] { - BuildManager::rebuildProjectWithDependencies(SessionManager::startupProject(), + BuildManager::rebuildProjectWithDependencies(ProjectManager::startupProject(), ConfigSelection::All); }); connect(dd->m_rebuildActionContextMenu, &QAction::triggered, dd, [] { @@ -1817,32 +1818,32 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er ConfigSelection::Active); }); connect(dd->m_rebuildSessionAction, &QAction::triggered, dd, [] { - BuildManager::rebuildProjects(SessionManager::projectOrder(), ConfigSelection::Active); + BuildManager::rebuildProjects(ProjectManager::projectOrder(), ConfigSelection::Active); }); connect(dd->m_rebuildSessionForAllConfigsAction, &QAction::triggered, dd, [] { - BuildManager::rebuildProjects(SessionManager::projectOrder(), ConfigSelection::All); + BuildManager::rebuildProjects(ProjectManager::projectOrder(), ConfigSelection::All); }); connect(dd->m_deployProjectOnlyAction, &QAction::triggered, dd, [] { - BuildManager::deployProjects({SessionManager::startupProject()}); + BuildManager::deployProjects({ProjectManager::startupProject()}); }); connect(dd->m_deployAction, &QAction::triggered, dd, [] { - BuildManager::deployProjects(SessionManager::projectOrder(SessionManager::startupProject())); + BuildManager::deployProjects(ProjectManager::projectOrder(ProjectManager::startupProject())); }); connect(dd->m_deployActionContextMenu, &QAction::triggered, dd, [] { BuildManager::deployProjects({ProjectTree::currentProject()}); }); connect(dd->m_deploySessionAction, &QAction::triggered, dd, [] { - BuildManager::deployProjects(SessionManager::projectOrder()); + BuildManager::deployProjects(ProjectManager::projectOrder()); }); connect(dd->m_cleanProjectOnlyAction, &QAction::triggered, dd, [] { - BuildManager::cleanProjectWithoutDependencies(SessionManager::startupProject()); + BuildManager::cleanProjectWithoutDependencies(ProjectManager::startupProject()); }); connect(dd->m_cleanAction, &QAction::triggered, dd, [] { - BuildManager::cleanProjectWithDependencies(SessionManager::startupProject(), + BuildManager::cleanProjectWithDependencies(ProjectManager::startupProject(), ConfigSelection::Active); }); connect(dd->m_cleanProjectForAllConfigsAction, &QAction::triggered, dd, [] { - BuildManager::cleanProjectWithDependencies(SessionManager::startupProject(), + BuildManager::cleanProjectWithDependencies(ProjectManager::startupProject(), ConfigSelection::All); }); connect(dd->m_cleanActionContextMenu, &QAction::triggered, dd, [] { @@ -1853,10 +1854,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er ConfigSelection::Active); }); connect(dd->m_cleanSessionAction, &QAction::triggered, dd, [] { - BuildManager::cleanProjects(SessionManager::projectOrder(), ConfigSelection::Active); + BuildManager::cleanProjects(ProjectManager::projectOrder(), ConfigSelection::Active); }); connect(dd->m_cleanSessionForAllConfigsAction, &QAction::triggered, dd, [] { - BuildManager::cleanProjects(SessionManager::projectOrder(), ConfigSelection::All); + BuildManager::cleanProjects(ProjectManager::projectOrder(), ConfigSelection::All); }); connect(dd->m_runAction, &QAction::triggered, dd, [] { runStartupProject(Constants::NORMAL_RUN_MODE); }); @@ -1921,7 +1922,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(dd->m_setStartupProjectAction, &QAction::triggered, dd, &ProjectExplorerPluginPrivate::handleSetStartupProject); connect(dd->m_closeProjectFilesActionFileMenu, &QAction::triggered, - dd, [] { dd->closeAllFilesInProject(SessionManager::projects().first()); }); + dd, [] { dd->closeAllFilesInProject(ProjectManager::projects().first()); }); connect(dd->m_closeProjectFilesActionContextMenu, &QAction::triggered, dd, [] { dd->closeAllFilesInProject(ProjectTree::currentProject()); }); connect(dd->m_projectTreeCollapseAllAction, &QAction::triggered, @@ -1966,7 +1967,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er Project::addVariablesToMacroExpander("ActiveProject:", "Active project", expander, - &SessionManager::startupProject); + &ProjectManager::startupProject); EnvironmentProvider::addProvider( {"ActiveProject:BuildConfig:Env", Tr::tr("Active build environment of the active project."), [] { if (const BuildConfiguration * const bc = activeBuildConfiguration()) @@ -2033,7 +2034,7 @@ void ProjectExplorerPluginPrivate::unloadProjectContextMenu() void ProjectExplorerPluginPrivate::unloadOtherProjectsContextMenu() { if (Project *currentProject = ProjectTree::currentProject()) { - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); QTC_ASSERT(!projects.isEmpty(), return); for (Project *p : projects) { @@ -2046,7 +2047,7 @@ void ProjectExplorerPluginPrivate::unloadOtherProjectsContextMenu() void ProjectExplorerPluginPrivate::handleUnloadProject() { - QList projects = SessionManager::projects(); + QList projects = ProjectManager::projects(); QTC_ASSERT(!projects.isEmpty(), return); ProjectExplorerPlugin::unloadProject(projects.first()); @@ -2073,7 +2074,7 @@ void ProjectExplorerPlugin::unloadProject(Project *project) dd->addToRecentProjects(project->projectFilePath(), project->displayName()); - SessionManager::removeProject(project); + ProjectManager::removeProject(project); dd->updateActions(); } @@ -2082,7 +2083,7 @@ void ProjectExplorerPluginPrivate::closeAllProjects() if (!EditorManager::closeAllDocuments()) return; // Action has been cancelled - SessionManager::closeAllProjects(); + ProjectManager::closeAllProjects(); updateActions(); ModeManager::activateMode(Core::Constants::MODE_WELCOME); @@ -2196,7 +2197,7 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown() dd, &ProjectExplorerPluginPrivate::currentModeChanged); ProjectTree::aboutToShutDown(); ToolChainManager::aboutToShutdown(); - SessionManager::closeAllProjects(); + ProjectManager::closeAllProjects(); dd->m_shuttingDown = true; @@ -2229,7 +2230,7 @@ void ProjectExplorerPlugin::openNewProjectDialog() void ProjectExplorerPluginPrivate::showSessionManager() { - SessionManager::save(); + ProjectManager::save(); SessionDialog sessionDialog(ICore::dialogParent()); sessionDialog.setAutoLoadSession(dd->m_projectExplorerSettings.autorestoreLastSession); sessionDialog.exec(); @@ -2245,7 +2246,7 @@ void ProjectExplorerPluginPrivate::setStartupProject(Project *project) { if (!project) return; - SessionManager::setStartupProject(project); + ProjectManager::setStartupProject(project); updateActions(); } @@ -2256,7 +2257,7 @@ bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project Utils::erase(openFiles, [project](const DocumentModel::Entry *entry) { return entry->pinned || !project->isKnownFile(entry->filePath()); }); - for (const Project * const otherProject : SessionManager::projects()) { + for (const Project * const otherProject : ProjectManager::projects()) { if (otherProject == project) continue; Utils::erase(openFiles, [otherProject](const DocumentModel::Entry *entry) { @@ -2272,10 +2273,10 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() return; if (!SessionManager::loadingSession()) { - for (Project *pro : SessionManager::projects()) + for (Project *pro : ProjectManager::projects()) pro->saveSettings(); - SessionManager::save(); + ProjectManager::save(); } QtcSettings *s = ICore::settings(); @@ -2369,7 +2370,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProject(cons if (!project) return result; dd->addToRecentProjects(filePath, project->displayName()); - SessionManager::setStartupProject(project); + ProjectManager::setStartupProject(project); return result; } @@ -2421,11 +2422,11 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con QTC_ASSERT(!fileName.isEmpty(), continue); const FilePath filePath = fileName.absoluteFilePath(); - Project *found = Utils::findOrDefault(SessionManager::projects(), + Project *found = Utils::findOrDefault(ProjectManager::projects(), Utils::equal(&Project::projectFilePath, filePath)); if (found) { alreadyOpen.append(found); - SessionManager::reportProjectLoadingProgress(); + ProjectManager::reportProjectLoadingProgress(); continue; } @@ -2440,7 +2441,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con if (restoreResult == Project::RestoreResult::Ok) { connect(pro, &Project::fileListChanged, m_instance, &ProjectExplorerPlugin::fileListChanged); - SessionManager::addProject(pro); + ProjectManager::addProject(pro); openedPro += pro; } else { if (restoreResult == Project::RestoreResult::Error) @@ -2454,7 +2455,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con .arg(mt.name())); } if (filePaths.size() > 1) - SessionManager::reportProjectLoadingProgress(); + ProjectManager::reportProjectLoadingProgress(); } dd->updateActions(); @@ -2595,7 +2596,7 @@ void ProjectExplorerPluginPrivate::restoreSession() } // !arguments.isEmpty() // Restore latest session or what was passed on the command line - SessionManager::loadSession(!dd->m_sessionToRestoreAtStartup.isEmpty() + ProjectManager::loadSession(!dd->m_sessionToRestoreAtStartup.isEmpty() ? dd->m_sessionToRestoreAtStartup : QString(), true); // update welcome page @@ -2733,7 +2734,7 @@ RecentProjectsEntries ProjectExplorerPluginPrivate::recentProjects() const void ProjectExplorerPluginPrivate::updateActions() { - const Project *const project = SessionManager::startupProject(); + const Project *const project = ProjectManager::startupProject(); const Project *const currentProject = ProjectTree::currentProject(); // for context menu actions const QPair buildActionState = buildSettingsEnabled(project); @@ -2744,10 +2745,10 @@ void ProjectExplorerPluginPrivate::updateActions() const QString projectName = project ? project->displayName() : QString(); const QString projectNameContextMenu = currentProject ? currentProject->displayName() : QString(); - m_unloadAction->setParameter(SessionManager::projects().size() == 1 ? projectName : QString()); + m_unloadAction->setParameter(ProjectManager::projects().size() == 1 ? projectName : QString()); m_unloadActionContextMenu->setParameter(projectNameContextMenu); m_unloadOthersActionContextMenu->setParameter(projectNameContextMenu); - m_closeProjectFilesActionFileMenu->setParameter(SessionManager::projects().size() == 1 + m_closeProjectFilesActionFileMenu->setParameter(ProjectManager::projects().size() == 1 ? projectName : QString()); m_closeProjectFilesActionContextMenu->setParameter(projectNameContextMenu); @@ -2792,7 +2793,7 @@ void ProjectExplorerPluginPrivate::updateActions() m_setStartupProjectAction->setParameter(projectNameContextMenu); m_setStartupProjectAction->setVisible(currentProject != project); - const bool hasDependencies = SessionManager::projectOrder(currentProject).size() > 1; + const bool hasDependencies = ProjectManager::projectOrder(currentProject).size() > 1; m_buildActionContextMenu->setVisible(hasDependencies); m_rebuildActionContextMenu->setVisible(hasDependencies); m_cleanActionContextMenu->setVisible(hasDependencies); @@ -2819,17 +2820,17 @@ void ProjectExplorerPluginPrivate::updateActions() m_cleanProjectOnlyAction->setToolTip(buildActionState.second); // Session actions - m_closeAllProjects->setEnabled(SessionManager::hasProjects()); - m_unloadAction->setEnabled(SessionManager::projects().size() <= 1); - m_unloadAction->setEnabled(SessionManager::projects().size() == 1); - m_unloadActionContextMenu->setEnabled(SessionManager::hasProjects()); - m_unloadOthersActionContextMenu->setEnabled(SessionManager::projects().size() >= 2); - m_closeProjectFilesActionFileMenu->setEnabled(SessionManager::projects().size() == 1); - m_closeProjectFilesActionContextMenu->setEnabled(SessionManager::hasProjects()); + m_closeAllProjects->setEnabled(ProjectManager::hasProjects()); + m_unloadAction->setEnabled(ProjectManager::projects().size() <= 1); + m_unloadAction->setEnabled(ProjectManager::projects().size() == 1); + m_unloadActionContextMenu->setEnabled(ProjectManager::hasProjects()); + m_unloadOthersActionContextMenu->setEnabled(ProjectManager::projects().size() >= 2); + m_closeProjectFilesActionFileMenu->setEnabled(ProjectManager::projects().size() == 1); + m_closeProjectFilesActionContextMenu->setEnabled(ProjectManager::hasProjects()); ActionContainer *aci = ActionManager::actionContainer(Constants::M_UNLOADPROJECTS); - aci->menu()->menuAction()->setEnabled(SessionManager::hasProjects()); + aci->menu()->menuAction()->setEnabled(ProjectManager::hasProjects()); m_buildSessionAction->setEnabled(buildSessionState.first); m_buildSessionForAllConfigsAction->setEnabled(buildSessionState.first); @@ -2847,7 +2848,7 @@ void ProjectExplorerPluginPrivate::updateActions() m_cancelBuildAction->setEnabled(BuildManager::isBuilding()); - const bool hasProjects = SessionManager::hasProjects(); + const bool hasProjects = ProjectManager::hasProjects(); m_projectSelectorAction->setEnabled(hasProjects); m_projectSelectorActionMenu->setEnabled(hasProjects); m_projectSelectorActionQuick->setEnabled(hasProjects); @@ -2968,7 +2969,7 @@ void ProjectExplorerPluginPrivate::runProjectContextMenu(RunConfiguration *rc) static bool hasBuildSettings(const Project *pro) { - return Utils::anyOf(SessionManager::projectOrder(pro), [](const Project *project) { + return Utils::anyOf(ProjectManager::projectOrder(pro), [](const Project *project) { return project && project->activeTarget() && project->activeTarget()->activeBuildConfiguration(); @@ -2980,7 +2981,7 @@ static QPair subprojectEnabledState(const Project *pro) QPair result; result.first = true; - const QList &projects = SessionManager::projectOrder(pro); + const QList &projects = ProjectManager::projectOrder(pro); for (const Project *project : projects) { if (project && project->activeTarget() && project->activeTarget()->activeBuildConfiguration() @@ -3022,7 +3023,7 @@ QPair ProjectExplorerPluginPrivate::buildSettingsEnabledForSessio { QPair result; result.first = true; - if (!SessionManager::hasProjects()) { + if (!ProjectManager::hasProjects()) { result.first = false; result.second = Tr::tr("No project loaded."); } else if (BuildManager::isBuilding()) { @@ -3079,7 +3080,7 @@ void ProjectExplorerPlugin::handleCommandLineArguments(const QStringList &argume static bool hasDeploySettings(Project *pro) { - return Utils::anyOf(SessionManager::projectOrder(pro), [](Project *project) { + return Utils::anyOf(ProjectManager::projectOrder(pro), [](Project *project) { return project->activeTarget() && project->activeTarget()->activeDeployConfiguration(); }); @@ -3097,7 +3098,7 @@ void ProjectExplorerPlugin::runProject(Project *pro, Id mode, const bool forceSk void ProjectExplorerPlugin::runStartupProject(Id runMode, bool forceSkipDeploy) { - runProject(SessionManager::startupProject(), runMode, forceSkipDeploy); + runProject(ProjectManager::startupProject(), runMode, forceSkipDeploy); } void ProjectExplorerPlugin::runRunConfiguration(RunConfiguration *rc, @@ -3158,7 +3159,7 @@ void ProjectExplorerPluginPrivate::projectAdded(Project *pro) void ProjectExplorerPluginPrivate::projectRemoved(Project *pro) { Q_UNUSED(pro) - m_projectsMode.setEnabled(SessionManager::hasProjects()); + m_projectsMode.setEnabled(ProjectManager::hasProjects()); } void ProjectExplorerPluginPrivate::projectDisplayNameChanged(Project *pro) @@ -3169,7 +3170,7 @@ void ProjectExplorerPluginPrivate::projectDisplayNameChanged(Project *pro) void ProjectExplorerPluginPrivate::updateDeployActions() { - Project *project = SessionManager::startupProject(); + Project *project = ProjectManager::startupProject(); bool enableDeployActions = project && !BuildManager::isBuilding(project) @@ -3188,7 +3189,7 @@ void ProjectExplorerPluginPrivate::updateDeployActions() enableDeployActionsContextMenu = false; } - bool hasProjects = SessionManager::hasProjects(); + bool hasProjects = ProjectManager::hasProjects(); m_deployAction->setEnabled(enableDeployActions); @@ -3204,7 +3205,7 @@ void ProjectExplorerPluginPrivate::updateDeployActions() && !project->activeTarget()->activeBuildConfiguration()->isEnabled(); }; - if (Utils::anyOf(SessionManager::projectOrder(nullptr), hasDisabledBuildConfiguration)) + if (Utils::anyOf(ProjectManager::projectOrder(nullptr), hasDisabledBuildConfiguration)) enableDeploySessionAction = false; } if (!hasProjects || !hasDeploySettings(nullptr) || BuildManager::isBuilding()) @@ -3216,7 +3217,7 @@ void ProjectExplorerPluginPrivate::updateDeployActions() bool ProjectExplorerPlugin::canRunStartupProject(Id runMode, QString *whyNot) { - Project *project = SessionManager::startupProject(); + Project *project = ProjectManager::startupProject(); if (!project) { if (whyNot) *whyNot = Tr::tr("No active project."); @@ -3321,7 +3322,7 @@ void ProjectExplorerPluginPrivate::updateUnloadProjectMenu() ActionContainer *aci = ActionManager::actionContainer(Constants::M_UNLOADPROJECTS); QMenu *menu = aci->menu(); menu->clear(); - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { QAction *action = menu->addAction(Tr::tr("Close Project \"%1\"").arg(project->displayName())); connect(action, &QAction::triggered, [project] { ProjectExplorerPlugin::unloadProject(project); } ); @@ -4117,7 +4118,7 @@ void ProjectExplorerPluginPrivate::updateSessionMenu() void ProjectExplorerPluginPrivate::setSession(QAction *action) { - SessionManager::loadSession(action->data().toString()); + ProjectManager::loadSession(action->data().toString()); } void ProjectExplorerPlugin::setProjectExplorerSettings(const ProjectExplorerSettings &pes) @@ -4375,7 +4376,7 @@ void AllProjectFilesFilter::restoreState(const QJsonObject &object) RunConfigurationLocatorFilter::RunConfigurationLocatorFilter() { - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &RunConfigurationLocatorFilter::targetListUpdated); targetListUpdated(); @@ -4384,7 +4385,7 @@ RunConfigurationLocatorFilter::RunConfigurationLocatorFilter() void RunConfigurationLocatorFilter::prepareSearch(const QString &entry) { m_result.clear(); - const Target *target = SessionManager::startupTarget(); + const Target *target = ProjectManager::startupTarget(); if (!target) return; for (auto rc : target->runConfigurations()) { @@ -4403,12 +4404,12 @@ QList RunConfigurationLocatorFilter::matchesFor( void RunConfigurationLocatorFilter::targetListUpdated() { - setEnabled(SessionManager::startupProject()); // at least one project opened + setEnabled(ProjectManager::startupProject()); // at least one project opened } static RunConfiguration *runConfigurationForDisplayName(const QString &displayName) { - const Project *project = SessionManager::instance()->startupProject(); + const Project *project = ProjectManager::instance()->startupProject(); if (!project) return nullptr; const QList runconfigs = project->activeTarget()->runConfigurations(); @@ -4461,7 +4462,7 @@ void SwitchToRunConfigurationLocatorFilter::accept(const LocatorFilterEntry &sel if (!toSwitchTo) return; - SessionManager::startupTarget()->setActiveRunConfiguration(toSwitchTo); + ProjectManager::startupTarget()->setActiveRunConfiguration(toSwitchTo); QTimer::singleShot(200, this, [displayName = selection.displayName] { if (auto ks = ICore::mainWindow()->findChild("KitSelector.Button")) { Utils::ToolTip::show(ks->mapToGlobal(QPoint{25, 25}), diff --git a/src/plugins/projectexplorer/projectfilewizardextension.cpp b/src/plugins/projectexplorer/projectfilewizardextension.cpp index 53d3eb15781..134db6ea484 100644 --- a/src/plugins/projectexplorer/projectfilewizardextension.cpp +++ b/src/plugins/projectexplorer/projectfilewizardextension.cpp @@ -7,10 +7,10 @@ #include "project.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectnodes.h" #include "projecttree.h" #include "projectwizardpage.h" -#include "session.h" #include @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -134,7 +133,7 @@ Node *ProjectFileWizardExtension::findWizardContextNode(Node *contextNode, Proje const FilePath &path) { if (contextNode && !ProjectTree::hasNode(contextNode)) { - if (SessionManager::projects().contains(project) && project->rootProjectNode()) { + if (ProjectManager::projects().contains(project) && project->rootProjectNode()) { contextNode = project->rootProjectNode()->findNode([path](const Node *n) { return path == n->filePath(); }); diff --git a/src/plugins/projectexplorer/projectmanager.h b/src/plugins/projectexplorer/projectmanager.h index 9d54eba572c..ad3e402992a 100644 --- a/src/plugins/projectexplorer/projectmanager.h +++ b/src/plugins/projectexplorer/projectmanager.h @@ -6,20 +6,35 @@ #include "projectexplorer_export.h" #include +#include + +namespace Core { class IEditor; } #include namespace Utils { class FilePath; +using FilePaths = QList; class MimeType; } // Utils namespace ProjectExplorer { +class BuildSystem; class Project; +class RunConfiguration; +class Target; -class PROJECTEXPLORER_EXPORT ProjectManager +class PROJECTEXPLORER_EXPORT ProjectManager : public QObject { + Q_OBJECT + +public: + ProjectManager(); + ~ProjectManager() override; + + static ProjectManager *instance(); + public: static bool canOpenProjectForMimeType(const Utils::MimeType &mt); static Project *openProject(const Utils::MimeType &mt, const Utils::FilePath &fileName); @@ -32,7 +47,64 @@ public: }); } + static bool save(); + static void closeAllProjects(); + + static void addProject(Project *project); + static void removeProject(Project *project); + static void removeProjects(const QList &remove); + + static void setStartupProject(Project *startupProject); + + static QList dependencies(const Project *project); + static bool hasDependency(const Project *project, const Project *depProject); + static bool canAddDependency(const Project *project, const Project *depProject); + static bool addDependency(Project *project, Project *depProject); + static void removeDependency(Project *project, Project *depProject); + + static bool isProjectConfigurationCascading(); + static void setProjectConfigurationCascading(bool b); + + static Project *startupProject(); + static Target *startupTarget(); + static BuildSystem *startupBuildSystem(); + static RunConfiguration *startupRunConfiguration(); + + static const QList projects(); + static bool hasProjects(); + static bool hasProject(Project *p); + + // NBS rewrite projectOrder (dependency management) + static QList projectOrder(const Project *project = nullptr); + + static Project *projectForFile(const Utils::FilePath &fileName); + static Project *projectWithProjectFilePath(const Utils::FilePath &filePath); + + static Utils::FilePaths projectsForSessionName(const QString &session); + + static void reportProjectLoadingProgress(); + + static bool loadSession(const QString &session, bool initial = false); + +signals: + void targetAdded(ProjectExplorer::Target *target); + void targetRemoved(ProjectExplorer::Target *target); + void projectAdded(ProjectExplorer::Project *project); + void aboutToRemoveProject(ProjectExplorer::Project *project); + void projectDisplayNameChanged(ProjectExplorer::Project *project); + void projectRemoved(ProjectExplorer::Project *project); + + void startupProjectChanged(ProjectExplorer::Project *project); + + void dependencyChanged(ProjectExplorer::Project *a, ProjectExplorer::Project *b); + + // for tests only + void projectFinishedParsing(ProjectExplorer::Project *project); + private: + static void configureEditor(Core::IEditor *editor, const QString &fileName); + static void configureEditors(Project *project); + static void registerProjectCreator(const QString &mimeType, const std::function &); }; diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 0a761f91e62..d318de8cc34 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -8,6 +8,7 @@ #include "projectnodes.h" #include "projectexplorer.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projecttree.h" #include "session.h" #include "target.h" @@ -174,14 +175,15 @@ FlatModel::FlatModel(QObject *parent) ProjectTree *tree = ProjectTree::instance(); connect(tree, &ProjectTree::subtreeChanged, this, &FlatModel::updateSubtree); - SessionManager *sm = SessionManager::instance(); - connect(sm, &SessionManager::projectRemoved, this, &FlatModel::handleProjectRemoved); - connect(sm, &SessionManager::aboutToLoadSession, this, &FlatModel::loadExpandData); - connect(sm, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData); - connect(sm, &SessionManager::projectAdded, this, &FlatModel::handleProjectAdded); - connect(sm, &SessionManager::startupProjectChanged, this, [this] { emit layoutChanged(); }); + ProjectManager *sm = ProjectManager::instance(); + SessionManager *sb = SessionManager::instance(); + connect(sm, &ProjectManager::projectRemoved, this, &FlatModel::handleProjectRemoved); + connect(sb, &SessionManager::aboutToLoadSession, this, &FlatModel::loadExpandData); + connect(sb, &SessionManager::aboutToSaveSession, this, &FlatModel::saveExpandData); + connect(sm, &ProjectManager::projectAdded, this, &FlatModel::handleProjectAdded); + connect(sm, &ProjectManager::startupProjectChanged, this, [this] { emit layoutChanged(); }); - for (Project *project : SessionManager::projects()) + for (Project *project : ProjectManager::projects()) handleProjectAdded(project); } @@ -234,7 +236,7 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const } case Qt::FontRole: { QFont font; - if (project == SessionManager::startupProject()) + if (project == ProjectManager::startupProject()) font.setBold(true); return font; } @@ -407,7 +409,7 @@ void FlatModel::updateSubtree(FolderNode *node) void FlatModel::rebuildModel() { - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); for (Project *project : projects) addOrRebuildProjectModel(project); } diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp index 18b03d3ae0e..5f81f473fe4 100644 --- a/src/plugins/projectexplorer/projecttree.cpp +++ b/src/plugins/projectexplorer/projecttree.cpp @@ -6,9 +6,9 @@ #include "project.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectnodes.h" #include "projecttreewidget.h" -#include "session.h" #include "target.h" #include @@ -53,11 +53,11 @@ ProjectTree::ProjectTree(QObject *parent) : QObject(parent) connect(qApp, &QApplication::focusChanged, this, &ProjectTree::update); - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, &ProjectTree::sessionAndTreeChanged); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, &ProjectTree::sessionAndTreeChanged); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &ProjectTree::sessionChanged); connect(this, &ProjectTree::subtreeChanged, this, &ProjectTree::treeChanged); } @@ -170,7 +170,7 @@ void ProjectTree::updateFromNode(Node *node) if (node) project = projectForNode(node); else - project = SessionManager::startupProject(); + project = ProjectManager::startupProject(); setCurrent(node, project); for (ProjectTreeWidget *widget : std::as_const(m_projectTreeWidgets)) @@ -224,7 +224,7 @@ void ProjectTree::sessionChanged() { if (m_currentProject) { Core::DocumentManager::setDefaultLocationForNewFiles(m_currentProject->projectDirectory()); - } else if (Project *project = SessionManager::startupProject()) { + } else if (Project *project = ProjectManager::startupProject()) { Core::DocumentManager::setDefaultLocationForNewFiles(project->projectDirectory()); updateFromNode(nullptr); // Make startup project current if there is no other current } else { @@ -300,7 +300,7 @@ void ProjectTree::updateFileWarning(Core::IDocument *document, const QString &te if (!infoBar->canInfoBeAdded(infoId)) return; const FilePath filePath = document->filePath(); - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); if (projects.isEmpty()) return; for (Project *project : projects) { @@ -394,7 +394,7 @@ void ProjectTree::applyTreeManager(FolderNode *folder, ConstructionPhase phase) bool ProjectTree::hasNode(const Node *node) { - return Utils::contains(SessionManager::projects(), [node](const Project *p) { + return Utils::contains(ProjectManager::projects(), [node](const Project *p) { if (!p) return false; if (p->containerNode() == node) @@ -409,7 +409,7 @@ bool ProjectTree::hasNode(const Node *node) void ProjectTree::forEachNode(const std::function &task) { - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); for (Project *project : projects) { if (ProjectNode *projectNode = project->rootProjectNode()) { task(projectNode); @@ -430,7 +430,7 @@ Project *ProjectTree::projectForNode(const Node *node) while (folder && folder->parentFolderNode()) folder = folder->parentFolderNode(); - return Utils::findOrDefault(SessionManager::projects(), [folder](const Project *pro) { + return Utils::findOrDefault(ProjectManager::projects(), [folder](const Project *pro) { return pro->containerNode() == folder; }); } @@ -438,7 +438,7 @@ Project *ProjectTree::projectForNode(const Node *node) Node *ProjectTree::nodeForFile(const FilePath &fileName) { Node *node = nullptr; - for (const Project *project : SessionManager::projects()) { + for (const Project *project : ProjectManager::projects()) { project->nodeForFilePath(fileName, [&](const Node *n) { if (!node || (!node->asFileNode() && n->asFileNode())) node = const_cast(n); diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index 65f38626fef..28c06e9254d 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -6,10 +6,10 @@ #include "project.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectmodels.h" #include "projectnodes.h" #include "projecttree.h" -#include "session.h" #include #include @@ -343,7 +343,7 @@ Node *ProjectTreeWidget::nodeForFile(const FilePath &fileName) int bestNodeExpandCount = INT_MAX; // FIXME: Looks like this could be done with less cycles. - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { if (ProjectNode *projectNode = project->rootProjectNode()) { projectNode->forEachGenericNode([&](Node *node) { if (node->filePath() == fileName) { diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 156212a5041..5b392ea7a15 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -7,6 +7,7 @@ #include "sessionmodel.h" #include "projectexplorer.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include #include @@ -324,7 +325,7 @@ public: if (expanded) { painter->setPen(textColor); painter->setFont(sizedFont(12, option.widget)); - const FilePaths projects = SessionManager::projectsForSessionName(sessionName); + const FilePaths projects = ProjectManager::projectsForSessionName(sessionName); int yy = firstBase + SESSION_LINE_HEIGHT - 3; QFontMetrics fm(option.widget->font()); for (const FilePath &projectPath : projects) { @@ -378,7 +379,7 @@ public: int h = SESSION_LINE_HEIGHT; QString sessionName = idx.data(Qt::DisplayRole).toString(); if (m_expandedSessions.contains(sessionName)) { - const FilePaths projects = SessionManager::projectsForSessionName(sessionName); + const FilePaths projects = ProjectManager::projectsForSessionName(sessionName); h += projects.size() * 40 + LINK_HEIGHT - 6; } return QSize(380, h + ItemGap); diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index afe2b45e7e7..e91dbf94feb 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -12,9 +12,9 @@ #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "projectimporter.h" +#include "projectmanager.h" #include "projectpanelfactory.h" #include "projectsettingswidget.h" -#include "session.h" #include "target.h" #include "targetsettingspanel.h" @@ -351,7 +351,7 @@ public: case Qt::FontRole: { QFont font; - font.setBold(m_project == SessionManager::startupProject()); + font.setBold(m_project == ProjectManager::startupProject()); return font; } @@ -391,7 +391,7 @@ public: if (role == ItemActivatedDirectlyRole) { // Someone selected the project using the combobox or similar. - SessionManager::setStartupProject(m_project); + ProjectManager::setStartupProject(m_project); m_currentChildIndex = 0; // Use some Target page by defaults m_targetsItem->setData(column, dat, ItemActivatedFromAboveRole); // And propagate downwards. announceChange(); @@ -545,18 +545,18 @@ public: m_projectSelection->showPopup(); }); - SessionManager *sessionManager = SessionManager::instance(); - connect(sessionManager, &SessionManager::projectAdded, + ProjectManager *sessionManager = ProjectManager::instance(); + connect(sessionManager, &ProjectManager::projectAdded, this, &ProjectWindowPrivate::registerProject); - connect(sessionManager, &SessionManager::aboutToRemoveProject, + connect(sessionManager, &ProjectManager::aboutToRemoveProject, this, &ProjectWindowPrivate::deregisterProject); - connect(sessionManager, &SessionManager::startupProjectChanged, + connect(sessionManager, &ProjectManager::startupProjectChanged, this, &ProjectWindowPrivate::startupProjectChanged); m_importBuild = new QPushButton(Tr::tr("Import Existing Build...")); connect(m_importBuild, &QPushButton::clicked, this, &ProjectWindowPrivate::handleImportBuild); - connect(sessionManager, &SessionManager::startupProjectChanged, this, [this](Project *project) { + connect(sessionManager, &ProjectManager::startupProjectChanged, this, [this](Project *project) { m_importBuild->setEnabled(project && project->projectImporter()); }); @@ -671,7 +671,7 @@ public: void projectSelected(int index) { Project *project = m_comboBoxModel.rootItem()->childAt(index)->m_projectItem->project(); - SessionManager::setStartupProject(project); + ProjectManager::setStartupProject(project); } ComboBoxItem *itemForProject(Project *project) const @@ -774,8 +774,8 @@ public: } } if (lastTarget && lastBc) { - SessionManager::setActiveBuildConfiguration(lastTarget, lastBc, SetActive::Cascade); - SessionManager::setActiveTarget(project, lastTarget, SetActive::Cascade); + lastTarget->setActiveBuildConfiguration(lastBc, SetActive::Cascade); + project->setActiveTarget(lastTarget, SetActive::Cascade); } } diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp index 34dc0b9aaa5..a648eb0981f 100644 --- a/src/plugins/projectexplorer/projectwizardpage.cpp +++ b/src/plugins/projectexplorer/projectwizardpage.cpp @@ -5,8 +5,8 @@ #include "project.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectmodels.h" -#include "session.h" #include #include @@ -463,7 +463,7 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const FilePaths &pa TreeItem *root = m_model.rootItem(); root->removeChildren(); - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { if (ProjectNode *pn = project->rootProjectNode()) { if (kind == IWizardFactory::ProjectWizard) { if (AddNewTree *child = buildAddProjectTree(pn, paths.first(), context, &selector)) diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index b5f3f8e703e..cdb6d708c4d 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -12,10 +12,10 @@ #include "projectexplorer.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectnodes.h" #include "runconfigurationaspects.h" #include "runcontrol.h" -#include "session.h" #include "target.h" #include @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -313,7 +312,7 @@ void RunConfiguration::update() const bool isActive = target()->isActive() && target()->activeRunConfiguration() == this; - if (isActive && project() == SessionManager::startupProject()) + if (isActive && project() == ProjectManager::startupProject()) ProjectExplorerPlugin::updateRunActions(); } diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.cpp b/src/plugins/projectexplorer/runsettingspropertiespage.cpp index bd8b30f2b7a..c1a3a75e3c2 100644 --- a/src/plugins/projectexplorer/runsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/runsettingspropertiespage.cpp @@ -291,11 +291,10 @@ void RunSettingsWidget::currentDeployConfigurationChanged(int index) if (m_ignoreChanges.isLocked()) return; if (index == -1) - SessionManager::setActiveDeployConfiguration(m_target, nullptr, SetActive::Cascade); + m_target->setActiveDeployConfiguration(nullptr, SetActive::Cascade); else - SessionManager::setActiveDeployConfiguration(m_target, - qobject_cast(m_target->deployConfigurationModel()->projectConfigurationAt(index)), - SetActive::Cascade); + m_target->setActiveDeployConfiguration(qobject_cast(m_target->deployConfigurationModel()->projectConfigurationAt(index)), + SetActive::Cascade); } void RunSettingsWidget::aboutToShowDeployMenu() @@ -309,7 +308,7 @@ void RunSettingsWidget::aboutToShowDeployMenu() if (!newDc) return; m_target->addDeployConfiguration(newDc); - SessionManager::setActiveDeployConfiguration(m_target, newDc, SetActive::Cascade); + m_target->setActiveDeployConfiguration(newDc, SetActive::Cascade); m_removeDeployToolButton->setEnabled(m_target->deployConfigurations().size() > 1); }); } diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 6dcfd9a4619..3efbb76f9b9 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -11,6 +11,7 @@ #include "projectexplorer.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectnodes.h" #include "target.h" @@ -65,12 +66,37 @@ class SessionManagerPrivate { public: void restoreValues(const PersistentSettingsReader &reader); + void restoreEditors(const PersistentSettingsReader &reader); + void sessionLoadingProgress(); + + bool recursiveDependencyCheck(const FilePath &newDep, const FilePath &checkDep) const; + FilePaths dependencies(const FilePath &proName) const; + FilePaths dependenciesOrder() const; + void dependencies(const FilePath &proName, FilePaths &result) const; + + static QString windowTitleAddition(const FilePath &filePath); + static QString sessionTitle(const FilePath &filePath); + + QString m_sessionName = QLatin1String(DEFAULT_SESSION); + bool m_virginSession = true; + bool m_loadingSession = false; + + mutable QStringList m_sessions; + mutable QHash m_sessionDateTimes; + QHash m_lastActiveTimes; + + QMap m_values; + QFutureInterface m_future; + PersistentSettingsWriter *m_writer = nullptr; +}; + +class ProjectManagerPrivate +{ +public: void restoreDependencies(const PersistentSettingsReader &reader); void restoreStartupProject(const PersistentSettingsReader &reader); - void restoreEditors(const PersistentSettingsReader &reader); void restoreProjects(const FilePaths &fileList); void askUserAboutFailedProjects(); - void sessionLoadingProgress(); bool recursiveDependencyCheck(const FilePath &newDep, const FilePath &checkDep) const; FilePaths dependencies(const FilePath &proName) const; @@ -82,29 +108,22 @@ public: bool hasProjects() const { return !m_projects.isEmpty(); } - QString m_sessionName = QLatin1String(DEFAULT_SESSION); - bool m_virginSession = true; - bool m_loadingSession = false; bool m_casadeSetActive = false; - mutable QStringList m_sessions; - mutable QHash m_sessionDateTimes; - QHash m_lastActiveTimes; - Project *m_startupProject = nullptr; QList m_projects; FilePaths m_failedProjects; QMap m_depMap; - QMap m_values; - QFutureInterface m_future; - PersistentSettingsWriter *m_writer = nullptr; private: static QString locationInProject(const FilePath &filePath); }; -static SessionManager *m_instance = nullptr; -static SessionManagerPrivate *d = nullptr; +static ProjectManager *m_instance = nullptr; +static ProjectManagerPrivate *d = nullptr; + +static SessionManager *sb_instance = nullptr; +static SessionManagerPrivate *sb_d = nullptr; static QString projectFolderId(Project *pro) { @@ -113,56 +132,74 @@ static QString projectFolderId(Project *pro) const int PROJECT_SORT_VALUE = 100; -SessionManager::SessionManager(QObject *parent) : QObject(parent) +SessionManager::SessionManager() { - m_instance = this; - d = new SessionManagerPrivate; + sb_instance = this; + sb_d = new SessionManagerPrivate; connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, &SessionManager::saveActiveMode); connect(ICore::instance(), &ICore::saveSettingsRequested, this, [] { QVariantMap times; - for (auto it = d->m_lastActiveTimes.cbegin(); it != d->m_lastActiveTimes.cend(); ++it) + for (auto it = sb_d->m_lastActiveTimes.cbegin(); it != sb_d->m_lastActiveTimes.cend(); ++it) times.insert(it.key(), it.value()); ICore::settings()->setValue(LAST_ACTIVE_TIMES_KEY, times); }); - connect(EditorManager::instance(), &EditorManager::editorCreated, - this, &SessionManager::configureEditor); - connect(this, &SessionManager::projectAdded, - EditorManager::instance(), &EditorManager::updateWindowTitles); - connect(this, &SessionManager::projectRemoved, - EditorManager::instance(), &EditorManager::updateWindowTitles); - connect(this, &SessionManager::projectDisplayNameChanged, - EditorManager::instance(), &EditorManager::updateWindowTitles); connect(EditorManager::instance(), &EditorManager::editorOpened, this, &SessionManager::markSessionFileDirty); connect(EditorManager::instance(), &EditorManager::editorsClosed, this, &SessionManager::markSessionFileDirty); - - EditorManager::setWindowTitleAdditionHandler(&SessionManagerPrivate::windowTitleAddition); - EditorManager::setSessionTitleHandler(&SessionManagerPrivate::sessionTitle); } SessionManager::~SessionManager() +{ + emit sb_instance->aboutToUnloadSession(sb_d->m_sessionName); + delete sb_d->m_writer; + delete sb_d; + sb_d = nullptr; +} + +ProjectManager::ProjectManager() +{ + m_instance = this; + d = new ProjectManagerPrivate; + + connect(EditorManager::instance(), &EditorManager::editorCreated, + this, &ProjectManager::configureEditor); + connect(this, &ProjectManager::projectAdded, + EditorManager::instance(), &EditorManager::updateWindowTitles); + connect(this, &ProjectManager::projectRemoved, + EditorManager::instance(), &EditorManager::updateWindowTitles); + connect(this, &ProjectManager::projectDisplayNameChanged, + EditorManager::instance(), &EditorManager::updateWindowTitles); + + EditorManager::setWindowTitleAdditionHandler(&ProjectManagerPrivate::windowTitleAddition); + EditorManager::setSessionTitleHandler(&ProjectManagerPrivate::sessionTitle); +} + +ProjectManager::~ProjectManager() { EditorManager::setWindowTitleAdditionHandler({}); EditorManager::setSessionTitleHandler({}); - emit m_instance->aboutToUnloadSession(d->m_sessionName); - delete d->m_writer; delete d; d = nullptr; } SessionManager *SessionManager::instance() +{ + return sb_instance; +} + +ProjectManager *ProjectManager::instance() { return m_instance; } bool SessionManager::isDefaultVirgin() { - return isDefaultSession(d->m_sessionName) && d->m_virginSession; + return isDefaultSession(sb_d->m_sessionName) && sb_d->m_virginSession; } bool SessionManager::isDefaultSession(const QString &session) @@ -176,7 +213,7 @@ void SessionManager::saveActiveMode(Id mode) setValue(QLatin1String("ActiveMode"), mode.toString()); } -bool SessionManagerPrivate::recursiveDependencyCheck(const FilePath &newDep, +bool ProjectManagerPrivate::recursiveDependencyCheck(const FilePath &newDep, const FilePath &checkDep) const { if (newDep == checkDep) @@ -198,7 +235,7 @@ bool SessionManagerPrivate::recursiveDependencyCheck(const FilePath &newDep, * filenames when saving. */ -QList SessionManager::dependencies(const Project *project) +QList ProjectManager::dependencies(const Project *project) { const FilePath proName = project->projectFilePath(); const FilePaths proDeps = d->m_depMap.value(proName); @@ -215,7 +252,7 @@ QList SessionManager::dependencies(const Project *project) return projects; } -bool SessionManager::hasDependency(const Project *project, const Project *depProject) +bool ProjectManager::hasDependency(const Project *project, const Project *depProject) { const FilePath proName = project->projectFilePath(); const FilePath depName = depProject->projectFilePath(); @@ -224,7 +261,7 @@ bool SessionManager::hasDependency(const Project *project, const Project *depPro return proDeps.contains(depName); } -bool SessionManager::canAddDependency(const Project *project, const Project *depProject) +bool ProjectManager::canAddDependency(const Project *project, const Project *depProject) { const FilePath newDep = project->projectFilePath(); const FilePath checkDep = depProject->projectFilePath(); @@ -232,7 +269,7 @@ bool SessionManager::canAddDependency(const Project *project, const Project *dep return d->recursiveDependencyCheck(newDep, checkDep); } -bool SessionManager::addDependency(Project *project, Project *depProject) +bool ProjectManager::addDependency(Project *project, Project *depProject) { const FilePath proName = project->projectFilePath(); const FilePath depName = depProject->projectFilePath(); @@ -251,7 +288,7 @@ bool SessionManager::addDependency(Project *project, Project *depProject) return true; } -void SessionManager::removeDependency(Project *project, Project *depProject) +void ProjectManager::removeDependency(Project *project, Project *depProject) { const FilePath proName = project->projectFilePath(); const FilePath depName = depProject->projectFilePath(); @@ -265,109 +302,18 @@ void SessionManager::removeDependency(Project *project, Project *depProject) emit m_instance->dependencyChanged(project, depProject); } -bool SessionManager::isProjectConfigurationCascading() +bool ProjectManager::isProjectConfigurationCascading() { return d->m_casadeSetActive; } -void SessionManager::setProjectConfigurationCascading(bool b) +void ProjectManager::setProjectConfigurationCascading(bool b) { d->m_casadeSetActive = b; - markSessionFileDirty(); + SessionManager::markSessionFileDirty(); } -void SessionManager::setActiveTarget(Project *project, Target *target, SetActive cascade) -{ - QTC_ASSERT(project, return); - - if (project->isShuttingDown()) - return; - - project->setActiveTarget(target); - - if (!target) // never cascade setting no target - return; - - if (cascade != SetActive::Cascade || !d->m_casadeSetActive) - return; - - Utils::Id kitId = target->kit()->id(); - for (Project *otherProject : SessionManager::projects()) { - if (otherProject == project) - continue; - if (Target *otherTarget = Utils::findOrDefault(otherProject->targets(), - [kitId](Target *t) { return t->kit()->id() == kitId; })) - otherProject->setActiveTarget(otherTarget); - } -} - -void SessionManager::setActiveBuildConfiguration(Target *target, BuildConfiguration *bc, SetActive cascade) -{ - QTC_ASSERT(target, return); - QTC_ASSERT(target->project(), return); - - if (target->project()->isShuttingDown() || target->isShuttingDown()) - return; - - target->setActiveBuildConfiguration(bc); - - if (!bc) - return; - if (cascade != SetActive::Cascade || !d->m_casadeSetActive) - return; - - Utils::Id kitId = target->kit()->id(); - QString name = bc->displayName(); // We match on displayname - for (Project *otherProject : SessionManager::projects()) { - if (otherProject == target->project()) - continue; - Target *otherTarget = otherProject->activeTarget(); - if (!otherTarget || otherTarget->kit()->id() != kitId) - continue; - - for (BuildConfiguration *otherBc : otherTarget->buildConfigurations()) { - if (otherBc->displayName() == name) { - otherTarget->setActiveBuildConfiguration(otherBc); - break; - } - } - } -} - -void SessionManager::setActiveDeployConfiguration(Target *target, DeployConfiguration *dc, SetActive cascade) -{ - QTC_ASSERT(target, return); - QTC_ASSERT(target->project(), return); - - if (target->project()->isShuttingDown() || target->isShuttingDown()) - return; - - target->setActiveDeployConfiguration(dc); - - if (!dc) - return; - if (cascade != SetActive::Cascade || !d->m_casadeSetActive) - return; - - Utils::Id kitId = target->kit()->id(); - QString name = dc->displayName(); // We match on displayname - for (Project *otherProject : SessionManager::projects()) { - if (otherProject == target->project()) - continue; - Target *otherTarget = otherProject->activeTarget(); - if (!otherTarget || otherTarget->kit()->id() != kitId) - continue; - - for (DeployConfiguration *otherDc : otherTarget->deployConfigurations()) { - if (otherDc->displayName() == name) { - otherTarget->setActiveDeployConfiguration(otherDc); - break; - } - } - } -} - -void SessionManager::setStartupProject(Project *startupProject) +void ProjectManager::setStartupProject(Project *startupProject) { QTC_ASSERT((!startupProject && d->m_projects.isEmpty()) || (startupProject && d->m_projects.contains(startupProject)), return); @@ -385,17 +331,17 @@ void SessionManager::setStartupProject(Project *startupProject) emit m_instance->startupProjectChanged(startupProject); } -Project *SessionManager::startupProject() +Project *ProjectManager::startupProject() { return d->m_startupProject; } -Target *SessionManager::startupTarget() +Target *ProjectManager::startupTarget() { return d->m_startupProject ? d->m_startupProject->activeTarget() : nullptr; } -BuildSystem *SessionManager::startupBuildSystem() +BuildSystem *ProjectManager::startupBuildSystem() { Target *t = startupTarget(); return t ? t->buildSystem() : nullptr; @@ -407,19 +353,19 @@ BuildSystem *SessionManager::startupBuildSystem() */ -RunConfiguration *SessionManager::startupRunConfiguration() +RunConfiguration *ProjectManager::startupRunConfiguration() { Target *t = startupTarget(); return t ? t->activeRunConfiguration() : nullptr; } -void SessionManager::addProject(Project *pro) +void ProjectManager::addProject(Project *pro) { QTC_ASSERT(pro, return); QTC_CHECK(!pro->displayName().isEmpty()); QTC_CHECK(pro->id().isValid()); - d->m_virginSession = false; + sb_d->m_virginSession = false; QTC_ASSERT(!d->m_projects.contains(pro), return); d->m_projects.append(pro); @@ -451,27 +397,27 @@ void SessionManager::addProject(Project *pro) setStartupProject(pro); } -void SessionManager::removeProject(Project *project) +void ProjectManager::removeProject(Project *project) { - d->m_virginSession = false; + sb_d->m_virginSession = false; QTC_ASSERT(project, return); removeProjects({project}); } bool SessionManager::loadingSession() { - return d->m_loadingSession; + return sb_d->m_loadingSession; } -bool SessionManager::save() +bool ProjectManager::save() { - emit m_instance->aboutToSaveSession(); + emit sb_instance->aboutToSaveSession(); - const FilePath filePath = sessionNameToFileName(d->m_sessionName); + const FilePath filePath = SessionManager::sessionNameToFileName(sb_d->m_sessionName); QVariantMap data; // See the explanation at loadSession() for how we handle the implicit default session. - if (isDefaultVirgin()) { + if (SessionManager::isDefaultVirgin()) { if (filePath.exists()) { PersistentSettingsReader reader; if (!reader.load(filePath)) { @@ -522,25 +468,25 @@ bool SessionManager::save() data.insert(QLatin1String("EditorSettings"), EditorManager::saveState().toBase64()); } - const auto end = d->m_values.constEnd(); + const auto end = sb_d->m_values.constEnd(); QStringList keys; - for (auto it = d->m_values.constBegin(); it != end; ++it) { + for (auto it = sb_d->m_values.constBegin(); it != end; ++it) { data.insert(QLatin1String("value-") + it.key(), it.value()); keys << it.key(); } data.insert(QLatin1String("valueKeys"), keys); - if (!d->m_writer || d->m_writer->fileName() != filePath) { - delete d->m_writer; - d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession"); + if (!sb_d->m_writer || sb_d->m_writer->fileName() != filePath) { + delete sb_d->m_writer; + sb_d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession"); } - const bool result = d->m_writer->save(data, ICore::dialogParent()); + const bool result = sb_d->m_writer->save(data, ICore::dialogParent()); if (result) { - if (!isDefaultVirgin()) - d->m_sessionDateTimes.insert(activeSession(), QDateTime::currentDateTime()); + if (!SessionManager::isDefaultVirgin()) + sb_d->m_sessionDateTimes.insert(SessionManager::activeSession(), QDateTime::currentDateTime()); } else { QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"), - Tr::tr("Could not save session to file %1").arg(d->m_writer->fileName().toUserOutput())); + Tr::tr("Could not save session to file %1").arg(sb_d->m_writer->fileName().toUserOutput())); } return result; @@ -549,34 +495,34 @@ bool SessionManager::save() /*! Closes all projects */ -void SessionManager::closeAllProjects() +void ProjectManager::closeAllProjects() { removeProjects(projects()); } -const QList SessionManager::projects() +const QList ProjectManager::projects() { return d->m_projects; } -bool SessionManager::hasProjects() +bool ProjectManager::hasProjects() { return d->hasProjects(); } -bool SessionManager::hasProject(Project *p) +bool ProjectManager::hasProject(Project *p) { return d->m_projects.contains(p); } -FilePaths SessionManagerPrivate::dependencies(const FilePath &proName) const +FilePaths ProjectManagerPrivate::dependencies(const FilePath &proName) const { FilePaths result; dependencies(proName, result); return result; } -void SessionManagerPrivate::dependencies(const FilePath &proName, FilePaths &result) const +void ProjectManagerPrivate::dependencies(const FilePath &proName, FilePaths &result) const { const FilePaths depends = m_depMap.value(proName); @@ -587,17 +533,17 @@ void SessionManagerPrivate::dependencies(const FilePath &proName, FilePaths &res result.append(proName); } -QString SessionManagerPrivate::sessionTitle(const FilePath &filePath) +QString ProjectManagerPrivate::sessionTitle(const FilePath &filePath) { - if (SessionManager::isDefaultSession(d->m_sessionName)) { + if (SessionManager::isDefaultSession(sb_d->m_sessionName)) { if (filePath.isEmpty()) { // use single project's name if there is only one loaded. - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); if (projects.size() == 1) return projects.first()->displayName(); } } else { - QString sessionName = d->m_sessionName; + QString sessionName = sb_d->m_sessionName; if (sessionName.isEmpty()) sessionName = Tr::tr("Untitled"); return sessionName; @@ -605,8 +551,8 @@ QString SessionManagerPrivate::sessionTitle(const FilePath &filePath) return QString(); } -QString SessionManagerPrivate::locationInProject(const FilePath &filePath) { - const Project *project = SessionManager::projectForFile(filePath); +QString ProjectManagerPrivate::locationInProject(const FilePath &filePath) { + const Project *project = ProjectManager::projectForFile(filePath); if (!project) return QString(); @@ -625,12 +571,12 @@ QString SessionManagerPrivate::locationInProject(const FilePath &filePath) { return "(" + parentDir.toUserOutput() + " @ " + project->displayName() + ")"; } -QString SessionManagerPrivate::windowTitleAddition(const FilePath &filePath) +QString ProjectManagerPrivate::windowTitleAddition(const FilePath &filePath) { return filePath.isEmpty() ? QString() : locationInProject(filePath); } -FilePaths SessionManagerPrivate::dependenciesOrder() const +FilePaths ProjectManagerPrivate::dependenciesOrder() const { QList> unordered; FilePaths ordered; @@ -669,7 +615,7 @@ FilePaths SessionManagerPrivate::dependenciesOrder() const return ordered; } -QList SessionManager::projectOrder(const Project *project) +QList ProjectManager::projectOrder(const Project *project) { QList result; @@ -691,13 +637,13 @@ QList SessionManager::projectOrder(const Project *project) return result; } -Project *SessionManager::projectForFile(const FilePath &fileName) +Project *ProjectManager::projectForFile(const FilePath &fileName) { - if (Project * const project = Utils::findOrDefault(SessionManager::projects(), + if (Project * const project = Utils::findOrDefault(ProjectManager::projects(), [&fileName](const Project *p) { return p->isKnownFile(fileName); })) { return project; } - return Utils::findOrDefault(SessionManager::projects(), + return Utils::findOrDefault(ProjectManager::projects(), [&fileName](const Project *p) { for (const Target * const target : p->targets()) { for (const BuildConfiguration * const bc : target->buildConfigurations()) { @@ -709,13 +655,13 @@ Project *SessionManager::projectForFile(const FilePath &fileName) }); } -Project *SessionManager::projectWithProjectFilePath(const FilePath &filePath) +Project *ProjectManager::projectWithProjectFilePath(const FilePath &filePath) { - return Utils::findOrDefault(SessionManager::projects(), + return Utils::findOrDefault(ProjectManager::projects(), [&filePath](const Project *p) { return p->projectFilePath() == filePath; }); } -void SessionManager::configureEditor(IEditor *editor, const QString &fileName) +void ProjectManager::configureEditor(IEditor *editor, const QString &fileName) { if (auto textEditor = qobject_cast(editor)) { Project *project = projectForFile(Utils::FilePath::fromString(fileName)); @@ -725,7 +671,7 @@ void SessionManager::configureEditor(IEditor *editor, const QString &fileName) } } -void SessionManager::configureEditors(Project *project) +void ProjectManager::configureEditors(Project *project) { const QList documents = DocumentModel::openedDocuments(); for (IDocument *document : documents) { @@ -740,7 +686,7 @@ void SessionManager::configureEditors(Project *project) } } -void SessionManager::removeProjects(const QList &remove) +void ProjectManager::removeProjects(const QList &remove) { for (Project *pro : remove) emit m_instance->aboutToRemoveProject(pro); @@ -775,52 +721,52 @@ void SessionManager::removeProjects(const QList &remove) void SessionManager::setValue(const QString &name, const QVariant &value) { - if (d->m_values.value(name) == value) + if (sb_d->m_values.value(name) == value) return; - d->m_values.insert(name, value); + sb_d->m_values.insert(name, value); } QVariant SessionManager::value(const QString &name) { - auto it = d->m_values.constFind(name); - return (it == d->m_values.constEnd()) ? QVariant() : *it; + auto it = sb_d->m_values.constFind(name); + return (it == sb_d->m_values.constEnd()) ? QVariant() : *it; } QString SessionManager::activeSession() { - return d->m_sessionName; + return sb_d->m_sessionName; } QStringList SessionManager::sessions() { - if (d->m_sessions.isEmpty()) { + if (sb_d->m_sessions.isEmpty()) { // We are not initialized yet, so do that now const FilePaths sessionFiles = ICore::userResourcePath().dirEntries({{"*qws"}}, QDir::Time | QDir::Reversed); const QVariantMap lastActiveTimes = ICore::settings()->value(LAST_ACTIVE_TIMES_KEY).toMap(); for (const FilePath &file : sessionFiles) { const QString &name = file.completeBaseName(); - d->m_sessionDateTimes.insert(name, file.lastModified()); + sb_d->m_sessionDateTimes.insert(name, file.lastModified()); const auto lastActiveTime = lastActiveTimes.find(name); - d->m_lastActiveTimes.insert(name, lastActiveTime != lastActiveTimes.end() + sb_d->m_lastActiveTimes.insert(name, lastActiveTime != lastActiveTimes.end() ? lastActiveTime->toDateTime() : file.lastModified()); if (name != QLatin1String(DEFAULT_SESSION)) - d->m_sessions << name; + sb_d->m_sessions << name; } - d->m_sessions.prepend(QLatin1String(DEFAULT_SESSION)); + sb_d->m_sessions.prepend(QLatin1String(DEFAULT_SESSION)); } - return d->m_sessions; + return sb_d->m_sessions; } QDateTime SessionManager::sessionDateTime(const QString &session) { - return d->m_sessionDateTimes.value(session); + return sb_d->m_sessionDateTimes.value(session); } QDateTime SessionManager::lastActiveTime(const QString &session) { - return d->m_lastActiveTimes.value(session); + return sb_d->m_lastActiveTimes.value(session); } FilePath SessionManager::sessionNameToFileName(const QString &session) @@ -836,9 +782,9 @@ bool SessionManager::createSession(const QString &session) { if (sessions().contains(session)) return false; - Q_ASSERT(d->m_sessions.size() > 0); - d->m_sessions.insert(1, session); - d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); + Q_ASSERT(sb_d->m_sessions.size() > 0); + sb_d->m_sessions.insert(1, session); + sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); return true; } @@ -847,7 +793,7 @@ bool SessionManager::renameSession(const QString &original, const QString &newNa if (!cloneSession(original, newName)) return false; if (original == activeSession()) - loadSession(newName); + ProjectManager::loadSession(newName); emit instance()->sessionRenamed(original, newName); return deleteSession(original); } @@ -873,10 +819,10 @@ bool SessionManager::confirmSessionDelete(const QStringList &sessions) */ bool SessionManager::deleteSession(const QString &session) { - if (!d->m_sessions.contains(session)) + if (!sb_d->m_sessions.contains(session)) return false; - d->m_sessions.removeOne(session); - d->m_lastActiveTimes.remove(session); + sb_d->m_sessions.removeOne(session); + sb_d->m_lastActiveTimes.remove(session); emit instance()->sessionRemoved(session); FilePath sessionFile = sessionNameToFileName(session); if (sessionFile.exists()) @@ -892,14 +838,14 @@ void SessionManager::deleteSessions(const QStringList &sessions) bool SessionManager::cloneSession(const QString &original, const QString &clone) { - if (!d->m_sessions.contains(original)) + if (!sb_d->m_sessions.contains(original)) return false; FilePath sessionFile = sessionNameToFileName(original); // If the file does not exist, we can still clone if (!sessionFile.exists() || sessionFile.copyFile(sessionNameToFileName(clone))) { - d->m_sessions.insert(1, clone); - d->m_sessionDateTimes.insert(clone, sessionNameToFileName(clone).lastModified()); + sb_d->m_sessions.insert(1, clone); + sb_d->m_sessionDateTimes.insert(clone, sessionNameToFileName(clone).lastModified()); return true; } return false; @@ -914,7 +860,7 @@ void SessionManagerPrivate::restoreValues(const PersistentSettingsReader &reader } } -void SessionManagerPrivate::restoreDependencies(const PersistentSettingsReader &reader) +void ProjectManagerPrivate::restoreDependencies(const PersistentSettingsReader &reader) { QMap depMap = reader.restoreValue(QLatin1String("ProjectDependencies")).toMap(); auto i = depMap.constBegin(); @@ -929,7 +875,7 @@ void SessionManagerPrivate::restoreDependencies(const PersistentSettingsReader & } } -void SessionManagerPrivate::askUserAboutFailedProjects() +void ProjectManagerPrivate::askUserAboutFailedProjects() { FilePaths failedProjects = m_failedProjects; if (!failedProjects.isEmpty()) { @@ -950,7 +896,7 @@ void SessionManagerPrivate::askUserAboutFailedProjects() } } -void SessionManagerPrivate::restoreStartupProject(const PersistentSettingsReader &reader) +void ProjectManagerPrivate::restoreStartupProject(const PersistentSettingsReader &reader) { const FilePath startupProject = FilePath::fromSettings(reader.restoreValue("StartupProject")); if (!startupProject.isEmpty()) { @@ -981,7 +927,7 @@ void SessionManagerPrivate::restoreEditors(const PersistentSettingsReader &reade /*! Loads a session, takes a session name (not filename). */ -void SessionManagerPrivate::restoreProjects(const FilePaths &fileList) +void ProjectManagerPrivate::restoreProjects(const FilePaths &fileList) { // indirectly adds projects to session // Keep projects that failed to load in the session! @@ -1021,24 +967,24 @@ void SessionManagerPrivate::restoreProjects(const FilePaths &fileList) * either the implicit or the explicit default session. * */ -bool SessionManager::loadSession(const QString &session, bool initial) +bool ProjectManager::loadSession(const QString &session, bool initial) { const bool loadImplicitDefault = session.isEmpty(); const bool switchFromImplicitToExplicitDefault = session == DEFAULT_SESSION - && d->m_sessionName == DEFAULT_SESSION && !initial; + && sb_d->m_sessionName == DEFAULT_SESSION && !initial; // Do nothing if we have that session already loaded, // exception if the session is the default virgin session // we still want to be able to load the default session - if (session == d->m_sessionName && !isDefaultVirgin()) + if (session == sb_d->m_sessionName && !SessionManager::isDefaultVirgin()) return true; - if (!loadImplicitDefault && !sessions().contains(session)) + if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) return false; FilePaths fileList; // Try loading the file - FilePath fileName = sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION : session); + FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION : session); PersistentSettingsReader reader; if (fileName.exists()) { if (!reader.load(fileName)) { @@ -1049,8 +995,8 @@ bool SessionManager::loadSession(const QString &session, bool initial) } if (loadImplicitDefault) { - d->restoreValues(reader); - emit m_instance->sessionLoaded(DEFAULT_SESSION); + sb_d->restoreValues(reader); + emit sb_instance->sessionLoaded(DEFAULT_SESSION); return true; } @@ -1059,19 +1005,19 @@ bool SessionManager::loadSession(const QString &session, bool initial) return true; } - d->m_loadingSession = true; + sb_d->m_loadingSession = true; // Allow everyone to set something in the session and before saving - emit m_instance->aboutToUnloadSession(d->m_sessionName); + emit sb_instance->aboutToUnloadSession(sb_d->m_sessionName); if (!save()) { - d->m_loadingSession = false; + sb_d->m_loadingSession = false; return false; } // Clean up if (!EditorManager::closeAllEditors()) { - d->m_loadingSession = false; + sb_d->m_loadingSession = false; return false; } @@ -1088,29 +1034,29 @@ bool SessionManager::loadSession(const QString &session, bool initial) d->m_failedProjects.clear(); d->m_depMap.clear(); if (!switchFromImplicitToExplicitDefault) - d->m_values.clear(); + sb_d->m_values.clear(); d->m_casadeSetActive = false; - d->m_sessionName = session; - delete d->m_writer; - d->m_writer = nullptr; + sb_d->m_sessionName = session; + delete sb_d->m_writer; + sb_d->m_writer = nullptr; EditorManager::updateWindowTitles(); if (fileName.exists()) { - d->m_virginSession = false; + sb_d->m_virginSession = false; - ProgressManager::addTask(d->m_future.future(), Tr::tr("Loading Session"), + ProgressManager::addTask(sb_d->m_future.future(), Tr::tr("Loading Session"), "ProjectExplorer.SessionFile.Load"); - d->m_future.setProgressRange(0, 1); - d->m_future.setProgressValue(0); + sb_d->m_future.setProgressRange(0, 1); + sb_d->m_future.setProgressValue(0); if (!switchFromImplicitToExplicitDefault) - d->restoreValues(reader); - emit m_instance->aboutToLoadSession(session); + sb_d->restoreValues(reader); + emit sb_instance->aboutToLoadSession(session); // retrieve all values before the following code could change them again - Id modeId = Id::fromSetting(value(QLatin1String("ActiveMode"))); + Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); if (!modeId.isValid()) modeId = Id(Core::Constants::MODE_EDIT); @@ -1118,21 +1064,21 @@ bool SessionManager::loadSession(const QString &session, bool initial) if (c.isValid()) StyleHelper::setBaseColor(c); - d->m_future.setProgressRange(0, projectPathsToLoad.count() + 1/*initialization above*/ + 1/*editors*/); - d->m_future.setProgressValue(1); + sb_d->m_future.setProgressRange(0, projectPathsToLoad.count() + 1/*initialization above*/ + 1/*editors*/); + sb_d->m_future.setProgressValue(1); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); d->restoreProjects(projectPathsToLoad); - d->sessionLoadingProgress(); + sb_d->sessionLoadingProgress(); d->restoreDependencies(reader); d->restoreStartupProject(reader); removeProjects(projectsToRemove); // only remove old projects now that the startup project is set! - d->restoreEditors(reader); + sb_d->restoreEditors(reader); - d->m_future.reportFinished(); - d->m_future = QFutureInterface(); + sb_d->m_future.reportFinished(); + sb_d->m_future = QFutureInterface(); // Fall back to Project mode if the startup project is unconfigured and // use the mode saved in the session otherwise @@ -1148,13 +1094,13 @@ bool SessionManager::loadSession(const QString &session, bool initial) } d->m_casadeSetActive = reader.restoreValue(QLatin1String("CascadeSetActive"), false).toBool(); - d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); + sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); - emit m_instance->sessionLoaded(session); + emit sb_instance->sessionLoaded(session); // Starts a event loop, better do that at the very end d->askUserAboutFailedProjects(); - d->m_loadingSession = false; + sb_d->m_loadingSession = false; return true; } @@ -1174,14 +1120,14 @@ QString SessionManager::startupSession() return ICore::settings()->value(Constants::STARTUPSESSION_KEY).toString(); } -void SessionManager::reportProjectLoadingProgress() +void ProjectManager::reportProjectLoadingProgress() { - d->sessionLoadingProgress(); + sb_d->sessionLoadingProgress(); } void SessionManager::markSessionFileDirty() { - d->m_virginSession = false; + sb_d->m_virginSession = false; } void SessionManagerPrivate::sessionLoadingProgress() @@ -1190,9 +1136,9 @@ void SessionManagerPrivate::sessionLoadingProgress() QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } -FilePaths SessionManager::projectsForSessionName(const QString &session) +FilePaths ProjectManager::projectsForSessionName(const QString &session) { - const FilePath fileName = sessionNameToFileName(session); + const FilePath fileName = SessionManager::sessionNameToFileName(session); PersistentSettingsReader reader; if (fileName.exists()) { if (!reader.load(fileName)) { @@ -1230,7 +1176,7 @@ void ProjectExplorerPlugin::testSessionSwitch() QVERIFY(sessionSpec.projectFile.open()); sessionSpec.projectFile.write(proFileContents); sessionSpec.projectFile.close(); - QVERIFY(SessionManager::loadSession(sessionSpec.name)); + QVERIFY(ProjectManager::loadSession(sessionSpec.name)); const OpenProjectResult openResult = ProjectExplorerPlugin::openProject( FilePath::fromString(sessionSpec.projectFile.fileName())); @@ -1239,20 +1185,20 @@ void ProjectExplorerPlugin::testSessionSwitch() QVERIFY(openResult); QCOMPARE(openResult.projects().count(), 1); QVERIFY(openResult.project()); - QCOMPARE(SessionManager::projects().count(), 1); + QCOMPARE(ProjectManager::projects().count(), 1); } for (int i = 0; i < 30; ++i) { - QVERIFY(SessionManager::loadSession("session1")); + QVERIFY(ProjectManager::loadSession("session1")); QCOMPARE(SessionManager::activeSession(), "session1"); - QCOMPARE(SessionManager::projects().count(), 1); - QVERIFY(SessionManager::loadSession("session2")); + QCOMPARE(ProjectManager::projects().count(), 1); + QVERIFY(ProjectManager::loadSession("session2")); QCOMPARE(SessionManager::activeSession(), "session2"); - QCOMPARE(SessionManager::projects().count(), 1); + QCOMPARE(ProjectManager::projects().count(), 1); } - QVERIFY(SessionManager::loadSession("session1")); - SessionManager::closeAllProjects(); - QVERIFY(SessionManager::loadSession("session2")); - SessionManager::closeAllProjects(); + QVERIFY(ProjectManager::loadSession("session1")); + ProjectManager::closeAllProjects(); + QVERIFY(ProjectManager::loadSession("session2")); + ProjectManager::closeAllProjects(); QVERIFY(SessionManager::deleteSession("session1")); QVERIFY(SessionManager::deleteSession("session2")); } diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index a29e478046b..6cab7b68db5 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -5,6 +5,8 @@ #include "projectexplorer_export.h" +#include "projectmanager.h" // FIXME: Remove once dowstream is adjusted. + #include #include @@ -12,25 +14,14 @@ #include #include -namespace Core { class IEditor; } - namespace ProjectExplorer { -class Project; -class Target; -class BuildConfiguration; -class BuildSystem; -class DeployConfiguration; -class RunConfiguration; - -enum class SetActive { Cascade, NoCascade }; - class PROJECTEXPLORER_EXPORT SessionManager : public QObject { Q_OBJECT public: - explicit SessionManager(QObject *parent = nullptr); + SessionManager(); ~SessionManager() override; static SessionManager *instance(); @@ -52,39 +43,7 @@ public: static bool cloneSession(const QString &original, const QString &clone); static bool renameSession(const QString &original, const QString &newName); - static bool loadSession(const QString &session, bool initial = false); - - static bool save(); - static void closeAllProjects(); - - static void addProject(Project *project); - static void removeProject(Project *project); - static void removeProjects(const QList &remove); - - static void setStartupProject(Project *startupProject); - - static QList dependencies(const Project *project); - static bool hasDependency(const Project *project, const Project *depProject); - static bool canAddDependency(const Project *project, const Project *depProject); - static bool addDependency(Project *project, Project *depProject); - static void removeDependency(Project *project, Project *depProject); - - static bool isProjectConfigurationCascading(); - static void setProjectConfigurationCascading(bool b); - - static void setActiveTarget(Project *p, Target *t, SetActive cascade); - static void setActiveBuildConfiguration(Target *t, BuildConfiguration *bc, SetActive cascade); - static void setActiveDeployConfiguration(Target *t, DeployConfiguration *dc, SetActive cascade); - static Utils::FilePath sessionNameToFileName(const QString &session); - static Project *startupProject(); - static Target *startupTarget(); - static BuildSystem *startupBuildSystem(); - static RunConfiguration *startupRunConfiguration(); - - static const QList projects(); - static bool hasProjects(); - static bool hasProject(Project *p); static bool isDefaultVirgin(); static bool isDefaultSession(const QString &session); @@ -93,44 +52,20 @@ public: static void setValue(const QString &name, const QVariant &value); static QVariant value(const QString &name); - // NBS rewrite projectOrder (dependency management) - static QList projectOrder(const Project *project = nullptr); - - static Project *projectForFile(const Utils::FilePath &fileName); - static Project *projectWithProjectFilePath(const Utils::FilePath &filePath); - - static Utils::FilePaths projectsForSessionName(const QString &session); - - static void reportProjectLoadingProgress(); static bool loadingSession(); + static void markSessionFileDirty(); signals: - void targetAdded(ProjectExplorer::Target *target); - void targetRemoved(ProjectExplorer::Target *target); - void projectAdded(ProjectExplorer::Project *project); - void aboutToRemoveProject(ProjectExplorer::Project *project); - void projectDisplayNameChanged(ProjectExplorer::Project *project); - void projectRemoved(ProjectExplorer::Project *project); - - void startupProjectChanged(ProjectExplorer::Project *project); - void aboutToUnloadSession(QString sessionName); void aboutToLoadSession(QString sessionName); void sessionLoaded(QString sessionName); void aboutToSaveSession(); - void dependencyChanged(ProjectExplorer::Project *a, ProjectExplorer::Project *b); void sessionRenamed(const QString &oldName, const QString &newName); void sessionRemoved(const QString &name); - // for tests only - void projectFinishedParsing(ProjectExplorer::Project *project); - private: static void saveActiveMode(Utils::Id mode); - static void configureEditor(Core::IEditor *editor, const QString &fileName); - static void markSessionFileDirty(); - static void configureEditors(Project *project); }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/sessionmodel.cpp b/src/plugins/projectexplorer/sessionmodel.cpp index d8c9aa935e2..6e22c3b091d 100644 --- a/src/plugins/projectexplorer/sessionmodel.cpp +++ b/src/plugins/projectexplorer/sessionmodel.cpp @@ -4,6 +4,7 @@ #include "sessionmodel.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "session.h" #include "sessiondialog.h" @@ -122,10 +123,10 @@ QVariant SessionModel::data(const QModelIndex &index, int role) const result = SessionManager::activeSession() == sessionName; break; case ProjectsPathRole: - result = pathsWithTildeHomePath(SessionManager::projectsForSessionName(sessionName)); + result = pathsWithTildeHomePath(ProjectManager::projectsForSessionName(sessionName)); break; case ProjectsDisplayRole: - result = pathsToBaseNames(SessionManager::projectsForSessionName(sessionName)); + result = pathsToBaseNames(ProjectManager::projectsForSessionName(sessionName)); break; case ShortcutRole: { const Id sessionBase = SESSION_BASE_ID; @@ -240,7 +241,7 @@ void SessionModel::renameSession(QWidget *parent, const QString &session) void SessionModel::switchToSession(const QString &session) { - SessionManager::loadSession(session); + ProjectManager::loadSession(session); emit sessionSwitched(); } diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 8f227512eec..d2e59aab063 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -21,8 +21,8 @@ #include "projectexplorericons.h" #include "projectexplorersettings.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "runconfiguration.h" -#include "session.h" #include @@ -120,10 +120,10 @@ Target::Target(Project *project, Kit *k, _constructor_tag) : }); connect(this, &Target::parsingFinished, this, [this, project](bool success) { - if (success && this == SessionManager::startupTarget()) + if (success && this == ProjectManager::startupTarget()) updateDefaultRunConfigurations(); // For testing. - emit SessionManager::instance()->projectFinishedParsing(project); + emit ProjectManager::instance()->projectFinishedParsing(project); emit project->anyParsingFinished(this, success); }, Qt::QueuedConnection); // Must wait for run configs to change their enabled state. @@ -242,6 +242,70 @@ QString Target::activeBuildKey() const return d->m_activeRunConfiguration->buildKey(); } +void Target::setActiveBuildConfiguration(BuildConfiguration *bc, SetActive cascade) +{ + QTC_ASSERT(project(), return); + + if (project()->isShuttingDown() || isShuttingDown()) + return; + + setActiveBuildConfiguration(bc); + + if (!bc) + return; + if (cascade != SetActive::Cascade || !ProjectManager::isProjectConfigurationCascading()) + return; + + Id kitId = kit()->id(); + QString name = bc->displayName(); // We match on displayname + for (Project *otherProject : ProjectManager::projects()) { + if (otherProject == project()) + continue; + Target *otherTarget = otherProject->activeTarget(); + if (!otherTarget || otherTarget->kit()->id() != kitId) + continue; + + for (BuildConfiguration *otherBc : otherTarget->buildConfigurations()) { + if (otherBc->displayName() == name) { + otherTarget->setActiveBuildConfiguration(otherBc); + break; + } + } + } +} + +void Target::setActiveDeployConfiguration(DeployConfiguration *dc, SetActive cascade) +{ + QTC_ASSERT(project(), return); + + if (project()->isShuttingDown() || isShuttingDown()) + return; + + setActiveDeployConfiguration(dc); + + if (!dc) + return; + if (cascade != SetActive::Cascade || !ProjectManager::isProjectConfigurationCascading()) + return; + + Id kitId = kit()->id(); + QString name = dc->displayName(); // We match on displayname + for (Project *otherProject : ProjectManager::projects()) { + if (otherProject == project()) + continue; + Target *otherTarget = otherProject->activeTarget(); + if (!otherTarget || otherTarget->kit()->id() != kitId) + continue; + + for (DeployConfiguration *otherDc : otherTarget->deployConfigurations()) { + if (otherDc->displayName() == name) { + otherTarget->setActiveDeployConfiguration(otherDc); + break; + } + } + } +} + Utils::Id Target::id() const { return d->m_kit->id(); @@ -307,9 +371,9 @@ bool Target::removeBuildConfiguration(BuildConfiguration *bc) if (activeBuildConfiguration() == bc) { if (d->m_buildConfigurations.isEmpty()) - SessionManager::setActiveBuildConfiguration(this, nullptr, SetActive::Cascade); + setActiveBuildConfiguration(nullptr, SetActive::Cascade); else - SessionManager::setActiveBuildConfiguration(this, d->m_buildConfigurations.at(0), SetActive::Cascade); + setActiveBuildConfiguration(d->m_buildConfigurations.at(0), SetActive::Cascade); } emit removedBuildConfiguration(bc); @@ -377,10 +441,9 @@ bool Target::removeDeployConfiguration(DeployConfiguration *dc) if (activeDeployConfiguration() == dc) { if (d->m_deployConfigurations.isEmpty()) - SessionManager::setActiveDeployConfiguration(this, nullptr, SetActive::Cascade); + setActiveDeployConfiguration(nullptr, SetActive::Cascade); else - SessionManager::setActiveDeployConfiguration(this, d->m_deployConfigurations.at(0), - SetActive::Cascade); + setActiveDeployConfiguration(d->m_deployConfigurations.at(0), SetActive::Cascade); } ProjectExplorerPlugin::targetSelector()->removedDeployConfiguration(dc); diff --git a/src/plugins/projectexplorer/target.h b/src/plugins/projectexplorer/target.h index 78f0b5f3b5b..aeca2fd9e0b 100644 --- a/src/plugins/projectexplorer/target.h +++ b/src/plugins/projectexplorer/target.h @@ -26,11 +26,13 @@ class Project; class ProjectConfigurationModel; class RunConfiguration; +enum class SetActive : int { Cascade, NoCascade }; + class TargetPrivate; class PROJECTEXPLORER_EXPORT Target : public QObject { - friend class SessionManager; // for setActiveBuild and setActiveDeployConfiguration + friend class ProjectManager; // for setActiveBuild and setActiveDeployConfiguration Q_OBJECT public: @@ -109,6 +111,9 @@ public: QString activeBuildKey() const; // Build key of active run configuaration + void setActiveBuildConfiguration(BuildConfiguration *bc, SetActive cascade); + void setActiveDeployConfiguration(DeployConfiguration *dc, SetActive cascade); + signals: void targetEnabled(bool); void iconChanged(); diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index 6d8c81e634c..d2fdc3b43a8 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -12,9 +12,9 @@ #include "project.h" #include "projectexplorericons.h" #include "projectexplorertr.h" +#include "projectmanager.h" #include "projectwindow.h" #include "runsettingspropertiespage.h" -#include "session.h" #include "target.h" #include "targetsetuppage.h" #include "task.h" @@ -281,7 +281,7 @@ public: QFont font = parent()->data(column, role).value(); if (TargetItem *targetItem = parent()->currentTargetItem()) { Target *t = targetItem->target(); - if (t && t->id() == m_kitId && m_project == SessionManager::startupProject()) + if (t && t->id() == m_kitId && m_project == ProjectManager::startupProject()) font.setBold(true); } return font; @@ -334,7 +334,7 @@ public: // Go to Run page, when on Run previously etc. TargetItem *previousItem = parent()->currentTargetItem(); m_currentChild = previousItem ? previousItem->m_currentChild : DefaultPage; - SessionManager::setActiveTarget(m_project, target(), SetActive::Cascade); + m_project->setActiveTarget(target(), SetActive::Cascade); parent()->setData(column, QVariant::fromValue(static_cast(this)), ItemActivatedFromBelowRole); } @@ -346,7 +346,7 @@ public: int child = indexOf(data.value()); QTC_ASSERT(child != -1, return false); m_currentChild = child; // Triggered from sub-item. - SessionManager::setActiveTarget(m_project, target(), SetActive::Cascade); + m_project->setActiveTarget(target(), SetActive::Cascade); // Propagate Build/Run selection up. parent()->setData(column, QVariant::fromValue(static_cast(this)), ItemActivatedFromBelowRole); @@ -355,7 +355,7 @@ public: if (role == ItemActivatedFromAboveRole) { // Usually programmatic activation, e.g. after opening the Project mode. - SessionManager::setActiveTarget(m_project, target(), SetActive::Cascade); + m_project->setActiveTarget(target(), SetActive::Cascade); return true; } return false; @@ -377,7 +377,7 @@ public: = menu->addAction(Tr::tr("Enable Kit for All Projects")); enableForAllAction->setEnabled(isSelectable); QObject::connect(enableForAllAction, &QAction::triggered, [kit] { - for (Project * const p : SessionManager::projects()) { + for (Project * const p : ProjectManager::projects()) { if (!p->target(kit)) p->addTargetForKit(kit); } @@ -411,7 +411,7 @@ public: QAction *disableForAllAction = menu->addAction(Tr::tr("Disable Kit for All Projects")); disableForAllAction->setEnabled(isSelectable); QObject::connect(disableForAllAction, &QAction::triggered, [kit] { - for (Project * const p : SessionManager::projects()) { + for (Project * const p : ProjectManager::projects()) { Target * const t = p->target(kit); if (!t) continue; diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index a17aa58c946..3b11c8f1471 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -658,7 +658,7 @@ bool TargetSetupPage::setupProject(Project *project) if (m_importer) activeTarget = m_importer->preferredTarget(project->targets()); if (activeTarget) - SessionManager::setActiveTarget(project, activeTarget, SetActive::NoCascade); + project->setActiveTarget(activeTarget, SetActive::NoCascade); return true; } diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 848184b462f..c23ae2d8649 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index 6551facef50..f758ae3d9b6 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -152,7 +152,7 @@ void PythonEditorWidget::setUserDefinedPython(const Interpreter &interpreter) QTC_ASSERT(pythonDocument, return); FilePath documentPath = pythonDocument->filePath(); QTC_ASSERT(!documentPath.isEmpty(), return); - if (Project *project = SessionManager::projectForFile(documentPath)) { + if (Project *project = ProjectManager::projectForFile(documentPath)) { if (Target *target = project->activeTarget()) { if (RunConfiguration *rc = target->activeRunConfiguration()) { if (auto interpretersAspect= rc->aspect()) { @@ -184,7 +184,7 @@ void PythonEditorWidget::updateInterpretersSelector() disconnect(connection); m_projectConnections.clear(); const FilePath documentPath = textDocument()->filePath(); - if (Project *project = SessionManager::projectForFile(documentPath)) { + if (Project *project = ProjectManager::projectForFile(documentPath)) { m_projectConnections << connect(project, &Project::activeTargetChanged, this, diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index dde324dbd95..74edb153e12 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 346c42d183d..86356050928 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -31,9 +31,9 @@ static QHash &userDefinedPythonsForDocument() FilePath detectPython(const FilePath &documentPath) { Project *project = documentPath.isEmpty() ? nullptr - : SessionManager::projectForFile(documentPath); + : ProjectManager::projectForFile(documentPath); if (!project) - project = SessionManager::startupProject(); + project = ProjectManager::startupProject(); Environment env = Environment::systemEnvironment(); @@ -107,7 +107,7 @@ void openPythonRepl(QObject *parent, const FilePath &file, ReplType type) { static const auto workingDir = [](const FilePath &file) { if (file.isEmpty()) { - if (Project *project = SessionManager::startupProject()) + if (Project *project = ProjectManager::startupProject()) return project->projectDirectory(); return FilePath::currentWorkingPath(); } @@ -155,7 +155,7 @@ QString pythonName(const FilePath &pythonPath) PythonProject *pythonProjectForFile(const FilePath &pythonFile) { - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { if (auto pythonProject = qobject_cast(project)) { if (pythonProject->isKnownFile(pythonFile)) return pythonProject; diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index 01a58753a20..3245b609bef 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -60,7 +60,7 @@ static Node *currentEditorNode() static QbsProject *currentEditorProject() { Core::IDocument *doc = Core::EditorManager::currentDocument(); - return doc ? qobject_cast(SessionManager::projectForFile(doc->filePath())) : nullptr; + return doc ? qobject_cast(ProjectManager::projectForFile(doc->filePath())) : nullptr; } class QbsProjectManagerPluginPrivate @@ -226,13 +226,13 @@ void QbsProjectManagerPlugin::initialize() connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, this, &QbsProjectManagerPlugin::updateBuildActions); - connect(SessionManager::instance(), &SessionManager::targetAdded, + connect(ProjectManager::instance(), &ProjectManager::targetAdded, this, &QbsProjectManagerPlugin::targetWasAdded); - connect(SessionManager::instance(), &SessionManager::targetRemoved, + connect(ProjectManager::instance(), &ProjectManager::targetRemoved, this, &QbsProjectManagerPlugin::updateBuildActions); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &QbsProjectManagerPlugin::updateReparseQbsAction); - connect(SessionManager::instance(), &SessionManager::projectAdded, + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this](Project *project) { auto qbsProject = qobject_cast(project); connect(project, &Project::anyParsingStarted, @@ -283,7 +283,7 @@ void QbsProjectManagerPlugin::updateContextActions(Node *node) void QbsProjectManagerPlugin::updateReparseQbsAction() { - auto project = qobject_cast(SessionManager::startupProject()); + auto project = qobject_cast(ProjectManager::startupProject()); m_reparseQbs->setEnabled(project && !BuildManager::isBuilding(project) && project && project->activeTarget() @@ -342,7 +342,7 @@ void QbsProjectManagerPlugin::projectChanged(QbsProject *project) { auto qbsProject = qobject_cast(project); - if (!qbsProject || qbsProject == SessionManager::startupProject()) + if (!qbsProject || qbsProject == ProjectManager::startupProject()) updateReparseQbsAction(); if (!qbsProject || qbsProject == ProjectTree::currentProject()) @@ -537,7 +537,7 @@ void QbsProjectManagerPlugin::reparseSelectedProject() void QbsProjectManagerPlugin::reparseCurrentProject() { - reparseProject(dynamic_cast(SessionManager::startupProject())); + reparseProject(dynamic_cast(ProjectManager::startupProject())); } void QbsProjectManagerPlugin::reparseProject(QbsProject *project) diff --git a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp index b1427c84bae..8c094c557a8 100644 --- a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp +++ b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp @@ -3,13 +3,13 @@ #include "librarydetailscontroller.h" -#include "qmakebuildconfiguration.h" #include "qmakeparsernodes.h" #include "qmakeproject.h" #include "qmakeprojectmanagertr.h" +#include #include -#include +#include #include #include @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -868,7 +869,7 @@ QString PackageLibraryDetailsController::snippet() const bool PackageLibraryDetailsController::isLinkPackageGenerated() const { - const Project *project = SessionManager::projectForFile(proFile()); + const Project *project = ProjectManager::projectForFile(proFile()); if (!project) return false; @@ -1016,7 +1017,7 @@ void InternalLibraryDetailsController::updateProFile() libraryDetailsWidget()->libraryComboBox->clear(); const QmakeProject *project - = dynamic_cast(SessionManager::projectForFile(proFile())); + = dynamic_cast(ProjectManager::projectForFile(proFile())); if (!project) return; @@ -1104,7 +1105,7 @@ QString InternalLibraryDetailsController::snippet() const // the build directory of the active build configuration QDir rootBuildDir = rootDir; // If the project is unconfigured use the project dir - if (const Project *project = SessionManager::projectForFile(proFile())) { + if (const Project *project = ProjectManager::projectForFile(proFile())) { if (ProjectExplorer::Target *t = project->activeTarget()) if (ProjectExplorer::BuildConfiguration *bc = t->activeBuildConfiguration()) rootBuildDir.setPath(bc->buildDirectory().toString()); diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp index 810d5d4f2e0..b492112db3d 100644 --- a/src/plugins/qmakeprojectmanager/profileeditor.cpp +++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp @@ -7,18 +7,22 @@ #include "profilehighlighter.h" #include "profilehoverhandler.h" #include "qmakenodes.h" -#include "qmakeproject.h" #include "qmakeprojectmanagerconstants.h" #include + #include + #include #include -#include +#include #include + #include + #include #include + #include #include #include @@ -65,7 +69,7 @@ QString ProFileEditorWidget::checkForPrfFile(const QString &baseName) const const QmakePriFileNode *projectNode = nullptr; // FIXME: Remove this check once project nodes are fully "static". - for (const Project * const project : SessionManager::projects()) { + for (const Project * const project : ProjectManager::projects()) { static const auto isParsing = [](const Project *project) { for (const Target * const t : project->targets()) { for (const BuildConfiguration * const bc : t->buildConfigurations()) { diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index e557615507d..67d450b56f4 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include @@ -244,7 +244,7 @@ void QmakeProjectManagerPlugin::initialize() connect(BuildManager::instance(), &BuildManager::buildStateChanged, d, &QmakeProjectManagerPluginPrivate::buildStateChanged); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, d, &QmakeProjectManagerPluginPrivate::projectChanged); connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, d, &QmakeProjectManagerPluginPrivate::projectChanged); @@ -294,7 +294,7 @@ void QmakeProjectManagerPluginPrivate::projectChanged() if (ProjectTree::currentProject()) m_previousStartupProject = qobject_cast(ProjectTree::currentProject()); else - m_previousStartupProject = qobject_cast(SessionManager::startupProject()); + m_previousStartupProject = qobject_cast(ProjectManager::startupProject()); if (m_previousStartupProject) { connect(m_previousStartupProject, &Project::activeTargetChanged, @@ -366,7 +366,7 @@ void QmakeProjectManagerPluginPrivate::addLibraryImpl(const FilePath &filePath, void QmakeProjectManagerPluginPrivate::runQMake() { - runQMakeImpl(SessionManager::startupProject(), nullptr); + runQMakeImpl(ProjectManager::startupProject(), nullptr); } void QmakeProjectManagerPluginPrivate::runQMakeContextMenu() @@ -411,7 +411,7 @@ void QmakeProjectManagerPluginPrivate::buildFile() FileNode *node = n ? n->asFileNode() : nullptr; if (!node) return; - Project *project = SessionManager::projectForFile(file); + Project *project = ProjectManager::projectForFile(file); if (!project) return; Target *target = project->activeTarget(); @@ -563,7 +563,7 @@ void QmakeProjectManagerPluginPrivate::enableBuildFileMenus(const FilePath &file bool enabled = false; if (Node *node = ProjectTree::nodeForFile(file)) { - if (Project *project = SessionManager::projectForFile(file)) { + if (Project *project = ProjectManager::projectForFile(file)) { if (const FileNode *fileNode = node->asFileNode()) { const FileType type = fileNode->fileType(); visible = qobject_cast(project) diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp index f3460cbca81..e9b5ab7082b 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -63,7 +63,7 @@ AssetExportDialog::AssetExportDialog(const Utils::FilePath &exportPath, m_ui->exportPath->setExpectedKind(Utils::PathChooser::Kind::SaveFile); m_ui->exportPath->setFilePath( exportPath.pathAppended( - ProjectExplorer::SessionManager::startupProject()->displayName() + ".metadata" + ProjectExplorer::ProjectManager::startupProject()->displayName() + ".metadata" )); m_ui->exportPath->setPromptDialogTitle(tr("Choose Export File")); m_ui->exportPath->setPromptDialogFilter(tr("Metadata file (*.metadata)")); diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp index d9167049a56..e1b95b75068 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp @@ -13,7 +13,7 @@ #include "coreplugin/editormanager/editormanager.h" #include "utils/qtcassert.h" #include "utils/runextensions.h" -#include "projectexplorer/session.h" +#include "projectexplorer/projectmanager.h" #include "projectexplorer/project.h" #include @@ -406,7 +406,7 @@ void AssetExporter::writeMetadata() const m_currentState.change(ParsingState::WritingJson); - auto const startupProject = ProjectExplorer::SessionManager::startupProject(); + auto const startupProject = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(startupProject, return); const QString projectName = startupProject->displayName(); diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp index 2d6f6c7d80f..3ab1d1a6869 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp @@ -19,9 +19,9 @@ #include "coreplugin/documentmanager.h" #include "qmldesigner/qmldesignerplugin.h" #include "projectexplorer/projectexplorerconstants.h" -#include "projectexplorer/session.h" +#include "projectexplorer/projectmanager.h" #include "projectexplorer/project.h" -#include "projectexplorer/session.h" +#include "projectexplorer/projectmanager.h" #include "projectexplorer/taskhub.h" #include "extensionsystem/pluginmanager.h" @@ -54,8 +54,8 @@ AssetExporterPlugin::AssetExporterPlugin() // Instantiate actions created by the plugin. addActions(); - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, this, &AssetExporterPlugin::updateActions); updateActions(); @@ -68,7 +68,7 @@ QString AssetExporterPlugin::pluginName() const void AssetExporterPlugin::onExport() { - auto startupProject = ProjectExplorer::SessionManager::startupProject(); + auto startupProject = ProjectExplorer::ProjectManager::startupProject(); if (!startupProject) return; @@ -97,7 +97,7 @@ void AssetExporterPlugin::addActions() void AssetExporterPlugin::updateActions() { - auto project = ProjectExplorer::SessionManager::startupProject(); + auto project = ProjectExplorer::ProjectManager::startupProject(); QAction* const exportAction = Core::ActionManager::command(Constants::EXPORT_QML)->action(); exportAction->setEnabled(project && !project->needsConfiguration()); } diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp index 9792a6615a3..f9c44229899 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp index 56ab654912e..1c68fdf0733 100644 --- a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp +++ b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp @@ -5,7 +5,7 @@ #include "designermcumanager.h" #include -#include +#include #include #include @@ -14,7 +14,7 @@ namespace QmlDesigner { static QString styleConfigFileName(const QString &qmlFileName) { - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(Utils::FilePath::fromString(qmlFileName)); + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile(Utils::FilePath::fromString(qmlFileName)); if (currentProject) { const QList fileNames = currentProject->files( diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp index f0969bfabb0..ca1e288815e 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -20,7 +20,7 @@ #ifndef QMLDESIGNER_TEST #include -#include +#include #include #include #include @@ -367,7 +367,7 @@ void ContentLibraryView::updateBundleMaterialsQuick3DVersion() #ifndef QMLDESIGNER_TEST if (hasImport && major == -1) { // Import without specifying version, so we take the kit version - auto target = ProjectExplorer::SessionManager::startupTarget(); + auto target = ProjectExplorer::ProjectManager::startupTarget(); if (target) { QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); if (qtVersion) { diff --git a/src/plugins/qmldesigner/components/eventlist/eventlist.cpp b/src/plugins/qmldesigner/components/eventlist/eventlist.cpp index 23e60dbda28..a0d7cc89815 100644 --- a/src/plugins/qmldesigner/components/eventlist/eventlist.cpp +++ b/src/plugins/qmldesigner/components/eventlist/eventlist.cpp @@ -8,7 +8,7 @@ #include "bindingproperty.h" #include "metainfo.h" #include "projectexplorer/project.h" -#include "projectexplorer/session.h" +#include "projectexplorer/projectmanager.h" #include "qmldesignerplugin.h" #include "signalhandlerproperty.h" #include "utils/fileutils.h" @@ -23,7 +23,7 @@ namespace QmlDesigner { Utils::FilePath projectFilePath() { if (auto *doc = QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()) { - if (auto *proj = ProjectExplorer::SessionManager::projectForFile(doc->fileName())) + if (auto *proj = ProjectExplorer::ProjectManager::projectForFile(doc->fileName())) return proj->projectDirectory(); } return Utils::FilePath(); diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index efeea8aa36f..9c73789c91c 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -403,7 +403,7 @@ bool DesignDocument::isQtForMCUsProject() const Utils::FilePath DesignDocument::projectFolder() const { - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName()); + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile(fileName()); if (currentProject) return currentProject->projectDirectory(); @@ -434,7 +434,7 @@ void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textMod void DesignDocument::updateQrcFiles() { - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName()); + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile(fileName()); if (currentProject) { const auto srcFiles = currentProject->files(ProjectExplorer::Project::SourceFiles); @@ -716,7 +716,7 @@ void DesignDocument::redo() static Target *getActiveTarget(DesignDocument *designDocument) { - Project *currentProject = SessionManager::projectForFile(designDocument->fileName()); + Project *currentProject = ProjectManager::projectForFile(designDocument->fileName()); if (!currentProject) currentProject = ProjectTree::currentProject(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 648ffdb56cc..df9f2737972 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + #include "itemlibraryassetimportdialog.h" #include "ui_itemlibraryassetimportdialog.h" @@ -13,7 +14,8 @@ #include "theme.h" #include -#include +#include + #include #include @@ -322,7 +324,7 @@ void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode, // Unable to find original scene source, launch file dialog to locate it QString initialPath; ProjectExplorer::Project *currentProject - = ProjectExplorer::SessionManager::projectForFile( + = ProjectExplorer::ProjectManager::projectForFile( Utils::FilePath::fromString(compFileName)); if (currentProject) initialPath = currentProject->projectDirectory().toString(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 556d0c978fe..96b95f7949a 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" #include @@ -336,7 +336,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); Utils::FilePath qmlFileName = document->fileName(); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(qmlFileName); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile(qmlFileName); QString projectName = project ? project->displayName() : ""; QString materialBundlePrefix = QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index 95b6476638d..aacbd9b1b53 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index e6450d45627..2d4cd76cc4b 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -454,14 +454,14 @@ const ProjectExplorer::FileNode *NavigatorView::fileNodeForModelNode(const Model { QString filename = node.metaInfo().componentFileName(); Utils::FilePath filePath = Utils::FilePath::fromString(filename); - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile( + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile( filePath); if (!currentProject) { filePath = Utils::FilePath::fromString(node.model()->fileUrl().toLocalFile()); /* If the component does not belong to the project then we can fallback to the current file */ - currentProject = ProjectExplorer::SessionManager::projectForFile(filePath); + currentProject = ProjectExplorer::ProjectManager::projectForFile(filePath); } if (!currentProject) return nullptr; diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp index 7164586fea4..02ffd84c93d 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include static QString s_lastBrowserPath; @@ -23,7 +23,7 @@ FileResourcesModel::FileResourcesModel(QObject *parent) : QObject(parent) , m_filter(QLatin1String("(*.*)")) { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile( QmlDesigner::DocumentManager::currentFilePath()); if (project) { diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp index d2bf9eac514..9fdf4e41198 100644 --- a/src/plugins/qmldesigner/documentmanager.cpp +++ b/src/plugins/qmldesigner/documentmanager.cpp @@ -21,10 +21,11 @@ #include #include #include -#include + #include +#include +#include #include -#include #include #include @@ -335,11 +336,11 @@ Utils::FilePath DocumentManager::currentProjectDirPath() Utils::FilePath qmlFileName = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName(); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(qmlFileName); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile(qmlFileName); if (project) return project->projectDirectory(); - const QList projects = ProjectExplorer::SessionManager::projects(); + const QList projects = ProjectExplorer::ProjectManager::projects(); for (auto p : projects) { if (qmlFileName.startsWith(p->projectDirectory().toString())) return p->projectDirectory(); @@ -402,7 +403,7 @@ void DocumentManager::findPathToIsoProFile(bool *iconResourceFileAlreadyExists, QString *resourceFileProPath, const QString &isoIconsQrcFile) { Utils::FilePath qmlFileName = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName(); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(qmlFileName); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile(qmlFileName); ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(qmlFileName)->parentFolderNode(); ProjectExplorer::Node *iconQrcFileNode = nullptr; @@ -492,7 +493,7 @@ bool DocumentManager::belongsToQmakeProject() return false; Utils::FilePath qmlFileName = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName(); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(qmlFileName); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile(qmlFileName); if (!project) return false; diff --git a/src/plugins/qmldesigner/generateresource.cpp b/src/plugins/qmldesigner/generateresource.cpp index 1901a8e2ea1..8b00335ce33 100644 --- a/src/plugins/qmldesigner/generateresource.cpp +++ b/src/plugins/qmldesigner/generateresource.cpp @@ -12,8 +12,8 @@ #include #include -#include #include +#include #include #include @@ -223,16 +223,16 @@ void GenerateResource::generateMenuEntry(QObject *parent) auto action = new QAction(QCoreApplication::translate("QmlDesigner::GenerateResource", "Generate QRC Resource File..."), parent); - action->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr); + action->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr); // todo make it more intelligent when it gets enabled - QObject::connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, [action]() { - action->setEnabled(ProjectExplorer::SessionManager::startupProject()); + QObject::connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, [action]() { + action->setEnabled(ProjectExplorer::ProjectManager::startupProject()); }); Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateResource"); QObject::connect(action, &QAction::triggered, [] () { - auto currentProject = ProjectExplorer::SessionManager::startupProject(); + auto currentProject = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(currentProject, return); const FilePath projectPath = currentProject->projectFilePath().parentDir(); @@ -331,16 +331,16 @@ void GenerateResource::generateMenuEntry(QObject *parent) auto rccAction = new QAction(QCoreApplication::translate("QmlDesigner::GenerateResource", "Generate Deployable Package..."), parent); - rccAction->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr); - QObject::connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, [rccAction]() { - rccAction->setEnabled(ProjectExplorer::SessionManager::startupProject()); + rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr); + QObject::connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, [rccAction]() { + rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject()); }); Core::Command *cmd2 = Core::ActionManager::registerAction(rccAction, "QmlProject.CreateRCCResource"); QObject::connect(rccAction, &QAction::triggered, []() { - auto currentProject = ProjectExplorer::SessionManager::startupProject(); + auto currentProject = ProjectExplorer::ProjectManager::startupProject(); QTC_ASSERT(currentProject, return); const FilePath projectPath = currentProject->projectFilePath().parentDir(); diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp index e332f1d49c7..47174ba3d88 100644 --- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp +++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -109,7 +109,7 @@ QString ExternalDependencies::itemLibraryImportUserComponentsTitle() const bool ExternalDependencies::isQt6Import() const { - auto target = ProjectExplorer::SessionManager::startupTarget(); + auto target = ProjectExplorer::ProjectManager::startupTarget(); if (target) { QtSupport::QtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); if (currentQtVersion && currentQtVersion->isValid()) { @@ -122,7 +122,7 @@ bool ExternalDependencies::isQt6Import() const bool ExternalDependencies::hasStartupTarget() const { - auto target = ProjectExplorer::SessionManager::startupTarget(); + auto target = ProjectExplorer::ProjectManager::startupTarget(); if (target) { QtSupport::QtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); if (currentQtVersion && currentQtVersion->isValid()) { @@ -208,7 +208,7 @@ QString createFreeTypeOption(ProjectExplorer::Target *target) PuppetStartData ExternalDependencies::puppetStartData(const Model &model) const { PuppetStartData data; - auto target = ProjectExplorer::SessionManager::startupTarget(); + auto target = ProjectExplorer::ProjectManager::startupTarget(); auto [workingDirectory, puppetPath] = qmlPuppetPaths(target, m_designerSettings); data.puppetPath = puppetPath.toString(); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 3fe639b5d8d..b8685ba700a 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include #include @@ -347,7 +347,7 @@ ExtensionSystem::IPlugin::ShutdownFlag QmlDesignerPlugin::aboutToShutdown() static QStringList allUiQmlFilesforCurrentProject(const Utils::FilePath &fileName) { QStringList list; - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName); + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile(fileName); if (currentProject) { const QList fileNames = currentProject->files(ProjectExplorer::Project::SourceFiles); @@ -363,7 +363,7 @@ static QStringList allUiQmlFilesforCurrentProject(const Utils::FilePath &fileNam static QString projectPath(const Utils::FilePath &fileName) { QString path; - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName); + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::projectForFile(fileName); if (currentProject) path = currentProject->projectDirectory().toString(); diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index e708e8ebf11..60363e5fbd1 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -199,15 +199,15 @@ QmlDesignerProjectManager::QmlDesignerProjectManager(ExternalDependenciesInterfa QObject::connect(editorManager, &::Core::EditorManager::editorsClosed, [&](const auto &editors) { editorsClosed(editors); }); - auto sessionManager = ::ProjectExplorer::SessionManager::instance(); + auto sessionManager = ::ProjectExplorer::ProjectManager::instance(); QObject::connect(sessionManager, - &::ProjectExplorer::SessionManager::projectAdded, + &::ProjectExplorer::ProjectManager::projectAdded, [&](auto *project) { projectAdded(project); }); QObject::connect(sessionManager, - &::ProjectExplorer::SessionManager::aboutToRemoveProject, + &::ProjectExplorer::ProjectManager::aboutToRemoveProject, [&](auto *project) { aboutToRemoveProject(project); }); QObject::connect(sessionManager, - &::ProjectExplorer::SessionManager::projectRemoved, + &::ProjectExplorer::ProjectManager::projectRemoved, [&](auto *project) { projectRemoved(project); }); QObject::connect(&m_previewTimer, @@ -428,7 +428,7 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache imageCacheData->nodeInstanceCollector.setTarget(target); }; - if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { + if (auto project = ProjectExplorer::ProjectManager::startupProject(); project) { // TODO wrap in function in image cache data m_imageCacheData->meshImageCollector.setTarget(project->activeTarget()); m_imageCacheData->nodeInstanceCollector.setTarget(project->activeTarget()); @@ -437,8 +437,8 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache this, setTargetInImageCache); } - QObject::connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, + QObject::connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, this, [=](ProjectExplorer::Project *project) { setTargetInImageCache(activeTarget(project)); diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp index a90c6240125..cba3411ead5 100644 --- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp +++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -36,7 +36,7 @@ static void handleAction(const SelectionContext &context) if (context.view()->isAttached()) { if (context.toggled()) { bool skipDeploy = false; - if (const Target *startupTarget = SessionManager::startupTarget()) { + if (const Target *startupTarget = ProjectManager::startupTarget()) { const Kit *kit = startupTarget->kit(); if (kit && (kit->supportedPlatforms().contains(Android::Constants::ANDROID_DEVICE_TYPE) @@ -241,10 +241,10 @@ QWidget *SwitchLanguageComboboxAction::createWidget(QWidget *parent) } } }; - connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::startupProjectChanged, + connect(ProjectExplorer::ProjectManager::instance(), &ProjectExplorer::ProjectManager::startupProjectChanged, comboBox, refreshComboBoxFunction); - if (auto project = SessionManager::startupProject()) + if (auto project = ProjectManager::startupProject()) refreshComboBoxFunction(project); // do this after refreshComboBoxFunction so we do not get currentLocaleChanged signals at initialization diff --git a/src/plugins/qmljstools/qmljslocatordata.cpp b/src/plugins/qmljstools/qmljslocatordata.cpp index 679a230e8e1..477447c9e36 100644 --- a/src/plugins/qmljstools/qmljslocatordata.cpp +++ b/src/plugins/qmljstools/qmljslocatordata.cpp @@ -4,7 +4,7 @@ #include "qmljslocatordata.h" #include -#include +#include #include #include @@ -40,10 +40,10 @@ LocatorData::LocatorData() connect(manager, &ModelManagerInterface::aboutToRemoveFiles, this, &LocatorData::onAboutToRemoveFiles); - ProjectExplorer::SessionManager *session = ProjectExplorer::SessionManager::instance(); + ProjectExplorer::ProjectManager *session = ProjectExplorer::ProjectManager::instance(); if (session) connect(session, - &ProjectExplorer::SessionManager::projectRemoved, + &ProjectExplorer::ProjectManager::projectRemoved, this, [this](ProjectExplorer::Project *) { m_entries.clear(); }); } diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index da1d82b73d0..914a4f77945 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -18,10 +18,11 @@ #include #include #include +#include #include #include #include -#include +#include #include #include @@ -273,9 +274,9 @@ void ModelManager::delayedInitialization() connect(cppModelManager, &CppEditor::CppModelManager::documentUpdated, this, &ModelManagerInterface::maybeQueueCppQmlTypeUpdate, Qt::DirectConnection); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(ProjectManager::instance(), &ProjectManager::projectRemoved, this, &ModelManager::removeProjectInfo); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &ModelManager::updateDefaultProjectInfo); ViewerContext qbsVContext; @@ -323,7 +324,7 @@ ModelManagerInterface::WorkingCopy ModelManager::workingCopyInternal() const void ModelManager::updateDefaultProjectInfo() { // needs to be performed in the ui thread - Project *currentProject = SessionManager::startupProject(); + Project *currentProject = ProjectManager::startupProject(); setDefaultProject(containsProject(currentProject) ? projectInfo(currentProject) : defaultProjectInfoForProject(currentProject, {}), diff --git a/src/plugins/qmlpreview/qmlpreviewplugin.cpp b/src/plugins/qmlpreview/qmlpreviewplugin.cpp index 6175eac2a2f..8803475d8a6 100644 --- a/src/plugins/qmlpreview/qmlpreviewplugin.cpp +++ b/src/plugins/qmlpreview/qmlpreviewplugin.cpp @@ -25,10 +25,10 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -150,15 +150,15 @@ QmlPreviewPluginPrivate::QmlPreviewPluginPrivate(QmlPreviewPlugin *parent) Constants::M_BUILDPROJECT); QAction *action = new QAction(Tr::tr("QML Preview"), this); action->setToolTip(Tr::tr("Preview changes to QML code live in your application.")); - action->setEnabled(SessionManager::startupProject() != nullptr); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, action, + action->setEnabled(ProjectManager::startupProject() != nullptr); + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, action, &QAction::setEnabled); connect(action, &QAction::triggered, this, [this]() { if (auto multiLanguageAspect = QmlProjectManager::QmlMultiLanguageAspect::current()) m_localeIsoCode = multiLanguageAspect->currentLocale(); bool skipDeploy = false; - const Kit *kit = SessionManager::startupTarget()->kit(); - if (SessionManager::startupTarget() && kit) + const Kit *kit = ProjectManager::startupTarget()->kit(); + if (ProjectManager::startupTarget() && kit) skipDeploy = kit->supportedPlatforms().contains(Android::Constants::ANDROID_DEVICE_TYPE) || DeviceTypeKitAspect::deviceTypeId(kit) == Android::Constants::ANDROID_DEVICE_TYPE; ProjectExplorerPlugin::runStartupProject(Constants::QML_PREVIEW_RUN_MODE, skipDeploy); diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index 57088ad19bf..3aa935db74e 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp b/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp index 396c8305680..e9f0b1a7807 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 579a870a4b0..dc33663e895 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -39,8 +39,8 @@ #include #include #include +#include #include -#include #include @@ -540,7 +540,7 @@ ProjectExplorer::RunControl *QmlProfilerTool::attachToWaitingApplication() d->m_viewContainer->perspective()->select(); auto runControl = new RunControl(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); - runControl->copyDataFromRunConfiguration(SessionManager::startupRunConfiguration()); + runControl->copyDataFromRunConfiguration(ProjectManager::startupRunConfiguration()); auto profiler = new QmlProfilerRunner(runControl); profiler->setServerUrl(serverUrl); diff --git a/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp b/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp index e01b6ab5ef3..ad787e05a5e 100644 --- a/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp +++ b/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp @@ -3,15 +3,16 @@ #include "qmlprofilerdetailsrewriter_test.h" +#include #include #include -#include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include + #include #include @@ -157,15 +158,15 @@ void QmlProfilerDetailsRewriterTest::testPopulateFileFinder() // Test that the rewriter will populate from available projects if given nullptr as parameter. DummyProject *project1 = new DummyProject(":/nix.nix"); - ProjectExplorer::SessionManager::addProject(project1); + ProjectExplorer::ProjectManager::addProject(project1); DummyProject *project2 = new DummyProject(":/qmlprofiler/tests/Test.qml"); - ProjectExplorer::SessionManager::addProject(project2); + ProjectExplorer::ProjectManager::addProject(project2); m_rewriter.populateFileFinder(nullptr); QCOMPARE(m_rewriter.getLocalFile("Test.qml"), Utils::FilePath::fromString(":/qmlprofiler/tests/Test.qml")); - ProjectExplorer::SessionManager::removeProject(project1); - ProjectExplorer::SessionManager::removeProject(project2); + ProjectExplorer::ProjectManager::removeProject(project1); + ProjectExplorer::ProjectManager::removeProject(project2); } void QmlProfilerDetailsRewriterTest::seedRewriter() @@ -196,11 +197,11 @@ void QmlProfilerDetailsRewriterTest::seedRewriter() ProjectExplorer::SysRootKitAspect::setSysRoot(kit.get(), "/nowhere"); DummyProject *project = new DummyProject(Utils::FilePath::fromString(filename)); - ProjectExplorer::SessionManager::addProject(project); + ProjectExplorer::ProjectManager::addProject(project); m_rewriter.populateFileFinder(project->addTargetForKit(kit.get())); - ProjectExplorer::SessionManager::removeProject(project); + ProjectExplorer::ProjectManager::removeProject(project); } } // namespace Internal diff --git a/src/plugins/qmlprojectmanager/cmakegen/cmakeprojectconverter.cpp b/src/plugins/qmlprojectmanager/cmakegen/cmakeprojectconverter.cpp index 99995bc2abe..21a538c7c51 100644 --- a/src/plugins/qmlprojectmanager/cmakegen/cmakeprojectconverter.cpp +++ b/src/plugins/qmlprojectmanager/cmakegen/cmakeprojectconverter.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + #include "cmakeprojectconverter.h" #include "cmakeprojectconverterdialog.h" #include "generatecmakelists.h" @@ -11,7 +12,7 @@ #include #include -#include +#include #include #include @@ -41,10 +42,10 @@ void CmakeProjectConverter::generateMenuEntry(QObject *parent) Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.ConvertToCmakeProject"); exportMenu->addAction(cmd, QmlProjectManager::Constants::G_EXPORT_CONVERT); - action->setEnabled(isProjectConvertable(ProjectExplorer::SessionManager::startupProject())); - QObject::connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, [action]() { - action->setEnabled(isProjectConvertable(ProjectExplorer::SessionManager::startupProject())); + action->setEnabled(isProjectConvertable(ProjectExplorer::ProjectManager::startupProject())); + QObject::connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, [action]() { + action->setEnabled(isProjectConvertable(ProjectExplorer::ProjectManager::startupProject())); }); } @@ -83,7 +84,7 @@ bool CmakeProjectConverter::isProjectCurrentFormat(const ProjectExplorer::Projec void CmakeProjectConverter::onConvertProject() { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); const QmlProjectManager::QmlProject *qmlProject = qobject_cast(project); if (qmlProject) { diff --git a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp index ef83206d982..e1124319196 100644 --- a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp +++ b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "generatecmakelists.h" + #include "generatecmakelistsconstants.h" #include "cmakegeneratordialog.h" #include "../qmlprojectmanagertr.h" @@ -10,9 +11,9 @@ #include #include -#include #include -#include +#include +#include #include #include @@ -79,18 +80,18 @@ void generateMenuEntry(QObject *parent) exportMenu->addAction(cmd, QmlProjectManager::Constants::G_EXPORT_GENERATE); action->setEnabled(false); - QObject::connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, + QObject::connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, [action]() { auto qmlProject = qobject_cast( - ProjectExplorer::SessionManager::startupProject()); + ProjectExplorer::ProjectManager::startupProject()); action->setEnabled(qmlProject != nullptr); }); } void onGenerateCmakeLists() { - FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory(); + FilePath rootDir = ProjectExplorer::ProjectManager::startupProject()->projectDirectory(); int projectDirErrors = isProjectCorrectlyFormed(rootDir); if (projectDirErrors != NoError) { @@ -246,7 +247,7 @@ const QString projectEnvironmentVariable(const QString &key) { QString value = {}; - auto *target = ProjectExplorer::SessionManager::startupProject()->activeTarget(); + auto *target = ProjectExplorer::ProjectManager::startupProject()->activeTarget(); if (target && target->buildSystem()) { auto buildSystem = qobject_cast(target->buildSystem()); if (buildSystem) { @@ -304,7 +305,7 @@ const char ADD_SUBDIR[] = "add_subdirectory(%1)\n"; void CmakeFileGenerator::generateMainCmake(const FilePath &rootDir) { //TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all. - QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); + QString projectName = ProjectExplorer::ProjectManager::startupProject()->displayName(); QString appName = projectName + "App"; QString fileSection = ""; @@ -523,7 +524,7 @@ bool CmakeFileGenerator::isDirBlacklisted(const FilePath &dir) bool CmakeFileGenerator::includeFile(const FilePath &filePath) { if (m_checkFileIsInProject) { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project->isKnownFile(filePath)) return false; } @@ -570,7 +571,7 @@ bool CmakeFileGenerator::generateMainCpp(const FilePath &dir) bool envHeaderOk = true; QString environment; - auto *target = ProjectExplorer::SessionManager::startupProject()->activeTarget(); + auto *target = ProjectExplorer::ProjectManager::startupProject()->activeTarget(); if (target && target->buildSystem()) { auto buildSystem = qobject_cast(target->buildSystem()); if (buildSystem) { diff --git a/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp b/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp index 8ae0efe3119..8cde4e2c222 100644 --- a/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp +++ b/src/plugins/qmlprojectmanager/projectfilecontenttools.cpp @@ -18,7 +18,7 @@ QRegularExpression qdsVerRegexp(R"x(qdsVersion: "(.*)")x"); const Utils::FilePaths rootCmakeFiles(ProjectExplorer::Project *project) { if (!project) - project = ProjectExplorer::SessionManager::startupProject(); + project = ProjectExplorer::ProjectManager::startupProject(); if (!project) return {}; return project->projectDirectory().dirEntries({QList({"CMakeLists.txt"}), QDir::Files}); diff --git a/src/plugins/qmlprojectmanager/projectfilecontenttools.h b/src/plugins/qmlprojectmanager/projectfilecontenttools.h index 843912eb7c8..3c3fcb5847e 100644 --- a/src/plugins/qmlprojectmanager/projectfilecontenttools.h +++ b/src/plugins/qmlprojectmanager/projectfilecontenttools.h @@ -6,7 +6,7 @@ #include "qmlprojectmanager_global.h" #include -#include +#include #include diff --git a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp index 4ca9f9aa626..db0001ac70f 100644 --- a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp +++ b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include static bool isMultilanguagePresent() @@ -114,7 +114,7 @@ void QmlMultiLanguageAspect::fromMap(const QVariantMap &map) QmlMultiLanguageAspect *QmlMultiLanguageAspect::current() { - if (auto project = ProjectExplorer::SessionManager::startupProject()) + if (auto project = ProjectExplorer::ProjectManager::startupProject()) return current(project); return {}; } diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index c283ec73e31..f08b9c4bda7 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -97,7 +97,7 @@ QmlProject::QmlProject(const Utils::FilePath &fileName) if (QmlProject::isQtDesignStudio()) { if (allowOnlySingleProject()) { EditorManager::closeAllDocuments(); - SessionManager::closeAllProjects(); + ProjectManager::closeAllProjects(); } m_openFileConnection diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index 3c156311b41..443d5478fc9 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -181,7 +181,7 @@ const Utils::FilePath findQmlProjectUpwards(const Utils::FilePath &folder) static bool findAndOpenProject(const Utils::FilePath &filePath) { ProjectExplorer::Project *project - = ProjectExplorer::SessionManager::projectForFile(filePath); + = ProjectExplorer::ProjectManager::projectForFile(filePath); if (project) { if (project->projectFilePath().suffix() == "qmlproject") { @@ -437,7 +437,7 @@ void QmlProjectPlugin::updateQmlLandingPageProjectInfo(const Utils::FilePath &pr Utils::FilePath QmlProjectPlugin::projectFilePath() { - auto project = ProjectExplorer::SessionManager::startupProject(); + auto project = ProjectExplorer::ProjectManager::startupProject(); const QmlProjectManager::QmlProject *qmlProject = qobject_cast(project); if (qmlProject) { return qmlProject->projectFilePath(); diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index 8e8527b32c0..e0b1e6a9b15 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -274,7 +274,7 @@ void QmlProjectRunConfiguration::createQtVersionAspect() if (!newTarget) newTarget = project->addTargetForKit(kits.first()); - SessionManager::setActiveTarget(project, newTarget, SetActive::Cascade); + project->setActiveTarget(newTarget, SetActive::Cascade); /* Reset the aspect. We changed the target and this aspect should not change. */ m_qtversionAspect->blockSignals(true); diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index cb3932daab5..d6ee8618980 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -223,7 +223,7 @@ void showAttachToProcessDialog() return; // FIXME: That should be somehow related to the selected kit. - auto runConfig = SessionManager::startupRunConfiguration(); + auto runConfig = ProjectManager::startupRunConfiguration(); const int pid = dlg.currentProcess().processId; // QString projectSourceDirectory = dlg.projectSource(); diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 6b1d64600f4..446f7d576a1 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -21,7 +21,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -1542,10 +1543,10 @@ void QtVersion::populateQmlFileFinder(FileInProjectFinder *finder, const Target // ... else try the session manager's global startup project ... if (!startupProject) - startupProject = SessionManager::startupProject(); + startupProject = ProjectManager::startupProject(); // ... and if that is null, use the first project available. - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); QTC_CHECK(projects.isEmpty() || startupProject); FilePath projectDirectory; diff --git a/src/plugins/qtsupport/externaleditors.cpp b/src/plugins/qtsupport/externaleditors.cpp index bed8b7618fa..ee3a3611031 100644 --- a/src/plugins/qtsupport/externaleditors.cpp +++ b/src/plugins/qtsupport/externaleditors.cpp @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include @@ -181,7 +181,7 @@ static bool getEditorLaunchData(const CommandForQtVersion &commandForQtVersion, // As fallback check PATH data->workingDirectory.clear(); QVector qtVersionsToCheck; // deduplicated after being filled - if (const Project *project = SessionManager::projectForFile(filePath)) { + if (const Project *project = ProjectManager::projectForFile(filePath)) { data->workingDirectory = project->projectDirectory(); // active kit if (const Target *target = project->activeTarget()) { diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index c54c1bfc232..8a1c94bddca 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -24,8 +24,8 @@ #include #include #include +#include #include -#include #include #include @@ -170,7 +170,7 @@ void QtSupportPlugin::extensionsInitialized() }); static const auto activeQtVersion = []() -> const QtVersion * { - ProjectExplorer::Project *project = SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectManager::startupProject(); if (!project || !project->activeTarget()) return nullptr; return QtKitAspect::qtVersion(project->activeTarget()->kit()); @@ -208,7 +208,7 @@ void QtSupportPlugin::extensionsInitialized() const FilePath filePath = item.filePath(); if (filePath.isEmpty()) return links; - const Project *project = SessionManager::projectForFile(filePath); + const Project *project = ProjectManager::projectForFile(filePath); Target *target = project ? project->activeTarget() : nullptr; QtVersion *qt = target ? QtKitAspect::qtVersion(target->kit()) : nullptr; if (!qt) diff --git a/src/plugins/scxmleditor/scxmleditordocument.cpp b/src/plugins/scxmleditor/scxmleditordocument.cpp index 9c84910b2dd..e10c8759084 100644 --- a/src/plugins/scxmleditor/scxmleditordocument.cpp +++ b/src/plugins/scxmleditor/scxmleditordocument.cpp @@ -6,7 +6,7 @@ #include "scxmleditorconstants.h" #include -#include +#include #include #include #include diff --git a/src/plugins/squish/squishfilehandler.cpp b/src/plugins/squish/squishfilehandler.cpp index 956f9488227..918120a4063 100644 --- a/src/plugins/squish/squishfilehandler.cpp +++ b/src/plugins/squish/squishfilehandler.cpp @@ -15,8 +15,10 @@ #include #include #include + #include #include + #include #include #include @@ -93,8 +95,7 @@ SquishFileHandler::SquishFileHandler(QObject *parent) : QObject(parent) { m_instance = this; - auto sessionManager = ProjectExplorer::SessionManager::instance(); - connect(sessionManager, &ProjectExplorer::SessionManager::sessionLoaded, + connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::sessionLoaded, this, &SquishFileHandler::onSessionLoaded); } diff --git a/src/plugins/todo/todoitemsprovider.cpp b/src/plugins/todo/todoitemsprovider.cpp index 02790c64dfb..02ba71e2fcc 100644 --- a/src/plugins/todo/todoitemsprovider.cpp +++ b/src/plugins/todo/todoitemsprovider.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "todoitemsprovider.h" + #include "constants.h" #include "cpptodoitemsscanner.h" #include "qmljstodoitemsscanner.h" @@ -13,9 +14,9 @@ #include #include +#include #include #include -#include #include @@ -182,8 +183,8 @@ void TodoItemsProvider::updateListTimeoutElapsed() void TodoItemsProvider::setupStartupProjectBinding() { - m_startupProject = SessionManager::startupProject(); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + m_startupProject = ProjectManager::startupProject(); + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &TodoItemsProvider::startupProjectChanged); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, this, &TodoItemsProvider::projectsFilesChanged); diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index fc50b2ecf09..4daa04efcf6 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -47,8 +47,8 @@ #include #include #include +#include #include -#include #include #include @@ -256,7 +256,7 @@ CallgrindToolPrivate::CallgrindToolPrivate() menu->addAction(ActionManager::registerAction(action, CallgrindRemoteActionId), Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); QObject::connect(action, &QAction::triggered, this, [this, action] { - auto runConfig = SessionManager::startupRunConfiguration(); + auto runConfig = ProjectManager::startupRunConfiguration(); if (!runConfig) { showCannotStartDialog(action->text()); return; diff --git a/src/plugins/valgrind/memcheckerrorview.cpp b/src/plugins/valgrind/memcheckerrorview.cpp index 3bb8a66a02e..48e9afd8018 100644 --- a/src/plugins/valgrind/memcheckerrorview.cpp +++ b/src/plugins/valgrind/memcheckerrorview.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index d4a5e4a6499..6129a0b4dbd 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -30,8 +30,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -337,7 +337,7 @@ bool MemcheckErrorFilterProxyModel::filterAcceptsRow(int sourceRow, const QModel // ALGORITHM: look at last five stack frames, if none of these is inside any open projects, // assume this error was created by an external library QSet validFolders; - for (Project *project : SessionManager::projects()) { + for (Project *project : ProjectManager::projects()) { validFolders << project->projectDirectory().toString(); const QList targets = project->targets(); for (const Target *target : targets) { @@ -676,7 +676,7 @@ MemcheckToolPrivate::MemcheckToolPrivate() menu->addAction(ActionManager::registerAction(action, "Memcheck.Remote"), Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); QObject::connect(action, &QAction::triggered, this, [this, action] { - RunConfiguration *runConfig = SessionManager::startupRunConfiguration(); + RunConfiguration *runConfig = ProjectManager::startupRunConfiguration(); if (!runConfig) { showCannotStartDialog(action->text()); return; @@ -718,7 +718,7 @@ void MemcheckToolPrivate::heobAction() Abi abi; bool hasLocalRc = false; Kit *kit = nullptr; - if (Target *target = SessionManager::startupTarget()) { + if (Target *target = ProjectManager::startupTarget()) { if (RunConfiguration *rc = target->activeRunConfiguration()) { kit = target->kit(); if (kit) { @@ -940,7 +940,7 @@ void MemcheckToolPrivate::maybeActiveRunConfigurationChanged() updateRunActions(); ValgrindBaseSettings *settings = nullptr; - if (Project *project = SessionManager::startupProject()) + if (Project *project = ProjectManager::startupProject()) if (Target *target = project->activeTarget()) if (RunConfiguration *rc = target->activeRunConfiguration()) settings = rc->currentSettings(ANALYZER_VALGRIND_SETTINGS); diff --git a/src/plugins/valgrind/suppressiondialog.cpp b/src/plugins/valgrind/suppressiondialog.cpp index 08ed8ae5ff7..6273580e82d 100644 --- a/src/plugins/valgrind/suppressiondialog.cpp +++ b/src/plugins/valgrind/suppressiondialog.cpp @@ -12,9 +12,9 @@ #include "xmlprotocol/stack.h" #include "xmlprotocol/frame.h" -#include -#include #include +#include +#include #include #include @@ -182,8 +182,8 @@ void SuppressionDialog::accept() return; // Add file to project if there is a project containing this file on the file system. - if (!ProjectExplorer::SessionManager::projectForFile(path)) { - for (ProjectExplorer::Project *p : ProjectExplorer::SessionManager::projects()) { + if (!ProjectExplorer::ProjectManager::projectForFile(path)) { + for (ProjectExplorer::Project *p : ProjectExplorer::ProjectManager::projects()) { if (path.startsWith(p->projectDirectory().toString())) { p->rootProjectNode()->addFiles({path}); break; diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index c73c14f9f66..26c19c7f91e 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -1234,7 +1234,7 @@ static QTextCodec *findProjectCodec(const FilePath &dirPath) { typedef QList ProjectList; // Try to find a project under which file tree the file is. - const ProjectList projects = ProjectExplorer::SessionManager::projects(); + const ProjectList projects = ProjectExplorer::ProjectManager::projects(); const ProjectExplorer::Project *p = findOrDefault(projects, equal(&ProjectExplorer::Project::projectDirectory, dirPath)); return p ? p->editorConfiguration()->textCodec() : nullptr; diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index b277a2d0680..dfd89842c52 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -9,12 +9,14 @@ #include "vcsplugin.h" #include +#include #include #include -#include -#include + #include -#include +#include +#include + #include #include @@ -195,7 +197,7 @@ StateListener::StateListener(QObject *parent) : QObject(parent) connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &StateListener::slotStateChanged); - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &StateListener::slotStateChanged); EditorManager::setWindowTitleVcsTopicHandler(&StateListener::windowTitleVcsTopic); @@ -213,7 +215,7 @@ QString StateListener::windowTitleVcsTopic(const FilePath &filePath) searchPath = filePath.absolutePath(); } else { // use single project's information if there is only one loaded. - const QList projects = SessionManager::projects(); + const QList projects = ProjectManager::projects(); if (projects.size() == 1) searchPath = projects.first()->projectDirectory(); } @@ -282,7 +284,7 @@ void StateListener::slotStateChanged() IVersionControl *projectControl = nullptr; Project *currentProject = ProjectTree::currentProject(); if (!currentProject) - currentProject = SessionManager::startupProject(); + currentProject = ProjectManager::startupProject(); if (currentProject) { state.currentProjectPath = currentProject->projectDirectory(); diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index eaa825adb10..23a41f363ea 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include @@ -606,7 +606,7 @@ void VcsBaseSubmitEditor::filterUntrackedFilesOfProject(const FilePath &reposito { for (QStringList::iterator it = untrackedFiles->begin(); it != untrackedFiles->end(); ) { const FilePath path = repositoryDirectory.resolvePath(*it).absoluteFilePath(); - if (ProjectExplorer::SessionManager::projectForFile(path)) + if (ProjectExplorer::ProjectManager::projectForFile(path)) ++it; else it = untrackedFiles->erase(it); From 00938bd7bf3771c4b47c56555ffd3e5d7c656003 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Feb 2023 00:54:48 +0100 Subject: [PATCH 0115/1447] TaskTree manual test: Use QPromise for async calls Change-Id: I532520af644b431441d74c0e06eff4d06d0b3924 Reviewed-by: hjk Reviewed-by: Qt CI Bot Reviewed-by: --- tests/manual/tasktree/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index b57481bfc41..4dc6da3fee7 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -18,11 +18,11 @@ using namespace Utils; // TODO: make tasks cancellable -static void sleepInThread(QFutureInterface &fi, int seconds, bool reportSuccess) +static void sleepInThread(QPromise &promise, int seconds, bool reportSuccess) { QThread::sleep(seconds); if (!reportSuccess) - fi.reportCanceled(); + promise.future().cancel(); } int main(int argc, char *argv[]) @@ -155,7 +155,7 @@ int main(int argc, char *argv[]) auto taskItem = [sync = &synchronizer, synchronizerCheckBox](TaskWidget *widget) { const auto setupHandler = [=](AsyncTask &task) { - task.setAsyncCallData(sleepInThread, widget->busyTime(), widget->isSuccess()); + task.setConcurrentCallData(sleepInThread, widget->busyTime(), widget->isSuccess()); if (synchronizerCheckBox->isChecked()) task.setFutureSynchronizer(sync); widget->setState(State::Running); From 6451538d39813640f227f79c316f7f656c5882f5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 1 Mar 2023 09:55:12 +0100 Subject: [PATCH 0116/1447] Docker: Don't try to mount existing directories Change-Id: I1df4e1bf8689edf08c539d71529e4149909502d7 Reviewed-by: hjk Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/docker/dockerdevice.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index a464c49abb4..0d8da3a57db 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1208,6 +1208,9 @@ bool DockerDevicePrivate::ensureReachable(const FilePath &other) return true; } + if (q->filePath(other.path()).exists()) + return false; + addTemporaryMount(other, other); return true; } From c8567312f620972a97993f5f07ce74e58984fd40 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 26 Jan 2023 11:40:23 +0100 Subject: [PATCH 0117/1447] Plugin wizard: Fix missing include, add some test infrastructure Just basic CMake setup that is needed for actually adding tests. Change-Id: Ief778c28f27ff122c82a190a334b7a932bead658 Reviewed-by: Cristian Adam --- .../wizards/qtcreatorplugin/CMakeLists.txt | 17 +++++++++++++++++ .../wizards/qtcreatorplugin/myplugin_global.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt b/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt index 48884eae644..a60e46cb7cd 100644 --- a/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt @@ -22,6 +22,23 @@ find_package(QtCreator REQUIRED COMPONENTS Core) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) set(QtX Qt${QT_VERSION_MAJOR}) +# Add a CMake option that enables building your plugin with tests. +# You don't want your released plugin binaries to contain tests, +# so make that default to 'NO'. +# Enable tests by passing -DWITH_TESTS=ON to CMake. +option(WITH_TESTS "Builds with tests" NO) + +if(WITH_TESTS) + # Look for QtTest + find_package(${QtX} REQUIRED COMPONENTS Test) + + # Tell CMake functions like add_qtc_plugin about the QtTest component. + set(IMPLICIT_DEPENDS Qt::Test) + + # Enable ctest for auto tests. + enable_testing() +endif() + add_qtc_plugin(%{PluginName} PLUGIN_DEPENDS QtCreator::Core diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin_global.h b/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin_global.h index b8b387bc01f..ad863f17945 100644 --- a/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin_global.h +++ b/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin_global.h @@ -6,6 +6,8 @@ #define %{GLOBAL_GUARD} @endif +#include + #if defined(%{LibraryDefine}) # define %{LibraryExport} Q_DECL_EXPORT #else From 9e223c6bde9148edb83198adbddaa92f88cfbec7 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 1 Mar 2023 17:54:39 +0100 Subject: [PATCH 0118/1447] Adapt to upstream Session/ProjectManager split Change-Id: Ia41a0985f95d2274219ea24c518341ac4accc3e8 Reviewed-by: Christian Kandeler --- plugins/axivion/axivionplugin.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 9f626656437..253ca34ad2f 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -15,14 +15,18 @@ #include #include #include + #include + #include #include +#include #include -#include + #include #include #include + #include #include @@ -134,8 +138,8 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return new AxivionProjectSettingsWidget(project); }); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, dd, &AxivionPluginPrivate::onStartupProjectChanged); connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, dd, &AxivionPluginPrivate::onDocumentOpened); @@ -198,7 +202,7 @@ AxivionProjectSettings *AxivionPluginPrivate::projectSettings(ProjectExplorer::P void AxivionPluginPrivate::onStartupProjectChanged() { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) { clearAllMarks(); m_currentProjectInfo = ProjectInfo(); @@ -255,14 +259,14 @@ void AxivionPluginPrivate::fetchRuleInfo(const QString &id) void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) { - if (project && ProjectExplorer::SessionManager::startupProject() != project) + if (project && ProjectExplorer::ProjectManager::startupProject() != project) return; const QList openDocuments = Core::DocumentModel::openedDocuments(); for (Core::IDocument *doc : openDocuments) onDocumentOpened(doc); if (project) - disconnect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::projectFinishedParsing, + disconnect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing, this, &AxivionPluginPrivate::handleOpenedDocs); } @@ -288,12 +292,12 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) return; // handle already opened documents - if (auto buildSystem = ProjectExplorer::SessionManager::startupBuildSystem(); + if (auto buildSystem = ProjectExplorer::ProjectManager::startupBuildSystem(); !buildSystem || !buildSystem->isParsing()) { handleOpenedDocs(nullptr); } else { - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::projectFinishedParsing, + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing, this, &AxivionPluginPrivate::handleOpenedDocs); } } @@ -303,7 +307,7 @@ void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) if (m_currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) return; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!doc || !project->isKnownFile(doc->filePath())) return; @@ -337,7 +341,7 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) if (issues.issues.isEmpty()) return; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) return; From 5a5776400a17543366c9a2a07d8d535a77c14cde Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 2 Mar 2023 07:59:56 +0100 Subject: [PATCH 0119/1447] AutoTest: Fix missing includes Change-Id: Ieb34092c8c78068ae1630cfaa0f18a45f7d43c0c Reviewed-by: Jarek Kobus --- src/plugins/autotest/boost/boosttestparser.cpp | 1 + src/plugins/autotest/catch/catchtestparser.cpp | 1 + src/plugins/autotest/gtest/gtestparser.cpp | 1 + src/plugins/autotest/qtest/qttestparser.cpp | 1 + src/plugins/autotest/quick/quicktestparser.cpp | 2 ++ 5 files changed, 6 insertions(+) diff --git a/src/plugins/autotest/boost/boosttestparser.cpp b/src/plugins/autotest/boost/boosttestparser.cpp index 74c463244b9..8c701942ada 100644 --- a/src/plugins/autotest/boost/boosttestparser.cpp +++ b/src/plugins/autotest/boost/boosttestparser.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/src/plugins/autotest/catch/catchtestparser.cpp b/src/plugins/autotest/catch/catchtestparser.cpp index 9198e41342b..3cc7a4540be 100644 --- a/src/plugins/autotest/catch/catchtestparser.cpp +++ b/src/plugins/autotest/catch/catchtestparser.cpp @@ -11,6 +11,7 @@ #include #include +#include #include using namespace Utils; diff --git a/src/plugins/autotest/gtest/gtestparser.cpp b/src/plugins/autotest/gtest/gtestparser.cpp index 7e3f987905b..c8cc92005e8 100644 --- a/src/plugins/autotest/gtest/gtestparser.cpp +++ b/src/plugins/autotest/gtest/gtestparser.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp index ece94f82474..a532a13cb3d 100644 --- a/src/plugins/autotest/qtest/qttestparser.cpp +++ b/src/plugins/autotest/qtest/qttestparser.cpp @@ -10,6 +10,7 @@ #include #include +#include #include using namespace Utils; diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index b8035f11a7a..09965a099a4 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -23,6 +23,8 @@ #include #include +#include + using namespace QmlJS; using namespace Utils; From 0020129afed5aa4a9fc4eeee07e4b7febfa0f40b Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Thu, 2 Mar 2023 14:55:22 +0900 Subject: [PATCH 0120/1447] PluginDialog: set initial focus to filter Qt Creator provides numbers of plugins. Setting focus to the filter control helps to find a plugin. Change-Id: Iac34ff04b97311a8c7890a3cbafdde22b2242dcd Reviewed-by: Alessandro Portale Reviewed-by: Eike Ziller --- src/plugins/coreplugin/plugindialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp index 1298238722c..f6ea25e719c 100644 --- a/src/plugins/coreplugin/plugindialog.cpp +++ b/src/plugins/coreplugin/plugindialog.cpp @@ -40,6 +40,7 @@ PluginDialog::PluginDialog(QWidget *parent) auto filterLayout = new QHBoxLayout; vl->addLayout(filterLayout); auto filterEdit = new Utils::FancyLineEdit(this); + filterEdit->setFocus(); filterEdit->setFiltering(true); connect(filterEdit, &Utils::FancyLineEdit::filterChanged, m_view, &ExtensionSystem::PluginView::setFilter); From 3287e14dd11fce2c41013351841fbf719b7323ad Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 2 Mar 2023 08:11:30 +0100 Subject: [PATCH 0121/1447] Utils: Add QTC_USE_WINPTY environment variable Change-Id: I769bfe8bd92529f672694da38d04914e0a51ed1b Reviewed-by: Cristian Adam Reviewed-by: --- src/libs/3rdparty/libptyqt/ptyqt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/3rdparty/libptyqt/ptyqt.cpp b/src/libs/3rdparty/libptyqt/ptyqt.cpp index 3883395e22d..b3e7aa1b164 100644 --- a/src/libs/3rdparty/libptyqt/ptyqt.cpp +++ b/src/libs/3rdparty/libptyqt/ptyqt.cpp @@ -34,7 +34,7 @@ IPtyProcess *PtyQt::createPtyProcess(IPtyProcess::PtyType ptyType) } #ifdef Q_OS_WIN - if (ConPtyProcess().isAvailable()) + if (ConPtyProcess().isAvailable() && qgetenv("QTC_USE_WINPTY").isEmpty()) return new ConPtyProcess(); else return new WinPtyProcess(); From 007c47a2d425eab45925eb4d642f35b20360a508 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 22 Feb 2023 15:12:48 +0100 Subject: [PATCH 0122/1447] Terminal: Use QWinEventNotifier for shell process termination Change-Id: I59ddcaa76714a0b15987b9e0912f4701a2951648 Reviewed-by: Cristian Adam --- src/libs/3rdparty/libptyqt/conptyprocess.cpp | 35 ++++++++++--------- src/libs/3rdparty/libptyqt/conptyprocess.h | 4 ++- src/libs/3rdparty/libptyqt/winptyprocess.cpp | 36 +++++++++++--------- src/libs/3rdparty/libptyqt/winptyprocess.h | 5 +-- 4 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.cpp b/src/libs/3rdparty/libptyqt/conptyprocess.cpp index b50f319ebf1..d112f5e1533 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/conptyprocess.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -179,21 +180,19 @@ bool ConPtyProcess::startProcess(const QString &executable, m_pid = m_shellProcessInformation.dwProcessId; // Notify when the shell process has been terminated - RegisterWaitForSingleObject( - &m_shellCloseWaitHandle, - m_shellProcessInformation.hProcess, - [](PVOID data, BOOLEAN) { - auto self = static_cast(data); - DWORD exitCode = 0; - GetExitCodeProcess(self->m_shellProcessInformation.hProcess, &exitCode); - self->m_exitCode = exitCode; - // Do not respawn if the object is about to be destructed - if (!self->m_aboutToDestruct) - emit self->notifier()->aboutToClose(); - }, - this, - INFINITE, - WT_EXECUTEONLYONCE); + m_shellCloseWaitNotifier = new QWinEventNotifier(m_shellProcessInformation.hProcess, notifier()); + QObject::connect(m_shellCloseWaitNotifier, + &QWinEventNotifier::activated, + notifier(), + [this](HANDLE hEvent) { + DWORD exitCode = 0; + GetExitCodeProcess(hEvent, &exitCode); + m_exitCode = exitCode; + // Do not respawn if the object is about to be destructed + if (!m_aboutToDestruct) + emit notifier()->aboutToClose(); + m_shellCloseWaitNotifier->setEnabled(false); + }); //this code runned in separate thread m_readThread = QThread::create([this]() @@ -220,6 +219,8 @@ bool ConPtyProcess::startProcess(const QString &executable, if (QThread::currentThread()->isInterruptionRequested() || brokenPipe) break; } + + CancelIoEx(m_hPipeIn, nullptr); }); //start read thread @@ -269,6 +270,9 @@ bool ConPtyProcess::kill() m_readThread->deleteLater(); m_readThread = nullptr; + delete m_shellCloseWaitNotifier; + m_shellCloseWaitNotifier = nullptr; + m_pid = 0; m_ptyHandler = INVALID_HANDLE_VALUE; m_hPipeIn = INVALID_HANDLE_VALUE; @@ -276,7 +280,6 @@ bool ConPtyProcess::kill() CloseHandle(m_shellProcessInformation.hThread); CloseHandle(m_shellProcessInformation.hProcess); - UnregisterWait(m_shellCloseWaitHandle); // Cleanup attribute list if (m_shellStartupInfo.lpAttributeList) { diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.h b/src/libs/3rdparty/libptyqt/conptyprocess.h index b3f77664c26..a22b6290c77 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.h +++ b/src/libs/3rdparty/libptyqt/conptyprocess.h @@ -23,6 +23,8 @@ typedef VOID* HPCON; #define TOO_OLD_WINSDK #endif +class QWinEventNotifier; + template std::vector vectorFromString(const std::basic_string &str) { @@ -160,7 +162,7 @@ private: PtyBuffer m_buffer; bool m_aboutToDestruct{false}; PROCESS_INFORMATION m_shellProcessInformation{}; - HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE}; + QWinEventNotifier* m_shellCloseWaitNotifier; STARTUPINFOEX m_shellStartupInfo{}; }; diff --git a/src/libs/3rdparty/libptyqt/winptyprocess.cpp b/src/libs/3rdparty/libptyqt/winptyprocess.cpp index 90ac139b9c3..be3a0de609e 100644 --- a/src/libs/3rdparty/libptyqt/winptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/winptyprocess.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #define DEBUG_VAR_LEGACY "WINPTYDBG" #define DEBUG_VAR_ACTUAL "WINPTY_DEBUG" @@ -132,22 +134,22 @@ bool WinPtyProcess::startProcess(const QString &executable, m_pid = (int)GetProcessId(m_innerHandle); + m_outSocket = new QLocalSocket(); + // Notify when the shell process has been terminated - RegisterWaitForSingleObject( - &m_shellCloseWaitHandle, - m_innerHandle, - [](PVOID data, BOOLEAN) { - auto self = static_cast(data); - // Do not respawn if the object is about to be destructed - DWORD exitCode = 0; - GetExitCodeProcess(self->m_innerHandle, &exitCode); - self->m_exitCode = exitCode; - if (!self->m_aboutToDestruct) - emit self->notifier()->aboutToClose(); - }, - this, - INFINITE, - WT_EXECUTEONLYONCE); + m_shellCloseWaitNotifier = new QWinEventNotifier(m_innerHandle, notifier()); + QObject::connect(m_shellCloseWaitNotifier, + &QWinEventNotifier::activated, + notifier(), + [this](HANDLE hEvent) { + DWORD exitCode = 0; + GetExitCodeProcess(hEvent, &exitCode); + m_exitCode = exitCode; + // Do not respawn if the object is about to be destructed + if (!m_aboutToDestruct) + emit notifier()->aboutToClose(); + m_shellCloseWaitNotifier->setEnabled(false); + }); //get pipe names LPCWSTR conInPipeName = winpty_conin_name(m_ptyHandler); @@ -158,7 +160,6 @@ bool WinPtyProcess::startProcess(const QString &executable, LPCWSTR conOutPipeName = winpty_conout_name(m_ptyHandler); m_conOutName = QString::fromStdWString(std::wstring(conOutPipeName)); - m_outSocket = new QLocalSocket(); m_outSocket->connectToServer(m_conOutName, QIODevice::ReadOnly); m_outSocket->waitForConnected(); @@ -214,7 +215,8 @@ bool WinPtyProcess::kill() winpty_free(m_ptyHandler); exitCode = CloseHandle(m_innerHandle); - UnregisterWait(m_shellCloseWaitHandle); + delete m_shellCloseWaitNotifier; + m_shellCloseWaitNotifier = nullptr; m_ptyHandler = nullptr; m_innerHandle = nullptr; diff --git a/src/libs/3rdparty/libptyqt/winptyprocess.h b/src/libs/3rdparty/libptyqt/winptyprocess.h index 547bcf7c97a..0bfb27c02c4 100644 --- a/src/libs/3rdparty/libptyqt/winptyprocess.h +++ b/src/libs/3rdparty/libptyqt/winptyprocess.h @@ -4,7 +4,8 @@ #include "iptyprocess.h" #include "winpty.h" -#include +class QLocalSocket; +class QWinEventNotifier; class WinPtyProcess : public IPtyProcess { @@ -36,7 +37,7 @@ private: QLocalSocket *m_inSocket; QLocalSocket *m_outSocket; bool m_aboutToDestruct{false}; - HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE}; + QWinEventNotifier* m_shellCloseWaitNotifier; }; #endif // WINPTYPROCESS_H From 18364db94a336087d1160980ce9efdb51bc4edbb Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 2 Mar 2023 09:20:51 +0100 Subject: [PATCH 0123/1447] Editor: ensure block is layouted when painting it The painting of an editor assumes the block is layouted properly. This was done implicitly when calculating the block bounding rect previously. With the option to replace the block layout with another document this is not the case anymore, so we need to explicitly make sure that a block was layouted before painting. Change-Id: If6947a3a5c13a03310e0cab0f6fcbd4ff8078b1b Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/texteditor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index db2f0de9c9e..cc37fca79d5 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -4849,6 +4849,7 @@ void TextEditorWidget::paintEvent(QPaintEvent *e) if (blockData.boundingRect.bottom() >= data.eventRect.top() && blockData.boundingRect.top() <= data.eventRect.bottom()) { + data.documentLayout->ensureBlockLayout(data.block); d->setupBlockLayout(data, painter, blockData); blockData.position = data.block.position(); blockData.length = data.block.length(); From fef8bc4bc43029813ca3bfe936130860ecd9defe Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 2 Mar 2023 12:30:19 +0100 Subject: [PATCH 0124/1447] ClangCodeModel: request symbol update in clangd locator filter Change-Id: I60dfb4cfe8af9abf3bd40c2359c4414ac729cd65 Reviewed-by: Eike Ziller --- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 9a6dee28eca..e94e65f1af5 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -221,8 +221,9 @@ public: } private: - void prepareSearch(const QString &) override + void prepareSearch(const QString &entry) override { + DocumentLocatorFilter::prepareSearch(entry); m_content = TextEditor::TextDocument::currentTextDocument()->plainText(); } From 4b93f47565f70860f20ddf6ea49aca0899f6855b Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 1 Mar 2023 13:50:06 +0100 Subject: [PATCH 0125/1447] Utils: Iterate environment via callback Iterators expose the underlying datastructure and get in the way of moving towards "env as stack of changes" Task-number: QTCREATORBUG-28357 Change-Id: I69e3b53e62ed4c9ab394779e97afbc6fd1986838 Reviewed-by: Marcus Tillmanns --- src/libs/utils/environment.cpp | 6 ++++++ src/libs/utils/environment.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 96e7ea17758..6d8785c9d73 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -24,6 +24,12 @@ NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepe return m_dict.diff(other.m_dict, checkAppendPrepend); } +void Environment::forEachEntry(const std::function &callBack) const +{ + for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) + callBack(it.key().name, it.value().first, it.value().second); +} + bool Environment::hasChanges() const { return m_dict.size() != 0; diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index e6bf46b32dd..7d670a4ae79 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -93,6 +93,8 @@ public: const_iterator constEnd() const { return m_dict.constEnd(); } // FIXME: avoid const_iterator constFind(const QString &name) const { return m_dict.constFind(name); } // FIXME: avoid + void forEachEntry(const std::function &callBack) const; + friend bool operator!=(const Environment &first, const Environment &second) { return first.m_dict != second.m_dict; From 81748fa00b2331fd407f87dc1e9162e9990a4a9c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 12:04:56 +0100 Subject: [PATCH 0126/1447] Docker: Avoid explicit environment iteration Task-number: QTCREATORBUG-28357 Change-Id: I0addc68309ab532d5a710916c7d017eccee1f348 Reviewed-by: Marcus Tillmanns --- src/plugins/docker/dockerdevice.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 0d8da3a57db..b0e0c281258 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -468,10 +468,10 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, dockerCmd.addArg("-t"); if (env) { - for (auto it = env->constBegin(); it != env->constEnd(); ++it) { + env->forEachEntry([&](const QString &key, const QString &, bool) { dockerCmd.addArg("-e"); - dockerCmd.addArg(env->key(it) + "=" + env->expandedValueForKey(env->key(it))); - } + dockerCmd.addArg(key + "=" + env->expandedValueForKey(key)); + }); } if (workDir && !workDir->isEmpty()) From 8b09ad889803c764862b58df312a842037f4458e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Mar 2023 14:03:54 +0100 Subject: [PATCH 0127/1447] QtcProcess: Introduce PtyData That's going to be used by PtyProcessImpl. Change-Id: Ifc1a7886ceed73272c9e415414db49452175a334 Reviewed-by: Marcus Tillmanns --- src/libs/utils/processinterface.cpp | 11 ++++++++++ src/libs/utils/processinterface.h | 29 +++++++++++++++++++++++++ src/libs/utils/qtcprocess.cpp | 11 +++++++++- src/libs/utils/qtcprocess.h | 4 ++++ src/plugins/docker/dockerdevice.cpp | 1 + src/plugins/remotelinux/linuxdevice.cpp | 1 + src/plugins/terminal/terminalwidget.cpp | 1 + 7 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/processinterface.cpp b/src/libs/utils/processinterface.cpp index 9e13494cda1..a5e60c97a31 100644 --- a/src/libs/utils/processinterface.cpp +++ b/src/libs/utils/processinterface.cpp @@ -7,6 +7,17 @@ namespace Utils { +namespace Pty { + +void Data::resize(const QSize &size) +{ + m_size = size; + if (m_data->m_handler) + m_data->m_handler(size); +} + +} // namespace Pty + /*! * \brief controlSignalToInt * \param controlSignal diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index d398d8fe139..210df7d268a 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -10,11 +10,39 @@ #include "processenums.h" #include +#include namespace Utils { namespace Internal { class QtcProcessPrivate; } +namespace Pty { + +using ResizeHandler = std::function; + +class QTCREATOR_UTILS_EXPORT SharedData +{ +public: + ResizeHandler m_handler; +}; + +class QTCREATOR_UTILS_EXPORT Data +{ +public: + Data() : m_data(new SharedData) {} + + void setResizeHandler(const ResizeHandler &handler) { m_data->m_handler = handler; } + + QSize size() const { return m_size; } + void resize(const QSize &size); + +private: + QSize m_size{80, 60}; + QSharedPointer m_data; +}; + +} // namespace Pty + class QTCREATOR_UTILS_EXPORT ProcessSetupData { public: @@ -22,6 +50,7 @@ public: ProcessMode m_processMode = ProcessMode::Reader; TerminalMode m_terminalMode = TerminalMode::Off; + Pty::Data m_ptyData; CommandLine m_commandLine; FilePath m_workingDirectory; Environment m_environment; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 096f6445617..42a29366bd9 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -13,7 +13,6 @@ #include "processutils.h" #include "stringutils.h" #include "terminalhooks.h" -#include "terminalprocess_p.h" #include "threadutils.h" #include "utilstr.h" @@ -1026,6 +1025,16 @@ void QtcProcess::setProcessImpl(ProcessImpl processImpl) d->m_setup.m_processImpl = processImpl; } +void QtcProcess::setPtyData(const Pty::Data &data) +{ + d->m_setup.m_ptyData = data; +} + +Pty::Data QtcProcess::ptyData() const +{ + return d->m_setup.m_ptyData; +} + ProcessMode QtcProcess::processMode() const { return d->m_setup.m_processMode; diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 67898ba855a..72181051491 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -21,6 +21,7 @@ class tst_QtcProcess; namespace Utils { namespace Internal { class QtcProcessPrivate; } +namespace Pty { class Data; } class Environment; class DeviceProcessHooks; @@ -76,6 +77,9 @@ public: void setProcessImpl(ProcessImpl processImpl); + void setPtyData(const Pty::Data &data); + Pty::Data ptyData() const; + void setTerminalMode(TerminalMode mode); TerminalMode terminalMode() const; bool usesTerminal() const { return terminalMode() != TerminalMode::Off; } diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index b0e0c281258..9c6bf8c9bd8 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -284,6 +284,7 @@ void DockerProcessImpl::start() m_process.setProcessImpl(m_setup.m_processImpl); m_process.setProcessMode(m_setup.m_processMode); m_process.setTerminalMode(m_setup.m_terminalMode); + m_process.setPtyData(m_setup.m_ptyData); m_process.setReaperTimeout(m_setup.m_reaperTimeout); m_process.setWriteData(m_setup.m_writeData); m_process.setProcessChannelMode(m_setup.m_processChannelMode); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 781147a1e2e..6d611bf7b83 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -785,6 +785,7 @@ void SshProcessInterfacePrivate::doStart() m_process.setProcessImpl(q->m_setup.m_processImpl); m_process.setProcessMode(q->m_setup.m_processMode); m_process.setTerminalMode(q->m_setup.m_terminalMode); + m_process.setPtyData(q->m_setup.m_ptyData); m_process.setReaperTimeout(q->m_setup.m_reaperTimeout); m_process.setWriteData(q->m_setup.m_writeData); // TODO: what about other fields from m_setup? diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 5f6b8f079b0..94cff232d16 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include From 1da18a4b62c9fcb5d499b098b0e13049f0c34193 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 1 Mar 2023 08:15:58 +0100 Subject: [PATCH 0128/1447] Utils: Integrate ptyqt into qtcprocess Integrating PtyQt directly into QtcProcess allows us to start Pseudo terminal processes using the existing QtcProcess functionality such as starting remote process on e.g. docker or remote linux devices. This is needed for the new Terminal plugin. Change-Id: Iaeed5ff9b341ba4646d955b2ed9577a18cd7100f Reviewed-by: Jarek Kobus Reviewed-by: Cristian Adam --- src/libs/3rdparty/libptyqt/conptyprocess.cpp | 16 +-- src/libs/3rdparty/libptyqt/unixptyprocess.cpp | 4 +- src/libs/3rdparty/libptyqt/winptyprocess.cpp | 1 + src/libs/3rdparty/winpty/src/CMakeLists.txt | 1 - src/libs/utils/CMakeLists.txt | 2 +- src/libs/utils/processenums.h | 1 + src/libs/utils/qtcprocess.cpp | 98 +++++++++++++++++++ src/plugins/docker/dockerdevice.cpp | 6 +- src/plugins/remotelinux/linuxdevice.cpp | 14 ++- src/plugins/terminal/CMakeLists.txt | 2 +- src/plugins/terminal/terminalwidget.cpp | 78 +++++++-------- src/plugins/terminal/terminalwidget.h | 4 +- 12 files changed, 168 insertions(+), 59 deletions(-) diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.cpp b/src/libs/3rdparty/libptyqt/conptyprocess.cpp index d112f5e1533..c788e74c92a 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/conptyprocess.cpp @@ -123,6 +123,7 @@ bool ConPtyProcess::startProcess(const QString &executable, } m_shellPath = executable; + m_shellPath.replace('/', '\\'); m_size = QPair(cols, rows); //env @@ -134,6 +135,7 @@ bool ConPtyProcess::startProcess(const QString &executable, envBlock << L'\0'; std::wstring env = envBlock.str(); LPWSTR envArg = env.empty() ? nullptr : env.data(); + LPCWSTR workingDirPointer = workingDir.isEmpty() ? nullptr : workingDir.toStdWString().c_str(); QStringList exeAndArgs = arguments; exeAndArgs.prepend(m_shellPath); @@ -165,7 +167,7 @@ bool ConPtyProcess::startProcess(const QString &executable, FALSE, // Inherit handles EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // Creation flags envArg, // Environment block - workingDir.toStdWString().c_str(), // Use parent's starting directory + workingDirPointer, // Use parent's starting directory &m_shellStartupInfo.StartupInfo, // Pointer to STARTUPINFO &m_shellProcessInformation) // Pointer to PROCESS_INFORMATION ? S_OK @@ -264,11 +266,13 @@ bool ConPtyProcess::kill() if (INVALID_HANDLE_VALUE != m_hPipeIn) CloseHandle(m_hPipeIn); - m_readThread->requestInterruption(); - if (!m_readThread->wait(1000)) - m_readThread->terminate(); - m_readThread->deleteLater(); - m_readThread = nullptr; + if (m_readThread) { + m_readThread->requestInterruption(); + if (!m_readThread->wait(1000)) + m_readThread->terminate(); + m_readThread->deleteLater(); + m_readThread = nullptr; + } delete m_shellCloseWaitNotifier; m_shellCloseWaitNotifier = nullptr; diff --git a/src/libs/3rdparty/libptyqt/unixptyprocess.cpp b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp index 7cb8237a605..e049a2abb92 100644 --- a/src/libs/3rdparty/libptyqt/unixptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp @@ -182,6 +182,7 @@ bool UnixPtyProcess::startProcess(const QString &shellPath, QObject::connect(&m_shellProcess, &QProcess::finished, &m_shellProcess, [this](int exitCode) { m_exitCode = exitCode; emit m_shellProcess.aboutToClose(); + m_readMasterNotify->disconnect(); }); QStringList defaultVars; @@ -216,7 +217,8 @@ bool UnixPtyProcess::startProcess(const QString &shellPath, m_shellProcess.setProcessEnvironment(envFormat); m_shellProcess.setReadChannel(QProcess::StandardOutput); m_shellProcess.start(m_shellPath, arguments); - m_shellProcess.waitForStarted(); + if (!m_shellProcess.waitForStarted()) + return false; m_pid = m_shellProcess.processId(); diff --git a/src/libs/3rdparty/libptyqt/winptyprocess.cpp b/src/libs/3rdparty/libptyqt/winptyprocess.cpp index be3a0de609e..0509bb77c37 100644 --- a/src/libs/3rdparty/libptyqt/winptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/winptyprocess.cpp @@ -60,6 +60,7 @@ bool WinPtyProcess::startProcess(const QString &executable, } m_shellPath = executable; + m_shellPath.replace('/', '\\'); m_size = QPair(cols, rows); #ifdef PTYQT_DEBUG diff --git a/src/libs/3rdparty/winpty/src/CMakeLists.txt b/src/libs/3rdparty/winpty/src/CMakeLists.txt index 5763955e8d0..22b15111d4f 100644 --- a/src/libs/3rdparty/winpty/src/CMakeLists.txt +++ b/src/libs/3rdparty/winpty/src/CMakeLists.txt @@ -46,7 +46,6 @@ set(shared_sources # add_qtc_executable(winpty-agent - DESTINATION ${IDE_PLUGIN_PATH} INCLUDES include ${CMAKE_BINARY_DIR} DEFINES WINPTY_AGENT_ASSERT diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 04f475afb7c..d6b6efb4f2d 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -257,7 +257,7 @@ extend_qtc_library(Utils CONDITION UNIX AND NOT APPLE extend_qtc_library(Utils CONDITION TARGET Qt::CorePrivate - DEPENDS Qt::CorePrivate + DEPENDS Qt::CorePrivate ptyqt DEFINES QTC_UTILS_WITH_FSENGINE SOURCES fsengine/fsengine_impl.cpp fsengine/fsengine_impl.h diff --git a/src/libs/utils/processenums.h b/src/libs/utils/processenums.h index 6ea37a2d37a..1c16f22dcb4 100644 --- a/src/libs/utils/processenums.h +++ b/src/libs/utils/processenums.h @@ -24,6 +24,7 @@ enum class ProcessImpl { enum class TerminalMode { Off, + Pty, Run, Debug, Suspend, diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 42a29366bd9..4808764ddde 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -16,6 +16,9 @@ #include "threadutils.h" #include "utilstr.h" +#include +#include + #include #include #include @@ -304,6 +307,99 @@ private: QProcess *m_process = nullptr; }; +class PtyProcessImpl final : public DefaultImpl +{ +public: + ~PtyProcessImpl() { m_setup.m_ptyData.setResizeHandler({}); } + + qint64 write(const QByteArray &data) final + { + if (m_ptyProcess) + return m_ptyProcess->write(data); + return -1; + } + + void sendControlSignal(ControlSignal controlSignal) final + { + if (!m_ptyProcess) + return; + + switch (controlSignal) { + case ControlSignal::Terminate: + m_ptyProcess.reset(); + break; + case ControlSignal::Kill: + m_ptyProcess->kill(); + break; + default: + QTC_CHECK(false); + } + } + + void doDefaultStart(const QString &program, const QStringList &arguments) final + { + m_setup.m_ptyData.setResizeHandler([this](const QSize &size) { + if (m_ptyProcess) + m_ptyProcess->resize(size.width(), size.height()); + }); + m_ptyProcess.reset(PtyQt::createPtyProcess(IPtyProcess::AutoPty)); + if (!m_ptyProcess) { + const ProcessResultData result = {-1, + QProcess::CrashExit, + QProcess::FailedToStart, + "Failed to create pty process"}; + emit done(result); + return; + } + + bool startResult + = m_ptyProcess->startProcess(program, + arguments, + m_setup.m_workingDirectory.path(), + m_setup.m_environment.toProcessEnvironment().toStringList(), + m_setup.m_ptyData.size().width(), + m_setup.m_ptyData.size().height()); + + if (!startResult) { + const ProcessResultData result = {-1, + QProcess::CrashExit, + QProcess::FailedToStart, + "Failed to start pty process: " + + m_ptyProcess->lastError()}; + emit done(result); + return; + } + + if (!m_ptyProcess->lastError().isEmpty()) { + const ProcessResultData result + = {-1, QProcess::CrashExit, QProcess::FailedToStart, m_ptyProcess->lastError()}; + emit done(result); + return; + } + + connect(m_ptyProcess->notifier(), &QIODevice::readyRead, this, [this] { + emit readyRead(m_ptyProcess->readAll(), {}); + }); + + connect(m_ptyProcess->notifier(), &QIODevice::aboutToClose, this, [this] { + if (m_ptyProcess) { + const ProcessResultData result + = {m_ptyProcess->exitCode(), QProcess::NormalExit, QProcess::UnknownError, {}}; + emit done(result); + return; + } + + const ProcessResultData result = {0, QProcess::NormalExit, QProcess::UnknownError, {}}; + emit done(result); + }); + + emit started(m_ptyProcess->pid()); + } + +private: + std::unique_ptr m_ptyProcess; +}; + class QProcessImpl final : public DefaultImpl { public: @@ -629,6 +725,8 @@ public: ProcessInterface *createProcessInterface() { + if (m_setup.m_terminalMode == TerminalMode::Pty) + return new PtyProcessImpl(); if (m_setup.m_terminalMode != TerminalMode::Off) return Terminal::Hooks::instance().createTerminalProcessInterfaceHook()(); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 9c6bf8c9bd8..26569166a7d 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -241,7 +241,7 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva if (!m_hasReceivedFirstOutput) { QByteArray output = m_process.readAllRawStandardOutput(); qsizetype idx = output.indexOf('\n'); - QByteArray firstLine = output.left(idx); + QByteArray firstLine = output.left(idx).trimmed(); QByteArray rest = output.mid(idx + 1); qCDebug(dockerDeviceLog) << "Process first line received:" << m_process.commandLine() << firstLine; @@ -301,7 +301,9 @@ void DockerProcessImpl::start() = m_devicePrivate->withDockerExecCmd(m_setup.m_commandLine, m_setup.m_environment, m_setup.m_workingDirectory, - interactive); + interactive, + true, + m_setup.m_terminalMode == TerminalMode::Pty); m_process.setCommand(fullCommandLine); m_process.start(); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 6d611bf7b83..754a7f0281e 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -656,9 +656,15 @@ void LinuxProcessInterface::handleReadyReadStandardOutput(const QByteArray &outp m_output.append(outputData); static const QByteArray endMarker = s_pidMarker + '\n'; - const int endMarkerOffset = m_output.indexOf(endMarker); - if (endMarkerOffset == -1) - return; + int endMarkerLength = endMarker.length(); + int endMarkerOffset = m_output.indexOf(endMarker); + if (endMarkerOffset == -1) { + static const QByteArray endMarker = s_pidMarker + "\r\n"; + endMarkerOffset = m_output.indexOf(endMarker); + endMarkerLength = endMarker.length(); + if (endMarkerOffset == -1) + return; + } const int startMarkerOffset = m_output.indexOf(s_pidMarker); if (startMarkerOffset == endMarkerOffset) // Only theoretically possible. return; @@ -668,7 +674,7 @@ void LinuxProcessInterface::handleReadyReadStandardOutput(const QByteArray &outp const qint64 processId = pidString.toLongLong(); // We don't want to show output from e.g. /etc/profile. - m_output = m_output.mid(endMarkerOffset + endMarker.length()); + m_output = m_output.mid(endMarkerOffset + endMarkerLength); emitStarted(processId); diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index a970b467e19..fafe3e7346e 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -1,7 +1,7 @@ add_qtc_plugin(Terminal PLUGIN_DEPENDS Core - DEPENDS libvterm ptyqt + DEPENDS libvterm SOURCES celllayout.cpp celllayout.h terminal.qrc diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 94cff232d16..572bc74f9e0 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -15,11 +15,11 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -69,7 +69,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op m_readDelayTimer.setSingleShot(true); m_readDelayTimer.setInterval(10); - connect(&m_readDelayTimer, &QTimer::timeout, this, [this]() { + connect(&m_readDelayTimer, &QTimer::timeout, this, [this] { m_readDelayRestarts = 0; onReadyRead(); }); @@ -80,7 +80,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op connect(&m_zoomInAction, &QAction::triggered, this, &TerminalWidget::zoomIn); connect(&m_zoomOutAction, &QAction::triggered, this, &TerminalWidget::zoomOut); - connect(&TerminalSettings::instance(), &AspectContainer::applied, this, [this]() { + connect(&TerminalSettings::instance(), &AspectContainer::applied, this, [this] { m_layoutVersion++; // Setup colors first, as setupFont will redraw the screen. setupColors(); @@ -90,7 +90,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op void TerminalWidget::setupPty() { - m_ptyProcess.reset(PtyQt::createPtyProcess(IPtyProcess::PtyType::AutoPty)); + m_process = std::make_unique(); Environment env = m_openParameters.environment.value_or(Environment::systemEnvironment()); @@ -99,29 +99,17 @@ void TerminalWidget::setupPty() // For git bash on Windows env.prependOrSetPath(shellCommand.executable().parentDir()); + if (env.hasKey("CLINK_NOAUTORUN")) + env.unset("CLINK_NOAUTORUN"); - QStringList envList = filtered(env.toStringList(), [](const QString &envPair) { - return envPair != "CLINK_NOAUTORUN=1"; - }); + m_process->setProcessMode(ProcessMode::Writer); + m_process->setTerminalMode(TerminalMode::Pty); + m_process->setCommand(shellCommand); + m_process->setWorkingDirectory( + m_openParameters.workingDirectory.value_or(FilePath::fromString(QDir::homePath()))); + m_process->setEnvironment(env); - m_ptyProcess->startProcess(shellCommand.executable().nativePath(), - shellCommand.splitArguments(), - m_openParameters.workingDirectory - .value_or(FilePath::fromString(QDir::homePath())) - .nativePath(), - envList, - m_vtermSize.width(), - m_vtermSize.height()); - - emit started(m_ptyProcess->pid()); - - if (!m_ptyProcess->lastError().isEmpty()) { - qCWarning(terminalLog) << m_ptyProcess->lastError(); - m_ptyProcess.reset(); - return; - } - - connect(m_ptyProcess->notifier(), &QIODevice::readyRead, this, [this]() { + connect(m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this] { if (m_readDelayTimer.isActive()) m_readDelayRestarts++; @@ -131,16 +119,19 @@ void TerminalWidget::setupPty() m_readDelayTimer.start(); }); - connect(m_ptyProcess->notifier(), &QIODevice::aboutToClose, this, [this]() { + connect(m_process.get(), &QtcProcess::done, this, [this] { m_cursor.visible = false; - if (m_ptyProcess) { + if (m_process) { onReadyRead(); - if (m_ptyProcess->exitCode() != 0) { + if (m_process->exitCode() != 0) { QByteArray msg = QString("\r\n\033[31mProcess exited with code: %1") - .arg(m_ptyProcess->exitCode()) + .arg(m_process->exitCode()) .toUtf8(); + if (!m_process->errorString().isEmpty()) + msg += QString(" (%1)").arg(m_process->errorString()).toUtf8(); + vterm_input_write(m_vterm.get(), msg.constData(), msg.size()); vterm_screen_flush_damage(m_vtermScreen); @@ -149,10 +140,8 @@ void TerminalWidget::setupPty() } if (m_openParameters.m_exitBehavior == ExitBehavior::Restart) { - QMetaObject::invokeMethod( - this, - [this]() { - m_ptyProcess.reset(); + QMetaObject::invokeMethod(this, [this] { + m_process.reset(); setupPty(); }, Qt::QueuedConnection); @@ -163,13 +152,20 @@ void TerminalWidget::setupPty() if (m_openParameters.m_exitBehavior == ExitBehavior::Keep) { QByteArray msg = QString("\r\nProcess exited with code: %1") - .arg(m_ptyProcess ? m_ptyProcess->exitCode() : -1) + .arg(m_process ? m_process->exitCode() : -1) .toUtf8(); vterm_input_write(m_vterm.get(), msg.constData(), msg.size()); vterm_screen_flush_damage(m_vtermScreen); } }); + + connect(m_process.get(), &QtcProcess::started, this, [this] { + applySizeChange(); + emit started(m_process->processId()); + }); + + m_process->start(); } void TerminalWidget::setupFont() @@ -229,8 +225,8 @@ void TerminalWidget::setupColors() void TerminalWidget::writeToPty(const QByteArray &data) { - if (m_ptyProcess) - m_ptyProcess->write(data); + if (m_process) + m_process->writeRaw(data); } void TerminalWidget::setupVTerm() @@ -305,7 +301,7 @@ void TerminalWidget::setFont(const QFont &font) QAbstractScrollArea::setFont(m_font); - if (m_ptyProcess) { + if (m_process) { applySizeChange(); } } @@ -425,7 +421,7 @@ void TerminalWidget::clearContents() void TerminalWidget::onReadyRead() { - QByteArray data = m_ptyProcess->readAll(); + QByteArray data = m_process->readAllRawStandardOutput(); vterm_input_write(m_vterm.get(), data.constData(), data.size()); vterm_screen_flush_damage(m_vtermScreen); } @@ -709,8 +705,8 @@ void TerminalWidget::applySizeChange() if (m_vtermSize.width() <= 0) m_vtermSize.setWidth(1); - if (m_ptyProcess) - m_ptyProcess->resize(m_vtermSize.width(), m_vtermSize.height()); + if (m_process) + m_process->ptyData().resize(m_vtermSize); vterm_set_size(m_vterm.get(), m_vtermSize.height(), m_vtermSize.width()); vterm_screen_flush_damage(m_vtermScreen); @@ -869,7 +865,7 @@ void TerminalWidget::showEvent(QShowEvent *event) { Q_UNUSED(event); - if (!m_ptyProcess) + if (!m_process) setupPty(); QAbstractScrollArea::showEvent(event); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 3f1590dfaaf..96e24f41172 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -5,6 +5,7 @@ #include "scrollback.h" +#include #include #include @@ -12,7 +13,6 @@ #include #include -#include #include #include @@ -111,7 +111,7 @@ protected: void updateScrollBars(); private: - std::unique_ptr m_ptyProcess; + std::unique_ptr m_process; std::unique_ptr m_vterm; VTermScreen *m_vtermScreen; From 517400e7f6fc345ab69daf6f49b7068752452d8e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 2 Mar 2023 13:12:56 +0100 Subject: [PATCH 0129/1447] Copilot: do not activate the editor when requesting completions This has unwanted side effects like closing the completion and switching the current editor. Change-Id: Ic0e150f2377a731910e409b9edc959fda670cd99 Reviewed-by: Marcus Tillmanns Reviewed-by: hjk --- src/plugins/copilot/documentwatcher.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/copilot/documentwatcher.cpp b/src/plugins/copilot/documentwatcher.cpp index a11ff8bbec3..69b201b5216 100644 --- a/src/plugins/copilot/documentwatcher.cpp +++ b/src/plugins/copilot/documentwatcher.cpp @@ -37,12 +37,13 @@ DocumentWatcher::DocumentWatcher(CopilotClient *client, TextDocument *textDocume void DocumentWatcher::getSuggestion() { - Core::IEditor *editor = Core::EditorManager::instance()->activateEditorForDocument( - m_textDocument); - if (!editor) - return; - TextEditor::TextEditorWidget *textEditorWidget = qobject_cast( - editor->widget()); + TextEditorWidget *textEditorWidget = nullptr; + for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(m_textDocument)) { + textEditorWidget = qobject_cast(editor->widget()); + if (textEditorWidget) + break; + } + if (!textEditorWidget) return; @@ -50,12 +51,12 @@ void DocumentWatcher::getSuggestion() if (cursor.hasMultipleCursors() || cursor.hasSelection()) return; - const int currentCursorPos = cursor.cursors().first().position(); + const int currentCursorPos = cursor.mainCursor().position(); m_client->requestCompletion( m_textDocument->filePath(), m_client->documentVersion(m_textDocument->filePath()), - Position(editor->currentLine() - 1, editor->currentColumn() - 1), + Position(cursor.mainCursor()), [this, textEditorWidget, currentCursorPos](const GetCompletionRequest::Response &response) { if (response.error()) { qDebug() << "ERROR:" << *response.error(); From 86da87d3062adea1a1eb64426750978d19043492 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 1 Mar 2023 09:57:43 +0100 Subject: [PATCH 0130/1447] ProjectExplorer: Remove IDevice::terminalCommand Since Terminals can now be started for device file paths, there is no need anymore for IDevice::terminalCommand. Change-Id: I01c831ea7ee29d53efa6880631e8c6d54a4316aa Reviewed-by: Cristian Adam --- src/libs/utils/terminalhooks.cpp | 18 +++++++++++ src/libs/utils/terminalhooks.h | 2 ++ src/plugins/docker/dockerdevice.cpp | 13 -------- src/plugins/docker/dockerdevice.h | 3 -- .../devicesupport/devicemanager.cpp | 9 ++++-- .../projectexplorer/devicesupport/idevice.cpp | 8 ----- .../projectexplorer/devicesupport/idevice.h | 3 -- .../projectexplorer/projectexplorer.cpp | 31 ++++++++++++++----- src/plugins/terminal/shellmodel.cpp | 9 +++--- src/plugins/terminal/terminalwidget.cpp | 6 ++-- 10 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index df27e0404b9..f4a5944dbdc 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -8,6 +8,24 @@ namespace Utils::Terminal { +FilePath defaultShellForDevice(const FilePath &deviceRoot) +{ + if (!deviceRoot.needsDevice()) + return {}; + + // TODO: Windows ? + const Environment env = deviceRoot.deviceEnvironment(); + FilePath shell = FilePath::fromUserInput(env.value_or("SHELL", "/bin/sh")); + + if (!shell.isAbsolutePath()) + shell = env.searchInPath(shell.nativePath()); + + if (shell.isEmpty()) + return shell; + + return shell.onDevice(deviceRoot); +} + struct HooksPrivate { HooksPrivate() diff --git a/src/libs/utils/terminalhooks.h b/src/libs/utils/terminalhooks.h index 492c53da81f..3f3d8485810 100644 --- a/src/libs/utils/terminalhooks.h +++ b/src/libs/utils/terminalhooks.h @@ -54,6 +54,8 @@ struct NameAndCommandLine CommandLine commandLine; }; +QTCREATOR_UTILS_EXPORT FilePath defaultShellForDevice(const FilePath &deviceRoot); + class QTCREATOR_UTILS_EXPORT Hooks { public: diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 26569166a7d..97a4dba0da8 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -1240,17 +1240,4 @@ std::optional DockerDevice::clangdExecutable() const return d->clangdExecutable(); } -std::optional DockerDevice::terminalCommand(const FilePath &workDir, - const Environment &env) const -{ - Q_UNUSED(env) - const QString shell = d->environment().value_or("SHELL", "/bin/sh"); - return d->withDockerExecCmd({FilePath::fromUserInput(shell), {}}, - std::nullopt, - workDir, - true, - false, - true); -} - } // namespace Docker::Internal diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 0a1a77f947b..3ecc0118d49 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -101,9 +101,6 @@ public: bool prepareForBuild(const ProjectExplorer::Target *target) override; std::optional clangdExecutable() const override; - std::optional terminalCommand(const Utils::FilePath &workDir, - const Utils::Environment &env) const override; - protected: void fromMap(const QVariantMap &map) final; QVariantMap toMap() const final; diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index c254afcd7e7..53e1e5c4d73 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -465,9 +465,12 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_uniquedevices) { if (device->type() == Constants::DESKTOP_DEVICE_TYPE) continue; - const std::optional terminalCommand = device->terminalCommand({}, {}); - if (terminalCommand) - result << Terminal::NameAndCommandLine{device->displayName(), *terminalCommand}; + + const FilePath shell = Terminal::defaultShellForDevice(device->rootPath()); + + if (!shell.isEmpty()) + result << Terminal::NameAndCommandLine{device->displayName(), + CommandLine{shell, {}}}; } return result; }); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index c615a89badc..ab3a44f0d84 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -181,14 +181,6 @@ void IDevice::openTerminal(const Environment &env, const FilePath &workingDir) c d->openTerminal(env, workingDir); } -std::optional IDevice::terminalCommand(const FilePath &workDir, const Environment &env) const -{ - Q_UNUSED(workDir); - Q_UNUSED(env); - - return std::nullopt; -} - bool IDevice::isEmptyCommandAllowed() const { return d->emptyCommandAllowed; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index c4759a7d327..6323b8589bb 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -193,9 +193,6 @@ public: bool canOpenTerminal() const; void openTerminal(const Utils::Environment &env, const Utils::FilePath &workingDir) const; - virtual std::optional terminalCommand(const Utils::FilePath &workDir, - const Utils::Environment &env) const; - bool isEmptyCommandAllowed() const; void setAllowEmptyCommand(bool allow); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 8842b1f1cab..3834593a63e 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3825,11 +3825,18 @@ void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env return; FilePath workingDir = currentNode->directory(); - if (!buildDevice->ensureReachable(workingDir)) + if (!buildDevice->filePath(workingDir.path()).exists() + && !buildDevice->ensureReachable(workingDir)) workingDir.clear(); - const auto cmd = buildDevice->terminalCommand(workingDir, *environment); - Terminal::Hooks::instance().openTerminalHook()({cmd, workingDir, environment}); + const FilePath shell = Terminal::defaultShellForDevice(buildDevice->rootPath()); + + if (!shell.isEmpty() && buildDevice->rootPath().needsDevice()) { + Terminal::Hooks::instance().openTerminalHook()( + {CommandLine{shell, {}}, workingDir, environment}); + } else { + Terminal::Hooks::instance().openTerminalHook()({std::nullopt, workingDir, environment}); + } } void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() @@ -3851,11 +3858,21 @@ void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() device = DeviceKitAspect::device(target->kit()); QTC_ASSERT(device && device->canOpenTerminal(), return); - const FilePath workingDir = device->type() == Constants::DESKTOP_DEVICE_TYPE - ? currentNode->directory() : runnable.workingDirectory; + FilePath workingDir = device->type() == Constants::DESKTOP_DEVICE_TYPE + ? currentNode->directory() + : runnable.workingDirectory; - const auto cmd = device->terminalCommand(workingDir, runnable.environment); - Terminal::Hooks::instance().openTerminalHook()({cmd, workingDir, runnable.environment}); + if (!device->filePath(workingDir.path()).exists() && !device->ensureReachable(workingDir)) + workingDir.clear(); + + const FilePath shell = Terminal::defaultShellForDevice(device->rootPath()); + if (!shell.isEmpty() && device->rootPath().needsDevice()) { + Terminal::Hooks::instance().openTerminalHook()( + {CommandLine{shell, {}}, workingDir, runnable.environment}); + } else { + Terminal::Hooks::instance().openTerminalHook()( + {std::nullopt, workingDir, runnable.environment}); + } } void ProjectExplorerPluginPrivate::removeFile() diff --git a/src/plugins/terminal/shellmodel.cpp b/src/plugins/terminal/shellmodel.cpp index cd901fbb6e8..b4cf53a1e99 100644 --- a/src/plugins/terminal/shellmodel.cpp +++ b/src/plugins/terminal/shellmodel.cpp @@ -99,11 +99,10 @@ QList ShellModel::remote() const { const auto deviceCmds = Utils::Terminal::Hooks::instance().getTerminalCommandsForDevicesHook()(); - const QList deviceItems - = Utils::transform(deviceCmds, - [](const Utils::Terminal::NameAndCommandLine &item) -> ShellModelItem { - return ShellModelItem{item.name, {}, {item.commandLine, {}, {}}}; - }); + const QList deviceItems = Utils::transform( + deviceCmds, [](const Utils::Terminal::NameAndCommandLine &item) -> ShellModelItem { + return ShellModelItem{item.name, {}, {item.commandLine, std::nullopt, std::nullopt}}; + }); return deviceItems; } diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 572bc74f9e0..1cc965b0b8b 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -105,8 +105,8 @@ void TerminalWidget::setupPty() m_process->setProcessMode(ProcessMode::Writer); m_process->setTerminalMode(TerminalMode::Pty); m_process->setCommand(shellCommand); - m_process->setWorkingDirectory( - m_openParameters.workingDirectory.value_or(FilePath::fromString(QDir::homePath()))); + if (m_openParameters.workingDirectory.has_value()) + m_process->setWorkingDirectory(*m_openParameters.workingDirectory); m_process->setEnvironment(env); connect(m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this] { @@ -122,8 +122,6 @@ void TerminalWidget::setupPty() connect(m_process.get(), &QtcProcess::done, this, [this] { m_cursor.visible = false; if (m_process) { - onReadyRead(); - if (m_process->exitCode() != 0) { QByteArray msg = QString("\r\n\033[31mProcess exited with code: %1") .arg(m_process->exitCode()) From 46ccaa642f5dbe6035ea071c5b6ccece498ec3a5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 1 Mar 2023 10:48:05 +0100 Subject: [PATCH 0131/1447] Terminal: Improve performance for cat /dev/random Change-Id: Ibc7e09dd9388fd6f06f0bed3ade4e83d05f03c28 Reviewed-by: Cristian Adam --- src/plugins/terminal/scrollback.cpp | 4 +- src/plugins/terminal/scrollback.h | 2 +- src/plugins/terminal/terminalwidget.cpp | 51 ++++++++++++++++--------- src/plugins/terminal/terminalwidget.h | 9 +++-- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/plugins/terminal/scrollback.cpp b/src/plugins/terminal/scrollback.cpp index 8a07c700f8d..f3bb6319734 100644 --- a/src/plugins/terminal/scrollback.cpp +++ b/src/plugins/terminal/scrollback.cpp @@ -20,7 +20,6 @@ Scrollback::Line::Line(int cols, const VTermScreenCell *cells, VTermState *vts) vterm_state_convert_color_to_rgb(vts, &m_cells[i].fg); vterm_state_convert_color_to_rgb(vts, &m_cells[i].bg); } - m_layout = std::make_unique(); } const VTermScreenCell *Scrollback::Line::cell(int i) const @@ -31,6 +30,9 @@ const VTermScreenCell *Scrollback::Line::cell(int i) const const QTextLayout &Scrollback::Line::layout(int version, const QFont &font, qreal lineSpacing) const { + if (!m_layout) + m_layout = std::make_unique(); + if (m_layoutVersion != version) { QString text; VTermColor defaultBg; diff --git a/src/plugins/terminal/scrollback.h b/src/plugins/terminal/scrollback.h index 63c18772b93..33799bdcd43 100644 --- a/src/plugins/terminal/scrollback.h +++ b/src/plugins/terminal/scrollback.h @@ -33,7 +33,7 @@ public: private: int m_cols; std::unique_ptr m_cells; - std::unique_ptr m_layout; + mutable std::unique_ptr m_layout; mutable int m_layoutVersion{-1}; }; diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 1cc965b0b8b..3d197ca31fd 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -29,6 +29,8 @@ #include #include +#include + Q_LOGGING_CATEGORY(terminalLog, "qtc.terminal", QtWarningMsg) using namespace Utils; @@ -36,6 +38,11 @@ using namespace Utils::Terminal; namespace Terminal { +using namespace std::chrono_literals; + +// Minimum time between two refreshes. +static const auto minRefreshInterval = 16ms; + TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &openParameters) : QAbstractScrollArea(parent) , m_vterm(vterm_new(size().height(), size().width()), vterm_free) @@ -47,6 +54,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op , m_zoomInAction(Tr::tr("Zoom In")) , m_zoomOutAction(Tr::tr("Zoom Out")) , m_openParameters(openParameters) + , m_lastFlush(QDateTime::currentDateTime()) { setupVTerm(); setupFont(); @@ -66,13 +74,10 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - m_readDelayTimer.setSingleShot(true); - m_readDelayTimer.setInterval(10); + m_flushDelayTimer.setSingleShot(true); + m_flushDelayTimer.setInterval(minRefreshInterval); - connect(&m_readDelayTimer, &QTimer::timeout, this, [this] { - m_readDelayRestarts = 0; - onReadyRead(); - }); + connect(&m_flushDelayTimer, &QTimer::timeout, this, [this]() { flushVTerm(true); }); connect(&m_copyAction, &QAction::triggered, this, &TerminalWidget::copyToClipboard); connect(&m_pasteAction, &QAction::triggered, this, &TerminalWidget::pasteFromClipboard); @@ -109,14 +114,8 @@ void TerminalWidget::setupPty() m_process->setWorkingDirectory(*m_openParameters.workingDirectory); m_process->setEnvironment(env); - connect(m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this] { - if (m_readDelayTimer.isActive()) - m_readDelayRestarts++; - - if (m_readDelayRestarts > 100) - return; - - m_readDelayTimer.start(); + connect(m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this]() { + onReadyRead(false); }); connect(m_process.get(), &QtcProcess::done, this, [this] { @@ -138,7 +137,9 @@ void TerminalWidget::setupPty() } if (m_openParameters.m_exitBehavior == ExitBehavior::Restart) { - QMetaObject::invokeMethod(this, [this] { + QMetaObject::invokeMethod( + this, + [this] { m_process.reset(); setupPty(); }, @@ -411,17 +412,29 @@ void TerminalWidget::clearContents() // Fake a scrollback clearing QByteArray data{"\x1b[3J"}; vterm_input_write(m_vterm.get(), data.constData(), data.size()); - vterm_screen_flush_damage(m_vtermScreen); // Send Ctrl+L which will clear the screen writeToPty(QByteArray("\f")); } -void TerminalWidget::onReadyRead() +void TerminalWidget::onReadyRead(bool forceFlush) { QByteArray data = m_process->readAllRawStandardOutput(); vterm_input_write(m_vterm.get(), data.constData(), data.size()); - vterm_screen_flush_damage(m_vtermScreen); + + flushVTerm(forceFlush); +} + +void TerminalWidget::flushVTerm(bool force) +{ + if (force || QDateTime::currentDateTime() - m_lastFlush > minRefreshInterval) { + m_lastFlush = QDateTime::currentDateTime(); + vterm_screen_flush_damage(m_vtermScreen); + return; + } + + if (!m_flushDelayTimer.isActive()) + m_flushDelayTimer.start(); } const VTermScreenCell *TerminalWidget::fetchCell(int x, int y) const @@ -707,7 +720,7 @@ void TerminalWidget::applySizeChange() m_process->ptyData().resize(m_vtermSize); vterm_set_size(m_vterm.get(), m_vtermSize.height(), m_vtermSize.width()); - vterm_screen_flush_damage(m_vtermScreen); + flushVTerm(true); } void TerminalWidget::updateScrollBars() diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 96e24f41172..ec0b0f80d85 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -76,7 +76,7 @@ protected: bool event(QEvent *event) override; protected: - void onReadyRead(); + void onReadyRead(bool forceFlush); void setupVTerm(); void setupFont(); void setupPty(); @@ -110,6 +110,8 @@ protected: void updateScrollBars(); + void flushVTerm(bool force); + private: std::unique_ptr m_process; @@ -151,14 +153,15 @@ private: QAction m_zoomInAction; QAction m_zoomOutAction; - QTimer m_readDelayTimer; - int m_readDelayRestarts{0}; + QTimer m_flushDelayTimer; int m_layoutVersion{0}; std::array m_currentColors; Utils::Terminal::OpenTerminalParameters m_openParameters; + + QDateTime m_lastFlush; }; } // namespace Terminal From 76b55fd6e615288310563df129ca31e25eeac17e Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 1 Mar 2023 16:03:18 +0100 Subject: [PATCH 0132/1447] Terminal: Implement selection via double click Change-Id: I7665df5f37836331f202f168828bb1b1636bf5de Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/celllayout.cpp | 46 ++++++++++++---- src/plugins/terminal/celllayout.h | 4 +- src/plugins/terminal/scrollback.cpp | 18 +++++-- src/plugins/terminal/scrollback.h | 4 ++ src/plugins/terminal/terminalwidget.cpp | 72 +++++++++++++++++++++---- src/plugins/terminal/terminalwidget.h | 4 ++ 6 files changed, 122 insertions(+), 26 deletions(-) diff --git a/src/plugins/terminal/celllayout.cpp b/src/plugins/terminal/celllayout.cpp index f9034dccce6..45b7ca07835 100644 --- a/src/plugins/terminal/celllayout.cpp +++ b/src/plugins/terminal/celllayout.cpp @@ -12,8 +12,27 @@ QColor toQColor(const VTermColor &c) return QColor(qRgb(c.rgb.red, c.rgb.green, c.rgb.blue)); }; +std::u32string cellToString(const VTermScreenCell &cell) +{ + if (cell.chars[0] != 0xFFFFFFFF) { + QString ch = QString::fromUcs4(cell.chars); + if (ch.size() > 1) + ch = ch.normalized(QString::NormalizationForm_C); + QList asUcs4 = ch.toUcs4(); + + std::u32string chUcs = std::u32string(asUcs4.begin(), asUcs4.end()); + if (chUcs.size() > 0) { + if (chUcs[0] == 0) + chUcs[0] = 0x00a0; + + return chUcs; + } + } + return std::u32string(1, (char32_t) 0x00a0); +} + void createTextLayout(QTextLayout &textLayout, - QString &resultText, + std::u32string *resultText, VTermColor defaultBg, QRect cellRect, qreal lineSpacing, @@ -26,22 +45,24 @@ void createTextLayout(QTextLayout &textLayout, currentFormat.setForeground(QColor(0xff, 0xff, 0xff)); currentFormat.clearBackground(); - resultText.clear(); + QString layoutText; + if (resultText) + resultText->clear(); for (int y = cellRect.y(); y < cellRect.bottom() + 1; y++) { QTextCharFormat format; - const auto setNewFormat = [&formats, ¤tFormatStart, &resultText, ¤tFormat]( + const auto setNewFormat = [&formats, ¤tFormatStart, &layoutText, ¤tFormat]( const QTextCharFormat &format) { - if (resultText.size() != currentFormatStart) { + if (layoutText.size() != currentFormatStart) { QTextLayout::FormatRange fr; fr.start = currentFormatStart; - fr.length = resultText.size() - currentFormatStart; + fr.length = layoutText.size() - currentFormatStart; fr.format = currentFormat; formats.append(fr); currentFormat = format; - currentFormatStart = resultText.size(); + currentFormatStart = layoutText.size(); } else { currentFormat = format; } @@ -81,24 +102,27 @@ void createTextLayout(QTextLayout &textLayout, if (cell->chars[0] != 0xFFFFFFFF) { QString ch = QString::fromUcs4(cell->chars); if (ch.size() > 0) { - resultText += ch; + layoutText += ch; } else { - resultText += QChar::Nbsp; + layoutText += QChar::Nbsp; } } + + if (resultText) + *resultText += cellToString(*cell); } // for x setNewFormat(format); if (y != cellRect.bottom()) - resultText.append(QChar::LineSeparator); + layoutText.append(QChar::LineSeparator); } // for y QTextLayout::FormatRange fr; fr.start = currentFormatStart; - fr.length = (resultText.size() - 1) - currentFormatStart; + fr.length = (layoutText.size() - 1) - currentFormatStart; fr.format = currentFormat; formats.append(fr); - textLayout.setText(resultText); + textLayout.setText(layoutText); textLayout.setFormats(formats); qreal height = 0; diff --git a/src/plugins/terminal/celllayout.h b/src/plugins/terminal/celllayout.h index 286ed8944fb..c86adef5fcc 100644 --- a/src/plugins/terminal/celllayout.h +++ b/src/plugins/terminal/celllayout.h @@ -18,10 +18,12 @@ namespace Terminal::Internal { QColor toQColor(const VTermColor &c); void createTextLayout(QTextLayout &textLayout, - QString &resultText, + std::u32string *resultText, VTermColor defaultBg, QRect cellRect, qreal lineSpacing, std::function fetchCell); +std::u32string cellToString(const VTermScreenCell &cell); + } // namespace Terminal::Internal diff --git a/src/plugins/terminal/scrollback.cpp b/src/plugins/terminal/scrollback.cpp index f3bb6319734..c3be95f706c 100644 --- a/src/plugins/terminal/scrollback.cpp +++ b/src/plugins/terminal/scrollback.cpp @@ -34,13 +34,12 @@ const QTextLayout &Scrollback::Line::layout(int version, const QFont &font, qrea m_layout = std::make_unique(); if (m_layoutVersion != version) { - QString text; VTermColor defaultBg; defaultBg.type = VTERM_COLOR_DEFAULT_BG; m_layout->clearLayout(); m_layout->setFont(font); createTextLayout(*m_layout, - text, + nullptr, defaultBg, QRect(0, 0, m_cols, 1), lineSpacing, @@ -57,8 +56,14 @@ Scrollback::Scrollback(size_t capacity) void Scrollback::emplace(int cols, const VTermScreenCell *cells, VTermState *vts) { m_deque.emplace_front(cols, cells, vts); - while (m_deque.size() > m_capacity) + while (m_deque.size() > m_capacity) { + m_currentText = m_currentText.substr(m_deque.back().cols()); m_deque.pop_back(); + } + + for (int i = 0; i < cols; i++) { + m_currentText += cellToString(cells[i]); + } } void Scrollback::popto(int cols, VTermScreenCell *cells) @@ -77,6 +82,7 @@ void Scrollback::popto(int cols, VTermScreenCell *cells) } m_deque.pop_front(); + m_currentText.resize(m_currentText.size() - cols); } size_t Scrollback::scroll(int delta) @@ -90,6 +96,12 @@ void Scrollback::clear() { m_offset = 0; m_deque.clear(); + m_currentText.clear(); +} + +std::u32string Scrollback::currentText() +{ + return m_currentText; } } // namespace Terminal::Internal diff --git a/src/plugins/terminal/scrollback.h b/src/plugins/terminal/scrollback.h index 33799bdcd43..22abc07b73f 100644 --- a/src/plugins/terminal/scrollback.h +++ b/src/plugins/terminal/scrollback.h @@ -57,10 +57,14 @@ public: void clear(); + std::u32string currentText(); + private: size_t m_capacity; size_t m_offset{0}; std::deque m_deque; + + std::u32string m_currentText; }; } // namespace Terminal::Internal diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 3d197ca31fd..5639f0d16aa 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -40,8 +40,8 @@ namespace Terminal { using namespace std::chrono_literals; -// Minimum time between two refreshes. -static const auto minRefreshInterval = 16ms; +// Minimum time between two refreshes. (30fps) +static const auto minRefreshInterval = 1s / 30; TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &openParameters) : QAbstractScrollArea(parent) @@ -55,6 +55,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op , m_zoomOutAction(Tr::tr("Zoom Out")) , m_openParameters(openParameters) , m_lastFlush(QDateTime::currentDateTime()) + , m_lastDoubleClick(QDateTime::currentDateTime()) { setupVTerm(); setupFont(); @@ -479,10 +480,8 @@ void TerminalWidget::createTextLayout() m_textLayout.clearLayout(); - QString allText; - Internal::createTextLayout(m_textLayout, - allText, + &m_currentLiveText, defaultBg, QRect({0, 0}, m_vtermSize), m_lineSpacing, @@ -812,11 +811,19 @@ void TerminalWidget::inputMethodEvent(QInputMethodEvent *event) void TerminalWidget::mousePressEvent(QMouseEvent *event) { - if (event->button() == Qt::LeftButton) { - m_selectionStartPos = event->pos(); + m_selectionStartPos = event->pos(); + + if (event->button() == Qt::LeftButton) { + if (QDateTime::currentDateTime() - m_lastDoubleClick < 500ms) { + m_selectLineMode = true; + m_selection->start.setX(0); + m_selection->end.setX(viewport()->width()); + } else { + m_selectLineMode = false; + QPoint pos = viewportToGlobal(event->pos()); + m_selection = Selection{pos, pos}; + } - QPoint pos = viewportToGlobal(event->pos()); - m_selection = Selection{pos, pos}; viewport()->update(); } } @@ -829,6 +836,11 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) if (start.y() > newEnd.y() || (start.y() == newEnd.y() && start.x() > newEnd.x())) std::swap(start, newEnd); + if (m_selectLineMode) { + start.setX(0); + newEnd.setX(viewport()->width()); + } + m_selection->start = start; m_selection->end = newEnd; @@ -848,9 +860,47 @@ void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) { - // TODO :( - Q_UNUSED(event); + std::u32string text = m_scrollback->currentText() + m_currentLiveText; + + const QPoint clickPos = viewportToGlobal(event->pos()); + + const QPoint clickPosInGrid = QPoint(clickPos.x() / m_cellSize.width(), + clickPos.y() / m_cellSize.height()); + + std::u32string::size_type chIdx = (clickPosInGrid.x()) + + (clickPosInGrid.y()) * m_vtermSize.width(); + + if (chIdx >= text.length() || chIdx < 0) + return; + + std::u32string whiteSpaces = U" \t\x00a0"; + + const bool inverted = whiteSpaces.find(text[chIdx]) != std::u32string::npos; + + const std::u32string::size_type leftEnd = inverted + ? text.find_last_not_of(whiteSpaces, chIdx) + 1 + : text.find_last_of(whiteSpaces, chIdx) + 1; + std::u32string::size_type rightEnd = inverted ? text.find_first_not_of(whiteSpaces, chIdx) + : text.find_first_of(whiteSpaces, chIdx); + if (rightEnd == std::u32string::npos) + rightEnd = text.length(); + + const auto found = text.substr(leftEnd, rightEnd - leftEnd); + + const QPoint selectionStart((leftEnd % m_vtermSize.width()) * m_cellSize.width() + + (m_cellSize.width() / 4), + (leftEnd / m_vtermSize.width()) * m_cellSize.height() + + (m_cellSize.height() / 4)); + const QPoint selectionEnd((rightEnd % m_vtermSize.width()) * m_cellSize.width(), + (rightEnd / m_vtermSize.width()) * m_cellSize.height() + + m_cellSize.height()); + + m_selection = Selection{selectionStart, selectionEnd}; + + m_lastDoubleClick = QDateTime::currentDateTime(); + viewport()->update(); + event->accept(); } void TerminalWidget::scrollContentsBy(int dx, int dy) diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index ec0b0f80d85..8f09b833b69 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -162,6 +162,10 @@ private: Utils::Terminal::OpenTerminalParameters m_openParameters; QDateTime m_lastFlush; + QDateTime m_lastDoubleClick; + bool m_selectLineMode{false}; + + std::u32string m_currentLiveText; }; } // namespace Terminal From d8dc1c7f0f994461b1bf21c5c7a4e890c57c16af Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 2 Mar 2023 12:07:53 +0100 Subject: [PATCH 0133/1447] Terminal: Improve performance while selecting Change-Id: I4f0a7a937f6e600430d8c89e51d1ea2d1ab8687f Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalwidget.cpp | 17 +++++++++++++---- src/plugins/terminal/terminalwidget.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 5639f0d16aa..f30a0fb5782 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -460,6 +460,11 @@ QPoint TerminalWidget::viewportToGlobal(QPoint p) const return {p.x(), y}; } +QPoint TerminalWidget::globalToGrid(QPoint p) const +{ + return QPoint(p.x() / m_cellSize.width(), p.y() / m_cellSize.height()); +} + void TerminalWidget::createTextLayout() { QElapsedTimer t; @@ -830,6 +835,9 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) void TerminalWidget::mouseMoveEvent(QMouseEvent *event) { if (m_selection && event->buttons() & Qt::LeftButton) { + const std::array oldGrid = {globalToGrid(m_selection->start), + globalToGrid(m_selection->end)}; + QPoint start = viewportToGlobal(m_selectionStartPos); QPoint newEnd = viewportToGlobal(event->pos()); @@ -844,7 +852,10 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) m_selection->start = start; m_selection->end = newEnd; - viewport()->update(); + const std::array newGrid = {globalToGrid(m_selection->start), + globalToGrid(m_selection->end)}; + if (newGrid != oldGrid) + viewport()->update(); } } @@ -863,9 +874,7 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) std::u32string text = m_scrollback->currentText() + m_currentLiveText; const QPoint clickPos = viewportToGlobal(event->pos()); - - const QPoint clickPosInGrid = QPoint(clickPos.x() / m_cellSize.width(), - clickPos.y() / m_cellSize.height()); + const QPoint clickPosInGrid = globalToGrid(clickPos); std::u32string::size_type chIdx = (clickPosInGrid.x()) + (clickPosInGrid.y()) * m_vtermSize.width(); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 8f09b833b69..0f83ca70920 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -99,6 +99,7 @@ protected: qreal topMargin() const; QPoint viewportToGlobal(QPoint p) const; + QPoint globalToGrid(QPoint p) const; int textLineFromPixel(int y) const; std::optional textPosFromPoint(const QTextLayout &textLayout, QPoint p) const; From 928bef59efe4fa65078b9160f22ee430ccc4ac49 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 2 Mar 2023 16:20:28 +0100 Subject: [PATCH 0134/1447] Fix qbs build Change-Id: Iddc8bdc08367cb596b16c22494c9289ea7eb4c86 Reviewed-by: hjk --- src/libs/utils/utils.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index a1b3415e719..cf952ae62d8 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -36,6 +36,7 @@ Project { Depends { name: "Qt"; submodules: ["concurrent", "core-private", "network", "qml", "widgets", "xml"] } Depends { name: "Qt.macextras"; condition: Qt.core.versionMajor < 6 && qbs.targetOS.contains("macos") } Depends { name: "app_version_header" } + Depends { name: "ptyqt" } files: [ "QtConcurrentTools", From ef0b958c74dc03f2af1e11bb2b263e6fdc475a9d Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 12:06:49 +0100 Subject: [PATCH 0135/1447] Qbs: Avoid explicit use of Environmnet iterators Task-number: QTCREATORBUG-28357 Change-Id: Ib703941bf50053df5481945e0714dd831191b625 Reviewed-by: Christian Kandeler --- src/plugins/qbsprojectmanager/qbsprojectparser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp index 1620b747ac3..ee1aafdb6b0 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp @@ -67,10 +67,10 @@ void QbsProjectParser::parse(const QVariantMap &config, const Environment &env, request.insert("override-build-graph-data", true); static const auto envToJson = [](const Environment &env) { QJsonObject envObj; - for (auto it = env.constBegin(); it != env.constEnd(); ++it) { - if (env.isEnabled(it)) - envObj.insert(env.key(it), env.value(it)); - } + env.forEachEntry([&](const QString &key, const QString &value, bool enabled) { + if (enabled) + envObj.insert(key, value); + }); return envObj; }; request.insert("environment", envToJson(env)); From 3d45683edfb6e2924aeaf72a2e462b1456df65cb Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 12:10:06 +0100 Subject: [PATCH 0136/1447] QMake: Avoid some explicit use of environment iterators Task-number: QTCREATORBUG-28357 Change-Id: I80eae26eb1e7c7202654acdd3eb9380934bb7347 Reviewed-by: Christian Kandeler --- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 6d840187251..575de11f66c 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -872,9 +872,9 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi rootProFileName, deviceRoot()); - Environment::const_iterator eit = env.constBegin(), eend = env.constEnd(); - for (; eit != eend; ++eit) - m_qmakeGlobals->environment.insert(env.key(eit), env.expandedValueForKey(env.key(eit))); + env.forEachEntry([&](const QString &key, const QString &, bool) { + m_qmakeGlobals->environment.insert(key, env.expandedValueForKey(key)); + }); m_qmakeGlobals->setCommandLineArguments(rootProFileName, qmakeArgs); m_qmakeGlobals->runSystemFunction = bc->runSystemFunction(); From 21de068c148402f185f5ef5028f5fe88c2620a59 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 12:21:58 +0100 Subject: [PATCH 0137/1447] RemoteLinux: Avoid some explicit uses of environment iterators Task-number: QTCREATORBUG-28357 Change-Id: Ic8eb7592853749a7d511acc9a528059765c4ed75 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 5 +++-- src/plugins/remotelinux/makeinstallstep.cpp | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 754a7f0281e..d38542fefde 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -613,8 +613,9 @@ QString LinuxProcessInterface::fullCommandLine(const CommandLine &commandLine) c cmd.addArgs(QString("echo ") + s_pidMarker + "$$" + s_pidMarker + " && ", CommandLine::Raw); const Environment &env = m_setup.m_environment; - for (auto it = env.constBegin(); it != env.constEnd(); ++it) - cmd.addArgs(env.key(it) + "='" + env.expandedValueForKey(env.key(it)) + '\'', CommandLine::Raw); + env.forEachEntry([&](const QString &key, const QString &, bool) { + cmd.addArgs(key + "='" + env.expandedValueForKey(key) + '\'', CommandLine::Raw); + }); if (m_setup.m_terminalMode == TerminalMode::Off) cmd.addArg("exec"); diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index ea7b6364586..a23dba21037 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -172,12 +172,10 @@ bool MakeInstallStep::init() const MakeInstallCommand cmd = buildSystem()->makeInstallCommand(rootDir); if (cmd.environment.hasChanges()) { Environment env = processParameters()->environment(); - for (auto it = cmd.environment.constBegin(); it != cmd.environment.constEnd(); ++it) { - if (cmd.environment.isEnabled(it)) { - const QString key = cmd.environment.key(it); + cmd.environment.forEachEntry([&](const QString &key, const QString &, bool enabled) { + if (enabled) env.set(key, cmd.environment.expandedValueForKey(key)); - } - } + }); processParameters()->setEnvironment(env); } m_noInstallTarget = false; From 3e5d14b02047794669db82620e9411065988b4d7 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 13:26:26 +0100 Subject: [PATCH 0138/1447] Utils: Replace Environment::find iterator use Task-number: QTCREATORBUG-28357 Change-Id: I2723ffd6b7842f88009701eccea9aacac8cbf516 Reviewed-by: Christian Kandeler --- src/libs/utils/commandline.cpp | 12 ++++---- src/libs/utils/environment.cpp | 32 ++++++++++++++-------- src/libs/utils/environment.h | 5 +++- tests/auto/environment/tst_environment.cpp | 12 ++++---- 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 6f8d4a4f5d9..81285259acc 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -362,12 +362,12 @@ static QStringList splitArgsUnix(const QString &args, bool abortOnMeta, if (var == pwdName && pwd && !pwd->isEmpty()) { cret += *pwd; } else { - Environment::const_iterator vit = env->constFind(var); - if (vit == env->constEnd()) { + const Environment::FindResult res = env->find(var); + if (!res) { if (abortOnMeta) goto metaerr; // Assume this is a shell builtin } else { - cret += env->expandedValueForKey(env->key(vit)); + cret += env->expandedValueForKey(res->key); } } if (!braced) @@ -412,12 +412,12 @@ static QStringList splitArgsUnix(const QString &args, bool abortOnMeta, if (var == pwdName && pwd && !pwd->isEmpty()) { val = *pwd; } else { - Environment::const_iterator vit = env->constFind(var); - if (vit == env->constEnd()) { + const Environment::FindResult res = env->find(var); + if (!res) { if (abortOnMeta) goto metaerr; // Assume this is a shell builtin } else { - val = env->expandedValueForKey(env->key(vit)); + val = env->expandedValueForKey(res->key); } } for (int i = 0; i < val.length(); i++) { diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 6d8785c9d73..eb49db208d7 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -24,6 +24,14 @@ NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepe return m_dict.diff(other.m_dict, checkAppendPrepend); } +Environment::FindResult Environment::find(const QString &name) const +{ + const auto it = m_dict.constFind(name); + if (it == m_dict.constEnd()) + return {}; + return Entry{it.key().name, it.value().first, it.value().second}; +} + void Environment::forEachEntry(const std::function &callBack) const { for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) @@ -356,28 +364,30 @@ QString Environment::expandVariables(const QString &input) const } } else if (state == BRACEDVARIABLE) { if (c == '}') { - const_iterator it = constFind(result.mid(vStart, i - 1 - vStart)); - if (it != constEnd()) { - result.replace(vStart - 2, i - vStart + 2, it->first); - i = vStart - 2 + it->first.length(); + const QString key = result.mid(vStart, i - 1 - vStart); + const Environment::FindResult res = find(key); + if (res) { + result.replace(vStart - 2, i - vStart + 2, res->value); + i = vStart - 2 + res->value.length(); } state = BASE; } } else if (state == VARIABLE) { if (!c.isLetterOrNumber() && c != '_') { - const_iterator it = constFind(result.mid(vStart, i - vStart - 1)); - if (it != constEnd()) { - result.replace(vStart - 1, i - vStart, it->first); - i = vStart - 1 + it->first.length(); + const QString key = result.mid(vStart, i - vStart - 1); + const Environment::FindResult res = find(key); + if (res) { + result.replace(vStart - 1, i - vStart, res->value); + i = vStart - 1 + res->value.length(); } state = BASE; } } } if (state == VARIABLE) { - const_iterator it = constFind(result.mid(vStart)); - if (it != constEnd()) - result.replace(vStart - 1, result.length() - vStart + 1, it->first); + const Environment::FindResult res = find(result.mid(vStart)); + if (res) + result.replace(vStart - 1, result.length() - vStart + 1, res->value); } } return result; diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 7d670a4ae79..52ac1db6286 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -91,7 +91,10 @@ public: const_iterator constBegin() const { return m_dict.constBegin(); } // FIXME: avoid const_iterator constEnd() const { return m_dict.constEnd(); } // FIXME: avoid - const_iterator constFind(const QString &name) const { return m_dict.constFind(name); } // FIXME: avoid + + struct Entry { QString key; QString value; bool enabled; }; + using FindResult = std::optional; + FindResult find(const QString &name) const; // Note res->key may differ in case from name. void forEachEntry(const std::function &callBack) const; diff --git a/tests/auto/environment/tst_environment.cpp b/tests/auto/environment/tst_environment.cpp index 994027308db..85ade0fe1df 100644 --- a/tests/auto/environment/tst_environment.cpp +++ b/tests/auto/environment/tst_environment.cpp @@ -270,8 +270,9 @@ void tst_Environment::incrementalChanges() newEnv.modify(changes); QVERIFY(!newEnv.hasKey("VAR1")); QCOMPARE(newEnv.value("VAR2"), QString()); - QCOMPARE(newEnv.constFind("VAR2")->first, "VALUE2"); - QVERIFY(!newEnv.isEnabled(newEnv.constFind("VAR2"))); + Environment::FindResult res = newEnv.find("VAR2"); + QCOMPARE(res->value, "VALUE2"); + QVERIFY(!res->enabled); const QChar sep = HostOsInfo::pathListSeparator(); QCOMPARE(newEnv.value("PATH"), QString("/tmp").append(sep).append("/usr/bin").append(sep).append("/usr/local/bin")); @@ -317,13 +318,12 @@ void tst_Environment::find() Environment env(QStringList({"Foo=bar", "Hi=HO"}), osType); - auto end = env.constEnd(); - auto it = env.constFind(variable); + Environment::FindResult res = env.find(variable); - QCOMPARE((end != it), contains); + QCOMPARE(bool(res), contains); if (contains) - QCOMPARE(env.value(it), QString("bar")); + QCOMPARE(res->value, QString("bar")); } From 5e3af5b0f514121d24511193f99a35bbf7e1336c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 14:03:41 +0100 Subject: [PATCH 0139/1447] Qnx: Avoid use of Environment iterators Change-Id: I2a1be67c1d21a731de1ada3d58099896fb676ffa Reviewed-by: Christian Kandeler --- src/plugins/qnx/qnxdevice.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 0c7c99a5c39..89d1241cfe7 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -61,10 +61,9 @@ QString QnxProcessImpl::fullCommandLine(const CommandLine &commandLine) const ProcessArgs::quoteArg(m_setup.m_workingDirectory.toString())); const Environment env = m_setup.m_environment; - for (auto it = env.constBegin(); it != env.constEnd(); ++it) { - fullCommandLine += QString::fromLatin1("%1='%2' ") - .arg(env.key(it)).arg(env.expandedValueForKey(env.key(it))); - } + env.forEachEntry([&](const QString &key, const QString &, bool) { + fullCommandLine += QString("%1='%2' ").arg(key).arg(env.expandedValueForKey(key)); + }); fullCommandLine += QString::fromLatin1("%1 & echo $! > %2").arg(cmd).arg(m_pidFile); From 78b1407adf6ef09dc59ce597e69cae709d99f922 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 2 Mar 2023 11:15:51 +0100 Subject: [PATCH 0140/1447] Docker: Don't swallow output when startup fails Previously error output occurring while the PID marker was not parsed yet was not passed on to the parent QtcProcess. Change-Id: Id6cbaa13a7d6c62d7a8612e118092eb2be6e790c Reviewed-by: hjk --- src/plugins/docker/dockerdevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 97a4dba0da8..45e024b400b 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -238,8 +238,8 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva }); connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + QByteArray output = m_process.readAllRawStandardOutput(); if (!m_hasReceivedFirstOutput) { - QByteArray output = m_process.readAllRawStandardOutput(); qsizetype idx = output.indexOf('\n'); QByteArray firstLine = output.left(idx).trimmed(); QByteArray rest = output.mid(idx + 1); @@ -259,7 +259,7 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva return; } } - emit readyRead(m_process.readAllRawStandardOutput(), {}); + emit readyRead(output, {}); }); connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { From 0a0827da41bc5c2d12ad8c160b6cdeed813b2db9 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 2 Mar 2023 15:21:50 +0100 Subject: [PATCH 0141/1447] Terminal: Improve keyboard shortcuts and mouse copy/paste Change-Id: I7e032a48cc55143dd8fb038d74eb71c4ad8badac Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalwidget.cpp | 98 +++++++++++++++++-------- src/plugins/terminal/terminalwidget.h | 3 + 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index f30a0fb5782..e88b78d2f11 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -60,6 +60,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op setupVTerm(); setupFont(); setupColors(); + setupActions(); setAttribute(Qt::WA_InputMethodEnabled); setAttribute(Qt::WA_MouseTracking); @@ -223,6 +224,23 @@ void TerminalWidget::setupColors() clearContents(); } +void TerminalWidget::setupActions() +{ + m_copyAction.setShortcuts( + {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") + : QLatin1String("Ctrl+Shift+C")), + QKeySequence(Qt::Key_Return)}); + m_pasteAction.setShortcut(QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V"))); + + m_clearSelectionAction.setShortcut(QKeySequence("Esc")); + + m_zoomInAction.setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+Shift++")}); + m_zoomOutAction.setShortcut(QKeySequence("Ctrl+-")); + + addActions({&m_copyAction, &m_pasteAction, &m_clearSelectionAction, &m_zoomInAction, &m_zoomOutAction}); +} + void TerminalWidget::writeToPty(const QByteArray &data) { if (m_process) @@ -392,8 +410,9 @@ void TerminalWidget::pasteFromClipboard() void TerminalWidget::clearSelection() { - m_selection.reset(); - update(); + setSelection(std::nullopt); + viewport()->update(); + vterm_keyboard_key(m_vterm.get(), VTERM_KEY_ESCAPE, VTERM_MOD_NONE); } void TerminalWidget::zoomIn() { @@ -438,6 +457,12 @@ void TerminalWidget::flushVTerm(bool force) m_flushDelayTimer.start(); } +void TerminalWidget::setSelection(const std::optional &selection) +{ + m_copyAction.setEnabled(selection.has_value()); + m_selection = selection; +} + const VTermScreenCell *TerminalWidget::fetchCell(int x, int y) const { QTC_ASSERT(y >= 0, return nullptr); @@ -647,33 +672,32 @@ void TerminalWidget::paintEvent(QPaintEvent *event) void TerminalWidget::keyPressEvent(QKeyEvent *event) { + bool actionTriggered = false; + for (const auto &action : actions()) { + if (!action->isEnabled()) + continue; + + for (const auto &shortcut : action->shortcuts()) { + const auto result = shortcut.matches(QKeySequence(event->keyCombination())); + if (result == QKeySequence::ExactMatch) { + action->trigger(); + actionTriggered = true; + break; + } + } + + if (actionTriggered) + break; + } + + if (actionTriggered) { + setSelection(std::nullopt); + viewport()->update(); + return; + } + event->accept(); - if (event->modifiers() == Qt::NoModifier && event->key() == Qt::Key_Escape && m_selection) { - clearSelectionAction().trigger(); - return; - } - - if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Plus) { - zoomInAction().trigger(); - return; - } - - if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Minus) { - zoomOutAction().trigger(); - return; - } - - if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_C) { - copyAction().trigger(); - return; - } - - if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_V) { - pasteAction().trigger(); - return; - } - bool keypad = event->modifiers() & Qt::KeypadModifier; VTermModifier mod = Internal::qtModifierToVTerm(event->modifiers()); VTermKey key = Internal::qtKeyToVTerm(Qt::Key(event->key()), keypad); @@ -702,6 +726,8 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) vterm_keyboard_unichar(m_vterm.get(), event->text().toUcs4()[0], static_cast(mod & ~VTERM_MOD_CTRL)); + + setSelection(std::nullopt); } else if (mod != VTERM_MOD_NONE && event->key() == Qt::Key_C) { vterm_keyboard_unichar(m_vterm.get(), 'c', mod); } @@ -745,7 +771,7 @@ void TerminalWidget::resizeEvent(QResizeEvent *event) applySizeChange(); - m_selection.reset(); + setSelection(std::nullopt); m_ignoreScroll = false; } @@ -826,10 +852,18 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) } else { m_selectLineMode = false; QPoint pos = viewportToGlobal(event->pos()); - m_selection = Selection{pos, pos}; + setSelection(Selection{pos, pos}); } viewport()->update(); + } else if (event->button() == Qt::RightButton) { + if (m_selection) { + m_copyAction.trigger(); + setSelection(std::nullopt); + viewport()->update(); + } else { + m_pasteAction.trigger(); + } } } void TerminalWidget::mouseMoveEvent(QMouseEvent *event) @@ -863,7 +897,7 @@ void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) { if (m_selection && event->button() != Qt::LeftButton) { if ((m_selectionStartPos - event->pos()).manhattanLength() < 2) { - m_selection.reset(); + setSelection(std::nullopt); viewport()->update(); } } @@ -904,7 +938,7 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) (rightEnd / m_vtermSize.width()) * m_cellSize.height() + m_cellSize.height()); - m_selection = Selection{selectionStart, selectionEnd}; + setSelection(Selection{selectionStart, selectionEnd}); m_lastDoubleClick = QDateTime::currentDateTime(); @@ -992,7 +1026,7 @@ int TerminalWidget::setTerminalProperties(VTermProp prop, VTermValue *val) break; case VTERM_PROP_ALTSCREEN: m_altscreen = val->boolean; - m_selection.reset(); + setSelection(std::nullopt); break; case VTERM_PROP_MOUSE: qCDebug(terminalLog) << "Ignoring VTERM_PROP_MOUSE" << val->number; diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 0f83ca70920..04fdc7cefc3 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -81,6 +81,7 @@ protected: void setupFont(); void setupPty(); void setupColors(); + void setupActions(); void writeToPty(const QByteArray &data); @@ -113,6 +114,8 @@ protected: void flushVTerm(bool force); + void setSelection(const std::optional &selection); + private: std::unique_ptr m_process; From d387802a3e1d1ed0e1feb7faacb6fdb2ec31f511 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 2 Mar 2023 16:59:03 +0100 Subject: [PATCH 0142/1447] Terminal: use shell name as terminal tab name This way cmd, bash, powershell are more descriptive than "Terminal" Change-Id: I19310f423cd4188ecc48580a30ed414833a15aee Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalpane.cpp | 29 ++++++++++++++++++++++--- src/plugins/terminal/terminalpane.h | 1 + src/plugins/terminal/terminalwidget.cpp | 9 ++++++++ src/plugins/terminal/terminalwidget.h | 4 ++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 260924a1b17..9eedfb3cce5 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -74,8 +74,9 @@ TerminalPane::TerminalPane(QObject *parent) void TerminalPane::openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters) { showPage(0); - m_tabWidget->setCurrentIndex( - m_tabWidget->addTab(new TerminalWidget(m_tabWidget, parameters), Tr::tr("Terminal"))); + auto terminalWidget = new TerminalWidget(m_tabWidget, parameters); + m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal"))); + setupTerminalWidget(terminalWidget); m_tabWidget->currentWidget()->setFocus(); @@ -87,6 +88,7 @@ void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) { showPage(0); m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminal, title)); + setupTerminalWidget(terminal); m_closeTerminal.setEnabled(m_tabWidget->count() > 1); emit navigateStateUpdate(); @@ -106,7 +108,10 @@ QWidget *TerminalPane::outputWidget(QWidget *parent) removeTab(index); }); - m_tabWidget->addTab(new TerminalWidget(parent), Tr::tr("Terminal")); + auto terminalWidget = new TerminalWidget(parent); + m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal")); + setupTerminalWidget(terminalWidget); + } return m_tabWidget; @@ -127,6 +132,24 @@ void TerminalPane::removeTab(int index) emit navigateStateUpdate(); } +void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) +{ + if (!terminal) + return; + + auto setTabText = [this](TerminalWidget * terminal) { + auto index = m_tabWidget->indexOf(terminal); + m_tabWidget->setTabText(index, terminal->shellName()); + }; + + connect(terminal, &TerminalWidget::started, [setTabText, terminal](qint64 /*pid*/) { + setTabText(terminal); + }); + + if (!terminal->shellName().isEmpty()) + setTabText(terminal); +} + QList TerminalPane::toolBarWidgets() const { return {m_newTerminalButton, m_closeTerminalButton}; diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 3dea1c84142..838fb3376ad 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -43,6 +43,7 @@ private: TerminalWidget *currentTerminal() const; void removeTab(int index); + void setupTerminalWidget(TerminalWidget *terminal); private: QTabWidget *m_tabWidget{nullptr}; diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index e88b78d2f11..a0096332981 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -162,6 +162,10 @@ void TerminalWidget::setupPty() }); connect(m_process.get(), &QtcProcess::started, this, [this] { + m_shellName = m_process->commandLine().executable().fileName(); + if (HostOsInfo::isWindowsHost() && m_shellName.endsWith(QTC_WIN_EXE_SUFFIX)) + m_shellName.chop(QStringLiteral(QTC_WIN_EXE_SUFFIX).size()); + applySizeChange(); emit started(m_process->processId()); }); @@ -463,6 +467,11 @@ void TerminalWidget::setSelection(const std::optional &selection) m_selection = selection; } +QString TerminalWidget::shellName() const +{ + return m_shellName; +} + const VTermScreenCell *TerminalWidget::fetchCell(int x, int y) const { QTC_ASSERT(y >= 0, return nullptr); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 04fdc7cefc3..14c8be119f2 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -52,6 +52,8 @@ public: QPoint end; }; + QString shellName() const; + signals: void started(qint64 pid); @@ -119,6 +121,8 @@ protected: private: std::unique_ptr m_process; + QString m_shellName; + std::unique_ptr m_vterm; VTermScreen *m_vtermScreen; QSize m_vtermSize; From 13a202564bfc7b01fb932d8c1b2c00bf7b0a9f03 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Mar 2023 19:58:52 +0100 Subject: [PATCH 0143/1447] TerminalProcess: Add Pty into switch statement Amends 1da18a4b62c9fcb5d499b098b0e13049f0c34193 Change-Id: I1cef188a28f19eea3885a17e983b4cf7a4815498 Reviewed-by: Marcus Tillmanns --- src/libs/utils/terminalprocess.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/terminalprocess.cpp b/src/libs/utils/terminalprocess.cpp index bd0333c9d74..91423539a33 100644 --- a/src/libs/utils/terminalprocess.cpp +++ b/src/libs/utils/terminalprocess.cpp @@ -44,13 +44,15 @@ namespace Internal { static QString modeOption(TerminalMode m) { switch (m) { - case TerminalMode::Run: - return QLatin1String("run"); - case TerminalMode::Debug: - return QLatin1String("debug"); - case TerminalMode::Suspend: - return QLatin1String("suspend"); - case TerminalMode::Off: + case TerminalMode::Pty: + return "pty"; + case TerminalMode::Run: + return "run"; + case TerminalMode::Debug: + return "debug"; + case TerminalMode::Suspend: + return "suspend"; + case TerminalMode::Off: QTC_CHECK(false); break; } From 9b7b0d4f02b8c35bd46dc6eedb641d05d3d2f098 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 08:11:07 +0100 Subject: [PATCH 0144/1447] Terminal: Switch to std::chrono QDateTime's interface various between supported Qt Versions, so we use std::chrono instead Change-Id: I5af5ae9950e61c2ed38ff15dc0580f0dc2aa1f57 Reviewed-by: Christian Stenger --- src/plugins/terminal/terminalwidget.cpp | 32 +++++++++++++++---------- src/plugins/terminal/terminalwidget.h | 5 ++-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index a0096332981..58f370913a3 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -29,8 +29,6 @@ #include #include -#include - Q_LOGGING_CATEGORY(terminalLog, "qtc.terminal", QtWarningMsg) using namespace Utils; @@ -41,7 +39,7 @@ namespace Terminal { using namespace std::chrono_literals; // Minimum time between two refreshes. (30fps) -static const auto minRefreshInterval = 1s / 30; +static constexpr std::chrono::milliseconds minRefreshInterval = 1s / 30; TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &openParameters) : QAbstractScrollArea(parent) @@ -54,8 +52,8 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op , m_zoomInAction(Tr::tr("Zoom In")) , m_zoomOutAction(Tr::tr("Zoom Out")) , m_openParameters(openParameters) - , m_lastFlush(QDateTime::currentDateTime()) - , m_lastDoubleClick(QDateTime::currentDateTime()) + , m_lastFlush(std::chrono::system_clock::now()) + , m_lastDoubleClick(std::chrono::system_clock::now()) { setupVTerm(); setupFont(); @@ -451,14 +449,24 @@ void TerminalWidget::onReadyRead(bool forceFlush) void TerminalWidget::flushVTerm(bool force) { - if (force || QDateTime::currentDateTime() - m_lastFlush > minRefreshInterval) { - m_lastFlush = QDateTime::currentDateTime(); + const std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + const std::chrono::milliseconds timeSinceLastFlush + = std::chrono::duration_cast(now - m_lastFlush); + + const bool shouldFlushImmediately = timeSinceLastFlush > minRefreshInterval; + if (force || shouldFlushImmediately) { + if (m_flushDelayTimer.isActive()) + m_flushDelayTimer.stop(); + + m_lastFlush = now; vterm_screen_flush_damage(m_vtermScreen); return; } - if (!m_flushDelayTimer.isActive()) - m_flushDelayTimer.start(); + if (!m_flushDelayTimer.isActive()) { + const std::chrono::milliseconds timeToNextFlush = (minRefreshInterval - timeSinceLastFlush); + m_flushDelayTimer.start(timeToNextFlush.count()); + } } void TerminalWidget::setSelection(const std::optional &selection) @@ -854,7 +862,7 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) m_selectionStartPos = event->pos(); if (event->button() == Qt::LeftButton) { - if (QDateTime::currentDateTime() - m_lastDoubleClick < 500ms) { + if (std::chrono::system_clock::now() - m_lastDoubleClick < 500ms) { m_selectLineMode = true; m_selection->start.setX(0); m_selection->end.setX(viewport()->width()); @@ -922,7 +930,7 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) std::u32string::size_type chIdx = (clickPosInGrid.x()) + (clickPosInGrid.y()) * m_vtermSize.width(); - if (chIdx >= text.length() || chIdx < 0) + if (chIdx >= text.length()) return; std::u32string whiteSpaces = U" \t\x00a0"; @@ -949,7 +957,7 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) setSelection(Selection{selectionStart, selectionEnd}); - m_lastDoubleClick = QDateTime::currentDateTime(); + m_lastDoubleClick = std::chrono::system_clock::now(); viewport()->update(); event->accept(); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 14c8be119f2..7c006873761 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -15,6 +15,7 @@ #include +#include #include namespace Terminal { @@ -169,8 +170,8 @@ private: Utils::Terminal::OpenTerminalParameters m_openParameters; - QDateTime m_lastFlush; - QDateTime m_lastDoubleClick; + std::chrono::system_clock::time_point m_lastFlush; + std::chrono::system_clock::time_point m_lastDoubleClick; bool m_selectLineMode{false}; std::u32string m_currentLiveText; From 9673dc7cd4b21775efd98ad7a335006674d0e77c Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 2 Mar 2023 18:13:27 +0100 Subject: [PATCH 0145/1447] Terminal: New terminal and switch between terminals shortcuts On macOS: * new terminal Ctrl+T * next terminal Ctrl+Shift+] * prev terminal Ctrl+Shift+[ On Windows / Linux * new terminal Ctrl+Shift+T * next terminal Ctrl+PgUp * prev terminal Ctrl+PgDown Change-Id: I5626816cd18fd7a6d2b1cea5eea835a40b0c1029 Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalpane.cpp | 35 ++++++++++++++++++++++++--- src/plugins/terminal/terminalpane.h | 2 ++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 9eedfb3cce5..b93bdd3a5e9 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -64,11 +64,28 @@ TerminalPane::TerminalPane(QObject *parent) }); m_newTerminal.setMenu(shellMenu); + m_newTerminal.setShortcut(QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") : QLatin1String("Ctrl+Shift+T"))); m_newTerminalButton->setDefaultAction(&m_newTerminal); m_closeTerminalButton = new QToolButton(); m_closeTerminalButton->setDefaultAction(&m_closeTerminal); + + m_nextTerminal.setShortcut(QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[") + : QLatin1String("Ctrl+PgUp"))); + m_prevTerminal.setShortcut(QKeySequence(HostOsInfo::isMacHost() + ? QLatin1String("Ctrl+Shift+]") + : QLatin1String("Ctrl+PgDown"))); + + connect(&m_nextTerminal, &QAction::triggered, this, [this] { + if (canNavigate()) + goToNext(); + }); + connect(&m_prevTerminal, &QAction::triggered, this, [this] { + if (canPrevious()) + goToPrev(); + }); } void TerminalPane::openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters) @@ -148,6 +165,8 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) if (!terminal->shellName().isEmpty()) setTabText(terminal); + + terminal->addActions({&m_newTerminal, &m_nextTerminal, &m_prevTerminal}); } QList TerminalPane::toolBarWidgets() const @@ -202,23 +221,31 @@ bool TerminalPane::canNavigate() const bool TerminalPane::canNext() const { - return m_tabWidget->count() > 1 && m_tabWidget->currentIndex() < m_tabWidget->count() - 1; + return m_tabWidget->count() > 1; } bool TerminalPane::canPrevious() const { - return m_tabWidget->count() > 1 && m_tabWidget->currentIndex() > 0; + return m_tabWidget->count() > 1; } void TerminalPane::goToNext() { - m_tabWidget->setCurrentIndex(m_tabWidget->currentIndex() + 1); + int nextIndex = m_tabWidget->currentIndex() + 1; + if (nextIndex >= m_tabWidget->count()) + nextIndex = 0; + + m_tabWidget->setCurrentIndex(nextIndex); emit navigateStateUpdate(); } void TerminalPane::goToPrev() { - m_tabWidget->setCurrentIndex(m_tabWidget->currentIndex() - 1); + int prevIndex = m_tabWidget->currentIndex() - 1; + if (prevIndex < 0) + prevIndex = m_tabWidget->count() - 1; + + m_tabWidget->setCurrentIndex(prevIndex); emit navigateStateUpdate(); } diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 838fb3376ad..f748c70e717 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -53,6 +53,8 @@ private: QAction m_newTerminal; QAction m_closeTerminal; + QAction m_nextTerminal; + QAction m_prevTerminal; }; } // namespace Terminal From b26e3a45012788370083ab67b86897043abb0e3c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 14:21:23 +0100 Subject: [PATCH 0146/1447] Utils: Remove unused Environment functions Change-Id: Idea6b1a126b1d4fe82b597e96ce447da9f546396 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/utils/environment.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 52ac1db6286..1485dff2a12 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -41,7 +41,6 @@ public: void modify(const NameValueItems &items) { m_dict.modify(items); } bool hasChanges() const; - void clear() { return m_dict.clear(); } QStringList toStringList() const { return m_dict.toStringList(); } QProcessEnvironment toProcessEnvironment() const; @@ -76,7 +75,6 @@ public: QStringList expandVariables(const QStringList &input) const; OsType osType() const { return m_dict.osType(); } - QString userName() const; using const_iterator = NameValueMap::const_iterator; // FIXME: avoid NameValueDictionary toDictionary() const { return m_dict; } // FIXME: avoid From 6d70a2796564dae8d8cec591dfe0d7b2f58d0469 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 09:00:11 +0100 Subject: [PATCH 0147/1447] UnixPtyProcess: Fix read loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously a value of "-1" from ::read would result in an endless loop. This could easily be reproduced by "cat /dev/random | base64" The buffer usage was also much more complicated than needed. A static readBuffer now keeps the amount of allocations lower. Change-Id: I5bb1a3c84b107ff8c2d3801bca8c6ae9a709cdb3 Reviewed-by: Cristian Adam --- src/libs/3rdparty/libptyqt/unixptyprocess.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/libs/3rdparty/libptyqt/unixptyprocess.cpp b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp index e049a2abb92..8c018daf8c0 100644 --- a/src/libs/3rdparty/libptyqt/unixptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/unixptyprocess.cpp @@ -164,19 +164,14 @@ bool UnixPtyProcess::startProcess(const QString &shellPath, QObject::connect(m_readMasterNotify, &QSocketNotifier::activated, [this](int socket) { Q_UNUSED(socket) - QByteArray buffer; - int size = 1025; - int readSize = 1024; - QByteArray data; - do { - char nativeBuffer[size]; - int len = ::read(m_shellProcess.m_handleMaster, nativeBuffer, readSize); - data = QByteArray(nativeBuffer, len); - buffer.append(data); - } while (data.size() == readSize); //last data block always < readSize + const size_t maxRead = 16 * 1024; + static std::array buffer; - m_shellReadBuffer.append(buffer); - m_shellProcess.emitReadyRead(); + int len = ::read(m_shellProcess.m_handleMaster, buffer.data(), buffer.size()); + if (len > 0) { + m_shellReadBuffer.append(buffer.data(), len); + m_shellProcess.emitReadyRead(); + } }); QObject::connect(&m_shellProcess, &QProcess::finished, &m_shellProcess, [this](int exitCode) { From 240686b7ea35e143589aa826f6930138dea982f3 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 09:12:12 +0100 Subject: [PATCH 0148/1447] Terminal: Start with disabled copy action The copy action should only be enabled once a selection exists. In the beginning no selection can exist, therefore the copy action is disabled. Previously this lead to a bug where only the second "Enter" keypress was passed on to the terminal. Change-Id: Iac01c273f70a50a4fc131bd6a2bbb1507705b853 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 58f370913a3..86af9fb4f11 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -79,12 +79,6 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op connect(&m_flushDelayTimer, &QTimer::timeout, this, [this]() { flushVTerm(true); }); - connect(&m_copyAction, &QAction::triggered, this, &TerminalWidget::copyToClipboard); - connect(&m_pasteAction, &QAction::triggered, this, &TerminalWidget::pasteFromClipboard); - connect(&m_clearSelectionAction, &QAction::triggered, this, &TerminalWidget::clearSelection); - connect(&m_zoomInAction, &QAction::triggered, this, &TerminalWidget::zoomIn); - connect(&m_zoomOutAction, &QAction::triggered, this, &TerminalWidget::zoomOut); - connect(&TerminalSettings::instance(), &AspectContainer::applied, this, [this] { m_layoutVersion++; // Setup colors first, as setupFont will redraw the screen. @@ -228,6 +222,7 @@ void TerminalWidget::setupColors() void TerminalWidget::setupActions() { + m_copyAction.setEnabled(false); m_copyAction.setShortcuts( {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") : QLatin1String("Ctrl+Shift+C")), @@ -240,6 +235,12 @@ void TerminalWidget::setupActions() m_zoomInAction.setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+Shift++")}); m_zoomOutAction.setShortcut(QKeySequence("Ctrl+-")); + connect(&m_copyAction, &QAction::triggered, this, &TerminalWidget::copyToClipboard); + connect(&m_pasteAction, &QAction::triggered, this, &TerminalWidget::pasteFromClipboard); + connect(&m_clearSelectionAction, &QAction::triggered, this, &TerminalWidget::clearSelection); + connect(&m_zoomInAction, &QAction::triggered, this, &TerminalWidget::zoomIn); + connect(&m_zoomOutAction, &QAction::triggered, this, &TerminalWidget::zoomOut); + addActions({&m_copyAction, &m_pasteAction, &m_clearSelectionAction, &m_zoomInAction, &m_zoomOutAction}); } From 22b9826e22566e82f106abae6ba14a2c7e3d2f94 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 24 Feb 2023 09:37:33 +0100 Subject: [PATCH 0149/1447] Utils: Introduce FileStreamer The class is responsible for asynchronous read / write of file contents. The file may be local or remote. It's also able to do an asynchronous copy of files between different devices. Change-Id: I65e4325b6b7f98bfc17286c9a72b0018db472a16 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/asynctask.h | 8 +- src/libs/utils/filestreamer.cpp | 489 ++++++++++++++++++ src/libs/utils/filestreamer.h | 62 +++ src/libs/utils/utils.qbs | 2 + .../remotelinux/filesystemaccess_test.cpp | 355 ++++++++++++- .../remotelinux/filesystemaccess_test.h | 15 + 7 files changed, 926 insertions(+), 6 deletions(-) create mode 100644 src/libs/utils/filestreamer.cpp create mode 100644 src/libs/utils/filestreamer.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index d6b6efb4f2d..e8adad413e4 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -55,6 +55,7 @@ add_qtc_library(Utils filepath.cpp filepath.h filepathinfo.h filesearch.cpp filesearch.h + filestreamer.cpp filestreamer.h filesystemmodel.cpp filesystemmodel.h filesystemwatcher.cpp filesystemwatcher.h fileutils.cpp fileutils.h diff --git a/src/libs/utils/asynctask.h b/src/libs/utils/asynctask.h index 84cf1ee838c..5beaf400eae 100644 --- a/src/libs/utils/asynctask.h +++ b/src/libs/utils/asynctask.h @@ -24,13 +24,18 @@ class QTCREATOR_UTILS_EXPORT AsyncTaskBase : public QObject signals: void started(); void done(); + void resultReadyAt(int index); }; template class AsyncTask : public AsyncTaskBase { public: - AsyncTask() { connect(&m_watcher, &QFutureWatcherBase::finished, this, &AsyncTaskBase::done); } + AsyncTask() { + connect(&m_watcher, &QFutureWatcherBase::finished, this, &AsyncTaskBase::done); + connect(&m_watcher, &QFutureWatcherBase::resultReadyAt, + this, &AsyncTaskBase::resultReadyAt); + } ~AsyncTask() { if (isDone()) @@ -72,6 +77,7 @@ public: QFuture future() const { return m_watcher.future(); } ResultType result() const { return m_watcher.result(); } + ResultType resultAt(int index) const { return m_watcher.resultAt(index); } QList results() const { return future().results(); } bool isResultAvailable() const { return future().resultCount(); } diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp new file mode 100644 index 00000000000..222488a5100 --- /dev/null +++ b/src/libs/utils/filestreamer.cpp @@ -0,0 +1,489 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "filestreamer.h" + +#include "asynctask.h" +#include "qtcprocess.h" + +#include +#include +#include +#include + +namespace Utils { + +using namespace Tasking; + +// TODO: Adjust according to time spent on single buffer read so that it's not more than ~50 ms +// in case of local read / write. Should it be adjusted dynamically / automatically? +static const qint64 s_bufferSize = 0x1 << 20; // 1048576 + +class FileStreamBase : public QObject +{ + Q_OBJECT + +public: + void setFilePath(const FilePath &filePath) { m_filePath = filePath; } + void start() { + QTC_ASSERT(!m_taskTree, return); + + const TaskItem task = m_filePath.needsDevice() ? remoteTask() : localTask(); + m_taskTree.reset(new TaskTree({task})); + const auto finalize = [this](bool success) { + m_taskTree.release()->deleteLater(); + emit done(success); + }; + connect(m_taskTree.get(), &TaskTree::done, this, [=] { finalize(true); }); + connect(m_taskTree.get(), &TaskTree::errorOccurred, this, [=] { finalize(false); }); + m_taskTree->start(); + } + +signals: + void done(bool success); + +protected: + FilePath m_filePath; + std::unique_ptr m_taskTree; + +private: + virtual TaskItem remoteTask() = 0; + virtual TaskItem localTask() = 0; +}; + +static void localRead(QPromise &promise, const FilePath &filePath) +{ + if (promise.isCanceled()) + return; + + QFile file(filePath.path()); + if (!file.exists()) { + promise.future().cancel(); + return; + } + + if (!file.open(QFile::ReadOnly)) { + promise.future().cancel(); + return; + } + + while (int chunkSize = qMin(s_bufferSize, file.bytesAvailable())) { + if (promise.isCanceled()) + return; + promise.addResult(file.read(chunkSize)); + } +} + +class FileStreamReader : public FileStreamBase +{ + Q_OBJECT + +signals: + void readyRead(const QByteArray &newData); + +private: + TaskItem remoteTask() final { + const auto setup = [this](QtcProcess &process) { + const QStringList args = {"if=" + m_filePath.path()}; + const FilePath dd = m_filePath.withNewPath("dd"); + process.setCommand({dd, args, OsType::OsTypeLinux}); + QtcProcess *processPtr = &process; + connect(processPtr, &QtcProcess::readyReadStandardOutput, this, [this, processPtr] { + emit readyRead(processPtr->readAllRawStandardOutput()); + }); + }; + return Process(setup); + } + TaskItem localTask() final { + const auto setup = [this](AsyncTask &async) { + async.setConcurrentCallData(localRead, m_filePath); + AsyncTask *asyncPtr = &async; + connect(asyncPtr, &AsyncTaskBase::resultReadyAt, this, [=](int index) { + emit readyRead(asyncPtr->resultAt(index)); + }); + }; + return Async(setup); + } +}; + +class WriteBuffer : public QObject +{ + Q_OBJECT + +public: + WriteBuffer(bool isConcurrent, QObject *parent) + : QObject(parent) + , m_isConcurrent(isConcurrent) {} + struct Data { + QByteArray m_writeData; + bool m_closeWriteChannel = false; + bool m_canceled = false; + bool hasNewData() const { return m_closeWriteChannel || !m_writeData.isEmpty(); } + }; + + void write(const QByteArray &newData) { + if (m_isConcurrent) { + QMutexLocker locker(&m_mutex); + QTC_ASSERT(!m_data.m_closeWriteChannel, return); + QTC_ASSERT(!m_data.m_canceled, return); + m_data.m_writeData += newData; + m_waitCondition.wakeOne(); + return; + } + emit writeRequested(newData); + } + void closeWriteChannel() { + if (m_isConcurrent) { + QMutexLocker locker(&m_mutex); + QTC_ASSERT(!m_data.m_canceled, return); + m_data.m_closeWriteChannel = true; + m_waitCondition.wakeOne(); + return; + } + emit closeWriteChannelRequested(); + } + void cancel() { + if (m_isConcurrent) { + QMutexLocker locker(&m_mutex); + m_data.m_canceled = true; + m_waitCondition.wakeOne(); + return; + } + emit closeWriteChannelRequested(); + } + Data waitForData() { + QTC_ASSERT(m_isConcurrent, return {}); + QMutexLocker locker(&m_mutex); + if (!m_data.hasNewData()) + m_waitCondition.wait(&m_mutex); + return std::exchange(m_data, {}); + } + +signals: + void writeRequested(const QByteArray &newData); + void closeWriteChannelRequested(); + +private: + QMutex m_mutex; + QWaitCondition m_waitCondition; + Data m_data; + bool m_isConcurrent = false; // Depends on whether FileStreamWriter::m_writeData is empty or not +}; + +static void localWrite(QPromise &promise, const FilePath &filePath, + const QByteArray &initialData, WriteBuffer *buffer) +{ + if (promise.isCanceled()) + return; + + QFile file(filePath.path()); + + if (!file.open(QFile::WriteOnly | QFile::Truncate)) { + promise.future().cancel(); + return; + } + + if (!initialData.isEmpty()) { + const qint64 res = file.write(initialData); + if (res != initialData.size()) + promise.future().cancel(); + return; + } + + while (true) { + if (promise.isCanceled()) { + promise.future().cancel(); + return; + } + const WriteBuffer::Data data = buffer->waitForData(); + if (data.m_canceled || promise.isCanceled()) { + promise.future().cancel(); + return; + } + if (!data.m_writeData.isEmpty()) { + // TODO: Write in chunks of s_bufferSize and check for promise.isCanceled() + const qint64 res = file.write(data.m_writeData); + if (res != data.m_writeData.size()) { + promise.future().cancel(); + return; + } + } + if (data.m_closeWriteChannel) + return; + } +} + +class FileStreamWriter : public FileStreamBase +{ + Q_OBJECT + +public: + ~FileStreamWriter() { // TODO: should d'tor remove unfinished file write leftovers? + if (m_writeBuffer && isBuffered()) + m_writeBuffer->cancel(); + } + + void setWriteData(const QByteArray &writeData) { + QTC_ASSERT(!m_taskTree, return); + m_writeData = writeData; + } + void write(const QByteArray &newData) { + QTC_ASSERT(m_taskTree, return); + QTC_ASSERT(m_writeData.isEmpty(), return); + QTC_ASSERT(m_writeBuffer, return); + m_writeBuffer->write(newData); + } + void closeWriteChannel() { + QTC_ASSERT(m_taskTree, return); + QTC_ASSERT(m_writeData.isEmpty(), return); + QTC_ASSERT(m_writeBuffer, return); + m_writeBuffer->closeWriteChannel(); + } + +signals: + void started(); + +private: + TaskItem remoteTask() final { + const auto setup = [this](QtcProcess &process) { + m_writeBuffer = new WriteBuffer(false, &process); + connect(m_writeBuffer, &WriteBuffer::writeRequested, &process, &QtcProcess::writeRaw); + connect(m_writeBuffer, &WriteBuffer::closeWriteChannelRequested, + &process, &QtcProcess::closeWriteChannel); + const QStringList args = {"of=" + m_filePath.path()}; + const FilePath dd = m_filePath.withNewPath("dd"); + process.setCommand({dd, args, OsType::OsTypeLinux}); + if (isBuffered()) + process.setProcessMode(ProcessMode::Writer); + else + process.setWriteData(m_writeData); + connect(&process, &QtcProcess::started, this, [this] { emit started(); }); + }; + const auto finalize = [this](const QtcProcess &) { + delete m_writeBuffer; + m_writeBuffer = nullptr; + }; + return Process(setup, finalize, finalize); + } + TaskItem localTask() final { + const auto setup = [this](AsyncTask &async) { + m_writeBuffer = new WriteBuffer(isBuffered(), &async); + async.setConcurrentCallData(localWrite, m_filePath, m_writeData, m_writeBuffer); + emit started(); + }; + const auto finalize = [this](const AsyncTask &) { + delete m_writeBuffer; + m_writeBuffer = nullptr; + }; + return Async(setup, finalize, finalize); + } + + bool isBuffered() const { return m_writeData.isEmpty(); } + QByteArray m_writeData; + WriteBuffer *m_writeBuffer = nullptr; +}; + +class FileStreamReaderAdapter : public Utils::Tasking::TaskAdapter +{ +public: + FileStreamReaderAdapter() { connect(task(), &FileStreamBase::done, this, &TaskInterface::done); } + void start() override { task()->start(); } +}; + +class FileStreamWriterAdapter : public Utils::Tasking::TaskAdapter +{ +public: + FileStreamWriterAdapter() { connect(task(), &FileStreamBase::done, this, &TaskInterface::done); } + void start() override { task()->start(); } +}; + +} // namespace Utils + +QTC_DECLARE_CUSTOM_TASK(Reader, Utils::FileStreamReaderAdapter); +QTC_DECLARE_CUSTOM_TASK(Writer, Utils::FileStreamWriterAdapter); + +namespace Utils { + +static Group interDeviceTransfer(const FilePath &source, const FilePath &destination) +{ + struct TransferStorage { QPointer writer; }; + Condition condition; + TreeStorage storage; + + const auto setupReader = [=](FileStreamReader &reader) { + reader.setFilePath(source); + QTC_CHECK(storage->writer != nullptr); + QObject::connect(&reader, &FileStreamReader::readyRead, + storage->writer, &FileStreamWriter::write); + }; + const auto finalizeReader = [=](const FileStreamReader &) { + QTC_CHECK(storage->writer != nullptr); + storage->writer->closeWriteChannel(); + }; + const auto setupWriter = [=](FileStreamWriter &writer) { + writer.setFilePath(destination); + ConditionActivator *activator = condition.activator(); + QObject::connect(&writer, &FileStreamWriter::started, + &writer, [activator] { activator->activate(); }); + QTC_CHECK(storage->writer == nullptr); + storage->writer = &writer; + }; + + const Group root { + parallel, + Storage(storage), + Writer(setupWriter), + Group { + WaitFor(condition), + Reader(setupReader, finalizeReader, finalizeReader) + } + }; + + return root; +} + +static void transfer(QPromise &promise, const FilePath &source, const FilePath &destination) +{ + if (promise.isCanceled()) + return; + + std::unique_ptr taskTree(new TaskTree(interDeviceTransfer(source, destination))); + + QEventLoop eventLoop; + bool finalized = false; + const auto finalize = [loop = &eventLoop, &taskTree, &finalized](int exitCode) { + if (finalized) // finalize only once + return; + finalized = true; + // Give the tree a chance to delete later all tasks that have finished and caused + // emission of tree's done or errorOccurred signal. + // TODO: maybe these signals should be sent queued already? + QMetaObject::invokeMethod(loop, [loop, &taskTree, exitCode] { + taskTree.reset(); + loop->exit(exitCode); + }, Qt::QueuedConnection); + }; + QTimer timer; + timer.setInterval(50); + QObject::connect(&timer, &QTimer::timeout, [&promise, finalize] { + if (promise.isCanceled()) + finalize(2); + }); + QObject::connect(taskTree.get(), &TaskTree::done, &eventLoop, [=] { finalize(0); }); + QObject::connect(taskTree.get(), &TaskTree::errorOccurred, &eventLoop, [=] { finalize(1); }); + taskTree->start(); + timer.start(); + if (eventLoop.exec()) + promise.future().cancel(); +} + +class FileStreamerPrivate : public QObject +{ +public: + StreamMode m_streamerMode = StreamMode::Transfer; + FilePath m_source; + FilePath m_destination; + QByteArray m_readBuffer; + QByteArray m_writeBuffer; + StreamResult m_streamResult = StreamResult::FinishedWithError; + std::unique_ptr m_taskTree; + + TaskItem task() { + if (m_streamerMode == StreamMode::Reader) + return readerTask(); + if (m_streamerMode == StreamMode::Writer) + return writerTask(); + return transferTask(); + } + +private: + TaskItem readerTask() { + const auto setup = [this](FileStreamReader &reader) { + m_readBuffer.clear(); + reader.setFilePath(m_source); + connect(&reader, &FileStreamReader::readyRead, this, [this](const QByteArray &data) { + m_readBuffer += data; + }); + }; + return Reader(setup); + } + TaskItem writerTask() { + const auto setup = [this](FileStreamWriter &writer) { + writer.setFilePath(m_destination); + writer.setWriteData(m_writeBuffer); + }; + return Writer(setup); + } + TaskItem transferTask() { + const auto setup = [this](AsyncTask &async) { + async.setConcurrentCallData(transfer, m_source, m_destination); + }; + return Async(setup); + } +}; + +FileStreamer::FileStreamer(QObject *parent) + : QObject(parent) + , d(new FileStreamerPrivate) +{ +} + +FileStreamer::~FileStreamer() +{ + delete d; +} + +void FileStreamer::setSource(const FilePath &source) +{ + d->m_source = source; +} + +void FileStreamer::setDestination(const FilePath &destination) +{ + d->m_destination = destination; +} + +void FileStreamer::setStreamMode(StreamMode mode) +{ + d->m_streamerMode = mode; +} + +QByteArray FileStreamer::readData() const +{ + return d->m_readBuffer; +} + +void FileStreamer::setWriteData(const QByteArray &writeData) +{ + d->m_writeBuffer = writeData; +} + +StreamResult FileStreamer::result() const +{ + return d->m_streamResult; +} + +void FileStreamer::start() +{ + // TODO: Preliminary check if local source exists? + QTC_ASSERT(!d->m_taskTree, return); + d->m_taskTree.reset(new TaskTree({d->task()})); + const auto finalize = [this](bool success) { + d->m_streamResult = success ? StreamResult::FinishedWithSuccess + : StreamResult::FinishedWithError; + d->m_taskTree.release()->deleteLater(); + emit done(); + }; + connect(d->m_taskTree.get(), &TaskTree::done, this, [=] { finalize(true); }); + connect(d->m_taskTree.get(), &TaskTree::errorOccurred, this, [=] { finalize(false); }); + d->m_taskTree->start(); +} + +void FileStreamer::stop() +{ + d->m_taskTree.reset(); +} + +} // namespace Utils + +#include "filestreamer.moc" diff --git a/src/libs/utils/filestreamer.h b/src/libs/utils/filestreamer.h new file mode 100644 index 00000000000..b572e910a20 --- /dev/null +++ b/src/libs/utils/filestreamer.h @@ -0,0 +1,62 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "utils_global.h" + +#include "filepath.h" +#include "tasktree.h" + +#include + +QT_BEGIN_NAMESPACE +class QByteArray; +QT_END_NAMESPACE + +namespace Utils { + +enum class StreamMode { Reader, Writer, Transfer }; + +enum class StreamResult { FinishedWithSuccess, FinishedWithError }; + +class QTCREATOR_UTILS_EXPORT FileStreamer final : public QObject +{ + Q_OBJECT + +public: + FileStreamer(QObject *parent = nullptr); + ~FileStreamer(); + + void setSource(const FilePath &source); + void setDestination(const FilePath &destination); + void setStreamMode(StreamMode mode); // Transfer by default + + // Only for Reader mode + QByteArray readData() const; + // Only for Writer mode + void setWriteData(const QByteArray &writeData); + + StreamResult result() const; + + void start(); + void stop(); + +signals: + void done(); + +private: + class FileStreamerPrivate *d = nullptr; +}; + +class FileStreamerAdapter : public Utils::Tasking::TaskAdapter +{ +public: + FileStreamerAdapter() { connect(task(), &FileStreamer::done, this, + [this] { emit done(task()->result() == StreamResult::FinishedWithSuccess); }); } + void start() override { task()->start(); } +}; + +} // namespace Utils + +QTC_DECLARE_CUSTOM_TASK(Streamer, Utils::FileStreamerAdapter); diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index cf952ae62d8..8c0312ed03b 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -127,6 +127,8 @@ Project { "filepath.h", "filesearch.cpp", "filesearch.h", + "filestreamer.cpp", + "filestreamer.h", "filesystemmodel.cpp", "filesystemmodel.h", "filesystemwatcher.cpp", diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index fcc8477974a..fa3f654f388 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -86,6 +87,44 @@ void FileSystemAccessTest::initTestCase() QVERIFY(!filePath.exists()); QVERIFY(filePath.createDir()); QVERIFY(filePath.exists()); + + const QString streamerDir("streamerDir"); + const QString sourceDir("source"); + const QString destDir("dest"); + const QString localDir("local"); + const QString remoteDir("remote"); + const FilePath localRoot; + const FilePath remoteRoot = m_device->rootPath(); + const FilePath localTempDir = *localRoot.tmpDir(); + const FilePath remoteTempDir = *remoteRoot.tmpDir(); + m_localStreamerDir = localTempDir / streamerDir; + m_remoteStreamerDir = remoteTempDir / streamerDir; + m_localSourceDir = m_localStreamerDir / sourceDir; + m_remoteSourceDir = m_remoteStreamerDir / sourceDir; + m_localDestDir = m_localStreamerDir / destDir; + m_remoteDestDir = m_remoteStreamerDir / destDir; + m_localLocalDestDir = m_localDestDir / localDir; + m_localRemoteDestDir = m_localDestDir / remoteDir; + m_remoteLocalDestDir = m_remoteDestDir / localDir; + m_remoteRemoteDestDir = m_remoteDestDir / remoteDir; + + QVERIFY(m_localSourceDir.createDir()); + QVERIFY(m_remoteSourceDir.createDir()); + QVERIFY(m_localDestDir.createDir()); + QVERIFY(m_remoteDestDir.createDir()); + QVERIFY(m_localLocalDestDir.createDir()); + QVERIFY(m_localRemoteDestDir.createDir()); + QVERIFY(m_remoteLocalDestDir.createDir()); + QVERIFY(m_remoteRemoteDestDir.createDir()); + + QVERIFY(m_localSourceDir.exists()); + QVERIFY(m_remoteSourceDir.exists()); + QVERIFY(m_localDestDir.exists()); + QVERIFY(m_remoteDestDir.exists()); + QVERIFY(m_localLocalDestDir.exists()); + QVERIFY(m_localRemoteDestDir.exists()); + QVERIFY(m_remoteLocalDestDir.exists()); + QVERIFY(m_remoteRemoteDestDir.exists()); } void FileSystemAccessTest::cleanupTestCase() @@ -94,6 +133,12 @@ void FileSystemAccessTest::cleanupTestCase() return; QVERIFY(baseFilePath().exists()); QVERIFY(baseFilePath().removeRecursively()); + + QVERIFY(m_localStreamerDir.removeRecursively()); + QVERIFY(m_remoteStreamerDir.removeRecursively()); + + QVERIFY(!m_localStreamerDir.exists()); + QVERIFY(!m_remoteStreamerDir.exists()); } void FileSystemAccessTest::testCreateRemoteFile_data() @@ -102,13 +147,13 @@ void FileSystemAccessTest::testCreateRemoteFile_data() QTest::newRow("Spaces") << QByteArray("Line with spaces"); QTest::newRow("Newlines") << QByteArray("Some \n\n newlines \n"); - QTest::newRow("Carriage return") << QByteArray("Line with carriage \r return"); + QTest::newRow("CarriageReturn") << QByteArray("Line with carriage \r return"); QTest::newRow("Tab") << QByteArray("Line with \t tab"); QTest::newRow("Apostrophe") << QByteArray("Line with apostrophe's character"); - QTest::newRow("Quotation marks") << QByteArray("Line with \"quotation marks\""); - QTest::newRow("Backslash 1") << QByteArray("Line with \\ backslash"); - QTest::newRow("Backslash 2") << QByteArray("Line with \\\" backslash"); - QTest::newRow("Command output") << QByteArray("The date is: $(date +%D)"); + QTest::newRow("QuotationMarks") << QByteArray("Line with \"quotation marks\""); + QTest::newRow("Backslash1") << QByteArray("Line with \\ backslash"); + QTest::newRow("Backslash2") << QByteArray("Line with \\\" backslash"); + QTest::newRow("CommandOutput") << QByteArray("The date is: $(date +%D)"); const int charSize = sizeof(char) * 0x100; QByteArray charString(charSize, Qt::Uninitialized); @@ -201,6 +246,8 @@ void FileSystemAccessTest::testFileTransfer_data() QTest::addColumn("fileTransferMethod"); QTest::addRow("Sftp") << FileTransferMethod::Sftp; + // TODO: By default rsync doesn't support creating target directories, + // needs to be done manually - see RsyncDeployService. // QTest::addRow("Rsync") << FileTransferMethod::Rsync; } @@ -282,5 +329,303 @@ void FileSystemAccessTest::testFileTransfer() QVERIFY2(remoteDir.removeRecursively(&errorString), qPrintable(errorString)); } +void FileSystemAccessTest::testFileStreamer_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("data"); + + const QByteArray spaces("Line with spaces"); + const QByteArray newlines("Some \n\n newlines \n"); + const QByteArray carriageReturn("Line with carriage \r return"); + const QByteArray tab("Line with \t tab"); + const QByteArray apostrophe("Line with apostrophe's character"); + const QByteArray quotationMarks("Line with \"quotation marks\""); + const QByteArray backslash1("Line with \\ backslash"); + const QByteArray backslash2("Line with \\\" backslash"); + const QByteArray commandOutput("The date is: $(date +%D)"); + + const int charSize = sizeof(char) * 0x100; + QByteArray charString(charSize, Qt::Uninitialized); + char *data = charString.data(); + for (int c = 0; c < charSize; ++c) + data[c] = c; + + const int bigSize = 1024 * 1024; // = 256 * 1024 * 1024 = 268.435.456 bytes + QByteArray bigString; + for (int i = 0; i < bigSize; ++i) + bigString += charString; + + QTest::newRow("Spaces") << QString("spaces") << spaces; + QTest::newRow("Newlines") << QString("newlines") << newlines; + QTest::newRow("CarriageReturn") << QString("carriageReturn") << carriageReturn; + QTest::newRow("Tab") << QString("tab") << tab; + QTest::newRow("Apostrophe") << QString("apostrophe") << apostrophe; + QTest::newRow("QuotationMarks") << QString("quotationMarks") << quotationMarks; + QTest::newRow("Backslash1") << QString("backslash1") << backslash1; + QTest::newRow("Backslash2") << QString("backslash2") << backslash2; + QTest::newRow("CommandOutput") << QString("commandOutput") << commandOutput; + QTest::newRow("AllCharacters") << QString("charString") << charString; + QTest::newRow("BigString") << QString("bigString") << bigString; +} + +void FileSystemAccessTest::testFileStreamer() +{ + QElapsedTimer timer; + timer.start(); + + QFETCH(QString, fileName); + QFETCH(QByteArray, data); + + const FilePath localSourcePath = m_localSourceDir / fileName; + const FilePath remoteSourcePath = m_remoteSourceDir / fileName; + const FilePath localLocalDestPath = m_localDestDir / "local" / fileName; + const FilePath localRemoteDestPath = m_localDestDir / "remote" / fileName; + const FilePath remoteLocalDestPath = m_remoteDestDir / "local" / fileName; + const FilePath remoteRemoteDestPath = m_remoteDestDir / "remote" / fileName; + + localSourcePath.removeFile(); + remoteSourcePath.removeFile(); + localLocalDestPath.removeFile(); + localRemoteDestPath.removeFile(); + remoteLocalDestPath.removeFile(); + remoteRemoteDestPath.removeFile(); + + QVERIFY(!localSourcePath.exists()); + QVERIFY(!remoteSourcePath.exists()); + QVERIFY(!localLocalDestPath.exists()); + QVERIFY(!localRemoteDestPath.exists()); + QVERIFY(!remoteLocalDestPath.exists()); + QVERIFY(!remoteRemoteDestPath.exists()); + + std::optional localData; + std::optional remoteData; + std::optional localLocalData; + std::optional localRemoteData; + std::optional remoteLocalData; + std::optional remoteRemoteData; + + using namespace Tasking; + + const auto localWriter = [&] { + const auto setup = [&](FileStreamer &streamer) { + streamer.setStreamMode(StreamMode::Writer); + streamer.setDestination(localSourcePath); + streamer.setWriteData(data); + }; + return Streamer(setup); + }; + const auto remoteWriter = [&] { + const auto setup = [&](FileStreamer &streamer) { + streamer.setStreamMode(StreamMode::Writer); + streamer.setDestination(remoteSourcePath); + streamer.setWriteData(data); + }; + return Streamer(setup); + }; + const auto localReader = [&] { + const auto setup = [&](FileStreamer &streamer) { + streamer.setStreamMode(StreamMode::Reader); + streamer.setSource(localSourcePath); + }; + const auto onDone = [&](const FileStreamer &streamer) { + localData = streamer.readData(); + }; + return Streamer(setup, onDone); + }; + const auto remoteReader = [&] { + const auto setup = [&](FileStreamer &streamer) { + streamer.setStreamMode(StreamMode::Reader); + streamer.setSource(remoteSourcePath); + }; + const auto onDone = [&](const FileStreamer &streamer) { + remoteData = streamer.readData(); + }; + return Streamer(setup, onDone); + }; + const auto transfer = [](const FilePath &source, const FilePath &dest, + std::optional *result) { + const auto setupTransfer = [=](FileStreamer &streamer) { + streamer.setSource(source); + streamer.setDestination(dest); + }; + const auto setupReader = [=](FileStreamer &streamer) { + streamer.setStreamMode(StreamMode::Reader); + streamer.setSource(dest); + }; + const auto onReaderDone = [result](const FileStreamer &streamer) { + *result = streamer.readData(); + }; + const Group root { + Streamer(setupTransfer), + Streamer(setupReader, onReaderDone) + }; + return root; + }; + + // In total: 5 local reads, 3 local writes, 5 remote reads, 3 remote writes + const Group root { + Group { + parallel, + localWriter(), + remoteWriter() + }, + Group { + parallel, + localReader(), + remoteReader() + }, + Group { + parallel, + transfer(localSourcePath, localLocalDestPath, &localLocalData), + transfer(remoteSourcePath, localRemoteDestPath, &localRemoteData), + transfer(localSourcePath, remoteLocalDestPath, &remoteLocalData), + transfer(remoteSourcePath, remoteRemoteDestPath, &remoteRemoteData), + } + }; + + QEventLoop eventLoop; + TaskTree taskTree(root); + int doneCount = 0; + int errorCount = 0; + connect(&taskTree, &TaskTree::done, this, [&doneCount, &eventLoop] { + ++doneCount; + eventLoop.quit(); + }); + connect(&taskTree, &TaskTree::errorOccurred, this, [&errorCount, &eventLoop] { + ++errorCount; + eventLoop.quit(); + }); + taskTree.start(); + QVERIFY(taskTree.isRunning()); + + QTimer timeoutTimer; + bool timedOut = false; + connect(&timeoutTimer, &QTimer::timeout, &eventLoop, [&eventLoop, &timedOut] { + timedOut = true; + eventLoop.quit(); + }); + timeoutTimer.setInterval(10000); + timeoutTimer.setSingleShot(true); + timeoutTimer.start(); + eventLoop.exec(); + QCOMPARE(timedOut, false); + QCOMPARE(taskTree.isRunning(), false); + QCOMPARE(doneCount, 1); + QCOMPARE(errorCount, 0); + + QVERIFY(localData); + QCOMPARE(*localData, data); + QVERIFY(remoteData); + QCOMPARE(*remoteData, data); + + QVERIFY(localLocalData); + QCOMPARE(*localLocalData, data); + QVERIFY(localRemoteData); + QCOMPARE(*localRemoteData, data); + QVERIFY(remoteLocalData); + QCOMPARE(*remoteLocalData, data); + QVERIFY(remoteRemoteData); + QCOMPARE(*remoteRemoteData, data); + + qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; +} + +void FileSystemAccessTest::testBlockingTransfer_data() +{ + testFileStreamer_data(); +} + +void FileSystemAccessTest::testBlockingTransfer() +{ + QElapsedTimer timer; + timer.start(); + + QFETCH(QString, fileName); + QFETCH(QByteArray, data); + + const FilePath localSourcePath = m_localSourceDir / fileName; + const FilePath remoteSourcePath = m_remoteSourceDir / fileName; + const FilePath localLocalDestPath = m_localDestDir / "local" / fileName; + const FilePath localRemoteDestPath = m_localDestDir / "remote" / fileName; + const FilePath remoteLocalDestPath = m_remoteDestDir / "local" / fileName; + const FilePath remoteRemoteDestPath = m_remoteDestDir / "remote" / fileName; + + localSourcePath.removeFile(); + remoteSourcePath.removeFile(); + localLocalDestPath.removeFile(); + localRemoteDestPath.removeFile(); + remoteLocalDestPath.removeFile(); + remoteRemoteDestPath.removeFile(); + + QVERIFY(!localSourcePath.exists()); + QVERIFY(!remoteSourcePath.exists()); + QVERIFY(!localLocalDestPath.exists()); + QVERIFY(!localRemoteDestPath.exists()); + QVERIFY(!remoteLocalDestPath.exists()); + QVERIFY(!remoteRemoteDestPath.exists()); + + bool writerHit = false; + const auto writeChecker = [&](const expected_str &res) { + writerHit = true; + QVERIFY(res); + }; + + bool readerHit = false; + const auto readChecker = [&](const QByteArray &expected) { + return [&](const expected_str &result) { + readerHit = true; + QCOMPARE(result, expected); + }; + }; + + bool dummyHit = false; + const auto dummy = [&](const expected_str &res) { + dummyHit = true; + QVERIFY(res); + }; + + localSourcePath.asyncWriteFileContents(writeChecker, data); + localSourcePath.asyncFileContents(readChecker(data)); + QVERIFY(writerHit); + QVERIFY(readerHit); + + writerHit = false; + readerHit = false; + remoteSourcePath.asyncWriteFileContents(writeChecker, data); + remoteSourcePath.asyncFileContents(readChecker(data)); + QVERIFY(writerHit); + QVERIFY(readerHit); + + dummyHit = false; + readerHit = false; + localSourcePath.asyncCopyFile(dummy, localLocalDestPath); + localLocalDestPath.asyncFileContents(readChecker(data)); + QVERIFY(dummyHit); + QVERIFY(readerHit); + + dummyHit = false; + readerHit = false; + remoteSourcePath.asyncCopyFile(dummy, localRemoteDestPath); + localRemoteDestPath.asyncFileContents(readChecker(data)); + QVERIFY(dummyHit); + QVERIFY(readerHit); + + dummyHit = false; + readerHit = false; + localSourcePath.asyncCopyFile(dummy, remoteLocalDestPath); + remoteLocalDestPath.asyncFileContents(readChecker(data)); + QVERIFY(dummyHit); + QVERIFY(readerHit); + + dummyHit = false; + readerHit = false; + remoteSourcePath.asyncCopyFile(dummy, remoteRemoteDestPath); + remoteRemoteDestPath.asyncFileContents(readChecker(data)); + QVERIFY(dummyHit); + QVERIFY(readerHit); + + qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; +} + } // Internal } // RemoteLinux diff --git a/src/plugins/remotelinux/filesystemaccess_test.h b/src/plugins/remotelinux/filesystemaccess_test.h index 9684cbc9264..f7101af3908 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.h +++ b/src/plugins/remotelinux/filesystemaccess_test.h @@ -4,6 +4,7 @@ #pragma once #include +#include namespace RemoteLinux { namespace Internal { @@ -28,6 +29,10 @@ private slots: void testFileActions(); void testFileTransfer_data(); void testFileTransfer(); + void testFileStreamer_data(); + void testFileStreamer(); + void testBlockingTransfer_data(); + void testBlockingTransfer(); void cleanupTestCase(); @@ -35,6 +40,16 @@ private: TestLinuxDeviceFactory m_testLinuxDeviceFactory; bool m_skippedAtWhole = false; ProjectExplorer::IDeviceConstPtr m_device; + Utils::FilePath m_localStreamerDir; + Utils::FilePath m_remoteStreamerDir; + Utils::FilePath m_localSourceDir; + Utils::FilePath m_remoteSourceDir; + Utils::FilePath m_localDestDir; + Utils::FilePath m_remoteDestDir; + Utils::FilePath m_localLocalDestDir; + Utils::FilePath m_localRemoteDestDir; + Utils::FilePath m_remoteLocalDestDir; + Utils::FilePath m_remoteRemoteDestDir; }; } // Internal From c1b1842c48632970cd0ddce79a80801afcae2043 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 27 Feb 2023 15:54:14 +0100 Subject: [PATCH 0150/1447] Utils: Introduce FileStreamerManager To be used for FilePath::async[Copy/Read/Write]() methods. Change-Id: Ie34e600f8d65eae10b41893e15685afe19ce2a46 Reviewed-by: hjk --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/filestreamermanager.cpp | 200 ++++++++++++++++++ src/libs/utils/filestreamermanager.h | 46 ++++ src/libs/utils/utils.qbs | 2 + .../remotelinux/filesystemaccess_test.cpp | 124 ++++++++++- .../remotelinux/filesystemaccess_test.h | 2 + 6 files changed, 372 insertions(+), 3 deletions(-) create mode 100644 src/libs/utils/filestreamermanager.cpp create mode 100644 src/libs/utils/filestreamermanager.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index e8adad413e4..e296f2857a3 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -56,6 +56,7 @@ add_qtc_library(Utils filepathinfo.h filesearch.cpp filesearch.h filestreamer.cpp filestreamer.h + filestreamermanager.cpp filestreamermanager.h filesystemmodel.cpp filesystemmodel.h filesystemwatcher.cpp filesystemwatcher.h fileutils.cpp fileutils.h diff --git a/src/libs/utils/filestreamermanager.cpp b/src/libs/utils/filestreamermanager.cpp new file mode 100644 index 00000000000..5a1ec9847ea --- /dev/null +++ b/src/libs/utils/filestreamermanager.cpp @@ -0,0 +1,200 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "filestreamermanager.h" + +#include "filestreamer.h" +#include "threadutils.h" +#include "utilstr.h" + +#include +#include +#include +#include + +#include + +namespace Utils { + +// TODO: destruct the instance before destructing ProjectExplorer::DeviceManager (?) + +static FileStreamHandle generateUniqueHandle() +{ + static std::atomic_int handleCounter = 1; + return FileStreamHandle(handleCounter.fetch_add(1)); +} + +static QMutex s_mutex = {}; +static QWaitCondition s_waitCondition = {}; +static std::unordered_map s_fileStreamers = {}; + +static void addStreamer(FileStreamHandle handle, FileStreamer *streamer) +{ + QMutexLocker locker(&s_mutex); + const bool added = s_fileStreamers.try_emplace(handle, streamer).second; + QTC_CHECK(added); +} + +static void removeStreamer(FileStreamHandle handle) +{ + QMutexLocker locker(&s_mutex); + auto it = s_fileStreamers.find(handle); + QTC_ASSERT(it != s_fileStreamers.end(), return); + QTC_ASSERT(QThread::currentThread() == it->second->thread(), return); + s_fileStreamers.erase(it); + s_waitCondition.wakeAll(); +} + +static void deleteStreamer(FileStreamHandle handle) +{ + QMutexLocker locker(&s_mutex); + auto it = s_fileStreamers.find(handle); + if (it != s_fileStreamers.end()) + return; + if (QThread::currentThread() == it->second->thread()) { + delete it->second; + s_fileStreamers.erase(it); + s_waitCondition.wakeAll(); + } else { + QMetaObject::invokeMethod(it->second, [handle] { + deleteStreamer(handle); + }); + s_waitCondition.wait(&s_mutex); + QTC_CHECK(s_fileStreamers.find(handle) == s_fileStreamers.end()); + } +} + +static void deleteAllStreamers() +{ + QMutexLocker locker(&s_mutex); + QTC_ASSERT(Utils::isMainThread(), return); + while (s_fileStreamers.size()) { + auto it = s_fileStreamers.begin(); + if (QThread::currentThread() == it->second->thread()) { + delete it->second; + s_fileStreamers.erase(it); + s_waitCondition.wakeAll(); + } else { + const FileStreamHandle handle = it->first; + QMetaObject::invokeMethod(it->second, [handle] { + deleteStreamer(handle); + }); + s_waitCondition.wait(&s_mutex); + QTC_CHECK(s_fileStreamers.find(handle) == s_fileStreamers.end()); + } + } +} + +static FileStreamHandle checkHandle(FileStreamHandle handle) +{ + QMutexLocker locker(&s_mutex); + return s_fileStreamers.find(handle) != s_fileStreamers.end() ? handle : FileStreamHandle(0); +} + +FileStreamHandle execute(const std::function &onSetup, + const std::function &onDone, + QObject *context) +{ + FileStreamer *streamer = new FileStreamer; + onSetup(streamer); + const FileStreamHandle handle = generateUniqueHandle(); + QTC_CHECK(context == nullptr || context->thread() == QThread::currentThread()); + QObject *finalContext = context ? context : streamer; + QObject::connect(streamer, &FileStreamer::done, finalContext, [=] { + if (onDone) + onDone(streamer); + removeStreamer(handle); + streamer->deleteLater(); + }); + addStreamer(handle, streamer); + streamer->start(); + return checkHandle(handle); // The handle could have been already removed +} + +FileStreamHandle FileStreamerManager::copy(const FilePath &source, const FilePath &destination, + const CopyContinuation &cont) +{ + return copy(source, destination, nullptr, cont); +} + +FileStreamHandle FileStreamerManager::copy(const FilePath &source, const FilePath &destination, + QObject *context, const CopyContinuation &cont) +{ + const auto onSetup = [=](FileStreamer *streamer) { + streamer->setSource(source); + streamer->setDestination(destination); + }; + if (!cont) + return execute(onSetup, {}, context); + + const auto onDone = [=](FileStreamer *streamer) { + if (streamer->result() == StreamResult::FinishedWithSuccess) + cont({}); + else + cont(make_unexpected(Tr::tr("Failed copying file"))); + }; + return execute(onSetup, onDone, context); +} + +FileStreamHandle FileStreamerManager::read(const FilePath &source, const ReadContinuation &cont) +{ + return read(source, nullptr, cont); +} + +FileStreamHandle FileStreamerManager::read(const FilePath &source, QObject *context, + const ReadContinuation &cont) +{ + const auto onSetup = [=](FileStreamer *streamer) { + streamer->setStreamMode(StreamMode::Reader); + streamer->setSource(source); + }; + if (!cont) + return execute(onSetup, {}, context); + + const auto onDone = [=](FileStreamer *streamer) { + if (streamer->result() == StreamResult::FinishedWithSuccess) + cont(streamer->readData()); + else + cont(make_unexpected(Tr::tr("Failed reading file"))); + }; + return execute(onSetup, onDone, context); +} + +FileStreamHandle FileStreamerManager::write(const FilePath &destination, const QByteArray &data, + const WriteContinuation &cont) +{ + return write(destination, data, nullptr, cont); +} + +FileStreamHandle FileStreamerManager::write(const FilePath &destination, const QByteArray &data, + QObject *context, const WriteContinuation &cont) +{ + const auto onSetup = [=](FileStreamer *streamer) { + streamer->setStreamMode(StreamMode::Writer); + streamer->setDestination(destination); + streamer->setWriteData(data); + }; + if (!cont) + return execute(onSetup, {}, context); + + const auto onDone = [=](FileStreamer *streamer) { + if (streamer->result() == StreamResult::FinishedWithSuccess) + cont(0); // TODO: return write count? + else + cont(make_unexpected(Tr::tr("Failed writing file"))); + }; + return execute(onSetup, onDone, context); +} + +void FileStreamerManager::stop(FileStreamHandle handle) +{ + deleteStreamer(handle); +} + +void FileStreamerManager::stopAll() +{ + deleteAllStreamers(); +} + +} // namespace Utils + diff --git a/src/libs/utils/filestreamermanager.h b/src/libs/utils/filestreamermanager.h new file mode 100644 index 00000000000..261d58ba299 --- /dev/null +++ b/src/libs/utils/filestreamermanager.h @@ -0,0 +1,46 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "utils_global.h" + +#include "filepath.h" + +#include + +QT_BEGIN_NAMESPACE +class QByteArray; +QT_END_NAMESPACE + +namespace Utils { + +enum FileStreamHandle : int {}; + +class QTCREATOR_UTILS_EXPORT FileStreamerManager +{ +public: + using CopyContinuation = Continuation &>; + using ReadContinuation = Continuation &>; + using WriteContinuation = Continuation &>; + + static FileStreamHandle copy(const FilePath &source, const FilePath &destination, + const CopyContinuation &cont); + static FileStreamHandle copy(const FilePath &source, const FilePath &destination, + QObject *context, const CopyContinuation &cont); + + static FileStreamHandle read(const FilePath &source, const ReadContinuation &cont = {}); + static FileStreamHandle read(const FilePath &source, QObject *context, + const ReadContinuation &cont = {}); + + static FileStreamHandle write(const FilePath &destination, const QByteArray &data, + const WriteContinuation &cont = {}); + static FileStreamHandle write(const FilePath &destination, const QByteArray &data, + QObject *context, const WriteContinuation &cont = {}); + + // If called from the same thread that started the task, no continuation is going to be called. + static void stop(FileStreamHandle handle); + static void stopAll(); +}; + +} // namespace Utils diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 8c0312ed03b..9e3d1eaeaaf 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -129,6 +129,8 @@ Project { "filesearch.h", "filestreamer.cpp", "filestreamer.h", + "filestreamermanager.cpp", + "filestreamermanager.h", "filesystemmodel.cpp", "filesystemmodel.h", "filesystemwatcher.cpp", diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index fa3f654f388..268e36acb4f 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -88,7 +89,8 @@ void FileSystemAccessTest::initTestCase() QVERIFY(filePath.createDir()); QVERIFY(filePath.exists()); - const QString streamerDir("streamerDir"); + const QString streamerLocalDir("streamerLocalDir"); + const QString streamerRemoteDir("streamerRemoteDir"); const QString sourceDir("source"); const QString destDir("dest"); const QString localDir("local"); @@ -97,8 +99,8 @@ void FileSystemAccessTest::initTestCase() const FilePath remoteRoot = m_device->rootPath(); const FilePath localTempDir = *localRoot.tmpDir(); const FilePath remoteTempDir = *remoteRoot.tmpDir(); - m_localStreamerDir = localTempDir / streamerDir; - m_remoteStreamerDir = remoteTempDir / streamerDir; + m_localStreamerDir = localTempDir / streamerLocalDir; + m_remoteStreamerDir = remoteTempDir / streamerRemoteDir; m_localSourceDir = m_localStreamerDir / sourceDir; m_remoteSourceDir = m_remoteStreamerDir / sourceDir; m_localDestDir = m_localStreamerDir / destDir; @@ -139,6 +141,8 @@ void FileSystemAccessTest::cleanupTestCase() QVERIFY(!m_localStreamerDir.exists()); QVERIFY(!m_remoteStreamerDir.exists()); + + FileStreamerManager::stopAll(); } void FileSystemAccessTest::testCreateRemoteFile_data() @@ -530,6 +534,120 @@ void FileSystemAccessTest::testFileStreamer() qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; } +void FileSystemAccessTest::testFileStreamerManager_data() +{ + testFileStreamer_data(); +} + +void FileSystemAccessTest::testFileStreamerManager() +{ + QElapsedTimer timer; + timer.start(); + + QFETCH(QString, fileName); + QFETCH(QByteArray, data); + + const FilePath localSourcePath = m_localSourceDir / fileName; + const FilePath remoteSourcePath = m_remoteSourceDir / fileName; + const FilePath localLocalDestPath = m_localDestDir / "local" / fileName; + const FilePath localRemoteDestPath = m_localDestDir / "remote" / fileName; + const FilePath remoteLocalDestPath = m_remoteDestDir / "local" / fileName; + const FilePath remoteRemoteDestPath = m_remoteDestDir / "remote" / fileName; + + localSourcePath.removeFile(); + remoteSourcePath.removeFile(); + localLocalDestPath.removeFile(); + localRemoteDestPath.removeFile(); + remoteLocalDestPath.removeFile(); + remoteRemoteDestPath.removeFile(); + + QVERIFY(!localSourcePath.exists()); + QVERIFY(!remoteSourcePath.exists()); + QVERIFY(!localLocalDestPath.exists()); + QVERIFY(!localRemoteDestPath.exists()); + QVERIFY(!remoteLocalDestPath.exists()); + QVERIFY(!remoteRemoteDestPath.exists()); + + std::optional localData; + std::optional remoteData; + std::optional localLocalData; + std::optional localRemoteData; + std::optional remoteLocalData; + std::optional remoteRemoteData; + + QEventLoop eventLoop1; + QEventLoop *loop = &eventLoop1; + int counter = 0; + int *hitCount = &counter; + + const auto writeAndRead = [hitCount, loop, data](const FilePath &destination, + std::optional *result) { + const auto onWrite = [hitCount, loop, destination, result] + (const expected_str &writeResult) { + QVERIFY(writeResult); + const auto onRead = [hitCount, loop, result] + (const expected_str &readResult) { + QVERIFY(readResult); + *result = *readResult; + ++(*hitCount); + if (*hitCount == 2) + loop->quit(); + }; + FileStreamerManager::read(destination, onRead); + }; + FileStreamerManager::write(destination, data, onWrite); + }; + + writeAndRead(localSourcePath, &localData); + writeAndRead(remoteSourcePath, &remoteData); + loop->exec(); + + QVERIFY(localData); + QCOMPARE(*localData, data); + QVERIFY(remoteData); + QCOMPARE(*remoteData, data); + + QEventLoop eventLoop2; + loop = &eventLoop2; + counter = 0; + + const auto transferAndRead = [hitCount, loop, data](const FilePath &source, + const FilePath &destination, + std::optional *result) { + const auto onTransfer = [hitCount, loop, destination, result] + (const expected_str &transferResult) { + QVERIFY(transferResult); + const auto onRead = [hitCount, loop, result] + (const expected_str &readResult) { + QVERIFY(readResult); + *result = *readResult; + ++(*hitCount); + if (*hitCount == 4) + loop->quit(); + }; + FileStreamerManager::read(destination, onRead); + }; + FileStreamerManager::copy(source, destination, onTransfer); + }; + + transferAndRead(localSourcePath, localLocalDestPath, &localLocalData); + transferAndRead(remoteSourcePath, localRemoteDestPath, &localRemoteData); + transferAndRead(localSourcePath, remoteLocalDestPath, &remoteLocalData); + transferAndRead(remoteSourcePath, remoteRemoteDestPath, &remoteRemoteData); + loop->exec(); + + QVERIFY(localLocalData); + QCOMPARE(*localLocalData, data); + QVERIFY(localRemoteData); + QCOMPARE(*localRemoteData, data); + QVERIFY(remoteLocalData); + QCOMPARE(*remoteLocalData, data); + QVERIFY(remoteRemoteData); + QCOMPARE(*remoteRemoteData, data); + + qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; +} + void FileSystemAccessTest::testBlockingTransfer_data() { testFileStreamer_data(); diff --git a/src/plugins/remotelinux/filesystemaccess_test.h b/src/plugins/remotelinux/filesystemaccess_test.h index f7101af3908..2d3e6ae241b 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.h +++ b/src/plugins/remotelinux/filesystemaccess_test.h @@ -31,6 +31,8 @@ private slots: void testFileTransfer(); void testFileStreamer_data(); void testFileStreamer(); + void testFileStreamerManager_data(); + void testFileStreamerManager(); void testBlockingTransfer_data(); void testBlockingTransfer(); From 30760747a321485e5e69a057235aae42830d3130 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 2 Mar 2023 23:44:36 +0100 Subject: [PATCH 0151/1447] FileStreamer: Optimize transfer on the same device Run just "cp" on device instead of transferring the content of the source into local and sending it back again to remote. Change-Id: I703ad1181d77d470ae145691979c34fc75b59a97 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/filestreamer.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 222488a5100..47cbffd3c27 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -304,7 +304,21 @@ QTC_DECLARE_CUSTOM_TASK(Writer, Utils::FileStreamWriterAdapter); namespace Utils { -static Group interDeviceTransfer(const FilePath &source, const FilePath &destination) +static Group sameRemoteDeviceTransferTask(const FilePath &source, const FilePath &destination) +{ + QTC_CHECK(source.needsDevice()); + QTC_CHECK(destination.needsDevice()); + QTC_CHECK(source.isSameDevice(destination)); + + const auto setup = [source, destination](QtcProcess &process) { + const QStringList args = {source.path(), destination.path()}; + const FilePath cp = source.withNewPath("cp"); + process.setCommand({cp, args, OsType::OsTypeLinux}); + }; + return {Process(setup)}; +} + +static Group interDeviceTransferTask(const FilePath &source, const FilePath &destination) { struct TransferStorage { QPointer writer; }; Condition condition; @@ -342,12 +356,19 @@ static Group interDeviceTransfer(const FilePath &source, const FilePath &destina return root; } +static Group transferTask(const FilePath &source, const FilePath &destination) +{ + if (source.needsDevice() && destination.needsDevice() && source.isSameDevice(destination)) + return sameRemoteDeviceTransferTask(source, destination); + return interDeviceTransferTask(source, destination); +} + static void transfer(QPromise &promise, const FilePath &source, const FilePath &destination) { if (promise.isCanceled()) return; - std::unique_ptr taskTree(new TaskTree(interDeviceTransfer(source, destination))); + std::unique_ptr taskTree(new TaskTree(transferTask(source, destination))); QEventLoop eventLoop; bool finalized = false; From 7214d794209d3c5770d481615a428de88fa99873 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 3 Mar 2023 11:17:08 +0100 Subject: [PATCH 0152/1447] Start debugger dialog: Enable clear button for command line arguments Change-Id: Ia8d1a9a39ad61df37fd18a81e18d7e3e2ccad674 Reviewed-by: hjk --- src/plugins/debugger/debuggerdialogs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index ece2c226692..c382e91c175 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -212,6 +212,7 @@ StartApplicationDialog::StartApplicationDialog(QWidget *parent) d->localExecutablePathChooser->setHistoryCompleter("LocalExecutable"); d->arguments = new FancyLineEdit(this); + d->arguments->setClearButtonEnabled(true); d->arguments->setHistoryCompleter("CommandlineArguments"); d->workingDirectory = new PathChooser(this); From 47d375bbb419accc1b5af8c588a6fa86a52f1f52 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 28 Feb 2023 11:09:50 +0100 Subject: [PATCH 0153/1447] CPlusPlus: Support requires clause in parser Change-Id: Ice6a7a287453516a1cfc296e2c9f16160b3ea130 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.cpp | 2 ++ src/libs/3rdparty/cplusplus/AST.h | 22 +++++++++++++++++++++ src/libs/3rdparty/cplusplus/ASTClone.cpp | 11 +++++++++++ src/libs/3rdparty/cplusplus/ASTMatch0.cpp | 7 +++++++ src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 15 ++++++++++++++ src/libs/3rdparty/cplusplus/ASTMatcher.h | 1 + src/libs/3rdparty/cplusplus/ASTVisit.cpp | 8 ++++++++ src/libs/3rdparty/cplusplus/ASTVisitor.h | 2 ++ src/libs/3rdparty/cplusplus/ASTfwd.h | 1 + src/libs/3rdparty/cplusplus/Parser.cpp | 18 +++++++++++++++++ src/libs/3rdparty/cplusplus/Parser.h | 1 + tests/auto/cplusplus/cxx11/tst_cxx11.cpp | 23 ++++++++++++++++++++++ 12 files changed, 111 insertions(+) diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 260b3582713..2f351ff7be8 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -911,6 +911,8 @@ int DeclaratorAST::lastToken() const return candidate; if (equal_token) return equal_token + 1; + if (requiresClause) + return requiresClause->lastToken(); if (post_attribute_list) if (int candidate = post_attribute_list->lastToken()) return candidate; diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 9288725edd3..ff5759ffb2b 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -340,6 +340,7 @@ public: virtual TypeofSpecifierAST *asTypeofSpecifier() { return nullptr; } virtual UnaryExpressionAST *asUnaryExpression() { return nullptr; } virtual RequiresExpressionAST *asRequiresExpression() { return nullptr; } + virtual RequiresClauseAST *asRequiresClause() { return nullptr; } virtual UsingAST *asUsing() { return nullptr; } virtual UsingDirectiveAST *asUsingDirective() { return nullptr; } virtual WhileStatementAST *asWhileStatement() { return nullptr; } @@ -693,6 +694,7 @@ public: SpecifierListAST *post_attribute_list = nullptr; int equal_token = 0; ExpressionAST *initializer = nullptr; + RequiresClauseAST *requiresClause = nullptr; public: DeclaratorAST *asDeclarator() override { return this; } @@ -2763,6 +2765,7 @@ public: int less_token = 0; DeclarationListAST *template_parameter_list = nullptr; int greater_token = 0; + RequiresClauseAST *requiresClause = nullptr; DeclarationAST *declaration = nullptr; public: // annotations @@ -3020,6 +3023,25 @@ protected: bool match0(AST *, ASTMatcher *) override; }; +class CPLUSPLUS_EXPORT RequiresClauseAST: public AST +{ +public: + int requires_token = 0; + ExpressionAST *constraint = nullptr; + +public: + RequiresClauseAST *asRequiresClause() override { return this; } + + int firstToken() const override { return requires_token; } + int lastToken() const override { return constraint->lastToken(); } + + RequiresClauseAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + class CPLUSPLUS_EXPORT UsingAST: public DeclarationAST { public: diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 4e4cda40f9f..f4a2f626dad 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -1305,6 +1305,8 @@ TemplateDeclarationAST *TemplateDeclarationAST::clone(MemoryPool *pool) const iter; iter = iter->next, ast_iter = &(*ast_iter)->next) *ast_iter = new (pool) DeclarationListAST((iter->value) ? iter->value->clone(pool) : nullptr); ast->greater_token = greater_token; + if (requiresClause) + ast->requiresClause = requiresClause->clone(pool); if (declaration) ast->declaration = declaration->clone(pool); return ast; @@ -1338,6 +1340,15 @@ RequiresExpressionAST *RequiresExpressionAST::clone(MemoryPool *pool) const return ast; } +RequiresClauseAST *RequiresClauseAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) RequiresClauseAST; + ast->requires_token = requires_token; + if (constraint) + ast->constraint = constraint->clone(pool); + return ast; +} + ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const { ThrowExpressionAST *ast = new (pool) ThrowExpressionAST; diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index afe94aba06f..a4bd9935f0e 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -926,6 +926,13 @@ bool RequiresExpressionAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool RequiresClauseAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto other = pattern->asRequiresClause()) + return matcher->match(this, other); + return false; +} + bool ThrowExpressionAST::match0(AST *pattern, ASTMatcher *matcher) { if (ThrowExpressionAST *_other = pattern->asThrowExpression()) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index ccf41dbae2f..d39d0717c55 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -2205,6 +2205,11 @@ bool ASTMatcher::match(TemplateDeclarationAST *node, TemplateDeclarationAST *pat pattern->greater_token = node->greater_token; + if (! pattern->requiresClause) + pattern->requiresClause = node->requiresClause; + else if (! AST::match(node->requiresClause, pattern->requiresClause, this)) + return false; + if (! pattern->declaration) pattern->declaration = node->declaration; else if (! AST::match(node->declaration, pattern->declaration, this)) @@ -2247,6 +2252,16 @@ bool ASTMatcher::match(RequiresExpressionAST *node, RequiresExpressionAST *patte return true; } +bool ASTMatcher::match(RequiresClauseAST *node, RequiresClauseAST *pattern) +{ + pattern->requires_token = node->requires_token; + if (!pattern->constraint) + pattern->constraint = node->constraint; + else if (!AST::match(node->constraint, pattern->constraint, this)) + return false; + return true; +} + bool ASTMatcher::match(ThrowExpressionAST *node, ThrowExpressionAST *pattern) { (void) node; diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index 214c37a283b..c7d762c9e11 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -158,6 +158,7 @@ public: virtual bool match(QualifiedNameAST *node, QualifiedNameAST *pattern); virtual bool match(RangeBasedForStatementAST *node, RangeBasedForStatementAST *pattern); virtual bool match(ReferenceAST *node, ReferenceAST *pattern); + virtual bool match(RequiresClauseAST *node, RequiresClauseAST *pattern); virtual bool match(RequiresExpressionAST *node, RequiresExpressionAST *pattern); virtual bool match(ReturnStatementAST *node, ReturnStatementAST *pattern); virtual bool match(SimpleDeclarationAST *node, SimpleDeclarationAST *pattern); diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index cb05dbde62b..cde7842280d 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -958,6 +958,7 @@ void TemplateDeclarationAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { accept(template_parameter_list, visitor); + accept(requiresClause, visitor); accept(declaration, visitor); } visitor->endVisit(this); @@ -980,6 +981,13 @@ void RequiresExpressionAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void RequiresClauseAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) + accept(constraint, visitor); + visitor->endVisit(this); +} + void ThrowExpressionAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index 455936f9842..9f277836937 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -201,6 +201,7 @@ public: virtual bool visit(RangeBasedForStatementAST *) { return true; } virtual bool visit(ReferenceAST *) { return true; } virtual bool visit(RequiresExpressionAST *) { return true; } + virtual bool visit(RequiresClauseAST *) { return true; } virtual bool visit(ReturnStatementAST *) { return true; } virtual bool visit(SimpleDeclarationAST *) { return true; } virtual bool visit(SimpleNameAST *) { return true; } @@ -359,6 +360,7 @@ public: virtual void endVisit(RangeBasedForStatementAST *) {} virtual void endVisit(ReferenceAST *) {} virtual void endVisit(RequiresExpressionAST *) {} + virtual void endVisit(RequiresClauseAST *) {} virtual void endVisit(ReturnStatementAST *) {} virtual void endVisit(SimpleDeclarationAST *) {} virtual void endVisit(SimpleNameAST *) {} diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index f0899b2e1c8..b5222e2bbec 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -167,6 +167,7 @@ class QtPropertyDeclarationItemAST; class QualifiedNameAST; class RangeBasedForStatementAST; class ReferenceAST; +class RequiresClauseAST; class RequiresExpressionAST; class ReturnStatementAST; class SimpleDeclarationAST; diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index ed023b15f03..004bee40e71 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -1247,6 +1247,8 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) ast->less_token = consumeToken(); if (maybeSplitGreaterGreaterToken() || LA() == T_GREATER || parseTemplateParameterList(ast->template_parameter_list)) match(T_GREATER, &ast->greater_token); + if (!parseRequiresClauseOpt(ast->requiresClause)) + return false; } while (LA()) { @@ -1402,6 +1404,20 @@ bool Parser::parseRequirement() return true; } +bool Parser::parseRequiresClauseOpt(RequiresClauseAST *&node) +{ + if (!_languageFeatures.cxx20Enabled) + return true; + if (LA() != T_REQUIRES) + return true; + const auto ast = new (_pool) RequiresClauseAST; + ast->requires_token = consumeToken(); + if (!parseLogicalOrExpression(ast->constraint)) + return false; + node = ast; + return true; +} + bool Parser::parseRequiresExpression(ExpressionAST *&node) { if (!_languageFeatures.cxx20Enabled) @@ -2999,6 +3015,8 @@ bool Parser::parseInitDeclarator(DeclaratorAST *&node, SpecifierListAST *decl_sp } else if (node->core_declarator && node->core_declarator->asDecompositionDeclarator()) { error(cursor(), "structured binding needs initializer"); return false; + } else if (!parseRequiresClauseOpt(node->requiresClause)) { + return false; } return true; } diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index dbbb5630971..a50706b5f34 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -147,6 +147,7 @@ public: bool parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node); bool parseTypeConstraint(TypeConstraintAST *&node); bool parseRequirement(); + bool parseRequiresClauseOpt(RequiresClauseAST *&node); bool parseRequiresExpression(ExpressionAST *&node); bool parseTemplateParameter(DeclarationAST *&node); bool parseTemplateParameterList(DeclarationListAST *&node); diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index f626c402230..ea859b77d98 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -147,6 +147,7 @@ private Q_SLOTS: void lambdaType(); void concepts(); + void requiresClause(); }; @@ -318,5 +319,27 @@ void *func2(IsPointer auto p) QVERIFY(!hasErrors); } +void tst_cxx11::requiresClause() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx20Enabled = true; + + const QString source = R"( +template constexpr bool is_meowable = true; +template constexpr bool is_purrable() { return true; } +template void f(T) requires is_meowable; +template requires is_meowable void g(T) ; +template void h(T) requires (is_purrable()); +)"; + QByteArray errors; + Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile")); + processDocument(doc, source.toUtf8(), features, &errors); + const bool hasErrors = !errors.isEmpty(); + if (hasErrors) + qDebug() << errors; + QVERIFY(!hasErrors); +} + QTEST_APPLESS_MAIN(tst_cxx11) #include "tst_cxx11.moc" From 08bacd3f19b817a7ffbd606a92eff5000eaaca2c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 14:19:42 +0100 Subject: [PATCH 0154/1447] Avoid a few double lookups when expanding environment values Change-Id: Ie84caee89a48d8006e6324c5a82901d01a5fac6c Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/docker/dockerdevice.cpp | 4 ++-- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 4 ++-- src/plugins/qnx/qnxdevice.cpp | 4 ++-- src/plugins/remotelinux/linuxdevice.cpp | 4 ++-- src/plugins/remotelinux/makeinstallstep.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 45e024b400b..a9687352529 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -471,9 +471,9 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, dockerCmd.addArg("-t"); if (env) { - env->forEachEntry([&](const QString &key, const QString &, bool) { + env->forEachEntry([&](const QString &key, const QString &value, bool) { dockerCmd.addArg("-e"); - dockerCmd.addArg(key + "=" + env->expandedValueForKey(key)); + dockerCmd.addArg(key + "=" + env->expandVariables(value)); }); } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 575de11f66c..322e58c37d0 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -872,8 +872,8 @@ QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFi rootProFileName, deviceRoot()); - env.forEachEntry([&](const QString &key, const QString &, bool) { - m_qmakeGlobals->environment.insert(key, env.expandedValueForKey(key)); + env.forEachEntry([&](const QString &key, const QString &value, bool) { + m_qmakeGlobals->environment.insert(key, env.expandVariables(value)); }); m_qmakeGlobals->setCommandLineArguments(rootProFileName, qmakeArgs); diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 89d1241cfe7..ad205196ed7 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -61,8 +61,8 @@ QString QnxProcessImpl::fullCommandLine(const CommandLine &commandLine) const ProcessArgs::quoteArg(m_setup.m_workingDirectory.toString())); const Environment env = m_setup.m_environment; - env.forEachEntry([&](const QString &key, const QString &, bool) { - fullCommandLine += QString("%1='%2' ").arg(key).arg(env.expandedValueForKey(key)); + env.forEachEntry([&](const QString &key, const QString &value, bool) { + fullCommandLine += QString("%1='%2' ").arg(key).arg(env.expandVariables(value)); }); fullCommandLine += QString::fromLatin1("%1 & echo $! > %2").arg(cmd).arg(m_pidFile); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index d38542fefde..fc3268c892d 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -613,8 +613,8 @@ QString LinuxProcessInterface::fullCommandLine(const CommandLine &commandLine) c cmd.addArgs(QString("echo ") + s_pidMarker + "$$" + s_pidMarker + " && ", CommandLine::Raw); const Environment &env = m_setup.m_environment; - env.forEachEntry([&](const QString &key, const QString &, bool) { - cmd.addArgs(key + "='" + env.expandedValueForKey(key) + '\'', CommandLine::Raw); + env.forEachEntry([&](const QString &key, const QString &value, bool) { + cmd.addArgs(key + "='" + env.expandVariables(value) + '\'', CommandLine::Raw); }); if (m_setup.m_terminalMode == TerminalMode::Off) diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index a23dba21037..de7f9a336e6 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -172,9 +172,9 @@ bool MakeInstallStep::init() const MakeInstallCommand cmd = buildSystem()->makeInstallCommand(rootDir); if (cmd.environment.hasChanges()) { Environment env = processParameters()->environment(); - cmd.environment.forEachEntry([&](const QString &key, const QString &, bool enabled) { + cmd.environment.forEachEntry([&](const QString &key, const QString &value, bool enabled) { if (enabled) - env.set(key, cmd.environment.expandedValueForKey(key)); + env.set(key, cmd.environment.expandVariables(value)); }); processParameters()->setEnvironment(env); } From 9feef11b5da95f8cbaa589d9d2775306676641e3 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 2 Mar 2023 13:56:11 +0100 Subject: [PATCH 0155/1447] Copilot: robustify request logic Change-Id: Ifa46bc05f0bab8e3c7fc40d855a35e940f0628da Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/CMakeLists.txt | 1 - src/plugins/copilot/copilotclient.cpp | 137 ++++++++++++++---- src/plugins/copilot/copilotclient.h | 20 ++- src/plugins/copilot/copilotplugin.cpp | 6 +- src/plugins/copilot/copilotplugin.h | 2 + src/plugins/copilot/documentwatcher.cpp | 90 ------------ src/plugins/copilot/documentwatcher.h | 31 ---- src/plugins/copilot/requests/getcompletions.h | 3 +- 8 files changed, 128 insertions(+), 162 deletions(-) delete mode 100644 src/plugins/copilot/documentwatcher.cpp delete mode 100644 src/plugins/copilot/documentwatcher.h diff --git a/src/plugins/copilot/CMakeLists.txt b/src/plugins/copilot/CMakeLists.txt index f0e29df2cf9..8e8526542a7 100644 --- a/src/plugins/copilot/CMakeLists.txt +++ b/src/plugins/copilot/CMakeLists.txt @@ -7,7 +7,6 @@ add_qtc_plugin(Copilot copilotclient.cpp copilotclient.h copilotsettings.cpp copilotsettings.h copilotoptionspage.cpp copilotoptionspage.h - documentwatcher.cpp documentwatcher.h requests/getcompletions.h requests/checkstatus.h requests/signout.h diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index de4653fcbd5..95fa78d2630 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -4,7 +4,6 @@ #include "copilotclient.h" #include "copilotsettings.h" -#include "documentwatcher.h" #include #include @@ -14,6 +13,14 @@ #include +#include + +#include + +#include + +using namespace LanguageServerProtocol; +using namespace TextEditor; using namespace Utils; namespace Copilot::Internal { @@ -48,51 +55,119 @@ CopilotClient::CopilotClient() setSupportedLanguage(langFilter); start(); - connect(Core::EditorManager::instance(), - &Core::EditorManager::documentOpened, - this, - [this](Core::IDocument *document) { - TextEditor::TextDocument *textDocument = qobject_cast( - document); - if (!textDocument) - return; - - openDocument(textDocument); - - m_documentWatchers.emplace(textDocument->filePath(), - std::make_unique(this, textDocument)); - }); + auto openDoc = [this](Core::IDocument *document) { + if (auto *textDocument = qobject_cast(document)) + openDocument(textDocument); + }; + connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, this, openDoc); connect(Core::EditorManager::instance(), &Core::EditorManager::documentClosed, this, [this](Core::IDocument *document) { - auto textDocument = qobject_cast(document); - if (!textDocument) - return; - - closeDocument(textDocument); - m_documentWatchers.erase(textDocument->filePath()); + if (auto textDocument = qobject_cast(document)) + closeDocument(textDocument); }); + for (Core::IDocument *doc : Core::DocumentModel::openedDocuments()) + openDoc(doc); currentInstance = this; } -void CopilotClient::requestCompletion( - const Utils::FilePath &path, - int version, - LanguageServerProtocol::Position position, - std::function callback) +void CopilotClient::openDocument(TextDocument *document) { - GetCompletionRequest request{ - {LanguageServerProtocol::TextDocumentIdentifier(hostPathToServerUri(path)), - version, - position}}; - request.setResponseCallback(callback); + Client::openDocument(document); + connect(document, + &TextDocument::contentsChangedWithPosition, + this, + [this, document](int position, int charsRemoved, int charsAdded) { + auto textEditor = BaseTextEditor::currentTextEditor(); + if (!textEditor || textEditor->document() != document) + return; + TextEditorWidget *widget = textEditor->editorWidget(); + if (widget->multiTextCursor().hasMultipleCursors()) + return; + if (widget->textCursor().position() != (position + charsAdded)) + return; + scheduleRequest(textEditor->editorWidget()); + }); +} +void CopilotClient::scheduleRequest(TextEditorWidget *editor) +{ + cancelRunningRequest(editor); + + if (!m_scheduledRequests.contains(editor)) { + auto timer = new QTimer(this); + timer->setSingleShot(true); + connect(timer, &QTimer::timeout, this, [this, editor]() { requestCompletions(editor); }); + connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() { + m_scheduledRequests.remove(editor); + }); + connect(editor, &TextEditorWidget::cursorPositionChanged, this, [this, editor] { + cancelRunningRequest(editor); + }); + m_scheduledRequests.insert(editor, {editor->textCursor().position(), timer}); + } else { + m_scheduledRequests[editor].cursorPosition = editor->textCursor().position(); + } + m_scheduledRequests[editor].timer->start(500); +} + +void CopilotClient::requestCompletions(TextEditorWidget *editor) +{ + Utils::MultiTextCursor cursor = editor->multiTextCursor(); + if (cursor.hasMultipleCursors() || cursor.hasSelection()) + return; + + if (m_scheduledRequests[editor].cursorPosition != cursor.mainCursor().position()) + return; + + const Utils::FilePath filePath = editor->textDocument()->filePath(); + GetCompletionRequest request{ + {TextDocumentIdentifier(hostPathToServerUri(filePath)), + documentVersion(filePath), + Position(cursor.mainCursor())}}; + request.setResponseCallback([this, editor = QPointer(editor)]( + const GetCompletionRequest::Response &response) { + if (editor) + handleCompletions(response, editor); + }); + m_runningRequests[editor] = request; sendMessage(request); } +void CopilotClient::handleCompletions(const GetCompletionRequest::Response &response, + TextEditorWidget *editor) +{ + if (response.error()) + log(*response.error()); + + Utils::MultiTextCursor cursor = editor->multiTextCursor(); + if (cursor.hasMultipleCursors() || cursor.hasSelection()) + return; + + if (const std::optional result = response.result()) { + LanguageClientArray completions = result->completions(); + if (completions.isNull() || completions.toList().isEmpty()) + return; + + const Completion firstCompletion = completions.toList().first(); + const QString content = firstCompletion.text().mid(firstCompletion.position().character()); + + editor->insertSuggestion(content); + } +} + +void CopilotClient::cancelRunningRequest(TextEditor::TextEditorWidget *editor) +{ + auto it = m_runningRequests.find(editor); + if (it == m_runningRequests.end()) + return; + cancelRequest(it->id()); + m_runningRequests.erase(it); +} + void CopilotClient::requestCheckStatus( bool localChecksOnly, std::function callback) { diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index 7521fc73b7b..73fe95e2531 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -27,11 +27,13 @@ public: static CopilotClient *instance(); - void requestCompletion( - const Utils::FilePath &path, - int version, - LanguageServerProtocol::Position position, - std::function callback); + void openDocument(TextEditor::TextDocument *document) override; + + void scheduleRequest(TextEditor::TextEditorWidget *editor); + void requestCompletions(TextEditor::TextEditorWidget *editor); + void handleCompletions(const GetCompletionRequest::Response &response, + TextEditor::TextEditorWidget *editor); + void cancelRunningRequest(TextEditor::TextEditorWidget *editor); void requestCheckStatus( bool localChecksOnly, @@ -47,7 +49,13 @@ public: std::function callback); private: - std::map> m_documentWatchers; + QMap m_runningRequests; + struct ScheduleData + { + int cursorPosition = -1; + QTimer *timer = nullptr; + }; + QMap m_scheduledRequests; }; } // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 910bfa33b7b..d473cac2cbc 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -8,8 +8,12 @@ #include "copilotsettings.h" #include +#include + +#include using namespace Utils; +using namespace Core; namespace Copilot { namespace Internal { @@ -24,7 +28,7 @@ CopilotPlugin::~CopilotPlugin() void CopilotPlugin::initialize() { - CopilotSettings::instance().readSettings(Core::ICore::settings()); + CopilotSettings::instance().readSettings(ICore::settings()); m_client = new CopilotClient(); diff --git a/src/plugins/copilot/copilotplugin.h b/src/plugins/copilot/copilotplugin.h index d81d2e86282..798db7c2819 100644 --- a/src/plugins/copilot/copilotplugin.h +++ b/src/plugins/copilot/copilotplugin.h @@ -7,6 +7,8 @@ #include +namespace TextEditor { class TextEditorWidget; } + namespace Copilot { namespace Internal { diff --git a/src/plugins/copilot/documentwatcher.cpp b/src/plugins/copilot/documentwatcher.cpp deleted file mode 100644 index 69b201b5216..00000000000 --- a/src/plugins/copilot/documentwatcher.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#include "documentwatcher.h" - -#include - -#include - -#include - -using namespace LanguageServerProtocol; -using namespace TextEditor; - -namespace Copilot::Internal { - -DocumentWatcher::DocumentWatcher(CopilotClient *client, TextDocument *textDocument) - : m_client(client) - , m_textDocument(textDocument) -{ - m_lastContentSize = m_textDocument->document()->characterCount(); //toPlainText().size(); - m_debounceTimer.setInterval(500); - m_debounceTimer.setSingleShot(true); - - connect(textDocument, &TextDocument::contentsChanged, this, [this]() { - if (!m_isEditing) { - const int newSize = m_textDocument->document()->characterCount(); - if (m_lastContentSize < newSize) { - m_debounceTimer.start(); - } - m_lastContentSize = newSize; - } - }); - - connect(&m_debounceTimer, &QTimer::timeout, this, [this]() { getSuggestion(); }); -} - -void DocumentWatcher::getSuggestion() -{ - TextEditorWidget *textEditorWidget = nullptr; - for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(m_textDocument)) { - textEditorWidget = qobject_cast(editor->widget()); - if (textEditorWidget) - break; - } - - if (!textEditorWidget) - return; - - Utils::MultiTextCursor cursor = textEditorWidget->multiTextCursor(); - if (cursor.hasMultipleCursors() || cursor.hasSelection()) - return; - - const int currentCursorPos = cursor.mainCursor().position(); - - m_client->requestCompletion( - m_textDocument->filePath(), - m_client->documentVersion(m_textDocument->filePath()), - Position(cursor.mainCursor()), - [this, textEditorWidget, currentCursorPos](const GetCompletionRequest::Response &response) { - if (response.error()) { - qDebug() << "ERROR:" << *response.error(); - return; - } - - const std::optional result = response.result(); - QTC_ASSERT(result, return); - - const QList list = result->completions().toList(); - - if (list.isEmpty()) - return; - - Utils::MultiTextCursor cursor = textEditorWidget->multiTextCursor(); - if (cursor.hasMultipleCursors() || cursor.hasSelection()) - return; - if (cursor.cursors().first().position() != currentCursorPos) - return; - - const Completion firstCompletion = list.first(); - const QString content = firstCompletion.text().mid( - firstCompletion.position().character()); - - m_isEditing = true; - textEditorWidget->insertSuggestion(content); - m_isEditing = false; - }); -} - -} // namespace Copilot::Internal diff --git a/src/plugins/copilot/documentwatcher.h b/src/plugins/copilot/documentwatcher.h deleted file mode 100644 index 868be7956d4..00000000000 --- a/src/plugins/copilot/documentwatcher.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "copilotclient.h" - -#include - -#include - -namespace Copilot::Internal { - -class DocumentWatcher : public QObject -{ - Q_OBJECT -public: - explicit DocumentWatcher(CopilotClient *client, TextEditor::TextDocument *textDocument); - - void getSuggestion(); - -private: - CopilotClient *m_client; - TextEditor::TextDocument *m_textDocument; - - QTimer m_debounceTimer; - bool m_isEditing = false; - int m_lastContentSize = 0; -}; - -} // namespace Copilot::Internal diff --git a/src/plugins/copilot/requests/getcompletions.h b/src/plugins/copilot/requests/getcompletions.h index 6a503071d8a..d602fea97d3 100644 --- a/src/plugins/copilot/requests/getcompletions.h +++ b/src/plugins/copilot/requests/getcompletions.h @@ -42,7 +42,6 @@ class GetCompletionParams : public LanguageServerProtocol::JsonObject public: static constexpr char16_t docKey[] = u"doc"; - GetCompletionParams(); GetCompletionParams(const LanguageServerProtocol::TextDocumentIdentifier &document, int version, const LanguageServerProtocol::Position &position) @@ -110,7 +109,7 @@ class GetCompletionRequest : public LanguageServerProtocol::Request { public: - explicit GetCompletionRequest(const GetCompletionParams ¶ms) + explicit GetCompletionRequest(const GetCompletionParams ¶ms = {}) : Request(methodName, params) {} using Request::Request; From 34fd28327d9b81bd3a4aa340a90869caccbddfc6 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 1 Mar 2023 16:27:47 +0100 Subject: [PATCH 0156/1447] CMake: Use callback-based environment iteration Hides underlying data structure. Task-number: QTCREATORBUG-28357 Change-Id: Ib0d7fb70afa820b1bd28d23e12b9379a6de6546b Reviewed-by: Cristian Adam Reviewed-by: --- .../cmakeprojectmanager/presetsmacros.cpp | 55 ++++++++----------- .../cmakeprojectmanager/presetsparser.cpp | 6 +- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/presetsmacros.cpp b/src/plugins/cmakeprojectmanager/presetsmacros.cpp index 4dd25c3b1d1..d267e295411 100644 --- a/src/plugins/cmakeprojectmanager/presetsmacros.cpp +++ b/src/plugins/cmakeprojectmanager/presetsmacros.cpp @@ -8,6 +8,8 @@ #include #include +using namespace Utils; + namespace CMakeProjectManager::Internal::CMakePresets::Macros { static QString getHostSystemName(Utils::OsType osType) @@ -99,32 +101,26 @@ static QString expandMacroEnv(const QString ¯oPrefix, return result; } -static Utils::Environment getEnvCombined(const std::optional &optPresetEnv, - const Utils::Environment &env) +static Environment getEnvCombined(const std::optional &optPresetEnv, + const Environment &env) { - Utils::Environment result = env; + Environment result = env; - if (!optPresetEnv) - return result; - - Utils::Environment presetEnv = optPresetEnv.value(); - for (auto it = presetEnv.constBegin(); it != presetEnv.constEnd(); ++it) { - result.set(it.key().name, it.value().first); + if (optPresetEnv) { + optPresetEnv->forEachEntry([&result](const QString &key, const QString &value, bool) { + result.set(key, value); + }); } return result; } template -void expand(const PresetType &preset, - Utils::Environment &env, - const Utils::FilePath &sourceDirectory) +void expand(const PresetType &preset, Environment &env, const FilePath &sourceDirectory) { - const Utils::Environment presetEnv = getEnvCombined(preset.environment, env); - for (auto it = presetEnv.constBegin(); it != presetEnv.constEnd(); ++it) { - const QString key = it.key().name; - QString value = it.value().first; - + const Environment presetEnv = getEnvCombined(preset.environment, env); + presetEnv.forEachEntry([&](const QString &key, const QString &value_, bool) { + QString value = value_; expandAllButEnv(preset, sourceDirectory, value); value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) { return presetEnv.value(macroName); @@ -133,7 +129,7 @@ void expand(const PresetType &preset, QString sep; bool append = true; if (key.compare("PATH", Qt::CaseInsensitive) == 0) { - sep = Utils::OsSpecificAspects::pathListSeparator(env.osType()); + sep = OsSpecificAspects::pathListSeparator(env.osType()); const int index = value.indexOf("$penv{PATH}", 0, Qt::CaseInsensitive); if (index != 0) append = false; @@ -148,20 +144,15 @@ void expand(const PresetType &preset, env.appendOrSet(key, value, sep); else env.prependOrSet(key, value, sep); - } + }); } template -void expand(const PresetType &preset, - Utils::EnvironmentItems &envItems, - const Utils::FilePath &sourceDirectory) +void expand(const PresetType &preset, EnvironmentItems &envItems, const FilePath &sourceDirectory) { - const Utils::Environment presetEnv = preset.environment ? preset.environment.value() - : Utils::Environment(); - for (auto it = presetEnv.constBegin(); it != presetEnv.constEnd(); ++it) { - const QString key = it.key().name; - QString value = it.value().first; - + const Environment presetEnv = preset.environment ? *preset.environment : Environment(); + presetEnv.forEachEntry([&](const QString &key, const QString &value_, bool) { + QString value = value_; expandAllButEnv(preset, sourceDirectory, value); value = expandMacroEnv("env", value, [presetEnv](const QString ¯oName) { if (presetEnv.hasKey(macroName)) @@ -169,12 +160,12 @@ void expand(const PresetType &preset, return QString("${%1}").arg(macroName); }); - auto operation = Utils::EnvironmentItem::Operation::SetEnabled; + auto operation = EnvironmentItem::Operation::SetEnabled; if (key.compare("PATH", Qt::CaseInsensitive) == 0) { - operation = Utils::EnvironmentItem::Operation::Append; + operation = EnvironmentItem::Operation::Append; const int index = value.indexOf("$penv{PATH}", 0, Qt::CaseInsensitive); if (index != 0) - operation = Utils::EnvironmentItem::Operation::Prepend; + operation = EnvironmentItem::Operation::Prepend; value.replace("$penv{PATH}", "", Qt::CaseInsensitive); } @@ -183,7 +174,7 @@ void expand(const PresetType &preset, }); envItems.emplace_back(Utils::EnvironmentItem(key, value, operation)); - } + }); } template diff --git a/src/plugins/cmakeprojectmanager/presetsparser.cpp b/src/plugins/cmakeprojectmanager/presetsparser.cpp index 8d1cc1610df..b6e8ddb205c 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.cpp +++ b/src/plugins/cmakeprojectmanager/presetsparser.cpp @@ -456,9 +456,9 @@ static QHash merge(const QHash &first, static Utils::Environment merge(const Utils::Environment &first, const Utils::Environment &second) { Utils::Environment result = first; - for (auto it = second.constBegin(); it != second.constEnd(); ++it) { - result.set(it.key().name, it.value().first); - } + second.forEachEntry([&](const QString &key, const QString &value, bool) { + result.set(key, value); + }); return result; } From 215f79f5800e6de08c8a5efce54eb4a4b64b9384 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 22 Feb 2023 19:51:22 +0100 Subject: [PATCH 0157/1447] LocatorFilter classes: Use more linkForEditor Limit the usage of ambiguous internalData. Change-Id: Ice67884b9fb2ff303939cd5998c6e80453e82530 Reviewed-by: Reviewed-by: Eike Ziller --- src/libs/utils/link.h | 16 ++++-- .../clangcodemodel/clangdlocatorfilters.cpp | 49 +++++++------------ .../cmakelocatorfilter.cpp | 25 +++------- .../coreplugin/locator/locatorsearchutils.cpp | 4 +- .../cppeditor/cppcurrentdocumentfilter.cpp | 8 +-- src/plugins/cppeditor/cpplocatorfilter.cpp | 7 +-- src/plugins/cppeditor/cppmodelmanager.cpp | 9 ++-- src/plugins/languageclient/locatorfilter.cpp | 26 +++------- src/plugins/languageclient/locatorfilter.h | 1 + src/plugins/modeleditor/elementtasks.cpp | 4 +- .../qmljstools/qmljsfunctionfilter.cpp | 4 +- 11 files changed, 61 insertions(+), 92 deletions(-) diff --git a/src/libs/utils/link.h b/src/libs/utils/link.h index 6f01b484348..655957e9acc 100644 --- a/src/libs/utils/link.h +++ b/src/libs/utils/link.h @@ -17,7 +17,8 @@ namespace Utils { class QTCREATOR_UTILS_EXPORT Link { public: - Link(const FilePath &filePath = FilePath(), int line = 0, int column = 0) + Link() = default; + Link(const FilePath &filePath, int line = 0, int column = 0) : targetFilePath(filePath) , targetLine(line) , targetColumn(column) @@ -48,8 +49,8 @@ public: int linkTextEnd = -1; FilePath targetFilePath; - int targetLine; - int targetColumn; + int targetLine = 0; + int targetColumn = 0; }; using LinkHandler = std::function; @@ -58,3 +59,12 @@ using Links = QList; } // namespace Utils Q_DECLARE_METATYPE(Utils::Link) + +namespace std { + +template<> struct hash +{ + size_t operator()(const Utils::Link &fn) const { return qHash(fn); } +}; + +} // std diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index e94e65f1af5..7f431a36bf7 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -6,25 +6,20 @@ #include "clangdclient.h" #include "clangmodelmanagersupport.h" +#include #include #include #include #include #include - #include #include - #include - #include #include #include -#include -#include - using namespace Core; using namespace LanguageClient; using namespace LanguageServerProtocol; @@ -159,33 +154,27 @@ QList ClangGlobalSymbolFilter::matchesFor( QList matches = m_cppFilter->matchesFor(future, entry); const QList lspMatches = m_lspFilter->matchesFor(future, entry); if (!lspMatches.isEmpty()) { - std::set> locations; + QSet locations; for (const auto &entry : std::as_const(matches)) { - const CppEditor::IndexItem::Ptr item - = qvariant_cast(entry.internalData); - locations.insert(std::make_tuple(item->filePath(), item->line(), item->column())); + QTC_ASSERT(entry.linkForEditor, continue); + locations.insert(*entry.linkForEditor); } for (const auto &entry : lspMatches) { - if (!entry.internalData.canConvert()) - continue; - const auto link = qvariant_cast(entry.internalData); - if (locations.find(std::make_tuple(link.targetFilePath, link.targetLine, - link.targetColumn)) == locations.cend()) { + QTC_ASSERT(entry.linkForEditor, continue); + if (!locations.contains(*entry.linkForEditor)) matches << entry; // TODO: Insert sorted? - } } } - return matches; } void ClangGlobalSymbolFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { - if (qvariant_cast(selection.internalData)) - m_cppFilter->accept(selection, newText, selectionStart, selectionLength); - else - m_lspFilter->accept(selection, newText, selectionStart, selectionLength); + Q_UNUSED(newText) + Q_UNUSED(selectionStart) + Q_UNUSED(selectionLength) + EditorManager::openEditor(selection); } @@ -236,6 +225,8 @@ private: static_cast(info.kind()), info.name(), info.detail().value_or(QString())); entry.internalData = QVariant::fromValue(info); + const Position pos = info.range().start(); + entry.linkForEditor = {m_currentFilePath, pos.line() + 1, pos.character()}; entry.extraInfo = parent.extraInfo; if (!entry.extraInfo.isEmpty()) entry.extraInfo.append("::"); @@ -289,19 +280,13 @@ private: } if (definitions.size() == 1 && declarations.size() + definitions.size() == duplicates.size()) { - for (const LocatorFilterEntry &decl : std::as_const(declarations)) + for (const LocatorFilterEntry &decl : std::as_const(declarations)) { Utils::erase(allMatches, [&decl](const LocatorFilterEntry &e) { return e.internalData == decl.internalData; }); + } } } - - // The base implementation expects the position in the internal data. - for (LocatorFilterEntry &e : allMatches) { - const Position pos = qvariant_cast(e.internalData).range().start(); - e.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character())); - } - return allMatches; } @@ -362,8 +347,10 @@ QList ClangdCurrentDocumentFilter::matchesFor( void ClangdCurrentDocumentFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { - QTC_ASSERT(d->activeFilter, return); - d->activeFilter->accept(selection, newText, selectionStart, selectionLength); + Q_UNUSED(newText) + Q_UNUSED(selectionStart) + Q_UNUSED(selectionLength) + EditorManager::openEditor(selection); } } // namespace Internal diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 65b179cdf00..e902230ae43 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -58,17 +58,13 @@ void CMakeTargetLocatorFilter::prepareSearch(const QString &entry) if (index >= 0) { const FilePath path = target.backtrace.isEmpty() ? cmakeProject->projectFilePath() : target.backtrace.last().path; - const int line = target.backtrace.isEmpty() ? -1 : target.backtrace.last().line; + const int line = target.backtrace.isEmpty() ? 0 : target.backtrace.last().line; - QVariantMap extraData; - extraData.insert("project", cmakeProject->projectFilePath().toString()); - extraData.insert("line", line); - extraData.insert("file", path.toString()); - - LocatorFilterEntry filterEntry(this, target.title, extraData); + LocatorFilterEntry filterEntry(this, target.title); + filterEntry.linkForEditor = {path, line}; filterEntry.extraInfo = path.shortNativePath(); filterEntry.highlightInfo = {index, int(entry.length())}; - filterEntry.filePath = path; + filterEntry.filePath = cmakeProject->projectFilePath(); m_result.append(filterEntry); } @@ -111,8 +107,7 @@ void BuildCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) - const QVariantMap extraData = selection.internalData.toMap(); - const FilePath projectPath = FilePath::fromString(extraData.value("project").toString()); + const FilePath projectPath = selection.filePath; // Get the project containing the target selected const auto cmakeProject = qobject_cast( @@ -160,15 +155,7 @@ void OpenCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) - - const QVariantMap extraData = selection.internalData.toMap(); - const int line = extraData.value("line").toInt(); - const auto file = FilePath::fromVariant(extraData.value("file")); - - if (line >= 0) - EditorManager::openEditorAt({file, line}, {}, EditorManager::AllowExternalEditor); - else - EditorManager::openEditor(file, {}, EditorManager::AllowExternalEditor); + EditorManager::openEditor(selection); } } // CMakeProjectManager::Internal diff --git a/src/plugins/coreplugin/locator/locatorsearchutils.cpp b/src/plugins/coreplugin/locator/locatorsearchutils.cpp index 77e460ad4f3..a6a90107fe3 100644 --- a/src/plugins/coreplugin/locator/locatorsearchutils.cpp +++ b/src/plugins/coreplugin/locator/locatorsearchutils.cpp @@ -10,7 +10,7 @@ void Core::Internal::runSearch(QFutureInterface &future, const QList &filters, const QString &searchText) { - std::unordered_set addedCache; + std::unordered_set addedCache; const bool checkDuplicates = (filters.size() > 1); const auto duplicatesRemoved = [&](const QList &entries) { if (!checkDuplicates) @@ -19,7 +19,7 @@ void Core::Internal::runSearch(QFutureInterface &futur results.reserve(entries.size()); for (const LocatorFilterEntry &entry : entries) { const auto &link = entry.linkForEditor; - if (!link || addedCache.emplace(link->targetFilePath).second) + if (!link || addedCache.emplace(*link).second) results.append(entry); } return results; diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index a52edbfce52..8b9386567d9 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -86,6 +86,7 @@ QList CppCurrentDocumentFilter::matchesFor( } LocatorFilterEntry filterEntry(this, name, id, info->icon()); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; if (match.hasMatch()) { filterEntry.highlightInfo = highlightInfo(match); @@ -127,13 +128,13 @@ QList CppCurrentDocumentFilter::matchesFor( } if (definitions.size() == 1 && declarations.size() + definitions.size() == duplicates.size()) { - for (const LocatorFilterEntry &decl : std::as_const(declarations)) + for (const LocatorFilterEntry &decl : std::as_const(declarations)) { Utils::erase(betterEntries, [&decl](const LocatorFilterEntry &e) { return e.internalData == decl.internalData; }); + } } } - return betterEntries; } @@ -143,8 +144,7 @@ void CppCurrentDocumentFilter::accept(const LocatorFilterEntry &selection, QStri Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) - IndexItem::Ptr info = qvariant_cast(selection.internalData); - EditorManager::openEditorAt({info->filePath(), info->line(), info->column()}); + EditorManager::openEditor(selection); } void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc) diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index c6567165910..ddf185c2aed 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -33,6 +33,7 @@ LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr inf { const QVariant id = QVariant::fromValue(info); LocatorFilterEntry filterEntry(this, info->scopedSymbolName(), id, info->icon()); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) filterEntry.extraInfo = info->shortNativeFilePath(); else @@ -121,9 +122,7 @@ void CppLocatorFilter::accept(const LocatorFilterEntry &selection, Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) - IndexItem::Ptr info = qvariant_cast(selection.internalData); - EditorManager::openEditorAt({info->filePath(), info->line(), info->column()}, {}, - EditorManager::AllowExternalEditor); + EditorManager::openEditor(selection); } CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData) @@ -141,6 +140,7 @@ LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr inf { const QVariant id = QVariant::fromValue(info); LocatorFilterEntry filterEntry(this, info->symbolName(), id, info->icon()); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = info->symbolScope().isEmpty() ? info->shortNativeFilePath() : info->symbolScope(); @@ -173,6 +173,7 @@ LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr i } LocatorFilterEntry filterEntry(this, name + info->symbolType(), id, info->icon()); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; return filterEntry; diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 36d70882920..27984cce88f 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -572,12 +572,9 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) return entry.displayName.startsWith(prefix); })) { continue; } - Link link; - if (entry.internalData.canConvert()) - link = qvariant_cast(entry.internalData); - else if (const auto item = qvariant_cast(entry.internalData)) - link = Link(item->filePath(), item->line(), item->column()); - + if (!entry.linkForEditor) + continue; + const Link link = *entry.linkForEditor; if (link.hasValidTarget() && link.targetFilePath.isReadableFile() && (folder.isEmpty() || link.targetFilePath.isChildOf(folder)) && ProjectManager::projectForFile(link.targetFilePath)) { diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 03f3cf50bca..88dc4419972 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -96,7 +96,7 @@ static LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, if (std::optional container = info.containerName()) entry.extraInfo = container.value_or(QString()); entry.displayIcon = symbolIcon(info.kind()); - entry.internalData = QVariant::fromValue(info.location().toLink(pathMapper)); + entry.linkForEditor = info.location().toLink(pathMapper); return entry; } @@ -127,7 +127,7 @@ LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const DocumentSym entry.extraInfo = detail.value_or(QString()); entry.displayIcon = symbolIcon(info.kind()); const Position &pos = info.range().start(); - entry.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character())); + entry.linkForEditor = {m_currentFilePath, pos.line() + 1, pos.character()}; return entry; } @@ -150,7 +150,7 @@ QList DocumentLocatorFilter::generateLocatorEntries( template QList DocumentLocatorFilter::generateEntries(const QList &list, - const QString &filter) + const QString &filter) { QList entries; FuzzyMatcher::CaseSensitivity caseSensitivity @@ -169,6 +169,7 @@ QList DocumentLocatorFilter::generateEntries(const QList void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) { QMutexLocker locker(&m_mutex); + m_currentFilePath = m_pathMapper ? m_currentUri.toFilePath(m_pathMapper) : Utils::FilePath(); if (m_symbolCache && !m_currentSymbols.has_value()) { locker.unlock(); m_symbolCache->requestSymbols(m_currentUri, Schedule::Now); @@ -208,17 +209,8 @@ void DocumentLocatorFilter::accept(const LocatorFilterEntry &selection, int * /*selectionStart*/, int * /*selectionLength*/) const { - if (selection.internalData.canConvert()) { - QTC_ASSERT(m_pathMapper, return); - auto lineColumn = qvariant_cast(selection.internalData); - const Utils::Link link(m_currentUri.toFilePath(m_pathMapper), - lineColumn.line + 1, - lineColumn.column); - EditorManager::openEditorAt(link, {}, EditorManager::AllowExternalEditor); - } else if (selection.internalData.canConvert()) { - EditorManager::openEditorAt(qvariant_cast(selection.internalData), {}, - EditorManager::AllowExternalEditor); - } + if (selection.linkForEditor) + EditorManager::openEditor(selection); } WorkspaceLocatorFilter::WorkspaceLocatorFilter() @@ -299,7 +291,6 @@ QList WorkspaceLocatorFilter::matchesFor( locker.relock(); } - if (!m_filterKinds.isEmpty()) { m_results = Utils::filtered(m_results, [&](const SymbolInfoWithPathMapper &info) { return m_filterKinds.contains(SymbolKind(info.symbol.kind())); @@ -316,10 +307,7 @@ void WorkspaceLocatorFilter::accept(const LocatorFilterEntry &selection, int * /*selectionStart*/, int * /*selectionLength*/) const { - if (selection.internalData.canConvert()) { - EditorManager::openEditorAt(qvariant_cast(selection.internalData), {}, - EditorManager::AllowExternalEditor); - } + EditorManager::openEditor(selection); } void WorkspaceLocatorFilter::handleResponse(Client *client, diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 3eebd907a26..0d762b669ae 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -42,6 +42,7 @@ protected: QPointer m_symbolCache; LanguageServerProtocol::DocumentUri m_currentUri; + Utils::FilePath m_currentFilePath; private: void updateSymbols(const LanguageServerProtocol::DocumentUri &uri, diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp index 6702344db5c..74c3faa3f4f 100644 --- a/src/plugins/modeleditor/elementtasks.cpp +++ b/src/plugins/modeleditor/elementtasks.cpp @@ -136,10 +136,8 @@ void ElementTasks::openClassDefinition(const qmt::MElement *element) CppEditor::IndexItem::Ptr info = qvariant_cast(entry.internalData); if (info->scopedSymbolName() != qualifiedClassName) continue; - if (EditorManager::instance()->openEditorAt( - {info->filePath(), info->line(), info->column()})) { + if (EditorManager::openEditor(entry)) return; - } } } } diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 7ce42af1149..7fcf045c7de 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -52,6 +52,7 @@ QList FunctionFilter::matchesFor(QFutureInterface(selection.internalData); - EditorManager::openEditorAt({entry.fileName, entry.line, entry.column}); + EditorManager::openEditor(selection); } From 6efecebb10e6134f179ccea677f0e883cb76cab2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 22 Feb 2023 23:08:19 +0100 Subject: [PATCH 0158/1447] ILocatorFilter: Provide default implementation for accept() Change-Id: Ide3c65ac78da60c9634b8f1c3009e947e8f1e2f3 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/bookmarks/bookmarkfilter.cpp | 4 +-- .../clangcodemodel/clangdlocatorfilters.cpp | 19 ------------- .../clangcodemodel/clangdlocatorfilters.h | 6 ---- .../cmakelocatorfilter.cpp | 13 --------- .../cmakeprojectmanager/cmakelocatorfilter.h | 5 ---- .../coreplugin/locator/basefilefilter.cpp | 14 ---------- .../coreplugin/locator/basefilefilter.h | 3 -- .../coreplugin/locator/ilocatorfilter.cpp | 28 +++++++++++++------ .../coreplugin/locator/ilocatorfilter.h | 4 +-- .../locator/opendocumentsfilter.cpp | 11 -------- .../coreplugin/locator/opendocumentsfilter.h | 3 -- .../cppeditor/cppcurrentdocumentfilter.cpp | 10 ------- .../cppeditor/cppcurrentdocumentfilter.h | 3 -- src/plugins/cppeditor/cpplocatorfilter.cpp | 13 --------- src/plugins/cppeditor/cpplocatorfilter.h | 4 --- src/plugins/languageclient/locatorfilter.cpp | 21 -------------- src/plugins/languageclient/locatorfilter.h | 10 ------- .../qmljstools/qmljsfunctionfilter.cpp | 12 -------- src/plugins/qmljstools/qmljsfunctionfilter.h | 3 -- 19 files changed, 22 insertions(+), 164 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index 7cc9bf2a759..d659885a548 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -110,10 +110,8 @@ void BookmarkFilter::accept(const LocatorFilterEntry &selection, QString *newTex Q_UNUSED(newText) Q_UNUSED(selectionStart) Q_UNUSED(selectionLength) - if (const Bookmark *bookmark = m_manager->bookmarkForIndex( - selection.internalData.toModelIndex())) { + if (Bookmark *bookmark = m_manager->bookmarkForIndex(selection.internalData.toModelIndex())) m_manager->gotoBookmark(bookmark); - } } } // Bookmarks::Internal diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 7f431a36bf7..84b0171cbe3 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -168,16 +168,6 @@ QList ClangGlobalSymbolFilter::matchesFor( return matches; } -void ClangGlobalSymbolFilter::accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - - ClangClassesFilter::ClangClassesFilter() : ClangGlobalSymbolFilter(new CppClassesFilter, new LspClassesFilter) { @@ -344,14 +334,5 @@ QList ClangdCurrentDocumentFilter::matchesFor( return d->activeFilter->matchesFor(future, entry); } -void ClangdCurrentDocumentFilter::accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - } // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index f7deacc7605..11cf4c00b6b 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -22,9 +22,6 @@ private: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const override; - Core::ILocatorFilter * const m_cppFilter; LanguageClient::WorkspaceLocatorFilter * const m_lspFilter; }; @@ -53,9 +50,6 @@ private: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const override; - class Private; Private * const d; }; diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index e902230ae43..7141fb276cb 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -8,8 +8,6 @@ #include "cmakeproject.h" #include "cmakeprojectmanagertr.h" -#include - #include #include #include @@ -147,15 +145,4 @@ OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter() setPriority(Medium); } -void OpenCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - } // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h index 0a74eeafeb3..b8a748be85a 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h @@ -37,11 +37,6 @@ class OpenCMakeTargetLocatorFilter : CMakeTargetLocatorFilter { public: OpenCMakeTargetLocatorFilter(); - - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const final; }; } // CMakeProjectManager::Internal diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 823b5d7fb58..3f8e87af20f 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -3,10 +3,8 @@ #include "basefilefilter.h" -#include #include #include -#include #include #include @@ -192,18 +190,6 @@ QList BaseFileFilter::matchesFor(QFutureInterface()); } -/*! - \reimp -*/ -void BaseFileFilter::accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - /*! Takes ownership of the \a iterator. The previously set iterator might not be deleted until a currently running search is finished. diff --git a/src/plugins/coreplugin/locator/basefilefilter.h b/src/plugins/coreplugin/locator/basefilefilter.h index 47754dc08f5..55289e57b0a 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.h +++ b/src/plugins/coreplugin/locator/basefilefilter.h @@ -46,9 +46,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - protected: void setFileIterator(Iterator *iterator); QSharedPointer fileIterator(); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 4523c719fb6..61a433ffed7 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -4,6 +4,7 @@ #include "ilocatorfilter.h" #include "../coreplugintr.h" +#include "../editormanager/editormanager.h" #include @@ -98,6 +99,24 @@ void ILocatorFilter::prepareSearch(const QString &entry) Q_UNUSED(entry) } +/*! + Called with the entry specified by \a selection when the user activates it + in the result list. + Implementations can return a new search term \a newText, which has \a selectionLength characters + starting from \a selectionStart preselected, and the cursor set to the end of the selection. + + The default implementation tries to open an editor for \a selections's linkForEditor, + if it exists. +*/ +void ILocatorFilter::accept(const LocatorFilterEntry &selection, QString *newText, + int *selectionStart, int *selectionLength) const +{ + Q_UNUSED(newText) + Q_UNUSED(selectionStart) + Q_UNUSED(selectionLength) + EditorManager::openEditor(selection); +} + /*! Sets the default \a shortcut string that can be used to explicitly choose this filter in the locator input field. Call for example from the @@ -597,15 +616,6 @@ bool ILocatorFilter::isOldSetting(const QByteArray &state) \sa caseSensitivity() */ -/*! - \fn void Core::ILocatorFilter::accept(Core::const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const - - Called with the entry specified by \a selection when the user activates it - in the result list. - Implementations can return a new search term \a newText, which has \a selectionLength characters - starting from \a selectionStart preselected, and the cursor set to the end of the selection. -*/ - /*! \fn void Core::ILocatorFilter::refresh(QFutureInterface &future) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 1e0a2fcf4b4..5adb2ebef71 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -154,8 +154,8 @@ public: virtual QList matchesFor(QFutureInterface &future, const QString &entry) = 0; - virtual void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const = 0; + virtual void accept(const LocatorFilterEntry &selection, QString *newText, + int *selectionStart, int *selectionLength) const; virtual void refresh(QFutureInterface &future) { Q_UNUSED(future) }; diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 5a9042ce430..dc2a25b3736 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -4,11 +4,9 @@ #include "opendocumentsfilter.h" #include "../coreplugintr.h" -#include "../editormanager/editormanager.h" #include #include -#include #include #include @@ -117,13 +115,4 @@ QList OpenDocumentsFilter::editors() const return m_editors; } -void OpenDocumentsFilter::accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - } // Core::Internal diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index 537bdd45a5a..4924b04a1fb 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -23,9 +23,6 @@ public: OpenDocumentsFilter(); QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - public slots: void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index 8b9386567d9..adb1e5d48e3 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -138,15 +137,6 @@ QList CppCurrentDocumentFilter::matchesFor( return betterEntries; } -void CppCurrentDocumentFilter::accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc) { QMutexLocker locker(&m_mutex); diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.h b/src/plugins/cppeditor/cppcurrentdocumentfilter.h index 484812a0cba..72a8359b097 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.h +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.h @@ -27,9 +27,6 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void onCurrentEditorChanged(Core::IEditor *currentEditor); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index ddf185c2aed..b72bf261c98 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -6,14 +6,10 @@ #include "cppeditorconstants.h" #include "cppeditortr.h" -#include #include #include -#include -#include - using namespace Core; namespace CppEditor { @@ -116,15 +112,6 @@ QList CppLocatorFilter::matchesFor( return std::accumulate(std::begin(entries), std::end(entries), QList()); } -void CppLocatorFilter::accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData) : CppLocatorFilter(locatorData) { diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 9770afe21b4..0bfa8a2d2da 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -5,7 +5,6 @@ #include "cppeditor_global.h" #include "cpplocatordata.h" -#include "searchsymbols.h" #include @@ -21,9 +20,6 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - protected: virtual IndexItem::ItemType matchTypes() const { return IndexItem::All; } virtual Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info); diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 88dc4419972..f646209e28d 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -7,18 +7,14 @@ #include "languageclient_global.h" #include "languageclientmanager.h" #include "languageclienttr.h" -#include "languageclientutils.h" #include #include -#include #include -#include #include -#include #include #include @@ -204,15 +200,6 @@ QList DocumentLocatorFilter::matchesFor( return {}; } -void DocumentLocatorFilter::accept(const LocatorFilterEntry &selection, - QString * /*newText*/, - int * /*selectionStart*/, - int * /*selectionLength*/) const -{ - if (selection.linkForEditor) - EditorManager::openEditor(selection); -} - WorkspaceLocatorFilter::WorkspaceLocatorFilter() : WorkspaceLocatorFilter(QVector()) {} @@ -302,14 +289,6 @@ QList WorkspaceLocatorFilter::matchesFor( return Utils::transform(m_results, generateEntry).toList(); } -void WorkspaceLocatorFilter::accept(const LocatorFilterEntry &selection, - QString * /*newText*/, - int * /*selectionStart*/, - int * /*selectionLength*/) const -{ - EditorManager::openEditor(selection); -} - void WorkspaceLocatorFilter::handleResponse(Client *client, const WorkspaceSymbolRequest::Response &response) { diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 0d762b669ae..a6e107e97eb 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -29,11 +29,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const override; - signals: void symbolsUpToDate(QPrivateSignal); @@ -85,11 +80,6 @@ public: void prepareSearch(const QString &entry, const QList &clients); QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const override; - signals: void allRequestsFinished(QPrivateSignal); diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 7fcf045c7de..e713351e635 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -5,13 +5,10 @@ #include "qmljslocatordata.h" #include "qmljstoolstr.h" -#include #include #include -#include - using namespace Core; using namespace QmlJSTools::Internal; @@ -72,12 +69,3 @@ QList FunctionFilter::matchesFor(QFutureInterface()); } - -void FunctionFilter::accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.h b/src/plugins/qmljstools/qmljsfunctionfilter.h index 83b93e8f361..4334d5d9fca 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.h +++ b/src/plugins/qmljstools/qmljsfunctionfilter.h @@ -20,9 +20,6 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: LocatorData *m_data = nullptr; }; From 89f98659ca89299504c1c552524c0190f4672b26 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 22 Feb 2023 11:18:05 +0100 Subject: [PATCH 0159/1447] Change filesystem locator filter to FilePath Allows using the filesystem locator filter on remote systems. Change-Id: I4753691cdc0ec8a0e598001371ff3cf6be44737c Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Marcus Tillmanns --- .../coreplugin/locator/filesystemfilter.cpp | 70 ++++++++++--------- .../coreplugin/locator/filesystemfilter.h | 2 +- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 148852b1b09..fdc127e5d92 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -60,7 +60,7 @@ FileSystemFilter::FileSystemFilter() void FileSystemFilter::prepareSearch(const QString &entry) { Q_UNUSED(entry) - m_currentDocumentDirectory = DocumentManager::fileDialogInitialDirectory().toString(); + m_currentDocumentDirectory = DocumentManager::fileDialogInitialDirectory(); m_currentIncludeHidden = m_includeHidden; } @@ -71,18 +71,21 @@ QList FileSystemFilter::matchesFor(QFutureInterface FileSystemFilter::matchesFor(QFutureInterface FileSystemFilter::matchesFor(QFutureInterface FileSystemFilter::matchesFor(QFutureInterface Date: Fri, 3 Mar 2023 14:43:50 +0100 Subject: [PATCH 0160/1447] Utils: Fix missing modeBase Change-Id: I8ce9393ef97b83b9db8cde12cc8653e9072dad65 Reviewed-by: Eike Ziller --- src/libs/utils/devicefileaccess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index c50f3b145cb..cf14faefc48 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -1170,7 +1170,7 @@ FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const const RunResult stat = runInShell({"stat", args, OsType::OsTypeLinux}); return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut), - osType() != OsTypeMac); + osType() == OsTypeMac ? 8 : 16); } // returns whether 'find' could be used. From dc4ec494b36be703eee7930b98cf02b986d33ba7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 10:37:38 +0100 Subject: [PATCH 0161/1447] Terminal: Fix mouse selection Previously m_selection was not correctly ordered such that start < end. This patch fixes that and also adds optional debug visualizations to aid in debugging / validating the selection. Change-Id: I9b0d2fcd917f39eeb5082bc374796fed91521c7c Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 56 ++++++++++++++++++++++--- src/plugins/terminal/terminalwidget.h | 1 + 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 86af9fb4f11..7c76fa76084 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -30,6 +30,7 @@ #include Q_LOGGING_CATEGORY(terminalLog, "qtc.terminal", QtWarningMsg) +Q_LOGGING_CATEGORY(selectionLog, "qtc.terminal.selection", QtWarningMsg) using namespace Utils; using namespace Utils::Terminal; @@ -472,7 +473,10 @@ void TerminalWidget::flushVTerm(bool force) void TerminalWidget::setSelection(const std::optional &selection) { - m_copyAction.setEnabled(selection.has_value()); + if (selection.has_value() != m_selection.has_value()) { + qCDebug(selectionLog) << "Copy enabled:" << selection.has_value(); + m_copyAction.setEnabled(selection.has_value()); + } m_selection = selection; } @@ -503,6 +507,15 @@ QPoint TerminalWidget::viewportToGlobal(QPoint p) const return {p.x(), y}; } +QPoint TerminalWidget::globalToViewport(QPoint p) const +{ + int y = p.y() + topMargin(); + const double offset = (m_scrollback->size() - m_scrollback->offset()) * m_lineSpacing; + y -= offset; + + return {p.x(), y}; +} + QPoint TerminalWidget::globalToGrid(QPoint p) const { return QPoint(p.x() / m_cellSize.width(), p.y() / m_cellSize.height()); @@ -686,6 +699,20 @@ void TerminalWidget::paintEvent(QPaintEvent *event) } p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), margin}}, Internal::toQColor(defaultBg)); + + if (selectionLog().isDebugEnabled() && m_selection) { + const auto s = globalToViewport(m_selection->start); + const auto e = globalToViewport(m_selection->end); + + p.setPen(QPen(Qt::green, 1, Qt::DashLine)); + p.drawLine(s.x(), 0, s.x(), height()); + p.drawLine(0, s.y(), width(), s.y()); + + p.setPen(QPen(Qt::red, 1, Qt::DashLine)); + + p.drawLine(e.x(), 0, e.x(), height()); + p.drawLine(0, e.y(), width(), e.y()); + } } void TerminalWidget::keyPressEvent(QKeyEvent *event) @@ -872,7 +899,7 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) QPoint pos = viewportToGlobal(event->pos()); setSelection(Selection{pos, pos}); } - + event->accept(); viewport()->update(); } else if (event->button() == Qt::RightButton) { if (m_selection) { @@ -893,8 +920,24 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) QPoint start = viewportToGlobal(m_selectionStartPos); QPoint newEnd = viewportToGlobal(event->pos()); - if (start.y() > newEnd.y() || (start.y() == newEnd.y() && start.x() > newEnd.x())) + const auto startInGrid = globalToGrid(start); + const auto endInGrid = globalToGrid(newEnd); + + if (startInGrid.y() > endInGrid.y()) std::swap(start, newEnd); + else if (startInGrid.y() == endInGrid.y()) { + if (startInGrid.x() > endInGrid.x()) { + const auto s = start.x(); + start.setX(newEnd.x()); + newEnd.setX(s); + } + } + + if (start.y() > newEnd.y()) { + const auto s = start.y(); + start.setY(newEnd.y()); + newEnd.setY(s); + } if (m_selectLineMode) { start.setX(0); @@ -906,15 +949,16 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) const std::array newGrid = {globalToGrid(m_selection->start), globalToGrid(m_selection->end)}; - if (newGrid != oldGrid) + + if (newGrid != oldGrid || selectionLog().isDebugEnabled()) viewport()->update(); } } void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) { - if (m_selection && event->button() != Qt::LeftButton) { - if ((m_selectionStartPos - event->pos()).manhattanLength() < 2) { + if (m_selection && event->button() == Qt::LeftButton) { + if ((m_selection->end - m_selection->start).manhattanLength() < 2) { setSelection(std::nullopt); viewport()->update(); } diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 7c006873761..bd64b2f4776 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -103,6 +103,7 @@ protected: qreal topMargin() const; QPoint viewportToGlobal(QPoint p) const; + QPoint globalToViewport(QPoint p) const; QPoint globalToGrid(QPoint p) const; int textLineFromPixel(int y) const; From af520667caff8afcb815873531b237cfcc0e35f9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 10:40:01 +0100 Subject: [PATCH 0162/1447] Terminal: Defer scrollback text calculation In high load situations, the conversion of cells to std::u32string's can become a bottleneck. To address this, the calculation is deferred until it is needed. Change-Id: I0cc3c941fa680d8b9ebc3a5cba13cdc5c2db50f9 Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/terminal/scrollback.cpp | 31 ++++++++++++++++++++--------- src/plugins/terminal/scrollback.h | 6 ++++-- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/plugins/terminal/scrollback.cpp b/src/plugins/terminal/scrollback.cpp index c3be95f706c..6330e3c0ac7 100644 --- a/src/plugins/terminal/scrollback.cpp +++ b/src/plugins/terminal/scrollback.cpp @@ -7,14 +7,23 @@ #include #include +#include namespace Terminal::Internal { Scrollback::Line::Line(int cols, const VTermScreenCell *cells, VTermState *vts) : m_cols(cols) , m_cells(std::make_unique(cols)) - { + m_textFuture = std::async(std::launch::async, [this, cols] { + std::u32string text; + text.reserve(cols); + for (int i = 0; i < cols; ++i) { + text += cellToString(m_cells[i]); + } + return text; + }); + memcpy(m_cells.get(), cells, cols * sizeof(cells[0])); for (int i = 0; i < cols; ++i) { vterm_state_convert_color_to_rgb(vts, &m_cells[i].fg); @@ -49,6 +58,13 @@ const QTextLayout &Scrollback::Line::layout(int version, const QFont &font, qrea return *m_layout; } +const std::u32string &Scrollback::Line::text() const +{ + if (!m_text) + m_text = m_textFuture.get(); + return *m_text; +} + Scrollback::Scrollback(size_t capacity) : m_capacity(capacity) {} @@ -57,13 +73,8 @@ void Scrollback::emplace(int cols, const VTermScreenCell *cells, VTermState *vts { m_deque.emplace_front(cols, cells, vts); while (m_deque.size() > m_capacity) { - m_currentText = m_currentText.substr(m_deque.back().cols()); m_deque.pop_back(); } - - for (int i = 0; i < cols; i++) { - m_currentText += cellToString(cells[i]); - } } void Scrollback::popto(int cols, VTermScreenCell *cells) @@ -82,7 +93,6 @@ void Scrollback::popto(int cols, VTermScreenCell *cells) } m_deque.pop_front(); - m_currentText.resize(m_currentText.size() - cols); } size_t Scrollback::scroll(int delta) @@ -96,12 +106,15 @@ void Scrollback::clear() { m_offset = 0; m_deque.clear(); - m_currentText.clear(); } std::u32string Scrollback::currentText() { - return m_currentText; + std::u32string currentText; + for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) { + currentText += it->text(); + } + return currentText; } } // namespace Terminal::Internal diff --git a/src/plugins/terminal/scrollback.h b/src/plugins/terminal/scrollback.h index 22abc07b73f..4d8849182c9 100644 --- a/src/plugins/terminal/scrollback.h +++ b/src/plugins/terminal/scrollback.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -29,12 +30,15 @@ public: const VTermScreenCell *cells() const { return &m_cells[0]; }; const QTextLayout &layout(int version, const QFont &font, qreal lineSpacing) const; + const std::u32string &text() const; private: int m_cols; std::unique_ptr m_cells; mutable std::unique_ptr m_layout; mutable int m_layoutVersion{-1}; + mutable std::optional m_text; + mutable std::future m_textFuture; }; public: @@ -63,8 +67,6 @@ private: size_t m_capacity; size_t m_offset{0}; std::deque m_deque; - - std::u32string m_currentText; }; } // namespace Terminal::Internal From 7fc674b566e6bfc7efb48daa70abd84fb9dd0415 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 16:40:11 +0100 Subject: [PATCH 0163/1447] Terminal: Fix "nano" titlebar QTextLayout ignores trailing spaces, and does not draw their background color. Converting them to Nbsp fixes this. Change-Id: I19a363bcb4792c613eb9c59f7caaa40fa631b937 Reviewed-by: Cristian Adam --- src/plugins/terminal/celllayout.cpp | 2 ++ src/plugins/terminal/terminalwidget.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/plugins/terminal/celllayout.cpp b/src/plugins/terminal/celllayout.cpp index 45b7ca07835..a2628eccb05 100644 --- a/src/plugins/terminal/celllayout.cpp +++ b/src/plugins/terminal/celllayout.cpp @@ -101,6 +101,8 @@ void createTextLayout(QTextLayout &textLayout, if (cell->chars[0] != 0xFFFFFFFF) { QString ch = QString::fromUcs4(cell->chars); + if (ch == ' ') + ch = QChar::Nbsp; if (ch.size() > 0) { layoutText += ch; } else { diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 7c76fa76084..8325f2839c7 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -390,6 +390,8 @@ void TerminalWidget::copyToClipboard() const .trimmed()); } + selectedText.replace(QChar::Nbsp, QChar::Space); + setClipboardAndSelection(selectedText); } } From 74f15c99ce5b17941e5a41896bf9bfd8e51baf34 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 16:41:16 +0100 Subject: [PATCH 0164/1447] Terminal: Fix Ctrl+[A-Z] and '|' Change-Id: Id245a015d6092236c20634c47af682bcf073d982 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 8325f2839c7..b0515833076 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -770,13 +770,11 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) mod = VTERM_MOD_NONE; } - vterm_keyboard_unichar(m_vterm.get(), - event->text().toUcs4()[0], - static_cast(mod & ~VTERM_MOD_CTRL)); + vterm_keyboard_unichar(m_vterm.get(), event->text().toUcs4()[0], VTERM_MOD_NONE); setSelection(std::nullopt); - } else if (mod != VTERM_MOD_NONE && event->key() == Qt::Key_C) { - vterm_keyboard_unichar(m_vterm.get(), 'c', mod); + } else if (mod == VTERM_MOD_CTRL && event->key() >= Qt::Key_A && event->key() < Qt::Key_Z) { + vterm_keyboard_unichar(m_vterm.get(), 'a' + (event->key() - Qt::Key_A), mod); } } From 2fd91ad18e71bd6e7f09f04027d083209f688992 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 3 Mar 2023 15:05:56 +0100 Subject: [PATCH 0165/1447] Fix qbs build Change-Id: Ic2673f6f90610b1e58c9ec1fbf2f63522068cca8 Reviewed-by: David Schulz Reviewed-by: Christian Stenger --- src/plugins/copilot/copilot.qbs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs index 24b1d01bf5d..aec95112ad8 100644 --- a/src/plugins/copilot/copilot.qbs +++ b/src/plugins/copilot/copilot.qbs @@ -20,8 +20,6 @@ QtcPlugin { "copilotsettings.h", "copilotoptionspage.cpp", "copilotoptionspage.h", - "documentwatcher.cpp", - "documentwatcher.h", "requests/getcompletions.h", "requests/checkstatus.h", "requests/signout.h", From ae86a6a4bc6ccd93e704d49490791096c1a39085 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 13:54:49 +0100 Subject: [PATCH 0166/1447] Utils: Remove some iterator bases accessed to Environment Now unused. Change-Id: I21bce9218662d9cb8acc18e5c2ede6dfbb8962bb Reviewed-by: Christian Kandeler --- src/libs/utils/environment.cpp | 2 +- src/libs/utils/environment.h | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index eb49db208d7..462eeab31d7 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -48,7 +48,7 @@ QProcessEnvironment Environment::toProcessEnvironment() const QProcessEnvironment result; for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) { if (it.value().second) - result.insert(it.key().name, expandedValueForKey(key(it))); + result.insert(it.key().name, expandedValueForKey(m_dict.key(it))); } return result; } diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 1485dff2a12..541a730965b 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -76,20 +76,12 @@ public: OsType osType() const { return m_dict.osType(); } - using const_iterator = NameValueMap::const_iterator; // FIXME: avoid NameValueDictionary toDictionary() const { return m_dict; } // FIXME: avoid NameValueItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid - QString key(const_iterator it) const { return m_dict.key(it); } // FIXME: avoid - QString value(const_iterator it) const { return m_dict.value(it); } // FIXME: avoid - bool isEnabled(const_iterator it) const { return m_dict.isEnabled(it); } // FIXME: avoid - void setCombineWithDeviceEnvironment(bool combine) { m_combineWithDeviceEnvironment = combine; } bool combineWithDeviceEnvironment() const { return m_combineWithDeviceEnvironment; } - const_iterator constBegin() const { return m_dict.constBegin(); } // FIXME: avoid - const_iterator constEnd() const { return m_dict.constEnd(); } // FIXME: avoid - struct Entry { QString key; QString value; bool enabled; }; using FindResult = std::optional; FindResult find(const QString &name) const; // Note res->key may differ in case from name. From cabba52a89d7dab3ea58e8e509aaa40e40425e90 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 6 Mar 2023 08:51:18 +0200 Subject: [PATCH 0167/1447] Utils: Fix bad condition on iterator end Detected by Coverity. Amends c1b1842c486. Change-Id: Ie0233aab33317e286722dec7066d11dfc2a11a06 Reviewed-by: Jarek Kobus --- src/libs/utils/filestreamermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/filestreamermanager.cpp b/src/libs/utils/filestreamermanager.cpp index 5a1ec9847ea..051f114578a 100644 --- a/src/libs/utils/filestreamermanager.cpp +++ b/src/libs/utils/filestreamermanager.cpp @@ -49,7 +49,7 @@ static void deleteStreamer(FileStreamHandle handle) { QMutexLocker locker(&s_mutex); auto it = s_fileStreamers.find(handle); - if (it != s_fileStreamers.end()) + if (it == s_fileStreamers.end()) return; if (QThread::currentThread() == it->second->thread()) { delete it->second; From 913513ff622fdf423ea97a5f9bf6144e80f57501 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 3 Mar 2023 15:25:20 +0100 Subject: [PATCH 0168/1447] qbs build: Turn off warnings for vterm library As in the cmake build. Change-Id: I2cbc5d3fcae89053f310675dc0ea55c52f72f646 Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/3rdparty/libvterm/vterm.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/3rdparty/libvterm/vterm.qbs b/src/libs/3rdparty/libvterm/vterm.qbs index 274e3a46d6c..18ccb638aab 100644 --- a/src/libs/3rdparty/libvterm/vterm.qbs +++ b/src/libs/3rdparty/libvterm/vterm.qbs @@ -5,6 +5,7 @@ Project { Depends { name: "cpp" } cpp.includePaths: base.concat("include") + cpp.warningLevel: "none" Group { prefix: "src/" From ce457a9cdc85e80349a4a9f6209c60d4b1150ab7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 6 Feb 2023 22:59:30 +0100 Subject: [PATCH 0169/1447] ILocatorFilter: Replace refresh() with refreshRecipe() Most of refresh overrides were running synchronous method in main thread, however, it was really convoluted: we were starting asynchronous call and from inside the method running in separate thread we were scheduling the call back to main thread. Use Tasking::Sync for these cases instead. The only subclass that is doing the real asynchronous refresh is DirectoryFilter. Simplify the async call internals and pass data to the async call explicitly. Move the refresh method outside of DirectoryFilter class (to make it clear we shouldn't touch private members). Change-Id: I6af788611bdc49db1ff812f91202ac40a280fbc8 Reviewed-by: Eike Ziller --- .../coreplugin/locator/directoryfilter.cpp | 109 +++++++----------- .../coreplugin/locator/directoryfilter.h | 6 +- .../coreplugin/locator/ilocatorfilter.cpp | 22 ++-- .../coreplugin/locator/ilocatorfilter.h | 9 +- src/plugins/coreplugin/locator/locator.cpp | 16 +-- .../coreplugin/locator/locator_test.cpp | 2 - .../locator/opendocumentsfilter.cpp | 19 +++ .../coreplugin/locator/opendocumentsfilter.h | 5 +- src/plugins/cppeditor/cppincludesfilter.cpp | 31 ++--- src/plugins/cppeditor/cppincludesfilter.h | 4 +- src/plugins/help/helpindexfilter.cpp | 14 ++- src/plugins/help/helpindexfilter.h | 6 +- .../projectexplorer/allprojectsfilter.cpp | 20 ++-- .../projectexplorer/allprojectsfilter.h | 6 +- .../projectexplorer/currentprojectfilter.cpp | 25 ++-- .../projectexplorer/currentprojectfilter.h | 6 +- 16 files changed, 151 insertions(+), 149 deletions(-) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 19a9f098e62..9d07e530cd2 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -7,12 +7,12 @@ #include "../coreplugintr.h" #include +#include #include #include #include #include -#include #include #include #include @@ -60,8 +60,6 @@ DirectoryFilter::DirectoryFilter(Id id) void DirectoryFilter::saveState(QJsonObject &object) const { - QMutexLocker locker(&m_lock); // m_files is modified in other thread - if (displayName() != defaultDisplayName()) object.insert(kDisplayNameKey, displayName()); if (!m_directories.isEmpty()) { @@ -92,7 +90,6 @@ static FilePaths toFilePaths(const QJsonArray &array) void DirectoryFilter::restoreState(const QJsonObject &object) { - QMutexLocker locker(&m_lock); setDisplayName(object.value(kDisplayNameKey).toString(defaultDisplayName())); m_directories = toFilePaths(object.value(kDirectoriesKey).toArray()); m_filters = toStringList( @@ -107,8 +104,6 @@ void DirectoryFilter::restoreState(const QByteArray &state) { if (isOldSetting(state)) { // TODO read old settings, remove some time after Qt Creator 4.15 - QMutexLocker locker(&m_lock); - QString name; QStringList directories; QString shortcut; @@ -136,8 +131,6 @@ void DirectoryFilter::restoreState(const QByteArray &state) setDisplayName(name); setShortcutString(shortcut); setIncludedByDefault(defaultFilter); - - locker.unlock(); } else { ILocatorFilter::restoreState(state); } @@ -263,8 +256,6 @@ bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) &DirectoryFilter::updateOptionButtons, Qt::DirectConnection); m_dialog->directoryList->clear(); - // Note: assuming we only change m_directories in the Gui thread, - // we don't need to protect it here with mutex m_dialog->directoryList->addItems(Utils::transform(m_directories, &FilePath::toString)); m_dialog->nameLabel->setVisible(m_isCustomFilter); m_dialog->nameEdit->setVisible(m_isCustomFilter); @@ -276,14 +267,10 @@ bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) m_dialog->filePatternLabel->setText(Utils::msgFilePatternLabel()); m_dialog->filePatternLabel->setBuddy(m_dialog->filePattern); m_dialog->filePattern->setToolTip(Utils::msgFilePatternToolTip()); - // Note: assuming we only change m_filters in the Gui thread, - // we don't need to protect it here with mutex m_dialog->filePattern->setText(Utils::transform(m_filters, &QDir::toNativeSeparators).join(',')); m_dialog->exclusionPatternLabel->setText(Utils::msgExclusionPatternLabel()); m_dialog->exclusionPatternLabel->setBuddy(m_dialog->exclusionPattern); m_dialog->exclusionPattern->setToolTip(Utils::msgFilePatternToolTip()); - // Note: assuming we only change m_exclusionFilters in the Gui thread, - // we don't need to protect it here with mutex m_dialog->exclusionPattern->setText( Utils::transform(m_exclusionFilters, &QDir::toNativeSeparators).join(',')); m_dialog->shortcutEdit->setText(shortcutString()); @@ -291,7 +278,6 @@ bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) updateOptionButtons(); dialog.adjustSize(); if (dialog.exec() == QDialog::Accepted) { - QMutexLocker locker(&m_lock); bool directoriesChanged = false; const FilePaths oldDirectories = m_directories; const QStringList oldFilters = m_filters; @@ -353,53 +339,9 @@ void DirectoryFilter::updateOptionButtons() void DirectoryFilter::updateFileIterator() { - QMutexLocker locker(&m_lock); setFileIterator(new BaseFileFilter::ListIterator(m_files)); } -void DirectoryFilter::refresh(QFutureInterface &future) -{ - FilePaths directories; - QStringList filters, exclusionFilters; - { - QMutexLocker locker(&m_lock); - if (m_directories.isEmpty()) { - m_files.clear(); - QMetaObject::invokeMethod(this, &DirectoryFilter::updateFileIterator, - Qt::QueuedConnection); - future.setProgressRange(0, 1); - future.setProgressValueAndText(1, Tr::tr("%1 filter update: 0 files").arg(displayName())); - return; - } - directories = m_directories; - filters = m_filters; - exclusionFilters = m_exclusionFilters; - } - Utils::SubDirFileIterator subDirIterator(directories, filters, exclusionFilters); - future.setProgressRange(0, subDirIterator.maxProgress()); - Utils::FilePaths filesFound; - auto end = subDirIterator.end(); - for (auto it = subDirIterator.begin(); it != end; ++it) { - if (future.isCanceled()) - break; - filesFound << (*it).filePath; - if (future.isProgressUpdateNeeded() - || future.progressValue() == 0 /*workaround for regression in Qt*/) { - future.setProgressValueAndText(subDirIterator.currentProgress(), - Tr::tr("%1 filter update: %n files", nullptr, filesFound.size()).arg(displayName())); - } - } - - if (!future.isCanceled()) { - QMutexLocker locker(&m_lock); - m_files = filesFound; - QMetaObject::invokeMethod(this, &DirectoryFilter::updateFileIterator, Qt::QueuedConnection); - future.setProgressValue(subDirIterator.maxProgress()); - } else { - future.setProgressValueAndText(subDirIterator.currentProgress(), Tr::tr("%1 filter update: canceled").arg(displayName())); - } -} - void DirectoryFilter::setIsCustomFilter(bool value) { m_isCustomFilter = value; @@ -409,10 +351,7 @@ void DirectoryFilter::setDirectories(const FilePaths &directories) { if (directories == m_directories) return; - { - QMutexLocker locker(&m_lock); - m_directories = directories; - } + m_directories = directories; Internal::Locator::instance()->refresh({this}); } @@ -435,14 +374,54 @@ FilePaths DirectoryFilter::directories() const void DirectoryFilter::setFilters(const QStringList &filters) { - QMutexLocker locker(&m_lock); m_filters = filters; } void DirectoryFilter::setExclusionFilters(const QStringList &exclusionFilters) { - QMutexLocker locker(&m_lock); m_exclusionFilters = exclusionFilters; } +static void refresh(QFutureInterface &future, const FilePaths &directories, + const QStringList &filters, const QStringList &exclusionFilters, + const QString &displayName) +{ + if (directories.isEmpty()) + return; + + SubDirFileIterator subDirIterator(directories, filters, exclusionFilters); + future.setProgressRange(0, subDirIterator.maxProgress()); + FilePaths files; + const auto end = subDirIterator.end(); + for (auto it = subDirIterator.begin(); it != end; ++it) { + if (future.isCanceled()) { + future.setProgressValueAndText(subDirIterator.currentProgress(), + Tr::tr("%1 filter update: canceled").arg(displayName)); + return; + } + files << (*it).filePath; + if (future.isProgressUpdateNeeded() || future.progressValue() == 0) { + future.setProgressValueAndText(subDirIterator.currentProgress(), + Tr::tr("%1 filter update: %n files", nullptr, files.size()).arg(displayName)); + } + } + future.setProgressValue(subDirIterator.maxProgress()); + future.reportResult(files); +} + +using namespace Utils::Tasking; + +std::optional DirectoryFilter::refreshRecipe() +{ + const auto setup = [this](AsyncTask &async) { + async.setAsyncCallData(&refresh, m_directories, m_filters, m_exclusionFilters, + displayName()); + }; + const auto done = [this](const AsyncTask &async) { + m_files = async.isResultAvailable() ? async.result() : FilePaths(); + updateFileIterator(); + }; + return Async(setup, done); +} + } // namespace Core diff --git a/src/plugins/coreplugin/locator/directoryfilter.h b/src/plugins/coreplugin/locator/directoryfilter.h index 7fb88ce112d..04067988c32 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.h +++ b/src/plugins/coreplugin/locator/directoryfilter.h @@ -7,10 +7,7 @@ #include -#include #include -#include -#include namespace Core { @@ -22,7 +19,6 @@ public: DirectoryFilter(Utils::Id id); void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; - void refresh(QFutureInterface &future) override; void setIsCustomFilter(bool value); void setDirectories(const Utils::FilePaths &directories); @@ -42,6 +38,7 @@ private: void handleRemoveDirectory(); void updateOptionButtons(); void updateFileIterator(); + std::optional refreshRecipe() override; Utils::FilePaths m_directories; QStringList m_filters; @@ -49,7 +46,6 @@ private: // Our config dialog, uses in addDirectory and editDirectory // to give their dialogs the right parent class DirectoryFilterOptions *m_dialog = nullptr; - mutable QMutex m_lock; Utils::FilePaths m_files; bool m_isCustomFilter = true; }; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 61a433ffed7..4705ee32caa 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -7,6 +7,7 @@ #include "../editormanager/editormanager.h" #include +#include #include #include @@ -99,6 +100,15 @@ void ILocatorFilter::prepareSearch(const QString &entry) Q_UNUSED(entry) } +/*! + Returns refresh recipe for refreshing cached data. By default, no recipe is returned, so + that the filter won't be refreshed. +*/ +std::optional ILocatorFilter::refreshRecipe() +{ + return {}; +} + /*! Called with the entry specified by \a selection when the user activates it in the result list. @@ -220,13 +230,13 @@ void ILocatorFilter::restoreState(const QByteArray &state) various aspects of the filter. Called when the user requests to configure the filter. - Set \a needsRefresh to \c true, if a refresh() should be done after + Set \a needsRefresh to \c true, if a refresh should be done after closing the dialog. Return \c false if the user canceled the dialog. The default implementation allows changing the shortcut and whether the filter is included by default. - \sa refresh() + \sa refreshRecipe() */ bool ILocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) { @@ -616,14 +626,6 @@ bool ILocatorFilter::isOldSetting(const QByteArray &state) \sa caseSensitivity() */ -/*! - \fn void Core::ILocatorFilter::refresh(QFutureInterface &future) - - Refreshes cached data asynchronously. - - If \a future is \c canceled, the refresh should be aborted. -*/ - /*! \enum Core::ILocatorFilter::Priority diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 5adb2ebef71..b032ab5f94d 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -17,8 +17,12 @@ #include +namespace Utils::Tasking { class TaskItem; } + namespace Core { +namespace Internal { class Locator; } + class ILocatorFilter; class LocatorFilterEntry @@ -157,8 +161,6 @@ public: virtual void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const; - virtual void refresh(QFutureInterface &future) { Q_UNUSED(future) }; - virtual QByteArray saveState() const; virtual void restoreState(const QByteArray &state); @@ -202,6 +204,9 @@ protected: static bool isOldSetting(const QByteArray &state); private: + friend class Internal::Locator; + virtual std::optional refreshRecipe(); + Utils::Id m_id; QString m_shortcut; Priority m_priority = Medium; diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index afc060385bc..d43b77e7508 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -382,14 +382,16 @@ void Locator::refresh(const QList &filters) using namespace Tasking; QList tasks{parallel}; for (ILocatorFilter *filter : std::as_const(m_refreshingFilters)) { - const auto setupRefresh = [filter](AsyncTask &async) { - async.setAsyncCallData(&ILocatorFilter::refresh, filter); + const auto task = filter->refreshRecipe(); + if (!task.has_value()) + continue; + + const Group group { + optional, + *task, + OnGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); }) }; - const auto onRefreshDone = [this, filter](const AsyncTask &async) { - Q_UNUSED(async) - m_refreshingFilters.removeOne(filter); - }; - tasks.append(Async(setupRefresh, onRefreshDone)); + tasks.append(group); } m_taskTree.reset(new TaskTree{tasks}); diff --git a/src/plugins/coreplugin/locator/locator_test.cpp b/src/plugins/coreplugin/locator/locator_test.cpp index eca70f2eaab..a261d15586b 100644 --- a/src/plugins/coreplugin/locator/locator_test.cpp +++ b/src/plugins/coreplugin/locator/locator_test.cpp @@ -28,8 +28,6 @@ public: { setFileIterator(new BaseFileFilter::ListIterator(theFiles)); } - - void refresh(QFutureInterface &) override {} }; class ReferenceData diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index dc2a25b3736..cc24d086065 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -115,4 +116,22 @@ QList OpenDocumentsFilter::editors() const return m_editors; } +void OpenDocumentsFilter::refreshInternally() +{ + QMutexLocker lock(&m_mutex); + m_editors.clear(); + const QList documentEntries = DocumentModel::entries(); + // create copy with only the information relevant to use + // to avoid model deleting entries behind our back + for (DocumentModel::Entry *e : documentEntries) + m_editors.append({e->filePath(), e->displayName()}); +} + +using namespace Utils::Tasking; + +std::optional OpenDocumentsFilter::refreshRecipe() +{ + return Sync([this] { refreshInternally(); return true; }); +} + } // Core::Internal diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index 4924b04a1fb..aa8792730f0 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -7,10 +7,7 @@ #include -#include -#include #include -#include namespace Core { namespace Internal { @@ -38,6 +35,8 @@ private: }; QList editors() const; + void refreshInternally(); + std::optional refreshRecipe() override; mutable QMutex m_mutex; QList m_editors; diff --git a/src/plugins/cppeditor/cppincludesfilter.cpp b/src/plugins/cppeditor/cppincludesfilter.cpp index 970e179fc00..e96b3ee0d20 100644 --- a/src/plugins/cppeditor/cppincludesfilter.cpp +++ b/src/plugins/cppeditor/cppincludesfilter.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include using namespace Core; using namespace ProjectExplorer; @@ -109,19 +111,19 @@ CppIncludesFilter::CppIncludesFilter() setPriority(ILocatorFilter::Low); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, - this, &CppIncludesFilter::markOutdated); + this, &CppIncludesFilter::invalidateCache); connect(CppModelManager::instance(), &CppModelManager::documentUpdated, - this, &CppIncludesFilter::markOutdated); + this, &CppIncludesFilter::invalidateCache); connect(CppModelManager::instance(), &CppModelManager::aboutToRemoveFiles, - this, &CppIncludesFilter::markOutdated); + this, &CppIncludesFilter::invalidateCache); connect(DocumentModel::model(), &QAbstractItemModel::rowsInserted, - this, &CppIncludesFilter::markOutdated); + this, &CppIncludesFilter::invalidateCache); connect(DocumentModel::model(), &QAbstractItemModel::rowsRemoved, - this, &CppIncludesFilter::markOutdated); + this, &CppIncludesFilter::invalidateCache); connect(DocumentModel::model(), &QAbstractItemModel::dataChanged, - this, &CppIncludesFilter::markOutdated); + this, &CppIncludesFilter::invalidateCache); connect(DocumentModel::model(), &QAbstractItemModel::modelReset, - this, &CppIncludesFilter::markOutdated); + this, &CppIncludesFilter::invalidateCache); } void CppIncludesFilter::prepareSearch(const QString &entry) @@ -146,16 +148,17 @@ void CppIncludesFilter::prepareSearch(const QString &entry) BaseFileFilter::prepareSearch(entry); } -void CppIncludesFilter::refresh(QFutureInterface &future) -{ - Q_UNUSED(future) - QMetaObject::invokeMethod(this, &CppIncludesFilter::markOutdated, Qt::QueuedConnection); -} - -void CppIncludesFilter::markOutdated() +void CppIncludesFilter::invalidateCache() { m_needsUpdate = true; setFileIterator(nullptr); // clean up } +using namespace Utils::Tasking; + +std::optional CppIncludesFilter::refreshRecipe() +{ + return Sync([this] { invalidateCache(); return true; }); +} + } // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cppincludesfilter.h b/src/plugins/cppeditor/cppincludesfilter.h index 6ae5dbb91c4..720b6cbb9b9 100644 --- a/src/plugins/cppeditor/cppincludesfilter.h +++ b/src/plugins/cppeditor/cppincludesfilter.h @@ -15,10 +15,10 @@ public: // ILocatorFilter interface public: void prepareSearch(const QString &entry) override; - void refresh(QFutureInterface &future) override; private: - void markOutdated(); + void invalidateCache(); + std::optional refreshRecipe() override; bool m_needsUpdate = true; }; diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index fe1c34a48e0..ef77f343468 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -105,12 +106,6 @@ void HelpIndexFilter::accept(const LocatorFilterEntry &selection, emit linksActivated(links, key); } -void HelpIndexFilter::refresh(QFutureInterface &future) -{ - Q_UNUSED(future) - invalidateCache(); -} - QStringList HelpIndexFilter::allIndices() const { LocalHelpManager::setupGuiHelpEngine(); @@ -121,3 +116,10 @@ void HelpIndexFilter::invalidateCache() { m_needsUpdate = true; } + +using namespace Utils::Tasking; + +std::optional HelpIndexFilter::refreshRecipe() +{ + return Sync([this] { invalidateCache(); return true; }); +} diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h index 1dfc6f59952..56ffa226bb4 100644 --- a/src/plugins/help/helpindexfilter.h +++ b/src/plugins/help/helpindexfilter.h @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -28,7 +27,6 @@ public: const QString &entry) override; void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; - void refresh(QFutureInterface &future) override; QStringList allIndices() const; @@ -36,10 +34,10 @@ signals: void linksActivated(const QMultiMap &links, const QString &key) const; private: - void invalidateCache(); - bool updateCache(QFutureInterface &future, const QStringList &cache, const QString &entry); + void invalidateCache(); + std::optional refreshRecipe() override; QStringList m_allIndicesCache; QStringList m_lastIndicesCache; diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index fddbceccb1c..19c2d499255 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -9,6 +9,7 @@ #include "projectmanager.h" #include +#include using namespace Core; @@ -25,12 +26,7 @@ AllProjectsFilter::AllProjectsFilter() setDefaultIncludedByDefault(true); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, - this, &AllProjectsFilter::markFilesAsOutOfDate); -} - -void AllProjectsFilter::markFilesAsOutOfDate() -{ - setFileIterator(nullptr); + this, &AllProjectsFilter::invalidateCache); } void AllProjectsFilter::prepareSearch(const QString &entry) @@ -46,10 +42,16 @@ void AllProjectsFilter::prepareSearch(const QString &entry) BaseFileFilter::prepareSearch(entry); } -void AllProjectsFilter::refresh(QFutureInterface &future) +void AllProjectsFilter::invalidateCache() { - Q_UNUSED(future) - QMetaObject::invokeMethod(this, &AllProjectsFilter::markFilesAsOutOfDate, Qt::QueuedConnection); + setFileIterator(nullptr); +} + +using namespace Utils::Tasking; + +std::optional AllProjectsFilter::refreshRecipe() +{ + return Sync([this] { invalidateCache(); return true; }); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/allprojectsfilter.h b/src/plugins/projectexplorer/allprojectsfilter.h index ae9fdffe92b..c85cc3fe28f 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.h +++ b/src/plugins/projectexplorer/allprojectsfilter.h @@ -5,8 +5,6 @@ #include -#include - namespace ProjectExplorer { namespace Internal { @@ -16,11 +14,11 @@ class AllProjectsFilter : public Core::BaseFileFilter public: AllProjectsFilter(); - void refresh(QFutureInterface &future) override; void prepareSearch(const QString &entry) override; private: - void markFilesAsOutOfDate(); + void invalidateCache(); + std::optional refreshRecipe() override; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index 69b88ddf46c..ec5a1e7ffdd 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -8,6 +8,7 @@ #include "projecttree.h" #include +#include using namespace Core; using namespace ProjectExplorer; @@ -28,11 +29,6 @@ CurrentProjectFilter::CurrentProjectFilter() this, &CurrentProjectFilter::currentProjectChanged); } -void CurrentProjectFilter::markFilesAsOutOfDate() -{ - setFileIterator(nullptr); -} - void CurrentProjectFilter::prepareSearch(const QString &entry) { Q_UNUSED(entry) @@ -52,19 +48,24 @@ void CurrentProjectFilter::currentProjectChanged() return; if (m_project) disconnect(m_project, &Project::fileListChanged, - this, &CurrentProjectFilter::markFilesAsOutOfDate); + this, &CurrentProjectFilter::invalidateCache); if (project) connect(project, &Project::fileListChanged, - this, &CurrentProjectFilter::markFilesAsOutOfDate); + this, &CurrentProjectFilter::invalidateCache); m_project = project; - markFilesAsOutOfDate(); + invalidateCache(); } -void CurrentProjectFilter::refresh(QFutureInterface &future) +void CurrentProjectFilter::invalidateCache() { - Q_UNUSED(future) - QMetaObject::invokeMethod(this, &CurrentProjectFilter::markFilesAsOutOfDate, - Qt::QueuedConnection); + setFileIterator(nullptr); +} + +using namespace Utils::Tasking; + +std::optional CurrentProjectFilter::refreshRecipe() +{ + return Sync([this] { invalidateCache(); return true; }); } diff --git a/src/plugins/projectexplorer/currentprojectfilter.h b/src/plugins/projectexplorer/currentprojectfilter.h index b9d63db2930..8db0c567c0e 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.h +++ b/src/plugins/projectexplorer/currentprojectfilter.h @@ -5,8 +5,6 @@ #include -#include - namespace ProjectExplorer { class Project; @@ -19,12 +17,12 @@ class CurrentProjectFilter : public Core::BaseFileFilter public: CurrentProjectFilter(); - void refresh(QFutureInterface &future) override; void prepareSearch(const QString &entry) override; private: void currentProjectChanged(); - void markFilesAsOutOfDate(); + void invalidateCache(); + std::optional refreshRecipe() override; Project *m_project = nullptr; }; From dc8da57e6452ce4dbd97b1a53de8c297bd4e5bcf Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 6 Mar 2023 13:11:15 +0100 Subject: [PATCH 0170/1447] tst_QtcProcess: Use snprintf instead of sprintf This fixes the following warning: warning: 'sprintf' is deprecated: This function is provided for compatibility reasons only. Due to security concerns inherent in the design of sprintf(3), it is highly recommended that you use snprintf(3) instead. Change-Id: Ic8eac91b02cb60122f603506e083dbdf9eca8712 Reviewed-by: Eike Ziller --- tests/auto/utils/qtcprocess/tst_qtcprocess.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp index a26924089e0..97792d9fb47 100644 --- a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp @@ -698,11 +698,11 @@ void tst_QtcProcess::expandMacros_data() title = vals[i].in; } else { char buf[80]; - sprintf(buf, "%s: %s", title, vals[i].in); + snprintf(buf, 80, "%s: %s", title, vals[i].in); QTest::newRow(buf) << QString::fromLatin1(vals[i].in) << QString::fromLatin1(vals[i].out) << vals[i].os; - sprintf(buf, "padded %s: %s", title, vals[i].in); + snprintf(buf, 80, "padded %s: %s", title, vals[i].in); QTest::newRow(buf) << QString(sp + QString::fromLatin1(vals[i].in) + sp) << QString(sp + QString::fromLatin1(vals[i].out) + sp) << vals[i].os; From 755d9769d81a5dc4e0b837650f9fab27a3f094ab Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 3 Mar 2023 15:00:21 +0100 Subject: [PATCH 0171/1447] CPlusPlus: Add support for coroutines Also fix some concept-related bugs uncovered by the test case. Change-Id: Ia67c971026bcd85d9cc252f46cd4f56c2865d432 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.cpp | 4 + src/libs/3rdparty/cplusplus/AST.h | 41 +++++ src/libs/3rdparty/cplusplus/ASTClone.cpp | 22 +++ src/libs/3rdparty/cplusplus/ASTMatch0.cpp | 14 ++ src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 25 +++ src/libs/3rdparty/cplusplus/ASTMatcher.h | 2 + src/libs/3rdparty/cplusplus/ASTVisit.cpp | 15 ++ src/libs/3rdparty/cplusplus/ASTVisitor.h | 4 + src/libs/3rdparty/cplusplus/ASTfwd.h | 2 + src/libs/3rdparty/cplusplus/Bind.cpp | 5 + src/libs/3rdparty/cplusplus/Bind.h | 1 + src/libs/3rdparty/cplusplus/Parser.cpp | 81 ++++++--- src/libs/3rdparty/cplusplus/Parser.h | 2 + src/plugins/cppeditor/cppcodeformatter.cpp | 2 + tests/auto/cplusplus/cxx11/tst_cxx11.cpp | 184 ++++++++++++++++++++- 15 files changed, 382 insertions(+), 22 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 2f351ff7be8..53c84a95c68 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -3763,6 +3763,8 @@ int TemplateTypeParameterAST::firstToken() const { if (template_token) return template_token; + if (typeConstraint) + return typeConstraint->firstToken(); if (less_token) return less_token; if (template_parameter_list) @@ -3807,6 +3809,8 @@ int TemplateTypeParameterAST::lastToken() const return candidate; if (less_token) return less_token + 1; + if (typeConstraint) + return typeConstraint->lastToken(); if (template_token) return template_token + 1; return 1; diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index ff5759ffb2b..0d7e337fd8b 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -184,6 +184,7 @@ public: virtual ArrayInitializerAST *asArrayInitializer() { return nullptr; } virtual AsmDefinitionAST *asAsmDefinition() { return nullptr; } virtual AttributeSpecifierAST *asAttributeSpecifier() { return nullptr; } + virtual AwaitExpressionAST *asAwaitExpression() { return nullptr; } virtual BaseSpecifierAST *asBaseSpecifier() { return nullptr; } virtual BinaryExpressionAST *asBinaryExpression() { return nullptr; } virtual BoolLiteralAST *asBoolLiteral() { return nullptr; } @@ -344,6 +345,7 @@ public: virtual UsingAST *asUsing() { return nullptr; } virtual UsingDirectiveAST *asUsingDirective() { return nullptr; } virtual WhileStatementAST *asWhileStatement() { return nullptr; } + virtual YieldExpressionAST *asYieldExpression() { return nullptr; } protected: virtual void accept0(ASTVisitor *visitor) = 0; @@ -2826,6 +2828,44 @@ protected: bool match0(AST *, ASTMatcher *) override; }; +class CPLUSPLUS_EXPORT YieldExpressionAST: public ExpressionAST +{ +public: + int yield_token = 0; + ExpressionAST *expression = nullptr; + +public: + YieldExpressionAST *asYieldExpression() override { return this; } + + int firstToken() const override { return yield_token; } + int lastToken() const override { return expression->lastToken(); } + + YieldExpressionAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + +class CPLUSPLUS_EXPORT AwaitExpressionAST: public ExpressionAST +{ +public: + int await_token = 0; + ExpressionAST *castExpression = nullptr; + +public: + AwaitExpressionAST *asAwaitExpression() override { return this; } + + int firstToken() const override { return await_token; } + int lastToken() const override { return castExpression->lastToken(); } + + AwaitExpressionAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + class CPLUSPLUS_EXPORT NoExceptOperatorExpressionAST: public ExpressionAST { public: @@ -2956,6 +2996,7 @@ class CPLUSPLUS_EXPORT TemplateTypeParameterAST: public DeclarationAST { public: int template_token = 0; + TypeConstraintAST *typeConstraint = nullptr; int less_token = 0; DeclarationListAST *template_parameter_list = nullptr; int greater_token = 0; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index f4a2f626dad..e1e014afccf 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -147,6 +147,8 @@ TypeConstraintAST *TypeConstraintAST::clone(MemoryPool *pool) const for (NestedNameSpecifierListAST *iter = nestedName, **ast_iter = &ast->nestedName; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) *ast_iter = new (pool) NestedNameSpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); + if (conceptName) + ast->conceptName = conceptName->clone(pool); ast->lessToken = lessToken; for (ExpressionListAST *iter = templateArgs, **ast_iter = &ast->templateArgs; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) @@ -1358,6 +1360,24 @@ ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const return ast; } +YieldExpressionAST *YieldExpressionAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) YieldExpressionAST; + ast->yield_token = yield_token; + if (expression) + ast->expression = expression->clone(pool); + return ast; +} + +AwaitExpressionAST *AwaitExpressionAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) AwaitExpressionAST; + ast->await_token = await_token; + if (castExpression) + ast->castExpression = castExpression->clone(pool); + return ast; +} + NoExceptOperatorExpressionAST *NoExceptOperatorExpressionAST::clone(MemoryPool *pool) const { NoExceptOperatorExpressionAST *ast = new (pool) NoExceptOperatorExpressionAST; @@ -1429,6 +1449,8 @@ TemplateTypeParameterAST *TemplateTypeParameterAST::clone(MemoryPool *pool) cons { TemplateTypeParameterAST *ast = new (pool) TemplateTypeParameterAST; ast->template_token = template_token; + if (typeConstraint) + ast->typeConstraint = typeConstraint->clone(pool); ast->less_token = less_token; for (DeclarationListAST *iter = template_parameter_list, **ast_iter = &ast->template_parameter_list; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index a4bd9935f0e..b58bd59efe0 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -941,6 +941,20 @@ bool ThrowExpressionAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool YieldExpressionAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto other = pattern->asYieldExpression()) + return matcher->match(this, other); + return false; +} + +bool AwaitExpressionAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto other = pattern->asAwaitExpression()) + return matcher->match(this, other); + return false; +} + bool NoExceptOperatorExpressionAST::match0(AST *pattern, ASTMatcher *matcher) { if (NoExceptOperatorExpressionAST *_other = pattern->asNoExceptOperatorExpression()) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index d39d0717c55..4567cd68a25 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -2277,6 +2277,26 @@ bool ASTMatcher::match(ThrowExpressionAST *node, ThrowExpressionAST *pattern) return true; } +bool ASTMatcher::match(YieldExpressionAST *node, YieldExpressionAST *pattern) +{ + pattern->yield_token = node->yield_token; + if (!pattern->expression) + pattern->expression = node->expression; + else if (!AST::match(node->expression, pattern->expression, this)) + return false; + return true; +} + +bool ASTMatcher::match(AwaitExpressionAST *node, AwaitExpressionAST *pattern) +{ + pattern->await_token = node->await_token; + if (!pattern->castExpression) + pattern->castExpression = node->castExpression; + else if (!AST::match(node->castExpression, pattern->castExpression, this)) + return false; + return true; +} + bool ASTMatcher::match(NoExceptOperatorExpressionAST *node, NoExceptOperatorExpressionAST *pattern) { (void) node; @@ -2398,6 +2418,11 @@ bool ASTMatcher::match(TemplateTypeParameterAST *node, TemplateTypeParameterAST pattern->template_token = node->template_token; + if (!pattern->typeConstraint) + pattern->typeConstraint = node->typeConstraint; + else if (!AST::match(node->typeConstraint, pattern->typeConstraint, this)) + return false; + pattern->less_token = node->less_token; if (! pattern->template_parameter_list) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index c7d762c9e11..fb6109a07dc 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -38,6 +38,7 @@ public: virtual bool match(ArrayAccessAST *node, ArrayAccessAST *pattern); virtual bool match(ArrayDeclaratorAST *node, ArrayDeclaratorAST *pattern); virtual bool match(ArrayInitializerAST *node, ArrayInitializerAST *pattern); + virtual bool match(AwaitExpressionAST *node, AwaitExpressionAST *pattern); virtual bool match(AsmDefinitionAST *node, AsmDefinitionAST *pattern); virtual bool match(BaseSpecifierAST *node, BaseSpecifierAST *pattern); virtual bool match(BinaryExpressionAST *node, BinaryExpressionAST *pattern); @@ -188,6 +189,7 @@ public: virtual bool match(UsingAST *node, UsingAST *pattern); virtual bool match(UsingDirectiveAST *node, UsingDirectiveAST *pattern); virtual bool match(WhileStatementAST *node, WhileStatementAST *pattern); + virtual bool match(YieldExpressionAST *node, YieldExpressionAST *pattern); }; } // namespace CPlusPlus diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index cde7842280d..d83684b966d 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -996,6 +996,20 @@ void ThrowExpressionAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void YieldExpressionAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) + accept(expression, visitor); + visitor->endVisit(this); +} + +void AwaitExpressionAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) + accept(castExpression, visitor); + visitor->endVisit(this); +} + void NoExceptOperatorExpressionAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { @@ -1051,6 +1065,7 @@ void TypenameTypeParameterAST::accept0(ASTVisitor *visitor) void TemplateTypeParameterAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { + accept(typeConstraint, visitor); accept(template_parameter_list, visitor); accept(name, visitor); accept(type_id, visitor); diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index 9f277836937..9d9fec75b1d 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -81,6 +81,7 @@ public: virtual bool visit(ArrayDeclaratorAST *) { return true; } virtual bool visit(ArrayInitializerAST *) { return true; } virtual bool visit(AsmDefinitionAST *) { return true; } + virtual bool visit(AwaitExpressionAST *) { return true; } virtual bool visit(BaseSpecifierAST *) { return true; } virtual bool visit(BinaryExpressionAST *) { return true; } virtual bool visit(BoolLiteralAST *) { return true; } @@ -230,6 +231,7 @@ public: virtual bool visit(UsingAST *) { return true; } virtual bool visit(UsingDirectiveAST *) { return true; } virtual bool visit(WhileStatementAST *) { return true; } + virtual bool visit(YieldExpressionAST *) { return true; } virtual void endVisit(AccessDeclarationAST *) {} virtual void endVisit(AliasDeclarationAST *) {} @@ -240,6 +242,7 @@ public: virtual void endVisit(ArrayDeclaratorAST *) {} virtual void endVisit(ArrayInitializerAST *) {} virtual void endVisit(AsmDefinitionAST *) {} + virtual void endVisit(AwaitExpressionAST *) {} virtual void endVisit(BaseSpecifierAST *) {} virtual void endVisit(BinaryExpressionAST *) {} virtual void endVisit(BoolLiteralAST *) {} @@ -389,6 +392,7 @@ public: virtual void endVisit(UsingAST *) {} virtual void endVisit(UsingDirectiveAST *) {} virtual void endVisit(WhileStatementAST *) {} + virtual void endVisit(YieldExpressionAST *) {} private: TranslationUnit *_translationUnit; diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index b5222e2bbec..102fda75fb5 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -40,6 +40,7 @@ class ArrayDeclaratorAST; class ArrayInitializerAST; class AsmDefinitionAST; class AttributeSpecifierAST; +class AwaitExpressionAST; class BaseSpecifierAST; class BinaryExpressionAST; class BoolLiteralAST; @@ -200,6 +201,7 @@ class UnaryExpressionAST; class UsingAST; class UsingDirectiveAST; class WhileStatementAST; +class YieldExpressionAST; typedef List ExpressionListAST; typedef List DeclarationListAST; diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 6293d732e05..202c36a51fa 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -2532,6 +2532,11 @@ bool Bind::visit(TemplateTypeParameterAST *ast) return false; } +bool Bind::visit(TypeConstraintAST *) +{ + return false; +} + bool Bind::visit(UsingAST *ast) { int sourceLocation = location(ast->name, ast->firstToken()); diff --git a/src/libs/3rdparty/cplusplus/Bind.h b/src/libs/3rdparty/cplusplus/Bind.h index 4d12beee86d..867ed7baaa8 100644 --- a/src/libs/3rdparty/cplusplus/Bind.h +++ b/src/libs/3rdparty/cplusplus/Bind.h @@ -230,6 +230,7 @@ protected: bool visit(TemplateDeclarationAST *ast) override; bool visit(TypenameTypeParameterAST *ast) override; bool visit(TemplateTypeParameterAST *ast) override; + bool visit(TypeConstraintAST *ast) override; bool visit(UsingAST *ast) override; bool visit(UsingDirectiveAST *ast) override; bool visit(ObjCClassForwardDeclarationAST *ast) override; diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 004bee40e71..45c2493fff4 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -413,6 +413,7 @@ bool Parser::skipUntilStatement() case T_BREAK: case T_CONTINUE: case T_RETURN: + case T_CO_RETURN: case T_GOTO: case T_TRY: case T_CATCH: @@ -1329,16 +1330,20 @@ bool Parser::parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node) bool Parser::parseTypeConstraint(TypeConstraintAST *&node) { + if (!_languageFeatures.cxx20Enabled) + return false; NestedNameSpecifierListAST *nestedName = nullptr; parseNestedNameSpecifierOpt(nestedName, true); NameAST *conceptName = nullptr; - if (!parseUnqualifiedName(conceptName, true)) + if (!parseUnqualifiedName(conceptName, false)) return false; const auto typeConstraint = new (_pool) TypeConstraintAST; typeConstraint->nestedName = nestedName; typeConstraint->conceptName = conceptName; - if (LA() != T_LESS) + if (LA() != T_LESS) { + node = typeConstraint; return true; + } typeConstraint->lessToken = consumeToken(); if (LA() != T_GREATER) { if (!parseTemplateArgumentList(typeConstraint->templateArgs)) @@ -2208,8 +2213,8 @@ bool Parser::parseTypenameTypeParameter(DeclarationAST *&node) bool Parser::parseTemplateTypeParameter(DeclarationAST *&node) { DEBUG_THIS_RULE(); + TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST; if (LA() == T_TEMPLATE) { - TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST; ast->template_token = consumeToken(); if (LA() == T_LESS) ast->less_token = consumeToken(); @@ -2218,20 +2223,21 @@ bool Parser::parseTemplateTypeParameter(DeclarationAST *&node) ast->greater_token = consumeToken(); if (LA() == T_CLASS) ast->class_token = consumeToken(); - if (_languageFeatures.cxx11Enabled && LA() == T_DOT_DOT_DOT) - ast->dot_dot_dot_token = consumeToken(); - - // parse optional name - parseName(ast->name); - - if (LA() == T_EQUAL) { - ast->equal_token = consumeToken(); - parseTypeId(ast->type_id); - } - node = ast; - return true; + } else if (!parseTypeConstraint(ast->typeConstraint)) { + return false; } - return false; + if (_languageFeatures.cxx11Enabled && LA() == T_DOT_DOT_DOT) + ast->dot_dot_dot_token = consumeToken(); + + // parse optional name + parseName(ast->name); + + if (LA() == T_EQUAL) { + ast->equal_token = consumeToken(); + parseTypeId(ast->type_id); + } + node = ast; + return true; } bool Parser::lookAtTypeParameter() @@ -2267,10 +2273,9 @@ bool Parser::parseTypeParameter(DeclarationAST *&node) if (lookAtTypeParameter()) return parseTypenameTypeParameter(node); - else if (LA() == T_TEMPLATE) + if (LA() == T_TEMPLATE) return parseTemplateTypeParameter(node); - else - return false; + return parseTemplateTypeParameter(node); } bool Parser::parseTypeId(ExpressionAST *&node) @@ -3556,6 +3561,7 @@ bool Parser::parseStatement(StatementAST *&node, bool blockLabeledStatement) return parseGotoStatement(node); case T_RETURN: + case T_CO_RETURN: return parseReturnStatement(node); case T_LBRACE: @@ -3666,7 +3672,7 @@ bool Parser::parseGotoStatement(StatementAST *&node) bool Parser::parseReturnStatement(StatementAST *&node) { DEBUG_THIS_RULE(); - if (LA() == T_RETURN) { + if (LA() == T_RETURN || LA() == T_CO_RETURN) { ReturnStatementAST *ast = new (_pool) ReturnStatementAST; ast->return_token = consumeToken(); if (_languageFeatures.cxx11Enabled && LA() == T_LBRACE) @@ -5637,6 +5643,11 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node) return parseNoExceptOperatorExpression(node); } + case T_CO_AWAIT: + if (!_languageFeatures.cxx20Enabled) + break; + return parseAwaitExpression(node); + default: break; } // switch @@ -5895,6 +5906,8 @@ bool Parser::parseAssignmentExpression(ExpressionAST *&node) DEBUG_THIS_RULE(); if (LA() == T_THROW) return parseThrowExpression(node); + else if (LA() == T_CO_YIELD) + return parseYieldExpression(node); else PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Assignment) } @@ -6023,6 +6036,34 @@ bool Parser::parseThrowExpression(ExpressionAST *&node) return false; } +bool Parser::parseYieldExpression(ExpressionAST *&node) +{ + DEBUG_THIS_RULE(); + if (LA() != T_CO_YIELD) + return false; + const auto ast = new (_pool) YieldExpressionAST; + ast->yield_token = consumeToken(); + if (parseBracedInitList0x(ast->expression) || parseAssignmentExpression(ast->expression)) { + node = ast; + return true; + } + return false; +} + +bool Parser::parseAwaitExpression(ExpressionAST *&node) +{ + DEBUG_THIS_RULE(); + if (LA() != T_CO_AWAIT) + return false; + const auto ast = new (_pool) AwaitExpressionAST; + ast->await_token = consumeToken(); + if (parseCastExpression(ast->castExpression)) { + node = ast; + return true; + } + return false; +} + bool Parser::parseNoExceptOperatorExpression(ExpressionAST *&node) { DEBUG_THIS_RULE(); diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index a50706b5f34..e34a4ff5223 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -152,6 +152,8 @@ public: bool parseTemplateParameter(DeclarationAST *&node); bool parseTemplateParameterList(DeclarationListAST *&node); bool parseThrowExpression(ExpressionAST *&node); + bool parseYieldExpression(ExpressionAST *&node); + bool parseAwaitExpression(ExpressionAST *&node); bool parseNoExceptOperatorExpression(ExpressionAST *&node); bool parseTryBlockStatement(StatementAST *&node, CtorInitializerAST **placeholder); bool parseCatchClause(CatchClauseListAST *&node); diff --git a/src/plugins/cppeditor/cppcodeformatter.cpp b/src/plugins/cppeditor/cppcodeformatter.cpp index ce250f672b0..6b30e78fa6c 100644 --- a/src/plugins/cppeditor/cppcodeformatter.cpp +++ b/src/plugins/cppeditor/cppcodeformatter.cpp @@ -924,6 +924,7 @@ bool CodeFormatter::tryStatement() return true; switch (kind) { case T_RETURN: + case T_CO_RETURN: enter(return_statement); enter(expression); return true; @@ -1651,6 +1652,7 @@ void QtStyleCodeFormatter::adjustIndent(const Tokens &tokens, int lexerState, in case T_BREAK: case T_CONTINUE: case T_RETURN: + case T_CO_RETURN: if (topState.type == case_cont) { *indentDepth = topState.savedIndentDepth; if (m_styleSettings.indentControlFlowRelativeToSwitchLabels) diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index ea859b77d98..4bb4e4b4b24 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -148,6 +148,7 @@ private Q_SLOTS: void concepts(); void requiresClause(); + void coroutines(); }; @@ -315,7 +316,7 @@ void *func2(IsPointer auto p) processDocument(doc, source.toUtf8(), features, &errors); const bool hasErrors = !errors.isEmpty(); if (hasErrors) - qDebug() << errors; + qDebug().noquote() << errors; QVERIFY(!hasErrors); } @@ -337,7 +338,186 @@ template void h(T) requires (is_purrable()); processDocument(doc, source.toUtf8(), features, &errors); const bool hasErrors = !errors.isEmpty(); if (hasErrors) - qDebug() << errors; + qDebug().noquote() << errors; + QVERIFY(!hasErrors); +} + +void tst_cxx11::coroutines() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx20Enabled = true; + + const QString source = R"( +struct promise; +struct coroutine : std::coroutine_handle +{ + using promise_type = struct promise; +}; +struct promise +{ + coroutine get_return_object() { return {coroutine::from_promise(*this)}; } + std::suspend_always initial_suspend() noexcept { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} +}; +struct S +{ + int i; + coroutine f() + { + std::cout << i; + co_return; + } +}; +void good() +{ + coroutine h = [](int i) -> coroutine + { + std::cout << i; + co_return; + }(0); + h.resume(); + h.destroy(); +} +auto switch_to_new_thread(std::jthread& out) +{ + struct awaitable + { + std::jthread* p_out; + bool await_ready() { return false; } + void await_suspend(std::coroutine_handle<> h) + { + std::jthread& out = *p_out; + if (out.joinable()) + throw std::runtime_error("Output jthread parameter not empty"); + out = std::jthread([h] { h.resume(); }); + std::cout << "New thread ID: " << out.get_id() << '\n'; // this is OK + } + void await_resume() {} + }; + return awaitable{&out}; +} +struct task +{ + struct promise_type + { + task get_return_object() { return {}; } + std::suspend_never initial_suspend() { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} + }; +}; +task resuming_on_new_thread(std::jthread& out) +{ + std::cout << "Coroutine started on thread: " << std::this_thread::get_id() << '\n'; + co_await switch_to_new_thread(out); + std::cout << "Coroutine resumed on thread: " << std::this_thread::get_id() << '\n'; +} +void run() +{ + std::jthread out; + resuming_on_new_thread(out); +} +template +struct Generator +{ + struct promise_type; + using handle_type = std::coroutine_handle; + struct promise_type // required + { + T value_; + std::exception_ptr exception_; + + Generator get_return_object() + { + return Generator(handle_type::from_promise(*this)); + } + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() { exception_ = std::current_exception(); } + template From> + std::suspend_always yield_value(From&& from) + { + value_ = std::forward(from); + return {}; + } + void return_void() { } + }; + handle_type h_; + Generator(handle_type h) : h_(h) {} + ~Generator() { h_.destroy(); } + explicit operator bool() + { + fill(); + return !h_.done(); + } + T operator()() + { + fill(); + full_ = false; + return std::move(h_.promise().value_); + } +private: + bool full_ = false; + void fill() + { + if (!full_) + { + h_(); + if (h_.promise().exception_) + std::rethrow_exception(h_.promise().exception_); + full_ = true; + } + } +}; +Generator +fibonacci_sequence(unsigned n) +{ + if (n == 0) + co_return; + if (n > 94) + throw std::runtime_error("Too big Fibonacci sequence. Elements would overflow."); + co_yield 0; + if (n == 1) + co_return; + co_yield 1; + if (n == 2) + co_return; + std::uint64_t a = 0; + std::uint64_t b = 1; + for (unsigned i = 2; i < n; i++) + { + std::uint64_t s = a + b; + co_yield s; + a = b; + b = s; + } +} +int main() +{ + try + { + auto gen = fibonacci_sequence(10); // max 94 before uint64_t overflows + for (int j = 0; gen; j++) + std::cout << "fib(" << j << ")=" << gen() << '\n'; + } catch (const std::exception& ex) { + std::cerr << "Exception: " << ex.what() << '\n'; + } + catch (...) + { + std::cerr << "Unknown exception.\n"; + } +} +)"; + QByteArray errors; + Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile")); + processDocument(doc, source.toUtf8(), features, &errors); + const bool hasErrors = !errors.isEmpty(); + if (hasErrors) + qDebug().noquote() << errors; QVERIFY(!hasErrors); } From bb4d9c92e77f44b55f06a8b8080b5f35d363a1f5 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 3 Mar 2023 11:25:09 +0100 Subject: [PATCH 0172/1447] SdkTool: Fork utils/persistentsettings And a few helper classes. This allows SdkTool being build without Creator's Utils, and does not impose restrictions on the development there. Change-Id: Id15db9293f343ad2aeee5c09cc819d112ec144e4 Reviewed-by: Eike Ziller --- src/tools/sdktool/CMakeLists.txt | 28 +- src/tools/sdktool/addcmakeoperation.cpp | 5 +- src/tools/sdktool/adddebuggeroperation.cpp | 3 +- src/tools/sdktool/addkitoperation.cpp | 3 +- src/tools/sdktool/addqtoperation.cpp | 8 +- src/tools/sdktool/addtoolchainoperation.cpp | 5 +- src/tools/sdktool/main.cpp | 10 +- src/tools/sdktool/operation.cpp | 25 +- src/tools/sdktool/operation.h | 2 - src/tools/sdktool/sdkpersistentsettings.cpp | 870 ++++++++++++++++++++ src/tools/sdktool/sdkpersistentsettings.h | 37 + src/tools/sdktool/sdktoollib.qbs | 31 +- src/tools/sdktool/settings.cpp | 26 +- src/tools/sdktool/settings.h | 6 +- 14 files changed, 948 insertions(+), 111 deletions(-) create mode 100644 src/tools/sdktool/sdkpersistentsettings.cpp create mode 100644 src/tools/sdktool/sdkpersistentsettings.h diff --git a/src/tools/sdktool/CMakeLists.txt b/src/tools/sdktool/CMakeLists.txt index 39c7a1b5446..937aa04087a 100644 --- a/src/tools/sdktool/CMakeLists.txt +++ b/src/tools/sdktool/CMakeLists.txt @@ -66,33 +66,7 @@ add_qtc_library(sdktoolLib rmqtoperation.cpp rmqtoperation.h rmtoolchainoperation.cpp rmtoolchainoperation.h settings.cpp settings.h -) - -extend_qtc_library(sdktoolLib - SOURCES_PREFIX "${UtilsSourcesDir}" - PUBLIC_DEFINES UTILS_STATIC_LIBRARY - SOURCES - commandline.cpp commandline.h - devicefileaccess.cpp devicefileaccess.h - environment.cpp environment.h - filepath.cpp filepath.h - fileutils.cpp fileutils.h - hostosinfo.cpp hostosinfo.h - macroexpander.cpp macroexpander.h - namevaluedictionary.cpp namevaluedictionary.h - namevalueitem.cpp namevalueitem.h - persistentsettings.cpp persistentsettings.h - qtcassert.cpp qtcassert.h - savefile.cpp savefile.h - stringutils.cpp stringutils.h -) - -extend_qtc_library(sdktoolLib CONDITION APPLE - SOURCES_PREFIX "${UtilsSourcesDir}" - SOURCES - fileutils_mac.mm fileutils_mac.h - PUBLIC_DEPENDS - ${FWFoundation} + sdkpersistentsettings.cpp sdkpersistentsettings.h ) if (MSVC) diff --git a/src/tools/sdktool/addcmakeoperation.cpp b/src/tools/sdktool/addcmakeoperation.cpp index 751db965e82..f97fcef2a68 100644 --- a/src/tools/sdktool/addcmakeoperation.cpp +++ b/src/tools/sdktool/addcmakeoperation.cpp @@ -4,13 +4,10 @@ #include "addcmakeoperation.h" #include "addkeysoperation.h" -#include "findkeyoperation.h" #include "findvalueoperation.h" #include "getoperation.h" #include "rmkeysoperation.h" -#include "settings.h" - #ifdef WITH_TESTS #include #endif @@ -205,7 +202,7 @@ QVariantMap AddCMakeData::addCMake(const QVariantMap &map) const data << KeyValuePair({cm, ID_KEY}, QVariant(m_id)); data << KeyValuePair({cm, DISPLAYNAME_KEY}, QVariant(m_displayName)); data << KeyValuePair({cm, AUTODETECTED_KEY}, QVariant(true)); - data << KeyValuePair({cm, PATH_KEY}, Utils::FilePath::fromUserInput(m_path).toVariant()); + data << KeyValuePair({cm, PATH_KEY}, QVariant(m_path)); KeyValuePairList extraList; for (const KeyValuePair &pair : std::as_const(m_extra)) extraList << KeyValuePair(QStringList({cm}) << pair.key, pair.value); diff --git a/src/tools/sdktool/adddebuggeroperation.cpp b/src/tools/sdktool/adddebuggeroperation.cpp index c11b20ec81d..69de58be05e 100644 --- a/src/tools/sdktool/adddebuggeroperation.cpp +++ b/src/tools/sdktool/adddebuggeroperation.cpp @@ -222,8 +222,7 @@ QVariantMap AddDebuggerData::addDebugger(const QVariantMap &map) const data << KeyValuePair(QStringList() << debugger << QLatin1String(ABIS), QVariant(m_abis)); data << KeyValuePair(QStringList() << debugger << QLatin1String(ENGINE_TYPE), QVariant(m_engine)); - data << KeyValuePair(QStringList() << debugger << QLatin1String(BINARY), - Utils::FilePath::fromUserInput(m_binary).toSettings()); + data << KeyValuePair(QStringList() << debugger << QLatin1String(BINARY), QVariant(m_binary)); data << KeyValuePair(QStringList() << QLatin1String(COUNT), QVariant(count + 1)); diff --git a/src/tools/sdktool/addkitoperation.cpp b/src/tools/sdktool/addkitoperation.cpp index 14569ba8398..6ed2feea365 100644 --- a/src/tools/sdktool/addkitoperation.cpp +++ b/src/tools/sdktool/addkitoperation.cpp @@ -685,8 +685,7 @@ QVariantMap AddKitData::addKit(const QVariantMap &map, if (!m_buildDevice.isNull()) data << KeyValuePair({kit, DATA, BUILDDEVICE_ID}, QVariant(m_buildDevice)); if (!m_sysRoot.isNull()) - data << KeyValuePair({kit, DATA, SYSROOT}, - Utils::FilePath::fromUserInput(m_sysRoot).toSettings()); + data << KeyValuePair({kit, DATA, SYSROOT}, QVariant(QDir::cleanPath(m_sysRoot))); for (auto i = m_tcs.constBegin(); i != m_tcs.constEnd(); ++i) data << KeyValuePair({kit, DATA, TOOLCHAIN, i.key()}, QVariant(i.value())); if (!qtId.isNull()) diff --git a/src/tools/sdktool/addqtoperation.cpp b/src/tools/sdktool/addqtoperation.cpp index 875e59d9143..69117eb53a0 100644 --- a/src/tools/sdktool/addqtoperation.cpp +++ b/src/tools/sdktool/addqtoperation.cpp @@ -11,8 +11,6 @@ #include "settings.h" -#include - #ifdef WITH_TESTS #include #endif @@ -22,8 +20,6 @@ Q_LOGGING_CATEGORY(log, "qtc.sdktool.operations.addqt", QtWarningMsg) -using namespace Utils; - // Qt version file stuff: const char PREFIX[] = "QtVersion."; const char VERSION[] = "Version"; @@ -282,7 +278,7 @@ QVariantMap AddQtData::addQt(const QVariantMap &map) const const QString qt = QString::fromLatin1(PREFIX) + QString::number(versionCount); // Sanitize qmake path: - FilePath saneQmake = FilePath::fromUserInput(m_qmake).cleanPath(); + QString saneQmake = QDir::cleanPath(m_qmake); // insert data: KeyValuePairList data; @@ -291,7 +287,7 @@ QVariantMap AddQtData::addQt(const QVariantMap &map) const data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTED), QVariant(true)); data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTION_SOURCE), QVariant(sdkId)); - data << KeyValuePair(QStringList() << qt << QLatin1String(QMAKE), saneQmake.toSettings()); + data << KeyValuePair(QStringList() << qt << QLatin1String(QMAKE), QVariant(saneQmake)); data << KeyValuePair(QStringList() << qt << QLatin1String(TYPE), QVariant(m_type)); data << KeyValuePair(QStringList() << qt << ABIS, QVariant(m_abis)); diff --git a/src/tools/sdktool/addtoolchainoperation.cpp b/src/tools/sdktool/addtoolchainoperation.cpp index 1290711e566..74f4965cf87 100644 --- a/src/tools/sdktool/addtoolchainoperation.cpp +++ b/src/tools/sdktool/addtoolchainoperation.cpp @@ -4,13 +4,10 @@ #include "addtoolchainoperation.h" #include "addkeysoperation.h" -#include "findkeyoperation.h" #include "findvalueoperation.h" #include "getoperation.h" #include "rmkeysoperation.h" -#include "settings.h" - #include #ifdef WITH_TESTS @@ -283,7 +280,7 @@ QVariantMap AddToolChainData::addToolChain(const QVariantMap &map) const data << KeyValuePair({tc, LANGUAGE_KEY_V2}, QVariant(newLang)); data << KeyValuePair({tc, DISPLAYNAME}, QVariant(m_displayName)); data << KeyValuePair({tc, AUTODETECTED}, QVariant(true)); - data << KeyValuePair({tc, PATH}, Utils::FilePath::fromUserInput(m_path).toSettings()); + data << KeyValuePair({tc, PATH}, QVariant(m_path)); data << KeyValuePair({tc, TARGET_ABI}, QVariant(m_targetAbi)); QVariantList abis; const QStringList abiStrings = m_supportedAbis.split(','); diff --git a/src/tools/sdktool/main.cpp b/src/tools/sdktool/main.cpp index 4f28b64b9e5..f53cd306a1c 100644 --- a/src/tools/sdktool/main.cpp +++ b/src/tools/sdktool/main.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -60,10 +61,7 @@ void printHelp(const std::vector> &operations) std::cout << " --sdkpath=PATH|-s PATH Set the path to the SDK files" << std::endl << std::endl; std::cout << "Default sdkpath is \"" - << qPrintable(QDir::cleanPath( - Utils::FilePath::fromString(QCoreApplication::applicationDirPath()) - .pathAppended(DATA_PATH) - .toUserOutput())) + << qPrintable(QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + DATA_PATH)) << "\"" << std::endl << std::endl; @@ -105,7 +103,7 @@ int parseArguments(const QStringList &args, Settings *s, // sdkpath if (current.startsWith(QLatin1String("--sdkpath="))) { - s->sdkPath = Utils::FilePath::fromString(current.mid(10)); + s->sdkPath = current.mid(10); continue; } if (current == QLatin1String("-s")) { @@ -114,7 +112,7 @@ int parseArguments(const QStringList &args, Settings *s, printHelp(operations); return 1; } - s->sdkPath = Utils::FilePath::fromString(next); + s->sdkPath = next; ++i; // skip next; continue; } diff --git a/src/tools/sdktool/operation.cpp b/src/tools/sdktool/operation.cpp index ed673b9b780..7a81c3c7adf 100644 --- a/src/tools/sdktool/operation.cpp +++ b/src/tools/sdktool/operation.cpp @@ -4,8 +4,7 @@ #include "operation.h" #include "settings.h" - -#include +#include "sdkpersistentsettings.h" #include #include @@ -65,9 +64,9 @@ QVariantMap Operation::load(const QString &file) QVariantMap map; // Read values from original file: - Utils::FilePath path = Settings::instance()->getPath(file); - if (path.exists()) { - Utils::PersistentSettingsReader reader; + QString path = Settings::instance()->getPath(file); + if (QFileInfo::exists(path)) { + SdkPersistentSettingsReader reader; if (!reader.load(path)) return QVariantMap(); map = reader.restoreValues(); @@ -78,32 +77,32 @@ QVariantMap Operation::load(const QString &file) bool Operation::save(const QVariantMap &map, const QString &file) const { - Utils::FilePath path = Settings::instance()->getPath(file); + QString path = Settings::instance()->getPath(file); if (path.isEmpty()) { std::cerr << "Error: No path found for " << qPrintable(file) << "." << std::endl; return false; } - Utils::FilePath dirName = path.parentDir(); - QDir dir(dirName.toString()); + QString dirName = QDir::cleanPath(path + "/.."); + QDir dir(dirName); if (!dir.exists() && !dir.mkpath(QLatin1String("."))) { - std::cerr << "Error: Could not create directory " << qPrintable(dirName.toString()) + std::cerr << "Error: Could not create directory " << qPrintable(dirName) << "." << std::endl; return false; } - Utils::PersistentSettingsWriter writer(path, QLatin1String("QtCreator") + SdkPersistentSettingsWriter writer(path, QLatin1String("QtCreator") + file[0].toUpper() + file.mid(1)); QString errorMessage; if (!writer.save(map, &errorMessage)) { - std::cerr << "Error: Could not save settings " << qPrintable(path.toString()) + std::cerr << "Error: Could not save settings " << qPrintable(path) << "." << std::endl; return false; } - if (!path.setPermissions(QFile::ReadOwner | QFile::WriteOwner + if (!QFile(path).setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther)) { - std::cerr << "Error: Could not set permissions for " << qPrintable(path.toString()) + std::cerr << "Error: Could not set permissions for " << qPrintable(path) << "." << std::endl; return false; } diff --git a/src/tools/sdktool/operation.h b/src/tools/sdktool/operation.h index 1b43eb7b441..886ed386675 100644 --- a/src/tools/sdktool/operation.h +++ b/src/tools/sdktool/operation.h @@ -3,8 +3,6 @@ #pragma once -#include - #include #include diff --git a/src/tools/sdktool/sdkpersistentsettings.cpp b/src/tools/sdktool/sdkpersistentsettings.cpp new file mode 100644 index 00000000000..db5ba21a34d --- /dev/null +++ b/src/tools/sdktool/sdkpersistentsettings.cpp @@ -0,0 +1,870 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "sdkpersistentsettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +# include +# include +#else +# include +# include +#endif + + +#define QTC_ASSERT_STRINGIFY_HELPER(x) #x +#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x) +#define QTC_ASSERT_STRING(cond) writeAssertLocation(\ + "\"" cond"\" in " __FILE__ ":" QTC_ASSERT_STRINGIFY(__LINE__)) + +// The 'do {...} while (0)' idiom is not used for the main block here to be +// able to use 'break' and 'continue' as 'actions'. + +#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0) +#define QTC_CHECK(cond) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); } do {} while (0) +#define QTC_GUARD(cond) ((Q_LIKELY(cond)) ? true : (QTC_ASSERT_STRING(#cond), false)) + +void writeAssertLocation(const char *msg) +{ + const QByteArray time = QTime::currentTime().toString(Qt::ISODateWithMs).toLatin1(); + static bool goBoom = qEnvironmentVariableIsSet("QTC_FATAL_ASSERTS"); + if (goBoom) + qFatal("SOFT ASSERT [%s] made fatal: %s", time.data(), msg); + else + qDebug("SOFT ASSERT [%s]: %s", time.data(), msg); +} + +static QFile::Permissions m_umask; + +class SdkSaveFile : public QFile +{ +public: + explicit SdkSaveFile(const QString &filePath) : m_finalFilePath(filePath) {} + ~SdkSaveFile() override; + + bool open(OpenMode flags = QIODevice::WriteOnly) override; + + void rollback(); + bool commit(); + + static void initializeUmask(); + +private: + const QString m_finalFilePath; + std::unique_ptr m_tempFile; + bool m_finalized = true; +}; + +SdkSaveFile::~SdkSaveFile() +{ + if (!m_finalized) + rollback(); +} + +bool SdkSaveFile::open(OpenMode flags) +{ + if (m_finalFilePath.isEmpty()) { + qWarning("Save file path empty"); + return false; + } + + QFile ofi(m_finalFilePath); + // Check whether the existing file is writable + if (ofi.exists() && !ofi.open(QIODevice::ReadWrite)) { + setErrorString(ofi.errorString()); + return false; + } + + m_tempFile = std::make_unique(m_finalFilePath); + m_tempFile->setAutoRemove(false); + if (!m_tempFile->open()) + return false; + setFileName(m_tempFile->fileName()); + + if (!QFile::open(flags)) + return false; + + m_finalized = false; // needs clean up in the end + if (ofi.exists()) { + setPermissions(ofi.permissions()); // Ignore errors + } else { + Permissions permAll = QFile::ReadOwner + | QFile::ReadGroup + | QFile::ReadOther + | QFile::WriteOwner + | QFile::WriteGroup + | QFile::WriteOther; + + // set permissions with respect to the current umask + setPermissions(permAll & ~m_umask); + } + + return true; +} + +void SdkSaveFile::rollback() +{ + close(); + if (m_tempFile) + m_tempFile->remove(); + m_finalized = true; +} + +static QString resolveSymlinks(QString current) +{ + int links = 16; + while (links--) { + const QFileInfo info(current); + if (!info.isSymLink()) + return {}; + current = info.symLinkTarget(); + } + return current; +} + +bool SdkSaveFile::commit() +{ + QTC_ASSERT(!m_finalized && m_tempFile, return false;); + m_finalized = true; + + if (!flush()) { + close(); + m_tempFile->remove(); + return false; + } +#ifdef Q_OS_WIN + FlushFileBuffers(reinterpret_cast(_get_osfhandle(handle()))); +#elif _POSIX_SYNCHRONIZED_IO > 0 + fdatasync(handle()); +#else + fsync(handle()); +#endif + close(); + m_tempFile->close(); + if (error() != NoError) { + m_tempFile->remove(); + return false; + } + + QString finalFileName = resolveSymlinks(m_finalFilePath); + +#ifdef Q_OS_WIN + // Release the file lock + m_tempFile.reset(); + bool result = ReplaceFile(finalFileName.toStdWString().data(), + fileName().toStdWString().data(), + nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr); + if (!result) { + DWORD replaceErrorCode = GetLastError(); + QString errorStr; + if (!QFile::exists(finalFileName)) { + // Replace failed because finalFileName does not exist, try rename. + if (!(result = rename(finalFileName))) + errorStr = errorString(); + } else { + if (replaceErrorCode == ERROR_UNABLE_TO_REMOVE_REPLACED) { + // If we do not get the rights to remove the original final file we still might try + // to replace the file contents + result = MoveFileEx(fileName().toStdWString().data(), + finalFileName.toStdWString().data(), + MOVEFILE_COPY_ALLOWED + | MOVEFILE_REPLACE_EXISTING + | MOVEFILE_WRITE_THROUGH); + if (!result) + replaceErrorCode = GetLastError(); + } + if (!result) { + wchar_t messageBuffer[256]; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, replaceErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + messageBuffer, sizeof(messageBuffer), nullptr); + errorStr = QString::fromWCharArray(messageBuffer); + } + } + if (!result) { + remove(); + setErrorString(errorStr); + } + } + + return result; +#else + const QString backupName = finalFileName + '~'; + + // Back up current file. + // If it's opened by another application, the lock follows the move. + if (QFile::exists(finalFileName)) { + // Kill old backup. Might be useful if creator crashed before removing backup. + QFile::remove(backupName); + QFile finalFile(finalFileName); + if (!finalFile.rename(backupName)) { + m_tempFile->remove(); + setErrorString(finalFile.errorString()); + return false; + } + } + + bool result = true; + if (!m_tempFile->rename(finalFileName)) { + // The case when someone else was able to create finalFileName after we've renamed it. + // Higher level call may try to save this file again but here we do nothing and + // return false while keeping the error string from last rename call. + const QString &renameError = m_tempFile->errorString(); + m_tempFile->remove(); + setErrorString(renameError); + QFile::rename(backupName, finalFileName); // rollback to backup if possible ... + return false; // ... or keep the backup copy at least + } + + QFile::remove(backupName); + + return result; +#endif +} + +void SdkSaveFile::initializeUmask() +{ +#ifdef Q_OS_WIN + m_umask = QFile::WriteGroup | QFile::WriteOther; +#else + // Get the current process' file creation mask (umask) + // umask() is not thread safe so this has to be done by single threaded + // application initialization + mode_t mask = umask(0); // get current umask + umask(mask); // set it back + + m_umask = ((mask & S_IRUSR) ? QFile::ReadOwner : QFlags()) + | ((mask & S_IWUSR) ? QFile::WriteOwner : QFlags()) + | ((mask & S_IXUSR) ? QFile::ExeOwner : QFlags()) + | ((mask & S_IRGRP) ? QFile::ReadGroup : QFlags()) + | ((mask & S_IWGRP) ? QFile::WriteGroup : QFlags()) + | ((mask & S_IXGRP) ? QFile::ExeGroup : QFlags()) + | ((mask & S_IROTH) ? QFile::ReadOther : QFlags()) + | ((mask & S_IWOTH) ? QFile::WriteOther : QFlags()) + | ((mask & S_IXOTH) ? QFile::ExeOther : QFlags()); +#endif +} + +class SdkFileSaverBase +{ +public: + SdkFileSaverBase() = default; + virtual ~SdkFileSaverBase() = default; + + QString filePath() const { return m_filePath; } + bool hasError() const { return m_hasError; } + QString errorString() const { return m_errorString; } + virtual bool finalize(); + bool finalize(QString *errStr); + + bool write(const char *data, int len); + bool write(const QByteArray &bytes); + bool setResult(QTextStream *stream); + bool setResult(QDataStream *stream); + bool setResult(QXmlStreamWriter *stream); + bool setResult(bool ok); + + QFile *file() { return m_file.get(); } + +protected: + std::unique_ptr m_file; + QString m_filePath; + QString m_errorString; + bool m_hasError = false; +}; + +bool SdkFileSaverBase::finalize() +{ + m_file->close(); + setResult(m_file->error() == QFile::NoError); + m_file.reset(); + return !m_hasError; +} + +bool SdkFileSaverBase::finalize(QString *errStr) +{ + if (finalize()) + return true; + if (errStr) + *errStr = errorString(); + return false; +} + +bool SdkFileSaverBase::write(const char *data, int len) +{ + if (m_hasError) + return false; + return setResult(m_file->write(data, len) == len); +} + +bool SdkFileSaverBase::write(const QByteArray &bytes) +{ + if (m_hasError) + return false; + return setResult(m_file->write(bytes) == bytes.count()); +} + +bool SdkFileSaverBase::setResult(bool ok) +{ + if (!ok && !m_hasError) { + if (!m_file->errorString().isEmpty()) { + m_errorString = QString("Cannot write file %1: %2") + .arg(m_filePath, m_file->errorString()); + } else { + m_errorString = QString("Cannot write file %1. Disk full?") + .arg(m_filePath); + } + m_hasError = true; + } + return ok; +} + +bool SdkFileSaverBase::setResult(QTextStream *stream) +{ + stream->flush(); + return setResult(stream->status() == QTextStream::Ok); +} + +bool SdkFileSaverBase::setResult(QDataStream *stream) +{ + return setResult(stream->status() == QDataStream::Ok); +} + +bool SdkFileSaverBase::setResult(QXmlStreamWriter *stream) +{ + return setResult(!stream->hasError()); +} + +// SdkFileSaver + +class SdkFileSaver : public SdkFileSaverBase +{ +public: + // QIODevice::WriteOnly is implicit + explicit SdkFileSaver(const QString &filePath, QIODevice::OpenMode mode = QIODevice::NotOpen); + + bool finalize() override; + +private: + bool m_isSafe = false; +}; + +SdkFileSaver::SdkFileSaver(const QString &filePath, QIODevice::OpenMode mode) +{ + m_filePath = filePath; + // Workaround an assert in Qt -- and provide a useful error message, too: +#if Q_OS_WIN + // Taken from: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx + static const QStringList reservedNames + = {"CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}; + const QString fn = QFileInfo(filePath).baseName().toUpper(); + if (reservedNames.contains(fn)) { + m_errorString = QString("%1: Is a reserved filename on Windows. Cannot save.").arg(filePath); + m_hasError = true; + return; + } +#endif + + if (mode & (QIODevice::ReadOnly | QIODevice::Append)) { + m_file.reset(new QFile{filePath}); + m_isSafe = false; + } else { + m_file.reset(new SdkSaveFile(filePath)); + m_isSafe = true; + } + if (!m_file->open(QIODevice::WriteOnly | mode)) { + QString err = QFileInfo::exists(filePath) ? + QString("Cannot overwrite file %1: %2") : QString("Cannot create file %1: %2"); + m_errorString = err.arg(filePath, m_file->errorString()); + m_hasError = true; + } +} + +bool SdkFileSaver::finalize() +{ + if (!m_isSafe) + return SdkFileSaverBase::finalize(); + + auto sf = static_cast(m_file.get()); + if (m_hasError) { + if (sf->isOpen()) + sf->rollback(); + } else { + setResult(sf->commit()); + } + m_file.reset(); + return !m_hasError; +} + + +// Read and write rectangle in X11 resource syntax "12x12+4+3" +static QString rectangleToString(const QRect &r) +{ + QString result; + QTextStream str(&result); + str << r.width() << 'x' << r.height(); + if (r.x() >= 0) + str << '+'; + str << r.x(); + if (r.y() >= 0) + str << '+'; + str << r.y(); + return result; +} + +static QRect stringToRectangle(const QString &v) +{ + static QRegularExpression pattern("^(\\d+)x(\\d+)([-+]\\d+)([-+]\\d+)$"); + Q_ASSERT(pattern.isValid()); + const QRegularExpressionMatch match = pattern.match(v); + return match.hasMatch() ? + QRect(QPoint(match.captured(3).toInt(), match.captured(4).toInt()), + QSize(match.captured(1).toInt(), match.captured(2).toInt())) : + QRect(); +} + +/*! + \class SdkPersistentSettingsReader + + \note This is aQString based fork of Utils::PersistentSettigsReader + + \brief The SdkPersistentSettingsReader class reads a QVariantMap of arbitrary, + nested data structures from an XML file. + + Handles all string-serializable simple types and QVariantList and QVariantMap. Example: + \code + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + + + \endcode + + When parsing the structure, a parse stack of ParseValueStackEntry is used for each + element. ParseValueStackEntry is a variant/union of: + \list + \li simple value + \li map + \li list + \endlist + + You can register string-serialize functions for custom types by registering them in the Qt Meta + type system. Example: + \code + QMetaType::registerConverter(&MyCustomType::toString); + QMetaType::registerConverter(&myCustomTypeFromString); + \endcode + + When entering a value element ( \c / \c , \c ), entry is pushed + accordingly. When leaving the element, the QVariant-value of the entry is taken off the stack + and added to the stack entry below (added to list or inserted into map). The first element + of the stack is the value of the element. + + \sa SdkPersistentSettingsWriter +*/ + +struct Context // Basic context containing element name string constants. +{ + Context() {} + const QString qtCreatorElement = QString("qtcreator"); + const QString dataElement = QString("data"); + const QString variableElement = QString("variable"); + const QString typeAttribute = QString("type"); + const QString valueElement = QString("value"); + const QString valueListElement = QString("valuelist"); + const QString valueMapElement = QString("valuemap"); + const QString keyAttribute = QString("key"); +}; + +struct ParseValueStackEntry +{ + explicit ParseValueStackEntry(QVariant::Type t = QVariant::Invalid, const QString &k = QString()) : type(t), key(k) {} + explicit ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k); + + QVariant value() const; + void addChild(const QString &key, const QVariant &v); + + QVariant::Type type; + QString key; + QVariant simpleValue; + QVariantList listValue; + QVariantMap mapValue; +}; + +ParseValueStackEntry::ParseValueStackEntry(const QVariant &aSimpleValue, const QString &k) : + type(aSimpleValue.type()), key(k), simpleValue(aSimpleValue) +{ + QTC_ASSERT(simpleValue.isValid(), return); +} + +QVariant ParseValueStackEntry::value() const +{ + switch (type) { + case QVariant::Invalid: + return QVariant(); + case QVariant::Map: + return QVariant(mapValue); + case QVariant::List: + return QVariant(listValue); + default: + break; + } + return simpleValue; +} + +void ParseValueStackEntry::addChild(const QString &key, const QVariant &v) +{ + switch (type) { + case QVariant::Map: + mapValue.insert(key, v); + break; + case QVariant::List: + listValue.push_back(v); + break; + default: + qWarning() << "ParseValueStackEntry::Internal error adding " << key << v << " to " + << QVariant::typeToName(type) << value(); + break; + } +} + +class ParseContext : public Context +{ +public: + QVariantMap parse(const QString &file); + +private: + enum Element { QtCreatorElement, DataElement, VariableElement, + SimpleValueElement, ListValueElement, MapValueElement, UnknownElement }; + + Element element(const QStringView &r) const; + static inline bool isValueElement(Element e) + { return e == SimpleValueElement || e == ListValueElement || e == MapValueElement; } + QVariant readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const; + + bool handleStartElement(QXmlStreamReader &r); + bool handleEndElement(const QStringView &name); + + static QString formatWarning(const QXmlStreamReader &r, const QString &message); + + QStack m_valueStack; + QVariantMap m_result; + QString m_currentVariableName; +}; + +static QByteArray fileContents(const QString &path) +{ + QFile f(path); + if (!f.exists()) + return {}; + + if (!f.open(QFile::ReadOnly)) + return {}; + + return f.readAll(); +} + +QVariantMap ParseContext::parse(const QString &file) +{ + QXmlStreamReader r(fileContents(file)); + + m_result.clear(); + m_currentVariableName.clear(); + + while (!r.atEnd()) { + switch (r.readNext()) { + case QXmlStreamReader::StartElement: + if (handleStartElement(r)) + return m_result; + break; + case QXmlStreamReader::EndElement: + if (handleEndElement(r.name())) + return m_result; + break; + case QXmlStreamReader::Invalid: + qWarning("Error reading %s:%d: %s", qPrintable(file), + int(r.lineNumber()), qPrintable(r.errorString())); + return QVariantMap(); + default: + break; + } // switch token + } // while (!r.atEnd()) + return m_result; +} + +bool ParseContext::handleStartElement(QXmlStreamReader &r) +{ + const QStringView name = r.name(); + const Element e = element(name); + if (e == VariableElement) { + m_currentVariableName = r.readElementText(); + return false; + } + if (!ParseContext::isValueElement(e)) + return false; + + const QXmlStreamAttributes attributes = r.attributes(); + const QString key = attributes.hasAttribute(keyAttribute) ? + attributes.value(keyAttribute).toString() : QString(); + switch (e) { + case SimpleValueElement: { + // This reads away the end element, so, handle end element right here. + const QVariant v = readSimpleValue(r, attributes); + if (!v.isValid()) { + qWarning() << ParseContext::formatWarning(r, QString::fromLatin1("Failed to read element \"%1\".").arg(name.toString())); + return false; + } + m_valueStack.push_back(ParseValueStackEntry(v, key)); + return handleEndElement(name); + } + case ListValueElement: + m_valueStack.push_back(ParseValueStackEntry(QVariant::List, key)); + break; + case MapValueElement: + m_valueStack.push_back(ParseValueStackEntry(QVariant::Map, key)); + break; + default: + break; + } + return false; +} + +bool ParseContext::handleEndElement(const QStringView &name) +{ + const Element e = element(name); + if (ParseContext::isValueElement(e)) { + QTC_ASSERT(!m_valueStack.isEmpty(), return true); + const ParseValueStackEntry top = m_valueStack.pop(); + if (m_valueStack.isEmpty()) { // Last element? -> Done with that variable. + QTC_ASSERT(!m_currentVariableName.isEmpty(), return true); + m_result.insert(m_currentVariableName, top.value()); + m_currentVariableName.clear(); + return false; + } + m_valueStack.top().addChild(top.key, top.value()); + } + return e == QtCreatorElement; +} + +QString ParseContext::formatWarning(const QXmlStreamReader &r, const QString &message) +{ + QString result = QLatin1String("Warning reading "); + if (const QIODevice *device = r.device()) + if (const auto file = qobject_cast(device)) + result += QDir::toNativeSeparators(file->fileName()) + QLatin1Char(':'); + result += QString::number(r.lineNumber()); + result += QLatin1String(": "); + result += message; + return result; +} + +ParseContext::Element ParseContext::element(const QStringView &r) const +{ + if (r == valueElement) + return SimpleValueElement; + if (r == valueListElement) + return ListValueElement; + if (r == valueMapElement) + return MapValueElement; + if (r == qtCreatorElement) + return QtCreatorElement; + if (r == dataElement) + return DataElement; + if (r == variableElement) + return VariableElement; + return UnknownElement; +} + +QVariant ParseContext::readSimpleValue(QXmlStreamReader &r, const QXmlStreamAttributes &attributes) const +{ + // Simple value + const QStringView type = attributes.value(typeAttribute); + const QString text = r.readElementText(); + if (type == QLatin1String("QChar")) { // Workaround: QTBUG-12345 + QTC_ASSERT(text.size() == 1, return QVariant()); + return QVariant(QChar(text.at(0))); + } + if (type == QLatin1String("QRect")) { + const QRect rectangle = stringToRectangle(text); + return rectangle.isValid() ? QVariant(rectangle) : QVariant(); + } + QVariant value; + value.setValue(text); + value.convert(QMetaType::type(type.toLatin1().constData())); + return value; +} + +// =================================== SdkPersistentSettingsReader + +SdkPersistentSettingsReader::SdkPersistentSettingsReader() = default; + +QVariant SdkPersistentSettingsReader::restoreValue(const QString &variable, const QVariant &defaultValue) const +{ + if (m_valueMap.contains(variable)) + return m_valueMap.value(variable); + return defaultValue; +} + +QVariantMap SdkPersistentSettingsReader::restoreValues() const +{ + return m_valueMap; +} + +bool SdkPersistentSettingsReader::load(const QString &fileName) +{ + m_valueMap.clear(); + + if (QFileInfo(fileName).size() == 0) // skip empty files + return false; + + ParseContext ctx; + m_valueMap = ctx.parse(fileName); + return true; +} + +/*! + \class SdkPersistentSettingsWriter + + \note This is a fork of Utils::PersistentSettingsWriter + + \brief The SdkPersistentSettingsWriter class serializes a QVariantMap of + arbitrary, nested data structures to an XML file. + \sa SdkPersistentSettingsReader +*/ + +static void writeVariantValue(QXmlStreamWriter &w, const Context &ctx, + const QVariant &variant, const QString &key = QString()) +{ + switch (static_cast(variant.type())) { + case static_cast(QVariant::StringList): + case static_cast(QVariant::List): { + w.writeStartElement(ctx.valueListElement); + w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::List))); + if (!key.isEmpty()) + w.writeAttribute(ctx.keyAttribute, key); + const QList list = variant.toList(); + for (const QVariant &var : list) + writeVariantValue(w, ctx, var); + w.writeEndElement(); + break; + } + case static_cast(QVariant::Map): { + w.writeStartElement(ctx.valueMapElement); + w.writeAttribute(ctx.typeAttribute, QLatin1String(QVariant::typeToName(QVariant::Map))); + if (!key.isEmpty()) + w.writeAttribute(ctx.keyAttribute, key); + const QVariantMap varMap = variant.toMap(); + const QVariantMap::const_iterator cend = varMap.constEnd(); + for (QVariantMap::const_iterator i = varMap.constBegin(); i != cend; ++i) + writeVariantValue(w, ctx, i.value(), i.key()); + w.writeEndElement(); + } + break; + case static_cast(QMetaType::QObjectStar): // ignore QObjects! + case static_cast(QMetaType::VoidStar): // ignore void pointers! + break; + default: + w.writeStartElement(ctx.valueElement); + w.writeAttribute(ctx.typeAttribute, QLatin1String(variant.typeName())); + if (!key.isEmpty()) + w.writeAttribute(ctx.keyAttribute, key); + switch (variant.type()) { + case QVariant::Rect: + w.writeCharacters(rectangleToString(variant.toRect())); + break; + default: + w.writeCharacters(variant.toString()); + break; + } + w.writeEndElement(); + break; + } +} + +SdkPersistentSettingsWriter::SdkPersistentSettingsWriter(const QString &fileName, const QString &docType) : + m_fileName(fileName), m_docType(docType) +{ } + +bool SdkPersistentSettingsWriter::save(const QVariantMap &data, QString *errorString) const +{ + if (data == m_savedData) + return true; + return write(data, errorString); +} + +QString SdkPersistentSettingsWriter::fileName() const +{ return m_fileName; } + +//** * @brief Set contents of file (e.g. from data read from it). */ +void SdkPersistentSettingsWriter::setContents(const QVariantMap &data) +{ + m_savedData = data; +} + +bool SdkPersistentSettingsWriter::write(const QVariantMap &data, QString *errorString) const +{ + const QString parentDir = QDir::cleanPath(m_fileName + "/.."); + + const QFileInfo fi(parentDir); + if (!(fi.exists() && fi.isDir() && fi.isWritable())) { + bool res = QDir().mkpath(parentDir); + if (!res) + return false; + } + + SdkFileSaver saver(m_fileName, QIODevice::Text); + if (!saver.hasError()) { + const Context ctx; + QXmlStreamWriter w(saver.file()); + w.setAutoFormatting(true); + w.setAutoFormattingIndent(1); // Historical, used to be QDom. + w.writeStartDocument(); + w.writeDTD(QLatin1String("')); + w.writeComment(QString::fromLatin1(" Written by %1 %2, %3. "). + arg(QCoreApplication::applicationName(), + QCoreApplication::applicationVersion(), + QDateTime::currentDateTime().toString(Qt::ISODate))); + w.writeStartElement(ctx.qtCreatorElement); + const QVariantMap::const_iterator cend = data.constEnd(); + for (QVariantMap::const_iterator it = data.constBegin(); it != cend; ++it) { + w.writeStartElement(ctx.dataElement); + w.writeTextElement(ctx.variableElement, it.key()); + writeVariantValue(w, ctx, it.value()); + w.writeEndElement(); + } + w.writeEndDocument(); + + saver.setResult(&w); + } + bool ok = saver.finalize(); + if (ok) { + m_savedData = data; + } else if (errorString) { + m_savedData.clear(); + *errorString = saver.errorString(); + } + + return ok; +} diff --git a/src/tools/sdktool/sdkpersistentsettings.h b/src/tools/sdktool/sdkpersistentsettings.h new file mode 100644 index 00000000000..691cf0e08a7 --- /dev/null +++ b/src/tools/sdktool/sdkpersistentsettings.h @@ -0,0 +1,37 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +class SdkPersistentSettingsReader +{ +public: + SdkPersistentSettingsReader(); + QVariant restoreValue(const QString &variable, const QVariant &defaultValue = QVariant()) const; + QVariantMap restoreValues() const; + bool load(const QString &fileName); + +private: + QMap m_valueMap; +}; + +class SdkPersistentSettingsWriter +{ +public: + SdkPersistentSettingsWriter(const QString &fileName, const QString &docType); + + bool save(const QVariantMap &data, QString *errorString) const; + + QString fileName() const; + + void setContents(const QVariantMap &data); + +private: + bool write(const QVariantMap &data, QString *errorString) const; + + const QString m_fileName; + const QString m_docType; + mutable QMap m_savedData; +}; diff --git a/src/tools/sdktool/sdktoollib.qbs b/src/tools/sdktool/sdktoollib.qbs index 60823390832..ca40590d8d1 100644 --- a/src/tools/sdktool/sdktoollib.qbs +++ b/src/tools/sdktool/sdktoollib.qbs @@ -85,34 +85,7 @@ QtcLibrary { "rmtoolchainoperation.h", "settings.cpp", "settings.h", + "sdkpersistentsettings.cpp", + "sdkpersistentsettings.h", ] - - Group { - name: "Utils" - prefix: libsDir + "/utils/" - files: [ - "commandline.cpp", "commandline.h", - "devicefileaccess.cpp", "devicefileaccess.h", - "environment.cpp", "environment.h", - "filepath.cpp", "filepath.h", - "fileutils.cpp", "fileutils.h", - "hostosinfo.cpp", "hostosinfo.h", - "macroexpander.cpp", "macroexpander.h", - "namevaluedictionary.cpp", "namevaluedictionary.h", - "namevalueitem.cpp", "namevalueitem.h", - "persistentsettings.cpp", "persistentsettings.h", - "qtcassert.cpp", "qtcassert.h", - "savefile.cpp", "savefile.h", - "stringutils.cpp" - ] - } - Group { - name: "Utils/macOS" - condition: qbs.targetOS.contains("macos") - prefix: libsDir + "/utils/" - files: [ - "fileutils_mac.h", - "fileutils_mac.mm", - ] - } } diff --git a/src/tools/sdktool/settings.cpp b/src/tools/sdktool/settings.cpp index d87df504f6e..53a1af0565f 100644 --- a/src/tools/sdktool/settings.cpp +++ b/src/tools/sdktool/settings.cpp @@ -2,11 +2,11 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "settings.h" -#include "operation.h" #include #include +#include static Settings *m_instance = nullptr; @@ -21,28 +21,28 @@ Settings::Settings() m_instance = this; // autodetect sdk dir: - sdkPath = Utils::FilePath::fromUserInput(QCoreApplication::applicationDirPath()) - .pathAppended(DATA_PATH).cleanPath() - .pathAppended(Core::Constants::IDE_SETTINGSVARIANT_STR) - .pathAppended(Core::Constants::IDE_ID); + sdkPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + + '/' + DATA_PATH + + '/' + Core::Constants::IDE_SETTINGSVARIANT_STR + + '/' + Core::Constants::IDE_ID); } -Utils::FilePath Settings::getPath(const QString &file) +QString Settings::getPath(const QString &file) { - Utils::FilePath result = sdkPath; + QString result = sdkPath; const QString lowerFile = file.toLower(); const QStringList identical = { "android", "cmaketools", "debuggers", "devices", "profiles", "qtversions", "toolchains", "abi" }; if (lowerFile == "cmake") - result = result.pathAppended("cmaketools"); + result += "/cmaketools"; else if (lowerFile == "kits") - result = result.pathAppended("profiles"); + result += "/profiles"; else if (lowerFile == "qtversions") - result = result.pathAppended("qtversion"); + result += "/qtversion"; else if (identical.contains(lowerFile)) - result = result.pathAppended(lowerFile); + result += '/' + lowerFile; else - result = result.pathAppended(file); // handle arbitrary file names not known yet - return result.stringAppended(".xml"); + result += '/' + file; // handle arbitrary file names not known yet + return result += ".xml"; } diff --git a/src/tools/sdktool/settings.h b/src/tools/sdktool/settings.h index b94c2c9ad0c..3b182e1c96f 100644 --- a/src/tools/sdktool/settings.h +++ b/src/tools/sdktool/settings.h @@ -3,7 +3,7 @@ #pragma once -#include +#include class Operation; @@ -13,8 +13,8 @@ public: Settings(); static Settings *instance(); - Utils::FilePath getPath(const QString &file); + QString getPath(const QString &file); - Utils::FilePath sdkPath; + QString sdkPath; Operation *operation = nullptr; }; From 098c76832afb098c844b77101bc1613c4e4b6ef4 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 3 Mar 2023 17:18:56 +0100 Subject: [PATCH 0173/1447] Terminal: Rewrite rendering The rendering has been rewritten to use cached GlyphRuns instead of text layouts. The VTerm specific code was moved into TerminalSurface. Change-Id: I10caa3db4ee932414987c9ddae2dcb777dc1f6e7 Reviewed-by: Cristian Adam Reviewed-by: --- src/libs/3rdparty/libvterm/include/vterm.h | 4 +- src/libs/3rdparty/libvterm/src/pen.c | 6 + src/libs/3rdparty/libvterm/src/screen.c | 2 +- .../3rdparty/libvterm/src/vterm_internal.h | 2 +- src/plugins/terminal/CMakeLists.txt | 16 +- src/plugins/terminal/celliterator.cpp | 89 ++ src/plugins/terminal/celliterator.h | 95 ++ src/plugins/terminal/celllayout.cpp | 146 --- src/plugins/terminal/celllayout.h | 29 - src/plugins/terminal/glyphcache.cpp | 44 + src/plugins/terminal/glyphcache.h | 34 + src/plugins/terminal/scrollback.cpp | 55 - src/plugins/terminal/scrollback.h | 17 +- src/plugins/terminal/terminalsurface.cpp | 504 ++++++++ src/plugins/terminal/terminalsurface.h | 103 ++ src/plugins/terminal/terminalwidget.cpp | 1042 +++++++++-------- src/plugins/terminal/terminalwidget.h | 92 +- src/plugins/terminal/tests/colors | 112 ++ 18 files changed, 1592 insertions(+), 800 deletions(-) create mode 100644 src/plugins/terminal/celliterator.cpp create mode 100644 src/plugins/terminal/celliterator.h delete mode 100644 src/plugins/terminal/celllayout.cpp delete mode 100644 src/plugins/terminal/celllayout.h create mode 100644 src/plugins/terminal/glyphcache.cpp create mode 100644 src/plugins/terminal/glyphcache.h create mode 100644 src/plugins/terminal/terminalsurface.cpp create mode 100644 src/plugins/terminal/terminalsurface.h create mode 100755 src/plugins/terminal/tests/colors diff --git a/src/libs/3rdparty/libvterm/include/vterm.h b/src/libs/3rdparty/libvterm/include/vterm.h index c0f008776ba..cb16ff2a044 100644 --- a/src/libs/3rdparty/libvterm/include/vterm.h +++ b/src/libs/3rdparty/libvterm/include/vterm.h @@ -496,7 +496,7 @@ void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTer typedef struct { unsigned int bold : 1; - unsigned int underline : 2; + unsigned int underline : 3; unsigned int italic : 1; unsigned int blink : 1; unsigned int reverse : 1; @@ -514,6 +514,8 @@ enum { VTERM_UNDERLINE_SINGLE, VTERM_UNDERLINE_DOUBLE, VTERM_UNDERLINE_CURLY, + VTERM_UNDERLINE_DOTTED, + VTERM_UNDERLINE_DASHED }; enum { diff --git a/src/libs/3rdparty/libvterm/src/pen.c b/src/libs/3rdparty/libvterm/src/pen.c index 2227a6fcd33..891a45cec78 100644 --- a/src/libs/3rdparty/libvterm/src/pen.c +++ b/src/libs/3rdparty/libvterm/src/pen.c @@ -323,6 +323,12 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco case 3: state->pen.underline = VTERM_UNDERLINE_CURLY; break; + case 4: + state->pen.underline = VTERM_UNDERLINE_DOTTED; + break; + case 5: + state->pen.underline = VTERM_UNDERLINE_DASHED; + break; } } setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); diff --git a/src/libs/3rdparty/libvterm/src/screen.c b/src/libs/3rdparty/libvterm/src/screen.c index 51c7f99e74a..9d1028e67ae 100644 --- a/src/libs/3rdparty/libvterm/src/screen.c +++ b/src/libs/3rdparty/libvterm/src/screen.c @@ -18,7 +18,7 @@ typedef struct VTermColor fg, bg; unsigned int bold : 1; - unsigned int underline : 2; + unsigned int underline : 3; unsigned int italic : 1; unsigned int blink : 1; unsigned int reverse : 1; diff --git a/src/libs/3rdparty/libvterm/src/vterm_internal.h b/src/libs/3rdparty/libvterm/src/vterm_internal.h index df9495c6786..ad61bff8b0f 100644 --- a/src/libs/3rdparty/libvterm/src/vterm_internal.h +++ b/src/libs/3rdparty/libvterm/src/vterm_internal.h @@ -41,7 +41,7 @@ struct VTermPen VTermColor fg; VTermColor bg; unsigned int bold:1; - unsigned int underline:2; + unsigned int underline:3; unsigned int italic:1; unsigned int blink:1; unsigned int reverse:1; diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index fafe3e7346e..e12e518bd88 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -3,16 +3,18 @@ add_qtc_plugin(Terminal PLUGIN_DEPENDS Core DEPENDS libvterm SOURCES - celllayout.cpp celllayout.h + celliterator.cpp celliterator.h + glyphcache.cpp glyphcache.h + keys.cpp keys.h + scrollback.cpp scrollback.h + shellmodel.cpp shellmodel.h terminal.qrc - terminalplugin.cpp terminalplugin.h - terminaltr.h terminalpane.cpp terminalpane.h - terminalwidget.cpp terminalwidget.h + terminalplugin.cpp terminalplugin.h terminalprocessinterface.cpp terminalprocessinterface.h terminalsettings.cpp terminalsettings.h terminalsettingspage.cpp terminalsettingspage.h - scrollback.h scrollback.cpp - shellmodel.cpp shellmodel.h - keys.cpp keys.h + terminalsurface.cpp terminalsurface.h + terminaltr.h + terminalwidget.cpp terminalwidget.h ) diff --git a/src/plugins/terminal/celliterator.cpp b/src/plugins/terminal/celliterator.cpp new file mode 100644 index 00000000000..76adbd5b4a3 --- /dev/null +++ b/src/plugins/terminal/celliterator.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "celliterator.h" + +#include "terminalsurface.h" + +#include + +namespace Terminal::Internal { + +CellIterator::CellIterator(const TerminalSurface *surface, QPoint pos) + : m_state(State::INSIDE) + , m_surface(surface) +{ + m_pos = (pos.x()) + (pos.y() * surface->liveSize().width()); + m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; + updateChar(); +} + +CellIterator::CellIterator(const TerminalSurface *surface, int pos) + : m_state(State::INSIDE) + , m_surface(surface) +{ + m_pos = pos; + m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; + updateChar(); +} + +CellIterator::CellIterator(const TerminalSurface *surface, State state) + : m_state(state) + , m_surface(surface) + , m_pos() +{ + m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; + if (state == State::END) { + m_pos = m_maxpos + 1; + } +} + +QPoint CellIterator::gridPos() const +{ + return m_surface->posToGrid(m_pos); +} + +void CellIterator::updateChar() +{ + QPoint cell = m_surface->posToGrid(m_pos); + m_char = m_surface->fetchCharAt(cell.x(), cell.y()); + if (m_char == 0) + m_char = U' '; +} + +CellIterator &CellIterator::operator-=(int n) +{ + if (n == 0) + return *this; + + if (m_pos - n < 0) + throw new std::runtime_error("-= n too big!"); + + m_pos -= n; + updateChar(); + + m_state = State::INSIDE; + + if (m_pos == 0) { + m_state = State::BEGIN; + } + + return *this; +} + +CellIterator &CellIterator::operator+=(int n) +{ + if (n == 0) + return *this; + + if (m_pos + n < m_maxpos) { + m_state = State::INSIDE; + m_pos += n; + updateChar(); + } else { + *this = m_surface->end(); + } + return *this; +} + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/celliterator.h b/src/plugins/terminal/celliterator.h new file mode 100644 index 00000000000..c420f4248a3 --- /dev/null +++ b/src/plugins/terminal/celliterator.h @@ -0,0 +1,95 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include + +namespace Terminal::Internal { + +class TerminalSurface; + +class CellIterator +{ +public: + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = std::u32string::value_type; + using pointer = std::u32string::value_type *; + // We need to return copies for std::reverse_iterator to work + using reference = std::u32string::value_type; + + enum class State { BEGIN, INSIDE, END } m_state{}; + +public: + CellIterator(const TerminalSurface *surface, QPoint pos); + CellIterator(const TerminalSurface *surface, int pos); + CellIterator(const TerminalSurface *surface, State state); + +public: + QPoint gridPos() const; + +public: + CellIterator &operator-=(int n); + CellIterator &operator+=(int n); + + reference operator*() const { return m_char; } + pointer operator->() { return &m_char; } + + CellIterator &operator++() { return *this += 1; } + CellIterator operator++(int) + { + CellIterator tmp = *this; + ++(*this); + return tmp; + } + + CellIterator &operator--() { return *this -= 1; } + CellIterator operator--(int) + { + CellIterator tmp = *this; + --(*this); + return tmp; + } + + bool operator!=(const CellIterator &other) const + { + if (other.m_state != m_state) + return true; + + if (other.m_pos != m_pos) + return true; + + return false; + } + + bool operator==(const CellIterator &other) const { return !operator!=(other); } + + CellIterator operator-(int n) const + { + CellIterator result = *this; + result -= n; + return result; + } + + CellIterator operator+(int n) const + { + CellIterator result = *this; + result += n; + return result; + } + + int position() const { return m_pos; } + +private: + void updateChar(); + + const TerminalSurface *m_surface{nullptr}; + int m_pos{-1}; + int m_maxpos{-1}; + mutable std::u32string::value_type m_char; +}; + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/celllayout.cpp b/src/plugins/terminal/celllayout.cpp deleted file mode 100644 index a2628eccb05..00000000000 --- a/src/plugins/terminal/celllayout.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#include "celllayout.h" - -#include - -namespace Terminal::Internal { - -QColor toQColor(const VTermColor &c) -{ - return QColor(qRgb(c.rgb.red, c.rgb.green, c.rgb.blue)); -}; - -std::u32string cellToString(const VTermScreenCell &cell) -{ - if (cell.chars[0] != 0xFFFFFFFF) { - QString ch = QString::fromUcs4(cell.chars); - if (ch.size() > 1) - ch = ch.normalized(QString::NormalizationForm_C); - QList asUcs4 = ch.toUcs4(); - - std::u32string chUcs = std::u32string(asUcs4.begin(), asUcs4.end()); - if (chUcs.size() > 0) { - if (chUcs[0] == 0) - chUcs[0] = 0x00a0; - - return chUcs; - } - } - return std::u32string(1, (char32_t) 0x00a0); -} - -void createTextLayout(QTextLayout &textLayout, - std::u32string *resultText, - VTermColor defaultBg, - QRect cellRect, - qreal lineSpacing, - std::function fetchCell) -{ - QList formats; - - QTextCharFormat currentFormat; - int currentFormatStart = 0; - currentFormat.setForeground(QColor(0xff, 0xff, 0xff)); - currentFormat.clearBackground(); - - QString layoutText; - if (resultText) - resultText->clear(); - - for (int y = cellRect.y(); y < cellRect.bottom() + 1; y++) { - QTextCharFormat format; - - const auto setNewFormat = [&formats, ¤tFormatStart, &layoutText, ¤tFormat]( - const QTextCharFormat &format) { - if (layoutText.size() != currentFormatStart) { - QTextLayout::FormatRange fr; - fr.start = currentFormatStart; - fr.length = layoutText.size() - currentFormatStart; - fr.format = currentFormat; - formats.append(fr); - - currentFormat = format; - currentFormatStart = layoutText.size(); - } else { - currentFormat = format; - } - }; - - for (int x = cellRect.x(); x < cellRect.right() + 1; x++) { - const VTermScreenCell *cell = fetchCell(x, y); - - const VTermColor *bg = &cell->bg; - const VTermColor *fg = &cell->fg; - - if (static_cast(cell->attrs.reverse)) { - bg = &cell->fg; - fg = &cell->bg; - } - - format = QTextCharFormat(); - format.setForeground(toQColor(*fg)); - - if (!vterm_color_is_equal(bg, &defaultBg)) - format.setBackground(toQColor(*bg)); - else - format.clearBackground(); - - if (cell->attrs.bold) - format.setFontWeight(QFont::Bold); - if (cell->attrs.underline) - format.setFontUnderline(true); - if (cell->attrs.italic) - format.setFontItalic(true); - if (cell->attrs.strike) - format.setFontStrikeOut(true); - - if (format != currentFormat) - setNewFormat(format); - - if (cell->chars[0] != 0xFFFFFFFF) { - QString ch = QString::fromUcs4(cell->chars); - if (ch == ' ') - ch = QChar::Nbsp; - if (ch.size() > 0) { - layoutText += ch; - } else { - layoutText += QChar::Nbsp; - } - } - - if (resultText) - *resultText += cellToString(*cell); - } // for x - setNewFormat(format); - if (y != cellRect.bottom()) - layoutText.append(QChar::LineSeparator); - } // for y - - QTextLayout::FormatRange fr; - fr.start = currentFormatStart; - fr.length = (layoutText.size() - 1) - currentFormatStart; - fr.format = currentFormat; - formats.append(fr); - - textLayout.setText(layoutText); - textLayout.setFormats(formats); - - qreal height = 0; - textLayout.beginLayout(); - while (1) { - QTextLine line = textLayout.createLine(); - if (!line.isValid()) - break; - - // Just give it a number that is definitely larger than - // the number of columns in a line. - line.setNumColumns(std::numeric_limits::max()); - line.setPosition(QPointF(0, height)); - height += lineSpacing; - } - textLayout.endLayout(); -} - -} // namespace Terminal::Internal diff --git a/src/plugins/terminal/celllayout.h b/src/plugins/terminal/celllayout.h deleted file mode 100644 index c86adef5fcc..00000000000 --- a/src/plugins/terminal/celllayout.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include -#include -#include -#include -#include - -#include - -namespace Terminal::Internal { - -QColor toQColor(const VTermColor &c); - -void createTextLayout(QTextLayout &textLayout, - std::u32string *resultText, - VTermColor defaultBg, - QRect cellRect, - qreal lineSpacing, - std::function fetchCell); - -std::u32string cellToString(const VTermScreenCell &cell); - -} // namespace Terminal::Internal diff --git a/src/plugins/terminal/glyphcache.cpp b/src/plugins/terminal/glyphcache.cpp new file mode 100644 index 00000000000..21c4b0d8090 --- /dev/null +++ b/src/plugins/terminal/glyphcache.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "glyphcache.h" + +#include + +namespace Terminal::Internal { + +size_t qHash(const GlyphCacheKey &key, size_t seed = 0) +{ + return qHash(key.font, seed) ^ qHash(key.text, seed); +} + +GlyphCache &GlyphCache::instance() +{ + static GlyphCache cache(5000); + return cache; +} + +const QGlyphRun *GlyphCache::get(const QFont &font, const QString &text) +{ + GlyphCacheKey key{font, text}; + if (auto *run = object(key)) + return run; + + QTextLayout layout; + + layout.setText(text); + layout.setFont(font); + + layout.beginLayout(); + layout.createLine().setNumColumns(std::numeric_limits::max()); + layout.endLayout(); + + if (layout.lineCount() > 0) { + QGlyphRun *run = new QGlyphRun(layout.lineAt(0).glyphRuns().first()); + insert(key, run); + return run; + } + return nullptr; +} + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/glyphcache.h b/src/plugins/terminal/glyphcache.h new file mode 100644 index 00000000000..60701098f5f --- /dev/null +++ b/src/plugins/terminal/glyphcache.h @@ -0,0 +1,34 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include +#include +#include + +namespace Terminal::Internal { + +struct GlyphCacheKey +{ + QFont font; + QString text; + + bool operator==(const GlyphCacheKey &other) const + { + return font == other.font && text == other.text; + } +}; + +class GlyphCache : public QCache +{ +public: + using QCache::QCache; + + static GlyphCache &instance(); + + const QGlyphRun *get(const QFont &font, const QString &text); +}; + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/scrollback.cpp b/src/plugins/terminal/scrollback.cpp index 6330e3c0ac7..ca85c942d3d 100644 --- a/src/plugins/terminal/scrollback.cpp +++ b/src/plugins/terminal/scrollback.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: BSD-3-Clause #include "scrollback.h" -#include "celllayout.h" #include #include @@ -15,15 +14,6 @@ Scrollback::Line::Line(int cols, const VTermScreenCell *cells, VTermState *vts) : m_cols(cols) , m_cells(std::make_unique(cols)) { - m_textFuture = std::async(std::launch::async, [this, cols] { - std::u32string text; - text.reserve(cols); - for (int i = 0; i < cols; ++i) { - text += cellToString(m_cells[i]); - } - return text; - }); - memcpy(m_cells.get(), cells, cols * sizeof(cells[0])); for (int i = 0; i < cols; ++i) { vterm_state_convert_color_to_rgb(vts, &m_cells[i].fg); @@ -37,34 +27,6 @@ const VTermScreenCell *Scrollback::Line::cell(int i) const return &m_cells[i]; } -const QTextLayout &Scrollback::Line::layout(int version, const QFont &font, qreal lineSpacing) const -{ - if (!m_layout) - m_layout = std::make_unique(); - - if (m_layoutVersion != version) { - VTermColor defaultBg; - defaultBg.type = VTERM_COLOR_DEFAULT_BG; - m_layout->clearLayout(); - m_layout->setFont(font); - createTextLayout(*m_layout, - nullptr, - defaultBg, - QRect(0, 0, m_cols, 1), - lineSpacing, - [this](int x, int) { return &m_cells[x]; }); - m_layoutVersion = version; - } - return *m_layout; -} - -const std::u32string &Scrollback::Line::text() const -{ - if (!m_text) - m_text = m_textFuture.get(); - return *m_text; -} - Scrollback::Scrollback(size_t capacity) : m_capacity(capacity) {} @@ -95,26 +57,9 @@ void Scrollback::popto(int cols, VTermScreenCell *cells) m_deque.pop_front(); } -size_t Scrollback::scroll(int delta) -{ - m_offset = std::min(std::max(0, static_cast(m_offset) + delta), - static_cast(m_deque.size())); - return m_offset; -} - void Scrollback::clear() { - m_offset = 0; m_deque.clear(); } -std::u32string Scrollback::currentText() -{ - std::u32string currentText; - for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) { - currentText += it->text(); - } - return currentText; -} - } // namespace Terminal::Internal diff --git a/src/plugins/terminal/scrollback.h b/src/plugins/terminal/scrollback.h index 4d8849182c9..72c64547a15 100644 --- a/src/plugins/terminal/scrollback.h +++ b/src/plugins/terminal/scrollback.h @@ -29,25 +29,17 @@ public: const VTermScreenCell *cell(int i) const; const VTermScreenCell *cells() const { return &m_cells[0]; }; - const QTextLayout &layout(int version, const QFont &font, qreal lineSpacing) const; - const std::u32string &text() const; - private: int m_cols; std::unique_ptr m_cells; - mutable std::unique_ptr m_layout; - mutable int m_layoutVersion{-1}; - mutable std::optional m_text; - mutable std::future m_textFuture; }; public: Scrollback(size_t capacity); Scrollback() = delete; - size_t capacity() const { return m_capacity; }; - size_t size() const { return m_deque.size(); }; - size_t offset() const { return m_offset; }; + int capacity() const { return m_capacity; }; + int size() const { return static_cast(m_deque.size()); }; const Line &line(size_t index) const { return m_deque.at(index); }; const std::deque &lines() const { return m_deque; }; @@ -56,16 +48,11 @@ public: const VTermScreenCell *cells, VTermState *vts); void popto(int cols, VTermScreenCell *cells); - size_t scroll(int delta); - void unscroll() { m_offset = 0; }; void clear(); - std::u32string currentText(); - private: size_t m_capacity; - size_t m_offset{0}; std::deque m_deque; }; diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp new file mode 100644 index 00000000000..2bd7327c26b --- /dev/null +++ b/src/plugins/terminal/terminalsurface.cpp @@ -0,0 +1,504 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalsurface.h" + +#include "keys.h" +#include "scrollback.h" + +#include + +#include + +#include + +Q_LOGGING_CATEGORY(log, "qtc.terminal.surface", QtWarningMsg); + +namespace Terminal::Internal { + +QColor toQColor(const VTermColor &c) +{ + return QColor(qRgb(c.rgb.red, c.rgb.green, c.rgb.blue)); +}; + +struct TerminalSurfacePrivate +{ + TerminalSurfacePrivate(TerminalSurface *surface, const QSize &initialGridSize) + : m_vterm(vterm_new(initialGridSize.height(), initialGridSize.width()), vterm_free) + , m_vtermScreen(vterm_obtain_screen(m_vterm.get())) + , m_scrollback(std::make_unique(5000)) + , q(surface) + { + vterm_set_utf8(m_vterm.get(), true); + + static auto writeToPty = [](const char *s, size_t len, void *user) { + auto p = static_cast(user); + emit p->q->writeToPty(QByteArray(s, static_cast(len))); + }; + + vterm_output_set_callback(m_vterm.get(), writeToPty, this); + + memset(&m_vtermScreenCallbacks, 0, sizeof(m_vtermScreenCallbacks)); + + m_vtermScreenCallbacks.damage = [](VTermRect rect, void *user) { + auto p = static_cast(user); + rect.start_row += p->m_scrollback->size(); + rect.end_row += p->m_scrollback->size(); + p->invalidate(rect); + return 1; + }; + m_vtermScreenCallbacks.sb_pushline = [](int cols, const VTermScreenCell *cells, void *user) { + auto p = static_cast(user); + return p->sb_pushline(cols, cells); + }; + m_vtermScreenCallbacks.sb_popline = [](int cols, VTermScreenCell *cells, void *user) { + auto p = static_cast(user); + return p->sb_popline(cols, cells); + }; + m_vtermScreenCallbacks.settermprop = [](VTermProp prop, VTermValue *val, void *user) { + auto p = static_cast(user); + return p->setTerminalProperties(prop, val); + }; + m_vtermScreenCallbacks.movecursor = + [](VTermPos pos, VTermPos oldpos, int visible, void *user) { + auto p = static_cast(user); + return p->movecursor(pos, oldpos, visible); + }; + + m_vtermScreenCallbacks.sb_clear = [](void *user) { + auto p = static_cast(user); + return p->sb_clear(); + }; + + vterm_screen_set_callbacks(m_vtermScreen, &m_vtermScreenCallbacks, this); + vterm_screen_set_damage_merge(m_vtermScreen, VTERM_DAMAGE_SCROLL); + vterm_screen_enable_altscreen(m_vtermScreen, true); + + VTermState *vts = vterm_obtain_state(m_vterm.get()); + vterm_state_set_bold_highbright(vts, true); + + vterm_screen_reset(m_vtermScreen, 1); + } + + QSize liveSize() const + { + int rows; + int cols; + vterm_get_size(m_vterm.get(), &rows, &cols); + + return QSize(cols, rows); + } + + TerminalCell toCell(const VTermScreenCell &cell) + { + TerminalCell result; + result.width = cell.width; + result.text = QString::fromUcs4(cell.chars); + + const VTermColor *bg = &cell.bg; + const VTermColor *fg = &cell.fg; + + if (static_cast(cell.attrs.reverse)) + std::swap(fg, bg); + + const QColor cellBgColor = toQColor(*bg); + const QColor cellFgColor = toQColor(*fg); + + if (cellBgColor != m_defaultBgColor) + result.background = toQColor(*bg); + + result.foreground = cellFgColor; + + result.bold = cell.attrs.bold; + result.strikeOut = cell.attrs.strike; + + if (cell.attrs.underline > 0) { + result.underlineStyle = QTextCharFormat::NoUnderline; + switch (cell.attrs.underline) { + case VTERM_UNDERLINE_SINGLE: + result.underlineStyle = QTextCharFormat::SingleUnderline; + break; + case VTERM_UNDERLINE_DOUBLE: + // TODO: Double underline + result.underlineStyle = QTextCharFormat::SingleUnderline; + break; + case VTERM_UNDERLINE_CURLY: + result.underlineStyle = QTextCharFormat::WaveUnderline; + break; + case VTERM_UNDERLINE_DASHED: + result.underlineStyle = QTextCharFormat::DashUnderline; + break; + case VTERM_UNDERLINE_DOTTED: + result.underlineStyle = QTextCharFormat::DotLine; + break; + } + } + + result.strikeOut = cell.attrs.strike; + + return result; + } + + VTermColor defaultBgColor() const + { + VTermColor defaultBg; + if (!m_altscreen) { + VTermColor defaultFg; + vterm_state_get_default_colors(vterm_obtain_state(m_vterm.get()), + &defaultFg, + &defaultBg); + // We want to compare the cell bg against this later and cells don't + // set DEFAULT_BG + defaultBg.type = VTERM_COLOR_RGB; + return defaultBg; + } // This is a slightly better guess when in an altscreen + + VTermPos vtp{0, 0}; + static VTermScreenCell refCell{}; + vterm_screen_get_cell(m_vtermScreen, vtp, &refCell); + return refCell.bg; + } + + // Callbacks from vterm + void invalidate(VTermRect rect) + { + emit q->invalidated( + QRect{QPoint{rect.start_col, rect.start_row}, QPoint{rect.end_col, rect.end_row - 1}}); + } + + int sb_pushline(int cols, const VTermScreenCell *cells) + { + m_scrollback->emplace(cols, cells, vterm_obtain_state(m_vterm.get())); + emit q->fullSizeChanged(q->fullSize()); + return 1; + } + + int sb_popline(int cols, VTermScreenCell *cells) + { + if (m_scrollback->size() == 0) + return 0; + + m_scrollback->popto(cols, cells); + emit q->fullSizeChanged(q->fullSize()); + return 1; + } + + int sb_clear() + { + m_scrollback->clear(); + emit q->fullSizeChanged(q->fullSize()); + return 1; + } + + int setTerminalProperties(VTermProp prop, VTermValue *val) + { + switch (prop) { + case VTERM_PROP_CURSORVISIBLE: + m_cursor.visible = val->boolean; + break; + case VTERM_PROP_CURSORBLINK: + qCDebug(log) << "Ignoring VTERM_PROP_CURSORBLINK" << val->boolean; + break; + case VTERM_PROP_CURSORSHAPE: + qCDebug(log) << "Ignoring VTERM_PROP_CURSORSHAPE" << val->number; + break; + case VTERM_PROP_ICONNAME: + //emit iconTextChanged(val->string); + break; + case VTERM_PROP_TITLE: + break; + case VTERM_PROP_ALTSCREEN: + m_altscreen = val->boolean; + emit q->altscreenChanged(m_altscreen); + //setSelection(std::nullopt); + break; + case VTERM_PROP_MOUSE: + qCDebug(log) << "Ignoring VTERM_PROP_MOUSE" << val->number; + break; + case VTERM_PROP_REVERSE: + qCDebug(log) << "Ignoring VTERM_PROP_REVERSE" << val->boolean; + break; + case VTERM_N_PROPS: + break; + } + return 1; + } + int movecursor(VTermPos pos, VTermPos oldpos, int visible) + { + Q_UNUSED(oldpos); + Cursor oldCursor = q->cursor(); + m_cursor = {{pos.col, pos.row}, visible > 0}; + q->cursorChanged(oldCursor, q->cursor()); + return 1; + } + + const VTermScreenCell *cellAt(int x, int y) + { + QTC_ASSERT(y >= 0 && x >= 0, return nullptr); + QTC_ASSERT(y < liveSize().height() + m_scrollback->size() && x < liveSize().width(), + return nullptr); + if (y < m_scrollback->size()) { + const auto &sbl = m_scrollback->line((m_scrollback->size() - 1) - y); + if (x < sbl.cols()) { + return sbl.cell(x); + } + return nullptr; + } + + y -= m_scrollback->size(); + + static VTermScreenCell refCell{}; + VTermPos vtp{y, x}; + vterm_screen_get_cell(m_vtermScreen, vtp, &refCell); + vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.fg); + vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.bg); + + return &refCell; + } + + std::unique_ptr m_vterm; + VTermScreen *m_vtermScreen; + VTermScreenCallbacks m_vtermScreenCallbacks; + + QColor m_defaultBgColor; + Cursor m_cursor; + + bool m_altscreen{false}; + + std::unique_ptr m_scrollback; + + TerminalSurface *q; +}; + +TerminalSurface::TerminalSurface(QSize initialGridSize) + : d(std::make_unique(this, initialGridSize)) +{} + +TerminalSurface::~TerminalSurface() = default; + +int TerminalSurface::cellWidthAt(int x, int y) const +{ + const VTermScreenCell *cell = d->cellAt(x, y); + if (!cell) + return 0; + return cell->width; +} + +QSize TerminalSurface::liveSize() const +{ + return d->liveSize(); +} + +QSize TerminalSurface::fullSize() const +{ + return QSize{d->liveSize().width(), d->liveSize().height() + d->m_scrollback->size()}; +} + +std::u32string::value_type TerminalSurface::fetchCharAt(int x, int y) const +{ + const VTermScreenCell *cell = d->cellAt(x, y); + if (!cell) + return 0; + + if (cell->width == 0) + return 0; + + QString s = QString::fromUcs4(cell->chars, 6).normalized(QString::NormalizationForm_C); + const QList ucs4 = s.toUcs4(); + return std::u32string(ucs4.begin(), ucs4.end()).front(); +} + +TerminalCell TerminalSurface::fetchCell(int x, int y) const +{ + static TerminalCell emptyCell{1, {}, {}}; + + QTC_ASSERT(y >= 0, return emptyCell); + QTC_ASSERT(y < d->liveSize().height() + d->m_scrollback->size(), return emptyCell); + + const VTermScreenCell *refCell = d->cellAt(x, y); + if (!refCell) + return emptyCell; + + return d->toCell(*refCell); +} + +void TerminalSurface::clearAll() +{ + // Fake a scrollback clearing + QByteArray data{"\x1b[3J"}; + vterm_input_write(d->m_vterm.get(), data.constData(), data.size()); + + // Send Ctrl+L which will clear the screen + emit writeToPty(QByteArray("\f")); +} + +void TerminalSurface::resize(QSize newSize) +{ + vterm_set_size(d->m_vterm.get(), newSize.height(), newSize.width()); +} + +QPoint TerminalSurface::posToGrid(int pos) const +{ + return {pos % d->liveSize().width(), pos / d->liveSize().width()}; +} +int TerminalSurface::gridToPos(QPoint gridPos) const +{ + return gridPos.y() * d->liveSize().width() + gridPos.x(); +} + +void TerminalSurface::dataFromPty(const QByteArray &data) +{ + vterm_input_write(d->m_vterm.get(), data.constData(), data.size()); + vterm_screen_flush_damage(d->m_vtermScreen); +} + +void TerminalSurface::flush() +{ + vterm_screen_flush_damage(d->m_vtermScreen); +} + +void TerminalSurface::setColors(QColor foreground, QColor background) +{ + VTermState *vts = vterm_obtain_state(d->m_vterm.get()); + + VTermColor fg; + VTermColor bg; + + vterm_color_rgb(&fg, foreground.red(), foreground.green(), foreground.blue()); + vterm_color_rgb(&bg, background.red(), background.green(), background.blue()); + + d->m_defaultBgColor = background; + + vterm_state_set_default_colors(vts, &fg, &bg); + vterm_screen_reset(d->m_vtermScreen, 1); +} + +void TerminalSurface::setAnsiColor(int index, QColor color) +{ + VTermState *vts = vterm_obtain_state(d->m_vterm.get()); + + VTermColor col; + vterm_color_rgb(&col, color.red(), color.green(), color.blue()); + vterm_state_set_palette_color(vts, index, &col); + + vterm_screen_reset(d->m_vtermScreen, 1); +} + +void TerminalSurface::pasteFromClipboard(const QString &clipboardText) +{ + if (clipboardText.isEmpty()) + return; + + vterm_keyboard_start_paste(d->m_vterm.get()); + for (unsigned int ch : clipboardText.toUcs4()) + vterm_keyboard_unichar(d->m_vterm.get(), ch, VTERM_MOD_NONE); + vterm_keyboard_end_paste(d->m_vterm.get()); + + if (!d->m_altscreen) { + emit unscroll(); + } +} + +void TerminalSurface::sendKey(Qt::Key key) +{ + if (key == Qt::Key_Escape) + vterm_keyboard_key(d->m_vterm.get(), VTERM_KEY_ESCAPE, VTERM_MOD_NONE); +} + +void TerminalSurface::sendKey(const QString &text) +{ + for (const unsigned int ch : text.toUcs4()) + vterm_keyboard_unichar(d->m_vterm.get(), ch, VTERM_MOD_NONE); +} + +void TerminalSurface::sendKey(QKeyEvent *event) +{ + bool keypad = event->modifiers() & Qt::KeypadModifier; + VTermModifier mod = Internal::qtModifierToVTerm(event->modifiers()); + VTermKey key = Internal::qtKeyToVTerm(Qt::Key(event->key()), keypad); + + if (key != VTERM_KEY_NONE) { + if (mod == VTERM_MOD_SHIFT && (key == VTERM_KEY_ESCAPE || key == VTERM_KEY_BACKSPACE)) + mod = VTERM_MOD_NONE; + + vterm_keyboard_key(d->m_vterm.get(), key, mod); + } else if (event->text().length() == 1) { + // This maps to delete word and is way to easy to mistakenly type + // if (event->key() == Qt::Key_Space && mod == VTERM_MOD_SHIFT) + // mod = VTERM_MOD_NONE; + + // Per https://github.com/justinmk/neovim/commit/317d5ca7b0f92ef42de989b3556ca9503f0a3bf6 + // libvterm prefers we send the full keycode rather than sending the + // ctrl modifier. This helps with ncurses applications which otherwise + // do not recognize ctrl+ and in the shell for getting common control characters + // like ctrl+i for tab or ctrl+j for newline. + + // Workaround for "ALT+SHIFT+/" (\ on german mac keyboards) + if (mod == (VTERM_MOD_SHIFT | VTERM_MOD_ALT) && event->key() == Qt::Key_Slash) { + mod = VTERM_MOD_NONE; + } + + vterm_keyboard_unichar(d->m_vterm.get(), event->text().toUcs4()[0], VTERM_MOD_NONE); + + // TODO: ?? + //setSelection(std::nullopt); + } else if (mod == VTERM_MOD_CTRL && event->key() >= Qt::Key_A && event->key() < Qt::Key_Z) { + vterm_keyboard_unichar(d->m_vterm.get(), 'a' + (event->key() - Qt::Key_A), mod); + } +} + +Cursor TerminalSurface::cursor() const +{ + Cursor cursor = d->m_cursor; + cursor.position.setY(cursor.position.y() + d->m_scrollback->size()); + + return cursor; +} + +QColor TerminalSurface::defaultBgColor() const +{ + return toQColor(d->defaultBgColor()); +} + +CellIterator TerminalSurface::begin() const +{ + auto res = CellIterator(this, {0, 0}); + res.m_state = CellIterator::State::BEGIN; + return res; +} + +CellIterator TerminalSurface::end() const +{ + return CellIterator(this, CellIterator::State::END); +} + +std::reverse_iterator TerminalSurface::rbegin() const +{ + return std::make_reverse_iterator(end()); +} + +std::reverse_iterator TerminalSurface::rend() const +{ + return std::make_reverse_iterator(begin()); +} + +CellIterator TerminalSurface::iteratorAt(QPoint pos) const +{ + return CellIterator(this, pos); +} +CellIterator TerminalSurface::iteratorAt(int pos) const +{ + return CellIterator(this, pos); +} + +std::reverse_iterator TerminalSurface::rIteratorAt(QPoint pos) const +{ + return std::make_reverse_iterator(iteratorAt(pos)); +} + +std::reverse_iterator TerminalSurface::rIteratorAt(int pos) const +{ + return std::make_reverse_iterator(iteratorAt(pos)); +} + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/terminalsurface.h b/src/plugins/terminal/terminalsurface.h new file mode 100644 index 00000000000..b92cc9da833 --- /dev/null +++ b/src/plugins/terminal/terminalsurface.h @@ -0,0 +1,103 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "celliterator.h" + +#include +#include +#include + +#include + +namespace Terminal::Internal { + +class Scrollback; + +struct TerminalSurfacePrivate; + +struct TerminalCell +{ + int width; + QString text; + bool bold{false}; + bool italic{false}; + QColor foreground; + std::optional background; + QTextCharFormat::UnderlineStyle underlineStyle{QTextCharFormat::NoUnderline}; + bool strikeOut{false}; +}; + +struct Cursor +{ + QPoint position; + bool visible; +}; + +class TerminalSurface : public QObject +{ + Q_OBJECT; + +public: + TerminalSurface(QSize initialGridSize); + ~TerminalSurface(); + +public: + CellIterator begin() const; + CellIterator end() const; + std::reverse_iterator rbegin() const; + std::reverse_iterator rend() const; + + CellIterator iteratorAt(QPoint pos) const; + CellIterator iteratorAt(int pos) const; + + std::reverse_iterator rIteratorAt(QPoint pos) const; + std::reverse_iterator rIteratorAt(int pos) const; + +public: + void clearAll(); + + void resize(QSize newSize); + + TerminalCell fetchCell(int x, int y) const; + std::u32string::value_type fetchCharAt(int x, int y) const; + int cellWidthAt(int x, int y) const; + + QSize liveSize() const; + QSize fullSize() const; + + QPoint posToGrid(int pos) const; + int gridToPos(QPoint gridPos) const; + + void dataFromPty(const QByteArray &data); + void flush(); + + void setColors(QColor foreground, QColor background); + void setAnsiColor(int index, QColor color); + + void pasteFromClipboard(const QString &text); + + void sendKey(Qt::Key key); + void sendKey(QKeyEvent *event); + void sendKey(const QString &text); + + int invertedScrollOffset() const; + + Cursor cursor() const; + + QColor defaultBgColor() const; + +signals: + void writeToPty(const QByteArray &data); + void invalidated(QRect grid); + void fullSizeChanged(QSize newSize); + void cursorChanged(Cursor oldCursor, Cursor newCursor); + void altscreenChanged(bool altScreen); + void unscroll(); + +private: + std::unique_ptr d; +}; + +} // namespace Terminal::Internal diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index b0515833076..0be7bc7b72a 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -2,11 +2,13 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "terminalwidget.h" -#include "celllayout.h" +#include "glyphcache.h" #include "keys.h" #include "terminalsettings.h" +#include "terminalsurface.h" #include "terminaltr.h" +#include #include #include @@ -18,19 +20,26 @@ #include #include +#include #include +#include #include #include #include #include #include +#include +#include #include #include #include +#include #include +#include Q_LOGGING_CATEGORY(terminalLog, "qtc.terminal", QtWarningMsg) Q_LOGGING_CATEGORY(selectionLog, "qtc.terminal.selection", QtWarningMsg) +Q_LOGGING_CATEGORY(paintLog, "qtc.terminal.paint", QtWarningMsg) using namespace Utils; using namespace Utils::Terminal; @@ -44,9 +53,6 @@ static constexpr std::chrono::milliseconds minRefreshInterval = 1s / 30; TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &openParameters) : QAbstractScrollArea(parent) - , m_vterm(vterm_new(size().height(), size().width()), vterm_free) - , m_vtermScreen(vterm_obtain_screen(m_vterm.get())) - , m_scrollback(std::make_unique(5000)) , m_copyAction(Tr::tr("Copy")) , m_pasteAction(Tr::tr("Paste")) , m_clearSelectionAction(Tr::tr("Clear Selection")) @@ -56,7 +62,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op , m_lastFlush(std::chrono::system_clock::now()) , m_lastDoubleClick(std::chrono::system_clock::now()) { - setupVTerm(); + setupSurface(); setupFont(); setupColors(); setupActions(); @@ -68,8 +74,6 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op setViewportMargins(1, 1, 1, 1); - m_textLayout.setCacheEnabled(true); - setFocus(); setFocusPolicy(Qt::StrongFocus); @@ -81,7 +85,6 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op connect(&m_flushDelayTimer, &QTimer::timeout, this, [this]() { flushVTerm(true); }); connect(&TerminalSettings::instance(), &AspectContainer::applied, this, [this] { - m_layoutVersion++; // Setup colors first, as setupFont will redraw the screen. setupColors(); setupFont(); @@ -114,7 +117,6 @@ void TerminalWidget::setupPty() }); connect(m_process.get(), &QtcProcess::done, this, [this] { - m_cursor.visible = false; if (m_process) { if (m_process->exitCode() != 0) { QByteArray msg = QString("\r\n\033[31mProcess exited with code: %1") @@ -124,8 +126,7 @@ void TerminalWidget::setupPty() if (!m_process->errorString().isEmpty()) msg += QString(" (%1)").arg(m_process->errorString()).toUtf8(); - vterm_input_write(m_vterm.get(), msg.constData(), msg.size()); - vterm_screen_flush_damage(m_vtermScreen); + m_surface->dataFromPty(msg); return; } @@ -149,8 +150,7 @@ void TerminalWidget::setupPty() .arg(m_process ? m_process->exitCode() : -1) .toUtf8(); - vterm_input_write(m_vterm.get(), msg.constData(), msg.size()); - vterm_screen_flush_damage(m_vtermScreen); + m_surface->dataFromPty(msg); } }); @@ -191,33 +191,13 @@ void TerminalWidget::setupColors() m_currentColors = newColors; - VTermState *vts = vterm_obtain_state(m_vterm.get()); - - auto setColor = [vts](int index, uint8_t r, uint8_t g, uint8_t b) { - VTermColor col; - vterm_color_rgb(&col, r, g, b); - vterm_state_set_palette_color(vts, index, &col); - }; + m_surface->setColors(TerminalSettings::instance().foregroundColor.value(), + TerminalSettings::instance().backgroundColor.value()); for (int i = 0; i < 16; ++i) { - QColor c = TerminalSettings::instance().colors[i].value(); - setColor(i, c.red(), c.green(), c.blue()); + m_surface->setAnsiColor(i, TerminalSettings::instance().colors[i].value()); } - VTermColor fg; - VTermColor bg; - - vterm_color_rgb(&fg, - TerminalSettings::instance().foregroundColor.value().red(), - TerminalSettings::instance().foregroundColor.value().green(), - TerminalSettings::instance().foregroundColor.value().blue()); - vterm_color_rgb(&bg, - TerminalSettings::instance().backgroundColor.value().red(), - TerminalSettings::instance().backgroundColor.value().green(), - TerminalSettings::instance().backgroundColor.value().blue()); - - vterm_state_set_default_colors(vts, &fg, &bg); - clearContents(); } @@ -251,65 +231,52 @@ void TerminalWidget::writeToPty(const QByteArray &data) m_process->writeRaw(data); } -void TerminalWidget::setupVTerm() +void TerminalWidget::setupSurface() { - vterm_set_utf8(m_vterm.get(), true); + m_surface = std::make_unique(QSize{80, 60}); - static auto writeToPty = [](const char *s, size_t len, void *user) { - auto p = static_cast(user); - p->writeToPty(QByteArray(s, static_cast(len))); - }; + connect(m_surface.get(), + &Internal::TerminalSurface::writeToPty, + this, + &TerminalWidget::writeToPty); + connect(m_surface.get(), &Internal::TerminalSurface::fullSizeChanged, this, [this] { + updateScrollBars(); + }); + connect(m_surface.get(), + &Internal::TerminalSurface::invalidated, + this, + [this](const QRect &rect) { updateViewport(gridToViewport(rect)); }); + connect(m_surface.get(), + &Internal::TerminalSurface::cursorChanged, + this, + [this](const Internal::Cursor &oldCursor, const Internal::Cursor &newCursor) { + int startX = oldCursor.position.x(); + int endX = newCursor.position.x(); - vterm_output_set_callback(m_vterm.get(), writeToPty, this); + if (startX > endX) + std::swap(startX, endX); - memset(&m_vtermScreenCallbacks, 0, sizeof(m_vtermScreenCallbacks)); + int startY = oldCursor.position.y(); + int endY = newCursor.position.y(); + if (startY > endY) + std::swap(startY, endY); - m_vtermScreenCallbacks.damage = [](VTermRect rect, void *user) { - auto p = static_cast(user); - p->invalidate(rect); - return 1; - }; - m_vtermScreenCallbacks.sb_pushline = [](int cols, const VTermScreenCell *cells, void *user) { - auto p = static_cast(user); - return p->sb_pushline(cols, cells); - }; - m_vtermScreenCallbacks.sb_popline = [](int cols, VTermScreenCell *cells, void *user) { - auto p = static_cast(user); - return p->sb_popline(cols, cells); - }; - m_vtermScreenCallbacks.settermprop = [](VTermProp prop, VTermValue *val, void *user) { - auto p = static_cast(user); - return p->setTerminalProperties(prop, val); - }; - m_vtermScreenCallbacks.movecursor = [](VTermPos pos, VTermPos oldpos, int visible, void *user) { - auto p = static_cast(user); - return p->movecursor(pos, oldpos, visible); - }; - - m_vtermScreenCallbacks.sb_clear = [](void *user) { - auto p = static_cast(user); - return p->sb_clear(); - }; - - vterm_screen_set_callbacks(m_vtermScreen, &m_vtermScreenCallbacks, this); - vterm_screen_set_damage_merge(m_vtermScreen, VTERM_DAMAGE_SCROLL); - vterm_screen_enable_altscreen(m_vtermScreen, true); - - VTermState *vts = vterm_obtain_state(m_vterm.get()); - vterm_state_set_bold_highbright(vts, true); - - vterm_screen_reset(m_vtermScreen, 1); + updateViewport(gridToViewport(QRect{QPoint{startX, startY}, QPoint{endX, endY}})); + }); + connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] { + setSelection(std::nullopt); + }); + connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] { + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); + }); } void TerminalWidget::setFont(const QFont &font) { m_font = font; - //QRawFont rawFont = QRawFont::fromFont(m_font); - m_textLayout.setFont(m_font); - QFontMetricsF qfm{m_font}; - const auto w = [qfm]() -> qreal { + const qreal w = [qfm]() -> qreal { if (HostOsInfo::isMacHost()) return qfm.maxWidth(); return qfm.averageCharWidth(); @@ -317,9 +284,7 @@ void TerminalWidget::setFont(const QFont &font) qCInfo(terminalLog) << font.family() << font.pointSize() << w << viewport()->size(); - m_cellSize = {w, qfm.height()}; - m_cellBaseline = qfm.ascent(); - m_lineSpacing = qfm.height(); + m_cellSize = {w, (double) qCeil(qfm.height())}; QAbstractScrollArea::setFont(m_font); @@ -355,46 +320,22 @@ QAction &TerminalWidget::zoomOutAction() void TerminalWidget::copyToClipboard() const { - if (m_selection) { - const size_t startLine = qFloor(m_selection->start.y() / m_lineSpacing); - const size_t endLine = qFloor(m_selection->end.y() / m_lineSpacing); + if (!m_selection) + return; - QString selectedText; - size_t row = startLine; - for (; row < m_scrollback->size(); row++) { - const Internal::Scrollback::Line &line = m_scrollback->line((m_scrollback->size() - 1) - - row); - if (row > endLine) - break; + Internal::CellIterator it = m_surface->iteratorAt(m_selection->start); + Internal::CellIterator end = m_surface->iteratorAt(m_selection->end); - const QTextLayout &layout = line.layout(m_layoutVersion, m_font, m_lineSpacing); - const std::optional range - = selectionToFormatRange(*m_selection, layout, row); - if (range) - selectedText.append(line.layout(m_layoutVersion, m_font, m_lineSpacing) - .text() - .mid(range->start, range->length) - .trimmed()); + std::u32string s; + std::copy(it, end, std::back_inserter(s)); - if (endLine > row) - selectedText.append(QChar::LineFeed); - } + const QString text = QString::fromUcs4(s.data(), static_cast(s.size())); - if (row <= endLine) { - const std::optional range - = selectionToFormatRange(*m_selection, m_textLayout, m_scrollback->size()); - if (range) - selectedText.append(m_textLayout.text() - .mid(range->start, range->length) - .replace(QChar::LineSeparator, QChar::LineFeed) - .trimmed()); - } + qCDebug(selectionLog) << "Copied to clipboard: " << text; - selectedText.replace(QChar::Nbsp, QChar::Space); - - setClipboardAndSelection(selectedText); - } + setClipboardAndSelection(text); } + void TerminalWidget::pasteFromClipboard() { QClipboard *clipboard = QApplication::clipboard(); @@ -403,50 +344,38 @@ void TerminalWidget::pasteFromClipboard() if (clipboardText.isEmpty()) return; - vterm_keyboard_start_paste(m_vterm.get()); - for (unsigned int ch : clipboardText.toUcs4()) - vterm_keyboard_unichar(m_vterm.get(), ch, VTERM_MOD_NONE); - vterm_keyboard_end_paste(m_vterm.get()); - - if (!m_altscreen && m_scrollback->offset()) { - m_scrollback->unscroll(); - viewport()->update(); - } + m_surface->pasteFromClipboard(clipboardText); } void TerminalWidget::clearSelection() { setSelection(std::nullopt); - viewport()->update(); - vterm_keyboard_key(m_vterm.get(), VTERM_KEY_ESCAPE, VTERM_MOD_NONE); + updateViewport(); + m_surface->sendKey(Qt::Key_Escape); } + void TerminalWidget::zoomIn() { - m_layoutVersion++; m_font.setPointSize(m_font.pointSize() + 1); setFont(m_font); } + void TerminalWidget::zoomOut() { - m_layoutVersion++; m_font.setPointSize(qMax(m_font.pointSize() - 1, 1)); setFont(m_font); } void TerminalWidget::clearContents() { - // Fake a scrollback clearing - QByteArray data{"\x1b[3J"}; - vterm_input_write(m_vterm.get(), data.constData(), data.size()); - - // Send Ctrl+L which will clear the screen - writeToPty(QByteArray("\f")); + m_surface->clearAll(); } void TerminalWidget::onReadyRead(bool forceFlush) { QByteArray data = m_process->readAllRawStandardOutput(); - vterm_input_write(m_vterm.get(), data.constData(), data.size()); + + m_surface->dataFromPty(data); flushVTerm(forceFlush); } @@ -463,7 +392,7 @@ void TerminalWidget::flushVTerm(bool force) m_flushDelayTimer.stop(); m_lastFlush = now; - vterm_screen_flush_damage(m_vtermScreen); + m_surface->flush(); return; } @@ -487,23 +416,10 @@ QString TerminalWidget::shellName() const return m_shellName; } -const VTermScreenCell *TerminalWidget::fetchCell(int x, int y) const -{ - QTC_ASSERT(y >= 0, return nullptr); - QTC_ASSERT(y < m_vtermSize.height(), return nullptr); - - static VTermScreenCell refCell{}; - VTermPos vtp{y, x}; - vterm_screen_get_cell(m_vtermScreen, vtp, &refCell); - vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.fg); - vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.bg); - return &refCell; -}; - QPoint TerminalWidget::viewportToGlobal(QPoint p) const { int y = p.y() - topMargin(); - const double offset = (m_scrollback->size() - m_scrollback->offset()) * m_lineSpacing; + const double offset = verticalScrollBar()->value() * m_cellSize.height(); y += offset; return {p.x(), y}; @@ -512,208 +428,382 @@ QPoint TerminalWidget::viewportToGlobal(QPoint p) const QPoint TerminalWidget::globalToViewport(QPoint p) const { int y = p.y() + topMargin(); - const double offset = (m_scrollback->size() - m_scrollback->offset()) * m_lineSpacing; + const double offset = verticalScrollBar()->value() * m_cellSize.height(); y -= offset; return {p.x(), y}; } -QPoint TerminalWidget::globalToGrid(QPoint p) const +QPoint TerminalWidget::globalToGrid(QPointF p) const { return QPoint(p.x() / m_cellSize.width(), p.y() / m_cellSize.height()); } -void TerminalWidget::createTextLayout() +QPointF TerminalWidget::gridToGlobal(QPoint p, bool bottom, bool right) const { - QElapsedTimer t; - t.start(); - - VTermColor defaultBg; - if (!m_altscreen) { - VTermColor defaultFg; - vterm_state_get_default_colors(vterm_obtain_state(m_vterm.get()), &defaultFg, &defaultBg); - // We want to compare the cell bg against this later and cells don't - // set DEFAULT_BG - defaultBg.type = VTERM_COLOR_RGB; - } else { - // This is a slightly better guess when in an altscreen - const VTermScreenCell *cell = fetchCell(0, 0); - defaultBg = cell->bg; - } - - m_textLayout.clearLayout(); - - Internal::createTextLayout(m_textLayout, - &m_currentLiveText, - defaultBg, - QRect({0, 0}, m_vtermSize), - m_lineSpacing, - [this](int x, int y) { return fetchCell(x, y); }); - - qCInfo(terminalLog) << "createTextLayout took:" << t.elapsed() << "ms"; + QPointF result = QPointF(p.x() * m_cellSize.width(), p.y() * m_cellSize.height()); + if (bottom || right) + result += {right ? m_cellSize.width() : 0, bottom ? m_cellSize.height() : 0}; + return result; } qreal TerminalWidget::topMargin() const { - return (qreal) viewport()->size().height() - ((qreal) m_vtermSize.height() * m_lineSpacing); + return viewport()->size().height() - (m_surface->liveSize().height() * m_cellSize.height()); } -std::optional TerminalWidget::selectionToFormatRange( - TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const +static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) { - int selectionStartLine = qFloor(selection.start.y() / m_lineSpacing) - rowOffset; - int selectionEndLine = qFloor(selection.end.y() / m_lineSpacing) - rowOffset; + const qreal radiusBase = qMax(qreal(1), maxRadius); + const qreal pWidth = pen.widthF(); - int nRows = layout.lineCount(); + QString key = QLatin1StringView("WaveUnderline-") % pen.color().name() + % QString::number(*(size_t *) &radiusBase, 16) + % QString::number(*(size_t *) &pWidth); - if (selectionStartLine < nRows && selectionEndLine >= 0) { - QTextLine lStart = layout.lineAt(qMax(0, qMin(selectionStartLine, nRows))); - QTextLine lEnd = layout.lineAt(qMin(nRows - 1, qMax(0, selectionEndLine))); + QPixmap pixmap; + if (QPixmapCache::find(key, &pixmap)) + return pixmap; - int startPos = 0; - int endPos = lEnd.textLength(); + const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio + const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod); + const qreal radius = qFloor(radiusBase * 2) / 2.; - if (selectionStartLine >= 0) - startPos = lStart.xToCursor(selection.start.x()); - if (selectionEndLine < (nRows)) - endPos = lEnd.xToCursor(selection.end.x()); + QPainterPath path; - QTextLayout::FormatRange range; - range.start = startPos; - range.length = endPos - startPos; - range.format.setBackground(TerminalSettings::instance().selectionColor.value()); - return range; + qreal xs = 0; + qreal ys = radius; + + while (xs < width) { + xs += halfPeriod; + ys = -ys; + path.quadTo(xs - halfPeriod / 2, ys, xs, 0); } - return {}; + pixmap = QPixmap(width, radius * 2); + pixmap.fill(Qt::transparent); + { + QPen wavePen = pen; + wavePen.setCapStyle(Qt::SquareCap); + + // This is to protect against making the line too fat, as happens on macOS + // due to it having a rather thick width for the regular underline. + const qreal maxPenWidth = .8 * radius; + if (wavePen.widthF() > maxPenWidth) + wavePen.setWidthF(maxPenWidth); + + QPainter imgPainter(&pixmap); + imgPainter.setPen(wavePen); + imgPainter.setRenderHint(QPainter::Antialiasing); + imgPainter.translate(0, radius); + imgPainter.drawPath(path); + } + + QPixmapCache::insert(key, pixmap); + + return pixmap; +} + +// Copied from qpainter.cpp +static void drawTextItemDecoration(QPainter &painter, + const QPointF &pos, + QTextCharFormat::UnderlineStyle underlineStyle, + QTextItem::RenderFlags flags, + qreal width, + const QColor &underlineColor, + const QRawFont &font) +{ + if (underlineStyle == QTextCharFormat::NoUnderline + && !(flags & (QTextItem::StrikeOut | QTextItem::Overline))) + return; + + const QPen oldPen = painter.pen(); + const QBrush oldBrush = painter.brush(); + painter.setBrush(Qt::NoBrush); + QPen pen = oldPen; + pen.setStyle(Qt::SolidLine); + pen.setWidthF(font.lineThickness()); + pen.setCapStyle(Qt::FlatCap); + + QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y()); + + const qreal underlineOffset = font.underlinePosition(); + + /*if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { + QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme(); + if (theme) + underlineStyle = QTextCharFormat::UnderlineStyle( + theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt()); + if (underlineStyle == QTextCharFormat::SpellCheckUnderline) // still not resolved + underlineStyle = QTextCharFormat::WaveUnderline; + }*/ + + if (underlineStyle == QTextCharFormat::WaveUnderline) { + painter.save(); + painter.translate(0, pos.y() + 1); + qreal maxHeight = font.descent() - qreal(1); + + QColor uc = underlineColor; + if (uc.isValid()) + pen.setColor(uc); + + // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms + const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), + maxHeight / qreal(2.)), + pen); + const int descent = qFloor(maxHeight); + + painter.setBrushOrigin(painter.brushOrigin().x(), 0); + painter.fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave); + painter.restore(); + } else if (underlineStyle != QTextCharFormat::NoUnderline) { + // Deliberately ceil the offset to avoid the underline coming too close to + // the text above it, but limit it to stay within descent. + qreal adjustedUnderlineOffset = std::ceil(underlineOffset) + 0.5; + if (underlineOffset <= font.descent()) + adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, font.descent() - qreal(0.5)); + const qreal underlinePos = pos.y() + adjustedUnderlineOffset; + QColor uc = underlineColor; + if (uc.isValid()) + pen.setColor(uc); + + pen.setStyle((Qt::PenStyle)(underlineStyle)); + painter.setPen(pen); + QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos); + painter.drawLine(underline); + } + + pen.setStyle(Qt::SolidLine); + pen.setColor(oldPen.color()); + + if (flags & QTextItem::StrikeOut) { + QLineF strikeOutLine = line; + strikeOutLine.translate(0., -font.ascent() / 3.); + QColor uc = underlineColor; + if (uc.isValid()) + pen.setColor(uc); + painter.setPen(pen); + painter.drawLine(strikeOutLine); + } + + if (flags & QTextItem::Overline) { + QLineF overline = line; + overline.translate(0., -font.ascent()); + QColor uc = underlineColor; + if (uc.isValid()) + pen.setColor(uc); + painter.setPen(pen); + painter.drawLine(overline); + } + + painter.setPen(oldPen); + painter.setBrush(oldBrush); +} + +int TerminalWidget::paintCell(QPainter &p, + const QRectF &cellRect, + QPoint gridPos, + const Internal::TerminalCell &cell, + QFont &f) const +{ + if (cell.background) + p.fillRect(cellRect, *cell.background); + + p.setPen(cell.foreground); + + f.setBold(cell.bold); + f.setItalic(cell.italic); + + if (!cell.text.isEmpty()) { + const auto r = Internal::GlyphCache::instance().get(f, cell.text); + + if (r) { + const auto brSize = r->boundingRect().size(); + QPointF brOffset; + if (brSize.width() > cellRect.size().width()) + brOffset.setX(-(brSize.width() - cellRect.size().width()) / 2.0); + if (brSize.height() > cellRect.size().height()) + brOffset.setY(-(brSize.height() - cellRect.size().height()) / 2.0); + + QPointF finalPos = cellRect.topLeft() + brOffset; + + p.drawGlyphRun(finalPos, *r); + + bool tempLink = false; + if (m_linkSelection) { + int chPos = m_surface->gridToPos(gridPos); + tempLink = chPos >= m_linkSelection->start && chPos < m_linkSelection->end; + } + if (cell.underlineStyle != QTextCharFormat::NoUnderline || cell.strikeOut || tempLink) { + QTextItem::RenderFlags flags; + //flags.setFlag(QTextItem::RenderFlag::Underline, cell.format.fontUnderline()); + flags.setFlag(QTextItem::StrikeOut, cell.strikeOut); + finalPos.setY(finalPos.y() + r->rawFont().ascent()); + drawTextItemDecoration(p, + finalPos, + tempLink ? QTextCharFormat::DashUnderline + : cell.underlineStyle, + flags, + cellRect.size().width(), + {}, + r->rawFont()); + } + } + } + + return cell.width; +} + +void TerminalWidget::paintCursor(QPainter &p) const +{ + auto cursor = m_surface->cursor(); + + if (cursor.visible) { + const int cursorCellWidth = m_surface->cellWidthAt(cursor.position.x(), cursor.position.y()); + + QRectF cursorRect = QRectF(gridToGlobal(cursor.position), + gridToGlobal({cursor.position.x() + cursorCellWidth, + cursor.position.y()}, + true)); + if (hasFocus()) { + QPainter::CompositionMode oldMode = p.compositionMode(); + p.setCompositionMode(QPainter::RasterOp_NotDestination); + p.fillRect(cursorRect, p.pen().brush()); + p.setCompositionMode(oldMode); + } else { + p.drawRect(cursorRect); + } + } +} + +void TerminalWidget::paintPreedit(QPainter &p) const +{ + auto cursor = m_surface->cursor(); + if (!m_preEditString.isEmpty()) { + QRectF rect = QRectF(gridToGlobal(cursor.position), + gridToGlobal({cursor.position.x(), cursor.position.y()}, true, true)); + + p.fillRect(rect, QColor::fromRgb(0, 0, 0)); + p.setPen(Qt::white); + p.drawText(rect, m_preEditString); + } +} + +void TerminalWidget::paintCells(QPainter &p, QPaintEvent *event) const +{ + QFont f = m_font; + + const int scrollOffset = verticalScrollBar()->value(); + + const int maxRow = m_surface->fullSize().height(); + const int startRow = qFloor((qreal) event->rect().y() / m_cellSize.height()) + scrollOffset; + const int endRow = qMin(maxRow, + qCeil((event->rect().y() + event->rect().height()) / m_cellSize.height()) + + scrollOffset); + + for (int cellY = startRow; cellY < endRow; ++cellY) { + for (int cellX = 0; cellX < m_surface->liveSize().width();) { + const auto cell = m_surface->fetchCell(cellX, cellY); + + QRectF cellRect(gridToGlobal({cellX, cellY}), + QSizeF{m_cellSize.width() * cell.width, m_cellSize.height()}); + + int numCells = paintCell(p, cellRect, {cellX, cellY}, cell, f); + + cellX += numCells; + } + } +} + +void TerminalWidget::paintSelection(QPainter &p) const +{ + if (!m_selection) + return; + + const QPoint start = m_surface->posToGrid(m_selection->start); + const QPoint end = m_surface->posToGrid(m_selection->end); + + const QColor selectionColor = TerminalSettings::instance().selectionColor.value(); + const QSize liveSize = m_surface->liveSize(); + + if (start.y() != end.y()) { + QRectF firstLineRect = QRectF(gridToGlobal(start), + gridToGlobal({liveSize.width(), start.y()}, true)); + + p.fillRect(firstLineRect, selectionColor); + + if (end.y() > start.y() + 1) { + QRectF middleRect = QRectF(gridToGlobal({0, (start.y() + 1)}), + gridToGlobal({liveSize.width(), end.y() - 1}, true)); + p.fillRect(middleRect, selectionColor); + } + + QRectF lastLineRect = QRectF(gridToGlobal({0, end.y()}), gridToGlobal(end, true)); + p.fillRect(lastLineRect, selectionColor); + } else { + QRectF rect = QRectF(gridToGlobal(start), gridToGlobal(end, true)); + p.fillRect(rect, selectionColor); + } +} + +void TerminalWidget::paintDebugSelection(QPainter &p, const Selection &selection) const +{ + auto s = globalToViewport(gridToGlobal(m_surface->posToGrid(selection.start)).toPoint()); + const auto e = globalToViewport( + gridToGlobal(m_surface->posToGrid(selection.end), true).toPoint()); + + p.setPen(QPen(Qt::green, 1, Qt::DashLine)); + p.drawLine(s.x(), 0, s.x(), height()); + p.drawLine(0, s.y(), width(), s.y()); + + p.setPen(QPen(Qt::red, 1, Qt::DashLine)); + + p.drawLine(e.x(), 0, e.x(), height()); + p.drawLine(0, e.y(), width(), e.y()); } void TerminalWidget::paintEvent(QPaintEvent *event) { + QElapsedTimer t; + t.start(); event->accept(); QPainter p(viewport()); - p.setCompositionMode(QPainter::CompositionMode_Source); + p.save(); - VTermColor defaultBg; - if (!m_altscreen) { - VTermColor defaultFg; - vterm_state_get_default_colors(vterm_obtain_state(m_vterm.get()), &defaultFg, &defaultBg); - // We want to compare the cell bg against this later and cells don't - // set DEFAULT_BG - defaultBg.type = VTERM_COLOR_RGB; - } else { - // This is a slightly better guess when in an altscreen - const VTermScreenCell *cell = fetchCell(0, 0); - defaultBg = cell->bg; - } + const QColor defaultBgColor = m_surface->defaultBgColor(); - p.fillRect(event->rect(), Internal::toQColor(defaultBg)); + if (paintLog().isDebugEnabled()) + p.fillRect(event->rect(), QColor::fromRgb(rand() % 60, rand() % 60, rand() % 60)); + else + p.fillRect(event->rect(), defaultBgColor); - unsigned long off = m_scrollback->size() - m_scrollback->offset(); - - // transform painter according to scroll offsets - QPointF offset{0, -(off * m_lineSpacing)}; + int scrollOffset = verticalScrollBar()->value(); + int offset = -(scrollOffset * m_cellSize.height()); qreal margin = topMargin(); - qreal y = offset.y() + margin; - size_t row = qFloor((offset.y() * -1) / m_lineSpacing); - y += row * m_lineSpacing; - for (; row < m_scrollback->size(); row++) { - if (y >= 0 && y < viewport()->height()) { - const Internal::Scrollback::Line &line = m_scrollback->line((m_scrollback->size() - 1) - - row); + p.translate(QPointF{0.0, offset + margin}); - QList selections; + paintSelection(p); + paintCells(p, event); + paintCursor(p); + paintPreedit(p); - if (m_selection) { - const std::optional range - = selectionToFormatRange(m_selection.value(), - line.layout(m_layoutVersion, m_font, m_lineSpacing), - row); - if (range) { - selections.append(range.value()); - } - } - line.layout(m_layoutVersion, m_font, m_lineSpacing).draw(&p, {0.0, y}, selections); - } + p.restore(); - y += m_lineSpacing; + p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), topMargin()}}, defaultBgColor); + + if (selectionLog().isDebugEnabled()) { + if (m_selection) + paintDebugSelection(p, *m_selection); + if (m_linkSelection) + paintDebugSelection(p, *m_linkSelection); } - // Draw the live part - if (y < m_vtermSize.height() * m_lineSpacing) { - QList selections; - - if (m_selection) { - const std::optional range - = selectionToFormatRange(m_selection.value(), m_textLayout, row); - if (range) { - selections.append(range.value()); - } - } - - m_textLayout.draw(&p, {0.0, y}, selections); - - if (m_cursor.visible && m_preEditString.isEmpty()) { - p.setPen(QColor::fromRgb(0xFF, 0xFF, 0xFF)); - if (m_textLayout.lineCount() > m_cursor.row) { - QTextLine cursorLine = m_textLayout.lineAt(m_cursor.row); - if (cursorLine.isValid()) { - QFontMetricsF fm(m_font); - const QString text = m_textLayout.text(); - const QList asUcs4 = text.toUcs4(); - const int textStart = cursorLine.textStart(); - const int cPos = textStart + m_cursor.col; - if (cPos >= 0 && cPos < asUcs4.size()) { - const unsigned int ch = asUcs4.at(cPos); - const qreal br = fm.horizontalAdvance(QString::fromUcs4(&ch, 1)); - const qreal xCursor = cursorLine.cursorToX(cPos); - const double yCursor = cursorLine.y() + y; - const QRectF cursorRect - = QRectF{xCursor, yCursor + 1, br, m_lineSpacing - 2}; - if (hasFocus()) { - QPainter::CompositionMode oldMode = p.compositionMode(); - p.setCompositionMode(QPainter::RasterOp_NotDestination); - p.fillRect(cursorRect, p.pen().brush()); - p.setCompositionMode(oldMode); - } else { - p.drawRect(cursorRect); - } - } - } - } - } - - if (!m_preEditString.isEmpty()) { - QTextLine cursorLine = m_textLayout.lineAt(m_cursor.row); - if (cursorLine.isValid()) { - int pos = cursorLine.textStart() + m_cursor.col; - QPointF displayPos = QPointF{cursorLine.cursorToX(pos), cursorLine.y() + y}; - - p.fillRect(QRectF{displayPos.toPoint(), m_cellSize}, QColor::fromRgb(0, 0, 0)); - p.setPen(Qt::white); - displayPos.setY(displayPos.y() + m_cellBaseline); - p.drawText(displayPos, m_preEditString); - } - } - } - - p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), margin}}, Internal::toQColor(defaultBg)); - - if (selectionLog().isDebugEnabled() && m_selection) { - const auto s = globalToViewport(m_selection->start); - const auto e = globalToViewport(m_selection->end); - - p.setPen(QPen(Qt::green, 1, Qt::DashLine)); - p.drawLine(s.x(), 0, s.x(), height()); - p.drawLine(0, s.y(), width(), s.y()); - - p.setPen(QPen(Qt::red, 1, Qt::DashLine)); - - p.drawLine(e.x(), 0, e.x(), height()); - p.drawLine(0, e.y(), width(), e.y()); + if (paintLog().isDebugEnabled()) { + QToolTip::showText(this->mapToGlobal(QPoint(width() - 200, 0)), + QString("Paint: %1ms").arg(t.elapsed())); } } @@ -739,69 +829,41 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) if (actionTriggered) { setSelection(std::nullopt); - viewport()->update(); + updateViewport(); return; } event->accept(); - bool keypad = event->modifiers() & Qt::KeypadModifier; - VTermModifier mod = Internal::qtModifierToVTerm(event->modifiers()); - VTermKey key = Internal::qtKeyToVTerm(Qt::Key(event->key()), keypad); - - if (key != VTERM_KEY_NONE) { - if (mod == VTERM_MOD_SHIFT && (key == VTERM_KEY_ESCAPE || key == VTERM_KEY_BACKSPACE)) - mod = VTERM_MOD_NONE; - - vterm_keyboard_key(m_vterm.get(), key, mod); - } else if (event->text().length() == 1) { - // This maps to delete word and is way to easy to mistakenly type - // if (event->key() == Qt::Key_Space && mod == VTERM_MOD_SHIFT) - // mod = VTERM_MOD_NONE; - - // Per https://github.com/justinmk/neovim/commit/317d5ca7b0f92ef42de989b3556ca9503f0a3bf6 - // libvterm prefers we send the full keycode rather than sending the - // ctrl modifier. This helps with ncurses applications which otherwise - // do not recognize ctrl+ and in the shell for getting common control characters - // like ctrl+i for tab or ctrl+j for newline. - - // Workaround for "ALT+SHIFT+/" (\ on german mac keyboards) - if (mod == (VTERM_MOD_SHIFT | VTERM_MOD_ALT) && event->key() == Qt::Key_Slash) { - mod = VTERM_MOD_NONE; - } - - vterm_keyboard_unichar(m_vterm.get(), event->text().toUcs4()[0], VTERM_MOD_NONE); - - setSelection(std::nullopt); - } else if (mod == VTERM_MOD_CTRL && event->key() >= Qt::Key_A && event->key() < Qt::Key_Z) { - vterm_keyboard_unichar(m_vterm.get(), 'a' + (event->key() - Qt::Key_A), mod); - } + m_surface->sendKey(event); } void TerminalWidget::applySizeChange() { - m_vtermSize = { + QSize newLiveSize = { qFloor((qreal) (viewport()->size().width()) / (qreal) m_cellSize.width()), - qFloor((qreal) (viewport()->size().height()) / m_lineSpacing), + qFloor((qreal) (viewport()->size().height()) / m_cellSize.height()), }; - if (m_vtermSize.height() <= 0) - m_vtermSize.setHeight(1); + if (newLiveSize.height() <= 0) + newLiveSize.setHeight(1); - if (m_vtermSize.width() <= 0) - m_vtermSize.setWidth(1); + if (newLiveSize.width() <= 0) + newLiveSize.setWidth(1); if (m_process) - m_process->ptyData().resize(m_vtermSize); + m_process->ptyData().resize(newLiveSize); - vterm_set_size(m_vterm.get(), m_vtermSize.height(), m_vtermSize.width()); + m_surface->resize(newLiveSize); flushVTerm(true); } void TerminalWidget::updateScrollBars() { - verticalScrollBar()->setRange(0, static_cast(m_scrollback->size())); + int scrollSize = m_surface->fullSize().height() - m_surface->liveSize().height(); + verticalScrollBar()->setRange(0, scrollSize); verticalScrollBar()->setValue(verticalScrollBar()->maximum()); + updateViewport(); } void TerminalWidget::resizeEvent(QResizeEvent *event) @@ -820,41 +882,32 @@ void TerminalWidget::resizeEvent(QResizeEvent *event) m_ignoreScroll = false; } -void TerminalWidget::invalidate(VTermRect rect) +QRect TerminalWidget::gridToViewport(QRect rect) const { - Q_UNUSED(rect); - createTextLayout(); + int offset = verticalScrollBar()->value(); + int startRow = rect.y() - offset; + int numRows = rect.height(); + int numCols = rect.width(); + + QRect r{qFloor(rect.x() * m_cellSize.width()), + qFloor(startRow * m_cellSize.height()), + qCeil(numCols * m_cellSize.width()), + qCeil(numRows * m_cellSize.height())}; + + r.translate(0, topMargin()); + + return r; +} + +void TerminalWidget::updateViewport() +{ viewport()->update(); } -int TerminalWidget::sb_pushline(int cols, const VTermScreenCell *cells) +void TerminalWidget::updateViewport(const QRect &rect) { - m_scrollback->emplace(cols, cells, vterm_obtain_state(m_vterm.get())); - - updateScrollBars(); - - return 1; -} - -int TerminalWidget::sb_popline(int cols, VTermScreenCell *cells) -{ - if (m_scrollback->size() == 0) - return 0; - - m_scrollback->popto(cols, cells); - - updateScrollBars(); - - return 1; -} - -int TerminalWidget::sb_clear() -{ - m_scrollback->clear(); - updateScrollBars(); - - return 1; + viewport()->update(rect); } void TerminalWidget::wheelEvent(QWheelEvent *event) @@ -864,11 +917,11 @@ void TerminalWidget::wheelEvent(QWheelEvent *event) void TerminalWidget::focusInEvent(QFocusEvent *) { - viewport()->update(); + updateViewport(); } void TerminalWidget::focusOutEvent(QFocusEvent *) { - viewport()->update(); + updateViewport(); } void TerminalWidget::inputMethodEvent(QInputMethodEvent *event) @@ -876,36 +929,47 @@ void TerminalWidget::inputMethodEvent(QInputMethodEvent *event) m_preEditString = event->preeditString(); if (event->commitString().isEmpty()) { - viewport()->update(); + updateViewport(); return; } - for (const unsigned int ch : event->commitString().toUcs4()) { - vterm_keyboard_unichar(m_vterm.get(), ch, VTERM_MOD_NONE); - } + m_surface->sendKey(event->commitString()); } void TerminalWidget::mousePressEvent(QMouseEvent *event) { - m_selectionStartPos = event->pos(); + m_activeMouseSelect.start = event->pos(); + + if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) { + if (m_linkSelection) { + if (m_linkSelection->filePath.scheme().toString().startsWith("http")) { + QDesktopServices::openUrl(m_linkSelection->filePath.toUrl()); + return; + } + Core::EditorManager::openEditorAt(Utils::Link(m_linkSelection->filePath)); + } + return; + } if (event->button() == Qt::LeftButton) { if (std::chrono::system_clock::now() - m_lastDoubleClick < 500ms) { m_selectLineMode = true; - m_selection->start.setX(0); - m_selection->end.setX(viewport()->width()); + m_selection->start = m_surface->gridToPos( + {0, m_surface->posToGrid(m_selection->start).y()}); + m_selection->end = m_surface->gridToPos( + {viewport()->width(), m_surface->posToGrid(m_selection->end).y()}); } else { m_selectLineMode = false; - QPoint pos = viewportToGlobal(event->pos()); + int pos = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos()))); setSelection(Selection{pos, pos}); } event->accept(); - viewport()->update(); + updateViewport(); } else if (event->button() == Qt::RightButton) { if (m_selection) { m_copyAction.trigger(); setSelection(std::nullopt); - viewport()->update(); + updateViewport(); } else { m_pasteAction.trigger(); } @@ -914,107 +978,119 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) void TerminalWidget::mouseMoveEvent(QMouseEvent *event) { if (m_selection && event->buttons() & Qt::LeftButton) { - const std::array oldGrid = {globalToGrid(m_selection->start), - globalToGrid(m_selection->end)}; + const auto old = m_selection; - QPoint start = viewportToGlobal(m_selectionStartPos); - QPoint newEnd = viewportToGlobal(event->pos()); + int start = m_surface->gridToPos(globalToGrid(viewportToGlobal(m_activeMouseSelect.start))); + int newEnd = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos()))); - const auto startInGrid = globalToGrid(start); - const auto endInGrid = globalToGrid(newEnd); - - if (startInGrid.y() > endInGrid.y()) + if (start > newEnd) { std::swap(start, newEnd); - else if (startInGrid.y() == endInGrid.y()) { - if (startInGrid.x() > endInGrid.x()) { - const auto s = start.x(); - start.setX(newEnd.x()); - newEnd.setX(s); - } - } - - if (start.y() > newEnd.y()) { - const auto s = start.y(); - start.setY(newEnd.y()); - newEnd.setY(s); - } - - if (m_selectLineMode) { - start.setX(0); - newEnd.setX(viewport()->width()); } m_selection->start = start; m_selection->end = newEnd; - const std::array newGrid = {globalToGrid(m_selection->start), - globalToGrid(m_selection->end)}; + if (old != *m_selection || selectionLog().isDebugEnabled()) + updateViewport(); + } else if (event->modifiers() == Qt::ControlModifier) { + checkLinkAt(event->pos()); + } else if (m_linkSelection) { + m_linkSelection.reset(); + updateViewport(); + } - if (newGrid != oldGrid || selectionLog().isDebugEnabled()) - viewport()->update(); + if (m_linkSelection) { + setCursor(Qt::PointingHandCursor); + } else { + setCursor(Qt::IBeamCursor); + } +} + +void TerminalWidget::checkLinkAt(const QPoint &pos) +{ + const TextAndOffsets hit = textAt(pos); + + if (hit.text.size() > 0) { + QString t = QString::fromUcs4(hit.text.c_str(), hit.text.size()); + if (t.startsWith("~/")) { + t = QDir::homePath() + t.mid(1); + } + + // Todo: Windows path support + const FilePath p = FilePath::fromString(t.trimmed()); + + if (!p.isEmpty() && (p.scheme().toString().startsWith("http") || p.exists())) { + const LinkSelection newSelection = LinkSelection{{hit.start, hit.end}, p}; + if (*m_linkSelection != newSelection) { + m_linkSelection = newSelection; + updateViewport(); + } + return; + } + } + + if (m_linkSelection) { + m_linkSelection.reset(); + updateViewport(); } } void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) { if (m_selection && event->button() == Qt::LeftButton) { - if ((m_selection->end - m_selection->start).manhattanLength() < 2) { + if (m_selection->end - m_selection->start == 0) { setSelection(std::nullopt); - viewport()->update(); + updateViewport(); } } } -void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) +TerminalWidget::TextAndOffsets TerminalWidget::textAt(const QPoint &pos) const { - std::u32string text = m_scrollback->currentText() + m_currentLiveText; - - const QPoint clickPos = viewportToGlobal(event->pos()); - const QPoint clickPosInGrid = globalToGrid(clickPos); - - std::u32string::size_type chIdx = (clickPosInGrid.x()) - + (clickPosInGrid.y()) * m_vtermSize.width(); - - if (chIdx >= text.length()) - return; + auto it = m_surface->iteratorAt(globalToGrid(viewportToGlobal(pos))); + auto itRev = m_surface->rIteratorAt(globalToGrid(viewportToGlobal(pos))); std::u32string whiteSpaces = U" \t\x00a0"; - const bool inverted = whiteSpaces.find(text[chIdx]) != std::u32string::npos; + const bool inverted = whiteSpaces.find(*it) != std::u32string::npos || *it == 0; - const std::u32string::size_type leftEnd = inverted - ? text.find_last_not_of(whiteSpaces, chIdx) + 1 - : text.find_last_of(whiteSpaces, chIdx) + 1; - std::u32string::size_type rightEnd = inverted ? text.find_first_not_of(whiteSpaces, chIdx) - : text.find_first_of(whiteSpaces, chIdx); - if (rightEnd == std::u32string::npos) - rightEnd = text.length(); + auto predicate = [inverted, whiteSpaces](const std::u32string::value_type &ch) { + if (inverted) + return ch != 0 && whiteSpaces.find(ch) == std::u32string::npos; + else + return ch == 0 || whiteSpaces.find(ch) != std::u32string::npos; + }; - const auto found = text.substr(leftEnd, rightEnd - leftEnd); + auto itRight = std::find_if(it, m_surface->end(), predicate); + auto itLeft = std::find_if(itRev, m_surface->rend(), predicate); - const QPoint selectionStart((leftEnd % m_vtermSize.width()) * m_cellSize.width() - + (m_cellSize.width() / 4), - (leftEnd / m_vtermSize.width()) * m_cellSize.height() - + (m_cellSize.height() / 4)); - const QPoint selectionEnd((rightEnd % m_vtermSize.width()) * m_cellSize.width(), - (rightEnd / m_vtermSize.width()) * m_cellSize.height() - + m_cellSize.height()); + std::u32string text; + std::copy(itLeft.base(), it, std::back_inserter(text)); + std::copy(it, itRight, std::back_inserter(text)); - setSelection(Selection{selectionStart, selectionEnd}); + return {(itLeft.base()).position(), itRight.position(), text}; +} + +void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + const auto hit = textAt(event->pos()); + + setSelection(Selection{hit.start, hit.end}); m_lastDoubleClick = std::chrono::system_clock::now(); - viewport()->update(); + updateViewport(); event->accept(); } void TerminalWidget::scrollContentsBy(int dx, int dy) { Q_UNUSED(dx); + Q_UNUSED(dy); if (m_ignoreScroll) return; - + /* if (m_altscreen) return; @@ -1024,7 +1100,9 @@ void TerminalWidget::scrollContentsBy(int dx, int dy) return; m_cursor.visible = (offset == 0); - viewport()->update(); + */ + + updateViewport(); } void TerminalWidget::showEvent(QShowEvent *event) @@ -1067,50 +1145,4 @@ bool TerminalWidget::event(QEvent *event) return QAbstractScrollArea::event(event); } -int TerminalWidget::setTerminalProperties(VTermProp prop, VTermValue *val) -{ - switch (prop) { - case VTERM_PROP_CURSORVISIBLE: - m_cursor.visible = val->boolean; - break; - case VTERM_PROP_CURSORBLINK: - qCDebug(terminalLog) << "Ignoring VTERM_PROP_CURSORBLINK" << val->boolean; - break; - case VTERM_PROP_CURSORSHAPE: - qCDebug(terminalLog) << "Ignoring VTERM_PROP_CURSORSHAPE" << val->number; - break; - case VTERM_PROP_ICONNAME: - //emit iconTextChanged(val->string); - break; - case VTERM_PROP_TITLE: - //emit titleChanged(val->string); - setWindowTitle(QString::fromUtf8(val->string.str, val->string.len)); - break; - case VTERM_PROP_ALTSCREEN: - m_altscreen = val->boolean; - setSelection(std::nullopt); - break; - case VTERM_PROP_MOUSE: - qCDebug(terminalLog) << "Ignoring VTERM_PROP_MOUSE" << val->number; - break; - case VTERM_PROP_REVERSE: - qCDebug(terminalLog) << "Ignoring VTERM_PROP_REVERSE" << val->boolean; - break; - case VTERM_N_PROPS: - break; - } - return 1; -} - -int TerminalWidget::movecursor(VTermPos pos, VTermPos oldpos, int visible) -{ - Q_UNUSED(oldpos); - viewport()->update(); - m_cursor.row = pos.row; - m_cursor.col = pos.col; - m_cursor.visible = visible; - - return 1; -} - } // namespace Terminal diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index bd64b2f4776..058e0e2cb38 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -3,7 +3,7 @@ #pragma once -#include "scrollback.h" +#include "terminalsurface.h" #include #include @@ -13,8 +13,6 @@ #include #include -#include - #include #include @@ -22,6 +20,7 @@ namespace Terminal { class TerminalWidget : public QAbstractScrollArea { + friend class CellIterator; Q_OBJECT public: TerminalWidget(QWidget *parent = nullptr, @@ -49,8 +48,23 @@ public: struct Selection { - QPoint start; - QPoint end; + int start; + int end; + + bool operator!=(const Selection &other) const + { + return start != other.start || end != other.end; + } + }; + + struct LinkSelection : public Selection + { + Utils::FilePath filePath; + + bool operator!=(const LinkSelection &other) const + { + return filePath != other.filePath || Selection::operator!=(other); + } }; QString shellName() const; @@ -80,7 +94,7 @@ protected: protected: void onReadyRead(bool forceFlush); - void setupVTerm(); + void setupSurface(); void setupFont(); void setupPty(); void setupColors(); @@ -88,23 +102,27 @@ protected: void writeToPty(const QByteArray &data); - void createTextLayout(); - - // Callbacks from vterm - void invalidate(VTermRect rect); - int sb_pushline(int cols, const VTermScreenCell *cells); - int sb_popline(int cols, VTermScreenCell *cells); - int sb_clear(); - int setTerminalProperties(VTermProp prop, VTermValue *val); - int movecursor(VTermPos pos, VTermPos oldpos, int visible); - - const VTermScreenCell *fetchCell(int x, int y) const; + int paintCell(QPainter &p, + const QRectF &cellRect, + QPoint gridPos, + const Internal::TerminalCell &cell, + QFont &f) const; + void paintCells(QPainter &painter, QPaintEvent *event) const; + void paintCursor(QPainter &painter) const; + void paintPreedit(QPainter &painter) const; + void paintSelection(QPainter &painter) const; + void paintDebugSelection(QPainter &painter, const Selection &selection) const; qreal topMargin() const; QPoint viewportToGlobal(QPoint p) const; QPoint globalToViewport(QPoint p) const; - QPoint globalToGrid(QPoint p) const; + QPoint globalToGrid(QPointF p) const; + QPointF gridToGlobal(QPoint p, bool bottom = false, bool right = false) const; + QRect gridToViewport(QRect rect) const; + + void updateViewport(); + void updateViewport(const QRect &rect); int textLineFromPixel(int y) const; std::optional textPosFromPoint(const QTextLayout &textLayout, QPoint p) const; @@ -112,6 +130,17 @@ protected: std::optional selectionToFormatRange( TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const; + void checkLinkAt(const QPoint &pos); + + struct TextAndOffsets + { + int start; + int end; + std::u32string text; + }; + + TextAndOffsets textAt(const QPoint &pos) const; + void applySizeChange(); void updateScrollBars(); @@ -122,38 +151,25 @@ protected: private: std::unique_ptr m_process; + std::unique_ptr m_surface; QString m_shellName; - std::unique_ptr m_vterm; - VTermScreen *m_vtermScreen; - QSize m_vtermSize; - QFont m_font; QSizeF m_cellSize; - qreal m_cellBaseline; - qreal m_lineSpacing; - bool m_altscreen{false}; bool m_ignoreScroll{false}; QString m_preEditString; std::optional m_selection; - QPoint m_selectionStartPos; - - std::unique_ptr m_scrollback; - - QTextLayout m_textLayout; + std::optional m_linkSelection; struct { - int row{0}; - int col{0}; - bool visible{false}; - } m_cursor; - - VTermScreenCallbacks m_vtermScreenCallbacks; + QPoint start; + QPoint end; + } m_activeMouseSelect; QAction m_copyAction; QAction m_pasteAction; @@ -165,8 +181,6 @@ private: QTimer m_flushDelayTimer; - int m_layoutVersion{0}; - std::array m_currentColors; Utils::Terminal::OpenTerminalParameters m_openParameters; @@ -174,8 +188,6 @@ private: std::chrono::system_clock::time_point m_lastFlush; std::chrono::system_clock::time_point m_lastDoubleClick; bool m_selectLineMode{false}; - - std::u32string m_currentLiveText; }; } // namespace Terminal diff --git a/src/plugins/terminal/tests/colors b/src/plugins/terminal/tests/colors new file mode 100755 index 00000000000..a1910d45cc7 --- /dev/null +++ b/src/plugins/terminal/tests/colors @@ -0,0 +1,112 @@ +#!/usr/bin/python3 +# Source: https://gist.github.com/lilydjwg/fdeaf79e921c2f413f44b6f613f6ad53 + +from functools import partial + + +def colors16(): + for bold in [0, 1]: + for i in range(30, 38): + for j in range(40, 48): + print(f'\x1b[{bold};{i};{j}m {bold};{i};{j} |\x1b[0m', end='') + print() + print() + + for bold in [0, 1]: + for i in range(90, 98): + for j in range(100, 108): + print(f'\x1b[{bold};{i};{j}m {bold};{i};{j} |\x1b[0m', end='') + print() + print() + + +def color1(c, n=0): + print(f'\x1b[{n};38;5;{c}m{c:4}\x1b[0m', end='') + + +def color1_sep(c): + if (c - 15) % 18 == 0: + print() + + +def color2(c): + print(f'\x1b[48;5;{c}m \x1b[0m', end='') + + +def color2_sep(c): + if (c - 15) % 36 == 0: + print() + elif (c - 15) % 6 == 0: + print(' ', end='') + + +def colors256(color, sepfunc): + for i in range(0, 8): + color(i) + print() + for i in range(8, 16): + color(i) + print('\n') + + for i in range(16, 232): + color(i) + sepfunc(i) + print() + + for i in range(232, 256): + color(i) + print('\n') + + +def colors_gradient(): + s = '/\\' * 40 + for col in range(0, 77): + r = 255 - col * 255 // 76 + g = col * 510 // 76 + b = col * 255 // 76 + if g > 255: + g = 510 - g + print( + f'\x1b[48;2;{r};{g};{b}m\x1b[38;2;{255-r};{255-g};{255-b}m{s[col]}\x1b[0m', end='') + print() + + +def other_attributes(): + for i in range(0, 10): + print(f' \x1b[{i}mSGR {i:2}\x1b[m', end=' ') + print(' \x1b[53mSGR 53\x1b[m', end=' ') # overline + print('\n') + # https://askubuntu.com/a/985386/235132 + for i in range(1, 6): + print(f' \x1b[4:{i}mSGR 4:{i}\x1b[m', end=' ') + print(' \x1b[21mSGR 21\x1b[m', end=' ') + + print( + ' \x1b[4:3m\x1b[58;2;135;0;255mtruecolor underline\x1b[59m\x1b[4:0m', end=' ') + print(' \x1b]8;;https://askubuntu.com/a/985386/235132\x1b\\hyperlink\x1b]8;;\x1b\\') + + +if __name__ == '__main__': + print('basic 16 colors, foreground & background:\n') + colors16() + + print('256 colors:\n') + colors256(color1, color1_sep) + + print('256 colors, bold:\n') + colors256(partial(color1, n=1), color1_sep) + + print('256 colors, dim:\n') + colors256(partial(color1, n=2), color1_sep) + + print('256 colors, bold dim:\n') + colors256(partial(color1, n='1;2'), color1_sep) + + print('256 colors, solid background:\n') + colors256(color2, color2_sep) + + print('true colors gradient:\n') + colors_gradient() + + print('other attributes:\n') + other_attributes() From e38b817fc0c4f48b8f0cf908c660d8402a4bd7a0 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Feb 2023 17:37:59 +0100 Subject: [PATCH 0174/1447] ProjectExplorer: Split Session and ProjectManager files Still a lot of cross-referencing in the implementations, currently faciliated by a separate session_p.h that is meant to go away again. Change-Id: I6e32a62e02f60e790e54637de5de945bfaca36f6 Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/CMakeLists.txt | 4 +- .../projectexplorer/projectexplorer.qbs | 4 +- .../projectexplorer/projectmanager.cpp | 931 ++++++++++++++++++ src/plugins/projectexplorer/session.cpp | 929 +---------------- src/plugins/projectexplorer/session.h | 3 +- src/plugins/projectexplorer/session_p.h | 38 + 6 files changed, 981 insertions(+), 928 deletions(-) create mode 100644 src/plugins/projectexplorer/projectmanager.cpp create mode 100644 src/plugins/projectexplorer/session_p.h diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 518d2842c8b..deacbc57c56 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -140,7 +140,7 @@ add_qtc_plugin(ProjectExplorer projectfilewizardextension.cpp projectfilewizardextension.h projectimporter.cpp projectimporter.h projectmacro.cpp projectmacro.h - projectmanager.h + projectmanager.cpp projectmanager.h projectmodels.cpp projectmodels.h projectnodes.cpp projectnodes.h projectpanelfactory.cpp projectpanelfactory.h @@ -158,7 +158,7 @@ add_qtc_plugin(ProjectExplorer runsettingspropertiespage.cpp runsettingspropertiespage.h sanitizerparser.cpp sanitizerparser.h selectablefilesmodel.cpp selectablefilesmodel.h - session.cpp session.h + session.cpp session.h session_p.h sessiondialog.cpp sessiondialog.h sessionmodel.cpp sessionmodel.h sessionview.cpp sessionview.h diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index e65cc1bdc3f..665f28e14e7 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -116,7 +116,7 @@ Project { "projectfilewizardextension.cpp", "projectfilewizardextension.h", "projectimporter.cpp", "projectimporter.h", "projectmacro.cpp", "projectmacro.h", - "projectmanager.h", + "projectexplorer.cpp", "projectmanager.h" "projectmodels.cpp", "projectmodels.h", "projectnodes.cpp", "projectnodes.h", "projectpanelfactory.cpp", "projectpanelfactory.h", @@ -134,7 +134,7 @@ Project { "runsettingspropertiespage.cpp", "runsettingspropertiespage.h", "sanitizerparser.cpp", "sanitizerparser.h", "selectablefilesmodel.cpp", "selectablefilesmodel.h", - "session.cpp", "session.h", + "session.cpp", "session.h", "session_p.h", "sessionmodel.cpp", "sessionmodel.h", "sessionview.cpp", "sessionview.h", "sessiondialog.cpp", "sessiondialog.h", diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp new file mode 100644 index 00000000000..09f6ad2cf41 --- /dev/null +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -0,0 +1,931 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "projectmanager.h" + +#include "session_p.h" +#include "session.h" + +#include "buildconfiguration.h" +#include "editorconfiguration.h" +#include "project.h" +#include "projectexplorer.h" +#include "projectexplorerconstants.h" +#include "projectexplorertr.h" +#include "projectmanager.h" +#include "projectnodes.h" +#include "target.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef WITH_TESTS +#include +#include +#include +#endif + +using namespace Core; +using namespace Utils; +using namespace ProjectExplorer::Internal; + +namespace ProjectExplorer { + +const char DEFAULT_SESSION[] = "default"; + +class ProjectManagerPrivate +{ +public: + void restoreDependencies(const PersistentSettingsReader &reader); + void restoreStartupProject(const PersistentSettingsReader &reader); + void restoreProjects(const FilePaths &fileList); + void askUserAboutFailedProjects(); + + bool recursiveDependencyCheck(const FilePath &newDep, const FilePath &checkDep) const; + FilePaths dependencies(const FilePath &proName) const; + FilePaths dependenciesOrder() const; + void dependencies(const FilePath &proName, FilePaths &result) const; + + static QString windowTitleAddition(const FilePath &filePath); + static QString sessionTitle(const FilePath &filePath); + + bool hasProjects() const { return !m_projects.isEmpty(); } + + bool m_casadeSetActive = false; + + Project *m_startupProject = nullptr; + QList m_projects; + FilePaths m_failedProjects; + QMap m_depMap; + +private: + static QString locationInProject(const FilePath &filePath); +}; + +static ProjectManager *m_instance = nullptr; +static ProjectManagerPrivate *d = nullptr; + +static QString projectFolderId(Project *pro) +{ + return pro->projectFilePath().toString(); +} + +const int PROJECT_SORT_VALUE = 100; + +ProjectManager::ProjectManager() +{ + m_instance = this; + d = new ProjectManagerPrivate; + + connect(EditorManager::instance(), &EditorManager::editorCreated, + this, &ProjectManager::configureEditor); + connect(this, &ProjectManager::projectAdded, + EditorManager::instance(), &EditorManager::updateWindowTitles); + connect(this, &ProjectManager::projectRemoved, + EditorManager::instance(), &EditorManager::updateWindowTitles); + connect(this, &ProjectManager::projectDisplayNameChanged, + EditorManager::instance(), &EditorManager::updateWindowTitles); + + EditorManager::setWindowTitleAdditionHandler(&ProjectManagerPrivate::windowTitleAddition); + EditorManager::setSessionTitleHandler(&ProjectManagerPrivate::sessionTitle); +} + +ProjectManager::~ProjectManager() +{ + EditorManager::setWindowTitleAdditionHandler({}); + EditorManager::setSessionTitleHandler({}); + delete d; + d = nullptr; +} + +ProjectManager *ProjectManager::instance() +{ + return m_instance; +} + +bool ProjectManagerPrivate::recursiveDependencyCheck(const FilePath &newDep, + const FilePath &checkDep) const +{ + if (newDep == checkDep) + return false; + + const FilePaths depList = m_depMap.value(checkDep); + for (const FilePath &dependency : depList) { + if (!recursiveDependencyCheck(newDep, dependency)) + return false; + } + + return true; +} + +/* + * The dependency management exposes an interface based on projects, but + * is internally purely string based. This is suboptimal. Probably it would be + * nicer to map the filenames to projects on load and only map it back to + * filenames when saving. + */ + +QList ProjectManager::dependencies(const Project *project) +{ + const FilePath proName = project->projectFilePath(); + const FilePaths proDeps = d->m_depMap.value(proName); + + QList projects; + for (const FilePath &dep : proDeps) { + Project *pro = Utils::findOrDefault(d->m_projects, [&dep](Project *p) { + return p->projectFilePath() == dep; + }); + if (pro) + projects += pro; + } + + return projects; +} + +bool ProjectManager::hasDependency(const Project *project, const Project *depProject) +{ + const FilePath proName = project->projectFilePath(); + const FilePath depName = depProject->projectFilePath(); + + const FilePaths proDeps = d->m_depMap.value(proName); + return proDeps.contains(depName); +} + +bool ProjectManager::canAddDependency(const Project *project, const Project *depProject) +{ + const FilePath newDep = project->projectFilePath(); + const FilePath checkDep = depProject->projectFilePath(); + + return d->recursiveDependencyCheck(newDep, checkDep); +} + +bool ProjectManager::addDependency(Project *project, Project *depProject) +{ + const FilePath proName = project->projectFilePath(); + const FilePath depName = depProject->projectFilePath(); + + // check if this dependency is valid + if (!d->recursiveDependencyCheck(proName, depName)) + return false; + + FilePaths proDeps = d->m_depMap.value(proName); + if (!proDeps.contains(depName)) { + proDeps.append(depName); + d->m_depMap[proName] = proDeps; + } + emit m_instance->dependencyChanged(project, depProject); + + return true; +} + +void ProjectManager::removeDependency(Project *project, Project *depProject) +{ + const FilePath proName = project->projectFilePath(); + const FilePath depName = depProject->projectFilePath(); + + FilePaths proDeps = d->m_depMap.value(proName); + proDeps.removeAll(depName); + if (proDeps.isEmpty()) + d->m_depMap.remove(proName); + else + d->m_depMap[proName] = proDeps; + emit m_instance->dependencyChanged(project, depProject); +} + +bool ProjectManager::isProjectConfigurationCascading() +{ + return d->m_casadeSetActive; +} + +void ProjectManager::setProjectConfigurationCascading(bool b) +{ + d->m_casadeSetActive = b; + SessionManager::markSessionFileDirty(); +} + +void ProjectManager::setStartupProject(Project *startupProject) +{ + QTC_ASSERT((!startupProject && d->m_projects.isEmpty()) + || (startupProject && d->m_projects.contains(startupProject)), return); + + if (d->m_startupProject == startupProject) + return; + + d->m_startupProject = startupProject; + if (d->m_startupProject && d->m_startupProject->needsConfiguration()) { + ModeManager::activateMode(Constants::MODE_SESSION); + ModeManager::setFocusToCurrentMode(); + } + FolderNavigationWidgetFactory::setFallbackSyncFilePath( + startupProject ? startupProject->projectFilePath().parentDir() : FilePath()); + emit m_instance->startupProjectChanged(startupProject); +} + +Project *ProjectManager::startupProject() +{ + return d->m_startupProject; +} + +Target *ProjectManager::startupTarget() +{ + return d->m_startupProject ? d->m_startupProject->activeTarget() : nullptr; +} + +BuildSystem *ProjectManager::startupBuildSystem() +{ + Target *t = startupTarget(); + return t ? t->buildSystem() : nullptr; +} + +/*! + * Returns the RunConfiguration of the currently active target + * of the startup project, if such exists, or \c nullptr otherwise. + */ + + +RunConfiguration *ProjectManager::startupRunConfiguration() +{ + Target *t = startupTarget(); + return t ? t->activeRunConfiguration() : nullptr; +} + +void ProjectManager::addProject(Project *pro) +{ + QTC_ASSERT(pro, return); + QTC_CHECK(!pro->displayName().isEmpty()); + QTC_CHECK(pro->id().isValid()); + + sb_d->m_virginSession = false; + QTC_ASSERT(!d->m_projects.contains(pro), return); + + d->m_projects.append(pro); + + connect(pro, &Project::displayNameChanged, + m_instance, [pro]() { emit m_instance->projectDisplayNameChanged(pro); }); + + emit m_instance->projectAdded(pro); + const auto updateFolderNavigation = [pro] { + // destructing projects might trigger changes, so check if the project is actually there + if (QTC_GUARD(d->m_projects.contains(pro))) { + const QIcon icon = pro->rootProjectNode() ? pro->rootProjectNode()->icon() : QIcon(); + FolderNavigationWidgetFactory::insertRootDirectory({projectFolderId(pro), + PROJECT_SORT_VALUE, + pro->displayName(), + pro->projectFilePath().parentDir(), + icon}); + } + }; + updateFolderNavigation(); + configureEditors(pro); + connect(pro, &Project::fileListChanged, m_instance, [pro, updateFolderNavigation]() { + configureEditors(pro); + updateFolderNavigation(); // update icon + }); + connect(pro, &Project::displayNameChanged, m_instance, updateFolderNavigation); + + if (!startupProject()) + setStartupProject(pro); +} + +void ProjectManager::removeProject(Project *project) +{ + sb_d->m_virginSession = false; + QTC_ASSERT(project, return); + removeProjects({project}); +} + +bool ProjectManager::save() +{ + emit SessionManager::instance()->aboutToSaveSession(); + + const FilePath filePath = SessionManager::sessionNameToFileName(sb_d->m_sessionName); + QVariantMap data; + + // See the explanation at loadSession() for how we handle the implicit default session. + if (SessionManager::isDefaultVirgin()) { + if (filePath.exists()) { + PersistentSettingsReader reader; + if (!reader.load(filePath)) { + QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"), + Tr::tr("Could not save session %1").arg(filePath.toUserOutput())); + return false; + } + data = reader.restoreValues(); + } + } else { + // save the startup project + if (d->m_startupProject) + data.insert("StartupProject", d->m_startupProject->projectFilePath().toSettings()); + + const QColor c = StyleHelper::requestedBaseColor(); + if (c.isValid()) { + QString tmp = QString::fromLatin1("#%1%2%3") + .arg(c.red(), 2, 16, QLatin1Char('0')) + .arg(c.green(), 2, 16, QLatin1Char('0')) + .arg(c.blue(), 2, 16, QLatin1Char('0')); + data.insert(QLatin1String("Color"), tmp); + } + + FilePaths projectFiles = Utils::transform(projects(), &Project::projectFilePath); + // Restore information on projects that failed to load: + // don't read projects to the list, which the user loaded + for (const FilePath &failed : std::as_const(d->m_failedProjects)) { + if (!projectFiles.contains(failed)) + projectFiles << failed; + } + + data.insert("ProjectList", Utils::transform(projectFiles, + &FilePath::toString)); + data.insert("CascadeSetActive", d->m_casadeSetActive); + + QVariantMap depMap; + auto i = d->m_depMap.constBegin(); + while (i != d->m_depMap.constEnd()) { + QString key = i.key().toString(); + QStringList values; + const FilePaths valueList = i.value(); + for (const FilePath &value : valueList) + values << value.toString(); + depMap.insert(key, values); + ++i; + } + data.insert(QLatin1String("ProjectDependencies"), QVariant(depMap)); + data.insert(QLatin1String("EditorSettings"), EditorManager::saveState().toBase64()); + } + + const auto end = sb_d->m_values.constEnd(); + QStringList keys; + for (auto it = sb_d->m_values.constBegin(); it != end; ++it) { + data.insert(QLatin1String("value-") + it.key(), it.value()); + keys << it.key(); + } + data.insert(QLatin1String("valueKeys"), keys); + + if (!sb_d->m_writer || sb_d->m_writer->fileName() != filePath) { + delete sb_d->m_writer; + sb_d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession"); + } + const bool result = sb_d->m_writer->save(data, ICore::dialogParent()); + if (result) { + if (!SessionManager::isDefaultVirgin()) + sb_d->m_sessionDateTimes.insert(SessionManager::activeSession(), QDateTime::currentDateTime()); + } else { + QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"), + Tr::tr("Could not save session to file %1").arg(sb_d->m_writer->fileName().toUserOutput())); + } + + return result; +} + +/*! + Closes all projects + */ +void ProjectManager::closeAllProjects() +{ + removeProjects(projects()); +} + +const QList ProjectManager::projects() +{ + return d->m_projects; +} + +bool ProjectManager::hasProjects() +{ + return d->hasProjects(); +} + +bool ProjectManager::hasProject(Project *p) +{ + return d->m_projects.contains(p); +} + +FilePaths ProjectManagerPrivate::dependencies(const FilePath &proName) const +{ + FilePaths result; + dependencies(proName, result); + return result; +} + +void ProjectManagerPrivate::dependencies(const FilePath &proName, FilePaths &result) const +{ + const FilePaths depends = m_depMap.value(proName); + + for (const FilePath &dep : depends) + dependencies(dep, result); + + if (!result.contains(proName)) + result.append(proName); +} + +QString ProjectManagerPrivate::sessionTitle(const FilePath &filePath) +{ + if (SessionManager::isDefaultSession(sb_d->m_sessionName)) { + if (filePath.isEmpty()) { + // use single project's name if there is only one loaded. + const QList projects = ProjectManager::projects(); + if (projects.size() == 1) + return projects.first()->displayName(); + } + } else { + QString sessionName = sb_d->m_sessionName; + if (sessionName.isEmpty()) + sessionName = Tr::tr("Untitled"); + return sessionName; + } + return QString(); +} + +QString ProjectManagerPrivate::locationInProject(const FilePath &filePath) +{ + const Project *project = ProjectManager::projectForFile(filePath); + if (!project) + return QString(); + + const FilePath parentDir = filePath.parentDir(); + if (parentDir == project->projectDirectory()) + return "@ " + project->displayName(); + + if (filePath.isChildOf(project->projectDirectory())) { + const FilePath dirInProject = parentDir.relativeChildPath(project->projectDirectory()); + return "(" + dirInProject.toUserOutput() + " @ " + project->displayName() + ")"; + } + + // For a file that is "outside" the project it belongs to, we display its + // dir's full path because it is easier to read than a series of "../../.". + // Example: /home/hugo/GenericProject/App.files lists /home/hugo/lib/Bar.cpp + return "(" + parentDir.toUserOutput() + " @ " + project->displayName() + ")"; +} + +QString ProjectManagerPrivate::windowTitleAddition(const FilePath &filePath) +{ + return filePath.isEmpty() ? QString() : locationInProject(filePath); +} + +FilePaths ProjectManagerPrivate::dependenciesOrder() const +{ + QList> unordered; + FilePaths ordered; + + // copy the map to a temporary list + for (const Project *pro : m_projects) { + const FilePath proName = pro->projectFilePath(); + const FilePaths depList = filtered(m_depMap.value(proName), + [this](const FilePath &proPath) { + return contains(m_projects, [proPath](const Project *p) { + return p->projectFilePath() == proPath; + }); + }); + unordered.push_back({proName, depList}); + } + + while (!unordered.isEmpty()) { + for (int i = (unordered.count() - 1); i >= 0; --i) { + if (unordered.at(i).second.isEmpty()) { + ordered << unordered.at(i).first; + unordered.removeAt(i); + } + } + + // remove the handled projects from the dependency lists + // of the remaining unordered projects + for (int i = 0; i < unordered.count(); ++i) { + for (const FilePath &pro : std::as_const(ordered)) { + FilePaths depList = unordered.at(i).second; + depList.removeAll(pro); + unordered[i].second = depList; + } + } + } + + return ordered; +} + +QList ProjectManager::projectOrder(const Project *project) +{ + QList result; + + FilePaths pros; + if (project) + pros = d->dependencies(project->projectFilePath()); + else + pros = d->dependenciesOrder(); + + for (const FilePath &proFile : std::as_const(pros)) { + for (Project *pro : projects()) { + if (pro->projectFilePath() == proFile) { + result << pro; + break; + } + } + } + + return result; +} + +Project *ProjectManager::projectForFile(const FilePath &fileName) +{ + if (Project * const project = Utils::findOrDefault(ProjectManager::projects(), + [&fileName](const Project *p) { return p->isKnownFile(fileName); })) { + return project; + } + return Utils::findOrDefault(ProjectManager::projects(), + [&fileName](const Project *p) { + for (const Target * const target : p->targets()) { + for (const BuildConfiguration * const bc : target->buildConfigurations()) { + if (fileName.isChildOf(bc->buildDirectory())) + return false; + } + } + return fileName.isChildOf(p->projectDirectory()); + }); +} + +Project *ProjectManager::projectWithProjectFilePath(const FilePath &filePath) +{ + return Utils::findOrDefault(ProjectManager::projects(), + [&filePath](const Project *p) { return p->projectFilePath() == filePath; }); +} + +void ProjectManager::configureEditor(IEditor *editor, const QString &fileName) +{ + if (auto textEditor = qobject_cast(editor)) { + Project *project = projectForFile(Utils::FilePath::fromString(fileName)); + // Global settings are the default. + if (project) + project->editorConfiguration()->configureEditor(textEditor); + } +} + +void ProjectManager::configureEditors(Project *project) +{ + const QList documents = DocumentModel::openedDocuments(); + for (IDocument *document : documents) { + if (project->isKnownFile(document->filePath())) { + const QList editors = DocumentModel::editorsForDocument(document); + for (IEditor *editor : editors) { + if (auto textEditor = qobject_cast(editor)) { + project->editorConfiguration()->configureEditor(textEditor); + } + } + } + } +} + +void ProjectManager::removeProjects(const QList &remove) +{ + for (Project *pro : remove) + emit m_instance->aboutToRemoveProject(pro); + + bool changeStartupProject = false; + + // Delete projects + for (Project *pro : remove) { + pro->saveSettings(); + pro->markAsShuttingDown(); + + // Remove the project node: + d->m_projects.removeOne(pro); + + if (pro == d->m_startupProject) + changeStartupProject = true; + + FolderNavigationWidgetFactory::removeRootDirectory(projectFolderId(pro)); + disconnect(pro, nullptr, m_instance, nullptr); + emit m_instance->projectRemoved(pro); + } + + if (changeStartupProject) + setStartupProject(hasProjects() ? projects().first() : nullptr); + + qDeleteAll(remove); +} + +void ProjectManagerPrivate::restoreDependencies(const PersistentSettingsReader &reader) +{ + QMap depMap = reader.restoreValue(QLatin1String("ProjectDependencies")).toMap(); + auto i = depMap.constBegin(); + while (i != depMap.constEnd()) { + const QString &key = i.key(); + FilePaths values; + const QStringList valueList = i.value().toStringList(); + for (const QString &value : valueList) + values << FilePath::fromString(value); + m_depMap.insert(FilePath::fromString(key), values); + ++i; + } +} + +void ProjectManagerPrivate::askUserAboutFailedProjects() +{ + FilePaths failedProjects = m_failedProjects; + if (!failedProjects.isEmpty()) { + QString fileList = FilePath::formatFilePaths(failedProjects, "
"); + QMessageBox box(QMessageBox::Warning, + Tr::tr("Failed to restore project files"), + Tr::tr("Could not restore the following project files:
%1"). + arg(fileList)); + auto keepButton = new QPushButton(Tr::tr("Keep projects in Session"), &box); + auto removeButton = new QPushButton(Tr::tr("Remove projects from Session"), &box); + box.addButton(keepButton, QMessageBox::AcceptRole); + box.addButton(removeButton, QMessageBox::DestructiveRole); + + box.exec(); + + if (box.clickedButton() == removeButton) + m_failedProjects.clear(); + } +} + +void ProjectManagerPrivate::restoreStartupProject(const PersistentSettingsReader &reader) +{ + const FilePath startupProject = FilePath::fromSettings(reader.restoreValue("StartupProject")); + if (!startupProject.isEmpty()) { + for (Project *pro : std::as_const(m_projects)) { + if (pro->projectFilePath() == startupProject) { + m_instance->setStartupProject(pro); + break; + } + } + } + if (!m_startupProject) { + if (!startupProject.isEmpty()) + qWarning() << "Could not find startup project" << startupProject; + if (hasProjects()) + m_instance->setStartupProject(m_projects.first()); + } +} + +/*! + Loads a session, takes a session name (not filename). +*/ +void ProjectManagerPrivate::restoreProjects(const FilePaths &fileList) +{ + // indirectly adds projects to session + // Keep projects that failed to load in the session! + m_failedProjects = fileList; + if (!fileList.isEmpty()) { + ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProjects(fileList); + if (!result) + ProjectExplorerPlugin::showOpenProjectError(result); + const QList projects = result.projects(); + for (const Project *p : projects) + m_failedProjects.removeAll(p->projectFilePath()); + } +} + +/* + * ========== Notes on storing and loading the default session ========== + * The default session comes in two flavors: implicit and explicit. The implicit one, + * also referred to as "default virgin" in the code base, is the one that is active + * at start-up, if no session has been explicitly loaded due to command-line arguments + * or the "restore last session" setting in the session manager. + * The implicit default session silently turns into the explicit default session + * by loading a project or a file or changing settings in the Dependencies panel. The explicit + * default session can also be loaded by the user via the Welcome Screen. + * This mechanism somewhat complicates the handling of session-specific settings such as + * the ones in the task pane: Users expect that changes they make there become persistent, even + * when they are in the implicit default session. However, we can't just blindly store + * the implicit default session, because then we'd overwrite the project list of the explicit + * default session. Therefore, we use the following logic: + * - Upon start-up, if no session is to be explicitly loaded, we restore the parts of the + * explicit default session that are not related to projects, editors etc; the + * "general settings" of the session, so to speak. + * - When storing the implicit default session, we overwrite only these "general settings" + * of the explicit default session and keep the others as they are. + * - When switching from the implicit to the explicit default session, we keep the + * "general settings" and load everything else from the session file. + * This guarantees that user changes are properly transferred and nothing gets lost from + * either the implicit or the explicit default session. + * + */ +bool ProjectManager::loadSession(const QString &session, bool initial) +{ + const bool loadImplicitDefault = session.isEmpty(); + const bool switchFromImplicitToExplicitDefault = session == DEFAULT_SESSION + && sb_d->m_sessionName == DEFAULT_SESSION && !initial; + + // Do nothing if we have that session already loaded, + // exception if the session is the default virgin session + // we still want to be able to load the default session + if (session == sb_d->m_sessionName && !SessionManager::isDefaultVirgin()) + return true; + + if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) + return false; + + FilePaths fileList; + // Try loading the file + FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION : session); + PersistentSettingsReader reader; + if (fileName.exists()) { + if (!reader.load(fileName)) { + QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while restoring session"), + Tr::tr("Could not restore session %1").arg(fileName.toUserOutput())); + + return false; + } + + if (loadImplicitDefault) { + sb_d->restoreValues(reader); + emit SessionManager::instance()->sessionLoaded(DEFAULT_SESSION); + return true; + } + + fileList = FileUtils::toFilePathList(reader.restoreValue("ProjectList").toStringList()); + } else if (loadImplicitDefault) { + return true; + } + + sb_d->m_loadingSession = true; + + // Allow everyone to set something in the session and before saving + emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName); + + if (!save()) { + sb_d->m_loadingSession = false; + return false; + } + + // Clean up + if (!EditorManager::closeAllEditors()) { + sb_d->m_loadingSession = false; + return false; + } + + // find a list of projects to close later + const QList projectsToRemove = Utils::filtered(projects(), [&fileList](Project *p) { + return !fileList.contains(p->projectFilePath()); + }); + const QList openProjects = projects(); + const FilePaths projectPathsToLoad = Utils::filtered(fileList, [&openProjects](const FilePath &path) { + return !Utils::contains(openProjects, [&path](Project *p) { + return p->projectFilePath() == path; + }); + }); + d->m_failedProjects.clear(); + d->m_depMap.clear(); + if (!switchFromImplicitToExplicitDefault) + sb_d->m_values.clear(); + d->m_casadeSetActive = false; + + sb_d->m_sessionName = session; + delete sb_d->m_writer; + sb_d->m_writer = nullptr; + EditorManager::updateWindowTitles(); + + if (fileName.exists()) { + sb_d->m_virginSession = false; + + ProgressManager::addTask(sb_d->m_future.future(), Tr::tr("Loading Session"), + "ProjectExplorer.SessionFile.Load"); + + sb_d->m_future.setProgressRange(0, 1); + sb_d->m_future.setProgressValue(0); + + if (!switchFromImplicitToExplicitDefault) + sb_d->restoreValues(reader); + emit SessionManager::instance()->aboutToLoadSession(session); + + // retrieve all values before the following code could change them again + Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); + if (!modeId.isValid()) + modeId = Id(Core::Constants::MODE_EDIT); + + QColor c = QColor(reader.restoreValue(QLatin1String("Color")).toString()); + if (c.isValid()) + StyleHelper::setBaseColor(c); + + sb_d->m_future.setProgressRange(0, projectPathsToLoad.count() + 1/*initialization above*/ + 1/*editors*/); + sb_d->m_future.setProgressValue(1); + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + + d->restoreProjects(projectPathsToLoad); + sb_d->sessionLoadingProgress(); + d->restoreDependencies(reader); + d->restoreStartupProject(reader); + + removeProjects(projectsToRemove); // only remove old projects now that the startup project is set! + + sb_d->restoreEditors(reader); + + sb_d->m_future.reportFinished(); + sb_d->m_future = QFutureInterface(); + + // Fall back to Project mode if the startup project is unconfigured and + // use the mode saved in the session otherwise + if (d->m_startupProject && d->m_startupProject->needsConfiguration()) + modeId = Id(Constants::MODE_SESSION); + + ModeManager::activateMode(modeId); + ModeManager::setFocusToCurrentMode(); + } else { + removeProjects(projects()); + ModeManager::activateMode(Id(Core::Constants::MODE_EDIT)); + ModeManager::setFocusToCurrentMode(); + } + + d->m_casadeSetActive = reader.restoreValue(QLatin1String("CascadeSetActive"), false).toBool(); + sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); + + emit SessionManager::instance()->sessionLoaded(session); + + // Starts a event loop, better do that at the very end + d->askUserAboutFailedProjects(); + sb_d->m_loadingSession = false; + return true; +} + +void ProjectManager::reportProjectLoadingProgress() +{ + sb_d->sessionLoadingProgress(); +} + +FilePaths ProjectManager::projectsForSessionName(const QString &session) +{ + const FilePath fileName = SessionManager::sessionNameToFileName(session); + PersistentSettingsReader reader; + if (fileName.exists()) { + if (!reader.load(fileName)) { + qWarning() << "Could not restore session" << fileName.toUserOutput(); + return {}; + } + } + return transform(reader.restoreValue(QLatin1String("ProjectList")).toStringList(), + &FilePath::fromUserInput); +} + +#ifdef WITH_TESTS + +void ProjectExplorerPlugin::testSessionSwitch() +{ + QVERIFY(SessionManager::createSession("session1")); + QVERIFY(SessionManager::createSession("session2")); + QTemporaryFile cppFile("main.cpp"); + QVERIFY(cppFile.open()); + cppFile.close(); + QTemporaryFile projectFile1("XXXXXX.pro"); + QTemporaryFile projectFile2("XXXXXX.pro"); + struct SessionSpec { + SessionSpec(const QString &n, QTemporaryFile &f) : name(n), projectFile(f) {} + const QString name; + QTemporaryFile &projectFile; + }; + std::vector sessionSpecs{SessionSpec("session1", projectFile1), + SessionSpec("session2", projectFile2)}; + for (const SessionSpec &sessionSpec : sessionSpecs) { + static const QByteArray proFileContents + = "TEMPLATE = app\n" + "CONFIG -= qt\n" + "SOURCES = " + cppFile.fileName().toLocal8Bit(); + QVERIFY(sessionSpec.projectFile.open()); + sessionSpec.projectFile.write(proFileContents); + sessionSpec.projectFile.close(); + QVERIFY(ProjectManager::loadSession(sessionSpec.name)); + const OpenProjectResult openResult + = ProjectExplorerPlugin::openProject( + FilePath::fromString(sessionSpec.projectFile.fileName())); + if (openResult.errorMessage().contains("text/plain")) + QSKIP("This test requires the presence of QmakeProjectManager to be fully functional"); + QVERIFY(openResult); + QCOMPARE(openResult.projects().count(), 1); + QVERIFY(openResult.project()); + QCOMPARE(ProjectManager::projects().count(), 1); + } + for (int i = 0; i < 30; ++i) { + QVERIFY(ProjectManager::loadSession("session1")); + QCOMPARE(SessionManager::activeSession(), "session1"); + QCOMPARE(ProjectManager::projects().count(), 1); + QVERIFY(ProjectManager::loadSession("session2")); + QCOMPARE(SessionManager::activeSession(), "session2"); + QCOMPARE(ProjectManager::projects().count(), 1); + } + QVERIFY(ProjectManager::loadSession("session1")); + ProjectManager::closeAllProjects(); + QVERIFY(ProjectManager::loadSession("session2")); + ProjectManager::closeAllProjects(); + QVERIFY(SessionManager::deleteSession("session1")); + QVERIFY(SessionManager::deleteSession("session2")); +} + +#endif // WITH_TESTS + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 3efbb76f9b9..427cb8e4ca0 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -3,17 +3,11 @@ #include "session.h" -#include "buildconfiguration.h" -#include "deployconfiguration.h" -#include "editorconfiguration.h" -#include "kit.h" -#include "project.h" -#include "projectexplorer.h" +#include "session_p.h" + #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "projectmanager.h" -#include "projectnodes.h" -#include "target.h" #include #include @@ -36,15 +30,8 @@ #include #include -#ifdef WITH_TESTS -#include -#include -#include -#endif - using namespace Core; using namespace Utils; -using namespace ProjectExplorer::Internal; namespace ProjectExplorer { @@ -62,79 +49,12 @@ const char LAST_ACTIVE_TIMES_KEY[] = "LastActiveTimes"; This could be improved. */ -class SessionManagerPrivate -{ -public: - void restoreValues(const PersistentSettingsReader &reader); - void restoreEditors(const PersistentSettingsReader &reader); - void sessionLoadingProgress(); - - bool recursiveDependencyCheck(const FilePath &newDep, const FilePath &checkDep) const; - FilePaths dependencies(const FilePath &proName) const; - FilePaths dependenciesOrder() const; - void dependencies(const FilePath &proName, FilePaths &result) const; - - static QString windowTitleAddition(const FilePath &filePath); - static QString sessionTitle(const FilePath &filePath); - - QString m_sessionName = QLatin1String(DEFAULT_SESSION); - bool m_virginSession = true; - bool m_loadingSession = false; - - mutable QStringList m_sessions; - mutable QHash m_sessionDateTimes; - QHash m_lastActiveTimes; - - QMap m_values; - QFutureInterface m_future; - PersistentSettingsWriter *m_writer = nullptr; -}; - -class ProjectManagerPrivate -{ -public: - void restoreDependencies(const PersistentSettingsReader &reader); - void restoreStartupProject(const PersistentSettingsReader &reader); - void restoreProjects(const FilePaths &fileList); - void askUserAboutFailedProjects(); - - bool recursiveDependencyCheck(const FilePath &newDep, const FilePath &checkDep) const; - FilePaths dependencies(const FilePath &proName) const; - FilePaths dependenciesOrder() const; - void dependencies(const FilePath &proName, FilePaths &result) const; - - static QString windowTitleAddition(const FilePath &filePath); - static QString sessionTitle(const FilePath &filePath); - - bool hasProjects() const { return !m_projects.isEmpty(); } - - bool m_casadeSetActive = false; - - Project *m_startupProject = nullptr; - QList m_projects; - FilePaths m_failedProjects; - QMap m_depMap; - -private: - static QString locationInProject(const FilePath &filePath); -}; - -static ProjectManager *m_instance = nullptr; -static ProjectManagerPrivate *d = nullptr; - -static SessionManager *sb_instance = nullptr; -static SessionManagerPrivate *sb_d = nullptr; - -static QString projectFolderId(Project *pro) -{ - return pro->projectFilePath().toString(); -} - -const int PROJECT_SORT_VALUE = 100; +static SessionManager *m_instance = nullptr; +SessionManagerPrivate *sb_d = nullptr; SessionManager::SessionManager() { - sb_instance = this; + m_instance = this; sb_d = new SessionManagerPrivate; connect(ModeManager::instance(), &ModeManager::currentModeChanged, @@ -155,44 +75,13 @@ SessionManager::SessionManager() SessionManager::~SessionManager() { - emit sb_instance->aboutToUnloadSession(sb_d->m_sessionName); + emit m_instance->aboutToUnloadSession(sb_d->m_sessionName); delete sb_d->m_writer; delete sb_d; sb_d = nullptr; } -ProjectManager::ProjectManager() -{ - m_instance = this; - d = new ProjectManagerPrivate; - - connect(EditorManager::instance(), &EditorManager::editorCreated, - this, &ProjectManager::configureEditor); - connect(this, &ProjectManager::projectAdded, - EditorManager::instance(), &EditorManager::updateWindowTitles); - connect(this, &ProjectManager::projectRemoved, - EditorManager::instance(), &EditorManager::updateWindowTitles); - connect(this, &ProjectManager::projectDisplayNameChanged, - EditorManager::instance(), &EditorManager::updateWindowTitles); - - EditorManager::setWindowTitleAdditionHandler(&ProjectManagerPrivate::windowTitleAddition); - EditorManager::setSessionTitleHandler(&ProjectManagerPrivate::sessionTitle); -} - -ProjectManager::~ProjectManager() -{ - EditorManager::setWindowTitleAdditionHandler({}); - EditorManager::setSessionTitleHandler({}); - delete d; - d = nullptr; -} - SessionManager *SessionManager::instance() -{ - return sb_instance; -} - -ProjectManager *ProjectManager::instance() { return m_instance; } @@ -213,508 +102,11 @@ void SessionManager::saveActiveMode(Id mode) setValue(QLatin1String("ActiveMode"), mode.toString()); } -bool ProjectManagerPrivate::recursiveDependencyCheck(const FilePath &newDep, - const FilePath &checkDep) const -{ - if (newDep == checkDep) - return false; - - const FilePaths depList = m_depMap.value(checkDep); - for (const FilePath &dependency : depList) { - if (!recursiveDependencyCheck(newDep, dependency)) - return false; - } - - return true; -} - -/* - * The dependency management exposes an interface based on projects, but - * is internally purely string based. This is suboptimal. Probably it would be - * nicer to map the filenames to projects on load and only map it back to - * filenames when saving. - */ - -QList ProjectManager::dependencies(const Project *project) -{ - const FilePath proName = project->projectFilePath(); - const FilePaths proDeps = d->m_depMap.value(proName); - - QList projects; - for (const FilePath &dep : proDeps) { - Project *pro = Utils::findOrDefault(d->m_projects, [&dep](Project *p) { - return p->projectFilePath() == dep; - }); - if (pro) - projects += pro; - } - - return projects; -} - -bool ProjectManager::hasDependency(const Project *project, const Project *depProject) -{ - const FilePath proName = project->projectFilePath(); - const FilePath depName = depProject->projectFilePath(); - - const FilePaths proDeps = d->m_depMap.value(proName); - return proDeps.contains(depName); -} - -bool ProjectManager::canAddDependency(const Project *project, const Project *depProject) -{ - const FilePath newDep = project->projectFilePath(); - const FilePath checkDep = depProject->projectFilePath(); - - return d->recursiveDependencyCheck(newDep, checkDep); -} - -bool ProjectManager::addDependency(Project *project, Project *depProject) -{ - const FilePath proName = project->projectFilePath(); - const FilePath depName = depProject->projectFilePath(); - - // check if this dependency is valid - if (!d->recursiveDependencyCheck(proName, depName)) - return false; - - FilePaths proDeps = d->m_depMap.value(proName); - if (!proDeps.contains(depName)) { - proDeps.append(depName); - d->m_depMap[proName] = proDeps; - } - emit m_instance->dependencyChanged(project, depProject); - - return true; -} - -void ProjectManager::removeDependency(Project *project, Project *depProject) -{ - const FilePath proName = project->projectFilePath(); - const FilePath depName = depProject->projectFilePath(); - - FilePaths proDeps = d->m_depMap.value(proName); - proDeps.removeAll(depName); - if (proDeps.isEmpty()) - d->m_depMap.remove(proName); - else - d->m_depMap[proName] = proDeps; - emit m_instance->dependencyChanged(project, depProject); -} - -bool ProjectManager::isProjectConfigurationCascading() -{ - return d->m_casadeSetActive; -} - -void ProjectManager::setProjectConfigurationCascading(bool b) -{ - d->m_casadeSetActive = b; - SessionManager::markSessionFileDirty(); -} - -void ProjectManager::setStartupProject(Project *startupProject) -{ - QTC_ASSERT((!startupProject && d->m_projects.isEmpty()) - || (startupProject && d->m_projects.contains(startupProject)), return); - - if (d->m_startupProject == startupProject) - return; - - d->m_startupProject = startupProject; - if (d->m_startupProject && d->m_startupProject->needsConfiguration()) { - ModeManager::activateMode(Constants::MODE_SESSION); - ModeManager::setFocusToCurrentMode(); - } - FolderNavigationWidgetFactory::setFallbackSyncFilePath( - startupProject ? startupProject->projectFilePath().parentDir() : FilePath()); - emit m_instance->startupProjectChanged(startupProject); -} - -Project *ProjectManager::startupProject() -{ - return d->m_startupProject; -} - -Target *ProjectManager::startupTarget() -{ - return d->m_startupProject ? d->m_startupProject->activeTarget() : nullptr; -} - -BuildSystem *ProjectManager::startupBuildSystem() -{ - Target *t = startupTarget(); - return t ? t->buildSystem() : nullptr; -} - -/*! - * Returns the RunConfiguration of the currently active target - * of the startup project, if such exists, or \c nullptr otherwise. - */ - - -RunConfiguration *ProjectManager::startupRunConfiguration() -{ - Target *t = startupTarget(); - return t ? t->activeRunConfiguration() : nullptr; -} - -void ProjectManager::addProject(Project *pro) -{ - QTC_ASSERT(pro, return); - QTC_CHECK(!pro->displayName().isEmpty()); - QTC_CHECK(pro->id().isValid()); - - sb_d->m_virginSession = false; - QTC_ASSERT(!d->m_projects.contains(pro), return); - - d->m_projects.append(pro); - - connect(pro, &Project::displayNameChanged, - m_instance, [pro]() { emit m_instance->projectDisplayNameChanged(pro); }); - - emit m_instance->projectAdded(pro); - const auto updateFolderNavigation = [pro] { - // destructing projects might trigger changes, so check if the project is actually there - if (QTC_GUARD(d->m_projects.contains(pro))) { - const QIcon icon = pro->rootProjectNode() ? pro->rootProjectNode()->icon() : QIcon(); - FolderNavigationWidgetFactory::insertRootDirectory({projectFolderId(pro), - PROJECT_SORT_VALUE, - pro->displayName(), - pro->projectFilePath().parentDir(), - icon}); - } - }; - updateFolderNavigation(); - configureEditors(pro); - connect(pro, &Project::fileListChanged, m_instance, [pro, updateFolderNavigation]() { - configureEditors(pro); - updateFolderNavigation(); // update icon - }); - connect(pro, &Project::displayNameChanged, m_instance, updateFolderNavigation); - - if (!startupProject()) - setStartupProject(pro); -} - -void ProjectManager::removeProject(Project *project) -{ - sb_d->m_virginSession = false; - QTC_ASSERT(project, return); - removeProjects({project}); -} - bool SessionManager::loadingSession() { return sb_d->m_loadingSession; } -bool ProjectManager::save() -{ - emit sb_instance->aboutToSaveSession(); - - const FilePath filePath = SessionManager::sessionNameToFileName(sb_d->m_sessionName); - QVariantMap data; - - // See the explanation at loadSession() for how we handle the implicit default session. - if (SessionManager::isDefaultVirgin()) { - if (filePath.exists()) { - PersistentSettingsReader reader; - if (!reader.load(filePath)) { - QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"), - Tr::tr("Could not save session %1").arg(filePath.toUserOutput())); - return false; - } - data = reader.restoreValues(); - } - } else { - // save the startup project - if (d->m_startupProject) - data.insert("StartupProject", d->m_startupProject->projectFilePath().toSettings()); - - const QColor c = StyleHelper::requestedBaseColor(); - if (c.isValid()) { - QString tmp = QString::fromLatin1("#%1%2%3") - .arg(c.red(), 2, 16, QLatin1Char('0')) - .arg(c.green(), 2, 16, QLatin1Char('0')) - .arg(c.blue(), 2, 16, QLatin1Char('0')); - data.insert(QLatin1String("Color"), tmp); - } - - FilePaths projectFiles = Utils::transform(projects(), &Project::projectFilePath); - // Restore information on projects that failed to load: - // don't read projects to the list, which the user loaded - for (const FilePath &failed : std::as_const(d->m_failedProjects)) { - if (!projectFiles.contains(failed)) - projectFiles << failed; - } - - data.insert("ProjectList", Utils::transform(projectFiles, - &FilePath::toString)); - data.insert("CascadeSetActive", d->m_casadeSetActive); - - QVariantMap depMap; - auto i = d->m_depMap.constBegin(); - while (i != d->m_depMap.constEnd()) { - QString key = i.key().toString(); - QStringList values; - const FilePaths valueList = i.value(); - for (const FilePath &value : valueList) - values << value.toString(); - depMap.insert(key, values); - ++i; - } - data.insert(QLatin1String("ProjectDependencies"), QVariant(depMap)); - data.insert(QLatin1String("EditorSettings"), EditorManager::saveState().toBase64()); - } - - const auto end = sb_d->m_values.constEnd(); - QStringList keys; - for (auto it = sb_d->m_values.constBegin(); it != end; ++it) { - data.insert(QLatin1String("value-") + it.key(), it.value()); - keys << it.key(); - } - data.insert(QLatin1String("valueKeys"), keys); - - if (!sb_d->m_writer || sb_d->m_writer->fileName() != filePath) { - delete sb_d->m_writer; - sb_d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession"); - } - const bool result = sb_d->m_writer->save(data, ICore::dialogParent()); - if (result) { - if (!SessionManager::isDefaultVirgin()) - sb_d->m_sessionDateTimes.insert(SessionManager::activeSession(), QDateTime::currentDateTime()); - } else { - QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"), - Tr::tr("Could not save session to file %1").arg(sb_d->m_writer->fileName().toUserOutput())); - } - - return result; -} - -/*! - Closes all projects - */ -void ProjectManager::closeAllProjects() -{ - removeProjects(projects()); -} - -const QList ProjectManager::projects() -{ - return d->m_projects; -} - -bool ProjectManager::hasProjects() -{ - return d->hasProjects(); -} - -bool ProjectManager::hasProject(Project *p) -{ - return d->m_projects.contains(p); -} - -FilePaths ProjectManagerPrivate::dependencies(const FilePath &proName) const -{ - FilePaths result; - dependencies(proName, result); - return result; -} - -void ProjectManagerPrivate::dependencies(const FilePath &proName, FilePaths &result) const -{ - const FilePaths depends = m_depMap.value(proName); - - for (const FilePath &dep : depends) - dependencies(dep, result); - - if (!result.contains(proName)) - result.append(proName); -} - -QString ProjectManagerPrivate::sessionTitle(const FilePath &filePath) -{ - if (SessionManager::isDefaultSession(sb_d->m_sessionName)) { - if (filePath.isEmpty()) { - // use single project's name if there is only one loaded. - const QList projects = ProjectManager::projects(); - if (projects.size() == 1) - return projects.first()->displayName(); - } - } else { - QString sessionName = sb_d->m_sessionName; - if (sessionName.isEmpty()) - sessionName = Tr::tr("Untitled"); - return sessionName; - } - return QString(); -} - -QString ProjectManagerPrivate::locationInProject(const FilePath &filePath) { - const Project *project = ProjectManager::projectForFile(filePath); - if (!project) - return QString(); - - const FilePath parentDir = filePath.parentDir(); - if (parentDir == project->projectDirectory()) - return "@ " + project->displayName(); - - if (filePath.isChildOf(project->projectDirectory())) { - const FilePath dirInProject = parentDir.relativeChildPath(project->projectDirectory()); - return "(" + dirInProject.toUserOutput() + " @ " + project->displayName() + ")"; - } - - // For a file that is "outside" the project it belongs to, we display its - // dir's full path because it is easier to read than a series of "../../.". - // Example: /home/hugo/GenericProject/App.files lists /home/hugo/lib/Bar.cpp - return "(" + parentDir.toUserOutput() + " @ " + project->displayName() + ")"; -} - -QString ProjectManagerPrivate::windowTitleAddition(const FilePath &filePath) -{ - return filePath.isEmpty() ? QString() : locationInProject(filePath); -} - -FilePaths ProjectManagerPrivate::dependenciesOrder() const -{ - QList> unordered; - FilePaths ordered; - - // copy the map to a temporary list - for (const Project *pro : m_projects) { - const FilePath proName = pro->projectFilePath(); - const FilePaths depList = filtered(m_depMap.value(proName), - [this](const FilePath &proPath) { - return contains(m_projects, [proPath](const Project *p) { - return p->projectFilePath() == proPath; - }); - }); - unordered.push_back({proName, depList}); - } - - while (!unordered.isEmpty()) { - for (int i = (unordered.count() - 1); i >= 0; --i) { - if (unordered.at(i).second.isEmpty()) { - ordered << unordered.at(i).first; - unordered.removeAt(i); - } - } - - // remove the handled projects from the dependency lists - // of the remaining unordered projects - for (int i = 0; i < unordered.count(); ++i) { - for (const FilePath &pro : std::as_const(ordered)) { - FilePaths depList = unordered.at(i).second; - depList.removeAll(pro); - unordered[i].second = depList; - } - } - } - - return ordered; -} - -QList ProjectManager::projectOrder(const Project *project) -{ - QList result; - - FilePaths pros; - if (project) - pros = d->dependencies(project->projectFilePath()); - else - pros = d->dependenciesOrder(); - - for (const FilePath &proFile : std::as_const(pros)) { - for (Project *pro : projects()) { - if (pro->projectFilePath() == proFile) { - result << pro; - break; - } - } - } - - return result; -} - -Project *ProjectManager::projectForFile(const FilePath &fileName) -{ - if (Project * const project = Utils::findOrDefault(ProjectManager::projects(), - [&fileName](const Project *p) { return p->isKnownFile(fileName); })) { - return project; - } - return Utils::findOrDefault(ProjectManager::projects(), - [&fileName](const Project *p) { - for (const Target * const target : p->targets()) { - for (const BuildConfiguration * const bc : target->buildConfigurations()) { - if (fileName.isChildOf(bc->buildDirectory())) - return false; - } - } - return fileName.isChildOf(p->projectDirectory()); - }); -} - -Project *ProjectManager::projectWithProjectFilePath(const FilePath &filePath) -{ - return Utils::findOrDefault(ProjectManager::projects(), - [&filePath](const Project *p) { return p->projectFilePath() == filePath; }); -} - -void ProjectManager::configureEditor(IEditor *editor, const QString &fileName) -{ - if (auto textEditor = qobject_cast(editor)) { - Project *project = projectForFile(Utils::FilePath::fromString(fileName)); - // Global settings are the default. - if (project) - project->editorConfiguration()->configureEditor(textEditor); - } -} - -void ProjectManager::configureEditors(Project *project) -{ - const QList documents = DocumentModel::openedDocuments(); - for (IDocument *document : documents) { - if (project->isKnownFile(document->filePath())) { - const QList editors = DocumentModel::editorsForDocument(document); - for (IEditor *editor : editors) { - if (auto textEditor = qobject_cast(editor)) { - project->editorConfiguration()->configureEditor(textEditor); - } - } - } - } -} - -void ProjectManager::removeProjects(const QList &remove) -{ - for (Project *pro : remove) - emit m_instance->aboutToRemoveProject(pro); - - bool changeStartupProject = false; - - // Delete projects - for (Project *pro : remove) { - pro->saveSettings(); - pro->markAsShuttingDown(); - - // Remove the project node: - d->m_projects.removeOne(pro); - - if (pro == d->m_startupProject) - changeStartupProject = true; - - FolderNavigationWidgetFactory::removeRootDirectory(projectFolderId(pro)); - disconnect(pro, nullptr, m_instance, nullptr); - emit m_instance->projectRemoved(pro); - } - - if (changeStartupProject) - setStartupProject(hasProjects() ? projects().first() : nullptr); - - qDeleteAll(remove); -} - /*! Lets other plugins store persistent values within the session file. */ @@ -860,61 +252,6 @@ void SessionManagerPrivate::restoreValues(const PersistentSettingsReader &reader } } -void ProjectManagerPrivate::restoreDependencies(const PersistentSettingsReader &reader) -{ - QMap depMap = reader.restoreValue(QLatin1String("ProjectDependencies")).toMap(); - auto i = depMap.constBegin(); - while (i != depMap.constEnd()) { - const QString &key = i.key(); - FilePaths values; - const QStringList valueList = i.value().toStringList(); - for (const QString &value : valueList) - values << FilePath::fromString(value); - m_depMap.insert(FilePath::fromString(key), values); - ++i; - } -} - -void ProjectManagerPrivate::askUserAboutFailedProjects() -{ - FilePaths failedProjects = m_failedProjects; - if (!failedProjects.isEmpty()) { - QString fileList = FilePath::formatFilePaths(failedProjects, "
"); - QMessageBox box(QMessageBox::Warning, - Tr::tr("Failed to restore project files"), - Tr::tr("Could not restore the following project files:
%1"). - arg(fileList)); - auto keepButton = new QPushButton(Tr::tr("Keep projects in Session"), &box); - auto removeButton = new QPushButton(Tr::tr("Remove projects from Session"), &box); - box.addButton(keepButton, QMessageBox::AcceptRole); - box.addButton(removeButton, QMessageBox::DestructiveRole); - - box.exec(); - - if (box.clickedButton() == removeButton) - m_failedProjects.clear(); - } -} - -void ProjectManagerPrivate::restoreStartupProject(const PersistentSettingsReader &reader) -{ - const FilePath startupProject = FilePath::fromSettings(reader.restoreValue("StartupProject")); - if (!startupProject.isEmpty()) { - for (Project *pro : std::as_const(m_projects)) { - if (pro->projectFilePath() == startupProject) { - m_instance->setStartupProject(pro); - break; - } - } - } - if (!m_startupProject) { - if (!startupProject.isEmpty()) - qWarning() << "Could not find startup project" << startupProject; - if (hasProjects()) - m_instance->setStartupProject(m_projects.first()); - } -} - void SessionManagerPrivate::restoreEditors(const PersistentSettingsReader &reader) { const QVariant editorsettings = reader.restoreValue(QLatin1String("EditorSettings")); @@ -924,186 +261,6 @@ void SessionManagerPrivate::restoreEditors(const PersistentSettingsReader &reade } } -/*! - Loads a session, takes a session name (not filename). -*/ -void ProjectManagerPrivate::restoreProjects(const FilePaths &fileList) -{ - // indirectly adds projects to session - // Keep projects that failed to load in the session! - m_failedProjects = fileList; - if (!fileList.isEmpty()) { - ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProjects(fileList); - if (!result) - ProjectExplorerPlugin::showOpenProjectError(result); - const QList projects = result.projects(); - for (const Project *p : projects) - m_failedProjects.removeAll(p->projectFilePath()); - } -} - -/* - * ========== Notes on storing and loading the default session ========== - * The default session comes in two flavors: implicit and explicit. The implicit one, - * also referred to as "default virgin" in the code base, is the one that is active - * at start-up, if no session has been explicitly loaded due to command-line arguments - * or the "restore last session" setting in the session manager. - * The implicit default session silently turns into the explicit default session - * by loading a project or a file or changing settings in the Dependencies panel. The explicit - * default session can also be loaded by the user via the Welcome Screen. - * This mechanism somewhat complicates the handling of session-specific settings such as - * the ones in the task pane: Users expect that changes they make there become persistent, even - * when they are in the implicit default session. However, we can't just blindly store - * the implicit default session, because then we'd overwrite the project list of the explicit - * default session. Therefore, we use the following logic: - * - Upon start-up, if no session is to be explicitly loaded, we restore the parts of the - * explicit default session that are not related to projects, editors etc; the - * "general settings" of the session, so to speak. - * - When storing the implicit default session, we overwrite only these "general settings" - * of the explicit default session and keep the others as they are. - * - When switching from the implicit to the explicit default session, we keep the - * "general settings" and load everything else from the session file. - * This guarantees that user changes are properly transferred and nothing gets lost from - * either the implicit or the explicit default session. - * - */ -bool ProjectManager::loadSession(const QString &session, bool initial) -{ - const bool loadImplicitDefault = session.isEmpty(); - const bool switchFromImplicitToExplicitDefault = session == DEFAULT_SESSION - && sb_d->m_sessionName == DEFAULT_SESSION && !initial; - - // Do nothing if we have that session already loaded, - // exception if the session is the default virgin session - // we still want to be able to load the default session - if (session == sb_d->m_sessionName && !SessionManager::isDefaultVirgin()) - return true; - - if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) - return false; - - FilePaths fileList; - // Try loading the file - FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION : session); - PersistentSettingsReader reader; - if (fileName.exists()) { - if (!reader.load(fileName)) { - QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while restoring session"), - Tr::tr("Could not restore session %1").arg(fileName.toUserOutput())); - - return false; - } - - if (loadImplicitDefault) { - sb_d->restoreValues(reader); - emit sb_instance->sessionLoaded(DEFAULT_SESSION); - return true; - } - - fileList = FileUtils::toFilePathList(reader.restoreValue("ProjectList").toStringList()); - } else if (loadImplicitDefault) { - return true; - } - - sb_d->m_loadingSession = true; - - // Allow everyone to set something in the session and before saving - emit sb_instance->aboutToUnloadSession(sb_d->m_sessionName); - - if (!save()) { - sb_d->m_loadingSession = false; - return false; - } - - // Clean up - if (!EditorManager::closeAllEditors()) { - sb_d->m_loadingSession = false; - return false; - } - - // find a list of projects to close later - const QList projectsToRemove = Utils::filtered(projects(), [&fileList](Project *p) { - return !fileList.contains(p->projectFilePath()); - }); - const QList openProjects = projects(); - const FilePaths projectPathsToLoad = Utils::filtered(fileList, [&openProjects](const FilePath &path) { - return !Utils::contains(openProjects, [&path](Project *p) { - return p->projectFilePath() == path; - }); - }); - d->m_failedProjects.clear(); - d->m_depMap.clear(); - if (!switchFromImplicitToExplicitDefault) - sb_d->m_values.clear(); - d->m_casadeSetActive = false; - - sb_d->m_sessionName = session; - delete sb_d->m_writer; - sb_d->m_writer = nullptr; - EditorManager::updateWindowTitles(); - - if (fileName.exists()) { - sb_d->m_virginSession = false; - - ProgressManager::addTask(sb_d->m_future.future(), Tr::tr("Loading Session"), - "ProjectExplorer.SessionFile.Load"); - - sb_d->m_future.setProgressRange(0, 1); - sb_d->m_future.setProgressValue(0); - - if (!switchFromImplicitToExplicitDefault) - sb_d->restoreValues(reader); - emit sb_instance->aboutToLoadSession(session); - - // retrieve all values before the following code could change them again - Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); - if (!modeId.isValid()) - modeId = Id(Core::Constants::MODE_EDIT); - - QColor c = QColor(reader.restoreValue(QLatin1String("Color")).toString()); - if (c.isValid()) - StyleHelper::setBaseColor(c); - - sb_d->m_future.setProgressRange(0, projectPathsToLoad.count() + 1/*initialization above*/ + 1/*editors*/); - sb_d->m_future.setProgressValue(1); - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - - d->restoreProjects(projectPathsToLoad); - sb_d->sessionLoadingProgress(); - d->restoreDependencies(reader); - d->restoreStartupProject(reader); - - removeProjects(projectsToRemove); // only remove old projects now that the startup project is set! - - sb_d->restoreEditors(reader); - - sb_d->m_future.reportFinished(); - sb_d->m_future = QFutureInterface(); - - // Fall back to Project mode if the startup project is unconfigured and - // use the mode saved in the session otherwise - if (d->m_startupProject && d->m_startupProject->needsConfiguration()) - modeId = Id(Constants::MODE_SESSION); - - ModeManager::activateMode(modeId); - ModeManager::setFocusToCurrentMode(); - } else { - removeProjects(projects()); - ModeManager::activateMode(Id(Core::Constants::MODE_EDIT)); - ModeManager::setFocusToCurrentMode(); - } - - d->m_casadeSetActive = reader.restoreValue(QLatin1String("CascadeSetActive"), false).toBool(); - sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); - - emit sb_instance->sessionLoaded(session); - - // Starts a event loop, better do that at the very end - d->askUserAboutFailedProjects(); - sb_d->m_loadingSession = false; - return true; -} - /*! Returns the last session that was opened by the user. */ @@ -1120,11 +277,6 @@ QString SessionManager::startupSession() return ICore::settings()->value(Constants::STARTUPSESSION_KEY).toString(); } -void ProjectManager::reportProjectLoadingProgress() -{ - sb_d->sessionLoadingProgress(); -} - void SessionManager::markSessionFileDirty() { sb_d->m_virginSession = false; @@ -1136,73 +288,4 @@ void SessionManagerPrivate::sessionLoadingProgress() QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } -FilePaths ProjectManager::projectsForSessionName(const QString &session) -{ - const FilePath fileName = SessionManager::sessionNameToFileName(session); - PersistentSettingsReader reader; - if (fileName.exists()) { - if (!reader.load(fileName)) { - qWarning() << "Could not restore session" << fileName.toUserOutput(); - return {}; - } - } - return transform(reader.restoreValue(QLatin1String("ProjectList")).toStringList(), - &FilePath::fromUserInput); -} - -#ifdef WITH_TESTS - -void ProjectExplorerPlugin::testSessionSwitch() -{ - QVERIFY(SessionManager::createSession("session1")); - QVERIFY(SessionManager::createSession("session2")); - QTemporaryFile cppFile("main.cpp"); - QVERIFY(cppFile.open()); - cppFile.close(); - QTemporaryFile projectFile1("XXXXXX.pro"); - QTemporaryFile projectFile2("XXXXXX.pro"); - struct SessionSpec { - SessionSpec(const QString &n, QTemporaryFile &f) : name(n), projectFile(f) {} - const QString name; - QTemporaryFile &projectFile; - }; - std::vector sessionSpecs{SessionSpec("session1", projectFile1), - SessionSpec("session2", projectFile2)}; - for (const SessionSpec &sessionSpec : sessionSpecs) { - static const QByteArray proFileContents - = "TEMPLATE = app\n" - "CONFIG -= qt\n" - "SOURCES = " + cppFile.fileName().toLocal8Bit(); - QVERIFY(sessionSpec.projectFile.open()); - sessionSpec.projectFile.write(proFileContents); - sessionSpec.projectFile.close(); - QVERIFY(ProjectManager::loadSession(sessionSpec.name)); - const OpenProjectResult openResult - = ProjectExplorerPlugin::openProject( - FilePath::fromString(sessionSpec.projectFile.fileName())); - if (openResult.errorMessage().contains("text/plain")) - QSKIP("This test requires the presence of QmakeProjectManager to be fully functional"); - QVERIFY(openResult); - QCOMPARE(openResult.projects().count(), 1); - QVERIFY(openResult.project()); - QCOMPARE(ProjectManager::projects().count(), 1); - } - for (int i = 0; i < 30; ++i) { - QVERIFY(ProjectManager::loadSession("session1")); - QCOMPARE(SessionManager::activeSession(), "session1"); - QCOMPARE(ProjectManager::projects().count(), 1); - QVERIFY(ProjectManager::loadSession("session2")); - QCOMPARE(SessionManager::activeSession(), "session2"); - QCOMPARE(ProjectManager::projects().count(), 1); - } - QVERIFY(ProjectManager::loadSession("session1")); - ProjectManager::closeAllProjects(); - QVERIFY(ProjectManager::loadSession("session2")); - ProjectManager::closeAllProjects(); - QVERIFY(SessionManager::deleteSession("session1")); - QVERIFY(SessionManager::deleteSession("session2")); -} - -#endif // WITH_TESTS - } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 6cab7b68db5..d42868f129b 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -5,7 +5,8 @@ #include "projectexplorer_export.h" -#include "projectmanager.h" // FIXME: Remove once dowstream is adjusted. +// FIXME: Remove once dowstream is adjusted. +#include "projectmanager.h" #include #include diff --git a/src/plugins/projectexplorer/session_p.h b/src/plugins/projectexplorer/session_p.h new file mode 100644 index 00000000000..078fad5c364 --- /dev/null +++ b/src/plugins/projectexplorer/session_p.h @@ -0,0 +1,38 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "session.h" + +#include + +using namespace Core; +using namespace Utils; + +namespace ProjectExplorer { + +class SessionManagerPrivate +{ +public: + void restoreValues(const PersistentSettingsReader &reader); + void restoreEditors(const PersistentSettingsReader &reader); + void sessionLoadingProgress(); + + static QString windowTitleAddition(const FilePath &filePath); + static QString sessionTitle(const FilePath &filePath); + + QString m_sessionName = "default"; + bool m_virginSession = true; + bool m_loadingSession = false; + + mutable QStringList m_sessions; + mutable QHash m_sessionDateTimes; + QHash m_lastActiveTimes; + + QMap m_values; + QFutureInterface m_future; + PersistentSettingsWriter *m_writer = nullptr; +}; + +extern SessionManagerPrivate *sb_d; + +} // namespace ProjectExplorer From c26db7a657ae105227d24077b6a81a555e3138fc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 6 Mar 2023 16:00:26 +0100 Subject: [PATCH 0175/1447] SdkPersistentSettings: Fix build Amends bb4d9c92e77f44b55f06a8b8080b5f35d363a1f5 Change-Id: If20b80f30d87b1be8f606cab402c5a220fa68d07 Reviewed-by: hjk Reviewed-by: David Schulz --- src/tools/sdktool/addkitoperation.cpp | 1 + src/tools/sdktool/addqtoperation.cpp | 1 + src/tools/sdktool/sdkpersistentsettings.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/sdktool/addkitoperation.cpp b/src/tools/sdktool/addkitoperation.cpp index 6ed2feea365..4f0911d011a 100644 --- a/src/tools/sdktool/addkitoperation.cpp +++ b/src/tools/sdktool/addkitoperation.cpp @@ -15,6 +15,7 @@ #include "settings.h" +#include #include #include diff --git a/src/tools/sdktool/addqtoperation.cpp b/src/tools/sdktool/addqtoperation.cpp index 69117eb53a0..ee48c1e5ec5 100644 --- a/src/tools/sdktool/addqtoperation.cpp +++ b/src/tools/sdktool/addqtoperation.cpp @@ -15,6 +15,7 @@ #include #endif +#include #include #include diff --git a/src/tools/sdktool/sdkpersistentsettings.cpp b/src/tools/sdktool/sdkpersistentsettings.cpp index db5ba21a34d..ff8b172d632 100644 --- a/src/tools/sdktool/sdkpersistentsettings.cpp +++ b/src/tools/sdktool/sdkpersistentsettings.cpp @@ -367,7 +367,7 @@ SdkFileSaver::SdkFileSaver(const QString &filePath, QIODevice::OpenMode mode) { m_filePath = filePath; // Workaround an assert in Qt -- and provide a useful error message, too: -#if Q_OS_WIN +#ifdef Q_OS_WIN // Taken from: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx static const QStringList reservedNames = {"CON", "PRN", "AUX", "NUL", From dc1a3f8a8da18eeb6a2ce9be01489a5a31e81546 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 6 Mar 2023 17:48:23 +0100 Subject: [PATCH 0176/1447] Fix qbs build Change-Id: I840fbce750ce354ec99dd2019dea924326319271 Reviewed-by: hjk --- src/plugins/projectexplorer/projectexplorer.qbs | 2 +- src/plugins/terminal/terminal.qbs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 665f28e14e7..27be767db9c 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -116,7 +116,7 @@ Project { "projectfilewizardextension.cpp", "projectfilewizardextension.h", "projectimporter.cpp", "projectimporter.h", "projectmacro.cpp", "projectmacro.h", - "projectexplorer.cpp", "projectmanager.h" + "projectmanager.cpp", "projectmanager.h", "projectmodels.cpp", "projectmodels.h", "projectnodes.cpp", "projectnodes.h", "projectpanelfactory.cpp", "projectpanelfactory.h", diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 4eb3b621fc2..4619d7cf496 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -8,8 +8,10 @@ QtcPlugin { Depends { name: "ptyqt" } files: [ - "celllayout.cpp", - "celllayout.h", + "celliterator.cpp", + "celliterator.h", + "glyphcache.cpp", + "glyphcache.h", "keys.cpp", "keys.h", "scrollback.cpp", @@ -27,6 +29,8 @@ QtcPlugin { "terminalsettings.h", "terminalsettingspage.cpp", "terminalsettingspage.h", + "terminalsurface.cpp", + "terminalsurface.h", "terminaltr.h", "terminalwidget.cpp", "terminalwidget.h", From 8660ee06dbb09afcfcf9eb8ab95fe84e1b8d3516 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 6 Mar 2023 17:26:03 +0100 Subject: [PATCH 0177/1447] SdkPersistentSettings: Fix build - part 2 Amends c26db7a657ae105227d24077b6a81a555e3138fc Change-Id: Idf934d4095f29ef413f59b211a292b48957d44b2 Reviewed-by: hjk --- src/tools/sdktool/main.cpp | 1 + src/tools/sdktool/sdkpersistentsettings.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tools/sdktool/main.cpp b/src/tools/sdktool/main.cpp index f53cd306a1c..1136aa9d446 100644 --- a/src/tools/sdktool/main.cpp +++ b/src/tools/sdktool/main.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include diff --git a/src/tools/sdktool/sdkpersistentsettings.cpp b/src/tools/sdktool/sdkpersistentsettings.cpp index ff8b172d632..4ca9b5e3701 100644 --- a/src/tools/sdktool/sdkpersistentsettings.cpp +++ b/src/tools/sdktool/sdkpersistentsettings.cpp @@ -4,6 +4,7 @@ #include "sdkpersistentsettings.h" #include +#include #include #include #include From 2ac2c5c07d4c04862030c7289c6a760cb03cfb36 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 6 Mar 2023 18:02:00 +0100 Subject: [PATCH 0178/1447] Copilot: Fix warning Change-Id: If2c9c8bf6c2af6eb712949ef200935b4d24cc69b Reviewed-by: David Schulz Reviewed-by: --- src/plugins/copilot/copilotclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 95fa78d2630..7bfddb0cf5a 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -81,6 +81,7 @@ void CopilotClient::openDocument(TextDocument *document) &TextDocument::contentsChangedWithPosition, this, [this, document](int position, int charsRemoved, int charsAdded) { + Q_UNUSED(charsRemoved) auto textEditor = BaseTextEditor::currentTextEditor(); if (!textEditor || textEditor->document() != document) return; From f95f815e9817e4daf927f621ea56a48efe7dcb99 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sun, 5 Mar 2023 23:55:37 +0100 Subject: [PATCH 0179/1447] Terminal: Add support for Cursor shape and blink Change-Id: I7f71578a714d375bcd4ef8ae431f4127cbc57a55 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalsettings.cpp | 6 ++ src/plugins/terminal/terminalsettings.h | 2 + src/plugins/terminal/terminalsettingspage.cpp | 6 ++ src/plugins/terminal/terminalsurface.cpp | 32 ++++++++--- src/plugins/terminal/terminalsurface.h | 7 +++ src/plugins/terminal/terminalwidget.cpp | 55 ++++++++++++++++++- src/plugins/terminal/terminalwidget.h | 6 ++ src/plugins/terminal/tests/cursor/bar | 3 + src/plugins/terminal/tests/cursor/blinkbar | 3 + src/plugins/terminal/tests/cursor/blinkblock | 3 + .../terminal/tests/cursor/blinkunderline | 3 + src/plugins/terminal/tests/cursor/block | 3 + src/plugins/terminal/tests/cursor/underline | 3 + 13 files changed, 122 insertions(+), 10 deletions(-) create mode 100755 src/plugins/terminal/tests/cursor/bar create mode 100755 src/plugins/terminal/tests/cursor/blinkbar create mode 100755 src/plugins/terminal/tests/cursor/blinkblock create mode 100755 src/plugins/terminal/tests/cursor/blinkunderline create mode 100755 src/plugins/terminal/tests/cursor/block create mode 100755 src/plugins/terminal/tests/cursor/underline diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index d19b488f3e2..cbb43d78bbe 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -71,6 +71,11 @@ TerminalSettings::TerminalSettings() fontSize.setDefaultValue(defaultFontSize()); fontSize.setRange(1, 100); + allowBlinkingCursor.setSettingsKey("AllowBlinkingCursor"); + allowBlinkingCursor.setLabelText(Tr::tr("Allow blinking cursor")); + allowBlinkingCursor.setToolTip(Tr::tr("Allow the cursor to blink.")); + allowBlinkingCursor.setDefaultValue(false); + shell.setSettingsKey("ShellPath"); shell.setLabelText(Tr::tr("Shell path:")); shell.setExpectedKind(PathChooser::ExistingCommand); @@ -110,6 +115,7 @@ TerminalSettings::TerminalSettings() registerAspect(&font); registerAspect(&fontSize); registerAspect(&shell); + registerAspect(&allowBlinkingCursor); registerAspect(&foregroundColor); registerAspect(&backgroundColor); diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index 3f92f1aa7aa..de5f0a32428 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -23,6 +23,8 @@ public: Utils::ColorAspect selectionColor; Utils::ColorAspect colors[16]; + + Utils::BoolAspect allowBlinkingCursor; }; } // namespace Terminal diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index f3986878380..bf73cddd0f4 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -54,6 +54,12 @@ QWidget *TerminalSettingsPage::widget() settings.fontSize, st, }, }, + Group { + title(Tr::tr("Cursor")), + Row { + settings.allowBlinkingCursor, st, + }, + }, Group { title(Tr::tr("Colors")), Column { diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index 2bd7327c26b..4c9021d5965 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -28,6 +28,9 @@ struct TerminalSurfacePrivate , m_vtermScreen(vterm_obtain_screen(m_vterm.get())) , m_scrollback(std::make_unique(5000)) , q(surface) + {} + + void init() { vterm_set_utf8(m_vterm.get(), true); @@ -193,15 +196,24 @@ struct TerminalSurfacePrivate int setTerminalProperties(VTermProp prop, VTermValue *val) { switch (prop) { - case VTERM_PROP_CURSORVISIBLE: + case VTERM_PROP_CURSORVISIBLE: { + Cursor old = q->cursor(); m_cursor.visible = val->boolean; + q->cursorChanged(old, q->cursor()); break; - case VTERM_PROP_CURSORBLINK: - qCDebug(log) << "Ignoring VTERM_PROP_CURSORBLINK" << val->boolean; + } + case VTERM_PROP_CURSORBLINK: { + Cursor old = q->cursor(); + m_cursor.blink = val->boolean; + emit q->cursorChanged(old, q->cursor()); break; - case VTERM_PROP_CURSORSHAPE: - qCDebug(log) << "Ignoring VTERM_PROP_CURSORSHAPE" << val->number; + } + case VTERM_PROP_CURSORSHAPE: { + Cursor old = q->cursor(); + m_cursor.shape = (Cursor::Shape) val->number; + emit q->cursorChanged(old, q->cursor()); break; + } case VTERM_PROP_ICONNAME: //emit iconTextChanged(val->string); break; @@ -227,7 +239,8 @@ struct TerminalSurfacePrivate { Q_UNUSED(oldpos); Cursor oldCursor = q->cursor(); - m_cursor = {{pos.col, pos.row}, visible > 0}; + m_cursor.position = {pos.col, pos.row}; + m_cursor.visible = visible > 0; q->cursorChanged(oldCursor, q->cursor()); return 1; } @@ -272,7 +285,9 @@ struct TerminalSurfacePrivate TerminalSurface::TerminalSurface(QSize initialGridSize) : d(std::make_unique(this, initialGridSize)) -{} +{ + d->init(); +} TerminalSurface::~TerminalSurface() = default; @@ -310,7 +325,8 @@ std::u32string::value_type TerminalSurface::fetchCharAt(int x, int y) const TerminalCell TerminalSurface::fetchCell(int x, int y) const { - static TerminalCell emptyCell{1, {}, {}}; + static TerminalCell + emptyCell{1, {}, {}, false, {}, std::nullopt, QTextCharFormat::NoUnderline, false}; QTC_ASSERT(y >= 0, return emptyCell); QTC_ASSERT(y < d->liveSize().height() + d->m_scrollback->size(), return emptyCell); diff --git a/src/plugins/terminal/terminalsurface.h b/src/plugins/terminal/terminalsurface.h index b92cc9da833..354a3a028d4 100644 --- a/src/plugins/terminal/terminalsurface.h +++ b/src/plugins/terminal/terminalsurface.h @@ -31,8 +31,15 @@ struct TerminalCell struct Cursor { + enum class Shape { + Block = 1, + Underline, + LeftBar, + }; QPoint position; bool visible; + Shape shape; + bool blink{false}; }; class TerminalSurface : public QObject diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 0be7bc7b72a..9d515972b0a 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -67,6 +67,17 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op setupColors(); setupActions(); + m_cursorBlinkTimer.setInterval(750); + m_cursorBlinkTimer.setSingleShot(false); + + connect(&m_cursorBlinkTimer, &QTimer::timeout, this, [this]() { + if (hasFocus()) + m_cursorBlinkState = !m_cursorBlinkState; + else + m_cursorBlinkState = true; + updateViewport(gridToViewport(QRect{m_cursor.position, m_cursor.position})); + }); + setAttribute(Qt::WA_InputMethodEnabled); setAttribute(Qt::WA_MouseTracking); @@ -88,6 +99,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op // Setup colors first, as setupFont will redraw the screen. setupColors(); setupFont(); + configBlinkTimer(); }); } @@ -261,7 +273,10 @@ void TerminalWidget::setupSurface() if (startY > endY) std::swap(startY, endY); + m_cursor = newCursor; + updateViewport(gridToViewport(QRect{QPoint{startX, startY}, QPoint{endX, endY}})); + configBlinkTimer(); }); connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] { setSelection(std::nullopt); @@ -271,6 +286,18 @@ void TerminalWidget::setupSurface() }); } +void TerminalWidget::configBlinkTimer() +{ + bool shouldRun = m_cursor.visible && m_cursor.blink && hasFocus() + && TerminalSettings::instance().allowBlinkingCursor.value(); + if (shouldRun != m_cursorBlinkTimer.isActive()) { + if (shouldRun) + m_cursorBlinkTimer.start(); + else + m_cursorBlinkTimer.stop(); + } +} + void TerminalWidget::setFont(const QFont &font) { m_font = font; @@ -658,17 +685,33 @@ void TerminalWidget::paintCursor(QPainter &p) const { auto cursor = m_surface->cursor(); - if (cursor.visible) { + const bool blinkState = !cursor.blink || m_cursorBlinkState + || !TerminalSettings::instance().allowBlinkingCursor.value(); + + if (cursor.visible && blinkState) { const int cursorCellWidth = m_surface->cellWidthAt(cursor.position.x(), cursor.position.y()); QRectF cursorRect = QRectF(gridToGlobal(cursor.position), gridToGlobal({cursor.position.x() + cursorCellWidth, cursor.position.y()}, true)); + + cursorRect.adjust(0, 0, 0, -1); + if (hasFocus()) { QPainter::CompositionMode oldMode = p.compositionMode(); p.setCompositionMode(QPainter::RasterOp_NotDestination); - p.fillRect(cursorRect, p.pen().brush()); + switch (cursor.shape) { + case Internal::Cursor::Shape::Block: + p.fillRect(cursorRect, p.pen().brush()); + break; + case Internal::Cursor::Shape::Underline: + p.drawLine(cursorRect.bottomLeft(), cursorRect.bottomRight()); + break; + case Internal::Cursor::Shape::LeftBar: + p.drawLine(cursorRect.topLeft(), cursorRect.bottomLeft()); + break; + } p.setCompositionMode(oldMode); } else { p.drawRect(cursorRect); @@ -809,6 +852,12 @@ void TerminalWidget::paintEvent(QPaintEvent *event) void TerminalWidget::keyPressEvent(QKeyEvent *event) { + // Don't blink during typing + if (m_cursorBlinkTimer.isActive()) { + m_cursorBlinkTimer.start(); + m_cursorBlinkState = true; + } + bool actionTriggered = false; for (const auto &action : actions()) { if (!action->isEnabled()) @@ -918,10 +967,12 @@ void TerminalWidget::wheelEvent(QWheelEvent *event) void TerminalWidget::focusInEvent(QFocusEvent *) { updateViewport(); + configBlinkTimer(); } void TerminalWidget::focusOutEvent(QFocusEvent *) { updateViewport(); + configBlinkTimer(); } void TerminalWidget::inputMethodEvent(QInputMethodEvent *event) diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 058e0e2cb38..07355b95bc2 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -149,6 +149,8 @@ protected: void setSelection(const std::optional &selection); + void configBlinkTimer(); + private: std::unique_ptr m_process; std::unique_ptr m_surface; @@ -188,6 +190,10 @@ private: std::chrono::system_clock::time_point m_lastFlush; std::chrono::system_clock::time_point m_lastDoubleClick; bool m_selectLineMode{false}; + + Internal::Cursor m_cursor; + QTimer m_cursorBlinkTimer; + bool m_cursorBlinkState{true}; }; } // namespace Terminal diff --git a/src/plugins/terminal/tests/cursor/bar b/src/plugins/terminal/tests/cursor/bar new file mode 100755 index 00000000000..a7bd99b55dd --- /dev/null +++ b/src/plugins/terminal/tests/cursor/bar @@ -0,0 +1,3 @@ +#!/bin/sh + +echo -e -n "\x1b[\x36 q" # Steady bar diff --git a/src/plugins/terminal/tests/cursor/blinkbar b/src/plugins/terminal/tests/cursor/blinkbar new file mode 100755 index 00000000000..0acf6179d9c --- /dev/null +++ b/src/plugins/terminal/tests/cursor/blinkbar @@ -0,0 +1,3 @@ +#!/bin/sh + +echo -e -n "\x1b[\x35 q" # Blinking bar diff --git a/src/plugins/terminal/tests/cursor/blinkblock b/src/plugins/terminal/tests/cursor/blinkblock new file mode 100755 index 00000000000..c536c83b8b7 --- /dev/null +++ b/src/plugins/terminal/tests/cursor/blinkblock @@ -0,0 +1,3 @@ +#!/bin/sh + +echo -e -n "\x1b[\x31 q" # Blinking block (default) diff --git a/src/plugins/terminal/tests/cursor/blinkunderline b/src/plugins/terminal/tests/cursor/blinkunderline new file mode 100755 index 00000000000..745d9e2a29c --- /dev/null +++ b/src/plugins/terminal/tests/cursor/blinkunderline @@ -0,0 +1,3 @@ +#!/bin/sh + +echo -e -n "\x1b[\x33 q" # Blinking underline diff --git a/src/plugins/terminal/tests/cursor/block b/src/plugins/terminal/tests/cursor/block new file mode 100755 index 00000000000..421df3b8c5a --- /dev/null +++ b/src/plugins/terminal/tests/cursor/block @@ -0,0 +1,3 @@ +#!/bin/sh + +echo -e -n "\x1b[\x32 q" # Steady block diff --git a/src/plugins/terminal/tests/cursor/underline b/src/plugins/terminal/tests/cursor/underline new file mode 100755 index 00000000000..7638b5358d0 --- /dev/null +++ b/src/plugins/terminal/tests/cursor/underline @@ -0,0 +1,3 @@ +#!/bin/sh + +echo -e -n "\x1b[\x34 q" # Steady underline From 66094398fb1e05a4581784eaf3d367e96b73a013 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 6 Mar 2023 11:54:21 +0100 Subject: [PATCH 0180/1447] Terminal: New Terminal opens project folder Change-Id: I974a3c73363a810a18f9327d8682c2a56a42fee2 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/CMakeLists.txt | 2 +- src/plugins/terminal/terminalpane.cpp | 25 ++++++++++++++++++++++++- src/plugins/terminal/terminalpane.h | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index e12e518bd88..c0972eccf36 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -1,6 +1,6 @@ add_qtc_plugin(Terminal - PLUGIN_DEPENDS Core + PLUGIN_DEPENDS Core ProjectExplorer DEPENDS libvterm SOURCES celliterator.cpp celliterator.h diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index b93bdd3a5e9..c70cb412e3c 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -10,6 +10,9 @@ #include #include +#include +#include + #include #include #include @@ -88,9 +91,29 @@ TerminalPane::TerminalPane(QObject *parent) }); } -void TerminalPane::openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters) +static std::optional startupProjectDirectory() +{ + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); + if (!project) + return std::nullopt; + + return project->projectDirectory(); +} + +void TerminalPane::openTerminal(Utils::Terminal::OpenTerminalParameters parameters) { showPage(0); + + if (!parameters.workingDirectory) { + const std::optional projectDir = startupProjectDirectory(); + if (projectDir) { + if (!parameters.shellCommand + || parameters.shellCommand->executable().ensureReachable(*projectDir)) { + parameters.workingDirectory = *projectDir; + } + } + } + auto terminalWidget = new TerminalWidget(m_tabWidget, parameters); m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal"))); setupTerminalWidget(terminalWidget); diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index f748c70e717..1761e1b556a 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -36,7 +36,7 @@ public: virtual void goToNext(); virtual void goToPrev(); - void openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters); + void openTerminal(Utils::Terminal::OpenTerminalParameters parameters); void addTerminal(TerminalWidget *terminal, const QString &title); private: From 0f1f5435ea4f3cca043b87549c74c076f20ab019 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 7 Mar 2023 06:52:19 +0100 Subject: [PATCH 0181/1447] Terminal: Fix build before Qt6.4 Change-Id: Idc1138289516eb2cdeffc310cec4b9ba019d1b16 Reviewed-by: David Schulz --- src/plugins/terminal/terminalwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 9d515972b0a..f2af06d5774 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -484,7 +484,7 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) const qreal radiusBase = qMax(qreal(1), maxRadius); const qreal pWidth = pen.widthF(); - QString key = QLatin1StringView("WaveUnderline-") % pen.color().name() + QString key = QLatin1String("WaveUnderline-") % pen.color().name() % QString::number(*(size_t *) &radiusBase, 16) % QString::number(*(size_t *) &pWidth); From ae2690e4b16ae686da8443bf59584a900890a39c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 27 Feb 2023 07:18:57 +0100 Subject: [PATCH 0182/1447] Debugger: make default number of array elements configurable Change-Id: Iad7b653d66f9f87d818f8cce612a82a5fc391b23 Reviewed-by: Reviewed-by: hjk --- src/plugins/debugger/commonoptionspage.cpp | 3 ++- src/plugins/debugger/debuggeractions.cpp | 10 ++++++++++ src/plugins/debugger/debuggeractions.h | 1 + src/plugins/debugger/watchhandler.cpp | 6 +++--- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index dc47fb79e08..f04eeb74b91 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -153,7 +153,8 @@ public: Grid limits { s.maximalStringLength, br, - s.displayStringLimit + s.displayStringLimit, br, + s.defaultArraySize }; Column { diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index a3a6187a417..208ca88d61e 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -531,6 +531,15 @@ DebuggerSettings::DebuggerSettings() + Tr::tr("The maximum length for strings in separated windows. " "Longer strings are cut off and displayed with an ellipsis attached.")); + defaultArraySize.setSettingsKey(debugModeGroup, "DefaultArraySize"); + defaultArraySize.setDefaultValue(100); + defaultArraySize.setRange(10, 1000000000); + defaultArraySize.setSingleStep(100); + defaultArraySize.setLabelText(Tr::tr("Default array size:")); + defaultArraySize.setToolTip("

" + + Tr::tr("The number of array elements requested when expanding " + "entries in the Locals and Expressions views.")); + expandStack.setLabelText(Tr::tr("Reload Full Stack")); createFullBacktrace.setLabelText(Tr::tr("Create Full Backtrace")); @@ -610,6 +619,7 @@ DebuggerSettings::DebuggerSettings() page4.registerAspect(&showQObjectNames); page4.registerAspect(&displayStringLimit); page4.registerAspect(&maximalStringLength); + page4.registerAspect(&defaultArraySize); // Page 5 page5.registerAspect(&cdbAdditionalArguments); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 69cc76a1f1b..f01ef74aa99 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -146,6 +146,7 @@ public: Utils::BoolAspect autoDerefPointers; Utils::IntegerAspect maximalStringLength; Utils::IntegerAspect displayStringLimit; + Utils::IntegerAspect defaultArraySize; Utils::BoolAspect sortStructMembers; Utils::BoolAspect useToolTipsInLocalsView; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 9b3521e11fd..0923348d94f 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -402,7 +402,6 @@ public: WatchModel(WatchHandler *handler, DebuggerEngine *engine); static QString nameForFormat(int format); - constexpr static int defaultMaxArrayCount = 100; QVariant data(const QModelIndex &idx, int role) const override; bool setData(const QModelIndex &idx, const QVariant &value, int role) override; @@ -1350,7 +1349,8 @@ void WatchModel::expand(WatchItem *item, bool requestEngineUpdate) return; if (item->isLoadMore()) { item = item->parent(); - m_maxArrayCount[item->iname] = m_maxArrayCount.value(item->iname, defaultMaxArrayCount) * 10; + m_maxArrayCount[item->iname] + = m_maxArrayCount.value(item->iname, debuggerSettings()->defaultArraySize.value()) * 10; if (requestEngineUpdate) m_engine->updateItem(item->iname); } else { @@ -2848,7 +2848,7 @@ QSet WatchHandler::expandedINames() const int WatchHandler::maxArrayCount(const QString &iname) const { - return m_model->m_maxArrayCount.value(iname, WatchModel::defaultMaxArrayCount); + return m_model->m_maxArrayCount.value(iname, debuggerSettings()->defaultArraySize.value()); } void WatchHandler::recordTypeInfo(const GdbMi &typeInfo) From 69fa8f3f3ccf5da4a02c44ae1e0a3109e2de422a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 01:04:45 +0100 Subject: [PATCH 0183/1447] FilePath: Integrate FileStreamerManager for async i-face Change-Id: I3371471e3c23b86a62b5e4056b343941ab46e191 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/devicefileaccess.cpp | 23 ----- src/libs/utils/devicefileaccess.h | 14 --- src/libs/utils/filepath.cpp | 44 +++------ src/libs/utils/filepath.h | 15 ++- src/libs/utils/filestreamermanager.h | 6 +- .../remotelinux/filesystemaccess_test.cpp | 97 ------------------- .../remotelinux/filesystemaccess_test.h | 2 - src/plugins/valgrind/callgrindengine.cpp | 5 +- tests/auto/utils/filepath/tst_filepath.cpp | 4 +- 9 files changed, 27 insertions(+), 183 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index cf14faefc48..1dd035d916f 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -380,29 +380,6 @@ std::optional DeviceFileAccess::refersToExecutableFile( return {}; } -void DeviceFileAccess::asyncFileContents(const FilePath &filePath, - const Continuation> &cont, - qint64 limit, - qint64 offset) const -{ - cont(fileContents(filePath, limit, offset)); -} - -void DeviceFileAccess::asyncWriteFileContents(const FilePath &filePath, - const Continuation> &cont, - const QByteArray &data, - qint64 offset) const -{ - cont(writeFileContents(filePath, data, offset)); -} - -void DeviceFileAccess::asyncCopyFile(const FilePath &filePath, - const Continuation> &cont, - const FilePath &target) const -{ - cont(copyFile(filePath, target)); -} - expected_str DeviceFileAccess::createTempFile(const FilePath &filePath) { Q_UNUSED(filePath) diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 238bab5e777..e3a2acdb8fb 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -72,20 +72,6 @@ protected: const QByteArray &data, qint64 offset) const; - virtual void asyncFileContents(const FilePath &filePath, - const Continuation> &cont, - qint64 limit, - qint64 offset) const; - - virtual void asyncWriteFileContents(const FilePath &filePath, - const Continuation> &cont, - const QByteArray &data, - qint64 offset) const; - - virtual void asyncCopyFile(const FilePath &filePath, - const Continuation> &cont, - const FilePath &target) const; - virtual expected_str createTempFile(const FilePath &filePath); }; diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 29ee8de6f75..12796afec9f 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -6,6 +6,7 @@ #include "algorithm.h" #include "devicefileaccess.h" #include "environment.h" +#include "filestreamermanager.h" #include "fileutils.h" #include "hostosinfo.h" #include "qtcassert.h" @@ -626,13 +627,6 @@ bool FilePath::ensureReachable(const FilePath &other) const return false; } -void FilePath::asyncFileContents(const Continuation &> &cont, - qint64 maxSize, - qint64 offset) const -{ - return fileAccess()->asyncFileContents(*this, cont, maxSize, offset); -} - expected_str FilePath::writeFileContents(const QByteArray &data, qint64 offset) const { return fileAccess()->writeFileContents(*this, data, offset); @@ -643,11 +637,19 @@ FilePathInfo FilePath::filePathInfo() const return fileAccess()->filePathInfo(*this); } -void FilePath::asyncWriteFileContents(const Continuation &> &cont, - const QByteArray &data, - qint64 offset) const +FileStreamHandle FilePath::asyncCopy(const FilePath &target, const CopyContinuation &cont) const { - return fileAccess()->asyncWriteFileContents(*this, cont, data, offset); + return FileStreamerManager::copy(*this, target, cont); +} + +FileStreamHandle FilePath::asyncRead(const ReadContinuation &cont) const +{ + return FileStreamerManager::read(*this, cont); +} + +FileStreamHandle FilePath::asyncWrite(const QByteArray &data, const WriteContinuation &cont) const +{ + return FileStreamerManager::write(*this, data, cont); } bool FilePath::needsDevice() const @@ -1614,26 +1616,6 @@ expected_str FilePath::copyFile(const FilePath &target) const return fileAccess()->copyFile(*this, target); } -void FilePath::asyncCopyFile(const Continuation &> &cont, - const FilePath &target) const -{ - if (host() != target.host()) { - asyncFileContents([cont, target](const expected_str &contents) { - if (contents) - target.asyncWriteFileContents( - [cont](const expected_str &result) { - if (result) - cont({}); - else - cont(make_unexpected(result.error())); - }, - *contents); - }); - return; - } - return fileAccess()->asyncCopyFile(*this, cont, target); -} - bool FilePath::renameFile(const FilePath &target) const { return fileAccess()->renameFile(*this, target); diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 77a3b84382b..11fd8e10e21 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -33,8 +33,12 @@ namespace Utils { class DeviceFileAccess; class Environment; class EnvironmentChange; +enum class FileStreamHandle; template using Continuation = std::function; +using CopyContinuation = Continuation &>; +using ReadContinuation = Continuation &>; +using WriteContinuation = Continuation &>; class QTCREATOR_UTILS_EXPORT FileFilter { @@ -206,14 +210,9 @@ public: static void sort(FilePaths &files); // Asynchronous interface - void asyncCopyFile(const Continuation &> &cont, - const FilePath &target) const; - void asyncFileContents(const Continuation &> &cont, - qint64 maxSize = -1, - qint64 offset = 0) const; - void asyncWriteFileContents(const Continuation &> &cont, - const QByteArray &data, - qint64 offset = 0) const; + FileStreamHandle asyncCopy(const FilePath &target, const CopyContinuation &cont = {}) const; + FileStreamHandle asyncRead(const ReadContinuation &cont = {}) const; + FileStreamHandle asyncWrite(const QByteArray &data, const WriteContinuation &cont = {}) const; // Prefer not to use // Using needsDevice() in "user" code is likely to result in code that diff --git a/src/libs/utils/filestreamermanager.h b/src/libs/utils/filestreamermanager.h index 261d58ba299..f86a3db480f 100644 --- a/src/libs/utils/filestreamermanager.h +++ b/src/libs/utils/filestreamermanager.h @@ -15,15 +15,11 @@ QT_END_NAMESPACE namespace Utils { -enum FileStreamHandle : int {}; +enum class FileStreamHandle : int {}; class QTCREATOR_UTILS_EXPORT FileStreamerManager { public: - using CopyContinuation = Continuation &>; - using ReadContinuation = Continuation &>; - using WriteContinuation = Continuation &>; - static FileStreamHandle copy(const FilePath &source, const FilePath &destination, const CopyContinuation &cont); static FileStreamHandle copy(const FilePath &source, const FilePath &destination, diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index 268e36acb4f..13e46619ff3 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -648,102 +648,5 @@ void FileSystemAccessTest::testFileStreamerManager() qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; } -void FileSystemAccessTest::testBlockingTransfer_data() -{ - testFileStreamer_data(); -} - -void FileSystemAccessTest::testBlockingTransfer() -{ - QElapsedTimer timer; - timer.start(); - - QFETCH(QString, fileName); - QFETCH(QByteArray, data); - - const FilePath localSourcePath = m_localSourceDir / fileName; - const FilePath remoteSourcePath = m_remoteSourceDir / fileName; - const FilePath localLocalDestPath = m_localDestDir / "local" / fileName; - const FilePath localRemoteDestPath = m_localDestDir / "remote" / fileName; - const FilePath remoteLocalDestPath = m_remoteDestDir / "local" / fileName; - const FilePath remoteRemoteDestPath = m_remoteDestDir / "remote" / fileName; - - localSourcePath.removeFile(); - remoteSourcePath.removeFile(); - localLocalDestPath.removeFile(); - localRemoteDestPath.removeFile(); - remoteLocalDestPath.removeFile(); - remoteRemoteDestPath.removeFile(); - - QVERIFY(!localSourcePath.exists()); - QVERIFY(!remoteSourcePath.exists()); - QVERIFY(!localLocalDestPath.exists()); - QVERIFY(!localRemoteDestPath.exists()); - QVERIFY(!remoteLocalDestPath.exists()); - QVERIFY(!remoteRemoteDestPath.exists()); - - bool writerHit = false; - const auto writeChecker = [&](const expected_str &res) { - writerHit = true; - QVERIFY(res); - }; - - bool readerHit = false; - const auto readChecker = [&](const QByteArray &expected) { - return [&](const expected_str &result) { - readerHit = true; - QCOMPARE(result, expected); - }; - }; - - bool dummyHit = false; - const auto dummy = [&](const expected_str &res) { - dummyHit = true; - QVERIFY(res); - }; - - localSourcePath.asyncWriteFileContents(writeChecker, data); - localSourcePath.asyncFileContents(readChecker(data)); - QVERIFY(writerHit); - QVERIFY(readerHit); - - writerHit = false; - readerHit = false; - remoteSourcePath.asyncWriteFileContents(writeChecker, data); - remoteSourcePath.asyncFileContents(readChecker(data)); - QVERIFY(writerHit); - QVERIFY(readerHit); - - dummyHit = false; - readerHit = false; - localSourcePath.asyncCopyFile(dummy, localLocalDestPath); - localLocalDestPath.asyncFileContents(readChecker(data)); - QVERIFY(dummyHit); - QVERIFY(readerHit); - - dummyHit = false; - readerHit = false; - remoteSourcePath.asyncCopyFile(dummy, localRemoteDestPath); - localRemoteDestPath.asyncFileContents(readChecker(data)); - QVERIFY(dummyHit); - QVERIFY(readerHit); - - dummyHit = false; - readerHit = false; - localSourcePath.asyncCopyFile(dummy, remoteLocalDestPath); - remoteLocalDestPath.asyncFileContents(readChecker(data)); - QVERIFY(dummyHit); - QVERIFY(readerHit); - - dummyHit = false; - readerHit = false; - remoteSourcePath.asyncCopyFile(dummy, remoteRemoteDestPath); - remoteRemoteDestPath.asyncFileContents(readChecker(data)); - QVERIFY(dummyHit); - QVERIFY(readerHit); - - qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; -} - } // Internal } // RemoteLinux diff --git a/src/plugins/remotelinux/filesystemaccess_test.h b/src/plugins/remotelinux/filesystemaccess_test.h index 2d3e6ae241b..84321db6ce8 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.h +++ b/src/plugins/remotelinux/filesystemaccess_test.h @@ -33,8 +33,6 @@ private slots: void testFileStreamer(); void testFileStreamerManager_data(); void testFileStreamerManager(); - void testBlockingTransfer_data(); - void testBlockingTransfer(); void cleanupTestCase(); diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index d70c667df6f..00de8b42fd8 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -261,7 +262,9 @@ void CallgrindToolRunner::triggerParse() showStatusMessage(Tr::tr("Parsing Profile Data...")); m_parser.parse(m_hostOutputFile); }; - m_valgrindOutputFile.asyncCopyFile(afterCopy, m_hostOutputFile); + // TODO: Store the handle and cancel on CallgrindToolRunner destructor? + // TODO: Should d'tor of context object cancel the running task? + FileStreamerManager::copy(m_valgrindOutputFile, m_hostOutputFile, this, afterCopy); } void CallgrindToolRunner::cleanupTempFile() diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index fed266d80b7..b2bd5d11bb8 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -1308,8 +1308,8 @@ void tst_filepath::asyncLocalCopy() QCOMPARE(dest.fileContents(), orig.fileContents()); wasCalled = true; }; - orig.asyncCopyFile(afterCopy, dest); - QCOMPARE(wasCalled, true); + orig.asyncCopy(dest, afterCopy); + QTRY_VERIFY(wasCalled); } void tst_filepath::startsWithDriveLetter_data() From d0fae7fa592795468a2fe6e86197a7899fa1b5a0 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 7 Mar 2023 12:17:21 +0100 Subject: [PATCH 0184/1447] Terminal: Fix conpty process creation When the Project's source directory would be used as a working directory for the terminal, conpty would fail to start the shell. Change-Id: I1050ec11c2bb46e17187431114a1319c86dd449c Reviewed-by: Reviewed-by: David Schulz --- src/libs/3rdparty/libptyqt/conptyprocess.cpp | 80 +++++++++----------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.cpp b/src/libs/3rdparty/libptyqt/conptyprocess.cpp index c788e74c92a..687d3116f5a 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/conptyprocess.cpp @@ -105,8 +105,7 @@ bool ConPtyProcess::startProcess(const QString &executable, qint16 cols, qint16 rows) { - if (!isAvailable()) - { + if (!isAvailable()) { m_lastError = m_winContext.lastError(); return false; } @@ -127,54 +126,45 @@ bool ConPtyProcess::startProcess(const QString &executable, m_size = QPair(cols, rows); //env - std::wstringstream envBlock; - for (const QString &line: std::as_const(environment)) - { - envBlock << line.toStdWString() << L'\0'; - } - envBlock << L'\0'; - std::wstring env = envBlock.str(); - LPWSTR envArg = env.empty() ? nullptr : env.data(); - LPCWSTR workingDirPointer = workingDir.isEmpty() ? nullptr : workingDir.toStdWString().c_str(); + const QString env = environment.join(QChar(QChar::Null)) + QChar(QChar::Null); + LPVOID envPtr = env.isEmpty() ? nullptr : (LPVOID) env.utf16(); + + LPCWSTR workingDirPtr = workingDir.isEmpty() ? nullptr : (LPCWSTR) workingDir.utf16(); QStringList exeAndArgs = arguments; exeAndArgs.prepend(m_shellPath); + std::wstring cmdArg{(LPCWSTR) (exeAndArgs.join(QLatin1String(" ")).utf16())}; - std::wstring cmdArg = exeAndArgs.join(" ").toStdWString(); - - HRESULT hr{ E_UNEXPECTED }; + HRESULT hr{E_UNEXPECTED}; // Create the Pseudo Console and pipes to it hr = createPseudoConsoleAndPipes(&m_ptyHandler, &m_hPipeIn, &m_hPipeOut, cols, rows); - if (S_OK != hr) - { + if (S_OK != hr) { m_lastError = QString("ConPty Error: CreatePseudoConsoleAndPipes fail"); return false; } // Initialize the necessary startup info struct - if (S_OK != initializeStartupInfoAttachedToPseudoConsole(&m_shellStartupInfo, m_ptyHandler)) - { + if (S_OK != initializeStartupInfoAttachedToPseudoConsole(&m_shellStartupInfo, m_ptyHandler)) { m_lastError = QString("ConPty Error: InitializeStartupInfoAttachedToPseudoConsole fail"); return false; } - hr = CreateProcess(NULL, // No module name - use Command Line - cmdArg.data(), // Command Line - NULL, // Process handle not inheritable - NULL, // Thread handle not inheritable - FALSE, // Inherit handles - EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // Creation flags - envArg, // Environment block - workingDirPointer, // Use parent's starting directory - &m_shellStartupInfo.StartupInfo, // Pointer to STARTUPINFO - &m_shellProcessInformation) // Pointer to PROCESS_INFORMATION + hr = CreateProcessW(nullptr, // No module name - use Command Line + cmdArg.data(), // Command Line + nullptr, // Process handle not inheritable + nullptr, // Thread handle not inheritable + FALSE, // Inherit handles + EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // Creation flags + envPtr, // Environment block + workingDirPtr, // Use parent's starting directory + &m_shellStartupInfo.StartupInfo, // Pointer to STARTUPINFO + &m_shellProcessInformation) // Pointer to PROCESS_INFORMATION ? S_OK : GetLastError(); - if (S_OK != hr) - { + if (S_OK != hr) { m_lastError = QString("ConPty Error: Cannot create process -> %1").arg(hr); return false; } @@ -184,27 +174,25 @@ bool ConPtyProcess::startProcess(const QString &executable, // Notify when the shell process has been terminated m_shellCloseWaitNotifier = new QWinEventNotifier(m_shellProcessInformation.hProcess, notifier()); QObject::connect(m_shellCloseWaitNotifier, - &QWinEventNotifier::activated, - notifier(), - [this](HANDLE hEvent) { - DWORD exitCode = 0; - GetExitCodeProcess(hEvent, &exitCode); - m_exitCode = exitCode; - // Do not respawn if the object is about to be destructed - if (!m_aboutToDestruct) - emit notifier()->aboutToClose(); - m_shellCloseWaitNotifier->setEnabled(false); - }); + &QWinEventNotifier::activated, + notifier(), + [this](HANDLE hEvent) { + DWORD exitCode = 0; + GetExitCodeProcess(hEvent, &exitCode); + m_exitCode = exitCode; + // Do not respawn if the object is about to be destructed + if (!m_aboutToDestruct) + emit notifier()->aboutToClose(); + m_shellCloseWaitNotifier->setEnabled(false); + }); //this code runned in separate thread - m_readThread = QThread::create([this]() - { + m_readThread = QThread::create([this]() { //buffers - const DWORD BUFF_SIZE{ 1024 }; + const DWORD BUFF_SIZE{1024}; char szBuffer[BUFF_SIZE]{}; - forever - { + forever { DWORD dwBytesRead{}; // Read from the pipe From 5d21da74f952600482afe300dbc67aa63ab2eaf5 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 7 Feb 2023 16:46:47 +0100 Subject: [PATCH 0185/1447] Utils: More explicit host os use to make it stand out Quite a few of the uses are actually wrong, but are better visible now and therefore more likely to be fixed. Change-Id: Ia51f7d6eb1b2d3a9c9f73d67dabacfd227c44b15 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/utils/commandline.h | 2 +- .../autotoolsprojectmanager/makefileparser.cpp | 4 +++- .../debugservers/gdb/openocdgdbserverprovider.cpp | 2 +- src/plugins/clangtools/clangtoolsutils.cpp | 2 +- .../cmakebuildconfiguration.cpp | 15 +++++++++------ .../cmakeprojectmanager/fileapidataextractor.cpp | 4 ++-- src/plugins/coreplugin/fileutils.cpp | 3 ++- src/plugins/debugger/lldb/lldbengine.cpp | 3 ++- .../genericprojectmanager/genericproject.cpp | 2 +- src/plugins/ios/iosbuildstep.cpp | 6 ++++-- src/plugins/ios/iosdsymbuildstep.cpp | 3 ++- .../mesonbuildconfiguration.cpp | 3 ++- src/plugins/nim/project/nimcompilerbuildstep.cpp | 2 +- src/plugins/perfprofiler/perfsettings.cpp | 2 +- .../devicesupport/desktopdevice.cpp | 2 +- src/plugins/projectexplorer/gcctoolchain.cpp | 6 ++++-- src/plugins/qmakeprojectmanager/makefileparse.cpp | 4 ++-- src/plugins/qnx/qnxdevice.cpp | 2 +- src/plugins/remotelinux/makeinstallstep.cpp | 2 +- src/plugins/valgrind/callgrindengine.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 2 +- 21 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/libs/utils/commandline.h b/src/libs/utils/commandline.h index 23585adb8af..c3aa17c7d85 100644 --- a/src/libs/utils/commandline.h +++ b/src/libs/utils/commandline.h @@ -55,7 +55,7 @@ public: //! Append already quoted arguments to a shell command static void addArgs(QString *args, const QString &inArgs); //! Split a shell command into separate arguments. - static QStringList splitArgs(const QString &cmd, OsType osType = HostOsInfo::hostOs(), + static QStringList splitArgs(const QString &cmd, OsType osType, bool abortOnMeta = false, SplitError *err = nullptr, const Environment *env = nullptr, const QString *pwd = nullptr); //! Safely replace the expandos in a shell command diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.cpp b/src/plugins/autotoolsprojectmanager/makefileparser.cpp index 09fbd666479..9bbccdb86ad 100644 --- a/src/plugins/autotoolsprojectmanager/makefileparser.cpp +++ b/src/plugins/autotoolsprojectmanager/makefileparser.cpp @@ -13,6 +13,8 @@ #include #include +using namespace Utils; + namespace AutotoolsProjectManager::Internal { MakefileParser::MakefileParser(const QString &makefile) : m_makefile(makefile) @@ -423,7 +425,7 @@ QStringList MakefileParser::parseTermsAfterAssign(const QString &line) if (assignPos <= 0 || assignPos >= line.size()) return QStringList(); - const QStringList parts = Utils::ProcessArgs::splitArgs(line.mid(assignPos)); + const QStringList parts = ProcessArgs::splitArgs(line.mid(assignPos), HostOsInfo::hostOs()); QStringList result; for (int i = 0; i < parts.count(); ++i) { const QString cur = parts.at(i); diff --git a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp index 334f31132cb..03933cff50e 100644 --- a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp @@ -64,7 +64,7 @@ QString OpenOcdGdbServerProvider::channelString() const // otherwise running will be stuck. CommandLine cmd = command(); QStringList args = {"|", cmd.executable().toString()}; - for (const QString &a : ProcessArgs::splitArgs(cmd.arguments())) { + for (const QString &a : ProcessArgs::splitArgs(cmd.arguments(), HostOsInfo::hostOs())) { if (a.startsWith('\"') && a.endsWith('\"')) args << a; else diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index 01dcb614b5a..acfd768797b 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -284,7 +284,7 @@ static QStringList extraOptions(const QString &envVar) if (!qtcEnvironmentVariableIsSet(envVar)) return QStringList(); QString arguments = qtcEnvironmentVariable(envVar); - return Utils::ProcessArgs::splitArgs(arguments); + return ProcessArgs::splitArgs(arguments, HostOsInfo::hostOs()); } QStringList extraClangToolsPrependOptions() diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 7b398fac5be..07780d72e9f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -643,7 +643,7 @@ void CMakeBuildSettingsWidget::updateInitialCMakeArguments() // As the user would expect to have e.g. "--preset" from "Initial Configuration" // to "Current Configuration" as additional parameters m_buildSystem->setAdditionalCMakeArguments(ProcessArgs::splitArgs( - bc->aspect()->value())); + bc->aspect()->value(), HostOsInfo::hostOs())); } void CMakeBuildSettingsWidget::kitCMakeConfiguration() @@ -823,9 +823,10 @@ void CMakeBuildSettingsWidget::updateFromKit() // Then the additional parameters const QStringList additionalKitCMake = ProcessArgs::splitArgs( - CMakeConfigurationKitAspect::additionalConfiguration(k)); + CMakeConfigurationKitAspect::additionalConfiguration(k), HostOsInfo::hostOs()); const QStringList additionalInitialCMake = ProcessArgs::splitArgs( - m_buildSystem->buildConfiguration()->aspect()->value()); + m_buildSystem->buildConfiguration()->aspect()->value(), + HostOsInfo::hostOs()); QStringList mergedArgumentList; std::set_union(additionalInitialCMake.begin(), @@ -1725,7 +1726,8 @@ void CMakeBuildSystem::setInitialCMakeArguments(const QStringList &args) QStringList CMakeBuildSystem::additionalCMakeArguments() const { - return ProcessArgs::splitArgs(buildConfiguration()->aspect()->value()); + return ProcessArgs::splitArgs(buildConfiguration()->aspect()->value(), + HostOsInfo::hostOs()); } void CMakeBuildSystem::setAdditionalCMakeArguments(const QStringList &args) @@ -1748,7 +1750,8 @@ void CMakeBuildSystem::filterConfigArgumentsFromAdditionalCMakeArguments() // which is already part of the CMake variables and should not be also // in the addtional CMake options const QStringList arguments = ProcessArgs::splitArgs( - buildConfiguration()->aspect()->value()); + buildConfiguration()->aspect()->value(), + HostOsInfo::hostOs()); QStringList unknownOptions; const CMakeConfig config = CMakeConfig::fromArguments(arguments, unknownOptions); @@ -2144,7 +2147,7 @@ const QStringList InitialCMakeArgumentsAspect::allValues() const return ci.toArgument(nullptr); }); - initialCMakeArguments.append(ProcessArgs::splitArgs(value())); + initialCMakeArguments.append(ProcessArgs::splitArgs(value(), HostOsInfo::hostOs())); return initialCMakeArguments; } diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 9293831fdcf..29ace13a6bd 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -245,7 +245,7 @@ QList generateBuildTargets(const PreprocessedData &input, continue; // CMake sometimes mixes several shell-escaped pieces into one fragment. Disentangle that again: - const QStringList parts = ProcessArgs::splitArgs(f.fragment); + const QStringList parts = ProcessArgs::splitArgs(f.fragment, HostOsInfo::hostOs()); for (QString part : parts) { // Library search paths that are added with target_link_directories are added as // -LIBPATH:... (Windows/MSVC), or @@ -306,7 +306,7 @@ static QStringList splitFragments(const QStringList &fragments) { QStringList result; for (const QString &f : fragments) { - result += ProcessArgs::splitArgs(f); + result += ProcessArgs::splitArgs(f, HostOsInfo::hostOs()); } return result; } diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 116fe244f2f..929ebfe61d3 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -76,7 +76,8 @@ void FileUtils::showInGraphicalShell(QWidget *parent, const FilePath &pathIn) const QString folder = fileInfo.isDir() ? fileInfo.absoluteFilePath() : fileInfo.filePath(); const QString app = UnixUtils::fileBrowser(ICore::settings()); QStringList browserArgs = ProcessArgs::splitArgs( - UnixUtils::substituteFileBrowserParameters(app, folder)); + UnixUtils::substituteFileBrowserParameters(app, folder), + HostOsInfo::hostOs()); QString error; if (browserArgs.isEmpty()) { error = Tr::tr("The command for file browser is not set."); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index e8c3c361383..38fe8c6b01f 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -267,7 +267,8 @@ void LldbEngine::handleLldbStarted() cmd2.arg("nativemixed", isNativeMixedActive()); cmd2.arg("workingdirectory", rp.inferior.workingDirectory.path()); cmd2.arg("environment", rp.inferior.environment.toStringList()); - cmd2.arg("processargs", toHex(ProcessArgs::splitArgs(rp.inferior.command.arguments()).join(QChar(0)))); + cmd2.arg("processargs", toHex(ProcessArgs::splitArgs(rp.inferior.command.arguments(), + HostOsInfo::hostOs()).join(QChar(0)))); cmd2.arg("platform", rp.platform); cmd2.arg("symbolfile", rp.symbolFile.path()); diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index e819235c9b6..c219b88b2eb 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -400,7 +400,7 @@ static QStringList readFlags(const QString &filePath) return QStringList(); QStringList flags; for (const auto &line : lines) - flags.append(ProcessArgs::splitArgs(line)); + flags.append(ProcessArgs::splitArgs(line, HostOsInfo::hostOs())); return flags; } diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp index eb6664c155c..e4771d97e84 100644 --- a/src/plugins/ios/iosbuildstep.cpp +++ b/src/plugins/ios/iosbuildstep.cpp @@ -101,7 +101,8 @@ QWidget *IosBuildStep::createConfigWidget() updateDetails(); connect(buildArgumentsTextEdit, &QPlainTextEdit::textChanged, this, [=] { - setBaseArguments(ProcessArgs::splitArgs(buildArgumentsTextEdit->toPlainText())); + setBaseArguments(ProcessArgs::splitArgs(buildArgumentsTextEdit->toPlainText(), + HostOsInfo::hostOs())); resetDefaultsButton->setEnabled(!m_useDefaultArguments); updateDetails(); }); @@ -113,7 +114,8 @@ QWidget *IosBuildStep::createConfigWidget() }); connect(extraArgumentsLineEdit, &QLineEdit::editingFinished, this, [=] { - setExtraArguments(ProcessArgs::splitArgs(extraArgumentsLineEdit->text())); + setExtraArguments(ProcessArgs::splitArgs(extraArgumentsLineEdit->text(), + HostOsInfo::hostOs())); }); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp index 54481ded9b7..33ff0e7e202 100644 --- a/src/plugins/ios/iosdsymbuildstep.cpp +++ b/src/plugins/ios/iosdsymbuildstep.cpp @@ -242,7 +242,8 @@ QWidget *IosDsymBuildStep::createConfigWidget() connect(argumentsTextEdit, &QPlainTextEdit::textChanged, this, [this, argumentsTextEdit, resetDefaultsButton, updateDetails] { - setArguments(Utils::ProcessArgs::splitArgs(argumentsTextEdit->toPlainText())); + setArguments(ProcessArgs::splitArgs(argumentsTextEdit->toPlainText(), + HostOsInfo::hostOs())); resetDefaultsButton->setEnabled(!isDefault()); updateDetails(); }); diff --git a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp index a24a1f52bf5..bd90ee818c6 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp @@ -91,7 +91,8 @@ void MesonBuildConfiguration::build(const QString &target) QStringList MesonBuildConfiguration::mesonConfigArgs() { - return Utils::ProcessArgs::splitArgs(m_parameters) + QStringList{QString("-Dbuildtype=%1").arg(mesonBuildTypeName(m_buildType))}; + return Utils::ProcessArgs::splitArgs(m_parameters, HostOsInfo::hostOs()) + + QStringList{QString("-Dbuildtype=%1").arg(mesonBuildTypeName(m_buildType))}; } const QString &MesonBuildConfiguration::parameters() const diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp index 3ca151def72..87f93e53e2a 100644 --- a/src/plugins/nim/project/nimcompilerbuildstep.cpp +++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp @@ -76,7 +76,7 @@ QWidget *NimCompilerBuildStep::createConfigWidget() auto updateUi = [=] { const CommandLine cmd = commandLine(); - const QStringList parts = ProcessArgs::splitArgs(cmd.toUserOutput()); + const QStringList parts = ProcessArgs::splitArgs(cmd.toUserOutput(), HostOsInfo::hostOs()); commandTextEdit->setText(parts.join(QChar::LineFeed)); diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index 8175dece0ea..9bea76b3e29 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -122,7 +122,7 @@ QStringList PerfSettings::perfRecordArguments() const "--call-graph", callgraphArg, sampleMode.itemValue().toString(), QString::number(period.value())}) - + ProcessArgs::splitArgs(extraArguments.value()); + + ProcessArgs::splitArgs(extraArguments.value(), HostOsInfo::hostOs()); } void PerfSettings::resetToDefault() diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index a09c8bac76d..566b669c393 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -78,7 +78,7 @@ static void startTerminalEmulator(const QString &workingDir, const Environment & const TerminalCommand term = TerminalCommand::terminalEmulator(); QProcess process; process.setProgram(term.command.nativePath()); - process.setArguments(ProcessArgs::splitArgs(term.openArgs)); + process.setArguments(ProcessArgs::splitArgs(term.openArgs, HostOsInfo::hostOs())); process.setProcessEnvironment(env.toProcessEnvironment()); process.setWorkingDirectory(workingDir); process.startDetached(); diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index d2449bd69ae..cac1905f111 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1385,8 +1385,10 @@ void GccToolChainConfigWidget::setFromToolchain() QSignalBlocker blocker(this); auto tc = static_cast(toolChain()); m_compilerCommand->setFilePath(tc->compilerCommand()); - m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformCodeGenFlags())); - m_platformLinkerFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformLinkerFlags())); + m_platformCodeGenFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformCodeGenFlags(), + HostOsInfo::hostOs())); + m_platformLinkerFlagsLineEdit->setText(ProcessArgs::joinArgs(tc->platformLinkerFlags(), + HostOsInfo::hostOs())); if (m_abiWidget) { m_abiWidget->setAbis(tc->supportedAbis(), tc->targetAbi()); if (!m_isReadOnly && !m_compilerCommand->filePath().toString().isEmpty()) diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp index e9d8c2878e7..32193a4dbdc 100644 --- a/src/plugins/qmakeprojectmanager/makefileparse.cpp +++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp @@ -479,8 +479,8 @@ void QmakeProjectManagerPlugin::testMakefileParser() MakeFileParse parser("/tmp/something", MakeFileParse::Mode::FilterKnownConfigValues); parser.parseCommandLine(command, project); - QCOMPARE(ProcessArgs::splitArgs(parser.unparsedArguments()), - ProcessArgs::splitArgs(unparsedArguments)); + QCOMPARE(ProcessArgs::splitArgs(parser.unparsedArguments(), HostOsInfo::hostOs()), + ProcessArgs::splitArgs(unparsedArguments, HostOsInfo::hostOs())); QCOMPARE(parser.effectiveBuildConfig({}), effectiveBuildConfig); const QMakeStepConfig qmsc = parser.config(); diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index ad205196ed7..f1770a55222 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -48,7 +48,7 @@ QnxProcessImpl::QnxProcessImpl(const LinuxDevice *linuxDevice) QString QnxProcessImpl::fullCommandLine(const CommandLine &commandLine) const { - QStringList args = ProcessArgs::splitArgs(commandLine.arguments()); + QStringList args = ProcessArgs::splitArgs(commandLine.arguments(), HostOsInfo::hostOs()); args.prepend(commandLine.executable().toString()); const QString cmd = ProcessArgs::createUnixArgs(args).toString(); diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index de7f9a336e6..8f51c0b827c 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -261,7 +261,7 @@ void MakeInstallStep::updateFromCustomCommandLineAspect() const StringAspect * const aspect = customCommandLineAspect(); if (!aspect->isChecked()) return; - const QStringList tokens = ProcessArgs::splitArgs(aspect->value()); + const QStringList tokens = ProcessArgs::splitArgs(aspect->value(), HostOsInfo::hostOs()); setMakeCommand(tokens.isEmpty() ? FilePath() : FilePath::fromString(tokens.first())); setUserArguments(ProcessArgs::joinArgs(tokens.mid(1))); } diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 00de8b42fd8..51ec76a1305 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -86,7 +86,7 @@ QStringList CallgrindToolRunner::toolArguments() const arguments << "--callgrind-out-file=" + m_valgrindOutputFile.path(); - arguments << ProcessArgs::splitArgs(m_settings.callgrindArguments.value()); + arguments << ProcessArgs::splitArgs(m_settings.callgrindArguments.value(), HostOsInfo::hostOs()); return arguments; } diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 6129a0b4dbd..7042419a7b5 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -214,7 +214,7 @@ QStringList MemcheckToolRunner::toolArguments() const if (m_withGdb) arguments << "--vgdb=yes" << "--vgdb-error=0"; - arguments << Utils::ProcessArgs::splitArgs(m_settings.memcheckArguments.value()); + arguments << ProcessArgs::splitArgs(m_settings.memcheckArguments.value(), HostOsInfo::hostOs()); return arguments; } From cca7c2a12bef29f9b693d7494c85c7fecd5c5d6f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 20:00:20 +0100 Subject: [PATCH 0186/1447] AsyncTask: add asyncRun() wrappers around QtConcurrent::run() These wrappers accept the additional QThread::Priority argument. Change-Id: I05a692d13bb539622146e3267f8a918431af06ac Reviewed-by: Reviewed-by: Eike Ziller --- src/libs/utils/asynctask.cpp | 26 ++++++- src/libs/utils/asynctask.h | 54 +++++++------ tests/auto/utils/asynctask/tst_asynctask.cpp | 79 +++++++++++++++++++- 3 files changed, 130 insertions(+), 29 deletions(-) diff --git a/src/libs/utils/asynctask.cpp b/src/libs/utils/asynctask.cpp index 73217318a92..2f5aa4d27af 100644 --- a/src/libs/utils/asynctask.cpp +++ b/src/libs/utils/asynctask.cpp @@ -12,17 +12,35 @@ static int s_maxThreadCount = INT_MAX; class AsyncThreadPool : public QThreadPool { public: - AsyncThreadPool() { + AsyncThreadPool(QThread::Priority priority) { + setThreadPriority(priority); setMaxThreadCount(s_maxThreadCount); moveToThread(qApp->thread()); } }; -Q_GLOBAL_STATIC(AsyncThreadPool, s_asyncThreadPool); +Q_GLOBAL_STATIC(AsyncThreadPool, s_idle, QThread::IdlePriority); +Q_GLOBAL_STATIC(AsyncThreadPool, s_lowest, QThread::LowestPriority); +Q_GLOBAL_STATIC(AsyncThreadPool, s_low, QThread::LowPriority); +Q_GLOBAL_STATIC(AsyncThreadPool, s_normal, QThread::NormalPriority); +Q_GLOBAL_STATIC(AsyncThreadPool, s_high, QThread::HighPriority); +Q_GLOBAL_STATIC(AsyncThreadPool, s_highest, QThread::HighestPriority); +Q_GLOBAL_STATIC(AsyncThreadPool, s_timeCritical, QThread::TimeCriticalPriority); +Q_GLOBAL_STATIC(AsyncThreadPool, s_inherit, QThread::InheritPriority); -QThreadPool *asyncThreadPool() +QThreadPool *asyncThreadPool(QThread::Priority priority) { - return s_asyncThreadPool; + switch (priority) { + case QThread::IdlePriority : return s_idle; + case QThread::LowestPriority : return s_lowest; + case QThread::LowPriority : return s_low; + case QThread::NormalPriority : return s_normal; + case QThread::HighPriority : return s_high; + case QThread::HighestPriority : return s_highest; + case QThread::TimeCriticalPriority : return s_timeCritical; + case QThread::InheritPriority : return s_inherit; + } + return nullptr; } } // namespace Utils diff --git a/src/libs/utils/asynctask.h b/src/libs/utils/asynctask.h index 5beaf400eae..1c2f9e9a808 100644 --- a/src/libs/utils/asynctask.h +++ b/src/libs/utils/asynctask.h @@ -15,7 +15,36 @@ namespace Utils { -QTCREATOR_UTILS_EXPORT QThreadPool *asyncThreadPool(); +QTCREATOR_UTILS_EXPORT QThreadPool *asyncThreadPool(QThread::Priority priority); + +template +auto asyncRun(QThreadPool *threadPool, QThread::Priority priority, + Function &&function, Args &&...args) +{ + QThreadPool *pool = threadPool ? threadPool : asyncThreadPool(priority); + return QtConcurrent::run(pool, std::forward(function), std::forward(args)...); +} + +template +auto asyncRun(QThread::Priority priority, Function &&function, Args &&...args) +{ + return asyncRun(nullptr, priority, + std::forward(function), std::forward(args)...); +} + +template +auto asyncRun(QThreadPool *threadPool, Function &&function, Args &&...args) +{ + return asyncRun(threadPool, QThread::InheritPriority, + std::forward(function), std::forward(args)...); +} + +template +auto asyncRun(Function &&function, Args &&...args) +{ + return asyncRun(nullptr, QThread::InheritPriority, + std::forward(function), std::forward(args)...); +} class QTCREATOR_UTILS_EXPORT AsyncTaskBase : public QObject { @@ -86,7 +115,7 @@ private: void wrapConcurrent(Function &&function, Args &&...args) { m_startHandler = [=] { - return callConcurrent(function, args...); + return asyncRun(m_threadPool, m_priority, function, args...); }; } @@ -94,28 +123,11 @@ private: void wrapConcurrent(std::reference_wrapper &&wrapper, Args &&...args) { m_startHandler = [=] { - return callConcurrent(std::forward(wrapper.get()), args...); + return asyncRun(m_threadPool, m_priority, std::forward(wrapper.get()), + args...); }; } - template - auto callConcurrent(Function &&function, Args &&...args) - { - // Notice: we can't just call: - // - // return QtConcurrent::run(function, args...); - // - // since there is no way of passing m_priority there. - // There is an overload with thread pool, however, there is no overload with priority. - // - // Below implementation copied from QtConcurrent::run(): - QThreadPool *threadPool = m_threadPool ? m_threadPool : asyncThreadPool(); - QtConcurrent::DecayedTuple - tuple{std::forward(function), std::forward(args)...}; - return QtConcurrent::TaskResolver, std::decay_t...> - ::run(std::move(tuple), QtConcurrent::TaskStartParameters{threadPool, m_priority}); - } - using StartHandler = std::function()>; StartHandler m_startHandler; FutureSynchronizer *m_synchronizer = nullptr; diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/asynctask/tst_asynctask.cpp index 9ca972973cc..12dc849591b 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/asynctask/tst_asynctask.cpp @@ -102,16 +102,16 @@ public: } }; -template +template struct FutureArgType; -template +template struct FutureArgType> { using Type = Arg; }; -template +template struct ConcurrentResultType; template @@ -122,7 +122,7 @@ struct ConcurrentResultType }; template ::Type> + typename ResultType = typename ConcurrentResultType::Type> std::shared_ptr> createAsyncTask(Function &&function, Args &&...args) { auto asyncTask = std::make_shared>(); @@ -136,13 +136,21 @@ void tst_AsyncTask::runAsync() // free function pointer QCOMPARE(createAsyncTask(&report3)->results(), QList({0, 2, 1})); + QCOMPARE(Utils::asyncRun(&report3).results(), + QList({0, 2, 1})); QCOMPARE(createAsyncTask(report3)->results(), QList({0, 2, 1})); + QCOMPARE(Utils::asyncRun(report3).results(), + QList({0, 2, 1})); QCOMPARE(createAsyncTask(reportN, 4)->results(), QList({0, 0, 0, 0})); + QCOMPARE(Utils::asyncRun(reportN, 4).results(), + QList({0, 0, 0, 0})); QCOMPARE(createAsyncTask(reportN, 2)->results(), QList({0, 0})); + QCOMPARE(Utils::asyncRun(reportN, 2).results(), + QList({0, 0})); QString s = QLatin1String("string"); const QString &crs = QLatin1String("cr string"); @@ -150,21 +158,37 @@ void tst_AsyncTask::runAsync() QCOMPARE(createAsyncTask(reportString1, s)->results(), QList({s})); + QCOMPARE(Utils::asyncRun(reportString1, s).results(), + QList({s})); QCOMPARE(createAsyncTask(reportString1, crs)->results(), QList({crs})); + QCOMPARE(Utils::asyncRun(reportString1, crs).results(), + QList({crs})); QCOMPARE(createAsyncTask(reportString1, cs)->results(), QList({cs})); + QCOMPARE(Utils::asyncRun(reportString1, cs).results(), + QList({cs})); QCOMPARE(createAsyncTask(reportString1, QString(QLatin1String("rvalue")))->results(), QList({QString(QLatin1String("rvalue"))})); + QCOMPARE(Utils::asyncRun(reportString1, QString(QLatin1String("rvalue"))).results(), + QList({QString(QLatin1String("rvalue"))})); QCOMPARE(createAsyncTask(reportString2, s)->results(), QList({s})); + QCOMPARE(Utils::asyncRun(reportString2, s).results(), + QList({s})); QCOMPARE(createAsyncTask(reportString2, crs)->results(), QList({crs})); + QCOMPARE(Utils::asyncRun(reportString2, crs).results(), + QList({crs})); QCOMPARE(createAsyncTask(reportString2, cs)->results(), QList({cs})); + QCOMPARE(Utils::asyncRun(reportString2, cs).results(), + QList({cs})); QCOMPARE(createAsyncTask(reportString2, QString(QLatin1String("rvalue")))->results(), QList({QString(QLatin1String("rvalue"))})); + QCOMPARE(Utils::asyncRun(reportString2, QString(QLatin1String("rvalue"))).results(), + QList({QString(QLatin1String("rvalue"))})); // lambda QCOMPARE(createAsyncTask([](QPromise &promise, int n) { @@ -172,6 +196,11 @@ void tst_AsyncTask::runAsync() promise.addResult(0); }, 3)->results(), QList({0, 0, 0})); + QCOMPARE(Utils::asyncRun([](QPromise &promise, int n) { + for (int i = 0; i < n; ++i) + promise.addResult(0); + }, 3).results(), + QList({0, 0, 0})); // std::function const std::function&,int)> fun = [](QPromise &promise, int n) { @@ -180,45 +209,77 @@ void tst_AsyncTask::runAsync() }; QCOMPARE(createAsyncTask(fun, 2)->results(), QList({0, 0})); + QCOMPARE(Utils::asyncRun(fun, 2).results(), + QList({0, 0})); // operator() QCOMPARE(createAsyncTask(Callable(), 3)->results(), QList({0, 0, 0})); + QCOMPARE(Utils::asyncRun(Callable(), 3).results(), + QList({0, 0, 0})); const Callable c{}; QCOMPARE(createAsyncTask(c, 2)->results(), QList({0, 0})); + QCOMPARE(Utils::asyncRun(c, 2).results(), + QList({0, 0})); // static member functions QCOMPARE(createAsyncTask(&MyObject::staticMember0)->results(), QList({0, 2, 1})); + QCOMPARE(Utils::asyncRun(&MyObject::staticMember0).results(), + QList({0, 2, 1})); QCOMPARE(createAsyncTask(&MyObject::staticMember1, 2)->results(), QList({0, 0})); + QCOMPARE(Utils::asyncRun(&MyObject::staticMember1, 2).results(), + QList({0, 0})); // member functions const MyObject obj{}; QCOMPARE(createAsyncTask(&MyObject::member0, &obj)->results(), QList({0, 2, 1})); + QCOMPARE(Utils::asyncRun(&MyObject::member0, &obj).results(), + QList({0, 2, 1})); QCOMPARE(createAsyncTask(&MyObject::member1, &obj, 4)->results(), QList({0, 0, 0, 0})); + QCOMPARE(Utils::asyncRun(&MyObject::member1, &obj, 4).results(), + QList({0, 0, 0, 0})); QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, s)->results(), QList({s})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, s).results(), + QList({s})); QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, crs)->results(), QList({crs})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, crs).results(), + QList({crs})); QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, cs)->results(), QList({cs})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, cs).results(), + QList({cs})); QCOMPARE(createAsyncTask(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue")))->results(), QList({QString(QLatin1String("rvalue"))})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(), + QList({QString(QLatin1String("rvalue"))})); QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, s)->results(), QList({s})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, s).results(), + QList({s})); QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, crs)->results(), QList({crs})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, crs).results(), + QList({crs})); QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, cs)->results(), QList({cs})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, cs).results(), + QList({cs})); QCOMPARE(createAsyncTask(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue")))->results(), QList({QString(QLatin1String("rvalue"))})); + QCOMPARE(Utils::asyncRun(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(), + QList({QString(QLatin1String("rvalue"))})); MyObject nonConstObj{}; QCOMPARE(createAsyncTask(&MyObject::nonConstMember, &nonConstObj)->results(), QList({0, 2, 1})); + QCOMPARE(Utils::asyncRun(&MyObject::nonConstMember, &nonConstObj).results(), + QList({0, 2, 1})); } void tst_AsyncTask::crefFunction() @@ -227,6 +288,8 @@ void tst_AsyncTask::crefFunction() auto fun = &report3; QCOMPARE(createAsyncTask(std::cref(fun))->results(), QList({0, 2, 1})); + QCOMPARE(Utils::asyncRun(std::cref(fun)).results(), + QList({0, 2, 1})); // lambda with promise auto lambda = [](QPromise &promise, int n) { @@ -235,6 +298,8 @@ void tst_AsyncTask::crefFunction() }; QCOMPARE(createAsyncTask(std::cref(lambda), 3)->results(), QList({0, 0, 0})); + QCOMPARE(Utils::asyncRun(std::cref(lambda), 3).results(), + QList({0, 0, 0})); // std::function with promise const std::function&,int)> funObj = [](QPromise &promise, int n) { @@ -243,17 +308,23 @@ void tst_AsyncTask::crefFunction() }; QCOMPARE(createAsyncTask(std::cref(funObj), 2)->results(), QList({0, 0})); + QCOMPARE(Utils::asyncRun(std::cref(funObj), 2).results(), + QList({0, 0})); // callable with promise const Callable c{}; QCOMPARE(createAsyncTask(std::cref(c), 2)->results(), QList({0, 0})); + QCOMPARE(Utils::asyncRun(std::cref(c), 2).results(), + QList({0, 0})); // member functions with promise auto member = &MyObject::member0; const MyObject obj{}; QCOMPARE(createAsyncTask(std::cref(member), &obj)->results(), QList({0, 2, 1})); + QCOMPARE(Utils::asyncRun(std::cref(member), &obj).results(), + QList({0, 2, 1})); } void tst_AsyncTask::futureSynchonizer() From cae18f88724cff430fb2a54ab0811c751723b6d4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 20:02:25 +0100 Subject: [PATCH 0187/1447] QmlJSSemanticHighlighter: Use QPromise for async calls Change-Id: Ic5d70d766cc25214a3c4a54251d514b678aa9aff Reviewed-by: David Schulz Reviewed-by: Qt CI Bot Reviewed-by: --- .../qmljseditor/qmljssemantichighlighter.cpp | 26 +++++++++---------- .../qmljseditor/qmljssemantichighlighter.h | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp index 0ca826cb005..56f8dfd0bb8 100644 --- a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp +++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp @@ -20,9 +20,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -156,11 +156,11 @@ public: AddMessagesHighlights, SkipMessagesHighlights, }; - CollectionTask(QFutureInterface &futureInterface, + CollectionTask(QPromise &promise, const QmlJSTools::SemanticInfo &semanticInfo, const TextEditor::FontSettings &fontSettings, Flags flags) - : m_futureInterface(futureInterface) + : m_promise(promise) , m_semanticInfo(semanticInfo) , m_fontSettings(fontSettings) , m_scopeChain(semanticInfo.scopeChain()) @@ -211,7 +211,7 @@ public: protected: void accept(Node *ast) { - if (m_futureInterface.isCanceled()) + if (m_promise.isCanceled()) return; if (ast) ast->accept(this); @@ -219,7 +219,7 @@ protected: void scopedAccept(Node *ast, Node *child) { - if (m_futureInterface.isCanceled()) + if (m_promise.isCanceled()) return; m_scopeBuilder.push(ast); accept(child); @@ -510,12 +510,13 @@ private: return; Utils::sort(m_uses, sortByLinePredicate); - m_futureInterface.reportResults(m_uses); + for (const SemanticHighlighter::Use &use : std::as_const(m_uses)) + m_promise.addResult(use); m_uses.clear(); m_uses.reserve(chunkSize); } - QFutureInterface &m_futureInterface; + QPromise &m_promise; const QmlJSTools::SemanticInfo &m_semanticInfo; const TextEditor::FontSettings &m_fontSettings; ScopeChain m_scopeChain; @@ -549,11 +550,8 @@ void SemanticHighlighter::rerun(const QmlJSTools::SemanticInfo &semanticInfo) m_watcher.cancel(); m_startRevision = m_document->document()->revision(); - auto future = Utils::runAsync(QThread::LowestPriority, - &SemanticHighlighter::run, - this, - semanticInfo, - TextEditor::TextEditorSettings::fontSettings()); + auto future = Utils::asyncRun(QThread::LowestPriority, &SemanticHighlighter::run, this, + semanticInfo, TextEditor::TextEditorSettings::fontSettings()); m_watcher.setFuture(future); m_futureSynchronizer.addFuture(future); } @@ -590,11 +588,11 @@ void SemanticHighlighter::finished() m_document->syntaxHighlighter(), m_watcher.future()); } -void SemanticHighlighter::run(QFutureInterface &futureInterface, +void SemanticHighlighter::run(QPromise &promise, const QmlJSTools::SemanticInfo &semanticInfo, const TextEditor::FontSettings &fontSettings) { - CollectionTask task(futureInterface, + CollectionTask task(promise, semanticInfo, fontSettings, (m_enableWarnings ? CollectionTask::AddMessagesHighlights diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.h b/src/plugins/qmljseditor/qmljssemantichighlighter.h index 6ea1e85c6e6..74c51d12d7f 100644 --- a/src/plugins/qmljseditor/qmljssemantichighlighter.h +++ b/src/plugins/qmljseditor/qmljssemantichighlighter.h @@ -62,7 +62,7 @@ public: private: void applyResults(int from, int to); void finished(); - void run(QFutureInterface &futureInterface, + void run(QPromise &promise, const QmlJSTools::SemanticInfo &semanticInfo, const TextEditor::FontSettings &fontSettings); From ce037d09a2a85ee06840cd4de2804e1b967dd90b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 4 Mar 2023 00:39:50 +0100 Subject: [PATCH 0188/1447] VcsBase: Use QtConcurrent invocation for async run Change-Id: Ia4e461c1a2e71d4c959f582e9ed464d4713b672a Reviewed-by: Orgad Shaneh Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/clearcase/clearcaseplugin.cpp | 15 ++++++----- src/plugins/clearcase/clearcasesync.cpp | 32 +++++++++++------------ src/plugins/clearcase/clearcasesync.h | 9 ++++--- src/plugins/git/gitgrep.cpp | 15 ++++++----- src/plugins/git/gitsubmiteditor.cpp | 4 +-- src/plugins/vcsbase/cleandialog.cpp | 29 ++++++++++---------- 6 files changed, 54 insertions(+), 50 deletions(-) diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 83db3d6919e..f60db85ac05 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -30,13 +30,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include @@ -259,7 +259,7 @@ private: CommandResult runCleartool(const FilePath &workingDir, const QStringList &arguments, VcsBase::RunFlags flags = VcsBase::RunFlags::None, QTextCodec *codec = nullptr, int timeoutMultiplier = 1) const; - static void sync(QFutureInterface &future, QStringList files); + static void sync(QPromise &promise, QStringList files); void history(const FilePath &workingDir, const QStringList &file = {}, @@ -1657,7 +1657,7 @@ bool ClearCasePluginPrivate::vcsOpen(const FilePath &workingDir, const QString & if (!m_settings.disableIndexer && (fi.isWritable() || vcsStatus(absPath).status == FileStatus::Unknown)) - runAsync(sync, QStringList(absPath)).waitForFinished(); + Utils::asyncRun(sync, QStringList(absPath)).waitForFinished(); if (vcsStatus(absPath).status == FileStatus::CheckedOut) { QMessageBox::information(ICore::dialogParent(), Tr::tr("ClearCase Checkout"), Tr::tr("File is already checked out.")); @@ -2129,7 +2129,8 @@ void ClearCasePluginPrivate::updateIndex() return; m_checkInAllAction->setEnabled(false); m_statusMap->clear(); - QFuture result = runAsync(sync, transform(project->files(Project::SourceFiles), &FilePath::toString)); + QFuture result = Utils::asyncRun(sync, transform(project->files(Project::SourceFiles), + &FilePath::toString)); if (!m_settings.disableIndexer) ProgressManager::addTask(result, Tr::tr("Updating ClearCase Index"), ClearCase::Constants::TASK_INDEX); } @@ -2261,7 +2262,7 @@ void ClearCasePluginPrivate::syncSlot() FilePath topLevel = state.topLevel(); if (topLevel != state.currentProjectTopLevel()) return; - runAsync(sync, QStringList()); + Utils::asyncRun(sync, QStringList()); // TODO: make use of returned QFuture } void ClearCasePluginPrivate::closing() @@ -2271,12 +2272,12 @@ void ClearCasePluginPrivate::closing() disconnect(qApp, &QApplication::applicationStateChanged, nullptr, nullptr); } -void ClearCasePluginPrivate::sync(QFutureInterface &future, QStringList files) +void ClearCasePluginPrivate::sync(QPromise &promise, QStringList files) { ClearCasePluginPrivate *plugin = ClearCasePluginPrivate::instance(); ClearCaseSync ccSync(plugin->m_statusMap); connect(&ccSync, &ClearCaseSync::updateStreamAndView, plugin, &ClearCasePluginPrivate::updateStreamAndView); - ccSync.run(future, files); + ccSync.run(promise, files); } QString ClearCasePluginPrivate::displayName() const diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp index 388ce1a8c18..90dad2b988c 100644 --- a/src/plugins/clearcase/clearcasesync.cpp +++ b/src/plugins/clearcase/clearcasesync.cpp @@ -13,6 +13,8 @@ #include #include +#include + #ifdef WITH_TESTS #include #include @@ -22,8 +24,7 @@ using namespace Utils; namespace ClearCase::Internal { -static void runProcess(QFutureInterface &future, - const ClearCaseSettings &settings, +static void runProcess(QPromise &promise, const ClearCaseSettings &settings, const QStringList &args, std::function processLine) { @@ -37,7 +38,7 @@ static void runProcess(QFutureInterface &future, int processed = 0; QString buffer; - while (process.waitForReadyRead() && !future.isCanceled()) { + while (process.waitForReadyRead() && !promise.isCanceled()) { buffer += QString::fromLocal8Bit(process.readAllRawStandardOutput()); int index = buffer.indexOf('\n'); while (index != -1) { @@ -135,7 +136,7 @@ void ClearCaseSync::updateStatusForNotManagedFiles(const QStringList &files) } } -void ClearCaseSync::syncSnapshotView(QFutureInterface &future, QStringList &files, +void ClearCaseSync::syncSnapshotView(QPromise &promise, QStringList &files, const ClearCaseSettings &settings) { const QString view = ClearCasePlugin::viewData().name; @@ -167,18 +168,18 @@ void ClearCaseSync::syncSnapshotView(QFutureInterface &future, QStringList // adding 1 for initial sync in which total is not accurate, to prevent finishing // (we don't want it to become green) - future.setProgressRange(0, totalFileCount + 1); + promise.setProgressRange(0, totalFileCount + 1); int totalProcessed = 0; - runProcess(future, settings, args, [&](const QString &buffer, int processed) { + runProcess(promise, settings, args, [&](const QString &buffer, int processed) { processCleartoolLsLine(viewRootDir, buffer); - future.setProgressValue(qMin(totalFileCount, processed)); + promise.setProgressValue(qMin(totalFileCount, processed)); totalProcessed = processed; }); - if (!future.isCanceled()) { + if (!promise.isCanceled()) { updateStatusForNotManagedFiles(files); - future.setProgressValue(totalFileCount + 1); + promise.setProgressValue(totalFileCount + 1); if (!hot) updateTotalFilesCount(view, settings, totalProcessed); } @@ -193,21 +194,20 @@ void ClearCaseSync::processCleartoolLscheckoutLine(const QString &buffer) /// /// Update the file status for dynamic views. /// -void ClearCaseSync::syncDynamicView(QFutureInterface &future, - const ClearCaseSettings& settings) +void ClearCaseSync::syncDynamicView(QPromise &promise, const ClearCaseSettings& settings) { // Always invalidate status for all files invalidateStatusAllFiles(); const QStringList args({"lscheckout", "-avobs", "-me", "-cview", "-s"}); - runProcess(future, settings, args, [&](const QString &buffer, int processed) { + runProcess(promise, settings, args, [&](const QString &buffer, int processed) { processCleartoolLscheckoutLine(buffer); - future.setProgressValue(processed); + promise.setProgressValue(processed); }); } -void ClearCaseSync::run(QFutureInterface &future, QStringList &files) +void ClearCaseSync::run(QPromise &promise, QStringList &files) { ClearCaseSettings settings = ClearCasePlugin::settings(); if (settings.disableIndexer) @@ -225,9 +225,9 @@ void ClearCaseSync::run(QFutureInterface &future, QStringList &files) emit updateStreamAndView(); if (ClearCasePlugin::viewData().isDynamic) - syncDynamicView(future, settings); + syncDynamicView(promise, settings); else - syncSnapshotView(future, files, settings); + syncSnapshotView(promise, files, settings); } #ifdef WITH_TESTS diff --git a/src/plugins/clearcase/clearcasesync.h b/src/plugins/clearcase/clearcasesync.h index a008dabb600..c2862d9d404 100644 --- a/src/plugins/clearcase/clearcasesync.h +++ b/src/plugins/clearcase/clearcasesync.h @@ -9,6 +9,8 @@ QT_BEGIN_NAMESPACE class QDir; template class QFutureInterface; +template +class QPromise; QT_END_NAMESPACE namespace ClearCase::Internal { @@ -18,7 +20,7 @@ class ClearCaseSync : public QObject Q_OBJECT public: explicit ClearCaseSync(QSharedPointer statusMap); - void run(QFutureInterface &future, QStringList &files); + void run(QPromise &promise, QStringList &files); QStringList updateStatusHotFiles(const QString &viewRoot, int &total); void invalidateStatus(const QDir &viewRootDir, const QStringList &files); @@ -28,9 +30,8 @@ public: const int processed); void updateStatusForNotManagedFiles(const QStringList &files); - void syncDynamicView(QFutureInterface &future, - const ClearCaseSettings &settings); - void syncSnapshotView(QFutureInterface &future, QStringList &files, + void syncDynamicView(QPromise &promise, const ClearCaseSettings &settings); + void syncSnapshotView(QPromise &promise, QStringList &files, const ClearCaseSettings &settings); void processCleartoolLscheckoutLine(const QString &buffer); diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 6baa635080d..9d4aeec6980 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -45,7 +46,7 @@ public: class GitGrepRunner { - using FutureInterfaceType = QFutureInterface; + using PromiseType = QPromise; public: GitGrepRunner(const TextEditor::FileFindParameters ¶meters) @@ -116,7 +117,7 @@ public: } } - void read(FutureInterfaceType &fi, const QString &text) + void read(PromiseType &fi, const QString &text) { FileSearchResultList resultList; QString t = text; @@ -124,10 +125,10 @@ public: while (!stream.atEnd() && !fi.isCanceled()) processLine(stream.readLine(), &resultList); if (!resultList.isEmpty() && !fi.isCanceled()) - fi.reportResult(resultList); + fi.addResult(resultList); } - void operator()(FutureInterfaceType &fi) + void operator()(PromiseType &promise) { QStringList arguments = { "-c", "color.grep.match=bold red", @@ -165,7 +166,7 @@ public: process.setEnvironment(m_environment); process.setCommand({m_vcsBinary, arguments}); process.setWorkingDirectory(m_directory); - process.setStdOutCallback([this, &fi](const QString &text) { read(fi, text); }); + process.setStdOutCallback([this, &promise](const QString &text) { read(promise, text); }); process.start(); process.waitForFinished(); @@ -173,7 +174,7 @@ public: case ProcessResult::TerminatedAbnormally: case ProcessResult::StartFailed: case ProcessResult::Hang: - fi.reportCanceled(); + promise.future().cancel(); break; case ProcessResult::FinishedWithSuccess: case ProcessResult::FinishedWithError: @@ -275,7 +276,7 @@ void GitGrep::writeSettings(QSettings *settings) const QFuture GitGrep::executeSearch(const TextEditor::FileFindParameters ¶meters, TextEditor::BaseFileFind * /*baseFileFind*/) { - return Utils::runAsync(GitGrepRunner(parameters)); + return Utils::asyncRun(GitGrepRunner(parameters)); } IEditor *GitGrep::openEditor(const SearchResultItem &item, diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 23755d98751..8cc483cbf74 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include @@ -204,7 +204,7 @@ void GitSubmitEditor::updateFileModel() return; w->setUpdateInProgress(true); // TODO: Check if fetch works OK from separate thread, refactor otherwise - m_fetchWatcher.setFuture(Utils::runAsync(&CommitDataFetchResult::fetch, + m_fetchWatcher.setFuture(Utils::asyncRun(&CommitDataFetchResult::fetch, m_commitType, m_workingDirectory)); Core::ProgressManager::addTask(m_fetchWatcher.future(), Tr::tr("Refreshing Commit Data"), TASK_UPDATE_COMMIT); diff --git a/src/plugins/vcsbase/cleandialog.cpp b/src/plugins/vcsbase/cleandialog.cpp index bc5ddafe66d..487c7c7e1eb 100644 --- a/src/plugins/vcsbase/cleandialog.cpp +++ b/src/plugins/vcsbase/cleandialog.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include @@ -38,10 +38,10 @@ enum { nameColumn, columnCount }; enum { fileNameRole = Qt::UserRole, isDirectoryRole = Qt::UserRole + 1 }; // Helper for recursively removing files. -static void removeFileRecursion(QFutureInterface &futureInterface, - const QFileInfo &f, QString *errorMessage) +static void removeFileRecursion(QPromise &promise, const QFileInfo &f, + QString *errorMessage) { - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; // The version control system might list files/directory in arbitrary // order, causing files to be removed from parent directories. @@ -51,7 +51,7 @@ static void removeFileRecursion(QFutureInterface &futureInterface, const QDir dir(f.absoluteFilePath()); const QList infos = dir.entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Hidden); for (const QFileInfo &fi : infos) - removeFileRecursion(futureInterface, fi, errorMessage); + removeFileRecursion(promise, fi, errorMessage); QDir parent = f.absoluteDir(); if (!parent.rmdir(f.fileName())) errorMessage->append(Tr::tr("The directory %1 could not be deleted.") @@ -67,18 +67,19 @@ static void removeFileRecursion(QFutureInterface &futureInterface, } // Cleaning files in the background -static void runCleanFiles(QFutureInterface &futureInterface, - const FilePath &repository, const QStringList &files, +static void runCleanFiles(QPromise &promise, const FilePath &repository, + const QStringList &files, const std::function &errorHandler) { QString errorMessage; - futureInterface.setProgressRange(0, files.size()); - futureInterface.setProgressValue(0); + promise.setProgressRange(0, files.size()); + promise.setProgressValue(0); + int fileIndex = 0; for (const QString &name : files) { - removeFileRecursion(futureInterface, QFileInfo(name), &errorMessage); - if (futureInterface.isCanceled()) + removeFileRecursion(promise, QFileInfo(name), &errorMessage); + if (promise.isCanceled()) break; - futureInterface.setProgressValue(futureInterface.progressValue() + 1); + promise.setProgressValue(++fileIndex); } if (!errorMessage.isEmpty()) { // Format and emit error. @@ -258,8 +259,8 @@ bool CleanDialog::promptToDelete() return false; // Remove in background - QFuture task = runAsync(Internal::runCleanFiles, d->m_workingDirectory, - selectedFiles, Internal::handleError); + QFuture task = Utils::asyncRun(Internal::runCleanFiles, d->m_workingDirectory, + selectedFiles, Internal::handleError); const QString taskName = Tr::tr("Cleaning \"%1\"").arg(d->m_workingDirectory.toUserOutput()); Core::ProgressManager::addTask(task, taskName, "VcsBase.cleanRepository"); From 2baf59b87a59e0c7b1727d54de0ad24515d4f89e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 22:11:44 +0100 Subject: [PATCH 0189/1447] Meson: Use QtConcurrent invocation for async run Change-Id: I2b222a481a32edbea38d1784629b0a888c8b0c57 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/mesonprojectmanager/mesonprojectparser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp index 5a9babeedfd..6f8ce162ed7 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp +++ b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp @@ -12,8 +12,8 @@ #include +#include #include -#include #include #include @@ -197,7 +197,7 @@ QList MesonProjectParser::appsTargets() const bool MesonProjectParser::startParser() { - m_parserFutureResult = Utils::runAsync( + m_parserFutureResult = Utils::asyncRun( ProjectExplorer::ProjectExplorerPlugin::sharedThreadPool(), [processOutput = m_process.stdOut(), introType = m_introType, buildDir = m_buildDir.toString(), srcDir = m_srcDir] { From fad7bb9382b0f4df7b9a01fee535e21c55ba93c5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 4 Mar 2023 01:01:31 +0100 Subject: [PATCH 0190/1447] PluginInstallWizard: Use QtConcurrent invocation for async run Change-Id: I82fad61c765af283e5d5cee4d7262e13a6843a84 Reviewed-by: Eike Ziller Reviewed-by: --- .../coreplugin/plugininstallwizard.cpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index 6547c78835f..3587d211068 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -221,8 +222,8 @@ public: m_label->setText(Tr::tr("There was an error while unarchiving.")); } } else { // unarchiving was successful, run a check - m_archiveCheck = Utils::runAsync( - [this](QFutureInterface &fi) { return checkContents(fi); }); + m_archiveCheck = Utils::asyncRun([this](QPromise &promise) + { return checkContents(promise); }); Utils::onFinished(m_archiveCheck, this, [this](const QFuture &f) { m_cancelButton->setVisible(false); m_cancelButton->disconnect(); @@ -248,7 +249,7 @@ public: } // Async. Result is set if any issue was found. - void checkContents(QFutureInterface &fi) + void checkContents(QPromise &promise) { QTC_ASSERT(m_tempDir.get(), return ); @@ -260,7 +261,7 @@ public: QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories); while (it.hasNext()) { - if (fi.isCanceled()) + if (promise.isCanceled()) return; it.next(); PluginSpec *spec = PluginSpec::read(it.filePath()); @@ -275,18 +276,18 @@ public: }); if (found != dependencies.constEnd()) { if (!coreplugin->provides(found->name, found->version)) { - fi.reportResult({Tr::tr("Plugin requires an incompatible version of %1 (%2).") - .arg(Constants::IDE_DISPLAY_NAME) - .arg(found->version), - InfoLabel::Error}); + promise.addResult(ArchiveIssue{ + Tr::tr("Plugin requires an incompatible version of %1 (%2).") + .arg(Constants::IDE_DISPLAY_NAME).arg(found->version), + InfoLabel::Error}); return; } } return; // successful / no error } } - fi.reportResult({Tr::tr("Did not find %1 plugin.").arg(Constants::IDE_DISPLAY_NAME), - InfoLabel::Error}); + promise.addResult(ArchiveIssue{Tr::tr("Did not find %1 plugin.") + .arg(Constants::IDE_DISPLAY_NAME), InfoLabel::Error}); } void cleanupPage() final From c54317e47a77ff090e34c7fb18e56076e90ee38b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 7 Mar 2023 13:53:29 +0100 Subject: [PATCH 0191/1447] QmlDesigner: Remove unused PuppetDialog class Change-Id: I0939d28137fe5119df1c8c7c1203aef6c093aac5 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/CMakeLists.txt | 3 - .../designercore/instances/puppetdialog.cpp | 42 -------- .../designercore/instances/puppetdialog.h | 35 ------- .../designercore/instances/puppetdialog.ui | 96 ------------------- 4 files changed, 176 deletions(-) delete mode 100644 src/plugins/qmldesigner/designercore/instances/puppetdialog.cpp delete mode 100644 src/plugins/qmldesigner/designercore/instances/puppetdialog.h delete mode 100644 src/plugins/qmldesigner/designercore/instances/puppetdialog.ui diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 0c9992efe29..fae93b19a8f 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -82,7 +82,6 @@ extend_qtc_library(QmlDesignerCore set(UI_FILES ${CMAKE_CURRENT_LIST_DIR}/designercore/instances/puppetbuildprogressdialog.ui - ${CMAKE_CURRENT_LIST_DIR}/designercore/instances/puppetdialog.ui ) qt_wrap_ui(UI_SOURCES ${UI_FILES}) @@ -283,8 +282,6 @@ extend_qtc_library(QmlDesignerCore puppetstartdata.h puppetstarter.cpp puppetstarter.h - puppetdialog.cpp - puppetdialog.h qprocessuniqueptr.h ) diff --git a/src/plugins/qmldesigner/designercore/instances/puppetdialog.cpp b/src/plugins/qmldesigner/designercore/instances/puppetdialog.cpp deleted file mode 100644 index 935b5021680..00000000000 --- a/src/plugins/qmldesigner/designercore/instances/puppetdialog.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "puppetdialog.h" -#include "ui_puppetdialog.h" - -namespace QmlDesigner { - -PuppetDialog::PuppetDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::PuppetDialog) -{ - ui->setupUi(this); -} - -PuppetDialog::~PuppetDialog() -{ - delete ui; -} - -void PuppetDialog::setDescription(const QString &description) -{ - ui->descriptionLabel->setText(description); -} - -void PuppetDialog::setCopyAndPasteCode(const QString &text) -{ - ui->copyAndPasteTextEdit->setText(text); -} - -void PuppetDialog::warning(QWidget *parent, const QString &title, const QString &description, const QString ©AndPasteCode) -{ - PuppetDialog dialog(parent); - - dialog.setWindowTitle(title); - dialog.setDescription(description); - dialog.setCopyAndPasteCode(copyAndPasteCode); - - dialog.exec(); -} - -} //QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/puppetdialog.h b/src/plugins/qmldesigner/designercore/instances/puppetdialog.h deleted file mode 100644 index 32d0b8deb42..00000000000 --- a/src/plugins/qmldesigner/designercore/instances/puppetdialog.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace QmlDesigner { - -namespace Ui { -class PuppetDialog; -} - - -class PuppetDialog : public QDialog -{ - Q_OBJECT - -public: - explicit PuppetDialog(QWidget *parent = nullptr); - ~PuppetDialog() override; - - void setDescription(const QString &description); - void setCopyAndPasteCode(const QString &text); - - static void warning(QWidget *parent, - const QString &title, - const QString &description, - const QString ©AndPasteCode); - -private: - Ui::PuppetDialog *ui; -}; - -} //QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/puppetdialog.ui b/src/plugins/qmldesigner/designercore/instances/puppetdialog.ui deleted file mode 100644 index b7efa8c26c3..00000000000 --- a/src/plugins/qmldesigner/designercore/instances/puppetdialog.ui +++ /dev/null @@ -1,96 +0,0 @@ - - - QmlDesigner::PuppetDialog - - - - 0 - 0 - 1148 - 344 - - - - Dialog - - - - 12 - - - - - - 0 - 1 - - - - - - - true - - - - - - - - 0 - 1 - - - - true - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - - - - - - buttonBox - accepted() - QmlDesigner::PuppetDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - QmlDesigner::PuppetDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - From e3ce7cf2f97d971e542357bac81ce8418a41f10a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 9 Mar 2023 10:01:43 +0100 Subject: [PATCH 0192/1447] Utils: Fix build with Qt6.2 Change-Id: I00a0e562bf4c290e4bdc441abd422b2771ba0a53 Reviewed-by: Jarek Kobus Reviewed-by: Eike Ziller --- src/libs/utils/asynctask.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libs/utils/asynctask.cpp b/src/libs/utils/asynctask.cpp index 2f5aa4d27af..c2c42431d18 100644 --- a/src/libs/utils/asynctask.cpp +++ b/src/libs/utils/asynctask.cpp @@ -19,6 +19,16 @@ public: } }; +#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0) +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_idle, (QThread::IdlePriority)); +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_lowest, (QThread::LowestPriority)); +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_low, (QThread::LowPriority)); +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_normal, (QThread::NormalPriority)); +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_high, (QThread::HighPriority)); +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_highest, (QThread::HighestPriority)); +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_timeCritical, (QThread::TimeCriticalPriority)); +Q_GLOBAL_STATIC_WITH_ARGS(AsyncThreadPool, s_inherit, (QThread::InheritPriority)); +#else Q_GLOBAL_STATIC(AsyncThreadPool, s_idle, QThread::IdlePriority); Q_GLOBAL_STATIC(AsyncThreadPool, s_lowest, QThread::LowestPriority); Q_GLOBAL_STATIC(AsyncThreadPool, s_low, QThread::LowPriority); @@ -27,6 +37,7 @@ Q_GLOBAL_STATIC(AsyncThreadPool, s_high, QThread::HighPriority); Q_GLOBAL_STATIC(AsyncThreadPool, s_highest, QThread::HighestPriority); Q_GLOBAL_STATIC(AsyncThreadPool, s_timeCritical, QThread::TimeCriticalPriority); Q_GLOBAL_STATIC(AsyncThreadPool, s_inherit, QThread::InheritPriority); +#endif QThreadPool *asyncThreadPool(QThread::Priority priority) { From f670ceaa5e3b0cf710a69c73cb34cbabf2d14614 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 20:14:15 +0100 Subject: [PATCH 0193/1447] QbsBuildSystem: Use QtConcurrent invocation for async run Change-Id: I23024d31627d767ad74c8495abfa3d5042673f7d Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/qbsprojectmanager/qbsproject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index dc72660e7a3..ac27ba43f00 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -41,10 +41,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -483,7 +483,7 @@ void QbsBuildSystem::updateProjectNodes(const std::function &continuati if (continuation) continuation(); }); - m_treeCreationWatcher->setFuture(runAsync(ProjectExplorerPlugin::sharedThreadPool(), + m_treeCreationWatcher->setFuture(Utils::asyncRun(ProjectExplorerPlugin::sharedThreadPool(), QThread::LowPriority, &QbsNodeTreeBuilder::buildTree, project()->displayName(), project()->projectFilePath(), project()->projectDirectory(), projectData())); From d80b02de56406aeff9534960097b55f2286418da Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 23:57:21 +0100 Subject: [PATCH 0194/1447] StringTable: Use QtConcurrent invocation for async run Change-Id: I33da94ee9d564104edf4b93f1ae40d97adc407fd Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/libs/utils/stringtable.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/stringtable.cpp b/src/libs/utils/stringtable.cpp index 6345b80c32e..e501203a10a 100644 --- a/src/libs/utils/stringtable.cpp +++ b/src/libs/utils/stringtable.cpp @@ -3,7 +3,7 @@ #include "stringtable.h" -#include "runextensions.h" +#include "asynctask.h" #include #include @@ -34,7 +34,7 @@ public: void cancelAndWait(); QString insert(const QString &string); void startGC(); - void GC(QFutureInterface &futureInterface); + void GC(QPromise &promise); QFuture m_future; QMutex m_lock; @@ -90,7 +90,7 @@ void StringTablePrivate::startGC() { QMutexLocker locker(&m_lock); cancelAndWait(); - m_future = Utils::runAsync(&StringTablePrivate::GC, this); + m_future = Utils::asyncRun(&StringTablePrivate::GC, this); } QTCREATOR_UTILS_EXPORT void scheduleGC() @@ -113,7 +113,7 @@ static inline bool isQStringInUse(const QString &string) return data_ptr->isShared() || !data_ptr->isMutable() /* QStringLiteral ? */; } -void StringTablePrivate::GC(QFutureInterface &futureInterface) +void StringTablePrivate::GC(QPromise &promise) { int initialSize = 0; bytesSaved = 0; @@ -125,7 +125,7 @@ void StringTablePrivate::GC(QFutureInterface &futureInterface) // Collect all QStrings which have refcount 1. (One reference in m_strings and nowhere else.) for (QSet::iterator i = m_strings.begin(); i != m_strings.end();) { - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; if (!isQStringInUse(*i)) From adaf067e77dc4f5c7f630c040656ec6085889913 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 7 Mar 2023 15:48:57 +0100 Subject: [PATCH 0195/1447] CompilationDBParser: Use QtConcurrent invocation for async run Change-Id: I9649db2d7c890e89ddc3f5da36715b4fa6d5219b Reviewed-by: Christian Kandeler --- .../compilationdatabaseprojectmanager/compilationdbparser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index 251e9685c45..830d51439fc 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include @@ -95,7 +95,7 @@ void CompilationDbParser::start() } // Thread 2: Parse the project file. - const QFuture future = runAsync(&CompilationDbParser::parseProject, this); + const QFuture future = Utils::asyncRun(&CompilationDbParser::parseProject, this); Core::ProgressManager::addTask(future, Tr::tr("Parse \"%1\" project").arg(m_projectName), "CompilationDatabase.Parse"); From d6f5d07639c3d0313b758ba6fb7cc5eb57d188ef Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 7 Mar 2023 15:44:01 +0100 Subject: [PATCH 0196/1447] ClangCodeModel: Use QtConcurrent invocation for async run Change-Id: Id404d3a7699f12cdbc1e51390b3e5218ab3459b6 Reviewed-by: Christian Kandeler --- .../clangcodemodel/clangcodemodelplugin.cpp | 4 ++-- src/plugins/clangcodemodel/clangdclient.cpp | 5 ++-- .../clangdsemantichighlighting.cpp | 24 +++++++++---------- .../clangdsemantichighlighting.h | 8 +++++-- .../clangmodelmanagersupport.cpp | 4 ++-- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index b0250bf819a..c4f083592d1 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -34,9 +34,9 @@ #include +#include #include #include -#include #include using namespace Core; @@ -61,7 +61,7 @@ void ClangCodeModelPlugin::generateCompilationDB() baseDir = TemporaryDirectory::masterDirectoryFilePath(); QFuture task - = Utils::runAsync(&Internal::generateCompilationDB, ProjectInfoList{projectInfo}, + = Utils::asyncRun(&Internal::generateCompilationDB, ProjectInfoList{projectInfo}, baseDir, CompilationDbPurpose::Project, warningsConfigForProject(target->project()), globalClangOptions(), diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 238b46a09b4..3413f250380 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -14,7 +14,6 @@ #include "clangdquickfixes.h" #include "clangdsemantichighlighting.h" #include "clangdswitchdecldef.h" -#include "clangmodelmanagersupport.h" #include "clangtextmark.h" #include "clangutils.h" #include "tasktimers.h" @@ -58,10 +57,10 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -1469,7 +1468,7 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc, clangdVersion = q->versionNumber(), this] { try { - return Utils::runAsync(doSemanticHighlighting, filePath, tokens, text, ast, doc, + return Utils::asyncRun(doSemanticHighlighting, filePath, tokens, text, ast, doc, rev, clangdVersion, highlightingTimer); } catch (const std::exception &e) { qWarning() << "caught" << e.what() << "in main highlighting thread"; diff --git a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp index 14746f5ac79..939415d62db 100644 --- a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp +++ b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp @@ -112,7 +112,7 @@ static QList cleanupDisabledCode(HighlightingResults &results, const class ExtraHighlightingResultsCollector { public: - ExtraHighlightingResultsCollector(QFutureInterface &future, + ExtraHighlightingResultsCollector(QPromise &promise, HighlightingResults &results, const Utils::FilePath &filePath, const ClangdAstNode &ast, const QTextDocument *doc, const QString &docContent, @@ -131,7 +131,7 @@ private: void collectFromNode(const ClangdAstNode &node); void visitNode(const ClangdAstNode&node); - QFutureInterface &m_future; + QPromise &m_promise; HighlightingResults &m_results; const Utils::FilePath m_filePath; const ClangdAstNode &m_ast; @@ -142,7 +142,7 @@ private: }; void doSemanticHighlighting( - QFutureInterface &future, + QPromise &promise, const Utils::FilePath &filePath, const QList &tokens, const QString &docContents, @@ -153,10 +153,8 @@ void doSemanticHighlighting( const TaskTimer &taskTimer) { ThreadedSubtaskTimer t("highlighting", taskTimer); - if (future.isCanceled()) { - future.reportFinished(); + if (promise.isCanceled()) return; - } const QTextDocument doc(docContents); const auto tokenRange = [&doc](const ExpandedSemanticToken &token) { @@ -399,13 +397,13 @@ void doSemanticHighlighting( }; auto results = QtConcurrent::blockingMapped(tokens, safeToResult); const QList ifdefedOutBlocks = cleanupDisabledCode(results, &doc, docContents); - ExtraHighlightingResultsCollector(future, results, filePath, ast, &doc, docContents, + ExtraHighlightingResultsCollector(promise, results, filePath, ast, &doc, docContents, clangdVersion).collect(); Utils::erase(results, [](const HighlightingResult &res) { // QTCREATORBUG-28639 return res.textStyles.mainStyle == C_TEXT && res.textStyles.mixinStyles.empty(); }); - if (!future.isCanceled()) { + if (!promise.isCanceled()) { qCInfo(clangdLogHighlight) << "reporting" << results.size() << "highlighting results"; QMetaObject::invokeMethod(textDocument, [textDocument, ifdefedOutBlocks, docRevision] { if (textDocument && textDocument->document()->revision() == docRevision) @@ -423,16 +421,16 @@ void doSemanticHighlighting( if (ClangdClient * const client = ClangModelManagerSupport::clientForFile(filePath)) client->setVirtualRanges(filePath, virtualRanges, docRevision); }, Qt::QueuedConnection); - future.reportResults(QVector(results.cbegin(), results.cend())); + for (const HighlightingResult &r : results) + promise.addResult(r); } - future.reportFinished(); } ExtraHighlightingResultsCollector::ExtraHighlightingResultsCollector( - QFutureInterface &future, HighlightingResults &results, + QPromise &promise, HighlightingResults &results, const Utils::FilePath &filePath, const ClangdAstNode &ast, const QTextDocument *doc, const QString &docContent, const QVersionNumber &clangdVersion) - : m_future(future), m_results(results), m_filePath(filePath), m_ast(ast), m_doc(doc), + : m_promise(promise), m_results(results), m_filePath(filePath), m_ast(ast), m_doc(doc), m_docContent(docContent), m_clangdVersion(clangdVersion.majorVersion()) { } @@ -916,7 +914,7 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod void ExtraHighlightingResultsCollector::visitNode(const ClangdAstNode &node) { - if (m_future.isCanceled()) + if (m_promise.isCanceled()) return; const ClangdAstNode::FileStatus prevFileStatus = m_currentFileStatus; m_currentFileStatus = node.fileStatus(m_filePath); diff --git a/src/plugins/clangcodemodel/clangdsemantichighlighting.h b/src/plugins/clangcodemodel/clangdsemantichighlighting.h index 10bc4b8d091..a7f667d459f 100644 --- a/src/plugins/clangcodemodel/clangdsemantichighlighting.h +++ b/src/plugins/clangcodemodel/clangdsemantichighlighting.h @@ -3,11 +3,15 @@ #pragma once -#include #include #include #include +QT_BEGIN_NAMESPACE +template +class QPromise; +QT_END_NAMESPACE + namespace LanguageClient { class ExpandedSemanticToken; } namespace TextEditor { class HighlightingResult; @@ -21,7 +25,7 @@ class TaskTimer; Q_DECLARE_LOGGING_CATEGORY(clangdLogHighlight); void doSemanticHighlighting( - QFutureInterface &future, + QPromise &promise, const Utils::FilePath &filePath, const QList &tokens, const QString &docContents, diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 5e3a84c46ef..0cde889e45e 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -41,9 +41,9 @@ #include #include +#include #include #include -#include #include #include @@ -591,7 +591,7 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr }); const FilePath includeDir = settings.clangdIncludePath(); - auto future = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, + auto future = Utils::asyncRun(&Internal::generateCompilationDB, projectInfo, jsonDbDir, CompilationDbPurpose::CodeModel, warningsConfigForProject(project), globalClangOptions(), includeDir); From a8214665fe45f61668df380f045150258487a55a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 22:18:46 +0100 Subject: [PATCH 0197/1447] CppEditor: Use QtConcurrent invocation for async run Change-Id: Ibbac7f7788fe966c0dd846d68b7d17c43acadb0e Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../cppeditor/baseeditordocumentparser.cpp | 6 +- .../cppeditor/baseeditordocumentparser.h | 11 ++-- .../cppeditor/baseeditordocumentprocessor.cpp | 12 ++-- .../cppeditor/baseeditordocumentprocessor.h | 2 +- src/plugins/cppeditor/builtincursorinfo.cpp | 6 +- .../cppeditor/builtineditordocumentparser.cpp | 4 +- .../cppeditor/builtineditordocumentparser.h | 3 +- .../builtineditordocumentprocessor.cpp | 10 ++- src/plugins/cppeditor/cppfindreferences.cpp | 64 +++++++++---------- .../cppeditor/cppfunctiondecldeflink.cpp | 4 +- src/plugins/cppeditor/cppindexingsupport.cpp | 48 +++++++------- src/plugins/cppeditor/cppindexingsupport.h | 2 +- .../cppeditor/cppsemanticinfoupdater.cpp | 17 +++-- src/plugins/cppeditor/symbolsearcher_test.cpp | 6 +- src/plugins/cppeditor/symbolsfindfilter.cpp | 8 +-- 15 files changed, 97 insertions(+), 106 deletions(-) diff --git a/src/plugins/cppeditor/baseeditordocumentparser.cpp b/src/plugins/cppeditor/baseeditordocumentparser.cpp index 8a8d1bc9afd..d9bfc022e31 100644 --- a/src/plugins/cppeditor/baseeditordocumentparser.cpp +++ b/src/plugins/cppeditor/baseeditordocumentparser.cpp @@ -59,15 +59,15 @@ void BaseEditorDocumentParser::setConfiguration(const Configuration &configurati void BaseEditorDocumentParser::update(const UpdateParams &updateParams) { - QFutureInterface dummy; + QPromise dummy; update(dummy, updateParams); } -void BaseEditorDocumentParser::update(const QFutureInterface &future, +void BaseEditorDocumentParser::update(const QPromise &promise, const UpdateParams &updateParams) { QMutexLocker locker(&m_updateIsRunning); - updateImpl(future, updateParams); + updateImpl(promise, updateParams); } BaseEditorDocumentParser::State BaseEditorDocumentParser::state() const diff --git a/src/plugins/cppeditor/baseeditordocumentparser.h b/src/plugins/cppeditor/baseeditordocumentparser.h index fb7f79d1016..45f6b953990 100644 --- a/src/plugins/cppeditor/baseeditordocumentparser.h +++ b/src/plugins/cppeditor/baseeditordocumentparser.h @@ -6,14 +6,17 @@ #include "cppeditor_global.h" #include "cpptoolsreuse.h" #include "cppworkingcopy.h" -#include "projectpart.h" #include -#include #include #include +QT_BEGIN_NAMESPACE +template +class QPromise; +QT_END_NAMESPACE + namespace ProjectExplorer { class Project; } namespace CppEditor { @@ -66,7 +69,7 @@ public: void setConfiguration(const Configuration &configuration); void update(const UpdateParams &updateParams); - void update(const QFutureInterface &future, const UpdateParams &updateParams); + void update(const QPromise &promise, const UpdateParams &updateParams); ProjectPartInfo projectPartInfo() const; @@ -91,7 +94,7 @@ protected: mutable QMutex m_stateAndConfigurationMutex; private: - virtual void updateImpl(const QFutureInterface &future, + virtual void updateImpl(const QPromise &promise, const UpdateParams &updateParams) = 0; const Utils::FilePath m_filePath; diff --git a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp index 98784a1fb94..63ade2d3f74 100644 --- a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp @@ -59,20 +59,20 @@ void BaseEditorDocumentProcessor::setParserConfig( parser()->setConfiguration(config); } -void BaseEditorDocumentProcessor::runParser(QFutureInterface &future, +void BaseEditorDocumentProcessor::runParser(QPromise &promise, BaseEditorDocumentParser::Ptr parser, BaseEditorDocumentParser::UpdateParams updateParams) { - future.setProgressRange(0, 1); - if (future.isCanceled()) { - future.setProgressValue(1); + promise.setProgressRange(0, 1); + if (promise.isCanceled()) { + promise.setProgressValue(1); return; } - parser->update(future, updateParams); + parser->update(promise, updateParams); CppModelManager::instance()->finishedRefreshingSourceFiles({parser->filePath().toString()}); - future.setProgressValue(1); + promise.setProgressValue(1); } } // namespace CppEditor diff --git a/src/plugins/cppeditor/baseeditordocumentprocessor.h b/src/plugins/cppeditor/baseeditordocumentprocessor.h index afb74f46e64..5f341c06d96 100644 --- a/src/plugins/cppeditor/baseeditordocumentprocessor.h +++ b/src/plugins/cppeditor/baseeditordocumentprocessor.h @@ -83,7 +83,7 @@ signals: void semanticInfoUpdated(const SemanticInfo semanticInfo); // TODO: Remove me protected: - static void runParser(QFutureInterface &future, + static void runParser(QPromise &promise, BaseEditorDocumentParser::Ptr parser, BaseEditorDocumentParser::UpdateParams updateParams); diff --git a/src/plugins/cppeditor/builtincursorinfo.cpp b/src/plugins/cppeditor/builtincursorinfo.cpp index 14d99ce4db8..6a0897c2433 100644 --- a/src/plugins/cppeditor/builtincursorinfo.cpp +++ b/src/plugins/cppeditor/builtincursorinfo.cpp @@ -14,9 +14,9 @@ #include #include -#include +#include #include -#include +#include #include @@ -322,7 +322,7 @@ QFuture BuiltinCursorInfo::run(const CursorInfoParams &cursorInfoPar QString expression; Scope *scope = canonicalSymbol.getScopeAndExpression(textCursor, &expression); - return Utils::runAsync(&FindUses::find, document, snapshot, line, column, scope, expression); + return Utils::asyncRun(&FindUses::find, document, snapshot, line, column, scope, expression); } SemanticInfo::LocalUseMap diff --git a/src/plugins/cppeditor/builtineditordocumentparser.cpp b/src/plugins/cppeditor/builtineditordocumentparser.cpp index 60c768b3a15..efa97cf935c 100644 --- a/src/plugins/cppeditor/builtineditordocumentparser.cpp +++ b/src/plugins/cppeditor/builtineditordocumentparser.cpp @@ -42,7 +42,7 @@ BuiltinEditorDocumentParser::BuiltinEditorDocumentParser(const FilePath &filePat qRegisterMetaType("CPlusPlus::Snapshot"); } -void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface &future, +void BuiltinEditorDocumentParser::updateImpl(const QPromise &promise, const UpdateParams &updateParams) { if (filePath().isEmpty()) @@ -180,7 +180,7 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface &futur doc->releaseSourceAndAST(); }); sourceProcessor.setFileSizeLimitInMb(m_fileSizeLimitInMb); - sourceProcessor.setCancelChecker([future]() { return future.isCanceled(); }); + sourceProcessor.setCancelChecker([&promise] { return promise.isCanceled(); }); Snapshot globalSnapshot = modelManager->snapshot(); globalSnapshot.remove(filePath()); diff --git a/src/plugins/cppeditor/builtineditordocumentparser.h b/src/plugins/cppeditor/builtineditordocumentparser.h index b1a400a7c43..31ac126c694 100644 --- a/src/plugins/cppeditor/builtineditordocumentparser.h +++ b/src/plugins/cppeditor/builtineditordocumentparser.h @@ -34,8 +34,7 @@ public: static Ptr get(const Utils::FilePath &filePath); private: - void updateImpl(const QFutureInterface &future, - const UpdateParams &updateParams) override; + void updateImpl(const QPromise &promise, const UpdateParams &updateParams) override; void addFileAndDependencies(CPlusPlus::Snapshot *snapshot, QSet *toRemove, const Utils::FilePath &fileName) const; diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index c94a639eefb..0ea0c9c2dd7 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -18,9 +18,9 @@ #include #include -#include +#include #include -#include +#include #include #include @@ -180,10 +180,8 @@ BuiltinEditorDocumentProcessor::~BuiltinEditorDocumentProcessor() void BuiltinEditorDocumentProcessor::runImpl( const BaseEditorDocumentParser::UpdateParams &updateParams) { - m_parserFuture = Utils::runAsync(CppModelManager::instance()->sharedThreadPool(), - runParser, - parser(), - updateParams); + m_parserFuture = Utils::asyncRun(CppModelManager::instance()->sharedThreadPool(), + runParser, parser(), updateParams); } BaseEditorDocumentParser::Ptr BuiltinEditorDocumentProcessor::parser() diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index c553a5124b5..589ac2d1a67 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -25,8 +25,8 @@ #include #include +#include #include -#include #include #include @@ -220,7 +220,7 @@ class ProcessFile const CPlusPlus::Snapshot snapshot; CPlusPlus::Document::Ptr symbolDocument; CPlusPlus::Symbol *symbol; - QFutureInterface *future; + QPromise *m_promise; const bool categorize; public: @@ -232,22 +232,21 @@ public: const CPlusPlus::Snapshot snapshot, CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol, - QFutureInterface *future, + QPromise *promise, bool categorize) : workingCopy(workingCopy), snapshot(snapshot), symbolDocument(symbolDocument), symbol(symbol), - future(future), + m_promise(promise), categorize(categorize) { } QList operator()(const Utils::FilePath &filePath) { QList usages; - if (future->isPaused()) - future->waitForResume(); - if (future->isCanceled()) + m_promise->suspendIfRequested(); + if (m_promise->isCanceled()) return usages; const CPlusPlus::Identifier *symbolId = symbol->identifier(); @@ -277,25 +276,24 @@ public: usages = process.usages(); } - if (future->isPaused()) - future->waitForResume(); + m_promise->suspendIfRequested(); return usages; } }; class UpdateUI { - QFutureInterface *future; + QPromise *m_promise; public: - explicit UpdateUI(QFutureInterface *future): future(future) {} + explicit UpdateUI(QPromise *promise): m_promise(promise) {} void operator()(QList &, const QList &usages) { for (const CPlusPlus::Usage &u : usages) - future->reportResult(u); + m_promise->addResult(u); - future->setProgressValue(future->progressValue() + 1); + m_promise->setProgressValue(m_promise->future().progressValue() + 1); } }; @@ -321,7 +319,7 @@ QList CppFindReferences::references(CPlusPlus::Symbol *symbol, return references; } -static void find_helper(QFutureInterface &future, +static void find_helper(QPromise &promise, const WorkingCopy workingCopy, const CPlusPlus::LookupContext &context, CPlusPlus::Symbol *symbol, @@ -355,16 +353,16 @@ static void find_helper(QFutureInterface &future, } files = Utils::filteredUnique(files); - future.setProgressRange(0, files.size()); + promise.setProgressRange(0, files.size()); - ProcessFile process(workingCopy, snapshot, context.thisDocument(), symbol, &future, categorize); - UpdateUI reduce(&future); + ProcessFile process(workingCopy, snapshot, context.thisDocument(), symbol, &promise, categorize); + UpdateUI reduce(&promise); // This thread waits for blockingMappedReduced to finish, so reduce the pool's used thread count // so the blockingMappedReduced can use one more thread, and increase it again afterwards. QThreadPool::globalInstance()->releaseThread(); QtConcurrent::blockingMappedReduced > (files, process, reduce); QThreadPool::globalInstance()->reserveThread(); - future.setProgressValue(files.size()); + promise.setProgressValue(files.size()); } void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, @@ -439,7 +437,7 @@ void CppFindReferences::findAll_helper(SearchResult *search, CPlusPlus::Symbol * SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); const WorkingCopy workingCopy = m_modelManager->workingCopy(); QFuture result; - result = Utils::runAsync(m_modelManager->sharedThreadPool(), find_helper, + result = Utils::asyncRun(m_modelManager->sharedThreadPool(), find_helper, workingCopy, context, symbol, categorize); createWatcher(result, search); @@ -625,7 +623,7 @@ class FindMacroUsesInFile const WorkingCopy workingCopy; const CPlusPlus::Snapshot snapshot; const CPlusPlus::Macro ¯o; - QFutureInterface *future; + QPromise *m_promise; public: // needed by QtConcurrent @@ -635,8 +633,8 @@ public: FindMacroUsesInFile(const WorkingCopy &workingCopy, const CPlusPlus::Snapshot snapshot, const CPlusPlus::Macro ¯o, - QFutureInterface *future) - : workingCopy(workingCopy), snapshot(snapshot), macro(macro), future(future) + QPromise *promise) + : workingCopy(workingCopy), snapshot(snapshot), macro(macro), m_promise(promise) { } QList operator()(const Utils::FilePath &fileName) @@ -646,9 +644,8 @@ public: QByteArray source; restart_search: - if (future->isPaused()) - future->waitForResume(); - if (future->isCanceled()) + m_promise->suspendIfRequested(); + if (m_promise->isCanceled()) return usages; usages.clear(); @@ -676,8 +673,7 @@ restart_search: } } - if (future->isPaused()) - future->waitForResume(); + m_promise->suspendIfRequested(); return usages; } @@ -706,7 +702,7 @@ restart_search: } // end of anonymous namespace -static void findMacroUses_helper(QFutureInterface &future, +static void findMacroUses_helper(QPromise &promise, const WorkingCopy workingCopy, const CPlusPlus::Snapshot snapshot, const CPlusPlus::Macro macro) @@ -715,15 +711,15 @@ static void findMacroUses_helper(QFutureInterface &future, FilePaths files{sourceFile}; files = Utils::filteredUnique(files + snapshot.filesDependingOn(sourceFile)); - future.setProgressRange(0, files.size()); - FindMacroUsesInFile process(workingCopy, snapshot, macro, &future); - UpdateUI reduce(&future); + promise.setProgressRange(0, files.size()); + FindMacroUsesInFile process(workingCopy, snapshot, macro, &promise); + UpdateUI reduce(&promise); // This thread waits for blockingMappedReduced to finish, so reduce the pool's used thread count // so the blockingMappedReduced can use one more thread, and increase it again afterwards. QThreadPool::globalInstance()->releaseThread(); QtConcurrent::blockingMappedReduced > (files, process, reduce); QThreadPool::globalInstance()->reserveThread(); - future.setProgressValue(files.size()); + promise.setProgressValue(files.size()); } void CppFindReferences::findMacroUses(const CPlusPlus::Macro ¯o) @@ -773,7 +769,7 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro ¯o, const QStri } QFuture result; - result = Utils::runAsync(m_modelManager->sharedThreadPool(), findMacroUses_helper, + result = Utils::asyncRun(m_modelManager->sharedThreadPool(), findMacroUses_helper, workingCopy, snapshot, macro); createWatcher(result, search); @@ -834,7 +830,7 @@ void CppFindReferences::checkUnused(Core::SearchResult *search, const Link &link }); connect(search, &SearchResult::canceled, watcher, [watcher] { watcher->cancel(); }); connect(search, &SearchResult::destroyed, watcher, [watcher] { watcher->cancel(); }); - watcher->setFuture(Utils::runAsync(m_modelManager->sharedThreadPool(), find_helper, + watcher->setFuture(Utils::asyncRun(m_modelManager->sharedThreadPool(), find_helper, m_modelManager->workingCopy(), context, symbol, true)); } diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index fa271108cf0..d196261db22 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -21,9 +21,9 @@ #include #include +#include #include #include -#include #include #include @@ -232,7 +232,7 @@ void FunctionDeclDefLinkFinder::startFindLinkAt( // handle the rest in a thread m_watcher.reset(new QFutureWatcher >()); connect(m_watcher.data(), &QFutureWatcherBase::finished, this, &FunctionDeclDefLinkFinder::onFutureDone); - m_watcher->setFuture(Utils::runAsync(findLinkHelper, result, refactoringChanges)); + m_watcher->setFuture(Utils::asyncRun(findLinkHelper, result, refactoringChanges)); } bool FunctionDeclDefLink::isValid() const diff --git a/src/plugins/cppeditor/cppindexingsupport.cpp b/src/plugins/cppeditor/cppindexingsupport.cpp index 2d0e2b55194..4b415058862 100644 --- a/src/plugins/cppeditor/cppindexingsupport.cpp +++ b/src/plugins/cppeditor/cppindexingsupport.cpp @@ -15,8 +15,8 @@ #include +#include #include -#include #include #include @@ -116,8 +116,7 @@ void classifyFiles(const QSet &files, QStringList *headers, QStringList } } -void indexFindErrors(QFutureInterface &indexingFuture, - const ParseParams params) +void indexFindErrors(QPromise &promise, const ParseParams params) { QStringList sources, headers; classifyFiles(params.sourceFiles, &headers, &sources); @@ -130,7 +129,7 @@ void indexFindErrors(QFutureInterface &indexingFuture, timer.start(); for (int i = 0, end = files.size(); i < end ; ++i) { - if (indexingFuture.isCanceled()) + if (promise.isCanceled()) break; const QString file = files.at(i); @@ -153,15 +152,14 @@ void indexFindErrors(QFutureInterface &indexingFuture, document->releaseSourceAndAST(); - indexingFuture.setProgressValue(i + 1); + promise.setProgressValue(i + 1); } const QString elapsedTime = Utils::formatElapsedTime(timer.elapsed()); qDebug("FindErrorsIndexing: %s", qPrintable(elapsedTime)); } -void index(QFutureInterface &indexingFuture, - const ParseParams params) +void index(QPromise &promise, const ParseParams params) { QScopedPointer sourceProcessor(CppModelManager::createSourceProcessor()); sourceProcessor->setFileSizeLimitInMb(params.indexerFileSizeLimitInMb); @@ -190,7 +188,7 @@ void index(QFutureInterface &indexingFuture, qCDebug(indexerLog) << "About to index" << files.size() << "files."; for (int i = 0; i < files.size(); ++i) { - if (indexingFuture.isCanceled()) + if (promise.isCanceled()) break; const QString fileName = files.at(i); @@ -216,7 +214,7 @@ void index(QFutureInterface &indexingFuture, sourceProcessor->setHeaderPaths(headerPaths); sourceProcessor->run(FilePath::fromString(fileName)); - indexingFuture.setProgressValue(files.size() - sourceProcessor->todo().size()); + promise.setProgressValue(files.size() - sourceProcessor->todo().size()); if (isSourceFile) sourceProcessor->resetEnvironment(); @@ -224,29 +222,29 @@ void index(QFutureInterface &indexingFuture, qCDebug(indexerLog) << "Indexing finished."; } -void parse(QFutureInterface &indexingFuture, const ParseParams params) +void parse(QPromise &promise, const ParseParams params) { const QSet &files = params.sourceFiles; if (files.isEmpty()) return; - indexingFuture.setProgressRange(0, files.size()); + promise.setProgressRange(0, files.size()); if (CppIndexingSupport::isFindErrorsIndexingActive()) - indexFindErrors(indexingFuture, params); + indexFindErrors(promise, params); else - index(indexingFuture, params); + index(promise, params); - indexingFuture.setProgressValue(files.size()); + promise.setProgressValue(files.size()); CppModelManager::instance()->finishedRefreshingSourceFiles(files); } } // anonymous namespace -void SymbolSearcher::runSearch(QFutureInterface &future) +void SymbolSearcher::runSearch(QPromise &promise) { - future.setProgressRange(0, m_snapshot.size()); - future.setProgressValue(0); + promise.setProgressRange(0, m_snapshot.size()); + promise.setProgressValue(0); int progress = 0; SearchSymbols search; @@ -262,9 +260,8 @@ void SymbolSearcher::runSearch(QFutureInterface &future) : QRegularExpression::CaseInsensitiveOption)); matcher.optimize(); while (it != m_snapshot.end()) { - if (future.isPaused()) - future.waitForResume(); - if (future.isCanceled()) + promise.suspendIfRequested(); + if (promise.isCanceled()) break; if (m_fileNames.isEmpty() || m_fileNames.contains(it.value()->filePath().path())) { QVector resultItems; @@ -291,15 +288,14 @@ void SymbolSearcher::runSearch(QFutureInterface &future) return IndexItem::Recurse; }; search(it.value())->visitAllChildren(filter); - if (!resultItems.isEmpty()) - future.reportResults(resultItems); + for (const Core::SearchResultItem &item : std::as_const(resultItems)) + promise.addResult(item); } ++it; ++progress; - future.setProgressValue(progress); + promise.setProgressValue(progress); } - if (future.isPaused()) - future.waitForResume(); + promise.suspendIfRequested(); } CppIndexingSupport::CppIndexingSupport() @@ -325,7 +321,7 @@ QFuture CppIndexingSupport::refreshSourceFiles(const QSet &source params.workingCopy = mgr->workingCopy(); params.sourceFiles = sourceFiles; - QFuture result = Utils::runAsync(mgr->sharedThreadPool(), parse, params); + QFuture result = Utils::asyncRun(mgr->sharedThreadPool(), parse, params); m_synchronizer.addFuture(result); if (mode == CppModelManager::ForcedProgressNotification || sourceFiles.count() > 1) { diff --git a/src/plugins/cppeditor/cppindexingsupport.h b/src/plugins/cppeditor/cppindexingsupport.h index 584632a4f00..690c1be9b42 100644 --- a/src/plugins/cppeditor/cppindexingsupport.h +++ b/src/plugins/cppeditor/cppindexingsupport.h @@ -44,7 +44,7 @@ public: }; SymbolSearcher(const SymbolSearcher::Parameters ¶meters, const QSet &fileNames); - void runSearch(QFutureInterface &future); + void runSearch(QPromise &promise); private: const CPlusPlus::Snapshot m_snapshot; diff --git a/src/plugins/cppeditor/cppsemanticinfoupdater.cpp b/src/plugins/cppeditor/cppsemanticinfoupdater.cpp index 3e2438dbf80..349c722fb36 100644 --- a/src/plugins/cppeditor/cppsemanticinfoupdater.cpp +++ b/src/plugins/cppeditor/cppsemanticinfoupdater.cpp @@ -3,11 +3,10 @@ #include "cppsemanticinfoupdater.h" -#include "cpplocalsymbols.h" #include "cppmodelmanager.h" +#include #include -#include #include #include @@ -29,11 +28,11 @@ public: class FuturizedTopLevelDeclarationProcessor: public TopLevelDeclarationProcessor { public: - explicit FuturizedTopLevelDeclarationProcessor(QFutureInterface &future): m_future(future) {} + explicit FuturizedTopLevelDeclarationProcessor(QPromise &promise): m_promise(promise) {} bool processDeclaration(DeclarationAST *) override { return !isCanceled(); } - bool isCanceled() { return m_future.isCanceled(); } + bool isCanceled() { return m_promise.isCanceled(); } private: - QFutureInterface m_future; + QPromise &m_promise; }; public: @@ -49,7 +48,7 @@ public: bool reuseCurrentSemanticInfo(const SemanticInfo::Source &source, bool emitSignalWhenFinished); - void update_helper(QFutureInterface &future, const SemanticInfo::Source &source); + void update_helper(QPromise &promise, const SemanticInfo::Source &source); public: SemanticInfoUpdater *q; @@ -136,10 +135,10 @@ bool SemanticInfoUpdaterPrivate::reuseCurrentSemanticInfo(const SemanticInfo::So return false; } -void SemanticInfoUpdaterPrivate::update_helper(QFutureInterface &future, +void SemanticInfoUpdaterPrivate::update_helper(QPromise &promise, const SemanticInfo::Source &source) { - FuturizedTopLevelDeclarationProcessor processor(future); + FuturizedTopLevelDeclarationProcessor processor(promise); update(source, true, &processor); } @@ -179,7 +178,7 @@ void SemanticInfoUpdater::updateDetached(const SemanticInfo::Source &source) return; } - d->m_future = Utils::runAsync(CppModelManager::instance()->sharedThreadPool(), + d->m_future = Utils::asyncRun(CppModelManager::instance()->sharedThreadPool(), &SemanticInfoUpdaterPrivate::update_helper, d.data(), source); } diff --git a/src/plugins/cppeditor/symbolsearcher_test.cpp b/src/plugins/cppeditor/symbolsearcher_test.cpp index 9f700d99726..04b14b1002d 100644 --- a/src/plugins/cppeditor/symbolsearcher_test.cpp +++ b/src/plugins/cppeditor/symbolsearcher_test.cpp @@ -4,13 +4,13 @@ #include "symbolsearcher_test.h" #include "cppindexingsupport.h" -#include "cppmodelmanager.h" #include "cpptoolstestcase.h" #include "searchsymbols.h" #include #include -#include + +#include #include @@ -78,7 +78,7 @@ public: const QScopedPointer symbolSearcher( new SymbolSearcher(searchParameters, QSet{testFile})); QFuture search - = Utils::runAsync(&SymbolSearcher::runSearch, symbolSearcher.data()); + = Utils::asyncRun(&SymbolSearcher::runSearch, symbolSearcher.data()); search.waitForFinished(); ResultDataList results = ResultData::fromSearchResultList(search.results()); QCOMPARE(results, expectedResults); diff --git a/src/plugins/cppeditor/symbolsfindfilter.cpp b/src/plugins/cppeditor/symbolsfindfilter.cpp index 0317d0ee98d..acfbdaf298b 100644 --- a/src/plugins/cppeditor/symbolsfindfilter.cpp +++ b/src/plugins/cppeditor/symbolsfindfilter.cpp @@ -18,13 +18,13 @@ #include #include -#include +#include #include -#include +#include #include #include -#include +#include using namespace Core; using namespace Utils; @@ -121,7 +121,7 @@ void SymbolsFindFilter::startSearch(SearchResult *search) SymbolSearcher *symbolSearcher = new SymbolSearcher(parameters, projectFileNames); connect(watcher, &QFutureWatcherBase::finished, symbolSearcher, &QObject::deleteLater); - watcher->setFuture(Utils::runAsync(m_manager->sharedThreadPool(), + watcher->setFuture(Utils::asyncRun(m_manager->sharedThreadPool(), &SymbolSearcher::runSearch, symbolSearcher)); FutureProgress *progress = ProgressManager::addTask(watcher->future(), Tr::tr("Searching for Symbol"), Core::Constants::TASK_SEARCH); From 5ff073df19b872b8db601f31e1124c6048a89a3c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 11 Feb 2023 23:21:58 +0100 Subject: [PATCH 0198/1447] DiffEditor: Use QtConcurrent invocation for async tasks Change-Id: I06640837ffee830e60e8dd2a566f9388f8444010 Reviewed-by: Orgad Shaneh --- src/libs/utils/differ.cpp | 25 ++--- src/libs/utils/differ.h | 6 +- src/plugins/diffeditor/diffeditordocument.cpp | 6 +- src/plugins/diffeditor/diffeditorplugin.cpp | 27 +++-- src/plugins/diffeditor/diffutils.cpp | 101 +++++++----------- src/plugins/diffeditor/diffutils.h | 8 +- .../diffeditor/sidebysidediffeditorwidget.cpp | 44 ++++---- .../diffeditor/sidebysidediffeditorwidget.h | 4 +- .../diffeditor/unifieddiffeditorwidget.cpp | 42 ++++---- .../diffeditor/unifieddiffeditorwidget.h | 8 +- .../vcsbase/vcsbasediffeditorcontroller.cpp | 13 +-- 11 files changed, 114 insertions(+), 170 deletions(-) diff --git a/src/libs/utils/differ.cpp b/src/libs/utils/differ.cpp index 538aa6657ab..b1c163bb5b4 100644 --- a/src/libs/utils/differ.cpp +++ b/src/libs/utils/differ.cpp @@ -14,11 +14,10 @@ publication by Neil Fraser: http://neil.fraser.name/writing/diff/ #include "utilstr.h" #include -#include -#include #include #include -#include +#include +#include namespace Utils { @@ -937,10 +936,9 @@ QString Diff::toString() const /////////////// -Differ::Differ(QFutureInterfaceBase *jobController) - : m_jobController(jobController) +Differ::Differ(const QFuture &future) + : m_future(future) { - } QList Differ::diff(const QString &text1, const QString &text2) @@ -1075,7 +1073,7 @@ QList Differ::diffMyers(const QString &text1, const QString &text2) int kMinReverse = -D; int kMaxReverse = D; for (int d = 0; d <= D; d++) { - if (m_jobController && m_jobController->isCanceled()) { + if (m_future.isCanceled()) { delete [] forwardV; delete [] reverseV; return QList(); @@ -1193,17 +1191,10 @@ QList Differ::diffNonCharMode(const QString &text1, const QString &text2) QString lastDelete; QString lastInsert; QList newDiffList; - if (m_jobController) { - m_jobController->setProgressRange(0, diffList.count()); - m_jobController->setProgressValue(0); - } for (int i = 0; i <= diffList.count(); i++) { - if (m_jobController) { - if (m_jobController->isCanceled()) { - m_currentDiffMode = diffMode; - return QList(); - } - m_jobController->setProgressValue(i + 1); + if (m_future.isCanceled()) { + m_currentDiffMode = diffMode; + return {}; } const Diff diffItem = i < diffList.count() ? diffList.at(i) diff --git a/src/libs/utils/differ.h b/src/libs/utils/differ.h index 62b8bc7ec46..09b79652225 100644 --- a/src/libs/utils/differ.h +++ b/src/libs/utils/differ.h @@ -5,12 +5,12 @@ #include "utils_global.h" +#include #include QT_BEGIN_NAMESPACE template class QMap; -class QFutureInterfaceBase; QT_END_NAMESPACE namespace Utils { @@ -42,7 +42,7 @@ public: WordMode, LineMode }; - Differ(QFutureInterfaceBase *jobController = nullptr); + Differ(const QFuture &future = {}); QList diff(const QString &text1, const QString &text2); QList unifiedDiff(const QString &text1, const QString &text2); void setDiffMode(DiffMode mode); @@ -90,7 +90,7 @@ private: int subTextStart); DiffMode m_diffMode = Differ::LineMode; DiffMode m_currentDiffMode = Differ::LineMode; - QFutureInterfaceBase *m_jobController = nullptr; + QFuture m_future; }; } // namespace Utils diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index 05b1684c8a3..1d43064d60f 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -291,8 +291,8 @@ Core::IDocument::OpenResult DiffEditorDocument::open(QString *errorString, const return OpenResult::ReadError; } - bool ok = false; - QList fileDataList = DiffUtils::readPatch(patch, &ok); + const std::optional> fileDataList = DiffUtils::readPatch(patch); + bool ok = fileDataList.has_value(); if (!ok) { *errorString = Tr::tr("Could not parse patch file \"%1\". " "The content is not of unified diff format.") @@ -302,7 +302,7 @@ Core::IDocument::OpenResult DiffEditorDocument::open(QString *errorString, const emit temporaryStateChanged(); setFilePath(filePath.absoluteFilePath()); setWorkingDirectory(filePath.absoluteFilePath()); - setDiffFiles(fileDataList); + setDiffFiles(*fileDataList); } endReload(ok); if (!ok && readResult == TextFileFormat::ReadEncodingError) diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 29020755ea7..6ae5f816c30 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -47,13 +47,12 @@ public: m_ignoreWhitespace(ignoreWhitespace) {} - void operator()(QFutureInterface &futureInterface, - const ReloadInput &reloadInput) const + void operator()(QPromise &promise, const ReloadInput &reloadInput) const { if (reloadInput.text[LeftSide] == reloadInput.text[RightSide]) return; // We show "No difference" in this case, regardless if it's binary or not - Differ differ(&futureInterface); + Differ differ(QFuture(promise.future())); FileData fileData; if (!reloadInput.binaryFiles) { @@ -85,7 +84,7 @@ public: fileData.fileInfo = reloadInput.fileInfo; fileData.fileOperation = reloadInput.fileOperation; fileData.binaryFiles = reloadInput.binaryFiles; - futureInterface.reportResult(fileData); + promise.addResult(fileData); } private: @@ -115,7 +114,7 @@ DiffFilesController::DiffFilesController(IDocument *document) QList> *outputList = storage.activeStorage(); const auto setupDiff = [this](AsyncTask &async, const ReloadInput &reloadInput) { - async.setAsyncCallData(DiffFile(ignoreWhitespace(), contextLineCount()), reloadInput); + async.setConcurrentCallData(DiffFile(ignoreWhitespace(), contextLineCount()), reloadInput); async.setFutureSynchronizer(Internal::DiffEditorPlugin::futureSynchronizer()); }; const auto onDiffDone = [outputList](const AsyncTask &async, int i) { @@ -771,13 +770,13 @@ void DiffEditor::Internal::DiffEditorPlugin::testMakePatch() QCOMPARE(result, patchText); - bool ok; - QList resultList = DiffUtils::readPatch(result, &ok); + const std::optional> resultList = DiffUtils::readPatch(result); + const bool ok = resultList.has_value(); QVERIFY(ok); - QCOMPARE(resultList.count(), 1); - for (int i = 0; i < resultList.count(); i++) { - const FileData &resultFileData = resultList.at(i); + QCOMPARE(resultList->count(), 1); + for (int i = 0; i < resultList->count(); i++) { + const FileData &resultFileData = resultList->at(i); QCOMPARE(resultFileData.fileInfo[LeftSide].fileName, fileName); QCOMPARE(resultFileData.fileInfo[RightSide].fileName, fileName); QCOMPARE(resultFileData.chunks.count(), 1); @@ -1335,14 +1334,14 @@ void DiffEditor::Internal::DiffEditorPlugin::testReadPatch() QFETCH(QString, sourcePatch); QFETCH(QList, fileDataList); - bool ok; - const QList &result = DiffUtils::readPatch(sourcePatch, &ok); + const std::optional> result = DiffUtils::readPatch(sourcePatch); + const bool ok = result.has_value(); QVERIFY(ok); - QCOMPARE(result.count(), fileDataList.count()); + QCOMPARE(result->count(), fileDataList.count()); for (int i = 0; i < fileDataList.count(); i++) { const FileData &origFileData = fileDataList.at(i); - const FileData &resultFileData = result.at(i); + const FileData &resultFileData = result->at(i); QCOMPARE(resultFileData.fileInfo[LeftSide].fileName, origFileData.fileInfo[LeftSide].fileName); QCOMPARE(resultFileData.fileInfo[LeftSide].typeInfo, origFileData.fileInfo[LeftSide].typeInfo); QCOMPARE(resultFileData.fileInfo[RightSide].fileName, origFileData.fileInfo[RightSide].fileName); diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index f9d7d6b264a..efea3530a43 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include #include @@ -892,7 +893,7 @@ static FileData readDiffHeaderAndChunks(QStringView headerAndChunks, bool *ok) } -static QList readDiffPatch(QStringView patch, bool *ok, QFutureInterfaceBase *jobController) +static void readDiffPatch(QPromise> &promise, QStringView patch) { const QRegularExpression diffRegExp("(?:\\n|^)" // new line of the beginning of a patch "(" // either @@ -911,23 +912,20 @@ static QList readDiffPatch(QStringView patch, bool *ok, QFutureInterfa ")"); // end of or bool readOk = false; - QList fileDataList; - QRegularExpressionMatch diffMatch = diffRegExp.match(patch); if (diffMatch.hasMatch()) { readOk = true; int lastPos = -1; do { - if (jobController && jobController->isCanceled()) - return {}; + if (promise.isCanceled()) + return; int pos = diffMatch.capturedStart(); if (lastPos >= 0) { QStringView headerAndChunks = patch.mid(lastPos, pos - lastPos); - const FileData fileData = readDiffHeaderAndChunks(headerAndChunks, - &readOk); + const FileData fileData = readDiffHeaderAndChunks(headerAndChunks, &readOk); if (!readOk) break; @@ -942,21 +940,15 @@ static QList readDiffPatch(QStringView patch, bool *ok, QFutureInterfa if (readOk) { QStringView headerAndChunks = patch.mid(lastPos, patch.size() - lastPos - 1); - const FileData fileData = readDiffHeaderAndChunks(headerAndChunks, - &readOk); + const FileData fileData = readDiffHeaderAndChunks(headerAndChunks, &readOk); if (readOk) fileDataList.append(fileData); } } - - if (ok) - *ok = readOk; - if (!readOk) - return {}; - - return fileDataList; + return; + promise.addResult(fileDataList); } // The git diff patch format (ChangeFile, NewFile, DeleteFile) @@ -1203,7 +1195,7 @@ static bool detectFileData(QStringView patch, FileData *fileData, QStringView *r return detectIndexAndBinary(*remainingPatch, fileData, remainingPatch); } -static QList readGitPatch(QStringView patch, bool *ok, QFutureInterfaceBase *jobController) +static void readGitPatch(QPromise> &promise, QStringView patch) { int position = -1; @@ -1221,13 +1213,12 @@ static QList readGitPatch(QStringView patch, bool *ok, QFutureInterfac }; const QChar newLine('\n'); - bool readOk = true; QVector patches; const int count = startingPositions.size(); for (int i = 0; i < count; i++) { - if (jobController && jobController->isCanceled()) - return {}; + if (promise.isCanceled()) + return; const int diffStart = startingPositions.at(i); const int diffEnd = (i < count - 1) @@ -1242,32 +1233,21 @@ static QList readGitPatch(QStringView patch, bool *ok, QFutureInterfac FileData fileData; QStringView remainingFileDiff; - readOk = detectFileData(fileDiff, &fileData, &remainingFileDiff); - - if (!readOk) - break; + if (!detectFileData(fileDiff, &fileData, &remainingFileDiff)) + return; patches.append(PatchInfo { remainingFileDiff, fileData }); } - if (!readOk) { - if (ok) - *ok = readOk; - return {}; - } - - if (jobController) - jobController->setProgressRange(0, patches.size()); + promise.setProgressRange(0, patches.size()); QList fileDataList; - readOk = false; + bool readOk = false; int i = 0; for (const auto &patchInfo : std::as_const(patches)) { - if (jobController) { - if (jobController->isCanceled()) - return {}; - jobController->setProgressValue(i++); - } + if (promise.isCanceled()) + return; + promise.setProgressValue(i++); FileData fileData = patchInfo.fileData; if (!patchInfo.patch.isEmpty() || fileData.fileOperation == FileData::ChangeFile) @@ -1276,31 +1256,27 @@ static QList readGitPatch(QStringView patch, bool *ok, QFutureInterfac readOk = true; if (!readOk) - break; + return; fileDataList.append(fileData); } - - if (ok) - *ok = readOk; - - if (!readOk) - return {}; - - return fileDataList; + promise.addResult(fileDataList); } -QList DiffUtils::readPatch(const QString &patch, bool *ok, - QFutureInterfaceBase *jobController) +std::optional> DiffUtils::readPatch(const QString &patch) { - bool readOk = false; + QPromise> promise; + promise.start(); + readPatchWithPromise(promise, patch); + if (promise.future().resultCount() == 0) + return {}; + return promise.future().result(); +} - QList fileDataList; - - if (jobController) { - jobController->setProgressRange(0, 1); - jobController->setProgressValue(0); - } +void DiffUtils::readPatchWithPromise(QPromise> &promise, const QString &patch) +{ + promise.setProgressRange(0, 1); + promise.setProgressValue(0); QStringView croppedPatch = QStringView(patch); // Crop e.g. "-- \n2.10.2.windows.1\n\n" at end of file const QRegularExpression formatPatchEndingRegExp("(\\n-- \\n\\S*\\n\\n$)"); @@ -1308,14 +1284,9 @@ QList DiffUtils::readPatch(const QString &patch, bool *ok, if (match.hasMatch()) croppedPatch = croppedPatch.left(match.capturedStart() + 1); - fileDataList = readGitPatch(croppedPatch, &readOk, jobController); - if (!readOk) - fileDataList = readDiffPatch(croppedPatch, &readOk, jobController); - - if (ok) - *ok = readOk; - - return fileDataList; + readGitPatch(promise, croppedPatch); + if (promise.future().resultCount() == 0) + readDiffPatch(promise, croppedPatch); } } // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffutils.h b/src/plugins/diffeditor/diffutils.h index 65fcda46786..e128f01012c 100644 --- a/src/plugins/diffeditor/diffutils.h +++ b/src/plugins/diffeditor/diffutils.h @@ -14,7 +14,8 @@ #include QT_BEGIN_NAMESPACE -class QFutureInterfaceBase; +template +class QPromise; QT_END_NAMESPACE namespace Utils { class Diff; } @@ -142,9 +143,8 @@ public: const QString &rightFileName, bool lastChunk = false); static QString makePatch(const QList &fileDataList); - static QList readPatch(const QString &patch, - bool *ok = nullptr, - QFutureInterfaceBase *jobController = nullptr); + static std::optional> readPatch(const QString &patch); + static void readPatchWithPromise(QPromise> &promise, const QString &patch); }; } // namespace DiffEditor diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index da69e607840..3bff22f030f 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -8,14 +8,8 @@ #include "diffeditorplugin.h" #include "diffeditortr.h" -#include -#include -#include -#include -#include - -#include #include +#include #include #include @@ -29,6 +23,11 @@ #include #include +#include +#include +#include +#include + using namespace Core; using namespace TextEditor; using namespace Utils; @@ -245,7 +244,7 @@ QString SideDiffEditorWidget::plainTextFromSelection(const QTextCursor &cursor) return TextDocument::convertToPlainText(text); } -SideBySideDiffOutput SideDiffData::diffOutput(QFutureInterface &fi, int progressMin, +SideBySideDiffOutput SideDiffData::diffOutput(QFutureInterfaceBase &fi, int progressMin, int progressMax, const DiffEditorInput &input) { SideBySideDiffOutput output; @@ -914,19 +913,15 @@ void SideBySideDiffEditorWidget::showDiff() const DiffEditorInput input(&m_controller); - auto getDocument = [input](QFutureInterface &futureInterface) { - auto cleanup = qScopeGuard([&futureInterface] { - if (futureInterface.isCanceled()) - futureInterface.reportCanceled(); - }); + auto getDocument = [input](QPromise &promise) { const int firstPartMax = 20; // diffOutput is about 4 times quicker than filling document const int leftPartMax = 60; const int rightPartMax = 100; - futureInterface.setProgressRange(0, rightPartMax); - futureInterface.setProgressValue(0); - QFutureInterface fi = futureInterface; + promise.setProgressRange(0, rightPartMax); + promise.setProgressValue(0); + QFutureInterfaceBase fi = QFutureInterfaceBase::get(promise.future()); const SideBySideDiffOutput output = SideDiffData::diffOutput(fi, 0, firstPartMax, input); - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; const ShowResult leftResult{TextDocumentPtr(new TextDocument("DiffEditor.SideDiffEditor")), @@ -935,7 +930,7 @@ void SideBySideDiffEditorWidget::showDiff() output.side[RightSide].diffData, output.side[RightSide].selections}; const ShowResults result{leftResult, rightResult}; - auto propagateDocument = [&output, &fi](DiffSide side, const ShowResult &result, + auto propagateDocument = [&output, &promise](DiffSide side, const ShowResult &result, int progressMin, int progressMax) { // No need to store the change history result.textDocument->document()->setUndoRedoEnabled(false); @@ -952,8 +947,9 @@ void SideBySideDiffEditorWidget::showDiff() const QString package = output.side[side].diffText.mid(currentPos, packageSize); cursor.insertText(package); currentPos += package.size(); - fi.setProgressValue(MathUtils::interpolateLinear(currentPos, 0, diffSize, progressMin, progressMax)); - if (fi.isCanceled()) + promise.setProgressValue(MathUtils::interpolateLinear(currentPos, 0, diffSize, + progressMin, progressMax)); + if (promise.isCanceled()) return; } @@ -968,16 +964,16 @@ void SideBySideDiffEditorWidget::showDiff() }; propagateDocument(LeftSide, leftResult, firstPartMax, leftPartMax); - if (fi.isCanceled()) + if (promise.isCanceled()) return; propagateDocument(RightSide, rightResult, leftPartMax, rightPartMax); - if (fi.isCanceled()) + if (promise.isCanceled()) return; - futureInterface.reportResult(result); + promise.addResult(result); }; - m_asyncTask->setAsyncCallData(getDocument); + m_asyncTask->setConcurrentCallData(getDocument); m_asyncTask->start(); ProgressManager::addTask(m_asyncTask->future(), Tr::tr("Rendering diff"), "DiffEditor"); } diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index 21225fa5580..e85e341b936 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -7,7 +7,6 @@ #include "diffeditorwidgetcontroller.h" #include "selectabletexteditorwidget.h" // TODO: we need DiffSelections here only -#include #include namespace Core { class IContext; } @@ -23,6 +22,7 @@ class AsyncTask; } QT_BEGIN_NAMESPACE +class QFutureInterfaceBase; class QMenu; class QSplitter; QT_END_NAMESPACE @@ -40,7 +40,7 @@ class SideBySideDiffOutput; class SideDiffData { public: - static SideBySideDiffOutput diffOutput(QFutureInterface &fi, int progressMin, + static SideBySideDiffOutput diffOutput(QFutureInterfaceBase &fi, int progressMin, int progressMax, const DiffEditorInput &input); DiffChunkInfo m_chunkInfo; diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index b937b919f7c..82ba5e51fa4 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -8,23 +8,20 @@ #include "diffeditorplugin.h" #include "diffeditortr.h" -#include -#include -#include -#include - #include #include #include #include -#include #include #include #include #include -#include + +#include +#include +#include using namespace Core; using namespace TextEditor; @@ -48,10 +45,10 @@ UnifiedDiffEditorWidget::UnifiedDiffEditorWidget(QWidget *parent) connect(this, &QPlainTextEdit::cursorPositionChanged, this, &UnifiedDiffEditorWidget::slotCursorPositionChangedInEditor); - auto context = new Core::IContext(this); + auto context = new IContext(this); context->setWidget(this); - context->setContext(Core::Context(Constants::UNIFIED_VIEW_ID)); - Core::ICore::addContextObject(context); + context->setContext(Context(Constants::UNIFIED_VIEW_ID)); + ICore::addContextObject(context); } UnifiedDiffEditorWidget::~UnifiedDiffEditorWidget() = default; @@ -391,7 +388,7 @@ QString UnifiedDiffData::setChunk(const DiffEditorInput &input, const ChunkData return diffText; } -UnifiedDiffOutput UnifiedDiffData::diffOutput(QFutureInterface &fi, int progressMin, +UnifiedDiffOutput UnifiedDiffData::diffOutput(QFutureInterfaceBase &fi, int progressMin, int progressMax, const DiffEditorInput &input) { UnifiedDiffOutput output; @@ -481,18 +478,14 @@ void UnifiedDiffEditorWidget::showDiff() const DiffEditorInput input(&m_controller); - auto getDocument = [input](QFutureInterface &futureInterface) { - auto cleanup = qScopeGuard([&futureInterface] { - if (futureInterface.isCanceled()) - futureInterface.reportCanceled(); - }); + auto getDocument = [input](QPromise &promise) { const int progressMax = 100; const int firstPartMax = 20; // diffOutput is about 4 times quicker than filling document - futureInterface.setProgressRange(0, progressMax); - futureInterface.setProgressValue(0); - QFutureInterface fi = futureInterface; + promise.setProgressRange(0, progressMax); + promise.setProgressValue(0); + QFutureInterfaceBase fi = QFutureInterfaceBase::get(promise.future()); const UnifiedDiffOutput output = UnifiedDiffData::diffOutput(fi, 0, firstPartMax, input); - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; const ShowResult result = {TextDocumentPtr(new TextDocument("DiffEditor.UnifiedDiffEditor")), @@ -512,8 +505,9 @@ void UnifiedDiffEditorWidget::showDiff() const QString package = output.diffText.mid(currentPos, packageSize); cursor.insertText(package); currentPos += package.size(); - fi.setProgressValue(MathUtils::interpolateLinear(currentPos, 0, diffSize, firstPartMax, progressMax)); - if (futureInterface.isCanceled()) + promise.setProgressValue(MathUtils::interpolateLinear(currentPos, 0, diffSize, + firstPartMax, progressMax)); + if (promise.isCanceled()) return; } @@ -525,10 +519,10 @@ void UnifiedDiffEditorWidget::showDiff() // to caller's thread. We push it to no thread (make object to have no thread affinity), // and later, in the caller's thread, we pull it back to the caller's thread. result.textDocument->moveToThread(nullptr); - futureInterface.reportResult(result); + promise.addResult(result); }; - m_asyncTask->setAsyncCallData(getDocument); + m_asyncTask->setConcurrentCallData(getDocument); m_asyncTask->start(); ProgressManager::addTask(m_asyncTask->future(), Tr::tr("Rendering diff"), "DiffEditor"); } diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h index 842eec9ea36..027f8830ab4 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.h +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h @@ -6,8 +6,6 @@ #include "diffeditorwidgetcontroller.h" #include "selectabletexteditorwidget.h" -#include - namespace Core { class IContext; } namespace TextEditor { class FontSettings; } @@ -17,6 +15,10 @@ template class AsyncTask; } +QT_BEGIN_NAMESPACE +class QFutureInterfaceBase; +QT_END_NAMESPACE + namespace DiffEditor { class ChunkData; @@ -31,7 +33,7 @@ class UnifiedDiffOutput; class UnifiedDiffData { public: - static UnifiedDiffOutput diffOutput(QFutureInterface &fi, int progressMin, int progressMax, + static UnifiedDiffOutput diffOutput(QFutureInterfaceBase &fi, int progressMin, int progressMax, const DiffEditorInput &input); DiffChunkInfo m_chunkInfo; diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index c0d31775af9..65e425cf64b 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -15,15 +15,6 @@ using namespace Utils; namespace VcsBase { -static void readPatch(QFutureInterface> &futureInterface, const QString &patch) -{ - bool ok; - const QList &fileDataList = DiffUtils::readPatch(patch, &ok, &futureInterface); - futureInterface.reportResult(fileDataList); -} - -///////////////////// - class VcsBaseDiffEditorControllerPrivate { public: @@ -61,11 +52,11 @@ Tasking::TaskItem VcsBaseDiffEditorController::postProcessTask() QTC_ASSERT(storage, qWarning("Using postProcessTask() requires putting inputStorage() " "into task tree's root group.")); const QString inputData = storage ? *storage : QString(); - async.setAsyncCallData(readPatch, inputData); + async.setConcurrentCallData(&DiffUtils::readPatchWithPromise, inputData); async.setFutureSynchronizer(Internal::VcsPlugin::futureSynchronizer()); }; const auto onDiffProcessorDone = [this](const AsyncTask> &async) { - setDiffFiles(async.result()); + setDiffFiles(async.isResultAvailable() ? async.result() : QList()); }; const auto onDiffProcessorError = [this](const AsyncTask> &) { setDiffFiles({}); From ab523ee083b2a446919dec9f2299a52a6398774e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 21:29:50 +0100 Subject: [PATCH 0199/1447] ProjectExplorer: Use QtConcurrent invocation for async run Change-Id: I7c09b3c299eae1b0672a8bf8ba8dcc71a9d4feef Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- src/plugins/projectexplorer/msvctoolchain.cpp | 22 ++++++---------- src/plugins/projectexplorer/msvctoolchain.h | 5 ++-- .../projectexplorer/projectnodeshelper.h | 26 +++++++++---------- .../projectexplorer/selectablefilesmodel.cpp | 14 +++++----- .../projectexplorer/selectablefilesmodel.h | 6 ++--- src/plugins/projectexplorer/treescanner.cpp | 16 ++++++------ src/plugins/projectexplorer/treescanner.h | 4 +-- 7 files changed, 42 insertions(+), 51 deletions(-) diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index d0856e29d44..d7b036ead81 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -14,12 +14,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include @@ -747,10 +747,8 @@ static QString winExpandDelayedEnvReferences(QString in, const Utils::Environmen return in; } -void MsvcToolChain::environmentModifications( - QFutureInterface &future, - QString vcvarsBat, - QString varsBatArg) +void MsvcToolChain::environmentModifications(QPromise &promise, + QString vcvarsBat, QString varsBatArg) { const Utils::Environment inEnv = Utils::Environment::systemEnvironment(); Utils::Environment outEnv; @@ -776,7 +774,7 @@ void MsvcToolChain::environmentModifications( } } - future.reportResult({error, diff}); + promise.addResult(MsvcToolChain::GenerateEnvResult{error, diff}); } void MsvcToolChain::initEnvModWatcher(const QFuture &future) @@ -1004,10 +1002,8 @@ bool MsvcToolChain::fromMap(const QVariantMap &data) data.value(QLatin1String(environModsKeyC)).toList()); rescanForCompiler(); - initEnvModWatcher(Utils::runAsync(envModThreadPool(), - &MsvcToolChain::environmentModifications, - m_vcvarsBat, - m_varsBatArg)); + initEnvModWatcher(Utils::asyncRun(envModThreadPool(), &MsvcToolChain::environmentModifications, + m_vcvarsBat, m_varsBatArg)); const bool valid = !m_vcvarsBat.isEmpty() && targetAbi().isValid(); if (!valid) @@ -1236,10 +1232,8 @@ void MsvcToolChain::setupVarsBat(const Abi &abi, const QString &varsBat, const Q m_varsBatArg = varsBatArg; if (!varsBat.isEmpty()) { - initEnvModWatcher(Utils::runAsync(envModThreadPool(), - &MsvcToolChain::environmentModifications, - varsBat, - varsBatArg)); + initEnvModWatcher(Utils::asyncRun(envModThreadPool(), + &MsvcToolChain::environmentModifications, varsBat, varsBatArg)); } } diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index 042bbfe38f8..f93f3be28cc 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -111,9 +111,8 @@ protected: std::optional error; Utils::EnvironmentItems environmentItems; }; - static void environmentModifications(QFutureInterface &future, - QString vcvarsBat, - QString varsBatArg); + static void environmentModifications(QPromise &future, + QString vcvarsBat, QString varsBatArg); void initEnvModWatcher(const QFuture &future); protected: diff --git a/src/plugins/projectexplorer/projectnodeshelper.h b/src/plugins/projectexplorer/projectnodeshelper.h index 727497c6bf5..bcb5454fd89 100644 --- a/src/plugins/projectexplorer/projectnodeshelper.h +++ b/src/plugins/projectexplorer/projectnodeshelper.h @@ -11,18 +11,19 @@ #include #include +#include + namespace ProjectExplorer { template -QList scanForFiles(QFutureInterface &future, - const Utils::FilePath &directory, +QList scanForFiles(QPromise &promise, const Utils::FilePath &directory, const std::function factory); namespace Internal { template QList scanForFilesRecursively( - QFutureInterface &future, + QPromise &promise, double progressStart, double progressRange, const Utils::FilePath &directory, @@ -46,7 +47,7 @@ QList scanForFilesRecursively( const double progressIncrement = progressRange / static_cast(entries.count()); int lastIntProgress = 0; for (const QFileInfo &entry : entries) { - if (future.isCanceled()) + if (promise.isCanceled()) return result; const Utils::FilePath entryName = Utils::FilePath::fromString(entry.absoluteFilePath()); @@ -54,7 +55,7 @@ QList scanForFilesRecursively( return vc->isVcsFileOrDirectory(entryName); })) { if (entry.isDir()) - result.append(scanForFilesRecursively(future, + result.append(scanForFilesRecursively(promise, progress, progressIncrement, entryName, @@ -66,26 +67,25 @@ QList scanForFilesRecursively( } progress += progressIncrement; const int intProgress = std::min(static_cast(progressStart + progress), - future.progressMaximum()); + promise.future().progressMaximum()); if (lastIntProgress < intProgress) { - future.setProgressValue(intProgress); + promise.setProgressValue(intProgress); lastIntProgress = intProgress; } } - future.setProgressValue( - std::min(static_cast(progressStart + progressRange), future.progressMaximum())); + promise.setProgressValue(std::min(static_cast(progressStart + progressRange), + promise.future().progressMaximum())); return result; } } // namespace Internal template -QList scanForFiles(QFutureInterface &future, - const Utils::FilePath &directory, +QList scanForFiles(QPromise &promise, const Utils::FilePath &directory, const std::function factory) { QSet visited; - future.setProgressRange(0, 1000000); - return Internal::scanForFilesRecursively(future, + promise.setProgressRange(0, 1000000); + return Internal::scanForFilesRecursively(promise, 0.0, 1000000.0, directory, diff --git a/src/plugins/projectexplorer/selectablefilesmodel.cpp b/src/plugins/projectexplorer/selectablefilesmodel.cpp index 365c319992d..28d601f89b7 100644 --- a/src/plugins/projectexplorer/selectablefilesmodel.cpp +++ b/src/plugins/projectexplorer/selectablefilesmodel.cpp @@ -9,10 +9,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -51,13 +51,13 @@ void SelectableFilesFromDirModel::startParsing(const Utils::FilePath &baseDir) m_rootForFuture->fullPath = baseDir; m_rootForFuture->isDir = true; - m_watcher.setFuture(Utils::runAsync(&SelectableFilesFromDirModel::run, this)); + m_watcher.setFuture(Utils::asyncRun(&SelectableFilesFromDirModel::run, this)); } -void SelectableFilesFromDirModel::run(QFutureInterface &fi) +void SelectableFilesFromDirModel::run(QPromise &promise) { m_futureCount = 0; - buildTree(m_baseDir, m_rootForFuture, fi, 5); + buildTree(m_baseDir, m_rootForFuture, promise, 5); } void SelectableFilesFromDirModel::buildTreeFinished() @@ -97,7 +97,7 @@ SelectableFilesModel::FilterState SelectableFilesModel::filter(Tree *t) } void SelectableFilesFromDirModel::buildTree(const Utils::FilePath &baseDir, Tree *tree, - QFutureInterface &fi, int symlinkDepth) + QPromise &promise, int symlinkDepth) { if (symlinkDepth == 0) return; @@ -111,7 +111,7 @@ void SelectableFilesFromDirModel::buildTree(const Utils::FilePath &baseDir, Tree Utils::FilePath fn = Utils::FilePath::fromFileInfo(fileInfo); if (m_futureCount % 100) { emit parsingProgress(fn); - if (fi.isCanceled()) + if (promise.isCanceled()) return; } ++m_futureCount; @@ -121,7 +121,7 @@ void SelectableFilesFromDirModel::buildTree(const Utils::FilePath &baseDir, Tree t->name = fileInfo.fileName(); t->fullPath = fn; t->isDir = true; - buildTree(fn, t, fi, symlinkDepth - fileInfo.isSymLink()); + buildTree(fn, t, promise, symlinkDepth - fileInfo.isSymLink()); allChecked &= t->checked == Qt::Checked; allUnchecked &= t->checked == Qt::Unchecked; tree->childDirectories.append(t); diff --git a/src/plugins/projectexplorer/selectablefilesmodel.h b/src/plugins/projectexplorer/selectablefilesmodel.h index 6340e2d1a2d..6f9d7b67bed 100644 --- a/src/plugins/projectexplorer/selectablefilesmodel.h +++ b/src/plugins/projectexplorer/selectablefilesmodel.h @@ -147,11 +147,9 @@ signals: void parsingProgress(const Utils::FilePath &fileName); private: - void buildTree(const Utils::FilePath &baseDir, - Tree *tree, - QFutureInterface &fi, + void buildTree(const Utils::FilePath &baseDir, Tree *tree, QPromise &promise, int symlinkDepth); - void run(QFutureInterface &fi); + void run(QPromise &promise); void buildTreeFinished(); // Used in the future thread need to all not used after calling startParsing diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp index abcc66c3cc3..05d3db702f6 100644 --- a/src/plugins/projectexplorer/treescanner.cpp +++ b/src/plugins/projectexplorer/treescanner.cpp @@ -9,9 +9,9 @@ #include #include +#include #include #include -#include #include @@ -42,9 +42,9 @@ bool TreeScanner::asyncScanForFiles(const Utils::FilePath &directory) if (!m_futureWatcher.isFinished()) return false; - m_scanFuture = Utils::runAsync( - [directory, filter = m_filter, factory = m_factory] (FutureInterface &fi) { - TreeScanner::scanForFiles(fi, directory, filter, factory); + m_scanFuture = Utils::asyncRun( + [directory, filter = m_filter, factory = m_factory] (Promise &promise) { + TreeScanner::scanForFiles(promise, directory, filter, factory); }); m_futureWatcher.setFuture(m_scanFuture); @@ -139,10 +139,10 @@ static std::unique_ptr createFolderNode(const Utils::FilePath &direc return fileSystemNode; } -void TreeScanner::scanForFiles(FutureInterface &fi, const Utils::FilePath& directory, +void TreeScanner::scanForFiles(Promise &promise, const Utils::FilePath& directory, const FileFilter &filter, const FileTypeFactory &factory) { - QList nodes = ProjectExplorer::scanForFiles(fi, directory, + QList nodes = ProjectExplorer::scanForFiles(promise, directory, [&filter, &factory](const Utils::FilePath &fn) -> FileNode * { const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn); @@ -160,10 +160,10 @@ void TreeScanner::scanForFiles(FutureInterface &fi, const Utils::FilePath& direc Utils::sort(nodes, ProjectExplorer::Node::sortByPath); - fi.setProgressValue(fi.progressMaximum()); + promise.setProgressValue(promise.future().progressMaximum()); Result result{createFolderNode(directory, nodes), nodes}; - fi.reportResult(result); + promise.addResult(result); } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/treescanner.h b/src/plugins/projectexplorer/treescanner.h index e324303c172..f8d019121b9 100644 --- a/src/plugins/projectexplorer/treescanner.h +++ b/src/plugins/projectexplorer/treescanner.h @@ -31,7 +31,7 @@ public: }; using Future = QFuture; using FutureWatcher = QFutureWatcher; - using FutureInterface = QFutureInterface; + using Promise = QPromise; using FileFilter = std::function; using FileTypeFactory = std::function; @@ -69,7 +69,7 @@ signals: void finished(); private: - static void scanForFiles(FutureInterface &fi, const Utils::FilePath &directory, + static void scanForFiles(Promise &fi, const Utils::FilePath &directory, const FileFilter &filter, const FileTypeFactory &factory); private: From 4ae94a9910d5c4200f13fa9dfdb5ecb711913102 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 22:06:23 +0100 Subject: [PATCH 0200/1447] CMakeProjectManager: Use QtConcurrent invocation for async run Change-Id: I03b23a6bd32bfaa435ddddab1a7ab47a5203ff44 Reviewed-by: Cristian Adam Reviewed-by: Qt CI Bot --- src/plugins/cmakeprojectmanager/fileapiparser.cpp | 7 ++++--- src/plugins/cmakeprojectmanager/fileapiparser.h | 8 ++++++-- src/plugins/cmakeprojectmanager/fileapireader.cpp | 10 +++++----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.cpp b/src/plugins/cmakeprojectmanager/fileapiparser.cpp index 0f25f27580d..e4dca5c9b26 100644 --- a/src/plugins/cmakeprojectmanager/fileapiparser.cpp +++ b/src/plugins/cmakeprojectmanager/fileapiparser.cpp @@ -16,6 +16,7 @@ #include #include #include +#include using namespace Utils; @@ -825,7 +826,7 @@ static QStringList uniqueTargetFiles(const Configuration &config) return files; } -FileApiData FileApiParser::parseData(QFutureInterface> &fi, +FileApiData FileApiParser::parseData(QPromise> &promise, const FilePath &replyFilePath, const QString &cmakeBuildType, QString &errorMessage) @@ -836,8 +837,8 @@ FileApiData FileApiParser::parseData(QFutureInterface #include -#include #include #include #include #include +QT_BEGIN_NAMESPACE +template +class QPromise; +QT_END_NAMESPACE + namespace CMakeProjectManager::Internal { namespace FileApiDetails { @@ -218,7 +222,7 @@ public: class FileApiParser { public: - static FileApiData parseData(QFutureInterface> &fi, + static FileApiData parseData(QPromise> &promise, const Utils::FilePath &replyFilePath, const QString &cmakeBuildType, QString &errorMessage); diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index c6ee73d6abb..6167ad84278 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -5,7 +5,6 @@ #include "cmakeprocess.h" #include "cmakeprojectmanagertr.h" -#include "cmakeprojectplugin.h" #include "cmakespecificsettings.h" #include "fileapidataextractor.h" #include "fileapiparser.h" @@ -15,6 +14,7 @@ #include #include +#include #include #include @@ -235,11 +235,11 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac m_lastReplyTimestamp = replyFilePath.lastModified(); - m_future = runAsync(ProjectExplorerPlugin::sharedThreadPool(), + m_future = Utils::asyncRun(ProjectExplorerPlugin::sharedThreadPool(), [replyFilePath, sourceDirectory, buildDirectory, cmakeBuildType]( - QFutureInterface> &fi) { + QPromise> &promise) { auto result = std::make_shared(); - FileApiData data = FileApiParser::parseData(fi, + FileApiData data = FileApiParser::parseData(promise, replyFilePath, cmakeBuildType, result->errorMessage); @@ -248,7 +248,7 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac else qWarning() << result->errorMessage; - fi.reportResult(result); + promise.addResult(result); }); onResultReady(m_future.value(), this, From e3bae749ea2dc478ac713bf89ec81e644b3ef6d7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Feb 2023 09:51:00 +0100 Subject: [PATCH 0201/1447] DirectoryFilter: Use synchronous task when empty directories There is no need to run asynchronous task in this case. Change-Id: Iaca0a5950572c167b996a8d8f0a376d9c35c38ab Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../coreplugin/locator/directoryfilter.cpp | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 9d07e530cd2..bca78cc8bcf 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -386,9 +386,6 @@ static void refresh(QFutureInterface &future, const FilePaths &direct const QStringList &filters, const QStringList &exclusionFilters, const QString &displayName) { - if (directories.isEmpty()) - return; - SubDirFileIterator subDirIterator(directories, filters, exclusionFilters); future.setProgressRange(0, subDirIterator.maxProgress()); FilePaths files; @@ -413,15 +410,26 @@ using namespace Utils::Tasking; std::optional DirectoryFilter::refreshRecipe() { - const auto setup = [this](AsyncTask &async) { + const auto groupSetup = [this] { + if (!m_directories.isEmpty()) + return TaskAction::Continue; // Async task will run + m_files.clear(); + updateFileIterator(); + return TaskAction::StopWithDone; // Group stops, skips async task + }; + const auto asyncSetup = [this](AsyncTask &async) { async.setAsyncCallData(&refresh, m_directories, m_filters, m_exclusionFilters, displayName()); }; - const auto done = [this](const AsyncTask &async) { + const auto asyncDone = [this](const AsyncTask &async) { m_files = async.isResultAvailable() ? async.result() : FilePaths(); updateFileIterator(); }; - return Async(setup, done); + const Group root { + OnGroupSetup(groupSetup), + Async(asyncSetup, asyncDone) + }; + return root; } } // namespace Core From 4859aa2aaab33f7be528b965ec9ad895f5cd7d7b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Feb 2023 01:04:16 +0100 Subject: [PATCH 0202/1447] DirectoryFilter: Use QPromise for async calls Change-Id: I0f5fd3de4d31990f6e8642068e6886b7e76258a1 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- .../coreplugin/locator/directoryfilter.cpp | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index bca78cc8bcf..1d7bba06e49 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -382,28 +382,26 @@ void DirectoryFilter::setExclusionFilters(const QStringList &exclusionFilters) m_exclusionFilters = exclusionFilters; } -static void refresh(QFutureInterface &future, const FilePaths &directories, +static void refresh(QPromise &promise, const FilePaths &directories, const QStringList &filters, const QStringList &exclusionFilters, const QString &displayName) { SubDirFileIterator subDirIterator(directories, filters, exclusionFilters); - future.setProgressRange(0, subDirIterator.maxProgress()); + promise.setProgressRange(0, subDirIterator.maxProgress()); FilePaths files; const auto end = subDirIterator.end(); for (auto it = subDirIterator.begin(); it != end; ++it) { - if (future.isCanceled()) { - future.setProgressValueAndText(subDirIterator.currentProgress(), + if (promise.isCanceled()) { + promise.setProgressValueAndText(subDirIterator.currentProgress(), Tr::tr("%1 filter update: canceled").arg(displayName)); return; } files << (*it).filePath; - if (future.isProgressUpdateNeeded() || future.progressValue() == 0) { - future.setProgressValueAndText(subDirIterator.currentProgress(), - Tr::tr("%1 filter update: %n files", nullptr, files.size()).arg(displayName)); - } + promise.setProgressValueAndText(subDirIterator.currentProgress(), + Tr::tr("%1 filter update: %n files", nullptr, files.size()).arg(displayName)); } - future.setProgressValue(subDirIterator.maxProgress()); - future.reportResult(files); + promise.setProgressValue(subDirIterator.maxProgress()); + promise.addResult(files); } using namespace Utils::Tasking; @@ -418,8 +416,8 @@ std::optional DirectoryFilter::refreshRecipe() return TaskAction::StopWithDone; // Group stops, skips async task }; const auto asyncSetup = [this](AsyncTask &async) { - async.setAsyncCallData(&refresh, m_directories, m_filters, m_exclusionFilters, - displayName()); + async.setConcurrentCallData(&refresh, m_directories, m_filters, m_exclusionFilters, + displayName()); }; const auto asyncDone = [this](const AsyncTask &async) { m_files = async.isResultAvailable() ? async.result() : FilePaths(); From 7a2bd0898d78a5031297ab5d6784fbaa021840d0 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 27 Feb 2023 22:54:45 +0100 Subject: [PATCH 0203/1447] Haskell: Settings/options icon Change-Id: I6b65901951fbfd9680bf7617991c47884f67df9c Reviewed-by: Alessandro Portale --- src/plugins/haskell/haskell.qrc | 3 ++- .../haskell/images/category_haskell.png | Bin 6264 -> 0 bytes .../images/settingscategory_haskell.png | Bin 0 -> 187 bytes .../images/settingscategory_haskell@2x.png | Bin 0 -> 322 bytes src/plugins/haskell/optionspage.cpp | 2 +- src/tools/icons/qtcreatoricons.svg | 21 ++++++++++++++++++ 6 files changed, 24 insertions(+), 2 deletions(-) delete mode 100644 src/plugins/haskell/images/category_haskell.png create mode 100644 src/plugins/haskell/images/settingscategory_haskell.png create mode 100644 src/plugins/haskell/images/settingscategory_haskell@2x.png diff --git a/src/plugins/haskell/haskell.qrc b/src/plugins/haskell/haskell.qrc index 654f45818c3..3ddf22f76d0 100644 --- a/src/plugins/haskell/haskell.qrc +++ b/src/plugins/haskell/haskell.qrc @@ -1,5 +1,6 @@ - images/category_haskell.png + images/settingscategory_haskell.png + images/settingscategory_haskell@2x.png diff --git a/src/plugins/haskell/images/category_haskell.png b/src/plugins/haskell/images/category_haskell.png deleted file mode 100644 index 947f948bd916f243c9844dbc575c3a78f5dc609f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6264 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F7-8`6DgcKB4+?eRfdR0D`{!JPCD3jYPQIQuUkLAv;2I1y7l*aKi@q$H%F3TO76{_J0n+c zG2CpbNer2wZ>(t8>G_J0i-G->gZzw*mWyKMpEzN_khe7#r86M1<6O(Ai&|+2DQMlfP}Bp_y!W^UW4Rozt#bDfRm_%)4#B|BvbWuX{7{(M3z1#Kp_Fn-{BC z9xh#d>I~=91g#_LteOu61y(!Obe^Aj%lpILlEQ*Dcj_9HKQ(8wNiZyEIQ@;kHG(~< z&BFMad*9oePAm1dxF7!cQ_-+!j?$UVNypu}St1`MezG`yxl(a)1-rk9fNj>~Q~W%Q z5@AwRYYc4F;*JUDYCbsL>b!=fuwBF0D&*bo6$W?pYp%Fy^i3)-Yx|MA%D})YtvNHT z+wJqA9E+TnF&o4T!s@DgHk=Xne$Xj&$j!2#@*krSpTu80!zPB;5#d z;5)(a=UZbN;}35$A&wgk9G4jQBTkzxmiu@~knxXOv(pE47aIks&!4CEeR5#DQZIS= z)V^y9p;l1}Ur(_3E1o;HwNU>KGk9S@P4J5|Eri#nSybEjCcjm3mg zu^guZ|IK#=-1wYOCZyMNQD)y!WgFEJAvxhZp9n}~5cVG_ZvW7ef z-GF(qr@r5OxNO2!;dkBDPX8uYpF6O%(exdM@yCOE6Z8B6e%m^Kl-Qo1{qu2+(6#%| zm9J|@YFVC)T+;K`xGp)&-tFV>yxtuf`2SuMitdv=8nvQUY}@^BpZSY7KmF`|&3nrE*^~8e^3+-GEN=a?-^-Gv84Dh1GJGk& zU*fhtap!u*2O;e4Iyw_xsvI{|VBiX9+wH{tf>Akv@AF3Xa|f6=I55oMQF7q%U@?B! zwY)j!M5Wmb{%H+D0c_VAdK0v7aDHphD&UY||1oki= z=4hHAAm!w~MWFTw%SNX+g5gKFIUNp7&`=Tdbh{+LsO0uc*?XcO%MM6X?3laH$lEo z$?y2g9j0r}CfJBQe^B|usYZ35==wviKZ^aay4TGAD4x@#iSJ<713wN$6@g0}n>kfm ziVoQwDm=uxBmWo2`wkbS<_x!z#@|L0XE@GrkMX?Yw?=uMYMD@Vr?ZNXXLpM0Cl%KT zHK7mVT1lnjCPT@HvbSlkD_bJm;#;3iD7A;!1X!fHJ*L{zY zj-Ksm7uDDNrct+KRiN(5x+^b33`<2z?Z4`L)%(iZ>t?)kV}|FJnp;{?rf+TD3chU? ziaqJ3>C(A+i^oc*m2oS*UoPF$w5fAb|0kcPPEU)TEW_sb+L8c>+^R))$U&l+Ge#acAIldrkATXSn4iMPvR+##1z9Y<358tL%ZI~ zvd@kC%=3=!xK$YY_+ED3^_0v{Cf=s6P4ctqE+u8LW~64Vy_$8QYDI5$be8|sd29DN z|8DwrpyKOCxyP1|y^qUF*88(x-FT(*(#++X-Ix2OdxZO&dzgopcfYH=%V^ss=dJIY z-+V7~Z(Z%KebepY>zn^c{c`Ws~T8&F>o!U#a**;Oe_h!$Ud2F_xajrpa-m*-w zq_B*zZjmS zFk4|pfaSw&rdMwr-*sTuv0ca85{1)(Q!XcbE?V^Q$db-%^=*ECvR*ZT7vsR|E&syfa#l^YHEOd*r%6>h1^GK&; zUFo}W!!pmZo6m}Fhu$^4RJ!!Fs(I7w^|zI_PtKFSJNNGAyZt-G@-^k3u{C|a0Q?^4w+9efFCk&N((ma(a5! z`7^UBv!;F0`L<^9$(AQSo-m)Be^c;{*S7#Kk5k*GIQGe>3qNO_e)R5vx6dm-UHdq1 zY1OiI-nH|d&D>_U*8Z;bUYpv6_s8#_s-G%2XQT1s+BBDE|ISQY^JC4foT9R#Z=8*@ z6oM~IT0GrYeYx>hslyrptYE^!|C?34Rb75cnan z?9Q9T#Ual*o^3h1b4|bsn+&yAHCnT**c@Vc4=nnPq|0)nr!{QAA6ho_vqK@ zuWE1oKJ~5krv8olv7(_@gWd+k);c^t@JecnTg>J9f?o&wod2~;Wv|UHzi#;I6kqe< zM~CbG%=+_st@1+mS^c}@*4m~O<=ig(_3={GlDfRV3C>l{<;h9O&pS`5&zfyBtM7l> z=iC1#v#D$QWzLDJomI5!$Cnc`4;eeB7oX>w<86KYw$19F|9-Z7Hji4iZA(1I-h!7& z4~~9bYqvICuQJZ6^5)-9o!aZdrPf)+ugx#cvi`UG^84er=iYw3erHVfn}XLFujX8- z+;w{Q>pP|YUyJ9r+}TlO{3q@C+8fd3dH(zF*0xta|9N-K?)C3P??~_4|AX^Rr7D#+uxMG zasT7-E%v|Sp6rv5)A$+u^?a`W*?76%-Cx6RCmc$+ul;cK#OvDkGxpy6f9+%L=YS^{ z7MI_A-*$g`-GyHPUoU=5e!cvM|M|A`dbQene~v!#zI^?{dVaS}?rudlowj|^YB<=o zY#GysDtm@4E*0f37#bF-R9AblPTVWLl;e-OPW61xqmm7Obr_PwnFZM1Ygi{3H_qUy zK6%x;jWvM1eWRLq;Hu`mI%1;x5;)}D-0r<#a>!zO&|Q#{Qt|u5iRpVMyoqHv_w3}o z8X?6)zyGf56uNTpyU-tv|19#4bG3H1Pd&)Mz`$AH5n0T@Af^h!jGjR%9~c-|R5C*% zN+NuHtdjF{^%7I^lT!66atjzhz^1~gBDWwnwIorYA~z?m*s8)-39P~@uhKSE{q5fh%V>++=8Oi;^NHwJUdgU7GyDW^$`eb>C&iOg{MZpD$ z$*CZhfwdqBp{oX46N$?jBnc#qDalsFrAb+-$t6hf1xvL~iRt=C!Z!L?RohhL7FhY_ zr(~v8x+IpQ+8G%bnp+uIS{WHA7@C3@7KS$ZXljsL0FrSoN=+=uFAB-e&#?phA{WF} zFxE4J=tP!>YPHb^|?LoV`I=-Hyw(q9N)=t!qp&1JvdN(>A?doVJuO)%N0%rnP>lb=(00|DLAOO@2U>(`oh4|yU#iK z6z&M?>Z;V#Z{dFXDDCqsuZ8O*XLTz4`DOFw@5A@y_dYY5{9Jwi=DB;H?amj^`&_H{ z-12#CY|NaqFBzA!&yg#rdSG91z*JN7<&(d^zb~FOYgSB5Z0y^RojZ5#bgD`}8 z1PiX|y_dLPt)lYe($CM&>t#$bE~Gw*W6aoa!XWQuTOgyw;jdR#2D4jntoO{_eA>NV z?yuB6edaaGwGv&PS}j=o{oUPaOI_W!mB;R1{QF|n4wpr8zfSZ@o7ZJ0l`$NQEqQd; zyJDyIOTop=tatez|MHzwz_tU3OpD**9D|PCJ#Flld*1R~}zh*DZt=JB`tz&!J3!{Vr3A zv1@;S|M{L-vt~)2n58S$=$^r+tYFpQWHQgzgR5foOU0EgyIDJC{QdoXzAD#wrC`T; zuc@MrG8a1xJ7=5aYAG{0GBPqAH(WD6Yr_dUug$BSUb*n?$Yy5a`EX$K`d1E)-;Ygb z+*|$qURYFAm9df0C$lZrOG7y=H6`?0+S|p~$L{{-=HqjQm8XJxZ=Tg%Eiw1^%e0no zmA$-_%Gt25JY?#E{x6?CotjX&b?esGA702ctjv1irz-tR^4lTzLor)2E?&R0)$B!z z@8oF3Ewh}iRmv0uR=nhRZ?|fDPsl3Pgg5(Yf1g{jWJ!yIbz_WqXxNuTmPNkFJGE;~ z^Y86hzH@I_$-6t2E<81JuIVwm82(md&)2{5RA<2wE!jm{M}w!nTJAG*5}WU$#6v0* zk8J2>=)1S4^7Gj_bLL3!NUWc1>U&M#R<1)t#EkTUf)9>+q*s5QCc#*n7a4goh+)^V zWy|U~BX%yEJ#Ffi#(kX{OJ>aI_sA&bkNDc!)^_UeiQB){*{R09*y{AWV6tz5m-%ZM zOML^qnI65HFUft+yqC*oQds+gLErtAjn=*PeckU{zZ%UgG}|J$tNH9Ix#YVYX>t>- z&S}=hdSxdhJXr2>TwL;Vdt2$EPdU>WKYskE9HHaQF1KsRxzaEDob!$BD(+oAd25|+ zCdZ9BiJc<9mb`lPN_yYEedaf=ygYV&?%ExP3s*mHI5W#2(TRbpoN3GQC7riYf-f0; z_&0IQ8XbMF$7LCBS7{}&Y!aL!pWfBgb&f~Y>WjwvPM7uVF8)7qznXn#Sh<;D>B2=G zxs$9ec;DDDpZop0ySq0pIJ)g=t!uw_-$`$OfBs4H85zz$+Uuxvd)~EGj8o19YE(tD zdx$msvt~P!q{uC8#O1tox;>-Pu~!bA$q&9dUN4$>`s`U-7m@G+3$ybRE7z9IT#{W_ zSlFnuLpY9KR(`{yznOQM`%=@>tEE?7j%Qfu%W%Q&@a9Fv4o{`sT0S>^(XKbCd#Jpk z$@2V0H{G_-!{s+*^ODp~msTloUHLl8mZ?@+J%6LYPNzMm+j_2r$};kQkiRgs%SR|- z+lvwB&ibro45^kquW1 z|DTN6o)_yJ5D*~v+1t=%*)7vfrmCuse{S?$Jl4IEOI1y+%(*i}_HAsNtImhZ{4y2+ z2akPrtmoXakI5mI?Lti6eAh$PH9t0_-q?^RDlxyM?sC2AMaLtDR(Of8TD7V!=2PT-4w6s5V7> zef<7^OU_2=IzNlt(Rj{j*)4-@t?JB$Tzyjhne$SPU)Zxnf+3%i`@8!}&oc~LS}$)4 znNeC=YI&jUg_7!~3;rLbZacH&M4Q4?wwpH@wl1`j;o__CUg7muKIrV?XE#IU7FH-l zvU`XfxGny&IMs@)eRIJ!ziS_!-Tz?x{QUg;&(7-vz2tr-V(q1R?Omhd&li`XIpxgX z$scT4)9|}*b&KCyhN=IpZpuWM|G35Fk|$~uSM)F_m6y3lb7p8-{7cQ4d(R%s(Jq;6 wS9i7h^SuYRZG7!-dzMxmfYhx&_E$fMKe{&U;=h_zg`l>-r>mdKI;Vst0N!>viU0rr diff --git a/src/plugins/haskell/images/settingscategory_haskell.png b/src/plugins/haskell/images/settingscategory_haskell.png new file mode 100644 index 0000000000000000000000000000000000000000..5bd3f69fa8caf1b897e5e71f64e346152965bc4e GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4h9AWhNCh`Dhvz^O`a}}AsQ2tfAljO@a#Bp zrRCQBg*?CP4OQ%(tFEcnJr~fQd1YtIlHbx25$6(aF&gRc95qhV`m*vE|Cdo3s z*hlrHho=1B<{EQ=od{KZgq8XPS3{(w_Qwapk-RvfiR;nfhG7{t~Pq#tz3hjZz< zDN{tVl{$D5+&m&1rb+!;`sP^Z(oGT5mtWS{DsUuF)txa^v(le2>eZqppVS<@b*F|r z&O2InI@Ds4($q6coWycfpE3q`tXpt+{Xb__SMzlzG)yOR-I5A+4>~jZ0^^+J{er&5 z^X#4pz7jjX*4wi0MU2la@#NB#LKAqsrd;4~&kj1HTXI=gNwnd+vs!D})0R~szw3X9 aKj7XZd2&LMZIvV_a6Dc8T-G@yGywnw9)X7d literal 0 HcmV?d00001 diff --git a/src/plugins/haskell/optionspage.cpp b/src/plugins/haskell/optionspage.cpp index e64a6012345..ac33b757eb9 100644 --- a/src/plugins/haskell/optionspage.cpp +++ b/src/plugins/haskell/optionspage.cpp @@ -22,7 +22,7 @@ OptionsPage::OptionsPage() setDisplayName(Tr::tr("General")); setCategory("J.Z.Haskell"); setDisplayCategory(Tr::tr("Haskell")); - setCategoryIcon(Utils::Icon(":/haskell/images/category_haskell.png")); + setCategoryIconPath(":/haskell/images/settingscategory_haskell.png"); } QWidget *OptionsPage::widget() diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index d2b92dd605b..e3bf52e6eb1 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -3184,6 +3184,27 @@ id="path3678" d="m 1133.4931,482.92349 c 1.2309,-7.2e-4 2.6907,0.20509 3.4049,1.34287 0.832,1.39305 0.4718,3.51373 -1.0108,4.32399 -1.1526,0.68867 -2.5252,0.56507 -3.8119,0.57709 0,1.32708 0,2.65416 0,3.98124 -0.4296,0 -0.8592,0 -1.2888,0 0,-3.4084 0,-6.81679 0,-10.22519 0.9022,0 1.8044,0 2.7066,0 z m -0.1145,1.10271 c -0.4344,0 -0.8689,0 -1.3033,0 0,1.34618 0,2.69235 0,4.03853 1.1413,-0.0225 2.414,0.13991 3.3757,-0.60104 0.6576,-0.63013 0.6991,-1.73406 0.3022,-2.5149 -0.4777,-0.81039 -1.5253,-0.91406 -2.3746,-0.92259 z m -7.2608,-0.11456 c -1.2534,-0.0527 -2.5094,0.63954 -3.049,1.78756 -0.6219,1.30647 -0.619,2.86103 -0.2119,4.23045 0.3167,1.06743 1.2059,1.9627 2.3249,2.14365 1.1265,0.21498 2.2861,0.0103 3.3706,-0.31376 0,0.37235 0,0.74469 0,1.11704 -1.2924,0.46392 -2.7269,0.53819 -4.0672,0.2542 -1.5087,-0.32824 -2.6766,-1.61705 -3.0215,-3.09988 -0.4203,-1.74943 -0.3686,-3.7411 0.6344,-5.29133 0.8809,-1.36394 2.5502,-2.02668 4.1347,-1.9587 0.9342,0.01 1.8806,0.17957 2.7206,0.60089 -0.1719,0.3628 -0.3437,0.7256 -0.5156,1.0884 -0.7312,-0.3223 -1.5123,-0.57452 -2.32,-0.55852 z" /> + + + + + From 665ae04605cfa4033201b42194580b32739c9df9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 6 Mar 2023 12:25:26 +0100 Subject: [PATCH 0204/1447] Terminal: Open Link with line/column info Change-Id: I3e70a7c33a935b7bd3e12fb903148bcd60ff55aa Reviewed-by: hjk Reviewed-by: Cristian Adam --- src/libs/utils/link.h | 6 +++++- src/plugins/terminal/terminalwidget.cpp | 23 +++++++++++++---------- src/plugins/terminal/terminalwidget.h | 5 +++-- src/plugins/terminal/tests/filenames | 22 ++++++++++++++++++++++ 4 files changed, 43 insertions(+), 13 deletions(-) create mode 100755 src/plugins/terminal/tests/filenames diff --git a/src/libs/utils/link.h b/src/libs/utils/link.h index 655957e9acc..00194654c97 100644 --- a/src/libs/utils/link.h +++ b/src/libs/utils/link.h @@ -27,7 +27,11 @@ public: static Link fromString(const QString &filePathWithNumbers, bool canContainLineNumber = false); bool hasValidTarget() const - { return !targetFilePath.isEmpty(); } + { + if (!targetFilePath.isEmpty()) + return true; + return !targetFilePath.scheme().isEmpty() || !targetFilePath.host().isEmpty(); + } bool hasValidLinkText() const { return linkTextStart != linkTextEnd; } diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index f2af06d5774..8df6e3c02aa 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -3,7 +3,6 @@ #include "terminalwidget.h" #include "glyphcache.h" -#include "keys.h" #include "terminalsettings.h" #include "terminalsurface.h" #include "terminaltr.h" @@ -993,11 +992,12 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) { if (m_linkSelection) { - if (m_linkSelection->filePath.scheme().toString().startsWith("http")) { - QDesktopServices::openUrl(m_linkSelection->filePath.toUrl()); + if (m_linkSelection->link.targetFilePath.scheme().toString().startsWith("http")) { + QDesktopServices::openUrl(m_linkSelection->link.targetFilePath.toUrl()); return; } - Core::EditorManager::openEditorAt(Utils::Link(m_linkSelection->filePath)); + + Core::EditorManager::openEditorAt(m_linkSelection->link); } return; } @@ -1062,17 +1062,20 @@ void TerminalWidget::checkLinkAt(const QPoint &pos) const TextAndOffsets hit = textAt(pos); if (hit.text.size() > 0) { - QString t = QString::fromUcs4(hit.text.c_str(), hit.text.size()); + QString t + = Utils::chopIfEndsWith(QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed(), + ':'); if (t.startsWith("~/")) { t = QDir::homePath() + t.mid(1); } - // Todo: Windows path support - const FilePath p = FilePath::fromString(t.trimmed()); + Utils::Link link = Utils::Link::fromString(t, true); - if (!p.isEmpty() && (p.scheme().toString().startsWith("http") || p.exists())) { - const LinkSelection newSelection = LinkSelection{{hit.start, hit.end}, p}; - if (*m_linkSelection != newSelection) { + if (link.hasValidTarget() + && (link.targetFilePath.scheme().toString().startsWith("http") + || link.targetFilePath.exists())) { + const LinkSelection newSelection = LinkSelection{{hit.start, hit.end}, link}; + if (!m_linkSelection || *m_linkSelection != newSelection) { m_linkSelection = newSelection; updateViewport(); } diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 07355b95bc2..6238fac52c7 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -5,6 +5,7 @@ #include "terminalsurface.h" +#include #include #include @@ -59,11 +60,11 @@ public: struct LinkSelection : public Selection { - Utils::FilePath filePath; + Utils::Link link; bool operator!=(const LinkSelection &other) const { - return filePath != other.filePath || Selection::operator!=(other); + return link != other.link || Selection::operator!=(other); } }; diff --git a/src/plugins/terminal/tests/filenames b/src/plugins/terminal/tests/filenames new file mode 100755 index 00000000000..6a4e33e3ede --- /dev/null +++ b/src/plugins/terminal/tests/filenames @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +echo "Home:" +echo "~/" + +FULLPATH=$(readlink -f "$0") + +echo "This file:" +echo "$FULLPATH" + +echo "This file, this line:" +echo "$FULLPATH:11" + +echo "This file, this line, this word:" +echo "$FULLPATH:14:34" + +echo "This file, with an error message:" +echo "$FULLPATH:18:23: error: C++ requires a type specifier for all declarations" + +echo "A link: http://google.com" +echo "Another link: https://www.qt.io" +echo "Another one: https://codereview.qt-project.org/c/qt-creator/qt-creator/+/464740" From 9b4e0c62fd8b43232d5255670a05340887057f1f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 6 Mar 2023 17:02:28 +0100 Subject: [PATCH 0205/1447] Terminal: Add decoration test Change-Id: I4fc54ea542e57fe49bd19ae517486765b666499f Reviewed-by: Cristian Adam --- src/plugins/terminal/tests/decoration | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 src/plugins/terminal/tests/decoration diff --git a/src/plugins/terminal/tests/decoration b/src/plugins/terminal/tests/decoration new file mode 100755 index 00000000000..a584d460927 --- /dev/null +++ b/src/plugins/terminal/tests/decoration @@ -0,0 +1,9 @@ +#!/bin/sh + +printf "\e[1mbold\e[0m\n" +printf "\e[3mitalic\e[0m\n" +printf "\e[3m\e[1mbold italic\e[0m\n" +printf "\e[4munderline (abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ)\e[0m\n" +printf "\e[9mstrikethrough\e[0m\n" +printf "\e[31mHello World\e[0m\n" +printf "\x1B[31mHello World\e[0m\n" From b95c0d247d1c89ca60c724c95201e3d410b5a318 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 6 Mar 2023 18:16:28 +0100 Subject: [PATCH 0206/1447] Terminal: Fix "altscreen" handling When "altscreen" is enabled ( e.g. when starting nano ), the terminal switches into an alternate mode without scrollback buffer. This was not correctly handled where the scrollback buffer would stay active. Change-Id: I443d26383d9cd908befcd24a837ecf84c0c1e849 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalsurface.cpp | 25 ++++++++++++++---------- src/plugins/terminal/terminalwidget.cpp | 2 ++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index 4c9021d5965..eb95215f948 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -45,8 +45,6 @@ struct TerminalSurfacePrivate m_vtermScreenCallbacks.damage = [](VTermRect rect, void *user) { auto p = static_cast(user); - rect.start_row += p->m_scrollback->size(); - rect.end_row += p->m_scrollback->size(); p->invalidate(rect); return 1; }; @@ -165,6 +163,11 @@ struct TerminalSurfacePrivate // Callbacks from vterm void invalidate(VTermRect rect) { + if (!m_altscreen) { + rect.start_row += m_scrollback->size(); + rect.end_row += m_scrollback->size(); + } + emit q->invalidated( QRect{QPoint{rect.start_col, rect.start_row}, QPoint{rect.end_col, rect.end_row - 1}}); } @@ -215,14 +218,12 @@ struct TerminalSurfacePrivate break; } case VTERM_PROP_ICONNAME: - //emit iconTextChanged(val->string); break; case VTERM_PROP_TITLE: break; case VTERM_PROP_ALTSCREEN: m_altscreen = val->boolean; emit q->altscreenChanged(m_altscreen); - //setSelection(std::nullopt); break; case VTERM_PROP_MOUSE: qCDebug(log) << "Ignoring VTERM_PROP_MOUSE" << val->number; @@ -248,9 +249,9 @@ struct TerminalSurfacePrivate const VTermScreenCell *cellAt(int x, int y) { QTC_ASSERT(y >= 0 && x >= 0, return nullptr); - QTC_ASSERT(y < liveSize().height() + m_scrollback->size() && x < liveSize().width(), - return nullptr); - if (y < m_scrollback->size()) { + QTC_ASSERT(y < q->fullSize().height() && x < liveSize().width(), return nullptr); + + if (!m_altscreen && y < m_scrollback->size()) { const auto &sbl = m_scrollback->line((m_scrollback->size() - 1) - y); if (x < sbl.cols()) { return sbl.cell(x); @@ -258,7 +259,8 @@ struct TerminalSurfacePrivate return nullptr; } - y -= m_scrollback->size(); + if (!m_altscreen) + y -= m_scrollback->size(); static VTermScreenCell refCell{}; VTermPos vtp{y, x}; @@ -306,6 +308,8 @@ QSize TerminalSurface::liveSize() const QSize TerminalSurface::fullSize() const { + if (d->m_altscreen) + return liveSize(); return QSize{d->liveSize().width(), d->liveSize().height() + d->m_scrollback->size()}; } @@ -329,7 +333,7 @@ TerminalCell TerminalSurface::fetchCell(int x, int y) const emptyCell{1, {}, {}, false, {}, std::nullopt, QTextCharFormat::NoUnderline, false}; QTC_ASSERT(y >= 0, return emptyCell); - QTC_ASSERT(y < d->liveSize().height() + d->m_scrollback->size(), return emptyCell); + QTC_ASSERT(y < fullSize().height() && x < fullSize().width(), return emptyCell); const VTermScreenCell *refCell = d->cellAt(x, y); if (!refCell) @@ -466,7 +470,8 @@ void TerminalSurface::sendKey(QKeyEvent *event) Cursor TerminalSurface::cursor() const { Cursor cursor = d->m_cursor; - cursor.position.setY(cursor.position.y() + d->m_scrollback->size()); + if (!d->m_altscreen) + cursor.position.setY(cursor.position.y() + d->m_scrollback->size()); return cursor; } diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 8df6e3c02aa..b40110e653e 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -278,6 +278,8 @@ void TerminalWidget::setupSurface() configBlinkTimer(); }); connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] { + updateScrollBars(); + updateViewport(); setSelection(std::nullopt); }); connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] { From e54b0e93c286f3246c8970582ffd0ab5fdb63024 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 6 Mar 2023 18:37:45 +0100 Subject: [PATCH 0207/1447] Terminal: Fix selections Selections were invisible if a cell with a background color was selected. Changes to the terminal did not reliably reset the selection. Change-Id: I923223f43e5ee1b6576966f9dd791aa109ac1d5f Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalsurface.cpp | 3 - src/plugins/terminal/terminalwidget.cpp | 73 ++++++++++++------------ src/plugins/terminal/terminalwidget.h | 9 ++- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index eb95215f948..ad47fd8b15b 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -459,9 +459,6 @@ void TerminalSurface::sendKey(QKeyEvent *event) } vterm_keyboard_unichar(d->m_vterm.get(), event->text().toUcs4()[0], VTERM_MOD_NONE); - - // TODO: ?? - //setSelection(std::nullopt); } else if (mod == VTERM_MOD_CTRL && event->key() >= Qt::Key_A && event->key() < Qt::Key_Z) { vterm_keyboard_unichar(d->m_vterm.get(), 'a' + (event->key() - Qt::Key_A), mod); } diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index b40110e653e..cb8e50166da 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -256,7 +256,12 @@ void TerminalWidget::setupSurface() connect(m_surface.get(), &Internal::TerminalSurface::invalidated, this, - [this](const QRect &rect) { updateViewport(gridToViewport(rect)); }); + [this](const QRect &rect) { + if (setSelection(std::nullopt)) + updateViewport(); + else + updateViewport(gridToViewport(rect)); + }); connect(m_surface.get(), &Internal::TerminalSurface::cursorChanged, this, @@ -430,13 +435,20 @@ void TerminalWidget::flushVTerm(bool force) } } -void TerminalWidget::setSelection(const std::optional &selection) +bool TerminalWidget::setSelection(const std::optional &selection) { if (selection.has_value() != m_selection.has_value()) { qCDebug(selectionLog) << "Copy enabled:" << selection.has_value(); m_copyAction.setEnabled(selection.has_value()); } + + if (selection.has_value() && m_selection.has_value()) { + if (*selection == *m_selection) + return false; + } + m_selection = selection; + return true; } QString TerminalWidget::shellName() const @@ -628,14 +640,31 @@ static void drawTextItemDecoration(QPainter &painter, painter.setBrush(oldBrush); } +void TerminalWidget::paintSelectionOrBackground(QPainter &p, + const Internal::TerminalCell &cell, + const QRectF &cellRect, + const QPoint gridPos) const +{ + bool isInSelection = false; + + if (m_selection) { + const int pos = m_surface->gridToPos(gridPos); + isInSelection = pos >= m_selection->start && pos < m_selection->end; + } + + if (isInSelection) + p.fillRect(cellRect, TerminalSettings::instance().selectionColor.value()); + else if (cell.background) + p.fillRect(cellRect, *cell.background); +} + int TerminalWidget::paintCell(QPainter &p, const QRectF &cellRect, QPoint gridPos, const Internal::TerminalCell &cell, QFont &f) const { - if (cell.background) - p.fillRect(cellRect, *cell.background); + paintSelectionOrBackground(p, cell, cellRect, gridPos); p.setPen(cell.foreground); @@ -759,37 +788,6 @@ void TerminalWidget::paintCells(QPainter &p, QPaintEvent *event) const } } -void TerminalWidget::paintSelection(QPainter &p) const -{ - if (!m_selection) - return; - - const QPoint start = m_surface->posToGrid(m_selection->start); - const QPoint end = m_surface->posToGrid(m_selection->end); - - const QColor selectionColor = TerminalSettings::instance().selectionColor.value(); - const QSize liveSize = m_surface->liveSize(); - - if (start.y() != end.y()) { - QRectF firstLineRect = QRectF(gridToGlobal(start), - gridToGlobal({liveSize.width(), start.y()}, true)); - - p.fillRect(firstLineRect, selectionColor); - - if (end.y() > start.y() + 1) { - QRectF middleRect = QRectF(gridToGlobal({0, (start.y() + 1)}), - gridToGlobal({liveSize.width(), end.y() - 1}, true)); - p.fillRect(middleRect, selectionColor); - } - - QRectF lastLineRect = QRectF(gridToGlobal({0, end.y()}), gridToGlobal(end, true)); - p.fillRect(lastLineRect, selectionColor); - } else { - QRectF rect = QRectF(gridToGlobal(start), gridToGlobal(end, true)); - p.fillRect(rect, selectionColor); - } -} - void TerminalWidget::paintDebugSelection(QPainter &p, const Selection &selection) const { auto s = globalToViewport(gridToGlobal(m_surface->posToGrid(selection.start)).toPoint()); @@ -829,7 +827,6 @@ void TerminalWidget::paintEvent(QPaintEvent *event) p.translate(QPointF{0.0, offset + margin}); - paintSelection(p); paintCells(p, event); paintCursor(p); paintPreedit(p); @@ -878,8 +875,8 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) } if (actionTriggered) { - setSelection(std::nullopt); - updateViewport(); + if (setSelection(std::nullopt)) + updateViewport(); return; } diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 6238fac52c7..3e4da77fc18 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -56,6 +56,8 @@ public: { return start != other.start || end != other.end; } + + bool operator==(const Selection &other) const { return !operator!=(other); } }; struct LinkSelection : public Selection @@ -111,7 +113,10 @@ protected: void paintCells(QPainter &painter, QPaintEvent *event) const; void paintCursor(QPainter &painter) const; void paintPreedit(QPainter &painter) const; - void paintSelection(QPainter &painter) const; + void paintSelectionOrBackground(QPainter &painter, + const Internal::TerminalCell &cell, + const QRectF &cellRect, + const QPoint gridPos) const; void paintDebugSelection(QPainter &painter, const Selection &selection) const; qreal topMargin() const; @@ -148,7 +153,7 @@ protected: void flushVTerm(bool force); - void setSelection(const std::optional &selection); + bool setSelection(const std::optional &selection); void configBlinkTimer(); From ce091cbcca5164bf4faad419d17feae8b763fe17 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 9 Mar 2023 20:08:49 +0100 Subject: [PATCH 0208/1447] Terminal: add minMax terminal panel keyboard shortcut On Windows the terminal (both cmd and Terminal) have Alt+Return as fullscreen. For Qt Creator this will map to the minMax Terminal panel action. Change-Id: I04594850a0fafa8f620dc81d0b5b49937c12a0cd Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalpane.cpp | 11 ++++++++++- src/plugins/terminal/terminalpane.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index c70cb412e3c..3ad8fc713a5 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -89,6 +89,15 @@ TerminalPane::TerminalPane(QObject *parent) if (canPrevious()) goToPrev(); }); + + m_minMaxAction.setShortcut(QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return") + : QLatin1String("Alt+Return"))); + + connect(&m_minMaxAction, &QAction::triggered, this, []() { + Core::Command *minMaxCommand = Core::ActionManager::command("Coreplugin.OutputPane.minmax"); + if (minMaxCommand) + emit minMaxCommand->action()->triggered(); + }); } static std::optional startupProjectDirectory() @@ -189,7 +198,7 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) if (!terminal->shellName().isEmpty()) setTabText(terminal); - terminal->addActions({&m_newTerminal, &m_nextTerminal, &m_prevTerminal}); + terminal->addActions({&m_newTerminal, &m_nextTerminal, &m_prevTerminal, &m_minMaxAction}); } QList TerminalPane::toolBarWidgets() const diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 1761e1b556a..59621b9b665 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -55,6 +55,7 @@ private: QAction m_closeTerminal; QAction m_nextTerminal; QAction m_prevTerminal; + QAction m_minMaxAction; }; } // namespace Terminal From 4fc891563a053d4e225cc28144c6897118fe978e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 20:08:29 +0100 Subject: [PATCH 0209/1447] DiffEditor: Fix DiffEditor tests Amends 5ff073df19b872b8db601f31e1124c6048a89a3c Change-Id: I4597453b057dfce41b73b4973205cba33d8e4a58 Reviewed-by: Qt CI Bot Reviewed-by: hjk Reviewed-by: --- src/libs/utils/differ.cpp | 6 +++--- src/libs/utils/differ.h | 6 ++++-- src/plugins/diffeditor/diffutils.cpp | 13 ++++++++----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/libs/utils/differ.cpp b/src/libs/utils/differ.cpp index b1c163bb5b4..9dc2ce8454e 100644 --- a/src/libs/utils/differ.cpp +++ b/src/libs/utils/differ.cpp @@ -936,7 +936,7 @@ QString Diff::toString() const /////////////// -Differ::Differ(const QFuture &future) +Differ::Differ(const std::optional> &future) : m_future(future) { } @@ -1073,7 +1073,7 @@ QList Differ::diffMyers(const QString &text1, const QString &text2) int kMinReverse = -D; int kMaxReverse = D; for (int d = 0; d <= D; d++) { - if (m_future.isCanceled()) { + if (m_future && m_future->isCanceled()) { delete [] forwardV; delete [] reverseV; return QList(); @@ -1192,7 +1192,7 @@ QList Differ::diffNonCharMode(const QString &text1, const QString &text2) QString lastInsert; QList newDiffList; for (int i = 0; i <= diffList.count(); i++) { - if (m_future.isCanceled()) { + if (m_future && m_future->isCanceled()) { m_currentDiffMode = diffMode; return {}; } diff --git a/src/libs/utils/differ.h b/src/libs/utils/differ.h index 09b79652225..dc6d74f30da 100644 --- a/src/libs/utils/differ.h +++ b/src/libs/utils/differ.h @@ -8,6 +8,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE template class QMap; @@ -42,7 +44,7 @@ public: WordMode, LineMode }; - Differ(const QFuture &future = {}); + Differ(const std::optional> &future = {}); QList diff(const QString &text1, const QString &text2); QList unifiedDiff(const QString &text1, const QString &text2); void setDiffMode(DiffMode mode); @@ -90,7 +92,7 @@ private: int subTextStart); DiffMode m_diffMode = Differ::LineMode; DiffMode m_currentDiffMode = Differ::LineMode; - QFuture m_future; + std::optional> m_future; }; } // namespace Utils diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index efea3530a43..afb75203037 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -557,7 +557,7 @@ static QList readLines(QStringView patch, bool lastChunk, bool *lastChu int noNewLineInDelete = -1; int noNewLineInInsert = -1; - const QVector lines = patch.split(newLine); + const QList lines = patch.split(newLine); int i; for (i = 0; i < lines.size(); i++) { QStringView line = lines.at(i); @@ -795,7 +795,7 @@ static QList readChunks(QStringView patch, bool *lastChunkAtTheEndOfF QList chunkDataList; int position = -1; - QVector startingPositions; // store starting positions of @@ + QList startingPositions; // store starting positions of @@ if (patch.startsWith(QStringLiteral("@@ -"))) startingPositions.append(position + 1); @@ -1199,7 +1199,7 @@ static void readGitPatch(QPromise> &promise, QStringView patch) { int position = -1; - QVector startingPositions; // store starting positions of git headers + QList startingPositions; // store starting positions of git headers if (patch.startsWith(QStringLiteral("diff --git "))) startingPositions.append(position + 1); @@ -1214,7 +1214,7 @@ static void readGitPatch(QPromise> &promise, QStringView patch) const QChar newLine('\n'); - QVector patches; + QList patches; const int count = startingPositions.size(); for (int i = 0; i < count; i++) { if (promise.isCanceled()) @@ -1239,10 +1239,12 @@ static void readGitPatch(QPromise> &promise, QStringView patch) patches.append(PatchInfo { remainingFileDiff, fileData }); } + if (patches.isEmpty()) + return; + promise.setProgressRange(0, patches.size()); QList fileDataList; - bool readOk = false; int i = 0; for (const auto &patchInfo : std::as_const(patches)) { if (promise.isCanceled()) @@ -1250,6 +1252,7 @@ static void readGitPatch(QPromise> &promise, QStringView patch) promise.setProgressValue(i++); FileData fileData = patchInfo.fileData; + bool readOk = false; if (!patchInfo.patch.isEmpty() || fileData.fileOperation == FileData::ChangeFile) fileData.chunks = readChunks(patchInfo.patch, &fileData.lastChunkAtTheEndOfFile, &readOk); else From 209b591eaced20447fb5c639b465c798b288e3e9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 18:02:18 +0100 Subject: [PATCH 0210/1447] TextEditor: Use QtConcurrent invocation for async run Change-Id: I4b40e2e3591a9a74570e318e216c4ad74c01ca6b Reviewed-by: Qt CI Bot Reviewed-by: David Schulz Reviewed-by: --- src/plugins/texteditor/codeassist/asyncprocessor.cpp | 4 ++-- src/plugins/texteditor/formattexteditor.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/texteditor/codeassist/asyncprocessor.cpp b/src/plugins/texteditor/codeassist/asyncprocessor.cpp index 90f993a39c7..bd074f04c0d 100644 --- a/src/plugins/texteditor/codeassist/asyncprocessor.cpp +++ b/src/plugins/texteditor/codeassist/asyncprocessor.cpp @@ -6,7 +6,7 @@ #include "assistinterface.h" #include "iassistproposal.h" -#include +#include namespace TextEditor { @@ -21,7 +21,7 @@ IAssistProposal *AsyncProcessor::perform() { IAssistProposal *result = immediateProposal(); interface()->prepareForAsyncUse(); - m_watcher.setFuture(Utils::runAsync([this] { + m_watcher.setFuture(Utils::asyncRun([this] { interface()->recreateTextDocument(); return performAsync(); })); diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp index 8f2fc358441..7066e249409 100644 --- a/src/plugins/texteditor/formattexteditor.cpp +++ b/src/plugins/texteditor/formattexteditor.cpp @@ -10,10 +10,10 @@ #include +#include #include #include #include -#include #include #include @@ -324,7 +324,7 @@ void formatEditorAsync(TextEditorWidget *editor, const Command &command, int sta checkAndApplyTask(watcher->result()); watcher->deleteLater(); }); - watcher->setFuture(Utils::runAsync(&format, FormatTask(editor, doc->filePath(), sd, + watcher->setFuture(Utils::asyncRun(&format, FormatTask(editor, doc->filePath(), sd, command, startPos, endPos))); } From 3fae8fdc36bf9d1a489e70618808632922dd47a4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 17:11:29 +0100 Subject: [PATCH 0211/1447] Python: Use QtConcurrent invocation for async run Change-Id: I26254d5c78c3b6ea06ed9baec8e52b988a6e9608 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz Reviewed-by: --- src/plugins/python/pipsupport.cpp | 4 ++-- src/plugins/python/pyside.cpp | 5 ++--- src/plugins/python/pythonlanguageclient.cpp | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index c23ae2d8649..96aa4f64e2f 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -14,9 +14,9 @@ #include #include +#include #include #include -#include using namespace Utils; @@ -145,7 +145,7 @@ Pip *Pip::instance(const FilePath &python) QFuture Pip::info(const PipPackage &package) { - return Utils::runAsync(&Pip::infoImpl, this, package); + return Utils::asyncRun(&Pip::infoImpl, this, package); } PipPackageInfo Pip::infoImpl(const PipPackage &package) diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index 592addd3085..f16e81af939 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -17,10 +17,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -140,8 +140,7 @@ void PySideInstaller::runPySideChecker(const FilePath &python, handlePySideMissing(python, pySide, document); watcher->deleteLater(); }); - watcher->setFuture( - Utils::runAsync(&missingPySideInstallation, python, pySide)); + watcher->setFuture(Utils::asyncRun(&missingPySideInstallation, python, pySide)); } } // Python::Internal diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index 74edb153e12..088cd516440 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -29,9 +29,9 @@ #include #include +#include #include #include -#include #include #include @@ -341,7 +341,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, instance()->handlePyLSState(python, watcher->result(), document); watcher->deleteLater(); }); - watcher->setFuture(Utils::runAsync(&checkPythonLanguageServer, python)); + watcher->setFuture(Utils::asyncRun(&checkPythonLanguageServer, python)); } void PyLSConfigureAssistant::handlePyLSState(const FilePath &python, From 0613a492f375714b1f8807839c87858c1a665efa Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 6 Dec 2022 12:36:26 +0100 Subject: [PATCH 0212/1447] Vcpkg: Initial commit This introduces the vcpkg support plugin. Initial features are: - Options page for defining vcpkg installation location - Search dialog for searching/selecting a package (incl. parsing autotest) - TextEditor that shows search/options toolbuttons - File wizard that creates a vcpkg.json manifest Change-Id: I098784100c869e0bb2ed6f60db4dedad559a142a Reviewed-by: hjk --- src/plugins/CMakeLists.txt | 1 + src/plugins/plugins.qbs | 1 + src/plugins/vcpkg/CMakeLists.txt | 16 ++ src/plugins/vcpkg/Vcpkg.json.in | 30 +++ src/plugins/vcpkg/vcpkg.qbs | 34 +++ src/plugins/vcpkg/vcpkg.qrc | 6 + src/plugins/vcpkg/vcpkg_test.cpp | 110 +++++++++ src/plugins/vcpkg/vcpkg_test.h | 24 ++ src/plugins/vcpkg/vcpkgconstants.h | 14 ++ src/plugins/vcpkg/vcpkgmanifesteditor.cpp | 71 ++++++ src/plugins/vcpkg/vcpkgmanifesteditor.h | 16 ++ src/plugins/vcpkg/vcpkgplugin.cpp | 38 ++++ src/plugins/vcpkg/vcpkgplugin.h | 26 +++ src/plugins/vcpkg/vcpkgsearch.cpp | 214 ++++++++++++++++++ src/plugins/vcpkg/vcpkgsearch.h | 29 +++ src/plugins/vcpkg/vcpkgsettings.cpp | 80 +++++++ src/plugins/vcpkg/vcpkgsettings.h | 30 +++ src/plugins/vcpkg/vcpkgtr.h | 15 ++ .../vcpkg/wizards/manifest/vcpkg.json.tpl | 6 + .../vcpkg/wizards/manifest/wizard.json | 80 +++++++ 20 files changed, 841 insertions(+) create mode 100644 src/plugins/vcpkg/CMakeLists.txt create mode 100644 src/plugins/vcpkg/Vcpkg.json.in create mode 100644 src/plugins/vcpkg/vcpkg.qbs create mode 100644 src/plugins/vcpkg/vcpkg.qrc create mode 100644 src/plugins/vcpkg/vcpkg_test.cpp create mode 100644 src/plugins/vcpkg/vcpkg_test.h create mode 100644 src/plugins/vcpkg/vcpkgconstants.h create mode 100644 src/plugins/vcpkg/vcpkgmanifesteditor.cpp create mode 100644 src/plugins/vcpkg/vcpkgmanifesteditor.h create mode 100644 src/plugins/vcpkg/vcpkgplugin.cpp create mode 100644 src/plugins/vcpkg/vcpkgplugin.h create mode 100644 src/plugins/vcpkg/vcpkgsearch.cpp create mode 100644 src/plugins/vcpkg/vcpkgsearch.h create mode 100644 src/plugins/vcpkg/vcpkgsettings.cpp create mode 100644 src/plugins/vcpkg/vcpkgsettings.h create mode 100644 src/plugins/vcpkg/vcpkgtr.h create mode 100644 src/plugins/vcpkg/wizards/manifest/vcpkg.json.tpl create mode 100644 src/plugins/vcpkg/wizards/manifest/wizard.json diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 5e3ff9bb18a..02f13199140 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -27,6 +27,7 @@ add_subdirectory(help) add_subdirectory(resourceeditor) add_subdirectory(nim) add_subdirectory(conan) +add_subdirectory(vcpkg) # Level 4: (only depends on Level 3 and below) add_subdirectory(classview) diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index d28aeb05f17..8e57311d9fe 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -84,6 +84,7 @@ Project { "todo/todo.qbs", "updateinfo/updateinfo.qbs", "valgrind/valgrind.qbs", + "vcpkg/vcpkg.qbs", "vcsbase/vcsbase.qbs", "webassembly/webassembly.qbs", "welcome/welcome.qbs", diff --git a/src/plugins/vcpkg/CMakeLists.txt b/src/plugins/vcpkg/CMakeLists.txt new file mode 100644 index 00000000000..f5d65cf3937 --- /dev/null +++ b/src/plugins/vcpkg/CMakeLists.txt @@ -0,0 +1,16 @@ +add_qtc_plugin(Vcpkg + PLUGIN_DEPENDS Core ProjectExplorer + SOURCES + vcpkg.qrc + vcpkgconstants.h + vcpkgmanifesteditor.cpp vcpkgmanifesteditor.h + vcpkgplugin.cpp vcpkgplugin.h + vcpkgsearch.cpp vcpkgsearch.h + vcpkgsettings.cpp vcpkgsettings.h +) + +extend_qtc_plugin(Vcpkg + CONDITION WITH_TESTS + SOURCES + vcpkg_test.cpp vcpkg_test.h +) diff --git a/src/plugins/vcpkg/Vcpkg.json.in b/src/plugins/vcpkg/Vcpkg.json.in new file mode 100644 index 00000000000..7357c9e845b --- /dev/null +++ b/src/plugins/vcpkg/Vcpkg.json.in @@ -0,0 +1,30 @@ +{ + \"Name\" : \"Vcpkg\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"Vendor\" : \"The Qt Company Ltd\", + \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", + \"\", + \"GNU General Public License Usage\", + \"\", + \"Alternatively, this plugin 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 plugin. 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.\" + ], + \"Experimental\" : true, + \"Description\" : \"vcpkg integration.\", + \"Url\" : \"http://www.qt.io\", + $$dependencyList, + + \"Mimetypes\" : [ + \"\", + \"\", + \" \", + \" \", + \" Vcpkg Manifest File\", + \" \", + \" \", + \"\" + ] +} diff --git a/src/plugins/vcpkg/vcpkg.qbs b/src/plugins/vcpkg/vcpkg.qbs new file mode 100644 index 00000000000..9ab32702090 --- /dev/null +++ b/src/plugins/vcpkg/vcpkg.qbs @@ -0,0 +1,34 @@ +import qbs 1.0 + +QtcPlugin { + name: "Vcpkg" + + Depends { name: "Qt.widgets" } + Depends { name: "Utils" } + + Depends { name: "Core" } + Depends { name: "ProjectExplorer" } + Depends { name: "TextEditor" } + + files: [ + "vcpkg.qrc", + "vcpkgconstants.h", + "vcpkgmanifesteditor.cpp", + "vcpkgmanifesteditor.h", + "vcpkgplugin.cpp", + "vcpkgplugin.h", + "vcpkgsearch.cpp", + "vcpkgsearch.h", + "vcpkgsettings.cpp", + "vcpkgsettings.h", + ] + + Group { + name: "Unit tests" + condition: qtc.testsEnabled + files: [ + "vcpkg_test.h", + "vcpkg_test.cpp", + ] + } +} diff --git a/src/plugins/vcpkg/vcpkg.qrc b/src/plugins/vcpkg/vcpkg.qrc new file mode 100644 index 00000000000..a377b736db3 --- /dev/null +++ b/src/plugins/vcpkg/vcpkg.qrc @@ -0,0 +1,6 @@ + + + wizards/manifest/vcpkg.json.tpl + wizards/manifest/wizard.json + + diff --git a/src/plugins/vcpkg/vcpkg_test.cpp b/src/plugins/vcpkg/vcpkg_test.cpp new file mode 100644 index 00000000000..65079b96a4e --- /dev/null +++ b/src/plugins/vcpkg/vcpkg_test.cpp @@ -0,0 +1,110 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "vcpkg_test.h" + +#include "vcpkgsearch.h" + +#include + +namespace Vcpkg::Internal { + +VcpkgSearchTest::VcpkgSearchTest(QObject *parent) + : QObject(parent) +{ } + +VcpkgSearchTest::~VcpkgSearchTest() = default; + +void VcpkgSearchTest::testVcpkgJsonParser_data() +{ + QTest::addColumn("vcpkgManifestJsonData"); + QTest::addColumn("name"); + QTest::addColumn("version"); + QTest::addColumn("license"); + QTest::addColumn("shortDescription"); + QTest::addColumn("description"); + QTest::addColumn("homepage"); + QTest::addColumn("success"); + + QTest::newRow("cimg, version, short description") + << R"({ + "name": "cimg", + "version": "2.9.9", + "description": "The CImg Library is a small, open-source, and modern C++ toolkit for image processing", + "homepage": "https://github.com/dtschump/CImg", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + } + ] + })" + << "cimg" + << "2.9.9" + << "" + << "The CImg Library is a small, open-source, and modern C++ toolkit for image processing" + << QStringList() + << QUrl::fromUserInput("https://github.com/dtschump/CImg") + << true; + + QTest::newRow("catch-classic, version-string, complete description") + << R"({ + "name": "catch-classic", + "version-string": "1.12.2", + "port-version": 1, + "description": [ + "A modern, header-only test framework for unit tests", + "This is specifically the legacy 1.x branch provided for compatibility", + "with older compilers." + ], + "homepage": "https://github.com/catchorg/Catch2" + })" + << "catch-classic" + << "1.12.2" + << "" + << "A modern, header-only test framework for unit tests" + << QStringList({"This is specifically the legacy 1.x branch provided for compatibility", + "with older compilers."}) + << QUrl::fromUserInput("https://github.com/catchorg/Catch2") + << true; + + QTest::newRow("Incomplete") + << R"({ + "version-semver": "1.0", + "description": "foo", + "license": "WTFPL" + })" + << "" + << "1.0" + << "WTFPL" + << "foo" + << QStringList() + << QUrl() + << false; +} + +void VcpkgSearchTest::testVcpkgJsonParser() +{ + QFETCH(QString, vcpkgManifestJsonData); + QFETCH(QString, name); + QFETCH(QString, version); + QFETCH(QString, license); + QFETCH(QString, shortDescription); + QFETCH(QStringList, description); + QFETCH(QUrl, homepage); + QFETCH(bool, success); + + bool ok = false; + const Search::VcpkgManifest mf = + Search::parseVcpkgManifest(vcpkgManifestJsonData.toUtf8(), &ok); + + QCOMPARE(mf.name, name); + QCOMPARE(mf.version, version); + QCOMPARE(mf.license, license); + QCOMPARE(mf.shortDescription, shortDescription); + QCOMPARE(mf.description, description); + QCOMPARE(mf.homepage, homepage); + QCOMPARE(ok, success); +} + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkg_test.h b/src/plugins/vcpkg/vcpkg_test.h new file mode 100644 index 00000000000..8175e28d594 --- /dev/null +++ b/src/plugins/vcpkg/vcpkg_test.h @@ -0,0 +1,24 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace Vcpkg::Internal { + +class VcpkgSearchTest : public QObject +{ + Q_OBJECT + +public: + VcpkgSearchTest(QObject *parent = nullptr); + ~VcpkgSearchTest(); + +private slots: + void testVcpkgJsonParser_data(); + void testVcpkgJsonParser(); +}; + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgconstants.h b/src/plugins/vcpkg/vcpkgconstants.h new file mode 100644 index 00000000000..644dfab95f9 --- /dev/null +++ b/src/plugins/vcpkg/vcpkgconstants.h @@ -0,0 +1,14 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace Vcpkg::Constants { + +const char TOOLSSETTINGSPAGE_ID[] = "Vcpkg.VcpkgSettings"; +const char WEBSITE_URL[] = "https://vcpkg.io/"; +const char ENVVAR_VCPKG_ROOT[] = "VCPKG_ROOT"; +const char VCPKGMANIFEST_EDITOR_ID[] = "Vcpkg.VcpkgManifestEditor"; +const char VCPKGMANIFEST_MIMETYPE[] = "application/vcpkg.manifest+json"; + +} // namespace Vcpkg::Constants diff --git a/src/plugins/vcpkg/vcpkgmanifesteditor.cpp b/src/plugins/vcpkg/vcpkgmanifesteditor.cpp new file mode 100644 index 00000000000..fa7c6ebfaf3 --- /dev/null +++ b/src/plugins/vcpkg/vcpkgmanifesteditor.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "vcpkgmanifesteditor.h" + +#include "vcpkgconstants.h" +#include "vcpkgsearch.h" +#include "vcpkgsettings.h" +#include "vcpkgtr.h" + +#include + +#include + +#include + +#include + +namespace Vcpkg::Internal { + +class VcpkgManifestEditorWidget : public TextEditor::TextEditorWidget +{ +public: + VcpkgManifestEditorWidget() + { + m_searchPkgAction = toolBar()->addAction(Utils::Icons::ZOOM_TOOLBAR.icon(), + Tr::tr("Search package...")); + connect(m_searchPkgAction, &QAction::triggered, this, [this] { + const Search::VcpkgManifest package = Search::showVcpkgPackageSearchDialog(); + if (!package.name.isEmpty()) + textCursor().insertText(package.name); + }); + updateToolBar(); + + QAction *optionsAction = toolBar()->addAction(Utils::Icons::SETTINGS_TOOLBAR.icon(), + Core::ICore::msgShowOptionsDialog()); + connect(optionsAction, &QAction::triggered, [] { + Core::ICore::showOptionsDialog(Constants::TOOLSSETTINGSPAGE_ID); + }); + + connect(&VcpkgSettings::instance()->vcpkgRoot, &Utils::BaseAspect::changed, + this, &VcpkgManifestEditorWidget::updateToolBar); + } + + void updateToolBar() + { + m_searchPkgAction->setEnabled(VcpkgSettings::instance()->vcpkgRootValid()); + } + +private: + QAction *m_searchPkgAction; +}; + +static TextEditor::TextDocument *createVcpkgManifestDocument() +{ + auto doc = new TextEditor::TextDocument; + doc->setId(Constants::VCPKGMANIFEST_EDITOR_ID); + return doc; +} + +VcpkgManifestEditorFactory::VcpkgManifestEditorFactory() +{ + setId(Constants::VCPKGMANIFEST_EDITOR_ID); + setDisplayName(Tr::tr("Vcpkg Manifest Editor")); + addMimeType(Constants::VCPKGMANIFEST_MIMETYPE); + setDocumentCreator(createVcpkgManifestDocument); + setEditorWidgetCreator([] { return new VcpkgManifestEditorWidget; }); + setUseGenericHighlighter(true); +} + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgmanifesteditor.h b/src/plugins/vcpkg/vcpkgmanifesteditor.h new file mode 100644 index 00000000000..c7762d69df9 --- /dev/null +++ b/src/plugins/vcpkg/vcpkgmanifesteditor.h @@ -0,0 +1,16 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Vcpkg::Internal { + +class VcpkgManifestEditorFactory : public TextEditor::TextEditorFactory +{ +public: + VcpkgManifestEditorFactory(); +}; + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgplugin.cpp b/src/plugins/vcpkg/vcpkgplugin.cpp new file mode 100644 index 00000000000..883b6896a72 --- /dev/null +++ b/src/plugins/vcpkg/vcpkgplugin.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "vcpkgplugin.h" + +#ifdef WITH_TESTS +#include "vcpkg_test.h" +#endif // WITH_TESTS +#include "vcpkgmanifesteditor.h" +#include "vcpkgsettings.h" + +#include + +namespace Vcpkg::Internal { + +class VcpkgPluginPrivate +{ +public: + VcpkgManifestEditorFactory manifestEditorFactory; + VcpkgSettingsPage settingsPage; +}; + +VcpkgPlugin::~VcpkgPlugin() +{ + delete d; +} + +void VcpkgPlugin::initialize() +{ + d = new VcpkgPluginPrivate; + ProjectExplorer::JsonWizardFactory::addWizardPath(":/vcpkg/wizards/"); + +#ifdef WITH_TESTS + addTest(); +#endif +} + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgplugin.h b/src/plugins/vcpkg/vcpkgplugin.h new file mode 100644 index 00000000000..797083ea956 --- /dev/null +++ b/src/plugins/vcpkg/vcpkgplugin.h @@ -0,0 +1,26 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace ProjectExplorer { class Project; } + +namespace Vcpkg::Internal { + +class VcpkgPlugin final : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Vcpkg.json") + +public: + ~VcpkgPlugin(); + + void initialize() final; + +private: + class VcpkgPluginPrivate *d = nullptr; +}; + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgsearch.cpp b/src/plugins/vcpkg/vcpkgsearch.cpp new file mode 100644 index 00000000000..dc3fe7a0c6c --- /dev/null +++ b/src/plugins/vcpkg/vcpkgsearch.cpp @@ -0,0 +1,214 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "vcpkgsearch.h" + +#include "qpushbutton.h" +#include "vcpkgsettings.h" +#include "vcpkgtr.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace Utils; + +namespace Vcpkg::Internal::Search { + +class VcpkgPackageSearchDialog : public QDialog +{ +public: + explicit VcpkgPackageSearchDialog(QWidget *parent); + + VcpkgManifest selectedPackage() const; + +private: + void listPackages(const QString &filter); + void showPackageDetails(const QString &packageName); + + VcpkgManifests m_allPackages; + VcpkgManifest m_selectedPackage; + + FancyLineEdit *m_packagesFilter; + ListWidget *m_packagesList; + QLineEdit *m_vcpkgName; + QLabel *m_vcpkgVersion; + QLabel *m_vcpkgLicense; + QTextBrowser *m_vcpkgDescription; + QLabel *m_vcpkgHomepage; + QDialogButtonBox *m_buttonBox; +}; + +VcpkgPackageSearchDialog::VcpkgPackageSearchDialog(QWidget *parent) + : QDialog(parent) +{ + resize(920, 400); + + m_packagesFilter = new FancyLineEdit; + m_packagesFilter->setFiltering(true); + m_packagesFilter->setFocus(); + m_packagesFilter->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + + m_packagesList = new ListWidget; + m_packagesList->setMaximumWidth(300); + + m_vcpkgName = new QLineEdit; + m_vcpkgName->setReadOnly(true); + + m_vcpkgVersion = new QLabel; + m_vcpkgLicense = new QLabel; + m_vcpkgDescription = new QTextBrowser; + + m_vcpkgHomepage = new QLabel; + m_vcpkgHomepage->setOpenExternalLinks(true); + m_vcpkgHomepage->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + m_vcpkgHomepage->setTextInteractionFlags(Qt::TextBrowserInteraction); + + m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close); + + using namespace Utils::Layouting; + Column { + Row { + Column { + m_packagesFilter, + m_packagesList, + }, + Form { + Tr::tr("Name:"), m_vcpkgName, br, + Tr::tr("Version:"), m_vcpkgVersion, br, + Tr::tr("License:"), m_vcpkgLicense, br, + Tr::tr("Description:"), m_vcpkgDescription, br, + Tr::tr("Homepage:"), m_vcpkgHomepage, br, + }, + }, + m_buttonBox, + }.attachTo(this); + + m_allPackages = vcpkgManifests(VcpkgSettings::instance()->vcpkgRoot.filePath()); + + listPackages({}); + + connect(m_packagesFilter, &FancyLineEdit::filterChanged, + this, &VcpkgPackageSearchDialog::listPackages); + connect(m_packagesList, &ListWidget::currentTextChanged, + this, &VcpkgPackageSearchDialog::showPackageDetails); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +VcpkgManifest VcpkgPackageSearchDialog::selectedPackage() const +{ + return m_selectedPackage; +} + +void VcpkgPackageSearchDialog::listPackages(const QString &filter) +{ + const VcpkgManifests filteredPackages = filtered(m_allPackages, + [&filter] (const VcpkgManifest &package) { + return filter.isEmpty() + || package.name.contains(filter, Qt::CaseInsensitive) + || package.shortDescription.contains(filter, Qt::CaseInsensitive) + || package.description.contains(filter, Qt::CaseInsensitive); + }); + QStringList names = transform(filteredPackages, [] (const VcpkgManifest &package) { + return package.name; + }); + names.sort(); + m_packagesList->clear(); + m_packagesList->addItems(names); +} + +void VcpkgPackageSearchDialog::showPackageDetails(const QString &packageName) +{ + const VcpkgManifest manifest = findOrDefault(m_allPackages, + [&packageName] (const VcpkgManifest &m) { + return m.name == packageName; + }); + + m_vcpkgName->setText(manifest.name); + m_vcpkgVersion->setText(manifest.version); + m_vcpkgLicense->setText(manifest.license); + QString description = manifest.shortDescription; + if (!manifest.description.isEmpty()) + description.append("

" + manifest.description.join("

") + "

"); + m_vcpkgDescription->setText(description); + m_vcpkgHomepage->setText(QString::fromLatin1("
%1") + .arg(manifest.homepage.toDisplayString())); + + m_selectedPackage = manifest; + m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!manifest.name.isEmpty()); +} + +VcpkgManifest parseVcpkgManifest(const QByteArray &vcpkgManifestJsonData, bool *ok) +{ + // https://learn.microsoft.com/en-us/vcpkg/reference/vcpkg-json + VcpkgManifest result; + const QJsonObject jsonObject = QJsonDocument::fromJson(vcpkgManifestJsonData).object(); + if (const QJsonValue name = jsonObject.value("name"); !name.isUndefined()) + result.name = name.toString(); + for (const char *key : {"version", "version-semver", "version-date", "version-string"} ) { + if (const QJsonValue ver = jsonObject.value(QLatin1String(key)); !ver.isUndefined()) { + result.version = ver.toString(); + break; + } + } + if (const QJsonValue license = jsonObject.value("license"); !license.isUndefined()) + result.license = license.toString(); + if (const QJsonValue description = jsonObject.value("description"); !description.isUndefined()) { + if (description.isArray()) { + const QJsonArray descriptionLines = description.toArray(); + for (const QJsonValue &val : descriptionLines) { + const QString line = val.toString(); + if (result.shortDescription.isEmpty()) { + result.shortDescription = line; + continue; + } + result.description.append(line); + } + } else { + result.shortDescription = description.toString(); + } + } + if (const QJsonValue homepage = jsonObject.value("homepage"); !homepage.isUndefined()) + result.homepage = QUrl::fromUserInput(homepage.toString()); + + if (ok) + *ok = !(result.name.isEmpty() || result.version.isEmpty()); + + return result; +} + +VcpkgManifests vcpkgManifests(const FilePath &vcpkgRoot) +{ + const FilePath portsDir = vcpkgRoot / "ports"; + VcpkgManifests result; + const FilePaths manifestFiles = + portsDir.dirEntries({{"vcpkg.json"}, QDir::Files, QDirIterator::Subdirectories}); + for (const FilePath &manifestFile : manifestFiles) { + FileReader reader; + if (reader.fetch(manifestFile)) { + const QByteArray &manifestData = reader.data(); + const VcpkgManifest manifest = parseVcpkgManifest(manifestData); + result.append(manifest); + } + } + return result; +} + +VcpkgManifest showVcpkgPackageSearchDialog(QWidget *parent) +{ + VcpkgPackageSearchDialog dlg(parent ? parent : Core::ICore::dialogParent()); + return (dlg.exec() == QDialog::Accepted) ? dlg.selectedPackage() : VcpkgManifest(); +} + +} // namespace Vcpkg::Internal::Search diff --git a/src/plugins/vcpkg/vcpkgsearch.h b/src/plugins/vcpkg/vcpkgsearch.h new file mode 100644 index 00000000000..bb2d568a00c --- /dev/null +++ b/src/plugins/vcpkg/vcpkgsearch.h @@ -0,0 +1,29 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +#include + +namespace Vcpkg::Internal::Search { + +struct VcpkgManifest +{ + QString name; + QString version; + QString license; + QString shortDescription; + QStringList description; + QUrl homepage; +}; + +using VcpkgManifests = QList; + +VcpkgManifest parseVcpkgManifest(const QByteArray &vcpkgManifestJsonData, bool *ok = nullptr); +VcpkgManifests vcpkgManifests(const Utils::FilePath &vcpkgRoot); +VcpkgManifest showVcpkgPackageSearchDialog(QWidget *parent = nullptr); + +} // namespace Vcpkg::Internal::Search diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp new file mode 100644 index 00000000000..bea6c8ed6c7 --- /dev/null +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "vcpkgsettings.h" + +#include "vcpkgconstants.h" + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +namespace Vcpkg::Internal { + +VcpkgSettings::VcpkgSettings() +{ + setSettingsGroup("Vcpkg"); + + registerAspect(&vcpkgRoot); + vcpkgRoot.setSettingsKey("VcpkgRoot"); + vcpkgRoot.setDisplayStyle(Utils::StringAspect::PathChooserDisplay); + vcpkgRoot.setExpectedKind(Utils::PathChooser::ExistingDirectory); + vcpkgRoot.setDefaultValue(Utils::qtcEnvironmentVariable(Constants::ENVVAR_VCPKG_ROOT)); + + readSettings(Core::ICore::settings()); +} + +VcpkgSettings *VcpkgSettings::instance() +{ + static VcpkgSettings s; + return &s; +} + +bool VcpkgSettings::vcpkgRootValid() const +{ + return (vcpkgRoot.filePath() / "vcpkg").withExecutableSuffix().isExecutableFile(); +} + +VcpkgSettingsPage::VcpkgSettingsPage() +{ + setId(Constants::TOOLSSETTINGSPAGE_ID); + setDisplayName("Vcpkg"); + setCategory(CMakeProjectManager::Constants::Settings::CATEGORY); + + setLayouter([] (QWidget *widget) { + auto websiteButton = new QToolButton; + websiteButton->setIcon(Utils::Icons::ONLINE.icon()); + websiteButton->setToolTip(Constants::WEBSITE_URL); + + using namespace Utils::Layouting; + Column { + Group { + title(tr("Vcpkg installation")), + Form { + Utils::PathChooser::label(), + Span{ 2, Row{ VcpkgSettings::instance()->vcpkgRoot, websiteButton} }, + }, + }, + st, + }.attachTo(widget); + + connect(websiteButton, &QAbstractButton::clicked, [] { + QDesktopServices::openUrl(QUrl::fromUserInput(Constants::WEBSITE_URL)); + }); + }); +} + +void VcpkgSettingsPage::apply() +{ + VcpkgSettings::instance()->writeSettings(Core::ICore::settings()); +} + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgsettings.h b/src/plugins/vcpkg/vcpkgsettings.h new file mode 100644 index 00000000000..a0a7973cc01 --- /dev/null +++ b/src/plugins/vcpkg/vcpkgsettings.h @@ -0,0 +1,30 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace Vcpkg::Internal { + +class VcpkgSettings : public Utils::AspectContainer +{ +public: + VcpkgSettings(); + + static VcpkgSettings *instance(); + bool vcpkgRootValid() const; + + Utils::StringAspect vcpkgRoot; +}; + +class VcpkgSettingsPage final : public Core::IOptionsPage +{ +public: + VcpkgSettingsPage(); + + void apply() override; +}; + +} // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgtr.h b/src/plugins/vcpkg/vcpkgtr.h new file mode 100644 index 00000000000..0914ce6444d --- /dev/null +++ b/src/plugins/vcpkg/vcpkgtr.h @@ -0,0 +1,15 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Vcpkg { + +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(Vcpkg) +}; + +} // namespace Vcpkg diff --git a/src/plugins/vcpkg/wizards/manifest/vcpkg.json.tpl b/src/plugins/vcpkg/wizards/manifest/vcpkg.json.tpl new file mode 100644 index 00000000000..1519949d2ea --- /dev/null +++ b/src/plugins/vcpkg/wizards/manifest/vcpkg.json.tpl @@ -0,0 +1,6 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", + "name": "%{Name}", + "version-string": "%{VersionString}", +%{Dependencies} +} diff --git a/src/plugins/vcpkg/wizards/manifest/wizard.json b/src/plugins/vcpkg/wizards/manifest/wizard.json new file mode 100644 index 00000000000..80e8b0fcc52 --- /dev/null +++ b/src/plugins/vcpkg/wizards/manifest/wizard.json @@ -0,0 +1,80 @@ +{ + "version": 1, + "supportedProjectTypes": [ ], + "id": "VcpkgManifest.Json", + "category": "U.VcpkgManifest", + "trDescription": "Creates a vcpkg.json manifest file.", + "trDisplayName": "vcpkg.json Manifest File", + "trDisplayCategory": "vcpkg", + "iconText": "json", + + "options": [ + { "key": "InitialFileName", "value": "vcpkg.json" }, + { "key": "TargetPath", "value": "%{Path}" } + ], + + "pages": + [ + { + "trDisplayName": "Location", + "trShortTitle": "Location", + "typeId": "File" + }, + { + "trDisplayName": "vcpkg.json Manifest File", + "trShortTitle": "Manifest fields", + "typeId": "Fields", + "data": + [ + { + "name": "Name", + "trDisplayName": "Name:", + "mandatory": true, + "type": "LineEdit", + "data": + { + "trText": "mypackage", + "validator": "^[a-z_0-9]+$" + } + }, + { + "name": "VersionString", + "trDisplayName": "Version string:", + "mandatory": true, + "type": "LineEdit", + "data": + { + "trText": "0.0.1" + } + }, + { + "name": "Dependencies", + "trDisplayName": "Dependencies:", + "mandatory": false, + "type": "TextEdit", + "data": + { + "trText": " \"dependencies\": [\n \"fmt\"\n ]" + } + } + ] + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + { + "source": "vcpkg.json.tpl", + "target": "%{Path}/vcpkg.json", + "openInEditor": true + } + } + ] +} From 40b0f670e11e25ec8a52b390b1b1ab16609a1c56 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 10 Mar 2023 08:54:25 +0100 Subject: [PATCH 0213/1447] DiffEditor: Don't use QFutureInterfaceBase::get() It's available only since Qt 6.3. Amends 5ff073df19b872b8db601f31e1124c6048a89a3c Change-Id: I38c8c3b0bc3c94612dee15614f00e83ebc86db04 Reviewed-by: Orgad Shaneh --- .../diffeditor/sidebysidediffeditorwidget.cpp | 25 +++++++------ .../diffeditor/sidebysidediffeditorwidget.h | 24 ++++++------- .../diffeditor/unifieddiffeditorwidget.cpp | 35 +++++++++---------- .../diffeditor/unifieddiffeditorwidget.h | 24 ++++++------- 4 files changed, 51 insertions(+), 57 deletions(-) diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index 3bff22f030f..6847bf0e3a2 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -244,8 +244,8 @@ QString SideDiffEditorWidget::plainTextFromSelection(const QTextCursor &cursor) return TextDocument::convertToPlainText(text); } -SideBySideDiffOutput SideDiffData::diffOutput(QFutureInterfaceBase &fi, int progressMin, - int progressMax, const DiffEditorInput &input) +static SideBySideDiffOutput diffOutput(QPromise &promise, int progressMin, + int progressMax, const DiffEditorInput &input) { SideBySideDiffOutput output; @@ -365,8 +365,8 @@ SideBySideDiffOutput SideDiffData::diffOutput(QFutureInterfaceBase &fi, int prog diffText[RightSide].replace('\r', ' '); output.side[LeftSide].diffText += diffText[LeftSide]; output.side[RightSide].diffText += diffText[RightSide]; - fi.setProgressValue(MathUtils::interpolateLinear(++i, 0, count, progressMin, progressMax)); - if (fi.isCanceled()) + promise.setProgressValue(MathUtils::interpolateLinear(++i, 0, count, progressMin, progressMax)); + if (promise.isCanceled()) return {}; } output.side[LeftSide].selections = SelectableTextEditorWidget::polishedSelections( @@ -868,7 +868,7 @@ void SideBySideDiffEditorWidget::restoreState() void SideBySideDiffEditorWidget::showDiff() { - m_asyncTask.reset(new AsyncTask()); + m_asyncTask.reset(new AsyncTask()); m_asyncTask->setFutureSynchronizer(DiffEditorPlugin::futureSynchronizer()); m_controller.setBusyShowing(true); @@ -877,7 +877,7 @@ void SideBySideDiffEditorWidget::showDiff() for (SideDiffEditorWidget *editor : m_editor) editor->clearAll(Tr::tr("Retrieving data failed.")); } else { - const ShowResults results = m_asyncTask->result(); + const SideBySideShowResults results = m_asyncTask->result(); m_editor[LeftSide]->setDiffData(results[LeftSide].diffData); m_editor[RightSide]->setDiffData(results[RightSide].diffData); TextDocumentPtr leftDoc(results[LeftSide].textDocument); @@ -913,24 +913,23 @@ void SideBySideDiffEditorWidget::showDiff() const DiffEditorInput input(&m_controller); - auto getDocument = [input](QPromise &promise) { + auto getDocument = [input](QPromise &promise) { const int firstPartMax = 20; // diffOutput is about 4 times quicker than filling document const int leftPartMax = 60; const int rightPartMax = 100; promise.setProgressRange(0, rightPartMax); promise.setProgressValue(0); - QFutureInterfaceBase fi = QFutureInterfaceBase::get(promise.future()); - const SideBySideDiffOutput output = SideDiffData::diffOutput(fi, 0, firstPartMax, input); + const SideBySideDiffOutput output = diffOutput(promise, 0, firstPartMax, input); if (promise.isCanceled()) return; - const ShowResult leftResult{TextDocumentPtr(new TextDocument("DiffEditor.SideDiffEditor")), + const SideBySideShowResult leftResult{TextDocumentPtr(new TextDocument("DiffEditor.SideDiffEditor")), output.side[LeftSide].diffData, output.side[LeftSide].selections}; - const ShowResult rightResult{TextDocumentPtr(new TextDocument("DiffEditor.SideDiffEditor")), + const SideBySideShowResult rightResult{TextDocumentPtr(new TextDocument("DiffEditor.SideDiffEditor")), output.side[RightSide].diffData, output.side[RightSide].selections}; - const ShowResults result{leftResult, rightResult}; + const SideBySideShowResults result{leftResult, rightResult}; - auto propagateDocument = [&output, &promise](DiffSide side, const ShowResult &result, + auto propagateDocument = [&output, &promise](DiffSide side, const SideBySideShowResult &result, int progressMin, int progressMax) { // No need to store the change history result.textDocument->document()->setUndoRedoEnabled(false); diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index e85e341b936..c12025a6c00 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -40,9 +40,6 @@ class SideBySideDiffOutput; class SideDiffData { public: - static SideBySideDiffOutput diffOutput(QFutureInterfaceBase &fi, int progressMin, - int progressMax, const DiffEditorInput &input); - DiffChunkInfo m_chunkInfo; // block number, fileInfo. Set for file lines only. QMap m_fileInfo; @@ -60,7 +57,6 @@ public: int blockNumberForFileIndex(int fileIndex) const; int fileIndexForBlockNumber(int blockNumber) const; -private: void setLineNumber(int blockNumber, int lineNumber); void setFileInfo(int blockNumber, const DiffFileInfo &fileInfo); void setSkippedLines(int blockNumber, int skippedLines, const QString &contextInfo = {}) { @@ -88,6 +84,16 @@ public: QHash foldingIndent; }; +class SideBySideShowResult +{ +public: + QSharedPointer textDocument{}; + SideDiffData diffData; + DiffSelections selections; +}; + +using SideBySideShowResults = std::array; + class SideBySideDiffEditorWidget : public QWidget { Q_OBJECT @@ -135,15 +141,7 @@ private: bool m_horizontalSync = false; - struct ShowResult - { - QSharedPointer textDocument{}; - SideDiffData diffData; - DiffSelections selections; - }; - using ShowResults = std::array; - - std::unique_ptr> m_asyncTask; + std::unique_ptr> m_asyncTask; }; } // namespace Internal diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index 82ba5e51fa4..cb113612c20 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -65,6 +65,14 @@ DiffEditorDocument *UnifiedDiffEditorWidget::diffDocument() const return m_controller.document(); } +void UnifiedDiffEditorWidget::setDiff(const QList &diffFileList) +{ + const GuardLocker locker(m_controller.m_ignoreChanges); + clear(Tr::tr("Waiting for data...")); + m_controller.m_contextFileData = diffFileList; + showDiff(); +} + void UnifiedDiffEditorWidget::saveState() { if (!m_state.isNull()) @@ -257,14 +265,6 @@ void UnifiedDiffData::setLineNumber(DiffSide side, int blockNumber, int lineNumb m_lineNumberDigits[side] = qMax(m_lineNumberDigits[side], lineNumberString.count()); } -void UnifiedDiffEditorWidget::setDiff(const QList &diffFileList) -{ - const GuardLocker locker(m_controller.m_ignoreChanges); - clear(Tr::tr("Waiting for data...")); - m_controller.m_contextFileData = diffFileList; - showDiff(); -} - QString UnifiedDiffData::setChunk(const DiffEditorInput &input, const ChunkData &chunkData, bool lastChunk, int *blockNumber, DiffSelections *selections) { @@ -388,8 +388,8 @@ QString UnifiedDiffData::setChunk(const DiffEditorInput &input, const ChunkData return diffText; } -UnifiedDiffOutput UnifiedDiffData::diffOutput(QFutureInterfaceBase &fi, int progressMin, - int progressMax, const DiffEditorInput &input) +static UnifiedDiffOutput diffOutput(QPromise &promise, int progressMin, + int progressMax, const DiffEditorInput &input) { UnifiedDiffOutput output; @@ -434,8 +434,8 @@ UnifiedDiffOutput UnifiedDiffData::diffOutput(QFutureInterfaceBase &fi, int prog output.diffData.m_chunkInfo.setChunkIndex(oldBlock, blockNumber - oldBlock, j); } } - fi.setProgressValue(MathUtils::interpolateLinear(++i, 0, count, progressMin, progressMax)); - if (fi.isCanceled()) + promise.setProgressValue(MathUtils::interpolateLinear(++i, 0, count, progressMin, progressMax)); + if (promise.isCanceled()) return {}; } @@ -451,14 +451,14 @@ void UnifiedDiffEditorWidget::showDiff() return; } - m_asyncTask.reset(new AsyncTask()); + m_asyncTask.reset(new AsyncTask()); m_asyncTask->setFutureSynchronizer(DiffEditorPlugin::futureSynchronizer()); m_controller.setBusyShowing(true); connect(m_asyncTask.get(), &AsyncTaskBase::done, this, [this] { if (m_asyncTask->isCanceled() || !m_asyncTask->isResultAvailable()) { setPlainText(Tr::tr("Retrieving data failed.")); } else { - const ShowResult result = m_asyncTask->result(); + const UnifiedShowResult result = m_asyncTask->result(); m_data = result.diffData; TextDocumentPtr doc(result.textDocument); { @@ -478,17 +478,16 @@ void UnifiedDiffEditorWidget::showDiff() const DiffEditorInput input(&m_controller); - auto getDocument = [input](QPromise &promise) { + auto getDocument = [input](QPromise &promise) { const int progressMax = 100; const int firstPartMax = 20; // diffOutput is about 4 times quicker than filling document promise.setProgressRange(0, progressMax); promise.setProgressValue(0); - QFutureInterfaceBase fi = QFutureInterfaceBase::get(promise.future()); - const UnifiedDiffOutput output = UnifiedDiffData::diffOutput(fi, 0, firstPartMax, input); + const UnifiedDiffOutput output = diffOutput(promise, 0, firstPartMax, input); if (promise.isCanceled()) return; - const ShowResult result = {TextDocumentPtr(new TextDocument("DiffEditor.UnifiedDiffEditor")), + const UnifiedShowResult result = {TextDocumentPtr(new TextDocument("DiffEditor.UnifiedDiffEditor")), output.diffData, output.selections}; // No need to store the change history result.textDocument->document()->setUndoRedoEnabled(false); diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h index 027f8830ab4..cbad273ab2f 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.h +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h @@ -33,9 +33,6 @@ class UnifiedDiffOutput; class UnifiedDiffData { public: - static UnifiedDiffOutput diffOutput(QFutureInterfaceBase &fi, int progressMin, int progressMax, - const DiffEditorInput &input); - DiffChunkInfo m_chunkInfo; // block number, visual line number. QMap m_fileInfo; @@ -47,10 +44,10 @@ public: int blockNumberForFileIndex(int fileIndex) const; int fileIndexForBlockNumber(int blockNumber) const; -private: - void setLineNumber(DiffSide side, int blockNumber, int lineNumber, int rowNumberInChunk); QString setChunk(const DiffEditorInput &input, const ChunkData &chunkData, bool lastChunk, int *blockNumber, DiffSelections *selections); +private: + void setLineNumber(DiffSide side, int blockNumber, int lineNumber, int rowNumberInChunk); }; class UnifiedDiffOutput @@ -65,6 +62,14 @@ public: DiffSelections selections; }; +class UnifiedShowResult +{ +public: + QSharedPointer textDocument; + UnifiedDiffData diffData; + DiffSelections selections; +}; + class UnifiedDiffEditorWidget final : public SelectableTextEditorWidget { Q_OBJECT @@ -107,14 +112,7 @@ private: DiffEditorWidgetController m_controller; QByteArray m_state; - struct ShowResult - { - QSharedPointer textDocument; - UnifiedDiffData diffData; - DiffSelections selections; - }; - - std::unique_ptr> m_asyncTask; + std::unique_ptr> m_asyncTask; }; } // namespace Internal From bd2062c455dfdce67360d68bdba341b03e4e5acc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 10 Mar 2023 10:43:42 +0100 Subject: [PATCH 0214/1447] CppEditor: Fix includes Amends a8214665fe45f61668df380f045150258487a55a Change-Id: I61083a6832c55ee04837864506249b0cae1f360a Reviewed-by: Christian Stenger --- src/plugins/cppeditor/baseeditordocumentprocessor.cpp | 2 ++ src/plugins/cppeditor/baseeditordocumentprocessor.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp index 63ade2d3f74..c6c51675eb9 100644 --- a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp @@ -12,6 +12,8 @@ #include +#include + namespace CppEditor { /*! diff --git a/src/plugins/cppeditor/baseeditordocumentprocessor.h b/src/plugins/cppeditor/baseeditordocumentprocessor.h index 5f341c06d96..78c0f55aabc 100644 --- a/src/plugins/cppeditor/baseeditordocumentprocessor.h +++ b/src/plugins/cppeditor/baseeditordocumentprocessor.h @@ -23,6 +23,11 @@ #include +QT_BEGIN_NAMESPACE +template +class QPromise; +QT_END_NAMESPACE + namespace TextEditor { class TextDocument; } namespace CppEditor { From cfedbb2cb05ca7ce7487d4bc24f538d09fac72e0 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 10 Mar 2023 08:18:04 +0100 Subject: [PATCH 0215/1447] Terminal: Fix qbs build Amends 66094398fb1e05a4581784eaf3d367e96b73a013. Change-Id: I14370d18e0f9b0ab0ef7434503956c2bfa7d7029 Reviewed-by: David Schulz --- src/plugins/terminal/terminal.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 4619d7cf496..961f4081160 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -4,6 +4,7 @@ QtcPlugin { name: "Terminal" Depends { name: "Core" } + Depends { name: "ProjectExplorer" } Depends { name: "vterm" } Depends { name: "ptyqt" } From 8240333f969ff1707997e080733d7f83b2385fc0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 7 Mar 2023 17:31:48 +0100 Subject: [PATCH 0216/1447] TestCodeParser: Apply priority to thead pool Rather to async task. Change-Id: I253de9f04e655e394027d15273a86049f5b61f5b Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/autotest/testcodeparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 3b9c396fedf..55fc5ec9079 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -50,6 +50,7 @@ TestCodeParser::TestCodeParser() m_reparseTimer.setSingleShot(true); connect(&m_reparseTimer, &QTimer::timeout, this, &TestCodeParser::parsePostponedFiles); m_threadPool->setMaxThreadCount(std::max(QThread::idealThreadCount()/4, 1)); + m_threadPool->setThreadPriority(QThread::LowestPriority); m_futureSynchronizer.setCancelOnWait(true); } @@ -361,7 +362,6 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList &async) { async.setConcurrentCallData(parseFileForTests, codeParsers, file); async.setThreadPool(m_threadPool); - async.setPriority(QThread::LowestPriority); async.setFutureSynchronizer(&m_futureSynchronizer); }; const auto onDone = [this](const AsyncTask &async) { From 62489e49f8478f7cc3b8d68e5ecc5dd13a1282ea Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Feb 2023 02:08:11 +0100 Subject: [PATCH 0217/1447] ProjectInfoGenerator: Use QPromise for async calls Change-Id: Ibf95090bee773cabcaed82a79687508e1f017059 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- .../cppeditor/cppprojectinfogenerator.cpp | 16 +++++----------- src/plugins/cppeditor/cppprojectinfogenerator.h | 11 ++++++----- src/plugins/cppeditor/cppprojectupdater.cpp | 8 ++++---- src/plugins/cppeditor/projectinfo_test.cpp | 6 +++--- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/plugins/cppeditor/cppprojectinfogenerator.cpp b/src/plugins/cppeditor/cppprojectinfogenerator.cpp index fe077bd3771..5c4c03de4cc 100644 --- a/src/plugins/cppeditor/cppprojectinfogenerator.cpp +++ b/src/plugins/cppeditor/cppprojectinfogenerator.cpp @@ -10,30 +10,24 @@ #include #include -#include - +#include #include -#include - using namespace ProjectExplorer; using namespace Utils; namespace CppEditor::Internal { -ProjectInfoGenerator::ProjectInfoGenerator( - const QFutureInterface &futureInterface, - const ProjectUpdateInfo &projectUpdateInfo) - : m_futureInterface(futureInterface) - , m_projectUpdateInfo(projectUpdateInfo) +ProjectInfoGenerator::ProjectInfoGenerator(const ProjectUpdateInfo &projectUpdateInfo) + : m_projectUpdateInfo(projectUpdateInfo) { } -ProjectInfo::ConstPtr ProjectInfoGenerator::generate() +ProjectInfo::ConstPtr ProjectInfoGenerator::generate(const QPromise &promise) { QVector projectParts; for (const RawProjectPart &rpp : m_projectUpdateInfo.rawProjectParts) { - if (m_futureInterface.isCanceled()) + if (promise.isCanceled()) return {}; for (const ProjectPart::ConstPtr &part : createProjectParts( rpp, m_projectUpdateInfo.projectFilePath)) { diff --git a/src/plugins/cppeditor/cppprojectinfogenerator.h b/src/plugins/cppeditor/cppprojectinfogenerator.h index c090974c042..8720d3e1cd2 100644 --- a/src/plugins/cppeditor/cppprojectinfogenerator.h +++ b/src/plugins/cppeditor/cppprojectinfogenerator.h @@ -5,17 +5,19 @@ #include "projectinfo.h" -#include +QT_BEGIN_NAMESPACE +template +class QPromise; +QT_END_NAMESPACE namespace CppEditor::Internal { class ProjectInfoGenerator { public: - ProjectInfoGenerator(const QFutureInterface &futureInterface, - const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo); + ProjectInfoGenerator(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo); - ProjectInfo::ConstPtr generate(); + ProjectInfo::ConstPtr generate(const QPromise &promise); private: const QVector createProjectParts( @@ -29,7 +31,6 @@ private: Utils::LanguageExtensions languageExtensions); private: - const QFutureInterface m_futureInterface; const ProjectExplorer::ProjectUpdateInfo &m_projectUpdateInfo; bool m_cToolchainMissing = false; bool m_cxxToolchainMissing = false; diff --git a/src/plugins/cppeditor/cppprojectupdater.cpp b/src/plugins/cppeditor/cppprojectupdater.cpp index a784d3bb794..cb64ea61bc8 100644 --- a/src/plugins/cppeditor/cppprojectupdater.cpp +++ b/src/plugins/cppeditor/cppprojectupdater.cpp @@ -49,12 +49,12 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo, using namespace ProjectExplorer; // Run the project info generator in a worker thread and continue if that one is finished. - const auto infoGenerator = [=](QFutureInterface &futureInterface) { + const auto infoGenerator = [=](QPromise &promise) { ProjectUpdateInfo fullProjectUpdateInfo = projectUpdateInfo; if (fullProjectUpdateInfo.rppGenerator) fullProjectUpdateInfo.rawProjectParts = fullProjectUpdateInfo.rppGenerator(); - Internal::ProjectInfoGenerator generator(futureInterface, fullProjectUpdateInfo); - futureInterface.reportResult(generator.generate()); + Internal::ProjectInfoGenerator generator(fullProjectUpdateInfo); + promise.addResult(generator.generate(promise)); }; using namespace Tasking; @@ -63,7 +63,7 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo, }; const TreeStorage storage; const auto setupInfoGenerator = [=](AsyncTask &async) { - async.setAsyncCallData(infoGenerator); + async.setConcurrentCallData(infoGenerator); async.setFutureSynchronizer(&m_futureSynchronizer); }; const auto onInfoGeneratorDone = [=](const AsyncTask &async) { diff --git a/src/plugins/cppeditor/projectinfo_test.cpp b/src/plugins/cppeditor/projectinfo_test.cpp index 73254647f5e..88115e2ea4f 100644 --- a/src/plugins/cppeditor/projectinfo_test.cpp +++ b/src/plugins/cppeditor/projectinfo_test.cpp @@ -362,12 +362,12 @@ public: ProjectInfo::ConstPtr generate() { - QFutureInterface fi; + QPromise promise; projectUpdateInfo.rawProjectParts += rawProjectPart; - ProjectInfoGenerator generator(fi, projectUpdateInfo); + ProjectInfoGenerator generator(projectUpdateInfo); - return generator.generate(); + return generator.generate(promise); } ProjectUpdateInfo projectUpdateInfo; From 811e54145ff7d5d39433fc6ff53ac5eb5ba661ec Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Feb 2023 03:02:52 +0100 Subject: [PATCH 0218/1447] AsyncTask: Get rid of setAsyncCallData() Replaced by setConcurrentCallData(), potentially with QPromise. Change-Id: I7eddb407d7df161d440c92cdce6be59dce3609da Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/utils/asynctask.h | 8 -------- src/plugins/mesonprojectmanager/mesonprojectparser.cpp | 1 + 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libs/utils/asynctask.h b/src/libs/utils/asynctask.h index 1c2f9e9a808..a600a14b247 100644 --- a/src/libs/utils/asynctask.h +++ b/src/libs/utils/asynctask.h @@ -7,7 +7,6 @@ #include "futuresynchronizer.h" #include "qtcassert.h" -#include "runextensions.h" #include "tasktree.h" #include @@ -81,13 +80,6 @@ public: return wrapConcurrent(std::forward(function), std::forward(args)...); } - template - void setAsyncCallData(const Function &function, const Args &...args) - { - m_startHandler = [=] { - return Utils::runAsync(m_threadPool, m_priority, function, args...); - }; - } void setFutureSynchronizer(FutureSynchronizer *synchorizer) { m_synchronizer = synchorizer; } void setThreadPool(QThreadPool *pool) { m_threadPool = pool; } void setPriority(QThread::Priority priority) { m_priority = priority; } diff --git a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp index 6f8ce162ed7..96b5fa9cb7b 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp +++ b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include From 0132cd9937d2ebaee24d379d1e9271f807e43c87 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 17:30:11 +0100 Subject: [PATCH 0219/1447] SilverSearcher: Use QtConcurrent invocation for async run Change-Id: Ia958a393e1eb42cc565d41a1d90b292257a56750 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- .../silversearcher/findinfilessilversearcher.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index b2887cd0a91..6e08a301d1a 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -4,14 +4,13 @@ #include "findinfilessilversearcher.h" #include -#include #include #include +#include #include #include #include #include -#include #include "silversearcheroutputparser.h" #include "silversearchertr.h" @@ -28,8 +27,6 @@ using namespace Utils; namespace { const QLatin1String silverSearcherName("Silver Searcher"); -using FutureInterfaceType = QFutureInterface; - const QString metacharacters = "+()^$.{}[]|\\"; const QString SearchOptionsString = "SearchOptionsString"; @@ -76,9 +73,8 @@ bool isSilverSearcherAvailable() return false; } -void runSilverSeacher(FutureInterfaceType &fi, FileFindParameters parameters) +void runSilverSeacher(QPromise &promise, FileFindParameters parameters) { - ProgressTimer progress(fi, 5); const FilePath directory = FilePath::fromUserInput(parameters.additionalParameters.toString()); QStringList arguments = {"--parallel", "--ackmate"}; @@ -126,9 +122,9 @@ void runSilverSeacher(FutureInterfaceType &fi, FileFindParameters parameters) SilverSearcher::SilverSearcherOutputParser parser(process.cleanedStdOut(), regexp); FileSearchResultList items = parser.parse(); if (!items.isEmpty()) - fi.reportResult(items); + promise.addResult(items); } else { - fi.reportCanceled(); + promise.future().cancel(); } } @@ -196,7 +192,7 @@ void FindInFilesSilverSearcher::writeSettings(QSettings *settings) const QFuture FindInFilesSilverSearcher::executeSearch( const FileFindParameters ¶meters, BaseFileFind * /*baseFileFind*/) { - return Utils::runAsync(runSilverSeacher, parameters); + return Utils::asyncRun(runSilverSeacher, parameters); } IEditor *FindInFilesSilverSearcher::openEditor(const SearchResultItem & /*item*/, From 301f66f190ec3a37180c5f531f98fee48b316be6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 17:07:58 +0100 Subject: [PATCH 0220/1447] Help: Use QtConcurrent invocation for async run Change-Id: I670d263efa979a08bbbc7c5f936e96feadda038b Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/help/helpmanager.cpp | 18 ++++++++++-------- src/plugins/help/helpmanager.h | 13 ++++++++----- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/plugins/help/helpmanager.cpp b/src/plugins/help/helpmanager.cpp index c3e0bd31512..69fe0dabf9e 100644 --- a/src/plugins/help/helpmanager.cpp +++ b/src/plugins/help/helpmanager.cpp @@ -7,7 +7,9 @@ #include #include + #include +#include #include #include #include @@ -17,6 +19,7 @@ #include #include #include +#include #include #include @@ -99,7 +102,7 @@ void HelpManager::registerDocumentation(const QStringList &files) return; } - QFuture future = Utils::runAsync(&HelpManager::registerDocumentationNow, files); + QFuture future = Utils::asyncRun(&HelpManager::registerDocumentationNow, files); Utils::onResultReady(future, this, [](bool docsChanged){ if (docsChanged) { d->m_helpEngine->setupData(); @@ -122,13 +125,12 @@ void HelpManager::unregisterDocumentation(const QStringList &fileNames) unregisterNamespaces(getNamespaces(fileNames)); } -void HelpManager::registerDocumentationNow(QFutureInterface &futureInterface, - const QStringList &files) +void HelpManager::registerDocumentationNow(QPromise &promise, const QStringList &files) { QMutexLocker locker(&d->m_helpengineMutex); - futureInterface.setProgressRange(0, files.count()); - futureInterface.setProgressValue(0); + promise.setProgressRange(0, files.count()); + promise.setProgressValue(0); QHelpEngineCore helpEngine(collectionFilePath()); helpEngine.setReadOnly(false); @@ -136,9 +138,9 @@ void HelpManager::registerDocumentationNow(QFutureInterface &futureInterfa bool docsChanged = false; QStringList nameSpaces = helpEngine.registeredDocumentations(); for (const QString &file : files) { - if (futureInterface.isCanceled()) + if (promise.isCanceled()) break; - futureInterface.setProgressValue(futureInterface.progressValue() + 1); + promise.setProgressValue(promise.future().progressValue() + 1); const QString &nameSpace = QHelpEngineCore::namespaceName(file); if (nameSpace.isEmpty()) continue; @@ -152,7 +154,7 @@ void HelpManager::registerDocumentationNow(QFutureInterface &futureInterfa } } } - futureInterface.reportResult(docsChanged); + promise.addResult(docsChanged); } void HelpManager::unregisterNamespaces(const QStringList &nameSpaces) diff --git a/src/plugins/help/helpmanager.h b/src/plugins/help/helpmanager.h index d868e96256e..6ab3e72cd97 100644 --- a/src/plugins/help/helpmanager.h +++ b/src/plugins/help/helpmanager.h @@ -5,12 +5,16 @@ #include -QT_FORWARD_DECLARE_CLASS(QUrl) - #include #include #include +QT_BEGIN_NAMESPACE +template +class QPromise; +class QUrl; +QT_END_NAMESPACE + namespace Help { namespace Internal { @@ -55,10 +59,9 @@ public: const QUrl &url, Core::HelpManager::HelpViewerLocation location = Core::HelpManager::HelpModeAlways) override; - static void setupHelpManager(); - static void registerDocumentationNow(QFutureInterface &futureInterface, - const QStringList &fileNames); + static void registerDocumentationNow(QPromise &promise, const QStringList &fileNames); + signals: void collectionFileChanged(); void helpRequested(const QUrl &url, Core::HelpManager::HelpViewerLocation location); From bf059bff7df9c3d7534496721e07933e1883f402 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 12:04:09 +0100 Subject: [PATCH 0221/1447] Android: Replace QFutureInterfaceBase with QFuture In case a passed future interface is used only for checking for cancel, use QFuture instead. This will properly integrate with QPromise API. Change-Id: I33e5e9c62dbcfb1f7aa71eace6158e5b7c0a7098 Reviewed-by: Alessandro Portale --- src/plugins/android/androidavdmanager.cpp | 20 ++++++++------------ src/plugins/android/androidavdmanager.h | 9 +++++---- src/plugins/android/androiddeployqtstep.cpp | 3 ++- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index 7cf62fadf86..d64d810e1de 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -14,21 +14,17 @@ #include #include -#include #include #include #include -#include #include -#include using namespace Utils; +using namespace std; namespace Android::Internal { -using namespace std; - const int avdCreateTimeoutMs = 30000; static Q_LOGGING_CATEGORY(avdManagerLog, "qtc.android.avdManager", QtWarningMsg) @@ -228,7 +224,7 @@ QString AndroidAvdManager::startAvd(const QString &name) const { if (!findAvd(name).isEmpty() || startAvdAsync(name)) return waitForAvd(name); - return QString(); + return {}; } static bool is32BitUserSpace() @@ -301,21 +297,21 @@ QString AndroidAvdManager::findAvd(const QString &avdName) const if (device.avdName == avdName) return device.serialNumber; } - return QString(); + return {}; } QString AndroidAvdManager::waitForAvd(const QString &avdName, - const QFutureInterfaceBase &fi) const + const std::optional> &future) const { // we cannot use adb -e wait-for-device, since that doesn't work if a emulator is already running // 60 rounds of 2s sleeping, two minutes for the avd to start QString serialNumber; for (int i = 0; i < 60; ++i) { - if (fi.isCanceled()) + if (future && future->isCanceled()) return {}; serialNumber = findAvd(avdName); if (!serialNumber.isEmpty()) - return waitForBooted(serialNumber, fi) ? serialNumber : QString(); + return waitForBooted(serialNumber, future) ? serialNumber : QString(); QThread::sleep(2); } return {}; @@ -339,11 +335,11 @@ bool AndroidAvdManager::isAvdBooted(const QString &device) const } bool AndroidAvdManager::waitForBooted(const QString &serialNumber, - const QFutureInterfaceBase &fi) const + const std::optional> &future) const { // found a serial number, now wait until it's done booting... for (int i = 0; i < 60; ++i) { - if (fi.isCanceled()) + if (future && future->isCanceled()) return false; if (isAvdBooted(serialNumber)) return true; diff --git a/src/plugins/android/androidavdmanager.h b/src/plugins/android/androidavdmanager.h index cad3a2efe73..545dedbfe21 100644 --- a/src/plugins/android/androidavdmanager.h +++ b/src/plugins/android/androidavdmanager.h @@ -4,8 +4,9 @@ #include "androidconfigurations.h" -#include -#include +#include + +#include namespace Android::Internal { @@ -22,14 +23,14 @@ public: QString startAvd(const QString &name) const; bool startAvdAsync(const QString &avdName) const; QString findAvd(const QString &avdName) const; - QString waitForAvd(const QString &avdName, const QFutureInterfaceBase &fi = {}) const; + QString waitForAvd(const QString &avdName, const std::optional> &future = {}) const; bool isAvdBooted(const QString &device) const; static bool avdManagerCommand(const AndroidConfig &config, const QStringList &args, QString *output); private: - bool waitForBooted(const QString &serialNumber, const QFutureInterfaceBase &fi = {}) const; + bool waitForBooted(const QString &serialNumber, const std::optional> &future = {}) const; private: const AndroidConfig &m_config; diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index c305987a502..120a89b33b1 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -404,7 +404,8 @@ void AndroidDeployQtStep::slotAskForUninstall(DeployErrorCode errorCode) void AndroidDeployQtStep::runImpl(QFutureInterface &fi) { if (!m_avdName.isEmpty()) { - QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, fi); + const QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, + QFuture(fi.future())); qCDebug(deployStepLog) << "Deploying to AVD:" << m_avdName << serialNumber; if (serialNumber.isEmpty()) { reportWarningOrError(Tr::tr("The deployment AVD \"%1\" cannot be started.") From defa51e2c56bd0434cda178481911985889669c6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 16:36:56 +0100 Subject: [PATCH 0222/1447] ILocatorFilter: De-virtualize refreshRecipe Provide protected setter and getter instead. Change-Id: I799db735afe4ab64f5155b6ee31fb4cade9542c6 Reviewed-by: Eike Ziller Reviewed-by: --- .../coreplugin/locator/directoryfilter.cpp | 92 +++++++++---------- .../coreplugin/locator/directoryfilter.h | 1 - .../coreplugin/locator/ilocatorfilter.cpp | 17 +++- .../coreplugin/locator/ilocatorfilter.h | 6 +- .../locator/opendocumentsfilter.cpp | 8 +- .../coreplugin/locator/opendocumentsfilter.h | 1 - src/plugins/cppeditor/cppincludesfilter.cpp | 11 +-- src/plugins/cppeditor/cppincludesfilter.h | 1 - src/plugins/help/helpindexfilter.cpp | 8 +- src/plugins/help/helpindexfilter.h | 1 - .../projectexplorer/allprojectsfilter.cpp | 11 +-- .../projectexplorer/allprojectsfilter.h | 1 - .../projectexplorer/currentprojectfilter.cpp | 13 +-- .../projectexplorer/currentprojectfilter.h | 1 - 14 files changed, 72 insertions(+), 100 deletions(-) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 1d7bba06e49..785c411f19a 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -46,6 +46,28 @@ static QString defaultDisplayName() return Tr::tr("Generic Directory Filter"); } +static void refresh(QPromise &promise, const FilePaths &directories, + const QStringList &filters, const QStringList &exclusionFilters, + const QString &displayName) +{ + SubDirFileIterator subDirIterator(directories, filters, exclusionFilters); + promise.setProgressRange(0, subDirIterator.maxProgress()); + FilePaths files; + const auto end = subDirIterator.end(); + for (auto it = subDirIterator.begin(); it != end; ++it) { + if (promise.isCanceled()) { + promise.setProgressValueAndText(subDirIterator.currentProgress(), + Tr::tr("%1 filter update: canceled").arg(displayName)); + return; + } + files << (*it).filePath; + promise.setProgressValueAndText(subDirIterator.currentProgress(), + Tr::tr("%1 filter update: %n files", nullptr, files.size()).arg(displayName)); + } + promise.setProgressValue(subDirIterator.maxProgress()); + promise.addResult(files); +} + DirectoryFilter::DirectoryFilter(Id id) : m_filters(kFiltersDefault) , m_exclusionFilters(kExclusionFiltersDefault) @@ -56,6 +78,28 @@ DirectoryFilter::DirectoryFilter(Id id) setDescription(Tr::tr("Matches all files from a custom set of directories. Append \"+\" " "or \":\" to jump to the given line number. Append another " "\"+\" or \":\" to jump to the column number as well.")); + + using namespace Tasking; + const auto groupSetup = [this] { + if (!m_directories.isEmpty()) + return TaskAction::Continue; // Async task will run + m_files.clear(); + updateFileIterator(); + return TaskAction::StopWithDone; // Group stops, skips async task + }; + const auto asyncSetup = [this](AsyncTask &async) { + async.setConcurrentCallData(&refresh, m_directories, m_filters, m_exclusionFilters, + displayName()); + }; + const auto asyncDone = [this](const AsyncTask &async) { + m_files = async.isResultAvailable() ? async.result() : FilePaths(); + updateFileIterator(); + }; + const Group root { + OnGroupSetup(groupSetup), + Async(asyncSetup, asyncDone) + }; + setRefreshRecipe(root); } void DirectoryFilter::saveState(QJsonObject &object) const @@ -382,52 +426,4 @@ void DirectoryFilter::setExclusionFilters(const QStringList &exclusionFilters) m_exclusionFilters = exclusionFilters; } -static void refresh(QPromise &promise, const FilePaths &directories, - const QStringList &filters, const QStringList &exclusionFilters, - const QString &displayName) -{ - SubDirFileIterator subDirIterator(directories, filters, exclusionFilters); - promise.setProgressRange(0, subDirIterator.maxProgress()); - FilePaths files; - const auto end = subDirIterator.end(); - for (auto it = subDirIterator.begin(); it != end; ++it) { - if (promise.isCanceled()) { - promise.setProgressValueAndText(subDirIterator.currentProgress(), - Tr::tr("%1 filter update: canceled").arg(displayName)); - return; - } - files << (*it).filePath; - promise.setProgressValueAndText(subDirIterator.currentProgress(), - Tr::tr("%1 filter update: %n files", nullptr, files.size()).arg(displayName)); - } - promise.setProgressValue(subDirIterator.maxProgress()); - promise.addResult(files); -} - -using namespace Utils::Tasking; - -std::optional DirectoryFilter::refreshRecipe() -{ - const auto groupSetup = [this] { - if (!m_directories.isEmpty()) - return TaskAction::Continue; // Async task will run - m_files.clear(); - updateFileIterator(); - return TaskAction::StopWithDone; // Group stops, skips async task - }; - const auto asyncSetup = [this](AsyncTask &async) { - async.setConcurrentCallData(&refresh, m_directories, m_filters, m_exclusionFilters, - displayName()); - }; - const auto asyncDone = [this](const AsyncTask &async) { - m_files = async.isResultAvailable() ? async.result() : FilePaths(); - updateFileIterator(); - }; - const Group root { - OnGroupSetup(groupSetup), - Async(asyncSetup, asyncDone) - }; - return root; -} - } // namespace Core diff --git a/src/plugins/coreplugin/locator/directoryfilter.h b/src/plugins/coreplugin/locator/directoryfilter.h index 04067988c32..06916165003 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.h +++ b/src/plugins/coreplugin/locator/directoryfilter.h @@ -38,7 +38,6 @@ private: void handleRemoveDirectory(); void updateOptionButtons(); void updateFileIterator(); - std::optional refreshRecipe() override; Utils::FilePaths m_directories; QStringList m_filters; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 4705ee32caa..f529aa0285a 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -100,13 +100,22 @@ void ILocatorFilter::prepareSearch(const QString &entry) Q_UNUSED(entry) } + /*! - Returns refresh recipe for refreshing cached data. By default, no recipe is returned, so - that the filter won't be refreshed. + Sets the refresh recipe for refreshing cached data. */ -std::optional ILocatorFilter::refreshRecipe() +void ILocatorFilter::setRefreshRecipe(const std::optional &recipe) { - return {}; + m_refreshRecipe = recipe; +} + +/*! + Returns the refresh recipe for refreshing cached data. By default, the locator filter has + no recipe set, so that it won't be refreshed. +*/ +std::optional ILocatorFilter::refreshRecipe() const +{ + return m_refreshRecipe; } /*! diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index b032ab5f94d..e7042387602 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -3,6 +3,7 @@ #pragma once +#include "utils/tasktree.h" #include #include @@ -201,11 +202,13 @@ protected: virtual void saveState(QJsonObject &object) const; virtual void restoreState(const QJsonObject &object); + void setRefreshRecipe(const std::optional &recipe); + std::optional refreshRecipe() const; + static bool isOldSetting(const QByteArray &state); private: friend class Internal::Locator; - virtual std::optional refreshRecipe(); Utils::Id m_id; QString m_shortcut; @@ -214,6 +217,7 @@ private: QString m_description; QString m_defaultShortcut; std::optional m_defaultSearchText; + std::optional m_refreshRecipe; QKeySequence m_defaultKeySequence; bool m_defaultIncludedByDefault = false; bool m_includedByDefault = m_defaultIncludedByDefault; diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index cc24d086065..2ec6aca0531 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -24,6 +24,7 @@ OpenDocumentsFilter::OpenDocumentsFilter() setDefaultShortcutString("o"); setPriority(High); setDefaultIncludedByDefault(true); + setRefreshRecipe(Tasking::Sync([this] { refreshInternally(); return true; })); connect(DocumentModel::model(), &QAbstractItemModel::dataChanged, this, &OpenDocumentsFilter::slotDataChanged); @@ -127,11 +128,4 @@ void OpenDocumentsFilter::refreshInternally() m_editors.append({e->filePath(), e->displayName()}); } -using namespace Utils::Tasking; - -std::optional OpenDocumentsFilter::refreshRecipe() -{ - return Sync([this] { refreshInternally(); return true; }); -} - } // Core::Internal diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index aa8792730f0..7bbd98698fa 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -36,7 +36,6 @@ private: QList editors() const; void refreshInternally(); - std::optional refreshRecipe() override; mutable QMutex m_mutex; QList m_editors; diff --git a/src/plugins/cppeditor/cppincludesfilter.cpp b/src/plugins/cppeditor/cppincludesfilter.cpp index e96b3ee0d20..44f21045d24 100644 --- a/src/plugins/cppeditor/cppincludesfilter.cpp +++ b/src/plugins/cppeditor/cppincludesfilter.cpp @@ -15,6 +15,7 @@ #include #include #include + #include using namespace Core; @@ -49,8 +50,6 @@ private: FilePath m_currentPath; }; - - void CppIncludesIterator::toFront() { m_queuedPaths = m_paths; @@ -108,6 +107,7 @@ CppIncludesFilter::CppIncludesFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("ai"); setDefaultIncludedByDefault(true); + setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); setPriority(ILocatorFilter::Low); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, @@ -154,11 +154,4 @@ void CppIncludesFilter::invalidateCache() setFileIterator(nullptr); // clean up } -using namespace Utils::Tasking; - -std::optional CppIncludesFilter::refreshRecipe() -{ - return Sync([this] { invalidateCache(); return true; }); -} - } // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cppincludesfilter.h b/src/plugins/cppeditor/cppincludesfilter.h index 720b6cbb9b9..303de152d60 100644 --- a/src/plugins/cppeditor/cppincludesfilter.h +++ b/src/plugins/cppeditor/cppincludesfilter.h @@ -18,7 +18,6 @@ public: private: void invalidateCache(); - std::optional refreshRecipe() override; bool m_needsUpdate = true; }; diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index ef77f343468..de4e412ab9d 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -28,6 +28,7 @@ HelpIndexFilter::HelpIndexFilter() setDisplayName(Tr::tr("Help Index")); setDefaultIncludedByDefault(false); setDefaultShortcutString("?"); + setRefreshRecipe(Utils::Tasking::Sync([this] { invalidateCache(); return true; })); m_icon = Utils::Icons::BOOKMARK.icon(); connect(Core::HelpManager::Signals::instance(), &Core::HelpManager::Signals::setupFinished, @@ -116,10 +117,3 @@ void HelpIndexFilter::invalidateCache() { m_needsUpdate = true; } - -using namespace Utils::Tasking; - -std::optional HelpIndexFilter::refreshRecipe() -{ - return Sync([this] { invalidateCache(); return true; }); -} diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h index 56ffa226bb4..e74e071b12f 100644 --- a/src/plugins/help/helpindexfilter.h +++ b/src/plugins/help/helpindexfilter.h @@ -37,7 +37,6 @@ private: bool updateCache(QFutureInterface &future, const QStringList &cache, const QString &entry); void invalidateCache(); - std::optional refreshRecipe() override; QStringList m_allIndicesCache; QStringList m_lastIndicesCache; diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index 19c2d499255..3a9b8e7a45a 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -12,6 +12,7 @@ #include using namespace Core; +using namespace Utils; namespace ProjectExplorer::Internal { @@ -24,6 +25,7 @@ AllProjectsFilter::AllProjectsFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("a"); setDefaultIncludedByDefault(true); + setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, this, &AllProjectsFilter::invalidateCache); @@ -33,7 +35,7 @@ void AllProjectsFilter::prepareSearch(const QString &entry) { Q_UNUSED(entry) if (!fileIterator()) { - Utils::FilePaths paths; + FilePaths paths; for (Project *project : ProjectManager::projects()) paths.append(project->files(Project::SourceFiles)); Utils::sort(paths); @@ -47,11 +49,4 @@ void AllProjectsFilter::invalidateCache() setFileIterator(nullptr); } -using namespace Utils::Tasking; - -std::optional AllProjectsFilter::refreshRecipe() -{ - return Sync([this] { invalidateCache(); return true; }); -} - } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/allprojectsfilter.h b/src/plugins/projectexplorer/allprojectsfilter.h index c85cc3fe28f..5d6e3b72fff 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.h +++ b/src/plugins/projectexplorer/allprojectsfilter.h @@ -18,7 +18,6 @@ public: private: void invalidateCache(); - std::optional refreshRecipe() override; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index ec5a1e7ffdd..8d7d699a693 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -13,6 +13,7 @@ using namespace Core; using namespace ProjectExplorer; using namespace ProjectExplorer::Internal; +using namespace Utils; CurrentProjectFilter::CurrentProjectFilter() : BaseFileFilter() @@ -24,6 +25,7 @@ CurrentProjectFilter::CurrentProjectFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("p"); setDefaultIncludedByDefault(false); + setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &CurrentProjectFilter::currentProjectChanged); @@ -33,9 +35,7 @@ void CurrentProjectFilter::prepareSearch(const QString &entry) { Q_UNUSED(entry) if (!fileIterator()) { - Utils::FilePaths paths; - if (m_project) - paths = m_project->files(Project::SourceFiles); + const FilePaths paths = m_project ? m_project->files(Project::SourceFiles) : FilePaths(); setFileIterator(new BaseFileFilter::ListIterator(paths)); } BaseFileFilter::prepareSearch(entry); @@ -62,10 +62,3 @@ void CurrentProjectFilter::invalidateCache() { setFileIterator(nullptr); } - -using namespace Utils::Tasking; - -std::optional CurrentProjectFilter::refreshRecipe() -{ - return Sync([this] { invalidateCache(); return true; }); -} diff --git a/src/plugins/projectexplorer/currentprojectfilter.h b/src/plugins/projectexplorer/currentprojectfilter.h index 8db0c567c0e..9b74161fbd5 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.h +++ b/src/plugins/projectexplorer/currentprojectfilter.h @@ -22,7 +22,6 @@ public: private: void currentProjectChanged(); void invalidateCache(); - std::optional refreshRecipe() override; Project *m_project = nullptr; }; From c2d6501e640f8f68d1f1767f427435642a857de0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 17:16:03 +0100 Subject: [PATCH 0223/1447] RemoteLinux: Use QtConcurrent invocation for async run Change-Id: Ibf69ab82a1f1664d5290ad4a1dc14de7a15d9c3a Reviewed-by: Christian Kandeler Reviewed-by: Reviewed-by: Qt CI Bot --- .../remotelinux/tarpackagecreationstep.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/plugins/remotelinux/tarpackagecreationstep.cpp b/src/plugins/remotelinux/tarpackagecreationstep.cpp index 0d53d36ff55..80aec8053de 100644 --- a/src/plugins/remotelinux/tarpackagecreationstep.cpp +++ b/src/plugins/remotelinux/tarpackagecreationstep.cpp @@ -13,8 +13,8 @@ #include #include +#include #include -#include #include #include @@ -74,9 +74,9 @@ private: bool isPackagingNeeded() const; void deployFinished(bool success); void addNeededDeploymentFiles(const DeployableFile &deployable, const Kit *kit); - void doPackage(QFutureInterface &fi, const Utils::FilePath &tarFilePath, + void doPackage(QPromise &promise, const Utils::FilePath &tarFilePath, bool ignoreMissingFiles); - bool appendFile(QFutureInterface &fi, QFile &tarFile, const QFileInfo &fileInfo, + bool appendFile(QPromise &promise, QFile &tarFile, const QFileInfo &fileInfo, const QString &remoteFilePath, const Utils::FilePath &tarFilePath, bool ignoreMissingFiles); @@ -167,7 +167,7 @@ void TarPackageCreationStep::doRun() connect(BuildManager::instance(), &BuildManager::buildQueueFinished, this, &TarPackageCreationStep::deployFinished); }); - auto future = Utils::runAsync(&TarPackageCreationStep::doPackage, this, + auto future = Utils::asyncRun(&TarPackageCreationStep::doPackage, this, m_tarFilePath, m_ignoreMissingFilesAspect->value()); watcher->setFuture(future); m_synchronizer.addFuture(future); @@ -271,7 +271,7 @@ void TarPackageCreationStep::addNeededDeploymentFiles( } } -void TarPackageCreationStep::doPackage(QFutureInterface &fi, const FilePath &tarFilePath, +void TarPackageCreationStep::doPackage(QPromise &promise, const FilePath &tarFilePath, bool ignoreMissingFiles) { // TODO: Optimization: Only package changed files @@ -280,7 +280,7 @@ void TarPackageCreationStep::doPackage(QFutureInterface &fi, const FilePat if (!tarFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { raiseError(Tr::tr("Error: tar file %1 cannot be opened (%2).") .arg(tarFilePath.toUserOutput(), tarFile.errorString())); - fi.reportResult(false); + promise.addResult(false); return; } @@ -291,10 +291,10 @@ void TarPackageCreationStep::doPackage(QFutureInterface &fi, const FilePat continue; } QFileInfo fileInfo = d.localFilePath().toFileInfo(); - if (!appendFile(fi, tarFile, fileInfo, + if (!appendFile(promise, tarFile, fileInfo, d.remoteDirectory() + QLatin1Char('/') + fileInfo.fileName(), tarFilePath, ignoreMissingFiles)) { - fi.reportResult(false); + promise.addResult(false); return; } } @@ -303,10 +303,10 @@ void TarPackageCreationStep::doPackage(QFutureInterface &fi, const FilePat if (tarFile.write(eofIndicator) != eofIndicator.length()) { raiseError(Tr::tr("Error writing tar file \"%1\": %2.") .arg(QDir::toNativeSeparators(tarFile.fileName()), tarFile.errorString())); - fi.reportResult(false); + promise.addResult(false); return; } - fi.reportResult(true); + promise.addResult(true); } static bool setFilePath(TarFileHeader &header, const QByteArray &filePath) @@ -388,7 +388,7 @@ static bool writeHeader(QFile &tarFile, const QFileInfo &fileInfo, const QString return true; } -bool TarPackageCreationStep::appendFile(QFutureInterface &fi, +bool TarPackageCreationStep::appendFile(QPromise &promise, QFile &tarFile, const QFileInfo &fileInfo, const QString &remoteFilePath, @@ -406,7 +406,7 @@ bool TarPackageCreationStep::appendFile(QFutureInterface &fi, for (const QString &fileName : files) { const QString thisLocalFilePath = dir.path() + QLatin1Char('/') + fileName; const QString thisRemoteFilePath = remoteFilePath + QLatin1Char('/') + fileName; - if (!appendFile(fi, tarFile, QFileInfo(thisLocalFilePath), thisRemoteFilePath, + if (!appendFile(promise, tarFile, QFileInfo(thisLocalFilePath), thisRemoteFilePath, tarFilePath, ignoreMissingFiles)) { return false; } @@ -437,7 +437,7 @@ bool TarPackageCreationStep::appendFile(QFutureInterface &fi, while (!file.atEnd() && file.error() == QFile::NoError && tarFile.error() == QFile::NoError) { const QByteArray data = file.read(chunkSize); tarFile.write(data); - if (fi.isCanceled()) + if (promise.isCanceled()) return false; } if (file.error() != QFile::NoError) { From 2f5aad0cdb56c0984dce1614ca55fc6fd58ed1db Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 23:59:37 +0100 Subject: [PATCH 0224/1447] Android: Use QtConcurrent invocation for async run Change-Id: I275af7c52197ecdb0c02e2e1039b37bd8c9bb1c1 Reviewed-by: Alessandro Portale Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/android/androidavdmanager.cpp | 6 +- src/plugins/android/androiddeployqtstep.cpp | 12 +-- src/plugins/android/androiddeployqtstep.h | 2 +- src/plugins/android/androiddevice.cpp | 7 +- .../android/androidqmlpreviewworker.cpp | 4 +- src/plugins/android/androidrunnerworker.cpp | 13 ++-- src/plugins/android/androidsdkmanager.cpp | 76 +++++++++---------- 7 files changed, 61 insertions(+), 59 deletions(-) diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index d64d810e1de..6567c119a6e 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -10,9 +10,9 @@ #include #include +#include #include #include -#include #include #include @@ -139,7 +139,7 @@ AndroidAvdManager::~AndroidAvdManager() = default; QFuture AndroidAvdManager::createAvd(CreateAvdInfo info) const { - return runAsync(&createAvdCommand, m_config, info); + return Utils::asyncRun(&createAvdCommand, m_config, info); } bool AndroidAvdManager::removeAvd(const QString &name) const @@ -217,7 +217,7 @@ static AndroidDeviceInfoList listVirtualDevices(const AndroidConfig &config) QFuture AndroidAvdManager::avdList() const { - return runAsync(listVirtualDevices, m_config); + return Utils::asyncRun(listVirtualDevices, m_config); } QString AndroidAvdManager::startAvd(const QString &name) const diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 120a89b33b1..5d0ad61c578 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -30,10 +30,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -401,16 +401,16 @@ void AndroidDeployQtStep::slotAskForUninstall(DeployErrorCode errorCode) m_askForUninstall = button == QMessageBox::Yes; } -void AndroidDeployQtStep::runImpl(QFutureInterface &fi) +void AndroidDeployQtStep::runImpl(QPromise &promise) { if (!m_avdName.isEmpty()) { const QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, - QFuture(fi.future())); + QFuture(promise.future())); qCDebug(deployStepLog) << "Deploying to AVD:" << m_avdName << serialNumber; if (serialNumber.isEmpty()) { reportWarningOrError(Tr::tr("The deployment AVD \"%1\" cannot be started.") .arg(m_avdName), Task::Error); - fi.reportResult(false); + promise.addResult(false); return; } m_serialNumber = serialNumber; @@ -446,7 +446,7 @@ void AndroidDeployQtStep::runImpl(QFutureInterface &fi) reportWarningOrError(error, Task::Error); } } - fi.reportResult(returnValue == NoError); + promise.addResult(returnValue == NoError); } void AndroidDeployQtStep::gatherFilesToPull() @@ -486,7 +486,7 @@ void AndroidDeployQtStep::doRun() emit finished(success); watcher->deleteLater(); }); - auto future = Utils::runAsync(&AndroidDeployQtStep::runImpl, this); + auto future = Utils::asyncRun(&AndroidDeployQtStep::runImpl, this); watcher->setFuture(future); m_synchronizer.addFuture(future); } diff --git a/src/plugins/android/androiddeployqtstep.h b/src/plugins/android/androiddeployqtstep.h index 334be8ea22a..b83adea34a8 100644 --- a/src/plugins/android/androiddeployqtstep.h +++ b/src/plugins/android/androiddeployqtstep.h @@ -53,7 +53,7 @@ private: DeployErrorCode runDeploy(); void slotAskForUninstall(DeployErrorCode errorCode); - void runImpl(QFutureInterface &fi); + void runImpl(QPromise &promise); QWidget *createConfigWidget() override; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 1902631fd6b..be5f3071242 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -21,9 +21,9 @@ #include #include +#include #include #include -#include #include #include @@ -454,7 +454,7 @@ void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, const AndroidDevice *androidDev = static_cast(device.data()); const QString name = androidDev->avdName(); qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name)); - runAsync([this, name, device] { + auto future = Utils::asyncRun([this, name, device] { const QString serialNumber = m_avdManager.startAvd(name); // Mark the AVD as ReadyToUse once we know it's started if (!serialNumber.isEmpty()) { @@ -462,6 +462,7 @@ void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, devMgr->setDeviceState(device->id(), IDevice::DeviceReadyToUse); } }); + // TODO: use future! } void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent) @@ -479,7 +480,7 @@ void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent) return; qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name); - m_removeAvdFutureWatcher.setFuture(runAsync([this, name, device] { + m_removeAvdFutureWatcher.setFuture(Utils::asyncRun([this, name, device] { QPair pair; pair.first = device; pair.second = false; diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index ab9fb34de5a..f18306f9f8a 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -27,8 +27,8 @@ #include #include +#include #include -#include #include #include @@ -163,7 +163,7 @@ bool AndroidQmlPreviewWorker::isPreviewRunning(int lastKnownPid) const void AndroidQmlPreviewWorker::startPidWatcher() { - m_pidFutureWatcher.setFuture(runAsync([this] { + m_pidFutureWatcher.setFuture(Utils::asyncRun([this] { // wait for started const int sleepTimeMs = 2000; QDeadlineTimer deadline(20000); diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 53721cebdb0..d54a0677f80 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -11,8 +11,8 @@ #include #include -#include #include +#include #include #include #include @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -77,7 +78,7 @@ static qint64 extractPID(const QString &output, const QString &packageName) return pid; } -static void findProcessPID(QFutureInterface &fi, QStringList selector, +static void findProcessPID(QPromise &promise, QStringList selector, const QString &packageName, bool preNougat) { if (packageName.isEmpty()) @@ -105,11 +106,11 @@ static void findProcessPID(QFutureInterface &fi, QStringList selector, if (!out.isEmpty()) processPID = out.trimmed().toLongLong(); } - } while ((processPID == -1 || processPID == 0) && !isTimedOut(start) && !fi.isCanceled()); + } while ((processPID == -1 || processPID == 0) && !isTimedOut(start) && !promise.isCanceled()); qCDebug(androidRunWorkerLog) << "PID found:" << processPID << ", PreNougat:" << preNougat; - if (!fi.isCanceled()) - fi.reportResult(processPID); + if (!promise.isCanceled()) + promise.addResult(processPID); } static void deleter(QProcess *p) @@ -683,7 +684,7 @@ void AndroidRunnerWorker::asyncStart() { asyncStartHelper(); - m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, selector(), + m_pidFinder = Utils::onResultReady(Utils::asyncRun(findProcessPID, selector(), m_packageName, m_isPreNougat), bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1)); } diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 4494f4837fa..cb46f39ab75 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -8,9 +8,9 @@ #include "sdkmanageroutputparser.h" #include +#include #include #include -#include #include #include @@ -34,7 +34,7 @@ namespace Internal { const int sdkManagerCmdTimeoutS = 60; const int sdkManagerOperationTimeoutS = 600; -using SdkCmdFutureInterface = QFutureInterface; +using SdkCmdPromise = QPromise; static const QRegularExpression &assertionRegExp() { @@ -111,7 +111,7 @@ static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &ar after the lapse of \a timeout seconds. The function blocks the calling thread. */ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &args, - AndroidSdkManager &sdkManager, SdkCmdFutureInterface &fi, + AndroidSdkManager &sdkManager, SdkCmdPromise &promise, AndroidSdkManager::OperationOutput &output, double progressQuota, bool interruptible = true, int timeout = sdkManagerOperationTimeoutS) { @@ -120,19 +120,19 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar qCDebug(sdkManagerLog).noquote() << "Running SDK Manager command (async):" << CommandLine(config.sdkManagerToolPath(), newArgs) .toUserOutput(); - int offset = fi.progressValue(); + int offset = promise.future().progressValue(); QtcProcess proc; proc.setEnvironment(AndroidConfigurations::toolsEnvironment(config)); bool assertionFound = false; proc.setTimeoutS(timeout); - proc.setStdOutCallback([offset, progressQuota, &proc, &assertionFound, &fi](const QString &out) { + proc.setStdOutCallback([offset, progressQuota, &proc, &assertionFound, &promise](const QString &out) { int progressPercent = parseProgress(out, assertionFound); if (assertionFound) { proc.stop(); proc.waitForFinished(); } if (progressPercent != -1) - fi.setProgressValue(offset + qRound((progressPercent / 100.0) * progressQuota)); + promise.setProgressValue(offset + qRound((progressPercent / 100.0) * progressQuota)); }); proc.setStdErrCallback([&output](const QString &err) { output.stdError = err; @@ -168,12 +168,12 @@ public: const AndroidSdkPackageList &allPackages(bool forceUpdate = false); void refreshSdkPackages(bool forceReload = false); - void parseCommonArguments(QFutureInterface &fi); - void updateInstalled(SdkCmdFutureInterface &fi); - void update(SdkCmdFutureInterface &fi, const QStringList &install, + void parseCommonArguments(QPromise &promise); + void updateInstalled(SdkCmdPromise &fi); + void update(SdkCmdPromise &fi, const QStringList &install, const QStringList &uninstall); - void checkPendingLicense(SdkCmdFutureInterface &fi); - void getPendingLicense(SdkCmdFutureInterface &fi); + void checkPendingLicense(SdkCmdPromise &fi); + void getPendingLicense(SdkCmdPromise &fi); void addWatcher(const QFuture &future); void setLicenseInput(bool acceptLicense); @@ -186,7 +186,7 @@ private: void reloadSdkPackages(); void clearPackages(); bool onLicenseStdOut(const QString &output, bool notify, - AndroidSdkManager::OperationOutput &result, SdkCmdFutureInterface &fi); + AndroidSdkManager::OperationOutput &result, SdkCmdPromise &fi); AndroidSdkManager &m_sdkManager; const AndroidConfig &m_config; @@ -308,7 +308,7 @@ bool AndroidSdkManager::packageListingSuccessful() const QFuture AndroidSdkManager::availableArguments() const { - return Utils::runAsync(&AndroidSdkManagerPrivate::parseCommonArguments, m_d.get()); + return Utils::asyncRun(&AndroidSdkManagerPrivate::parseCommonArguments, m_d.get()); } QFuture AndroidSdkManager::updateAll() @@ -316,7 +316,7 @@ QFuture AndroidSdkManager::updateAll() if (isBusy()) { return QFuture(); } - auto future = Utils::runAsync(&AndroidSdkManagerPrivate::updateInstalled, m_d.get()); + auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::updateInstalled, m_d.get()); m_d->addWatcher(future); return future; } @@ -326,7 +326,7 @@ AndroidSdkManager::update(const QStringList &install, const QStringList &uninsta { if (isBusy()) return QFuture(); - auto future = Utils::runAsync(&AndroidSdkManagerPrivate::update, m_d.get(), install, uninstall); + auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::update, m_d.get(), install, uninstall); m_d->addWatcher(future); return future; } @@ -335,7 +335,7 @@ QFuture AndroidSdkManager::checkPendingLicen { if (isBusy()) return QFuture(); - auto future = Utils::runAsync(&AndroidSdkManagerPrivate::checkPendingLicense, m_d.get()); + auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::checkPendingLicense, m_d.get()); m_d->addWatcher(future); return future; } @@ -344,7 +344,7 @@ QFuture AndroidSdkManager::runLicenseCommand { if (isBusy()) return QFuture(); - auto future = Utils::runAsync(&AndroidSdkManagerPrivate::getPendingLicense, m_d.get()); + auto future = Utils::asyncRun(&AndroidSdkManagerPrivate::getPendingLicense, m_d.get()); m_d->addWatcher(future); return future; } @@ -422,29 +422,29 @@ void AndroidSdkManagerPrivate::refreshSdkPackages(bool forceReload) reloadSdkPackages(); } -void AndroidSdkManagerPrivate::updateInstalled(SdkCmdFutureInterface &fi) +void AndroidSdkManagerPrivate::updateInstalled(SdkCmdPromise &promise) { - fi.setProgressRange(0, 100); - fi.setProgressValue(0); + promise.setProgressRange(0, 100); + promise.setProgressValue(0); AndroidSdkManager::OperationOutput result; result.type = AndroidSdkManager::UpdateAll; result.stdOutput = Tr::tr("Updating installed packages."); - fi.reportResult(result); + promise.addResult(result); QStringList args("--update"); args << m_config.sdkManagerToolArgs(); - if (!fi.isCanceled()) - sdkManagerCommand(m_config, args, m_sdkManager, fi, result, 100); + if (!promise.isCanceled()) + sdkManagerCommand(m_config, args, m_sdkManager, promise, result, 100); else qCDebug(sdkManagerLog) << "Update: Operation cancelled before start"; if (result.stdError.isEmpty() && !result.success) result.stdError = Tr::tr("Failed."); result.stdOutput = Tr::tr("Done\n\n"); - fi.reportResult(result); - fi.setProgressValue(100); + promise.addResult(result); + promise.setProgressValue(100); } -void AndroidSdkManagerPrivate::update(SdkCmdFutureInterface &fi, const QStringList &install, +void AndroidSdkManagerPrivate::update(SdkCmdPromise &fi, const QStringList &install, const QStringList &uninstall) { fi.setProgressRange(0, 100); @@ -461,7 +461,7 @@ void AndroidSdkManagerPrivate::update(SdkCmdFutureInterface &fi, const QStringLi result.type = AndroidSdkManager::UpdatePackage; result.stdOutput = QString("%1 %2").arg(isInstall ? installTag : uninstallTag) .arg(packagePath); - fi.reportResult(result); + fi.addResult(result); if (fi.isCanceled()) qCDebug(sdkManagerLog) << args << "Update: Operation cancelled before start"; else @@ -471,7 +471,7 @@ void AndroidSdkManagerPrivate::update(SdkCmdFutureInterface &fi, const QStringLi if (result.stdError.isEmpty() && !result.success) result.stdError = Tr::tr("AndroidSdkManager", "Failed"); result.stdOutput = Tr::tr("AndroidSdkManager", "Done\n\n"); - fi.reportResult(result); + fi.addResult(result); return fi.isCanceled(); }; @@ -495,7 +495,7 @@ void AndroidSdkManagerPrivate::update(SdkCmdFutureInterface &fi, const QStringLi fi.setProgressValue(100); } -void AndroidSdkManagerPrivate::checkPendingLicense(SdkCmdFutureInterface &fi) +void AndroidSdkManagerPrivate::checkPendingLicense(SdkCmdPromise &fi) { fi.setProgressRange(0, 100); fi.setProgressValue(0); @@ -509,11 +509,11 @@ void AndroidSdkManagerPrivate::checkPendingLicense(SdkCmdFutureInterface &fi) qCDebug(sdkManagerLog) << "Update: Operation cancelled before start"; } - fi.reportResult(result); + fi.addResult(result); fi.setProgressValue(100); } -void AndroidSdkManagerPrivate::getPendingLicense(SdkCmdFutureInterface &fi) +void AndroidSdkManagerPrivate::getPendingLicense(SdkCmdPromise &fi) { fi.setProgressRange(0, 100); fi.setProgressValue(0); @@ -571,7 +571,7 @@ void AndroidSdkManagerPrivate::getPendingLicense(SdkCmdFutureInterface &fi) result.success = licenseCommand.exitStatus() == QProcess::NormalExit; if (!result.success) result.stdError = Tr::tr("License command failed.\n\n"); - fi.reportResult(result); + fi.addResult(result); fi.setProgressValue(100); } @@ -595,14 +595,14 @@ void AndroidSdkManagerPrivate::clearUserInput() bool AndroidSdkManagerPrivate::onLicenseStdOut(const QString &output, bool notify, AndroidSdkManager::OperationOutput &result, - SdkCmdFutureInterface &fi) + SdkCmdPromise &fi) { m_licenseTextCache.append(output); const QRegularExpressionMatch assertionMatch = assertionRegExp().match(m_licenseTextCache); if (assertionMatch.hasMatch()) { if (notify) { result.stdOutput = m_licenseTextCache; - fi.reportResult(result); + fi.addResult(result); } // Clear the current contents. The found license text is dispatched. Continue collecting the // next license text. @@ -620,7 +620,7 @@ void AndroidSdkManagerPrivate::addWatcher(const QFuturesetFuture(QFuture(future)); } -void AndroidSdkManagerPrivate::parseCommonArguments(QFutureInterface &fi) +void AndroidSdkManagerPrivate::parseCommonArguments(QPromise &promise) { QString argumentDetails; QString output; @@ -628,7 +628,7 @@ void AndroidSdkManagerPrivate::parseCommonArguments(QFutureInterface &f bool foundTag = false; const auto lines = output.split('\n'); for (const QString& line : lines) { - if (fi.isCanceled()) + if (promise.isCanceled()) break; if (foundTag) argumentDetails.append(line + "\n"); @@ -636,8 +636,8 @@ void AndroidSdkManagerPrivate::parseCommonArguments(QFutureInterface &f foundTag = true; } - if (!fi.isCanceled()) - fi.reportResult(argumentDetails); + if (!promise.isCanceled()) + promise.addResult(argumentDetails); } void AndroidSdkManagerPrivate::clearPackages() From 814d2f732ef8fd9a9422082177722949fbad4fd3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 20:22:51 +0100 Subject: [PATCH 0225/1447] QMakeProject: Use QtConcurrent invocation for async run Change-Id: I9e5027acb71eb03efef0f5f38a57286c37e74983 Reviewed-by: Christian Kandeler --- src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp | 11 ++++++----- src/plugins/qmakeprojectmanager/qmakeparsernodes.h | 2 +- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 10 ++++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index e15fadb46db..cad20e189f1 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -1284,9 +1285,9 @@ void QmakeProFile::asyncUpdate() if (!includedInExactParse()) m_readerExact->setExact(false); QmakeEvalInput input = evalInput(); - QFuture future = runAsync(ProjectExplorerPlugin::sharedThreadPool(), - QThread::LowestPriority, - &QmakeProFile::asyncEvaluate, this, input); + QFuture future = Utils::asyncRun(ProjectExplorerPlugin::sharedThreadPool(), + QThread::LowestPriority, + &QmakeProFile::asyncEvaluate, this, input); m_parseFutureWatcher->setFuture(future); } @@ -1630,9 +1631,9 @@ QmakeEvalResultPtr QmakeProFile::evaluate(const QmakeEvalInput &input) return result; } -void QmakeProFile::asyncEvaluate(QFutureInterface &fi, QmakeEvalInput input) +void QmakeProFile::asyncEvaluate(QPromise &promise, QmakeEvalInput input) { - fi.reportResult(evaluate(input)); + promise.addResult(evaluate(input)); } bool sortByParserNodes(Node *a, Node *b) diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index 34c4958564b..9296addfa80 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -336,7 +336,7 @@ private: static Internal::QmakeEvalResultPtr evaluate(const Internal::QmakeEvalInput &input); void applyEvaluate(const Internal::QmakeEvalResultPtr &parseResult); - void asyncEvaluate(QFutureInterface &fi, + void asyncEvaluate(QPromise &promise, Internal::QmakeEvalInput input); void cleanupProFileReaders(); diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 322e58c37d0..b4f1bea8dcd 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -40,15 +40,17 @@ #include #include +#include + #include #include #include #include #include +#include #include #include -#include #include #include @@ -923,9 +925,9 @@ const FilePath &QmakeBuildSystem::qmakeSysroot() const void QmakeBuildSystem::destroyProFileReader(QtSupport::ProFileReader *reader) { // The ProFileReader destructor is super expensive (but thread-safe). - const auto deleteFuture = runAsync(ProjectExplorerPlugin::sharedThreadPool(), QThread::LowestPriority, - [reader] { delete reader; }); - onFinished(deleteFuture, this, [this](const QFuture &) { + const auto deleteFuture = Utils::asyncRun(ProjectExplorerPlugin::sharedThreadPool(), + [reader] { delete reader; }); + Utils::onFinished(deleteFuture, this, [this](const QFuture &) { if (!--m_qmakeGlobalsRefCnt) { deregisterFromCacheManager(); m_qmakeGlobals.reset(); From fcb919482850b130acd40309de8915760a320d4c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 17:03:28 +0100 Subject: [PATCH 0226/1447] Docker: Use QtConcurrent invocation for async run Change-Id: Ie5e6f5c746cf194fa00310a24db9344b72933ad5 Reviewed-by: hjk Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/docker/dockerapi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/docker/dockerapi.cpp b/src/plugins/docker/dockerapi.cpp index 75256f9473f..eb77059a544 100644 --- a/src/plugins/docker/dockerapi.cpp +++ b/src/plugins/docker/dockerapi.cpp @@ -6,9 +6,9 @@ #include "dockertr.h" #include +#include #include #include -#include #include @@ -65,7 +65,7 @@ void DockerApi::checkCanConnect(bool async) m_dockerDaemonAvailable = std::nullopt; emit dockerDaemonAvailableChanged(); - auto future = Utils::runAsync([lk = std::move(lk), this] { + auto future = Utils::asyncRun([lk = std::move(lk), this] { m_dockerDaemonAvailable = canConnect(); emit dockerDaemonAvailableChanged(); }); From 7ceb185539bc12a3ae8eb74b765a0f844acc8f31 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 9 Mar 2023 21:38:01 +0100 Subject: [PATCH 0227/1447] Terminal: Fix line selection mode Change-Id: I03d4bf7343a49b19edfcb20d1eb57bfe18703ddf Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index cb8e50166da..3ff38722c2c 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -1007,7 +1007,7 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) m_selection->start = m_surface->gridToPos( {0, m_surface->posToGrid(m_selection->start).y()}); m_selection->end = m_surface->gridToPos( - {viewport()->width(), m_surface->posToGrid(m_selection->end).y()}); + {m_surface->liveSize().width(), m_surface->posToGrid(m_selection->end).y()}); } else { m_selectLineMode = false; int pos = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos()))); @@ -1037,8 +1037,14 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) std::swap(start, newEnd); } - m_selection->start = start; - m_selection->end = newEnd; + if (m_selectLineMode) { + m_selection->start = m_surface->gridToPos({0, m_surface->posToGrid(start).y()}); + m_selection->end = m_surface->gridToPos( + {m_surface->liveSize().width(), m_surface->posToGrid(newEnd).y()}); + } else { + m_selection->start = start; + m_selection->end = newEnd; + } if (old != *m_selection || selectionLog().isDebugEnabled()) updateViewport(); From ddad64e176dc5b406beed0d3f231d4d24b970630 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 9 Mar 2023 22:33:09 +0100 Subject: [PATCH 0228/1447] Terminal: Fix multi-line copy&paste Previously all lines would be copied into one without lines breaks. Change-Id: Id87dbde84a19ccbc5f53438a305173d1b070eaba Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 3ff38722c2c..2d798d34d45 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -360,7 +360,12 @@ void TerminalWidget::copyToClipboard() const Internal::CellIterator end = m_surface->iteratorAt(m_selection->end); std::u32string s; - std::copy(it, end, std::back_inserter(s)); + for (; it != end; ++it) { + if (it.gridPos().x() == 0 && !s.empty()) + s += U'\n'; + if (*it != 0) + s += *it; + } const QString text = QString::fromUcs4(s.data(), static_cast(s.size())); From b138ab151012afc2fbbb747ff2a13f0caaf2ca8f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 9 Mar 2023 22:30:47 +0100 Subject: [PATCH 0229/1447] Terminal: Fix copyToClipboard when selecting all When selecting the whole screen (e.g. while running nano) the iterator position would be "end", but the iterator state was not, as "CellIterator(this, pos)" did not check for that. Change-Id: Ie26ce27c0078f7b3fcc3c77673ac66bc273c842d Reviewed-by: Cristian Adam --- src/plugins/terminal/celliterator.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/celliterator.cpp b/src/plugins/terminal/celliterator.cpp index 76adbd5b4a3..101f7295213 100644 --- a/src/plugins/terminal/celliterator.cpp +++ b/src/plugins/terminal/celliterator.cpp @@ -22,8 +22,13 @@ CellIterator::CellIterator(const TerminalSurface *surface, int pos) : m_state(State::INSIDE) , m_surface(surface) { - m_pos = pos; m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; + m_pos = qMin(m_maxpos + 1, pos); + if (m_pos == 0) { + m_state = State::BEGIN; + } else if (m_pos == m_maxpos + 1) { + m_state = State::END; + } updateChar(); } @@ -47,8 +52,6 @@ void CellIterator::updateChar() { QPoint cell = m_surface->posToGrid(m_pos); m_char = m_surface->fetchCharAt(cell.x(), cell.y()); - if (m_char == 0) - m_char = U' '; } CellIterator &CellIterator::operator-=(int n) From 215bd2ef2b02dc5a49cdd83be9173c2b25c98a5e Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 9 Mar 2023 18:52:02 +0100 Subject: [PATCH 0230/1447] Terminal: fix copy to clipboard of bottom up selection The multi line selection from bottom right corner to top left was broken for copy to clipboard. Change-Id: Ica40ec2ce5bb7b9d4b0187ebb454cd16e039e339 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalwidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 2d798d34d45..aba69664fb1 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -1041,6 +1041,8 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) if (start > newEnd) { std::swap(start, newEnd); } + if (start < 0) + start = 0; if (m_selectLineMode) { m_selection->start = m_surface->gridToPos({0, m_surface->posToGrid(start).y()}); From 5f8f2f4bcbf114e0e909635f1474629378dcef4e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 8 Mar 2023 19:44:39 -0800 Subject: [PATCH 0231/1447] Update perfparser to fix build with elfutils 0.188 Change-Id: Ib1d2fc7100134f7597cdfffd174aa36d069375a8 Reviewed-by: Reviewed-by: Milian Wolff --- src/tools/perfparser | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/perfparser b/src/tools/perfparser index 6c475b413b3..630828ad26f 160000 --- a/src/tools/perfparser +++ b/src/tools/perfparser @@ -1 +1 @@ -Subproject commit 6c475b413b3edb26897cbc1bd19296d497aaee79 +Subproject commit 630828ad26f4c3ffbddc10daba547919ff404511 From 887f6afd258233c476bea1a34834a67e12a864c0 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 9 Mar 2023 22:33:47 +0100 Subject: [PATCH 0232/1447] Terminal: Auto-scroll when selecting outside Change-Id: I5dea3256524634d9c3e6c0f8132c6bdba4494978 Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 60 +++++++++++++++---------- src/plugins/terminal/terminalwidget.h | 5 ++- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index aba69664fb1..0321c0ce5ca 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -94,6 +94,15 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op connect(&m_flushDelayTimer, &QTimer::timeout, this, [this]() { flushVTerm(true); }); + m_scrollTimer.setSingleShot(false); + m_scrollTimer.setInterval(1s / 2); + connect(&m_scrollTimer, &QTimer::timeout, this, [this] { + if (m_scrollDirection < 0) + verticalScrollBar()->triggerAction(QAbstractSlider::SliderSingleStepSub); + else if (m_scrollDirection > 0) + verticalScrollBar()->triggerAction(QAbstractSlider::SliderSingleStepAdd); + }); + connect(&TerminalSettings::instance(), &AspectContainer::applied, this, [this] { // Setup colors first, as setupFont will redraw the screen. setupColors(); @@ -992,7 +1001,9 @@ void TerminalWidget::inputMethodEvent(QInputMethodEvent *event) void TerminalWidget::mousePressEvent(QMouseEvent *event) { - m_activeMouseSelect.start = event->pos(); + m_scrollDirection = 0; + + m_activeMouseSelect.start = viewportToGlobal(event->pos()); if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) { if (m_linkSelection) { @@ -1034,8 +1045,29 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) { if (m_selection && event->buttons() & Qt::LeftButton) { const auto old = m_selection; + int scrollVelocity = 0; + if (event->pos().y() < 0) { + scrollVelocity = (event->pos().y()); + } else if (event->pos().y() > viewport()->height()) { + scrollVelocity = (event->pos().y() - viewport()->height()); + } - int start = m_surface->gridToPos(globalToGrid(viewportToGlobal(m_activeMouseSelect.start))); + if ((scrollVelocity != 0) != m_scrollTimer.isActive()) { + if (scrollVelocity != 0) + m_scrollTimer.start(); + else + m_scrollTimer.stop(); + } + + m_scrollDirection = scrollVelocity; + + if (m_scrollTimer.isActive() && scrollVelocity != 0) { + const std::chrono::milliseconds scrollInterval = 1000ms / qAbs(scrollVelocity); + if (m_scrollTimer.intervalAsDuration() != scrollInterval) + m_scrollTimer.setInterval(scrollInterval); + } + + int start = m_surface->gridToPos(globalToGrid(m_activeMouseSelect.start)); int newEnd = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos()))); if (start > newEnd) { @@ -1103,6 +1135,8 @@ void TerminalWidget::checkLinkAt(const QPoint &pos) void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) { + m_scrollTimer.stop(); + if (m_selection && event->button() == Qt::LeftButton) { if (m_selection->end - m_selection->start == 0) { setSelection(std::nullopt); @@ -1149,28 +1183,6 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) event->accept(); } -void TerminalWidget::scrollContentsBy(int dx, int dy) -{ - Q_UNUSED(dx); - Q_UNUSED(dy); - - if (m_ignoreScroll) - return; - /* - if (m_altscreen) - return; - - size_t orig = m_scrollback->offset(); - size_t offset = m_scrollback->scroll(dy); - if (orig == offset) - return; - - m_cursor.visible = (offset == 0); - */ - - updateViewport(); -} - void TerminalWidget::showEvent(QShowEvent *event) { Q_UNUSED(event); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 3e4da77fc18..53d82b3899d 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -89,8 +89,6 @@ protected: void mouseReleaseEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override; - void scrollContentsBy(int dx, int dy) override; - void showEvent(QShowEvent *event) override; bool event(QEvent *event) override; @@ -189,6 +187,9 @@ private: QTimer m_flushDelayTimer; + QTimer m_scrollTimer; + int m_scrollDirection{0}; + std::array m_currentColors; Utils::Terminal::OpenTerminalParameters m_openParameters; From 67f7968e9b0fe9997110d41363b8c6ef60737c5b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 11 Mar 2023 12:17:27 +0100 Subject: [PATCH 0233/1447] CMake: Add feature info for executables Change-Id: I4cfa2168b6e03730c02ca089f3c6f86fc07a6a01 Reviewed-by: Cristian Adam Reviewed-by: --- cmake/QtCreatorAPI.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index fb843f29280..0f512b9ef87 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -628,6 +628,7 @@ function(add_qtc_executable name) update_cached_list(__QTC_EXECUTABLES "${name}") + condition_info(_extra_text _arg_CONDITION) if (NOT _arg_CONDITION) set(_arg_CONDITION ON) endif() @@ -648,6 +649,9 @@ function(add_qtc_executable name) else() set(_executable_enabled OFF) endif() + if (NOT _arg_INTERNAL_ONLY) + add_feature_info("Executable ${name}" _executable_enabled "${_extra_text}") + endif() if (NOT _executable_enabled) return() endif() From 5c0a956e8c238fd5906005e89ae7b3e3de725034 Mon Sep 17 00:00:00 2001 From: Artem Mukhin Date: Thu, 9 Mar 2023 22:03:42 +0100 Subject: [PATCH 0234/1447] Debugger: Fix GDB MI output parsing When using `lldbbridge.py`, Python throws `TypeError: string indices must be integers` because `gdbmiparser.parse_response` cannot parse the multiline output. The bug was introduced in bb11788. Change-Id: I5faae4c3d034c0f159e9c1e473b6929ba79b8272 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- share/qtcreator/debugger/dumper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 1c1d72fc1aa..136961db3e7 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -877,7 +877,7 @@ class DumperBase(): self.output.append(stuff) def takeOutput(self): - res = '\n'.join(self.output) + res = ''.join(self.output) self.output = [] return res From dc2f6b234578b30eacba75980885083396fabaec Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Mar 2023 19:32:18 +0100 Subject: [PATCH 0235/1447] DeviceShell tests: Use QtConcurrent instead of Utils::mapped() Fix some const correctness and style. Change-Id: Id284f14530ff454e92e3c77b33e0844fcb429daf Reviewed-by: Reviewed-by: Marcus Tillmanns --- .../utils/deviceshell/tst_deviceshell.cpp | 21 ++++++------ tests/manual/deviceshell/tst_deviceshell.cpp | 34 +++++++++---------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/tests/auto/utils/deviceshell/tst_deviceshell.cpp b/tests/auto/utils/deviceshell/tst_deviceshell.cpp index d767d5a4799..a0d8a9cfcc9 100644 --- a/tests/auto/utils/deviceshell/tst_deviceshell.cpp +++ b/tests/auto/utils/deviceshell/tst_deviceshell.cpp @@ -3,16 +3,16 @@ #include +#include #include #include #include #include -#include #include -#include #include #include +#include #include using namespace Utils; @@ -312,15 +312,14 @@ private slots: TestShell shell(cmdLine); QCOMPARE(shell.state(), DeviceShell::State::Succeeded); - QList runs{1,2,3,4,5,6,7,8,9}; - int maxDepth = 4; int numMs = 0; while (true) { QElapsedTimer t; t.start(); - RunResult result = shell.runInShell({"find", {"/usr", "-maxdepth", QString::number(maxDepth)}}); + const RunResult result = shell.runInShell({"find", {"/usr", "-maxdepth", + QString::number(maxDepth)}}); numMs = t.elapsed(); qDebug() << "adjusted maxDepth" << maxDepth << "took" << numMs << "ms"; if (numMs < 100 || maxDepth == 1) { @@ -329,15 +328,17 @@ private slots: maxDepth--; } - QList results = Utils::mapped(runs, [&shell, maxDepth](const int i) -> QByteArray{ + const auto find = [&shell, maxDepth](int i) { QElapsedTimer t; t.start(); - RunResult result = shell.runInShell({"find", {"/usr", "-maxdepth", QString::number(maxDepth)}}); + const RunResult result = shell.runInShell({"find", {"/usr", "-maxdepth", + QString::number(maxDepth)}}); qDebug() << i << "took" << t.elapsed() << "ms"; return result.stdOut; - }); - - QVERIFY (!Utils::anyOf(results, [&results](const QByteArray r){ return r != results[0]; })); + }; + const QList runs{1,2,3,4,5,6,7,8,9}; + const QList results = QtConcurrent::blockingMapped(runs, find); + QVERIFY(!Utils::anyOf(results, [&results](const QByteArray r) { return r != results[0]; })); } void testNoScript_data() diff --git a/tests/manual/deviceshell/tst_deviceshell.cpp b/tests/manual/deviceshell/tst_deviceshell.cpp index 10c14149758..2703e6b82d6 100644 --- a/tests/manual/deviceshell/tst_deviceshell.cpp +++ b/tests/manual/deviceshell/tst_deviceshell.cpp @@ -5,14 +5,12 @@ #include #include -#include #include #include -#include #include -#include #include +#include #include using namespace Utils; @@ -86,45 +84,47 @@ class tst_DeviceShell : public QObject return result; } - void test(int maxNumThreads, int numCalls) + void test(int numCalls, int maxNumThreads) { TestShell shell; QCOMPARE(shell.state(), DeviceShell::State::Succeeded); QThreadPool::globalInstance()->setMaxThreadCount(maxNumThreads); - QList testArray = testArrays(numCalls); + const QList testArray = testArrays(numCalls); QElapsedTimer t; t.start(); - const QList result - = mapped(testArray, [&shell](QByteArray data) -> QByteArray { - return shell.runInShell({"cat", {}}, data).stdOut; - }, MapReduceOption::Ordered, QThreadPool::globalInstance()); - - QCOMPARE(result, testArray); + const auto cat = [&shell](const QByteArray &data) { + return shell.runInShell({"cat", {}}, data).stdOut; + }; + const QList results = QtConcurrent::blockingMapped(testArray, cat); + QCOMPARE(results, testArray); qDebug() << "maxThreads:" << maxNumThreads << ", took:" << t.elapsed() / 1000.0 << "seconds"; } - void testSleep(QList testData, int nThreads) + void testSleep(QList testData, int maxNumThreads) { TestShell shell; QCOMPARE(shell.state(), DeviceShell::State::Succeeded); - QThreadPool::globalInstance()->setMaxThreadCount(nThreads); + QThreadPool::globalInstance()->setMaxThreadCount(maxNumThreads); QElapsedTimer t; t.start(); - const auto result = mapped(testData, [&shell](const int &time) { + const auto sleep = [&shell](int time) { shell.runInShell({"sleep", {QString("%1").arg(time)}}); return 0; - }, MapReduceOption::Unordered, QThreadPool::globalInstance()); + }; + const QList results = QtConcurrent::blockingMapped(testData, sleep); + QCOMPARE(results, QList(testData.size(), 0)); - qDebug() << "maxThreads:" << nThreads << ", took:" << t.elapsed() / 1000.0 << "seconds"; + qDebug() << "maxThreads:" << maxNumThreads << ", took:" << t.elapsed() / 1000.0 + << "seconds"; } private slots: @@ -183,7 +183,7 @@ private slots: QFETCH(int, numThreads); QFETCH(int, numIterations); - test(numThreads, numIterations); + test(numIterations, numThreads); } void testSleepMulti() From 3859b703751736d8365ca037178e4abd16a98292 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Mar 2023 12:24:12 +0100 Subject: [PATCH 0236/1447] CppEditor: Fix missing include, start dummy promise Amends a8214665fe45f61668df380f045150258487a55a Change-Id: I40c24d2895fe10105827928bb49d98c8a9a5cf74 Reviewed-by: Christian Stenger Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/cppeditor/baseeditordocumentparser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/cppeditor/baseeditordocumentparser.cpp b/src/plugins/cppeditor/baseeditordocumentparser.cpp index d9bfc022e31..cbfa6f96859 100644 --- a/src/plugins/cppeditor/baseeditordocumentparser.cpp +++ b/src/plugins/cppeditor/baseeditordocumentparser.cpp @@ -8,6 +8,8 @@ #include "cppprojectpartchooser.h" #include "editordocumenthandle.h" +#include + using namespace Utils; namespace CppEditor { @@ -60,6 +62,7 @@ void BaseEditorDocumentParser::setConfiguration(const Configuration &configurati void BaseEditorDocumentParser::update(const UpdateParams &updateParams) { QPromise dummy; + dummy.start(); update(dummy, updateParams); } From 87b5176fd23b749d13fef81e65db09939b446e4f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 9 Mar 2023 11:30:31 +0100 Subject: [PATCH 0237/1447] Add test for examples parsing Change-Id: Id2ec8afcdbdff97e12b32b836c955552589081c4 Reviewed-by: Eike Ziller Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/qtsupport/examplesparser.cpp | 14 +- src/plugins/qtsupport/examplesparser.h | 21 ++- tests/auto/CMakeLists.txt | 1 + tests/auto/auto.qbs | 1 + tests/auto/examples/CMakeLists.txt | 5 + tests/auto/examples/examples.qbs | 9 ++ tests/auto/examples/tst_examples.cpp | 156 +++++++++++++++++++++++ 7 files changed, 198 insertions(+), 9 deletions(-) create mode 100644 tests/auto/examples/CMakeLists.txt create mode 100644 tests/auto/examples/examples.qbs create mode 100644 tests/auto/examples/tst_examples.cpp diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index 1d7211b6367..de6a14d8369 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -229,10 +229,18 @@ expected_str> parseExamples(const FilePath &manifest, if (!contents) return make_unexpected(contents.error()); - const FilePath path = manifest.parentDir(); + return parseExamples(*contents, manifest, examplesInstallPath, demosInstallPath, examples); +} +expected_str> parseExamples(const QByteArray &manifestData, + const Utils::FilePath &manifestPath, + const FilePath &examplesInstallPath, + const FilePath &demosInstallPath, + const bool examples) +{ + const FilePath path = manifestPath.parentDir(); QList items; - QXmlStreamReader reader(*contents); + QXmlStreamReader reader(manifestData); while (!reader.atEnd()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement: @@ -251,7 +259,7 @@ expected_str> parseExamples(const FilePath &manifest, if (reader.hasError()) { qDeleteAll(items); return make_unexpected(QString("Could not parse file \"%1\" as XML document: %2:%3: %4") - .arg(manifest.toUserOutput()) + .arg(manifestPath.toUserOutput()) .arg(reader.lineNumber()) .arg(reader.columnNumber()) .arg(reader.errorString())); diff --git a/src/plugins/qtsupport/examplesparser.h b/src/plugins/qtsupport/examplesparser.h index 494a42b1473..b133d2c6c8a 100644 --- a/src/plugins/qtsupport/examplesparser.h +++ b/src/plugins/qtsupport/examplesparser.h @@ -3,6 +3,8 @@ #pragma once +#include "qtsupport_global.h" + #include #include #include @@ -11,7 +13,7 @@ namespace QtSupport::Internal { enum InstructionalType { Example = 0, Demo, Tutorial }; -class ExampleItem : public Core::ListItem +class QTSUPPORT_EXPORT ExampleItem : public Core::ListItem { public: Utils::FilePath projectPath; @@ -20,7 +22,6 @@ public: Utils::FilePath mainFile; /* file to be visible after opening filesToOpen */ Utils::FilePaths dependencies; InstructionalType type; - int difficulty = 0; bool hasSourceCode = false; bool isVideo = false; bool isHighlighted = false; @@ -29,10 +30,18 @@ public: QStringList platforms; }; -Utils::expected_str> parseExamples(const Utils::FilePath &manifest, - const Utils::FilePath &examplesInstallPath, - const Utils::FilePath &demosInstallPath, - bool examples); +QTSUPPORT_EXPORT Utils::expected_str> parseExamples( + const Utils::FilePath &manifest, + const Utils::FilePath &examplesInstallPath, + const Utils::FilePath &demosInstallPath, + bool examples); + +QTSUPPORT_EXPORT Utils::expected_str> parseExamples( + const QByteArray &manifestData, + const Utils::FilePath &manifestPath, + const Utils::FilePath &examplesInstallPath, + const Utils::FilePath &demosInstallPath, + bool examples); } // namespace QtSupport::Internal diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index c71cbafdb2d..98ee3458965 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(cplusplus) add_subdirectory(debugger) add_subdirectory(diff) add_subdirectory(environment) +add_subdirectory(examples) add_subdirectory(extensionsystem) add_subdirectory(externaltool) add_subdirectory(filesearch) diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs index af173fa9f09..2ff98d14097 100644 --- a/tests/auto/auto.qbs +++ b/tests/auto/auto.qbs @@ -12,6 +12,7 @@ Project { "debugger/debugger.qbs", "diff/diff.qbs", "environment/environment.qbs", + "examples/examples.qbs", "extensionsystem/extensionsystem.qbs", "externaltool/externaltool.qbs", "filesearch/filesearch.qbs", diff --git a/tests/auto/examples/CMakeLists.txt b/tests/auto/examples/CMakeLists.txt new file mode 100644 index 00000000000..cf8d1e4191e --- /dev/null +++ b/tests/auto/examples/CMakeLists.txt @@ -0,0 +1,5 @@ +add_qtc_test(tst_examples + DEPENDS Utils Core QtSupport + SOURCES tst_examples.cpp +) + diff --git a/tests/auto/examples/examples.qbs b/tests/auto/examples/examples.qbs new file mode 100644 index 00000000000..39cacc395fa --- /dev/null +++ b/tests/auto/examples/examples.qbs @@ -0,0 +1,9 @@ +import qbs + +QtcAutotest { + name: "Examples autotest" + Depends { name: "Core" } + Depends { name: "QtSupport" } + Depends { name: "Utils" } + files: "tst_examples.cpp" +} diff --git a/tests/auto/examples/tst_examples.cpp b/tests/auto/examples/tst_examples.cpp new file mode 100644 index 00000000000..22236ed4c5d --- /dev/null +++ b/tests/auto/examples/tst_examples.cpp @@ -0,0 +1,156 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include +#include + +#include + +using namespace Utils; +using namespace QtSupport::Internal; + +class tst_Examples : public QObject +{ + Q_OBJECT + +public: + tst_Examples(); + ~tst_Examples(); + +private slots: + void parsing_data(); + void parsing(); +}; + +tst_Examples::tst_Examples() = default; +tst_Examples::~tst_Examples() = default; + +static ExampleItem fetchItem() +{ + QFETCH(QString, name); + QFETCH(QString, description); + QFETCH(QString, imageUrl); + QFETCH(QStringList, tags); + QFETCH(FilePath, projectPath); + QFETCH(QString, docUrl); + QFETCH(FilePaths, filesToOpen); + QFETCH(FilePath, mainFile); + QFETCH(FilePaths, dependencies); + QFETCH(InstructionalType, type); + QFETCH(bool, hasSourceCode); + QFETCH(bool, isVideo); + QFETCH(bool, isHighlighted); + QFETCH(QString, videoUrl); + QFETCH(QString, videoLength); + QFETCH(QStringList, platforms); + ExampleItem item; + item.name = name; + item.description = description; + item.imageUrl = imageUrl; + item.tags = tags; + item.projectPath = projectPath; + item.docUrl = docUrl; + item.filesToOpen = filesToOpen; + item.mainFile = mainFile; + item.dependencies = dependencies; + item.type = type; + item.hasSourceCode = hasSourceCode; + item.isVideo = isVideo; + item.isHighlighted = isHighlighted; + item.videoUrl = videoUrl; + item.videoLength = videoLength; + item.platforms = platforms; + return item; +} + +void tst_Examples::parsing_data() +{ + QTest::addColumn("data"); + QTest::addColumn("isExamples"); + QTest::addColumn("name"); + QTest::addColumn("description"); + QTest::addColumn("imageUrl"); + QTest::addColumn("tags"); + QTest::addColumn("projectPath"); + QTest::addColumn("docUrl"); + QTest::addColumn("filesToOpen"); + QTest::addColumn("mainFile"); + QTest::addColumn("dependencies"); + QTest::addColumn("type"); + QTest::addColumn("hasSourceCode"); + QTest::addColumn("isVideo"); + QTest::addColumn("isHighlighted"); + QTest::addColumn("videoUrl"); + QTest::addColumn("videoLength"); + QTest::addColumn("platforms"); + + QTest::addRow("example") + << QByteArray(R"raw( + + + + ios,widgets + widgets/widgets/analogclock/main.cpp + widgets/widgets/analogclock/analogclock.h + widgets/widgets/analogclock/analogclock.cpp + + Graphics + widgets + + + + )raw") << /*isExamples=*/true + << "Analog Clock" + << "The Analog Clock example shows how to draw the contents of a custom widget." + << "qthelp://org.qt-project.qtwidgets.660/qtwidgets/images/analogclock-example.png" + << QStringList{"ios", "widgets"} + << FilePath::fromUserInput("manifest/widgets/widgets/analogclock/CMakeLists.txt") + << "qthelp://org.qt-project.qtwidgets.660/qtwidgets/" + "qtwidgets-widgets-analogclock-example.html" + << FilePaths{FilePath::fromUserInput("manifest/widgets/widgets/analogclock/main.cpp"), + FilePath::fromUserInput("manifest/widgets/widgets/analogclock/analogclock.h"), + FilePath::fromUserInput( + "manifest/widgets/widgets/analogclock/analogclock.cpp")} + << FilePath::fromUserInput("manifest/widgets/widgets/analogclock/analogclock.cpp") + << FilePaths() << Example << true << false << false << "" + << "" << QStringList(); +} + +void tst_Examples::parsing() +{ + QFETCH(QByteArray, data); + QFETCH(bool, isExamples); + const ExampleItem expected = fetchItem(); + const expected_str> result + = parseExamples(data, + FilePath("manifest/examples-manifest.xml"), + FilePath("examples"), + FilePath("demos"), + isExamples); + QVERIFY(result); + QCOMPARE(result->size(), 1); + const ExampleItem item = *result->at(0); + QCOMPARE(item.name, expected.name); + QCOMPARE(item.description, expected.description); + QCOMPARE(item.imageUrl, expected.imageUrl); + QCOMPARE(item.tags, expected.tags); + QCOMPARE(item.projectPath, expected.projectPath); + QCOMPARE(item.docUrl, expected.docUrl); + QCOMPARE(item.filesToOpen, expected.filesToOpen); + QCOMPARE(item.mainFile, expected.mainFile); + QCOMPARE(item.dependencies, expected.dependencies); + QCOMPARE(item.type, expected.type); + QCOMPARE(item.hasSourceCode, expected.hasSourceCode); + QCOMPARE(item.isVideo, expected.isVideo); + QCOMPARE(item.isHighlighted, expected.isHighlighted); + QCOMPARE(item.videoUrl, expected.videoUrl); + QCOMPARE(item.videoLength, expected.videoLength); + QCOMPARE(item.platforms, expected.platforms); + qDeleteAll(*result); +} + +QTEST_APPLESS_MAIN(tst_Examples) + +#include "tst_examples.moc" From e060f82fa56131436a0c578c5857501b53ef7978 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 9 Mar 2023 14:00:08 +0100 Subject: [PATCH 0238/1447] Examples: Read meta data, which includes categories Task-number: QTCREATORBUG-28546 Change-Id: I11505d4f8b8eaef3f525185cd45757b6f41012ec Reviewed-by: Christian Stenger --- src/plugins/qtsupport/examplesparser.cpp | 31 ++++++++++++++++++++++++ src/plugins/qtsupport/examplesparser.h | 1 + tests/auto/examples/tst_examples.cpp | 8 +++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index de6a14d8369..bdde8e66a0f 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -43,6 +43,35 @@ static QStringList trimStringList(const QStringList &stringlist) return Utils::transform(stringlist, [](const QString &str) { return str.trimmed(); }); } +static QHash parseMeta(QXmlStreamReader *reader) +{ + QHash result; + while (!reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: + if (reader->name() == QLatin1String("entry")) { + const QString key = reader->attributes().value("name").toString(); + if (key.isEmpty()) { + reader->raiseError("Tag \"entry\" requires \"name\" attribute"); + break; + } + const QString value = reader->readElementText( + QXmlStreamReader::ErrorOnUnexpectedElement); + if (!value.isEmpty()) + result[key].append(value); + } + break; + case QXmlStreamReader::EndElement: + if (reader->name() == QLatin1String("meta")) + return result; + break; + default: + break; + } + } + return result; +} + static QList parseExamples(QXmlStreamReader *reader, const FilePath &projectsOffset, const FilePath &examplesInstallPath) @@ -95,6 +124,8 @@ static QList parseExamples(QXmlStreamReader *reader, item->platforms = trimStringList( reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) .split(QLatin1Char(','), Qt::SkipEmptyParts)); + } else if (reader->name() == QLatin1String("meta")) { + item->metaData = parseMeta(reader); } break; case QXmlStreamReader::EndElement: diff --git a/src/plugins/qtsupport/examplesparser.h b/src/plugins/qtsupport/examplesparser.h index b133d2c6c8a..2d1afa54838 100644 --- a/src/plugins/qtsupport/examplesparser.h +++ b/src/plugins/qtsupport/examplesparser.h @@ -28,6 +28,7 @@ public: QString videoUrl; QString videoLength; QStringList platforms; + QHash metaData; }; QTSUPPORT_EXPORT Utils::expected_str> parseExamples( diff --git a/tests/auto/examples/tst_examples.cpp b/tests/auto/examples/tst_examples.cpp index 22236ed4c5d..5a18f1e4498 100644 --- a/tests/auto/examples/tst_examples.cpp +++ b/tests/auto/examples/tst_examples.cpp @@ -25,6 +25,8 @@ private slots: tst_Examples::tst_Examples() = default; tst_Examples::~tst_Examples() = default; +using MetaData = QHash; + static ExampleItem fetchItem() { QFETCH(QString, name); @@ -43,6 +45,7 @@ static ExampleItem fetchItem() QFETCH(QString, videoUrl); QFETCH(QString, videoLength); QFETCH(QStringList, platforms); + QFETCH(MetaData, metaData); ExampleItem item; item.name = name; item.description = description; @@ -60,6 +63,7 @@ static ExampleItem fetchItem() item.videoUrl = videoUrl; item.videoLength = videoLength; item.platforms = platforms; + item.metaData = metaData; return item; } @@ -83,6 +87,7 @@ void tst_Examples::parsing_data() QTest::addColumn("videoUrl"); QTest::addColumn("videoLength"); QTest::addColumn("platforms"); + QTest::addColumn("metaData"); QTest::addRow("example") << QByteArray(R"raw( @@ -115,7 +120,7 @@ void tst_Examples::parsing_data() "manifest/widgets/widgets/analogclock/analogclock.cpp")} << FilePath::fromUserInput("manifest/widgets/widgets/analogclock/analogclock.cpp") << FilePaths() << Example << true << false << false << "" - << "" << QStringList(); + << "" << QStringList() << MetaData({{"category", {"Graphics"}}, {"tags", {"widgets"}}}); } void tst_Examples::parsing() @@ -148,6 +153,7 @@ void tst_Examples::parsing() QCOMPARE(item.videoUrl, expected.videoUrl); QCOMPARE(item.videoLength, expected.videoLength); QCOMPARE(item.platforms, expected.platforms); + QCOMPARE(item.metaData, expected.metaData); qDeleteAll(*result); } From d558741985f97f0928eec957f0f1118fdceedec4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 10 Mar 2023 15:57:40 +0100 Subject: [PATCH 0239/1447] Tracing: Use QtConcurrent invocation for async run Change-Id: I40dea7276ed9d54c7ce898f0463df05929576648 Reviewed-by: Ulf Hermann Reviewed-by: Reviewed-by: Qt CI Bot --- src/libs/tracing/timelinetracemanager.cpp | 36 +++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/libs/tracing/timelinetracemanager.cpp b/src/libs/tracing/timelinetracemanager.cpp index 96eb147519e..b252a02cee9 100644 --- a/src/libs/tracing/timelinetracemanager.cpp +++ b/src/libs/tracing/timelinetracemanager.cpp @@ -6,12 +6,10 @@ #include "timelinetracemanager.h" #include "tracingtr.h" +#include #include -#include -#include #include -#include #include @@ -223,8 +221,11 @@ QFuture TimelineTraceManager::save(const QString &filename) connect(writer, &QObject::destroyed, this, &TimelineTraceManager::saveFinished); connect(writer, &TimelineTraceFile::error, this, &TimelineTraceManager::error); - return Utils::runAsync([filename, writer] (QFutureInterface &future) { - writer->setFuture(future); + QFutureInterface fi; + fi.reportStarted(); + writer->setFuture(fi); + + Utils::asyncRun([filename, writer, fi] { QFile file(filename); if (file.open(QIODevice::WriteOnly)) @@ -232,10 +233,13 @@ QFuture TimelineTraceManager::save(const QString &filename) else writer->fail(Tr::tr("Could not open %1 for writing.").arg(filename)); - if (future.isCanceled()) + if (fi.isCanceled()) file.remove(); writer->deleteLater(); + QFutureInterface fiCopy = fi; + fiCopy.reportFinished(); }); + return fi.future(); } QFuture TimelineTraceManager::load(const QString &filename) @@ -249,8 +253,10 @@ QFuture TimelineTraceManager::load(const QString &filename) connect(reader, &QObject::destroyed, this, &TimelineTraceManager::loadFinished); connect(reader, &TimelineTraceFile::error, this, &TimelineTraceManager::error); - QFuture future = Utils::runAsync([filename, reader] (QFutureInterface &future) { - reader->setFuture(future); + QFutureInterface fi; + fi.reportStarted(); + reader->setFuture(fi); + Utils::asyncRun([filename, reader, fi] { QFile file(filename); if (file.open(QIODevice::ReadOnly)) @@ -259,11 +265,13 @@ QFuture TimelineTraceManager::load(const QString &filename) reader->fail(Tr::tr("Could not open %1 for reading.").arg(filename)); reader->deleteLater(); + QFutureInterface fiCopy = fi; + fiCopy.reportFinished(); }); QFutureWatcher *watcher = new QFutureWatcher(reader); connect(watcher, &QFutureWatcherBase::canceled, this, &TimelineTraceManager::clearAll); - connect(watcher, &QFutureWatcherBase::finished, this, [this, reader]() { + connect(watcher, &QFutureWatcherBase::finished, this, [this, reader] { if (!reader->isCanceled()) { if (reader->traceStart() >= 0) decreaseTraceStart(reader->traceStart()); @@ -272,9 +280,8 @@ QFuture TimelineTraceManager::load(const QString &filename) finalize(); } }); - watcher->setFuture(future); - - return future; + watcher->setFuture(fi.future()); + return fi.future(); } qint64 TimelineTraceManager::traceStart() const @@ -366,10 +373,9 @@ void TimelineTraceManager::restrictByFilter(TraceEventFilter filter) QFutureInterface future; replayEvents(filter(std::bind(&TimelineTraceManagerPrivate::dispatch, d, - std::placeholders::_1, std::placeholders::_2)), - [this]() { + std::placeholders::_1, std::placeholders::_2)), [this] { initialize(); - }, [this]() { + }, [this] { if (d->notesModel) d->notesModel->restore(); finalize(); From 2fc801e15346aaa442fe52e4b344ba24a294849b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 6 Mar 2023 19:37:55 +0100 Subject: [PATCH 0240/1447] Copilot: robustify authentication widget - fix initial state - prevent accessing unreachable servers Change-Id: Ia8d66ad215b864b672d5a1d1651123ca5848effa Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/authwidget.cpp | 35 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp index 9298bc66138..c8ee0cd173e 100644 --- a/src/plugins/copilot/authwidget.cpp +++ b/src/plugins/copilot/authwidget.cpp @@ -15,22 +15,24 @@ #include using namespace LanguageClient; +using namespace Copilot::Internal; namespace Copilot { bool isCopilotClient(Client *client) { - return dynamic_cast(client) != nullptr; + return dynamic_cast(client) != nullptr; } -Internal::CopilotClient *coPilotClient(Client *client) +CopilotClient *asCoPilotClient(Client *client) { - return static_cast(client); + return static_cast(client); } Internal::CopilotClient *findClient() { - return Internal::CopilotClient::instance(); + CopilotClient *client = Internal::CopilotClient::instance(); + return client && client->reachable() ? client : nullptr; } AuthWidget::AuthWidget(QWidget *parent) @@ -38,9 +40,12 @@ AuthWidget::AuthWidget(QWidget *parent) { using namespace Utils::Layouting; - m_button = new QPushButton(); + m_button = new QPushButton(Tr::tr("Sign in")); + m_button->setEnabled(false); m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Small); + m_progressIndicator->setVisible(false); m_statusLabel = new QLabel(); + m_statusLabel->setVisible(false); // clang-format off Column { @@ -51,8 +56,6 @@ AuthWidget::AuthWidget(QWidget *parent) }.attachTo(this); // clang-format on - setState("Checking status ...", true); - connect(LanguageClientManager::instance(), &LanguageClientManager::clientAdded, this, @@ -65,7 +68,7 @@ AuthWidget::AuthWidget(QWidget *parent) signIn(); }); - auto client = findClient(); + CopilotClient *client = findClient(); if (client) checkStatus(client); @@ -74,20 +77,30 @@ AuthWidget::AuthWidget(QWidget *parent) void AuthWidget::setState(const QString &buttonText, bool working) { m_button->setText(buttonText); + m_button->setVisible(true); m_progressIndicator->setVisible(working); m_statusLabel->setVisible(!m_statusLabel->text().isEmpty()); m_button->setEnabled(!working); } -void AuthWidget::onClientAdded(LanguageClient::Client *client) +void AuthWidget::onClientAdded(Client *client) { if (isCopilotClient(client)) { - checkStatus(coPilotClient(client)); + auto coPilotClient = asCoPilotClient(client); + if (coPilotClient->reachable()) { + checkStatus(coPilotClient); + } else { + connect(client, &Client::initialized, this, [this, coPilotClient] { + checkStatus(coPilotClient); + }); + } } } -void AuthWidget::checkStatus(Internal::CopilotClient *client) +void AuthWidget::checkStatus(CopilotClient *client) { + setState("Checking status ...", true); + client->requestCheckStatus(false, [this](const CheckStatusRequest::Response &response) { if (response.error()) { setState("failed: " + response.error()->message(), false); From 301a3cb34f782a7bbe256231996b2e466cffb864 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 9 Mar 2023 11:08:57 +0100 Subject: [PATCH 0241/1447] Copilot: improve client handling - centralize starting client - allow to start copilot with alternative settings - do not reset the client on finished. A finish might be followed by a restart attempt, so untracking the client in the plugin can result in having multiple running clients. Use a QPointer instead to safely reset once the client is deleted. Change-Id: Ifab8b04287d84bbdd4a0e936f4684b8d4391da2b Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/plugins/copilot/copilotclient.cpp | 10 ++++----- src/plugins/copilot/copilotclient.h | 2 +- src/plugins/copilot/copilotplugin.cpp | 31 ++++++++++++--------------- src/plugins/copilot/copilotplugin.h | 7 +++--- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 7bfddb0cf5a..a6047004aa8 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -25,11 +25,9 @@ using namespace Utils; namespace Copilot::Internal { -static LanguageClient::BaseClientInterface *clientInterface() +static LanguageClient::BaseClientInterface *clientInterface(const FilePath &nodePath, + const FilePath &distPath) { - const FilePath nodePath = CopilotSettings::instance().nodeJsPath.filePath(); - const FilePath distPath = CopilotSettings::instance().distPath.filePath(); - CommandLine cmd{nodePath, {distPath.toFSPathString()}}; const auto interface = new LanguageClient::StdIOClientInterface; @@ -44,8 +42,8 @@ CopilotClient *CopilotClient::instance() return currentInstance; } -CopilotClient::CopilotClient() - : LanguageClient::Client(clientInterface()) +CopilotClient::CopilotClient(const FilePath &nodePath, const FilePath &distPath) + : LanguageClient::Client(clientInterface(nodePath, distPath)) { setName("Copilot"); LanguageClient::LanguageFilter langFilter; diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index 73fe95e2531..42989e93f77 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -23,7 +23,7 @@ class DocumentWatcher; class CopilotClient : public LanguageClient::Client { public: - explicit CopilotClient(); + explicit CopilotClient(const Utils::FilePath &nodePath, const Utils::FilePath &distPath); static CopilotClient *instance(); diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index d473cac2cbc..45a859b1380 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include using namespace Utils; @@ -18,28 +20,16 @@ using namespace Core; namespace Copilot { namespace Internal { -CopilotPlugin::~CopilotPlugin() -{ - if (m_client) - m_client->shutdown(); - - m_client = nullptr; -} - void CopilotPlugin::initialize() { CopilotSettings::instance().readSettings(ICore::settings()); - m_client = new CopilotClient(); + restartClient(); - connect(m_client, &CopilotClient::finished, this, [this]() { m_client = nullptr; }); - - connect(&CopilotSettings::instance(), &CopilotSettings::applied, this, [this]() { - if (m_client) - m_client->shutdown(); - m_client = nullptr; - m_client = new CopilotClient(); - }); + connect(&CopilotSettings::instance(), + &CopilotSettings::applied, + this, + &CopilotPlugin::restartClient); } void CopilotPlugin::extensionsInitialized() @@ -47,5 +37,12 @@ void CopilotPlugin::extensionsInitialized() CopilotOptionsPage::instance().init(); } +void CopilotPlugin::restartClient() +{ + LanguageClient::LanguageClientManager::shutdownClient(m_client); + m_client = new CopilotClient(CopilotSettings::instance().nodeJsPath.filePath(), + CopilotSettings::instance().distPath.filePath()); +} + } // namespace Internal } // namespace Copilot diff --git a/src/plugins/copilot/copilotplugin.h b/src/plugins/copilot/copilotplugin.h index 798db7c2819..5d915030653 100644 --- a/src/plugins/copilot/copilotplugin.h +++ b/src/plugins/copilot/copilotplugin.h @@ -7,6 +7,8 @@ #include +#include + namespace TextEditor { class TextEditorWidget; } namespace Copilot { @@ -18,13 +20,12 @@ class CopilotPlugin : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Copilot.json") public: - ~CopilotPlugin(); - void initialize() override; void extensionsInitialized() override; + void restartClient(); private: - CopilotClient *m_client{nullptr}; + QPointer m_client; }; } // namespace Internal From 27881325a040512380a18dee1763738caa6bf527 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 8 Mar 2023 12:05:23 +0100 Subject: [PATCH 0242/1447] qml2puppet: Don't always recompile qml2puppet Whenever cmake runs, the app_version.h of qml2puppet is recreated. This was included almost everywhere so a complete rebuild of qml2puppet would be triggered. This patch moves the app_version.h include into a single .cpp to limit how much of qml2puppet needs to be recompiled. Fixes: QTCREATORBUG-28784 Change-Id: I5064d450ed92ec003f164bcd42be694612011196 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/tools/qml2puppet/CMakeLists.txt | 18 ++++--- .../qml2puppet/qml2puppet/appmetadata.cpp | 51 +++++++++++++++++++ src/tools/qml2puppet/qml2puppet/appmetadata.h | 44 +--------------- 3 files changed, 63 insertions(+), 50 deletions(-) create mode 100644 src/tools/qml2puppet/qml2puppet/appmetadata.cpp diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 75c9dd9ce5b..4543091ab71 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -29,8 +29,6 @@ else() set(QT_VERSION_MAJOR ${Qt6_VERSION_MAJOR}) endif() -configure_file(../../app/app_version.h.cmakein app/app_version.h ESCAPE_QUOTES) - if (NOT TARGET QmlPuppetCommunication) include(../../libs/qmlpuppetcommunication/QmlPuppetCommunication.cmake) endif() @@ -46,28 +44,32 @@ add_qtc_executable(qml2puppet ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} SOURCES qml2puppet/main.cpp - qml2puppet/qmlbase.h qml2puppet/appmetadata.h + qml2puppet/qmlbase.h + qml2puppet/appmetadata.cpp qml2puppet/appmetadata.h qml2puppet/qmlpuppet.h qml2puppet/qmlpuppet.cpp qml2puppet/configcrashpad.h qmlpuppet.qrc PROPERTIES OUTPUT_NAME qml2puppet-${IDE_VERSION} ) -if(TARGET qml2puppet) +if (TARGET qml2puppet) execute_process( COMMAND git describe --tags --always --dirty=+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE GIT_SHA_RESULT - OUTPUT_VARIABLE GIT_SHA_OUTPUT + OUTPUT_VARIABLE GIT_SHA ERROR_VARIABLE GIT_SHA_ERROR + OUTPUT_STRIP_TRAILING_WHITESPACE ) #if we are not a git repository use the .tag file - if(NOT GIT_SHA_OUTPUT) - file(READ ${CMAKE_CURRENT_SOURCE_DIR}/../../../.tag GIT_SHA_OUTPUT) + if(NOT GIT_SHA) + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/../../../.tag GIT_SHA LIMIT_COUNT 1) endif() - add_definitions( -D GIT_SHA=${GIT_SHA_OUTPUT} ) + set(IDE_REVISION_STR ${GIT_SHA}) + + configure_file(../../app/app_version.h.cmakein app/app_version.h ESCAPE_QUOTES) endif() extend_qtc_executable(qml2puppet diff --git a/src/tools/qml2puppet/qml2puppet/appmetadata.cpp b/src/tools/qml2puppet/qml2puppet/appmetadata.cpp new file mode 100644 index 00000000000..1896e4db926 --- /dev/null +++ b/src/tools/qml2puppet/qml2puppet/appmetadata.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "appmetadata.h" + +#include + +namespace QDSMeta::AppInfo { + +void printAppInfo() +{ + qInfo() << Qt::endl + << "<< QDS Meta Info >>" << Qt::endl + << "App Info" << Qt::endl + << " - Name :" << Core::Constants::IDE_ID << Qt::endl + << " - Version :" << Core::Constants::IDE_VERSION_DISPLAY << Qt::endl + << " - Author :" << Core::Constants::IDE_AUTHOR << Qt::endl + << " - Year :" << Core::Constants::IDE_YEAR << Qt::endl + << " - App :" << QCoreApplication::applicationName() << Qt::endl + << "Build Info " << Qt::endl + << " - Date :" << __DATE__ << Qt::endl + << " - Commit :" << QStringLiteral(QDS_STRINGIFY(IDE_REVISION_STR)) << Qt::endl + << " - Qt Version :" << QT_VERSION_STR << Qt::endl + << "Compiler Info " << Qt::endl +#if defined(__GNUC__) + << " - GCC :" << __GNUC__ << Qt::endl + << " - GCC Minor :" << __GNUC_MINOR__ << Qt::endl + << " - GCC Patch :" << __GNUC_PATCHLEVEL__ << Qt::endl +#endif +#if defined(_MSC_VER) + << " - MSC Short :" << _MSC_VER << Qt::endl + << " - MSC Full :" << _MSC_FULL_VER << Qt::endl +#endif +#if defined(__clang__) + << " - clang maj :" << __clang_major__ << Qt::endl + << " - clang min :" << __clang_minor__ << Qt::endl + << " - clang patch :" << __clang_patchlevel__ << Qt::endl +#endif + << "<< End Of QDS Meta Info >>" << Qt::endl; + exit(0); +} + +void registerAppInfo(const QString &appName) +{ + QCoreApplication::setOrganizationName(Core::Constants::IDE_AUTHOR); + QCoreApplication::setOrganizationDomain("qt-project.org"); + QCoreApplication::setApplicationName(appName); + QCoreApplication::setApplicationVersion(Core::Constants::IDE_VERSION_LONG); +} + +} // namespace QDSMeta::AppInfo diff --git a/src/tools/qml2puppet/qml2puppet/appmetadata.h b/src/tools/qml2puppet/qml2puppet/appmetadata.h index d134135fd8f..18eb650461e 100644 --- a/src/tools/qml2puppet/qml2puppet/appmetadata.h +++ b/src/tools/qml2puppet/qml2puppet/appmetadata.h @@ -5,8 +5,6 @@ #include #include -#include - // Common functions can be used in all QDS apps namespace QDSMeta { @@ -50,46 +48,8 @@ namespace AppInfo { #define STRINGIFY_INTERNAL(x) #x #define QDS_STRINGIFY(x) STRINGIFY_INTERNAL(x) -inline void printAppInfo() -{ - qInfo() << Qt::endl - << "<< QDS Meta Info >>" << Qt::endl - << "App Info" << Qt::endl - << " - Name :" << Core::Constants::IDE_ID << Qt::endl - << " - Version :" << Core::Constants::IDE_VERSION_DISPLAY << Qt::endl - << " - Author :" << Core::Constants::IDE_AUTHOR << Qt::endl - << " - Year :" << Core::Constants::IDE_YEAR << Qt::endl - << " - App :" << QCoreApplication::applicationName() << Qt::endl - << "Build Info " << Qt::endl - << " - Date :" << __DATE__ << Qt::endl - << " - Commit :" << QStringLiteral(QDS_STRINGIFY(GIT_SHA)) << Qt::endl - << " - Qt Version :" << QT_VERSION_STR << Qt::endl - << "Compiler Info " << Qt::endl -#if defined(__GNUC__) - << " - GCC :" << __GNUC__ << Qt::endl - << " - GCC Minor :" << __GNUC_MINOR__ << Qt::endl - << " - GCC Patch :" << __GNUC_PATCHLEVEL__ << Qt::endl -#endif -#if defined(_MSC_VER) - << " - MSC Short :" << _MSC_VER << Qt::endl - << " - MSC Full :" << _MSC_FULL_VER << Qt::endl -#endif -#if defined(__clang__) - << " - clang maj :" << __clang_major__ << Qt::endl - << " - clang min :" << __clang_minor__ << Qt::endl - << " - clang patch :" << __clang_patchlevel__ << Qt::endl -#endif - << "<< End Of QDS Meta Info >>" << Qt::endl; - exit(0); -} - -inline void registerAppInfo(const QString &appName) -{ - QCoreApplication::setOrganizationName(Core::Constants::IDE_AUTHOR); - QCoreApplication::setOrganizationDomain("qt-project.org"); - QCoreApplication::setApplicationName(appName); - QCoreApplication::setApplicationVersion(Core::Constants::IDE_VERSION_LONG); -} +void printAppInfo(); +void registerAppInfo(const QString &appName); } // namespace AppInfo } // namespace QDSMeta From e25b89ae39857e47ce6839d224997a61f919eb36 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 9 Mar 2023 12:26:42 +0100 Subject: [PATCH 0243/1447] Copilot: Update authenticator widget while changing settings Use a separate client for the authenticator widget that can react on changes in the settings widget. This removes the need to manually apply the settings between setting up the nodejs and agent.js paths and signing into github. Change-Id: I6628a3a8906ccbba208f9dac968262df962f93c0 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/authwidget.cpp | 97 ++++++++-------------- src/plugins/copilot/authwidget.h | 6 +- src/plugins/copilot/copilotoptionspage.cpp | 18 ++++ 3 files changed, 57 insertions(+), 64 deletions(-) diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp index c8ee0cd173e..cba1f178d31 100644 --- a/src/plugins/copilot/authwidget.cpp +++ b/src/plugins/copilot/authwidget.cpp @@ -19,22 +19,6 @@ using namespace Copilot::Internal; namespace Copilot { -bool isCopilotClient(Client *client) -{ - return dynamic_cast(client) != nullptr; -} - -CopilotClient *asCoPilotClient(Client *client) -{ - return static_cast(client); -} - -Internal::CopilotClient *findClient() -{ - CopilotClient *client = Internal::CopilotClient::instance(); - return client && client->reachable() ? client : nullptr; -} - AuthWidget::AuthWidget(QWidget *parent) : QWidget(parent) { @@ -56,22 +40,12 @@ AuthWidget::AuthWidget(QWidget *parent) }.attachTo(this); // clang-format on - connect(LanguageClientManager::instance(), - &LanguageClientManager::clientAdded, - this, - &AuthWidget::onClientAdded); - connect(m_button, &QPushButton::clicked, this, [this]() { if (m_status == Status::SignedIn) signOut(); else if (m_status == Status::SignedOut) signIn(); }); - - CopilotClient *client = findClient(); - - if (client) - checkStatus(client); } void AuthWidget::setState(const QString &buttonText, bool working) @@ -83,25 +57,13 @@ void AuthWidget::setState(const QString &buttonText, bool working) m_button->setEnabled(!working); } -void AuthWidget::onClientAdded(Client *client) +void AuthWidget::checkStatus() { - if (isCopilotClient(client)) { - auto coPilotClient = asCoPilotClient(client); - if (coPilotClient->reachable()) { - checkStatus(coPilotClient); - } else { - connect(client, &Client::initialized, this, [this, coPilotClient] { - checkStatus(coPilotClient); - }); - } - } -} + QTC_ASSERT(m_client && m_client->reachable(), return); -void AuthWidget::checkStatus(CopilotClient *client) -{ setState("Checking status ...", true); - client->requestCheckStatus(false, [this](const CheckStatusRequest::Response &response) { + m_client->requestCheckStatus(false, [this](const CheckStatusRequest::Response &response) { if (response.error()) { setState("failed: " + response.error()->message(), false); return; @@ -119,15 +81,26 @@ void AuthWidget::checkStatus(CopilotClient *client) }); } +void AuthWidget::updateClient(const Utils::FilePath &nodeJs, const Utils::FilePath &agent) +{ + LanguageClientManager::shutdownClient(m_client); + m_client = nullptr; + setState(Tr::tr("Sign in"), true); + if (!nodeJs.exists() || !agent.exists()) + return; + + m_client = new CopilotClient(nodeJs, agent); + connect(m_client, &Client::initialized, this, &AuthWidget::checkStatus); +} + void AuthWidget::signIn() { qCritical() << "Not implemented"; - auto client = findClient(); - QTC_ASSERT(client, return); + QTC_ASSERT(m_client && m_client->reachable(), return); setState("Signing in ...", true); - client->requestSignInInitiate([this, client](const SignInInitiateRequest::Response &response) { + m_client->requestSignInInitiate([this](const SignInInitiateRequest::Response &response) { QTC_ASSERT(!response.error(), return); Utils::setClipboardAndSelection(response.result()->userCode()); @@ -139,37 +112,37 @@ void AuthWidget::signIn() .arg(response.result()->userCode())); m_statusLabel->setVisible(true); - client->requestSignInConfirm(response.result()->userCode(), - [this](const SignInConfirmRequest::Response &response) { - m_statusLabel->setText(""); + m_client + ->requestSignInConfirm(response.result()->userCode(), + [this](const SignInConfirmRequest::Response &response) { + m_statusLabel->setText(""); - if (response.error()) { - QMessageBox::critical(this, - Tr::tr("Login failed"), - Tr::tr( - "The login request failed: ") - + response.error()->message()); - setState("Sign in", false); - return; - } + if (response.error()) { + QMessageBox::critical(this, + Tr::tr("Login failed"), + Tr::tr( + "The login request failed: ") + + response.error()->message()); + setState("Sign in", false); + return; + } - setState("Sign Out " + response.result()->user(), false); - }); + setState("Sign Out " + response.result()->user(), false); + }); }); } void AuthWidget::signOut() { - auto client = findClient(); - QTC_ASSERT(client, return); + QTC_ASSERT(m_client && m_client->reachable(), return); setState("Signing out ...", true); - client->requestSignOut([this, client](const SignOutRequest::Response &response) { + m_client->requestSignOut([this](const SignOutRequest::Response &response) { QTC_ASSERT(!response.error(), return); QTC_ASSERT(response.result()->status() == "NotSignedIn", return); - checkStatus(client); + checkStatus(); }); } diff --git a/src/plugins/copilot/authwidget.h b/src/plugins/copilot/authwidget.h index 9d0f8fdbbcf..0d5406591e0 100644 --- a/src/plugins/copilot/authwidget.h +++ b/src/plugins/copilot/authwidget.h @@ -25,11 +25,12 @@ class AuthWidget : public QWidget public: explicit AuthWidget(QWidget *parent = nullptr); + void updateClient(const Utils::FilePath &nodeJs, const Utils::FilePath &agent); private: - void onClientAdded(LanguageClient::Client *client); void setState(const QString &buttonText, bool working); - void checkStatus(Internal::CopilotClient *client); + void checkStatus(); + void signIn(); void signOut(); @@ -39,6 +40,7 @@ private: QPushButton *m_button = nullptr; QLabel *m_statusLabel = nullptr; Utils::ProgressIndicator *m_progressIndicator = nullptr; + Internal::CopilotClient *m_client = nullptr; }; } // namespace Copilot diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index b74597dcec6..feb807d7f1e 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -54,6 +54,24 @@ file from the Copilot neovim plugin. st }.attachTo(this); // clang-format on + + auto updateAuthWidget = [authWidget]() { + authWidget->updateClient( + FilePath::fromUserInput( + CopilotSettings::instance().nodeJsPath.volatileValue().toString()), + FilePath::fromUserInput( + CopilotSettings::instance().distPath.volatileValue().toString())); + }; + + connect(CopilotSettings::instance().nodeJsPath.pathChooser(), + &PathChooser::textChanged, + authWidget, + updateAuthWidget); + connect(CopilotSettings::instance().distPath.pathChooser(), + &PathChooser::textChanged, + authWidget, + updateAuthWidget); + updateAuthWidget(); } }; From 7c8bb03cf665c0340730327ae88ae7b92af6f9fb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 12 Mar 2023 18:37:14 +0100 Subject: [PATCH 0244/1447] ActionsFilter: Use QtConcurrent instead of Utils::map() Change-Id: If29822c25f50d88ba5e4c29c2978c7e7f78e18d9 Reviewed-by: David Schulz Reviewed-by: --- src/plugins/coreplugin/actionsfilter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index 927e7da6331..00c1be83e52 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -21,6 +20,7 @@ #include #include #include +#include #include static const char lastTriggeredC[] = "LastTriggeredActions"; @@ -155,8 +155,8 @@ QList ActionsFilter::matchesFor(QFutureInterface> filtered; - const QList> filterResults = Utils::map(std::as_const(m_entries), filter) - .results(); + const QList> filterResults + = QtConcurrent::blockingMapped(m_entries, filter); for (const std::optional &filterResult : filterResults) { if (filterResult) filtered[filterResult->first] << filterResult->second; From 8d5e08c58c93ad5c7d6a1bd043e7c753c653fa1d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 13 Mar 2023 10:50:43 +0100 Subject: [PATCH 0245/1447] CppEditor: Compile fix Change-Id: I71838715834072a368115423cb5460c5120300e3 Reviewed-by: Christian Stenger --- src/plugins/cppeditor/builtineditordocumentparser.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/cppeditor/builtineditordocumentparser.cpp b/src/plugins/cppeditor/builtineditordocumentparser.cpp index efa97cf935c..ca7b83960dd 100644 --- a/src/plugins/cppeditor/builtineditordocumentparser.cpp +++ b/src/plugins/cppeditor/builtineditordocumentparser.cpp @@ -11,6 +11,8 @@ #include #include +#include + using namespace CPlusPlus; using namespace Utils; From 81dcfd907b961f4f3aab438d648a3fc3a50fc4ee Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 7 Mar 2023 10:04:14 +0100 Subject: [PATCH 0246/1447] CPlusPlus: Add parser support for generic lambdas Change-Id: Id17975a4296925c10b1b43f963412eea61ccfa5d Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.cpp | 24 +++++++++++++++++ src/libs/3rdparty/cplusplus/AST.h | 4 +++ src/libs/3rdparty/cplusplus/ASTClone.cpp | 10 ++++++++ src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 20 +++++++++++++++ src/libs/3rdparty/cplusplus/ASTVisit.cpp | 4 +++ src/libs/3rdparty/cplusplus/Parser.cpp | 30 ++++++++++++++++++++-- tests/auto/cplusplus/cxx11/tst_cxx11.cpp | 29 +++++++++++++++++++++ 7 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 53c84a95c68..5c59bb683ca 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -1659,12 +1659,18 @@ int LambdaDeclaratorAST::firstToken() const if (trailing_return_type) if (int candidate = trailing_return_type->firstToken()) return candidate; + if (requiresClause) + if (int candidate = requiresClause->firstToken()) + return candidate; return 0; } /** \generated */ int LambdaDeclaratorAST::lastToken() const { + if (requiresClause) + if (int candidate = requiresClause->firstToken()) + return candidate; if (trailing_return_type) if (int candidate = trailing_return_type->lastToken()) return candidate; @@ -1692,6 +1698,15 @@ int LambdaExpressionAST::firstToken() const if (lambda_introducer) if (int candidate = lambda_introducer->firstToken()) return candidate; + if (templateParameters) + if (int candidate = templateParameters->firstToken()) + return candidate; + if (requiresClause) + if (int candidate = requiresClause->firstToken()) + return candidate; + if (attributes) + if (int candidate = attributes->firstToken()) + return candidate; if (lambda_declarator) if (int candidate = lambda_declarator->firstToken()) return candidate; @@ -1710,6 +1725,15 @@ int LambdaExpressionAST::lastToken() const if (lambda_declarator) if (int candidate = lambda_declarator->lastToken()) return candidate; + if (attributes) + if (int candidate = attributes->firstToken()) + return candidate; + if (requiresClause) + if (int candidate = requiresClause->firstToken()) + return candidate; + if (templateParameters) + if (int candidate = templateParameters->firstToken()) + return candidate; if (lambda_introducer) if (int candidate = lambda_introducer->lastToken()) return candidate; diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 0d7e337fd8b..0f40424464e 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -3678,6 +3678,9 @@ class LambdaExpressionAST: public ExpressionAST { public: LambdaIntroducerAST *lambda_introducer = nullptr; + DeclarationListAST *templateParameters = nullptr; + RequiresClauseAST *requiresClause = nullptr; + SpecifierListAST *attributes = nullptr; LambdaDeclaratorAST *lambda_declarator = nullptr; StatementAST *statement = nullptr; @@ -3758,6 +3761,7 @@ public: int mutable_token = 0; ExceptionSpecificationAST *exception_specification = nullptr; TrailingReturnTypeAST *trailing_return_type = nullptr; + RequiresClauseAST *requiresClause = nullptr; public: // annotations Function *symbol = nullptr; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index e1e014afccf..e494ad71ac6 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -1816,6 +1816,14 @@ LambdaExpressionAST *LambdaExpressionAST::clone(MemoryPool *pool) const LambdaExpressionAST *ast = new (pool) LambdaExpressionAST; if (lambda_introducer) ast->lambda_introducer = lambda_introducer->clone(pool); + for (DeclarationListAST *iter = templateParameters, **ast_iter = &ast->templateParameters; + iter; iter = iter->next, ast_iter = &(*ast_iter)->next) + *ast_iter = new (pool) DeclarationListAST((iter->value) ? iter->value->clone(pool) : nullptr); + if (requiresClause) + ast->requiresClause = requiresClause->clone(pool); + for (SpecifierListAST *iter = attributes, **ast_iter = &ast->attributes; + iter; iter = iter->next, ast_iter = &(*ast_iter)->next) + *ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); if (lambda_declarator) ast->lambda_declarator = lambda_declarator->clone(pool); if (statement) @@ -1867,6 +1875,8 @@ LambdaDeclaratorAST *LambdaDeclaratorAST::clone(MemoryPool *pool) const ast->exception_specification = exception_specification->clone(pool); if (trailing_return_type) ast->trailing_return_type = trailing_return_type->clone(pool); + if (requiresClause) + ast->requiresClause = requiresClause->clone(pool); return ast; } diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index 4567cd68a25..de6f6fc87c0 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -3056,6 +3056,21 @@ bool ASTMatcher::match(LambdaExpressionAST *node, LambdaExpressionAST *pattern) else if (! AST::match(node->lambda_introducer, pattern->lambda_introducer, this)) return false; + if (! pattern->templateParameters) + pattern->templateParameters = node->templateParameters; + else if (! AST::match(node->templateParameters, pattern->templateParameters, this)) + return false; + + if (! pattern->requiresClause) + pattern->requiresClause = node->requiresClause; + else if (! AST::match(node->requiresClause, pattern->requiresClause, this)) + return false; + + if (! pattern->attributes) + pattern->attributes = node->attributes; + else if (! AST::match(node->attributes, pattern->attributes, this)) + return false; + if (! pattern->lambda_declarator) pattern->lambda_declarator = node->lambda_declarator; else if (! AST::match(node->lambda_declarator, pattern->lambda_declarator, this)) @@ -3147,6 +3162,11 @@ bool ASTMatcher::match(LambdaDeclaratorAST *node, LambdaDeclaratorAST *pattern) else if (! AST::match(node->trailing_return_type, pattern->trailing_return_type, this)) return false; + if (! pattern->requiresClause) + pattern->requiresClause = node->requiresClause; + else if (! AST::match(node->requiresClause, pattern->requiresClause, this)) + return false; + return true; } diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index d83684b966d..17941d8122f 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -1317,6 +1317,9 @@ void LambdaExpressionAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { accept(lambda_introducer, visitor); + accept(templateParameters, visitor); + accept(requiresClause, visitor); + accept(attributes, visitor); accept(lambda_declarator, visitor); accept(statement, visitor); } @@ -1354,6 +1357,7 @@ void LambdaDeclaratorAST::accept0(ASTVisitor *visitor) accept(attributes, visitor); accept(exception_specification, visitor); accept(trailing_return_type, visitor); + accept(requiresClause, visitor); } visitor->endVisit(this); } diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 45c2493fff4..f8c737c0978 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -1417,8 +1417,22 @@ bool Parser::parseRequiresClauseOpt(RequiresClauseAST *&node) return true; const auto ast = new (_pool) RequiresClauseAST; ast->requires_token = consumeToken(); - if (!parseLogicalOrExpression(ast->constraint)) + if (!parsePrimaryExpression(ast->constraint)) return false; + while (true) { + if (LA() != T_PIPE_PIPE && LA() != T_AMPER_AMPER) + break; + ExpressionAST *next = nullptr; + if (!parsePrimaryExpression(next)) + return false; + + // This won't yield the right precedence, but I don't care. + BinaryExpressionAST *expr = new (_pool) BinaryExpressionAST; + expr->left_expression = ast->constraint; + expr->binary_op_token = consumeToken(); + expr->right_expression = next; + ast->constraint = expr; + } node = ast; return true; } @@ -6999,6 +7013,15 @@ bool Parser::parseLambdaExpression(ExpressionAST *&node) if (parseLambdaIntroducer(lambda_introducer)) { LambdaExpressionAST *ast = new (_pool) LambdaExpressionAST; ast->lambda_introducer = lambda_introducer; + if (_languageFeatures.cxx20Enabled && LA() == T_LESS) { + consumeToken(); + parseTemplateParameterList(ast->templateParameters); + if (LA() != T_GREATER) + return false; + consumeToken(); + parseRequiresClauseOpt(ast->requiresClause); + } + parseOptionalAttributeSpecifierSequence(ast->attributes); parseLambdaDeclarator(ast->lambda_declarator); parseCompoundStatement(ast->statement); node = ast; @@ -7023,7 +7046,9 @@ bool Parser::parseLambdaIntroducer(LambdaIntroducerAST *&node) if (LA() == T_RBRACKET) { ast->rbracket_token = consumeToken(); - if (LA() == T_LPAREN || LA() == T_LBRACE) { + // FIXME: Attributes are also allowed ... + if (LA() == T_LPAREN || LA() == T_LBRACE + || (_languageFeatures.cxx20Enabled && LA() == T_LESS)) { node = ast; return true; } @@ -7139,6 +7164,7 @@ bool Parser::parseLambdaDeclarator(LambdaDeclaratorAST *&node) parseExceptionSpecification(ast->exception_specification); parseTrailingReturnType(ast->trailing_return_type); + parseRequiresClauseOpt(ast->requiresClause); node = ast; return true; diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index 4bb4e4b4b24..958aa631c68 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -149,6 +149,7 @@ private Q_SLOTS: void concepts(); void requiresClause(); void coroutines(); + void genericLambdas(); }; @@ -521,5 +522,33 @@ int main() QVERIFY(!hasErrors); } +void tst_cxx11::genericLambdas() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx20Enabled = true; + + const QString source = R"( +template concept C1 = true; +template concept C2 = true; +template concept C3 = true; +int main() +{ + auto f = [](T a, auto&& b) { return a < b; }; + auto g = [](Ts&&... ts) { return foo(std::forward(ts)...); }; + auto h = [] requires C2 + (T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3 { + }; +} +)"; + QByteArray errors; + Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile")); + processDocument(doc, source.toUtf8(), features, &errors); + const bool hasErrors = !errors.isEmpty(); + if (hasErrors) + qDebug().noquote() << errors; + QVERIFY(!hasErrors); +} + QTEST_APPLESS_MAIN(tst_cxx11) #include "tst_cxx11.moc" From 0c4dff7c10962ed438bc27c73942b2d1a81cb3fb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 13 Mar 2023 10:43:54 +0100 Subject: [PATCH 0247/1447] FileListIterator: Minor fixes Add a reference to c'tor's encodings arg. Make c'tor's args default. Make m_items field const. Change-Id: I74bb1829f3ba0ea8a61106bddadeb935b6405f77 Reviewed-by: Eike Ziller --- src/libs/utils/filesearch.cpp | 19 ++++++++++--------- src/libs/utils/filesearch.h | 7 ++++--- .../projectexplorer/currentprojectfind.cpp | 5 ++--- tests/auto/filesearch/tst_filesearch.cpp | 6 ++---- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index d0fa1c71c3a..02f6409de08 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -598,19 +598,20 @@ FileIterator::const_iterator FileIterator::end() const // #pragma mark -- FileListIterator -QTextCodec *encodingAt(const QList &encodings, int index) +QList constructItems(const FilePaths &fileList, + const QList &encodings) { - if (index >= 0 && index < encodings.size()) - return encodings.at(index); - return QTextCodec::codecForLocale(); + QList items; + items.reserve(fileList.size()); + QTextCodec *defaultEncoding = QTextCodec::codecForLocale(); + for (int i = 0; i < fileList.size(); ++i) + items.append(FileIterator::Item(fileList.at(i), encodings.value(i, defaultEncoding))); + return items; } -FileListIterator::FileListIterator(const FilePaths &fileList, const QList encodings) - : m_maxIndex(-1) +FileListIterator::FileListIterator(const FilePaths &fileList, const QList &encodings) + : m_items(constructItems(fileList, encodings)) { - m_items.reserve(fileList.size()); - for (int i = 0; i < fileList.size(); ++i) - m_items.append(Item(fileList.at(i), encodingAt(encodings, i))); } void FileListIterator::update(int requestedIndex) diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index 9d427f5946e..ecb6c574af0 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -107,7 +107,8 @@ protected: class QTCREATOR_UTILS_EXPORT FileListIterator : public FileIterator { public: - explicit FileListIterator(const FilePaths &fileList, const QList encodings); + explicit FileListIterator(const FilePaths &fileList = {}, + const QList &encodings = {}); int maxProgress() const override; int currentProgress() const override; @@ -118,8 +119,8 @@ protected: const Item &itemAt(int index) const override; private: - QVector m_items; - int m_maxIndex; + const QList m_items; + int m_maxIndex = -1; }; class QTCREATOR_UTILS_EXPORT SubDirFileIterator : public FileIterator diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index fb9b8f44d66..3bde2bb62f2 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -61,14 +61,13 @@ FileIterator *CurrentProjectFind::files(const QStringList &nameFilters, const QStringList &exclusionFilters, const QVariant &additionalParameters) const { - QTC_ASSERT(additionalParameters.isValid(), - return new FileListIterator(FilePaths(), QList())); + QTC_ASSERT(additionalParameters.isValid(), return new FileListIterator); const FilePath projectFile = FilePath::fromVariant(additionalParameters); for (Project *project : ProjectManager::projects()) { if (project && projectFile == project->projectFilePath()) return filesForProjects(nameFilters, exclusionFilters, {project}); } - return new FileListIterator(FilePaths(), QList()); + return new FileListIterator; } QString CurrentProjectFind::label() const diff --git a/tests/auto/filesearch/tst_filesearch.cpp b/tests/auto/filesearch/tst_filesearch.cpp index d900175bf9d..2532f7a313a 100644 --- a/tests/auto/filesearch/tst_filesearch.cpp +++ b/tests/auto/filesearch/tst_filesearch.cpp @@ -31,10 +31,8 @@ namespace { const QString &term, QTextDocument::FindFlags flags, tst_FileSearch::RegExpFlag regexp = tst_FileSearch::NoRegExp) { - Utils::FileIterator *it = new Utils::FileListIterator(FilePaths{FilePath::fromString( - FILENAME)}, - QList() - << QTextCodec::codecForLocale()); + Utils::FileIterator *it = new Utils::FileListIterator({FilePath::fromString(FILENAME)}, + {QTextCodec::codecForLocale()}); QFutureWatcher watcher; QSignalSpy ready(&watcher, &QFutureWatcherBase::resultsReadyAt); if (regexp == tst_FileSearch::NoRegExp) From a98c45f9ba75a4d9ed0a94d0d2619e511c9c312a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 9 Mar 2023 15:22:24 +0100 Subject: [PATCH 0248/1447] Examples/Marketplace: Move ownership to the "all" products model To allow the same item to appear in multiple categories. Change-Id: Ib957b1fb0d98a28ceeb1d80e9fb497cc2a6b1f48 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/coreplugin/welcomepagehelper.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 0c46ea98f30..d5f09a8c5c6 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -637,8 +637,6 @@ SectionedGridView::SectionedGridView(QWidget *parent) { auto allItemsModel = new ListModel(this); allItemsModel->setPixmapFunction(m_pixmapFunction); - // it just "borrows" the items from the section models: - allItemsModel->setOwnsItems(false); m_filteredAllItemsModel = new Core::ListModelFilter(allItemsModel, this); auto area = new QScrollArea(this); @@ -690,6 +688,10 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetPixmapFunction(m_pixmapFunction); + // the sections only keep a weak reference to the items, + // they are owned by the allProducts model, since multiple sections can contain duplicates + // of the same item + model->setOwnsItems(false); model->appendItems(items); auto gridView = new SectionGridView(this); @@ -716,7 +718,11 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList(m_filteredAllItemsModel->sourceModel()); - allProducts->appendItems(items); + const QSet allItems = toSet(allProducts->items()); + const QList newItems = filtered(items, [&allItems](ListItem *item) { + return !allItems.contains(item); + }); + allProducts->appendItems(newItems); // only show section label(s) if there is more than one section m_sectionLabels.at(0)->setVisible(m_sectionLabels.size() > 1); From 4b30ac4e9ef773074e55082213b10d2f1a095fb8 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 10 Mar 2023 14:37:33 +0100 Subject: [PATCH 0249/1447] Terminal: Fix access violation Change-Id: I271f4bac05b64d3f4160b2f8ed5ff30cbc3e259d Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/glyphcache.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/glyphcache.cpp b/src/plugins/terminal/glyphcache.cpp index 21c4b0d8090..72a0fd7b9d1 100644 --- a/src/plugins/terminal/glyphcache.cpp +++ b/src/plugins/terminal/glyphcache.cpp @@ -34,9 +34,13 @@ const QGlyphRun *GlyphCache::get(const QFont &font, const QString &text) layout.endLayout(); if (layout.lineCount() > 0) { - QGlyphRun *run = new QGlyphRun(layout.lineAt(0).glyphRuns().first()); - insert(key, run); - return run; + const auto &line = layout.lineAt(0); + const auto runs = line.glyphRuns(); + if (!runs.isEmpty()) { + QGlyphRun *run = new QGlyphRun(layout.lineAt(0).glyphRuns().first()); + insert(key, run); + return run; + } } return nullptr; } From f1d50c0d550fa5d8701d165b005ffce8cb59df44 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 15:42:05 +0100 Subject: [PATCH 0250/1447] ProgressManager: Add a addTimedTask() that accepts QFuture That's more convenient when QFutureInterface isn't accessible. Change-Id: I30af82a4e731dc577d36b62d4e11c5b65852fd4f Reviewed-by: Eike Ziller Reviewed-by: --- .../progressmanager/progressmanager.cpp | 27 +++++++++++++++++++ .../progressmanager/progressmanager.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.cpp b/src/plugins/coreplugin/progressmanager/progressmanager.cpp index efc97312217..18cc2f6f34f 100644 --- a/src/plugins/coreplugin/progressmanager/progressmanager.cpp +++ b/src/plugins/coreplugin/progressmanager/progressmanager.cpp @@ -740,6 +740,33 @@ FutureProgress *ProgressManager::addTimedTask(const QFutureInterface &futu return fp; } +FutureProgress *ProgressManager::addTimedTask(const QFuture &future, const QString &title, + Id type, int expectedSeconds, ProgressFlags flags) +{ + QFutureInterface dummyFutureInterface; + QFuture dummyFuture = dummyFutureInterface.future(); + FutureProgress *fp = m_instance->doAddTask(dummyFuture, title, type, flags); + (void) new ProgressTimer(dummyFutureInterface, expectedSeconds, fp); + + QFutureWatcher *dummyWatcher = new QFutureWatcher(fp); + connect(dummyWatcher, &QFutureWatcher::canceled, dummyWatcher, [future] { + QFuture mutableFuture = future; + mutableFuture.cancel(); + }); + dummyWatcher->setFuture(dummyFuture); + + QFutureWatcher *origWatcher = new QFutureWatcher(fp); + connect(origWatcher, &QFutureWatcher::finished, origWatcher, [future, dummyFutureInterface] { + QFutureInterface mutableDummyFutureInterface = dummyFutureInterface; + if (future.isCanceled()) + mutableDummyFutureInterface.reportCanceled(); + mutableDummyFutureInterface.reportFinished(); + }); + origWatcher->setFuture(future); + + return fp; +} + /*! Shows the given \a text in a platform dependent way in the application icon in the system's task bar or dock. This is used to show the number diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.h b/src/plugins/coreplugin/progressmanager/progressmanager.h index 78c1b771aea..8c51bf4ccd4 100644 --- a/src/plugins/coreplugin/progressmanager/progressmanager.h +++ b/src/plugins/coreplugin/progressmanager/progressmanager.h @@ -40,6 +40,8 @@ public: Utils::Id type, ProgressFlags flags = {}); static FutureProgress *addTimedTask(const QFutureInterface &fi, const QString &title, Utils::Id type, int expectedSeconds, ProgressFlags flags = {}); + static FutureProgress *addTimedTask(const QFuture &future, const QString &title, + Utils::Id type, int expectedSeconds, ProgressFlags flags = {}); static void setApplicationLabel(const QString &text); public slots: From 9f1afb0318a0cdf63603dcb9bfcf3685a34a7ed6 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sun, 12 Mar 2023 20:26:25 +0100 Subject: [PATCH 0251/1447] Utils: Add stringutils splitAtFirst Change-Id: I221d6c6086f53ec5f94c1157ea533d862db38d52 Reviewed-by: hjk --- src/libs/utils/stringutils.cpp | 19 +++++++++++ src/libs/utils/stringutils.h | 4 +++ .../utils/stringutils/tst_stringutils.cpp | 34 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index 3a1afe1fa18..7315a69da2a 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -527,4 +527,23 @@ QTCREATOR_UTILS_EXPORT FilePath appendHelper(const FilePath &base, int n) return base.stringAppended(QString::number(n)); } +QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QStringView &stringView, + QChar ch) +{ + int splitIdx = stringView.indexOf(ch); + if (splitIdx == -1) + return {stringView, {}}; + + QStringView left = stringView.mid(0, splitIdx); + QStringView right = stringView.mid(splitIdx + 1); + + return {left, right}; +} + +QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QString &string, QChar ch) +{ + QStringView view = string; + return splitAtFirst(view, ch); +} + } // namespace Utils diff --git a/src/libs/utils/stringutils.h b/src/libs/utils/stringutils.h index 5cf2978c07b..865a1dea122 100644 --- a/src/libs/utils/stringutils.h +++ b/src/libs/utils/stringutils.h @@ -115,4 +115,8 @@ QTCREATOR_UTILS_EXPORT QString trimFront(const QString &string, QChar ch); QTCREATOR_UTILS_EXPORT QString trimBack(const QString &string, QChar ch); QTCREATOR_UTILS_EXPORT QString trim(const QString &string, QChar ch); +QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QString &string, QChar ch); +QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QStringView &stringView, + QChar ch); + } // namespace Utils diff --git a/tests/auto/utils/stringutils/tst_stringutils.cpp b/tests/auto/utils/stringutils/tst_stringutils.cpp index e13e8411a5b..4863bfd9508 100644 --- a/tests/auto/utils/stringutils/tst_stringutils.cpp +++ b/tests/auto/utils/stringutils/tst_stringutils.cpp @@ -79,6 +79,8 @@ private slots: void testTrim(); void testWildcardToRegularExpression_data(); void testWildcardToRegularExpression(); + void testSplitAtFirst_data(); + void testSplitAtFirst(); private: TestMacroExpander mx; @@ -404,6 +406,38 @@ void tst_StringUtils::testWildcardToRegularExpression() QCOMPARE(string.contains(re), matches); } +void tst_StringUtils::testSplitAtFirst_data() +{ + QTest::addColumn("string"); + QTest::addColumn("separator"); + QTest::addColumn("left"); + QTest::addColumn("right"); + + QTest::newRow("Empty") << QString{} << QChar{} << QString{} << QString{}; + QTest::newRow("EmptyString") << QString{} << QChar{'a'} << QString{} << QString{}; + QTest::newRow("EmptySeparator") << QString{"abc"} << QChar{} << QString{"abc"} << QString{}; + QTest::newRow("NoSeparator") << QString{"abc"} << QChar{'d'} << QString{"abc"} << QString{}; + QTest::newRow("SeparatorAtStart") << QString{"abc"} << QChar{'a'} << QString{} << QString{"bc"}; + QTest::newRow("SeparatorAtEnd") << QString{"abc"} << QChar{'c'} << QString{"ab"} << QString{}; + QTest::newRow("SeparatorInMiddle") + << QString{"abc"} << QChar{'b'} << QString{"a"} << QString{"c"}; + QTest::newRow("SeparatorAtStartAndEnd") + << QString{"abca"} << QChar{'a'} << QString{} << QString{"bca"}; +} + +void tst_StringUtils::testSplitAtFirst() +{ + QFETCH(QString, string); + QFETCH(QChar, separator); + QFETCH(QString, left); + QFETCH(QString, right); + + const auto [l, r] = Utils::splitAtFirst(string, separator); + + QCOMPARE(l, left); + QCOMPARE(r, right); +} + QTEST_GUILESS_MAIN(tst_StringUtils) #include "tst_stringutils.moc" From 72e2df0c9512e95dc1fb4659fa204f88850f9f6a Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 13 Mar 2023 10:41:29 +0100 Subject: [PATCH 0252/1447] Qnx: Remove QnxProcessImpl The LinuxProcessImpl works better. Specifically the QnxProcessImpl process exit code would always return 0. Change-Id: I939d486e1cf7a1bdbb61a120a303d79e7cbce8e6 Reviewed-by: hjk --- src/plugins/qnx/qnxdevice.cpp | 62 ----------------------------------- src/plugins/qnx/qnxdevice.h | 1 - 2 files changed, 63 deletions(-) diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index f1770a55222..410d0397516 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -11,8 +11,6 @@ #include "qnxdevicewizard.h" #include "qnxtr.h" -#include - #include #include #include @@ -25,61 +23,6 @@ using namespace Utils; namespace Qnx::Internal { -class QnxProcessImpl final : public SshProcessInterface -{ -public: - QnxProcessImpl(const LinuxDevice *linuxDevice); - ~QnxProcessImpl() { killIfRunning(); } - -private: - QString fullCommandLine(const CommandLine &commandLine) const final; - void handleSendControlSignal(Utils::ControlSignal controlSignal) final; - - const QString m_pidFile; -}; - -static std::atomic_int s_pidFileCounter = 1; - -QnxProcessImpl::QnxProcessImpl(const LinuxDevice *linuxDevice) - : SshProcessInterface(linuxDevice) - , m_pidFile(QString("%1/qtc.%2.pid").arg(Constants::QNX_TMP_DIR).arg(s_pidFileCounter.fetch_add(1))) -{ -} - -QString QnxProcessImpl::fullCommandLine(const CommandLine &commandLine) const -{ - QStringList args = ProcessArgs::splitArgs(commandLine.arguments(), HostOsInfo::hostOs()); - args.prepend(commandLine.executable().toString()); - const QString cmd = ProcessArgs::createUnixArgs(args).toString(); - - QString fullCommandLine = - "test -f /etc/profile && . /etc/profile ; " - "test -f $HOME/profile && . $HOME/profile ; "; - - if (!m_setup.m_workingDirectory.isEmpty()) - fullCommandLine += QString::fromLatin1("cd %1 ; ").arg( - ProcessArgs::quoteArg(m_setup.m_workingDirectory.toString())); - - const Environment env = m_setup.m_environment; - env.forEachEntry([&](const QString &key, const QString &value, bool) { - fullCommandLine += QString("%1='%2' ").arg(key).arg(env.expandVariables(value)); - }); - - fullCommandLine += QString::fromLatin1("%1 & echo $! > %2").arg(cmd).arg(m_pidFile); - - return fullCommandLine; -} - -void QnxProcessImpl::handleSendControlSignal(Utils::ControlSignal controlSignal) -{ - QTC_ASSERT(controlSignal != ControlSignal::KickOff, return); - const QString args = QString::fromLatin1("-%1 `cat %2`") - .arg(controlSignalToInt(controlSignal)).arg(m_pidFile); - CommandLine command = { "kill", args, CommandLine::Raw }; - // Note: This blocking call takes up to 2 ms for local remote. - runInShell(command); -} - const char QnxVersionKey[] = "QnxVersion"; QnxDevice::QnxDevice() @@ -158,11 +101,6 @@ DeviceTester *QnxDevice::createDeviceTester() const return new QnxDeviceTester; } -Utils::ProcessInterface *QnxDevice::createProcessInterface() const -{ - return new QnxProcessImpl(this); -} - DeviceProcessSignalOperation::Ptr QnxDevice::signalOperation() const { return DeviceProcessSignalOperation::Ptr(new QnxDeviceProcessSignalOperation(sharedFromThis())); diff --git a/src/plugins/qnx/qnxdevice.h b/src/plugins/qnx/qnxdevice.h index f4efa3e1f25..0ee38912f37 100644 --- a/src/plugins/qnx/qnxdevice.h +++ b/src/plugins/qnx/qnxdevice.h @@ -20,7 +20,6 @@ public: ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; ProjectExplorer::DeviceTester *createDeviceTester() const override; - Utils::ProcessInterface *createProcessInterface() const override; int qnxVersion() const; From 4f8ad43c1e2b5b33b6323f618bb718c926e8e0aa Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 13 Mar 2023 15:03:33 +0100 Subject: [PATCH 0253/1447] Qnx: Merge qnxdeviceprocesssignaloperation.{h,cpp} into qnxdevice.cpp Not worth a file pair anymore. Change-Id: I86afff84586592dd05d40e573e6b9a95c54913fe Reviewed-by: Marcus Tillmanns --- src/plugins/qnx/CMakeLists.txt | 1 - src/plugins/qnx/qnx.qbs | 2 -- src/plugins/qnx/qnxdevice.cpp | 32 ++++++++++++++++- .../qnx/qnxdeviceprocesssignaloperation.cpp | 36 ------------------- .../qnx/qnxdeviceprocesssignaloperation.h | 22 ------------ 5 files changed, 31 insertions(+), 62 deletions(-) delete mode 100644 src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp delete mode 100644 src/plugins/qnx/qnxdeviceprocesssignaloperation.h diff --git a/src/plugins/qnx/CMakeLists.txt b/src/plugins/qnx/CMakeLists.txt index 66dd7058770..2c0e77cee8c 100644 --- a/src/plugins/qnx/CMakeLists.txt +++ b/src/plugins/qnx/CMakeLists.txt @@ -11,7 +11,6 @@ add_qtc_plugin(Qnx qnxdeployqtlibrariesdialog.cpp qnxdeployqtlibrariesdialog.h qnxdevice.cpp qnxdevice.h qnxdeviceprocesslist.cpp qnxdeviceprocesslist.h - qnxdeviceprocesssignaloperation.cpp qnxdeviceprocesssignaloperation.h qnxdevicetester.cpp qnxdevicetester.h qnxdevicewizard.cpp qnxdevicewizard.h qnxplugin.cpp diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index 0389f542a65..b9e19ead0b1 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -32,8 +32,6 @@ QtcPlugin { "qnxdevicewizard.h", "qnxdeviceprocesslist.cpp", "qnxdeviceprocesslist.h", - "qnxdeviceprocesssignaloperation.cpp", - "qnxdeviceprocesssignaloperation.h", "qnxdevicetester.cpp", "qnxdevicetester.h", "qnxconfigurationmanager.cpp", diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 410d0397516..958f09a59e5 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -7,10 +7,11 @@ #include "qnxdeployqtlibrariesdialog.h" #include "qnxdevicetester.h" #include "qnxdeviceprocesslist.h" -#include "qnxdeviceprocesssignaloperation.h" #include "qnxdevicewizard.h" #include "qnxtr.h" +#include + #include #include #include @@ -25,6 +26,35 @@ namespace Qnx::Internal { const char QnxVersionKey[] = "QnxVersion"; +static QString signalProcessByNameQnxCommandLine(const QString &filePath, int sig) +{ + QString executable = filePath; + return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); " + "do " + "kill -%2 $PID; " + "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig); +} + +class QnxDeviceProcessSignalOperation : public RemoteLinuxSignalOperation +{ +public: + explicit QnxDeviceProcessSignalOperation(const IDeviceConstPtr &device) + : RemoteLinuxSignalOperation(device) + {} + + + QString killProcessByNameCommandLine(const QString &filePath) const override + { + return QString::fromLatin1("%1; %2").arg(signalProcessByNameQnxCommandLine(filePath, 15), + signalProcessByNameQnxCommandLine(filePath, 9)); + } + + QString interruptProcessByNameCommandLine(const QString &filePath) const override + { + return signalProcessByNameQnxCommandLine(filePath, 2); + } +}; + QnxDevice::QnxDevice() { setDisplayType(Tr::tr("QNX")); diff --git a/src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp b/src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp deleted file mode 100644 index 56df01d8a9e..00000000000 --- a/src/plugins/qnx/qnxdeviceprocesssignaloperation.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qnxdeviceprocesssignaloperation.h" - -namespace Qnx::Internal { - -QnxDeviceProcessSignalOperation::QnxDeviceProcessSignalOperation( - const ProjectExplorer::IDeviceConstPtr &device) - : RemoteLinux::RemoteLinuxSignalOperation(device) -{ -} - -static QString signalProcessByNameQnxCommandLine(const QString &filePath, int sig) -{ - QString executable = filePath; - return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); " - "do " - "kill -%2 $PID; " - "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig); -} - -QString QnxDeviceProcessSignalOperation::killProcessByNameCommandLine( - const QString &filePath) const -{ - return QString::fromLatin1("%1; %2").arg(signalProcessByNameQnxCommandLine(filePath, 15), - signalProcessByNameQnxCommandLine(filePath, 9)); -} - -QString QnxDeviceProcessSignalOperation::interruptProcessByNameCommandLine( - const QString &filePath) const -{ - return signalProcessByNameQnxCommandLine(filePath, 2); -} - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxdeviceprocesssignaloperation.h b/src/plugins/qnx/qnxdeviceprocesssignaloperation.h deleted file mode 100644 index 271aea6a4e0..00000000000 --- a/src/plugins/qnx/qnxdeviceprocesssignaloperation.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Qnx::Internal { - -class QnxDeviceProcessSignalOperation : public RemoteLinux::RemoteLinuxSignalOperation -{ -protected: - explicit QnxDeviceProcessSignalOperation(const ProjectExplorer::IDeviceConstPtr &device); - -private: - QString killProcessByNameCommandLine(const QString &filePath) const override; - QString interruptProcessByNameCommandLine(const QString &filePath) const override; - - friend class QnxDevice; -}; - -} // Qnx::Internal From cdfe9462af3b8fec912fe26ec9cc56d6f1e35768 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 7 Mar 2023 17:30:23 +0100 Subject: [PATCH 0254/1447] Debugger: Fix "Run in Terminal" with lldb Previously lldb never actually attached to the process running in the terminal, but started its own copy. Since the process is interrupted by the terminal stub already, code was added to automatically continue the process. "Start and break on main" and "Run in Terminal" also did not work together and are now fixed. Change-Id: Iaeb6e7dd0f511f3bf195ab5d0008856b310615d9 Reviewed-by: hjk Reviewed-by: --- share/qtcreator/debugger/lldbbridge.py | 9 +++++++++ share/qtcreator/debugger/utils.py | 1 + src/plugins/debugger/lldb/lldbengine.cpp | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 8a97e642970..bef97482af6 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -870,6 +870,7 @@ class Dumper(DumperBase): self.startMode_ = args.get('startmode', 1) self.breakOnMain_ = args.get('breakonmain', 0) self.useTerminal_ = args.get('useterminal', 0) + self.firstStop_ = True pargs = self.hexdecode(args.get('processargs', '')) self.processArgs_ = pargs.split('\0') if len(pargs) else [] self.environment_ = args.get('environment', []) @@ -930,6 +931,8 @@ class Dumper(DumperBase): if self.startMode_ == DebuggerStartMode.AttachExternal: attach_info = lldb.SBAttachInfo(self.attachPid_) + if self.breakOnMain_: + self.createBreakpointAtMain() self.process = self.target.Attach(attach_info, error) if not error.Success(): self.reportState('enginerunfailed') @@ -1474,6 +1477,12 @@ class Dumper(DumperBase): self.reportState("inferiorstopok") else: self.reportState("stopped") + if self.firstStop_: + self.firstStop_ = False + if self.useTerminal_: + # When using a terminal, the process will be interrupted on startup. + # We therefore need to continue it here. + self.process.Continue() else: self.reportState(self.stateName(state)) diff --git a/share/qtcreator/debugger/utils.py b/share/qtcreator/debugger/utils.py index fe2e558e711..8019d1e530a 100644 --- a/share/qtcreator/debugger/utils.py +++ b/share/qtcreator/debugger/utils.py @@ -4,6 +4,7 @@ # Debugger start modes. Keep in sync with DebuggerStartMode in debuggerconstants.h +# MT: Why does this not match (anymore?) to debuggerconstants.h : DebuggerStartMode ? class DebuggerStartMode(): ( NoStartMode, diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 020c9e7758b..5de46911576 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -279,8 +279,8 @@ void LldbEngine::handleLldbStarted() ? QString::fromLatin1("Attaching to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID) : QString::fromLatin1("Attaching to %1").arg(attachedPID); showMessage(msg, LogMisc); + cmd2.arg("startmode", DebuggerStartMode::AttachToLocalProcess); cmd2.arg("attachpid", attachedPID); - } else { cmd2.arg("startmode", rp.startMode); // it is better not to check the start mode on the python sid (as we would have to duplicate the From 5effb95ad964136871b78a644d0725cd7f739706 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 10 Mar 2023 19:50:37 +0100 Subject: [PATCH 0255/1447] ClangGlobalSymbolFilter: Don't remove duplicates prematurely That's being done later, inside Core::Internal::runSearch(). Change-Id: Ib131aefdb39dbe2dfd457020ff13f1c453814597 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- .../clangcodemodel/clangdlocatorfilters.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 84b0171cbe3..4da1ece4cc8 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -151,21 +151,7 @@ void ClangGlobalSymbolFilter::prepareSearch(const QString &entry) QList ClangGlobalSymbolFilter::matchesFor( QFutureInterface &future, const QString &entry) { - QList matches = m_cppFilter->matchesFor(future, entry); - const QList lspMatches = m_lspFilter->matchesFor(future, entry); - if (!lspMatches.isEmpty()) { - QSet locations; - for (const auto &entry : std::as_const(matches)) { - QTC_ASSERT(entry.linkForEditor, continue); - locations.insert(*entry.linkForEditor); - } - for (const auto &entry : lspMatches) { - QTC_ASSERT(entry.linkForEditor, continue); - if (!locations.contains(*entry.linkForEditor)) - matches << entry; // TODO: Insert sorted? - } - } - return matches; + return m_cppFilter->matchesFor(future, entry) + m_lspFilter->matchesFor(future, entry); } ClangClassesFilter::ClangClassesFilter() From 169b4110400e3b20fb2e87a5795d5b3964ff3887 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 14:06:33 +0100 Subject: [PATCH 0256/1447] CppElementEvaluator: Use QtConcurrent invocation for async run Change-Id: Idc67ecd4e9e95c5893a04ca1a9ee7b30662ec664 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/cplusplus/CppDocument.cpp | 10 +---- src/libs/cplusplus/CppDocument.h | 8 +--- src/libs/cplusplus/DependencyTable.cpp | 18 ++++---- src/libs/cplusplus/DependencyTable.h | 5 ++- src/plugins/cppeditor/cppelementevaluator.cpp | 43 ++++++++++--------- src/plugins/cppeditor/cppelementevaluator.h | 10 ++--- src/plugins/cppeditor/cpptypehierarchy.cpp | 3 +- .../cppeditor/typehierarchybuilder.cpp | 28 +++--------- src/plugins/cppeditor/typehierarchybuilder.h | 12 +++--- 9 files changed, 57 insertions(+), 80 deletions(-) diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 6e241fb29b0..42616498977 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -821,16 +821,10 @@ FilePaths Snapshot::filesDependingOn(const FilePath &filePath) const return m_deps.filesDependingOn(filePath); } -void Snapshot::updateDependencyTable() const -{ - QFutureInterfaceBase futureInterface; - updateDependencyTable(futureInterface); -} - -void Snapshot::updateDependencyTable(QFutureInterfaceBase &futureInterface) const +void Snapshot::updateDependencyTable(const std::optional> &future) const { if (m_deps.files.isEmpty()) - m_deps.build(futureInterface, *this); + m_deps.build(future, *this); } bool Snapshot::operator==(const Snapshot &other) const diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index cfbad3be1ea..679663f2d99 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -15,12 +15,9 @@ #include #include #include +#include #include -QT_BEGIN_NAMESPACE -class QFutureInterfaceBase; -QT_END_NAMESPACE - namespace CPlusPlus { class Macro; @@ -406,8 +403,7 @@ public: Utils::FilePaths filesDependingOn(const Utils::FilePath &filePath) const; - void updateDependencyTable() const; - void updateDependencyTable(QFutureInterfaceBase &futureInterface) const; + void updateDependencyTable(const std::optional> &future = {}) const; bool operator==(const Snapshot &other) const; diff --git a/src/libs/cplusplus/DependencyTable.cpp b/src/libs/cplusplus/DependencyTable.cpp index 00aca7dc65a..5960957330b 100644 --- a/src/libs/cplusplus/DependencyTable.cpp +++ b/src/libs/cplusplus/DependencyTable.cpp @@ -4,7 +4,7 @@ #include "CppDocument.h" #include -#include +#include using namespace Utils; @@ -28,14 +28,14 @@ Utils::FilePaths DependencyTable::filesDependingOn(const Utils::FilePath &fileNa return deps; } -void DependencyTable::build(QFutureInterfaceBase &futureInterface, const Snapshot &snapshot) +void DependencyTable::build(const std::optional> &future, const Snapshot &snapshot) { files.clear(); fileIndex.clear(); includes.clear(); includeMap.clear(); - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; const int documentCount = snapshot.size(); @@ -49,7 +49,7 @@ void DependencyTable::build(QFutureInterfaceBase &futureInterface, const Snapsho fileIndex[it.key()] = i; } - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; for (int i = 0; i < files.size(); ++i) { @@ -68,13 +68,13 @@ void DependencyTable::build(QFutureInterfaceBase &futureInterface, const Snapsho directIncludes.append(index); bitmap.setBit(index, true); - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; } includeMap[i] = bitmap; includes[i] = directIncludes; - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; } } @@ -91,7 +91,7 @@ void DependencyTable::build(QFutureInterfaceBase &futureInterface, const Snapsho const QList includedFileIndexes = includes.value(i); for (const int includedFileIndex : includedFileIndexes) { bitmap |= includeMap.value(includedFileIndex); - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; } @@ -99,10 +99,10 @@ void DependencyTable::build(QFutureInterfaceBase &futureInterface, const Snapsho includeMap[i] = bitmap; changed = true; } - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; } - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; } while (changed); } diff --git a/src/libs/cplusplus/DependencyTable.h b/src/libs/cplusplus/DependencyTable.h index d9057844330..d460ebeb7f3 100644 --- a/src/libs/cplusplus/DependencyTable.h +++ b/src/libs/cplusplus/DependencyTable.h @@ -14,7 +14,8 @@ #include QT_BEGIN_NAMESPACE -class QFutureInterfaceBase; +template +class QFuture; QT_END_NAMESPACE namespace CPlusPlus { @@ -25,7 +26,7 @@ class CPLUSPLUS_EXPORT DependencyTable { private: friend class Snapshot; - void build(QFutureInterfaceBase &futureInterface, const Snapshot &snapshot); + void build(const std::optional> &future, const Snapshot &snapshot); Utils::FilePaths filesDependingOn(const Utils::FilePath &fileName) const; QVector files; diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cppeditor/cppelementevaluator.cpp index dabb8cffc0d..3ce1761ce59 100644 --- a/src/plugins/cppeditor/cppelementevaluator.cpp +++ b/src/plugins/cppeditor/cppelementevaluator.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -140,20 +140,20 @@ CppClass *CppClass::toCppClass() return this; } -void CppClass::lookupBases(QFutureInterfaceBase &futureInterface, - Symbol *declaration, const LookupContext &context) +void CppClass::lookupBases(const QFuture &future, Symbol *declaration, + const LookupContext &context) { ClassOrNamespace *hierarchy = context.lookupType(declaration); if (!hierarchy) return; QSet visited; - addBaseHierarchy(futureInterface, context, hierarchy, &visited); + addBaseHierarchy(future, context, hierarchy, &visited); } -void CppClass::addBaseHierarchy(QFutureInterfaceBase &futureInterface, const LookupContext &context, +void CppClass::addBaseHierarchy(const QFuture &future, const LookupContext &context, ClassOrNamespace *hierarchy, QSet *visited) { - if (futureInterface.isCanceled()) + if (future.isCanceled()) return; visited->insert(hierarchy); const QList &baseClasses = hierarchy->usings(); @@ -165,21 +165,21 @@ void CppClass::addBaseHierarchy(QFutureInterfaceBase &futureInterface, const Loo ClassOrNamespace *baseHierarchy = context.lookupType(symbol); if (baseHierarchy && !visited->contains(baseHierarchy)) { CppClass classSymbol(symbol); - classSymbol.addBaseHierarchy(futureInterface, context, baseHierarchy, visited); + classSymbol.addBaseHierarchy(future, context, baseHierarchy, visited); bases.append(classSymbol); } } } } -void CppClass::lookupDerived(QFutureInterfaceBase &futureInterface, - Symbol *declaration, const Snapshot &snapshot) +void CppClass::lookupDerived(const QFuture &future, Symbol *declaration, + const Snapshot &snapshot) { - snapshot.updateDependencyTable(futureInterface); - if (futureInterface.isCanceled()) + snapshot.updateDependencyTable(future); + if (future.isCanceled()) return; addDerivedHierarchy(TypeHierarchyBuilder::buildDerivedTypeHierarchy( - futureInterface, declaration, snapshot)); + declaration, snapshot, future)); } void CppClass::addDerivedHierarchy(const TypeHierarchy &hierarchy) @@ -340,13 +340,13 @@ static Symbol *followTemplateAsClass(Symbol *symbol) return symbol; } -static void createTypeHierarchy(QFutureInterface> &futureInterface, +static void createTypeHierarchy(QPromise> &promise, const Snapshot &snapshot, const LookupItem &lookupItem, const LookupContext &context, SymbolFinder symbolFinder) { - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; Symbol *declaration = lookupItem.declaration(); @@ -360,16 +360,17 @@ static void createTypeHierarchy(QFutureInterface> &fu declaration = followClassDeclaration(declaration, snapshot, symbolFinder, &contextToUse); declaration = followTemplateAsClass(declaration); - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; QSharedPointer cppClass(new CppClass(declaration)); - cppClass->lookupBases(futureInterface, declaration, contextToUse); - if (futureInterface.isCanceled()) + const QFuture future = QFuture(promise.future()); + cppClass->lookupBases(future, declaration, contextToUse); + if (promise.isCanceled()) return; - cppClass->lookupDerived(futureInterface, declaration, snapshot); - if (futureInterface.isCanceled()) + cppClass->lookupDerived(future, declaration, snapshot); + if (promise.isCanceled()) return; - futureInterface.reportResult(cppClass); + promise.addResult(cppClass); } static QSharedPointer handleLookupItemMatch(const Snapshot &snapshot, @@ -495,7 +496,7 @@ static QFuture> asyncExec( const CPlusPlus::Snapshot &snapshot, const CPlusPlus::LookupItem &lookupItem, const CPlusPlus::LookupContext &lookupContext) { - return Utils::runAsync(&createTypeHierarchy, snapshot, lookupItem, lookupContext, + return Utils::asyncRun(&createTypeHierarchy, snapshot, lookupItem, lookupContext, *CppModelManager::instance()->symbolFinder()); } diff --git a/src/plugins/cppeditor/cppelementevaluator.h b/src/plugins/cppeditor/cppelementevaluator.h index 7d03df67121..47ddcbeae19 100644 --- a/src/plugins/cppeditor/cppelementevaluator.h +++ b/src/plugins/cppeditor/cppelementevaluator.h @@ -92,16 +92,16 @@ public: CppClass *toCppClass() final; - void lookupBases(QFutureInterfaceBase &futureInterface, - CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context); - void lookupDerived(QFutureInterfaceBase &futureInterface, - CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot); + void lookupBases(const QFuture &future, CPlusPlus::Symbol *declaration, + const CPlusPlus::LookupContext &context); + void lookupDerived(const QFuture &future, CPlusPlus::Symbol *declaration, + const CPlusPlus::Snapshot &snapshot); QList bases; QList derived; private: - void addBaseHierarchy(QFutureInterfaceBase &futureInterface, + void addBaseHierarchy(const QFuture &future, const CPlusPlus::LookupContext &context, CPlusPlus::ClassOrNamespace *hierarchy, QSet *visited); diff --git a/src/plugins/cppeditor/cpptypehierarchy.cpp b/src/plugins/cppeditor/cpptypehierarchy.cpp index c7a9e472ca5..27ef5751d10 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.cpp +++ b/src/plugins/cppeditor/cpptypehierarchy.cpp @@ -183,7 +183,8 @@ void CppTypeHierarchyWidget::perform() m_futureWatcher.setFuture(QFuture(m_future)); m_synchronizer.addFuture(m_future); - Core::ProgressManager::addTask(m_future, Tr::tr("Evaluating Type Hierarchy"), "TypeHierarchy"); + Core::ProgressManager::addTimedTask(m_futureWatcher.future(), + Tr::tr("Evaluating Type Hierarchy"), "TypeHierarchy", 2); } void CppTypeHierarchyWidget::performFromExpression(const QString &expression, const FilePath &filePath) diff --git a/src/plugins/cppeditor/typehierarchybuilder.cpp b/src/plugins/cppeditor/typehierarchybuilder.cpp index 5f3aae00e79..889d0eacfc0 100644 --- a/src/plugins/cppeditor/typehierarchybuilder.cpp +++ b/src/plugins/cppeditor/typehierarchybuilder.cpp @@ -108,20 +108,12 @@ const QList &TypeHierarchy::hierarchy() const } TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(Symbol *symbol, - const Snapshot &snapshot) -{ - QFutureInterfaceBase dummy; - return TypeHierarchyBuilder::buildDerivedTypeHierarchy(dummy, symbol, snapshot); -} - -TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface, - Symbol *symbol, - const Snapshot &snapshot) + const Snapshot &snapshot, const std::optional> &future) { TypeHierarchy hierarchy(symbol); TypeHierarchyBuilder builder; QHash> cache; - builder.buildDerived(futureInterface, &hierarchy, snapshot, cache); + builder.buildDerived(future, &hierarchy, snapshot, cache); return hierarchy; } @@ -172,11 +164,10 @@ static FilePaths filesDependingOn(const Snapshot &snapshot, Symbol *symbol) return FilePaths{file} + snapshot.filesDependingOn(file); } -void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface, +void TypeHierarchyBuilder::buildDerived(const std::optional> &future, TypeHierarchy *typeHierarchy, const Snapshot &snapshot, - QHash> &cache, - int depth) + QHash> &cache) { Symbol *symbol = typeHierarchy->_symbol; if (_visited.contains(symbol)) @@ -188,15 +179,10 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface, DerivedHierarchyVisitor visitor(symbolName, cache); const FilePaths dependingFiles = filesDependingOn(snapshot, symbol); - if (depth == 0) - futureInterface.setProgressRange(0, dependingFiles.size()); - int i = -1; for (const FilePath &fileName : dependingFiles) { - if (futureInterface.isCanceled()) + if (future && future->isCanceled()) return; - if (depth == 0) - futureInterface.setProgressValue(++i); Document::Ptr doc = snapshot.document(fileName); if ((_candidates.contains(fileName) && !_candidates.value(fileName).contains(symbolName)) || !doc->control()->findIdentifier(symbol->identifier()->chars(), @@ -210,8 +196,8 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface, const QList &derived = visitor.derived(); for (Symbol *s : derived) { TypeHierarchy derivedHierarchy(s); - buildDerived(futureInterface, &derivedHierarchy, snapshot, cache, depth + 1); - if (futureInterface.isCanceled()) + buildDerived(future, &derivedHierarchy, snapshot, cache); + if (future && future->isCanceled()) return; typeHierarchy->_hierarchy.append(derivedHierarchy); } diff --git a/src/plugins/cppeditor/typehierarchybuilder.h b/src/plugins/cppeditor/typehierarchybuilder.h index 07556126dd8..c6ee8a56bf6 100644 --- a/src/plugins/cppeditor/typehierarchybuilder.h +++ b/src/plugins/cppeditor/typehierarchybuilder.h @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include @@ -44,19 +44,17 @@ class TypeHierarchyBuilder { public: static TypeHierarchy buildDerivedTypeHierarchy(CPlusPlus::Symbol *symbol, - const CPlusPlus::Snapshot &snapshot); - static TypeHierarchy buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface, - CPlusPlus::Symbol *symbol, - const CPlusPlus::Snapshot &snapshot); + const CPlusPlus::Snapshot &snapshot, + const std::optional> &future = {}); static CPlusPlus::LookupItem followTypedef(const CPlusPlus::LookupContext &context, const CPlusPlus::Name *symbolName, CPlusPlus::Scope *enclosingScope, std::set typedefs = {}); private: TypeHierarchyBuilder() = default; - void buildDerived(QFutureInterfaceBase &futureInterface, TypeHierarchy *typeHierarchy, + void buildDerived(const std::optional> &future, TypeHierarchy *typeHierarchy, const CPlusPlus::Snapshot &snapshot, - QHash > &cache, int depth = 0); + QHash > &cache); QSet _visited; QHash > _candidates; From 1811c3149057df42e70e71bf8ad4fdeab75fdd66 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 7 Mar 2023 13:00:44 +0100 Subject: [PATCH 0257/1447] Python: add interpreter selector to the python project wizard Change-Id: I7ea1df34fa0096a84a0d611b401f991508c826c1 Reviewed-by: Christian Stenger --- .../qtforpythonapplication/empty/wizard.json | 32 ++-- .../mainwindow/wizard.json | 36 ++-- .../qtquickapplication/wizard.json | 108 ++++++----- .../qtforpythonapplication/widget/wizard.json | 36 ++-- src/plugins/python/CMakeLists.txt | 1 + src/plugins/python/python.qbs | 2 + src/plugins/python/pythonplugin.cpp | 5 +- src/plugins/python/pythonwizardpage.cpp | 167 ++++++++++++++++++ src/plugins/python/pythonwizardpage.h | 42 +++++ 9 files changed, 338 insertions(+), 91 deletions(-) create mode 100644 src/plugins/python/pythonwizardpage.cpp create mode 100644 src/plugins/python/pythonwizardpage.h diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json index 2d566dc1f66..8ca7c0cdcc5 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -26,20 +26,28 @@ { "trDisplayName": "Define Project Details", "trShortTitle": "Details", - "typeId": "Fields", - "data" : - [ - { - "name": "PySideVersion", - "trDisplayName": "PySide version:", - "type": "ComboBox", - "data": + "typeId": "PythonConfiguration", + "data": + { + "index": 0, + "items": + [ { - "index": 1, - "items": [ "PySide2", "PySide6" ] + "trKey": "PySide 6", + "value": + { + "PySideVersion": "PySide6" + } + }, + { + "trKey": "PySide 2", + "value": + { + "PySideVersion": "PySide2" + } } - } - ] + ] + } }, { "trDisplayName": "Project Management", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json index 58e9f8cd526..9156caaffd8 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json @@ -30,16 +30,6 @@ "typeId": "Fields", "data" : [ - { - "name": "PySideVersion", - "trDisplayName": "PySide version:", - "type": "ComboBox", - "data": - { - "index": 1, - "items": [ "PySide2", "PySide6" ] - } - }, { "name": "Class", "trDisplayName": "Class name:", @@ -77,6 +67,32 @@ } ] }, + { + "trDisplayName": "Define Project Details", + "trShortTitle": "Details", + "typeId": "PythonConfiguration", + "data": + { + "index": 0, + "items": + [ + { + "trKey": "PySide 6", + "value": + { + "PySideVersion": "PySide6" + } + }, + { + "trKey": "PySide 2", + "value": + { + "PySideVersion": "PySide2" + } + } + ] + } + }, { "trDisplayName": "Project Management", "trShortTitle": "Summary", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json index c04407347c8..b1b75fc0885 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json @@ -30,67 +30,59 @@ { "trDisplayName": "Define Project Details", "trShortTitle": "Details", - "typeId": "Fields", + "typeId": "PythonConfiguration", "data": - [ - { - "name": "QtVersion", - "trDisplayName": "PySide version:", - "type": "ComboBox", - "data": + { + "index": 0, + "items": + [ { - "index": 0, - "items": - [ - { - "trKey": "PySide 6", - "value": - { - "QtQuickVersion": "", - "QtQuickWindowVersion": "", - "PySideVersion": "PySide6" - } - }, - { - "trKey": "PySide 5.15", - "value": - { - "QtQuickVersion": "2.15", - "QtQuickWindowVersion": "2.15", - "PySideVersion": "PySide2" - } - }, - { - "trKey": "PySide 5.14", - "value": - { - "QtQuickVersion": "2.14", - "QtQuickWindowVersion": "2.14", - "PySideVersion": "PySide2" - } - }, - { - "trKey": "PySide 5.13", - "value": - { - "QtQuickVersion": "2.13", - "QtQuickWindowVersion": "2.13", - "PySideVersion": "PySide2" - } - }, - { - "trKey": "PySide 5.12", - "value": - { - "QtQuickVersion": "2.12", - "QtQuickWindowVersion": "2.12", - "PySideVersion": "PySide2" - } - } - ] + "trKey": "PySide 6", + "value": + { + "QtQuickVersion": "", + "QtQuickWindowVersion": "", + "PySideVersion": "PySide6" + } + }, + { + "trKey": "PySide 5.15", + "value": + { + "QtQuickVersion": "2.15", + "QtQuickWindowVersion": "2.15", + "PySideVersion": "PySide2" + } + }, + { + "trKey": "PySide 5.14", + "value": + { + "QtQuickVersion": "2.14", + "QtQuickWindowVersion": "2.14", + "PySideVersion": "PySide2" + } + }, + { + "trKey": "PySide 5.13", + "value": + { + "QtQuickVersion": "2.13", + "QtQuickWindowVersion": "2.13", + "PySideVersion": "PySide2" + } + }, + { + "trKey": "PySide 5.12", + "value": + { + "QtQuickVersion": "2.12", + "QtQuickWindowVersion": "2.12", + "PySideVersion": "PySide2" + } } - } - ] + ] + } }, { "trDisplayName": "Project Management", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json index 951be734757..8362cd55ecc 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json @@ -30,16 +30,6 @@ "typeId": "Fields", "data" : [ - { - "name": "PySideVersion", - "trDisplayName": "PySide version:", - "type": "ComboBox", - "data": - { - "index": 1, - "items": [ "PySide2", "PySide6" ] - } - }, { "name": "Class", "trDisplayName": "Class name:", @@ -77,6 +67,32 @@ } ] }, + { + "trDisplayName": "Define Python Interpreter", + "trShortTitle": "Interpreter", + "typeId": "PythonConfiguration", + "data": + { + "index": 0, + "items": + [ + { + "trKey": "PySide 6", + "value": + { + "PySideVersion": "PySide6" + } + }, + { + "trKey": "PySide 2", + "value": + { + "PySideVersion": "PySide2" + } + } + ] + } + }, { "trDisplayName": "Project Management", "trShortTitle": "Summary", diff --git a/src/plugins/python/CMakeLists.txt b/src/plugins/python/CMakeLists.txt index a508e14ddc8..c1f4767f83b 100644 --- a/src/plugins/python/CMakeLists.txt +++ b/src/plugins/python/CMakeLists.txt @@ -19,4 +19,5 @@ add_qtc_plugin(Python pythonscanner.cpp pythonscanner.h pythonsettings.cpp pythonsettings.h pythonutils.cpp pythonutils.h + pythonwizardpage.cpp pythonwizardpage.h ) diff --git a/src/plugins/python/python.qbs b/src/plugins/python/python.qbs index 9f8288cb11a..5186dafcdcd 100644 --- a/src/plugins/python/python.qbs +++ b/src/plugins/python/python.qbs @@ -49,6 +49,8 @@ QtcPlugin { "pythontr.h", "pythonutils.cpp", "pythonutils.h", + "pythonwizardpage.cpp", + "pythonwizardpage.h", ] } } diff --git a/src/plugins/python/pythonplugin.cpp b/src/plugins/python/pythonplugin.cpp index dff3c0cb220..4728da37ae5 100644 --- a/src/plugins/python/pythonplugin.cpp +++ b/src/plugins/python/pythonplugin.cpp @@ -6,10 +6,12 @@ #include "pysidebuildconfiguration.h" #include "pythoneditor.h" #include "pythonproject.h" -#include "pythonsettings.h" #include "pythonrunconfiguration.h" +#include "pythonsettings.h" +#include "pythonwizardpage.h" #include +#include #include #include #include @@ -57,6 +59,7 @@ void PythonPlugin::initialize() d = new PythonPluginPrivate; ProjectManager::registerProjectType(PythonMimeType); + JsonWizardFactory::registerPageFactory(new PythonWizardPageFactory); } void PythonPlugin::extensionsInitialized() diff --git a/src/plugins/python/pythonwizardpage.cpp b/src/plugins/python/pythonwizardpage.cpp new file mode 100644 index 00000000000..9243a6375f3 --- /dev/null +++ b/src/plugins/python/pythonwizardpage.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "pythonwizardpage.h" + +#include "pythonconstants.h" +#include "pythonsettings.h" +#include "pythontr.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace Python::Internal { + +PythonWizardPageFactory::PythonWizardPageFactory() +{ + setTypeIdsSuffix("PythonConfiguration"); +} + +WizardPage *PythonWizardPageFactory::create(JsonWizard *wizard, Id typeId, const QVariant &data) +{ + Q_UNUSED(wizard) + + QTC_ASSERT(canCreate(typeId), return nullptr); + + auto page = new PythonWizardPage; + for (const QVariant &item : data.toMap().value("items").toList()) { + const QMap map = item.toMap(); + const QVariant name = map.value("trKey"); + if (name.isValid()) + page->addPySideVersions(name.toString(), map.value("value")); + } + bool validIndex = false; + const int index = data.toMap().value("index").toInt(&validIndex); + if (validIndex) + page->setDefaultPySideVersions(index); + return page; +} + +static bool validItem(const QVariant &item) +{ + QMap map = item.toMap(); + if (!map.value("trKey").canConvert()) + return false; + map = map.value("value").toMap(); + return map.value("PySideVersion").canConvert(); +} + +bool PythonWizardPageFactory::validateData(Id typeId, const QVariant &data, QString *errorMessage) +{ + QTC_ASSERT(canCreate(typeId), return false); + const QList items = data.toMap().value("items").toList(); + + if (items.isEmpty()) { + if (errorMessage) { + *errorMessage = Tr::tr("'data' of a Python wizard page expects a map with 'items' " + "containing a list of objects"); + } + return false; + } + + if (!Utils::allOf(items, &validItem)) { + if (errorMessage) { + *errorMessage = Tr::tr( + "An item of Python wizard page data expects a 'trKey' field containing the ui " + "visible string for that python version and an field 'value' containing an object " + "with a 'PySideVersion' field used for import statements in the python files."); + } + return false; + } + return true; + + + if (!items.isEmpty() && Utils::allOf(items, &validItem)) + return true; + +} + +PythonWizardPage::PythonWizardPage() +{ + m_interpreter.setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID); + connect(PythonSettings::instance(), + &PythonSettings::interpretersChanged, + this, + &PythonWizardPage::updateInterpreters); + + m_pySideVersion.setLabelText(Tr::tr("PySide version")); + m_pySideVersion.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); +} + +void PythonWizardPage::initializePage() +{ + using namespace Utils::Layouting; + + auto wiz = qobject_cast(wizard()); + QTC_ASSERT(wiz, return); + + updateInterpreters(); + + connect(wiz, &JsonWizard::filesPolished, this, &PythonWizardPage::setupProject); + + Grid { + m_pySideVersion, br, + m_interpreter, br + }.attachTo(this, WithoutMargins); +} + +bool PythonWizardPage::validatePage() +{ + auto wiz = qobject_cast(wizard()); + const QMap data = m_pySideVersion.itemValue().toMap(); + for (auto it = data.begin(), end = data.end(); it != end; ++it) + wiz->setValue(it.key(), it.value()); + return true; +} + +void PythonWizardPage::addPySideVersions(const QString &name, const QVariant &data) +{ + m_pySideVersion.addOption(SelectionAspect::Option(name, {}, data)); +} + +void PythonWizardPage::setDefaultPySideVersions(int index) +{ + m_pySideVersion.setDefaultValue(index); +} + +void PythonWizardPage::setupProject(const JsonWizard::GeneratorFiles &files) +{ + for (const JsonWizard::GeneratorFile &f : files) { + if (f.file.attributes() & Core::GeneratedFile::OpenProjectAttribute) { + Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(f.file.filePath()), + f.file.filePath().absoluteFilePath()); + if (project) { + project->addTargetForDefaultKit(); + if (Target *target = project->activeTarget()) { + if (RunConfiguration *rc = target->activeRunConfiguration()) { + if (auto interpreters = rc->aspect()) { + interpreters->setCurrentInterpreter(m_interpreter.currentInterpreter()); + project->saveSettings(); + } + } + } + delete project; + } + } + } +} + +void PythonWizardPage::updateInterpreters() +{ + m_interpreter.setDefaultInterpreter(PythonSettings::defaultInterpreter()); + m_interpreter.updateInterpreters(PythonSettings::interpreters()); +} + +} // namespace Python::Internal + diff --git a/src/plugins/python/pythonwizardpage.h b/src/plugins/python/pythonwizardpage.h new file mode 100644 index 00000000000..e35e3ca55cb --- /dev/null +++ b/src/plugins/python/pythonwizardpage.h @@ -0,0 +1,42 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include +#include +#include + +#include +#include + +namespace Python::Internal { + +class PythonWizardPageFactory : public ProjectExplorer::JsonWizardPageFactory +{ +public: + PythonWizardPageFactory(); + + Utils::WizardPage *create(ProjectExplorer::JsonWizard *wizard, + Utils::Id typeId, + const QVariant &data) override; + bool validateData(Utils::Id typeId, const QVariant &data, QString *errorMessage) override; +}; + +class PythonWizardPage : public Utils::WizardPage +{ +public: + PythonWizardPage(); + void initializePage() override; + bool validatePage() override; + + void addPySideVersions(const QString &name, const QVariant &data); + void setDefaultPySideVersions(int index); + +private: + void setupProject(const ProjectExplorer::JsonWizard::GeneratorFiles &files); + void updateInterpreters(); + + ProjectExplorer::InterpreterAspect m_interpreter; + Utils::SelectionAspect m_pySideVersion; +}; + +} // namespace Python::Internal From 9eb218aee74769d7f70dc08dc522daa4ea7dfc34 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 10 Mar 2023 09:54:16 +0100 Subject: [PATCH 0258/1447] Examples: Use "install" path as fallback If neither relative nor install path of the example files exist. This makes the error message that the file is not found more sensible. Change-Id: I1a7d2acdb4017cdaac97af35d9d35b70c06323a6 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/qtsupport/examplesparser.cpp | 4 ++-- tests/auto/examples/tst_examples.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index bdde8e66a0f..99a3dafc5ba 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -24,8 +24,8 @@ static FilePath relativeOrInstallPath(const FilePath &path, return relativeResolvedPath; if (installResolvedPath.exists()) return installResolvedPath; - // doesn't exist, just return relative - return relativeResolvedPath; + // doesn't exist, return the preferred resolved install path + return installResolvedPath; } static QString fixStringForTags(const QString &string) diff --git a/tests/auto/examples/tst_examples.cpp b/tests/auto/examples/tst_examples.cpp index 5a18f1e4498..eef0429d29f 100644 --- a/tests/auto/examples/tst_examples.cpp +++ b/tests/auto/examples/tst_examples.cpp @@ -111,14 +111,14 @@ void tst_Examples::parsing_data() << "The Analog Clock example shows how to draw the contents of a custom widget." << "qthelp://org.qt-project.qtwidgets.660/qtwidgets/images/analogclock-example.png" << QStringList{"ios", "widgets"} - << FilePath::fromUserInput("manifest/widgets/widgets/analogclock/CMakeLists.txt") + << FilePath::fromUserInput("examples/widgets/widgets/analogclock/CMakeLists.txt") << "qthelp://org.qt-project.qtwidgets.660/qtwidgets/" "qtwidgets-widgets-analogclock-example.html" - << FilePaths{FilePath::fromUserInput("manifest/widgets/widgets/analogclock/main.cpp"), - FilePath::fromUserInput("manifest/widgets/widgets/analogclock/analogclock.h"), + << FilePaths{FilePath::fromUserInput("examples/widgets/widgets/analogclock/main.cpp"), + FilePath::fromUserInput("examples/widgets/widgets/analogclock/analogclock.h"), FilePath::fromUserInput( - "manifest/widgets/widgets/analogclock/analogclock.cpp")} - << FilePath::fromUserInput("manifest/widgets/widgets/analogclock/analogclock.cpp") + "examples/widgets/widgets/analogclock/analogclock.cpp")} + << FilePath::fromUserInput("examples/widgets/widgets/analogclock/analogclock.cpp") << FilePaths() << Example << true << false << false << "" << "" << QStringList() << MetaData({{"category", {"Graphics"}}, {"tags", {"widgets"}}}); } From 0bec769b69c660abec9ed0cc333522e4d4b0fc55 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 3 Mar 2023 20:53:58 +0100 Subject: [PATCH 0259/1447] QmlJS: Use QtConcurrent invocation for async run Add ModelManagerInterface::importScan() overload to avoid instantiating dummy QPromise arg on caller side. Change-Id: Idf836d30b2167d8840cc4e7ac6f95377c9d5622a Reviewed-by: hjk Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 95 ++++++++++--------- src/libs/qmljs/qmljsmodelmanagerinterface.h | 19 ++-- src/libs/qmljs/qmljsplugindumper.cpp | 22 ++--- .../autotest/quick/quicktestparser.cpp | 6 +- .../itemlibrary/itemlibraryassetimporter.cpp | 4 +- .../tests/qmlprofilerdetailsrewriter_test.cpp | 3 +- tests/auto/qml/codemodel/check/tst_check.cpp | 3 +- .../dependencies/tst_dependencies.cpp | 3 +- .../codemodel/ecmascript7/tst_ecmascript7.cpp | 3 +- .../importscheck/tst_importscheck.cpp | 6 +- .../qmldesigner/coretests/tst_testcore.cpp | 4 +- 11 files changed, 79 insertions(+), 89 deletions(-) diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index 3d2fc32120b..f6c84fb88f4 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -15,8 +15,8 @@ #include #include +#include #include -#include #include #ifdef WITH_TESTS @@ -337,11 +337,9 @@ QFuture ModelManagerInterface::refreshSourceFiles(const QList(); - QFuture result = Utils::runAsync(&m_threadPool, - &ModelManagerInterface::parse, - workingCopyInternal(), sourceFiles, - this, Dialect(Dialect::Qml), - emitDocumentOnDiskChanged); + QFuture result = Utils::asyncRun(&m_threadPool, &ModelManagerInterface::parse, + workingCopyInternal(), sourceFiles, this, + Dialect(Dialect::Qml), emitDocumentOnDiskChanged); addFuture(result); if (sourceFiles.count() > 1) @@ -365,13 +363,8 @@ QFuture ModelManagerInterface::refreshSourceFiles(const QList &files) @@ -1044,24 +1037,24 @@ void ModelManagerInterface::parseLoop(QSet &scannedPaths, class FutureReporter { public: - FutureReporter(QFutureInterface &future, int multiplier, int base) - : future(future), multiplier(multiplier), base(base) + FutureReporter(QPromise &promise, int multiplier, int base) + : m_promise(promise), m_multiplier(multiplier), m_base(base) {} bool operator()(qreal val) { - if (future.isCanceled()) + if (m_promise.isCanceled()) return false; - future.setProgressValue(int(base + multiplier * val)); + m_promise.setProgressValue(int(m_base + m_multiplier * val)); return true; } private: - QFutureInterface &future; - int multiplier; - int base; + QPromise &m_promise; + int m_multiplier; + int m_base; }; -void ModelManagerInterface::parse(QFutureInterface &future, +void ModelManagerInterface::parse(QPromise &promise, const WorkingCopy &workingCopy, QList files, ModelManagerInterface *modelManager, @@ -1069,8 +1062,8 @@ void ModelManagerInterface::parse(QFutureInterface &future, bool emitDocChangedOnDisk) { const int progressMax = 100; - FutureReporter reporter(future, progressMax, 0); - future.setProgressRange(0, progressMax); + FutureReporter reporter(promise, progressMax, 0); + promise.setProgressRange(0, progressMax); // paths we have scanned for files and added to the files list QSet scannedPaths; @@ -1078,7 +1071,7 @@ void ModelManagerInterface::parse(QFutureInterface &future, QSet newLibraries; parseLoop(scannedPaths, newLibraries, workingCopy, std::move(files), modelManager, mainLanguage, emitDocChangedOnDisk, reporter); - future.setProgressValue(progressMax); + promise.setProgressValue(progressMax); } struct ScanItem { @@ -1087,11 +1080,20 @@ struct ScanItem { Dialect language = Dialect::AnyLanguage; }; -void ModelManagerInterface::importScan(QFutureInterface &future, - const ModelManagerInterface::WorkingCopy &workingCopy, +void ModelManagerInterface::importScan(const WorkingCopy &workingCopy, const PathsAndLanguages &paths, ModelManagerInterface *modelManager, - bool emitDocChangedOnDisk, bool libOnly, bool forceRescan) + bool emitDocChanged, bool libOnly, bool forceRescan) +{ + QPromise promise; + promise.start(); + importScanAsync(promise, workingCopy, paths, modelManager, emitDocChanged, libOnly, forceRescan); +} + +void ModelManagerInterface::importScanAsync(QPromise &promise, const WorkingCopy &workingCopy, + const PathsAndLanguages &paths, + ModelManagerInterface *modelManager, + bool emitDocChanged, bool libOnly, bool forceRescan) { // paths we have scanned for files and added to the files list QSet scannedPaths; @@ -1118,9 +1120,9 @@ void ModelManagerInterface::importScan(QFutureInterface &future, int progressRange = pathsToScan.size() * (1 << (2 + maxScanDepth)); int totalWork = progressRange; int workDone = 0; - future.setProgressRange(0, progressRange); // update max length while iterating? + promise.setProgressRange(0, progressRange); // update max length while iterating? const Snapshot snapshot = modelManager->snapshot(); - bool isCanceled = future.isCanceled(); + bool isCanceled = promise.isCanceled(); while (!pathsToScan.isEmpty() && !isCanceled) { ScanItem toScan = pathsToScan.last(); pathsToScan.pop_back(); @@ -1135,16 +1137,16 @@ void ModelManagerInterface::importScan(QFutureInterface &future, toScan.language.companionLanguages()); } workDone += 1; - future.setProgressValue(progressRange * workDone / totalWork); + promise.setProgressValue(progressRange * workDone / totalWork); if (!importedFiles.isEmpty()) { - FutureReporter reporter(future, progressRange * pathBudget / (4 * totalWork), + FutureReporter reporter(promise, progressRange * pathBudget / (4 * totalWork), progressRange * workDone / totalWork); parseLoop(scannedPaths, newLibraries, workingCopy, importedFiles, modelManager, - toScan.language, emitDocChangedOnDisk, reporter); // run in parallel?? + toScan.language, emitDocChanged, reporter); // run in parallel?? importedFiles.clear(); } workDone += pathBudget / 4 - 1; - future.setProgressValue(progressRange * workDone / totalWork); + promise.setProgressValue(progressRange * workDone / totalWork); } else { workDone += pathBudget / 4; } @@ -1159,10 +1161,10 @@ void ModelManagerInterface::importScan(QFutureInterface &future, } else { workDone += pathBudget * 3 / 4; } - future.setProgressValue(progressRange * workDone / totalWork); - isCanceled = future.isCanceled(); + promise.setProgressValue(progressRange * workDone / totalWork); + isCanceled = promise.isCanceled(); } - future.setProgressValue(progressRange); + promise.setProgressValue(progressRange); if (isCanceled) { // assume no work has been done QMutexLocker l(&modelManager->m_mutex); @@ -1206,8 +1208,8 @@ void ModelManagerInterface::maybeScan(const PathsAndLanguages &importPaths) } if (pathToScan.length() >= 1) { - QFuture result = Utils::runAsync(&m_threadPool, - &ModelManagerInterface::importScan, + QFuture result = Utils::asyncRun(&m_threadPool, + &ModelManagerInterface::importScanAsync, workingCopyInternal(), pathToScan, this, true, true, false); addFuture(result); @@ -1373,8 +1375,8 @@ void ModelManagerInterface::startCppQmlTypeUpdate() if (!cppModelManager) return; - m_cppQmlTypesUpdater = Utils::runAsync(&ModelManagerInterface::updateCppQmlTypes, - this, cppModelManager->snapshot(), m_queuedCppDocuments); + m_cppQmlTypesUpdater = Utils::asyncRun(&ModelManagerInterface::updateCppQmlTypes, this, + cppModelManager->snapshot(), m_queuedCppDocuments); m_queuedCppDocuments.clear(); } @@ -1415,13 +1417,12 @@ bool rescanExports(const QString &fileName, FindExportedCppTypes &finder, return hasNewInfo; } -void ModelManagerInterface::updateCppQmlTypes( - QFutureInterface &futureInterface, ModelManagerInterface *qmlModelManager, - const CPlusPlus::Snapshot &snapshot, +void ModelManagerInterface::updateCppQmlTypes(QPromise &promise, + ModelManagerInterface *qmlModelManager, const CPlusPlus::Snapshot &snapshot, const QHash> &documents) { - futureInterface.setProgressRange(0, documents.size()); - futureInterface.setProgressValue(0); + promise.setProgressRange(0, documents.size()); + promise.setProgressValue(0); CppDataHash newData; QHash> newDeclarations; @@ -1436,9 +1437,9 @@ void ModelManagerInterface::updateCppQmlTypes( bool hasNewInfo = false; using DocScanPair = QPair; for (const DocScanPair &pair : documents) { - if (futureInterface.isCanceled()) + if (promise.isCanceled()) return; - futureInterface.setProgressValue(futureInterface.progressValue() + 1); + promise.setProgressValue(promise.future().progressValue() + 1); CPlusPlus::Document::Ptr doc = pair.first; const bool scan = pair.second; diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index b7b88c24ff5..e702b91afbb 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -179,10 +179,12 @@ public: void addFuture(const QFuture &future); QmlJS::Document::Ptr ensuredGetDocumentForPath(const Utils::FilePath &filePath); - static void importScan(QFutureInterface &future, const WorkingCopy& workingCopyInternal, - const PathsAndLanguages& paths, ModelManagerInterface *modelManager, - bool emitDocChangedOnDisk, bool libOnly = true, - bool forceRescan = false); + static void importScan(const WorkingCopy &workingCopy, const PathsAndLanguages &paths, + ModelManagerInterface *modelManager, bool emitDocChanged, + bool libOnly = true, bool forceRescan = false); + static void importScanAsync(QPromise &promise, const WorkingCopy& workingCopyInternal, + const PathsAndLanguages& paths, ModelManagerInterface *modelManager, + bool emitDocChanged, bool libOnly = true, bool forceRescan = false); virtual void resetCodeModel(); void removeProjectInfo(ProjectExplorer::Project *project); @@ -218,16 +220,15 @@ protected: QmlJS::Dialect mainLanguage, bool emitDocChangedOnDisk, const std::function &reportProgress); - static void parse(QFutureInterface &future, + static void parse(QPromise &promise, const WorkingCopy &workingCopyInternal, QList files, ModelManagerInterface *modelManager, QmlJS::Dialect mainLanguage, bool emitDocChangedOnDisk); - static void updateCppQmlTypes( - QFutureInterface &futureInterface, ModelManagerInterface *qmlModelManager, - const CPlusPlus::Snapshot &snapshot, - const QHash> &documents); + static void updateCppQmlTypes(QPromise &promise, ModelManagerInterface *qmlModelManager, + const CPlusPlus::Snapshot &snapshot, + const QHash> &documents); void maybeScan(const PathsAndLanguages &importPaths); void updateImportPaths(); diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index a7bafdde948..20736803d27 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -7,9 +7,9 @@ #include "qmljsmodelmanagerinterface.h" #include "qmljstr.h" #include "qmljsutils.h" -#include "qmljsviewercontext.h" #include +#include #include #include #include @@ -273,14 +273,13 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process) QStringList dependencies; }; - auto future = Utils::runAsync(m_modelManager->threadPool(), - [output, libraryPath](QFutureInterface& future) - { + auto future = Utils::asyncRun(m_modelManager->threadPool(), + [output, libraryPath](QPromise &promise) { CppQmlTypesInfo infos; - CppQmlTypesLoader::parseQmlTypeDescriptions(output, &infos.objectsList, &infos.moduleApis, &infos.dependencies, - &infos.error, &infos.warning, - "'); - future.reportFinished(&infos); + CppQmlTypesLoader::parseQmlTypeDescriptions(output, &infos.objectsList, + &infos.moduleApis, &infos.dependencies, &infos.error, &infos.warning, + "'); + promise.addResult(infos); }); m_modelManager->addFuture(future); @@ -327,8 +326,8 @@ void PluginDumper::pluginChanged(const QString &pluginLibrary) QFuture PluginDumper::loadQmlTypeDescription(const FilePaths &paths) const { - auto future = Utils::runAsync(m_modelManager->threadPool(), [=](QFutureInterface &future) - { + auto future = Utils::asyncRun(m_modelManager->threadPool(), + [=](QPromise &promise) { PluginDumper::QmlTypeDescription result; for (const FilePath &p: paths) { @@ -355,8 +354,7 @@ QFuture PluginDumper::loadQmlTypeDescription(c if (!warning.isEmpty()) result.warnings += warning; } - - future.reportFinished(&result); + promise.addResult(result); }); m_modelManager->addFuture(future); diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index 09965a099a4..de0003b2ffc 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -160,10 +160,9 @@ QList QuickTestParser::scanDirectoryForQuickTestQmlFiles(const Fi QStringList dirsStr({srcDir.toString()}); ModelManagerInterface *qmlJsMM = QmlJSTools::Internal::ModelManager::instance(); // make sure even files not listed in pro file are available inside the snapshot - QFutureInterface future; PathsAndLanguages paths; paths.maybeInsert(srcDir, Dialect::Qml); - ModelManagerInterface::importScan(future, ModelManagerInterface::workingCopy(), paths, qmlJsMM, + ModelManagerInterface::importScan(ModelManagerInterface::workingCopy(), paths, qmlJsMM, false /*emitDocumentChanges*/, false /*onlyTheLib*/, true /*forceRescan*/ ); const Snapshot snapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot(); @@ -307,9 +306,8 @@ void QuickTestParser::handleDirectoryChanged(const QString &directory) m_watchedFiles[directory] = filesAndDates; PathsAndLanguages paths; paths.maybeInsert(FilePath::fromString(directory), Dialect::Qml); - QFutureInterface future; ModelManagerInterface *qmlJsMM = ModelManagerInterface::instance(); - ModelManagerInterface::importScan(future, ModelManagerInterface::workingCopy(), paths, + ModelManagerInterface::importScan(ModelManagerInterface::workingCopy(), paths, qmlJsMM, true /*emitDocumentChanges*/, false /*onlyTheLib*/, diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index d9b82419433..cca5ed47b31 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include @@ -684,7 +684,7 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() if (modelManager) { QmlJS::PathsAndLanguages pathToScan; pathToScan.maybeInsert(Utils::FilePath::fromString(m_importPath)); - result = Utils::runAsync(&QmlJS::ModelManagerInterface::importScan, + result = Utils::asyncRun(&QmlJS::ModelManagerInterface::importScan, modelManager->workingCopy(), pathToScan, modelManager, true, true, true); } diff --git a/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp b/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp index ad787e05a5e..d71836319cc 100644 --- a/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp +++ b/src/plugins/qmlprofiler/tests/qmlprofilerdetailsrewriter_test.cpp @@ -175,12 +175,11 @@ void QmlProfilerDetailsRewriterTest::seedRewriter() m_modelManager = new QmlJS::ModelManagerInterface(this); QString filename = ":/qmlprofiler/tests/Test.qml"; - QFutureInterface result; QmlJS::PathsAndLanguages lPaths; lPaths.maybeInsert( Utils::FilePath::fromString(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)), QmlJS::Dialect::Qml); - QmlJS::ModelManagerInterface::importScan(result, QmlJS::ModelManagerInterface::workingCopy(), + QmlJS::ModelManagerInterface::importScan(QmlJS::ModelManagerInterface::workingCopy(), lPaths, m_modelManager, false); QFile file(filename); diff --git a/tests/auto/qml/codemodel/check/tst_check.cpp b/tests/auto/qml/codemodel/check/tst_check.cpp index 46542b8bf8f..56ccdfd2a37 100644 --- a/tests/auto/qml/codemodel/check/tst_check.cpp +++ b/tests/auto/qml/codemodel/check/tst_check.cpp @@ -72,12 +72,11 @@ void tst_Check::initTestCase() new ExtensionSystem::PluginManager; ModelManagerInterface *modelManager = ModelManagerInterface::instance(); - QFutureInterface result; PathsAndLanguages lPaths; QStringList paths(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)); for (auto p: paths) lPaths.maybeInsert(Utils::FilePath::fromString(p), Dialect::Qml); - ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), lPaths, + ModelManagerInterface::importScan(ModelManagerInterface::workingCopy(), lPaths, modelManager, false); modelManager->test_joinAllThreads(); } diff --git a/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp b/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp index 1a09449c114..48f8d7ce6cf 100644 --- a/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp +++ b/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp @@ -122,13 +122,12 @@ void tst_Dependencies::test() ModelManagerInterface *modelManager = ModelManagerInterface::instance(); - QFutureInterface result; PathsAndLanguages lPaths; QStringList paths(m_basePaths); paths << m_path; for (auto p: paths) lPaths.maybeInsert(Utils::FilePath::fromString(p), Dialect::Qml); - ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), lPaths, + ModelManagerInterface::importScan(ModelManagerInterface::workingCopy(), lPaths, ModelManagerInterface::instance(), false); ModelManagerInterface::instance()->test_joinAllThreads(); TestData data = testData(filename); diff --git a/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp b/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp index 9ca768cbeee..4f86e3ba988 100644 --- a/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp +++ b/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp @@ -149,12 +149,11 @@ void tst_Ecmascript::test() ModelManagerInterface *modelManager = ModelManagerInterface::instance(); - QFutureInterface result; PathsAndLanguages lPaths; QStringList paths(m_basePaths); for (auto p: paths) lPaths.maybeInsert(Utils::FilePath::fromString(p), Dialect::Qml); - ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), lPaths, + ModelManagerInterface::importScan(ModelManagerInterface::workingCopy(), lPaths, ModelManagerInterface::instance(), false); TestData data = testData(filename); diff --git a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp index 5cad7930e8f..e47c77db482 100644 --- a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp +++ b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp @@ -51,10 +51,9 @@ private: void scanDirectory(const QString &dir) { auto dirPath = Utils::FilePath::fromString(dir); - QFutureInterface result; PathsAndLanguages paths; paths.maybeInsert(dirPath, Dialect::Qml); - ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), paths, + ModelManagerInterface::importScan(ModelManagerInterface::workingCopy(), paths, ModelManagerInterface::instance(), false); ModelManagerInterface::instance()->test_joinAllThreads(); ViewerContext vCtx; @@ -170,11 +169,10 @@ void tst_ImportCheck::test() const auto pathPaths = Utils::transform(paths, [](const QString &s) { return Utils::FilePath::fromString(s); }); - QFutureInterface result; PathsAndLanguages lPaths; for (const Utils::FilePath &path : pathPaths) lPaths.maybeInsert(path, Dialect::Qml); - ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), lPaths, + ModelManagerInterface::importScan(ModelManagerInterface::workingCopy(), lPaths, ModelManagerInterface::instance(), false); ModelManagerInterface::instance()->test_joinAllThreads(); ViewerContext vCtx; diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index d6e62263807..f483e1d09dc 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -233,12 +233,10 @@ void tst_TestCore::initTestCase() QStringList basePaths; basePaths.append(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)); - - QFutureInterface result; QmlJS::PathsAndLanguages lPaths; lPaths.maybeInsert(Utils::FilePath::fromString(basePaths.first()), QmlJS::Dialect::Qml); - QmlJS::ModelManagerInterface::importScan(result, QmlJS::ModelManagerInterface::workingCopy(), + QmlJS::ModelManagerInterface::importScan(QmlJS::ModelManagerInterface::workingCopy(), lPaths, QmlJS::ModelManagerInterface::instance(), false); // Load plugins From 8709ab5ee5fa7df945d677f36d22cf2471517965 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 17:43:08 +0100 Subject: [PATCH 0260/1447] QmlJSEditor/QmlDesigner: Use QtConcurrent invocation for async run Change-Id: Ic3ad1bb4e2d473f6d5134d7e1eebef020bffee0d Reviewed-by: hjk Reviewed-by: Reviewed-by: Qt CI Bot --- .../assetexporterplugin/assetexporter.cpp | 22 +++--- .../assetexporterplugin/filepathmodel.cpp | 19 ++--- .../qmljseditor/qmljsfindreferences.cpp | 70 ++++++++----------- src/plugins/qmljseditor/qmltaskmanager.cpp | 12 ++-- src/plugins/qmljseditor/qmltaskmanager.h | 2 +- 5 files changed, 55 insertions(+), 70 deletions(-) diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp index e1b95b75068..5cfb1414ed0 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp @@ -10,11 +10,12 @@ #include "rewriterview.h" #include "qmlitemnode.h" #include "qmlobjectnode.h" -#include "coreplugin/editormanager/editormanager.h" -#include "utils/qtcassert.h" -#include "utils/runextensions.h" -#include "projectexplorer/projectmanager.h" -#include "projectexplorer/project.h" + +#include +#include +#include +#include +#include #include @@ -69,7 +70,7 @@ public: private: void addAsset(const QPixmap &p, const Utils::FilePath &path); - void doDumping(QFutureInterface &fi); + void doDumping(QPromise &promise); void savePixmap(const QPixmap &p, Utils::FilePath &path) const; QFuture m_dumpFuture; @@ -452,7 +453,7 @@ QDebug operator<<(QDebug os, const AssetExporter::ParsingState &s) AssetDumper::AssetDumper(): m_quitDumper(false) { - m_dumpFuture = Utils::runAsync(&AssetDumper::doDumping, this); + m_dumpFuture = Utils::asyncRun(&AssetDumper::doDumping, this); } AssetDumper::~AssetDumper() @@ -489,7 +490,7 @@ void AssetDumper::addAsset(const QPixmap &p, const Utils::FilePath &path) m_assets.push({p, path}); } -void AssetDumper::doDumping(QFutureInterface &fi) +void AssetDumper::doDumping(QPromise &promise) { auto haveAsset = [this] (std::pair *asset) { QMutexLocker locker(&m_queueMutex); @@ -503,7 +504,7 @@ void AssetDumper::doDumping(QFutureInterface &fi) forever { std::pair asset; if (haveAsset(&asset)) { - if (fi.isCanceled()) + if (promise.isCanceled()) break; savePixmap(asset.first, asset.second); } else { @@ -513,10 +514,9 @@ void AssetDumper::doDumping(QFutureInterface &fi) m_queueCondition.wait(&m_queueMutex); } - if (fi.isCanceled()) + if (promise.isCanceled()) break; } - fi.reportFinished(); } void AssetDumper::savePixmap(const QPixmap &p, Utils::FilePath &path) const diff --git a/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp b/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp index b50bc3cffba..dd92973eba9 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp @@ -4,9 +4,10 @@ #include "exportnotification.h" -#include "projectexplorer/project.h" -#include "projectexplorer/projectnodes.h" -#include "utils/runextensions.h" +#include +#include + +#include #include #include @@ -17,19 +18,19 @@ namespace { Q_LOGGING_CATEGORY(loggerError, "qtc.designer.assetExportPlugin.filePathModel", QtCriticalMsg) Q_LOGGING_CATEGORY(loggerInfo, "qtc.designer.assetExportPlugin.filePathModel", QtInfoMsg) -void findQmlFiles(QFutureInterface &f, const Project *project) +void findQmlFiles(QPromise &promise, const Project *project) { - if (!project || f.isCanceled()) + if (!project || promise.isCanceled()) return; int index = 0; - project->files([&f, &index](const Node* node) ->bool { - if (f.isCanceled()) + project->files([&promise, &index](const Node* node) ->bool { + if (promise.isCanceled()) return false; Utils::FilePath path = node->filePath(); bool isComponent = !path.fileName().isEmpty() && path.fileName().front().isUpper(); if (isComponent && node->filePath().endsWith(".ui.qml")) - f.reportResult(path, index++); + promise.addResult(path, index++); return true; }); } @@ -132,7 +133,7 @@ void FilePathModel::processProject() connect(m_preprocessWatcher.get(), &QFutureWatcher::finished, this, &FilePathModel::endResetModel); - QFuture f = Utils::runAsync(&findQmlFiles, m_project); + QFuture f = Utils::asyncRun(&findQmlFiles, m_project); m_preprocessWatcher->setFuture(f); } diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index b37d0e8758d..c8ae1f8b8b0 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include @@ -26,19 +26,10 @@ #include #include -#include "qmljseditorconstants.h" - -#include #include -#include #include -#include -#include -#include #include -#include - using namespace Core; using namespace QmlJS; using namespace QmlJS::AST; @@ -704,7 +695,7 @@ class ProcessFile using Usage = FindReferences::Usage; const QString name; const ObjectValue *scope; - QFutureInterface *future; + QPromise &m_promise; public: // needed by QtConcurrent @@ -714,16 +705,15 @@ public: ProcessFile(const ContextPtr &context, const QString &name, const ObjectValue *scope, - QFutureInterface *future) - : context(context), name(name), scope(scope), future(future) + QPromise &promise) + : context(context), name(name), scope(scope), m_promise(promise) { } QList operator()(const Utils::FilePath &fileName) { QList usages; - if (future->isPaused()) - future->waitForResume(); - if (future->isCanceled()) + m_promise.suspendIfRequested(); + if (m_promise.isCanceled()) return usages; ModelManagerInterface *modelManager = ModelManagerInterface::instance(); Document::Ptr doc = context->snapshot().document(fileName); @@ -739,8 +729,7 @@ public: loc.startLine, loc.startColumn - 1, loc.length)); - if (future->isPaused()) - future->waitForResume(); + m_promise.suspendIfRequested(); return usages; } }; @@ -751,7 +740,7 @@ class SearchFileForType using Usage = FindReferences::Usage; const QString name; const ObjectValue *scope; - QFutureInterface *future; + QPromise &m_promise; public: // needed by QtConcurrent @@ -761,16 +750,15 @@ public: SearchFileForType(const ContextPtr &context, const QString &name, const ObjectValue *scope, - QFutureInterface *future) - : context(context), name(name), scope(scope), future(future) + QPromise &promise) + : context(context), name(name), scope(scope), m_promise(promise) { } QList operator()(const Utils::FilePath &fileName) { QList usages; - if (future->isPaused()) - future->waitForResume(); - if (future->isCanceled()) + m_promise.suspendIfRequested(); + if (m_promise.isCanceled()) return usages; Document::Ptr doc = context->snapshot().document(fileName); if (!doc) @@ -781,8 +769,7 @@ public: const FindTypeUsages::Result results = findUsages(name, scope); for (const SourceLocation &loc : results) usages.append(Usage(fileName, matchingLine(loc.offset, doc->source()), loc.startLine, loc.startColumn - 1, loc.length)); - if (future->isPaused()) - future->waitForResume(); + m_promise.suspendIfRequested(); return usages; } }; @@ -790,7 +777,7 @@ public: class UpdateUI { using Usage = FindReferences::Usage; - QFutureInterface *future; + QPromise &m_promise; public: // needed by QtConcurrent @@ -798,14 +785,13 @@ public: using second_argument_type = const QList &; using result_type = void; - UpdateUI(QFutureInterface *future): future(future) {} + UpdateUI(QPromise &promise): m_promise(promise) {} void operator()(QList &, const QList &usages) { for (const Usage &u : usages) - future->reportResult(u); - - future->setProgressValue(future->progressValue() + 1); + m_promise.addResult(u); + m_promise.setProgressValue(m_promise.future().progressValue() + 1); } }; @@ -822,7 +808,7 @@ FindReferences::FindReferences(QObject *parent) FindReferences::~FindReferences() = default; -static void find_helper(QFutureInterface &future, +static void find_helper(QPromise &promise, const ModelManagerInterface::WorkingCopy &workingCopy, Snapshot snapshot, const Utils::FilePath &fileName, @@ -885,7 +871,7 @@ static void find_helper(QFutureInterface &future, } files = Utils::filteredUnique(files); - future.setProgressRange(0, files.size()); + promise.setProgressRange(0, files.size()); // report a dummy usage to indicate the search is starting FindReferences::Usage searchStarting(Utils::FilePath::fromString(replacement), name, 0, 0, 0); @@ -894,10 +880,10 @@ static void find_helper(QFutureInterface &future, const ObjectValue *typeValue = value_cast(findTarget.targetValue()); if (!typeValue) return; - future.reportResult(searchStarting); + promise.addResult(searchStarting); - SearchFileForType process(context, name, typeValue, &future); - UpdateUI reduce(&future); + SearchFileForType process(context, name, typeValue, promise); + UpdateUI reduce(promise); QtConcurrent::blockingMappedReduced > (files, process, reduce); } else { @@ -909,21 +895,21 @@ static void find_helper(QFutureInterface &future, return; if (!scope->className().isEmpty()) searchStarting.lineText.prepend(scope->className() + QLatin1Char('.')); - future.reportResult(searchStarting); + promise.addResult(searchStarting); - ProcessFile process(context, name, scope, &future); - UpdateUI reduce(&future); + ProcessFile process(context, name, scope, promise); + UpdateUI reduce(promise); QtConcurrent::blockingMappedReduced > (files, process, reduce); } - future.setProgressValue(files.size()); + promise.setProgressValue(files.size()); } void FindReferences::findUsages(const Utils::FilePath &fileName, quint32 offset) { ModelManagerInterface *modelManager = ModelManagerInterface::instance(); - QFuture result = Utils::runAsync(&find_helper, ModelManagerInterface::workingCopy(), + QFuture result = Utils::asyncRun(&find_helper, ModelManagerInterface::workingCopy(), modelManager->snapshot(), fileName, offset, QString()); m_watcher.setFuture(result); m_synchronizer.addFuture(result); @@ -940,7 +926,7 @@ void FindReferences::renameUsages(const Utils::FilePath &fileName, if (newName.isNull()) newName = QLatin1String(""); - QFuture result = Utils::runAsync(&find_helper, ModelManagerInterface::workingCopy(), + QFuture result = Utils::asyncRun(&find_helper, ModelManagerInterface::workingCopy(), modelManager->snapshot(), fileName, offset, newName); m_watcher.setFuture(result); m_synchronizer.addFuture(result); diff --git a/src/plugins/qmljseditor/qmltaskmanager.cpp b/src/plugins/qmljseditor/qmltaskmanager.cpp index 08019019da0..0d25bb3f13a 100644 --- a/src/plugins/qmljseditor/qmltaskmanager.cpp +++ b/src/plugins/qmljseditor/qmltaskmanager.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qmltaskmanager.h" -#include "qmljseditor.h" #include "qmljseditorconstants.h" #include @@ -13,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -57,7 +56,7 @@ static Tasks convertToTasks(const QList &messages, cons return convertToTasks(diagnostics, fileName, category); } -void QmlTaskManager::collectMessages(QFutureInterface &future, +void QmlTaskManager::collectMessages(QPromise &promise, Snapshot snapshot, const QList &projectInfos, ViewerContext vContext, @@ -96,8 +95,8 @@ void QmlTaskManager::collectMessages(QFutureInterface &future } if (!result.tasks.isEmpty()) - future.reportResult(result); - if (future.isCanceled()) + promise.addResult(result); + if (promise.isCanceled()) break; } } @@ -127,8 +126,7 @@ void QmlTaskManager::updateMessagesNow(bool updateSemantic) ModelManagerInterface *modelManager = ModelManagerInterface::instance(); // process them - QFuture future = - Utils::runAsync( + QFuture future = Utils::asyncRun( &collectMessages, modelManager->newestSnapshot(), modelManager->projectInfos(), modelManager->defaultVContext(Dialect::AnyLanguage), updateSemantic); m_messageCollector.setFuture(future); diff --git a/src/plugins/qmljseditor/qmltaskmanager.h b/src/plugins/qmljseditor/qmltaskmanager.h index 26fa3bd347f..226fd2203d4 100644 --- a/src/plugins/qmljseditor/qmltaskmanager.h +++ b/src/plugins/qmljseditor/qmltaskmanager.h @@ -45,7 +45,7 @@ private: Utils::FilePath fileName; ProjectExplorer::Tasks tasks; }; - static void collectMessages(QFutureInterface &future, + static void collectMessages(QPromise &promise, QmlJS::Snapshot snapshot, const QList &projectInfos, QmlJS::ViewerContext vContext, From 4a121833b1f78ce07c9ad7e83c8b0b5966e6ba76 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 9 Mar 2023 18:07:26 +0100 Subject: [PATCH 0261/1447] Ios: Use QtConcurrent invocation for async run Change-Id: I1d02a7a0467864a702bed8f73793f8f21832762b Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/ios/iostoolhandler.cpp | 23 +++--- src/plugins/ios/simulatorcontrol.cpp | 113 +++++++++++++-------------- src/plugins/ios/simulatorcontrol.h | 6 +- 3 files changed, 69 insertions(+), 73 deletions(-) diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 0331ba2ccab..b8a3c592ef4 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -63,22 +64,22 @@ class LogTailFiles : public QObject Q_OBJECT public: - void exec(QFutureInterface &fi, std::shared_ptr stdoutFile, - std::shared_ptr stderrFile) + void exec(QPromise &promise, std::shared_ptr stdoutFile, + std::shared_ptr stderrFile) { - if (fi.isCanceled()) + if (promise.isCanceled()) return; // The future is canceled when app on simulator is stoped. QEventLoop loop; QFutureWatcher watcher; connect(&watcher, &QFutureWatcher::canceled, &loop, [&] { loop.quit(); }); - watcher.setFuture(fi.future()); + watcher.setFuture(promise.future()); // Process to print the console output while app is running. auto logProcess = [&](QProcess *tailProcess, std::shared_ptr file) { - QObject::connect(tailProcess, &QProcess::readyReadStandardOutput, &loop, [=] { - if (!fi.isCanceled()) + QObject::connect(tailProcess, &QProcess::readyReadStandardOutput, &loop, [&, tailProcess] { + if (!promise.isCanceled()) emit logMessage(QString::fromLocal8Bit(tailProcess->readAll())); }); tailProcess->start(QStringLiteral("tail"), {"-f", file->fileName()}); @@ -931,17 +932,17 @@ void IosSimulatorToolHandlerPrivate::launchAppOnSimulator(const QStringList &ext "Install Xcode 8 or later.").arg(bundleId)); } - auto monitorPid = [this](QFutureInterface &fi, qint64 pid) { + auto monitorPid = [this](QPromise &promise, qint64 pid) { #ifdef Q_OS_UNIX do { // Poll every 1 sec to check whether the app is running. QThread::msleep(1000); - } while (!fi.isCanceled() && kill(pid, 0) == 0); + } while (!promise.isCanceled() && kill(pid, 0) == 0); #else Q_UNUSED(pid) #endif // Future is cancelled if the app is stopped from the qt creator. - if (!fi.isCanceled()) + if (!promise.isCanceled()) stop(0); }; @@ -953,9 +954,9 @@ void IosSimulatorToolHandlerPrivate::launchAppOnSimulator(const QStringList &ext gotInferiorPid(m_bundlePath, m_deviceId, response.pID); didStartApp(m_bundlePath, m_deviceId, Ios::IosToolHandler::Success); // Start monitoring app's life signs. - futureSynchronizer.addFuture(Utils::runAsync(monitorPid, response.pID)); + futureSynchronizer.addFuture(Utils::asyncRun(monitorPid, response.pID)); if (captureConsole) - futureSynchronizer.addFuture(Utils::runAsync(&LogTailFiles::exec, &outputLogger, + futureSynchronizer.addFuture(Utils::asyncRun(&LogTailFiles::exec, &outputLogger, stdoutFile, stderrFile)); } else { m_pid = -1; diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index 6e090b61886..6a19513fd2a 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -5,9 +5,10 @@ #include "iosconfigurations.h" #include -#include +#include #include #include +#include #ifdef Q_OS_MAC #include @@ -162,30 +163,30 @@ static SimulatorInfo deviceInfo(const QString &simUdid); static QString bundleIdentifier(const Utils::FilePath &bundlePath); static QString bundleExecutable(const Utils::FilePath &bundlePath); -static void startSimulator(QFutureInterface &fi, +static void startSimulator(QPromise &promise, const QString &simUdid); -static void installApp(QFutureInterface &fi, +static void installApp(QPromise &promise, const QString &simUdid, const Utils::FilePath &bundlePath); -static void launchApp(QFutureInterface &fi, +static void launchApp(QPromise &promise, const QString &simUdid, const QString &bundleIdentifier, bool waitForDebugger, const QStringList &extraArgs, const QString &stdoutPath, const QString &stderrPath); -static void deleteSimulator(QFutureInterface &fi, +static void deleteSimulator(QPromise &promise, const QString &simUdid); -static void resetSimulator(QFutureInterface &fi, +static void resetSimulator(QPromise &promise, const QString &simUdid); -static void renameSimulator(QFutureInterface &fi, +static void renameSimulator(QPromise &promise, const QString &simUdid, const QString &newName); -static void createSimulator(QFutureInterface &fi, +static void createSimulator(QPromise &promise, const QString &name, const DeviceTypeInfo &deviceType, const RuntimeInfo &runtime); -static void takeSceenshot(QFutureInterface &fi, +static void takeSceenshot(QPromise &promise, const QString &simUdid, const QString &filePath); @@ -234,9 +235,9 @@ static QList getAvailableSimulators() return availableDevices; } -QFuture > SimulatorControl::updateDeviceTypes() +QFuture> SimulatorControl::updateDeviceTypes() { - QFuture< QList > future = Utils::runAsync(getAvailableDeviceTypes); + QFuture> future = Utils::asyncRun(getAvailableDeviceTypes); Utils::onResultReady(future, [](const QList &deviceTypes) { s_availableDeviceTypes = deviceTypes; }); @@ -248,18 +249,18 @@ QList SimulatorControl::availableRuntimes() return s_availableRuntimes; } -QFuture > SimulatorControl::updateRuntimes() +QFuture> SimulatorControl::updateRuntimes() { - QFuture< QList > future = Utils::runAsync(getAvailableRuntimes); + QFuture> future = Utils::asyncRun(getAvailableRuntimes); Utils::onResultReady(future, [](const QList &runtimes) { s_availableRuntimes = runtimes; }); return future; } -QFuture< QList > SimulatorControl::updateAvailableSimulators() +QFuture> SimulatorControl::updateAvailableSimulators() { - QFuture< QList > future = Utils::runAsync(getAvailableSimulators); + QFuture> future = Utils::asyncRun(getAvailableSimulators); Utils::onResultReady(future, [](const QList &devices) { s_availableDevices = devices; }); return future; @@ -284,13 +285,13 @@ QString SimulatorControl::bundleExecutable(const Utils::FilePath &bundlePath) QFuture SimulatorControl::startSimulator(const QString &simUdid) { - return Utils::runAsync(Internal::startSimulator, simUdid); + return Utils::asyncRun(Internal::startSimulator, simUdid); } QFuture SimulatorControl::installApp( const QString &simUdid, const Utils::FilePath &bundlePath) { - return Utils::runAsync(Internal::installApp, simUdid, bundlePath); + return Utils::asyncRun(Internal::installApp, simUdid, bundlePath); } QFuture SimulatorControl::launchApp(const QString &simUdid, @@ -300,7 +301,7 @@ QFuture SimulatorControl::launchApp(const QStrin const QString &stdoutPath, const QString &stderrPath) { - return Utils::runAsync(Internal::launchApp, + return Utils::asyncRun(Internal::launchApp, simUdid, bundleIdentifier, waitForDebugger, @@ -311,18 +312,18 @@ QFuture SimulatorControl::launchApp(const QStrin QFuture SimulatorControl::deleteSimulator(const QString &simUdid) { - return Utils::runAsync(Internal::deleteSimulator, simUdid); + return Utils::asyncRun(Internal::deleteSimulator, simUdid); } QFuture SimulatorControl::resetSimulator(const QString &simUdid) { - return Utils::runAsync(Internal::resetSimulator, simUdid); + return Utils::asyncRun(Internal::resetSimulator, simUdid); } QFuture SimulatorControl::renameSimulator(const QString &simUdid, const QString &newName) { - return Utils::runAsync(Internal::renameSimulator, simUdid, newName); + return Utils::asyncRun(Internal::renameSimulator, simUdid, newName); } QFuture @@ -330,13 +331,13 @@ SimulatorControl::createSimulator(const QString &name, const DeviceTypeInfo &deviceType, const RuntimeInfo &runtime) { - return Utils::runAsync(Internal::createSimulator, name, deviceType, runtime); + return Utils::asyncRun(Internal::createSimulator, name, deviceType, runtime); } QFuture SimulatorControl::takeSceenshot(const QString &simUdid, const QString &filePath) { - return Utils::runAsync(Internal::takeSceenshot, simUdid, filePath); + return Utils::asyncRun(Internal::takeSceenshot, simUdid, filePath); } // Static members @@ -392,7 +393,7 @@ QString bundleExecutable(const Utils::FilePath &bundlePath) return executable; } -void startSimulator(QFutureInterface &fi, const QString &simUdid) +void startSimulator(QPromise &promise, const QString &simUdid) { SimulatorControl::ResponseData response(simUdid); SimulatorInfo simInfo = deviceInfo(simUdid); @@ -420,7 +421,7 @@ void startSimulator(QFutureInterface &fi, const if (simInfo.isShutdown()) { if (launchSimulator(simUdid)) { - if (fi.isCanceled()) + if (promise.isCanceled()) return; // At this point the sim device exists, available and was not running. // So the simulator is started and we'll wait for it to reach to a state @@ -429,13 +430,11 @@ void startSimulator(QFutureInterface &fi, const SimulatorInfo info; do { info = deviceInfo(simUdid); - if (fi.isCanceled()) + if (promise.isCanceled()) return; - } while (!info.isBooted() - && !checkForTimeout(start, simulatorStartTimeout)); - if (info.isBooted()) { + } while (!info.isBooted() && !checkForTimeout(start, simulatorStartTimeout)); + if (info.isBooted()) response.success = true; - } } else { qCDebug(simulatorLog) << "Error starting simulator."; } @@ -444,14 +443,12 @@ void startSimulator(QFutureInterface &fi, const << simInfo; } - if (!fi.isCanceled()) { - fi.reportResult(response); - } + if (!promise.isCanceled()) + promise.addResult(response); } -void installApp(QFutureInterface &fi, - const QString &simUdid, - const Utils::FilePath &bundlePath) +void installApp(QPromise &promise, + const QString &simUdid, const Utils::FilePath &bundlePath) { QTC_CHECK(bundlePath.exists()); @@ -459,11 +456,11 @@ void installApp(QFutureInterface &fi, response.success = runSimCtlCommand({"install", simUdid, bundlePath.toString()}, nullptr, &response.commandOutput); - if (!fi.isCanceled()) - fi.reportResult(response); + if (!promise.isCanceled()) + promise.addResult(response); } -void launchApp(QFutureInterface &fi, +void launchApp(QPromise &promise, const QString &simUdid, const QString &bundleIdentifier, bool waitForDebugger, @@ -472,7 +469,7 @@ void launchApp(QFutureInterface &fi, const QString &stderrPath) { SimulatorControl::ResponseData response(simUdid); - if (!bundleIdentifier.isEmpty() && !fi.isCanceled()) { + if (!bundleIdentifier.isEmpty() && !promise.isCanceled()) { QStringList args({"launch", simUdid, bundleIdentifier}); // simctl usage documentation : Note: Log output is often directed to stderr, not stdout. @@ -499,30 +496,29 @@ void launchApp(QFutureInterface &fi, } } - if (!fi.isCanceled()) { - fi.reportResult(response); - } + if (!promise.isCanceled()) + promise.addResult(response); } -void deleteSimulator(QFutureInterface &fi, const QString &simUdid) +void deleteSimulator(QPromise &promise, const QString &simUdid) { SimulatorControl::ResponseData response(simUdid); response.success = runSimCtlCommand({"delete", simUdid}, nullptr, &response.commandOutput); - if (!fi.isCanceled()) - fi.reportResult(response); + if (!promise.isCanceled()) + promise.addResult(response); } -void resetSimulator(QFutureInterface &fi, const QString &simUdid) +void resetSimulator(QPromise &promise, const QString &simUdid) { SimulatorControl::ResponseData response(simUdid); response.success = runSimCtlCommand({"erase", simUdid}, nullptr, &response.commandOutput); - if (!fi.isCanceled()) - fi.reportResult(response); + if (!promise.isCanceled()) + promise.addResult(response); } -void renameSimulator(QFutureInterface &fi, +void renameSimulator(QPromise &promise, const QString &simUdid, const QString &newName) { @@ -530,12 +526,11 @@ void renameSimulator(QFutureInterface &fi, response.success = runSimCtlCommand({"rename", simUdid, newName}, nullptr, &response.commandOutput); - - if (!fi.isCanceled()) - fi.reportResult(response); + if (!promise.isCanceled()) + promise.addResult(response); } -void createSimulator(QFutureInterface &fi, +void createSimulator(QPromise &promise, const QString &name, const DeviceTypeInfo &deviceType, const RuntimeInfo &runtime) @@ -550,11 +545,11 @@ void createSimulator(QFutureInterface &fi, response.simUdid = response.success ? stdOutput.trimmed() : QString(); } - if (!fi.isCanceled()) - fi.reportResult(response); + if (!promise.isCanceled()) + promise.addResult(response); } -void takeSceenshot(QFutureInterface &fi, +void takeSceenshot(QPromise &promise, const QString &simUdid, const QString &filePath) { @@ -562,8 +557,8 @@ void takeSceenshot(QFutureInterface &fi, response.success = runSimCtlCommand({"io", simUdid, "screenshot", filePath}, nullptr, &response.commandOutput); - if (!fi.isCanceled()) - fi.reportResult(response); + if (!promise.isCanceled()) + promise.addResult(response); } QDebug &operator<<(QDebug &stream, const SimulatorInfo &info) diff --git a/src/plugins/ios/simulatorcontrol.h b/src/plugins/ios/simulatorcontrol.h index 15fea7b27bd..90a0a6ac4b2 100644 --- a/src/plugins/ios/simulatorcontrol.h +++ b/src/plugins/ios/simulatorcontrol.h @@ -65,11 +65,11 @@ public: public: static QList availableDeviceTypes(); - static QFuture > updateDeviceTypes(); + static QFuture> updateDeviceTypes(); static QList availableRuntimes(); - static QFuture > updateRuntimes(); + static QFuture> updateRuntimes(); static QList availableSimulators(); - static QFuture > updateAvailableSimulators(); + static QFuture> updateAvailableSimulators(); static bool isSimulatorRunning(const QString &simUdid); static QString bundleIdentifier(const Utils::FilePath &bundlePath); static QString bundleExecutable(const Utils::FilePath &bundlePath); From 392cc524db7339d5ae77cbd64cba4f2a86dc091e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 10:17:33 +0100 Subject: [PATCH 0262/1447] Copilot/Terminal: Use Qtc::... as translation contexts lupdate doesn't like toplevel ::, so we changed globally to Qtc::* Change-Id: Id6f27989653dd16974d0c12ea4832c4e1abe3ca3 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilottr.h | 2 +- src/plugins/terminal/terminaltr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/copilot/copilottr.h b/src/plugins/copilot/copilottr.h index a25a534f0d3..42fef818db0 100644 --- a/src/plugins/copilot/copilottr.h +++ b/src/plugins/copilot/copilottr.h @@ -9,7 +9,7 @@ namespace Copilot { struct Tr { - Q_DECLARE_TR_FUNCTIONS(::Copilot) + Q_DECLARE_TR_FUNCTIONS(QtC::Copilot) }; } // namespace Copilot diff --git a/src/plugins/terminal/terminaltr.h b/src/plugins/terminal/terminaltr.h index 711e0e82000..b645284833c 100644 --- a/src/plugins/terminal/terminaltr.h +++ b/src/plugins/terminal/terminaltr.h @@ -9,7 +9,7 @@ namespace Terminal { struct Tr { - Q_DECLARE_TR_FUNCTIONS(::Terminal) + Q_DECLARE_TR_FUNCTIONS(QtC::Terminal) }; } // namespace Terminal From b077a105fadba1b18a680d46eb016b38878e894e Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 13 Mar 2023 17:28:15 +0100 Subject: [PATCH 0263/1447] GdbEngine: Allow remote symbol files They may be needed when running gdb itself remotely. Change-Id: I57242e3111ab23701d197d26f1c3b12a9b3e96bd Reviewed-by: Orgad Shaneh --- src/plugins/debugger/gdb/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index b8ba1441edd..de3c075fe3f 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4369,7 +4369,7 @@ void GdbEngine::setupInferior() setLinuxOsAbi(); QString symbolFile; if (!rp.symbolFile.isEmpty()) - symbolFile = rp.symbolFile.toFileInfo().absoluteFilePath(); + symbolFile = rp.symbolFile.absoluteFilePath().path(); //const QByteArray sysroot = sp.sysroot.toLocal8Bit(); //const QByteArray remoteArch = sp.remoteArchitecture.toLatin1(); From 0b92ba92b261d27db78a5707cc058dc8d81a8da3 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 14 Mar 2023 09:26:53 +0100 Subject: [PATCH 0264/1447] Python: Remove dead code Change-Id: I31aa1610b548b37f30f3daa353627f9c6418c3c8 Reviewed-by: hjk --- src/plugins/python/pythonwizardpage.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/python/pythonwizardpage.cpp b/src/plugins/python/pythonwizardpage.cpp index 9243a6375f3..1b5798f1733 100644 --- a/src/plugins/python/pythonwizardpage.cpp +++ b/src/plugins/python/pythonwizardpage.cpp @@ -80,11 +80,6 @@ bool PythonWizardPageFactory::validateData(Id typeId, const QVariant &data, QStr return false; } return true; - - - if (!items.isEmpty() && Utils::allOf(items, &validItem)) - return true; - } PythonWizardPage::PythonWizardPage() From c43ff702f7945981d2eb7de1dd5f3d9d588346d1 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 14 Mar 2023 10:57:10 +0100 Subject: [PATCH 0265/1447] CMake: Fix WITH_SANITIZE Change-Id: Ic0ad66f08b29416ddb1a546e84f9ed574b9ac6fc Reviewed-by: Cristian Adam --- src/shared/registryaccess/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/registryaccess/CMakeLists.txt b/src/shared/registryaccess/CMakeLists.txt index 135df2c501f..634c8c19e60 100644 --- a/src/shared/registryaccess/CMakeLists.txt +++ b/src/shared/registryaccess/CMakeLists.txt @@ -3,10 +3,10 @@ if (WIN32) target_link_libraries(registryaccess PUBLIC advapi32 ole32 shell32 Qt::Widgets) target_compile_definitions(registryaccess PRIVATE _UNICODE UNICODE) target_include_directories(registryaccess PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + if (WITH_SANITIZE) + qtc_enable_sanitize(registryaccess ${SANITIZE_FLAGS}) + endif() else() add_library(registryaccess INTERFACE) endif() -if (WITH_SANITIZE) - qtc_enable_sanitize(registryaccess ${SANITIZE_FLAGS}) -endif() From 8778eaaaa06c669b35377ca8b61d509444acdb86 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 14 Mar 2023 14:39:24 +0100 Subject: [PATCH 0266/1447] FileIconProvider: Improve performance of icon(FilePath) By re-using the caching QFileInfo variant for icon(FilePath). QFileInfo/FSEngine caches the result of isDir etc for a while, which improves performance for slower devices in case that is called for the same file paths over and over again, like it is the case for locator. The cache might be out of date for some time when things change on disk, but for a cosmetic property like an icon that is not a big deal. (And it would be a file that transforms into a directory or vice versa, which is not very common either.) Change-Id: I663ac7e81f8f2996b87591dad17c5483e3f4ad3c Reviewed-by: Marcus Tillmanns --- src/libs/utils/fsengine/fileiconprovider.cpp | 41 +------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/src/libs/utils/fsengine/fileiconprovider.cpp b/src/libs/utils/fsengine/fileiconprovider.cpp index e5ed4a1281f..07ea4b3f5a8 100644 --- a/src/libs/utils/fsengine/fileiconprovider.cpp +++ b/src/libs/utils/fsengine/fileiconprovider.cpp @@ -216,46 +216,7 @@ QIcon FileIconProviderImplementation::icon(const FilePath &filePath) const { qCDebug(fileIconProvider) << "FileIconProvider::icon" << filePath.absoluteFilePath(); - if (filePath.isEmpty()) - return unknownFileIcon(); - - // Check if its one of the virtual devices directories - if (filePath.path().startsWith(FilePath::specialRootPath())) { - // If the filepath does not need a device, it is a virtual device directory - if (!filePath.needsDevice()) - return dirIcon(); - } - - bool isDir = filePath.isDir(); - - // Check for cached overlay icons by file suffix. - const QString filename = !isDir ? filePath.fileName() : QString(); - if (!filename.isEmpty()) { - const std::optional icon = getIcon(m_filenameCache, filename); - if (icon) - return *icon; - } - - const QString suffix = !isDir ? filePath.suffix() : QString(); - if (!suffix.isEmpty()) { - const std::optional icon = getIcon(m_suffixCache, suffix); - if (icon) - return *icon; - } - - if (filePath.needsDevice()) - return isDir ? dirIcon() : unknownFileIcon(); - - // Get icon from OS (and cache it based on suffix!) - QIcon icon; - if (HostOsInfo::isWindowsHost() || HostOsInfo::isMacHost()) - icon = QFileIconProvider::icon(filePath.toFileInfo()); - else // File icons are unknown on linux systems. - icon = isDir ? QFileIconProvider::icon(filePath.toFileInfo()) : unknownFileIcon(); - - if (!isDir && !suffix.isEmpty()) - m_suffixCache.insert(suffix, icon); - return icon; + return icon(QFileInfo(filePath.toFSPathString())); } /*! From c08322900fe3b20152feb831cd8500e3dce7bfc2 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 08:27:50 +0100 Subject: [PATCH 0267/1447] Debugger: Use more FilePaths in module handling interface Change-Id: Ie058b928900015d0f71776151547bf7ba32a62bf Reviewed-by: David Schulz Reviewed-by: --- src/plugins/debugger/cdb/cdbengine.cpp | 5 +++-- src/plugins/debugger/cdb/cdbengine.h | 4 ++-- src/plugins/debugger/debuggerengine.cpp | 18 +++++++++--------- src/plugins/debugger/debuggerengine.h | 10 +++++----- src/plugins/debugger/gdb/gdbengine.cpp | 18 +++++++++--------- src/plugins/debugger/gdb/gdbengine.h | 8 ++++---- src/plugins/debugger/lldb/lldbengine.cpp | 10 +++++----- src/plugins/debugger/lldb/lldbengine.h | 4 ++-- src/plugins/debugger/pdb/pdbengine.cpp | 8 ++++---- src/plugins/debugger/pdb/pdbengine.h | 4 ++-- src/plugins/debugger/qml/qmlengine.cpp | 4 ++-- src/plugins/debugger/qml/qmlengine.h | 4 ++-- 12 files changed, 49 insertions(+), 48 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 450d36b8f04..8400eee7510 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1441,15 +1441,16 @@ void CdbEngine::reloadModules() runCommand({"modules", ExtensionCommand, CB(handleModules)}); } -void CdbEngine::loadSymbols(const QString & /* moduleName */) +void CdbEngine::loadSymbols(const FilePath &moduleName) { + Q_UNUSED(moduleName) } void CdbEngine::loadAllSymbols() { } -void CdbEngine::requestModuleSymbols(const QString &moduleName) +void CdbEngine::requestModuleSymbols(const FilePath &moduleName) { Q_UNUSED(moduleName) } diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 3bea692d5b5..a231ce39c23 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -65,9 +65,9 @@ public: void changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data) override; void reloadModules() override; - void loadSymbols(const QString &moduleName) override; + void loadSymbols(const Utils::FilePath &moduleName) override; void loadAllSymbols() override; - void requestModuleSymbols(const QString &moduleName) override; + void requestModuleSymbols(const Utils::FilePath &moduleName) override; void reloadRegisters() override; void reloadSourceFiles() override; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index a9609584c6e..5a465e2798b 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2083,7 +2083,7 @@ void DebuggerEngine::examineModules() { } -void DebuggerEngine::loadSymbols(const QString &) +void DebuggerEngine::loadSymbols(const FilePath &) { } @@ -2095,11 +2095,11 @@ void DebuggerEngine::loadSymbolsForStack() { } -void DebuggerEngine::requestModuleSymbols(const QString &) +void DebuggerEngine::requestModuleSymbols(const FilePath &) { } -void DebuggerEngine::requestModuleSections(const QString &) +void DebuggerEngine::requestModuleSections(const FilePath &) { } @@ -2652,7 +2652,7 @@ static void createNewDock(QWidget *widget) dockWidget->show(); } -void DebuggerEngine::showModuleSymbols(const QString &moduleName, const Symbols &symbols) +void DebuggerEngine::showModuleSymbols(const FilePath &moduleName, const Symbols &symbols) { auto w = new QTreeWidget; w->setUniformRowHeights(true); @@ -2660,7 +2660,7 @@ void DebuggerEngine::showModuleSymbols(const QString &moduleName, const Symbols w->setRootIsDecorated(false); w->setAlternatingRowColors(true); w->setSortingEnabled(true); - w->setObjectName("Symbols." + moduleName); + w->setObjectName("Symbols." + moduleName.toFSPathString()); QStringList header; header.append(Tr::tr("Symbol")); header.append(Tr::tr("Address")); @@ -2668,7 +2668,7 @@ void DebuggerEngine::showModuleSymbols(const QString &moduleName, const Symbols header.append(Tr::tr("Section")); header.append(Tr::tr("Name")); w->setHeaderLabels(header); - w->setWindowTitle(Tr::tr("Symbols in \"%1\"").arg(moduleName)); + w->setWindowTitle(Tr::tr("Symbols in \"%1\"").arg(moduleName.toUserOutput())); for (const Symbol &s : symbols) { auto it = new QTreeWidgetItem; it->setData(0, Qt::DisplayRole, s.name); @@ -2681,7 +2681,7 @@ void DebuggerEngine::showModuleSymbols(const QString &moduleName, const Symbols createNewDock(w); } -void DebuggerEngine::showModuleSections(const QString &moduleName, const Sections §ions) +void DebuggerEngine::showModuleSections(const FilePath &moduleName, const Sections §ions) { auto w = new QTreeWidget; w->setUniformRowHeights(true); @@ -2689,7 +2689,7 @@ void DebuggerEngine::showModuleSections(const QString &moduleName, const Section w->setRootIsDecorated(false); w->setAlternatingRowColors(true); w->setSortingEnabled(true); - w->setObjectName("Sections." + moduleName); + w->setObjectName("Sections." + moduleName.toFSPathString()); QStringList header; header.append(Tr::tr("Name")); header.append(Tr::tr("From")); @@ -2697,7 +2697,7 @@ void DebuggerEngine::showModuleSections(const QString &moduleName, const Section header.append(Tr::tr("Address")); header.append(Tr::tr("Flags")); w->setHeaderLabels(header); - w->setWindowTitle(Tr::tr("Sections in \"%1\"").arg(moduleName)); + w->setWindowTitle(Tr::tr("Sections in \"%1\"").arg(moduleName.toUserOutput())); for (const Section &s : sections) { auto it = new QTreeWidgetItem; it->setData(0, Qt::DisplayRole, s.name); diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 422d4eb788c..c07ce656da8 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -303,11 +303,11 @@ public: virtual void reloadModules(); virtual void examineModules(); - virtual void loadSymbols(const QString &moduleName); + virtual void loadSymbols(const Utils::FilePath &moduleName); virtual void loadSymbolsForStack(); virtual void loadAllSymbols(); - virtual void requestModuleSymbols(const QString &moduleName); - virtual void requestModuleSections(const QString &moduleName); + virtual void requestModuleSymbols(const Utils::FilePath &moduleName); + virtual void requestModuleSections(const Utils::FilePath &moduleName); virtual void reloadRegisters(); virtual void reloadPeripheralRegisters(); @@ -452,8 +452,8 @@ public: void openMemoryEditor(); - static void showModuleSymbols(const QString &moduleName, const QVector &symbols); - static void showModuleSections(const QString &moduleName, const QVector
§ions); + static void showModuleSymbols(const Utils::FilePath &moduleName, const QVector &symbols); + static void showModuleSections(const Utils::FilePath &moduleName, const QVector
§ions); void handleExecDetach(); void handleExecContinue(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index de3c075fe3f..bf9647e2203 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -2783,10 +2783,10 @@ static QString dotEscape(QString str) return str; } -void GdbEngine::loadSymbols(const QString &modulePath) +void GdbEngine::loadSymbols(const FilePath &modulePath) { // FIXME: gdb does not understand quoted names here (tested with 6.8) - runCommand({"sharedlibrary " + dotEscape(modulePath)}); + runCommand({"sharedlibrary " + dotEscape(modulePath.path())}); reloadModulesInternal(); reloadStack(); updateLocals(); @@ -2824,7 +2824,7 @@ void GdbEngine::loadSymbolsForStack() } static void handleShowModuleSymbols(const DebuggerResponse &response, - const QString &modulePath, const QString &fileName) + const FilePath &modulePath, const QString &fileName) { if (response.resultClass == ResultDone) { Symbols symbols; @@ -2883,21 +2883,21 @@ static void handleShowModuleSymbols(const DebuggerResponse &response, } } -void GdbEngine::requestModuleSymbols(const QString &modulePath) +void GdbEngine::requestModuleSymbols(const FilePath &modulePath) { - Utils::TemporaryFile tf("gdbsymbols"); + TemporaryFile tf("gdbsymbols"); if (!tf.open()) return; QString fileName = tf.fileName(); tf.close(); - DebuggerCommand cmd("maint print msymbols \"" + fileName + "\" " + modulePath, NeedsTemporaryStop); + DebuggerCommand cmd("maint print msymbols \"" + fileName + "\" " + modulePath.path(), NeedsTemporaryStop); cmd.callback = [modulePath, fileName](const DebuggerResponse &r) { handleShowModuleSymbols(r, modulePath, fileName); }; runCommand(cmd); } -void GdbEngine::requestModuleSections(const QString &moduleName) +void GdbEngine::requestModuleSections(const FilePath &moduleName) { // There seems to be no way to get the symbols from a single .so. DebuggerCommand cmd("maint info section ALLOBJ", NeedsTemporaryStop); @@ -2908,14 +2908,14 @@ void GdbEngine::requestModuleSections(const QString &moduleName) } void GdbEngine::handleShowModuleSections(const DebuggerResponse &response, - const QString &moduleName) + const FilePath &moduleName) { // ~" Object file: /usr/lib/i386-linux-gnu/libffi.so.6\n" // ~" 0xb44a6114->0xb44a6138 at 0x00000114: .note.gnu.build-id ALLOC LOAD READONLY DATA HAS_CONTENTS\n" if (response.resultClass == ResultDone) { const QStringList lines = response.consoleStreamOutput.split('\n'); const QString prefix = " Object file: "; - const QString needle = prefix + moduleName; + const QString needle = prefix + moduleName.path(); Sections sections; bool active = false; for (const QString &line : std::as_const(lines)) { diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index cd3a21ffbde..9fac0347eb3 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -216,17 +216,17 @@ private: ////////// General Interface ////////// // // Modules specific stuff // - void loadSymbols(const QString &moduleName) final; + void loadSymbols(const Utils::FilePath &moduleName) final; void loadAllSymbols() final; void loadSymbolsForStack() final; - void requestModuleSymbols(const QString &moduleName) final; - void requestModuleSections(const QString &moduleName) final; + void requestModuleSymbols(const Utils::FilePath &moduleName) final; + void requestModuleSections(const Utils::FilePath &moduleName) final; void reloadModules() final; void examineModules() final; void reloadModulesInternal(); void handleModulesList(const DebuggerResponse &response); - void handleShowModuleSections(const DebuggerResponse &response, const QString &moduleName); + void handleShowModuleSections(const DebuggerResponse &response, const Utils::FilePath &moduleName); // // Snapshot specific stuff diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 5de46911576..8912375477c 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -630,7 +630,7 @@ void LldbEngine::handleInterpreterBreakpointModified(const GdbMi &bpItem) updateBreakpointData(bp, bpItem, false); } -void LldbEngine::loadSymbols(const QString &moduleName) +void LldbEngine::loadSymbols(const FilePath &moduleName) { Q_UNUSED(moduleName) } @@ -660,13 +660,13 @@ void LldbEngine::reloadModules() runCommand(cmd); } -void LldbEngine::requestModuleSymbols(const QString &moduleName) +void LldbEngine::requestModuleSymbols(const FilePath &moduleName) { DebuggerCommand cmd("fetchSymbols"); - cmd.arg("module", moduleName); + cmd.arg("module", moduleName.path()); cmd.callback = [moduleName](const DebuggerResponse &response) { const GdbMi &symbols = response.data["symbols"]; - QString moduleName = response.data["module"].data(); + const QString module = response.data["module"].data(); Symbols syms; for (const GdbMi &item : symbols) { Symbol symbol; @@ -677,7 +677,7 @@ void LldbEngine::requestModuleSymbols(const QString &moduleName) symbol.demangled = item["demangled"].data(); syms.append(symbol); } - showModuleSymbols(moduleName, syms); + showModuleSymbols(moduleName.withNewPath(module), syms); }; runCommand(cmd); } diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 0a0d9adfb55..8c0396ba509 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -68,9 +68,9 @@ private: void assignValueInDebugger(WatchItem *item, const QString &expr, const QVariant &value) override; void executeDebuggerCommand(const QString &command) override; - void loadSymbols(const QString &moduleName) override; + void loadSymbols(const Utils::FilePath &moduleName) override; void loadAllSymbols() override; - void requestModuleSymbols(const QString &moduleName) override; + void requestModuleSymbols(const Utils::FilePath &moduleName) override; void reloadModules() override; void reloadRegisters() override; void reloadSourceFiles() override {} diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index fd749a2d0ce..a8766691147 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -263,7 +263,7 @@ void PdbEngine::removeBreakpoint(const Breakpoint &bp) notifyBreakpointRemoveOk(bp); } -void PdbEngine::loadSymbols(const QString &moduleName) +void PdbEngine::loadSymbols(const FilePath &moduleName) { Q_UNUSED(moduleName) } @@ -300,10 +300,10 @@ void PdbEngine::refreshModules(const GdbMi &modules) handler->endUpdateAll(); } -void PdbEngine::requestModuleSymbols(const QString &moduleName) +void PdbEngine::requestModuleSymbols(const FilePath &moduleName) { DebuggerCommand cmd("listSymbols"); - cmd.arg("module", moduleName); + cmd.arg("module", moduleName.path()); runCommand(cmd); } @@ -341,7 +341,7 @@ void PdbEngine::refreshSymbols(const GdbMi &symbols) symbol.name = item["name"].data(); syms.append(symbol); } - showModuleSymbols(moduleName, syms); + showModuleSymbols(runParameters().inferior.command.executable().withNewPath(moduleName), syms); } bool PdbEngine::canHandleToolTip(const DebuggerToolTipContext &) const diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index d65f0e33b1c..c4003884578 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -52,9 +52,9 @@ private: const QString &expr, const QVariant &value) override; void executeDebuggerCommand(const QString &command) override; - void loadSymbols(const QString &moduleName) override; + void loadSymbols(const Utils::FilePath &moduleName) override; void loadAllSymbols() override; - void requestModuleSymbols(const QString &moduleName) override; + void requestModuleSymbols(const Utils::FilePath &moduleName) override; void reloadModules() override; void reloadRegisters() override {} void reloadSourceFiles() override {} diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index c0cf98cfb4a..eb1ebc939a8 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -736,7 +736,7 @@ bool QmlEngine::acceptsBreakpoint(const BreakpointParameters &bp) const return bp.isQmlFileAndLineBreakpoint(); } -void QmlEngine::loadSymbols(const QString &moduleName) +void QmlEngine::loadSymbols(const FilePath &moduleName) { Q_UNUSED(moduleName) } @@ -759,7 +759,7 @@ void QmlEngine::updateAll() d->updateLocals(); } -void QmlEngine::requestModuleSymbols(const QString &moduleName) +void QmlEngine::requestModuleSymbols(const FilePath &moduleName) { Q_UNUSED(moduleName) } diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 331176d4269..bfdc9bfb005 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -75,9 +75,9 @@ private: void assignValueInDebugger(WatchItem *item, const QString &expr, const QVariant &value) override; - void loadSymbols(const QString &moduleName) override; + void loadSymbols(const Utils::FilePath &moduleName) override; void loadAllSymbols() override; - void requestModuleSymbols(const QString &moduleName) override; + void requestModuleSymbols(const Utils::FilePath &moduleName) override; void reloadModules() override; void reloadRegisters() override {} void reloadSourceFiles() override; From dd4235eb35d9651f7a8eb59dfc82d12f8e5709c4 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 14 Mar 2023 09:53:03 +0100 Subject: [PATCH 0268/1447] CppEditor: Verify proper highlighting of the concept keyword Change-Id: I1c814da472f10539f87640a52822b188b9b7a2cd Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz --- src/plugins/cppeditor/cpphighlighter.cpp | 1 + src/plugins/cppeditor/testcases/highlightingtestcase.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 1f83b317ada..0f9184600b8 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -513,6 +513,7 @@ void CppHighlighterTest::test_data() QTest::newRow("struct keyword") << 25 << 1 << 25 << 6 << C_KEYWORD; QTest::newRow("operator keyword") << 26 << 5 << 26 << 12 << C_KEYWORD; QTest::newRow("type in conversion operator") << 26 << 14 << 26 << 16 << C_PRIMITIVE_TYPE; + QTest::newRow("concept keyword") << 29 << 22 << 29 << 28 << C_KEYWORD; } void CppHighlighterTest::test() diff --git a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp index 20fa2526467..770b22e553e 100644 --- a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp +++ b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp @@ -25,3 +25,5 @@ template class C; struct ConversionFunction { operator int(); }; + +template concept NoConstraint = true; From b6a593e4f9dcfeb48c9c080a67aa88a346699fbe Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Feb 2023 16:04:59 +0100 Subject: [PATCH 0269/1447] ProjectExplorer: Add a generic copy step Change-Id: I6b4a70e3f71776f7009c0419c8d2f41dfd1c704d Reviewed-by: Jarek Kobus --- src/plugins/projectexplorer/CMakeLists.txt | 1 + src/plugins/projectexplorer/copystep.cpp | 114 ++++++++++++++++++ src/plugins/projectexplorer/copystep.h | 22 ++++ .../projectexplorer/projectexplorer.cpp | 3 + .../projectexplorer/projectexplorer.qbs | 1 + 5 files changed, 141 insertions(+) create mode 100644 src/plugins/projectexplorer/copystep.cpp create mode 100644 src/plugins/projectexplorer/copystep.h diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index deacbc57c56..b14cb87a5ff 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -28,6 +28,7 @@ add_qtc_plugin(ProjectExplorer codestylesettingspropertiespage.cpp codestylesettingspropertiespage.h compileoutputwindow.cpp compileoutputwindow.h configtaskhandler.cpp configtaskhandler.h + copystep.cpp copystep.h copytaskhandler.cpp copytaskhandler.h currentprojectfilter.cpp currentprojectfilter.h currentprojectfind.cpp currentprojectfind.h diff --git a/src/plugins/projectexplorer/copystep.cpp b/src/plugins/projectexplorer/copystep.cpp new file mode 100644 index 00000000000..b07c28b3cfd --- /dev/null +++ b/src/plugins/projectexplorer/copystep.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "copystep.h" + +#include "projectexplorertr.h" + +#include + +using namespace Utils; + +namespace ProjectExplorer::Internal { + +const char SOURCE_KEY[] = "ProjectExplorer.CopyStep.Source"; +const char TARGET_KEY[] = "ProjectExplorer.CopyStep.Target"; + +class CopyStepBase : public BuildStep +{ +public: + CopyStepBase(BuildStepList *bsl, Id id) + : BuildStep(bsl, id) + { + m_sourceAspect = addAspect(); + m_sourceAspect->setSettingsKey(SOURCE_KEY); + m_sourceAspect->setDisplayStyle(StringAspect::PathChooserDisplay); + m_sourceAspect->setLabelText(Tr::tr("Source:")); + + m_targetAspect = addAspect(); + m_targetAspect->setSettingsKey(TARGET_KEY); + m_targetAspect->setDisplayStyle(StringAspect::PathChooserDisplay); + m_targetAspect->setLabelText(Tr::tr("Target:")); + + addMacroExpander(); + } + +protected: + bool init() final + { + m_source = m_sourceAspect->filePath(); + m_target = m_targetAspect->filePath(); + return m_source.exists(); + } + + void doRun() final + { + // FIXME: asyncCopy does not handle directories yet. + QTC_ASSERT(m_source.isFile(), emit finished(false)); + m_source.asyncCopy(m_target, [this](const expected_str &cont) { + if (!cont) { + addOutput(cont.error(), OutputFormat::ErrorMessage); + addOutput(Tr::tr("Copying failed"), OutputFormat::ErrorMessage); + emit finished(false); + } else { + addOutput(Tr::tr("Copying finished"), OutputFormat::NormalMessage); + emit finished(true); + } + }); + } + + StringAspect *m_sourceAspect; + StringAspect *m_targetAspect; + +private: + FilePath m_source; + FilePath m_target; +}; + +class CopyFileStep final : public CopyStepBase +{ +public: + CopyFileStep(BuildStepList *bsl, Id id) + : CopyStepBase(bsl, id) + { + m_sourceAspect->setExpectedKind(PathChooser::File); + m_targetAspect->setExpectedKind(PathChooser::SaveFile); + + setSummaryUpdater([] { + return QString("" + Tr::tr("Copy file") + ""); + }); + } +}; + +class CopyDirectoryStep final : public CopyStepBase +{ +public: + CopyDirectoryStep(BuildStepList *bsl, Id id) + : CopyStepBase(bsl, id) + { + m_sourceAspect->setExpectedKind(PathChooser::Directory); + m_targetAspect->setExpectedKind(PathChooser::Directory); + + setSummaryUpdater([] { + return QString("" + Tr::tr("Copy directory recursively") + ""); + }); + } +}; + +// Factories + +CopyFileStepFactory::CopyFileStepFactory() +{ + registerStep("ProjectExplorer.CopyFileStep"); + //: Default CopyStep display name + setDisplayName(Tr::tr("Copy file")); +} + +CopyDirectoryStepFactory::CopyDirectoryStepFactory() +{ + registerStep("ProjectExplorer.CopyDirectoryStep"); + //: Default CopyStep display name + setDisplayName(Tr::tr("Copy directory recursively")); +} + +} // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/copystep.h b/src/plugins/projectexplorer/copystep.h new file mode 100644 index 00000000000..07940f3a89a --- /dev/null +++ b/src/plugins/projectexplorer/copystep.h @@ -0,0 +1,22 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "buildstep.h" + +namespace ProjectExplorer::Internal { + +class CopyFileStepFactory final : public BuildStepFactory +{ +public: + CopyFileStepFactory(); +}; + +class CopyDirectoryStepFactory final : public BuildStepFactory +{ +public: + CopyDirectoryStepFactory(); +}; + +} // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 3834593a63e..25aae3385c2 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -8,6 +8,7 @@ #include "buildsystem.h" #include "compileoutputwindow.h" #include "configtaskhandler.h" +#include "copystep.h" #include "customexecutablerunconfiguration.h" #include "customparserssettingspage.h" #include "customwizard/customwizard.h" @@ -680,6 +681,8 @@ public: RunRunConfigurationLocatorFilter m_runConfigurationLocatorFilter; SwitchToRunConfigurationLocatorFilter m_switchRunConfigurationLocatorFilter; + CopyFileStepFactory m_copyFileStepFactory; + CopyDirectoryStepFactory m_copyDirectoryFactory; ProcessStepFactory m_processStepFactory; AllProjectsFind m_allProjectsFind; diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 27be767db9c..e7d3d76b794 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -45,6 +45,7 @@ Project { "codestylesettingspropertiespage.cpp", "codestylesettingspropertiespage.h", "compileoutputwindow.cpp", "compileoutputwindow.h", "configtaskhandler.cpp", "configtaskhandler.h", + "copystep.cpp", "copystep.h", "copytaskhandler.cpp", "copytaskhandler.h", "currentprojectfilter.cpp", "currentprojectfilter.h", "currentprojectfind.cpp", "currentprojectfind.h", From 2d15be91bf8bab5ce5307b6e16ca1c13ecbdcf8f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 10 Mar 2023 16:29:41 +0100 Subject: [PATCH 0270/1447] ProjectExplorer: Consolidate ProcessList * Combined local and ssh process list retrieval into LocalProcessList * Combined QnxProcessList into LocalProcessList * Renamed LocalProcessList to ProcessList Change-Id: I230c575375e306c638e4ca3034fa2d7ed243a44c Reviewed-by: David Schulz Reviewed-by: hjk --- src/libs/utils/processinfo.cpp | 175 +++++++++++------- src/libs/utils/processinfo.h | 4 +- src/plugins/docker/dockerdevice.cpp | 9 +- src/plugins/docker/dockerdevice.h | 2 +- src/plugins/projectexplorer/CMakeLists.txt | 3 +- .../devicesupport/desktopdevice.cpp | 8 +- .../devicesupport/localprocesslist.cpp | 59 ------ .../devicesupport/processlist.cpp | 61 ++++++ .../{localprocesslist.h => processlist.h} | 10 +- .../devicesupport/sshdeviceprocesslist.cpp | 83 --------- .../devicesupport/sshdeviceprocesslist.h | 36 ---- .../projectexplorer/projectexplorer.qbs | 3 +- src/plugins/qnx/CMakeLists.txt | 1 - src/plugins/qnx/qnx.qbs | 2 - src/plugins/qnx/qnxdevice.cpp | 6 - src/plugins/qnx/qnxdevice.h | 1 - src/plugins/qnx/qnxdeviceprocesslist.cpp | 59 ------ src/plugins/qnx/qnxdeviceprocesslist.h | 21 --- src/plugins/remotelinux/linuxdevice.cpp | 78 +------- 19 files changed, 188 insertions(+), 433 deletions(-) delete mode 100644 src/plugins/projectexplorer/devicesupport/localprocesslist.cpp create mode 100644 src/plugins/projectexplorer/devicesupport/processlist.cpp rename src/plugins/projectexplorer/devicesupport/{localprocesslist.h => processlist.h} (66%) delete mode 100644 src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp delete mode 100644 src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h delete mode 100644 src/plugins/qnx/qnxdeviceprocesslist.cpp delete mode 100644 src/plugins/qnx/qnxdeviceprocesslist.h diff --git a/src/libs/utils/processinfo.cpp b/src/libs/utils/processinfo.cpp index 366800d3161..d6ecd4d2344 100644 --- a/src/libs/utils/processinfo.cpp +++ b/src/libs/utils/processinfo.cpp @@ -3,14 +3,13 @@ #include "processinfo.h" +#include "algorithm.h" #include "qtcprocess.h" -#if defined(Q_OS_UNIX) #include -#include -#include -#include -#include +#include + +#if defined(Q_OS_UNIX) #elif defined(Q_OS_WIN) #include "winutils.h" #ifdef QTCREATOR_PCH_H @@ -32,82 +31,64 @@ bool ProcessInfo::operator<(const ProcessInfo &other) const return commandLine < other.commandLine; } -#if defined(Q_OS_UNIX) - -static bool isUnixProcessId(const QString &procname) -{ - for (int i = 0; i != procname.size(); ++i) - if (!procname.at(i).isDigit()) - return false; - return true; -} - // Determine UNIX processes by reading "/proc". Default to ps if // it does not exist -static const char procDirC[] = "/proc/"; - -static QList getLocalProcessesUsingProc() +static QList getLocalProcessesUsingProc(const FilePath &procDir) { + static const QString execs = "-exec test -f {}/exe \\; " + "-exec test -f {}/cmdline \\; " + "-exec echo -en 'p{}\\ne' \\; " + "-exec readlink {}/exe \\; " + "-exec echo -n c \\; " + "-exec head -n 1 {}/cmdline \\; " + "-exec echo \\; " + "-exec echo __SKIP_ME__ \\;"; + + CommandLine cmd{procDir.withNewPath("find"), + {procDir.nativePath(), "-maxdepth", "1", "-type", "d", "-name", "[0-9]*"}}; + + cmd.addArgs(execs, CommandLine::Raw); + + QtcProcess procProcess; + procProcess.setCommand(cmd); + procProcess.runBlocking(); + QList processes; - const QString procDirPath = QLatin1String(procDirC); - const QDir procDir = QDir(QLatin1String(procDirC)); - const QStringList procIds = procDir.entryList(); - for (const QString &procId : procIds) { - if (!isUnixProcessId(procId)) - continue; - ProcessInfo proc; - proc.processId = procId.toInt(); - const QString root = procDirPath + procId; - const QFile exeFile(root + QLatin1String("/exe")); - proc.executable = exeFile.symLinkTarget(); + const auto lines = procProcess.readAllStandardOutput().split('\n'); + for (auto it = lines.begin(); it != lines.end(); ++it) { + if (it->startsWith('p')) { + ProcessInfo proc; + bool ok; + proc.processId = FilePath::fromUserInput(it->mid(1).trimmed()).fileName().toInt(&ok); + QTC_ASSERT(ok, continue); + ++it; - QFile cmdLineFile(root + QLatin1String("/cmdline")); - if (cmdLineFile.open(QIODevice::ReadOnly)) { // process may have exited - const QList tokens = cmdLineFile.readAll().split('\0'); - if (!tokens.isEmpty()) { - if (proc.executable.isEmpty()) - proc.executable = QString::fromLocal8Bit(tokens.front()); - for (const QByteArray &t : tokens) { - if (!proc.commandLine.isEmpty()) - proc.commandLine.append(QLatin1Char(' ')); - proc.commandLine.append(QString::fromLocal8Bit(t)); - } - } + QTC_ASSERT(it->startsWith('e'), continue); + proc.executable = it->mid(1).trimmed(); + ++it; + + QTC_ASSERT(it->startsWith('c'), continue); + proc.commandLine = it->mid(1).trimmed().replace('\0', ' '); + if (!proc.commandLine.contains("__SKIP_ME__")) + processes.append(proc); } - - if (proc.executable.isEmpty()) { - QFile statFile(root + QLatin1String("/stat")); - if (statFile.open(QIODevice::ReadOnly)) { - const QStringList data = QString::fromLocal8Bit(statFile.readAll()).split(QLatin1Char(' ')); - if (data.size() < 2) - continue; - proc.executable = data.at(1); - proc.commandLine = data.at(1); // PPID is element 3 - if (proc.executable.startsWith(QLatin1Char('(')) && proc.executable.endsWith(QLatin1Char(')'))) { - proc.executable.truncate(proc.executable.size() - 1); - proc.executable.remove(0, 1); - } - } - } - if (!proc.executable.isEmpty()) - processes.push_back(proc); } + return processes; } // Determine UNIX processes by running ps -static QMap getLocalProcessDataUsingPs(const QString &column) +static QMap getLocalProcessDataUsingPs(const FilePath &deviceRoot, + const QString &column) { QtcProcess process; - process.setCommand({"ps", {"-e", "-o", "pid," + column}}); - process.start(); - if (!process.waitForFinished()) - return {}; + process.setCommand({deviceRoot.withNewPath("ps"), {"-e", "-o", "pid," + column}}); + process.runBlocking(); // Split "457 /Users/foo.app arg1 arg2" - const QStringList lines = process.stdOut().split(QLatin1Char('\n')); + const QStringList lines = process.readAllStandardOutput().split(QLatin1Char('\n')); QMap result; for (int i = 1; i < lines.size(); ++i) { // Skip header const QString line = lines.at(i).trimmed(); @@ -118,14 +99,14 @@ static QMap getLocalProcessDataUsingPs(const QString &column) return result; } -static QList getLocalProcessesUsingPs() +static QList getLocalProcessesUsingPs(const FilePath &deviceRoot) { QList processes; // cmdLines are full command lines, usually with absolute path, // exeNames only the file part of the executable's path. - const QMap exeNames = getLocalProcessDataUsingPs("comm"); - const QMap cmdLines = getLocalProcessDataUsingPs("args"); + const QMap exeNames = getLocalProcessDataUsingPs(deviceRoot, "comm"); + const QMap cmdLines = getLocalProcessDataUsingPs(deviceRoot, "args"); for (auto it = exeNames.begin(), end = exeNames.end(); it != end; ++it) { const qint64 pid = it.key(); @@ -146,16 +127,68 @@ static QList getLocalProcessesUsingPs() return processes; } -QList ProcessInfo::processInfoList() +static QList getProcessesUsingPidin(const FilePath &pidin) { - const QDir procDir = QDir(QLatin1String(procDirC)); - return procDir.exists() ? getLocalProcessesUsingProc() : getLocalProcessesUsingPs(); + QtcProcess process; + process.setCommand({pidin, {"-F", "%a %A {/%n}"}}); + process.runBlocking(); + + QList processes; + QStringList lines = process.readAllStandardOutput().split(QLatin1Char('\n')); + if (lines.isEmpty()) + return processes; + + lines.pop_front(); // drop headers + const QRegularExpression re("\\s*(\\d+)\\s+(.*){(.*)}"); + + for (const QString &line : std::as_const(lines)) { + const QRegularExpressionMatch match = re.match(line); + if (match.hasMatch()) { + const QStringList captures = match.capturedTexts(); + if (captures.size() == 4) { + const int pid = captures[1].toInt(); + const QString args = captures[2]; + const QString exe = captures[3]; + ProcessInfo deviceProcess; + deviceProcess.processId = pid; + deviceProcess.executable = exe.trimmed(); + deviceProcess.commandLine = args.trimmed(); + processes.append(deviceProcess); + } + } + } + + return Utils::sorted(std::move(processes)); +} + +static QList processInfoListUnix(const FilePath &deviceRoot) +{ + const FilePath procDir = deviceRoot.withNewPath("/proc"); + const FilePath pidin = deviceRoot.withNewPath("pidin").searchInPath(); + + if (pidin.isExecutableFile()) + return getProcessesUsingPidin(pidin); + + if (procDir.isReadableDir()) + return getLocalProcessesUsingProc(procDir); + + return getLocalProcessesUsingPs(deviceRoot); +} + +#if defined(Q_OS_UNIX) + +QList ProcessInfo::processInfoList(const FilePath &deviceRoot) +{ + return processInfoListUnix(deviceRoot); } #elif defined(Q_OS_WIN) -QList ProcessInfo::processInfoList() +QList ProcessInfo::processInfoList(const FilePath &deviceRoot) { + if (deviceRoot.needsDevice()) + return processInfoListUnix(deviceRoot); + QList processes; PROCESSENTRY32 pe; diff --git a/src/libs/utils/processinfo.h b/src/libs/utils/processinfo.h index 47fd2d6d0de..90c1a97374d 100644 --- a/src/libs/utils/processinfo.h +++ b/src/libs/utils/processinfo.h @@ -5,6 +5,8 @@ #include "utils_global.h" +#include "filepath.h" + #include #include @@ -19,7 +21,7 @@ public: bool operator<(const ProcessInfo &other) const; - static QList processInfoList(); + static QList processInfoList(const Utils::FilePath &deviceRoot = Utils::FilePath()); }; } // namespace Utils diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index a9687352529..9ead5e8c783 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -486,7 +487,7 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, dockerCmd.addArgs({"/bin/sh", "-c"}); CommandLine exec("exec"); - exec.addCommandLineAsArgs(cmd); + exec.addCommandLineAsArgs(cmd, CommandLine::Raw); CommandLine echo("echo"); echo.addArgs("__qtc$$qtc__", CommandLine::Raw); @@ -494,7 +495,7 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, dockerCmd.addCommandLineAsSingleArg(echo); } else { - dockerCmd.addCommandLineAsArgs(cmd); + dockerCmd.addCommandLineAsArgs(cmd, CommandLine::Raw); } return dockerCmd; @@ -792,9 +793,9 @@ PortsGatheringMethod DockerDevice::portsGatheringMethod() const &Port::parseFromSedOutput}; }; -DeviceProcessList *DockerDevice::createProcessListModel(QObject *) const +DeviceProcessList *DockerDevice::createProcessListModel(QObject *parent) const { - return nullptr; + return new ProcessList(sharedFromThis(), parent); } DeviceTester *DockerDevice::createDeviceTester() const diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 3ecc0118d49..38e9956a230 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -75,7 +75,7 @@ public: bool canAutoDetectPorts() const override; ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; - bool canCreateProcessModel() const override { return false; } + bool canCreateProcessModel() const override { return true; } ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override; bool hasDeviceTester() const override { return false; } ProjectExplorer::DeviceTester *createDeviceTester() const override; diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index b14cb87a5ff..491587d7766 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -66,8 +66,7 @@ add_qtc_plugin(ProjectExplorer devicesupport/idevicefactory.cpp devicesupport/idevicefactory.h devicesupport/idevicefwd.h devicesupport/idevicewidget.h - devicesupport/localprocesslist.cpp devicesupport/localprocesslist.h - devicesupport/sshdeviceprocesslist.cpp devicesupport/sshdeviceprocesslist.h + devicesupport/processlist.cpp devicesupport/processlist.h devicesupport/sshparameters.cpp devicesupport/sshparameters.h devicesupport/sshsettings.cpp devicesupport/sshsettings.h devicesupport/sshsettingspage.cpp devicesupport/sshsettingspage.h diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 566b669c393..724b6608aad 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -3,11 +3,11 @@ #include "desktopdevice.h" -#include "desktopprocesssignaloperation.h" -#include "deviceprocesslist.h" -#include "localprocesslist.h" #include "../projectexplorerconstants.h" #include "../projectexplorertr.h" +#include "desktopprocesssignaloperation.h" +#include "deviceprocesslist.h" +#include "processlist.h" #include @@ -137,7 +137,7 @@ bool DesktopDevice::canCreateProcessModel() const DeviceProcessList *DesktopDevice::createProcessListModel(QObject *parent) const { - return new Internal::LocalProcessList(sharedFromThis(), parent); + return new ProcessList(sharedFromThis(), parent); } DeviceProcessSignalOperation::Ptr DesktopDevice::signalOperation() const diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp deleted file mode 100644 index c6fd49012fb..00000000000 --- a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "localprocesslist.h" - -#include -#include - -#include - -#if defined(Q_OS_UNIX) -#include -#elif defined(Q_OS_WIN) -#include -#endif - -using namespace Utils; - -namespace ProjectExplorer { -namespace Internal { - -LocalProcessList::LocalProcessList(const IDevice::ConstPtr &device, QObject *parent) - : DeviceProcessList(device, parent) -{ -#if defined(Q_OS_UNIX) - setOwnPid(getpid()); -#elif defined(Q_OS_WIN) - setOwnPid(GetCurrentProcessId()); -#endif -} - -void LocalProcessList::doKillProcess(const ProcessInfo &processInfo) -{ - DeviceProcessSignalOperation::Ptr signalOperation = device()->signalOperation(); - connect(signalOperation.data(), &DeviceProcessSignalOperation::finished, - this, &LocalProcessList::reportDelayedKillStatus); - signalOperation->killProcess(processInfo.processId); -} - -void LocalProcessList::handleUpdate() -{ - reportProcessListUpdated(ProcessInfo::processInfoList()); -} - -void LocalProcessList::doUpdate() -{ - QTimer::singleShot(0, this, &LocalProcessList::handleUpdate); -} - -void LocalProcessList::reportDelayedKillStatus(const QString &errorMessage) -{ - if (errorMessage.isEmpty()) - reportProcessKilled(); - else - reportError(errorMessage); -} - -} // namespace Internal -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/processlist.cpp b/src/plugins/projectexplorer/devicesupport/processlist.cpp new file mode 100644 index 00000000000..11e0932832d --- /dev/null +++ b/src/plugins/projectexplorer/devicesupport/processlist.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "processlist.h" + +#include +#include + +#include + +#if defined(Q_OS_UNIX) +#include +#elif defined(Q_OS_WIN) +#include +#endif + +using namespace Utils; + +namespace ProjectExplorer { + +ProcessList::ProcessList(const IDevice::ConstPtr &device, QObject *parent) + : DeviceProcessList(device, parent) +{ +#if defined(Q_OS_UNIX) + setOwnPid(getpid()); +#elif defined(Q_OS_WIN) + setOwnPid(GetCurrentProcessId()); +#endif +} + +void ProcessList::doKillProcess(const ProcessInfo &processInfo) +{ + m_signalOperation = device()->signalOperation(); + connect(m_signalOperation.data(), + &DeviceProcessSignalOperation::finished, + this, + &ProcessList::reportDelayedKillStatus); + m_signalOperation->killProcess(processInfo.processId); +} + +void ProcessList::handleUpdate() +{ + reportProcessListUpdated(ProcessInfo::processInfoList(DeviceProcessList::device()->rootPath())); +} + +void ProcessList::doUpdate() +{ + QTimer::singleShot(0, this, &ProcessList::handleUpdate); +} + +void ProcessList::reportDelayedKillStatus(const QString &errorMessage) +{ + if (errorMessage.isEmpty()) + reportProcessKilled(); + else + reportError(errorMessage); + + m_signalOperation.reset(); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.h b/src/plugins/projectexplorer/devicesupport/processlist.h similarity index 66% rename from src/plugins/projectexplorer/devicesupport/localprocesslist.h rename to src/plugins/projectexplorer/devicesupport/processlist.h index e3445f47b20..caebaf22f97 100644 --- a/src/plugins/projectexplorer/devicesupport/localprocesslist.h +++ b/src/plugins/projectexplorer/devicesupport/processlist.h @@ -4,16 +4,16 @@ #pragma once #include "deviceprocesslist.h" +#include "idevice.h" namespace ProjectExplorer { -namespace Internal { -class LocalProcessList : public DeviceProcessList +class PROJECTEXPLORER_EXPORT ProcessList : public DeviceProcessList { Q_OBJECT public: - explicit LocalProcessList(const IDeviceConstPtr &device, QObject *parent = nullptr); + explicit ProcessList(const IDeviceConstPtr &device, QObject *parent = nullptr); private: void doUpdate() override; @@ -22,7 +22,9 @@ private: private: void handleUpdate(); void reportDelayedKillStatus(const QString &errorMessage); + +private: + DeviceProcessSignalOperation::Ptr m_signalOperation; }; -} // namespace Internal } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp deleted file mode 100644 index d64cde6e3ed..00000000000 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "sshdeviceprocesslist.h" - -#include "idevice.h" -#include "../projectexplorertr.h" - -#include -#include -#include -#include - -using namespace Utils; - -namespace ProjectExplorer { - -class SshDeviceProcessListPrivate -{ -public: - QtcProcess m_process; - DeviceProcessSignalOperation::Ptr m_signalOperation; -}; - -SshDeviceProcessList::SshDeviceProcessList(const IDevice::ConstPtr &device, QObject *parent) : - DeviceProcessList(device, parent), d(std::make_unique()) -{ - connect(&d->m_process, &QtcProcess::done, this, &SshDeviceProcessList::handleProcessDone); -} - -SshDeviceProcessList::~SshDeviceProcessList() = default; - -void SshDeviceProcessList::doUpdate() -{ - d->m_process.close(); - d->m_process.setCommand({device()->filePath("/bin/sh"), {"-c", listProcessesCommandLine()}}); - d->m_process.start(); -} - -void SshDeviceProcessList::doKillProcess(const ProcessInfo &process) -{ - d->m_signalOperation = device()->signalOperation(); - QTC_ASSERT(d->m_signalOperation, return); - connect(d->m_signalOperation.data(), &DeviceProcessSignalOperation::finished, - this, &SshDeviceProcessList::handleKillProcessFinished); - d->m_signalOperation->killProcess(process.processId); -} - -void SshDeviceProcessList::handleProcessDone() -{ - if (d->m_process.result() == ProcessResult::FinishedWithSuccess) { - reportProcessListUpdated(buildProcessList(d->m_process.cleanedStdOut())); - } else { - const QString errorString = d->m_process.exitStatus() == QProcess::NormalExit - ? Tr::tr("Process listing command failed with exit code %1.").arg(d->m_process.exitCode()) - : d->m_process.errorString(); - const QString stdErr = d->m_process.cleanedStdErr(); - const QString outputString - = stdErr.isEmpty() ? stdErr : Tr::tr("Remote stderr was: %1").arg(stdErr); - reportError(Utils::joinStrings({errorString, outputString}, '\n')); - } - setFinished(); -} - -void SshDeviceProcessList::handleKillProcessFinished(const QString &errorString) -{ - if (errorString.isEmpty()) - reportProcessKilled(); - else - reportError(Tr::tr("Error: Kill process failed: %1").arg(errorString)); - setFinished(); -} - -void SshDeviceProcessList::setFinished() -{ - d->m_process.close(); - if (d->m_signalOperation) { - d->m_signalOperation->disconnect(this); - d->m_signalOperation.clear(); - } -} - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h deleted file mode 100644 index fd560f53755..00000000000 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "deviceprocesslist.h" - -#include - -namespace ProjectExplorer { - -class SshDeviceProcessListPrivate; - -class PROJECTEXPLORER_EXPORT SshDeviceProcessList : public DeviceProcessList -{ - Q_OBJECT -public: - explicit SshDeviceProcessList(const IDeviceConstPtr &device, QObject *parent = nullptr); - ~SshDeviceProcessList() override; - -private: - void handleProcessDone(); - void handleKillProcessFinished(const QString &errorString); - - virtual QString listProcessesCommandLine() const = 0; - virtual QList buildProcessList(const QString &listProcessesReply) const = 0; - - void doUpdate() override; - void doKillProcess(const Utils::ProcessInfo &process) override; - - void setFinished(); - - const std::unique_ptr d; -}; - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index e7d3d76b794..315a8d361e0 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -227,8 +227,7 @@ Project { "idevicefactory.cpp", "idevicefactory.h", "idevicefwd.h", "idevicewidget.h", - "localprocesslist.cpp", "localprocesslist.h", - "sshdeviceprocesslist.cpp", "sshdeviceprocesslist.h", + "processlist.cpp", "processlist.h", "sshparameters.cpp", "sshparameters.h", "sshsettings.cpp", "sshsettings.h", "sshsettingspage.cpp", "sshsettingspage.h", diff --git a/src/plugins/qnx/CMakeLists.txt b/src/plugins/qnx/CMakeLists.txt index 2c0e77cee8c..2de34ae95f8 100644 --- a/src/plugins/qnx/CMakeLists.txt +++ b/src/plugins/qnx/CMakeLists.txt @@ -10,7 +10,6 @@ add_qtc_plugin(Qnx qnxdebugsupport.cpp qnxdebugsupport.h qnxdeployqtlibrariesdialog.cpp qnxdeployqtlibrariesdialog.h qnxdevice.cpp qnxdevice.h - qnxdeviceprocesslist.cpp qnxdeviceprocesslist.h qnxdevicetester.cpp qnxdevicetester.h qnxdevicewizard.cpp qnxdevicewizard.h qnxplugin.cpp diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index b9e19ead0b1..e62cc8975ce 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -30,8 +30,6 @@ QtcPlugin { "qnxdevice.h", "qnxdevicewizard.cpp", "qnxdevicewizard.h", - "qnxdeviceprocesslist.cpp", - "qnxdeviceprocesslist.h", "qnxdevicetester.cpp", "qnxdevicetester.h", "qnxconfigurationmanager.cpp", diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 958f09a59e5..4460d5bf00d 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -6,7 +6,6 @@ #include "qnxconstants.h" #include "qnxdeployqtlibrariesdialog.h" #include "qnxdevicetester.h" -#include "qnxdeviceprocesslist.h" #include "qnxdevicewizard.h" #include "qnxtr.h" @@ -121,11 +120,6 @@ PortsGatheringMethod QnxDevice::portsGatheringMethod() const }; } -DeviceProcessList *QnxDevice::createProcessListModel(QObject *parent) const -{ - return new QnxDeviceProcessList(sharedFromThis(), parent); -} - DeviceTester *QnxDevice::createDeviceTester() const { return new QnxDeviceTester; diff --git a/src/plugins/qnx/qnxdevice.h b/src/plugins/qnx/qnxdevice.h index 0ee38912f37..f1deaf6a377 100644 --- a/src/plugins/qnx/qnxdevice.h +++ b/src/plugins/qnx/qnxdevice.h @@ -16,7 +16,6 @@ public: static Ptr create() { return Ptr(new QnxDevice); } ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; - ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; ProjectExplorer::DeviceTester *createDeviceTester() const override; diff --git a/src/plugins/qnx/qnxdeviceprocesslist.cpp b/src/plugins/qnx/qnxdeviceprocesslist.cpp deleted file mode 100644 index 39735329934..00000000000 --- a/src/plugins/qnx/qnxdeviceprocesslist.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qnxdeviceprocesslist.h" - -#include -#include -#include -#include - -#include -#include - -using namespace Utils; - -namespace Qnx::Internal { - -QnxDeviceProcessList::QnxDeviceProcessList( - const ProjectExplorer::IDevice::ConstPtr &device, QObject *parent) - : ProjectExplorer::SshDeviceProcessList(device, parent) -{ -} - -QString QnxDeviceProcessList::listProcessesCommandLine() const -{ - return QLatin1String("pidin -F '%a %A {/%n}'"); -} - -QList QnxDeviceProcessList::buildProcessList(const QString &listProcessesReply) const -{ - QList processes; - QStringList lines = listProcessesReply.split(QLatin1Char('\n')); - if (lines.isEmpty()) - return processes; - - lines.pop_front(); // drop headers - const QRegularExpression re("\\s*(\\d+)\\s+(.*){(.*)}"); - - for (const QString &line : std::as_const(lines)) { - const QRegularExpressionMatch match = re.match(line); - if (match.hasMatch()) { - const QStringList captures = match.capturedTexts(); - if (captures.size() == 4) { - const int pid = captures[1].toInt(); - const QString args = captures[2]; - const QString exe = captures[3]; - ProcessInfo deviceProcess; - deviceProcess.processId = pid; - deviceProcess.executable = exe.trimmed(); - deviceProcess.commandLine = args.trimmed(); - processes.append(deviceProcess); - } - } - } - - return Utils::sorted(std::move(processes)); -} - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxdeviceprocesslist.h b/src/plugins/qnx/qnxdeviceprocesslist.h deleted file mode 100644 index 0e71ae7ab01..00000000000 --- a/src/plugins/qnx/qnxdeviceprocesslist.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Qnx::Internal { - -class QnxDeviceProcessList : public ProjectExplorer::SshDeviceProcessList -{ -public: - explicit QnxDeviceProcessList( - const ProjectExplorer::IDeviceConstPtr &device, QObject *parent = nullptr); - -private: - QString listProcessesCommandLine() const override; - QList buildProcessList(const QString &listProcessesReply) const override; -}; - -} // Qnx::Internal diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index fc3268c892d..345f6e28497 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -51,9 +51,6 @@ namespace RemoteLinux { const QByteArray s_pidMarker = "__qtc"; -const char Delimiter0[] = "x--"; -const char Delimiter1[] = "---"; - static Q_LOGGING_CATEGORY(linuxDeviceLog, "qtc.remotelinux.device", QtWarningMsg); #define DEBUG(x) qCDebug(linuxDeviceLog) << x << '\n' @@ -274,77 +271,6 @@ private: IDevice::ConstPtr m_device; }; -static QString visualizeNull(QString s) -{ - return s.replace(QLatin1Char('\0'), QLatin1String("")); -} - -class LinuxDeviceProcessList : public SshDeviceProcessList -{ -public: - LinuxDeviceProcessList(const IDevice::ConstPtr &device, QObject *parent) - : SshDeviceProcessList(device, parent) - { - } - -private: - QString listProcessesCommandLine() const override - { - return QString::fromLatin1( - "for dir in `ls -d /proc/[0123456789]*`; do " - "test -d $dir || continue;" // Decrease the likelihood of a race condition. - "echo $dir;" - "cat $dir/cmdline;echo;" // cmdline does not end in newline - "cat $dir/stat;" - "readlink $dir/exe;" - "printf '%1''%2';" - "done").arg(QLatin1String(Delimiter0)).arg(QLatin1String(Delimiter1)); - } - - QList buildProcessList(const QString &listProcessesReply) const override - { - QList processes; - const QStringList lines = listProcessesReply.split(QString::fromLatin1(Delimiter0) - + QString::fromLatin1(Delimiter1), Qt::SkipEmptyParts); - for (const QString &line : lines) { - const QStringList elements = line.split(QLatin1Char('\n')); - if (elements.count() < 4) { - qDebug("%s: Expected four list elements, got %d. Line was '%s'.", Q_FUNC_INFO, - int(elements.count()), qPrintable(visualizeNull(line))); - continue; - } - bool ok; - const int pid = elements.first().mid(6).toInt(&ok); - if (!ok) { - qDebug("%s: Expected number in %s. Line was '%s'.", Q_FUNC_INFO, - qPrintable(elements.first()), qPrintable(visualizeNull(line))); - continue; - } - QString command = elements.at(1); - command.replace(QLatin1Char('\0'), QLatin1Char(' ')); - if (command.isEmpty()) { - const QString &statString = elements.at(2); - const int openParenPos = statString.indexOf(QLatin1Char('(')); - const int closedParenPos = statString.indexOf(QLatin1Char(')'), openParenPos); - if (openParenPos == -1 || closedParenPos == -1) - continue; - command = QLatin1Char('[') - + statString.mid(openParenPos + 1, closedParenPos - openParenPos - 1) - + QLatin1Char(']'); - } - - ProcessInfo process; - process.processId = pid; - process.commandLine = command; - process.executable = elements.at(3); - processes.append(process); - } - - return Utils::sorted(std::move(processes)); - } -}; - - // LinuxDevicePrivate class ShellThreadHandler; @@ -1094,7 +1020,7 @@ PortsGatheringMethod LinuxDevice::portsGatheringMethod() const DeviceProcessList *LinuxDevice::createProcessListModel(QObject *parent) const { - return new LinuxDeviceProcessList(sharedFromThis(), parent); + return new ProcessList(sharedFromThis(), parent); } DeviceTester *LinuxDevice::createDeviceTester() const From 8f1cbd2e5212986faa8222c8097d9cab670b03eb Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 13 Mar 2023 13:56:50 +0100 Subject: [PATCH 0271/1447] Utils: Improve and test CommandLine::fromUserInput Change-Id: Ia18f5b01d91200e6ad65735496395215c6393533 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- src/libs/utils/commandline.cpp | 24 +++--- .../utils/commandline/tst_commandline.cpp | 77 +++++++++++++++++++ 2 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 81285259acc..e19eafa4c15 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -1429,16 +1429,20 @@ CommandLine::CommandLine(const FilePath &exe, const QString &args, RawType) CommandLine CommandLine::fromUserInput(const QString &cmdline, MacroExpander *expander) { - CommandLine cmd; - const int pos = cmdline.indexOf(' '); - if (pos == -1) { - cmd.m_executable = FilePath::fromString(cmdline); - } else { - cmd.m_executable = FilePath::fromString(cmdline.left(pos)); - cmd.m_arguments = cmdline.right(cmdline.length() - pos - 1); - if (expander) - cmd.m_arguments = expander->expand(cmd.m_arguments); - } + if (cmdline.isEmpty()) + return {}; + + QString input = cmdline.trimmed(); + + QStringList result = ProcessArgs::splitArgs(cmdline, HostOsInfo::hostOs()); + + if (result.isEmpty()) + return {}; + + auto cmd = CommandLine(FilePath::fromUserInput(result.value(0)), result.mid(1)); + if (expander) + cmd.m_arguments = expander->expand(cmd.m_arguments); + return cmd; } diff --git a/tests/auto/utils/commandline/tst_commandline.cpp b/tests/auto/utils/commandline/tst_commandline.cpp index 05357d2526e..6972ae6ba39 100644 --- a/tests/auto/utils/commandline/tst_commandline.cpp +++ b/tests/auto/utils/commandline/tst_commandline.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +124,82 @@ private slots: QString actual = run(shell); QCOMPARE(actual, expected); } + + void testFromUserInput_data() + { + QTest::addColumn("input"); + QTest::addColumn("executable"); + QTest::addColumn("arguments"); + + QTest::newRow("empty") << "" + << "" + << ""; + QTest::newRow("command") << "command" + << "command" + << ""; + QTest::newRow("command-with-args") << "command and args" + << "command" + << "and args"; + + if (!HostOsInfo::isWindowsHost()) { + QTest::newRow("command-with-space-slash") << "command\\ with-space and args" + << "command with-space" + << "and args"; + QTest::newRow("command-with-space-single-quote") << "'command with-space' and args" + << "command with-space" + << "and args"; + } + QTest::newRow("command-with-space-double-quote") << "\"command with-space\" and args" + << "command with-space" + << "and args"; + + QTest::newRow("command-with-space-double-quote-in-name") + << "\"command\\\"with-quote\" and args" + << "command\"with-quote" + << "and args"; + + QTest::newRow("inside-space-quoted") << "command\" \"withspace args here" + << "command withspace" + << "args here"; + } + + void testFromUserInput() + { + QFETCH(QString, input); + QFETCH(QString, executable); + QFETCH(QString, arguments); + + CommandLine cmd = CommandLine::fromUserInput(input); + QCOMPARE(cmd.executable(), FilePath::fromUserInput(executable)); + QCOMPARE(cmd.arguments(), arguments); + } + + void testFromInputFails() + { + if (HostOsInfo::isWindowsHost()) + QSKIP("The test does not work on Windows."); + + CommandLine cmd = CommandLine::fromUserInput("command\\\\\\ with-space and args"); + QEXPECT_FAIL("", + "CommandLine::fromUserInput (and FilePath::fromUserInput) does not handle " + "backslashes correctly", + Continue); + QCOMPARE(cmd.executable().fileName(), "command\\ with-space"); + QCOMPARE(cmd.arguments(), "and args"); + } + + void testFromInputWithMacro() + { + MacroExpander expander; + expander.registerVariable("hello", "world var", [] { return "hello world"; }); + CommandLine cmd = CommandLine::fromUserInput("command macroarg: %{hello}", &expander); + QCOMPARE(cmd.executable(), "command"); + + if (HostOsInfo::isWindowsHost()) + QEXPECT_FAIL("", "Windows does not correctly quote macro arguments", Continue); + + QCOMPARE(cmd.arguments(), "macroarg: 'hello world'"); + } }; int main(int argc, char *argv[]) From e093c39727b3a31ef9c89e9f571edcfe4c163e35 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sun, 12 Mar 2023 20:26:00 +0100 Subject: [PATCH 0272/1447] Utils: Better error reporting for copyFile Change-Id: Id76280e83e9dae92bff2db5722f1e582867e1566 Reviewed-by: David Schulz Reviewed-by: --- src/libs/utils/devicefileaccess.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 1dd035d916f..5cec46b9e2f 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -565,10 +565,13 @@ bool DesktopDeviceFileAccess::removeRecursively(const FilePath &filePath, QStrin expected_str DesktopDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { - if (QFile::copy(filePath.path(), target.path())) + QFile srcFile(filePath.path()); + + if (srcFile.copy(target.path())) return {}; - return make_unexpected(Tr::tr("Failed to copy file \"%1\" to \"%2\".") - .arg(filePath.toUserOutput(), target.toUserOutput())); + return make_unexpected( + Tr::tr("Failed to copy file \"%1\" to \"%2\": %3") + .arg(filePath.toUserOutput(), target.toUserOutput(), srcFile.errorString())); } bool DesktopDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const From 7f1e6d0e9be29157a8f81ac334f691c1a12ed746 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 14 Mar 2023 15:27:25 +0100 Subject: [PATCH 0273/1447] Debugger: Fix QString=>FilePath Change-Id: I32128c7a47ab8bdd06237251c572be3d6a5df1d1 Reviewed-by: Alessandro Portale --- src/plugins/debugger/moduleshandler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 3451b9b5725..26d1cd23409 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -161,7 +161,7 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Show Source Files for Module \"%1\"").arg(moduleName), Tr::tr("Show Source Files for Module"), moduleNameValid && enabled && canReload, - [this, modulePath] { engine->loadSymbols(modulePath); }); + [this, modulePath] { engine->loadSymbols(FilePath::fromUserInput(modulePath)); }); // FIXME: Dependencies only available on Windows, when "depends" is installed. addAction(this, menu, Tr::tr("Show Dependencies of \"%1\"").arg(moduleName), @@ -180,7 +180,7 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Load Symbols for Module \"%1\"").arg(moduleName), Tr::tr("Load Symbols for Module"), moduleNameValid && canLoadSymbols, - [this, modulePath] { engine->loadSymbols(modulePath); }); + [this, modulePath] { engine->loadSymbols(FilePath::fromUserInput(modulePath)); }); addAction(this, menu, Tr::tr("Edit File \"%1\"").arg(moduleName), Tr::tr("Edit File"), @@ -190,12 +190,12 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Show Symbols in File \"%1\"").arg(moduleName), Tr::tr("Show Symbols"), canShowSymbols && moduleNameValid, - [this, modulePath] { engine->requestModuleSymbols(modulePath); }); + [this, modulePath] { engine->requestModuleSymbols(FilePath::fromUserInput(modulePath)); }); addAction(this, menu, Tr::tr("Show Sections in File \"%1\"").arg(moduleName), Tr::tr("Show Sections"), canShowSymbols && moduleNameValid, - [this, modulePath] { engine->requestModuleSections(modulePath); }); + [this, modulePath] { engine->requestModuleSections(FilePath::fromUserInput(modulePath)); }); menu->addAction(debuggerSettings()->settingsDialog.action()); From 15a39259e97c48b2e9cfa433fdfcdb97700d9495 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 07:53:08 +0100 Subject: [PATCH 0274/1447] Debugger: Use FilePath for Modules Change-Id: Ib3c8cf0de3560fdc77775460aa6282d69dbfef9e Reviewed-by: Marcus Tillmanns Reviewed-by: Orgad Shaneh --- src/plugins/debugger/cdb/cdbengine.cpp | 3 ++- src/plugins/debugger/gdb/gdbengine.cpp | 28 +++++++++++------------- src/plugins/debugger/lldb/lldbengine.cpp | 3 ++- src/plugins/debugger/moduleshandler.cpp | 26 +++++++++++----------- src/plugins/debugger/moduleshandler.h | 6 ++--- src/plugins/debugger/pdb/pdbengine.cpp | 2 +- src/plugins/debugger/uvsc/uvscengine.cpp | 2 +- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 8400eee7510..ed7e0da9c82 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1488,12 +1488,13 @@ void CdbEngine::handleModules(const DebuggerResponse &response) { if (response.resultClass == ResultDone) { if (response.data.type() == GdbMi::List) { + const FilePath inferior = runParameters().inferior.command.executable(); ModulesHandler *handler = modulesHandler(); handler->beginUpdateAll(); for (const GdbMi &gdbmiModule : response.data) { Module module; module.moduleName = gdbmiModule["name"].data(); - module.modulePath = gdbmiModule["image"].data(); + module.modulePath = inferior.withNewPath(gdbmiModule["image"].data()); module.startAddress = gdbmiModule["start"].data().toULongLong(nullptr, 0); module.endAddress = gdbmiModule["end"].data().toULongLong(nullptr, 0); if (gdbmiModule["deferred"].type() == GdbMi::Invalid) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index bf9647e2203..095e46f1770 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -470,7 +470,8 @@ void GdbEngine::handleAsyncOutput(const QStringView asyncClass, const GdbMi &res module.startAddress = 0; module.endAddress = 0; module.hostPath = result["host-name"].data(); - module.modulePath = result["target-name"].data(); + const QString target = result["target-name"].data(); + module.modulePath = runParameters().inferior.command.executable().withNewPath(target); module.moduleName = QFileInfo(module.hostPath).baseName(); modulesHandler()->updateModule(module); } else if (asyncClass == u"library-unloaded") { @@ -478,7 +479,8 @@ void GdbEngine::handleAsyncOutput(const QStringView asyncClass, const GdbMi &res // target-name="/usr/lib/libdrm.so.2", // host-name="/usr/lib/libdrm.so.2" QString id = result["id"].data(); - modulesHandler()->removeModule(result["target-name"].data()); + const QString target = result["target-name"].data(); + modulesHandler()->removeModule(runParameters().inferior.command.executable().withNewPath(target)); progressPing(); showStatusMessage(Tr::tr("Library %1 unloaded.").arg(id), 1000); } else if (asyncClass == u"thread-group-added") { @@ -2811,7 +2813,7 @@ void GdbEngine::loadSymbolsForStack() for (const Module &module : modules) { if (module.startAddress <= frame.address && frame.address < module.endAddress) { - runCommand({"sharedlibrary " + dotEscape(module.modulePath)}); + runCommand({"sharedlibrary " + dotEscape(module.modulePath.path())}); needUpdate = true; } } @@ -2956,11 +2958,6 @@ void GdbEngine::reloadModulesInternal() runCommand({"info shared", NeedsTemporaryStop, CB(handleModulesList)}); } -static QString nameFromPath(const QString &path) -{ - return QFileInfo(path).baseName(); -} - void GdbEngine::handleModulesList(const DebuggerResponse &response) { if (response.resultClass == ResultDone) { @@ -2971,14 +2968,15 @@ void GdbEngine::handleModulesList(const DebuggerResponse &response) QString data = response.consoleStreamOutput; QTextStream ts(&data, QIODevice::ReadOnly); bool found = false; + const FilePath inferior = runParameters().inferior.command.executable(); while (!ts.atEnd()) { QString line = ts.readLine(); QString symbolsRead; QTextStream ts(&line, QIODevice::ReadOnly); if (line.startsWith("0x")) { ts >> module.startAddress >> module.endAddress >> symbolsRead; - module.modulePath = ts.readLine().trimmed(); - module.moduleName = nameFromPath(module.modulePath); + module.modulePath = inferior.withNewPath(ts.readLine().trimmed()); + module.moduleName = module.modulePath.baseName(); module.symbolsRead = (symbolsRead == "Yes" ? Module::ReadOk : Module::ReadFailed); handler->updateModule(module); @@ -2989,8 +2987,8 @@ void GdbEngine::handleModulesList(const DebuggerResponse &response) QTC_ASSERT(symbolsRead == "No", continue); module.startAddress = 0; module.endAddress = 0; - module.modulePath = ts.readLine().trimmed(); - module.moduleName = nameFromPath(module.modulePath); + module.modulePath = inferior.withNewPath(ts.readLine().trimmed()); + module.moduleName = module.modulePath.baseName(); handler->updateModule(module); found = true; } @@ -3002,8 +3000,8 @@ void GdbEngine::handleModulesList(const DebuggerResponse &response) // loaded_addr="0x8fe00000",slide="0x0",prefix="__dyld_"}, // shlib-info={...}... for (const GdbMi &item : response.data) { - module.modulePath = item["path"].data(); - module.moduleName = nameFromPath(module.modulePath); + module.modulePath = inferior.withNewPath(item["path"].data()); + module.moduleName = module.modulePath.baseName(); module.symbolsRead = (item["state"].data() == "Y") ? Module::ReadOk : Module::ReadFailed; module.startAddress = @@ -3922,7 +3920,7 @@ void GdbEngine::handleGdbStarted() Module module; module.startAddress = 0; module.endAddress = 0; - module.modulePath = rp.inferior.command.executable().toString(); + module.modulePath = rp.inferior.command.executable(); module.moduleName = ""; modulesHandler()->updateModule(module); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 8912375477c..f2c7c23744c 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -643,12 +643,13 @@ void LldbEngine::reloadModules() { DebuggerCommand cmd("fetchModules"); cmd.callback = [this](const DebuggerResponse &response) { + const FilePath inferior = runParameters().inferior.command.executable(); const GdbMi &modules = response.data["modules"]; ModulesHandler *handler = modulesHandler(); handler->beginUpdateAll(); for (const GdbMi &item : modules) { Module module; - module.modulePath = item["file"].data(); + module.modulePath = inferior.withNewPath(item["file"].data()); module.moduleName = item["name"].data(); module.symbolsRead = Module::UnknownReadState; module.startAddress = item["loaded_addr"].toAddress(); diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 26d1cd23409..9ae6b068af8 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -48,7 +48,7 @@ QVariant ModuleItem::data(int column, int role) const break; case 1: if (role == Qt::DisplayRole) - return module.modulePath; + return module.modulePath.toUserOutput(); if (role == Qt::ToolTipRole) { QString msg; if (!module.elfData.buildId.isEmpty()) @@ -150,7 +150,7 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) const bool canShowSymbols = engine->hasCapability(ShowModuleSymbolsCapability); const bool moduleNameValid = item && !item->module.moduleName.isEmpty(); const QString moduleName = item ? item->module.moduleName : QString(); - const QString modulePath = item ? item->module.modulePath : QString(); + const FilePath modulePath = item ? item->module.modulePath : FilePath(); auto menu = new QMenu; @@ -161,13 +161,13 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Show Source Files for Module \"%1\"").arg(moduleName), Tr::tr("Show Source Files for Module"), moduleNameValid && enabled && canReload, - [this, modulePath] { engine->loadSymbols(FilePath::fromUserInput(modulePath)); }); + [this, modulePath] { engine->loadSymbols(modulePath); }); // FIXME: Dependencies only available on Windows, when "depends" is installed. addAction(this, menu, Tr::tr("Show Dependencies of \"%1\"").arg(moduleName), Tr::tr("Show Dependencies"), moduleNameValid && !moduleName.isEmpty() && HostOsInfo::isWindowsHost(), - [modulePath] { QtcProcess::startDetached({{"depends"}, {modulePath}}); }); + [modulePath] { QtcProcess::startDetached({{"depends"}, {modulePath.toString()}}); }); addAction(this, menu, Tr::tr("Load Symbols for All Modules"), enabled && canLoadSymbols, @@ -180,22 +180,22 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, Tr::tr("Load Symbols for Module \"%1\"").arg(moduleName), Tr::tr("Load Symbols for Module"), moduleNameValid && canLoadSymbols, - [this, modulePath] { engine->loadSymbols(FilePath::fromUserInput(modulePath)); }); + [this, modulePath] { engine->loadSymbols(modulePath); }); addAction(this, menu, Tr::tr("Edit File \"%1\"").arg(moduleName), Tr::tr("Edit File"), moduleNameValid, - [this, modulePath] { engine->gotoLocation(FilePath::fromString(modulePath)); }); + [this, modulePath] { engine->gotoLocation(modulePath); }); addAction(this, menu, Tr::tr("Show Symbols in File \"%1\"").arg(moduleName), Tr::tr("Show Symbols"), canShowSymbols && moduleNameValid, - [this, modulePath] { engine->requestModuleSymbols(FilePath::fromUserInput(modulePath)); }); + [this, modulePath] { engine->requestModuleSymbols(modulePath); }); addAction(this, menu, Tr::tr("Show Sections in File \"%1\"").arg(moduleName), Tr::tr("Show Sections"), canShowSymbols && moduleNameValid, - [this, modulePath] { engine->requestModuleSections(FilePath::fromUserInput(modulePath)); }); + [this, modulePath] { engine->requestModuleSections(modulePath); }); menu->addAction(debuggerSettings()->settingsDialog.action()); @@ -239,7 +239,7 @@ QAbstractItemModel *ModulesHandler::model() const return m_proxyModel; } -ModuleItem *ModulesHandler::moduleFromPath(const QString &modulePath) const +ModuleItem *ModulesHandler::moduleFromPath(const FilePath &modulePath) const { // Recent modules are more likely to be unloaded first. return m_model->findItemAtLevel<1>([modulePath](ModuleItem *item) { @@ -259,7 +259,7 @@ const Modules ModulesHandler::modules() const return mods; } -void ModulesHandler::removeModule(const QString &modulePath) +void ModulesHandler::removeModule(const FilePath &modulePath) { if (ModuleItem *item = moduleFromPath(modulePath)) m_model->destroyItem(item); @@ -267,7 +267,7 @@ void ModulesHandler::removeModule(const QString &modulePath) void ModulesHandler::updateModule(const Module &module) { - const QString path = module.modulePath; + const FilePath path = module.modulePath; if (path.isEmpty()) return; @@ -281,12 +281,12 @@ void ModulesHandler::updateModule(const Module &module) } try { // MinGW occasionallly throws std::bad_alloc. - ElfReader reader(FilePath::fromUserInput(path)); + ElfReader reader(path); item->module.elfData = reader.readHeaders(); item->update(); } catch(...) { qWarning("%s: An exception occurred while reading module '%s'", - Q_FUNC_INFO, qPrintable(module.modulePath)); + Q_FUNC_INFO, qPrintable(module.modulePath.toUserOutput())); } item->updated = true; } diff --git a/src/plugins/debugger/moduleshandler.h b/src/plugins/debugger/moduleshandler.h index 082a66f2ca0..03434edab28 100644 --- a/src/plugins/debugger/moduleshandler.h +++ b/src/plugins/debugger/moduleshandler.h @@ -70,7 +70,7 @@ public: ReadOk // Dwarf index available. }; QString moduleName; - QString modulePath; + Utils::FilePath modulePath; QString hostPath; SymbolReadState symbolsRead = UnknownReadState; quint64 startAddress = 0; @@ -99,7 +99,7 @@ public: QAbstractItemModel *model() const; - void removeModule(const QString &modulePath); + void removeModule(const Utils::FilePath &modulePath); void updateModule(const Module &module); void beginUpdateAll(); @@ -109,7 +109,7 @@ public: const Modules modules() const; private: - ModuleItem *moduleFromPath(const QString &modulePath) const; + ModuleItem *moduleFromPath(const Utils::FilePath &modulePath) const; ModulesModel *m_model; QSortFilterProxyModel *m_proxyModel; diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index a8766691147..4435409506b 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -294,7 +294,7 @@ void PdbEngine::refreshModules(const GdbMi &modules) && path.endsWith("' (built-in)>")) { path = "(builtin)"; } - module.modulePath = path; + module.modulePath = FilePath::fromString(path); handler->updateModule(module); } handler->endUpdateAll(); diff --git a/src/plugins/debugger/uvsc/uvscengine.cpp b/src/plugins/debugger/uvsc/uvscengine.cpp index 2bb0bef8e76..06450651de2 100644 --- a/src/plugins/debugger/uvsc/uvscengine.cpp +++ b/src/plugins/debugger/uvsc/uvscengine.cpp @@ -600,7 +600,7 @@ void UvscEngine::handleProjectClosed() Module module; module.startAddress = 0; module.endAddress = 0; - module.modulePath = rp.inferior.command.executable().toString(); + module.modulePath = rp.inferior.command.executable(); module.moduleName = ""; modulesHandler()->updateModule(module); From 7cb585af87fec81b2cd23e7c47aea48440a63972 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 13 Mar 2023 15:11:50 +0100 Subject: [PATCH 0275/1447] TextEditor: support inline suggestions Change-Id: I70924a37f9078c5b33c1703e099fc9ddc0b1ae9a Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/copilot/copilotclient.cpp | 17 +++- src/plugins/texteditor/textdocument.cpp | 14 +++- src/plugins/texteditor/textdocument.h | 2 +- src/plugins/texteditor/textdocumentlayout.cpp | 82 +++++++++++++++++-- src/plugins/texteditor/textdocumentlayout.h | 12 ++- src/plugins/texteditor/texteditor.cpp | 61 +++++++------- 6 files changed, 144 insertions(+), 44 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index a6047004aa8..70eeb842bac 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -102,6 +102,7 @@ void CopilotClient::scheduleRequest(TextEditorWidget *editor) connect(timer, &QTimer::timeout, this, [this, editor]() { requestCompletions(editor); }); connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() { m_scheduledRequests.remove(editor); + cancelRunningRequest(editor); }); connect(editor, &TextEditorWidget::cursorPositionChanged, this, [this, editor] { cancelRunningRequest(editor); @@ -129,8 +130,8 @@ void CopilotClient::requestCompletions(TextEditorWidget *editor) Position(cursor.mainCursor())}}; request.setResponseCallback([this, editor = QPointer(editor)]( const GetCompletionRequest::Response &response) { - if (editor) - handleCompletions(response, editor); + QTC_ASSERT(editor, return); + handleCompletions(response, editor); }); m_runningRequests[editor] = request; sendMessage(request); @@ -142,8 +143,16 @@ void CopilotClient::handleCompletions(const GetCompletionRequest::Response &resp if (response.error()) log(*response.error()); - Utils::MultiTextCursor cursor = editor->multiTextCursor(); - if (cursor.hasMultipleCursors() || cursor.hasSelection()) + int requestPosition = -1; + if (const auto requestParams = m_runningRequests.take(editor).params()) + requestPosition = requestParams->position().toPositionInDocument(editor->document()); + + const Utils::MultiTextCursor cursors = editor->multiTextCursor(); + if (cursors.hasMultipleCursors()) + return; + + const QTextCursor cursor = cursors.mainCursor(); + if (cursors.hasSelection() || cursors.mainCursor().position() != requestPosition) return; if (const std::optional result = response.result()) { diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index b6851411693..966edd4e7d8 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -373,10 +373,16 @@ QAction *TextDocument::createDiffAgainstCurrentFileAction( return diffAction; } -void TextDocument::insertSuggestion(const QString &text, const QTextBlock &block) +void TextDocument::insertSuggestion(const QString &text, const QTextCursor &cursor) { - TextDocumentLayout::userData(block)->setReplacement(block.text() + text); - TextDocumentLayout::updateReplacmentFormats(block, fontSettings()); + const QTextBlock block = cursor.block(); + const QString blockText = block.text(); + QString replacement = blockText.left(cursor.positionInBlock()) + text; + if (!text.contains('\n')) + replacement.append(blockText.mid(cursor.positionInBlock())); + TextDocumentLayout::userData(block)->setReplacement(replacement); + TextDocumentLayout::userData(block)->setReplacementPosition(cursor.positionInBlock()); + TextDocumentLayout::updateReplacementFormats(block, fontSettings()); updateLayout(); } @@ -428,7 +434,7 @@ void TextDocument::applyFontSettings() d->m_fontSettingsNeedsApply = false; QTextBlock block = document()->firstBlock(); while (block.isValid()) { - TextDocumentLayout::updateReplacmentFormats(block, fontSettings()); + TextDocumentLayout::updateReplacementFormats(block, fontSettings()); block = block.next(); } updateLayout(); diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 8ddfe9effb1..9ef556503fd 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -144,7 +144,7 @@ public: static QAction *createDiffAgainstCurrentFileAction(QObject *parent, const std::function &filePath); - void insertSuggestion(const QString &text, const QTextBlock &block); + void insertSuggestion(const QString &text, const QTextCursor &cursor); #ifdef WITH_TESTS void setSilentReload(); diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index 8738f43bd15..ce337efa022 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -352,6 +352,17 @@ void TextBlockUserData::setReplacement(const QString &replacement) m_replacement->setDocumentMargin(0); } +void TextBlockUserData::setReplacementPosition(int replacementPosition) +{ + m_replacementPosition = replacementPosition; +} + +void TextBlockUserData::clearReplacement() +{ + m_replacement.reset(); + m_replacementPosition = -1; +} + void TextBlockUserData::addMark(TextMark *mark) { int i = 0; @@ -525,26 +536,64 @@ QByteArray TextDocumentLayout::expectedRawStringSuffix(const QTextBlock &block) return {}; } -void TextDocumentLayout::updateReplacmentFormats(const QTextBlock &block, +void TextDocumentLayout::updateReplacementFormats(const QTextBlock &block, const FontSettings &fontSettings) { if (QTextDocument *replacement = replacementDocument(block)) { const QTextCharFormat replacementFormat = fontSettings.toTextCharFormat( TextStyles{C_TEXT, {C_DISABLED_CODE}}); + QList formats = block.layout()->formats(); QTextCursor cursor(replacement); cursor.select(QTextCursor::Document); cursor.setCharFormat(fontSettings.toTextCharFormat(C_TEXT)); - cursor.setPosition(block.length() - 1); + const int position = replacementPosition(block); + cursor.setPosition(position); + const QString trailingText = block.text().mid(position); + if (!trailingText.isEmpty()) { + const int trailingIndex = replacement->firstBlock().text().indexOf(trailingText, + position); + if (trailingIndex >= 0) { + cursor.setPosition(trailingIndex, QTextCursor::KeepAnchor); + cursor.setCharFormat(replacementFormat); + cursor.setPosition(trailingIndex + trailingText.size()); + const int length = std::max(trailingIndex - position, 0); + if (length) { + // we have a replacement in the middle of the line adjust all formats that are + // behind the replacement + QTextLayout::FormatRange rest; + rest.start = -1; + for (QTextLayout::FormatRange &range : formats) { + if (range.start >= position) { + range.start += length; + } else if (range.start + range.length > position) { + // the format range starts before and ends after the position so we need to + // split the format into before and after the suggestion format ranges + rest.start = trailingIndex; + rest.length = range.length - (position - range.start); + rest.format = range.format; + range.length = position - range.start; + } + } + if (rest.start >= 0) + formats += rest; + } + } + } cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.setCharFormat(replacementFormat); - replacement->firstBlock().layout()->setFormats(block.layout()->formats()); + replacement->firstBlock().layout()->setFormats(formats); } } QString TextDocumentLayout::replacement(const QTextBlock &block) { - if (QTextDocument *replacement = replacementDocument(block)) - return replacement->toPlainText().mid(block.length() - 1); + if (QTextDocument *replacement = replacementDocument(block)) { + QTextCursor cursor(replacement); + const int position = replacementPosition(block); + cursor.setPosition(position); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + return cursor.selectedText(); + } return {}; } @@ -554,6 +603,29 @@ QTextDocument *TextDocumentLayout::replacementDocument(const QTextBlock &block) return userData ? userData->replacement() : nullptr; } +int TextDocumentLayout::replacementPosition(const QTextBlock &block) +{ + TextBlockUserData *userData = textUserData(block); + return userData ? userData->replacementPosition() : -1; +} + +bool TextDocumentLayout::updateReplacement(const QTextBlock &block, + int position, + const FontSettings &fontSettings) +{ + if (QTextDocument *replacementDocument = TextDocumentLayout::replacementDocument(block)) { + const QString start = block.text().left(position); + const QString end = block.text().mid(position); + const QString replacement = replacementDocument->firstBlock().text(); + if (replacement.startsWith(start) && replacement.endsWith(end)) { + userData(block)->setReplacementPosition(position); + TextDocumentLayout::updateReplacementFormats(block, fontSettings); + return true; + } + } + return false; +} + void TextDocumentLayout::requestExtraAreaUpdate() { emit updateExtraArea(); diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 7a2e7e948e9..97fa5992abb 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -127,8 +127,10 @@ public: void setExpectedRawStringSuffix(const QByteArray &suffix) { m_expectedRawStringSuffix = suffix; } void setReplacement(const QString &replacement); - void clearReplacement() { m_replacement.reset(); } + void setReplacementPosition(int replacementPosition); + void clearReplacement(); QTextDocument *replacement() const { return m_replacement.get(); } + int replacementPosition() const { return m_replacementPosition; } private: TextMarks m_marks; @@ -144,6 +146,7 @@ private: KSyntaxHighlighting::State m_syntaxState; QByteArray m_expectedRawStringSuffix; // A bit C++-specific, but let's be pragmatic. std::unique_ptr m_replacement; + int m_replacementPosition = -1; }; @@ -177,9 +180,14 @@ public: static void setFolded(const QTextBlock &block, bool folded); static void setExpectedRawStringSuffix(const QTextBlock &block, const QByteArray &suffix); static QByteArray expectedRawStringSuffix(const QTextBlock &block); - static void updateReplacmentFormats(const QTextBlock &block, const FontSettings &fontSettings); + static void updateReplacementFormats(const QTextBlock &block, + const FontSettings &fontSettings); static QString replacement(const QTextBlock &block); static QTextDocument *replacementDocument(const QTextBlock &block); + static int replacementPosition(const QTextBlock &block); + static bool updateReplacement(const QTextBlock &block, + int position, + const FontSettings &fontSettings); class TEXTEDITOR_EXPORT FoldValidator { diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index cc37fca79d5..b614a18e736 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -820,7 +820,8 @@ public: QList m_visualIndentCache; int m_visualIndentOffset = 0; - void insertSuggestion(const QString &suggestion, const QTextBlock &block); + void insertSuggestion(const QString &suggestion); + void updateSuggestion(); void clearCurrentSuggestion(); QTextBlock m_suggestionBlock; }; @@ -1650,15 +1651,28 @@ void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperatio q->setMultiTextCursor(MultiTextCursor(cursors)); } -void TextEditorWidgetPrivate::insertSuggestion(const QString &suggestion, const QTextBlock &block) +void TextEditorWidgetPrivate::insertSuggestion(const QString &suggestion) { clearCurrentSuggestion(); - m_suggestionBlock = block; - m_document->insertSuggestion(suggestion, block); auto cursor = q->textCursor(); - cursor.setPosition(block.position()); - cursor.movePosition(QTextCursor::EndOfBlock); - q->setTextCursor(cursor); + m_suggestionBlock = cursor.block(); + m_document->insertSuggestion(suggestion, cursor); +} + +void TextEditorWidgetPrivate::updateSuggestion() +{ + if (!m_suggestionBlock.isValid()) + return; + if (m_cursors.mainCursor().block() != m_suggestionBlock) { + clearCurrentSuggestion(); + } else { + const int position = m_cursors.mainCursor().position() - m_suggestionBlock.position(); + if (!TextDocumentLayout::updateReplacement(m_suggestionBlock, + position, + m_document->fontSettings())) { + clearCurrentSuggestion(); + } + } } void TextEditorWidgetPrivate::clearCurrentSuggestion() @@ -1852,16 +1866,7 @@ TextEditorWidget *TextEditorWidget::fromEditor(const IEditor *editor) void TextEditorWidgetPrivate::editorContentsChange(int position, int charsRemoved, int charsAdded) { - if (m_suggestionBlock.isValid()) { - if (QTextDocument *replacementDocument = TextDocumentLayout::replacementDocument( - m_suggestionBlock)) { - if (replacementDocument->firstBlock().text().startsWith(m_suggestionBlock.text())) - TextDocumentLayout::updateReplacmentFormats(m_suggestionBlock, - m_document->fontSettings()); - else - clearCurrentSuggestion(); - } - } + updateSuggestion(); if (m_bracketsAnimator) m_bracketsAnimator->finish(); @@ -2680,10 +2685,15 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) case Qt::Key_Backtab: { if (ro) break; if (d->m_suggestionBlock.isValid()) { - QTextCursor cursor(d->m_suggestionBlock); - cursor.movePosition(QTextCursor::EndOfBlock); - cursor.insertText(TextDocumentLayout::replacement(d->m_suggestionBlock)); - setTextCursor(cursor); + const int position = TextDocumentLayout::replacementPosition(d->m_suggestionBlock); + if (position >= 0) { + QTextCursor cursor(d->m_suggestionBlock); + cursor.setPosition(d->m_suggestionBlock.position() + position); + cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + cursor.insertText(TextDocumentLayout::replacement(d->m_suggestionBlock)); + setTextCursor(cursor); + } + d->clearCurrentSuggestion(); e->accept(); return; } @@ -5481,17 +5491,12 @@ void TextEditorWidget::slotCursorPositionChanged() if (EditorManager::currentEditor() && EditorManager::currentEditor()->widget() == this) EditorManager::setLastEditLocation(EditorManager::currentEditor()); } - if (d->m_suggestionBlock.isValid()) { - if (textCursor().position() - != d->m_suggestionBlock.position() + d->m_suggestionBlock.length() - 1) { - d->clearCurrentSuggestion(); - } - } MultiTextCursor cursor = multiTextCursor(); cursor.replaceMainCursor(textCursor()); setMultiTextCursor(cursor); d->updateCursorSelections(); d->updateHighlights(); + d->updateSuggestion(); } void TextEditorWidgetPrivate::updateHighlights() @@ -5933,7 +5938,7 @@ void TextEditorWidget::removeHoverHandler(BaseHoverHandler *handler) void TextEditorWidget::insertSuggestion(const QString &suggestion) { - d->insertSuggestion(suggestion, textCursor().block()); + d->insertSuggestion(suggestion); } void TextEditorWidget::clearSuggestion() From 7a2dbace9b24d381004b6a4414732c6a411699b7 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 14 Mar 2023 13:07:45 +0100 Subject: [PATCH 0276/1447] Copilot: add command to explicitly request copilot suggestions Change-Id: I3bf321fc2ebc6d44819c1a799be9207aa3ca59f1 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/plugins/copilot/copilotclient.cpp | 8 ++++---- src/plugins/copilot/copilotplugin.cpp | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 70eeb842bac..06f127e645f 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -99,7 +99,10 @@ void CopilotClient::scheduleRequest(TextEditorWidget *editor) if (!m_scheduledRequests.contains(editor)) { auto timer = new QTimer(this); timer->setSingleShot(true); - connect(timer, &QTimer::timeout, this, [this, editor]() { requestCompletions(editor); }); + connect(timer, &QTimer::timeout, this, [this, editor]() { + if (m_scheduledRequests[editor].cursorPosition == editor->textCursor().position()) + requestCompletions(editor); + }); connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() { m_scheduledRequests.remove(editor); cancelRunningRequest(editor); @@ -120,9 +123,6 @@ void CopilotClient::requestCompletions(TextEditorWidget *editor) if (cursor.hasMultipleCursors() || cursor.hasSelection()) return; - if (m_scheduledRequests[editor].cursorPosition != cursor.mainCursor().position()) - return; - const Utils::FilePath filePath = editor->textDocument()->filePath(); GetCompletionRequest request{ {TextDocumentIdentifier(hostPathToServerUri(filePath)), diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 45a859b1380..171eb3c3395 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -6,9 +6,11 @@ #include "copilotclient.h" #include "copilotoptionspage.h" #include "copilotsettings.h" +#include "copilottr.h" -#include +#include #include +#include #include @@ -30,6 +32,18 @@ void CopilotPlugin::initialize() &CopilotSettings::applied, this, &CopilotPlugin::restartClient); + + QAction *action = new QAction(this); + action->setText(Tr::tr("Request Copilot Suggestion")); + action->setToolTip(Tr::tr("Request Copilot Suggestion at the current editors cursor position.")); + + QObject::connect(action, &QAction::triggered, this, [this] { + if (auto editor = TextEditor::TextEditorWidget::currentTextEditorWidget()) { + if (m_client->reachable()) + m_client->requestCompletions(editor); + } + }); + ActionManager::registerAction(action, "Copilot.RequestSuggestion"); } void CopilotPlugin::extensionsInitialized() From 4d325522e06b9a892c8bb70f47cb4a9ba13bbcc7 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 16:38:02 +0100 Subject: [PATCH 0277/1447] Qnx: DeviceTester code cosmetics Change-Id: I77463ecde1c64333de35b33773f3eacf275f983f Reviewed-by: Marcus Tillmanns --- src/plugins/qnx/qnxdevicetester.cpp | 10 +++++----- src/plugins/qnx/qnxdevicetester.h | 12 ++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp index fa60bfe69b6..bd78f2ec228 100644 --- a/src/plugins/qnx/qnxdevicetester.cpp +++ b/src/plugins/qnx/qnxdevicetester.cpp @@ -33,7 +33,7 @@ static QStringList versionSpecificCommandsToTest(int versionNumber) return {}; } -void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &deviceConfiguration) +void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) { static const QStringList s_commandsToTest = {"awk", "cat", @@ -52,8 +52,8 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &deviceConf "sleep", "tail", "uname"}; - m_deviceConfiguration = deviceConfiguration; - QnxDevice::ConstPtr qnxDevice = m_deviceConfiguration.dynamicCast(); + m_device = device; + QnxDevice::ConstPtr qnxDevice = m_device.dynamicCast(); m_genericTester->setExtraCommandsToTest( s_commandsToTest + versionSpecificCommandsToTest(qnxDevice->qnxVersion())); @@ -63,7 +63,7 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &deviceConf emit progressMessage(Tr::tr("Checking that files can be created in %1...") .arg(Constants::QNX_TMP_DIR)); const QString pidFile = QString("%1/qtc_xxxx.pid").arg(Constants::QNX_TMP_DIR); - const CommandLine cmd(m_deviceConfiguration->filePath("/bin/sh"), + const CommandLine cmd(m_device->filePath("/bin/sh"), {"-c", QLatin1String("rm %1 > /dev/null 2>&1; echo ABC > %1 && rm %1").arg(pidFile)}); process.setCommand(cmd); }; @@ -79,7 +79,7 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &deviceConf }; m_genericTester->setExtraTests({Process(setupHandler, doneHandler, errorHandler)}); - m_genericTester->testDevice(deviceConfiguration); + m_genericTester->testDevice(device); } void QnxDeviceTester::stopTest() diff --git a/src/plugins/qnx/qnxdevicetester.h b/src/plugins/qnx/qnxdevicetester.h index 96f31f38416..d23428b3532 100644 --- a/src/plugins/qnx/qnxdevicetester.h +++ b/src/plugins/qnx/qnxdevicetester.h @@ -5,23 +5,19 @@ #include -namespace Qnx { -namespace Internal { +namespace Qnx::Internal { class QnxDeviceTester : public ProjectExplorer::DeviceTester { - Q_OBJECT - public: explicit QnxDeviceTester(QObject *parent = nullptr); - void testDevice(const ProjectExplorer::IDevice::Ptr &deviceConfiguration) override; + void testDevice(const ProjectExplorer::IDevice::Ptr &device) override; void stopTest() override; private: RemoteLinux::GenericLinuxDeviceTester *m_genericTester = nullptr; - ProjectExplorer::IDevice::ConstPtr m_deviceConfiguration; + ProjectExplorer::IDevice::ConstPtr m_device; }; -} // namespace Internal -} // namespace Qnx +} // Qnx::Internal From 2704f8ff0bc6e92dd71eaf616ef04b4a6a0221ad Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 25 Nov 2022 14:06:47 +0100 Subject: [PATCH 0278/1447] ProjectExplorer: Proliferate FilePath a bit Change-Id: Ia671a1de17b9e58764375c5f64cc47b053b0725a Reviewed-by: Christian Kandeler --- .../autotoolsbuildsystem.cpp | 3 ++- .../cmakeprojectmanager/cmakebuildsystem.cpp | 2 +- .../compilationdatabaseproject.cpp | 14 ++++++----- .../compilationdatabasetests.cpp | 4 ++- .../compilationdatabaseutils.cpp | 25 ++++++------------- .../compilationdatabaseutils.h | 8 +++--- .../compilationdbparser.cpp | 2 +- .../genericprojectmanager/genericproject.cpp | 4 +-- src/plugins/projectexplorer/gcctoolchain.cpp | 2 +- src/plugins/projectexplorer/gcctoolchain.h | 4 +-- src/plugins/projectexplorer/msvctoolchain.cpp | 4 +-- src/plugins/projectexplorer/msvctoolchain.h | 4 +-- .../projectexplorer/rawprojectpart.cpp | 6 +++-- src/plugins/projectexplorer/rawprojectpart.h | 2 +- src/plugins/projectexplorer/toolchain.cpp | 19 ++++++-------- src/plugins/projectexplorer/toolchain.h | 10 ++++---- .../qmakeprojectmanager/qmakeproject.cpp | 2 +- 17 files changed, 54 insertions(+), 61 deletions(-) diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp index 0375ce9ac61..113212be5fb 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp @@ -14,6 +14,7 @@ #include using namespace ProjectExplorer; +using namespace Utils; namespace AutotoolsProjectManager::Internal { @@ -140,7 +141,7 @@ void AutotoolsBuildSystem::updateCppCodeModel() if (cxxflags.isEmpty()) cxxflags = cflags; - const QString includeFileBaseDir = projectDirectory().toString(); + const FilePath includeFileBaseDir = projectDirectory(); rpp.setFlagsForC({kitInfo.cToolChain, cflags, includeFileBaseDir}); rpp.setFlagsForCxx({kitInfo.cxxToolChain, cxxflags, includeFileBaseDir}); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 726414dafc3..ebc41fea787 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -601,7 +601,7 @@ void CMakeBuildSystem::updateProjectData() for (RawProjectPart &rpp : rpps) { rpp.setQtVersion( kitInfo.projectPartQtVersion); // TODO: Check if project actually uses Qt. - const QString includeFileBaseDir = buildConfiguration()->buildDirectory().toString(); + const FilePath includeFileBaseDir = buildConfiguration()->buildDirectory(); QStringList cxxFlags = rpp.flagsForCxx.commandLineFlags; QStringList cFlags = rpp.flagsForC.commandLineFlags; addTargetFlagForIos(cxxFlags, cFlags, this, [this] { diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index 051552d16ca..49712c32061 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -148,8 +148,8 @@ void addDriverModeFlagIfNeeded(const ToolChain *toolchain, RawProjectPart makeRawProjectPart(const Utils::FilePath &projectFile, Kit *kit, ProjectExplorer::KitInfo &kitInfo, - const QString &workingDir, - const Utils::FilePath &fileName, + const FilePath &workingDir, + const FilePath &filePath, QStringList flags) { HeaderPaths headerPaths; @@ -157,7 +157,7 @@ RawProjectPart makeRawProjectPart(const Utils::FilePath &projectFile, CppEditor::ProjectFile::Kind fileKind = CppEditor::ProjectFile::Unclassified; const QStringList originalFlags = flags; - filteredFlags(fileName.fileName(), + filteredFlags(filePath, workingDir, flags, headerPaths, @@ -166,10 +166,12 @@ RawProjectPart makeRawProjectPart(const Utils::FilePath &projectFile, kitInfo.sysRootPath); RawProjectPart rpp; + rpp.setProjectFileLocation(projectFile.toString()); - rpp.setBuildSystemTarget(workingDir); - rpp.setDisplayName(fileName.fileName()); - rpp.setFiles({fileName.toString()}); + rpp.setBuildSystemTarget(workingDir.path()); + rpp.setDisplayName(filePath.fileName()); + rpp.setFiles({filePath.toFSPathString()}); + rpp.setHeaderPaths(headerPaths); rpp.setMacros(macros); diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp index 6fff4947647..f8b25747716 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp @@ -92,7 +92,9 @@ public: QStringList getFilteredFlags() { - filteredFlags(fileName, workingDir, flags, headerPaths, macros, fileKind, sysRoot); + filteredFlags(FilePath::fromString(fileName), + FilePath::fromString(workingDir), + flags, headerPaths, macros, fileKind, sysRoot); return flags; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index df8e08a68f5..f773d5fc5d5 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -22,15 +22,6 @@ using namespace Utils; namespace CompilationDatabaseProjectManager { namespace Internal { -static QString updatedPathFlag(const QString &pathStr, const QString &workingDir) -{ - QString result = pathStr; - if (QDir(pathStr).isRelative()) - result = workingDir + "/" + pathStr; - - return result; -} - static CppEditor::ProjectFile::Kind fileKindFromString(QString flag) { using namespace CppEditor; @@ -86,13 +77,13 @@ QStringList filterFromFileName(const QStringList &flags, QString fileName) return result; } -void filteredFlags(const QString &fileName, - const QString &workingDir, +void filteredFlags(const FilePath &filePath, + const FilePath &workingDir, QStringList &flags, HeaderPaths &headerPaths, Macros ¯os, CppEditor::ProjectFile::Kind &fileKind, - Utils::FilePath &sysRoot) + FilePath &sysRoot) { if (flags.empty()) return; @@ -113,7 +104,7 @@ void filteredFlags(const QString &fileName, } if (includePathType) { - const QString pathStr = updatedPathFlag(flag, workingDir); + const QString pathStr = workingDir.resolvePath(flag).toString(); headerPaths.append({pathStr, includePathType.value()}); includePathType.reset(); continue; @@ -152,7 +143,7 @@ void filteredFlags(const QString &fileName, return flag.startsWith(opt) && flag != opt; }); if (!includeOpt.isEmpty()) { - const QString pathStr = updatedPathFlag(flag.mid(includeOpt.length()), workingDir); + const QString pathStr = workingDir.resolvePath(flag.mid(includeOpt.length())).toString(); headerPaths.append({pathStr, userIncludeFlags.contains(includeOpt) ? HeaderPathType::User : HeaderPathType::System}); continue; @@ -182,14 +173,14 @@ void filteredFlags(const QString &fileName, if (flag.startsWith("--sysroot=")) { if (sysRoot.isEmpty()) - sysRoot = FilePath::fromUserInput(updatedPathFlag(flag.mid(10), workingDir)); + sysRoot = workingDir.resolvePath(flag.mid(10)); continue; } if ((flag.startsWith("-std=") || flag.startsWith("/std:")) && fileKind == CppEditor::ProjectFile::Unclassified) { const bool cpp = (flag.contains("c++") || flag.contains("gnu++")); - if (CppEditor::ProjectFile::isHeader(CppEditor::ProjectFile::classify(fileName))) + if (CppEditor::ProjectFile::isHeader(CppEditor::ProjectFile::classify(filePath.path()))) fileKind = cpp ? CppEditor::ProjectFile::CXXHeader : CppEditor::ProjectFile::CHeader; else fileKind = cpp ? CppEditor::ProjectFile::CXXSource : CppEditor::ProjectFile::CSource; @@ -203,7 +194,7 @@ void filteredFlags(const QString &fileName, } if (fileKind == CppEditor::ProjectFile::Unclassified) - fileKind = CppEditor::ProjectFile::classify(fileName); + fileKind = CppEditor::ProjectFile::classify(filePath.path()); flags = filtered; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h index 79130799b48..ec024443d8f 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.h @@ -4,10 +4,8 @@ #pragma once #include -#include #include -#include namespace ProjectExplorer { class HeaderPath; @@ -21,7 +19,7 @@ class DbEntry { public: QStringList flags; Utils::FilePath fileName; - QString workingDir; + Utils::FilePath workingDir; }; class DbContents { @@ -35,8 +33,8 @@ using MimeBinaryCache = QHash; QStringList filterFromFileName(const QStringList &flags, QString baseName); -void filteredFlags(const QString &fileName, - const QString &workingDir, +void filteredFlags(const Utils::FilePath &filePath, + const Utils::FilePath &workingDir, QStringList &flags, QVector &headerPaths, QVector ¯os, diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index 830d51439fc..7d6b399d91a 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -182,7 +182,7 @@ std::vector CompilationDbParser::readJsonObjects() const const Utils::FilePath filePath = jsonObjectFilePath(object); const QStringList flags = filterFromFileName(jsonObjectFlags(object, flagsCache), filePath.fileName()); - result.push_back({flags, filePath, object["directory"].toString()}); + result.push_back({flags, filePath, FilePath::fromUserInput(object["directory"].toString())}); objectStart = m_projectFileContents.indexOf('{', objectEnd + 1); objectEnd = m_projectFileContents.indexOf('}', objectStart + 1); diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index c219b88b2eb..5553e0a7404 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -569,8 +569,8 @@ void GenericBuildSystem::refreshCppCodeModel() rpp.setQtVersion(kitInfo.projectPartQtVersion); rpp.setHeaderPaths(m_projectIncludePaths); rpp.setConfigFileName(m_configFileName); - rpp.setFlagsForCxx({nullptr, m_cxxflags, projectDirectory().toString()}); - rpp.setFlagsForC({nullptr, m_cflags, projectDirectory().toString()}); + rpp.setFlagsForCxx({nullptr, m_cxxflags, projectDirectory()}); + rpp.setFlagsForC({nullptr, m_cflags, projectDirectory()}); static const auto sourceFilesToStringList = [](const SourceFiles &sourceFiles) { return Utils::transform(sourceFiles, [](const SourceFile &f) { diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index cac1905f111..f8e99c32444 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -569,7 +569,7 @@ WarningFlags GccToolChain::warningFlags(const QStringList &cflags) const return flags; } -QStringList GccToolChain::includedFiles(const QStringList &flags, const QString &directoryPath) const +FilePaths GccToolChain::includedFiles(const QStringList &flags, const FilePath &directoryPath) const { return ToolChain::includedFiles("-include", flags, directoryPath, PossiblyConcatenatedFlag::No); } diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index 55ba61e9fb1..1e6353d0a75 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -55,8 +55,8 @@ public: Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override; Utils::WarningFlags warningFlags(const QStringList &cflags) const override; - QStringList includedFiles(const QStringList &flags, - const QString &directoryPath) const override; + Utils::FilePaths includedFiles(const QStringList &flags, + const Utils::FilePath &directoryPath) const override; MacroInspectionRunner createMacroInspectionRunner() const override; BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &env) const override; diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index d7b036ead81..1eebcc68069 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1124,8 +1124,8 @@ WarningFlags MsvcToolChain::warningFlags(const QStringList &cflags) const return flags; } -QStringList MsvcToolChain::includedFiles(const QStringList &flags, - const QString &directoryPath) const +FilePaths MsvcToolChain::includedFiles(const QStringList &flags, + const FilePath &directoryPath) const { return ToolChain::includedFiles("/FI", flags, directoryPath, PossiblyConcatenatedFlag::Yes); } diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index f93f3be28cc..cb1fdc5523b 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -55,8 +55,8 @@ public: MacroInspectionRunner createMacroInspectionRunner() const override; Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override; Utils::WarningFlags warningFlags(const QStringList &cflags) const override; - QStringList includedFiles(const QStringList &flags, - const QString &directoryPath) const override; + Utils::FilePaths includedFiles(const QStringList &flags, + const Utils::FilePath &directoryPath) const override; BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner( const Utils::Environment &env) const override; void addToEnvironment(Utils::Environment &env) const override; diff --git a/src/plugins/projectexplorer/rawprojectpart.cpp b/src/plugins/projectexplorer/rawprojectpart.cpp index 6abbedde93b..31147c3803b 100644 --- a/src/plugins/projectexplorer/rawprojectpart.cpp +++ b/src/plugins/projectexplorer/rawprojectpart.cpp @@ -11,13 +11,14 @@ #include "target.h" #include + #include namespace ProjectExplorer { RawProjectPartFlags::RawProjectPartFlags(const ToolChain *toolChain, const QStringList &commandLineFlags, - const QString &includeFileBaseDir) + const Utils::FilePath &includeFileBaseDir) { // Keep the following cheap/non-blocking for the ui thread. Expensive // operations are encapsulated in ToolChainInfo as "runners". @@ -25,7 +26,8 @@ RawProjectPartFlags::RawProjectPartFlags(const ToolChain *toolChain, if (toolChain) { warningFlags = toolChain->warningFlags(commandLineFlags); languageExtensions = toolChain->languageExtensions(commandLineFlags); - includedFiles = toolChain->includedFiles(commandLineFlags, includeFileBaseDir); + includedFiles = Utils::transform(toolChain->includedFiles(commandLineFlags, includeFileBaseDir), + &Utils::FilePath::toFSPathString); } } diff --git a/src/plugins/projectexplorer/rawprojectpart.h b/src/plugins/projectexplorer/rawprojectpart.h index 580c83d439d..ca210ed43e2 100644 --- a/src/plugins/projectexplorer/rawprojectpart.h +++ b/src/plugins/projectexplorer/rawprojectpart.h @@ -37,7 +37,7 @@ class PROJECTEXPLORER_EXPORT RawProjectPartFlags public: RawProjectPartFlags() = default; RawProjectPartFlags(const ToolChain *toolChain, const QStringList &commandLineFlags, - const QString &includeFileBaseDir); + const Utils::FilePath &includeFileBaseDir); public: QStringList commandLineFlags; diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index 1a3d3d43f59..dfca4040fe3 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -192,7 +192,7 @@ bool ToolChain::isValid() const return d->m_isValid.value_or(false); } -QStringList ToolChain::includedFiles(const QStringList &flags, const QString &directory) const +FilePaths ToolChain::includedFiles(const QStringList &flags, const FilePath &directory) const { Q_UNUSED(flags) Q_UNUSED(directory) @@ -466,12 +466,12 @@ Utils::LanguageVersion ToolChain::languageVersion(const Utils::Id &language, con } } -QStringList ToolChain::includedFiles(const QString &option, - const QStringList &flags, - const QString &directoryPath, - PossiblyConcatenatedFlag possiblyConcatenated) +FilePaths ToolChain::includedFiles(const QString &option, + const QStringList &flags, + const FilePath &directoryPath, + PossiblyConcatenatedFlag possiblyConcatenated) { - QStringList result; + FilePaths result; for (int i = 0; i < flags.size(); ++i) { QString includeFile; @@ -484,11 +484,8 @@ QStringList ToolChain::includedFiles(const QString &option, if (includeFile.isEmpty() && flag == option && i + 1 < flags.size()) includeFile = flags[++i]; - if (!includeFile.isEmpty()) { - if (!QFileInfo(includeFile).isAbsolute()) - includeFile = directoryPath + "/" + includeFile; - result.append(QDir::cleanPath(includeFile)); - } + if (!includeFile.isEmpty()) + result.append(directoryPath.resolvePath(includeFile)); } return result; diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index 15bee2fdaa8..35cad5333ee 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -102,7 +102,7 @@ public: virtual Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const = 0; virtual Utils::WarningFlags warningFlags(const QStringList &cflags) const = 0; - virtual QStringList includedFiles(const QStringList &flags, const QString &directory) const; + virtual Utils::FilePaths includedFiles(const QStringList &flags, const Utils::FilePath &directory) const; virtual QString sysRoot() const; QString explicitCodeModelTargetTriple() const; @@ -184,10 +184,10 @@ protected: virtual bool fromMap(const QVariantMap &data); enum class PossiblyConcatenatedFlag { No, Yes }; - static QStringList includedFiles(const QString &option, - const QStringList &flags, - const QString &directoryPath, - PossiblyConcatenatedFlag possiblyConcatenated); + static Utils::FilePaths includedFiles(const QString &option, + const QStringList &flags, + const Utils::FilePath &directoryPath, + PossiblyConcatenatedFlag possiblyConcatenated); private: ToolChain(const ToolChain &) = delete; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index b4f1bea8dcd..3c78099b0f9 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -337,7 +337,7 @@ void QmakeBuildSystem::updateCppCodeModel() rpp.setBuildTargetType(BuildTargetType::Unknown); break; } - const QString includeFileBaseDir = pro->sourceDir().toString(); + const FilePath includeFileBaseDir = pro->sourceDir(); QStringList cxxArgs = pro->variableValue(Variable::CppFlags); QStringList cArgs = pro->variableValue(Variable::CFlags); From ba39377edb674b75ae8fe3526e230c91a7eb93f3 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 16:15:13 +0100 Subject: [PATCH 0279/1447] Qnx: Simplify QnxDeviceWizard interface Also provide a parent. Change-Id: I8ca95d09af8126b9e822f891ef815bfcaa84a9d2 Reviewed-by: Marcus Tillmanns --- src/plugins/qnx/qnxdevice.cpp | 8 +-- src/plugins/qnx/qnxdevice.h | 7 +- src/plugins/qnx/qnxdevicewizard.cpp | 69 ++++++++++++------- src/plugins/qnx/qnxdevicewizard.h | 30 +------- ...nericlinuxdeviceconfigurationwizardpages.h | 2 +- 5 files changed, 52 insertions(+), 64 deletions(-) diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 4460d5bf00d..7f1d73ae0d1 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -41,7 +41,6 @@ public: : RemoteLinuxSignalOperation(device) {} - QString killProcessByNameCommandLine(const QString &filePath) const override { return QString::fromLatin1("%1; %2").arg(signalProcessByNameQnxCommandLine(filePath, 15), @@ -138,12 +137,7 @@ QnxDeviceFactory::QnxDeviceFactory() : IDeviceFactory(Constants::QNX_QNX_OS_TYPE setCombinedIcon(":/qnx/images/qnxdevicesmall.png", ":/qnx/images/qnxdevice.png"); setConstructionFunction(&QnxDevice::create); - setCreator([] { - QnxDeviceWizard wizard; - if (wizard.exec() != QDialog::Accepted) - return IDevice::Ptr(); - return wizard.device(); - }); + setCreator(&runDeviceWizard); } } // Qnx::Internal diff --git a/src/plugins/qnx/qnxdevice.h b/src/plugins/qnx/qnxdevice.h index f1deaf6a377..34940580e1a 100644 --- a/src/plugins/qnx/qnxdevice.h +++ b/src/plugins/qnx/qnxdevice.h @@ -22,16 +22,15 @@ public: int qnxVersion() const; -protected: +private: + QnxDevice(); + void fromMap(const QVariantMap &map) final; QVariantMap toMap() const final; QString interruptProcessByNameCommandLine(const QString &filePath) const; QString killProcessByNameCommandLine(const QString &filePath) const; -private: - QnxDevice(); - void updateVersionNumber() const; mutable int m_versionNumber = 0; diff --git a/src/plugins/qnx/qnxdevicewizard.cpp b/src/plugins/qnx/qnxdevicewizard.cpp index 1e7d1cfcdd6..cd4a132ee4a 100644 --- a/src/plugins/qnx/qnxdevicewizard.cpp +++ b/src/plugins/qnx/qnxdevicewizard.cpp @@ -4,45 +4,66 @@ #include "qnxdevicewizard.h" #include "qnxconstants.h" +#include "qnxdevice.h" #include "qnxtr.h" +#include + #include + #include + #include +#include using namespace ProjectExplorer; +using namespace RemoteLinux; +using namespace Utils; namespace Qnx::Internal { -QnxDeviceWizard::QnxDeviceWizard(QWidget *parent) : - Utils::Wizard(parent) +class QnxDeviceWizard : public Wizard { - setWindowTitle(Tr::tr("New QNX Device Configuration Setup")); +public: + QnxDeviceWizard() : Wizard(Core::ICore::dialogParent()) + { + setWindowTitle(Tr::tr("New QNX Device Configuration Setup")); - m_setupPage = new RemoteLinux::GenericLinuxDeviceConfigurationWizardSetupPage(this); - m_keyDeploymentPage - = new RemoteLinux::GenericLinuxDeviceConfigurationWizardKeyDeploymentPage(this); - m_finalPage = new RemoteLinux::GenericLinuxDeviceConfigurationWizardFinalPage(this); + addPage(&m_setupPage); + addPage(&m_keyDeploymentPage); + addPage(&m_finalPage); + m_finalPage.setCommitPage(true); - setPage(SetupPageId, m_setupPage); - setPage(KeyDeploymenPageId, m_keyDeploymentPage); - setPage(FinalPageId, m_finalPage); - m_finalPage->setCommitPage(true); - SshParameters sshParams; - sshParams.timeout = 10; - m_device = QnxDevice::create(); - m_device->setupId(IDevice::ManuallyAdded); - m_device->setType(Constants::QNX_QNX_OS_TYPE); - m_device->setMachineType(IDevice::Hardware); - m_device->setSshParameters(sshParams); - m_device->setFreePorts(Utils::PortList::fromString(QLatin1String("10000-10100"))); - m_setupPage->setDevice(m_device); - m_keyDeploymentPage->setDevice(m_device); -} + SshParameters sshParams; + sshParams.timeout = 10; + m_device = QnxDevice::create(); + m_device->setupId(IDevice::ManuallyAdded); + m_device->setType(Constants::QNX_QNX_OS_TYPE); + m_device->setMachineType(IDevice::Hardware); + m_device->setSshParameters(sshParams); + m_device->setFreePorts(PortList::fromString("10000-10100")); -IDevice::Ptr QnxDeviceWizard::device() + m_setupPage.setDevice(m_device); + m_keyDeploymentPage.setDevice(m_device); + } + + IDevice::Ptr device() const { return m_device; } + +private: + GenericLinuxDeviceConfigurationWizardSetupPage m_setupPage; + GenericLinuxDeviceConfigurationWizardKeyDeploymentPage m_keyDeploymentPage; + GenericLinuxDeviceConfigurationWizardFinalPage m_finalPage; + + LinuxDevice::Ptr m_device; +}; + + +IDevice::Ptr runDeviceWizard() { - return m_device; + QnxDeviceWizard wizard; + if (wizard.exec() != QDialog::Accepted) + return IDevice::Ptr(); + return wizard.device(); } } // Qnx::Internal diff --git a/src/plugins/qnx/qnxdevicewizard.h b/src/plugins/qnx/qnxdevicewizard.h index ce30658ce11..3adaa337011 100644 --- a/src/plugins/qnx/qnxdevicewizard.h +++ b/src/plugins/qnx/qnxdevicewizard.h @@ -3,36 +3,10 @@ #pragma once -#include "qnxdevice.h" - -#include - -namespace RemoteLinux { -class GenericLinuxDeviceConfigurationWizardSetupPage; -class GenericLinuxDeviceConfigurationWizardKeyDeploymentPage; -class GenericLinuxDeviceConfigurationWizardFinalPage; -} +#include namespace Qnx::Internal { -class QnxDeviceWizard : public Utils::Wizard -{ -public: - explicit QnxDeviceWizard(QWidget *parent = nullptr); - - ProjectExplorer::IDevice::Ptr device(); - -private: - enum PageId { - SetupPageId, - KeyDeploymenPageId, - FinalPageId - }; - - RemoteLinux::GenericLinuxDeviceConfigurationWizardSetupPage *m_setupPage; - RemoteLinux::GenericLinuxDeviceConfigurationWizardKeyDeploymentPage *m_keyDeploymentPage; - RemoteLinux::GenericLinuxDeviceConfigurationWizardFinalPage *m_finalPage; - QnxDevice::Ptr m_device; -}; +ProjectExplorer::IDevice::Ptr runDeviceWizard(); } // Qnx::Internal diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h index 6e5e00119ad..55388f48147 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h @@ -64,7 +64,7 @@ class REMOTELINUX_EXPORT GenericLinuxDeviceConfigurationWizardFinalPage final : { Q_OBJECT public: - GenericLinuxDeviceConfigurationWizardFinalPage(QWidget *parent); + GenericLinuxDeviceConfigurationWizardFinalPage(QWidget *parent = nullptr); ~GenericLinuxDeviceConfigurationWizardFinalPage() override; protected: From 0842f69888a575c6feb74880978acb1bd397e697 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 15 Mar 2023 11:55:47 +0200 Subject: [PATCH 0280/1447] Terminal: Fix MSVC "loss of data" warning Change-Id: I856223c4830b5d78290d492b18cc2037e96fcc20 Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/scrollback.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/terminal/scrollback.h b/src/plugins/terminal/scrollback.h index 72c64547a15..356b44fa535 100644 --- a/src/plugins/terminal/scrollback.h +++ b/src/plugins/terminal/scrollback.h @@ -38,7 +38,7 @@ public: Scrollback(size_t capacity); Scrollback() = delete; - int capacity() const { return m_capacity; }; + int capacity() const { return static_cast(m_capacity); }; int size() const { return static_cast(m_deque.size()); }; const Line &line(size_t index) const { return m_deque.at(index); }; From 52a7205965a1e7991a80bba4cf6aa3e45e9be003 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 16:38:02 +0100 Subject: [PATCH 0281/1447] Qnx: Simplify QnxDeviceTester Change-Id: I789c5ab4fa4a6f79f89db4159d889f67223b8619 Reviewed-by: Marcus Tillmanns --- src/plugins/qnx/qnxdevicetester.cpp | 80 ++++++++++++----------------- src/plugins/qnx/qnxdevicetester.h | 7 +-- 2 files changed, 34 insertions(+), 53 deletions(-) diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp index bd78f2ec228..daecd468f99 100644 --- a/src/plugins/qnx/qnxdevicetester.cpp +++ b/src/plugins/qnx/qnxdevicetester.cpp @@ -15,55 +15,46 @@ using namespace Utils; namespace Qnx::Internal { QnxDeviceTester::QnxDeviceTester(QObject *parent) - : ProjectExplorer::DeviceTester(parent) -{ - m_genericTester = new RemoteLinux::GenericLinuxDeviceTester(this); - connect(m_genericTester, &DeviceTester::progressMessage, - this, &DeviceTester::progressMessage); - connect(m_genericTester, &DeviceTester::errorMessage, - this, &DeviceTester::errorMessage); - connect(m_genericTester, &DeviceTester::finished, - this, &QnxDeviceTester::finished); -} - -static QStringList versionSpecificCommandsToTest(int versionNumber) -{ - if (versionNumber > 0x060500) - return {"slog2info"}; - return {}; -} + : RemoteLinux::GenericLinuxDeviceTester(parent) +{} void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) { - static const QStringList s_commandsToTest = {"awk", - "cat", - "cut", - "df", - "grep", - "kill", - "netstat", - "mkdir", - "print", - "printf", - "pidin", - "read", - "rm", - "sed", - "sleep", - "tail", - "uname"}; - m_device = device; - QnxDevice::ConstPtr qnxDevice = m_device.dynamicCast(); - m_genericTester->setExtraCommandsToTest( - s_commandsToTest + versionSpecificCommandsToTest(qnxDevice->qnxVersion())); + QStringList commandsToTest = { + "awk", + "cat", + "cut", + "df", + "grep", + "kill", + "netstat", + "mkdir", + "print", + "printf", + "pidin", + "read", + "rm", + "sed", + "sleep", + "tail", + "uname" + }; + + QnxDevice::ConstPtr qnxDevice = device.dynamicCast(); + QTC_ASSERT(qnxDevice, return); + + if (qnxDevice->qnxVersion() > 0x060500) + commandsToTest.append("slog2info"); + + setExtraCommandsToTest(commandsToTest); using namespace Tasking; - auto setupHandler = [this](QtcProcess &process) { + auto setupHandler = [device, this](QtcProcess &process) { emit progressMessage(Tr::tr("Checking that files can be created in %1...") .arg(Constants::QNX_TMP_DIR)); const QString pidFile = QString("%1/qtc_xxxx.pid").arg(Constants::QNX_TMP_DIR); - const CommandLine cmd(m_device->filePath("/bin/sh"), + const CommandLine cmd(device->filePath("/bin/sh"), {"-c", QLatin1String("rm %1 > /dev/null 2>&1; echo ABC > %1 && rm %1").arg(pidFile)}); process.setCommand(cmd); }; @@ -77,14 +68,9 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) : Tr::tr("Files cannot be created in %1.").arg(Constants::QNX_TMP_DIR); emit errorMessage(message + '\n'); }; - m_genericTester->setExtraTests({Process(setupHandler, doneHandler, errorHandler)}); + setExtraTests({Process(setupHandler, doneHandler, errorHandler)}); - m_genericTester->testDevice(device); -} - -void QnxDeviceTester::stopTest() -{ - m_genericTester->stopTest(); + RemoteLinux::GenericLinuxDeviceTester::testDevice(device); } } // Qnx::Internal diff --git a/src/plugins/qnx/qnxdevicetester.h b/src/plugins/qnx/qnxdevicetester.h index d23428b3532..f8fc4be8821 100644 --- a/src/plugins/qnx/qnxdevicetester.h +++ b/src/plugins/qnx/qnxdevicetester.h @@ -7,17 +7,12 @@ namespace Qnx::Internal { -class QnxDeviceTester : public ProjectExplorer::DeviceTester +class QnxDeviceTester : public RemoteLinux::GenericLinuxDeviceTester { public: explicit QnxDeviceTester(QObject *parent = nullptr); void testDevice(const ProjectExplorer::IDevice::Ptr &device) override; - void stopTest() override; - -private: - RemoteLinux::GenericLinuxDeviceTester *m_genericTester = nullptr; - ProjectExplorer::IDevice::ConstPtr m_device; }; } // Qnx::Internal From 821dce1e9d3d76d6ccb4920230be7e603482c97d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 17:19:01 +0100 Subject: [PATCH 0282/1447] Qnx: Drop support for QNX 6.5 Or, rather, assume that slog2info is available and handle a missting slog2info more or less gracefully. Change-Id: I739482ff0a3d88ee7ff735adf42809cc2ee3e510 Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/plugins/qnx/qnxdevice.cpp | 42 ----------------------------- src/plugins/qnx/qnxdevice.h | 9 ------- src/plugins/qnx/qnxdevicetester.cpp | 12 +++------ src/plugins/qnx/slog2inforunner.cpp | 9 +++---- 4 files changed, 6 insertions(+), 66 deletions(-) diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 7f1d73ae0d1..dac5c9698b3 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -23,8 +23,6 @@ using namespace Utils; namespace Qnx::Internal { -const char QnxVersionKey[] = "QnxVersion"; - static QString signalProcessByNameQnxCommandLine(const QString &filePath, int sig) { QString executable = filePath; @@ -65,46 +63,6 @@ QnxDevice::QnxDevice() }}); } -int QnxDevice::qnxVersion() const -{ - if (m_versionNumber == 0) - updateVersionNumber(); - - return m_versionNumber; -} - -void QnxDevice::updateVersionNumber() const -{ - QtcProcess versionNumberProcess; - - versionNumberProcess.setCommand({filePath("uname"), {"-r"}}); - versionNumberProcess.runBlocking(EventLoopMode::On); - - QByteArray output = versionNumberProcess.readAllRawStandardOutput(); - QString versionMessage = QString::fromLatin1(output); - const QRegularExpression versionNumberRegExp("(\\d+)\\.(\\d+)\\.(\\d+)"); - const QRegularExpressionMatch match = versionNumberRegExp.match(versionMessage); - if (match.hasMatch()) { - int major = match.captured(1).toInt(); - int minor = match.captured(2).toInt(); - int patch = match.captured(3).toInt(); - m_versionNumber = (major << 16)|(minor<<8)|(patch); - } -} - -void QnxDevice::fromMap(const QVariantMap &map) -{ - m_versionNumber = map.value(QLatin1String(QnxVersionKey), 0).toInt(); - LinuxDevice::fromMap(map); -} - -QVariantMap QnxDevice::toMap() const -{ - QVariantMap map(LinuxDevice::toMap()); - map.insert(QLatin1String(QnxVersionKey), m_versionNumber); - return map; -} - PortsGatheringMethod QnxDevice::portsGatheringMethod() const { return { diff --git a/src/plugins/qnx/qnxdevice.h b/src/plugins/qnx/qnxdevice.h index 34940580e1a..e2e6403432e 100644 --- a/src/plugins/qnx/qnxdevice.h +++ b/src/plugins/qnx/qnxdevice.h @@ -20,20 +20,11 @@ public: ProjectExplorer::DeviceTester *createDeviceTester() const override; - int qnxVersion() const; - private: QnxDevice(); - void fromMap(const QVariantMap &map) final; - QVariantMap toMap() const final; - QString interruptProcessByNameCommandLine(const QString &filePath) const; QString killProcessByNameCommandLine(const QString &filePath) const; - - void updateVersionNumber() const; - - mutable int m_versionNumber = 0; }; class QnxDeviceFactory final : public ProjectExplorer::IDeviceFactory diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp index daecd468f99..1fd755138de 100644 --- a/src/plugins/qnx/qnxdevicetester.cpp +++ b/src/plugins/qnx/qnxdevicetester.cpp @@ -4,7 +4,6 @@ #include "qnxdevicetester.h" #include "qnxconstants.h" -#include "qnxdevice.h" #include "qnxtr.h" #include @@ -20,7 +19,7 @@ QnxDeviceTester::QnxDeviceTester(QObject *parent) void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) { - QStringList commandsToTest = { + static const QStringList commandsToTest { "awk", "cat", "cut", @@ -37,15 +36,10 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) "sed", "sleep", "tail", - "uname" + "uname", + "slog2info" }; - QnxDevice::ConstPtr qnxDevice = device.dynamicCast(); - QTC_ASSERT(qnxDevice, return); - - if (qnxDevice->qnxVersion() > 0x060500) - commandsToTest.append("slog2info"); - setExtraCommandsToTest(commandsToTest); using namespace Tasking; diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 58509782c5b..e350c75f6ec 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -3,9 +3,9 @@ #include "slog2inforunner.h" -#include "qnxdevice.h" #include "qnxtr.h" +#include #include #include @@ -41,11 +41,8 @@ void Slog2InfoRunner::start() m_found = true; }; const auto testErrorHandler = [this](const QtcProcess &) { - QnxDevice::ConstPtr qnxDevice = device().dynamicCast(); - if (qnxDevice && qnxDevice->qnxVersion() > 0x060500) { - appendMessage(Tr::tr("Warning: \"slog2info\" is not found on the device, " - "debug output not available."), ErrorMessageFormat); - } + appendMessage(Tr::tr("Warning: \"slog2info\" is not found on the device, " + "debug output not available."), ErrorMessageFormat); }; const auto launchTimeStartHandler = [this](QtcProcess &process) { From 13baedad8241d1180c44a467be085358a7663359 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 17:42:39 +0100 Subject: [PATCH 0283/1447] Qnx: Fix passing nto-executable Change-Id: I6c1749a74d153a8dbbbef891e8eee230226e452d Reviewed-by: hjk --- src/plugins/debugger/gdb/gdbengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 095e46f1770..b2f1865f6f7 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4853,7 +4853,7 @@ void GdbEngine::handleTargetQnx(const DebuggerResponse &response) if (rp.attachPID.isValid()) runCommand({"attach " + QString::number(rp.attachPID.pid()), CB(handleRemoteAttach)}); else if (!rp.inferior.command.isEmpty()) - runCommand({"set nto-executable " + rp.inferior.command.executable().toString(), + runCommand({"set nto-executable " + rp.inferior.command.executable().path(), CB(handleSetNtoExecutable)}); else handleInferiorPrepared(); From 47ed25e95dd1e7a5c0ac937785e7127dd7592cd0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 14 Mar 2023 23:19:14 +0100 Subject: [PATCH 0284/1447] ModelEditor: Add lacking calls to prepareSearch() Before matchesFor() are called. Change-Id: If55dc078c8c2ff79ee01d2873eaf5e22132ddc84 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/modeleditor/elementtasks.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp index 74c3faa3f4f..1df37cb71ca 100644 --- a/src/plugins/modeleditor/elementtasks.cpp +++ b/src/plugins/modeleditor/elementtasks.cpp @@ -94,6 +94,7 @@ bool ElementTasks::hasClassDefinition(const qmt::MElement *element) const return false; QFutureInterface dummyInterface; + classesFilter->prepareSearch(qualifiedClassName); const QList matches = classesFilter->matchesFor(dummyInterface, qualifiedClassName); for (const LocatorFilterEntry &entry : matches) { @@ -130,6 +131,7 @@ void ElementTasks::openClassDefinition(const qmt::MElement *element) return; QFutureInterface dummyInterface; + classesFilter->prepareSearch(qualifiedClassName); const QList matches = classesFilter->matchesFor(dummyInterface, qualifiedClassName); for (const LocatorFilterEntry &entry : matches) { From 0dc61f55c3919765ae0fd453de2719daeb4f0718 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Mar 2023 18:18:39 +0100 Subject: [PATCH 0285/1447] Debugger: Use more FilePath in source file handling Needed for the double-remote case. With this we have proper breakpoint markers in the text editor for a remotely running gdb on a remotely loaded project. Change-Id: If80e4a4108a4a0bcdd7612a59e2bd695213f5ea5 Reviewed-by: Orgad Shaneh --- src/plugins/debugger/breakhandler.cpp | 4 +- src/plugins/debugger/breakhandler.h | 2 +- src/plugins/debugger/breakpoint.cpp | 7 +- src/plugins/debugger/breakpoint.h | 2 +- src/plugins/debugger/debuggerruncontrol.cpp | 3 + src/plugins/debugger/gdb/gdbengine.cpp | 86 +++++++++---------- src/plugins/debugger/gdb/gdbengine.h | 12 +-- src/plugins/debugger/qml/qmlengine.cpp | 13 ++- src/plugins/debugger/qml/qmlengine.h | 2 +- src/plugins/debugger/qml/qmlengineutils.cpp | 8 +- src/plugins/debugger/qml/qmlengineutils.h | 4 +- .../debugger/qml/qmlinspectoragent.cpp | 7 +- src/plugins/debugger/sourcefileshandler.cpp | 14 +-- src/plugins/debugger/sourcefileshandler.h | 6 +- 14 files changed, 87 insertions(+), 83 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index bcc50a4b0d0..f13ac94d89b 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1126,9 +1126,9 @@ void BreakpointItem::addToCommand(DebuggerCommand *cmd) const cmd->arg("expression", requested.expression); } -void BreakpointItem::updateFromGdbOutput(const GdbMi &bkpt) +void BreakpointItem::updateFromGdbOutput(const GdbMi &bkpt, const FilePath &fileRoot) { - m_parameters.updateFromGdbOutput(bkpt); + m_parameters.updateFromGdbOutput(bkpt, fileRoot); adjustMarker(); } diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 1024783db38..0b939a011fc 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -107,7 +107,7 @@ public: const BreakpointParameters &requestedParameters() const; void addToCommand(DebuggerCommand *cmd) const; - void updateFromGdbOutput(const GdbMi &bkpt); + void updateFromGdbOutput(const GdbMi &bkpt, const Utils::FilePath &fileRoot); int modelId() const; QString responseId() const { return m_responseId; } diff --git a/src/plugins/debugger/breakpoint.cpp b/src/plugins/debugger/breakpoint.cpp index 8d456ef67f6..79e2badf7b5 100644 --- a/src/plugins/debugger/breakpoint.cpp +++ b/src/plugins/debugger/breakpoint.cpp @@ -265,7 +265,8 @@ static QString cleanupFullName(const QString &fileName) return cleanFilePath; } -void BreakpointParameters::updateFromGdbOutput(const GdbMi &bkpt) + +void BreakpointParameters::updateFromGdbOutput(const GdbMi &bkpt, const Utils::FilePath &fileRoot) { QTC_ASSERT(bkpt.isValid(), return); @@ -358,7 +359,7 @@ void BreakpointParameters::updateFromGdbOutput(const GdbMi &bkpt) QString name; if (!fullName.isEmpty()) { name = cleanupFullName(fullName); - fileName = Utils::FilePath::fromString(name); + fileName = fileRoot.withNewPath(name); //if (data->markerFileName().isEmpty()) // data->setMarkerFileName(name); } else { @@ -367,7 +368,7 @@ void BreakpointParameters::updateFromGdbOutput(const GdbMi &bkpt) // gdb's own. No point in assigning markerFileName for now. } if (!name.isEmpty()) - fileName = Utils::FilePath::fromString(name); + fileName = fileRoot.withNewPath(name); if (fileName.isEmpty()) updateLocation(originalLocation); diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h index 52a150f15e2..b5ea0628da7 100644 --- a/src/plugins/debugger/breakpoint.h +++ b/src/plugins/debugger/breakpoint.h @@ -128,7 +128,7 @@ public: bool isQmlFileAndLineBreakpoint() const; QString toString() const; void updateLocation(const QString &location); // file.cpp:42 - void updateFromGdbOutput(const GdbMi &bkpt); + void updateFromGdbOutput(const GdbMi &bkpt, const Utils::FilePath &fileRoot); bool operator==(const BreakpointParameters &p) const { return equals(p); } bool operator!=(const BreakpointParameters &p) const { return !equals(p); } diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 3a5d84d3b6b..d972413bbb0 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -901,6 +901,9 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm if (Project *project = runControl->project()) { m_runParameters.projectSourceDirectory = project->projectDirectory(); m_runParameters.projectSourceFiles = project->files(Project::SourceFiles); + } else { + m_runParameters.projectSourceDirectory = m_runParameters.debugger.command.executable().parentDir(); + m_runParameters.projectSourceFiles.clear(); } m_runParameters.toolChainAbi = ToolChainKitAspect::targetAbi(kit); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index b2f1865f6f7..1e17d97d10e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -539,6 +539,7 @@ void GdbEngine::handleAsyncOutput(const QStringView asyncClass, const GdbMi &res ba.remove(pos1, pos3 - pos1 + 1); GdbMi res; res.fromString(ba); + const FilePath &fileRoot = runParameters().projectSourceDirectory; BreakHandler *handler = breakHandler(); Breakpoint bp; for (const GdbMi &bkpt : res) { @@ -547,13 +548,13 @@ void GdbEngine::handleAsyncOutput(const QStringView asyncClass, const GdbMi &res // A sub-breakpoint. QTC_ASSERT(bp, continue); SubBreakpoint loc = bp->findOrCreateSubBreakpoint(nr); - loc->params.updateFromGdbOutput(bkpt); + loc->params.updateFromGdbOutput(bkpt, fileRoot); loc->params.type = bp->type(); } else { // A primary breakpoint. bp = handler->findBreakpointByResponseId(nr); if (bp) - bp->updateFromGdbOutput(bkpt); + bp->updateFromGdbOutput(bkpt, fileRoot); } } if (bp) @@ -569,7 +570,7 @@ void GdbEngine::handleAsyncOutput(const QStringView asyncClass, const GdbMi &res const QString nr = bkpt["number"].data(); BreakpointParameters br; br.type = BreakpointByFileAndLine; - br.updateFromGdbOutput(bkpt); + br.updateFromGdbOutput(bkpt, runParameters().projectSourceDirectory); handler->handleAlienBreakpoint(nr, br); } } else if (asyncClass == u"breakpoint-deleted") { @@ -1028,7 +1029,7 @@ void GdbEngine::handleQuerySources(const DebuggerResponse &response) { m_sourcesListUpdating = false; if (response.resultClass == ResultDone) { - QMap oldShortToFull = m_shortToFullName; + QMap oldShortToFull = m_shortToFullName; m_shortToFullName.clear(); m_fullToShortName.clear(); // "^done,files=[{file="../../../../bin/dumper/dumper.cpp", @@ -1039,7 +1040,7 @@ void GdbEngine::handleQuerySources(const DebuggerResponse &response) continue; GdbMi fullName = item["fullname"]; QString file = fileName.data(); - QString full; + FilePath full; if (fullName.isValid()) { full = cleanupFullName(fullName.data()); m_fullToShortName[full] = file; @@ -1183,7 +1184,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) const QString nr = data["bkptno"].data(); int lineNumber = 0; - QString fullName; + FilePath fullName; QString function; QString language; if (frame.isValid()) { @@ -1196,15 +1197,13 @@ void GdbEngine::handleStopResponse(const GdbMi &data) lineNumber = lineNumberG.toInt(); fullName = cleanupFullName(frame["fullname"].data()); if (fullName.isEmpty()) - fullName = frame["file"].data(); + fullName = runParameters().projectSourceDirectory.withNewPath(frame["file"].data()); } // found line number } else { showMessage("INVALID STOPPED REASON", LogWarning); } - const FilePath onDevicePath = FilePath::fromString(fullName).onDevice( - runParameters().debugger.command.executable()); - const FilePath fileName = onDevicePath.localSource().value_or(onDevicePath); + const FilePath fileName = fullName.localSource().value_or(fullName); if (!nr.isEmpty() && frame.isValid()) { // Use opportunity to update the breakpoint marker position. @@ -1560,50 +1559,47 @@ void GdbEngine::handleExecuteContinue(const DebuggerResponse &response) } } -QString GdbEngine::fullName(const QString &fileName) +FilePath GdbEngine::fullName(const QString &fileName) { if (fileName.isEmpty()) - return QString(); - QTC_ASSERT(!m_sourcesListUpdating, /* */); - return m_shortToFullName.value(fileName, QString()); + return {}; + QTC_CHECK(!m_sourcesListUpdating); + return m_shortToFullName.value(fileName, {}); } -QString GdbEngine::cleanupFullName(const QString &fileName) +FilePath GdbEngine::cleanupFullName(const QString &fileName) { - QString cleanFilePath = fileName; + FilePath cleanFilePath = + runParameters().projectSourceDirectory.withNewPath(fileName).cleanPath(); // Gdb running on windows often delivers "fullnames" which // (a) have no drive letter and (b) are not normalized. if (Abi::hostAbi().os() == Abi::WindowsOS) { if (fileName.isEmpty()) - return QString(); - QFileInfo fi(fileName); - if (fi.isReadable()) - cleanFilePath = QDir::cleanPath(fi.absoluteFilePath()); + return {}; } if (!debuggerSettings()->autoEnrichParameters.value()) return cleanFilePath; - const QString sysroot = runParameters().sysRoot.toString(); - if (QFileInfo(cleanFilePath).isReadable()) + if (cleanFilePath.isReadableFile()) return cleanFilePath; + + const FilePath sysroot = runParameters().sysRoot; if (!sysroot.isEmpty() && fileName.startsWith('/')) { - cleanFilePath = sysroot + fileName; - if (QFileInfo(cleanFilePath).isReadable()) + cleanFilePath = sysroot.pathAppended(fileName.mid(1)); + if (cleanFilePath.isReadableFile()) return cleanFilePath; } if (m_baseNameToFullName.isEmpty()) { - FilePath filePath = FilePath::fromString(sysroot + "/usr/src/debug"); + FilePath filePath = sysroot.pathAppended("/usr/src/debug"); if (filePath.isDir()) { filePath.iterateDirectory( [this](const FilePath &filePath) { QString name = filePath.fileName(); - if (!name.startsWith('.')) { - QString path = filePath.path(); - m_baseNameToFullName.insert(name, path); - } + if (!name.startsWith('.')) + m_baseNameToFullName.insert(name, filePath); return IterationPolicy::Continue; }, {{"*"}, QDir::NoFilter, QDirIterator::Subdirectories}); @@ -1613,7 +1609,7 @@ QString GdbEngine::cleanupFullName(const QString &fileName) cleanFilePath.clear(); const QString base = FilePath::fromUserInput(fileName).fileName(); - QMultiMap::const_iterator jt = m_baseNameToFullName.constFind(base); + auto jt = m_baseNameToFullName.constFind(base); while (jt != m_baseNameToFullName.constEnd() && jt.key() == base) { // FIXME: Use some heuristics to find the "best" match. return jt.value(); @@ -1950,7 +1946,7 @@ void GdbEngine::executeRunToLine(const ContextData &data) if (data.address) loc = addressSpec(data.address); else - loc = '"' + breakLocation(data.fileName.toString()) + '"' + ':' + QString::number(data.lineNumber); + loc = '"' + breakLocation(data.fileName) + '"' + ':' + QString::number(data.lineNumber); runCommand({"tbreak " + loc}); runCommand({"continue", NativeCommand|RunRequest, CB(handleExecuteRunToLine)}); @@ -1978,7 +1974,7 @@ void GdbEngine::executeJumpToLine(const ContextData &data) if (data.address) loc = addressSpec(data.address); else - loc = '"' + breakLocation(data.fileName.toString()) + '"' + ':' + QString::number(data.lineNumber); + loc = '"' + breakLocation(data.fileName) + '"' + ':' + QString::number(data.lineNumber); runCommand({"tbreak " + loc}); notifyInferiorRunRequested(); @@ -2052,11 +2048,11 @@ void GdbEngine::setTokenBarrier() // ////////////////////////////////////////////////////////////////////// -QString GdbEngine::breakLocation(const QString &file) const +QString GdbEngine::breakLocation(const FilePath &file) const { QString where = m_fullToShortName.value(file); if (where.isEmpty()) - return FilePath::fromString(file).fileName(); + return file.fileName(); return where; } @@ -2080,7 +2076,7 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data) usage = BreakpointUseShortPath; const QString fileName = usage == BreakpointUseFullPath - ? data.fileName.toString() : breakLocation(data.fileName.toString()); + ? data.fileName.path() : breakLocation(data.fileName); // The argument is simply a C-quoted version of the argument to the // non-MI "break" command, including the "original" quoting it wants. return "\"\\\"" + GdbMi::escapeCString(fileName) + "\\\":" @@ -2094,7 +2090,7 @@ QString GdbEngine::breakpointLocation2(const BreakpointParameters &data) usage = BreakpointUseShortPath; const QString fileName = usage == BreakpointUseFullPath - ? data.fileName.toString() : breakLocation(data.fileName.toString()); + ? data.fileName.path() : breakLocation(data.fileName); return GdbMi::escapeCString(fileName) + ':' + QString::number(data.lineNumber); } @@ -2107,7 +2103,7 @@ void GdbEngine::handleInsertInterpreterBreakpoint(const DebuggerResponse &respon notifyBreakpointInsertOk(bp); } else { bp->setResponseId(response.data["number"].data()); - bp->updateFromGdbOutput(response.data); + bp->updateFromGdbOutput(response.data, runParameters().projectSourceDirectory); notifyBreakpointInsertOk(bp); } } @@ -2117,7 +2113,7 @@ void GdbEngine::handleInterpreterBreakpointModified(const GdbMi &data) int modelId = data["modelid"].toInt(); Breakpoint bp = breakHandler()->findBreakpointByModelId(modelId); QTC_ASSERT(bp, return); - bp->updateFromGdbOutput(data); + bp->updateFromGdbOutput(data, runParameters().projectSourceDirectory); } void GdbEngine::handleWatchInsert(const DebuggerResponse &response, const Breakpoint &bp) @@ -2167,7 +2163,7 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp) // A sub-breakpoint. SubBreakpoint sub = bp->findOrCreateSubBreakpoint(nr); QTC_ASSERT(sub, return); - sub->params.updateFromGdbOutput(bkpt); + sub->params.updateFromGdbOutput(bkpt, runParameters().projectSourceDirectory); sub->params.type = bp->type(); if (usePseudoTracepoints && bp->isTracepoint()) { sub->params.tracepoint = true; @@ -2185,7 +2181,7 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp) const QString subnr = location["number"].data(); SubBreakpoint sub = bp->findOrCreateSubBreakpoint(subnr); QTC_ASSERT(sub, return); - sub->params.updateFromGdbOutput(location); + sub->params.updateFromGdbOutput(location, runParameters().projectSourceDirectory); sub->params.type = bp->type(); if (usePseudoTracepoints && bp->isTracepoint()) { sub->params.tracepoint = true; @@ -2196,7 +2192,7 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp) // A (the?) primary breakpoint. bp->setResponseId(nr); - bp->updateFromGdbOutput(bkpt); + bp->updateFromGdbOutput(bkpt, runParameters().projectSourceDirectory); if (usePseudoTracepoints && bp->isTracepoint()) bp->setMessage(bp->requestedParameters().message); } @@ -2503,7 +2499,7 @@ void GdbEngine::handleTracepointModified(const GdbMi &data) // A sub-breakpoint. QTC_ASSERT(bp, continue); SubBreakpoint loc = bp->findOrCreateSubBreakpoint(nr); - loc->params.updateFromGdbOutput(bkpt); + loc->params.updateFromGdbOutput(bkpt, runParameters().projectSourceDirectory); loc->params.type = bp->type(); if (bp->isTracepoint()) { loc->params.tracepoint = true; @@ -2513,7 +2509,7 @@ void GdbEngine::handleTracepointModified(const GdbMi &data) // A primary breakpoint. bp = handler->findBreakpointByResponseId(nr); if (bp) - bp->updateFromGdbOutput(bkpt); + bp->updateFromGdbOutput(bkpt, runParameters().projectSourceDirectory); } } QTC_ASSERT(bp, return); @@ -3036,7 +3032,7 @@ void GdbEngine::reloadSourceFiles() cmd.callback = [this](const DebuggerResponse &response) { m_sourcesListUpdating = false; if (response.resultClass == ResultDone) { - QMap oldShortToFull = m_shortToFullName; + QMap oldShortToFull = m_shortToFullName; m_shortToFullName.clear(); m_fullToShortName.clear(); // "^done,files=[{file="../../../../bin/dumper/dumper.cpp", @@ -3047,7 +3043,7 @@ void GdbEngine::reloadSourceFiles() continue; GdbMi fullName = item["fullname"]; QString file = fileName.data(); - QString full; + FilePath full; if (fullName.isValid()) { full = cleanupFullName(fullName.data()); m_fullToShortName[full] = file; diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 9fac0347eb3..5e84366b649 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -210,7 +210,7 @@ private: ////////// General Interface ////////// void handleBkpt(const GdbMi &bkpt, const Breakpoint &bp); QString breakpointLocation(const BreakpointParameters &data); // For gdb/MI. QString breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback. - QString breakLocation(const QString &file) const; + QString breakLocation(const Utils::FilePath &file) const; void updateTracepointCaptures(const Breakpoint &bp); // @@ -265,13 +265,13 @@ private: ////////// General Interface ////////// void reloadSourceFilesInternal(); void handleQuerySources(const DebuggerResponse &response); - QString fullName(const QString &fileName); - QString cleanupFullName(const QString &fileName); + Utils::FilePath fullName(const QString &fileName); + Utils::FilePath cleanupFullName(const QString &fileName); // awful hack to keep track of used files - QMap m_shortToFullName; - QMap m_fullToShortName; - QMultiMap m_baseNameToFullName; + QMap m_shortToFullName; + QMap m_fullToShortName; + QMultiMap m_baseNameToFullName; bool m_sourcesListUpdating = false; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index eb1ebc939a8..0730caaf78f 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -1802,10 +1802,10 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) updateScriptSource(name, lineOffset, columnOffset, source); } - QMap files; + QMap files; for (const QString &file : std::as_const(sourceFiles)) { QString shortName = file; - QString fullName = engine->toFileInProject(file); + FilePath fullName = engine->toFileInProject(file); files.insert(shortName, fullName); } @@ -1915,7 +1915,7 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) const QVariantMap script = body.value("script").toMap(); QUrl fileUrl(script.value(NAME).toString()); - QString filePath = engine->toFileInProject(fileUrl); + FilePath filePath = engine->toFileInProject(fileUrl); const QVariantMap exception = body.value("exception").toMap(); QString errorMessage = exception.value("text").toString(); @@ -2045,8 +2045,7 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) stackFrame.function = extractString(body.value("func")); if (stackFrame.function.isEmpty()) stackFrame.function = Tr::tr("Anonymous Function"); - stackFrame.file = FilePath::fromString( - engine->toFileInProject(extractString(body.value("script")))); + stackFrame.file = engine->toFileInProject(extractString(body.value("script"))); stackFrame.usable = stackFrame.file.isReadableFile(); stackFrame.receiver = extractString(body.value("receiver")); stackFrame.line = body.value("line").toInt() + 1; @@ -2444,7 +2443,7 @@ void QmlEnginePrivate::flushSendBuffer() sendBuffer.clear(); } -QString QmlEngine::toFileInProject(const QUrl &fileUrl) +FilePath QmlEngine::toFileInProject(const QUrl &fileUrl) { // make sure file finder is properly initialized const DebuggerRunParameters &rp = runParameters(); @@ -2453,7 +2452,7 @@ QString QmlEngine::toFileInProject(const QUrl &fileUrl) d->fileFinder.setAdditionalSearchDirectories(rp.additionalSearchDirectories); d->fileFinder.setSysroot(rp.sysRoot); - return d->fileFinder.findFile(fileUrl).constFirst().toString(); + return d->fileFinder.findFile(fileUrl).constFirst(); } DebuggerEngine *createQmlEngine() diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index bfdc9bfb005..2006ce081ff 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -25,7 +25,7 @@ public: void logServiceActivity(const QString &service, const QString &logMessage); void expressionEvaluated(quint32 queryId, const QVariant &result); - QString toFileInProject(const QUrl &fileUrl); + Utils::FilePath toFileInProject(const QUrl &fileUrl); private: void disconnected(); diff --git a/src/plugins/debugger/qml/qmlengineutils.cpp b/src/plugins/debugger/qml/qmlengineutils.cpp index 7e304d3c921..80e0ac98f17 100644 --- a/src/plugins/debugger/qml/qmlengineutils.cpp +++ b/src/plugins/debugger/qml/qmlengineutils.cpp @@ -20,6 +20,7 @@ using namespace QmlDebug; using namespace QmlJS; using namespace QmlJS::AST; using namespace TextEditor; +using namespace Utils; namespace Debugger::Internal { @@ -218,11 +219,10 @@ void clearExceptionSelection() } } -QStringList highlightExceptionCode(int lineNumber, const QString &filePath, const QString &errorMessage) +QStringList highlightExceptionCode(int lineNumber, const FilePath &filePath, const QString &errorMessage) { QStringList messages; - const QList editors = DocumentModel::editorsForFilePath( - Utils::FilePath::fromString(filePath)); + const QList editors = DocumentModel::editorsForFilePath(filePath); const TextEditor::FontSettings &fontSettings = TextEditor::TextEditorSettings::fontSettings(); QTextCharFormat errorFormat = fontSettings.toTextCharFormat(TextEditor::C_ERROR); @@ -251,7 +251,7 @@ QStringList highlightExceptionCode(int lineNumber, const QString &filePath, cons selections.append(sel); ed->setExtraSelections(TextEditorWidget::DebuggerExceptionSelection, selections); - messages.append(QString::fromLatin1("%1: %2: %3").arg(filePath).arg(lineNumber).arg(errorMessage)); + messages.append(QString::fromLatin1("%1: %2: %3").arg(filePath.toUserOutput()).arg(lineNumber).arg(errorMessage)); } return messages; } diff --git a/src/plugins/debugger/qml/qmlengineutils.h b/src/plugins/debugger/qml/qmlengineutils.h index 7cf55067b66..325c8f28e93 100644 --- a/src/plugins/debugger/qml/qmlengineutils.h +++ b/src/plugins/debugger/qml/qmlengineutils.h @@ -6,11 +6,13 @@ #include #include +namespace Utils { class FilePath; } + namespace Debugger::Internal { void appendDebugOutput(QtMsgType type, const QString &message, const QmlDebug::QDebugContextInfo &info); void clearExceptionSelection(); -QStringList highlightExceptionCode(int lineNumber, const QString &filePath, const QString &errorMessage); +QStringList highlightExceptionCode(int lineNumber, const Utils::FilePath &filePath, const QString &errorMessage); } // Debugger::Internal diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp index 983e38adc0d..4b632c0f0db 100644 --- a/src/plugins/debugger/qml/qmlinspectoragent.cpp +++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp @@ -32,6 +32,7 @@ using namespace QmlDebug; using namespace QmlDebug::Constants; +using namespace Utils; namespace Debugger::Internal { @@ -541,8 +542,8 @@ void QmlInspectorAgent::buildDebugIdHashRecursive(const ObjectReference &ref) lineNum += match.captured(3).toInt() - 1; } - const QString filePath = m_qmlEngine->toFileInProject(fileUrl); - m_debugIdLocations.insert(ref.debugId(), FileReference(filePath, lineNum, colNum)); + const FilePath filePath = m_qmlEngine->toFileInProject(fileUrl); + m_debugIdLocations.insert(ref.debugId(), FileReference(filePath.toFSPathString(), lineNum, colNum)); const auto children = ref.children(); for (const ObjectReference &it : children) @@ -735,7 +736,7 @@ void QmlInspectorAgent::onShowAppOnTopChanged(bool checked) void QmlInspectorAgent::jumpToObjectDefinitionInEditor(const FileReference &objSource) { - const auto filePath = Utils::FilePath::fromString(m_qmlEngine->toFileInProject(objSource.url())); + const FilePath filePath = m_qmlEngine->toFileInProject(objSource.url()); Core::EditorManager::openEditorAt({filePath, objSource.lineNumber()}); } diff --git a/src/plugins/debugger/sourcefileshandler.cpp b/src/plugins/debugger/sourcefileshandler.cpp index 412f550482a..bec03054173 100644 --- a/src/plugins/debugger/sourcefileshandler.cpp +++ b/src/plugins/debugger/sourcefileshandler.cpp @@ -55,8 +55,8 @@ Qt::ItemFlags SourceFilesHandler::flags(const QModelIndex &index) const { if (index.row() >= m_fullNames.size()) return {}; - QFileInfo fi(m_fullNames.at(index.row())); - return fi.isReadable() ? QAbstractItemModel::flags(index) : Qt::ItemFlags({}); + FilePath filePath = m_fullNames.at(index.row()); + return filePath.isReadableFile() ? QAbstractItemModel::flags(index) : Qt::ItemFlags({}); } QVariant SourceFilesHandler::data(const QModelIndex &index, int role) const @@ -75,7 +75,7 @@ QVariant SourceFilesHandler::data(const QModelIndex &index, int role) const break; case 1: if (role == Qt::DisplayRole) - return m_fullNames.at(row); + return m_fullNames.at(row).toUserOutput(); //if (role == Qt::DecorationRole) // return module.symbolsRead ? icon2 : icon; break; @@ -123,13 +123,13 @@ bool SourceFilesHandler::setData(const QModelIndex &idx, const QVariant &data, i return false; } -void SourceFilesHandler::setSourceFiles(const QMap &sourceFiles) +void SourceFilesHandler::setSourceFiles(const QMap &sourceFiles) { beginResetModel(); m_shortNames.clear(); m_fullNames.clear(); - QMap::ConstIterator it = sourceFiles.begin(); - QMap::ConstIterator et = sourceFiles.end(); + auto it = sourceFiles.begin(); + const auto et = sourceFiles.end(); for (; it != et; ++it) { m_shortNames.append(it.key()); m_fullNames.append(it.value()); @@ -139,7 +139,7 @@ void SourceFilesHandler::setSourceFiles(const QMap &sourceFile void SourceFilesHandler::removeAll() { - setSourceFiles(QMap()); + setSourceFiles({}); //header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); } diff --git a/src/plugins/debugger/sourcefileshandler.h b/src/plugins/debugger/sourcefileshandler.h index dabbdbdad0d..d714eda2e36 100644 --- a/src/plugins/debugger/sourcefileshandler.h +++ b/src/plugins/debugger/sourcefileshandler.h @@ -3,6 +3,8 @@ #pragma once +#include + #include #include @@ -29,7 +31,7 @@ public: void clearModel(); - void setSourceFiles(const QMap &sourceFiles); + void setSourceFiles(const QMap &sourceFiles); void removeAll(); QAbstractItemModel *model() { return m_proxyModel; } @@ -37,7 +39,7 @@ public: private: DebuggerEngine *m_engine; QStringList m_shortNames; - QStringList m_fullNames; + Utils::FilePaths m_fullNames; QAbstractItemModel *m_proxyModel; }; From 2509c3471b894d21c89e6ce5dfbfe429db207c41 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 15 Mar 2023 14:05:54 +0100 Subject: [PATCH 0286/1447] Copilot: Add missing include Change-Id: I313a394a0ff5bd352b7cb15ed2b7e6e02aefaa61 Reviewed-by: hjk --- src/plugins/copilot/copilotplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 171eb3c3395..67e07b170c5 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -16,6 +16,8 @@ #include +#include + using namespace Utils; using namespace Core; From 666f3258ba0e6ed0b8068da32cc748b98383eaf2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 10 Mar 2023 14:49:55 +0100 Subject: [PATCH 0287/1447] Docker: Fix shell exit handling Previously if a docker container was removed outside of Qt Creator the shell would not be correctly reset by the dockerdevice and therefor cause a hang. Change-Id: I5e84f7c114e525c732f45b701277736d6acc7a11 Reviewed-by: hjk Reviewed-by: --- src/libs/utils/deviceshell.cpp | 1 + src/plugins/docker/dockerdevice.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp index 283e9789c00..e8675745c08 100644 --- a/src/libs/utils/deviceshell.cpp +++ b/src/libs/utils/deviceshell.cpp @@ -98,6 +98,7 @@ RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData) const RunResult errorResult{-1, {}, {}}; QTC_ASSERT(m_shellProcess, return errorResult); + QTC_ASSERT(m_shellProcess->isRunning(), return errorResult); QTC_ASSERT(m_shellScriptState == State::Succeeded, return errorResult); QMutexLocker lk(&m_commandMutex); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 9ead5e8c783..e96ce9d6a47 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -679,12 +679,12 @@ void DockerDevicePrivate::startContainer() m_shell = std::make_unique(m_settings, m_container, q->rootPath()); connect(m_shell.get(), &DeviceShell::done, this, [this](const ProcessResultData &resultData) { + m_shell.release()->deleteLater(); if (resultData.m_error != QProcess::UnknownError || resultData.m_exitStatus == QProcess::NormalExit) return; qCWarning(dockerDeviceLog) << "Container shell encountered error:" << resultData.m_error; - m_shell.release()->deleteLater(); DockerApi::recheckDockerDaemon(); MessageManager::writeFlashing(Tr::tr("Docker daemon appears to be not running. " From a43c20969cad7733268f5bb5d47a0eb3aad885e7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 14 Mar 2023 12:10:59 +0100 Subject: [PATCH 0288/1447] QtcProcess: Remove TerminalMode::Pty enum value Make Pty::Data optional. When set, the PtyProcessImpl implementation is implied. Change-Id: I7990e9d9016223e6597d876a5d0c4ed177365874 Reviewed-by: Marcus Tillmanns --- src/libs/utils/processenums.h | 1 - src/libs/utils/processinterface.h | 2 +- src/libs/utils/qtcprocess.cpp | 21 +++++++++++---------- src/libs/utils/qtcprocess.h | 4 ++-- src/plugins/docker/dockerdevice.cpp | 2 +- src/plugins/remotelinux/linuxdevice.cpp | 8 ++++---- src/plugins/terminal/terminalwidget.cpp | 6 +++--- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libs/utils/processenums.h b/src/libs/utils/processenums.h index 1c16f22dcb4..6ea37a2d37a 100644 --- a/src/libs/utils/processenums.h +++ b/src/libs/utils/processenums.h @@ -24,7 +24,6 @@ enum class ProcessImpl { enum class TerminalMode { Off, - Pty, Run, Debug, Suspend, diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index 210df7d268a..5f3a4378d48 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -50,7 +50,7 @@ public: ProcessMode m_processMode = ProcessMode::Reader; TerminalMode m_terminalMode = TerminalMode::Off; - Pty::Data m_ptyData; + std::optional m_ptyData; CommandLine m_commandLine; FilePath m_workingDirectory; Environment m_environment; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 4808764ddde..a5de95d29db 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -310,7 +310,7 @@ private: class PtyProcessImpl final : public DefaultImpl { public: - ~PtyProcessImpl() { m_setup.m_ptyData.setResizeHandler({}); } + ~PtyProcessImpl() { QTC_CHECK(m_setup.m_ptyData); m_setup.m_ptyData->setResizeHandler({}); } qint64 write(const QByteArray &data) final { @@ -338,7 +338,8 @@ public: void doDefaultStart(const QString &program, const QStringList &arguments) final { - m_setup.m_ptyData.setResizeHandler([this](const QSize &size) { + QTC_CHECK(m_setup.m_ptyData); + m_setup.m_ptyData->setResizeHandler([this](const QSize &size) { if (m_ptyProcess) m_ptyProcess->resize(size.width(), size.height()); }); @@ -357,8 +358,8 @@ public: arguments, m_setup.m_workingDirectory.path(), m_setup.m_environment.toProcessEnvironment().toStringList(), - m_setup.m_ptyData.size().width(), - m_setup.m_ptyData.size().height()); + m_setup.m_ptyData->size().width(), + m_setup.m_ptyData->size().height()); if (!startResult) { const ProcessResultData result = {-1, @@ -725,16 +726,16 @@ public: ProcessInterface *createProcessInterface() { - if (m_setup.m_terminalMode == TerminalMode::Pty) - return new PtyProcessImpl(); + if (m_setup.m_ptyData) + return new PtyProcessImpl; if (m_setup.m_terminalMode != TerminalMode::Off) return Terminal::Hooks::instance().createTerminalProcessInterfaceHook()(); const ProcessImpl impl = m_setup.m_processImpl == ProcessImpl::Default ? defaultProcessImpl() : m_setup.m_processImpl; if (impl == ProcessImpl::QProcess) - return new QProcessImpl(); - return new ProcessLauncherImpl(); + return new QProcessImpl; + return new ProcessLauncherImpl; } void setProcessInterface(ProcessInterface *process) @@ -1123,12 +1124,12 @@ void QtcProcess::setProcessImpl(ProcessImpl processImpl) d->m_setup.m_processImpl = processImpl; } -void QtcProcess::setPtyData(const Pty::Data &data) +void QtcProcess::setPtyData(const std::optional &data) { d->m_setup.m_ptyData = data; } -Pty::Data QtcProcess::ptyData() const +std::optional QtcProcess::ptyData() const { return d->m_setup.m_ptyData; } diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 72181051491..9d539f08e20 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -77,8 +77,8 @@ public: void setProcessImpl(ProcessImpl processImpl); - void setPtyData(const Pty::Data &data); - Pty::Data ptyData() const; + void setPtyData(const std::optional &data); + std::optional ptyData() const; void setTerminalMode(TerminalMode mode); TerminalMode terminalMode() const; diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index e96ce9d6a47..020aeec31f4 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -304,7 +304,7 @@ void DockerProcessImpl::start() m_setup.m_workingDirectory, interactive, true, - m_setup.m_terminalMode == TerminalMode::Pty); + m_setup.m_ptyData.has_value()); m_process.setCommand(fullCommandLine); m_process.start(); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 345f6e28497..57eaf8ccd14 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -535,7 +535,7 @@ QString LinuxProcessInterface::fullCommandLine(const CommandLine &commandLine) c cmd.addArgs("&&", CommandLine::Raw); } - if (m_setup.m_terminalMode == TerminalMode::Off) + if (m_setup.m_terminalMode == TerminalMode::Off && !m_setup.m_ptyData) cmd.addArgs(QString("echo ") + s_pidMarker + "$$" + s_pidMarker + " && ", CommandLine::Raw); const Environment &env = m_setup.m_environment; @@ -543,7 +543,7 @@ QString LinuxProcessInterface::fullCommandLine(const CommandLine &commandLine) c cmd.addArgs(key + "='" + env.expandVariables(value) + '\'', CommandLine::Raw); }); - if (m_setup.m_terminalMode == TerminalMode::Off) + if (m_setup.m_terminalMode == TerminalMode::Off && !m_setup.m_ptyData) cmd.addArg("exec"); if (!commandLine.isEmpty()) @@ -555,7 +555,7 @@ void LinuxProcessInterface::handleStarted(qint64 processId) { // Don't emit started() when terminal is off, // it's being done later inside handleReadyReadStandardOutput(). - if (m_setup.m_terminalMode == TerminalMode::Off) + if (m_setup.m_terminalMode == TerminalMode::Off && !m_setup.m_ptyData) return; m_pidParsed = true; @@ -740,7 +740,7 @@ CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const if (!m_sshParameters.x11DisplayName.isEmpty()) cmd.addArg("-X"); - if (q->m_setup.m_terminalMode != TerminalMode::Off) + if (q->m_setup.m_terminalMode != TerminalMode::Off || q->m_setup.m_ptyData) cmd.addArg("-tt"); cmd.addArg("-q"); diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 0321c0ce5ca..23da5088ce9 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -126,7 +126,7 @@ void TerminalWidget::setupPty() env.unset("CLINK_NOAUTORUN"); m_process->setProcessMode(ProcessMode::Writer); - m_process->setTerminalMode(TerminalMode::Pty); + m_process->setPtyData(Utils::Pty::Data()); m_process->setCommand(shellCommand); if (m_openParameters.workingDirectory.has_value()) m_process->setWorkingDirectory(*m_openParameters.workingDirectory); @@ -912,8 +912,8 @@ void TerminalWidget::applySizeChange() if (newLiveSize.width() <= 0) newLiveSize.setWidth(1); - if (m_process) - m_process->ptyData().resize(newLiveSize); + if (m_process && m_process->ptyData()) + m_process->ptyData()->resize(newLiveSize); m_surface->resize(newLiveSize); flushVTerm(true); From 958db5a1440284a4332ced14e2a29ab92bedfba3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 15 Mar 2023 15:12:56 +0100 Subject: [PATCH 0289/1447] TerminalProcess: Fix merge conflict Amends a43c20969cad7733268f5bb5d47a0eb3aad885e7 Change-Id: Ib94845dfb3a7a17a86d5a07ad6501a3c3cb905b2 Reviewed-by: Marcus Tillmanns --- src/libs/utils/terminalprocess.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/utils/terminalprocess.cpp b/src/libs/utils/terminalprocess.cpp index 91423539a33..0070a4db2c2 100644 --- a/src/libs/utils/terminalprocess.cpp +++ b/src/libs/utils/terminalprocess.cpp @@ -44,8 +44,6 @@ namespace Internal { static QString modeOption(TerminalMode m) { switch (m) { - case TerminalMode::Pty: - return "pty"; case TerminalMode::Run: return "run"; case TerminalMode::Debug: From 3507229a007e3fd5f004a94f4c3857518ab1c9df Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Mar 2023 15:32:40 +0100 Subject: [PATCH 0290/1447] RemoteLinux: Use SshParameter::userAtHost() ... instead of rolling its own. Change-Id: I99cf1714e871b3af2c825d3b3f131982383a10b7 Reviewed-by: Jarek Kobus --- src/plugins/remotelinux/linuxdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 57eaf8ccd14..55a0238d938 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1202,7 +1202,7 @@ protected: } QString host() const { return m_sshParameters.host(); } - QString userAtHost() const { return m_sshParameters.userName() + '@' + m_sshParameters.host(); } + QString userAtHost() const { return m_sshParameters.userAtHost(); } QtcProcess &process() { return m_process; } FileTransferDirection direction() const { return m_direction; } From bd52e53dbfa7641098313edd56d885df69916f9f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 10 Mar 2023 13:55:17 +0100 Subject: [PATCH 0291/1447] Terminal: Add shell integration Change-Id: Ic1e226b56f0103e5a6e7764073ab7ab241b67baa Reviewed-by: Cristian Adam --- README.md | 30 ++- .../overview/creator-acknowledgements.qdoc | 13 + src/libs/utils/fileutils.cpp | 1 - src/libs/utils/fileutils.h | 1 - src/libs/utils/qtcprocess.cpp | 4 +- src/plugins/terminal/CMakeLists.txt | 1 + src/plugins/terminal/shellintegration.cpp | 143 ++++++++++ src/plugins/terminal/shellintegration.h | 34 +++ .../shellintegration-bash.sh | 252 ++++++++++++++++++ .../shellintegration-env.zsh | 15 ++ .../shellintegration-login.zsh | 7 + .../shellintegration-profile.zsh | 15 ++ .../shellintegrations/shellintegration-rc.zsh | 160 +++++++++++ .../shellintegrations/shellintegration.fish | 122 +++++++++ .../shellintegrations/shellintegration.ps1 | 158 +++++++++++ src/plugins/terminal/terminal.qrc | 15 +- src/plugins/terminal/terminalpane.cpp | 18 +- src/plugins/terminal/terminalsurface.cpp | 34 ++- src/plugins/terminal/terminalsurface.h | 5 +- src/plugins/terminal/terminalwidget.cpp | 37 ++- src/plugins/terminal/terminalwidget.h | 9 + src/plugins/terminal/tests/integration | 70 +++++ 22 files changed, 1129 insertions(+), 15 deletions(-) create mode 100644 src/plugins/terminal/shellintegration.cpp create mode 100644 src/plugins/terminal/shellintegration.h create mode 100755 src/plugins/terminal/shellintegrations/shellintegration-bash.sh create mode 100644 src/plugins/terminal/shellintegrations/shellintegration-env.zsh create mode 100644 src/plugins/terminal/shellintegrations/shellintegration-login.zsh create mode 100644 src/plugins/terminal/shellintegrations/shellintegration-profile.zsh create mode 100644 src/plugins/terminal/shellintegrations/shellintegration-rc.zsh create mode 100644 src/plugins/terminal/shellintegrations/shellintegration.fish create mode 100644 src/plugins/terminal/shellintegrations/shellintegration.ps1 create mode 100755 src/plugins/terminal/tests/integration diff --git a/README.md b/README.md index c58acc13f83..1866b96052f 100644 --- a/README.md +++ b/README.md @@ -783,7 +783,6 @@ SQLite (https://www.sqlite.org) is in the Public Domain. ### libvterm - An abstract C99 library which implements a VT220 or xterm-like terminal emulator. It doesn't use any particular graphics toolkit or output system, instead it invokes callback function pointers that its embedding program should provide it to draw on its behalf. @@ -813,3 +812,32 @@ SQLite (https://www.sqlite.org) is in the Public Domain. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +### terminal/shellintegrations + + The Terminal plugin uses scripts to integrate with the shell. The scripts are + located in the Qt Creator source tree in src/plugins/terminal/shellintegrations. + + https://github.com/microsoft/vscode/tree/main/src/vs/workbench/contrib/terminal/browser/media + + MIT License + + Copyright (c) 2015 - present Microsoft Corporation + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc index 29b006985d1..820e97247d5 100644 --- a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc +++ b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc @@ -1046,5 +1046,18 @@ \include license-mit.qdocinc + \li \b terminal/shellintegrations + + The Terminal plugin uses scripts to integrate with the shell. The scripts are + located in the Qt Creator source tree in src/plugins/terminal/shellintegrations. + + \list + \li \l https://github.com/microsoft/vscode/tree/main/src/vs/workbench/contrib/terminal/browser/media + \endlist + + Distributed under the MIT license. + + \include license-mit.qdocinc + \endlist */ diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index c0a574f9c34..4bd0692e133 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -5,7 +5,6 @@ #include "savefile.h" #include "algorithm.h" -#include "hostosinfo.h" #include "qtcassert.h" #include "utilstr.h" diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 19f17a6d719..a1a7ffef977 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -121,7 +121,6 @@ public: QString *selectedFilter = nullptr, QFileDialog::Options options = {}); #endif - }; // for actually finding out if e.g. directories are writable on Windows diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index a5de95d29db..21b1684242b 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -355,7 +355,9 @@ public: bool startResult = m_ptyProcess->startProcess(program, - arguments, + HostOsInfo::isWindowsHost() + ? QStringList{m_setup.m_nativeArguments} << arguments + : arguments, m_setup.m_workingDirectory.path(), m_setup.m_environment.toProcessEnvironment().toStringList(), m_setup.m_ptyData->size().width(), diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index c0972eccf36..f68a0b2ce42 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -7,6 +7,7 @@ add_qtc_plugin(Terminal glyphcache.cpp glyphcache.h keys.cpp keys.h scrollback.cpp scrollback.h + shellintegration.cpp shellintegration.h shellmodel.cpp shellmodel.h terminal.qrc terminalpane.cpp terminalpane.h diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp new file mode 100644 index 00000000000..fd4c1364696 --- /dev/null +++ b/src/plugins/terminal/shellintegration.cpp @@ -0,0 +1,143 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "shellintegration.h" + +#include +#include +#include + +#include + +Q_LOGGING_CATEGORY(integrationLog, "qtc.terminal.shellintegration", QtWarningMsg) + +using namespace Utils; + +namespace Terminal { + +struct FileToCopy +{ + FilePath source; + QString destName; +}; + +// clang-format off +struct +{ + struct + { + FilePath rcFile{":/terminal/shellintegrations/shellintegration-bash.sh"}; + } bash; + struct + { + QList files{ + {":/terminal/shellintegrations/shellintegration-env.zsh", ".zshenv"}, + {":/terminal/shellintegrations/shellintegration-login.zsh", ".zlogin"}, + {":/terminal/shellintegrations/shellintegration-profile.zsh", ".zprofile"}, + {":/terminal/shellintegrations/shellintegration-rc.zsh", ".zshrc"} + }; + } zsh; + struct + { + FilePath script{":/terminal/shellintegrations/shellintegration.ps1"}; + } pwsh; + +} filesToCopy; +// clang-format on + +bool ShellIntegration::canIntegrate(const Utils::CommandLine &cmdLine) +{ + if (cmdLine.executable().needsDevice()) + return false; // TODO: Allow integration for remote shells + + if (!cmdLine.arguments().isEmpty()) + return false; + + if (cmdLine.executable().baseName() == "bash") + return true; + + if (cmdLine.executable().baseName() == "zsh") + return true; + + if (cmdLine.executable().baseName() == "pwsh" + || cmdLine.executable().baseName() == "powershell") { + return true; + } + + return false; +} + +void ShellIntegration::onOsc(int cmd, const VTermStringFragment &fragment) +{ + QString d = QString::fromLocal8Bit(fragment.str, fragment.len); + const auto [command, data] = Utils::splitAtFirst(d, ';'); + + if (cmd == 1337) { + const auto [key, value] = Utils::splitAtFirst(command, '='); + if (key == QStringView(u"CurrentDir")) + emit currentDirChanged(FilePath::fromUserInput(value.toString()).path()); + + } else if (cmd == 7) { + emit currentDirChanged(FilePath::fromUserInput(d).path()); + } else if (cmd == 133) { + qCDebug(integrationLog) << "OSC 133:" << data; + } else if (cmd == 633 && command.length() == 1) { + if (command[0] == 'E') { + CommandLine cmdLine = CommandLine::fromUserInput(data.toString()); + emit commandChanged(cmdLine); + } else if (command[0] == 'D') { + emit commandChanged({}); + } else if (command[0] == 'P') { + const auto [key, value] = Utils::splitAtFirst(data, '='); + if (key == QStringView(u"Cwd")) + emit currentDirChanged(value.toString()); + } + } +} + +void ShellIntegration::prepareProcess(Utils::QtcProcess &process) +{ + Environment env = process.environment().hasChanges() ? process.environment() + : Environment::systemEnvironment(); + CommandLine cmd = process.commandLine(); + + if (!canIntegrate(cmd)) + return; + + env.set("VSCODE_INJECTION", "1"); + + if (cmd.executable().baseName() == "bash") { + const FilePath rcPath = filesToCopy.bash.rcFile; + const FilePath tmpRc = FilePath::fromUserInput( + m_tempDir.filePath(filesToCopy.bash.rcFile.fileName())); + rcPath.copyFile(tmpRc); + + cmd.addArgs({"--init-file", tmpRc.nativePath()}); + } else if (cmd.executable().baseName() == "zsh") { + for (const FileToCopy &file : filesToCopy.zsh.files) { + const auto copyResult = file.source.copyFile( + FilePath::fromUserInput(m_tempDir.filePath(file.destName))); + QTC_ASSERT_EXPECTED(copyResult, return); + } + + const Utils::FilePath originalZdotDir = FilePath::fromUserInput( + env.value_or("ZDOTDIR", QDir::homePath())); + + env.set("ZDOTDIR", m_tempDir.path()); + env.set("USER_ZDOTDIR", originalZdotDir.nativePath()); + } else if (cmd.executable().baseName() == "pwsh" + || cmd.executable().baseName() == "powershell") { + const FilePath rcPath = filesToCopy.pwsh.script; + const FilePath tmpRc = FilePath::fromUserInput( + m_tempDir.filePath(filesToCopy.pwsh.script.fileName())); + rcPath.copyFile(tmpRc); + + cmd.addArgs(QString("-noexit -command try { . \"%1\" } catch {}{1}").arg(tmpRc.nativePath()), + CommandLine::Raw); + } + + process.setCommand(cmd); + process.setEnvironment(env); +} + +} // namespace Terminal diff --git a/src/plugins/terminal/shellintegration.h b/src/plugins/terminal/shellintegration.h new file mode 100644 index 00000000000..264b5a4d67a --- /dev/null +++ b/src/plugins/terminal/shellintegration.h @@ -0,0 +1,34 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH +// Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +#include + +#include + +namespace Terminal { + +class ShellIntegration : public QObject +{ + Q_OBJECT +public: + static bool canIntegrate(const Utils::CommandLine &cmdLine); + + void onOsc(int cmd, const VTermStringFragment &fragment); + + void prepareProcess(Utils::QtcProcess &process); + +signals: + void commandChanged(const Utils::CommandLine &command); + void currentDirChanged(const QString &dir); + +private: + QTemporaryDir m_tempDir; +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/shellintegrations/shellintegration-bash.sh b/src/plugins/terminal/shellintegrations/shellintegration-bash.sh new file mode 100755 index 00000000000..7db188be08e --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration-bash.sh @@ -0,0 +1,252 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + + +# Prevent the script recursing when setting up +if [[ -n "$VSCODE_SHELL_INTEGRATION" ]]; then + builtin return +fi + +VSCODE_SHELL_INTEGRATION=1 + +# Run relevant rc/profile only if shell integration has been injected, not when run manually +if [ "$VSCODE_INJECTION" == "1" ]; then + if [ -z "$VSCODE_SHELL_LOGIN" ]; then + if [ -r ~/.bashrc ]; then + . ~/.bashrc + fi + else + # Imitate -l because --init-file doesn't support it: + # run the first of these files that exists + if [ -r /etc/profile ]; then + . /etc/profile + fi + # exceute the first that exists + if [ -r ~/.bash_profile ]; then + . ~/.bash_profile + elif [ -r ~/.bash_login ]; then + . ~/.bash_login + elif [ -r ~/.profile ]; then + . ~/.profile + fi + builtin unset VSCODE_SHELL_LOGIN + + # Apply any explicit path prefix (see #99878) + if [ -n "$VSCODE_PATH_PREFIX" ]; then + export PATH=$VSCODE_PATH_PREFIX$PATH + builtin unset VSCODE_PATH_PREFIX + fi + fi + builtin unset VSCODE_INJECTION +fi + +if [ -z "$VSCODE_SHELL_INTEGRATION" ]; then + builtin return +fi + +__vsc_get_trap() { + # 'trap -p DEBUG' outputs a shell command like `trap -- '…shellcode…' DEBUG`. + # The terms are quoted literals, but are not guaranteed to be on a single line. + # (Consider a trap like $'echo foo\necho \'bar\''). + # To parse, we splice those terms into an expression capturing them into an array. + # This preserves the quoting of those terms: when we `eval` that expression, they are preserved exactly. + # This is different than simply exploding the string, which would split everything on IFS, oblivious to quoting. + builtin local -a terms + builtin eval "terms=( $(trap -p "${1:-DEBUG}") )" + # |________________________| + # | + # \-------------------*--------------------/ + # terms=( trap -- '…arbitrary shellcode…' DEBUG ) + # |____||__| |_____________________| |_____| + # | | | | + # 0 1 2 3 + # | + # \--------*----/ + builtin printf '%s' "${terms[2]:-}" +} + +# The property (P) and command (E) codes embed values which require escaping. +# Backslashes are doubled. Non-alphanumeric characters are converted to escaped hex. +__vsc_escape_value() { + # Process text byte by byte, not by codepoint. + builtin local LC_ALL=C str="${1}" i byte token out='' + + for (( i=0; i < "${#str}"; ++i )); do + byte="${str:$i:1}" + + # Escape backslashes and semi-colons + if [ "$byte" = "\\" ]; then + token="\\\\" + elif [ "$byte" = ";" ]; then + token="\\x3b" + else + token="$byte" + fi + + out+="$token" + done + + builtin printf '%s\n' "${out}" +} + +# Send the IsWindows property if the environment looks like Windows +if [[ "$(uname -s)" =~ ^CYGWIN*|MINGW*|MSYS* ]]; then + builtin printf '\e]633;P;IsWindows=True\a' +fi + +# Allow verifying $BASH_COMMAND doesn't have aliases resolved via history when the right HISTCONTROL +# configuration is used +if [[ "$HISTCONTROL" =~ .*(erasedups|ignoreboth|ignoredups).* ]]; then + __vsc_history_verify=0 +else + __vsc_history_verify=1 +fi + +__vsc_initialized=0 +__vsc_original_PS1="$PS1" +__vsc_original_PS2="$PS2" +__vsc_custom_PS1="" +__vsc_custom_PS2="" +__vsc_in_command_execution="1" +__vsc_current_command="" + +__vsc_prompt_start() { + builtin printf '\e]633;A\a' +} + +__vsc_prompt_end() { + builtin printf '\e]633;B\a' +} + +__vsc_update_cwd() { + builtin printf '\e]633;P;Cwd=%s\a' "$(__vsc_escape_value "$PWD")" +} + +__vsc_command_output_start() { + builtin printf '\e]633;C\a' + builtin printf '\e]633;E;%s\a' "$(__vsc_escape_value "${__vsc_current_command}")" +} + +__vsc_continuation_start() { + builtin printf '\e]633;F\a' +} + +__vsc_continuation_end() { + builtin printf '\e]633;G\a' +} + +__vsc_command_complete() { + if [ "$__vsc_current_command" = "" ]; then + builtin printf '\e]633;D\a' + else + builtin printf '\e]633;D;%s\a' "$__vsc_status" + fi + __vsc_update_cwd +} +__vsc_update_prompt() { + # in command execution + if [ "$__vsc_in_command_execution" = "1" ]; then + # Wrap the prompt if it is not yet wrapped, if the PS1 changed this this was last set it + # means the user re-exported the PS1 so we should re-wrap it + if [[ "$__vsc_custom_PS1" == "" || "$__vsc_custom_PS1" != "$PS1" ]]; then + __vsc_original_PS1=$PS1 + __vsc_custom_PS1="\[$(__vsc_prompt_start)\]$__vsc_original_PS1\[$(__vsc_prompt_end)\]" + PS1="$__vsc_custom_PS1" + fi + if [[ "$__vsc_custom_PS2" == "" || "$__vsc_custom_PS2" != "$PS2" ]]; then + __vsc_original_PS2=$PS2 + __vsc_custom_PS2="\[$(__vsc_continuation_start)\]$__vsc_original_PS2\[$(__vsc_continuation_end)\]" + PS2="$__vsc_custom_PS2" + fi + __vsc_in_command_execution="0" + fi +} + +__vsc_precmd() { + __vsc_command_complete "$__vsc_status" + __vsc_current_command="" + __vsc_update_prompt +} + +__vsc_preexec() { + __vsc_initialized=1 + if [[ ! "$BASH_COMMAND" =~ ^__vsc_prompt* ]]; then + # Use history if it's available to verify the command as BASH_COMMAND comes in with aliases + # resolved + if [ "$__vsc_history_verify" = "1" ]; then + __vsc_current_command="$(builtin history 1 | sed 's/ *[0-9]* *//')" + else + __vsc_current_command=$BASH_COMMAND + fi + else + __vsc_current_command="" + fi + __vsc_command_output_start +} + +# Debug trapping/preexec inspired by starship (ISC) +if [[ -n "${bash_preexec_imported:-}" ]]; then + __vsc_preexec_only() { + if [ "$__vsc_in_command_execution" = "0" ]; then + __vsc_in_command_execution="1" + __vsc_preexec + fi + } + precmd_functions+=(__vsc_prompt_cmd) + preexec_functions+=(__vsc_preexec_only) +else + __vsc_dbg_trap="$(__vsc_get_trap DEBUG)" + + if [[ -z "$__vsc_dbg_trap" ]]; then + __vsc_preexec_only() { + if [ "$__vsc_in_command_execution" = "0" ]; then + __vsc_in_command_execution="1" + __vsc_preexec + fi + } + trap '__vsc_preexec_only "$_"' DEBUG + elif [[ "$__vsc_dbg_trap" != '__vsc_preexec "$_"' && "$__vsc_dbg_trap" != '__vsc_preexec_all "$_"' ]]; then + __vsc_preexec_all() { + if [ "$__vsc_in_command_execution" = "0" ]; then + __vsc_in_command_execution="1" + builtin eval "${__vsc_dbg_trap}" + __vsc_preexec + fi + } + trap '__vsc_preexec_all "$_"' DEBUG + fi +fi + +__vsc_update_prompt + +__vsc_restore_exit_code() { + return "$1" +} + +__vsc_prompt_cmd_original() { + __vsc_status="$?" + __vsc_restore_exit_code "${__vsc_status}" + # Evaluate the original PROMPT_COMMAND similarly to how bash would normally + # See https://unix.stackexchange.com/a/672843 for technique + for cmd in "${__vsc_original_prompt_command[@]}"; do + eval "${cmd:-}" + done + __vsc_precmd +} + +__vsc_prompt_cmd() { + __vsc_status="$?" + __vsc_precmd +} + +# PROMPT_COMMAND arrays and strings seem to be handled the same (handling only the first entry of +# the array?) +__vsc_original_prompt_command=$PROMPT_COMMAND + +if [[ -z "${bash_preexec_imported:-}" ]]; then + if [[ -n "$__vsc_original_prompt_command" && "$__vsc_original_prompt_command" != "__vsc_prompt_cmd" ]]; then + PROMPT_COMMAND=__vsc_prompt_cmd_original + else + PROMPT_COMMAND=__vsc_prompt_cmd + fi +fi diff --git a/src/plugins/terminal/shellintegrations/shellintegration-env.zsh b/src/plugins/terminal/shellintegrations/shellintegration-env.zsh new file mode 100644 index 00000000000..3c890539aeb --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration-env.zsh @@ -0,0 +1,15 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +if [[ -f $USER_ZDOTDIR/.zshenv ]]; then + VSCODE_ZDOTDIR=$ZDOTDIR + ZDOTDIR=$USER_ZDOTDIR + + # prevent recursion + if [[ $USER_ZDOTDIR != $VSCODE_ZDOTDIR ]]; then + . $USER_ZDOTDIR/.zshenv + fi + + USER_ZDOTDIR=$ZDOTDIR + ZDOTDIR=$VSCODE_ZDOTDIR +fi diff --git a/src/plugins/terminal/shellintegrations/shellintegration-login.zsh b/src/plugins/terminal/shellintegrations/shellintegration-login.zsh new file mode 100644 index 00000000000..37ff5439790 --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration-login.zsh @@ -0,0 +1,7 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +ZDOTDIR=$USER_ZDOTDIR +if [[ $options[norcs] = off && -o "login" && -f $ZDOTDIR/.zlogin ]]; then + . $ZDOTDIR/.zlogin +fi diff --git a/src/plugins/terminal/shellintegrations/shellintegration-profile.zsh b/src/plugins/terminal/shellintegrations/shellintegration-profile.zsh new file mode 100644 index 00000000000..724e1f28790 --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration-profile.zsh @@ -0,0 +1,15 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +if [[ $options[norcs] = off && -o "login" && -f $USER_ZDOTDIR/.zprofile ]]; then + VSCODE_ZDOTDIR=$ZDOTDIR + ZDOTDIR=$USER_ZDOTDIR + . $USER_ZDOTDIR/.zprofile + ZDOTDIR=$VSCODE_ZDOTDIR + + # Apply any explicit path prefix (see #99878) + if (( ${+VSCODE_PATH_PREFIX} )); then + export PATH=$VSCODE_PATH_PREFIX$PATH + fi + builtin unset VSCODE_PATH_PREFIX +fi diff --git a/src/plugins/terminal/shellintegrations/shellintegration-rc.zsh b/src/plugins/terminal/shellintegrations/shellintegration-rc.zsh new file mode 100644 index 00000000000..df4109131a9 --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration-rc.zsh @@ -0,0 +1,160 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +builtin autoload -Uz add-zsh-hook + +# Prevent the script recursing when setting up +if [ -n "$VSCODE_SHELL_INTEGRATION" ]; then + ZDOTDIR=$USER_ZDOTDIR + builtin return +fi + +# This variable allows the shell to both detect that VS Code's shell integration is enabled as well +# as disable it by unsetting the variable. +VSCODE_SHELL_INTEGRATION=1 + +# By default, zsh will set the $HISTFILE to the $ZDOTDIR location automatically. In the case of the +# shell integration being injected, this means that the terminal will use a different history file +# to other terminals. To fix this issue, set $HISTFILE back to the default location before ~/.zshrc +# is called as that may depend upon the value. +if [[ "$VSCODE_INJECTION" == "1" ]]; then + HISTFILE=$USER_ZDOTDIR/.zsh_history +fi + +# Only fix up ZDOTDIR if shell integration was injected (not manually installed) and has not been called yet +if [[ "$VSCODE_INJECTION" == "1" ]]; then + if [[ $options[norcs] = off && -f $USER_ZDOTDIR/.zshrc ]]; then + VSCODE_ZDOTDIR=$ZDOTDIR + ZDOTDIR=$USER_ZDOTDIR + # A user's custom HISTFILE location might be set when their .zshrc file is sourced below + . $USER_ZDOTDIR/.zshrc + fi +fi + +# Shell integration was disabled by the shell, exit without warning assuming either the shell has +# explicitly disabled shell integration as it's incompatible or it implements the protocol. +if [ -z "$VSCODE_SHELL_INTEGRATION" ]; then + builtin return +fi + +# The property (P) and command (E) codes embed values which require escaping. +# Backslashes are doubled. Non-alphanumeric characters are converted to escaped hex. +__vsc_escape_value() { + builtin emulate -L zsh + + # Process text byte by byte, not by codepoint. + builtin local LC_ALL=C str="$1" i byte token out='' + + for (( i = 0; i < ${#str}; ++i )); do + byte="${str:$i:1}" + + # Escape backslashes and semi-colons + if [ "$byte" = "\\" ]; then + token="\\\\" + elif [ "$byte" = ";" ]; then + token="\\x3b" + else + token="$byte" + fi + + out+="$token" + done + + builtin print -r "$out" +} + +__vsc_in_command_execution="1" +__vsc_current_command="" + +__vsc_prompt_start() { + builtin printf '\e]633;A\a' +} + +__vsc_prompt_end() { + builtin printf '\e]633;B\a' +} + +__vsc_update_cwd() { + builtin printf '\e]633;P;Cwd=%s\a' "$(__vsc_escape_value "${PWD}")" +} + +__vsc_command_output_start() { + builtin printf '\e]633;C\a' + builtin printf '\e]633;E;%s\a' "${__vsc_current_command}" +} + +__vsc_continuation_start() { + builtin printf '\e]633;F\a' +} + +__vsc_continuation_end() { + builtin printf '\e]633;G\a' +} + +__vsc_right_prompt_start() { + builtin printf '\e]633;H\a' +} + +__vsc_right_prompt_end() { + builtin printf '\e]633;I\a' +} + +__vsc_command_complete() { + if [[ "$__vsc_current_command" == "" ]]; then + builtin printf '\e]633;D\a' + else + builtin printf '\e]633;D;%s\a' "$__vsc_status" + fi + __vsc_update_cwd +} + +if [[ -o NOUNSET ]]; then + if [ -z "${RPROMPT-}" ]; then + RPROMPT="" + fi +fi +__vsc_update_prompt() { + __vsc_prior_prompt="$PS1" + __vsc_prior_prompt2="$PS2" + __vsc_in_command_execution="" + PS1="%{$(__vsc_prompt_start)%}$PS1%{$(__vsc_prompt_end)%}" + PS2="%{$(__vsc_continuation_start)%}$PS2%{$(__vsc_continuation_end)%}" + if [ -n "$RPROMPT" ]; then + __vsc_prior_rprompt="$RPROMPT" + RPROMPT="%{$(__vsc_right_prompt_start)%}$RPROMPT%{$(__vsc_right_prompt_end)%}" + fi +} + +__vsc_precmd() { + local __vsc_status="$?" + if [ -z "${__vsc_in_command_execution-}" ]; then + # not in command execution + __vsc_command_output_start + fi + + __vsc_command_complete "$__vsc_status" + __vsc_current_command="" + + # in command execution + if [ -n "$__vsc_in_command_execution" ]; then + # non null + __vsc_update_prompt + fi +} + +__vsc_preexec() { + PS1="$__vsc_prior_prompt" + PS2="$__vsc_prior_prompt2" + if [ -n "$RPROMPT" ]; then + RPROMPT="$__vsc_prior_rprompt" + fi + __vsc_in_command_execution="1" + __vsc_current_command=$2 + __vsc_command_output_start +} +add-zsh-hook precmd __vsc_precmd +add-zsh-hook preexec __vsc_preexec + +if [[ $options[login] = off && $USER_ZDOTDIR != $VSCODE_ZDOTDIR ]]; then + ZDOTDIR=$USER_ZDOTDIR +fi diff --git a/src/plugins/terminal/shellintegrations/shellintegration.fish b/src/plugins/terminal/shellintegrations/shellintegration.fish new file mode 100644 index 00000000000..7495bab3f40 --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration.fish @@ -0,0 +1,122 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT +# +# Visual Studio Code terminal integration for fish +# +# Manual installation: +# +# (1) Add the following to the end of `$__fish_config_dir/config.fish`: +# +# string match -q "$TERM_PROGRAM" "vscode" +# and . (code --locate-shell-integration-path fish) +# +# (2) Restart fish. + +# Don't run in scripts, other terminals, or more than once per session. +status is-interactive +and string match --quiet "$TERM_PROGRAM" "vscode" +and ! set --query VSCODE_SHELL_INTEGRATION +or exit + +set --global VSCODE_SHELL_INTEGRATION 1 + +# Apply any explicit path prefix (see #99878) +if status --is-login; and set -q VSCODE_PATH_PREFIX + fish_add_path -p $VSCODE_PATH_PREFIX +end +set -e VSCODE_PATH_PREFIX + +# Helper function +function __vsc_esc -d "Emit escape sequences for VS Code shell integration" + builtin printf "\e]633;%s\a" (string join ";" $argv) +end + +# Sent right before executing an interactive command. +# Marks the beginning of command output. +function __vsc_cmd_executed --on-event fish_preexec + __vsc_esc C + __vsc_esc E (__vsc_escape_value "$argv") + + # Creates a marker to indicate a command was run. + set --global _vsc_has_cmd +end + + +# Escape a value for use in the 'P' ("Property") or 'E' ("Command Line") sequences. +# Backslashes are doubled and non-alphanumeric characters are hex encoded. +function __vsc_escape_value + # Escape backslashes and semi-colons + echo $argv \ + | string replace --all '\\' '\\\\' \ + | string replace --all ';' '\\x3b' \ + ; +end + +# Sent right after an interactive command has finished executing. +# Marks the end of command output. +function __vsc_cmd_finished --on-event fish_postexec + __vsc_esc D $status +end + +# Sent when a command line is cleared or reset, but no command was run. +# Marks the cleared line with neither success nor failure. +function __vsc_cmd_clear --on-event fish_cancel + __vsc_esc D +end + +# Sent whenever a new fish prompt is about to be displayed. +# Updates the current working directory. +function __vsc_update_cwd --on-event fish_prompt + __vsc_esc P Cwd=(__vsc_escape_value "$PWD") + + # If a command marker exists, remove it. + # Otherwise, the commandline is empty and no command was run. + if set --query _vsc_has_cmd + set --erase _vsc_has_cmd + else + __vsc_cmd_clear + end +end + +# Sent at the start of the prompt. +# Marks the beginning of the prompt (and, implicitly, a new line). +function __vsc_fish_prompt_start + __vsc_esc A +end + +# Sent at the end of the prompt. +# Marks the beginning of the user's command input. +function __vsc_fish_cmd_start + __vsc_esc B +end + +function __vsc_fish_has_mode_prompt -d "Returns true if fish_mode_prompt is defined and not empty" + functions fish_mode_prompt | string match -rvq '^ *(#|function |end$|$)' +end + +# Preserve the user's existing prompt, to wrap in our escape sequences. +functions --copy fish_prompt __vsc_fish_prompt + +# Preserve and wrap fish_mode_prompt (which appears to the left of the regular +# prompt), but only if it's not defined as an empty function (which is the +# officially documented way to disable that feature). +if __vsc_fish_has_mode_prompt + functions --copy fish_mode_prompt __vsc_fish_mode_prompt + + function fish_mode_prompt + __vsc_fish_prompt_start + __vsc_fish_mode_prompt + end + + function fish_prompt + __vsc_fish_prompt + __vsc_fish_cmd_start + end +else + # No fish_mode_prompt, so put everything in fish_prompt. + function fish_prompt + __vsc_fish_prompt_start + __vsc_fish_prompt + __vsc_fish_cmd_start + end +end diff --git a/src/plugins/terminal/shellintegrations/shellintegration.ps1 b/src/plugins/terminal/shellintegrations/shellintegration.ps1 new file mode 100644 index 00000000000..4fd978a8844 --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration.ps1 @@ -0,0 +1,158 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +# Prevent installing more than once per session +if (Test-Path variable:global:__VSCodeOriginalPrompt) { + return; +} + +# Disable shell integration when the language mode is restricted +if ($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") { + return; +} + +$Global:__VSCodeOriginalPrompt = $function:Prompt + +$Global:__LastHistoryId = -1 + +function Global:__VSCode-Escape-Value([string]$value) { + # NOTE: In PowerShell v6.1+, this can be written `$value -replace '…', { … }` instead of `[regex]::Replace`. + # Replace any non-alphanumeric characters. + [regex]::Replace($value, '[\\\n;]', { param($match) + # Encode the (ascii) matches as `\x` + -Join ( + [System.Text.Encoding]::UTF8.GetBytes($match.Value) | ForEach-Object { '\x{0:x2}' -f $_ } + ) + }) +} + +function Global:Prompt() { + $FakeCode = [int]!$global:? + # NOTE: We disable strict mode for the scope of this function because it unhelpfully throws an + # error when $LastHistoryEntry is null, and is not otherwise useful. + Set-StrictMode -Off + $LastHistoryEntry = Get-History -Count 1 + # Skip finishing the command if the first command has not yet started + if ($Global:__LastHistoryId -ne -1) { + if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) { + # Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command) + $Result = "$([char]0x1b)]633;E`a" + $Result += "$([char]0x1b)]633;D`a" + } else { + # Command finished command line + # OSC 633 ; A ; ST + $Result = "$([char]0x1b)]633;E;" + # Sanitize the command line to ensure it can get transferred to the terminal and can be parsed + # correctly. This isn't entirely safe but good for most cases, it's important for the Pt parameter + # to only be composed of _printable_ characters as per the spec. + if ($LastHistoryEntry.CommandLine) { + $CommandLine = $LastHistoryEntry.CommandLine + } else { + $CommandLine = "" + } + $Result += $(__VSCode-Escape-Value $CommandLine) + $Result += "`a" + # Command finished exit code + # OSC 633 ; D [; ] ST + $Result += "$([char]0x1b)]633;D;$FakeCode`a" + } + } + # Prompt started + # OSC 633 ; A ST + $Result += "$([char]0x1b)]633;A`a" + # Current working directory + # OSC 633 ; = ST + $Result += if($pwd.Provider.Name -eq 'FileSystem'){"$([char]0x1b)]633;P;Cwd=$(__VSCode-Escape-Value $pwd.ProviderPath)`a"} + # Before running the original prompt, put $? back to what it was: + if ($FakeCode -ne 0) { + Write-Error "failure" -ea ignore + } + # Run the original prompt + $Result += $Global:__VSCodeOriginalPrompt.Invoke() + # Write command started + $Result += "$([char]0x1b)]633;B`a" + $Global:__LastHistoryId = $LastHistoryEntry.Id + return $Result +} + +# Only send the command executed sequence when PSReadLine is loaded, if not shell integration should +# still work thanks to the command line sequence +if (Get-Module -Name PSReadLine) { + $__VSCodeOriginalPSConsoleHostReadLine = $function:PSConsoleHostReadLine + function Global:PSConsoleHostReadLine { + $tmp = $__VSCodeOriginalPSConsoleHostReadLine.Invoke() + # Write command executed sequence directly to Console to avoid the new line from Write-Host + [Console]::Write("$([char]0x1b)]633;C`a") + $tmp + } +} + +# Set IsWindows property +[Console]::Write("$([char]0x1b)]633;P;IsWindows=$($IsWindows)`a") + +# Set always on key handlers which map to default VS Code keybindings +function Set-MappedKeyHandler { + param ([string[]] $Chord, [string[]]$Sequence) + try { + $Handler = Get-PSReadLineKeyHandler -Chord $Chord | Select-Object -First 1 + } catch [System.Management.Automation.ParameterBindingException] { + # PowerShell 5.1 ships with PSReadLine 2.0.0 which does not have -Chord, + # so we check what's bound and filter it. + $Handler = Get-PSReadLineKeyHandler -Bound | Where-Object -FilterScript { $_.Key -eq $Chord } | Select-Object -First 1 + } + if ($Handler) { + Set-PSReadLineKeyHandler -Chord $Sequence -Function $Handler.Function + } +} + +function Set-MappedKeyHandlers { + Set-MappedKeyHandler -Chord Ctrl+Spacebar -Sequence 'F12,a' + Set-MappedKeyHandler -Chord Alt+Spacebar -Sequence 'F12,b' + Set-MappedKeyHandler -Chord Shift+Enter -Sequence 'F12,c' + Set-MappedKeyHandler -Chord Shift+End -Sequence 'F12,d' + + # Conditionally enable suggestions + if ($env:VSCODE_SUGGEST -eq '1') { + Remove-Item Env:VSCODE_SUGGEST + + # VS Code send completions request (may override Ctrl+Spacebar) + Set-PSReadLineKeyHandler -Chord 'F12,e' -ScriptBlock { + Send-Completions + } + + # Suggest trigger characters + Set-PSReadLineKeyHandler -Chord "-" -ScriptBlock { + [Microsoft.PowerShell.PSConsoleReadLine]::Insert("-") + Send-Completions + } + } +} + +function Send-Completions { + $commandLine = "" + $cursorIndex = 0 + # TODO: Since fuzzy matching exists, should completions be provided only for character after the + # last space and then filter on the client side? That would let you trigger ctrl+space + # anywhere on a word and have full completions available + [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$commandLine, [ref]$cursorIndex) + $completionPrefix = $commandLine + + # Get completions + $result = "`e]633;Completions" + if ($completionPrefix.Length -gt 0) { + # Get and send completions + $completions = TabExpansion2 -inputScript $completionPrefix -cursorColumn $cursorIndex + if ($null -ne $completions.CompletionMatches) { + $result += ";$($completions.ReplacementIndex);$($completions.ReplacementLength);$($cursorIndex);" + $result += $completions.CompletionMatches | ConvertTo-Json -Compress + } + } + $result += "`a" + + Write-Host -NoNewLine $result +} + +# Register key handlers if PSReadLine is available +if (Get-Module -Name PSReadLine) { + Set-MappedKeyHandlers +} diff --git a/src/plugins/terminal/terminal.qrc b/src/plugins/terminal/terminal.qrc index a4fece92fce..32d717d0f46 100644 --- a/src/plugins/terminal/terminal.qrc +++ b/src/plugins/terminal/terminal.qrc @@ -1,6 +1,13 @@ - - images/settingscategory_terminal.png - images/settingscategory_terminal@2x.png - + + images/settingscategory_terminal.png + images/settingscategory_terminal@2x.png + shellintegrations/shellintegration-bash.sh + shellintegrations/shellintegration-env.zsh + shellintegrations/shellintegration-login.zsh + shellintegrations/shellintegration-profile.zsh + shellintegrations/shellintegration-rc.zsh + shellintegrations/shellintegration.fish + shellintegrations/shellintegration.ps1 + diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 3ad8fc713a5..215a3883c40 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -188,13 +188,29 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) auto setTabText = [this](TerminalWidget * terminal) { auto index = m_tabWidget->indexOf(terminal); - m_tabWidget->setTabText(index, terminal->shellName()); + const FilePath cwd = terminal->cwd(); + + const QString exe = terminal->currentCommand().isEmpty() ? terminal->shellName() + : terminal->currentCommand().executable().fileName(); + + if (cwd.isEmpty()) + m_tabWidget->setTabText(index, exe); + else + m_tabWidget->setTabText(index, exe + " - " + cwd.fileName()); }; connect(terminal, &TerminalWidget::started, [setTabText, terminal](qint64 /*pid*/) { setTabText(terminal); }); + connect(terminal, &TerminalWidget::cwdChanged, [setTabText, terminal]() { + setTabText(terminal); + }); + + connect(terminal, &TerminalWidget::commandChanged, [setTabText, terminal]() { + setTabText(terminal); + }); + if (!terminal->shellName().isEmpty()) setTabText(terminal); diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index ad47fd8b15b..128c05213d6 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -23,10 +23,13 @@ QColor toQColor(const VTermColor &c) struct TerminalSurfacePrivate { - TerminalSurfacePrivate(TerminalSurface *surface, const QSize &initialGridSize) + TerminalSurfacePrivate(TerminalSurface *surface, + const QSize &initialGridSize, + ShellIntegration *shellIntegration) : m_vterm(vterm_new(initialGridSize.height(), initialGridSize.width()), vterm_free) , m_vtermScreen(vterm_obtain_screen(m_vterm.get())) , m_scrollback(std::make_unique(5000)) + , m_shellIntegration(shellIntegration) , q(surface) {} @@ -75,7 +78,15 @@ struct TerminalSurfacePrivate vterm_screen_set_damage_merge(m_vtermScreen, VTERM_DAMAGE_SCROLL); vterm_screen_enable_altscreen(m_vtermScreen, true); + memset(&m_vtermStateFallbacks, 0, sizeof(m_vtermStateFallbacks)); + + m_vtermStateFallbacks.osc = [](int cmd, VTermStringFragment fragment, void *user) { + auto p = static_cast(user); + return p->osc(cmd, fragment); + }; + VTermState *vts = vterm_obtain_state(m_vterm.get()); + vterm_state_set_unrecognised_fallbacks(vts, &m_vtermStateFallbacks, this); vterm_state_set_bold_highbright(vts, true); vterm_screen_reset(m_vtermScreen, 1); @@ -196,6 +207,14 @@ struct TerminalSurfacePrivate return 1; } + int osc(int cmd, const VTermStringFragment &fragment) + { + if (m_shellIntegration) + m_shellIntegration->onOsc(cmd, fragment); + + return 1; + } + int setTerminalProperties(VTermProp prop, VTermValue *val) { switch (prop) { @@ -274,19 +293,23 @@ struct TerminalSurfacePrivate std::unique_ptr m_vterm; VTermScreen *m_vtermScreen; VTermScreenCallbacks m_vtermScreenCallbacks; + VTermStateFallbacks m_vtermStateFallbacks; QColor m_defaultBgColor; Cursor m_cursor; + QString m_currentCommand; bool m_altscreen{false}; std::unique_ptr m_scrollback; + ShellIntegration *m_shellIntegration{nullptr}; + TerminalSurface *q; }; -TerminalSurface::TerminalSurface(QSize initialGridSize) - : d(std::make_unique(this, initialGridSize)) +TerminalSurface::TerminalSurface(QSize initialGridSize, ShellIntegration *shellIntegration) + : d(std::make_unique(this, initialGridSize, shellIntegration)) { d->init(); } @@ -478,6 +501,11 @@ QColor TerminalSurface::defaultBgColor() const return toQColor(d->defaultBgColor()); } +ShellIntegration *TerminalSurface::shellIntegration() const +{ + return d->m_shellIntegration; +} + CellIterator TerminalSurface::begin() const { auto res = CellIterator(this, {0, 0}); diff --git a/src/plugins/terminal/terminalsurface.h b/src/plugins/terminal/terminalsurface.h index 354a3a028d4..04958582c27 100644 --- a/src/plugins/terminal/terminalsurface.h +++ b/src/plugins/terminal/terminalsurface.h @@ -4,6 +4,7 @@ #pragma once #include "celliterator.h" +#include "shellintegration.h" #include #include @@ -47,7 +48,7 @@ class TerminalSurface : public QObject Q_OBJECT; public: - TerminalSurface(QSize initialGridSize); + TerminalSurface(QSize initialGridSize, ShellIntegration *shellIntegration); ~TerminalSurface(); public: @@ -95,6 +96,8 @@ public: QColor defaultBgColor() const; + ShellIntegration *shellIntegration() const; + signals: void writeToPty(const QByteArray &data); void invalidated(QRect grid); diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 23da5088ce9..b168320dce5 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -132,6 +133,10 @@ void TerminalWidget::setupPty() m_process->setWorkingDirectory(*m_openParameters.workingDirectory); m_process->setEnvironment(env); + if (m_surface->shellIntegration()) { + m_surface->shellIntegration()->prepareProcess(*m_process.get()); + } + connect(m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this]() { onReadyRead(false); }); @@ -242,7 +247,8 @@ void TerminalWidget::setupActions() connect(&m_zoomInAction, &QAction::triggered, this, &TerminalWidget::zoomIn); connect(&m_zoomOutAction, &QAction::triggered, this, &TerminalWidget::zoomOut); - addActions({&m_copyAction, &m_pasteAction, &m_clearSelectionAction, &m_zoomInAction, &m_zoomOutAction}); + addActions( + {&m_copyAction, &m_pasteAction, &m_clearSelectionAction, &m_zoomInAction, &m_zoomOutAction}); } void TerminalWidget::writeToPty(const QByteArray &data) @@ -253,7 +259,8 @@ void TerminalWidget::writeToPty(const QByteArray &data) void TerminalWidget::setupSurface() { - m_surface = std::make_unique(QSize{80, 60}); + m_shellIntegration.reset(new ShellIntegration()); + m_surface = std::make_unique(QSize{80, 60}, m_shellIntegration.get()); connect(m_surface.get(), &Internal::TerminalSurface::writeToPty, @@ -299,6 +306,22 @@ void TerminalWidget::setupSurface() connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] { verticalScrollBar()->setValue(verticalScrollBar()->maximum()); }); + if (m_shellIntegration) { + connect(m_shellIntegration.get(), + &ShellIntegration::commandChanged, + this, + [this](const CommandLine &command) { + m_currentCommand = command; + emit commandChanged(m_currentCommand); + }); + connect(m_shellIntegration.get(), + &ShellIntegration::currentDirChanged, + this, + [this](const QString ¤tDir) { + m_cwd = FilePath::fromUserInput(currentDir); + emit cwdChanged(m_cwd); + }); + } } void TerminalWidget::configBlinkTimer() @@ -470,6 +493,16 @@ QString TerminalWidget::shellName() const return m_shellName; } +FilePath TerminalWidget::cwd() const +{ + return m_cwd; +} + +CommandLine TerminalWidget::currentCommand() const +{ + return m_currentCommand; +} + QPoint TerminalWidget::viewportToGlobal(QPoint p) const { int y = p.y() - topMargin(); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 53d82b3899d..60cff4183fd 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -72,8 +72,13 @@ public: QString shellName() const; + Utils::FilePath cwd() const; + Utils::CommandLine currentCommand() const; + signals: void started(qint64 pid); + void cwdChanged(const Utils::FilePath &cwd); + void commandChanged(const Utils::CommandLine &cmd); protected: void paintEvent(QPaintEvent *event) override; @@ -158,6 +163,7 @@ protected: private: std::unique_ptr m_process; std::unique_ptr m_surface; + std::unique_ptr m_shellIntegration; QString m_shellName; @@ -201,6 +207,9 @@ private: Internal::Cursor m_cursor; QTimer m_cursorBlinkTimer; bool m_cursorBlinkState{true}; + + Utils::FilePath m_cwd; + Utils::CommandLine m_currentCommand; }; } // namespace Terminal diff --git a/src/plugins/terminal/tests/integration b/src/plugins/terminal/tests/integration new file mode 100755 index 00000000000..ac17432cb66 --- /dev/null +++ b/src/plugins/terminal/tests/integration @@ -0,0 +1,70 @@ +#!/bin/bash + +echo "Testing integration response, best start this from a terminal that has no builtin integration" +echo "e.g. 'sh'" +echo + +echo -e "\033[1m ⎆ Current dir should have changed to '/Some/Dir/Here'\033[0m" +printf "\033]7;file:///Some/Dir/Here\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ Current dir should have changed to '/Some/Other/Dir/Here'\033[0m" +printf "\033]1337;CurrentDir=/Some/Other/Dir/Here\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + + +echo -e "\033[1m ⎆ Current dir should have changed to '/VSCode/dir/with space'\033[0m" +printf "\033]633P;Cwd=/VSCode/dir/with space\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ The current process should have changed to 'test'\033[0m" +printf "\033]633E;test with arguments\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ The current process should have changed to 'test with space'\033[0m" +printf "\033]633E;'test with space'\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ The current process should have changed to 'test with space v2'\033[0m" +printf "\033]633E;\"test with space v2\"\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ The current process should have changed to 'test with space v3'\033[0m" +printf "\033]633E;\"./test/test with space v3\" -argument\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ The current process should have changed to 'cat'\033[0m" +printf "\033]633E;cat /dev/random | base64 -argument\033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ The current process should have changed to 'cat me'\033[0m" +printf "\033]633E;cat\\ me args \033\\" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + From 43968201452eb986286f7518404e1af332242a35 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 14 Mar 2023 20:08:03 +0100 Subject: [PATCH 0292/1447] CppQuickFixes: Add lacking calls to prepareSearch() Before matchesFor() are called. Change-Id: I6acc9b39c5fd9c500312fa1863456d4e71e50165 Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppquickfixes.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 8ae20d1c5a0..24e62a65d2c 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -2006,6 +2006,7 @@ bool matchName(const Name *name, QList *matches, QStri } else { simpleName = oo.prettyName(name); *className = simpleName; + classesFilter->prepareSearch(*className); *matches = classesFilter->matchesFor(dummy, *className); if (matches->empty()) { if (const Name *name = qualifiedName->base()) { @@ -2022,8 +2023,10 @@ bool matchName(const Name *name, QList *matches, QStri *className = oo.prettyName(name); } - if (matches->empty()) + if (matches->empty()) { + classesFilter->prepareSearch(*className); *matches = classesFilter->matchesFor(dummy, *className); + } if (matches->empty() && !simpleName.isEmpty()) *className = simpleName; } From 6dc7bfb8184ed223ab6e957d2c8055ec7cd3bd15 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 14 Mar 2023 18:30:49 +0100 Subject: [PATCH 0293/1447] ClangGlobalSymbolFilter: Avoid custom prepareSearch() for aggregate Delegate prepareSearch() directly to m_lspFilter aggregate inside ClangGlobalSymbolFilter::prepareSearch(). This helps to keep filters' responsibilites more self-contained. Disambiguate different overloads of WorkspaceLocatorFilter::prepareSearch(). Change-Id: I98f25d01ad713a8c209a07bfd0d05b3ddcf16948 Reviewed-by: David Schulz --- .../clangcodemodel/clangdlocatorfilters.cpp | 34 ++++++++++++++----- .../clangcodemodel/clangdlocatorfilters.h | 4 +-- src/plugins/languageclient/locatorfilter.cpp | 14 ++++---- src/plugins/languageclient/locatorfilter.h | 4 +-- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 4da1ece4cc8..76efcec54c5 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -23,6 +23,7 @@ using namespace Core; using namespace LanguageClient; using namespace LanguageServerProtocol; +using namespace ProjectExplorer; using namespace Utils; namespace ClangCodeModel { @@ -30,6 +31,17 @@ namespace Internal { const int MaxResultCount = 10000; +static QList clientsForOpenProjects() +{ + QSet clients; + const QList projects = ProjectManager::projects(); + for (Project *project : projects) { + if (Client *client = ClangModelManagerSupport::clientForProject(project)) + clients << client; + } + return clients.values(); +} + class CppLocatorFilter : public CppEditor::CppLocatorFilter { public: @@ -56,6 +68,10 @@ public: setHidden(true); setMaxResultCount(MaxResultCount); } + void prepareSearch(const QString &entry) override + { + prepareSearchForClients(entry, clientsForOpenProjects()); + } }; @@ -84,6 +100,10 @@ public: setHidden(true); setMaxResultCount(MaxResultCount); } + void prepareSearch(const QString &entry) override + { + prepareSearchForClients(entry, clientsForOpenProjects()); + } }; class CppFunctionsFilter : public CppEditor::CppFunctionsFilter @@ -112,6 +132,10 @@ public: setHidden(true); setMaxResultCount(MaxResultCount); } + void prepareSearch(const QString &entry) override + { + prepareSearchForClients(entry, clientsForOpenProjects()); + } }; @@ -121,7 +145,7 @@ ClangGlobalSymbolFilter::ClangGlobalSymbolFilter() } ClangGlobalSymbolFilter::ClangGlobalSymbolFilter(ILocatorFilter *cppFilter, - WorkspaceLocatorFilter *lspFilter) + ILocatorFilter *lspFilter) : m_cppFilter(cppFilter), m_lspFilter(lspFilter) { setId(CppEditor::Constants::LOCATOR_FILTER_ID); @@ -139,13 +163,7 @@ ClangGlobalSymbolFilter::~ClangGlobalSymbolFilter() void ClangGlobalSymbolFilter::prepareSearch(const QString &entry) { m_cppFilter->prepareSearch(entry); - QList clients; - for (ProjectExplorer::Project * const project : ProjectExplorer::ProjectManager::projects()) { - if (Client * const client = ClangModelManagerSupport::clientForProject(project)) - clients << client; - } - if (!clients.isEmpty()) - m_lspFilter->prepareSearch(entry, clients); + m_lspFilter->prepareSearch(entry); } QList ClangGlobalSymbolFilter::matchesFor( diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index 11cf4c00b6b..3a6011b8eea 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -15,7 +15,7 @@ class ClangGlobalSymbolFilter : public Core::ILocatorFilter public: ClangGlobalSymbolFilter(); ClangGlobalSymbolFilter(Core::ILocatorFilter *cppFilter, - LanguageClient::WorkspaceLocatorFilter *lspFilter); + Core::ILocatorFilter *lspFilter); ~ClangGlobalSymbolFilter() override; private: @@ -23,7 +23,7 @@ private: QList matchesFor(QFutureInterface &future, const QString &entry) override; Core::ILocatorFilter * const m_cppFilter; - LanguageClient::WorkspaceLocatorFilter * const m_lspFilter; + Core::ILocatorFilter * const m_lspFilter; }; class ClangClassesFilter : public ClangGlobalSymbolFilter diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index f646209e28d..29619496c50 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -216,21 +216,23 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter void WorkspaceLocatorFilter::prepareSearch(const QString &entry) { - prepareSearch(entry, LanguageClientManager::clients(), false); + prepareSearchHelper(entry, LanguageClientManager::clients(), false); } -void WorkspaceLocatorFilter::prepareSearch(const QString &entry, const QList &clients) +void WorkspaceLocatorFilter::prepareSearchForClients(const QString &entry, const QList &clients) { - prepareSearch(entry, clients, true); + prepareSearchHelper(entry, clients, true); } -void WorkspaceLocatorFilter::prepareSearch(const QString &entry, - const QList &clients, - bool force) +void WorkspaceLocatorFilter::prepareSearchHelper(const QString &entry, + const QList &clients, bool force) { m_pendingRequests.clear(); m_results.clear(); + if (clients.isEmpty()) + return; + WorkspaceSymbolParams params; params.setQuery(entry); if (m_maxResultCount > 0) diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index a6e107e97eb..58d8560c8e7 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -77,7 +77,7 @@ public: /// request workspace symbols for all clients with enabled locator void prepareSearch(const QString &entry) override; /// force request workspace symbols for all given clients - void prepareSearch(const QString &entry, const QList &clients); + void prepareSearchForClients(const QString &entry, const QList &clients); QList matchesFor(QFutureInterface &future, const QString &entry) override; signals: @@ -89,7 +89,7 @@ protected: void setMaxResultCount(qint64 limit) { m_maxResultCount = limit; } private: - void prepareSearch(const QString &entry, const QList &clients, bool force); + void prepareSearchHelper(const QString &entry, const QList &clients, bool force); void handleResponse(Client *client, const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); From 76d2e7a4f36360fed300be11e2f67f709dbf65aa Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 15 Mar 2023 13:43:59 +0100 Subject: [PATCH 0294/1447] ProjectExplorer: Add infrastructure for source -> binary mapping Task-number: QTCREATORBUG-28815 Change-Id: Ib692981e92f5a395dbe400c2cd48042479f12c78 Reviewed-by: Reviewed-by: David Schulz --- .../cmakeprojectmanager/cmakeproject.cpp | 16 +++- .../cmakeprojectmanager/cmakeproject.h | 2 + src/plugins/projectexplorer/project.cpp | 77 +++++++++++++++++++ src/plugins/projectexplorer/project.h | 1 + src/plugins/projectexplorer/projectexplorer.h | 3 + .../projectexplorer/projectexplorer.qrc | 8 ++ .../multi-target-project/CMakeLists.txt | 3 + .../multi-target-project-app.pro | 4 + .../multi-target-project-lib.cpp | 6 ++ .../multi-target-project-lib.pro | 4 + .../multi-target-project-main.cpp | 6 ++ .../multi-target-project-shared.h | 3 + .../multi-target-project.pro | 4 + .../multi-target-project.qbs | 10 +++ 14 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/CMakeLists.txt create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-app.pro create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.cpp create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.pro create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-main.cpp create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-shared.h create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.pro create mode 100644 src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.qbs diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 829c28be152..8be4716a838 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -7,16 +7,17 @@ #include "cmakeprojectconstants.h" #include "cmakeprojectimporter.h" #include "cmakeprojectmanagertr.h" -#include "cmaketool.h" #include #include +#include #include #include #include #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; @@ -237,4 +238,17 @@ ProjectExplorer::DeploymentKnowledge CMakeProject::deploymentKnowledge() const : DeploymentKnowledge::Bad; } +void CMakeProject::configureAsExampleProject(ProjectExplorer::Kit *kit) +{ + QList infoList; + const QList kits(kit != nullptr ? QList({kit}) : KitManager::kits()); + for (Kit *k : kits) { + if (QtSupport::QtKitAspect::qtVersion(k) != nullptr) { + if (auto factory = BuildConfigurationFactory::find(k, projectFilePath())) + infoList << factory->allAvailableSetups(k, projectFilePath()); + } + } + setup(infoList); +} + } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 2885b9eb4b1..09154615013 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -36,6 +36,8 @@ protected: private: ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; + void configureAsExampleProject(ProjectExplorer::Kit *kit) override; + Internal::PresetsData combinePresets(Internal::PresetsData &cmakePresetsData, Internal::PresetsData &cmakeUserPresetsData); void setupBuildPresets(Internal::PresetsData &presetsData); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 84f5363cd11..e62d65c0f89 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -869,6 +869,13 @@ const Node *Project::nodeForFilePath(const FilePath &filePath, return nullptr; } +FilePaths Project::binariesForSourceFile(const Utils::FilePath &sourceFile) const +{ + Q_UNUSED(sourceFile); + // TODO: QTCREATORBUG-28815 + return {}; +} + void Project::setProjectLanguages(Context language) { if (d->m_projectLanguages == language) @@ -1482,6 +1489,76 @@ void ProjectExplorerPlugin::testProject_multipleBuildConfigs() ProjectManager::closeAllProjects(); // QTCREATORBUG-25655 } +void ProjectExplorerPlugin::testSourceToBinaryMapping() +{ + // Find suitable kit. + Kit * const kit = findOr(KitManager::kits(), nullptr, [](const Kit *k) { + return k->isValid(); + }); + if (!kit) + QSKIP("The test requires at least one valid kit."); + + // Copy project from qrc. + QTemporaryDir * const tempDir = TemporaryDirectory::masterTemporaryDirectory(); + QVERIFY(tempDir->isValid()); + const FilePath projectDir = FilePath::fromString(tempDir->path() + "/multi-target-project"); + if (!projectDir.exists()) { + const auto result = FilePath(":/projectexplorer/testdata/multi-target-project") + .copyRecursively(projectDir); + QVERIFY2(result, qPrintable(result.error())); + const QFileInfoList files = QDir(projectDir.toString()).entryInfoList(QDir::Files); + for (const QFileInfo &f : files) + QFile(f.absoluteFilePath()).setPermissions(f.permissions() | QFile::WriteUser); + } + + // Load Project. + QFETCH(QString, projectFileName); + const auto theProject = openProject(projectDir.pathAppended(projectFileName)); + if (theProject.errorMessage().contains("text/")) { + QSKIP("This test requires the presence of the qmake/cmake/qbs project managers " + "to be fully functional"); + } + + QVERIFY2(theProject, qPrintable(theProject.errorMessage())); + theProject.project()->configureAsExampleProject(kit); + QCOMPARE(theProject.project()->targets().size(), 1); + Target * const target = theProject.project()->activeTarget(); + QVERIFY(target); + BuildSystem * const bs = target->buildSystem(); + QVERIFY(bs); + QCOMPARE(bs, target->activeBuildConfiguration()->buildSystem()); + if (bs->isWaitingForParse() || bs->isParsing()) { + QSignalSpy parsingFinishedSpy(bs, &BuildSystem::parsingFinished); + QVERIFY(parsingFinishedSpy.wait(10000)); + } + QVERIFY(!bs->isWaitingForParse() && !bs->isParsing()); + + // Build project. + BuildManager::buildProjectWithoutDependencies(theProject.project()); + if (BuildManager::isBuilding()) { + QSignalSpy buildingFinishedSpy(BuildManager::instance(), &BuildManager::buildQueueFinished); + QVERIFY(buildingFinishedSpy.wait(10000)); + } + QVERIFY(!BuildManager::isBuilding()); + + // Check mapping + const auto binariesForSource = [&](const QString &fileName) { + return theProject.project()->binariesForSourceFile(projectDir.pathAppended(fileName)); + }; + QEXPECT_FAIL(0, "QTCREATORBUG-28815", Abort); + QCOMPARE(binariesForSource("multi-target-project-main.cpp").size(), 1); + QCOMPARE(binariesForSource("multi-target-project-lib.cpp").size(), 1); + QCOMPARE(binariesForSource("multi-target-project-shared.h").size(), 2); +} + +void ProjectExplorerPlugin::testSourceToBinaryMapping_data() +{ + QTest::addColumn("projectFileName"); + QTest::addRow("cmake") << "CMakeLists.txt"; + QTest::addRow("qbs") << "multi-target-project.qbs"; + QTest::addRow("qmake") << "multi-target-project.pro"; +} + #endif // WITH_TESTS } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index ebf38a688d4..d753048aff5 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -110,6 +110,7 @@ public: bool isKnownFile(const Utils::FilePath &filename) const; const Node *nodeForFilePath(const Utils::FilePath &filePath, const NodeMatcher &extraMatcher = {}) const; + Utils::FilePaths binariesForSourceFile(const Utils::FilePath &sourceFile) const; virtual QVariantMap toMap() const; diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index baa8bb83a6b..e5f91bd334d 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -261,6 +261,9 @@ private slots: void testProject_projectTree(); void testProject_multipleBuildConfigs(); + void testSourceToBinaryMapping(); + void testSourceToBinaryMapping_data(); + void testSessionSwitch(); #endif // WITH_TESTS }; diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index ececb0854b3..0cc88e3331a 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -86,5 +86,13 @@ images/settingscategory_cpp@2x.png images/importasproject.png images/importasproject@2x.png + testdata/multi-target-project/CMakeLists.txt + testdata/multi-target-project/multi-target-project-app.pro + testdata/multi-target-project/multi-target-project-lib.cpp + testdata/multi-target-project/multi-target-project-lib.pro + testdata/multi-target-project/multi-target-project-main.cpp + testdata/multi-target-project/multi-target-project-shared.h + testdata/multi-target-project/multi-target-project.pro + testdata/multi-target-project/multi-target-project.qbs diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/CMakeLists.txt b/src/plugins/projectexplorer/testdata/multi-target-project/CMakeLists.txt new file mode 100644 index 00000000000..5313539cd79 --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/CMakeLists.txt @@ -0,0 +1,3 @@ +project(multi-target-project) +add_executable(multi-target-project-app multi-target-project-main.cpp multi-target-project-shared.h) +add_library(multi-target-project-lib STATIC multi-target-project-lib.cpp multi-target-project-shared.h) diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-app.pro b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-app.pro new file mode 100644 index 00000000000..96870c05c1f --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-app.pro @@ -0,0 +1,4 @@ +TARGET = app +CONFIG -= qt +SOURCES = multi-target-project-main.cpp +HEADERS = multi-target-project-shared.h diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.cpp b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.cpp new file mode 100644 index 00000000000..9b7a34861c7 --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.cpp @@ -0,0 +1,6 @@ +#include "multi-target-project-shared.h" + +int increaseNumber() +{ + return getNumber() + 1; +} diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.pro b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.pro new file mode 100644 index 00000000000..42571540519 --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-lib.pro @@ -0,0 +1,4 @@ +TEMPLATE = lib +CONFIG += static +SOURCES = multi-target-project-lib.cpp +HEADERS = multi-target-project-shared.h diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-main.cpp b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-main.cpp new file mode 100644 index 00000000000..306400b3502 --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-main.cpp @@ -0,0 +1,6 @@ +#include "multi-target-project-shared.h" + +int main() +{ + return getNumber(); +} diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-shared.h b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-shared.h new file mode 100644 index 00000000000..9f839e82d02 --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project-shared.h @@ -0,0 +1,3 @@ +#pragma once + +inline int getNumber() { return 5; } diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.pro b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.pro new file mode 100644 index 00000000000..5e6289d7b26 --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +app.file = multi-target-project-app.pro +lib.file = multi-target-project-lib.pro +SUBDIRS = app lib diff --git a/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.qbs b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.qbs new file mode 100644 index 00000000000..079ac82c955 --- /dev/null +++ b/src/plugins/projectexplorer/testdata/multi-target-project/multi-target-project.qbs @@ -0,0 +1,10 @@ +Project { + CppApplication { + name: "app" + files: ["multi-target-project-main.cpp", "multi-target-project-shared.h"] + } + StaticLibrary { + Depends { name: "cpp" } + files: ["multi-target-project-lib.cpp", "multi-target-project-shared.h"] + } +} From 23513bb714e9551af54e7b4d1428fa3c6396c5e2 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 15 Mar 2023 08:29:37 +0100 Subject: [PATCH 0295/1447] Copilot: remove unused client instance function Change-Id: I84c3d674bae1011a7b0bff070c2d3d5d89675147 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotclient.cpp | 10 ---------- src/plugins/copilot/copilotclient.h | 2 -- 2 files changed, 12 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 06f127e645f..baf902c15fa 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -3,8 +3,6 @@ #include "copilotclient.h" -#include "copilotsettings.h" - #include #include #include @@ -35,13 +33,6 @@ static LanguageClient::BaseClientInterface *clientInterface(const FilePath &node return interface; } -static CopilotClient *currentInstance = nullptr; - -CopilotClient *CopilotClient::instance() -{ - return currentInstance; -} - CopilotClient::CopilotClient(const FilePath &nodePath, const FilePath &distPath) : LanguageClient::Client(clientInterface(nodePath, distPath)) { @@ -69,7 +60,6 @@ CopilotClient::CopilotClient(const FilePath &nodePath, const FilePath &distPath) for (Core::IDocument *doc : Core::DocumentModel::openedDocuments()) openDoc(doc); - currentInstance = this; } void CopilotClient::openDocument(TextDocument *document) diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index 42989e93f77..5111e04e1df 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -25,8 +25,6 @@ class CopilotClient : public LanguageClient::Client public: explicit CopilotClient(const Utils::FilePath &nodePath, const Utils::FilePath &distPath); - static CopilotClient *instance(); - void openDocument(TextEditor::TextDocument *document) override; void scheduleRequest(TextEditor::TextEditorWidget *editor); From 7f56ccaa9ec5f077df1f3a9594943b00137c7721 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 16 Mar 2023 06:56:02 +0100 Subject: [PATCH 0296/1447] TextEditor: avoid painting annotations over suggestions Blocks with suggestions are longer than without the suggestion. So we have to calculate the annotation start position based on the reaplcement and not the actual document layout. Change-Id: I32ce81134e1146dd28ae11a70356a98c75529236 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/texteditor.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index b614a18e736..b92d848d4ea 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -4061,7 +4061,13 @@ static TextMarks availableMarks(const TextMarks &marks, QRectF TextEditorWidgetPrivate::getLastLineLineRect(const QTextBlock &block) { - const QTextLayout *layout = block.layout(); + QTextLayout *layout = nullptr; + if (block != m_suggestionBlock) + layout = block.layout(); + else if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(block)) + layout = replacement->firstBlock().layout(); + + QTC_ASSERT(layout, layout = block.layout()); const int lineCount = layout->lineCount(); if (lineCount < 1) return {}; From 8247d578c735b4ce74f76b86aaa9065d76cb1498 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 16 Mar 2023 07:13:42 +0100 Subject: [PATCH 0297/1447] TextEditor: skip auto completion while suggestion is visible The use can still explicitly request completions in that case via the keyboard shortcut. Change-Id: I4ed47232a24288c540d1357c0f876a1cdfcfec08 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/codeassist/codeassistant.cpp | 1 + src/plugins/texteditor/texteditor.cpp | 5 +++++ src/plugins/texteditor/texteditor.h | 1 + 3 files changed, 7 insertions(+) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index 34ba897d8db..b092d69bc04 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -444,6 +444,7 @@ void CodeAssistantPrivate::automaticProposalTimeout() { if (isWaitingForProposal() || m_editorWidget->multiTextCursor().hasMultipleCursors() + || m_editorWidget->suggestionVisible() || (isDisplayingProposal() && !m_proposalWidget->isFragile())) { return; } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index b92d848d4ea..d2c253fb6c0 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -5952,6 +5952,11 @@ void TextEditorWidget::clearSuggestion() d->clearCurrentSuggestion(); } +bool TextEditorWidget::suggestionVisible() const +{ + return d->m_suggestionBlock.isValid(); +} + #ifdef WITH_TESTS void TextEditorWidget::processTooltipRequest(const QTextCursor &c) { diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index db20e0beb5f..31c4c9d6bf4 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -471,6 +471,7 @@ public: void insertSuggestion(const QString &suggestion); void clearSuggestion(); + bool suggestionVisible() const; #ifdef WITH_TESTS void processTooltipRequest(const QTextCursor &c); From d5d7b1d19262780c5350a234ef27abbc3378335a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 16 Mar 2023 10:39:37 +0100 Subject: [PATCH 0298/1447] TextEditor: avoid showing suggestion and completion simultaneously If the use erxplicitly requested the completion hide the suggestion otherwise ignore the completion. Change-Id: I52485e322b0521b0af10ae6945437bf96642ad89 Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/codeassist/codeassistant.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index b092d69bc04..b81161dd6a7 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -252,6 +252,14 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR return; } + if (m_editorWidget->suggestionVisible()) { + if (reason != ExplicitlyInvoked) { + destroyContext(); + return; + } + m_editorWidget->clearSuggestion(); + } + const QString prefix = m_editorWidget->textAt(basePosition, m_editorWidget->position() - basePosition); if (!newProposal->hasItemsToPropose(prefix, reason)) { From a2de016f64f91c154a222a2216c50f59e9350459 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 9 Mar 2023 17:02:58 +0100 Subject: [PATCH 0299/1447] Examples: Optionally parse categories from meta data Optionally parses example categories from the examples manifests, when setting the environment variable QTC_USE_EXAMPLE_CATEGORIES (can be done in Qt Creator's Environment > System > Environment settings). It doesn't make sense to unconditionally enable that yet, because only few examples actually have categories so far, so we will need to wait until some Qt version is suited for enabling this. If an example set does not provide categories, the "highlighted" property is used to provide a "Featured" category, as before. If an example set does provide categories, these are shown instead, sorted alphabetically, and examples with the "highlighted" property are put at the front of the category, overriding the otherwise alphabetical listing inside the categories. Examples without a category are put into a separate "Other" category at the end. Task-number: QTCREATORBUG-28546 Change-Id: I7ca312686eae13e16961def1b4b36ffd7050a447 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/qtsupport/exampleslistmodel.cpp | 67 +++++++++++++++++---- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 40196934d46..c567f992e41 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -320,6 +320,56 @@ static bool isValidExampleOrDemo(ExampleItem *item) return ok || debugExamples(); } +static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) +{ + if (first->isHighlighted && !second->isHighlighted) + return true; + if (!first->isHighlighted && second->isHighlighted) + return false; + return first->name.compare(second->name, Qt::CaseInsensitive) < 0; +} + +static QList>> getCategories( + const QList &items) +{ + static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples"); + const bool useCategories = qtcEnvironmentVariableIsSet("QTC_USE_EXAMPLE_CATEGORIES"); + QList other; + QMap> categoryMap; + if (useCategories) { + for (ExampleItem *item : items) { + const QStringList itemCategories = item->metaData.value("category"); + for (const QString &category : itemCategories) + categoryMap[category].append(item); + if (itemCategories.isEmpty()) + other.append(item); + } + } + QList>> categories; + if (categoryMap.isEmpty()) { + // The example set doesn't define categories. Consider the "highlighted" ones as "featured" + QList featured; + QList allOther; + std::tie(featured, allOther) = Utils::partition(items, [](ExampleItem *i) { + return i->isHighlighted; + }); + if (!featured.isEmpty()) + categories.append({Tr::tr("Featured", "Category for highlighted examples"), featured}); + if (!allOther.isEmpty()) + categories.append({otherDisplayName, allOther}); + } else { + const auto end = categoryMap.constKeyValueEnd(); + for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) + categories.append(*it); + if (!other.isEmpty()) + categories.append({otherDisplayName, other}); + } + const auto end = categories.end(); + for (auto it = categories.begin(); it != end; ++it) + sort(it->second, sortByHighlightedAndName); + return categories; +} + void ExamplesViewController::updateExamples() { QString examplesInstallPath; @@ -363,21 +413,12 @@ void ExamplesViewController::updateExamples() [](ExampleItem *item) { return item->tags.contains("ios"); }); } } - Utils::sort(items, [](ExampleItem *first, ExampleItem *second) { - return first->name.compare(second->name, Qt::CaseInsensitive) < 0; - }); - QList featured; - QList other; - std::tie(featured, other) = Utils::partition(items, - [](ExampleItem *i) { return i->isHighlighted; }); - - if (!featured.isEmpty()) { - m_view->addSection({Tr::tr("Featured", "Category for highlighted examples"), 0}, - static_container_cast(featured)); + const QList>> sections = getCategories(items); + for (int i = 0; i < sections.size(); ++i) { + m_view->addSection({sections.at(i).first, i}, + static_container_cast(sections.at(i).second)); } - m_view->addSection({Tr::tr("Other", "Category for all other examples"), 1}, - static_container_cast(other)); } void ExampleSetModel::updateQtVersionList() From d3d2536022ebb7cb489da0e1011a6be12e75f09e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 14 Mar 2023 23:07:24 +0100 Subject: [PATCH 0300/1447] JsonFieldPage: Remove superfluous reportFinished() Change-Id: I0f55b89a03fe012d6b2ac5a6430193729620edec Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index f155c5656e7..c5a82b62a8a 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -666,7 +666,6 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) const QList matches = classesFilter->matchesFor(f, {}); if (!matches.isEmpty()) f.reportResults(QVector(matches.cbegin(), matches.cend())); - f.reportFinished(); })); } From f5aa99f2298542c15cd379cd14f5001a55ea5291 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 16 Mar 2023 12:32:53 +0100 Subject: [PATCH 0301/1447] ProjectExplorer: Add functionality for mapping source files to binaries Works out of the box with qbs. cmake and qmake need backend adaptations. Task-number: QTCREATORBUG-28815 Change-Id: I0238416a23c1574bc2b6121e2ef942a9260d94d9 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/projectexplorer/project.cpp | 47 ++++++++++++++----- src/plugins/projectexplorer/projectnodes.h | 2 + .../qbsprojectmanager/qbsnodetreebuilder.cpp | 4 ++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index e62d65c0f89..b9767fdedcb 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -869,11 +869,32 @@ const Node *Project::nodeForFilePath(const FilePath &filePath, return nullptr; } -FilePaths Project::binariesForSourceFile(const Utils::FilePath &sourceFile) const +FilePaths Project::binariesForSourceFile(const FilePath &sourceFile) const { - Q_UNUSED(sourceFile); - // TODO: QTCREATORBUG-28815 - return {}; + if (!rootProjectNode()) + return {}; + const QList fileNodes = rootProjectNode()->findNodes([&sourceFile](Node *n) { + return n->filePath() == sourceFile; + }); + FilePaths binaries; + for (const Node * const fileNode : fileNodes) { + for (ProjectNode *projectNode = fileNode->parentProjectNode(); projectNode; + projectNode = projectNode->parentProjectNode()) { + if (!projectNode->isProduct()) + continue; + if (projectNode->productType() == ProductType::App + || projectNode->productType() == ProductType::Lib) { + const QList binaryNodes = projectNode->findNodes([](Node *n) { + return n->asFileNode() && (n->asFileNode()->fileType() == FileType::App + || n->asFileNode()->fileType() == FileType::Lib); + + }); + binaries << Utils::transform(binaryNodes, &Node::filePath); + } + break; + } + } + return binaries; } void Project::setProjectLanguages(Context language) @@ -1533,19 +1554,23 @@ void ProjectExplorerPlugin::testSourceToBinaryMapping() } QVERIFY(!bs->isWaitingForParse() && !bs->isParsing()); - // Build project. - BuildManager::buildProjectWithoutDependencies(theProject.project()); - if (BuildManager::isBuilding()) { - QSignalSpy buildingFinishedSpy(BuildManager::instance(), &BuildManager::buildQueueFinished); - QVERIFY(buildingFinishedSpy.wait(10000)); + if (QLatin1String(QTest::currentDataTag()) == QLatin1String("qbs")) { + BuildManager::buildProjectWithoutDependencies(theProject.project()); + if (BuildManager::isBuilding()) { + QSignalSpy buildingFinishedSpy(BuildManager::instance(), &BuildManager::buildQueueFinished); + QVERIFY(buildingFinishedSpy.wait(10000)); + } + QVERIFY(!BuildManager::isBuilding()); + QSignalSpy projectUpdateSpy(theProject.project(), &Project::fileListChanged); + QVERIFY(projectUpdateSpy.wait(5000)); } - QVERIFY(!BuildManager::isBuilding()); // Check mapping const auto binariesForSource = [&](const QString &fileName) { return theProject.project()->binariesForSourceFile(projectDir.pathAppended(fileName)); }; - QEXPECT_FAIL(0, "QTCREATORBUG-28815", Abort); + QEXPECT_FAIL("cmake", "QTCREATORBUG-28815", Abort); + QEXPECT_FAIL("qmake", "QTCREATORBUG-28815", Abort); QCOMPARE(binariesForSource("multi-target-project-main.cpp").size(), 1); QCOMPARE(binariesForSource("multi-target-project-lib.cpp").size(), 1); QCOMPARE(binariesForSource("multi-target-project-shared.h").size(), 2); diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 35927c02c8e..58fbf9cb925 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -32,6 +32,8 @@ enum class FileType : quint16 { Resource, QML, Project, + App, + Lib, FileTypeSize }; diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp index 55ae7d8ac03..82e896e77a8 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp @@ -42,6 +42,10 @@ static FileType fileType(const QJsonObject &artifact) return FileType::StateChart; if (fileTags.contains("qt.qml.qml")) return FileType::QML; + if (fileTags.contains("application")) + return FileType::App; + if (fileTags.contains("staticlibrary") || fileTags.contains("dynamiclibrary")) + return FileType::Lib; return FileType::Unknown; } From 97d8b9fe672774353b8bc8fe318fe9267e88dbea Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 17 Mar 2023 07:50:28 +0100 Subject: [PATCH 0302/1447] Terminal: Fix qbs build Amends bd52e53dbfa7641098313edd56d885df69916f9f. Change-Id: I23766fb9d3e67e1e2a94e95476092233e839002f Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminal.qbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 961f4081160..53f08803393 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -19,6 +19,8 @@ QtcPlugin { "scrollback.h", "shellmodel.cpp", "shellmodel.h", + "shellintegration.cpp", + "shellintegration.h", "terminal.qrc", "terminalpane.cpp", "terminalpane.h", From 65e1baf5f7a5ddd780e4d8e982035999eddfe198 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 16 Mar 2023 14:45:18 +0100 Subject: [PATCH 0303/1447] TextEditor: set the cursor to the widget before closing the edit block This will make sure that code reacting on the document change signal can get the final cursor position from the widget. More specificly this fixes requesting copilot suggestions when automatic text is inserted like closing parentheses when typing "if (" Change-Id: I01a13e67e72b89010fe39de3d0def0622a9b08b8 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotclient.cpp | 3 ++- src/plugins/texteditor/texteditor.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index baf902c15fa..50be6788410 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -76,7 +76,8 @@ void CopilotClient::openDocument(TextDocument *document) TextEditorWidget *widget = textEditor->editorWidget(); if (widget->multiTextCursor().hasMultipleCursors()) return; - if (widget->textCursor().position() != (position + charsAdded)) + const int cursorPosition = widget->textCursor().position(); + if (cursorPosition < position || cursorPosition > position + charsAdded) return; scheduleRequest(textEditor->editorWidget()); }); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index d2c253fb6c0..8ffdcd1c26e 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -2894,13 +2894,13 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) if (!autoText.isEmpty()) cursor.setPosition(autoText.length() == 1 ? cursor.position() : cursor.anchor()); + setTextCursor(cursor); + if (doEditBlock) { cursor.endEditBlock(); if (cursorWithinSnippet) d->m_snippetOverlay->updateEquivalentSelections(textCursor()); } - - setTextCursor(cursor); } if (!ro && e->key() == Qt::Key_Delete && d->m_parenthesesMatchingEnabled) From bcd4c3f360a907f9a8855b6794e2157feb0e4cb0 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 16 Mar 2023 11:33:51 +0100 Subject: [PATCH 0304/1447] TextEditor: Adjust extra selections when suggestions are visible Change-Id: Id914ce544b2289bff5403c8a673dceebbc517b54 Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/texteditor.cpp | 41 ++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 8ffdcd1c26e..6cc8084bdd0 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -4730,6 +4730,24 @@ void TextEditorWidgetPrivate::setupSelections(const PaintEventData &data, PaintEventBlockData &blockData) const { QVector prioritySelections; + + int deltaPos = -1; + int delta = 0; + + if (m_suggestionBlock == data.block) { + if (QTextDocument *replacement = TextDocumentLayout::replacementDocument( + m_suggestionBlock)) { + deltaPos = TextDocumentLayout::replacementPosition(data.block); + const QString trailingText = data.block.text().mid(deltaPos); + if (!trailingText.isEmpty()) { + const int trailingIndex = replacement->firstBlock().text().indexOf(trailingText, + deltaPos); + if (trailingIndex >= 0) + delta = std::max(trailingIndex - deltaPos, 0); + } + } + } + for (int i = 0; i < data.context.selections.size(); ++i) { const QAbstractTextDocumentLayout::Selection &range = data.context.selections.at(i); const int selStart = range.cursor.selectionStart() - blockData.position; @@ -4739,6 +4757,22 @@ void TextEditorWidgetPrivate::setupSelections(const PaintEventData &data, QTextLayout::FormatRange o; o.start = selStart; o.length = selEnd - selStart; + o.format = range.format; + QTextLayout::FormatRange rest; + rest.start = -1; + if (deltaPos >= 0 && delta != 0) { + if (o.start >= deltaPos) { + o.start += delta; + } else if (o.start + o.length > deltaPos) { + // the format range starts before and ends after the position so we need to + // split the format into before and after the suggestion format ranges + rest.start = deltaPos + delta; + rest.length = o.length - (deltaPos - o.start); + rest.format = o.format; + o.length = deltaPos - o.start; + } + } + o.format = range.format; if (data.textCursor.hasSelection() && data.textCursor == range.cursor && data.textCursor.anchor() == range.cursor.anchor()) { @@ -4751,10 +4785,15 @@ void TextEditorWidgetPrivate::setupSelections(const PaintEventData &data, || (o.format.foreground().style() == Qt::NoBrush && o.format.underlineStyle() != QTextCharFormat::NoUnderline && o.format.background() == Qt::NoBrush)) { - if (q->selectionVisible(data.block.blockNumber())) + if (q->selectionVisible(data.block.blockNumber())) { prioritySelections.append(o); + if (rest.start >= 0) + prioritySelections.append(rest); + } } else { blockData.selections.append(o); + if (rest.start >= 0) + blockData.selections.append(rest); } } } From 400dad939ee210e9f3b29b957665797f314f2983 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Mar 2023 16:46:09 +0100 Subject: [PATCH 0305/1447] ProjectExplorer: Store host, port and user in SshParameters again This effectively reverts 21c66ce5fdaf9fcf. We are not aiming at using QUrl everywhere anymore, rather have Utils::FilePath. Change-Id: I97ccc7ee6976c27e629b446bc4f3851532463213 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../devicesupport/sshparameters.cpp | 22 ++++----------- .../devicesupport/sshparameters.h | 28 +++++++++++-------- ...riclinuxdeviceconfigurationwizardpages.cpp | 13 ++------- ...nericlinuxdeviceconfigurationwizardpages.h | 1 - 4 files changed, 24 insertions(+), 40 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp index 3cc6364a677..17e50bdf2ee 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp @@ -19,10 +19,7 @@ using namespace Utils; namespace ProjectExplorer { -SshParameters::SshParameters() -{ - url.setPort(0); -} +SshParameters::SshParameters() = default; QStringList SshParameters::connectionOptions(const FilePath &binary) const { @@ -81,10 +78,11 @@ bool SshParameters::setupSshEnvironment(QtcProcess *process) return hasDisplay; } - -static inline bool equals(const SshParameters &p1, const SshParameters &p2) +bool operator==(const SshParameters &p1, const SshParameters &p2) { - return p1.url == p2.url + return p1.m_host == p2.m_host + && p1.m_port == p2.m_port + && p1.m_userName == p2.m_userName && p1.authenticationType == p2.authenticationType && p1.privateKeyFile == p2.privateKeyFile && p1.hostKeyCheckingMode == p2.hostKeyCheckingMode @@ -92,16 +90,6 @@ static inline bool equals(const SshParameters &p1, const SshParameters &p2) && p1.timeout == p2.timeout; } -bool operator==(const SshParameters &p1, const SshParameters &p2) -{ - return equals(p1, p2); -} - -bool operator!=(const SshParameters &p1, const SshParameters &p2) -{ - return !equals(p1, p2); -} - #ifdef WITH_TESTS namespace SshTest { const QString getHostFromEnvironment() diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.h b/src/plugins/projectexplorer/devicesupport/sshparameters.h index 00b63e3aacf..b4da396db56 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.h +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.h @@ -7,8 +7,6 @@ #include -#include - namespace Utils { class QtcProcess; } namespace ProjectExplorer { @@ -29,17 +27,18 @@ public: SshParameters(); - QString host() const { return url.host(); } - quint16 port() const { return url.port(); } - QString userName() const { return url.userName(); } + QString host() const { return m_host; } + quint16 port() const { return m_port; } + QString userName() const { return m_userName; } + QString userAtHost() const { return userName().isEmpty() ? host() : userName() + '@' + host(); } - void setHost(const QString &host) { url.setHost(host); } - void setPort(int port) { url.setPort(port); } - void setUserName(const QString &name) { url.setUserName(name); } + + void setHost(const QString &host) { m_host = host; } + void setPort(int port) { m_port = port; } + void setUserName(const QString &name) { m_userName = name; } QStringList connectionOptions(const Utils::FilePath &binary) const; - QUrl url; Utils::FilePath privateKeyFile; QString x11DisplayName; int timeout = 0; // In seconds. @@ -47,10 +46,15 @@ public: SshHostKeyCheckingMode hostKeyCheckingMode = SshHostKeyCheckingAllowNoMatch; static bool setupSshEnvironment(Utils::QtcProcess *process); -}; -PROJECTEXPLORER_EXPORT bool operator==(const SshParameters &p1, const SshParameters &p2); -PROJECTEXPLORER_EXPORT bool operator!=(const SshParameters &p1, const SshParameters &p2); + friend PROJECTEXPLORER_EXPORT bool operator==(const SshParameters &p1, const SshParameters &p2); + friend bool operator!=(const SshParameters &p1, const SshParameters &p2) { return !(p1 == p2); } + +private: + QString m_host; + quint16 m_port = 0; + QString m_userName; +}; #ifdef WITH_TESTS namespace SshTest { diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp index 89e4c2e4838..24ac00bfd00 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp @@ -97,7 +97,9 @@ bool GenericLinuxDeviceConfigurationWizardSetupPage::validatePage() { d->device->setDisplayName(configurationName()); SshParameters sshParams = d->device->sshParameters(); - sshParams.url = url(); + sshParams.setHost(d->hostNameLineEdit->text().trimmed()); + sshParams.setUserName(d->userNameLineEdit->text().trimmed()); + sshParams.setPort(d->sshPortSpinBox->value()); d->device->setSshParameters(sshParams); return true; } @@ -107,15 +109,6 @@ QString GenericLinuxDeviceConfigurationWizardSetupPage::configurationName() cons return d->nameLineEdit->text().trimmed(); } -QUrl GenericLinuxDeviceConfigurationWizardSetupPage::url() const -{ - QUrl url; - url.setHost(d->hostNameLineEdit->text().trimmed()); - url.setUserName(d->userNameLineEdit->text().trimmed()); - url.setPort(d->sshPortSpinBox->value()); - return url; -} - void GenericLinuxDeviceConfigurationWizardSetupPage::setDevice(const LinuxDevice::Ptr &device) { d->device = device; diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h index 55388f48147..2e2d5298913 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.h @@ -32,7 +32,6 @@ private: bool validatePage() override; QString configurationName() const; - QUrl url() const; Internal::GenericLinuxDeviceConfigurationWizardSetupPagePrivate * const d; }; From 44655995d124a34db64b32d2d21f87f0fe387527 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 17 Mar 2023 11:12:26 +0100 Subject: [PATCH 0306/1447] FilePath: Provide overloads for async tasks taking context object Change-Id: I0bb2f2bfc0f54e8a81efb7d9279d539bcdfd9bc9 Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 17 +++++++++++++++++ src/libs/utils/filepath.h | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 12796afec9f..6e6ffe16fb5 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -642,16 +642,33 @@ FileStreamHandle FilePath::asyncCopy(const FilePath &target, const CopyContinuat return FileStreamerManager::copy(*this, target, cont); } +FileStreamHandle FilePath::asyncCopy(const FilePath &target, QObject *context, + const CopyContinuation &cont) const +{ + return FileStreamerManager::copy(*this, target, context, cont); +} + FileStreamHandle FilePath::asyncRead(const ReadContinuation &cont) const { return FileStreamerManager::read(*this, cont); } +FileStreamHandle FilePath::asyncRead(QObject *context, const ReadContinuation &cont) const +{ + return FileStreamerManager::read(*this, context, cont); +} + FileStreamHandle FilePath::asyncWrite(const QByteArray &data, const WriteContinuation &cont) const { return FileStreamerManager::write(*this, data, cont); } +FileStreamHandle FilePath::asyncWrite(const QByteArray &data, QObject *context, + const WriteContinuation &cont) const +{ + return FileStreamerManager::write(*this, data, context, cont); +} + bool FilePath::needsDevice() const { return m_schemeLen != 0; diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 11fd8e10e21..ee173615700 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -211,8 +211,13 @@ public: // Asynchronous interface FileStreamHandle asyncCopy(const FilePath &target, const CopyContinuation &cont = {}) const; + FileStreamHandle asyncCopy(const FilePath &target, QObject *context, + const CopyContinuation &cont = {}) const; FileStreamHandle asyncRead(const ReadContinuation &cont = {}) const; + FileStreamHandle asyncRead(QObject *context, const ReadContinuation &cont = {}) const; FileStreamHandle asyncWrite(const QByteArray &data, const WriteContinuation &cont = {}) const; + FileStreamHandle asyncWrite(const QByteArray &data, QObject *context, + const WriteContinuation &cont = {}) const; // Prefer not to use // Using needsDevice() in "user" code is likely to result in code that From dea3ea226235251ebe7a4fa9616fd7f9ee2d2ebc Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 25 Jan 2023 15:00:25 +0100 Subject: [PATCH 0307/1447] Python: remove unused function Change-Id: Iceee91f761e080dcdd329375638f883261c0a319 Reviewed-by: Christian Stenger --- src/plugins/python/pyside.cpp | 9 --------- src/plugins/python/pyside.h | 1 - 2 files changed, 10 deletions(-) diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index f16e81af939..f994108cae0 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -92,15 +92,6 @@ void PySideInstaller::installPyside(const FilePath &python, install->run(); } -void PySideInstaller::changeInterpreter(const QString &interpreterId, - RunConfiguration *runConfig) -{ - if (runConfig) { - if (auto aspect = runConfig->aspect()) - aspect->setCurrentInterpreter(PythonSettings::interpreter(interpreterId)); - } -} - void PySideInstaller::handlePySideMissing(const FilePath &python, const QString &pySide, TextEditor::TextDocument *document) diff --git a/src/plugins/python/pyside.h b/src/plugins/python/pyside.h index 299a095412a..3b4f99974a5 100644 --- a/src/plugins/python/pyside.h +++ b/src/plugins/python/pyside.h @@ -30,7 +30,6 @@ private: void installPyside(const Utils::FilePath &python, const QString &pySide, TextEditor::TextDocument *document); - void changeInterpreter(const QString &interpreterId, ProjectExplorer::RunConfiguration *runConfig); void handlePySideMissing(const Utils::FilePath &python, const QString &pySide, TextEditor::TextDocument *document); From 024897521c7bd0de1e9c7395d95f8851fb1545e1 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Mar 2023 10:30:46 +0100 Subject: [PATCH 0308/1447] RemoteLinux: Disable sourcing /etc/profile and ~/.profile by default [ChangeLog][RemoteLinux] Target-side shell profiles are not sourced by default anymore. Change-Id: Ide5029d02a0d149c4e532ee523f1dd49e7080c7b Reviewed-by: hjk --- .../genericlinuxdeviceconfigurationwidget.cpp | 15 ++++++++++++++- .../genericlinuxdeviceconfigurationwidget.h | 2 ++ src/plugins/remotelinux/linuxdevice.cpp | 8 +++++++- src/plugins/remotelinux/remotelinux_constants.h | 1 + src/plugins/remotelinux/sshprocessinterface.h | 4 ++++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index 23534a902fc..fb4ef53579f 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -3,6 +3,7 @@ #include "genericlinuxdeviceconfigurationwidget.h" +#include "remotelinux_constants.h" #include "remotelinuxtr.h" #include "sshkeycreationdialog.h" @@ -80,6 +81,9 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_qmlRuntimeLineEdit->setPlaceholderText(hint); m_qmlRuntimeLineEdit->setToolTip(hint); + m_sourceProfileCheckBox = + new QCheckBox(Tr::tr("Source %1 and %2").arg("/etc/profile").arg("$HOME/.profile")); + auto sshPortLabel = new QLabel(Tr::tr("&SSH port:")); sshPortLabel->setBuddy(m_sshPortSpinBox); @@ -93,7 +97,8 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( Tr::tr("&Username:"), m_userLineEdit, st, br, m_keyLabel, m_keyFileLineEdit, createKeyButton, br, Tr::tr("GDB server executable:"), m_gdbServerLineEdit, br, - Tr::tr("QML runtime executable:"), m_qmlRuntimeLineEdit, br + Tr::tr("QML runtime executable:"), m_qmlRuntimeLineEdit, br, + QString(), m_sourceProfileCheckBox, br }.attachTo(this); connect(m_hostLineEdit, &QLineEdit::editingFinished, @@ -124,6 +129,8 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( this, &GenericLinuxDeviceConfigurationWidget::qmlRuntimeEditingFinished); connect(m_hostKeyCheckBox, &QCheckBox::toggled, this, &GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged); + connect(m_sourceProfileCheckBox, &QCheckBox::toggled, + this, &GenericLinuxDeviceConfigurationWidget::sourceProfileCheckingChanged); initGui(); } @@ -214,6 +221,11 @@ void GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged(bool doCheck) device()->setSshParameters(sshParams); } +void GenericLinuxDeviceConfigurationWidget::sourceProfileCheckingChanged(bool doCheck) +{ + device()->setExtraData(Constants::SourceProfile, doCheck); +} + void GenericLinuxDeviceConfigurationWidget::updateDeviceFromUi() { hostNameEditingFinished(); @@ -260,6 +272,7 @@ void GenericLinuxDeviceConfigurationWidget::initGui() m_hostLineEdit->setEnabled(!device()->isAutoDetected()); m_sshPortSpinBox->setEnabled(!device()->isAutoDetected()); m_hostKeyCheckBox->setChecked(sshParams.hostKeyCheckingMode != SshHostKeyCheckingNone); + m_sourceProfileCheckBox->setChecked(device()->extraData(Constants::SourceProfile).toBool()); m_hostLineEdit->setText(sshParams.host()); m_sshPortSpinBox->setValue(sshParams.port()); diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h index 4e00cedcb62..024656d1fa0 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h @@ -42,6 +42,7 @@ private: void setPrivateKey(const Utils::FilePath &path); void createNewKey(); void hostKeyCheckingChanged(bool doCheck); + void sourceProfileCheckingChanged(bool doCheck); void updateDeviceFromUi() override; void updatePortsWarningLabel(); @@ -61,6 +62,7 @@ private: QLabel *m_machineTypeValueLabel; Utils::PathChooser *m_gdbServerLineEdit; Utils::PathChooser *m_qmlRuntimeLineEdit; + QCheckBox *m_sourceProfileCheckBox; }; } // RemoteLinux::Internal diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 55a0238d938..2ed875b07a8 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -464,6 +464,11 @@ bool SshProcessInterface::runInShell(const CommandLine &command, const QByteArra return isFinished; } +IDevice::ConstPtr SshProcessInterface::device() const +{ + return d->m_device; +} + void SshProcessInterface::start() { d->start(); @@ -520,7 +525,7 @@ QString LinuxProcessInterface::fullCommandLine(const CommandLine &commandLine) c { CommandLine cmd; - if (!commandLine.isEmpty()) { + if (!commandLine.isEmpty() && device()->extraData(Constants::SourceProfile).toBool()) { const QStringList rcFilesToSource = {"/etc/profile", "$HOME/.profile"}; for (const QString &filePath : rcFilesToSource) { cmd.addArgs({"test", "-f", filePath}); @@ -730,6 +735,7 @@ void SshProcessInterfacePrivate::doStart() env.set("DISPLAY", m_sshParameters.x11DisplayName); m_process.setControlEnvironment(env); } + m_process.setExtraData(q->m_setup.m_extraData); m_process.setCommand(fullLocalCommandLine()); m_process.start(); } diff --git a/src/plugins/remotelinux/remotelinux_constants.h b/src/plugins/remotelinux/remotelinux_constants.h index 31a97588281..a7ad8de6989 100644 --- a/src/plugins/remotelinux/remotelinux_constants.h +++ b/src/plugins/remotelinux/remotelinux_constants.h @@ -20,6 +20,7 @@ const char CustomCommandDeployStepId[] = "RemoteLinux.GenericRemoteLinuxCustomCo const char KillAppStepId[] = "RemoteLinux.KillAppStep"; const char SupportsRSync[] = "RemoteLinux.SupportsRSync"; +const char SourceProfile[] = "RemoteLinux.SourceProfile"; const char RunConfigId[] = "RemoteLinuxRunConfiguration:"; const char CustomRunConfigId[] = "RemoteLinux.CustomRunConfig"; diff --git a/src/plugins/remotelinux/sshprocessinterface.h b/src/plugins/remotelinux/sshprocessinterface.h index 9d67d6a4e67..bd896a0a4b3 100644 --- a/src/plugins/remotelinux/sshprocessinterface.h +++ b/src/plugins/remotelinux/sshprocessinterface.h @@ -5,6 +5,8 @@ #include "remotelinux_export.h" +#include + #include namespace RemoteLinux { @@ -26,6 +28,8 @@ protected: qint64 processId() const; bool runInShell(const Utils::CommandLine &command, const QByteArray &data = {}); + ProjectExplorer::IDevice::ConstPtr device() const; + private: virtual void handleStarted(qint64 processId); virtual void handleDone(const Utils::ProcessResultData &resultData); From 13bf47c875e88f2eaaa1a6a82c180ab7c9aef58a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 17 Mar 2023 13:37:39 +0100 Subject: [PATCH 0309/1447] Tests: Add another environment test Test appending and prepending PATH. Change-Id: If2ff84b24a8f961af0a3bb64ed77aaf37fe247fd Reviewed-by: hjk Reviewed-by: Qt CI Bot --- tests/auto/environment/tst_environment.cpp | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/auto/environment/tst_environment.cpp b/tests/auto/environment/tst_environment.cpp index 85ade0fe1df..8aa0cbe063a 100644 --- a/tests/auto/environment/tst_environment.cpp +++ b/tests/auto/environment/tst_environment.cpp @@ -40,6 +40,9 @@ private slots: void incrementalChanges(); + void pathChanges_data(); + void pathChanges(); + void find_data(); void find(); @@ -296,6 +299,82 @@ void tst_Environment::incrementalChanges() reverseDiff); } +void tst_Environment::pathChanges_data() +{ + const Environment origEnvLinux({"PATH=/bin:/usr/bin", "VAR=VALUE"}, OsTypeLinux); + const Environment origEnvWin({"PATH=C:\\Windows\\System32;D:\\gnu\\bin", "VAR=VALUE"}, OsTypeWindows); + + QTest::addColumn("environment"); + QTest::addColumn("prepend"); // if false => append + QTest::addColumn("variable"); + QTest::addColumn("value"); + QTest::addColumn("expected"); + + QTest::newRow("appendOrSetPath existingLeading Unix") + << origEnvLinux << false << "PATH" << "/bin" + << Environment({"PATH=/bin:/usr/bin:/bin", "VAR=VALUE"}, OsTypeLinux); + QTest::newRow("appendOrSetPath existingLeading Win") + << origEnvWin << false << "PATH" << "C:\\Windows\\System32" + << Environment({"PATH=C:\\Windows\\System32;D:\\gnu\\bin;C:\\Windows\\System32", + "VAR=VALUE"}, OsTypeWindows); + QTest::newRow("appendOrSetPath existingTrailing Unix") + << origEnvLinux << false << "PATH" << "/usr/bin" + << Environment({"PATH=/bin:/usr/bin", "VAR=VALUE"}, OsTypeLinux); + QTest::newRow("appendOrSetPath existingTrailing Win") + << origEnvWin << false << "PATH" << "D:\\gnu\\bin" + << Environment({"PATH=C:\\Windows\\System32;D:\\gnu\\bin", + "VAR=VALUE"}, OsTypeWindows); + QTest::newRow("prependOrSetPath existingLeading Unix") + << origEnvLinux << true << "PATH" << "/bin" + << Environment({"PATH=/bin:/usr/bin", "VAR=VALUE"}, OsTypeLinux); + QTest::newRow("prependOrSetPath existingLeading Win") + << origEnvWin << true << "PATH" << "C:\\Windows\\System32" + << Environment({"PATH=C:\\Windows\\System32;D:\\gnu\\bin", + "VAR=VALUE"}, OsTypeWindows); + QTest::newRow("prependOrSetPath existingTrailing Unix") + << origEnvLinux << true << "PATH" << "/usr/bin" + << Environment({"PATH=/usr/bin:/bin:/usr/bin", "VAR=VALUE"}, OsTypeLinux); + QTest::newRow("prependOrSetPath existingTrailing Win") + << origEnvWin << true << "PATH" << "D:\\gnu\\bin" + << Environment({"PATH=D:\\gnu\\bin;C:\\Windows\\System32;D:\\gnu\\bin", + "VAR=VALUE"}, OsTypeWindows); + + QTest::newRow("appendOrSetPath non-existing Unix") + << origEnvLinux << false << "PATH" << "/opt" + << Environment({"PATH=/bin:/usr/bin:/opt", "VAR=VALUE"}, OsTypeLinux); + QTest::newRow("appendOrSetPath non-existing Win") + << origEnvWin << false << "PATH" << "C:\\Windows" + << Environment({"PATH=C:\\Windows\\System32;D:\\gnu\\bin;C:\\Windows", + "VAR=VALUE"}, OsTypeWindows); + QTest::newRow("prependOrSetPath non-existing half-matching Unix") + << origEnvLinux << true << "PATH" << "/bi" + << Environment({"PATH=/bi:/bin:/usr/bin", "VAR=VALUE"}, OsTypeLinux); + QTest::newRow("prependOrSetPath non-existing half-matching Win") + << origEnvWin << true << "PATH" << "C:\\Windows" + << Environment({"PATH=C:\\Windows;C:\\Windows\\System32;D:\\gnu\\bin", + "VAR=VALUE"}, OsTypeWindows); +} + +void tst_Environment::pathChanges() +{ + QFETCH(Environment, environment); + QFETCH(bool, prepend); + QFETCH(QString, variable); + QFETCH(QString, value); + QFETCH(Environment, expected); + + const QString sep = environment.osType() == OsTypeWindows ? ";" : ":"; + + if (prepend) + environment.prependOrSet(variable, value, sep); + else + environment.appendOrSet(variable, value, sep); + + qDebug() << "Actual :" << environment.toStringList(); + qDebug() << "Expected:" << expected.toStringList(); + QCOMPARE(environment, expected); +} + void tst_Environment::find_data() { QTest::addColumn("osType"); From 81bd8e3bd89712fad41077f7ee0a67326b0ba4f2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 17 Mar 2023 11:17:51 +0100 Subject: [PATCH 0310/1447] FilePath: Remove overloads for async tasks that don't take context Passing mandatory context object clearly suggests a special care should be taken for assuring the passed function may still run when the task finishes in the future. Fix FileStreamManager so that it deletes the streamer even when context object was deleted in meantime. Fix 2 usages of asyncCopy so that we pass a context object now. Side note: passing nullptr as a context object is still possible and should work, but it's not recommended. Change-Id: I464438db42ed9292c2f89ecb9d5dde7c78f77640 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 15 --------------- src/libs/utils/filepath.h | 3 --- src/libs/utils/filestreamermanager.cpp | 9 +++++---- src/plugins/projectexplorer/copystep.cpp | 2 +- tests/auto/utils/filepath/tst_filepath.cpp | 4 +++- 5 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 6e6ffe16fb5..f117f4e8687 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -637,32 +637,17 @@ FilePathInfo FilePath::filePathInfo() const return fileAccess()->filePathInfo(*this); } -FileStreamHandle FilePath::asyncCopy(const FilePath &target, const CopyContinuation &cont) const -{ - return FileStreamerManager::copy(*this, target, cont); -} - FileStreamHandle FilePath::asyncCopy(const FilePath &target, QObject *context, const CopyContinuation &cont) const { return FileStreamerManager::copy(*this, target, context, cont); } -FileStreamHandle FilePath::asyncRead(const ReadContinuation &cont) const -{ - return FileStreamerManager::read(*this, cont); -} - FileStreamHandle FilePath::asyncRead(QObject *context, const ReadContinuation &cont) const { return FileStreamerManager::read(*this, context, cont); } -FileStreamHandle FilePath::asyncWrite(const QByteArray &data, const WriteContinuation &cont) const -{ - return FileStreamerManager::write(*this, data, cont); -} - FileStreamHandle FilePath::asyncWrite(const QByteArray &data, QObject *context, const WriteContinuation &cont) const { diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index ee173615700..877e8beb8e9 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -210,12 +210,9 @@ public: static void sort(FilePaths &files); // Asynchronous interface - FileStreamHandle asyncCopy(const FilePath &target, const CopyContinuation &cont = {}) const; FileStreamHandle asyncCopy(const FilePath &target, QObject *context, const CopyContinuation &cont = {}) const; - FileStreamHandle asyncRead(const ReadContinuation &cont = {}) const; FileStreamHandle asyncRead(QObject *context, const ReadContinuation &cont = {}) const; - FileStreamHandle asyncWrite(const QByteArray &data, const WriteContinuation &cont = {}) const; FileStreamHandle asyncWrite(const QByteArray &data, QObject *context, const WriteContinuation &cont = {}) const; diff --git a/src/libs/utils/filestreamermanager.cpp b/src/libs/utils/filestreamermanager.cpp index 051f114578a..11d05faee57 100644 --- a/src/libs/utils/filestreamermanager.cpp +++ b/src/libs/utils/filestreamermanager.cpp @@ -99,10 +99,11 @@ FileStreamHandle execute(const std::function &onSetup, onSetup(streamer); const FileStreamHandle handle = generateUniqueHandle(); QTC_CHECK(context == nullptr || context->thread() == QThread::currentThread()); - QObject *finalContext = context ? context : streamer; - QObject::connect(streamer, &FileStreamer::done, finalContext, [=] { - if (onDone) - onDone(streamer); + if (onDone) { + QObject *finalContext = context ? context : streamer; + QObject::connect(streamer, &FileStreamer::done, finalContext, [=] { onDone(streamer); }); + } + QObject::connect(streamer, &FileStreamer::done, streamer, [=] { removeStreamer(handle); streamer->deleteLater(); }); diff --git a/src/plugins/projectexplorer/copystep.cpp b/src/plugins/projectexplorer/copystep.cpp index b07c28b3cfd..e2b478a237a 100644 --- a/src/plugins/projectexplorer/copystep.cpp +++ b/src/plugins/projectexplorer/copystep.cpp @@ -45,7 +45,7 @@ protected: { // FIXME: asyncCopy does not handle directories yet. QTC_ASSERT(m_source.isFile(), emit finished(false)); - m_source.asyncCopy(m_target, [this](const expected_str &cont) { + m_source.asyncCopy(m_target, this, [this](const expected_str &cont) { if (!cont) { addOutput(cont.error(), OutputFormat::ErrorMessage); addOutput(Tr::tr("Copying failed"), OutputFormat::ErrorMessage); diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index b2bd5d11bb8..fa586ad5bcd 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -1300,6 +1300,8 @@ void tst_filepath::asyncLocalCopy() QVERIFY(orig.exists()); const FilePath dest = FilePath::fromString(rootPath).pathAppended("x/fileToCopyDest.txt"); bool wasCalled = false; + // When QTRY_VERIFY failed, don't call the continuation after we leave this method + QObject context; auto afterCopy = [&orig, &dest, &wasCalled](expected_str result) { QVERIFY(result); // check existence, size and content @@ -1308,7 +1310,7 @@ void tst_filepath::asyncLocalCopy() QCOMPARE(dest.fileContents(), orig.fileContents()); wasCalled = true; }; - orig.asyncCopy(dest, afterCopy); + orig.asyncCopy(dest, &context, afterCopy); QTRY_VERIFY(wasCalled); } From 59724524841a796814c4ec76cb1aea9cd74905c5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 17 Mar 2023 11:01:49 +0100 Subject: [PATCH 0311/1447] Terminal: Support clipboard selection Change-Id: Ief59f9e21782e0dd0292f3625e35c1742cf9b3bc Reviewed-by: hjk --- src/plugins/terminal/terminalwidget.cpp | 120 ++++++++++++++---------- src/plugins/terminal/terminalwidget.h | 5 +- 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index b168320dce5..6521291d4ca 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -273,10 +273,8 @@ void TerminalWidget::setupSurface() &Internal::TerminalSurface::invalidated, this, [this](const QRect &rect) { - if (setSelection(std::nullopt)) - updateViewport(); - else - updateViewport(gridToViewport(rect)); + setSelection(std::nullopt); + updateViewport(gridToViewport(rect)); }); connect(m_surface.get(), &Internal::TerminalSurface::cursorChanged, @@ -300,8 +298,8 @@ void TerminalWidget::setupSurface() }); connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] { updateScrollBars(); - updateViewport(); - setSelection(std::nullopt); + if (!setSelection(std::nullopt)) + updateViewport(); }); connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] { verticalScrollBar()->setValue(verticalScrollBar()->maximum()); @@ -385,21 +383,7 @@ QAction &TerminalWidget::zoomOutAction() void TerminalWidget::copyToClipboard() const { - if (!m_selection) - return; - - Internal::CellIterator it = m_surface->iteratorAt(m_selection->start); - Internal::CellIterator end = m_surface->iteratorAt(m_selection->end); - - std::u32string s; - for (; it != end; ++it) { - if (it.gridPos().x() == 0 && !s.empty()) - s += U'\n'; - if (*it != 0) - s += *it; - } - - const QString text = QString::fromUcs4(s.data(), static_cast(s.size())); + QString text = textFromSelection(); qCDebug(selectionLog) << "Copied to clipboard: " << text; @@ -420,7 +404,6 @@ void TerminalWidget::pasteFromClipboard() void TerminalWidget::clearSelection() { setSelection(std::nullopt); - updateViewport(); m_surface->sendKey(Qt::Key_Escape); } @@ -472,19 +455,59 @@ void TerminalWidget::flushVTerm(bool force) } } +QString TerminalWidget::textFromSelection() const +{ + if (!m_selection) + return {}; + + Internal::CellIterator it = m_surface->iteratorAt(m_selection->start); + Internal::CellIterator end = m_surface->iteratorAt(m_selection->end); + + std::u32string s; + for (; it != end; ++it) { + if (it.gridPos().x() == 0 && !s.empty()) + s += U'\n'; + if (*it != 0) + s += *it; + } + + return QString::fromUcs4(s.data(), static_cast(s.size())); +} + bool TerminalWidget::setSelection(const std::optional &selection) { - if (selection.has_value() != m_selection.has_value()) { - qCDebug(selectionLog) << "Copy enabled:" << selection.has_value(); - m_copyAction.setEnabled(selection.has_value()); + if (selectionLog().isDebugEnabled()) + updateViewport(); + + if (selection == m_selection) { + return false; } - if (selection.has_value() && m_selection.has_value()) { - if (*selection == *m_selection) - return false; - } + /*if (m_selection && m_selection->final) { + QClipboard *clipboard = QApplication::clipboard(); + if (clipboard->supportsSelection()) { + qCDebug(selectionLog) << "Clearing selection from clipboard"; + clipboard->clear(QClipboard::Selection); + } + }*/ m_selection = selection; + + if (m_selection && m_selection->final) { + qCDebug(selectionLog) << "Copy enabled:" << selection.has_value(); + m_copyAction.setEnabled(selection.has_value()); + + QClipboard *clipboard = QApplication::clipboard(); + if (clipboard->supportsSelection()) { + QString text = textFromSelection(); + qCDebug(selectionLog) << "Selection set to clipboard: " << text; + clipboard->setText(text, QClipboard::Selection); + } + } + + if (!selectionLog().isDebugEnabled()) + updateViewport(); + return true; } @@ -922,8 +945,7 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) } if (actionTriggered) { - if (setSelection(std::nullopt)) - updateViewport(); + setSelection(std::nullopt); return; } @@ -1053,14 +1075,17 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) if (event->button() == Qt::LeftButton) { if (std::chrono::system_clock::now() - m_lastDoubleClick < 500ms) { m_selectLineMode = true; - m_selection->start = m_surface->gridToPos( - {0, m_surface->posToGrid(m_selection->start).y()}); - m_selection->end = m_surface->gridToPos( - {m_surface->liveSize().width(), m_surface->posToGrid(m_selection->end).y()}); + const Selection newSelection{m_surface->gridToPos( + {0, m_surface->posToGrid(m_selection->start).y()}), + m_surface->gridToPos( + {m_surface->liveSize().width(), + m_surface->posToGrid(m_selection->end).y()}), + false}; + setSelection(newSelection); } else { m_selectLineMode = false; int pos = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos()))); - setSelection(Selection{pos, pos}); + setSelection(Selection{pos, pos, false}); } event->accept(); updateViewport(); @@ -1068,7 +1093,6 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) if (m_selection) { m_copyAction.trigger(); setSelection(std::nullopt); - updateViewport(); } else { m_pasteAction.trigger(); } @@ -1077,7 +1101,7 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) void TerminalWidget::mouseMoveEvent(QMouseEvent *event) { if (m_selection && event->buttons() & Qt::LeftButton) { - const auto old = m_selection; + Selection newSelection = *m_selection; int scrollVelocity = 0; if (event->pos().y() < 0) { scrollVelocity = (event->pos().y()); @@ -1110,16 +1134,15 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) start = 0; if (m_selectLineMode) { - m_selection->start = m_surface->gridToPos({0, m_surface->posToGrid(start).y()}); - m_selection->end = m_surface->gridToPos( + newSelection.start = m_surface->gridToPos({0, m_surface->posToGrid(start).y()}); + newSelection.end = m_surface->gridToPos( {m_surface->liveSize().width(), m_surface->posToGrid(newEnd).y()}); } else { - m_selection->start = start; - m_selection->end = newEnd; + newSelection.start = start; + newSelection.end = newEnd; } - if (old != *m_selection || selectionLog().isDebugEnabled()) - updateViewport(); + setSelection(newSelection); } else if (event->modifiers() == Qt::ControlModifier) { checkLinkAt(event->pos()); } else if (m_linkSelection) { @@ -1171,10 +1194,10 @@ void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) m_scrollTimer.stop(); if (m_selection && event->button() == Qt::LeftButton) { - if (m_selection->end - m_selection->start == 0) { + if (m_selection->end - m_selection->start == 0) setSelection(std::nullopt); - updateViewport(); - } + else + setSelection(Selection{m_selection->start, m_selection->end, true}); } } @@ -1208,11 +1231,10 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) { const auto hit = textAt(event->pos()); - setSelection(Selection{hit.start, hit.end}); + setSelection(Selection{hit.start, hit.end, true}); m_lastDoubleClick = std::chrono::system_clock::now(); - updateViewport(); event->accept(); } diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 60cff4183fd..4c862835f7f 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -51,10 +51,11 @@ public: { int start; int end; + bool final{false}; bool operator!=(const Selection &other) const { - return start != other.start || end != other.end; + return start != other.start || end != other.end || final != other.final; } bool operator==(const Selection &other) const { return !operator!=(other); } @@ -151,12 +152,12 @@ protected: TextAndOffsets textAt(const QPoint &pos) const; void applySizeChange(); - void updateScrollBars(); void flushVTerm(bool force); bool setSelection(const std::optional &selection); + QString textFromSelection() const; void configBlinkTimer(); From 2d2eef1c2cd3e55e8d1c37b0dff739f29d06f5ca Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 20 Mar 2023 10:21:21 +0100 Subject: [PATCH 0312/1447] Terminal: Fix "Enter does not work after copy" Change-Id: Ic541ba15f52084bcd9b955af718efc3defc64539 Reviewed-by: Christian Stenger --- src/plugins/terminal/terminalwidget.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 6521291d4ca..a684d5470d5 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -483,19 +483,12 @@ bool TerminalWidget::setSelection(const std::optional &selection) return false; } - /*if (m_selection && m_selection->final) { - QClipboard *clipboard = QApplication::clipboard(); - if (clipboard->supportsSelection()) { - qCDebug(selectionLog) << "Clearing selection from clipboard"; - clipboard->clear(QClipboard::Selection); - } - }*/ + m_copyAction.setEnabled(selection.has_value()); m_selection = selection; if (m_selection && m_selection->final) { qCDebug(selectionLog) << "Copy enabled:" << selection.has_value(); - m_copyAction.setEnabled(selection.has_value()); QClipboard *clipboard = QApplication::clipboard(); if (clipboard->supportsSelection()) { From 0870f2583bbc659df00ff65bf51918b940221665 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 7 Mar 2023 17:55:38 +0100 Subject: [PATCH 0313/1447] Terminal: Enable TerminalProcessInterface Adds a new helper app "process_stub" that replaces the previous. "process_stub_unix/win". The purpose was and is to allow processes to be "injected" into other hosts apps like terminals while still being able to control and debug them. A new base class called "TerminalInterface" is used for both the new Terminal plugin and the legacy TerminalProcess implementation. Fixes: QTCREATORBUG-16364 Change-Id: If21273fe53ad545d1a768c17c83db4bf2fd85395 Reviewed-by: Christian Stenger Reviewed-by: Jarek Kobus Reviewed-by: hjk --- src/libs/3rdparty/libptyqt/.clang-format | 1 + src/libs/3rdparty/libptyqt/conptyprocess.h | 8 +- src/libs/libs.qbs | 1 - src/libs/utils/CMakeLists.txt | 20 +- src/libs/utils/process_stub.qbs | 21 - src/libs/utils/process_stub_unix.c | 340 --------- src/libs/utils/process_stub_win.c | 204 ----- src/libs/utils/processenums.h | 1 - src/libs/utils/qtcprocess.cpp | 2 +- src/libs/utils/terminalhooks.cpp | 66 +- src/libs/utils/terminalhooks.h | 2 + src/libs/utils/terminalinterface.cpp | 400 ++++++++++ src/libs/utils/terminalinterface.h | 61 ++ src/libs/utils/terminalprocess.cpp | 721 ------------------ src/libs/utils/terminalprocess_p.h | 54 -- src/libs/utils/utils.qbs | 4 +- src/plugins/debugger/gdb/gdbengine.cpp | 23 +- src/plugins/debugger/terminal.cpp | 3 +- src/plugins/terminal/CMakeLists.txt | 2 +- src/plugins/terminal/terminal.qbs | 4 +- src/plugins/terminal/terminalpane.cpp | 31 +- src/plugins/terminal/terminalpane.h | 4 +- src/plugins/terminal/terminalplugin.cpp | 8 +- src/plugins/terminal/terminalprocessimpl.cpp | 67 ++ src/plugins/terminal/terminalprocessimpl.h | 18 + .../terminal/terminalprocessinterface.cpp | 47 -- .../terminal/terminalprocessinterface.h | 49 -- src/plugins/terminal/terminalwidget.cpp | 44 +- src/plugins/terminal/terminalwidget.h | 6 + src/tools/CMakeLists.txt | 2 + src/tools/process_stub/CMakeLists.txt | 12 + src/tools/process_stub/main.cpp | 541 +++++++++++++ src/tools/process_stub/process_stub.qbs | 10 + src/tools/tools.qbs | 1 + 34 files changed, 1276 insertions(+), 1502 deletions(-) create mode 100644 src/libs/3rdparty/libptyqt/.clang-format delete mode 100644 src/libs/utils/process_stub.qbs delete mode 100644 src/libs/utils/process_stub_unix.c delete mode 100644 src/libs/utils/process_stub_win.c create mode 100644 src/libs/utils/terminalinterface.cpp create mode 100644 src/libs/utils/terminalinterface.h delete mode 100644 src/libs/utils/terminalprocess.cpp delete mode 100644 src/libs/utils/terminalprocess_p.h create mode 100644 src/plugins/terminal/terminalprocessimpl.cpp create mode 100644 src/plugins/terminal/terminalprocessimpl.h delete mode 100644 src/plugins/terminal/terminalprocessinterface.cpp delete mode 100644 src/plugins/terminal/terminalprocessinterface.h create mode 100644 src/tools/process_stub/CMakeLists.txt create mode 100644 src/tools/process_stub/main.cpp create mode 100644 src/tools/process_stub/process_stub.qbs diff --git a/src/libs/3rdparty/libptyqt/.clang-format b/src/libs/3rdparty/libptyqt/.clang-format new file mode 100644 index 00000000000..b861ff7a951 --- /dev/null +++ b/src/libs/3rdparty/libptyqt/.clang-format @@ -0,0 +1 @@ +{ "DisableFormat" : true } \ No newline at end of file diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.h b/src/libs/3rdparty/libptyqt/conptyprocess.h index a22b6290c77..ac940489816 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.h +++ b/src/libs/3rdparty/libptyqt/conptyprocess.h @@ -154,15 +154,15 @@ private: private: WindowsContext m_winContext; - HPCON m_ptyHandler; - HANDLE m_hPipeIn, m_hPipeOut; + HPCON m_ptyHandler{INVALID_HANDLE_VALUE}; + HANDLE m_hPipeIn{INVALID_HANDLE_VALUE}, m_hPipeOut{INVALID_HANDLE_VALUE}; - QThread *m_readThread; + QThread *m_readThread{nullptr}; QMutex m_bufferMutex; PtyBuffer m_buffer; bool m_aboutToDestruct{false}; PROCESS_INFORMATION m_shellProcessInformation{}; - QWinEventNotifier* m_shellCloseWaitNotifier; + QWinEventNotifier *m_shellCloseWaitNotifier{nullptr}; STARTUPINFOEX m_shellStartupInfo{}; }; diff --git a/src/libs/libs.qbs b/src/libs/libs.qbs index f9f58565ace..141e2a65475 100644 --- a/src/libs/libs.qbs +++ b/src/libs/libs.qbs @@ -21,7 +21,6 @@ Project { "qtcreatorcdbext/qtcreatorcdbext.qbs", "sqlite/sqlite.qbs", "tracing/tracing.qbs", - "utils/process_stub.qbs", "utils/process_ctrlc_stub.qbs", "utils/utils.qbs", "3rdparty/libptyqt/ptyqt.qbs", diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index e296f2857a3..ab55a0deecf 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -173,7 +173,7 @@ add_qtc_library(Utils temporaryfile.cpp temporaryfile.h terminalcommand.cpp terminalcommand.h terminalhooks.cpp terminalhooks.h - terminalprocess.cpp terminalprocess_p.h + terminalinterface.cpp terminalinterface.h textfieldcheckbox.cpp textfieldcheckbox.h textfieldcombobox.cpp textfieldcombobox.h textfileformat.cpp textfileformat.h @@ -271,21 +271,3 @@ extend_qtc_library(Utils fsengine/fsenginehandler.h fsengine/filepathinfocache.h ) - -if (WIN32) - add_qtc_executable(qtcreator_process_stub - SOURCES process_stub_win.c - DEPENDS shell32 - DEFINES _UNICODE UNICODE _CRT_SECURE_NO_WARNINGS - ) - - add_qtc_executable(qtcreator_ctrlc_stub - DEPENDS user32 shell32 - DEFINES _UNICODE UNICODE _CRT_SECURE_NO_WARNINGS - SOURCES - process_ctrlc_stub.cpp - ) -else() - add_qtc_executable(qtcreator_process_stub SOURCES process_stub_unix.c) -endif() - diff --git a/src/libs/utils/process_stub.qbs b/src/libs/utils/process_stub.qbs deleted file mode 100644 index 341fb57791b..00000000000 --- a/src/libs/utils/process_stub.qbs +++ /dev/null @@ -1,21 +0,0 @@ -import qbs 1.0 - -QtcTool { - name: "qtcreator_process_stub" - consoleApplication: true - - - files: { - if (qbs.targetOS.contains("windows")) { - return [ "process_stub_win.c" ] - } else { - return [ "process_stub_unix.c" ] - } - } - - cpp.dynamicLibraries: { - if (qbs.targetOS.contains("windows")) { - return [ "shell32" ] - } - } -} diff --git a/src/libs/utils/process_stub_unix.c b/src/libs/utils/process_stub_unix.c deleted file mode 100644 index 716e88d1012..00000000000 --- a/src/libs/utils/process_stub_unix.c +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include - -// Enable compilation with older header that doesn't contain this constant -// for running on newer libraries that do support it -#ifndef PR_SET_PTRACER -#define PR_SET_PTRACER 0x59616d61 -#endif -#endif - -/* For OpenBSD */ -#ifndef EPROTO -# define EPROTO EINVAL -#endif - -extern char **environ; - -static int qtcFd; -static char *sleepMsg; -static int chldPipe[2]; -static int blockingPipe[2]; -static int isDebug; -static volatile int isDetached; -static volatile int chldPid; - -static void __attribute__((noreturn)) doExit(int code) -{ - tcsetpgrp(0, getpid()); - puts(sleepMsg); - const char *rv = fgets(sleepMsg, 2, stdin); /* Minimal size to make it wait */ - (void)rv; // Q_UNUSED - exit(code); -} - -static void sendMsg(const char *msg, int num) -{ - int pidStrLen; - int ioRet; - char pidStr[64]; - - pidStrLen = sprintf(pidStr, msg, num); - if (!isDetached && (ioRet = write(qtcFd, pidStr, pidStrLen)) != pidStrLen) { - fprintf(stderr, "Cannot write to creator comm socket: %s\n", - (ioRet < 0) ? strerror(errno) : "short write"); - isDetached = 2; - } -} - -enum { - ArgCmd = 0, - ArgAction, - ArgSocket, - ArgMsg, - ArgDir, - ArgEnv, - ArgPid, - ArgExe -}; - -/* Handle sigchld */ -static void sigchldHandler(int sig) -{ - int chldStatus; - /* Currently we have only one child, so we exit in case of error. */ - int waitRes; - (void)sig; - for (;;) { - waitRes = waitpid(-1, &chldStatus, WNOHANG); - if (!waitRes) - break; - if (waitRes < 0) { - perror("Cannot obtain exit status of child process"); - doExit(3); - } - if (WIFSTOPPED(chldStatus)) { - /* The child stopped. This can be the result of the initial SIGSTOP handling. - * We won't need the notification pipe any more, as we know that - * the exec() succeeded. */ - close(chldPipe[0]); - close(chldPipe[1]); - chldPipe[0] = -1; - if (isDetached == 2 && isDebug) { - /* qtcreator was not informed and died while debugging, killing the child */ - kill(chldPid, SIGKILL); - } - } else if (WIFEXITED(chldStatus)) { - sendMsg("exit %d\n", WEXITSTATUS(chldStatus)); - doExit(0); - } else { - sendMsg("crash %d\n", WTERMSIG(chldStatus)); - doExit(0); - } - } -} - - -/* syntax: $0 {"run"|"debug"} */ -/* exit codes: 0 = ok, 1 = invocation error, 3 = internal error */ -int main(int argc, char *argv[]) -{ - int errNo, hadInvalidCommand = 0; - char **env = 0; - struct sockaddr_un sau; - struct sigaction act; - - memset(&act, 0, sizeof(act)); - - if (argc < ArgEnv) { - fprintf(stderr, "This is an internal helper of Qt Creator. Do not run it manually.\n"); - return 1; - } - sleepMsg = argv[ArgMsg]; - - /* Connect to the master, i.e. Creator. */ - if ((qtcFd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("Cannot create creator comm socket"); - doExit(3); - } - memset(&sau, 0, sizeof(sau)); - sau.sun_family = AF_UNIX; - strncpy(sau.sun_path, argv[ArgSocket], sizeof(sau.sun_path) - 1); - if (connect(qtcFd, (struct sockaddr *)&sau, sizeof(sau))) { - fprintf(stderr, "Cannot connect creator comm socket %s: %s\n", sau.sun_path, strerror(errno)); - doExit(1); - } - - isDebug = !strcmp(argv[ArgAction], "debug"); - isDetached = 0; - - if (*argv[ArgDir] && chdir(argv[ArgDir])) { - /* Only expected error: no such file or direcotry */ - sendMsg("err:chdir %d\n", errno); - return 1; - } - - if (*argv[ArgEnv]) { - FILE *envFd; - char *envdata, *edp, *termEnv; - long size; - int count; - if (!(envFd = fopen(argv[ArgEnv], "r"))) { - fprintf(stderr, "Cannot read creator env file %s: %s\n", - argv[ArgEnv], strerror(errno)); - doExit(1); - } - fseek(envFd, 0, SEEK_END); - size = ftell(envFd); - if (size < 0) { - perror("Failed to get size of env file"); - doExit(1); - } - rewind(envFd); - envdata = malloc(size + 1); - if (fread(envdata, 1, size, envFd) != (size_t)size) { - perror("Failed to read env file"); - doExit(1); - } - envdata[size] = '\0'; - fclose(envFd); - assert(!size || !envdata[size - 1]); - for (count = 0, edp = envdata; edp < envdata + size; ++count) - edp += strlen(edp) + 1; - env = malloc((count + 2) * sizeof(char *)); - for (count = 0, edp = envdata; edp < envdata + size; ++count) { - env[count] = edp; - edp += strlen(edp) + 1; - } - if ((termEnv = getenv("TERM"))) - env[count++] = termEnv - 5; - env[count] = 0; - } - - /* send our pid after we read the environment file (creator will get rid of it) */ - sendMsg("spid %ld\n", (long)getpid()); - - /* - * set up the signal handlers - */ - { - /* Ignore SIGTTOU. Without this, calling tcsetpgrp() from a background - * process group (in which we will be, once as child and once as parent) - * generates the mentioned signal and stops the concerned process. */ - act.sa_handler = SIG_IGN; - if (sigaction(SIGTTOU, &act, 0)) { - perror("sigaction SIGTTOU"); - doExit(3); - } - - /* Handle SIGCHLD to keep track of what the child does without blocking */ - act.sa_handler = sigchldHandler; - if (sigaction(SIGCHLD, &act, 0)) { - perror("sigaction SIGCHLD"); - doExit(3); - } - } - - /* Create execution result notification pipe. */ - if (pipe(chldPipe)) { - perror("Cannot create status pipe"); - doExit(3); - } - - /* The debugged program is not supposed to inherit these handles. But we cannot - * close the writing end before calling exec(). Just handle both ends the same way ... */ - fcntl(chldPipe[0], F_SETFD, FD_CLOEXEC); - fcntl(chldPipe[1], F_SETFD, FD_CLOEXEC); - - if (isDebug) { - /* Create execution start notification pipe. The child waits on this until - the parent writes to it, triggered by an 'c' message from Creator */ - if (pipe(blockingPipe)) { - perror("Cannot create blocking pipe"); - doExit(3); - } - } - - switch ((chldPid = fork())) { - case -1: - perror("Cannot fork child process"); - doExit(3); - case 0: - close(qtcFd); - - /* Remove the SIGCHLD handler from the child */ - act.sa_handler = SIG_DFL; - sigaction(SIGCHLD, &act, 0); - - /* Put the process into an own process group and make it the foregroud - * group on this terminal, so it will receive ctrl-c events, etc. - * This is the main reason for *all* this stub magic in the first place. */ - /* If one of these calls fails, the world is about to end anyway, so - * don't bother checking the return values. */ - setpgid(0, 0); - tcsetpgrp(0, getpid()); - -#ifdef __linux__ - prctl(PR_SET_PTRACER, atoi(argv[ArgPid])); -#endif - /* Block to allow the debugger to attach */ - if (isDebug) { - char buf; - int res = read(blockingPipe[0], &buf, 1); - if (res < 0) - perror("Could not read from blocking pipe"); - close(blockingPipe[0]); - close(blockingPipe[1]); - } - - if (env) - environ = env; - - execvp(argv[ArgExe], argv + ArgExe); - /* Only expected error: no such file or direcotry, i.e. executable not found */ - errNo = errno; - /* Only realistic error case is SIGPIPE */ - if (write(chldPipe[1], &errNo, sizeof(errNo)) != sizeof(errNo)) - perror("Error passing errno to child"); - _exit(0); - default: - sendMsg("pid %d\n", chldPid); - for (;;) { - char buffer[100]; - int nbytes; - - nbytes = read(qtcFd, buffer, 100); - if (nbytes <= 0) { - if (nbytes < 0 && errno == EINTR) - continue; - if (!isDetached) { - isDetached = 2; - if (nbytes == 0) - fprintf(stderr, "Lost connection to QtCreator, detaching from it.\n"); - else - perror("Lost connection to QtCreator, detaching from it"); - } - break; - } else { - int i; - char c = 'i'; - for (i = 0; i < nbytes; ++i) { - switch (buffer[i]) { - case 'k': - if (chldPid > 0) { - kill(chldPid, SIGTERM); - sleep(1); - kill(chldPid, SIGKILL); - } - break; - case 'i': - if (chldPid > 0) { - int res = kill(chldPid, SIGINT); - if (res) - perror("Stub could not interrupt inferior"); - } - break; - case 'c': { - int res = write(blockingPipe[1], &c, 1); - if (res < 0) - perror("Could not write to blocking pipe"); - break; - } - case 'd': - isDetached = 1; - break; - case 's': - exit(0); - default: - if (!hadInvalidCommand) { - fprintf(stderr, "Ignoring invalid commands from QtCreator.\n"); - hadInvalidCommand = 1; - } - } - } - } - } - if (isDetached) { - for (;;) - pause(); /* will exit in the signal handler... */ - } - } - assert(0); - return 0; -} diff --git a/src/libs/utils/process_stub_win.c b/src/libs/utils/process_stub_win.c deleted file mode 100644 index 09f220a6c65..00000000000 --- a/src/libs/utils/process_stub_win.c +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 /* WinXP, needed for DebugActiveProcessStop() */ - -#include -#include -#include -#include -#include -#include -#include - -static FILE *qtcFd; -static wchar_t *sleepMsg; - -enum RunMode { Run, Debug, Suspend }; - -/* Print some "press enter" message, wait for that, exit. */ -static void doExit(int code) -{ - char buf[2]; - _putws(sleepMsg); - fgets(buf, 2, stdin); /* Minimal size to make it wait */ - exit(code); -} - -/* Print an error message for unexpected Windows system errors, wait, exit. */ -static void systemError(const char *str) -{ - fprintf(stderr, str, GetLastError()); - doExit(3); -} - -/* Send a message to the master. */ -static void sendMsg(const char *msg, int num) -{ - int pidStrLen; - char pidStr[64]; - - pidStrLen = sprintf(pidStr, msg, num); - if (fwrite(pidStr, pidStrLen, 1, qtcFd) != 1 || fflush(qtcFd)) { - fprintf(stderr, "Cannot write to creator comm socket: %s\n", - strerror(errno)); - doExit(3); - } -} - -/* Ignore the first ctrl-c/break within a second. */ -static BOOL WINAPI ctrlHandler(DWORD dwCtrlType) -{ - static ULARGE_INTEGER lastTime; - ULARGE_INTEGER thisTime; - SYSTEMTIME sysTime; - FILETIME fileTime; - - if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { - GetSystemTime(&sysTime); - SystemTimeToFileTime(&sysTime, &fileTime); - thisTime.LowPart = fileTime.dwLowDateTime; - thisTime.HighPart = fileTime.dwHighDateTime; - if (lastTime.QuadPart + 10000000 < thisTime.QuadPart) { - lastTime.QuadPart = thisTime.QuadPart; - return TRUE; - } - } - return FALSE; -} - -enum { - ArgCmd = 0, - ArgAction, - ArgSocket, - ArgDir, - ArgEnv, - ArgCmdLine, - ArgMsg, - ArgCount -}; - -/* syntax: $0 {"run"|"debug"} */ -/* exit codes: 0 = ok, 1 = invocation error, 3 = internal error */ -int main() -{ - int argc; - int creationFlags; - wchar_t **argv; - wchar_t *env = 0; - STARTUPINFOW si; - PROCESS_INFORMATION pi; - DEBUG_EVENT dbev; - enum RunMode mode = Run; - HANDLE image = NULL; - - argv = CommandLineToArgvW(GetCommandLine(), &argc); - - if (argc != ArgCount) { - fprintf(stderr, "This is an internal helper of Qt Creator. Do not run it manually.\n"); - return 1; - } - sleepMsg = argv[ArgMsg]; - - /* Connect to the master, i.e. Creator. */ - if (!(qtcFd = _wfopen(argv[ArgSocket], L"w"))) { - fprintf(stderr, "Cannot connect creator comm pipe %S: %s\n", - argv[ArgSocket], strerror(errno)); - doExit(1); - } - - if (*argv[ArgDir] && !SetCurrentDirectoryW(argv[ArgDir])) { - /* Only expected error: no such file or direcotry */ - sendMsg("err:chdir %d\n", GetLastError()); - return 1; - } - - if (*argv[ArgEnv]) { - FILE *envFd; - long size; - if (!(envFd = _wfopen(argv[ArgEnv], L"rb"))) { - fprintf(stderr, "Cannot read creator env file %S: %s\n", - argv[ArgEnv], strerror(errno)); - doExit(1); - } - fseek(envFd, 0, SEEK_END); - size = ftell(envFd); - rewind(envFd); - env = malloc(size); - if (fread(env, 1, size, envFd) != size) { - perror("Failed to read env file"); - doExit(1); - } - fclose(envFd); - } - - ZeroMemory(&pi, sizeof(pi)); - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - - creationFlags = CREATE_UNICODE_ENVIRONMENT; - if (!wcscmp(argv[ArgAction], L"debug")) { - mode = Debug; - } else if (!wcscmp(argv[ArgAction], L"suspend")) { - mode = Suspend; - } - - switch (mode) { - case Debug: - creationFlags |= DEBUG_ONLY_THIS_PROCESS; - break; - case Suspend: - creationFlags |= CREATE_SUSPENDED; - break; - default: - break; - } - if (!CreateProcessW(0, argv[ArgCmdLine], 0, 0, FALSE, creationFlags, env, 0, &si, &pi)) { - /* Only expected error: no such file or direcotry, i.e. executable not found */ - sendMsg("err:exec %d\n", GetLastError()); - doExit(1); - } - - /* This is somewhat convoluted. What we actually want is creating a - suspended process and letting gdb attach to it. Unfortunately, - the Windows kernel runs amok when we attempt this. - So instead we start a debugged process, eat all the initial - debug events, suspend the process and detach from it. If gdb - tries to attach *now*, everything goes smoothly. Yay. */ - if (mode == Debug) { - do { - if (!WaitForDebugEvent (&dbev, INFINITE)) - systemError("Cannot fetch debug event, error %d\n"); - if (dbev.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) - image = dbev.u.CreateProcessInfo.hFile; - if (dbev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { - /* The first exception to be delivered is a trap - which indicates completion of startup. */ - if (SuspendThread(pi.hThread) == (DWORD)-1) - systemError("Cannot suspend debugee, error %d\n"); - } - if (!ContinueDebugEvent(dbev.dwProcessId, dbev.dwThreadId, DBG_CONTINUE)) - systemError("Cannot continue debug event, error %d\n"); - } while (dbev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT); - if (!DebugActiveProcessStop(dbev.dwProcessId)) - systemError("Cannot detach from debugee, error %d\n"); - if (image) - CloseHandle(image); - } - - SetConsoleCtrlHandler(ctrlHandler, TRUE); - - sendMsg("thread %d\n", pi.dwThreadId); - sendMsg("pid %d\n", pi.dwProcessId); - - if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) - systemError("Wait for debugee failed, error %d\n"); - - /* Don't close the process/thread handles, so that the kernel doesn't free - the resources before ConsoleProcess is able to obtain handles to them - - this would be a problem if the child process exits very quickly. */ - doExit(0); - - return 0; -} diff --git a/src/libs/utils/processenums.h b/src/libs/utils/processenums.h index 6ea37a2d37a..5ce782cd946 100644 --- a/src/libs/utils/processenums.h +++ b/src/libs/utils/processenums.h @@ -26,7 +26,6 @@ enum class TerminalMode { Off, Run, Debug, - Suspend, On = Run // Default mode for terminal set to on }; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 21b1684242b..0ec90d393b4 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -358,7 +358,7 @@ public: HostOsInfo::isWindowsHost() ? QStringList{m_setup.m_nativeArguments} << arguments : arguments, - m_setup.m_workingDirectory.path(), + m_setup.m_workingDirectory.nativePath(), m_setup.m_environment.toProcessEnvironment().toStringList(), m_setup.m_ptyData->size().width(), m_setup.m_ptyData->size().height()); diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index f4a5944dbdc..8187229cbf5 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -3,8 +3,12 @@ #include "terminalhooks.h" +#include "terminalinterface.h" #include "filepath.h" -#include "terminalprocess_p.h" +#include "qtcprocess.h" +#include "terminalcommand.h" + +#include namespace Utils::Terminal { @@ -26,6 +30,61 @@ FilePath defaultShellForDevice(const FilePath &deviceRoot) return shell.onDevice(deviceRoot); } +class ExternalTerminalProcessImpl final : public TerminalInterface +{ + class ProcessStubCreator : public StubCreator + { + public: + ProcessStubCreator(ExternalTerminalProcessImpl *interface) + : m_interface(interface) + {} + + void startStubProcess(const CommandLine &cmd, const ProcessSetupData &) override + { + if (HostOsInfo::isWindowsHost()) { + m_terminalProcess.setCommand(cmd); + QObject::connect(&m_terminalProcess, &QtcProcess::done, this, [this] { + m_interface->onStubExited(); + }); + m_terminalProcess.start(); + } else if (HostOsInfo::isMacHost()) { + QTemporaryFile f; + f.setAutoRemove(false); + f.open(); + f.setPermissions(QFile::ExeUser | QFile::ReadUser | QFile::WriteUser); + f.write("#!/bin/sh\n"); + f.write(QString("exec '%1' %2\n") + .arg(cmd.executable().nativePath()) + .arg(cmd.arguments()) + .toUtf8()); + f.close(); + + const QString path = f.fileName(); + const QString exe + = QString("tell app \"Terminal\" to do script \"'%1'; rm -f '%1'; exit\"") + .arg(path); + + m_terminalProcess.setCommand({"osascript", {"-e", exe}}); + m_terminalProcess.runBlocking(); + } else { + const TerminalCommand terminal = TerminalCommand::terminalEmulator(); + + CommandLine cmdLine = {terminal.command, {terminal.executeArgs}}; + cmdLine.addCommandLineAsArgs(cmd, CommandLine::Raw); + + m_terminalProcess.setCommand(cmdLine); + m_terminalProcess.start(); + } + } + + ExternalTerminalProcessImpl *m_interface; + QtcProcess m_terminalProcess; + }; + +public: + ExternalTerminalProcessImpl() { setStubCreator(new ProcessStubCreator(this)); } +}; + struct HooksPrivate { HooksPrivate() @@ -34,9 +93,8 @@ struct HooksPrivate FilePath{}), parameters.environment.value_or(Environment{})); }) - , m_createTerminalProcessInterfaceHook( - []() -> ProcessInterface * { return new Internal::TerminalImpl(); }) - , m_getTerminalCommandsForDevicesHook([]() -> QList { return {}; }) + , m_createTerminalProcessInterfaceHook([] { return new ExternalTerminalProcessImpl(); }) + , m_getTerminalCommandsForDevicesHook([] { return QList{}; }) {} Hooks::OpenTerminalHook m_openTerminalHook; diff --git a/src/libs/utils/terminalhooks.h b/src/libs/utils/terminalhooks.h index 3f3d8485810..2da470d1711 100644 --- a/src/libs/utils/terminalhooks.h +++ b/src/libs/utils/terminalhooks.h @@ -6,6 +6,7 @@ #include "commandline.h" #include "environment.h" #include "filepath.h" +#include "id.h" #include #include @@ -46,6 +47,7 @@ struct OpenTerminalParameters std::optional workingDirectory; std::optional environment; ExitBehavior m_exitBehavior{ExitBehavior::Close}; + std::optional identifier{std::nullopt}; }; struct NameAndCommandLine diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp new file mode 100644 index 00000000000..04468ddab7c --- /dev/null +++ b/src/libs/utils/terminalinterface.cpp @@ -0,0 +1,400 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalinterface.h" + +#include "utilstr.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(terminalInterfaceLog, "qtc.terminalinterface", QtWarningMsg) + +namespace Utils { + +static QString msgCommChannelFailed(const QString &error) +{ + return Tr::tr("Cannot set up communication channel: %1").arg(error); +} + +static QString msgCannotCreateTempFile(const QString &why) +{ + return Tr::tr("Cannot create temporary file: %1").arg(why); +} + +static QString msgCannotWriteTempFile() +{ + return Tr::tr("Cannot write temporary file. Disk full?"); +} + +static QString msgCannotCreateTempDir(const QString &dir, const QString &why) +{ + return Tr::tr("Cannot create temporary directory \"%1\": %2").arg(dir, why); +} + +static QString msgUnexpectedOutput(const QByteArray &what) +{ + return Tr::tr("Unexpected output from helper program (%1).").arg(QString::fromLatin1(what)); +} + +static QString msgCannotChangeToWorkDir(const FilePath &dir, const QString &why) +{ + return Tr::tr("Cannot change to working directory \"%1\": %2").arg(dir.toString(), why); +} + +static QString msgCannotExecute(const QString &p, const QString &why) +{ + return Tr::tr("Cannot execute \"%1\": %2").arg(p, why); +} + +class TerminalInterfacePrivate : public QObject +{ + Q_OBJECT +public: + TerminalInterfacePrivate(TerminalInterface *p) + : q(p) + { + connect(&stubServer, + &QLocalServer::newConnection, + q, + &TerminalInterface::onNewStubConnection); + } + +public: + QLocalServer stubServer; + QLocalSocket *stubSocket = nullptr; + + int stubProcessId = 0; + int inferiorProcessId = 0; + int inferiorThreadId = 0; + + std::unique_ptr envListFile; + QTemporaryDir tempDir; + + std::unique_ptr stubConnectTimeoutTimer; + + ProcessResultData processResultData; + TerminalInterface *q; + + StubCreator *stubCreator{nullptr}; +}; + +TerminalInterface::TerminalInterface() + : d(new TerminalInterfacePrivate(this)) +{} + +TerminalInterface::~TerminalInterface() +{ + if (d->stubSocket && d->stubSocket->state() == QLocalSocket::ConnectedState) { + if (d->inferiorProcessId) + killInferiorProcess(); + killStubProcess(); + } + if (d->stubCreator) + d->stubCreator->deleteLater(); + delete d; +} + +void TerminalInterface::setStubCreator(StubCreator *creator) +{ + d->stubCreator = creator; +} + +int TerminalInterface::inferiorProcessId() const +{ + return d->inferiorProcessId; +} + +int TerminalInterface::inferiorThreadId() const +{ + return d->inferiorThreadId; +} + +static QString errnoToString(int code) +{ + return QString::fromLocal8Bit(strerror(code)); +} + +void TerminalInterface::onNewStubConnection() +{ + d->stubConnectTimeoutTimer.reset(); + + d->stubSocket = d->stubServer.nextPendingConnection(); + if (!d->stubSocket) + return; + + connect(d->stubSocket, &QIODevice::readyRead, this, &TerminalInterface::onStubReadyRead); + + if (HostOsInfo::isAnyUnixHost()) + connect(d->stubSocket, &QLocalSocket::disconnected, this, &TerminalInterface::onStubExited); +} + +void TerminalInterface::onStubExited() +{ + // The stub exit might get noticed before we read the pid for the kill on Windows + // or the error status elsewhere. + if (d->stubSocket && d->stubSocket->state() == QLocalSocket::ConnectedState) + d->stubSocket->waitForDisconnected(); + + shutdownStubServer(); + d->envListFile.reset(); + + if (d->inferiorProcessId) + emitFinished(-1, QProcess::CrashExit); +} + +void TerminalInterface::onStubReadyRead() +{ + while (d->stubSocket && d->stubSocket->canReadLine()) { + QByteArray out = d->stubSocket->readLine(); + out.chop(1); // remove newline + if (out.startsWith("err:chdir ")) { + emitError(QProcess::FailedToStart, + msgCannotChangeToWorkDir(m_setup.m_workingDirectory, + errnoToString(out.mid(10).toInt()))); + } else if (out.startsWith("err:exec ")) { + emitError(QProcess::FailedToStart, + msgCannotExecute(m_setup.m_commandLine.executable().toString(), + errnoToString(out.mid(9).toInt()))); + } else if (out.startsWith("spid ")) { + d->envListFile.reset(); + d->envListFile = nullptr; + } else if (out.startsWith("pid ")) { + d->inferiorProcessId = out.mid(4).toInt(); + emit started(d->inferiorProcessId, d->inferiorThreadId); + } else if (out.startsWith("thread ")) { // Windows only + d->inferiorThreadId = out.mid(7).toLongLong(); + } else if (out.startsWith("exit ")) { + emitFinished(out.mid(5).toInt(), QProcess::NormalExit); + } else if (out.startsWith("crash ")) { + emitFinished(out.mid(6).toInt(), QProcess::CrashExit); + } else { + emitError(QProcess::UnknownError, msgUnexpectedOutput(out)); + break; + } + } +} + +expected_str TerminalInterface::startStubServer() +{ + if (HostOsInfo::isWindowsHost()) { + if (d->stubServer.listen(QString::fromLatin1("creator-%1-%2") + .arg(QCoreApplication::applicationPid()) + .arg(rand()))) + return {}; + return make_unexpected(d->stubServer.errorString()); + } + + // We need to put the socket in a private directory, as some systems simply do not + // check the file permissions of sockets. + if (!QDir(d->tempDir.path()) + .mkdir("socket")) { // QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner + return make_unexpected(msgCannotCreateTempDir(d->tempDir.filePath("socket"), + QString::fromLocal8Bit(strerror(errno)))); + } + + if (!QFile::setPermissions(d->tempDir.filePath("socket"), + QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner)) { + return make_unexpected(Tr::tr("Cannot set permissions on temporary directory \"%1\": %2") + .arg(d->tempDir.filePath("socket")) + .arg(QString::fromLocal8Bit(strerror(errno)))); + } + + const QString socketPath = d->tempDir.filePath("socket/stub-socket"); + if (!d->stubServer.listen(socketPath)) { + return make_unexpected( + Tr::tr("Cannot create socket \"%1\": %2").arg(socketPath, d->stubServer.errorString())); + } + return {}; +} + +void TerminalInterface::shutdownStubServer() +{ + if (d->stubSocket) { + // Read potentially remaining data + onStubReadyRead(); + // avoid getting queued readyRead signals + d->stubSocket->disconnect(); + // we might be called from the disconnected signal of stubSocket + d->stubSocket->deleteLater(); + } + d->stubSocket = nullptr; + if (d->stubServer.isListening()) + d->stubServer.close(); +} + +void TerminalInterface::emitError(QProcess::ProcessError error, const QString &errorString) +{ + d->processResultData.m_error = error; + d->processResultData.m_errorString = errorString; + if (error == QProcess::FailedToStart) + emit done(d->processResultData); +} + +void TerminalInterface::emitFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + d->inferiorProcessId = 0; + d->inferiorThreadId = 0; + d->processResultData.m_exitCode = exitCode; + d->processResultData.m_exitStatus = exitStatus; + emit done(d->processResultData); +} + +bool TerminalInterface::isRunning() const +{ + return d->stubSocket && d->stubSocket->isOpen(); +} + +void TerminalInterface::cleanupAfterStartFailure(const QString &errorMessage) +{ + shutdownStubServer(); + emitError(QProcess::FailedToStart, errorMessage); + d->envListFile.reset(); +} + +void TerminalInterface::sendCommand(char c) +{ + if (d->stubSocket && d->stubSocket->isWritable()) { + d->stubSocket->write(&c, 1); + d->stubSocket->flush(); + } +} + +void TerminalInterface::killInferiorProcess() +{ + sendCommand('k'); + if (d->stubSocket) + d->stubSocket->waitForReadyRead(); +} + +void TerminalInterface::killStubProcess() +{ + if (!isRunning()) + return; + + sendCommand('s'); + if (d->stubSocket) + d->stubSocket->waitForReadyRead(); + shutdownStubServer(); +} + +void TerminalInterface::start() +{ + if (isRunning()) + return; + + const expected_str result = startStubServer(); + if (!result) { + emitError(QProcess::FailedToStart, msgCommChannelFailed(result.error())); + return; + } + + m_setup.m_environment.unset(QLatin1String("TERM")); + + Environment finalEnv = m_setup.m_environment; + + if (HostOsInfo::isWindowsHost()) { + if (!finalEnv.hasKey("PATH")) { + const QString path = qtcEnvironmentVariable("PATH"); + if (!path.isEmpty()) + finalEnv.set("PATH", path); + } + if (!finalEnv.hasKey("SystemRoot")) { + const QString systemRoot = qtcEnvironmentVariable("SystemRoot"); + if (!systemRoot.isEmpty()) + finalEnv.set("SystemRoot", systemRoot); + } + } + + if (finalEnv.hasChanges()) { + d->envListFile = std::make_unique(this); + if (!d->envListFile->open()) { + cleanupAfterStartFailure(msgCannotCreateTempFile(d->envListFile->errorString())); + return; + } + QTextStream stream(d->envListFile.get()); + finalEnv.forEachEntry([&stream](const QString &key, const QString &value, bool) { + stream << key << '=' << value << '\0'; + }); + + if (d->envListFile->error() != QFile::NoError) { + cleanupAfterStartFailure(msgCannotWriteTempFile()); + return; + } + } + + const FilePath stubPath = FilePath::fromUserInput(QCoreApplication::applicationDirPath()) + .pathAppended(QLatin1String(RELATIVE_LIBEXEC_PATH)) + .pathAppended((HostOsInfo::isWindowsHost() + ? QLatin1String("qtcreator_process_stub.exe") + : QLatin1String("qtcreator_process_stub"))); + + CommandLine cmd{stubPath, {"-s", d->stubServer.fullServerName()}}; + + if (!m_setup.m_workingDirectory.isEmpty()) + cmd.addArgs({"-w", m_setup.m_workingDirectory.nativePath()}); + + if (m_setup.m_terminalMode == TerminalMode::Debug) + cmd.addArg("-d"); + + if (terminalInterfaceLog().isDebugEnabled()) + cmd.addArg("-v"); + + if (d->envListFile) + cmd.addArgs({"-e", d->envListFile->fileName()}); + + cmd.addArgs({"--", m_setup.m_commandLine.executable().nativePath()}); + cmd.addArgs(m_setup.m_commandLine.arguments(), CommandLine::Raw); + + QTC_ASSERT(d->stubCreator, return); + + QMetaObject::invokeMethod( + d->stubCreator, + [cmd, this] { d->stubCreator->startStubProcess(cmd, m_setup); }, + d->stubCreator->thread() == QThread::currentThread() ? Qt::DirectConnection + : Qt::BlockingQueuedConnection); + + d->stubConnectTimeoutTimer = std::make_unique(); + + connect(d->stubConnectTimeoutTimer.get(), &QTimer::timeout, this, [this] { + killInferiorProcess(); + killStubProcess(); + }); + d->stubConnectTimeoutTimer->setSingleShot(true); + d->stubConnectTimeoutTimer->start(10000); +} + +qint64 TerminalInterface::write(const QByteArray &data) +{ + Q_UNUSED(data); + QTC_CHECK(false); + return -1; +} +void TerminalInterface::sendControlSignal(ControlSignal controlSignal) +{ + switch (controlSignal) { + case ControlSignal::Terminate: + case ControlSignal::Kill: + killInferiorProcess(); + break; + case ControlSignal::Interrupt: + sendCommand('i'); + break; + case ControlSignal::KickOff: + sendCommand('c'); + break; + case ControlSignal::CloseWriteChannel: + QTC_CHECK(false); + break; + } +} + +} // namespace Utils + +#include "terminalinterface.moc" diff --git a/src/libs/utils/terminalinterface.h b/src/libs/utils/terminalinterface.h new file mode 100644 index 00000000000..135fb8257dd --- /dev/null +++ b/src/libs/utils/terminalinterface.h @@ -0,0 +1,61 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "commandline.h" +#include "expected.h" +#include "processinterface.h" + +namespace Utils { + +class TerminalInterfacePrivate; + +class StubCreator : public QObject +{ +public: + virtual void startStubProcess(const CommandLine &cmd, const ProcessSetupData &setup) = 0; +}; + +class QTCREATOR_UTILS_EXPORT TerminalInterface : public ProcessInterface +{ + friend class TerminalInterfacePrivate; + friend class StubCreator; + +public: + TerminalInterface(); + ~TerminalInterface() override; + + int inferiorProcessId() const; + int inferiorThreadId() const; + + void setStubCreator(StubCreator *creator); + + void emitError(QProcess::ProcessError error, const QString &errorString); + void emitFinished(int exitCode, QProcess::ExitStatus exitStatus); + void onStubExited(); + +protected: + void onNewStubConnection(); + void onStubReadyRead(); + + void sendCommand(char c); + + void killInferiorProcess(); + void killStubProcess(); + + expected_str startStubServer(); + void shutdownStubServer(); + void cleanupAfterStartFailure(const QString &errorMessage); + + bool isRunning() const; + +private: + void start() override; + qint64 write(const QByteArray &data) override; + void sendControlSignal(ControlSignal controlSignal) override; + + TerminalInterfacePrivate *d{nullptr}; +}; + +} // namespace Utils diff --git a/src/libs/utils/terminalprocess.cpp b/src/libs/utils/terminalprocess.cpp deleted file mode 100644 index 0070a4db2c2..00000000000 --- a/src/libs/utils/terminalprocess.cpp +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "terminalprocess_p.h" - -#include "commandline.h" -#include "environment.h" -#include "hostosinfo.h" -#include "qtcassert.h" -#include "qtcprocess.h" -#include "terminalcommand.h" -#include "utilstr.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN - -#include "winutils.h" - -#include -#include -#include - -#else - -#include -#include -#include -#include -#include - -#endif - -namespace Utils { -namespace Internal { - -static QString modeOption(TerminalMode m) -{ - switch (m) { - case TerminalMode::Run: - return "run"; - case TerminalMode::Debug: - return "debug"; - case TerminalMode::Suspend: - return "suspend"; - case TerminalMode::Off: - QTC_CHECK(false); - break; - } - return {}; -} - -static QString msgCommChannelFailed(const QString &error) -{ - return Tr::tr("Cannot set up communication channel: %1").arg(error); -} - -static QString msgPromptToClose() -{ - // Shown in a terminal which might have a different character set on Windows. - return Tr::tr("Press to close this window..."); -} - -static QString msgCannotCreateTempFile(const QString &why) -{ - return Tr::tr("Cannot create temporary file: %1").arg(why); -} - -static QString msgCannotWriteTempFile() -{ - return Tr::tr("Cannot write temporary file. Disk full?"); -} - -static QString msgCannotCreateTempDir(const QString & dir, const QString &why) -{ - return Tr::tr("Cannot create temporary directory \"%1\": %2").arg(dir, why); -} - -static QString msgUnexpectedOutput(const QByteArray &what) -{ - return Tr::tr("Unexpected output from helper program (%1).") - .arg(QString::fromLatin1(what)); -} - -static QString msgCannotChangeToWorkDir(const FilePath &dir, const QString &why) -{ - return Tr::tr("Cannot change to working directory \"%1\": %2").arg(dir.toString(), why); -} - -static QString msgCannotExecute(const QString & p, const QString &why) -{ - return Tr::tr("Cannot execute \"%1\": %2").arg(p, why); -} - -class TerminalProcessPrivate -{ -public: - TerminalProcessPrivate(QObject *parent) - : m_stubServer(parent) - , m_process(parent) {} - - qint64 m_processId = 0; - ProcessResultData m_result; - QLocalServer m_stubServer; - QLocalSocket *m_stubSocket = nullptr; - QTemporaryFile *m_tempFile = nullptr; - - // Used on Unix only - QtcProcess m_process; - QTimer *m_stubConnectTimer = nullptr; - QByteArray m_stubServerDir; - - // Used on Windows only - qint64 m_appMainThreadId = 0; - -#ifdef Q_OS_WIN - PROCESS_INFORMATION *m_pid = nullptr; - HANDLE m_hInferior = NULL; - QWinEventNotifier *inferiorFinishedNotifier = nullptr; - QWinEventNotifier *processFinishedNotifier = nullptr; -#endif -}; - -TerminalImpl::TerminalImpl() - : d(new TerminalProcessPrivate(this)) -{ - connect(&d->m_stubServer, &QLocalServer::newConnection, - this, &TerminalImpl::stubConnectionAvailable); - - d->m_process.setProcessChannelMode(QProcess::ForwardedChannels); -} - -TerminalImpl::~TerminalImpl() -{ - stopProcess(); - delete d; -} - -void TerminalImpl::start() -{ - if (isRunning()) - return; - - d->m_result = {}; - -#ifdef Q_OS_WIN - - QString pcmd; - QString pargs; - if (m_setup.m_terminalMode != TerminalMode::Run) { // The debugger engines already pre-process the arguments. - pcmd = m_setup.m_commandLine.executable().toString(); - pargs = m_setup.m_commandLine.arguments(); - } else { - ProcessArgs outArgs; - ProcessArgs::prepareCommand(m_setup.m_commandLine, &pcmd, &outArgs, - &m_setup.m_environment, &m_setup.m_workingDirectory); - pargs = outArgs.toWindowsArgs(); - } - - const QString err = stubServerListen(); - if (!err.isEmpty()) { - emitError(QProcess::FailedToStart, msgCommChannelFailed(err)); - return; - } - - QStringList env = m_setup.m_environment.toStringList(); - if (!env.isEmpty()) { - d->m_tempFile = new QTemporaryFile(); - if (!d->m_tempFile->open()) { - cleanupAfterStartFailure(msgCannotCreateTempFile(d->m_tempFile->errorString())); - return; - } - QString outString; - QTextStream out(&outString); - // Add PATH and SystemRoot environment variables in case they are missing - const QStringList fixedEnvironment = [env] { - QStringList envStrings = env; - // add PATH if necessary (for DLL loading) - if (envStrings.filter(QRegularExpression("^PATH=.*", QRegularExpression::CaseInsensitiveOption)).isEmpty()) { - const QString path = qtcEnvironmentVariable("PATH"); - if (!path.isEmpty()) - envStrings.prepend(QString::fromLatin1("PATH=%1").arg(path)); - } - // add systemroot if needed - if (envStrings.filter(QRegularExpression("^SystemRoot=.*", QRegularExpression::CaseInsensitiveOption)).isEmpty()) { - const QString systemRoot = qtcEnvironmentVariable("SystemRoot"); - if (!systemRoot.isEmpty()) - envStrings.prepend(QString::fromLatin1("SystemRoot=%1").arg(systemRoot)); - } - return envStrings; - }(); - - for (const QString &var : fixedEnvironment) - out << var << QChar(0); - out << QChar(0); - const QTextCodec *textCodec = QTextCodec::codecForName("UTF-16LE"); - QTC_CHECK(textCodec); - const QByteArray outBytes = textCodec ? textCodec->fromUnicode(outString) : QByteArray(); - if (!textCodec || d->m_tempFile->write(outBytes) < 0) { - cleanupAfterStartFailure(msgCannotWriteTempFile()); - return; - } - d->m_tempFile->flush(); - } - - STARTUPINFO si; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - - d->m_pid = new PROCESS_INFORMATION; - ZeroMemory(d->m_pid, sizeof(PROCESS_INFORMATION)); - - QString workDir = m_setup.m_workingDirectory.toUserOutput(); - if (!workDir.isEmpty() && !workDir.endsWith(QLatin1Char('\\'))) - workDir.append(QLatin1Char('\\')); - - // Quote a Windows command line correctly for the "CreateProcess" API - static const auto quoteWinCommand = [](const QString &program) { - const QChar doubleQuote = QLatin1Char('"'); - - // add the program as the first arg ... it works better - QString programName = program; - programName.replace(QLatin1Char('/'), QLatin1Char('\\')); - if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote) - && programName.contains(QLatin1Char(' '))) { - programName.prepend(doubleQuote); - programName.append(doubleQuote); - } - return programName; - }; - static const auto quoteWinArgument = [](const QString &arg) { - if (arg.isEmpty()) - return QString::fromLatin1("\"\""); - - QString ret(arg); - // Quotes are escaped and their preceding backslashes are doubled. - ret.replace(QRegularExpression("(\\\\*)\""), "\\1\\1\\\""); - if (ret.contains(QRegularExpression("\\s"))) { - // The argument must not end with a \ since this would be interpreted - // as escaping the quote -- rather put the \ behind the quote: e.g. - // rather use "foo"\ than "foo\" - int i = ret.length(); - while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) - --i; - ret.insert(i, QLatin1Char('"')); - ret.prepend(QLatin1Char('"')); - } - return ret; - }; - static const auto createWinCommandlineMultiArgs = [](const QString &program, const QStringList &args) { - QString programName = quoteWinCommand(program); - for (const QString &arg : args) { - programName += QLatin1Char(' '); - programName += quoteWinArgument(arg); - } - return programName; - }; - static const auto createWinCommandlineSingleArg = [](const QString &program, const QString &args) - { - QString programName = quoteWinCommand(program); - if (!args.isEmpty()) { - programName += QLatin1Char(' '); - programName += args; - } - return programName; - }; - - QStringList stubArgs; - stubArgs << modeOption(m_setup.m_terminalMode) - << d->m_stubServer.fullServerName() - << workDir - << (d->m_tempFile ? d->m_tempFile->fileName() : QString()) - << createWinCommandlineSingleArg(pcmd, pargs) - << msgPromptToClose(); - - const QString cmdLine = createWinCommandlineMultiArgs( - QCoreApplication::applicationDirPath() + QLatin1String("/qtcreator_process_stub.exe"), stubArgs); - - bool success = CreateProcessW(0, (WCHAR*)cmdLine.utf16(), - 0, 0, FALSE, CREATE_NEW_CONSOLE, - 0, 0, - &si, d->m_pid); - - if (!success) { - delete d->m_pid; - d->m_pid = nullptr; - const QString msg = Tr::tr("The process \"%1\" could not be started: %2") - .arg(cmdLine, winErrorMessage(GetLastError())); - cleanupAfterStartFailure(msg); - return; - } - - d->processFinishedNotifier = new QWinEventNotifier(d->m_pid->hProcess, this); - connect(d->processFinishedNotifier, &QWinEventNotifier::activated, - this, &TerminalImpl::stubExited); - -#else - - ProcessArgs::SplitError perr; - ProcessArgs pargs = ProcessArgs::prepareArgs(m_setup.m_commandLine.arguments(), - &perr, - HostOsInfo::hostOs(), - &m_setup.m_environment, - &m_setup.m_workingDirectory, - m_setup.m_abortOnMetaChars); - - QString pcmd; - if (perr == ProcessArgs::SplitOk) { - pcmd = m_setup.m_commandLine.executable().toString(); - } else { - if (perr != ProcessArgs::FoundMeta) { - emitError(QProcess::FailedToStart, Tr::tr("Quoting error in command.")); - return; - } - if (m_setup.m_terminalMode == TerminalMode::Debug) { - // FIXME: QTCREATORBUG-2809 - emitError(QProcess::FailedToStart, - Tr::tr("Debugging complex shell commands in a terminal" - " is currently not supported.")); - return; - } - pcmd = qtcEnvironmentVariable("SHELL", "/bin/sh"); - pargs = ProcessArgs::createUnixArgs( - {"-c", (ProcessArgs::quoteArg(m_setup.m_commandLine.executable().toString()) - + ' ' + m_setup.m_commandLine.arguments())}); - } - - ProcessArgs::SplitError qerr; - const TerminalCommand terminal = TerminalCommand::terminalEmulator(); - const ProcessArgs terminalArgs = ProcessArgs::prepareArgs(terminal.executeArgs, - &qerr, - HostOsInfo::hostOs(), - &m_setup.m_environment, - &m_setup.m_workingDirectory); - if (qerr != ProcessArgs::SplitOk) { - emitError(QProcess::FailedToStart, - qerr == ProcessArgs::BadQuoting - ? Tr::tr("Quoting error in terminal command.") - : Tr::tr("Terminal command may not be a shell command.")); - return; - } - - const QString err = stubServerListen(); - if (!err.isEmpty()) { - emitError(QProcess::FailedToStart, msgCommChannelFailed(err)); - return; - } - - m_setup.m_environment.unset(QLatin1String("TERM")); - - const QStringList env = m_setup.m_environment.toStringList(); - if (!env.isEmpty()) { - d->m_tempFile = new QTemporaryFile(this); - if (!d->m_tempFile->open()) { - cleanupAfterStartFailure(msgCannotCreateTempFile(d->m_tempFile->errorString())); - return; - } - QByteArray contents; - for (const QString &var : env) { - const QByteArray l8b = var.toLocal8Bit(); - contents.append(l8b.constData(), l8b.size() + 1); - } - if (d->m_tempFile->write(contents) != contents.size() || !d->m_tempFile->flush()) { - cleanupAfterStartFailure(msgCannotWriteTempFile()); - return; - } - } - - const QString stubPath = QCoreApplication::applicationDirPath() - + QLatin1String("/" RELATIVE_LIBEXEC_PATH "/qtcreator_process_stub"); - - QStringList allArgs = terminalArgs.toUnixArgs(); - - allArgs << stubPath - << modeOption(m_setup.m_terminalMode) - << d->m_stubServer.fullServerName() - << msgPromptToClose() - << m_setup.m_workingDirectory.path() - << (d->m_tempFile ? d->m_tempFile->fileName() : QString()) - << QString::number(getpid()) - << pcmd - << pargs.toUnixArgs(); - - if (terminal.needsQuotes) - allArgs = QStringList { ProcessArgs::joinArgs(allArgs) }; - - d->m_process.setEnvironment(m_setup.m_environment); - d->m_process.setCommand({terminal.command, allArgs}); - d->m_process.setProcessImpl(m_setup.m_processImpl); - d->m_process.setReaperTimeout(m_setup.m_reaperTimeout); - - d->m_process.start(); - if (!d->m_process.waitForStarted()) { - const QString msg = Tr::tr("Cannot start the terminal emulator \"%1\", change the " - "setting in the Environment preferences. (%2)") - .arg(terminal.command.toUserOutput(), d->m_process.errorString()); - cleanupAfterStartFailure(msg); - return; - } - d->m_stubConnectTimer = new QTimer(this); - connect(d->m_stubConnectTimer, &QTimer::timeout, this, &TerminalImpl::stopProcess); - d->m_stubConnectTimer->setSingleShot(true); - d->m_stubConnectTimer->start(10000); - -#endif -} - -void TerminalImpl::cleanupAfterStartFailure(const QString &errorMessage) -{ - stubServerShutdown(); - emitError(QProcess::FailedToStart, errorMessage); - delete d->m_tempFile; - d->m_tempFile = nullptr; -} - -void TerminalImpl::sendControlSignal(ControlSignal controlSignal) -{ - switch (controlSignal) { - case ControlSignal::Terminate: - case ControlSignal::Kill: - killProcess(); - if (HostOsInfo::isWindowsHost()) - killStub(); - break; - case ControlSignal::Interrupt: - sendCommand('i'); - break; - case ControlSignal::KickOff: - sendCommand('c'); - break; - case ControlSignal::CloseWriteChannel: - QTC_CHECK(false); - break; - } -} - -void TerminalImpl::sendCommand(char c) -{ -#ifdef Q_OS_WIN - Q_UNUSED(c) -#else - if (d->m_stubSocket && d->m_stubSocket->isWritable()) { - d->m_stubSocket->write(&c, 1); - d->m_stubSocket->flush(); - } -#endif -} - -void TerminalImpl::killProcess() -{ -#ifdef Q_OS_WIN - if (d->m_hInferior != NULL) { - TerminateProcess(d->m_hInferior, (unsigned)-1); - cleanupInferior(); - } -#else - sendCommand('k'); -#endif - d->m_processId = 0; -} - -void TerminalImpl::killStub() -{ - if (!isRunning()) - return; - -#ifdef Q_OS_WIN - TerminateProcess(d->m_pid->hProcess, (unsigned)-1); - WaitForSingleObject(d->m_pid->hProcess, INFINITE); - cleanupStub(); - emitFinished(-1, QProcess::CrashExit); -#else - sendCommand('s'); - stubServerShutdown(); - d->m_process.stop(); - d->m_process.waitForFinished(); -#endif -} - -void TerminalImpl::stopProcess() -{ - killProcess(); - killStub(); -} - -bool TerminalImpl::isRunning() const -{ -#ifdef Q_OS_WIN - return d->m_pid != nullptr; -#else - return d->m_process.state() != QProcess::NotRunning - || (d->m_stubSocket && d->m_stubSocket->isOpen()); -#endif -} - -QString TerminalImpl::stubServerListen() -{ -#ifdef Q_OS_WIN - if (d->m_stubServer.listen(QString::fromLatin1("creator-%1-%2") - .arg(QCoreApplication::applicationPid()) - .arg(rand()))) - return QString(); - return d->m_stubServer.errorString(); -#else - // We need to put the socket in a private directory, as some systems simply do not - // check the file permissions of sockets. - QString stubFifoDir; - while (true) { - { - QTemporaryFile tf; - if (!tf.open()) - return msgCannotCreateTempFile(tf.errorString()); - stubFifoDir = tf.fileName(); - } - // By now the temp file was deleted again - d->m_stubServerDir = QFile::encodeName(stubFifoDir); - if (!::mkdir(d->m_stubServerDir.constData(), 0700)) - break; - if (errno != EEXIST) - return msgCannotCreateTempDir(stubFifoDir, QString::fromLocal8Bit(strerror(errno))); - } - const QString stubServer = stubFifoDir + QLatin1String("/stub-socket"); - if (!d->m_stubServer.listen(stubServer)) { - ::rmdir(d->m_stubServerDir.constData()); - return Tr::tr("Cannot create socket \"%1\": %2") - .arg(stubServer, d->m_stubServer.errorString()); - } - return {}; -#endif -} - -void TerminalImpl::stubServerShutdown() -{ -#ifdef Q_OS_WIN - delete d->m_stubSocket; - d->m_stubSocket = nullptr; - if (d->m_stubServer.isListening()) - d->m_stubServer.close(); -#else - if (d->m_stubSocket) { - readStubOutput(); // we could get the shutdown signal before emptying the buffer - d->m_stubSocket->disconnect(); // avoid getting queued readyRead signals - d->m_stubSocket->deleteLater(); // we might be called from the disconnected signal of m_stubSocket - } - d->m_stubSocket = nullptr; - if (d->m_stubServer.isListening()) { - d->m_stubServer.close(); - ::rmdir(d->m_stubServerDir.constData()); - } -#endif -} - -void TerminalImpl::stubConnectionAvailable() -{ - if (d->m_stubConnectTimer) { - delete d->m_stubConnectTimer; - d->m_stubConnectTimer = nullptr; - } - - d->m_stubSocket = d->m_stubServer.nextPendingConnection(); - connect(d->m_stubSocket, &QIODevice::readyRead, this, &TerminalImpl::readStubOutput); - - if (HostOsInfo::isAnyUnixHost()) - connect(d->m_stubSocket, &QLocalSocket::disconnected, this, &TerminalImpl::stubExited); -} - -static QString errorMsg(int code) -{ - return QString::fromLocal8Bit(strerror(code)); -} - -void TerminalImpl::readStubOutput() -{ - while (d->m_stubSocket->canReadLine()) { - QByteArray out = d->m_stubSocket->readLine(); -#ifdef Q_OS_WIN - out.chop(2); // \r\n - if (out.startsWith("err:chdir ")) { - emitError(QProcess::FailedToStart, - msgCannotChangeToWorkDir(m_setup.m_workingDirectory, winErrorMessage(out.mid(10).toInt()))); - } else if (out.startsWith("err:exec ")) { - emitError(QProcess::FailedToStart, - msgCannotExecute(m_setup.m_commandLine.executable().toUserOutput(), winErrorMessage(out.mid(9).toInt()))); - } else if (out.startsWith("thread ")) { // Windows only - // TODO: ensure that it comes before "pid " comes - d->m_appMainThreadId = out.mid(7).toLongLong(); - } else if (out.startsWith("pid ")) { - // Will not need it any more - delete d->m_tempFile; - d->m_tempFile = nullptr; - d->m_processId = out.mid(4).toLongLong(); - - d->m_hInferior = OpenProcess( - SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, - FALSE, d->m_processId); - if (d->m_hInferior == NULL) { - emitError(QProcess::FailedToStart, - Tr::tr("Cannot obtain a handle to the inferior: %1") - .arg(winErrorMessage(GetLastError()))); - // Uhm, and now what? - continue; - } - d->inferiorFinishedNotifier = new QWinEventNotifier(d->m_hInferior, this); - connect(d->inferiorFinishedNotifier, &QWinEventNotifier::activated, this, [this] { - DWORD chldStatus; - - if (!GetExitCodeProcess(d->m_hInferior, &chldStatus)) - emitError(QProcess::UnknownError, - Tr::tr("Cannot obtain exit status from inferior: %1") - .arg(winErrorMessage(GetLastError()))); - cleanupInferior(); - emitFinished(chldStatus, QProcess::NormalExit); - }); - - emit started(d->m_processId, d->m_appMainThreadId); - } else { - emitError(QProcess::UnknownError, msgUnexpectedOutput(out)); - TerminateProcess(d->m_pid->hProcess, (unsigned)-1); - break; - } -#else - out.chop(1); // \n - if (out.startsWith("err:chdir ")) { - emitError(QProcess::FailedToStart, - msgCannotChangeToWorkDir(m_setup.m_workingDirectory, errorMsg(out.mid(10).toInt()))); - } else if (out.startsWith("err:exec ")) { - emitError(QProcess::FailedToStart, - msgCannotExecute(m_setup.m_commandLine.executable().toString(), errorMsg(out.mid(9).toInt()))); - } else if (out.startsWith("spid ")) { - delete d->m_tempFile; - d->m_tempFile = nullptr; - } else if (out.startsWith("pid ")) { - d->m_processId = out.mid(4).toInt(); - emit started(d->m_processId); - } else if (out.startsWith("exit ")) { - emitFinished(out.mid(5).toInt(), QProcess::NormalExit); - } else if (out.startsWith("crash ")) { - emitFinished(out.mid(6).toInt(), QProcess::CrashExit); - } else { - emitError(QProcess::UnknownError, msgUnexpectedOutput(out)); - d->m_process.terminate(); - break; - } -#endif - } // while -} - -void TerminalImpl::stubExited() -{ - // The stub exit might get noticed before we read the pid for the kill on Windows - // or the error status elsewhere. - if (d->m_stubSocket && d->m_stubSocket->state() == QLocalSocket::ConnectedState) - d->m_stubSocket->waitForDisconnected(); - -#ifdef Q_OS_WIN - cleanupStub(); - if (d->m_hInferior != NULL) { - TerminateProcess(d->m_hInferior, (unsigned)-1); - cleanupInferior(); - emitFinished(-1, QProcess::CrashExit); - } -#else - stubServerShutdown(); - delete d->m_tempFile; - d->m_tempFile = nullptr; - if (d->m_processId) - emitFinished(-1, QProcess::CrashExit); -#endif -} - -void TerminalImpl::cleanupInferior() -{ -#ifdef Q_OS_WIN - delete d->inferiorFinishedNotifier; - d->inferiorFinishedNotifier = nullptr; - CloseHandle(d->m_hInferior); - d->m_hInferior = NULL; -#endif -} - -void TerminalImpl::cleanupStub() -{ -#ifdef Q_OS_WIN - stubServerShutdown(); - delete d->processFinishedNotifier; - d->processFinishedNotifier = nullptr; - CloseHandle(d->m_pid->hThread); - CloseHandle(d->m_pid->hProcess); - delete d->m_pid; - d->m_pid = nullptr; - delete d->m_tempFile; - d->m_tempFile = nullptr; -#endif -} - -void TerminalImpl::emitError(QProcess::ProcessError error, const QString &errorString) -{ - d->m_result.m_error = error; - d->m_result.m_errorString = errorString; - if (error == QProcess::FailedToStart) - emit done(d->m_result); -} - -void TerminalImpl::emitFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - d->m_processId = 0; - d->m_result.m_exitCode = exitCode; - d->m_result.m_exitStatus = exitStatus; - emit done(d->m_result); -} - - -} // Internal -} // Utils diff --git a/src/libs/utils/terminalprocess_p.h b/src/libs/utils/terminalprocess_p.h deleted file mode 100644 index 27c99cee26e..00000000000 --- a/src/libs/utils/terminalprocess_p.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "processenums.h" -#include "processinterface.h" -#include "qtcassert.h" - -#include - -namespace Utils { - -class CommandLine; -class Environment; -class FilePath; - -namespace Internal { - -class TerminalImpl final : public ProcessInterface -{ -public: - TerminalImpl(); - ~TerminalImpl() final; - -private: - void start() final; - qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; } - void sendControlSignal(ControlSignal controlSignal) final; - - // OK, however, impl looks a bit different (!= NotRunning vs == Running). - // Most probably changing it into (== Running) should be OK. - bool isRunning() const; - - void stopProcess(); - void stubConnectionAvailable(); - void readStubOutput(); - void stubExited(); - void cleanupAfterStartFailure(const QString &errorMessage); - void killProcess(); - void killStub(); - void emitError(QProcess::ProcessError error, const QString &errorString); - void emitFinished(int exitCode, QProcess::ExitStatus exitStatus); - QString stubServerListen(); - void stubServerShutdown(); - void cleanupStub(); - void cleanupInferior(); - void sendCommand(char c); - - class TerminalProcessPrivate *d; -}; - -} // Internal -} // Utils diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 9e3d1eaeaaf..35fe753d1c5 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -314,8 +314,8 @@ Project { "terminalcommand.h", "terminalhooks.cpp", "terminalhooks.h", - "terminalprocess.cpp", - "terminalprocess_p.h", + "terminalinterface.cpp", + "terminalinterface.h", "textfieldcheckbox.cpp", "textfieldcheckbox.h", "textfieldcombobox.cpp", diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 9a81694d647..90aa6dd36ec 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1105,9 +1105,9 @@ void GdbEngine::handleStopResponse(const GdbMi &data) // Ignore trap on Windows terminals, which results in // spurious "* stopped" message. if (m_expectTerminalTrap) { - m_expectTerminalTrap = false; if ((!data.isValid() || !data["reason"].isValid()) && Abi::hostAbi().os() == Abi::WindowsOS) { + m_expectTerminalTrap = false; showMessage("IGNORING TERMINAL SIGTRAP", LogMisc); return; } @@ -1421,14 +1421,19 @@ void GdbEngine::handleStop2(const GdbMi &data) } else if (m_isQnxGdb && name == "0" && meaning == "Signal 0") { showMessage("SIGNAL 0 CONSIDERED BOGUS."); } else { - showMessage("HANDLING SIGNAL " + name); - if (debuggerSettings()->useMessageBoxForSignals.value() && !isStopperThread) - if (!showStoppedBySignalMessageBox(meaning, name)) { - showMessage("SIGNAL RECEIVED WHILE SHOWING SIGNAL MESSAGE"); - return; - } - if (!name.isEmpty() && !meaning.isEmpty()) - reasontr = msgStoppedBySignal(meaning, name); + if (terminal() && name == "SIGCONT" && m_expectTerminalTrap) { + continueInferior(); + m_expectTerminalTrap = false; + } else { + showMessage("HANDLING SIGNAL " + name); + if (debuggerSettings()->useMessageBoxForSignals.value() && !isStopperThread) + if (!showStoppedBySignalMessageBox(meaning, name)) { + showMessage("SIGNAL RECEIVED WHILE SHOWING SIGNAL MESSAGE"); + return; + } + if (!name.isEmpty() && !meaning.isEmpty()) + reasontr = msgStoppedBySignal(meaning, name); + } } } if (reason.isEmpty()) diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index 6707137e853..49048ec1797 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -175,8 +175,7 @@ void TerminalRunner::start() Runnable stub = m_stubRunnable(); m_stubProc = new QtcProcess(this); - m_stubProc->setTerminalMode(HostOsInfo::isWindowsHost() - ? TerminalMode::Suspend : TerminalMode::Debug); + m_stubProc->setTerminalMode(TerminalMode::Debug); connect(m_stubProc, &QtcProcess::started, this, &TerminalRunner::stubStarted); diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index f68a0b2ce42..1250455378a 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -12,7 +12,7 @@ add_qtc_plugin(Terminal terminal.qrc terminalpane.cpp terminalpane.h terminalplugin.cpp terminalplugin.h - terminalprocessinterface.cpp terminalprocessinterface.h + terminalprocessimpl.cpp terminalprocessimpl.h terminalsettings.cpp terminalsettings.h terminalsettingspage.cpp terminalsettingspage.h terminalsurface.cpp terminalsurface.h diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 53f08803393..982a89bcb2a 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -26,8 +26,8 @@ QtcPlugin { "terminalpane.h", "terminalplugin.cpp", "terminalplugin.h", - "terminalprocessinterface.cpp", - "terminalprocessinterface.h", + "terminalprocessimpl.cpp", + "terminalprocessimpl.h", "terminalsettings.cpp", "terminalsettings.h", "terminalsettingspage.cpp", diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 215a3883c40..dd9cdb5239a 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -23,18 +23,19 @@ namespace Terminal { using namespace Utils; +using namespace Utils::Terminal; TerminalPane::TerminalPane(QObject *parent) : Core::IOutputPane(parent) { Core::Context context("Terminal.Window"); - m_newTerminal.setIcon(Utils::Icons::PLUS_TOOLBAR.icon()); + m_newTerminal.setIcon(Icons::PLUS_TOOLBAR.icon()); m_newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); connect(&m_newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); - m_closeTerminal.setIcon(Utils::Icons::CLOSE_TOOLBAR.icon()); + m_closeTerminal.setIcon(Icons::CLOSE_TOOLBAR.icon()); m_closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); m_closeTerminal.setEnabled(false); @@ -109,21 +110,22 @@ static std::optional startupProjectDirectory() return project->projectDirectory(); } -void TerminalPane::openTerminal(Utils::Terminal::OpenTerminalParameters parameters) +void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) { + OpenTerminalParameters parametersCopy{parameters}; showPage(0); - if (!parameters.workingDirectory) { + if (!parametersCopy.workingDirectory) { const std::optional projectDir = startupProjectDirectory(); if (projectDir) { - if (!parameters.shellCommand - || parameters.shellCommand->executable().ensureReachable(*projectDir)) { - parameters.workingDirectory = *projectDir; + if (!parametersCopy.shellCommand + || parametersCopy.shellCommand->executable().ensureReachable(*projectDir)) { + parametersCopy.workingDirectory = *projectDir; } } } - auto terminalWidget = new TerminalWidget(m_tabWidget, parameters); + auto terminalWidget = new TerminalWidget(m_tabWidget, parametersCopy); m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal"))); setupTerminalWidget(terminalWidget); @@ -143,6 +145,19 @@ void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) emit navigateStateUpdate(); } +TerminalWidget *TerminalPane::stoppedTerminalWithId(const Id &identifier) const +{ + QTC_ASSERT(m_tabWidget, return nullptr); + + for (int i = 0; i < m_tabWidget->count(); ++i) { + auto terminal = qobject_cast(m_tabWidget->widget(i)); + if (terminal->processState() == QProcess::NotRunning && terminal->identifier() == identifier) + return terminal; + } + + return nullptr; +} + QWidget *TerminalPane::outputWidget(QWidget *parent) { if (!m_tabWidget) { diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 59621b9b665..ac3bed9a96c 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -36,9 +36,11 @@ public: virtual void goToNext(); virtual void goToPrev(); - void openTerminal(Utils::Terminal::OpenTerminalParameters parameters); + void openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters); void addTerminal(TerminalWidget *terminal, const QString &title); + TerminalWidget *stoppedTerminalWithId(const Utils::Id &identifier) const; + private: TerminalWidget *currentTerminal() const; diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp index ce196441182..a3258fcaf0e 100644 --- a/src/plugins/terminal/terminalplugin.cpp +++ b/src/plugins/terminal/terminalplugin.cpp @@ -4,7 +4,7 @@ #include "terminalplugin.h" #include "terminalpane.h" -#include "terminalprocessinterface.h" +#include "terminalprocessimpl.h" #include "terminalsettings.h" #include "terminalsettingspage.h" @@ -48,10 +48,8 @@ void TerminalPlugin::extensionsInitialized() m_terminalPane->openTerminal(p); }); - /*Utils::Terminal::Hooks::instance().createTerminalProcessInterfaceHook().set( - [this]() -> Utils::ProcessInterface * { - return new TerminalProcessInterface(m_terminalPane); - });*/ + Utils::Terminal::Hooks::instance().createTerminalProcessInterfaceHook().set( + [this] { return new TerminalProcessImpl(m_terminalPane); }); } } // namespace Internal diff --git a/src/plugins/terminal/terminalprocessimpl.cpp b/src/plugins/terminal/terminalprocessimpl.cpp new file mode 100644 index 00000000000..8724510eb46 --- /dev/null +++ b/src/plugins/terminal/terminalprocessimpl.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "terminalprocessimpl.h" +#include "terminalwidget.h" + +#include +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(terminalProcessLog, "qtc.terminal.stubprocess", QtDebugMsg) + +using namespace Utils; +using namespace Utils::Terminal; + +namespace Terminal { + +class ProcessStubCreator : public StubCreator +{ +public: + ProcessStubCreator(TerminalProcessImpl *interface, TerminalPane *terminalPane) + : m_terminalPane(terminalPane) + , m_process(interface) + {} + + void startStubProcess(const CommandLine &cmd, const ProcessSetupData &setup) override + { + const Id id = Id::fromString(setup.m_commandLine.executable().toUserOutput()); + + TerminalWidget *terminal = m_terminalPane->stoppedTerminalWithId(id); + + const OpenTerminalParameters openParameters{cmd, + std::nullopt, + std::nullopt, + ExitBehavior::Keep, + id}; + + if (!terminal) { + terminal = new TerminalWidget(nullptr, openParameters); + + terminal->setShellName(setup.m_commandLine.executable().fileName()); + m_terminalPane->addTerminal(terminal, "App"); + } else { + terminal->restart(openParameters); + } + + connect(terminal, &TerminalWidget::destroyed, m_process, [process = m_process] { + if (process->inferiorProcessId()) + process->emitFinished(-1, QProcess::CrashExit); + }); + } + + TerminalPane *m_terminalPane; + TerminalProcessImpl *m_process; +}; + +TerminalProcessImpl::TerminalProcessImpl(TerminalPane *terminalPane) +{ + auto creator = new ProcessStubCreator(this, terminalPane); + creator->moveToThread(qApp->thread()); + setStubCreator(creator); +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalprocessimpl.h b/src/plugins/terminal/terminalprocessimpl.h new file mode 100644 index 00000000000..f77f418281c --- /dev/null +++ b/src/plugins/terminal/terminalprocessimpl.h @@ -0,0 +1,18 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "terminalpane.h" + +#include + +namespace Terminal { + +class TerminalProcessImpl : public Utils::TerminalInterface +{ +public: + TerminalProcessImpl(TerminalPane *terminalPane); +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalprocessinterface.cpp b/src/plugins/terminal/terminalprocessinterface.cpp deleted file mode 100644 index 75f56338146..00000000000 --- a/src/plugins/terminal/terminalprocessinterface.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#include "terminalprocessinterface.h" -#include "terminalwidget.h" - -namespace Terminal { - -TerminalProcessInterface::TerminalProcessInterface(TerminalPane *terminalPane) - : m_terminalPane(terminalPane) -{} - -// It's being called only in Starting state. Just before this method is being called, -// the process transitions from NotRunning into Starting state. -void TerminalProcessInterface::start() -{ - QTC_ASSERT(!m_setup.m_commandLine.executable().needsDevice(), return); - - TerminalWidget *terminal = new TerminalWidget(nullptr, - {m_setup.m_commandLine, - m_setup.m_workingDirectory, - m_setup.m_environment, - Utils::Terminal::ExitBehavior::Keep}); - - connect(terminal, &TerminalWidget::started, this, [this](qint64 pid) { emit started(pid); }); - - connect(terminal, &QObject::destroyed, this, [this]() { - emit done(Utils::ProcessResultData{}); - }); - - m_terminalPane->addTerminal(terminal, "App"); -} - -// It's being called only in Running state. -qint64 TerminalProcessInterface::write(const QByteArray &data) -{ - Q_UNUSED(data); - return 0; -} - -// It's being called in Starting or Running state. -void TerminalProcessInterface::sendControlSignal(Utils::ControlSignal controlSignal) -{ - Q_UNUSED(controlSignal); -} - -} // namespace Terminal diff --git a/src/plugins/terminal/terminalprocessinterface.h b/src/plugins/terminal/terminalprocessinterface.h deleted file mode 100644 index 55dc7be3f80..00000000000 --- a/src/plugins/terminal/terminalprocessinterface.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "terminalpane.h" - -#include - -namespace Terminal { - -class TerminalProcessInterface : public Utils::ProcessInterface -{ - Q_OBJECT - -public: - TerminalProcessInterface(TerminalPane *terminalPane); - - /* - // This should be emitted when being in Starting state only. - // After emitting this signal the process enters Running state. - void started(qint64 processId, qint64 applicationMainThreadId = 0); - - // This should be emitted when being in Running state only. - void readyRead(const QByteArray &outputData, const QByteArray &errorData); - - // This should be emitted when being in Starting or Running state. - // When being in Starting state, the resultData should set error to FailedToStart. - // After emitting this signal the process enters NotRunning state. - void done(const Utils::ProcessResultData &resultData); -*/ -private: - // It's being called only in Starting state. Just before this method is being called, - // the process transitions from NotRunning into Starting state. - void start() override; - - // It's being called only in Running state. - qint64 write(const QByteArray &data) override; - - // It's being called in Starting or Running state. - void sendControlSignal(Utils::ControlSignal controlSignal) override; - - //Utils::ProcessBlockingInterface *processBlockingInterface() const { return nullptr; } - -private: - TerminalPane *m_terminalPane; -}; - -} // namespace Terminal diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index a684d5470d5..e9c86bec886 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -162,6 +162,7 @@ void TerminalWidget::setupPty() this, [this] { m_process.reset(); + setupSurface(); setupPty(); }, Qt::QueuedConnection); @@ -180,7 +181,8 @@ void TerminalWidget::setupPty() }); connect(m_process.get(), &QtcProcess::started, this, [this] { - m_shellName = m_process->commandLine().executable().fileName(); + if (m_shellName.isEmpty()) + m_shellName = m_process->commandLine().executable().fileName(); if (HostOsInfo::isWindowsHost() && m_shellName.endsWith(QTC_WIN_EXE_SUFFIX)) m_shellName.chop(QStringLiteral(QTC_WIN_EXE_SUFFIX).size()); @@ -253,7 +255,7 @@ void TerminalWidget::setupActions() void TerminalWidget::writeToPty(const QByteArray &data) { - if (m_process) + if (m_process && m_process->isRunning()) m_process->writeRaw(data); } @@ -504,6 +506,11 @@ bool TerminalWidget::setSelection(const std::optional &selection) return true; } +void TerminalWidget::setShellName(const QString &shellName) +{ + m_shellName = shellName; +} + QString TerminalWidget::shellName() const { return m_shellName; @@ -519,6 +526,29 @@ CommandLine TerminalWidget::currentCommand() const return m_currentCommand; } +std::optional TerminalWidget::identifier() const +{ + return m_openParameters.identifier; +} + +QProcess::ProcessState TerminalWidget::processState() const +{ + if (m_process) + return m_process->state(); + + return QProcess::NotRunning; +} + +void TerminalWidget::restart(const OpenTerminalParameters &openParameters) +{ + QTC_ASSERT(!m_process || !m_process->isRunning(), return); + m_openParameters = openParameters; + + m_process.reset(); + setupSurface(); + setupPty(); +} + QPoint TerminalWidget::viewportToGlobal(QPoint p) const { int y = p.y() - topMargin(); @@ -776,6 +806,9 @@ int TerminalWidget::paintCell(QPainter &p, void TerminalWidget::paintCursor(QPainter &p) const { + if (!m_process || !m_process->isRunning()) + return; + auto cursor = m_surface->cursor(); const bool blinkState = !cursor.blink || m_cursorBlinkState @@ -1155,14 +1188,13 @@ void TerminalWidget::checkLinkAt(const QPoint &pos) const TextAndOffsets hit = textAt(pos); if (hit.text.size() > 0) { - QString t - = Utils::chopIfEndsWith(QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed(), - ':'); + QString t = chopIfEndsWith(QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed(), + ':'); if (t.startsWith("~/")) { t = QDir::homePath() + t.mid(1); } - Utils::Link link = Utils::Link::fromString(t, true); + const Link link = Link::fromString(t, true); if (link.hasValidTarget() && (link.targetFilePath.scheme().toString().startsWith("http") diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 4c862835f7f..34b95a2e2d2 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -71,10 +71,15 @@ public: } }; + void setShellName(const QString &shellName); QString shellName() const; Utils::FilePath cwd() const; Utils::CommandLine currentCommand() const; + std::optional identifier() const; + QProcess::ProcessState processState() const; + + void restart(const Utils::Terminal::OpenTerminalParameters &openParameters); signals: void started(qint64 pid); @@ -167,6 +172,7 @@ private: std::unique_ptr m_shellIntegration; QString m_shellName; + Utils::Id m_identifier; QFont m_font; QSizeF m_cellSize; diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 75ca1590b00..2204ac3c5f9 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -41,3 +41,5 @@ add_subdirectory(wininterrupt) ## windows only if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/perfparser/CMakeLists.txt) add_subdirectory(perfparser) endif() + +add_subdirectory(process_stub) diff --git a/src/tools/process_stub/CMakeLists.txt b/src/tools/process_stub/CMakeLists.txt new file mode 100644 index 00000000000..b8181ad8361 --- /dev/null +++ b/src/tools/process_stub/CMakeLists.txt @@ -0,0 +1,12 @@ + +add_qtc_executable(qtcreator_process_stub + DEPENDS Qt::Core Qt::Network + SOURCES + main.cpp +) + +if (WIN32) + extend_qtc_executable(qtcreator_process_stub + DEFINES _UNICODE UNICODE _CRT_SECURE_NO_WARNINGS + ) +endif() diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp new file mode 100644 index 00000000000..5912fdae674 --- /dev/null +++ b/src/tools/process_stub/main.cpp @@ -0,0 +1,541 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include +#else +#include +#include +#include +#include +#endif + +#ifdef Q_OS_LINUX +#include +#endif + +#include + +Q_LOGGING_CATEGORY(log, "qtc.process_stub", QtWarningMsg); + +// Global variables + +QCommandLineParser commandLineParser; + +// The inferior command and arguments +QStringList inferiorCmdAndArguments; +// Whether to Suspend the inferior process on startup (to allow a debugger to attach) +bool debugMode = false; +// Whether to run in test mode (i.e. to start manually from the command line) +bool testMode = false; +// The control socket used to communicate with Qt Creator +QLocalSocket controlSocket; +// Environment variables to set for the inferior process +std::optional environmentVariables; + +QProcess inferiorProcess; +int inferiorId{0}; + +#ifndef Q_OS_WIN + +#ifdef Q_OS_DARWIN +// A memory mapped helper to retrieve the pid of the inferior process in debugMode +static int *shared_child_pid = nullptr; +#endif + +using OSSocketNotifier = QSocketNotifier; +#else +Q_PROCESS_INFORMATION *win_process_information = nullptr; +using OSSocketNotifier = QWinEventNotifier; +#endif +// Helper to read a single character from stdin in testMode +OSSocketNotifier *stdInNotifier; + +QThread processThread; + +// Helper to create the shared memory mapped segment +void setupSharedPid(); +// Parses the command line, returns a status code in case of error +std::optional tryParseCommandLine(QCoreApplication &app); +// Sets the working directory, returns a status code in case of error +std::optional trySetWorkingDir(); +// Reads the environment variables from the env file, returns a status code in case of error +std::optional readEnvFile(); + +void setupControlSocket(); +void setupSignalHandlers(); +void startProcess(const QString &program, const QStringList &arguments, const QString &workingDir); +void readKey(); +void sendSelfPid(); + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + setupSharedPid(); + + auto error = tryParseCommandLine(a); + if (error) + return error.value(); + + qCInfo(log) << "Debug helper started: "; + qCInfo(log) << "Socket:" << commandLineParser.value("socket"); + qCInfo(log) << "Inferior:" << inferiorCmdAndArguments.join(QChar::Space); + qCInfo(log) << "Working Directory" << commandLineParser.value("workingDir"); + qCInfo(log) << "Env file:" << commandLineParser.value("envfile"); + qCInfo(log) << "Mode:" + << QLatin1String(testMode ? "test | " : "") + + QLatin1String(debugMode ? "debug" : "run"); + + error = trySetWorkingDir(); + if (error) + return error.value(); + + error = readEnvFile(); + if (error) + return error.value(); + + if (testMode) { + sendSelfPid(); + setupSignalHandlers(); + + startProcess(inferiorCmdAndArguments[0], + inferiorCmdAndArguments.mid(1), + commandLineParser.value("workingDir")); + + if (debugMode) { + qDebug() << "Press 'c' to continue or 'k' to kill, followed by 'enter'"; + readKey(); + } + + return a.exec(); + } + + setupControlSocket(); + + return a.exec(); +} + +void sendMsg(const QByteArray &msg) +{ + if (controlSocket.state() == QLocalSocket::ConnectedState) { + controlSocket.write(msg); + } else { + qDebug() << "MSG:" << msg; + } +} + +void sendPid(int inferiorPid) +{ + sendMsg(QString("pid %1\n").arg(inferiorPid).toUtf8()); +} + +void sendThreadId(int inferiorThreadPid) +{ + sendMsg(QString("thread %1\n").arg(inferiorThreadPid).toUtf8()); +} + +void sendSelfPid() +{ + sendMsg(QString("spid %1\n").arg(QCoreApplication::applicationPid()).toUtf8()); +} + +void sendExit(int exitCode) +{ + sendMsg(QString("exit %1\n").arg(exitCode).toUtf8()); +} + +void sendCrash(int exitCode) +{ + sendMsg(QString("crash %1\n").arg(exitCode).toUtf8()); +} + +void sendErrChDir() +{ + sendMsg(QString("err:chdir %1\n").arg(errno).toUtf8()); +} + +void doExit(int exitCode) +{ + if (controlSocket.state() == QLocalSocket::ConnectedState && controlSocket.bytesToWrite()) + controlSocket.waitForBytesWritten(1000); + + exit(exitCode); +} + +void onInferiorFinished(int exitCode, QProcess::ExitStatus status) +{ + qCInfo(log) << "Inferior finished"; + + if (status == QProcess::CrashExit) { + sendCrash(exitCode); + doExit(exitCode); + } else { + sendExit(exitCode); + doExit(exitCode); + } +} + +void onInferiorErrorOccurered(QProcess::ProcessError error) +{ + qCInfo(log) << "Inferior error: " << error << inferiorProcess.errorString(); + sendCrash(inferiorProcess.exitCode()); + doExit(1); +} + +void onInferiorStarted() +{ + inferiorId = inferiorProcess.processId(); + qCInfo(log) << "Inferior started ( pid:" << inferiorId << ")"; +#ifdef Q_OS_WIN + sendThreadId(win_process_information->dwThreadId); + sendPid(inferiorId); +#elif defined(Q_OS_DARWIN) + // In debug mode we use the poll timer to send the pid. + if (!debugMode) + sendPid(inferiorId); +#else + ptrace(PTRACE_DETACH, inferiorId, 0, SIGSTOP); + sendPid(inferiorId); +#endif +} + +void setupUnixInferior() +{ +#ifndef Q_OS_WIN + if (debugMode) { + qCInfo(log) << "Debug mode enabled"; +#ifdef Q_OS_DARWIN + // We are using raise(SIGSTOP) to stop the child process, macOS does not support ptrace(...) + inferiorProcess.setChildProcessModifier([] { + // Let the parent know our pid ... + *shared_child_pid = getpid(); + // Suspend ourselves ... + raise(SIGSTOP); + }); +#else + // PTRACE_TRACEME will stop execution of the child process as soon as execve is called. + inferiorProcess.setChildProcessModifier([] { ptrace(PTRACE_TRACEME, 0, 0, 0); }); +#endif + } +#endif +} + +void setupWindowsInferior() +{ +#ifdef Q_OS_WIN + inferiorProcess.setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args) { + if (debugMode) + args->flags |= CREATE_SUSPENDED; + win_process_information = args->processInformation; + }); +#endif +} + +void setupPidPollTimer() +{ +#ifdef Q_OS_DARWIN + if (!debugMode) + return; + + static QTimer pollPidTimer; + + pollPidTimer.setInterval(1); + pollPidTimer.setSingleShot(false); + QObject::connect(&pollPidTimer, &QTimer::timeout, &pollPidTimer, [&] { + if (*shared_child_pid) { + qCInfo(log) << "Received pid during polling:" << *shared_child_pid; + inferiorId = *shared_child_pid; + sendPid(inferiorId); + pollPidTimer.stop(); + munmap(shared_child_pid, sizeof(int)); + } else { + qCDebug(log) << "Waiting for inferior to start..."; + } + }); + pollPidTimer.start(); +#endif +} +void startProcess(const QString &executable, const QStringList &arguments, const QString &workingDir) +{ + setupPidPollTimer(); + + qCInfo(log) << "Starting Inferior"; + + QObject::connect(&inferiorProcess, + &QProcess::finished, + QCoreApplication::instance(), + &onInferiorFinished); + QObject::connect(&inferiorProcess, + &QProcess::errorOccurred, + QCoreApplication::instance(), + &onInferiorErrorOccurered); + QObject::connect(&inferiorProcess, + &QProcess::started, + QCoreApplication::instance(), + &onInferiorStarted); + + inferiorProcess.setProcessChannelMode(QProcess::ForwardedChannels); + if (!(testMode && debugMode)) + inferiorProcess.setInputChannelMode(QProcess::ForwardedInputChannel); + inferiorProcess.setWorkingDirectory(workingDir); + inferiorProcess.setProgram(executable); + inferiorProcess.setArguments(arguments); + + if (environmentVariables) + inferiorProcess.setEnvironment(*environmentVariables); + + setupWindowsInferior(); + setupUnixInferior(); + + inferiorProcess.start(); +} + +std::optional readEnvFile() +{ + if (!commandLineParser.isSet("envfile")) + return std::nullopt; + + const QString path = commandLineParser.value("envfile"); + qCInfo(log) << "Reading env file: " << path << "..."; + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCWarning(log) << "Failed to open env file: " << path; + return 1; + } + + environmentVariables = QStringList{}; + + while (!file.atEnd()) { + QByteArray data = file.readAll(); + if (!data.isEmpty()) { + for (const auto &line : data.split('\0')) { + if (!line.isEmpty()) + *environmentVariables << QString::fromUtf8(line); + } + } + } + + qCDebug(log) << "Env: "; + for (const auto &env : *environmentVariables) + qCDebug(log) << env; + + return std::nullopt; +} + +#ifndef Q_OS_WIN +void forwardSignal(int signum) +{ + qCDebug(log) << "SIGTERM received, terminating inferior..."; + kill(inferiorId, signum); +} +#else +static BOOL WINAPI ctrlHandler(DWORD dwCtrlType) +{ + if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { + qCDebug(log) << "Terminate inferior..."; + inferiorProcess.terminate(); + return TRUE; + } + return FALSE; +} +#endif + +void setupSignalHandlers() +{ +#ifdef Q_OS_WIN + SetConsoleCtrlHandler(ctrlHandler, TRUE); +#else + struct sigaction act; + memset(&act, 0, sizeof(act)); + + act.sa_handler = SIG_IGN; + if (sigaction(SIGTTOU, &act, NULL)) { + qCWarning(log) << "sigaction SIGTTOU: " << strerror(errno); + doExit(3); + } + + act.sa_handler = forwardSignal; + if (sigaction(SIGTERM, &act, NULL)) { + qCWarning(log) << "sigaction SIGTERM: " << strerror(errno); + doExit(3); + } + + if (sigaction(SIGINT, &act, NULL)) { + qCWarning(log) << "sigaction SIGINT: " << strerror(errno); + doExit(3); + } + + qCDebug(log) << "Signals set up"; +#endif +} + +std::optional tryParseCommandLine(QCoreApplication &app) +{ + commandLineParser.setApplicationDescription("Debug helper for QtCreator"); + commandLineParser.addHelpOption(); + commandLineParser.addOption(QCommandLineOption({"d", "debug"}, "Start inferior in debug mode")); + commandLineParser.addOption(QCommandLineOption({"t", "test"}, "Don't start the control socket")); + commandLineParser.addOption( + QCommandLineOption({"s", "socket"}, "Path to the unix socket", "socket")); + commandLineParser.addOption( + QCommandLineOption({"w", "workingDir"}, "Working directory for inferior", "workingDir")); + commandLineParser.addOption(QCommandLineOption({"v", "verbose"}, "Print debug messages")); + commandLineParser.addOption(QCommandLineOption({"e", "envfile"}, "Path to env file", "envfile")); + + commandLineParser.process(app); + + inferiorCmdAndArguments = commandLineParser.positionalArguments(); + debugMode = commandLineParser.isSet("debug"); + testMode = commandLineParser.isSet("test"); + + if (!(commandLineParser.isSet("socket") || testMode) || inferiorCmdAndArguments.isEmpty()) { + commandLineParser.showHelp(1); + return 1; + } + + if (commandLineParser.isSet("verbose")) + QLoggingCategory::setFilterRules("qtc.process_stub=true"); + + return std::nullopt; +} + +std::optional trySetWorkingDir() +{ + if (commandLineParser.isSet("workingDir")) { + if (!QDir::setCurrent(commandLineParser.value("workingDir"))) { + qCWarning(log) << "Failed to change working directory to: " + << commandLineParser.value("workingDir"); + sendErrChDir(); + return 1; + } + } + + return std::nullopt; +} + +void setupSharedPid() +{ +#ifdef Q_OS_DARWIN + shared_child_pid = (int *) mmap(NULL, + sizeof *shared_child_pid, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, + -1, + 0); + *shared_child_pid = 0; +#endif +} + +void onControlSocketConnected() +{ + qCInfo(log) << "Connected to control socket"; + + sendSelfPid(); + setupSignalHandlers(); + + startProcess(inferiorCmdAndArguments[0], + inferiorCmdAndArguments.mid(1), + commandLineParser.value("workingDir")); +} + +void resumeInferior() +{ + qCDebug(log) << "Continuing inferior... (" << inferiorId << ")"; +#ifdef Q_OS_WIN + ResumeThread(win_process_information->hThread); +#else + kill(inferiorId, SIGCONT); +#endif +} + +void killInferior() +{ +#ifdef Q_OS_WIN + inferiorProcess.kill(); +#else + kill(inferiorId, SIGKILL); +#endif +} + +void onControlSocketReadyRead() +{ + //k = kill, i = interrupt, c = continue, s = shutdown + QByteArray data = controlSocket.readAll(); + for (auto ch : data) { + qCDebug(log) << "Received:" << ch; + + switch (ch) { + case 'k': { + qCDebug(log) << "Killing inferior..."; + killInferior(); + break; + } +#ifndef Q_OS_WIN + case 'i': { + qCDebug(log) << "Interrupting inferior..."; + kill(inferiorId, SIGINT); + break; + } +#endif + case 'c': { + resumeInferior(); + break; + } + case 's': { + qCDebug(log) << "Shutting down..."; + doExit(0); + break; + } + } + } +} + +void onControlSocketErrorOccurred(QLocalSocket::LocalSocketError socketError) +{ + qCWarning(log) << "Control socket error:" << socketError; + doExit(1); +} + +void setupControlSocket() +{ + QObject::connect(&controlSocket, &QLocalSocket::connected, &onControlSocketConnected); + QObject::connect(&controlSocket, &QLocalSocket::readyRead, &onControlSocketReadyRead); + QObject::connect(&controlSocket, &QLocalSocket::errorOccurred, &onControlSocketErrorOccurred); + + qCInfo(log) << "Waiting for connection..."; + controlSocket.connectToServer(commandLineParser.value("socket")); +} + +void onStdInReadyRead() +{ + char ch; + std::cin >> ch; + if (ch == 'k') { + killInferior(); + } else { + resumeInferior(); + } +} + +void readKey() +{ +#ifdef Q_OS_WIN + stdInNotifier = new QWinEventNotifier(GetStdHandle(STD_INPUT_HANDLE)); +#else + stdInNotifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read); +#endif + QObject::connect(stdInNotifier, &OSSocketNotifier::activated, &onStdInReadyRead); +} diff --git a/src/tools/process_stub/process_stub.qbs b/src/tools/process_stub/process_stub.qbs new file mode 100644 index 00000000000..1fa1bc32a3f --- /dev/null +++ b/src/tools/process_stub/process_stub.qbs @@ -0,0 +1,10 @@ +import qbs 1.0 + +QtcTool { + name: "qtcreator_process_stub" + consoleApplication: true + + Depends { name: "Qt"; submodules: ["core", "network"]; } + + files: [ "main.cpp" ] +} diff --git a/src/tools/tools.qbs b/src/tools/tools.qbs index cb4230dfde4..48a35448d7e 100644 --- a/src/tools/tools.qbs +++ b/src/tools/tools.qbs @@ -7,6 +7,7 @@ Project { "buildoutputparser/buildoutputparser.qbs", "cplusplustools.qbs", "disclaim/disclaim.qbs", + "process_stub/process_stub.qbs", "processlauncher/processlauncher.qbs", "qml2puppet/qml2puppet.qbs", "qtcdebugger/qtcdebugger.qbs", From 521ce41c09a6fc023b1db8a2c3ec5e0e70935ece Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 17 Mar 2023 12:44:35 +0100 Subject: [PATCH 0314/1447] QmakeProjectManager: Add lib and app binaries to project tree Task-number: QTCREATORBUG-28815 Change-Id: I4a3bbab54ce4f5cf6553d61f50b047f63b88cfa3 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz --- src/plugins/projectexplorer/project.cpp | 1 - .../qmakenodetreebuilder.cpp | 23 +++++++++++- .../qmakeprojectmanager/qmakeproject.cpp | 36 +++++++++++-------- .../qmakeprojectmanager/qmakeproject.h | 1 + 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index b9767fdedcb..fd95c807994 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -1570,7 +1570,6 @@ void ProjectExplorerPlugin::testSourceToBinaryMapping() return theProject.project()->binariesForSourceFile(projectDir.pathAppended(fileName)); }; QEXPECT_FAIL("cmake", "QTCREATORBUG-28815", Abort); - QEXPECT_FAIL("qmake", "QTCREATORBUG-28815", Abort); QCOMPARE(binariesForSource("multi-target-project-main.cpp").size(), 1); QCOMPARE(binariesForSource("multi-target-project-lib.cpp").size(), 1); QCOMPARE(binariesForSource("multi-target-project-shared.h").size(), 2); diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index f261594e59e..752cb7c3192 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -202,7 +202,23 @@ static void createTree(QmakeBuildSystem *buildSystem, } } - if (!generatedFiles.empty()) { + FileType targetFileType = FileType::Unknown; + FilePath targetBinary; + if (proFile && proFile->targetInformation().valid) { + if (proFile->projectType() == ProjectType::ApplicationTemplate) { + targetFileType = FileType::App; + targetBinary = buildSystem->executableFor(proFile); + } else if (proFile->projectType() == ProjectType::SharedLibraryTemplate + || proFile->projectType() == ProjectType::StaticLibraryTemplate) { + targetFileType = FileType::Lib; + const FilePaths libs = Utils::sorted(buildSystem->allLibraryTargetFiles(proFile), + [](const FilePath &fp1, const FilePath &fp2) { + return fp1.fileName().length() < fp2.fileName().length(); }); + if (!libs.isEmpty()) + targetBinary = libs.last(); // Longest file name is the one that's not a symlink. + } + } + if (!generatedFiles.empty() || !targetBinary.isEmpty()) { QTC_CHECK(proFile); const FilePath baseDir = generatedFiles.size() == 1 ? generatedFiles.first().parentDir() : buildSystem->buildDir(proFile->filePath()); @@ -214,6 +230,11 @@ static void createTree(QmakeBuildSystem *buildSystem, fileNode->setIsGenerated(true); genFolder->addNestedNode(std::move(fileNode)); } + if (!targetBinary.isEmpty()) { + auto targetFileNode = std::make_unique(targetBinary, targetFileType); + targetFileNode->setIsGenerated(true); + genFolder->addNestedNode(std::move(targetFileNode)); + } node->addNode(std::move(genFolder)); } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 3c78099b0f9..c12827b6b43 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1311,15 +1311,13 @@ static FilePath destDirFor(const TargetInformation &ti) return ti.destDir; } -void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentData &deploymentData) +FilePaths QmakeBuildSystem::allLibraryTargetFiles(const QmakeProFile *file) const { - const QString targetPath = file->installsList().targetPath; - if (targetPath.isEmpty()) - return; const ToolChain *const toolchain = ToolChainKitAspect::cxxToolChain(kit()); if (!toolchain) - return; + return {}; + FilePaths libs; TargetInformation ti = file->targetInformation(); QString targetFileName = ti.target; const QStringList config = file->variableValue(Variable::Config); @@ -1339,7 +1337,7 @@ void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentDa } targetFileName += targetVersionExt + QLatin1Char('.'); targetFileName += QLatin1String(isStatic ? "lib" : "dll"); - deploymentData.addFile(destDirFor(ti) / targetFileName, targetPath); + libs << FilePath::fromString(targetFileName); break; } case Abi::DarwinOS: { @@ -1359,10 +1357,10 @@ void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentDa targetFileName += majorVersion; } targetFileName += QLatin1Char('.'); - targetFileName += file->singleVariableValue(isStatic - ? Variable::StaticLibExtension : Variable::ShLibExtension); + targetFileName += file->singleVariableValue(isStatic ? Variable::StaticLibExtension + : Variable::ShLibExtension); } - deploymentData.addFile(destDir / targetFileName, targetPath); + libs << destDir / targetFileName; break; } case Abi::LinuxOS: @@ -1374,10 +1372,10 @@ void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentDa targetFileName += QLatin1Char('.'); if (isStatic) { - targetFileName += QLatin1Char('a'); + libs << destDirFor(ti) / (targetFileName + QLatin1Char('a')); } else { targetFileName += QLatin1String("so"); - deploymentData.addFile(destDirFor(ti) / targetFileName, targetPath); + libs << destDirFor(ti) / targetFileName; if (nameIsVersioned) { QString version = file->singleVariableValue(Variable::Version); if (version.isEmpty()) @@ -1388,9 +1386,7 @@ void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentDa targetFileName += QLatin1Char('.'); while (!versionComponents.isEmpty()) { const QString versionString = versionComponents.join(QLatin1Char('.')); - deploymentData.addFile(destDirFor(ti).pathAppended(targetFileName - + versionString), - targetPath); + libs << destDirFor(ti).pathAppended(targetFileName + versionString); versionComponents.removeLast(); } } @@ -1399,6 +1395,18 @@ void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentDa default: break; } + + return libs; +} + +void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentData &deploymentData) +{ + const QString targetPath = file->installsList().targetPath; + if (!targetPath.isEmpty()) { + const FilePaths libs = allLibraryTargetFiles(file); + for (const FilePath &lib : libs) + deploymentData.addFile(lib, targetPath); + } } static FilePath getFullPathOf(const QmakeProFile *pro, Variable variable, diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h index 6615baaaca5..3097ae7b579 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.h +++ b/src/plugins/qmakeprojectmanager/qmakeproject.h @@ -106,6 +106,7 @@ public: void collectData(const QmakeProFile *file, ProjectExplorer::DeploymentData &deploymentData); void collectApplicationData(const QmakeProFile *file, ProjectExplorer::DeploymentData &deploymentData); + Utils::FilePaths allLibraryTargetFiles(const QmakeProFile *file) const; void collectLibraryData(const QmakeProFile *file, ProjectExplorer::DeploymentData &deploymentData); void startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay); From bff2e12120c542e2369902fce6a4b99d221d203d Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Mar 2023 15:09:14 +0100 Subject: [PATCH 0315/1447] ProjectExplorer: Also encode unusual ports in SshParameters::userAndHost() Needed when e.g. using an SSH tunnel to a device. Should be mostly invisible to conventional use cases. Change-Id: I8d975b018e5c3e315b5e62996e819d9941a268e2 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- .../projectexplorer/devicesupport/sshparameters.cpp | 11 +++++++++++ .../projectexplorer/devicesupport/sshparameters.h | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp index 17e50bdf2ee..2ab8aa006ea 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp @@ -21,6 +21,17 @@ namespace ProjectExplorer { SshParameters::SshParameters() = default; +QString SshParameters::userAtHost() const +{ + QString res; + if (!m_userName.isEmpty()) + res = m_userName + '@'; + res += m_host; + if (m_port != 22) + res += QString(":%1").arg(m_port); + return res; +} + QStringList SshParameters::connectionOptions(const FilePath &binary) const { QString hostKeyCheckingString; diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.h b/src/plugins/projectexplorer/devicesupport/sshparameters.h index b4da396db56..1ed49c90a2d 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.h +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.h @@ -31,7 +31,7 @@ public: quint16 port() const { return m_port; } QString userName() const { return m_userName; } - QString userAtHost() const { return userName().isEmpty() ? host() : userName() + '@' + host(); } + QString userAtHost() const; void setHost(const QString &host) { m_host = host; } void setPort(int port) { m_port = port; } From af84305f124f1af02d80f1696efe008e41ada17d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 17 Mar 2023 07:18:47 +0100 Subject: [PATCH 0316/1447] DocumentLocatorFilter: Make it more self-contained Hide public DocumentLocatorFilter::updateCurrentClient() method and remove ClangdCurrentDocumentFilter::updateCurrentClient(). Connect DocumentLocatorFilter internally into a new LanguageClientManager::clientInitialized() signal instead. Change-Id: Ie74a112bda811525b7d226da1377e5624130e9ed Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- src/plugins/clangcodemodel/clangdclient.cpp | 8 +------- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 7 ++----- src/plugins/clangcodemodel/clangdlocatorfilters.h | 2 -- src/plugins/languageclient/languageclientmanager.cpp | 4 ++-- src/plugins/languageclient/languageclientmanager.h | 3 ++- src/plugins/languageclient/locatorfilter.cpp | 4 +++- src/plugins/languageclient/locatorfilter.h | 6 ++++-- 7 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 3413f250380..91a850f1b18 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -9,7 +9,6 @@ #include "clangdcompletion.h" #include "clangdfindreferences.h" #include "clangdfollowsymbol.h" -#include "clangdlocatorfilters.h" #include "clangdmemoryusagewidget.h" #include "clangdquickfixes.h" #include "clangdsemantichighlighting.h" @@ -471,12 +470,7 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c } }); - connect(this, &Client::initialized, this, [this] { - auto currentDocumentFilter = static_cast( - CppEditor::CppModelManager::instance()->currentDocumentFilter()); - currentDocumentFilter->updateCurrentClient(); - d->openedExtraFiles.clear(); - }); + connect(this, &Client::initialized, this, [this] { d->openedExtraFiles.clear(); }); start(); } diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 76efcec54c5..76a19f684f2 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -194,6 +195,7 @@ class LspCurrentDocumentFilter : public DocumentLocatorFilter { public: LspCurrentDocumentFilter() + : DocumentLocatorFilter(LanguageClientManager::instance()) { setId({}); setDisplayName({}); @@ -313,11 +315,6 @@ ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private) ClangdCurrentDocumentFilter::~ClangdCurrentDocumentFilter() { delete d; } -void ClangdCurrentDocumentFilter::updateCurrentClient() -{ - d->lspFilter.updateCurrentClient(); -} - void ClangdCurrentDocumentFilter::prepareSearch(const QString &entry) { const auto doc = TextEditor::TextDocument::currentTextDocument(); diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index 3a6011b8eea..70afd4cce2e 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -44,8 +44,6 @@ public: ClangdCurrentDocumentFilter(); ~ClangdCurrentDocumentFilter() override; - void updateCurrentClient(); - private: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 2b1255f25ca..56ef4a1c3a6 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -41,7 +41,7 @@ static LanguageClientManager *managerInstance = nullptr; static bool g_shuttingDown = false; LanguageClientManager::LanguageClientManager(QObject *parent) - : QObject (parent) + : QObject(parent) { using namespace Core; using namespace ProjectExplorer; @@ -91,7 +91,7 @@ void LanguageClient::LanguageClientManager::addClient(Client *client) &Client::initialized, managerInstance, [client](const LanguageServerProtocol::ServerCapabilities &capabilities) { - managerInstance->m_currentDocumentLocatorFilter.updateCurrentClient(); + emit managerInstance->clientInitialized(client); managerInstance->m_inspector.clientInitialized(client->name(), capabilities); }); connect(client, diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index 6ceca307a61..db6357ee9e1 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -80,6 +80,7 @@ public: signals: void clientAdded(Client *client); + void clientInitialized(Client *client); void clientRemoved(Client *client); void shutdownFinished(); @@ -102,7 +103,7 @@ private: QList m_currentSettings; // owned QMap> m_clientsForSetting; QHash> m_clientForDocument; - DocumentLocatorFilter m_currentDocumentLocatorFilter; + DocumentLocatorFilter m_currentDocumentLocatorFilter{this}; WorkspaceLocatorFilter m_workspaceLocatorFilter; WorkspaceClassLocatorFilter m_workspaceClassLocatorFilter; WorkspaceMethodLocatorFilter m_workspaceMethodLocatorFilter; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 29619496c50..f8b14f04bf6 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -24,7 +24,7 @@ using namespace LanguageServerProtocol; namespace LanguageClient { -DocumentLocatorFilter::DocumentLocatorFilter() +DocumentLocatorFilter::DocumentLocatorFilter(LanguageClientManager *languageManager) { setId(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DISPLAY_NAME)); @@ -35,6 +35,8 @@ DocumentLocatorFilter::DocumentLocatorFilter() setPriority(ILocatorFilter::Low); connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, &DocumentLocatorFilter::updateCurrentClient); + connect(languageManager, &LanguageClientManager::clientInitialized, + this, &DocumentLocatorFilter::updateCurrentClient); } void DocumentLocatorFilter::updateCurrentClient() diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 58d8560c8e7..e37b013ef71 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -19,13 +19,14 @@ namespace Core { class IEditor; } namespace LanguageClient { +class LanguageClientManager; + class LANGUAGECLIENT_EXPORT DocumentLocatorFilter : public Core::ILocatorFilter { Q_OBJECT public: - DocumentLocatorFilter(); + DocumentLocatorFilter(LanguageClientManager *languageManager); - void updateCurrentClient(); void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; @@ -40,6 +41,7 @@ protected: Utils::FilePath m_currentFilePath; private: + void updateCurrentClient(); void updateSymbols(const LanguageServerProtocol::DocumentUri &uri, const LanguageServerProtocol::DocumentSymbolsResult &symbols); void resetSymbols(); From 38687119958dc2b63c27f7f8d2e852a9a9904c51 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Mar 2023 10:30:46 +0100 Subject: [PATCH 0317/1447] RemoteLinux: Merge SshProcessInterface and LinuxProcessInterface Change-Id: I961f65551a4c3146e8bab220b7c37a76c3f9fb38 Reviewed-by: Christian Kandeler --- src/plugins/boot2qt/qdbdevice.cpp | 7 +- src/plugins/remotelinux/CMakeLists.txt | 1 - src/plugins/remotelinux/linuxdevice.cpp | 245 ++++++++---------- src/plugins/remotelinux/linuxdevice.h | 4 +- .../remotelinux/linuxprocessinterface.h | 33 +-- src/plugins/remotelinux/remotelinux.qbs | 1 - src/plugins/remotelinux/sshprocessinterface.h | 50 ---- 7 files changed, 125 insertions(+), 216 deletions(-) delete mode 100644 src/plugins/remotelinux/sshprocessinterface.h diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index 90568f42641..c595645a444 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -30,11 +30,10 @@ using namespace Utils; namespace Qdb::Internal { -class QdbProcessImpl : public LinuxProcessInterface +class QdbProcessImpl : public SshProcessInterface { public: - QdbProcessImpl(const LinuxDevice *linuxDevice) - : LinuxProcessInterface(linuxDevice) {} + QdbProcessImpl(const IDevice::ConstPtr &device) : SshProcessInterface(device) {} ~QdbProcessImpl() { killIfRunning(); } private: @@ -124,7 +123,7 @@ ProjectExplorer::IDeviceWidget *QdbDevice::createWidget() ProcessInterface *QdbDevice::createProcessInterface() const { - return new QdbProcessImpl(this); + return new QdbProcessImpl(sharedFromThis()); } void QdbDevice::setSerialNumber(const QString &serial) diff --git a/src/plugins/remotelinux/CMakeLists.txt b/src/plugins/remotelinux/CMakeLists.txt index 2899475f13d..c37c31d24af 100644 --- a/src/plugins/remotelinux/CMakeLists.txt +++ b/src/plugins/remotelinux/CMakeLists.txt @@ -28,7 +28,6 @@ add_qtc_plugin(RemoteLinux remotelinuxsignaloperation.cpp remotelinuxsignaloperation.h rsyncdeploystep.cpp rsyncdeploystep.h sshkeycreationdialog.cpp sshkeycreationdialog.h - sshprocessinterface.h tarpackagecreationstep.cpp tarpackagecreationstep.h tarpackagedeploystep.cpp tarpackagedeploystep.h ) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 2ed875b07a8..a51a7d3bf03 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -11,7 +11,6 @@ #include "remotelinux_constants.h" #include "remotelinuxsignaloperation.h" #include "remotelinuxtr.h" -#include "sshprocessinterface.h" #include #include @@ -361,10 +360,8 @@ Environment LinuxDeviceFileAccess::deviceEnvironment() const class SshProcessInterfacePrivate : public QObject { - Q_OBJECT - public: - SshProcessInterfacePrivate(SshProcessInterface *sshInterface, LinuxDevicePrivate *devicePrivate); + SshProcessInterfacePrivate(SshProcessInterface *sshInterface, const IDevice::ConstPtr &device); void start(); @@ -388,7 +385,6 @@ public: IDevice::ConstPtr m_device; std::unique_ptr m_connectionHandle; QtcProcess m_process; - LinuxDevicePrivate *m_devicePrivate = nullptr; QString m_socketFilePath; SshParameters m_sshParameters; @@ -396,38 +392,22 @@ public: bool m_killed = false; ProcessResultData m_result; + + QByteArray m_output; + QByteArray m_error; + bool m_pidParsed = false; }; -SshProcessInterface::SshProcessInterface(const LinuxDevice *linuxDevice) - : d(new SshProcessInterfacePrivate(this, linuxDevice->d)) -{ -} +SshProcessInterface::SshProcessInterface(const IDevice::ConstPtr &device) + : d(new SshProcessInterfacePrivate(this, device)) +{} SshProcessInterface::~SshProcessInterface() { + killIfRunning(); delete d; } -void SshProcessInterface::handleStarted(qint64 processId) -{ - emitStarted(processId); -} - -void SshProcessInterface::handleDone(const ProcessResultData &resultData) -{ - emit done(resultData); -} - -void SshProcessInterface::handleReadyReadStandardOutput(const QByteArray &outputData) -{ - emit readyRead(outputData, {}); -} - -void SshProcessInterface::handleReadyReadStandardError(const QByteArray &errorData) -{ - emit readyRead({}, errorData); -} - void SshProcessInterface::emitStarted(qint64 processId) { d->m_processId = processId; @@ -464,11 +444,6 @@ bool SshProcessInterface::runInShell(const CommandLine &command, const QByteArra return isFinished; } -IDevice::ConstPtr SshProcessInterface::device() const -{ - return d->m_device; -} - void SshProcessInterface::start() { d->start(); @@ -498,17 +473,7 @@ void SshProcessInterface::sendControlSignal(ControlSignal controlSignal) handleSendControlSignal(controlSignal); } -LinuxProcessInterface::LinuxProcessInterface(const LinuxDevice *linuxDevice) - : SshProcessInterface(linuxDevice) -{ -} - -LinuxProcessInterface::~LinuxProcessInterface() -{ - killIfRunning(); -} - -void LinuxProcessInterface::handleSendControlSignal(ControlSignal controlSignal) +void SshProcessInterface::handleSendControlSignal(ControlSignal controlSignal) { QTC_ASSERT(controlSignal != ControlSignal::KickOff, return); QTC_ASSERT(controlSignal != ControlSignal::CloseWriteChannel, return); @@ -521,67 +486,43 @@ void LinuxProcessInterface::handleSendControlSignal(ControlSignal controlSignal) runInShell(command); } -QString LinuxProcessInterface::fullCommandLine(const CommandLine &commandLine) const +void SshProcessInterfacePrivate::handleStarted() { - CommandLine cmd; + const qint64 processId = m_process.usesTerminal() ? m_process.processId() : 0; - if (!commandLine.isEmpty() && device()->extraData(Constants::SourceProfile).toBool()) { - const QStringList rcFilesToSource = {"/etc/profile", "$HOME/.profile"}; - for (const QString &filePath : rcFilesToSource) { - cmd.addArgs({"test", "-f", filePath}); - cmd.addArgs("&&", CommandLine::Raw); - cmd.addArgs({".", filePath}); - cmd.addArgs(";", CommandLine::Raw); - } - } - - if (!m_setup.m_workingDirectory.isEmpty()) { - cmd.addArgs({"cd", m_setup.m_workingDirectory.path()}); - cmd.addArgs("&&", CommandLine::Raw); - } - - if (m_setup.m_terminalMode == TerminalMode::Off && !m_setup.m_ptyData) - cmd.addArgs(QString("echo ") + s_pidMarker + "$$" + s_pidMarker + " && ", CommandLine::Raw); - - const Environment &env = m_setup.m_environment; - env.forEachEntry([&](const QString &key, const QString &value, bool) { - cmd.addArgs(key + "='" + env.expandVariables(value) + '\'', CommandLine::Raw); - }); - - if (m_setup.m_terminalMode == TerminalMode::Off && !m_setup.m_ptyData) - cmd.addArg("exec"); - - if (!commandLine.isEmpty()) - cmd.addCommandLineAsArgs(commandLine, CommandLine::Raw); - return cmd.arguments(); -} - -void LinuxProcessInterface::handleStarted(qint64 processId) -{ // Don't emit started() when terminal is off, // it's being done later inside handleReadyReadStandardOutput(). - if (m_setup.m_terminalMode == TerminalMode::Off && !m_setup.m_ptyData) + if (q->m_setup.m_terminalMode == TerminalMode::Off && !q->m_setup.m_ptyData) return; m_pidParsed = true; - emitStarted(processId); + q->emitStarted(processId); } -void LinuxProcessInterface::handleDone(const ProcessResultData &resultData) +void SshProcessInterfacePrivate::handleDone() { - ProcessResultData finalData = resultData; + if (m_connectionHandle) // TODO: should it disconnect from signals first? + m_connectionHandle.release()->deleteLater(); + + ProcessResultData finalData = m_process.resultData(); if (!m_pidParsed) { finalData.m_error = QProcess::FailedToStart; finalData.m_errorString = Utils::joinStrings({finalData.m_errorString, QString::fromLocal8Bit(m_error)}, '\n'); } - emit done(finalData); + emit q->done(finalData); } -void LinuxProcessInterface::handleReadyReadStandardOutput(const QByteArray &outputData) +void SshProcessInterfacePrivate::handleReadyReadStandardOutput() { + // By default this forwards readyRead immediately, but only buffers the + // output in case the start signal is not emitted yet. + // In case the pid can be parsed now, the delayed started() is + // emitted, and any previously buffered output emitted now. + const QByteArray outputData = m_process.readAllRawStandardOutput(); + if (m_pidParsed) { - emit readyRead(outputData, {}); + emit q->readyRead(outputData, {}); return; } @@ -608,31 +549,34 @@ void LinuxProcessInterface::handleReadyReadStandardOutput(const QByteArray &outp // We don't want to show output from e.g. /etc/profile. m_output = m_output.mid(endMarkerOffset + endMarkerLength); - emitStarted(processId); + q->emitStarted(processId); if (!m_output.isEmpty() || !m_error.isEmpty()) - emit readyRead(m_output, m_error); + emit q->readyRead(m_output, m_error); m_output.clear(); m_error.clear(); } -void LinuxProcessInterface::handleReadyReadStandardError(const QByteArray &errorData) +void SshProcessInterfacePrivate::handleReadyReadStandardError() { + // By default forwards readyRead immediately, but buffers it in + // case the start signal is not emitted yet. + const QByteArray errorData = m_process.readAllRawStandardError(); + if (m_pidParsed) { - emit readyRead({}, errorData); + emit q->readyRead({}, errorData); return; } m_error.append(errorData); } SshProcessInterfacePrivate::SshProcessInterfacePrivate(SshProcessInterface *sshInterface, - LinuxDevicePrivate *devicePrivate) + const IDevice::ConstPtr &device) : QObject(sshInterface) , q(sshInterface) - , m_device(devicePrivate->q->sharedFromThis()) + , m_device(device) , m_process(this) - , m_devicePrivate(devicePrivate) { connect(&m_process, &QtcProcess::started, this, &SshProcessInterfacePrivate::handleStarted); connect(&m_process, &QtcProcess::done, this, &SshProcessInterfacePrivate::handleDone); @@ -646,19 +590,22 @@ void SshProcessInterfacePrivate::start() { clearForStart(); - m_sshParameters = m_devicePrivate->q->sshParameters(); + m_sshParameters = m_device->sshParameters(); // TODO: Do we really need it for master process? m_sshParameters.x11DisplayName = q->m_setup.m_extraData.value("Ssh.X11ForwardToDisplay").toString(); if (SshSettings::connectionSharingEnabled()) { m_connecting = true; - m_connectionHandle.reset(new SshConnectionHandle(m_devicePrivate->q->sharedFromThis())); + m_connectionHandle.reset(new SshConnectionHandle(m_device)); m_connectionHandle->setParent(this); connect(m_connectionHandle.get(), &SshConnectionHandle::connected, this, &SshProcessInterfacePrivate::handleConnected); connect(m_connectionHandle.get(), &SshConnectionHandle::disconnected, this, &SshProcessInterfacePrivate::handleDisconnected); - m_devicePrivate->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); + auto linuxDevice = m_device.dynamicCast(); + QTC_ASSERT(linuxDevice, handleDone(); return); + linuxDevice->connectionAccess() + ->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); } else { doStart(); } @@ -685,34 +632,6 @@ void SshProcessInterfacePrivate::handleDisconnected(const ProcessResultData &res emit q->done(resultData); // TODO: don't emit done() on process finished afterwards } -void SshProcessInterfacePrivate::handleStarted() -{ - const qint64 processId = m_process.usesTerminal() ? m_process.processId() : 0; - // By default emits started signal, Linux impl doesn't emit it when terminal is off. - q->handleStarted(processId); -} - -void SshProcessInterfacePrivate::handleDone() -{ - if (m_connectionHandle) // TODO: should it disconnect from signals first? - m_connectionHandle.release()->deleteLater(); - q->handleDone(m_process.resultData()); -} - -void SshProcessInterfacePrivate::handleReadyReadStandardOutput() -{ - // By default emits signal. LinuxProcessImpl does custom parsing for processId - // and emits delayed start() - only when terminal is off. - q->handleReadyReadStandardOutput(m_process.readAllRawStandardOutput()); -} - -void SshProcessInterfacePrivate::handleReadyReadStandardError() -{ - // By default emits signal. LinuxProcessImpl buffers the error channel until - // it emits delayed start() - only when terminal is off. - q->handleReadyReadStandardError(m_process.readAllRawStandardError()); -} - void SshProcessInterfacePrivate::clearForStart() { m_result = {}; @@ -757,11 +676,44 @@ CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const options << m_sshParameters.host(); cmd.addArgs(options); - CommandLine remoteWithLocalPath = q->m_setup.m_commandLine; - FilePath executable = FilePath::fromParts({}, {}, remoteWithLocalPath.executable().path()); - remoteWithLocalPath.setExecutable(executable); + CommandLine commandLine = q->m_setup.m_commandLine; + FilePath executable = FilePath::fromParts({}, {}, commandLine.executable().path()); + commandLine.setExecutable(executable); + + CommandLine inner; + + if (!commandLine.isEmpty() && m_device->extraData(Constants::SourceProfile).toBool()) { + const QStringList rcFilesToSource = {"/etc/profile", "$HOME/.profile"}; + for (const QString &filePath : rcFilesToSource) { + inner.addArgs({"test", "-f", filePath}); + inner.addArgs("&&", CommandLine::Raw); + inner.addArgs({".", filePath}); + inner.addArgs(";", CommandLine::Raw); + } + } + + if (!q->m_setup.m_workingDirectory.isEmpty()) { + inner.addArgs({"cd", q->m_setup.m_workingDirectory.path()}); + inner.addArgs("&&", CommandLine::Raw); + } + + if (q->m_setup.m_terminalMode == TerminalMode::Off && !q->m_setup.m_ptyData) + inner.addArgs(QString("echo ") + s_pidMarker + "$$" + s_pidMarker + " && ", CommandLine::Raw); + + const Environment &env = q->m_setup.m_environment; + env.forEachEntry([&](const QString &key, const QString &value, bool) { + inner.addArgs(key + "='" + env.expandVariables(value) + '\'', CommandLine::Raw); + }); + + if (q->m_setup.m_terminalMode == TerminalMode::Off && !q->m_setup.m_ptyData) + inner.addArg("exec"); + + if (!commandLine.isEmpty()) + inner.addCommandLineAsArgs(commandLine, CommandLine::Raw); + + + cmd.addArg(inner.arguments()); - cmd.addArg(q->fullCommandLine(remoteWithLocalPath)); return cmd; } @@ -1065,7 +1017,7 @@ bool LinuxDevice::handlesFile(const FilePath &filePath) const ProcessInterface *LinuxDevice::createProcessInterface() const { - return new LinuxProcessInterface(this); + return new SshProcessInterface(sharedFromThis()); } LinuxDevicePrivate::LinuxDevicePrivate(LinuxDevice *parent) @@ -1160,10 +1112,9 @@ class SshTransferInterface : public FileTransferInterface Q_OBJECT protected: - SshTransferInterface(const FileTransferSetupData &setup, LinuxDevicePrivate *devicePrivate) + SshTransferInterface(const FileTransferSetupData &setup, const IDevice::ConstPtr &device) : FileTransferInterface(setup) - , m_device(devicePrivate->q->sharedFromThis()) - , m_devicePrivate(devicePrivate) + , m_device(device) , m_process(this) { m_direction = m_setup.m_files.isEmpty() ? FileTransferDirection::Invalid @@ -1228,7 +1179,10 @@ private: this, &SshTransferInterface::handleConnected); connect(m_connectionHandle.get(), &SshConnectionHandle::disconnected, this, &SshTransferInterface::handleDisconnected); - m_devicePrivate->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); + auto linuxDevice = m_device.dynamicCast(); + QTC_ASSERT(linuxDevice, startFailed("No Linux device"); return); + linuxDevice->connectionAccess() + ->attachToSharedConnection(m_connectionHandle.get(), m_sshParameters); } else { startImpl(); } @@ -1256,7 +1210,6 @@ private: } IDevice::ConstPtr m_device; - LinuxDevicePrivate *m_devicePrivate = nullptr; SshParameters m_sshParameters; FileTransferDirection m_direction = FileTransferDirection::Invalid; // helper @@ -1271,8 +1224,9 @@ private: class SftpTransferImpl : public SshTransferInterface { public: - SftpTransferImpl(const FileTransferSetupData &setup, LinuxDevicePrivate *devicePrivate) - : SshTransferInterface(setup, devicePrivate) { } + SftpTransferImpl(const FileTransferSetupData &setup, const IDevice::ConstPtr &device) + : SshTransferInterface(setup, device) + {} private: void startImpl() final @@ -1328,8 +1282,8 @@ private: class RsyncTransferImpl : public SshTransferInterface { public: - RsyncTransferImpl(const FileTransferSetupData &setup, LinuxDevicePrivate *devicePrivate) - : SshTransferInterface(setup, devicePrivate) + RsyncTransferImpl(const FileTransferSetupData &setup, const IDevice::ConstPtr &device) + : SshTransferInterface(setup, device) { } private: @@ -1421,7 +1375,7 @@ private: class GenericTransferImpl : public FileTransferInterface { public: - GenericTransferImpl(const FileTransferSetupData &setup, LinuxDevicePrivate *) + GenericTransferImpl(const FileTransferSetupData &setup) : FileTransferInterface(setup) {} @@ -1483,14 +1437,19 @@ FileTransferInterface *LinuxDevice::createFileTransferInterface( const FileTransferSetupData &setup) const { switch (setup.m_method) { - case FileTransferMethod::Sftp: return new SftpTransferImpl(setup, d); - case FileTransferMethod::Rsync: return new RsyncTransferImpl(setup, d); - case FileTransferMethod::GenericCopy: return new GenericTransferImpl(setup, d); + case FileTransferMethod::Sftp: return new SftpTransferImpl(setup, sharedFromThis()); + case FileTransferMethod::Rsync: return new RsyncTransferImpl(setup, sharedFromThis()); + case FileTransferMethod::GenericCopy: return new GenericTransferImpl(setup); } QTC_CHECK(false); return {}; } +LinuxDevicePrivate *LinuxDevice::connectionAccess() const +{ + return d; +} + namespace Internal { // Factory diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index ac65d6e89c9..fd111447201 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -41,12 +41,12 @@ public: ProjectExplorer::FileTransferInterface *createFileTransferInterface( const ProjectExplorer::FileTransferSetupData &setup) const override; + class LinuxDevicePrivate *connectionAccess() const; + protected: LinuxDevice(); class LinuxDevicePrivate *d; - friend class SshProcessInterface; - friend class SshTransferInterface; }; namespace Internal { diff --git a/src/plugins/remotelinux/linuxprocessinterface.h b/src/plugins/remotelinux/linuxprocessinterface.h index 949c5934200..e2a8e82fc8c 100644 --- a/src/plugins/remotelinux/linuxprocessinterface.h +++ b/src/plugins/remotelinux/linuxprocessinterface.h @@ -5,32 +5,35 @@ #include "remotelinux_export.h" -#include "sshprocessinterface.h" +#include "linuxdevice.h" + +#include namespace RemoteLinux { -class LinuxDevice; class SshProcessInterfacePrivate; -class REMOTELINUX_EXPORT LinuxProcessInterface : public SshProcessInterface +class REMOTELINUX_EXPORT SshProcessInterface : public Utils::ProcessInterface { public: - LinuxProcessInterface(const LinuxDevice *linuxDevice); - ~LinuxProcessInterface(); + explicit SshProcessInterface(const ProjectExplorer::IDevice::ConstPtr &device); + ~SshProcessInterface(); + +protected: + void emitStarted(qint64 processId); + void killIfRunning(); + qint64 processId() const; + bool runInShell(const Utils::CommandLine &command, const QByteArray &data = {}); private: - void handleSendControlSignal(Utils::ControlSignal controlSignal) override; + virtual void handleSendControlSignal(Utils::ControlSignal controlSignal); - void handleStarted(qint64 processId) final; - void handleDone(const Utils::ProcessResultData &resultData) final; - void handleReadyReadStandardOutput(const QByteArray &outputData) final; - void handleReadyReadStandardError(const QByteArray &errorData) final; + void start() final; + qint64 write(const QByteArray &data) final; + void sendControlSignal(Utils::ControlSignal controlSignal) final; - QString fullCommandLine(const Utils::CommandLine &commandLine) const final; - - QByteArray m_output; - QByteArray m_error; - bool m_pidParsed = false; + friend class SshProcessInterfacePrivate; + SshProcessInterfacePrivate *d = nullptr; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index 7881cab47de..5235dbaef5e 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -62,7 +62,6 @@ Project { "rsyncdeploystep.h", "sshkeycreationdialog.cpp", "sshkeycreationdialog.h", - "sshprocessinterface.h", "tarpackagecreationstep.cpp", "tarpackagecreationstep.h", "tarpackagedeploystep.cpp", diff --git a/src/plugins/remotelinux/sshprocessinterface.h b/src/plugins/remotelinux/sshprocessinterface.h deleted file mode 100644 index bd896a0a4b3..00000000000 --- a/src/plugins/remotelinux/sshprocessinterface.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "remotelinux_export.h" - -#include - -#include - -namespace RemoteLinux { - -class LinuxDevice; -class SshProcessInterfacePrivate; - -class REMOTELINUX_EXPORT SshProcessInterface : public Utils::ProcessInterface -{ -public: - SshProcessInterface(const LinuxDevice *linuxDevice); - ~SshProcessInterface(); - -protected: - void emitStarted(qint64 processId); - // To be called from leaf destructor. - // Can't call it from SshProcessInterface destructor as it calls virtual method. - void killIfRunning(); - qint64 processId() const; - bool runInShell(const Utils::CommandLine &command, const QByteArray &data = {}); - - ProjectExplorer::IDevice::ConstPtr device() const; - -private: - virtual void handleStarted(qint64 processId); - virtual void handleDone(const Utils::ProcessResultData &resultData); - virtual void handleReadyReadStandardOutput(const QByteArray &outputData); - virtual void handleReadyReadStandardError(const QByteArray &errorData); - virtual void handleSendControlSignal(Utils::ControlSignal controlSignal) = 0; - - virtual QString fullCommandLine(const Utils::CommandLine &commandLine) const = 0; - - void start() final; - qint64 write(const QByteArray &data) final; - void sendControlSignal(Utils::ControlSignal controlSignal) final; - - friend class SshProcessInterfacePrivate; - SshProcessInterfacePrivate *d = nullptr; -}; - -} // namespace RemoteLinux From 5256f08b6dcd6fe5abdf80427626b56194ca209a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 17 Mar 2023 12:03:13 +0100 Subject: [PATCH 0318/1447] AutoTest: Remove unused code Change-Id: Ib2388e7566eaaac05a358c605418d9cb58825c39 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/autotest/testresultdelegate.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/plugins/autotest/testresultdelegate.h b/src/plugins/autotest/testresultdelegate.h index c5a4919a71e..f7d6aa1ab27 100644 --- a/src/plugins/autotest/testresultdelegate.h +++ b/src/plugins/autotest/testresultdelegate.h @@ -38,7 +38,6 @@ private: public: LayoutPositions(QStyleOptionViewItem &options, const TestResultFilterModel *filterModel) : m_top(options.rect.top()), - m_bottom(options.rect.bottom()), m_left(options.rect.left()), m_right(options.rect.right()) { @@ -57,20 +56,15 @@ private: int top() const { return m_top + ITEM_MARGIN; } int left() const { return m_left + ITEM_MARGIN; } int right() const { return m_right - ITEM_MARGIN; } - int bottom() const { return m_bottom; } int minimumHeight() const { return ICON_SIZE + 2 * ITEM_MARGIN; } int iconSize() const { return ICON_SIZE; } - int fontHeight() const { return m_fontHeight; } int typeAreaLeft() const { return left() + ICON_SIZE + ITEM_SPACING; } - int typeAreaWidth() const { return m_typeAreaWidth; } int textAreaLeft() const { return typeAreaLeft() + m_typeAreaWidth + ITEM_SPACING; } int textAreaWidth() const { return fileAreaLeft() - ITEM_SPACING - textAreaLeft(); } int fileAreaLeft() const { return lineAreaLeft() - ITEM_SPACING - m_realFileLength; } int lineAreaLeft() const { return right() - m_maxLineLength; } - QRect typeArea() const { return QRect(typeAreaLeft(), top(), - typeAreaWidth(), m_fontHeight); } QRect textArea() const { return QRect(textAreaLeft(), top(), textAreaWidth(), m_fontHeight); } QRect fileArea() const { return QRect(fileAreaLeft(), top(), @@ -84,7 +78,6 @@ private: int m_maxLineLength; int m_realFileLength; int m_top; - int m_bottom; int m_left; int m_right; int m_fontHeight; From 7d4f123842ea937de4390b2ba783c7c13f9ea55a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 23 Jan 2023 13:43:58 +0100 Subject: [PATCH 0319/1447] Python: add create venv action The action can be triggered from the interpreter chooser of the editor toolbar. Change-Id: Ie23b68a3790525ea02883ef359b357a0d317b2f5 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/python/pythoneditor.cpp | 37 +++++++++--- src/plugins/python/pythonsettings.cpp | 81 ++++++++++++++++++++++++--- src/plugins/python/pythonsettings.h | 4 +- src/plugins/python/pythonutils.cpp | 21 +++++++ src/plugins/python/pythonutils.h | 4 ++ 5 files changed, 130 insertions(+), 17 deletions(-) diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index f758ae3d9b6..42771fc91a2 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -163,6 +163,7 @@ void PythonEditorWidget::setUserDefinedPython(const Interpreter &interpreter) } } definePythonForDocument(textDocument()->filePath(), interpreter.command); + updateInterpretersSelector(); pythonDocument->checkForPyls(); } @@ -212,33 +213,51 @@ void PythonEditorWidget::updateInterpretersSelector() m_interpreters->setText(text); }; - const FilePath currentInterpreter = detectPython(textDocument()->filePath()); + const FilePath currentInterpreterPath = detectPython(textDocument()->filePath()); const QList configuredInterpreters = PythonSettings::interpreters(); - bool foundCurrentInterpreter = false; auto interpretersGroup = new QActionGroup(menu); interpretersGroup->setExclusive(true); + std::optional currentInterpreter; for (const Interpreter &interpreter : configuredInterpreters) { QAction *action = interpretersGroup->addAction(interpreter.name); connect(action, &QAction::triggered, this, [this, interpreter]() { setUserDefinedPython(interpreter); }); action->setCheckable(true); - if (!foundCurrentInterpreter && interpreter.command == currentInterpreter) { - foundCurrentInterpreter = true; + if (!currentInterpreter && interpreter.command == currentInterpreterPath) { + currentInterpreter = interpreter; action->setChecked(true); setButtonText(interpreter.name); m_interpreters->setToolTip(interpreter.command.toUserOutput()); } } menu->addActions(interpretersGroup->actions()); - if (!foundCurrentInterpreter) { - if (currentInterpreter.exists()) - setButtonText(currentInterpreter.toUserOutput()); + if (!currentInterpreter) { + if (currentInterpreterPath.exists()) + setButtonText(currentInterpreterPath.toUserOutput()); else setButtonText(Tr::tr("No Python Selected")); } - if (!interpretersGroup->actions().isEmpty()) - menu->addSeparator(); + if (!interpretersGroup->actions().isEmpty()) { + menu->addSeparator(); + auto venvAction = menu->addAction(Tr::tr("Create Virtual Environment")); + connect(venvAction, + &QAction::triggered, + this, + [self = QPointer(this), currentInterpreter]() { + if (!currentInterpreter) + return; + auto callback = [self](const std::optional &venvInterpreter) { + if (self && venvInterpreter) + self->setUserDefinedPython(*venvInterpreter); + }; + PythonSettings::createVirtualEnvironment(self->textDocument() + ->filePath() + .parentDir(), + *currentInterpreter, + callback); + }); + } auto settingsAction = menu->addAction(Tr::tr("Manage Python Interpreters")); connect(settingsAction, &QAction::triggered, this, []() { Core::ICore::showOptionsDialog(Constants::C_PYTHONOPTIONS_PAGE_ID); diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 9306fe3b6f4..f22f0c3c8ce 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -6,6 +6,7 @@ #include "pythonconstants.h" #include "pythonplugin.h" #include "pythontr.h" +#include "pythonutils.h" #include #include @@ -30,19 +31,22 @@ #include #include +#include +#include +#include #include +#include +#include +#include +#include #include -#include #include +#include #include #include #include -#include #include -#include -#include -#include -#include +#include using namespace ProjectExplorer; using namespace Utils; @@ -69,7 +73,7 @@ static Interpreter createInterpreter(const FilePath &python, result.name = defaultName; QDir pythonDir(python.parentDir().toString()); if (pythonDir.exists() && pythonDir.exists("activate") && pythonDir.cdUp()) - result.name += QString(" (%1 Virtual Environment)").arg(pythonDir.dirName()); + result.name += QString(" (%1)").arg(pythonDir.dirName()); if (!suffix.isEmpty()) result.name += ' ' + suffix; @@ -769,12 +773,75 @@ void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefau saveSettings(); } +Interpreter PythonSettings::addInterpreter(const FilePath &interpreterPath, bool isDefault) +{ + const Interpreter interpreter = createInterpreter(interpreterPath, {}); + addInterpreter(interpreter, isDefault); + return interpreter; +} + PythonSettings *PythonSettings::instance() { QTC_CHECK(settingsInstance); return settingsInstance; } +void PythonSettings::createVirtualEnvironment( + const FilePath &startDirectory, + const Interpreter &defaultInterpreter, + const std::function)> &callback) +{ + QDialog dialog; + dialog.setModal(true); + auto layout = new QFormLayout(&dialog); + auto interpreters = new QComboBox; + const QString preselectedId = defaultInterpreter.id.isEmpty() + ? PythonSettings::defaultInterpreter().id + : defaultInterpreter.id; + for (const Interpreter &interpreter : PythonSettings::interpreters()) { + interpreters->addItem(interpreter.name, interpreter.id); + if (!preselectedId.isEmpty() && interpreter.id == preselectedId) + interpreters->setCurrentIndex(interpreters->count() - 1); + } + layout->addRow(Tr::tr("Python Interpreter"), interpreters); + auto pathChooser = new PathChooser(); + pathChooser->setInitialBrowsePathBackup(startDirectory); + pathChooser->setExpectedKind(PathChooser::Directory); + pathChooser->setPromptDialogTitle(Tr::tr("New Python Virtual Environment Directory")); + layout->addRow(Tr::tr("Virtual Environment Directory"), pathChooser); + auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel); + auto createButton = buttons->addButton(Tr::tr("Create"), QDialogButtonBox::AcceptRole); + createButton->setEnabled(false); + connect(pathChooser, + &PathChooser::validChanged, + createButton, + [createButton](bool valid) { createButton->setEnabled(valid); }); + connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + layout->addRow(buttons); + dialog.setLayout(layout); + if (dialog.exec() == QDialog::Rejected) { + callback({}); + return; + } + + const Interpreter interpreter = PythonSettings::interpreter( + interpreters->currentData().toString()); + + auto venvDir = pathChooser->filePath(); + createVenv(interpreter.command, venvDir, [venvDir, callback](bool success){ + std::optional result; + if (success) { + FilePath venvPython = venvDir.osType() == Utils::OsTypeWindows ? venvDir / "Scripts" + : venvDir / "bin"; + venvPython = venvPython.pathAppended("python").withExecutableSuffix(); + if (venvPython.exists()) + result = PythonSettings::addInterpreter(venvPython); + } + callback(result); + }); +} + QList PythonSettings::detectPythonVenvs(const FilePath &path) { QList result; diff --git a/src/plugins/python/pythonsettings.h b/src/plugins/python/pythonsettings.h index 693c7322085..2e27e266162 100644 --- a/src/plugins/python/pythonsettings.h +++ b/src/plugins/python/pythonsettings.h @@ -24,12 +24,14 @@ public: static Interpreter interpreter(const QString &interpreterId); static void setInterpreter(const QList &interpreters, const QString &defaultId); static void addInterpreter(const Interpreter &interpreter, bool isDefault = false); + static Interpreter addInterpreter(const Utils::FilePath &interpreterPath, + bool isDefault = false); static void setPyLSConfiguration(const QString &configuration); static bool pylsEnabled(); static void setPylsEnabled(const bool &enabled); static QString pylsConfiguration(); static PythonSettings *instance(); - + static void createVirtualEnvironment(const Utils::FilePath &startDirectory, const Interpreter &defaultInterpreter, const std::function)> &callback); static QList detectPythonVenvs(const Utils::FilePath &path); signals: diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 86356050928..1f89eef5b5f 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -8,6 +8,7 @@ #include "pythontr.h" #include +#include #include #include @@ -164,4 +165,24 @@ PythonProject *pythonProjectForFile(const FilePath &pythonFile) return nullptr; } +void createVenv(const Utils::FilePath &python, + const Utils::FilePath &venvPath, + const std::function &callback) +{ + QTC_ASSERT(python.isExecutableFile(), callback(false); return); + QTC_ASSERT(!venvPath.exists() || venvPath.isDir(), callback(false); return); + + const CommandLine command(python, QStringList{"-m", "venv", venvPath.toUserOutput()}); + + auto process = new QtcProcess; + auto progress = new Core::ProcessProgress(process); + progress->setDisplayName(Tr::tr("Create Python venv")); + QObject::connect(process, &QtcProcess::done, [process, callback](){ + callback(process->result() == ProcessResult::FinishedWithSuccess); + process->deleteLater(); + }); + process->setCommand(command); + process->start(); +} + } // Python::Internal diff --git a/src/plugins/python/pythonutils.h b/src/plugins/python/pythonutils.h index 8d5b06974ef..f3e685b4ae0 100644 --- a/src/plugins/python/pythonutils.h +++ b/src/plugins/python/pythonutils.h @@ -16,4 +16,8 @@ QString pythonName(const Utils::FilePath &pythonPath); class PythonProject; PythonProject *pythonProjectForFile(const Utils::FilePath &pythonFile); +void createVenv(const Utils::FilePath &python, + const Utils::FilePath &venvPath, + const std::function &callback); + } // Python::Internal From 6dcc1771e3b69073a4560778b29b0ac3fa4d2c56 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 20 Mar 2023 11:42:41 +0100 Subject: [PATCH 0320/1447] LanguageClient: fix show message box Add a default close button and connect all language server defined buttons to accepted, so the message box gets closed when the user presses a button. Change-Id: I846eadf5953e75441bdc7910c2587a2fa098a388 Reviewed-by: Alexandru Croitor Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/languageclient/client.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 1a20d60541c..461e908bcf9 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -1669,10 +1669,15 @@ LanguageClientValue ClientPrivate::showMessageBox( } QHash itemForButton; if (const std::optional> actions = message.actions()) { - for (const MessageActionItem &action : *actions) - itemForButton.insert(box->addButton(action.title(), QMessageBox::InvalidRole), action); + auto button = box->addButton(QMessageBox::Close); + connect(button, &QPushButton::clicked, box, &QMessageBox::reject); + for (const MessageActionItem &action : *actions) { + connect(button, &QPushButton::clicked, box, &QMessageBox::accept); + itemForButton.insert(button, action); + } } - box->exec(); + if (box->exec() == QDialog::Rejected) + return {}; const MessageActionItem &item = itemForButton.value(box->clickedButton()); return item.isValid() ? LanguageClientValue(item) : LanguageClientValue(); From 8e9b8933256c1483f1f72ade010ea879550d40d7 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 20 Mar 2023 16:29:51 +0100 Subject: [PATCH 0321/1447] LanguageClient: Introduce ClientRequestTask This class is going to be used inside TaskTree. Change-Id: Ia227a8f41e4557b45053cb018497a7eca8f8ac6a Reviewed-by: Jarek Kobus Reviewed-by: Reviewed-by: Qt CI Bot --- .../languageserverprotocol/jsonrpcmessages.h | 1 + src/libs/languageserverprotocol/workspace.h | 2 +- src/plugins/languageclient/CMakeLists.txt | 1 + .../languageclient/clientrequesttask.cpp | 39 ++++++++++ .../languageclient/clientrequesttask.h | 78 +++++++++++++++++++ src/plugins/languageclient/languageclient.qbs | 2 + 6 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/plugins/languageclient/clientrequesttask.cpp create mode 100644 src/plugins/languageclient/clientrequesttask.h diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.h b/src/libs/languageserverprotocol/jsonrpcmessages.h index 0b018d7f54a..680bff95782 100644 --- a/src/libs/languageserverprotocol/jsonrpcmessages.h +++ b/src/libs/languageserverprotocol/jsonrpcmessages.h @@ -141,6 +141,7 @@ public: void setMethod(const QString &method) { m_jsonObject.insert(methodKey, method); } + using Parameters = Params; std::optional params() const { const QJsonValue ¶ms = m_jsonObject.value(paramsKey); diff --git a/src/libs/languageserverprotocol/workspace.h b/src/libs/languageserverprotocol/workspace.h index efe77a68ec2..42cfcf451d2 100644 --- a/src/libs/languageserverprotocol/workspace.h +++ b/src/libs/languageserverprotocol/workspace.h @@ -175,7 +175,7 @@ class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceSymbolRequest : public Request< LanguageClientArray, std::nullptr_t, WorkspaceSymbolParams> { public: - WorkspaceSymbolRequest(const WorkspaceSymbolParams ¶ms); + explicit WorkspaceSymbolRequest(const WorkspaceSymbolParams ¶ms); using Request::Request; constexpr static const char methodName[] = "workspace/symbol"; }; diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt index 8e1748a04a1..0677cdf867a 100644 --- a/src/plugins/languageclient/CMakeLists.txt +++ b/src/plugins/languageclient/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(LanguageClient SOURCES callhierarchy.cpp callhierarchy.h client.cpp client.h + clientrequesttask.cpp clientrequesttask.h diagnosticmanager.cpp diagnosticmanager.h documentsymbolcache.cpp documentsymbolcache.h dynamiccapabilities.cpp dynamiccapabilities.h diff --git a/src/plugins/languageclient/clientrequesttask.cpp b/src/plugins/languageclient/clientrequesttask.cpp new file mode 100644 index 00000000000..c5503bd6947 --- /dev/null +++ b/src/plugins/languageclient/clientrequesttask.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "clientrequesttask.h" + +#include + +using namespace LanguageServerProtocol; + +namespace LanguageClient { + +ClientRequestTaskAdapter::ClientRequestTaskAdapter() +{ + task()->setResponseCallback([this](const WorkspaceSymbolRequest::Response &response){ + emit done(response.result().has_value()); + }); +} + +void ClientRequestTaskAdapter::start() +{ + task()->start(); +} + +bool WorkspaceSymbolRequestTask::preStartCheck() +{ + if (!ClientRequestTask::preStartCheck() || !client()->locatorsEnabled()) + return false; + + const std::optional> capability + = client()->capabilities().workspaceSymbolProvider(); + if (!capability.has_value()) + return false; + if (std::holds_alternative(*capability) && !std::get(*capability)) + return false; + + return true; +} + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/clientrequesttask.h b/src/plugins/languageclient/clientrequesttask.h new file mode 100644 index 00000000000..c2de15e7007 --- /dev/null +++ b/src/plugins/languageclient/clientrequesttask.h @@ -0,0 +1,78 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "languageclient_global.h" + +#include "client.h" + +#include +#include +#include +#include + +namespace LanguageClient { + + +template +class LANGUAGECLIENT_EXPORT ClientRequestTask +{ +public: + virtual ~ClientRequestTask() + { + if (m_id) + m_client->cancelRequest(*m_id); // In order to not to invoke a response callback anymore + } + + void setClient(Client *client) { m_client = client; } + Client *client() const { return m_client; } + void setParams(const typename Request::Parameters ¶ms) { m_params = params; } + + void start() + { + QTC_ASSERT(isRunning(), return); + QTC_ASSERT(preStartCheck(), m_callback({}); return); + + Request request(m_params); + request.setResponseCallback([this](const typename Request::Response &response) { + m_response = response; + m_id = {}; + m_callback(response); + }); + m_id = request.id(); + m_client->sendMessage(request); + } + + bool isRunning() const { return m_id.has_value(); } + virtual bool preStartCheck() { return m_client && m_client->reachable() && m_params.isValid(); } + + typename Request::Response response() const { return m_response; } + void setResponseCallback(typename Request::ResponseCallback callback) { m_callback = callback; } + +private: + Client *m_client = nullptr; + typename Request::Parameters m_params; + typename Request::ResponseCallback m_callback; + std::optional m_id; + typename Request::Response m_response; +}; + +class LANGUAGECLIENT_EXPORT WorkspaceSymbolRequestTask + : public ClientRequestTask +{ +public: + bool preStartCheck() override; +}; + +class LANGUAGECLIENT_EXPORT ClientRequestTaskAdapter + : public Utils::Tasking::TaskAdapter +{ +public: + ClientRequestTaskAdapter(); + void start() final; +}; + +} // namespace LanguageClient + +QTC_DECLARE_CUSTOM_TASK(WorkspaceSymbolRequest, LanguageClient::WorkspaceSymbolRequestTask); diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index 9a48caf9e3c..649308b9b9b 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -24,6 +24,8 @@ QtcPlugin { "callhierarchy.h", "client.cpp", "client.h", + "clientrequesttask.cpp", + "clientrequesttask.h", "diagnosticmanager.cpp", "diagnosticmanager.h", "documentsymbolcache.cpp", From 31d6990ab856e4f25166c635fd1e6ccc8041a521 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 14 Mar 2023 20:42:38 +0100 Subject: [PATCH 0322/1447] HelpIndexFilter: Simplify internals Implement properly prepareSearch() instead of scheduling a blocked call to caller thread from matchesFor() thread. Change-Id: Id417235b19da36675afb13cf9a6f35759fe9d66d Reviewed-by: Eike Ziller --- src/plugins/help/helpindexfilter.cpp | 57 ++++++++++------------------ src/plugins/help/helpindexfilter.h | 11 +----- 2 files changed, 22 insertions(+), 46 deletions(-) diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index de4e412ab9d..63578ef944d 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -16,7 +16,6 @@ #include #include #include -#include using namespace Core; using namespace Help; @@ -41,11 +40,25 @@ HelpIndexFilter::HelpIndexFilter() this, &HelpIndexFilter::invalidateCache); } -HelpIndexFilter::~HelpIndexFilter() = default; - -bool HelpIndexFilter::updateCache(QFutureInterface &future, - const QStringList &cache, const QString &entry) +void HelpIndexFilter::prepareSearch(const QString &entry) { + Q_UNUSED(entry) + if (!m_needsUpdate) + return; + + m_needsUpdate = false; + LocalHelpManager::setupGuiHelpEngine(); + m_allIndicesCache = LocalHelpManager::filterEngine()->indices({}); + m_lastIndicesCache.clear(); + m_lastEntry.clear(); +} + +QList HelpIndexFilter::matchesFor(QFutureInterface &future, + const QString &entry) +{ + const QStringList cache = m_lastEntry.isEmpty() || !entry.contains(m_lastEntry) + ? m_allIndicesCache : m_lastIndicesCache; + const Qt::CaseSensitivity cs = caseSensitivity(entry); QStringList bestKeywords; QStringList worseKeywords; @@ -53,38 +66,15 @@ bool HelpIndexFilter::updateCache(QFutureInterface &future, worseKeywords.reserve(cache.size()); for (const QString &keyword : cache) { if (future.isCanceled()) - return false; + return {}; if (keyword.startsWith(entry, cs)) bestKeywords.append(keyword); else if (keyword.contains(entry, cs)) worseKeywords.append(keyword); } - bestKeywords << worseKeywords; - m_lastIndicesCache = bestKeywords; + m_lastIndicesCache = bestKeywords + worseKeywords; m_lastEntry = entry; - return true; -} - -QList HelpIndexFilter::matchesFor(QFutureInterface &future, const QString &entry) -{ - if (m_needsUpdate.exchange(false)) { - QStringList indices; - QMetaObject::invokeMethod(this, [this] { return allIndices(); }, - Qt::BlockingQueuedConnection, &indices); - m_allIndicesCache = indices; - // force updating the cache taking the m_allIndicesCache - m_lastIndicesCache = QStringList(); - m_lastEntry = QString(); - } - - const QStringList cacheBase = m_lastEntry.isEmpty() || !entry.contains(m_lastEntry) - ? m_allIndicesCache : m_lastIndicesCache; - - if (!updateCache(future, cacheBase, entry)) - return QList(); - - const Qt::CaseSensitivity cs = caseSensitivity(entry); QList entries; for (const QString &keyword : std::as_const(m_lastIndicesCache)) { const int index = keyword.indexOf(entry, 0, cs); @@ -92,7 +82,6 @@ QList HelpIndexFilter::matchesFor(QFutureInterfaceindices(QString()); -} - void HelpIndexFilter::invalidateCache() { m_needsUpdate = true; diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h index e74e071b12f..f836941d483 100644 --- a/src/plugins/help/helpindexfilter.h +++ b/src/plugins/help/helpindexfilter.h @@ -9,8 +9,6 @@ #include #include -#include - namespace Help { namespace Internal { @@ -20,28 +18,23 @@ class HelpIndexFilter final : public Core::ILocatorFilter public: HelpIndexFilter(); - ~HelpIndexFilter() final; - // ILocatorFilter + void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; - QStringList allIndices() const; - signals: void linksActivated(const QMultiMap &links, const QString &key) const; private: - bool updateCache(QFutureInterface &future, - const QStringList &cache, const QString &entry); void invalidateCache(); QStringList m_allIndicesCache; QStringList m_lastIndicesCache; QString m_lastEntry; - std::atomic_bool m_needsUpdate = true; + bool m_needsUpdate = true; QIcon m_icon; }; From d6c5cf593408c0ca8a1a2a036fc59f6802ef502b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 17 Mar 2023 14:13:01 +0100 Subject: [PATCH 0323/1447] TextEditor: only paint selections in the first block of a suggestion Fixes highlighting of matching parentheses or errors of the code model in every line of the suggestion. Change-Id: I223cb567ee8ce95badd91c4819417310a0e28cff Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/texteditor.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 6cc8084bdd0..6d3593aab7b 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -4994,7 +4994,13 @@ void TextEditorWidget::paintBlock(QPainter *painter, QPointF replacementOffset = offset; replacementOffset.rx() += document()->documentMargin(); while (replacementBlock.isValid()) { - replacementBlock.layout()->draw(painter, replacementOffset, selections, clipRect); + const QVector blockSelections + = replacementBlock.blockNumber() == 0 ? selections + : QVector{}; + replacementBlock.layout()->draw(painter, + replacementOffset, + blockSelections, + clipRect); replacementOffset.ry() += replacement->documentLayout()->blockBoundingRect(replacementBlock).height(); replacementBlock = replacementBlock.next(); From eb9416b35fd10cb0e20f66177bc36a10e2aebe8c Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 27 Jan 2023 16:16:46 +0100 Subject: [PATCH 0324/1447] RemoteLinux: Move GenericDirectUploadService implementation ... to genericdirectuploadstep.cpp and inline its pimpl. Change-Id: I50550ee4bbf4266fa191008c9db1696bae3f7f43 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/CMakeLists.txt | 1 - .../genericdirectuploadservice.cpp | 314 ------------------ .../remotelinux/genericdirectuploadservice.h | 38 --- .../remotelinux/genericdirectuploadstep.cpp | 303 ++++++++++++++++- src/plugins/remotelinux/remotelinux.qbs | 2 - 5 files changed, 301 insertions(+), 357 deletions(-) delete mode 100644 src/plugins/remotelinux/genericdirectuploadservice.cpp delete mode 100644 src/plugins/remotelinux/genericdirectuploadservice.h diff --git a/src/plugins/remotelinux/CMakeLists.txt b/src/plugins/remotelinux/CMakeLists.txt index c37c31d24af..dbb2b8e143d 100644 --- a/src/plugins/remotelinux/CMakeLists.txt +++ b/src/plugins/remotelinux/CMakeLists.txt @@ -5,7 +5,6 @@ add_qtc_plugin(RemoteLinux abstractremotelinuxdeploystep.cpp abstractremotelinuxdeploystep.h customcommanddeploystep.cpp customcommanddeploystep.h deploymenttimeinfo.cpp deploymenttimeinfo.h - genericdirectuploadservice.cpp genericdirectuploadservice.h genericdirectuploadstep.cpp genericdirectuploadstep.h genericlinuxdeviceconfigurationwidget.cpp genericlinuxdeviceconfigurationwidget.h genericlinuxdeviceconfigurationwizard.cpp genericlinuxdeviceconfigurationwizard.h diff --git a/src/plugins/remotelinux/genericdirectuploadservice.cpp b/src/plugins/remotelinux/genericdirectuploadservice.cpp deleted file mode 100644 index 6cd3c799376..00000000000 --- a/src/plugins/remotelinux/genericdirectuploadservice.cpp +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "genericdirectuploadservice.h" - -#include "remotelinuxtr.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -using namespace ProjectExplorer; -using namespace Utils; -using namespace Utils::Tasking; - -namespace RemoteLinux { -namespace Internal { - -const int MaxConcurrentStatCalls = 10; - -struct UploadStorage -{ - QList filesToUpload; -}; - -class GenericDirectUploadServicePrivate -{ -public: - GenericDirectUploadServicePrivate(GenericDirectUploadService *service) : q(service) {} - - QDateTime timestampFromStat(const DeployableFile &file, QtcProcess *statProc); - - using FilesToStat = std::function(UploadStorage *)>; - using StatEndHandler - = std::function; - TaskItem statTask(UploadStorage *storage, const DeployableFile &file, - StatEndHandler statEndHandler); - TaskItem statTree(const TreeStorage &storage, FilesToStat filesToStat, - StatEndHandler statEndHandler); - TaskItem uploadTask(const TreeStorage &storage); - TaskItem chmodTask(const DeployableFile &file); - TaskItem chmodTree(const TreeStorage &storage); - - GenericDirectUploadService *q = nullptr; - IncrementalDeployment incremental = IncrementalDeployment::NotSupported; - bool ignoreMissingFiles = false; - QList deployableFiles; -}; - -QList collectFilesToUpload(const DeployableFile &deployable) -{ - QList collected; - FilePath localFile = deployable.localFilePath(); - if (localFile.isDir()) { - const FilePaths files = localFile.dirEntries(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); - const QString remoteDir = deployable.remoteDirectory() + '/' + localFile.fileName(); - for (const FilePath &localFilePath : files) - collected.append(collectFilesToUpload(DeployableFile(localFilePath, remoteDir))); - } else { - collected << deployable; - } - return collected; -} - -} // namespace Internal - -using namespace Internal; - -GenericDirectUploadService::GenericDirectUploadService(QObject *parent) - : AbstractRemoteLinuxDeployService(parent), d(new GenericDirectUploadServicePrivate(this)) -{ -} - -GenericDirectUploadService::~GenericDirectUploadService() -{ - delete d; -} - -void GenericDirectUploadService::setDeployableFiles(const QList &deployableFiles) -{ - d->deployableFiles = deployableFiles; -} - -void GenericDirectUploadService::setIncrementalDeployment(IncrementalDeployment incremental) -{ - d->incremental = incremental; -} - -void GenericDirectUploadService::setIgnoreMissingFiles(bool ignoreMissingFiles) -{ - d->ignoreMissingFiles = ignoreMissingFiles; -} - -bool GenericDirectUploadService::isDeploymentNecessary() const -{ - QList collected; - for (int i = 0; i < d->deployableFiles.count(); ++i) - collected.append(collectFilesToUpload(d->deployableFiles.at(i))); - - QTC_CHECK(collected.size() >= d->deployableFiles.size()); - d->deployableFiles = collected; - return !d->deployableFiles.isEmpty(); -} - -QDateTime GenericDirectUploadServicePrivate::timestampFromStat(const DeployableFile &file, - QtcProcess *statProc) -{ - bool succeeded = false; - QString error; - if (statProc->error() == QProcess::FailedToStart) { - error = Tr::tr("Failed to start \"stat\": %1").arg(statProc->errorString()); - } else if (statProc->exitStatus() == QProcess::CrashExit) { - error = Tr::tr("\"stat\" crashed."); - } else if (statProc->exitCode() != 0) { - error = Tr::tr("\"stat\" failed with exit code %1: %2") - .arg(statProc->exitCode()).arg(statProc->cleanedStdErr()); - } else { - succeeded = true; - } - if (!succeeded) { - emit q->warningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " - "Incremental deployment will not work. Error message was: %2") - .arg(file.remoteFilePath(), error)); - return {}; - } - const QByteArray output = statProc->readAllRawStandardOutput().trimmed(); - const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2") - .arg(file.remoteFilePath()).arg(QString::fromUtf8(output))); - if (!output.startsWith(file.remoteFilePath().toUtf8())) { - emit q->warningMessage(warningString); - return {}; - } - const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' '); - if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns - emit q->warningMessage(warningString); - return {}; - } - bool isNumber; - const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber); - if (!isNumber) { - emit q->warningMessage(warningString); - return {}; - } - return QDateTime::fromSecsSinceEpoch(secsSinceEpoch); -} - -TaskItem GenericDirectUploadServicePrivate::statTask(UploadStorage *storage, - const DeployableFile &file, - StatEndHandler statEndHandler) -{ - const auto setupHandler = [=](QtcProcess &process) { - // We'd like to use --format=%Y, but it's not supported by busybox. - process.setCommand({q->deviceConfiguration()->filePath("stat"), - {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); - }; - const auto endHandler = [=](const QtcProcess &process) { - QtcProcess *proc = const_cast(&process); - const QDateTime timestamp = timestampFromStat(file, proc); - statEndHandler(storage, file, timestamp); - }; - return Process(setupHandler, endHandler, endHandler); -} - -TaskItem GenericDirectUploadServicePrivate::statTree(const TreeStorage &storage, - FilesToStat filesToStat, StatEndHandler statEndHandler) -{ - const auto setupHandler = [=](TaskTree &tree) { - UploadStorage *storagePtr = storage.activeStorage(); - const QList files = filesToStat(storagePtr); - QList statList{optional, ParallelLimit(MaxConcurrentStatCalls)}; - for (const DeployableFile &file : std::as_const(files)) { - QTC_ASSERT(file.isValid(), continue); - statList.append(statTask(storagePtr, file, statEndHandler)); - } - tree.setupRoot({statList}); - }; - return Tree(setupHandler); -} - -TaskItem GenericDirectUploadServicePrivate::uploadTask(const TreeStorage &storage) -{ - const auto setupHandler = [this, storage](FileTransfer &transfer) { - if (storage->filesToUpload.isEmpty()) { - emit q->progressMessage(Tr::tr("No files need to be uploaded.")); - return TaskAction::StopWithDone; - } - emit q->progressMessage(Tr::tr("%n file(s) need to be uploaded.", "", - storage->filesToUpload.size())); - FilesToTransfer files; - for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { - if (!file.localFilePath().exists()) { - const QString message = Tr::tr("Local file \"%1\" does not exist.") - .arg(file.localFilePath().toUserOutput()); - if (ignoreMissingFiles) { - emit q->warningMessage(message); - continue; - } - emit q->errorMessage(message); - return TaskAction::StopWithError; - } - files.append({file.localFilePath(), - q->deviceConfiguration()->filePath(file.remoteFilePath())}); - } - if (files.isEmpty()) { - emit q->progressMessage(Tr::tr("No files need to be uploaded.")); - return TaskAction::StopWithDone; - } - transfer.setFilesToTransfer(files); - QObject::connect(&transfer, &FileTransfer::progress, - q, &GenericDirectUploadService::progressMessage); - return TaskAction::Continue; - }; - const auto errorHandler = [this](const FileTransfer &transfer) { - emit q->errorMessage(transfer.resultData().m_errorString); - }; - - return Transfer(setupHandler, {}, errorHandler); -} - -TaskItem GenericDirectUploadServicePrivate::chmodTask(const DeployableFile &file) -{ - const auto setupHandler = [=](QtcProcess &process) { - process.setCommand({q->deviceConfiguration()->filePath("chmod"), - {"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); - }; - const auto errorHandler = [=](const QtcProcess &process) { - const QString error = process.errorString(); - if (!error.isEmpty()) { - emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") - .arg(file.remoteFilePath(), error)); - } else if (process.exitCode() != 0) { - emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") - .arg(file.remoteFilePath(), process.cleanedStdErr())); - } - }; - return Process(setupHandler, {}, errorHandler); -} - -TaskItem GenericDirectUploadServicePrivate::chmodTree(const TreeStorage &storage) -{ - const auto setupChmodHandler = [=](TaskTree &tree) { - QList filesToChmod; - for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { - if (file.isExecutable()) - filesToChmod << file; - } - QList chmodList{optional, ParallelLimit(MaxConcurrentStatCalls)}; - for (const DeployableFile &file : std::as_const(filesToChmod)) { - QTC_ASSERT(file.isValid(), continue); - chmodList.append(chmodTask(file)); - } - tree.setupRoot({chmodList}); - }; - return Tree(setupChmodHandler); -} - -Group GenericDirectUploadService::deployRecipe() -{ - const auto preFilesToStat = [this](UploadStorage *storage) { - QList filesToStat; - for (const DeployableFile &file : std::as_const(d->deployableFiles)) { - if (d->incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) { - storage->filesToUpload.append(file); - continue; - } - if (d->incremental == IncrementalDeployment::NotSupported) - continue; - filesToStat << file; - } - return filesToStat; - }; - const auto preStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file, - const QDateTime ×tamp) { - if (!timestamp.isValid() || hasRemoteFileChanged(file, timestamp)) - storage->filesToUpload.append(file); - }; - - const auto postFilesToStat = [this](UploadStorage *storage) { - return d->incremental == IncrementalDeployment::NotSupported - ? QList() : storage->filesToUpload; - }; - const auto postStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file, - const QDateTime ×tamp) { - Q_UNUSED(storage) - if (timestamp.isValid()) - saveDeploymentTimeStamp(file, timestamp); - }; - const auto doneHandler = [this] { - emit progressMessage(Tr::tr("All files successfully deployed.")); - }; - - const TreeStorage storage; - const Group root { - Storage(storage), - d->statTree(storage, preFilesToStat, preStatEndHandler), - d->uploadTask(storage), - Group { - d->chmodTree(storage), - d->statTree(storage, postFilesToStat, postStatEndHandler) - }, - OnGroupDone(doneHandler) - }; - return root; -} - -} //namespace RemoteLinux diff --git a/src/plugins/remotelinux/genericdirectuploadservice.h b/src/plugins/remotelinux/genericdirectuploadservice.h deleted file mode 100644 index 31799f063ad..00000000000 --- a/src/plugins/remotelinux/genericdirectuploadservice.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "remotelinux_export.h" - -#include "abstractremotelinuxdeploystep.h" - -#include - -namespace ProjectExplorer { class DeployableFile; } - -namespace RemoteLinux { -namespace Internal { class GenericDirectUploadServicePrivate; } - -enum class IncrementalDeployment { Enabled, Disabled, NotSupported }; - -class REMOTELINUX_EXPORT GenericDirectUploadService : public AbstractRemoteLinuxDeployService -{ - Q_OBJECT -public: - GenericDirectUploadService(QObject *parent = nullptr); - ~GenericDirectUploadService(); - - void setDeployableFiles(const QList &deployableFiles); - void setIncrementalDeployment(IncrementalDeployment incremental); - void setIgnoreMissingFiles(bool ignoreMissingFiles); - -private: - bool isDeploymentNecessary() const final; - Utils::Tasking::Group deployRecipe() final; - - friend class Internal::GenericDirectUploadServicePrivate; - Internal::GenericDirectUploadServicePrivate * const d; -}; - -} //namespace RemoteLinux diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 2b778e2b9c8..46a431861d1 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -3,18 +3,317 @@ #include "genericdirectuploadstep.h" -#include "genericdirectuploadservice.h" #include "remotelinux_constants.h" #include "remotelinuxtr.h" +#include #include -#include +#include +#include #include +#include + +#include +#include +#include +#include + +#include using namespace ProjectExplorer; using namespace Utils; +using namespace Utils::Tasking; namespace RemoteLinux { +namespace Internal { + +const int MaxConcurrentStatCalls = 10; + +struct UploadStorage +{ + QList filesToUpload; +}; + +enum class IncrementalDeployment { Enabled, Disabled, NotSupported }; + +class GenericDirectUploadService : public AbstractRemoteLinuxDeployService +{ +public: + GenericDirectUploadService(QObject *parent = nullptr) + : AbstractRemoteLinuxDeployService(parent) + {} + + void setDeployableFiles(const QList &deployableFiles); + void setIncrementalDeployment(IncrementalDeployment incremental); + void setIgnoreMissingFiles(bool ignoreMissingFiles); + +private: + bool isDeploymentNecessary() const final; + Utils::Tasking::Group deployRecipe() final; + + QDateTime timestampFromStat(const DeployableFile &file, QtcProcess *statProc); + + using FilesToStat = std::function(UploadStorage *)>; + using StatEndHandler + = std::function; + TaskItem statTask(UploadStorage *storage, const DeployableFile &file, + StatEndHandler statEndHandler); + TaskItem statTree(const TreeStorage &storage, FilesToStat filesToStat, + StatEndHandler statEndHandler); + TaskItem uploadTask(const TreeStorage &storage); + TaskItem chmodTask(const DeployableFile &file); + TaskItem chmodTree(const TreeStorage &storage); + + IncrementalDeployment m_incremental = IncrementalDeployment::NotSupported; + bool m_ignoreMissingFiles = false; + mutable QList m_deployableFiles; +}; + +QList collectFilesToUpload(const DeployableFile &deployable) +{ + QList collected; + FilePath localFile = deployable.localFilePath(); + if (localFile.isDir()) { + const FilePaths files = localFile.dirEntries(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + const QString remoteDir = deployable.remoteDirectory() + '/' + localFile.fileName(); + for (const FilePath &localFilePath : files) + collected.append(collectFilesToUpload(DeployableFile(localFilePath, remoteDir))); + } else { + collected << deployable; + } + return collected; +} + +} // namespace Internal + +using namespace Internal; + +void GenericDirectUploadService::setDeployableFiles(const QList &deployableFiles) +{ + m_deployableFiles = deployableFiles; +} + +void GenericDirectUploadService::setIncrementalDeployment(IncrementalDeployment incremental) +{ + m_incremental = incremental; +} + +void GenericDirectUploadService::setIgnoreMissingFiles(bool ignoreMissingFiles) +{ + m_ignoreMissingFiles = ignoreMissingFiles; +} + +bool GenericDirectUploadService::isDeploymentNecessary() const +{ + QList collected; + for (int i = 0; i < m_deployableFiles.count(); ++i) + collected.append(collectFilesToUpload(m_deployableFiles.at(i))); + + QTC_CHECK(collected.size() >= m_deployableFiles.size()); + m_deployableFiles = collected; + return !m_deployableFiles.isEmpty(); +} + +QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &file, + QtcProcess *statProc) +{ + bool succeeded = false; + QString error; + if (statProc->error() == QProcess::FailedToStart) { + error = Tr::tr("Failed to start \"stat\": %1").arg(statProc->errorString()); + } else if (statProc->exitStatus() == QProcess::CrashExit) { + error = Tr::tr("\"stat\" crashed."); + } else if (statProc->exitCode() != 0) { + error = Tr::tr("\"stat\" failed with exit code %1: %2") + .arg(statProc->exitCode()).arg(statProc->cleanedStdErr()); + } else { + succeeded = true; + } + if (!succeeded) { + emit warningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " + "Incremental deployment will not work. Error message was: %2") + .arg(file.remoteFilePath(), error)); + return {}; + } + const QByteArray output = statProc->readAllRawStandardOutput().trimmed(); + const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2") + .arg(file.remoteFilePath()).arg(QString::fromUtf8(output))); + if (!output.startsWith(file.remoteFilePath().toUtf8())) { + emit warningMessage(warningString); + return {}; + } + const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' '); + if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns + emit warningMessage(warningString); + return {}; + } + bool isNumber; + const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber); + if (!isNumber) { + emit warningMessage(warningString); + return {}; + } + return QDateTime::fromSecsSinceEpoch(secsSinceEpoch); +} + +TaskItem GenericDirectUploadService::statTask(UploadStorage *storage, + const DeployableFile &file, + StatEndHandler statEndHandler) +{ + const auto setupHandler = [=](QtcProcess &process) { + // We'd like to use --format=%Y, but it's not supported by busybox. + process.setCommand({deviceConfiguration()->filePath("stat"), + {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); + }; + const auto endHandler = [=](const QtcProcess &process) { + QtcProcess *proc = const_cast(&process); + const QDateTime timestamp = timestampFromStat(file, proc); + statEndHandler(storage, file, timestamp); + }; + return Process(setupHandler, endHandler, endHandler); +} + +TaskItem GenericDirectUploadService::statTree(const TreeStorage &storage, + FilesToStat filesToStat, StatEndHandler statEndHandler) +{ + const auto setupHandler = [=](TaskTree &tree) { + UploadStorage *storagePtr = storage.activeStorage(); + const QList files = filesToStat(storagePtr); + QList statList{optional, ParallelLimit(MaxConcurrentStatCalls)}; + for (const DeployableFile &file : std::as_const(files)) { + QTC_ASSERT(file.isValid(), continue); + statList.append(statTask(storagePtr, file, statEndHandler)); + } + tree.setupRoot({statList}); + }; + return Tree(setupHandler); +} + +TaskItem GenericDirectUploadService::uploadTask(const TreeStorage &storage) +{ + const auto setupHandler = [this, storage](FileTransfer &transfer) { + if (storage->filesToUpload.isEmpty()) { + emit progressMessage(Tr::tr("No files need to be uploaded.")); + return TaskAction::StopWithDone; + } + emit progressMessage(Tr::tr("%n file(s) need to be uploaded.", "", + storage->filesToUpload.size())); + FilesToTransfer files; + for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { + if (!file.localFilePath().exists()) { + const QString message = Tr::tr("Local file \"%1\" does not exist.") + .arg(file.localFilePath().toUserOutput()); + if (m_ignoreMissingFiles) { + emit warningMessage(message); + continue; + } + emit errorMessage(message); + return TaskAction::StopWithError; + } + files.append({file.localFilePath(), + deviceConfiguration()->filePath(file.remoteFilePath())}); + } + if (files.isEmpty()) { + emit progressMessage(Tr::tr("No files need to be uploaded.")); + return TaskAction::StopWithDone; + } + transfer.setFilesToTransfer(files); + QObject::connect(&transfer, &FileTransfer::progress, + this, &GenericDirectUploadService::progressMessage); + return TaskAction::Continue; + }; + const auto errorHandler = [this](const FileTransfer &transfer) { + emit errorMessage(transfer.resultData().m_errorString); + }; + + return Transfer(setupHandler, {}, errorHandler); +} + +TaskItem GenericDirectUploadService::chmodTask(const DeployableFile &file) +{ + const auto setupHandler = [=](QtcProcess &process) { + process.setCommand({deviceConfiguration()->filePath("chmod"), + {"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); + }; + const auto errorHandler = [=](const QtcProcess &process) { + const QString error = process.errorString(); + if (!error.isEmpty()) { + emit warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + .arg(file.remoteFilePath(), error)); + } else if (process.exitCode() != 0) { + emit warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + .arg(file.remoteFilePath(), process.cleanedStdErr())); + } + }; + return Process(setupHandler, {}, errorHandler); +} + +TaskItem GenericDirectUploadService::chmodTree(const TreeStorage &storage) +{ + const auto setupChmodHandler = [=](TaskTree &tree) { + QList filesToChmod; + for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { + if (file.isExecutable()) + filesToChmod << file; + } + QList chmodList{optional, ParallelLimit(MaxConcurrentStatCalls)}; + for (const DeployableFile &file : std::as_const(filesToChmod)) { + QTC_ASSERT(file.isValid(), continue); + chmodList.append(chmodTask(file)); + } + tree.setupRoot({chmodList}); + }; + return Tree(setupChmodHandler); +} + +Group GenericDirectUploadService::deployRecipe() +{ + const auto preFilesToStat = [this](UploadStorage *storage) { + QList filesToStat; + for (const DeployableFile &file : std::as_const(m_deployableFiles)) { + if (m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) { + storage->filesToUpload.append(file); + continue; + } + if (m_incremental == IncrementalDeployment::NotSupported) + continue; + filesToStat << file; + } + return filesToStat; + }; + const auto preStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file, + const QDateTime ×tamp) { + if (!timestamp.isValid() || hasRemoteFileChanged(file, timestamp)) + storage->filesToUpload.append(file); + }; + + const auto postFilesToStat = [this](UploadStorage *storage) { + return m_incremental == IncrementalDeployment::NotSupported + ? QList() : storage->filesToUpload; + }; + const auto postStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file, + const QDateTime ×tamp) { + Q_UNUSED(storage) + if (timestamp.isValid()) + saveDeploymentTimeStamp(file, timestamp); + }; + const auto doneHandler = [this] { + emit progressMessage(Tr::tr("All files successfully deployed.")); + }; + + const TreeStorage storage; + const Group root { + Storage(storage), + statTree(storage, preFilesToStat, preStatEndHandler), + uploadTask(storage), + Group { + chmodTree(storage), + statTree(storage, postFilesToStat, postStatEndHandler) + }, + OnGroupDone(doneHandler) + }; + return root; +} GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id, bool offerIncrementalDeployment) diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index 5235dbaef5e..94a3878fe04 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -19,8 +19,6 @@ Project { "deploymenttimeinfo.h", "customcommanddeploystep.cpp", "customcommanddeploystep.h", - "genericdirectuploadservice.cpp", - "genericdirectuploadservice.h", "genericdirectuploadstep.cpp", "genericdirectuploadstep.h", "genericlinuxdeviceconfigurationwidget.cpp", From 129562ea6f7260f2db71be28d94ca9606899a7ae Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 20 Mar 2023 11:30:07 +0100 Subject: [PATCH 0325/1447] Utils: Test QtcProcess default environment Change-Id: I62f56bd070ec531462ad3dd4e39cf6708115c7ba Reviewed-by: Qt CI Bot Reviewed-by: hjk Reviewed-by: --- .../auto/utils/qtcprocess/tst_qtcprocess.cpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp index 97792d9fb47..bd8bb58af25 100644 --- a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp @@ -94,6 +94,33 @@ class tst_QtcProcess : public QObject private slots: void initTestCase(); + void testEnv() + { + if (HostOsInfo::isWindowsHost()) + QSKIP("Skipping env test on Windows"); + + QProcess qproc; + FilePath envPath = Environment::systemEnvironment().searchInPath("env"); + + qproc.setProgram(envPath.nativePath()); + qproc.start(); + qproc.waitForFinished(); + QByteArray qoutput = qproc.readAllStandardOutput() + qproc.readAllStandardError(); + qDebug() << "QProcess output:" << qoutput; + QCOMPARE(qproc.exitCode(), 0); + + QtcProcess qtcproc; + qtcproc.setCommand({envPath, {}}); + qtcproc.runBlocking(); + QCOMPARE(qtcproc.exitCode(), 0); + QByteArray qtcoutput = qtcproc.readAllRawStandardOutput() + + qtcproc.readAllRawStandardError(); + + qDebug() << "QtcProcess output:" << qtcoutput; + + QCOMPARE(qtcoutput.size() > 0, qoutput.size() > 0); + } + void multiRead(); void splitArgs_data(); From 80fa3339e06236bebeb1894deeb4cf7e648c2888 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 21 Mar 2023 10:15:54 +0100 Subject: [PATCH 0326/1447] Utils: Re-add "press enter to continue" to stub To keep the terminal from closing immediately, ask the user to press enter after the inferior exited. Make it configurable as the terminal plugin does not need this. Change-Id: I1949895f022a54539a6139be9f92fdc698f6534e Reviewed-by: Reviewed-by: Eike Ziller --- src/libs/utils/terminalinterface.cpp | 17 ++++++++++++++--- src/libs/utils/terminalinterface.h | 2 +- src/plugins/terminal/terminalprocessimpl.cpp | 1 + src/tools/process_stub/main.cpp | 10 ++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index 04468ddab7c..7ec7c755fd3 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -53,12 +53,19 @@ static QString msgCannotExecute(const QString &p, const QString &why) return Tr::tr("Cannot execute \"%1\": %2").arg(p, why); } +static QString msgPromptToClose() +{ + // Shown in a terminal which might have a different character set on Windows. + return Tr::tr("Press to close this window..."); +} + class TerminalInterfacePrivate : public QObject { Q_OBJECT public: - TerminalInterfacePrivate(TerminalInterface *p) + TerminalInterfacePrivate(TerminalInterface *p, bool waitOnExit) : q(p) + , waitOnExit(waitOnExit) { connect(&stubServer, &QLocalServer::newConnection, @@ -83,10 +90,12 @@ public: TerminalInterface *q; StubCreator *stubCreator{nullptr}; + + const bool waitOnExit; }; -TerminalInterface::TerminalInterface() - : d(new TerminalInterfacePrivate(this)) +TerminalInterface::TerminalInterface(bool waitOnExit) + : d(new TerminalInterfacePrivate(this, waitOnExit)) {} TerminalInterface::~TerminalInterface() @@ -349,6 +358,8 @@ void TerminalInterface::start() if (d->envListFile) cmd.addArgs({"-e", d->envListFile->fileName()}); + cmd.addArgs({"--wait", d->waitOnExit ? msgPromptToClose() : ""}); + cmd.addArgs({"--", m_setup.m_commandLine.executable().nativePath()}); cmd.addArgs(m_setup.m_commandLine.arguments(), CommandLine::Raw); diff --git a/src/libs/utils/terminalinterface.h b/src/libs/utils/terminalinterface.h index 135fb8257dd..feb19875ba2 100644 --- a/src/libs/utils/terminalinterface.h +++ b/src/libs/utils/terminalinterface.h @@ -23,7 +23,7 @@ class QTCREATOR_UTILS_EXPORT TerminalInterface : public ProcessInterface friend class StubCreator; public: - TerminalInterface(); + TerminalInterface(bool waitOnExit = true); ~TerminalInterface() override; int inferiorProcessId() const; diff --git a/src/plugins/terminal/terminalprocessimpl.cpp b/src/plugins/terminal/terminalprocessimpl.cpp index 8724510eb46..2397af50d17 100644 --- a/src/plugins/terminal/terminalprocessimpl.cpp +++ b/src/plugins/terminal/terminalprocessimpl.cpp @@ -58,6 +58,7 @@ public: }; TerminalProcessImpl::TerminalProcessImpl(TerminalPane *terminalPane) + : TerminalInterface(false) { auto creator = new ProcessStubCreator(this, terminalPane); creator->moveToThread(qApp->thread()); diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index 5912fdae674..45ac9c41f9b 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -172,6 +172,11 @@ void doExit(int exitCode) if (controlSocket.state() == QLocalSocket::ConnectedState && controlSocket.bytesToWrite()) controlSocket.waitForBytesWritten(1000); + if (!commandLineParser.value("wait").isEmpty()) { + std::cout << commandLineParser.value("wait").toStdString(); + std::cin.get(); + } + exit(exitCode); } @@ -394,6 +399,11 @@ std::optional tryParseCommandLine(QCoreApplication &app) QCommandLineOption({"w", "workingDir"}, "Working directory for inferior", "workingDir")); commandLineParser.addOption(QCommandLineOption({"v", "verbose"}, "Print debug messages")); commandLineParser.addOption(QCommandLineOption({"e", "envfile"}, "Path to env file", "envfile")); + commandLineParser.addOption( + QCommandLineOption("wait", + "Message to display to the user while waiting for key press", + "waitmessage", + "Press enter to continue ...")); commandLineParser.process(app); From 65814b124c2dcbd59f9bbd91a9c04c355ae37d4d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 20 Mar 2023 12:32:37 +0100 Subject: [PATCH 0327/1447] CMakeProjectManager: Add lib and app binaries to project tree Task-number: QTCREATORBUG-28815 Change-Id: I58ebcd2a6935eb4b6746b5fd58e6ab8b97fdef43 Reviewed-by: Reviewed-by: David Schulz --- .../cmakeprojectmanager/cmakeprojectnodes.cpp | 4 ++++ .../fileapidataextractor.cpp | 23 +++++++++++++++++++ src/plugins/projectexplorer/msvctoolchain.h | 2 ++ src/plugins/projectexplorer/project.cpp | 17 +++++++++++--- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 9c0d687ca6f..10f18fbf675 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -198,6 +198,10 @@ void CMakeTargetNode::setTargetInformation(const QList &artifacts, con m_tooltip += Tr::tr("Build artifacts:") + "
" + tmp.join("
"); m_artifact = artifacts.first(); } + if (type == "EXECUTABLE") + setProductType(ProductType::App); + else if (type == "SHARED_LIBRARY" || type == "STATIC_LIBRARY") + setProductType(ProductType::Lib); } } // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 29ace13a6bd..ab79be78aea 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -605,6 +605,28 @@ void addCompileGroups(ProjectNode *targetRoot, std::move(otherFileNodes)); } +static void addGeneratedFilesNode(ProjectNode *targetRoot, const FilePath &topLevelBuildDir, + const TargetDetails &td) +{ + if (td.artifacts.isEmpty()) + return; + FileType type = FileType::Unknown; + if (td.type == "EXECUTABLE") + type = FileType::App; + else if (td.type == "SHARED_LIBRARY" || td.type == "STATIC_LIBRARY") + type = FileType::Lib; + if (type == FileType::Unknown) + return; + std::vector> nodes; + const FilePath buildDir = topLevelBuildDir.resolvePath(td.buildDir); + for (const FilePath &artifact : td.artifacts) { + nodes.emplace_back(new FileNode(buildDir.resolvePath(artifact), type)); + type = FileType::Unknown; + nodes.back()->setIsGenerated(true); + } + addCMakeVFolder(targetRoot, buildDir, 10, Tr::tr(""), std::move(nodes)); +} + void addTargets(const QHash &cmakeListsNodes, const Configuration &config, const std::vector &targetDetails, @@ -635,6 +657,7 @@ void addTargets(const QHash &cm tNode->setBuildDirectory(directoryBuildDir(config, buildDir, t.directory)); addCompileGroups(tNode, sourceDir, dir, tNode->buildDirectory(), td); + addGeneratedFilesNode(tNode, buildDir, td); } } diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index cb1fdc5523b..68f8b9dcf19 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -81,6 +81,8 @@ public: const QString &batchFile, const QString &batchArgs, QMap &envPairs); + bool environmentInitialized() const { return !m_environmentModifications.isEmpty(); } + protected: class WarningFlagAdder { diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index fd95c807994..3b32e3c2650 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -11,6 +11,7 @@ #include "environmentaspect.h" #include "kit.h" #include "kitinformation.h" +#include "msvctoolchain.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" @@ -20,6 +21,7 @@ #include "runconfigurationaspects.h" #include "target.h" #include "taskhub.h" +#include "toolchainmanager.h" #include "userfileaccessor.h" #include @@ -1514,10 +1516,20 @@ void ProjectExplorerPlugin::testSourceToBinaryMapping() { // Find suitable kit. Kit * const kit = findOr(KitManager::kits(), nullptr, [](const Kit *k) { - return k->isValid(); + return k->isValid() && ToolChainKitAspect::cxxToolChain(k); }); if (!kit) - QSKIP("The test requires at least one valid kit."); + QSKIP("The test requires at least one kit with a toolchain."); + + const auto toolchain = ToolChainKitAspect::cxxToolChain(kit); + QVERIFY(toolchain); + if (const auto msvcToolchain = dynamic_cast(toolchain)) { + while (!msvcToolchain->environmentInitialized()) { + QSignalSpy parsingFinishedSpy(ToolChainManager::instance(), + &ToolChainManager::toolChainUpdated); + QVERIFY(parsingFinishedSpy.wait(10000)); + } + } // Copy project from qrc. QTemporaryDir * const tempDir = TemporaryDirectory::masterTemporaryDirectory(); @@ -1569,7 +1581,6 @@ void ProjectExplorerPlugin::testSourceToBinaryMapping() const auto binariesForSource = [&](const QString &fileName) { return theProject.project()->binariesForSourceFile(projectDir.pathAppended(fileName)); }; - QEXPECT_FAIL("cmake", "QTCREATORBUG-28815", Abort); QCOMPARE(binariesForSource("multi-target-project-main.cpp").size(), 1); QCOMPARE(binariesForSource("multi-target-project-lib.cpp").size(), 1); QCOMPARE(binariesForSource("multi-target-project-shared.h").size(), 2); From 97c1bb53a501316505aec76e6e7b7222debaf60c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 21 Mar 2023 09:43:10 +0100 Subject: [PATCH 0328/1447] Docker: Check Image available Docker will try to download images from the registry if an image is not available locally. This takes a while, even if the image is not available remotely. To circumvent the hangs resulting from this we first check if the image is available locally and if it is not we do not try to start it. Fixes: QTCREATORBUG-28880 Change-Id: I6b9de8601b87e3050ae9ac5f1bbe3fa9701d4cc1 Reviewed-by: David Schulz --- src/plugins/docker/dockerdevice.cpp | 64 +++++++++++++++++++++-------- src/plugins/docker/dockerdevice.h | 2 +- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 020aeec31f4..7bac522c5ba 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -143,7 +143,7 @@ public: RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); - void updateContainerAccess(); + bool updateContainerAccess(); void changeMounts(QStringList newMounts); bool ensureReachable(const FilePath &other); void shutdown(); @@ -171,7 +171,7 @@ public: Tasks validateMounts() const; bool createContainer(); - void startContainer(); + bool startContainer(); void stopCurrentContainer(); void fetchSystemEnviroment(); @@ -186,6 +186,8 @@ public: QStringList createMountArgs() const; + bool isImageAvailable() const; + DockerDevice *const q; DockerDeviceData m_data; DockerSettings *m_settings; @@ -392,7 +394,9 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat setOpenTerminal([this, settings](const Environment &env, const FilePath &workingDir) { Q_UNUSED(env); // TODO: That's the runnable's environment in general. Use it via -e below. - updateContainerAccess(); + if (!updateContainerAccess()) + return; + if (d->containerId().isEmpty()) { MessageManager::writeDisrupting(Tr::tr("Error starting remote shell. No container.")); return; @@ -446,9 +450,9 @@ void DockerDevice::setData(const DockerDeviceData &data) d->setData(data); } -void DockerDevice::updateContainerAccess() const +bool DockerDevice::updateContainerAccess() const { - d->updateContainerAccess(); + return d->updateContainerAccess(); } CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, @@ -461,7 +465,8 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, if (!m_settings) return {}; - updateContainerAccess(); + if (!updateContainerAccess()) + return {}; CommandLine dockerCmd{m_settings->dockerBinaryPath.filePath(), {"exec"}}; @@ -614,11 +619,30 @@ QStringList DockerDevicePrivate::createMountArgs() const return cmds; } +bool DockerDevicePrivate::isImageAvailable() const +{ + QtcProcess proc; + proc.setCommand( + {m_settings->dockerBinaryPath.filePath(), + {"image", "list", m_data.repoAndTag(), "--format", "{{.Repository}}:{{.Tag}}"}}); + proc.runBlocking(); + if (proc.result() != ProcessResult::FinishedWithSuccess) + return false; + + if (proc.stdOut().trimmed() == m_data.repoAndTag()) + return true; + + return false; +} + bool DockerDevicePrivate::createContainer() { if (!m_settings) return false; + if (!isImageAvailable()) + return false; + const QString display = HostOsInfo::isLinuxHost() ? QString(":0") : QString("host.docker.internal:0"); CommandLine dockerCreate{m_settings->dockerBinaryPath.filePath(), @@ -671,10 +695,10 @@ bool DockerDevicePrivate::createContainer() return true; } -void DockerDevicePrivate::startContainer() +bool DockerDevicePrivate::startContainer() { if (!createContainer()) - return; + return false; m_shell = std::make_unique(m_settings, m_container, q->rootPath()); @@ -693,23 +717,25 @@ void DockerDevicePrivate::startContainer() "or restart Qt Creator.")); }); - if (!m_shell->start()) { - qCWarning(dockerDeviceLog) << "Container shell failed to start"; - } + if (m_shell->start()) + return true; + + qCWarning(dockerDeviceLog) << "Container shell failed to start"; + return false; } -void DockerDevicePrivate::updateContainerAccess() +bool DockerDevicePrivate::updateContainerAccess() { if (m_isShutdown) - return; + return false; if (DockerApi::isDockerDaemonAvailable(false).value_or(false) == false) - return; + return false; if (m_shell) - return; + return true; - startContainer(); + return startContainer(); } void DockerDevice::setMounts(const QStringList &mounts) const @@ -881,7 +907,8 @@ void DockerDevice::aboutToBeRemoved() const void DockerDevicePrivate::fetchSystemEnviroment() { - updateContainerAccess(); + if (!updateContainerAccess()) + return; if (m_shell && m_shell->state() == DeviceShell::State::Succeeded) { const RunResult result = runInShell({"env", {}}); @@ -905,7 +932,8 @@ void DockerDevicePrivate::fetchSystemEnviroment() RunResult DockerDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &stdInData) { - updateContainerAccess(); + if (!updateContainerAccess()) + return {}; QTC_ASSERT(m_shell, return {}); return m_shell->runInShell(cmd, stdInData); } diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 38e9956a230..affe4cf2714 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -95,7 +95,7 @@ public: void setData(const DockerDeviceData &data); - void updateContainerAccess() const; + bool updateContainerAccess() const; void setMounts(const QStringList &mounts) const; bool prepareForBuild(const ProjectExplorer::Target *target) override; From 1029cb959b80e81d911951df67ae2c02a478aff9 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 21 Mar 2023 12:59:10 +0100 Subject: [PATCH 0329/1447] Build: Fix translation targets Filter out .pro files from the translation sources. A ProjectExplorer test was added that added files like `multi-target-project-app.pro` to the target sources. lupdate then triggers a call for lupdate-pro, which in turn fails. Also filter .css files, which result in lupdate warnings. Change-Id: Ib2fa5f0228307bc5850915ed89c14a0956d1d6a8 Reviewed-by: Christian Stenger --- cmake/QtCreatorTranslations.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/QtCreatorTranslations.cmake b/cmake/QtCreatorTranslations.cmake index a900efa18f7..98ede46582e 100644 --- a/cmake/QtCreatorTranslations.cmake +++ b/cmake/QtCreatorTranslations.cmake @@ -30,7 +30,7 @@ function(_extract_ts_data_from_targets outprefix) set(_target_sources "") if(_source_files) - list(FILTER _source_files EXCLUDE REGEX ".*[.]json[.]in|.*[.]svg") + list(FILTER _source_files EXCLUDE REGEX ".*[.]json[.]in|.*[.]svg|.*[.]pro|.*[.]css") list(APPEND _target_sources ${_source_files}) endif() if(_extra_translations) From 50a214de9e8444f3e43e9b1013c95072f8ff196f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 21 Mar 2023 10:01:28 +0100 Subject: [PATCH 0330/1447] Qbs build system: Add a component for test files groups Mainly in order to enforce a unified group name across QtC libraries and plugins. Change-Id: I6eafe0f9d227ec73d8c9029675866c67063768fb Reviewed-by: Reviewed-by: Christian Stenger --- qbs/imports/QtcTestFiles.qbs | 6 ++++++ src/plugins/android/android.qbs | 4 +--- src/plugins/autotest/autotest.qbs | 4 +--- src/plugins/clangcodemodel/clangcodemodel.qbs | 4 +--- src/plugins/clangformat/clangformat.qbs | 4 +--- src/plugins/clangtools/clangtools.qbs | 4 +--- .../compilationdatabaseprojectmanager.qbs | 4 +--- src/plugins/coreplugin/coreplugin.qbs | 4 +--- src/plugins/cppeditor/cppeditor.qbs | 4 +--- src/plugins/debugger/debugger.qbs | 4 +--- src/plugins/designer/designer.qbs | 4 +--- src/plugins/fakevim/fakevim.qbs | 4 +--- src/plugins/mcusupport/mcusupport.qbs | 3 +-- src/plugins/perfprofiler/perfprofiler.qbs | 4 +--- src/plugins/projectexplorer/projectexplorer.qbs | 4 +--- src/plugins/qmljstools/qmljstools.qbs | 4 +--- src/plugins/qmlpreview/qmlpreview.qbs | 4 +--- src/plugins/qmlprofiler/qmlprofiler.qbs | 4 +--- src/plugins/remotelinux/remotelinux.qbs | 4 +--- src/plugins/silversearcher/silversearcher.qbs | 4 +--- src/plugins/texteditor/texteditor.qbs | 4 +--- src/plugins/valgrind/valgrind.qbs | 4 +--- src/plugins/vcpkg/vcpkg.qbs | 4 +--- src/plugins/webassembly/webassembly.qbs | 4 +--- 24 files changed, 29 insertions(+), 68 deletions(-) create mode 100644 qbs/imports/QtcTestFiles.qbs diff --git a/qbs/imports/QtcTestFiles.qbs b/qbs/imports/QtcTestFiles.qbs new file mode 100644 index 00000000000..ab27a8df8a1 --- /dev/null +++ b/qbs/imports/QtcTestFiles.qbs @@ -0,0 +1,6 @@ +import qbs 1.0 + +Group { + name: "Unit tests" + condition: qtc.testsEnabled +} diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 5c9b6564c7b..c6d1611636f 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -116,9 +116,7 @@ Project { "sdkmanageroutputparser.h" ] - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "android_tst.qrc", "androidsdkmanager_test.cpp", diff --git a/src/plugins/autotest/autotest.qbs b/src/plugins/autotest/autotest.qbs index f0bccd79c33..90f1728c4ae 100644 --- a/src/plugins/autotest/autotest.qbs +++ b/src/plugins/autotest/autotest.qbs @@ -125,9 +125,7 @@ QtcPlugin { ] } - Group { - name: "Test sources" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "autotestunittests.cpp", "autotestunittests.h", diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index b4a1bc93a53..903a81147a9 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -94,9 +94,7 @@ QtcPlugin { } } - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { prefix: "test/" files: [ "activationsequenceprocessortest.cpp", diff --git a/src/plugins/clangformat/clangformat.qbs b/src/plugins/clangformat/clangformat.qbs index bd1b9677632..057035cd1a6 100644 --- a/src/plugins/clangformat/clangformat.qbs +++ b/src/plugins/clangformat/clangformat.qbs @@ -54,10 +54,8 @@ QtcPlugin { "clangformatutils.cpp", ] - Group { - name: "Tests" + QtcTestFiles { prefix: "tests/" - condition: qtc.testsEnabled cpp.defines: outer.concat('TESTDATA_DIR="' + sourceDirectory + "/tests/data" + '"') files: [ "clangformat-test.cpp", diff --git a/src/plugins/clangtools/clangtools.qbs b/src/plugins/clangtools/clangtools.qbs index 9c86d4bb113..ad8543bf611 100644 --- a/src/plugins/clangtools/clangtools.qbs +++ b/src/plugins/clangtools/clangtools.qbs @@ -74,9 +74,7 @@ QtcPlugin { "virtualfilesystemoverlay.h", ] - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "clangtoolspreconfiguredsessiontests.cpp", "clangtoolspreconfiguredsessiontests.h", diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanager.qbs b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanager.qbs index 9c12b05a3a7..ce7e4e35ac3 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanager.qbs +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanager.qbs @@ -21,9 +21,7 @@ QtcPlugin { "compilationdbparser.h", ] - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "compilationdatabasetests.cpp", "compilationdatabasetests.h", diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index be30292174b..b99b8be2dfb 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -271,9 +271,7 @@ Project { ] } - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "testdatadir.cpp", "testdatadir.h", diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index cb7b145078c..1824af07090 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -245,9 +245,7 @@ QtcPlugin { ] } - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { cpp.defines: outer.concat(['SRCDIR="' + FileInfo.path(filePath) + '"']) files: [ "compileroptionsbuilder_test.cpp", diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 50f1eba24f9..8319bea822b 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -239,9 +239,7 @@ Project { ] } - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "debuggerunittests.qrc", ] diff --git a/src/plugins/designer/designer.qbs b/src/plugins/designer/designer.qbs index 411be43283b..b730485329d 100644 --- a/src/plugins/designer/designer.qbs +++ b/src/plugins/designer/designer.qbs @@ -77,9 +77,7 @@ QtcPlugin { ] } - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "gotoslot_test.cpp" ] cpp.defines: outer.concat(['SRCDIR="' + FileInfo.path(filePath) + '"']) diff --git a/src/plugins/fakevim/fakevim.qbs b/src/plugins/fakevim/fakevim.qbs index cdfb9e24ddf..a4dad38428f 100644 --- a/src/plugins/fakevim/fakevim.qbs +++ b/src/plugins/fakevim/fakevim.qbs @@ -25,9 +25,7 @@ QtcPlugin { "fakevimtr.h", ] - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: ["fakevim_test.cpp"] } } diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index e6aec151a06..b0fa090b414 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -58,8 +58,7 @@ QtcPlugin { "settingshandler.cpp", ] - Group { - name: "McuSupport test files" + QtcTestFiles { condition: qtc.testsEnabled && (qtc_gtest_gmock.hasRepo || qtc_gtest_gmock.externalLibsPresent) prefix: "test/" files: [ diff --git a/src/plugins/perfprofiler/perfprofiler.qbs b/src/plugins/perfprofiler/perfprofiler.qbs index f3151ae0a63..7a037e7fa47 100644 --- a/src/plugins/perfprofiler/perfprofiler.qbs +++ b/src/plugins/perfprofiler/perfprofiler.qbs @@ -75,9 +75,7 @@ QtcPlugin { files: [ "PerfProfilerFlameGraphView.qml" ] } - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { prefix: "tests/" files: [ "perfprofilertracefile_test.cpp", diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 315a8d361e0..23870334857 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -250,9 +250,7 @@ Project { ] } - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: ["outputparser_test.h", "outputparser_test.cpp"] } diff --git a/src/plugins/qmljstools/qmljstools.qbs b/src/plugins/qmljstools/qmljstools.qbs index 68c9a9dfc15..d13342e8dd2 100644 --- a/src/plugins/qmljstools/qmljstools.qbs +++ b/src/plugins/qmljstools/qmljstools.qbs @@ -54,9 +54,7 @@ QtcPlugin { "qmljstools.qrc" ] - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: ["qmljstools_test.cpp"] } diff --git a/src/plugins/qmlpreview/qmlpreview.qbs b/src/plugins/qmlpreview/qmlpreview.qbs index 7b0f96dde76..e44f432c41a 100644 --- a/src/plugins/qmlpreview/qmlpreview.qbs +++ b/src/plugins/qmlpreview/qmlpreview.qbs @@ -38,9 +38,7 @@ QtcPlugin { ] } - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { prefix: "tests/" files: [ "qmlpreviewclient_test.cpp", diff --git a/src/plugins/qmlprofiler/qmlprofiler.qbs b/src/plugins/qmlprofiler/qmlprofiler.qbs index 5cc3604a07b..56a1e00cd6a 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.qbs +++ b/src/plugins/qmlprofiler/qmlprofiler.qbs @@ -73,9 +73,7 @@ QtcPlugin { files: "qml/**" } - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { prefix: "tests/" files: [ "debugmessagesmodel_test.cpp", "debugmessagesmodel_test.h", diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index 94a3878fe04..03a6afad10f 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -67,9 +67,7 @@ Project { "images/embeddedtarget.png", ] - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "filesystemaccess_test.cpp", "filesystemaccess_test.h", diff --git a/src/plugins/silversearcher/silversearcher.qbs b/src/plugins/silversearcher/silversearcher.qbs index f099858f6e3..8cf2cd15090 100644 --- a/src/plugins/silversearcher/silversearcher.qbs +++ b/src/plugins/silversearcher/silversearcher.qbs @@ -13,9 +13,7 @@ QtcPlugin { "silversearcherplugin.cpp", "silversearcherplugin.h", ] - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "outputparser_test.cpp", "outputparser_test.h", diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index 2aacf5d3736..1b94811a563 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -222,9 +222,7 @@ Project { ] } - Group { - name: "Tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "texteditor_test.cpp", ] diff --git a/src/plugins/valgrind/valgrind.qbs b/src/plugins/valgrind/valgrind.qbs index f0e117ce98a..973b1d7b85a 100644 --- a/src/plugins/valgrind/valgrind.qbs +++ b/src/plugins/valgrind/valgrind.qbs @@ -76,9 +76,7 @@ QtcPlugin { ] } - Group { - name: "Test sources" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "valgrindmemcheckparsertest.cpp", "valgrindmemcheckparsertest.h", diff --git a/src/plugins/vcpkg/vcpkg.qbs b/src/plugins/vcpkg/vcpkg.qbs index 9ab32702090..dff796ab917 100644 --- a/src/plugins/vcpkg/vcpkg.qbs +++ b/src/plugins/vcpkg/vcpkg.qbs @@ -23,9 +23,7 @@ QtcPlugin { "vcpkgsettings.h", ] - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "vcpkg_test.h", "vcpkg_test.cpp", diff --git a/src/plugins/webassembly/webassembly.qbs b/src/plugins/webassembly/webassembly.qbs index 9c6e95f99f7..b859ea538a2 100644 --- a/src/plugins/webassembly/webassembly.qbs +++ b/src/plugins/webassembly/webassembly.qbs @@ -33,9 +33,7 @@ QtcPlugin { "webassemblytoolchain.h", ] - Group { - name: "Unit tests" - condition: qtc.testsEnabled + QtcTestFiles { files: [ "webassembly_test.cpp", "webassembly_test.h", From 44074accc7eb2fe0659ccd5166975d54dfb5cc68 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 14 Mar 2023 09:09:55 +0100 Subject: [PATCH 0331/1447] Terminal: Use QtcProcess to start terminal window Previously DesktopDevice::openTerminal used custom code to open a terminal window. This patch changes it to use QtcProcess with TerminalMode::On. This also removes the need for "openTerminal.py" on macOS. Change-Id: Iec978bdd19487ff8e59dcd88c35c2d01b0681022 Reviewed-by: Cristian Adam --- share/qtcreator/CMakeLists.txt | 4 - share/qtcreator/scripts/openTerminal.py | 112 ------------------ src/libs/utils/launcherpackets.cpp | 6 +- src/libs/utils/launcherpackets.h | 1 + src/libs/utils/launchersocket.cpp | 1 + src/libs/utils/processinterface.h | 1 + src/libs/utils/processutils.cpp | 33 ++++-- src/libs/utils/processutils.h | 2 +- src/libs/utils/qtcprocess.cpp | 15 ++- src/libs/utils/qtcprocess.h | 3 + src/libs/utils/terminalcommand.cpp | 8 +- src/libs/utils/terminalhooks.cpp | 19 +-- src/libs/utils/terminalinterface.cpp | 4 +- src/plugins/docker/dockerdevice.cpp | 11 +- .../devicesupport/desktopdevice.cpp | 74 +++--------- .../devicesupport/desktopdevice.h | 8 +- src/plugins/remotelinux/linuxdevice.cpp | 2 + src/plugins/terminal/terminalpane.cpp | 9 +- .../processlauncher/launchersockethandler.cpp | 5 +- 19 files changed, 102 insertions(+), 216 deletions(-) delete mode 100755 share/qtcreator/scripts/openTerminal.py diff --git a/share/qtcreator/CMakeLists.txt b/share/qtcreator/CMakeLists.txt index 0a868915a3d..49b556b5c52 100644 --- a/share/qtcreator/CMakeLists.txt +++ b/share/qtcreator/CMakeLists.txt @@ -37,10 +37,6 @@ set(resource_files debugger/utils.py ) -if (APPLE) - set(resource_directories ${resource_directories} scripts) -endif() - # copy resource directories during build qtc_copy_to_builddir(copy_share_to_builddir DIRECTORIES ${resource_directories} diff --git a/share/qtcreator/scripts/openTerminal.py b/share/qtcreator/scripts/openTerminal.py deleted file mode 100755 index 3dd1bcb1b92..00000000000 --- a/share/qtcreator/scripts/openTerminal.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2018 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -import os -import pipes -import stat -import subprocess -import sys -from tempfile import NamedTemporaryFile - -def quote_shell(arg): - return pipes.quote(arg) - -def clean_environment_script(): - # keep some basic environment settings to ensure functioning terminal and config files - env_to_keep = ' '.join(['_', 'HOME', 'LOGNAME', 'PWD', 'SHELL', 'TMPDIR', 'USER', 'TERM', - 'TERM_PROGRAM', 'TERM_PROGRAM_VERSION', 'TERM_SESSION_CLASS_ID', - 'TERM_SESSION_ID']) - return r''' -function ignore() { - local keys=(''' + env_to_keep + ''') - local v=$1 - for e in "${keys[@]}"; do [[ "$e" == "$v" ]] && return 0; done -} -while read -r line; do - key=$(echo $line | /usr/bin/cut -d '=' -f 1) - ignore $key || unset $key -done < <(env) -''' - -def system_login_script_bash(): - return r''' -[ -r /etc/profile ] && source /etc/profile -# fake behavior of /etc/profile as if BASH was set. It isn't for non-interactive shell -export PS1='\h:\W \u\$ ' -[ -r /etc/bashrc ] && source /etc/bashrc -''' - -def login_script_bash(): - return r''' -if [ -f $HOME/.bash_profile ]; then - source $HOME/.bash_profile -elif [ -f $HOME/.bash_login ]; then - source $HOME/.bash_login ] -elif [ -f $HOME/.profile ]; then - source $HOME/.profile -fi -''' - -def system_login_script_zsh(): - return '[ -r /etc/profile ] && source /etc/profile\n' - -def login_script_zsh(): - return r''' -[ -r $HOME/.zprofile ] && source $HOME/.zprofile -[ -r $HOME/.zshrc ] && source $HOME/.zshrc -[ -r $HOME/.zlogin ] && source $HOME/.zlogin -''' - -def environment_script(): - return ''.join(['export ' + quote_shell(key + '=' + os.environ[key]) + '\n' - for key in os.environ]) - -def zsh_setup(shell): - return (shell, - system_login_script_zsh, - login_script_zsh, - shell + ' -c', - shell + ' -d -f') - -def bash_setup(shell): - bash = shell if shell is not None and shell.endswith('/bash') else '/bin/bash' - return (bash, - system_login_script_bash, - login_script_bash, - bash + ' -c', - bash + ' --noprofile -l') - -def main(): - # create temporary file to be sourced into bash that deletes itself - with NamedTemporaryFile(mode='wt', delete=False) as shell_script: - shell = os.environ.get('SHELL') - shell, system_login_script, login_script, non_interactive_shell, interactive_shell = ( - zsh_setup(shell) if shell is not None and shell.endswith('/zsh') - else bash_setup(shell)) - - commands = ('#!' + shell + '\n' + - 'rm ' + quote_shell(shell_script.name) + '\n' + - clean_environment_script() + - system_login_script() + # /etc/(z)profile by default resets the path, so do first - environment_script() + - login_script() + - 'cd ' + quote_shell(os.getcwd()) + '\n' + - ('exec ' + non_interactive_shell + ' ' + - quote_shell(' '.join([quote_shell(arg) for arg in sys.argv[1:]])) + '\n' - if len(sys.argv) > 1 else 'exec ' + interactive_shell + '\n') - ) - shell_script.write(commands) - shell_script.flush() - os.chmod(shell_script.name, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR) - # TODO /usr/bin/open doesn't work with notarized app in macOS 13, - # use osascript instead (QTCREATORBUG-28683). - # This has the disadvantage that the Terminal windows doesn't close - # automatically anymore. - # subprocess.call(['/usr/bin/open', '-a', 'Terminal', shell_script.name]) - subprocess.call(['/usr/bin/osascript', '-e', 'tell app "Terminal" to activate']) - subprocess.call(['/usr/bin/osascript', '-e', 'tell app "Terminal" to do script "' + shell_script.name + '"']) - -if __name__ == "__main__": - main() diff --git a/src/libs/utils/launcherpackets.cpp b/src/libs/utils/launcherpackets.cpp index 13c3a1560d4..37261224ef5 100644 --- a/src/libs/utils/launcherpackets.cpp +++ b/src/libs/utils/launcherpackets.cpp @@ -48,7 +48,8 @@ void StartProcessPacket::doSerialize(QDataStream &stream) const << lowPriority << unixTerminalDisabled << useCtrlCStub - << reaperTimeout; + << reaperTimeout + << createConsoleOnWindows; } void StartProcessPacket::doDeserialize(QDataStream &stream) @@ -68,7 +69,8 @@ void StartProcessPacket::doDeserialize(QDataStream &stream) >> lowPriority >> unixTerminalDisabled >> useCtrlCStub - >> reaperTimeout; + >> reaperTimeout + >> createConsoleOnWindows; processMode = Utils::ProcessMode(processModeInt); processChannelMode = QProcess::ProcessChannelMode(processChannelModeInt); } diff --git a/src/libs/utils/launcherpackets.h b/src/libs/utils/launcherpackets.h index 2f0bae2915e..27e98a74e5b 100644 --- a/src/libs/utils/launcherpackets.h +++ b/src/libs/utils/launcherpackets.h @@ -98,6 +98,7 @@ public: bool unixTerminalDisabled = false; bool useCtrlCStub = false; int reaperTimeout = 500; + bool createConsoleOnWindows = false; private: void doSerialize(QDataStream &stream) const override; diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index 07ebc84df9a..f4feda595a4 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -257,6 +257,7 @@ void CallerHandle::start(const QString &program, const QStringList &arguments) p.unixTerminalDisabled = m_setup->m_unixTerminalDisabled; p.useCtrlCStub = m_setup->m_useCtrlCStub; p.reaperTimeout = m_setup->m_reaperTimeout; + p.createConsoleOnWindows = m_setup->m_createConsoleOnWindows; sendPacket(p); } diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index 5f3a4378d48..bd02428ef9b 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -68,6 +68,7 @@ public: bool m_unixTerminalDisabled = false; bool m_useCtrlCStub = false; bool m_belowNormalPriority = false; // internal, dependent on other fields and specific code path + bool m_createConsoleOnWindows = false; }; class QTCREATOR_UTILS_EXPORT ProcessResultData diff --git a/src/libs/utils/processutils.cpp b/src/libs/utils/processutils.cpp index c8394e37dd2..b534d6f8bb2 100644 --- a/src/libs/utils/processutils.cpp +++ b/src/libs/utils/processutils.cpp @@ -45,16 +45,6 @@ void ProcessStartHandler::handleProcessStarted() } } -void ProcessStartHandler::setBelowNormalPriority() -{ -#ifdef Q_OS_WIN - m_process->setCreateProcessArgumentsModifier( - [](QProcess::CreateProcessArguments *args) { - args->flags |= BELOW_NORMAL_PRIORITY_CLASS; - }); -#endif // Q_OS_WIN -} - void ProcessStartHandler::setNativeArguments(const QString &arguments) { #ifdef Q_OS_WIN @@ -65,6 +55,29 @@ void ProcessStartHandler::setNativeArguments(const QString &arguments) #endif // Q_OS_WIN } +void ProcessStartHandler::setWindowsSpecificStartupFlags(bool belowNormalPriority, + bool createConsoleWindow) +{ +#ifdef Q_OS_WIN + if (!belowNormalPriority && !createConsoleWindow) + return; + + m_process->setCreateProcessArgumentsModifier( + [belowNormalPriority, createConsoleWindow](QProcess::CreateProcessArguments *args) { + if (createConsoleWindow) { + args->flags |= CREATE_NEW_CONSOLE; + args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES; + } + + if (belowNormalPriority) + args->flags |= BELOW_NORMAL_PRIORITY_CLASS; + }); +#else // Q_OS_WIN + Q_UNUSED(belowNormalPriority) + Q_UNUSED(createConsoleWindow) +#endif +} + #ifdef Q_OS_WIN static BOOL sendMessage(UINT message, HWND hwnd, LPARAM lParam) { diff --git a/src/libs/utils/processutils.h b/src/libs/utils/processutils.h index 60161f83984..fa915e2ac42 100644 --- a/src/libs/utils/processutils.h +++ b/src/libs/utils/processutils.h @@ -20,8 +20,8 @@ public: QIODevice::OpenMode openMode() const; void handleProcessStart(); void handleProcessStarted(); - void setBelowNormalPriority(); void setNativeArguments(const QString &arguments); + void setWindowsSpecificStartupFlags(bool belowNormalPriority, bool createConsoleWindow); private: ProcessMode m_processMode = ProcessMode::Reader; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 0ec90d393b4..1583316832b 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -454,9 +454,10 @@ private: ProcessStartHandler *handler = m_process->processStartHandler(); handler->setProcessMode(m_setup.m_processMode); handler->setWriteData(m_setup.m_writeData); - if (m_setup.m_belowNormalPriority) - handler->setBelowNormalPriority(); handler->setNativeArguments(m_setup.m_nativeArguments); + handler->setWindowsSpecificStartupFlags(m_setup.m_belowNormalPriority, + m_setup.m_createConsoleOnWindows); + m_process->setProcessEnvironment(m_setup.m_environment.toProcessEnvironment()); m_process->setWorkingDirectory(m_setup.m_workingDirectory.path()); m_process->setStandardInputFile(m_setup.m_standardInputFile); @@ -1313,6 +1314,16 @@ QString QtcProcess::toStandaloneCommandLine() const return parts.join(" "); } +void QtcProcess::setCreateConsoleOnWindows(bool create) +{ + d->m_setup.m_createConsoleOnWindows = create; +} + +bool QtcProcess::createConsoleOnWindows() const +{ + return d->m_setup.m_createConsoleOnWindows; +} + void QtcProcess::setExtraData(const QString &key, const QVariant &value) { d->m_setup.m_extraData.insert(key, value); diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 9d539f08e20..e016b50d613 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -181,6 +181,9 @@ public: QString toStandaloneCommandLine() const; + void setCreateConsoleOnWindows(bool create); + bool createConsoleOnWindows() const; + signals: void starting(); // On NotRunning -> Starting state transition void started(); // On Starting -> Running state transition diff --git a/src/libs/utils/terminalcommand.cpp b/src/libs/utils/terminalcommand.cpp index c25b379f321..102fc42e05d 100644 --- a/src/libs/utils/terminalcommand.cpp +++ b/src/libs/utils/terminalcommand.cpp @@ -65,13 +65,7 @@ TerminalCommand TerminalCommand::defaultTerminalEmulator() if (defaultTerm.command.isEmpty()) { if (HostOsInfo::isMacHost()) { - const FilePath termCmd = FilePath::fromString(QCoreApplication::applicationDirPath()) - / "../Resources/scripts/openTerminal.py"; - if (termCmd.exists()) - defaultTerm = {termCmd, "", ""}; - else - defaultTerm = {"/usr/X11/bin/xterm", "", "-e"}; - + return {"Terminal.app", "", ""}; } else if (HostOsInfo::isAnyUnixHost()) { defaultTerm = {"xterm", "", "-e"}; const Environment env = Environment::systemEnvironment(); diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index 8187229cbf5..6ee46b33616 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -3,10 +3,10 @@ #include "terminalhooks.h" -#include "terminalinterface.h" #include "filepath.h" #include "qtcprocess.h" #include "terminalcommand.h" +#include "terminalinterface.h" #include @@ -14,10 +14,9 @@ namespace Utils::Terminal { FilePath defaultShellForDevice(const FilePath &deviceRoot) { - if (!deviceRoot.needsDevice()) - return {}; + if (deviceRoot.osType() == OsTypeWindows) + return deviceRoot.withNewPath("cmd.exe").searchInPath(); - // TODO: Windows ? const Environment env = deviceRoot.deviceEnvironment(); FilePath shell = FilePath::fromUserInput(env.value_or("SHELL", "/bin/sh")); @@ -41,18 +40,23 @@ class ExternalTerminalProcessImpl final : public TerminalInterface void startStubProcess(const CommandLine &cmd, const ProcessSetupData &) override { + const TerminalCommand terminal = TerminalCommand::terminalEmulator(); + if (HostOsInfo::isWindowsHost()) { m_terminalProcess.setCommand(cmd); QObject::connect(&m_terminalProcess, &QtcProcess::done, this, [this] { m_interface->onStubExited(); }); + m_terminalProcess.setCreateConsoleOnWindows(true); + m_terminalProcess.setProcessMode(ProcessMode::Writer); m_terminalProcess.start(); - } else if (HostOsInfo::isMacHost()) { + } else if (HostOsInfo::isMacHost() && terminal.command == "Terminal.app") { QTemporaryFile f; f.setAutoRemove(false); f.open(); f.setPermissions(QFile::ExeUser | QFile::ReadUser | QFile::WriteUser); f.write("#!/bin/sh\n"); + f.write("clear\n"); f.write(QString("exec '%1' %2\n") .arg(cmd.executable().nativePath()) .arg(cmd.arguments()) @@ -64,11 +68,10 @@ class ExternalTerminalProcessImpl final : public TerminalInterface = QString("tell app \"Terminal\" to do script \"'%1'; rm -f '%1'; exit\"") .arg(path); - m_terminalProcess.setCommand({"osascript", {"-e", exe}}); + m_terminalProcess.setCommand( + {"osascript", {"-e", "tell app \"Terminal\" to activate", "-e", exe}}); m_terminalProcess.runBlocking(); } else { - const TerminalCommand terminal = TerminalCommand::terminalEmulator(); - CommandLine cmdLine = {terminal.command, {terminal.executeArgs}}; cmdLine.addCommandLineAsArgs(cmd, CommandLine::Raw); diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index 7ec7c755fd3..58d48cb910a 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -304,8 +304,6 @@ void TerminalInterface::start() return; } - m_setup.m_environment.unset(QLatin1String("TERM")); - Environment finalEnv = m_setup.m_environment; if (HostOsInfo::isWindowsHost()) { @@ -319,6 +317,8 @@ void TerminalInterface::start() if (!systemRoot.isEmpty()) finalEnv.set("SystemRoot", systemRoot); } + } else if (HostOsInfo::isMacHost()) { + finalEnv.set("TERM", "xterm-256color"); } if (finalEnv.hasChanges()) { diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 7bac522c5ba..861a8197ab7 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -294,6 +295,7 @@ void DockerProcessImpl::start() m_process.setExtraData(m_setup.m_extraData); m_process.setStandardInputFile(m_setup.m_standardInputFile); m_process.setAbortOnMetaChars(m_setup.m_abortOnMetaChars); + m_process.setCreateConsoleOnWindows(m_setup.m_createConsoleOnWindows); if (m_setup.m_lowPriority) m_process.setLowPriority(); @@ -403,7 +405,6 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat } QtcProcess *proc = new QtcProcess(d); - proc->setTerminalMode(TerminalMode::On); QObject::connect(proc, &QtcProcess::done, [proc] { if (proc->error() != QProcess::UnknownError && MessageManager::instance()) { @@ -413,10 +414,10 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat proc->deleteLater(); }); - const QString wd = workingDir.isEmpty() ? "/" : workingDir.path(); - proc->setCommand({settings->dockerBinaryPath.filePath(), - {"exec", "-it", "-w", wd, d->containerId(), "/bin/sh"}}); - proc->setEnvironment(Environment::systemEnvironment()); // The host system env. Intentional. + proc->setTerminalMode(TerminalMode::On); + proc->setEnvironment(env); + proc->setWorkingDirectory(workingDir); + proc->setCommand({Terminal::defaultShellForDevice(rootPath()), {}}); proc->start(); }); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 724b6608aad..4ad0d59d328 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -34,58 +35,11 @@ using namespace Utils; namespace ProjectExplorer { -static void startTerminalEmulator(const QString &workingDir, const Environment &env) -{ -#ifdef Q_OS_WIN - STARTUPINFO si; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - - PROCESS_INFORMATION pinfo; - ZeroMemory(&pinfo, sizeof(pinfo)); - - static const auto quoteWinCommand = [](const QString &program) { - const QChar doubleQuote = QLatin1Char('"'); - - // add the program as the first arg ... it works better - QString programName = program; - programName.replace(QLatin1Char('/'), QLatin1Char('\\')); - if (!programName.startsWith(doubleQuote) && !programName.endsWith(doubleQuote) - && programName.contains(QLatin1Char(' '))) { - programName.prepend(doubleQuote); - programName.append(doubleQuote); - } - return programName; - }; - const QString cmdLine = quoteWinCommand(qtcEnvironmentVariable("COMSPEC")); - // cmdLine is assumed to be detached - - // https://blogs.msdn.microsoft.com/oldnewthing/20090601-00/?p=18083 - - const QString totalEnvironment = env.toStringList().join(QChar(QChar::Null)) + QChar(QChar::Null); - LPVOID envPtr = (env != Environment::systemEnvironment()) - ? (WCHAR *)(totalEnvironment.utf16()) : nullptr; - - const bool success = CreateProcessW(0, (WCHAR *)cmdLine.utf16(), - 0, 0, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, - envPtr, workingDir.isEmpty() ? 0 : (WCHAR *)workingDir.utf16(), - &si, &pinfo); - - if (success) { - CloseHandle(pinfo.hThread); - CloseHandle(pinfo.hProcess); - } -#else - const TerminalCommand term = TerminalCommand::terminalEmulator(); - QProcess process; - process.setProgram(term.command.nativePath()); - process.setArguments(ProcessArgs::splitArgs(term.openArgs, HostOsInfo::hostOs())); - process.setProcessEnvironment(env.toProcessEnvironment()); - process.setWorkingDirectory(workingDir); - process.startDetached(); -#endif -} +class DesktopDevicePrivate : public QObject +{}; DesktopDevice::DesktopDevice() + : d(new DesktopDevicePrivate()) { setFileAccess(DesktopDeviceFileAccess::instance()); @@ -102,16 +56,24 @@ DesktopDevice::DesktopDevice() QString::fromLatin1("%1-%2").arg(DESKTOP_PORT_START).arg(DESKTOP_PORT_END); setFreePorts(Utils::PortList::fromString(portRange)); - setOpenTerminal([](const Environment &env, const FilePath &path) { - const QFileInfo fileInfo = path.toFileInfo(); - const QString workingDir = QDir::toNativeSeparators(fileInfo.isDir() ? - fileInfo.absoluteFilePath() : - fileInfo.absolutePath()); + setOpenTerminal([this](const Environment &env, const FilePath &path) { const Environment realEnv = env.hasChanges() ? env : Environment::systemEnvironment(); - startTerminalEmulator(workingDir, realEnv); + + const FilePath shell = Terminal::defaultShellForDevice(path); + + QtcProcess *process = new QtcProcess(d.get()); + QObject::connect(process, &QtcProcess::done, process, &QtcProcess::deleteLater); + + process->setTerminalMode(TerminalMode::On); + process->setEnvironment(realEnv); + process->setCommand({shell, {}}); + process->setWorkingDirectory(path); + process->start(); }); } +DesktopDevice::~DesktopDevice() = default; + IDevice::DeviceInfo DesktopDevice::deviceInformation() const { return DeviceInfo(); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h index ee5ac1ca5eb..28220f21ed6 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h @@ -6,18 +6,22 @@ #include "../projectexplorer_export.h" #include "idevice.h" -#include "idevicefactory.h" #include +#include + namespace ProjectExplorer { class ProjectExplorerPlugin; +class DesktopDevicePrivate; namespace Internal { class DesktopDeviceFactory; } class PROJECTEXPLORER_EXPORT DesktopDevice : public IDevice { public: + ~DesktopDevice() override; + IDevice::DeviceInfo deviceInformation() const override; IDeviceWidget *createWidget() override; @@ -40,6 +44,8 @@ protected: friend class ProjectExplorerPlugin; friend class Internal::DesktopDeviceFactory; + + std::unique_ptr d; }; } // namespace ProjectExplorer diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index a51a7d3bf03..760273e9ab5 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -645,6 +645,8 @@ void SshProcessInterfacePrivate::doStart() m_process.setPtyData(q->m_setup.m_ptyData); m_process.setReaperTimeout(q->m_setup.m_reaperTimeout); m_process.setWriteData(q->m_setup.m_writeData); + m_process.setCreateConsoleOnWindows(q->m_setup.m_createConsoleOnWindows); + // TODO: what about other fields from m_setup? SshParameters::setupSshEnvironment(&m_process); if (!m_sshParameters.x11DisplayName.isEmpty()) { diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index dd9cdb5239a..c2467ec71d4 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -6,6 +6,7 @@ #include "shellmodel.h" #include "terminaltr.h" #include "terminalwidget.h" +#include "utils/terminalhooks.h" #include #include @@ -175,7 +176,6 @@ QWidget *TerminalPane::outputWidget(QWidget *parent) auto terminalWidget = new TerminalWidget(parent); m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal")); setupTerminalWidget(terminalWidget); - } return m_tabWidget; @@ -201,12 +201,13 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) if (!terminal) return; - auto setTabText = [this](TerminalWidget * terminal) { + auto setTabText = [this](TerminalWidget *terminal) { auto index = m_tabWidget->indexOf(terminal); const FilePath cwd = terminal->cwd(); - const QString exe = terminal->currentCommand().isEmpty() ? terminal->shellName() - : terminal->currentCommand().executable().fileName(); + const QString exe = terminal->currentCommand().isEmpty() + ? terminal->shellName() + : terminal->currentCommand().executable().fileName(); if (cwd.isEmpty()) m_tabWidget->setTabText(index, exe); diff --git a/src/tools/processlauncher/launchersockethandler.cpp b/src/tools/processlauncher/launchersockethandler.cpp index 21167f8d773..a0a2733ded1 100644 --- a/src/tools/processlauncher/launchersockethandler.cpp +++ b/src/tools/processlauncher/launchersockethandler.cpp @@ -172,6 +172,7 @@ void LauncherSocketHandler::handleStartPacket() const auto packet = LauncherPacket::extractPacket( m_packetParser.token(), m_packetParser.packetData()); + process->setEnvironment(packet.env); process->setWorkingDirectory(packet.workingDir); // Forwarding is handled by the LauncherInterface @@ -179,10 +180,10 @@ void LauncherSocketHandler::handleStartPacket() ? QProcess::MergedChannels : QProcess::SeparateChannels); process->setStandardInputFile(packet.standardInputFile); ProcessStartHandler *handler = process->processStartHandler(); + handler->setWindowsSpecificStartupFlags(packet.belowNormalPriority, + packet.createConsoleOnWindows); handler->setProcessMode(packet.processMode); handler->setWriteData(packet.writeData); - if (packet.belowNormalPriority) - handler->setBelowNormalPriority(); handler->setNativeArguments(packet.nativeArguments); if (packet.lowPriority) process->setLowPriority(); From 97f1333cf7d529a1a25dd4d1fbf5b33c55ff5b1f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 20 Mar 2023 20:01:10 +0100 Subject: [PATCH 0332/1447] CppCurrentDocumentFilter: Avoid using internalData Change-Id: Ic4dc03101f319449ca9835a23c786fbb0528f1c3 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../cppeditor/cppcurrentdocumentfilter.cpp | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index adb1e5d48e3..6c6a568fac9 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -53,13 +53,17 @@ void CppCurrentDocumentFilter::makeAuxiliary() QList CppCurrentDocumentFilter::matchesFor( QFutureInterface &future, const QString & entry) { - QList goodEntries; - QList betterEntries; - const QRegularExpression regexp = createRegExp(entry); if (!regexp.isValid()) - return goodEntries; + return {}; + struct Entry + { + LocatorFilterEntry entry; + IndexItem::Ptr info; + }; + QList goodEntries; + QList betterEntries; const QList items = itemsOfCurrentDocument(); for (const IndexItem::Ptr &info : items) { if (future.isCanceled()) @@ -74,7 +78,6 @@ QList CppCurrentDocumentFilter::matchesFor( QRegularExpressionMatch match = regexp.match(matchString); if (match.hasMatch()) { const bool betterMatch = match.capturedStart() == 0; - QVariant id = QVariant::fromValue(info); QString name = matchString; QString extraInfo = info->symbolScope(); if (info->type() == IndexItem::Function) { @@ -84,7 +87,7 @@ QList CppCurrentDocumentFilter::matchesFor( } } - LocatorFilterEntry filterEntry(this, name, id, info->icon()); + LocatorFilterEntry filterEntry(this, name, {}, info->icon()); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; if (match.hasMatch()) { @@ -96,28 +99,26 @@ QList CppCurrentDocumentFilter::matchesFor( } if (betterMatch) - betterEntries.append(filterEntry); + betterEntries.append({filterEntry, info}); else - goodEntries.append(filterEntry); + goodEntries.append({filterEntry, info}); } } // entries are unsorted by design! betterEntries += goodEntries; - QHash> possibleDuplicates; - for (const LocatorFilterEntry &e : std::as_const(betterEntries)) { - const IndexItem::Ptr info = qvariant_cast(e.internalData); - possibleDuplicates[info->scopedSymbolName() + info->symbolType()] << e; - } + QHash> possibleDuplicates; + for (const Entry &e : std::as_const(betterEntries)) + possibleDuplicates[e.info->scopedSymbolName() + e.info->symbolType()] << e; for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { - const QList &duplicates = it.value(); + const QList &duplicates = it.value(); if (duplicates.size() == 1) continue; - QList declarations; - QList definitions; - for (const LocatorFilterEntry &candidate : duplicates) { - const IndexItem::Ptr info = qvariant_cast(candidate.internalData); + QList declarations; + QList definitions; + for (const Entry &candidate : duplicates) { + const IndexItem::Ptr info = candidate.info; if (info->type() != IndexItem::Function) break; if (info->isFunctionDefinition()) @@ -127,14 +128,14 @@ QList CppCurrentDocumentFilter::matchesFor( } if (definitions.size() == 1 && declarations.size() + definitions.size() == duplicates.size()) { - for (const LocatorFilterEntry &decl : std::as_const(declarations)) { - Utils::erase(betterEntries, [&decl](const LocatorFilterEntry &e) { - return e.internalData == decl.internalData; + for (const Entry &decl : std::as_const(declarations)) { + Utils::erase(betterEntries, [&decl](const Entry &e) { + return e.info == decl.info; }); } } } - return betterEntries; + return Utils::transform(betterEntries, [](const Entry &entry) { return entry.entry; }); } void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc) From 83d818496c1cb9492f72139b1f7629c25aee2fad Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 21 Mar 2023 16:19:16 +0100 Subject: [PATCH 0333/1447] WASM/MCU: Fix includes Change-Id: I47b547249c15d799bf4567fbede83afd83fcd1bf Reviewed-by: Cristian Adam --- src/plugins/mcusupport/mcusupportdevice.h | 1 + src/plugins/webassembly/webassemblydevice.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/plugins/mcusupport/mcusupportdevice.h b/src/plugins/mcusupport/mcusupportdevice.h index 262edc39ab8..78bf6b68e3a 100644 --- a/src/plugins/mcusupport/mcusupportdevice.h +++ b/src/plugins/mcusupport/mcusupportdevice.h @@ -4,6 +4,7 @@ #pragma once #include +#include namespace McuSupport { namespace Internal { diff --git a/src/plugins/webassembly/webassemblydevice.h b/src/plugins/webassembly/webassemblydevice.h index 6ff4a2481e7..520d0fb5355 100644 --- a/src/plugins/webassembly/webassemblydevice.h +++ b/src/plugins/webassembly/webassemblydevice.h @@ -4,6 +4,7 @@ #pragma once #include +#include namespace WebAssembly { namespace Internal { From 5a0ec63895b009058ecfca4d0d4dd9d3b841aedb Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Thu, 16 Feb 2023 15:43:17 +0100 Subject: [PATCH 0334/1447] Core: Refactor disambiguateDisplayNames - Used FilePath utils for finding common ancestor Change-Id: I2491a66196128e927bd0da5729ed45eeb0b35646 Reviewed-by: Eike Ziller --- .../editormanager/documentmodel.cpp | 110 +++++++----------- .../editormanager/documentmodel_p.h | 12 -- 2 files changed, 40 insertions(+), 82 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index 04a877ec491..876b22b1281 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -121,63 +123,55 @@ DocumentModel::Entry *DocumentModelPrivate::addEntry(DocumentModel::Entry *entry bool DocumentModelPrivate::disambiguateDisplayNames(DocumentModel::Entry *entry) { const QString displayName = entry->plainDisplayName(); - int minIdx = -1, maxIdx = -1; - QList dups; + QList dups; + FilePaths paths; + int minIdx = m_entries.count(); + int maxIdx = 0; - for (int i = 0, total = m_entries.count(); i < total; ++i) { + for (int i = 0; i < m_entries.count(); ++i) { DocumentModel::Entry *e = m_entries.at(i); if (e == entry || e->plainDisplayName() == displayName) { - e->document->setUniqueDisplayName(QString()); - dups += DynamicEntry(e); - maxIdx = i; - if (minIdx < 0) + if (minIdx > i) minIdx = i; + if (maxIdx < i) + maxIdx = i; + dups += e; + if (!e->filePath().isEmpty()) + paths += e->filePath(); } } - const int dupsCount = dups.count(); - if (dupsCount == 0) + const auto triggerDataChanged = [this](int minIdx, int maxIdx) { + const QModelIndex idxMin = index(minIdx + 1 /**/, 0); + const QModelIndex idxMax = index(maxIdx + 1 /**/, 0); + if (idxMin.isValid() && idxMax.isValid()) + emit dataChanged(idxMin, idxMax); + }; + + if (dups.count() == 1) { + dups.at(0)->document->setUniqueDisplayName({}); + triggerDataChanged(minIdx, maxIdx); return false; - - if (dupsCount > 1) { - int serial = 0; - int count = 0; - // increase uniqueness unless no dups are left - forever { - bool seenDups = false; - for (int i = 0; i < dupsCount - 1; ++i) { - DynamicEntry &e = dups[i]; - const Utils::FilePath myFileName = e->document->filePath(); - if (e->document->isTemporary() || myFileName.isEmpty() || count > 10) { - // path-less entry, append number - e.setNumberedName(++serial); - continue; - } - for (int j = i + 1; j < dupsCount; ++j) { - DynamicEntry &e2 = dups[j]; - if (e->displayName().compare(e2->displayName(), Utils::HostOsInfo::fileNameCaseSensitivity()) == 0) { - const Utils::FilePath otherFileName = e2->document->filePath(); - if (otherFileName.isEmpty()) - continue; - seenDups = true; - e2.disambiguate(); - if (j > maxIdx) - maxIdx = j; - } - } - if (seenDups) { - e.disambiguate(); - ++count; - break; - } - } - if (!seenDups) - break; - } } - emit dataChanged(index(minIdx + 1, 0), index(maxIdx + 1, 0)); + const FilePath commonAncestor = FileUtils::commonPath(paths); + + int countWithoutFilePath = 0; + for (DocumentModel::Entry *e : std::as_const(dups)) { + const FilePath path = e->filePath(); + if (path.isEmpty()) { + e->document->setUniqueDisplayName(QStringLiteral("%1 (%2)") + .arg(e->document->displayName()) + .arg(++countWithoutFilePath)); + continue; + } + const QString uniqueDisplayName = path.relativeChildPath(commonAncestor).toString(); + if (uniqueDisplayName != "" && e->document->uniqueDisplayName() != uniqueDisplayName) { + e->document->setUniqueDisplayName(uniqueDisplayName); + } + } + triggerDataChanged(minIdx, maxIdx); return true; } @@ -483,30 +477,6 @@ void DocumentModelPrivate::removeAllSuspendedEntries(PinnedFileRemovalPolicy pin } } -DocumentModelPrivate::DynamicEntry::DynamicEntry(DocumentModel::Entry *e) : - entry(e), - pathComponents(0) -{ -} - -DocumentModel::Entry *DocumentModelPrivate::DynamicEntry::operator->() const -{ - return entry; -} - -void DocumentModelPrivate::DynamicEntry::disambiguate() -{ - const QString display = entry->filePath().fileNameWithPathComponents(++pathComponents); - entry->document->setUniqueDisplayName(display); -} - -void DocumentModelPrivate::DynamicEntry::setNumberedName(int number) -{ - entry->document->setUniqueDisplayName(QStringLiteral("%1 (%2)") - .arg(entry->document->displayName()) - .arg(number)); -} - } // Internal DocumentModel::Entry::Entry() : diff --git a/src/plugins/coreplugin/editormanager/documentmodel_p.h b/src/plugins/coreplugin/editormanager/documentmodel_p.h index 8e3efa98b0b..6b99d3fe438 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel_p.h +++ b/src/plugins/coreplugin/editormanager/documentmodel_p.h @@ -61,18 +61,6 @@ public: void itemChanged(IDocument *document); - class DynamicEntry - { - public: - DocumentModel::Entry *entry; - int pathComponents; - - DynamicEntry(DocumentModel::Entry *e); - DocumentModel::Entry *operator->() const; - void disambiguate(); - void setNumberedName(int number); - }; - QList m_entries; QMap > m_editors; QHash m_entryByFixedPath; From 4d6683b2cb4bb52a80bac8b3771f85bc29adace4 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 22 Mar 2023 08:55:39 +0100 Subject: [PATCH 0335/1447] Docker: Fix warning Change-Id: Ia4665c1fcd0f52b5b8180b811e59ad7ba5bc2587 Reviewed-by: Eike Ziller --- src/plugins/docker/dockerdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 861a8197ab7..02770e89a7d 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -394,7 +394,7 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat setDisplayName(Tr::tr("Docker Image \"%1\" (%2)").arg(data.repoAndTag()).arg(data.imageId)); setAllowEmptyCommand(true); - setOpenTerminal([this, settings](const Environment &env, const FilePath &workingDir) { + setOpenTerminal([this](const Environment &env, const FilePath &workingDir) { Q_UNUSED(env); // TODO: That's the runnable's environment in general. Use it via -e below. if (!updateContainerAccess()) return; From 6079b7b37849205858aa218a580719fc6ca26166 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 20 Mar 2023 15:40:59 +0100 Subject: [PATCH 0336/1447] Android: Update SDK manager tree display Adopt latest naming in Android Studio. Change-Id: I524adf5858933fddefe496db434b2fdca029d18f Reviewed-by: Reviewed-by: Assam Boudjelthia --- src/plugins/android/androidmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index fd5e442cdb3..fa299ba4e21 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -519,9 +519,9 @@ QString AndroidManager::androidNameForApiLevel(int x) case 31: return QLatin1String("Android 12.0 (S)"); case 32: - return QLatin1String("Android 12L (API 32)"); + return QLatin1String("Android 12L (Sv2, API 32)"); case 33: - return QLatin1String("Android Tiramisu"); + return QLatin1String("Android 13.0 (Tiramisu)"); default: return Tr::tr("Unknown Android version. API Level: %1").arg(x); } From 7014376aaaafad1c17d2bfc265eb419aeb7c8f04 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 22 Mar 2023 10:05:10 +0100 Subject: [PATCH 0337/1447] Python: Tweak handling of python project files Improves the handling of the preferred python project file (*.pyproject) and makes use of the json support. Change-Id: I24d6e2c1d10899efacec0fc9b03660bb8f25dfe7 Reviewed-by: David Schulz --- src/plugins/python/Python.json.in | 8 ++++++-- src/plugins/python/pythonplugin.cpp | 1 + src/plugins/python/pythonproject.h | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/python/Python.json.in b/src/plugins/python/Python.json.in index 3e62d146313..98fd52ec8d5 100644 --- a/src/plugins/python/Python.json.in +++ b/src/plugins/python/Python.json.in @@ -30,12 +30,16 @@ \" Python module interface file\", \" \", \" \", - \" \", + \" \", \" \", \" Qt Creator Python project file\", - \" \", \" \", \" \", + \" \", + \" \", + \" Qt Creator Python project file\", + \" \", + \" \", \"\" ] } diff --git a/src/plugins/python/pythonplugin.cpp b/src/plugins/python/pythonplugin.cpp index 4728da37ae5..7eefbc5d4bd 100644 --- a/src/plugins/python/pythonplugin.cpp +++ b/src/plugins/python/pythonplugin.cpp @@ -59,6 +59,7 @@ void PythonPlugin::initialize() d = new PythonPluginPrivate; ProjectManager::registerProjectType(PythonMimeType); + ProjectManager::registerProjectType(PythonMimeTypeLegacy); JsonWizardFactory::registerPageFactory(new PythonWizardPageFactory); } diff --git a/src/plugins/python/pythonproject.h b/src/plugins/python/pythonproject.h index 0217a77b615..676e010a015 100644 --- a/src/plugins/python/pythonproject.h +++ b/src/plugins/python/pythonproject.h @@ -7,7 +7,8 @@ namespace Python::Internal { -const char PythonMimeType[] = "text/x-python-project"; // ### FIXME +const char PythonMimeType[] = "text/x-python-project"; +const char PythonMimeTypeLegacy[] = "text/x-pyqt-project"; const char PythonProjectId[] = "PythonProject"; const char PythonErrorTaskCategory[] = "Task.Category.Python"; From f423db5cb71c7e3442ef31d5eb3ced615b9d1322 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Mar 2023 10:51:57 +0100 Subject: [PATCH 0338/1447] Android: Slim down androiddeployqtstep.h Change-Id: I8a7cf3c33cc1dea6dd79f4c2bf0808f24a3b2369 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/android/androiddeployqtstep.cpp | 89 +++++++++++++++++++-- src/plugins/android/androiddeployqtstep.h | 83 +------------------ 2 files changed, 85 insertions(+), 87 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 5d0ad61c578..1389f0b1007 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -2,10 +2,11 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "androiddeployqtstep.h" + #include "androidavdmanager.h" #include "androidbuildapkstep.h" #include "androidconstants.h" -#include "androiddeployqtstep.h" #include "androiddevice.h" #include "androidmanager.h" #include "androidqtversion.h" @@ -16,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,10 +29,14 @@ #include #include +#include #include #include #include +#include +#include +#include #include #include #include @@ -59,7 +65,78 @@ const QLatin1String InstallFailedVersionDowngrade("INSTALL_FAILED_VERSION_DOWNGR // AndroidDeployQtStep -AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Utils::Id id) +class AndroidDeployQtStep : public BuildStep +{ + Q_OBJECT + + enum DeployErrorCode + { + NoError = 0, + InconsistentCertificates = 0x0001, + UpdateIncompatible = 0x0002, + PermissionModelDowngrade = 0x0004, + VersionDowngrade = 0x0008, + Failure = 0x0010 + }; + +public: + AndroidDeployQtStep(BuildStepList *bc, Id id); + +signals: + void askForUninstall(DeployErrorCode errorCode); + +private: + void runCommand(const CommandLine &command); + + bool init() override; + void doRun() override; + void doCancel() override; + void gatherFilesToPull(); + DeployErrorCode runDeploy(); + void slotAskForUninstall(DeployErrorCode errorCode); + + void runImpl(QPromise &promise); + + QWidget *createConfigWidget() override; + + void processReadyReadStdOutput(DeployErrorCode &errorCode); + void stdOutput(const QString &line); + void processReadyReadStdError(DeployErrorCode &errorCode); + void stdError(const QString &line); + DeployErrorCode parseDeployErrors(const QString &deployOutputLine) const; + + friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &e2) { + e1 = static_cast((int)e1 | (int)e2); + } + + friend DeployErrorCode operator|(const DeployErrorCode &e1, const DeployErrorCode &e2) { + return static_cast((int)e1 | (int)e2); + } + + void reportWarningOrError(const QString &message, Task::TaskType type); + + FilePath m_manifestName; + QString m_serialNumber; + QString m_avdName; + FilePath m_apkPath; + QMap m_filesToPull; + + QStringList m_androidABIs; + BoolAspect *m_uninstallPreviousPackage = nullptr; + bool m_uninstallPreviousPackageRun = false; + bool m_useAndroiddeployqt = false; + bool m_askForUninstall = false; + CommandLine m_androiddeployqtArgs; + FilePath m_adbPath; + FilePath m_command; + FilePath m_workingDirectory; + Environment m_environment; + AndroidDeviceInfo m_deviceInfo; + + FutureSynchronizer m_synchronizer; +}; + +AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id) : BuildStep(parent, id) { setImmutable(true); @@ -209,9 +286,9 @@ bool AndroidDeployQtStep::init() reportWarningOrError(Tr::tr("The deployment step's project node is invalid."), Task::Error); return false; } - m_apkPath = Utils::FilePath::fromString(node->data(Constants::AndroidApk).toString()); + m_apkPath = FilePath::fromString(node->data(Constants::AndroidApk).toString()); if (!m_apkPath.isEmpty()) { - m_manifestName = Utils::FilePath::fromString(node->data(Constants::AndroidManifest).toString()); + m_manifestName = FilePath::fromString(node->data(Constants::AndroidManifest).toString()); m_command = AndroidConfigurations::currentConfig().adbToolPath(); AndroidManager::setManifestPath(target(), m_manifestName); } else { @@ -254,7 +331,7 @@ bool AndroidDeployQtStep::init() m_apkPath = AndroidManager::packagePath(target()); m_workingDirectory = bc ? AndroidManager::buildDirectory(target()): FilePath(); } - m_environment = bc ? bc->environment() : Utils::Environment(); + m_environment = bc ? bc->environment() : Environment(); m_adbPath = AndroidConfigurations::currentConfig().adbToolPath(); @@ -593,3 +670,5 @@ AndroidDeployQtStepFactory::AndroidDeployQtStepFactory() } } // Android::Internal + +#include "androiddeployqtstep.moc" diff --git a/src/plugins/android/androiddeployqtstep.h b/src/plugins/android/androiddeployqtstep.h index b83adea34a8..dda4304b6af 100644 --- a/src/plugins/android/androiddeployqtstep.h +++ b/src/plugins/android/androiddeployqtstep.h @@ -4,16 +4,7 @@ #pragma once -#include "androiddeviceinfo.h" - -#include -#include - -#include -#include -#include - -namespace Utils { class QtcProcess; } +#include namespace Android::Internal { @@ -23,76 +14,4 @@ public: AndroidDeployQtStepFactory(); }; -class AndroidDeployQtStep : public ProjectExplorer::BuildStep -{ - Q_OBJECT - - enum DeployErrorCode - { - NoError = 0, - InconsistentCertificates = 0x0001, - UpdateIncompatible = 0x0002, - PermissionModelDowngrade = 0x0004, - VersionDowngrade = 0x0008, - Failure = 0x0010 - }; - -public: - AndroidDeployQtStep(ProjectExplorer::BuildStepList *bc, Utils::Id id); - -signals: - void askForUninstall(DeployErrorCode errorCode); - -private: - void runCommand(const Utils::CommandLine &command); - - bool init() override; - void doRun() override; - void doCancel() override; - void gatherFilesToPull(); - DeployErrorCode runDeploy(); - void slotAskForUninstall(DeployErrorCode errorCode); - - void runImpl(QPromise &promise); - - QWidget *createConfigWidget() override; - - void processReadyReadStdOutput(DeployErrorCode &errorCode); - void stdOutput(const QString &line); - void processReadyReadStdError(DeployErrorCode &errorCode); - void stdError(const QString &line); - DeployErrorCode parseDeployErrors(const QString &deployOutputLine) const; - - friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &e2) { - e1 = static_cast((int)e1 | (int)e2); - } - - friend DeployErrorCode operator|(const DeployErrorCode &e1, const DeployErrorCode &e2) { - return static_cast((int)e1 | (int)e2); - } - - void reportWarningOrError(const QString &message, ProjectExplorer::Task::TaskType type); - - Utils::FilePath m_manifestName; - QString m_serialNumber; - QString m_avdName; - Utils::FilePath m_apkPath; - QMap m_filesToPull; - - QStringList m_androidABIs; - Utils::BoolAspect *m_uninstallPreviousPackage = nullptr; - bool m_uninstallPreviousPackageRun = false; - bool m_useAndroiddeployqt = false; - bool m_askForUninstall = false; - static const Utils::Id Id; - Utils::CommandLine m_androiddeployqtArgs; - Utils::FilePath m_adbPath; - Utils::FilePath m_command; - Utils::FilePath m_workingDirectory; - Utils::Environment m_environment; - AndroidDeviceInfo m_deviceInfo; - - Utils::FutureSynchronizer m_synchronizer; -}; - } // Android::Internal From eb7ccfd8893607d0b8a46c17ed444233c353bf8e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 22 Mar 2023 10:39:09 +0100 Subject: [PATCH 0339/1447] LanguageClient: add action to open call hierarchy Fixes: QTCREATORBUG-28839 Fixes: QTCREATORBUG-28842 Change-Id: Icb70412282c0c2c36241559d942a58ffddab5664 Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppeditorplugin.cpp | 4 ++ src/plugins/languageclient/callhierarchy.cpp | 47 +++++++++++-------- src/plugins/languageclient/callhierarchy.h | 6 +++ src/plugins/languageclient/client.cpp | 3 ++ .../languageclient/languageclient_global.h | 2 + .../languageclient/languageclientmanager.cpp | 11 +++++ .../languageclient/languageclientmanager.h | 1 + src/plugins/texteditor/texteditor.cpp | 10 ++++ src/plugins/texteditor/texteditor.h | 2 + .../texteditor/texteditoractionhandler.cpp | 5 ++ .../texteditor/texteditoractionhandler.h | 3 +- src/plugins/texteditor/texteditorconstants.h | 1 + 12 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index f1fc63b49ab..2d4cabe726e 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -431,6 +431,10 @@ void CppEditorPlugin::initialize() contextMenu->addAction(cmd, Constants::G_CONTEXT_FIRST); cppToolsMenu->addAction(cmd); + cmd = ActionManager::command(TextEditor::Constants::OPEN_CALL_HIERARCHY); + contextMenu->addAction(cmd, Constants::G_CONTEXT_FIRST); + cppToolsMenu->addAction(cmd); + // Refactoring sub-menu Command *sep = contextMenu->addSeparator(); sep->action()->setObjectName(QLatin1String(Constants::M_REFACTORING_MENU_INSERTION_POINT)); diff --git a/src/plugins/languageclient/callhierarchy.cpp b/src/plugins/languageclient/callhierarchy.cpp index 069e31b163b..5a8cb9e88e3 100644 --- a/src/plugins/languageclient/callhierarchy.cpp +++ b/src/plugins/languageclient/callhierarchy.cpp @@ -23,8 +23,6 @@ using namespace LanguageServerProtocol; namespace LanguageClient { -const char CALL_HIERARCHY_FACTORY_ID[] = "LanguageClient.CallHierarchy"; - namespace { enum Direction { Incoming, Outgoing }; @@ -186,6 +184,9 @@ public: layout()->setSpacing(0); connect(m_view, &NavigationTreeView::activated, this, &CallHierarchy::onItemActivated); + + connect(LanguageClientManager::instance(), &LanguageClientManager::openCallHierarchy, + this, &CallHierarchy::updateHierarchyAtCursorPosition); } void onItemActivated(const QModelIndex &index) @@ -211,26 +212,14 @@ void CallHierarchy::updateHierarchyAtCursorPosition() BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); if (!editor) return; - Client *client = LanguageClientManager::clientForFilePath(editor->document()->filePath()); + + Core::IDocument *document = editor->document(); + + Client *client = LanguageClientManager::clientForFilePath(document->filePath()); if (!client) return; - const QString methodName = PrepareCallHierarchyRequest::methodName; - std::optional registered = client->dynamicCapabilities().isRegistered(methodName); - bool supported = registered.value_or(false); - const Core::IDocument *document = editor->document(); - if (registered) { - if (supported) { - const QJsonValue &options = client->dynamicCapabilities().option(methodName); - const TextDocumentRegistrationOptions docOptions(options); - supported = docOptions.filterApplies(document->filePath(), - Utils::mimeTypeForName(document->mimeType())); - } - } else { - supported = client->capabilities().callHierarchyProvider().has_value(); - } - - if (!supported) + if (!CallHierarchyFactory::supportsCallHierarchy(client, document)) return; TextDocumentPositionParams params; @@ -273,7 +262,25 @@ CallHierarchyFactory::CallHierarchyFactory() { setDisplayName(Tr::tr("Call Hierarchy")); setPriority(650); - setId(CALL_HIERARCHY_FACTORY_ID); + setId(Constants::CALL_HIERARCHY_FACTORY_ID); +} + +bool CallHierarchyFactory::supportsCallHierarchy(Client *client, const Core::IDocument *document) +{ + const QString methodName = PrepareCallHierarchyRequest::methodName; + std::optional registered = client->dynamicCapabilities().isRegistered(methodName); + bool supported = registered.value_or(false); + if (registered) { + if (supported) { + const QJsonValue &options = client->dynamicCapabilities().option(methodName); + const TextDocumentRegistrationOptions docOptions(options); + supported = docOptions.filterApplies(document->filePath(), + Utils::mimeTypeForName(document->mimeType())); + } + } else { + supported = client->capabilities().callHierarchyProvider().has_value(); + } + return supported; } Core::NavigationView CallHierarchyFactory::createWidget() diff --git a/src/plugins/languageclient/callhierarchy.h b/src/plugins/languageclient/callhierarchy.h index f707c4fbcbb..bbc15b09712 100644 --- a/src/plugins/languageclient/callhierarchy.h +++ b/src/plugins/languageclient/callhierarchy.h @@ -5,8 +5,12 @@ #pragma once +namespace Core { class IDocument; } + namespace LanguageClient { +class Client; + class CallHierarchyFactory : public Core::INavigationWidgetFactory { Q_OBJECT @@ -14,6 +18,8 @@ class CallHierarchyFactory : public Core::INavigationWidgetFactory public: CallHierarchyFactory(); + static bool supportsCallHierarchy(Client *client, const Core::IDocument *document); + Core::NavigationView createWidget() override; }; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 461e908bcf9..17248c7ca29 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -3,6 +3,7 @@ #include "client.h" +#include "callhierarchy.h" #include "diagnosticmanager.h" #include "documentsymbolcache.h" #include "languageclientcompletionassist.h" @@ -879,6 +880,8 @@ void Client::activateEditor(Core::IEditor *editor) optionalActions |= TextEditor::TextEditorActionHandler::FindUsage; if (symbolSupport().supportsRename(widget->textDocument())) optionalActions |= TextEditor::TextEditorActionHandler::RenameSymbol; + if (CallHierarchyFactory::supportsCallHierarchy(this, textEditor->document())) + optionalActions |= TextEditor::TextEditorActionHandler::CallHierarchy; widget->setOptionalActions(optionalActions); } } diff --git a/src/plugins/languageclient/languageclient_global.h b/src/plugins/languageclient/languageclient_global.h index 0dca3e6bbfc..d115d10a252 100644 --- a/src/plugins/languageclient/languageclient_global.h +++ b/src/plugins/languageclient/languageclient_global.h @@ -29,5 +29,7 @@ const char LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_N const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID[] = "Workspace Functions and Methods"; const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Functions and Methods in Workspace"); +const char CALL_HIERARCHY_FACTORY_ID[] = "LanguageClient.CallHierarchy"; + } // namespace Constants } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 56ef4a1c3a6..f21a951607d 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -448,6 +449,8 @@ QList LanguageClientManager::reachableClients() void LanguageClientManager::editorOpened(Core::IEditor *editor) { using namespace TextEditor; + using namespace Core; + if (auto *textEditor = qobject_cast(editor)) { if (TextEditorWidget *widget = textEditor->editorWidget()) { connect(widget, &TextEditorWidget::requestLinkAt, this, @@ -466,6 +469,14 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor) if (auto client = clientForDocument(document)) client->symbolSupport().renameSymbol(document, cursor); }); + connect(widget, &TextEditorWidget::requestCallHierarchy, this, + [this, textEditor](const QTextCursor &cursor) { + if (auto client = clientForDocument(textEditor->textDocument())) { + emit openCallHierarchy(); + NavigationWidget::activateSubWidget(Constants::CALL_HIERARCHY_FACTORY_ID, + Side::Left); + } + }); connect(widget, &TextEditorWidget::cursorPositionChanged, this, [widget]() { if (Client *client = clientForDocument(widget->textDocument())) if (client->reachable()) diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index db6357ee9e1..cf90a2f7468 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -83,6 +83,7 @@ signals: void clientInitialized(Client *client); void clientRemoved(Client *client); void shutdownFinished(); + void openCallHierarchy(); private: LanguageClientManager(QObject *parent); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 6d3593aab7b..ccbdb0467d0 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -2348,6 +2348,11 @@ void TextEditorWidget::renameSymbolUnderCursor() emit requestRename(textCursor()); } +void TextEditorWidget::openCallHierarchy() +{ + emit requestCallHierarchy(textCursor()); +} + void TextEditorWidget::abortAssist() { d->m_codeAssistant.destroyContext(); @@ -8225,6 +8230,11 @@ void TextEditorWidget::appendStandardContextMenuActions(QMenu *menu) if (!menu->actions().contains(findUsage)) menu->addAction(findUsage); } + if (optionalActions() & TextEditorActionHandler::CallHierarchy) { + const auto callHierarchy = ActionManager::command(Constants::OPEN_CALL_HIERARCHY)->action(); + if (!menu->actions().contains(callHierarchy)) + menu->addAction(callHierarchy); + } menu->addSeparator(); appendMenuActionsFromContext(menu, Constants::M_STANDARDCONTEXTMENU); diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 31c4c9d6bf4..4234645d50a 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -437,6 +437,7 @@ public: virtual void findUsages(); virtual void renameSymbolUnderCursor(); + virtual void openCallHierarchy(); /// Abort code assistant if it is running. void abortAssist(); @@ -487,6 +488,7 @@ signals: bool resolveTarget, bool inNextSplit); void requestUsages(const QTextCursor &cursor); void requestRename(const QTextCursor &cursor); + void requestCallHierarchy(const QTextCursor &cursor); void optionalActionMaskChanged(); void toolbarOutlineChanged(QWidget *newOutline); diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp index 25116729c99..00ed94a5ee7 100644 --- a/src/plugins/texteditor/texteditoractionhandler.cpp +++ b/src/plugins/texteditor/texteditoractionhandler.cpp @@ -116,6 +116,7 @@ public: QAction *m_followSymbolAction = nullptr; QAction *m_followSymbolInNextSplitAction = nullptr; QAction *m_findUsageAction = nullptr; + QAction *m_openCallHierarchyAction = nullptr; QAction *m_renameSymbolAction = nullptr; QAction *m_jumpToFileAction = nullptr; QAction *m_jumpToFileInNextSplitAction = nullptr; @@ -228,6 +229,8 @@ void TextEditorActionHandlerPrivate::createActions() m_jumpToFileInNextSplitAction = registerAction(JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT, [] (TextEditorWidget *w) { w->openLinkUnderCursorInNextSplit(); }, true, Tr::tr("Jump to File Under Cursor in Next Split"), QKeySequence(Utils::HostOsInfo::isMacHost() ? Tr::tr("Meta+E, F2") : Tr::tr("Ctrl+E, F2")).toString()); + m_openCallHierarchyAction = registerAction(OPEN_CALL_HIERARCHY, + [] (TextEditorWidget *w) { w->openCallHierarchy(); }, true, Tr::tr("Open Call Hierarchy")); registerAction(VIEW_PAGE_UP, [] (TextEditorWidget *w) { w->viewPageUp(); }, true, Tr::tr("Move the View a Page Up and Keep the Cursor Position"), @@ -484,6 +487,8 @@ void TextEditorActionHandlerPrivate::updateOptionalActions() optionalActions & TextEditorActionHandler::UnCollapseAll); m_renameSymbolAction->setEnabled( optionalActions & TextEditorActionHandler::RenameSymbol); + m_openCallHierarchyAction->setEnabled( + optionalActions & TextEditorActionHandler::CallHierarchy); bool formatEnabled = (optionalActions & TextEditorActionHandler::Format) && m_currentEditorWidget && !m_currentEditorWidget->isReadOnly(); diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h index 277c2cf66f4..2bdb8efff3e 100644 --- a/src/plugins/texteditor/texteditoractionhandler.h +++ b/src/plugins/texteditor/texteditoractionhandler.h @@ -36,7 +36,8 @@ public: FollowSymbolUnderCursor = 8, JumpToFileUnderCursor = 16, RenameSymbol = 32, - FindUsage = 64 + FindUsage = 64, + CallHierarchy = 128 }; using TextEditorWidgetResolver = std::function; diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index 0560dae9d82..f422630f0d2 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -208,6 +208,7 @@ const char FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.FollowSymbol const char FIND_USAGES[] = "TextEditor.FindUsages"; // moved from CppEditor to TextEditor avoid breaking the setting by using the old key const char RENAME_SYMBOL[] = "CppEditor.RenameSymbolUnderCursor"; +const char OPEN_CALL_HIERARCHY[] = "TextEditor.OpenCallHierarchy"; const char JUMP_TO_FILE_UNDER_CURSOR[] = "TextEditor.JumpToFileUnderCursor"; const char JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT[] = "TextEditor.JumpToFileUnderCursorInNextSplit"; From f3d620fe7939d7dcdd4f97788283111e983d0ca1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 22 Mar 2023 14:45:09 +0100 Subject: [PATCH 0340/1447] LanguageClient: add tooltip to reload call hierarchy tool button Change-Id: I9811bdf39f39175cd53f201b94aaf3dc3a6fae22 Reviewed-by: Leena Miettinen Reviewed-by: --- src/plugins/languageclient/callhierarchy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/languageclient/callhierarchy.cpp b/src/plugins/languageclient/callhierarchy.cpp index 5a8cb9e88e3..c372705e810 100644 --- a/src/plugins/languageclient/callhierarchy.cpp +++ b/src/plugins/languageclient/callhierarchy.cpp @@ -291,6 +291,7 @@ Core::NavigationView CallHierarchyFactory::createWidget() Icons::RELOAD_TOOLBAR.icon(); auto button = new QToolButton; button->setIcon(Icons::RELOAD_TOOLBAR.icon()); + button->setToolTip(Tr::tr("Reloads the call hierarchy for the symbol under cursor position.")); connect(button, &QToolButton::clicked, [h](){ h->updateHierarchyAtCursorPosition(); }); From 1bdc638e6530b2e003410238ee81cb5bb8f73a23 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 23 Mar 2023 07:08:09 +0100 Subject: [PATCH 0341/1447] LanguageClient: remove unused variables Change-Id: I75281300ae5bc432d4571fd9b423c91d53eda310 Reviewed-by: Christian Stenger --- src/plugins/languageclient/languageclientmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index f21a951607d..2d896f1a2d3 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -470,8 +470,8 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor) client->symbolSupport().renameSymbol(document, cursor); }); connect(widget, &TextEditorWidget::requestCallHierarchy, this, - [this, textEditor](const QTextCursor &cursor) { - if (auto client = clientForDocument(textEditor->textDocument())) { + [this, document = textEditor->textDocument()]() { + if (clientForDocument(document)) { emit openCallHierarchy(); NavigationWidget::activateSubWidget(Constants::CALL_HIERARCHY_FACTORY_ID, Side::Left); From a4ed630c7df684cbe62c93f6f6f82643e9958d93 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 21 Mar 2023 16:07:20 +0100 Subject: [PATCH 0342/1447] RemoteLinux/Boot2Qt: Merge DeployStep and DeployService hierarchies They were 1:1 now. The change here is as small as possible, there are quite a few places to clean up left. Change-Id: I4f78d1de857b93d8372e2592a7723b02fe2fc947 Reviewed-by: Marcus Tillmanns --- src/plugins/boot2qt/qdbmakedefaultappstep.cpp | 42 ++--- .../boot2qt/qdbstopapplicationstep.cpp | 34 ++--- .../abstractremotelinuxdeploystep.cpp | 126 ++++++--------- .../abstractremotelinuxdeploystep.h | 69 +++------ .../remotelinux/customcommanddeploystep.cpp | 51 +++---- .../remotelinux/genericdirectuploadstep.cpp | 144 +++++++----------- .../remotelinux/genericdirectuploadstep.h | 8 +- src/plugins/remotelinux/killappstep.cpp | 38 ++--- src/plugins/remotelinux/rsyncdeploystep.cpp | 97 +++++------- src/plugins/remotelinux/rsyncdeploystep.h | 18 +++ .../remotelinux/tarpackagedeploystep.cpp | 79 +++++----- 11 files changed, 286 insertions(+), 420 deletions(-) diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp index 70c1c40acba..4887183ac18 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp @@ -22,12 +22,22 @@ using namespace Utils::Tasking; namespace Qdb::Internal { -// QdbMakeDefaultAppService - -class QdbMakeDefaultAppService : public RemoteLinux::AbstractRemoteLinuxDeployService +class QdbMakeDefaultAppStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep { public: - void setMakeDefault(bool makeDefault) { m_makeDefault = makeDefault; } + QdbMakeDefaultAppStep(BuildStepList *bsl, Id id) + : AbstractRemoteLinuxDeployStep(bsl, id) + { + auto selection = addAspect(); + selection->setSettingsKey("QdbMakeDefaultDeployStep.MakeDefault"); + selection->addOption(Tr::tr("Set this application to start by default")); + selection->addOption(Tr::tr("Reset default application")); + + setInternalInitializer([this, selection] { + m_makeDefault = selection->value() == 0; + return isDeploymentPossible(); + }); + } private: bool isDeploymentNecessary() const final { return true; } @@ -66,30 +76,6 @@ private: bool m_makeDefault = true; }; -// QdbMakeDefaultAppStep - -class QdbMakeDefaultAppStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep -{ -public: - QdbMakeDefaultAppStep(BuildStepList *bsl, Id id) - : AbstractRemoteLinuxDeployStep(bsl, id) - { - auto service = new QdbMakeDefaultAppService; - setDeployService(service); - - auto selection = addAspect(); - selection->setSettingsKey("QdbMakeDefaultDeployStep.MakeDefault"); - selection->addOption(Tr::tr("Set this application to start by default")); - selection->addOption(Tr::tr("Reset default application")); - - setInternalInitializer([service, selection] { - service->setMakeDefault(selection->value() == 0); - return service->isDeploymentPossible(); - }); - } -}; - - // QdbMakeDefaultAppStepFactory QdbMakeDefaultAppStepFactory::QdbMakeDefaultAppStepFactory() diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index 60d891beafb..688ab745142 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -21,16 +21,24 @@ using namespace Utils::Tasking; namespace Qdb::Internal { -// QdbStopApplicationService +// QdbStopApplicationStep -class QdbStopApplicationService : public RemoteLinux::AbstractRemoteLinuxDeployService +class QdbStopApplicationStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep { -private: +public: + QdbStopApplicationStep(BuildStepList *bsl, Id id) + : AbstractRemoteLinuxDeployStep(bsl, id) + { + setWidgetExpandedByDefault(false); + + setInternalInitializer([this] { return isDeploymentPossible(); }); + } + bool isDeploymentNecessary() const final { return true; } Group deployRecipe() final; }; -Group QdbStopApplicationService::deployRecipe() +Group QdbStopApplicationStep::deployRecipe() { const auto setupHandler = [this](QtcProcess &process) { const auto device = DeviceKitAspect::device(target()->kit()); @@ -67,24 +75,6 @@ Group QdbStopApplicationService::deployRecipe() return Group { Process(setupHandler, doneHandler, errorHandler) }; } -// QdbStopApplicationStep - -class QdbStopApplicationStep final : public RemoteLinux::AbstractRemoteLinuxDeployStep -{ -public: - QdbStopApplicationStep(BuildStepList *bsl, Id id) - : AbstractRemoteLinuxDeployStep(bsl, id) - { - auto service = new QdbStopApplicationService; - setDeployService(service); - - setWidgetExpandedByDefault(false); - - setInternalInitializer([service] { return service->isDeploymentPossible(); }); - } -}; - - // QdbStopApplicationStepFactory QdbStopApplicationStepFactory::QdbStopApplicationStepFactory() diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp index 7e7e3d9a19a..84e4b53cee8 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp @@ -24,137 +24,116 @@ using namespace Utils; namespace RemoteLinux { namespace Internal { -class AbstractRemoteLinuxDeployServicePrivate -{ -public: - IDevice::ConstPtr deviceConfiguration; - QPointer target; - - DeploymentTimeInfo deployTimes; - std::unique_ptr m_taskTree; -}; - class AbstractRemoteLinuxDeployStepPrivate { public: bool hasError; std::function internalInit; std::function runPreparer; - AbstractRemoteLinuxDeployService *deployService = nullptr; + + DeploymentTimeInfo deployTimes; + std::unique_ptr m_taskTree; }; } // Internal using namespace Internal; -AbstractRemoteLinuxDeployService::AbstractRemoteLinuxDeployService(QObject *parent) - : QObject(parent), d(new AbstractRemoteLinuxDeployServicePrivate) +AbstractRemoteLinuxDeployStep::AbstractRemoteLinuxDeployStep(BuildStepList *bsl, Id id) + : BuildStep(bsl, id), d(new Internal::AbstractRemoteLinuxDeployStepPrivate) { + connect(this, &AbstractRemoteLinuxDeployStep::errorMessage, + this, &AbstractRemoteLinuxDeployStep::handleErrorMessage); + connect(this, &AbstractRemoteLinuxDeployStep::progressMessage, + this, &AbstractRemoteLinuxDeployStep::handleProgressMessage); + connect(this, &AbstractRemoteLinuxDeployStep::warningMessage, + this, &AbstractRemoteLinuxDeployStep::handleWarningMessage); + connect(this, &AbstractRemoteLinuxDeployStep::stdOutData, + this, &AbstractRemoteLinuxDeployStep::handleStdOutData); + connect(this, &AbstractRemoteLinuxDeployStep::stdErrData, + this, &AbstractRemoteLinuxDeployStep::handleStdErrData); } -AbstractRemoteLinuxDeployService::~AbstractRemoteLinuxDeployService() +AbstractRemoteLinuxDeployStep::~AbstractRemoteLinuxDeployStep() { delete d; } -const Target *AbstractRemoteLinuxDeployService::target() const +IDevice::ConstPtr AbstractRemoteLinuxDeployStep::deviceConfiguration() const { - return d->target; + return DeviceKitAspect::device(kit()); } -const Kit *AbstractRemoteLinuxDeployService::kit() const -{ - return d->target ? d->target->kit() : nullptr; -} - -IDevice::ConstPtr AbstractRemoteLinuxDeployService::deviceConfiguration() const -{ - return d->deviceConfiguration; -} - -void AbstractRemoteLinuxDeployService::saveDeploymentTimeStamp(const DeployableFile &deployableFile, +void AbstractRemoteLinuxDeployStep::saveDeploymentTimeStamp(const DeployableFile &deployableFile, const QDateTime &remoteTimestamp) { d->deployTimes.saveDeploymentTimeStamp(deployableFile, kit(), remoteTimestamp); } -bool AbstractRemoteLinuxDeployService::hasLocalFileChanged( +bool AbstractRemoteLinuxDeployStep::hasLocalFileChanged( const DeployableFile &deployableFile) const { return d->deployTimes.hasLocalFileChanged(deployableFile, kit()); } -bool AbstractRemoteLinuxDeployService::hasRemoteFileChanged( +bool AbstractRemoteLinuxDeployStep::hasRemoteFileChanged( const DeployableFile &deployableFile, const QDateTime &remoteTimestamp) const { return d->deployTimes.hasRemoteFileChanged(deployableFile, kit(), remoteTimestamp); } -void AbstractRemoteLinuxDeployService::setTarget(Target *target) -{ - d->target = target; - d->deviceConfiguration = DeviceKitAspect::device(kit()); -} - -void AbstractRemoteLinuxDeployService::start() +void AbstractRemoteLinuxDeployStep::start() { QTC_ASSERT(!d->m_taskTree, return); const CheckResult check = isDeploymentPossible(); if (!check) { emit errorMessage(check.errorMessage()); - emit finished(); + handleFinished(); return; } if (!isDeploymentNecessary()) { emit progressMessage(Tr::tr("No deployment action necessary. Skipping.")); - emit finished(); + handleFinished(); return; } d->m_taskTree.reset(new TaskTree(deployRecipe())); const auto endHandler = [this] { d->m_taskTree.release()->deleteLater(); - emit finished(); + handleFinished(); }; connect(d->m_taskTree.get(), &TaskTree::done, this, endHandler); connect(d->m_taskTree.get(), &TaskTree::errorOccurred, this, endHandler); d->m_taskTree->start(); } -void AbstractRemoteLinuxDeployService::stop() +void AbstractRemoteLinuxDeployStep::stop() { if (!d->m_taskTree) return; d->m_taskTree.reset(); - emit finished(); + handleFinished(); } -CheckResult AbstractRemoteLinuxDeployService::isDeploymentPossible() const +CheckResult AbstractRemoteLinuxDeployStep::isDeploymentPossible() const { if (!deviceConfiguration()) return CheckResult::failure(Tr::tr("No device configuration set.")); return CheckResult::success(); } -QVariantMap AbstractRemoteLinuxDeployService::exportDeployTimes() const +QVariantMap AbstractRemoteLinuxDeployStep::exportDeployTimes() const { return d->deployTimes.exportDeployTimes(); } -void AbstractRemoteLinuxDeployService::importDeployTimes(const QVariantMap &map) +void AbstractRemoteLinuxDeployStep::importDeployTimes(const QVariantMap &map) { d->deployTimes.importDeployTimes(map); } - - -AbstractRemoteLinuxDeployStep::AbstractRemoteLinuxDeployStep(BuildStepList *bsl, Utils::Id id) - : BuildStep(bsl, id), d(new Internal::AbstractRemoteLinuxDeployStepPrivate) -{ -} - void AbstractRemoteLinuxDeployStep::setInternalInitializer(const std::function &init) { d->internalInit = init; @@ -165,36 +144,23 @@ void AbstractRemoteLinuxDeployStep::setRunPreparer(const std::function d->runPreparer = prep; } -void AbstractRemoteLinuxDeployStep::setDeployService(AbstractRemoteLinuxDeployService *service) -{ - d->deployService = service; -} - -AbstractRemoteLinuxDeployStep::~AbstractRemoteLinuxDeployStep() -{ - delete d->deployService; - delete d; -} - bool AbstractRemoteLinuxDeployStep::fromMap(const QVariantMap &map) { if (!BuildStep::fromMap(map)) return false; - d->deployService->importDeployTimes(map); + importDeployTimes(map); return true; } QVariantMap AbstractRemoteLinuxDeployStep::toMap() const { QVariantMap map = BuildStep::toMap(); - map.insert(d->deployService->exportDeployTimes()); + map.insert(exportDeployTimes()); return map; } bool AbstractRemoteLinuxDeployStep::init() { - d->deployService->setTarget(target()); - QTC_ASSERT(d->internalInit, return false); const CheckResult canDeploy = d->internalInit(); if (!canDeploy) { @@ -209,21 +175,8 @@ void AbstractRemoteLinuxDeployStep::doRun() if (d->runPreparer) d->runPreparer(); - connect(d->deployService, &AbstractRemoteLinuxDeployService::errorMessage, - this, &AbstractRemoteLinuxDeployStep::handleErrorMessage); - connect(d->deployService, &AbstractRemoteLinuxDeployService::progressMessage, - this, &AbstractRemoteLinuxDeployStep::handleProgressMessage); - connect(d->deployService, &AbstractRemoteLinuxDeployService::warningMessage, - this, &AbstractRemoteLinuxDeployStep::handleWarningMessage); - connect(d->deployService, &AbstractRemoteLinuxDeployService::stdOutData, - this, &AbstractRemoteLinuxDeployStep::handleStdOutData); - connect(d->deployService, &AbstractRemoteLinuxDeployService::stdErrData, - this, &AbstractRemoteLinuxDeployStep::handleStdErrData); - connect(d->deployService, &AbstractRemoteLinuxDeployService::finished, - this, &AbstractRemoteLinuxDeployStep::handleFinished); - d->hasError = false; - d->deployService->start(); + start(); } void AbstractRemoteLinuxDeployStep::doCancel() @@ -234,7 +187,7 @@ void AbstractRemoteLinuxDeployStep::doCancel() emit addOutput(Tr::tr("User requests deployment to stop; cleaning up."), OutputFormat::NormalMessage); d->hasError = true; - d->deployService->stop(); + stop(); } void AbstractRemoteLinuxDeployStep::handleProgressMessage(const QString &message) @@ -261,7 +214,6 @@ void AbstractRemoteLinuxDeployStep::handleFinished() emit addOutput(Tr::tr("Deploy step failed."), OutputFormat::ErrorMessage); else emit addOutput(Tr::tr("Deploy step finished."), OutputFormat::NormalMessage); - disconnect(d->deployService, nullptr, this, nullptr); emit finished(!d->hasError); } @@ -275,4 +227,14 @@ void AbstractRemoteLinuxDeployStep::handleStdErrData(const QString &data) emit addOutput(data, OutputFormat::Stderr, DontAppendNewline); } +bool AbstractRemoteLinuxDeployStep::isDeploymentNecessary() const +{ + return true; +} + +Tasking::Group AbstractRemoteLinuxDeployStep::deployRecipe() +{ + return {}; +} + } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h index 67855064bb0..72af36e49b3 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h @@ -21,42 +21,9 @@ namespace Utils::Tasking { class Group; } namespace RemoteLinux { -class AbstractRemoteLinuxDeployService; class CheckResult; namespace Internal { class AbstractRemoteLinuxDeployStepPrivate; } -namespace Internal { class AbstractRemoteLinuxDeployServicePrivate; } - -class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployStep : public ProjectExplorer::BuildStep -{ - Q_OBJECT - -public: - ~AbstractRemoteLinuxDeployStep() override; - -protected: - bool fromMap(const QVariantMap &map) override; - QVariantMap toMap() const override; - bool init() override; - void doRun() final; - void doCancel() override; - - explicit AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); - - void setInternalInitializer(const std::function &init); - void setRunPreparer(const std::function &prep); - void setDeployService(AbstractRemoteLinuxDeployService *service); - -private: - void handleProgressMessage(const QString &message); - void handleErrorMessage(const QString &message); - void handleWarningMessage(const QString &message); - void handleFinished(); - void handleStdOutData(const QString &data); - void handleStdErrData(const QString &data); - - Internal::AbstractRemoteLinuxDeployStepPrivate *d; -}; class REMOTELINUX_EXPORT CheckResult { @@ -74,21 +41,20 @@ private: QString m_error; }; -class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployService : public QObject +class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployStep : public ProjectExplorer::BuildStep { Q_OBJECT - Q_DISABLE_COPY(AbstractRemoteLinuxDeployService) -public: - explicit AbstractRemoteLinuxDeployService(QObject *parent = nullptr); - ~AbstractRemoteLinuxDeployService() override; - void setTarget(ProjectExplorer::Target *bc); +public: + explicit AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); + ~AbstractRemoteLinuxDeployStep() override; void start(); void stop(); QVariantMap exportDeployTimes() const; void importDeployTimes(const QVariantMap &map); + ProjectExplorer::IDeviceConstPtr deviceConfiguration() const; virtual CheckResult isDeploymentPossible() const; @@ -98,12 +64,16 @@ signals: void warningMessage(const QString &message); void stdOutData(const QString &data); void stdErrData(const QString &data); - void finished(); // Used by Qnx. protected: - const ProjectExplorer::Target *target() const; - const ProjectExplorer::Kit *kit() const; - ProjectExplorer::IDeviceConstPtr deviceConfiguration() const; + bool fromMap(const QVariantMap &map) override; + QVariantMap toMap() const override; + bool init() override; + void doRun() final; + void doCancel() override; + + void setInternalInitializer(const std::function &init); + void setRunPreparer(const std::function &prep); void saveDeploymentTimeStamp(const ProjectExplorer::DeployableFile &deployableFile, const QDateTime &remoteTimestamp); @@ -112,10 +82,17 @@ protected: const QDateTime &remoteTimestamp) const; private: - virtual bool isDeploymentNecessary() const = 0; - virtual Utils::Tasking::Group deployRecipe() = 0; + void handleProgressMessage(const QString &message); + void handleErrorMessage(const QString &message); + void handleWarningMessage(const QString &message); + void handleFinished(); + void handleStdOutData(const QString &data); + void handleStdErrData(const QString &data); - Internal::AbstractRemoteLinuxDeployServicePrivate * const d; + virtual bool isDeploymentNecessary() const; + virtual Utils::Tasking::Group deployRecipe(); + + Internal::AbstractRemoteLinuxDeployStepPrivate *d; }; } // RemoteLinux diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index b7abdd83044..e0efa25f002 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -19,9 +19,26 @@ using namespace Utils::Tasking; namespace RemoteLinux::Internal { -class CustomCommandDeployService : public AbstractRemoteLinuxDeployService +class CustomCommandDeployStep : public AbstractRemoteLinuxDeployStep { public: + CustomCommandDeployStep(BuildStepList *bsl, Id id) + : AbstractRemoteLinuxDeployStep(bsl, id) + { + auto commandLine = addAspect(); + commandLine->setSettingsKey("RemoteLinuxCustomCommandDeploymentStep.CommandLine"); + commandLine->setLabelText(Tr::tr("Command line:")); + commandLine->setDisplayStyle(StringAspect::LineEditDisplay); + commandLine->setHistoryCompleter("RemoteLinuxCustomCommandDeploymentStep.History"); + + setInternalInitializer([this, commandLine] { + setCommandLine(commandLine->value().trimmed()); + return isDeploymentPossible(); + }); + + addMacroExpander(); + } + void setCommandLine(const QString &commandLine); CheckResult isDeploymentPossible() const final; @@ -34,20 +51,20 @@ private: QString m_commandLine; }; -void CustomCommandDeployService::setCommandLine(const QString &commandLine) +void CustomCommandDeployStep::setCommandLine(const QString &commandLine) { m_commandLine = commandLine; } -CheckResult CustomCommandDeployService::isDeploymentPossible() const +CheckResult CustomCommandDeployStep::isDeploymentPossible() const { if (m_commandLine.isEmpty()) return CheckResult::failure(Tr::tr("No command line given.")); - return AbstractRemoteLinuxDeployService::isDeploymentPossible(); + return AbstractRemoteLinuxDeployStep::isDeploymentPossible(); } -Group CustomCommandDeployService::deployRecipe() +Group CustomCommandDeployStep::deployRecipe() { const auto setupHandler = [this](QtcProcess &process) { emit progressMessage(Tr::tr("Starting remote command \"%1\"...").arg(m_commandLine)); @@ -76,30 +93,6 @@ Group CustomCommandDeployService::deployRecipe() return Group { Process(setupHandler, doneHandler, errorHandler) }; } -class CustomCommandDeployStep : public AbstractRemoteLinuxDeployStep -{ -public: - CustomCommandDeployStep(BuildStepList *bsl, Id id) - : AbstractRemoteLinuxDeployStep(bsl, id) - { - auto service = new CustomCommandDeployService; - setDeployService(service); - - auto commandLine = addAspect(); - commandLine->setSettingsKey("RemoteLinuxCustomCommandDeploymentStep.CommandLine"); - commandLine->setLabelText(Tr::tr("Command line:")); - commandLine->setDisplayStyle(StringAspect::LineEditDisplay); - commandLine->setHistoryCompleter("RemoteLinuxCustomCommandDeploymentStep.History"); - - setInternalInitializer([service, commandLine] { - service->setCommandLine(commandLine->value().trimmed()); - return service->isDeploymentPossible(); - }); - - addMacroExpander(); - } -}; - // CustomCommandDeployStepFactory diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 46a431861d1..8b20effca69 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -25,7 +25,6 @@ using namespace Utils; using namespace Utils::Tasking; namespace RemoteLinux { -namespace Internal { const int MaxConcurrentStatCalls = 10; @@ -36,21 +35,13 @@ struct UploadStorage enum class IncrementalDeployment { Enabled, Disabled, NotSupported }; -class GenericDirectUploadService : public AbstractRemoteLinuxDeployService +class GenericDirectUploadStepPrivate { public: - GenericDirectUploadService(QObject *parent = nullptr) - : AbstractRemoteLinuxDeployService(parent) + GenericDirectUploadStepPrivate(GenericDirectUploadStep *parent) + : q(parent) {} - void setDeployableFiles(const QList &deployableFiles); - void setIncrementalDeployment(IncrementalDeployment incremental); - void setIgnoreMissingFiles(bool ignoreMissingFiles); - -private: - bool isDeploymentNecessary() const final; - Utils::Tasking::Group deployRecipe() final; - QDateTime timestampFromStat(const DeployableFile &file, QtcProcess *statProc); using FilesToStat = std::function(UploadStorage *)>; @@ -64,6 +55,7 @@ private: TaskItem chmodTask(const DeployableFile &file); TaskItem chmodTree(const TreeStorage &storage); + GenericDirectUploadStep *q; IncrementalDeployment m_incremental = IncrementalDeployment::NotSupported; bool m_ignoreMissingFiles = false; mutable QList m_deployableFiles; @@ -84,38 +76,19 @@ QList collectFilesToUpload(const DeployableFile &deployable) return collected; } -} // namespace Internal - -using namespace Internal; - -void GenericDirectUploadService::setDeployableFiles(const QList &deployableFiles) -{ - m_deployableFiles = deployableFiles; -} - -void GenericDirectUploadService::setIncrementalDeployment(IncrementalDeployment incremental) -{ - m_incremental = incremental; -} - -void GenericDirectUploadService::setIgnoreMissingFiles(bool ignoreMissingFiles) -{ - m_ignoreMissingFiles = ignoreMissingFiles; -} - -bool GenericDirectUploadService::isDeploymentNecessary() const +bool GenericDirectUploadStep::isDeploymentNecessary() const { QList collected; - for (int i = 0; i < m_deployableFiles.count(); ++i) - collected.append(collectFilesToUpload(m_deployableFiles.at(i))); + for (int i = 0; i < d->m_deployableFiles.count(); ++i) + collected.append(collectFilesToUpload(d->m_deployableFiles.at(i))); - QTC_CHECK(collected.size() >= m_deployableFiles.size()); - m_deployableFiles = collected; - return !m_deployableFiles.isEmpty(); + QTC_CHECK(collected.size() >= d->m_deployableFiles.size()); + d->m_deployableFiles = collected; + return !d->m_deployableFiles.isEmpty(); } -QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &file, - QtcProcess *statProc) +QDateTime GenericDirectUploadStepPrivate::timestampFromStat(const DeployableFile &file, + QtcProcess *statProc) { bool succeeded = false; QString error; @@ -130,7 +103,7 @@ QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &fi succeeded = true; } if (!succeeded) { - emit warningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " + emit q->warningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " "Incremental deployment will not work. Error message was: %2") .arg(file.remoteFilePath(), error)); return {}; @@ -139,30 +112,30 @@ QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &fi const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2") .arg(file.remoteFilePath()).arg(QString::fromUtf8(output))); if (!output.startsWith(file.remoteFilePath().toUtf8())) { - emit warningMessage(warningString); + emit q->warningMessage(warningString); return {}; } const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' '); if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns - emit warningMessage(warningString); + emit q->warningMessage(warningString); return {}; } bool isNumber; const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber); if (!isNumber) { - emit warningMessage(warningString); + emit q->warningMessage(warningString); return {}; } return QDateTime::fromSecsSinceEpoch(secsSinceEpoch); } -TaskItem GenericDirectUploadService::statTask(UploadStorage *storage, - const DeployableFile &file, - StatEndHandler statEndHandler) +TaskItem GenericDirectUploadStepPrivate::statTask(UploadStorage *storage, + const DeployableFile &file, + StatEndHandler statEndHandler) { const auto setupHandler = [=](QtcProcess &process) { // We'd like to use --format=%Y, but it's not supported by busybox. - process.setCommand({deviceConfiguration()->filePath("stat"), + process.setCommand({q->deviceConfiguration()->filePath("stat"), {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); }; const auto endHandler = [=](const QtcProcess &process) { @@ -173,8 +146,8 @@ TaskItem GenericDirectUploadService::statTask(UploadStorage *storage, return Process(setupHandler, endHandler, endHandler); } -TaskItem GenericDirectUploadService::statTree(const TreeStorage &storage, - FilesToStat filesToStat, StatEndHandler statEndHandler) +TaskItem GenericDirectUploadStepPrivate::statTree(const TreeStorage &storage, + FilesToStat filesToStat, StatEndHandler statEndHandler) { const auto setupHandler = [=](TaskTree &tree) { UploadStorage *storagePtr = storage.activeStorage(); @@ -189,14 +162,14 @@ TaskItem GenericDirectUploadService::statTree(const TreeStorage & return Tree(setupHandler); } -TaskItem GenericDirectUploadService::uploadTask(const TreeStorage &storage) +TaskItem GenericDirectUploadStepPrivate::uploadTask(const TreeStorage &storage) { const auto setupHandler = [this, storage](FileTransfer &transfer) { if (storage->filesToUpload.isEmpty()) { - emit progressMessage(Tr::tr("No files need to be uploaded.")); + emit q->progressMessage(Tr::tr("No files need to be uploaded.")); return TaskAction::StopWithDone; } - emit progressMessage(Tr::tr("%n file(s) need to be uploaded.", "", + emit q->progressMessage(Tr::tr("%n file(s) need to be uploaded.", "", storage->filesToUpload.size())); FilesToTransfer files; for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { @@ -204,51 +177,51 @@ TaskItem GenericDirectUploadService::uploadTask(const TreeStorage const QString message = Tr::tr("Local file \"%1\" does not exist.") .arg(file.localFilePath().toUserOutput()); if (m_ignoreMissingFiles) { - emit warningMessage(message); + emit q->warningMessage(message); continue; } - emit errorMessage(message); + emit q->errorMessage(message); return TaskAction::StopWithError; } files.append({file.localFilePath(), - deviceConfiguration()->filePath(file.remoteFilePath())}); + q->deviceConfiguration()->filePath(file.remoteFilePath())}); } if (files.isEmpty()) { - emit progressMessage(Tr::tr("No files need to be uploaded.")); + emit q->progressMessage(Tr::tr("No files need to be uploaded.")); return TaskAction::StopWithDone; } transfer.setFilesToTransfer(files); QObject::connect(&transfer, &FileTransfer::progress, - this, &GenericDirectUploadService::progressMessage); + q, &GenericDirectUploadStep::progressMessage); return TaskAction::Continue; }; const auto errorHandler = [this](const FileTransfer &transfer) { - emit errorMessage(transfer.resultData().m_errorString); + emit q->errorMessage(transfer.resultData().m_errorString); }; return Transfer(setupHandler, {}, errorHandler); } -TaskItem GenericDirectUploadService::chmodTask(const DeployableFile &file) +TaskItem GenericDirectUploadStepPrivate::chmodTask(const DeployableFile &file) { const auto setupHandler = [=](QtcProcess &process) { - process.setCommand({deviceConfiguration()->filePath("chmod"), + process.setCommand({q->deviceConfiguration()->filePath("chmod"), {"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); }; const auto errorHandler = [=](const QtcProcess &process) { const QString error = process.errorString(); if (!error.isEmpty()) { - emit warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") .arg(file.remoteFilePath(), error)); } else if (process.exitCode() != 0) { - emit warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") .arg(file.remoteFilePath(), process.cleanedStdErr())); } }; return Process(setupHandler, {}, errorHandler); } -TaskItem GenericDirectUploadService::chmodTree(const TreeStorage &storage) +TaskItem GenericDirectUploadStepPrivate::chmodTree(const TreeStorage &storage) { const auto setupChmodHandler = [=](TaskTree &tree) { QList filesToChmod; @@ -266,16 +239,16 @@ TaskItem GenericDirectUploadService::chmodTree(const TreeStorage return Tree(setupChmodHandler); } -Group GenericDirectUploadService::deployRecipe() +Group GenericDirectUploadStep::deployRecipe() { const auto preFilesToStat = [this](UploadStorage *storage) { QList filesToStat; - for (const DeployableFile &file : std::as_const(m_deployableFiles)) { - if (m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) { + for (const DeployableFile &file : std::as_const(d->m_deployableFiles)) { + if (d->m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) { storage->filesToUpload.append(file); continue; } - if (m_incremental == IncrementalDeployment::NotSupported) + if (d->m_incremental == IncrementalDeployment::NotSupported) continue; filesToStat << file; } @@ -288,7 +261,7 @@ Group GenericDirectUploadService::deployRecipe() }; const auto postFilesToStat = [this](UploadStorage *storage) { - return m_incremental == IncrementalDeployment::NotSupported + return d->m_incremental == IncrementalDeployment::NotSupported ? QList() : storage->filesToUpload; }; const auto postStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file, @@ -304,11 +277,11 @@ Group GenericDirectUploadService::deployRecipe() const TreeStorage storage; const Group root { Storage(storage), - statTree(storage, preFilesToStat, preStatEndHandler), - uploadTask(storage), + d->statTree(storage, preFilesToStat, preStatEndHandler), + d->uploadTask(storage), Group { - chmodTree(storage), - statTree(storage, postFilesToStat, postStatEndHandler) + d->chmodTree(storage), + d->statTree(storage, postFilesToStat, postStatEndHandler) }, OnGroupDone(doneHandler) }; @@ -317,11 +290,9 @@ Group GenericDirectUploadService::deployRecipe() GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id, bool offerIncrementalDeployment) - : AbstractRemoteLinuxDeployStep(bsl, id) + : AbstractRemoteLinuxDeployStep(bsl, id), + d(new GenericDirectUploadStepPrivate(this)) { - auto service = new GenericDirectUploadService; - setDeployService(service); - BoolAspect *incremental = nullptr; if (offerIncrementalDeployment) { incremental = addAspect(); @@ -338,23 +309,26 @@ GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id i BoolAspect::LabelPlacement::AtCheckBox); ignoreMissingFiles->setValue(false); - setInternalInitializer([incremental, ignoreMissingFiles, service] { + setInternalInitializer([this, incremental, ignoreMissingFiles] { if (incremental) { - service->setIncrementalDeployment(incremental->value() - ? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled); + d->m_incremental = incremental->value() + ? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled; } else { - service->setIncrementalDeployment(IncrementalDeployment::NotSupported); + d->m_incremental = IncrementalDeployment::NotSupported; } - service->setIgnoreMissingFiles(ignoreMissingFiles->value()); - return service->isDeploymentPossible(); + d->m_ignoreMissingFiles = ignoreMissingFiles->value(); + return isDeploymentPossible(); }); - setRunPreparer([this, service] { - service->setDeployableFiles(target()->deploymentData().allFiles()); + setRunPreparer([this] { + d->m_deployableFiles = target()->deploymentData().allFiles(); }); } -GenericDirectUploadStep::~GenericDirectUploadStep() = default; +GenericDirectUploadStep::~GenericDirectUploadStep() +{ + delete d; +} Utils::Id GenericDirectUploadStep::stepId() { diff --git a/src/plugins/remotelinux/genericdirectuploadstep.h b/src/plugins/remotelinux/genericdirectuploadstep.h index 0c2fb1b67d8..e04426136cf 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.h +++ b/src/plugins/remotelinux/genericdirectuploadstep.h @@ -18,8 +18,14 @@ public: bool offerIncrementalDeployment = true); ~GenericDirectUploadStep() override; + bool isDeploymentNecessary() const final; + Utils::Tasking::Group deployRecipe() final; + static Utils::Id stepId(); static QString displayName(); + +private: + class GenericDirectUploadStepPrivate *d; }; -} //namespace RemoteLinux +} // RemoteLinux diff --git a/src/plugins/remotelinux/killappstep.cpp b/src/plugins/remotelinux/killappstep.cpp index 03473d95a23..57adfefd9b1 100644 --- a/src/plugins/remotelinux/killappstep.cpp +++ b/src/plugins/remotelinux/killappstep.cpp @@ -20,10 +20,21 @@ using namespace Utils::Tasking; namespace RemoteLinux::Internal { -class KillAppService : public AbstractRemoteLinuxDeployService +class KillAppStep : public AbstractRemoteLinuxDeployStep { public: - void setRemoteExecutable(const FilePath &filePath) { m_remoteExecutable = filePath; } + KillAppStep(BuildStepList *bsl, Id id) : AbstractRemoteLinuxDeployStep(bsl, id) + { + setWidgetExpandedByDefault(false); + + setInternalInitializer([this] { + Target * const theTarget = target(); + QTC_ASSERT(theTarget, return CheckResult::failure()); + RunConfiguration * const rc = theTarget->activeRunConfiguration(); + m_remoteExecutable = rc ? rc->runnable().command.executable() : FilePath(); + return CheckResult::success(); + }); + } private: bool isDeploymentNecessary() const final { return !m_remoteExecutable.isEmpty(); } @@ -32,7 +43,7 @@ private: FilePath m_remoteExecutable; }; -Group KillAppService::deployRecipe() +Group KillAppStep::deployRecipe() { const auto setupHandler = [this](DeviceProcessKiller &killer) { killer.setProcessPath(m_remoteExecutable); @@ -49,27 +60,6 @@ Group KillAppService::deployRecipe() return Group { Killer(setupHandler, doneHandler, errorHandler) }; } -class KillAppStep : public AbstractRemoteLinuxDeployStep -{ -public: - KillAppStep(BuildStepList *bsl, Id id) : AbstractRemoteLinuxDeployStep(bsl, id) - { - auto service = new Internal::KillAppService; - setDeployService(service); - - setWidgetExpandedByDefault(false); - - setInternalInitializer([this, service] { - Target * const theTarget = target(); - QTC_ASSERT(theTarget, return CheckResult::failure()); - RunConfiguration * const rc = theTarget->activeRunConfiguration(); - const FilePath remoteExe = rc ? rc->runnable().command.executable() : FilePath(); - service->setRemoteExecutable(remoteExe); - return CheckResult::success(); - }); - } -}; - KillAppStepFactory::KillAppStepFactory() { registerStep(Constants::KillAppStepId); diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index b20eaf90499..e5a012ff88c 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -25,39 +25,57 @@ using namespace Utils::Tasking; namespace RemoteLinux { -class RsyncDeployService : public AbstractRemoteLinuxDeployService +// RsyncDeployStep + +RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id) + : AbstractRemoteLinuxDeployStep(bsl, id) { -public: - void setDeployableFiles(const QList &files); - void setIgnoreMissingFiles(bool ignore) { m_ignoreMissingFiles = ignore; } - void setFlags(const QString &flags) { m_flags = flags; } + auto flags = addAspect(); + flags->setDisplayStyle(StringAspect::LineEditDisplay); + flags->setSettingsKey("RemoteLinux.RsyncDeployStep.Flags"); + flags->setLabelText(Tr::tr("Flags:")); + flags->setValue(FileTransferSetupData::defaultRsyncFlags()); -private: - bool isDeploymentNecessary() const final; - Group deployRecipe() final; - TaskItem mkdirTask(); - TaskItem transferTask(); + auto ignoreMissingFiles = addAspect(); + ignoreMissingFiles->setSettingsKey("RemoteLinux.RsyncDeployStep.IgnoreMissingFiles"); + ignoreMissingFiles->setLabel(Tr::tr("Ignore missing files:"), + BoolAspect::LabelPlacement::InExtraLabel); + ignoreMissingFiles->setValue(false); - mutable FilesToTransfer m_files; - bool m_ignoreMissingFiles = false; - QString m_flags; -}; + setInternalInitializer([this, ignoreMissingFiles, flags] { + if (BuildDeviceKitAspect::device(kit()) == DeviceKitAspect::device(kit())) { + // rsync transfer on the same device currently not implemented + // and typically not wanted. + return CheckResult::failure( + Tr::tr("rsync is only supported for transfers between different devices.")); + } + setIgnoreMissingFiles(ignoreMissingFiles->value()); + setFlags(flags->value()); + return isDeploymentPossible(); + }); -void RsyncDeployService::setDeployableFiles(const QList &files) + setRunPreparer([this] { + setDeployableFiles(target()->deploymentData().allFiles()); + }); +} + +RsyncDeployStep::~RsyncDeployStep() = default; + +void RsyncDeployStep::setDeployableFiles(const QList &files) { m_files.clear(); for (const DeployableFile &f : files) m_files.append({f.localFilePath(), deviceConfiguration()->filePath(f.remoteFilePath())}); } -bool RsyncDeployService::isDeploymentNecessary() const +bool RsyncDeployStep::isDeploymentNecessary() const { if (m_ignoreMissingFiles) Utils::erase(m_files, [](const FileToTransfer &file) { return !file.m_source.exists(); }); return !m_files.empty(); } -TaskItem RsyncDeployService::mkdirTask() +TaskItem RsyncDeployStep::mkdirTask() { const auto setupHandler = [this](QtcProcess &process) { QStringList remoteDirs; @@ -85,14 +103,14 @@ TaskItem RsyncDeployService::mkdirTask() return Process(setupHandler, {}, errorHandler); } -TaskItem RsyncDeployService::transferTask() +TaskItem RsyncDeployStep::transferTask() { const auto setupHandler = [this](FileTransfer &transfer) { transfer.setTransferMethod(FileTransferMethod::Rsync); transfer.setRsyncFlags(m_flags); transfer.setFilesToTransfer(m_files); connect(&transfer, &FileTransfer::progress, - this, &AbstractRemoteLinuxDeployService::stdOutData); + this, &AbstractRemoteLinuxDeployStep::stdOutData); }; const auto errorHandler = [this](const FileTransfer &transfer) { const ProcessResultData result = transfer.resultData(); @@ -108,50 +126,11 @@ TaskItem RsyncDeployService::transferTask() return Transfer(setupHandler, {}, errorHandler); } -Group RsyncDeployService::deployRecipe() +Group RsyncDeployStep::deployRecipe() { return Group { mkdirTask(), transferTask() }; } -// RsyncDeployStep - -RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id) - : AbstractRemoteLinuxDeployStep(bsl, id) -{ - auto service = new RsyncDeployService; - setDeployService(service); - - auto flags = addAspect(); - flags->setDisplayStyle(StringAspect::LineEditDisplay); - flags->setSettingsKey("RemoteLinux.RsyncDeployStep.Flags"); - flags->setLabelText(Tr::tr("Flags:")); - flags->setValue(FileTransferSetupData::defaultRsyncFlags()); - - auto ignoreMissingFiles = addAspect(); - ignoreMissingFiles->setSettingsKey("RemoteLinux.RsyncDeployStep.IgnoreMissingFiles"); - ignoreMissingFiles->setLabel(Tr::tr("Ignore missing files:"), - BoolAspect::LabelPlacement::InExtraLabel); - ignoreMissingFiles->setValue(false); - - setInternalInitializer([this, service, flags, ignoreMissingFiles] { - if (BuildDeviceKitAspect::device(kit()) == DeviceKitAspect::device(kit())) { - // rsync transfer on the same device currently not implemented - // and typically not wanted. - return CheckResult::failure( - Tr::tr("rsync is only supported for transfers between different devices.")); - } - service->setIgnoreMissingFiles(ignoreMissingFiles->value()); - service->setFlags(flags->value()); - return service->isDeploymentPossible(); - }); - - setRunPreparer([this, service] { - service->setDeployableFiles(target()->deploymentData().allFiles()); - }); -} - -RsyncDeployStep::~RsyncDeployStep() = default; - Utils::Id RsyncDeployStep::stepId() { return Constants::RsyncDeployStepId; diff --git a/src/plugins/remotelinux/rsyncdeploystep.h b/src/plugins/remotelinux/rsyncdeploystep.h index a0f87905311..c5d3d1eeb12 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.h +++ b/src/plugins/remotelinux/rsyncdeploystep.h @@ -7,6 +7,10 @@ #include "abstractremotelinuxdeploystep.h" +#include + +#include + namespace RemoteLinux { class REMOTELINUX_EXPORT RsyncDeployStep : public AbstractRemoteLinuxDeployStep @@ -17,6 +21,20 @@ public: static Utils::Id stepId(); static QString displayName(); + + void setDeployableFiles(const QList &files); + void setIgnoreMissingFiles(bool ignore) { m_ignoreMissingFiles = ignore; } + void setFlags(const QString &flags) { m_flags = flags; } + +private: + bool isDeploymentNecessary() const final; + Utils::Tasking::Group deployRecipe() final; + Utils::Tasking::TaskItem mkdirTask(); + Utils::Tasking::TaskItem transferTask(); + + mutable ProjectExplorer::FilesToTransfer m_files; + bool m_ignoreMissingFiles = false; + QString m_flags; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index ee276666ac8..ed793101b93 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -21,9 +21,36 @@ using namespace Utils::Tasking; namespace RemoteLinux::Internal { -class TarPackageDeployService : public AbstractRemoteLinuxDeployService +// TarPackageDeployStep + +class TarPackageDeployStep : public AbstractRemoteLinuxDeployStep { public: + TarPackageDeployStep(BuildStepList *bsl, Id id) + : AbstractRemoteLinuxDeployStep(bsl, id) + { + setWidgetExpandedByDefault(false); + + setInternalInitializer([this] { + const BuildStep *tarCreationStep = nullptr; + + for (BuildStep *step : deployConfiguration()->stepList()->steps()) { + if (step == this) + break; + if (step->id() == Constants::TarPackageCreationStepId) { + tarCreationStep = step; + break; + } + } + if (!tarCreationStep) + return CheckResult::failure(Tr::tr("No tarball creation step found.")); + + const FilePath tarFile = + FilePath::fromVariant(tarCreationStep->data(Constants::TarPackageFilePathId)); + setPackageFilePath(tarFile); + return isDeploymentPossible(); + }); + } void setPackageFilePath(const FilePath &filePath); private: @@ -36,29 +63,28 @@ private: FilePath m_packageFilePath; }; -void TarPackageDeployService::setPackageFilePath(const FilePath &filePath) +void TarPackageDeployStep::setPackageFilePath(const FilePath &filePath) { m_packageFilePath = filePath; } -QString TarPackageDeployService::remoteFilePath() const +QString TarPackageDeployStep::remoteFilePath() const { return QLatin1String("/tmp/") + m_packageFilePath.fileName(); } -bool TarPackageDeployService::isDeploymentNecessary() const +bool TarPackageDeployStep::isDeploymentNecessary() const { return hasLocalFileChanged(DeployableFile(m_packageFilePath, {})); } -TaskItem TarPackageDeployService::uploadTask() +TaskItem TarPackageDeployStep::uploadTask() { const auto setupHandler = [this](FileTransfer &transfer) { const FilesToTransfer files {{m_packageFilePath, deviceConfiguration()->filePath(remoteFilePath())}}; transfer.setFilesToTransfer(files); - connect(&transfer, &FileTransfer::progress, - this, &TarPackageDeployService::progressMessage); + connect(&transfer, &FileTransfer::progress, this, &TarPackageDeployStep::progressMessage); emit progressMessage(Tr::tr("Uploading package to device...")); }; const auto doneHandler = [this](const FileTransfer &) { @@ -71,7 +97,7 @@ TaskItem TarPackageDeployService::uploadTask() return Transfer(setupHandler, doneHandler, errorHandler); } -TaskItem TarPackageDeployService::installTask() +TaskItem TarPackageDeployStep::installTask() { const auto setupHandler = [this](QtcProcess &process) { const QString cmdLine = QLatin1String("cd / && tar xvf ") + remoteFilePath() @@ -96,46 +122,11 @@ TaskItem TarPackageDeployService::installTask() return Process(setupHandler, doneHandler, errorHandler); } -Group TarPackageDeployService::deployRecipe() +Group TarPackageDeployStep::deployRecipe() { return Group { uploadTask(), installTask() }; } -// TarPackageDeployStep - -class TarPackageDeployStep : public AbstractRemoteLinuxDeployStep -{ -public: - TarPackageDeployStep(BuildStepList *bsl, Id id) - : AbstractRemoteLinuxDeployStep(bsl, id) - { - auto service = new TarPackageDeployService; - setDeployService(service); - - setWidgetExpandedByDefault(false); - - setInternalInitializer([this, service] { - const BuildStep *tarCreationStep = nullptr; - - for (BuildStep *step : deployConfiguration()->stepList()->steps()) { - if (step == this) - break; - if (step->id() == Constants::TarPackageCreationStepId) { - tarCreationStep = step; - break; - } - } - if (!tarCreationStep) - return CheckResult::failure(Tr::tr("No tarball creation step found.")); - - const FilePath tarFile = - FilePath::fromVariant(tarCreationStep->data(Constants::TarPackageFilePathId)); - service->setPackageFilePath(tarFile); - return service->isDeploymentPossible(); - }); - } -}; - // TarPackageDeployStepFactory From c6b6e5b0c6aa883d32a6f241d0f76476563c4a0a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Mar 2023 09:34:34 +0100 Subject: [PATCH 0343/1447] RemoteLinux: Drop some in-class signalling Not needed since the deploy step and service hierarchy merge. Change-Id: I644bdeca31caa2182b9d618e5f1ec6865c95f4c8 Reviewed-by: Marcus Tillmanns --- src/plugins/boot2qt/qdbmakedefaultappstep.cpp | 8 ++--- .../boot2qt/qdbstopapplicationstep.cpp | 16 ++++----- .../abstractremotelinuxdeploystep.cpp | 26 +++++--------- .../abstractremotelinuxdeploystep.h | 21 +++++------- .../remotelinux/customcommanddeploystep.cpp | 12 +++---- .../remotelinux/genericdirectuploadstep.cpp | 34 +++++++++---------- .../remotelinux/genericdirectuploadstep.h | 1 + src/plugins/remotelinux/killappstep.cpp | 8 ++--- src/plugins/remotelinux/rsyncdeploystep.cpp | 16 ++++----- .../remotelinux/tarpackagedeploystep.cpp | 18 +++++----- 10 files changed, 73 insertions(+), 87 deletions(-) diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp index 4887183ac18..7b13f253bc7 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp @@ -58,17 +58,17 @@ private: process.setCommand(cmd); QtcProcess *proc = &process; connect(proc, &QtcProcess::readyReadStandardError, this, [this, proc] { - emit stdErrData(proc->readAllStandardError()); + handleStdErrData(proc->readAllStandardError()); }); }; const auto doneHandler = [this](const QtcProcess &) { if (m_makeDefault) - emit progressMessage(Tr::tr("Application set as the default one.")); + addProgressMessage(Tr::tr("Application set as the default one.")); else - emit progressMessage(Tr::tr("Reset the default application.")); + addProgressMessage(Tr::tr("Reset the default application.")); }; const auto errorHandler = [this](const QtcProcess &process) { - emit errorMessage(Tr::tr("Remote process failed: %1").arg(process.errorString())); + addErrorMessage(Tr::tr("Remote process failed: %1").arg(process.errorString())); }; return Group { Process(setupHandler, doneHandler, errorHandler) }; } diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index 688ab745142..00abe38c6f5 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -43,7 +43,7 @@ Group QdbStopApplicationStep::deployRecipe() const auto setupHandler = [this](QtcProcess &process) { const auto device = DeviceKitAspect::device(target()->kit()); if (!device) { - emit errorMessage(Tr::tr("No device to stop the application on.")); + addErrorMessage(Tr::tr("No device to stop the application on.")); return TaskAction::StopWithError; } QTC_CHECK(device); @@ -51,25 +51,25 @@ Group QdbStopApplicationStep::deployRecipe() process.setWorkingDirectory("/usr/bin"); QtcProcess *proc = &process; connect(proc, &QtcProcess::readyReadStandardOutput, this, [this, proc] { - emit stdOutData(proc->readAllStandardOutput()); + handleStdOutData(proc->readAllStandardOutput()); }); return TaskAction::Continue; }; const auto doneHandler = [this](const QtcProcess &) { - emit progressMessage(Tr::tr("Stopped the running application.")); + addProgressMessage(Tr::tr("Stopped the running application.")); }; const auto errorHandler = [this](const QtcProcess &process) { const QString errorOutput = process.cleanedStdErr(); const QString failureMessage = Tr::tr("Could not check and possibly stop running application."); if (process.exitStatus() == QProcess::CrashExit) { - emit errorMessage(failureMessage); + addErrorMessage(failureMessage); } else if (process.result() != ProcessResult::FinishedWithSuccess) { - emit stdErrData(process.errorString()); + handleStdErrData(process.errorString()); } else if (errorOutput.contains("Could not connect: Connection refused")) { - emit progressMessage(Tr::tr("Checked that there is no running application.")); + addProgressMessage(Tr::tr("Checked that there is no running application.")); } else if (!errorOutput.isEmpty()) { - emit stdErrData(errorOutput); - emit errorMessage(failureMessage); + handleStdErrData(errorOutput); + addErrorMessage(failureMessage); } }; return Group { Process(setupHandler, doneHandler, errorHandler) }; diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp index 84e4b53cee8..e5b6415f348 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp @@ -40,19 +40,8 @@ public: using namespace Internal; AbstractRemoteLinuxDeployStep::AbstractRemoteLinuxDeployStep(BuildStepList *bsl, Id id) - : BuildStep(bsl, id), d(new Internal::AbstractRemoteLinuxDeployStepPrivate) -{ - connect(this, &AbstractRemoteLinuxDeployStep::errorMessage, - this, &AbstractRemoteLinuxDeployStep::handleErrorMessage); - connect(this, &AbstractRemoteLinuxDeployStep::progressMessage, - this, &AbstractRemoteLinuxDeployStep::handleProgressMessage); - connect(this, &AbstractRemoteLinuxDeployStep::warningMessage, - this, &AbstractRemoteLinuxDeployStep::handleWarningMessage); - connect(this, &AbstractRemoteLinuxDeployStep::stdOutData, - this, &AbstractRemoteLinuxDeployStep::handleStdOutData); - connect(this, &AbstractRemoteLinuxDeployStep::stdErrData, - this, &AbstractRemoteLinuxDeployStep::handleStdErrData); -} + : BuildStep(bsl, id), d(new AbstractRemoteLinuxDeployStepPrivate) +{} AbstractRemoteLinuxDeployStep::~AbstractRemoteLinuxDeployStep() { @@ -88,13 +77,13 @@ void AbstractRemoteLinuxDeployStep::start() const CheckResult check = isDeploymentPossible(); if (!check) { - emit errorMessage(check.errorMessage()); + addErrorMessage(check.errorMessage()); handleFinished(); return; } if (!isDeploymentNecessary()) { - emit progressMessage(Tr::tr("No deployment action necessary. Skipping.")); + addProgressMessage(Tr::tr("No deployment action necessary. Skipping.")); handleFinished(); return; } @@ -190,19 +179,19 @@ void AbstractRemoteLinuxDeployStep::doCancel() stop(); } -void AbstractRemoteLinuxDeployStep::handleProgressMessage(const QString &message) +void AbstractRemoteLinuxDeployStep::addProgressMessage(const QString &message) { emit addOutput(message, OutputFormat::NormalMessage); } -void AbstractRemoteLinuxDeployStep::handleErrorMessage(const QString &message) +void AbstractRemoteLinuxDeployStep::addErrorMessage(const QString &message) { emit addOutput(message, OutputFormat::ErrorMessage); emit addTask(DeploymentTask(Task::Error, message), 1); // TODO correct? d->hasError = true; } -void AbstractRemoteLinuxDeployStep::handleWarningMessage(const QString &message) +void AbstractRemoteLinuxDeployStep::addWarningMessage(const QString &message) { emit addOutput(message, OutputFormat::ErrorMessage); emit addTask(DeploymentTask(Task::Warning, message), 1); // TODO correct? @@ -214,6 +203,7 @@ void AbstractRemoteLinuxDeployStep::handleFinished() emit addOutput(Tr::tr("Deploy step failed."), OutputFormat::ErrorMessage); else emit addOutput(Tr::tr("Deploy step finished."), OutputFormat::NormalMessage); + emit finished(!d->hasError); } diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h index 72af36e49b3..8131a997d0a 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h @@ -58,12 +58,8 @@ public: virtual CheckResult isDeploymentPossible() const; -signals: - void errorMessage(const QString &message); - void progressMessage(const QString &message); - void warningMessage(const QString &message); - void stdOutData(const QString &data); - void stdErrData(const QString &data); + void handleStdOutData(const QString &data); + void handleStdErrData(const QString &data); protected: bool fromMap(const QVariantMap &map) override; @@ -81,14 +77,13 @@ protected: bool hasRemoteFileChanged(const ProjectExplorer::DeployableFile &deployableFile, const QDateTime &remoteTimestamp) const; -private: - void handleProgressMessage(const QString &message); - void handleErrorMessage(const QString &message); - void handleWarningMessage(const QString &message); - void handleFinished(); - void handleStdOutData(const QString &data); - void handleStdErrData(const QString &data); + void addProgressMessage(const QString &message); + void addErrorMessage(const QString &message); + void addWarningMessage(const QString &message); + void handleFinished(); + +private: virtual bool isDeploymentNecessary() const; virtual Utils::Tasking::Group deployRecipe(); diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index e0efa25f002..17b3f0317a8 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -67,26 +67,26 @@ CheckResult CustomCommandDeployStep::isDeploymentPossible() const Group CustomCommandDeployStep::deployRecipe() { const auto setupHandler = [this](QtcProcess &process) { - emit progressMessage(Tr::tr("Starting remote command \"%1\"...").arg(m_commandLine)); + addProgressMessage(Tr::tr("Starting remote command \"%1\"...").arg(m_commandLine)); process.setCommand({deviceConfiguration()->filePath("/bin/sh"), {"-c", m_commandLine}}); QtcProcess *proc = &process; connect(proc, &QtcProcess::readyReadStandardOutput, this, [this, proc] { - emit stdOutData(proc->readAllStandardOutput()); + handleStdOutData(proc->readAllStandardOutput()); }); connect(proc, &QtcProcess::readyReadStandardError, this, [this, proc] { - emit stdErrData(proc->readAllStandardError()); + handleStdErrData(proc->readAllStandardError()); }); }; const auto doneHandler = [this](const QtcProcess &) { - emit progressMessage(Tr::tr("Remote command finished successfully.")); + addProgressMessage(Tr::tr("Remote command finished successfully.")); }; const auto errorHandler = [this](const QtcProcess &process) { if (process.error() != QProcess::UnknownError || process.exitStatus() != QProcess::NormalExit) { - emit errorMessage(Tr::tr("Remote process failed: %1").arg(process.errorString())); + addErrorMessage(Tr::tr("Remote process failed: %1").arg(process.errorString())); } else if (process.exitCode() != 0) { - emit errorMessage(Tr::tr("Remote process finished with exit code %1.") + addErrorMessage(Tr::tr("Remote process finished with exit code %1.") .arg(process.exitCode())); } }; diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 8b20effca69..5764fc0d646 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -103,7 +103,7 @@ QDateTime GenericDirectUploadStepPrivate::timestampFromStat(const DeployableFile succeeded = true; } if (!succeeded) { - emit q->warningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " + q->addWarningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " "Incremental deployment will not work. Error message was: %2") .arg(file.remoteFilePath(), error)); return {}; @@ -112,18 +112,18 @@ QDateTime GenericDirectUploadStepPrivate::timestampFromStat(const DeployableFile const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2") .arg(file.remoteFilePath()).arg(QString::fromUtf8(output))); if (!output.startsWith(file.remoteFilePath().toUtf8())) { - emit q->warningMessage(warningString); + q->addWarningMessage(warningString); return {}; } const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' '); if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns - emit q->warningMessage(warningString); + q->addWarningMessage(warningString); return {}; } bool isNumber; const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber); if (!isNumber) { - emit q->warningMessage(warningString); + q->addWarningMessage(warningString); return {}; } return QDateTime::fromSecsSinceEpoch(secsSinceEpoch); @@ -166,37 +166,37 @@ TaskItem GenericDirectUploadStepPrivate::uploadTask(const TreeStoragefilesToUpload.isEmpty()) { - emit q->progressMessage(Tr::tr("No files need to be uploaded.")); + q->addProgressMessage(Tr::tr("No files need to be uploaded.")); return TaskAction::StopWithDone; } - emit q->progressMessage(Tr::tr("%n file(s) need to be uploaded.", "", - storage->filesToUpload.size())); + q->addProgressMessage(Tr::tr("%n file(s) need to be uploaded.", "", + storage->filesToUpload.size())); FilesToTransfer files; for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { if (!file.localFilePath().exists()) { const QString message = Tr::tr("Local file \"%1\" does not exist.") .arg(file.localFilePath().toUserOutput()); if (m_ignoreMissingFiles) { - emit q->warningMessage(message); + q->addWarningMessage(message); continue; } - emit q->errorMessage(message); + q->addErrorMessage(message); return TaskAction::StopWithError; } files.append({file.localFilePath(), q->deviceConfiguration()->filePath(file.remoteFilePath())}); } if (files.isEmpty()) { - emit q->progressMessage(Tr::tr("No files need to be uploaded.")); + q->addProgressMessage(Tr::tr("No files need to be uploaded.")); return TaskAction::StopWithDone; } transfer.setFilesToTransfer(files); QObject::connect(&transfer, &FileTransfer::progress, - q, &GenericDirectUploadStep::progressMessage); + q, &GenericDirectUploadStep::addProgressMessage); return TaskAction::Continue; }; const auto errorHandler = [this](const FileTransfer &transfer) { - emit q->errorMessage(transfer.resultData().m_errorString); + q->addErrorMessage(transfer.resultData().m_errorString); }; return Transfer(setupHandler, {}, errorHandler); @@ -211,11 +211,11 @@ TaskItem GenericDirectUploadStepPrivate::chmodTask(const DeployableFile &file) const auto errorHandler = [=](const QtcProcess &process) { const QString error = process.errorString(); if (!error.isEmpty()) { - emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") - .arg(file.remoteFilePath(), error)); + q->addWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + .arg(file.remoteFilePath(), error)); } else if (process.exitCode() != 0) { - emit q->warningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") - .arg(file.remoteFilePath(), process.cleanedStdErr())); + q->addWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + .arg(file.remoteFilePath(), process.cleanedStdErr())); } }; return Process(setupHandler, {}, errorHandler); @@ -271,7 +271,7 @@ Group GenericDirectUploadStep::deployRecipe() saveDeploymentTimeStamp(file, timestamp); }; const auto doneHandler = [this] { - emit progressMessage(Tr::tr("All files successfully deployed.")); + addProgressMessage(Tr::tr("All files successfully deployed.")); }; const TreeStorage storage; diff --git a/src/plugins/remotelinux/genericdirectuploadstep.h b/src/plugins/remotelinux/genericdirectuploadstep.h index e04426136cf..dd022d2b32c 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.h +++ b/src/plugins/remotelinux/genericdirectuploadstep.h @@ -25,6 +25,7 @@ public: static QString displayName(); private: + friend class GenericDirectUploadStepPrivate; class GenericDirectUploadStepPrivate *d; }; diff --git a/src/plugins/remotelinux/killappstep.cpp b/src/plugins/remotelinux/killappstep.cpp index 57adfefd9b1..d82844fa157 100644 --- a/src/plugins/remotelinux/killappstep.cpp +++ b/src/plugins/remotelinux/killappstep.cpp @@ -47,14 +47,14 @@ Group KillAppStep::deployRecipe() { const auto setupHandler = [this](DeviceProcessKiller &killer) { killer.setProcessPath(m_remoteExecutable); - emit progressMessage(Tr::tr("Trying to kill \"%1\" on remote device...") - .arg(m_remoteExecutable.path())); + addProgressMessage(Tr::tr("Trying to kill \"%1\" on remote device...") + .arg(m_remoteExecutable.path())); }; const auto doneHandler = [this](const DeviceProcessKiller &) { - emit progressMessage(Tr::tr("Remote application killed.")); + addProgressMessage(Tr::tr("Remote application killed.")); }; const auto errorHandler = [this](const DeviceProcessKiller &) { - emit progressMessage(Tr::tr("Failed to kill remote application. " + addProgressMessage(Tr::tr("Failed to kill remote application. " "Assuming it was not running.")); }; return Group { Killer(setupHandler, doneHandler, errorHandler) }; diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index e5a012ff88c..65f2a16720d 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -86,7 +86,7 @@ TaskItem RsyncDeployStep::mkdirTask() process.setCommand({deviceConfiguration()->filePath("mkdir"), QStringList("-p") + remoteDirs}); connect(&process, &QtcProcess::readyReadStandardError, this, [this, proc = &process] { - emit stdErrData(QString::fromLocal8Bit(proc->readAllRawStandardError())); + handleStdErrData(QString::fromLocal8Bit(proc->readAllRawStandardError())); }); }; const auto errorHandler = [this](const QtcProcess &process) { @@ -97,8 +97,8 @@ TaskItem RsyncDeployStep::mkdirTask() finalMessage += '\n'; finalMessage += stdErr; } - emit errorMessage(Tr::tr("Deploy via rsync: failed to create remote directories:") - + '\n' + finalMessage); + addErrorMessage(Tr::tr("Deploy via rsync: failed to create remote directories:") + + '\n' + finalMessage); }; return Process(setupHandler, {}, errorHandler); } @@ -110,17 +110,17 @@ TaskItem RsyncDeployStep::transferTask() transfer.setRsyncFlags(m_flags); transfer.setFilesToTransfer(m_files); connect(&transfer, &FileTransfer::progress, - this, &AbstractRemoteLinuxDeployStep::stdOutData); + this, &AbstractRemoteLinuxDeployStep::handleStdOutData); }; const auto errorHandler = [this](const FileTransfer &transfer) { const ProcessResultData result = transfer.resultData(); if (result.m_error == QProcess::FailedToStart) { - emit errorMessage(Tr::tr("rsync failed to start: %1").arg(result.m_errorString)); + addErrorMessage(Tr::tr("rsync failed to start: %1").arg(result.m_errorString)); } else if (result.m_exitStatus == QProcess::CrashExit) { - emit errorMessage(Tr::tr("rsync crashed.")); + addErrorMessage(Tr::tr("rsync crashed.")); } else if (result.m_exitCode != 0) { - emit errorMessage(Tr::tr("rsync failed with exit code %1.").arg(result.m_exitCode) - + "\n" + result.m_errorString); + addErrorMessage(Tr::tr("rsync failed with exit code %1.").arg(result.m_exitCode) + + "\n" + result.m_errorString); } }; return Transfer(setupHandler, {}, errorHandler); diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index ed793101b93..885fd2944d5 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -84,15 +84,15 @@ TaskItem TarPackageDeployStep::uploadTask() const FilesToTransfer files {{m_packageFilePath, deviceConfiguration()->filePath(remoteFilePath())}}; transfer.setFilesToTransfer(files); - connect(&transfer, &FileTransfer::progress, this, &TarPackageDeployStep::progressMessage); - emit progressMessage(Tr::tr("Uploading package to device...")); + connect(&transfer, &FileTransfer::progress, this, &TarPackageDeployStep::addProgressMessage); + addProgressMessage(Tr::tr("Uploading package to device...")); }; const auto doneHandler = [this](const FileTransfer &) { - emit progressMessage(Tr::tr("Successfully uploaded package file.")); + addProgressMessage(Tr::tr("Successfully uploaded package file.")); }; const auto errorHandler = [this](const FileTransfer &transfer) { const ProcessResultData result = transfer.resultData(); - emit errorMessage(result.m_errorString); + addErrorMessage(result.m_errorString); }; return Transfer(setupHandler, doneHandler, errorHandler); } @@ -105,19 +105,19 @@ TaskItem TarPackageDeployStep::installTask() process.setCommand({deviceConfiguration()->filePath("/bin/sh"), {"-c", cmdLine}}); QtcProcess *proc = &process; connect(proc, &QtcProcess::readyReadStandardOutput, this, [this, proc] { - emit stdOutData(proc->readAllStandardOutput()); + handleStdOutData(proc->readAllStandardOutput()); }); connect(proc, &QtcProcess::readyReadStandardError, this, [this, proc] { - emit stdErrData(proc->readAllStandardError()); + handleStdErrData(proc->readAllStandardError()); }); - emit progressMessage(Tr::tr("Installing package to device...")); + addProgressMessage(Tr::tr("Installing package to device...")); }; const auto doneHandler = [this](const QtcProcess &) { saveDeploymentTimeStamp(DeployableFile(m_packageFilePath, {}), {}); - emit progressMessage(Tr::tr("Successfully installed package file.")); + addProgressMessage(Tr::tr("Successfully installed package file.")); }; const auto errorHandler = [this](const QtcProcess &process) { - emit errorMessage(Tr::tr("Installing package failed.") + process.errorString()); + addErrorMessage(Tr::tr("Installing package failed.") + process.errorString()); }; return Process(setupHandler, doneHandler, errorHandler); } From 2d0b2fd464089656429bd20bc477859b9d85e4b1 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Mar 2023 10:05:26 +0100 Subject: [PATCH 0344/1447] RemoteLinux: simplify AbstractRemoteLinuxDeployStep interface Effectively inline four functions that are used only once. Change-Id: I2cc96205e457a16a1f68f2bcda1cdf4945cec93e Reviewed-by: Reviewed-by: Marcus Tillmanns --- .../abstractremotelinuxdeploystep.cpp | 126 ++++++++---------- .../abstractremotelinuxdeploystep.h | 5 - 2 files changed, 54 insertions(+), 77 deletions(-) diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp index e5b6415f348..60982c32872 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp @@ -71,8 +71,56 @@ bool AbstractRemoteLinuxDeployStep::hasRemoteFileChanged( return d->deployTimes.hasRemoteFileChanged(deployableFile, kit(), remoteTimestamp); } -void AbstractRemoteLinuxDeployStep::start() +CheckResult AbstractRemoteLinuxDeployStep::isDeploymentPossible() const { + if (!deviceConfiguration()) + return CheckResult::failure(Tr::tr("No device configuration set.")); + return CheckResult::success(); +} + +void AbstractRemoteLinuxDeployStep::setInternalInitializer(const std::function &init) +{ + d->internalInit = init; +} + +void AbstractRemoteLinuxDeployStep::setRunPreparer(const std::function &prep) +{ + d->runPreparer = prep; +} + +bool AbstractRemoteLinuxDeployStep::fromMap(const QVariantMap &map) +{ + if (!BuildStep::fromMap(map)) + return false; + d->deployTimes.importDeployTimes(map); + return true; +} + +QVariantMap AbstractRemoteLinuxDeployStep::toMap() const +{ + QVariantMap map = BuildStep::toMap(); + map.insert(d->deployTimes.exportDeployTimes()); + return map; +} + +bool AbstractRemoteLinuxDeployStep::init() +{ + QTC_ASSERT(d->internalInit, return false); + const CheckResult canDeploy = d->internalInit(); + if (!canDeploy) { + emit addOutput(Tr::tr("Cannot deploy: %1").arg(canDeploy.errorMessage()), + OutputFormat::ErrorMessage); + } + return canDeploy; +} + +void AbstractRemoteLinuxDeployStep::doRun() +{ + if (d->runPreparer) + d->runPreparer(); + + d->hasError = false; + QTC_ASSERT(!d->m_taskTree, return); const CheckResult check = isDeploymentPossible(); @@ -98,76 +146,6 @@ void AbstractRemoteLinuxDeployStep::start() d->m_taskTree->start(); } -void AbstractRemoteLinuxDeployStep::stop() -{ - if (!d->m_taskTree) - return; - d->m_taskTree.reset(); - handleFinished(); -} - -CheckResult AbstractRemoteLinuxDeployStep::isDeploymentPossible() const -{ - if (!deviceConfiguration()) - return CheckResult::failure(Tr::tr("No device configuration set.")); - return CheckResult::success(); -} - -QVariantMap AbstractRemoteLinuxDeployStep::exportDeployTimes() const -{ - return d->deployTimes.exportDeployTimes(); -} - -void AbstractRemoteLinuxDeployStep::importDeployTimes(const QVariantMap &map) -{ - d->deployTimes.importDeployTimes(map); -} - -void AbstractRemoteLinuxDeployStep::setInternalInitializer(const std::function &init) -{ - d->internalInit = init; -} - -void AbstractRemoteLinuxDeployStep::setRunPreparer(const std::function &prep) -{ - d->runPreparer = prep; -} - -bool AbstractRemoteLinuxDeployStep::fromMap(const QVariantMap &map) -{ - if (!BuildStep::fromMap(map)) - return false; - importDeployTimes(map); - return true; -} - -QVariantMap AbstractRemoteLinuxDeployStep::toMap() const -{ - QVariantMap map = BuildStep::toMap(); - map.insert(exportDeployTimes()); - return map; -} - -bool AbstractRemoteLinuxDeployStep::init() -{ - QTC_ASSERT(d->internalInit, return false); - const CheckResult canDeploy = d->internalInit(); - if (!canDeploy) { - emit addOutput(Tr::tr("Cannot deploy: %1").arg(canDeploy.errorMessage()), - OutputFormat::ErrorMessage); - } - return canDeploy; -} - -void AbstractRemoteLinuxDeployStep::doRun() -{ - if (d->runPreparer) - d->runPreparer(); - - d->hasError = false; - start(); -} - void AbstractRemoteLinuxDeployStep::doCancel() { if (d->hasError) @@ -176,7 +154,11 @@ void AbstractRemoteLinuxDeployStep::doCancel() emit addOutput(Tr::tr("User requests deployment to stop; cleaning up."), OutputFormat::NormalMessage); d->hasError = true; - stop(); + + if (!d->m_taskTree) + return; + d->m_taskTree.reset(); + handleFinished(); } void AbstractRemoteLinuxDeployStep::addProgressMessage(const QString &message) diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h index 8131a997d0a..a0db68664ab 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h @@ -49,11 +49,6 @@ public: explicit AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); ~AbstractRemoteLinuxDeployStep() override; - void start(); - void stop(); - - QVariantMap exportDeployTimes() const; - void importDeployTimes(const QVariantMap &map); ProjectExplorer::IDeviceConstPtr deviceConfiguration() const; virtual CheckResult isDeploymentPossible() const; From c6659020be0094645bb880e85ffc47382c69d091 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Mar 2023 10:14:30 +0100 Subject: [PATCH 0345/1447] Boot2Qt/RL: Remove some function re-implementations ... that are identical to the base implementation. Change-Id: I75dd2c2c560ae04fe410a1846c68a82aa6d214a2 Reviewed-by: Marcus Tillmanns --- src/plugins/boot2qt/qdbmakedefaultappstep.cpp | 2 -- src/plugins/boot2qt/qdbstopapplicationstep.cpp | 1 - src/plugins/remotelinux/customcommanddeploystep.cpp | 2 -- 3 files changed, 5 deletions(-) diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp index 7b13f253bc7..ffc1c4c487f 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp @@ -40,8 +40,6 @@ public: } private: - bool isDeploymentNecessary() const final { return true; } - Group deployRecipe() final { const auto setupHandler = [this](QtcProcess &process) { diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index 00abe38c6f5..ac67385a7be 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -34,7 +34,6 @@ public: setInternalInitializer([this] { return isDeploymentPossible(); }); } - bool isDeploymentNecessary() const final { return true; } Group deployRecipe() final; }; diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index 17b3f0317a8..6d6fbcd65e4 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -46,8 +46,6 @@ protected: Group deployRecipe() final; private: - bool isDeploymentNecessary() const final { return true; } - QString m_commandLine; }; From 64e40631ec5565b36e647d1e61cc1da8981e245f Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Mar 2023 10:25:25 +0100 Subject: [PATCH 0346/1447] RemoteLinux: Inline a few more deploy step functions Change-Id: Ib93562b24de796f570cfa76dd3990ede5ebc6061 Reviewed-by: Marcus Tillmanns --- .../remotelinux/customcommanddeploystep.cpp | 11 ++--------- src/plugins/remotelinux/rsyncdeploystep.cpp | 16 ++++++---------- src/plugins/remotelinux/rsyncdeploystep.h | 4 ---- src/plugins/remotelinux/tarpackagedeploystep.cpp | 11 ++--------- 4 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index 6d6fbcd65e4..db8f9988b2b 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -32,28 +32,21 @@ public: commandLine->setHistoryCompleter("RemoteLinuxCustomCommandDeploymentStep.History"); setInternalInitializer([this, commandLine] { - setCommandLine(commandLine->value().trimmed()); + m_commandLine = commandLine->value().trimmed(); return isDeploymentPossible(); }); addMacroExpander(); } - void setCommandLine(const QString &commandLine); CheckResult isDeploymentPossible() const final; -protected: +private: Group deployRecipe() final; -private: QString m_commandLine; }; -void CustomCommandDeployStep::setCommandLine(const QString &commandLine) -{ - m_commandLine = commandLine; -} - CheckResult CustomCommandDeployStep::isDeploymentPossible() const { if (m_commandLine.isEmpty()) diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 65f2a16720d..b81914b072b 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -49,25 +49,21 @@ RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id) return CheckResult::failure( Tr::tr("rsync is only supported for transfers between different devices.")); } - setIgnoreMissingFiles(ignoreMissingFiles->value()); - setFlags(flags->value()); + m_ignoreMissingFiles = ignoreMissingFiles->value(); + m_flags = flags->value(); return isDeploymentPossible(); }); setRunPreparer([this] { - setDeployableFiles(target()->deploymentData().allFiles()); + const QList files = target()->deploymentData().allFiles(); + m_files.clear(); + for (const DeployableFile &f : files) + m_files.append({f.localFilePath(), deviceConfiguration()->filePath(f.remoteFilePath())}); }); } RsyncDeployStep::~RsyncDeployStep() = default; -void RsyncDeployStep::setDeployableFiles(const QList &files) -{ - m_files.clear(); - for (const DeployableFile &f : files) - m_files.append({f.localFilePath(), deviceConfiguration()->filePath(f.remoteFilePath())}); -} - bool RsyncDeployStep::isDeploymentNecessary() const { if (m_ignoreMissingFiles) diff --git a/src/plugins/remotelinux/rsyncdeploystep.h b/src/plugins/remotelinux/rsyncdeploystep.h index c5d3d1eeb12..1cbd2edee38 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.h +++ b/src/plugins/remotelinux/rsyncdeploystep.h @@ -22,10 +22,6 @@ public: static Utils::Id stepId(); static QString displayName(); - void setDeployableFiles(const QList &files); - void setIgnoreMissingFiles(bool ignore) { m_ignoreMissingFiles = ignore; } - void setFlags(const QString &flags) { m_flags = flags; } - private: bool isDeploymentNecessary() const final; Utils::Tasking::Group deployRecipe() final; diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index 885fd2944d5..9f6022e8160 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -45,13 +45,11 @@ public: if (!tarCreationStep) return CheckResult::failure(Tr::tr("No tarball creation step found.")); - const FilePath tarFile = - FilePath::fromVariant(tarCreationStep->data(Constants::TarPackageFilePathId)); - setPackageFilePath(tarFile); + m_packageFilePath = + FilePath::fromVariant(tarCreationStep->data(Constants::TarPackageFilePathId)); return isDeploymentPossible(); }); } - void setPackageFilePath(const FilePath &filePath); private: QString remoteFilePath() const; @@ -63,11 +61,6 @@ private: FilePath m_packageFilePath; }; -void TarPackageDeployStep::setPackageFilePath(const FilePath &filePath) -{ - m_packageFilePath = filePath; -} - QString TarPackageDeployStep::remoteFilePath() const { return QLatin1String("/tmp/") + m_packageFilePath.fileName(); From 04dd3e87b48277e6065d46176ba6a2710f31b8f6 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 08:02:48 +0100 Subject: [PATCH 0347/1447] RemoteLinux: Use FancyLineEdits in device setup wizard Change-Id: Ibd94630e8acc4e99073760a15eddb82193a44d75 Reviewed-by: Alessandro Portale --- ...riclinuxdeviceconfigurationwizardpages.cpp | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp index 24ac00bfd00..0a34683bdeb 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp @@ -9,14 +9,15 @@ #include +#include #include +#include #include #include #include #include #include -#include #include #include @@ -29,10 +30,10 @@ namespace Internal { class GenericLinuxDeviceConfigurationWizardSetupPagePrivate { public: - QLineEdit *nameLineEdit; - QLineEdit *hostNameLineEdit; + FancyLineEdit *nameLineEdit; + FancyLineEdit *hostNameLineEdit; QSpinBox *sshPortSpinBox; - QLineEdit *userNameLineEdit; + FancyLineEdit *userNameLineEdit; LinuxDevice::Ptr device; }; @@ -52,10 +53,16 @@ GenericLinuxDeviceConfigurationWizardSetupPage::GenericLinuxDeviceConfigurationW setTitle(Tr::tr("Connection")); setWindowTitle(Tr::tr("WizardPage")); - d->nameLineEdit = new QLineEdit(this); - d->hostNameLineEdit = new QLineEdit(this); + d->nameLineEdit = new FancyLineEdit(this); + d->nameLineEdit->setHistoryCompleter("DeviceName"); + + d->hostNameLineEdit = new FancyLineEdit(this); + d->hostNameLineEdit->setHistoryCompleter("HostName"); + d->sshPortSpinBox = new QSpinBox(this); - d->userNameLineEdit = new QLineEdit(this); + + d->userNameLineEdit = new FancyLineEdit(this); + d->userNameLineEdit->setHistoryCompleter("UserName"); using namespace Layouting; Form { From d5b419dfa8851d57b42b9ffc417eeb8d03d04beb Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 22 Mar 2023 13:36:06 +0100 Subject: [PATCH 0348/1447] Terminal: Fix settings aspect registration Change-Id: I6f38660ba041dd745900746b16c7045d61a39e5b Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalsettings.cpp | 51 +++++++++++------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index cbb43d78bbe..32d1ff5097e 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -47,11 +47,16 @@ TerminalSettings &TerminalSettings::instance() return settings; } -void setupColor(ColorAspect &color, const QString &label, const QColor &defaultColor) +void setupColor(TerminalSettings *settings, + ColorAspect &color, + const QString &label, + const QColor &defaultColor) { color.setSettingsKey(label); color.setDefaultValue(defaultColor); color.setToolTip(Tr::tr("The color used for %1.").arg(label)); + + settings->registerAspect(&color); } TerminalSettings::TerminalSettings() @@ -84,44 +89,38 @@ TerminalSettings::TerminalSettings() shell.setToolTip(Tr::tr("The shell executable to be started as terminal")); shell.setDefaultValue(defaultShell()); - setupColor(foregroundColor, "Foreground", QColor::fromRgb(0xff, 0xff, 0xff)); - setupColor(backgroundColor, "Background", QColor::fromRgb(0x0, 0x0, 0x0)); - setupColor(selectionColor, "Selection", QColor::fromRgb(0xFF, 0xFF, 0xFF, 0x7F)); + setupColor(this, foregroundColor, "Foreground", QColor::fromRgb(0xff, 0xff, 0xff)); + setupColor(this, backgroundColor, "Background", QColor::fromRgb(0x0, 0x0, 0x0)); + setupColor(this, selectionColor, "Selection", QColor::fromRgb(0xFF, 0xFF, 0xFF, 0x7F)); - setupColor(colors[0], "0", QColor::fromRgb(0x00, 0x00, 0x00)); - setupColor(colors[8], "8", QColor::fromRgb(102, 102, 102)); + setupColor(this, colors[0], "0", QColor::fromRgb(0x00, 0x00, 0x00)); + setupColor(this, colors[8], "8", QColor::fromRgb(102, 102, 102)); - setupColor(colors[1], "1", QColor::fromRgb(139, 27, 16)); - setupColor(colors[9], "9", QColor::fromRgb(210, 45, 31)); + setupColor(this, colors[1], "1", QColor::fromRgb(139, 27, 16)); + setupColor(this, colors[9], "9", QColor::fromRgb(210, 45, 31)); - setupColor(colors[2], "2", QColor::fromRgb(74, 163, 46)); - setupColor(colors[10], "10", QColor::fromRgb(98, 214, 63)); + setupColor(this, colors[2], "2", QColor::fromRgb(74, 163, 46)); + setupColor(this, colors[10], "10", QColor::fromRgb(98, 214, 63)); - setupColor(colors[3], "3", QColor::fromRgb(154, 154, 47)); - setupColor(colors[11], "11", QColor::fromRgb(229, 229, 75)); + setupColor(this, colors[3], "3", QColor::fromRgb(154, 154, 47)); + setupColor(this, colors[11], "11", QColor::fromRgb(229, 229, 75)); - setupColor(colors[4], "4", QColor::fromRgb(0, 0, 171)); - setupColor(colors[12], "12", QColor::fromRgb(0, 0, 254)); + setupColor(this, colors[4], "4", QColor::fromRgb(0, 0, 171)); + setupColor(this, colors[12], "12", QColor::fromRgb(0, 0, 254)); - setupColor(colors[5], "5", QColor::fromRgb(163, 32, 172)); - setupColor(colors[13], "13", QColor::fromRgb(210, 45, 222)); + setupColor(this, colors[5], "5", QColor::fromRgb(163, 32, 172)); + setupColor(this, colors[13], "13", QColor::fromRgb(210, 45, 222)); - setupColor(colors[6], "6", QColor::fromRgb(73, 163, 176)); - setupColor(colors[14], "14", QColor::fromRgb(105, 226, 228)); + setupColor(this, colors[6], "6", QColor::fromRgb(73, 163, 176)); + setupColor(this, colors[14], "14", QColor::fromRgb(105, 226, 228)); - setupColor(colors[7], "7", QColor::fromRgb(191, 191, 191)); - setupColor(colors[15], "15", QColor::fromRgb(229, 229, 230)); + setupColor(this, colors[7], "7", QColor::fromRgb(191, 191, 191)); + setupColor(this, colors[15], "15", QColor::fromRgb(229, 229, 230)); registerAspect(&font); registerAspect(&fontSize); registerAspect(&shell); registerAspect(&allowBlinkingCursor); - - registerAspect(&foregroundColor); - registerAspect(&backgroundColor); - - for (auto &color : colors) - registerAspect(&color); } } // namespace Terminal From 5341570572cc35b6656837d19f813994d90dd47b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 22 Mar 2023 15:39:55 +0100 Subject: [PATCH 0349/1447] Terminal: Move color mapping to widget This allows us to easily update the view when the colors are changed in the settings. Change-Id: I0b4f150b4fc9cec9aee2796d63f2395e05ce70df Reviewed-by: Cristian Adam --- src/plugins/terminal/scrollback.cpp | 10 +-- src/plugins/terminal/scrollback.h | 6 +- src/plugins/terminal/terminalsurface.cpp | 107 +++++++++-------------- src/plugins/terminal/terminalsurface.h | 11 +-- src/plugins/terminal/terminalwidget.cpp | 39 +++++---- src/plugins/terminal/terminalwidget.h | 2 + 6 files changed, 75 insertions(+), 100 deletions(-) diff --git a/src/plugins/terminal/scrollback.cpp b/src/plugins/terminal/scrollback.cpp index ca85c942d3d..e22d5fa2436 100644 --- a/src/plugins/terminal/scrollback.cpp +++ b/src/plugins/terminal/scrollback.cpp @@ -10,15 +10,11 @@ namespace Terminal::Internal { -Scrollback::Line::Line(int cols, const VTermScreenCell *cells, VTermState *vts) +Scrollback::Line::Line(int cols, const VTermScreenCell *cells) : m_cols(cols) , m_cells(std::make_unique(cols)) { memcpy(m_cells.get(), cells, cols * sizeof(cells[0])); - for (int i = 0; i < cols; ++i) { - vterm_state_convert_color_to_rgb(vts, &m_cells[i].fg); - vterm_state_convert_color_to_rgb(vts, &m_cells[i].bg); - } } const VTermScreenCell *Scrollback::Line::cell(int i) const @@ -31,9 +27,9 @@ Scrollback::Scrollback(size_t capacity) : m_capacity(capacity) {} -void Scrollback::emplace(int cols, const VTermScreenCell *cells, VTermState *vts) +void Scrollback::emplace(int cols, const VTermScreenCell *cells) { - m_deque.emplace_front(cols, cells, vts); + m_deque.emplace_front(cols, cells); while (m_deque.size() > m_capacity) { m_deque.pop_back(); } diff --git a/src/plugins/terminal/scrollback.h b/src/plugins/terminal/scrollback.h index 356b44fa535..9ca71eec615 100644 --- a/src/plugins/terminal/scrollback.h +++ b/src/plugins/terminal/scrollback.h @@ -21,7 +21,7 @@ public: class Line { public: - Line(int cols, const VTermScreenCell *cells, VTermState *vts); + Line(int cols, const VTermScreenCell *cells); Line(Line &&other) = default; Line() = delete; @@ -44,9 +44,7 @@ public: const Line &line(size_t index) const { return m_deque.at(index); }; const std::deque &lines() const { return m_deque; }; - void emplace(int cols, - const VTermScreenCell *cells, - VTermState *vts); + void emplace(int cols, const VTermScreenCell *cells); void popto(int cols, VTermScreenCell *cells); void clear(); diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index 128c05213d6..83749596c38 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -89,6 +89,18 @@ struct TerminalSurfacePrivate vterm_state_set_unrecognised_fallbacks(vts, &m_vtermStateFallbacks, this); vterm_state_set_bold_highbright(vts, true); + VTermColor fg; + VTermColor bg; + vterm_color_indexed(&fg, ColorIndex::Foreground); + vterm_color_indexed(&bg, ColorIndex::Background); + vterm_state_set_default_colors(vts, &fg, &bg); + + for (int i = 0; i < 16; ++i) { + VTermColor col; + vterm_color_indexed(&col, i); + vterm_state_set_palette_color(vts, i, &col); + } + vterm_screen_reset(m_vtermScreen, 1); } @@ -101,6 +113,25 @@ struct TerminalSurfacePrivate return QSize(cols, rows); } + std::variant toVariantColor(const VTermColor &color) + { + if (color.type & VTERM_COLOR_DEFAULT_BG) + return ColorIndex::Background; + else if (color.type & VTERM_COLOR_DEFAULT_FG) + return ColorIndex::Foreground; + else if (color.type & VTERM_COLOR_INDEXED) { + if (color.indexed.idx >= 16) { + VTermColor c = color; + vterm_state_convert_color_to_rgb(vterm_obtain_state(m_vterm.get()), &c); + return toQColor(c); + } + return color.indexed.idx; + } else if (color.type == VTERM_COLOR_RGB) + return toQColor(color); + else + return -1; + } + TerminalCell toCell(const VTermScreenCell &cell) { TerminalCell result; @@ -113,13 +144,8 @@ struct TerminalSurfacePrivate if (static_cast(cell.attrs.reverse)) std::swap(fg, bg); - const QColor cellBgColor = toQColor(*bg); - const QColor cellFgColor = toQColor(*fg); - - if (cellBgColor != m_defaultBgColor) - result.background = toQColor(*bg); - - result.foreground = cellFgColor; + result.backgroundColor = toVariantColor(*bg); + result.foregroundColor = toVariantColor(*fg); result.bold = cell.attrs.bold; result.strikeOut = cell.attrs.strike; @@ -151,26 +177,6 @@ struct TerminalSurfacePrivate return result; } - VTermColor defaultBgColor() const - { - VTermColor defaultBg; - if (!m_altscreen) { - VTermColor defaultFg; - vterm_state_get_default_colors(vterm_obtain_state(m_vterm.get()), - &defaultFg, - &defaultBg); - // We want to compare the cell bg against this later and cells don't - // set DEFAULT_BG - defaultBg.type = VTERM_COLOR_RGB; - return defaultBg; - } // This is a slightly better guess when in an altscreen - - VTermPos vtp{0, 0}; - static VTermScreenCell refCell{}; - vterm_screen_get_cell(m_vtermScreen, vtp, &refCell); - return refCell.bg; - } - // Callbacks from vterm void invalidate(VTermRect rect) { @@ -185,7 +191,7 @@ struct TerminalSurfacePrivate int sb_pushline(int cols, const VTermScreenCell *cells) { - m_scrollback->emplace(cols, cells, vterm_obtain_state(m_vterm.get())); + m_scrollback->emplace(cols, cells); emit q->fullSizeChanged(q->fullSize()); return 1; } @@ -284,8 +290,6 @@ struct TerminalSurfacePrivate static VTermScreenCell refCell{}; VTermPos vtp{y, x}; vterm_screen_get_cell(m_vtermScreen, vtp, &refCell); - vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.fg); - vterm_screen_convert_color_to_rgb(m_vtermScreen, &refCell.bg); return &refCell; } @@ -295,7 +299,6 @@ struct TerminalSurfacePrivate VTermScreenCallbacks m_vtermScreenCallbacks; VTermStateFallbacks m_vtermStateFallbacks; - QColor m_defaultBgColor; Cursor m_cursor; QString m_currentCommand; @@ -352,8 +355,14 @@ std::u32string::value_type TerminalSurface::fetchCharAt(int x, int y) const TerminalCell TerminalSurface::fetchCell(int x, int y) const { - static TerminalCell - emptyCell{1, {}, {}, false, {}, std::nullopt, QTextCharFormat::NoUnderline, false}; + static TerminalCell emptyCell{1, + {}, + {}, + false, + ColorIndex::Foreground, + ColorIndex::Background, + QTextCharFormat::NoUnderline, + false}; QTC_ASSERT(y >= 0, return emptyCell); QTC_ASSERT(y < fullSize().height() && x < fullSize().width(), return emptyCell); @@ -400,33 +409,6 @@ void TerminalSurface::flush() vterm_screen_flush_damage(d->m_vtermScreen); } -void TerminalSurface::setColors(QColor foreground, QColor background) -{ - VTermState *vts = vterm_obtain_state(d->m_vterm.get()); - - VTermColor fg; - VTermColor bg; - - vterm_color_rgb(&fg, foreground.red(), foreground.green(), foreground.blue()); - vterm_color_rgb(&bg, background.red(), background.green(), background.blue()); - - d->m_defaultBgColor = background; - - vterm_state_set_default_colors(vts, &fg, &bg); - vterm_screen_reset(d->m_vtermScreen, 1); -} - -void TerminalSurface::setAnsiColor(int index, QColor color) -{ - VTermState *vts = vterm_obtain_state(d->m_vterm.get()); - - VTermColor col; - vterm_color_rgb(&col, color.red(), color.green(), color.blue()); - vterm_state_set_palette_color(vts, index, &col); - - vterm_screen_reset(d->m_vtermScreen, 1); -} - void TerminalSurface::pasteFromClipboard(const QString &clipboardText) { if (clipboardText.isEmpty()) @@ -496,11 +478,6 @@ Cursor TerminalSurface::cursor() const return cursor; } -QColor TerminalSurface::defaultBgColor() const -{ - return toQColor(d->defaultBgColor()); -} - ShellIntegration *TerminalSurface::shellIntegration() const { return d->m_shellIntegration; diff --git a/src/plugins/terminal/terminalsurface.h b/src/plugins/terminal/terminalsurface.h index 04958582c27..01923fb538f 100644 --- a/src/plugins/terminal/terminalsurface.h +++ b/src/plugins/terminal/terminalsurface.h @@ -18,14 +18,16 @@ class Scrollback; struct TerminalSurfacePrivate; +enum ColorIndex { Foreground = 16, Background = 17 }; + struct TerminalCell { int width; QString text; bool bold{false}; bool italic{false}; - QColor foreground; - std::optional background; + std::variant foregroundColor; + std::variant backgroundColor; QTextCharFormat::UnderlineStyle underlineStyle{QTextCharFormat::NoUnderline}; bool strikeOut{false}; }; @@ -81,9 +83,6 @@ public: void dataFromPty(const QByteArray &data); void flush(); - void setColors(QColor foreground, QColor background); - void setAnsiColor(int index, QColor color); - void pasteFromClipboard(const QString &text); void sendKey(Qt::Key key); @@ -94,8 +93,6 @@ public: Cursor cursor() const; - QColor defaultBgColor() const; - ShellIntegration *shellIntegration() const; signals: diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index e9c86bec886..12d696c69e2 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -218,14 +218,8 @@ void TerminalWidget::setupColors() m_currentColors = newColors; - m_surface->setColors(TerminalSettings::instance().foregroundColor.value(), - TerminalSettings::instance().backgroundColor.value()); - - for (int i = 0; i < 16; ++i) { - m_surface->setAnsiColor(i, TerminalSettings::instance().colors[i].value()); - } - - clearContents(); + updateViewport(); + update(); } void TerminalWidget::setupActions() @@ -336,6 +330,18 @@ void TerminalWidget::configBlinkTimer() } } +QColor TerminalWidget::toQColor(std::variant color) const +{ + if (std::holds_alternative(color)) { + int idx = std::get(color); + if (idx >= 0 && idx < 18) + return m_currentColors[idx]; + + return m_currentColors[Internal::ColorIndex::Background]; + } + return std::get(color); +} + void TerminalWidget::setFont(const QFont &font) { m_font = font; @@ -747,8 +753,9 @@ void TerminalWidget::paintSelectionOrBackground(QPainter &p, if (isInSelection) p.fillRect(cellRect, TerminalSettings::instance().selectionColor.value()); - else if (cell.background) - p.fillRect(cellRect, *cell.background); + else if (!(std::holds_alternative(cell.backgroundColor) + && std::get(cell.backgroundColor) == 17)) + p.fillRect(cellRect, toQColor(cell.backgroundColor)); } int TerminalWidget::paintCell(QPainter &p, @@ -759,7 +766,7 @@ int TerminalWidget::paintCell(QPainter &p, { paintSelectionOrBackground(p, cell, cellRect, gridPos); - p.setPen(cell.foreground); + p.setPen(toQColor(cell.foregroundColor)); f.setBold(cell.bold); f.setItalic(cell.italic); @@ -909,12 +916,10 @@ void TerminalWidget::paintEvent(QPaintEvent *event) p.save(); - const QColor defaultBgColor = m_surface->defaultBgColor(); - if (paintLog().isDebugEnabled()) p.fillRect(event->rect(), QColor::fromRgb(rand() % 60, rand() % 60, rand() % 60)); else - p.fillRect(event->rect(), defaultBgColor); + p.fillRect(event->rect(), m_currentColors[Internal::ColorIndex::Background]); int scrollOffset = verticalScrollBar()->value(); int offset = -(scrollOffset * m_cellSize.height()); @@ -929,7 +934,8 @@ void TerminalWidget::paintEvent(QPaintEvent *event) p.restore(); - p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), topMargin()}}, defaultBgColor); + p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), topMargin()}}, + m_currentColors[Internal::ColorIndex::Background]); if (selectionLog().isDebugEnabled()) { if (m_selection) @@ -1295,8 +1301,7 @@ bool TerminalWidget::event(QEvent *event) if (event->type() == QEvent::Paint) { QPainter p(this); - p.fillRect(QRect(QPoint(0, 0), size()), - TerminalSettings::instance().backgroundColor.value()); + p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[Internal::ColorIndex::Background]); return true; } diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 34b95a2e2d2..d7aff0648b8 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -166,6 +166,8 @@ protected: void configBlinkTimer(); + QColor toQColor(std::variant color) const; + private: std::unique_ptr m_process; std::unique_ptr m_surface; From c0676540eea543f2dc73f8f229dfb9f177ed58f7 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 23 Mar 2023 09:35:45 +0100 Subject: [PATCH 0350/1447] Utils: Add header to be installed Referenced in filepath.h Change-Id: Ie7c8a270c64e2d2a5f979bbf8ad5990fb6ff1a8c Reviewed-by: Marcus Tillmanns --- src/libs/utils/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index ab55a0deecf..7277b7c8cf2 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -193,6 +193,7 @@ add_qtc_library(Utils utils_global.h utilstr.h utilsicons.cpp utilsicons.h + utiltypes.h variablechooser.cpp variablechooser.h winutils.cpp winutils.h wizard.cpp wizard.h From cd3c7e368d338b4bc3a1b10c0196cde64e370a1a Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 12:04:08 +0100 Subject: [PATCH 0351/1447] RemoteLinux: Clean up abstractremotelinuxdeploystep.h Change-Id: I14297c2f7ccff34dd2119c90eab8a9ee42800ba1 Reviewed-by: Marcus Tillmanns --- .../remotelinux/abstractremotelinuxdeploystep.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h index a0db68664ab..5b4eb8bbe92 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h @@ -8,21 +8,14 @@ #include #include -#include #include -namespace ProjectExplorer { -class DeployableFile; -class Kit; -class Target; -} +namespace ProjectExplorer { class DeployableFile; } namespace Utils::Tasking { class Group; } namespace RemoteLinux { -class CheckResult; - namespace Internal { class AbstractRemoteLinuxDeployStepPrivate; } class REMOTELINUX_EXPORT CheckResult @@ -43,8 +36,6 @@ private: class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployStep : public ProjectExplorer::BuildStep { - Q_OBJECT - public: explicit AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); ~AbstractRemoteLinuxDeployStep() override; From 75bdaf25d044750af44cb8cc491f53f4af7ac01f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 23 Mar 2023 11:43:23 +0100 Subject: [PATCH 0352/1447] Debugger: enable dependency action only if we can find depends Change-Id: I1f8c8d4108a1e3c6a03b93c9cf280c005806fc44 Reviewed-by: hjk --- src/plugins/debugger/moduleshandler.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 9ae6b068af8..6e7496bd37d 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -140,6 +140,12 @@ public: DebuggerEngine *engine; }; +static bool dependsCanBeFound() +{ + static bool dependsInPath = Environment::systemEnvironment().searchInPath("depends").isEmpty(); + return dependsInPath; +} + bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) { ModuleItem *item = itemForIndexAtLevel<1>(ev.sourceModelIndex()); @@ -163,11 +169,13 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) moduleNameValid && enabled && canReload, [this, modulePath] { engine->loadSymbols(modulePath); }); - // FIXME: Dependencies only available on Windows, when "depends" is installed. addAction(this, menu, Tr::tr("Show Dependencies of \"%1\"").arg(moduleName), Tr::tr("Show Dependencies"), - moduleNameValid && !moduleName.isEmpty() && HostOsInfo::isWindowsHost(), - [modulePath] { QtcProcess::startDetached({{"depends"}, {modulePath.toString()}}); }); + moduleNameValid && !modulePath.needsDevice() && modulePath.exists() + && dependsCanBeFound(), + [modulePath] { + QtcProcess::startDetached({{"depends"}, {modulePath.toString()}}); + }); addAction(this, menu, Tr::tr("Load Symbols for All Modules"), enabled && canLoadSymbols, From 1d9c96a9f456833c027e4220c19b7b9622b9d22d Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 22 Mar 2023 16:54:53 +0100 Subject: [PATCH 0353/1447] Terminal: Add enable setting Change-Id: I13cca8b2d4c55df7db29807c1252718e2819ea0b Reviewed-by: Cristian Adam --- src/libs/utils/qtcprocess.cpp | 2 +- src/libs/utils/terminalhooks.cpp | 79 ++++++++++++++++--- src/libs/utils/terminalhooks.h | 21 +++-- src/plugins/coreplugin/fileutils.cpp | 2 +- .../projectexplorer/projectexplorer.cpp | 12 ++- src/plugins/terminal/terminalplugin.cpp | 33 ++++++-- src/plugins/terminal/terminalsettings.cpp | 8 ++ src/plugins/terminal/terminalsettings.h | 3 +- src/plugins/terminal/terminalsettingspage.cpp | 3 + 9 files changed, 130 insertions(+), 33 deletions(-) diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 1583316832b..04276a610b9 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -732,7 +732,7 @@ public: if (m_setup.m_ptyData) return new PtyProcessImpl; if (m_setup.m_terminalMode != TerminalMode::Off) - return Terminal::Hooks::instance().createTerminalProcessInterfaceHook()(); + return Terminal::Hooks::instance().createTerminalProcessInterface(); const ProcessImpl impl = m_setup.m_processImpl == ProcessImpl::Default ? defaultProcessImpl() : m_setup.m_processImpl; diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index 6ee46b33616..6922f5c4304 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -8,6 +8,7 @@ #include "terminalcommand.h" #include "terminalinterface.h" +#include #include namespace Utils::Terminal { @@ -88,21 +89,65 @@ public: ExternalTerminalProcessImpl() { setStubCreator(new ProcessStubCreator(this)); } }; -struct HooksPrivate +class HooksPrivate { +public: HooksPrivate() - : m_openTerminalHook([](const OpenTerminalParameters ¶meters) { + : m_getTerminalCommandsForDevicesHook([] { return QList{}; }) + { + auto openTerminal = [](const OpenTerminalParameters ¶meters) { DeviceFileHooks::instance().openTerminal(parameters.workingDirectory.value_or( FilePath{}), parameters.environment.value_or(Environment{})); - }) - , m_createTerminalProcessInterfaceHook([] { return new ExternalTerminalProcessImpl(); }) - , m_getTerminalCommandsForDevicesHook([] { return QList{}; }) - {} + }; + auto createProcessInterface = []() { return new ExternalTerminalProcessImpl(); }; + + addCallbackSet("External", {openTerminal, createProcessInterface}); + } + + void addCallbackSet(const QString &name, const Hooks::CallbackSet &callbackSet) + { + QMutexLocker lk(&m_mutex); + m_callbackSets.push_back(qMakePair(name, callbackSet)); + + m_createTerminalProcessInterface + = m_callbackSets.back().second.createTerminalProcessInterface; + m_openTerminal = m_callbackSets.back().second.openTerminal; + } + + void removeCallbackSet(const QString &name) + { + if (name == "External") + return; + + QMutexLocker lk(&m_mutex); + m_callbackSets.removeIf([name](const auto &pair) { return pair.first == name; }); + + m_createTerminalProcessInterface + = m_callbackSets.back().second.createTerminalProcessInterface; + m_openTerminal = m_callbackSets.back().second.openTerminal; + } + + Hooks::CreateTerminalProcessInterface createTerminalProcessInterface() + { + QMutexLocker lk(&m_mutex); + return m_createTerminalProcessInterface; + } + + Hooks::OpenTerminal openTerminal() + { + QMutexLocker lk(&m_mutex); + return m_openTerminal; + } - Hooks::OpenTerminalHook m_openTerminalHook; - Hooks::CreateTerminalProcessInterfaceHook m_createTerminalProcessInterfaceHook; Hooks::GetTerminalCommandsForDevicesHook m_getTerminalCommandsForDevicesHook; + +private: + Hooks::OpenTerminal m_openTerminal; + Hooks::CreateTerminalProcessInterface m_createTerminalProcessInterface; + + QMutex m_mutex; + QList> m_callbackSets; }; Hooks &Hooks::instance() @@ -117,14 +162,14 @@ Hooks::Hooks() Hooks::~Hooks() = default; -Hooks::OpenTerminalHook &Hooks::openTerminalHook() +void Hooks::openTerminal(const OpenTerminalParameters ¶meters) const { - return d->m_openTerminalHook; + d->openTerminal()(parameters); } -Hooks::CreateTerminalProcessInterfaceHook &Hooks::createTerminalProcessInterfaceHook() +ProcessInterface *Hooks::createTerminalProcessInterface() const { - return d->m_createTerminalProcessInterfaceHook; + return d->createTerminalProcessInterface()(); } Hooks::GetTerminalCommandsForDevicesHook &Hooks::getTerminalCommandsForDevicesHook() @@ -132,4 +177,14 @@ Hooks::GetTerminalCommandsForDevicesHook &Hooks::getTerminalCommandsForDevicesHo return d->m_getTerminalCommandsForDevicesHook; } +void Hooks::addCallbackSet(const QString &name, const CallbackSet &callbackSet) +{ + d->addCallbackSet(name, callbackSet); +} + +void Hooks::removeCallbackSet(const QString &name) +{ + d->removeCallbackSet(name); +} + } // namespace Utils::Terminal diff --git a/src/libs/utils/terminalhooks.h b/src/libs/utils/terminalhooks.h index 2da470d1711..5a614400f4f 100644 --- a/src/libs/utils/terminalhooks.h +++ b/src/libs/utils/terminalhooks.h @@ -37,7 +37,7 @@ private: }; namespace Terminal { -struct HooksPrivate; +class HooksPrivate; enum class ExitBehavior { Close, Restart, Keep }; @@ -61,18 +61,29 @@ QTCREATOR_UTILS_EXPORT FilePath defaultShellForDevice(const FilePath &deviceRoot class QTCREATOR_UTILS_EXPORT Hooks { public: - using OpenTerminalHook = Hook; - using CreateTerminalProcessInterfaceHook = Hook; + using OpenTerminal = std::function; + using CreateTerminalProcessInterface = std::function; + + struct CallbackSet + { + OpenTerminal openTerminal; + CreateTerminalProcessInterface createTerminalProcessInterface; + }; + using GetTerminalCommandsForDevicesHook = Hook>; public: static Hooks &instance(); ~Hooks(); - OpenTerminalHook &openTerminalHook(); - CreateTerminalProcessInterfaceHook &createTerminalProcessInterfaceHook(); GetTerminalCommandsForDevicesHook &getTerminalCommandsForDevicesHook(); + void openTerminal(const OpenTerminalParameters ¶meters) const; + ProcessInterface *createTerminalProcessInterface() const; + + void addCallbackSet(const QString &name, const CallbackSet &callbackSet); + void removeCallbackSet(const QString &name); + private: Hooks(); std::unique_ptr d; diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 929ebfe61d3..a48cd34da70 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -106,7 +106,7 @@ void FileUtils::showInFileSystemView(const FilePath &path) void FileUtils::openTerminal(const FilePath &path, const Environment &env) { - Terminal::Hooks::instance().openTerminalHook()({std::nullopt, path, env}); + Terminal::Hooks::instance().openTerminal({std::nullopt, path, env}); } QString FileUtils::msgFindInDirectory() diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 25aae3385c2..6956d7862a3 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3818,7 +3818,7 @@ void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env BuildConfiguration *bc = activeBuildConfiguration(ProjectTree::projectForNode(currentNode)); if (!bc) { - Terminal::Hooks::instance().openTerminalHook()({{}, currentNode->directory(), environment}); + Terminal::Hooks::instance().openTerminal({{}, currentNode->directory(), environment}); return; } @@ -3835,10 +3835,9 @@ void ProjectExplorerPluginPrivate::openTerminalHere(const EnvironmentGetter &env const FilePath shell = Terminal::defaultShellForDevice(buildDevice->rootPath()); if (!shell.isEmpty() && buildDevice->rootPath().needsDevice()) { - Terminal::Hooks::instance().openTerminalHook()( - {CommandLine{shell, {}}, workingDir, environment}); + Terminal::Hooks::instance().openTerminal({CommandLine{shell, {}}, workingDir, environment}); } else { - Terminal::Hooks::instance().openTerminalHook()({std::nullopt, workingDir, environment}); + Terminal::Hooks::instance().openTerminal({std::nullopt, workingDir, environment}); } } @@ -3870,11 +3869,10 @@ void ProjectExplorerPluginPrivate::openTerminalHereWithRunEnv() const FilePath shell = Terminal::defaultShellForDevice(device->rootPath()); if (!shell.isEmpty() && device->rootPath().needsDevice()) { - Terminal::Hooks::instance().openTerminalHook()( + Terminal::Hooks::instance().openTerminal( {CommandLine{shell, {}}, workingDir, runnable.environment}); } else { - Terminal::Hooks::instance().openTerminalHook()( - {std::nullopt, workingDir, runnable.environment}); + Terminal::Hooks::instance().openTerminal({std::nullopt, workingDir, runnable.environment}); } } diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp index a3258fcaf0e..409030acd12 100644 --- a/src/plugins/terminal/terminalplugin.cpp +++ b/src/plugins/terminal/terminalplugin.cpp @@ -43,13 +43,34 @@ void TerminalPlugin::extensionsInitialized() m_terminalPane = new TerminalPane(); ExtensionSystem::PluginManager::instance()->addObject(m_terminalPane); - Utils::Terminal::Hooks::instance().openTerminalHook().set( - [this](const Utils::Terminal::OpenTerminalParameters &p) { - m_terminalPane->openTerminal(p); - }); + auto enable = [this] { + Utils::Terminal::Hooks::instance() + .addCallbackSet("Internal", + {[this](const Utils::Terminal::OpenTerminalParameters &p) { + m_terminalPane->openTerminal(p); + }, + [this] { return new TerminalProcessImpl(m_terminalPane); }}); + }; - Utils::Terminal::Hooks::instance().createTerminalProcessInterfaceHook().set( - [this] { return new TerminalProcessImpl(m_terminalPane); }); + auto disable = [] { Utils::Terminal::Hooks::instance().removeCallbackSet("Internal"); }; + + static bool isEnabled = false; + auto settingsChanged = [enable, disable] { + if (isEnabled != TerminalSettings::instance().enableTerminal.value()) { + isEnabled = TerminalSettings::instance().enableTerminal.value(); + if (isEnabled) + enable(); + else + disable(); + } + }; + + QObject::connect(&TerminalSettings::instance(), + &Utils::AspectContainer::applied, + this, + settingsChanged); + + settingsChanged(); } } // namespace Internal diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 32d1ff5097e..b43d964320b 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -64,6 +64,13 @@ TerminalSettings::TerminalSettings() setAutoApply(false); setSettingsGroup("Terminal"); + enableTerminal.setSettingsKey("EnableTerminal"); + enableTerminal.setLabelText(Tr::tr("Use internal Terminal")); + enableTerminal.setToolTip( + Tr::tr("If enabled, use the internal terminal when \"Run In Terminal\" is " + "enabled and for \"Open Terminal here\".")); + enableTerminal.setDefaultValue(true); + font.setSettingsKey("FontFamily"); font.setLabelText(Tr::tr("Family:")); font.setHistoryCompleter("Terminal.Fonts.History"); @@ -121,6 +128,7 @@ TerminalSettings::TerminalSettings() registerAspect(&fontSize); registerAspect(&shell); registerAspect(&allowBlinkingCursor); + registerAspect(&enableTerminal); } } // namespace Terminal diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index de5f0a32428..c793bd123a3 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -13,13 +13,14 @@ public: static TerminalSettings &instance(); + Utils::BoolAspect enableTerminal; + Utils::StringAspect font; Utils::IntegerAspect fontSize; Utils::StringAspect shell; Utils::ColorAspect foregroundColor; Utils::ColorAspect backgroundColor; - Utils::ColorAspect selectionColor; Utils::ColorAspect colors[16]; diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index bf73cddd0f4..9f0544bea37 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -47,6 +47,9 @@ QWidget *TerminalSettingsPage::widget() // clang-format off Column { + Row { + settings.enableTerminal, st, + }, Group { title(Tr::tr("Font")), Row { From f00a4ef46b01e47d29c917e83859a886128fbc60 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 21 Mar 2023 16:11:08 +0100 Subject: [PATCH 0354/1447] Terminal: Import color schemes Change-Id: I86c7ccdb28b81eff9d9519c40321a3b3890ef73a Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalsettingspage.cpp | 336 +++++++++++++++++- 1 file changed, 335 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index 9f0544bea37..7eabca19b06 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -8,10 +8,21 @@ #include +#include +#include +#include +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include using namespace Utils; @@ -29,6 +40,286 @@ TerminalSettingsPage::TerminalSettingsPage() void TerminalSettingsPage::init() {} +static expected_str loadXdefaults(const FilePath &path) +{ + const expected_str readResult = path.fileContents(); + if (!readResult) + return make_unexpected(readResult.error()); + + QRegularExpression re(R"(.*\*(color[0-9]{1,2}|foreground|background):\s*(#[0-9a-f]{6}))"); + + for (const QByteArray &line : readResult->split('\n')) { + if (line.trimmed().startsWith('!')) + continue; + + const auto match = re.match(QString::fromUtf8(line)); + if (match.hasMatch()) { + const QString colorName = match.captured(1); + const QColor color(match.captured(2)); + if (colorName == "foreground") { + TerminalSettings::instance().foregroundColor.setVolatileValue(color); + } else if (colorName == "background") { + TerminalSettings::instance().backgroundColor.setVolatileValue(color); + } else { + const int colorIndex = colorName.mid(5).toInt(); + if (colorIndex >= 0 && colorIndex < 16) + TerminalSettings::instance().colors[colorIndex].setVolatileValue(color); + } + } + } + + return {}; +} + +static expected_str loadItermColors(const FilePath &path) +{ + QFile f(path.toFSPathString()); + const bool opened = f.open(QIODevice::ReadOnly); + if (!opened) + return make_unexpected(Tr::tr("Failed to open file")); + + QXmlStreamReader reader(&f); + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"plist") { + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"dict") { + QString colorName; + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"key") { + colorName = reader.readElementText(); + } else if (reader.name() == u"dict") { + QColor color; + int component; + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"key") { + const auto &text = reader.readElementText(); + if (text == u"Red Component") + component = 0; + else if (text == u"Green Component") + component = 1; + else if (text == u"Blue Component") + component = 2; + else if (text == u"Alpha Component") + component = 3; + } else if (reader.name() == u"real") { + // clang-format off + switch (component) { + case 0: color.setRedF(reader.readElementText().toDouble()); break; + case 1: color.setGreenF(reader.readElementText().toDouble()); break; + case 2: color.setBlueF(reader.readElementText().toDouble()); break; + case 3: color.setAlphaF(reader.readElementText().toDouble()); break; + } + // clang-format on + } else { + reader.skipCurrentElement(); + } + } + + if (colorName.startsWith("Ansi")) { + const auto c = colorName.mid(5, 2); + const int colorIndex = c.toInt(); + if (colorIndex >= 0 && colorIndex < 16) + TerminalSettings::instance().colors[colorIndex].setVolatileValue( + color); + } else if (colorName == "Foreground Color") { + TerminalSettings::instance().foregroundColor.setVolatileValue(color); + } else if (colorName == "Background Color") { + TerminalSettings::instance().backgroundColor.setVolatileValue(color); + } else if (colorName == "Selection Color") { + TerminalSettings::instance().selectionColor.setVolatileValue(color); + } + } + } + } + } + break; + } + } + if (reader.hasError()) + return make_unexpected(reader.errorString()); + + return {}; +} + +static expected_str loadVsCodeColors(const FilePath &path) +{ + const expected_str readResult = path.fileContents(); + if (!readResult) + return make_unexpected(readResult.error()); + + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(*readResult, &error); + if (error.error != QJsonParseError::NoError) + return make_unexpected(Tr::tr("JSON parsing error: \"%1\", at offset: %2") + .arg(error.errorString()) + .arg(error.offset)); + + const QJsonObject root = doc.object(); + const auto itColors = root.find("colors"); + if (itColors == root.end()) + return make_unexpected(Tr::tr("No colors found")); + + const QJsonObject colors = itColors->toObject(); + + // clang-format off + const QList> colorKeys = { + qMakePair(u"editor.background", &TerminalSettings::instance().backgroundColor), + qMakePair(u"terminal.foreground", &TerminalSettings::instance().foregroundColor), + qMakePair(u"terminal.selectionBackground", &TerminalSettings::instance().selectionColor), + + qMakePair(u"terminal.ansiBlack", &TerminalSettings::instance().colors[0]), + qMakePair(u"terminal.ansiBrightBlack", &TerminalSettings::instance().colors[8]), + + qMakePair(u"terminal.ansiRed", &TerminalSettings::instance().colors[1]), + qMakePair(u"terminal.ansiBrightRed", &TerminalSettings::instance().colors[9]), + + qMakePair(u"terminal.ansiGreen", &TerminalSettings::instance().colors[2]), + qMakePair(u"terminal.ansiBrightGreen", &TerminalSettings::instance().colors[10]), + + qMakePair(u"terminal.ansiYellow", &TerminalSettings::instance().colors[3]), + qMakePair(u"terminal.ansiBrightYellow", &TerminalSettings::instance().colors[11]), + + qMakePair(u"terminal.ansiBlue", &TerminalSettings::instance().colors[4]), + qMakePair(u"terminal.ansiBrightBlue", &TerminalSettings::instance().colors[12]), + + qMakePair(u"terminal.ansiMagenta", &TerminalSettings::instance().colors[5]), + qMakePair(u"terminal.ansiBrightMagenta", &TerminalSettings::instance().colors[13]), + + qMakePair(u"terminal.ansiCyan", &TerminalSettings::instance().colors[6]), + qMakePair(u"terminal.ansiBrightCyan", &TerminalSettings::instance().colors[14]), + + qMakePair(u"terminal.ansiWhite", &TerminalSettings::instance().colors[7]), + qMakePair(u"terminal.ansiBrightWhite", &TerminalSettings::instance().colors[15]) + }; + // clang-format on + + for (const auto &pair : colorKeys) { + const auto it = colors.find(pair.first); + if (it != colors.end()) { + const QString colorString = it->toString(); + if (colorString.startsWith("#")) { + QColor color(colorString.mid(0, 7)); + if (colorString.size() > 7) { + int alpha = colorString.mid(7).toInt(nullptr, 16); + color.setAlpha(alpha); + } + if (color.isValid()) + pair.second->setVolatileValue(color); + } + } + } + + return {}; +} + +static expected_str loadKonsoleColorScheme(const FilePath &path) +{ + QSettings settings(path.toFSPathString(), QSettings::IniFormat); + + auto parseColor = [](const QStringList &parts) -> expected_str { + if (parts.size() != 3 && parts.size() != 4) + return make_unexpected(Tr::tr("Invalid color format")); + int alpha = parts.size() == 4 ? parts[3].toInt() : 255; + return QColor(parts[0].toInt(), parts[1].toInt(), parts[2].toInt(), alpha); + }; + + // clang-format off + const QList> colorKeys = { + qMakePair(QLatin1String("Background/Color"), &TerminalSettings::instance().backgroundColor), + qMakePair(QLatin1String("Foreground/Color"), &TerminalSettings::instance().foregroundColor), + + qMakePair(QLatin1String("Color0/Color"), &TerminalSettings::instance().colors[0]), + qMakePair(QLatin1String("Color0Intense/Color"), &TerminalSettings::instance().colors[8]), + + qMakePair(QLatin1String("Color1/Color"), &TerminalSettings::instance().colors[1]), + qMakePair(QLatin1String("Color1Intense/Color"), &TerminalSettings::instance().colors[9]), + + qMakePair(QLatin1String("Color2/Color"), &TerminalSettings::instance().colors[2]), + qMakePair(QLatin1String("Color2Intense/Color"), &TerminalSettings::instance().colors[10]), + + qMakePair(QLatin1String("Color3/Color"), &TerminalSettings::instance().colors[3]), + qMakePair(QLatin1String("Color3Intense/Color"), &TerminalSettings::instance().colors[11]), + + qMakePair(QLatin1String("Color4/Color"), &TerminalSettings::instance().colors[4]), + qMakePair(QLatin1String("Color4Intense/Color"), &TerminalSettings::instance().colors[12]), + + qMakePair(QLatin1String("Color5/Color"), &TerminalSettings::instance().colors[5]), + qMakePair(QLatin1String("Color5Intense/Color"), &TerminalSettings::instance().colors[13]), + + qMakePair(QLatin1String("Color6/Color"), &TerminalSettings::instance().colors[6]), + qMakePair(QLatin1String("Color6Intense/Color"), &TerminalSettings::instance().colors[14]), + + qMakePair(QLatin1String("Color7/Color"), &TerminalSettings::instance().colors[7]), + qMakePair(QLatin1String("Color7Intense/Color"), &TerminalSettings::instance().colors[15]) + }; + // clang-format on + + for (const auto &colorKey : colorKeys) { + if (settings.contains(colorKey.first)) { + const auto color = parseColor(settings.value(colorKey.first).toStringList()); + if (!color) + return make_unexpected(color.error()); + + colorKey.second->setVolatileValue(*color); + } + } + + return {}; +} + +static expected_str loadXFCE4ColorScheme(const FilePath &path) +{ + expected_str arr = path.fileContents(); + if (!arr) + return make_unexpected(arr.error()); + + arr->replace(';', ','); + + QTemporaryFile f; + f.open(); + f.write(*arr); + f.close(); + + QSettings settings(f.fileName(), QSettings::IniFormat); + + // clang-format off + const QList> colorKeys = { + qMakePair(QLatin1String("Scheme/ColorBackground"), &TerminalSettings::instance().backgroundColor), + qMakePair(QLatin1String("Scheme/ColorForeground"), &TerminalSettings::instance().foregroundColor), + }; + // clang-format on + + for (const auto &colorKey : colorKeys) { + if (settings.contains(colorKey.first)) { + colorKey.second->setVolatileValue(QColor(settings.value(colorKey.first).toString())); + } + } + + QStringList colors = settings.value(QLatin1String("Scheme/ColorPalette")).toStringList(); + int i = 0; + for (const auto &color : colors) { + TerminalSettings::instance().colors[i++].setVolatileValue(QColor(color)); + } + + return {}; +} + +static expected_str loadColorScheme(const FilePath &path) +{ + if (path.endsWith("Xdefaults")) + return loadXdefaults(path); + else if (path.suffix() == "itermcolors") + return loadItermColors(path); + else if (path.suffix() == "json") + return loadVsCodeColors(path); + else if (path.suffix() == "colorscheme") + return loadKonsoleColorScheme(path); + else if (path.suffix() == "theme" || path.completeSuffix() == "theme.txt") + return loadXFCE4ColorScheme(path); + + return make_unexpected(Tr::tr("Unknown color scheme format")); +} + QWidget *TerminalSettingsPage::widget() { QWidget *widget = new QWidget; @@ -45,6 +336,33 @@ QWidget *TerminalSettingsPage::widget() TerminalSettings &settings = TerminalSettings::instance(); + QPushButton *loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); + + connect(loadThemeButton, &QPushButton::clicked, this, [widget] { + const FilePath path = FileUtils::getOpenFilePath( + widget, + "Open Theme", + {}, + "All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;" + "Xdefaults (.Xdefaults Xdefaults);;" + "iTerm Color Schemes(*.itermcolors);;" + "VS Code Color Schemes(*.json);;" + "Konsole Color Schemes(*.colorscheme);;" + "XFCE4 Terminal Color Schemes(*.theme *.theme.txt);;" + "All files (*)", + nullptr, + {}, + true, + false); + + if (path.isEmpty()) + return; + + const expected_str result = loadColorScheme(path); + if (!result) + QMessageBox::warning(widget, Tr::tr("Error"), result.error()); + }); + // clang-format off Column { Row { @@ -83,7 +401,10 @@ QWidget *TerminalSettingsPage::widget() settings.colors[12], settings.colors[13], settings.colors[14], settings.colors[15] }, - } + Row { + loadThemeButton, st, + } + }, }, Row { settings.shell, @@ -92,6 +413,19 @@ QWidget *TerminalSettingsPage::widget() }.attachTo(widget); // clang-format on + DropSupport *dropSupport = new DropSupport(widget); + connect(dropSupport, + &DropSupport::filesDropped, + this, + [widget](const QList &files) { + if (files.size() != 1) + return; + + const expected_str result = loadColorScheme(files.at(0).filePath); + if (!result) + QMessageBox::warning(widget, Tr::tr("Error"), result.error()); + }); + return widget; } From a485f18a9415815ee7a0e2d435bdf08251bb8c4c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 11:04:54 +0100 Subject: [PATCH 0355/1447] Terminal: Make shortcuts configurable Fixes: QTCREATORBUG-28940 Change-Id: I1afe114c357243a8fa4f101b5eac80a766dc87b9 Reviewed-by: Cristian Adam --- src/plugins/terminal/CMakeLists.txt | 1 + src/plugins/terminal/terminalcommands.cpp | 132 ++++++++++++++++++++++ src/plugins/terminal/terminalcommands.h | 59 ++++++++++ src/plugins/terminal/terminalpane.cpp | 99 +++++++++------- src/plugins/terminal/terminalpane.h | 35 +++--- src/plugins/terminal/terminalwidget.cpp | 102 +++++------------ src/plugins/terminal/terminalwidget.h | 20 +--- 7 files changed, 298 insertions(+), 150 deletions(-) create mode 100644 src/plugins/terminal/terminalcommands.cpp create mode 100644 src/plugins/terminal/terminalcommands.h diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index 1250455378a..067cab8d1cd 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -10,6 +10,7 @@ add_qtc_plugin(Terminal shellintegration.cpp shellintegration.h shellmodel.cpp shellmodel.h terminal.qrc + terminalcommands.cpp terminalcommands.h terminalpane.cpp terminalpane.h terminalplugin.cpp terminalplugin.h terminalprocessimpl.cpp terminalprocessimpl.h diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp new file mode 100644 index 00000000000..9f177720b3e --- /dev/null +++ b/src/plugins/terminal/terminalcommands.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "terminalcommands.h" + +#include +#include + +#include + +//#include + +using namespace Core; +using namespace Utils; + +namespace Terminal { + +constexpr char COPY[] = "Terminal.Copy"; +constexpr char PASTE[] = "Terminal.Paste"; +constexpr char CLEARSELECTION[] = "Terminal.ClearSelection"; + +constexpr char NEWTERMINAL[] = "Terminal.NewTerminal"; +constexpr char CLOSETERMINAL[] = "Terminal.CloseTerminal"; +constexpr char NEXTTERMINAL[] = "Terminal.NextTerminal"; +constexpr char PREVTERMINAL[] = "Terminal.PrevTerminal"; +constexpr char MINMAX[] = "Terminal.MinMax"; + +TerminalCommands &TerminalCommands::instance() +{ + static TerminalCommands instance; + return instance; +} + +TerminalCommands::TerminalCommands() {} + +void TerminalCommands::init(const Core::Context &context) +{ + initWidgetActions(context); + initPaneActions(context); + initGlobalCommands(); +} + +void TerminalCommands::initWidgetActions(const Core::Context &context) +{ + Command *command = ActionManager::instance()->registerAction(&m_widgetActions.copy, + COPY, + context); + command->setDefaultKeySequences( + {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") + : QLatin1String("Ctrl+Shift+C")), + QKeySequence(Qt::Key_Return)}); + m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_widgetActions.paste, PASTE, context); + command->setDefaultKeySequence(QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V"))); + m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_widgetActions.clearSelection, + CLEARSELECTION); + command->setDefaultKeySequence(QKeySequence("Esc")); + m_commands.push_back(command); +} + +void TerminalCommands::initPaneActions(const Core::Context &context) +{ + Command *command = ActionManager::instance()->registerAction(&m_paneActions.newTerminal, + NEWTERMINAL, + context); + command->setDefaultKeySequence(QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") : QLatin1String("Ctrl+Shift+T"))); + m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_paneActions.closeTerminal, + CLOSETERMINAL, + context); + command->setDefaultKeySequence(QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+W") : QLatin1String("Ctrl+Shift+W"))); + m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_paneActions.nextTerminal, + NEXTTERMINAL, + context); + command->setDefaultKeySequences( + {QKeySequence("ALT+TAB"), + QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[") + : QLatin1String("Ctrl+PgUp"))}); + m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_paneActions.prevTerminal, + PREVTERMINAL, + context); + command->setDefaultKeySequences( + {QKeySequence("ALT+SHIFT+TAB"), + QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+]") + : QLatin1String("Ctrl+PgDown"))}); + m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_paneActions.minMax, MINMAX, context); + command->setDefaultKeySequence(QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return") : QLatin1String("Alt+Return"))); + m_commands.push_back(command); +} + +void TerminalCommands::initGlobalCommands() +{ + // Global commands we still want to allow + m_commands.push_back(ActionManager::command(Constants::ZOOM_IN)); + m_commands.push_back(ActionManager::command(Constants::ZOOM_OUT)); + m_commands.push_back(ActionManager::command(Constants::EXIT)); + m_commands.push_back(ActionManager::command(Constants::OPTIONS)); +} + +bool TerminalCommands::triggerAction(QKeyEvent *event) +{ + for (const auto &command : TerminalCommands::instance().m_commands) { + if (!command->action()->isEnabled()) + continue; + + for (const auto &shortcut : command->keySequences()) { + const auto result = shortcut.matches(QKeySequence(event->keyCombination())); + if (result == QKeySequence::ExactMatch) { + command->action()->trigger(); + return true; + } + } + } + + return false; +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h new file mode 100644 index 00000000000..11392f2dcfc --- /dev/null +++ b/src/plugins/terminal/terminalcommands.h @@ -0,0 +1,59 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "terminaltr.h" + +#include +#include + +namespace Core { +class Command; +class Context; +} + +namespace Terminal { + +struct WidgetActions +{ + QAction copy{Tr::tr("Copy")}; + QAction paste{Tr::tr("Paste")}; + QAction clearSelection{Tr::tr("Clear Selection")}; +}; + +struct PaneActions +{ + QAction newTerminal{Tr::tr("New Terminal")}; + QAction closeTerminal{Tr::tr("Close Terminal")}; + QAction nextTerminal{Tr::tr("Next Terminal")}; + QAction prevTerminal{Tr::tr("Previous Terminal")}; + QAction minMax{Tr::tr("Minimize/Maximize Terminal")}; +}; + +class TerminalCommands +{ +public: + TerminalCommands(); + + void init(const Core::Context &context); + static TerminalCommands &instance(); + static WidgetActions &widgetActions() { return instance().m_widgetActions; } + static PaneActions &paneActions() { return instance().m_paneActions; } + + static QList shortcutsFor(QAction *action); + + static bool triggerAction(QKeyEvent *event); + +protected: + void initWidgetActions(const Core::Context &context); + void initPaneActions(const Core::Context &context); + void initGlobalCommands(); + +private: + WidgetActions m_widgetActions; + PaneActions m_paneActions; + QList m_commands; +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index c2467ec71d4..cdf14c55e37 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -4,9 +4,9 @@ #include "terminalpane.h" #include "shellmodel.h" +#include "terminalcommands.h" #include "terminaltr.h" #include "terminalwidget.h" -#include "utils/terminalhooks.h" #include #include @@ -16,10 +16,12 @@ #include #include +#include #include #include #include +#include namespace Terminal { @@ -28,19 +30,33 @@ using namespace Utils::Terminal; TerminalPane::TerminalPane(QObject *parent) : Core::IOutputPane(parent) + , m_tabWidget(new QTabWidget) { - Core::Context context("Terminal.Window"); + setupContext("Terminal.Pane", m_tabWidget); + TerminalCommands::instance().init(Core::Context("Terminal.Pane")); - m_newTerminal.setIcon(Icons::PLUS_TOOLBAR.icon()); - m_newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); + connect(this, &IOutputPane::zoomInRequested, this, [this] { + if (currentTerminal()) + currentTerminal()->zoomIn(); + }); + connect(this, &IOutputPane::zoomOutRequested, this, [this] { + if (currentTerminal()) + currentTerminal()->zoomOut(); + }); - connect(&m_newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); + QAction &newTerminal = TerminalCommands::instance().paneActions().newTerminal; + QAction &closeTerminal = TerminalCommands::instance().paneActions().closeTerminal; - m_closeTerminal.setIcon(Icons::CLOSE_TOOLBAR.icon()); - m_closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); - m_closeTerminal.setEnabled(false); + newTerminal.setIcon(Icons::PLUS_TOOLBAR.icon()); + newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); - connect(&m_closeTerminal, &QAction::triggered, this, [this] { + connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); + + closeTerminal.setIcon(Icons::CLOSE_TOOLBAR.icon()); + closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); + closeTerminal.setEnabled(false); + + connect(&closeTerminal, &QAction::triggered, this, [this] { removeTab(m_tabWidget->currentIndex()); }); @@ -68,40 +84,40 @@ TerminalPane::TerminalPane(QObject *parent) addItems(shellModel->remote()); }); - m_newTerminal.setMenu(shellMenu); - m_newTerminal.setShortcut(QKeySequence( - HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") : QLatin1String("Ctrl+Shift+T"))); + newTerminal.setMenu(shellMenu); - m_newTerminalButton->setDefaultAction(&m_newTerminal); + m_newTerminalButton->setDefaultAction(&newTerminal); m_closeTerminalButton = new QToolButton(); - m_closeTerminalButton->setDefaultAction(&m_closeTerminal); + m_closeTerminalButton->setDefaultAction(&closeTerminal); - m_nextTerminal.setShortcut(QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[") - : QLatin1String("Ctrl+PgUp"))); - m_prevTerminal.setShortcut(QKeySequence(HostOsInfo::isMacHost() - ? QLatin1String("Ctrl+Shift+]") - : QLatin1String("Ctrl+PgDown"))); + connect(&TerminalCommands::instance().paneActions().nextTerminal, + &QAction::triggered, + this, + [this] { + if (canNavigate()) + goToNext(); + }); + connect(&TerminalCommands::instance().paneActions().prevTerminal, + &QAction::triggered, + this, + [this] { + if (canPrevious()) + goToPrev(); + }); - connect(&m_nextTerminal, &QAction::triggered, this, [this] { - if (canNavigate()) - goToNext(); - }); - connect(&m_prevTerminal, &QAction::triggered, this, [this] { - if (canPrevious()) - goToPrev(); - }); - - m_minMaxAction.setShortcut(QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return") - : QLatin1String("Alt+Return"))); - - connect(&m_minMaxAction, &QAction::triggered, this, []() { + connect(&TerminalCommands::instance().paneActions().minMax, &QAction::triggered, this, []() { Core::Command *minMaxCommand = Core::ActionManager::command("Coreplugin.OutputPane.minmax"); if (minMaxCommand) emit minMaxCommand->action()->triggered(); }); } +TerminalPane::~TerminalPane() +{ + delete m_tabWidget; +} + static std::optional startupProjectDirectory() { ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); @@ -132,7 +148,7 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) m_tabWidget->currentWidget()->setFocus(); - m_closeTerminal.setEnabled(m_tabWidget->count() > 1); + TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); emit navigateStateUpdate(); } @@ -142,7 +158,7 @@ void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminal, title)); setupTerminalWidget(terminal); - m_closeTerminal.setEnabled(m_tabWidget->count() > 1); + TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); emit navigateStateUpdate(); } @@ -161,9 +177,8 @@ TerminalWidget *TerminalPane::stoppedTerminalWithId(const Id &identifier) const QWidget *TerminalPane::outputWidget(QWidget *parent) { - if (!m_tabWidget) { - m_tabWidget = new QTabWidget(parent); - + if (!m_widgetInitialized) { + m_widgetInitialized = true; m_tabWidget->setTabBarAutoHide(true); m_tabWidget->setDocumentMode(true); m_tabWidget->setTabsClosable(true); @@ -192,7 +207,7 @@ void TerminalPane::removeTab(int index) if (m_tabWidget->count() > 1) delete m_tabWidget->widget(index); - m_closeTerminal.setEnabled(m_tabWidget->count() > 1); + TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); emit navigateStateUpdate(); } @@ -229,13 +244,15 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) if (!terminal->shellName().isEmpty()) setTabText(terminal); - - terminal->addActions({&m_newTerminal, &m_nextTerminal, &m_prevTerminal, &m_minMaxAction}); } QList TerminalPane::toolBarWidgets() const { - return {m_newTerminalButton, m_closeTerminalButton}; + QList widgets = IOutputPane::toolBarWidgets(); + widgets.prepend(m_newTerminalButton); + widgets.prepend(m_closeTerminalButton); + + return widgets; } QString TerminalPane::displayName() const diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index ac3bed9a96c..fd902f9176a 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -20,21 +20,22 @@ class TerminalPane : public Core::IOutputPane Q_OBJECT public: TerminalPane(QObject *parent = nullptr); + ~TerminalPane() override; - virtual QWidget *outputWidget(QWidget *parent); - virtual QList toolBarWidgets() const; - virtual QString displayName() const; - virtual int priorityInStatusBar() const; - virtual void clearContents(); - virtual void visibilityChanged(bool visible); - virtual void setFocus(); - virtual bool hasFocus() const; - virtual bool canFocus() const; - virtual bool canNavigate() const; - virtual bool canNext() const; - virtual bool canPrevious() const; - virtual void goToNext(); - virtual void goToPrev(); + QWidget *outputWidget(QWidget *parent) override; + QList toolBarWidgets() const override; + QString displayName() const override; + int priorityInStatusBar() const override; + void clearContents() override; + void visibilityChanged(bool visible) override; + void setFocus() override; + bool hasFocus() const override; + bool canFocus() const override; + bool canNavigate() const override; + bool canNext() const override; + bool canPrevious() const override; + void goToNext() override; + void goToPrev() override; void openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters); void addTerminal(TerminalWidget *terminal, const QString &title); @@ -53,11 +54,7 @@ private: QToolButton *m_newTerminalButton{nullptr}; QToolButton *m_closeTerminalButton{nullptr}; - QAction m_newTerminal; - QAction m_closeTerminal; - QAction m_nextTerminal; - QAction m_prevTerminal; - QAction m_minMaxAction; + bool m_widgetInitialized{false}; }; } // namespace Terminal diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 12d696c69e2..5c099d96f8c 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -3,9 +3,9 @@ #include "terminalwidget.h" #include "glyphcache.h" +#include "terminalcommands.h" #include "terminalsettings.h" #include "terminalsurface.h" -#include "terminaltr.h" #include #include @@ -53,11 +53,6 @@ static constexpr std::chrono::milliseconds minRefreshInterval = 1s / 30; TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &openParameters) : QAbstractScrollArea(parent) - , m_copyAction(Tr::tr("Copy")) - , m_pasteAction(Tr::tr("Paste")) - , m_clearSelectionAction(Tr::tr("Clear Selection")) - , m_zoomInAction(Tr::tr("Zoom In")) - , m_zoomOutAction(Tr::tr("Zoom Out")) , m_openParameters(openParameters) , m_lastFlush(std::chrono::system_clock::now()) , m_lastDoubleClick(std::chrono::system_clock::now()) @@ -224,27 +219,20 @@ void TerminalWidget::setupColors() void TerminalWidget::setupActions() { - m_copyAction.setEnabled(false); - m_copyAction.setShortcuts( - {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") - : QLatin1String("Ctrl+Shift+C")), - QKeySequence(Qt::Key_Return)}); - m_pasteAction.setShortcut(QKeySequence( - HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V"))); + WidgetActions &a = TerminalCommands::widgetActions(); - m_clearSelectionAction.setShortcut(QKeySequence("Esc")); + auto ifHasFocus = [this](void (TerminalWidget::*f)()) { + return [this, f] { + if (hasFocus()) + (this->*f)(); + }; + }; - m_zoomInAction.setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+Shift++")}); - m_zoomOutAction.setShortcut(QKeySequence("Ctrl+-")); - - connect(&m_copyAction, &QAction::triggered, this, &TerminalWidget::copyToClipboard); - connect(&m_pasteAction, &QAction::triggered, this, &TerminalWidget::pasteFromClipboard); - connect(&m_clearSelectionAction, &QAction::triggered, this, &TerminalWidget::clearSelection); - connect(&m_zoomInAction, &QAction::triggered, this, &TerminalWidget::zoomIn); - connect(&m_zoomOutAction, &QAction::triggered, this, &TerminalWidget::zoomOut); - - addActions( - {&m_copyAction, &m_pasteAction, &m_clearSelectionAction, &m_zoomInAction, &m_zoomOutAction}); + // clang-format off + connect(&a.copy, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyToClipboard)); + connect(&a.paste, &QAction::triggered, this, ifHasFocus(&TerminalWidget::pasteFromClipboard)); + connect(&a.clearSelection, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearSelection)); + // clang-format on } void TerminalWidget::writeToPty(const QByteArray &data) @@ -342,6 +330,14 @@ QColor TerminalWidget::toQColor(std::variant color) const return std::get(color); } +void TerminalWidget::updateCopyState() +{ + if (!hasFocus()) + return; + + TerminalCommands::widgetActions().copy.setEnabled(m_selection.has_value()); +} + void TerminalWidget::setFont(const QFont &font) { m_font = font; @@ -364,33 +360,10 @@ void TerminalWidget::setFont(const QFont &font) } } -QAction &TerminalWidget::copyAction() +void TerminalWidget::copyToClipboard() { - return m_copyAction; -} + QTC_ASSERT(m_selection.has_value(), return); -QAction &TerminalWidget::pasteAction() -{ - return m_pasteAction; -} - -QAction &TerminalWidget::clearSelectionAction() -{ - return m_clearSelectionAction; -} - -QAction &TerminalWidget::zoomInAction() -{ - return m_zoomInAction; -} - -QAction &TerminalWidget::zoomOutAction() -{ - return m_zoomOutAction; -} - -void TerminalWidget::copyToClipboard() const -{ QString text = textFromSelection(); qCDebug(selectionLog) << "Copied to clipboard: " << text; @@ -491,10 +464,10 @@ bool TerminalWidget::setSelection(const std::optional &selection) return false; } - m_copyAction.setEnabled(selection.has_value()); - m_selection = selection; + updateCopyState(); + if (m_selection && m_selection->final) { qCDebug(selectionLog) << "Copy enabled:" << selection.has_value(); @@ -958,25 +931,7 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) m_cursorBlinkState = true; } - bool actionTriggered = false; - for (const auto &action : actions()) { - if (!action->isEnabled()) - continue; - - for (const auto &shortcut : action->shortcuts()) { - const auto result = shortcut.matches(QKeySequence(event->keyCombination())); - if (result == QKeySequence::ExactMatch) { - action->trigger(); - actionTriggered = true; - break; - } - } - - if (actionTriggered) - break; - } - - if (actionTriggered) { + if (TerminalCommands::triggerAction(event)) { setSelection(std::nullopt); return; } @@ -1067,6 +1022,7 @@ void TerminalWidget::focusInEvent(QFocusEvent *) { updateViewport(); configBlinkTimer(); + updateCopyState(); } void TerminalWidget::focusOutEvent(QFocusEvent *) { @@ -1123,10 +1079,10 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) updateViewport(); } else if (event->button() == Qt::RightButton) { if (m_selection) { - m_copyAction.trigger(); + copyToClipboard(); setSelection(std::nullopt); } else { - m_pasteAction.trigger(); + pasteFromClipboard(); } } } diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index d7aff0648b8..997abda13dd 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -29,15 +29,7 @@ public: void setFont(const QFont &font); - QAction ©Action(); - QAction &pasteAction(); - - QAction &clearSelectionAction(); - - QAction &zoomInAction(); - QAction &zoomOutAction(); - - void copyToClipboard() const; + void copyToClipboard(); void pasteFromClipboard(); void clearSelection(); @@ -168,6 +160,8 @@ protected: QColor toQColor(std::variant color) const; + void updateCopyState(); + private: std::unique_ptr m_process; std::unique_ptr m_surface; @@ -192,14 +186,6 @@ private: QPoint end; } m_activeMouseSelect; - QAction m_copyAction; - QAction m_pasteAction; - - QAction m_clearSelectionAction; - - QAction m_zoomInAction; - QAction m_zoomOutAction; - QTimer m_flushDelayTimer; QTimer m_scrollTimer; From af809b3a528bb8c4d57a22484a72b8414b869bda Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 12:28:44 +0100 Subject: [PATCH 0356/1447] Terminal: Add context menu & Settings button Fixes: QTCREATORBUG-28937 Change-Id: I9dab5da0adccb8cff4d4e824ead0eba3e27eef5c Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalcommands.cpp | 5 +++++ src/plugins/terminal/terminalcommands.h | 3 +++ src/plugins/terminal/terminalpane.cpp | 12 ++++++++++-- src/plugins/terminal/terminalpane.h | 1 + src/plugins/terminal/terminalwidget.cpp | 14 +++++++++++++- 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp index 9f177720b3e..28b8583c93a 100644 --- a/src/plugins/terminal/terminalcommands.cpp +++ b/src/plugins/terminal/terminalcommands.cpp @@ -129,4 +129,9 @@ bool TerminalCommands::triggerAction(QKeyEvent *event) return false; } +QAction *TerminalCommands::openSettingsAction() +{ + return ActionManager::command("Preferences.Terminal.General")->action(); +} + } // namespace Terminal diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h index 11392f2dcfc..795e5188acd 100644 --- a/src/plugins/terminal/terminalcommands.h +++ b/src/plugins/terminal/terminalcommands.h @@ -20,6 +20,7 @@ struct WidgetActions QAction copy{Tr::tr("Copy")}; QAction paste{Tr::tr("Paste")}; QAction clearSelection{Tr::tr("Clear Selection")}; + QAction clearTerminal{Tr::tr("Clear Terminal")}; }; struct PaneActions @@ -45,6 +46,8 @@ public: static bool triggerAction(QKeyEvent *event); + static QAction *openSettingsAction(); + protected: void initWidgetActions(const Core::Context &context); void initPaneActions(const Core::Context &context); diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index cdf14c55e37..c94fbc0b3bb 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include namespace Terminal { @@ -111,6 +111,14 @@ TerminalPane::TerminalPane(QObject *parent) if (minMaxCommand) emit minMaxCommand->action()->triggered(); }); + + m_openSettingsButton = new QToolButton(); + m_openSettingsButton->setToolTip(Tr::tr("Open Terminal Settings")); + m_openSettingsButton->setIcon(Icons::SETTINGS_TOOLBAR.icon()); + + connect(m_openSettingsButton, &QToolButton::clicked, m_openSettingsButton, []() { + TerminalCommands::openSettingsAction()->trigger(); + }); } TerminalPane::~TerminalPane() @@ -252,7 +260,7 @@ QList TerminalPane::toolBarWidgets() const widgets.prepend(m_newTerminalButton); widgets.prepend(m_closeTerminalButton); - return widgets; + return widgets << m_openSettingsButton; } QString TerminalPane::displayName() const diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index fd902f9176a..47cb3ac039e 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -53,6 +53,7 @@ private: QToolButton *m_newTerminalButton{nullptr}; QToolButton *m_closeTerminalButton{nullptr}; + QToolButton *m_openSettingsButton{nullptr}; bool m_widgetInitialized{false}; }; diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 5c099d96f8c..50f4ac0c1c6 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -232,6 +233,7 @@ void TerminalWidget::setupActions() connect(&a.copy, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyToClipboard)); connect(&a.paste, &QAction::triggered, this, ifHasFocus(&TerminalWidget::pasteFromClipboard)); connect(&a.clearSelection, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearSelection)); + connect(&a.clearTerminal, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearContents)); // clang-format on } @@ -1078,7 +1080,17 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) event->accept(); updateViewport(); } else if (event->button() == Qt::RightButton) { - if (m_selection) { + if (event->modifiers() == Qt::ShiftModifier) { + QMenu *contextMenu = new QMenu(this); + contextMenu->addAction(&TerminalCommands::widgetActions().copy); + contextMenu->addAction(&TerminalCommands::widgetActions().paste); + contextMenu->addSeparator(); + contextMenu->addAction(&TerminalCommands::widgetActions().clearTerminal); + contextMenu->addSeparator(); + contextMenu->addAction(TerminalCommands::openSettingsAction()); + + contextMenu->popup(event->globalPos()); + } else if (m_selection) { copyToClipboard(); setSelection(std::nullopt); } else { From 29873068eb88b51fe16d06f3ae8672dbb00c9845 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 15 Mar 2023 09:30:14 +0100 Subject: [PATCH 0357/1447] Utils: Store Device::osType in settings Change-Id: I41348be752598b7a8d1f1979764e7111cccc95a9 Reviewed-by: hjk Reviewed-by: Eike Ziller --- src/libs/utils/devicefileaccess.cpp | 44 ++----------------- src/libs/utils/devicefileaccess.h | 5 --- src/libs/utils/filepath.cpp | 6 ++- src/libs/utils/filepath.h | 1 + src/libs/utils/osspecificaspects.h | 30 +++++++++++++ src/plugins/docker/dockerdevice.cpp | 7 --- .../devicesupport/devicemanager.cpp | 7 +++ .../devicesupport/devicesettingswidget.cpp | 3 ++ .../projectexplorer/devicesupport/idevice.cpp | 7 +-- .../projectexplorer/devicesupport/idevice.h | 2 + src/plugins/remotelinux/linuxdevice.cpp | 35 +++++++++++++++ src/plugins/remotelinux/linuxdevice.h | 4 ++ .../tst_unixdevicefileaccess.cpp | 6 --- 13 files changed, 95 insertions(+), 62 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 5cec46b9e2f..1e3c771ee7e 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -269,12 +269,6 @@ bool DeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &targ return false; } -OsType DeviceFileAccess::osType(const FilePath &filePath) const -{ - Q_UNUSED(filePath) - return OsTypeOther; -} - FilePath DeviceFileAccess::symLinkTarget(const FilePath &filePath) const { Q_UNUSED(filePath) @@ -799,12 +793,6 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const return result; } -OsType DesktopDeviceFileAccess::osType(const FilePath &filePath) const -{ - Q_UNUSED(filePath) - return HostOsInfo::hostOs(); -} - // UnixDeviceAccess UnixDeviceFileAccess::~UnixDeviceFileAccess() = default; @@ -1035,30 +1023,6 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file return newPath; } -OsType UnixDeviceFileAccess::osType() const -{ - if (m_osType) - return *m_osType; - - const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); - QTC_ASSERT(result.exitCode == 0, return OsTypeLinux); - const QString osName = QString::fromUtf8(result.stdOut).trimmed(); - if (osName == "Darwin") - m_osType = OsTypeMac; - else if (osName == "Linux") - m_osType = OsTypeLinux; - else - m_osType = OsTypeOtherUnix; - - return *m_osType; -} - -OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const -{ - Q_UNUSED(filePath); - return osType(); -} - QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const { const RunResult result = runInShell( @@ -1072,7 +1036,7 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const { - return (osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) + return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) << "-L" << filePath.path(); } @@ -1150,7 +1114,7 @@ FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const const RunResult stat = runInShell({"stat", args, OsType::OsTypeLinux}); return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut), - osType() == OsTypeMac ? 8 : 16); + filePath.osType() == OsTypeMac ? 8 : 16); } // returns whether 'find' could be used. @@ -1165,7 +1129,7 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, // TODO: Using stat -L will always return the link target, not the link itself. // We may wan't to add the information that it is a link at some point. - const QString statFormat = osType() == OsTypeMac + const QString statFormat = filePath.osType() == OsTypeMac ? QLatin1String("-f \"%p %m %z\"") : QLatin1String("-c \"%f %Y %s\""); if (callBack.index() == 1) @@ -1192,7 +1156,7 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, if (entries.isEmpty()) return true; - const int modeBase = osType() == OsTypeMac ? 8 : 16; + const int modeBase = filePath.osType() == OsTypeMac ? 8 : 16; const auto toFilePath = [&filePath, &callBack, modeBase](const QString &entry) { diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index e3a2acdb8fb..d57da462d2f 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -45,7 +45,6 @@ protected: const FilePath &target) const; virtual bool renameFile(const FilePath &filePath, const FilePath &target) const; - virtual OsType osType(const FilePath &filePath) const; virtual FilePath symLinkTarget(const FilePath &filePath) const; virtual FilePathInfo filePathInfo(const FilePath &filePath) const; virtual QDateTime lastModified(const FilePath &filePath) const; @@ -100,7 +99,6 @@ protected: expected_str copyFile(const FilePath &filePath, const FilePath &target) const override; bool renameFile(const FilePath &filePath, const FilePath &target) const override; - OsType osType(const FilePath &filePath) const override; FilePath symLinkTarget(const FilePath &filePath) const override; FilePathInfo filePathInfo(const FilePath &filePath) const override; QDateTime lastModified(const FilePath &filePath) const override; @@ -159,7 +157,6 @@ protected: bool renameFile(const FilePath &filePath, const FilePath &target) const override; FilePathInfo filePathInfo(const FilePath &filePath) const override; - OsType osType(const FilePath &filePath) const override; FilePath symLinkTarget(const FilePath &filePath) const override; QDateTime lastModified(const FilePath &filePath) const override; QFile::Permissions permissions(const FilePath &filePath) const override; @@ -194,14 +191,12 @@ private: const FileFilter &filter, QStringList *found) const; - Utils::OsType osType() const; QStringList statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const; mutable bool m_tryUseFind = true; mutable std::optional m_hasMkTemp; - mutable std::optional m_osType; }; } // Utils diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index f117f4e8687..23450661903 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1566,7 +1566,11 @@ bool FilePath::setPermissions(QFile::Permissions permissions) const OsType FilePath::osType() const { - return fileAccess()->osType(*this); + if (!needsDevice()) + return HostOsInfo::hostOs(); + + QTC_ASSERT(s_deviceHooks.osType, return HostOsInfo::hostOs()); + return s_deviceHooks.osType(*this); } bool FilePath::removeFile() const diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 877e8beb8e9..0ecdc09dab9 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -291,6 +291,7 @@ public: std::function isSameDevice; std::function(const FilePath &)> localSource; std::function openTerminal; + std::function osType; }; // For testing diff --git a/src/libs/utils/osspecificaspects.h b/src/libs/utils/osspecificaspects.h index 0cc22efe5fe..c735f313abc 100644 --- a/src/libs/utils/osspecificaspects.h +++ b/src/libs/utils/osspecificaspects.h @@ -14,6 +14,36 @@ namespace Utils { // Add more as needed. enum OsType { OsTypeWindows, OsTypeLinux, OsTypeMac, OsTypeOtherUnix, OsTypeOther }; +inline QString osTypeToString(OsType osType) +{ + switch (osType) { + case OsTypeWindows: + return "Windows"; + case OsTypeLinux: + return "Linux"; + case OsTypeMac: + return "Mac"; + case OsTypeOtherUnix: + return "Other Unix"; + case OsTypeOther: + default: + return "Other"; + } +} + +inline OsType osTypeFromString(const QString &string) +{ + if (string == "Windows") + return OsTypeWindows; + if (string == "Linux") + return OsTypeLinux; + if (string == "Mac") + return OsTypeMac; + if (string == "Other Unix") + return OsTypeOtherUnix; + return OsTypeOther; +} + namespace OsSpecificAspects { inline QString withExecutableSuffix(OsType osType, const QString &executable) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 02770e89a7d..d0a8c4c8e97 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -126,7 +126,6 @@ public: RunResult runInShell(const CommandLine &cmdLine, const QByteArray &stdInData) const override; QString mapToDevicePath(const QString &hostPath) const override; - OsType osType(const FilePath &filePath) const override; DockerDevicePrivate *m_dev = nullptr; }; @@ -377,12 +376,6 @@ QString DockerDeviceFileAccess::mapToDevicePath(const QString &hostPath) const return newPath; } -OsType DockerDeviceFileAccess::osType(const FilePath &filePath) const -{ - QTC_ASSERT(m_dev, return UnixDeviceFileAccess::osType(filePath)); - return m_dev->q->osType(); -} - DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &data) : d(new DockerDevicePrivate(this, settings, data)) { diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 53e1e5c4d73..ff3baf6148a 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -443,6 +443,13 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_uniqueopenTerminal(env, filePath); }; + deviceHooks.osType = [](const FilePath &filePath) { + auto device = DeviceManager::deviceForPath(filePath); + if (!device) + return OsTypeLinux; + return device->osType(); + }; + DeviceProcessHooks processHooks; processHooks.processImplHook = [](const FilePath &filePath) -> ProcessInterface * { diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index 27ad8252ab0..6de16afac00 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -182,6 +183,8 @@ void DeviceSettingsWidget::addDevice() if (device.isNull()) return; + Utils::asyncRun([device] { device->checkOsType(); }); + m_deviceManager->addDevice(device); m_removeConfigButton->setEnabled(true); m_configurationComboBox->setCurrentIndex(m_deviceManagerModel->indexOf(device)); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index ab3a44f0d84..2e6e80801b5 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -93,6 +93,7 @@ static Id newId() const char DisplayNameKey[] = "Name"; const char TypeKey[] = "OsType"; +const char ClientOsTypeKey[] = "ClientOsType"; const char IdKey[] = "InternalId"; const char OriginKey[] = "Origin"; const char MachineTypeKey[] = "Type"; @@ -426,6 +427,8 @@ void IDevice::fromMap(const QVariantMap &map) d->type = typeFromMap(map); d->displayName.fromMap(map, DisplayNameKey); d->id = Id::fromSetting(map.value(QLatin1String(IdKey))); + d->osType = osTypeFromString( + map.value(QLatin1String(ClientOsTypeKey), osTypeToString(OsTypeLinux)).toString()); if (!d->id.isValid()) d->id = newId(); d->origin = static_cast(map.value(QLatin1String(OriginKey), ManuallyAdded).toInt()); @@ -472,6 +475,7 @@ QVariantMap IDevice::toMap() const QVariantMap map; d->displayName.toMap(map, DisplayNameKey); map.insert(QLatin1String(TypeKey), d->type.toString()); + map.insert(QLatin1String(ClientOsTypeKey), osTypeToString(d->osType)); map.insert(QLatin1String(IdKey), d->id.toSetting()); map.insert(QLatin1String(OriginKey), d->origin); @@ -504,9 +508,6 @@ IDevice::Ptr IDevice::clone() const device->d->deviceState = d->deviceState; device->d->deviceActions = d->deviceActions; device->d->deviceIcons = d->deviceIcons; - // Os type is only set in the constructor, always to the same value. - // But make sure we notice if that changes in the future (which it shouldn't). - QTC_CHECK(device->d->osType == d->osType); device->d->osType = d->osType; device->fromMap(toMap()); return device; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 6323b8589bb..2497bdcc452 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -221,6 +221,8 @@ public: virtual bool prepareForBuild(const Target *target); virtual std::optional clangdExecutable() const; + virtual void checkOsType(){}; + protected: IDevice(); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 760273e9ab5..191ee9d5d32 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -305,6 +305,9 @@ public: Environment getEnvironment(); void invalidateEnvironmentCache(); + void checkOsType(); + void queryOsType(std::function run); + LinuxDevice *q = nullptr; QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; @@ -939,6 +942,12 @@ LinuxDevice::LinuxDevice() }}); } +void LinuxDevice::_setOsType(Utils::OsType osType) +{ + qCDebug(linuxDeviceLog) << "Setting OS type to" << osType << "for" << displayName(); + IDevice::setOsType(osType); +} + LinuxDevice::~LinuxDevice() { delete d; @@ -1045,6 +1054,23 @@ LinuxDevicePrivate::~LinuxDevicePrivate() QMetaObject::invokeMethod(&m_shellThread, closeShell, Qt::BlockingQueuedConnection); } +void LinuxDevicePrivate::queryOsType(std::function runInShell) +{ + const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); + if (result.exitCode != 0) + q->_setOsType(OsTypeOtherUnix); + const QString osName = QString::fromUtf8(result.stdOut).trimmed(); + if (osName == "Darwin") + q->_setOsType(OsTypeMac); + if (osName == "Linux") + q->_setOsType(OsTypeLinux); +} + +void LinuxDevicePrivate::checkOsType() +{ + queryOsType([this](const CommandLine &cmd) { return runInShell(cmd); }); +} + // Call me with shell mutex locked bool LinuxDevicePrivate::setupShell() { @@ -1058,6 +1084,10 @@ bool LinuxDevicePrivate::setupShell() QMetaObject::invokeMethod(m_handler, [this, sshParameters] { return m_handler->start(sshParameters); }, Qt::BlockingQueuedConnection, &ok); + + if (ok) { + queryOsType([this](const CommandLine &cmd) { return m_handler->runInShell(cmd); }); + } return ok; } @@ -1452,6 +1482,11 @@ LinuxDevicePrivate *LinuxDevice::connectionAccess() const return d; } +void LinuxDevice::checkOsType() +{ + d->checkOsType(); +} + namespace Internal { // Factory diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index fd111447201..d9dad9ba75f 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -42,11 +42,15 @@ public: const ProjectExplorer::FileTransferSetupData &setup) const override; class LinuxDevicePrivate *connectionAccess() const; + void checkOsType() override; protected: LinuxDevice(); + void _setOsType(Utils::OsType osType); + class LinuxDevicePrivate *d; + friend class LinuxDevicePrivate; }; namespace Internal { diff --git a/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp b/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp index 8aa9609057c..b5aef12d06c 100644 --- a/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp +++ b/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp @@ -59,12 +59,6 @@ private slots: m_fileSizeTestFile.writeFileContents(QByteArray(1024, 'a')); } - void osType() - { - const auto osType = m_dfaPtr->osType({}); - QCOMPARE(osType, HostOsInfo::hostOs()); - } - void fileSize() { const auto size = m_dfaPtr->fileSize(m_fileSizeTestFile); From 6e0a50c660634af7a748fe5c34ea0c7a74625884 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 23 Mar 2023 13:46:58 +0100 Subject: [PATCH 0358/1447] Terminal: Use terminal icon for the shells dropdown button The + icon is confusing with the zoom in. Change-Id: Ibafa538a7ef3c1f58c940780caca4c24bfc23ef3 Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalpane.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index c94fbc0b3bb..187df2b074b 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -47,7 +47,9 @@ TerminalPane::TerminalPane(QObject *parent) QAction &newTerminal = TerminalCommands::instance().paneActions().newTerminal; QAction &closeTerminal = TerminalCommands::instance().paneActions().closeTerminal; - newTerminal.setIcon(Icons::PLUS_TOOLBAR.icon()); + newTerminal.setIcon( + Icon({{":/terminal/images/settingscategory_terminal.png", Theme::Theme::IconsBaseColor}}) + .icon()); newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); From 10816ecbe016e23cdbd7fd8ebcb34ae5cd4563f7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 14:28:06 +0100 Subject: [PATCH 0359/1447] Terminal: Add default themes to Creator themes Fixes: QTCREATORBUG-28939 Change-Id: I51ded621cdd2e87743a93853686bba09aa9aa44d Reviewed-by: Cristian Adam --- share/qtcreator/themes/dark.creatortheme | 20 ++++++++ share/qtcreator/themes/default.creatortheme | 20 ++++++++ .../themes/design-light.creatortheme | 20 ++++++++ share/qtcreator/themes/design.creatortheme | 20 ++++++++ share/qtcreator/themes/flat-dark.creatortheme | 20 ++++++++ .../qtcreator/themes/flat-light.creatortheme | 20 ++++++++ share/qtcreator/themes/flat.creatortheme | 20 ++++++++ src/libs/utils/theme/theme.h | 21 ++++++++ src/plugins/terminal/terminalsettings.cpp | 48 +++++++++++-------- src/plugins/terminal/terminalsettingspage.cpp | 13 ++++- 10 files changed, 202 insertions(+), 20 deletions(-) diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index 82fa00f6142..fe8807eab1d 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -385,6 +385,26 @@ QmlDesigner_FormeditorBackgroundColor=qmlDesignerButtonColor QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor QmlDesigner_ScrollBarHandleColor=ff505050 +TerminalForeground=ffffffff +TerminalBackground=ff000000 +TerminalSelection=7fffffff +TerminalAnsi0=000000 +TerminalAnsi1=8b1b10 +TerminalAnsi2=4aa32e +TerminalAnsi3=9a9a2f +TerminalAnsi4=0000ab +TerminalAnsi5=a320ac +TerminalAnsi6=49a3b0 +TerminalAnsi7=bfbfbf +TerminalAnsi8=666666 +TerminalAnsi9=d22d1f +TerminalAnsi10=62d63f +TerminalAnsi11=e5e54b +TerminalAnsi12=0000fe +TerminalAnsi13=d22dde +TerminalAnsi14=69e2e4 +TerminalAnsi15=e5e5e6 + [Flags] ComboBoxDrawTextShadow=false DerivePaletteFromTheme=true diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 06d36f669e9..52101b881bd 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -353,6 +353,26 @@ QmlDesigner_FormeditorBackgroundColor=qmlDesignerButtonColor QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor QmlDesigner_ScrollBarHandleColor=ff7a7a7a +TerminalForeground=ff000000 +TerminalBackground=ffffffff +TerminalSelection=7fffffff +TerminalAnsi0=000000 +TerminalAnsi1=8b1b10 +TerminalAnsi2=4aa32e +TerminalAnsi3=9a9a2f +TerminalAnsi4=0000ab +TerminalAnsi5=a320ac +TerminalAnsi6=49a3b0 +TerminalAnsi7=bfbfbf +TerminalAnsi8=666666 +TerminalAnsi9=d22d1f +TerminalAnsi10=62d63f +TerminalAnsi11=e5e54b +TerminalAnsi12=0000fe +TerminalAnsi13=d22dde +TerminalAnsi14=69e2e4 +TerminalAnsi15=e5e5e6 + [Flags] ComboBoxDrawTextShadow=true DerivePaletteFromTheme=false diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 12691562788..f3cf92f58ac 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -397,6 +397,26 @@ PaletteWindowTextDisabled=textDisabled PaletteBaseDisabled=backgroundColorDisabled PaletteTextDisabled=textDisabled +TerminalForeground=ff000000 +TerminalBackground=ffffffff +TerminalSelection=7fffffff +TerminalAnsi0=000000 +TerminalAnsi1=8b1b10 +TerminalAnsi2=4aa32e +TerminalAnsi3=9a9a2f +TerminalAnsi4=0000ab +TerminalAnsi5=a320ac +TerminalAnsi6=49a3b0 +TerminalAnsi7=bfbfbf +TerminalAnsi8=666666 +TerminalAnsi9=d22d1f +TerminalAnsi10=62d63f +TerminalAnsi11=e5e54b +TerminalAnsi12=0000fe +TerminalAnsi13=d22dde +TerminalAnsi14=69e2e4 +TerminalAnsi15=e5e5e6 + [Flags] ComboBoxDrawTextShadow=false DerivePaletteFromTheme=true diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index 93355132175..1783ba8e9d0 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -497,6 +497,26 @@ PaletteTextDisabled=textDisabled PaletteMid=ffafafaf PalettePlaceholderText=ff808081 +TerminalForeground=ffffffff +TerminalBackground=ff000000 +TerminalSelection=7fffffff +TerminalAnsi0=000000 +TerminalAnsi1=8b1b10 +TerminalAnsi2=4aa32e +TerminalAnsi3=9a9a2f +TerminalAnsi4=0000ab +TerminalAnsi5=a320ac +TerminalAnsi6=49a3b0 +TerminalAnsi7=bfbfbf +TerminalAnsi8=666666 +TerminalAnsi9=d22d1f +TerminalAnsi10=62d63f +TerminalAnsi11=e5e54b +TerminalAnsi12=0000fe +TerminalAnsi13=d22dde +TerminalAnsi14=69e2e4 +TerminalAnsi15=e5e5e6 + [Flags] ComboBoxDrawTextShadow=false DerivePaletteFromTheme=true diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 1e282303310..16bf4e26e72 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -389,6 +389,26 @@ PaletteTextDisabled=textDisabled PaletteMid=ffa0a0a0 PalettePlaceholderText=ff7f7f80 +TerminalForeground=ffffffff +TerminalBackground=ff000000 +TerminalSelection=7fffffff +TerminalAnsi0=000000 +TerminalAnsi1=8b1b10 +TerminalAnsi2=4aa32e +TerminalAnsi3=9a9a2f +TerminalAnsi4=0000ab +TerminalAnsi5=a320ac +TerminalAnsi6=49a3b0 +TerminalAnsi7=bfbfbf +TerminalAnsi8=666666 +TerminalAnsi9=d22d1f +TerminalAnsi10=62d63f +TerminalAnsi11=e5e54b +TerminalAnsi12=0000fe +TerminalAnsi13=d22dde +TerminalAnsi14=69e2e4 +TerminalAnsi15=e5e5e6 + [Flags] ComboBoxDrawTextShadow=false DerivePaletteFromTheme=true diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index d3ff03a7985..512f511f735 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -362,6 +362,26 @@ QmlDesigner_FormeditorBackgroundColor=qmlDesignerButtonColor QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor QmlDesigner_ScrollBarHandleColor=ffcccccc +TerminalForeground=ff000000 +TerminalBackground=ffffffff +TerminalSelection=7fffffff +TerminalAnsi0=000000 +TerminalAnsi1=8b1b10 +TerminalAnsi2=4aa32e +TerminalAnsi3=9a9a2f +TerminalAnsi4=0000ab +TerminalAnsi5=a320ac +TerminalAnsi6=49a3b0 +TerminalAnsi7=bfbfbf +TerminalAnsi8=666666 +TerminalAnsi9=d22d1f +TerminalAnsi10=62d63f +TerminalAnsi11=e5e54b +TerminalAnsi12=0000fe +TerminalAnsi13=d22dde +TerminalAnsi14=69e2e4 +TerminalAnsi15=e5e5e6 + [Flags] ComboBoxDrawTextShadow=false DerivePaletteFromTheme=false diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 45ffe8537df..e0e27654329 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -360,6 +360,26 @@ QmlDesigner_FormeditorBackgroundColor=qmlDesignerButtonColor QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor QmlDesigner_ScrollBarHandleColor=ff595b5c +TerminalForeground=ff000000 +TerminalBackground=ffffffff +TerminalSelection=7fffffff +TerminalAnsi0=000000 +TerminalAnsi1=8b1b10 +TerminalAnsi2=4aa32e +TerminalAnsi3=9a9a2f +TerminalAnsi4=0000ab +TerminalAnsi5=a320ac +TerminalAnsi6=49a3b0 +TerminalAnsi7=bfbfbf +TerminalAnsi8=666666 +TerminalAnsi9=d22d1f +TerminalAnsi10=62d63f +TerminalAnsi11=e5e54b +TerminalAnsi12=0000fe +TerminalAnsi13=d22dde +TerminalAnsi14=69e2e4 +TerminalAnsi15=e5e5e6 + [Flags] ComboBoxDrawTextShadow=false DerivePaletteFromTheme=false diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 1fbae4934e2..d3ba34b3ee5 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -420,6 +420,27 @@ public: DSstatePanelBackground, DSstateHighlight, + + TerminalForeground, + TerminalBackground, + TerminalSelection, + + TerminalAnsi0, + TerminalAnsi1, + TerminalAnsi2, + TerminalAnsi3, + TerminalAnsi4, + TerminalAnsi5, + TerminalAnsi6, + TerminalAnsi7, + TerminalAnsi8, + TerminalAnsi9, + TerminalAnsi10, + TerminalAnsi11, + TerminalAnsi12, + TerminalAnsi13, + TerminalAnsi14, + TerminalAnsi15, }; enum ImageFile { diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index b43d964320b..a7c0d8fb2cf 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -7,6 +7,7 @@ #include #include +#include using namespace Utils; @@ -96,33 +97,42 @@ TerminalSettings::TerminalSettings() shell.setToolTip(Tr::tr("The shell executable to be started as terminal")); shell.setDefaultValue(defaultShell()); - setupColor(this, foregroundColor, "Foreground", QColor::fromRgb(0xff, 0xff, 0xff)); - setupColor(this, backgroundColor, "Background", QColor::fromRgb(0x0, 0x0, 0x0)); - setupColor(this, selectionColor, "Selection", QColor::fromRgb(0xFF, 0xFF, 0xFF, 0x7F)); + setupColor(this, + foregroundColor, + "Foreground", + Utils::creatorTheme()->color(Theme::TerminalForeground)); + setupColor(this, + backgroundColor, + "Background", + Utils::creatorTheme()->color(Theme::TerminalBackground)); + setupColor(this, + selectionColor, + "Selection", + Utils::creatorTheme()->color(Theme::TerminalSelection)); - setupColor(this, colors[0], "0", QColor::fromRgb(0x00, 0x00, 0x00)); - setupColor(this, colors[8], "8", QColor::fromRgb(102, 102, 102)); + setupColor(this, colors[0], "0", Utils::creatorTheme()->color(Theme::TerminalAnsi0)); + setupColor(this, colors[8], "8", Utils::creatorTheme()->color(Theme::TerminalAnsi8)); - setupColor(this, colors[1], "1", QColor::fromRgb(139, 27, 16)); - setupColor(this, colors[9], "9", QColor::fromRgb(210, 45, 31)); + setupColor(this, colors[1], "1", Utils::creatorTheme()->color(Theme::TerminalAnsi1)); + setupColor(this, colors[9], "9", Utils::creatorTheme()->color(Theme::TerminalAnsi9)); - setupColor(this, colors[2], "2", QColor::fromRgb(74, 163, 46)); - setupColor(this, colors[10], "10", QColor::fromRgb(98, 214, 63)); + setupColor(this, colors[2], "2", Utils::creatorTheme()->color(Theme::TerminalAnsi2)); + setupColor(this, colors[10], "10", Utils::creatorTheme()->color(Theme::TerminalAnsi10)); - setupColor(this, colors[3], "3", QColor::fromRgb(154, 154, 47)); - setupColor(this, colors[11], "11", QColor::fromRgb(229, 229, 75)); + setupColor(this, colors[3], "3", Utils::creatorTheme()->color(Theme::TerminalAnsi3)); + setupColor(this, colors[11], "11", Utils::creatorTheme()->color(Theme::TerminalAnsi11)); - setupColor(this, colors[4], "4", QColor::fromRgb(0, 0, 171)); - setupColor(this, colors[12], "12", QColor::fromRgb(0, 0, 254)); + setupColor(this, colors[4], "4", Utils::creatorTheme()->color(Theme::TerminalAnsi4)); + setupColor(this, colors[12], "12", Utils::creatorTheme()->color(Theme::TerminalAnsi12)); - setupColor(this, colors[5], "5", QColor::fromRgb(163, 32, 172)); - setupColor(this, colors[13], "13", QColor::fromRgb(210, 45, 222)); + setupColor(this, colors[5], "5", Utils::creatorTheme()->color(Theme::TerminalAnsi5)); + setupColor(this, colors[13], "13", Utils::creatorTheme()->color(Theme::TerminalAnsi13)); - setupColor(this, colors[6], "6", QColor::fromRgb(73, 163, 176)); - setupColor(this, colors[14], "14", QColor::fromRgb(105, 226, 228)); + setupColor(this, colors[6], "6", Utils::creatorTheme()->color(Theme::TerminalAnsi6)); + setupColor(this, colors[14], "14", Utils::creatorTheme()->color(Theme::TerminalAnsi14)); - setupColor(this, colors[7], "7", QColor::fromRgb(191, 191, 191)); - setupColor(this, colors[15], "15", QColor::fromRgb(229, 229, 230)); + setupColor(this, colors[7], "7", Utils::creatorTheme()->color(Theme::TerminalAnsi7)); + setupColor(this, colors[15], "15", Utils::creatorTheme()->color(Theme::TerminalAnsi15)); registerAspect(&font); registerAspect(&fontSize); diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index 7eabca19b06..54ddc4d35e9 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -337,6 +337,7 @@ QWidget *TerminalSettingsPage::widget() TerminalSettings &settings = TerminalSettings::instance(); QPushButton *loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); + QPushButton *resetTheme = new QPushButton(Tr::tr("Reset Theme to default")); connect(loadThemeButton, &QPushButton::clicked, this, [widget] { const FilePath path = FileUtils::getOpenFilePath( @@ -363,6 +364,16 @@ QWidget *TerminalSettingsPage::widget() QMessageBox::warning(widget, Tr::tr("Error"), result.error()); }); + connect(resetTheme, &QPushButton::clicked, this, [] { + TerminalSettings &settings = TerminalSettings::instance(); + settings.foregroundColor.setVolatileValue(settings.foregroundColor.defaultValue()); + settings.backgroundColor.setVolatileValue(settings.backgroundColor.defaultValue()); + settings.selectionColor.setVolatileValue(settings.selectionColor.defaultValue()); + + for (auto &color : settings.colors) + color.setVolatileValue(color.defaultValue()); + }); + // clang-format off Column { Row { @@ -402,7 +413,7 @@ QWidget *TerminalSettingsPage::widget() settings.colors[14], settings.colors[15] }, Row { - loadThemeButton, st, + loadThemeButton, resetTheme, st, } }, }, From 84155e835468d16dc595f785a4013e77bfad9aa3 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 13:34:59 +0100 Subject: [PATCH 0360/1447] Terminal: Set focus after closing tab Change-Id: I1c13d0e59000ca3d1a88a3fe543ccd1aa6db7462 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalpane.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 187df2b074b..27b512b92e3 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -218,6 +218,11 @@ void TerminalPane::removeTab(int index) delete m_tabWidget->widget(index); TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); + + if (auto terminal = currentTerminal()) { + terminal->setFocus(); + } + emit navigateStateUpdate(); } From e045c643c3e854b3cd0ec736c1aa40c14984f60c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 14:51:24 +0100 Subject: [PATCH 0361/1447] Terminal: Support Alt+Left / Alt+Right cursor move Fixes: QTCREATORBUG-28941 Change-Id: I7c8e012733f6dcb2851e8e1b840d53317e413cd8 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalcommands.cpp | 21 ++++++++++++++++++++- src/plugins/terminal/terminalcommands.h | 2 ++ src/plugins/terminal/terminalwidget.cpp | 12 ++++++++++++ src/plugins/terminal/terminalwidget.h | 3 +++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp index 28b8583c93a..2bfb9ce5199 100644 --- a/src/plugins/terminal/terminalcommands.cpp +++ b/src/plugins/terminal/terminalcommands.cpp @@ -18,6 +18,8 @@ namespace Terminal { constexpr char COPY[] = "Terminal.Copy"; constexpr char PASTE[] = "Terminal.Paste"; constexpr char CLEARSELECTION[] = "Terminal.ClearSelection"; +constexpr char MOVECURSORWORDLEFT[] = "Terminal.MoveCursorWordLeft"; +constexpr char MOVECURSORWORDRIGHT[] = "Terminal.MoveCursorWordRight"; constexpr char NEWTERMINAL[] = "Terminal.NewTerminal"; constexpr char CLOSETERMINAL[] = "Terminal.CloseTerminal"; @@ -60,6 +62,16 @@ void TerminalCommands::initWidgetActions(const Core::Context &context) CLEARSELECTION); command->setDefaultKeySequence(QKeySequence("Esc")); m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_widgetActions.moveCursorWordLeft, + MOVECURSORWORDLEFT); + command->setDefaultKeySequence(QKeySequence("Alt+Left")); + m_commands.push_back(command); + + command = ActionManager::instance()->registerAction(&m_widgetActions.moveCursorWordRight, + MOVECURSORWORDRIGHT); + command->setDefaultKeySequence(QKeySequence("Alt+Right")); + m_commands.push_back(command); } void TerminalCommands::initPaneActions(const Core::Context &context) @@ -113,12 +125,19 @@ void TerminalCommands::initGlobalCommands() bool TerminalCommands::triggerAction(QKeyEvent *event) { + QKeyCombination combination = event->keyCombination(); + + // On macOS, the arrow keys include the KeypadModifier, which we don't want. + if (HostOsInfo::isMacHost() && combination.keyboardModifiers() & Qt::KeypadModifier) + combination = QKeyCombination(combination.keyboardModifiers() & ~Qt::KeypadModifier, + combination.key()); + for (const auto &command : TerminalCommands::instance().m_commands) { if (!command->action()->isEnabled()) continue; for (const auto &shortcut : command->keySequences()) { - const auto result = shortcut.matches(QKeySequence(event->keyCombination())); + const auto result = shortcut.matches(QKeySequence(combination)); if (result == QKeySequence::ExactMatch) { command->action()->trigger(); return true; diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h index 795e5188acd..5257913fba7 100644 --- a/src/plugins/terminal/terminalcommands.h +++ b/src/plugins/terminal/terminalcommands.h @@ -21,6 +21,8 @@ struct WidgetActions QAction paste{Tr::tr("Paste")}; QAction clearSelection{Tr::tr("Clear Selection")}; QAction clearTerminal{Tr::tr("Clear Terminal")}; + QAction moveCursorWordLeft{Tr::tr("Move Cursor Word Left")}; + QAction moveCursorWordRight{Tr::tr("Move Cursor Word Right")}; }; struct PaneActions diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 50f4ac0c1c6..0e133b73472 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -234,6 +234,8 @@ void TerminalWidget::setupActions() connect(&a.paste, &QAction::triggered, this, ifHasFocus(&TerminalWidget::pasteFromClipboard)); connect(&a.clearSelection, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearSelection)); connect(&a.clearTerminal, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearContents)); + connect(&a.moveCursorWordLeft, &QAction::triggered, this, ifHasFocus(&TerminalWidget::moveCursorWordLeft)); + connect(&a.moveCursorWordRight, &QAction::triggered, this, ifHasFocus(&TerminalWidget::moveCursorWordRight)); // clang-format on } @@ -402,6 +404,16 @@ void TerminalWidget::zoomOut() setFont(m_font); } +void TerminalWidget::moveCursorWordLeft() +{ + writeToPty("\x1b\x62"); +} + +void TerminalWidget::moveCursorWordRight() +{ + writeToPty("\x1b\x66"); +} + void TerminalWidget::clearContents() { m_surface->clearAll(); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 997abda13dd..95f80d687ce 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -37,6 +37,9 @@ public: void zoomIn(); void zoomOut(); + void moveCursorWordLeft(); + void moveCursorWordRight(); + void clearContents(); struct Selection From 1c099b2bd2072a319139d96653f0fc9ae4b9e384 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 15:04:28 +0100 Subject: [PATCH 0362/1447] Terminal: Use current dir for links Fixes: QTCREATORBUG-28942 Change-Id: I424676d3ef3395eead9c4c0c0e826e1c44500b40 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 0e133b73472..d1319fe8c13 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -1180,7 +1180,10 @@ void TerminalWidget::checkLinkAt(const QPoint &pos) t = QDir::homePath() + t.mid(1); } - const Link link = Link::fromString(t, true); + Link link = Link::fromString(t, true); + + if (!link.targetFilePath.isAbsolutePath()) + link.targetFilePath = m_cwd.pathAppended(link.targetFilePath.path()); if (link.hasValidTarget() && (link.targetFilePath.scheme().toString().startsWith("http") From 7fe4fde8862160b4e1c97bc6289873a5b05023fd Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 15:04:02 +0100 Subject: [PATCH 0363/1447] Terminal: Open directory links in navigation Fixes: QTCREATORBUG-28938 Change-Id: If49def66501ff29f72d8a92e3971da6be5d93367 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index d1319fe8c13..c517d29735b 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -8,6 +8,7 @@ #include "terminalsurface.h" #include +#include #include #include @@ -1069,7 +1070,10 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) return; } - Core::EditorManager::openEditorAt(m_linkSelection->link); + if (m_linkSelection->link.targetFilePath.isDir()) + Core::FileUtils::showInFileSystemView(m_linkSelection->link.targetFilePath); + else + Core::EditorManager::openEditorAt(m_linkSelection->link); } return; } From 8432760f9aff6c0edeba108da887c5c76e29e3e3 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 22 Mar 2023 16:13:40 +0100 Subject: [PATCH 0364/1447] Android: Make QRegularExpressions static const Change-Id: I76653261c47a91dc5c3e3368e1961774917bc741 Reviewed-by: Assam Boudjelthia Reviewed-by: --- src/plugins/android/androidbuildapkstep.cpp | 5 +++-- src/plugins/android/androidconfigurations.cpp | 4 ++-- src/plugins/android/androidcreatekeystorecertificate.cpp | 3 ++- src/plugins/android/androiddeployqtstep.cpp | 3 ++- src/plugins/android/androidsdkmanager.cpp | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index adf96eb68d7..789e6c92fd7 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -863,7 +863,7 @@ void AndroidBuildApkStep::updateBuildToolsVersionInJsonFile() if (!contents) return; - QRegularExpression regex(QLatin1String("\"sdkBuildToolsRevision\":.\"[0-9.]+\"")); + static const QRegularExpression regex(R"("sdkBuildToolsRevision":."[0-9.]+")"); QRegularExpressionMatch match = regex.match(QString::fromUtf8(contents.value())); const QString version = buildToolsVersion().toString(); if (match.hasMatch() && !version.isEmpty()) { @@ -925,7 +925,8 @@ void AndroidBuildApkStep::setBuildToolsVersion(const QVersionNumber &version) void AndroidBuildApkStep::stdError(const QString &output) { QString newOutput = output; - newOutput.remove(QRegularExpression("^(\\n)+")); + static const QRegularExpression re("^(\\n)+"); + newOutput.remove(re); if (newOutput.isEmpty()) return; diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 530a0bb6bd4..4616cff2aed 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -306,7 +306,7 @@ void AndroidConfig::parseDependenciesJson() auto fillQtVersionsRange = [](const QString &shortVersion) { QList versions; - const QRegularExpression re(R"(([0-9]\.[0-9]+\.)\[([0-9]+)\-([0-9]+)\])"); + static const QRegularExpression re(R"(([0-9]\.[0-9]+\.)\[([0-9]+)\-([0-9]+)\])"); QRegularExpressionMatch match = re.match(shortVersion); if (match.hasMatch() && match.lastCapturedIndex() == 3) for (int i = match.captured(2).toInt(); i <= match.captured(3).toInt(); ++i) @@ -892,7 +892,7 @@ QVersionNumber AndroidConfig::ndkVersion(const FilePath &ndkPath) // r6a // r10e (64 bit) QString content = QString::fromUtf8(reader.data()); - QRegularExpression re("(r)(?[0-9]{1,2})(?[a-z]{1,1})"); + static const QRegularExpression re("(r)(?[0-9]{1,2})(?[a-z]{1,1})"); QRegularExpressionMatch match = re.match(content); if (match.hasMatch()) { QString major = match.captured("major"); diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp index 003eb7e9b98..e6537b8a27f 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/androidcreatekeystorecertificate.cpp @@ -217,7 +217,8 @@ bool AndroidCreateKeystoreCertificate::checkCertificateAlias() bool AndroidCreateKeystoreCertificate::checkCountryCode() { - if (!m_countryLineEdit->text().contains(QRegularExpression("[A-Z]{2}"))) { + static const QRegularExpression re("[A-Z]{2}"); + if (!m_countryLineEdit->text().contains(re)) { m_infoLabel->show(); m_infoLabel->setText(Tr::tr("Invalid country code.")); return false; diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 1389f0b1007..88092aef529 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -620,7 +620,8 @@ void AndroidDeployQtStep::stdError(const QString &line) emit addOutput(line, BuildStep::OutputFormat::Stderr, BuildStep::DontAppendNewline); QString newOutput = line; - newOutput.remove(QRegularExpression("^(\\n)+")); + static const QRegularExpression re("^(\\n)+"); + newOutput.remove(re); if (newOutput.isEmpty()) return; diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index cb46f39ab75..af5fde48bea 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -549,7 +549,7 @@ void AndroidSdkManagerPrivate::getPendingLicense(SdkCmdPromise &fi) } else if (assertionFound) { // The first assertion is to start reviewing licenses. Always accept. reviewingLicenses = true; - QRegularExpression reg("(\\d+\\sof\\s)(?\\d+)"); + static const QRegularExpression reg(R"((\d+\sof\s)(?\d+))"); QRegularExpressionMatch match = reg.match(stdOut); if (match.hasMatch()) steps = match.captured("steps").toInt(); From 8064496f4e6fdc24c8bfbf363a0258d80aa06304 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 15:06:40 +0100 Subject: [PATCH 0365/1447] Terminal: Always show tabs Fixes: QTCREATORBUG-28944 Change-Id: I59242eb08999ca9bd25363c144c05f29f36cbc54 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalpane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 27b512b92e3..e796bb98229 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -189,7 +189,7 @@ QWidget *TerminalPane::outputWidget(QWidget *parent) { if (!m_widgetInitialized) { m_widgetInitialized = true; - m_tabWidget->setTabBarAutoHide(true); + m_tabWidget->setTabBarAutoHide(false); m_tabWidget->setDocumentMode(true); m_tabWidget->setTabsClosable(true); m_tabWidget->setMovable(true); From 48850026136b54ca53122261d37bc64ddc287a72 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 16:05:20 +0100 Subject: [PATCH 0366/1447] ProjectExplorer: Code cosmetics Amends 29873068eb88. Change-Id: I353a591b6199422886473e6ae94920e6f4097ce6 Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/plugins/projectexplorer/devicesupport/idevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 2497bdcc452..2dc75a36980 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -221,7 +221,7 @@ public: virtual bool prepareForBuild(const Target *target); virtual std::optional clangdExecutable() const; - virtual void checkOsType(){}; + virtual void checkOsType() {} protected: IDevice(); From 875dc22ef43304cda057d747b50ce080bdbaad4b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 24 Mar 2023 06:53:02 +0100 Subject: [PATCH 0367/1447] Terminal: Do not use plugin tr includes inside header ...to avoid accidently including it elsewhere and using a different Tr::tr() in turn. Amends a485f18a941. Change-Id: Iee5b6626ebf53cd2c18833f48ca1a603c3cbff8b Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalcommands.h | 27 +++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h index 5257913fba7..613d0d98229 100644 --- a/src/plugins/terminal/terminalcommands.h +++ b/src/plugins/terminal/terminalcommands.h @@ -3,9 +3,8 @@ #pragma once -#include "terminaltr.h" - #include +#include #include namespace Core { @@ -17,21 +16,23 @@ namespace Terminal { struct WidgetActions { - QAction copy{Tr::tr("Copy")}; - QAction paste{Tr::tr("Paste")}; - QAction clearSelection{Tr::tr("Clear Selection")}; - QAction clearTerminal{Tr::tr("Clear Terminal")}; - QAction moveCursorWordLeft{Tr::tr("Move Cursor Word Left")}; - QAction moveCursorWordRight{Tr::tr("Move Cursor Word Right")}; + QAction copy{QCoreApplication::translate("QtC::Terminal", "Copy")}; + QAction paste{QCoreApplication::translate("QtC::Terminal", "Paste")}; + QAction clearSelection{QCoreApplication::translate("QtC::Terminal", "Clear Selection")}; + QAction clearTerminal{QCoreApplication::translate("QtC::Terminal", "Clear Terminal")}; + QAction moveCursorWordLeft{QCoreApplication::translate("QtC::Terminal", + "Move Cursor Word Left")}; + QAction moveCursorWordRight{QCoreApplication::translate("QtC::Terminal", + "Move Cursor Word Right")}; }; struct PaneActions { - QAction newTerminal{Tr::tr("New Terminal")}; - QAction closeTerminal{Tr::tr("Close Terminal")}; - QAction nextTerminal{Tr::tr("Next Terminal")}; - QAction prevTerminal{Tr::tr("Previous Terminal")}; - QAction minMax{Tr::tr("Minimize/Maximize Terminal")}; + QAction newTerminal{QCoreApplication::translate("QtC::Terminal", "New Terminal")}; + QAction closeTerminal{QCoreApplication::translate("QtC::Terminal", "Close Terminal")}; + QAction nextTerminal{QCoreApplication::translate("QtC::Terminal", "Next Terminal")}; + QAction prevTerminal{QCoreApplication::translate("QtC::Terminal", "Previous Terminal")}; + QAction minMax{QCoreApplication::translate("QtC::Terminal", "Minimize/Maximize Terminal")}; }; class TerminalCommands From 8af05292e731dac71b119ecbefde21512598e275 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 24 Mar 2023 07:36:20 +0100 Subject: [PATCH 0368/1447] Terminal: Fix Qbs build Amends a485f18a941. Change-Id: I107d142b4d1e4ca427d5d52af7bdfc102accae2e Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminal.qbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 982a89bcb2a..29c3c90e313 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -22,6 +22,8 @@ QtcPlugin { "shellintegration.cpp", "shellintegration.h", "terminal.qrc", + "terminalcommands.cpp", + "terminalcommands.h", "terminalpane.cpp", "terminalpane.h", "terminalplugin.cpp", From ae4e1782214b3284cd8cf8b842909ffa6e2d3aaa Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 12:40:20 +0100 Subject: [PATCH 0369/1447] Utils: Move the CommandLine destructor out-of-line Not really cheap and bloats the user code. Change-Id: I2039794f0608838d97b404bb7d92b489d22f2cbe Reviewed-by: Christian Stenger Reviewed-by: --- src/libs/utils/commandline.cpp | 2 ++ src/libs/utils/commandline.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index e19eafa4c15..9f6fdec35d1 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -1409,6 +1409,8 @@ CommandLine::CommandLine(const FilePath &executable) : m_executable(executable) {} +CommandLine::~CommandLine() = default; + CommandLine::CommandLine(const FilePath &exe, const QStringList &args) : m_executable(exe) { diff --git a/src/libs/utils/commandline.h b/src/libs/utils/commandline.h index c3aa17c7d85..d7fc0a066be 100644 --- a/src/libs/utils/commandline.h +++ b/src/libs/utils/commandline.h @@ -119,6 +119,8 @@ public: enum RawType { Raw }; CommandLine(); + ~CommandLine(); + explicit CommandLine(const FilePath &executable); CommandLine(const FilePath &exe, const QStringList &args); CommandLine(const FilePath &exe, const QStringList &args, OsType osType); From 2766b4004b69377480f9e3a701fd20eb51b578bd Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 26 Jan 2023 17:48:36 +0100 Subject: [PATCH 0370/1447] Utils: Continue Environment/EnvironmentChange consolidation Make Environment a stack of changes that gets "expanded" to a full environment before things are actively accessed. Later this expansion should be done lazily if possible. Task-number: QTCREATORBUG-28357 Change-Id: If1c7bfdb9f58b81e71c51ed87ee75d6964a47019 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- share/qtcreator/debugger/creatortypes.py | 4 +- src/libs/utils/aspects.cpp | 15 +- src/libs/utils/aspects.h | 1 - src/libs/utils/environment.cpp | 255 +++++++++++++----- src/libs/utils/environment.h | 94 +++---- src/libs/utils/filepath.h | 1 - src/libs/utils/launchersocket.cpp | 2 + src/libs/utils/pathchooser.cpp | 14 +- src/libs/utils/pathchooser.h | 2 - src/libs/utils/qtcprocess.cpp | 29 +- .../cmakeprojectmanager/presetsparser.cpp | 14 +- src/plugins/coreplugin/systemsettings.cpp | 6 +- .../runconfigurationaspects.cpp | 13 +- .../projectexplorer/runconfigurationaspects.h | 1 - src/plugins/remotelinux/linuxdevice.cpp | 10 +- src/plugins/vcsbase/commonvcssettings.cpp | 6 +- 16 files changed, 261 insertions(+), 206 deletions(-) diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py index af790544601..a11377b0db5 100644 --- a/share/qtcreator/debugger/creatortypes.py +++ b/share/qtcreator/debugger/creatortypes.py @@ -235,7 +235,7 @@ def qdump__Utils__Port(d, value): -def qdump__Utils__Environment(d, value): +def x_qdump__Utils__Environment(d, value): qdump__Utils__NameValueDictionary(d, value) @@ -243,7 +243,7 @@ def qdump__Utils__DictKey(d, value): d.putStringValue(value["name"]) -def qdump__Utils__NameValueDictionary(d, value): +def x_qdump__Utils__NameValueDictionary(d, value): dptr = d.extractPointer(value) if d.qtVersion() >= 0x60000: if dptr == 0: diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 51be951a8fe..aed8c851d17 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -632,7 +632,7 @@ public: QString m_placeHolderText; QString m_historyCompleterKey; PathChooser::Kind m_expectedKind = PathChooser::File; - EnvironmentChange m_environmentChange; + Environment m_environment; QPointer m_labelDisplay; QPointer m_lineEditDisplay; QPointer m_pathChooserDisplay; @@ -975,16 +975,11 @@ void StringAspect::setExpectedKind(const PathChooser::Kind expectedKind) d->m_pathChooserDisplay->setExpectedKind(expectedKind); } -void StringAspect::setEnvironmentChange(const EnvironmentChange &change) -{ - d->m_environmentChange = change; - if (d->m_pathChooserDisplay) - d->m_pathChooserDisplay->setEnvironmentChange(change); -} - void StringAspect::setEnvironment(const Environment &env) { - setEnvironmentChange(EnvironmentChange::fromDictionary(env.toDictionary())); + d->m_environment = env; + if (d->m_pathChooserDisplay) + d->m_pathChooserDisplay->setEnvironment(env); } void StringAspect::setBaseFileName(const FilePath &baseFileName) @@ -1082,7 +1077,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) d->m_pathChooserDisplay->setHistoryCompleter(d->m_historyCompleterKey); if (d->m_validator) d->m_pathChooserDisplay->setValidationFunction(d->m_validator); - d->m_pathChooserDisplay->setEnvironmentChange(d->m_environmentChange); + d->m_pathChooserDisplay->setEnvironment(d->m_environment); d->m_pathChooserDisplay->setBaseDirectory(d->m_baseFileName); d->m_pathChooserDisplay->setOpenTerminalHandler(d->m_openTerminal); if (defaultValue() == value()) diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 1aaaca3f299..0b9a5606596 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -383,7 +383,6 @@ public: void setPlaceHolderText(const QString &placeHolderText); void setHistoryCompleter(const QString &historyCompleterKey); void setExpectedKind(const PathChooser::Kind expectedKind); - void setEnvironmentChange(const EnvironmentChange &change); void setEnvironment(const Environment &env); void setBaseFileName(const FilePath &baseFileName); void setUndoRedoEnabled(bool readOnly); diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 462eeab31d7..e64db0e2a32 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -19,84 +19,137 @@ Q_GLOBAL_STATIC_WITH_ARGS(Environment, staticSystemEnvironment, (QProcessEnvironment::systemEnvironment().toStringList())) Q_GLOBAL_STATIC(QVector, environmentProviders) +Environment::Environment() + : m_dict(HostOsInfo::hostOs()) +{} + +Environment::Environment(OsType osType) + : m_dict(osType) +{} + +Environment::Environment(const QStringList &env, OsType osType) + : m_dict(osType) +{ + m_changeItems.append(NameValueDictionary(env, osType)); +} + +Environment::Environment(const NameValuePairs &nameValues) +{ + m_changeItems.append(NameValueDictionary(nameValues)); +} + +Environment::Environment(const NameValueDictionary &dict) +{ + m_changeItems.append(dict); +} + NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepend) const { - return m_dict.diff(other.m_dict, checkAppendPrepend); + const NameValueDictionary &dict = resolved(); + const NameValueDictionary &otherDict = other.resolved(); + return dict.diff(otherDict, checkAppendPrepend); } Environment::FindResult Environment::find(const QString &name) const { - const auto it = m_dict.constFind(name); - if (it == m_dict.constEnd()) + const NameValueDictionary &dict = resolved(); + const auto it = dict.constFind(name); + if (it == dict.constEnd()) return {}; return Entry{it.key().name, it.value().first, it.value().second}; } void Environment::forEachEntry(const std::function &callBack) const { - for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) + const NameValueDictionary &dict = resolved(); + for (auto it = dict.m_values.constBegin(); it != dict.m_values.constEnd(); ++it) callBack(it.key().name, it.value().first, it.value().second); } +bool Environment::operator==(const Environment &other) const +{ + const NameValueDictionary &dict = resolved(); + const NameValueDictionary &otherDict = other.resolved(); + return dict == otherDict; +} + +bool Environment::operator!=(const Environment &other) const +{ + const NameValueDictionary &dict = resolved(); + const NameValueDictionary &otherDict = other.resolved(); + return dict != otherDict; +} + +QString Environment::value(const QString &key) const +{ + const NameValueDictionary &dict = resolved(); + return dict.value(key); +} + +QString Environment::value_or(const QString &key, const QString &defaultValue) const +{ + const NameValueDictionary &dict = resolved(); + return dict.hasKey(key) ? dict.value(key) : defaultValue; +} + +bool Environment::hasKey(const QString &key) const +{ + const NameValueDictionary &dict = resolved(); + return dict.hasKey(key); +} + bool Environment::hasChanges() const { - return m_dict.size() != 0; + const NameValueDictionary &dict = resolved(); + return dict.size() != 0; +} + +OsType Environment::osType() const +{ + return m_dict.m_osType; +} + +QStringList Environment::toStringList() const +{ + const NameValueDictionary &dict = resolved(); + return dict.toStringList(); } QProcessEnvironment Environment::toProcessEnvironment() const { + const NameValueDictionary &dict = resolved(); QProcessEnvironment result; - for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) { + for (auto it = dict.m_values.constBegin(); it != dict.m_values.constEnd(); ++it) { if (it.value().second) - result.insert(it.key().name, expandedValueForKey(m_dict.key(it))); + result.insert(it.key().name, expandedValueForKey(dict.key(it))); } return result; } void Environment::appendOrSetPath(const FilePath &value) { - QTC_CHECK(value.osType() == osType()); + QTC_CHECK(value.osType() == m_dict.m_osType); if (value.isEmpty()) return; - appendOrSet("PATH", value.nativePath(), - QString(OsSpecificAspects::pathListSeparator(osType()))); + appendOrSet("PATH", value.nativePath(), OsSpecificAspects::pathListSeparator(osType())); } void Environment::prependOrSetPath(const FilePath &value) { - QTC_CHECK(value.osType() == osType()); + QTC_CHECK(value.osType() == m_dict.m_osType); if (value.isEmpty()) return; - prependOrSet("PATH", value.nativePath(), - QString(OsSpecificAspects::pathListSeparator(osType()))); + prependOrSet("PATH", value.nativePath(), OsSpecificAspects::pathListSeparator(osType())); } void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep) { - QTC_ASSERT(!key.contains('='), return ); - const auto it = m_dict.findKey(key); - if (it == m_dict.m_values.end()) { - m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); - } else { - // Append unless it is already there - const QString toAppend = sep + value; - if (!it.value().first.endsWith(toAppend)) - it.value().first.append(toAppend); - } + addItem(Item{std::in_place_index_t(), key, value, sep}); } void Environment::prependOrSet(const QString &key, const QString &value, const QString &sep) { - QTC_ASSERT(!key.contains('='), return ); - const auto it = m_dict.findKey(key); - if (it == m_dict.m_values.end()) { - m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); - } else { - // Prepend unless it is already there - const QString toPrepend = value + sep; - if (!it.value().first.startsWith(toPrepend)) - it.value().first.prepend(toPrepend); - } + addItem(Item{std::in_place_index_t(), key, value, sep}); } void Environment::prependOrSetLibrarySearchPath(const FilePath &value) @@ -105,11 +158,11 @@ void Environment::prependOrSetLibrarySearchPath(const FilePath &value) switch (osType()) { case OsTypeWindows: { const QChar sep = ';'; - prependOrSet("PATH", value.nativePath(), QString(sep)); + prependOrSet("PATH", value.nativePath(), sep); break; } case OsTypeMac: { - const QString sep = ":"; + const QChar sep = ':'; const QString nativeValue = value.nativePath(); prependOrSet("DYLD_LIBRARY_PATH", nativeValue, sep); prependOrSet("DYLD_FRAMEWORK_PATH", nativeValue, sep); @@ -118,7 +171,7 @@ void Environment::prependOrSetLibrarySearchPath(const FilePath &value) case OsTypeLinux: case OsTypeOtherUnix: { const QChar sep = ':'; - prependOrSet("LD_LIBRARY_PATH", value.nativePath(), QString(sep)); + prependOrSet("LD_LIBRARY_PATH", value.nativePath(), sep); break; } default: @@ -141,8 +194,7 @@ Environment Environment::systemEnvironment() void Environment::setupEnglishOutput() { - m_dict.set("LC_MESSAGES", "en_US.utf8"); - m_dict.set("LANGUAGE", "en_US:en"); + addItem(Item{std::in_place_index_t()}); } using SearchResultCallback = std::function; @@ -190,7 +242,8 @@ static FilePaths appendExeExtensions(const Environment &env, const FilePath &exe QString Environment::expandedValueForKey(const QString &key) const { - return expandVariables(m_dict.value(key)); + const NameValueDictionary &dict = resolved(); + return expandVariables(dict.value(key)); } static void searchInDirectoriesHelper(const SearchResultCallback &resultCallback, @@ -324,14 +377,16 @@ void Environment::setSystemEnvironment(const Environment &environment) */ QString Environment::expandVariables(const QString &input) const { + const NameValueDictionary &dict = resolved(); + QString result = input; if (osType() == OsTypeWindows) { for (int vStart = -1, i = 0; i < result.length(); ) { if (result.at(i++) == '%') { if (vStart > 0) { - const auto it = m_dict.findKey(result.mid(vStart, i - vStart - 1)); - if (it != m_dict.m_values.constEnd()) { + const auto it = dict.findKey(result.mid(vStart, i - vStart - 1)); + if (it != dict.m_values.constEnd()) { result.replace(vStart - 1, i - vStart + 1, it->first); i = vStart - 1 + it->first.length(); vStart = -1; @@ -403,6 +458,12 @@ QStringList Environment::expandVariables(const QStringList &variables) const return transform(variables, [this](const QString &i) { return expandVariables(i); }); } +NameValueDictionary Environment::toDictionary() const +{ + const NameValueDictionary &dict = resolved(); + return dict; +} + void EnvironmentProvider::addProvider(EnvironmentProvider &&provider) { environmentProviders->append(std::move(provider)); @@ -421,63 +482,125 @@ std::optional EnvironmentProvider::provider(const QByteArra return std::nullopt; } -void EnvironmentChange::addSetValue(const QString &key, const QString &value) +void Environment::addItem(const Item &item) { - m_changeItems.append(Item{std::in_place_index_t(), QPair{key, value}}); + m_dict.clear(); + m_changeItems.append(item); } -void EnvironmentChange::addUnsetValue(const QString &key) +void Environment::set(const QString &key, const QString &value, bool enabled) { - m_changeItems.append(Item{std::in_place_index_t(), key}); + addItem(Item{std::in_place_index_t(), + std::tuple{key, value, enabled}}); } -void EnvironmentChange::addPrependToPath(const FilePaths &values) +void Environment::unset(const QString &key) { + addItem(Item{std::in_place_index_t(), key}); +} + +void Environment::modify(const NameValueItems &items) +{ + addItem(Item{std::in_place_index_t(), items}); +} + +void Environment::prependToPath(const FilePaths &values) +{ + m_dict.clear(); for (int i = values.size(); --i >= 0; ) { const FilePath value = values.at(i); - m_changeItems.append(Item{std::in_place_index_t(), value}); + m_changeItems.append(Item{ + std::in_place_index_t(), + QString("PATH"), + value.nativePath(), + value.pathListSeparator() + }); } } -void EnvironmentChange::addAppendToPath(const FilePaths &values) +void Environment::appendToPath(const FilePaths &values) { - for (const FilePath &value : values) - m_changeItems.append(Item{std::in_place_index_t(), value}); + m_dict.clear(); + for (const FilePath &value : values) { + m_changeItems.append(Item{ + std::in_place_index_t(), + QString("PATH"), + value.nativePath(), + value.pathListSeparator() + }); + } } -EnvironmentChange EnvironmentChange::fromDictionary(const NameValueDictionary &dict) +const NameValueDictionary &Environment::resolved() const { - EnvironmentChange change; - change.m_changeItems.append(Item{std::in_place_index_t(), dict}); - return change; -} + if (m_dict.size() != 0) + return m_dict; -void EnvironmentChange::applyToEnvironment(Environment &env) const -{ for (const Item &item : m_changeItems) { switch (item.index()) { case SetSystemEnvironment: - env = Environment::systemEnvironment(); + m_dict = Environment::systemEnvironment().toDictionary(); break; case SetFixedDictionary: - env = Environment(std::get(item)); + m_dict = std::get(item); break; case SetValue: { - const QPair data = std::get(item); - env.set(data.first, data.second); + auto [key, value, enabled] = std::get(item); + m_dict.set(key, value, enabled); break; } case UnsetValue: - env.unset(std::get(item)); + m_dict.unset(std::get(item)); break; - case PrependToPath: - env.prependOrSetPath(std::get(item)); + case PrependOrSet: { + auto [key, value, sep] = std::get(item); + QTC_ASSERT(!key.contains('='), return m_dict); + const auto it = m_dict.findKey(key); + if (it == m_dict.m_values.end()) { + m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); + } else { + // Prepend unless it is already there + const QString toPrepend = value + sep; + if (!it.value().first.startsWith(toPrepend)) + it.value().first.prepend(toPrepend); + } break; - case AppendToPath: - env.appendOrSetPath(std::get(item)); + } + case AppendOrSet: { + auto [key, value, sep] = std::get(item); + QTC_ASSERT(!key.contains('='), return m_dict); + const auto it = m_dict.findKey(key); + if (it == m_dict.m_values.end()) { + m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); + } else { + // Prepend unless it is already there + const QString toAppend = sep + value; + if (!it.value().first.endsWith(toAppend)) + it.value().first.append(toAppend); + } + break; + } + case Modify: { + NameValueItems items = std::get(item); + m_dict.modify(items); + break; + } + case SetupEnglishOutput: + m_dict.set("LC_MESSAGES", "en_US.utf8"); + m_dict.set("LANGUAGE", "en_US:en"); break; } } + + return m_dict; +} + +Environment Environment::appliedToEnvironment(const Environment &base) const +{ + Environment res = base; + res.m_dict.clear(); + res.m_changeItems.append(m_changeItems); + return res; } /*! diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 541a730965b..8424eb1d24b 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -22,27 +22,24 @@ namespace Utils { class QTCREATOR_UTILS_EXPORT Environment final { public: - Environment() : m_dict(HostOsInfo::hostOs()) {} - explicit Environment(OsType osType) : m_dict(osType) {} - explicit Environment(const QStringList &env, OsType osType = HostOsInfo::hostOs()) - : m_dict(env, osType) {} - explicit Environment(const NameValuePairs &nameValues) : m_dict(nameValues) {} - explicit Environment(const NameValueDictionary &dict) : m_dict(dict) {} + Environment(); + explicit Environment(OsType osType); + explicit Environment(const QStringList &env, OsType osType = HostOsInfo::hostOs()); + explicit Environment(const NameValuePairs &nameValues); + explicit Environment(const NameValueDictionary &dict); - QString value(const QString &key) const { return m_dict.value(key); } - QString value_or(const QString &key, const QString &defaultValue) const - { - return m_dict.hasKey(key) ? m_dict.value(key) : defaultValue; - } - bool hasKey(const QString &key) const { return m_dict.hasKey(key); } + QString value(const QString &key) const; + QString value_or(const QString &key, const QString &defaultValue) const; + bool hasKey(const QString &key) const; - void set(const QString &key, const QString &value, bool enabled = true) { m_dict.set(key, value, enabled); } - void unset(const QString &key) { m_dict.unset(key); } - void modify(const NameValueItems &items) { m_dict.modify(items); } + void set(const QString &key, const QString &value, bool enabled = true); + void unset(const QString &key); + void modify(const NameValueItems &items); bool hasChanges() const; - QStringList toStringList() const { return m_dict.toStringList(); } + OsType osType() const; + QStringList toStringList() const; QProcessEnvironment toProcessEnvironment() const; void appendOrSet(const QString &key, const QString &value, const QString &sep = QString()); @@ -54,6 +51,9 @@ public: void prependOrSetLibrarySearchPath(const FilePath &value); void prependOrSetLibrarySearchPaths(const FilePaths &values); + void prependToPath(const FilePaths &values); + void appendToPath(const FilePaths &values); + void setupEnglishOutput(); FilePath searchInPath(const QString &executable, @@ -74,76 +74,58 @@ public: FilePath expandVariables(const FilePath &input) const; QStringList expandVariables(const QStringList &input) const; - OsType osType() const { return m_dict.osType(); } - - NameValueDictionary toDictionary() const { return m_dict; } // FIXME: avoid + NameValueDictionary toDictionary() const; // FIXME: avoid NameValueItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid - void setCombineWithDeviceEnvironment(bool combine) { m_combineWithDeviceEnvironment = combine; } - bool combineWithDeviceEnvironment() const { return m_combineWithDeviceEnvironment; } - struct Entry { QString key; QString value; bool enabled; }; using FindResult = std::optional; FindResult find(const QString &name) const; // Note res->key may differ in case from name. void forEachEntry(const std::function &callBack) const; - friend bool operator!=(const Environment &first, const Environment &second) - { - return first.m_dict != second.m_dict; - } - - friend bool operator==(const Environment &first, const Environment &second) - { - return first.m_dict == second.m_dict; - } + bool operator!=(const Environment &other) const; + bool operator==(const Environment &other) const; static Environment systemEnvironment(); static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!! static void setSystemEnvironment(const Environment &environment); // don't use at all!!! -private: - NameValueDictionary m_dict; - bool m_combineWithDeviceEnvironment = true; -}; - -class QTCREATOR_UTILS_EXPORT EnvironmentChange final -{ -public: - EnvironmentChange() = default; - enum Type { SetSystemEnvironment, SetFixedDictionary, SetValue, UnsetValue, - PrependToPath, - AppendToPath, + PrependOrSet, + AppendOrSet, + Modify, + SetupEnglishOutput, }; using Item = std::variant< - std::monostate, // SetSystemEnvironment dummy - NameValueDictionary, // SetFixedDictionary - QPair, // SetValue - QString, // UnsetValue - FilePath, // PrependToPath - FilePath // AppendToPath + std::monostate, // SetSystemEnvironment dummy + NameValueDictionary, // SetFixedDictionary + std::tuple, // SetValue (key, value, enabled) + QString, // UnsetValue (key) + std::tuple, // PrependOrSet (key, value, separator) + std::tuple, // AppendOrSet (key, value, separator) + NameValueItems, // Modify + std::monostate // SetupEnglishOutput >; - static EnvironmentChange fromDictionary(const NameValueDictionary &dict); + void addItem(const Item &item); - void applyToEnvironment(Environment &) const; + Environment appliedToEnvironment(const Environment &base) const; - void addSetValue(const QString &key, const QString &value); - void addUnsetValue(const QString &key); - void addPrependToPath(const FilePaths &values); - void addAppendToPath(const FilePaths &values); + const NameValueDictionary &resolved() const; private: - QList m_changeItems; + mutable QList m_changeItems; + mutable NameValueDictionary m_dict; // Latest resolved. }; +using EnviromentChange = Environment; + class QTCREATOR_UTILS_EXPORT EnvironmentProvider { public: diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 0ecdc09dab9..220c6de5daa 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -32,7 +32,6 @@ namespace Utils { class DeviceFileAccess; class Environment; -class EnvironmentChange; enum class FileStreamHandle; template using Continuation = std::function; diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index f4feda595a4..ccf2ee7b2f4 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -246,6 +246,8 @@ void CallerHandle::start(const QString &program, const QStringList &arguments) p.command = m_command; p.arguments = m_arguments; p.env = m_setup->m_environment.toStringList(); + if (p.env.isEmpty()) + p.env = Environment::systemEnvironment().toStringList(); p.workingDir = m_setup->m_workingDirectory.path(); p.processMode = m_setup->m_processMode; p.writeData = m_setup->m_writeData; diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 53825931b97..0f0737f54c5 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -171,7 +171,7 @@ public: FilePath m_initialBrowsePathOverride; QString m_defaultValue; FilePath m_baseDirectory; - EnvironmentChange m_environmentChange; + Environment m_environment; BinaryVersionToolTipEventFilter *m_binaryVersionToolTipEventFilter = nullptr; QList m_buttons; const MacroExpander *m_macroExpander = globalMacroExpander(); @@ -196,8 +196,7 @@ FilePath PathChooserPrivate::expandedPath(const FilePath &input) const FilePath path = input; - Environment env = path.deviceEnvironment(); - m_environmentChange.applyToEnvironment(env); + Environment env = m_environment.appliedToEnvironment(path.deviceEnvironment()); path = env.expandVariables(path); if (m_macroExpander) @@ -324,20 +323,15 @@ void PathChooser::setBaseDirectory(const FilePath &base) triggerChanged(); } -void PathChooser::setEnvironment(const Environment &env) -{ - setEnvironmentChange(EnvironmentChange::fromDictionary(env.toDictionary())); -} - FilePath PathChooser::baseDirectory() const { return d->m_baseDirectory; } -void PathChooser::setEnvironmentChange(const EnvironmentChange &env) +void PathChooser::setEnvironment(const Environment &env) { QString oldExpand = filePath().toString(); - d->m_environmentChange = env; + d->m_environment = env; if (filePath().toString() != oldExpand) { triggerChanged(); emit rawPathChanged(); diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h index 92b5973b2de..62a370185da 100644 --- a/src/libs/utils/pathchooser.h +++ b/src/libs/utils/pathchooser.h @@ -20,7 +20,6 @@ namespace Utils { class CommandLine; class MacroExpander; class Environment; -class EnvironmentChange; class PathChooserPrivate; class QTCREATOR_UTILS_EXPORT PathChooser : public QWidget @@ -77,7 +76,6 @@ public: void setBaseDirectory(const FilePath &base); void setEnvironment(const Environment &env); - void setEnvironmentChange(const EnvironmentChange &change); /** Returns the suggested label title when used in a form layout. */ static QString label(); diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 04276a610b9..5220e8b5d56 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -353,13 +353,18 @@ public: return; } + QProcessEnvironment penv = m_setup.m_environment.toProcessEnvironment(); + if (penv.isEmpty()) + penv = Environment::systemEnvironment().toProcessEnvironment(); + const QStringList senv = penv.toStringList(); + bool startResult = m_ptyProcess->startProcess(program, HostOsInfo::isWindowsHost() ? QStringList{m_setup.m_nativeArguments} << arguments : arguments, m_setup.m_workingDirectory.nativePath(), - m_setup.m_environment.toProcessEnvironment().toStringList(), + senv, m_setup.m_ptyData->size().width(), m_setup.m_ptyData->size().height()); @@ -458,7 +463,9 @@ private: handler->setWindowsSpecificStartupFlags(m_setup.m_belowNormalPriority, m_setup.m_createConsoleOnWindows); - m_process->setProcessEnvironment(m_setup.m_environment.toProcessEnvironment()); + const QProcessEnvironment penv = m_setup.m_environment.toProcessEnvironment(); + if (!penv.isEmpty()) + m_process->setProcessEnvironment(penv); m_process->setWorkingDirectory(m_setup.m_workingDirectory.path()); m_process->setStandardInputFile(m_setup.m_standardInputFile); m_process->setProcessChannelMode(m_setup.m_processChannelMode); @@ -715,7 +722,6 @@ public: , q(parent) , m_killTimer(this) { - m_setup.m_controlEnvironment = Environment::systemEnvironment(); m_killTimer.setSingleShot(true); connect(&m_killTimer, &QTimer::timeout, this, [this] { m_killTimer.stop(); @@ -769,22 +775,6 @@ public: return rootCommand; } - Environment fullEnvironment() const - { - Environment env = m_setup.m_environment; - if (!env.hasChanges() && env.combineWithDeviceEnvironment()) { - // FIXME: Either switch to using EnvironmentChange instead of full Environments, or - // feed the full environment into the QtcProcess instead of fixing it up here. - // qWarning("QtcProcess::start: Empty environment set when running '%s'.", - // qPrintable(m_setup.m_commandLine.executable().toString())); - env = m_setup.m_commandLine.executable().deviceEnvironment(); - } - // TODO: needs SshSettings - // if (m_runAsRoot) - // RunControl::provideAskPassEntry(env); - return env; - } - QtcProcess *q; std::unique_ptr m_blockingInterface; std::unique_ptr m_process; @@ -1227,7 +1217,6 @@ void QtcProcess::start() d->m_state = QProcess::Starting; d->m_process->m_setup = d->m_setup; d->m_process->m_setup.m_commandLine = d->fullCommandLine(); - d->m_process->m_setup.m_environment = d->fullEnvironment(); d->emitGuardedSignal(&QtcProcess::starting); d->m_process->start(); } diff --git a/src/plugins/cmakeprojectmanager/presetsparser.cpp b/src/plugins/cmakeprojectmanager/presetsparser.cpp index ceb67a50be7..06c12de8401 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.cpp +++ b/src/plugins/cmakeprojectmanager/presetsparser.cpp @@ -482,16 +482,6 @@ static QHash merge(const QHash &first, return result; } -static Utils::Environment merge(const Utils::Environment &first, const Utils::Environment &second) -{ - Utils::Environment result = first; - second.forEachEntry([&](const QString &key, const QString &value, bool) { - result.set(key, value); - }); - - return result; -} - static CMakeConfig merge(const CMakeConfig &first, const CMakeConfig &second) { return Utils::setUnionMerge( @@ -549,7 +539,7 @@ void PresetsDetails::ConfigurePreset::inheritFrom(const ConfigurePreset &other) if (!environment && other.environment) environment = other.environment; else if (environment && other.environment) - environment = merge(other.environment.value(), environment.value()); + environment = environment.value().appliedToEnvironment(other.environment.value()); if (!warnings && other.warnings) warnings = other.warnings; @@ -575,7 +565,7 @@ void PresetsDetails::BuildPreset::inheritFrom(const BuildPreset &other) if (!environment && other.environment) environment = other.environment; else if (environment && other.environment) - environment = merge(other.environment.value(), environment.value()); + environment = environment.value().appliedToEnvironment(other.environment.value()); if (!configurePreset && other.configurePreset) configurePreset = other.configurePreset; diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index f34e7fb5b70..a65f7fee8b1 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -438,9 +438,9 @@ void SystemSettingsWidget::resetFileBrowser() void SystemSettingsWidget::updatePath() { - EnvironmentChange change; - change.addAppendToPath(VcsManager::additionalToolsPath()); - m_patchChooser->setEnvironmentChange(change); + Environment env; + env.appendToPath(VcsManager::additionalToolsPath()); + m_patchChooser->setEnvironment(env); } void SystemSettingsWidget::updateEnvironmentChangesLabel() diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 9ba24c04672..7e278d353e9 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -570,19 +570,12 @@ void ExecutableAspect::setExpectedKind(const PathChooser::Kind expectedKind) Sets the environment in which paths will be searched when the expected kind of paths is chosen as PathChooser::Command or PathChooser::ExistingCommand to \a env. - - \sa Utils::StringAspect::setEnvironmentChange() */ -void ExecutableAspect::setEnvironmentChange(const EnvironmentChange &change) -{ - m_executable.setEnvironmentChange(change); - if (m_alternativeExecutable) - m_alternativeExecutable->setEnvironmentChange(change); -} - void ExecutableAspect::setEnvironment(const Environment &env) { - setEnvironmentChange(EnvironmentChange::fromDictionary(env.toDictionary())); + m_executable.setEnvironment(env); + if (m_alternativeExecutable) + m_alternativeExecutable->setEnvironment(env); } /*! diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index 9e948bc6ecf..9656c2f5bdb 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -168,7 +168,6 @@ public: void setPlaceHolderText(const QString &placeHolderText); void setHistoryCompleter(const QString &historyCompleterKey); void setExpectedKind(const Utils::PathChooser::Kind expectedKind); - void setEnvironmentChange(const Utils::EnvironmentChange &change); void setEnvironment(const Utils::Environment &env); void setDisplayStyle(Utils::StringAspect::DisplayStyle style); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 191ee9d5d32..aa5889516cc 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -338,9 +338,6 @@ Environment LinuxDevicePrivate::getEnvironment() QtcProcess getEnvProc; getEnvProc.setCommand({FilePath("env").onDevice(q->rootPath()), {}}); - Environment inEnv; - inEnv.setCombineWithDeviceEnvironment(false); - getEnvProc.setEnvironment(inEnv); getEnvProc.runBlocking(); const QString remoteOutput = getEnvProc.cleanedStdOut(); @@ -919,16 +916,11 @@ LinuxDevice::LinuxDevice() d->m_terminals.removeOne(proc); }); - // We recreate the same way that QtcProcess uses to create the actual environment. - const Environment finalEnv = (!env.hasChanges() && env.combineWithDeviceEnvironment()) - ? d->getEnvironment() - : env; // If we will not set any environment variables, we can leave out the shell executable // as the "ssh ..." call will automatically launch the default shell if there are // no arguments. But if we will set environment variables, we need to explicitly // specify the shell executable. - const QString shell = finalEnv.hasChanges() ? finalEnv.value_or("SHELL", "/bin/sh") - : QString(); + const QString shell = env.hasChanges() ? env.value_or("SHELL", "/bin/sh") : QString(); proc->setCommand({filePath(shell), {}}); proc->setTerminalMode(TerminalMode::On); diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 160095d38dc..2f970ccbb83 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -135,9 +135,9 @@ CommonSettingsWidget::CommonSettingsWidget(CommonOptionsPage *page) void CommonSettingsWidget::updatePath() { - EnvironmentChange change; - change.addAppendToPath(Core::VcsManager::additionalToolsPath()); - m_page->settings().sshPasswordPrompt.setEnvironmentChange(change); + Environment env; + env.appendToPath(Core::VcsManager::additionalToolsPath()); + m_page->settings().sshPasswordPrompt.setEnvironment(env); } void CommonSettingsWidget::apply() From f95bd6119aee15e459d1ceadd96604f76b777860 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 23 Mar 2023 16:37:58 +0100 Subject: [PATCH 0371/1447] Terminal: Register the command to open/close the Terminal pane This way Alt+5 (Ctrl+5) would open / close the Terminal pane. Change-Id: I91003987c1b8109abc302a79a895fab1557fefea Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalcommands.cpp | 9 +++++++++ src/plugins/terminal/terminalcommands.h | 2 ++ src/plugins/terminal/terminalpane.cpp | 2 ++ 3 files changed, 13 insertions(+) diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp index 2bfb9ce5199..2bd14090286 100644 --- a/src/plugins/terminal/terminalcommands.cpp +++ b/src/plugins/terminal/terminalcommands.cpp @@ -153,4 +153,13 @@ QAction *TerminalCommands::openSettingsAction() return ActionManager::command("Preferences.Terminal.General")->action(); } +void TerminalCommands::registerOpenCloseTerminalPaneCommand() +{ + Command* terminalCmd = ActionManager::command("QtCreator.Pane.Terminal"); + QTC_ASSERT(terminalCmd, return); + + if (!m_commands.contains(terminalCmd)) + m_commands.append(terminalCmd); +} + } // namespace Terminal diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h index 613d0d98229..59f9add643e 100644 --- a/src/plugins/terminal/terminalcommands.h +++ b/src/plugins/terminal/terminalcommands.h @@ -51,6 +51,8 @@ public: static QAction *openSettingsAction(); + void registerOpenCloseTerminalPaneCommand(); + protected: void initWidgetActions(const Core::Context &context); void initPaneActions(const Core::Context &context); diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index e796bb98229..94a93ed84e4 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -295,6 +295,8 @@ void TerminalPane::setFocus() { if (const auto t = currentTerminal()) t->setFocus(); + + TerminalCommands::instance().registerOpenCloseTerminalPaneCommand(); } bool TerminalPane::hasFocus() const From 83d40683d903000e484303bd93c08ea81a7cca47 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 23 Mar 2023 15:07:44 +0100 Subject: [PATCH 0372/1447] Core: Fix error text color in SearchResultWidget Remove the CanceledSearchTextColor theme role and use TextColorError instead. Change-Id: I3dde538d107ecfdd9c9a3f2406f6cd26ad28c902 Reviewed-by: David Schulz Reviewed-by: --- share/qtcreator/themes/dark.creatortheme | 1 - share/qtcreator/themes/default.creatortheme | 1 - share/qtcreator/themes/design-light.creatortheme | 1 - share/qtcreator/themes/design.creatortheme | 1 - share/qtcreator/themes/flat-dark.creatortheme | 1 - share/qtcreator/themes/flat-light.creatortheme | 1 - share/qtcreator/themes/flat.creatortheme | 1 - src/libs/utils/theme/theme.h | 1 - src/plugins/coreplugin/find/searchresultwidget.cpp | 2 +- 9 files changed, 1 insertion(+), 9 deletions(-) diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index fe8807eab1d..2c00e67971c 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -184,7 +184,6 @@ BadgeLabelBackgroundColorChecked=normalBackground BadgeLabelBackgroundColorUnchecked=selectedBackground BadgeLabelTextColorChecked=text BadgeLabelTextColorUnchecked=text -CanceledSearchTextColor=ff0000 ComboBoxArrowColor=text ComboBoxArrowColorDisabled=text ComboBoxTextColor=text diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 52101b881bd..7327307c982 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -175,7 +175,6 @@ BadgeLabelBackgroundColorChecked=ffe0e0e0 BadgeLabelBackgroundColorUnchecked=ff808080 BadgeLabelTextColorChecked=ff606060 BadgeLabelTextColorUnchecked=ffffffff -CanceledSearchTextColor=ffff0000 ComboBoxArrowColor=ffb8b5b2 ComboBoxArrowColorDisabled=ffdcdcdc ComboBoxTextColor=ffffffff diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index f3cf92f58ac..6ffeca69bff 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -189,7 +189,6 @@ BadgeLabelBackgroundColorChecked=ffe0e0e0 BadgeLabelBackgroundColorUnchecked=ff808080 BadgeLabelTextColorChecked=ff606060 BadgeLabelTextColorUnchecked=ffffffff -CanceledSearchTextColor=ff0000 ComboBoxArrowColor=toolBarItem ComboBoxArrowColorDisabled=toolBarItemDisabled ComboBoxTextColor=fancyBarsNormalTextColor diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index 1783ba8e9d0..a3b8425b080 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -186,7 +186,6 @@ BadgeLabelBackgroundColorChecked=ffe0e0e0 BadgeLabelBackgroundColorUnchecked=ff808080 BadgeLabelTextColorChecked=ff606060 BadgeLabelTextColorUnchecked=ffffffff -CanceledSearchTextColor=ff0000 ComboBoxArrowColor=toolBarItem ComboBoxArrowColorDisabled=toolBarItemDisabled ComboBoxTextColor=fancyBarsNormalTextColor diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 16bf4e26e72..70c86db8f6b 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -188,7 +188,6 @@ BadgeLabelBackgroundColorChecked=ffe0e0e0 BadgeLabelBackgroundColorUnchecked=ff808080 BadgeLabelTextColorChecked=ff606060 BadgeLabelTextColorUnchecked=ffffffff -CanceledSearchTextColor=ff0000 ComboBoxArrowColor=toolBarItem ComboBoxArrowColorDisabled=toolBarItemDisabled ComboBoxTextColor=fancyBarsNormalTextColor diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index 512f511f735..f378eae16fd 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -184,7 +184,6 @@ BadgeLabelBackgroundColorChecked=ffe0e0e0 BadgeLabelBackgroundColorUnchecked=ff808080 BadgeLabelTextColorChecked=ff606060 BadgeLabelTextColorUnchecked=ffffffff -CanceledSearchTextColor=ff0000 ComboBoxArrowColor=toolBarItem ComboBoxArrowColorDisabled=toolBarItemDisabled ComboBoxTextColor=fancyBarsNormalTextColor diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index e0e27654329..7c26e782d12 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -182,7 +182,6 @@ BadgeLabelBackgroundColorChecked=ffe0e0e0 BadgeLabelBackgroundColorUnchecked=ff808080 BadgeLabelTextColorChecked=ff606060 BadgeLabelTextColorUnchecked=ffffffff -CanceledSearchTextColor=ff0000 ComboBoxArrowColor=toolBarItem ComboBoxArrowColorDisabled=toolBarItemDisabled ComboBoxTextColor=fancyBarsNormalTextColor diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index d3ba34b3ee5..2652c73b135 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -36,7 +36,6 @@ public: BadgeLabelBackgroundColorUnchecked, BadgeLabelTextColorChecked, BadgeLabelTextColorUnchecked, - CanceledSearchTextColor, ComboBoxArrowColor, ComboBoxArrowColorDisabled, ComboBoxTextColor, diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp index 36344ed804d..5959cd40fda 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.cpp +++ b/src/plugins/coreplugin/find/searchresultwidget.cpp @@ -93,7 +93,7 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : topLayout->addWidget(m_topReplaceWidget); m_messageWidget = new QFrame; - pal.setColor(QPalette::WindowText, creatorTheme()->color(Theme::CanceledSearchTextColor)); + pal.setColor(QPalette::WindowText, creatorTheme()->color(Theme::TextColorError)); m_messageWidget->setPalette(pal); if (creatorTheme()->flag(Theme::DrawSearchResultWidgetFrame)) { m_messageWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); From 8bf24bac3a135b61314a9f28dd62d97d021f00c6 Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Sun, 19 Mar 2023 21:48:27 +0100 Subject: [PATCH 0373/1447] Remove auto-format-on-file-save dependency from custom formatter widgets We can use custom formatter not only with auto-formatting on file save, but also tools/qmljs/reformat file action. Hence, command and arguments lineedits of custom formatter should only be enabled/disabled by useCustomFormatter checkbox. useCustomFormatter also should not depend on auto-format-on-file-save checkbox's state. Change-Id: If1a634612f38395fd846166f4cc72593f5150f91 Reviewed-by: Reviewed-by: Xavier BESSON Reviewed-by: Eike Ziller --- src/plugins/qmljseditor/qmljseditingsettingspage.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 2a0ecb41771..6d9e95f4389 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -287,8 +287,7 @@ public: Utils::globalMacroExpander()); const auto updateFormatCommandState = [&, formatCommandLabel, formatCommandOptionsLabel] { - const bool enabled = useCustomFormatCommand->isChecked() - && autoFormatOnSave->isChecked(); + const bool enabled = useCustomFormatCommand->isChecked(); formatCommandLabel->setEnabled(enabled); formatCommand->setEnabled(enabled); formatCommandOptionsLabel->setEnabled(enabled); @@ -298,7 +297,6 @@ public: connect(autoFormatOnSave, &QCheckBox::toggled, this, [&, updateFormatCommandState]() { autoFormatOnlyCurrentProject->setEnabled(autoFormatOnSave->isChecked()); - useCustomFormatCommand->setEnabled(autoFormatOnSave->isChecked()); updateFormatCommandState(); }); connect(useCustomFormatCommand, &QCheckBox::toggled, this, updateFormatCommandState); From 47fcb28c8f5c401788a2865d9425bf52b46ac494 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 10:52:44 +0100 Subject: [PATCH 0374/1447] Utils: Restore ctrlc stub It was incorrectly removed in 0870f2583bbc659df00ff65bf51918b940221665 Change-Id: Id219981d459ab3bf9560945275ed874cc63efa64 Reviewed-by: Alessandro Portale --- src/libs/utils/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 7277b7c8cf2..6b2e835d198 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -272,3 +272,12 @@ extend_qtc_library(Utils fsengine/fsenginehandler.h fsengine/filepathinfocache.h ) + +if (WIN32) + add_qtc_executable(qtcreator_ctrlc_stub + DEPENDS user32 shell32 + DEFINES _UNICODE UNICODE _CRT_SECURE_NO_WARNINGS + SOURCES + process_ctrlc_stub.cpp + ) +endif() From 3526b6a7350704e0b89706a175bea2141a47d0e1 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 23 Mar 2023 16:40:10 +0100 Subject: [PATCH 0375/1447] Terminal: Introduce Add/Close icons for the pane Required a new "close" overlay. Change-Id: I5268ec280992124ebcee78a73ab58b18e7c9309b Reviewed-by: Marcus Tillmanns Reviewed-by: Cristian Adam --- .../utils/images/iconoverlay_close_small.png | Bin 0 -> 173 bytes .../images/iconoverlay_close_small@2x.png | Bin 0 -> 249 bytes src/libs/utils/utils.qrc | 2 ++ src/plugins/terminal/images/terminal.png | Bin 0 -> 154 bytes src/plugins/terminal/images/terminal@2x.png | Bin 0 -> 180 bytes src/plugins/terminal/terminal.qrc | 2 ++ src/plugins/terminal/terminalpane.cpp | 10 +++--- src/tools/icons/qtcreatoricons.svg | 30 ++++++++++++++++++ 8 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 src/libs/utils/images/iconoverlay_close_small.png create mode 100644 src/libs/utils/images/iconoverlay_close_small@2x.png create mode 100644 src/plugins/terminal/images/terminal.png create mode 100644 src/plugins/terminal/images/terminal@2x.png diff --git a/src/libs/utils/images/iconoverlay_close_small.png b/src/libs/utils/images/iconoverlay_close_small.png new file mode 100644 index 0000000000000000000000000000000000000000..e39b67cfbb357fdb71a3404a7ef1bdcf54fdfa1e GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdsSyd_r6q7#K7(G<0-ybai#h z%ggKQ>l+#xIyyR@J$v^2`SX`AU%qdTie|NsBDeIe?>z`$VV>Eal|5uLn)o0Uh! z_}sm{%xN)GckI3?e#GL)7B5HkBRiHZII=}-O`2e{n9IjBHckU(J=XA=*iY}C#q4Ng Zuy`1|c%%I>Z3YGg22WQ%mvv4FO#nQ@LMZ?M literal 0 HcmV?d00001 diff --git a/src/libs/utils/images/iconoverlay_close_small@2x.png b/src/libs/utils/images/iconoverlay_close_small@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e8a02dff03af6808f2358c23712bd56985b6e689 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8x&b~Rt_%ze%*@OzEG*^a z<@NRT4Gj$)9UY4oFJ7`_$%+*#R;^mKdiCndmoHzra^?U3|L(J+!WbAB+C5zyLo_BP zSG2Q9v@JehEAUZF@q>$ui{7SYZVQ8Jd#k^DHA<>|aBFn@e0R4ekI(Z2Ei*%dYkPwd zCNyMMu05czucL7ze%U=cGk=uqa~!<4zQy8U**1Zju7 zM(&0?3`N{|%hen1e28ikUH5b*%MJI!9n2hj3^U|smo~0{{eyvlfx*+&&t;ucLK6V0 CxLuzB literal 0 HcmV?d00001 diff --git a/src/libs/utils/utils.qrc b/src/libs/utils/utils.qrc index 1f2ef64898e..20f6d7c788b 100644 --- a/src/libs/utils/utils.qrc +++ b/src/libs/utils/utils.qrc @@ -173,6 +173,8 @@ images/iconoverlay_add@2x.png images/iconoverlay_add_background.png images/iconoverlay_add_background@2x.png + images/iconoverlay_close_small.png + images/iconoverlay_close_small@2x.png images/iconoverlay_error.png images/iconoverlay_error@2x.png images/iconoverlay_error_background.png diff --git a/src/plugins/terminal/images/terminal.png b/src/plugins/terminal/images/terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..0a1dd311ec88c868bfda40ac1495192959aaa995 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdo_nd_r6q7#KuFMa9I#OifL@ zy1Mr6-MfGP{zHcj9X@>c^XJch{`~p>|37ctyN?VE42GUAjv*Y;$v1ded88#87|z_- zTlJmIAbGmvl#RPJrB2;Y;!G8BUA(&SWz$S%^O+)S4BK7>KT=w^6J!a4r>mdKI;Vst E065P$Q2+n{ literal 0 HcmV?d00001 diff --git a/src/plugins/terminal/images/terminal@2x.png b/src/plugins/terminal/images/terminal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..da36b36721c4c6b913d3ba514ee2f4b517d28ddf GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8Dgizrt_%ze8X6ipIy$<# zy7l$-9UUFdo;`d1{Q1k5FJHZS_2tW#|NsAQZ+g6(fq}u>)5S4FV`B1+UN#8>R*3|L z?F_5ZHXP6^VLYA_(iqDnm7%3(oVJ+jjfsG>=#9HauJpzyEN`^fweTv-8s0T(PfASA i3-a(EO0)`LVVFA8rm=6{v`_{H1_n=8KbLh*2~7ZT^g images/settingscategory_terminal.png images/settingscategory_terminal@2x.png + images/terminal.png + images/terminal@2x.png shellintegrations/shellintegration-bash.sh shellintegrations/shellintegration-env.zsh shellintegrations/shellintegration-login.zsh diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 94a93ed84e4..8c6a77ba360 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -47,14 +47,16 @@ TerminalPane::TerminalPane(QObject *parent) QAction &newTerminal = TerminalCommands::instance().paneActions().newTerminal; QAction &closeTerminal = TerminalCommands::instance().paneActions().closeTerminal; - newTerminal.setIcon( - Icon({{":/terminal/images/settingscategory_terminal.png", Theme::Theme::IconsBaseColor}}) - .icon()); + newTerminal.setIcon(Icon({ + {":/terminal/images/terminal.png", Theme::IconsBaseColor}, + {":/utils/images/iconoverlay_add_small.png", Theme::IconsRunToolBarColor}}).icon()); newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); - closeTerminal.setIcon(Icons::CLOSE_TOOLBAR.icon()); + closeTerminal.setIcon(Icon({ + {":/terminal/images/terminal.png", Theme::IconsBaseColor}, + {":/utils/images/iconoverlay_close_small.png", Theme::IconsStopToolBarColor}}).icon()); closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); closeTerminal.setEnabled(false); diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index e3bf52e6eb1..4ec2b2bb145 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -3542,6 +3542,22 @@ inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" /> + + + + + + + + From b4bc5f6e1b077d620add58f057003abdd7fe620a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Mar 2023 14:49:42 +0100 Subject: [PATCH 0376/1447] Utils: Add short documentation for two FilePath functions ensureWriteableDir() and createDir() Also change a few \returns to Returns. Change-Id: I8c80616a465a7e665ff56fab8279e43e5755fb4f Reviewed-by: Leena Miettinen --- src/libs/utils/filepath.cpp | 95 ++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 23450661903..9b97fb6b028 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -163,7 +163,7 @@ FilePath FilePath::fromFileInfo(const QFileInfo &info) } /*! - \returns a QFileInfo + Returns a QFileInfo. */ QFileInfo FilePath::toFileInfo() const { @@ -215,7 +215,7 @@ QString decodeHost(QString host) } /*! - \returns a QString for passing through QString based APIs + Returns a QString for passing through QString based APIs. \note This is obsolete API and should be replaced by extended use of proper \c FilePath, or, in case this is not possible by \c toFSPathString(). @@ -243,7 +243,7 @@ QString FilePath::toString() const } /*! - \returns a QString for passing on to QString based APIs + Returns a QString for passing on to QString based APIs. This uses a /__qtc_devices__/host/path setup. @@ -296,7 +296,7 @@ QString FilePath::toUserOutput() const } /*! - \returns a QString to pass to target system native commands, without the device prefix. + Returns a QString to pass to target system native commands, without the device prefix. Converts the separators to the native format of the system this path belongs to. @@ -350,7 +350,7 @@ QString FilePath::fileNameWithPathComponents(int pathComponents) const } /*! - \returns the base name of the file without the path. + Returns the base name of the file without the path. The base name consists of all characters in the file up to (but not including) the first '.' character. @@ -362,7 +362,7 @@ QString FilePath::baseName() const } /*! - \returns the complete base name of the file without the path. + Returns the complete base name of the file without the path. The complete base name consists of all characters in the file up to (but not including) the last '.' character. In case of ".ui.qml" @@ -377,7 +377,7 @@ QString FilePath::completeBaseName() const } /*! - \returns the suffix (extension) of the file. + Returns the suffix (extension) of the file. The suffix consists of all characters in the file after (but not including) the last '.'. In case of ".ui.qml" it will @@ -400,7 +400,7 @@ QString FilePath::suffix() const } /*! - \returns the complete suffix (extension) of the file. + Returns the complete suffix (extension) of the file. The complete suffix consists of all characters in the file after (but not including) the first '.'. @@ -448,7 +448,7 @@ void FilePath::setParts(const QStringView scheme, const QStringView host, QStrin } /*! - \returns a bool indicating whether a file or directory with this FilePath exists. + Returns a bool indicating whether a file or directory with this FilePath exists. */ bool FilePath::exists() const { @@ -456,7 +456,7 @@ bool FilePath::exists() const } /*! - \returns a bool indicating whether this is a writable directory. + Returns a bool indicating whether this is a writable directory. */ bool FilePath::isWritableDir() const { @@ -464,13 +464,20 @@ bool FilePath::isWritableDir() const } /*! - \returns a bool indicating whether this is a writable file. + Returns a bool indicating whether this is a writable file. */ bool FilePath::isWritableFile() const { return fileAccess()->isWritableFile(*this); } +/*! + \brief Re-uses or creates a directory in this location. + + Returns true if the directory is writable afterwards. + + \sa createDir() +*/ bool FilePath::ensureWritableDir() const { return fileAccess()->ensureWritableDirectory(*this); @@ -487,7 +494,7 @@ bool FilePath::isExecutableFile() const } /*! - \returns a bool indicating on whether a process with this FilePath's + Returns a bool indicating on whether a process with this FilePath's .nativePath() is likely to start. This is equivalent to \c isExecutableFile() in general. @@ -557,6 +564,14 @@ bool FilePath::isSymLink() const return fileAccess()->isSymLink(*this); } +/*! + \brief Creates a directory in this location. + + Returns true if the directory could be created, false if not, + even if it existed before. + + \sa ensureWriteableDir() +*/ bool FilePath::createDir() const { return fileAccess()->createDirectory(*this); @@ -726,7 +741,7 @@ bool FilePath::isSameExecutable(const FilePath &other) const } /*! - \returns an empty FilePath if this is not a symbolic linl + Returns an empty FilePath if this is not a symbolic link. */ FilePath FilePath::symLinkTarget() const { @@ -930,7 +945,7 @@ QString doCleanPath(const QString &input_) Returns an empty FilePath if the current directory is already a root level directory. - \returns \a FilePath with the last segment removed. + Returns \a FilePath with the last segment removed. */ FilePath FilePath::parentDir() const { @@ -1225,7 +1240,7 @@ QVariant FilePath::toVariant() const } /*! - \returns whether FilePath is a child of \a s + Returns whether FilePath is a child of \a s. */ bool FilePath::isChildOf(const FilePath &s) const { @@ -1247,7 +1262,7 @@ bool FilePath::isChildOf(const FilePath &s) const } /*! - \returns whether \c path() starts with \a s. + Returns whether \c path() starts with \a s. */ bool FilePath::startsWith(const QString &s) const { @@ -1255,7 +1270,7 @@ bool FilePath::startsWith(const QString &s) const } /*! - \returns whether \c path() ends with \a s. + Returns whether \c path() ends with \a s. */ bool FilePath::endsWith(const QString &s) const { @@ -1263,7 +1278,7 @@ bool FilePath::endsWith(const QString &s) const } /*! - \returns whether \c path() contains \a s. + Returns whether \c path() contains \a s. */ bool FilePath::contains(const QString &s) const { @@ -1274,7 +1289,8 @@ bool FilePath::contains(const QString &s) const \brief Checks whether the FilePath starts with a drive letter. Defaults to \c false if it is a non-Windows host or represents a path on device - \returns whether FilePath starts with a drive letter + + Returns whether FilePath starts with a drive letter */ bool FilePath::startsWithDriveLetter() const { @@ -1288,7 +1304,8 @@ bool FilePath::startsWithDriveLetter() const Returns a empty FilePath if this is not a child of \p parent. That is, this never returns a path starting with "../" \param parent The Parent to calculate the relative path to. - \returns The relative path of this to \p parent if this is a child of \p parent. + + Returns The relative path of this to \p parent if this is a child of \p parent. */ FilePath FilePath::relativeChildPath(const FilePath &parent) const { @@ -1303,7 +1320,7 @@ FilePath FilePath::relativeChildPath(const FilePath &parent) const } /*! - \returns the relativePath of FilePath from a given \a anchor. + Returns the relativePath of FilePath from a given \a anchor. Both, FilePath and anchor may be files or directories. Example usage: @@ -1348,8 +1365,10 @@ FilePath FilePath::relativePathFrom(const FilePath &anchor) const } /*! - \returns the relativePath of \a absolutePath to given \a absoluteAnchorPath. - Both paths must be an absolute path to a directory. Example usage: + Returns the relativePath of \a absolutePath to given \a absoluteAnchorPath. + Both paths must be an absolute path to a directory. + + Example usage: \code qDebug() << FilePath::calcRelativePath("/foo/b/ar", "/foo/c"); @@ -1397,8 +1416,7 @@ QString FilePath::calcRelativePath(const QString &absolutePath, const QString &a } /*! - \brief Returns a path corresponding to the current object on the - + Returns a path corresponding to the current object on the same device as \a deviceTemplate. The FilePath needs to be local. Example usage: @@ -1410,8 +1428,6 @@ QString FilePath::calcRelativePath(const QString &absolutePath, const QString &a \endcode \param deviceTemplate A path from which the host and scheme is taken. - - \returns A path on the same device as \a deviceTemplate. */ FilePath FilePath::onDevice(const FilePath &deviceTemplate) const { @@ -1583,7 +1599,7 @@ bool FilePath::removeFile() const \note The \a error parameter is optional. - \returns A bool indicating whether the operation succeeded. + Returns a Bool indicating whether the operation succeeded. */ bool FilePath::removeRecursively(QString *error) const { @@ -1641,7 +1657,7 @@ qint64 FilePath::bytesAvailable() const \brief Checks if this is newer than \p timeStamp \param timeStamp The time stamp to compare with - \returns true if this is newer than \p timeStamp. + Returns true if this is newer than \p timeStamp. If this is a directory, the function will recursively check all files and return true if one of them is newer than \a timeStamp. If this is a single file, true will be returned if the file is newer than \a timeStamp. @@ -1666,7 +1682,6 @@ bool FilePath::isNewerThan(const QDateTime &timeStamp) const /*! \brief Returns the caseSensitivity of the path. - \returns The caseSensitivity of the path. This is currently only based on the Host OS. For device paths, \c Qt::CaseSensitive is always returned. */ @@ -1685,7 +1700,7 @@ Qt::CaseSensitivity FilePath::caseSensitivity() const /*! \brief Returns the separator of path components for this path. - \returns The path separator of the path. + Returns the path separator of the path. */ QChar FilePath::pathComponentSeparator() const { @@ -1695,7 +1710,7 @@ QChar FilePath::pathComponentSeparator() const /*! \brief Returns the path list separator for the device this path belongs to. - \returns The path list separator of the device for this path + Returns the path list separator of the device for this path. */ QChar FilePath::pathListSeparator() const { @@ -1711,7 +1726,7 @@ QChar FilePath::pathListSeparator() const \note Maximum recursion depth == 16. - \returns the symlink target file path. + Returns the symlink target file path. */ FilePath FilePath::resolveSymlinks() const { @@ -1732,7 +1747,7 @@ FilePath FilePath::resolveSymlinks() const * Unlike QFileInfo::canonicalFilePath(), this function will not return an empty * string if path doesn't exist. * -* \returns the canonical path. +* Returns the canonical path. */ FilePath FilePath::canonicalPath() const { @@ -1789,7 +1804,7 @@ void FilePath::clear() /*! \brief Checks if the path() is empty. - \returns true if the path() is empty. + Returns true if the path() is empty. The Host and Scheme of the part are ignored. */ bool FilePath::isEmpty() const @@ -1803,7 +1818,7 @@ bool FilePath::isEmpty() const Like QDir::toNativeSeparators(), but use prefix '~' instead of $HOME on unix systems when an absolute path is given. - \returns the possibly shortened path with native separators. + Returns the possibly shortened path with native separators. */ QString FilePath::shortNativePath() const { @@ -1820,7 +1835,7 @@ QString FilePath::shortNativePath() const /*! \brief Checks whether the path is relative - \returns true if the path is relative. + Returns true if the path is relative. */ bool FilePath::isRelativePath() const { @@ -1838,7 +1853,8 @@ bool FilePath::isRelativePath() const \brief Appends the tail to this, if the tail is a relative path. \param tail The tail to append. - \returns Returns tail if tail is absolute, otherwise this + tail. + + Returns tail if tail is absolute, otherwise this + tail. */ FilePath FilePath::resolvePath(const FilePath &tail) const { @@ -1853,7 +1869,8 @@ FilePath FilePath::resolvePath(const FilePath &tail) const \brief Appends the tail to this, if the tail is a relative path. \param tail The tail to append. - \returns Returns tail if tail is absolute, otherwise this + tail. + + Returns tail if tail is absolute, otherwise this + tail. */ FilePath FilePath::resolvePath(const QString &tail) const { From 3b6e59ab914b46d8d640a46ee3a8173b221b98c4 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 24 Mar 2023 11:46:40 +0100 Subject: [PATCH 0377/1447] Terminal: Update on open/close the Terminal pane registration Amends f95bd6119aee15e459d1ceadd96604f76b777860 Change-Id: Ie20d73ad9d87c5b244c768a28f3a7bd71fdd272c Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalpane.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 8c6a77ba360..ee23b62db4e 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -290,15 +290,14 @@ void TerminalPane::clearContents() void TerminalPane::visibilityChanged(bool visible) { - Q_UNUSED(visible); + if (visible) + TerminalCommands::instance().registerOpenCloseTerminalPaneCommand(); } void TerminalPane::setFocus() { if (const auto t = currentTerminal()) t->setFocus(); - - TerminalCommands::instance().registerOpenCloseTerminalPaneCommand(); } bool TerminalPane::hasFocus() const From 1be65dd1eef167789c8d3432896b5f9980560c1a Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 24 Mar 2023 12:38:55 +0100 Subject: [PATCH 0378/1447] Terminal: Update on set focus after closing tab Amends 84155e835468d16dc595f785a4013e77bfad9aa3 This change sets the focus also on terminals that get destroyed via exit or Ctrl+D Change-Id: I9a96ae5b257f3e8a93db7efb4e7d4468b287c143 Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalpane.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index ee23b62db4e..961359712a5 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -200,6 +200,11 @@ QWidget *TerminalPane::outputWidget(QWidget *parent) removeTab(index); }); + connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int index) { + if (auto widget = m_tabWidget->widget(index)) + widget->setFocus(); + }); + auto terminalWidget = new TerminalWidget(parent); m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal")); setupTerminalWidget(terminalWidget); @@ -221,10 +226,6 @@ void TerminalPane::removeTab(int index) TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); - if (auto terminal = currentTerminal()) { - terminal->setFocus(); - } - emit navigateStateUpdate(); } From e6e895d6beea5e7676ac6783003d49e560f49963 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 24 Mar 2023 11:27:21 +0100 Subject: [PATCH 0379/1447] Copilot: correctly cleanup compression timer fixes a leak and a crash if the timer triggers after the widget was deleted. Change-Id: I57794009186d4c5e4dee0b0c0746ffc5468000b7 Reviewed-by: Artem Sokolovskii Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotclient.cpp | 5 +++++ src/plugins/copilot/copilotclient.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 50be6788410..e1122020926 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -108,6 +108,11 @@ void CopilotClient::scheduleRequest(TextEditorWidget *editor) m_scheduledRequests[editor].timer->start(500); } +CopilotClient::ScheduleData::~ScheduleData() +{ + delete timer; +} + void CopilotClient::requestCompletions(TextEditorWidget *editor) { Utils::MultiTextCursor cursor = editor->multiTextCursor(); diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index 5111e04e1df..e29343f3680 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -50,6 +50,7 @@ private: QMap m_runningRequests; struct ScheduleData { + ~ScheduleData(); int cursorPosition = -1; QTimer *timer = nullptr; }; From 9ac1f221ccc3c1667d58ecc13f9716e41dc30b2f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 24 Mar 2023 12:31:14 +0100 Subject: [PATCH 0380/1447] TextEditor: ensure block is layouted ...after requesting block bounding rect. Change-Id: Id7420a1b1ae4761fad86b6dbbc9c9ebe639cc5fe Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/textdocumentlayout.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index ce337efa022..9c257d3a257 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -756,8 +756,12 @@ static QRectF replacementBoundingRect(const QTextDocument *replacement) QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const { - if (QTextDocument *replacement = replacementDocument(block)) + if (QTextDocument *replacement = replacementDocument(block)) { + // since multiple code paths expects that we have a valid block layout after requesting the + // block bounding rect explicitly create that layout here + ensureBlockLayout(block); return replacementBoundingRect(replacement); + } QRectF boundingRect = QPlainTextDocumentLayout::blockBoundingRect(block); From a0924caea273cffc715ebb8fdbe56a2966ab926f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 09:27:24 +0100 Subject: [PATCH 0381/1447] Terminal: Improve light default themes * Made Ansi 11 easier to read ( darker ) * Fixed selection color to be black with 25% opacity Change-Id: I2380e45b9cc15732085961f21eb6e5360321a9fe Reviewed-by: Alessandro Portale --- share/qtcreator/themes/default.creatortheme | 4 ++-- share/qtcreator/themes/design-light.creatortheme | 4 ++-- share/qtcreator/themes/flat-light.creatortheme | 4 ++-- share/qtcreator/themes/flat.creatortheme | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 7327307c982..92d4ff5c11c 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -354,7 +354,7 @@ QmlDesigner_ScrollBarHandleColor=ff7a7a7a TerminalForeground=ff000000 TerminalBackground=ffffffff -TerminalSelection=7fffffff +TerminalSelection=3f000000 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e @@ -366,7 +366,7 @@ TerminalAnsi7=bfbfbf TerminalAnsi8=666666 TerminalAnsi9=d22d1f TerminalAnsi10=62d63f -TerminalAnsi11=e5e54b +TerminalAnsi11=dac911 TerminalAnsi12=0000fe TerminalAnsi13=d22dde TerminalAnsi14=69e2e4 diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 6ffeca69bff..49895cdb7d5 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -398,7 +398,7 @@ PaletteTextDisabled=textDisabled TerminalForeground=ff000000 TerminalBackground=ffffffff -TerminalSelection=7fffffff +TerminalSelection=3f000000 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e @@ -410,7 +410,7 @@ TerminalAnsi7=bfbfbf TerminalAnsi8=666666 TerminalAnsi9=d22d1f TerminalAnsi10=62d63f -TerminalAnsi11=e5e54b +TerminalAnsi11=dac911 TerminalAnsi12=0000fe TerminalAnsi13=d22dde TerminalAnsi14=69e2e4 diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index f378eae16fd..2c41c7b68f8 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -363,7 +363,7 @@ QmlDesigner_ScrollBarHandleColor=ffcccccc TerminalForeground=ff000000 TerminalBackground=ffffffff -TerminalSelection=7fffffff +TerminalSelection=3f000000 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e @@ -375,7 +375,7 @@ TerminalAnsi7=bfbfbf TerminalAnsi8=666666 TerminalAnsi9=d22d1f TerminalAnsi10=62d63f -TerminalAnsi11=e5e54b +TerminalAnsi11=dac911 TerminalAnsi12=0000fe TerminalAnsi13=d22dde TerminalAnsi14=69e2e4 diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 7c26e782d12..15a9f7b866b 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -361,7 +361,7 @@ QmlDesigner_ScrollBarHandleColor=ff595b5c TerminalForeground=ff000000 TerminalBackground=ffffffff -TerminalSelection=7fffffff +TerminalSelection=3f000000 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e @@ -373,7 +373,7 @@ TerminalAnsi7=bfbfbf TerminalAnsi8=666666 TerminalAnsi9=d22d1f TerminalAnsi10=62d63f -TerminalAnsi11=e5e54b +TerminalAnsi11=dac911 TerminalAnsi12=0000fe TerminalAnsi13=d22dde TerminalAnsi14=69e2e4 From 6e276b0a00843e48e1695bf27f3530a32dafe441 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Mar 2023 10:59:30 +0100 Subject: [PATCH 0382/1447] Utils: Add a way to provide fall-back entries in an environment These are used if a (presumably fully-expanded) environment does not have a value for a certain key. Currently this works only for fully-known environments, but this can at least be delayed until the environment is needed, not when it is set up. Change-Id: I9baaa2d23002ddd574101741a91d5f872e6b0314 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/utils/environment.cpp | 20 ++++++++++++++++++++ src/libs/utils/environment.h | 10 ++++++++-- src/plugins/projectexplorer/runcontrol.cpp | 8 +++----- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index e64db0e2a32..cacd60fcd6f 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -494,6 +494,12 @@ void Environment::set(const QString &key, const QString &value, bool enabled) std::tuple{key, value, enabled}}); } +void Environment::setFallback(const QString &key, const QString &value) +{ + addItem(Item{std::in_place_index_t(), + std::tuple{key, value}}); +} + void Environment::unset(const QString &key) { addItem(Item{std::in_place_index_t(), key}); @@ -536,19 +542,33 @@ const NameValueDictionary &Environment::resolved() const if (m_dict.size() != 0) return m_dict; + m_fullDict = false; for (const Item &item : m_changeItems) { switch (item.index()) { case SetSystemEnvironment: m_dict = Environment::systemEnvironment().toDictionary(); + m_fullDict = true; break; case SetFixedDictionary: m_dict = std::get(item); + m_fullDict = true; break; case SetValue: { auto [key, value, enabled] = std::get(item); m_dict.set(key, value, enabled); break; } + case SetFallbackValue: { + auto [key, value] = std::get(item); + if (m_fullDict) { + if (m_dict.value(key).isEmpty()) + m_dict.set(key, value, true); + } else { + QTC_ASSERT(false, qDebug() << "operating on partial dictionary"); + m_dict.set(key, value, true); + } + break; + } case UnsetValue: m_dict.unset(std::get(item)); break; diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 8424eb1d24b..7afa48ba0bb 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -33,6 +33,7 @@ public: bool hasKey(const QString &key) const; void set(const QString &key, const QString &value, bool enabled = true); + void setFallback(const QString &key, const QString &value); void unset(const QString &key); void modify(const NameValueItems &items); @@ -55,6 +56,7 @@ public: void appendToPath(const FilePaths &values); void setupEnglishOutput(); + void setupSudoAskPass(const FilePath &askPass); FilePath searchInPath(const QString &executable, const FilePaths &additionalDirs = FilePaths(), @@ -95,22 +97,25 @@ public: SetSystemEnvironment, SetFixedDictionary, SetValue, + SetFallbackValue, UnsetValue, PrependOrSet, AppendOrSet, Modify, - SetupEnglishOutput, + SetupEnglishOutput }; using Item = std::variant< std::monostate, // SetSystemEnvironment dummy NameValueDictionary, // SetFixedDictionary std::tuple, // SetValue (key, value, enabled) + std::tuple, // SetFallbackValue (key, value) QString, // UnsetValue (key) std::tuple, // PrependOrSet (key, value, separator) std::tuple, // AppendOrSet (key, value, separator) NameValueItems, // Modify - std::monostate // SetupEnglishOutput + std::monostate, // SetupEnglishOutput + FilePath // SetupSudoAskPass (file path of qtc-askpass or ssh-askpass) >; void addItem(const Item &item); @@ -122,6 +127,7 @@ public: private: mutable QList m_changeItems; mutable NameValueDictionary m_dict; // Latest resolved. + mutable bool m_fullDict = false; }; using EnviromentChange = Environment; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 72b2e76e502..96bbc302ac5 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1069,11 +1069,9 @@ bool RunControl::showPromptToStopDialog(const QString &title, void RunControl::provideAskPassEntry(Environment &env) { - if (env.value("SUDO_ASKPASS").isEmpty()) { - const FilePath askpass = SshSettings::askpassFilePath(); - if (askpass.exists()) - env.set("SUDO_ASKPASS", askpass.toUserOutput()); - } + const FilePath askpass = SshSettings::askpassFilePath(); + if (askpass.exists()) + env.setFallback("SUDO_ASKPASS", askpass.toUserOutput()); } bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlState to) From b7394e073e4aaec34d59af1f9973ea4b2ac384cf Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 17:26:25 +0100 Subject: [PATCH 0383/1447] QmakeProjectManager: Work around a warning warning: this statement may fall through [-Wimplicit-fallthrough=] Change-Id: I95b97781934521b578571da196d6688302ce76f6 Reviewed-by: Reviewed-by: Christian Stenger --- .../qmakeprojectmanager/wizards/qtprojectparameters.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp b/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp index e2db56e8246..1612e36753b 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp @@ -65,8 +65,10 @@ void QtProjectParameters::writeProFile(QTextStream &str) const switch (type) { case ConsoleApp: // Mac: Command line apps should not be bundles - str << "CONFIG += console\nCONFIG -= app_bundle\n\n"; - // fallthrough + str << "CONFIG += console\n" + "CONFIG -= app_bundle\n\n" + "TEMPLATE = app\n"; + break; case GuiApp: str << "TEMPLATE = app\n"; break; From 17a482bebe26fa3dd6d892bae9aa1449046eef10 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 23 Mar 2023 13:31:21 +0100 Subject: [PATCH 0384/1447] Terminal: Support paste via Middle mouse button Fixes: QTCREATORBUG-28943 Change-Id: If48c021e509e10fd13e6e5356d0a364e91aae8da Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index c517d29735b..458e5554008 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -1112,6 +1112,15 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) } else { pasteFromClipboard(); } + } else if (event->button() == Qt::MiddleButton) { + QClipboard *clipboard = QApplication::clipboard(); + if (clipboard->supportsSelection()) { + const QString selectionText = clipboard->text(QClipboard::Selection); + if (!selectionText.isEmpty()) + m_surface->pasteFromClipboard(selectionText); + } else { + m_surface->pasteFromClipboard(textFromSelection()); + } } } void TerminalWidget::mouseMoveEvent(QMouseEvent *event) From 5996e58ffa79bc058a01989423e5a7edd29e409d Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 15:32:42 +0100 Subject: [PATCH 0385/1447] ProjectExplorer: Allow Devices to be added without using the wizard This re-organizes the buttons on the main device page a bit: The topmost one still starts the wizard selection, below that are direct individual buttons to add specific devices. Change-Id: I52b2803febf658259dde9589544656fd4c8fc889 Reviewed-by: David Schulz --- src/plugins/android/androiddevice.cpp | 1 - src/plugins/baremetal/baremetaldevice.cpp | 1 - src/plugins/boot2qt/qdbdevice.cpp | 2 ++ src/plugins/docker/dockerdevice.cpp | 7 ++-- .../devicesupport/devicesettingswidget.cpp | 35 ++++++++++++++----- .../devicesupport/idevicefactory.cpp | 26 ++++++++++++-- .../devicesupport/idevicefactory.h | 3 ++ src/plugins/qnx/qnxdevice.cpp | 11 ++++++ .../genericlinuxdeviceconfigurationwizard.cpp | 8 ----- src/plugins/remotelinux/linuxdevice.cpp | 11 +++++- 10 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index be5f3071242..b707b81cc6f 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -847,7 +847,6 @@ AndroidDeviceFactory::AndroidDeviceFactory() setDisplayName(Tr::tr("Android Device")); setCombinedIcon(":/android/images/androiddevicesmall.png", ":/android/images/androiddevice.png"); - setConstructionFunction(&AndroidDevice::create); if (m_androidConfig.sdkToolsOk()) { setCreator([this] { diff --git a/src/plugins/baremetal/baremetaldevice.cpp b/src/plugins/baremetal/baremetaldevice.cpp index 4c8d7ea8c66..d7754ebc9a0 100644 --- a/src/plugins/baremetal/baremetaldevice.cpp +++ b/src/plugins/baremetal/baremetaldevice.cpp @@ -24,7 +24,6 @@ const char debugServerProviderIdKeyC[] = "IDebugServerProviderId"; BareMetalDevice::BareMetalDevice() { setDisplayType(Tr::tr("Bare Metal")); - setDefaultDisplayName(defaultDisplayName()); setOsType(Utils::OsTypeOther); } diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index c595645a444..c2c25b65372 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -104,6 +104,7 @@ private: QdbDevice::QdbDevice() { setDisplayType(Tr::tr("Boot2Qt Device")); + setType(Constants::QdbLinuxOsType); addDeviceAction({Tr::tr("Reboot Device"), [](const IDevice::Ptr &device, QWidget *) { (void) new DeviceApplicationObserver(device, {device->filePath("reboot"), {}}); @@ -247,6 +248,7 @@ QdbLinuxDeviceFactory::QdbLinuxDeviceFactory() { setDisplayName(Tr::tr("Boot2Qt Device")); setCombinedIcon(":/qdb/images/qdbdevicesmall.png", ":/qdb/images/qdbdevice.png"); + setQuickCreationAllowed(true); setConstructionFunction(&QdbDevice::create); setCreator([] { QdbDeviceWizard wizard(Core::ICore::dialogParent()); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index d0a8c4c8e97..0745dd95238 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -383,7 +383,9 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat setDisplayType(Tr::tr("Docker")); setOsType(OsTypeOtherUnix); setDefaultDisplayName(Tr::tr("Docker Image")); - + setupId(IDevice::ManuallyAdded); + setType(Constants::DOCKER_DEVICE_TYPE); + setMachineType(IDevice::Hardware); setDisplayName(Tr::tr("Docker Image \"%1\" (%2)").arg(data.repoAndTag()).arg(data.imageId)); setAllowEmptyCommand(true); @@ -1095,9 +1097,6 @@ public: QTC_ASSERT(item, return {}); auto device = DockerDevice::create(m_settings, *item); - device->setupId(IDevice::ManuallyAdded); - device->setType(Constants::DOCKER_DEVICE_TYPE); - device->setMachineType(IDevice::Hardware); return device; } diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index 6de16afac00..663d1932ca3 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -101,14 +101,31 @@ void DeviceSettingsWidget::initGui() m_deviceStateTextLabel = new QLabel; m_osSpecificGroupBox = new QGroupBox(Tr::tr("Type Specific")); m_osSpecificGroupBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); - m_addConfigButton = new QPushButton(Tr::tr("&Add...")); + m_addConfigButton = new QPushButton(Tr::tr("&Start Wizard to Add Device...")); m_removeConfigButton = new QPushButton(Tr::tr("&Remove")); m_defaultDeviceButton = new QPushButton(Tr::tr("Set As Default")); - auto line = new QFrame; - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - auto customButtonsContainer = new QWidget; - m_buttonsLayout = new QVBoxLayout(customButtonsContainer); + + auto directLayout = new QVBoxLayout; + for (IDeviceFactory *factory : IDeviceFactory::allDeviceFactories()) { + if (!factory->canCreate()) + continue; + auto button = new QPushButton(Tr::tr("Add %1").arg(factory->displayName())); + directLayout->addWidget(button); + if (!factory->quickCreationAllowed()) { + button->setEnabled(false); + continue; + } + connect (button, &QPushButton::clicked, this, [factory, this] { + IDevice::Ptr device = factory->construct(); + QTC_ASSERT(device, return); + m_deviceManager->addDevice(device); + m_removeConfigButton->setEnabled(true); + m_configurationComboBox->setCurrentIndex(m_deviceManagerModel->indexOf(device)); + saveSettings(); + }); + } + + m_buttonsLayout = new QVBoxLayout; m_buttonsLayout->setContentsMargins({}); auto scrollAreaWidget = new QWidget; auto scrollArea = new QScrollArea; @@ -135,10 +152,12 @@ void DeviceSettingsWidget::initGui() }, Column { m_addConfigButton, + Space(10), + directLayout, + Space(30), m_removeConfigButton, m_defaultDeviceButton, - line, - customButtonsContainer, + m_buttonsLayout, st, }, }.attachTo(this); diff --git a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp index c33bc125bb5..c20f4776d61 100644 --- a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp @@ -63,12 +63,24 @@ bool IDeviceFactory::canCreate() const IDevice::Ptr IDeviceFactory::create() const { - return m_creator ? m_creator() : IDevice::Ptr(); + if (m_creator) + return {}; + + IDevice::Ptr device = m_constructor(); + QTC_ASSERT(device, return {}); + device->setDefaultDisplayName(displayName()); + return device; } IDevice::Ptr IDeviceFactory::construct() const { - return m_constructor ? m_constructor() : IDevice::Ptr(); + if (!m_constructor) + return {}; + + IDevice::Ptr device = m_constructor(); + QTC_ASSERT(device, return {}); + device->setDefaultDisplayName(displayName()); + return device; } static QList g_deviceFactories; @@ -105,6 +117,16 @@ void IDeviceFactory::setCreator(const std::function &creator) m_creator = creator; } +void IDeviceFactory::setQuickCreationAllowed(bool on) +{ + m_quickCreationAllowed = on; +} + +bool IDeviceFactory::quickCreationAllowed() const +{ + return m_quickCreationAllowed; +} + void IDeviceFactory::setConstructionFunction(const std::function &constructor) { m_constructor = constructor; diff --git a/src/plugins/projectexplorer/devicesupport/idevicefactory.h b/src/plugins/projectexplorer/devicesupport/idevicefactory.h index 87a54244adb..665059f5b2c 100644 --- a/src/plugins/projectexplorer/devicesupport/idevicefactory.h +++ b/src/plugins/projectexplorer/devicesupport/idevicefactory.h @@ -26,6 +26,7 @@ public: bool canCreate() const; IDevicePtr construct() const; IDevicePtr create() const; + bool quickCreationAllowed() const; virtual bool canRestore(const QVariantMap &) const { return true; } @@ -41,6 +42,7 @@ protected: void setCombinedIcon(const Utils::FilePath &smallIcon, const Utils::FilePath &largeIcon); void setConstructionFunction(const std::function &constructor); void setCreator(const std::function &creator); + void setQuickCreationAllowed(bool on); private: std::function m_creator; @@ -48,6 +50,7 @@ private: QString m_displayName; QIcon m_icon; std::function m_constructor; + bool m_quickCreationAllowed = false; }; } // namespace ProjectExplorer diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index dac5c9698b3..2b6520e0025 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -9,9 +9,12 @@ #include "qnxdevicewizard.h" #include "qnxtr.h" +#include + #include #include +#include #include #include @@ -56,6 +59,13 @@ QnxDevice::QnxDevice() setDisplayType(Tr::tr("QNX")); setDefaultDisplayName(Tr::tr("QNX Device")); setOsType(OsTypeOtherUnix); + setupId(IDevice::ManuallyAdded); + setType(Constants::QNX_QNX_OS_TYPE); + setMachineType(IDevice::Hardware); + SshParameters sshParams; + sshParams.timeout = 10; + setSshParameters(sshParams); + setFreePorts(PortList::fromString("10000-10100")); addDeviceAction({Tr::tr("Deploy Qt libraries..."), [](const IDevice::Ptr &device, QWidget *parent) { QnxDeployQtLibrariesDialog dialog(device, parent); @@ -94,6 +104,7 @@ QnxDeviceFactory::QnxDeviceFactory() : IDeviceFactory(Constants::QNX_QNX_OS_TYPE setDisplayName(Tr::tr("QNX Device")); setCombinedIcon(":/qnx/images/qnxdevicesmall.png", ":/qnx/images/qnxdevice.png"); + setQuickCreationAllowed(true); setConstructionFunction(&QnxDevice::create); setCreator(&runDeviceWizard); } diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp index 4de31d898de..7bd047a590e 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp @@ -11,7 +11,6 @@ #include #include -#include #include using namespace ProjectExplorer; @@ -45,13 +44,6 @@ GenericLinuxDeviceConfigurationWizard::GenericLinuxDeviceConfigurationWizard(QWi setPage(Internal::FinalPageId, &d->finalPage); d->finalPage.setCommitPage(true); d->device = LinuxDevice::create(); - d->device->setupId(IDevice::ManuallyAdded, Utils::Id()); - d->device->setType(Constants::GenericLinuxOsType); - d->device->setMachineType(IDevice::Hardware); - d->device->setFreePorts(Utils::PortList::fromString(QLatin1String("10000-10100"))); - SshParameters sshParams; - sshParams.timeout = 10; - d->device->setSshParameters(sshParams); d->setupPage.setDevice(d->device); d->keyDeploymentPage.setDevice(d->device); } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index aa5889516cc..da7b7aa2d18 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -887,9 +888,16 @@ LinuxDevice::LinuxDevice() { setFileAccess(&d->m_fileAccess); setDisplayType(Tr::tr("Remote Linux")); - setDefaultDisplayName(Tr::tr("Remote Linux Device")); setOsType(OsTypeLinux); + setupId(IDevice::ManuallyAdded, Utils::Id()); + setType(Constants::GenericLinuxOsType); + setMachineType(IDevice::Hardware); + setFreePorts(PortList::fromString(QLatin1String("10000-10100"))); + SshParameters sshParams; + sshParams.timeout = 10; + setSshParameters(sshParams); + addDeviceAction({Tr::tr("Deploy Public Key..."), [](const IDevice::Ptr &device, QWidget *parent) { if (auto d = PublicKeyDeploymentDialog::createDialog(device, parent)) { d->exec(); @@ -1489,6 +1497,7 @@ LinuxDeviceFactory::LinuxDeviceFactory() setDisplayName(Tr::tr("Remote Linux Device")); setIcon(QIcon()); setConstructionFunction(&LinuxDevice::create); + setQuickCreationAllowed(true); setCreator([] { GenericLinuxDeviceConfigurationWizard wizard(Core::ICore::dialogParent()); if (wizard.exec() != QDialog::Accepted) From b5af4501df0d72b9bb6d977a4abe9e87355b6468 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 21 Mar 2023 19:20:55 +0100 Subject: [PATCH 0386/1447] Fix include style Change-Id: I64cb77f8d39dac35821fe96d735bc5dda35738e7 Reviewed-by: Christian Stenger --- src/libs/utils/qrcparser.h | 3 ++- src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp | 2 +- src/plugins/clangformat/clangformatfile.h | 3 ++- src/plugins/cmakeprojectmanager/cmakeprojectimporter.h | 3 ++- src/plugins/coreplugin/editormanager/editormanager.h | 4 ++-- src/plugins/coreplugin/locator/ilocatorfilter.h | 2 +- src/plugins/cppeditor/cppquickfixsettingspage.h | 4 +++- src/plugins/debugger/debuggerengine.cpp | 6 +++--- src/plugins/debugger/debuggerengine.h | 4 +++- src/plugins/docker/dockersettings.cpp | 2 +- src/plugins/imageviewer/imageview.cpp | 2 +- .../mesonprojectmanager/mesonbuildconfiguration.h | 4 ++-- src/plugins/qmakeprojectmanager/makefileparse.cpp | 7 ++++--- src/plugins/qmakeprojectmanager/qmakeparser.cpp | 7 ++++--- src/plugins/qnx/qnxconfiguration.cpp | 10 ++++------ src/plugins/studiowelcome/stylemodel.cpp | 4 ++-- src/plugins/studiowelcome/wizardhandler.cpp | 2 +- tests/auto/utils/asynctask/tst_asynctask.cpp | 5 ++--- tests/auto/utils/mathutils/tst_mathutils.cpp | 2 +- 19 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/libs/utils/qrcparser.h b/src/libs/utils/qrcparser.h index 42cd9b6666f..14352e26b8d 100644 --- a/src/libs/utils/qrcparser.h +++ b/src/libs/utils/qrcparser.h @@ -4,7 +4,8 @@ #pragma once #include "utils_global.h" -#include "utils/filepath.h" + +#include "filepath.h" #include #include diff --git a/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp b/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp index f1156857948..3abb700df1d 100644 --- a/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp +++ b/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp @@ -7,7 +7,7 @@ #include "qdbtr.h" #include -#include "projectexplorer/devicesupport/idevice.h" +#include #include #include #include diff --git a/src/plugins/clangformat/clangformatfile.h b/src/plugins/clangformat/clangformatfile.h index 6e2267befc9..dcd0e0d6c10 100644 --- a/src/plugins/clangformat/clangformatfile.h +++ b/src/plugins/clangformat/clangformatfile.h @@ -3,7 +3,8 @@ #pragma once -#include "utils/filepath.h" +#include + #include namespace CppEditor { class CppCodeStyleSettings; } diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h index 7c7716dc8b2..229ccfa36d5 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h @@ -4,10 +4,11 @@ #pragma once #include "presetsparser.h" -#include "utils/temporarydirectory.h" #include +#include + namespace CMakeProjectManager { class CMakeTool; diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index f73142a933e..6118d15c3dd 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -9,8 +9,8 @@ #include "documentmodel.h" #include "ieditor.h" -#include "utils/link.h" -#include "utils/textfileformat.h" +#include +#include #include #include diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index e7042387602..a8e30029d6f 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -3,12 +3,12 @@ #pragma once -#include "utils/tasktree.h" #include #include #include #include +#include #include #include diff --git a/src/plugins/cppeditor/cppquickfixsettingspage.h b/src/plugins/cppeditor/cppquickfixsettingspage.h index 3e14fde864a..0fea07f91a1 100644 --- a/src/plugins/cppeditor/cppquickfixsettingspage.h +++ b/src/plugins/cppeditor/cppquickfixsettingspage.h @@ -2,7 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "coreplugin/dialogs/ioptionspage.h" + +#include + #include namespace CppEditor { diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 5a465e2798b..eeba3bfe9ed 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -13,15 +13,16 @@ #include "debuggertr.h" #include "breakhandler.h" +#include "debuggermainwindow.h" #include "disassembleragent.h" +#include "enginemanager.h" #include "localsandexpressionswindow.h" #include "logwindow.h" -#include "debuggermainwindow.h" -#include "enginemanager.h" #include "memoryagent.h" #include "moduleshandler.h" #include "registerhandler.h" #include "peripheralregisterhandler.h" +#include "shared/peutils.h" #include "sourcefileshandler.h" #include "sourceutils.h" #include "stackhandler.h" @@ -31,7 +32,6 @@ #include "watchhandler.h" #include "watchutils.h" #include "watchwindow.h" -#include "debugger/shared/peutils.h" #include #include diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index c07ce656da8..215cb3081dd 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -7,12 +7,14 @@ #include "debuggerconstants.h" #include "debuggerprotocol.h" #include "breakhandler.h" -#include "projectexplorer/abi.h" #include "threadshandler.h" #include + +#include #include #include + #include #include diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp index bfec44f2433..60e9ec4ff2a 100644 --- a/src/plugins/docker/dockersettings.cpp +++ b/src/plugins/docker/dockersettings.cpp @@ -5,13 +5,13 @@ #include "dockerconstants.h" #include "dockertr.h" -#include "utils/hostosinfo.h" #include #include #include +#include #include using namespace Utils; diff --git a/src/plugins/imageviewer/imageview.cpp b/src/plugins/imageviewer/imageview.cpp index 34b74d49086..9a2af284f49 100644 --- a/src/plugins/imageviewer/imageview.cpp +++ b/src/plugins/imageviewer/imageview.cpp @@ -8,11 +8,11 @@ #include "imageviewerfile.h" #include "imageviewertr.h" #include "multiexportdialog.h" -#include "utils/mimeutils.h" #include #include +#include #include #include diff --git a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h index 6bc4a96afe8..a4059091892 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h +++ b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.h @@ -2,8 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "projectexplorer/buildconfiguration.h" -#include "projectexplorer/target.h" +#include +#include namespace MesonProjectManager { namespace Internal { diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp index 32193a4dbdc..5fbab2084dd 100644 --- a/src/plugins/qmakeprojectmanager/makefileparse.cpp +++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp @@ -359,11 +359,12 @@ void MakeFileParse::parseCommandLine(const QString &command, const QString &proj // Unit tests: #ifdef WITH_TESTS -# include -# include "qmakeprojectmanagerplugin.h" +#include "qmakeprojectmanagerplugin.h" -# include "projectexplorer/outputparser_test.h" +#include + +#include using namespace QmakeProjectManager::Internal; using namespace ProjectExplorer; diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp index e95b403bff4..2cb9d941c14 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp @@ -71,11 +71,12 @@ OutputLineParser::Result QMakeParser::handleLine(const QString &line, OutputForm // Unit tests: #ifdef WITH_TESTS -# include -# include "qmakeprojectmanagerplugin.h" +#include "qmakeprojectmanagerplugin.h" -# include "projectexplorer/outputparser_test.h" +#include + +#include using namespace QmakeProjectManager::Internal; diff --git a/src/plugins/qnx/qnxconfiguration.cpp b/src/plugins/qnx/qnxconfiguration.cpp index c1b0e498f0c..0ca024248a8 100644 --- a/src/plugins/qnx/qnxconfiguration.cpp +++ b/src/plugins/qnx/qnxconfiguration.cpp @@ -8,10 +8,12 @@ #include "qnxtoolchain.h" #include "qnxtr.h" -#include "debugger/debuggeritem.h" - #include +#include +#include +#include + #include #include #include @@ -23,10 +25,6 @@ #include -#include -#include -#include - #include #include diff --git a/src/plugins/studiowelcome/stylemodel.cpp b/src/plugins/studiowelcome/stylemodel.cpp index d93fc5fded2..1198052994e 100644 --- a/src/plugins/studiowelcome/stylemodel.cpp +++ b/src/plugins/studiowelcome/stylemodel.cpp @@ -3,8 +3,8 @@ #include "stylemodel.h" -#include "utils/algorithm.h" -#include "utils/qtcassert.h" +#include +#include #include diff --git a/src/plugins/studiowelcome/wizardhandler.cpp b/src/plugins/studiowelcome/wizardhandler.cpp index ee20518e604..d6d750d39eb 100644 --- a/src/plugins/studiowelcome/wizardhandler.cpp +++ b/src/plugins/studiowelcome/wizardhandler.cpp @@ -11,8 +11,8 @@ #include -#include "utils/wizard.h" #include +#include using namespace StudioWelcome; diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/asynctask/tst_asynctask.cpp index 12dc849591b..67a291172a1 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/asynctask/tst_asynctask.cpp @@ -1,9 +1,8 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "utils/asynctask.h" - -#include "utils/algorithm.h" +#include +#include #include diff --git a/tests/auto/utils/mathutils/tst_mathutils.cpp b/tests/auto/utils/mathutils/tst_mathutils.cpp index b817f157436..a29f908748d 100644 --- a/tests/auto/utils/mathutils/tst_mathutils.cpp +++ b/tests/auto/utils/mathutils/tst_mathutils.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "utils/mathutils.h" +#include #include From 48cd81b015c2ca8d66465cac134afa2eb5efa848 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 24 Mar 2023 13:35:03 +0100 Subject: [PATCH 0387/1447] Copilot: fixup compression timer cleanup Unfortunately the timer gets deleted to early when the temporary object that gets copied into the hash gets deleted. Delete the timer only if the editor widget or client gets destructed. Amends e6e895d6beea5e7676ac6783003d49e560f49963 Change-Id: Ifee0dce337e7fc69ffeaeb82901135bd23ea8d81 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotclient.cpp | 7 +------ src/plugins/copilot/copilotclient.h | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index e1122020926..d245e68eaa3 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -95,7 +95,7 @@ void CopilotClient::scheduleRequest(TextEditorWidget *editor) requestCompletions(editor); }); connect(editor, &TextEditorWidget::destroyed, this, [this, editor]() { - m_scheduledRequests.remove(editor); + delete m_scheduledRequests.take(editor).timer; cancelRunningRequest(editor); }); connect(editor, &TextEditorWidget::cursorPositionChanged, this, [this, editor] { @@ -108,11 +108,6 @@ void CopilotClient::scheduleRequest(TextEditorWidget *editor) m_scheduledRequests[editor].timer->start(500); } -CopilotClient::ScheduleData::~ScheduleData() -{ - delete timer; -} - void CopilotClient::requestCompletions(TextEditorWidget *editor) { Utils::MultiTextCursor cursor = editor->multiTextCursor(); diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index e29343f3680..5111e04e1df 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -50,7 +50,6 @@ private: QMap m_runningRequests; struct ScheduleData { - ~ScheduleData(); int cursorPosition = -1; QTimer *timer = nullptr; }; From 1df085b9b4f76a634a43e76e7dd07f1759fa961a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 24 Mar 2023 15:25:57 +0100 Subject: [PATCH 0388/1447] Bump version to 11.0.0-beta1 Change-Id: I6f87635449be080dcc532168c0180945f4ddc02c Reviewed-by: Eike Ziller --- cmake/QtCreatorIDEBranding.cmake | 6 +++--- qbs/modules/qtc/qtc.qbs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 0b9447a85de..713fc82d042 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "9.0.84") # The IDE version. -set(IDE_VERSION_COMPAT "9.0.84") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "10.0.0-rc1") # The IDE display version. +set(IDE_VERSION "10.0.82") # The IDE version. +set(IDE_VERSION_COMPAT "10.0.82") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "11.0.0-beta1" # The IDE display version. set(IDE_COPYRIGHT_YEAR "2023") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 14529677fe8..1e028f62fca 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -6,16 +6,16 @@ import qbs.Utilities Module { Depends { name: "cpp"; required: false } - property string qtcreator_display_version: '10.0.0-rc1' - property string ide_version_major: '9' + property string qtcreator_display_version: '11.0.0-beta1' + property string ide_version_major: '10' property string ide_version_minor: '0' - property string ide_version_release: '84' + property string ide_version_release: '82' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release - property string ide_compat_version_major: '9' + property string ide_compat_version_major: '10' property string ide_compat_version_minor: '0' - property string ide_compat_version_release: '84' + property string ide_compat_version_release: '82' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release From 623a7fa358d0b616d69c9ddb344ab1351970b8e2 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 24 Mar 2023 15:38:13 +0100 Subject: [PATCH 0389/1447] Fix QtCreatorIDEBranding.cmake Change-Id: I1513058affb047c1a6483fbcd45547348d75e756 Reviewed-by: Cristian Adam --- cmake/QtCreatorIDEBranding.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 713fc82d042..0d9e4b81860 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ set(IDE_VERSION "10.0.82") # The IDE version. set(IDE_VERSION_COMPAT "10.0.82") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "11.0.0-beta1" # The IDE display version. +set(IDE_VERSION_DISPLAY "11.0.0-beta1") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2023") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. From 884a1d6f944b1334fb1350f426944993eaaf72af Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Mar 2023 12:07:30 +0100 Subject: [PATCH 0390/1447] Replace a few \returns by Returns Change-Id: I09c633e610421f5cc8257b15de60ffa98d890ee0 Reviewed-by: Leena Miettinen --- src/libs/3rdparty/cplusplus/Symbol.h | 4 +-- src/libs/qmljs/qmljsutils.cpp | 5 ++-- src/libs/utils/multitextcursor.h | 18 ++++++------- src/plugins/clearcase/clearcaseplugin.cpp | 2 +- src/plugins/cppeditor/cppmodelmanager.cpp | 2 +- .../cppeditor/generatedcodemodelsupport.h | 2 +- src/plugins/cppeditor/insertionpointlocator.h | 26 +++++++------------ src/plugins/qmljseditor/qmljsquickfix.h | 2 +- .../qmljstools/qmljsrefactoringchanges.h | 2 +- src/plugins/texteditor/quickfix.h | 6 ++--- 10 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/Symbol.h b/src/libs/3rdparty/cplusplus/Symbol.h index 497226dcc1a..dc07ced907d 100644 --- a/src/libs/3rdparty/cplusplus/Symbol.h +++ b/src/libs/3rdparty/cplusplus/Symbol.h @@ -66,10 +66,10 @@ public: /// Returns this Symbol's source location. int sourceLocation() const { return _sourceLocation; } - /// \returns this Symbol's line number. The line number is 1-based. + /// Returns this Symbol's line number. The line number is 1-based. int line() const { return _line; } - /// \returns this Symbol's column number. The column number is 1-based. + /// Returns this Symbol's column number. The column number is 1-based. int column() const { return _column; } /// Returns this Symbol's file name. diff --git a/src/libs/qmljs/qmljsutils.cpp b/src/libs/qmljs/qmljsutils.cpp index 1609e49c68c..e33a6b3e809 100644 --- a/src/libs/qmljs/qmljsutils.cpp +++ b/src/libs/qmljs/qmljsutils.cpp @@ -115,8 +115,9 @@ SourceLocation QmlJS::fullLocationForQualifiedId(AST::UiQualifiedId *qualifiedId } /*! - \returns the value of the 'id:' binding in \a object - \param idBinding optional out parameter to get the UiScriptBinding for the id binding + Returns the value of the 'id:' binding in \a object. + + \a idBinding is optional out parameter to get the UiScriptBinding for the id binding. */ QString QmlJS::idOfObject(Node *object, UiScriptBinding **idBinding) { diff --git a/src/libs/utils/multitextcursor.h b/src/libs/utils/multitextcursor.h index edb4f5f1fd6..b2565f931ff 100644 --- a/src/libs/utils/multitextcursor.h +++ b/src/libs/utils/multitextcursor.h @@ -28,15 +28,15 @@ public: ~MultiTextCursor(); - /// replace all cursors with \param cursors and the last one will be the new main cursors + /// Replaces all cursors with \param cursors and the last one will be the new main cursors. void setCursors(const QList &cursors); const QList cursors() const; - /// \returns whether this multi cursor contains any cursor + /// Returns whether this multi cursor contains any cursor. bool isNull() const; - /// \returns whether this multi cursor contains more than one cursor + /// Returns whether this multi cursor contains more than one cursor. bool hasMultipleCursors() const; - /// \returns the number of cursors handled by this cursor + /// Returns the number of cursors handled by this cursor. int cursorCount() const; /// the \param cursor that is appended by added by \brief addCursor @@ -46,9 +46,9 @@ public: /// convenience function that removes the old main cursor and appends /// \param cursor as the new main cursor void replaceMainCursor(const QTextCursor &cursor); - /// \returns the main cursor + /// Returns the main cursor. QTextCursor mainCursor() const; - /// \returns the main cursor and removes it from this multi cursor + /// Returns the main cursor and removes it from this multi cursor. QTextCursor takeMainCursor(); void beginEditBlock(); @@ -62,10 +62,10 @@ public: /// with the move \param mode void movePosition(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode, int n = 1); - /// \returns whether any cursor has a selection + /// Returns whether any cursor has a selection. bool hasSelection() const; - /// \returns the selected text of all cursors that have a selection separated by - /// a newline character + /// Returns the selected text of all cursors that have a selection separated by + /// a newline character. QString selectedText() const; /// removes the selected text of all cursors that have a selection from the document void removeSelectedText(); diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index f60db85ac05..4c810544b3f 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -488,7 +488,7 @@ FileStatus::Status ClearCasePluginPrivate::getFileStatus(const QString &fileName /// "cleartool pwv" returns the values for "set view" and "working directory view", also for /// snapshot views. /// -/// \returns The ClearCase topLevel/VOB directory for this directory +/// Returns the ClearCase topLevel/VOB directory for this directory. QString ClearCasePluginPrivate::ccManagesDirectory(const FilePath &directory) const { const CommandResult result = runCleartoolProc(directory, {"pwv"}); diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 27984cce88f..4f482e6c6d1 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -1000,7 +1000,7 @@ Document::Ptr CppModelManager::document(const FilePath &filePath) const /// Replace the document in the snapshot. /// -/// \returns true if successful, false if the new document is out-dated. +/// Returns true if successful, false if the new document is out-dated. bool CppModelManager::replaceDocument(Document::Ptr newDoc) { QMutexLocker locker(&d->m_snapshotMutex); diff --git a/src/plugins/cppeditor/generatedcodemodelsupport.h b/src/plugins/cppeditor/generatedcodemodelsupport.h index cd7591a3b00..d37177d9910 100644 --- a/src/plugins/cppeditor/generatedcodemodelsupport.h +++ b/src/plugins/cppeditor/generatedcodemodelsupport.h @@ -20,7 +20,7 @@ public: const Utils::FilePath &generatedFile); ~GeneratedCodeModelSupport() override; - /// \returns the contents encoded in UTF-8. + /// Returns the contents encoded in UTF-8. QByteArray contents() const override; Utils::FilePath filePath() const override; // The generated file Utils::FilePath sourceFilePath() const override; diff --git a/src/plugins/cppeditor/insertionpointlocator.h b/src/plugins/cppeditor/insertionpointlocator.h index c4091d5f9dc..d6fd5d735cc 100644 --- a/src/plugins/cppeditor/insertionpointlocator.h +++ b/src/plugins/cppeditor/insertionpointlocator.h @@ -23,27 +23,21 @@ public: InsertionLocation(const Utils::FilePath &filePath, const QString &prefix, const QString &suffix, int line, int column); - const Utils::FilePath &filePath() const - { return m_filePath; } + const Utils::FilePath &filePath() const { return m_filePath; } - /// \returns The prefix to insert before any other text. - QString prefix() const - { return m_prefix; } + /// Returns the prefix to insert before any other text. + QString prefix() const { return m_prefix; } - /// \returns The suffix to insert after the other inserted text. - QString suffix() const - { return m_suffix; } + /// Returns the suffix to insert after the other inserted text. + QString suffix() const { return m_suffix; } - /// \returns The line where to insert. The line number is 1-based. - int line() const - { return m_line; } + /// Returns the line where to insert. The line number is 1-based. + int line() const { return m_line; } - /// \returns The column where to insert. The column number is 1-based. - int column() const - { return m_column; } + /// Returns the column where to insert. The column number is 1-based. + int column() const { return m_column; } - bool isValid() const - { return !m_filePath.isEmpty() && m_line > 0 && m_column > 0; } + bool isValid() const { return !m_filePath.isEmpty() && m_line > 0 && m_column > 0; } private: Utils::FilePath m_filePath; diff --git a/src/plugins/qmljseditor/qmljsquickfix.h b/src/plugins/qmljseditor/qmljsquickfix.h index 643334a94c7..b050ba4d1f1 100644 --- a/src/plugins/qmljseditor/qmljsquickfix.h +++ b/src/plugins/qmljseditor/qmljsquickfix.h @@ -44,7 +44,7 @@ protected: const QmlJSTools::SemanticInfo &semanticInfo() const; - /// \returns The name of the file for for which this operation is invoked. + /// Returns The name of the file for for which this operation is invoked. Utils::FilePath fileName() const; private: diff --git a/src/plugins/qmljstools/qmljsrefactoringchanges.h b/src/plugins/qmljstools/qmljsrefactoringchanges.h index d16564832b6..33545e2bfc5 100644 --- a/src/plugins/qmljstools/qmljsrefactoringchanges.h +++ b/src/plugins/qmljstools/qmljsrefactoringchanges.h @@ -24,7 +24,7 @@ public: QmlJS::Document::Ptr qmljsDocument() const; /*! - \returns the offset in the document for the start position of the given + Returns the offset in the document for the start position of the given source location. */ unsigned startOf(const QmlJS::SourceLocation &loc) const; diff --git a/src/plugins/texteditor/quickfix.h b/src/plugins/texteditor/quickfix.h index 6469bd7d8bc..e456230ac20 100644 --- a/src/plugins/texteditor/quickfix.h +++ b/src/plugins/texteditor/quickfix.h @@ -35,8 +35,7 @@ public: virtual ~QuickFixOperation(); /*! - \returns The priority for this quick-fix. See the QuickFixCollector for more - information. + Returns The priority for this quick-fix. See the QuickFixCollector for more information. */ virtual int priority() const; @@ -44,8 +43,7 @@ public: void setPriority(int priority); /*! - \returns The description for this quick-fix. This description is shown to the - user. + Returns The description for this quick-fix. This description is shown to the user. */ virtual QString description() const; From 9417f8b99eb7e10f0cf40deb8eceee1106c4d647 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 12:53:21 +0100 Subject: [PATCH 0391/1447] Terminal: Add search * Adds new search widget to terminal * Adds new theme color "TerminalFindMatch" * Fixes ESC key handling in terminal Fixes: QTCREATORBUG-28946 Change-Id: I7b6057d13902a94a6bcd41dde6cc8ba8418cd585 Reviewed-by: Cristian Adam --- share/qtcreator/themes/dark.creatortheme | 1 + share/qtcreator/themes/default.creatortheme | 1 + .../themes/design-light.creatortheme | 1 + share/qtcreator/themes/design.creatortheme | 1 + share/qtcreator/themes/flat-dark.creatortheme | 1 + .../qtcreator/themes/flat-light.creatortheme | 1 + share/qtcreator/themes/flat.creatortheme | 1 + src/libs/utils/theme/theme.h | 1 + src/plugins/terminal/CMakeLists.txt | 1 + src/plugins/terminal/celliterator.cpp | 15 +- src/plugins/terminal/celliterator.h | 4 +- src/plugins/terminal/terminal.qbs | 2 + src/plugins/terminal/terminalcommands.cpp | 153 +++++----- src/plugins/terminal/terminalcommands.h | 42 +-- src/plugins/terminal/terminalpane.cpp | 22 +- src/plugins/terminal/terminalpane.h | 1 - src/plugins/terminal/terminalplugin.cpp | 7 + src/plugins/terminal/terminalplugin.h | 1 + src/plugins/terminal/terminalsearch.cpp | 280 ++++++++++++++++++ src/plugins/terminal/terminalsearch.h | 82 +++++ src/plugins/terminal/terminalsettings.cpp | 5 + src/plugins/terminal/terminalsettings.h | 1 + src/plugins/terminal/terminalsettingspage.cpp | 1 + src/plugins/terminal/terminalwidget.cpp | 175 +++++++++-- src/plugins/terminal/terminalwidget.h | 29 +- 25 files changed, 686 insertions(+), 143 deletions(-) create mode 100644 src/plugins/terminal/terminalsearch.cpp create mode 100644 src/plugins/terminal/terminalsearch.h diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index 2c00e67971c..ab8e1a36f39 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -387,6 +387,7 @@ QmlDesigner_ScrollBarHandleColor=ff505050 TerminalForeground=ffffffff TerminalBackground=ff000000 TerminalSelection=7fffffff +TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 92d4ff5c11c..31a7dcc8ea2 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -355,6 +355,7 @@ QmlDesigner_ScrollBarHandleColor=ff7a7a7a TerminalForeground=ff000000 TerminalBackground=ffffffff TerminalSelection=3f000000 +TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 49895cdb7d5..550c84c41ec 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -399,6 +399,7 @@ PaletteTextDisabled=textDisabled TerminalForeground=ff000000 TerminalBackground=ffffffff TerminalSelection=3f000000 +TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index a3b8425b080..e2785d426b5 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -499,6 +499,7 @@ PalettePlaceholderText=ff808081 TerminalForeground=ffffffff TerminalBackground=ff000000 TerminalSelection=7fffffff +TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 70c86db8f6b..ac7e2bf920c 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -391,6 +391,7 @@ PalettePlaceholderText=ff7f7f80 TerminalForeground=ffffffff TerminalBackground=ff000000 TerminalSelection=7fffffff +TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index 2c41c7b68f8..be6431d2c1c 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -364,6 +364,7 @@ QmlDesigner_ScrollBarHandleColor=ffcccccc TerminalForeground=ff000000 TerminalBackground=ffffffff TerminalSelection=3f000000 +TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 15a9f7b866b..94a13d0347f 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -362,6 +362,7 @@ QmlDesigner_ScrollBarHandleColor=ff595b5c TerminalForeground=ff000000 TerminalBackground=ffffffff TerminalSelection=3f000000 +TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 2652c73b135..762f4490f9b 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -423,6 +423,7 @@ public: TerminalForeground, TerminalBackground, TerminalSelection, + TerminalFindMatch, TerminalAnsi0, TerminalAnsi1, diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index 067cab8d1cd..005a3aaca56 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -14,6 +14,7 @@ add_qtc_plugin(Terminal terminalpane.cpp terminalpane.h terminalplugin.cpp terminalplugin.h terminalprocessimpl.cpp terminalprocessimpl.h + terminalsearch.cpp terminalsearch.h terminalsettings.cpp terminalsettings.h terminalsettingspage.cpp terminalsettingspage.h terminalsurface.cpp terminalsurface.h diff --git a/src/plugins/terminal/celliterator.cpp b/src/plugins/terminal/celliterator.cpp index 101f7295213..26f347f4fda 100644 --- a/src/plugins/terminal/celliterator.cpp +++ b/src/plugins/terminal/celliterator.cpp @@ -48,10 +48,11 @@ QPoint CellIterator::gridPos() const return m_surface->posToGrid(m_pos); } -void CellIterator::updateChar() +bool CellIterator::updateChar() { QPoint cell = m_surface->posToGrid(m_pos); m_char = m_surface->fetchCharAt(cell.x(), cell.y()); + return m_char != 0; } CellIterator &CellIterator::operator-=(int n) @@ -63,7 +64,9 @@ CellIterator &CellIterator::operator-=(int n) throw new std::runtime_error("-= n too big!"); m_pos -= n; - updateChar(); + + while (!updateChar() && m_pos > 0 && m_skipZeros) + m_pos--; m_state = State::INSIDE; @@ -79,10 +82,14 @@ CellIterator &CellIterator::operator+=(int n) if (n == 0) return *this; - if (m_pos + n < m_maxpos) { + if (m_pos + n < m_maxpos + 1) { m_state = State::INSIDE; m_pos += n; - updateChar(); + while (!updateChar() && m_pos < (m_maxpos + 1) && m_skipZeros) + m_pos++; + + if (m_pos == m_maxpos + 1) + m_state = State::END; } else { *this = m_surface->end(); } diff --git a/src/plugins/terminal/celliterator.h b/src/plugins/terminal/celliterator.h index c420f4248a3..e5e7847edc2 100644 --- a/src/plugins/terminal/celliterator.h +++ b/src/plugins/terminal/celliterator.h @@ -82,13 +82,15 @@ public: } int position() const { return m_pos; } + void setSkipZeros(bool skipZeros) { m_skipZeros = skipZeros; } private: - void updateChar(); + bool updateChar(); const TerminalSurface *m_surface{nullptr}; int m_pos{-1}; int m_maxpos{-1}; + bool m_skipZeros{false}; mutable std::u32string::value_type m_char; }; diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 29c3c90e313..231d3630b7b 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -30,6 +30,8 @@ QtcPlugin { "terminalplugin.h", "terminalprocessimpl.cpp", "terminalprocessimpl.h", + "terminalsearch.cpp", + "terminalsearch.h", "terminalsettings.cpp", "terminalsettings.h", "terminalsettingspage.cpp", diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp index 2bd14090286..d9f9d5ec817 100644 --- a/src/plugins/terminal/terminalcommands.cpp +++ b/src/plugins/terminal/terminalcommands.cpp @@ -2,9 +2,11 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "terminalcommands.h" +#include "terminaltr.h" #include #include +#include #include @@ -37,81 +39,87 @@ TerminalCommands::TerminalCommands() {} void TerminalCommands::init(const Core::Context &context) { - initWidgetActions(context); - initPaneActions(context); + m_context = context; + initWidgetActions(); + initPaneActions(); initGlobalCommands(); } -void TerminalCommands::initWidgetActions(const Core::Context &context) +void TerminalCommands::registerAction(QAction &action, + const Utils::Id &id, + QList shortCuts) { - Command *command = ActionManager::instance()->registerAction(&m_widgetActions.copy, - COPY, - context); - command->setDefaultKeySequences( - {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") - : QLatin1String("Ctrl+Shift+C")), - QKeySequence(Qt::Key_Return)}); - m_commands.push_back(command); - - command = ActionManager::instance()->registerAction(&m_widgetActions.paste, PASTE, context); - command->setDefaultKeySequence(QKeySequence( - HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V"))); - m_commands.push_back(command); - - command = ActionManager::instance()->registerAction(&m_widgetActions.clearSelection, - CLEARSELECTION); - command->setDefaultKeySequence(QKeySequence("Esc")); - m_commands.push_back(command); - - command = ActionManager::instance()->registerAction(&m_widgetActions.moveCursorWordLeft, - MOVECURSORWORDLEFT); - command->setDefaultKeySequence(QKeySequence("Alt+Left")); - m_commands.push_back(command); - - command = ActionManager::instance()->registerAction(&m_widgetActions.moveCursorWordRight, - MOVECURSORWORDRIGHT); - command->setDefaultKeySequence(QKeySequence("Alt+Right")); - m_commands.push_back(command); + Command *cmd = ActionManager::instance()->registerAction(&action, id, m_context); + cmd->setKeySequences(shortCuts); + m_commands.push_back(cmd); } -void TerminalCommands::initPaneActions(const Core::Context &context) +void TerminalCommands::initWidgetActions() { - Command *command = ActionManager::instance()->registerAction(&m_paneActions.newTerminal, - NEWTERMINAL, - context); - command->setDefaultKeySequence(QKeySequence( - HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") : QLatin1String("Ctrl+Shift+T"))); - m_commands.push_back(command); + m_widgetActions.copy.setText(Tr::tr("Copy")); + m_widgetActions.paste.setText(Tr::tr("Paste")); + m_widgetActions.clearSelection.setText(Tr::tr("Clear Selection")); + m_widgetActions.clearTerminal.setText(Tr::tr("Clear Terminal")); + m_widgetActions.moveCursorWordLeft.setText(Tr::tr("Move Cursor Word Left")); + m_widgetActions.moveCursorWordRight.setText(Tr::tr("Move Cursor Word Right")); + m_widgetActions.findNext.setText(Tr::tr("Find Next")); + m_widgetActions.findPrevious.setText(Tr::tr("Find Previous")); - command = ActionManager::instance()->registerAction(&m_paneActions.closeTerminal, - CLOSETERMINAL, - context); - command->setDefaultKeySequence(QKeySequence( - HostOsInfo::isMacHost() ? QLatin1String("Ctrl+W") : QLatin1String("Ctrl+Shift+W"))); - m_commands.push_back(command); + registerAction(m_widgetActions.copy, + COPY, + {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") + : QLatin1String("Ctrl+Shift+C"))}); - command = ActionManager::instance()->registerAction(&m_paneActions.nextTerminal, - NEXTTERMINAL, - context); - command->setDefaultKeySequences( - {QKeySequence("ALT+TAB"), - QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[") - : QLatin1String("Ctrl+PgUp"))}); - m_commands.push_back(command); + registerAction(m_widgetActions.paste, + PASTE, + {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") + : QLatin1String("Ctrl+Shift+V"))}); - command = ActionManager::instance()->registerAction(&m_paneActions.prevTerminal, - PREVTERMINAL, - context); - command->setDefaultKeySequences( - {QKeySequence("ALT+SHIFT+TAB"), - QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+]") - : QLatin1String("Ctrl+PgDown"))}); - m_commands.push_back(command); + registerAction(m_widgetActions.clearSelection, CLEARSELECTION); - command = ActionManager::instance()->registerAction(&m_paneActions.minMax, MINMAX, context); - command->setDefaultKeySequence(QKeySequence( - HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return") : QLatin1String("Alt+Return"))); - m_commands.push_back(command); + registerAction(m_widgetActions.moveCursorWordLeft, + MOVECURSORWORDLEFT, + {QKeySequence("Alt+Left")}); + + registerAction(m_widgetActions.moveCursorWordRight, + MOVECURSORWORDRIGHT, + {QKeySequence("Alt+Right")}); +} + +void TerminalCommands::initPaneActions() +{ + m_paneActions.newTerminal.setText(Tr::tr("New Terminal")); + m_paneActions.closeTerminal.setText(Tr::tr("Close Terminal")); + m_paneActions.nextTerminal.setText(Tr::tr("Next Terminal")); + m_paneActions.prevTerminal.setText(Tr::tr("Previous Terminal")); + m_paneActions.minMax.setText(Tr::tr("Minimize/Maximize Terminal")); + + registerAction(m_paneActions.newTerminal, + NEWTERMINAL, + {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") + : QLatin1String("Ctrl+Shift+T"))}); + + registerAction(m_paneActions.closeTerminal, + CLOSETERMINAL, + {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+W") + : QLatin1String("Ctrl+Shift+W"))}); + + registerAction(m_paneActions.nextTerminal, + NEXTTERMINAL, + {QKeySequence("ALT+TAB"), + QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[") + : QLatin1String("Ctrl+PgUp"))}); + + registerAction(m_paneActions.prevTerminal, + PREVTERMINAL, + {QKeySequence("ALT+SHIFT+TAB"), + QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+]") + : QLatin1String("Ctrl+PgDown"))}); + + registerAction(m_paneActions.minMax, + MINMAX, + {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return") + : QLatin1String("Alt+Return"))}); } void TerminalCommands::initGlobalCommands() @@ -153,13 +161,20 @@ QAction *TerminalCommands::openSettingsAction() return ActionManager::command("Preferences.Terminal.General")->action(); } -void TerminalCommands::registerOpenCloseTerminalPaneCommand() +void TerminalCommands::lazyInitCommand(const Utils::Id &id) { - Command* terminalCmd = ActionManager::command("QtCreator.Pane.Terminal"); - QTC_ASSERT(terminalCmd, return); + Command *cmd = ActionManager::command(id); + QTC_ASSERT(cmd, return); + m_commands.append(cmd); +} - if (!m_commands.contains(terminalCmd)) - m_commands.append(terminalCmd); +void TerminalCommands::lazyInitCommands() +{ + static const Utils::Id terminalPaneCmd("QtCreator.Pane.Terminal"); + lazyInitCommand(terminalPaneCmd); + lazyInitCommand(Core::Constants::FIND_IN_DOCUMENT); + lazyInitCommand(Core::Constants::FIND_NEXT); + lazyInitCommand(Core::Constants::FIND_PREVIOUS); } } // namespace Terminal diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h index 59f9add643e..80af894d662 100644 --- a/src/plugins/terminal/terminalcommands.h +++ b/src/plugins/terminal/terminalcommands.h @@ -3,6 +3,10 @@ #pragma once +#include + +#include + #include #include #include @@ -10,29 +14,29 @@ namespace Core { class Command; class Context; -} +} // namespace Core namespace Terminal { struct WidgetActions { - QAction copy{QCoreApplication::translate("QtC::Terminal", "Copy")}; - QAction paste{QCoreApplication::translate("QtC::Terminal", "Paste")}; - QAction clearSelection{QCoreApplication::translate("QtC::Terminal", "Clear Selection")}; - QAction clearTerminal{QCoreApplication::translate("QtC::Terminal", "Clear Terminal")}; - QAction moveCursorWordLeft{QCoreApplication::translate("QtC::Terminal", - "Move Cursor Word Left")}; - QAction moveCursorWordRight{QCoreApplication::translate("QtC::Terminal", - "Move Cursor Word Right")}; + QAction copy; + QAction paste; + QAction clearSelection; + QAction clearTerminal; + QAction moveCursorWordLeft; + QAction moveCursorWordRight; + QAction findNext; + QAction findPrevious; }; struct PaneActions { - QAction newTerminal{QCoreApplication::translate("QtC::Terminal", "New Terminal")}; - QAction closeTerminal{QCoreApplication::translate("QtC::Terminal", "Close Terminal")}; - QAction nextTerminal{QCoreApplication::translate("QtC::Terminal", "Next Terminal")}; - QAction prevTerminal{QCoreApplication::translate("QtC::Terminal", "Previous Terminal")}; - QAction minMax{QCoreApplication::translate("QtC::Terminal", "Minimize/Maximize Terminal")}; + QAction newTerminal; + QAction closeTerminal; + QAction nextTerminal; + QAction prevTerminal; + QAction minMax; }; class TerminalCommands @@ -51,17 +55,21 @@ public: static QAction *openSettingsAction(); - void registerOpenCloseTerminalPaneCommand(); + void lazyInitCommands(); protected: - void initWidgetActions(const Core::Context &context); - void initPaneActions(const Core::Context &context); + void initWidgetActions(); + void initPaneActions(); void initGlobalCommands(); + void lazyInitCommand(const Utils::Id &id); + void registerAction(QAction &action, const Utils::Id &id, QList shortcuts = {}); + private: WidgetActions m_widgetActions; PaneActions m_paneActions; QList m_commands; + Core::Context m_context; }; } // namespace Terminal diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 961359712a5..7295216e162 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -33,6 +33,8 @@ TerminalPane::TerminalPane(QObject *parent) , m_tabWidget(new QTabWidget) { setupContext("Terminal.Pane", m_tabWidget); + setZoomButtonsEnabled(true); + TerminalCommands::instance().init(Core::Context("Terminal.Pane")); connect(this, &IOutputPane::zoomInRequested, this, [this] { @@ -47,16 +49,18 @@ TerminalPane::TerminalPane(QObject *parent) QAction &newTerminal = TerminalCommands::instance().paneActions().newTerminal; QAction &closeTerminal = TerminalCommands::instance().paneActions().closeTerminal; - newTerminal.setIcon(Icon({ - {":/terminal/images/terminal.png", Theme::IconsBaseColor}, - {":/utils/images/iconoverlay_add_small.png", Theme::IconsRunToolBarColor}}).icon()); + newTerminal.setIcon( + Icon({{":/terminal/images/terminal.png", Theme::IconsBaseColor}, + {":/utils/images/iconoverlay_add_small.png", Theme::IconsRunToolBarColor}}) + .icon()); newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); - closeTerminal.setIcon(Icon({ - {":/terminal/images/terminal.png", Theme::IconsBaseColor}, - {":/utils/images/iconoverlay_close_small.png", Theme::IconsStopToolBarColor}}).icon()); + closeTerminal.setIcon( + Icon({{":/terminal/images/terminal.png", Theme::IconsBaseColor}, + {":/utils/images/iconoverlay_close_small.png", Theme::IconsStopToolBarColor}}) + .icon()); closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); closeTerminal.setEnabled(false); @@ -289,12 +293,6 @@ void TerminalPane::clearContents() t->clearContents(); } -void TerminalPane::visibilityChanged(bool visible) -{ - if (visible) - TerminalCommands::instance().registerOpenCloseTerminalPaneCommand(); -} - void TerminalPane::setFocus() { if (const auto t = currentTerminal()) diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 47cb3ac039e..952f863e27c 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -27,7 +27,6 @@ public: QString displayName() const override; int priorityInStatusBar() const override; void clearContents() override; - void visibilityChanged(bool visible) override; void setFocus() override; bool hasFocus() const override; bool canFocus() const override; diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp index 409030acd12..9062e417f0f 100644 --- a/src/plugins/terminal/terminalplugin.cpp +++ b/src/plugins/terminal/terminalplugin.cpp @@ -7,6 +7,7 @@ #include "terminalprocessimpl.h" #include "terminalsettings.h" #include "terminalsettingspage.h" +#include "terminalcommands.h" #include #include @@ -35,6 +36,12 @@ TerminalPlugin::~TerminalPlugin() m_terminalPane = nullptr; } +bool TerminalPlugin::delayedInitialize() +{ + TerminalCommands::instance().lazyInitCommands(); + return true; +} + void TerminalPlugin::extensionsInitialized() { TerminalSettingsPage::instance().init(); diff --git a/src/plugins/terminal/terminalplugin.h b/src/plugins/terminal/terminalplugin.h index 5e39dded711..2bfbd9f22e0 100644 --- a/src/plugins/terminal/terminalplugin.h +++ b/src/plugins/terminal/terminalplugin.h @@ -20,6 +20,7 @@ public: ~TerminalPlugin() override; void extensionsInitialized() override; + bool delayedInitialize() override; private: TerminalPane *m_terminalPane{nullptr}; diff --git a/src/plugins/terminal/terminalsearch.cpp b/src/plugins/terminal/terminalsearch.cpp new file mode 100644 index 00000000000..5339beef26e --- /dev/null +++ b/src/plugins/terminal/terminalsearch.cpp @@ -0,0 +1,280 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "terminalsearch.h" +#include "terminalcommands.h" + +#include +#include + +#include + +using namespace std::chrono_literals; + +namespace Terminal { + +using namespace Terminal::Internal; + +constexpr std::chrono::milliseconds debounceInterval = 100ms; + +TerminalSearch::TerminalSearch(TerminalSurface *surface) + : m_surface(surface) +{ + m_debounceTimer.setInterval(debounceInterval); + m_debounceTimer.setSingleShot(true); + + connect(surface, &TerminalSurface::invalidated, this, &TerminalSearch::updateHits); + connect(&m_debounceTimer, &QTimer::timeout, this, &TerminalSearch::debouncedUpdateHits); + + connect(&TerminalCommands::widgetActions().findNext, + &QAction::triggered, + this, + &TerminalSearch::nextHit); + connect(&TerminalCommands::widgetActions().findPrevious, + &QAction::triggered, + this, + &TerminalSearch::previousHit); +} + +void TerminalSearch::setCurrentSelection(std::optional selection) +{ + m_currentSelection = selection; +} + +void TerminalSearch::setSearchString(const QString &searchString, Core::FindFlags findFlags) +{ + if (m_currentSearchString != searchString || m_findFlags != findFlags) { + m_currentSearchString = searchString; + m_findFlags = findFlags; + updateHits(); + } +} + +void TerminalSearch::nextHit() +{ + if (m_hits.isEmpty()) + return; + + m_currentHit = (m_currentHit + 1) % m_hits.size(); + emit currentHitChanged(); +} + +void TerminalSearch::previousHit() +{ + if (m_hits.isEmpty()) + return; + + m_currentHit = (m_currentHit - 1 + m_hits.size()) % m_hits.size(); + emit currentHitChanged(); +} + +void TerminalSearch::updateHits() +{ + if (!m_hits.isEmpty()) { + m_hits.clear(); + m_currentHit = -1; + emit hitsChanged(); + emit currentHitChanged(); + } + + m_debounceTimer.start(); +} + +bool isSpace(char32_t a, char32_t b) +{ + if (a == std::numeric_limits::max()) + return std::isspace(b); + else if (b == std::numeric_limits::max()) + return std::isspace(a); + + return false; +} + +QList TerminalSearch::search() +{ + QList hits; + + std::function compare; + + if (m_findFlags.testFlag(Core::FindFlag::FindCaseSensitively)) + compare = [](char32_t a, char32_t b) { + return std::tolower(a) == std::tolower(b) || isSpace(a, b); + }; + else + compare = [](char32_t a, char32_t b) { return a == b || isSpace(a, b); }; + + if (!m_currentSearchString.isEmpty()) { + const QList asUcs4 = m_currentSearchString.toUcs4(); + std::u32string searchString(asUcs4.begin(), asUcs4.end()); + + if (m_findFlags.testFlag(Core::FindFlag::FindWholeWords)) { + searchString.push_back(std::numeric_limits::max()); + searchString.insert(searchString.begin(), std::numeric_limits::max()); + } + + Internal::CellIterator it = m_surface->begin(); + while (it != m_surface->end()) { + it = std::search(it, m_surface->end(), searchString.begin(), searchString.end(), compare); + + if (it != m_surface->end()) { + auto hit = SearchHit{it.position(), + static_cast(it.position() + searchString.size())}; + if (m_findFlags.testFlag(Core::FindFlag::FindWholeWords)) { + hit.start++; + hit.end--; + } + hits << hit; + it += m_currentSearchString.size(); + } + } + } + return hits; +} + +QList TerminalSearch::searchRegex() +{ + QList hits; + + QString allText; + allText.reserve(1000); + + // Contains offsets at which there are characters > 2 bytes + QList adjustTable; + + for (auto it = m_surface->begin(); it != m_surface->end(); ++it) { + auto chs = QChar::fromUcs4(*it); + if (chs.size() > 1) + adjustTable << (allText.size()); + allText += chs; + } + + QRegularExpression re(m_currentSearchString, + m_findFlags.testFlag(Core::FindFlag::FindCaseSensitively) + ? QRegularExpression::NoPatternOption + : QRegularExpression::CaseInsensitiveOption); + + QRegularExpressionMatchIterator it = re.globalMatch(allText); + int adjust = 0; + auto itAdjust = adjustTable.begin(); + while (it.hasNext()) { + QRegularExpressionMatch match = it.next(); + int s = match.capturedStart(); + int e = match.capturedEnd(); + + // Update 'adjust' to account for characters > 2 bytes + if (itAdjust != adjustTable.end()) { + while (s > *itAdjust && itAdjust != adjustTable.end()) { + adjust++; + itAdjust++; + } + s -= adjust; + while (e > *itAdjust && itAdjust != adjustTable.end()) { + adjust++; + itAdjust++; + } + e -= adjust; + } + hits << SearchHit{s, e}; + } + + return hits; +} + +void TerminalSearch::debouncedUpdateHits() +{ + QElapsedTimer t; + t.start(); + + m_currentHit = -1; + + const bool regex = m_findFlags.testFlag(Core::FindFlag::FindRegularExpression); + + QList hits = regex ? searchRegex() : search(); + + if (hits != m_hits) { + m_currentHit = -1; + if (m_currentSelection) + m_currentHit = hits.indexOf(*m_currentSelection); + + if (m_currentHit == -1 && !hits.isEmpty()) + m_currentHit = 0; + + m_hits = hits; + emit hitsChanged(); + emit currentHitChanged(); + emit changed(); + } + if (!m_currentSearchString.isEmpty()) + qDebug() << "Search took" << t.elapsed() << "ms"; +} + +Core::FindFlags TerminalSearch::supportedFindFlags() const +{ + return Core::FindFlag::FindCaseSensitively | Core::FindFlag::FindBackward + | Core::FindFlag::FindRegularExpression | Core::FindFlag::FindWholeWords; +} + +void TerminalSearch::resetIncrementalSearch() +{ + m_currentSelection.reset(); +} + +void TerminalSearch::clearHighlights() +{ + setSearchString("", {}); +} + +QString TerminalSearch::currentFindString() const +{ + if (m_currentSelection) + return m_currentSelection->text; + else + return m_currentSearchString; +} + +QString TerminalSearch::completedFindString() const +{ + return {}; +} + +Core::IFindSupport::Result TerminalSearch::findIncremental(const QString &txt, + Core::FindFlags findFlags) +{ + if (txt == m_currentSearchString) { + if (m_debounceTimer.isActive()) + return Result::NotYetFound; + else if (m_hits.isEmpty()) + return Result::NotFound; + else + return Result::Found; + } + + setSearchString(txt, findFlags); + return Result::NotYetFound; +} + +Core::IFindSupport::Result TerminalSearch::findStep(const QString &txt, Core::FindFlags findFlags) +{ + if (txt == m_currentSearchString) { + if (m_debounceTimer.isActive()) + return Result::NotYetFound; + else if (m_hits.isEmpty()) + return Result::NotFound; + + if (findFlags.testFlag(Core::FindFlag::FindBackward)) + previousHit(); + else + nextHit(); + + return Result::Found; + } + + return findIncremental(txt, findFlags); +} + +void TerminalSearch::highlightAll(const QString &txt, Core::FindFlags findFlags) +{ + setSearchString(txt, findFlags); +} + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalsearch.h b/src/plugins/terminal/terminalsearch.h new file mode 100644 index 00000000000..29af50fa0da --- /dev/null +++ b/src/plugins/terminal/terminalsearch.h @@ -0,0 +1,82 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "terminalsurface.h" + +#include +#include + +#include + +namespace Terminal { + +struct SearchHit +{ + int start{-1}; + int end{-1}; + + bool operator!=(const SearchHit &other) const + { + return start != other.start || end != other.end; + } + bool operator==(const SearchHit &other) const { return !operator!=(other); } +}; + +struct SearchHitWithText : SearchHit +{ + QString text; +}; + +class TerminalSearch : public Core::IFindSupport +{ + Q_OBJECT +public: + TerminalSearch(Internal::TerminalSurface *surface); + + void setCurrentSelection(std::optional selection); + void setSearchString(const QString &searchString, Core::FindFlags findFlags); + void nextHit(); + void previousHit(); + + QList hits() const { return m_hits; } + SearchHit currentHit() const + { + return m_currentHit >= 0 ? m_hits.at(m_currentHit) : SearchHit{}; + } + +public: + bool supportsReplace() const override { return false; } + Core::FindFlags supportedFindFlags() const override; + void resetIncrementalSearch() override; + void clearHighlights() override; + QString currentFindString() const override; + QString completedFindString() const override; + Result findIncremental(const QString &txt, Core::FindFlags findFlags) override; + Result findStep(const QString &txt, Core::FindFlags findFlags) override; + + void highlightAll(const QString &, Core::FindFlags) override; + +signals: + void hitsChanged(); + void currentHitChanged(); + +protected: + void updateHits(); + void debouncedUpdateHits(); + QList search(); + QList searchRegex(); + +private: + std::optional m_currentSelection; + QString m_currentSearchString; + Core::FindFlags m_findFlags; + Internal::TerminalSurface *m_surface; + + int m_currentHit{-1}; + QList m_hits; + QTimer m_debounceTimer; +}; + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index a7c0d8fb2cf..b813ee246c6 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -110,6 +110,11 @@ TerminalSettings::TerminalSettings() "Selection", Utils::creatorTheme()->color(Theme::TerminalSelection)); + setupColor(this, + findMatchColor, + "Find matches", + Utils::creatorTheme()->color(Theme::TerminalFindMatch)); + setupColor(this, colors[0], "0", Utils::creatorTheme()->color(Theme::TerminalAnsi0)); setupColor(this, colors[8], "8", Utils::creatorTheme()->color(Theme::TerminalAnsi8)); diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index c793bd123a3..35f40031737 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -22,6 +22,7 @@ public: Utils::ColorAspect foregroundColor; Utils::ColorAspect backgroundColor; Utils::ColorAspect selectionColor; + Utils::ColorAspect findMatchColor; Utils::ColorAspect colors[16]; diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index 54ddc4d35e9..86fb2edda38 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -399,6 +399,7 @@ QWidget *TerminalSettingsPage::widget() Tr::tr("Foreground"), settings.foregroundColor, st, Tr::tr("Background"), settings.backgroundColor, st, Tr::tr("Selection"), settings.selectionColor, st, + Tr::tr("Find match"), settings.findMatchColor, st, }, Row { settings.colors[0], settings.colors[1], diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 458e5554008..07080ea23f9 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -7,6 +7,10 @@ #include "terminalsettings.h" #include "terminalsurface.h" +#include + +#include +#include #include #include #include @@ -48,6 +52,15 @@ using namespace Utils::Terminal; namespace Terminal { +namespace ColorIndex { +enum Indices { + Foreground = Internal::ColorIndex::Foreground, + Background = Internal::ColorIndex::Background, + Selection, + FindMatch, +}; +} + using namespace std::chrono_literals; // Minimum time between two refreshes. (30fps) @@ -72,7 +85,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op m_cursorBlinkState = !m_cursorBlinkState; else m_cursorBlinkState = true; - updateViewport(gridToViewport(QRect{m_cursor.position, m_cursor.position})); + updateViewportRect(gridToViewport(QRect{m_cursor.position, m_cursor.position})); }); setAttribute(Qt::WA_InputMethodEnabled); @@ -107,6 +120,18 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op setupFont(); configBlinkTimer(); }); + + m_aggregate = new Aggregation::Aggregate(this); + m_aggregate->add(this); + m_aggregate->add(m_search.get()); +} + +TerminalWidget::~TerminalWidget() +{ + // The Aggregate stuff tries to do clever deletion of the children, but we + // we don't want that. + m_aggregate->remove(this); + m_aggregate->remove(m_search.get()); } void TerminalWidget::setupPty() @@ -203,12 +228,14 @@ void TerminalWidget::setupFont() void TerminalWidget::setupColors() { // Check if the colors have changed. - std::array newColors; + std::array newColors; for (int i = 0; i < 16; ++i) { newColors[i] = TerminalSettings::instance().colors[i].value(); } - newColors[16] = TerminalSettings::instance().foregroundColor.value(); - newColors[17] = TerminalSettings::instance().backgroundColor.value(); + newColors[ColorIndex::Background] = TerminalSettings::instance().backgroundColor.value(); + newColors[ColorIndex::Foreground] = TerminalSettings::instance().foregroundColor.value(); + newColors[ColorIndex::Selection] = TerminalSettings::instance().selectionColor.value(); + newColors[ColorIndex::FindMatch] = TerminalSettings::instance().findMatchColor.value(); if (m_currentColors == newColors) return; @@ -250,6 +277,16 @@ void TerminalWidget::setupSurface() { m_shellIntegration.reset(new ShellIntegration()); m_surface = std::make_unique(QSize{80, 60}, m_shellIntegration.get()); + m_search = std::make_unique(m_surface.get()); + + connect(m_search.get(), &TerminalSearch::hitsChanged, this, &TerminalWidget::updateViewport); + connect(m_search.get(), &TerminalSearch::currentHitChanged, this, [this] { + SearchHit hit = m_search->currentHit(); + if (hit.start >= 0) { + setSelection(Selection{hit.start, hit.end, true}, hit != m_lastSelectedHit); + m_lastSelectedHit = hit; + } + }); connect(m_surface.get(), &Internal::TerminalSurface::writeToPty, @@ -263,7 +300,8 @@ void TerminalWidget::setupSurface() this, [this](const QRect &rect) { setSelection(std::nullopt); - updateViewport(gridToViewport(rect)); + updateViewportRect(gridToViewport(rect)); + verticalScrollBar()->setValue(m_surface->fullSize().height()); }); connect(m_surface.get(), &Internal::TerminalSurface::cursorChanged, @@ -282,7 +320,8 @@ void TerminalWidget::setupSurface() m_cursor = newCursor; - updateViewport(gridToViewport(QRect{QPoint{startX, startY}, QPoint{endX, endY}})); + updateViewportRect( + gridToViewport(QRect{QPoint{startX, startY}, QPoint{endX, endY}})); configBlinkTimer(); }); connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] { @@ -330,7 +369,7 @@ QColor TerminalWidget::toQColor(std::variant color) const if (idx >= 0 && idx < 18) return m_currentColors[idx]; - return m_currentColors[Internal::ColorIndex::Background]; + return m_currentColors[ColorIndex::Background]; } return std::get(color); } @@ -460,24 +499,34 @@ QString TerminalWidget::textFromSelection() const Internal::CellIterator end = m_surface->iteratorAt(m_selection->end); std::u32string s; + bool previousWasZero = false; for (; it != end; ++it) { - if (it.gridPos().x() == 0 && !s.empty()) + if (it.gridPos().x() == 0 && !s.empty() && previousWasZero) s += U'\n'; - if (*it != 0) + + if (*it != 0) { + previousWasZero = false; s += *it; + } else { + previousWasZero = true; + } } return QString::fromUcs4(s.data(), static_cast(s.size())); } -bool TerminalWidget::setSelection(const std::optional &selection) +bool TerminalWidget::setSelection(const std::optional &selection, bool scroll) { + qCDebug(selectionLog) << "setSelection" << selection.has_value(); + if (selection.has_value()) + qCDebug(selectionLog) << "start:" << selection->start << "end:" << selection->end + << "final:" << selection->final; + if (selectionLog().isDebugEnabled()) updateViewport(); - if (selection == m_selection) { + if (selection == m_selection) return false; - } m_selection = selection; @@ -485,13 +534,25 @@ bool TerminalWidget::setSelection(const std::optional &selection) if (m_selection && m_selection->final) { qCDebug(selectionLog) << "Copy enabled:" << selection.has_value(); + QString text = textFromSelection(); QClipboard *clipboard = QApplication::clipboard(); if (clipboard->supportsSelection()) { - QString text = textFromSelection(); qCDebug(selectionLog) << "Selection set to clipboard: " << text; clipboard->setText(text, QClipboard::Selection); } + + if (scroll) { + QPoint start = m_surface->posToGrid(m_selection->start); + QPoint end = m_surface->posToGrid(m_selection->end); + QRect viewRect = gridToViewport(QRect{start, end}); + if (viewRect.y() >= viewport()->height() || viewRect.y() < 0) { + // Selection is outside of the viewport, scroll to it. + verticalScrollBar()->setValue(start.y()); + } + } + + m_search->setCurrentSelection(SearchHitWithText{{selection->start, selection->end}, text}); } if (!selectionLog().isDebugEnabled()) @@ -727,32 +788,64 @@ static void drawTextItemDecoration(QPainter &painter, painter.setBrush(oldBrush); } -void TerminalWidget::paintSelectionOrBackground(QPainter &p, - const Internal::TerminalCell &cell, - const QRectF &cellRect, - const QPoint gridPos) const +bool TerminalWidget::paintFindMatches(QPainter &p, + QList::const_iterator &it, + const QRectF &cellRect, + const QPoint gridPos) const +{ + if (it == m_search->hits().constEnd()) + return false; + + const int pos = m_surface->gridToPos(gridPos); + while (it != m_search->hits().constEnd()) { + if (pos < it->start) + return false; + + if (pos >= it->end) { + ++it; + continue; + } + break; + } + if (it == m_search->hits().constEnd()) + return false; + + p.fillRect(cellRect, m_currentColors[ColorIndex::FindMatch]); + + return true; +} + +bool TerminalWidget::paintSelection(QPainter &p, const QRectF &cellRect, const QPoint gridPos) const { bool isInSelection = false; + const int pos = m_surface->gridToPos(gridPos); if (m_selection) { - const int pos = m_surface->gridToPos(gridPos); isInSelection = pos >= m_selection->start && pos < m_selection->end; } - if (isInSelection) - p.fillRect(cellRect, TerminalSettings::instance().selectionColor.value()); - else if (!(std::holds_alternative(cell.backgroundColor) - && std::get(cell.backgroundColor) == 17)) - p.fillRect(cellRect, toQColor(cell.backgroundColor)); + if (isInSelection) { + p.fillRect(cellRect, m_currentColors[ColorIndex::Selection]); + } + + return isInSelection; } int TerminalWidget::paintCell(QPainter &p, const QRectF &cellRect, QPoint gridPos, const Internal::TerminalCell &cell, - QFont &f) const + QFont &f, + QList::const_iterator &searchIt) const { - paintSelectionOrBackground(p, cell, cellRect, gridPos); + bool paintBackground = !paintSelection(p, cellRect, gridPos) + && !paintFindMatches(p, searchIt, cellRect, gridPos); + + bool isDefaultBg = std::holds_alternative(cell.backgroundColor) + && std::get(cell.backgroundColor) == 17; + + if (paintBackground && !isDefaultBg) + p.fillRect(cellRect, toQColor(cell.backgroundColor)); p.setPen(toQColor(cell.foregroundColor)); @@ -865,6 +958,14 @@ void TerminalWidget::paintCells(QPainter &p, QPaintEvent *event) const qCeil((event->rect().y() + event->rect().height()) / m_cellSize.height()) + scrollOffset); + QList::const_iterator searchIt + = std::lower_bound(m_search->hits().constBegin(), + m_search->hits().constEnd(), + startRow, + [this](const SearchHit &hit, int value) { + return m_surface->posToGrid(hit.start).y() < value; + }); + for (int cellY = startRow; cellY < endRow; ++cellY) { for (int cellX = 0; cellX < m_surface->liveSize().width();) { const auto cell = m_surface->fetchCell(cellX, cellY); @@ -872,7 +973,7 @@ void TerminalWidget::paintCells(QPainter &p, QPaintEvent *event) const QRectF cellRect(gridToGlobal({cellX, cellY}), QSizeF{m_cellSize.width() * cell.width, m_cellSize.height()}); - int numCells = paintCell(p, cellRect, {cellX, cellY}, cell, f); + int numCells = paintCell(p, cellRect, {cellX, cellY}, cell, f, searchIt); cellX += numCells; } @@ -907,7 +1008,7 @@ void TerminalWidget::paintEvent(QPaintEvent *event) if (paintLog().isDebugEnabled()) p.fillRect(event->rect(), QColor::fromRgb(rand() % 60, rand() % 60, rand() % 60)); else - p.fillRect(event->rect(), m_currentColors[Internal::ColorIndex::Background]); + p.fillRect(event->rect(), m_currentColors[ColorIndex::Background]); int scrollOffset = verticalScrollBar()->value(); int offset = -(scrollOffset * m_cellSize.height()); @@ -923,7 +1024,7 @@ void TerminalWidget::paintEvent(QPaintEvent *event) p.restore(); p.fillRect(QRectF{{0, 0}, QSizeF{(qreal) width(), topMargin()}}, - m_currentColors[Internal::ColorIndex::Background]); + m_currentColors[ColorIndex::Background]); if (selectionLog().isDebugEnabled()) { if (m_selection) @@ -946,8 +1047,20 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) m_cursorBlinkState = true; } + if (event->key() == Qt::Key_Escape) { + if (m_selection) + TerminalCommands::widgetActions().clearSelection.trigger(); + else { + QTC_ASSERT(Core::ActionManager::command(Core::Constants::S_RETURNTOEDITOR), return); + Core::ActionManager::command(Core::Constants::S_RETURNTOEDITOR)->action()->trigger(); + } + return; + } + + auto oldSelection = m_selection; if (TerminalCommands::triggerAction(event)) { - setSelection(std::nullopt); + if (oldSelection && oldSelection == m_selection) + setSelection(std::nullopt); return; } @@ -1023,7 +1136,7 @@ void TerminalWidget::updateViewport() viewport()->update(); } -void TerminalWidget::updateViewport(const QRect &rect) +void TerminalWidget::updateViewportRect(const QRect &rect) { viewport()->update(rect); } @@ -1297,7 +1410,7 @@ bool TerminalWidget::event(QEvent *event) if (event->type() == QEvent::Paint) { QPainter p(this); - p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[Internal::ColorIndex::Background]); + p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[ColorIndex::Background]); return true; } diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 95f80d687ce..215d8c6d58e 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -3,8 +3,11 @@ #pragma once +#include "terminalsearch.h" #include "terminalsurface.h" +#include + #include #include #include @@ -26,6 +29,7 @@ class TerminalWidget : public QAbstractScrollArea public: TerminalWidget(QWidget *parent = nullptr, const Utils::Terminal::OpenTerminalParameters &openParameters = {}); + ~TerminalWidget() override; void setFont(const QFont &font); @@ -42,6 +46,8 @@ public: void clearContents(); + TerminalSearch *search() { return m_search.get(); } + struct Selection { int start; @@ -113,14 +119,16 @@ protected: const QRectF &cellRect, QPoint gridPos, const Internal::TerminalCell &cell, - QFont &f) const; + QFont &f, + QList::const_iterator &searchIt) const; void paintCells(QPainter &painter, QPaintEvent *event) const; void paintCursor(QPainter &painter) const; void paintPreedit(QPainter &painter) const; - void paintSelectionOrBackground(QPainter &painter, - const Internal::TerminalCell &cell, - const QRectF &cellRect, - const QPoint gridPos) const; + bool paintFindMatches(QPainter &painter, + QList::const_iterator &searchIt, + const QRectF &cellRect, + const QPoint gridPos) const; + bool paintSelection(QPainter &painter, const QRectF &cellRect, const QPoint gridPos) const; void paintDebugSelection(QPainter &painter, const Selection &selection) const; qreal topMargin() const; @@ -132,7 +140,7 @@ protected: QRect gridToViewport(QRect rect) const; void updateViewport(); - void updateViewport(const QRect &rect); + void updateViewportRect(const QRect &rect); int textLineFromPixel(int y) const; std::optional textPosFromPoint(const QTextLayout &textLayout, QPoint p) const; @@ -156,7 +164,7 @@ protected: void flushVTerm(bool force); - bool setSelection(const std::optional &selection); + bool setSelection(const std::optional &selection, bool scroll = true); QString textFromSelection() const; void configBlinkTimer(); @@ -194,7 +202,7 @@ private: QTimer m_scrollTimer; int m_scrollDirection{0}; - std::array m_currentColors; + std::array m_currentColors; Utils::Terminal::OpenTerminalParameters m_openParameters; @@ -208,6 +216,11 @@ private: Utils::FilePath m_cwd; Utils::CommandLine m_currentCommand; + + std::unique_ptr m_search; + + Aggregation::Aggregate *m_aggregate{nullptr}; + SearchHit m_lastSelectedHit{}; }; } // namespace Terminal From ae94d3b7ea71e7ba5b0c0f6e1dcfb1a466925b38 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 17:05:08 +0100 Subject: [PATCH 0392/1447] Terminal: Handle bell Change-Id: I61681166fc8e489ffd0807cf3bcb4a2abc9cf6e1 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalsurface.cpp | 6 +++++- src/plugins/terminal/terminalsurface.h | 1 + src/plugins/terminal/terminalwidget.cpp | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index 83749596c38..01b1f2c2aae 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -68,11 +68,15 @@ struct TerminalSurfacePrivate auto p = static_cast(user); return p->movecursor(pos, oldpos, visible); }; - m_vtermScreenCallbacks.sb_clear = [](void *user) { auto p = static_cast(user); return p->sb_clear(); }; + m_vtermScreenCallbacks.bell = [](void *user) { + auto p = static_cast(user); + emit p->q->bell(); + return 1; + }; vterm_screen_set_callbacks(m_vtermScreen, &m_vtermScreenCallbacks, this); vterm_screen_set_damage_merge(m_vtermScreen, VTERM_DAMAGE_SCROLL); diff --git a/src/plugins/terminal/terminalsurface.h b/src/plugins/terminal/terminalsurface.h index 01923fb538f..a6fc7425d48 100644 --- a/src/plugins/terminal/terminalsurface.h +++ b/src/plugins/terminal/terminalsurface.h @@ -102,6 +102,7 @@ signals: void cursorChanged(Cursor oldCursor, Cursor newCursor); void altscreenChanged(bool altScreen); void unscroll(); + void bell(); private: std::unique_ptr d; diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 07080ea23f9..bb2f5e210ac 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -332,6 +332,7 @@ void TerminalWidget::setupSurface() connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] { verticalScrollBar()->setValue(verticalScrollBar()->maximum()); }); + connect(m_surface.get(), &Internal::TerminalSurface::bell, this, [] { QApplication::beep(); }); if (m_shellIntegration) { connect(m_shellIntegration.get(), &ShellIntegration::commandChanged, From 623661a034f34631161feaa2bf03f7e582ec9f82 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 22 Mar 2023 14:11:47 +0100 Subject: [PATCH 0393/1447] ProjectExplorer: Remove usused MakeStep functions They had been left in to ease downstream transition and originally planned for removal for 4.15. We are beyond that now. Change-Id: I046ea8a29ff709d639f3d1bb5298ee446a1feb11 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/makestep.cpp | 16 ---------------- src/plugins/projectexplorer/makestep.h | 5 ----- 2 files changed, 21 deletions(-) diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 57ebc2490b3..c50e2091cb0 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -383,22 +383,6 @@ QWidget *MakeStep::createConfigWidget() return widget; } -bool MakeStep::buildsTarget(const QString &target) const -{ - return m_buildTargetsAspect->value().contains(target); -} - -void MakeStep::setBuildTarget(const QString &target, bool on) -{ - QStringList old = m_buildTargetsAspect->value(); - if (on && !old.contains(target)) - old << target; - else if (!on && old.contains(target)) - old.removeOne(target); - - m_buildTargetsAspect->setValue(old); -} - QStringList MakeStep::availableTargets() const { return m_buildTargetsAspect->allValues(); diff --git a/src/plugins/projectexplorer/makestep.h b/src/plugins/projectexplorer/makestep.h index b08462db2ff..73c4e9b7e79 100644 --- a/src/plugins/projectexplorer/makestep.h +++ b/src/plugins/projectexplorer/makestep.h @@ -55,11 +55,6 @@ public: Utils::Environment makeEnvironment() const; - // FIXME: All unused, remove in 4.15. - void setBuildTarget(const QString &buildTarget) { setSelectedBuildTarget(buildTarget); } - bool buildsTarget(const QString &target) const; - void setBuildTarget(const QString &target, bool on); - protected: void supportDisablingForSubdirs() { m_disablingForSubDirsSupported = true; } virtual QStringList displayArguments() const; From 3afe94777c9a359a01de93a40bfed15144601770 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 17 Mar 2023 15:18:59 +0100 Subject: [PATCH 0394/1447] Examples/Marketplace: Create grid view with all items on demand No need to create that at startup. Change-Id: Iff4cc634777fdd6cc9920a60e3260ee6d5a1a619 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/coreplugin/welcomepagehelper.cpp | 53 ++++++++++++-------- src/plugins/coreplugin/welcomepagehelper.h | 9 ++-- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index d5f09a8c5c6..0e8f1211bf2 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -633,11 +633,9 @@ void ListItemDelegate::goon() SectionedGridView::SectionedGridView(QWidget *parent) : QStackedWidget(parent) - , m_allItemsView(new Core::GridView(this)) { - auto allItemsModel = new ListModel(this); - allItemsModel->setPixmapFunction(m_pixmapFunction); - m_filteredAllItemsModel = new Core::ListModelFilter(allItemsModel, this); + m_allItemsModel.reset(new ListModel); + m_allItemsModel->setPixmapFunction(m_pixmapFunction); auto area = new QScrollArea(this); area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -653,16 +651,18 @@ SectionedGridView::SectionedGridView(QWidget *parent) area->setWidget(sectionedView); addWidget(area); - - m_allItemsView->setModel(m_filteredAllItemsModel); - addWidget(m_allItemsView); } -SectionedGridView::~SectionedGridView() = default; +SectionedGridView::~SectionedGridView() +{ + clear(); +} void SectionedGridView::setItemDelegate(QAbstractItemDelegate *delegate) { - m_allItemsView->setItemDelegate(delegate); + m_itemDelegate = delegate; + if (m_allItemsView) + m_allItemsView->setItemDelegate(delegate); for (GridView *view : std::as_const(m_gridViews)) view->setItemDelegate(delegate); } @@ -670,18 +670,30 @@ void SectionedGridView::setItemDelegate(QAbstractItemDelegate *delegate) void SectionedGridView::setPixmapFunction(const Core::ListModel::PixmapFunction &pixmapFunction) { m_pixmapFunction = pixmapFunction; - auto allProducts = static_cast(m_filteredAllItemsModel->sourceModel()); - allProducts->setPixmapFunction(pixmapFunction); + m_allItemsModel->setPixmapFunction(pixmapFunction); for (ListModel *model : std::as_const(m_sectionModels)) model->setPixmapFunction(pixmapFunction); } void SectionedGridView::setSearchString(const QString &searchString) { - int view = searchString.isEmpty() ? 0 // sectioned view - : 1; // search view - setCurrentIndex(view); - m_filteredAllItemsModel->setSearchString(searchString); + if (searchString.isEmpty()) { + // back to sectioned view + setCurrentIndex(0); + return; + } + if (!m_allItemsView) { + // We don't have a grid set for searching yet. + // Create all items view for filtering. + m_allItemsView.reset(new GridView); + m_allItemsView->setModel(new ListModelFilter(m_allItemsModel.get(), m_allItemsView.get())); + if (m_itemDelegate) + m_allItemsView->setItemDelegate(m_itemDelegate); + addWidget(m_allItemsView.get()); + } + setCurrentWidget(m_allItemsView.get()); + auto filterModel = static_cast(m_allItemsView.get()->model()); + filterModel->setSearchString(searchString); } ListModel *SectionedGridView::addSection(const Section §ion, const QList &items) @@ -695,7 +707,7 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListappendItems(items); auto gridView = new SectionGridView(this); - gridView->setItemDelegate(m_allItemsView->itemDelegate()); + gridView->setItemDelegate(m_itemDelegate); gridView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); gridView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); gridView->setModel(model); @@ -717,12 +729,11 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListinsertWidget(position + 1, gridView); // add the items also to the all products model to be able to search correctly - auto allProducts = static_cast(m_filteredAllItemsModel->sourceModel()); - const QSet allItems = toSet(allProducts->items()); + const QSet allItems = toSet(m_allItemsModel->items()); const QList newItems = filtered(items, [&allItems](ListItem *item) { return !allItems.contains(item); }); - allProducts->appendItems(newItems); + m_allItemsModel->appendItems(newItems); // only show section label(s) if there is more than one section m_sectionLabels.at(0)->setVisible(m_sectionLabels.size() > 1); @@ -732,14 +743,14 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList(m_filteredAllItemsModel->sourceModel()); - allProducts->clear(); + m_allItemsModel->clear(); qDeleteAll(m_sectionModels); qDeleteAll(m_sectionLabels); qDeleteAll(m_gridViews); m_sectionModels.clear(); m_sectionLabels.clear(); m_gridViews.clear(); + m_allItemsView.reset(); } } // namespace Core diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 77760000e9e..cf9f438aced 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -40,7 +40,7 @@ public: class CORE_EXPORT GridView : public QListView { public: - explicit GridView(QWidget *parent); + explicit GridView(QWidget *parent = nullptr); protected: void leaveEvent(QEvent *) final; @@ -74,7 +74,7 @@ public: using PixmapFunction = std::function; - explicit ListModel(QObject *parent); + explicit ListModel(QObject *parent = nullptr); ~ListModel() override; void appendItems(const QList &items); @@ -199,9 +199,10 @@ private: QMap m_sectionModels; QList m_sectionLabels; QMap m_gridViews; - Core::GridView *m_allItemsView = nullptr; - Core::ListModelFilter *m_filteredAllItemsModel = nullptr; + std::unique_ptr m_allItemsModel; + std::unique_ptr m_allItemsView; Core::ListModel::PixmapFunction m_pixmapFunction; + QAbstractItemDelegate *m_itemDelegate = nullptr; }; } // namespace Core From eb8c996f49b462f4a26c7b243a098569ac13542a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 10 Mar 2023 10:26:56 +0100 Subject: [PATCH 0395/1447] Python: add create venv option to the wizard and optimize layouting Fixes: PYSIDE-2152 Change-Id: If3ecb76c4bac885840f54fd382471ac22a06dee3 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/python/pythoneditor.cpp | 10 +-- src/plugins/python/pythonsettings.cpp | 25 ++++-- src/plugins/python/pythonsettings.h | 13 ++- src/plugins/python/pythonwizardpage.cpp | 111 ++++++++++++++++++------ src/plugins/python/pythonwizardpage.h | 9 +- 5 files changed, 123 insertions(+), 45 deletions(-) diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index 42771fc91a2..ca6b606616a 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -251,11 +251,11 @@ void PythonEditorWidget::updateInterpretersSelector() if (self && venvInterpreter) self->setUserDefinedPython(*venvInterpreter); }; - PythonSettings::createVirtualEnvironment(self->textDocument() - ->filePath() - .parentDir(), - *currentInterpreter, - callback); + PythonSettings::createVirtualEnvironmentInteractive(self->textDocument() + ->filePath() + .parentDir(), + *currentInterpreter, + callback); }); } auto settingsAction = menu->addAction(Tr::tr("Manage Python Interpreters")); diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index f22f0c3c8ce..ff3a18ef149 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -773,9 +773,11 @@ void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefau saveSettings(); } -Interpreter PythonSettings::addInterpreter(const FilePath &interpreterPath, bool isDefault) +Interpreter PythonSettings::addInterpreter(const FilePath &interpreterPath, + bool isDefault, + const QString &nameSuffix) { - const Interpreter interpreter = createInterpreter(interpreterPath, {}); + const Interpreter interpreter = createInterpreter(interpreterPath, {}, nameSuffix); addInterpreter(interpreter, isDefault); return interpreter; } @@ -786,7 +788,7 @@ PythonSettings *PythonSettings::instance() return settingsInstance; } -void PythonSettings::createVirtualEnvironment( +void PythonSettings::createVirtualEnvironmentInteractive( const FilePath &startDirectory, const Interpreter &defaultInterpreter, const std::function)> &callback) @@ -829,14 +831,23 @@ void PythonSettings::createVirtualEnvironment( interpreters->currentData().toString()); auto venvDir = pathChooser->filePath(); - createVenv(interpreter.command, venvDir, [venvDir, callback](bool success){ + createVirtualEnvironment(venvDir, interpreter, callback); +} + +void PythonSettings::createVirtualEnvironment( + const FilePath &directory, + const Interpreter &interpreter, + const std::function)> &callback, + const QString &nameSuffix) +{ + createVenv(interpreter.command, directory, [directory, callback, nameSuffix](bool success) { std::optional result; if (success) { - FilePath venvPython = venvDir.osType() == Utils::OsTypeWindows ? venvDir / "Scripts" - : venvDir / "bin"; + FilePath venvPython = directory.osType() == Utils::OsTypeWindows ? directory / "Scripts" + : directory / "bin"; venvPython = venvPython.pathAppended("python").withExecutableSuffix(); if (venvPython.exists()) - result = PythonSettings::addInterpreter(venvPython); + result = PythonSettings::addInterpreter(venvPython, false, nameSuffix); } callback(result); }); diff --git a/src/plugins/python/pythonsettings.h b/src/plugins/python/pythonsettings.h index 2e27e266162..35939c1ecd1 100644 --- a/src/plugins/python/pythonsettings.h +++ b/src/plugins/python/pythonsettings.h @@ -25,13 +25,22 @@ public: static void setInterpreter(const QList &interpreters, const QString &defaultId); static void addInterpreter(const Interpreter &interpreter, bool isDefault = false); static Interpreter addInterpreter(const Utils::FilePath &interpreterPath, - bool isDefault = false); + bool isDefault = false, + const QString &nameSuffix = {}); static void setPyLSConfiguration(const QString &configuration); static bool pylsEnabled(); static void setPylsEnabled(const bool &enabled); static QString pylsConfiguration(); static PythonSettings *instance(); - static void createVirtualEnvironment(const Utils::FilePath &startDirectory, const Interpreter &defaultInterpreter, const std::function)> &callback); + static void createVirtualEnvironmentInteractive( + const Utils::FilePath &startDirectory, + const Interpreter &defaultInterpreter, + const std::function)> &callback); + static void createVirtualEnvironment( + const Utils::FilePath &directory, + const Interpreter &interpreter, + const std::function)> &callback, + const QString &nameSuffix = {}); static QList detectPythonVenvs(const Utils::FilePath &path); signals: diff --git a/src/plugins/python/pythonwizardpage.cpp b/src/plugins/python/pythonwizardpage.cpp index 1b5798f1733..b13cf3c346d 100644 --- a/src/plugins/python/pythonwizardpage.cpp +++ b/src/plugins/python/pythonwizardpage.cpp @@ -34,18 +34,18 @@ WizardPage *PythonWizardPageFactory::create(JsonWizard *wizard, Id typeId, const QTC_ASSERT(canCreate(typeId), return nullptr); - auto page = new PythonWizardPage; + QList> pySideAndData; for (const QVariant &item : data.toMap().value("items").toList()) { const QMap map = item.toMap(); const QVariant name = map.value("trKey"); if (name.isValid()) - page->addPySideVersions(name.toString(), map.value("value")); + pySideAndData.emplaceBack(QPair{name.toString(), map.value("value")}); } bool validIndex = false; - const int index = data.toMap().value("index").toInt(&validIndex); - if (validIndex) - page->setDefaultPySideVersions(index); - return page; + int defaultPySide = data.toMap().value("index").toInt(&validIndex); + if (!validIndex) + defaultPySide = -1; + return new PythonWizardPage(pySideAndData, defaultPySide); } static bool validItem(const QVariant &item) @@ -82,8 +82,10 @@ bool PythonWizardPageFactory::validateData(Id typeId, const QVariant &data, QStr return true; } -PythonWizardPage::PythonWizardPage() +PythonWizardPage::PythonWizardPage(const QList> &pySideAndData, + const int defaultPyside) { + using namespace Utils::Layouting; m_interpreter.setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID); connect(PythonSettings::instance(), &PythonSettings::interpretersChanged, @@ -92,27 +94,55 @@ PythonWizardPage::PythonWizardPage() m_pySideVersion.setLabelText(Tr::tr("PySide version")); m_pySideVersion.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); + for (auto [name, data] : pySideAndData) + m_pySideVersion.addOption(SelectionAspect::Option(name, {}, data)); + if (defaultPyside >= 0) + m_pySideVersion.setDefaultValue(defaultPyside); + + m_createVenv.setLabelText(Tr::tr("Create new Virtual Environment")); + + m_venvPath.setLabelText(Tr::tr("Path to virtual environment")); + m_venvPath.setDisplayStyle(StringAspect::PathChooserDisplay); + m_venvPath.setEnabler(&m_createVenv); + m_venvPath.setExpectedKind(PathChooser::Directory); + + m_stateLabel = new InfoLabel(); + m_stateLabel->setWordWrap(true); + m_stateLabel->setFilled(true); + m_stateLabel->setType(InfoLabel::Error); + connect(&m_venvPath, &StringAspect::valueChanged, this, &PythonWizardPage::updateStateLabel); + connect(&m_createVenv, &BoolAspect::valueChanged, this, &PythonWizardPage::updateStateLabel); + + Grid { + m_pySideVersion, br, + m_interpreter, br, + m_createVenv, br, + m_venvPath, br, + m_stateLabel, br + }.attachTo(this, WithoutMargins); } void PythonWizardPage::initializePage() { - using namespace Utils::Layouting; - auto wiz = qobject_cast(wizard()); QTC_ASSERT(wiz, return); + connect(wiz, &JsonWizard::filesPolished, + this, &PythonWizardPage::setupProject, + Qt::UniqueConnection); + + const FilePath projectDir = FilePath::fromString(wiz->property("ProjectDirectory").toString()); + m_createVenv.setValue(!projectDir.isEmpty()); + if (m_venvPath.filePath().isEmpty()) + m_venvPath.setFilePath(projectDir.isEmpty() ? FilePath{} : projectDir / "venv"); updateInterpreters(); - - connect(wiz, &JsonWizard::filesPolished, this, &PythonWizardPage::setupProject); - - Grid { - m_pySideVersion, br, - m_interpreter, br - }.attachTo(this, WithoutMargins); + updateStateLabel(); } bool PythonWizardPage::validatePage() { + if (m_createVenv.value() && !m_venvPath.pathChooser()->isValid()) + return false; auto wiz = qobject_cast(wizard()); const QMap data = m_pySideVersion.itemValue().toMap(); for (auto it = data.begin(), end = data.end(); it != end; ++it) @@ -120,28 +150,40 @@ bool PythonWizardPage::validatePage() return true; } -void PythonWizardPage::addPySideVersions(const QString &name, const QVariant &data) -{ - m_pySideVersion.addOption(SelectionAspect::Option(name, {}, data)); -} - -void PythonWizardPage::setDefaultPySideVersions(int index) -{ - m_pySideVersion.setDefaultValue(index); -} - void PythonWizardPage::setupProject(const JsonWizard::GeneratorFiles &files) { for (const JsonWizard::GeneratorFile &f : files) { if (f.file.attributes() & Core::GeneratedFile::OpenProjectAttribute) { + Interpreter interpreter = m_interpreter.currentInterpreter(); Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(f.file.filePath()), f.file.filePath().absoluteFilePath()); + if (m_createVenv.value()) { + auto openProjectWithInterpreter = [f](const std::optional &interpreter) { + if (!interpreter) + return; + Project *project = ProjectManager::projectWithProjectFilePath(f.file.filePath()); + if (!project) + return; + if (Target *target = project->activeTarget()) { + if (RunConfiguration *rc = target->activeRunConfiguration()) { + if (auto interpreters = rc->aspect()) + interpreters->setCurrentInterpreter(*interpreter); + } + } + }; + PythonSettings::createVirtualEnvironment(m_venvPath.filePath(), + interpreter, + openProjectWithInterpreter, + project ? project->displayName() + : QString{}); + } + if (project) { project->addTargetForDefaultKit(); if (Target *target = project->activeTarget()) { if (RunConfiguration *rc = target->activeRunConfiguration()) { if (auto interpreters = rc->aspect()) { - interpreters->setCurrentInterpreter(m_interpreter.currentInterpreter()); + interpreters->setCurrentInterpreter(interpreter); project->saveSettings(); } } @@ -158,5 +200,20 @@ void PythonWizardPage::updateInterpreters() m_interpreter.updateInterpreters(PythonSettings::interpreters()); } +void PythonWizardPage::updateStateLabel() +{ + QTC_ASSERT(m_stateLabel, return); + if (m_createVenv.value()) { + if (PathChooser *pathChooser = m_venvPath.pathChooser()) { + if (!pathChooser->isValid()) { + m_stateLabel->show(); + m_stateLabel->setText(pathChooser->errorMessage()); + return; + } + } + } + m_stateLabel->hide(); +} + } // namespace Python::Internal diff --git a/src/plugins/python/pythonwizardpage.h b/src/plugins/python/pythonwizardpage.h index e35e3ca55cb..1d605b24176 100644 --- a/src/plugins/python/pythonwizardpage.h +++ b/src/plugins/python/pythonwizardpage.h @@ -24,19 +24,20 @@ public: class PythonWizardPage : public Utils::WizardPage { public: - PythonWizardPage(); + PythonWizardPage(const QList> &pySideAndData, const int defaultPyside); void initializePage() override; bool validatePage() override; - void addPySideVersions(const QString &name, const QVariant &data); - void setDefaultPySideVersions(int index); - private: void setupProject(const ProjectExplorer::JsonWizard::GeneratorFiles &files); void updateInterpreters(); + void updateStateLabel(); ProjectExplorer::InterpreterAspect m_interpreter; Utils::SelectionAspect m_pySideVersion; + Utils::BoolAspect m_createVenv; + Utils::StringAspect m_venvPath; + Utils::InfoLabel *m_stateLabel = nullptr; }; } // namespace Python::Internal From 54b8bdc390d9f7a7ee39fcc497488c9d4864abc3 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 27 Mar 2023 08:47:33 +0200 Subject: [PATCH 0396/1447] ProjectExplorer: Fix logic to start device creation wizard Amends 5996e58ff. Change-Id: Ifbb31059b138234c37fbb3b335598406c9f328e5 Reviewed-by: David Schulz Reviewed-by: --- src/plugins/projectexplorer/devicesupport/idevicefactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp index c20f4776d61..e88a1e61367 100644 --- a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp @@ -63,10 +63,10 @@ bool IDeviceFactory::canCreate() const IDevice::Ptr IDeviceFactory::create() const { - if (m_creator) + if (!m_creator) return {}; - IDevice::Ptr device = m_constructor(); + IDevice::Ptr device = m_creator(); QTC_ASSERT(device, return {}); device->setDefaultDisplayName(displayName()); return device; From ed8f0fb03e8dd82745f3d916f3f36e4518dc3b74 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 16:28:34 +0100 Subject: [PATCH 0397/1447] Qnx: Compactify QnxDevice creation infrastructure Change-Id: I939a435859c494f8750d62d2ca393775e01ad214 Reviewed-by: David Schulz Reviewed-by: --- src/plugins/qnx/CMakeLists.txt | 1 - src/plugins/qnx/qnx.qbs | 2 - src/plugins/qnx/qnxdevice.cpp | 112 ++++++++++++++++++---------- src/plugins/qnx/qnxdevice.h | 22 +----- src/plugins/qnx/qnxdevicewizard.cpp | 69 ----------------- src/plugins/qnx/qnxdevicewizard.h | 12 --- 6 files changed, 73 insertions(+), 145 deletions(-) delete mode 100644 src/plugins/qnx/qnxdevicewizard.cpp delete mode 100644 src/plugins/qnx/qnxdevicewizard.h diff --git a/src/plugins/qnx/CMakeLists.txt b/src/plugins/qnx/CMakeLists.txt index 2de34ae95f8..c36c0db077d 100644 --- a/src/plugins/qnx/CMakeLists.txt +++ b/src/plugins/qnx/CMakeLists.txt @@ -11,7 +11,6 @@ add_qtc_plugin(Qnx qnxdeployqtlibrariesdialog.cpp qnxdeployqtlibrariesdialog.h qnxdevice.cpp qnxdevice.h qnxdevicetester.cpp qnxdevicetester.h - qnxdevicewizard.cpp qnxdevicewizard.h qnxplugin.cpp qnxqtversion.cpp qnxqtversion.h qnxrunconfiguration.cpp qnxrunconfiguration.h diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index e62cc8975ce..ee1752f816f 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -28,8 +28,6 @@ QtcPlugin { "qnxdebugsupport.h", "qnxdevice.cpp", "qnxdevice.h", - "qnxdevicewizard.cpp", - "qnxdevicewizard.h", "qnxdevicetester.cpp", "qnxdevicetester.h", "qnxconfigurationmanager.cpp", diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 2b6520e0025..e574a8eed78 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -6,19 +6,21 @@ #include "qnxconstants.h" #include "qnxdeployqtlibrariesdialog.h" #include "qnxdevicetester.h" -#include "qnxdevicewizard.h" #include "qnxtr.h" +#include + #include +#include #include +#include #include #include #include #include - -#include +#include using namespace ProjectExplorer; using namespace RemoteLinux; @@ -54,48 +56,73 @@ public: } }; -QnxDevice::QnxDevice() +class QnxDevice final : public LinuxDevice { - setDisplayType(Tr::tr("QNX")); - setDefaultDisplayName(Tr::tr("QNX Device")); - setOsType(OsTypeOtherUnix); - setupId(IDevice::ManuallyAdded); - setType(Constants::QNX_QNX_OS_TYPE); - setMachineType(IDevice::Hardware); - SshParameters sshParams; - sshParams.timeout = 10; - setSshParameters(sshParams); - setFreePorts(PortList::fromString("10000-10100")); +public: + QnxDevice() + { + setDisplayType(Tr::tr("QNX")); + setDefaultDisplayName(Tr::tr("QNX Device")); + setOsType(OsTypeOtherUnix); + setupId(IDevice::ManuallyAdded); + setType(Constants::QNX_QNX_OS_TYPE); + setMachineType(IDevice::Hardware); + SshParameters sshParams; + sshParams.timeout = 10; + setSshParameters(sshParams); + setFreePorts(PortList::fromString("10000-10100")); - addDeviceAction({Tr::tr("Deploy Qt libraries..."), [](const IDevice::Ptr &device, QWidget *parent) { - QnxDeployQtLibrariesDialog dialog(device, parent); - dialog.exec(); - }}); -} + addDeviceAction({Tr::tr("Deploy Qt libraries..."), [](const IDevice::Ptr &device, QWidget *parent) { + QnxDeployQtLibrariesDialog dialog(device, parent); + dialog.exec(); + }}); + } -PortsGatheringMethod QnxDevice::portsGatheringMethod() const + PortsGatheringMethod portsGatheringMethod() const final + { + return { + [this](QAbstractSocket::NetworkLayerProtocol) { + return CommandLine(filePath("netstat"), {"-na"}); + }, + &Port::parseFromNetstatOutput + }; + } + + DeviceProcessSignalOperation::Ptr signalOperation() const final + { + return DeviceProcessSignalOperation::Ptr(new QnxDeviceProcessSignalOperation(sharedFromThis())); + } + + DeviceTester *createDeviceTester() const final { return new QnxDeviceTester; } +}; + +class QnxDeviceWizard : public Wizard { - return { - // TODO: The command is probably needlessly complicated because the parsing method - // used to be fixed. These two can now be matched to each other. - [this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { - Q_UNUSED(protocol) - return {filePath("netstat"), {"-na"}}; - }, +public: + QnxDeviceWizard() : Wizard(Core::ICore::dialogParent()) + { + setWindowTitle(Tr::tr("New QNX Device Configuration Setup")); - &Port::parseFromNetstatOutput - }; -} + addPage(&m_setupPage); + addPage(&m_keyDeploymentPage); + addPage(&m_finalPage); + m_finalPage.setCommitPage(true); -DeviceTester *QnxDevice::createDeviceTester() const -{ - return new QnxDeviceTester; -} + m_device.reset(new QnxDevice); -DeviceProcessSignalOperation::Ptr QnxDevice::signalOperation() const -{ - return DeviceProcessSignalOperation::Ptr(new QnxDeviceProcessSignalOperation(sharedFromThis())); -} + m_setupPage.setDevice(m_device); + m_keyDeploymentPage.setDevice(m_device); + } + + IDevice::Ptr device() const { return m_device; } + +private: + GenericLinuxDeviceConfigurationWizardSetupPage m_setupPage; + GenericLinuxDeviceConfigurationWizardKeyDeploymentPage m_keyDeploymentPage; + GenericLinuxDeviceConfigurationWizardFinalPage m_finalPage; + + LinuxDevice::Ptr m_device; +}; // Factory @@ -105,8 +132,13 @@ QnxDeviceFactory::QnxDeviceFactory() : IDeviceFactory(Constants::QNX_QNX_OS_TYPE setCombinedIcon(":/qnx/images/qnxdevicesmall.png", ":/qnx/images/qnxdevice.png"); setQuickCreationAllowed(true); - setConstructionFunction(&QnxDevice::create); - setCreator(&runDeviceWizard); + setConstructionFunction([] { return IDevice::Ptr(new QnxDevice); }); + setCreator([] { + QnxDeviceWizard wizard; + if (wizard.exec() != QDialog::Accepted) + return IDevice::Ptr(); + return wizard.device(); + }); } } // Qnx::Internal diff --git a/src/plugins/qnx/qnxdevice.h b/src/plugins/qnx/qnxdevice.h index e2e6403432e..c4b484f478c 100644 --- a/src/plugins/qnx/qnxdevice.h +++ b/src/plugins/qnx/qnxdevice.h @@ -3,30 +3,10 @@ #pragma once -#include +#include namespace Qnx::Internal { -class QnxDevice final : public RemoteLinux::LinuxDevice -{ -public: - using Ptr = QSharedPointer; - using ConstPtr = QSharedPointer; - - static Ptr create() { return Ptr(new QnxDevice); } - - ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; - ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; - - ProjectExplorer::DeviceTester *createDeviceTester() const override; - -private: - QnxDevice(); - - QString interruptProcessByNameCommandLine(const QString &filePath) const; - QString killProcessByNameCommandLine(const QString &filePath) const; -}; - class QnxDeviceFactory final : public ProjectExplorer::IDeviceFactory { public: diff --git a/src/plugins/qnx/qnxdevicewizard.cpp b/src/plugins/qnx/qnxdevicewizard.cpp deleted file mode 100644 index cd4a132ee4a..00000000000 --- a/src/plugins/qnx/qnxdevicewizard.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qnxdevicewizard.h" - -#include "qnxconstants.h" -#include "qnxdevice.h" -#include "qnxtr.h" - -#include - -#include - -#include - -#include -#include - -using namespace ProjectExplorer; -using namespace RemoteLinux; -using namespace Utils; - -namespace Qnx::Internal { - -class QnxDeviceWizard : public Wizard -{ -public: - QnxDeviceWizard() : Wizard(Core::ICore::dialogParent()) - { - setWindowTitle(Tr::tr("New QNX Device Configuration Setup")); - - addPage(&m_setupPage); - addPage(&m_keyDeploymentPage); - addPage(&m_finalPage); - m_finalPage.setCommitPage(true); - - SshParameters sshParams; - sshParams.timeout = 10; - m_device = QnxDevice::create(); - m_device->setupId(IDevice::ManuallyAdded); - m_device->setType(Constants::QNX_QNX_OS_TYPE); - m_device->setMachineType(IDevice::Hardware); - m_device->setSshParameters(sshParams); - m_device->setFreePorts(PortList::fromString("10000-10100")); - - m_setupPage.setDevice(m_device); - m_keyDeploymentPage.setDevice(m_device); - } - - IDevice::Ptr device() const { return m_device; } - -private: - GenericLinuxDeviceConfigurationWizardSetupPage m_setupPage; - GenericLinuxDeviceConfigurationWizardKeyDeploymentPage m_keyDeploymentPage; - GenericLinuxDeviceConfigurationWizardFinalPage m_finalPage; - - LinuxDevice::Ptr m_device; -}; - - -IDevice::Ptr runDeviceWizard() -{ - QnxDeviceWizard wizard; - if (wizard.exec() != QDialog::Accepted) - return IDevice::Ptr(); - return wizard.device(); -} - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxdevicewizard.h b/src/plugins/qnx/qnxdevicewizard.h deleted file mode 100644 index 3adaa337011..00000000000 --- a/src/plugins/qnx/qnxdevicewizard.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Qnx::Internal { - -ProjectExplorer::IDevice::Ptr runDeviceWizard(); - -} // Qnx::Internal From 83759e80834ea33f8f67c68123a4fe9e13df193f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 24 Mar 2023 18:09:04 +0100 Subject: [PATCH 0398/1447] Utils: Improve QtColorButton By making it more theme aware, using a contrast color to draw the outline; using the whole button area for the color (had to implement a custom focus rect for that); Tidying up the checkerboard code a bit. Change-Id: I9855c07668f920caf371a03fef7be2795feb2a08 Reviewed-by: Marcus Tillmanns Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/utils/qtcolorbutton.cpp | 76 +++++++++++++------------------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/src/libs/utils/qtcolorbutton.cpp b/src/libs/utils/qtcolorbutton.cpp index ca0aa631ba5..e6735baae2a 100644 --- a/src/libs/utils/qtcolorbutton.cpp +++ b/src/libs/utils/qtcolorbutton.cpp @@ -3,12 +3,13 @@ #include "qtcolorbutton.h" -#include #include #include -#include -#include #include +#include +#include +#include +#include namespace Utils { @@ -157,51 +158,36 @@ bool QtColorButton::isDialogOpen() const void QtColorButton::paintEvent(QPaintEvent *event) { - QToolButton::paintEvent(event); - if (!isEnabled()) - return; - - const int pixSize = 10; - QBrush br(d_ptr->shownColor()); - if (d_ptr->m_backgroundCheckered) { - QPixmap pm(2 * pixSize, 2 * pixSize); - QPainter pmp(&pm); - pmp.fillRect(0, 0, pixSize, pixSize, Qt::white); - pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white); - pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); - pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); - pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, d_ptr->shownColor()); - br = QBrush(pm); - } + Q_UNUSED(event) QPainter p(this); - const int corr = 5; - QRect r = rect().adjusted(corr, corr, -corr, -corr); - p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr); - p.fillRect(r, br); + if (isEnabled()) { + QBrush br(d_ptr->shownColor()); + if (d_ptr->m_backgroundCheckered) { + const int pixSize = 10; + QPixmap pm(2 * pixSize, 2 * pixSize); + pm.fill(Qt::white); + QPainter pmp(&pm); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); + pmp.fillRect(pm.rect(), d_ptr->shownColor()); + br = QBrush(pm); + p.setBrushOrigin((width() - pixSize) / 2, (height() - pixSize) / 2); + } + p.fillRect(rect(), br); + } - //const int adjX = qRound(r.width() / 4.0); - //const int adjY = qRound(r.height() / 4.0); - //p.fillRect(r.adjusted(adjX, adjY, -adjX, -adjY), - // QColor(d_ptr->shownColor().rgb())); - /* - p.fillRect(r.adjusted(0, r.height() * 3 / 4, 0, 0), - QColor(d_ptr->shownColor().rgb())); - p.fillRect(r.adjusted(0, 0, 0, -r.height() * 3 / 4), - QColor(d_ptr->shownColor().rgb())); - */ - /* - const QColor frameColor0(0, 0, 0, qRound(0.2 * (0xFF - d_ptr->shownColor().alpha()))); - p.setPen(frameColor0); - p.drawRect(r.adjusted(adjX, adjY, -adjX - 1, -adjY - 1)); - */ - - const QColor frameColor1(0, 0, 0, 26); - p.setPen(frameColor1); - p.drawRect(r.adjusted(1, 1, -2, -2)); - const QColor frameColor2(0, 0, 0, 51); - p.setPen(frameColor2); - p.drawRect(r.adjusted(0, 0, -1, -1)); + if (hasFocus()) { + QPen pen; + pen.setBrush(Qt::white); + pen.setStyle(Qt::DotLine); + p.setPen(pen); + p.setCompositionMode(QPainter::CompositionMode_Difference); + } else { + p.setPen(palette().text().color()); + p.setOpacity(0.25); + } + p.drawRect(rect().adjusted(0, 0, -1, -1)); } void QtColorButton::mousePressEvent(QMouseEvent *event) From af5f702f54b696be47e4fd36bc0dc88e03d7c981 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 22:02:23 +0100 Subject: [PATCH 0399/1447] Terminal: Make ESC key behavior configurable Change-Id: I806870c5dd7edbcd3ac2642849cca82f1939ce01 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalpane.cpp | 34 ++++++++++++++++--- src/plugins/terminal/terminalpane.h | 1 + src/plugins/terminal/terminalsettings.cpp | 20 +++++++---- src/plugins/terminal/terminalsettings.h | 2 ++ src/plugins/terminal/terminalsettingspage.cpp | 8 +++-- src/plugins/terminal/terminalwidget.cpp | 20 ++++++++--- 6 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 7295216e162..247f8d8f16c 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -5,11 +5,13 @@ #include "shellmodel.h" #include "terminalcommands.h" +#include "terminalsettings.h" #include "terminaltr.h" #include "terminalwidget.h" #include #include +#include #include #include @@ -127,6 +129,30 @@ TerminalPane::TerminalPane(QObject *parent) connect(m_openSettingsButton, &QToolButton::clicked, m_openSettingsButton, []() { TerminalCommands::openSettingsAction()->trigger(); }); + + auto updateEscButton = [this] { + m_escSettingButton->setChecked(TerminalSettings::instance().sendEscapeToTerminal.value()); + if (TerminalSettings::instance().sendEscapeToTerminal.value()) { + m_escSettingButton->setText("⎋"); + m_escSettingButton->setToolTip(Tr::tr("Sending ESC to terminal instead of Qt Creator")); + } else { + m_escSettingButton->setText("⇧+⎋"); + m_escSettingButton->setToolTip(Tr::tr("Press ⇧+⎋ to send ESC to terminal")); + } + }; + + m_escSettingButton = new QToolButton(); + m_escSettingButton->setCheckable(true); + + updateEscButton(); + + connect(m_escSettingButton, &QToolButton::toggled, this, [this] { + TerminalSettings::instance().sendEscapeToTerminal.setValue(m_escSettingButton->isChecked()); + TerminalSettings::instance().apply(); + TerminalSettings::instance().writeSettings(Core::ICore::settings()); + }); + + connect(&TerminalSettings::instance(), &TerminalSettings::applied, this, updateEscButton); } TerminalPane::~TerminalPane() @@ -252,15 +278,15 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) m_tabWidget->setTabText(index, exe + " - " + cwd.fileName()); }; - connect(terminal, &TerminalWidget::started, [setTabText, terminal](qint64 /*pid*/) { + connect(terminal, &TerminalWidget::started, this, [setTabText, terminal](qint64 /*pid*/) { setTabText(terminal); }); - connect(terminal, &TerminalWidget::cwdChanged, [setTabText, terminal]() { + connect(terminal, &TerminalWidget::cwdChanged, this, [setTabText, terminal]() { setTabText(terminal); }); - connect(terminal, &TerminalWidget::commandChanged, [setTabText, terminal]() { + connect(terminal, &TerminalWidget::commandChanged, this, [setTabText, terminal]() { setTabText(terminal); }); @@ -274,7 +300,7 @@ QList TerminalPane::toolBarWidgets() const widgets.prepend(m_newTerminalButton); widgets.prepend(m_closeTerminalButton); - return widgets << m_openSettingsButton; + return widgets << m_openSettingsButton << m_escSettingButton; } QString TerminalPane::displayName() const diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 952f863e27c..5d93dcb4d9a 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -53,6 +53,7 @@ private: QToolButton *m_newTerminalButton{nullptr}; QToolButton *m_closeTerminalButton{nullptr}; QToolButton *m_openSettingsButton{nullptr}; + QToolButton *m_escSettingButton{nullptr}; bool m_widgetInitialized{false}; }; diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index b813ee246c6..86e88fc72fc 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -97,6 +97,20 @@ TerminalSettings::TerminalSettings() shell.setToolTip(Tr::tr("The shell executable to be started as terminal")); shell.setDefaultValue(defaultShell()); + sendEscapeToTerminal.setSettingsKey("SendEscapeToTerminal"); + sendEscapeToTerminal.setLabelText(Tr::tr("Send escape key to terminal")); + sendEscapeToTerminal.setToolTip( + Tr::tr("If enabled, pressing the escape key will send it to the terminal " + "instead of closing the terminal.")); + sendEscapeToTerminal.setDefaultValue(false); + + registerAspect(&font); + registerAspect(&fontSize); + registerAspect(&shell); + registerAspect(&allowBlinkingCursor); + registerAspect(&enableTerminal); + registerAspect(&sendEscapeToTerminal); + setupColor(this, foregroundColor, "Foreground", @@ -138,12 +152,6 @@ TerminalSettings::TerminalSettings() setupColor(this, colors[7], "7", Utils::creatorTheme()->color(Theme::TerminalAnsi7)); setupColor(this, colors[15], "15", Utils::creatorTheme()->color(Theme::TerminalAnsi15)); - - registerAspect(&font); - registerAspect(&fontSize); - registerAspect(&shell); - registerAspect(&allowBlinkingCursor); - registerAspect(&enableTerminal); } } // namespace Terminal diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index 35f40031737..d57c411c233 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -27,6 +27,8 @@ public: Utils::ColorAspect colors[16]; Utils::BoolAspect allowBlinkingCursor; + + Utils::BoolAspect sendEscapeToTerminal; }; } // namespace Terminal diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index 86fb2edda38..12ca9f26d86 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -376,8 +376,12 @@ QWidget *TerminalSettingsPage::widget() // clang-format off Column { - Row { - settings.enableTerminal, st, + Group { + title(Tr::tr("General")), + Row { + settings.enableTerminal, st, + settings.sendEscapeToTerminal, st + }, }, Group { title(Tr::tr("Font")), diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index bb2f5e210ac..cc1b3b9f269 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -808,6 +808,7 @@ bool TerminalWidget::paintFindMatches(QPainter &p, } break; } + if (it == m_search->hits().constEnd()) return false; @@ -821,13 +822,11 @@ bool TerminalWidget::paintSelection(QPainter &p, const QRectF &cellRect, const Q bool isInSelection = false; const int pos = m_surface->gridToPos(gridPos); - if (m_selection) { + if (m_selection) isInSelection = pos >= m_selection->start && pos < m_selection->end; - } - if (isInSelection) { + if (isInSelection) p.fillRect(cellRect, m_currentColors[ColorIndex::Selection]); - } return isInSelection; } @@ -1049,6 +1048,19 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) } if (event->key() == Qt::Key_Escape) { + bool sendToTerminal = TerminalSettings::instance().sendEscapeToTerminal.value(); + bool send = false; + if (sendToTerminal && event->modifiers() == Qt::NoModifier) + send = true; + else if (!sendToTerminal && event->modifiers() == Qt::ShiftModifier) + send = true; + + if (send) { + event->setModifiers(Qt::NoModifier); + m_surface->sendKey(event); + return; + } + if (m_selection) TerminalCommands::widgetActions().clearSelection.trigger(); else { From 2eb4884742297141d47622d94d6bd0c4859190da Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 22:14:18 +0100 Subject: [PATCH 0400/1447] Terminal: Make audible bell configurable Change-Id: I6cc02f2f1b873f39352151265fb7ba1fe0f170fc Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalsettings.cpp | 7 +++++++ src/plugins/terminal/terminalsettings.h | 1 + src/plugins/terminal/terminalsettingspage.cpp | 5 +++-- src/plugins/terminal/terminalwidget.cpp | 6 +++++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 86e88fc72fc..1a3625098da 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -104,12 +104,19 @@ TerminalSettings::TerminalSettings() "instead of closing the terminal.")); sendEscapeToTerminal.setDefaultValue(false); + audibleBell.setSettingsKey("AudibleBell"); + audibleBell.setLabelText(Tr::tr("Audible bell")); + audibleBell.setToolTip(Tr::tr("If enabled, the terminal will beep when a bell " + "character is received.")); + audibleBell.setDefaultValue(true); + registerAspect(&font); registerAspect(&fontSize); registerAspect(&shell); registerAspect(&allowBlinkingCursor); registerAspect(&enableTerminal); registerAspect(&sendEscapeToTerminal); + registerAspect(&audibleBell); setupColor(this, foregroundColor, diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index d57c411c233..45b85c5910f 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -29,6 +29,7 @@ public: Utils::BoolAspect allowBlinkingCursor; Utils::BoolAspect sendEscapeToTerminal; + Utils::BoolAspect audibleBell; }; } // namespace Terminal diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index 12ca9f26d86..f0bfa883d7a 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -378,9 +378,10 @@ QWidget *TerminalSettingsPage::widget() Column { Group { title(Tr::tr("General")), - Row { + Column { settings.enableTerminal, st, - settings.sendEscapeToTerminal, st + settings.sendEscapeToTerminal, st, + settings.audibleBell, st, }, }, Group { diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index cc1b3b9f269..14b11762f7b 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -332,7 +332,11 @@ void TerminalWidget::setupSurface() connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] { verticalScrollBar()->setValue(verticalScrollBar()->maximum()); }); - connect(m_surface.get(), &Internal::TerminalSurface::bell, this, [] { QApplication::beep(); }); + connect(m_surface.get(), &Internal::TerminalSurface::bell, this, [] { + if (TerminalSettings::instance().audibleBell.value()) + QApplication::beep(); + }); + if (m_shellIntegration) { connect(m_shellIntegration.get(), &ShellIntegration::commandChanged, From 4ab5eb53392c76b1b9a70abe28e894ef76259cec Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 22:42:10 +0100 Subject: [PATCH 0401/1447] Terminal: Fix warning messages Change-Id: I1ab473c79219cf6e2adefaa1349b4675a2455b2f Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 14b11762f7b..06fcfe57791 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -1317,8 +1317,12 @@ void TerminalWidget::checkLinkAt(const QPoint &pos) const TextAndOffsets hit = textAt(pos); if (hit.text.size() > 0) { - QString t = chopIfEndsWith(QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed(), - ':'); + QString t = QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed(); + t = chopIfEndsWith(t, ':'); + + if (t.isEmpty()) + return; + if (t.startsWith("~/")) { t = QDir::homePath() + t.mid(1); } @@ -1380,6 +1384,9 @@ TerminalWidget::TextAndOffsets TerminalWidget::textAt(const QPoint &pos) const std::u32string text; std::copy(itLeft.base(), it, std::back_inserter(text)); std::copy(it, itRight, std::back_inserter(text)); + std::transform(text.begin(), text.end(), text.begin(), [](const char32_t &ch) { + return ch == 0 ? U' ' : ch; + }); return {(itLeft.base()).position(), itRight.position(), text}; } From 9f5f213337c2008ae8c1a40d80081ccb19c414e5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 25 Mar 2023 14:03:43 +0100 Subject: [PATCH 0402/1447] Terminal: Fix search debug output Change-Id: I66f5a5e5d11f892b11d009df234fe9d7c29356be Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalsearch.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalsearch.cpp b/src/plugins/terminal/terminalsearch.cpp index 5339beef26e..b69587298b7 100644 --- a/src/plugins/terminal/terminalsearch.cpp +++ b/src/plugins/terminal/terminalsearch.cpp @@ -5,10 +5,13 @@ #include "terminalcommands.h" #include +#include #include #include +Q_LOGGING_CATEGORY(terminalSearchLog, "qtc.terminal.search", QtWarningMsg) + using namespace std::chrono_literals; namespace Terminal { @@ -205,7 +208,7 @@ void TerminalSearch::debouncedUpdateHits() emit changed(); } if (!m_currentSearchString.isEmpty()) - qDebug() << "Search took" << t.elapsed() << "ms"; + qCDebug(terminalSearchLog) << "Search took" << t.elapsed() << "ms"; } Core::FindFlags TerminalSearch::supportedFindFlags() const From 43d6f1b29484441dfa02b975e1b802251bd091d9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 22:41:32 +0100 Subject: [PATCH 0403/1447] Terminal: Allow Locator shortcut Change-Id: I278eb3ec2c18efe49a400149a83f71d0fbb2a35c Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalcommands.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp index d9f9d5ec817..2313ac722e4 100644 --- a/src/plugins/terminal/terminalcommands.cpp +++ b/src/plugins/terminal/terminalcommands.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -175,6 +176,7 @@ void TerminalCommands::lazyInitCommands() lazyInitCommand(Core::Constants::FIND_IN_DOCUMENT); lazyInitCommand(Core::Constants::FIND_NEXT); lazyInitCommand(Core::Constants::FIND_PREVIOUS); + lazyInitCommand(Core::Constants::LOCATE); } } // namespace Terminal From b82fdb0499ee17956b5b9d10b371f6bb9e8d3c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Mon, 27 Mar 2023 10:40:05 +0200 Subject: [PATCH 0404/1447] Git: Fix explanation in GerritPushDialog Change-Id: I527414dc3948a009099ec993c0f71d3501394ecd Reviewed-by: Orgad Shaneh Reviewed-by: Leena Miettinen Reviewed-by: --- src/plugins/git/gerrit/gerritpushdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/git/gerrit/gerritpushdialog.cpp b/src/plugins/git/gerrit/gerritpushdialog.cpp index 057d4cd6448..fa45e2591f8 100644 --- a/src/plugins/git/gerrit/gerritpushdialog.cpp +++ b/src/plugins/git/gerrit/gerritpushdialog.cpp @@ -125,7 +125,7 @@ GerritPushDialog::GerritPushDialog(const Utils::FilePath &workingDir, const QStr "Unchecked - Remove mark.\n" "Partially checked - Do not change current state.")); m_commitView->setToolTip(::Git::Tr::tr( - "Pushes the selected commit and all dependent commits.")); + "Pushes the selected commit and all commits it depends on.")); m_reviewersLineEdit->setToolTip(::Git::Tr::tr("Comma-separated list of reviewers.\n" "\n" "Reviewers can be specified by nickname or email address. Spaces not allowed.\n" From 9783ffd7c38263ff03146b92e9b869124226acc9 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Mar 2023 17:27:53 +0100 Subject: [PATCH 0405/1447] Qnx: Allow incremental deployment Seems to work nowadays. Change-Id: I5d6ee3054d1ef127385403a92f8c1e3119eb27f7 Reviewed-by: Marcus Tillmanns --- src/plugins/qnx/qnxplugin.cpp | 2 +- .../remotelinux/genericdirectuploadstep.cpp | 26 +++++++------------ .../remotelinux/genericdirectuploadstep.h | 3 +-- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index c6664b9f600..5796668f8ae 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -46,7 +46,7 @@ namespace Qnx::Internal { class QnxUploadStep : public RemoteLinux::GenericDirectUploadStep { public: - QnxUploadStep(BuildStepList *bsl, Utils::Id id) : GenericDirectUploadStep(bsl, id, false) {} + QnxUploadStep(BuildStepList *bsl, Utils::Id id) : GenericDirectUploadStep(bsl, id) {} static Utils::Id stepId() { return "Qnx.DirectUploadStep"; } }; diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 5764fc0d646..dd867d4e698 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -288,20 +288,16 @@ Group GenericDirectUploadStep::deployRecipe() return root; } -GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id, - bool offerIncrementalDeployment) +GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id) : AbstractRemoteLinuxDeployStep(bsl, id), d(new GenericDirectUploadStepPrivate(this)) { - BoolAspect *incremental = nullptr; - if (offerIncrementalDeployment) { - incremental = addAspect(); - incremental->setSettingsKey("RemoteLinux.GenericDirectUploadStep.Incremental"); - incremental->setLabel(Tr::tr("Incremental deployment"), - BoolAspect::LabelPlacement::AtCheckBox); - incremental->setValue(true); - incremental->setDefaultValue(true); - } + auto incremental = addAspect(); + incremental->setSettingsKey("RemoteLinux.GenericDirectUploadStep.Incremental"); + incremental->setLabel(Tr::tr("Incremental deployment"), + BoolAspect::LabelPlacement::AtCheckBox); + incremental->setValue(true); + incremental->setDefaultValue(true); auto ignoreMissingFiles = addAspect(); ignoreMissingFiles->setSettingsKey("RemoteLinux.GenericDirectUploadStep.IgnoreMissingFiles"); @@ -310,12 +306,8 @@ GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id i ignoreMissingFiles->setValue(false); setInternalInitializer([this, incremental, ignoreMissingFiles] { - if (incremental) { - d->m_incremental = incremental->value() - ? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled; - } else { - d->m_incremental = IncrementalDeployment::NotSupported; - } + d->m_incremental = incremental->value() + ? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled; d->m_ignoreMissingFiles = ignoreMissingFiles->value(); return isDeploymentPossible(); }); diff --git a/src/plugins/remotelinux/genericdirectuploadstep.h b/src/plugins/remotelinux/genericdirectuploadstep.h index dd022d2b32c..a59e89c66d6 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.h +++ b/src/plugins/remotelinux/genericdirectuploadstep.h @@ -14,8 +14,7 @@ class REMOTELINUX_EXPORT GenericDirectUploadStep : public AbstractRemoteLinuxDep Q_OBJECT public: - GenericDirectUploadStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id, - bool offerIncrementalDeployment = true); + GenericDirectUploadStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); ~GenericDirectUploadStep() override; bool isDeploymentNecessary() const final; From 193b1295f6363d9d88600f34cdaca73ff288546e Mon Sep 17 00:00:00 2001 From: Filippo Gentile Date: Wed, 8 Feb 2023 13:03:40 +0100 Subject: [PATCH 0406/1447] Debugger: run GDB post attach commands also for local inferiors GDB post attach commands previously where only run for Remote or Extended Remote targets. Now they are also run for Local and Local Attach targets Task-number: QTCREATORBUG-28764 Change-Id: I6cf34091f2e53ffc7ea436465c2c1de3ef637e9d Reviewed-by: Reviewed-by: hjk --- src/plugins/debugger/gdb/gdbengine.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 90aa6dd36ec..8a98c0e4337 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4557,7 +4557,13 @@ void GdbEngine::handleLocalAttach(const DebuggerResponse &response) switch (response.resultClass) { case ResultDone: case ResultRunning: + { showMessage("INFERIOR ATTACHED"); + + QString commands = expand(debuggerSettings()->gdbPostAttachCommands.value()); + if (!commands.isEmpty()) + runCommand({commands, NativeCommand}); + if (state() == EngineRunRequested) { // Happens e.g. for "Attach to unstarted application" // We will get a '*stopped' later that we'll interpret as 'spontaneous' @@ -4577,6 +4583,7 @@ void GdbEngine::handleLocalAttach(const DebuggerResponse &response) updateAll(); } break; + } case ResultError: if (response.data["msg"].data() == "ptrace: Operation not permitted.") { QString msg = msgPtraceError(runParameters().startMode); @@ -4731,6 +4738,13 @@ void GdbEngine::handleExecRun(const DebuggerResponse &response) CHECK_STATE(EngineRunRequested); if (response.resultClass == ResultRunning) { + + if (isLocalRunEngine()) { + QString commands = expand(debuggerSettings()->gdbPostAttachCommands.value()); + if (!commands.isEmpty()) + runCommand({commands, NativeCommand}); + } + notifyEngineRunAndInferiorRunOk(); showMessage("INFERIOR STARTED"); showMessage(msgInferiorSetupOk(), StatusBar); From e45ee44ae6fd1e0959bc9378bbe6148513dd56b7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 27 Mar 2023 12:00:27 +0200 Subject: [PATCH 0407/1447] Terminal: Use native shortcut representation Changes the ESC configure button to display the native representation of the ESC Key instead of the macOS specific one. Change-Id: Id3ec69901afb2bcb8b352b9c50a1adb4a074cd74 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/plugins/terminal/terminalpane.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 247f8d8f16c..3d110e764ee 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -132,12 +132,15 @@ TerminalPane::TerminalPane(QObject *parent) auto updateEscButton = [this] { m_escSettingButton->setChecked(TerminalSettings::instance().sendEscapeToTerminal.value()); + static QString escKey = QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText); + static QString shiftEsc = QKeySequence(QKeyCombination(Qt::ShiftModifier, Qt::Key_Escape)) + .toString(QKeySequence::NativeText); if (TerminalSettings::instance().sendEscapeToTerminal.value()) { - m_escSettingButton->setText("⎋"); + m_escSettingButton->setText(escKey); m_escSettingButton->setToolTip(Tr::tr("Sending ESC to terminal instead of Qt Creator")); } else { - m_escSettingButton->setText("⇧+⎋"); - m_escSettingButton->setToolTip(Tr::tr("Press ⇧+⎋ to send ESC to terminal")); + m_escSettingButton->setText(shiftEsc); + m_escSettingButton->setToolTip(Tr::tr("Press %1 to send ESC to terminal").arg(shiftEsc)); } }; From 103c03afd439181414ae53d083d5fe963a19712f Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 27 Mar 2023 14:13:06 +0200 Subject: [PATCH 0408/1447] RemoteLinux: Drop workaround for remote executables Not needed anymore and gets into the way of "double remotes". With this change "Local host as 'double remote' behind some real remote linux" can run plain C++ applications. Change-Id: Id0863c0893e3df0ced59384d12adbe00bc39073e Reviewed-by: Marcus Tillmanns --- .../remotelinuxrunconfiguration.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index 3e28f24af49..06128ad2ffd 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -58,18 +59,16 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Id id) envAspect, &EnvironmentAspect::environmentChanged); setUpdater([this, target, exeAspect, symbolsAspect, libAspect] { - BuildTargetInfo bti = buildTargetInfo(); - const FilePath localExecutable = bti.targetFilePath; - DeployableFile depFile = target->deploymentData().deployableForLocalFile(localExecutable); - - if (depFile.localFilePath().needsDevice()) // a full remote build - exeAspect->setExecutable(depFile.localFilePath()); - else - exeAspect->setExecutable(FilePath::fromString(depFile.remoteFilePath())); - symbolsAspect->setFilePath(localExecutable); - const IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(target->kit()); const IDeviceConstPtr runDevice = DeviceKitAspect::device(target->kit()); + QTC_ASSERT(buildDevice, return); + QTC_ASSERT(runDevice, return); + const BuildTargetInfo bti = buildTargetInfo(); + const FilePath localExecutable = bti.targetFilePath; + const DeployableFile depFile = target->deploymentData().deployableForLocalFile(localExecutable); + + exeAspect->setExecutable(runDevice->filePath(depFile.remoteFilePath())); + symbolsAspect->setFilePath(localExecutable); libAspect->setEnabled(buildDevice == runDevice); }); From 18772b9db5bd51f301dd7febc6c0e281f184075b Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 27 Mar 2023 13:04:02 +0200 Subject: [PATCH 0409/1447] ProjectExplorer: Use 22 as ssh default port Also when constructing an SshParameters object. Change-Id: I0f5a194052c88805bf5f1f414c4b876229d7bdf8 Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/devicesupport/sshparameters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.h b/src/plugins/projectexplorer/devicesupport/sshparameters.h index 1ed49c90a2d..8bdd936d275 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.h +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.h @@ -52,7 +52,7 @@ public: private: QString m_host; - quint16 m_port = 0; + quint16 m_port = 22; QString m_userName; }; From 4adec47a3ebd302290dd5bc4b8f11ac2495276ea Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 27 Mar 2023 12:08:06 +0200 Subject: [PATCH 0410/1447] Qbs: Return FilePath from QbsInstallStep::installRoot() Change-Id: Ie4943ec3dfd760a37b9d85c65095ae0d6cad7fe1 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/qbsprojectmanager/qbsinstallstep.cpp | 10 +++++----- src/plugins/qbsprojectmanager/qbsinstallstep.h | 2 +- src/plugins/qbsprojectmanager/qbsproject.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index 27c875e8688..1aeee5be65b 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -81,7 +81,7 @@ void QbsInstallStep::doRun() QJsonObject request; request.insert("type", "install-project"); - request.insert("install-root", installRoot()); + request.insert("install-root", installRoot().path()); request.insert("clean-install-root", m_cleanInstallRoot->value()); request.insert("keep-going", m_keepGoing->value()); request.insert("dry-run", m_dryRun->value()); @@ -102,10 +102,10 @@ void QbsInstallStep::doCancel() m_session->cancelCurrentJob(); } -QString QbsInstallStep::installRoot() const +FilePath QbsInstallStep::installRoot() const { const QbsBuildStep * const bs = buildConfig()->qbsStep(); - return bs ? bs->installRoot().toString() : QString(); + return bs ? bs->installRoot() : FilePath(); } const QbsBuildConfiguration *QbsInstallStep::buildConfig() const @@ -162,7 +162,7 @@ QWidget *QbsInstallStep::createConfigWidget() { auto widget = new QWidget; - auto installRootValueLabel = new QLabel(installRoot()); + auto installRootValueLabel = new QLabel(installRoot().toUserOutput()); auto commandLineKeyLabel = new QLabel(Tr::tr("Equivalent command line:")); commandLineKeyLabel->setAlignment(Qt::AlignTop); @@ -183,7 +183,7 @@ QWidget *QbsInstallStep::createConfigWidget() builder.attachTo(widget); const auto updateState = [this, commandLineTextEdit, installRootValueLabel] { - installRootValueLabel->setText(installRoot()); + installRootValueLabel->setText(installRoot().toUserOutput()); commandLineTextEdit->setPlainText(buildConfig()->equivalentCommandLine(stepData())); }; diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.h b/src/plugins/qbsprojectmanager/qbsinstallstep.h index 7eef7aa9e14..e0063da8189 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.h +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.h @@ -25,7 +25,7 @@ public: QbsInstallStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); ~QbsInstallStep() override; - QString installRoot() const; + Utils::FilePath installRoot() const; QbsBuildStepData stepData() const; private: diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index ac27ba43f00..7bf1cfd425c 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -498,7 +498,7 @@ FilePath QbsBuildSystem::installRoot() if (!step->enabled()) continue; if (const auto qbsInstallStep = qobject_cast(step)) - return FilePath::fromUserInput(qbsInstallStep->installRoot()); + return qbsInstallStep->installRoot(); } } const QbsBuildStep * const buildStep = m_buildConfiguration->qbsStep(); From 5f65dc84f3459225e08dec4a113a65517ab12f91 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 22:33:14 +0100 Subject: [PATCH 0411/1447] Terminal: Adjust default colors Dark Terminal theme now matches normal background Change-Id: Icdb943e78995245d7e0e55bb11754935333953dd Reviewed-by: Cristian Adam --- share/qtcreator/themes/dark.creatortheme | 6 +++--- share/qtcreator/themes/design-light.creatortheme | 2 +- share/qtcreator/themes/design.creatortheme | 6 +++--- share/qtcreator/themes/flat-dark.creatortheme | 6 +++--- share/qtcreator/themes/flat-light.creatortheme | 2 +- share/qtcreator/themes/flat.creatortheme | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index ab8e1a36f39..b862ac5fc94 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -385,14 +385,14 @@ QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor QmlDesigner_ScrollBarHandleColor=ff505050 TerminalForeground=ffffffff -TerminalBackground=ff000000 +TerminalBackground=normalBackground TerminalSelection=7fffffff TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e TerminalAnsi3=9a9a2f -TerminalAnsi4=0000ab +TerminalAnsi4=0058D1 TerminalAnsi5=a320ac TerminalAnsi6=49a3b0 TerminalAnsi7=bfbfbf @@ -400,7 +400,7 @@ TerminalAnsi8=666666 TerminalAnsi9=d22d1f TerminalAnsi10=62d63f TerminalAnsi11=e5e54b -TerminalAnsi12=0000fe +TerminalAnsi12=003EFF TerminalAnsi13=d22dde TerminalAnsi14=69e2e4 TerminalAnsi15=e5e5e6 diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 550c84c41ec..253cb5f96a6 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -397,7 +397,7 @@ PaletteBaseDisabled=backgroundColorDisabled PaletteTextDisabled=textDisabled TerminalForeground=ff000000 -TerminalBackground=ffffffff +TerminalBackground=normalBackground TerminalSelection=3f000000 TerminalFindMatch=7fffff00 TerminalAnsi0=000000 diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index e2785d426b5..462d49f7f87 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -497,14 +497,14 @@ PaletteMid=ffafafaf PalettePlaceholderText=ff808081 TerminalForeground=ffffffff -TerminalBackground=ff000000 +TerminalBackground=normalBackground TerminalSelection=7fffffff TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e TerminalAnsi3=9a9a2f -TerminalAnsi4=0000ab +TerminalAnsi4=0058D1 TerminalAnsi5=a320ac TerminalAnsi6=49a3b0 TerminalAnsi7=bfbfbf @@ -512,7 +512,7 @@ TerminalAnsi8=666666 TerminalAnsi9=d22d1f TerminalAnsi10=62d63f TerminalAnsi11=e5e54b -TerminalAnsi12=0000fe +TerminalAnsi12=003EFF TerminalAnsi13=d22dde TerminalAnsi14=69e2e4 TerminalAnsi15=e5e5e6 diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index ac7e2bf920c..b05539d9635 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -389,14 +389,14 @@ PaletteMid=ffa0a0a0 PalettePlaceholderText=ff7f7f80 TerminalForeground=ffffffff -TerminalBackground=ff000000 +TerminalBackground=normalBackground TerminalSelection=7fffffff TerminalFindMatch=7fffff00 TerminalAnsi0=000000 TerminalAnsi1=8b1b10 TerminalAnsi2=4aa32e TerminalAnsi3=9a9a2f -TerminalAnsi4=0000ab +TerminalAnsi4=0058D1 TerminalAnsi5=a320ac TerminalAnsi6=49a3b0 TerminalAnsi7=bfbfbf @@ -404,7 +404,7 @@ TerminalAnsi8=666666 TerminalAnsi9=d22d1f TerminalAnsi10=62d63f TerminalAnsi11=e5e54b -TerminalAnsi12=0000fe +TerminalAnsi12=003EFF TerminalAnsi13=d22dde TerminalAnsi14=69e2e4 TerminalAnsi15=e5e5e6 diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index be6431d2c1c..23c4d97ffb8 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -362,7 +362,7 @@ QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor QmlDesigner_ScrollBarHandleColor=ffcccccc TerminalForeground=ff000000 -TerminalBackground=ffffffff +TerminalBackground=normalBackground TerminalSelection=3f000000 TerminalFindMatch=7fffff00 TerminalAnsi0=000000 diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 94a13d0347f..a3d04ba9c5d 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -360,7 +360,7 @@ QmlDesigner_AlternateBackgroundColor=qmlDesignerButtonColor QmlDesigner_ScrollBarHandleColor=ff595b5c TerminalForeground=ff000000 -TerminalBackground=ffffffff +TerminalBackground=normalBackground TerminalSelection=3f000000 TerminalFindMatch=7fffff00 TerminalAnsi0=000000 From d8e87413a34ba7036bf9b677adb825970ca0e717 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 16 Mar 2023 15:39:05 +0100 Subject: [PATCH 0412/1447] RemoteLinux: Add some support for "doubly remote" devices This adds an "Access via:" settings to RL based devices that allow the user to select an intermediate (also RL based) device as "stepping stone". Communication to these devices is done by running ssh from the intermediate device, currently without connection sharing. Currently kind-of-functional: "Show running processes" Change-Id: I6964fb4005ab8f42551c877da2c0bdb1e825cd61 Reviewed-by: Marcus Tillmanns --- .../genericlinuxdeviceconfigurationwidget.cpp | 37 +++++- .../genericlinuxdeviceconfigurationwidget.h | 3 + src/plugins/remotelinux/linuxdevice.cpp | 109 +++++++++++++++--- .../remotelinux/remotelinux_constants.h | 5 +- 4 files changed, 133 insertions(+), 21 deletions(-) diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index fb4ef53579f..b7890bb610b 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -7,6 +7,7 @@ #include "remotelinuxtr.h" #include "sshkeycreationdialog.h" +#include #include #include @@ -17,6 +18,7 @@ #include #include +#include #include #include #include @@ -84,6 +86,16 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_sourceProfileCheckBox = new QCheckBox(Tr::tr("Source %1 and %2").arg("/etc/profile").arg("$HOME/.profile")); + m_linkDeviceComboBox = new QComboBox; + m_linkDeviceComboBox->addItem(Tr::tr("Direct"), QVariant()); + + auto dm = DeviceManager::instance(); + const int dmCount = dm->deviceCount(); + for (int i = 0; i < dmCount; ++i) { + IDevice::ConstPtr dev = dm->deviceAt(i); + m_linkDeviceComboBox->addItem(dev->displayName(), dev->id().toSetting()); + } + auto sshPortLabel = new QLabel(Tr::tr("&SSH port:")); sshPortLabel->setBuddy(m_sshPortSpinBox); @@ -98,7 +110,8 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_keyLabel, m_keyFileLineEdit, createKeyButton, br, Tr::tr("GDB server executable:"), m_gdbServerLineEdit, br, Tr::tr("QML runtime executable:"), m_qmlRuntimeLineEdit, br, - QString(), m_sourceProfileCheckBox, br + QString(), m_sourceProfileCheckBox, br, + Tr::tr("Access via:"), m_linkDeviceComboBox }.attachTo(this); connect(m_hostLineEdit, &QLineEdit::editingFinished, @@ -131,6 +144,8 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( this, &GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged); connect(m_sourceProfileCheckBox, &QCheckBox::toggled, this, &GenericLinuxDeviceConfigurationWidget::sourceProfileCheckingChanged); + connect(m_linkDeviceComboBox, &QComboBox::currentIndexChanged, + this, &GenericLinuxDeviceConfigurationWidget::linkDeviceChanged); initGui(); } @@ -226,6 +241,12 @@ void GenericLinuxDeviceConfigurationWidget::sourceProfileCheckingChanged(bool do device()->setExtraData(Constants::SourceProfile, doCheck); } +void GenericLinuxDeviceConfigurationWidget::linkDeviceChanged(int index) +{ + const QVariant deviceId = m_linkDeviceComboBox->itemData(index); + device()->setExtraData(Constants::LinkDevice, deviceId); +} + void GenericLinuxDeviceConfigurationWidget::updateDeviceFromUi() { hostNameEditingFinished(); @@ -235,6 +256,10 @@ void GenericLinuxDeviceConfigurationWidget::updateDeviceFromUi() keyFileEditingFinished(); handleFreePortsChanged(); gdbServerEditingFinished(); + sshPortEditingFinished(); + timeoutEditingFinished(); + sourceProfileCheckingChanged(m_sourceProfileCheckBox->isChecked()); + linkDeviceChanged(m_linkDeviceComboBox->currentIndex()); } void GenericLinuxDeviceConfigurationWidget::updatePortsWarningLabel() @@ -273,6 +298,16 @@ void GenericLinuxDeviceConfigurationWidget::initGui() m_sshPortSpinBox->setEnabled(!device()->isAutoDetected()); m_hostKeyCheckBox->setChecked(sshParams.hostKeyCheckingMode != SshHostKeyCheckingNone); m_sourceProfileCheckBox->setChecked(device()->extraData(Constants::SourceProfile).toBool()); + Id linkDeviceId = Id::fromSetting(device()->extraData(Constants::LinkDevice)); + auto dm = DeviceManager::instance(); + int found = -1; + for (int i = 0, n = dm->deviceCount(); i < n; ++i) { + if (dm->deviceAt(i)->id() == linkDeviceId) { + found = i; + break; + } + } + m_linkDeviceComboBox->setCurrentIndex(found + 1); // There's the "Direct" entry first. m_hostLineEdit->setText(sshParams.host()); m_sshPortSpinBox->setValue(sshParams.port()); diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h index 024656d1fa0..e9840c9a436 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h @@ -7,6 +7,7 @@ QT_BEGIN_NAMESPACE class QCheckBox; +class QComboBox; class QLabel; class QLineEdit; class QRadioButton; @@ -43,6 +44,7 @@ private: void createNewKey(); void hostKeyCheckingChanged(bool doCheck); void sourceProfileCheckingChanged(bool doCheck); + void linkDeviceChanged(int index); void updateDeviceFromUi() override; void updatePortsWarningLabel(); @@ -63,6 +65,7 @@ private: Utils::PathChooser *m_gdbServerLineEdit; Utils::PathChooser *m_qmlRuntimeLineEdit; QCheckBox *m_sourceProfileCheckBox; + QComboBox *m_linkDeviceComboBox; }; } // RemoteLinux::Internal diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index da7b7aa2d18..4ef2c7340a1 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -389,6 +390,8 @@ public: QString m_socketFilePath; SshParameters m_sshParameters; + IDevice::ConstPtr m_linkDevice; + bool m_connecting = false; bool m_killed = false; @@ -397,6 +400,7 @@ public: QByteArray m_output; QByteArray m_error; bool m_pidParsed = false; + bool m_useConnectionSharing = false; }; SshProcessInterface::SshProcessInterface(const IDevice::ConstPtr &device) @@ -591,11 +595,15 @@ void SshProcessInterfacePrivate::start() { clearForStart(); + const Id linkDeviceId = Id::fromSetting(m_device->extraData(Constants::LinkDevice)); + m_linkDevice = DeviceManager::instance()->find(linkDeviceId); + m_useConnectionSharing = !m_linkDevice && SshSettings::connectionSharingEnabled(); + m_sshParameters = m_device->sshParameters(); // TODO: Do we really need it for master process? m_sshParameters.x11DisplayName = q->m_setup.m_extraData.value("Ssh.X11ForwardToDisplay").toString(); - if (SshSettings::connectionSharingEnabled()) { + if (m_useConnectionSharing) { m_connecting = true; m_connectionHandle.reset(new SshConnectionHandle(m_device)); m_connectionHandle->setParent(this); @@ -662,30 +670,35 @@ void SshProcessInterfacePrivate::doStart() m_process.start(); } -CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const +static CommandLine getCommandLine( + const FilePath sshBinary, + const CommandLine commandLine0, + const FilePath &workingDirectory, + const Environment &env, + const QStringList &options, + bool useX, + bool useTerminal, + bool usePidMarker, + bool sourceProfile) { - CommandLine cmd{SshSettings::sshFilePath()}; + CommandLine cmd{sshBinary}; - if (!m_sshParameters.x11DisplayName.isEmpty()) + if (useX) cmd.addArg("-X"); - if (q->m_setup.m_terminalMode != TerminalMode::Off || q->m_setup.m_ptyData) + if (useTerminal) cmd.addArg("-tt"); cmd.addArg("-q"); - QStringList options = m_sshParameters.connectionOptions(SshSettings::sshFilePath()); - if (!m_socketFilePath.isEmpty()) - options << "-o" << ("ControlPath=" + m_socketFilePath); - options << m_sshParameters.host(); cmd.addArgs(options); - CommandLine commandLine = q->m_setup.m_commandLine; + CommandLine commandLine = commandLine0; FilePath executable = FilePath::fromParts({}, {}, commandLine.executable().path()); commandLine.setExecutable(executable); CommandLine inner; - if (!commandLine.isEmpty() && m_device->extraData(Constants::SourceProfile).toBool()) { + if (!commandLine.isEmpty() && sourceProfile) { const QStringList rcFilesToSource = {"/etc/profile", "$HOME/.profile"}; for (const QString &filePath : rcFilesToSource) { inner.addArgs({"test", "-f", filePath}); @@ -695,31 +708,87 @@ CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const } } - if (!q->m_setup.m_workingDirectory.isEmpty()) { - inner.addArgs({"cd", q->m_setup.m_workingDirectory.path()}); + if (!workingDirectory.isEmpty()) { + inner.addArgs({"cd", workingDirectory.path()}); inner.addArgs("&&", CommandLine::Raw); } - if (q->m_setup.m_terminalMode == TerminalMode::Off && !q->m_setup.m_ptyData) + if (usePidMarker) inner.addArgs(QString("echo ") + s_pidMarker + "$$" + s_pidMarker + " && ", CommandLine::Raw); - const Environment &env = q->m_setup.m_environment; env.forEachEntry([&](const QString &key, const QString &value, bool) { inner.addArgs(key + "='" + env.expandVariables(value) + '\'', CommandLine::Raw); }); - if (q->m_setup.m_terminalMode == TerminalMode::Off && !q->m_setup.m_ptyData) + if (!useTerminal && !commandLine.isEmpty()) inner.addArg("exec"); if (!commandLine.isEmpty()) inner.addCommandLineAsArgs(commandLine, CommandLine::Raw); - cmd.addArg(inner.arguments()); return cmd; } +CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const +{ + const FilePath sshBinary = SshSettings::sshFilePath(); + const bool useTerminal = q->m_setup.m_terminalMode != TerminalMode::Off || q->m_setup.m_ptyData; + const bool usePidMarker = !useTerminal; + const bool sourceProfile = m_device->extraData(Constants::SourceProfile).toBool(); + const bool useX = !m_sshParameters.x11DisplayName.isEmpty(); + + CommandLine cmd; + if (m_linkDevice) { + QStringList farOptions = m_sshParameters.connectionOptions("ssh"); + farOptions << m_sshParameters.host(); + + const SshParameters nearParameters = m_linkDevice->sshParameters(); + QStringList nearOptions = nearParameters.connectionOptions(sshBinary); +// if (!m_socketFilePath.isEmpty()) +// options << "-o" << ("ControlPath=" + m_socketFilePath); + nearOptions << nearParameters.host(); + + cmd = getCommandLine("ssh", + q->m_setup.m_commandLine, + {}, + {}, + farOptions, + false, + false, + false, + false); + + cmd = getCommandLine(sshBinary, + cmd, + {}, + {}, + nearOptions, + false, + false, + usePidMarker, + false); + } else { + QStringList options = m_sshParameters.connectionOptions(sshBinary); + if (!m_socketFilePath.isEmpty()) + options << "-o" << ("ControlPath=" + m_socketFilePath); + options << m_sshParameters.host(); + + cmd = getCommandLine(sshBinary, + q->m_setup.m_commandLine, + q->m_setup.m_workingDirectory, + q->m_setup.m_environment, + options, + useX, + useTerminal, + usePidMarker, + sourceProfile); + } + + return cmd; +} + // ShellThreadHandler static SshParameters displayless(const SshParameters &sshParameters) @@ -1203,7 +1272,11 @@ private: void start() final { m_sshParameters = displayless(m_device->sshParameters()); - if (SshSettings::connectionSharingEnabled()) { + const Id linkDeviceId = Id::fromSetting(m_device->extraData(Constants::LinkDevice)); + const auto linkDevice = DeviceManager::instance()->find(linkDeviceId); + const bool useConnectionSharing = !linkDevice && SshSettings::connectionSharingEnabled(); + + if (useConnectionSharing) { m_connecting = true; m_connectionHandle.reset(new SshConnectionHandle(m_device)); m_connectionHandle->setParent(this); diff --git a/src/plugins/remotelinux/remotelinux_constants.h b/src/plugins/remotelinux/remotelinux_constants.h index a7ad8de6989..40cc1d1a8b1 100644 --- a/src/plugins/remotelinux/remotelinux_constants.h +++ b/src/plugins/remotelinux/remotelinux_constants.h @@ -19,8 +19,9 @@ const char RsyncDeployStepId[] = "RemoteLinux.RsyncDeployStep"; const char CustomCommandDeployStepId[] = "RemoteLinux.GenericRemoteLinuxCustomCommandDeploymentStep"; const char KillAppStepId[] = "RemoteLinux.KillAppStep"; -const char SupportsRSync[] = "RemoteLinux.SupportsRSync"; -const char SourceProfile[] = "RemoteLinux.SourceProfile"; +const char SupportsRSync[] = "RemoteLinux.SupportsRSync"; +const char SourceProfile[] = "RemoteLinux.SourceProfile"; +const char LinkDevice[] = "RemoteLinux.LinkDevice"; const char RunConfigId[] = "RemoteLinuxRunConfiguration:"; const char CustomRunConfigId[] = "RemoteLinux.CustomRunConfig"; From c7b6c66cab595e5c7f0b57439d72a0c4a1e3b80c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 07:52:57 +0200 Subject: [PATCH 0413/1447] Docker: Fix process state handling Fixes the following errors that would trigger warnings due to incorrect QtcProcess/ProcessImpl state synchronization * Don't emit readyRead when state != Running * Set result.m_error to FailedToStart if remote pid was not received * Send stderr data once the pid was received * Don't call deleteLater() on nullptr Change-Id: I4b498a860ad27bef1a5b3e26417576431b54e84c Reviewed-by: hjk --- src/plugins/docker/dockerdevice.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 0745dd95238..5c543dfc3a8 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -255,8 +255,10 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva if (ok) emit started(m_remotePID); - if (rest.size() > 0) - emit readyRead(rest, {}); + // In case we already received some error output, send it now. + const QByteArray stdErr = m_process.readAllRawStandardError(); + if (rest.size() > 0 || stdErr.size() > 0) + emit readyRead(rest, stdErr); m_hasReceivedFirstOutput = true; return; @@ -266,13 +268,28 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva }); connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { - emit readyRead({}, m_process.readAllRawStandardError()); + if (m_remotePID) + emit readyRead({}, m_process.readAllRawStandardError()); }); connect(&m_process, &QtcProcess::done, this, [this] { qCDebug(dockerDeviceLog) << "Process exited:" << m_process.commandLine() << "with code:" << m_process.resultData().m_exitCode; - emit done(m_process.resultData()); + + Utils::ProcessResultData resultData = m_process.resultData(); + + if (m_remotePID == 0) { + resultData.m_error = QProcess::FailedToStart; + qCWarning(dockerDeviceLog) << "Process failed to start:" << m_process.commandLine(); + QByteArray stdOut = m_process.readAllRawStandardOutput(); + QByteArray stdErr = m_process.readAllRawStandardError(); + if (!stdOut.isEmpty()) + qCWarning(dockerDeviceLog) << "stdout:" << stdOut; + if (!stdErr.isEmpty()) + qCWarning(dockerDeviceLog) << "stderr:" << stdErr; + } + + emit done(resultData); }); } @@ -699,7 +716,8 @@ bool DockerDevicePrivate::startContainer() m_shell = std::make_unique(m_settings, m_container, q->rootPath()); connect(m_shell.get(), &DeviceShell::done, this, [this](const ProcessResultData &resultData) { - m_shell.release()->deleteLater(); + if (m_shell) + m_shell.release()->deleteLater(); if (resultData.m_error != QProcess::UnknownError || resultData.m_exitStatus == QProcess::NormalExit) return; From 5db27d21daaca766b08796078362025262794f07 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Sat, 25 Mar 2023 15:50:00 +0100 Subject: [PATCH 0414/1447] Terminal: Add setting to change arguments of default shell On non windows systems, initialize it with "-l" to start a login shell. Change-Id: I972f845c3933c6a54752d4c71108a658311a0256 Reviewed-by: Christian Stenger --- src/plugins/terminal/terminalsettings.cpp | 23 +++++++++++++++---- src/plugins/terminal/terminalsettings.h | 1 + src/plugins/terminal/terminalsettingspage.cpp | 3 ++- src/plugins/terminal/terminalwidget.cpp | 4 +++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 1a3625098da..1f548a65fae 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -35,11 +35,15 @@ static int defaultFontSize() static QString defaultShell() { - if (Utils::HostOsInfo::isMacHost()) - return "/bin/zsh"; - if (Utils::HostOsInfo::isAnyUnixHost()) - return "/bin/bash"; - return qtcEnvironmentVariable("COMSPEC"); + if (HostOsInfo::isWindowsHost()) + return qtcEnvironmentVariable("COMSPEC"); + + QString defaultShell = qtcEnvironmentVariable("SHELL"); + if (FilePath::fromUserInput(defaultShell).isExecutableFile()) + return defaultShell; + + Utils::FilePath shPath = Utils::Environment::systemEnvironment().searchInPath("sh"); + return shPath.nativePath(); } TerminalSettings &TerminalSettings::instance() @@ -97,6 +101,14 @@ TerminalSettings::TerminalSettings() shell.setToolTip(Tr::tr("The shell executable to be started as terminal")); shell.setDefaultValue(defaultShell()); + shellArguments.setSettingsKey("ShellArguments"); + shellArguments.setLabelText(Tr::tr("Shell arguments:")); + shellArguments.setDisplayStyle(StringAspect::LineEditDisplay); + shellArguments.setHistoryCompleter("Terminal.Shell.History"); + shellArguments.setToolTip(Tr::tr("The arguments to be passed to the shell")); + if (!HostOsInfo::isWindowsHost()) + shellArguments.setDefaultValue(QString("-l")); + sendEscapeToTerminal.setSettingsKey("SendEscapeToTerminal"); sendEscapeToTerminal.setLabelText(Tr::tr("Send escape key to terminal")); sendEscapeToTerminal.setToolTip( @@ -117,6 +129,7 @@ TerminalSettings::TerminalSettings() registerAspect(&enableTerminal); registerAspect(&sendEscapeToTerminal); registerAspect(&audibleBell); + registerAspect(&shellArguments); setupColor(this, foregroundColor, diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index 45b85c5910f..137f3abe3aa 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -18,6 +18,7 @@ public: Utils::StringAspect font; Utils::IntegerAspect fontSize; Utils::StringAspect shell; + Utils::StringAspect shellArguments; Utils::ColorAspect foregroundColor; Utils::ColorAspect backgroundColor; diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index f0bfa883d7a..b6ef57f2d00 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -423,8 +423,9 @@ QWidget *TerminalSettingsPage::widget() } }, }, - Row { + Column { settings.shell, + settings.shellArguments, }, st, }.attachTo(widget); diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 06fcfe57791..a7b3590a599 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -141,7 +141,9 @@ void TerminalWidget::setupPty() Environment env = m_openParameters.environment.value_or(Environment::systemEnvironment()); CommandLine shellCommand = m_openParameters.shellCommand.value_or( - CommandLine{TerminalSettings::instance().shell.filePath(), {}}); + CommandLine{TerminalSettings::instance().shell.filePath(), + TerminalSettings::instance().shellArguments.value(), + CommandLine::Raw}); // For git bash on Windows env.prependOrSetPath(shellCommand.executable().parentDir()); From 3da30a8f2c93160cd1ba6b4291c7414249b9717e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 27 Mar 2023 22:47:04 +0200 Subject: [PATCH 0415/1447] MinGW build: Fix a few compilation warnings Change-Id: Ib4f85d2ef15a5c06c6d2b175823c196b8588f5d2 Reviewed-by: Cristian Adam --- src/libs/utils/process_ctrlc_stub.cpp | 10 +++++----- src/plugins/terminal/terminalsettingspage.cpp | 2 +- src/tools/qtcdebugger/main.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/process_ctrlc_stub.cpp b/src/libs/utils/process_ctrlc_stub.cpp index bbfdf7ff14d..b924e74e49d 100644 --- a/src/libs/utils/process_ctrlc_stub.cpp +++ b/src/libs/utils/process_ctrlc_stub.cpp @@ -44,7 +44,7 @@ public: fwprintf(stderr, L"qtcreator_ctrlc_stub: CreateJobObject failed: 0x%x.\n", GetLastError()); return; } - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0}; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if (!SetInformationJobObject(m_job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { fwprintf(stderr, L"qtcreator_ctrlc_stub: SetInformationJobObject failed: 0x%x.\n", GetLastError()); @@ -85,7 +85,7 @@ int main(int argc, char **) uiShutDownWindowMessage = RegisterWindowMessage(L"qtcctrlcstub_shutdown"); uiInterruptMessage = RegisterWindowMessage(L"qtcctrlcstub_interrupt"); - WNDCLASSEX wcex = {0}; + WNDCLASSEX wcex = {}; wcex.cbSize = sizeof(wcex); wcex.lpfnWndProc = WndProc; wcex.hInstance = GetModuleHandle(nullptr); @@ -188,14 +188,14 @@ DWORD WINAPI processWatcherThread(LPVOID lpParameter) bool startProcess(wchar_t *pCommandLine, bool lowerPriority, const JobKillOnClose& job) { - SECURITY_ATTRIBUTES sa = {0}; + SECURITY_ATTRIBUTES sa = {}; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; - STARTUPINFO si = {0}; + STARTUPINFO si = {}; si.cb = sizeof(si); - PROCESS_INFORMATION pi; + PROCESS_INFORMATION pi = {}; DWORD dwCreationFlags = lowerPriority ? BELOW_NORMAL_PRIORITY_CLASS : 0; BOOL bSuccess = CreateProcess(NULL, pCommandLine, &sa, &sa, TRUE, dwCreationFlags, NULL, NULL, &si, &pi); if (!bSuccess) { diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index b6ef57f2d00..db7920bd61c 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -89,7 +89,7 @@ static expected_str loadItermColors(const FilePath &path) colorName = reader.readElementText(); } else if (reader.name() == u"dict") { QColor color; - int component; + int component = 0; while (!reader.atEnd() && reader.readNextStartElement()) { if (reader.name() == u"key") { const auto &text = reader.readElementText(); diff --git a/src/tools/qtcdebugger/main.cpp b/src/tools/qtcdebugger/main.cpp index 5aee7b6fe91..cbb4b935d72 100644 --- a/src/tools/qtcdebugger/main.cpp +++ b/src/tools/qtcdebugger/main.cpp @@ -520,7 +520,7 @@ int main(int argc, char *argv[]) } if (debug) qDebug() << "Mode=" << optMode << " PID=" << argProcessId << " Evt=" << argWinCrashEvent; - bool ex = 0; + int ex = 0; switch (optMode) { case HelpMode: usage(QCoreApplication::applicationFilePath(), errorMessage); From 7e4c52959c10aa0092cb0393b515691a7c4d174d Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 07:49:05 +0200 Subject: [PATCH 0416/1447] Utils: Don't try to start clangd if path is empty Change-Id: I30d3279be81b66c16ee8081b09828aaa6bcd53e0 Reviewed-by: David Schulz --- src/libs/utils/clangutils.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/utils/clangutils.cpp b/src/libs/utils/clangutils.cpp index 3f2fb69909d..ee4868f94b3 100644 --- a/src/libs/utils/clangutils.cpp +++ b/src/libs/utils/clangutils.cpp @@ -45,6 +45,11 @@ QVersionNumber clangdVersion(const FilePath &clangd) bool checkClangdVersion(const FilePath &clangd, QString *error) { + if (clangd.isEmpty()) { + *error = Tr::tr("No clangd executable specified."); + return false; + } + const QVersionNumber version = clangdVersion(clangd); if (version >= minimumClangdVersion()) return true; From 62b1795fb0b4b39bf63d3c40a6d58e19419b0908 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Mar 2023 17:45:44 +0100 Subject: [PATCH 0417/1447] RemoteLinux: Further disantangle buildsteps from downstream Expose Factories, (mid term:) hide step implementations. Change-Id: I930899fe6873c8f727f3dedbb86aceb9bcbda0a4 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/boot2qt/qdbplugin.cpp | 21 +++++++------------ .../remotelinux/genericdirectuploadstep.cpp | 8 +++++++ .../remotelinux/genericdirectuploadstep.h | 7 +++++++ src/plugins/remotelinux/makeinstallstep.cpp | 10 ++++++++- src/plugins/remotelinux/makeinstallstep.h | 7 +++++++ src/plugins/remotelinux/rsyncdeploystep.cpp | 8 +++++++ src/plugins/remotelinux/rsyncdeploystep.h | 7 +++++++ 7 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index a73646b6c82..0d995ee0402 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -100,16 +100,14 @@ void registerFlashAction(QObject *parentForAction) toolsContainer->addAction(flashCommand, flashActionId); } -template -class QdbDeployStepFactory : public ProjectExplorer::BuildStepFactory +template +class QdbDeployStepFactory : public Factory { public: - explicit QdbDeployStepFactory(Id id) + QdbDeployStepFactory() { - registerStep(id); - setDisplayName(Step::displayName()); - setSupportedConfiguration(Constants::QdbDeployConfigurationId); - setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); + Factory::setSupportedConfiguration(Constants::QdbDeployConfigurationId); + Factory::setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } }; @@ -125,12 +123,9 @@ public: QdbStopApplicationStepFactory m_stopApplicationStepFactory; QdbMakeDefaultAppStepFactory m_makeDefaultAppStepFactory; - QdbDeployStepFactory - m_directUploadStepFactory{RemoteLinux::Constants::DirectUploadStepId}; - QdbDeployStepFactory - m_rsyncDeployStepFactory{RemoteLinux::Constants::RsyncDeployStepId}; - QdbDeployStepFactory - m_makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId}; + QdbDeployStepFactory m_directUploadStepFactory; + QdbDeployStepFactory m_rsyncDeployStepFactory; + QdbDeployStepFactory m_makeInstallStepFactory; const QList supportedRunConfigs { m_runConfigFactory.runConfigurationId(), diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index dd867d4e698..8345f76e6d7 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -332,4 +332,12 @@ QString GenericDirectUploadStep::displayName() return Tr::tr("Upload files via SFTP"); } +// Factory + +GenericDirectUploadStepFactory::GenericDirectUploadStepFactory() +{ + registerStep(Constants::DirectUploadStepId); + setDisplayName(Tr::tr("Upload files via SFTP")); +} + } //namespace RemoteLinux diff --git a/src/plugins/remotelinux/genericdirectuploadstep.h b/src/plugins/remotelinux/genericdirectuploadstep.h index a59e89c66d6..048be324a89 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.h +++ b/src/plugins/remotelinux/genericdirectuploadstep.h @@ -28,4 +28,11 @@ private: class GenericDirectUploadStepPrivate *d; }; +class REMOTELINUX_EXPORT GenericDirectUploadStepFactory + : public ProjectExplorer::BuildStepFactory +{ +public: + GenericDirectUploadStepFactory(); +}; + } // RemoteLinux diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index 8f51c0b827c..83bed3a74cc 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -281,4 +281,12 @@ bool MakeInstallStep::fromMap(const QVariantMap &map) return true; } -} // namespace RemoteLinux +// Factory + +MakeInstallStepFactory::MakeInstallStepFactory() +{ + registerStep(Constants::MakeInstallStepId); + setDisplayName(Tr::tr("Install into temporary host directory")); +} + +} // RemoteLinux diff --git a/src/plugins/remotelinux/makeinstallstep.h b/src/plugins/remotelinux/makeinstallstep.h index ec2fc3985a2..012a9924cf6 100644 --- a/src/plugins/remotelinux/makeinstallstep.h +++ b/src/plugins/remotelinux/makeinstallstep.h @@ -41,4 +41,11 @@ private: bool m_isCmakeProject = false; }; +class REMOTELINUX_EXPORT MakeInstallStepFactory + : public ProjectExplorer::BuildStepFactory +{ +public: + MakeInstallStepFactory(); +}; + } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index b81914b072b..1dd46cbc286 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -137,4 +137,12 @@ QString RsyncDeployStep::displayName() return Tr::tr("Deploy files via rsync"); } +// Factory + +RsyncDeployStepFactory::RsyncDeployStepFactory() +{ + registerStep(Constants::RsyncDeployStepId); + setDisplayName(Tr::tr("Deploy files via rsync")); +} + } // RemoteLinux diff --git a/src/plugins/remotelinux/rsyncdeploystep.h b/src/plugins/remotelinux/rsyncdeploystep.h index 1cbd2edee38..eb6ac41d6d4 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.h +++ b/src/plugins/remotelinux/rsyncdeploystep.h @@ -33,4 +33,11 @@ private: QString m_flags; }; +class REMOTELINUX_EXPORT RsyncDeployStepFactory + : public ProjectExplorer::BuildStepFactory +{ +public: + RsyncDeployStepFactory(); +}; + } // namespace RemoteLinux From 746f0f93be210d89563bd7f6d0d9c18ebde41cb9 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 09:37:02 +0200 Subject: [PATCH 0418/1447] ProjectExplorer: Inline BuildStepInfo Was a more or less arbitrary subset of BuildStepFactory data. Change-Id: Ie37735532da8a15a22d5f92e1b45d6ed5f7758fc Reviewed-by: Christian Stenger --- .../nim/project/nimcompilercleanstep.cpp | 2 +- src/plugins/projectexplorer/buildstep.cpp | 25 +++++++----- src/plugins/projectexplorer/buildstep.h | 40 ++++++++----------- .../projectexplorer/buildstepspage.cpp | 8 ++-- .../python/pysidebuildconfiguration.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 2 +- 6 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/plugins/nim/project/nimcompilercleanstep.cpp b/src/plugins/nim/project/nimcompilercleanstep.cpp index c17f9437a53..8e13c068131 100644 --- a/src/plugins/nim/project/nimcompilercleanstep.cpp +++ b/src/plugins/nim/project/nimcompilercleanstep.cpp @@ -110,7 +110,7 @@ bool NimCompilerCleanStep::removeOutFilePath() NimCompilerCleanStepFactory::NimCompilerCleanStepFactory() { registerStep(Constants::C_NIMCOMPILERCLEANSTEP_ID); - setFlags(BuildStepInfo::Unclonable); + setFlags(BuildStep::Unclonable); setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN); setSupportedConfiguration(Constants::C_NIMBUILDCONFIGURATION_ID); setRepeatable(false); diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index c078a73d822..84c2fcf79ee 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -361,7 +361,7 @@ bool BuildStepFactory::canHandle(BuildStepList *bsl) const return false; } - if (!m_isRepeatable && bsl->contains(m_info.id)) + if (!m_isRepeatable && bsl->contains(m_stepId)) return false; if (m_supportedConfiguration.isValid()) { @@ -375,14 +375,19 @@ bool BuildStepFactory::canHandle(BuildStepList *bsl) const return true; } -void BuildStepFactory::setDisplayName(const QString &displayName) +QString BuildStepFactory::displayName() const { - m_info.displayName = displayName; + return m_displayName; } -void BuildStepFactory::setFlags(BuildStepInfo::Flags flags) +void BuildStepFactory::setDisplayName(const QString &displayName) { - m_info.flags = flags; + m_displayName = displayName; +} + +void BuildStepFactory::setFlags(BuildStep::Flags flags) +{ + m_flags = flags; } void BuildStepFactory::setSupportedStepList(Id id) @@ -415,20 +420,20 @@ void BuildStepFactory::setSupportedDeviceTypes(const QList &ids) m_supportedDeviceTypes = ids; } -BuildStepInfo BuildStepFactory::stepInfo() const +BuildStep::Flags BuildStepFactory::stepFlags() const { - return m_info; + return m_flags; } Id BuildStepFactory::stepId() const { - return m_info.id; + return m_stepId; } BuildStep *BuildStepFactory::create(BuildStepList *parent) { - BuildStep *step = m_info.creator(parent); - step->setDefaultDisplayName(m_info.displayName); + BuildStep *step = m_creator(parent); + step->setDefaultDisplayName(m_displayName); return step; } diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h index 547a5e2027b..d0a21910afa 100644 --- a/src/plugins/projectexplorer/buildstep.h +++ b/src/plugins/projectexplorer/buildstep.h @@ -76,6 +76,12 @@ public: enum OutputNewlineSetting { DoAppendNewline, DontAppendNewline }; + enum Flags { + Uncreatable = 1 << 0, + Unclonable = 1 << 1, + UniqueStep = 1 << 8 // Can't be used twice in a BuildStepList + }; + bool widgetExpandedByDefault() const; void setWidgetExpandedByDefault(bool widgetExpandedByDefault); @@ -136,23 +142,6 @@ private: QString m_summaryText; }; -class PROJECTEXPLORER_EXPORT BuildStepInfo -{ -public: - enum Flags { - Uncreatable = 1 << 0, - Unclonable = 1 << 1, - UniqueStep = 1 << 8 // Can't be used twice in a BuildStepList - }; - - using BuildStepCreator = std::function; - - Utils::Id id; - QString displayName; - Flags flags = Flags(); - BuildStepCreator creator; -}; - class PROJECTEXPLORER_EXPORT BuildStepFactory { public: @@ -163,22 +152,24 @@ public: static const QList allBuildStepFactories(); - BuildStepInfo stepInfo() const; + BuildStep::Flags stepFlags() const; Utils::Id stepId() const; BuildStep *create(BuildStepList *parent); BuildStep *restore(BuildStepList *parent, const QVariantMap &map); bool canHandle(BuildStepList *bsl) const; + QString displayName() const; + protected: using BuildStepCreator = std::function; template void registerStep(Utils::Id id) { - QTC_CHECK(!m_info.creator); - m_info.id = id; - m_info.creator = [id](BuildStepList *bsl) { return new BuildStepType(bsl, id); }; + QTC_CHECK(!m_creator); + m_stepId = id; + m_creator = [id](BuildStepList *bsl) { return new BuildStepType(bsl, id); }; } void setSupportedStepList(Utils::Id id); @@ -189,10 +180,13 @@ protected: void setSupportedDeviceTypes(const QList &ids); void setRepeatable(bool on) { m_isRepeatable = on; } void setDisplayName(const QString &displayName); - void setFlags(BuildStepInfo::Flags flags); + void setFlags(BuildStep::Flags flags); private: - BuildStepInfo m_info; + Utils::Id m_stepId; + QString m_displayName; + BuildStep::Flags m_flags = {}; + BuildStepCreator m_creator; Utils::Id m_supportedProjectType; QList m_supportedDeviceTypes; diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp index 241d2a98352..21fb4c20932 100644 --- a/src/plugins/projectexplorer/buildstepspage.cpp +++ b/src/plugins/projectexplorer/buildstepspage.cpp @@ -209,14 +209,14 @@ void BuildStepListWidget::updateAddBuildStepMenu() if (!factory->canHandle(m_buildStepList)) continue; - const BuildStepInfo &info = factory->stepInfo(); - if (info.flags & BuildStepInfo::Uncreatable) + const BuildStep::Flags flags = factory->stepFlags(); + if (flags & BuildStep::Uncreatable) continue; - if ((info.flags & BuildStepInfo::UniqueStep) && m_buildStepList->contains(info.id)) + if ((flags & BuildStep::UniqueStep) && m_buildStepList->contains(factory->stepId())) continue; - QAction *action = menu->addAction(info.displayName); + QAction *action = menu->addAction(factory->displayName()); connect(action, &QAction::triggered, this, [factory, this] { BuildStep *newStep = factory->create(m_buildStepList); QTC_ASSERT(newStep, return); diff --git a/src/plugins/python/pysidebuildconfiguration.cpp b/src/plugins/python/pysidebuildconfiguration.cpp index 3480be3e87a..ce37bb67b32 100644 --- a/src/plugins/python/pysidebuildconfiguration.cpp +++ b/src/plugins/python/pysidebuildconfiguration.cpp @@ -42,7 +42,7 @@ PySideBuildStepFactory::PySideBuildStepFactory() registerStep(pySideBuildStep); setSupportedProjectType(PythonProjectId); setDisplayName(Tr::tr("Run PySide6 project tool")); - setFlags(BuildStepInfo::UniqueStep); + setFlags(BuildStep::UniqueStep); } PySideBuildStep::PySideBuildStep(BuildStepList *bsl, Id id) diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index c726156e942..344acf25ba0 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -744,7 +744,7 @@ QMakeStepFactory::QMakeStepFactory() setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); //: QMakeStep default display name setDisplayName(::QmakeProjectManager::Tr::tr("qmake")); // Fully qualifying for lupdate - setFlags(BuildStepInfo::UniqueStep); + setFlags(BuildStep::UniqueStep); } QMakeStepConfig::TargetArchConfig QMakeStepConfig::targetArchFor(const Abi &, const QtVersion *) From db38eef8115c74c1b8bf42644c9a51965d86f0ab Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 13:54:27 +0200 Subject: [PATCH 0419/1447] RemoteLinux: Display copy errors Change-Id: I6f75af7b4700e26d43b605bee014b4768224caf6 Reviewed-by: hjk --- src/plugins/remotelinux/linuxdevice.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 4ef2c7340a1..d70ca77295c 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1522,8 +1522,9 @@ private: .arg(m_currentIndex) .arg(m_fileCount) .arg(source.toUserOutput(), target.toUserOutput())); - if (!source.copyFile(target)) { - result.m_errorString = Tr::tr("Failed."); + expected_str copyResult = source.copyFile(target); + if (!copyResult) { + result.m_errorString = Tr::tr("Failed: %1").arg(copyResult.error()); result.m_exitCode = -1; // Random pick emit done(result); return; From 662aabd29f8e847abed41cce5f4bb5747502ed9d Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 14:31:48 +0200 Subject: [PATCH 0420/1447] ProjectExplorer: Add menu button to add devices Change-Id: I7078617dc0a981854ccf25cef7a8136dbe51000b Reviewed-by: hjk --- .../devicesupport/devicesettingswidget.cpp | 43 ++++++++++++------- .../devicesupport/devicesettingswidget.h | 1 - 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index 663d1932ca3..88812d49c8c 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -19,12 +19,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -101,21 +103,28 @@ void DeviceSettingsWidget::initGui() m_deviceStateTextLabel = new QLabel; m_osSpecificGroupBox = new QGroupBox(Tr::tr("Type Specific")); m_osSpecificGroupBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); - m_addConfigButton = new QPushButton(Tr::tr("&Start Wizard to Add Device...")); m_removeConfigButton = new QPushButton(Tr::tr("&Remove")); m_defaultDeviceButton = new QPushButton(Tr::tr("Set As Default")); - auto directLayout = new QVBoxLayout; + OptionPushButton *addButton = new OptionPushButton(Tr::tr("&Add...")); + connect(addButton, &OptionPushButton::clicked, this, &DeviceSettingsWidget::addDevice); + + QMenu *deviceTypeMenu = new QMenu(addButton); + QAction *defaultAction = new QAction(Tr::tr("&Start Wizard to Add Device...")); + connect(defaultAction, &QAction::triggered, this, &DeviceSettingsWidget::addDevice); + deviceTypeMenu->addAction(defaultAction); + deviceTypeMenu->addSeparator(); + for (IDeviceFactory *factory : IDeviceFactory::allDeviceFactories()) { if (!factory->canCreate()) continue; - auto button = new QPushButton(Tr::tr("Add %1").arg(factory->displayName())); - directLayout->addWidget(button); - if (!factory->quickCreationAllowed()) { - button->setEnabled(false); + if (!factory->quickCreationAllowed()) continue; - } - connect (button, &QPushButton::clicked, this, [factory, this] { + + QAction *action = new QAction(Tr::tr("Add %1").arg(factory->displayName())); + deviceTypeMenu->addAction(action); + + connect(action, &QAction::triggered, this, [factory, this] { IDevice::Ptr device = factory->construct(); QTC_ASSERT(device, return); m_deviceManager->addDevice(device); @@ -125,6 +134,8 @@ void DeviceSettingsWidget::initGui() }); } + addButton->setOptionalMenu(deviceTypeMenu); + m_buttonsLayout = new QVBoxLayout; m_buttonsLayout->setContentsMargins({}); auto scrollAreaWidget = new QWidget; @@ -145,15 +156,14 @@ void DeviceSettingsWidget::initGui() Tr::tr("Current state:"), Row { m_deviceStateIconLabel, m_deviceStateTextLabel, st, }, br, }.attachTo(m_generalGroupBox); + // clang-format off Row { Column { Form { m_configurationLabel, m_configurationComboBox, br, }, scrollArea, }, Column { - m_addConfigButton, - Space(10), - directLayout, + addButton, Space(30), m_removeConfigButton, m_defaultDeviceButton, @@ -161,11 +171,12 @@ void DeviceSettingsWidget::initGui() st, }, }.attachTo(this); + // clang-format on bool hasDeviceFactories = Utils::anyOf(IDeviceFactory::allDeviceFactories(), &IDeviceFactory::canCreate); - m_addConfigButton->setEnabled(hasDeviceFactories); + addButton->setEnabled(hasDeviceFactories); int lastIndex = ICore::settings() ->value(QLatin1String(LastDeviceIndexKey), 0).toInt(); @@ -180,10 +191,10 @@ void DeviceSettingsWidget::initGui() this, &DeviceSettingsWidget::setDefaultDevice); connect(m_removeConfigButton, &QAbstractButton::clicked, this, &DeviceSettingsWidget::removeDevice); - connect(m_nameLineEdit, &QLineEdit::editingFinished, - this, &DeviceSettingsWidget::deviceNameEditingFinished); - connect(m_addConfigButton, &QAbstractButton::clicked, - this, &DeviceSettingsWidget::addDevice); + connect(m_nameLineEdit, + &QLineEdit::editingFinished, + this, + &DeviceSettingsWidget::deviceNameEditingFinished); } void DeviceSettingsWidget::addDevice() diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h index 5cd5cec85e2..207b60cf749 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.h @@ -76,7 +76,6 @@ private: QLabel *m_deviceStateIconLabel; QLabel *m_deviceStateTextLabel; QGroupBox *m_osSpecificGroupBox; - QPushButton *m_addConfigButton; QPushButton *m_removeConfigButton; QPushButton *m_defaultDeviceButton; QVBoxLayout *m_buttonsLayout; From bc4629d427d5bec02e8a87bd7b2b0db11916b050 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 27 Mar 2023 09:50:01 +0200 Subject: [PATCH 0421/1447] RemoteLinux: Add history completion to a few device property line edits Change-Id: If871ff31ebd33a055bdcae38438eb0b4b48b904b Reviewed-by: Marcus Tillmanns Reviewed-by: --- .../genericlinuxdeviceconfigurationwidget.cpp | 11 ++++++++--- .../genericlinuxdeviceconfigurationwidget.h | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index b7890bb610b..a0a53e4e1c5 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -41,8 +41,9 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_keyButton = new QRadioButton(Tr::tr("Specific &key")); - m_hostLineEdit = new QLineEdit(this); + m_hostLineEdit = new FancyLineEdit(this); m_hostLineEdit->setPlaceholderText(Tr::tr("IP or host name of the device")); + m_hostLineEdit->setHistoryCompleter("HostName"); m_sshPortSpinBox = new QSpinBox(this); m_sshPortSpinBox->setMinimum(0); @@ -51,8 +52,9 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_hostKeyCheckBox = new QCheckBox(Tr::tr("&Check host key")); - m_portsLineEdit = new QLineEdit(this); + m_portsLineEdit = new FancyLineEdit(this); m_portsLineEdit->setToolTip(Tr::tr("You can enter lists and ranges like this: '1024,1026-1028,1030'.")); + m_portsLineEdit->setHistoryCompleter("PortRange"); m_portsWarningLabel = new QLabel(this); @@ -62,7 +64,8 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_timeoutSpinBox->setValue(1000); m_timeoutSpinBox->setSuffix(Tr::tr("s")); - m_userLineEdit = new QLineEdit(this); + m_userLineEdit = new FancyLineEdit(this); + m_userLineEdit->setHistoryCompleter("UserName"); m_keyLabel = new QLabel(Tr::tr("Private key file:")); @@ -77,11 +80,13 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_gdbServerLineEdit->setExpectedKind(PathChooser::ExistingCommand); m_gdbServerLineEdit->setPlaceholderText(hint); m_gdbServerLineEdit->setToolTip(hint); + m_gdbServerLineEdit->setHistoryCompleter("GdbServer"); m_qmlRuntimeLineEdit = new PathChooser(this); m_qmlRuntimeLineEdit->setExpectedKind(PathChooser::ExistingCommand); m_qmlRuntimeLineEdit->setPlaceholderText(hint); m_qmlRuntimeLineEdit->setToolTip(hint); + m_qmlRuntimeLineEdit->setHistoryCompleter("QmlRuntime"); m_sourceProfileCheckBox = new QCheckBox(Tr::tr("Source %1 and %2").arg("/etc/profile").arg("$HOME/.profile")); diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h index e9840c9a436..aba251b969e 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h @@ -9,12 +9,12 @@ QT_BEGIN_NAMESPACE class QCheckBox; class QComboBox; class QLabel; -class QLineEdit; class QRadioButton; class QSpinBox; QT_END_NAMESPACE namespace Utils { +class FancyLineEdit; class FilePath; class PathChooser; } // Utils @@ -53,12 +53,12 @@ private: QRadioButton *m_defaultAuthButton; QLabel *m_keyLabel; QRadioButton *m_keyButton; - QLineEdit *m_hostLineEdit; + Utils::FancyLineEdit *m_hostLineEdit; QSpinBox *m_sshPortSpinBox; QCheckBox *m_hostKeyCheckBox; - QLineEdit *m_portsLineEdit; + Utils::FancyLineEdit *m_portsLineEdit; QLabel *m_portsWarningLabel; - QLineEdit *m_userLineEdit; + Utils::FancyLineEdit *m_userLineEdit; QSpinBox *m_timeoutSpinBox; Utils::PathChooser *m_keyFileLineEdit; QLabel *m_machineTypeValueLabel; From 5cfc52a92c5858e90c650e74c2d84df6705e37a0 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 23 Mar 2023 14:28:39 +0100 Subject: [PATCH 0422/1447] Android/Baremetal: Clean up some header Change-Id: I63a3483a28d9a4ccd21042ae3bd2049598125f5f Reviewed-by: Alessandro Portale --- src/plugins/android/androidplugin.cpp | 2 ++ src/plugins/android/androidruncontrol.h | 6 +----- src/plugins/baremetal/baremetaldebugsupport.cpp | 1 + src/plugins/baremetal/baremetaldebugsupport.h | 5 ++--- .../baremetal/debugservers/gdb/gdbserverprovider.cpp | 2 ++ .../baremetal/debugservers/uvsc/uvscserverprovider.cpp | 1 + 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 0eeb890f821..04e9609b85e 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -50,6 +50,8 @@ #include +#include + using namespace ProjectExplorer; using namespace ProjectExplorer::Constants; diff --git a/src/plugins/android/androidruncontrol.h b/src/plugins/android/androidruncontrol.h index a466de72269..f96c19443b0 100644 --- a/src/plugins/android/androidruncontrol.h +++ b/src/plugins/android/androidruncontrol.h @@ -3,14 +3,10 @@ #pragma once -#include "androidrunner.h" - -#include +#include namespace Android::Internal { -class AndroidRunner; - class AndroidRunWorkerFactory final : public ProjectExplorer::RunWorkerFactory { public: diff --git a/src/plugins/baremetal/baremetaldebugsupport.cpp b/src/plugins/baremetal/baremetaldebugsupport.cpp index db0c376a5ad..c236ab32f24 100644 --- a/src/plugins/baremetal/baremetaldebugsupport.cpp +++ b/src/plugins/baremetal/baremetaldebugsupport.cpp @@ -11,6 +11,7 @@ #include "idebugserverprovider.h" #include +#include #include #include diff --git a/src/plugins/baremetal/baremetaldebugsupport.h b/src/plugins/baremetal/baremetaldebugsupport.h index f0addb4729b..ca16c1ab7ec 100644 --- a/src/plugins/baremetal/baremetaldebugsupport.h +++ b/src/plugins/baremetal/baremetaldebugsupport.h @@ -3,12 +3,11 @@ #pragma once -#include +#include namespace BareMetal::Internal { -class BareMetalDebugSupportFactory final - : public ProjectExplorer::RunWorkerFactory +class BareMetalDebugSupportFactory final : public ProjectExplorer::RunWorkerFactory { public: BareMetalDebugSupportFactory(); diff --git a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp index 336b606d798..222d22ade98 100644 --- a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp index b95c333600d..590c1158866 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include From 463e47bbdd10b33e3be85b47299f1b5d253d8c3e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 07:40:26 +0200 Subject: [PATCH 0423/1447] Debugger: Have a generic "GDB in PATH on Build Device" item This is only checked at run-time, but allows smoother creation of kits for standard setups as the (possibly remote) full path is not needed. Remove the DebuggerKitAspect::fixup() implementation. Too much magic by now, and worst thing that could happen is a non-matching debugger that will clearly bark when used. Change-Id: If2414610d479a5b93c3e6227b8736ddc61f70635 Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggeritemmanager.cpp | 28 +++++- .../debugger/debuggerkitinformation.cpp | 94 ++++--------------- src/plugins/debugger/debuggerkitinformation.h | 1 - src/plugins/remotelinux/linuxdevice.cpp | 2 +- 4 files changed, 44 insertions(+), 81 deletions(-) diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index b3792554168..3e77bf73bf2 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -170,6 +170,7 @@ class DebuggerItemModel : public TreeModelappendChild( - new StaticTreeItem({ProjectExplorer::Constants::msgAutoDetected()}, - {ProjectExplorer::Constants::msgAutoDetectedToolTip()})); + + auto generic = new StaticTreeItem(Tr::tr("Generic")); + auto autoDetected = new StaticTreeItem({ProjectExplorer::Constants::msgAutoDetected()}, + {ProjectExplorer::Constants::msgAutoDetectedToolTip()}); + rootItem()->appendChild(generic); + rootItem()->appendChild(autoDetected); rootItem()->appendChild(new StaticTreeItem(ProjectExplorer::Constants::msgManual())); + + DebuggerItem genericGdb(QVariant("gdb")); + genericGdb.setAutoDetected(true); + genericGdb.setEngineType(GdbEngineType); + genericGdb.setAbi(Abi()); + genericGdb.setCommand("gdb"); + genericGdb.setUnexpandedDisplayName(Tr::tr("%1 from PATH on Build Device").arg("GDB")); + generic->appendChild(new DebuggerTreeItem(genericGdb, false)); + + DebuggerItem genericLldb(QVariant("lldb")); + genericLldb.setAutoDetected(true); + genericLldb.setEngineType(LldbEngineType); + genericLldb.setAbi(Abi()); + genericLldb.setCommand("lldb"); + genericLldb.setUnexpandedDisplayName(Tr::tr("%1 from PATH on Build Device").arg("LLDB")); + generic->appendChild(new DebuggerTreeItem(genericLldb, false)); } void DebuggerItemModel::addDebugger(const DebuggerItem &item, bool changed) { QTC_ASSERT(item.id().isValid(), return); - int group = item.isAutoDetected() ? 0 : 1; + int group = item.isAutoDetected() ? AutoDetected : Manual; rootItem()->childAt(group)->appendChild(new DebuggerTreeItem(item, changed)); } diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index cac42d5a425..f3d01a1cc37 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -228,66 +228,6 @@ void DebuggerKitAspect::setup(Kit *k) k->setValue(DebuggerKitAspect::id(), bestLevel != DebuggerItem::DoesNotMatch ? bestItem.id() : QVariant()); } - -// This handles the upgrade path from 2.8 to 3.0 -void DebuggerKitAspect::fix(Kit *k) -{ - QTC_ASSERT(k, return); - - // This can be Id, binary path, but not "auto" anymore. - const QVariant rawId = k->value(DebuggerKitAspect::id()); - - if (rawId.toString().isEmpty()) // No debugger set, that is fine. - return; - - if (rawId.type() == QVariant::String) { - const DebuggerItem * const item = DebuggerItemManager::findById(rawId); - if (!item) { - qWarning("Unknown debugger id %s in kit %s", - qPrintable(rawId.toString()), qPrintable(k->displayName())); - k->setValue(DebuggerKitAspect::id(), QVariant()); - setup(k); - return; - } - - Abi kitAbi; - if (ToolChainKitAspect::toolChains(k).isEmpty()) { - if (DeviceTypeKitAspect::deviceTypeId(k) - != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { - return; - } - kitAbi = Abi(Abi::UnknownArchitecture, Abi::hostAbi().os()); - } else { - kitAbi = ToolChainKitAspect::targetAbi(k); - } - if (item->matchTarget(kitAbi) != DebuggerItem::DoesNotMatch) - return; - k->setValue(DebuggerKitAspect::id(), QVariant()); - setup(k); - return; // All fine (now). - } - - QMap map = rawId.toMap(); - QString binary = map.value("Binary").toString(); - if (binary == "auto") { - // This should not happen as "auto" is handled by setup() already. - QTC_CHECK(false); - k->setValue(DebuggerKitAspect::id(), QVariant()); - return; - } - - FilePath fileName = FilePath::fromUserInput(binary); - const DebuggerItem *item = DebuggerItemManager::findByCommand(fileName); - if (!item) { - qWarning("Debugger command %s invalid in kit %s", - qPrintable(binary), qPrintable(k->displayName())); - k->setValue(DebuggerKitAspect::id(), QVariant()); - return; - } - - k->setValue(DebuggerKitAspect::id(), item->id()); -} - // Check the configuration errors and return a flag mask. Provide a quick check and // a verbose one with a list of errors. @@ -299,15 +239,15 @@ DebuggerKitAspect::ConfigurationErrors DebuggerKitAspect::configurationErrors(co if (!item) return NoDebugger; - if (item->command().isEmpty()) + const FilePath debugger = item->command(); + if (debugger.isEmpty()) return NoDebugger; + if (debugger.isRelativePath()) + return NoConfigurationError; + ConfigurationErrors result = NoConfigurationError; - const FilePath debugger = item->command(); - const bool found = debugger.exists() && !debugger.isDir(); - if (!found) - result |= DebuggerNotFound; - else if (!debugger.isExecutableFile()) + if (!debugger.isExecutableFile()) result |= DebuggerNotExecutable; const Abi tcAbi = ToolChainKitAspect::targetAbi(k); @@ -318,16 +258,15 @@ DebuggerKitAspect::ConfigurationErrors DebuggerKitAspect::configurationErrors(co result |= DebuggerDoesNotMatch; } - if (!found) { - if (item->engineType() == NoEngineType) - return NoDebugger; + if (item->engineType() == NoEngineType) + return NoDebugger; - // We need an absolute path to be able to locate Python on Windows. - if (item->engineType() == GdbEngineType) { - if (tcAbi.os() == Abi::WindowsOS && !debugger.isAbsolutePath()) - result |= DebuggerNeedsAbsolutePath; - } + // We need an absolute path to be able to locate Python on Windows. + if (item->engineType() == GdbEngineType) { + if (tcAbi.os() == Abi::WindowsOS && !debugger.isAbsolutePath()) + result |= DebuggerNeedsAbsolutePath; } + return result; } @@ -342,7 +281,12 @@ Runnable DebuggerKitAspect::runnable(const Kit *kit) { Runnable runnable; if (const DebuggerItem *item = debugger(kit)) { - runnable.command = CommandLine{item->command()}; + FilePath cmd = item->command(); + if (cmd.isRelativePath()) { + if (const IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit)) + cmd = buildDevice->searchExecutableInPath(cmd.path()); + } + runnable.command.setExecutable(cmd); runnable.workingDirectory = item->workingDirectory(); runnable.environment = kit->runEnvironment(); runnable.environment.set("LC_NUMERIC", "C"); diff --git a/src/plugins/debugger/debuggerkitinformation.h b/src/plugins/debugger/debuggerkitinformation.h index eb6ad1d58aa..548f76793bb 100644 --- a/src/plugins/debugger/debuggerkitinformation.h +++ b/src/plugins/debugger/debuggerkitinformation.h @@ -21,7 +21,6 @@ public: { return DebuggerKitAspect::validateDebugger(k); } void setup(ProjectExplorer::Kit *k) override; - void fix(ProjectExplorer::Kit *k) override; static const DebuggerItem *debugger(const ProjectExplorer::Kit *kit); static ProjectExplorer::Runnable runnable(const ProjectExplorer::Kit *kit); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index d70ca77295c..e8b7d30eecd 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -339,7 +339,7 @@ Environment LinuxDevicePrivate::getEnvironment() return m_environmentCache.value(); QtcProcess getEnvProc; - getEnvProc.setCommand({FilePath("env").onDevice(q->rootPath()), {}}); + getEnvProc.setCommand({q->filePath("env"), {}}); getEnvProc.runBlocking(); const QString remoteOutput = getEnvProc.cleanedStdOut(); From cf138ad909bcf0d51bff08b94cad3955ae6007a8 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 18:22:58 +0200 Subject: [PATCH 0424/1447] Debugger: Small corrections to "Generic" item handling Change-Id: Idd8f6a64aa64b8f13e713b3337ad1f8f2b8735db Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggeritem.cpp | 17 +++- src/plugins/debugger/debuggeritem.h | 5 +- src/plugins/debugger/debuggeritemmanager.cpp | 92 +++++++++++++------- 3 files changed, 81 insertions(+), 33 deletions(-) diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index a7205d34a1c..0769d293dee 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -116,6 +116,9 @@ void DebuggerItem::createId() void DebuggerItem::reinitializeFromFile(QString *error, Utils::Environment *customEnv) { + if (isGeneric()) + return; + // CDB only understands the single-dash -version, whereas GDB and LLDB are // happy with both -version and --version. So use the "working" -version // except for the experimental LLDB-MI which insists on --version. @@ -282,6 +285,16 @@ QString DebuggerItem::engineTypeName() const } } +void DebuggerItem::setGeneric(bool on) +{ + m_detectionSource = on ? QLatin1String("Generic") : QLatin1String(); +} + +bool DebuggerItem::isGeneric() const +{ + return m_detectionSource == "Generic"; +} + QStringList DebuggerItem::abiNames() const { QStringList list; @@ -297,13 +310,15 @@ QDateTime DebuggerItem::lastModified() const QIcon DebuggerItem::decoration() const { + if (isGeneric()) + return {}; if (m_engineType == NoEngineType) return Icons::CRITICAL.icon(); if (!m_command.isExecutableFile()) return Icons::WARNING.icon(); if (!m_workingDirectory.isEmpty() && !m_workingDirectory.isDir()) return Icons::WARNING.icon(); - return QIcon(); + return {}; } QString DebuggerItem::validityMessage() const diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h index 1edaf283ca4..95993665b67 100644 --- a/src/plugins/debugger/debuggeritem.h +++ b/src/plugins/debugger/debuggeritem.h @@ -8,7 +8,7 @@ #include -#include +#include #include #include @@ -84,6 +84,9 @@ public: QString detectionSource() const { return m_detectionSource; } void setDetectionSource(const QString &source) { m_detectionSource = source; } + bool isGeneric() const; + void setGeneric(bool on); + static bool addAndroidLldbPythonEnv(const Utils::FilePath &lldbCmd, Utils::Environment &env); private: diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 3e77bf73bf2..a74ac5071fc 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -92,7 +92,8 @@ static DebuggerItemManagerPrivate *d = nullptr; class DebuggerItemConfigWidget : public QWidget { public: - explicit DebuggerItemConfigWidget(); + DebuggerItemConfigWidget(); + void load(const DebuggerItem *item); void store() const; @@ -104,13 +105,18 @@ private: QLineEdit *m_displayNameLineEdit; QLineEdit *m_typeLineEdit; QLabel *m_cdbLabel; - QLineEdit *m_versionLabel; PathChooser *m_binaryChooser; - PathChooser *m_workingDirectoryChooser; - QLineEdit *m_abis; bool m_autodetected = false; + bool m_generic = false; DebuggerEngineType m_engineType = NoEngineType; QVariant m_id; + + QLabel *m_abisLabel; + QLineEdit *m_abis; + QLabel *m_versionLabel; + QLineEdit *m_version; + QLabel *m_workingDirectoryLabel; + PathChooser *m_workingDirectoryChooser; }; // -------------------------------------------------------------------------- @@ -174,7 +180,7 @@ public: QModelIndex lastIndex() const; void setCurrentIndex(const QModelIndex &index); - void addDebugger(const DebuggerItem &item, bool changed = false); + DebuggerTreeItem *addDebugger(const DebuggerItem &item, bool changed = false); void updateDebugger(const DebuggerItem &item); void apply(); void cancel(); @@ -213,6 +219,7 @@ DebuggerItemModel::DebuggerItemModel() DebuggerItem genericGdb(QVariant("gdb")); genericGdb.setAutoDetected(true); + genericGdb.setGeneric(true); genericGdb.setEngineType(GdbEngineType); genericGdb.setAbi(Abi()); genericGdb.setCommand("gdb"); @@ -222,17 +229,20 @@ DebuggerItemModel::DebuggerItemModel() DebuggerItem genericLldb(QVariant("lldb")); genericLldb.setAutoDetected(true); genericLldb.setEngineType(LldbEngineType); + genericLldb.setGeneric(true); genericLldb.setAbi(Abi()); genericLldb.setCommand("lldb"); genericLldb.setUnexpandedDisplayName(Tr::tr("%1 from PATH on Build Device").arg("LLDB")); generic->appendChild(new DebuggerTreeItem(genericLldb, false)); } -void DebuggerItemModel::addDebugger(const DebuggerItem &item, bool changed) +DebuggerTreeItem *DebuggerItemModel::addDebugger(const DebuggerItem &item, bool changed) { - QTC_ASSERT(item.id().isValid(), return); - int group = item.isAutoDetected() ? AutoDetected : Manual; - rootItem()->childAt(group)->appendChild(new DebuggerTreeItem(item, changed)); + QTC_ASSERT(item.id().isValid(), return {}); + int group = item.isGeneric() ? Generic : (item.isAutoDetected() ? AutoDetected : Manual); + auto treeItem = new DebuggerTreeItem(item, changed); + rootItem()->childAt(group)->appendChild(treeItem); + return treeItem; } void DebuggerItemModel::updateDebugger(const DebuggerItem &item) @@ -321,6 +331,7 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget() }); m_binaryChooser->setAllowPathFromDevice(true); + m_workingDirectoryLabel = new QLabel(Tr::tr("ABIs:")); m_workingDirectoryChooser = new PathChooser(this); m_workingDirectoryChooser->setExpectedKind(PathChooser::Directory); m_workingDirectoryChooser->setMinimumWidth(400); @@ -330,10 +341,12 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget() m_cdbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); m_cdbLabel->setOpenExternalLinks(true); - m_versionLabel = new QLineEdit(this); - m_versionLabel->setPlaceholderText(Tr::tr("Unknown")); - m_versionLabel->setEnabled(false); + m_versionLabel = new QLabel(Tr::tr("Version:")); + m_version = new QLineEdit(this); + m_version->setPlaceholderText(Tr::tr("Unknown")); + m_version->setEnabled(false); + m_abisLabel = new QLabel(Tr::tr("Working directory:")); m_abis = new QLineEdit(this); m_abis->setEnabled(false); @@ -343,9 +356,9 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget() formLayout->addRow(m_cdbLabel); formLayout->addRow(new QLabel(Tr::tr("Path:")), m_binaryChooser); formLayout->addRow(new QLabel(Tr::tr("Type:")), m_typeLineEdit); - formLayout->addRow(new QLabel(Tr::tr("ABIs:")), m_abis); - formLayout->addRow(new QLabel(Tr::tr("Version:")), m_versionLabel); - formLayout->addRow(new QLabel(Tr::tr("Working directory:")), m_workingDirectoryChooser); + formLayout->addRow(m_abisLabel, m_abis); + formLayout->addRow(m_versionLabel, m_version); + formLayout->addRow(m_workingDirectoryLabel, m_workingDirectoryChooser); connect(m_binaryChooser, &PathChooser::textChanged, this, &DebuggerItemConfigWidget::binaryPathHasChanged); @@ -357,21 +370,24 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget() DebuggerItem DebuggerItemConfigWidget::item() const { + static const QRegularExpression noAbi("[^A-Za-z0-9-_]+"); + DebuggerItem item(m_id); item.setUnexpandedDisplayName(m_displayNameLineEdit->text()); item.setCommand(m_binaryChooser->filePath()); item.setWorkingDirectory(m_workingDirectoryChooser->filePath()); item.setAutoDetected(m_autodetected); Abis abiList; - const QStringList abis = m_abis->text().split(QRegularExpression("[^A-Za-z0-9-_]+")); + const QStringList abis = m_abis->text().split(noAbi); for (const QString &a : abis) { if (a.isNull()) continue; abiList << Abi::fromString(a); } item.setAbis(abiList); - item.setVersion(m_versionLabel->text()); + item.setVersion(m_version->text()); item.setEngineType(m_engineType); + item.setGeneric(m_generic); return item; } @@ -393,6 +409,7 @@ void DebuggerItemConfigWidget::load(const DebuggerItem *item) return; // Set values: + m_generic = item->isGeneric(); m_autodetected = item->isAutoDetected(); m_displayNameLineEdit->setEnabled(!item->isAutoDetected()); @@ -402,6 +419,15 @@ void DebuggerItemConfigWidget::load(const DebuggerItem *item) m_binaryChooser->setReadOnly(item->isAutoDetected()); m_binaryChooser->setFilePath(item->command()); + m_binaryChooser->setExpectedKind(m_generic ? PathChooser::Any : PathChooser::ExistingCommand); + + m_abisLabel->setVisible(!m_generic); + m_abis->setVisible(!m_generic); + m_versionLabel->setVisible(!m_generic); + m_version->setVisible(!m_generic); + m_workingDirectoryLabel->setVisible(!m_generic); + m_workingDirectoryChooser->setVisible(!m_generic); + m_workingDirectoryChooser->setReadOnly(item->isAutoDetected()); m_workingDirectoryChooser->setFilePath(item->workingDirectory()); @@ -425,7 +451,7 @@ void DebuggerItemConfigWidget::load(const DebuggerItem *item) m_cdbLabel->setText(text); m_cdbLabel->setVisible(!text.isEmpty()); m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand)); - m_versionLabel->setText(item->version()); + m_version->setText(item->version()); setAbis(item->abiNames()); m_engineType = item->engineType(); m_id = item->id(); @@ -437,16 +463,18 @@ void DebuggerItemConfigWidget::binaryPathHasChanged() if (!m_id.isValid()) return; - DebuggerItem tmp; - if (m_binaryChooser->filePath().isExecutableFile()) { - tmp = item(); - tmp.reinitializeFromFile(); - } + if (!m_generic) { + DebuggerItem tmp; + if (m_binaryChooser->filePath().isExecutableFile()) { + tmp = item(); + tmp.reinitializeFromFile(); + } - setAbis(tmp.abiNames()); - m_versionLabel->setText(tmp.version()); - m_engineType = tmp.engineType(); - m_typeLineEdit->setText(tmp.engineTypeName()); + setAbis(tmp.abiNames()); + m_version->setText(tmp.version()); + m_engineType = tmp.engineType(); + m_typeLineEdit->setText(tmp.engineTypeName()); + } store(); } @@ -554,8 +582,10 @@ void DebuggerConfigWidget::cloneDebugger() newItem.setUnexpandedDisplayName(d->uniqueDisplayName(Tr::tr("Clone of %1").arg(item->displayName()))); newItem.reinitializeFromFile(); newItem.setAutoDetected(false); - d->m_model->addDebugger(newItem, true); - m_debuggerView->setCurrentIndex(d->m_model->lastIndex()); + newItem.setGeneric(item->isGeneric()); + newItem.setEngineType(item->engineType()); + auto addedItem = d->m_model->addDebugger(newItem, true); + m_debuggerView->setCurrentIndex(d->m_model->indexForItem(addedItem)); } void DebuggerConfigWidget::addDebugger() @@ -565,8 +595,8 @@ void DebuggerConfigWidget::addDebugger() item.setEngineType(NoEngineType); item.setUnexpandedDisplayName(d->uniqueDisplayName(Tr::tr("New Debugger"))); item.setAutoDetected(false); - d->m_model->addDebugger(item, true); - m_debuggerView->setCurrentIndex(d->m_model->lastIndex()); + auto addedItem = d->m_model->addDebugger(item, true); + m_debuggerView->setCurrentIndex(d->m_model->indexForItem(addedItem)); } void DebuggerConfigWidget::removeDebugger() From de733a4294b8b411d3f11743babadec7ca43800b Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 28 Mar 2023 18:09:00 +0200 Subject: [PATCH 0425/1447] Utils: Add "pinned small" icon To be used it in pinnable floating dialogs. Change-Id: I379a0422af5b0f5dd4045fcaa8086c642832d641 Reviewed-by: Eike Ziller --- src/libs/utils/images/pinned_small.png | Bin 0 -> 145 bytes src/libs/utils/images/pinned_small@2x.png | Bin 0 -> 233 bytes src/libs/utils/utils.qrc | 2 ++ src/tools/icons/qtcreatoricons.svg | 29 ++++++++++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 src/libs/utils/images/pinned_small.png create mode 100644 src/libs/utils/images/pinned_small@2x.png diff --git a/src/libs/utils/images/pinned_small.png b/src/libs/utils/images/pinned_small.png new file mode 100644 index 0000000000000000000000000000000000000000..10f96f3095410df491e52caaf81eb94c5703d50b GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yVBi5^4h9AWhGIEpYX$~}2u~Ns5RT~NAN?#63Rmv_ zs^>W8-FT;7;9URpa9#=4J<5mq^V!1T+A#DUmaBKG&XKo zX=tEu@<7Rz!>*D&6%x}FZZb|6tg6}ZM}E^&*?>;b7w2lV`NaGkzdsQ7W}DD+OWdS$ z{yQGA{Kjuv7Pel!U%>WVUqO7s8uzIu(mDR{l{Nmc73q{}^T}9I=U|w{Qn|OOLua!pe*cS9aYnvklis1o^?!)z4*}Q$iB}N8?vo literal 0 HcmV?d00001 diff --git a/src/libs/utils/utils.qrc b/src/libs/utils/utils.qrc index 20f6d7c788b..c0f2d2559a1 100644 --- a/src/libs/utils/utils.qrc +++ b/src/libs/utils/utils.qrc @@ -36,6 +36,8 @@ images/unlocked@2x.png images/pinned.png images/pinned@2x.png + images/pinned_small.png + images/pinned_small@2x.png images/broken.png images/broken@2x.png images/notloaded.png diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 4ec2b2bb145..015498217bf 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -653,6 +653,14 @@ width="100%" height="100%" transform="matrix(1.5,0,0,1.5,0,-242)" /> + + + + + + + Date: Mon, 27 Mar 2023 12:00:13 +0200 Subject: [PATCH 0426/1447] Do not automatically reset progress details position Add a "pin" button that appears on hover if the details have been dragged around. Clicking on it resets the position. Position is also reset when hiding & re-showing the details with the button. And the details snap to the original position when dragged near it. Fixes: QTCREATORBUG-28829 Change-Id: I6a6f13ca1baac79951c20f2e8edf6fac137a8cfc Reviewed-by: Alessandro Portale Reviewed-by: --- .../progressmanager/progressview.cpp | 42 ++++++++++++++++++- .../coreplugin/progressmanager/progressview.h | 1 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/progressmanager/progressview.cpp b/src/plugins/coreplugin/progressmanager/progressview.cpp index 498ec8ae7b0..45b10286dc4 100644 --- a/src/plugins/coreplugin/progressmanager/progressview.cpp +++ b/src/plugins/coreplugin/progressmanager/progressview.cpp @@ -5,11 +5,19 @@ #include "../coreplugintr.h" +#include +#include + #include #include #include +#include #include +using namespace Utils; + +const int PIN_SIZE = 12; + namespace Core::Internal { ProgressView::ProgressView(QWidget *parent) @@ -21,15 +29,29 @@ ProgressView::ProgressView(QWidget *parent) m_layout->setSpacing(0); m_layout->setSizeConstraint(QLayout::SetFixedSize); setWindowTitle(Tr::tr("Processes")); + + auto pinButton = new OverlayWidget(this); + pinButton->attachToWidget(this); + pinButton->setAttribute(Qt::WA_TransparentForMouseEvents, false); // override OverlayWidget + pinButton->setPaintFunction([](QWidget *that, QPainter &p, QPaintEvent *) { + static const QIcon icon = Icon({{":/utils/images/pinned_small.png", Theme::IconsBaseColor}}, + Icon::Tint) + .icon(); + QRect iconRect(0, 0, PIN_SIZE, PIN_SIZE); + iconRect.moveTopRight(that->rect().topRight()); + icon.paint(&p, iconRect); + }); + pinButton->setVisible(false); + pinButton->installEventFilter(this); + m_pinButton = pinButton; } ProgressView::~ProgressView() = default; void ProgressView::addProgressWidget(QWidget *widget) { - if (m_layout->count() == 0) - m_anchorBottomRight = {}; // reset temporarily user-moved progress details m_layout->insertWidget(0, widget); + m_pinButton->raise(); } void ProgressView::removeProgressWidget(QWidget *widget) @@ -63,9 +85,12 @@ bool ProgressView::event(QEvent *event) reposition(); } else if (event->type() == QEvent::Enter) { m_hovered = true; + if (m_anchorBottomRight != QPoint()) + m_pinButton->setVisible(true); emit hoveredChanged(m_hovered); } else if (event->type() == QEvent::Leave) { m_hovered = false; + m_pinButton->setVisible(false); emit hoveredChanged(m_hovered); } else if (event->type() == QEvent::Show) { m_anchorBottomRight = {}; // reset temporarily user-moved progress details @@ -78,6 +103,16 @@ bool ProgressView::eventFilter(QObject *obj, QEvent *event) { if ((obj == parentWidget() || obj == m_referenceWidget) && event->type() == QEvent::Resize) reposition(); + if (obj == m_pinButton && event->type() == QEvent::MouseButtonRelease) { + auto me = static_cast(event); + if (me->button() == Qt::LeftButton + && QRectF(m_pinButton->width() - PIN_SIZE, 0, PIN_SIZE, PIN_SIZE) + .contains(me->position())) { + me->accept(); + m_anchorBottomRight = {}; + reposition(); + } + } return false; } @@ -133,6 +168,9 @@ void ProgressView::reposition() { if (!parentWidget() || !m_referenceWidget) return; + + m_pinButton->setVisible(m_anchorBottomRight != QPoint() && m_hovered); + move(boundedInParent(this, topRightReferenceInParent() + m_anchorBottomRight, parentWidget()) - rect().bottomRight()); } diff --git a/src/plugins/coreplugin/progressmanager/progressview.h b/src/plugins/coreplugin/progressmanager/progressview.h index 37cfa248265..e0b42c8547e 100644 --- a/src/plugins/coreplugin/progressmanager/progressview.h +++ b/src/plugins/coreplugin/progressmanager/progressview.h @@ -44,6 +44,7 @@ private: QVBoxLayout *m_layout; QWidget *m_referenceWidget = nullptr; + QWidget *m_pinButton = nullptr; // dragging std::optional m_clickPosition; From 0fb635e76c294b37caebdbd081a44de7c0dc094d Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 10:27:00 +0200 Subject: [PATCH 0427/1447] Docker: Fix Shell destruction handling Change-Id: I125ac2eaf99e8dff85da06640f048b502f36fa08 Reviewed-by: hjk Reviewed-by: --- src/plugins/docker/dockerdevice.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 5c543dfc3a8..f1b650268e5 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -528,7 +528,14 @@ void DockerDevicePrivate::stopCurrentContainer() if (!DockerApi::isDockerDaemonAvailable(false).value_or(false)) return; - m_shell.reset(); + if (m_shell) { + // We have to disconnect the shell from the device, otherwise it will try to + // tell us about the container being stopped. Since that signal is emitted in a different + // thread, it would be delayed received by us when we might already have started + // a new shell. + m_shell->disconnect(this); + m_shell.reset(); + } QtcProcess proc; proc.setCommand({m_settings->dockerBinaryPath.filePath(), {"container", "stop", m_container}}); From 1ee46580ac8afda64e63b3dd816b4acbfad5dfaa Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 11:48:39 +0200 Subject: [PATCH 0428/1447] RemoteLinux: Simplify display of make install command Including proper quoting. Change-Id: I49fd85b5cfc9d035d3b63fe1c7cef40247d8742c Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/remotelinux/makeinstallstep.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index 83bed3a74cc..79c42bdf107 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -249,11 +249,8 @@ void MakeInstallStep::updateArgsFromAspect() void MakeInstallStep::updateFullCommandLine() { - // FIXME: Only executable? - static_cast(aspect(FullCommandLineAspectId))->setValue( - QDir::toNativeSeparators( - ProcessArgs::quoteArg(makeExecutable().toString())) - + ' ' + userArguments()); + CommandLine cmd{makeExecutable(), userArguments(), CommandLine::Raw}; + static_cast(aspect(FullCommandLineAspectId))->setValue(cmd.toUserOutput()); } void MakeInstallStep::updateFromCustomCommandLineAspect() From 8a1e34f084f24f45d61e0011a2b6486aadc34218 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 27 Mar 2023 07:28:48 +0200 Subject: [PATCH 0429/1447] TextEditor: introduce text suggestion interface And also a copilot suggestion implementing that interface that allows reverting all changes done to a suggestion as well as applying it. Change-Id: I236c1fc5e5844d19ac606672af54e273e9c42e1c Reviewed-by: Marcus Tillmanns --- src/libs/languageserverprotocol/lsptypes.cpp | 10 ++ src/libs/languageserverprotocol/lsptypes.h | 2 + src/libs/languageserverprotocol/lsputils.h | 7 ++ src/plugins/copilot/copilotclient.cpp | 46 ++++++-- src/plugins/texteditor/textdocument.cpp | 15 +-- src/plugins/texteditor/textdocument.h | 2 + src/plugins/texteditor/textdocumentlayout.cpp | 90 +++++++------- src/plugins/texteditor/textdocumentlayout.h | 40 ++++--- src/plugins/texteditor/texteditor.cpp | 110 ++++++++---------- src/plugins/texteditor/texteditor.h | 15 +-- 10 files changed, 190 insertions(+), 147 deletions(-) diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp index 4bf3f3746e2..bd7798dcef9 100644 --- a/src/libs/languageserverprotocol/lsptypes.cpp +++ b/src/libs/languageserverprotocol/lsptypes.cpp @@ -311,6 +311,16 @@ bool Range::overlaps(const Range &range) const return !isLeftOf(range) && !range.isLeftOf(*this); } +QTextCursor Range::toSelection(QTextDocument *doc) const +{ + QTC_ASSERT(doc, return {}); + if (!isValid()) + return {}; + QTextCursor cursor = start().toTextCursor(doc); + cursor.setPosition(end().toPositionInDocument(doc), QTextCursor::KeepAnchor); + return cursor; +} + QString expressionForGlob(QString globPattern) { const QString anySubDir("qtc_anysubdir_id"); diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index 4adc35aa105..3a9adb1b0d8 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -117,6 +117,8 @@ public: bool isLeftOf(const Range &other) const { return isEmpty() || other.isEmpty() ? end() < other.start() : end() <= other.start(); } + QTextCursor toSelection(QTextDocument *doc) const; + bool isValid() const override { return JsonObject::contains(startKey) && JsonObject::contains(endKey); } }; diff --git a/src/libs/languageserverprotocol/lsputils.h b/src/libs/languageserverprotocol/lsputils.h index 5515b515767..0c815bafd8a 100644 --- a/src/libs/languageserverprotocol/lsputils.h +++ b/src/libs/languageserverprotocol/lsputils.h @@ -87,6 +87,13 @@ public: return QJsonValue(); } + QList toListOrEmpty() const + { + if (std::holds_alternative>(*this)) + return std::get>(*this); + return {}; + } + QList toList() const { QTC_ASSERT(std::holds_alternative>(*this), return {}); diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index d245e68eaa3..27bcbacf476 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -128,6 +129,39 @@ void CopilotClient::requestCompletions(TextEditorWidget *editor) sendMessage(request); } +class CopilotSuggestion final : public TextEditor::TextSuggestion +{ +public: + CopilotSuggestion(const Completion &completion, QTextDocument *origin) + : m_completion(completion) + { + document()->setPlainText(completion.text()); + m_start = completion.position().toTextCursor(origin); + m_start.setKeepPositionOnInsert(true); + setCurrentPosition(m_start.position()); + } + + bool apply() final + { + reset(); + QTextCursor cursor = m_completion.range().toSelection(m_start.document()); + cursor.insertText(m_completion.text()); + return true; + } + void reset() final + { + m_start.removeSelectedText(); + } + int position() final + { + return m_start.position(); + } + +private: + Completion m_completion; + QTextCursor m_start; +}; + void CopilotClient::handleCompletions(const GetCompletionRequest::Response &response, TextEditorWidget *editor) { @@ -142,19 +176,15 @@ void CopilotClient::handleCompletions(const GetCompletionRequest::Response &resp if (cursors.hasMultipleCursors()) return; - const QTextCursor cursor = cursors.mainCursor(); if (cursors.hasSelection() || cursors.mainCursor().position() != requestPosition) return; if (const std::optional result = response.result()) { - LanguageClientArray completions = result->completions(); - if (completions.isNull() || completions.toList().isEmpty()) + QList completions = result->completions().toListOrEmpty(); + if (completions.isEmpty()) return; - - const Completion firstCompletion = completions.toList().first(); - const QString content = firstCompletion.text().mid(firstCompletion.position().character()); - - editor->insertSuggestion(content); + editor->insertSuggestion( + std::make_unique(completions.first(), editor->document())); } } diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 966edd4e7d8..4a7e80f52ce 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -373,16 +373,13 @@ QAction *TextDocument::createDiffAgainstCurrentFileAction( return diffAction; } -void TextDocument::insertSuggestion(const QString &text, const QTextCursor &cursor) +void TextDocument::insertSuggestion(std::unique_ptr &&suggestion) { + QTextCursor cursor(&d->m_document); + cursor.setPosition(suggestion->position()); const QTextBlock block = cursor.block(); - const QString blockText = block.text(); - QString replacement = blockText.left(cursor.positionInBlock()) + text; - if (!text.contains('\n')) - replacement.append(blockText.mid(cursor.positionInBlock())); - TextDocumentLayout::userData(block)->setReplacement(replacement); - TextDocumentLayout::userData(block)->setReplacementPosition(cursor.positionInBlock()); - TextDocumentLayout::updateReplacementFormats(block, fontSettings()); + TextDocumentLayout::userData(block)->insertSuggestion(std::move(suggestion)); + TextDocumentLayout::updateSuggestionFormats(block, fontSettings()); updateLayout(); } @@ -434,7 +431,7 @@ void TextDocument::applyFontSettings() d->m_fontSettingsNeedsApply = false; QTextBlock block = document()->firstBlock(); while (block.isValid()) { - TextDocumentLayout::updateReplacementFormats(block, fontSettings()); + TextDocumentLayout::updateSuggestionFormats(block, fontSettings()); block = block.next(); } updateLayout(); diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 9ef556503fd..d1f686f6a0c 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -37,6 +37,7 @@ class SyntaxHighlighter; class TabSettings; class TextDocumentPrivate; class TextMark; +class TextSuggestion; class TypingSettings; using TextMarks = QList; @@ -145,6 +146,7 @@ public: const std::function &filePath); void insertSuggestion(const QString &text, const QTextCursor &cursor); + void insertSuggestion(std::unique_ptr &&suggestion); #ifdef WITH_TESTS void setSilentReload(); diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index 9c257d3a257..a80a1b77515 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -345,22 +345,19 @@ void TextBlockUserData::setCodeFormatterData(CodeFormatterData *data) m_codeFormatterData = data; } -void TextBlockUserData::setReplacement(const QString &replacement) +void TextBlockUserData::insertSuggestion(std::unique_ptr &&suggestion) { - m_replacement.reset(new QTextDocument(replacement)); - m_replacement->setDocumentLayout(new TextDocumentLayout(m_replacement.get())); - m_replacement->setDocumentMargin(0); + m_suggestion = std::move(suggestion); } -void TextBlockUserData::setReplacementPosition(int replacementPosition) +TextSuggestion *TextBlockUserData::suggestion() const { - m_replacementPosition = replacementPosition; + return m_suggestion.get(); } -void TextBlockUserData::clearReplacement() +void TextBlockUserData::clearSuggestion() { - m_replacement.reset(); - m_replacementPosition = -1; + m_suggestion.release(); } void TextBlockUserData::addMark(TextMark *mark) @@ -536,21 +533,29 @@ QByteArray TextDocumentLayout::expectedRawStringSuffix(const QTextBlock &block) return {}; } -void TextDocumentLayout::updateReplacementFormats(const QTextBlock &block, +TextSuggestion *TextDocumentLayout::suggestion(const QTextBlock &block) +{ + if (TextBlockUserData *userData = textUserData(block)) + return userData->suggestion(); + return nullptr; +} + +void TextDocumentLayout::updateSuggestionFormats(const QTextBlock &block, const FontSettings &fontSettings) { - if (QTextDocument *replacement = replacementDocument(block)) { + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) { + QTextDocument *suggestionDoc = suggestion->document(); const QTextCharFormat replacementFormat = fontSettings.toTextCharFormat( TextStyles{C_TEXT, {C_DISABLED_CODE}}); QList formats = block.layout()->formats(); - QTextCursor cursor(replacement); + QTextCursor cursor(suggestionDoc); cursor.select(QTextCursor::Document); cursor.setCharFormat(fontSettings.toTextCharFormat(C_TEXT)); - const int position = replacementPosition(block); + const int position = suggestion->currentPosition() - block.position(); cursor.setPosition(position); const QString trailingText = block.text().mid(position); if (!trailingText.isEmpty()) { - const int trailingIndex = replacement->firstBlock().text().indexOf(trailingText, + const int trailingIndex = suggestionDoc->firstBlock().text().indexOf(trailingText, position); if (trailingIndex >= 0) { cursor.setPosition(trailingIndex, QTextCursor::KeepAnchor); @@ -581,45 +586,22 @@ void TextDocumentLayout::updateReplacementFormats(const QTextBlock &block, } cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.setCharFormat(replacementFormat); - replacement->firstBlock().layout()->setFormats(formats); + suggestionDoc->firstBlock().layout()->setFormats(formats); } } -QString TextDocumentLayout::replacement(const QTextBlock &block) +bool TextDocumentLayout::updateSuggestion(const QTextBlock &block, + int position, + const FontSettings &fontSettings) { - if (QTextDocument *replacement = replacementDocument(block)) { - QTextCursor cursor(replacement); - const int position = replacementPosition(block); - cursor.setPosition(position); - cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); - return cursor.selectedText(); - } - return {}; -} - -QTextDocument *TextDocumentLayout::replacementDocument(const QTextBlock &block) -{ - TextBlockUserData *userData = textUserData(block); - return userData ? userData->replacement() : nullptr; -} - -int TextDocumentLayout::replacementPosition(const QTextBlock &block) -{ - TextBlockUserData *userData = textUserData(block); - return userData ? userData->replacementPosition() : -1; -} - -bool TextDocumentLayout::updateReplacement(const QTextBlock &block, - int position, - const FontSettings &fontSettings) -{ - if (QTextDocument *replacementDocument = TextDocumentLayout::replacementDocument(block)) { - const QString start = block.text().left(position); - const QString end = block.text().mid(position); - const QString replacement = replacementDocument->firstBlock().text(); - if (replacement.startsWith(start) && replacement.endsWith(end)) { - userData(block)->setReplacementPosition(position); - TextDocumentLayout::updateReplacementFormats(block, fontSettings); + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) { + auto positionInBlock = position - block.position(); + const QString start = block.text().left(positionInBlock); + const QString end = block.text().mid(positionInBlock); + const QString replacement = suggestion->document()->firstBlock().text(); + if (replacement.startsWith(start) && replacement.indexOf(end, start.size()) >= 0) { + suggestion->setCurrentPosition(position); + TextDocumentLayout::updateSuggestionFormats(block, fontSettings); return true; } } @@ -756,11 +738,11 @@ static QRectF replacementBoundingRect(const QTextDocument *replacement) QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const { - if (QTextDocument *replacement = replacementDocument(block)) { + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) { // since multiple code paths expects that we have a valid block layout after requesting the // block bounding rect explicitly create that layout here ensureBlockLayout(block); - return replacementBoundingRect(replacement); + return replacementBoundingRect(suggestion->document()); } QRectF boundingRect = QPlainTextDocumentLayout::blockBoundingRect(block); @@ -851,4 +833,10 @@ void insertSorted(Parentheses &list, const Parenthesis &elem) list.insert(it, elem); } +TextSuggestion::TextSuggestion() +{ + m_replacementDocument.setDocumentLayout(new TextDocumentLayout(&m_replacementDocument)); + m_replacementDocument.setDocumentMargin(0); +} + } // namespace TextEditor diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 97fa5992abb..e02615b1063 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -42,6 +42,24 @@ public: virtual ~CodeFormatterData(); }; +class TEXTEDITOR_EXPORT TextSuggestion +{ +public: + TextSuggestion(); + virtual bool apply() = 0; + virtual void reset() = 0; + virtual int position() = 0; + + int currentPosition() const { return m_currentPosition; } + void setCurrentPosition(int position) { m_currentPosition = position; } + + QTextDocument *document() { return &m_replacementDocument; } + +private: + QTextDocument m_replacementDocument; + int m_currentPosition = -1; +}; + class TEXTEDITOR_EXPORT TextBlockUserData : public QTextBlockUserData { public: @@ -126,11 +144,9 @@ public: QByteArray expectedRawStringSuffix() { return m_expectedRawStringSuffix; } void setExpectedRawStringSuffix(const QByteArray &suffix) { m_expectedRawStringSuffix = suffix; } - void setReplacement(const QString &replacement); - void setReplacementPosition(int replacementPosition); - void clearReplacement(); - QTextDocument *replacement() const { return m_replacement.get(); } - int replacementPosition() const { return m_replacementPosition; } + void insertSuggestion(std::unique_ptr &&suggestion); + TextSuggestion *suggestion() const; + void clearSuggestion(); private: TextMarks m_marks; @@ -146,7 +162,7 @@ private: KSyntaxHighlighting::State m_syntaxState; QByteArray m_expectedRawStringSuffix; // A bit C++-specific, but let's be pragmatic. std::unique_ptr m_replacement; - int m_replacementPosition = -1; + std::unique_ptr m_suggestion; }; @@ -180,14 +196,12 @@ public: static void setFolded(const QTextBlock &block, bool folded); static void setExpectedRawStringSuffix(const QTextBlock &block, const QByteArray &suffix); static QByteArray expectedRawStringSuffix(const QTextBlock &block); - static void updateReplacementFormats(const QTextBlock &block, + static TextSuggestion *suggestion(const QTextBlock &block); + static void updateSuggestionFormats(const QTextBlock &block, const FontSettings &fontSettings); - static QString replacement(const QTextBlock &block); - static QTextDocument *replacementDocument(const QTextBlock &block); - static int replacementPosition(const QTextBlock &block); - static bool updateReplacement(const QTextBlock &block, - int position, - const FontSettings &fontSettings); + static bool updateSuggestion(const QTextBlock &block, + int position, + const FontSettings &fontSettings); class TEXTEDITOR_EXPORT FoldValidator { diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index ccbdb0467d0..c5783acb919 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -820,7 +820,7 @@ public: QList m_visualIndentCache; int m_visualIndentOffset = 0; - void insertSuggestion(const QString &suggestion); + void insertSuggestion(std::unique_ptr &&suggestion); void updateSuggestion(); void clearCurrentSuggestion(); QTextBlock m_suggestionBlock; @@ -1651,12 +1651,13 @@ void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperatio q->setMultiTextCursor(MultiTextCursor(cursors)); } -void TextEditorWidgetPrivate::insertSuggestion(const QString &suggestion) +void TextEditorWidgetPrivate::insertSuggestion(std::unique_ptr &&suggestion) { clearCurrentSuggestion(); auto cursor = q->textCursor(); + cursor.setPosition(suggestion->position()); m_suggestionBlock = cursor.block(); - m_document->insertSuggestion(suggestion, cursor); + m_document->insertSuggestion(std::move(suggestion)); } void TextEditorWidgetPrivate::updateSuggestion() @@ -1666,10 +1667,9 @@ void TextEditorWidgetPrivate::updateSuggestion() if (m_cursors.mainCursor().block() != m_suggestionBlock) { clearCurrentSuggestion(); } else { - const int position = m_cursors.mainCursor().position() - m_suggestionBlock.position(); - if (!TextDocumentLayout::updateReplacement(m_suggestionBlock, - position, - m_document->fontSettings())) { + if (!TextDocumentLayout::updateSuggestion(m_suggestionBlock, + m_cursors.mainCursor().position(), + m_document->fontSettings())) { clearCurrentSuggestion(); } } @@ -1678,7 +1678,7 @@ void TextEditorWidgetPrivate::updateSuggestion() void TextEditorWidgetPrivate::clearCurrentSuggestion() { if (TextBlockUserData *userData = TextDocumentLayout::textUserData(m_suggestionBlock)) { - userData->clearReplacement(); + userData->clearSuggestion(); m_document->updateLayout(); } m_suggestionBlock = QTextBlock(); @@ -2689,25 +2689,18 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) case Qt::Key_Tab: case Qt::Key_Backtab: { if (ro) break; - if (d->m_suggestionBlock.isValid()) { - const int position = TextDocumentLayout::replacementPosition(d->m_suggestionBlock); - if (position >= 0) { - QTextCursor cursor(d->m_suggestionBlock); - cursor.setPosition(d->m_suggestionBlock.position() + position); - cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); - cursor.insertText(TextDocumentLayout::replacement(d->m_suggestionBlock)); - setTextCursor(cursor); - } - d->clearCurrentSuggestion(); - e->accept(); - return; - } if (d->m_snippetOverlay->isVisible() && !d->m_snippetOverlay->isEmpty()) { d->snippetTabOrBacktab(e->key() == Qt::Key_Tab); e->accept(); return; } QTextCursor cursor = textCursor(); + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(d->m_suggestionBlock)) { + suggestion->apply(); + d->clearCurrentSuggestion(); + e->accept(); + return; + } if (d->m_skipAutoCompletedText && e->key() == Qt::Key_Tab) { bool skippedAutoCompletedText = false; while (!d->m_autoCompleteHighlightPos.isEmpty() @@ -4067,10 +4060,10 @@ static TextMarks availableMarks(const TextMarks &marks, QRectF TextEditorWidgetPrivate::getLastLineLineRect(const QTextBlock &block) { QTextLayout *layout = nullptr; - if (block != m_suggestionBlock) + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) + layout = suggestion->document()->firstBlock().layout(); + else layout = block.layout(); - else if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(block)) - layout = replacement->firstBlock().layout(); QTC_ASSERT(layout, layout = block.layout()); const int lineCount = layout->lineCount(); @@ -4467,18 +4460,18 @@ void TextEditorWidgetPrivate::paintAdditionalVisualWhitespaces(PaintEventData &d visualArrow); } if (!nextBlockIsValid) { // paint EOF symbol - if (m_suggestionBlock.isValid() && data.block == m_suggestionBlock) { - if (QTextDocument *replacement = TextDocumentLayout::replacementDocument( - m_suggestionBlock)) { - const QTextBlock lastReplacementBlock = replacement->lastBlock(); - for (QTextBlock block = replacement->firstBlock(); - block != lastReplacementBlock && block.isValid(); - block = block.next()) { - top += replacement->documentLayout()->blockBoundingRect(block).height(); - } - layout = lastReplacementBlock.layout(); - lineCount = layout->lineCount(); + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(data.block)) { + const QTextBlock lastReplacementBlock = suggestion->document()->lastBlock(); + for (QTextBlock block = suggestion->document()->firstBlock(); + block != lastReplacementBlock && block.isValid(); + block = block.next()) { + top += suggestion->document() + ->documentLayout() + ->blockBoundingRect(block) + .height(); } + layout = lastReplacementBlock.layout(); + lineCount = layout->lineCount(); } QTextLine line = layout->lineAt(lineCount - 1); QRectF lineRect = line.naturalTextRect().translated(data.offset.x(), top); @@ -4739,17 +4732,14 @@ void TextEditorWidgetPrivate::setupSelections(const PaintEventData &data, int deltaPos = -1; int delta = 0; - if (m_suggestionBlock == data.block) { - if (QTextDocument *replacement = TextDocumentLayout::replacementDocument( - m_suggestionBlock)) { - deltaPos = TextDocumentLayout::replacementPosition(data.block); - const QString trailingText = data.block.text().mid(deltaPos); - if (!trailingText.isEmpty()) { - const int trailingIndex = replacement->firstBlock().text().indexOf(trailingText, - deltaPos); - if (trailingIndex >= 0) - delta = std::max(trailingIndex - deltaPos, 0); - } + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(data.block)) { + deltaPos = suggestion->currentPosition() - data.block.position(); + const QString trailingText = data.block.text().mid(deltaPos); + if (!trailingText.isEmpty()) { + const int trailingIndex + = suggestion->document()->firstBlock().text().indexOf(trailingText, deltaPos); + if (trailingIndex >= 0) + delta = std::max(trailingIndex - deltaPos, 0); } } @@ -4994,21 +4984,23 @@ void TextEditorWidget::paintBlock(QPainter *painter, const QVector &selections, const QRect &clipRect) const { - if (QTextDocument *replacement = TextDocumentLayout::replacementDocument(block)) { - QTextBlock replacementBlock = replacement->firstBlock(); - QPointF replacementOffset = offset; - replacementOffset.rx() += document()->documentMargin(); - while (replacementBlock.isValid()) { + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(block)) { + QTextBlock suggestionBlock = suggestion->document()->firstBlock(); + QPointF suggestionOffset = offset; + suggestionOffset.rx() += document()->documentMargin(); + while (suggestionBlock.isValid()) { const QVector blockSelections - = replacementBlock.blockNumber() == 0 ? selections + = suggestionBlock.blockNumber() == 0 ? selections : QVector{}; - replacementBlock.layout()->draw(painter, - replacementOffset, + suggestionBlock.layout()->draw(painter, + suggestionOffset, blockSelections, clipRect); - replacementOffset.ry() - += replacement->documentLayout()->blockBoundingRect(replacementBlock).height(); - replacementBlock = replacementBlock.next(); + suggestionOffset.ry() += suggestion->document() + ->documentLayout() + ->blockBoundingRect(suggestionBlock) + .height(); + suggestionBlock = suggestionBlock.next(); } return; } @@ -5992,9 +5984,9 @@ void TextEditorWidget::removeHoverHandler(BaseHoverHandler *handler) d->m_hoverHandlerRunner.handlerRemoved(handler); } -void TextEditorWidget::insertSuggestion(const QString &suggestion) +void TextEditorWidget::insertSuggestion(std::unique_ptr &&suggestion) { - d->insertSuggestion(suggestion); + d->insertSuggestion(std::move(suggestion)); } void TextEditorWidget::clearSuggestion() diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 4234645d50a..8c6bbb688e3 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -42,15 +42,16 @@ class HighlightScrollBarController; } namespace TextEditor { -class TextDocument; -class TextMark; -class BaseHoverHandler; -class RefactorOverlay; -class SyntaxHighlighter; class AssistInterface; +class BaseHoverHandler; +class CompletionAssistProvider; class IAssistProvider; class ICodeStylePreferences; -class CompletionAssistProvider; +class RefactorOverlay; +class SyntaxHighlighter; +class TextDocument; +class TextMark; +class TextSuggestion; using RefactorMarkers = QList; using TextMarks = QList; @@ -470,7 +471,7 @@ public: void addHoverHandler(BaseHoverHandler *handler); void removeHoverHandler(BaseHoverHandler *handler); - void insertSuggestion(const QString &suggestion); + void insertSuggestion(std::unique_ptr &&suggestion); void clearSuggestion(); bool suggestionVisible() const; From 6ab923c39fd4ac66edb3cf708e3c789cb4a31428 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 16 Mar 2023 06:38:46 +0100 Subject: [PATCH 0430/1447] Copilot: add copilot suggestion tooltips These tooltips allow to switch the currently visible suggestion as well as applying it using the mouse. Change-Id: I30b9a76ae57c66887f4e1b1311e1a7248ed0f194 Reviewed-by: Marcus Tillmanns --- .../images/qtcreator-debugger-threads.webp | Bin 0 -> 4800 bytes src/plugins/copilot/CMakeLists.txt | 12 +- src/plugins/copilot/copilot.qbs | 18 ++- src/plugins/copilot/copilotclient.cpp | 53 +++---- src/plugins/copilot/copilotclient.h | 10 +- src/plugins/copilot/copilothoverhandler.cpp | 140 ++++++++++++++++++ src/plugins/copilot/copilothoverhandler.h | 32 ++++ src/plugins/copilot/copilotsuggestion.cpp | 41 +++++ src/plugins/copilot/copilotsuggestion.h | 30 ++++ src/plugins/texteditor/basehoverhandler.h | 3 +- src/plugins/texteditor/textdocumentlayout.h | 1 - src/plugins/texteditor/texteditor.cpp | 18 ++- src/plugins/texteditor/texteditor.h | 1 + 13 files changed, 303 insertions(+), 56 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-debugger-threads.webp create mode 100644 src/plugins/copilot/copilothoverhandler.cpp create mode 100644 src/plugins/copilot/copilothoverhandler.h create mode 100644 src/plugins/copilot/copilotsuggestion.cpp create mode 100644 src/plugins/copilot/copilotsuggestion.h diff --git a/doc/qtcreator/images/qtcreator-debugger-threads.webp b/doc/qtcreator/images/qtcreator-debugger-threads.webp new file mode 100644 index 0000000000000000000000000000000000000000..1a84d6ae2b969453fb0c435a28f5c94f8d0e8e13 GIT binary patch literal 4800 zcmWIYbaUGw#J~{l>J$(bVBxbyh=D=>FQYEQ)fi? z!IYi7#eOp{#(w+OdP!%o+?~mff=^V-v`dzs+Hz)3YQ?3Cd;eFnm#Chd^0w^QHl>qI zo~u-RuVpPN)IQ(y#$;d9k(DaZx36uhJbXq$qxfvVH@;J{sq7!QR8(UfC!L$ocIM2P zyd@E78pYbdGdkStsXZv|hAp%EE{RU*kTVUedHm$%SWs?+T@tRr_*2C(n9^YEGT; zEOn;Rv>e;gwUK`=-(FciMe4tX`8vbyV)yTQflHSynHMtQ(5c7YYZyImkU6;$p{eG~Uzu?(Bi@iRAA=7TE^*R(ADKSK( zSDUw#)Y|`_Qj&E;^X8?gZ*OL|co$18`=*-t=DS+mwg8h^3t#=}ylC+}y}El+7{7kl z)5qMQhLsgJ3a8Dhnz3wS;l#7OLYl>T3t~1mgrt0J^IBlv%D(#M;wYz;_m;9)Pc%vV zzJ<|*>Co26eEIwLe16NndfR@7NpocT=e;-`U3gdE($mtC>9Dz%CDp$@_eTBg{?O-ba}50_-}bm5y?;qS z-5R%L>t4TN-#@f3gRa#4B8f#6*a%?`)Lq_2H+wDgBZ%IjTQ zyXL=boiFt(Dp>EF|Cgs1TNdQ_UlzT4e$Q3uc%{-M@17;CU2J)>^ugv$x}C?<``-S3 z|D5%C{rqR?8A-aWS^{2NZ4=zMu0OtWO!0HwBIgs+N-n4`Fb`qAyH+#YUM}nK+ot44 z_y0QZpKaoL)+O;d_j2@s?acwV<%E`Q-WvZ_L;SkrT+M{VbDHXU&ehrKFSy5=Hp!g$Xxt4rjwygSbZq#vw1tQZ}=tDyZtR8uWewX<%+aj7#VNj|5x#pSUE zo$$RmZ9_yt@Onji=S8}oZZuXj7Vz!6zH{w#%lkJ{w>qtz*!ebMb&yr)baTJBoBt$V zzuI?ugM*Lgn!1xZp-<;rto>h}R}r`~=kEvo_9H&NXRbdnat-2gNOAPJwyI9V?#9$b z|4i=aWqEJ#Psm@vw&t7E&Fiz6W*AQ~%=FvkFJgP6Ypa%O>-h=ss(+<(eyjOZo(yP{ z&cAN!(v)WQetM+p{rF?^J!AKJh+d!N%KqY4M&d**P1X&wbUL*1yBoi)O7Y&{AHsHb zt>zq!s$13!7fTNutETb3bMN2!FIu;wN-kP*dcyD9aissim zmGhL&@dX`Vi@VO_#I32>%0F@Uq}!=t4jXSSUexT7UB7p0hu#$)yY(g0+ zd`mBcE-M$#XZKwD@SfFc^W!_ST)aO`lzy~X(;1U4WVk(EY#TH8^tSb7#&3(Z^1oy)QZp!!ux!e3mr8HFeIZ9% znR~AC?G*1#TlAFgN@YfAY6?j+FVwhQ|K`}XuoV)oZ(pBx)7;7JMBJKEg@sl}TK2>} zPc2_}Ft+$^n^VM!7o~B#K5a37!K%l2YA2ug%YcIP3$C*!aQYSW?TUOMb5kvP($aM^ zO0t(^E?wf0!_%@T=l@3O=wz)c*H&NcRI%zmn?#X$N87>&Wp{5pVX?40|ER$-za;QP^Ji|^ zDDyApeZ`}=R1&O}dMYMHuBc^yoUCW2*srthc;zy_JqFSbY?x&>h{Ve}uILL~e6IUk zO!Mlj+ofN&q{{Z{U7fZxxzmjyV|DKBb|GuwZMo(V56!YlnKtD{{&-u)Re9tM=gS2R zX;Us;VsXED%+W;6x%EkFU*PR+fwoR9xBaFU%N;&<;g_FzqB`pf=6@C3+j4{V9C^d0 ztutlz64hu$&wk!%Z&D7X`5e=_;cd3{eL_vo(KdCaenG)oF7lhM^gmi)xg=-4O_0ND z;T@KD#9h2C8bEpvTKc=Rb8YK=T`3!G?kFkGbUWm-kWp2xAeMB_8L*aQ&snZyxJ%1O5M6!#hYeFmMn&htxz#nYI2^`;giYN~f`6f`^;rjRWB z+WK2kbMkZrw@uUTy|fHEHbu1a(mS(VA>M&f!V6#4R;_h79c6F(yeDzD^&G}UsuBl& zo(o)b`qF}V76;Z{eLi8$d%xiHMbd|3PxHOavyy1|Xy}oA$TVT?dq3q564FjPJ^M5# z@0erFJZ)3V49+DFzqedH{`05bGq#Rt56)$Ge0Gt4{?TTII&01+C-x$hgzr~h1pRF+ z`0>}YrMf{jLEfPAw57jrz@uctZ7r?GlWWcA-@861?jb{&z>2z*_4k_(ubtKTcAi33 zC&Md&MQt2>+q2BKO>|)>75FHr1kP~xTrz4xCw~8ao#Vk_mASjbZGA6Y*W#<1X?phX z`?A7&B7dZAtz5MK=$E25iWyJRxiX-$Br(t=Ezqn6*x#l8W9gxTG-WuF7Z9> zVsoX~HigNGYp7>NOx>`N zL3q{CQ;YjoFsMJdsB%dAgMsz}E;Wgbax;pwIlfH&d@yN^!p99^28@YIy|xG)oZs4i zb-|_+Sr1zH%C-qtEDx6`u77ye{h&k3ud_-rIc?kz-dysXe!)h{ zMDZvOqmIjmkFG5Xnch_%V%)gf$t|IiC-=e$ zr9M~V!}hG0yN?etKk~3y&u~wVUq8M7WW>C!#U3-N1oZ^YYcp&=efaQs9v=mZDi)p2WIE4OHm=-SZO8koT5ru;)E33pFRk9|secc>ovR{GoqGu&tEGTlq79k*8Xe-vXi)k?d(sHaP_x<{L9 z)#rQZZb#oFm$1H^A$)TFb&2FJ^E5>dmoA^f^Z%XsWc&GPJ2rhO$ygdEzw2e#+Z`); zBa(VHo0r{X$(i>;r&Y18PN8brl9#pX>aN9~m0kS(&%3bCGv?jAa6X~T^fb@ClGP#l zn$0(_K5W~(?Reey*%98izZ%MmUYA|`dwSfGTMI3;7kvBXcW3S^PW>y=UMfNPKh%$> zzp~ey>_79B^;C|ay%#^zw%lQxG*5Ni@6c8Mmn~?rTC`>NLLUDAUlO)> zUYk{Rq|WNDgxtNmAN2PfSzMLgp1MjTD6zWqM&c#S@>~DgA3l7t#PXPdu+9Jc;~hTU z8xB`I+_8AC`Cg5OXAki>RD8bwM=_{}G49_^TgfM1&RNZK2<@63xweTp>b7*;jk_DP zHI{y0e6e(4$gNzbzyRgsvZWWo*56gjQBK}Av2b_NtxaK?Th5+Ni97Gs-uy*q+rG2g z_ViED3x52HlYQS7>m%N`i_Lv6#ov0mlkq|2i8l}Kuxx%Zy{t0N;Zs4~k@GiF*`L2R z@T|?8`J8RWNfvL5`i7P6QnQ}!WOP}->0qvbwIBZ^7n3u^%!^)Zf4<@10pp8?tzDmm zw(UK+&GVkmX&dtcJx4zCG~A0l@4ox<6RDFKGoG_G++Tcz;YIGAp4{TZ@@*+g7sbw# zF8C1})|z2t=wbUJx1{pIyBOx+{p<-*SzmTCx*lYbzAnkLAbmq_?`OpuH7h)(@F(Y- zU|wCw`dgGfwv>K!?B;XZ zg;&@Pu`Efv8^}LFqTWJrcDQi9!acuV-LH(+Gu&B_$f+UkxA=UKk)Ua#`ok^mif`QY z)-xHdGG4E6OC>S-g7b;??N^zlPc1O}%+(cV7@ab8W&i$)X$P5m?58;B_PU;H?s;GH z^w`bkfB3xiaVP(naB0J8`M1$FiWLnX+n+P|J!d;~WXsd%tCchFPd2n*w0+p~{?H7i z6=(J|$?B?oUh_!ui2A$bwfbBUd6 zz|u}IxI%{t$U7JAqT zPL8?&_>?2Cbc}Y>kpG ze(B6b|D4$;y0%1V{nVTDv8C}-*OAYiFCy+r2gEWhR=k{_bL!FgBHrDd8Ljm zTl0qL*0iRov)Uefg>iS!oDX$E~0mw<^-uupAe$D*|f3e z;=zCOPGzX1#Dr=sWvZ!nd@Z=XZ^`Cava7Wl|Fce97N24i#dE8E_9>^(vSspD-{=HC zsR=!ExA51jh>yE65>H+WJ}t8FYUH9*GiU9v3fuMj{WkuBX>)4=F1)bWRgiMu-kX;_ z^W#eQ?$DJyYrN;`Kg)RZ?fvTQe=WseU)QU(Nr+a&O}Le|QEA%y zeOCD?@2@;eY^@ak8K(5vVD%{p&aY>ST)*wQ+}^TjPyZYL59$%3{$He5Nv;w(W^(Fj zU0A4|^s;XUO?;aJADTurC|uiHeCArq<24o^7c6)fxu|37W|NCA+xV{h+Iy7!m;2+_ Kj{hqQihKa_ghS;3 literal 0 HcmV?d00001 diff --git a/src/plugins/copilot/CMakeLists.txt b/src/plugins/copilot/CMakeLists.txt index 8e8526542a7..b718ec12695 100644 --- a/src/plugins/copilot/CMakeLists.txt +++ b/src/plugins/copilot/CMakeLists.txt @@ -3,13 +3,15 @@ add_qtc_plugin(Copilot SOURCES authwidget.cpp authwidget.h copilot.qrc - copilotplugin.cpp copilotplugin.h copilotclient.cpp copilotclient.h - copilotsettings.cpp copilotsettings.h + copilothoverhandler.cpp copilothoverhandler.h copilotoptionspage.cpp copilotoptionspage.h - requests/getcompletions.h + copilotplugin.cpp copilotplugin.h + copilotsettings.cpp copilotsettings.h + copilotsuggestion.cpp copilotsuggestion.h requests/checkstatus.h - requests/signout.h - requests/signininitiate.h + requests/getcompletions.h requests/signinconfirm.h + requests/signininitiate.h + requests/signout.h ) diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs index aec95112ad8..51d7febbd6b 100644 --- a/src/plugins/copilot/copilot.qbs +++ b/src/plugins/copilot/copilot.qbs @@ -12,18 +12,22 @@ QtcPlugin { "authwidget.cpp", "authwidget.h", "copilot.qrc", - "copilotplugin.cpp", - "copilotplugin.h", "copilotclient.cpp", "copilotclient.h", - "copilotsettings.cpp", - "copilotsettings.h", + "copilothoverhandler.cpp", + "copilothoverhandler.h", "copilotoptionspage.cpp", "copilotoptionspage.h", - "requests/getcompletions.h", + "copilotplugin.cpp", + "copilotplugin.h", + "copilotsettings.cpp", + "copilotsettings.h", + "copilotsuggestion.cpp", + "copilotsuggestion.h", "requests/checkstatus.h", - "requests/signout.h", - "requests/signininitiate.h", + "requests/getcompletions.h", "requests/signinconfirm.h", + "requests/signininitiate.h", + "requests/signout.h", ] } diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 27bcbacf476..5d2a6aa4b7b 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "copilotclient.h" +#include "copilotsuggestion.h" #include #include @@ -63,6 +64,14 @@ CopilotClient::CopilotClient(const FilePath &nodePath, const FilePath &distPath) openDoc(doc); } +CopilotClient::~CopilotClient() +{ + for (Core::IEditor *editor : Core::DocumentModel::editorsForOpenedDocuments()) { + if (auto textEditor = qobject_cast(editor)) + textEditor->editorWidget()->removeHoverHandler(&m_hoverHandler); + } +} + void CopilotClient::openDocument(TextDocument *document) { Client::openDocument(document); @@ -112,7 +121,7 @@ void CopilotClient::scheduleRequest(TextEditorWidget *editor) void CopilotClient::requestCompletions(TextEditorWidget *editor) { Utils::MultiTextCursor cursor = editor->multiTextCursor(); - if (cursor.hasMultipleCursors() || cursor.hasSelection()) + if (cursor.hasMultipleCursors() || cursor.hasSelection() || editor->suggestionVisible()) return; const Utils::FilePath filePath = editor->textDocument()->filePath(); @@ -129,39 +138,6 @@ void CopilotClient::requestCompletions(TextEditorWidget *editor) sendMessage(request); } -class CopilotSuggestion final : public TextEditor::TextSuggestion -{ -public: - CopilotSuggestion(const Completion &completion, QTextDocument *origin) - : m_completion(completion) - { - document()->setPlainText(completion.text()); - m_start = completion.position().toTextCursor(origin); - m_start.setKeepPositionOnInsert(true); - setCurrentPosition(m_start.position()); - } - - bool apply() final - { - reset(); - QTextCursor cursor = m_completion.range().toSelection(m_start.document()); - cursor.insertText(m_completion.text()); - return true; - } - void reset() final - { - m_start.removeSelectedText(); - } - int position() final - { - return m_start.position(); - } - -private: - Completion m_completion; - QTextCursor m_start; -}; - void CopilotClient::handleCompletions(const GetCompletionRequest::Response &response, TextEditorWidget *editor) { @@ -184,7 +160,9 @@ void CopilotClient::handleCompletions(const GetCompletionRequest::Response &resp if (completions.isEmpty()) return; editor->insertSuggestion( - std::make_unique(completions.first(), editor->document())); + std::make_unique(completions, editor->document())); + m_lastCompletions[editor] = *result; + editor->addHoverHandler(&m_hoverHandler); } } @@ -234,4 +212,9 @@ void CopilotClient::requestSignInConfirm( sendMessage(request); } +GetCompletionResponse CopilotClient::lastCompletion(TextEditor::TextEditorWidget *editor) const +{ + return m_lastCompletions.value(editor); +} + } // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index 5111e04e1df..13f43149f71 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -3,6 +3,7 @@ #pragma once +#include "copilothoverhandler.h" #include "requests/checkstatus.h" #include "requests/getcompletions.h" #include "requests/signinconfirm.h" @@ -18,12 +19,11 @@ namespace Copilot::Internal { -class DocumentWatcher; - class CopilotClient : public LanguageClient::Client { public: - explicit CopilotClient(const Utils::FilePath &nodePath, const Utils::FilePath &distPath); + CopilotClient(const Utils::FilePath &nodePath, const Utils::FilePath &distPath); + ~CopilotClient() override; void openDocument(TextEditor::TextDocument *document) override; @@ -46,6 +46,8 @@ public: const QString &userCode, std::function callback); + GetCompletionResponse lastCompletion(TextEditor::TextEditorWidget *editor) const; + private: QMap m_runningRequests; struct ScheduleData @@ -54,6 +56,8 @@ private: QTimer *timer = nullptr; }; QMap m_scheduledRequests; + CopilotHoverHandler m_hoverHandler; + QHash m_lastCompletions; }; } // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilothoverhandler.cpp b/src/plugins/copilot/copilothoverhandler.cpp new file mode 100644 index 00000000000..07aca2cbc7c --- /dev/null +++ b/src/plugins/copilot/copilothoverhandler.cpp @@ -0,0 +1,140 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "copilothoverhandler.h" + +#include "copilotclient.h" +#include "copilotsuggestion.h" +#include "copilottr.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include + +using namespace TextEditor; +using namespace LanguageServerProtocol; +using namespace Utils; + +namespace Copilot::Internal { + +class CopilotCompletionToolTip : public QToolBar +{ +public: + CopilotCompletionToolTip(QList completions, + int currentCompletion, + TextEditorWidget *editor) + : m_numberLabel(new QLabel) + , m_completions(completions) + , m_currentCompletion(std::max(0, std::min(currentCompletion, completions.size() - 1))) + , m_editor(editor) + { + auto prev = addAction(Utils::Icons::PREV_TOOLBAR.icon(), + Tr::tr("Select Previous Copilot Suggestion")); + prev->setEnabled(m_completions.size() > 1); + addWidget(m_numberLabel); + auto next = addAction(Utils::Icons::NEXT_TOOLBAR.icon(), + Tr::tr("Select Next Copilot Suggestion")); + next->setEnabled(m_completions.size() > 1); + + auto apply = addAction(Tr::tr("Apply (Tab)")); + + connect(prev, &QAction::triggered, this, &CopilotCompletionToolTip::selectPrevious); + connect(next, &QAction::triggered, this, &CopilotCompletionToolTip::selectNext); + connect(apply, &QAction::triggered, this, &CopilotCompletionToolTip::apply); + + updateLabels(); + } + +private: + void updateLabels() + { + m_numberLabel->setText(Tr::tr("%1 of %2") + .arg(m_currentCompletion + 1) + .arg(m_completions.count())); + } + + void selectPrevious() + { + --m_currentCompletion; + if (m_currentCompletion < 0) + m_currentCompletion = m_completions.size() - 1; + setCurrentCompletion(); + } + + void selectNext() + { + ++m_currentCompletion; + if (m_currentCompletion >= m_completions.size()) + m_currentCompletion = 0; + setCurrentCompletion(); + } + + void setCurrentCompletion() + { + updateLabels(); + if (TextSuggestion *suggestion = m_editor->currentSuggestion()) + suggestion->reset(); + m_editor->insertSuggestion(std::make_unique(m_completions, + m_editor->document(), + m_currentCompletion)); + } + + void apply() + { + if (TextSuggestion *suggestion = m_editor->currentSuggestion()) + suggestion->apply(); + ToolTip::hide(); + } + + QLabel *m_numberLabel; + QList m_completions; + int m_currentCompletion = 0; + TextEditorWidget *m_editor; +}; + +void CopilotHoverHandler::identifyMatch(TextEditorWidget *editorWidget, + int pos, + ReportPriority report) +{ + auto reportNone = qScopeGuard([&] { report(Priority_None); }); + if (!editorWidget->suggestionVisible()) + return; + + QTextCursor cursor(editorWidget->document()); + cursor.setPosition(pos); + m_block = cursor.block(); + auto *suggestion = dynamic_cast(TextDocumentLayout::suggestion(m_block)); + + if (!suggestion) + return; + + const QList completions = suggestion->completions(); + if (completions.isEmpty()) + return; + + reportNone.dismiss(); + report(Priority_Suggestion); +} + +void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) +{ + auto *suggestion = dynamic_cast(TextDocumentLayout::suggestion(m_block)); + + if (!suggestion) + return; + + auto tooltipWidget = new CopilotCompletionToolTip(suggestion->completions(), + suggestion->currentCompletion(), + editorWidget); + const qreal deltay = 2 * editorWidget->textDocument()->fontSettings().lineSpacing(); + ToolTip::show(point - QPoint{0, int(deltay)}, tooltipWidget, editorWidget); +} + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilothoverhandler.h b/src/plugins/copilot/copilothoverhandler.h new file mode 100644 index 00000000000..1c48e75d5b7 --- /dev/null +++ b/src/plugins/copilot/copilothoverhandler.h @@ -0,0 +1,32 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "requests/getcompletions.h" + +#include + +#include + +#pragma once + +namespace TextEditor { class TextSuggestion; } +namespace Copilot::Internal { + +class CopilotClient; + +class CopilotHoverHandler final : public TextEditor::BaseHoverHandler +{ +public: + CopilotHoverHandler() = default; + +protected: + void identifyMatch(TextEditor::TextEditorWidget *editorWidget, + int pos, + ReportPriority report) final; + void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) final; + +private: + QTextBlock m_block; +}; + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotsuggestion.cpp b/src/plugins/copilot/copilotsuggestion.cpp new file mode 100644 index 00000000000..96ccbbcd18a --- /dev/null +++ b/src/plugins/copilot/copilotsuggestion.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "copilotsuggestion.h" + +namespace Copilot::Internal { + +CopilotSuggestion::CopilotSuggestion(const QList &completions, + QTextDocument *origin, + int currentCompletion) + : m_completions(completions) + , m_currentCompletion(currentCompletion) +{ + const Completion completion = completions.value(currentCompletion); + document()->setPlainText(completion.text()); + m_start = completion.position().toTextCursor(origin); + m_start.setKeepPositionOnInsert(true); + setCurrentPosition(m_start.position()); +} + +bool CopilotSuggestion::apply() +{ + reset(); + const Completion completion = m_completions.value(m_currentCompletion); + QTextCursor cursor = completion.range().toSelection(m_start.document()); + cursor.insertText(completion.text()); + return true; +} + +void CopilotSuggestion::reset() +{ + m_start.removeSelectedText(); +} + +int CopilotSuggestion::position() +{ + return m_start.position(); +} + +} // namespace Copilot::Internal + diff --git a/src/plugins/copilot/copilotsuggestion.h b/src/plugins/copilot/copilotsuggestion.h new file mode 100644 index 00000000000..5374ab74c05 --- /dev/null +++ b/src/plugins/copilot/copilotsuggestion.h @@ -0,0 +1,30 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#pragma once + +#include "requests/getcompletions.h" + +#include + +namespace Copilot::Internal { + +class CopilotSuggestion final : public TextEditor::TextSuggestion +{ +public: + CopilotSuggestion(const QList &completions, + QTextDocument *origin, + int currentCompletion = 0); + + bool apply() final; + void reset() final; + int position() final; + + const QList &completions() const { return m_completions; } + const int currentCompletion() const { return m_currentCompletion; } + +private: + QList m_completions; + int m_currentCompletion = 0; + QTextCursor m_start; +}; +} // namespace Copilot::Internal diff --git a/src/plugins/texteditor/basehoverhandler.h b/src/plugins/texteditor/basehoverhandler.h index 9b6d90fd89a..c24ae4a1df5 100644 --- a/src/plugins/texteditor/basehoverhandler.h +++ b/src/plugins/texteditor/basehoverhandler.h @@ -39,7 +39,8 @@ protected: Priority_None = 0, Priority_Tooltip = 5, Priority_Help = 10, - Priority_Diagnostic = 20 + Priority_Diagnostic = 20, + Priority_Suggestion = 40 }; void setPriority(int priority); int priority() const; diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index e02615b1063..d4020f721c2 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -165,7 +165,6 @@ private: std::unique_ptr m_suggestion; }; - class TEXTEDITOR_EXPORT TextDocumentLayout : public QPlainTextDocumentLayout { Q_OBJECT diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index c5783acb919..e61262094fc 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -3736,7 +3736,10 @@ bool TextEditorWidget::viewportEvent(QEvent *event) // Only handle tool tip for text cursor if mouse is within the block for the text cursor, // and not if the mouse is e.g. in the empty space behind a short line. if (line.isValid()) { - if (pos.x() <= blockBoundingGeometry(block).left() + line.naturalTextRect().right()) { + const QRectF blockGeometry = blockBoundingGeometry(block); + const int width = block == d->m_suggestionBlock ? blockGeometry.width() + : line.naturalTextRect().right(); + if (pos.x() <= blockGeometry.left() + width) { d->processTooltipRequest(tc); return true; } else if (d->processAnnotaionTooltipRequest(block, pos)) { @@ -5980,8 +5983,8 @@ void TextEditorWidget::addHoverHandler(BaseHoverHandler *handler) void TextEditorWidget::removeHoverHandler(BaseHoverHandler *handler) { - d->m_hoverHandlers.removeAll(handler); - d->m_hoverHandlerRunner.handlerRemoved(handler); + if (d->m_hoverHandlers.removeAll(handler) > 0) + d->m_hoverHandlerRunner.handlerRemoved(handler); } void TextEditorWidget::insertSuggestion(std::unique_ptr &&suggestion) @@ -5994,9 +5997,16 @@ void TextEditorWidget::clearSuggestion() d->clearCurrentSuggestion(); } +TextSuggestion *TextEditorWidget::currentSuggestion() const +{ + if (d->m_suggestionBlock.isValid()) + return TextDocumentLayout::suggestion(d->m_suggestionBlock); + return nullptr; +} + bool TextEditorWidget::suggestionVisible() const { - return d->m_suggestionBlock.isValid(); + return currentSuggestion(); } #ifdef WITH_TESTS diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 8c6bbb688e3..56308d796ed 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -473,6 +473,7 @@ public: void insertSuggestion(std::unique_ptr &&suggestion); void clearSuggestion(); + TextSuggestion *currentSuggestion() const; bool suggestionVisible() const; #ifdef WITH_TESTS From 016385d514d40b64607a9996a3bae300360519b1 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 29 Mar 2023 08:52:37 +0200 Subject: [PATCH 0431/1447] Debugger: Do not store generic debuggers to settings They get added automatically. Silences a warning for each generic debugger. Change-Id: I5a60ddd9780e5992d67a67a75eb0917ceae778e6 Reviewed-by: hjk --- src/plugins/debugger/debuggeritemmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index a74ac5071fc..1c9a6e68dc7 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -982,6 +982,8 @@ void DebuggerItemManagerPrivate::saveDebuggers() int count = 0; forAllDebuggers([&count, &data](DebuggerItem &item) { + if (item.isGeneric()) // do not store generic debuggers, these get added automatically + return; if (item.isValid() && item.engineType() != NoEngineType) { QVariantMap tmp = item.toMap(); if (!tmp.isEmpty()) { From aefc8e296c3d7c1aaee9f03f6ce7fbd393594acc Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 14:25:22 +0200 Subject: [PATCH 0432/1447] ProjectExplorer: Provide access to copy step id constants Makes steps better re-usable. Change-Id: I5ef687480179b06985e525336f31be3fd69bcd23 Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/copystep.cpp | 5 +++-- src/plugins/projectexplorer/projectexplorerconstants.h | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/copystep.cpp b/src/plugins/projectexplorer/copystep.cpp index e2b478a237a..9f0201d73e9 100644 --- a/src/plugins/projectexplorer/copystep.cpp +++ b/src/plugins/projectexplorer/copystep.cpp @@ -3,6 +3,7 @@ #include "copystep.h" +#include "projectexplorerconstants.h" #include "projectexplorertr.h" #include @@ -99,14 +100,14 @@ public: CopyFileStepFactory::CopyFileStepFactory() { - registerStep("ProjectExplorer.CopyFileStep"); + registerStep(Constants::COPY_FILE_STEP); //: Default CopyStep display name setDisplayName(Tr::tr("Copy file")); } CopyDirectoryStepFactory::CopyDirectoryStepFactory() { - registerStep("ProjectExplorer.CopyDirectoryStep"); + registerStep(Constants::COPY_DIRECTORY_STEP); //: Default CopyStep display name setDisplayName(Tr::tr("Copy directory recursively")); } diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 9c86d6d9cf4..f612b9adb08 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -132,6 +132,9 @@ const char BUILDSTEPS_CLEAN[] = "ProjectExplorer.BuildSteps.Clean"; const char BUILDSTEPS_BUILD[] = "ProjectExplorer.BuildSteps.Build"; const char BUILDSTEPS_DEPLOY[] = "ProjectExplorer.BuildSteps.Deploy"; +const char COPY_FILE_STEP[] = "ProjectExplorer.CopyFileStep"; +const char COPY_DIRECTORY_STEP[] = "ProjectExplorer.CopyDirectoryStep"; + // Language // Keep these short: These constants are exposed to the MacroExplorer! From 3a23126419247cd77c4907431631c3fb6abc5b1b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 29 Mar 2023 12:58:55 +0200 Subject: [PATCH 0433/1447] CoPilot: Fix warning Change-Id: I867b44fd769c96d294830d0a2c1c8b1bdf669d6f Reviewed-by: hjk Reviewed-by: David Schulz --- src/plugins/copilot/copilotsuggestion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/copilot/copilotsuggestion.h b/src/plugins/copilot/copilotsuggestion.h index 5374ab74c05..a5b55b2d973 100644 --- a/src/plugins/copilot/copilotsuggestion.h +++ b/src/plugins/copilot/copilotsuggestion.h @@ -20,7 +20,7 @@ public: int position() final; const QList &completions() const { return m_completions; } - const int currentCompletion() const { return m_currentCompletion; } + int currentCompletion() const { return m_currentCompletion; } private: QList m_completions; From 2eebfb130c755b15bee3d71a7e3e0668ec4597ae Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 13:41:50 +0200 Subject: [PATCH 0434/1447] RemoteLinux: Also check for generic copy in device test Currently both ssh and rsysnc don't work on double remote, this allows passing the test with some deployment. Change-Id: Iad2f125b09d1b326d6399cdc3dff0faa9430e92d Reviewed-by: Christian Stenger Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/remotelinux/linuxdevicetester.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 3c34a638202..0ee175ef85f 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -208,6 +208,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::transferTasks() const return Tasking::Group { continueOnDone, Storage(storage), + transferTask(FileTransferMethod::GenericCopy, storage), transferTask(FileTransferMethod::Sftp, storage), transferTask(FileTransferMethod::Rsync, storage), OnGroupError([this] { emit q->errorMessage(Tr::tr("Deployment to this device will not " From 143dedf2f52096dad15fdfa66832a16c48010df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Mon, 27 Mar 2023 18:20:49 +0200 Subject: [PATCH 0435/1447] LanguageClient: Fix state string After a shutdown, the client is shut down. Change-Id: I092af02bfb72fda611229af42a838071890bfce9 Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Leena Miettinen --- src/plugins/languageclient/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 17248c7ca29..90717c4e0a7 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -555,7 +555,7 @@ QString Client::stateString() const case InitializeRequested: return Tr::tr("initialize requested"); case Initialized: return Tr::tr("initialized"); case ShutdownRequested: return Tr::tr("shutdown requested"); - case Shutdown: return Tr::tr("shutdown"); + case Shutdown: return Tr::tr("shut down"); case Error: return Tr::tr("error"); } return {}; From 0f3f5fb4d83c82d83366db2e1a464af573a39c05 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Tue, 28 Mar 2023 10:32:50 +0300 Subject: [PATCH 0436/1447] Git: Fix crash when menu is closed before fast-forward check result Fixes: QTCREATORBUG-28958 Change-Id: Ic3bfde2f355fdb3d44b0614e9ba176ff550d97c8 Reviewed-by: Alessandro Portale --- src/plugins/git/branchview.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index df9c255c587..2975f3c9eec 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -224,6 +224,7 @@ void BranchView::slotCustomContextMenu(const QPoint &point) const bool hasActions = m_model->isLeaf(index); const bool currentLocal = m_model->isLocal(currentBranch); std::unique_ptr taskTree; + QAction *mergeAction = nullptr; QMenu contextMenu; contextMenu.addAction(Tr::tr("&Add..."), this, &BranchView::add); @@ -267,10 +268,10 @@ void BranchView::slotCustomContextMenu(const QPoint &point) resetMenu->addAction(Tr::tr("&Mixed"), this, [this] { reset("mixed"); }); resetMenu->addAction(Tr::tr("&Soft"), this, [this] { reset("soft"); }); contextMenu.addMenu(resetMenu); - QAction *mergeAction = contextMenu.addAction(Tr::tr("&Merge \"%1\" into \"%2\"") - .arg(indexName, currentName), - this, - [this] { merge(false); }); + mergeAction = contextMenu.addAction(Tr::tr("&Merge \"%1\" into \"%2\"") + .arg(indexName, currentName), + this, + [this] { merge(false); }); taskTree.reset(onFastForwardMerge([&] { auto ffMerge = new QAction( Tr::tr("&Merge \"%1\" into \"%2\" (Fast-Forward)").arg(indexName, currentName)); @@ -279,6 +280,7 @@ void BranchView::slotCustomContextMenu(const QPoint &point) mergeAction->setText(Tr::tr("Merge \"%1\" into \"%2\" (No &Fast-Forward)") .arg(indexName, currentName)); })); + connect(mergeAction, &QObject::destroyed, taskTree.get(), &TaskTree::stop); contextMenu.addAction(Tr::tr("&Rebase \"%1\" on \"%2\"") .arg(currentName, indexName), From 73c645820fe3df797b5e813c1881afabcab0fd7e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 28 Mar 2023 14:33:39 +0200 Subject: [PATCH 0437/1447] TextEditor: use QScopeGuard instead of ExecuteOnDestruction Change-Id: I2d7c04d69ad49a121b157af2750eaed26bab9480 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/texteditor/texteditor.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index e61262094fc..4b0df472f89 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -2533,7 +2533,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) { ICore::restartTrimmer(); - ExecuteOnDestruction eod([&]() { d->clearBlockSelection(); }); + auto clearBlockSelectionGuard = qScopeGuard([&]() { d->clearBlockSelection(); }); if (!isModifier(e) && mouseHidingEnabled()) viewport()->setCursor(Qt::BlankCursor); @@ -2803,8 +2803,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) } if (blockSelectionOperation != QTextCursor::NoMove) { - auto doNothing = [](){}; - eod.reset(doNothing); + clearBlockSelectionGuard.dismiss(); d->handleMoveBlockSelection(blockSelectionOperation); } else if (!d->cursorMoveKeyEvent(e)) { QTextCursor cursor = textCursor(); From cb3fd6eb0dd564b7ff9d58473fe00d83bd24011c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 29 Mar 2023 15:58:56 +0200 Subject: [PATCH 0438/1447] Utils: Introduce Utils::Icons::PINNED_SMALL Replaces two duplicated pin.xpm in the pinnable debugger tooltip and the qmleditorwidgets with the new icon. Change-Id: I57b7adc5c0b92ffdf01da12dd832482d739cb86e Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../qmleditorwidgets/contextpanewidget.cpp | 29 ++----------------- src/libs/utils/utilsicons.cpp | 2 ++ src/libs/utils/utilsicons.h | 1 + src/plugins/debugger/debugger.qbs | 2 +- src/plugins/debugger/debugger.qrc | 1 - .../debugger/debuggertooltipmanager.cpp | 6 ++-- src/plugins/debugger/images/pin.xpm | 19 ------------ 7 files changed, 9 insertions(+), 51 deletions(-) delete mode 100644 src/plugins/debugger/images/pin.xpm diff --git a/src/libs/qmleditorwidgets/contextpanewidget.cpp b/src/libs/qmleditorwidgets/contextpanewidget.cpp index 688c65ad7b3..8d675bf95b1 100644 --- a/src/libs/qmleditorwidgets/contextpanewidget.cpp +++ b/src/libs/qmleditorwidgets/contextpanewidget.cpp @@ -6,6 +6,7 @@ #include "qmleditorwidgetstr.h" #include +#include #include #include @@ -27,26 +28,6 @@ using namespace Utils; namespace QmlEditorWidgets { -/* XPM */ -static const char * pin_xpm[] = { -"12 9 7 1", -" c None", -". c #000000", -"+ c #515151", -"@ c #A8A8A8", -"# c #A9A9A9", -"$ c #999999", -"% c #696969", -" . ", -" ......+", -" .@@@@@.", -" .#####.", -"+.....$$$$$.", -" .%%%%%.", -" .......", -" ......+", -" . "}; - DragWidget::DragWidget(QWidget *parent) : QFrame(parent) { setFrameStyle(QFrame::NoFrame); @@ -143,7 +124,7 @@ ContextPaneWidget::ContextPaneWidget(QWidget *parent) : DragWidget(parent), m_cu m_toolButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton)); m_toolButton->setToolButtonStyle(Qt::ToolButtonIconOnly); - m_toolButton->setFixedSize(16, 16); + m_toolButton->setFixedSize(20, 20); m_toolButton->setToolTip(Tr::tr("Hides this toolbar.")); connect(m_toolButton, &QToolButton::clicked, this, &ContextPaneWidget::onTogglePane); @@ -464,9 +445,7 @@ void ContextPaneWidget::setPinButton() m_toolButton->setAutoRaise(true); m_pinned = true; - m_toolButton->setIcon(QPixmap::fromImage(QImage(pin_xpm))); - m_toolButton->setToolButtonStyle(Qt::ToolButtonIconOnly); - m_toolButton->setFixedSize(20, 20); + m_toolButton->setIcon(Utils::Icons::PINNED_SMALL.icon()); m_toolButton->setToolTip(Tr::tr("Unpins the toolbar and moves it to the default position.")); emit pinnedChanged(true); @@ -481,8 +460,6 @@ void ContextPaneWidget::setLineButton() m_pinned = false; m_toolButton->setAutoRaise(true); m_toolButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton)); - m_toolButton->setToolButtonStyle(Qt::ToolButtonIconOnly); - m_toolButton->setFixedSize(20, 20); m_toolButton->setToolTip(Tr::tr("Hides this toolbar. This toolbar can be" " permanently disabled in the options page or in the context menu.")); diff --git a/src/libs/utils/utilsicons.cpp b/src/libs/utils/utilsicons.cpp index 7263b285946..cbc2ddf64fb 100644 --- a/src/libs/utils/utilsicons.cpp +++ b/src/libs/utils/utilsicons.cpp @@ -24,6 +24,8 @@ const Icon UNLOCKED({ {":/utils/images/unlocked.png", Theme::PanelTextColorDark}}, Icon::Tint); const Icon PINNED({ {":/utils/images/pinned.png", Theme::PanelTextColorDark}}, Icon::Tint); +const Icon PINNED_SMALL({ + {":/utils/images/pinned_small.png", Theme::PanelTextColorDark}}, Icon::Tint); const Icon NEXT({ {":/utils/images/next.png", Theme::IconsWarningColor}}, Icon::MenuTintedStyle); const Icon NEXT_TOOLBAR({ diff --git a/src/libs/utils/utilsicons.h b/src/libs/utils/utilsicons.h index b8fda0c53fd..3e5009c94c2 100644 --- a/src/libs/utils/utilsicons.h +++ b/src/libs/utils/utilsicons.h @@ -19,6 +19,7 @@ QTCREATOR_UTILS_EXPORT extern const Icon LOCKED; QTCREATOR_UTILS_EXPORT extern const Icon UNLOCKED_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon UNLOCKED; QTCREATOR_UTILS_EXPORT extern const Icon PINNED; +QTCREATOR_UTILS_EXPORT extern const Icon PINNED_SMALL; QTCREATOR_UTILS_EXPORT extern const Icon NEXT; QTCREATOR_UTILS_EXPORT extern const Icon NEXT_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon PREV; diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 8319bea822b..03b57c5885a 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -175,7 +175,7 @@ Project { Group { name: "Images" prefix: "images/" - files: ["*.png", "*.xpm"] + files: ["*.png"] } Group { diff --git a/src/plugins/debugger/debugger.qrc b/src/plugins/debugger/debugger.qrc index 86a05a73ff1..6fc31bb4fbb 100644 --- a/src/plugins/debugger/debugger.qrc +++ b/src/plugins/debugger/debugger.qrc @@ -42,7 +42,6 @@ images/mode_debug@2x.png images/mode_debug_mask.png images/mode_debug_mask@2x.png - images/pin.xpm images/debugger_restart_small.png images/debugger_restart_small@2x.png images/recordfill.png diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index f5e9933fbef..40f12f5470a 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -519,7 +519,7 @@ DebuggerToolTipWidget::DebuggerToolTipWidget() setAttribute(Qt::WA_DeleteOnClose); isPinned = false; - const QIcon pinIcon(":/debugger/images/pin.xpm"); + const QIcon pinIcon = Utils::Icons::PINNED_SMALL.icon(); pinButton = new QToolButton; pinButton->setIcon(pinIcon); @@ -534,9 +534,7 @@ DebuggerToolTipWidget::DebuggerToolTipWidget() auto toolBar = new QToolBar(this); toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); - const QList pinIconSizes = pinIcon.availableSizes(); - if (!pinIconSizes.isEmpty()) - toolBar->setIconSize(pinIconSizes.front()); + toolBar->setIconSize({12, 12}); toolBar->addWidget(pinButton); toolBar->addWidget(copyButton); toolBar->addWidget(titleLabel); diff --git a/src/plugins/debugger/images/pin.xpm b/src/plugins/debugger/images/pin.xpm deleted file mode 100644 index 0759becb67f..00000000000 --- a/src/plugins/debugger/images/pin.xpm +++ /dev/null @@ -1,19 +0,0 @@ -/* XPM */ -static const char * pin_xpm[] = { -"12 9 7 1", -" c None", -". c #000000", -"+ c #515151", -"@ c #A8A8A8", -"# c #A9A9A9", -"$ c #999999", -"% c #696969", -" . ", -" ......+", -" .@@@@@.", -" .#####.", -"+.....$$$$$.", -" .%%%%%.", -" .......", -" ......+", -" . "}; From 6f765181c9b9e716f3ae746183cdeac2459ac194 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 30 Mar 2023 12:11:34 +0200 Subject: [PATCH 0439/1447] Icons: Remove obsolete svg files and scripts Change-Id: Ibdb42808b70323eca6f751a6f74cd90a3f844ee7 Reviewed-by: Alessandro Portale --- .../GenericDocumentIcon.iconset/readme.txt | 15 - src/tools/icons/applicationicons.svg | 2206 ----------------- src/tools/icons/documenttypeicons.svg | 879 ------- src/tools/icons/exportapplicationicons.sh | 102 - src/tools/icons/exportdocumenttypeicons.sh | 32 - 5 files changed, 3234 deletions(-) delete mode 100644 src/tools/icons/GenericDocumentIcon.iconset/readme.txt delete mode 100644 src/tools/icons/applicationicons.svg delete mode 100644 src/tools/icons/documenttypeicons.svg delete mode 100644 src/tools/icons/exportapplicationicons.sh delete mode 100644 src/tools/icons/exportdocumenttypeicons.sh diff --git a/src/tools/icons/GenericDocumentIcon.iconset/readme.txt b/src/tools/icons/GenericDocumentIcon.iconset/readme.txt deleted file mode 100644 index a00748fafd0..00000000000 --- a/src/tools/icons/GenericDocumentIcon.iconset/readme.txt +++ /dev/null @@ -1,15 +0,0 @@ -This directory needs to contain the files - - icon_128x128.png - icon_128x128@2x.png - icon_16x16.png - icon_16x16@2x.png - icon_256x256.png - icon_256x256@2x.png - icon_32x32.png - icon_32x32@2x.png - icon_512x512.png - icon_512x512@2x.png - -On OSX, they are obtainable by executing the following command: -iconutil -c iconset /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericDocumentIcon.icns diff --git a/src/tools/icons/applicationicons.svg b/src/tools/icons/applicationicons.svg deleted file mode 100644 index 018fb75ea52..00000000000 --- a/src/tools/icons/applicationicons.svg +++ /dev/null @@ -1,2206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tools/icons/documenttypeicons.svg b/src/tools/icons/documenttypeicons.svg deleted file mode 100644 index d34829f5b4f..00000000000 --- a/src/tools/icons/documenttypeicons.svg +++ /dev/null @@ -1,879 +0,0 @@ - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UI - - - - - - - - - - - - - - - - - - - - - - UI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PRO - - - - - PRO - - - - - PRO - - - - - PRO - - - - - - - - - - PRO - - - - - PRO - - - - - PRO - - - - - PRO - - - - diff --git a/src/tools/icons/exportapplicationicons.sh b/src/tools/icons/exportapplicationicons.sh deleted file mode 100644 index eb74acbb90d..00000000000 --- a/src/tools/icons/exportapplicationicons.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/sh - -# Copyright (C) 2016 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -# This script creates several application icon files by using -# Inkscape to rasterize .svg items to .png, adding shadows via -# imagemagick, creating .ico files via imagemagick and .icns -# files via iconutil (OSX only). - -# optipng is required by this script -if ! hash optipng 2>/dev/null; then - echo "optipng was not found in PATH" >&2 - exit 1 -fi - -# Imagemagick convert is required by this script -if ! hash convert 2>/dev/null; then - echo "Imagemagick convert was not found in PATH" >&2 - exit 1 -fi - -cd `dirname $0` - -applicationNames="qtcreator designer linguist assistant qdbusviewer qmlviewer" -applicationIconDimensions="16:0 24:0 32:1 48:1 64:1 128:2 256:3 512:7 1024:15" - -# Creating the list of svg IDs to export -for applicationName in $applicationNames;\ -do - for applicationIconDimension in $applicationIconDimensions;\ - do - applicationIconSize=`echo $applicationIconDimension | awk -F: '{ print $1 }'` - iconIDs="${iconIDs} ${applicationName}_icon_${applicationIconSize}x${applicationIconSize}" - done -done - -# Copying the logos for Qt Creator's sources. Without shadows! -creatorLogoDir="logo" -rm -rf $creatorLogoDir -mkdir $creatorLogoDir -for uiFileIconSize in 16 24 32 48 64 128 256 512;\ -do - creatorLogoSource="qtcreator_icon_${uiFileIconSize}x${uiFileIconSize}.png" - creatorLogoTargetDir="${creatorLogoDir}/${uiFileIconSize}" - creatorLogoTarget="${creatorLogoTargetDir}/QtProject-qtcreator.png" - optipng $creatorLogoSource -o 7 -strip all - mkdir $creatorLogoTargetDir - cp $creatorLogoSource $creatorLogoTarget -done - -# Adding the shadows to the .png files -for applicationName in $applicationNames;\ -do - for applicationIconDimension in $applicationIconDimensions;\ - do - iconSize=`echo $applicationIconDimension | awk -F: '{ print $1 }'` - shadowSize=`echo $applicationIconDimension | awk -F: '{ print $2 }'` - iconFile=${applicationName}_icon_${iconSize}x${iconSize}.png - if [ "$shadowSize" != "0" ] - then - convert -page ${iconSize}x${iconSize} ${iconFile} \( +clone -background black -shadow 25x1+0+0 \) +swap -background none -flatten ${iconFile} - convert -page ${iconSize}x${iconSize} ${iconFile} \( +clone -background black -shadow 40x${shadowSize}+0+${shadowSize} \) +swap -background none -flatten ${iconFile} - fi - done -done - -# Creating the .ico files -iconSizes="256 128 64 48 32 24 16" -for applicationName in $applicationNames;\ -do - icoFiles="" - for iconSize in $iconSizes;\ - do - icoFiles="$icoFiles ${applicationName}_icon_${iconSize}x${iconSize}.png" - done - convert ${icoFiles} ${applicationName}.ico -done - -# Optimizing the .pngs -for iconID in $iconIDs;\ -do - optipng "${iconID}.png" -o 7 -strip all -done - -# Preparing application .iconsets for the conversion to .icns -for applicationName in $applicationNames;\ -do - inconsetName=${applicationName}.iconset - rm -rf $inconsetName - mkdir $inconsetName - cp ${applicationName}_icon_16x16.png ${inconsetName}/icon_16x16.png - cp ${applicationName}_icon_32x32.png ${inconsetName}/icon_32x32.png - cp ${applicationName}_icon_128x128.png ${inconsetName}/icon_128x128.png - cp ${applicationName}_icon_256x256.png ${inconsetName}/icon_256x256.png - cp ${applicationName}_icon_512x512.png ${inconsetName}/icon_512x512.png - cp ${applicationName}_icon_32x32.png ${inconsetName}/icon_16x16@2x.png - cp ${applicationName}_icon_64x64.png ${inconsetName}/icon_32x32@2x.png - cp ${applicationName}_icon_256x256.png ${inconsetName}/icon_128x128@2x.png - cp ${applicationName}_icon_512x512.png ${inconsetName}/icon_256x256@2x.png - cp ${applicationName}_icon_1024x1024.png ${inconsetName}/icon_512x512@2x.png -done diff --git a/src/tools/icons/exportdocumenttypeicons.sh b/src/tools/icons/exportdocumenttypeicons.sh deleted file mode 100644 index f0d8351c63d..00000000000 --- a/src/tools/icons/exportdocumenttypeicons.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -# Copyright (C) 2016 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -# optipng is required by this script -if ! hash optipng 2>/dev/null; then - echo "optipng was not found in PATH" >&2 - exit 1 -fi - -cd `dirname $0` - -# Adding the icons for the OSX document type icon for .ui files -for documentTypeName in "uifile" "qtcreator-project";\ -do - inconsetName=${documentTypeName}.iconset - rm -rf $inconsetName - mkdir $inconsetName - for iconSize in 16 32 128 256 512;\ - do - iconShortID="icon_${iconSize}x${iconSize}" - iconLongID="${documentTypeName}_${iconShortID}" - for sizeVariation in "" "@2x";\ - do - iconSourcePng="${iconLongID}${sizeVariation}.png" - iconTargetPng="${inconsetName}/${iconShortID}${sizeVariation}.png" - optipng $iconSourcePng -o 7 -strip all - cp $iconSourcePng $iconTargetPng - done - done -done From 9526971b238b950c9e5261c1a6d6fd66d5ae4979 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Thu, 30 Mar 2023 18:08:24 +0200 Subject: [PATCH 0440/1447] qds: fix build after merge with older Qt versions Change-Id: Ia6574b38d19df4a274d4e095a76bb1ceb60fa258 Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/components/toolbar/toolbar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/toolbar/toolbar.cpp b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp index 856546c1063..3326c889ad5 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbar.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp @@ -113,7 +113,7 @@ void ToolBar::createStatusBar() quickWidget->setSource(QUrl::fromLocalFile(qmlFilePath.toFSPathString())); - for (QWidget *w : Core::ICore::statusBar()->findChildren(Qt::FindDirectChildrenOnly)) { + for (QWidget *w : Core::ICore::statusBar()->findChildren(QString(), Qt::FindDirectChildrenOnly)) { w->hide(); } From 09ab24ca72f11466d7a619dccc3ada9931a1cfa9 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Thu, 30 Mar 2023 18:08:46 +0200 Subject: [PATCH 0441/1447] LanguageClient: fix build with mingw Change-Id: I447a21cc9eef6bb1f8cfdec500e68ae33c4db276 Reviewed-by: Tim Jenssen --- src/plugins/languageclient/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt index 0677cdf867a..20f7c680fbc 100644 --- a/src/plugins/languageclient/CMakeLists.txt +++ b/src/plugins/languageclient/CMakeLists.txt @@ -1,3 +1,9 @@ +if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +elseif (MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj") +endif() + add_qtc_plugin(LanguageClient PUBLIC_DEPENDS LanguageServerProtocol Qt::Core app_version PLUGIN_DEPENDS ProjectExplorer Core TextEditor From 93fb8cd1efab68f54ea4abb38db2e9e14131e03d Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 31 Mar 2023 07:33:58 +0200 Subject: [PATCH 0442/1447] Fix Qbs build Change-Id: Ia46cadd346561c2d52596290e3fbabcc2e746229 Reviewed-by: David Schulz --- src/plugins/plugins.qbs | 1 + .../qmldesignerbase/qmldesignerbase.qbs | 29 +++++++++++++++++++ .../qmlprojectmanager/qmlprojectmanager.qbs | 1 + 3 files changed, 31 insertions(+) create mode 100644 src/plugins/qmldesignerbase/qmldesignerbase.qbs diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 8e57311d9fe..48b0825430c 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -69,6 +69,7 @@ Project { "qmlprojectmanager/qmlprojectmanager.qbs", "qnx/qnx.qbs", "qmakeprojectmanager/qmakeprojectmanager.qbs", + "qmldesignerbase/qmldesignerbase.qbs", "qtsupport/qtsupport.qbs", "remotelinux/remotelinux.qbs", "resourceeditor/resourceeditor.qbs", diff --git a/src/plugins/qmldesignerbase/qmldesignerbase.qbs b/src/plugins/qmldesignerbase/qmldesignerbase.qbs new file mode 100644 index 00000000000..937f180c32c --- /dev/null +++ b/src/plugins/qmldesignerbase/qmldesignerbase.qbs @@ -0,0 +1,29 @@ +import qbs + +QtcPlugin { + name: "QmlDesignerBase" + + Depends { name: "Core" } + Depends { name: "ProjectExplorer" } + Depends { name: "QtSupport" } + Depends { name: "app_version_header" } + Depends { name: "Qt.quickwidgets" } + + files: [ + "qmldesignerbase_global.h", + "qmldesignerbaseplugin.cpp", + "qmldesignerbaseplugin.h", + ] + + Group { + prefix: "utils/" + files: [ + "designersettings.cpp", + "designersettings.h", + "qmlpuppetpaths.cpp", + "qmlpuppetpaths.h", + "studioquickwidget.cpp", + "studioquickwidget.h", + ] + } +} diff --git a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs index 9eac76dc6ca..d4938c8d798 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs +++ b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs @@ -9,6 +9,7 @@ QtcPlugin { Depends { name: "Core" } Depends { name: "ProjectExplorer" } + Depends { name: "QmlDesignerBase" } Depends { name: "QtSupport" } Depends { name: "TextEditor" } From 4b606ba9de36334cd8acdb34088b9c224a0f1def Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 30 Mar 2023 13:53:29 +0200 Subject: [PATCH 0443/1447] LanguageClient: optimize cloning documents Cloning the document that is needed to track the changes for the language server is 3 times slower than just getting the whole original document content and create a new QTextDocument with that content. Presumably some additional information gets cloned that is not needed for just the content tracking. Change-Id: I4a7002b2ac97563f01dc3a67351b9363e9cc7b3f Reviewed-by: Christian Stenger --- src/plugins/languageclient/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 90717c4e0a7..81811852a53 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -618,7 +618,7 @@ void Client::openDocument(TextEditor::TextDocument *document) } } - d->m_openedDocument[document].document = document->document()->clone(this); + d->m_openedDocument[document].document = new QTextDocument(document->document()->toPlainText()); d->m_openedDocument[document].contentsChangedConnection = connect(document, &TextDocument::contentsChangedWithPosition, From 3aa0291cd17b0133e94a5efbda60a0a64123bbfe Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 28 Mar 2023 14:28:59 +0200 Subject: [PATCH 0444/1447] Utils: Handle invalid colors in QtColorButton Paint a sublte placeholder. Change-Id: I4fc0a51744a98621fb8289ce7cddfc2ccd43784f Reviewed-by: Eike Ziller --- src/libs/utils/qtcolorbutton.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/qtcolorbutton.cpp b/src/libs/utils/qtcolorbutton.cpp index e6735baae2a..6a8537bd5fa 100644 --- a/src/libs/utils/qtcolorbutton.cpp +++ b/src/libs/utils/qtcolorbutton.cpp @@ -3,6 +3,8 @@ #include "qtcolorbutton.h" +#include "theme/theme.h" + #include #include #include @@ -160,9 +162,25 @@ void QtColorButton::paintEvent(QPaintEvent *event) { Q_UNUSED(event) + constexpr Theme::Color overlayColor = Theme::TextColorNormal; + constexpr qreal overlayOpacity = 0.25; + QPainter p(this); - if (isEnabled()) { - QBrush br(d_ptr->shownColor()); + const QColor color = d_ptr->shownColor(); + if (!color.isValid()) { + constexpr int size = 11; + const qreal horPadding = (width() - size) / 2.0; + const qreal verPadding = (height() - size) / 2.0; + const QPen pen(creatorTheme()->color(overlayColor), 2); + + p.save(); + p.setOpacity(overlayOpacity); + p.setPen(pen); + p.setRenderHint(QPainter::Antialiasing); + p.drawLine(QLineF(horPadding, height() - verPadding, width() - horPadding, verPadding)); + p.restore(); + } else if (isEnabled()) { + QBrush br(color); if (d_ptr->m_backgroundCheckered) { const int pixSize = 10; QPixmap pm(2 * pixSize, 2 * pixSize); @@ -170,7 +188,7 @@ void QtColorButton::paintEvent(QPaintEvent *event) QPainter pmp(&pm); pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); - pmp.fillRect(pm.rect(), d_ptr->shownColor()); + pmp.fillRect(pm.rect(), color); br = QBrush(pm); p.setBrushOrigin((width() - pixSize) / 2, (height() - pixSize) / 2); } @@ -184,8 +202,8 @@ void QtColorButton::paintEvent(QPaintEvent *event) p.setPen(pen); p.setCompositionMode(QPainter::CompositionMode_Difference); } else { - p.setPen(palette().text().color()); - p.setOpacity(0.25); + p.setPen(creatorTheme()->color(overlayColor)); + p.setOpacity(overlayOpacity); } p.drawRect(rect().adjusted(0, 0, -1, -1)); } From 556768b293c3f184719126dbff94b15fff50c0d7 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 28 Mar 2023 14:30:42 +0200 Subject: [PATCH 0445/1447] TextEditor: Use QtColorButton in ColorSchemeEdit Replaces the style-sheet based drawing. Reduces handling code. Adds Drag'n'drop capabilities. Change-Id: I7e7ff06df61ffead00d4c747c8b0f5e81de169ae Reviewed-by: Eike Ziller --- src/plugins/texteditor/colorschemeedit.cpp | 60 ++++++++-------------- src/plugins/texteditor/colorschemeedit.h | 8 +-- 2 files changed, 25 insertions(+), 43 deletions(-) diff --git a/src/plugins/texteditor/colorschemeedit.cpp b/src/plugins/texteditor/colorschemeedit.cpp index 0bd0c54015f..bd4c5b97ae4 100644 --- a/src/plugins/texteditor/colorschemeedit.cpp +++ b/src/plugins/texteditor/colorschemeedit.cpp @@ -6,13 +6,13 @@ #include "texteditortr.h" #include +#include #include #include #include #include #include -#include #include #include #include @@ -25,14 +25,6 @@ namespace TextEditor::Internal { const int layoutSpacing = 6; -static QString colorButtonStyleSheet(const QColor &bgColor) -{ - QString rc("border-width: 2px; border-radius: 2px; border-color: black; "); - rc += bgColor.isValid() ? "border-style: solid; background:" + bgColor.name() + ";" - : QString("border-style: dotted;"); - return rc; -} - class FormatsModel : public QAbstractListModel { public: @@ -132,7 +124,7 @@ ColorSchemeEdit::ColorSchemeEdit(QWidget *parent) : resize(513, 416); auto colorButton = [] () { - auto tb = new QToolButton; + auto tb = new Utils::QtColorButton; tb->setMinimumWidth(56); return tb; }; @@ -245,9 +237,9 @@ ColorSchemeEdit::ColorSchemeEdit(QWidget *parent) : connect(m_itemList->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ColorSchemeEdit::currentItemChanged); - connect(m_foregroundToolButton, &QAbstractButton::clicked, + connect(m_foregroundToolButton, &Utils::QtColorButton::colorChanged, this, &ColorSchemeEdit::changeForeColor); - connect(m_backgroundToolButton, &QAbstractButton::clicked, + connect(m_backgroundToolButton, &Utils::QtColorButton::colorChanged, this, &ColorSchemeEdit::changeBackColor); connect(m_eraseBackgroundToolButton, &QAbstractButton::clicked, this, &ColorSchemeEdit::eraseBackColor); @@ -265,7 +257,7 @@ ColorSchemeEdit::ColorSchemeEdit(QWidget *parent) : this, &ColorSchemeEdit::checkCheckBoxes); connect(m_italicCheckBox, &QAbstractButton::toggled, this, &ColorSchemeEdit::checkCheckBoxes); - connect(m_underlineColorToolButton, &QToolButton::clicked, + connect(m_underlineColorToolButton, &Utils::QtColorButton::colorChanged, this, &ColorSchemeEdit::changeUnderlineColor); connect(m_eraseUnderlineColorToolButton, &QToolButton::clicked, this, &ColorSchemeEdit::eraseUnderlineColor); @@ -347,7 +339,7 @@ void ColorSchemeEdit::updateForegroundControls() m_foregroundToolButton->setVisible(isVisible); m_eraseForegroundToolButton->setVisible(isVisible); - m_foregroundToolButton->setStyleSheet(colorButtonStyleSheet(format.foreground())); + m_foregroundToolButton->setColor(format.foreground()); m_eraseForegroundToolButton->setEnabled(!m_readOnly && m_curItem > 0 && format.foreground().isValid()); @@ -366,7 +358,7 @@ void ColorSchemeEdit::updateBackgroundControls() m_backgroundToolButton->setVisible(isVisible); m_eraseBackgroundToolButton->setVisible(isVisible); - m_backgroundToolButton->setStyleSheet(colorButtonStyleSheet(format.background())); + m_backgroundToolButton->setColor(format.background()); m_eraseBackgroundToolButton->setEnabled(!m_readOnly && m_curItem > 0 && format.background().isValid()); @@ -466,7 +458,7 @@ void ColorSchemeEdit::updateUnderlineControls() m_eraseUnderlineColorToolButton->setVisible(isVisible); m_underlineComboBox->setVisible(isVisible); - m_underlineColorToolButton->setStyleSheet(colorButtonStyleSheet(format.underlineColor())); + m_underlineColorToolButton->setColor(format.underlineColor()); m_eraseUnderlineColorToolButton->setEnabled(!m_readOnly && m_curItem > 0 && format.underlineColor().isValid()); @@ -478,11 +470,8 @@ void ColorSchemeEdit::changeForeColor() { if (m_curItem == -1) return; - QColor color = m_scheme.formatFor(m_descriptions[m_curItem].id()).foreground(); - const QColor newColor = QColorDialog::getColor(color, m_boldCheckBox->window()); - if (!newColor.isValid()) - return; - m_foregroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor)); + + const QColor newColor = m_foregroundToolButton->color(); m_eraseForegroundToolButton->setEnabled(true); for (const QModelIndex &index : m_itemList->selectionModel()->selectedRows()) { @@ -498,11 +487,8 @@ void ColorSchemeEdit::changeBackColor() { if (m_curItem == -1) return; - QColor color = m_scheme.formatFor(m_descriptions[m_curItem].id()).background(); - const QColor newColor = QColorDialog::getColor(color, m_boldCheckBox->window()); - if (!newColor.isValid()) - return; - m_backgroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor)); + + const QColor newColor = m_backgroundToolButton->color(); m_eraseBackgroundToolButton->setEnabled(true); for (const QModelIndex &index : m_itemList->selectionModel()->selectedRows()) { @@ -521,14 +507,13 @@ void ColorSchemeEdit::eraseBackColor() { if (m_curItem == -1) return; - QColor newColor; - m_backgroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor)); + m_backgroundToolButton->setColor({}); m_eraseBackgroundToolButton->setEnabled(false); const QList indexes = m_itemList->selectionModel()->selectedRows(); for (const QModelIndex &index : indexes) { const TextStyle category = m_descriptions[index.row()].id(); - m_scheme.formatFor(category).setBackground(newColor); + m_scheme.formatFor(category).setBackground({}); m_formatsModel->emitDataChanged(index); } @@ -539,14 +524,13 @@ void ColorSchemeEdit::eraseForeColor() { if (m_curItem == -1) return; - QColor newColor; - m_foregroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor)); + m_foregroundToolButton->setColor({}); m_eraseForegroundToolButton->setEnabled(false); const QList indexes = m_itemList->selectionModel()->selectedRows(); for (const QModelIndex &index : indexes) { const TextStyle category = m_descriptions[index.row()].id(); - m_scheme.formatFor(category).setForeground(newColor); + m_scheme.formatFor(category).setForeground({}); m_formatsModel->emitDataChanged(index); } @@ -635,11 +619,8 @@ void ColorSchemeEdit::changeUnderlineColor() { if (m_curItem == -1) return; - QColor color = m_scheme.formatFor(m_descriptions[m_curItem].id()).underlineColor(); - const QColor newColor = QColorDialog::getColor(color, m_boldCheckBox->window()); - if (!newColor.isValid()) - return; - m_underlineColorToolButton->setStyleSheet(colorButtonStyleSheet(newColor)); + + const QColor newColor = m_underlineColorToolButton->color(); m_eraseUnderlineColorToolButton->setEnabled(true); for (const QModelIndex &index : m_itemList->selectionModel()->selectedRows()) { @@ -653,13 +634,12 @@ void ColorSchemeEdit::eraseUnderlineColor() { if (m_curItem == -1) return; - QColor newColor; - m_underlineColorToolButton->setStyleSheet(colorButtonStyleSheet(newColor)); + m_underlineColorToolButton->setColor({}); m_eraseUnderlineColorToolButton->setEnabled(false); for (const QModelIndex &index : m_itemList->selectionModel()->selectedRows()) { const TextStyle category = m_descriptions[index.row()].id(); - m_scheme.formatFor(category).setUnderlineColor(newColor); + m_scheme.formatFor(category).setUnderlineColor({}); m_formatsModel->emitDataChanged(index); } } diff --git a/src/plugins/texteditor/colorschemeedit.h b/src/plugins/texteditor/colorschemeedit.h index 645ece9efe7..a2d57970795 100644 --- a/src/plugins/texteditor/colorschemeedit.h +++ b/src/plugins/texteditor/colorschemeedit.h @@ -20,6 +20,8 @@ class QScrollArea; class QToolButton; QT_END_NAMESPACE +namespace Utils { class QtColorButton; } + namespace TextEditor::Internal { class FormatsModel; @@ -80,10 +82,10 @@ private: QLabel *m_builtinSchemeLabel; QWidget *m_fontProperties; QLabel *m_foregroundLabel; - QToolButton *m_foregroundToolButton; + Utils::QtColorButton *m_foregroundToolButton; QAbstractButton *m_eraseForegroundToolButton; QLabel *m_backgroundLabel; - QToolButton *m_backgroundToolButton; + Utils::QtColorButton *m_backgroundToolButton; QAbstractButton *m_eraseBackgroundToolButton; QLabel *m_relativeForegroundHeadline; QLabel *m_foregroundLightnessLabel; @@ -100,7 +102,7 @@ private: QCheckBox *m_italicCheckBox; QLabel *m_underlineHeadline; QLabel *m_underlineLabel; - QToolButton *m_underlineColorToolButton; + Utils::QtColorButton *m_underlineColorToolButton; QAbstractButton *m_eraseUnderlineColorToolButton; QComboBox *m_underlineComboBox; From 82a4ea721f83c39813a44b68348df520f127a792 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 31 Mar 2023 11:39:31 +0200 Subject: [PATCH 0446/1447] TextEditor: add a virtual destructor to TextSuggestion Change-Id: I30378a5a3367a79eb3b39bc921c409ca0af04119 Reviewed-by: Eike Ziller --- src/plugins/texteditor/textdocumentlayout.cpp | 2 ++ src/plugins/texteditor/textdocumentlayout.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index a80a1b77515..2b6b77c374e 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -839,4 +839,6 @@ TextSuggestion::TextSuggestion() m_replacementDocument.setDocumentMargin(0); } +TextSuggestion::~TextSuggestion() = default; + } // namespace TextEditor diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index d4020f721c2..8ad013518c0 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -46,6 +46,7 @@ class TEXTEDITOR_EXPORT TextSuggestion { public: TextSuggestion(); + virtual ~TextSuggestion(); virtual bool apply() = 0; virtual void reset() = 0; virtual int position() = 0; From c6565611d650bfb51885e481317003e68c617eec Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 31 Mar 2023 12:09:36 +0200 Subject: [PATCH 0447/1447] RemoteLinux: Don't crash on empty test output Amends 95609cdd57. Change-Id: Id316ccf1989ac7853bdb71b22351aec7fd12fe7a Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/remotelinux/linuxdevicetester.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 0ee175ef85f..85bafe44eaf 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -13,6 +13,7 @@ #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; @@ -98,9 +99,10 @@ TaskItem GenericLinuxDeviceTesterPrivate::echoTask() const process.setCommand({m_device->filePath("echo"), {s_echoContents}}); }; const auto done = [this](const QtcProcess &process) { - const QString reply = process.cleanedStdOut().chopped(1); // Remove trailing '\n' + const QString reply = Utils::chopIfEndsWith(process.cleanedStdOut(), '\n'); if (reply != s_echoContents) - emit q->errorMessage(Tr::tr("Device replied to echo with unexpected contents.") + '\n'); + emit q->errorMessage(Tr::tr("Device replied to echo with unexpected contents: \"%1\"") + .arg(reply) + '\n'); else emit q->progressMessage(Tr::tr("Device replied to echo with expected contents.") + '\n'); }; From 9bdddd3df714bd73d4d0a08a83103b150e8fef27 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 2 Apr 2023 19:30:24 +0200 Subject: [PATCH 0448/1447] Compile fix Change-Id: If0a12d9e2b7d8782ecc65855285f95e05c816f39 Reviewed-by: Jarek Kobus --- src/plugins/qmldesigner/utils/filedownloader.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/qmldesigner/utils/filedownloader.h b/src/plugins/qmldesigner/utils/filedownloader.h index b1202e57cb8..4ecb6b49671 100644 --- a/src/plugins/qmldesigner/utils/filedownloader.h +++ b/src/plugins/qmldesigner/utils/filedownloader.h @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #pragma once +#include #include #include #include From e094e738b0cdf7204e8b6363025cae1f62a52db0 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 31 Mar 2023 12:28:54 +0200 Subject: [PATCH 0449/1447] RemoteLinux: Have an extra simple echo test First test without additional complications through quoting. Makes debugging easier. Change-Id: I3ea1a0725474fed09204fda1219cbc535bd2ef7c Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/remotelinux/linuxdevicetester.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 85bafe44eaf..af13c599e7f 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -34,7 +34,7 @@ public: QStringList commandsToTest() const; - TaskItem echoTask() const; + TaskItem echoTask(const QString &contents) const; TaskItem unameTask() const; TaskItem gathererTask() const; TaskItem transferTask(FileTransferMethod method, @@ -50,8 +50,6 @@ public: QList m_extraTests; }; -static const char s_echoContents[] = "Hello Remote World!"; - QStringList GenericLinuxDeviceTesterPrivate::commandsToTest() const { static const QStringList s_commandsToTest = {"base64", @@ -92,15 +90,15 @@ QStringList GenericLinuxDeviceTesterPrivate::commandsToTest() const return commands; } -TaskItem GenericLinuxDeviceTesterPrivate::echoTask() const +TaskItem GenericLinuxDeviceTesterPrivate::echoTask(const QString &contents) const { - const auto setup = [this](QtcProcess &process) { + const auto setup = [this, contents](QtcProcess &process) { emit q->progressMessage(Tr::tr("Sending echo to device...")); - process.setCommand({m_device->filePath("echo"), {s_echoContents}}); + process.setCommand({m_device->filePath("echo"), {contents}}); }; - const auto done = [this](const QtcProcess &process) { + const auto done = [this, contents](const QtcProcess &process) { const QString reply = Utils::chopIfEndsWith(process.cleanedStdOut(), '\n'); - if (reply != s_echoContents) + if (reply != contents) emit q->errorMessage(Tr::tr("Device replied to echo with unexpected contents: \"%1\"") .arg(reply) + '\n'); else @@ -284,7 +282,8 @@ void GenericLinuxDeviceTester::testDevice(const IDevice::Ptr &deviceConfiguratio }; QList taskItems = { - d->echoTask(), + d->echoTask("Hello"), // No quoting necessary + d->echoTask("Hello Remote World!"), // Checks quoting, too. d->unameTask(), d->gathererTask(), d->transferTasks() From 3cd0dad3d46ab41bcc7e94d02a4840973779553b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 15:19:39 +0200 Subject: [PATCH 0450/1447] RemoteLinux: Set up GenericCopy step when sftp and rsync fail Change-Id: Ia99275c9e1cabe06613a138dec87bd9c2f98b258 Reviewed-by: Christian Stenger --- src/plugins/remotelinux/linuxdevicetester.cpp | 23 +++++++---- .../remotelinux/remotelinux_constants.h | 1 + .../remotelinuxdeployconfiguration.cpp | 39 ++++++++++++------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index af13c599e7f..09f4d622820 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -24,7 +24,7 @@ namespace Internal { struct TransferStorage { - bool sftpWorks = false; + bool useGenericCopy = false; }; class GenericLinuxDeviceTesterPrivate @@ -173,8 +173,10 @@ TaskItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod method emit q->progressMessage(Tr::tr("\"%1\" is functional.\n").arg(methodName)); if (method == FileTransferMethod::Rsync) m_device->setExtraData(Constants::SupportsRSync, true); + else if (method == FileTransferMethod::Sftp) + m_device->setExtraData(Constants::SupportsSftp, true); else - storage->sftpWorks = true; + storage->useGenericCopy = true; }; const auto error = [this, method, storage](const FileTransfer &transfer) { const QString methodName = FileTransfer::transferMethodName(method); @@ -189,14 +191,21 @@ TaskItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod method .arg(methodName).arg(resultData.m_exitCode).arg(resultData.m_errorString); } emit q->errorMessage(error); - if (method == FileTransferMethod::Rsync) { + if (method == FileTransferMethod::Rsync) m_device->setExtraData(Constants::SupportsRSync, false); - if (!storage->sftpWorks) - return; + else if (method == FileTransferMethod::Sftp) + m_device->setExtraData(Constants::SupportsSftp, false); + + const QVariant supportsRSync = m_device->extraData(Constants::SupportsRSync); + const QVariant supportsSftp = m_device->extraData(Constants::SupportsSftp); + if (supportsRSync.isValid() && !supportsRSync.toBool() + && supportsSftp.isValid() && !supportsSftp.toBool()) { + const QString generic = FileTransfer::transferMethodName(FileTransferMethod::GenericCopy); const QString sftp = FileTransfer::transferMethodName(FileTransferMethod::Sftp); - const QString rsync = methodName; + const QString rsync = FileTransfer::transferMethodName(FileTransferMethod::Rsync); emit q->progressMessage(Tr::tr("\"%1\" will be used for deployment, because \"%2\" " - "is not available.\n").arg(sftp, rsync)); + "and \"%3\" are not available.\n") + .arg(generic, sftp, rsync)); } }; return TransferTest(setup, done, error); diff --git a/src/plugins/remotelinux/remotelinux_constants.h b/src/plugins/remotelinux/remotelinux_constants.h index 40cc1d1a8b1..9c428650c73 100644 --- a/src/plugins/remotelinux/remotelinux_constants.h +++ b/src/plugins/remotelinux/remotelinux_constants.h @@ -20,6 +20,7 @@ const char CustomCommandDeployStepId[] = "RemoteLinux.GenericRemoteLinuxCustomCo const char KillAppStepId[] = "RemoteLinux.KillAppStep"; const char SupportsRSync[] = "RemoteLinux.SupportsRSync"; +const char SupportsSftp[] = "RemoteLinux.SupportsSftp"; const char SourceProfile[] = "RemoteLinux.SourceProfile"; const char LinkDevice[] = "RemoteLinux.LinkDevice"; diff --git a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp index 8cacd63ff91..7f55d0a6c8b 100644 --- a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp @@ -7,15 +7,35 @@ #include "remotelinux_constants.h" #include "remotelinuxtr.h" +#include #include #include #include +#include #include using namespace ProjectExplorer; namespace RemoteLinux::Internal { +FileTransferMethod defaultTransferMethod(Kit *kit) +{ + auto runDevice = DeviceKitAspect::device(kit); + auto buildDevice = BuildDeviceKitAspect::device(kit); + + if (runDevice != buildDevice) { + // FIXME: That's not the full truth, we need support from the build + // device, too. + if (runDevice && runDevice->extraData(Constants::SupportsRSync).toBool()) + return FileTransferMethod::Rsync; + } + + if (runDevice && runDevice->extraData(Constants::SupportsSftp).toBool()) + return FileTransferMethod::Sftp; + + return FileTransferMethod::GenericCopy; +} + RemoteLinuxDeployConfigurationFactory::RemoteLinuxDeployConfigurationFactory() { setConfigBaseId(RemoteLinux::Constants::DeployToGenericLinux); @@ -40,23 +60,16 @@ RemoteLinuxDeployConfigurationFactory::RemoteLinuxDeployConfigurationFactory() addInitialStep(Constants::MakeInstallStepId, needsMakeInstall); addInitialStep(Constants::KillAppStepId); - // Todo: Check: Instead of having two different steps here, have one + // Todo: Check: Instead of having three different steps here, have one // and shift the logic into the implementation there? addInitialStep(Constants::RsyncDeployStepId, [](Target *target) { - auto runDevice = DeviceKitAspect::device(target->kit()); - auto buildDevice = BuildDeviceKitAspect::device(target->kit()); - if (runDevice == buildDevice) - return false; - // FIXME: That's not the full truth, we need support from the build - // device, too. - return runDevice && runDevice->extraData(Constants::SupportsRSync).toBool(); + return defaultTransferMethod(target->kit()) == FileTransferMethod::Rsync; }); addInitialStep(Constants::DirectUploadStepId, [](Target *target) { - auto runDevice = DeviceKitAspect::device(target->kit()); - auto buildDevice = BuildDeviceKitAspect::device(target->kit()); - if (runDevice == buildDevice) - return true; - return runDevice && !runDevice->extraData(Constants::SupportsRSync).toBool(); + return defaultTransferMethod(target->kit()) == FileTransferMethod::Sftp; + }); + addInitialStep(ProjectExplorer::Constants::COPY_FILE_STEP, [](Target *target) { + return defaultTransferMethod(target->kit()) == FileTransferMethod::GenericCopy; }); } From a8abb5ca505a7d6c09684f6b87075d9c41f06380 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 28 Mar 2023 18:22:17 +0200 Subject: [PATCH 0451/1447] RemoteLinux/Qnx: Disentangle deploy step factories further Change-Id: I5d6c9a6de05bf8284be13f877642de39f7c3d22d Reviewed-by: Christian Stenger --- .../devicesupport/devicecheckbuildstep.cpp | 104 +++++++++--------- .../devicesupport/devicecheckbuildstep.h | 14 +-- .../projectexplorerconstants.h | 1 + src/plugins/qnx/qnxconstants.h | 1 + src/plugins/qnx/qnxplugin.cpp | 27 ++--- .../remotelinux/genericdirectuploadstep.cpp | 12 +- .../remotelinux/genericdirectuploadstep.h | 3 - src/plugins/remotelinux/remotelinuxplugin.cpp | 18 ++- 8 files changed, 81 insertions(+), 99 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp index acce8bf29b6..84e3b274084 100644 --- a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.cpp @@ -4,6 +4,7 @@ #include "devicecheckbuildstep.h" #include "../kitinformation.h" +#include "../projectexplorerconstants.h" #include "../projectexplorertr.h" #include "devicemanager.h" @@ -12,60 +13,61 @@ #include -using namespace ProjectExplorer; +namespace ProjectExplorer { -DeviceCheckBuildStep::DeviceCheckBuildStep(BuildStepList *bsl, Utils::Id id) - : BuildStep(bsl, id) +class DeviceCheckBuildStep : public BuildStep { - setWidgetExpandedByDefault(false); -} - -bool DeviceCheckBuildStep::init() -{ - IDevice::ConstPtr device = DeviceKitAspect::device(kit()); - if (!device) { - Utils::Id deviceTypeId = DeviceTypeKitAspect::deviceTypeId(kit()); - IDeviceFactory *factory = IDeviceFactory::find(deviceTypeId); - if (!factory || !factory->canCreate()) { - emit addOutput(Tr::tr("No device configured."), BuildStep::OutputFormat::ErrorMessage); - return false; - } - - QMessageBox msgBox(QMessageBox::Question, Tr::tr("Set Up Device"), - Tr::tr("There is no device set up for this kit. Do you want to add a device?"), - QMessageBox::Yes|QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::Yes); - if (msgBox.exec() == QMessageBox::No) { - emit addOutput(Tr::tr("No device configured."), BuildStep::OutputFormat::ErrorMessage); - return false; - } - - IDevice::Ptr newDevice = factory->create(); - if (newDevice.isNull()) { - emit addOutput(Tr::tr("No device configured."), BuildStep::OutputFormat::ErrorMessage); - return false; - } - - DeviceManager *dm = DeviceManager::instance(); - dm->addDevice(newDevice); - - DeviceKitAspect::setDevice(kit(), newDevice); +public: + DeviceCheckBuildStep(BuildStepList *bsl, Utils::Id id) + : BuildStep(bsl, id) + { + setWidgetExpandedByDefault(false); } - return true; + bool init() override + { + IDevice::ConstPtr device = DeviceKitAspect::device(kit()); + if (!device) { + Utils::Id deviceTypeId = DeviceTypeKitAspect::deviceTypeId(kit()); + IDeviceFactory *factory = IDeviceFactory::find(deviceTypeId); + if (!factory || !factory->canCreate()) { + emit addOutput(Tr::tr("No device configured."), BuildStep::OutputFormat::ErrorMessage); + return false; + } + + QMessageBox msgBox(QMessageBox::Question, Tr::tr("Set Up Device"), + Tr::tr("There is no device set up for this kit. Do you want to add a device?"), + QMessageBox::Yes|QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + if (msgBox.exec() == QMessageBox::No) { + emit addOutput(Tr::tr("No device configured."), BuildStep::OutputFormat::ErrorMessage); + return false; + } + + IDevice::Ptr newDevice = factory->create(); + if (newDevice.isNull()) { + emit addOutput(Tr::tr("No device configured."), BuildStep::OutputFormat::ErrorMessage); + return false; + } + + DeviceManager *dm = DeviceManager::instance(); + dm->addDevice(newDevice); + + DeviceKitAspect::setDevice(kit(), newDevice); + } + + return true; + } + + void doRun() override { emit finished(true); } +}; + +// Factory + +DeviceCheckBuildStepFactory::DeviceCheckBuildStepFactory() +{ + registerStep(Constants::DEVICE_CHECK_STEP); + setDisplayName(Tr::tr("Check for a configured device")); } -void DeviceCheckBuildStep::doRun() -{ - emit finished(true); -} - -Utils::Id DeviceCheckBuildStep::stepId() -{ - return "ProjectExplorer.DeviceCheckBuildStep"; -} - -QString DeviceCheckBuildStep::displayName() -{ - return Tr::tr("Check for a configured device"); -} +} // ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.h b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.h index 8b7d3687b0f..6b7a8edb11b 100644 --- a/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.h +++ b/src/plugins/projectexplorer/devicesupport/devicecheckbuildstep.h @@ -8,18 +8,10 @@ namespace ProjectExplorer { -class PROJECTEXPLORER_EXPORT DeviceCheckBuildStep : public BuildStep +class PROJECTEXPLORER_EXPORT DeviceCheckBuildStepFactory : public BuildStepFactory { - Q_OBJECT - public: - DeviceCheckBuildStep(BuildStepList *bsl, Utils::Id id); - - bool init() override; - void doRun() override; - - static Utils::Id stepId(); - static QString displayName(); + DeviceCheckBuildStepFactory(); }; -} // namespace ProjectExplorer +} // ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index f612b9adb08..005981e697d 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -134,6 +134,7 @@ const char BUILDSTEPS_DEPLOY[] = "ProjectExplorer.BuildSteps.Deploy"; const char COPY_FILE_STEP[] = "ProjectExplorer.CopyFileStep"; const char COPY_DIRECTORY_STEP[] = "ProjectExplorer.CopyDirectoryStep"; +const char DEVICE_CHECK_STEP[] = "ProjectExplorer.DeviceCheckBuildStep"; // Language diff --git a/src/plugins/qnx/qnxconstants.h b/src/plugins/qnx/qnxconstants.h index b70db8c87e1..3b8bdd26996 100644 --- a/src/plugins/qnx/qnxconstants.h +++ b/src/plugins/qnx/qnxconstants.h @@ -15,5 +15,6 @@ const char QNX_QNX_OS_TYPE[] = "QnxOsType"; // Also used for device type. const char QNX_TOOLCHAIN_ID[] = "Qnx.QccToolChain"; const char QNX_TMP_DIR[] = "/tmp"; // /var/run is root:root drwxr-xr-x +const char QNX_DIRECT_UPLOAD_STEP_ID[] ="Qnx.DirectUploadStep"; } // Qnx::Constants diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index 5796668f8ae..7a06effc144 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -43,21 +43,22 @@ using namespace ProjectExplorer; namespace Qnx::Internal { -class QnxUploadStep : public RemoteLinux::GenericDirectUploadStep +// FIXME: Remove... +class QnxUploadStepFactory : public RemoteLinux::GenericDirectUploadStepFactory { public: - QnxUploadStep(BuildStepList *bsl, Utils::Id id) : GenericDirectUploadStep(bsl, id) {} - static Utils::Id stepId() { return "Qnx.DirectUploadStep"; } + QnxUploadStepFactory() + { + registerStep(Constants::QNX_DIRECT_UPLOAD_STEP_ID); + } }; -template -class GenericQnxDeployStepFactory : public BuildStepFactory +template +class QnxDeployStepFactory : public RemoteLinux::MakeInstallStepFactory { public: - GenericQnxDeployStepFactory() + QnxDeployStepFactory() { - registerStep(Step::stepId()); - setDisplayName(Step::displayName()); setSupportedConfiguration(Constants::QNX_QNX_DEPLOYCONFIGURATION_ID); setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } @@ -78,8 +79,8 @@ public: return prj->deploymentKnowledge() == DeploymentKnowledge::Bad && prj->hasMakeInstallEquivalent(); }); - addInitialStep(DeviceCheckBuildStep::stepId()); - addInitialStep(QnxUploadStep::stepId()); + addInitialStep(ProjectExplorer::Constants::DEVICE_CHECK_STEP); + addInitialStep(Constants::QNX_DIRECT_UPLOAD_STEP_ID); } }; @@ -95,9 +96,9 @@ public: QnxQtVersionFactory qtVersionFactory; QnxDeviceFactory deviceFactory; QnxDeployConfigurationFactory deployConfigFactory; - GenericQnxDeployStepFactory directUploadDeployFactory; - GenericQnxDeployStepFactory makeInstallDeployFactory; - GenericQnxDeployStepFactory checkBuildDeployFactory; + QnxDeployStepFactory directUploadDeployFactory; + QnxDeployStepFactory makeInstallDeployFactory; + QnxDeployStepFactory checkBuildDeployFactory; QnxRunConfigurationFactory runConfigFactory; QnxSettingsPage settingsPage; QnxToolChainFactory toolChainFactory; diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 8345f76e6d7..7a39b05af45 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -322,16 +322,6 @@ GenericDirectUploadStep::~GenericDirectUploadStep() delete d; } -Utils::Id GenericDirectUploadStep::stepId() -{ - return Constants::DirectUploadStepId; -} - -QString GenericDirectUploadStep::displayName() -{ - return Tr::tr("Upload files via SFTP"); -} - // Factory GenericDirectUploadStepFactory::GenericDirectUploadStepFactory() @@ -340,4 +330,4 @@ GenericDirectUploadStepFactory::GenericDirectUploadStepFactory() setDisplayName(Tr::tr("Upload files via SFTP")); } -} //namespace RemoteLinux +} // RemoteLinux diff --git a/src/plugins/remotelinux/genericdirectuploadstep.h b/src/plugins/remotelinux/genericdirectuploadstep.h index 048be324a89..49b9f3b5004 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.h +++ b/src/plugins/remotelinux/genericdirectuploadstep.h @@ -20,9 +20,6 @@ public: bool isDeploymentNecessary() const final; Utils::Tasking::Group deployRecipe() final; - static Utils::Id stepId(); - static QString displayName(); - private: friend class GenericDirectUploadStepPrivate; class GenericDirectUploadStepPrivate *d; diff --git a/src/plugins/remotelinux/remotelinuxplugin.cpp b/src/plugins/remotelinux/remotelinuxplugin.cpp index 73a30b27e3f..b3af1fb873d 100644 --- a/src/plugins/remotelinux/remotelinuxplugin.cpp +++ b/src/plugins/remotelinux/remotelinuxplugin.cpp @@ -34,16 +34,14 @@ using namespace Utils; namespace RemoteLinux { namespace Internal { -template -class GenericDeployStepFactory : public ProjectExplorer::BuildStepFactory +template +class RemoteLinuxDeployStepFactory : public Factory { public: - GenericDeployStepFactory() + RemoteLinuxDeployStepFactory() { - registerStep(Step::stepId()); - setDisplayName(Step::displayName()); - setSupportedConfiguration(RemoteLinux::Constants::DeployToGenericLinux); - setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); + Factory::setSupportedConfiguration(RemoteLinux::Constants::DeployToGenericLinux); + Factory::setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } }; @@ -56,11 +54,11 @@ public: RemoteLinuxDeployConfigurationFactory deployConfigurationFactory; TarPackageCreationStepFactory tarPackageCreationStepFactory; TarPackageDeployStepFactory tarPackageDeployStepFactory; - GenericDeployStepFactory genericDirectUploadStepFactory; - GenericDeployStepFactory rsyncDeployStepFactory; + RemoteLinuxDeployStepFactory genericDirectUploadStepFactory; + RemoteLinuxDeployStepFactory rsyncDeployStepFactory; CustomCommandDeployStepFactory customCommandDeployStepFactory; KillAppStepFactory killAppStepFactory; - GenericDeployStepFactory makeInstallStepFactory; + RemoteLinuxDeployStepFactory makeInstallStepFactory; RemoteLinuxRunWorkerFactory runWorkerFactory; RemoteLinuxDebugWorkerFactory debugWorkerFactory; RemoteLinuxQmlToolingWorkerFactory qmlToolingWorkerFactory; From 18045f3fe093f3e6d855c94bdfd40231d4e16b2b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 09:21:01 +0200 Subject: [PATCH 0452/1447] Terminal: Close Pane with last Terminal Closes the Terminal pane once the last terminal is closed. Opening the pane again will also open a new Terminal. Change-Id: I2f822b0058b26506250c784357ba522f29fd4078 Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/terminal/terminalpane.cpp | 30 ++++++++++++++++++--------- src/plugins/terminal/terminalpane.h | 2 ++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 3d110e764ee..35a099d410a 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -64,7 +64,6 @@ TerminalPane::TerminalPane(QObject *parent) {":/utils/images/iconoverlay_close_small.png", Theme::IconsStopToolBarColor}}) .icon()); closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); - closeTerminal.setEnabled(false); connect(&closeTerminal, &QAction::triggered, this, [this] { removeTab(m_tabWidget->currentIndex()); @@ -175,7 +174,8 @@ static std::optional startupProjectDirectory() void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) { OpenTerminalParameters parametersCopy{parameters}; - showPage(0); + if (!m_isVisible) + emit showPage(0); if (!parametersCopy.workingDirectory) { const std::optional projectDir = startupProjectDirectory(); @@ -193,17 +193,16 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) m_tabWidget->currentWidget()->setFocus(); - TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); emit navigateStateUpdate(); } void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) { - showPage(0); + if (!m_isVisible) + emit showPage(0); m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminal, title)); setupTerminalWidget(terminal); - TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); emit navigateStateUpdate(); } @@ -236,6 +235,8 @@ QWidget *TerminalPane::outputWidget(QWidget *parent) connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int index) { if (auto widget = m_tabWidget->widget(index)) widget->setFocus(); + else + emit hidePage(); }); auto terminalWidget = new TerminalWidget(parent); @@ -254,11 +255,7 @@ TerminalWidget *TerminalPane::currentTerminal() const void TerminalPane::removeTab(int index) { - if (m_tabWidget->count() > 1) - delete m_tabWidget->widget(index); - - TerminalCommands::instance().paneActions().closeTerminal.setEnabled(m_tabWidget->count() > 1); - + delete m_tabWidget->widget(index); emit navigateStateUpdate(); } @@ -322,6 +319,19 @@ void TerminalPane::clearContents() t->clearContents(); } +void TerminalPane::visibilityChanged(bool visible) +{ + if (m_isVisible == visible) + return; + + m_isVisible = visible; + + if (visible && m_tabWidget && m_tabWidget->count() == 0) + openTerminal({}); + + IOutputPane::visibilityChanged(visible); +} + void TerminalPane::setFocus() { if (const auto t = currentTerminal()) diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 5d93dcb4d9a..079d45a6712 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -27,6 +27,7 @@ public: QString displayName() const override; int priorityInStatusBar() const override; void clearContents() override; + void visibilityChanged(bool visible) override; void setFocus() override; bool hasFocus() const override; bool canFocus() const override; @@ -56,6 +57,7 @@ private: QToolButton *m_escSettingButton{nullptr}; bool m_widgetInitialized{false}; + bool m_isVisible{false}; }; } // namespace Terminal From 0015c666d2a6646cb58b9b73e839a9b52c64d71e Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 07:53:57 +0200 Subject: [PATCH 0453/1447] Docker: Fix ensureReachable return value DockerDevice::ensureReachable returned false in case a path was already mounted. Change-Id: I7b378a063dfe5380a1ead648f89911f2225c6338 Reviewed-by: hjk Reviewed-by: --- src/plugins/docker/dockerdevice.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index f1b650268e5..fa66c344492 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -725,6 +725,7 @@ bool DockerDevicePrivate::startContainer() connect(m_shell.get(), &DeviceShell::done, this, [this](const ProcessResultData &resultData) { if (m_shell) m_shell.release()->deleteLater(); + if (resultData.m_error != QProcess::UnknownError || resultData.m_exitStatus == QProcess::NormalExit) return; @@ -1248,12 +1249,18 @@ bool DockerDevicePrivate::ensureReachable(const FilePath &other) const FilePath fMount = FilePath::fromString(mount); if (other.isChildOf(fMount)) return true; + + if (fMount == other) + return true; } for (const auto &[path, containerPath] : m_temporaryMounts) { if (path.path() != containerPath.path()) continue; + if (path == other) + return true; + if (other.isChildOf(path)) return true; } From 94c4800ad8b6e591c2167c787efdff59be750f1b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 10:48:59 +0200 Subject: [PATCH 0454/1447] Terminal: Fix crash when reusing TerminalWidget Change-Id: I9d30df1abbecabd3909078e0a609fe5ba96769ae Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/terminal/terminalwidget.cpp | 6 ++++-- src/plugins/terminal/terminalwidget.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index a7b3590a599..65c19576cff 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -131,7 +131,6 @@ TerminalWidget::~TerminalWidget() // The Aggregate stuff tries to do clever deletion of the children, but we // we don't want that. m_aggregate->remove(this); - m_aggregate->remove(m_search.get()); } void TerminalWidget::setupPty() @@ -279,7 +278,10 @@ void TerminalWidget::setupSurface() { m_shellIntegration.reset(new ShellIntegration()); m_surface = std::make_unique(QSize{80, 60}, m_shellIntegration.get()); - m_search = std::make_unique(m_surface.get()); + m_search = TerminalSearchPtr(new TerminalSearch(m_surface.get()), [this](TerminalSearch *p) { + m_aggregate->remove(p); + delete p; + }); connect(m_search.get(), &TerminalSearch::hitsChanged, this, &TerminalWidget::updateViewport); connect(m_search.get(), &TerminalSearch::currentHitChanged, this, [this] { diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 215d8c6d58e..8498f35f83b 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -217,7 +217,8 @@ private: Utils::FilePath m_cwd; Utils::CommandLine m_currentCommand; - std::unique_ptr m_search; + using TerminalSearchPtr = std::unique_ptr>; + TerminalSearchPtr m_search; Aggregation::Aggregate *m_aggregate{nullptr}; SearchHit m_lastSelectedHit{}; From ea73bb9146af5ecc21978ec0bec6bec6c4b1423d Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 3 Apr 2023 08:17:38 +0200 Subject: [PATCH 0455/1447] DeviceSupport: Silence soft assert Change-Id: Ifa5bcbb799fcfeb25254a87a1e3e62bc8864bf4d Reviewed-by: hjk --- src/plugins/projectexplorer/devicesupport/idevicefactory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp index e88a1e61367..b5178445702 100644 --- a/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevicefactory.cpp @@ -67,7 +67,8 @@ IDevice::Ptr IDeviceFactory::create() const return {}; IDevice::Ptr device = m_creator(); - QTC_ASSERT(device, return {}); + if (!device) // e.g. Cancel used on the dialog to create a device + return {}; device->setDefaultDisplayName(displayName()); return device; } From 5715b8baecce2723605826254166608c0544d028 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 3 Apr 2023 11:39:23 +0200 Subject: [PATCH 0456/1447] Debugger: Execute the non-installed gdb data-dir magic ... only when there's a hope for it to help. Change-Id: I0b7215af371515a1eec8420fdf59e60037584941 Reviewed-by: Christian Stenger --- src/plugins/debugger/gdb/gdbengine.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 8a98c0e4337..23ebc1df942 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3969,11 +3969,14 @@ void GdbEngine::handleGdbStarted() //if (terminal()->isUsable()) // runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())}); - const QString uninstalledData = rp.debugger.command.executable().parentDir() - .pathAppended("data-directory/python").path(); - runCommand({"python sys.path.insert(1, '" + rp.dumperPath.path() + "')"}); - runCommand({"python sys.path.append('" + uninstalledData + "')"}); + + // This is useful (only) in custom gdb builds that did not run 'make install' + const FilePath uninstalledData = rp.debugger.command.executable().parentDir() + / "data-directory/python"; + if (uninstalledData.exists()) + runCommand({"python sys.path.append('" + uninstalledData.path() + "')"}); + runCommand({"python from gdbbridge import *"}); const QString path = debuggerSettings()->extraDumperFile.value(); From e0694c52d9f83db3a48d043c78e6573f729dba71 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 31 Mar 2023 14:07:57 +0200 Subject: [PATCH 0457/1447] RemoteLinux: Allow parsing used ports from cat output We used to run {filePath("sed"), {"-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*"} on the device side but doesn't pass quoting on double-remote setups. Chicken out by using a simpler for now command. Change-Id: I7794f803d185bd4b6b717d85c01cc250cc66f1eb Reviewed-by: Christian Stenger Reviewed-by: --- src/libs/utils/port.cpp | 32 +++++++++++++++++++++++++ src/libs/utils/port.h | 1 + src/plugins/remotelinux/linuxdevice.cpp | 14 +++++++---- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/port.cpp b/src/libs/utils/port.cpp index 3f9166a1a9d..ceab772b620 100644 --- a/src/libs/utils/port.cpp +++ b/src/libs/utils/port.cpp @@ -6,6 +6,8 @@ #include "qtcassert.h" #include "stringutils.h" +#include + #include /*! \class Utils::Port @@ -51,6 +53,36 @@ QList Port::parseFromSedOutput(const QByteArray &output) return ports; } +QList Port::parseFromCatOutput(const QByteArray &output) +{ + // Parse something like + // sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + // : 00000000:2717 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 3995881 1 0000000000000000 100 0 0 10 0 + // : 00000000:2716 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 3594482 1 0000000000000000 100 0 0 10 0 + const QRegularExpression re(".*: [[:xdigit:]]*:([[:xdigit:]]{4}).*"); + + QList ports; + const QStringList lines = QString::fromLocal8Bit(output).split('\n'); + for (const QString &line : lines) { + const QRegularExpressionMatch match = re.match(line); + if (!match.hasMatch()) + continue; + const QString portString = match.captured(1); + if (portString.size() != 4) + continue; + bool ok; + const Port port(portString.toInt(&ok, 16)); + if (ok) { + if (!ports.contains(port)) + ports << port; + } else { + qWarning("%s: Unexpected string '%s' is not a port.", + Q_FUNC_INFO, qPrintable(portString)); + } + } + return ports; +} + QList Port::parseFromNetstatOutput(const QByteArray &output) { QList ports; diff --git a/src/libs/utils/port.h b/src/libs/utils/port.h index 851b41ceaf4..3202ac5f18f 100644 --- a/src/libs/utils/port.h +++ b/src/libs/utils/port.h @@ -25,6 +25,7 @@ public: QString toString() const { return QString::number(m_port); } static QList parseFromSedOutput(const QByteArray &output); + static QList parseFromCatOutput(const QByteArray &output); static QList parseFromNetstatOutput(const QByteArray &output); friend bool operator<(const Port &p1, const Port &p2) { return p1.number() < p2.number(); } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 615ac56f4c7..d986ee88dd8 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1048,13 +1048,17 @@ PortsGatheringMethod LinuxDevice::portsGatheringMethod() const Q_UNUSED(protocol) - // /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6 - return {filePath("sed"), - "-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*", - CommandLine::Raw}; + // We used to have + // // /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6 + // return {filePath("sed"), + // "-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*", + // + // here, but that doesn't pass quoting on double-remote setups. + // Chicken out by using a simpler command. + return {filePath("cat"), {"/proc/net/tcp*"}}; }, - &Port::parseFromSedOutput + &Port::parseFromCatOutput }; } From 242d19c19d8f3cb4cc548d849bc2bbcea9377035 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 31 Mar 2023 16:52:22 +0200 Subject: [PATCH 0458/1447] CMakeProjectManager: Give some hints why deployment data looks wrong Change-Id: If42b32ca80f4144b86ff882e0db243ba9f0f5cbf Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 8 ++++++-- src/plugins/cmakeprojectmanager/cmakebuildsystem.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index ebc41fea787..02d1ca22532 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -747,7 +747,11 @@ void CMakeBuildSystem::handleParsingSucceeded(bool restoredFromBackup) m_ctestPath = tool->cmakeExecutable().withNewPath(m_reader.ctestPath()); setApplicationTargets(appTargets()); - setDeploymentData(deploymentData()); + + // Note: This is practically always wrong and resulting in an empty view. + // Setting the real data is triggered from a successful run of a + // MakeInstallStep. + setDeploymentData(deploymentDataFromFile()); QTC_ASSERT(m_waitingForParse, return ); m_waitingForParse = false; @@ -1064,7 +1068,7 @@ CommandLine CMakeBuildSystem::commandLineForTests(const QList &tests, return {m_ctestPath, args}; } -DeploymentData CMakeBuildSystem::deploymentData() const +DeploymentData CMakeBuildSystem::deploymentDataFromFile() const { DeploymentData result; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 802921f04b8..f3b26b8b4f6 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -67,7 +67,7 @@ public: const QList appTargets() const; QStringList buildTargetTitles() const; const QList &buildTargets() const; - ProjectExplorer::DeploymentData deploymentData() const; + ProjectExplorer::DeploymentData deploymentDataFromFile() const; CMakeBuildConfiguration *cmakeBuildConfiguration() const; From f1f5a7412a124ec011c5563a1120faf8343d3e8e Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 09:26:42 +0100 Subject: [PATCH 0459/1447] Utils: Send __qtc marker from stub Docker and ssh devices need the real process id on the remote device. The process stub now send this if it receives it as the first line of output. Change-Id: I5d3af39651958fc88d21c3854a0fa1d7f51547a6 Reviewed-by: Reviewed-by: David Schulz --- src/libs/utils/processinterface.cpp | 6 ++-- src/libs/utils/terminalinterface.cpp | 2 ++ src/plugins/docker/dockerdevice.cpp | 27 ++++++--------- src/tools/process_stub/main.cpp | 52 +++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/libs/utils/processinterface.cpp b/src/libs/utils/processinterface.cpp index a5e60c97a31..a2dc746905c 100644 --- a/src/libs/utils/processinterface.cpp +++ b/src/libs/utils/processinterface.cpp @@ -29,8 +29,10 @@ int ProcessInterface::controlSignalToInt(ControlSignal controlSignal) case ControlSignal::Terminate: return 15; case ControlSignal::Kill: return 9; case ControlSignal::Interrupt: return 2; - case ControlSignal::KickOff: QTC_CHECK(false); return 0; - case ControlSignal::CloseWriteChannel: QTC_CHECK(false); return 0; + case ControlSignal::KickOff: return 19; + case ControlSignal::CloseWriteChannel: + QTC_CHECK(false); + return 0; } return 0; } diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index 58d48cb910a..74831723296 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -183,6 +183,8 @@ void TerminalInterface::onStubReadyRead() emitFinished(out.mid(5).toInt(), QProcess::NormalExit); } else if (out.startsWith("crash ")) { emitFinished(out.mid(6).toInt(), QProcess::CrashExit); + } else if (out.startsWith("qtc: ")) { + emit readyRead(out.mid(5) + "\n", {}); } else { emitError(QProcess::UnknownError, msgUnexpectedOutput(out)); break; diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index fa66c344492..b7ff64ab9e3 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -164,7 +164,6 @@ public: const std::optional &env = std::nullopt, const std::optional &workDir = std::nullopt, bool interactive = false, - bool includeMarker = true, bool withPty = false); bool prepareForBuild(const Target *target); @@ -315,16 +314,17 @@ void DockerProcessImpl::start() if (m_setup.m_lowPriority) m_process.setLowPriority(); + const bool inTerminal = m_setup.m_terminalMode != TerminalMode::Off; + const bool interactive = m_setup.m_processMode == ProcessMode::Writer - || !m_setup.m_writeData.isEmpty(); + || !m_setup.m_writeData.isEmpty() || inTerminal; const CommandLine fullCommandLine = m_devicePrivate->withDockerExecCmd(m_setup.m_commandLine, m_setup.m_environment, m_setup.m_workingDirectory, interactive, - true, - m_setup.m_ptyData.has_value()); + inTerminal); m_process.setCommand(fullCommandLine); m_process.start(); @@ -472,7 +472,6 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, const std::optional &env, const std::optional &workDir, bool interactive, - bool includeMarker, bool withPty) { if (!m_settings) @@ -501,20 +500,16 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, dockerCmd.addArg(m_container); - if (includeMarker) { - dockerCmd.addArgs({"/bin/sh", "-c"}); + dockerCmd.addArgs({"/bin/sh", "-c"}); - CommandLine exec("exec"); - exec.addCommandLineAsArgs(cmd, CommandLine::Raw); + CommandLine exec("exec"); + exec.addCommandLineAsArgs(cmd, CommandLine::Raw); - CommandLine echo("echo"); - echo.addArgs("__qtc$$qtc__", CommandLine::Raw); - echo.addCommandLineWithAnd(exec); + CommandLine echo("echo"); + echo.addArgs("__qtc$$qtc__", CommandLine::Raw); + echo.addCommandLineWithAnd(exec); - dockerCmd.addCommandLineAsSingleArg(echo); - } else { - dockerCmd.addCommandLineAsArgs(cmd, CommandLine::Raw); - } + dockerCmd.addCommandLineAsSingleArg(echo); return dockerCmd; } diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index 45ac9c41f9b..3a3dd8af33b 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -137,6 +137,11 @@ void sendMsg(const QByteArray &msg) } } +void sendQtcMarker(const QByteArray &marker) +{ + sendMsg(QByteArray("qtc: ") + marker + "\n"); +} + void sendPid(int inferiorPid) { sendMsg(QString("pid %1\n").arg(inferiorPid).toUtf8()); @@ -273,6 +278,26 @@ void setupPidPollTimer() pollPidTimer.start(); #endif } + +enum class Out { StdOut, StdErr }; + +void writeToOut(const QByteArray &data, Out out) +{ +#ifdef Q_OS_WIN + static const HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE); + static const HANDLE errHandle = GetStdHandle(STD_ERROR_HANDLE); + WriteFile(out == Out::StdOut ? outHandle : errHandle, + data.constData(), + data.size(), + nullptr, + nullptr); +#else + auto fp = out == Out::StdOut ? stdout : stderr; + ::fwrite(data.constData(), 1, data.size(), fp); + ::fflush(fp); +#endif +} + void startProcess(const QString &executable, const QStringList &arguments, const QString &workingDir) { setupPidPollTimer(); @@ -292,7 +317,32 @@ void startProcess(const QString &executable, const QStringList &arguments, const QCoreApplication::instance(), &onInferiorStarted); - inferiorProcess.setProcessChannelMode(QProcess::ForwardedChannels); + inferiorProcess.setProcessChannelMode(QProcess::SeparateChannels); + + QObject::connect(&inferiorProcess, + &QProcess::readyReadStandardOutput, + QCoreApplication::instance(), + [] { + const QByteArray data = inferiorProcess.readAllStandardOutput(); + static bool isFirst = true; + if (isFirst) { + isFirst = false; + if (data.startsWith("__qtc")) { + int lineBreak = data.indexOf("\r\n"); + sendQtcMarker(data.mid(0, lineBreak)); + if (lineBreak != -1) + writeToOut(data.mid(lineBreak + 2), Out::StdOut); + return; + } + } + writeToOut(data, Out::StdOut); + }); + + QObject::connect(&inferiorProcess, + &QProcess::readyReadStandardError, + QCoreApplication::instance(), + [] { writeToOut(inferiorProcess.readAllStandardOutput(), Out::StdErr); }); + if (!(testMode && debugMode)) inferiorProcess.setInputChannelMode(QProcess::ForwardedInputChannel); inferiorProcess.setWorkingDirectory(workingDir); From b999e5700e77a5fa0a275dd1fb895090e36b65a0 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 28 Mar 2023 14:48:58 +0200 Subject: [PATCH 0460/1447] Terminal: Fix docker cmd for terminals * Fix env for terminals Change-Id: Ie16a74aeca3ad34a76af1dee0c5a01e607aabebb Reviewed-by: Cristian Adam Reviewed-by: --- src/plugins/docker/dockerdevice.cpp | 3 ++- src/plugins/terminal/terminalwidget.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index b7ff64ab9e3..c001cfb0b10 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -314,7 +314,8 @@ void DockerProcessImpl::start() if (m_setup.m_lowPriority) m_process.setLowPriority(); - const bool inTerminal = m_setup.m_terminalMode != TerminalMode::Off; + const bool inTerminal = m_setup.m_terminalMode != TerminalMode::Off + || m_setup.m_ptyData.has_value(); const bool interactive = m_setup.m_processMode == ProcessMode::Writer || !m_setup.m_writeData.isEmpty() || inTerminal; diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 65c19576cff..6ece9394c02 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -137,13 +137,14 @@ void TerminalWidget::setupPty() { m_process = std::make_unique(); - Environment env = m_openParameters.environment.value_or(Environment::systemEnvironment()); - CommandLine shellCommand = m_openParameters.shellCommand.value_or( CommandLine{TerminalSettings::instance().shell.filePath(), TerminalSettings::instance().shellArguments.value(), CommandLine::Raw}); + Environment env = m_openParameters.environment.value_or( + shellCommand.executable().deviceEnvironment()); + // For git bash on Windows env.prependOrSetPath(shellCommand.executable().parentDir()); if (env.hasKey("CLINK_NOAUTORUN")) From 0edf909b45b804852cb3acddbc8771bd7f8430de Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 31 Mar 2023 15:32:18 +0200 Subject: [PATCH 0461/1447] ProjectExplorer: Remove unconnected applicationTargetChanged Change-Id: Id6a283118c904ad13e8bcfc4b23b9dd76b3cc83f Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/projectexplorer/buildsystem.cpp | 6 +----- src/plugins/projectexplorer/buildsystem.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 4316bba9102..9a120a9863f 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -325,7 +325,6 @@ void BuildSystem::setDeploymentData(const DeploymentData &deploymentData) if (d->m_deploymentData != deploymentData) { d->m_deploymentData = deploymentData; emit deploymentDataChanged(); - emit applicationTargetsChanged(); emit target()->deploymentDataChanged(); } } @@ -337,10 +336,7 @@ DeploymentData BuildSystem::deploymentData() const void BuildSystem::setApplicationTargets(const QList &appTargets) { - if (Utils::toSet(appTargets) != Utils::toSet(d->m_appTargets)) { - d->m_appTargets = appTargets; - emit applicationTargetsChanged(); - } + d->m_appTargets = appTargets; } const QList BuildSystem::applicationTargets() const diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h index 0d19c9110ec..1cd1e41a060 100644 --- a/src/plugins/projectexplorer/buildsystem.h +++ b/src/plugins/projectexplorer/buildsystem.h @@ -152,7 +152,6 @@ signals: void parsingStarted(); void parsingFinished(bool success); void deploymentDataChanged(); - void applicationTargetsChanged(); void testInformationUpdated(); protected: From 9956740905ee16eff22f75b5d6c6a85c266fba0a Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 3 Apr 2023 23:20:22 +0300 Subject: [PATCH 0462/1447] FilePath: Optimize string compare in setParts Change-Id: Ibc390ee943ed41dfef30fbbd07e2e681d82379ba Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 3af026d9ba7..e397ffe9b74 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -438,7 +438,7 @@ void FilePath::setParts(const QStringView scheme, const QStringView host, QStrin { QTC_CHECK(!scheme.contains('/')); - if (path.startsWith(u"/./")) + if (path.length() >= 3 && path[0] == '/' && path[1] == '.' && path[2] == '/') path = path.mid(3); m_data = path.toString() + scheme.toString() + host.toString(); From 305ccfe259d44a5828b6a770ea90d7c9e189120a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 29 Mar 2023 13:45:42 +0200 Subject: [PATCH 0463/1447] Utils: Replace FilePath::onDevice() by new FilePath::withMappedPath() Basically a.onDevice(b) == b.withNewMappedPath(a), matching the order of b.withNewPath(a). Whether the (curretly docker-specific) path mapping is useful /there/, and whether some of the calls are needed at all is dubious. I added some FIXME and changed a few cases directly. Change-Id: I7514736ce922f632f1f737bc496f6783389a42b6 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/utils/devicefileaccess.cpp | 20 +++++----- src/libs/utils/filepath.cpp | 39 ++++++++++--------- src/libs/utils/filepath.h | 2 +- src/libs/utils/terminalhooks.cpp | 2 +- src/plugins/clangcodemodel/clangdclient.cpp | 2 +- .../cmakebuildconfiguration.cpp | 2 +- .../cmakeprojectmanager/cmakebuildstep.cpp | 2 +- .../cmakeprojectmanager/cmakebuildsystem.cpp | 2 +- .../cmakeprojectmanager/cmakeinstallstep.cpp | 2 +- .../cmakekitinformation.cpp | 15 ++++--- .../cmakeprojectmanager/cmakeprocess.cpp | 4 +- .../fileapidataextractor.cpp | 2 +- src/plugins/debugger/debuggerruncontrol.cpp | 4 +- src/plugins/debugger/stackframe.cpp | 2 +- src/plugins/docker/dockerdevice.cpp | 4 +- src/plugins/languageclient/client.cpp | 2 +- .../projectexplorer/abstractprocessstep.cpp | 2 +- src/plugins/projectexplorer/gcctoolchain.cpp | 2 +- .../projectexplorer/runconfiguration.cpp | 2 +- .../runconfigurationaspects.cpp | 2 +- .../python/pysidebuildconfiguration.cpp | 2 +- src/plugins/python/pythonrunconfiguration.cpp | 6 +-- src/plugins/qtsupport/baseqtversion.cpp | 4 +- src/plugins/remotelinux/linuxdevice.cpp | 2 +- src/plugins/remotelinux/makeinstallstep.cpp | 4 +- src/plugins/valgrind/callgrindengine.cpp | 2 +- tests/auto/utils/filepath/tst_filepath.cpp | 10 ++--- 27 files changed, 71 insertions(+), 73 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 1e3c771ee7e..016310744b1 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -204,11 +204,8 @@ expected_str DeviceFileAccess::copyRecursively(const FilePath &src, #ifdef UTILS_STATIC_LIBRARY return copyRecursively_fallback(src, target); #else - const FilePath tar = FilePath::fromString("tar").onDevice(target); - const FilePath targetTar = tar.searchInPath(); - - const FilePath sTar = FilePath::fromString("tar").onDevice(src); - const FilePath sourceTar = sTar.searchInPath(); + const FilePath targetTar = target.withNewPath("tar").searchInPath(); + const FilePath sourceTar = src.withNewPath("tar").searchInPath(); const bool isSrcOrTargetQrc = src.toFSPathString().startsWith(":/") || target.toFSPathString().startsWith(":/"); @@ -683,12 +680,13 @@ expected_str DesktopDeviceFileAccess::createTempFile(const FilePath &f { QTemporaryFile file(filePath.path()); file.setAutoRemove(false); - if (!file.open()) - return make_unexpected(Tr::tr("Could not create temporary file in \"%1\" (%2)").arg(filePath.toUserOutput()).arg(file.errorString())); - return FilePath::fromString(file.fileName()).onDevice(filePath); + if (!file.open()) { + return make_unexpected(Tr::tr("Could not create temporary file in \"%1\" (%2)") + .arg(filePath.toUserOutput()).arg(file.errorString())); + } + return filePath.withNewPath(file.fileName()); } - QDateTime DesktopDeviceFileAccess::lastModified(const FilePath &filePath) const { return QFileInfo(filePath.path()).lastModified(); @@ -984,7 +982,7 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file .arg(filePath.toUserOutput(), QString::fromUtf8(result.stdErr))); } - return FilePath::fromString(QString::fromUtf8(result.stdOut.trimmed())).onDevice(filePath); + return filePath.withNewPath(QString::fromUtf8(result.stdOut.trimmed())); } // Manually create a temporary/unique file. @@ -1008,7 +1006,7 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file for (QChar *it = firstX.base(); it != std::end(tmplate); ++it) { *it = chars[dist(*QRandomGenerator::global())]; } - newPath = FilePath::fromString(tmplate).onDevice(filePath); + newPath = filePath.withNewPath(tmplate); if (--maxTries == 0) { return make_unexpected(Tr::tr("Failed creating temporary file \"%1\" (too many tries)") .arg(filePath.toUserOutput())); diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index e397ffe9b74..1781831712c 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -510,14 +510,14 @@ expected_str FilePath::tmpDir() const if (needsDevice()) { const Environment env = deviceEnvironment(); if (env.hasKey("TMPDIR")) - return FilePath::fromUserInput(env.value("TMPDIR")).onDevice(*this); + return withNewPath(env.value("TMPDIR")).cleanPath(); if (env.hasKey("TEMP")) - return FilePath::fromUserInput(env.value("TEMP")).onDevice(*this); + return withNewPath(env.value("TEMP")).cleanPath(); if (env.hasKey("TMP")) - return FilePath::fromUserInput(env.value("TMP")).onDevice(*this); + return withNewPath(env.value("TMP")).cleanPath(); if (osType() != OsTypeWindows) - return FilePath("/tmp").onDevice(*this); + return withNewPath("/tmp"); return make_unexpected(QString("Could not find temporary directory on device %1") .arg(displayName())); } @@ -1416,30 +1416,31 @@ QString FilePath::calcRelativePath(const QString &absolutePath, const QString &a } /*! - Returns a path corresponding to the current object on the - same device as \a deviceTemplate. The FilePath needs to be local. + Returns a path corresponding to \a newPath object on the + same device as the current object. + + This may involve device-specific translations like converting + windows style paths to unix style paths with suitable file + system case or handling of drive letters: C:/dev/src -> /c/dev/src Example usage: \code localDir = FilePath("/tmp/workingdir"); executable = FilePath::fromUrl("docker://123/bin/ls") - realDir = localDir.onDevice(executable) + realDir = executable.withNewMappedPath(localDir) assert(realDir == FilePath::fromUrl("docker://123/tmp/workingdir")) \endcode - - \param deviceTemplate A path from which the host and scheme is taken. */ -FilePath FilePath::onDevice(const FilePath &deviceTemplate) const +FilePath FilePath::withNewMappedPath(const FilePath &newPath) const { - isSameDevice(deviceTemplate); - const bool sameDevice = scheme() == deviceTemplate.scheme() && host() == deviceTemplate.host(); + const bool sameDevice = newPath.scheme() == scheme() && newPath.host() == host(); if (sameDevice) - return *this; + return newPath; // TODO: converting paths between different non local devices is still unsupported - QTC_CHECK(!needsDevice() || !deviceTemplate.needsDevice()); - return fromParts(deviceTemplate.scheme(), - deviceTemplate.host(), - deviceTemplate.fileAccess()->mapToDevicePath(path())); + QTC_CHECK(!newPath.needsDevice() || !needsDevice()); + FilePath res; + res.setParts(scheme(), host(), fileAccess()->mapToDevicePath(newPath.path())); + return res; } /*! @@ -1486,8 +1487,8 @@ FilePath FilePath::searchInPath(const FilePaths &additionalDirs, return *this; FilePaths directories = deviceEnvironment().path(); if (needsDevice()) { - directories = Utils::transform(directories, [this](const FilePath &path) { - return path.onDevice(*this); + directories = Utils::transform(directories, [this](const FilePath &filePath) { + return withNewPath(filePath.path()); }); } if (!additionalDirs.isEmpty()) { diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 220c6de5daa..213eeb1e7b2 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -163,8 +163,8 @@ public: [[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter = {}) const; [[nodiscard]] Environment deviceEnvironment() const; - [[nodiscard]] FilePath onDevice(const FilePath &deviceTemplate) const; [[nodiscard]] FilePath withNewPath(const QString &newPath) const; + [[nodiscard]] FilePath withNewMappedPath(const FilePath &newPath) const; using IterateDirCallback = std::variant< diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index 6922f5c4304..d8e53010c30 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -27,7 +27,7 @@ FilePath defaultShellForDevice(const FilePath &deviceRoot) if (shell.isEmpty()) return shell; - return shell.onDevice(deviceRoot); + return deviceRoot.withNewMappedPath(shell); } class ExternalTerminalProcessImpl final : public TerminalInterface diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 91a850f1b18..e71764ea2aa 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -213,7 +213,7 @@ static BaseClientInterface *clientInterface(Project *project, const Utils::FileP if (settings.clangdVersion() >= QVersionNumber(16)) cmd.addArg("--rename-file-limit=0"); if (!jsonDbDir.isEmpty()) - cmd.addArg("--compile-commands-dir=" + jsonDbDir.onDevice(clangdExePath).path()); + cmd.addArg("--compile-commands-dir=" + clangdExePath.withNewMappedPath(jsonDbDir).path()); if (clangdLogServer().isDebugEnabled()) cmd.addArgs({"--log=verbose", "--pretty"}); cmd.addArg("--use-dirty-headers"); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 7cf47dc62d0..17871a590a3 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -701,7 +701,7 @@ void CMakeBuildSettingsWidget::updateConfigureDetailsWidgetsSummary( const FilePath buildDirectory = bc ? bc->buildDirectory() : "."; cmd.addArgs({"-S", m_buildSystem->projectDirectory().path()}); - cmd.addArgs({"-B", buildDirectory.onDevice(cmd.executable()).path()}); + cmd.addArgs({"-B", cmd.executable().withNewMappedPath(buildDirectory).path()}); // FIXME: Just buildDirectory.path() cmd.addArgs(configurationArguments); params.setCommandLine(cmd); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index ccb21ccfb3e..e0ce29fc75c 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -383,7 +383,7 @@ CommandLine CMakeBuildStep::cmakeCommand() const if (buildConfiguration()) buildDirectory = buildConfiguration()->buildDirectory(); - cmd.addArgs({"--build", buildDirectory.onDevice(cmd.executable()).path()}); + cmd.addArgs({"--build", cmd.executable().withNewMappedPath(buildDirectory).path()}); cmd.addArg("--target"); cmd.addArgs(Utils::transform(m_buildTargets, [this](const QString &s) { diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 02d1ca22532..5122f9a43ef 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -1303,7 +1303,7 @@ MakeInstallCommand CMakeBuildSystem::makeInstallCommand(const FilePath &installR buildDirectory = bc->buildDirectory(); cmd.command.addArg("--build"); - cmd.command.addArg(buildDirectory.onDevice(cmd.command.executable()).path()); + cmd.command.addArg(cmd.command.executable().withNewMappedPath(buildDirectory).path()); cmd.command.addArg("--target"); cmd.command.addArg(installTarget); diff --git a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp index 6e6a49523f7..2c56388804a 100644 --- a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp @@ -74,7 +74,7 @@ CommandLine CMakeInstallStep::cmakeCommand() const if (buildConfiguration()) buildDirectory = buildConfiguration()->buildDirectory(); - cmd.addArgs({"--install", buildDirectory.onDevice(cmd.executable()).path()}); + cmd.addArgs({"--install", cmd.executable().withNewMappedPath(buildDirectory).path()}); auto bs = qobject_cast(buildSystem()); if (bs && bs->isMultiConfigReader()) { diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 347c8e794c5..971b4c87445 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -1209,16 +1209,15 @@ Tasks CMakeConfigurationKitAspect::validate(const Kit *k) const FilePath tcCxxPath; for (const CMakeConfigItem &i : config) { // Do not use expand(QByteArray) as we cannot be sure the input is latin1 - const FilePath expandedValue - = FilePath::fromString(k->macroExpander()->expand(QString::fromUtf8(i.value))); + const QString expandedValue = k->macroExpander()->expand(QString::fromUtf8(i.value)); if (i.key == CMAKE_QMAKE_KEY) - qmakePath = expandedValue.onDevice(cmake->cmakeExecutable()); + qmakePath = cmake->cmakeExecutable().withNewPath(expandedValue); else if (i.key == CMAKE_C_TOOLCHAIN_KEY) - tcCPath = expandedValue.onDevice(cmake->cmakeExecutable()); + tcCPath = cmake->cmakeExecutable().withNewPath(expandedValue); else if (i.key == CMAKE_CXX_TOOLCHAIN_KEY) - tcCxxPath = expandedValue.onDevice(cmake->cmakeExecutable()); + tcCxxPath = cmake->cmakeExecutable().withNewPath(expandedValue); else if (i.key == CMAKE_PREFIX_PATH_KEY) - qtInstallDirs = CMakeConfigItem::cmakeSplitValue(expandedValue.path()); + qtInstallDirs = CMakeConfigItem::cmakeSplitValue(expandedValue); } Tasks result; @@ -1259,7 +1258,7 @@ Tasks CMakeConfigurationKitAspect::validate(const Kit *k) const if (!tcC || !tcC->isValid()) { addWarning(Tr::tr("CMake configuration has a path to a C compiler set, " "even though the kit has no valid tool chain.")); - } else if (tcCPath != tcC->compilerCommand() && tcCPath != tcC->compilerCommand().onDevice(tcCPath)) { + } else if (tcCPath != tcC->compilerCommand() && tcCPath != tcCPath.withNewMappedPath(tcC->compilerCommand())) { addWarning(Tr::tr("CMake configuration has a path to a C compiler set " "that does not match the compiler path " "configured in the tool chain of the kit.")); @@ -1275,7 +1274,7 @@ Tasks CMakeConfigurationKitAspect::validate(const Kit *k) const if (!tcCxx || !tcCxx->isValid()) { addWarning(Tr::tr("CMake configuration has a path to a C++ compiler set, " "even though the kit has no valid tool chain.")); - } else if (tcCxxPath != tcCxx->compilerCommand() && tcCxxPath != tcCxx->compilerCommand().onDevice(tcCxxPath)) { + } else if (tcCxxPath != tcCxx->compilerCommand() && tcCxxPath != tcCxxPath.withNewMappedPath(tcCxx->compilerCommand())) { addWarning(Tr::tr("CMake configuration has a path to a C++ compiler set " "that does not match the compiler path " "configured in the tool chain of the kit.")); diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 7a14143a4b9..4db0d519e76 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -67,8 +67,8 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & return; } - const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable); - const FilePath buildDirectory = parameters.buildDirectory.onDevice(cmakeExecutable); + const FilePath sourceDirectory = cmakeExecutable.withNewMappedPath(parameters.sourceDirectory); + const FilePath buildDirectory = cmakeExecutable.withNewMappedPath(parameters.buildDirectory); if (!buildDirectory.exists()) { const QString msg = ::CMakeProjectManager::Tr::tr( diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index ab79be78aea..cab07381ccd 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -264,7 +264,7 @@ QList generateBuildTargets(const PreprocessedData &input, continue; const FilePath buildDir = haveLibrariesRelativeToBuildDirectory ? buildDirectory : currentBuildDir; - FilePath tmp = buildDir.resolvePath(FilePath::fromUserInput(part).onDevice(buildDir)); + FilePath tmp = buildDir.resolvePath(buildDir.withNewPath(part)); if (f.role == "libraries") tmp = tmp.parentDir(); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index d972413bbb0..7f0dc8c3f42 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -886,8 +886,8 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm Runnable inferior = runControl->runnable(); const FilePath &debuggerExecutable = m_runParameters.debugger.command.executable(); - inferior.command.setExecutable(inferior.command.executable().onDevice(debuggerExecutable)); - inferior.workingDirectory = inferior.workingDirectory.onDevice(debuggerExecutable); + inferior.command.setExecutable(debuggerExecutable.withNewMappedPath(inferior.command.executable())); + inferior.workingDirectory = debuggerExecutable.withNewMappedPath(inferior.workingDirectory); // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...) inferior.workingDirectory = inferior.workingDirectory.normalizedPathName(); m_runParameters.inferior = inferior; diff --git a/src/plugins/debugger/stackframe.cpp b/src/plugins/debugger/stackframe.cpp index 7008900aab2..7ba504d5caf 100644 --- a/src/plugins/debugger/stackframe.cpp +++ b/src/plugins/debugger/stackframe.cpp @@ -74,7 +74,7 @@ StackFrame StackFrame::parseFrame(const GdbMi &frameMi, const DebuggerRunParamet frame.function = frameMi["function"].data(); frame.module = frameMi["module"].data(); const FilePath debugger = rp.debugger.command.executable(); - const FilePath onDevicePath = FilePath::fromUserInput(frameMi["file"].data()).onDevice(debugger); + const FilePath onDevicePath = debugger.withNewPath(frameMi["file"].data()).cleanPath(); frame.file = onDevicePath.localSource().value_or(onDevicePath); frame.line = frameMi["line"].toInt(); frame.address = frameMi["address"].toAddress(); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index c001cfb0b10..5e8fc5c521e 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -106,7 +106,7 @@ private: CommandLine createFallbackCommand(const CommandLine &cmdLine) { CommandLine result = cmdLine; - result.setExecutable(cmdLine.executable().onDevice(m_devicePath)); + result.setExecutable(m_devicePath.withNewPath(cmdLine.executable().path())); return result; } @@ -497,7 +497,7 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, } if (workDir && !workDir->isEmpty()) - dockerCmd.addArgs({"-w", workDir->onDevice(q->rootPath()).nativePath()}); + dockerCmd.addArgs({"-w", q->rootPath().withNewMappedPath(*workDir).nativePath()}); dockerCmd.addArg(m_container); diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 81811852a53..08d7429acd6 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -2114,7 +2114,7 @@ FilePath Client::serverUriToHostPath(const LanguageServerProtocol::DocumentUri & DocumentUri Client::hostPathToServerUri(const Utils::FilePath &path) const { return DocumentUri::fromFilePath(path, [&](const Utils::FilePath &clientPath) { - return clientPath.onDevice(d->m_serverDeviceTemplate); + return d->m_serverDeviceTemplate.withNewPath(clientPath.path()); }); } diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index c838458aa5d..30036fcdc5c 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -306,7 +306,7 @@ bool AbstractProcessStep::setupProcessParameters(ProcessParameters *params) cons const bool looksGood = executable.isEmpty() || executable.ensureReachable(workingDirectory); QTC_ASSERT(looksGood, return false); - params->setWorkingDirectory(workingDirectory.onDevice(executable)); + params->setWorkingDirectory(executable.withNewPath(workingDirectory.path())); return true; } diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index f8e99c32444..b145ba56b6b 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -196,7 +196,7 @@ HeaderPaths GccToolChain::gccHeaderPaths(const FilePath &gcc, } const FilePath headerPath - = FilePath::fromString(QString::fromUtf8(line)).onDevice(gcc).canonicalPath(); + = gcc.withNewPath(QString::fromUtf8(line)).canonicalPath(); if (!headerPath.isEmpty()) builtInHeaderPaths.append({headerPath, thisHeaderKind}); diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index cdb6d708c4d..928ca9db58d 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -391,7 +391,7 @@ Runnable RunConfiguration::runnable() const Runnable r; r.command = commandLine(); if (auto workingDirectoryAspect = aspect()) - r.workingDirectory = workingDirectoryAspect->workingDirectory().onDevice(r.command.executable()); + r.workingDirectory = r.command.executable().withNewPath(workingDirectoryAspect->workingDirectory().path()); if (auto environmentAspect = aspect()) r.environment = environmentAspect->environment(); if (m_runnableModifier) diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 7e278d353e9..c64fa4431aa 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -624,7 +624,7 @@ FilePath ExecutableAspect::executable() const : m_executable.filePath(); if (const IDevice::ConstPtr dev = executionDevice(m_target, m_selector)) - exe = exe.onDevice(dev->rootPath()); + exe = dev->rootPath().withNewMappedPath(exe); return exe; } diff --git a/src/plugins/python/pysidebuildconfiguration.cpp b/src/plugins/python/pysidebuildconfiguration.cpp index ce37bb67b32..eae9b4eeeae 100644 --- a/src/plugins/python/pysidebuildconfiguration.cpp +++ b/src/plugins/python/pysidebuildconfiguration.cpp @@ -63,7 +63,7 @@ PySideBuildStep::PySideBuildStep(BuildStepList *bsl, Id id) setCommandLineProvider([this] { return CommandLine(m_pysideProject->filePath(), {"build"}); }); setWorkingDirectoryProvider([this] { - return target()->project()->projectDirectory().onDevice(m_pysideProject->filePath()); + return m_pysideProject->filePath().withNewMappedPath(target()->project()->projectDirectory()); // FIXME: new path needed? }); setEnvironmentModifier([this](Environment &env) { env.prependOrSetPath(m_pysideProject->filePath().parentDir()); diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 2163e2b7ed6..dc383961172 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -216,7 +216,7 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id) currentInterpreterChanged(); setRunnableModifier([](Runnable &r) { - r.workingDirectory = r.workingDirectory.onDevice(r.command.executable()); + r.workingDirectory = r.command.executable().withNewMappedPath(r.workingDirectory); // FIXME: Needed? }); connect(PySideInstaller::instance(), &PySideInstaller::pySideInstalled, this, @@ -280,12 +280,12 @@ void PythonRunConfigurationPrivate::handlePySidePackageInfo(const PipPackageInfo = OsSpecificAspects::withExecutableSuffix(python.osType(), "pyside6-uic"); for (const FilePath &file : files) { if (file.fileName() == pySide6ProjectName) { - result.pySideProjectPath = location.resolvePath(file).onDevice(python); + result.pySideProjectPath = python.withNewMappedPath(location.resolvePath(file)); result.pySideProjectPath = result.pySideProjectPath.cleanPath(); if (!result.pySideUicPath.isEmpty()) return result; } else if (file.fileName() == pySide6UicName) { - result.pySideUicPath = location.resolvePath(file).onDevice(python); + result.pySideUicPath = python.withNewMappedPath(location.resolvePath(file)); result.pySideUicPath = result.pySideUicPath.cleanPath(); if (!result.pySideProjectPath.isEmpty()) return result; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 2012fb7470a..c96f310e0bc 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1253,7 +1253,7 @@ void QtVersionPrivate::updateVersionInfo() m_qmakeIsExecutable = true; auto fileProperty = [this](const QByteArray &name) { - return FilePath::fromUserInput(qmakeProperty(name)).onDevice(m_qmakeCommand); + return m_qmakeCommand.withNewPath(qmakeProperty(name)).cleanPath(); }; m_data.prefix = fileProperty("QT_INSTALL_PREFIX"); @@ -1774,7 +1774,7 @@ FilePath QtVersionPrivate::mkspecDirectoryFromVersionInfo(const QHash &versionInfo, diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index d986ee88dd8..96bc176cfa3 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -821,7 +821,7 @@ class ShellThreadHandler : public QObject CommandLine createFallbackCommand(const CommandLine &cmdLine) override { CommandLine result = cmdLine; - result.setExecutable(cmdLine.executable().onDevice(m_devicePath)); + result.setExecutable(m_devicePath.withNewMappedPath(cmdLine.executable())); // Needed? return result; } diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index 79c42bdf107..b078dce1a91 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -145,7 +145,7 @@ bool MakeInstallStep::init() if (!MakeStep::init()) return false; - const FilePath rootDir = installRoot().onDevice(makeCommand()); + const FilePath rootDir = makeCommand().withNewPath(installRoot().path()); // FIXME: Needed? if (rootDir.isEmpty()) { emit addTask(BuildSystemTask(Task::Error, Tr::tr("You must provide an install root."))); return false; @@ -191,7 +191,7 @@ bool MakeInstallStep::init() void MakeInstallStep::finish(ProcessResult result) { if (isSuccess(result)) { - const FilePath rootDir = installRoot().onDevice(makeCommand()); + const FilePath rootDir = makeCommand().withNewPath(installRoot().path()); // FIXME: Needed? m_deploymentData = DeploymentData(); m_deploymentData.setLocalInstallRoot(rootDir); diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 51ec76a1305..d238cb89e0c 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -201,7 +201,7 @@ void CallgrindToolRunner::run(Option option) this, &CallgrindToolRunner::controllerProcessDone); const FilePath control = - FilePath(CALLGRIND_CONTROL_BINARY).onDevice(m_valgrindRunnable.command.executable()); + m_valgrindRunnable.command.executable().withNewPath(CALLGRIND_CONTROL_BINARY); m_controllerProcess->setCommand({control, {toOptionString(option), QString::number(m_pid)}}); m_controllerProcess->setWorkingDirectory(m_valgrindRunnable.workingDirectory); m_controllerProcess->setEnvironment(m_valgrindRunnable.environment); diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index fa586ad5bcd..64888937dec 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -87,8 +87,8 @@ private slots: void startsWithDriveLetter(); void startsWithDriveLetter_data(); - void onDevice_data(); - void onDevice(); + void withNewMappedPath_data(); + void withNewMappedPath(); void stringAppended(); void stringAppended_data(); @@ -1333,7 +1333,7 @@ void tst_filepath::startsWithDriveLetter() QCOMPARE(path.startsWithDriveLetter(), expected); } -void tst_filepath::onDevice_data() +void tst_filepath::withNewMappedPath_data() { QTest::addColumn("path"); QTest::addColumn("templatePath"); @@ -1350,13 +1350,13 @@ void tst_filepath::onDevice_data() << FilePath("/a/b") << FilePath("docker://1234/c/d") << FilePath("docker://1234/a/b"); } -void tst_filepath::onDevice() +void tst_filepath::withNewMappedPath() { QFETCH(FilePath, path); QFETCH(FilePath, templatePath); QFETCH(FilePath, expected); - QCOMPARE(path.onDevice(templatePath), expected); + QCOMPARE(templatePath.withNewMappedPath(path), expected); } void tst_filepath::stringAppended_data() From 432d8e6e63251cb4d479f65f57ec5face91c9351 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 31 Mar 2023 12:10:20 +0200 Subject: [PATCH 0464/1447] RemoteLinux: Proper double-remote There seems something wrong with quoting the sed command for port access which should be fixed independently. As it is not crucial for plain deployment / run, make the test optional. Change-Id: Id82bdc7c25a7fb6e2f8799676b869216a7720cfa Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/plugins/remotelinux/linuxdevice.cpp | 112 ++++++------------ src/plugins/remotelinux/linuxdevicetester.cpp | 9 +- .../remotelinuxrunconfiguration.cpp | 3 +- 3 files changed, 47 insertions(+), 77 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 96bc176cfa3..1f344776df3 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -392,7 +392,6 @@ public: QString m_socketFilePath; SshParameters m_sshParameters; - IDevice::ConstPtr m_linkDevice; bool m_connecting = false; bool m_killed = false; @@ -596,12 +595,32 @@ SshProcessInterfacePrivate::SshProcessInterfacePrivate(SshProcessInterface *sshI void SshProcessInterfacePrivate::start() { clearForStart(); + m_sshParameters = m_device->sshParameters(); const Id linkDeviceId = Id::fromSetting(m_device->extraData(Constants::LinkDevice)); - m_linkDevice = DeviceManager::instance()->find(linkDeviceId); - m_useConnectionSharing = !m_linkDevice && SshSettings::connectionSharingEnabled(); + if (const IDevice::ConstPtr linkDevice = DeviceManager::instance()->find(linkDeviceId)) { + CommandLine cmd{linkDevice->filePath("ssh")}; + if (!m_sshParameters.userName().isEmpty()) { + cmd.addArg("-l"); + cmd.addArg(m_sshParameters.userName()); + } + cmd.addArg(m_sshParameters.host()); + + const CommandLine full = q->m_setup.m_commandLine; + if (!full.isEmpty()) { + // Empty is ok in case of opening a terminal. + cmd.addArgs(QString("echo ") + s_pidMarker + "\\$\\$" + s_pidMarker + " \\&\\& ", + CommandLine::Raw); + cmd.addCommandLineAsArgs(full, CommandLine::Raw); + } + + m_process.setCommand(cmd); + m_process.start(); + return; + } + + m_useConnectionSharing = SshSettings::connectionSharingEnabled(); - m_sshParameters = m_device->sshParameters(); // TODO: Do we really need it for master process? m_sshParameters.x11DisplayName = q->m_setup.m_extraData.value("Ssh.X11ForwardToDisplay").toString(); @@ -672,17 +691,14 @@ void SshProcessInterfacePrivate::doStart() m_process.start(); } -static CommandLine getCommandLine( - const FilePath sshBinary, - const CommandLine commandLine0, - const FilePath &workingDirectory, - const Environment &env, - const QStringList &options, - bool useX, - bool useTerminal, - bool usePidMarker, - bool sourceProfile) +CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const { + const FilePath sshBinary = SshSettings::sshFilePath(); + const bool useTerminal = q->m_setup.m_terminalMode != TerminalMode::Off || q->m_setup.m_ptyData; + const bool usePidMarker = !useTerminal; + const bool sourceProfile = m_device->extraData(Constants::SourceProfile).toBool(); + const bool useX = !m_sshParameters.x11DisplayName.isEmpty(); + CommandLine cmd{sshBinary}; if (useX) @@ -692,9 +708,13 @@ static CommandLine getCommandLine( cmd.addArg("-q"); - cmd.addArgs(options); + cmd.addArgs(m_sshParameters.connectionOptions(sshBinary)); + if (!m_socketFilePath.isEmpty()) + cmd.addArgs({"-o", "ControlPath=" + m_socketFilePath}); - CommandLine commandLine = commandLine0; + cmd.addArg(m_sshParameters.host()); + + CommandLine commandLine = q->m_setup.m_commandLine; FilePath executable = FilePath::fromParts({}, {}, commandLine.executable().path()); commandLine.setExecutable(executable); @@ -710,6 +730,7 @@ static CommandLine getCommandLine( } } + const FilePath &workingDirectory = q->m_setup.m_workingDirectory; if (!workingDirectory.isEmpty()) { inner.addArgs({"cd", workingDirectory.path()}); inner.addArgs("&&", CommandLine::Raw); @@ -718,6 +739,7 @@ static CommandLine getCommandLine( if (usePidMarker) inner.addArgs(QString("echo ") + s_pidMarker + "$$" + s_pidMarker + " && ", CommandLine::Raw); + const Environment &env = q->m_setup.m_environment; env.forEachEntry([&](const QString &key, const QString &value, bool) { inner.addArgs(key + "='" + env.expandVariables(value) + '\'', CommandLine::Raw); }); @@ -733,64 +755,6 @@ static CommandLine getCommandLine( return cmd; } -CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const -{ - const FilePath sshBinary = SshSettings::sshFilePath(); - const bool useTerminal = q->m_setup.m_terminalMode != TerminalMode::Off || q->m_setup.m_ptyData; - const bool usePidMarker = !useTerminal; - const bool sourceProfile = m_device->extraData(Constants::SourceProfile).toBool(); - const bool useX = !m_sshParameters.x11DisplayName.isEmpty(); - - CommandLine cmd; - if (m_linkDevice) { - QStringList farOptions = m_sshParameters.connectionOptions("ssh"); - farOptions << m_sshParameters.host(); - - const SshParameters nearParameters = m_linkDevice->sshParameters(); - QStringList nearOptions = nearParameters.connectionOptions(sshBinary); -// if (!m_socketFilePath.isEmpty()) -// options << "-o" << ("ControlPath=" + m_socketFilePath); - nearOptions << nearParameters.host(); - - cmd = getCommandLine("ssh", - q->m_setup.m_commandLine, - {}, - {}, - farOptions, - false, - false, - false, - false); - - cmd = getCommandLine(sshBinary, - cmd, - {}, - {}, - nearOptions, - false, - false, - usePidMarker, - false); - } else { - QStringList options = m_sshParameters.connectionOptions(sshBinary); - if (!m_socketFilePath.isEmpty()) - options << "-o" << ("ControlPath=" + m_socketFilePath); - options << m_sshParameters.host(); - - cmd = getCommandLine(sshBinary, - q->m_setup.m_commandLine, - q->m_setup.m_workingDirectory, - q->m_setup.m_environment, - options, - useX, - useTerminal, - usePidMarker, - sourceProfile); - } - - return cmd; -} - // ShellThreadHandler static SshParameters displayless(const SshParameters &sshParameters) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 09f4d622820..73a9c3f2b1f 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -154,9 +154,14 @@ TaskItem GenericLinuxDeviceTesterPrivate::gathererTask() const } }; const auto error = [this](const DeviceUsedPortsGatherer &gatherer) { - emit q->errorMessage(Tr::tr("Error gathering ports: %1").arg(gatherer.errorString()) + '\n'); + emit q->errorMessage(Tr::tr("Error gathering ports: %1").arg(gatherer.errorString()) + '\n' + + Tr::tr("Some tools will not work out of the box.\n")); + }; + + return Group { + optional, + PortGatherer(setup, done, error) }; - return PortGatherer(setup, done, error); } TaskItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod method, diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index 06128ad2ffd..42e80aae41b 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -65,7 +65,8 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Id id) QTC_ASSERT(runDevice, return); const BuildTargetInfo bti = buildTargetInfo(); const FilePath localExecutable = bti.targetFilePath; - const DeployableFile depFile = target->deploymentData().deployableForLocalFile(localExecutable); + const DeploymentData deploymentData = target->deploymentData(); + const DeployableFile depFile = deploymentData.deployableForLocalFile(localExecutable); exeAspect->setExecutable(runDevice->filePath(depFile.remoteFilePath())); symbolsAspect->setFilePath(localExecutable); From 16b9539a40c4ca8b49014136a89344a1fe7537c4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 20 Mar 2023 18:02:05 +0100 Subject: [PATCH 0465/1447] CppLocatorData: Introduce findSymbols Reuse it inside cppquickfixes.cpp. Don't use global CppModelManager::classesFilter, but more specialized and much faster CppLocatorData::findSymbols. The return value of CppLocatorData::findSymbols is a list of IndexItem::Ptr instead of LocatorFilterEntries, so that we may avoid using internalData for passing IndexItem::Ptr. Change-Id: I14591b3fcf4de34d6fea23b9f354fe898123c9af Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/cppeditor/cpplocatordata.cpp | 16 ++++++ src/plugins/cppeditor/cpplocatordata.h | 2 + src/plugins/cppeditor/cppquickfixes.cpp | 73 ++++++++++++------------ 3 files changed, 53 insertions(+), 38 deletions(-) diff --git a/src/plugins/cppeditor/cpplocatordata.cpp b/src/plugins/cppeditor/cpplocatordata.cpp index 9b260ccc2ea..a0899b0ddde 100644 --- a/src/plugins/cppeditor/cpplocatordata.cpp +++ b/src/plugins/cppeditor/cpplocatordata.cpp @@ -20,6 +20,22 @@ CppLocatorData::CppLocatorData() m_pendingDocuments.reserve(MaxPendingDocuments); } +QList CppLocatorData::findSymbols(IndexItem::ItemType type, + const QString &symbolName) const +{ + QList matches; + filterAllFiles([&](const IndexItem::Ptr &info) { + if (info->type() & type) { + if (info->symbolName() == symbolName || info->scopedSymbolName() == symbolName) + matches << info; + } + if (info->type() & IndexItem::Enum) + return IndexItem::Continue; + return IndexItem::Recurse; + }); + return matches; +} + void CppLocatorData::onDocumentUpdated(const CPlusPlus::Document::Ptr &document) { QMutexLocker locker(&m_pendingDocumentsMutex); diff --git a/src/plugins/cppeditor/cpplocatordata.h b/src/plugins/cppeditor/cpplocatordata.h index 2170deb75dd..d981eb7c04e 100644 --- a/src/plugins/cppeditor/cpplocatordata.h +++ b/src/plugins/cppeditor/cpplocatordata.h @@ -33,6 +33,8 @@ public: return; } + QList findSymbols(IndexItem::ItemType type, const QString &symbolName) const; + public slots: void onDocumentUpdated(const CPlusPlus::Document::Ptr &document); void onAboutToRemoveFiles(const QStringList &files); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 24e62a65d2c..dad99ff1344 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -10,6 +10,7 @@ #include "cppeditorwidget.h" #include "cppfunctiondecldeflink.h" #include "cppinsertvirtualmethods.h" +#include "cpplocatordata.h" #include "cpppointerdeclarationformatter.h" #include "cppquickfixassistant.h" #include "cppquickfixprojectsettings.h" @@ -1990,48 +1991,45 @@ Snapshot forwardingHeaders(const CppQuickFixInterface &interface) return result; } -bool matchName(const Name *name, QList *matches, QString *className) { +QList matchName(const Name *name, QString *className) +{ if (!name) - return false; + return {}; QString simpleName; - if (Core::ILocatorFilter *classesFilter = CppModelManager::instance()->classesFilter()) { - QFutureInterface dummy; - - const Overview oo; - if (const QualifiedNameId *qualifiedName = name->asQualifiedNameId()) { - const Name *name = qualifiedName->name(); - if (const TemplateNameId *templateName = name->asTemplateNameId()) { - *className = templateNameAsString(templateName); - } else { - simpleName = oo.prettyName(name); - *className = simpleName; - classesFilter->prepareSearch(*className); - *matches = classesFilter->matchesFor(dummy, *className); - if (matches->empty()) { - if (const Name *name = qualifiedName->base()) { - if (const TemplateNameId *templateName = name->asTemplateNameId()) - *className = templateNameAsString(templateName); - else - *className = oo.prettyName(name); - } - } - } - } else if (const TemplateNameId *templateName = name->asTemplateNameId()) { + QList matches; + CppLocatorData *locatorData = CppModelManager::instance()->locatorData(); + const Overview oo; + if (const QualifiedNameId *qualifiedName = name->asQualifiedNameId()) { + const Name *name = qualifiedName->name(); + if (const TemplateNameId *templateName = name->asTemplateNameId()) { *className = templateNameAsString(templateName); } else { - *className = oo.prettyName(name); - } - - if (matches->empty()) { - classesFilter->prepareSearch(*className); - *matches = classesFilter->matchesFor(dummy, *className); - } - if (matches->empty() && !simpleName.isEmpty()) + simpleName = oo.prettyName(name); *className = simpleName; + matches = locatorData->findSymbols(IndexItem::Class, *className); + if (matches.isEmpty()) { + if (const Name *name = qualifiedName->base()) { + if (const TemplateNameId *templateName = name->asTemplateNameId()) + *className = templateNameAsString(templateName); + else + *className = oo.prettyName(name); + } + } + } + } else if (const TemplateNameId *templateName = name->asTemplateNameId()) { + *className = templateNameAsString(templateName); + } else { + *className = oo.prettyName(name); } - return !matches->empty(); + if (matches.isEmpty()) + matches = locatorData->findSymbols(IndexItem::Class, *className); + + if (matches.isEmpty() && !simpleName.isEmpty()) + *className = simpleName; + + return matches; } } // anonymous namespace @@ -2048,17 +2046,16 @@ void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interfa return; QString className; - QList matches; const QString currentDocumentFilePath = interface.semanticInfo().doc->filePath().toString(); const ProjectExplorer::HeaderPaths headerPaths = relevantHeaderPaths(currentDocumentFilePath); FilePaths headers; + const QList matches = matchName(nameAst->name, &className); // Find an include file through the locator - if (matchName(nameAst->name, &matches, &className)) { + if (!matches.isEmpty()) { QList indexItems; const Snapshot forwardHeaders = forwardingHeaders(interface); - for (const Core::LocatorFilterEntry &entry : std::as_const(matches)) { - IndexItem::Ptr info = entry.internalData.value(); + for (const IndexItem::Ptr &info : matches) { if (!info || info->symbolName() != className) continue; indexItems << info; From 07a6d53daa9b26a2f5be219ebecad560c7c4bb43 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 09:50:49 +0200 Subject: [PATCH 0466/1447] ProjectExplorer: Add BuildConfig::BuildDirectory Change-Id: I7a05d8199c0ec12142438b4f23857abda14b87f6 Reviewed-by: hjk --- src/plugins/projectexplorer/buildconfiguration.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index fc8967aaa0b..9d36167625e 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -167,6 +167,10 @@ BuildConfiguration::BuildConfiguration(Target *target, Utils::Id id) expander->registerVariable("buildDir", Tr::tr("Build directory"), [this] { return buildDirectory().toUserOutput(); }); + expander->registerFileVariables("BuildConfig:BuildDirectory", + Tr::tr("Build directory"), + [this] { return buildDirectory(); }); + expander->registerVariable("BuildConfig:Name", Tr::tr("Name of the build configuration"), [this] { return displayName(); }); From f83dbc33160f2cd9149a2088219a5ca1c693554b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 21 Mar 2023 11:56:38 +0100 Subject: [PATCH 0467/1447] CppModelManager: Avoid using ILocatorFilter::allLocatorFilters() Use dedicated CppModelManager::functionsFilter(). Change-Id: Iafc93ae9d1d1f6a4767289238e2fd36b276611c2 Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/cppeditor/cppmodelmanager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 4f482e6c6d1..491982516a8 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -535,10 +535,7 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) const auto actionsSwitcher = std::make_shared(); // Step 1: Employ locator to find all functions - ILocatorFilter *const functionsFilter - = Utils::findOrDefault(ILocatorFilter::allLocatorFilters(), - Utils::equal(&ILocatorFilter::id, - Id(Constants::FUNCTIONS_FILTER_ID))); + ILocatorFilter *const functionsFilter = CppModelManager::instance()->functionsFilter(); QTC_ASSERT(functionsFilter, return); const QPointer search = SearchResultWindow::instance()->startNewSearch(Tr::tr("Find Unused Functions"), From 36463f3c879280cf2da9b4a482b1859017e3702a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 3 Apr 2023 21:00:48 +0200 Subject: [PATCH 0468/1447] CppLocatorFilter: Don't repeat CppLocatorData arg in c'tors It's always the same instance of: CppEditor::CppModelManager::instance()->locatorData(). Change-Id: I7d8aa2da6f0055d91b519efb6ebdf2177794e0b7 Reviewed-by: Christian Kandeler --- .../clangcodemodel/clangdlocatorfilters.cpp | 3 --- src/plugins/cppeditor/cpplocatorfilter.cpp | 19 ++++++------------- src/plugins/cppeditor/cpplocatorfilter.h | 14 ++++---------- src/plugins/cppeditor/cppmodelmanager.cpp | 6 +++--- 4 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 76a19f684f2..ebd04c538b3 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -47,7 +47,6 @@ class CppLocatorFilter : public CppEditor::CppLocatorFilter { public: CppLocatorFilter() - : CppEditor::CppLocatorFilter(CppEditor::CppModelManager::instance()->locatorData()) { setId({}); setDisplayName({}); @@ -80,7 +79,6 @@ class CppClassesFilter : public CppEditor::CppClassesFilter { public: CppClassesFilter() - : CppEditor::CppClassesFilter(CppEditor::CppModelManager::instance()->locatorData()) { setId({}); setDisplayName({}); @@ -111,7 +109,6 @@ class CppFunctionsFilter : public CppEditor::CppFunctionsFilter { public: CppFunctionsFilter() - : CppEditor::CppFunctionsFilter(CppEditor::CppModelManager::instance()->locatorData()) { setId({}); setDisplayName({}); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index b72bf261c98..144ba6b3c98 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -5,6 +5,7 @@ #include "cppeditorconstants.h" #include "cppeditortr.h" +#include "cpplocatordata.h" #include @@ -14,8 +15,7 @@ using namespace Core; namespace CppEditor { -CppLocatorFilter::CppLocatorFilter(CppLocatorData *locatorData) - : m_data(locatorData) +CppLocatorFilter::CppLocatorFilter() { setId(Constants::LOCATOR_FILTER_ID); setDisplayName(Tr::tr(Constants::LOCATOR_FILTER_DISPLAY_NAME)); @@ -23,8 +23,6 @@ CppLocatorFilter::CppLocatorFilter(CppLocatorData *locatorData) setDefaultIncludedByDefault(false); } -CppLocatorFilter::~CppLocatorFilter() = default; - LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { const QVariant id = QVariant::fromValue(info); @@ -52,7 +50,8 @@ QList CppLocatorFilter::matchesFor( const QRegularExpression shortRegexp = hasColonColon ? createRegExp(entry.mid(entry.lastIndexOf("::") + 2)) : regexp; - m_data->filterAllFiles([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult { + CppLocatorData *locatorData = CppModelManager::instance()->locatorData(); + locatorData->filterAllFiles([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult { if (future.isCanceled()) return IndexItem::Break; const IndexItem::ItemType type = info->type(); @@ -112,8 +111,7 @@ QList CppLocatorFilter::matchesFor( return std::accumulate(std::begin(entries), std::end(entries), QList()); } -CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData) - : CppLocatorFilter(locatorData) +CppClassesFilter::CppClassesFilter() { setId(Constants::CLASSES_FILTER_ID); setDisplayName(Tr::tr(Constants::CLASSES_FILTER_DISPLAY_NAME)); @@ -121,8 +119,6 @@ CppClassesFilter::CppClassesFilter(CppLocatorData *locatorData) setDefaultIncludedByDefault(false); } -CppClassesFilter::~CppClassesFilter() = default; - LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { const QVariant id = QVariant::fromValue(info); @@ -135,8 +131,7 @@ LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr inf return filterEntry; } -CppFunctionsFilter::CppFunctionsFilter(CppLocatorData *locatorData) - : CppLocatorFilter(locatorData) +CppFunctionsFilter::CppFunctionsFilter() { setId(Constants::FUNCTIONS_FILTER_ID); setDisplayName(Tr::tr(Constants::FUNCTIONS_FILTER_DISPLAY_NAME)); @@ -144,8 +139,6 @@ CppFunctionsFilter::CppFunctionsFilter(CppLocatorData *locatorData) setDefaultIncludedByDefault(false); } -CppFunctionsFilter::~CppFunctionsFilter() = default; - LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { const QVariant id = QVariant::fromValue(info); diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 0bfa8a2d2da..126853c313d 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -4,7 +4,7 @@ #pragma once #include "cppeditor_global.h" -#include "cpplocatordata.h" +#include "indexitem.h" #include @@ -15,17 +15,13 @@ class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter Q_OBJECT public: - explicit CppLocatorFilter(CppLocatorData *locatorData); - ~CppLocatorFilter() override; + explicit CppLocatorFilter(); QList matchesFor(QFutureInterface &future, const QString &entry) override; protected: virtual IndexItem::ItemType matchTypes() const { return IndexItem::All; } virtual Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info); - -protected: - CppLocatorData *m_data = nullptr; }; class CPPEDITOR_EXPORT CppClassesFilter : public CppLocatorFilter @@ -33,8 +29,7 @@ class CPPEDITOR_EXPORT CppClassesFilter : public CppLocatorFilter Q_OBJECT public: - explicit CppClassesFilter(CppLocatorData *locatorData); - ~CppClassesFilter() override; + explicit CppClassesFilter(); protected: IndexItem::ItemType matchTypes() const override { return IndexItem::Class; } @@ -46,8 +41,7 @@ class CPPEDITOR_EXPORT CppFunctionsFilter : public CppLocatorFilter Q_OBJECT public: - explicit CppFunctionsFilter(CppLocatorData *locatorData); - ~CppFunctionsFilter() override; + explicit CppFunctionsFilter(); protected: IndexItem::ItemType matchTypes() const override { return IndexItem::Function; } diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 491982516a8..0b8537925f3 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -897,10 +897,10 @@ void CppModelManager::initCppTools() &d->m_locatorData, &CppLocatorData::onAboutToRemoveFiles); // Set up builtin filters - setLocatorFilter(std::make_unique(&d->m_locatorData)); - setClassesFilter(std::make_unique(&d->m_locatorData)); + setLocatorFilter(std::make_unique()); + setClassesFilter(std::make_unique()); setIncludesFilter(std::make_unique()); - setFunctionsFilter(std::make_unique(&d->m_locatorData)); + setFunctionsFilter(std::make_unique()); setSymbolsFindFilter(std::make_unique(this)); setCurrentDocumentFilter( std::make_unique(this)); From 27fbe0c51d0bbb80c782ae1b5541f9710090ff91 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 10:13:03 +0200 Subject: [PATCH 0469/1447] ProjectExplorer: Add device root path macro Change-Id: Ie2a046c71194d2af20fb8483440bd0ffa22fda0f Reviewed-by: hjk --- .../projectexplorer/kitinformation.cpp | 79 +++++++++---------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index dcb490b70dc..9acfa27e69c 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -1023,30 +1023,29 @@ KitAspect::ItemList DeviceKitAspect::toUserOutput(const Kit *k) const void DeviceKitAspect::addToMacroExpander(Kit *kit, MacroExpander *expander) const { QTC_ASSERT(kit, return); - expander->registerVariable("Device:HostAddress", Tr::tr("Host address"), - [kit]() -> QString { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); - return device ? device->sshParameters().host() : QString(); + expander->registerVariable("Device:HostAddress", Tr::tr("Host address"), [kit] { + const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + return device ? device->sshParameters().host() : QString(); }); - expander->registerVariable("Device:SshPort", Tr::tr("SSH port"), - [kit]() -> QString { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); - return device ? QString::number(device->sshParameters().port()) : QString(); + expander->registerVariable("Device:SshPort", Tr::tr("SSH port"), [kit] { + const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + return device ? QString::number(device->sshParameters().port()) : QString(); }); - expander->registerVariable("Device:UserName", Tr::tr("User name"), - [kit]() -> QString { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); - return device ? device->sshParameters().userName() : QString(); + expander->registerVariable("Device:UserName", Tr::tr("User name"), [kit] { + const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + return device ? device->sshParameters().userName() : QString(); }); - expander->registerVariable("Device:KeyFile", Tr::tr("Private key file"), - [kit]() -> QString { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); - return device ? device->sshParameters().privateKeyFile.toString() : QString(); + expander->registerVariable("Device:KeyFile", Tr::tr("Private key file"), [kit] { + const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + return device ? device->sshParameters().privateKeyFile.toString() : QString(); }); - expander->registerVariable("Device:Name", Tr::tr("Device name"), - [kit]() -> QString { - const IDevice::ConstPtr device = DeviceKitAspect::device(kit); - return device ? device->displayName() : QString(); + expander->registerVariable("Device:Name", Tr::tr("Device name"), [kit] { + const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + return device ? device->displayName() : QString(); + }); + expander->registerFileVariables("Device::Root", Tr::tr("Device root directory"), [kit] { + const IDevice::ConstPtr device = DeviceKitAspect::device(kit); + return device ? device->rootPath() : FilePath{}; }); } @@ -1266,31 +1265,31 @@ KitAspect::ItemList BuildDeviceKitAspect::toUserOutput(const Kit *k) const void BuildDeviceKitAspect::addToMacroExpander(Kit *kit, MacroExpander *expander) const { QTC_ASSERT(kit, return); - expander->registerVariable("BuildDevice:HostAddress", Tr::tr("Build host address"), - [kit]() -> QString { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->sshParameters().host() : QString(); + expander->registerVariable("BuildDevice:HostAddress", Tr::tr("Build host address"), [kit] { + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); + return device ? device->sshParameters().host() : QString(); }); - expander->registerVariable("BuildDevice:SshPort", Tr::tr("Build SSH port"), - [kit]() -> QString { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? QString::number(device->sshParameters().port()) : QString(); + expander->registerVariable("BuildDevice:SshPort", Tr::tr("Build SSH port"), [kit] { + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); + return device ? QString::number(device->sshParameters().port()) : QString(); }); - expander->registerVariable("BuildDevice:UserName", Tr::tr("Build user name"), - [kit]() -> QString { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->sshParameters().userName() : QString(); + expander->registerVariable("BuildDevice:UserName", Tr::tr("Build user name"), [kit] { + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); + return device ? device->sshParameters().userName() : QString(); }); - expander->registerVariable("BuildDevice:KeyFile", Tr::tr("Build private key file"), - [kit]() -> QString { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->sshParameters().privateKeyFile.toString() : QString(); + expander->registerVariable("BuildDevice:KeyFile", Tr::tr("Build private key file"), [kit] { + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); + return device ? device->sshParameters().privateKeyFile.toString() : QString(); }); - expander->registerVariable("BuildDevice:Name", Tr::tr("Build device name"), - [kit]() -> QString { - const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); - return device ? device->displayName() : QString(); + expander->registerVariable("BuildDevice:Name", Tr::tr("Build device name"), [kit] { + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); + return device ? device->displayName() : QString(); }); + expander + ->registerFileVariables("BuildDevice::Root", Tr::tr("Build device root directory"), [kit] { + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(kit); + return device ? device->rootPath() : FilePath{}; + }); } Id BuildDeviceKitAspect::id() From a374dd8bfe8627c4d713a24ff06850506d081123 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 09:50:02 +0200 Subject: [PATCH 0470/1447] Utils: Fix PathChooser validation Change-Id: I5b0ad8a1011f51c5db732fe454c409812b406c17 Reviewed-by: hjk --- src/libs/utils/pathchooser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 0f0737f54c5..124fdc4cef4 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -613,8 +613,8 @@ bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) const *errorMessage = Tr::tr("The path \"%1\" is not a directory.").arg(filePath.toUserOutput()); return false; } - if (HostOsInfo::isWindowsHost() && !filePath.startsWithDriveLetter() - && !filePath.startsWith("\\\\") && !filePath.startsWith("//")) { + if (filePath.osType() == OsTypeWindows && !filePath.startsWithDriveLetter() + && !filePath.startsWith("\\\\") && !filePath.startsWith("//")) { if (errorMessage) *errorMessage = Tr::tr("Invalid path \"%1\".").arg(filePath.toUserOutput()); return false; From 4fbc56d453ef2fa73e494f371bd44285e3ac0d50 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 09:49:37 +0200 Subject: [PATCH 0471/1447] Utils: Change macro expander to use FilePath Change-Id: Ib7787d1b7f72f6b4728893636f6844e4297fcecd Reviewed-by: hjk --- src/libs/utils/macroexpander.cpp | 64 +++++++++++++++++--------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 4e24247833c..0bb91689e72 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -377,41 +377,45 @@ void MacroExpander::registerIntVariable(const QByteArray &variable, void MacroExpander::registerFileVariables(const QByteArray &prefix, const QString &heading, const FileFunction &base, bool visibleInChooser) { - registerVariable(prefix + kFilePathPostfix, - Tr::tr("%1: Full path including file name.").arg(heading), - [base]() -> QString { QString tmp = base().toString(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).filePath(); }, - visibleInChooser); + registerVariable( + prefix + kFilePathPostfix, + Tr::tr("%1: Full path including file name.").arg(heading), + [base]() -> QString { return base().toUserOutput(); }, + visibleInChooser); - registerVariable(prefix + kPathPostfix, - Tr::tr("%1: Full path excluding file name.").arg(heading), - [base]() -> QString { QString tmp = base().toString(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).path(); }, - visibleInChooser); + registerVariable( + prefix + kPathPostfix, + Tr::tr("%1: Full path excluding file name.").arg(heading), + [base]() -> QString { return base().parentDir().toUserOutput(); }, + visibleInChooser); - registerVariable(prefix + kNativeFilePathPostfix, - Tr::tr("%1: Full path including file name, with native path separator (backslash on Windows).").arg(heading), - [base]() -> QString { - QString tmp = base().toString(); - return tmp.isEmpty() ? QString() : QDir::toNativeSeparators(QFileInfo(tmp).filePath()); - }, - visibleInChooser); + registerVariable( + prefix + kNativeFilePathPostfix, + Tr::tr( + "%1: Full path including file name, with native path separator (backslash on Windows).") + .arg(heading), + [base]() -> QString { return base().nativePath(); }, + visibleInChooser); - registerVariable(prefix + kNativePathPostfix, - Tr::tr("%1: Full path excluding file name, with native path separator (backslash on Windows).").arg(heading), - [base]() -> QString { - QString tmp = base().toString(); - return tmp.isEmpty() ? QString() : QDir::toNativeSeparators(QFileInfo(tmp).path()); - }, - visibleInChooser); + registerVariable( + prefix + kNativePathPostfix, + Tr::tr( + "%1: Full path excluding file name, with native path separator (backslash on Windows).") + .arg(heading), + [base]() -> QString { return base().parentDir().nativePath(); }, + visibleInChooser); - registerVariable(prefix + kFileNamePostfix, - Tr::tr("%1: File name without path.").arg(heading), - [base]() -> QString { QString tmp = base().toString(); return tmp.isEmpty() ? QString() : FilePath::fromString(tmp).fileName(); }, - visibleInChooser); + registerVariable( + prefix + kFileNamePostfix, + Tr::tr("%1: File name without path.").arg(heading), + [base]() -> QString { return base().fileName(); }, + visibleInChooser); - registerVariable(prefix + kFileBaseNamePostfix, - Tr::tr("%1: File base name without path and suffix.").arg(heading), - [base]() -> QString { QString tmp = base().toString(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).baseName(); }, - visibleInChooser); + registerVariable( + prefix + kFileBaseNamePostfix, + Tr::tr("%1: File base name without path and suffix.").arg(heading), + [base]() -> QString { return base().baseName(); }, + visibleInChooser); } void MacroExpander::registerExtraResolver(const MacroExpander::ResolverFunction &value) From 53e81443300f068bf27497100bacbf1de636551f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 11:20:40 +0200 Subject: [PATCH 0472/1447] Utils: Remove unnecessary code Change-Id: I3844d71d3f77d49f7e84c4feae910679391fa91a Reviewed-by: Jarek Kobus --- src/libs/utils/macroexpander.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 0bb91689e72..2fe340efc6d 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -140,7 +140,7 @@ using namespace Internal; MacroExpander::registerVariable( "MyVariable", Tr::tr("The current value of whatever I want.")); - []() -> QString { + [] { QString value; // do whatever is necessary to retrieve the value [...] @@ -380,13 +380,13 @@ void MacroExpander::registerFileVariables(const QByteArray &prefix, registerVariable( prefix + kFilePathPostfix, Tr::tr("%1: Full path including file name.").arg(heading), - [base]() -> QString { return base().toUserOutput(); }, + [base] { return base().toUserOutput(); }, visibleInChooser); registerVariable( prefix + kPathPostfix, Tr::tr("%1: Full path excluding file name.").arg(heading), - [base]() -> QString { return base().parentDir().toUserOutput(); }, + [base] { return base().parentDir().toUserOutput(); }, visibleInChooser); registerVariable( @@ -394,7 +394,7 @@ void MacroExpander::registerFileVariables(const QByteArray &prefix, Tr::tr( "%1: Full path including file name, with native path separator (backslash on Windows).") .arg(heading), - [base]() -> QString { return base().nativePath(); }, + [base] { return base().nativePath(); }, visibleInChooser); registerVariable( @@ -402,19 +402,19 @@ void MacroExpander::registerFileVariables(const QByteArray &prefix, Tr::tr( "%1: Full path excluding file name, with native path separator (backslash on Windows).") .arg(heading), - [base]() -> QString { return base().parentDir().nativePath(); }, + [base] { return base().parentDir().nativePath(); }, visibleInChooser); registerVariable( prefix + kFileNamePostfix, Tr::tr("%1: File name without path.").arg(heading), - [base]() -> QString { return base().fileName(); }, + [base] { return base().fileName(); }, visibleInChooser); registerVariable( prefix + kFileBaseNamePostfix, Tr::tr("%1: File base name without path and suffix.").arg(heading), - [base]() -> QString { return base().baseName(); }, + [base] { return base().baseName(); }, visibleInChooser); } From ee52d204e6a2c26fda1740f2e5fdfc95cead7088 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 11:15:57 +0200 Subject: [PATCH 0473/1447] ProcessStub: Read correct channel Change-Id: Ib26c75f069c90290f7930becdec42bf6ff5aa3d9 Reviewed-by: Cristian Adam --- src/tools/process_stub/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index 3a3dd8af33b..ff3437659b9 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -341,7 +341,7 @@ void startProcess(const QString &executable, const QStringList &arguments, const QObject::connect(&inferiorProcess, &QProcess::readyReadStandardError, QCoreApplication::instance(), - [] { writeToOut(inferiorProcess.readAllStandardOutput(), Out::StdErr); }); + [] { writeToOut(inferiorProcess.readAllStandardError(), Out::StdErr); }); if (!(testMode && debugMode)) inferiorProcess.setInputChannelMode(QProcess::ForwardedInputChannel); From 9c182911d38c60c2043faa9839be63158acfc923 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 3 Apr 2023 09:50:51 +0200 Subject: [PATCH 0474/1447] PE/Qnx: Disentangle BuildStep factories from downstream further The idea is to only expose factories with properties and not the actual step implementations. Change-Id: I72dc3944993f898f12b6a9bec11317f87e45c648 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/buildstep.cpp | 24 +++++++++++++++++++ src/plugins/projectexplorer/buildstep.h | 1 + .../projectexplorer/projectexplorer.cpp | 2 ++ src/plugins/qnx/qnxplugin.cpp | 24 +++++-------------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 84c2fcf79ee..156aa5753f1 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -380,6 +380,29 @@ QString BuildStepFactory::displayName() const return m_displayName; } +void BuildStepFactory::cloneStep(Utils::Id exitstingStepId, Utils::Id overrideNewStepId) +{ + m_stepId = {}; + m_creator = {}; + for (BuildStepFactory *factory : BuildStepFactory::allBuildStepFactories()) { + if (factory->m_stepId == exitstingStepId) { + m_creator = factory->m_creator; + m_stepId = factory->m_stepId; + m_displayName = factory->m_displayName; + // Other bits are intentionally not copied as they are unlikely to be + // useful in the cloner's context. The cloner can/has to finish the + // setup on its own. + break; + } + } + // Existence should be guaranteed by plugin dependencies. In case it fails, + // bark and keep the factory in a state where the invalid m_stepId keeps it + // inaction. + QTC_ASSERT(m_creator, return); + if (overrideNewStepId.isValid()) + m_stepId = overrideNewStepId; +} + void BuildStepFactory::setDisplayName(const QString &displayName) { m_displayName = displayName; @@ -432,6 +455,7 @@ Id BuildStepFactory::stepId() const BuildStep *BuildStepFactory::create(BuildStepList *parent) { + QTC_ASSERT(m_creator, return nullptr); BuildStep *step = m_creator(parent); step->setDefaultDisplayName(m_displayName); return step; diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h index d0a21910afa..11adc4cf5fe 100644 --- a/src/plugins/projectexplorer/buildstep.h +++ b/src/plugins/projectexplorer/buildstep.h @@ -171,6 +171,7 @@ protected: m_stepId = id; m_creator = [id](BuildStepList *bsl) { return new BuildStepType(bsl, id); }; } + void cloneStep(Utils::Id exitstingStepId, Utils::Id overrideNewStepId = {}); void setSupportedStepList(Utils::Id id); void setSupportedStepLists(const QList &ids); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 6956d7862a3..cbf467349a1 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -36,6 +36,7 @@ #include "devicesupport/desktopdevice.h" #include "devicesupport/desktopdevicefactory.h" #include "devicesupport/devicemanager.h" +#include "devicesupport/devicecheckbuildstep.h" #include "devicesupport/devicesettingspage.h" #include "devicesupport/sshsettings.h" #include "devicesupport/sshsettingspage.h" @@ -726,6 +727,7 @@ public: cmakeRunConfigFactory.runConfigurationId() }}; + DeviceCheckBuildStepFactory deviceCheckBuildStepFactory; SanitizerOutputFormatterFactory sanitizerFormatterFactory; }; diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index 7a06effc144..d2cb1964ce5 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -33,8 +33,6 @@ #include #include -#include -#include #include #include @@ -43,22 +41,12 @@ using namespace ProjectExplorer; namespace Qnx::Internal { -// FIXME: Remove... -class QnxUploadStepFactory : public RemoteLinux::GenericDirectUploadStepFactory +class QnxDeployStepFactory : public BuildStepFactory { public: - QnxUploadStepFactory() - { - registerStep(Constants::QNX_DIRECT_UPLOAD_STEP_ID); - } -}; - -template -class QnxDeployStepFactory : public RemoteLinux::MakeInstallStepFactory -{ -public: - QnxDeployStepFactory() + QnxDeployStepFactory(Utils::Id existingStepId, Utils::Id overrideId = {}) { + cloneStep(existingStepId, overrideId); setSupportedConfiguration(Constants::QNX_QNX_DEPLOYCONFIGURATION_ID); setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } @@ -96,9 +84,9 @@ public: QnxQtVersionFactory qtVersionFactory; QnxDeviceFactory deviceFactory; QnxDeployConfigurationFactory deployConfigFactory; - QnxDeployStepFactory directUploadDeployFactory; - QnxDeployStepFactory makeInstallDeployFactory; - QnxDeployStepFactory checkBuildDeployFactory; + QnxDeployStepFactory directUploadDeployFactory{RemoteLinux::Constants::DirectUploadStepId, + Constants::QNX_DIRECT_UPLOAD_STEP_ID}; + QnxDeployStepFactory makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId}; QnxRunConfigurationFactory runConfigFactory; QnxSettingsPage settingsPage; QnxToolChainFactory toolChainFactory; From 6977d28f5589e74ef8e2e2a17035a9f4e3d8433b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 4 Apr 2023 09:52:35 +0200 Subject: [PATCH 0475/1447] RemoteLinux: Fix new port gatherer approach We need the shell to expand the glob pattern. Amends e0694c52d9f. Change-Id: Ibc8b7b68f52b17d1abe367f2b8672f40fd3bc1ee Reviewed-by: Christian Stenger --- src/plugins/remotelinux/linuxdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 1f344776df3..65d919b71ed 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1019,7 +1019,7 @@ PortsGatheringMethod LinuxDevice::portsGatheringMethod() const // // here, but that doesn't pass quoting on double-remote setups. // Chicken out by using a simpler command. - return {filePath("cat"), {"/proc/net/tcp*"}}; + return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}}; }, &Port::parseFromCatOutput From ca0bee902f9ec7eee604cc506d82a178c1e537c9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 10:39:20 +0200 Subject: [PATCH 0476/1447] ProjectExplorer: Create BuildDirectory on device The BuildDirectory is now assumed to be on the build device. The default build directory template path is resolved against the project path mapped to the build directory. Change-Id: Ie1d147d135e9e551f2ac46cbec583374d524d2d7 Reviewed-by: David Schulz --- .../cmakebuildconfiguration.cpp | 4 ++-- .../cmakeprojectmanager/cmakebuildstep.cpp | 2 +- .../cmakeprojectmanager/cmakebuildsystem.cpp | 2 +- .../cmakeprojectmanager/cmakeinstallstep.cpp | 2 +- .../cmakeprojectmanager/cmakeprocess.cpp | 2 +- .../projectexplorer/buildconfiguration.cpp | 24 +++++++++++++++---- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 17871a590a3..0b193251a4c 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -701,7 +701,7 @@ void CMakeBuildSettingsWidget::updateConfigureDetailsWidgetsSummary( const FilePath buildDirectory = bc ? bc->buildDirectory() : "."; cmd.addArgs({"-S", m_buildSystem->projectDirectory().path()}); - cmd.addArgs({"-B", cmd.executable().withNewMappedPath(buildDirectory).path()}); // FIXME: Just buildDirectory.path() + cmd.addArgs({"-B", buildDirectory.path()}); cmd.addArgs(configurationArguments); params.setCommandLine(cmd); @@ -1138,7 +1138,7 @@ static CommandLine defaultInitialCMakeCommand(const Kit *k, const QString buildT // Package manager auto setup if (Internal::CMakeSpecificSettings::instance()->packageManagerAutoSetup.value()) { cmd.addArg(QString("-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=" - "%{buildDir}/%1/auto-setup.cmake") + "%{BuildConfig:BuildDirectory:NativeFilePath}/%1/auto-setup.cmake") .arg(Constants::PACKAGE_MANAGER_DIR)); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index e0ce29fc75c..74220d9464a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -383,7 +383,7 @@ CommandLine CMakeBuildStep::cmakeCommand() const if (buildConfiguration()) buildDirectory = buildConfiguration()->buildDirectory(); - cmd.addArgs({"--build", cmd.executable().withNewMappedPath(buildDirectory).path()}); + cmd.addArgs({"--build", buildDirectory.path()}); cmd.addArg("--target"); cmd.addArgs(Utils::transform(m_buildTargets, [this](const QString &s) { diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 5122f9a43ef..9ccd87edda0 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -1303,7 +1303,7 @@ MakeInstallCommand CMakeBuildSystem::makeInstallCommand(const FilePath &installR buildDirectory = bc->buildDirectory(); cmd.command.addArg("--build"); - cmd.command.addArg(cmd.command.executable().withNewMappedPath(buildDirectory).path()); + cmd.command.addArg(buildDirectory.path()); cmd.command.addArg("--target"); cmd.command.addArg(installTarget); diff --git a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp index 2c56388804a..3f6da6e73b1 100644 --- a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp @@ -74,7 +74,7 @@ CommandLine CMakeInstallStep::cmakeCommand() const if (buildConfiguration()) buildDirectory = buildConfiguration()->buildDirectory(); - cmd.addArgs({"--install", cmd.executable().withNewMappedPath(buildDirectory).path()}); + cmd.addArgs({"--install", buildDirectory.path()}); auto bs = qobject_cast(buildSystem()); if (bs && bs->isMultiConfigReader()) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 4db0d519e76..2e2e221ba4c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -68,7 +68,7 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & } const FilePath sourceDirectory = cmakeExecutable.withNewMappedPath(parameters.sourceDirectory); - const FilePath buildDirectory = cmakeExecutable.withNewMappedPath(parameters.buildDirectory); + const FilePath buildDirectory = parameters.buildDirectory; if (!buildDirectory.exists()) { const QString msg = ::CMakeProjectManager::Tr::tr( diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 9d36167625e..124941b11a1 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -616,13 +616,27 @@ FilePath BuildConfiguration::buildDirectoryFromTemplate(const FilePath &projectD [buildType] { return buildTypeName(buildType); }); exp.registerSubProvider([kit] { return kit->macroExpander(); }); - QString buildDir = ProjectExplorerPlugin::buildDirectoryTemplate(); - qCDebug(bcLog) << "build dir template:" << buildDir; + FilePath buildDir = FilePath::fromUserInput(ProjectExplorerPlugin::buildDirectoryTemplate()); + qCDebug(bcLog) << "build dir template:" << buildDir.toUserOutput(); buildDir = exp.expand(buildDir); - qCDebug(bcLog) << "expanded build:" << buildDir; - buildDir.replace(" ", "-"); + qCDebug(bcLog) << "expanded build:" << buildDir.toUserOutput(); + buildDir = buildDir.withNewPath(buildDir.path().replace(" ", "-")); - return projectDir.resolvePath(buildDir); + auto buildDevice = BuildDeviceKitAspect::device(kit); + + if (buildDir.isAbsolutePath()) { + bool isReachable = buildDevice->ensureReachable(buildDir); + if (!isReachable) + return {}; + return buildDevice->rootPath().withNewMappedPath(buildDir); + } + + bool isReachable = buildDevice->ensureReachable(projectDir); + if (!isReachable) + return {}; + + const FilePath baseDir = buildDevice->rootPath().withNewMappedPath(projectDir); + return baseDir.resolvePath(buildDir); } /// // IBuildConfigurationFactory From a854c3d27316b41fd37fb7a6550366be74690c78 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 31 Mar 2023 14:02:36 +0200 Subject: [PATCH 0477/1447] Debugger: Put DebuggerRunConfigurationAspect into a DetailsWidget Mainly in order to put the fields into a visual frame. By default expanded. Fixes: QTCREATORBUG-27151 Change-Id: I9920d2c9f3872860e75e938ea90a9165aee5b92f Reviewed-by: hjk --- .../debuggerrunconfigurationaspect.cpp | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index ef80d58a334..d8ebd2e9b1d 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -20,6 +20,7 @@ #include +#include #include #include @@ -128,9 +129,13 @@ bool DebuggerLanguageAspect::value() const void DebuggerLanguageAspect::setValue(bool value) { - m_value = value ? EnabledLanguage : DisabledLanguage; + const DebuggerLanguageStatus status = value ? EnabledLanguage : DisabledLanguage; + const bool didChange = status != m_value; + m_value = status; if (m_checkBox) m_checkBox->setChecked(m_value); + if (didChange) + emit changed(); } void DebuggerLanguageAspect::setLabel(const QString &label) @@ -159,7 +164,31 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) static const QString env = qtcEnvironmentVariable("QTC_DEBUGGER_MULTIPROCESS"); if (env.toInt()) builder.addRow(m_multiProcessAspect); - return builder.emerge(Layouting::WithoutMargins); + + auto details = new DetailsWidget; + details->setState(DetailsWidget::Expanded); + auto innerPane = new QWidget; + details->setWidget(innerPane); + builder.attachTo(innerPane, Layouting::WithoutMargins); + + const auto setSummaryText = [this, details] { + QStringList items; + if (m_cppAspect->value()) + items.append(m_cppAspect->m_label); + if (m_qmlAspect->value()) + items.append(m_qmlAspect->m_label); + items.append(m_overrideStartupAspect->value().isEmpty() + ? Tr::tr("Without additional startup commands") + : Tr::tr("With additional startup commands")); + details->setSummaryText(items.join(". ")); + }; + setSummaryText(); + + connect(m_cppAspect, &BaseAspect::changed, this, setSummaryText); + connect(m_qmlAspect, &BaseAspect::changed, this, setSummaryText); + connect(m_overrideStartupAspect, &BaseAspect::changed, this, setSummaryText); + + return details; }); addDataExtractor(this, &DebuggerRunConfigurationAspect::useCppDebugger, &Data::useCppDebugger); From 605dfa23cdf70a875547f9a37523d546109f0000 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 20 Mar 2023 23:46:47 +0100 Subject: [PATCH 0478/1447] ILocatorFilter: Don't store IndexItem::Ptr as internalData Currently it's never read. Change-Id: If89486ad8ad74c3431fe420d83fbec9a22855f04 Reviewed-by: Christian Kandeler Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/cppeditor/cpplocatorfilter.cpp | 10 +++------- src/plugins/qmljstools/qmljsfunctionfilter.cpp | 3 +-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 144ba6b3c98..c74fc73d505 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -25,8 +25,7 @@ CppLocatorFilter::CppLocatorFilter() LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { - const QVariant id = QVariant::fromValue(info); - LocatorFilterEntry filterEntry(this, info->scopedSymbolName(), id, info->icon()); + LocatorFilterEntry filterEntry(this, info->scopedSymbolName(), {}, info->icon()); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) filterEntry.extraInfo = info->shortNativeFilePath(); @@ -121,8 +120,7 @@ CppClassesFilter::CppClassesFilter() LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { - const QVariant id = QVariant::fromValue(info); - LocatorFilterEntry filterEntry(this, info->symbolName(), id, info->icon()); + LocatorFilterEntry filterEntry(this, info->symbolName(), {}, info->icon()); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = info->symbolScope().isEmpty() ? info->shortNativeFilePath() @@ -141,8 +139,6 @@ CppFunctionsFilter::CppFunctionsFilter() LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { - const QVariant id = QVariant::fromValue(info); - QString name = info->symbolName(); QString extraInfo = info->symbolScope(); info->unqualifiedNameAndScope(name, &name, &extraInfo); @@ -152,7 +148,7 @@ LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr i extraInfo.append(" (" + info->filePath().fileName() + ')'); } - LocatorFilterEntry filterEntry(this, name + info->symbolType(), id, info->icon()); + LocatorFilterEntry filterEntry(this, name + info->symbolType(), {}, info->icon()); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index e713351e635..8d6206d0c9f 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -47,8 +47,7 @@ QList FunctionFilter::matchesFor(QFutureInterface Date: Mon, 20 Mar 2023 18:23:37 +0100 Subject: [PATCH 0479/1447] ModelEditor: Reuse CppLocatorData::findSymbols() Instead of using CppModelManager::classesFilter(). Avoid reusing LocatorFilterEntry::internalData. Change-Id: Ic59daa01b0596dee46ae4ae362e833aea4610546 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/modeleditor/elementtasks.cpp | 48 ++++++++++-------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp index 1df37cb71ca..620ee66d2c6 100644 --- a/src/plugins/modeleditor/elementtasks.cpp +++ b/src/plugins/modeleditor/elementtasks.cpp @@ -24,6 +24,7 @@ #include "qmt/project/project.h" #include +#include #include #include #include @@ -34,6 +35,7 @@ #include using namespace Core; +using namespace CppEditor; namespace ModelEditor { namespace Internal { @@ -85,23 +87,16 @@ void ElementTasks::openElement(const qmt::DElement *element, const qmt::MDiagram bool ElementTasks::hasClassDefinition(const qmt::MElement *element) const { if (auto klass = dynamic_cast(element)) { - QString qualifiedClassName = klass->umlNamespace().isEmpty() - ? klass->name() - : klass->umlNamespace() + "::" + klass->name(); - - ILocatorFilter *classesFilter = CppEditor::CppModelManager::instance()->classesFilter(); - if (!classesFilter) + const QString qualifiedClassName = klass->umlNamespace().isEmpty() ? klass->name() + : klass->umlNamespace() + "::" + klass->name(); + auto *locatorData = CppModelManager::instance()->locatorData(); + if (!locatorData) return false; - - QFutureInterface dummyInterface; - classesFilter->prepareSearch(qualifiedClassName); - const QList matches - = classesFilter->matchesFor(dummyInterface, qualifiedClassName); - for (const LocatorFilterEntry &entry : matches) { - CppEditor::IndexItem::Ptr info = qvariant_cast(entry.internalData); - if (info->scopedSymbolName() != qualifiedClassName) - continue; - return true; + const QList matches = locatorData->findSymbols(IndexItem::Class, + qualifiedClassName); + for (const IndexItem::Ptr &info : matches) { + if (info->scopedSymbolName() == qualifiedClassName) + return true; } } return false; @@ -122,23 +117,18 @@ bool ElementTasks::hasClassDefinition(const qmt::DElement *element, void ElementTasks::openClassDefinition(const qmt::MElement *element) { if (auto klass = dynamic_cast(element)) { - QString qualifiedClassName = klass->umlNamespace().isEmpty() - ? klass->name() - : klass->umlNamespace() + "::" + klass->name(); + const QString qualifiedClassName = klass->umlNamespace().isEmpty() ? klass->name() + : klass->umlNamespace() + "::" + klass->name(); - ILocatorFilter *classesFilter = CppEditor::CppModelManager::instance()->classesFilter(); - if (!classesFilter) + auto *locatorData = CppModelManager::instance()->locatorData(); + if (!locatorData) return; - - QFutureInterface dummyInterface; - classesFilter->prepareSearch(qualifiedClassName); - const QList matches - = classesFilter->matchesFor(dummyInterface, qualifiedClassName); - for (const LocatorFilterEntry &entry : matches) { - CppEditor::IndexItem::Ptr info = qvariant_cast(entry.internalData); + const QList matches = locatorData->findSymbols(IndexItem::Class, + qualifiedClassName); + for (const IndexItem::Ptr &info : matches) { if (info->scopedSymbolName() != qualifiedClassName) continue; - if (EditorManager::openEditor(entry)) + if (EditorManager::openEditorAt({info->filePath(), info->line(), info->column()})) return; } } From 2534226d26f373bab7165f980374ec4e2c439614 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 29 Mar 2023 08:09:49 +0200 Subject: [PATCH 0480/1447] RemoteLinux: Move RSyncDeployStep implementation out of sight Not needed publicly anymore. Change-Id: I07f36c2fb7f4f42a970c43a4c7ad957b0b1dfce1 Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/remotelinux/rsyncdeploystep.cpp | 21 +++++++++++++++++ src/plugins/remotelinux/rsyncdeploystep.h | 26 +-------------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 1dd46cbc286..9359df0f355 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -18,6 +18,7 @@ #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; @@ -27,6 +28,26 @@ namespace RemoteLinux { // RsyncDeployStep +class RsyncDeployStep : public AbstractRemoteLinuxDeployStep +{ +public: + RsyncDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); + ~RsyncDeployStep() override; + + static Utils::Id stepId(); + static QString displayName(); + +private: + bool isDeploymentNecessary() const final; + Utils::Tasking::Group deployRecipe() final; + Utils::Tasking::TaskItem mkdirTask(); + Utils::Tasking::TaskItem transferTask(); + + mutable ProjectExplorer::FilesToTransfer m_files; + bool m_ignoreMissingFiles = false; + QString m_flags; +}; + RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id) : AbstractRemoteLinuxDeployStep(bsl, id) { diff --git a/src/plugins/remotelinux/rsyncdeploystep.h b/src/plugins/remotelinux/rsyncdeploystep.h index eb6ac41d6d4..7450d84fcb6 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.h +++ b/src/plugins/remotelinux/rsyncdeploystep.h @@ -5,34 +5,10 @@ #include "remotelinux_export.h" -#include "abstractremotelinuxdeploystep.h" - -#include - -#include +#include namespace RemoteLinux { -class REMOTELINUX_EXPORT RsyncDeployStep : public AbstractRemoteLinuxDeployStep -{ -public: - RsyncDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); - ~RsyncDeployStep() override; - - static Utils::Id stepId(); - static QString displayName(); - -private: - bool isDeploymentNecessary() const final; - Utils::Tasking::Group deployRecipe() final; - Utils::Tasking::TaskItem mkdirTask(); - Utils::Tasking::TaskItem transferTask(); - - mutable ProjectExplorer::FilesToTransfer m_files; - bool m_ignoreMissingFiles = false; - QString m_flags; -}; - class REMOTELINUX_EXPORT RsyncDeployStepFactory : public ProjectExplorer::BuildStepFactory { From f10a524f057b51fd9d8ec03f50e3d76bacf50047 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 4 Apr 2023 16:10:21 +0200 Subject: [PATCH 0481/1447] Remove some QList::toVector() no-ops Change-Id: I4d7ecf26a2d18b7e58e8bbae8d1b12f3e73924d9 Reviewed-by: Christian Kandeler --- src/plugins/android/androidconfigurations.cpp | 2 +- src/plugins/clangtools/clangtoolsutils.cpp | 4 ++-- src/plugins/languageclient/locatorfilter.cpp | 2 +- .../qmldesigner/designercore/instances/nodeinstanceview.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 4616cff2aed..cf1b005bde5 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1169,7 +1169,7 @@ void AndroidConfigurations::removeUnusedDebuggers() uniqueNdks.append(ndkLocation); } - uniqueNdks.append(FileUtils::toFilePathList(currentConfig().getCustomNdkList()).toVector()); + uniqueNdks.append(FileUtils::toFilePathList(currentConfig().getCustomNdkList())); const QList allDebuggers = Debugger::DebuggerItemManager::debuggers(); for (const Debugger::DebuggerItem &debugger : allDebuggers) { diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index acfd768797b..2fad633bfaf 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -294,7 +294,7 @@ QStringList extraClangToolsPrependOptions() static const QStringList options = extraOptions(csaPrependOptions) + extraOptions(toolsPrependOptions); if (!options.isEmpty()) - qWarning() << "ClangTools options are prepended with " << options.toVector(); + qWarning() << "ClangTools options are prepended with " << options; return options; } @@ -305,7 +305,7 @@ QStringList extraClangToolsAppendOptions() static const QStringList options = extraOptions(csaAppendOptions) + extraOptions(toolsAppendOptions); if (!options.isEmpty()) - qWarning() << "ClangTools options are appended with " << options.toVector(); + qWarning() << "ClangTools options are appended with " << options; return options; } diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index f8b14f04bf6..6eca624ae0d 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -301,7 +301,7 @@ void WorkspaceLocatorFilter::handleResponse(Client *client, auto result = response.result().value_or(LanguageClientArray()); if (!result.isNull()) m_results.append( - Utils::transform(result.toList().toVector(), [client](const SymbolInformation &info) { + Utils::transform(result.toList(), [client](const SymbolInformation &info) { return SymbolInfoWithPathMapper{info, client->hostPathMapper()}; })); if (m_pendingRequests.isEmpty()) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 7aaed70c9dd..406a7a295d1 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -870,7 +870,7 @@ NodeInstance NodeInstanceView::activeStateInstance() const void NodeInstanceView::updateChildren(const NodeAbstractProperty &newPropertyParent) { - const QVector childNodeVector = newPropertyParent.directSubNodes().toVector(); + const QList childNodeVector = newPropertyParent.directSubNodes(); qint32 parentInstanceId = newPropertyParent.parentModelNode().internalId(); @@ -1506,7 +1506,7 @@ void NodeInstanceView::pixmapChanged(const PixmapChangedCommand &command) m_nodeInstanceServer->benchmark(Q_FUNC_INFO + QString::number(renderImageChangeSet.count())); if (!renderImageChangeSet.isEmpty()) - emitInstancesRenderImageChanged(Utils::toList(renderImageChangeSet).toVector()); + emitInstancesRenderImageChanged(Utils::toList(renderImageChangeSet)); if (!containerVector.isEmpty()) { QMultiHash informationChangeHash = informationChanged( From 5a5d6f7548b02efeabce7eccadeee685e2aeb0e3 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 3 Apr 2023 07:38:23 +0200 Subject: [PATCH 0482/1447] Android: Silence soft assert Change-Id: Ie4916e2de2cb51388df674219a45df0e7d4d5abf Reviewed-by: Alessandro Portale --- src/plugins/android/androidsettingswidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index ae2d28ae1aa..21fe13ad8ba 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -718,7 +718,7 @@ void AndroidSettingsWidget::updateUI() const bool openSslOk = m_openSslSummary->allRowsOk(); const QListWidgetItem *currentItem = m_ndkListWidget->currentItem(); - const FilePath currentNdk = FilePath::fromString(currentItem ? currentItem->text() : ""); + const FilePath currentNdk = FilePath::fromUserInput(currentItem ? currentItem->text() : ""); const QString infoText = Tr::tr("(SDK Version: %1, NDK Version: %2)") .arg(m_androidConfig.sdkToolsVersion().toString()) .arg(currentNdk.isEmpty() ? "" : m_androidConfig.ndkVersion(currentNdk).toString()); From fbd3285a7f888c9520dc9732b006423f009a3f80 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 4 Apr 2023 16:22:20 +0200 Subject: [PATCH 0483/1447] ProjectExplorer: Add functions to iterate over FolderNode child subsets Will be used to avoid some of the temporary lists created by FolderNode::{file,folder}Nodes. Change-Id: Icc4bd1473a480971230a0d2426b993afb82648e0 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectnodes.cpp | 16 ++++++++++++++++ src/plugins/projectexplorer/projectnodes.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 10699b7d90d..cdd926b5822 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -547,6 +547,22 @@ void FolderNode::forEachProjectNode(const std::function &fileTask) const +{ + for (const std::unique_ptr &n : m_nodes) { + if (FileNode *fn = n->asFileNode()) + fileTask(fn); + } +} + +void FolderNode::forEachFolderNode(const std::function &folderTask) const +{ + for (const std::unique_ptr &n : m_nodes) { + if (FolderNode *fn = n->asFolderNode()) + folderTask(fn); + } +} + ProjectNode *FolderNode::findProjectNode(const std::function &predicate) { if (ProjectNode *projectNode = asProjectNode()) { diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 58fbf9cb925..dd14913e2f9 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -230,6 +230,8 @@ public: const std::function &folderFilterTask = {}) const; void forEachGenericNode(const std::function &genericTask) const; void forEachProjectNode(const std::function &genericTask) const; + void forEachFileNode(const std::function &fileTask) const; + void forEachFolderNode(const std::function &folderTask) const; ProjectNode *findProjectNode(const std::function &predicate); const QList nodes() const; QList fileNodes() const; From 79c8e60a220b998cac3e60a50d0c5e2cd92e03be Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 4 Apr 2023 23:44:30 +0200 Subject: [PATCH 0484/1447] WorkspaceLocatorFilter: Get rid of prepareSearchHelper Filter out in advance the clients for which locators are not enabled. Change-Id: I74234fb39db737db86a0d6320f53297bcaa89a8a Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/languageclient/locatorfilter.cpp | 14 ++++---------- src/plugins/languageclient/locatorfilter.h | 5 ++--- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 6eca624ae0d..1b5b64d528c 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -218,16 +218,12 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter void WorkspaceLocatorFilter::prepareSearch(const QString &entry) { - prepareSearchHelper(entry, LanguageClientManager::clients(), false); + prepareSearchForClients(entry, Utils::filtered(LanguageClientManager::clients(), + &Client::locatorsEnabled)); } -void WorkspaceLocatorFilter::prepareSearchForClients(const QString &entry, const QList &clients) -{ - prepareSearchHelper(entry, clients, true); -} - -void WorkspaceLocatorFilter::prepareSearchHelper(const QString &entry, - const QList &clients, bool force) +void WorkspaceLocatorFilter::prepareSearchForClients(const QString &entry, + const QList &clients) { m_pendingRequests.clear(); m_results.clear(); @@ -244,8 +240,6 @@ void WorkspaceLocatorFilter::prepareSearchHelper(const QString &entry, for (auto client : std::as_const(clients)) { if (!client->reachable()) continue; - if (!(force || client->locatorsEnabled())) - continue; std::optional> capability = client->capabilities().workspaceSymbolProvider(); if (!capability.has_value()) diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index e37b013ef71..769fd39ba69 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -78,8 +78,6 @@ public: /// request workspace symbols for all clients with enabled locator void prepareSearch(const QString &entry) override; - /// force request workspace symbols for all given clients - void prepareSearchForClients(const QString &entry, const QList &clients); QList matchesFor(QFutureInterface &future, const QString &entry) override; signals: @@ -88,10 +86,11 @@ signals: protected: explicit WorkspaceLocatorFilter(const QVector &filter); + /// force request workspace symbols for all given clients + void prepareSearchForClients(const QString &entry, const QList &clients); void setMaxResultCount(qint64 limit) { m_maxResultCount = limit; } private: - void prepareSearchHelper(const QString &entry, const QList &clients, bool force); void handleResponse(Client *client, const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); From a22e3acf2841632bcca5fccdbb7718543deb5079 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 21 Mar 2023 00:07:22 +0100 Subject: [PATCH 0485/1447] LocatorFilterEntry: Discourage the use of internalData Drop internalData from c'tor. The internalData is going to be removed, soon. Drop also the icon arg from c'tor since LocatorFilterEntry instances are usually created in non-main thread, while operating on QIcon instances isn't really safe in non-main thread. The use of QIcon inside this struct is a subject to change in the future, in a way like it was done in other parts of code that generated icons from non-main thread. Change-Id: Ic6aa719a64e5fbd65883c54149796057c632780e Reviewed-by: David Schulz Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/bookmarks/bookmarkfilter.cpp | 4 ++-- src/plugins/coreplugin/actionsfilter.cpp | 14 ++++++++++---- .../coreplugin/locator/commandlocator.cpp | 3 ++- .../coreplugin/locator/externaltoolsfilter.cpp | 5 +++-- src/plugins/coreplugin/locator/ilocatorfilter.h | 9 ++------- .../coreplugin/locator/javascriptfilter.cpp | 16 ++++++++++++---- .../coreplugin/locator/locatorfiltersfilter.cpp | 7 +++---- .../cppeditor/cppcurrentdocumentfilter.cpp | 3 ++- src/plugins/cppeditor/cpplocatorfilter.cpp | 9 ++++++--- src/plugins/help/helpindexfilter.cpp | 3 ++- src/plugins/macros/macrolocatorfilter.cpp | 3 ++- src/plugins/texteditor/linenumberfilter.cpp | 4 +++- 12 files changed, 49 insertions(+), 31 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index d659885a548..2fad930d37e 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -59,8 +59,8 @@ void BookmarkFilter::prepareSearch(const QString &entry) const Bookmark *bookmark = m_manager->bookmarkForIndex(idx); const QString filename = bookmark->filePath().fileName(); LocatorFilterEntry filterEntry(this, - QString("%1:%2").arg(filename).arg(bookmark->lineNumber()), - QVariant::fromValue(idx)); + QString("%1:%2").arg(filename).arg(bookmark->lineNumber())); + filterEntry.internalData = QVariant::fromValue(idx); if (!bookmark->note().isEmpty()) filterEntry.extraInfo = bookmark->note(); else if (!bookmark->lineText().isEmpty()) diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index 00c1be83e52..9aaf5a1db74 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -215,7 +215,9 @@ void ActionsFilter::collectEntriesForAction(QAction *action, } } else if (!text.isEmpty()) { const ActionFilterEntryData data{action, {}}; - LocatorFilterEntry filterEntry(this, text, QVariant::fromValue(data), action->icon()); + LocatorFilterEntry filterEntry(this, text); + filterEntry.internalData = QVariant::fromValue(data); + filterEntry.displayIcon = action->icon(); filterEntry.extraInfo = path.join(" > "); updateEntry(action, filterEntry); } @@ -241,8 +243,10 @@ void ActionsFilter::collectEntriesForCommands() const QString identifier = command->id().toString(); const QStringList path = identifier.split(QLatin1Char('.')); - const ActionFilterEntryData data{action, command->id()}; - LocatorFilterEntry filterEntry(this, text, QVariant::fromValue(data), action->icon()); + const ActionFilterEntryData data{}; + LocatorFilterEntry filterEntry(this, text); + filterEntry.internalData = QVariant::fromValue(ActionFilterEntryData{action, command->id()}); + filterEntry.displayIcon = action->icon(); filterEntry.displayExtra = command->keySequence().toString(QKeySequence::NativeText); if (path.size() >= 2) filterEntry.extraInfo = path.mid(0, path.size() - 1).join(" > "); @@ -260,7 +264,9 @@ void ActionsFilter::collectEntriesForLastTriggered() if (!data.action || !m_enabledActions.contains(data.action)) continue; const QString text = actionText(data.action); - LocatorFilterEntry filterEntry(this, text, QVariant::fromValue(data), data.action->icon()); + LocatorFilterEntry filterEntry(this, text); + filterEntry.internalData = QVariant::fromValue(data); + filterEntry.displayIcon = data.action->icon(); updateEntry(data.action, filterEntry); } } diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index de2989bc17c..387cae9fef6 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -77,7 +77,8 @@ QList CommandLocator::matchesFor(QFutureInterface= 0) { - LocatorFilterEntry filterEntry(this, text, QVariant(pair.first)); + LocatorFilterEntry filterEntry(this, text); + filterEntry.internalData = QVariant(pair.first); filterEntry.highlightInfo = {index, int(entry.length())}; if (index == 0) diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index 96ce58e20b3..7828cc13724 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -66,7 +66,8 @@ void ExternalToolsFilter::prepareSearch(const QString &entry) } if (index >= 0) { - LocatorFilterEntry filterEntry(this, tool->displayName(), QVariant::fromValue(tool)); + LocatorFilterEntry filterEntry(this, tool->displayName()); + filterEntry.internalData = QVariant::fromValue(tool); filterEntry.extraInfo = tool->description(); filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); @@ -78,7 +79,7 @@ void ExternalToolsFilter::prepareSearch(const QString &entry) goodEntries.append(filterEntry); } } - LocatorFilterEntry configEntry(this, "Configure External Tool...", {}); + LocatorFilterEntry configEntry(this, "Configure External Tool..."); configEntry.extraInfo = "Opens External Tool settings"; m_results = {}; m_results << bestEntries << betterEntries << goodEntries << configEntry; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index a8e30029d6f..ca7a0dff763 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -72,14 +72,9 @@ public: LocatorFilterEntry() = default; - LocatorFilterEntry(ILocatorFilter *fromFilter, - const QString &name, - const QVariant &data = {}, - std::optional icon = std::nullopt) + LocatorFilterEntry(ILocatorFilter *fromFilter, const QString &name) : filter(fromFilter) , displayName(name) - , internalData(data) - , displayIcon(icon) {} /* backpointer to creating filter */ @@ -93,7 +88,7 @@ public: /* additional tooltip */ QString toolTip; /* can be used by the filter to save more information about the entry */ - QVariant internalData; + QVariant internalData; // DON'T USE IN NEW CODE, IT'S GOING TO BE REMOVED, SOON... /* icon to display along with the entry */ std::optional displayIcon; /* file path, if the entry is related to a file, is used e.g. for resolving a file icon */ diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index b97b054051f..37803abbaaa 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -52,17 +52,25 @@ QList JavaScriptFilter::matchesFor( QList entries; if (entry.trimmed().isEmpty()) { - entries.append({this, Tr::tr("Reset Engine"), QVariant::fromValue(EngineAction::Reset)}); + LocatorFilterEntry entry{this, Tr::tr("Reset Engine")}; + entry.internalData = QVariant::fromValue(EngineAction::Reset); + entries.append(entry); } else { const QString result = m_engine->evaluate(entry).toString(); if (m_aborted) { const QString message = entry + " = " + Tr::tr("Engine aborted after timeout."); - entries.append({this, message, QVariant::fromValue(EngineAction::Abort)}); + LocatorFilterEntry entry(this, message); + entry.internalData = QVariant::fromValue(EngineAction::Abort); + entries.append(entry); } else { const QString expression = entry + " = " + result; entries.append({this, expression}); - entries.append({this, Tr::tr("Copy to clipboard: %1").arg(result), result}); - entries.append({this, Tr::tr("Copy to clipboard: %1").arg(expression), expression}); + LocatorFilterEntry resultEntry(this, Tr::tr("Copy to clipboard: %1").arg(result)); + resultEntry.internalData = result; + entries.append(resultEntry); + LocatorFilterEntry expressionEntry(this, Tr::tr("Copy to clipboard: %1").arg(expression)); + resultEntry.internalData = expression; + entries.append(expressionEntry); } } diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index 800c9171dbc..b8cd9ef3007 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -60,10 +60,9 @@ QList LocatorFiltersFilter::matchesFor(QFutureInterface CppCurrentDocumentFilter::matchesFor( } } - LocatorFilterEntry filterEntry(this, name, {}, info->icon()); + LocatorFilterEntry filterEntry(this, name); + filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; if (match.hasMatch()) { diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index c74fc73d505..541acb05154 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -25,7 +25,8 @@ CppLocatorFilter::CppLocatorFilter() LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { - LocatorFilterEntry filterEntry(this, info->scopedSymbolName(), {}, info->icon()); + LocatorFilterEntry filterEntry(this, info->scopedSymbolName()); + filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) filterEntry.extraInfo = info->shortNativeFilePath(); @@ -120,7 +121,8 @@ CppClassesFilter::CppClassesFilter() LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { - LocatorFilterEntry filterEntry(this, info->symbolName(), {}, info->icon()); + LocatorFilterEntry filterEntry(this, info->symbolName()); + filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = info->symbolScope().isEmpty() ? info->shortNativeFilePath() @@ -148,7 +150,8 @@ LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr i extraInfo.append(" (" + info->filePath().fileName() + ')'); } - LocatorFilterEntry filterEntry(this, name + info->symbolType(), {}, info->icon()); + LocatorFilterEntry filterEntry(this, name + info->symbolType()); + filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 63578ef944d..9c2c7ada44c 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -78,7 +78,8 @@ QList HelpIndexFilter::matchesFor(QFutureInterface entries; for (const QString &keyword : std::as_const(m_lastIndicesCache)) { const int index = keyword.indexOf(entry, 0, cs); - LocatorFilterEntry filterEntry(this, keyword, {}, m_icon); + LocatorFilterEntry filterEntry(this, keyword); + filterEntry.displayIcon = m_icon; filterEntry.highlightInfo = {index, int(entry.length())}; entries.append(filterEntry); } diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 43a9a489459..5749b187eee 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -50,7 +50,8 @@ QList MacroLocatorFilter::matchesFor(QFutureInterface< } if (index >= 0) { - Core::LocatorFilterEntry filterEntry(this, displayName, {}, m_icon); + Core::LocatorFilterEntry filterEntry(this, displayName); + filterEntry.displayIcon = m_icon; filterEntry.extraInfo = description; filterEntry.highlightInfo = Core::LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index 78a65c84d2f..83f0adaf925 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -64,7 +64,9 @@ QList LineNumberFilter::matchesFor(QFutureInterface Date: Tue, 4 Apr 2023 14:28:06 +0200 Subject: [PATCH 0486/1447] RemoteLinux: Use only ID based creation of install step Also for configuration fixes due to upgrades. Change-Id: Iba48313fabfb0ae605cb56052ea9c0fe7fc414e7 Reviewed-by: Christian Stenger --- src/plugins/remotelinux/makeinstallstep.cpp | 10 ---------- src/plugins/remotelinux/makeinstallstep.h | 3 --- .../remotelinux/remotelinuxdeployconfiguration.cpp | 4 +--- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index b078dce1a91..e5641abec01 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -124,16 +124,6 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Id id) : MakeStep(parent }); } -Utils::Id MakeInstallStep::stepId() -{ - return Constants::MakeInstallStepId; -} - -QString MakeInstallStep::displayName() -{ - return Tr::tr("Install into temporary host directory"); -} - QWidget *MakeInstallStep::createConfigWidget() { // Note: this intentionally skips the MakeStep::createConfigWidget() level. diff --git a/src/plugins/remotelinux/makeinstallstep.h b/src/plugins/remotelinux/makeinstallstep.h index 012a9924cf6..3be2d5df979 100644 --- a/src/plugins/remotelinux/makeinstallstep.h +++ b/src/plugins/remotelinux/makeinstallstep.h @@ -16,9 +16,6 @@ class REMOTELINUX_EXPORT MakeInstallStep : public ProjectExplorer::MakeStep public: MakeInstallStep(ProjectExplorer::BuildStepList *parent, Utils::Id id); - static Utils::Id stepId(); - static QString displayName(); - private: bool fromMap(const QVariantMap &map) override; QWidget *createConfigWidget() override; diff --git a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp index 7f55d0a6c8b..94bfbfb981f 100644 --- a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp @@ -3,7 +3,6 @@ #include "remotelinuxdeployconfiguration.h" -#include "makeinstallstep.h" #include "remotelinux_constants.h" #include "remotelinuxtr.h" @@ -52,8 +51,7 @@ RemoteLinuxDeployConfigurationFactory::RemoteLinuxDeployConfigurationFactory() setPostRestore([needsMakeInstall](DeployConfiguration *dc, const QVariantMap &map) { // 4.9 -> 4.10. See QTCREATORBUG-22689. if (map.value("_checkMakeInstall").toBool() && needsMakeInstall(dc->target())) { - auto step = new MakeInstallStep(dc->stepList(), MakeInstallStep::stepId()); - dc->stepList()->insertStep(0, step); + dc->stepList()->insertStep(0, Constants::MakeInstallStepId); } }); From de546ff3ecbf9929d4bf19b50243c5b94e328616 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 3 Apr 2023 18:46:43 +0200 Subject: [PATCH 0487/1447] Debugger: Support piping dumpers into gdb This allows using dumpers available on the host being used from remotely running gdb. No lldb/cdb yet. Task-number: QTCREATORBUG-29000 Task-number: QTCREATORBUG-16246 Change-Id: Ib1a40a8c0284dcf41e8800d70ca3e632c699b2fa Reviewed-by: David Schulz Reviewed-by: --- share/qtcreator/CMakeLists.txt | 1 + share/qtcreator/debugger/dumper.py | 14 +++-- share/qtcreator/debugger/loadorder.txt | 13 ++++ src/plugins/debugger/cdb/cdbengine.cpp | 2 +- src/plugins/debugger/debuggerengine.cpp | 5 -- src/plugins/debugger/debuggerengine.h | 1 - src/plugins/debugger/debuggerruncontrol.cpp | 1 - src/plugins/debugger/gdb/gdbengine.cpp | 61 ++++++++++++++++--- src/plugins/debugger/lldb/lldbengine.cpp | 3 +- src/plugins/docker/dockerdevice.cpp | 3 - .../projectexplorer/devicesupport/idevice.cpp | 10 --- .../projectexplorer/devicesupport/idevice.h | 3 - 12 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 share/qtcreator/debugger/loadorder.txt diff --git a/share/qtcreator/CMakeLists.txt b/share/qtcreator/CMakeLists.txt index 49b556b5c52..f8be01a7a7b 100644 --- a/share/qtcreator/CMakeLists.txt +++ b/share/qtcreator/CMakeLists.txt @@ -35,6 +35,7 @@ set(resource_files debugger/libcpp_stdtypes.py debugger/stdtypes.py debugger/utils.py + debugger/loadorder.txt ) # copy resource directories during build diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 136961db3e7..50dabd217fd 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -195,10 +195,16 @@ class DumperBase(): self.childrenPrefix = 'children=[' self.childrenSuffix = '],' - self.dumpermodules = [ - os.path.splitext(os.path.basename(p))[0] for p in - glob.glob(os.path.join(os.path.dirname(__file__), '*types.py')) - ] + self.dumpermodules = [] + + try: + # Fails in the piping case + self.dumpermodules = [ + os.path.splitext(os.path.basename(p))[0] for p in + glob.glob(os.path.join(os.path.dirname(__file__), '*types.py')) + ] + except: + pass # These values are never used, but the variables need to have # some value base for the swapping logic in Children.__enter__() diff --git a/share/qtcreator/debugger/loadorder.txt b/share/qtcreator/debugger/loadorder.txt new file mode 100644 index 00000000000..e348970ced0 --- /dev/null +++ b/share/qtcreator/debugger/loadorder.txt @@ -0,0 +1,13 @@ +utils +gdbtracepoint +dumper +gdbbridge +boosttypes +creatortypes +libcpp_stdtypes +misctypes +opencvtypes +personaltypes +qttypes +stdtypes +android_stdtypes diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index ac382c4005d..a45dfdeb200 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2766,7 +2766,7 @@ void CdbEngine::setupScripting(const DebuggerResponse &response) return; } - QString dumperPath = runParameters().dumperPath.toUserOutput(); + QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput(); dumperPath.replace('\\', "\\\\"); runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand}); runCommand({"from cdbbridge import Dumper", ScriptCommand}); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index eeba3bfe9ed..1013fbe73c8 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1036,11 +1036,6 @@ void DebuggerEngine::setRunTool(DebuggerRunTool *runTool) { d->m_device = runTool->device(); - IDevice::ConstPtr debuggerDevice = - DeviceManager::deviceForPath(d->m_runParameters.debugger.command.executable()); - if (QTC_GUARD(debuggerDevice)) - d->m_runParameters.dumperPath = debuggerDevice->debugDumperPath(); - d->m_terminalRunner = runTool->terminalRunner(); validateRunParameters(d->m_runParameters); diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 215cb3081dd..ac91ecb6440 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -184,7 +184,6 @@ public: QStringList validationErrors; - Utils::FilePath dumperPath; int fallbackQtVersion = 0x50200; // Common debugger constants. diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 7f0dc8c3f42..bbb2556d68c 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -928,7 +928,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm } } - m_runParameters.dumperPath = Core::ICore::resourcePath("debugger/"); if (QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(kit)) { const QVersionNumber qtVersion = baseQtVersion->qtVersion(); m_runParameters.fallbackQtVersion = 0x10000 * qtVersion.majorVersion() diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 23ebc1df942..532c9ef0695 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -765,7 +765,8 @@ void GdbEngine::runCommand(const DebuggerCommand &command) if (cmd.flags & ConsoleCommand) cmd.function = "-interpreter-exec console \"" + cmd.function + '"'; cmd.function = QString::number(token) + cmd.function; - showMessage(cmd.function, LogInput); + + showMessage(cmd.function.left(100), LogInput); if (m_scheduledTestResponses.contains(token)) { // Fake response for test cases. @@ -3969,15 +3970,59 @@ void GdbEngine::handleGdbStarted() //if (terminal()->isUsable()) // runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())}); - runCommand({"python sys.path.insert(1, '" + rp.dumperPath.path() + "')"}); + const FilePath dumperPath = ICore::resourcePath("debugger"); + if (rp.debugger.command.executable().needsDevice()) { + // Gdb itself running remotely. + const FilePath loadOrderFile = dumperPath / "loadorder.txt"; + const expected_str toLoad = loadOrderFile.fileContents(); + if (!toLoad) { + AsynchronousMessageBox::critical( + Tr::tr("Cannot Find Debugger Initialization Script"), + Tr::tr("Cannot read %1: %2").arg(loadOrderFile.toUserOutput(), toLoad.error())); + notifyEngineSetupFailed(); + return; + } - // This is useful (only) in custom gdb builds that did not run 'make install' - const FilePath uninstalledData = rp.debugger.command.executable().parentDir() - / "data-directory/python"; - if (uninstalledData.exists()) - runCommand({"python sys.path.append('" + uninstalledData.path() + "')"}); + runCommand({"python import sys, types"}); + QStringList moduleList; + for (const QByteArray &rawModuleName : toLoad->split('\n')) { + const QString module = QString::fromUtf8(rawModuleName).trimmed(); + if (module.startsWith('#')) + continue; - runCommand({"python from gdbbridge import *"}); + const FilePath codeFile = dumperPath / (module + ".py"); + const expected_str code = codeFile.fileContents(); + if (!code) { + qDebug() << Tr::tr("Cannot read %1: %2").arg(codeFile.toUserOutput(), code.error()); + continue; + } + + showMessage("Reading " + codeFile.toUserOutput(), LogInput); + runCommand({QString("python module = types.ModuleType('%1')").arg(module)}); + runCommand({QString("python code = bytes.fromhex('%1').decode('utf-8')") + .arg(QString::fromUtf8(code->toHex()))}); + runCommand({QString("python exec(code, module.__dict__)")}); + runCommand({QString("python sys.modules['%1'] = module").arg(module)}); + runCommand({QString("python import %1").arg(module)}); + + if (module.endsWith("types")) + moduleList.append('"' + module + '"'); + } + + runCommand({"python from gdbbridge import *"}); + runCommand(QString("python theDumper.dumpermodules = [%1]").arg(moduleList.join(','))); + + } else { + // Gdb on local host + // This is useful (only) in custom gdb builds that did not run 'make install' + const FilePath uninstalledData = rp.debugger.command.executable().parentDir() + / "data-directory/python"; + if (uninstalledData.exists()) + runCommand({"python sys.path.append('" + uninstalledData.path() + "')"}); + + runCommand({"python sys.path.insert(1, '" + dumperPath.path() + "')"}); + runCommand({"python from gdbbridge import *"}); + } const QString path = debuggerSettings()->extraDumperFile.value(); if (!path.isEmpty() && QFileInfo(path).isReadable()) { diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index f2c7c23744c..a930465b68b 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -219,7 +219,8 @@ void LldbEngine::handleLldbStarted() const DebuggerRunParameters &rp = runParameters(); - executeCommand("script sys.path.insert(1, '" + rp.dumperPath.path() + "')"); + QString dumperPath = ICore::resourcePath("debugger").path(); + executeCommand("script sys.path.insert(1, '" + dumperPath + "')"); // This triggers reportState("enginesetupok") or "enginesetupfailed": executeCommand("script from lldbbridge import *"); diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 5e8fc5c521e..980275a4526 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -677,9 +677,6 @@ bool DockerDevicePrivate::createContainer() if (m_data.useLocalUidGid) dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())}); #endif - FilePath dumperPath = FilePath::fromString("/tmp/qtcreator/debugger"); - addTemporaryMount(Core::ICore::resourcePath("debugger/"), dumperPath); - q->setDebugDumperPath(dumperPath); dockerCreate.addArgs(createMountArgs()); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 2e6e80801b5..2e4dbcef59f 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -580,16 +580,6 @@ void IDevice::setDebugServerPath(const FilePath &path) d->debugServerPath = path; } -FilePath IDevice::debugDumperPath() const -{ - return d->debugDumperPath; -} - -void IDevice::setDebugDumperPath(const FilePath &path) -{ - d->debugDumperPath = path; -} - FilePath IDevice::qmlRunCommand() const { return d->qmlRunCommand; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 2dc75a36980..596637e3e08 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -179,9 +179,6 @@ public: Utils::FilePath debugServerPath() const; void setDebugServerPath(const Utils::FilePath &path); - Utils::FilePath debugDumperPath() const; - void setDebugDumperPath(const Utils::FilePath &path); - Utils::FilePath qmlRunCommand() const; void setQmlRunCommand(const Utils::FilePath &path); From 4c2e08912c7536400a65d0171a1fd1fa23a403c5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 15:35:32 +0200 Subject: [PATCH 0488/1447] RemoteLinux: Fix control signal if running in PTY Change-Id: I8bc6c5f686a2e20ead1742e1567ad5530dd13eaf Reviewed-by: Jarek Kobus Reviewed-by: --- src/plugins/remotelinux/linuxdevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 65d919b71ed..633f46dbe0b 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -466,7 +466,7 @@ void SshProcessInterface::sendControlSignal(ControlSignal controlSignal) d->m_process.closeWriteChannel(); return; } - if (d->m_process.usesTerminal()) { + if (d->m_process.usesTerminal() || d->m_process.ptyData().has_value()) { switch (controlSignal) { case ControlSignal::Terminate: d->m_process.terminate(); break; case ControlSignal::Kill: d->m_process.kill(); break; From e3565d41b88faec35e9229370362f0c57ae3a632 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 4 Apr 2023 16:03:53 +0200 Subject: [PATCH 0489/1447] Utils: Code cosmetics Change-Id: I34b566371fc4d6666439ed14c8ba95417584f0f5 Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/libs/utils/fileutils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 4bd0692e133..f31bd822bbf 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -803,11 +803,11 @@ FilePath FileUtils::homePath() return FilePath::fromUserInput(QDir::homePath()); } -FilePaths FileUtils::toFilePathList(const QStringList &paths) { - return transform(paths, [](const QString &path) { return FilePath::fromString(path); }); +FilePaths FileUtils::toFilePathList(const QStringList &paths) +{ + return transform(paths, &FilePath::fromString); } - qint64 FileUtils::bytesAvailableFromDFOutput(const QByteArray &dfOutput) { const auto lines = filtered(dfOutput.split('\n'), From 9f6209a228f9ae48c3f9e1f39609554b0ebf358f Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 4 Apr 2023 18:07:45 +0200 Subject: [PATCH 0490/1447] CMakePM: Do not check for changes for CMAKE_PROJECT_INCLUDE_BEFORE This was the case previously when the path was tied to the Qt Creator version. This fixes the docker case when the expanded value gets replaced with the unexpanded value from the initial configuration. Change-Id: If005d410bc4408403fd79fa619c58217a499d3a5 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 9ccd87edda0..68b3cb20a6c 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -1230,7 +1230,6 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars() "CMAKE_CXX_COMPILER", "QT_QMAKE_EXECUTABLE", "QT_HOST_PATH", - "CMAKE_PROJECT_INCLUDE_BEFORE", "CMAKE_TOOLCHAIN_FILE" }; for (const auto &var : singlePathList) { From 3108892c5c446e203b9b2b62708f78cb04d4521f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 20 Mar 2023 22:46:12 +0100 Subject: [PATCH 0491/1447] DocumentLocatorFilter: Refactor internals Avoid use of LocatorFilterEntry::internalData inside LspCurrentDocumentFilter. Change-Id: I5eb4831919281ab11a630bf7810890a72a1423bb Reviewed-by: David Schulz Reviewed-by: Reviewed-by: Qt CI Bot --- .../clangcodemodel/clangdlocatorfilters.cpp | 80 +++++++------ src/plugins/languageclient/locatorfilter.cpp | 109 +++++++++--------- src/plugins/languageclient/locatorfilter.h | 34 +++--- 3 files changed, 113 insertions(+), 110 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index ebd04c538b3..a7700d942af 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -209,46 +209,54 @@ private: m_content = TextEditor::TextDocument::currentTextDocument()->plainText(); } - LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info, - const LocatorFilterEntry &parent) override - { - LocatorFilterEntry entry; - entry.filter = this; - entry.displayName = ClangdClient::displayNameFromDocumentSymbol( - static_cast(info.kind()), info.name(), - info.detail().value_or(QString())); - entry.internalData = QVariant::fromValue(info); - const Position pos = info.range().start(); - entry.linkForEditor = {m_currentFilePath, pos.line() + 1, pos.character()}; - entry.extraInfo = parent.extraInfo; - if (!entry.extraInfo.isEmpty()) - entry.extraInfo.append("::"); - entry.extraInfo.append(parent.displayName); - - // TODO: Can we extend clangd to send visibility information? - entry.displayIcon = LanguageClient::symbolIcon(info.kind()); - - return entry; - } - // Filter out declarations for which a definition is also present. QList matchesFor(QFutureInterface &future, const QString &entry) override { - QList allMatches - = DocumentLocatorFilter::matchesFor(future, entry); - QHash> possibleDuplicates; - for (const LocatorFilterEntry &e : std::as_const(allMatches)) - possibleDuplicates[e.displayName + e.extraInfo] << e; + struct Entry + { + LocatorFilterEntry entry; + DocumentSymbol symbol; + }; + QList docEntries; + + const auto docSymbolGenerator = [&](const DocumentSymbol &info, + const LocatorFilterEntry &parent) { + LocatorFilterEntry entry; + entry.filter = this; + entry.displayName = ClangdClient::displayNameFromDocumentSymbol( + static_cast(info.kind()), info.name(), + info.detail().value_or(QString())); + entry.internalData = QVariant::fromValue(info); + entry.linkForEditor = linkForDocSymbol(info); + entry.extraInfo = parent.extraInfo; + if (!entry.extraInfo.isEmpty()) + entry.extraInfo.append("::"); + entry.extraInfo.append(parent.displayName); + + // TODO: Can we extend clangd to send visibility information? + entry.displayIcon = LanguageClient::symbolIcon(info.kind()); + docEntries.append({entry, info}); + return entry; + }; + + QList allMatches = matchesForImpl(future, entry, docSymbolGenerator); + if (docEntries.isEmpty()) + return allMatches; // SymbolInformation case + + QTC_CHECK(docEntries.size() == allMatches.size()); + QHash> possibleDuplicates; + for (const Entry &e : std::as_const(docEntries)) + possibleDuplicates[e.entry.displayName + e.entry.extraInfo] << e; const QTextDocument doc(m_content); for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { - const QList &duplicates = it.value(); + const QList &duplicates = it.value(); if (duplicates.size() == 1) continue; - QList declarations; - QList definitions; - for (const LocatorFilterEntry &candidate : duplicates) { - const auto symbol = qvariant_cast(candidate.internalData); + QList declarations; + QList definitions; + for (const Entry &candidate : duplicates) { + const DocumentSymbol symbol = candidate.symbol; const SymbolKind kind = static_cast(symbol.kind()); if (kind != SymbolKind::Class && kind != SymbolKind::Function) break; @@ -273,14 +281,14 @@ private: } if (definitions.size() == 1 && declarations.size() + definitions.size() == duplicates.size()) { - for (const LocatorFilterEntry &decl : std::as_const(declarations)) { - Utils::erase(allMatches, [&decl](const LocatorFilterEntry &e) { - return e.internalData == decl.internalData; + for (const Entry &decl : std::as_const(declarations)) { + Utils::erase(docEntries, [&decl](const Entry &e) { + return e.symbol == decl.symbol; }); } } } - return allMatches; + return Utils::transform(docEntries, [](const Entry &entry) { return entry.entry; }); } QString m_content; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 1b5b64d528c..ba4cc105abc 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -98,69 +98,31 @@ static LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, return entry; } -LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info) +QList DocumentLocatorFilter::entriesForSymbolsInfo( + const QList &infoList, const QRegularExpression ®exp) { QTC_ASSERT(m_pathMapper, return {}); - return LanguageClient::generateLocatorEntry(info, this, m_pathMapper); -} - -QList DocumentLocatorFilter::generateLocatorEntries( - const SymbolInformation &info, const QRegularExpression ®exp, - const LocatorFilterEntry &parent) -{ - Q_UNUSED(parent) - if (regexp.match(info.name()).hasMatch()) - return {generateLocatorEntry(info)}; - return {}; -} - -LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const DocumentSymbol &info, - const LocatorFilterEntry &parent) -{ - Q_UNUSED(parent) - LocatorFilterEntry entry; - entry.filter = this; - entry.displayName = info.name(); - if (std::optional detail = info.detail()) - entry.extraInfo = detail.value_or(QString()); - entry.displayIcon = symbolIcon(info.kind()); - const Position &pos = info.range().start(); - entry.linkForEditor = {m_currentFilePath, pos.line() + 1, pos.character()}; - return entry; -} - -QList DocumentLocatorFilter::generateLocatorEntries( - const DocumentSymbol &info, const QRegularExpression ®exp, - const LocatorFilterEntry &parent) -{ QList entries; - const QList children = info.children().value_or(QList()); - const bool hasMatch = regexp.match(info.name()).hasMatch(); - LocatorFilterEntry entry; - if (hasMatch || !children.isEmpty()) - entry = generateLocatorEntry(info, parent); - if (hasMatch) - entries << entry; - for (const DocumentSymbol &child : children) - entries << generateLocatorEntries(child, regexp, entry); + for (const SymbolInformation &info : infoList) { + if (regexp.match(info.name()).hasMatch()) + entries << LanguageClient::generateLocatorEntry(info, this, m_pathMapper); + } return entries; } -template -QList DocumentLocatorFilter::generateEntries(const QList &list, - const QString &filter) +QList DocumentLocatorFilter::entriesForDocSymbols( + const QList &infoList, const QRegularExpression ®exp, + const DocSymbolGenerator &docSymbolGenerator, const LocatorFilterEntry &parent) { QList entries; - FuzzyMatcher::CaseSensitivity caseSensitivity - = ILocatorFilter::caseSensitivity(filter) == Qt::CaseSensitive - ? FuzzyMatcher::CaseSensitivity::CaseSensitive - : FuzzyMatcher::CaseSensitivity::CaseInsensitive; - const QRegularExpression regexp = FuzzyMatcher::createRegExp(filter, caseSensitivity); - if (!regexp.isValid()) - return entries; - - for (const T &item : list) - entries << generateLocatorEntries(item, regexp, {}); + for (const DocumentSymbol &info : infoList) { + const QList children = info.children().value_or(QList()); + const bool hasMatch = regexp.match(info.name()).hasMatch(); + const LocatorFilterEntry entry = hasMatch ? docSymbolGenerator(info, parent) : parent; + if (hasMatch) + entries << entry; + entries << entriesForDocSymbols(children, regexp, docSymbolGenerator, entry); + } return entries; } @@ -177,6 +139,39 @@ void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) QList DocumentLocatorFilter::matchesFor( QFutureInterface &future, const QString &entry) { + const auto docSymbolGenerator = [this](const DocumentSymbol &info, + const LocatorFilterEntry &parent) { + Q_UNUSED(parent) + LocatorFilterEntry entry; + entry.filter = this; + entry.displayName = info.name(); + if (std::optional detail = info.detail()) + entry.extraInfo = detail.value_or(QString()); + entry.displayIcon = symbolIcon(info.kind()); + entry.linkForEditor = linkForDocSymbol(info); + return entry; + }; + return matchesForImpl(future, entry, docSymbolGenerator); +} + +Utils::Link DocumentLocatorFilter::linkForDocSymbol(const DocumentSymbol &info) const +{ + const Position &pos = info.range().start(); + return {m_currentFilePath, pos.line() + 1, pos.character()}; +} + +QList DocumentLocatorFilter::matchesForImpl( + QFutureInterface &future, const QString &entry, + const DocSymbolGenerator &docSymbolGenerator) +{ + const FuzzyMatcher::CaseSensitivity caseSensitivity + = ILocatorFilter::caseSensitivity(entry) == Qt::CaseSensitive + ? FuzzyMatcher::CaseSensitivity::CaseSensitive + : FuzzyMatcher::CaseSensitivity::CaseInsensitive; + const QRegularExpression regExp = FuzzyMatcher::createRegExp(entry, caseSensitivity); + if (!regExp.isValid()) + return {}; + QMutexLocker locker(&m_mutex); if (!m_symbolCache) return {}; @@ -195,9 +190,9 @@ QList DocumentLocatorFilter::matchesFor( QTC_ASSERT(m_currentSymbols.has_value(), return {}); if (auto list = std::get_if>(&*m_currentSymbols)) - return generateEntries(*list, entry); + return entriesForDocSymbols(*list, regExp, docSymbolGenerator); else if (auto list = std::get_if>(&*m_currentSymbols)) - return generateEntries(*list, entry); + return entriesForSymbolsInfo(*list, regExp); return {}; } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 769fd39ba69..1ac354ed357 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -36,31 +36,29 @@ signals: protected: void forceUse() { m_forced = true; } - QPointer m_symbolCache; - LanguageServerProtocol::DocumentUri m_currentUri; Utils::FilePath m_currentFilePath; + using DocSymbolGenerator = std::function; + + Utils::Link linkForDocSymbol(const LanguageServerProtocol::DocumentSymbol &info) const; + QList matchesForImpl( + QFutureInterface &future, const QString &entry, + const DocSymbolGenerator &docSymbolGenerator); + private: void updateCurrentClient(); void updateSymbols(const LanguageServerProtocol::DocumentUri &uri, const LanguageServerProtocol::DocumentSymbolsResult &symbols); void resetSymbols(); - template - QList generateEntries(const QList &list, const QString &filter); - QList generateLocatorEntries( - const LanguageServerProtocol::SymbolInformation &info, - const QRegularExpression ®exp, - const Core::LocatorFilterEntry &parent); - QList generateLocatorEntries( - const LanguageServerProtocol::DocumentSymbol &info, - const QRegularExpression ®exp, - const Core::LocatorFilterEntry &parent); - virtual Core::LocatorFilterEntry generateLocatorEntry( - const LanguageServerProtocol::DocumentSymbol &info, - const Core::LocatorFilterEntry &parent); - virtual Core::LocatorFilterEntry generateLocatorEntry( - const LanguageServerProtocol::SymbolInformation &info); + QList entriesForSymbolsInfo( + const QList &infoList, + const QRegularExpression ®exp); + QList entriesForDocSymbols( + const QList &infoList, + const QRegularExpression ®exp, const DocSymbolGenerator &docSymbolGenerator, + const Core::LocatorFilterEntry &parent = {}); QMutex m_mutex; QMetaObject::Connection m_updateSymbolsConnection; @@ -68,6 +66,8 @@ private: std::optional m_currentSymbols; LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper; bool m_forced = false; + QPointer m_symbolCache; + LanguageServerProtocol::DocumentUri m_currentUri; }; class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter From c378df273c056c37dd85ecb9395acb82d3dfd0b4 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 4 Apr 2023 15:34:52 +0200 Subject: [PATCH 0492/1447] Docker: Fix windows terminal Do not send the marker when running in a PTY. On windows it gets encased in junk and duplicated otherwise. Change-Id: I9017066b0f1d22d4700704bfa2120c4f5d66daa9 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/docker/dockerdevice.cpp | 95 ++++++++++++++++++----------- 1 file changed, 60 insertions(+), 35 deletions(-) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 980275a4526..4475f9fcbf3 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -164,7 +164,8 @@ public: const std::optional &env = std::nullopt, const std::optional &workDir = std::nullopt, bool interactive = false, - bool withPty = false); + bool withPty = false, + bool withMarker = true); bool prepareForBuild(const Target *target); Tasks validateMounts() const; @@ -237,33 +238,39 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva { connect(&m_process, &QtcProcess::started, this, [this] { qCDebug(dockerDeviceLog) << "Process started:" << m_process.commandLine(); + + if (m_setup.m_ptyData.has_value()) { + m_hasReceivedFirstOutput = true; + emit started(m_process.processId(), m_process.applicationMainThreadId()); + } }); connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + if (m_hasReceivedFirstOutput) + emit readyRead(m_process.readAllRawStandardOutput(), {}); + QByteArray output = m_process.readAllRawStandardOutput(); - if (!m_hasReceivedFirstOutput) { - qsizetype idx = output.indexOf('\n'); - QByteArray firstLine = output.left(idx).trimmed(); - QByteArray rest = output.mid(idx + 1); - qCDebug(dockerDeviceLog) - << "Process first line received:" << m_process.commandLine() << firstLine; - if (firstLine.startsWith("__qtc")) { - bool ok = false; - m_remotePID = firstLine.mid(5, firstLine.size() - 5 - 5).toLongLong(&ok); + qsizetype idx = output.indexOf('\n'); + QByteArray firstLine = output.left(idx).trimmed(); + QByteArray rest = output.mid(idx + 1); + qCDebug(dockerDeviceLog) << "Process first line received:" << m_process.commandLine() + << firstLine; - if (ok) - emit started(m_remotePID); + if (!firstLine.startsWith("__qtc")) + return; - // In case we already received some error output, send it now. - const QByteArray stdErr = m_process.readAllRawStandardError(); - if (rest.size() > 0 || stdErr.size() > 0) - emit readyRead(rest, stdErr); + bool ok = false; + m_remotePID = firstLine.mid(5, firstLine.size() - 5 - 5).toLongLong(&ok); - m_hasReceivedFirstOutput = true; - return; - } - } - emit readyRead(output, {}); + if (ok) + emit started(m_remotePID); + + // In case we already received some error output, send it now. + const QByteArray stdErr = m_process.readAllRawStandardError(); + if (rest.size() > 0 || stdErr.size() > 0) + emit readyRead(rest, stdErr); + + m_hasReceivedFirstOutput = true; }); connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { @@ -277,7 +284,7 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva Utils::ProcessResultData resultData = m_process.resultData(); - if (m_remotePID == 0) { + if (m_remotePID == 0 && !m_hasReceivedFirstOutput) { resultData.m_error = QProcess::FailedToStart; qCWarning(dockerDeviceLog) << "Process failed to start:" << m_process.commandLine(); QByteArray stdOut = m_process.readAllRawStandardOutput(); @@ -325,7 +332,8 @@ void DockerProcessImpl::start() m_setup.m_environment, m_setup.m_workingDirectory, interactive, - inTerminal); + inTerminal, + !m_process.ptyData().has_value()); m_process.setCommand(fullCommandLine); m_process.start(); @@ -338,14 +346,26 @@ qint64 DockerProcessImpl::write(const QByteArray &data) void DockerProcessImpl::sendControlSignal(ControlSignal controlSignal) { - QTC_ASSERT(m_remotePID, return); - if (controlSignal == ControlSignal::CloseWriteChannel) { - m_process.closeWriteChannel(); - return; + if (!m_setup.m_ptyData.has_value()) { + QTC_ASSERT(m_remotePID, return); + if (controlSignal == ControlSignal::CloseWriteChannel) { + m_process.closeWriteChannel(); + return; + } + const int signal = controlSignalToInt(controlSignal); + m_devicePrivate->runInShell( + {"kill", {QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}}); + } else { + // clang-format off + switch (controlSignal) { + case ControlSignal::Terminate: m_process.terminate(); break; + case ControlSignal::Kill: m_process.kill(); break; + case ControlSignal::Interrupt: m_process.interrupt(); break; + case ControlSignal::KickOff: m_process.kickoffProcess(); break; + case ControlSignal::CloseWriteChannel: break; + } + // clang-format on } - const int signal = controlSignalToInt(controlSignal); - m_devicePrivate->runInShell( - {"kill", {QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}}); } IDeviceWidget *DockerDevice::createWidget() @@ -473,7 +493,8 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, const std::optional &env, const std::optional &workDir, bool interactive, - bool withPty) + bool withPty, + bool withMarker) { if (!m_settings) return {}; @@ -506,11 +527,15 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, CommandLine exec("exec"); exec.addCommandLineAsArgs(cmd, CommandLine::Raw); - CommandLine echo("echo"); - echo.addArgs("__qtc$$qtc__", CommandLine::Raw); - echo.addCommandLineWithAnd(exec); + if (withMarker) { + CommandLine echo("echo"); + echo.addArgs("__qtc$$qtc__", CommandLine::Raw); + echo.addCommandLineWithAnd(exec); - dockerCmd.addCommandLineAsSingleArg(echo); + dockerCmd.addCommandLineAsSingleArg(echo); + } else { + dockerCmd.addCommandLineAsSingleArg(exec); + } return dockerCmd; } From a73c1b47f6b677e51eb097a14b16199658d9850e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 4 Apr 2023 20:13:09 +0200 Subject: [PATCH 0493/1447] CppEditor/ClangTools: Version tooltip for clang tools path choosers Change-Id: Idaacb8449ef298dfe9e54a06cefd373816011360 Reviewed-by: Christian Kandeler --- src/plugins/clangtools/settingswidget.cpp | 1 + src/plugins/cppeditor/cppcodemodelsettingspage.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/plugins/clangtools/settingswidget.cpp b/src/plugins/clangtools/settingswidget.cpp index 76f915dd99c..41b4807570a 100644 --- a/src/plugins/clangtools/settingswidget.cpp +++ b/src/plugins/clangtools/settingswidget.cpp @@ -53,6 +53,7 @@ SettingsWidget::SettingsWidget() pathChooser->setHistoryCompleter(tool == ClangToolType::Tidy ? QString("ClangTools.ClangTidyExecutable.History") : QString("ClangTools.ClazyStandaloneExecutable.History")); + pathChooser->setCommandVersionArguments({"--version"}); return pathChooser; }; m_clangTidyPathChooser = createPathChooser(ClangToolType::Tidy); diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 46870ba2520..570bd144bd1 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -241,6 +241,7 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD d->clangdChooser.setFilePath(settings.clangdFilePath()); d->clangdChooser.setAllowPathFromDevice(true); d->clangdChooser.setEnabled(d->useClangdCheckBox.isChecked()); + d->clangdChooser.setCommandVersionArguments({"--version"}); using Priority = ClangdSettings::IndexingPriority; for (Priority prio : {Priority::Off, Priority::Background, Priority::Low, Priority::Normal}) { d->indexingComboBox.addItem(ClangdSettings::priorityToDisplayString(prio), int(prio)); From 663bbbfb0eead89f133b23e9748a5df1d38cf5af Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 5 Apr 2023 10:46:13 +0200 Subject: [PATCH 0494/1447] Utils: Also list dot files when using the ls fallback Change-Id: I6763280134e8cb040b6bc627b4f67d595dc2fb5e Reviewed-by: Marcus Tillmanns --- src/libs/utils/devicefileaccess.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 016310744b1..9345b62e886 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -1192,7 +1192,7 @@ void UnixDeviceFileAccess::findUsingLs(const QString ¤t, const FileFilter &filter, QStringList *found) const { - const RunResult result = runInShell({"ls", {"-1", "-p", "--", current}, OsType::OsTypeLinux}); + const RunResult result = runInShell({"ls", {"-1", "-a", "-p", "--", current}, OsType::OsTypeLinux}); const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts); for (QString entry : entries) { const QChar last = entry.back(); @@ -1254,8 +1254,8 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, if (m_tryUseFind) { if (iterateWithFind(filePath, filter, callBack)) return; - m_tryUseFind - = false; // remember the failure for the next time and use the 'ls' fallback below. + // Remember the failure for the next time and use the 'ls' fallback below. + m_tryUseFind = false; } // if we do not have find - use ls as fallback From e22d79fbb5368820a382469cf823fa3ba95c6531 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 5 Apr 2023 08:24:14 +0200 Subject: [PATCH 0495/1447] ClangModelManagerSupport: Drop namespace scopes Change-Id: Id8d9474a35e367469b435d10b3eba0700dffc304 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- .../clangmodelmanagersupport.cpp | 159 ++++++++---------- 1 file changed, 74 insertions(+), 85 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 79f2760a7c1..8a0c40850ce 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -52,6 +52,7 @@ #include #include +using namespace Core; using namespace CppEditor; using namespace LanguageClient; using namespace ProjectExplorer; @@ -59,16 +60,16 @@ using namespace Utils; namespace ClangCodeModel::Internal { -static CppEditor::CppModelManager *cppModelManager() +static CppModelManager *cppModelManager() { - return CppEditor::CppModelManager::instance(); + return CppModelManager::instance(); } -static ProjectExplorer::Project *fallbackProject() +static Project *fallbackProject() { - if (ProjectExplorer::Project * const p = ProjectExplorer::ProjectTree::currentProject()) + if (Project * const p = ProjectTree::currentProject()) return p; - return ProjectExplorer::ProjectManager::startupProject(); + return ProjectManager::startupProject(); } static bool sessionModeEnabled() @@ -78,18 +79,17 @@ static bool sessionModeEnabled() static const QList allCppDocuments() { - const auto isCppDocument = Utils::equal(&Core::IDocument::id, - Utils::Id(CppEditor::Constants::CPPEDITOR_ID)); - const QList documents - = Utils::filtered(Core::DocumentModel::openedDocuments(), isCppDocument); + const auto isCppDocument = Utils::equal(&IDocument::id, Id(CppEditor::Constants::CPPEDITOR_ID)); + const QList documents = Utils::filtered(DocumentModel::openedDocuments(), + isCppDocument); return Utils::qobject_container_cast(documents); } -static const QList projectsForClient(const Client *client) +static const QList projectsForClient(const Client *client) { - QList projects; + QList projects; if (sessionModeEnabled()) { - for (ProjectExplorer::Project * const p : ProjectExplorer::ProjectManager::projects()) { + for (Project * const p : ProjectManager::projects()) { if (ClangdProjectSettings(p).settings().useClangd) projects << p; } @@ -101,7 +101,7 @@ static const QList projectsForClient(const Client *c static bool fileIsProjectBuildArtifact(const Client *client, const FilePath &filePath) { - for (const ProjectExplorer::Project * const p : projectsForClient(client)) { + for (const Project * const p : projectsForClient(client)) { if (const auto t = p->activeTarget()) { if (const auto bc = t->activeBuildConfiguration()) { if (filePath.isChildOf(bc->buildDirectory())) @@ -146,15 +146,15 @@ static void checkSystemForClangdSuitability() "You can enable/disable and fine-tune clangd here.")); label->setWordWrap(true); QObject::connect(label, &QLabel::linkActivated, [] { - Core::ICore::showOptionsDialog(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID); + ICore::showOptionsDialog(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID); }); return label; }); info.addCustomButton(Tr::tr("Enable Anyway"), [clangdWarningSetting] { ClangdSettings::setUseClangdAndSave(true); - Core::ICore::infoBar()->removeInfo(clangdWarningSetting); + ICore::infoBar()->removeInfo(clangdWarningSetting); }); - Core::ICore::infoBar()->addInfo(info); + ICore::infoBar()->addInfo(info); } static void updateParserConfig(ClangdClient *client) @@ -172,8 +172,8 @@ static void updateParserConfig(ClangdClient *client) static bool projectIsParsing(const ClangdClient *client) { - for (const ProjectExplorer::Project * const p : projectsForClient(client)) { - const ProjectExplorer::BuildSystem * const bs = p && p->activeTarget() + for (const Project * const p : projectsForClient(client)) { + const BuildSystem * const bs = p && p->activeTarget() ? p->activeTarget()->buildSystem() : nullptr; if (bs && (bs->isParsing() || bs->isWaitingForParse())) return true; @@ -181,7 +181,6 @@ static bool projectIsParsing(const ClangdClient *client) return false; } - ClangModelManagerSupport::ClangModelManagerSupport() : m_clientRestartTimer(new QTimer(this)) { @@ -206,20 +205,20 @@ ClangModelManagerSupport::ClangModelManagerSupport() cppModelManager()->setClassesFilter(std::make_unique()); cppModelManager()->setFunctionsFilter(std::make_unique()); - Core::EditorManager *editorManager = Core::EditorManager::instance(); - connect(editorManager, &Core::EditorManager::editorOpened, + EditorManager *editorManager = EditorManager::instance(); + connect(editorManager, &EditorManager::editorOpened, this, &ClangModelManagerSupport::onEditorOpened); - connect(editorManager, &Core::EditorManager::currentEditorChanged, + connect(editorManager, &EditorManager::currentEditorChanged, this, &ClangModelManagerSupport::onCurrentEditorChanged); - CppEditor::CppModelManager *modelManager = cppModelManager(); - connect(modelManager, &CppEditor::CppModelManager::abstractEditorSupportContentsUpdated, + CppModelManager *modelManager = cppModelManager(); + connect(modelManager, &CppModelManager::abstractEditorSupportContentsUpdated, this, &ClangModelManagerSupport::onAbstractEditorSupportContentsUpdated); - connect(modelManager, &CppEditor::CppModelManager::abstractEditorSupportRemoved, + connect(modelManager, &CppModelManager::abstractEditorSupportRemoved, this, &ClangModelManagerSupport::onAbstractEditorSupportRemoved); - connect(modelManager, &CppEditor::CppModelManager::projectPartsUpdated, + connect(modelManager, &CppModelManager::projectPartsUpdated, this, &ClangModelManagerSupport::onProjectPartsUpdated); - connect(modelManager, &CppEditor::CppModelManager::projectPartsRemoved, + connect(modelManager, &CppModelManager::projectPartsRemoved, this, &ClangModelManagerSupport::onProjectPartsRemoved); connect(modelManager, &CppModelManager::fallbackProjectPartUpdated, this, [this] { if (sessionModeEnabled()) @@ -230,9 +229,8 @@ ClangModelManagerSupport::ClangModelManagerSupport() } }); - auto projectManager = ProjectExplorer::ProjectManager::instance(); - connect(projectManager, &ProjectExplorer::ProjectManager::projectRemoved, - this, [this] { + auto projectManager = ProjectManager::instance(); + connect(projectManager, &ProjectManager::projectRemoved, this, [this] { if (!sessionModeEnabled()) claimNonProjectSources(clientForProject(fallbackProject())); }); @@ -241,11 +239,11 @@ ClangModelManagerSupport::ClangModelManagerSupport() onClangdSettingsChanged(); }); - CppEditor::ClangdSettings::setDefaultClangdPath(Core::ICore::clangdExecutable(CLANG_BINDIR)); - connect(&CppEditor::ClangdSettings::instance(), &CppEditor::ClangdSettings::changed, + ClangdSettings::setDefaultClangdPath(ICore::clangdExecutable(CLANG_BINDIR)); + connect(&ClangdSettings::instance(), &ClangdSettings::changed, this, &ClangModelManagerSupport::onClangdSettingsChanged); - if (CppEditor::ClangdSettings::instance().useClangd()) + if (ClangdSettings::instance().useClangd()) new ClangdClient(nullptr, {}); m_generatorSynchronizer.setCancelOnWait(true); @@ -257,9 +255,9 @@ ClangModelManagerSupport::~ClangModelManagerSupport() m_generatorSynchronizer.waitForFinished(); } -void ClangModelManagerSupport::followSymbol(const CppEditor::CursorInEditor &data, - const LinkHandler &processLinkCallback, bool resolveTarget, - bool inNextSplit) +void ClangModelManagerSupport::followSymbol(const CursorInEditor &data, + const LinkHandler &processLinkCallback, + bool resolveTarget, bool inNextSplit) { if (ClangdClient * const client = clientForFile(data.filePath()); client && client->isFullyIndexed()) { @@ -272,7 +270,7 @@ void ClangModelManagerSupport::followSymbol(const CppEditor::CursorInEditor &dat CppModelManager::Backend::Builtin); } -void ClangModelManagerSupport::followSymbolToType(const CppEditor::CursorInEditor &data, +void ClangModelManagerSupport::followSymbolToType(const CursorInEditor &data, const LinkHandler &processLinkCallback, bool inNextSplit) { @@ -285,8 +283,8 @@ void ClangModelManagerSupport::followSymbolToType(const CppEditor::CursorInEdito CppModelManager::Backend::Builtin); } -void ClangModelManagerSupport::switchDeclDef(const CppEditor::CursorInEditor &data, - const LinkHandler &processLinkCallback) +void ClangModelManagerSupport::switchDeclDef(const CursorInEditor &data, + const LinkHandler &processLinkCallback) { if (ClangdClient * const client = clientForFile(data.filePath()); client && client->isFullyIndexed()) { @@ -298,9 +296,9 @@ void ClangModelManagerSupport::switchDeclDef(const CppEditor::CursorInEditor &da CppModelManager::switchDeclDef(data, processLinkCallback, CppModelManager::Backend::Builtin); } -void ClangModelManagerSupport::startLocalRenaming(const CppEditor::CursorInEditor &data, - const CppEditor::ProjectPart *projectPart, - RenameCallback &&renameSymbolsCallback) +void ClangModelManagerSupport::startLocalRenaming(const CursorInEditor &data, + const ProjectPart *projectPart, + RenameCallback &&renameSymbolsCallback) { if (ClangdClient * const client = clientForFile(data.filePath()); client && client->reachable()) { @@ -313,7 +311,7 @@ void ClangModelManagerSupport::startLocalRenaming(const CppEditor::CursorInEdito std::move(renameSymbolsCallback), CppModelManager::Backend::Builtin); } -void ClangModelManagerSupport::globalRename(const CppEditor::CursorInEditor &cursor, +void ClangModelManagerSupport::globalRename(const CursorInEditor &cursor, const QString &replacement, const std::function &callback) { @@ -327,7 +325,7 @@ void ClangModelManagerSupport::globalRename(const CppEditor::CursorInEditor &cur CppModelManager::globalRename(cursor, replacement, callback, CppModelManager::Backend::Builtin); } -void ClangModelManagerSupport::findUsages(const CppEditor::CursorInEditor &cursor) const +void ClangModelManagerSupport::findUsages(const CursorInEditor &cursor) const { if (ClangdClient * const client = clientForFile(cursor.filePath()); client && client->isFullyIndexed()) { @@ -348,11 +346,10 @@ void ClangModelManagerSupport::switchHeaderSource(const FilePath &filePath, bool CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin); } -void ClangModelManagerSupport::checkUnused(const Link &link, Core::SearchResult *search, +void ClangModelManagerSupport::checkUnused(const Link &link, SearchResult *search, const LinkHandler &callback) { - if (const ProjectExplorer::Project * const project - = ProjectExplorer::ProjectManager::projectForFile(link.targetFilePath)) { + if (const Project * const project = ProjectManager::projectForFile(link.targetFilePath)) { if (ClangdClient * const client = clientWithProject(project); client && client->isFullyIndexed()) { client->checkUnused(link, search, callback); @@ -369,7 +366,7 @@ bool ClangModelManagerSupport::usesClangd(const TextEditor::TextDocument *docume return clientForFile(document->filePath()); } -CppEditor::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor( +BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) { const auto processor = new ClangEditorDocumentProcessor(baseTextDocument); @@ -383,10 +380,10 @@ CppEditor::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDo return processor; } -void ClangModelManagerSupport::onCurrentEditorChanged(Core::IEditor *editor) +void ClangModelManagerSupport::onCurrentEditorChanged(IEditor *editor) { // Update task hub issues for current CppEditorDocument - ProjectExplorer::TaskHub::clearTasks(Constants::TASK_CATEGORY_DIAGNOSTICS); + TaskHub::clearTasks(Constants::TASK_CATEGORY_DIAGNOSTICS); if (!editor || !editor->document() || !cppModelManager()->isCppEditor(editor)) return; @@ -409,28 +406,25 @@ void ClangModelManagerSupport::connectToWidgetsMarkContextMenuRequested(QWidget } } -static FilePath getJsonDbDir(const ProjectExplorer::Project *project) +static FilePath getJsonDbDir(const Project *project) { static const QString dirName(".qtc_clangd"); if (!project) { const QString sessionDirName = FileUtils::fileSystemFriendlyName( - ProjectExplorer::SessionManager::activeSession()); - return Core::ICore::userResourcePath() / dirName / sessionDirName; // TODO: Make configurable? + SessionManager::activeSession()); + return ICore::userResourcePath() / dirName / sessionDirName; // TODO: Make configurable? } - if (const ProjectExplorer::Target * const target = project->activeTarget()) { - if (const ProjectExplorer::BuildConfiguration * const bc - = target->activeBuildConfiguration()) { + if (const Target * const target = project->activeTarget()) { + if (const BuildConfiguration * const bc = target->activeBuildConfiguration()) return bc->buildDirectory() / dirName; - } } return {}; } -static bool isProjectDataUpToDate( - ProjectExplorer::Project *project, ProjectInfoList projectInfo, - const FilePath &jsonDbDir) +static bool isProjectDataUpToDate(Project *project, ProjectInfoList projectInfo, + const FilePath &jsonDbDir) { - if (project && !ProjectExplorer::ProjectManager::hasProject(project)) + if (project && !ProjectManager::hasProject(project)) return false; const ClangdSettings settings(ClangdProjectSettings(project).settings()); if (!settings.useClangd()) @@ -459,7 +453,7 @@ static bool isProjectDataUpToDate( return true; } -void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *project) +void ClangModelManagerSupport::updateLanguageClient(Project *project) { const ClangdSettings settings(ClangdProjectSettings(project).settings()); if (!settings.useClangd()) @@ -485,12 +479,12 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr return; const GenerateCompilationDbResult result = generatorWatcher->result(); if (!result.error.isEmpty()) { - Core::MessageManager::writeDisrupting( + MessageManager::writeDisrupting( Tr::tr("Cannot use clangd: Failed to generate compilation database:\n%1") .arg(result.error)); return; } - Utils::Id previousId; + Id previousId; if (Client * const oldClient = clientForProject(project)) { previousId = oldClient->id(); LanguageClientManager::shutdownClient(oldClient); @@ -593,18 +587,17 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr m_generatorSynchronizer.addFuture(future); } -ClangdClient *ClangModelManagerSupport::clientForProject(const ProjectExplorer::Project *project) +ClangdClient *ClangModelManagerSupport::clientForProject(const Project *project) { if (sessionModeEnabled()) project = nullptr; return clientWithProject(project); } -ClangdClient *ClangModelManagerSupport::clientWithProject(const ProjectExplorer::Project *project) +ClangdClient *ClangModelManagerSupport::clientWithProject(const Project *project) { const QList clients = Utils::filtered( - LanguageClientManager::clientsForProject(project), - [](const LanguageClient::Client *c) { + LanguageClientManager::clientsForProject(project), [](const Client *c) { return qobject_cast(c) && c->state() != Client::ShutdownRequested && c->state() != Client::Shutdown; @@ -642,7 +635,7 @@ void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *client) } if (!ClangdSettings::instance().sizeIsOkay(doc->filePath())) continue; - if (ProjectExplorer::ProjectManager::projectForFile(doc->filePath())) + if (ProjectManager::projectForFile(doc->filePath())) continue; if (client->project() && !ProjectFile::isHeader(doc->filePath())) continue; @@ -658,7 +651,7 @@ void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *client) // workflow, e.g. a git branch switch will hit at least one open file. void ClangModelManagerSupport::watchForExternalChanges() { - connect(Core::DocumentManager::instance(), &Core::DocumentManager::filesChangedExternally, + connect(DocumentManager::instance(), &DocumentManager::filesChangedExternally, this, [this](const QSet &files) { if (!LanguageClientManager::hasClients()) return; @@ -666,8 +659,7 @@ void ClangModelManagerSupport::watchForExternalChanges() const ProjectFile::Kind kind = ProjectFile::classify(file.toString()); if (!ProjectFile::isSource(kind) && !ProjectFile::isHeader(kind)) continue; - ProjectExplorer::Project * const project - = ProjectExplorer::ProjectManager::projectForFile(file); + Project * const project = ProjectManager::projectForFile(file); if (!project) continue; @@ -686,14 +678,13 @@ void ClangModelManagerSupport::watchForExternalChanges() // restart clangd for reliable re-parsing and re-indexing. void ClangModelManagerSupport::watchForInternalChanges() { - connect(Core::DocumentManager::instance(), &Core::DocumentManager::filesChangedInternally, + connect(DocumentManager::instance(), &DocumentManager::filesChangedInternally, this, [this](const FilePaths &filePaths) { for (const FilePath &fp : filePaths) { const ProjectFile::Kind kind = ProjectFile::classify(fp.toString()); if (!ProjectFile::isSource(kind) && !ProjectFile::isHeader(kind)) continue; - ProjectExplorer::Project * const project - = ProjectExplorer::ProjectManager::projectForFile(fp); + Project * const project = ProjectManager::projectForFile(fp); if (!project) continue; if (ClangdClient * const client = clientForProject(project); @@ -719,18 +710,17 @@ void ClangModelManagerSupport::scheduleClientRestart(ClangdClient *client) m_clientRestartTimer->start(); } -void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor) +void ClangModelManagerSupport::onEditorOpened(IEditor *editor) { QTC_ASSERT(editor, return); - Core::IDocument *document = editor->document(); + IDocument *document = editor->document(); QTC_ASSERT(document, return); auto textDocument = qobject_cast(document); if (textDocument && cppModelManager()->isCppEditor(editor)) { connectToWidgetsMarkContextMenuRequested(editor->widget()); - ProjectExplorer::Project * project - = ProjectExplorer::ProjectManager::projectForFile(document->filePath()); + Project * project = ProjectManager::projectForFile(document->filePath()); const ClangdSettings settings(ClangdProjectSettings(project).settings()); if (!settings.sizeIsOkay(textDocument->filePath())) return; @@ -825,17 +815,17 @@ static ClangEditorDocumentProcessors clangProcessors() return result; } -void ClangModelManagerSupport::onProjectPartsUpdated(ProjectExplorer::Project *project) +void ClangModelManagerSupport::onProjectPartsUpdated(Project *project) { QTC_ASSERT(project, return); updateLanguageClient(project); QStringList projectPartIds; - const CppEditor::ProjectInfo::ConstPtr projectInfo = cppModelManager()->projectInfo(project); + const ProjectInfo::ConstPtr projectInfo = cppModelManager()->projectInfo(project); QTC_ASSERT(projectInfo, return); - for (const CppEditor::ProjectPart::ConstPtr &projectPart : projectInfo->projectParts()) + for (const ProjectPart::ConstPtr &projectPart : projectInfo->projectParts()) projectPartIds.append(projectPart->id()); onProjectPartsRemoved(projectPartIds); } @@ -850,9 +840,8 @@ void ClangModelManagerSupport::onClangdSettingsChanged() { const bool sessionMode = sessionModeEnabled(); - for (ProjectExplorer::Project * const project : ProjectExplorer::ProjectManager::projects()) { - const CppEditor::ClangdSettings settings( - CppEditor::ClangdProjectSettings(project).settings()); + for (Project * const project : ProjectManager::projects()) { + const ClangdSettings settings(ClangdProjectSettings(project).settings()); ClangdClient * const client = clientWithProject(project); if (sessionMode) { if (client && client->project()) From 617d93761e895f908bb766dfc03a32c4aca73a3f Mon Sep 17 00:00:00 2001 From: Alexander Drozdov Date: Thu, 30 Mar 2023 16:50:20 +1000 Subject: [PATCH 0496/1447] BareMetal: add ability to connect to already running GdbServer Allow GenericGdbServerProvider connect via TCP to the already running GdbServers. Useful for the remote debugging for BareMetal devices like Xilinx UltraScape+ PSU: Xilinx provide his closed hw_server component that allow a Gdb connections. Change-Id: Ifd3af542a83d3357db366d6842461c2b2e49c4e5 Reviewed-by: Reviewed-by: hjk --- src/plugins/baremetal/debugservers/gdb/gdbserverprovider.h | 2 +- .../baremetal/debugservers/gdb/genericgdbserverprovider.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.h b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.h index eac2ca6e68a..1c23d499957 100644 --- a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.h +++ b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.h @@ -40,7 +40,7 @@ public: bool aboutToRun(Debugger::DebuggerRunTool *runTool, QString &errorMessage) const final; ProjectExplorer::RunWorker *targetRunner( - ProjectExplorer::RunControl *runControl) const final; + ProjectExplorer::RunControl *runControl) const override; bool isValid() const override; virtual QSet supportedStartupModes() const = 0; diff --git a/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h b/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h index 2754a3d91a2..7a89877bebf 100644 --- a/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h +++ b/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h @@ -19,6 +19,11 @@ class GenericGdbServerProvider final : public GdbServerProvider private: GenericGdbServerProvider(); QSet supportedStartupModes() const final; + ProjectExplorer::RunWorker *targetRunner( + ProjectExplorer::RunControl *runControl) const final { + // Generic Runner assumes GDB Server already running + return nullptr; + } friend class GenericGdbServerProviderConfigWidget; friend class GenericGdbServerProviderFactory; From 7265fd479c121330fbbb26888a5a0a7136ae050b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 4 Apr 2023 16:22:20 +0200 Subject: [PATCH 0497/1447] ProjectExplorer: Add more functions to find FolderNode children Will be used to avoid some of the temporary lists created by FolderNode::{file,folder}Nodes. Change-Id: Iac4bd1473a480971230a0d2426b993afb82648e0 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectnodes.cpp | 20 ++++++++++++++++++++ src/plugins/projectexplorer/projectnodes.h | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index cdd926b5822..4c828529545 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -579,6 +579,26 @@ ProjectNode *FolderNode::findProjectNode(const std::function &predicate) const +{ + for (const std::unique_ptr &n : m_nodes) { + if (FolderNode *fn = n->asFolderNode()) + if (predicate(fn)) + return fn; + } + return nullptr; +} + +FileNode *FolderNode::findChildFileNode(const std::function &predicate) const +{ + for (const std::unique_ptr &n : m_nodes) { + if (FileNode *fn = n->asFileNode()) + if (predicate(fn)) + return fn; + } + return nullptr; +} + const QList FolderNode::nodes() const { return Utils::toRawPointer(m_nodes); diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index dd14913e2f9..3af72aa0031 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -232,7 +232,9 @@ public: void forEachProjectNode(const std::function &genericTask) const; void forEachFileNode(const std::function &fileTask) const; void forEachFolderNode(const std::function &folderTask) const; - ProjectNode *findProjectNode(const std::function &predicate); + ProjectNode *findProjectNode(const std::function &predicate); // recursive + FolderNode *findChildFolderNode(const std::function &predicate) const; // non-recursive + FileNode *findChildFileNode(const std::function &predicate) const; // non-recursive const QList nodes() const; QList fileNodes() const; FileNode *fileNode(const Utils::FilePath &file) const; From 25c33be9f4d420d2026ce02cb23c7e8b75df151a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 5 Apr 2023 09:45:10 +0200 Subject: [PATCH 0498/1447] Boot2Qt: Switch deploy step creation to clone-by-id This finally cuts the compile-time dependency on individual factories or even step implementations. Change-Id: I764d489231762982dad803ce1cad9aca6352f1d9 Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/boot2qt/qdbplugin.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index 0d995ee0402..41fc79e2a25 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -27,9 +27,6 @@ #include -#include -#include -#include #include #include @@ -41,8 +38,7 @@ using namespace ProjectExplorer; using namespace Utils; -namespace Qdb { -namespace Internal { +namespace Qdb::Internal { static FilePath flashWizardFilePath() { @@ -100,14 +96,14 @@ void registerFlashAction(QObject *parentForAction) toolsContainer->addAction(flashCommand, flashActionId); } -template -class QdbDeployStepFactory : public Factory +class QdbDeployStepFactory : public BuildStepFactory { public: - QdbDeployStepFactory() + explicit QdbDeployStepFactory(Id existingStepId) { - Factory::setSupportedConfiguration(Constants::QdbDeployConfigurationId); - Factory::setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); + cloneStep(existingStepId); + setSupportedConfiguration(Constants::QdbDeployConfigurationId); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } }; @@ -123,9 +119,9 @@ public: QdbStopApplicationStepFactory m_stopApplicationStepFactory; QdbMakeDefaultAppStepFactory m_makeDefaultAppStepFactory; - QdbDeployStepFactory m_directUploadStepFactory; - QdbDeployStepFactory m_rsyncDeployStepFactory; - QdbDeployStepFactory m_makeInstallStepFactory; + QdbDeployStepFactory m_directUploadStepFactory{RemoteLinux::Constants::DirectUploadStepId}; + QdbDeployStepFactory m_rsyncDeployStepFactory{RemoteLinux::Constants::RsyncDeployStepId}; + QdbDeployStepFactory m_makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId}; const QList supportedRunConfigs { m_runConfigFactory.runConfigurationId(), @@ -175,5 +171,4 @@ void QdbPluginPrivate::setupDeviceDetection() m_deviceDetector.start(); } -} // Internal -} // Qdb +} // Qdb::Internal From aa5472ac1b662566d346a73bc962b25a4183dfac Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 5 Apr 2023 10:32:11 +0200 Subject: [PATCH 0499/1447] RemoteLinux: Hide GenericDeployStep implementation And un-export its factory. Re-use down-stream is now done via step ids instead by inheritance, so the implementations do not have to be visible anymore. Change-Id: I258adf7ede404b1eeedb8d703238b1a8b4793302 Reviewed-by: Christian Kandeler --- .../remotelinux/genericdirectuploadstep.cpp | 165 +++++++++--------- .../remotelinux/genericdirectuploadstep.h | 27 +-- 2 files changed, 83 insertions(+), 109 deletions(-) diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 7a39b05af45..3e3f40677f4 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "genericdirectuploadstep.h" +#include "abstractremotelinuxdeploystep.h" #include "remotelinux_constants.h" #include "remotelinuxtr.h" @@ -24,7 +25,7 @@ using namespace ProjectExplorer; using namespace Utils; using namespace Utils::Tasking; -namespace RemoteLinux { +namespace RemoteLinux::Internal { const int MaxConcurrentStatCalls = 10; @@ -35,12 +36,39 @@ struct UploadStorage enum class IncrementalDeployment { Enabled, Disabled, NotSupported }; -class GenericDirectUploadStepPrivate +class GenericDirectUploadStep : public AbstractRemoteLinuxDeployStep { public: - GenericDirectUploadStepPrivate(GenericDirectUploadStep *parent) - : q(parent) - {} + GenericDirectUploadStep(ProjectExplorer::BuildStepList *bsl, Id id) + : AbstractRemoteLinuxDeployStep(bsl, id) + { + auto incremental = addAspect(); + incremental->setSettingsKey("RemoteLinux.GenericDirectUploadStep.Incremental"); + incremental->setLabel(Tr::tr("Incremental deployment"), + BoolAspect::LabelPlacement::AtCheckBox); + incremental->setValue(true); + incremental->setDefaultValue(true); + + auto ignoreMissingFiles = addAspect(); + ignoreMissingFiles->setSettingsKey("RemoteLinux.GenericDirectUploadStep.IgnoreMissingFiles"); + ignoreMissingFiles->setLabel(Tr::tr("Ignore missing files"), + BoolAspect::LabelPlacement::AtCheckBox); + ignoreMissingFiles->setValue(false); + + setInternalInitializer([this, incremental, ignoreMissingFiles] { + m_incremental = incremental->value() + ? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled; + m_ignoreMissingFiles = ignoreMissingFiles->value(); + return isDeploymentPossible(); + }); + + setRunPreparer([this] { + m_deployableFiles = target()->deploymentData().allFiles(); + }); + } + + bool isDeploymentNecessary() const final; + Utils::Tasking::Group deployRecipe() final; QDateTime timestampFromStat(const DeployableFile &file, QtcProcess *statProc); @@ -55,13 +83,12 @@ public: TaskItem chmodTask(const DeployableFile &file); TaskItem chmodTree(const TreeStorage &storage); - GenericDirectUploadStep *q; IncrementalDeployment m_incremental = IncrementalDeployment::NotSupported; bool m_ignoreMissingFiles = false; mutable QList m_deployableFiles; }; -QList collectFilesToUpload(const DeployableFile &deployable) +static QList collectFilesToUpload(const DeployableFile &deployable) { QList collected; FilePath localFile = deployable.localFilePath(); @@ -79,16 +106,16 @@ QList collectFilesToUpload(const DeployableFile &deployable) bool GenericDirectUploadStep::isDeploymentNecessary() const { QList collected; - for (int i = 0; i < d->m_deployableFiles.count(); ++i) - collected.append(collectFilesToUpload(d->m_deployableFiles.at(i))); + for (int i = 0; i < m_deployableFiles.count(); ++i) + collected.append(collectFilesToUpload(m_deployableFiles.at(i))); - QTC_CHECK(collected.size() >= d->m_deployableFiles.size()); - d->m_deployableFiles = collected; - return !d->m_deployableFiles.isEmpty(); + QTC_CHECK(collected.size() >= m_deployableFiles.size()); + m_deployableFiles = collected; + return !m_deployableFiles.isEmpty(); } -QDateTime GenericDirectUploadStepPrivate::timestampFromStat(const DeployableFile &file, - QtcProcess *statProc) +QDateTime GenericDirectUploadStep::timestampFromStat(const DeployableFile &file, + QtcProcess *statProc) { bool succeeded = false; QString error; @@ -103,39 +130,39 @@ QDateTime GenericDirectUploadStepPrivate::timestampFromStat(const DeployableFile succeeded = true; } if (!succeeded) { - q->addWarningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " - "Incremental deployment will not work. Error message was: %2") - .arg(file.remoteFilePath(), error)); + addWarningMessage(Tr::tr("Failed to retrieve remote timestamp for file \"%1\". " + "Incremental deployment will not work. Error message was: %2") + .arg(file.remoteFilePath(), error)); return {}; } const QByteArray output = statProc->readAllRawStandardOutput().trimmed(); const QString warningString(Tr::tr("Unexpected stat output for remote file \"%1\": %2") .arg(file.remoteFilePath()).arg(QString::fromUtf8(output))); if (!output.startsWith(file.remoteFilePath().toUtf8())) { - q->addWarningMessage(warningString); + addWarningMessage(warningString); return {}; } const QByteArrayList columns = output.mid(file.remoteFilePath().toUtf8().size() + 1).split(' '); if (columns.size() < 14) { // Normal Linux stat: 16 columns in total, busybox stat: 15 columns - q->addWarningMessage(warningString); + addWarningMessage(warningString); return {}; } bool isNumber; const qint64 secsSinceEpoch = columns.at(11).toLongLong(&isNumber); if (!isNumber) { - q->addWarningMessage(warningString); + addWarningMessage(warningString); return {}; } return QDateTime::fromSecsSinceEpoch(secsSinceEpoch); } -TaskItem GenericDirectUploadStepPrivate::statTask(UploadStorage *storage, - const DeployableFile &file, - StatEndHandler statEndHandler) +TaskItem GenericDirectUploadStep::statTask(UploadStorage *storage, + const DeployableFile &file, + StatEndHandler statEndHandler) { const auto setupHandler = [=](QtcProcess &process) { // We'd like to use --format=%Y, but it's not supported by busybox. - process.setCommand({q->deviceConfiguration()->filePath("stat"), + process.setCommand({deviceConfiguration()->filePath("stat"), {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); }; const auto endHandler = [=](const QtcProcess &process) { @@ -146,8 +173,8 @@ TaskItem GenericDirectUploadStepPrivate::statTask(UploadStorage *storage, return Process(setupHandler, endHandler, endHandler); } -TaskItem GenericDirectUploadStepPrivate::statTree(const TreeStorage &storage, - FilesToStat filesToStat, StatEndHandler statEndHandler) +TaskItem GenericDirectUploadStep::statTree(const TreeStorage &storage, + FilesToStat filesToStat, StatEndHandler statEndHandler) { const auto setupHandler = [=](TaskTree &tree) { UploadStorage *storagePtr = storage.activeStorage(); @@ -162,66 +189,66 @@ TaskItem GenericDirectUploadStepPrivate::statTree(const TreeStorage &storage) +TaskItem GenericDirectUploadStep::uploadTask(const TreeStorage &storage) { const auto setupHandler = [this, storage](FileTransfer &transfer) { if (storage->filesToUpload.isEmpty()) { - q->addProgressMessage(Tr::tr("No files need to be uploaded.")); + addProgressMessage(Tr::tr("No files need to be uploaded.")); return TaskAction::StopWithDone; } - q->addProgressMessage(Tr::tr("%n file(s) need to be uploaded.", "", - storage->filesToUpload.size())); + addProgressMessage(Tr::tr("%n file(s) need to be uploaded.", "", + storage->filesToUpload.size())); FilesToTransfer files; for (const DeployableFile &file : std::as_const(storage->filesToUpload)) { if (!file.localFilePath().exists()) { const QString message = Tr::tr("Local file \"%1\" does not exist.") .arg(file.localFilePath().toUserOutput()); if (m_ignoreMissingFiles) { - q->addWarningMessage(message); + addWarningMessage(message); continue; } - q->addErrorMessage(message); + addErrorMessage(message); return TaskAction::StopWithError; } files.append({file.localFilePath(), - q->deviceConfiguration()->filePath(file.remoteFilePath())}); + deviceConfiguration()->filePath(file.remoteFilePath())}); } if (files.isEmpty()) { - q->addProgressMessage(Tr::tr("No files need to be uploaded.")); + addProgressMessage(Tr::tr("No files need to be uploaded.")); return TaskAction::StopWithDone; } transfer.setFilesToTransfer(files); QObject::connect(&transfer, &FileTransfer::progress, - q, &GenericDirectUploadStep::addProgressMessage); + this, &GenericDirectUploadStep::addProgressMessage); return TaskAction::Continue; }; const auto errorHandler = [this](const FileTransfer &transfer) { - q->addErrorMessage(transfer.resultData().m_errorString); + addErrorMessage(transfer.resultData().m_errorString); }; return Transfer(setupHandler, {}, errorHandler); } -TaskItem GenericDirectUploadStepPrivate::chmodTask(const DeployableFile &file) +TaskItem GenericDirectUploadStep::chmodTask(const DeployableFile &file) { const auto setupHandler = [=](QtcProcess &process) { - process.setCommand({q->deviceConfiguration()->filePath("chmod"), + process.setCommand({deviceConfiguration()->filePath("chmod"), {"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); }; const auto errorHandler = [=](const QtcProcess &process) { const QString error = process.errorString(); if (!error.isEmpty()) { - q->addWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") - .arg(file.remoteFilePath(), error)); + addWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + .arg(file.remoteFilePath(), error)); } else if (process.exitCode() != 0) { - q->addWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") - .arg(file.remoteFilePath(), process.cleanedStdErr())); + addWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") + .arg(file.remoteFilePath(), process.cleanedStdErr())); } }; return Process(setupHandler, {}, errorHandler); } -TaskItem GenericDirectUploadStepPrivate::chmodTree(const TreeStorage &storage) +TaskItem GenericDirectUploadStep::chmodTree(const TreeStorage &storage) { const auto setupChmodHandler = [=](TaskTree &tree) { QList filesToChmod; @@ -243,12 +270,12 @@ Group GenericDirectUploadStep::deployRecipe() { const auto preFilesToStat = [this](UploadStorage *storage) { QList filesToStat; - for (const DeployableFile &file : std::as_const(d->m_deployableFiles)) { - if (d->m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) { + for (const DeployableFile &file : std::as_const(m_deployableFiles)) { + if (m_incremental != IncrementalDeployment::Enabled || hasLocalFileChanged(file)) { storage->filesToUpload.append(file); continue; } - if (d->m_incremental == IncrementalDeployment::NotSupported) + if (m_incremental == IncrementalDeployment::NotSupported) continue; filesToStat << file; } @@ -261,7 +288,7 @@ Group GenericDirectUploadStep::deployRecipe() }; const auto postFilesToStat = [this](UploadStorage *storage) { - return d->m_incremental == IncrementalDeployment::NotSupported + return m_incremental == IncrementalDeployment::NotSupported ? QList() : storage->filesToUpload; }; const auto postStatEndHandler = [this](UploadStorage *storage, const DeployableFile &file, @@ -277,51 +304,17 @@ Group GenericDirectUploadStep::deployRecipe() const TreeStorage storage; const Group root { Storage(storage), - d->statTree(storage, preFilesToStat, preStatEndHandler), - d->uploadTask(storage), + statTree(storage, preFilesToStat, preStatEndHandler), + uploadTask(storage), Group { - d->chmodTree(storage), - d->statTree(storage, postFilesToStat, postStatEndHandler) + chmodTree(storage), + statTree(storage, postFilesToStat, postStatEndHandler) }, OnGroupDone(doneHandler) }; return root; } -GenericDirectUploadStep::GenericDirectUploadStep(BuildStepList *bsl, Utils::Id id) - : AbstractRemoteLinuxDeployStep(bsl, id), - d(new GenericDirectUploadStepPrivate(this)) -{ - auto incremental = addAspect(); - incremental->setSettingsKey("RemoteLinux.GenericDirectUploadStep.Incremental"); - incremental->setLabel(Tr::tr("Incremental deployment"), - BoolAspect::LabelPlacement::AtCheckBox); - incremental->setValue(true); - incremental->setDefaultValue(true); - - auto ignoreMissingFiles = addAspect(); - ignoreMissingFiles->setSettingsKey("RemoteLinux.GenericDirectUploadStep.IgnoreMissingFiles"); - ignoreMissingFiles->setLabel(Tr::tr("Ignore missing files"), - BoolAspect::LabelPlacement::AtCheckBox); - ignoreMissingFiles->setValue(false); - - setInternalInitializer([this, incremental, ignoreMissingFiles] { - d->m_incremental = incremental->value() - ? IncrementalDeployment::Enabled : IncrementalDeployment::Disabled; - d->m_ignoreMissingFiles = ignoreMissingFiles->value(); - return isDeploymentPossible(); - }); - - setRunPreparer([this] { - d->m_deployableFiles = target()->deploymentData().allFiles(); - }); -} - -GenericDirectUploadStep::~GenericDirectUploadStep() -{ - delete d; -} - // Factory GenericDirectUploadStepFactory::GenericDirectUploadStepFactory() @@ -330,4 +323,4 @@ GenericDirectUploadStepFactory::GenericDirectUploadStepFactory() setDisplayName(Tr::tr("Upload files via SFTP")); } -} // RemoteLinux +} // RemoteLinux::Internal diff --git a/src/plugins/remotelinux/genericdirectuploadstep.h b/src/plugins/remotelinux/genericdirectuploadstep.h index 49b9f3b5004..3e825caf5c6 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.h +++ b/src/plugins/remotelinux/genericdirectuploadstep.h @@ -3,33 +3,14 @@ #pragma once -#include "remotelinux_export.h" +#include -#include "abstractremotelinuxdeploystep.h" +namespace RemoteLinux::Internal { -namespace RemoteLinux { - -class REMOTELINUX_EXPORT GenericDirectUploadStep : public AbstractRemoteLinuxDeployStep -{ - Q_OBJECT - -public: - GenericDirectUploadStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); - ~GenericDirectUploadStep() override; - - bool isDeploymentNecessary() const final; - Utils::Tasking::Group deployRecipe() final; - -private: - friend class GenericDirectUploadStepPrivate; - class GenericDirectUploadStepPrivate *d; -}; - -class REMOTELINUX_EXPORT GenericDirectUploadStepFactory - : public ProjectExplorer::BuildStepFactory +class GenericDirectUploadStepFactory : public ProjectExplorer::BuildStepFactory { public: GenericDirectUploadStepFactory(); }; -} // RemoteLinux +} // RemoteLinux::Internal From 14ecda9ca2635de205c15e13562c8550c6977343 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 5 Apr 2023 14:18:11 +0200 Subject: [PATCH 0500/1447] ProjectExplorer: Rename BuildStepFactory::cloneStep{,Creator} It clones the functor to create the step, not a step as such. Change-Id: Ie07b321e28fae888bb800a574a717251f3661a2f Reviewed-by: Christian Kandeler --- src/plugins/boot2qt/qdbplugin.cpp | 2 +- src/plugins/projectexplorer/buildstep.cpp | 2 +- src/plugins/projectexplorer/buildstep.h | 2 +- src/plugins/qnx/qnxplugin.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index 41fc79e2a25..66196e246bb 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -101,7 +101,7 @@ class QdbDeployStepFactory : public BuildStepFactory public: explicit QdbDeployStepFactory(Id existingStepId) { - cloneStep(existingStepId); + cloneStepCreator(existingStepId); setSupportedConfiguration(Constants::QdbDeployConfigurationId); setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 156aa5753f1..69f05e41c4e 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -380,7 +380,7 @@ QString BuildStepFactory::displayName() const return m_displayName; } -void BuildStepFactory::cloneStep(Utils::Id exitstingStepId, Utils::Id overrideNewStepId) +void BuildStepFactory::cloneStepCreator(Id exitstingStepId, Id overrideNewStepId) { m_stepId = {}; m_creator = {}; diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h index 11adc4cf5fe..46be75f5633 100644 --- a/src/plugins/projectexplorer/buildstep.h +++ b/src/plugins/projectexplorer/buildstep.h @@ -171,7 +171,7 @@ protected: m_stepId = id; m_creator = [id](BuildStepList *bsl) { return new BuildStepType(bsl, id); }; } - void cloneStep(Utils::Id exitstingStepId, Utils::Id overrideNewStepId = {}); + void cloneStepCreator(Utils::Id exitstingStepId, Utils::Id overrideNewStepId = {}); void setSupportedStepList(Utils::Id id); void setSupportedStepLists(const QList &ids); diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index d2cb1964ce5..ef09b0b7b46 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -46,7 +46,7 @@ class QnxDeployStepFactory : public BuildStepFactory public: QnxDeployStepFactory(Utils::Id existingStepId, Utils::Id overrideId = {}) { - cloneStep(existingStepId, overrideId); + cloneStepCreator(existingStepId, overrideId); setSupportedConfiguration(Constants::QNX_QNX_DEPLOYCONFIGURATION_ID); setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } From 37f2d6846457b2dbeca9da911ba1b6d70d84e972 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 5 Apr 2023 10:34:32 +0200 Subject: [PATCH 0501/1447] CppModelManager: Pass context object into signal connection Change-Id: I6b66fbc6300597534a1498e4abbd8c3162cee73e Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/cppeditor/cppmodelmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 0b8537925f3..34da9da3f4c 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -886,7 +886,7 @@ void CppModelManager::initCppTools() connect(VcsManager::instance(), &VcsManager::repositoryChanged, this, &CppModelManager::updateModifiedSourceFiles); connect(DocumentManager::instance(), &DocumentManager::filesChangedInternally, - [this](const FilePaths &filePaths) { + this, [this](const FilePaths &filePaths) { updateSourceFiles(toSet(filePaths)); }); From 55cdfeab97a4c731f938a92fabfc795e1242a3db Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 5 Apr 2023 13:32:22 +0200 Subject: [PATCH 0502/1447] GenericGdbServerProvider: Fix a warning about unused variable Amends 617d93761e895f908bb766dfc03a32c4aca73a3f Change-Id: I7f9d89f8ff10e1618e9a02912a6c993311e9622b Reviewed-by: hjk --- .../baremetal/debugservers/gdb/genericgdbserverprovider.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h b/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h index 7a89877bebf..98ca17451c1 100644 --- a/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h +++ b/src/plugins/baremetal/debugservers/gdb/genericgdbserverprovider.h @@ -19,8 +19,8 @@ class GenericGdbServerProvider final : public GdbServerProvider private: GenericGdbServerProvider(); QSet supportedStartupModes() const final; - ProjectExplorer::RunWorker *targetRunner( - ProjectExplorer::RunControl *runControl) const final { + ProjectExplorer::RunWorker *targetRunner(ProjectExplorer::RunControl *runControl) const final { + Q_UNUSED(runControl) // Generic Runner assumes GDB Server already running return nullptr; } From 5b220e3a49e6fadc44ab0235f4d8e304543beb4a Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Wed, 5 Apr 2023 13:25:24 +0200 Subject: [PATCH 0503/1447] Fix typo in method name Change-Id: Icd8c057fa55cf1fb5d7cba7ab283237a20ab091f Reviewed-by: Fabian Kosmale Reviewed-by: David Schulz Reviewed-by: Reviewed-by: Qt CI Bot --- .../qmljseditor/qmljseditingsettingspage.cpp | 14 +++++++------- src/plugins/qmljseditor/qmljseditingsettingspage.h | 4 ++-- src/plugins/qmljseditor/qmllssettings.cpp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 6d9e95f4389..91ec37fcd65 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -181,12 +181,12 @@ void QmlJsEditingSettings::setUseCustomFormatCommand(bool customCommand) m_useCustomFormatCommand = customCommand; } -QmllsSettings &QmlJsEditingSettings::qmllsSettigs() +QmllsSettings &QmlJsEditingSettings::qmllsSettings() { return m_qmllsSettings; } -const QmllsSettings &QmlJsEditingSettings::qmllsSettigs() const +const QmllsSettings &QmlJsEditingSettings::qmllsSettings() const { return m_qmllsSettings; } @@ -239,10 +239,10 @@ public: uiQmlOpenComboBox->setSizeAdjustPolicy(QComboBox::QComboBox::AdjustToContents); useQmlls = new QCheckBox(Tr::tr("Use qmlls (EXPERIMENTAL!)")); - useQmlls->setChecked(s.qmllsSettigs().useQmlls); + useQmlls->setChecked(s.qmllsSettings().useQmlls); useLatestQmlls = new QCheckBox(Tr::tr("Always use latest qmlls")); - useLatestQmlls->setChecked(s.qmllsSettigs().useLatestQmlls); - useLatestQmlls->setEnabled(s.qmllsSettigs().useQmlls); + useLatestQmlls->setChecked(s.qmllsSettings().useLatestQmlls); + useLatestQmlls->setEnabled(s.qmllsSettings().useQmlls); QObject::connect(useQmlls, &QCheckBox::stateChanged, this, [this](int checked) { useLatestQmlls->setEnabled(checked != Qt::Unchecked); }); @@ -314,8 +314,8 @@ public: s.setFormatCommandOptions(formatCommandOptions->text()); s.setFoldAuxData(foldAuxData->isChecked()); s.setUiQmlOpenMode(uiQmlOpenComboBox->currentData().toString()); - s.qmllsSettigs().useQmlls = useQmlls->isChecked(); - s.qmllsSettigs().useLatestQmlls = useLatestQmlls->isChecked(); + s.qmllsSettings().useQmlls = useQmlls->isChecked(); + s.qmllsSettings().useLatestQmlls = useLatestQmlls->isChecked(); s.set(); } diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.h b/src/plugins/qmljseditor/qmljseditingsettingspage.h index 43aa9ee336a..dc6bf1e9fd9 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.h +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.h @@ -52,8 +52,8 @@ public: bool useCustomFormatCommand() const; void setUseCustomFormatCommand(bool customCommand); - QmllsSettings &qmllsSettigs(); - const QmllsSettings &qmllsSettigs() const; + QmllsSettings &qmllsSettings(); + const QmllsSettings &qmllsSettings() const; const QString uiQmlOpenMode() const; void setUiQmlOpenMode(const QString &mode); diff --git a/src/plugins/qmljseditor/qmllssettings.cpp b/src/plugins/qmljseditor/qmllssettings.cpp index 572d8aec786..eb98c041fa5 100644 --- a/src/plugins/qmljseditor/qmllssettings.cpp +++ b/src/plugins/qmljseditor/qmllssettings.cpp @@ -90,7 +90,7 @@ void QmllsSettingsManager::setupAutoupdate() void QmllsSettingsManager::checkForChanges() { FilePath newLatest = evaluateLatestQmlls(); - QmllsSettings newSettings = QmlJsEditingSettings::get().qmllsSettigs(); + QmllsSettings newSettings = QmlJsEditingSettings::get().qmllsSettings(); if (m_lastSettings == newSettings && newLatest == m_latestQmlls) return; qCDebug(qmllsLog) << "qmlls settings changed:" << newSettings.useQmlls From 0bb8cd2d6879169ed927ff64121c8d2739c13c33 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 30 Mar 2023 14:22:32 +0200 Subject: [PATCH 0504/1447] AutoTest: Tweak wizard a bit Provide a version for creating Boost tests using the shared library approach. Add second variant for creating Boost tests. The former version is the header only variant and can not get extended with further cpp files without modifying project files and the existing cpp file. Task-number: QTCREATORBUG-28846 Change-Id: Ie7ecc339dcbe11804ce19bdba20e8db36b893a50 Reviewed-by: David Schulz --- .../templates/wizards/autotest/files/tst.pro | 29 ++++++++++++++ .../templates/wizards/autotest/files/tst.qbs | 39 +++++++++++++++++++ .../templates/wizards/autotest/files/tst.txt | 27 +++++++++++++ .../wizards/autotest/files/tst_main.cpp | 11 +++++- .../wizards/autotest/files/tst_src_boost.cpp | 13 +++++++ .../templates/wizards/autotest/wizard.json | 25 ++++++++++-- 6 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 share/qtcreator/templates/wizards/autotest/files/tst_src_boost.cpp diff --git a/share/qtcreator/templates/wizards/autotest/files/tst.pro b/share/qtcreator/templates/wizards/autotest/files/tst.pro index 49ab1c90d83..766b0c14ae1 100644 --- a/share/qtcreator/templates/wizards/autotest/files/tst.pro +++ b/share/qtcreator/templates/wizards/autotest/files/tst.pro @@ -70,6 +70,35 @@ isEmpty(BOOST_INCLUDE_DIR): { SOURCES += \\ %{MainCppName} @endif +@if "%{TestFrameWork}" == "BoostTest_dyn" +TEMPLATE = app +CONFIG -= qt +CONFIG -= app_bundle +CONFIG += console + +isEmpty(BOOST_INSTALL_DIR): BOOST_INSTALL_DIR=$$(BOOST_INSTALL_DIR) +@if "%{BoostInstallDir}" != "" +# set by Qt Creator wizard +isEmpty(BOOST_INSTALL_DIR): BOOST_INSTALL_DIR="%{BoostInstallDir}" +@endif +!isEmpty(BOOST_INSTALL_DIR) { + win32: INCLUDEPATH *= $${BOOST_INSTALL_DIR} + else: INCLUDEPATH *= $${BOOST_INSTALL_DIR}/include +} +# Windows: adapt to name scheme, e.g. lib64-msvc-14.2 +!isEmpty(BOOST_INSTALL_DIR): LIBS *= -L$${BOOST_INSTALL_DIR}/lib +# Windows: adapt to name scheme, e.g. boost_unit_test_framework-vc142-mt-gd-x64-1_80 +LIBS *= -lboost_unit_test_framework +DEFINES *= BOOST_UNIT_TEST_FRAMEWORK_DYN_LINK + +isEmpty(BOOST_INSTALL_DIR): { + message("BOOST_INSTALL_DIR is not set, assuming Boost can be found automatically in your system") +} + +SOURCES += \\ + %{MainCppName} \\ + %{TestCaseFileWithCppSuffix} +@endif @if "%{TestFrameWork}" == "Catch2" TEMPLATE = app @if "%{Catch2NeedsQt}" == "true" diff --git a/share/qtcreator/templates/wizards/autotest/files/tst.qbs b/share/qtcreator/templates/wizards/autotest/files/tst.qbs index 99a218090ed..dda4df02cc9 100644 --- a/share/qtcreator/templates/wizards/autotest/files/tst.qbs +++ b/share/qtcreator/templates/wizards/autotest/files/tst.qbs @@ -7,6 +7,11 @@ import "googlecommon.js" as googleCommon import qbs.Environment import qbs.File @endif +@if "%{TestFrameWork}" == "BoostTest_dyn" +import qbs.Environment +import qbs.File +import qbs.FileInfo +@endif @if "%{TestFrameWork}" == "Catch2" import qbs.Environment import qbs.File @@ -116,6 +121,40 @@ CppApplication { files: [ "%{MainCppName}" ] +@endif +@if "%{TestFrameWork}" == "BoostTest_dyn" + type: "application" + + property string boostInstallDir: { + if (typeof Environment.getEnv("BOOST_INSTALL_DIR") !== 'undefined') + return Environment.getEnv("BOOST_INSTALL_DIR"); + return "%{BoostInstallDir}"; // set by Qt Creator wizard + } + + Properties { + condition: boostInstallDir && File.exists(boostInstallDir) + cpp.includePaths: base.concat([qbs.hostOS.contains("windows") + ? boostInstallDir + : FileInfo.joinPaths(boostInstallDir, "include")]) + // Windows: adapt to different directory layout, e.g. "lib64-msvc-14.2" + cpp.libraryPaths: base.concat([FileInfo.joinPaths(boostInstallDir, "lib")]) + } + cpp.defines: base.concat("BOOST_UNIT_TEST_FRAMEWORK_DYN_LINK") + // Windows: adapt to name scheme, e.g. "boost_unit_test_framework-vc142-mt-gd-x64-1_80" + cpp.dynamicLibraries: ["boost_unit_test_framework"] + + condition: { + if (!boostInstallDir) + console.log("BOOST_INSTALL_DIR is not set, assuming Boost can be " + + "found automatically in your system"); + return true; + } + + files: [ + "%{MainCppName}", + "%{TestCaseFileWithCppSuffix}", + ] + @endif @if "%{TestFrameWork}" == "Catch2" type: "application" diff --git a/share/qtcreator/templates/wizards/autotest/files/tst.txt b/share/qtcreator/templates/wizards/autotest/files/tst.txt index 7e1bd4c46ee..739ec2c26a8 100644 --- a/share/qtcreator/templates/wizards/autotest/files/tst.txt +++ b/share/qtcreator/templates/wizards/autotest/files/tst.txt @@ -133,6 +133,33 @@ elseif (EXISTS ${BOOST_INCLUDE_DIR}) include_directories(${BOOST_INCLUDE_DIR}) endif () @endif +@if "%{TestFrameWork}" == "BoostTest_dyn" +set(Boost_USE_STATIC_LIBS OFF) +set(Boost_USE_MULTITHREADED ON) +set(Boost_USE_STATIC_RUNTIME OFF) + +if (DEFINED ENV{BOOST_INSTALL_DIR}) + set(BOOST_INSTALL_DIR $ENV{BOOST_INSTALL_DIR}) +else () + set(BOOST_INSTALL_DIR "%{BoostInstallDir}") # set by Qt Creator wizard +endif () +if (BOOST_INSTALL_DIR STREQUAL "") + message("BOOST_INSTALL_DIR not set, assuming Boost can be found automatically in your system") +elseif (EXISTS ${BOOST_INSTALL_DIR}) + set(BOOST_ROOT ${BOOST_INSTALL_DIR}) +endif () +find_package(Boost COMPONENTS unit_test_framework REQUIRED) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_executable(%{TestCaseName} %{MainCppName} %{TestCaseFileGTestWithCppSuffix}) +add_test(NAME %{TestCaseName} COMMAND %{TestCaseName}) +if (Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) + target_link_libraries(%{TestCaseName} PUBLIC ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) +endif () +@endif @if "%{TestFrameWork}" == "Catch2" SET(CMAKE_CXX_STANDARD 11) diff --git a/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp b/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp index ac88e1b0f1d..1c915089d6f 100644 --- a/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp +++ b/share/qtcreator/templates/wizards/autotest/files/tst_main.cpp @@ -21,13 +21,22 @@ int main(int argc, char *argv[]) } @endif @if "%{TestFrameWork}" == "BoostTest" -#define BOOST_TEST_MODULE %{TestSuiteName} +#define BOOST_TEST_MODULE My test module #include +BOOST_AUTO_TEST_SUITE( %{TestSuiteName} ) + BOOST_AUTO_TEST_CASE( %{TestCaseName} ) { BOOST_TEST( true /* test assertion */ ); } + +BOOST_AUTO_TEST_SUITE_END() +@endif +@if "%{TestFrameWork}" == "BoostTest_dyn" +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE My test module +#include @endif @if "%{TestFrameWork}" == "Catch2" @if "%{Catch2NeedsQt}" == "true" diff --git a/share/qtcreator/templates/wizards/autotest/files/tst_src_boost.cpp b/share/qtcreator/templates/wizards/autotest/files/tst_src_boost.cpp new file mode 100644 index 00000000000..d523db48b99 --- /dev/null +++ b/share/qtcreator/templates/wizards/autotest/files/tst_src_boost.cpp @@ -0,0 +1,13 @@ +%{Cpp:LicenseTemplate}\ +@if "%{TestFrameWork}" == "BoostTest_dyn" +#define BOOST_TEST_DYN_LINK +#include + +BOOST_AUTO_TEST_SUITE( %{TestSuiteName} ) + +BOOST_AUTO_TEST_CASE( %{TestCaseName} ) +{ + BOOST_TEST( true /* test assertion */ ); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/share/qtcreator/templates/wizards/autotest/wizard.json b/share/qtcreator/templates/wizards/autotest/wizard.json index ae8fdb9d121..6f19d679eac 100644 --- a/share/qtcreator/templates/wizards/autotest/wizard.json +++ b/share/qtcreator/templates/wizards/autotest/wizard.json @@ -90,9 +90,13 @@ "value": "QtQuickTest" }, { - "trKey": "Boost Test", + "trKey": "Boost Test (header only)", "value": "BoostTest" }, + { + "trKey": "Boost Test (shared libraries)", + "value": "BoostTest_dyn" + }, { "trKey": "Catch2", "value": "Catch2" @@ -113,7 +117,7 @@ { "name": "TestSuiteName", "trDisplayName": "Test suite name:", - "visible": "%{JS: ['BoostTest', 'GTest'].indexOf(value('TestFrameWork')) >= 0}", + "visible": "%{JS: ['BoostTest', 'BoostTest_dyn', 'GTest'].indexOf(value('TestFrameWork')) >= 0}", "mandatory": true, "type": "LineEdit", "data": { "validator": "^[a-zA-Z_0-9]+$" } @@ -181,6 +185,16 @@ "kind": "existingDirectory" } }, + { + "name": "BoostInstallDir", + "trDisplayName": "Boost install directory (optional):", + "visible": "%{JS: value('TestFrameWork') == 'BoostTest_dyn'}", + "mandatory": false, + "type": "PathChooser", + "data": { + "kind": "existingDirectory" + } + }, { "name": "CatchIncDir", "trDisplayName": "Catch2 include directory (optional):", @@ -300,9 +314,14 @@ { "source": "files/tst_main.cpp", "target": "%{MainCppName}", - "condition": "%{JS: ['GTest', 'QtQuickTest', 'BoostTest', 'Catch2'].indexOf(value('TestFrameWork')) >= 0}", + "condition": "%{JS: ['GTest', 'QtQuickTest', 'BoostTest', 'BoostTest_dyn', 'Catch2'].indexOf(value('TestFrameWork')) >= 0}", "openInEditor": true }, + { + "source": "files/tst_src_boost.cpp", + "target": "%{TestCaseFileWithCppSuffix}", + "condition": "%{JS: value('TestFrameWork') === 'BoostTest_dyn'}" + }, { "source": "files/tst_qml.tmpl", "target": "%{TestCaseFileWithQmlSuffix}", From 4b73de5580971533807306d5067c3f37be410f51 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 4 Apr 2023 12:43:40 +0100 Subject: [PATCH 0505/1447] Android: allow non-integer platform sdk versions Some of the more recent SDK platform versions don't follow the form android-xx (x being integer) and can contain non-integer characters or other sections such as android-33-ext4, which were not showing on the list of SDK platform versions in the project's settings. Task-number: QTBUG-112465 Change-Id: I3de14c4f1b15a64dcced48c6e8817efbda6677bc Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/android/androidconfigurations.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index cf1b005bde5..3c3b64062ec 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -432,8 +432,12 @@ QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms) QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform) { - return platform && platform->apiLevel() > 0 ? - QString("android-%1").arg(platform->apiLevel()) : ""; + if (platform && platform->apiLevel() > 0) { + QString sdkStylePath = platform->sdkStylePath(); + return sdkStylePath.remove("platforms;"); + } + + return {}; } FilePath AndroidConfig::adbToolPath() const From f5c41a7f8350f210ee2e2815bd07669c40449b83 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 24 Jan 2023 11:28:28 +0100 Subject: [PATCH 0506/1447] Python: Allow installing multiple pip packages in one task Change-Id: If6cc1373cd38c07b29ac48fa51bf0ed35d6f104b Reviewed-by: Christian Stenger --- src/plugins/python/pipsupport.cpp | 37 ++++++++++++++------- src/plugins/python/pipsupport.h | 7 ++-- src/plugins/python/pyside.cpp | 2 +- src/plugins/python/pythonlanguageclient.cpp | 2 +- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 96aa4f64e2f..e84e8f63a6d 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -35,23 +35,31 @@ PipInstallTask::PipInstallTask(const FilePath &python) m_watcher.setFuture(m_future.future()); } -void PipInstallTask::setPackage(const PipPackage &package) +void PipInstallTask::addPackage(const PipPackage &package) { - m_package = package; + m_packages << package; +} + +void PipInstallTask::setPackages(const QList &packages) +{ + m_packages = packages; } void PipInstallTask::run() { - if (m_package.packageName.isEmpty()) { + if (m_packages.isEmpty()) { emit finished(false); return; } - const QString taskTitle = Tr::tr("Install %1").arg(m_package.displayName); + const QString taskTitle = Tr::tr("Install Python Packages"); Core::ProgressManager::addTask(m_future.future(), taskTitle, pipInstallTaskId); - QString package = m_package.packageName; - if (!m_package.version.isEmpty()) - package += "==" + m_package.version; - QStringList arguments = {"-m", "pip", "install", package}; + QStringList arguments = {"-m", "pip", "install"}; + for (const PipPackage &package : m_packages) { + QString pipPackage = package.packageName; + if (!package.version.isEmpty()) + pipPackage += "==" + package.version; + arguments << pipPackage; + } // add --user to global pythons, but skip it for venv pythons if (!QDir(m_python.parentDir().toString()).exists("activate")) @@ -62,7 +70,7 @@ void PipInstallTask::run() Core::MessageManager::writeDisrupting( Tr::tr("Running \"%1\" to install %2.") - .arg(m_process.commandLine().toUserOutput(), m_package.displayName)); + .arg(m_process.commandLine().toUserOutput(), packagesDisplayName())); m_killTimer.setSingleShot(true); m_killTimer.start(5 /*minutes*/ * 60 * 1000); @@ -74,7 +82,7 @@ void PipInstallTask::cancel() m_process.waitForFinished(); Core::MessageManager::writeFlashing( Tr::tr("The %1 installation was canceled by %2.") - .arg(m_package.displayName, m_killTimer.isActive() ? Tr::tr("user") : Tr::tr("time out"))); + .arg(packagesDisplayName(), m_killTimer.isActive() ? Tr::tr("user") : Tr::tr("time out"))); } void PipInstallTask::handleDone() @@ -82,8 +90,8 @@ void PipInstallTask::handleDone() m_future.reportFinished(); const bool success = m_process.result() == ProcessResult::FinishedWithSuccess; if (!success) { - Core::MessageManager::writeFlashing(Tr::tr("Installing the %1 failed with exit code %2") - .arg(m_package.displayName).arg(m_process.exitCode())); + Core::MessageManager::writeFlashing(Tr::tr("Installing %1 failed with exit code %2") + .arg(packagesDisplayName()).arg(m_process.exitCode())); } emit finished(success); } @@ -102,6 +110,11 @@ void PipInstallTask::handleError() Core::MessageManager::writeSilently(stdErr); } +QString PipInstallTask::packagesDisplayName() const +{ + return Utils::transform(m_packages, &PipPackage::displayName).join(", "); +} + void PipPackageInfo::parseField(const QString &field, const QStringList &data) { if (field.isEmpty()) diff --git a/src/plugins/python/pipsupport.h b/src/plugins/python/pipsupport.h index e5f53768ce9..aa17edca82f 100644 --- a/src/plugins/python/pipsupport.h +++ b/src/plugins/python/pipsupport.h @@ -66,7 +66,8 @@ class PipInstallTask : public QObject Q_OBJECT public: explicit PipInstallTask(const Utils::FilePath &python); - void setPackage(const PipPackage &package); + void addPackage(const PipPackage &package); + void setPackages(const QList &packages); void run(); signals: @@ -78,8 +79,10 @@ private: void handleOutput(); void handleError(); + QString packagesDisplayName() const; + const Utils::FilePath m_python; - PipPackage m_package; + QList m_packages; Utils::QtcProcess m_process; QFutureInterface m_future; QFutureWatcher m_watcher; diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index f994108cae0..1309f777ed9 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -88,7 +88,7 @@ void PySideInstaller::installPyside(const FilePath &python, if (success) emit pySideInstalled(python, pySide); }); - install->setPackage(PipPackage(pySide)); + install->setPackages({PipPackage(pySide)}); install->run(); } diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index 088cd516440..cd95d4d329f 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -305,7 +305,7 @@ void PyLSConfigureAssistant::installPythonLanguageServer(const FilePath &python, install->deleteLater(); }); - install->setPackage(PipPackage{"python-lsp-server[all]", "Python Language Server"}); + install->setPackages({PipPackage{"python-lsp-server[all]", "Python Language Server"}}); install->run(); } From 522de9bfd7afc30ae32affa728b7e929b46ccc60 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 5 Apr 2023 11:15:02 +0200 Subject: [PATCH 0507/1447] Devices: Unify Port Gathering method All devices that support it use the same mechanism to gather ports so this patch removes the individual implementations in favor of a single one in IDevice.cpp. This patch also removes: * canAutodetectPorts() as it was not used. * Port::parseFrom...Output as they are not used anymore. Change-Id: I8ecedec2d71e60985402387982c64311c5a651e6 Reviewed-by: hjk Reviewed-by: --- src/libs/utils/port.cpp | 50 ------------------- src/libs/utils/port.h | 2 - src/plugins/android/androiddevice.cpp | 5 -- src/plugins/android/androiddevice.h | 1 - src/plugins/docker/dockerdevice.cpp | 29 +---------- src/plugins/docker/dockerdevice.h | 2 - src/plugins/ios/iosdevice.cpp | 6 --- src/plugins/ios/iosdevice.h | 1 - src/plugins/ios/iossimulator.cpp | 5 -- src/plugins/ios/iossimulator.h | 1 - .../devicesupport/desktopdevice.cpp | 30 ----------- .../devicesupport/desktopdevice.h | 2 - .../projectexplorer/devicesupport/idevice.cpp | 21 ++++++++ .../projectexplorer/devicesupport/idevice.h | 5 +- src/plugins/qnx/qnxdevice.cpp | 10 ---- src/plugins/remotelinux/linuxdevice.cpp | 33 ------------ src/plugins/remotelinux/linuxdevice.h | 2 - 17 files changed, 23 insertions(+), 182 deletions(-) diff --git a/src/libs/utils/port.cpp b/src/libs/utils/port.cpp index ceab772b620..cf56047f3a8 100644 --- a/src/libs/utils/port.cpp +++ b/src/libs/utils/port.cpp @@ -33,56 +33,6 @@ quint16 Port::number() const QTC_ASSERT(isValid(), return -1); return quint16(m_port); } -QList Port::parseFromSedOutput(const QByteArray &output) -{ - QList ports; - const QList portStrings = output.split('\n'); - for (const QByteArray &portString : portStrings) { - if (portString.size() != 4) - continue; - bool ok; - const Port port(portString.toInt(&ok, 16)); - if (ok) { - if (!ports.contains(port)) - ports << port; - } else { - qWarning("%s: Unexpected string '%s' is not a port.", - Q_FUNC_INFO, portString.data()); - } - } - return ports; -} - -QList Port::parseFromCatOutput(const QByteArray &output) -{ - // Parse something like - // sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode - // : 00000000:2717 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 3995881 1 0000000000000000 100 0 0 10 0 - // : 00000000:2716 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 3594482 1 0000000000000000 100 0 0 10 0 - const QRegularExpression re(".*: [[:xdigit:]]*:([[:xdigit:]]{4}).*"); - - QList ports; - const QStringList lines = QString::fromLocal8Bit(output).split('\n'); - for (const QString &line : lines) { - const QRegularExpressionMatch match = re.match(line); - if (!match.hasMatch()) - continue; - const QString portString = match.captured(1); - if (portString.size() != 4) - continue; - bool ok; - const Port port(portString.toInt(&ok, 16)); - if (ok) { - if (!ports.contains(port)) - ports << port; - } else { - qWarning("%s: Unexpected string '%s' is not a port.", - Q_FUNC_INFO, qPrintable(portString)); - } - } - return ports; -} - QList Port::parseFromNetstatOutput(const QByteArray &output) { QList ports; diff --git a/src/libs/utils/port.h b/src/libs/utils/port.h index 3202ac5f18f..a3543f72a30 100644 --- a/src/libs/utils/port.h +++ b/src/libs/utils/port.h @@ -24,8 +24,6 @@ public: QString toString() const { return QString::number(m_port); } - static QList parseFromSedOutput(const QByteArray &output); - static QList parseFromCatOutput(const QByteArray &output); static QList parseFromNetstatOutput(const QByteArray &output); friend bool operator<(const Port &p1, const Port &p2) { return p1.number() < p2.number(); } diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 6346c47d7eb..bd518a4e707 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -388,11 +388,6 @@ IDeviceWidget *AndroidDevice::createWidget() return new AndroidDeviceWidget(sharedFromThis()); } -bool AndroidDevice::canAutoDetectPorts() const -{ - return true; -} - DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const { return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation()); diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index 0d17c73ec81..551d39b934d 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -61,7 +61,6 @@ private: void addActionsIfNotFound(); ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override; ProjectExplorer::IDeviceWidget *createWidget() override; - bool canAutoDetectPorts() const override; ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override; QUrl toolControlChannel(const ControlChannelHint &) const override; diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 4475f9fcbf3..474bc402e70 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -419,7 +419,7 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat { setFileAccess(&d->m_fileAccess); setDisplayType(Tr::tr("Docker")); - setOsType(OsTypeOtherUnix); + setOsType(OsTypeLinux); setDefaultDisplayName(Tr::tr("Docker Image")); setupId(IDevice::ManuallyAdded); setType(Constants::DOCKER_DEVICE_TYPE); @@ -832,33 +832,6 @@ ProcessInterface *DockerDevice::createProcessInterface() const return new DockerProcessImpl(this->sharedFromThis(), d); } -bool DockerDevice::canAutoDetectPorts() const -{ - return true; -} - -PortsGatheringMethod DockerDevice::portsGatheringMethod() const -{ - return {[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { - // We might encounter the situation that protocol is given IPv6 - // but the consumer of the free port information decides to open - // an IPv4(only) port. As a result the next IPv6 scan will - // report the port again as open (in IPv6 namespace), while the - // same port in IPv4 namespace might still be blocked, and - // re-use of this port fails. - // GDBserver behaves exactly like this. - - Q_UNUSED(protocol) - - // /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6 - return {filePath("sed"), - "-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*", - CommandLine::Raw}; - }, - - &Port::parseFromSedOutput}; -}; - DeviceProcessList *DockerDevice::createProcessListModel(QObject *parent) const { return new ProcessList(sharedFromThis(), parent); diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index affe4cf2714..bd0ce29d9d4 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -73,8 +73,6 @@ public: Utils::ProcessInterface *createProcessInterface() const override; - bool canAutoDetectPorts() const override; - ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; bool canCreateProcessModel() const override { return true; } ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override; bool hasDeviceTester() const override { return false; } diff --git a/src/plugins/ios/iosdevice.cpp b/src/plugins/ios/iosdevice.cpp index 49a07a2b101..326092fccc3 100644 --- a/src/plugins/ios/iosdevice.cpp +++ b/src/plugins/ios/iosdevice.cpp @@ -185,12 +185,6 @@ Utils::Port IosDevice::nextPort() const return Utils::Port(m_lastPort); } -bool IosDevice::canAutoDetectPorts() const -{ - return true; -} - - // IosDeviceManager IosDeviceManager::TranslationMap IosDeviceManager::translationMap() diff --git a/src/plugins/ios/iosdevice.h b/src/plugins/ios/iosdevice.h index 9f4e66c5025..ada952037d9 100644 --- a/src/plugins/ios/iosdevice.h +++ b/src/plugins/ios/iosdevice.h @@ -36,7 +36,6 @@ public: QString osVersion() const; QString cpuArchitecture() const; Utils::Port nextPort() const; - bool canAutoDetectPorts() const override; static QString name(); diff --git a/src/plugins/ios/iossimulator.cpp b/src/plugins/ios/iossimulator.cpp index b58e451400d..ceb9fd77859 100644 --- a/src/plugins/ios/iossimulator.cpp +++ b/src/plugins/ios/iossimulator.cpp @@ -66,11 +66,6 @@ Utils::Port IosSimulator::nextPort() const return Utils::Port(m_lastPort); } -bool IosSimulator::canAutoDetectPorts() const -{ - return true; -} - // IosDeviceType IosDeviceType::IosDeviceType(IosDeviceType::Type type, const QString &identifier, const QString &displayName) : diff --git a/src/plugins/ios/iossimulator.h b/src/plugins/ios/iossimulator.h index d2d69f1d0ef..988776e5086 100644 --- a/src/plugins/ios/iossimulator.h +++ b/src/plugins/ios/iossimulator.h @@ -48,7 +48,6 @@ public: ProjectExplorer::IDeviceWidget *createWidget() override; Utils::Port nextPort() const; - bool canAutoDetectPorts() const override; protected: friend class IosSimulatorFactory; diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 4ad0d59d328..2ac44ad6220 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -87,11 +87,6 @@ IDeviceWidget *DesktopDevice::createWidget() // range can be confusing to the user. Hence, disabling the widget for now. } -bool DesktopDevice::canAutoDetectPorts() const -{ - return true; -} - bool DesktopDevice::canCreateProcessModel() const { return true; @@ -107,31 +102,6 @@ DeviceProcessSignalOperation::Ptr DesktopDevice::signalOperation() const return DeviceProcessSignalOperation::Ptr(new DesktopProcessSignalOperation()); } -PortsGatheringMethod DesktopDevice::portsGatheringMethod() const -{ - return { - [this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { - // We might encounter the situation that protocol is given IPv6 - // but the consumer of the free port information decides to open - // an IPv4(only) port. As a result the next IPv6 scan will - // report the port again as open (in IPv6 namespace), while the - // same port in IPv4 namespace might still be blocked, and - // re-use of this port fails. - // GDBserver behaves exactly like this. - - Q_UNUSED(protocol) - - if (HostOsInfo::isWindowsHost() || HostOsInfo::isMacHost()) - return {filePath("netstat"), {"-a", "-n"}}; - if (HostOsInfo::isLinuxHost()) - return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}}; - return {}; - }, - - &Port::parseFromNetstatOutput - }; -} - QUrl DesktopDevice::toolControlChannel(const ControlChannelHint &) const { QUrl url; diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h index 28220f21ed6..d9cafbfda9a 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h @@ -25,10 +25,8 @@ public: IDevice::DeviceInfo deviceInformation() const override; IDeviceWidget *createWidget() override; - bool canAutoDetectPorts() const override; bool canCreateProcessModel() const override; DeviceProcessList *createProcessListModel(QObject *parent) const override; - ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; DeviceProcessSignalOperation::Ptr signalOperation() const override; QUrl toolControlChannel(const ControlChannelHint &) const override; bool usableAsBuildDevice() const override; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 2e4dbcef59f..b14e50ed13c 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -371,6 +371,27 @@ const QList IDevice::deviceActions() const return d->deviceActions; } +PortsGatheringMethod IDevice::portsGatheringMethod() const +{ + return {[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { + // We might encounter the situation that protocol is given IPv6 + // but the consumer of the free port information decides to open + // an IPv4(only) port. As a result the next IPv6 scan will + // report the port again as open (in IPv6 namespace), while the + // same port in IPv4 namespace might still be blocked, and + // re-use of this port fails. + // GDBserver behaves exactly like this. + + Q_UNUSED(protocol) + + if (filePath("/proc/net").isReadableDir()) + return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}}; + + return {filePath("netstat"), {"-a", "-n"}}; + }, + &Port::parseFromNetstatOutput}; +}; + DeviceProcessList *IDevice::createProcessListModel(QObject *parent) const { Q_UNUSED(parent) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 596637e3e08..9c2dc2122f8 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -139,10 +139,7 @@ public: void addDeviceAction(const DeviceAction &deviceAction); const QList deviceActions() const; - // Devices that can auto detect ports need not return a ports gathering method. Such devices can - // obtain a free port on demand. eg: Desktop device. - virtual bool canAutoDetectPorts() const { return false; } - virtual PortsGatheringMethod portsGatheringMethod() const { return {}; } + virtual PortsGatheringMethod portsGatheringMethod() const; virtual bool canCreateProcessModel() const { return false; } virtual DeviceProcessList *createProcessListModel(QObject *parent = nullptr) const; virtual bool hasDeviceTester() const { return false; } diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index e574a8eed78..49056d9ec40 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -78,16 +78,6 @@ public: }}); } - PortsGatheringMethod portsGatheringMethod() const final - { - return { - [this](QAbstractSocket::NetworkLayerProtocol) { - return CommandLine(filePath("netstat"), {"-na"}); - }, - &Port::parseFromNetstatOutput - }; - } - DeviceProcessSignalOperation::Ptr signalOperation() const final { return DeviceProcessSignalOperation::Ptr(new QnxDeviceProcessSignalOperation(sharedFromThis())); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 633f46dbe0b..d01ea1be8f4 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -993,39 +993,6 @@ IDeviceWidget *LinuxDevice::createWidget() return new Internal::GenericLinuxDeviceConfigurationWidget(sharedFromThis()); } -bool LinuxDevice::canAutoDetectPorts() const -{ - return true; -} - -PortsGatheringMethod LinuxDevice::portsGatheringMethod() const -{ - return { - [this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine { - // We might encounter the situation that protocol is given IPv6 - // but the consumer of the free port information decides to open - // an IPv4(only) port. As a result the next IPv6 scan will - // report the port again as open (in IPv6 namespace), while the - // same port in IPv4 namespace might still be blocked, and - // re-use of this port fails. - // GDBserver behaves exactly like this. - - Q_UNUSED(protocol) - - // We used to have - // // /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6 - // return {filePath("sed"), - // "-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*", - // - // here, but that doesn't pass quoting on double-remote setups. - // Chicken out by using a simpler command. - return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}}; - }, - - &Port::parseFromCatOutput - }; -} - DeviceProcessList *LinuxDevice::createProcessListModel(QObject *parent) const { return new ProcessList(sharedFromThis(), parent); diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index d9dad9ba75f..2094b426b4c 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -22,8 +22,6 @@ public: ProjectExplorer::IDeviceWidget *createWidget() override; - bool canAutoDetectPorts() const override; - ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override; bool canCreateProcessModel() const override { return true; } ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override; bool hasDeviceTester() const override { return true; } From 3cd5e32e9cfabe730b2aeb9503e270db4fb752c9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 06:58:39 +0200 Subject: [PATCH 0508/1447] Debugger: Start debugserver for remote macOS Change-Id: I5f713892dfbaaaecb7459c288df109bfe337f891 Reviewed-by: hjk --- src/plugins/debugger/debuggerruncontrol.cpp | 29 ++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index bbb2556d68c..e8ddb33b2c2 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -1039,14 +1039,37 @@ DebugServerRunner::DebugServerRunner(RunControl *runControl, DebugServerPortsGat cmd.setExecutable(commandLine().executable()); // FIXME: Case should not happen? } else { cmd.setExecutable(runControl->device()->debugServerPath()); - if (cmd.isEmpty()) - cmd.setExecutable(runControl->device()->filePath("gdbserver")); + + if (cmd.isEmpty()) { + if (runControl->device()->osType() == Utils::OsTypeMac) { + const FilePath debugServerLocation = runControl->device()->filePath( + "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/" + "Resources/debugserver"); + + if (debugServerLocation.isExecutableFile()) { + cmd.setExecutable(debugServerLocation); + } else { + // TODO: In the future it is expected that the debugserver will be + // replaced by lldb-server. Remove the check for debug server at that point. + const FilePath lldbserver + = runControl->device()->filePath("lldb-server").searchInPath(); + if (lldbserver.isExecutableFile()) + cmd.setExecutable(lldbserver); + } + } else { + cmd.setExecutable(runControl->device()->filePath("gdbserver")); + } + } args.clear(); - if (cmd.executable().toString().contains("lldb-server")) { + if (cmd.executable().baseName().contains("lldb-server")) { args.append("platform"); args.append("--listen"); args.append(QString("*:%1").arg(portsGatherer->gdbServer().port())); args.append("--server"); + } else if (cmd.executable().baseName() == "debugserver") { + args.append(QString("*:%1").arg(portsGatherer->gdbServer().port())); + args.append("--attach"); + args.append(QString::number(m_pid.pid())); } else { // Something resembling gdbserver if (m_useMulti) From f65206f9906a0543b733ff6ca0b9a737157ec8f7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 09:01:01 +0200 Subject: [PATCH 0509/1447] Utils: Rename Port::parseFrom function It can parse both netstat and cat /proc/net/tcp output Change-Id: Iafe37be7ace6a1eda068340b1f07e24a71724db1 Reviewed-by: hjk --- src/libs/utils/port.cpp | 2 +- src/libs/utils/port.h | 3 ++- src/plugins/projectexplorer/devicesupport/idevice.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/port.cpp b/src/libs/utils/port.cpp index cf56047f3a8..c41a65335db 100644 --- a/src/libs/utils/port.cpp +++ b/src/libs/utils/port.cpp @@ -33,7 +33,7 @@ quint16 Port::number() const QTC_ASSERT(isValid(), return -1); return quint16(m_port); } -QList Port::parseFromNetstatOutput(const QByteArray &output) +QList Port::parseFromCommandOutput(const QByteArray &output) { QList ports; const QList lines = output.split('\n'); diff --git a/src/libs/utils/port.h b/src/libs/utils/port.h index a3543f72a30..c4b46631de2 100644 --- a/src/libs/utils/port.h +++ b/src/libs/utils/port.h @@ -24,7 +24,8 @@ public: QString toString() const { return QString::number(m_port); } - static QList parseFromNetstatOutput(const QByteArray &output); + // Parses the output of "netstat -an" and "cat /proc/net/tcp" + static QList parseFromCommandOutput(const QByteArray &output); friend bool operator<(const Port &p1, const Port &p2) { return p1.number() < p2.number(); } friend bool operator<=(const Port &p1, const Port &p2) { return p1.number() <= p2.number(); } diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index b14e50ed13c..775f60e396d 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -389,7 +389,7 @@ PortsGatheringMethod IDevice::portsGatheringMethod() const return {filePath("netstat"), {"-a", "-n"}}; }, - &Port::parseFromNetstatOutput}; + &Port::parseFromCommandOutput}; }; DeviceProcessList *IDevice::createProcessListModel(QObject *parent) const From db2c5f87b1c03a88e78e23d6f120c3f37011dcdc Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 29 Mar 2023 21:13:34 +0200 Subject: [PATCH 0510/1447] Squish: Prepare perspective for object picker Visual adaption for the later addition of the object picker functionality. Change-Id: Id1c422465d4cebcea9eb366621b57a3c076385cc Reviewed-by: Reviewed-by: David Schulz --- src/plugins/squish/images/picker.png | Bin 0 -> 194 bytes src/plugins/squish/images/picker@2x.png | Bin 0 -> 362 bytes src/plugins/squish/squish.qrc | 2 + src/plugins/squish/squishperspective.cpp | 77 ++++++++++++++++++++--- src/plugins/squish/squishperspective.h | 4 ++ 5 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 src/plugins/squish/images/picker.png create mode 100644 src/plugins/squish/images/picker@2x.png diff --git a/src/plugins/squish/images/picker.png b/src/plugins/squish/images/picker.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9a13e8a199b5f5531b0411d921b601c6109d07 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4h9AW2CEqh_A)Rqbb7ithDc0J{?X4SG2zDg zX1hfkH3lgL70lv4-fcTNqp?v@M(xA#)|pdV8xKBF_Ia>fS(sUS_QUEOlJbvZZc0Qf zJCOTR;`@{B?842KJ`a-bT>k%FsJ7S6fz__z$I12oYul}OPPOm;694M+|MidWE6mxK x_WFM~hh4ye2lv-4*?wYPbl`?R@_hH37#a2@U*+Ct`ymwMI8RqUmvv4FO#qyvQvm<~ literal 0 HcmV?d00001 diff --git a/src/plugins/squish/images/picker@2x.png b/src/plugins/squish/images/picker@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..390926b891a62ee91d50c9a23765269ac676e706 GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2ALr)jS5R22vKl~XCCag_3 z&-#bUY*Uf!(d7x^*38Ps_OhO^bQ+=4YJ2VJ_Izm*7K_?N6ee} z+NiBb{L>nq9G-y6bHWl~H6ba?CmnPiSoFL+@xAB`kAdi$>W!73TXmR2SbvwTVJw{# z-^IKriS60~J7trnd+j1vCqGEl;X23R%W8E+V$mUvV8)1l|NpPQm0&;bNI*f4yw3l6 z>-Bo#SNb)$5h`!rkVHa(y5Dn@{Ec`2YVqa}P_gNTi&1SJTOS*XiwA7N_iG zwe|~U&$2mf&wnQJ{ASkdMSs`cWt{l@ZkKJS|CPVIN$U=)@dtfyW|Aq)uH63cg!t{L z|Ns8~pD*>kEJiXt=*9p4?PsR&KRgqe{xfN7>#co{PgX6rx>mo`@mVV)!`GHDvkjqw Q;-EnEboFyt=akR{0He8^xBvhE literal 0 HcmV?d00001 diff --git a/src/plugins/squish/squish.qrc b/src/plugins/squish/squish.qrc index 1a62ee1c1c6..e55323c3cc7 100644 --- a/src/plugins/squish/squish.qrc +++ b/src/plugins/squish/squish.qrc @@ -8,6 +8,8 @@ images/jumpTo@2x.png images/data.png images/data@2x.png + images/picker.png + images/picker@2x.png wizard/suite/wizard.json diff --git a/src/plugins/squish/squishperspective.cpp b/src/plugins/squish/squishperspective.cpp index fca93ce35db..b229541842a 100644 --- a/src/plugins/squish/squishperspective.cpp +++ b/src/plugins/squish/squishperspective.cpp @@ -26,10 +26,13 @@ namespace Squish { namespace Internal { -enum class IconType { StopRecord, Play, Pause, StepIn, StepOver, StepReturn, Stop }; +enum class IconType { StopRecord, Play, Pause, StepIn, StepOver, StepReturn, Stop, Inspect }; static QIcon iconForType(IconType type) { + static const Utils::Icon inspectIcon({{":/squish/images/picker.png", + Utils::Theme::IconsBaseColor}}); + switch (type) { case IconType::StopRecord: return Debugger::Icons::RECORD_ON.icon(); @@ -45,6 +48,8 @@ static QIcon iconForType(IconType type) return Debugger::Icons::STEP_OUT_TOOLBAR.icon(); case IconType::Stop: return Utils::Icons::STOP_SMALL.icon(); + case IconType::Inspect: + return inspectIcon.icon(); } return QIcon(); } @@ -209,10 +214,14 @@ void SquishPerspective::initPerspective() m_stepOutAction->setEnabled(false); m_stopAction = Debugger::createStopAction(); m_stopAction->setEnabled(false); + m_inspectAction = new QAction(this); + m_inspectAction->setIcon(iconForType(IconType::Inspect)); + m_inspectAction->setToolTip(Tr::tr("Inspect")); + m_inspectAction->setEnabled(false); - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->setContentsMargins(0, 0, 0, 0); - mainLayout->setSpacing(1); + QVBoxLayout *localsMainLayout = new QVBoxLayout; + localsMainLayout->setContentsMargins(0, 0, 0, 0); + localsMainLayout->setSpacing(1); m_localsModel.setHeader({Tr::tr("Name"), Tr::tr("Type"), Tr::tr("Value")}); auto localsView = new Utils::TreeView; @@ -220,11 +229,45 @@ void SquishPerspective::initPerspective() localsView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); localsView->setModel(&m_localsModel); localsView->setRootIsDecorated(true); - mainLayout->addWidget(localsView); - QWidget *mainWidget = new QWidget; - mainWidget->setObjectName("SquishLocalsView"); - mainWidget->setWindowTitle(Tr::tr("Squish Locals")); - mainWidget->setLayout(mainLayout); + localsMainLayout->addWidget(localsView); + QWidget *localsWidget = new QWidget; + localsWidget->setObjectName("SquishLocalsView"); + localsWidget->setWindowTitle(Tr::tr("Squish Locals")); + localsWidget->setLayout(localsMainLayout); + + QVBoxLayout *objectsMainLayout = new QVBoxLayout; + objectsMainLayout->setContentsMargins(0, 0, 0, 0); + objectsMainLayout->setSpacing(1); + + m_objectsModel.setHeader({Tr::tr("Object"), Tr::tr("Type")}); + auto objectsView = new Utils::TreeView; + objectsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + objectsView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + objectsView->setModel(&m_objectsModel); + objectsView->setRootIsDecorated(true); + objectsMainLayout->addWidget(objectsView); + + QWidget *objectWidget = new QWidget; + objectWidget->setObjectName("SquishObjectsView"); + objectWidget->setWindowTitle(Tr::tr("Squish Objects")); + objectWidget->setLayout(objectsMainLayout); + + QVBoxLayout *propertiesMainLayout = new QVBoxLayout; + propertiesMainLayout->setContentsMargins(0, 0, 0, 0); + propertiesMainLayout->setSpacing(1); + + m_propertiesModel.setHeader({Tr::tr("Property"), Tr::tr("Value")}); + auto propertiesView = new Utils::TreeView; + propertiesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + propertiesView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + propertiesView->setModel(&m_propertiesModel); + propertiesView->setRootIsDecorated(true); + propertiesMainLayout->addWidget(propertiesView); + + QWidget *propertiesWidget = new QWidget; + propertiesWidget->setObjectName("SquishPropertiesView"); + propertiesWidget->setWindowTitle(Tr::tr("Squish Object Properties")); + propertiesWidget->setLayout(propertiesMainLayout); addToolBarAction(m_pausePlayAction); addToolBarAction(m_stepInAction); @@ -232,10 +275,14 @@ void SquishPerspective::initPerspective() addToolBarAction(m_stepOutAction); addToolBarAction(m_stopAction); addToolbarSeparator(); + addToolBarAction(m_inspectAction); + addToolbarSeparator(); m_status = new QLabel; addToolBarWidget(m_status); - addWindow(mainWidget, Perspective::AddToTab, nullptr, true, Qt::RightDockWidgetArea); + addWindow(objectWidget, Perspective::SplitVertical, nullptr); + addWindow(propertiesWidget, Perspective::SplitHorizontal, objectWidget); + addWindow(localsWidget, Perspective::AddToTab, nullptr, true, Qt::RightDockWidgetArea); connect(m_pausePlayAction, &QAction::triggered, this, &SquishPerspective::onPausePlayTriggered); connect(m_stepInAction, &QAction::triggered, this, [this] { @@ -250,6 +297,10 @@ void SquishPerspective::initPerspective() connect(m_stopAction, &QAction::triggered, this, &SquishPerspective::onStopTriggered); connect(m_stopRecordAction, &QAction::triggered, this, &SquishPerspective::onStopRecordTriggered); + connect(m_inspectAction, &QAction::triggered, this, [this]{ + m_inspectAction->setEnabled(false); + emit inspectTriggered(); + }); connect(SquishTools::instance(), &SquishTools::localsUpdated, this, &SquishPerspective::onLocalsUpdated); @@ -269,6 +320,7 @@ void SquishPerspective::onStopTriggered() m_stopRecordAction->setEnabled(false); m_pausePlayAction->setEnabled(false); m_stopAction->setEnabled(false); + m_inspectAction->setEnabled(false); emit stopRequested(); } @@ -277,6 +329,7 @@ void SquishPerspective::onStopRecordTriggered() m_stopRecordAction->setEnabled(false); m_pausePlayAction->setEnabled(false); m_stopAction->setEnabled(false); + m_inspectAction->setEnabled(false); emit stopRecordRequested(); } @@ -376,6 +429,7 @@ void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) m_stepOverAction->setEnabled(false); m_stepOutAction->setEnabled(false); m_stopAction->setEnabled(true); + m_inspectAction->setEnabled(false); break; case Recording: m_stopRecordAction->setEnabled(true); @@ -386,6 +440,7 @@ void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) m_stepOverAction->setEnabled(false); m_stepOutAction->setEnabled(false); m_stopAction->setEnabled(true); + m_inspectAction->setEnabled(false); break; case Interrupted: m_pausePlayAction->setEnabled(true); @@ -395,6 +450,7 @@ void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) m_stepOverAction->setEnabled(true); m_stepOutAction->setEnabled(true); m_stopAction->setEnabled(true); + m_inspectAction->setEnabled(true); break; case Configuring: case Querying: @@ -407,6 +463,7 @@ void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) m_stepOverAction->setEnabled(false); m_stepOutAction->setEnabled(false); m_stopAction->setEnabled(false); + m_inspectAction->setEnabled(false); m_localsModel.clear(); break; default: diff --git a/src/plugins/squish/squishperspective.h b/src/plugins/squish/squishperspective.h index 1e5c4aa515f..3a69247c33a 100644 --- a/src/plugins/squish/squishperspective.h +++ b/src/plugins/squish/squishperspective.h @@ -47,6 +47,7 @@ signals: void stopRecordRequested(); void interruptRequested(); void runRequested(StepMode mode); + void inspectTriggered(); private: void onStopTriggered(); @@ -60,9 +61,12 @@ private: QAction *m_stepOverAction = nullptr; QAction *m_stepOutAction = nullptr; QAction *m_stopAction = nullptr; + QAction *m_inspectAction = nullptr; QLabel *m_status = nullptr; class SquishControlBar *m_controlBar = nullptr; Utils::TreeModel m_localsModel; + Utils::TreeModel<> m_objectsModel; + Utils::TreeModel<> m_propertiesModel; PerspectiveMode m_mode = NoMode; friend class SquishControlBar; From 388e516200338aa39d581c9b503c1be2f65864d8 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 10:34:33 +0200 Subject: [PATCH 0511/1447] Terminal: Improve link copy * Show link if control key is pressed (without mouse move) * Copy link on Control+Shift+Click * Add Copy Link Action to Right click menu Change-Id: Ide4ff4e77c03e015117c67f09c9d60dedd14dfcb Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalcommands.cpp | 4 ++ src/plugins/terminal/terminalcommands.h | 1 + src/plugins/terminal/terminalwidget.cpp | 74 ++++++++++++++++------- src/plugins/terminal/terminalwidget.h | 4 +- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp index 2313ac722e4..0e7cba8194c 100644 --- a/src/plugins/terminal/terminalcommands.cpp +++ b/src/plugins/terminal/terminalcommands.cpp @@ -20,6 +20,7 @@ namespace Terminal { constexpr char COPY[] = "Terminal.Copy"; constexpr char PASTE[] = "Terminal.Paste"; +constexpr char COPY_LINK[] = "Terminal.CopyLink"; constexpr char CLEARSELECTION[] = "Terminal.ClearSelection"; constexpr char MOVECURSORWORDLEFT[] = "Terminal.MoveCursorWordLeft"; constexpr char MOVECURSORWORDRIGHT[] = "Terminal.MoveCursorWordRight"; @@ -59,6 +60,7 @@ void TerminalCommands::initWidgetActions() { m_widgetActions.copy.setText(Tr::tr("Copy")); m_widgetActions.paste.setText(Tr::tr("Paste")); + m_widgetActions.copyLink.setText(Tr::tr("Copy Link")); m_widgetActions.clearSelection.setText(Tr::tr("Clear Selection")); m_widgetActions.clearTerminal.setText(Tr::tr("Clear Terminal")); m_widgetActions.moveCursorWordLeft.setText(Tr::tr("Move Cursor Word Left")); @@ -76,6 +78,8 @@ void TerminalCommands::initWidgetActions() {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V"))}); + registerAction(m_widgetActions.copyLink, COPY_LINK); + registerAction(m_widgetActions.clearSelection, CLEARSELECTION); registerAction(m_widgetActions.moveCursorWordLeft, diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h index 80af894d662..71bc7ffe0f8 100644 --- a/src/plugins/terminal/terminalcommands.h +++ b/src/plugins/terminal/terminalcommands.h @@ -22,6 +22,7 @@ struct WidgetActions { QAction copy; QAction paste; + QAction copyLink; QAction clearSelection; QAction clearTerminal; QAction moveCursorWordLeft; diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 6ece9394c02..08fe2f691d4 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -262,6 +262,7 @@ void TerminalWidget::setupActions() // clang-format off connect(&a.copy, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyToClipboard)); connect(&a.paste, &QAction::triggered, this, ifHasFocus(&TerminalWidget::pasteFromClipboard)); + connect(&a.copyLink, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyLinkToClipboard)); connect(&a.clearSelection, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearSelection)); connect(&a.clearTerminal, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearContents)); connect(&a.moveCursorWordLeft, &QAction::triggered, this, ifHasFocus(&TerminalWidget::moveCursorWordLeft)); @@ -390,6 +391,7 @@ void TerminalWidget::updateCopyState() return; TerminalCommands::widgetActions().copy.setEnabled(m_selection.has_value()); + TerminalCommands::widgetActions().copyLink.setEnabled(m_linkSelection.has_value()); } void TerminalWidget::setFont(const QFont &font) @@ -436,6 +438,12 @@ void TerminalWidget::pasteFromClipboard() m_surface->pasteFromClipboard(clipboardText); } +void TerminalWidget::copyLinkToClipboard() +{ + if (m_linkSelection) + setClipboardAndSelection(m_linkSelection->link.targetFilePath.toUserOutput()); +} + void TerminalWidget::clearSelection() { setSelection(std::nullopt); @@ -1086,11 +1094,27 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) return; } + if (event->key() == Qt::Key_Control) { + if (!m_linkSelection.has_value() && checkLinkAt(mapFromGlobal(QCursor::pos()))) { + setCursor(Qt::PointingHandCursor); + } + } + event->accept(); m_surface->sendKey(event); } +void TerminalWidget::keyReleaseEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Control && m_linkSelection.has_value()) { + m_linkSelection.reset(); + updateCopyState(); + setCursor(Qt::IBeamCursor); + updateViewport(); + } +} + void TerminalWidget::applySizeChange() { QSize newLiveSize = { @@ -1198,8 +1222,13 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) m_activeMouseSelect.start = viewportToGlobal(event->pos()); - if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier) { + if (event->button() == Qt::LeftButton && event->modifiers() & Qt::ControlModifier) { if (m_linkSelection) { + if (event->modifiers() & Qt::ShiftModifier) { + copyLinkToClipboard(); + return; + } + if (m_linkSelection->link.targetFilePath.scheme().toString().startsWith("http")) { QDesktopServices::openUrl(m_linkSelection->link.targetFilePath.toUrl()); return; @@ -1231,10 +1260,11 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) event->accept(); updateViewport(); } else if (event->button() == Qt::RightButton) { - if (event->modifiers() == Qt::ShiftModifier) { + if (event->modifiers() & Qt::ShiftModifier) { QMenu *contextMenu = new QMenu(this); contextMenu->addAction(&TerminalCommands::widgetActions().copy); contextMenu->addAction(&TerminalCommands::widgetActions().paste); + contextMenu->addAction(&TerminalCommands::widgetActions().copyLink); contextMenu->addSeparator(); contextMenu->addAction(&TerminalCommands::widgetActions().clearTerminal); contextMenu->addSeparator(); @@ -1303,10 +1333,11 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) } setSelection(newSelection); - } else if (event->modifiers() == Qt::ControlModifier) { + } else if (event->modifiers() & Qt::ControlModifier) { checkLinkAt(event->pos()); } else if (m_linkSelection) { m_linkSelection.reset(); + updateCopyState(); updateViewport(); } @@ -1317,7 +1348,7 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) } } -void TerminalWidget::checkLinkAt(const QPoint &pos) +bool TerminalWidget::checkLinkAt(const QPoint &pos) { const TextAndOffsets hit = textAt(pos); @@ -1325,34 +1356,35 @@ void TerminalWidget::checkLinkAt(const QPoint &pos) QString t = QString::fromUcs4(hit.text.c_str(), hit.text.size()).trimmed(); t = chopIfEndsWith(t, ':'); - if (t.isEmpty()) - return; + if (!t.isEmpty()) { + if (t.startsWith("~/")) + t = QDir::homePath() + t.mid(1); - if (t.startsWith("~/")) { - t = QDir::homePath() + t.mid(1); - } + Link link = Link::fromString(t, true); - Link link = Link::fromString(t, true); + if (!link.targetFilePath.isAbsolutePath()) + link.targetFilePath = m_cwd.pathAppended(link.targetFilePath.path()); - if (!link.targetFilePath.isAbsolutePath()) - link.targetFilePath = m_cwd.pathAppended(link.targetFilePath.path()); - - if (link.hasValidTarget() - && (link.targetFilePath.scheme().toString().startsWith("http") - || link.targetFilePath.exists())) { - const LinkSelection newSelection = LinkSelection{{hit.start, hit.end}, link}; - if (!m_linkSelection || *m_linkSelection != newSelection) { - m_linkSelection = newSelection; - updateViewport(); + if (link.hasValidTarget() + && (link.targetFilePath.scheme().toString().startsWith("http") + || link.targetFilePath.exists())) { + const LinkSelection newSelection = LinkSelection{{hit.start, hit.end}, link}; + if (!m_linkSelection || *m_linkSelection != newSelection) { + m_linkSelection = newSelection; + updateViewport(); + updateCopyState(); + } + return true; } - return; } } if (m_linkSelection) { m_linkSelection.reset(); + updateCopyState(); updateViewport(); } + return false; } void TerminalWidget::mouseReleaseEvent(QMouseEvent *event) diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 8498f35f83b..5833d17979e 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -35,6 +35,7 @@ public: void copyToClipboard(); void pasteFromClipboard(); + void copyLinkToClipboard(); void clearSelection(); @@ -90,6 +91,7 @@ signals: protected: void paintEvent(QPaintEvent *event) override; void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; void resizeEvent(QResizeEvent *event) override; void wheelEvent(QWheelEvent *event) override; void focusInEvent(QFocusEvent *event) override; @@ -148,7 +150,7 @@ protected: std::optional selectionToFormatRange( TerminalWidget::Selection selection, const QTextLayout &layout, int rowOffset) const; - void checkLinkAt(const QPoint &pos); + bool checkLinkAt(const QPoint &pos); struct TextAndOffsets { From 4753b658bb79a07dd19df27e2b6ddbcf80502bb2 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 5 Apr 2023 14:16:00 +0200 Subject: [PATCH 0512/1447] CMake: Allow to run staging installation in CMakeInstallStep User configurable, on by default (only) for cases where build and run device are different. The staging dir is by default a randomly named directory on the build device, but can be changed by the user if needed. Overall, this does not change anything for a pure local setup (but would let the user opt-in into staging, too) Change-Id: Ic1c5fd1f1261e067692710c9e3aa9d821897478d Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/cmakebuildstep.cpp | 108 +++++++++++++++++- .../cmakeprojectmanager/cmakebuildstep.h | 7 ++ .../cmakeprojectmanager/cmakeinstallstep.cpp | 1 + 3 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 74220d9464a..1e70c034ecd 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -44,6 +45,8 @@ namespace CMakeProjectManager::Internal { const char BUILD_TARGETS_KEY[] = "CMakeProjectManager.MakeStep.BuildTargets"; const char CMAKE_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.CMakeArguments"; const char TOOL_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.AdditionalArguments"; +const char USE_STAGING_KEY[] = "CMakeProjectManager.MakeStep.UseStaging"; +const char STAGING_DIR_KEY[] = "CMakeProjectManager.MakeStep.StagingDir"; const char IOS_AUTOMATIC_PROVISIONG_UPDATES_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.iOSAutomaticProvisioningUpdates"; const char CLEAR_SYSTEM_ENVIRONMENT_KEY[] = "CMakeProjectManager.MakeStep.ClearSystemEnvironment"; @@ -156,7 +159,25 @@ Qt::ItemFlags CMakeTargetItem::flags(int) const // CMakeBuildStep -CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) : +static QString initialStagingDir() +{ + // Avoid actual file accesses. + auto rg = QRandomGenerator::global(); + const qulonglong rand = rg->generate64(); + char buf[sizeof(rand)]; + memcpy(&buf, &rand, sizeof(rand)); + const QByteArray ba = QByteArray(buf, sizeof(buf)).toHex(); + return QString::fromUtf8("/tmp/Qt-Creator-staging-" + ba); +} + +static bool buildAndRunOnSameDevice(Kit *kit) +{ + IDeviceConstPtr runDevice = DeviceKitAspect::device(kit); + IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit); + return runDevice->id() == buildDevice->id(); +} + +CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) : CMakeAbstractProcessStep(bsl, id) { m_cmakeArguments = addAspect(); @@ -169,6 +190,17 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) : m_toolArguments->setLabelText(Tr::tr("Tool arguments:")); m_toolArguments->setDisplayStyle(StringAspect::LineEditDisplay); + m_useStaging = addAspect(); + m_useStaging->setSettingsKey(USE_STAGING_KEY); + m_useStaging->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + m_useStaging->setDefaultValue(!buildAndRunOnSameDevice(kit())); + + m_stagingDir = addAspect(); + m_stagingDir->setSettingsKey(STAGING_DIR_KEY); + m_stagingDir->setLabelText(Tr::tr("Staging directory:")); + m_stagingDir->setDisplayStyle(StringAspect::PathChooserDisplay); + m_stagingDir->setDefaultValue(initialStagingDir()); + Kit *kit = buildConfiguration()->kit(); if (CMakeBuildConfiguration::isIos(kit)) { m_useiOSAutomaticProvisioningUpdates = addAspect(); @@ -199,6 +231,9 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) : if (!env.expandedValueForKey("NINJA_STATUS").startsWith(ninjaProgressString)) env.set("NINJA_STATUS", ninjaProgressString + "%o/sec] "); env.modify(m_userEnvironmentChanges); + + if (m_useStaging) + env.set("DESTDIR", currentStagingDir()); }); connect(target(), &Target::parsingFinished, this, [this](bool success) { @@ -210,7 +245,6 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Utils::Id id) : this, &CMakeBuildStep::updateBuildTargetsModel); } - QVariantMap CMakeBuildStep::toMap() const { QVariantMap map(CMakeAbstractProcessStep::toMap()); @@ -375,9 +409,7 @@ void CMakeBuildStep::setBuildTargets(const QStringList &buildTargets) CommandLine CMakeBuildStep::cmakeCommand() const { - CommandLine cmd; - if (CMakeTool *tool = CMakeKitAspect::cmakeTool(kit())) - cmd.setExecutable(tool->cmakeExecutable()); + CommandLine cmd{cmakeExecutable()}; FilePath buildDirectory = "."; if (buildConfiguration()) @@ -406,6 +438,9 @@ CommandLine CMakeBuildStep::cmakeCommand() const if (!m_cmakeArguments->value().isEmpty()) cmd.addArgs(m_cmakeArguments->value(), CommandLine::Raw); + if (m_useStaging->value()) + cmd.addArg("install"); + bool toolArgumentsSpecified = false; if (!m_toolArguments->value().isEmpty()) { cmd.addArg("--"); @@ -466,6 +501,12 @@ QWidget *CMakeBuildStep::createConfigWidget() QString summaryText = param.summary(displayName()); + m_stagingDir->setEnabled(m_useStaging->value()); + if (m_useStaging->value()) { + summaryText.append(" " + Tr::tr("and stage at %2 for %3") + .arg(currentStagingDir(), currentInstallPrefix())); + } + if (!m_buildPreset.isEmpty()) { const CMakeProject *cp = static_cast(project()); @@ -526,6 +567,7 @@ QWidget *CMakeBuildStep::createConfigWidget() Layouting::Form builder; builder.addRow(m_cmakeArguments); builder.addRow(m_toolArguments); + builder.addRow({Tr::tr("Stage for installation:"), Layouting::Row{m_useStaging, m_stagingDir}}); if (m_useiOSAutomaticProvisioningUpdates) builder.addRow(m_useiOSAutomaticProvisioningUpdates); @@ -541,6 +583,8 @@ QWidget *CMakeBuildStep::createConfigWidget() connect(m_cmakeArguments, &StringAspect::changed, this, updateDetails); connect(m_toolArguments, &StringAspect::changed, this, updateDetails); + connect(m_useStaging, &BoolAspect::changed, this, updateDetails); + connect(m_stagingDir, &StringAspect::changed, this, updateDetails); if (m_useiOSAutomaticProvisioningUpdates) connect(m_useiOSAutomaticProvisioningUpdates, &BoolAspect::changed, this, updateDetails); @@ -683,8 +727,62 @@ QString CMakeBuildStep::baseEnvironmentText() const return Tr::tr("System Environment"); } +QString CMakeBuildStep::currentInstallPrefix() const +{ + auto bs = qobject_cast(buildSystem()); + QTC_ASSERT(bs, return {}); + const CMakeConfig config = bs->configurationFromCMake(); + return QString::fromUtf8(config.valueOf("CMAKE_INSTALL_PREFIX")); +} + +QString CMakeBuildStep::currentStagingDir() const +{ + return m_stagingDir->filePath().path(); +} + +FilePath CMakeBuildStep::cmakeExecutable() const +{ + CMakeTool *tool = CMakeKitAspect::cmakeTool(kit()); + return tool ? tool->cmakeExecutable() : FilePath(); +} + +void CMakeBuildStep::updateDeploymentData() +{ + if (!m_useStaging->value()) + return; + + QString install = currentInstallPrefix(); + QString stagingDir = currentStagingDir(); + FilePath rootDir = cmakeExecutable().withNewPath(stagingDir); + Q_UNUSED(install); + + DeploymentData deploymentData; + deploymentData.setLocalInstallRoot(rootDir); + + const int startPos = rootDir.path().length(); + + const auto appFileNames = transform>(buildSystem()->applicationTargets(), + [](const BuildTargetInfo &appTarget) { return appTarget.targetFilePath.fileName(); }); + + auto handleFile = [this, &appFileNames, startPos, &deploymentData](const FilePath &filePath) { + const DeployableFile::Type type = appFileNames.contains(filePath.fileName()) + ? DeployableFile::TypeExecutable + : DeployableFile::TypeNormal; + const QString targetDir = filePath.parentDir().path().mid(startPos); + deploymentData.addFile(filePath, targetDir, type); + return IterationPolicy::Continue; + }; + + rootDir.iterateDirectory(handleFile, + {{}, QDir::Files | QDir::Hidden, QDirIterator::Subdirectories}); + + buildSystem()->setDeploymentData(deploymentData); +} + void CMakeBuildStep::finish(ProcessResult result) { + updateDeploymentData(); + emit progress(100, {}); AbstractProcessStep::finish(result); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.h b/src/plugins/cmakeprojectmanager/cmakebuildstep.h index 96d53919e18..973b00e8f37 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.h @@ -85,6 +85,10 @@ private: void doRun() override; QWidget *createConfigWidget() override; + Utils::FilePath cmakeExecutable() const; + QString currentInstallPrefix() const; + QString currentStagingDir() const; + QString defaultBuildTarget() const; bool isCleanStep() const; @@ -94,6 +98,7 @@ private: void handleBuildTargetsChanges(bool success); void recreateBuildTargetsModel(); void updateBuildTargetsModel(); + void updateDeploymentData(); QMetaObject::Connection m_runTrigger; @@ -102,6 +107,8 @@ private: Utils::StringAspect *m_cmakeArguments = nullptr; Utils::StringAspect *m_toolArguments = nullptr; Utils::BoolAspect *m_useiOSAutomaticProvisioningUpdates = nullptr; + Utils::BoolAspect *m_useStaging = nullptr; + Utils::StringAspect *m_stagingDir = nullptr; QString m_allTarget = "all"; QString m_installTarget = "install"; diff --git a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp index 3f6da6e73b1..445bfd9c145 100644 --- a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp @@ -93,6 +93,7 @@ void CMakeInstallStep::finish(ProcessResult result) emit progress(100, {}); AbstractProcessStep::finish(result); } + QWidget *CMakeInstallStep::createConfigWidget() { auto updateDetails = [this] { From 7e635747649e23b6b04787feaee102e0ef298612 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 6 Apr 2023 11:45:10 +0200 Subject: [PATCH 0513/1447] CMake: Disable the default "install into temporary host" deploy step This is not needed with the new option in the actual cmake build step. Change-Id: I3bf8bd4ed96c44223ad401406a168d3c8d07fa23 Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/cmakeproject.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index be78fe28d34..13764fc3677 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -35,7 +35,11 @@ CMakeProject::CMakeProject(const FilePath &fileName) setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setDisplayName(projectDirectory().fileName()); setCanBuildProducts(); - setHasMakeInstallEquivalent(true); + + // This only influences whether 'Install into temporary host directory' + // will show up by default enabled in some remote deploy configurations. + // We rely on staging via the actual cmake build step. + setHasMakeInstallEquivalent(false); readPresets(); } From 6583f27caa01bbebb22b3192a1514749bd157ef2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 11:14:30 +0200 Subject: [PATCH 0514/1447] RemoteLinux: Fix double-remote terminal process Change-Id: Ibfc6b6f2ce218be39ca0aa9fc582516b0efe4536 Reviewed-by: hjk --- src/plugins/remotelinux/linuxdevice.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index d01ea1be8f4..0822c9e9e33 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -606,14 +606,30 @@ void SshProcessInterfacePrivate::start() } cmd.addArg(m_sshParameters.host()); + const bool useTerminal = q->m_setup.m_terminalMode != TerminalMode::Off + || q->m_setup.m_ptyData; + if (useTerminal) + cmd.addArg("-tt"); + const CommandLine full = q->m_setup.m_commandLine; if (!full.isEmpty()) { - // Empty is ok in case of opening a terminal. - cmd.addArgs(QString("echo ") + s_pidMarker + "\\$\\$" + s_pidMarker + " \\&\\& ", - CommandLine::Raw); + if (!useTerminal) { + // Empty is ok in case of opening a terminal. + cmd.addArgs(QString("echo ") + s_pidMarker + "\\$\\$" + s_pidMarker + " \\&\\& ", + CommandLine::Raw); + } cmd.addCommandLineAsArgs(full, CommandLine::Raw); } + m_process.setProcessImpl(q->m_setup.m_processImpl); + m_process.setProcessMode(q->m_setup.m_processMode); + m_process.setTerminalMode(q->m_setup.m_terminalMode); + m_process.setPtyData(q->m_setup.m_ptyData); + m_process.setReaperTimeout(q->m_setup.m_reaperTimeout); + m_process.setWriteData(q->m_setup.m_writeData); + m_process.setCreateConsoleOnWindows(q->m_setup.m_createConsoleOnWindows); + m_process.setExtraData(q->m_setup.m_extraData); + m_process.setCommand(cmd); m_process.start(); return; From ccbab62461533624730817546b16c80349fa18c2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 10:42:28 +0200 Subject: [PATCH 0515/1447] Docker: Make end of auto detection obvious Fixes: QTCREATORBUG-28819 Change-Id: I2d93c472ed7b29329642cb8052b6f7b980d017d9 Reviewed-by: Janne Juntunen Reviewed-by: Leena Miettinen Reviewed-by: hjk Reviewed-by: --- src/plugins/docker/dockerdevicewidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/docker/dockerdevicewidget.cpp b/src/plugins/docker/dockerdevicewidget.cpp index bc9c76f5b25..8477256a356 100644 --- a/src/plugins/docker/dockerdevicewidget.cpp +++ b/src/plugins/docker/dockerdevicewidget.cpp @@ -198,6 +198,8 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device) logView->append(Tr::tr("Docker daemon appears to be not running.")); else logView->append(Tr::tr("Docker daemon appears to be running.")); + + logView->append(Tr::tr("Detection complete.")); updateDaemonStateTexts(); }); From 392c13be110539039b522f3cb38f485e3efe1a9c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 07:03:01 +0200 Subject: [PATCH 0516/1447] Terminal: Enable by default Change-Id: Ic21d4f0431c5999a3671dd1afe04fa27c3d816fe Reviewed-by: Cristian Adam Reviewed-by: hjk Reviewed-by: --- src/plugins/terminal/Terminal.json.in | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/terminal/Terminal.json.in b/src/plugins/terminal/Terminal.json.in index 3715f77fa31..5640012c081 100644 --- a/src/plugins/terminal/Terminal.json.in +++ b/src/plugins/terminal/Terminal.json.in @@ -2,7 +2,6 @@ \"Name\" : \"Terminal\", \"Version\" : \"$$QTCREATOR_VERSION\", \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", - \"DisabledByDefault\" : true, \"Vendor\" : \"The Qt Company Ltd\", \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", \"License\" : [ \"Commercial Usage\", From 166c0d65587d66c11d8ba5600c8909849dc2d6e1 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 11:26:05 +0200 Subject: [PATCH 0517/1447] Terminal: Safety checks Change-Id: I095ca03dcc7bf943638d7ce785c658c0fed3b2f1 Reviewed-by: Cristian Adam --- src/plugins/terminal/celliterator.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/celliterator.cpp b/src/plugins/terminal/celliterator.cpp index 26f347f4fda..6ad487ae276 100644 --- a/src/plugins/terminal/celliterator.cpp +++ b/src/plugins/terminal/celliterator.cpp @@ -14,6 +14,11 @@ CellIterator::CellIterator(const TerminalSurface *surface, QPoint pos) , m_surface(surface) { m_pos = (pos.x()) + (pos.y() * surface->liveSize().width()); + if (m_pos < 0) + m_pos = 0; + if (m_pos == 0) + m_state = State::BEGIN; + m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; updateChar(); } @@ -23,7 +28,7 @@ CellIterator::CellIterator(const TerminalSurface *surface, int pos) , m_surface(surface) { m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; - m_pos = qMin(m_maxpos + 1, pos); + m_pos = qMax(0, qMin(m_maxpos + 1, pos)); if (m_pos == 0) { m_state = State::BEGIN; } else if (m_pos == m_maxpos + 1) { From 2c3373172b7fdf00679670e3983d22339915ad7b Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 6 Apr 2023 12:11:41 +0200 Subject: [PATCH 0518/1447] RemoteLinux: Simplify RsyncDeployStep implementation Change-Id: Ife6eb2d1f7ab2202e7ddc6c13c68f3ed09403553 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/rsyncdeploystep.cpp | 26 ++++----------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 9359df0f355..0d81a181b02 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -31,19 +31,15 @@ namespace RemoteLinux { class RsyncDeployStep : public AbstractRemoteLinuxDeployStep { public: - RsyncDeployStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); - ~RsyncDeployStep() override; - - static Utils::Id stepId(); - static QString displayName(); + RsyncDeployStep(BuildStepList *bsl, Id id); private: bool isDeploymentNecessary() const final; - Utils::Tasking::Group deployRecipe() final; - Utils::Tasking::TaskItem mkdirTask(); - Utils::Tasking::TaskItem transferTask(); + Tasking::Group deployRecipe() final; + Tasking::TaskItem mkdirTask(); + Tasking::TaskItem transferTask(); - mutable ProjectExplorer::FilesToTransfer m_files; + mutable FilesToTransfer m_files; bool m_ignoreMissingFiles = false; QString m_flags; }; @@ -83,8 +79,6 @@ RsyncDeployStep::RsyncDeployStep(BuildStepList *bsl, Id id) }); } -RsyncDeployStep::~RsyncDeployStep() = default; - bool RsyncDeployStep::isDeploymentNecessary() const { if (m_ignoreMissingFiles) @@ -148,16 +142,6 @@ Group RsyncDeployStep::deployRecipe() return Group { mkdirTask(), transferTask() }; } -Utils::Id RsyncDeployStep::stepId() -{ - return Constants::RsyncDeployStepId; -} - -QString RsyncDeployStep::displayName() -{ - return Tr::tr("Deploy files via rsync"); -} - // Factory RsyncDeployStepFactory::RsyncDeployStepFactory() From e0be80a19dfdd3f379a7db70c9ddf5632b1e4b76 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Tue, 4 Apr 2023 14:01:10 +0200 Subject: [PATCH 0519/1447] ClangFormat: Change Override check box name and ToolTip Change-Id: I3d80ca3c2fd9dd6210220eca0db1ecec5dad9f0e Reviewed-by: Christian Kandeler --- .../clangformat/clangformatglobalconfigwidget.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index f332a97070f..34b4f08f013 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -36,7 +36,7 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(ProjectExplorer::Pr m_indentingOrFormatting = new QComboBox(this); m_formatWhileTyping = new QCheckBox(Tr::tr("Format while typing")); m_formatOnSave = new QCheckBox(Tr::tr("Format edited code on file save")); - m_overrideDefault = new QCheckBox(Tr::tr("Override Clang Format configuration file")); + m_overrideDefault = new QCheckBox(Tr::tr("Override .clang-format file")); m_useGlobalSettings = new QCheckBox(Tr::tr("Use global settings")); m_useGlobalSettings->hide(); @@ -160,8 +160,15 @@ void ClangFormatGlobalConfigWidget::initOverrideCheckBox() connect(m_indentingOrFormatting, &QComboBox::currentIndexChanged, this, setEnableOverrideCheckBox); - m_overrideDefault->setToolTip( - Tr::tr("Override Clang Format configuration file with the chosen configuration.")); + m_overrideDefault->setToolTip(Tr::tr( + "When this option is enabled, ClangFormat will use a\n" + "user-specified configuration from the widget below,\n" + "instead of the project .clang-format file. You can\n" + "customize the formatting options for your code by\n" + "adjusting the settings in the widget. Note that any\n" + "changes made there will only affect the current\n" + "configuration, and will not modify the project\n" + ".clang-format file.")); m_overrideDefault->setChecked(getProjectOverriddenSettings(m_project)); From a8a9bf1713b0d0c346543f4dd1cda29dd55ab208 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 6 Apr 2023 11:37:01 +0200 Subject: [PATCH 0520/1447] ProjectExplorer: Be more generous on what the manual copy step accepts That's a manual fallback for odd cases, do not artificially restrict usability. Change-Id: I6e5433559534ae1d7be29a218442b46c306b2bed Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/copystep.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/copystep.cpp b/src/plugins/projectexplorer/copystep.cpp index 9f0201d73e9..d152671c70e 100644 --- a/src/plugins/projectexplorer/copystep.cpp +++ b/src/plugins/projectexplorer/copystep.cpp @@ -72,8 +72,11 @@ public: CopyFileStep(BuildStepList *bsl, Id id) : CopyStepBase(bsl, id) { - m_sourceAspect->setExpectedKind(PathChooser::File); - m_targetAspect->setExpectedKind(PathChooser::SaveFile); + // Expected kind could be stricter in theory, but since this here is + // a last stand fallback, better not impose extra "nice to have" + // work on the system. + m_sourceAspect->setExpectedKind(PathChooser::Any); // "File" + m_targetAspect->setExpectedKind(PathChooser::Any); // "SaveFile" setSummaryUpdater([] { return QString("" + Tr::tr("Copy file") + ""); From 45c2e3fe58fd9b5a85450ff18e0a40e701ebf8d6 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 08:24:22 +0200 Subject: [PATCH 0521/1447] Copilot: Add insert next word action Fixes: QTCREATORBUG-28959 Change-Id: Ied53ad5676133e2eb71988ecfcce90c5ad77e3c3 Reviewed-by: David Schulz --- src/libs/utils/stringutils.cpp | 22 +++++++++++++++ src/libs/utils/stringutils.h | 2 ++ src/plugins/copilot/copilothoverhandler.cpp | 20 +++++++++++--- src/plugins/copilot/copilotsuggestion.cpp | 30 +++++++++++++++++++++ src/plugins/copilot/copilotsuggestion.h | 2 ++ src/plugins/texteditor/textdocumentlayout.h | 3 +++ src/plugins/texteditor/texteditor.cpp | 21 ++++++++++----- 7 files changed, 91 insertions(+), 9 deletions(-) diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index 7315a69da2a..37f9336d376 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -546,4 +546,26 @@ QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QStrin return splitAtFirst(view, ch); } +QTCREATOR_UTILS_EXPORT int endOfNextWord(const QString &string, int position) +{ + QTC_ASSERT(string.size() > position, return -1); + + static const QString wordSeparators = QStringLiteral(" \t\n\r()[]{}<>"); + + const auto predicate = [](const QChar &c) { return wordSeparators.contains(c); }; + + auto it = string.begin() + position; + if (predicate(*it)) + it = std::find_if_not(it, string.end(), predicate); + + if (it == string.end()) + return -1; + + it = std::find_if(it, string.end(), predicate); + if (it == string.end()) + return -1; + + return std::distance(string.begin(), it); +} + } // namespace Utils diff --git a/src/libs/utils/stringutils.h b/src/libs/utils/stringutils.h index 865a1dea122..d1a94330b7b 100644 --- a/src/libs/utils/stringutils.h +++ b/src/libs/utils/stringutils.h @@ -119,4 +119,6 @@ QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QStrin QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QStringView &stringView, QChar ch); +QTCREATOR_UTILS_EXPORT int endOfNextWord(const QString &string, int position = 0); + } // namespace Utils diff --git a/src/plugins/copilot/copilothoverhandler.cpp b/src/plugins/copilot/copilothoverhandler.cpp index 07aca2cbc7c..b252cedc77d 100644 --- a/src/plugins/copilot/copilothoverhandler.cpp +++ b/src/plugins/copilot/copilothoverhandler.cpp @@ -43,11 +43,14 @@ public: Tr::tr("Select Next Copilot Suggestion")); next->setEnabled(m_completions.size() > 1); - auto apply = addAction(Tr::tr("Apply (Tab)")); + auto apply = addAction(Tr::tr("Apply (%1)").arg(QKeySequence(Qt::Key_Tab).toString())); + auto applyWord = addAction( + Tr::tr("Apply Word (%1)").arg(QKeySequence(QKeySequence::MoveToNextWord).toString())); connect(prev, &QAction::triggered, this, &CopilotCompletionToolTip::selectPrevious); connect(next, &QAction::triggered, this, &CopilotCompletionToolTip::selectNext); connect(apply, &QAction::triggered, this, &CopilotCompletionToolTip::apply); + connect(applyWord, &QAction::triggered, this, &CopilotCompletionToolTip::applyWord); updateLabels(); } @@ -88,8 +91,19 @@ private: void apply() { - if (TextSuggestion *suggestion = m_editor->currentSuggestion()) - suggestion->apply(); + if (TextSuggestion *suggestion = m_editor->currentSuggestion()) { + if (!suggestion->apply()) + return; + } + ToolTip::hide(); + } + + void applyWord() + { + if (TextSuggestion *suggestion = m_editor->currentSuggestion()) { + if (!suggestion->applyWord(m_editor)) + return; + } ToolTip::hide(); } diff --git a/src/plugins/copilot/copilotsuggestion.cpp b/src/plugins/copilot/copilotsuggestion.cpp index 96ccbbcd18a..de5660c02d1 100644 --- a/src/plugins/copilot/copilotsuggestion.cpp +++ b/src/plugins/copilot/copilotsuggestion.cpp @@ -3,6 +3,13 @@ #include "copilotsuggestion.h" +#include + +#include + +using namespace Utils; +using namespace TextEditor; + namespace Copilot::Internal { CopilotSuggestion::CopilotSuggestion(const QList &completions, @@ -27,6 +34,29 @@ bool CopilotSuggestion::apply() return true; } +bool CopilotSuggestion::applyWord(TextEditorWidget *widget) +{ + const Completion completion = m_completions.value(m_currentCompletion); + const QTextCursor cursor = completion.range().toSelection(m_start.document()); + QTextCursor currentCursor = widget->textCursor(); + const QString text = completion.text(); + const int startPos = currentCursor.positionInBlock() - cursor.positionInBlock() + + (cursor.selectionEnd() - cursor.selectionStart()); + const int next = endOfNextWord(text, startPos); + + if (next == -1) + return apply(); + + // TODO: Allow adding more than one line + QString subText = text.mid(startPos, next - startPos); + subText = subText.left(subText.indexOf('\n')); + if (subText.isEmpty()) + return false; + + currentCursor.insertText(subText); + return false; +} + void CopilotSuggestion::reset() { m_start.removeSelectedText(); diff --git a/src/plugins/copilot/copilotsuggestion.h b/src/plugins/copilot/copilotsuggestion.h index a5b55b2d973..719016236a2 100644 --- a/src/plugins/copilot/copilotsuggestion.h +++ b/src/plugins/copilot/copilotsuggestion.h @@ -5,6 +5,7 @@ #include "requests/getcompletions.h" #include +#include namespace Copilot::Internal { @@ -16,6 +17,7 @@ public: int currentCompletion = 0); bool apply() final; + bool applyWord(TextEditor::TextEditorWidget *widget) final; void reset() final; int position() final; diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 8ad013518c0..19278ad93c9 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -47,7 +47,10 @@ class TEXTEDITOR_EXPORT TextSuggestion public: TextSuggestion(); virtual ~TextSuggestion(); + // Returns true if the suggestion was applied completely, false if it was only partially applied. virtual bool apply() = 0; + // Returns true if the suggestion was applied completely, false if it was only partially applied. + virtual bool applyWord(TextEditorWidget *widget) = 0; virtual void reset() = 0; virtual int position() = 0; diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index d21644850c0..1ae22223a1a 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -2577,6 +2577,21 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) const bool inOverwriteMode = overwriteMode(); const bool hasMultipleCursors = cursor.hasMultipleCursors(); + if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(d->m_suggestionBlock)) { + if (e->matches(QKeySequence::MoveToNextWord)) { + e->accept(); + if (suggestion->applyWord(this)) + d->clearCurrentSuggestion(); + return; + } else if (e->modifiers() == Qt::NoModifier + && (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab)) { + e->accept(); + if (suggestion->apply()) + d->clearCurrentSuggestion(); + return; + } + } + if (!ro && (e == QKeySequence::InsertParagraphSeparator || (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))) { @@ -2695,12 +2710,6 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e) return; } QTextCursor cursor = textCursor(); - if (TextSuggestion *suggestion = TextDocumentLayout::suggestion(d->m_suggestionBlock)) { - suggestion->apply(); - d->clearCurrentSuggestion(); - e->accept(); - return; - } if (d->m_skipAutoCompletedText && e->key() == Qt::Key_Tab) { bool skippedAutoCompletedText = false; while (!d->m_autoCompleteHighlightPos.isEmpty() From 46b9cd952a93b98335dfb5761025d7ca27f40d44 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 3 Jan 2023 15:12:43 +0100 Subject: [PATCH 0522/1447] Debugger: Add skeleton for a debugger adapter protocol using engine - Support the launch of an application - Support continue/pause an application - Support add breakpoint only after an app is launched (I.e. preset breakpoints won't work) - Support stop the debug session - "Remove one break breakpoint" works but removes all breakpoints ToDo: - Polish the transition between stages - Fix breakpoints handling - Add support "Step in", "Step out" and "Step Over" Task-number: QTCREATORBUG-27279 Change-Id: I5c32ce713f5a0f19cc3b9d995cbbadd8adf6a413 Reviewed-by: Artem Sokolovskii Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/plugins/debugger/CMakeLists.txt | 1 + src/plugins/debugger/dap/dapengine.cpp | 730 +++++++++++++++++++ src/plugins/debugger/dap/dapengine.h | 97 +++ src/plugins/debugger/debugger.qbs | 6 + src/plugins/debugger/debuggerconstants.h | 1 + src/plugins/debugger/debuggerengine.cpp | 1 + src/plugins/debugger/debuggeritem.cpp | 7 + src/plugins/debugger/debuggeritemmanager.cpp | 8 + src/plugins/debugger/debuggerruncontrol.cpp | 4 + 9 files changed, 855 insertions(+) create mode 100644 src/plugins/debugger/dap/dapengine.cpp create mode 100644 src/plugins/debugger/dap/dapengine.h diff --git a/src/plugins/debugger/CMakeLists.txt b/src/plugins/debugger/CMakeLists.txt index f5f45deb4af..d06e82a27e1 100644 --- a/src/plugins/debugger/CMakeLists.txt +++ b/src/plugins/debugger/CMakeLists.txt @@ -27,6 +27,7 @@ add_qtc_plugin(Debugger console/consoleitemmodel.cpp console/consoleitemmodel.h console/consoleproxymodel.cpp console/consoleproxymodel.h console/consoleview.cpp console/consoleview.h + dap/dapengine.cpp dap/dapengine.h debugger.qrc debugger_global.h debuggeractions.cpp debuggeractions.h diff --git a/src/plugins/debugger/dap/dapengine.cpp b/src/plugins/debugger/dap/dapengine.cpp new file mode 100644 index 00000000000..6efe29d37d4 --- /dev/null +++ b/src/plugins/debugger/dap/dapengine.cpp @@ -0,0 +1,730 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "dapengine.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Core; +using namespace Utils; + +namespace Debugger::Internal { + +DapEngine::DapEngine() +{ + setObjectName("DapEngine"); + setDebuggerName("DAP"); +} + +void DapEngine::executeDebuggerCommand(const QString &command) +{ + QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); +// if (state() == DebuggerNotReady) { +// showMessage("DAP PROCESS NOT RUNNING, PLAIN CMD IGNORED: " + command); +// return; +// } +// QTC_ASSERT(m_proc.isRunning(), notifyEngineIll()); +// postDirectCommand(command); +} + +void DapEngine::postDirectCommand(const QJsonObject &ob) +{ + static int seq = 1; + QJsonObject obseq = ob; + obseq.insert("seq", seq++); + + const QByteArray data = QJsonDocument(obseq).toJson(QJsonDocument::Compact); + const QByteArray msg = "Content-Length: " + QByteArray::number(data.size()) + "\r\n\r\n" + data; + qDebug() << msg; + + m_proc.writeRaw(msg); + + showMessage(QString::fromUtf8(msg), LogInput); +} + +void DapEngine::runCommand(const DebuggerCommand &cmd) +{ + if (state() == EngineSetupRequested) { // cmd has been triggered too early + showMessage("IGNORED COMMAND: " + cmd.function); + return; + } + QTC_ASSERT(m_proc.isRunning(), notifyEngineIll()); +// postDirectCommand(cmd.args.toObject()); +// const QByteArray data = QJsonDocument(cmd.args.toObject()).toJson(QJsonDocument::Compact); +// m_proc.writeRaw("Content-Length: " + QByteArray::number(data.size()) + "\r\n" + data + "\r\n"); + +// showMessage(QString::fromUtf8(data), LogInput); +} + +void DapEngine::shutdownInferior() +{ + QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state()); + postDirectCommand({{"command", "terminate"}, + {"type", "request"}}); + + qDebug() << "DapEngine::shutdownInferior()"; + notifyInferiorShutdownFinished(); +} + +void DapEngine::shutdownEngine() +{ + QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); + + qDebug() << "DapEngine::shutdownEngine()"; + m_proc.kill(); +} + +void DapEngine::setupEngine() +{ + QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); + + connect(&m_proc, &QtcProcess::started, this, &DapEngine::handleDabStarted); + connect(&m_proc, &QtcProcess::done, this, &DapEngine::handleDapDone); + connect(&m_proc, &QtcProcess::readyReadStandardOutput, this, &DapEngine::readDapStandardOutput); + connect(&m_proc, &QtcProcess::readyReadStandardError, this, &DapEngine::readDapStandardError); + + const DebuggerRunParameters &rp = runParameters(); + const CommandLine cmd{rp.debugger.command.executable(), {"-i", "dap"}}; + showMessage("STARTING " + cmd.toUserOutput()); + m_proc.setProcessMode(ProcessMode::Writer); + m_proc.setEnvironment(rp.debugger.environment); + m_proc.setCommand(cmd); + m_proc.start(); + notifyEngineRunAndInferiorRunOk(); +} + +// From the docs: +// The sequence of events/requests is as follows: +// * adapters sends initialized event (after the initialize request has returned) +// * client sends zero or more setBreakpoints requests +// * client sends one setFunctionBreakpoints request +// (if corresponding capability supportsFunctionBreakpoints is true) +// * client sends a setExceptionBreakpoints request if one or more exceptionBreakpointFilters +// have been defined (or if supportsConfigurationDoneRequest is not true) +// * client sends other future configuration requests +// * client sends one configurationDone request to indicate the end of the configuration. + +void DapEngine::handleDabStarted() +{ + notifyEngineSetupOk(); + QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); + +// CHECK_STATE(EngineRunRequested); + + postDirectCommand({ + {"command", "initialize"}, + {"type", "request"}, + {"arguments", QJsonObject { + {"clientID", "QtCreator"}, // The ID of the client using this adapter. + {"clientName", "QtCreator"} // The human-readable name of the client using this adapter. + }} + }); + + qDebug() << "handleDabStarted"; +} + +void DapEngine::handleDabConfigurationDone() +{ + QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); + + // CHECK_STATE(EngineRunRequested); + + postDirectCommand({{"command", "configurationDone"}, {"type", "request"}}); + + qDebug() << "handleDabConfigurationDone"; +} + + +void DapEngine::handleDabLaunch() +{ + QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); + + // CHECK_STATE(EngineRunRequested); + + postDirectCommand( + {{"command", "launch"}, + {"type", "request"}, +// {"program", runParameters().inferior.command.executable().path()}, + {"arguments", + QJsonObject{ + {"noDebug", false}, + {"program", runParameters().inferior.command.executable().path()}, +// {"args", runParameters().inferior.command.arguments()}, +// {"cwd", runParameters().inferior.workingDirectory}, +// {"env", QJsonObject::fromVariantMap(runParameters().inferior.environment.toStringMap())} + {"__restart", ""} + }}}); + qDebug() << "handleDabLaunch"; +} + +void DapEngine::interruptInferior() +{ + QString error; + + postDirectCommand({{"command", "pause"}, + {"type", "request"}}); + + qDebug() << "DapEngine::interruptInferior()"; + + +// interruptProcess(m_proc.processId(), GdbEngineType, &error); +// notifyInferiorExited(); + notifyInferiorStopOk(); +} + +void DapEngine::executeStepIn(bool) +{ + notifyInferiorRunRequested(); + notifyInferiorRunOk(); +// postDirectCommand("step"); +} + +void DapEngine::executeStepOut() +{ + notifyInferiorRunRequested(); + notifyInferiorRunOk(); +// postDirectCommand("return"); +} + +void DapEngine::executeStepOver(bool) +{ + notifyInferiorRunRequested(); + notifyInferiorRunOk(); +// postDirectCommand("next"); +} + +void DapEngine::continueInferior() +{ + postDirectCommand({{"command", "continue"}, + {"type", "request"}, + {"arguments", + QJsonObject{ + {"threadId", 1}, // The ID of the client using this adapter. + }}}); + + qDebug() << "continueInferior"; + // notifyInferiorRunRequested(); + // notifyInferiorRunOk(); + + // Callback will be triggered e.g. when breakpoint is hit. +// postDirectCommand("continue"); +} + +void DapEngine::executeRunToLine(const ContextData &data) +{ + Q_UNUSED(data) + QTC_CHECK("FIXME: DapEngine::runToLineExec()" && false); +} + +void DapEngine::executeRunToFunction(const QString &functionName) +{ + Q_UNUSED(functionName) + QTC_CHECK("FIXME: DapEngine::runToFunctionExec()" && false); +} + +void DapEngine::executeJumpToLine(const ContextData &data) +{ + Q_UNUSED(data) + QTC_CHECK("FIXME: DapEngine::jumpToLineExec()" && false); +} + +void DapEngine::activateFrame(int frameIndex) +{ + if (state() != InferiorStopOk && state() != InferiorUnrunnable) + return; + + StackHandler *handler = stackHandler(); + QTC_ASSERT(frameIndex < handler->stackSize(), return); + handler->setCurrentIndex(frameIndex); + gotoLocation(handler->currentFrame()); + updateLocals(); +} + +void DapEngine::selectThread(const Thread &thread) +{ + Q_UNUSED(thread) +} + +bool DapEngine::acceptsBreakpoint(const BreakpointParameters &) const +{ + return true; // FIXME: Too bold. +} + +void DapEngine::insertBreakpoint(const Breakpoint &bp) +{ + QTC_ASSERT(bp, return); + QTC_CHECK(bp->state() == BreakpointInsertionRequested); + notifyBreakpointInsertProceeding(bp); + + QString loc; + const BreakpointParameters ¶ms = bp->requestedParameters(); + if (params.type == BreakpointByFunction) + loc = params.functionName; + else + loc = params.fileName.toString() + ':' + QString::number(params.lineNumber); + + postDirectCommand( + {{"command", "setBreakpoints"}, + {"type", "request"}, + {"arguments", + QJsonObject{{"source", QJsonObject{{"path", params.fileName.toString()}}}, + {"breakpoints", + QJsonArray{QJsonObject{{"id", 1}, {"line", params.lineNumber}}}} + + }}}); +} + +void DapEngine::updateBreakpoint(const Breakpoint &bp) +{ +// QTC_ASSERT(bp, return); +// const BreakpointState state = bp->state(); +// if (QTC_GUARD(state == BreakpointUpdateRequested)) +// notifyBreakpointChangeProceeding(bp); +// if (bp->responseId().isEmpty()) // FIXME postpone update somehow (QTimer::singleShot?) +// return; + +// // FIXME figure out what needs to be changed (there might be more than enabled state) +// const BreakpointParameters &requested = bp->requestedParameters(); +// if (requested.enabled != bp->isEnabled()) { +// if (bp->isEnabled()) +// postDirectCommand("disable " + bp->responseId()); +// else +// postDirectCommand("enable " + bp->responseId()); +// bp->setEnabled(!bp->isEnabled()); +// } +// // Pretend it succeeds without waiting for response. + notifyBreakpointChangeOk(bp); +} + +void DapEngine::removeBreakpoint(const Breakpoint &bp) +{ + QTC_ASSERT(bp, return); + QTC_CHECK(bp->state() == BreakpointRemoveRequested); + // notifyBreakpointRemoveProceeding(bp); + const BreakpointParameters ¶ms = bp->requestedParameters(); + postDirectCommand({{"command", "setBreakpoints"}, + {"type", "request"}, + {"arguments", + QJsonObject{{"source", QJsonObject{{"path", params.fileName.toString()}}}, + {"breakpoints", QJsonArray{}}}}}); + qDebug() << "removeBreakpoint"; + +// notifyBreakpointRemoveOk(bp); +} + +void DapEngine::loadSymbols(const Utils::FilePath &/*moduleName*/) +{ +} + +void DapEngine::loadAllSymbols() +{ +} + +void DapEngine::reloadModules() +{ + runCommand({"listModules"}); +} + +void DapEngine::refreshModules(const GdbMi &modules) +{ + ModulesHandler *handler = modulesHandler(); + handler->beginUpdateAll(); + for (const GdbMi &item : modules) { + Module module; + module.moduleName = item["name"].data(); + QString path = item["value"].data(); + int pos = path.indexOf("' from '"); + if (pos != -1) { + path = path.mid(pos + 8); + if (path.size() >= 2) + path.chop(2); + } else if (path.startsWith("")) { + path = "(builtin)"; + } + module.modulePath = FilePath::fromString(path); + handler->updateModule(module); + } + handler->endUpdateAll(); +} + +void DapEngine::requestModuleSymbols(const Utils::FilePath &/*moduleName*/) +{ +// DebuggerCommand cmd("listSymbols"); +// cmd.arg("module", moduleName); +// runCommand(cmd); +} + +void DapEngine::refreshState(const GdbMi &reportedState) +{ + QString newState = reportedState.data(); + if (newState == "stopped") { + notifyInferiorSpontaneousStop(); + updateAll(); + } else if (newState == "inferiorexited") { + notifyInferiorExited(); + } +} + +void DapEngine::refreshLocation(const GdbMi &reportedLocation) +{ + StackFrame frame; + frame.file = FilePath::fromString(reportedLocation["file"].data()); + frame.line = reportedLocation["line"].toInt(); + frame.usable = frame.file.isReadableFile(); + if (state() == InferiorRunOk) { + showMessage(QString("STOPPED AT: %1:%2").arg(frame.file.toUserOutput()).arg(frame.line)); + gotoLocation(frame); + notifyInferiorSpontaneousStop(); + updateAll(); + } +} + +void DapEngine::refreshSymbols(const GdbMi &symbols) +{ + QString moduleName = symbols["module"].data(); + Symbols syms; + for (const GdbMi &item : symbols["symbols"]) { + Symbol symbol; + symbol.name = item["name"].data(); + syms.append(symbol); + } + showModuleSymbols(FilePath::fromString(moduleName), syms); +} + +bool DapEngine::canHandleToolTip(const DebuggerToolTipContext &) const +{ + return state() == InferiorStopOk; +} + +void DapEngine::assignValueInDebugger(WatchItem *, const QString &expression, const QVariant &value) +{ + //DebuggerCommand cmd("assignValue"); + //cmd.arg("expression", expression); + //cmd.arg("value", value.toString()); + //runCommand(cmd); +// postDirectCommand("global " + expression + ';' + expression + "=" + value.toString()); + updateLocals(); +} + +void DapEngine::updateItem(const QString &iname) +{ + Q_UNUSED(iname) + updateAll(); +} + +QString DapEngine::errorMessage(QProcess::ProcessError error) const +{ + switch (error) { + case QProcess::FailedToStart: + return Tr::tr("The DAP process failed to start. Either the " + "invoked program \"%1\" is missing, or you may have insufficient " + "permissions to invoke the program.") + .arg(m_proc.commandLine().executable().toUserOutput()); + case QProcess::Crashed: + return Tr::tr("The DAP process crashed some time after starting " + "successfully."); + case QProcess::Timedout: + return Tr::tr("The last waitFor...() function timed out. " + "The state of QProcess is unchanged, and you can try calling " + "waitFor...() again."); + case QProcess::WriteError: + return Tr::tr("An error occurred when attempting to write " + "to the DAP process. For example, the process may not be running, " + "or it may have closed its input channel."); + case QProcess::ReadError: + return Tr::tr("An error occurred when attempting to read from " + "the DAP process. For example, the process may not be running."); + default: + return Tr::tr("An unknown error in the DAP process occurred.") + ' '; + } +} + +void DapEngine::handleDapDone() +{ + if (m_proc.result() == ProcessResult::StartFailed) { + notifyEngineSetupFailed(); + showMessage("ADAPTER START FAILED"); + ICore::showWarningWithOptions(Tr::tr("Adapter start failed"), m_proc.exitMessage()); + return; + } + + const QProcess::ProcessError error = m_proc.error(); + if (error != QProcess::UnknownError) { + showMessage("HANDLE DAP ERROR"); + if (error != QProcess::Crashed) + AsynchronousMessageBox::critical(Tr::tr("DAP I/O Error"), errorMessage(error)); + if (error == QProcess::FailedToStart) + return; + } + showMessage(QString("DAP PROCESS FINISHED, status %1, code %2") + .arg(m_proc.exitStatus()).arg(m_proc.exitCode())); + notifyEngineSpontaneousShutdown(); +} + +void DapEngine::readDapStandardError() +{ + QString err = m_proc.readAllStandardError(); + //qWarning() << "Unexpected DAP stderr:" << err; + showMessage("Unexpected DAP stderr: " + err); + //handleOutput(err); +} + +void DapEngine::readDapStandardOutput() +{ + m_inbuffer.append(m_proc.readAllStandardOutput().toUtf8()); +// qDebug() << m_inbuffer; + + while (true) { + // Something like + // Content-Length: 128\r\n + // {"type": "event", "event": "output", "body": {"category": "stdout", "output": "...\n"}, "seq": 1}\r\n + // FIXME: There coud be more than one header line. + int pos1 = m_inbuffer.indexOf("Content-Length:"); + if (pos1 == -1) + break; + pos1 += 15; + + int pos2 = m_inbuffer.indexOf('\n', pos1); + if (pos2 == -1) + break; + + const int len = m_inbuffer.mid(pos1, pos2 - pos1).trimmed().toInt(); + if (len < 4) + break; + + pos2 += 3; // Skip \r\n\r + + if (pos2 + len > m_inbuffer.size()) + break; + + QJsonParseError error; + const auto doc = QJsonDocument::fromJson(m_inbuffer.mid(pos2, len), &error); + + m_inbuffer = m_inbuffer.mid(pos2 + len); + + handleOutput(doc); + } +} + +void DapEngine::handleOutput(const QJsonDocument &data) +{ + QJsonObject ob = data.object(); + + const QJsonValue t = ob.value("type"); + const QString type = t.toString(); + qDebug() << "response" << ob; + + if (type == "response") { + const QString command = ob.value("command").toString(); + if (command == "configurationDone") { + showMessage("configurationDone", LogDebug); + qDebug() << "configurationDone success"; + notifyInferiorRunOk(); + + claimInitialBreakpoints(); + return; + } + + if (command == "continue") { + showMessage("continue", LogDebug); + qDebug() << "continue success"; + notifyInferiorRunOk(); + return; + } + + } + + if (type == "event") { + const QString event = ob.value("event").toString(); + if (event == "output") { + const QJsonObject body = ob.value("body").toObject(); + const QString category = body.value("category").toString(); + const QString output = body.value("output").toString(); + if (category == "stdout") + showMessage(output, AppOutput); + else if (category == "stderr") + showMessage(output, AppError); + else + showMessage(output, LogDebug); + return; + } + qDebug() << data; + + if (event == "initialized") { + showMessage(event, LogDebug); + qDebug() << "initialize success"; + handleDabLaunch(); + handleDabConfigurationDone(); + return; + } + + if (event == "initialized") { + showMessage(event, LogDebug); + return; + } + + if (event == "stopped") { + notifyInferiorSpontaneousStop(); + return; + } + + showMessage("UNKNOWN EVENT:" + event); + return; + } + + showMessage("UNKNOWN TYPE:" + type); +} + +void DapEngine::refreshLocals(const GdbMi &vars) +{ + WatchHandler *handler = watchHandler(); + handler->resetValueCache(); + handler->insertItems(vars); + handler->notifyUpdateFinished(); + + updateToolTips(); +} + +void DapEngine::refreshStack(const GdbMi &stack) +{ + StackHandler *handler = stackHandler(); + StackFrames frames; + for (const GdbMi &item : stack["frames"]) { + StackFrame frame; + frame.level = item["level"].data(); + frame.file = FilePath::fromString(item["file"].data()); + frame.function = item["function"].data(); + frame.module = item["function"].data(); + frame.line = item["line"].toInt(); + frame.address = item["address"].toAddress(); + GdbMi usable = item["usable"]; + if (usable.isValid()) + frame.usable = usable.data().toInt(); + else + frame.usable = frame.file.isReadableFile(); + frames.append(frame); + } + bool canExpand = stack["hasmore"].toInt(); + //action(ExpandStack)->setEnabled(canExpand); + handler->setFrames(frames, canExpand); + + int index = stackHandler()->firstUsableIndex(); + handler->setCurrentIndex(index); + if (index >= 0 && index < handler->stackSize()) + gotoLocation(handler->frameAt(index)); +} + +void DapEngine::updateAll() +{ + runCommand({"stackListFrames"}); + updateLocals(); +} + +void DapEngine::updateLocals() +{ +// DebuggerCommand cmd("updateData"); +// cmd.arg("nativeMixed", isNativeMixedActive()); +// watchHandler()->appendFormatRequests(&cmd); +// watchHandler()->appendWatchersAndTooltipRequests(&cmd); + +// const bool alwaysVerbose = qtcEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE"); +// cmd.arg("passexceptions", alwaysVerbose); +// cmd.arg("fancy", debuggerSettings()->useDebuggingHelpers.value()); + +// //cmd.arg("resultvarname", m_resultVarName); +// //m_lastDebuggableCommand = cmd; +// //m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1"); +// cmd.arg("frame", stackHandler()->currentIndex()); + +// watchHandler()->notifyUpdateStarted(); +// runCommand(cmd); +} + +bool DapEngine::hasCapability(unsigned cap) const +{ + return cap & (ReloadModuleCapability + | BreakConditionCapability + | ShowModuleSymbolsCapability); +} + +void DapEngine::claimInitialBreakpoints() +{ + BreakpointManager::claimBreakpointsForEngine(this); + qDebug() << "claimInitialBreakpoints"; + const Breakpoints bps = breakHandler()->breakpoints(); + for (const Breakpoint &bp : bps) + qDebug() << "breakpoit: " << bp->fileName() << bp->lineNumber(); + qDebug() << "claimInitialBreakpoints end"; + +// const DebuggerRunParameters &rp = runParameters(); +// if (rp.startMode != AttachToCore) { +// showStatusMessage(Tr::tr("Setting breakpoints...")); +// showMessage(Tr::tr("Setting breakpoints...")); +// BreakpointManager::claimBreakpointsForEngine(this); + +// const DebuggerSettings &s = *debuggerSettings(); +// const bool onAbort = s.breakOnAbort.value(); +// const bool onWarning = s.breakOnWarning.value(); +// const bool onFatal = s.breakOnFatal.value(); +// if (onAbort || onWarning || onFatal) { +// DebuggerCommand cmd("createSpecialBreakpoints"); +// cmd.arg("breakonabort", onAbort); +// cmd.arg("breakonwarning", onWarning); +// cmd.arg("breakonfatal", onFatal); +// runCommand(cmd); +// } +// } + +// // It is ok to cut corners here and not wait for createSpecialBreakpoints()'s +// // response, as the command is synchronous from Creator's point of view, +// // and even if it fails (e.g. due to stripped binaries), continuing with +// // the start up is the best we can do. + +// if (!rp.commandsAfterConnect.isEmpty()) { +// const QString commands = expand(rp.commandsAfterConnect); +// for (const QString &command : commands.split('\n')) +// runCommand({command, NativeCommand}); +// } +} + +DebuggerEngine *createDapEngine() +{ + return new DapEngine; +} + +} // Debugger::Internal diff --git a/src/plugins/debugger/dap/dapengine.h b/src/plugins/debugger/dap/dapengine.h new file mode 100644 index 00000000000..045cb3044a2 --- /dev/null +++ b/src/plugins/debugger/dap/dapengine.h @@ -0,0 +1,97 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +#include + +namespace Debugger::Internal { + +class DebuggerCommand; +class GdbMi; + +/* + * A debugger engine for the debugger adapter protocol. + */ + +class DapEngine : public DebuggerEngine +{ +public: + DapEngine(); + +private: + void executeStepIn(bool) override; + void executeStepOut() override; + void executeStepOver(bool) override; + + void setupEngine() override; + void shutdownInferior() override; + void shutdownEngine() override; + + bool canHandleToolTip(const DebuggerToolTipContext &) const override; + + void continueInferior() override; + void interruptInferior() override; + + void executeRunToLine(const ContextData &data) override; + void executeRunToFunction(const QString &functionName) override; + void executeJumpToLine(const ContextData &data) override; + + void activateFrame(int index) override; + void selectThread(const Thread &thread) override; + + bool acceptsBreakpoint(const BreakpointParameters &bp) const override; + void insertBreakpoint(const Breakpoint &bp) override; + void updateBreakpoint(const Breakpoint &bp) override; + void removeBreakpoint(const Breakpoint &bp) override; + + void assignValueInDebugger(WatchItem *item, + const QString &expr, const QVariant &value) override; + void executeDebuggerCommand(const QString &command) override; + + void loadSymbols(const Utils::FilePath &moduleName) override; + void loadAllSymbols() override; + void requestModuleSymbols(const Utils::FilePath &moduleName) override; + void reloadModules() override; + void reloadRegisters() override {} + void reloadSourceFiles() override {} + void reloadFullStack() override {} + + bool supportsThreads() const { return true; } + void updateItem(const QString &iname) override; + + void runCommand(const DebuggerCommand &cmd) override; + void postDirectCommand(const QJsonObject &ob); + + void refreshLocation(const GdbMi &reportedLocation); + void refreshStack(const GdbMi &stack); + void refreshLocals(const GdbMi &vars); + void refreshModules(const GdbMi &modules); + void refreshState(const GdbMi &reportedState); + void refreshSymbols(const GdbMi &symbols); + + QString errorMessage(QProcess::ProcessError error) const; + bool hasCapability(unsigned cap) const override; + + void claimInitialBreakpoints(); + + void handleDabStarted(); + void handleDabLaunch(); + void handleDabConfigurationDone(); + + void handleDapDone(); + void readDapStandardOutput(); + void readDapStandardError(); + void handleOutput(const QJsonDocument &data); + void handleResponse(const QString &ba); + void updateAll() override; + void updateLocals() override; + + QByteArray m_inbuffer; + Utils::QtcProcess m_proc; +}; + +} // Debugger::Internal diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 03b57c5885a..be2adfc04d9 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -122,6 +122,12 @@ Project { files: ["pdbengine.cpp", "pdbengine.h"] } + Group { + name: "dap" + prefix: "dap/" + files: ["dapengine.cpp", "dapengine.h"] + } + Group { name: "uvsc" prefix: "uvsc/" diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index b071713a844..06ccb94f1b9 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -99,6 +99,7 @@ enum DebuggerEngineType CdbEngineType = 0x004, PdbEngineType = 0x008, LldbEngineType = 0x100, + DapEngineType = 0x200, UvscEngineType = 0x1000 }; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 1013fbe73c8..d387ce142c1 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2587,6 +2587,7 @@ bool DebuggerRunParameters::isCppDebugging() const return cppEngineType == GdbEngineType || cppEngineType == LldbEngineType || cppEngineType == CdbEngineType + || cppEngineType == DapEngineType || cppEngineType == UvscEngineType; } diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index 0769d293dee..a6daacd16d3 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -174,8 +174,12 @@ void DebuggerItem::reinitializeFromFile(QString *error, Utils::Environment *cust return; } m_abis.clear(); + if (output.contains("gdb")) { m_engineType = GdbEngineType; + // FIXME: HACK while introducing DAP support + if (m_command.fileName().endsWith("-dap")) + m_engineType = DapEngineType; // Version bool isMacGdb, isQnxGdb; @@ -211,6 +215,7 @@ void DebuggerItem::reinitializeFromFile(QString *error, Utils::Environment *cust //! \note If unable to determine the GDB ABI, no ABI is appended to m_abis here. return; } + if (output.contains("lldb") || output.startsWith("LLDB")) { m_engineType = LldbEngineType; m_abis = Abi::abisOfBinary(m_command); @@ -278,6 +283,8 @@ QString DebuggerItem::engineTypeName() const return QLatin1String("CDB"); case LldbEngineType: return QLatin1String("LLDB"); + case DapEngineType: + return QLatin1String("DAP"); case UvscEngineType: return QLatin1String("UVSC"); default: diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 1c9a6e68dc7..ab1f53076d7 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -813,6 +813,14 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePaths &s item.setUnexpandedDisplayName(name.arg(item.engineTypeName()).arg(command.toUserOutput())); m_model->addDebugger(item); logMessages.append(Tr::tr("Found: \"%1\"").arg(command.toUserOutput())); + + if (item.engineType() == GdbEngineType) { + if (item.version().startsWith("GNU gdb (GDB) 14.0.50.2023")) { + // FIXME: Use something more robust + item.setEngineType(DapEngineType); + m_model->addDebugger(item); + } + } } if (logMessage) *logMessage = logMessages.join('\n'); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index e8ddb33b2c2..85b48880fe0 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -70,6 +70,7 @@ DebuggerEngine *createPdbEngine(); DebuggerEngine *createQmlEngine(); DebuggerEngine *createLldbEngine(); DebuggerEngine *createUvscEngine(); +DebuggerEngine *createDapEngine(); static QString noEngineMessage() { @@ -509,6 +510,9 @@ void DebuggerRunTool::start() case UvscEngineType: m_engine = createUvscEngine(); break; + case DapEngineType: + m_engine = createDapEngine(); + break; default: if (!m_runParameters.isQmlDebugging) { reportFailure(noEngineMessage() + '\n' + From d05faf64f46b4585152a9eb075500ceaf24c5ad7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 6 Apr 2023 14:32:06 +0200 Subject: [PATCH 0523/1447] Terminal: Correctly parse url links with empty path Previously urls such as http://google.com were appended to the current dir, as FilePath::isAbsolute would return false since there is no path. Change-Id: I17546aed322a74f6b8cbcc166d37608fd809fd1e Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 08fe2f691d4..67d7cae59d6 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -1362,7 +1362,7 @@ bool TerminalWidget::checkLinkAt(const QPoint &pos) Link link = Link::fromString(t, true); - if (!link.targetFilePath.isAbsolutePath()) + if (!link.targetFilePath.isEmpty() && !link.targetFilePath.isAbsolutePath()) link.targetFilePath = m_cwd.pathAppended(link.targetFilePath.path()); if (link.hasValidTarget() From 3eb60d80e5bffb5d852a751584bd7a337d609386 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 1 Mar 2023 20:35:53 +0100 Subject: [PATCH 0524/1447] Android: Skip "Make Install" and "Build APK" if not ProductType::App If the target's product type is not "App", the "Make Install" and "Build Android APK" build steps need to be skipped. Fixes: QTCREATORBUG-26980 Change-Id: Ia8bb61d407d040b851a74bad3d23876a7d31af73 Reviewed-by: Reviewed-by: Artem Sokolovskii Reviewed-by: Assam Boudjelthia --- src/plugins/android/androidbuildapkstep.cpp | 7 +++++++ src/plugins/android/androidmanager.cpp | 15 +++++++++++++++ src/plugins/android/androidmanager.h | 1 + .../android/androidpackageinstallationstep.cpp | 8 ++++++++ 4 files changed, 31 insertions(+) diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 789e6c92fd7..6e7dba97252 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -711,6 +711,13 @@ void AndroidBuildApkStep::doRun() return; } + if (AndroidManager::skipInstallationAndPackageSteps(target())) { + reportWarningOrError(Tr::tr("Product type is not an application, not building an APK."), + Task::Warning); + emit finished(true); + return; + } + auto setup = [this] { const auto androidAbis = AndroidManager::applicationAbis(target()); const QString buildKey = target()->activeBuildKey(); diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index fa299ba4e21..72a9e5c4799 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -359,6 +359,21 @@ Abi AndroidManager::androidAbi2Abi(const QString &androidAbi) } } +bool AndroidManager::skipInstallationAndPackageSteps(const Target *target) +{ + const Project *p = target->project(); + + const Core::Context cmakeCtx = Core::Context(CMakeProjectManager::Constants::CMAKE_PROJECT_ID); + const bool isCmakeProject = p->projectContext() == cmakeCtx; + if (isCmakeProject) + return false; // CMake reports ProductType::Other for Android Apps + + const ProjectNode *n = p->rootProjectNode()->findProjectNode([] (const ProjectNode *n) { + return n->productType() == ProductType::App; + }); + return n == nullptr; // If no Application target found, then skip steps +} + FilePath AndroidManager::manifestSourcePath(const Target *target) { if (const ProjectNode *node = currentProjectNode(target)) { diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index d468ec3279e..ec6aff85bc6 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -82,6 +82,7 @@ public: static bool matchedAbis(const QStringList &deviceAbis, const QStringList &appAbis); static QString devicePreferredAbi(const QStringList &deviceAbis, const QStringList &appAbis); static ProjectExplorer::Abi androidAbi2Abi(const QString &androidAbi); + static bool skipInstallationAndPackageSteps(const ProjectExplorer::Target *target); static QString androidNameForApiLevel(int x); diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp index 3b8a83fa578..e2f929f0813 100644 --- a/src/plugins/android/androidpackageinstallationstep.cpp +++ b/src/plugins/android/androidpackageinstallationstep.cpp @@ -122,6 +122,14 @@ void AndroidPackageInstallationStep::setupOutputFormatter(OutputFormatter *forma void AndroidPackageInstallationStep::doRun() { + if (AndroidManager::skipInstallationAndPackageSteps(target())) { + reportWarningOrError(Tr::tr("Product type is not an application, not running the " + "Make install step."), + Task::Warning); + emit finished(true); + return; + } + QString error; for (const QString &dir : std::as_const(m_androidDirsToClean)) { FilePath androidDir = FilePath::fromString(dir); From 25f7dfac25e8dd3f73ed5d189e2975843e808439 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 6 Apr 2023 14:28:12 +0200 Subject: [PATCH 0525/1447] ProjectExplorer: Remove FileTransferDirection Only 'Upload' is in active use, and the direction determination gets fiddly when more than one remote device is involved. If there'd ever be a real need for a 'Download', I add / reimplement that as a separate case in FileTransferMethod. Change-Id: I51580a180aae6f0ed5904ff1b828c9ffd6da658c Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../devicesupport/filetransfer.cpp | 39 ++-------- .../devicesupport/filetransferinterface.h | 8 -- src/plugins/remotelinux/linuxdevice.cpp | 75 ++++++------------- 3 files changed, 28 insertions(+), 94 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/filetransfer.cpp b/src/plugins/projectexplorer/devicesupport/filetransfer.cpp index bd386db0d11..523db6b32c2 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransfer.cpp +++ b/src/plugins/projectexplorer/devicesupport/filetransfer.cpp @@ -16,43 +16,18 @@ using namespace Utils; namespace ProjectExplorer { -FileTransferDirection FileToTransfer::direction() const -{ - if (m_source.needsDevice() == m_target.needsDevice()) - return FileTransferDirection::Invalid; - return m_source.needsDevice() ? FileTransferDirection::Download : FileTransferDirection::Upload; -} - QString FileTransferSetupData::defaultRsyncFlags() { return "-av"; } -static FileTransferDirection transferDirection(const FilesToTransfer &files) -{ - if (files.isEmpty()) - return FileTransferDirection::Invalid; - - const FileTransferDirection direction = files.first().direction(); - for (const FileToTransfer &file : files) { - if (file.direction() != direction) - return FileTransferDirection::Invalid; - } - return direction; -} - -static const FilePath &remoteFile(FileTransferDirection direction, const FileToTransfer &file) -{ - return direction == FileTransferDirection::Upload ? file.m_target : file.m_source; -} - -static IDeviceConstPtr matchedDevice(FileTransferDirection direction, const FilesToTransfer &files) +static IDeviceConstPtr matchedDevice(const FilesToTransfer &files) { if (files.isEmpty()) return {}; - const FilePath &filePath = remoteFile(direction, files.first()); + const FilePath filePath = files.first().m_target; for (const FileToTransfer &file : files) { - if (!filePath.isSameDevice(remoteFile(direction, file))) + if (!filePath.isSameDevice(file.m_target)) return {}; } return DeviceManager::deviceForPath(filePath); @@ -102,15 +77,11 @@ void FileTransferPrivate::start() if (m_setup.m_files.isEmpty()) return startFailed(Tr::tr("No files to transfer.")); - const FileTransferDirection direction = transferDirection(m_setup.m_files); - - IDeviceConstPtr device; - if (direction != FileTransferDirection::Invalid) - device = matchedDevice(direction, m_setup.m_files); + IDeviceConstPtr device = matchedDevice(m_setup.m_files); if (!device) { // Fall back to generic copy. - const FilePath &filePath = m_setup.m_files.first().m_target; + const FilePath filePath = m_setup.m_files.first().m_target; device = DeviceManager::deviceForPath(filePath); m_setup.m_method = FileTransferMethod::GenericCopy; } diff --git a/src/plugins/projectexplorer/devicesupport/filetransferinterface.h b/src/plugins/projectexplorer/devicesupport/filetransferinterface.h index 2907f9c2573..ce4e662db43 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransferinterface.h +++ b/src/plugins/projectexplorer/devicesupport/filetransferinterface.h @@ -11,12 +11,6 @@ namespace Utils { class ProcessResultData; } namespace ProjectExplorer { -enum class FileTransferDirection { - Invalid, - Upload, - Download -}; - enum class FileTransferMethod { Sftp, Rsync, @@ -29,8 +23,6 @@ class PROJECTEXPLORER_EXPORT FileToTransfer public: Utils::FilePath m_source; Utils::FilePath m_target; - - FileTransferDirection direction() const; }; using FilesToTransfer = QList; diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 0822c9e9e33..b17ed8fcf78 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1152,13 +1152,9 @@ static FilePaths dirsToCreate(const FilesToTransfer &files) return sorted(std::move(dirs)); } -static QByteArray transferCommand(const FileTransferDirection direction, bool link) +static QByteArray transferCommand(bool link) { - if (direction == FileTransferDirection::Upload) - return link ? "ln -s" : "put"; - if (direction == FileTransferDirection::Download) - return "get"; - return {}; + return link ? "ln -s" : "put"; } class SshTransferInterface : public FileTransferInterface @@ -1171,8 +1167,6 @@ protected: , m_device(device) , m_process(this) { - m_direction = m_setup.m_files.isEmpty() ? FileTransferDirection::Invalid - : m_setup.m_files.first().direction(); SshParameters::setupSshEnvironment(&m_process); connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { emit progress(QString::fromLocal8Bit(m_process.readAllRawStandardOutput())); @@ -1216,7 +1210,6 @@ protected: QString userAtHost() const { return m_sshParameters.userAtHost(); } QtcProcess &process() { return m_process; } - FileTransferDirection direction() const { return m_direction; } private: virtual void startImpl() = 0; @@ -1269,7 +1262,6 @@ private: IDevice::ConstPtr m_device; SshParameters m_sshParameters; - FileTransferDirection m_direction = FileTransferDirection::Invalid; // helper // ssh shared connection related std::unique_ptr m_connectionHandle; @@ -1299,35 +1291,26 @@ private: QByteArray batchData; const FilePaths dirs = dirsToCreate(m_setup.m_files); - for (const FilePath &dir : dirs) { - if (direction() == FileTransferDirection::Upload) { - batchData += "-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit() + '\n'; - } else if (direction() == FileTransferDirection::Download) { - if (!QDir::root().mkpath(dir.path())) { - startFailed(Tr::tr("Failed to create local directory \"%1\".") - .arg(QDir::toNativeSeparators(dir.path()))); - return; - } - } - } + for (const FilePath &dir : dirs) + batchData += "-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit() + '\n'; for (const FileToTransfer &file : m_setup.m_files) { FilePath sourceFileOrLinkTarget = file.m_source; bool link = false; - if (direction() == FileTransferDirection::Upload) { - const QFileInfo fi(file.m_source.toFileInfo()); - if (fi.isSymLink()) { - link = true; - batchData += "-rm " + ProcessArgs::quoteArgUnix( - file.m_target.path()).toLocal8Bit() + '\n'; - // see QTBUG-5817. - sourceFileOrLinkTarget = - sourceFileOrLinkTarget.withNewPath(fi.dir().relativeFilePath(fi.symLinkTarget())); - } - } - batchData += transferCommand(direction(), link) + ' ' - + ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()).toLocal8Bit() + ' ' - + ProcessArgs::quoteArgUnix(file.m_target.path()).toLocal8Bit() + '\n'; + + const QFileInfo fi(file.m_source.toFileInfo()); + if (fi.isSymLink()) { + link = true; + batchData += "-rm " + ProcessArgs::quoteArgUnix( + file.m_target.path()).toLocal8Bit() + '\n'; + // see QTBUG-5817. + sourceFileOrLinkTarget = + sourceFileOrLinkTarget.withNewPath(fi.dir().relativeFilePath(fi.symLinkTarget())); + } + + batchData += transferCommand(link) + ' ' + + ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()).toLocal8Bit() + ' ' + + ProcessArgs::quoteArgUnix(file.m_target.path()).toLocal8Bit() + '\n'; } process().setCommand({sftpBinary, fullConnectionOptions() << "-b" << "-" << host()}); process().setWriteData(batchData); @@ -1392,8 +1375,7 @@ private: if (!HostOsInfo::isWindowsHost()) return file; - QString localFilePath = direction() == FileTransferDirection::Upload - ? file.m_source.path() : file.m_target.path(); + QString localFilePath = file.m_source.path(); localFilePath = '/' + localFilePath.at(0) + localFilePath.mid(2); if (anyOf(options, [](const QString &opt) { return opt.contains("cygwin", Qt::CaseInsensitive); })) { @@ -1401,30 +1383,19 @@ private: } FileToTransfer fixedFile = file; - if (direction() == FileTransferDirection::Upload) - fixedFile.m_source = fixedFile.m_source.withNewPath(localFilePath); - else - fixedFile.m_target = fixedFile.m_target.withNewPath(localFilePath); + fixedFile.m_source = fixedFile.m_source.withNewPath(localFilePath); return fixedFile; } QPair fixPaths(const FileToTransfer &file, const QString &remoteHost) const { - FilePath localPath; - FilePath remotePath; - if (direction() == FileTransferDirection::Upload) { - localPath = file.m_source; - remotePath = file.m_target; - } else { - remotePath = file.m_source; - localPath = file.m_target; - } + FilePath localPath = file.m_source; + FilePath remotePath = file.m_target; const QString local = (localPath.isDir() && localPath.path().back() != '/') ? localPath.path() + '/' : localPath.path(); const QString remote = remoteHost + ':' + remotePath.path(); - return direction() == FileTransferDirection::Upload ? qMakePair(local, remote) - : qMakePair(remote, local); + return qMakePair(local, remote); } int m_currentIndex = 0; From 205fb14a43e9545b9e46b5019427454d9c947264 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 16:03:18 +0200 Subject: [PATCH 0526/1447] ClientRequestTask: A few fixes 1. Rename ClientRequestTaskAdapter into WorkspaceSymbolRequestTaskAdapter as it's adapting the WorkspaceSymbolRequestTask, not the general ClientRequestTask. 2. Rename the registered name inside Tasking namespace into SymbolRequest, as WorkspaceSymbolRequest may collide with the class defined inside workspace.h header. We also aim for rather short names inside Tasking namespace in order to not to be too verbose. 3. Register the adapter with QTC_DECLARE_CUSTOM_TASK, not the task itself. 4. Fix isRunning() assert inside start(). 5. Drop check for Client::locatorsEnabled() inside preStartCheck(), as that's being done beforehand when needed. Amends 8e9b8933256c1483f1f72ade010ea879550d40d7 Change-Id: I7cef290e18d5d86b48aa17d548a058bf35fd31ec Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/languageclient/clientrequesttask.cpp | 6 +++--- src/plugins/languageclient/clientrequesttask.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/languageclient/clientrequesttask.cpp b/src/plugins/languageclient/clientrequesttask.cpp index c5503bd6947..ed3ddaff2c5 100644 --- a/src/plugins/languageclient/clientrequesttask.cpp +++ b/src/plugins/languageclient/clientrequesttask.cpp @@ -9,21 +9,21 @@ using namespace LanguageServerProtocol; namespace LanguageClient { -ClientRequestTaskAdapter::ClientRequestTaskAdapter() +WorkspaceSymbolRequestTaskAdapter::WorkspaceSymbolRequestTaskAdapter() { task()->setResponseCallback([this](const WorkspaceSymbolRequest::Response &response){ emit done(response.result().has_value()); }); } -void ClientRequestTaskAdapter::start() +void WorkspaceSymbolRequestTaskAdapter::start() { task()->start(); } bool WorkspaceSymbolRequestTask::preStartCheck() { - if (!ClientRequestTask::preStartCheck() || !client()->locatorsEnabled()) + if (!ClientRequestTask::preStartCheck()) return false; const std::optional> capability diff --git a/src/plugins/languageclient/clientrequesttask.h b/src/plugins/languageclient/clientrequesttask.h index c2de15e7007..dc14d5bf2ff 100644 --- a/src/plugins/languageclient/clientrequesttask.h +++ b/src/plugins/languageclient/clientrequesttask.h @@ -31,7 +31,7 @@ public: void start() { - QTC_ASSERT(isRunning(), return); + QTC_ASSERT(!isRunning(), return); QTC_ASSERT(preStartCheck(), m_callback({}); return); Request request(m_params); @@ -65,14 +65,14 @@ public: bool preStartCheck() override; }; -class LANGUAGECLIENT_EXPORT ClientRequestTaskAdapter +class LANGUAGECLIENT_EXPORT WorkspaceSymbolRequestTaskAdapter : public Utils::Tasking::TaskAdapter { public: - ClientRequestTaskAdapter(); + WorkspaceSymbolRequestTaskAdapter(); void start() final; }; } // namespace LanguageClient -QTC_DECLARE_CUSTOM_TASK(WorkspaceSymbolRequest, LanguageClient::WorkspaceSymbolRequestTask); +QTC_DECLARE_CUSTOM_TASK(SymbolRequest, LanguageClient::WorkspaceSymbolRequestTaskAdapter); From abe773881152e7283922912728dc422a8c9c2c4d Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Mon, 10 Apr 2023 12:02:13 +0300 Subject: [PATCH 0527/1447] CompilationDatabaseProjectManager: Add missing GCC include flags GCC also accepts -iquote and -idirafter flags to set include path. Change-Id: Id8088faa4cfcfb9d6005ad13527c0bc26dc4feb3 Reviewed-by: Christian Kandeler --- .../compilationdatabaseutils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index f773d5fc5d5..be0ab87e547 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -136,8 +136,8 @@ void filteredFlags(const FilePath &filePath, continue; } - const QStringList userIncludeFlags{"-I", "/I"}; - const QStringList systemIncludeFlags{"-isystem", "-imsvc", "/imsvc"}; + const QStringList userIncludeFlags{"-I", "-iquote", "/I"}; + const QStringList systemIncludeFlags{"-isystem", "-idirafter", "-imsvc", "/imsvc"}; const QStringList allIncludeFlags = QStringList(userIncludeFlags) << systemIncludeFlags; const QString includeOpt = Utils::findOrDefault(allIncludeFlags, [flag](const QString &opt) { return flag.startsWith(opt) && flag != opt; From 59c1fae60b2c74559e65934f208b5d3edbb3ecd1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 3 Apr 2023 11:47:19 +0200 Subject: [PATCH 0528/1447] DirectoryFilter: Hide public methods Make most of the public methods of DirectoryFilter protected. Move connection to project manager signals into AllProjectFilesFilter c'tor. Remove unused DirectoryFilter::directories(). Change-Id: I66d16c2c90188de6a03fb072fed6c87ea3d9ce4c Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- .../coreplugin/locator/directoryfilter.cpp | 5 ----- .../coreplugin/locator/directoryfilter.h | 5 ++--- .../projectexplorer/projectexplorer.cpp | 19 +++++++++---------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 785c411f19a..88e17bad358 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -411,11 +411,6 @@ void DirectoryFilter::removeDirectory(const FilePath &directory) setDirectories(directories); } -FilePaths DirectoryFilter::directories() const -{ - return m_directories; -} - void DirectoryFilter::setFilters(const QStringList &filters) { m_filters = filters; diff --git a/src/plugins/coreplugin/locator/directoryfilter.h b/src/plugins/coreplugin/locator/directoryfilter.h index 06916165003..164c4ab164b 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.h +++ b/src/plugins/coreplugin/locator/directoryfilter.h @@ -20,19 +20,18 @@ public: void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; +protected: void setIsCustomFilter(bool value); - void setDirectories(const Utils::FilePaths &directories); void addDirectory(const Utils::FilePath &directory); void removeDirectory(const Utils::FilePath &directory); - Utils::FilePaths directories() const; void setFilters(const QStringList &filters); void setExclusionFilters(const QStringList &exclusionFilters); -protected: void saveState(QJsonObject &object) const override; void restoreState(const QJsonObject &object) override; private: + void setDirectories(const Utils::FilePaths &directories); void handleAddDirectory(); void handleEditDirectory(); void handleRemoveDirectory(); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index cbf467349a1..7e4938a2042 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -863,16 +863,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(SessionManager::instance(), &SessionManager::sessionLoaded, dd, &ProjectExplorerPluginPrivate::loadSesssionTasks); - connect(sessionManager, &ProjectManager::projectAdded, dd, [](ProjectExplorer::Project *project) { - dd->m_allProjectDirectoriesFilter.addDirectory(project->projectDirectory()); - }); - connect(sessionManager, - &ProjectManager::projectRemoved, - dd, - [](ProjectExplorer::Project *project) { - dd->m_allProjectDirectoriesFilter.removeDirectory(project->projectDirectory()); - }); - ProjectTree *tree = &dd->m_projectTree; connect(tree, &ProjectTree::currentProjectChanged, dd, [] { dd->updateContextMenuActions(ProjectTree::currentNode()); @@ -4371,6 +4361,15 @@ AllProjectFilesFilter::AllProjectFilesFilter() "Matches all files from all project directories. Append \"+\" or " "\":\" to jump to the given line number. Append another " "\"+\" or \":\" to jump to the column number as well.")); + + ProjectManager *projectManager = ProjectManager::instance(); + QTC_ASSERT(projectManager, return); + connect(projectManager, &ProjectManager::projectAdded, this, [this](Project *project) { + addDirectory(project->projectDirectory()); + }); + connect(projectManager, &ProjectManager::projectRemoved, this, [this](Project *project) { + removeDirectory(project->projectDirectory()); + }); } const char kDirectoriesKey[] = "directories"; From 3ba769fb466d1a96149e05727adc975d252a8264 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 28 Mar 2023 16:45:16 +0200 Subject: [PATCH 0529/1447] Fix saving of hardlinked files Our atomic write involves writing a temp file and renaming that (which is the only way to achieve something atomic). This creates a new inode, and disconnects any hardlinks. Note that the existing implementation for file paths with needsDevice already keeps hardlinks intact, because even though it first writes into a local temporary file it then writes the content directly into the target with dd. Check the number of hard links via system API and fallback to unsafe writing if there are any, for desktop paths. Fixes: QTCREATORBUG-19651 Change-Id: I3ce1ee81f339f241f0a2c9aa6f2259cb118ebef6 Reviewed-by: Christian Kandeler Reviewed-by: --- src/libs/utils/devicefileaccess.cpp | 29 +++++++++++++++++++++++++++++ src/libs/utils/devicefileaccess.h | 3 +++ src/libs/utils/filepath.cpp | 5 +++++ src/libs/utils/filepath.h | 1 + src/libs/utils/fileutils.cpp | 12 +++++++----- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 9345b62e886..76f90efb69c 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -106,6 +106,13 @@ bool DeviceFileAccess::isSymLink(const FilePath &filePath) const return false; } +bool DeviceFileAccess::hasHardLinks(const FilePath &filePath) const +{ + Q_UNUSED(filePath) + QTC_CHECK(false); + return false; +} + bool DeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const { if (isWritableDirectory(filePath)) @@ -475,6 +482,21 @@ bool DesktopDeviceFileAccess::isSymLink(const FilePath &filePath) const return fi.isSymLink(); } +bool DesktopDeviceFileAccess::hasHardLinks(const FilePath &filePath) const +{ +#ifdef Q_OS_UNIX + struct stat s + {}; + const int r = stat(filePath.absoluteFilePath().toString().toLocal8Bit().constData(), &s); + if (r == 0) { + // check for hardlinks because these would break without the atomic write implementation + if (s.st_nlink > 1) + return true; + } +#endif + return false; +} + bool DesktopDeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const { const QFileInfo fi(filePath.path()); @@ -849,6 +871,13 @@ bool UnixDeviceFileAccess::isSymLink(const FilePath &filePath) const return runInShellSuccess({"test", {"-h", path}, OsType::OsTypeLinux}); } +bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const +{ + const QStringList args = statArgs(filePath, "%h", "%l"); + const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); + return result.stdOut.toLongLong() > 1; +} + bool UnixDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const { const QString path = filePath.path(); diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index d57da462d2f..0f8282477f6 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -34,6 +34,7 @@ protected: virtual bool isFile(const FilePath &filePath) const; virtual bool isDirectory(const FilePath &filePath) const; virtual bool isSymLink(const FilePath &filePath) const; + virtual bool hasHardLinks(const FilePath &filePath) const; virtual bool ensureWritableDirectory(const FilePath &filePath) const; virtual bool ensureExistingFile(const FilePath &filePath) const; virtual bool createDirectory(const FilePath &filePath) const; @@ -90,6 +91,7 @@ protected: bool isFile(const FilePath &filePath) const override; bool isDirectory(const FilePath &filePath) const override; bool isSymLink(const FilePath &filePath) const override; + bool hasHardLinks(const FilePath &filePath) const override; bool ensureWritableDirectory(const FilePath &filePath) const override; bool ensureExistingFile(const FilePath &filePath) const override; bool createDirectory(const FilePath &filePath) const override; @@ -148,6 +150,7 @@ protected: bool isFile(const FilePath &filePath) const override; bool isDirectory(const FilePath &filePath) const override; bool isSymLink(const FilePath &filePath) const override; + bool hasHardLinks(const FilePath &filePath) const override; bool ensureExistingFile(const FilePath &filePath) const override; bool createDirectory(const FilePath &filePath) const override; bool exists(const FilePath &filePath) const override; diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 1781831712c..0fce0a9e4c4 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -564,6 +564,11 @@ bool FilePath::isSymLink() const return fileAccess()->isSymLink(*this); } +bool FilePath::hasHardLinks() const +{ + return fileAccess()->hasHardLinks(*this); +} + /*! \brief Creates a directory in this location. diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 213eeb1e7b2..64651691545 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -118,6 +118,7 @@ public: bool isFile() const; bool isDir() const; bool isSymLink() const; + bool hasHardLinks() const; bool isRootPath() const; bool isNewerThan(const QDateTime &timeStamp) const; QDateTime lastModified() const; diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index f31bd822bbf..22d855fea3b 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -5,6 +5,7 @@ #include "savefile.h" #include "algorithm.h" +#include "devicefileaccess.h" #include "qtcassert.h" #include "utilstr.h" @@ -189,12 +190,13 @@ FileSaver::FileSaver(const FilePath &filePath, QIODevice::OpenMode mode) auto tf = new QTemporaryFile(QDir::tempPath() + "/remotefilesaver-XXXXXX"); tf->setAutoRemove(false); m_file.reset(tf); - } else if (mode & (QIODevice::ReadOnly | QIODevice::Append)) { - m_file.reset(new QFile{filePath.path()}); - m_isSafe = false; } else { - m_file.reset(new SaveFile(filePath)); - m_isSafe = true; + const bool readOnlyOrAppend = mode & (QIODevice::ReadOnly | QIODevice::Append); + m_isSafe = !readOnlyOrAppend && !filePath.hasHardLinks(); + if (m_isSafe) + m_file.reset(new SaveFile(filePath)); + else + m_file.reset(new QFile{filePath.path()}); } if (!m_file->open(QIODevice::WriteOnly | mode)) { QString err = filePath.exists() ? From 8175d5abdaf97c487313a4d18a177b22e390a12d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 18:27:10 +0200 Subject: [PATCH 0530/1447] onResultReady: Provide a context object for all usages Remove overloads for onResultReady() and onFinished() that don't take context object. Change-Id: Iaec538bcccd29e22791ec65cc95b4b87640708c3 Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- src/libs/utils/runextensions.h | 34 ------------------- src/plugins/android/androidrunnerworker.cpp | 6 ++-- .../android/androidsdkmanagerwidget.cpp | 2 +- src/plugins/ios/createsimulatordialog.cpp | 4 +-- src/plugins/ios/iosconfigurations.cpp | 2 +- src/plugins/ios/iossettingswidget.cpp | 18 +++++----- src/plugins/ios/iostoolhandler.cpp | 25 ++++++-------- src/plugins/ios/simulatorcontrol.cpp | 15 ++++---- src/plugins/ios/simulatorcontrol.h | 6 ++-- src/plugins/ios/simulatorinfomodel.cpp | 2 +- .../auto/runextensions/tst_runextensions.cpp | 3 +- 11 files changed, 39 insertions(+), 78 deletions(-) diff --git a/src/libs/utils/runextensions.h b/src/libs/utils/runextensions.h index f81eb56699c..3e0b7afb952 100644 --- a/src/libs/utils/runextensions.h +++ b/src/libs/utils/runextensions.h @@ -513,23 +513,6 @@ const QFuture &onResultReady(const QFuture &future, QObject *guard, Functi return future; } -/*! - Adds a handler for when a result is ready. - This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions - or create a QFutureWatcher already for other reasons. -*/ -template -const QFuture &onResultReady(const QFuture &future, Function f) -{ - auto watcher = new QFutureWatcher(); - QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); - QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, [f, watcher](int index) { - f(watcher->future().resultAt(index)); - }); - watcher->setFuture(future); - return future; -} - /*! Adds a handler for when the future is finished. This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions @@ -568,21 +551,4 @@ const QFuture &onFinished(const QFuture &future, QObject *guard, Function return future; } -/*! - Adds a handler for when the future is finished. - This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions - or create a QFutureWatcher already for other reasons. -*/ -template -const QFuture &onFinished(const QFuture &future, Function f) -{ - auto watcher = new QFutureWatcher(); - QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); - QObject::connect(watcher, &QFutureWatcherBase::finished, [f, watcher] { - f(watcher->future()); - }); - watcher->setFuture(future); - return future; -} - } // namespace Utils diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 14dc9112e84..3ec9457ee37 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -684,9 +684,9 @@ void AndroidRunnerWorker::asyncStart() { asyncStartHelper(); - m_pidFinder = Utils::onResultReady(Utils::asyncRun(findProcessPID, selector(), - m_packageName, m_isPreNougat), - bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1)); + m_pidFinder = Utils::onResultReady( + Utils::asyncRun(findProcessPID, selector(),m_packageName, m_isPreNougat), this, + bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1)); } void AndroidRunnerWorker::asyncStop() diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index c2b1ce6d6b3..56f32833c86 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -644,7 +644,7 @@ OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &a } }; m_optionsFuture = sdkManager->availableArguments(); - Utils::onResultReady(m_optionsFuture, populateOptions); + Utils::onResultReady(m_optionsFuture, this, populateOptions); auto dialogButtons = new QDialogButtonBox(this); dialogButtons->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); diff --git a/src/plugins/ios/createsimulatordialog.cpp b/src/plugins/ios/createsimulatordialog.cpp index 784c33742ff..5dce52221eb 100644 --- a/src/plugins/ios/createsimulatordialog.cpp +++ b/src/plugins/ios/createsimulatordialog.cpp @@ -61,10 +61,10 @@ CreateSimulatorDialog::CreateSimulatorDialog(QWidget *parent) }); m_futureSync.setCancelOnWait(true); - m_futureSync.addFuture(Utils::onResultReady(SimulatorControl::updateDeviceTypes(), this, + m_futureSync.addFuture(Utils::onResultReady(SimulatorControl::updateDeviceTypes(this), this, &CreateSimulatorDialog::populateDeviceTypes)); - QFuture> runtimesfuture = SimulatorControl::updateRuntimes(); + QFuture> runtimesfuture = SimulatorControl::updateRuntimes(this); Utils::onResultReady(runtimesfuture, this, [this](const QList &runtimes) { m_runtimes = runtimes; }); diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 54674de8ecb..93c00fb2ee6 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -404,7 +404,7 @@ void IosConfigurations::updateSimulators() dev = IDevice::ConstPtr(new IosSimulator(devId)); devManager->addDevice(dev); } - SimulatorControl::updateAvailableSimulators(); + SimulatorControl::updateAvailableSimulators(this); } void IosConfigurations::setDeveloperPath(const FilePath &devPath) diff --git a/src/plugins/ios/iossettingswidget.cpp b/src/plugins/ios/iossettingswidget.cpp index 8c4149a91ba..eee8b08efc8 100644 --- a/src/plugins/ios/iossettingswidget.cpp +++ b/src/plugins/ios/iossettingswidget.cpp @@ -175,7 +175,7 @@ void IosSettingsWidget::onStart() Utils::StdErrFormat); } else { futureList << QFuture(Utils::onResultReady( - SimulatorControl::startSimulator(info.identifier), + SimulatorControl::startSimulator(info.identifier), this, std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator start"), _1))); } } @@ -207,11 +207,9 @@ void IosSettingsWidget::onCreate() CreateSimulatorDialog createDialog(this); if (createDialog.exec() == QDialog::Accepted) { - QFuture f = QFuture( - Utils::onResultReady(SimulatorControl::createSimulator(createDialog.name(), - createDialog.deviceType(), - createDialog.runtime()), - std::bind(onSimulatorCreate, createDialog.name(), _1))); + QFuture f = QFuture(Utils::onResultReady(SimulatorControl::createSimulator( + createDialog.name(), createDialog.deviceType(), createDialog.runtime()), + this, std::bind(onSimulatorCreate, createDialog.name(), _1))); statusDialog->addFutures({ f }); statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. } @@ -242,7 +240,7 @@ void IosSettingsWidget::onReset() QList> futureList; for (const SimulatorInfo &info : simulatorInfoList) { futureList << QFuture(Utils::onResultReady( - SimulatorControl::resetSimulator(info.identifier), + SimulatorControl::resetSimulator(info.identifier), this, std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator reset"), _1))); } @@ -270,7 +268,7 @@ void IosSettingsWidget::onRename() statusDialog->setAttribute(Qt::WA_DeleteOnClose); statusDialog->addMessage(Tr::tr("Renaming simulator device..."), Utils::NormalMessageFormat); QFuture f = QFuture(Utils::onResultReady( - SimulatorControl::renameSimulator(simInfo.identifier, newName), + SimulatorControl::renameSimulator(simInfo.identifier, newName), this, std::bind(onSimOperation, simInfo, statusDialog, Tr::tr("simulator rename"), _1))); statusDialog->addFutures({f}); statusDialog->exec(); // Modal dialog returns only when all the operations are done or cancelled. @@ -300,7 +298,7 @@ void IosSettingsWidget::onDelete() QList> futureList; for (const SimulatorInfo &info : simulatorInfoList) { futureList << QFuture(Utils::onResultReady( - SimulatorControl::deleteSimulator(info.identifier), + SimulatorControl::deleteSimulator(info.identifier), this, std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator delete"), _1))); } @@ -331,7 +329,7 @@ void IosSettingsWidget::onScreenshot() QList> futureList; for (const SimulatorInfo &info : simulatorInfoList) { futureList << QFuture(Utils::onResultReady( - SimulatorControl::takeSceenshot(info.identifier, generatePath(info)), + SimulatorControl::takeSceenshot(info.identifier, generatePath(info)), this, std::bind(onSimOperation, info, statusDialog, Tr::tr("simulator screenshot"), _1))); } diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index b8a3c592ef4..5db9b808a88 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -815,8 +815,8 @@ void IosSimulatorToolHandlerPrivate::requestTransferApp(const QString &appBundle if (SimulatorControl::isSimulatorRunning(m_deviceId)) installAppOnSimulator(); else - futureSynchronizer.addFuture( - Utils::onResultReady(SimulatorControl::startSimulator(m_deviceId), onSimulatorStart)); + futureSynchronizer.addFuture(Utils::onResultReady( + SimulatorControl::startSimulator(m_deviceId), q, onSimulatorStart)); } void IosSimulatorToolHandlerPrivate::requestRunApp(const QString &appBundlePath, @@ -852,8 +852,8 @@ void IosSimulatorToolHandlerPrivate::requestRunApp(const QString &appBundlePath, if (SimulatorControl::isSimulatorRunning(m_deviceId)) launchAppOnSimulator(extraArgs); else - futureSynchronizer.addFuture( - Utils::onResultReady(SimulatorControl::startSimulator(m_deviceId), onSimulatorStart)); + futureSynchronizer.addFuture(Utils::onResultReady( + SimulatorControl::startSimulator(m_deviceId), q, onSimulatorStart)); } void IosSimulatorToolHandlerPrivate::requestDeviceInfo(const QString &deviceId, int timeout) @@ -905,7 +905,7 @@ void IosSimulatorToolHandlerPrivate::installAppOnSimulator() isTransferringApp(m_bundlePath, m_deviceId, 20, 100, ""); auto installFuture = SimulatorControl::installApp(m_deviceId, Utils::FilePath::fromString(m_bundlePath)); - futureSynchronizer.addFuture(Utils::onResultReady(installFuture, onResponseAppInstall)); + futureSynchronizer.addFuture(Utils::onResultReady(installFuture, q, onResponseAppInstall)); } void IosSimulatorToolHandlerPrivate::launchAppOnSimulator(const QStringList &extraArgs) @@ -968,16 +968,11 @@ void IosSimulatorToolHandlerPrivate::launchAppOnSimulator(const QStringList &ext } }; - futureSynchronizer.addFuture( - Utils::onResultReady(SimulatorControl::launchApp(m_deviceId, - bundleId, - debugRun, - extraArgs, - captureConsole ? stdoutFile->fileName() - : QString(), - captureConsole ? stderrFile->fileName() - : QString()), - onResponseAppLaunch)); + futureSynchronizer.addFuture(Utils::onResultReady(SimulatorControl::launchApp( + m_deviceId, bundleId, debugRun, extraArgs, + captureConsole ? stdoutFile->fileName() : QString(), + captureConsole ? stderrFile->fileName() : QString()), + q, onResponseAppLaunch)); } bool IosSimulatorToolHandlerPrivate::isResponseValid(const SimulatorControl::ResponseData &responseData) diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index 6a19513fd2a..59970b649c1 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -235,10 +235,10 @@ static QList getAvailableSimulators() return availableDevices; } -QFuture> SimulatorControl::updateDeviceTypes() +QFuture> SimulatorControl::updateDeviceTypes(QObject *context) { QFuture> future = Utils::asyncRun(getAvailableDeviceTypes); - Utils::onResultReady(future, [](const QList &deviceTypes) { + Utils::onResultReady(future, context, [](const QList &deviceTypes) { s_availableDeviceTypes = deviceTypes; }); return future; @@ -249,20 +249,21 @@ QList SimulatorControl::availableRuntimes() return s_availableRuntimes; } -QFuture> SimulatorControl::updateRuntimes() +QFuture> SimulatorControl::updateRuntimes(QObject *context) { QFuture> future = Utils::asyncRun(getAvailableRuntimes); - Utils::onResultReady(future, [](const QList &runtimes) { + Utils::onResultReady(future, context, [](const QList &runtimes) { s_availableRuntimes = runtimes; }); return future; } -QFuture> SimulatorControl::updateAvailableSimulators() +QFuture> SimulatorControl::updateAvailableSimulators(QObject *context) { QFuture> future = Utils::asyncRun(getAvailableSimulators); - Utils::onResultReady(future, - [](const QList &devices) { s_availableDevices = devices; }); + Utils::onResultReady(future, context, [](const QList &devices) { + s_availableDevices = devices; + }); return future; } diff --git a/src/plugins/ios/simulatorcontrol.h b/src/plugins/ios/simulatorcontrol.h index 90a0a6ac4b2..402100fbeac 100644 --- a/src/plugins/ios/simulatorcontrol.h +++ b/src/plugins/ios/simulatorcontrol.h @@ -65,11 +65,11 @@ public: public: static QList availableDeviceTypes(); - static QFuture> updateDeviceTypes(); + static QFuture> updateDeviceTypes(QObject *context); static QList availableRuntimes(); - static QFuture> updateRuntimes(); + static QFuture> updateRuntimes(QObject *context); static QList availableSimulators(); - static QFuture> updateAvailableSimulators(); + static QFuture> updateAvailableSimulators(QObject *context); static bool isSimulatorRunning(const QString &simUdid); static QString bundleIdentifier(const Utils::FilePath &bundlePath); static QString bundleExecutable(const Utils::FilePath &bundlePath); diff --git a/src/plugins/ios/simulatorinfomodel.cpp b/src/plugins/ios/simulatorinfomodel.cpp index df58dc98cba..8c79d161da9 100644 --- a/src/plugins/ios/simulatorinfomodel.cpp +++ b/src/plugins/ios/simulatorinfomodel.cpp @@ -109,7 +109,7 @@ void SimulatorInfoModel::requestSimulatorInfo() if (!m_fetchFuture.isEmpty()) return; // Ignore the request if the last request is still pending. - m_fetchFuture.addFuture(Utils::onResultReady(SimulatorControl::updateAvailableSimulators(), + m_fetchFuture.addFuture(Utils::onResultReady(SimulatorControl::updateAvailableSimulators(this), this, &SimulatorInfoModel::populateSimulators)); } diff --git a/tests/auto/runextensions/tst_runextensions.cpp b/tests/auto/runextensions/tst_runextensions.cpp index 50a3f8a40d6..d9b989582ce 100644 --- a/tests/auto/runextensions/tst_runextensions.cpp +++ b/tests/auto/runextensions/tst_runextensions.cpp @@ -553,13 +553,14 @@ public: void tst_RunExtensions::onResultReady() { { // lambda + QObject context; QFuture f = Utils::runAsync([](QFutureInterface &fi) { fi.reportResult("Hi"); fi.reportResult("there"); }); int count = 0; QString res; - Utils::onResultReady(f, [&count, &res](const QString &s) { + Utils::onResultReady(f, &context, [&count, &res](const QString &s) { ++count; res = s; }); From 78cf563142efe442796ff74d332c1d96024d1fde Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Tue, 11 Apr 2023 11:11:08 +0200 Subject: [PATCH 0531/1447] reformatter: fix formatting of js directives Fix the miscalculation of the start / end of the js directives lines. Also small optimizations on usage of increment operators. Add a unit test. Fixes: QTCREATORBUG-29001 Change-Id: I38923f137dca5c0b89d474cd747a64ec11e62fd9 Reviewed-by: Reviewed-by: Fabian Kosmale --- src/libs/qmljs/qmljsreformatter.cpp | 15 ++++++++------- tests/auto/qml/reformatter/jsdirectives.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 tests/auto/qml/reformatter/jsdirectives.js diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp index 461c944afaf..097119eb270 100644 --- a/src/libs/qmljs/qmljsreformatter.cpp +++ b/src/libs/qmljs/qmljsreformatter.cpp @@ -109,14 +109,15 @@ public: } const QList &directives = _doc->jsDirectives(); for (const auto &d: directives) { - quint32 line = 1; - int i = 0; - while (line++ < d.startLine && i++ >= 0) - i = _doc->source().indexOf(QChar('\n'), i); + quint32 line = 0; + const QString &source = _doc->source(); + int i = -1; + while (++line < d.startLine) + i = source.indexOf(QChar('\n'), i + 1); quint32 offset = static_cast(i) + d.startColumn; - int endline = _doc->source().indexOf('\n', static_cast(offset) + 1); - int end = endline == -1 ? _doc->source().length() : endline; - quint32 length = static_cast(end) - offset; + int endline = source.indexOf('\n', static_cast(offset) + 1); + int end = endline == -1 ? source.length() : endline; + quint32 length = static_cast(end) - offset + 1; out(SourceLocation(offset, length, d.startLine, d.startColumn)); } if (!directives.isEmpty()) diff --git a/tests/auto/qml/reformatter/jsdirectives.js b/tests/auto/qml/reformatter/jsdirectives.js new file mode 100644 index 00000000000..9029ba72335 --- /dev/null +++ b/tests/auto/qml/reformatter/jsdirectives.js @@ -0,0 +1,15 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + + +.pragma library + +.import QtQml as QTQML + + + +.import QtQuick as QTQUICK + + + +function test() {} From f773c09f33a81880ea38199b5fe49d6ba67b8b69 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 5 Apr 2023 12:48:19 +0200 Subject: [PATCH 0532/1447] TextEditor: fix crash on reload Since TextDocument::openImpl potentially processes events it could delete TextMarks. So tracking them in TextDocument::reload can be considered unsafe. Track them in TextDocumentLayout instead and remove the tracked mark if it gets deleted while reloading the document. Task-number: QTCREATORBUG-29004 Change-Id: I9d0478e9c763b49f145c1bbaeed1a0b602757014 Reviewed-by: Jarek Kobus --- src/plugins/texteditor/textdocument.cpp | 5 ++--- src/plugins/texteditor/textdocumentlayout.cpp | 21 +++++++++++++++++-- src/plugins/texteditor/textdocumentlayout.h | 5 ++++- src/plugins/texteditor/textmark.cpp | 2 ++ src/plugins/texteditor/textmark.h | 6 ++++++ 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 4a7e80f52ce..6276d731d06 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -836,15 +836,14 @@ bool TextDocument::reload(QString *errorString, const FilePath &realFilePath) emit aboutToReload(); auto documentLayout = qobject_cast(d->m_document.documentLayout()); - TextMarks marks; if (documentLayout) - marks = documentLayout->documentClosing(); // removes text marks non-permanently + documentLayout->documentAboutToReload(); // removes text marks non-permanently bool success = openImpl(errorString, filePath(), realFilePath, /*reload =*/true) == OpenResult::Success; if (documentLayout) - documentLayout->documentReloaded(marks, this); // re-adds text marks + documentLayout->documentReloaded(this); // re-adds text marks emit reloadFinished(success); return success; } diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index 2b6b77c374e..c38c75bd5e0 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -656,6 +656,7 @@ QSizeF TextDocumentLayout::documentSize() const TextMarks TextDocumentLayout::documentClosing() { + QTC_ASSERT(m_reloadMarks.isEmpty(), resetReloadMarks()); TextMarks marks; for (QTextBlock block = document()->begin(); block.isValid(); block = block.next()) { if (auto data = static_cast(block.userData())) @@ -664,9 +665,17 @@ TextMarks TextDocumentLayout::documentClosing() return marks; } -void TextDocumentLayout::documentReloaded(TextMarks marks, TextDocument *baseTextDocument) +void TextDocumentLayout::documentAboutToReload() { - for (TextMark *mark : std::as_const(marks)) { + m_reloadMarks = documentClosing(); + for (TextMark *mark : std::as_const(m_reloadMarks)) + mark->setDeleteCallback([this, mark] { m_reloadMarks.removeOne(mark); }); +} + +void TextDocumentLayout::documentReloaded(TextDocument *baseTextDocument) +{ + for (TextMark *mark : std::as_const(m_reloadMarks)) { + mark->setDeleteCallback({}); int blockNumber = mark->lineNumber() - 1; QTextBlock block = document()->findBlockByNumber(blockNumber); if (block.isValid()) { @@ -680,6 +689,7 @@ void TextDocumentLayout::documentReloaded(TextMarks marks, TextDocument *baseTex mark->removedFromEditor(); } } + m_reloadMarks.clear(); requestUpdate(); } @@ -721,6 +731,13 @@ void TextDocumentLayout::requestUpdateNow() requestUpdate(); } +void TextDocumentLayout::resetReloadMarks() +{ + for (TextMark *mark : std::as_const(m_reloadMarks)) + mark->setDeleteCallback({}); + m_reloadMarks.clear(); +} + static QRectF replacementBoundingRect(const QTextDocument *replacement) { QTC_ASSERT(replacement, return {}); diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index 19278ad93c9..d6f847e4810 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -245,7 +245,8 @@ public: QRectF blockBoundingRect(const QTextBlock &block) const override; TextMarks documentClosing(); - void documentReloaded(TextMarks marks, TextDocument *baseextDocument); + void documentAboutToReload(); + void documentReloaded(TextDocument *baseextDocument); void updateMarksLineNumber(); void updateMarksBlock(const QTextBlock &block); void scheduleUpdate(); @@ -253,6 +254,8 @@ public: private: bool m_updateScheduled = false; + TextMarks m_reloadMarks; + void resetReloadMarks(); signals: void updateExtraArea(); diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index b7ded20d3fc..0609121bffc 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -81,6 +81,8 @@ TextMark::~TextMark() TextMarkRegistry::remove(this); if (m_baseTextDocument) m_baseTextDocument->removeMark(this); + if (m_deleteCallback) + m_deleteCallback(); m_baseTextDocument = nullptr; } diff --git a/src/plugins/texteditor/textmark.h b/src/plugins/texteditor/textmark.h index 72712557058..927255161d5 100644 --- a/src/plugins/texteditor/textmark.h +++ b/src/plugins/texteditor/textmark.h @@ -118,12 +118,15 @@ public: bool isLocationMarker() const;; void setIsLocationMarker(bool newIsLocationMarker); + protected: void setSettingsPage(Utils::Id settingsPage); private: Q_DISABLE_COPY(TextMark) + void setDeleteCallback(const std::function &callback) { m_deleteCallback = callback; }; + TextDocument *m_baseTextDocument = nullptr; Utils::FilePath m_fileName; int m_lineNumber = 0; @@ -141,6 +144,9 @@ private: QVector m_actions; // FIXME Remove in master std::function()> m_actionsProvider; Utils::Id m_settingsPage; + std::function m_deleteCallback; + + friend class TextDocumentLayout; }; } // namespace TextEditor From 8a0b3815df67b450c25c6ec5022a85cdd9818106 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 13 Apr 2023 08:06:51 +0200 Subject: [PATCH 0533/1447] TextEditor: fix leaking TextSuggestion Change-Id: I6f8b27e339219880cf9ade42a1e70e6dafb625b1 Reviewed-by: Eike Ziller --- src/plugins/texteditor/textdocumentlayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index c38c75bd5e0..f40290b393d 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -357,7 +357,7 @@ TextSuggestion *TextBlockUserData::suggestion() const void TextBlockUserData::clearSuggestion() { - m_suggestion.release(); + m_suggestion.reset(); } void TextBlockUserData::addMark(TextMark *mark) From f67f02066c2ed82bb6cf72f1ba29c80f05d247df Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 12 Apr 2023 18:12:58 +0200 Subject: [PATCH 0534/1447] ClangCodeModel: Classify Q_PROPERTY functions as Qt-invokable Fixes: QTCREATORBUG-28971 Change-Id: Ia60a82aa83ad89fbf6b5d1332d413de029510b34 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdast.cpp | 14 ++++++++++++++ src/plugins/clangcodemodel/clangdast.h | 1 + .../clangcodemodel/clangdfindreferences.cpp | 13 +++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/plugins/clangcodemodel/clangdast.cpp b/src/plugins/clangcodemodel/clangdast.cpp index 6b97146dd56..01f12d1177e 100644 --- a/src/plugins/clangcodemodel/clangdast.cpp +++ b/src/plugins/clangcodemodel/clangdast.cpp @@ -172,6 +172,20 @@ bool ClangdAstNode::hasChildWithRole(const QString &role) const [&role](const ClangdAstNode &c) { return c.role() == role; }); } +bool ClangdAstNode::hasChild(const std::function &predicate, + bool recursive) const +{ + std::function fullPredicate = predicate; + if (recursive) { + fullPredicate = [&predicate](const ClangdAstNode &n) { + if (predicate(n)) + return true; + return n.hasChild(predicate, true); + }; + } + return Utils::contains(children().value_or(QList()), fullPredicate); +} + QString ClangdAstNode::operatorString() const { if (kind() == "BinaryOperator") diff --git a/src/plugins/clangcodemodel/clangdast.h b/src/plugins/clangcodemodel/clangdast.h index 7eb24e9f21f..cdb87c7be07 100644 --- a/src/plugins/clangcodemodel/clangdast.h +++ b/src/plugins/clangcodemodel/clangdast.h @@ -77,6 +77,7 @@ public: bool childContainsRange(int index, const LanguageServerProtocol::Range &range) const; bool hasChildWithRole(const QString &role) const; + bool hasChild(const std::function &predicate, bool recursive) const; QString operatorString() const; enum class FileStatus { Ours, Foreign, Mixed, Unknown }; diff --git a/src/plugins/clangcodemodel/clangdfindreferences.cpp b/src/plugins/clangcodemodel/clangdfindreferences.cpp index 2130587a2d5..12f860c87c1 100644 --- a/src/plugins/clangcodemodel/clangdfindreferences.cpp +++ b/src/plugins/clangcodemodel/clangdfindreferences.cpp @@ -595,6 +595,19 @@ static Usage::Tags getUsageType(const ClangdAstPath &path, const QString &search tags |= Usage::Tag::Operator; } } + if (pathIt->kind() == "CXXMethod") { + const ClangdAstNode &classNode = *std::next(pathIt); + if (classNode.hasChild([&](const ClangdAstNode &n) { + if (n.kind() != "StaticAssert") + return false; + return n.hasChild([&](const ClangdAstNode &n) { + return n.arcanaContains("Q_PROPERTY"); }, true) + && n.hasChild([&](const ClangdAstNode &n) { + return n.arcanaContains(" " + searchTerm); }, true); + }, false)) { + tags |= Usage::Tag::MocInvokable; + } + } return tags; } if (pathIt->kind() == "MemberInitializer") From 8fb258b85e82e2d520d1ae20226c3f89af22d019 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 12 Apr 2023 16:33:59 +0200 Subject: [PATCH 0535/1447] ClangCodeModel: Make use of QT_ANNOTATE_FUNCTION() See qtbase/6c54e10144e7af02f4c35e20e5f375a0cf280b8b. Fixes: QTCREATORBUG-28970 Change-Id: I7500c1e25a63d2a1cda66259c5ebd84976c27335 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/cppeditor/compileroptionsbuilder.cpp | 7 +++++++ src/plugins/cppeditor/compileroptionsbuilder.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/plugins/cppeditor/compileroptionsbuilder.cpp b/src/plugins/cppeditor/compileroptionsbuilder.cpp index d2c5e16325f..5f092121214 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.cpp +++ b/src/plugins/cppeditor/compileroptionsbuilder.cpp @@ -130,6 +130,7 @@ QStringList CompilerOptionsBuilder::build(ProjectFile::Kind fileKind, undefineCppLanguageFeatureMacrosForMsvc2015(); addDefineFunctionMacrosMsvc(); addDefineFunctionMacrosQnx(); + addQtMacros(); addHeaderPathOptions(); @@ -786,6 +787,12 @@ void CompilerOptionsBuilder::addDefineFunctionMacrosQnx() addMacros({{"_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE"}}); } +void CompilerOptionsBuilder::addQtMacros() +{ + if (m_projectPart.qtVersion != QtMajorVersion::None) + addMacros({{"QT_ANNOTATE_FUNCTION(x)", "__attribute__((annotate(#x)))"}}); +} + void CompilerOptionsBuilder::reset() { m_options.clear(); diff --git a/src/plugins/cppeditor/compileroptionsbuilder.h b/src/plugins/cppeditor/compileroptionsbuilder.h index 0e8c1a5fad0..d47a7e87e3d 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder.h +++ b/src/plugins/cppeditor/compileroptionsbuilder.h @@ -62,6 +62,7 @@ public: void undefineClangVersionMacrosForMsvc(); void addDefineFunctionMacrosQnx(); + void addQtMacros(); // Add custom options void add(const QString &arg, bool gccOnlyOption = false); From b795b42980d24b8c3febb7d9c7c1fd6b6ff1ba9a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 12 Apr 2023 12:15:12 +0200 Subject: [PATCH 0536/1447] CppEditor: More special rendering for string literals Display prefixes and suffixes different from the actual string, like we already did for raw string literals. This uncovered some minor bugs in both lexer and highlighter: - Wrong length for a setFormat() call in highlightRawStringLiteral() - Missing check for user-defined literal in raw string literals - Missing check for user-defined literal in multi-line strings Fixes: QTCREATORBUG-28869 Change-Id: I018717c50ddc1d09c609556161c85dfb0cc29fab Reviewed-by: David Schulz --- src/libs/3rdparty/cplusplus/Lexer.cpp | 7 +- src/plugins/cppeditor/cpphighlighter.cpp | 87 +++++++++++++++++-- src/plugins/cppeditor/cpphighlighter.h | 1 + .../testcases/highlightingtestcase.cpp | 10 +++ 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/Lexer.cpp b/src/libs/3rdparty/cplusplus/Lexer.cpp index e2f1b4e0e6b..fc1b72cb7db 100644 --- a/src/libs/3rdparty/cplusplus/Lexer.cpp +++ b/src/libs/3rdparty/cplusplus/Lexer.cpp @@ -217,14 +217,17 @@ void Lexer::scan_helper(Token *tok) tok->f.kind = s._tokenKind; const bool found = _expectedRawStringSuffix.isEmpty() ? scanUntilRawStringLiteralEndSimple() : scanUntilRawStringLiteralEndPrecise(); - if (found) + if (found) { + scanOptionalUserDefinedLiteral(tok); _state = 0; + } return; } else { // non-raw strings tok->f.joined = true; tok->f.kind = s._tokenKind; _state = 0; scanUntilQuote(tok, '"'); + scanOptionalUserDefinedLiteral(tok); return; } @@ -829,6 +832,8 @@ void Lexer::scanRawStringLiteral(Token *tok, unsigned char hint) _expectedRawStringSuffix.prepend(')'); _expectedRawStringSuffix.append('"'); } + if (closed) + scanOptionalUserDefinedLiteral(tok); } bool Lexer::scanUntilRawStringLiteralEndPrecise() diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 0f9184600b8..87e36491ad7 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -161,10 +161,8 @@ void CppHighlighter::highlightBlock(const QString &text) } else if (tk.is(T_NUMERIC_LITERAL)) { setFormat(tk.utf16charsBegin(), tk.utf16chars(), formatForCategory(C_NUMBER)); } else if (tk.isStringLiteral() || tk.isCharLiteral()) { - if (!highlightRawStringLiteral(text, tk, QString::fromUtf8(inheritedRawStringSuffix))) { - setFormatWithSpaces(text, tk.utf16charsBegin(), tk.utf16chars(), - formatForCategory(C_STRING)); - } + if (!highlightRawStringLiteral(text, tk, QString::fromUtf8(inheritedRawStringSuffix))) + highlightStringLiteral(text, tk); } else if (tk.isComment()) { const int startPosition = initialLexerState ? previousTokenEnd : tk.utf16charsBegin(); if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT)) { @@ -413,8 +411,18 @@ bool CppHighlighter::highlightRawStringLiteral(QStringView text, const Token &tk stringOffset = delimiterOffset + delimiter.length() + 1; stringLength -= delimiter.length() + 1; }(); - if (text.mid(tk.utf16charsBegin(), tk.utf16chars()).endsWith(expectedSuffix)) { - endDelimiterOffset = tk.utf16charsBegin() + tk.utf16chars() - expectedSuffix.size(); + int operatorOffset = tk.utf16charsBegin() + tk.utf16chars(); + int operatorLength = 0; + if (tk.f.userDefinedLiteral) { + const int closingQuoteOffset = text.lastIndexOf('"', operatorOffset); + QTC_ASSERT(closingQuoteOffset >= tk.utf16charsBegin(), return false); + operatorOffset = closingQuoteOffset + 1; + operatorLength = tk.utf16charsBegin() + tk.utf16chars() - operatorOffset; + stringLength -= operatorLength; + } + if (text.mid(tk.utf16charsBegin(), operatorOffset - tk.utf16charsBegin()) + .endsWith(expectedSuffix)) { + endDelimiterOffset = operatorOffset - expectedSuffix.size(); stringLength -= expectedSuffix.size(); } @@ -422,13 +430,52 @@ bool CppHighlighter::highlightRawStringLiteral(QStringView text, const Token &tk // a string, and the rest (including the delimiter) as a keyword. const QTextCharFormat delimiterFormat = formatForCategory(C_KEYWORD); if (delimiterOffset != -1) - setFormat(tk.utf16charsBegin(), stringOffset, delimiterFormat); + setFormat(tk.utf16charsBegin(), stringOffset - tk.utf16charsBegin(), delimiterFormat); setFormatWithSpaces(text.toString(), stringOffset, stringLength, formatForCategory(C_STRING)); if (endDelimiterOffset != -1) setFormat(endDelimiterOffset, expectedSuffix.size(), delimiterFormat); + if (operatorLength > 0) + setFormat(operatorOffset, operatorLength, formatForCategory(C_OPERATOR)); return true; } +void CppHighlighter::highlightStringLiteral(QStringView text, const CPlusPlus::Token &tk) +{ + switch (tk.kind()) { + case T_WIDE_STRING_LITERAL: + case T_UTF8_STRING_LITERAL: + case T_UTF16_STRING_LITERAL: + case T_UTF32_STRING_LITERAL: + break; + default: + if (!tk.userDefinedLiteral()) { // Simple case: No prefix, no suffix. + setFormatWithSpaces(text.toString(), tk.utf16charsBegin(), tk.utf16chars(), + formatForCategory(C_STRING)); + return; + } + } + + int stringOffset = 0; + if (!tk.f.joined) { + stringOffset = text.indexOf('"', tk.utf16charsBegin()); + QTC_ASSERT(stringOffset > 0, return); + setFormat(tk.utf16charsBegin(), stringOffset - tk.utf16charsBegin(), + formatForCategory(C_KEYWORD)); + } + int operatorOffset = tk.utf16charsBegin() + tk.utf16chars(); + if (tk.userDefinedLiteral()) { + const int closingQuoteOffset = text.lastIndexOf('"', operatorOffset); + QTC_ASSERT(closingQuoteOffset >= tk.utf16charsBegin(), return); + operatorOffset = closingQuoteOffset + 1; + } + setFormatWithSpaces(text.toString(), stringOffset, operatorOffset - tk.utf16charsBegin(), + formatForCategory(C_STRING)); + if (const int operatorLength = tk.utf16charsBegin() + tk.utf16chars() - operatorOffset; + operatorLength > 0) { + setFormat(operatorOffset, operatorLength, formatForCategory(C_OPERATOR)); + } +} + void CppHighlighter::highlightDoxygenComment(const QString &text, int position, int) { int initial = position; @@ -514,6 +561,32 @@ void CppHighlighterTest::test_data() QTest::newRow("operator keyword") << 26 << 5 << 26 << 12 << C_KEYWORD; QTest::newRow("type in conversion operator") << 26 << 14 << 26 << 16 << C_PRIMITIVE_TYPE; QTest::newRow("concept keyword") << 29 << 22 << 29 << 28 << C_KEYWORD; + QTest::newRow("user-defined UTF-16 string literal (prefix)") + << 32 << 16 << 32 << 16 << C_KEYWORD; + QTest::newRow("user-defined UTF-16 string literal (content)") + << 32 << 17 << 32 << 21 << C_STRING; + QTest::newRow("user-defined UTF-16 string literal (suffix)") + << 32 << 22 << 32 << 23 << C_OPERATOR; + QTest::newRow("wide string literal (prefix)") << 33 << 17 << 33 << 17 << C_KEYWORD; + QTest::newRow("wide string literal (content)") << 33 << 18 << 33 << 24 << C_STRING; + QTest::newRow("UTF-8 string literal (prefix)") << 34 << 17 << 34 << 18 << C_KEYWORD; + QTest::newRow("UTF-8 string literal (content)") << 34 << 19 << 34 << 24 << C_STRING; + QTest::newRow("UTF-32 string literal (prefix)") << 35 << 17 << 35 << 17 << C_KEYWORD; + QTest::newRow("UTF-8 string literal (content)") << 35 << 18 << 35 << 23 << C_STRING; + QTest::newRow("user-defined UTF-16 raw string literal (prefix)") + << 36 << 17 << 36 << 20 << C_KEYWORD; + QTest::newRow("user-defined UTF-16 raw string literal (content)") + << 36 << 38 << 37 << 8 << C_STRING; + QTest::newRow("user-defined UTF-16 raw string literal (suffix 1)") + << 37 << 9 << 37 << 10 << C_KEYWORD; + QTest::newRow("user-defined UTF-16 raw string literal (suffix 2)") + << 37 << 11 << 37 << 12 << C_OPERATOR; + QTest::newRow("multi-line user-defined UTF-16 string literal (prefix)") + << 38 << 17 << 38 << 17 << C_KEYWORD; + QTest::newRow("multi-line user-defined UTF-16 string literal (content)") + << 38 << 18 << 39 << 3 << C_STRING; + QTest::newRow("multi-line user-defined UTF-16 string literal (suffix)") + << 39 << 4 << 39 << 5 << C_OPERATOR; } void CppHighlighterTest::test() diff --git a/src/plugins/cppeditor/cpphighlighter.h b/src/plugins/cppeditor/cpphighlighter.h index 358fcb2760e..1728ffeb777 100644 --- a/src/plugins/cppeditor/cpphighlighter.h +++ b/src/plugins/cppeditor/cpphighlighter.h @@ -29,6 +29,7 @@ private: void highlightWord(QStringView word, int position, int length); bool highlightRawStringLiteral(QStringView text, const CPlusPlus::Token &tk, const QString &inheritedSuffix); + void highlightStringLiteral(QStringView text, const CPlusPlus::Token &tk); void highlightDoxygenComment(const QString &text, int position, int length); diff --git a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp index 770b22e553e..dd1f9c1b3e8 100644 --- a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp +++ b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp @@ -27,3 +27,13 @@ struct ConversionFunction { }; template concept NoConstraint = true; + +const char16_t *operator ""_w(const char16_t *s, size_t) { return s; } +const auto s = u"one"_w; +const auto s2 = L"hello"; +const auto s3 = u8"hello"; +const auto s4 = U"hello"; +const auto s5 = uR"("o + ne")"_w; +const auto s6 = u"o\ +ne"_w; From de0e0fab188d2de89954e3a4a593560be93e8fbe Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 13 Apr 2023 13:45:51 +0200 Subject: [PATCH 0537/1447] CppEditor: Fix tests Amends 8fb258b85e82e2d520d1ae20226c3f89af22d019. Change-Id: I0b9339a60da459557c0335b0680f258ce689b45f Reviewed-by: David Schulz --- src/plugins/cppeditor/compileroptionsbuilder_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/cppeditor/compileroptionsbuilder_test.cpp b/src/plugins/cppeditor/compileroptionsbuilder_test.cpp index 3a19c16a663..b09a8061fc7 100644 --- a/src/plugins/cppeditor/compileroptionsbuilder_test.cpp +++ b/src/plugins/cppeditor/compileroptionsbuilder_test.cpp @@ -593,6 +593,7 @@ void CompilerOptionsBuilderTest::testBuildAllOptions() (QStringList{"-nostdinc", "-nostdinc++", "-arch", "x86_64", "-fsyntax-only", "-m64", "--target=x86_64-apple-darwin10", "-x", "c++", "-std=c++17", "-DprojectFoo=projectBar", + "-DQT_ANNOTATE_FUNCTION(x)=__attribute__((annotate(#x)))", wrappedQtHeadersPath, // contains -I already wrappedQtCoreHeadersPath, // contains -I already "-I" + t.toNative("/tmp/path"), @@ -621,6 +622,7 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvc() "-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"", "-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"", "-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"", + "-DQT_ANNOTATE_FUNCTION(x)=__attribute__((annotate(#x)))", wrappedQtHeadersPath, // contains -I already wrappedQtCoreHeadersPath, // contains -I already "-I" + t.toNative("/tmp/path"), @@ -651,6 +653,7 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvcWithExceptions() "-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"", "-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"", "-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"", + "-DQT_ANNOTATE_FUNCTION(x)=__attribute__((annotate(#x)))", wrappedQtHeadersPath, // contains -I already wrappedQtCoreHeadersPath, // contains -I already "-I" + t.toNative("/tmp/path"), From 402877774345d3b61e8a4924bf7f6075b4c37cbd Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 11 Apr 2023 12:49:21 +0200 Subject: [PATCH 0538/1447] ClangTools: Prefer .clang-tidy file by default ... and move this setting outside the diagnostic config. Fixes: QTCREATORBUG-28852 Change-Id: Ie3b19ba7bec2bc96451f3216fa06a6941cad4c94 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangtextmark.cpp | 9 ++-- src/plugins/clangtools/clangtool.cpp | 4 +- .../clangtools/clangtoolruncontrol.cpp | 6 ++- src/plugins/clangtools/clangtoolrunner.cpp | 25 ++++----- src/plugins/clangtools/clangtoolrunner.h | 2 + .../clangtools/clangtoolsdiagnosticview.cpp | 5 +- src/plugins/clangtools/clangtoolssettings.cpp | 17 ++++++ src/plugins/clangtools/clangtoolssettings.h | 6 +++ src/plugins/clangtools/clangtoolsutils.cpp | 8 +++ src/plugins/clangtools/clangtoolsutils.h | 3 ++ .../clangtools/diagnosticconfigswidget.cpp | 53 ++++--------------- .../clangtools/diagnosticconfigswidget.h | 1 - .../clangtools/documentclangtoolrunner.cpp | 8 +-- src/plugins/clangtools/runsettingswidget.cpp | 10 ++-- src/plugins/clangtools/runsettingswidget.h | 1 + src/plugins/cppeditor/clangdiagnosticconfig.h | 4 +- 16 files changed, 83 insertions(+), 79 deletions(-) diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index a38aeb62873..570e6a2e956 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -98,15 +98,12 @@ ClangDiagnosticConfig diagnosticConfig() return warningsConfigForProject(project); } -bool isDiagnosticConfigChangable(Project *project, const ClangDiagnostic &diagnostic) +static bool isDiagnosticConfigChangable(Project *project) { if (!project) return false; - const ClangDiagnosticConfig config = diagnosticConfig(); - if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::UseConfigFile - && diagnosticType(diagnostic) == DiagnosticType::Tidy) { + if (diagnosticConfig().useBuildSystemWarnings()) return false; - } return true; } @@ -308,7 +305,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath, // Remove diagnostic warning action Project *project = projectForCurrentEditor(); - if (project && isDiagnosticConfigChangable(project, diag)) { + if (project && isDiagnosticConfigChangable(project)) { action = new QAction(); action->setIcon(Icons::BROKEN.icon()); action->setToolTip(Tr::tr("Disable Diagnostic in Current Project")); diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index bf13622b590..565d899d838 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -858,13 +858,13 @@ static CheckResult canAnalyze() { const ClangDiagnosticConfig config = diagnosticConfig(runSettings().diagnosticConfigId()); - if (config.isEnabled(ClangToolType::Tidy) + if (toolEnabled(ClangToolType::Tidy, config, runSettings()) && !toolExecutable(ClangToolType::Tidy).isExecutableFile()) { return {CheckResult::InvalidTidyExecutable, Tr::tr("Set a valid Clang-Tidy executable.")}; } - if (config.isEnabled(ClangToolType::Clazy) + if (toolEnabled(ClangToolType::Clazy, config, runSettings()) && !toolExecutable(ClangToolType::Clazy).isExecutableFile()) { return {CheckResult::InvalidClazyExecutable, Tr::tr("Set a valid Clazy-Standalone executable.")}; diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index 7881b53916f..dabfb8a6b86 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -185,7 +185,11 @@ void ClangToolRunWorker::start() using namespace Tasking; QList tasks{ParallelLimit(qMax(1, m_runSettings.parallelJobs()))}; for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) { - const AnalyzeInputData input{tool, m_diagnosticConfig, m_temporaryDir.path(), + if (!m_diagnosticConfig.isEnabled(tool) + && !m_runSettings.hasConfigFileForSourceFile(unit.file)) { + continue; + } + const AnalyzeInputData input{tool, m_runSettings, m_diagnosticConfig, m_temporaryDir.path(), m_environment, unit}; const auto setupHandler = [this, unit, tool] { const QString filePath = unit.file.toUserOutput(); diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 90bfe51ca30..827cb9672b1 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -52,21 +52,22 @@ static bool isClMode(const QStringList &options) return options.contains("--driver-mode=cl"); } -static QStringList checksArguments(ClangToolType tool, - const ClangDiagnosticConfig &diagnosticConfig) +static QStringList checksArguments(const AnalyzeInputData &input) { - if (tool == ClangToolType::Tidy) { - const ClangDiagnosticConfig::TidyMode tidyMode = diagnosticConfig.clangTidyMode(); - // The argument "-config={}" stops stating/evaluating the .clang-tidy file. - if (tidyMode == ClangDiagnosticConfig::TidyMode::UseDefaultChecks) + if (input.tool == ClangToolType::Tidy) { + if (input.runSettings.hasConfigFileForSourceFile(input.unit.file)) + return {"--warnings-as-errors=-*", "-checks=-clang-diagnostic-*"}; + switch (input.config.clangTidyMode()) { + case ClangDiagnosticConfig::TidyMode::UseDefaultChecks: + // The argument "-config={}" stops stating/evaluating the .clang-tidy file. return {"-config={}", "-checks=-clang-diagnostic-*"}; - if (tidyMode == ClangDiagnosticConfig::TidyMode::UseCustomChecks) - return {"-config=" + diagnosticConfig.clangTidyChecksAsJson()}; - return {"--warnings-as-errors=-*", "-checks=-clang-diagnostic-*"}; + case ClangDiagnosticConfig::TidyMode::UseCustomChecks: + return {"-config=" + input.config.clangTidyChecksAsJson()}; + } } - const QString clazyChecks = diagnosticConfig.checks(ClangToolType::Clazy); + const QString clazyChecks = input.config.checks(ClangToolType::Clazy); if (!clazyChecks.isEmpty()) - return {"-checks=" + diagnosticConfig.checks(ClangToolType::Clazy)}; + return {"-checks=" + input.config.checks(ClangToolType::Clazy)}; return {}; } @@ -148,7 +149,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, const ClangToolStorage &data = *storage; - const QStringList args = checksArguments(input.tool, input.config) + const QStringList args = checksArguments(input) + mainToolArguments(data) + QStringList{"--"} + clangArguments(input.config, input.unit.arguments); diff --git a/src/plugins/clangtools/clangtoolrunner.h b/src/plugins/clangtools/clangtoolrunner.h index 104e3ab90b6..f581f7169aa 100644 --- a/src/plugins/clangtools/clangtoolrunner.h +++ b/src/plugins/clangtools/clangtoolrunner.h @@ -4,6 +4,7 @@ #pragma once #include "clangfileinfo.h" +#include "clangtoolssettings.h" #include @@ -28,6 +29,7 @@ using AnalyzeUnits = QList; struct AnalyzeInputData { CppEditor::ClangToolType tool = CppEditor::ClangToolType::Tidy; + RunSettings runSettings; CppEditor::ClangDiagnosticConfig config; Utils::FilePath outputDirPath; Utils::Environment environment; diff --git a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp index a516ef3066e..ed264b603d8 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp @@ -313,9 +313,8 @@ bool DiagnosticView::disableChecksEnabled() const if (!activeConfig.id().isValid()) return false; - // If all selected diagnostics come from clang-tidy and the active config is controlled - // by a .clang-tidy file, then we do not offer the action. - if (activeConfig.clangTidyMode() != ClangDiagnosticConfig::TidyMode::UseConfigFile) + // If all selected diagnostics come from clang-tidy and we prefer a .clang-tidy file, then we do not offer the action. + if (!settings->runSettings().preferConfigFile()) return true; return Utils::anyOf(indexes, [this](const QModelIndex &index) { return model()->data(index).toString().startsWith("clazy-"); diff --git a/src/plugins/clangtools/clangtoolssettings.cpp b/src/plugins/clangtools/clangtoolssettings.cpp index eeb24d14579..286b076f95c 100644 --- a/src/plugins/clangtools/clangtoolssettings.cpp +++ b/src/plugins/clangtools/clangtoolssettings.cpp @@ -27,6 +27,7 @@ const char clangTidyExecutableKey[] = "ClangTidyExecutable"; const char clazyStandaloneExecutableKey[] = "ClazyStandaloneExecutable"; const char parallelJobsKey[] = "ParallelJobs"; +const char preferConfigFileKey[] = "PreferConfigFile"; const char buildBeforeAnalysisKey[] = "BuildBeforeAnalysis"; const char analyzeOpenFilesKey[] = "AnalyzeOpenFiles"; const char oldDiagnosticConfigIdKey[] = "diagnosticConfigId"; @@ -46,6 +47,7 @@ void RunSettings::fromMap(const QVariantMap &map, const QString &prefix) { m_diagnosticConfigId = Id::fromSetting(map.value(prefix + diagnosticConfigIdKey)); m_parallelJobs = map.value(prefix + parallelJobsKey).toInt(); + m_preferConfigFile = map.value(prefix + preferConfigFileKey).toBool(); m_buildBeforeAnalysis = map.value(prefix + buildBeforeAnalysisKey).toBool(); m_analyzeOpenFiles = map.value(prefix + analyzeOpenFilesKey).toBool(); } @@ -54,6 +56,7 @@ void RunSettings::toMap(QVariantMap &map, const QString &prefix) const { map.insert(prefix + diagnosticConfigIdKey, m_diagnosticConfigId.toSetting()); map.insert(prefix + parallelJobsKey, m_parallelJobs); + map.insert(prefix + preferConfigFileKey, m_preferConfigFile); map.insert(prefix + buildBeforeAnalysisKey, m_buildBeforeAnalysis); map.insert(prefix + analyzeOpenFilesKey, m_analyzeOpenFiles); } @@ -69,10 +72,23 @@ bool RunSettings::operator==(const RunSettings &other) const { return m_diagnosticConfigId == other.m_diagnosticConfigId && m_parallelJobs == other.m_parallelJobs + && m_preferConfigFile == other.m_preferConfigFile && m_buildBeforeAnalysis == other.m_buildBeforeAnalysis && m_analyzeOpenFiles == other.m_analyzeOpenFiles; } +bool RunSettings::hasConfigFileForSourceFile(const Utils::FilePath &sourceFile) const +{ + if (!preferConfigFile()) + return false; + for (FilePath parentDir = sourceFile.parentDir(); !parentDir.isEmpty(); + parentDir = parentDir.parentDir()) { + if (parentDir.resolvePath(QLatin1String(".clang-tidy")).isReadableFile()) + return true; + } + return false; +} + ClangToolsSettings::ClangToolsSettings() { readSettings(); @@ -139,6 +155,7 @@ void ClangToolsSettings::readSettings() QVariantMap defaults; defaults.insert(diagnosticConfigIdKey, defaultDiagnosticId().toSetting()); defaults.insert(parallelJobsKey, m_runSettings.parallelJobs()); + defaults.insert(preferConfigFileKey, m_runSettings.preferConfigFile()); defaults.insert(buildBeforeAnalysisKey, m_runSettings.buildBeforeAnalysis()); defaults.insert(analyzeOpenFilesKey, m_runSettings.analyzeOpenFiles()); map = defaults; diff --git a/src/plugins/clangtools/clangtoolssettings.h b/src/plugins/clangtools/clangtoolssettings.h index 3ecbfcc30ac..45a2cb032e4 100644 --- a/src/plugins/clangtools/clangtoolssettings.h +++ b/src/plugins/clangtools/clangtoolssettings.h @@ -31,6 +31,9 @@ public: Utils::Id diagnosticConfigId() const; void setDiagnosticConfigId(const Utils::Id &id) { m_diagnosticConfigId = id; } + bool preferConfigFile() const { return m_preferConfigFile; } + void setPreferConfigFile(bool yesno) { m_preferConfigFile = yesno; } + bool buildBeforeAnalysis() const { return m_buildBeforeAnalysis; } void setBuildBeforeAnalysis(bool yesno) { m_buildBeforeAnalysis = yesno; } @@ -42,9 +45,12 @@ public: bool operator==(const RunSettings &other) const; + bool hasConfigFileForSourceFile(const Utils::FilePath &sourceFile) const; + private: Utils::Id m_diagnosticConfigId; int m_parallelJobs = -1; + bool m_preferConfigFile = true; bool m_buildBeforeAnalysis = true; bool m_analyzeOpenFiles = true; }; diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index 2fad633bfaf..72f8086be1e 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -343,5 +343,13 @@ QString clazyDocUrl(const QString &check) return QString::fromLatin1(urlTemplate).arg(versionString, check); } +bool toolEnabled(CppEditor::ClangToolType type, const ClangDiagnosticConfig &config, + const RunSettings &runSettings) +{ + if (type == ClangToolType::Tidy && runSettings.preferConfigFile()) + return true; + return config.isEnabled(type); +} + } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/clangtools/clangtoolsutils.h b/src/plugins/clangtools/clangtoolsutils.h index 6f4f2871a02..36bcc75ff29 100644 --- a/src/plugins/clangtools/clangtoolsutils.h +++ b/src/plugins/clangtools/clangtoolsutils.h @@ -17,6 +17,7 @@ namespace Utils { class FilePath; } namespace ClangTools { namespace Internal { +class RunSettings; QString clangTidyDocUrl(const QString &check); QString clazyDocUrl(const QString &check); @@ -47,6 +48,8 @@ Utils::FilePath toolShippedExecutable(CppEditor::ClangToolType tool); Utils::FilePath toolExecutable(CppEditor::ClangToolType tool); Utils::FilePath toolFallbackExecutable(CppEditor::ClangToolType tool); QString clangToolName(CppEditor::ClangToolType tool); +bool toolEnabled(CppEditor::ClangToolType type, const CppEditor::ClangDiagnosticConfig &config, + const RunSettings &runSettings); bool isVFSOverlaySupported(const Utils::FilePath &executable); diff --git a/src/plugins/clangtools/diagnosticconfigswidget.cpp b/src/plugins/clangtools/diagnosticconfigswidget.cpp index a2b55be1b4b..2b44fa6da85 100644 --- a/src/plugins/clangtools/diagnosticconfigswidget.cpp +++ b/src/plugins/clangtools/diagnosticconfigswidget.cpp @@ -56,7 +56,6 @@ QString removeClazyCheck(const QString &checks, const QString &check); class TidyChecksWidget : public QWidget { public: - QComboBox *tidyMode; QPushButton *plainTextEditButton; FancyLineEdit *filterLineEdit; QTreeView *checksPrefixesTree; @@ -65,10 +64,6 @@ public: TidyChecksWidget() { - tidyMode = new QComboBox; - tidyMode->addItem(Tr::tr("Select Checks")); - tidyMode->addItem(Tr::tr("Use .clang-tidy config file")); - plainTextEditButton = new QPushButton(Tr::tr("Edit Checks as String...")); filterLineEdit = new FancyLineEdit; @@ -104,7 +99,7 @@ public: }.attachTo(invalidExecutablePage, WithoutMargins); Column { - Row { tidyMode, plainTextEditButton, filterLineEdit }, + Row { plainTextEditButton, filterLineEdit }, stackedWidget, }.attachTo(this); } @@ -1107,32 +1102,18 @@ void DiagnosticConfigsWidget::syncClangTidyWidgets(const ClangDiagnosticConfig & disconnectClangTidyItemChanged(); - const ClangDiagnosticConfig::TidyMode tidyMode = config.clangTidyMode(); - switch (tidyMode) { - case ClangDiagnosticConfig::TidyMode::UseConfigFile: - m_tidyChecks->tidyMode->setCurrentIndex(1); + if (m_tidyInfo.supportedChecks.isEmpty()) { m_tidyChecks->plainTextEditButton->setVisible(false); m_tidyChecks->filterLineEdit->setVisible(false); - m_tidyChecks->stackedWidget->setCurrentIndex(TidyPages::EmptyPage); - break; - case ClangDiagnosticConfig::TidyMode::UseCustomChecks: - case ClangDiagnosticConfig::TidyMode::UseDefaultChecks: - m_tidyChecks->tidyMode->setCurrentIndex(0); - if (m_tidyInfo.supportedChecks.isEmpty()) { - m_tidyChecks->plainTextEditButton->setVisible(false); - m_tidyChecks->filterLineEdit->setVisible(false); - m_tidyChecks->stackedWidget->setCurrentIndex(TidyPages::InvalidExecutablePage); - } else { - m_tidyChecks->plainTextEditButton->setVisible(true); - m_tidyChecks->filterLineEdit->setVisible(true); - m_tidyChecks->stackedWidget->setCurrentIndex(TidyPages::ChecksPage); - syncTidyChecksToTree(config); - } - break; + m_tidyChecks->stackedWidget->setCurrentIndex(TidyPages::InvalidExecutablePage); + } else { + m_tidyChecks->plainTextEditButton->setVisible(true); + m_tidyChecks->filterLineEdit->setVisible(true); + m_tidyChecks->stackedWidget->setCurrentIndex(TidyPages::ChecksPage); + syncTidyChecksToTree(config); } const bool enabled = !config.isReadOnly(); - m_tidyChecks->tidyMode->setEnabled(enabled); m_tidyChecks->plainTextEditButton->setText(enabled ? Tr::tr("Edit Checks as String...") : Tr::tr("View Checks as String...")); m_tidyTreeModel->setEnabled(enabled); @@ -1189,16 +1170,12 @@ void DiagnosticConfigsWidget::syncExtraWidgets(const ClangDiagnosticConfig &conf void DiagnosticConfigsWidget::connectClangTidyItemChanged() { - connect(m_tidyChecks->tidyMode, &QComboBox::currentIndexChanged, - this, &DiagnosticConfigsWidget::onClangTidyModeChanged); connect(m_tidyTreeModel.get(), &TidyChecksTreeModel::dataChanged, this, &DiagnosticConfigsWidget::onClangTidyTreeChanged); } void DiagnosticConfigsWidget::disconnectClangTidyItemChanged() { - disconnect(m_tidyChecks->tidyMode, &QComboBox::currentIndexChanged, - this, &DiagnosticConfigsWidget::onClangTidyModeChanged); disconnect(m_tidyTreeModel.get(), &TidyChecksTreeModel::dataChanged, this, &DiagnosticConfigsWidget::onClangTidyTreeChanged); } @@ -1215,18 +1192,6 @@ void DiagnosticConfigsWidget::disconnectClazyItemChanged() this, &DiagnosticConfigsWidget::onClazyTreeChanged); } -void DiagnosticConfigsWidget::onClangTidyModeChanged(int index) -{ - const ClangDiagnosticConfig::TidyMode tidyMode - = index == 0 ? ClangDiagnosticConfig::TidyMode::UseCustomChecks - : ClangDiagnosticConfig::TidyMode::UseConfigFile; - - ClangDiagnosticConfig config = currentConfig(); - config.setClangTidyMode(tidyMode); - updateConfig(config); - syncClangTidyWidgets(config); -} - void DiagnosticConfigsWidget::onClangTidyTreeChanged() { ClangDiagnosticConfig config = currentConfig(); @@ -1330,7 +1295,7 @@ void disableChecks(const QList &diagnostics) } config.setChecks(ClangToolType::Clazy, removeClazyCheck(config.checks(ClangToolType::Clazy), diag.name)); - } else if (config.clangTidyMode() != ClangDiagnosticConfig::TidyMode::UseConfigFile) { + } else if (!settings->runSettings().preferConfigFile()){ if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::UseDefaultChecks) { config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::UseCustomChecks); const ClangTidyInfo tidyInfo(toolExecutable(ClangToolType::Tidy)); diff --git a/src/plugins/clangtools/diagnosticconfigswidget.h b/src/plugins/clangtools/diagnosticconfigswidget.h index 7a3b8927606..04af842f0e7 100644 --- a/src/plugins/clangtools/diagnosticconfigswidget.h +++ b/src/plugins/clangtools/diagnosticconfigswidget.h @@ -41,7 +41,6 @@ private: void syncClazyWidgets(const CppEditor::ClangDiagnosticConfig &config); void syncClazyChecksGroupBox(); - void onClangTidyModeChanged(int index); void onClangTidyTreeChanged(); void onClazyTreeChanged(); diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index 6a08b579f18..6683929011f 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -190,15 +190,17 @@ void DocumentClangToolRunner::run() const Environment env = projectBuildEnvironment(project); using namespace Tasking; QList tasks{parallel}; - const auto addClangTool = [this, &config, &env, &tasks](ClangToolType tool) { - if (!config.isEnabled(tool)) + const auto addClangTool = [this, &runSettings, &config, &env, &tasks](ClangToolType tool) { + if (!toolEnabled(tool, config, runSettings)) + return; + if (!config.isEnabled(tool) && !runSettings.hasConfigFileForSourceFile(m_fileInfo.file)) return; const FilePath executable = toolExecutable(tool); const auto [includeDir, clangVersion] = getClangIncludeDirAndVersion(executable); if (!executable.isExecutableFile() || includeDir.isEmpty() || clangVersion.isEmpty()) return; const AnalyzeUnit unit(m_fileInfo, includeDir, clangVersion); - const AnalyzeInputData input{tool, config, m_temporaryDir.path(), env, unit, + const AnalyzeInputData input{tool, runSettings, config, m_temporaryDir.path(), env, unit, vfso().overlayFilePath().toString()}; const auto setupHandler = [this, executable] { return !m_document->isModified() || isVFSOverlaySupported(executable); diff --git a/src/plugins/clangtools/runsettingswidget.cpp b/src/plugins/clangtools/runsettingswidget.cpp index 0e7a34959fd..841661f0155 100644 --- a/src/plugins/clangtools/runsettingswidget.cpp +++ b/src/plugins/clangtools/runsettingswidget.cpp @@ -31,11 +31,9 @@ RunSettingsWidget::RunSettingsWidget(QWidget *parent) resize(383, 125); m_diagnosticWidget = new ClangDiagnosticConfigsSelectionWidget; - + m_preferConfigFile = new QCheckBox(Tr::tr("Prefer .clang-tidy file, if present")); m_buildBeforeAnalysis = new QCheckBox(Tr::tr("Build the project before analysis")); - m_analyzeOpenFiles = new QCheckBox(Tr::tr("Analyze open files")); - m_parallelJobsSpinBox = new QSpinBox; m_parallelJobsSpinBox->setRange(1, 32); @@ -47,6 +45,7 @@ RunSettingsWidget::RunSettingsWidget(QWidget *parent) title(Tr::tr("Run Options")), Column { m_diagnosticWidget, + m_preferConfigFile, m_buildBeforeAnalysis, m_analyzeOpenFiles, Row { Tr::tr("Parallel jobs:"), m_parallelJobsSpinBox, st }, @@ -99,6 +98,9 @@ void RunSettingsWidget::fromSettings(const RunSettings &s) connect(m_diagnosticWidget, &ClangDiagnosticConfigsSelectionWidget::changed, this, &RunSettingsWidget::changed); + m_preferConfigFile->setChecked(s.preferConfigFile()); + connect(m_preferConfigFile, &QCheckBox::toggled, this, &RunSettingsWidget::changed); + disconnect(m_buildBeforeAnalysis, 0, 0, 0); m_buildBeforeAnalysis->setToolTip(hintAboutBuildBeforeAnalysis()); m_buildBeforeAnalysis->setCheckState(s.buildBeforeAnalysis() ? Qt::Checked : Qt::Unchecked); @@ -115,13 +117,13 @@ void RunSettingsWidget::fromSettings(const RunSettings &s) connect(m_parallelJobsSpinBox, &QSpinBox::valueChanged, this, &RunSettingsWidget::changed); m_analyzeOpenFiles->setChecked(s.analyzeOpenFiles()); connect(m_analyzeOpenFiles, &QCheckBox::toggled, this, &RunSettingsWidget::changed); - } RunSettings RunSettingsWidget::toSettings() const { RunSettings s; s.setDiagnosticConfigId(m_diagnosticWidget->currentConfigId()); + s.setPreferConfigFile(m_preferConfigFile->isChecked()); s.setBuildBeforeAnalysis(m_buildBeforeAnalysis->checkState() == Qt::CheckState::Checked); s.setParallelJobs(m_parallelJobsSpinBox->value()); s.setAnalyzeOpenFiles(m_analyzeOpenFiles->checkState() == Qt::CheckState::Checked); diff --git a/src/plugins/clangtools/runsettingswidget.h b/src/plugins/clangtools/runsettingswidget.h index 532bbd4ff8c..0d2e4b645a9 100644 --- a/src/plugins/clangtools/runsettingswidget.h +++ b/src/plugins/clangtools/runsettingswidget.h @@ -37,6 +37,7 @@ signals: private: CppEditor::ClangDiagnosticConfigsSelectionWidget *m_diagnosticWidget; + QCheckBox *m_preferConfigFile; QCheckBox *m_buildBeforeAnalysis; QCheckBox *m_analyzeOpenFiles; QSpinBox *m_parallelJobsSpinBox; diff --git a/src/plugins/cppeditor/clangdiagnosticconfig.h b/src/plugins/cppeditor/clangdiagnosticconfig.h index c1d21cf7d73..3442c95db50 100644 --- a/src/plugins/cppeditor/clangdiagnosticconfig.h +++ b/src/plugins/cppeditor/clangdiagnosticconfig.h @@ -42,10 +42,8 @@ public: // Clang-Tidy enum class TidyMode { - // Disabled, // Used by Qt Creator 4.10 and below. UseCustomChecks = 1, - UseConfigFile, - UseDefaultChecks, + UseDefaultChecks = 3, }; TidyMode clangTidyMode() const; void setClangTidyMode(TidyMode mode); From 9650a2bded4990108e96a6d0d7afe7d400cb928c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 15 Mar 2023 12:54:51 +0100 Subject: [PATCH 0539/1447] Examples: Limit categories to single row and allow showing all Limit the items shown for categories to a single row (two rows for first, "featured" category), and add a "Show All" link/button in the heading, that shows all items in that category only (with a "Back" button). The "Search in Examples" input ignores categories. Change-Id: I7c8561a306ad86c3b537587621d3fd030cd08af8 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/coreplugin/welcomepagehelper.cpp | 90 ++++++++++++++++++-- src/plugins/coreplugin/welcomepagehelper.h | 19 ++++- src/plugins/qtsupport/exampleslistmodel.cpp | 24 +++--- 3 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 0e8f1211bf2..bc3afe89ee1 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -25,9 +26,11 @@ #include +using namespace Utils; + namespace Core { -using namespace Utils; +using namespace WelcomePageHelpers; static QColor themeColor(Theme::Color role) { @@ -123,6 +126,17 @@ SectionGridView::SectionGridView(QWidget *parent) : GridView(parent) {} +void SectionGridView::setMaxRows(std::optional max) +{ + m_maxRows = max; + updateGeometry(); +} + +std::optional SectionGridView::maxRows() const +{ + return m_maxRows; +} + bool SectionGridView::hasHeightForWidth() const { return true; @@ -132,7 +146,16 @@ int SectionGridView::heightForWidth(int width) const { const int columnCount = width / Core::ListItemDelegate::GridItemWidth; const int rowCount = (model()->rowCount() + columnCount - 1) / columnCount; - return rowCount * Core::ListItemDelegate::GridItemHeight; + const int maxRowCount = m_maxRows ? std::min(*m_maxRows, rowCount) : rowCount; + return maxRowCount * Core::ListItemDelegate::GridItemHeight; +} + +void SectionGridView::wheelEvent(QWheelEvent *e) +{ + if (m_maxRows) // circumvent scrolling of the list view + QWidget::wheelEvent(e); + else + GridView::wheelEvent(e); } const QSize ListModel::defaultImageSize(214, 160); @@ -646,7 +669,7 @@ SectionedGridView::SectionedGridView(QWidget *parent) auto sectionedView = new QWidget; auto layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); - layout->addStretch(); + layout->addStretch(1); sectionedView->setLayout(layout); area->setWidget(sectionedView); @@ -678,8 +701,12 @@ void SectionedGridView::setPixmapFunction(const Core::ListModel::PixmapFunction void SectionedGridView::setSearchString(const QString &searchString) { if (searchString.isEmpty()) { - // back to sectioned view - setCurrentIndex(0); + // back to previous view + m_allItemsView.reset(); + if (m_zoomedInWidget) + setCurrentWidget(m_zoomedInWidget); + else + setCurrentIndex(0); return; } if (!m_allItemsView) { @@ -711,13 +738,19 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); gridView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); gridView->setModel(model); + gridView->setMaxRows(section.maxRows); m_sectionModels.insert(section, model); const auto it = m_gridViews.insert(section, gridView); - auto sectionLabel = new QLabel(section.name); + using namespace Layouting; + auto seeAllLink = new QLabel("" + Tr::tr("Show All") + " >", this); + seeAllLink->setVisible(gridView->maxRows().has_value()); + connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); }); + QWidget *sectionLabel = Column{hr, Row{section.name, st, seeAllLink, Space(HSpacing)}}.emerge( + Layouting::WithoutMargins); m_sectionLabels.append(sectionLabel); - sectionLabel->setContentsMargins(0, Core::WelcomePageHelpers::ItemGap, 0, 0); + sectionLabel->setContentsMargins(0, ItemGap, 0, 0); sectionLabel->setFont(Core::WelcomePageHelpers::brandFont()); auto scrollArea = qobject_cast(widget(0)); auto vbox = qobject_cast(scrollArea->widget()->layout()); @@ -753,4 +786,47 @@ void SectionedGridView::clear() m_allItemsView.reset(); } +void SectionedGridView::zoomInSection(const Section §ion) +{ + auto zoomedInWidget = new QWidget(this); + auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + zoomedInWidget->setLayout(layout); + + using namespace Layouting; + auto backLink = new QLabel("< " + Tr::tr("Back") + "", zoomedInWidget); + connect(backLink, &QLabel::linkActivated, this, [this, zoomedInWidget] { + removeWidget(zoomedInWidget); + delete zoomedInWidget; + setCurrentIndex(0); + }); + QWidget *sectionLabel = Column{hr, Row{section.name, st, backLink, Space(HSpacing)}}.emerge( + Layouting::WithoutMargins); + sectionLabel->setContentsMargins(0, ItemGap, 0, 0); + sectionLabel->setFont(Core::WelcomePageHelpers::brandFont()); + + auto gridView = new GridView(zoomedInWidget); + gridView->setItemDelegate(m_itemDelegate); + gridView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + gridView->setModel(m_sectionModels.value(section)); + + layout->addWidget(sectionLabel); + layout->addWidget(gridView); + + m_zoomedInWidget = zoomedInWidget; + addWidget(zoomedInWidget); + setCurrentWidget(zoomedInWidget); +} + +Section::Section(const QString &name, int priority) + : name(name) + , priority(priority) +{} + +Section::Section(const QString &name, int priority, std::optional maxRows) + : name(name) + , priority(priority) + , maxRows(maxRows) +{} + } // namespace Core diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index cf9f438aced..8308d65311b 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -51,8 +51,16 @@ class CORE_EXPORT SectionGridView : public GridView public: explicit SectionGridView(QWidget *parent); - bool hasHeightForWidth() const; - int heightForWidth(int width) const; + void setMaxRows(std::optional max); + std::optional maxRows() const; + + bool hasHeightForWidth() const override; + int heightForWidth(int width) const override; + + void wheelEvent(QWheelEvent *e) override; + +private: + std::optional m_maxRows; }; using OptModelIndex = std::optional; @@ -165,6 +173,9 @@ private: class CORE_EXPORT Section { public: + Section(const QString &name, int priority); + Section(const QString &name, int priority, std::optional maxRows); + friend bool operator<(const Section &lhs, const Section &rhs) { if (lhs.priority < rhs.priority) @@ -179,6 +190,7 @@ public: QString name; int priority; + std::optional maxRows; }; class CORE_EXPORT SectionedGridView : public QStackedWidget @@ -196,11 +208,14 @@ public: void clear(); private: + void zoomInSection(const Section §ion); + QMap m_sectionModels; QList m_sectionLabels; QMap m_gridViews; std::unique_ptr m_allItemsModel; std::unique_ptr m_allItemsView; + QPointer m_zoomedInWidget; Core::ListModel::PixmapFunction m_pixmapFunction; QAbstractItemDelegate *m_itemDelegate = nullptr; }; diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index c567f992e41..33817e08c40 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -329,7 +329,7 @@ static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) return first->name.compare(second->name, Qt::CaseInsensitive) < 0; } -static QList>> getCategories( +static QList>> getCategories( const QList &items) { static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples"); @@ -345,7 +345,7 @@ static QList>> getCategories( other.append(item); } } - QList>> categories; + QList>> categories; if (categoryMap.isEmpty()) { // The example set doesn't define categories. Consider the "highlighted" ones as "featured" QList featured; @@ -354,15 +354,19 @@ static QList>> getCategories( return i->isHighlighted; }); if (!featured.isEmpty()) - categories.append({Tr::tr("Featured", "Category for highlighted examples"), featured}); + categories.append( + {{Tr::tr("Featured", "Category for highlighted examples"), 0}, featured}); if (!allOther.isEmpty()) - categories.append({otherDisplayName, allOther}); + categories.append({{otherDisplayName, 1}, allOther}); } else { + int index = 0; const auto end = categoryMap.constKeyValueEnd(); - for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) - categories.append(*it); + for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) { + categories.append({{it->first, index, /*maxRows=*/index == 0 ? 2 : 1}, it->second}); + ++index; + } if (!other.isEmpty()) - categories.append({otherDisplayName, other}); + categories.append({{otherDisplayName, index, /*maxRows=*/1}, other}); } const auto end = categories.end(); for (auto it = categories.begin(); it != end; ++it) @@ -414,9 +418,9 @@ void ExamplesViewController::updateExamples() } } - const QList>> sections = getCategories(items); + const QList>> sections = getCategories(items); for (int i = 0; i < sections.size(); ++i) { - m_view->addSection({sections.at(i).first, i}, + m_view->addSection(sections.at(i).first, static_container_cast(sections.at(i).second)); } } @@ -519,7 +523,7 @@ QStringList ExampleSetModel::exampleSources(QString *examplesInstallPath, QStrin const QStringList demosPattern(QLatin1String("demos-manifest.xml")); QFileInfoList fis; const QFileInfoList subDirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); - for (QFileInfo subDir : subDirs) { + for (const QFileInfo &subDir : subDirs) { fis << QDir(subDir.absoluteFilePath()).entryInfoList(examplesPattern); fis << QDir(subDir.absoluteFilePath()).entryInfoList(demosPattern); } From b1415a0ea58e0860c790b1b5ff5fbd3d4bfdd87a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 13 Apr 2023 14:07:21 +0200 Subject: [PATCH 0540/1447] TextEditor: reuse resetReloadMarks in documentReloaded Change-Id: I41721e8c08fa70bf713154d7096753e0f49afb8c Reviewed-by: Eike Ziller --- src/plugins/texteditor/textdocumentlayout.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/textdocumentlayout.cpp b/src/plugins/texteditor/textdocumentlayout.cpp index f40290b393d..703f9563bf1 100644 --- a/src/plugins/texteditor/textdocumentlayout.cpp +++ b/src/plugins/texteditor/textdocumentlayout.cpp @@ -674,8 +674,9 @@ void TextDocumentLayout::documentAboutToReload() void TextDocumentLayout::documentReloaded(TextDocument *baseTextDocument) { - for (TextMark *mark : std::as_const(m_reloadMarks)) { - mark->setDeleteCallback({}); + const TextMarks marks = m_reloadMarks; + resetReloadMarks(); + for (TextMark *mark : marks) { int blockNumber = mark->lineNumber() - 1; QTextBlock block = document()->findBlockByNumber(blockNumber); if (block.isValid()) { @@ -689,7 +690,6 @@ void TextDocumentLayout::documentReloaded(TextDocument *baseTextDocument) mark->removedFromEditor(); } } - m_reloadMarks.clear(); requestUpdate(); } From e2bccfde24d396afa41500c92c442f9fd916f15e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 14 Apr 2023 09:59:44 +0200 Subject: [PATCH 0541/1447] DocumentSymbolCache: Don't schedule duplicate requests Avoid scheduling a new request for the uri when a request for the same uri is currently running. Change-Id: Iac056b275c62e8640bf43a0ec9b6b6561b44eaed Reviewed-by: Reviewed-by: David Schulz --- src/plugins/languageclient/documentsymbolcache.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/languageclient/documentsymbolcache.cpp b/src/plugins/languageclient/documentsymbolcache.cpp index 113b22695a5..b08e70d2911 100644 --- a/src/plugins/languageclient/documentsymbolcache.cpp +++ b/src/plugins/languageclient/documentsymbolcache.cpp @@ -40,6 +40,8 @@ DocumentSymbolCache::DocumentSymbolCache(Client *client) void DocumentSymbolCache::requestSymbols(const DocumentUri &uri, Schedule schedule) { + if (m_runningRequests.contains(uri)) + return; m_compressedUris.insert(uri); switch (schedule) { case Schedule::Now: From 15a06b77c01c3bcbbc69ca0e80035e0c3824d62c Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Fri, 14 Apr 2023 11:38:25 +0200 Subject: [PATCH 0542/1447] Fix tst_qml_reformatter auto test Add source location to pragma library writer so that the comments before .pragma line are also written. Fix tst_qml_reformatter by skipping the blankline comparisons. Line by line comparison with the non-formatted code is not a good idea to test reformatting. Ideally test should have compared the formatted file with the original one character wise, yet it is not worth changing into that at this point. Amends 0ce57fcf5e90f8bf8cfbe681f2954a0c1ef0e945 Change-Id: I39bcee2c881e1a0928c17ebb45aa1c85e6cf3b99 Reviewed-by: Qt CI Bot Reviewed-by: Jarek Kobus Reviewed-by: Eike Ziller --- src/libs/qmljs/qmljsreformatter.cpp | 6 +++--- tests/auto/qml/reformatter/tst_reformatter.cpp | 14 ++------------ 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp index 097119eb270..bad58e414ca 100644 --- a/src/libs/qmljs/qmljsreformatter.cpp +++ b/src/libs/qmljs/qmljsreformatter.cpp @@ -101,16 +101,16 @@ public: _hadEmptyLine = false; _binaryExpDepth = 0; - + const QString &source = _doc->source(); // emit directives if (_doc->bind()->isJsLibrary()) { - out(QLatin1String(".pragma library")); + const QLatin1String pragmaLine(".pragma library"); + out(pragmaLine, SourceLocation(source.indexOf(".pragma"), pragmaLine.length())); newLine(); } const QList &directives = _doc->jsDirectives(); for (const auto &d: directives) { quint32 line = 0; - const QString &source = _doc->source(); int i = -1; while (++line < d.startLine) i = source.indexOf(QChar('\n'), i + 1); diff --git a/tests/auto/qml/reformatter/tst_reformatter.cpp b/tests/auto/qml/reformatter/tst_reformatter.cpp index 42d98e02bed..68b192fa600 100644 --- a/tests/auto/qml/reformatter/tst_reformatter.cpp +++ b/tests/auto/qml/reformatter/tst_reformatter.cpp @@ -68,25 +68,15 @@ void tst_Reformatter::test() QString rewritten = reformat(doc); - QStringList sourceLines = source.split(QLatin1Char('\n')); - QStringList newLines = rewritten.split(QLatin1Char('\n')); + QStringList sourceLines = source.split(QLatin1Char('\n'), Qt::SkipEmptyParts); + QStringList newLines = rewritten.split(QLatin1Char('\n'), Qt::SkipEmptyParts); // compare line by line int commonLines = qMin(newLines.size(), sourceLines.size()); - bool insideMultiLineComment = false; for (int i = 0; i < commonLines; ++i) { // names intentional to make 'Actual (sourceLine): ...\nExpected (newLinee): ...' line up const QString &sourceLine = sourceLines.at(i); const QString &newLinee = newLines.at(i); - if (!insideMultiLineComment && sourceLine.trimmed().startsWith("/*")) { - insideMultiLineComment = true; - sourceLines.insert(i, "\n"); - continue; - } - if (sourceLine.trimmed().endsWith("*/")) - insideMultiLineComment = false; - if (sourceLine.trimmed().isEmpty() && newLinee.trimmed().isEmpty()) - continue; bool fail = !QCOMPARE_NOEXIT(newLinee, sourceLine); if (fail) { qDebug() << "in line" << (i + 1); From 6932c6ca230ee3805ef9a022812bc3de19ddc8f4 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 14 Apr 2023 16:27:13 +0200 Subject: [PATCH 0543/1447] Qnx: Fix Abi detection for remote toolchains We were suddenly ending up looking into the local file system. Change-Id: I4911206e6d29f10a9dfaa9bc97307b28e383c14c Reviewed-by: Christian Kandeler --- src/plugins/qnx/qnxtoolchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp index 773efc0c740..187c507da49 100644 --- a/src/plugins/qnx/qnxtoolchain.cpp +++ b/src/plugins/qnx/qnxtoolchain.cpp @@ -54,7 +54,7 @@ static Abis detectTargetAbis(const FilePath &sdpPath) const EnvironmentItems environment = QnxUtils::qnxEnvironment(sdpPath); for (const EnvironmentItem &item : environment) { if (item.name == QLatin1String("QNX_TARGET")) - qnxTarget = FilePath::fromString(item.value); + qnxTarget = sdpPath.withNewPath(item.value); } } From cbaeee89d6c6584a2b2fa6ef53176794b5dd3ac8 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Thu, 6 Apr 2023 14:20:01 +0200 Subject: [PATCH 0544/1447] Debugger: DAPEngine improve breakpoints handling - Added proper "Insert" breakpoint - Added proper "Remove" breakpoint - Fixed errors with engine states after pause and continue Change-Id: Icbe1b4cf549cee633809d0a1c9ab19dbf877dbf0 Reviewed-by: Reviewed-by: hjk --- src/plugins/debugger/dap/dapengine.cpp | 157 ++++++++++++++++++------- src/plugins/debugger/dap/dapengine.h | 1 + 2 files changed, 114 insertions(+), 44 deletions(-) diff --git a/src/plugins/debugger/dap/dapengine.cpp b/src/plugins/debugger/dap/dapengine.cpp index 6efe29d37d4..4b1a1198736 100644 --- a/src/plugins/debugger/dap/dapengine.cpp +++ b/src/plugins/debugger/dap/dapengine.cpp @@ -50,7 +50,7 @@ DapEngine::DapEngine() setDebuggerName("DAP"); } -void DapEngine::executeDebuggerCommand(const QString &command) +void DapEngine::executeDebuggerCommand(const QString &/*command*/) { QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); // if (state() == DebuggerNotReady) { @@ -183,9 +183,6 @@ void DapEngine::handleDabLaunch() QJsonObject{ {"noDebug", false}, {"program", runParameters().inferior.command.executable().path()}, -// {"args", runParameters().inferior.command.arguments()}, -// {"cwd", runParameters().inferior.workingDirectory}, -// {"env", QJsonObject::fromVariantMap(runParameters().inferior.environment.toStringMap())} {"__restart", ""} }}}); qDebug() << "handleDabLaunch"; @@ -193,24 +190,22 @@ void DapEngine::handleDabLaunch() void DapEngine::interruptInferior() { - QString error; - postDirectCommand({{"command", "pause"}, {"type", "request"}}); - - qDebug() << "DapEngine::interruptInferior()"; - - -// interruptProcess(m_proc.processId(), GdbEngineType, &error); -// notifyInferiorExited(); - notifyInferiorStopOk(); } void DapEngine::executeStepIn(bool) { notifyInferiorRunRequested(); + +// postDirectCommand({{"command", "stepIn"}, +// {"type", "request"}, +// {"arguments", +// QJsonObject{ +// {"threadId", 1}, // The ID of the client using this adapter. +// }}}); + notifyInferiorRunOk(); -// postDirectCommand("step"); } void DapEngine::executeStepOut() @@ -229,19 +224,13 @@ void DapEngine::executeStepOver(bool) void DapEngine::continueInferior() { + notifyInferiorRunRequested(); postDirectCommand({{"command", "continue"}, {"type", "request"}, {"arguments", QJsonObject{ {"threadId", 1}, // The ID of the client using this adapter. }}}); - - qDebug() << "continueInferior"; - // notifyInferiorRunRequested(); - // notifyInferiorRunOk(); - - // Callback will be triggered e.g. when breakpoint is hit. -// postDirectCommand("continue"); } void DapEngine::executeRunToLine(const ContextData &data) @@ -284,36 +273,57 @@ bool DapEngine::acceptsBreakpoint(const BreakpointParameters &) const return true; // FIXME: Too bold. } +static QJsonObject createBreakpoint(const Breakpoint &breakpoint) +{ + const BreakpointParameters ¶ms = breakpoint->requestedParameters(); + + if (params.fileName.isEmpty()) + return QJsonObject(); + + QJsonObject bp; + bp["line"] = params.lineNumber; + bp["source"] = QJsonObject{{"name", params.fileName.fileName()}, + {"path", params.fileName.path()}}; + return bp; +} + + void DapEngine::insertBreakpoint(const Breakpoint &bp) { QTC_ASSERT(bp, return); QTC_CHECK(bp->state() == BreakpointInsertionRequested); notifyBreakpointInsertProceeding(bp); - QString loc; const BreakpointParameters ¶ms = bp->requestedParameters(); - if (params.type == BreakpointByFunction) - loc = params.functionName; - else - loc = params.fileName.toString() + ':' + QString::number(params.lineNumber); + bp->setResponseId(QString::number(m_nextBreakpointId++)); + + QJsonArray breakpoints; + for (const auto &breakpoint : breakHandler()->breakpoints()) { + QJsonObject jsonBp = createBreakpoint(breakpoint); + if (!jsonBp.isEmpty() + && params.fileName.path() == jsonBp["source"].toObject()["path"].toString()) { + breakpoints.append(jsonBp); + } + } postDirectCommand( {{"command", "setBreakpoints"}, {"type", "request"}, {"arguments", - QJsonObject{{"source", QJsonObject{{"path", params.fileName.toString()}}}, - {"breakpoints", - QJsonArray{QJsonObject{{"id", 1}, {"line", params.lineNumber}}}} + QJsonObject{{"source", QJsonObject{{"path", params.fileName.path()}}}, + {"breakpoints", breakpoints} }}}); + + qDebug() << "insertBreakpoint" << bp->modelId() << bp->responseId(); } void DapEngine::updateBreakpoint(const Breakpoint &bp) { + notifyBreakpointChangeProceeding(bp); // QTC_ASSERT(bp, return); // const BreakpointState state = bp->state(); // if (QTC_GUARD(state == BreakpointUpdateRequested)) -// notifyBreakpointChangeProceeding(bp); // if (bp->responseId().isEmpty()) // FIXME postpone update somehow (QTimer::singleShot?) // return; @@ -334,16 +344,25 @@ void DapEngine::removeBreakpoint(const Breakpoint &bp) { QTC_ASSERT(bp, return); QTC_CHECK(bp->state() == BreakpointRemoveRequested); - // notifyBreakpointRemoveProceeding(bp); + notifyBreakpointRemoveProceeding(bp); + const BreakpointParameters ¶ms = bp->requestedParameters(); + + QJsonArray breakpoints; + for (const auto &breakpoint : breakHandler()->breakpoints()) + if (breakpoint->responseId() != bp->responseId() + && params.fileName == breakpoint->requestedParameters().fileName) { + QJsonObject jsonBp = createBreakpoint(breakpoint); + breakpoints.append(jsonBp); + } + postDirectCommand({{"command", "setBreakpoints"}, {"type", "request"}, {"arguments", - QJsonObject{{"source", QJsonObject{{"path", params.fileName.toString()}}}, - {"breakpoints", QJsonArray{}}}}}); - qDebug() << "removeBreakpoint"; + QJsonObject{{"source", QJsonObject{{"path", params.fileName.path()}}}, + {"breakpoints", breakpoints}}}}); -// notifyBreakpointRemoveOk(bp); + qDebug() << "removeBreakpoint" << bp->modelId() << bp->responseId(); } void DapEngine::loadSymbols(const Utils::FilePath &/*moduleName*/) @@ -431,7 +450,7 @@ bool DapEngine::canHandleToolTip(const DebuggerToolTipContext &) const return state() == InferiorStopOk; } -void DapEngine::assignValueInDebugger(WatchItem *, const QString &expression, const QVariant &value) +void DapEngine::assignValueInDebugger(WatchItem *, const QString &/*expression*/, const QVariant &/*value*/) { //DebuggerCommand cmd("assignValue"); //cmd.arg("expression", expression); @@ -555,8 +574,6 @@ void DapEngine::handleOutput(const QJsonDocument &data) showMessage("configurationDone", LogDebug); qDebug() << "configurationDone success"; notifyInferiorRunOk(); - - claimInitialBreakpoints(); return; } @@ -571,8 +588,9 @@ void DapEngine::handleOutput(const QJsonDocument &data) if (type == "event") { const QString event = ob.value("event").toString(); + const QJsonObject body = ob.value("body").toObject(); + if (event == "output") { - const QJsonObject body = ob.value("body").toObject(); const QString category = body.value("category").toString(); const QString output = body.value("output").toString(); if (category == "stdout") @@ -599,10 +617,61 @@ void DapEngine::handleOutput(const QJsonDocument &data) } if (event == "stopped") { - notifyInferiorSpontaneousStop(); + showMessage(event, LogDebug); + if (body.value("reason").toString() == "breakpoint") { + QString id = QString::number(body.value("hitBreakpointIds").toArray().first().toInteger()); + const BreakpointParameters ¶ms + = breakHandler()->findBreakpointByResponseId(id)->requestedParameters(); + gotoLocation(Location(params.fileName, params.lineNumber)); + } + + if (state() == InferiorStopRequested) + notifyInferiorStopOk(); + else + notifyInferiorSpontaneousStop(); return; } + if (event == "thread") { + showMessage(event, LogDebug); + if (body.value("reason").toString() == "started" && body.value("threadId").toInt() == 1) + claimInitialBreakpoints(); + return; + } + + if (event == "breakpoint") { + showMessage(event, LogDebug); + QJsonObject breakpoint = body.value("breakpoint").toObject(); + Breakpoint bp = breakHandler()->findBreakpointByResponseId( + QString::number(breakpoint.value("id").toInt())); + qDebug() << "breakpoint id :" << breakpoint.value("id").toInt(); + + if (body.value("reason").toString() == "new") { + if (breakpoint.value("verified").toBool()) { +// bp->setPending(false); + notifyBreakpointInsertOk(bp); + qDebug() << "breakpoint inserted"; + } else { + notifyBreakpointInsertFailed(bp); + qDebug() << "breakpoint insertion failed"; + } + return; + } + + if (body.value("reason").toString() == "removed") { + if (breakpoint.value("verified").toBool()) { + notifyBreakpointRemoveOk(bp); + qDebug() << "breakpoint removed"; + } else { + notifyBreakpointRemoveFailed(bp); + qDebug() << "breakpoint remove failed"; + } + return; + } + return; + } + + showMessage("UNKNOWN EVENT:" + event); return; } @@ -686,10 +755,10 @@ void DapEngine::claimInitialBreakpoints() { BreakpointManager::claimBreakpointsForEngine(this); qDebug() << "claimInitialBreakpoints"; - const Breakpoints bps = breakHandler()->breakpoints(); - for (const Breakpoint &bp : bps) - qDebug() << "breakpoit: " << bp->fileName() << bp->lineNumber(); - qDebug() << "claimInitialBreakpoints end"; +// const Breakpoints bps = breakHandler()->breakpoints(); +// for (const Breakpoint &bp : bps) +// qDebug() << "breakpoit: " << bp->fileName() << bp->lineNumber(); +// qDebug() << "claimInitialBreakpoints end"; // const DebuggerRunParameters &rp = runParameters(); // if (rp.startMode != AttachToCore) { diff --git a/src/plugins/debugger/dap/dapengine.h b/src/plugins/debugger/dap/dapengine.h index 045cb3044a2..d4dca0d2f73 100644 --- a/src/plugins/debugger/dap/dapengine.h +++ b/src/plugins/debugger/dap/dapengine.h @@ -92,6 +92,7 @@ private: QByteArray m_inbuffer; Utils::QtcProcess m_proc; + int m_nextBreakpointId = 1; }; } // Debugger::Internal From 2abe6bbe2c0d0707a533f826e903fa7a523fdce9 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 14 Apr 2023 14:22:00 +0200 Subject: [PATCH 0545/1447] CMakePM: Fix passing library search paths Amends 305ccfe259d. Change-Id: Icd08697720224e84cb4ad282d21191f80728865e Reviewed-by: hjk --- src/plugins/cmakeprojectmanager/fileapidataextractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index cab07381ccd..cf60c0b7dcf 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -264,7 +264,7 @@ QList generateBuildTargets(const PreprocessedData &input, continue; const FilePath buildDir = haveLibrariesRelativeToBuildDirectory ? buildDirectory : currentBuildDir; - FilePath tmp = buildDir.resolvePath(buildDir.withNewPath(part)); + FilePath tmp = buildDir.resolvePath(part); if (f.role == "libraries") tmp = tmp.parentDir(); From 7ab0fd56aea0ee43fc0ad36205b0b6f6823605c3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 17:59:27 +0200 Subject: [PATCH 0546/1447] RunExtensions: Move onResultReady and onFinished into asynctask.h Change-Id: I96dbf5b0253251224ae678172cd5fca12b34326a Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- src/libs/qmljs/qmljsplugindumper.cpp | 1 - src/libs/utils/asynctask.h | 70 +++++++++++++++++ src/libs/utils/runextensions.h | 75 ------------------- src/plugins/android/androidrunnerworker.cpp | 1 - .../android/androidsdkmanagerwidget.cpp | 2 +- .../cmakeprojectmanager/fileapireader.cpp | 1 - .../coreplugin/locator/locatorwidget.cpp | 1 + .../coreplugin/plugininstallwizard.cpp | 1 - .../progressmanager/progressmanager.cpp | 2 +- src/plugins/git/gitgrep.cpp | 1 - src/plugins/git/gitplugin.cpp | 2 +- src/plugins/haskell/haskellproject.cpp | 1 - src/plugins/help/helpmanager.cpp | 1 - src/plugins/ios/createsimulatordialog.cpp | 2 +- src/plugins/ios/iossettingswidget.cpp | 2 +- src/plugins/ios/iostoolhandler.cpp | 1 - src/plugins/ios/simulatorcontrol.cpp | 1 - src/plugins/ios/simulatorinfomodel.cpp | 2 +- .../mesonprojectparser.cpp | 1 - .../qmakeprojectmanager/qmakeproject.cpp | 1 - .../auto/runextensions/tst_runextensions.cpp | 1 + 21 files changed, 78 insertions(+), 92 deletions(-) diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index 20736803d27..9e2261014f0 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/src/libs/utils/asynctask.h b/src/libs/utils/asynctask.h index a600a14b247..d7c51a66fae 100644 --- a/src/libs/utils/asynctask.h +++ b/src/libs/utils/asynctask.h @@ -45,6 +45,76 @@ auto asyncRun(Function &&function, Args &&...args) std::forward(function), std::forward(args)...); } +/*! + Adds a handler for when a result is ready. + This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions + or create a QFutureWatcher already for other reasons. +*/ +template +const QFuture &onResultReady(const QFuture &future, R *receiver, void(R::*member)(const T &)) +{ + auto watcher = new QFutureWatcher(); + QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, receiver, [=](int index) { + (receiver->*member)(watcher->future().resultAt(index)); + }); + watcher->setFuture(future); + return future; +} + +/*! + Adds a handler for when a result is ready. The guard object determines the lifetime of + the connection. + This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions + or create a QFutureWatcher already for other reasons. +*/ +template +const QFuture &onResultReady(const QFuture &future, QObject *guard, Function f) +{ + auto watcher = new QFutureWatcher(); + QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, guard, [f, watcher](int index) { + f(watcher->future().resultAt(index)); + }); + watcher->setFuture(future); + return future; +} + +/*! + Adds a handler for when the future is finished. + This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions + or create a QFutureWatcher already for other reasons. +*/ +template +const QFuture &onFinished(const QFuture &future, + R *receiver, void (R::*member)(const QFuture &)) +{ + auto watcher = new QFutureWatcher(); + QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QFutureWatcherBase::finished, receiver, + [=] { (receiver->*member)(watcher->future()); }); + watcher->setFuture(future); + return future; +} + +/*! + Adds a handler for when the future is finished. The guard object determines the lifetime of + the connection. + This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions + or create a QFutureWatcher already for other reasons. +*/ +template +const QFuture &onFinished(const QFuture &future, QObject *guard, Function f) +{ + auto watcher = new QFutureWatcher(); + QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QFutureWatcherBase::finished, guard, [f, watcher] { + f(watcher->future()); + }); + watcher->setFuture(future); + return future; +} + class QTCREATOR_UTILS_EXPORT AsyncTaskBase : public QObject { Q_OBJECT diff --git a/src/libs/utils/runextensions.h b/src/libs/utils/runextensions.h index 3e0b7afb952..6505b12a9cf 100644 --- a/src/libs/utils/runextensions.h +++ b/src/libs/utils/runextensions.h @@ -476,79 +476,4 @@ runAsync(QThreadPool *pool, Function &&function, Args&&... args) std::forward(args)...); } - -/*! - Adds a handler for when a result is ready. - This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions - or create a QFutureWatcher already for other reasons. -*/ -template -const QFuture &onResultReady(const QFuture &future, R *receiver, void(R::*member)(const T &)) -{ - auto watcher = new QFutureWatcher(); - QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); - QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, receiver, - [receiver, member, watcher](int index) { - (receiver->*member)(watcher->future().resultAt(index)); - }); - watcher->setFuture(future); - return future; -} - -/*! - Adds a handler for when a result is ready. The guard object determines the lifetime of - the connection. - This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions - or create a QFutureWatcher already for other reasons. -*/ -template -const QFuture &onResultReady(const QFuture &future, QObject *guard, Function f) -{ - auto watcher = new QFutureWatcher(); - QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); - QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, guard, [f, watcher](int index) { - f(watcher->future().resultAt(index)); - }); - watcher->setFuture(future); - return future; -} - -/*! - Adds a handler for when the future is finished. - This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions - or create a QFutureWatcher already for other reasons. -*/ -template -const QFuture &onFinished(const QFuture &future, - R *receiver, - void (R::*member)(const QFuture &)) -{ - auto watcher = new QFutureWatcher(); - QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); - QObject::connect(watcher, - &QFutureWatcherBase::finished, - receiver, - [receiver, member, watcher] { (receiver->*member)(watcher->future()); }); - watcher->setFuture(future); - return future; -} - -/*! - Adds a handler for when the future is finished. The guard object determines the lifetime of - the connection. - This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions - or create a QFutureWatcher already for other reasons. -*/ -template -const QFuture &onFinished(const QFuture &future, QObject *guard, Function f) -{ - auto watcher = new QFutureWatcher(); - QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); - QObject::connect(watcher, &QFutureWatcherBase::finished, guard, [f, watcher] { - f(watcher->future()); - }); - watcher->setFuture(future); - return future; -} - } // namespace Utils diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 3ec9457ee37..c27965a9508 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index 56f32833c86..81098b776aa 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -9,10 +9,10 @@ #include +#include #include #include #include -#include #include #include diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 6167ad84278..2d8d4c5345c 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index ba717ea0f98..7bb381ac01b 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -14,6 +14,7 @@ #include "../modemanager.h" #include +#include #include #include #include diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index 3587d211068..02f0e15eb28 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.cpp b/src/plugins/coreplugin/progressmanager/progressmanager.cpp index 18cc2f6f34f..969579aafd3 100644 --- a/src/plugins/coreplugin/progressmanager/progressmanager.cpp +++ b/src/plugins/coreplugin/progressmanager/progressmanager.cpp @@ -109,7 +109,7 @@ namespace Core { start a task concurrently in a different thread. QtConcurrent has several different functions to run e.g. a class function in a different thread. Qt Creator itself - adds a few more in \c{src/libs/qtconcurrent/runextensions.h}. + adds a few more in \c{src/libs/utils/asynctask.h}. The QtConcurrent functions to run a concurrent task return a \c QFuture object. This is what you want to give the ProgressManager in the addTask() function. diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 9d4aeec6980..7d5dc7fa749 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 9729dbe4240..935fa5deb79 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -42,12 +42,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/src/plugins/haskell/haskellproject.cpp b/src/plugins/haskell/haskellproject.cpp index 916632c5dc6..f19840a67f5 100644 --- a/src/plugins/haskell/haskellproject.cpp +++ b/src/plugins/haskell/haskellproject.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/help/helpmanager.cpp b/src/plugins/help/helpmanager.cpp index 69fe0dabf9e..f62aa65f352 100644 --- a/src/plugins/help/helpmanager.cpp +++ b/src/plugins/help/helpmanager.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/ios/createsimulatordialog.cpp b/src/plugins/ios/createsimulatordialog.cpp index 5dce52221eb..3eb4c2cc40d 100644 --- a/src/plugins/ios/createsimulatordialog.cpp +++ b/src/plugins/ios/createsimulatordialog.cpp @@ -7,8 +7,8 @@ #include "simulatorcontrol.h" #include +#include #include -#include #include #include diff --git a/src/plugins/ios/iossettingswidget.cpp b/src/plugins/ios/iossettingswidget.cpp index eee8b08efc8..2d13c4952ab 100644 --- a/src/plugins/ios/iossettingswidget.cpp +++ b/src/plugins/ios/iossettingswidget.cpp @@ -12,9 +12,9 @@ #include "simulatoroperationdialog.h" #include +#include #include #include -#include #include #include diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 5db9b808a88..08e937d5ccf 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index 59970b649c1..fe015b18815 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #ifdef Q_OS_MAC #include diff --git a/src/plugins/ios/simulatorinfomodel.cpp b/src/plugins/ios/simulatorinfomodel.cpp index 8c79d161da9..4db3994f4b9 100644 --- a/src/plugins/ios/simulatorinfomodel.cpp +++ b/src/plugins/ios/simulatorinfomodel.cpp @@ -6,7 +6,7 @@ #include "iostr.h" #include -#include +#include #include diff --git a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp index 96b5fa9cb7b..6f8ce162ed7 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp +++ b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index c12827b6b43..da68b010d58 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -50,7 +50,6 @@ #include #include #include -#include #include #include diff --git a/tests/auto/runextensions/tst_runextensions.cpp b/tests/auto/runextensions/tst_runextensions.cpp index d9b989582ce..16f5642c942 100644 --- a/tests/auto/runextensions/tst_runextensions.cpp +++ b/tests/auto/runextensions/tst_runextensions.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include #include #include From 962888cb02f0b851d6c9945f96f71298f1be7dda Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 18:52:33 +0200 Subject: [PATCH 0547/1447] CommandLocator: Use Acceptor for LocatorFilterEntry Change-Id: I965cf7117d882afe4ac60df7d16dc67d4dac3891 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Orgad Shaneh --- .../coreplugin/locator/commandlocator.cpp | 34 +++++++------------ .../coreplugin/locator/commandlocator.h | 3 -- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 387cae9fef6..9c644f4f998 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -17,7 +17,7 @@ namespace Core { struct CommandLocatorPrivate { QList commands; - QList> commandsData; + QList> commandsData; }; /*! @@ -61,7 +61,7 @@ void CommandLocator::prepareSearch(const QString &entry) continue; QAction *action = command->action(); if (action && action->isEnabled()) - d->commandsData.append({i, action->text()}); + d->commandsData.append({action, action->text()}); } } @@ -77,8 +77,17 @@ QList CommandLocator::matchesFor(QFutureInterface= 0) { - LocatorFilterEntry filterEntry(this, text); - filterEntry.internalData = QVariant(pair.first); + QAction *action = pair.first; + LocatorFilterEntry filterEntry; + filterEntry.displayName = text; + filterEntry.acceptor = [action] { + // avoid nested stack trace and blocking locator by delayed triggering + QMetaObject::invokeMethod(action, [action] { + if (action->isEnabled()) + action->trigger(); + }, Qt::QueuedConnection); + return AcceptResult(); + }; filterEntry.highlightInfo = {index, int(entry.length())}; if (index == 0) @@ -91,21 +100,4 @@ QList CommandLocator::matchesFor(QFutureInterface= 0 && index < d->commands.size(), return); - QAction *action = d->commands.at(index)->action(); - // avoid nested stack trace and blocking locator by delayed triggering - QMetaObject::invokeMethod(action, [action] { - if (action->isEnabled()) - action->trigger(); - }, Qt::QueuedConnection); -} - } // namespace Core diff --git a/src/plugins/coreplugin/locator/commandlocator.h b/src/plugins/coreplugin/locator/commandlocator.h index 8199661bed6..e47fbde5c41 100644 --- a/src/plugins/coreplugin/locator/commandlocator.h +++ b/src/plugins/coreplugin/locator/commandlocator.h @@ -26,9 +26,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: CommandLocatorPrivate *d = nullptr; }; From 837967a77a2cf2ba536c5bc06cff15644acc4425 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 18:55:16 +0200 Subject: [PATCH 0548/1447] tst_RunExtensions: Move onResultReady test into tst_AsyncTask Change-Id: I73e2cc62be207adbfb2a4e4ce1367140986cc8b3 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../auto/runextensions/tst_runextensions.cpp | 61 ------------------- tests/auto/utils/asynctask/tst_asynctask.cpp | 60 ++++++++++++++++++ 2 files changed, 60 insertions(+), 61 deletions(-) diff --git a/tests/auto/runextensions/tst_runextensions.cpp b/tests/auto/runextensions/tst_runextensions.cpp index 16f5642c942..4ffee270025 100644 --- a/tests/auto/runextensions/tst_runextensions.cpp +++ b/tests/auto/runextensions/tst_runextensions.cpp @@ -1,7 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include #include #include @@ -23,7 +22,6 @@ private slots: void threadPriority(); void runAsyncNoFutureInterface(); void crefFunction(); - void onResultReady(); }; void report3(QFutureInterface &fi) @@ -537,65 +535,6 @@ void tst_RunExtensions::crefFunction() QCOMPARE(value, true); } -class ObjWithProperty : public QObject -{ - Q_OBJECT - -public slots: - void setValue(const QString &s) - { - value = s; - } - -public: - QString value; -}; - -void tst_RunExtensions::onResultReady() -{ - { // lambda - QObject context; - QFuture f = Utils::runAsync([](QFutureInterface &fi) { - fi.reportResult("Hi"); - fi.reportResult("there"); - }); - int count = 0; - QString res; - Utils::onResultReady(f, &context, [&count, &res](const QString &s) { - ++count; - res = s; - }); - f.waitForFinished(); - QCoreApplication::processEvents(); - QCOMPARE(count, 2); - QCOMPARE(res, QString("there")); - } - { // lambda with guard - QFuture f = Utils::runAsync([](QFutureInterface &fi) { - fi.reportResult("Hi"); - fi.reportResult("there"); - }); - int count = 0; - ObjWithProperty obj; - Utils::onResultReady(f, &obj, [&count, &obj](const QString &s) { - ++count; - obj.setValue(s); - }); - f.waitForFinished(); - QCoreApplication::processEvents(); - QCOMPARE(count, 2); - QCOMPARE(obj.value, QString("there")); - } - { // member - QFuture f = Utils::runAsync([]() { return QString("Hi"); }); - ObjWithProperty obj; - Utils::onResultReady(f, &obj, &ObjWithProperty::setValue); - f.waitForFinished(); - QCoreApplication::processEvents(); - QCOMPARE(obj.value, QString("Hi")); - } -} - QTEST_GUILESS_MAIN(tst_RunExtensions) #include "tst_runextensions.moc" diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/asynctask/tst_asynctask.cpp index 67a291172a1..5118b5555af 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/asynctask/tst_asynctask.cpp @@ -15,6 +15,7 @@ class tst_AsyncTask : public QObject private slots: void runAsync(); void crefFunction(); + void onResultReady(); void futureSynchonizer(); void taskTree(); void mapReduce_data(); @@ -326,6 +327,65 @@ void tst_AsyncTask::crefFunction() QList({0, 2, 1})); } +class ObjWithProperty : public QObject +{ + Q_OBJECT + +public slots: + void setValue(const QString &s) + { + value = s; + } + +public: + QString value; +}; + +void tst_AsyncTask::onResultReady() +{ + { // lambda + QObject context; + QFuture f = Utils::asyncRun([](QPromise &fi) { + fi.addResult("Hi"); + fi.addResult("there"); + }); + int count = 0; + QString res; + Utils::onResultReady(f, &context, [&count, &res](const QString &s) { + ++count; + res = s; + }); + f.waitForFinished(); + QCoreApplication::processEvents(); + QCOMPARE(count, 2); + QCOMPARE(res, QString("there")); + } + { // lambda with guard + QFuture f = Utils::asyncRun([](QPromise &fi) { + fi.addResult("Hi"); + fi.addResult("there"); + }); + int count = 0; + ObjWithProperty obj; + Utils::onResultReady(f, &obj, [&count, &obj](const QString &s) { + ++count; + obj.setValue(s); + }); + f.waitForFinished(); + QCoreApplication::processEvents(); + QCOMPARE(count, 2); + QCOMPARE(obj.value, QString("there")); + } + { // member + QFuture f = Utils::asyncRun([] { return QString("Hi"); }); + ObjWithProperty obj; + Utils::onResultReady(f, &obj, &ObjWithProperty::setValue); + f.waitForFinished(); + QCoreApplication::processEvents(); + QCOMPARE(obj.value, QString("Hi")); + } +} + void tst_AsyncTask::futureSynchonizer() { auto lambda = [](QPromise &promise) { From 20a4954cbdb82861ba9ebb5ebe5030f5b5bac976 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 09:16:36 +0000 Subject: [PATCH 0549/1447] Revert "CommandLocator: Use Acceptor for LocatorFilterEntry" This reverts commit 962888cb02f0b851d6c9945f96f71298f1be7dda. Reason for revert: Applied too early and produced a conflict Change-Id: I98a2895a81196b61cf7020a187d3740be231f671 Reviewed-by: Jarek Kobus --- .../coreplugin/locator/commandlocator.cpp | 34 ++++++++++++------- .../coreplugin/locator/commandlocator.h | 3 ++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 9c644f4f998..387cae9fef6 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -17,7 +17,7 @@ namespace Core { struct CommandLocatorPrivate { QList commands; - QList> commandsData; + QList> commandsData; }; /*! @@ -61,7 +61,7 @@ void CommandLocator::prepareSearch(const QString &entry) continue; QAction *action = command->action(); if (action && action->isEnabled()) - d->commandsData.append({action, action->text()}); + d->commandsData.append({i, action->text()}); } } @@ -77,17 +77,8 @@ QList CommandLocator::matchesFor(QFutureInterface= 0) { - QAction *action = pair.first; - LocatorFilterEntry filterEntry; - filterEntry.displayName = text; - filterEntry.acceptor = [action] { - // avoid nested stack trace and blocking locator by delayed triggering - QMetaObject::invokeMethod(action, [action] { - if (action->isEnabled()) - action->trigger(); - }, Qt::QueuedConnection); - return AcceptResult(); - }; + LocatorFilterEntry filterEntry(this, text); + filterEntry.internalData = QVariant(pair.first); filterEntry.highlightInfo = {index, int(entry.length())}; if (index == 0) @@ -100,4 +91,21 @@ QList CommandLocator::matchesFor(QFutureInterface= 0 && index < d->commands.size(), return); + QAction *action = d->commands.at(index)->action(); + // avoid nested stack trace and blocking locator by delayed triggering + QMetaObject::invokeMethod(action, [action] { + if (action->isEnabled()) + action->trigger(); + }, Qt::QueuedConnection); +} + } // namespace Core diff --git a/src/plugins/coreplugin/locator/commandlocator.h b/src/plugins/coreplugin/locator/commandlocator.h index e47fbde5c41..8199661bed6 100644 --- a/src/plugins/coreplugin/locator/commandlocator.h +++ b/src/plugins/coreplugin/locator/commandlocator.h @@ -26,6 +26,9 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; + void accept(const LocatorFilterEntry &selection, + QString *newText, int *selectionStart, int *selectionLength) const override; + private: CommandLocatorPrivate *d = nullptr; }; From 6b661ef1bed853acaa5a4006f9ba32a53ac465df Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 6 Apr 2023 13:20:55 +0200 Subject: [PATCH 0550/1447] RemoteLinux: Let sftp work on the last hop ... even if the final target is not directly accessible. This does not affect existing use cases but allows one more: DesktopDevice --ssh--> Source/Build --sft--> RunDevice, with the RunDevice not directly accessible from the Desktop. That setup exists in reality for our QNX CI machines. Change-Id: I5cda28cc835af914f2438f99d6a3facf584c74c6 Reviewed-by: Christian Kandeler --- src/plugins/remotelinux/linuxdevice.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index b17ed8fcf78..97b6412e6c2 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1174,6 +1174,8 @@ protected: connect(&m_process, &QtcProcess::done, this, &SshTransferInterface::doneImpl); } + IDevice::ConstPtr device() const { return m_device; } + bool handleError() { ProcessResultData resultData = m_process.resultData(); @@ -1281,7 +1283,13 @@ public: private: void startImpl() final { - const FilePath sftpBinary = SshSettings::sftpFilePath(); + FilePath sftpBinary = SshSettings::sftpFilePath(); + + // This is a hack. We only test the last hop here. + const Id linkDeviceId = Id::fromSetting(device()->extraData(Constants::LinkDevice)); + if (const auto linkDevice = DeviceManager::instance()->find(linkDeviceId)) + sftpBinary = linkDevice->filePath(sftpBinary.fileName()).searchInPath(); + if (!sftpBinary.exists()) { startFailed(Tr::tr("\"sftp\" binary \"%1\" does not exist.") .arg(sftpBinary.toUserOutput())); From d8de6c88e9deea13b7a95e01c6280882afc490ff Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 4 Apr 2023 16:43:44 +0200 Subject: [PATCH 0551/1447] Avoid creation of temporary lists of ProjectNodes Change-Id: Iac84f7f95291fb3b12a071a066d358aaab309c52 Reviewed-by: Christian Kandeler --- .../fileapidataextractor.cpp | 7 ++-- .../cmakeprojectmanager/projecttreehelper.cpp | 3 +- .../compilationdatabaseproject.cpp | 11 +++---- .../modeleditor/componentviewcontroller.cpp | 10 +++--- src/plugins/modeleditor/modelindexer.cpp | 28 +++++++++------- src/plugins/projectexplorer/projectnodes.cpp | 30 +++-------------- src/plugins/projectexplorer/projectnodes.h | 2 -- .../projectexplorer/projectwizardpage.cpp | 8 ++--- .../qmakeprojectmanager/qmakenodes.cpp | 4 +-- .../qmakenodetreebuilder.cpp | 3 +- .../qmakeprojectmanager/qmakeproject.cpp | 33 ++++++++----------- src/plugins/qmldesigner/documentmanager.cpp | 7 ++-- src/plugins/resourceeditor/resourcenode.cpp | 4 +-- 13 files changed, 56 insertions(+), 94 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index cf60c0b7dcf..399ed7385c7 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -497,11 +497,8 @@ FolderNode *createSourceGroupNode(const QString &sourceGroupName, const QStringList parts = sourceGroupName.split("\\"); for (const QString &p : parts) { - FolderNode *existingNode = Utils::findOrDefault(currentNode->folderNodes(), - [&p](const FolderNode *fn) { - return fn->displayName() == p; - }); - + FolderNode *existingNode = currentNode->findChildFolderNode( + [&p](const FolderNode *fn) { return fn->displayName() == p; }); if (!existingNode) { auto node = createCMakeVFolder(sourceDirectory, Node::DefaultFolderPriority + 5, p); node->setListInProject(false); diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp index 3fb89d9fec6..4069ca6aa1f 100644 --- a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp +++ b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp @@ -42,8 +42,7 @@ void addCMakeVFolder(FolderNode *base, base->addNode(std::move(newFolder)); } folder->addNestedNodes(std::move(files)); - for (FolderNode *fn : folder->folderNodes()) - fn->compress(); + folder->forEachFolderNode([] (FolderNode *fn) { fn->compress(); }); } std::vector> &&removeKnownNodes( diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index 49712c32061..ad614e7e23a 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -223,13 +223,10 @@ FolderNode *addChildFolderNode(FolderNode *parent, const QString &childName) FolderNode *addOrGetChildFolderNode(FolderNode *parent, const QString &childName) { - for (FolderNode *folder : parent->folderNodes()) { - if (folder->filePath().fileName() == childName) { - return folder; - } - } - - return addChildFolderNode(parent, childName); + FolderNode *fn = parent->findChildFolderNode([&](FolderNode *folder) { + return folder->filePath().fileName() == childName; + }); + return fn ? fn : addChildFolderNode(parent, childName); } // Return the node for folderPath. diff --git a/src/plugins/modeleditor/componentviewcontroller.cpp b/src/plugins/modeleditor/componentviewcontroller.cpp index 75495c6684e..4071c5b0159 100644 --- a/src/plugins/modeleditor/componentviewcontroller.cpp +++ b/src/plugins/modeleditor/componentviewcontroller.cpp @@ -29,6 +29,7 @@ // TODO implement removing include dependencies that are not longer used // TODO refactor add/remove relations between ancestor packages into extra controller class +using namespace ProjectExplorer; using namespace Utils; namespace ModelEditor { @@ -217,17 +218,16 @@ QStringList UpdateIncludeDependenciesVisitor::findFilePathOfComponent(const qmt: void UpdateIncludeDependenciesVisitor::collectElementPaths(const ProjectExplorer::FolderNode *folderNode, QMultiHash *filePathsMap) { - const QList fileNodes = folderNode->fileNodes(); - for (const ProjectExplorer::FileNode *fileNode : fileNodes) { + folderNode->forEachFileNode([&](FileNode *fileNode) { QString elementName = qmt::NameController::convertFileNameToElementName(fileNode->filePath().toString()); QFileInfo fileInfo = fileNode->filePath().toFileInfo(); QString nodePath = fileInfo.path(); QStringList elementsPath = qmt::NameController::buildElementsPath(nodePath, false); filePathsMap->insert(elementName, Node(fileNode->filePath().toString(), elementsPath)); - } - const QList subNodes = folderNode->folderNodes(); - for (const ProjectExplorer::FolderNode *subNode : subNodes) + }); + folderNode->forEachFolderNode([&](FolderNode *subNode) { collectElementPaths(subNode, filePathsMap); + }); } qmt::MComponent *UpdateIncludeDependenciesVisitor::findComponentFromFilePath(const QString &filePath) diff --git a/src/plugins/modeleditor/modelindexer.cpp b/src/plugins/modeleditor/modelindexer.cpp index 9923782ac72..d4471fe0ec6 100644 --- a/src/plugins/modeleditor/modelindexer.cpp +++ b/src/plugins/modeleditor/modelindexer.cpp @@ -34,6 +34,8 @@ #include #include +using namespace ProjectExplorer; + namespace ModelEditor { namespace Internal { @@ -447,18 +449,20 @@ QString ModelIndexer::findFirstModel(ProjectExplorer::FolderNode *folderNode, { if (!mimeType.isValid()) return QString(); - const QList fileNodes = folderNode->fileNodes(); - for (const ProjectExplorer::FileNode *fileNode : fileNodes) { - if (mimeType.suffixes().contains(fileNode->filePath().completeSuffix())) - return fileNode->filePath().toString(); - } - const QList subFolderNodes = folderNode->folderNodes(); - for (ProjectExplorer::FolderNode *subFolderNode : subFolderNodes) { - QString modelFileName = findFirstModel(subFolderNode, mimeType); - if (!modelFileName.isEmpty()) - return modelFileName; - } - return QString(); + + const QStringList suffixes = mimeType.suffixes(); + FileNode *foundFileNode = folderNode->findChildFileNode([&](FileNode *fn) { + return suffixes.contains(fn->filePath().completeSuffix()); + }); + if (foundFileNode) + return foundFileNode->filePath().toString(); + + QString modelFileName; + folderNode->findChildFolderNode([&](FolderNode *fn) { + modelFileName = findFirstModel(fn, mimeType); + return !modelFileName.isEmpty(); + }); + return modelFileName; } void ModelIndexer::forgetProject(ProjectExplorer::Project *project) diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 4c828529545..e5c8a9a3c64 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -326,14 +326,13 @@ FilePath Node::pathOrDirectory(bool dir) const FilePath location; // Virtual Folder case // If there are files directly below or no subfolders, take the folder path - if (!folder->fileNodes().isEmpty() || folder->folderNodes().isEmpty()) { + auto Any = [](auto) { return true; }; + if (folder->findChildFileNode(Any) || !folder->findChildFolderNode(Any)) { location = m_filePath; } else { // Otherwise we figure out a commonPath from the subfolders FilePaths list; - const QList folders = folder->folderNodes(); - for (FolderNode *f : folders) - list << f->filePath(); + folder->forEachFolderNode([&](FolderNode *f) { list << f->filePath(); }); location = FileUtils::commonPath(list); } @@ -604,16 +603,6 @@ const QList FolderNode::nodes() const return Utils::toRawPointer(m_nodes); } -QList FolderNode::fileNodes() const -{ - QList result; - for (const std::unique_ptr &n : m_nodes) { - if (FileNode *fn = n->asFileNode()) - result.append(fn); - } - return result; -} - FileNode *FolderNode::fileNode(const Utils::FilePath &file) const { return static_cast(Utils::findOrDefault(m_nodes, @@ -623,16 +612,6 @@ FileNode *FolderNode::fileNode(const Utils::FilePath &file) const })); } -QList FolderNode::folderNodes() const -{ - QList result; - for (const std::unique_ptr &n : m_nodes) { - if (FolderNode *fn = n->asFolderNode()) - result.append(fn); - } - return result; -} - FolderNode *FolderNode::folderNode(const Utils::FilePath &directory) const { Node *node = Utils::findOrDefault(m_nodes, [directory](const std::unique_ptr &n) { @@ -705,8 +684,7 @@ void FolderNode::compress() compress(); } else { - for (FolderNode *fn : folderNodes()) - fn->compress(); + forEachFolderNode([&](FolderNode *fn) { fn->compress(); }); } } diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 3af72aa0031..0e0068ba7b0 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -236,9 +236,7 @@ public: FolderNode *findChildFolderNode(const std::function &predicate) const; // non-recursive FileNode *findChildFileNode(const std::function &predicate) const; // non-recursive const QList nodes() const; - QList fileNodes() const; FileNode *fileNode(const Utils::FilePath &file) const; - QList folderNodes() const; FolderNode *folderNode(const Utils::FilePath &directory) const; using FolderNodeFactory = std::function(const Utils::FilePath &)>; diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp index a648eb0981f..b13bde370bc 100644 --- a/src/plugins/projectexplorer/projectwizardpage.cpp +++ b/src/plugins/projectexplorer/projectwizardpage.cpp @@ -245,12 +245,10 @@ static AddNewTree *buildAddFilesTree(FolderNode *root, const FilePaths &files, Node *contextNode, BestNodeSelector *selector) { QList children; - const QList folderNodes = root->folderNodes(); - for (FolderNode *fn : folderNodes) { - AddNewTree *child = buildAddFilesTree(fn, files, contextNode, selector); - if (child) + root->forEachFolderNode([&](FolderNode *fn) { + if (AddNewTree *child = buildAddFilesTree(fn, files, contextNode, selector)) children.append(child); - } + }); if (root->supportsAction(AddNewFile, root) && !root->supportsAction(InheritedFromParent, root)) { FolderNode::AddNewInformation info = root->addNewInformation(files, contextNode); diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 4f59d223ced..144a9cc0c9f 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -115,9 +115,7 @@ bool QmakeBuildSystem::supportsAction(Node *context, ProjectAction action, const const FolderNode *folder = node->asFolderNode(); if (folder) { FilePaths list; - const auto folderNodes = folder->folderNodes(); - for (FolderNode *f : folderNodes) - list << f->filePath(); + folder->forEachFolderNode([&](FolderNode *f) { list << f->filePath(); }); if (n->deploysFolder(FileUtils::commonPath(list).toString())) addExistingFiles = false; } diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index 752cb7c3192..528b18c95eb 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -195,8 +195,7 @@ static void createTree(QmakeBuildSystem *buildSystem, fileNode->setEnabled(fn.second == FileOrigin::ExactParse); vfolder->addNestedNode(std::move(fileNode)); } - for (FolderNode *fn : vfolder->folderNodes()) - fn->compress(); + vfolder->forEachFolderNode([](FolderNode *fn) { fn->compress(); }); } node->addNode(std::move(vfolder)); } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index da68b010d58..68494eca6bd 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -777,32 +777,25 @@ Tasks QmakeProject::projectIssues(const Kit *k) const } // Find the folder that contains a file with a certain name (recurse down) -static FolderNode *folderOf(FolderNode *in, const FilePath &fileName) +static FolderNode *folderOf(FolderNode *in, const FilePath &filePath) { - const QList fileNodeList = in->fileNodes(); - for (FileNode *fn : fileNodeList) { - if (fn->filePath() == fileName) - return in; - } - const QList folderNodeList = in->folderNodes(); - for (FolderNode *folder : folderNodeList) { - if (FolderNode *pn = folderOf(folder, fileName)) - return pn; - } - return {}; + if (in->findChildFileNode([&filePath](FileNode *fn) { return fn->filePath() == filePath; })) + return in; + + return in->findChildFolderNode([&filePath](FolderNode *folder) { + return folderOf(folder, filePath); + }); } // Find the QmakeProFileNode that contains a certain file. // First recurse down to folder, then find the pro-file. -static FileNode *fileNodeOf(FolderNode *in, const FilePath &fileName) +static FileNode *fileNodeOf(FolderNode *in, const FilePath &filePath) { - for (FolderNode *folder = folderOf(in, fileName); folder; folder = folder->parentFolderNode()) { - if (auto *proFile = dynamic_cast(folder)) { - const QList fileNodeList = proFile->fileNodes(); - for (FileNode *fileNode : fileNodeList) { - if (fileNode->filePath() == fileName) - return fileNode; - } + for (FolderNode *folder = folderOf(in, filePath); folder; folder = folder->parentFolderNode()) { + if (auto proFile = dynamic_cast(folder)) { + return proFile->findChildFileNode([&filePath](FileNode *fn) { + return fn->filePath() == filePath; + }); } } return nullptr; diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp index 9fdf4e41198..e3460622e7d 100644 --- a/src/plugins/qmldesigner/documentmanager.cpp +++ b/src/plugins/qmldesigner/documentmanager.cpp @@ -32,6 +32,7 @@ #include +using namespace ProjectExplorer; using namespace Utils; namespace QmlDesigner { @@ -413,8 +414,10 @@ void DocumentManager::findPathToIsoProFile(bool *iconResourceFileAlreadyExists, if (node->isVirtualFolderType() && node->displayName() == "Resources") { ProjectExplorer::FolderNode *virtualFolderNode = node->asFolderNode(); if (QTC_GUARD(virtualFolderNode)) { - for (int subFolderIndex = 0; subFolderIndex < virtualFolderNode->folderNodes().size() && !iconQrcFileNode; ++subFolderIndex) { - ProjectExplorer::FolderNode *subFolderNode = virtualFolderNode->folderNodes().at(subFolderIndex); + QList folderNodes; + virtualFolderNode->forEachFolderNode([&](FolderNode *fn) { folderNodes.append(fn); }); + for (int subFolderIndex = 0; subFolderIndex < folderNodes.size() && !iconQrcFileNode; ++subFolderIndex) { + ProjectExplorer::FolderNode *subFolderNode = folderNodes.at(subFolderIndex); qCDebug(documentManagerLog) << "Checking if" << subFolderNode->displayName() << "(" << subFolderNode << ") is" << isoIconsQrcFile; diff --git a/src/plugins/resourceeditor/resourcenode.cpp b/src/plugins/resourceeditor/resourcenode.cpp index fa0e3b5e4a2..d402e3ed89e 100644 --- a/src/plugins/resourceeditor/resourcenode.cpp +++ b/src/plugins/resourceeditor/resourcenode.cpp @@ -268,9 +268,7 @@ static void compressTree(FolderNode *n) compressable->compress(); return; } - const QList childFolders = n->folderNodes(); - for (FolderNode * const c : childFolders) - compressTree(c); + n->forEachFolderNode([](FolderNode *c) { compressTree(c); }); } void ResourceTopLevelNode::addInternalNodes() From 2eba3584a18c015f574e24fc679ffa8969870fd0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 21 Mar 2023 21:15:26 +0100 Subject: [PATCH 0552/1447] ILocatorFilter: Introduce LocatorMatcher This machinery is going to replace ILocatorFilter::matchesFor() and filter usages outside of locator scope, e.g. in find unused functions. In contrary to LocatorWidget, which calls Core::Internal::runSearch() in a separate thread and the latter executes matchesFor() sequentially for all filters, this patch offers a possibility to run all filters in parallel. Change-Id: Ia59463c95294299090173f3d510d57c9f8c7f993 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 6 + src/plugins/coreplugin/coreplugin.h | 5 +- .../coreplugin/locator/ilocatorfilter.cpp | 383 ++++++++++++++++++ .../coreplugin/locator/ilocatorfilter.h | 51 +++ 4 files changed, 444 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 043bdba74d1..83f21201678 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -313,6 +313,12 @@ QObject *CorePlugin::remoteCommand(const QStringList & /* options */, return res; } +FutureSynchronizer *CorePlugin::futureSynchronizer() +{ + QTC_ASSERT(m_instance, return nullptr); + return &m_instance->m_futureSynchronizer; +} + Environment CorePlugin::startupSystemEnvironment() { return m_instance->m_startupSystemEnvironment; diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index 7153c5415b8..b415ba146e3 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -8,6 +8,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QMenu; @@ -46,13 +47,14 @@ public: const QString &workingDirectory, const QStringList &args) override; + static Utils::FutureSynchronizer *futureSynchronizer(); static Utils::Environment startupSystemEnvironment(); static Utils::EnvironmentItems environmentChanges(); static void setEnvironmentChanges(const Utils::EnvironmentItems &changes); static QString msgCrashpadInformation(); public slots: - void fileOpenRequest(const QString&); + void fileOpenRequest(const QString &); #if defined(WITH_TESTS) private slots: @@ -77,6 +79,7 @@ private: FolderNavigationWidgetFactory *m_folderNavigationWidgetFactory = nullptr; Utils::Environment m_startupSystemEnvironment; Utils::EnvironmentItems m_environmentChanges; + Utils::FutureSynchronizer m_futureSynchronizer; }; } // namespace Internal diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index f529aa0285a..35c934fbc49 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -3,9 +3,11 @@ #include "ilocatorfilter.h" +#include "../coreplugin.h" #include "../coreplugintr.h" #include "../editormanager/editormanager.h" +#include #include #include @@ -14,12 +16,15 @@ #include #include #include +#include #include #include #include #include #include +#include + using namespace Utils; /*! @@ -46,6 +51,382 @@ using namespace Utils; namespace Core { +class OutputDataProvider +{ + enum class State { + Awaiting, + NewData, + Canceled + }; + + struct WorkingData { + WorkingData() = default; + WorkingData(const LocatorMatcherTask::OutputData &entries, std::atomic &state) { + mergeWith(entries, state); + } + LocatorMatcherTask::OutputData mergeWith(const LocatorMatcherTask::OutputData &entries, + std::atomic &state) { + LocatorMatcherTask::OutputData results; + results.reserve(entries.size()); + for (const LocatorFilterEntry &entry : entries) { + if (state == State::Canceled) + return LocatorMatcherTask::OutputData(); + const auto &link = entry.linkForEditor; + if (!link || m_cache.emplace(*link).second) + results.append(entry); + } + if (state == State::Canceled) + return LocatorMatcherTask::OutputData(); + + m_data += results; + return results; + } + LocatorMatcherTask::OutputData entries() const { return m_data; } + private: + LocatorMatcherTask::OutputData m_data; + std::unordered_set m_cache; + }; + +public: + OutputDataProvider(int filterCount) + : m_filterCount(filterCount) + , m_outputData(filterCount, {}) + {} + + void addOutputData(int index, const LocatorMatcherTask::OutputData &outputData) + { + QTC_ASSERT(index >= 0, return); + + QMutexLocker locker(&m_mutex); + QTC_ASSERT(index < m_filterCount, return); + QTC_ASSERT(m_state != State::Canceled, return); + QTC_ASSERT(!m_outputData.at(index).has_value(), return); + + m_outputData[index] = outputData; + m_state = State::NewData; + m_waitCondition.wakeOne(); + } + + void cancel() + { + QMutexLocker locker(&m_mutex); + m_state = State::Canceled; + m_waitCondition.wakeOne(); + } + + // Called from separate thread (OutputFilter's thread) + void run(QPromise &promise) + { + QList> data; + QList> workingList; + while (waitForData(&data)) { + // Emit new results only when new data is reachable from the beginning (i.e. no gaps) + int currentIndex = 0; + int mergeToIndex = 0; + bool hasGap = false; + while (currentIndex < m_filterCount) { + if (m_state == State::Canceled) + return; + const auto &outputData = data.at(currentIndex); + if (!outputData.has_value()) { + ++currentIndex; + mergeToIndex = currentIndex; + hasGap = true; + continue; + } + const auto &workingData = workingList.at(currentIndex); + if (!workingData.has_value()) { + const bool mergeToCurrent = currentIndex == mergeToIndex; + const LocatorMatcherTask::OutputData dataForIndex = mergeToCurrent + ? *outputData : LocatorMatcherTask::OutputData(); + workingList[currentIndex] = std::make_optional(WorkingData(dataForIndex, + m_state)); + if (m_state == State::Canceled) + return; + const LocatorMatcherTask::OutputData newData = mergeToCurrent + ? workingList[currentIndex]->entries() + : workingList[mergeToIndex]->mergeWith(*outputData, m_state); + if (m_state == State::Canceled) + return; + if (!hasGap && !newData.isEmpty()) + promise.addResult(newData); + } else if (currentIndex != mergeToIndex) { + const LocatorMatcherTask::OutputData newData + = workingList[mergeToIndex]->mergeWith(workingData->entries(), m_state); + workingList[currentIndex] = std::make_optional({}); + if (m_state == State::Canceled) + return; + if (!hasGap && !newData.isEmpty()) + promise.addResult(newData); + } + ++currentIndex; + } + // All data arrived (no gap), so finish here + if (!hasGap) + return; + } + } + +private: + bool waitForData(QList> *data) + { + QMutexLocker locker(&m_mutex); + if (m_state == State::Canceled) + return false; + if (m_state == State::NewData) { + m_state = State::Awaiting; + *data = m_outputData; + return true; + } + m_waitCondition.wait(&m_mutex); + QTC_ASSERT(m_state != State::Awaiting, return false); + if (m_state == State::Canceled) + return false; + m_state = State::Awaiting; + *data = m_outputData; + return true; + } + + QMutex m_mutex; + QWaitCondition m_waitCondition; + const int m_filterCount = 0; + std::atomic m_state = State::Awaiting; + QList> m_outputData; +}; + +class OutputFilter : public QObject +{ + Q_OBJECT + +public: + ~OutputFilter(); + void setFilterCount(int count); + // When last index is added it ends automatically (asynchronously) + void addOutputData(int index, const LocatorMatcherTask::OutputData &outputData); + void start(); + + bool isRunning() const { return m_watcher.get(); } + +signals: + void serialOutputDataReady(const LocatorMatcherTask::OutputData &serialOutputData); + void done(); + +private: + int m_filterCount = 0; + std::unique_ptr> m_watcher; + std::shared_ptr m_dataProvider; +}; + +OutputFilter::~OutputFilter() +{ + if (!isRunning()) + return; + + m_dataProvider->cancel(); + Internal::CorePlugin::futureSynchronizer()->addFuture(m_watcher->future()); +} + +void OutputFilter::setFilterCount(int count) +{ + QTC_ASSERT(!isRunning(), return); + QTC_ASSERT(count >= 0, return); + + m_filterCount = count; +} + +void OutputFilter::addOutputData(int index, const LocatorMatcherTask::OutputData &outputData) +{ + QTC_ASSERT(isRunning(), return); + + m_dataProvider->addOutputData(index, outputData); +} + +void OutputFilter::start() +{ + QTC_ASSERT(!m_watcher, return); + QTC_ASSERT(!isRunning(), return); + if (m_filterCount == 0) { + emit done(); + return; + } + + m_dataProvider.reset(new OutputDataProvider(m_filterCount)); + m_watcher.reset(new QFutureWatcher); + connect(m_watcher.get(), &QFutureWatcherBase::resultReadyAt, this, [this](int index) { + emit serialOutputDataReady(m_watcher->resultAt(index)); + }); + connect(m_watcher.get(), &QFutureWatcherBase::finished, this, [this] { + emit done(); + m_watcher.release()->deleteLater(); + m_dataProvider.reset(); + }); + + // TODO: When filterCount == 1, deliver results directly and finish? + auto filter = [](QPromise &promise, + const std::shared_ptr &dataProvider) { + dataProvider->run(promise); + }; + m_watcher->setFuture(Utils::asyncRun(filter, m_dataProvider)); +} + +class OutputFilterAdapter : public Tasking::TaskAdapter +{ +public: + OutputFilterAdapter() { + connect(task(), &OutputFilter::done, this, [this] { emit done(true); }); + } + void start() final { task()->start(); } +}; + +} // namespace Core + +QTC_DECLARE_CUSTOM_TASK(Filter, Core::OutputFilterAdapter); + +namespace Core { + +class LocatorMatcherPrivate +{ +public: + QList m_tasks; + LocatorMatcherTask::Storage m_storage; + int m_parallelLimit = 0; + std::unique_ptr m_taskTree; +}; + +LocatorMatcher::LocatorMatcher() + : d(new LocatorMatcherPrivate) {} + +LocatorMatcher::~LocatorMatcher() = default; + +void LocatorMatcher::setTasks(const QList &tasks) +{ + d->m_tasks = tasks; +} + +void LocatorMatcher::setInputData(const LocatorMatcherTask::InputData &inputData) +{ + d->m_storage.input = inputData; +} + +void LocatorMatcher::setParallelLimit(int limit) +{ + d->m_parallelLimit = limit; +} + +void LocatorMatcher::start() +{ + QTC_ASSERT(!isRunning(), return); + d->m_storage.output = {}; + d->m_taskTree.reset(new TaskTree); + + using namespace Tasking; + + struct FilterStorage + { + OutputFilter *m_filter = nullptr; + }; + TreeStorage filterStorage; + + const auto onFilterSetup = [this, filterCount = d->m_tasks.size(), filterStorage](OutputFilter &filter) { + filterStorage->m_filter = &filter; + filter.setFilterCount(filterCount); + connect(&filter, &OutputFilter::serialOutputDataReady, + this, [this](const LocatorMatcherTask::OutputData &serialOutputData) { + d->m_storage.output += serialOutputData; + emit serialOutputDataReady(serialOutputData); + }); + }; + const auto onFilterDone = [filterStorage](const OutputFilter &filter) { + Q_UNUSED(filter) + filterStorage->m_filter = nullptr; + }; + + QList parallelTasks { ParallelLimit(d->m_parallelLimit) }; + + const auto onGroupSetup = [this](const TreeStorage &storage) { + return [this, storage] { storage->input = d->m_storage.input; }; + }; + const auto onGroupDone = [filterStorage] + (const TreeStorage &storage, int index) { + return [filterStorage, storage, index] { + OutputFilter *outputFilter = filterStorage->m_filter; + QTC_ASSERT(outputFilter, return); + outputFilter->addOutputData(index, storage->output); + }; + }; + + int index = 0; + for (const LocatorMatcherTask &task : std::as_const(d->m_tasks)) { + const auto storage = task.storage; + const Group group { + optional, + Storage(storage), + OnGroupSetup(onGroupSetup(storage)), + OnGroupDone(onGroupDone(storage, index)), + OnGroupError(onGroupDone(storage, index)), + task.task + }; + parallelTasks << group; + ++index; + } + + const Group root { + parallel, + Storage(filterStorage), + Filter(onFilterSetup, onFilterDone, onFilterDone), + Group { + parallelTasks + } + }; + + d->m_taskTree->setupRoot(root); + + const auto onFinish = [this](bool success) { + return [this, success] { + emit done(success); + d->m_taskTree.release()->deleteLater(); + }; + }; + connect(d->m_taskTree.get(), &TaskTree::done, this, onFinish(true)); + connect(d->m_taskTree.get(), &TaskTree::errorOccurred, this, onFinish(false)); + d->m_taskTree->start(); +} + +void LocatorMatcher::stop() +{ + if (!isRunning()) + return; + + d->m_taskTree->stop(); + d->m_taskTree.reset(); +} + +bool LocatorMatcher::isRunning() const +{ + return d->m_taskTree.get() && d->m_taskTree->isRunning(); +} + +LocatorMatcherTask::OutputData LocatorMatcher::outputData() const +{ + return d->m_storage.output; +} + +LocatorMatcherTask::OutputData LocatorMatcher::runBlocking(const QList &tasks, + const LocatorMatcherTask::InputData &input, int parallelLimit) +{ + LocatorMatcher tree; + tree.setTasks(tasks); + tree.setInputData(input); + tree.setParallelLimit(parallelLimit); + + QEventLoop loop; + connect(&tree, &LocatorMatcher::done, &loop, [&loop] { loop.quit(); }); + tree.start(); + if (tree.isRunning()) + loop.exec(QEventLoop::ExcludeUserInputEvents); + return tree.outputData(); +} + static QList g_locatorFilters; /*! @@ -669,3 +1050,5 @@ bool ILocatorFilter::isOldSetting(const QByteArray &state) */ } // Core + +#include "ilocatorfilter.moc" diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index ca7a0dff763..888d7b391e1 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -109,6 +109,57 @@ public: } }; +class CORE_EXPORT LocatorMatcherTask final +{ +public: + using InputData = QString; + using OutputData = QList; + class Storage + { + public: + InputData input; + OutputData output; + }; + // The main task. Initial data taken from storage.input field. + // Results reporting is done through the storage.output field. + Utils::Tasking::TaskItem task = Utils::Tasking::Group{}; + // When setting up the task, take the input data from storage.input field. + // When task is done, report results by updating the storage.output field. + // When constructing the task, don't place the storage inside the task above. + Utils::Tasking::TreeStorage storage; +}; + +class LocatorMatcherPrivate; + +class CORE_EXPORT LocatorMatcher final : public QObject +{ + Q_OBJECT + +public: + LocatorMatcher(); + ~LocatorMatcher(); + void setTasks(const QList &tasks); + void setInputData(const LocatorMatcherTask::InputData &inputData); + void setParallelLimit(int limit); // by default 0 = parallel + void start(); + void stop(); + + bool isRunning() const; + // Total data collected so far, even when running. + LocatorMatcherTask::OutputData outputData() const; + + // Note: Starts internal event loop. + static LocatorMatcherTask::OutputData runBlocking(const QList &tasks, + const LocatorMatcherTask::InputData &input, + int parallelLimit = 0); +signals: + void serialOutputDataReady(const LocatorMatcherTask::OutputData &serialOutputData); + void done(bool success); + +private: + std::unique_ptr d; +}; + class CORE_EXPORT ILocatorFilter : public QObject { Q_OBJECT From 3b76420e0f5055e55d24dd51d1f88a880392982c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 3 Apr 2023 20:48:08 +0200 Subject: [PATCH 0553/1447] CppLocatorFilter: Introduce cpp matchers Change-Id: I7a9d3713a941c46ea8412a26743cdfcfa5791892 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppeditorplugin.cpp | 8 ++ src/plugins/cppeditor/cppeditorplugin.h | 6 +- src/plugins/cppeditor/cpplocatorfilter.cpp | 148 +++++++++++++++++++++ src/plugins/cppeditor/cpplocatorfilter.h | 4 + 4 files changed, 165 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 2d4cabe726e..53d6ef55bda 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,7 @@ public: ClangdSettingsPage *m_clangdSettingsPage = nullptr; CppCodeStyleSettingsPage m_cppCodeStyleSettingsPage; CppProjectUpdaterFactory m_cppProjectUpdaterFactory; + FutureSynchronizer m_futureSynchronizer; }; static CppEditorPlugin *m_instance = nullptr; @@ -631,6 +633,12 @@ bool CppEditorPlugin::usePragmaOnce() return m_instance->d->m_fileSettings.headerPragmaOnce; } +FutureSynchronizer *CppEditorPlugin::futureSynchronizer() +{ + QTC_ASSERT(m_instance, return nullptr); + return &m_instance->d->m_futureSynchronizer; +} + const QStringList &CppEditorPlugin::headerSearchPaths() { return m_instance->d->m_fileSettings.headerSearchPaths; diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index c28ee16b1e1..b24bc927f65 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -5,7 +5,10 @@ #include -namespace Utils { class FilePath; } +namespace Utils { +class FilePath; +class FutureSynchronizer; +} namespace CppEditor { class CppCodeModelSettings; @@ -37,6 +40,7 @@ public: static Utils::FilePath licenseTemplatePath(); static QString licenseTemplate(); static bool usePragmaOnce(); + static Utils::FutureSynchronizer *futureSynchronizer(); void openDeclarationDefinitionInNextSplit(); void openTypeHierarchy(); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 541acb05154..671c2d205e6 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -4,17 +4,165 @@ #include "cpplocatorfilter.h" #include "cppeditorconstants.h" +#include "cppeditorplugin.h" #include "cppeditortr.h" #include "cpplocatordata.h" #include +#include #include using namespace Core; +using namespace Utils; namespace CppEditor { +using EntryFromIndex = std::function; + +void matchesFor(QPromise &promise, const QString &entry, + IndexItem::ItemType wantedType, const EntryFromIndex &converter) +{ + QList entries[int(ILocatorFilter::MatchLevel::Count)]; + const Qt::CaseSensitivity caseSensitivityForPrefix = ILocatorFilter::caseSensitivity(entry); + const QRegularExpression regexp = ILocatorFilter::createRegExp(entry); + if (!regexp.isValid()) + return; + + const bool hasColonColon = entry.contains("::"); + const QRegularExpression shortRegexp = hasColonColon + ? ILocatorFilter::createRegExp(entry.mid(entry.lastIndexOf("::") + 2)) : regexp; + CppLocatorData *locatorData = CppModelManager::instance()->locatorData(); + locatorData->filterAllFiles([&](const IndexItem::Ptr &info) { + if (promise.isCanceled()) + return IndexItem::Break; + const IndexItem::ItemType type = info->type(); + if (type & wantedType) { + const QString symbolName = info->symbolName(); + QString matchString = hasColonColon ? info->scopedSymbolName() : symbolName; + int matchOffset = hasColonColon ? matchString.size() - symbolName.size() : 0; + QRegularExpressionMatch match = regexp.match(matchString); + bool matchInParameterList = false; + if (!match.hasMatch() && (type == IndexItem::Function)) { + matchString += info->symbolType(); + match = regexp.match(matchString); + matchInParameterList = true; + } + + if (match.hasMatch()) { + LocatorFilterEntry filterEntry = converter(info); + + // Highlight the matched characters, therefore it may be necessary + // to update the match if the displayName is different from matchString + if (QStringView(matchString).mid(matchOffset) != filterEntry.displayName) { + match = shortRegexp.match(filterEntry.displayName); + matchOffset = 0; + } + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + if (matchInParameterList && filterEntry.highlightInfo.startsDisplay.isEmpty()) { + match = regexp.match(filterEntry.extraInfo); + filterEntry.highlightInfo = ILocatorFilter::highlightInfo( + match, LocatorFilterEntry::HighlightInfo::ExtraInfo); + } else if (matchOffset > 0) { + for (int &start : filterEntry.highlightInfo.startsDisplay) + start -= matchOffset; + } + + if (matchInParameterList) + entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); + else if (filterEntry.displayName.startsWith(entry, caseSensitivityForPrefix)) + entries[int(ILocatorFilter::MatchLevel::Best)].append(filterEntry); + else if (filterEntry.displayName.contains(entry, caseSensitivityForPrefix)) + entries[int(ILocatorFilter::MatchLevel::Better)].append(filterEntry); + else + entries[int(ILocatorFilter::MatchLevel::Good)].append(filterEntry); + } + } + + if (info->type() & IndexItem::Enum) + return IndexItem::Continue; + return IndexItem::Recurse; + }); + + for (auto &entry : entries) { + if (entry.size() < 1000) + Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); + } + + promise.addResult(std::accumulate(std::begin(entries), std::end(entries), + QList())); +} + +LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex &converter) +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [=](AsyncTask &async) { + async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); + async.setConcurrentCallData(matchesFor, storage->input, type, converter); + }; + const auto onDone = [storage](const AsyncTask &async) { + if (async.isResultAvailable()) + storage->output = async.result(); + }; + return {Async(onSetup, onDone, onDone), storage}; +} + +LocatorMatcherTask cppLocatorMatcher() +{ + const auto converter = [](const IndexItem::Ptr &info) { + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + LocatorFilterEntry filterEntry(nullptr, info->scopedSymbolName()); + filterEntry.displayIcon = info->icon(); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; + if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) + filterEntry.extraInfo = info->shortNativeFilePath(); + else + filterEntry.extraInfo = info->symbolType(); + return filterEntry; + }; + return locatorMatcher(IndexItem::All, converter); +} + +LocatorMatcherTask cppClassMatcher() +{ + const auto converter = [](const IndexItem::Ptr &info) { + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + LocatorFilterEntry filterEntry(nullptr, info->symbolName()); + filterEntry.displayIcon = info->icon(); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; + filterEntry.extraInfo = info->symbolScope().isEmpty() + ? info->shortNativeFilePath() + : info->symbolScope(); + filterEntry.filePath = info->filePath(); + return filterEntry; + }; + return locatorMatcher(IndexItem::Class, converter); +} + +LocatorMatcherTask cppFunctionMatcher() +{ + const auto converter = [](const IndexItem::Ptr &info) { + QString name = info->symbolName(); + QString extraInfo = info->symbolScope(); + info->unqualifiedNameAndScope(name, &name, &extraInfo); + if (extraInfo.isEmpty()) + extraInfo = info->shortNativeFilePath(); + else + extraInfo.append(" (" + info->filePath().fileName() + ')'); + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + LocatorFilterEntry filterEntry(nullptr, name + info->symbolType()); + filterEntry.displayIcon = info->icon(); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; + filterEntry.extraInfo = extraInfo; + + return filterEntry; + }; + return locatorMatcher(IndexItem::Function, converter); +} + CppLocatorFilter::CppLocatorFilter() { setId(Constants::LOCATOR_FILTER_ID); diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 126853c313d..b484a9c7687 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -10,6 +10,10 @@ namespace CppEditor { +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppLocatorMatcher(); +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher(); +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher(); + class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter { Q_OBJECT From cacc4aeede245ddc92a196e99fb1e66458d4403c Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 17 Apr 2023 10:12:53 +0200 Subject: [PATCH 0554/1447] ProjectExplorer: Run toolchain autodetection on startup ... explicitly only for the Desktop device. This was implicitly done in some cases by assuming 'no device' == 'desktop'. Make that explicit now. Change-Id: I2ce86702a9b5b795fb4832301a11a8c8b40e77ea Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/ios/iosconfigurations.cpp | 3 ++- src/plugins/nim/project/nimtoolchainfactory.cpp | 5 +---- src/plugins/projectexplorer/gcctoolchain.cpp | 7 +++---- src/plugins/projectexplorer/msvctoolchain.cpp | 5 +++-- src/plugins/projectexplorer/toolchain.cpp | 4 +++- .../projectexplorer/toolchainsettingsaccessor.cpp | 9 ++++++--- src/plugins/webassembly/webassemblytoolchain.cpp | 2 +- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 93c00fb2ee6..4ba74298a9b 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -573,7 +574,7 @@ IosToolChainFactory::IosToolChainFactory() Toolchains IosToolChainFactory::autoDetect(const ToolchainDetector &detector) const { - if (detector.device) + if (detector.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) return {}; QList existingClangToolChains = clangToolChains(detector.alreadyKnown); diff --git a/src/plugins/nim/project/nimtoolchainfactory.cpp b/src/plugins/nim/project/nimtoolchainfactory.cpp index 4301140865a..01ec5373b55 100644 --- a/src/plugins/nim/project/nimtoolchainfactory.cpp +++ b/src/plugins/nim/project/nimtoolchainfactory.cpp @@ -35,10 +35,7 @@ Toolchains NimToolChainFactory::autoDetect(const ToolchainDetector &detector) co { Toolchains result; - IDevice::ConstPtr dev = - detector.device ? detector.device : DeviceManager::defaultDesktopDevice(); - - const FilePath compilerPath = dev->searchExecutableInPath("nim"); + const FilePath compilerPath = detector.device->searchExecutableInPath("nim"); if (compilerPath.isEmpty()) return result; diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index b145ba56b6b..7212e24dd5d 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1040,10 +1040,9 @@ GccToolChainFactory::GccToolChainFactory() Toolchains GccToolChainFactory::autoDetect(const ToolchainDetector &detector) const { // GCC is almost never what you want on macOS, but it is by default found in /usr/bin - if (HostOsInfo::isMacHost() - && (!detector.device || detector.device->type() == Constants::DESKTOP_DEVICE_TYPE)) { + if (HostOsInfo::isMacHost() && detector.device->type() == Constants::DESKTOP_DEVICE_TYPE) return {}; - } + Toolchains tcs; static const auto tcChecker = [](const ToolChain *tc) { return tc->targetAbi().osFlavor() != Abi::WindowsMSysFlavor @@ -1086,7 +1085,7 @@ static FilePaths findCompilerCandidates(const ToolchainDetector &detector, { const IDevice::ConstPtr device = detector.device; const QFileInfo fi(compilerName); - if (device.isNull() && fi.isAbsolute() && fi.isFile()) + if (device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE && fi.isAbsolute() && fi.isFile()) return {FilePath::fromString(compilerName)}; QStringList nameFilters(compilerName); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 1eebcc68069..334777c24e2 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -3,6 +3,7 @@ #include "msvctoolchain.h" +#include "devicesupport/idevice.h" #include "gcctoolchain.h" #include "msvcparser.h" #include "projectexplorer.h" @@ -1909,7 +1910,7 @@ static void detectCppBuildTools2015(Toolchains *list) Toolchains MsvcToolChainFactory::autoDetect(const ToolchainDetector &detector) const { - if (!detector.device.isNull()) { + if (detector.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { // FIXME currently no support for msvc toolchains on a device return {}; } @@ -2024,7 +2025,7 @@ bool ClangClToolChainFactory::canCreate() const Toolchains ClangClToolChainFactory::autoDetect(const ToolchainDetector &detector) const { - if (!detector.device.isNull()) { + if (detector.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { // FIXME currently no support for msvc toolchains on a device return {}; } diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index dfca4040fe3..8b8cfce2c80 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -674,7 +674,9 @@ ToolchainDetector::ToolchainDetector(const Toolchains &alreadyKnown, const IDevice::ConstPtr &device, const FilePaths &searchPaths) : alreadyKnown(alreadyKnown), device(device), searchPaths(searchPaths) -{} +{ + QTC_CHECK(device); +} BadToolchain::BadToolchain(const Utils::FilePath &filePath) : BadToolchain(filePath, filePath.symLinkTarget(), filePath.lastModified()) diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp index 4152e9882ee..d7db868e856 100644 --- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp +++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp @@ -3,6 +3,7 @@ #include "toolchainsettingsaccessor.h" +#include "devicesupport/devicemanager.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "toolchain.h" @@ -192,9 +193,11 @@ Toolchains ToolChainSettingsAccessor::restoreToolChains(QWidget *parent) const // Autodetect: Pass autodetected toolchains from user file so the information can be reused: const Toolchains autodetectedUserFileTcs = Utils::filtered(userFileTcs, &ToolChain::isAutoDetected); - // FIXME: Use real device? - const Toolchains autodetectedTcs = - autoDetectToolChains(ToolchainDetector(autodetectedUserFileTcs, {}, {})); + + // Autodect from system paths on the desktop device. + // The restriction is intentional to keep startup and automatic validation a limited effort + ToolchainDetector detector(autodetectedUserFileTcs, DeviceManager::defaultDesktopDevice(), {}); + const Toolchains autodetectedTcs = autoDetectToolChains(detector); // merge tool chains and register those that we need to keep: const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs); diff --git a/src/plugins/webassembly/webassemblytoolchain.cpp b/src/plugins/webassembly/webassemblytoolchain.cpp index e38b00dac6d..4ee3eff5916 100644 --- a/src/plugins/webassembly/webassemblytoolchain.cpp +++ b/src/plugins/webassembly/webassemblytoolchain.cpp @@ -96,7 +96,7 @@ static Toolchains doAutoDetect(const ToolchainDetector &detector) if (!WebAssemblyEmSdk::isValid(sdk)) return {}; - if (detector.device) { + if (detector.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { // Only detect toolchains from the emsdk installation device const FilePath deviceRoot = detector.device->rootPath(); if (deviceRoot.host() != sdk.host()) From 8db29850b168d9abc3c3d14af94878a819545514 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 16 Mar 2023 18:25:25 -0700 Subject: [PATCH 0555/1447] Clean up legacy content from Qt 5's QProcess::setupChildProcess() We needed a derived class because in Qt 5 we needed to override the setupChildProcess() virtual. Now have setChildProcessModifier(). The actual subclassing was removed in a prior commit; this merely cleans stuff up. Drive-by fix the arguments to setpgid: processId() always returns 0 in the child process. Change-Id: Icfe44ecf285a480fafe4fffd174d1073c0e1ddc3 Reviewed-by: Jarek Kobus --- src/libs/utils/launcherinterface.cpp | 24 ++++++++--------------- src/libs/utils/processutils.cpp | 29 ++++++++++++---------------- src/libs/utils/processutils.h | 1 - 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/libs/utils/launcherinterface.cpp b/src/libs/utils/launcherinterface.cpp index e71b09b0edc..218286521db 100644 --- a/src/libs/utils/launcherinterface.cpp +++ b/src/libs/utils/launcherinterface.cpp @@ -21,20 +21,6 @@ namespace Utils { namespace Internal { -class LauncherProcess : public QProcess -{ -public: - LauncherProcess(QObject *parent) : QProcess(parent) - { -#ifdef Q_OS_UNIX - setChildProcessModifier([this] { - const auto pid = static_cast(processId()); - setpgid(pid, pid); - }); -#endif - } -}; - static QString launcherSocketName() { return TemporaryDirectory::masterDirectoryPath() @@ -64,7 +50,7 @@ signals: private: QLocalServer * const m_server; Internal::LauncherSocket *const m_socket; - Internal::LauncherProcess *m_process = nullptr; + QProcess *m_process = nullptr; QString m_pathToLauncher; }; @@ -89,12 +75,18 @@ void LauncherInterfacePrivate::doStart() emit errorOccurred(m_server->errorString()); return; } - m_process = new LauncherProcess(this); + m_process = new QProcess(this); connect(m_process, &QProcess::errorOccurred, this, &LauncherInterfacePrivate::handleProcessError); connect(m_process, &QProcess::finished, this, &LauncherInterfacePrivate::handleProcessFinished); connect(m_process, &QProcess::readyReadStandardError, this, &LauncherInterfacePrivate::handleProcessStderr); +#ifdef Q_OS_UNIX + m_process->setChildProcessModifier([] { + setpgid(0, 0); + }); +#endif + m_process->start(launcherFilePath(), QStringList(m_server->fullServerName())); } diff --git a/src/libs/utils/processutils.cpp b/src/libs/utils/processutils.cpp index b534d6f8bb2..62ea514b658 100644 --- a/src/libs/utils/processutils.cpp +++ b/src/libs/utils/processutils.cpp @@ -107,7 +107,18 @@ ProcessHelper::ProcessHelper(QObject *parent) : QProcess(parent), m_processStartHandler(this) { #if defined(Q_OS_UNIX) - setChildProcessModifier([this] { setupChildProcess_impl(); }); + setChildProcessModifier([this] { + // nice value range is -20 to +19 where -20 is highest, 0 default and +19 is lowest + if (m_lowPriority) { + errno = 0; + if (::nice(5) == -1 && errno != 0) + perror("Failed to set nice value"); + } + + // Disable terminal by becoming a session leader. + if (m_unixTerminalDisabled) + setsid(); + }); #endif } @@ -153,20 +164,4 @@ void ProcessHelper::interruptProcess(QProcess *process) ProcessHelper::interruptPid(process->processId()); } -void ProcessHelper::setupChildProcess_impl() -{ -#if defined Q_OS_UNIX - // nice value range is -20 to +19 where -20 is highest, 0 default and +19 is lowest - if (m_lowPriority) { - errno = 0; - if (::nice(5) == -1 && errno != 0) - perror("Failed to set nice value"); - } - - // Disable terminal by becoming a session leader. - if (m_unixTerminalDisabled) - setsid(); -#endif -} - } // namespace Utils diff --git a/src/libs/utils/processutils.h b/src/libs/utils/processutils.h index fa915e2ac42..89202c0daf2 100644 --- a/src/libs/utils/processutils.h +++ b/src/libs/utils/processutils.h @@ -50,7 +50,6 @@ public: private: void terminateProcess(); - void setupChildProcess_impl(); bool m_lowPriority = false; bool m_unixTerminalDisabled = false; From c8ac10b4c1430f6fb3e75539e102b42bb1b00fc7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 4 Apr 2023 23:04:27 +0200 Subject: [PATCH 0556/1447] LanguageClient: Introduce workspace matchers Change-Id: I958e83f140ce5d12a5fb6734b9fbfd8a5f95a787 Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- .../languageclient/languageclientplugin.cpp | 6 ++ .../languageclient/languageclientplugin.h | 4 + src/plugins/languageclient/locatorfilter.cpp | 90 ++++++++++++++++++- src/plugins/languageclient/locatorfilter.h | 8 ++ 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index 7332f03e2b1..b1001137662 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -33,6 +33,12 @@ LanguageClientPlugin *LanguageClientPlugin::instance() return m_instance; } +Utils::FutureSynchronizer *LanguageClientPlugin::futureSynchronizer() +{ + QTC_ASSERT(m_instance, return nullptr); + return &m_instance->m_futureSynchronizer; +} + void LanguageClientPlugin::initialize() { using namespace Core; diff --git a/src/plugins/languageclient/languageclientplugin.h b/src/plugins/languageclient/languageclientplugin.h index b8eb3ac00a2..52e8dde9072 100644 --- a/src/plugins/languageclient/languageclientplugin.h +++ b/src/plugins/languageclient/languageclientplugin.h @@ -8,6 +8,8 @@ #include +#include + namespace LanguageClient { class LanguageClientPlugin : public ExtensionSystem::IPlugin @@ -19,6 +21,7 @@ public: ~LanguageClientPlugin() override; static LanguageClientPlugin *instance(); + static Utils::FutureSynchronizer *futureSynchronizer(); // IPlugin interface private: @@ -29,6 +32,7 @@ private: private: LanguageClientOutlineWidgetFactory m_outlineFactory; CallHierarchyFactory m_callHierarchyFactory; + Utils::FutureSynchronizer m_futureSynchronizer; #ifdef WITH_TESTS private slots: diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index ba4cc105abc..19f1698f3ed 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -3,9 +3,11 @@ #include "locatorfilter.h" +#include "clientrequesttask.h" #include "documentsymbolcache.h" #include "languageclient_global.h" #include "languageclientmanager.h" +#include "languageclientplugin.h" #include "languageclienttr.h" #include @@ -14,6 +16,7 @@ #include +#include #include #include @@ -21,9 +24,92 @@ using namespace Core; using namespace LanguageServerProtocol; +using namespace Utils; namespace LanguageClient { +void filterResults(QPromise &promise, Client *client, + const QList &results, const QList &filter) +{ + const auto doFilter = [&](const SymbolInformation &info) { + return filter.contains(SymbolKind(info.kind())); + }; + const QList filteredResults = filter.isEmpty() ? results + : Utils::filtered(results, doFilter); + const auto generateEntry = [client](const SymbolInformation &info) { + LocatorFilterEntry entry; + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + entry.filter = nullptr; + entry.displayName = info.name(); + if (std::optional container = info.containerName()) + entry.extraInfo = container.value_or(QString()); + entry.displayIcon = symbolIcon(info.kind()); + entry.linkForEditor = info.location().toLink(client->hostPathMapper()); + return entry; + }; + promise.addResult(Utils::transform(filteredResults, generateEntry)); +} + +LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, + const QList &filter) +{ + using namespace Tasking; + + TreeStorage storage; + TreeStorage> resultStorage; + + const auto onQuerySetup = [=](WorkspaceSymbolRequestTask &request) { + request.setClient(client); + WorkspaceSymbolParams params; + params.setQuery(storage->input); + if (maxResultCount > 0) + params.setLimit(maxResultCount); + request.setParams(params); + }; + const auto onQueryDone = [resultStorage](const WorkspaceSymbolRequestTask &request) { + const std::optional> result + = request.response().result(); + if (result.has_value()) + *resultStorage = result->toList(); + }; + + const auto onFilterSetup = [=](AsyncTask &async) { + const QList results = *resultStorage; + if (results.isEmpty()) + return TaskAction::StopWithDone; + async.setFutureSynchronizer(LanguageClientPlugin::futureSynchronizer()); + async.setConcurrentCallData(filterResults, client, results, filter); + return TaskAction::Continue; + }; + const auto onFilterDone = [storage](const AsyncTask &async) { + if (async.isResultAvailable()) + storage->output = async.result(); + }; + + const Group root { + Storage(resultStorage), + SymbolRequest(onQuerySetup, onQueryDone), + Async(onFilterSetup, onFilterDone) + }; + return {root, storage}; +} + +LocatorMatcherTask workspaceLocatorMatcher(Client *client, int maxResultCount) +{ + return locatorMatcher(client, maxResultCount, {}); +} + +LocatorMatcherTask workspaceClassMatcher(Client *client, int maxResultCount) +{ + return locatorMatcher(client, maxResultCount, {SymbolKind::Class, SymbolKind::Struct}); +} + +LocatorMatcherTask workspaceFunctionMatcher(Client *client, int maxResultCount) +{ + return locatorMatcher(client, maxResultCount, + {SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}); +} + DocumentLocatorFilter::DocumentLocatorFilter(LanguageClientManager *languageManager) { setId(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_ID); @@ -129,7 +215,7 @@ QList DocumentLocatorFilter::entriesForDocSymbols( void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) { QMutexLocker locker(&m_mutex); - m_currentFilePath = m_pathMapper ? m_currentUri.toFilePath(m_pathMapper) : Utils::FilePath(); + m_currentFilePath = m_pathMapper ? m_currentUri.toFilePath(m_pathMapper) : FilePath(); if (m_symbolCache && !m_currentSymbols.has_value()) { locker.unlock(); m_symbolCache->requestSymbols(m_currentUri, Schedule::Now); @@ -154,7 +240,7 @@ QList DocumentLocatorFilter::matchesFor( return matchesForImpl(future, entry, docSymbolGenerator); } -Utils::Link DocumentLocatorFilter::linkForDocSymbol(const DocumentSymbol &info) const +Link DocumentLocatorFilter::linkForDocSymbol(const DocumentSymbol &info) const { const Position &pos = info.range().start(); return {m_currentFilePath, pos.line() + 1, pos.character()}; diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 1ac354ed357..bf6ff30a015 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -19,6 +19,14 @@ namespace Core { class IEditor; } namespace LanguageClient { +// TODO: Could be public methods of Client instead +Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceLocatorMatcher(Client *client, + int maxResultCount = 0); +Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceClassMatcher(Client *client, + int maxResultCount = 0); +Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceFunctionMatcher(Client *client, + int maxResultCount = 0); + class LanguageClientManager; class LANGUAGECLIENT_EXPORT DocumentLocatorFilter : public Core::ILocatorFilter From ed120516f60f9c0570b1150cd9b7ea06d2aeab8b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 7 Apr 2023 09:34:00 +0200 Subject: [PATCH 0557/1447] DocumentLocatorFilter: Get rid of the arg from c'tor It's always LanguageClientManager::instance(). Pimpl LanguageClientManager's filters, so that they are constructed after the managerInstance is being assigned. Change-Id: Ib1f6f0c96d57d0e4cb7332ce322f6c4e9ef9fdb1 Reviewed-by: David Schulz Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 1 - .../clangcodemodel/clangmodelmanagersupport.cpp | 1 + .../languageclient/languageclientmanager.cpp | 13 ++++++++++++- src/plugins/languageclient/languageclientmanager.h | 7 ++----- src/plugins/languageclient/locatorfilter.cpp | 4 ++-- src/plugins/languageclient/locatorfilter.h | 2 +- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index a7700d942af..0f37e4fb554 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -192,7 +192,6 @@ class LspCurrentDocumentFilter : public DocumentLocatorFilter { public: LspCurrentDocumentFilter() - : DocumentLocatorFilter(LanguageClientManager::instance()) { setId({}); setDisplayName({}); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index d10c9c6e28f..4d9ee95d860 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -27,6 +27,7 @@ #include #include +#include #include diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 2d896f1a2d3..275e9ed9e49 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -6,6 +6,7 @@ #include "languageclientplugin.h" #include "languageclientsymbolsupport.h" #include "languageclienttr.h" +#include "locatorfilter.h" #include #include @@ -41,9 +42,19 @@ static Q_LOGGING_CATEGORY(Log, "qtc.languageclient.manager", QtWarningMsg) static LanguageClientManager *managerInstance = nullptr; static bool g_shuttingDown = false; +class LanguageClientManagerPrivate +{ + DocumentLocatorFilter m_currentDocumentLocatorFilter; + WorkspaceLocatorFilter m_workspaceLocatorFilter; + WorkspaceClassLocatorFilter m_workspaceClassLocatorFilter; + WorkspaceMethodLocatorFilter m_workspaceMethodLocatorFilter; +}; + LanguageClientManager::LanguageClientManager(QObject *parent) : QObject(parent) { + managerInstance = this; + d.reset(new LanguageClientManagerPrivate); using namespace Core; using namespace ProjectExplorer; connect(EditorManager::instance(), &EditorManager::editorOpened, @@ -74,7 +85,7 @@ void LanguageClientManager::init() if (managerInstance) return; QTC_ASSERT(LanguageClientPlugin::instance(), return); - managerInstance = new LanguageClientManager(LanguageClientPlugin::instance()); + new LanguageClientManager(LanguageClientPlugin::instance()); } void LanguageClient::LanguageClientManager::addClient(Client *client) diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index cf90a2f7468..dd36da935e8 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -6,7 +6,6 @@ #include "client.h" #include "languageclient_global.h" #include "languageclientsettings.h" -#include "locatorfilter.h" #include "lspinspector.h" #include @@ -25,6 +24,7 @@ namespace ProjectExplorer { class Project; } namespace LanguageClient { +class LanguageClientManagerPrivate; class LanguageClientMark; class LANGUAGECLIENT_EXPORT LanguageClientManager : public QObject @@ -104,10 +104,7 @@ private: QList m_currentSettings; // owned QMap> m_clientsForSetting; QHash> m_clientForDocument; - DocumentLocatorFilter m_currentDocumentLocatorFilter{this}; - WorkspaceLocatorFilter m_workspaceLocatorFilter; - WorkspaceClassLocatorFilter m_workspaceClassLocatorFilter; - WorkspaceMethodLocatorFilter m_workspaceMethodLocatorFilter; + std::unique_ptr d; LspInspector m_inspector; }; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 19f1698f3ed..fb883c7603d 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -110,7 +110,7 @@ LocatorMatcherTask workspaceFunctionMatcher(Client *client, int maxResultCount) {SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}); } -DocumentLocatorFilter::DocumentLocatorFilter(LanguageClientManager *languageManager) +DocumentLocatorFilter::DocumentLocatorFilter() { setId(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DISPLAY_NAME)); @@ -121,7 +121,7 @@ DocumentLocatorFilter::DocumentLocatorFilter(LanguageClientManager *languageMana setPriority(ILocatorFilter::Low); connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, &DocumentLocatorFilter::updateCurrentClient); - connect(languageManager, &LanguageClientManager::clientInitialized, + connect(LanguageClientManager::instance(), &LanguageClientManager::clientInitialized, this, &DocumentLocatorFilter::updateCurrentClient); } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index bf6ff30a015..d1c000331a9 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -33,7 +33,7 @@ class LANGUAGECLIENT_EXPORT DocumentLocatorFilter : public Core::ILocatorFilter { Q_OBJECT public: - DocumentLocatorFilter(LanguageClientManager *languageManager); + DocumentLocatorFilter(); void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, From abf7dd23eda813e5f1c32d4d128114169f7ca601 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 13 Apr 2023 12:50:51 +0200 Subject: [PATCH 0558/1447] Show filter description in locator settings Directly in the items, instead of just in the tooltip. Change-Id: I631598ef3e38967a6fcf84fd70f22bccc8b97ea7 Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- .../locator/locatorsettingspage.cpp | 113 +++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorsettingspage.cpp b/src/plugins/coreplugin/locator/locatorsettingspage.cpp index 9940680aa25..99116eea9c1 100644 --- a/src/plugins/coreplugin/locator/locatorsettingspage.cpp +++ b/src/plugins/coreplugin/locator/locatorsettingspage.cpp @@ -20,12 +20,15 @@ #include #include +#include #include #include #include #include +#include #include #include +#include using namespace Utils; @@ -77,8 +80,14 @@ QVariant FilterItem::data(int column, int role) const { switch (column) { case FilterName: - if (role == Qt::DisplayRole || role == SortRole) + if (role == SortRole) return m_filter->displayName(); + if (role == Qt::DisplayRole) { + if (m_filter->description().isEmpty()) + return m_filter->displayName(); + return QString("%1
%2") + .arg(m_filter->displayName(), m_filter->description().toHtmlEscaped()); + } break; case FilterPrefix: if (role == Qt::DisplayRole || role == SortRole || role == Qt::EditRole) @@ -146,6 +155,97 @@ QVariant CategoryItem::data(int column, int role) const return QVariant(); } +class RichTextDelegate : public QStyledItemDelegate +{ +public: + RichTextDelegate(QObject *parent); + ~RichTextDelegate(); + + QTextDocument &doc() { return m_doc; } + + void setMaxWidth(int width); + int maxWidth() const; + +private: + void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + + int m_maxWidth = -1; + mutable QTextDocument m_doc; +}; + +RichTextDelegate::RichTextDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{} + +void RichTextDelegate::setMaxWidth(int width) +{ + m_maxWidth = width; + emit sizeHintChanged({}); +} + +int RichTextDelegate::maxWidth() const +{ + return m_maxWidth; +} + +RichTextDelegate::~RichTextDelegate() = default; + +void RichTextDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItem options = option; + initStyleOption(&options, index); + + painter->save(); + QTextOption textOption; + if (m_maxWidth > 0) { + textOption.setWrapMode(QTextOption::WordWrap); + m_doc.setDefaultTextOption(textOption); + if (options.rect.width() > m_maxWidth) + options.rect.setWidth(m_maxWidth); + } + m_doc.setHtml(options.text); + m_doc.setTextWidth(options.rect.width()); + options.text = ""; + options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter); + painter->translate(options.rect.left(), options.rect.top()); + QRect clip(0, 0, options.rect.width(), options.rect.height()); + QAbstractTextDocumentLayout::PaintContext paintContext; + paintContext.palette = options.palette; + painter->setClipRect(clip); + paintContext.clip = clip; + if (qobject_cast(options.widget)->selectionModel()->isSelected(index)) { + QAbstractTextDocumentLayout::Selection selection; + selection.cursor = QTextCursor(&m_doc); + selection.cursor.select(QTextCursor::Document); + selection.format.setBackground(options.palette.brush(QPalette::Highlight)); + selection.format.setForeground(options.palette.brush(QPalette::HighlightedText)); + paintContext.selections << selection; + } + m_doc.documentLayout()->draw(painter, paintContext); + painter->restore(); +} + +QSize RichTextDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyleOptionViewItem options = option; + initStyleOption(&options, index); + QTextOption textOption; + if (m_maxWidth > 0) { + textOption.setWrapMode(QTextOption::WordWrap); + m_doc.setDefaultTextOption(textOption); + if (!options.rect.isValid() || options.rect.width() > m_maxWidth) + options.rect.setWidth(m_maxWidth); + } + m_doc.setHtml(options.text); + m_doc.setTextWidth(options.rect.width()); + return QSize(m_doc.idealWidth(), m_doc.size().height()); +} + class LocatorSettingsWidget : public IOptionsPageWidget { public: @@ -178,8 +278,17 @@ public: m_filterList->setSelectionMode(QAbstractItemView::SingleSelection); m_filterList->setSelectionBehavior(QAbstractItemView::SelectRows); m_filterList->setSortingEnabled(true); - m_filterList->setUniformRowHeights(true); m_filterList->setActivationMode(Utils::DoubleClickActivation); + m_filterList->setAlternatingRowColors(true); + auto nameDelegate = new RichTextDelegate(m_filterList); + connect(m_filterList->header(), + &QHeaderView::sectionResized, + nameDelegate, + [nameDelegate](int col, [[maybe_unused]] int old, int updated) { + if (col == 0) + nameDelegate->setMaxWidth(updated); + }); + m_filterList->setItemDelegateForColumn(0, nameDelegate); m_model = new TreeModel<>(m_filterList); initializeModel(); From 07b1e1c5fe03806f7c8d78e1ae72ebd38a1b9849 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 18:05:31 +0200 Subject: [PATCH 0559/1447] LocatorFilterEntry: Add Acceptor field Add also AcceptResult structure, returned by acceptor. The Acceptor, being a member of LocatorFilterEntry, is going to be used instead of virtual ILocatorFilter::accept() method. By default, when no Acceptor is provided, the locator widget is going to call EditorManager::openEditor() with a LocatorFilterEntry instance. Change-Id: Ic9697492738d65fd1331bbd0872bc374285c4e53 Reviewed-by: Eike Ziller --- .../coreplugin/locator/ilocatorfilter.h | 15 ++++++++++++++- .../coreplugin/locator/locatorwidget.cpp | 19 ++++++++++++------- .../coreplugin/locator/locatorwidget.h | 3 +-- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 888d7b391e1..3babe87516c 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -26,6 +26,14 @@ namespace Internal { class Locator; } class ILocatorFilter; +class AcceptResult +{ +public: + QString newText; + int selectionStart = -1; + int selectionLength = 0; +}; + class LocatorFilterEntry { public: @@ -77,6 +85,7 @@ public: , displayName(name) {} + using Acceptor = std::function; /* backpointer to creating filter */ ILocatorFilter *filter = nullptr; /* displayed string */ @@ -87,8 +96,12 @@ public: QString extraInfo; /* additional tooltip */ QString toolTip; + /* called by locator widget on accept. By default, when acceptor is empty, + EditorManager::openEditor(LocatorFilterEntry) will be used instead. */ + Acceptor acceptor; /* can be used by the filter to save more information about the entry */ - QVariant internalData; // DON'T USE IN NEW CODE, IT'S GOING TO BE REMOVED, SOON... + /* Replaced by acceptor - DON'T USE IN NEW CODE, IT'S GOING TO BE REMOVED, SOON... */ + QVariant internalData; /* icon to display along with the entry */ std::optional displayIcon; /* file path, if the entry is related to a file, is used e.g. for resolving a file icon */ diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 7bb381ac01b..bd31b69fe13 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -10,6 +10,7 @@ #include "locatorsearchutils.h" #include "../actionmanager/actionmanager.h" #include "../coreplugintr.h" +#include "../editormanager/editormanager.h" #include "../icore.h" #include "../modemanager.h" @@ -1003,18 +1004,22 @@ void LocatorWidget::acceptEntry(int row) if (!index.isValid()) return; const LocatorFilterEntry entry = m_locatorModel->data(index, LocatorEntryRole).value(); - Q_ASSERT(entry.filter != nullptr); - QString newText; - int selectionStart = -1; - int selectionLength = 0; QWidget *focusBeforeAccept = QApplication::focusWidget(); - entry.filter->accept(entry, &newText, &selectionStart, &selectionLength); - if (newText.isEmpty()) { + AcceptResult result; + if (entry.acceptor) { + result = entry.acceptor(); + } else if (entry.filter) { + entry.filter->accept(entry, &result.newText, &result.selectionStart, + &result.selectionLength); + } else { + EditorManager::openEditor(entry); + } + if (result.newText.isEmpty()) { emit hidePopup(); if (QApplication::focusWidget() == focusBeforeAccept) resetFocus(m_previousFocusWidget, isInMainWindow()); } else { - showText(newText, selectionStart, selectionLength); + showText(result.newText, result.selectionStart, result.selectionLength); } } diff --git a/src/plugins/coreplugin/locator/locatorwidget.h b/src/plugins/coreplugin/locator/locatorwidget.h index eef5a144147..efc90c3a517 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.h +++ b/src/plugins/coreplugin/locator/locatorwidget.h @@ -28,8 +28,7 @@ namespace Internal { class LocatorModel; class CompletionList; -class LocatorWidget - : public QWidget +class LocatorWidget : public QWidget { Q_OBJECT From ebfcb8af65c01083412eb63c86f7a8d85a177120 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 17 Apr 2023 06:45:30 +0200 Subject: [PATCH 0560/1447] QmlJS: Fix compile with Qt6.2 Amends 15a06b77c01c3bcbbc69ca0e80035e0c3824d62c. Change-Id: Iefac198e1d566fcbda77e22bcab289dda15fa1ba Reviewed-by: Eike Ziller --- src/libs/qmljs/qmljsreformatter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp index bad58e414ca..03a95a668c9 100644 --- a/src/libs/qmljs/qmljsreformatter.cpp +++ b/src/libs/qmljs/qmljsreformatter.cpp @@ -104,7 +104,7 @@ public: const QString &source = _doc->source(); // emit directives if (_doc->bind()->isJsLibrary()) { - const QLatin1String pragmaLine(".pragma library"); + const QString pragmaLine(".pragma library"); out(pragmaLine, SourceLocation(source.indexOf(".pragma"), pragmaLine.length())); newLine(); } From 5adb65655028fe41ce2f0d9d1990a01d01dc33f4 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 31 Mar 2023 15:49:51 +0200 Subject: [PATCH 0561/1447] Show locator filter descriptions more prominently - Sort items in the menu. - Disable items for disabled filters. - Show a tool tip when hovering over the magnifying glass menu. - Add descriptions to all filters and make them more consistent. Change-Id: Ic03e303c50422f9de5dd3c512fe32bbdc958d2ba Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- src/plugins/bookmarks/bookmarkfilter.cpp | 4 ++-- .../clangcodemodel/clangdlocatorfilters.cpp | 11 +++++++++++ .../cmakeprojectmanager/cmakelocatorfilter.cpp | 6 +++--- .../coreplugin/locator/directoryfilter.cpp | 2 +- .../coreplugin/locator/ilocatorfilter.cpp | 3 +++ src/plugins/coreplugin/locator/ilocatorfilter.h | 3 +++ src/plugins/coreplugin/locator/locator.cpp | 2 ++ .../coreplugin/locator/locatorsettingspage.cpp | 6 ++++-- .../coreplugin/locator/locatorwidget.cpp | 17 +++++++++++++++-- .../coreplugin/locator/opendocumentsfilter.cpp | 1 + .../locator/spotlightlocatorfilter.cpp | 8 ++++---- .../cppeditor/cppcurrentdocumentfilter.cpp | 1 + src/plugins/cppeditor/cppeditorconstants.h | 8 ++++++++ src/plugins/cppeditor/cppincludesfilter.cpp | 2 +- src/plugins/cppeditor/cpplocatorfilter.cpp | 3 +++ src/plugins/fossil/fossilplugin.cpp | 1 + src/plugins/help/helpindexfilter.cpp | 1 + .../languageclient/languageclient_global.h | 11 +++++++++++ src/plugins/languageclient/locatorfilter.cpp | 6 ++++-- .../projectexplorer/allprojectsfilter.cpp | 6 +++--- .../projectexplorer/currentprojectfilter.cpp | 6 +++--- src/plugins/projectexplorer/projectexplorer.cpp | 15 +++++++-------- src/plugins/qmljstools/qmljsfunctionfilter.cpp | 1 + 23 files changed, 93 insertions(+), 31 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index 2fad930d37e..28a03ce0074 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -19,8 +19,8 @@ BookmarkFilter::BookmarkFilter(BookmarkManager *manager) { setId("Bookmarks"); setDisplayName(Tr::tr("Bookmarks")); - setDescription(Tr::tr("Matches all bookmarks. Filter by file name, by the text on the line of the " - "bookmark, or by the bookmark's note text.")); + setDescription(Tr::tr("Locates bookmarks. Filter by file name, by the text on the line of the " + "bookmark, or by the bookmark's note text.")); setPriority(Medium); setDefaultShortcutString("b"); } diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 0f37e4fb554..58166fd499c 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -50,6 +50,7 @@ public: { setId({}); setDisplayName({}); + setDescription({}); setDefaultShortcutString({}); setEnabled(false); setHidden(true); @@ -63,6 +64,7 @@ public: { setId({}); setDisplayName({}); + setDescription({}); setDefaultShortcutString({}); setEnabled(false); setHidden(true); @@ -82,6 +84,7 @@ public: { setId({}); setDisplayName({}); + setDescription({}); setDefaultShortcutString({}); setEnabled(false); setHidden(true); @@ -94,6 +97,7 @@ public: LspClassesFilter() { setId({}); setDisplayName({}); + setDescription({}); setDefaultShortcutString({}); setEnabled(false); setHidden(true); @@ -112,6 +116,7 @@ public: { setId({}); setDisplayName({}); + setDescription({}); setDefaultShortcutString({}); setEnabled(false); setHidden(true); @@ -125,6 +130,7 @@ public: { setId({}); setDisplayName({}); + setDescription({}); setDefaultShortcutString({}); setEnabled(false); setHidden(true); @@ -148,6 +154,7 @@ ClangGlobalSymbolFilter::ClangGlobalSymbolFilter(ILocatorFilter *cppFilter, { setId(CppEditor::Constants::LOCATOR_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::LOCATOR_FILTER_DISPLAY_NAME)); + setDescription(::CppEditor::Tr::tr(CppEditor::Constants::LOCATOR_FILTER_DESCRIPTION)); setDefaultShortcutString(":"); setDefaultIncludedByDefault(false); } @@ -175,6 +182,7 @@ ClangClassesFilter::ClangClassesFilter() { setId(CppEditor::Constants::CLASSES_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::CLASSES_FILTER_DISPLAY_NAME)); + setDescription(::CppEditor::Tr::tr(CppEditor::Constants::CLASSES_FILTER_DESCRIPTION)); setDefaultShortcutString("c"); setDefaultIncludedByDefault(false); } @@ -184,6 +192,7 @@ ClangFunctionsFilter::ClangFunctionsFilter() { setId(CppEditor::Constants::FUNCTIONS_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::FUNCTIONS_FILTER_DISPLAY_NAME)); + setDescription(::CppEditor::Tr::tr(CppEditor::Constants::FUNCTIONS_FILTER_DESCRIPTION)); setDefaultShortcutString("m"); setDefaultIncludedByDefault(false); } @@ -195,6 +204,7 @@ public: { setId({}); setDisplayName({}); + setDescription({}); setDefaultShortcutString({}); setEnabled(false); setHidden(true); @@ -309,6 +319,7 @@ ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private) { setId(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME)); + setDescription(::CppEditor::Tr::tr(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_DESCRIPTION)); setDefaultShortcutString("."); setPriority(High); setDefaultIncludedByDefault(false); diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 7141fb276cb..dfee13d0911 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -92,7 +92,7 @@ void CMakeTargetLocatorFilter::projectListUpdated() BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() { setId("Build CMake target"); - setDisplayName(Tr::tr("Build CMake target")); + setDisplayName(Tr::tr("Build CMake Target")); setDescription(Tr::tr("Builds a target of any open CMake project.")); setDefaultShortcutString("cm"); setPriority(High); @@ -139,8 +139,8 @@ void BuildCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter() { setId("Open CMake target definition"); - setDisplayName(Tr::tr("Open CMake target")); - setDescription(Tr::tr("Jumps to the definition of a target of any open CMake project.")); + setDisplayName(Tr::tr("Open CMake Target")); + setDescription(Tr::tr("Locates the definition of a target of any open CMake project.")); setDefaultShortcutString("cmo"); setPriority(Medium); } diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 88e17bad358..59043051368 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -75,7 +75,7 @@ DirectoryFilter::DirectoryFilter(Id id) setId(id); setDefaultIncludedByDefault(true); setDisplayName(defaultDisplayName()); - setDescription(Tr::tr("Matches all files from a custom set of directories. Append \"+\" " + setDescription(Tr::tr("Locates files from a custom set of directories. Append \"+\" " "or \":\" to jump to the given line number. Append another " "\"+\" or \":\" to jump to the column number as well.")); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 35c934fbc49..e2b1fed4823 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -844,7 +844,10 @@ ILocatorFilter::Priority ILocatorFilter::priority() const */ void ILocatorFilter::setEnabled(bool enabled) { + if (enabled == m_enabled) + return; m_enabled = enabled; + emit enabledChanged(m_enabled); } /*! diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 3babe87516c..7d41eba9e13 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -251,6 +251,9 @@ public: public slots: void setEnabled(bool enabled); +signals: + void enabledChanged(bool enabled); + protected: void setHidden(bool hidden); void setId(Utils::Id id); diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index d43b77e7508..dab6cf364cf 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -66,6 +66,7 @@ public: LocatorData::LocatorData() { + m_urlFilter.setDescription(Tr::tr("Triggers a web search with the selected search engine.")); m_urlFilter.setDefaultShortcutString("r"); m_urlFilter.addDefaultUrl("https://www.bing.com/search?q=%1"); m_urlFilter.addDefaultUrl("https://www.google.com/search?q=%1"); @@ -75,6 +76,7 @@ LocatorData::LocatorData() "http://en.cppreference.com/mwiki/index.php?title=Special%3ASearch&search=%1"); m_urlFilter.addDefaultUrl("https://en.wikipedia.org/w/index.php?search=%1"); + m_bugFilter.setDescription(Tr::tr("Triggers a search in the Qt bug tracker.")); m_bugFilter.setDefaultShortcutString("bug"); m_bugFilter.addDefaultUrl("https://bugreports.qt.io/secure/QuickSearch.jspa?searchString=%1"); } diff --git a/src/plugins/coreplugin/locator/locatorsettingspage.cpp b/src/plugins/coreplugin/locator/locatorsettingspage.cpp index 99116eea9c1..bd5a9f63aa7 100644 --- a/src/plugins/coreplugin/locator/locatorsettingspage.cpp +++ b/src/plugins/coreplugin/locator/locatorsettingspage.cpp @@ -101,8 +101,10 @@ QVariant FilterItem::data(int column, int role) const break; } - if (role == Qt::ToolTipRole) - return m_filter->description(); + if (role == Qt::ToolTipRole) { + const QString description = m_filter->description(); + return description.isEmpty() ? QString() : ("" + description.toHtmlEscaped()); + } return QVariant(); } diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index bd31b69fe13..889223e440a 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -599,6 +600,10 @@ LocatorWidget::LocatorWidget(Locator *locator) connect(m_filterMenu, &QMenu::aboutToShow, this, [this] { m_centeredPopupAction->setChecked(Locator::useCenteredPopupForShortcut()); }); + connect(m_filterMenu, &QMenu::hovered, this, [this](QAction *action) { + ToolTip::show(m_filterMenu->mapToGlobal(m_filterMenu->actionGeometry(action).topRight()), + action->toolTip()); + }); connect(m_centeredPopupAction, &QAction::toggled, locator, [locator](bool toggled) { if (toggled != Locator::useCenteredPopupForShortcut()) { Locator::setUseCenteredPopupForShortcut(toggled); @@ -672,12 +677,20 @@ void LocatorWidget::updatePlaceholderText(Command *command) void LocatorWidget::updateFilterList() { m_filterMenu->clear(); - const QList filters = Locator::filters(); + const QList filters = Utils::sorted(Locator::filters(), + [](ILocatorFilter *a, ILocatorFilter *b) { + return a->displayName() + < b->displayName(); + }); for (ILocatorFilter *filter : filters) { if (filter->shortcutString().isEmpty() || filter->isHidden()) continue; QAction *action = m_filterMenu->addAction(filter->displayName()); - action->setToolTip(filter->description()); + action->setEnabled(filter->isEnabled()); + const QString description = filter->description(); + action->setToolTip(description.isEmpty() ? QString() + : ("" + description.toHtmlEscaped())); + connect(filter, &ILocatorFilter::enabledChanged, action, &QAction::setEnabled); connect(action, &QAction::triggered, this, [this, filter] { Locator::showFilter(filter, this); }); diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 2ec6aca0531..b68142bbb3f 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -21,6 +21,7 @@ OpenDocumentsFilter::OpenDocumentsFilter() { setId("Open documents"); setDisplayName(Tr::tr("Open Documents")); + setDescription(Tr::tr("Switches to an open document.")); setDefaultShortcutString("o"); setPriority(High); setDefaultIncludedByDefault(true); diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index cc62ec91c06..e266e707680 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -225,10 +225,10 @@ SpotlightLocatorFilter::SpotlightLocatorFilter() setDefaultShortcutString("md"); setDefaultIncludedByDefault(false); setDisplayName(Tr::tr("File Name Index")); - setDescription( - Tr::tr("Matches files from a global file system index (Spotlight, Locate, Everything). Append " - "\"+\" or \":\" to jump to the given line number. Append another " - "\"+\" or \":\" to jump to the column number as well.")); + setDescription(Tr::tr( + "Locates files from a global file system index (Spotlight, Locate, Everything). Append " + "\"+\" or \":\" to jump to the given line number. Append another " + "\"+\" or \":\" to jump to the column number as well.")); setConfigurable(true); reset(); } diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index 838160e918a..e148525b3b3 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -24,6 +24,7 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppModelManager *manager) { setId(Constants::CURRENT_DOCUMENT_FILTER_ID); setDisplayName(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DESCRIPTION)); setDefaultShortcutString("."); setPriority(High); setDefaultIncludedByDefault(false); diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h index 3c87aa6d63b..179c3b3b9b0 100644 --- a/src/plugins/cppeditor/cppeditorconstants.h +++ b/src/plugins/cppeditor/cppeditorconstants.h @@ -110,12 +110,18 @@ const char CPP_SETTINGS_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", "C++"); const char CURRENT_DOCUMENT_FILTER_ID[] = "Methods in current Document"; const char CURRENT_DOCUMENT_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", "C++ Symbols in Current Document"); +const char CURRENT_DOCUMENT_FILTER_DESCRIPTION[] + = QT_TRANSLATE_NOOP("QtC::CppEditor", "Locates C++ symbols in the current document."); const char CLASSES_FILTER_ID[] = "Classes"; const char CLASSES_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", "C++ Classes"); +const char CLASSES_FILTER_DESCRIPTION[] + = QT_TRANSLATE_NOOP("QtC::CppEditor", "Locates C++ classes in any open project."); const char FUNCTIONS_FILTER_ID[] = "Methods"; const char FUNCTIONS_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", "C++ Functions"); +const char FUNCTIONS_FILTER_DESCRIPTION[] + = QT_TRANSLATE_NOOP("QtC::CppEditor", "Locates C++ functions in any open project."); const char INCLUDES_FILTER_ID[] = "All Included C/C++ Files"; const char INCLUDES_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", @@ -124,6 +130,8 @@ const char INCLUDES_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", const char LOCATOR_FILTER_ID[] = "Classes and Methods"; const char LOCATOR_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", "C++ Classes, Enums, Functions and Type Aliases"); +const char LOCATOR_FILTER_DESCRIPTION[] = QT_TRANSLATE_NOOP( + "QtC::CppEditor", "Locates C++ classes, enums, functions and type aliases in any open project."); const char SYMBOLS_FIND_FILTER_ID[] = "Symbols"; const char SYMBOLS_FIND_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::CppEditor", "C++ Symbols"); diff --git a/src/plugins/cppeditor/cppincludesfilter.cpp b/src/plugins/cppeditor/cppincludesfilter.cpp index 44f21045d24..1c9cb298d4b 100644 --- a/src/plugins/cppeditor/cppincludesfilter.cpp +++ b/src/plugins/cppeditor/cppincludesfilter.cpp @@ -102,7 +102,7 @@ CppIncludesFilter::CppIncludesFilter() setId(Constants::INCLUDES_FILTER_ID); setDisplayName(Tr::tr(Constants::INCLUDES_FILTER_DISPLAY_NAME)); setDescription( - Tr::tr("Matches all files that are included by all C++ files in all projects. Append " + Tr::tr("Locates files that are included by C++ files of any open project. Append " "\"+\" or \":\" to jump to the given line number. Append another " "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("ai"); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 671c2d205e6..6a9f50a9c83 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -167,6 +167,7 @@ CppLocatorFilter::CppLocatorFilter() { setId(Constants::LOCATOR_FILTER_ID); setDisplayName(Tr::tr(Constants::LOCATOR_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::LOCATOR_FILTER_DESCRIPTION)); setDefaultShortcutString(":"); setDefaultIncludedByDefault(false); } @@ -263,6 +264,7 @@ CppClassesFilter::CppClassesFilter() { setId(Constants::CLASSES_FILTER_ID); setDisplayName(Tr::tr(Constants::CLASSES_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::CLASSES_FILTER_DESCRIPTION)); setDefaultShortcutString("c"); setDefaultIncludedByDefault(false); } @@ -283,6 +285,7 @@ CppFunctionsFilter::CppFunctionsFilter() { setId(Constants::FUNCTIONS_FILTER_ID); setDisplayName(Tr::tr(Constants::FUNCTIONS_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::FUNCTIONS_FILTER_DESCRIPTION)); setDefaultShortcutString("m"); setDefaultIncludedByDefault(false); } diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 94f800e1ea6..0840841416b 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -293,6 +293,7 @@ FossilPluginPrivate::FossilPluginPrivate() connect(&m_client, &VcsBase::VcsBaseClient::changed, this, &FossilPluginPrivate::changed); m_commandLocator = new Core::CommandLocator("Fossil", "fossil", "fossil", this); + m_commandLocator->setDescription(Tr::tr("Triggers a Fossil version control operation.")); ProjectExplorer::JsonWizardFactory::addWizardPath(Utils::FilePath::fromString(Constants::WIZARD_PATH)); Core::JsExpander::registerGlobalObject("Fossil", [this] { diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 9c2c7ada44c..8146b0aa2df 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -25,6 +25,7 @@ HelpIndexFilter::HelpIndexFilter() { setId("HelpIndexFilter"); setDisplayName(Tr::tr("Help Index")); + setDescription(Tr::tr("Locates help topics, for example in the Qt documentation.")); setDefaultIncludedByDefault(false); setDefaultShortcutString("?"); setRefreshRecipe(Utils::Tasking::Sync([this] { invalidateCache(); return true; })); diff --git a/src/plugins/languageclient/languageclient_global.h b/src/plugins/languageclient/languageclient_global.h index d115d10a252..2abb395d86e 100644 --- a/src/plugins/languageclient/languageclient_global.h +++ b/src/plugins/languageclient/languageclient_global.h @@ -22,12 +22,23 @@ const char LANGUAGECLIENT_STDIO_SETTINGS_ID[] = "LanguageClient::StdIOSettingsID const char LANGUAGECLIENT_SETTINGS_TR[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Language Client"); const char LANGUAGECLIENT_DOCUMENT_FILTER_ID[] = "Current Document Symbols"; const char LANGUAGECLIENT_DOCUMENT_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Symbols in Current Document"); +const char LANGUAGECLIENT_DOCUMENT_FILTER_DESCRIPTION[] + = QT_TRANSLATE_NOOP("QtC::LanguageClient", + "Locates symbols in the current document, based on a language server."); const char LANGUAGECLIENT_WORKSPACE_FILTER_ID[] = "Workspace Symbols"; const char LANGUAGECLIENT_WORKSPACE_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Symbols in Workspace"); +const char LANGUAGECLIENT_WORKSPACE_FILTER_DESCRIPTION[] + = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Locates symbols in the language server workspace."); const char LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_ID[] = "Workspace Classes and Structs"; const char LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Classes and Structs in Workspace"); +const char LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DESCRIPTION[] + = QT_TRANSLATE_NOOP("QtC::LanguageClient", + "Locates classes and structs in the language server workspace."); const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID[] = "Workspace Functions and Methods"; const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::LanguageClient", "Functions and Methods in Workspace"); +const char LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DESCRIPTION[] + = QT_TRANSLATE_NOOP("QtC::LanguageClient", + "Locates functions and methods in the language server workspace."); const char CALL_HIERARCHY_FACTORY_ID[] = "LanguageClient.CallHierarchy"; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index fb883c7603d..563f418e2a7 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -114,8 +114,7 @@ DocumentLocatorFilter::DocumentLocatorFilter() { setId(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DISPLAY_NAME)); - setDescription( - Tr::tr("Matches all symbols from the current document, based on a language server.")); + setDescription(Tr::tr(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DESCRIPTION)); setDefaultShortcutString("."); setDefaultIncludedByDefault(false); setPriority(ILocatorFilter::Low); @@ -292,6 +291,7 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter { setId(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_DESCRIPTION)); setDefaultShortcutString(":"); setDefaultIncludedByDefault(false); setPriority(ILocatorFilter::Low); @@ -388,6 +388,7 @@ WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DESCRIPTION)); setDefaultShortcutString("c"); } @@ -396,6 +397,7 @@ WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DESCRIPTION)); setDefaultShortcutString("m"); } diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index 3a9b8e7a45a..d89e111150d 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -20,9 +20,9 @@ AllProjectsFilter::AllProjectsFilter() { setId("Files in any project"); setDisplayName(Tr::tr("Files in Any Project")); - setDescription(Tr::tr("Matches all files of all open projects. Append \"+\" or " - "\":\" to jump to the given line number. Append another " - "\"+\" or \":\" to jump to the column number as well.")); + setDescription(Tr::tr("Locates files of all open projects. Append \"+\" or " + "\":\" to jump to the given line number. Append another " + "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("a"); setDefaultIncludedByDefault(true); setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index 8d7d699a693..c8d39d5403d 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -20,9 +20,9 @@ CurrentProjectFilter::CurrentProjectFilter() { setId("Files in current project"); setDisplayName(Tr::tr("Files in Current Project")); - setDescription(Tr::tr("Matches all files from the current document's project. Append \"+\" " - "or \":\" to jump to the given line number. Append another " - "\"+\" or \":\" to jump to the column number as well.")); + setDescription(Tr::tr("Locates files from the current document's project. Append \"+\" " + "or \":\" to jump to the given line number. Append another " + "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("p"); setDefaultIncludedByDefault(false); setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 7e4938a2042..57fe61080e1 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -4357,10 +4357,9 @@ AllProjectFilesFilter::AllProjectFilesFilter() setDefaultIncludedByDefault(false); // but not included in default setFilters({}); setIsCustomFilter(false); - setDescription(Tr::tr( - "Matches all files from all project directories. Append \"+\" or " - "\":\" to jump to the given line number. Append another " - "\"+\" or \":\" to jump to the column number as well.")); + setDescription(Tr::tr("Locates files from all project directories. Append \"+\" or " + "\":\" to jump to the given line number. Append another " + "\"+\" or \":\" to jump to the column number as well.")); ProjectManager *projectManager = ProjectManager::instance(); QTC_ASSERT(projectManager, return); @@ -4440,8 +4439,8 @@ static RunConfiguration *runConfigurationForDisplayName(const QString &displayNa RunRunConfigurationLocatorFilter::RunRunConfigurationLocatorFilter() { setId("Run run configuration"); - setDisplayName(Tr::tr("Run run configuration")); - setDescription(Tr::tr("Run a run configuration of the current active project")); + setDisplayName(Tr::tr("Run Run Configuration")); + setDescription(Tr::tr("Runs a run configuration of the active project.")); setDefaultShortcutString("rr"); setPriority(Medium); } @@ -4463,8 +4462,8 @@ void RunRunConfigurationLocatorFilter::accept(const LocatorFilterEntry &selectio SwitchToRunConfigurationLocatorFilter::SwitchToRunConfigurationLocatorFilter() { setId("Switch run configuration"); - setDisplayName(Tr::tr("Switch run configuration")); - setDescription(Tr::tr("Switch active run configuration")); + setDisplayName(Tr::tr("Switch Run Configuration")); + setDescription(Tr::tr("Switches the active run configuration of the active project.")); setDefaultShortcutString("sr"); setPriority(Medium); } diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 8d6206d0c9f..22050f7a9c7 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -20,6 +20,7 @@ FunctionFilter::FunctionFilter(LocatorData *data, QObject *parent) { setId("Functions"); setDisplayName(Tr::tr("QML Functions")); + setDescription(Tr::tr("Locates QML functions in any open project.")); setDefaultShortcutString("m"); setDefaultIncludedByDefault(false); } From dde4a7ebf5fd8366b3c70acfea205641f22e43ff Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 6 Apr 2023 17:29:18 +0200 Subject: [PATCH 0562/1447] Qnx: Re-work item store This reduces the number of updates from the env* files and overall simplifies the architecture. I actually believe that it would be better if the whole configuration settings page would not exist but be part of the device settings page. Change-Id: I4184b74fc2c9695356752903c861f3758a6d7c73 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/qnx/CMakeLists.txt | 2 - src/plugins/qnx/qnx.qbs | 4 - src/plugins/qnx/qnxconfiguration.cpp | 466 --------------- src/plugins/qnx/qnxconfiguration.h | 114 ---- src/plugins/qnx/qnxconfigurationmanager.cpp | 124 ---- src/plugins/qnx/qnxconfigurationmanager.h | 41 -- src/plugins/qnx/qnxplugin.cpp | 8 +- src/plugins/qnx/qnxsettingspage.cpp | 615 ++++++++++++++++++-- src/plugins/qnx/qnxsettingspage.h | 6 + src/plugins/qnx/qnxtoolchain.cpp | 8 +- src/plugins/qnx/qnxutils.cpp | 9 + src/plugins/qnx/qnxutils.h | 10 +- 12 files changed, 576 insertions(+), 831 deletions(-) delete mode 100644 src/plugins/qnx/qnxconfiguration.cpp delete mode 100644 src/plugins/qnx/qnxconfiguration.h delete mode 100644 src/plugins/qnx/qnxconfigurationmanager.cpp delete mode 100644 src/plugins/qnx/qnxconfigurationmanager.h diff --git a/src/plugins/qnx/CMakeLists.txt b/src/plugins/qnx/CMakeLists.txt index 7d842aa61ac..8d0c6751b3f 100644 --- a/src/plugins/qnx/CMakeLists.txt +++ b/src/plugins/qnx/CMakeLists.txt @@ -4,8 +4,6 @@ add_qtc_plugin(Qnx SOURCES qnx.qrc qnxanalyzesupport.cpp qnxanalyzesupport.h - qnxconfiguration.cpp qnxconfiguration.h - qnxconfigurationmanager.cpp qnxconfigurationmanager.h qnxconstants.h qnxdebugsupport.cpp qnxdebugsupport.h qnxdeployqtlibrariesdialog.cpp qnxdeployqtlibrariesdialog.h diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index ee1752f816f..ad4eae91c83 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -20,8 +20,6 @@ QtcPlugin { "qnxtoolchain.h", "qnx.qrc", "qnxconstants.h", - "qnxconfiguration.cpp", - "qnxconfiguration.h", "qnxanalyzesupport.cpp", "qnxanalyzesupport.h", "qnxdebugsupport.cpp", @@ -30,8 +28,6 @@ QtcPlugin { "qnxdevice.h", "qnxdevicetester.cpp", "qnxdevicetester.h", - "qnxconfigurationmanager.cpp", - "qnxconfigurationmanager.h", "qnxsettingspage.cpp", "qnxsettingspage.h", "qnxtr.h", diff --git a/src/plugins/qnx/qnxconfiguration.cpp b/src/plugins/qnx/qnxconfiguration.cpp deleted file mode 100644 index 0ca024248a8..00000000000 --- a/src/plugins/qnx/qnxconfiguration.cpp +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qnxconfiguration.h" - -#include "qnxqtversion.h" -#include "qnxutils.h" -#include "qnxtoolchain.h" -#include "qnxtr.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#include -#include -#include - -using namespace ProjectExplorer; -using namespace QtSupport; -using namespace Utils; -using namespace Debugger; - -namespace Qnx::Internal { - -const QLatin1String QNXEnvFileKey("EnvFile"); -const QLatin1String QNXVersionKey("QNXVersion"); -// For backward compatibility -const QLatin1String SdpEnvFileKey("NDKEnvFile"); - -const QLatin1String QNXConfiguration("QNX_CONFIGURATION"); -const QLatin1String QNXTarget("QNX_TARGET"); -const QLatin1String QNXHost("QNX_HOST"); - -QnxConfiguration::QnxConfiguration() = default; - -QnxConfiguration::QnxConfiguration(const FilePath &sdpEnvFile) -{ - setDefaultConfiguration(sdpEnvFile); - readInformation(); -} - -QnxConfiguration::QnxConfiguration(const QVariantMap &data) -{ - QString envFilePath = data.value(QNXEnvFileKey).toString(); - if (envFilePath.isEmpty()) - envFilePath = data.value(SdpEnvFileKey).toString(); - - m_version = QnxVersionNumber(data.value(QNXVersionKey).toString()); - - setDefaultConfiguration(FilePath::fromString(envFilePath)); - readInformation(); -} - -FilePath QnxConfiguration::envFile() const -{ - return m_envFile; -} - -FilePath QnxConfiguration::qnxTarget() const -{ - return m_qnxTarget; -} - -FilePath QnxConfiguration::qnxHost() const -{ - return m_qnxHost; -} - -FilePath QnxConfiguration::qccCompilerPath() const -{ - return m_qccCompiler; -} - -EnvironmentItems QnxConfiguration::qnxEnv() const -{ - return m_qnxEnv; -} - -QnxVersionNumber QnxConfiguration::version() const -{ - return m_version; -} - -QVariantMap QnxConfiguration::toMap() const -{ - QVariantMap data; - data.insert(QLatin1String(QNXEnvFileKey), m_envFile.toString()); - data.insert(QLatin1String(QNXVersionKey), m_version.toString()); - return data; -} - -bool QnxConfiguration::isValid() const -{ - return !m_qccCompiler.isEmpty() && !m_targets.isEmpty(); -} - -QString QnxConfiguration::displayName() const -{ - return m_configName; -} - -bool QnxConfiguration::activate() -{ - if (isActive()) - return true; - - if (!isValid()) { - QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Cannot Set Up QNX Configuration"), - validationErrorMessage(), QMessageBox::Ok); - return false; - } - - for (const Target &target : std::as_const(m_targets)) - createTools(target); - - return true; -} - -void QnxConfiguration::deactivate() -{ - if (!isActive()) - return; - - const Toolchains toolChainsToRemove = - ToolChainManager::toolchains(Utils::equal(&ToolChain::compilerCommand, qccCompilerPath())); - - QList debuggersToRemove; - const QList debuggerItems = DebuggerItemManager::debuggers(); - for (const DebuggerItem &debuggerItem : debuggerItems) { - if (findTargetByDebuggerPath(debuggerItem.command())) - debuggersToRemove.append(debuggerItem); - } - - const QList kits = KitManager::kits(); - for (Kit *kit : kits) { - if (kit->isAutoDetected() - && DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE - && toolChainsToRemove.contains(ToolChainKitAspect::cxxToolChain(kit))) { - KitManager::deregisterKit(kit); - } - } - - for (ToolChain *tc : toolChainsToRemove) - ToolChainManager::deregisterToolChain(tc); - - for (const DebuggerItem &debuggerItem : std::as_const(debuggersToRemove)) - DebuggerItemManager::deregisterDebugger(debuggerItem.id()); -} - -bool QnxConfiguration::isActive() const -{ - const bool hasToolChain = ToolChainManager::toolChain(Utils::equal(&ToolChain::compilerCommand, - qccCompilerPath())); - const bool hasDebugger = Utils::contains(DebuggerItemManager::debuggers(), [this](const DebuggerItem &di) { - return findTargetByDebuggerPath(di.command()); - }); - - return hasToolChain && hasDebugger; -} - -FilePath QnxConfiguration::sdpPath() const -{ - return envFile().parentDir(); -} - -QnxQtVersion *QnxConfiguration::qnxQtVersion(const Target &target) const -{ - const QtVersions versions = QtVersionManager::versions( - Utils::equal(&QtVersion::type, QString::fromLatin1(Constants::QNX_QNX_QT))); - for (QtVersion *version : versions) { - auto qnxQt = dynamic_cast(version); - if (qnxQt && qnxQt->sdpPath() == sdpPath()) { - const Abis abis = version->qtAbis(); - for (const Abi &qtAbi : abis) { - if ((qtAbi == target.m_abi) && (qnxQt->cpuDir() == target.cpuDir())) - return qnxQt; - } - } - } - return nullptr; -} - -QList QnxConfiguration::autoDetect(const QList &alreadyKnown) -{ - QList result; - - for (const Target &target : std::as_const(m_targets)) - result += findToolChain(alreadyKnown, target.m_abi); - - return result; -} - -void QnxConfiguration::createTools(const Target &target) -{ - QnxToolChainMap toolchainMap = createToolChain(target); - QVariant debuggerId = createDebugger(target); - createKit(target, toolchainMap, debuggerId); -} - -QVariant QnxConfiguration::createDebugger(const Target &target) -{ - Environment sysEnv = m_qnxHost.deviceEnvironment(); - sysEnv.modify(qnxEnvironmentItems()); - - Debugger::DebuggerItem debugger; - debugger.setCommand(target.m_debuggerPath); - debugger.reinitializeFromFile(nullptr, &sysEnv); - debugger.setUnexpandedDisplayName(Tr::tr("Debugger for %1 (%2)") - .arg(displayName()) - .arg(target.shortDescription())); - return Debugger::DebuggerItemManager::registerDebugger(debugger); -} - -QnxConfiguration::QnxToolChainMap QnxConfiguration::createToolChain(const Target &target) -{ - QnxToolChainMap toolChainMap; - - for (auto language : { ProjectExplorer::Constants::C_LANGUAGE_ID, - ProjectExplorer::Constants::CXX_LANGUAGE_ID}) { - auto toolChain = new QnxToolChain; - toolChain->setDetection(ToolChain::AutoDetection); - toolChain->setLanguage(language); - toolChain->setTargetAbi(target.m_abi); - toolChain->setDisplayName(Tr::tr("QCC for %1 (%2)") - .arg(displayName()) - .arg(target.shortDescription())); - toolChain->setSdpPath(sdpPath()); - toolChain->setCpuDir(target.cpuDir()); - toolChain->resetToolChain(qccCompilerPath()); - ToolChainManager::registerToolChain(toolChain); - - toolChainMap.insert({language, toolChain}); - } - - return toolChainMap; -} - -QList QnxConfiguration::findToolChain(const QList &alreadyKnown, - const Abi &abi) -{ - return Utils::filtered(alreadyKnown, [this, abi](ToolChain *tc) { - return tc->typeId() == Constants::QNX_TOOLCHAIN_ID - && tc->targetAbi() == abi - && tc->compilerCommand() == m_qccCompiler; - }); -} - -void QnxConfiguration::createKit(const Target &target, const QnxToolChainMap &toolChainMap, - const QVariant &debugger) -{ - QnxQtVersion *qnxQt = qnxQtVersion(target); // nullptr is ok. - - const auto init = [&](Kit *k) { - QtKitAspect::setQtVersion(k, qnxQt); - ToolChainKitAspect::setToolChain(k, toolChainMap.at(ProjectExplorer::Constants::C_LANGUAGE_ID)); - ToolChainKitAspect::setToolChain(k, toolChainMap.at(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); - - if (debugger.isValid()) - DebuggerKitAspect::setDebugger(k, debugger); - - DeviceTypeKitAspect::setDeviceTypeId(k, Constants::QNX_QNX_OS_TYPE); - // TODO: Add sysroot? - - k->setUnexpandedDisplayName(Tr::tr("Kit for %1 (%2)") - .arg(displayName()) - .arg(target.shortDescription())); - - k->setAutoDetected(false); - k->setAutoDetectionSource(envFile().toString()); - k->setMutable(DeviceKitAspect::id(), true); - - k->setSticky(ToolChainKitAspect::id(), true); - k->setSticky(DeviceTypeKitAspect::id(), true); - k->setSticky(SysRootKitAspect::id(), true); - k->setSticky(DebuggerKitAspect::id(), true); - k->setSticky(QmakeProjectManager::Constants::KIT_INFORMATION_ID, true); - - EnvironmentKitAspect::setEnvironmentChanges(k, qnxEnvironmentItems()); - }; - - // add kit with device and qt version not sticky - KitManager::registerKit(init); -} - -QString QnxConfiguration::validationErrorMessage() const -{ - if (isValid()) - return {}; - - QStringList errorStrings - = {Tr::tr("The following errors occurred while activating the QNX configuration:")}; - if (m_qccCompiler.isEmpty()) - errorStrings << Tr::tr("- No GCC compiler found."); - if (m_targets.isEmpty()) - errorStrings << Tr::tr("- No targets found."); - return errorStrings.join('\n'); -} - -void QnxConfiguration::setVersion(const QnxVersionNumber &version) -{ - m_version = version; -} - -void QnxConfiguration::readInformation() -{ - const FilePath configPath = m_qnxConfiguration / "qconfig"; - if (!configPath.isDir()) - return; - - configPath.iterateDirectory([this, configPath](const FilePath &sdpFile) { - QFile xmlFile(sdpFile.toFSPathString()); - if (!xmlFile.open(QIODevice::ReadOnly)) - return IterationPolicy::Continue; - - QDomDocument doc; - if (!doc.setContent(&xmlFile)) // Skip error message - return IterationPolicy::Continue; - - QDomElement docElt = doc.documentElement(); - if (docElt.tagName() != QLatin1String("qnxSystemDefinition")) - return IterationPolicy::Continue; - - QDomElement childElt = docElt.firstChildElement(QLatin1String("installation")); - // The file contains only one installation node - if (childElt.isNull()) // The file contains only one base node - return IterationPolicy::Continue; - - FilePath host = configPath.withNewPath( - childElt.firstChildElement(QLatin1String("host")).text()).canonicalPath(); - if (m_qnxHost != host) - return IterationPolicy::Continue; - - FilePath target = configPath.withNewPath( - childElt.firstChildElement(QLatin1String("target")).text()).canonicalPath(); - if (m_qnxTarget != target) - return IterationPolicy::Continue; - - m_configName = childElt.firstChildElement(QLatin1String("name")).text(); - QString version = childElt.firstChildElement(QLatin1String("version")).text(); - setVersion(QnxVersionNumber(version)); - return IterationPolicy::Stop; - }, {{"*.xml"}, QDir::Files}); -} - -void QnxConfiguration::setDefaultConfiguration(const FilePath &envScript) -{ - QTC_ASSERT(!envScript.isEmpty(), return); - m_envFile = envScript; - m_qnxEnv = QnxUtils::qnxEnvironmentFromEnvFile(m_envFile); - for (const EnvironmentItem &item : std::as_const(m_qnxEnv)) { - if (item.name == QNXConfiguration) - m_qnxConfiguration = envScript.withNewPath(item.value).canonicalPath(); - else if (item.name == QNXTarget) - m_qnxTarget = envScript.withNewPath(item.value).canonicalPath(); - else if (item.name == QNXHost) - m_qnxHost = envScript.withNewPath(item.value).canonicalPath(); - } - - const FilePath qccPath = m_qnxHost.pathAppended("usr/bin/qcc").withExecutableSuffix(); - if (qccPath.exists()) - m_qccCompiler = qccPath; - - // Some fall back in case the qconfig dir with .xml files is not found later - if (m_configName.isEmpty()) - m_configName = QString("%1 - %2").arg(m_qnxHost.fileName(), m_qnxTarget.fileName()); - - updateTargets(); - assignDebuggersToTargets(); - - // Remove debuggerless targets. - Utils::erase(m_targets, [](const Target &target) { - if (target.m_debuggerPath.isEmpty()) - qWarning() << "No debugger found for" << target.m_path << "... discarded"; - return target.m_debuggerPath.isEmpty(); - }); -} - -EnvironmentItems QnxConfiguration::qnxEnvironmentItems() const -{ - Utils::EnvironmentItems envList; - envList.push_back(EnvironmentItem(QNXConfiguration, m_qnxConfiguration.path())); - envList.push_back(EnvironmentItem(QNXTarget, m_qnxTarget.path())); - envList.push_back(EnvironmentItem(QNXHost, m_qnxHost.path())); - - return envList; -} - -const QnxConfiguration::Target *QnxConfiguration::findTargetByDebuggerPath( - const FilePath &path) const -{ - const auto it = std::find_if(m_targets.begin(), m_targets.end(), - [path](const Target &target) { return target.m_debuggerPath == path; }); - return it == m_targets.end() ? nullptr : &(*it); -} - -void QnxConfiguration::updateTargets() -{ - m_targets.clear(); - const QList targets = QnxUtils::findTargets(m_qnxTarget); - for (const QnxTarget &target : targets) - m_targets.append(Target(target.m_abi, target.m_path)); -} - -void QnxConfiguration::assignDebuggersToTargets() -{ - const FilePath hostUsrBinDir = m_qnxHost.pathAppended("usr/bin"); - QString pattern = "nto*-gdb"; - if (m_qnxHost.osType() == Utils::OsTypeWindows) - pattern += ".exe"; - - const FilePaths debuggerNames = hostUsrBinDir.dirEntries({{pattern}, QDir::Files}); - Environment sysEnv = m_qnxHost.deviceEnvironment(); - sysEnv.modify(qnxEnvironmentItems()); - - for (const FilePath &debuggerPath : debuggerNames) { - DebuggerItem item; - item.setCommand(debuggerPath); - item.reinitializeFromFile(nullptr, &sysEnv); - bool found = false; - for (const Abi &abi : item.abis()) { - for (Target &target : m_targets) { - if (target.m_abi.isCompatibleWith(abi)) { - found = true; - - if (target.m_debuggerPath.isEmpty()) { - target.m_debuggerPath = debuggerPath; - } else { - qWarning() << debuggerPath << "has the same ABI as" << target.m_debuggerPath - << "... discarded"; - break; - } - } - } - } - if (!found) - qWarning() << "No target found for" << debuggerPath.toUserOutput() << "... discarded"; - } -} - -QString QnxConfiguration::Target::shortDescription() const -{ - return QnxUtils::cpuDirShortDescription(cpuDir()); -} - -QString QnxConfiguration::Target::cpuDir() const -{ - return m_path.fileName(); -} - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxconfiguration.h b/src/plugins/qnx/qnxconfiguration.h deleted file mode 100644 index 34056536c35..00000000000 --- a/src/plugins/qnx/qnxconfiguration.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "qnxconstants.h" -#include "qnxversionnumber.h" - -#include -#include - -#include - -#include - -#include - -namespace ProjectExplorer -{ - class Kit; - class ToolChain; -} - -namespace Qnx::Internal { - -class QnxToolChain; -class QnxQtVersion; - -class QnxConfiguration -{ -public: - QnxConfiguration(); - QnxConfiguration(const Utils::FilePath &sdpEnvFile); - QnxConfiguration(const QVariantMap &data); - - Utils::FilePath envFile() const; - Utils::FilePath qnxTarget() const; - Utils::FilePath qnxHost() const; - Utils::FilePath qccCompilerPath() const; - Utils::EnvironmentItems qnxEnv() const; - QnxVersionNumber version() const; - QVariantMap toMap() const; - - bool isValid() const; - - QString displayName() const; - bool activate(); - void deactivate(); - bool isActive() const; - Utils::FilePath sdpPath() const; - - QList autoDetect( - const QList &alreadyKnown); - -private: - QList findToolChain( - const QList &alreadyKnown, - const ProjectExplorer::Abi &abi); - - QString validationErrorMessage() const; - - void setVersion(const QnxVersionNumber& version); - - void readInformation(); - - void setDefaultConfiguration(const Utils::FilePath &envScript); - - Utils::EnvironmentItems qnxEnvironmentItems() const; - - QString m_configName; - - Utils::FilePath m_envFile; - Utils::FilePath m_qnxConfiguration; - Utils::FilePath m_qnxTarget; - Utils::FilePath m_qnxHost; - Utils::FilePath m_qccCompiler; - Utils::EnvironmentItems m_qnxEnv; - QnxVersionNumber m_version; - - class Target - { - public: - Target(const ProjectExplorer::Abi &abi, const Utils::FilePath &path) - : m_abi(abi), m_path(path) - { - } - - QString shortDescription() const; - QString cpuDir() const; - - ProjectExplorer::Abi m_abi; - Utils::FilePath m_path; - Utils::FilePath m_debuggerPath; - }; - - QList m_targets; - - QnxQtVersion *qnxQtVersion(const Target &target) const; - - void createTools(const Target &target); - QVariant createDebugger(const Target &target); - - using QnxToolChainMap = std::map; - - QnxToolChainMap createToolChain(const Target &target); - void createKit(const Target &target, const QnxToolChainMap &toolChain, const QVariant &debugger); - - const Target *findTargetByDebuggerPath(const Utils::FilePath &path) const; - - void updateTargets(); - void assignDebuggersToTargets(); -}; - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxconfigurationmanager.cpp b/src/plugins/qnx/qnxconfigurationmanager.cpp deleted file mode 100644 index da585b69cf2..00000000000 --- a/src/plugins/qnx/qnxconfigurationmanager.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qnxconfigurationmanager.h" - -#include "qnxconfiguration.h" - -#include - -#include -#include - -using namespace Utils; - -namespace Qnx::Internal { - -const QLatin1String QNXConfigDataKey("QNXConfiguration."); -const QLatin1String QNXConfigCountKey("QNXConfiguration.Count"); -const QLatin1String QNXConfigsFileVersionKey("Version"); - -static FilePath qnxConfigSettingsFileName() -{ - return Core::ICore::userResourcePath("qnx/qnxconfigurations.xml"); -} - -static QnxConfigurationManager *m_instance = nullptr; - -QnxConfigurationManager::QnxConfigurationManager() -{ - m_instance = this; - m_writer = new PersistentSettingsWriter(qnxConfigSettingsFileName(), "QnxConfigurations"); - connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, - this, &QnxConfigurationManager::saveConfigs); -} - -QnxConfigurationManager *QnxConfigurationManager::instance() -{ - return m_instance; -} - -QnxConfigurationManager::~QnxConfigurationManager() -{ - m_instance = nullptr; - qDeleteAll(m_configurations); - delete m_writer; -} - -QList QnxConfigurationManager::configurations() const -{ - return m_configurations; -} - -void QnxConfigurationManager::removeConfiguration(QnxConfiguration *config) -{ - if (m_configurations.removeAll(config)) { - delete config; - emit configurationsListUpdated(); - } -} - -bool QnxConfigurationManager::addConfiguration(QnxConfiguration *config) -{ - if (!config || !config->isValid()) - return false; - - for (QnxConfiguration *c : std::as_const(m_configurations)) { - if (c->envFile() == config->envFile()) - return false; - } - - m_configurations.append(config); - emit configurationsListUpdated(); - return true; -} - -QnxConfiguration *QnxConfigurationManager::configurationFromEnvFile(const FilePath &envFile) const -{ - for (QnxConfiguration *c : m_configurations) { - if (c->envFile() == envFile) - return c; - } - - return nullptr; -} - -void QnxConfigurationManager::saveConfigs() -{ - QTC_ASSERT(m_writer, return); - QVariantMap data; - data.insert(QLatin1String(QNXConfigsFileVersionKey), 1); - int count = 0; - for (QnxConfiguration *config : std::as_const(m_configurations)) { - QVariantMap tmp = config->toMap(); - if (tmp.isEmpty()) - continue; - - data.insert(QNXConfigDataKey + QString::number(count), tmp); - ++count; - } - - data.insert(QLatin1String(QNXConfigCountKey), count); - m_writer->save(data, Core::ICore::dialogParent()); -} - -void QnxConfigurationManager::restoreConfigurations() -{ - PersistentSettingsReader reader; - if (!reader.load(qnxConfigSettingsFileName())) - return; - - QVariantMap data = reader.restoreValues(); - int count = data.value(QNXConfigCountKey, 0).toInt(); - for (int i = 0; i < count; ++i) { - const QString key = QNXConfigDataKey + QString::number(i); - if (!data.contains(key)) - continue; - - const QVariantMap dMap = data.value(key).toMap(); - auto configuration = new QnxConfiguration(dMap); - addConfiguration(configuration); - } -} - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxconfigurationmanager.h b/src/plugins/qnx/qnxconfigurationmanager.h deleted file mode 100644 index bc0d02dd988..00000000000 --- a/src/plugins/qnx/qnxconfigurationmanager.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2016 BlackBerry Limited. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Utils { class PersistentSettingsWriter; } - -namespace Qnx::Internal { - -class QnxConfiguration; -class QnxPlugin; - -class QnxConfigurationManager: public QObject -{ - Q_OBJECT -public: - QnxConfigurationManager(); - ~QnxConfigurationManager() override; - - void restoreConfigurations(); - - static QnxConfigurationManager *instance(); - QList configurations() const; - void removeConfiguration(QnxConfiguration *config); - bool addConfiguration(QnxConfiguration *config); - QnxConfiguration* configurationFromEnvFile(const Utils::FilePath &envFile) const; - -protected slots: - void saveConfigs(); - -signals: - void configurationsListUpdated(); - -private: - QList m_configurations; - Utils::PersistentSettingsWriter *m_writer; -}; - -} // Qnx::Internal diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index ef09b0b7b46..09fd528086c 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qnxanalyzesupport.h" -#include "qnxconfigurationmanager.h" #include "qnxconstants.h" #include "qnxdebugsupport.h" #include "qnxdevice.h" @@ -80,7 +79,7 @@ public: QAction *m_debugSeparator = nullptr; QAction m_attachToQnxApplication{Tr::tr("Attach to remote QNX application..."), nullptr}; - QnxConfigurationManager configurationManager; + QnxSettingsPage settingsPage; QnxQtVersionFactory qtVersionFactory; QnxDeviceFactory deviceFactory; QnxDeployConfigurationFactory deployConfigFactory; @@ -88,7 +87,6 @@ public: Constants::QNX_DIRECT_UPLOAD_STEP_ID}; QnxDeployStepFactory makeInstallStepFactory{RemoteLinux::Constants::MakeInstallStepId}; QnxRunConfigurationFactory runConfigFactory; - QnxSettingsPage settingsPage; QnxToolChainFactory toolChainFactory; SimpleTargetRunnerFactory runWorkerFactory{{runConfigFactory.runConfigurationId()}}; QnxDebugWorkerFactory debugWorkerFactory; @@ -112,10 +110,6 @@ private: void QnxPlugin::extensionsInitialized() { - // Can't do yet as not all devices are around. - connect(DeviceManager::instance(), &DeviceManager::devicesLoaded, - &d->configurationManager, &QnxConfigurationManager::restoreConfigurations); - // Attach support connect(&d->m_attachToQnxApplication, &QAction::triggered, this, &showAttachToProcessDialog); diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 0d354037735..119c7a3e2a0 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -3,29 +3,481 @@ #include "qnxsettingspage.h" -#include "qnxconfiguration.h" -#include "qnxconfigurationmanager.h" +#include "qnxqtversion.h" +#include "qnxtoolchain.h" #include "qnxtr.h" +#include "qnxutils.h" +#include "qnxversionnumber.h" #include +#include +#include +#include + +#include #include +#include +#include +#include +#include +#include #include +#include +#include + +#include #include +#include +#include #include #include +#include +#include #include #include #include #include +using namespace ProjectExplorer; +using namespace QtSupport; using namespace Utils; +using namespace Debugger; namespace Qnx::Internal { +const QLatin1String QNXEnvFileKey("EnvFile"); +const QLatin1String QNXVersionKey("QNXVersion"); +// For backward compatibility +const QLatin1String SdpEnvFileKey("NDKEnvFile"); + +const QLatin1String QNXConfiguration("QNX_CONFIGURATION"); +const QLatin1String QNXTarget("QNX_TARGET"); +const QLatin1String QNXHost("QNX_HOST"); + +const QLatin1String QNXConfigDataKey("QNXConfiguration."); +const QLatin1String QNXConfigCountKey("QNXConfiguration.Count"); +const QLatin1String QNXConfigsFileVersionKey("Version"); + +static FilePath qnxConfigSettingsFileName() +{ + return Core::ICore::userResourcePath("qnx/qnxconfigurations.xml"); +} + +class QnxConfiguration +{ +public: + QnxConfiguration() = default; + explicit QnxConfiguration(const FilePath &envFile) { m_envFile = envFile; } + + void fromMap(const QVariantMap &data) + { + QString envFilePath = data.value(QNXEnvFileKey).toString(); + if (envFilePath.isEmpty()) + envFilePath = data.value(SdpEnvFileKey).toString(); + + m_version = QnxVersionNumber(data.value(QNXVersionKey).toString()); + m_envFile = FilePath::fromString(envFilePath); + } + + QVariantMap toMap() const + { + QVariantMap data; + data.insert(QLatin1String(QNXEnvFileKey), m_envFile.toString()); + data.insert(QLatin1String(QNXVersionKey), m_version.toString()); + return data; + } + + bool isValid() const + { + return !m_qccCompiler.isEmpty() && !m_targets.isEmpty(); + } + + bool isActive() const + { + const bool hasToolChain = ToolChainManager::toolChain(Utils::equal(&ToolChain::compilerCommand, + m_qccCompiler)); + const bool hasDebugger = Utils::contains(DebuggerItemManager::debuggers(), [this](const DebuggerItem &di) { + return findTargetByDebuggerPath(di.command()); + }); + return hasToolChain && hasDebugger; + } + + void activate(); + void deactivate(); + + void ensureContents() const; + void mutableEnsureContents(); + + EnvironmentItems qnxEnvironmentItems() const; + + QnxQtVersion *qnxQtVersion(const QnxTarget &target) const; + + void createKit(const QnxTarget &target); + QVariant createDebugger(const QnxTarget &target); + Toolchains createToolChains(const QnxTarget &target); + + const QnxTarget *findTargetByDebuggerPath(const Utils::FilePath &path) const; + + bool m_hasContents = false; + QString m_configName; + + FilePath m_envFile; + FilePath m_qnxConfiguration; + FilePath m_qnxTarget; + FilePath m_qnxHost; + FilePath m_qccCompiler; + EnvironmentItems m_qnxEnv; + QnxVersionNumber m_version; + + QList m_targets; +}; + +void QnxConfiguration::activate() +{ + ensureContents(); + + if (!isValid()) { + QStringList errorStrings + = {Tr::tr("The following errors occurred while activating the QNX configuration:")}; + if (m_qccCompiler.isEmpty()) + errorStrings << Tr::tr("- No GCC compiler found."); + if (m_targets.isEmpty()) + errorStrings << Tr::tr("- No targets found."); + const QString msg = errorStrings.join('\n'); + + QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Cannot Set Up QNX Configuration"), + msg, QMessageBox::Ok); + return; + } + + for (const QnxTarget &target : std::as_const(m_targets)) + createKit(target); +} + +void QnxConfiguration::deactivate() +{ + QTC_ASSERT(isActive(), return); + + const Toolchains toolChainsToRemove = + ToolChainManager::toolchains(Utils::equal(&ToolChain::compilerCommand, m_qccCompiler)); + + QList debuggersToRemove; + const QList debuggerItems = DebuggerItemManager::debuggers(); + for (const DebuggerItem &debuggerItem : debuggerItems) { + if (findTargetByDebuggerPath(debuggerItem.command())) + debuggersToRemove.append(debuggerItem); + } + + const QList kits = KitManager::kits(); + for (Kit *kit : kits) { + if (kit->isAutoDetected() + && DeviceTypeKitAspect::deviceTypeId(kit) == Constants::QNX_QNX_OS_TYPE + && toolChainsToRemove.contains(ToolChainKitAspect::cxxToolChain(kit))) { + KitManager::deregisterKit(kit); + } + } + + for (ToolChain *tc : toolChainsToRemove) + ToolChainManager::deregisterToolChain(tc); + + for (const DebuggerItem &debuggerItem : std::as_const(debuggersToRemove)) + DebuggerItemManager::deregisterDebugger(debuggerItem.id()); +} + +QnxQtVersion *QnxConfiguration::qnxQtVersion(const QnxTarget &target) const +{ + const QtVersions versions = QtVersionManager::versions( + Utils::equal(&QtVersion::type, QString::fromLatin1(Constants::QNX_QNX_QT))); + for (QtVersion *version : versions) { + auto qnxQt = dynamic_cast(version); + if (qnxQt && qnxQt->sdpPath() == m_envFile.parentDir()) { + const Abis abis = version->qtAbis(); + for (const Abi &qtAbi : abis) { + if (qtAbi == target.m_abi && qnxQt->cpuDir() == target.cpuDir()) + return qnxQt; + } + } + } + return nullptr; +} + +QVariant QnxConfiguration::createDebugger(const QnxTarget &target) +{ + Environment sysEnv = m_qnxHost.deviceEnvironment(); + sysEnv.modify(qnxEnvironmentItems()); + + Debugger::DebuggerItem debugger; + debugger.setCommand(target.m_debuggerPath); + debugger.reinitializeFromFile(nullptr, &sysEnv); + debugger.setUnexpandedDisplayName(Tr::tr("Debugger for %1 (%2)") + .arg(m_configName) + .arg(target.shortDescription())); + return Debugger::DebuggerItemManager::registerDebugger(debugger); +} + +Toolchains QnxConfiguration::createToolChains(const QnxTarget &target) +{ + Toolchains toolChains; + + for (const Id language : {ProjectExplorer::Constants::C_LANGUAGE_ID, + ProjectExplorer::Constants::CXX_LANGUAGE_ID}) { + auto toolChain = new QnxToolChain; + toolChain->setDetection(ToolChain::AutoDetection); + toolChain->setLanguage(language); + toolChain->setTargetAbi(target.m_abi); + toolChain->setDisplayName(Tr::tr("QCC for %1 (%2)") + .arg(m_configName) + .arg(target.shortDescription())); + toolChain->setSdpPath(m_envFile.parentDir()); + toolChain->setCpuDir(target.cpuDir()); + toolChain->resetToolChain(m_qccCompiler); + ToolChainManager::registerToolChain(toolChain); + + toolChains.append(toolChain); + } + + return toolChains; +} + +void QnxConfiguration::createKit(const QnxTarget &target) +{ + Toolchains toolChains = createToolChains(target); + QVariant debugger = createDebugger(target); + + QnxQtVersion *qnxQt = qnxQtVersion(target); // nullptr is ok. + + const auto init = [&](Kit *k) { + QtKitAspect::setQtVersion(k, qnxQt); + ToolChainKitAspect::setToolChain(k, toolChains[0]); + ToolChainKitAspect::setToolChain(k, toolChains[1]); + + if (debugger.isValid()) + DebuggerKitAspect::setDebugger(k, debugger); + + DeviceTypeKitAspect::setDeviceTypeId(k, Constants::QNX_QNX_OS_TYPE); + // TODO: Add sysroot? + + k->setUnexpandedDisplayName(Tr::tr("Kit for %1 (%2)") + .arg(m_configName) + .arg(target.shortDescription())); + + k->setAutoDetected(false); + k->setAutoDetectionSource(m_envFile.toString()); + k->setMutable(DeviceKitAspect::id(), true); + + k->setSticky(ToolChainKitAspect::id(), true); + k->setSticky(DeviceTypeKitAspect::id(), true); + k->setSticky(SysRootKitAspect::id(), true); + k->setSticky(DebuggerKitAspect::id(), true); + k->setSticky(QmakeProjectManager::Constants::KIT_INFORMATION_ID, true); + + EnvironmentKitAspect::setEnvironmentChanges(k, qnxEnvironmentItems()); + }; + + // add kit with device and qt version not sticky + KitManager::registerKit(init); +} + +void QnxConfiguration::ensureContents() const +{ + if (!m_hasContents) + const_cast(this)->mutableEnsureContents(); +} + +void QnxConfiguration::mutableEnsureContents() +{ + QTC_ASSERT(!m_envFile.isEmpty(), return); + m_hasContents = true; + + m_qnxEnv = QnxUtils::qnxEnvironmentFromEnvFile(m_envFile); + for (const EnvironmentItem &item : std::as_const(m_qnxEnv)) { + if (item.name == QNXConfiguration) + m_qnxConfiguration = m_envFile.withNewPath(item.value).canonicalPath(); + else if (item.name == QNXTarget) + m_qnxTarget = m_envFile.withNewPath(item.value).canonicalPath(); + else if (item.name == QNXHost) + m_qnxHost = m_envFile.withNewPath(item.value).canonicalPath(); + } + + const FilePath qccPath = m_qnxHost.pathAppended("usr/bin/qcc").withExecutableSuffix(); + if (qccPath.exists()) + m_qccCompiler = qccPath; + + // Some fallback in case the qconfig dir with .xml files is not found later. + if (m_configName.isEmpty()) + m_configName = QString("%1 - %2").arg(m_qnxHost.fileName(), m_qnxTarget.fileName()); + + m_targets = QnxUtils::findTargets(m_qnxTarget); + + // Assign debuggers. + const FilePath hostUsrBinDir = m_qnxHost.pathAppended("usr/bin"); + QString pattern = "nto*-gdb"; + if (m_qnxHost.osType() == Utils::OsTypeWindows) + pattern += ".exe"; + + const FilePaths debuggerNames = hostUsrBinDir.dirEntries({{pattern}, QDir::Files}); + Environment sysEnv = m_qnxHost.deviceEnvironment(); + sysEnv.modify(qnxEnvironmentItems()); + + for (const FilePath &debuggerPath : debuggerNames) { + DebuggerItem item; + item.setCommand(debuggerPath); + item.reinitializeFromFile(nullptr, &sysEnv); + bool found = false; + for (const Abi &abi : item.abis()) { + for (QnxTarget &target : m_targets) { + if (target.m_abi.isCompatibleWith(abi)) { + found = true; + + if (target.m_debuggerPath.isEmpty()) { + target.m_debuggerPath = debuggerPath; + } else { + qWarning() << debuggerPath << "has the same ABI as" << target.m_debuggerPath + << "... discarded"; + break; + } + } + } + } + if (!found) + qWarning() << "No target found for" << debuggerPath.toUserOutput() << "... discarded"; + } + + // Remove debuggerless targets. + Utils::erase(m_targets, [](const QnxTarget &target) { + if (target.m_debuggerPath.isEmpty()) + qWarning() << "No debugger found for" << target.m_path << "... discarded"; + return target.m_debuggerPath.isEmpty(); + }); + + const FilePath configPath = m_qnxConfiguration / "qconfig"; + if (!configPath.isDir()) + return; + + configPath.iterateDirectory([this, configPath](const FilePath &sdpFile) { + QFile xmlFile(sdpFile.toFSPathString()); + if (!xmlFile.open(QIODevice::ReadOnly)) + return IterationPolicy::Continue; + + QDomDocument doc; + if (!doc.setContent(&xmlFile)) // Skip error message + return IterationPolicy::Continue; + + QDomElement docElt = doc.documentElement(); + if (docElt.tagName() != QLatin1String("qnxSystemDefinition")) + return IterationPolicy::Continue; + + QDomElement childElt = docElt.firstChildElement(QLatin1String("installation")); + // The file contains only one installation node + if (childElt.isNull()) // The file contains only one base node + return IterationPolicy::Continue; + + FilePath host = configPath.withNewPath( + childElt.firstChildElement(QLatin1String("host")).text()).canonicalPath(); + if (m_qnxHost != host) + return IterationPolicy::Continue; + + FilePath target = configPath.withNewPath( + childElt.firstChildElement(QLatin1String("target")).text()).canonicalPath(); + if (m_qnxTarget != target) + return IterationPolicy::Continue; + + m_configName = childElt.firstChildElement(QLatin1String("name")).text(); + QString version = childElt.firstChildElement(QLatin1String("version")).text(); + m_version = QnxVersionNumber(version); + return IterationPolicy::Stop; + }, {{"*.xml"}, QDir::Files}); +} + +EnvironmentItems QnxConfiguration::qnxEnvironmentItems() const +{ + ensureContents(); + return { + {QNXConfiguration, m_qnxConfiguration.path()}, + {QNXTarget, m_qnxTarget.path()}, + {QNXHost, m_qnxHost.path()} + }; +} + +const QnxTarget *QnxConfiguration::findTargetByDebuggerPath( + const FilePath &path) const +{ + const auto it = std::find_if(m_targets.begin(), m_targets.end(), + [path](const QnxTarget &target) { return target.m_debuggerPath == path; }); + return it == m_targets.end() ? nullptr : &(*it); +} + + +// QnxSettingsPagePrivate + +class QnxSettingsPagePrivate : public QObject +{ +public: + QnxSettingsPagePrivate() + { + connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, + this, &QnxSettingsPagePrivate::saveConfigs); + // Can't do yet as not all devices are around. + connect(DeviceManager::instance(), &DeviceManager::devicesLoaded, + this, &QnxSettingsPagePrivate::restoreConfigurations); + } + + void saveConfigs() + { + QVariantMap data; + data.insert(QLatin1String(QNXConfigsFileVersionKey), 1); + int count = 0; + for (const QnxConfiguration &config : std::as_const(m_configurations)) { + QVariantMap tmp = config.toMap(); + if (tmp.isEmpty()) + continue; + + data.insert(QNXConfigDataKey + QString::number(count), tmp); + ++count; + } + + data.insert(QLatin1String(QNXConfigCountKey), count); + m_writer.save(data, Core::ICore::dialogParent()); + } + + void restoreConfigurations() + { + PersistentSettingsReader reader; + if (!reader.load(qnxConfigSettingsFileName())) + return; + + QVariantMap data = reader.restoreValues(); + int count = data.value(QNXConfigCountKey, 0).toInt(); + for (int i = 0; i < count; ++i) { + const QString key = QNXConfigDataKey + QString::number(i); + if (!data.contains(key)) + continue; + + QnxConfiguration config; + config.fromMap(data.value(key).toMap()); + m_configurations[config.m_envFile] = config; + } + } + + QnxConfiguration *configurationFromEnvFile(const FilePath &envFile) + { + auto it = m_configurations.find(envFile); + return it == m_configurations.end() ? nullptr : &*it; + } + + QHash m_configurations; + PersistentSettingsWriter m_writer{qnxConfigSettingsFileName(), "QnxConfigurations"}; +}; + +static QnxSettingsPagePrivate *dd = nullptr; + + +// QnxSettingsWidget + class QnxSettingsWidget final : public Core::IOptionsPageWidget { public: @@ -42,10 +494,10 @@ public: public: bool operator ==(const ConfigState &cs) const { - return config == cs.config && state == cs.state; + return envFile == cs.envFile && state == cs.state; } - QnxConfiguration *config; + FilePath envFile; State state; }; @@ -57,7 +509,7 @@ public: void updateInformation(); void populateConfigsCombo(); - void setConfigState(QnxConfiguration *config, State state); + void setConfigState(const FilePath &envFile, State state); private: QComboBox *m_configsCombo = new QComboBox; @@ -67,7 +519,6 @@ private: QLabel *m_configHost = new QLabel; QLabel *m_configTarget = new QLabel; - QnxConfigurationManager *m_qnxConfigManager = QnxConfigurationManager::instance(); QList m_changedConfigs; }; @@ -101,6 +552,7 @@ QnxSettingsWidget::QnxSettingsWidget() }.attachTo(this); populateConfigsCombo(); + connect(addButton, &QAbstractButton::clicked, this, &QnxSettingsWidget::addConfiguration); connect(removeButton, &QAbstractButton::clicked, @@ -109,17 +561,14 @@ QnxSettingsWidget::QnxSettingsWidget() this, &QnxSettingsWidget::updateInformation); connect(m_generateKitsCheckBox, &QAbstractButton::toggled, this, &QnxSettingsWidget::generateKits); - connect(m_qnxConfigManager, &QnxConfigurationManager::configurationsListUpdated, - this, &QnxSettingsWidget::populateConfigsCombo); - connect(QtSupport::QtVersionManager::instance(), - &QtSupport::QtVersionManager::qtVersionsChanged, + connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged, this, &QnxSettingsWidget::updateInformation); } void QnxSettingsWidget::addConfiguration() { QString filter; - if (Utils::HostOsInfo::isWindowsHost()) + if (HostOsInfo::isWindowsHost()) filter = "*.bat file"; else filter = "*.sh file"; @@ -129,82 +578,88 @@ void QnxSettingsWidget::addConfiguration() if (envFile.isEmpty()) return; - QnxConfiguration *config = new QnxConfiguration(envFile); - if (m_qnxConfigManager->configurations().contains(config) || !config->isValid()) { + if (dd->m_configurations.contains(envFile)) { QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Warning"), - Tr::tr("Configuration already exists or is invalid.")); - delete config; + Tr::tr("Configuration already exists.")); return; } - setConfigState(config, Added); - m_configsCombo->addItem(config->displayName(), - QVariant::fromValue(static_cast(config))); + // Temporary to be able to check + QnxConfiguration config(envFile); + config.ensureContents(); + if (!config.isValid()) { + QMessageBox::warning(Core::ICore::dialogParent(), + Tr::tr("Warning"), + Tr::tr("Configuration is not valid.")); + return; + } + + setConfigState(envFile, Added); + m_configsCombo->addItem(config.m_configName, QVariant::fromValue(envFile)); } void QnxSettingsWidget::removeConfiguration() { - const int currentIndex = m_configsCombo->currentIndex(); - auto config = static_cast( - m_configsCombo->itemData(currentIndex).value()); + const FilePath envFile = m_configsCombo->currentData().value(); + QTC_ASSERT(!envFile.isEmpty(), return); - if (!config) - return; + QnxConfiguration *config = dd->configurationFromEnvFile(envFile); + QTC_ASSERT(config, return); + + config->ensureContents(); QMessageBox::StandardButton button = QMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Remove QNX Configuration"), - Tr::tr("Are you sure you want to remove:\n %1?").arg(config->displayName()), + Tr::tr("Are you sure you want to remove:\n %1?") + .arg(config->m_configName), QMessageBox::Yes | QMessageBox::No); if (button == QMessageBox::Yes) { - setConfigState(config, Removed); - m_configsCombo->removeItem(currentIndex); + setConfigState(envFile, Removed); + m_configsCombo->removeItem(m_configsCombo->currentIndex()); + updateInformation(); } } void QnxSettingsWidget::generateKits(bool checked) { - const int currentIndex = m_configsCombo->currentIndex(); - auto config = static_cast( - m_configsCombo->itemData(currentIndex).value()); - if (!config) - return; - - setConfigState(config, checked ? Activated : Deactivated); + const FilePath envFile = m_configsCombo->currentData().value(); + setConfigState(envFile, checked ? Activated : Deactivated); } void QnxSettingsWidget::updateInformation() { - const int currentIndex = m_configsCombo->currentIndex(); + const FilePath envFile = m_configsCombo->currentData().value(); - auto config = static_cast( - m_configsCombo->itemData(currentIndex).value()); - - // update the checkbox - m_generateKitsCheckBox->setEnabled(config ? config->isValid() : false); - m_generateKitsCheckBox->setChecked(config ? config->isActive() : false); - - // update information - m_configName->setText(config ? config->displayName() : QString()); - m_configVersion->setText(config ? config->version().toString() : QString()); - m_configHost->setText(config ? config->qnxHost().toString() : QString()); - m_configTarget->setText(config ? config->qnxTarget().toString() : QString()); + if (QnxConfiguration *config = dd->configurationFromEnvFile(envFile)) { + config->ensureContents(); + m_generateKitsCheckBox->setEnabled(config->isValid()); + m_generateKitsCheckBox->setChecked(config->isActive()); + m_configName->setText(config->m_configName); + m_configVersion->setText(config->m_version.toString()); + m_configHost->setText(config->m_qnxHost.toString()); + m_configTarget->setText(config->m_qnxTarget.toString()); + } else { + m_generateKitsCheckBox->setEnabled(false); + m_generateKitsCheckBox->setChecked(false); + m_configName->setText({}); + m_configVersion->setText({}); + m_configHost->setText({}); + m_configTarget->setText({}); + } } void QnxSettingsWidget::populateConfigsCombo() { m_configsCombo->clear(); - const QList configList = m_qnxConfigManager->configurations(); - for (QnxConfiguration *config : configList) { - m_configsCombo->addItem(config->displayName(), - QVariant::fromValue(static_cast(config))); - } + for (const QnxConfiguration &config : std::as_const(dd->m_configurations)) + m_configsCombo->addItem(config.m_configName, QVariant::fromValue(config.m_envFile)); updateInformation(); } -void QnxSettingsWidget::setConfigState(QnxConfiguration *config, State state) +void QnxSettingsWidget::setConfigState(const FilePath &envFile, State state) { State stateToRemove = Activated; switch (state) { @@ -223,45 +678,79 @@ void QnxSettingsWidget::setConfigState(QnxConfiguration *config, State state) } for (const ConfigState &configState : std::as_const(m_changedConfigs)) { - if (configState.config == config && configState.state == stateToRemove) + if (configState.envFile == envFile && configState.state == stateToRemove) m_changedConfigs.removeAll(configState); } - m_changedConfigs.append(ConfigState{config, state}); + m_changedConfigs.append(ConfigState{envFile, state}); } void QnxSettingsWidget::apply() { for (const ConfigState &configState : std::as_const(m_changedConfigs)) { switch (configState.state) { - case Activated : - configState.config->activate(); + case Activated: { + QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile); + QTC_ASSERT(config, break); + config->activate(); break; - case Deactivated: - configState.config->deactivate(); + } + case Deactivated: { + QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile); + QTC_ASSERT(config, break); + config->deactivate(); break; - case Added: - m_qnxConfigManager->addConfiguration(configState.config); + } + case Added: { + QnxConfiguration config(configState.envFile); + config.ensureContents(); + dd->m_configurations.insert(configState.envFile, config); break; + } case Removed: - configState.config->deactivate(); - m_qnxConfigManager->removeConfiguration(configState.config); + QnxConfiguration *config = dd->configurationFromEnvFile(configState.envFile); + QTC_ASSERT(config, break); + config->deactivate(); + dd->m_configurations.remove(configState.envFile); break; } } m_changedConfigs.clear(); + populateConfigsCombo(); } - // QnxSettingsPage +QList QnxSettingsPage::autoDetect(const QList &alreadyKnown) +{ + QList result; + for (const QnxConfiguration &config : std::as_const(dd->m_configurations)) { + config.ensureContents(); + for (const QnxTarget &target : std::as_const(config.m_targets)) { + result += Utils::filtered(alreadyKnown, [config, target](ToolChain *tc) { + return tc->typeId() == Constants::QNX_TOOLCHAIN_ID + && tc->targetAbi() == target.m_abi + && tc->compilerCommand() == config.m_qccCompiler; + }); + } + } + return result; +} + QnxSettingsPage::QnxSettingsPage() { setId("DD.Qnx Configuration"); setDisplayName(Tr::tr("QNX")); setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); setWidgetCreator([] { return new QnxSettingsWidget; }); + + dd = new QnxSettingsPagePrivate; +} + +QnxSettingsPage::~QnxSettingsPage() +{ + delete dd; } } // Qnx::Internal diff --git a/src/plugins/qnx/qnxsettingspage.h b/src/plugins/qnx/qnxsettingspage.h index cdf6f1ba860..f127d5f35e4 100644 --- a/src/plugins/qnx/qnxsettingspage.h +++ b/src/plugins/qnx/qnxsettingspage.h @@ -5,12 +5,18 @@ #include +namespace ProjectExplorer { class ToolChain; } + namespace Qnx::Internal { class QnxSettingsPage final : public Core::IOptionsPage { public: QnxSettingsPage(); + ~QnxSettingsPage(); + + static QList autoDetect( + const QList &alreadyKnown); }; } // Qnx::Internal diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp index 187c507da49..8176b3d17c9 100644 --- a/src/plugins/qnx/qnxtoolchain.cpp +++ b/src/plugins/qnx/qnxtoolchain.cpp @@ -3,9 +3,8 @@ #include "qnxtoolchain.h" -#include "qnxconfiguration.h" -#include "qnxconfigurationmanager.h" #include "qnxconstants.h" +#include "qnxsettingspage.h" #include "qnxtr.h" #include "qnxutils.h" @@ -222,10 +221,7 @@ Toolchains QnxToolChainFactory::autoDetect(const ToolchainDetector &detector) co if (detector.device) return {}; - Toolchains tcs; - const auto configurations = QnxConfigurationManager::instance()->configurations(); - for (QnxConfiguration *configuration : configurations) - tcs += configuration->autoDetect(detector.alreadyKnown); + Toolchains tcs = QnxSettingsPage::autoDetect(detector.alreadyKnown); return tcs; } diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index 697e95bebc6..5c1107f5997 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -16,6 +16,15 @@ using namespace Utils; namespace Qnx::Internal { +QnxTarget::QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi) : + m_path(path), m_abi(abi) +{} + +QString QnxTarget::shortDescription() const +{ + return QnxUtils::cpuDirShortDescription(cpuDir()); +} + QString QnxUtils::cpuDirFromAbi(const Abi &abi) { if (abi.os() != Abi::OS::QnxOS) diff --git a/src/plugins/qnx/qnxutils.h b/src/plugins/qnx/qnxutils.h index 4f523953e46..2fea51ccc63 100644 --- a/src/plugins/qnx/qnxutils.h +++ b/src/plugins/qnx/qnxutils.h @@ -14,12 +14,14 @@ namespace Qnx::Internal { class QnxTarget { public: - QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi) : - m_path(path), m_abi(abi) - { - } + QnxTarget(const Utils::FilePath &path, const ProjectExplorer::Abi &abi); + + QString shortDescription() const; + QString cpuDir() const { return m_path.fileName(); } + Utils::FilePath m_path; ProjectExplorer::Abi m_abi; + Utils::FilePath m_debuggerPath; }; namespace QnxUtils { From 0c3789726d97ff1a165607d664703c614ed96df4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 5 Apr 2023 08:12:43 +0200 Subject: [PATCH 0563/1447] LocatorMatcher: Introduce LocatorMatcherTaskCreator Register cpp and lsp matchers for all symbols, classes and functions. Change-Id: Id85c8164077ec395dac7e6ff45acc89db9e6ae08 Reviewed-by: Christian Kandeler --- .../clangcodemodel/clangdlocatorfilters.cpp | 17 ++----- .../clangmodelmanagersupport.cpp | 26 +++++++++++ .../clangcodemodel/clangmodelmanagersupport.h | 2 + .../coreplugin/locator/ilocatorfilter.cpp | 45 +++++++++++++++++++ .../coreplugin/locator/ilocatorfilter.h | 10 +++++ src/plugins/cppeditor/cppmodelmanager.cpp | 4 ++ 6 files changed, 90 insertions(+), 14 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 58166fd499c..593bd4c6669 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -32,17 +32,6 @@ namespace Internal { const int MaxResultCount = 10000; -static QList clientsForOpenProjects() -{ - QSet clients; - const QList projects = ProjectManager::projects(); - for (Project *project : projects) { - if (Client *client = ClangModelManagerSupport::clientForProject(project)) - clients << client; - } - return clients.values(); -} - class CppLocatorFilter : public CppEditor::CppLocatorFilter { public: @@ -72,7 +61,7 @@ public: } void prepareSearch(const QString &entry) override { - prepareSearchForClients(entry, clientsForOpenProjects()); + prepareSearchForClients(entry, ClangModelManagerSupport::clientsForOpenProjects()); } }; @@ -105,7 +94,7 @@ public: } void prepareSearch(const QString &entry) override { - prepareSearchForClients(entry, clientsForOpenProjects()); + prepareSearchForClients(entry, ClangModelManagerSupport::clientsForOpenProjects()); } }; @@ -138,7 +127,7 @@ public: } void prepareSearch(const QString &entry) override { - prepareSearchForClients(entry, clientsForOpenProjects()); + prepareSearchForClients(entry, ClangModelManagerSupport::clientsForOpenProjects()); } }; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 4d9ee95d860..43b41e54f9b 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -205,6 +205,21 @@ ClangModelManagerSupport::ClangModelManagerSupport() cppModelManager()->setLocatorFilter(std::make_unique()); cppModelManager()->setClassesFilter(std::make_unique()); cppModelManager()->setFunctionsFilter(std::make_unique()); + // Setup matchers + using WorkspaceMatcherCreator = std::function; + const auto matcherCreator = [](const WorkspaceMatcherCreator &creator) { + const QList clients = clientsForOpenProjects(); + QList matchers; + for (Client *client : clients) + matchers << creator(client, 10000); + return matchers; + }; + LocatorMatcher::addLocatorMatcherCreator( + [matcherCreator] { return matcherCreator(&LanguageClient::workspaceLocatorMatcher); }); + LocatorMatcher::addClassMatcherCreator( + [matcherCreator] { return matcherCreator(&LanguageClient::workspaceClassMatcher); }); + LocatorMatcher::addFunctionMatcherCreator( + [matcherCreator] { return matcherCreator(&LanguageClient::workspaceFunctionMatcher); }); EditorManager *editorManager = EditorManager::instance(); connect(editorManager, &EditorManager::editorOpened, @@ -587,6 +602,17 @@ void ClangModelManagerSupport::updateLanguageClient(Project *project) m_generatorSynchronizer.addFuture(future); } +QList ClangModelManagerSupport::clientsForOpenProjects() +{ + QSet clients; + const QList projects = ProjectManager::projects(); + for (Project *project : projects) { + if (Client *client = ClangModelManagerSupport::clientForProject(project)) + clients << client; + } + return clients.values(); +} + ClangdClient *ClangModelManagerSupport::clientForProject(const Project *project) { if (sessionModeEnabled()) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index a901b4407e2..140239550d8 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -24,6 +24,7 @@ QT_END_NAMESPACE namespace Core { class IEditor; } namespace CppEditor { class RefactoringEngineInterface; } +namespace LanguageClient { class Client; } namespace TextEditor { class TextEditorWidget; } namespace ClangCodeModel { @@ -45,6 +46,7 @@ public: TextEditor::TextDocument *baseTextDocument) override; bool usesClangd(const TextEditor::TextDocument *document) const override; + static QList clientsForOpenProjects(); static ClangdClient *clientForProject(const ProjectExplorer::Project *project); static ClangdClient *clientForFile(const Utils::FilePath &file); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index e2b1fed4823..98c18ac1b53 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -427,6 +427,51 @@ LocatorMatcherTask::OutputData LocatorMatcher::runBlocking(const QList s_locatorMatcherCreators = {}; +static QList s_classMatcherCreators = {}; +static QList s_functionMatcherCreators = {}; + +void LocatorMatcher::addLocatorMatcherCreator(const LocatorMatcherTaskCreator &creator) +{ + QTC_ASSERT(creator, return); + s_locatorMatcherCreators.append(creator); +} + +void LocatorMatcher::addClassMatcherCreator(const LocatorMatcherTaskCreator &creator) +{ + QTC_ASSERT(creator, return); + s_classMatcherCreators.append(creator); +} + +void LocatorMatcher::addFunctionMatcherCreator(const LocatorMatcherTaskCreator &creator) +{ + QTC_ASSERT(creator, return); + s_functionMatcherCreators.append(creator); +} + +static QList matchers(const QList &creators) +{ + QList result; + for (const LocatorMatcherTaskCreator &creator : creators) + result << creator(); + return result; +} + +QList LocatorMatcher::locatorMatchers() +{ + return matchers(s_locatorMatcherCreators); +} + +QList LocatorMatcher::classMatchers() +{ + return matchers(s_classMatcherCreators); +} + +QList LocatorMatcher::functionMatchers() +{ + return matchers(s_functionMatcherCreators); +} + static QList g_locatorFilters; /*! diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 7d41eba9e13..bcc413905f7 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -142,6 +142,7 @@ public: Utils::Tasking::TreeStorage storage; }; +using LocatorMatcherTaskCreator = std::function()>; class LocatorMatcherPrivate; class CORE_EXPORT LocatorMatcher final : public QObject @@ -165,6 +166,15 @@ public: static LocatorMatcherTask::OutputData runBlocking(const QList &tasks, const LocatorMatcherTask::InputData &input, int parallelLimit = 0); + + static void addLocatorMatcherCreator(const LocatorMatcherTaskCreator &creator); + static void addClassMatcherCreator(const LocatorMatcherTaskCreator &creator); + static void addFunctionMatcherCreator(const LocatorMatcherTaskCreator &creator); + + static QList locatorMatchers(); + static QList classMatchers(); + static QList functionMatchers(); + signals: void serialOutputDataReady(const LocatorMatcherTask::OutputData &serialOutputData); void done(bool success); diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 34da9da3f4c..9cc3b1c214b 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -904,6 +904,10 @@ void CppModelManager::initCppTools() setSymbolsFindFilter(std::make_unique(this)); setCurrentDocumentFilter( std::make_unique(this)); + // Setup matchers + LocatorMatcher::addLocatorMatcherCreator([] { return QList{CppEditor::cppLocatorMatcher()}; }); + LocatorMatcher::addClassMatcherCreator([] { return QList{CppEditor::cppClassMatcher()}; }); + LocatorMatcher::addFunctionMatcherCreator([] { return QList{CppEditor::cppFunctionMatcher()}; }); } CppModelManager::CppModelManager() From 9388ab252ee62560f035c3deeccda187cbf173f8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 18:31:22 +0200 Subject: [PATCH 0564/1447] LocatorFiltersFilter: Use Acceptor for LocatorFilterEntry Change-Id: I917ce346bf66cb18890d7d055501218d12a2c3ad Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- .../locator/locatorfiltersfilter.cpp | 22 +++++-------------- .../coreplugin/locator/locatorfiltersfilter.h | 3 --- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index b8cd9ef3007..b8c05aae97e 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -60,8 +60,12 @@ QList LocatorFiltersFilter::matchesFor(QFutureInterface LocatorFiltersFilter::matchesFor(QFutureInterface= 0 && index < m_filterShortcutStrings.size(), return); - const QString shortcutString = m_filterShortcutStrings.at(index); - if (!shortcutString.isEmpty()) { - *newText = shortcutString + ' '; - *selectionStart = shortcutString.length() + 1; - } -} - } // Core::Internal diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.h b/src/plugins/coreplugin/locator/locatorfiltersfilter.h index f4679ec9c10..7ad19f8c4dd 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.h +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.h @@ -27,9 +27,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: QStringList m_filterShortcutStrings; QStringList m_filterDisplayNames; From 9f78ca6f1150eccec95b862a6e8d49830a05a657 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 09:25:04 +0000 Subject: [PATCH 0565/1447] Reapply "CommandLocator: Use Acceptor for LocatorFilterEntry" This reverts commit 20a4954cbdb82861ba9ebb5ebe5030f5b5bac976. Change-Id: I52a969ee8a26a9835ef15f906e4e418af5352aab Reviewed-by: Eike Ziller Reviewed-by: Orgad Shaneh --- .../coreplugin/locator/commandlocator.cpp | 34 +++++++------------ .../coreplugin/locator/commandlocator.h | 3 -- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 387cae9fef6..9c644f4f998 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -17,7 +17,7 @@ namespace Core { struct CommandLocatorPrivate { QList commands; - QList> commandsData; + QList> commandsData; }; /*! @@ -61,7 +61,7 @@ void CommandLocator::prepareSearch(const QString &entry) continue; QAction *action = command->action(); if (action && action->isEnabled()) - d->commandsData.append({i, action->text()}); + d->commandsData.append({action, action->text()}); } } @@ -77,8 +77,17 @@ QList CommandLocator::matchesFor(QFutureInterface= 0) { - LocatorFilterEntry filterEntry(this, text); - filterEntry.internalData = QVariant(pair.first); + QAction *action = pair.first; + LocatorFilterEntry filterEntry; + filterEntry.displayName = text; + filterEntry.acceptor = [action] { + // avoid nested stack trace and blocking locator by delayed triggering + QMetaObject::invokeMethod(action, [action] { + if (action->isEnabled()) + action->trigger(); + }, Qt::QueuedConnection); + return AcceptResult(); + }; filterEntry.highlightInfo = {index, int(entry.length())}; if (index == 0) @@ -91,21 +100,4 @@ QList CommandLocator::matchesFor(QFutureInterface= 0 && index < d->commands.size(), return); - QAction *action = d->commands.at(index)->action(); - // avoid nested stack trace and blocking locator by delayed triggering - QMetaObject::invokeMethod(action, [action] { - if (action->isEnabled()) - action->trigger(); - }, Qt::QueuedConnection); -} - } // namespace Core diff --git a/src/plugins/coreplugin/locator/commandlocator.h b/src/plugins/coreplugin/locator/commandlocator.h index 8199661bed6..e47fbde5c41 100644 --- a/src/plugins/coreplugin/locator/commandlocator.h +++ b/src/plugins/coreplugin/locator/commandlocator.h @@ -26,9 +26,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: CommandLocatorPrivate *d = nullptr; }; From fadbc55cdfb06b89e956594485f2b8ae543710a8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 19:43:45 +0200 Subject: [PATCH 0566/1447] OutputDataProvider: Fix workingList initialization Broken in patchset 57 of the amended change. Amends 2eba3584a18c015f574e24fc679ffa8969870fd0 Change-Id: I92c54793c8a31dd0f3f9a1e0b2cf8c4efde741ec Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 98c18ac1b53..bd68d602f1f 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -118,7 +118,7 @@ public: void run(QPromise &promise) { QList> data; - QList> workingList; + QList> workingList(m_filterCount, {}); while (waitForData(&data)) { // Emit new results only when new data is reachable from the beginning (i.e. no gaps) int currentIndex = 0; From 0ab7a1473142d52f60589df176cb447525973e5a Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 18 Apr 2023 15:35:32 +0200 Subject: [PATCH 0567/1447] ProjectExplorer: De-O_OBJECT-ify IPotentialKit Change-Id: Ic7718b249375ae74bec2092ae7b0be80b6d574ee Reviewed-by: Christian Kandeler --- src/plugins/android/androidpotentialkit.cpp | 24 ++++++++++++++++----- src/plugins/android/androidpotentialkit.h | 18 ++-------------- src/plugins/projectexplorer/ipotentialkit.h | 10 ++++----- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/plugins/android/androidpotentialkit.cpp b/src/plugins/android/androidpotentialkit.cpp index 914cbc0acd5..4d95f485d0e 100644 --- a/src/plugins/android/androidpotentialkit.cpp +++ b/src/plugins/android/androidpotentialkit.cpp @@ -8,23 +8,35 @@ #include -#include -#include - #include #include + #include #include #include + #include #include +#include +#include + #include #include #include -using namespace Android; -using namespace Android::Internal; + +namespace Android::Internal { + +class AndroidPotentialKitWidget : public Utils::DetailsWidget +{ +public: + AndroidPotentialKitWidget(QWidget *parent); + +private: + void openOptions(); + void recheck(); +}; QString AndroidPotentialKit::displayName() const { @@ -102,3 +114,5 @@ void AndroidPotentialKitWidget::recheck() } } } + +} // Android::Internal diff --git a/src/plugins/android/androidpotentialkit.h b/src/plugins/android/androidpotentialkit.h index 9e1ed417423..d1110294756 100644 --- a/src/plugins/android/androidpotentialkit.h +++ b/src/plugins/android/androidpotentialkit.h @@ -4,14 +4,11 @@ #pragma once #include -#include -namespace Android { -namespace Internal { +namespace Android::Internal { class AndroidPotentialKit : public ProjectExplorer::IPotentialKit { - Q_OBJECT public: QString displayName() const override; void executeFromMenu() override; @@ -19,15 +16,4 @@ public: bool isEnabled() const override; }; -class AndroidPotentialKitWidget : public Utils::DetailsWidget -{ - Q_OBJECT -public: - AndroidPotentialKitWidget(QWidget *parent); -private: - void openOptions(); - void recheck(); -}; - -} -} +} // Android::Internal diff --git a/src/plugins/projectexplorer/ipotentialkit.h b/src/plugins/projectexplorer/ipotentialkit.h index ae032fb9e33..038a3a9fac8 100644 --- a/src/plugins/projectexplorer/ipotentialkit.h +++ b/src/plugins/projectexplorer/ipotentialkit.h @@ -4,18 +4,16 @@ #pragma once #include -#include + #include "projectexplorer_export.h" namespace ProjectExplorer { -class PROJECTEXPLORER_EXPORT IPotentialKit : public QObject +class PROJECTEXPLORER_EXPORT IPotentialKit { - Q_OBJECT - public: IPotentialKit(); - ~IPotentialKit() override; + virtual ~IPotentialKit(); virtual QString displayName() const = 0; virtual void executeFromMenu() = 0; @@ -23,4 +21,4 @@ public: virtual bool isEnabled() const = 0; }; -} +} // ProjectExplorer From e7d6501553db39fcaef26be4bb78aa8c5179f2bd Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 18 Apr 2023 15:58:03 +0200 Subject: [PATCH 0568/1447] ProjectExplorer: Postpone ToolChainConfigWidget creation ... until they are actually used, i.e. when the respective tool chain is selected in the Toolchain tab. Some of them (QNX) can be expensive to set up. Previously all of were created when the Kits settings page was opened. Change-Id: I80e4238269b9f08788c330e2052c525dcf41d1ba Reviewed-by: Christian Kandeler --- .../projectexplorer/toolchainoptionspage.cpp | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index b8df603850f..e0717ab7804 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -48,20 +48,8 @@ class ToolChainTreeItem : public TreeItem { public: ToolChainTreeItem(QStackedWidget *parentWidget, ToolChain *tc, bool c) : - toolChain(tc), changed(c) - { - widget = tc->createConfigurationWidget().release(); - if (widget) { - parentWidget->addWidget(widget); - if (tc->isAutoDetected()) - widget->makeReadOnly(); - QObject::connect(widget, &ToolChainConfigWidget::dirty, - [this] { - changed = true; - update(); - }); - } - } + toolChain(tc), changed(c), m_parentWidget(parentWidget) + {} QVariant data(int column, int role) const override { @@ -93,9 +81,30 @@ public: return QVariant(); } + ToolChainConfigWidget *widget() + { + if (!m_widget) { + m_widget = toolChain->createConfigurationWidget().release(); + if (m_widget) { + m_parentWidget->addWidget(m_widget); + if (toolChain->isAutoDetected()) + m_widget->makeReadOnly(); + QObject::connect(m_widget, &ToolChainConfigWidget::dirty, + [this] { + changed = true; + update(); + }); + } + } + return m_widget; + } + ToolChain *toolChain; - ToolChainConfigWidget *widget; bool changed; + +private: + ToolChainConfigWidget *m_widget = nullptr; + QStackedWidget *m_parentWidget = nullptr; }; class DetectionSettingsDialog : public QDialog @@ -423,7 +432,7 @@ void ToolChainOptionsWidget::toolChainSelectionChanged() { ToolChainTreeItem *item = currentTreeItem(); - QWidget *currentTcWidget = item ? item->widget : nullptr; + QWidget *currentTcWidget = item ? item->widget() : nullptr; if (currentTcWidget) m_widgetStack->setCurrentWidget(currentTcWidget); m_container->setVisible(currentTcWidget); @@ -447,8 +456,8 @@ void ToolChainOptionsWidget::apply() for (TreeItem *item : *parent) { auto tcItem = static_cast(item); Q_ASSERT(tcItem->toolChain); - if (!tcItem->toolChain->isAutoDetected() && tcItem->widget && tcItem->changed) - tcItem->widget->apply(); + if (!tcItem->toolChain->isAutoDetected() && tcItem->widget() && tcItem->changed) + tcItem->widget()->apply(); tcItem->changed = false; tcItem->update(); } From 778d7a981995898a3afd782bfc199d032d4a80f0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 21 Mar 2023 14:53:02 +0100 Subject: [PATCH 0569/1447] ProjectExplorer: Redo the TaskView - Make it a tree view. - Use the default delegate for top-level items. - If the task has details, show them in a child item. Fixes: QTCREATORBUG-28850 Change-Id: Iafd65496f916b9e382ef2c6ade0f9b3a323f63ed Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/task.cpp | 46 +- src/plugins/projectexplorer/task.h | 7 +- src/plugins/projectexplorer/taskhub.cpp | 5 +- src/plugins/projectexplorer/taskmodel.cpp | 78 ++-- src/plugins/projectexplorer/taskmodel.h | 2 +- src/plugins/projectexplorer/taskwindow.cpp | 508 ++++++++------------- 6 files changed, 286 insertions(+), 360 deletions(-) diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index c2937e76ed4..03c2a282be0 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -8,8 +8,8 @@ #include "projectexplorertr.h" #include +#include #include - #include #include #include @@ -105,11 +105,16 @@ void Task::setFile(const Utils::FilePath &file_) } } -QString Task::description() const +QString Task::description(DescriptionTags tags) const { - QString desc = summary; - if (!details.isEmpty()) - desc.append('\n').append(details.join('\n')); + QString desc; + if (tags & WithSummary) + desc = summary; + if (!details.isEmpty()) { + if (!desc.isEmpty()) + desc.append('\n'); + desc.append(details.join('\n')); + } return desc; } @@ -120,32 +125,37 @@ QIcon Task::icon() const return m_icon; } -QString Task::toolTip(const QString &extraHeading) const +QString Task::formattedDescription(DescriptionTags tags, const QString &extraHeading) const { if (isNull()) return {}; - QString text = description(); + QString text = description(tags); + const int offset = (tags & WithSummary) ? 0 : summary.size() + 1; static const QString linkTagStartPlaceholder("__QTC_LINK_TAG_START__"); static const QString linkTagEndPlaceholder("__QTC_LINK_TAG_END__"); static const QString linkEndPlaceholder("__QTC_LINK_END__"); - for (auto formatRange = formats.crbegin(); formatRange != formats.crend(); ++formatRange) { - if (!formatRange->format.isAnchor()) - continue; - text.insert(formatRange->start + formatRange->length, linkEndPlaceholder); - text.insert(formatRange->start, QString::fromLatin1("%1%2%3").arg( + if (tags & WithLinks) { + for (auto formatRange = formats.crbegin(); formatRange != formats.crend(); ++formatRange) { + if (!formatRange->format.isAnchor()) + continue; + text.insert(formatRange->start - offset + formatRange->length, linkEndPlaceholder); + text.insert(formatRange->start - offset, QString::fromLatin1("%1%2%3").arg( linkTagStartPlaceholder, formatRange->format.anchorHref(), linkTagEndPlaceholder)); + } } text = text.toHtmlEscaped(); - text.replace(linkEndPlaceholder, ""); - text.replace(linkTagStartPlaceholder, ""); + if (tags & WithLinks) { + text.replace(linkEndPlaceholder, ""); + text.replace(linkTagStartPlaceholder, ""); + } const QString htmlExtraHeading = extraHeading.isEmpty() ? QString() : QString::fromUtf8("%1
").arg(extraHeading); - return QString::fromUtf8("%1" - "%2") - .arg(htmlExtraHeading, text); + return QString::fromUtf8("%1" + "%3") + .arg(htmlExtraHeading, TextEditor::FontSettings::defaultFixedFontFamily(), text); } // diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h index 27adeebf039..830cea79397 100644 --- a/src/plugins/projectexplorer/task.h +++ b/src/plugins/projectexplorer/task.h @@ -38,6 +38,9 @@ public: }; using Options = char; + enum DescriptionTag { WithSummary = 1, WithLinks = 2 }; + using DescriptionTags = QFlags; + Task() = default; Task(TaskType type, const QString &description, const Utils::FilePath &file, int line, Utils::Id category, @@ -49,9 +52,9 @@ public: bool isNull() const; void clear(); void setFile(const Utils::FilePath &file); - QString description() const; + QString description(DescriptionTags tags = WithSummary) const; QIcon icon() const; - QString toolTip(const QString &extraHeading = {}) const; + QString formattedDescription(DescriptionTags tags, const QString &extraHeading = {}) const; friend PROJECTEXPLORER_EXPORT bool operator==(const Task &t1, const Task &t2); friend PROJECTEXPLORER_EXPORT bool operator<(const Task &a, const Task &b); diff --git a/src/plugins/projectexplorer/taskhub.cpp b/src/plugins/projectexplorer/taskhub.cpp index 7c1cff54542..58e797de803 100644 --- a/src/plugins/projectexplorer/taskhub.cpp +++ b/src/plugins/projectexplorer/taskhub.cpp @@ -51,8 +51,9 @@ public: : Tr::tr("Warning")); setPriority(task.type == Task::Error ? TextEditor::TextMark::NormalPriority : TextEditor::TextMark::LowPriority); - setToolTip(task.toolTip(task.category == Constants::TASK_CATEGORY_COMPILE - ? Tr::tr("Build Issue") : QString())); + setToolTip(task.formattedDescription({Task::WithSummary | Task::WithLinks}, + task.category == Constants::TASK_CATEGORY_COMPILE + ? Tr::tr("Build Issue") : QString())); setIcon(task.icon()); setVisible(!task.icon().isNull()); } diff --git a/src/plugins/projectexplorer/taskmodel.cpp b/src/plugins/projectexplorer/taskmodel.cpp index b8f7d723063..c05614a445f 100644 --- a/src/plugins/projectexplorer/taskmodel.cpp +++ b/src/plugins/projectexplorer/taskmodel.cpp @@ -210,58 +210,80 @@ void TaskModel::clearTasks(Utils::Id categoryId) QModelIndex TaskModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid()) - return QModelIndex(); + return createIndex(row, column, quintptr(parent.row() + 1)); return createIndex(row, column); } QModelIndex TaskModel::parent(const QModelIndex &child) const { - Q_UNUSED(child) - return QModelIndex(); + if (child.internalId()) + return index(child.internalId() - 1, 0); + return {}; } int TaskModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_tasks.count(); + if (!parent.isValid()) + return m_tasks.count(); + if (parent.column() != 0) + return 0; + return task(parent).details.isEmpty() ? 0 : 1; } int TaskModel::columnCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : 1; + return parent.isValid() ? 1 : 2; } QVariant TaskModel::data(const QModelIndex &index, int role) const { - int row = index.row(); - if (!index.isValid() || row < 0 || row >= m_tasks.count() || index.column() != 0) - return QVariant(); + if (!index.isValid() || index.row() < 0 || index.row() >= rowCount(index.parent()) + || index.column() >= columnCount(index.parent())) { + return {}; + } - if (role == TaskModel::File) - return m_tasks.at(index.row()).file.toString(); - else if (role == TaskModel::Line) - return m_tasks.at(index.row()).line; - else if (role == TaskModel::MovedLine) - return m_tasks.at(index.row()).movedLine; - else if (role == TaskModel::Description) - return m_tasks.at(index.row()).description(); - else if (role == TaskModel::FileNotFound) - return m_fileNotFound.value(m_tasks.at(index.row()).file.toString()); - else if (role == TaskModel::Type) - return (int)m_tasks.at(index.row()).type; - else if (role == TaskModel::Category) - return m_tasks.at(index.row()).category.uniqueIdentifier(); - else if (role == TaskModel::Icon) - return m_tasks.at(index.row()).icon(); - else if (role == TaskModel::Task_t) - return QVariant::fromValue(task(index)); - return QVariant(); + if (index.internalId()) { + const Task &task = m_tasks.at(index.internalId() - 1); + if (role != Qt::DisplayRole) + return {}; + return task.formattedDescription(Task::WithLinks); + } + + static const auto lineString = [](const Task &task) { + QString file = task.file.fileName(); + const int line = task.movedLine > 0 ? task.movedLine : task.line; + if (line > 0) + file.append(':').append(QString::number(line)); + return file; + }; + + const Task &task = m_tasks.at(index.row()); + if (index.column() == 1) { + if (role == Qt::DisplayRole) + return lineString(task); + if (role == Qt::ToolTipRole) + return task.file.toUserOutput(); + return {}; + } + + switch (role) { + case Qt::DecorationRole: + return task.icon(); + case Qt::DisplayRole: + return task.summary; + case TaskModel::Description: + return task.description(); + } + return {}; } Task TaskModel::task(const QModelIndex &index) const { int row = index.row(); - if (!index.isValid() || row < 0 || row >= m_tasks.count()) + if (!index.isValid() || row < 0 || row >= m_tasks.count() || index.internalId() + || index.column() > 0) { return Task(); + } return m_tasks.at(row); } diff --git a/src/plugins/projectexplorer/taskmodel.h b/src/plugins/projectexplorer/taskmodel.h index e10833f6131..e60d8a30a51 100644 --- a/src/plugins/projectexplorer/taskmodel.h +++ b/src/plugins/projectexplorer/taskmodel.h @@ -44,7 +44,7 @@ public: int sizeOfLineNumber(const QFont &font); void setFileNotFound(const QModelIndex &index, bool b); - enum Roles { File = Qt::UserRole, Line, MovedLine, Description, FileNotFound, Type, Category, Icon, Task_t }; + enum Roles { Description = Qt::UserRole, }; int taskCount(Utils::Id categoryId); int errorTaskCount(Utils::Id categoryId); diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index db8dbf7d5ba..5f1c6aa9e00 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -30,22 +31,22 @@ #include #include +#include +#include #include #include #include #include #include #include +#include #include #include using namespace Utils; -namespace { -const int ELLIPSIS_GRADIENT_WIDTH = 16; const char SESSION_FILTER_CATEGORIES[] = "TaskWindow.Categories"; const char SESSION_FILTER_WARNINGS[] = "TaskWindow.IncludeWarnings"; -} namespace ProjectExplorer { @@ -87,175 +88,43 @@ bool ITaskHandler::canHandle(const Tasks &tasks) const namespace Internal { -class TaskView : public ListView +class TaskView : public TreeView { public: - TaskView(QWidget *parent = nullptr); - ~TaskView() override; + TaskView() { setMouseTracking(true); } + void resizeColumns(); private: void resizeEvent(QResizeEvent *e) override; void keyReleaseEvent(QKeyEvent *e) override; bool event(QEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + QString anchorAt(const QPoint &pos); void showToolTip(const Task &task, const QPoint &pos); + + QString m_hoverAnchor; + QString m_clickAnchor; }; class TaskDelegate : public QStyledItemDelegate { - Q_OBJECT - - friend class TaskView; // for using Positions::minimumSize() - public: - TaskDelegate(QObject * parent = nullptr); - ~TaskDelegate() override; - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + using QStyledItemDelegate::QStyledItemDelegate; + + QTextDocument &doc() { return m_doc; } +private: + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; - // TaskView uses this method if the size of the taskview changes - void emitSizeHintChanged(const QModelIndex &index); + bool needsSpecialHandling(const QModelIndex &index) const; -private: - void generateGradientPixmap(int width, int height, QColor color, bool selected) const; - - mutable int m_cachedHeight = 0; - mutable QFont m_cachedFont; - - /* - +------------------------------------------------------------------------------------------+ - | TASKICONAREA TEXTAREA FILEAREA LINEAREA | - +------------------------------------------------------------------------------------------+ - */ - class Positions - { - public: - Positions(const QStyleOptionViewItem &options, TaskModel *model) : - m_totalWidth(options.rect.width()), - m_maxFileLength(model->sizeOfFile(options.font)), - m_maxLineLength(model->sizeOfLineNumber(options.font)), - m_realFileLength(m_maxFileLength), - m_top(options.rect.top()), - m_bottom(options.rect.bottom()) - { - int flexibleArea = lineAreaLeft() - textAreaLeft() - ITEM_SPACING; - if (m_maxFileLength > flexibleArea / 2) - m_realFileLength = flexibleArea / 2; - m_fontHeight = QFontMetrics(options.font).height(); - } - - int top() const { return m_top + ITEM_MARGIN; } - int left() const { return ITEM_MARGIN; } - int right() const { return m_totalWidth - ITEM_MARGIN; } - int bottom() const { return m_bottom; } - int firstLineHeight() const { return m_fontHeight + 1; } - static int minimumHeight() { return taskIconHeight() + 2 * ITEM_MARGIN; } - - int taskIconLeft() const { return left(); } - static int taskIconWidth() { return TASK_ICON_SIZE; } - static int taskIconHeight() { return TASK_ICON_SIZE; } - int taskIconRight() const { return taskIconLeft() + taskIconWidth(); } - QRect taskIcon() const { return QRect(taskIconLeft(), top(), taskIconWidth(), taskIconHeight()); } - - int textAreaLeft() const { return taskIconRight() + ITEM_SPACING; } - int textAreaWidth() const { return textAreaRight() - textAreaLeft(); } - int textAreaRight() const { return fileAreaLeft() - ITEM_SPACING; } - QRect textArea() const { return QRect(textAreaLeft(), top(), textAreaWidth(), firstLineHeight()); } - - int fileAreaLeft() const { return fileAreaRight() - fileAreaWidth(); } - int fileAreaWidth() const { return m_realFileLength; } - int fileAreaRight() const { return lineAreaLeft() - ITEM_SPACING; } - QRect fileArea() const { return QRect(fileAreaLeft(), top(), fileAreaWidth(), firstLineHeight()); } - - int lineAreaLeft() const { return lineAreaRight() - lineAreaWidth(); } - int lineAreaWidth() const { return m_maxLineLength; } - int lineAreaRight() const { return right(); } - QRect lineArea() const { return QRect(lineAreaLeft(), top(), lineAreaWidth(), firstLineHeight()); } - - private: - int m_totalWidth; - int m_maxFileLength; - int m_maxLineLength; - int m_realFileLength; - int m_top; - int m_bottom; - int m_fontHeight; - - static const int TASK_ICON_SIZE = 16; - static const int ITEM_MARGIN = 2; - static const int ITEM_SPACING = 2 * ITEM_MARGIN; - }; + mutable QTextDocument m_doc; }; -TaskView::TaskView(QWidget *parent) - : ListView(parent) -{ - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - setAutoScroll(false); // QTCREATORBUG-25101 - setUniformItemSizes(true); - - QFontMetrics fm(font()); - int vStepSize = fm.height() + 3; - if (vStepSize < TaskDelegate::Positions::minimumHeight()) - vStepSize = TaskDelegate::Positions::minimumHeight(); - - verticalScrollBar()->setSingleStep(vStepSize); -} - -TaskView::~TaskView() = default; - -void TaskView::resizeEvent(QResizeEvent *e) -{ - Q_UNUSED(e) - static_cast(itemDelegate())->emitSizeHintChanged(selectionModel()->currentIndex()); -} - -void TaskView::keyReleaseEvent(QKeyEvent *e) -{ - ListView::keyReleaseEvent(e); - if (e->key() == Qt::Key_Space) { - const Task task = static_cast(model())->task(currentIndex()); - if (!task.isNull()) { - const QPoint toolTipPos = mapToGlobal(visualRect(currentIndex()).topLeft()); - QMetaObject::invokeMethod(this, [this, task, toolTipPos] { - showToolTip(task, toolTipPos); }, Qt::QueuedConnection); - } - } -} - -bool TaskView::event(QEvent *e) -{ - if (e->type() != QEvent::ToolTip) - return QListView::event(e); - - const auto helpEvent = static_cast(e); - const Task task = static_cast(model())->task(indexAt(helpEvent->pos())); - if (task.isNull()) - return QListView::event(e); - showToolTip(task, helpEvent->globalPos()); - e->accept(); - return true; -} - -void TaskView::showToolTip(const Task &task, const QPoint &pos) -{ - const QString toolTip = task.toolTip(); - if (!toolTip.isEmpty()) { - const auto label = new QLabel(toolTip); - connect(label, &QLabel::linkActivated, [](const QString &link) { - Core::EditorManager::openEditorAt(OutputLineParser::parseLinkTarget(link), {}, - Core::EditorManager::SwitchSplitIfAlreadyVisible); - }); - const auto layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(label); - ToolTip::show(pos, layout); - } else { - ToolTip::hideImmediately(); - } -} - ///// // TaskWindow ///// @@ -271,7 +140,7 @@ public: Internal::TaskModel *m_model; Internal::TaskFilterModel *m_filter; - Internal::TaskView *m_listview; + TaskView m_treeView; Core::IContext *m_taskWindowContext; QMenu *m_contextMenu; QMap m_actionToHandlerMap; @@ -300,43 +169,46 @@ TaskWindow::TaskWindow() : d(std::make_unique()) { d->m_model = new Internal::TaskModel(this); d->m_filter = new Internal::TaskFilterModel(d->m_model); - d->m_listview = new Internal::TaskView; auto agg = new Aggregation::Aggregate; - agg->add(d->m_listview); - agg->add(new Core::ItemViewFind(d->m_listview, TaskModel::Description)); + agg->add(&d->m_treeView); + agg->add(new Core::ItemViewFind(&d->m_treeView, TaskModel::Description)); - d->m_listview->setModel(d->m_filter); - d->m_listview->setFrameStyle(QFrame::NoFrame); - d->m_listview->setWindowTitle(displayName()); - d->m_listview->setSelectionMode(QAbstractItemView::ExtendedSelection); - auto *tld = new Internal::TaskDelegate(this); - d->m_listview->setItemDelegate(tld); - d->m_listview->setWindowIcon(Icons::WINDOW.icon()); - d->m_listview->setContextMenuPolicy(Qt::ActionsContextMenu); - d->m_listview->setAttribute(Qt::WA_MacShowFocusRect, false); + d->m_treeView.setHeaderHidden(true); + d->m_treeView.setExpandsOnDoubleClick(false); + d->m_treeView.setAlternatingRowColors(true); + d->m_treeView.setTextElideMode(Qt::ElideMiddle); + d->m_treeView.setItemDelegate(new TaskDelegate(this)); + d->m_treeView.setModel(d->m_filter); + d->m_treeView.setFrameStyle(QFrame::NoFrame); + d->m_treeView.setWindowTitle(displayName()); + d->m_treeView.setSelectionMode(QAbstractItemView::ExtendedSelection); + d->m_treeView.setWindowIcon(Icons::WINDOW.icon()); + d->m_treeView.setContextMenuPolicy(Qt::ActionsContextMenu); + d->m_treeView.setAttribute(Qt::WA_MacShowFocusRect, false); + d->m_treeView.resizeColumns(); - d->m_taskWindowContext = new Core::IContext(d->m_listview); - d->m_taskWindowContext->setWidget(d->m_listview); + d->m_taskWindowContext = new Core::IContext(&d->m_treeView); + d->m_taskWindowContext->setWidget(&d->m_treeView); d->m_taskWindowContext->setContext(Core::Context(Core::Constants::C_PROBLEM_PANE)); Core::ICore::addContextObject(d->m_taskWindowContext); - connect(d->m_listview->selectionModel(), &QItemSelectionModel::currentChanged, - this, [this](const QModelIndex &index) { d->m_listview->scrollTo(index); }); - connect(d->m_listview, &QAbstractItemView::activated, + connect(d->m_treeView.selectionModel(), &QItemSelectionModel::currentChanged, + this, [this](const QModelIndex &index) { d->m_treeView.scrollTo(index); }); + connect(&d->m_treeView, &QAbstractItemView::activated, this, &TaskWindow::triggerDefaultHandler); - connect(d->m_listview->selectionModel(), &QItemSelectionModel::selectionChanged, + connect(d->m_treeView.selectionModel(), &QItemSelectionModel::selectionChanged, this, [this] { - const Tasks tasks = d->m_filter->tasks(d->m_listview->selectionModel()->selectedIndexes()); + const Tasks tasks = d->m_filter->tasks(d->m_treeView.selectionModel()->selectedIndexes()); for (QAction * const action : std::as_const(d->m_actions)) { ITaskHandler * const h = d->handler(action); action->setEnabled(h && h->canHandle(tasks)); } }); - d->m_contextMenu = new QMenu(d->m_listview); + d->m_contextMenu = new QMenu(&d->m_treeView); - d->m_listview->setContextMenuPolicy(Qt::ActionsContextMenu); + d->m_treeView.setContextMenuPolicy(Qt::ActionsContextMenu); d->m_filterWarningsButton = createFilterButton( Utils::Icons::WARNING_TOOLBAR.icon(), @@ -391,7 +263,6 @@ TaskWindow::TaskWindow() : d(std::make_unique()) TaskWindow::~TaskWindow() { delete d->m_filterWarningsButton; - delete d->m_listview; delete d->m_filter; delete d->m_model; } @@ -415,7 +286,7 @@ void TaskWindow::delayedInitialization() connect(action, &QAction::triggered, this, [this, action] { ITaskHandler *h = d->handler(action); if (h) - h->handle(d->m_filter->tasks(d->m_listview->selectionModel()->selectedIndexes())); + h->handle(d->m_filter->tasks(d->m_treeView.selectionModel()->selectedIndexes())); }); d->m_actions << action; @@ -425,7 +296,7 @@ void TaskWindow::delayedInitialization() Core::ActionManager::registerAction(action, id, d->m_taskWindowContext->context(), true); action = cmd->action(); } - d->m_listview->addAction(action); + d->m_treeView.addAction(action); } } @@ -441,7 +312,7 @@ QString TaskWindow::displayName() const QWidget *TaskWindow::outputWidget(QWidget *) { - return d->m_listview; + return &d->m_treeView; } void TaskWindow::clearTasks(Id categoryId) @@ -545,7 +416,7 @@ void TaskWindow::showTask(const Task &task) int sourceRow = d->m_model->rowForTask(task); QModelIndex sourceIdx = d->m_model->index(sourceRow, 0); QModelIndex filterIdx = d->m_filter->mapFromSource(sourceIdx); - d->m_listview->setCurrentIndex(filterIdx); + d->m_treeView.setCurrentIndex(filterIdx); popup(Core::IOutputPane::ModeSwitch); } @@ -562,7 +433,10 @@ void TaskWindow::triggerDefaultHandler(const QModelIndex &index) if (!index.isValid() || !d->m_defaultHandler) return; - Task task(d->m_filter->task(index)); + QModelIndex taskIndex = index; + if (index.parent().isValid()) + taskIndex = index.parent(); + Task task(d->m_filter->task(taskIndex)); if (task.isNull()) return; @@ -579,7 +453,7 @@ void TaskWindow::triggerDefaultHandler(const QModelIndex &index) d->m_defaultHandler->handle(task); } else { if (!task.file.exists()) - d->m_model->setFileNotFound(index, true); + d->m_model->setFileNotFound(taskIndex, true); } } @@ -645,7 +519,7 @@ void TaskWindow::clearContents() bool TaskWindow::hasFocus() const { - return d->m_listview->window()->focusWidget() == d->m_listview; + return d->m_treeView.window()->focusWidget() == &d->m_treeView; } bool TaskWindow::canFocus() const @@ -656,9 +530,13 @@ bool TaskWindow::canFocus() const void TaskWindow::setFocus() { if (d->m_filter->rowCount()) { - d->m_listview->setFocus(); - if (d->m_listview->currentIndex() == QModelIndex()) - d->m_listview->setCurrentIndex(d->m_filter->index(0,0, QModelIndex())); + d->m_treeView.setFocus(); + if (!d->m_treeView.currentIndex().isValid()) + d->m_treeView.setCurrentIndex(d->m_filter->index(0,0, QModelIndex())); + if (d->m_treeView.selectionModel()->selection().isEmpty()) { + d->m_treeView.selectionModel()->setCurrentIndex(d->m_treeView.currentIndex(), + QItemSelectionModel::Select); + } } } @@ -676,7 +554,7 @@ void TaskWindow::goToNext() { if (!canNext()) return; - QModelIndex startIndex = d->m_listview->currentIndex(); + QModelIndex startIndex = d->m_treeView.currentIndex(); QModelIndex currentIndex = startIndex; if (startIndex.isValid()) { @@ -691,7 +569,7 @@ void TaskWindow::goToNext() } else { currentIndex = d->m_filter->index(0, 0); } - d->m_listview->setCurrentIndex(currentIndex); + d->m_treeView.setCurrentIndex(currentIndex); triggerDefaultHandler(currentIndex); } @@ -699,7 +577,7 @@ void TaskWindow::goToPrev() { if (!canPrevious()) return; - QModelIndex startIndex = d->m_listview->currentIndex(); + QModelIndex startIndex = d->m_treeView.currentIndex(); QModelIndex currentIndex = startIndex; if (startIndex.isValid()) { @@ -714,7 +592,7 @@ void TaskWindow::goToPrev() } else { currentIndex = d->m_filter->index(0, 0); } - d->m_listview->setCurrentIndex(currentIndex); + d->m_treeView.setCurrentIndex(currentIndex); triggerDefaultHandler(currentIndex); } @@ -729,149 +607,161 @@ bool TaskWindow::canNavigate() const return true; } -///// -// Delegate -///// +void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if (!needsSpecialHandling(index)) { + QStyledItemDelegate::paint(painter, option, index); + return; + } -TaskDelegate::TaskDelegate(QObject *parent) : - QStyledItemDelegate(parent) -{ } + QStyleOptionViewItem options = option; + initStyleOption(&options, index); -TaskDelegate::~TaskDelegate() = default; + painter->save(); + m_doc.setHtml(options.text); + options.text = ""; + options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter); + painter->translate(options.rect.left(), options.rect.top()); + QRect clip(0, 0, options.rect.width(), options.rect.height()); + QAbstractTextDocumentLayout::PaintContext paintContext; + paintContext.palette = options.palette; + painter->setClipRect(clip); + paintContext.clip = clip; + if (qobject_cast(options.widget) + ->selectionModel()->isSelected(index)) { + QAbstractTextDocumentLayout::Selection selection; + selection.cursor = QTextCursor(&m_doc); + selection.cursor.select(QTextCursor::Document); + selection.format.setBackground(options.palette.brush(QPalette::Highlight)); + selection.format.setForeground(options.palette.brush(QPalette::HighlightedText)); + paintContext.selections << selection; + } + m_doc.documentLayout()->draw(painter, paintContext); + painter->restore(); +} QSize TaskDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - QStyleOptionViewItem opt = option; - initStyleOption(&opt, index); + if (!needsSpecialHandling(index)) + return QStyledItemDelegate::sizeHint(option, index); - QSize s; - s.setWidth(option.rect.width()); - - if (option.font == m_cachedFont && m_cachedHeight > 0) { - s.setHeight(m_cachedHeight); - return s; - } - - s.setHeight(option.fontMetrics.height() + 3); - if (s.height() < Positions::minimumHeight()) - s.setHeight(Positions::minimumHeight()); - m_cachedHeight = s.height(); - m_cachedFont = option.font; - - return s; + QStyleOptionViewItem options = option; + initStyleOption(&options, index); + m_doc.setHtml(options.text); + m_doc.setTextWidth(options.rect.width()); + return QSize(m_doc.idealWidth(), m_doc.size().height()); } -void TaskDelegate::emitSizeHintChanged(const QModelIndex &index) +bool TaskDelegate::needsSpecialHandling(const QModelIndex &index) const { - emit sizeHintChanged(index); + QModelIndex sourceIndex = index; + if (const auto proxyModel = qobject_cast(index.model())) + sourceIndex = proxyModel->mapToSource(index); + return sourceIndex.internalId(); } -void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +void TaskView::resizeColumns() { - QStyleOptionViewItem opt = option; - initStyleOption(&opt, index); - painter->save(); + setColumnWidth(0, width() * 0.85); + setColumnWidth(1, width() * 0.15); +} - QFontMetrics fm(opt.font); - QColor backgroundColor; - QColor textColor; +void TaskView::resizeEvent(QResizeEvent *e) +{ + TreeView::resizeEvent(e); + resizeColumns(); +} - auto view = qobject_cast(opt.widget); - const bool selected = view->selectionModel()->isSelected(index); +void TaskView::mousePressEvent(QMouseEvent *e) +{ + m_clickAnchor = anchorAt(e->pos()); + if (m_clickAnchor.isEmpty()) + TreeView::mousePressEvent(e); +} - if (selected) { - painter->setBrush(opt.palette.highlight().color()); - backgroundColor = opt.palette.highlight().color(); - } else { - painter->setBrush(opt.palette.window().color()); - backgroundColor = opt.palette.window().color(); +void TaskView::mouseMoveEvent(QMouseEvent *e) +{ + const QString anchor = anchorAt(e->pos()); + if (m_clickAnchor != anchor) + m_clickAnchor.clear(); + if (m_hoverAnchor != anchor) { + m_hoverAnchor = anchor; + if (!m_hoverAnchor.isEmpty()) + QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); + else + QApplication::restoreOverrideCursor(); } - painter->setPen(Qt::NoPen); - painter->drawRect(opt.rect); +} - // Set Text Color - if (selected) - textColor = opt.palette.highlightedText().color(); - else - textColor = opt.palette.text().color(); - - painter->setPen(textColor); - - auto model = static_cast(view->model())->taskModel(); - Positions positions(opt, model); - - // Paint TaskIconArea: - QIcon icon = index.data(TaskModel::Icon).value(); - painter->drawPixmap(positions.left(), positions.top(), - icon.pixmap(Positions::taskIconWidth(), Positions::taskIconHeight())); - - // Paint TextArea: - QString bottom = index.data(TaskModel::Description).toString().split(QLatin1Char('\n')).first(); - painter->setClipRect(positions.textArea()); - painter->drawText(positions.textAreaLeft(), positions.top() + fm.ascent(), bottom); - if (fm.horizontalAdvance(bottom) > positions.textAreaWidth()) { - // draw a gradient to mask the text - int gradientStart = positions.textAreaRight() - ELLIPSIS_GRADIENT_WIDTH + 1; - QLinearGradient lg(gradientStart, 0, gradientStart + ELLIPSIS_GRADIENT_WIDTH, 0); - lg.setColorAt(0, Qt::transparent); - lg.setColorAt(1, backgroundColor); - painter->fillRect(gradientStart, positions.top(), ELLIPSIS_GRADIENT_WIDTH, positions.firstLineHeight(), lg); +void TaskView::mouseReleaseEvent(QMouseEvent *e) +{ + if (m_clickAnchor.isEmpty()) { + TreeView::mouseReleaseEvent(e); + return; } - // Paint FileArea - QString file = index.data(TaskModel::File).toString(); - const int pos = file.lastIndexOf(QLatin1Char('/')); - if (pos != -1) - file = file.mid(pos +1); - const int realFileWidth = fm.horizontalAdvance(file); - painter->setClipRect(positions.fileArea()); - painter->drawText(qMin(positions.fileAreaLeft(), positions.fileAreaRight() - realFileWidth), - positions.top() + fm.ascent(), file); - if (realFileWidth > positions.fileAreaWidth()) { - // draw a gradient to mask the text - int gradientStart = positions.fileAreaLeft() - 1; - QLinearGradient lg(gradientStart + ELLIPSIS_GRADIENT_WIDTH, 0, gradientStart, 0); - lg.setColorAt(0, Qt::transparent); - lg.setColorAt(1, backgroundColor); - painter->fillRect(gradientStart, positions.top(), ELLIPSIS_GRADIENT_WIDTH, positions.firstLineHeight(), lg); + const QString anchor = anchorAt(e->pos()); + if (anchor == m_clickAnchor) { + Core::EditorManager::openEditorAt(OutputLineParser::parseLinkTarget(m_clickAnchor), {}, + Core::EditorManager::SwitchSplitIfAlreadyVisible); + } + m_clickAnchor.clear(); +} + +void TaskView::keyReleaseEvent(QKeyEvent *e) +{ + TreeView::keyReleaseEvent(e); + if (e->key() == Qt::Key_Space) { + const Task task = static_cast(model())->task(currentIndex()); + if (!task.isNull()) { + const QPoint toolTipPos = mapToGlobal(visualRect(currentIndex()).topLeft()); + QMetaObject::invokeMethod(this, [this, task, toolTipPos] { + showToolTip(task, toolTipPos); }, Qt::QueuedConnection); + } + } +} + +bool TaskView::event(QEvent *e) +{ + if (e->type() != QEvent::ToolTip) + return TreeView::event(e); + + const auto helpEvent = static_cast(e); + const Task task = static_cast(model())->task(indexAt(helpEvent->pos())); + if (task.isNull()) + return TreeView::event(e); + showToolTip(task, helpEvent->globalPos()); + e->accept(); + return true; +} + +void TaskView::showToolTip(const Task &task, const QPoint &pos) +{ + if (task.details.isEmpty()) { + ToolTip::hideImmediately(); + return; } - // Paint LineArea - int line = index.data(TaskModel::Line).toInt(); - int movedLine = index.data(TaskModel::MovedLine).toInt(); - QString lineText; + const auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(new QLabel(task.formattedDescription({}))); + ToolTip::show(pos, layout); +} - if (line == -1) { - // No line information at all - } else if (movedLine == -1) { - // removed the line, but we had line information, show the line in () - QFont f = painter->font(); - f.setItalic(true); - painter->setFont(f); - lineText = QLatin1Char('(') + QString::number(line) + QLatin1Char(')'); - } else if (movedLine != line) { - // The line was moved - QFont f = painter->font(); - f.setItalic(true); - painter->setFont(f); - lineText = QString::number(movedLine); - } else { - lineText = QString::number(line); - } +QString TaskView::anchorAt(const QPoint &pos) +{ + const QModelIndex index = indexAt(pos); + if (!index.isValid() || !index.internalId()) + return {}; - painter->setClipRect(positions.lineArea()); - const int realLineWidth = fm.horizontalAdvance(lineText); - painter->drawText(positions.lineAreaRight() - realLineWidth, positions.top() + fm.ascent(), lineText); - painter->setClipRect(opt.rect); - - // Separator lines - painter->setPen(QColor::fromRgb(150,150,150)); - const QRectF borderRect = QRectF(opt.rect).adjusted(0.5, 0.5, -0.5, -0.5); - painter->drawLine(borderRect.bottomLeft(), borderRect.bottomRight()); - painter->restore(); + const QRect itemRect = visualRect(index); + QTextDocument &doc = static_cast(itemDelegate())->doc(); + doc.setHtml(model()->data(index, Qt::DisplayRole).toString()); + const QAbstractTextDocumentLayout * const textLayout = doc.documentLayout(); + QTC_ASSERT(textLayout, return {}); + return textLayout->anchorAt(pos - itemRect.topLeft()); } } // namespace Internal } // namespace ProjectExplorer - -#include "taskwindow.moc" From b30983d3c72863297103f35a303149fe70147945 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 10:54:27 +0200 Subject: [PATCH 0570/1447] CppLocatorFilterTest: Add locator matchers tests Change-Id: Ifc9b25bd8503c75724ffec2a0ebd855e61a19bc6 Reviewed-by: Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../cppeditor/cpplocatorfilter_test.cpp | 58 +++++++++++++++---- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index 5b443ad42ce..7c70ee35bae 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -3,8 +3,6 @@ #include "cpplocatorfilter_test.h" -#include "cppcurrentdocumentfilter.h" -#include "cpplocatorfilter.h" #include "cppmodelmanager.h" #include "cpptoolstestcase.h" @@ -37,6 +35,7 @@ class CppLocatorFilterTestCase { public: CppLocatorFilterTestCase(ILocatorFilter *filter, + const QList &matchers, const QString &fileName, const QString &searchText, const ResultDataList &expectedResults) @@ -47,7 +46,15 @@ public: QVERIFY(!m_fileName.isEmpty()); QVERIFY(garbageCollectGlobalSnapshot()); - ResultDataList results = ResultData::fromFilterEntryList(matchesFor(searchText)); + const auto runMatcher = [this, matchers, searchText] { + CppLocatorFilterTestCase::doBeforeLocatorRun(); + const auto result = LocatorMatcher::runBlocking(matchers, searchText); + CppLocatorFilterTestCase::doAfterLocatorRun(); + return result; + }; + + const QList entries = filter ? matchesFor(searchText) : runMatcher(); + const ResultDataList results = ResultData::fromFilterEntryList(entries); if (debug) { ResultData::printFilterEntries(expectedResults, "Expected:"); ResultData::printFilterEntries(results, "Results:"); @@ -114,31 +121,44 @@ private: } // anonymous namespace +using MatcherCreator = std::function()>; + void LocatorFilterTest::testLocatorFilter() { QFETCH(QString, testFile); QFETCH(ILocatorFilter *, filter); + QFETCH(MatcherCreator, matcherCreator); QFETCH(QString, searchText); QFETCH(ResultDataList, expectedResults); - Tests::VerifyCleanCppModelManager verify; + { + Tests::VerifyCleanCppModelManager verify; + CppLocatorFilterTestCase(filter, {}, testFile, searchText, expectedResults); + } - CppLocatorFilterTestCase(filter, testFile, searchText, expectedResults); + { + Tests::VerifyCleanCppModelManager verify; + CppLocatorFilterTestCase(nullptr, matcherCreator(), testFile, searchText, expectedResults); + } } void LocatorFilterTest::testLocatorFilter_data() { QTest::addColumn("testFile"); QTest::addColumn("filter"); + QTest::addColumn("matcherCreator"); QTest::addColumn("searchText"); QTest::addColumn("expectedResults"); CppModelManager *cppModelManager = CppModelManager::instance(); - ILocatorFilter *cppFunctionsFilter = cppModelManager->functionsFilter(); ILocatorFilter *cppClassesFilter = cppModelManager->classesFilter(); ILocatorFilter *cppLocatorFilter = cppModelManager->locatorFilter(); + const MatcherCreator functionMatcherCreator = &LocatorMatcher::functionMatchers; + const MatcherCreator classMatcherCreator = &LocatorMatcher::classMatchers; + const MatcherCreator locatorMatcherCreator = &LocatorMatcher::locatorMatchers; + MyTestDataDir testDirectory("testdata_basic"); QString testFile = testDirectory.file("file1.cpp"); testFile[0] = testFile[0].toLower(); // Ensure Windows path sorts after scope names. @@ -149,6 +169,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter") << testFile << cppFunctionsFilter + << functionMatcherCreator << "function" << ResultDataList{ ResultData("functionDefinedInClass(bool, int)", @@ -171,6 +192,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-Sorting") << testFile << cppFunctionsFilter + << functionMatcherCreator << "pos" << ResultDataList{ ResultData("positiveNumber()", testFileShort), @@ -182,6 +204,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-arguments") << testFile << cppFunctionsFilter + << functionMatcherCreator << "function*bool" << ResultDataList{ ResultData("functionDefinedInClass(bool, int)", @@ -198,6 +221,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-WithNamespacePrefix") << testFile << cppFunctionsFilter + << functionMatcherCreator << "mynamespace::" << ResultDataList{ ResultData("MyClass()", "MyNamespace::MyClass (file1.cpp)"), @@ -213,6 +237,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-WithClassPrefix") << testFile << cppFunctionsFilter + << functionMatcherCreator << "MyClass::func" << ResultDataList{ ResultData("functionDefinedInClass(bool, int)", @@ -234,6 +259,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter") << testFile << cppClassesFilter + << classMatcherCreator << "myclass" << ResultDataList{ ResultData("MyClass", ""), @@ -244,6 +270,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter-WithNamespacePrefix") << testFile << cppClassesFilter + << classMatcherCreator << "mynamespace::" << ResultDataList{ ResultData("MyClass", "MyNamespace") @@ -253,6 +280,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppLocatorFilter-filtered") << testFile << cppLocatorFilter + << locatorMatcherCreator << "my" << ResultDataList{ ResultData("MyClass", testFileShort), @@ -279,6 +307,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter-ObjC") << objTestFile << cppClassesFilter + << classMatcherCreator << "M" << ResultDataList{ ResultData("MyClass", objTestFileShort), @@ -290,6 +319,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-ObjC") << objTestFile << cppFunctionsFilter + << functionMatcherCreator << "M" << ResultDataList{ ResultData("anotherMethod", "MyClass (file1.mm)"), @@ -389,12 +419,18 @@ void LocatorFilterTest::testFunctionsFilterHighlighting() " ~~~ ") }; - CppModelManager *cppModelManager = CppModelManager::instance(); - ILocatorFilter *filter = cppModelManager->functionsFilter(); + { + Tests::VerifyCleanCppModelManager verify; + CppModelManager *cppModelManager = CppModelManager::instance(); + ILocatorFilter *filter = cppModelManager->functionsFilter(); + CppLocatorFilterTestCase(filter, {}, testFile, searchText, expectedResults); + } - Tests::VerifyCleanCppModelManager verify; - - CppLocatorFilterTestCase(filter, testFile, searchText, expectedResults); + { + Tests::VerifyCleanCppModelManager verify; + const MatcherCreator matcherCreator = &LocatorMatcher::functionMatchers; + CppLocatorFilterTestCase(nullptr, matcherCreator(), testFile, searchText, expectedResults); + } } } // namespace CppEditor::Internal From dd7020d690ba9150fb76daf274277276fdfe3555 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 18 Apr 2023 16:28:28 +0200 Subject: [PATCH 0571/1447] ProjectExplorer: Postpone Kit widget creation ... at least conceptually. This has not visible effect yet, as they widget-creating code paths are triggered quickly. Change-Id: Ibef3a4221885fa76cf5c1c327dcb3c2e6bdcbd1b Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/kitmodel.cpp | 114 +++++++++++++---------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/src/plugins/projectexplorer/kitmodel.cpp b/src/plugins/projectexplorer/kitmodel.cpp index 4b250f23c98..f1d0c3645d3 100644 --- a/src/plugins/projectexplorer/kitmodel.cpp +++ b/src/plugins/projectexplorer/kitmodel.cpp @@ -24,57 +24,72 @@ namespace Internal { class KitNode : public TreeItem { public: - KitNode(Kit *k, KitModel *m) - { - widget = new KitManagerConfigWidget(k); + KitNode(Kit *k, KitModel *m, QBoxLayout *parentLayout) + : m_kit(k), m_model(m), m_parentLayout(parentLayout) + {} - QObject::connect(widget, &KitManagerConfigWidget::dirty, m, [this] { update(); }); - - QObject::connect(widget, &KitManagerConfigWidget::isAutoDetectedChanged, m, [this, m] { - TreeItem *oldParent = parent(); - TreeItem *newParent = - m->rootItem()->childAt(widget->workingCopy()->isAutoDetected() ? 0 : 1); - if (oldParent && oldParent != newParent) { - m->takeItem(this); - newParent->appendChild(this); - } - }); - } - - ~KitNode() override - { - delete widget; - } + ~KitNode() override { delete m_widget; } QVariant data(int, int role) const override { - if (widget) { + if (m_widget) { if (role == Qt::FontRole) { QFont f = QApplication::font(); - if (widget->isDirty()) + if (m_widget->isDirty()) f.setBold(!f.bold()); - if (widget->isDefaultKit()) + if (m_widget->isDefaultKit()) f.setItalic(f.style() != QFont::StyleItalic); return f; } if (role == Qt::DisplayRole) { - QString baseName = widget->displayName(); - if (widget->isDefaultKit()) + QString baseName = m_widget->displayName(); + if (m_widget->isDefaultKit()) //: Mark up a kit as the default one. baseName = Tr::tr("%1 (default)").arg(baseName); return baseName; } if (role == Qt::DecorationRole) { - return widget->displayIcon(); + return m_widget->displayIcon(); } if (role == Qt::ToolTipRole) { - return widget->validityMessage(); + return m_widget->validityMessage(); } } return QVariant(); } - KitManagerConfigWidget *widget; + KitManagerConfigWidget *widget() const + { + const_cast(this)->ensureWidget(); + return m_widget; + } + +private: + void ensureWidget() + { + if (m_widget) + return; + + m_widget = new KitManagerConfigWidget(m_kit); + + QObject::connect(m_widget, &KitManagerConfigWidget::dirty, m_model, [this] { update(); }); + + QObject::connect(m_widget, &KitManagerConfigWidget::isAutoDetectedChanged, m_model, [this] { + TreeItem *oldParent = parent(); + TreeItem *newParent = + m_model->rootItem()->childAt(m_widget->workingCopy()->isAutoDetected() ? 0 : 1); + if (oldParent && oldParent != newParent) { + m_model->takeItem(this); + newParent->appendChild(this); + } + }); + m_parentLayout->addWidget(m_widget); + } + + Kit *m_kit = m_kit; + KitModel *m_model = nullptr; + KitManagerConfigWidget *m_widget = nullptr; + QBoxLayout *m_parentLayout = nullptr; }; // -------------------------------------------------------------------------- @@ -113,7 +128,7 @@ KitModel::KitModel(QBoxLayout *parentLayout, QObject *parent) Kit *KitModel::kit(const QModelIndex &index) { KitNode *n = kitNode(index); - return n ? n->widget->workingCopy() : nullptr; + return n ? n->widget()->workingCopy() : nullptr; } KitNode *KitModel::kitNode(const QModelIndex &index) @@ -136,20 +151,20 @@ void KitModel::setDefaultKit(const QModelIndex &index) bool KitModel::isDefaultKit(Kit *k) const { - return m_defaultNode && m_defaultNode->widget->workingCopy() == k; + return m_defaultNode && m_defaultNode->widget()->workingCopy() == k; } KitManagerConfigWidget *KitModel::widget(const QModelIndex &index) { KitNode *n = kitNode(index); - return n ? n->widget : nullptr; + return n ? n->widget() : nullptr; } void KitModel::validateKitNames() { QHash nameHash; forItemsAtLevel<2>([&nameHash](KitNode *n) { - const QString displayName = n->widget->displayName(); + const QString displayName = n->widget()->displayName(); if (nameHash.contains(displayName)) ++nameHash[displayName]; else @@ -157,8 +172,8 @@ void KitModel::validateKitNames() }); forItemsAtLevel<2>([&nameHash](KitNode *n) { - const QString displayName = n->widget->displayName(); - n->widget->setHasUniqueName(nameHash.value(displayName) == 1); + const QString displayName = n->widget()->displayName(); + n->widget()->setHasUniqueName(nameHash.value(displayName) == 1); }); } @@ -166,8 +181,8 @@ void KitModel::apply() { // Add/update dirty nodes before removing kits. This ensures the right kit ends up as default. forItemsAtLevel<2>([](KitNode *n) { - if (n->widget->isDirty()) { - n->widget->apply(); + if (n->widget()->isDirty()) { + n->widget()->apply(); n->update(); } }); @@ -175,7 +190,7 @@ void KitModel::apply() // Remove unused kits: const QList removeList = m_toRemoveList; for (KitNode *n : removeList) - n->widget->removeKit(); + n->widget()->removeKit(); emit layoutChanged(); // Force update. } @@ -197,7 +212,7 @@ void KitModel::markForRemoval(Kit *k) setDefaultNode(findItemAtLevel<2>([node](KitNode *kn) { return kn != node; })); takeItem(node); - if (node->widget->configures(nullptr)) + if (node->widget()->configures(nullptr)) delete node; else m_toRemoveList.append(node); @@ -209,7 +224,7 @@ Kit *KitModel::markForAddition(Kit *baseKit) const QString newName = newKitName(baseKit ? baseKit->unexpandedDisplayName() : QString()); KitNode *node = createNode(nullptr); m_manualRoot->appendChild(node); - Kit *k = node->widget->workingCopy(); + Kit *k = node->widget()->workingCopy(); KitGuard g(k); if (baseKit) { k->copyFrom(baseKit); @@ -229,7 +244,7 @@ Kit *KitModel::markForAddition(Kit *baseKit) void KitModel::updateVisibility() { forItemsAtLevel<2>([](const TreeItem *ti) { - static_cast(ti)->widget->updateVisibility(); + static_cast(ti)->widget()->updateVisibility(); }); } @@ -237,32 +252,31 @@ QString KitModel::newKitName(const QString &sourceName) const { QList allKits; forItemsAtLevel<2>([&allKits](const TreeItem *ti) { - allKits << static_cast(ti)->widget->workingCopy(); + allKits << static_cast(ti)->widget()->workingCopy(); }); return Kit::newKitName(sourceName, allKits); } KitNode *KitModel::findWorkingCopy(Kit *k) const { - return findItemAtLevel<2>([k](KitNode *n) { return n->widget->workingCopy() == k; }); + return findItemAtLevel<2>([k](KitNode *n) { return n->widget()->workingCopy() == k; }); } KitNode *KitModel::createNode(Kit *k) { - auto node = new KitNode(k, this); - m_parentLayout->addWidget(node->widget); + auto node = new KitNode(k, this, m_parentLayout); return node; } void KitModel::setDefaultNode(KitNode *node) { if (m_defaultNode) { - m_defaultNode->widget->setIsDefaultKit(false); + m_defaultNode->widget()->setIsDefaultKit(false); m_defaultNode->update(); } m_defaultNode = node; if (m_defaultNode) { - m_defaultNode->widget->setIsDefaultKit(true); + m_defaultNode->widget()->setIsDefaultKit(true); m_defaultNode->update(); } } @@ -271,7 +285,7 @@ void KitModel::addKit(Kit *k) { for (TreeItem *n : *m_manualRoot) { // Was added by us - if (static_cast(n)->widget->isRegistering()) + if (static_cast(n)->widget()->isRegistering()) return; } @@ -292,7 +306,7 @@ void KitModel::removeKit(Kit *k) { QList nodes = m_toRemoveList; for (KitNode *n : std::as_const(nodes)) { - if (n->widget->configures(k)) { + if (n->widget()->configures(k)) { m_toRemoveList.removeOne(n); if (m_defaultNode == n) m_defaultNode = nullptr; @@ -303,7 +317,7 @@ void KitModel::removeKit(Kit *k) } KitNode *node = findItemAtLevel<2>([k](KitNode *n) { - return n->widget->configures(k); + return n->widget()->configures(k); }); if (node == m_defaultNode) @@ -319,7 +333,7 @@ void KitModel::changeDefaultKit() { Kit *defaultKit = KitManager::defaultKit(); KitNode *node = findItemAtLevel<2>([defaultKit](KitNode *n) { - return n->widget->configures(defaultKit); + return n->widget()->configures(defaultKit); }); setDefaultNode(node); } From f98a03a28d823a1bdffc57009ebef2637811aebb Mon Sep 17 00:00:00 2001 From: Jussi Witick Date: Wed, 19 Apr 2023 10:44:53 +0300 Subject: [PATCH 0572/1447] Fix namespace usage in QSR project wizard template Consistently use namespaces with different feature if/def's in main.cpp Task-number: QSR-2079 Change-Id: I0609f7eb8cb18d270e59c11025850e6369e5db87 Reviewed-by: Teemu Holappa --- src/plugins/saferenderer/wizards/qsrapp/main.cpp.tpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/saferenderer/wizards/qsrapp/main.cpp.tpl b/src/plugins/saferenderer/wizards/qsrapp/main.cpp.tpl index 4f36c6f6fa3..c491bee9aeb 100644 --- a/src/plugins/saferenderer/wizards/qsrapp/main.cpp.tpl +++ b/src/plugins/saferenderer/wizards/qsrapp/main.cpp.tpl @@ -28,23 +28,23 @@ int main(int argc, char *argv[]) static SafeRenderer::QSafeLayoutResourceReader layout("/layoutData/main/main.srl"); #if defined(USE_OUTPUTVERIFIER) - static OutputVerifier outputVerifier; + static SafeRenderer::OutputVerifier outputVerifier; #if defined(HOST_BUILD) //In host environment the TestVerifier must be explicitly created. //In OpeWFD adaptation the MISRVerifier instance is created in the SafeWindow adaptation. - static TestVerifier testVerifier(outputVerifier); + static SafeRenderer::TestVerifier testVerifier(outputVerifier); #endif - SafeWindow telltaleWindow(layout.size(), QSafePoint(0U, 0U), outputVerifier); + SafeRenderer::SafeWindow telltaleWindow(layout.size(), SafeRenderer::QSafePoint(0U, 0U), outputVerifier); #else - SafeWindow telltaleWindow(layout.size(), QSafePoint(0U, 0U)); + SafeRenderer::SafeWindow telltaleWindow(layout.size(), SafeRenderer::QSafePoint(0U, 0U)); #endif static SafeRenderer::StateManager stateManager(telltaleWindow, layout); telltaleWindow.requestUpdate(); //Request is required because eventHandler is not running yet. #if defined(USE_OUTPUTVERIFIER) - EventHandler msgHandler(stateManager, telltaleWindow, outputVerifier); + SafeRenderer::EventHandler msgHandler(stateManager, telltaleWindow, outputVerifier); #else - EventHandler msgHandler(stateManager, telltaleWindow); + SafeRenderer::EventHandler msgHandler(stateManager, telltaleWindow); #endif #if defined(HOST_BUILD) From 9eb826f3931ad9ed32582c709cee06d3fc7843d0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 23:12:36 +0200 Subject: [PATCH 0573/1447] JavaScriptFilter: Use Acceptor for LocatorFilterEntry Change-Id: Icceb830a391809cc760adf106e6c9e8b71dcb176 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- .../coreplugin/locator/javascriptfilter.cpp | 59 ++++++++----------- .../coreplugin/locator/javascriptfilter.h | 3 - 2 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 37803abbaaa..a0fb181b56d 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -12,8 +12,6 @@ namespace Core { namespace Internal { -enum class EngineAction { Reset = 1, Abort }; - JavaScriptFilter::JavaScriptFilter() { setId("JavaScriptFilter"); @@ -52,53 +50,46 @@ QList JavaScriptFilter::matchesFor( QList entries; if (entry.trimmed().isEmpty()) { - LocatorFilterEntry entry{this, Tr::tr("Reset Engine")}; - entry.internalData = QVariant::fromValue(EngineAction::Reset); + LocatorFilterEntry entry; + entry.displayName = Tr::tr("Reset Engine"); + entry.acceptor = [this] { + m_engine.reset(); + return AcceptResult(); + }; entries.append(entry); } else { + // Note, that evaluate may be interrupted from caller thread. + // In this case m_aborted is set to true. const QString result = m_engine->evaluate(entry).toString(); if (m_aborted) { const QString message = entry + " = " + Tr::tr("Engine aborted after timeout."); - LocatorFilterEntry entry(this, message); - entry.internalData = QVariant::fromValue(EngineAction::Abort); + LocatorFilterEntry entry; + entry.displayName = message; + entry.acceptor = [] { return AcceptResult(); }; entries.append(entry); } else { + const auto acceptor = [](const QString &clipboardContents) { + return [clipboardContents] { + QGuiApplication::clipboard()->setText(clipboardContents); + return AcceptResult(); + }; + }; const QString expression = entry + " = " + result; entries.append({this, expression}); - LocatorFilterEntry resultEntry(this, Tr::tr("Copy to clipboard: %1").arg(result)); - resultEntry.internalData = result; + LocatorFilterEntry resultEntry; + resultEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(result); + resultEntry.acceptor = acceptor(result); entries.append(resultEntry); - LocatorFilterEntry expressionEntry(this, Tr::tr("Copy to clipboard: %1").arg(expression)); - resultEntry.internalData = expression; + + LocatorFilterEntry expressionEntry; + expressionEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(expression); + expressionEntry.acceptor = acceptor(expression); entries.append(expressionEntry); } } - return entries; } -void JavaScriptFilter::accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - - if (selection.internalData.isNull()) - return; - - const EngineAction action = selection.internalData.value(); - if (action == EngineAction::Reset) { - m_engine.reset(); - return; - } - if (action == EngineAction::Abort) - return; - - QClipboard *clipboard = QGuiApplication::clipboard(); - clipboard->setText(selection.internalData.toString()); -} - void JavaScriptFilter::setupEngine() { m_engine.reset(new QJSEngine); @@ -130,5 +121,3 @@ void JavaScriptFilter::setupEngine() } // namespace Internal } // namespace Core - -Q_DECLARE_METATYPE(Core::Internal::EngineAction) diff --git a/src/plugins/coreplugin/locator/javascriptfilter.h b/src/plugins/coreplugin/locator/javascriptfilter.h index 5153e0b7b56..b65abf53439 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.h +++ b/src/plugins/coreplugin/locator/javascriptfilter.h @@ -27,9 +27,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const override; - private: void setupEngine(); From a5ad7221841e9fd2c358f1b2a43cfb0fc0c819b9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 19 Apr 2023 10:17:48 +0200 Subject: [PATCH 0574/1447] QtVersionManager: Fix a warning about missing initializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It fixes the following warning: warning: missing initializer for member ‘QtSupport::Internal::ExampleSetModel::ExtraExampleSet::qtVersion’ Amends bdfa412b14174e7e81b899ae8323fc78ddd7916e Change-Id: Ieb984664953f53d458297970e09678c499a26197 Reviewed-by: Eike Ziller --- src/plugins/qtsupport/exampleslistmodel.h | 2 +- src/plugins/qtsupport/qtversionmanager.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h index c444f9bc1e7..f0465655b79 100644 --- a/src/plugins/qtsupport/exampleslistmodel.h +++ b/src/plugins/qtsupport/exampleslistmodel.h @@ -31,7 +31,7 @@ public: // qtVersion is set by recreateModel for extra sets that correspond to actual Qt versions. // This is needed for the decision to show categories or not based on the Qt version // (which is not ideal). - QVersionNumber qtVersion; + QVersionNumber qtVersion = {}; }; static QVector pluginRegisteredExampleSets(); diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index c5a0f7b315e..e9a3691cdb9 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -5,7 +5,6 @@ #include "baseqtversion.h" #include "exampleslistmodel.h" -#include "qtkitinformation.h" #include "qtsupportconstants.h" #include "qtversionfactory.h" From 39b8bdab1788284c96efbf35bfadc07a1d76d85a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 19:17:55 +0200 Subject: [PATCH 0575/1447] BookmarkFilter: Use Acceptor for LocatorFilterEntry Change-Id: Idc3e0541b53277ab8e0cdc8626df7f9095f24ba9 Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/bookmarks/bookmarkfilter.cpp | 24 +++++++++++------------- src/plugins/bookmarks/bookmarkfilter.h | 3 --- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index 28a03ce0074..f5af4c9b5fb 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -58,9 +58,17 @@ void BookmarkFilter::prepareSearch(const QString &entry) for (const QModelIndex &idx : matches) { const Bookmark *bookmark = m_manager->bookmarkForIndex(idx); const QString filename = bookmark->filePath().fileName(); - LocatorFilterEntry filterEntry(this, - QString("%1:%2").arg(filename).arg(bookmark->lineNumber())); - filterEntry.internalData = QVariant::fromValue(idx); + LocatorFilterEntry filterEntry; + filterEntry.displayName = QString("%1:%2").arg(filename).arg(bookmark->lineNumber()); + // TODO: according to QModelIndex docs, we shouldn't store model indexes: + // Model indexes should be used immediately and then discarded. + // You should not rely on indexes to remain valid after calling model functions that change + // the structure of the model or delete items. + filterEntry.acceptor = [manager = m_manager, idx] { + if (Bookmark *bookmark = manager->bookmarkForIndex(idx)) + manager->gotoBookmark(bookmark); + return AcceptResult(); + }; if (!bookmark->note().isEmpty()) filterEntry.extraInfo = bookmark->note(); else if (!bookmark->lineText().isEmpty()) @@ -104,14 +112,4 @@ QList BookmarkFilter::matchesFor(QFutureInterfacebookmarkForIndex(selection.internalData.toModelIndex())) - m_manager->gotoBookmark(bookmark); -} - } // Bookmarks::Internal diff --git a/src/plugins/bookmarks/bookmarkfilter.h b/src/plugins/bookmarks/bookmarkfilter.h index 0c69e2b6d45..5745669dc2b 100644 --- a/src/plugins/bookmarks/bookmarkfilter.h +++ b/src/plugins/bookmarks/bookmarkfilter.h @@ -16,9 +16,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const override; - private: BookmarkManager *m_manager = nullptr; // not owned QList m_results; From ee140a8231e58455727afaeb44f36f00c186edcb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 22:56:33 +0200 Subject: [PATCH 0576/1447] LineNumberFilter: Use Acceptor for LocatorFilterEntry Change-Id: Id7da6d01a412633600c3ef905a5ddb18e9587bd7 Reviewed-by: Eike Ziller --- src/plugins/texteditor/linenumberfilter.cpp | 44 ++++++--------------- src/plugins/texteditor/linenumberfilter.h | 7 ---- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index 83f0adaf925..b22c73bfd8b 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -5,19 +5,10 @@ #include "texteditortr.h" -#include #include -#include -#include - -#include -#include -#include - -using LineColumn = QPair; -Q_DECLARE_METATYPE(LineColumn) using namespace Core; +using namespace Utils; namespace TextEditor::Internal { @@ -54,9 +45,6 @@ QList LineNumberFilter::matchesFor(QFutureInterface 0 || column > 0)) { - LineColumn data; - data.first = line; - data.second = column - 1; // column API is 0-based QString text; if (line > 0 && column > 0) text = Tr::tr("Line %1, Column %2").arg(line).arg(column); @@ -64,28 +52,20 @@ QList LineNumberFilter::matchesFor(QFutureInterfacegotoLine(line < 1 ? editor->currentLine() : line, targetColumn); + EditorManager::activateEditor(editor); + return AcceptResult(); + }; value.append(entry); } return value; } -void LineNumberFilter::accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - IEditor *editor = EditorManager::currentEditor(); - if (editor) { - EditorManager::addCurrentPositionToNavigationHistory(); - LineColumn data = selection.internalData.value(); - if (data.first < 1) // jump to column in same line - data.first = editor->currentLine(); - editor->gotoLine(data.first, data.second); - EditorManager::activateEditor(editor); - } -} - } // TextEditor::Internal diff --git a/src/plugins/texteditor/linenumberfilter.h b/src/plugins/texteditor/linenumberfilter.h index 03b52f270ba..70d2c1b6f01 100644 --- a/src/plugins/texteditor/linenumberfilter.h +++ b/src/plugins/texteditor/linenumberfilter.h @@ -5,10 +5,6 @@ #include -#include -#include -#include - namespace Core { class IEditor; } namespace TextEditor { @@ -24,9 +20,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: bool m_hasCurrentEditor = false; }; From b5d7b24733c05eba7a076be0a9da4deda44f9579 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 18 Apr 2023 15:59:30 +0200 Subject: [PATCH 0577/1447] Add wizard for markdown file Fixes: QTCREATORBUG-29056 Change-Id: Ia2ba9aef86aab3e156e3c36d8e28c9f37d7da8b3 Reviewed-by: David Schulz --- .../templates/wizards/files/markdown/file.md | 49 +++++++++++++++++++ .../wizards/files/markdown/wizard.json | 42 ++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 share/qtcreator/templates/wizards/files/markdown/file.md create mode 100644 share/qtcreator/templates/wizards/files/markdown/wizard.json diff --git a/share/qtcreator/templates/wizards/files/markdown/file.md b/share/qtcreator/templates/wizards/files/markdown/file.md new file mode 100644 index 00000000000..2062554585a --- /dev/null +++ b/share/qtcreator/templates/wizards/files/markdown/file.md @@ -0,0 +1,49 @@ +# First Level Heading + +Paragraph. + +## Second Level Heading + +Paragraph. + +- bullet ++ other bullet +* another bullet + * child bullet + +--- + +1. ordered +2. next ordered + +### Third Level Heading + +Some *italic* and **bold** text and `inline code`. + +An empty line starts a new paragraph. + +Use two spaces at the end +to force a line break. + +Add links inline like [this link to the Qt homepage](https://www.qt.io), +or with a reference like [this other link to the Qt homepage][1]. + + Add code blocks with + four spaces at the front. + +> A blockquote +> starts with > +> +> and has the same paragraph rules as normal text. + +First Level Heading in Alternate Style +====================================== + +Paragraph. + +Second Level Heading in Alternate Style +--------------------------------------- + +Paragraph. + +[1]: https://www.qt.io diff --git a/share/qtcreator/templates/wizards/files/markdown/wizard.json b/share/qtcreator/templates/wizards/files/markdown/wizard.json new file mode 100644 index 00000000000..a5e49c755e1 --- /dev/null +++ b/share/qtcreator/templates/wizards/files/markdown/wizard.json @@ -0,0 +1,42 @@ +{ + "version": 1, + "supportedProjectTypes": [ ], + "id": "E.Markdown", + "category": "U.General", + "trDescription": "Creates a markdown file.", + "trDisplayName": "Markdown File", + "trDisplayCategory": "General", + "iconText": "md", + "platformIndependent": true, + "enabled": "%{JS: value('Plugins').indexOf('TextEditor') >= 0}", + + "options": [ + { "key": "FileName", "value": "%{JS: Util.fileName(value('TargetPath'), 'md')}" } + ], + + "pages" : + [ + { + "trDisplayName": "Location", + "trShortTitle": "Location", + "typeId": "File" + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators" : + [ + { + "typeId": "File", + "data": + { + "source": "file.md", + "target": "%{FileName}", + "openInEditor": true + } + } + ] +} From eb98f2f404cc97f94762e9ca035f2a153e58eac5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 22:20:10 +0200 Subject: [PATCH 0578/1447] ActionsFilter: Use Acceptor for LocatorFilterEntry Change-Id: I433f9b44173efd0c66130bcf411cf0ec04816edb Reviewed-by: David Schulz --- src/plugins/coreplugin/actionsfilter.cpp | 32 +++++++++++------------- src/plugins/coreplugin/actionsfilter.h | 3 +-- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index 9aaf5a1db74..b3ef46ca543 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -168,15 +168,12 @@ QList ActionsFilter::matchesFor(QFutureInterface(); - if (data.action) { + return [this, data] { + if (!data.action) + return AcceptResult(); m_lastTriggered.removeAll(data); m_lastTriggered.prepend(data); QMetaObject::invokeMethod(data.action, [action = data.action] { @@ -185,7 +182,8 @@ void ActionsFilter::accept(const LocatorFilterEntry &selection, QString *newText }, Qt::QueuedConnection); if (m_lastTriggered.size() > maxHistorySize) m_lastTriggered.resize(maxHistorySize); - } + return AcceptResult(); + }; } static QString actionText(QAction *action) @@ -214,9 +212,9 @@ void ActionsFilter::collectEntriesForAction(QAction *action, collectEntriesForAction(menuAction, menuPath, processedMenus); } } else if (!text.isEmpty()) { - const ActionFilterEntryData data{action, {}}; - LocatorFilterEntry filterEntry(this, text); - filterEntry.internalData = QVariant::fromValue(data); + LocatorFilterEntry filterEntry; + filterEntry.displayName = text; + filterEntry.acceptor = acceptor({action, {}}); filterEntry.displayIcon = action->icon(); filterEntry.extraInfo = path.join(" > "); updateEntry(action, filterEntry); @@ -243,9 +241,9 @@ void ActionsFilter::collectEntriesForCommands() const QString identifier = command->id().toString(); const QStringList path = identifier.split(QLatin1Char('.')); - const ActionFilterEntryData data{}; - LocatorFilterEntry filterEntry(this, text); - filterEntry.internalData = QVariant::fromValue(ActionFilterEntryData{action, command->id()}); + LocatorFilterEntry filterEntry; + filterEntry.displayName = text; + filterEntry.acceptor = acceptor({action, command->id()}); filterEntry.displayIcon = action->icon(); filterEntry.displayExtra = command->keySequence().toString(QKeySequence::NativeText); if (path.size() >= 2) @@ -263,9 +261,9 @@ void ActionsFilter::collectEntriesForLastTriggered() } if (!data.action || !m_enabledActions.contains(data.action)) continue; - const QString text = actionText(data.action); - LocatorFilterEntry filterEntry(this, text); - filterEntry.internalData = QVariant::fromValue(data); + LocatorFilterEntry filterEntry; + filterEntry.displayName = actionText(data.action); + filterEntry.acceptor = acceptor(data); filterEntry.displayIcon = data.action->icon(); updateEntry(data.action, filterEntry); } diff --git a/src/plugins/coreplugin/actionsfilter.h b/src/plugins/coreplugin/actionsfilter.h index 50a993ad013..3a945c26f9c 100644 --- a/src/plugins/coreplugin/actionsfilter.h +++ b/src/plugins/coreplugin/actionsfilter.h @@ -36,13 +36,12 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const override; void prepareSearch(const QString &entry) override; private: void saveState(QJsonObject &object) const override; void restoreState(const QJsonObject &object) override; + LocatorFilterEntry::Acceptor acceptor(const ActionFilterEntryData &data) const; void collectEntriesForAction(QAction *action, const QStringList &path, QList &processedMenus); From fe067e1d49cdb648b3b387f8a3b4edd94d9b3742 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 00:02:43 +0200 Subject: [PATCH 0579/1447] HelpIndexFilter: Use Acceptor for LocatorFilterEntry Change-Id: If5fbe4f4c7d0f3c7cda3d232be596937b73c6fd0 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/help/helpindexfilter.cpp | 31 ++++++++++++---------------- src/plugins/help/helpindexfilter.h | 10 --------- src/plugins/help/helpplugin.cpp | 8 ++++--- src/plugins/help/helpplugin.h | 2 ++ 4 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 8146b0aa2df..fc6e5b8e24f 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -3,15 +3,16 @@ #include "helpindexfilter.h" -#include "helpmanager.h" -#include "helptr.h" #include "localhelpmanager.h" +#include "helpmanager.h" +#include "helpplugin.h" +#include "helptr.h" -#include #include +#include #include -#include #include +#include #include #include @@ -77,9 +78,14 @@ QList HelpIndexFilter::matchesFor(QFutureInterface entries; - for (const QString &keyword : std::as_const(m_lastIndicesCache)) { - const int index = keyword.indexOf(entry, 0, cs); - LocatorFilterEntry filterEntry(this, keyword); + for (const QString &key : std::as_const(m_lastIndicesCache)) { + const int index = key.indexOf(entry, 0, cs); + LocatorFilterEntry filterEntry; + filterEntry.displayName = key; + filterEntry.acceptor = [key] { + HelpPlugin::showLinksInCurrentViewer(LocalHelpManager::linksForKeyword(key), key); + return AcceptResult(); + }; filterEntry.displayIcon = m_icon; filterEntry.highlightInfo = {index, int(entry.length())}; entries.append(filterEntry); @@ -87,17 +93,6 @@ QList HelpIndexFilter::matchesFor(QFutureInterface links = LocalHelpManager::linksForKeyword(key); - emit linksActivated(links, key); -} - void HelpIndexFilter::invalidateCache() { m_needsUpdate = true; diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h index f836941d483..653d6ff9b7c 100644 --- a/src/plugins/help/helpindexfilter.h +++ b/src/plugins/help/helpindexfilter.h @@ -5,10 +5,6 @@ #include -#include -#include -#include - namespace Help { namespace Internal { @@ -22,12 +18,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - -signals: - void linksActivated(const QMultiMap &links, const QString &key) const; - private: void invalidateCache(); diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index de055889edb..c3a743043c9 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -165,6 +165,11 @@ void HelpPlugin::showHelpUrl(const QUrl &url, Core::HelpManager::HelpViewerLocat dd->showHelpUrl(url, location); } +void HelpPlugin::showLinksInCurrentViewer(const QMultiMap &links, const QString &key) +{ + dd->showLinksInCurrentViewer(links, key); +} + void HelpPlugin::initialize() { dd = new HelpPluginPrivate; @@ -265,9 +270,6 @@ HelpPluginPrivate::HelpPluginPrivate() ActionManager::actionContainer(Core::Constants::M_HELP)->addAction(cmd, Core::Constants::G_HELP_SUPPORT); connect(action, &QAction::triggered, this, &HelpPluginPrivate::slotSystemInformation); - connect(&helpIndexFilter, &HelpIndexFilter::linksActivated, - this, &HelpPluginPrivate::showLinksInCurrentViewer); - connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, &HelpPluginPrivate::modeChanged); diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h index d3a3e0b9801..96d14a152b8 100644 --- a/src/plugins/help/helpplugin.h +++ b/src/plugins/help/helpplugin.h @@ -26,6 +26,8 @@ public: ~HelpPlugin() final; static void showHelpUrl(const QUrl &url, Core::HelpManager::HelpViewerLocation location); + static void showLinksInCurrentViewer(const QMultiMap &links, + const QString &key); static HelpViewer *createHelpViewer(); static HelpWidget *modeHelpWidget(); From 8175f96e5045d881bab299690ce780eed63d7528 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 10:43:46 +0200 Subject: [PATCH 0580/1447] CMakeTargetLocatorFilter: Use Acceptor for LocatorFilterEntry Change-Id: I5f82853bab8fdc38ae0793e9865c6d1da10f8ccd Reviewed-by: Qt CI Bot Reviewed-by: Cristian Adam Reviewed-by: --- .../cmakelocatorfilter.cpp | 63 +++++++++---------- .../cmakeprojectmanager/cmakelocatorfilter.h | 9 ++- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index dfee13d0911..57cb7946de6 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -57,8 +57,16 @@ void CMakeTargetLocatorFilter::prepareSearch(const QString &entry) const FilePath path = target.backtrace.isEmpty() ? cmakeProject->projectFilePath() : target.backtrace.last().path; const int line = target.backtrace.isEmpty() ? 0 : target.backtrace.last().line; - - LocatorFilterEntry filterEntry(this, target.title); + const FilePath projectPath = cmakeProject->projectFilePath(); + const QString displayName = target.title; + LocatorFilterEntry filterEntry; + filterEntry.displayName = displayName; + if (m_acceptor) { + filterEntry.acceptor = [projectPath, displayName, acceptor = m_acceptor] { + acceptor(projectPath, displayName); + return AcceptResult(); + }; + } filterEntry.linkForEditor = {path, line}; filterEntry.extraInfo = path.shortNativePath(); filterEntry.highlightInfo = {index, int(entry.length())}; @@ -96,40 +104,31 @@ BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() setDescription(Tr::tr("Builds a target of any open CMake project.")); setDefaultShortcutString("cm"); setPriority(High); -} + setBuildAcceptor([](const Utils::FilePath &projectPath, const QString &displayName) { + // Get the project containing the target selected + const auto cmakeProject = qobject_cast( + Utils::findOrDefault(ProjectManager::projects(), [projectPath](Project *p) { + return p->projectFilePath() == projectPath; + })); + if (!cmakeProject || !cmakeProject->activeTarget() + || !cmakeProject->activeTarget()->activeBuildConfiguration()) + return; -void BuildCMakeTargetLocatorFilter::accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - - const FilePath projectPath = selection.filePath; - - // Get the project containing the target selected - const auto cmakeProject = qobject_cast( - Utils::findOrDefault(ProjectManager::projects(), [projectPath](Project *p) { - return p->projectFilePath() == projectPath; - })); - if (!cmakeProject || !cmakeProject->activeTarget() - || !cmakeProject->activeTarget()->activeBuildConfiguration()) - return; - - // Find the make step - BuildStepList *buildStepList = + // Find the make step + BuildStepList *buildStepList = cmakeProject->activeTarget()->activeBuildConfiguration()->buildSteps(); - auto buildStep = buildStepList->firstOfType(); - if (!buildStep) - return; + auto buildStep = buildStepList->firstOfType(); + if (!buildStep) + return; - // Change the make step to build only the given target - QStringList oldTargets = buildStep->buildTargets(); - buildStep->setBuildTargets({selection.displayName}); + // Change the make step to build only the given target + QStringList oldTargets = buildStep->buildTargets(); + buildStep->setBuildTargets({displayName}); - // Build - BuildManager::buildProjectWithDependencies(cmakeProject); - buildStep->setBuildTargets(oldTargets); + // Build + BuildManager::buildProjectWithDependencies(cmakeProject); + buildStep->setBuildTargets(oldTargets); + }); } // -------------------------------------------------------------------- diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h index b8a748be85a..4e73b59e4ad 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h @@ -15,22 +15,21 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) final; +protected: + using BuildAcceptor = std::function; + void setBuildAcceptor(const BuildAcceptor &acceptor) { m_acceptor = acceptor; } private: void projectListUpdated(); QList m_result; + BuildAcceptor m_acceptor; }; class BuildCMakeTargetLocatorFilter : CMakeTargetLocatorFilter { public: BuildCMakeTargetLocatorFilter(); - - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const final; }; class OpenCMakeTargetLocatorFilter : CMakeTargetLocatorFilter From a353e9fde19ae0862ed95aeb71654da57f24fcac Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 19 Apr 2023 11:03:58 +0200 Subject: [PATCH 0581/1447] Markdown: Reuse Markdown highlighter from change log viewer Change-Id: Ief1b0c135a34bfd5e9b5220e9fbf93f281d8e95a Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- .../templates/wizards/files/markdown/file.md | 6 +- src/libs/utils/stringutils.cpp | 63 +++++++++++++++++- src/libs/utils/stringutils.h | 12 ++++ src/plugins/coreplugin/mainwindow.cpp | 64 +------------------ src/plugins/texteditor/markdowneditor.cpp | 4 +- 5 files changed, 80 insertions(+), 69 deletions(-) diff --git a/share/qtcreator/templates/wizards/files/markdown/file.md b/share/qtcreator/templates/wizards/files/markdown/file.md index 2062554585a..1c00de1fca7 100644 --- a/share/qtcreator/templates/wizards/files/markdown/file.md +++ b/share/qtcreator/templates/wizards/files/markdown/file.md @@ -11,8 +11,6 @@ Paragraph. * another bullet * child bullet ---- - 1. ordered 2. next ordered @@ -25,6 +23,10 @@ An empty line starts a new paragraph. Use two spaces at the end to force a line break. +A horizontal ruler follows: + +--- + Add links inline like [this link to the Qt homepage](https://www.qt.io), or with a reference like [this other link to the Qt homepage][1]. diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index 37f9336d376..c296881cb8b 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -3,10 +3,9 @@ #include "stringutils.h" -#include "algorithm.h" -#include "hostosinfo.h" -#include "qtcassert.h" #include "filepath.h" +#include "qtcassert.h" +#include "theme/theme.h" #include "utilstr.h" #ifdef QT_WIDGETS_LIB @@ -15,11 +14,13 @@ #endif #include +#include #include #include #include #include #include +#include #include #include @@ -568,4 +569,60 @@ QTCREATOR_UTILS_EXPORT int endOfNextWord(const QString &string, int position) return std::distance(string.begin(), it); } +MarkdownHighlighter::MarkdownHighlighter(QTextDocument *parent) + : QSyntaxHighlighter(parent) + , h2Brush(Qt::NoBrush) +{ + parent->setIndentWidth(30); // default value is 40 +} + +void MarkdownHighlighter::highlightBlock(const QString &text) +{ + if (text.isEmpty()) + return; + + QTextBlockFormat fmt = currentBlock().blockFormat(); + QTextCursor cur(currentBlock()); + if (fmt.hasProperty(QTextFormat::HeadingLevel)) { + fmt.setTopMargin(10); + fmt.setBottomMargin(10); + + // Draw an underline for Heading 2, by creating a texture brush + // with the last pixel visible + if (fmt.property(QTextFormat::HeadingLevel) == 2) { + QTextCharFormat charFmt = currentBlock().charFormat(); + charFmt.setBaselineOffset(15); + setFormat(0, text.length(), charFmt); + + if (h2Brush.style() == Qt::NoBrush) { + const int height = QFontMetrics(charFmt.font()).height(); + QImage image(1, height, QImage::Format_ARGB32); + + image.fill(QColor(0, 0, 0, 0).rgba()); + image.setPixel(0, + height - 1, + Utils::creatorTheme()->color(Theme::TextColorDisabled).rgba()); + + h2Brush = QBrush(image); + } + fmt.setBackground(h2Brush); + } + cur.setBlockFormat(fmt); + } else if (fmt.hasProperty(QTextFormat::BlockCodeLanguage) && fmt.indent() == 0) { + // set identation for code blocks + fmt.setIndent(1); + cur.setBlockFormat(fmt); + } + + // Show the bulet points as filled circles + QTextList *list = cur.currentList(); + if (list) { + QTextListFormat listFmt = list->format(); + if (listFmt.indent() == 1 && listFmt.style() == QTextListFormat::ListCircle) { + listFmt.setStyle(QTextListFormat::ListDisc); + list->setFormat(listFmt); + } + } +} + } // namespace Utils diff --git a/src/libs/utils/stringutils.h b/src/libs/utils/stringutils.h index d1a94330b7b..3bab6110cf3 100644 --- a/src/libs/utils/stringutils.h +++ b/src/libs/utils/stringutils.h @@ -5,8 +5,10 @@ #include "utils_global.h" +#include #include #include +#include #include @@ -121,4 +123,14 @@ QTCREATOR_UTILS_EXPORT QPair splitAtFirst(const QStrin QTCREATOR_UTILS_EXPORT int endOfNextWord(const QString &string, int position = 0); +class QTCREATOR_UTILS_EXPORT MarkdownHighlighter : public QSyntaxHighlighter +{ +public: + MarkdownHighlighter(QTextDocument *parent); + void highlightBlock(const QString &text); + +private: + QBrush h2Brush; +}; + } // namespace Utils diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 168fff92208..2d7ec70c8eb 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -1384,67 +1384,6 @@ public: } }; -class MarkdownHighlighter : public QSyntaxHighlighter -{ - QBrush h2Brush; -public: - MarkdownHighlighter(QTextDocument *parent) - : QSyntaxHighlighter(parent) - , h2Brush(Qt::NoBrush) - { - parent->setIndentWidth(30); // default value is 40 - } - - void highlightBlock(const QString &text) - { - if (text.isEmpty()) - return; - - QTextBlockFormat fmt = currentBlock().blockFormat(); - QTextCursor cur(currentBlock()); - if (fmt.hasProperty(QTextFormat::HeadingLevel)) { - fmt.setTopMargin(10); - fmt.setBottomMargin(10); - - // Draw an underline for Heading 2, by creating a texture brush - // with the last pixel visible - if (fmt.property(QTextFormat::HeadingLevel) == 2) { - QTextCharFormat charFmt = currentBlock().charFormat(); - charFmt.setBaselineOffset(15); - setFormat(0, text.length(), charFmt); - - if (h2Brush.style() == Qt::NoBrush) { - const int height = QFontMetrics(charFmt.font()).height(); - QImage image(1, height, QImage::Format_ARGB32); - - image.fill(QColor(0, 0, 0, 0).rgba()); - image.setPixel(0, - height - 1, - Utils::creatorTheme()->color(Theme::TextColorDisabled).rgba()); - - h2Brush = QBrush(image); - } - fmt.setBackground(h2Brush); - } - cur.setBlockFormat(fmt); - } else if (fmt.hasProperty(QTextFormat::BlockCodeLanguage) && fmt.indent() == 0) { - // set identation for code blocks - fmt.setIndent(1); - cur.setBlockFormat(fmt); - } - - // Show the bulet points as filled circles - QTextList *list = cur.currentList(); - if (list) { - QTextListFormat listFmt = list->format(); - if (listFmt.indent() == 1 && listFmt.style() == QTextListFormat::ListCircle) { - listFmt.setStyle(QTextListFormat::ListDisc); - list->setFormat(listFmt); - } - } - } -}; - void MainWindow::changeLog() { static QPointer dialog; @@ -1484,8 +1423,7 @@ void MainWindow::changeLog() aggregate->add(textEdit); aggregate->add(new Core::BaseTextFind(textEdit)); - auto highlighter = new MarkdownHighlighter(textEdit->document()); - (void)highlighter; + new MarkdownHighlighter(textEdit->document()); auto textEditWidget = new QFrame; textEditWidget->setFrameStyle(QFrame::NoFrame); diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 4041a0069e9..c04dcf0942d 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -7,10 +7,11 @@ #include "texteditor.h" #include "texteditortr.h" -#include #include #include +#include #include +#include #include #include @@ -34,6 +35,7 @@ public: auto browser = new QTextBrowser(&m_widget); browser->setOpenExternalLinks(true); browser->setFrameShape(QFrame::NoFrame); + new Utils::MarkdownHighlighter(browser->document()); // Right side (hidable) auto editor = new TextEditorWidget(&m_widget); From 3351459ead3b114dd374e416716083f8ddb904ec Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 18 Apr 2023 16:54:53 +0200 Subject: [PATCH 0582/1447] ProjectExplorer: Avoid KitConfigWidget creation in some code paths They are now only created when the kit is selected for editing or for getting a tooltip. Change-Id: I50b4194610f662645eada9f69e4b6f2d20aa6c00 Reviewed-by: Christian Kandeler --- .../kitmanagerconfigwidget.cpp | 31 +---- .../projectexplorer/kitmanagerconfigwidget.h | 11 +- src/plugins/projectexplorer/kitmodel.cpp | 122 ++++++++++++------ 3 files changed, 93 insertions(+), 71 deletions(-) diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index 908238d3a7f..1f7ea6f88ba 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -36,12 +36,14 @@ using namespace Utils; namespace ProjectExplorer { namespace Internal { -KitManagerConfigWidget::KitManagerConfigWidget(Kit *k) : +KitManagerConfigWidget::KitManagerConfigWidget(Kit *k, bool &isDefaultKit, bool &hasUniqueName) : m_iconButton(new QToolButton), m_nameEdit(new QLineEdit), m_fileSystemFriendlyNameLineEdit(new QLineEdit), m_kit(k), - m_modifiedKit(std::make_unique(Utils::Id(WORKING_COPY_KIT_ID))) + m_modifiedKit(std::make_unique(Utils::Id(WORKING_COPY_KIT_ID))), + m_isDefaultKit(isDefaultKit), + m_hasUniqueName(hasUniqueName) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); @@ -213,11 +215,6 @@ void KitManagerConfigWidget::updateVisibility() } } -void KitManagerConfigWidget::setHasUniqueName(bool unique) -{ - m_hasUniqueName = unique; -} - void KitManagerConfigWidget::makeStickySubWidgetsReadOnly() { for (KitAspectWidget *w : std::as_const(m_widgets)) { @@ -231,31 +228,11 @@ Kit *KitManagerConfigWidget::workingCopy() const return m_modifiedKit.get(); } -bool KitManagerConfigWidget::configures(Kit *k) const -{ - return m_kit == k; -} - -void KitManagerConfigWidget::setIsDefaultKit(bool d) -{ - if (m_isDefaultKit == d) - return; - m_isDefaultKit = d; - emit dirty(); -} - bool KitManagerConfigWidget::isDefaultKit() const { return m_isDefaultKit; } -void KitManagerConfigWidget::removeKit() -{ - if (!m_kit) - return; - KitManager::deregisterKit(m_kit); -} - void KitManagerConfigWidget::setIcon() { const Utils::Id deviceType = DeviceTypeKitAspect::deviceTypeId(m_modifiedKit.get()); diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.h b/src/plugins/projectexplorer/kitmanagerconfigwidget.h index 142eb8fa364..bd4415ed480 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.h +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.h @@ -25,7 +25,7 @@ class KitManagerConfigWidget : public QWidget Q_OBJECT public: - explicit KitManagerConfigWidget(Kit *k); + explicit KitManagerConfigWidget(Kit *k, bool &isDefaultKit, bool &hasUniqueName); ~KitManagerConfigWidget() override; QString displayName() const; @@ -39,15 +39,10 @@ public: void makeStickySubWidgetsReadOnly(); Kit *workingCopy() const; - bool configures(Kit *k) const; bool isRegistering() const { return m_isRegistering; } - void setIsDefaultKit(bool d); bool isDefaultKit() const; - void removeKit(); void updateVisibility(); - void setHasUniqueName(bool unique); - signals: void dirty(); void isAutoDetectedChanged(); @@ -74,9 +69,9 @@ private: QList m_widgets; Kit *m_kit; std::unique_ptr m_modifiedKit; - bool m_isDefaultKit = false; + bool &m_isDefaultKit; bool m_fixingKit = false; - bool m_hasUniqueName = true; + bool &m_hasUniqueName; bool m_isRegistering = false; mutable QString m_cachedDisplayName; }; diff --git a/src/plugins/projectexplorer/kitmodel.cpp b/src/plugins/projectexplorer/kitmodel.cpp index f1d0c3645d3..12f23fb2819 100644 --- a/src/plugins/projectexplorer/kitmodel.cpp +++ b/src/plugins/projectexplorer/kitmodel.cpp @@ -30,32 +30,75 @@ public: ~KitNode() override { delete m_widget; } + Kit *kit() const { return m_kit; } + QVariant data(int, int role) const override { - if (m_widget) { - if (role == Qt::FontRole) { - QFont f = QApplication::font(); - if (m_widget->isDirty()) - f.setBold(!f.bold()); - if (m_widget->isDefaultKit()) - f.setItalic(f.style() != QFont::StyleItalic); - return f; - } - if (role == Qt::DisplayRole) { - QString baseName = m_widget->displayName(); - if (m_widget->isDefaultKit()) - //: Mark up a kit as the default one. - baseName = Tr::tr("%1 (default)").arg(baseName); - return baseName; - } - if (role == Qt::DecorationRole) { - return m_widget->displayIcon(); - } - if (role == Qt::ToolTipRole) { - return m_widget->validityMessage(); - } + if (role == Qt::FontRole) { + QFont f = QApplication::font(); + if (isDirty()) + f.setBold(!f.bold()); + if (isDefaultKit()) + f.setItalic(f.style() != QFont::StyleItalic); + return f; } - return QVariant(); + if (role == Qt::DisplayRole) { + QString baseName = displayName(); + if (isDefaultKit()) + //: Mark up a kit as the default one. + baseName = Tr::tr("%1 (default)").arg(baseName); + return baseName; + } + + if (role == Qt::DecorationRole) + return displayIcon(); + + if (role == Qt::ToolTipRole) + return widget()->validityMessage(); + + return {}; + } + + bool isDirty() const + { + if (m_widget) + return m_widget->isDirty(); + return false; + } + + QIcon displayIcon() const + { + if (m_widget) + return m_widget->displayIcon(); + return m_kit->displayIcon(); + } + + QString displayName() const + { + if (m_widget) + return m_widget->displayName(); + return m_kit->displayName(); + } + + bool isDefaultKit() const + { + return m_isDefaultKit; + } + + bool isRegistering() const + { + if (m_widget) + return m_widget->isRegistering(); + return false; + } + + void setIsDefaultKit(bool on) + { + if (m_isDefaultKit == on) + return; + m_isDefaultKit = on; + if (m_widget) + emit m_widget->dirty(); } KitManagerConfigWidget *widget() const @@ -64,13 +107,18 @@ public: return m_widget; } + void setHasUniqueName(bool on) + { + m_hasUniqueName = on; + } + private: void ensureWidget() { if (m_widget) return; - m_widget = new KitManagerConfigWidget(m_kit); + m_widget = new KitManagerConfigWidget(m_kit, m_isDefaultKit, m_hasUniqueName); QObject::connect(m_widget, &KitManagerConfigWidget::dirty, m_model, [this] { update(); }); @@ -90,6 +138,8 @@ private: KitModel *m_model = nullptr; KitManagerConfigWidget *m_widget = nullptr; QBoxLayout *m_parentLayout = nullptr; + bool m_isDefaultKit = false; + bool m_hasUniqueName = true; }; // -------------------------------------------------------------------------- @@ -164,7 +214,7 @@ void KitModel::validateKitNames() { QHash nameHash; forItemsAtLevel<2>([&nameHash](KitNode *n) { - const QString displayName = n->widget()->displayName(); + const QString displayName = n->displayName(); if (nameHash.contains(displayName)) ++nameHash[displayName]; else @@ -172,8 +222,8 @@ void KitModel::validateKitNames() }); forItemsAtLevel<2>([&nameHash](KitNode *n) { - const QString displayName = n->widget()->displayName(); - n->widget()->setHasUniqueName(nameHash.value(displayName) == 1); + const QString displayName = n->displayName(); + n->setHasUniqueName(nameHash.value(displayName) == 1); }); } @@ -181,7 +231,7 @@ void KitModel::apply() { // Add/update dirty nodes before removing kits. This ensures the right kit ends up as default. forItemsAtLevel<2>([](KitNode *n) { - if (n->widget()->isDirty()) { + if (n->isDirty()) { n->widget()->apply(); n->update(); } @@ -190,7 +240,7 @@ void KitModel::apply() // Remove unused kits: const QList removeList = m_toRemoveList; for (KitNode *n : removeList) - n->widget()->removeKit(); + KitManager::deregisterKit(n->kit()); emit layoutChanged(); // Force update. } @@ -212,7 +262,7 @@ void KitModel::markForRemoval(Kit *k) setDefaultNode(findItemAtLevel<2>([node](KitNode *kn) { return kn != node; })); takeItem(node); - if (node->widget()->configures(nullptr)) + if (node->kit() == nullptr) delete node; else m_toRemoveList.append(node); @@ -271,12 +321,12 @@ KitNode *KitModel::createNode(Kit *k) void KitModel::setDefaultNode(KitNode *node) { if (m_defaultNode) { - m_defaultNode->widget()->setIsDefaultKit(false); + m_defaultNode->setIsDefaultKit(false); m_defaultNode->update(); } m_defaultNode = node; if (m_defaultNode) { - m_defaultNode->widget()->setIsDefaultKit(true); + m_defaultNode->setIsDefaultKit(true); m_defaultNode->update(); } } @@ -285,7 +335,7 @@ void KitModel::addKit(Kit *k) { for (TreeItem *n : *m_manualRoot) { // Was added by us - if (static_cast(n)->widget()->isRegistering()) + if (static_cast(n)->isRegistering()) return; } @@ -306,7 +356,7 @@ void KitModel::removeKit(Kit *k) { QList nodes = m_toRemoveList; for (KitNode *n : std::as_const(nodes)) { - if (n->widget()->configures(k)) { + if (n->kit() == k) { m_toRemoveList.removeOne(n); if (m_defaultNode == n) m_defaultNode = nullptr; @@ -317,7 +367,7 @@ void KitModel::removeKit(Kit *k) } KitNode *node = findItemAtLevel<2>([k](KitNode *n) { - return n->widget()->configures(k); + return n->kit() == k; }); if (node == m_defaultNode) @@ -333,7 +383,7 @@ void KitModel::changeDefaultKit() { Kit *defaultKit = KitManager::defaultKit(); KitNode *node = findItemAtLevel<2>([defaultKit](KitNode *n) { - return n->widget()->configures(defaultKit); + return n->kit() == defaultKit; }); setDefaultNode(node); } From 1cc7342ef16cf904915355de9ee88c0250bca852 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 16:34:33 +0200 Subject: [PATCH 0583/1447] JsonFieldPage: Use locator matcher for line edit completion This may be tested in File | New File... | C/C++ | C++ Class, Base class line edit should provide class completion. With locator matcher the task is being executed ~20% faster. This patch also solves the potential issue with interference between parallel runs of classes filter in locator and in LineEditField. Change-Id: Ice3e719d9cbe72ec4cd11bd4362a94e9c3ce8874 Reviewed-by: Christian Kandeler Reviewed-by: Reviewed-by: Qt CI Bot --- .../jsonwizard/jsonfieldpage.cpp | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index 45f8e682abc..3fc9d9aea6c 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -16,10 +16,7 @@ #include #include -#include #include -#include -#include #include #include @@ -29,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -603,25 +599,17 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) using namespace Utils; if (m_completion == Completion::None) return; - ILocatorFilter * const classesFilter = findOrDefault( - ILocatorFilter::allLocatorFilters(), - equal(&ILocatorFilter::id, Id("Classes"))); - if (!classesFilter) - return; - classesFilter->prepareSearch({}); - const auto watcher = new QFutureWatcher; - const auto handleResults = [this, lineEdit, watcher](int firstIndex, int endIndex) { + const auto handleResults = [this, lineEdit](const QList &entries) { QSet namespaces; QStringList classes; Project * const project = ProjectTree::currentProject(); - for (int i = firstIndex; i < endIndex; ++i) { + for (const LocatorFilterEntry &entry : entries) { static const auto isReservedName = [](const QString &name) { static const QRegularExpression rx1("^_[A-Z].*"); static const QRegularExpression rx2(".*::_[A-Z].*"); return name.contains("__") || rx1.match(name).hasMatch() || rx2.match(name).hasMatch(); }; - const LocatorFilterEntry &entry = watcher->resultAt(i); const bool hasNamespace = !entry.extraInfo.isEmpty() && !entry.extraInfo.startsWith('<') && !entry.extraInfo.contains("::<") && !isReservedName(entry.extraInfo) @@ -658,15 +646,11 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) completionList.sort(); lineEdit->setSpecialCompleter(new QCompleter(completionList, lineEdit)); }; - QObject::connect(watcher, &QFutureWatcher::resultsReadyAt, lineEdit, - handleResults); - QObject::connect(watcher, &QFutureWatcher::finished, - watcher, &QFutureWatcher::deleteLater); - watcher->setFuture(runAsync([classesFilter](QFutureInterface &f) { - const QList matches = classesFilter->matchesFor(f, {}); - if (!matches.isEmpty()) - f.reportResults(QVector(matches.cbegin(), matches.cend())); - })); + LocatorMatcher *matcher = new LocatorMatcher; + matcher->setTasks(LocatorMatcher::classMatchers()); + QObject::connect(matcher, &LocatorMatcher::serialOutputDataReady, lineEdit, handleResults); + QObject::connect(matcher, &LocatorMatcher::done, matcher, &QObject::deleteLater); + matcher->start(); } void LineEditField::setText(const QString &text) From 8f449640593c21717572c4fcd382e169492fbfe2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 7 Apr 2023 08:31:21 +0200 Subject: [PATCH 0584/1447] CppCurrentDocumentFilter: Get rid of the arg from c'tor It's always CppModelManager::instance(). Change-Id: Ia049ad3bd452f8773d679549c33981460c2705d4 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppcurrentdocumentfilter.cpp | 6 +++--- src/plugins/cppeditor/cppcurrentdocumentfilter.h | 2 +- src/plugins/cppeditor/cppmodelmanager.cpp | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index e148525b3b3..6777ca1c11d 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -19,8 +19,8 @@ using namespace CPlusPlus; namespace CppEditor::Internal { -CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppModelManager *manager) - : m_modelManager(manager) +CppCurrentDocumentFilter::CppCurrentDocumentFilter() + : m_modelManager(CppModelManager::instance()) { setId(Constants::CURRENT_DOCUMENT_FILTER_ID); setDisplayName(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME)); @@ -34,7 +34,7 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppModelManager *manager) SymbolSearcher::Functions | SymbolSearcher::Classes); - connect(manager, &CppModelManager::documentUpdated, + connect(m_modelManager, &CppModelManager::documentUpdated, this, &CppCurrentDocumentFilter::onDocumentUpdated); connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, &CppCurrentDocumentFilter::onCurrentEditorChanged); diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.h b/src/plugins/cppeditor/cppcurrentdocumentfilter.h index 72a8359b097..cd53f37b810 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.h +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.h @@ -20,7 +20,7 @@ class CppCurrentDocumentFilter : public Core::ILocatorFilter Q_OBJECT public: - explicit CppCurrentDocumentFilter(CppModelManager *manager); + explicit CppCurrentDocumentFilter(); ~CppCurrentDocumentFilter() override = default; void makeAuxiliary(); diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 9cc3b1c214b..1e22d03d901 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -902,8 +902,7 @@ void CppModelManager::initCppTools() setIncludesFilter(std::make_unique()); setFunctionsFilter(std::make_unique()); setSymbolsFindFilter(std::make_unique(this)); - setCurrentDocumentFilter( - std::make_unique(this)); + setCurrentDocumentFilter(std::make_unique()); // Setup matchers LocatorMatcher::addLocatorMatcherCreator([] { return QList{CppEditor::cppLocatorMatcher()}; }); LocatorMatcher::addClassMatcherCreator([] { return QList{CppEditor::cppClassMatcher()}; }); @@ -2021,7 +2020,7 @@ void CppModelManager::switchDeclDef(const CursorInEditor &data, ILocatorFilter *CppModelManager::createAuxiliaryCurrentDocumentFilter() { - const auto filter = new Internal::CppCurrentDocumentFilter(instance()); + const auto filter = new Internal::CppCurrentDocumentFilter; filter->makeAuxiliary(); return filter; } From 6e8988c92626e870f90ac040fa307118ff77b06d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 15:13:59 +0200 Subject: [PATCH 0585/1447] CppModelManager: Use locator matcher for unused functions With this patch, when both cpp and lsp function filters are available, they now run in parallel. The execution time for getting the filter results (~110 K hits) for the Creator codebase went goes from ~1100 ms into ~650 ms. This patch also solves the potential issue with interference between parallel runs of functions filter in locator and in find unused functions. Change-Id: I8f7f0b85d325848c04760ab76a7b9f02bcb5991e Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppmodelmanager.cpp | 29 +++++++++-------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 1e22d03d901..78e3453460c 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -65,7 +65,6 @@ #include #include #include -#include #include #include @@ -535,8 +534,8 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) const auto actionsSwitcher = std::make_shared(); // Step 1: Employ locator to find all functions - ILocatorFilter *const functionsFilter = CppModelManager::instance()->functionsFilter(); - QTC_ASSERT(functionsFilter, return); + LocatorMatcher *matcher = new LocatorMatcher; + matcher->setTasks(LocatorMatcher::functionMatchers()); const QPointer search = SearchResultWindow::instance()->startNewSearch(Tr::tr("Find Unused Functions"), {}, @@ -544,25 +543,22 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) SearchResultWindow::SearchOnly, SearchResultWindow::PreserveCaseDisabled, "CppEditor"); + matcher->setParent(search); connect(search, &SearchResult::activated, [](const SearchResultItem &item) { EditorManager::openEditorAtSearchResult(item); }); SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); - const auto locatorWatcher = new QFutureWatcher(search); - functionsFilter->prepareSearch({}); - connect(search, &SearchResult::canceled, locatorWatcher, [locatorWatcher] { - locatorWatcher->cancel(); - }); - connect(locatorWatcher, &QFutureWatcher::finished, search, - [locatorWatcher, search, folder, actionsSwitcher] { - locatorWatcher->deleteLater(); - if (locatorWatcher->isCanceled()) { + connect(search, &SearchResult::canceled, matcher, [matcher] { delete matcher; }); + connect(matcher, &LocatorMatcher::done, search, + [matcher, search, folder, actionsSwitcher](bool success) { + matcher->deleteLater(); + if (!success) { search->finishSearch(true); return; } Links links; - for (int i = 0; i < locatorWatcher->future().resultCount(); ++i) { - const LocatorFilterEntry &entry = locatorWatcher->resultAt(i); + const auto entries = matcher->outputData(); + for (const LocatorFilterEntry &entry : entries) { static const QStringList prefixBlacklist{"main(", "~", "qHash(", "begin()", "end()", "cbegin()", "cend()", "constBegin()", "constEnd()"}; if (Utils::anyOf(prefixBlacklist, [&entry](const QString &prefix) { @@ -614,10 +610,7 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) for (int i = 0; i < inFlightCount; ++i) checkNextFunctionForUnused(search, findRefsFuture, actionsSwitcher); }); - locatorWatcher->setFuture( - Utils::runAsync([functionsFilter](QFutureInterface &future) { - future.reportResults(functionsFilter->matchesFor(future, {})); - })); + matcher->start(); } void CppModelManager::checkForUnusedSymbol(SearchResult *search, From dd5eed0b35cadfa746e448191962d92b67f04e65 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 18 Apr 2023 17:49:52 +0200 Subject: [PATCH 0586/1447] Utils: Fix painting artifacts of FancyLineEdit on StyledBar Don't enforce a premature polishing by the style. Fixes: QTCREATORBUG-27510 Change-Id: I1598a75741c5990567a33ad8376144432894597a Reviewed-by: Cristian Adam --- src/libs/utils/fancylineedit.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp index a0d1fd9b8aa..03e33c67b67 100644 --- a/src/libs/utils/fancylineedit.cpp +++ b/src/libs/utils/fancylineedit.cpp @@ -172,7 +172,6 @@ FancyLineEdit::FancyLineEdit(QWidget *parent) : CompletingLineEdit(parent), d(new FancyLineEditPrivate(this)) { - ensurePolished(); updateMargins(); connect(d->m_iconbutton[Left], &QAbstractButton::clicked, this, [this] { From 129fc0583fefe9966bc5e454156e3371493cfd1a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 6 Apr 2023 17:30:51 +0200 Subject: [PATCH 0587/1447] ILocatorFilter: Move allLocatorFilters() into private section This shouldn't be used outside of locator scope. For other usages that could reuse some filter's implementation use LocatorMatcher with shared list of LocatorMatcherTask. Change-Id: I63a62c79b38985e24835fecd38d016dfb164a16e Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/coreplugin/locator/ilocatorfilter.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index bcc413905f7..bf94650443d 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -201,8 +201,6 @@ public: ILocatorFilter(QObject *parent = nullptr); ~ILocatorFilter() override; - static const QList allLocatorFilters(); - Utils::Id id() const; Utils::Id actionId() const; @@ -281,6 +279,7 @@ protected: private: friend class Internal::Locator; + static const QList allLocatorFilters(); Utils::Id m_id; QString m_shortcut; From b6d1cbc5f6d65cdcc4a9eb8bafc78f0926bd1a19 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 19 Apr 2023 21:32:58 +0200 Subject: [PATCH 0588/1447] StringUtils: Fix missing include Amends a353e9fde19ae0862ed95aeb71654da57f24fcac Change-Id: Iee878da1f907ec0131dd3fd16fe4f84752355b38 Reviewed-by: Jarek Kobus --- src/libs/utils/stringutils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index c296881cb8b..f8602169613 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include From e73aaa044e7292ab27afd1bbafcf7337c3f35751 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 18 Apr 2023 16:13:20 +0200 Subject: [PATCH 0589/1447] Doc: Remove details about locator filters and refer to tooltips - Reorganize the topic contents, so that all examples are in one place - Add subtitles - Update screenshots Task-number: QTCREATORBUG-28996 Change-Id: Id139b19c5ff18c08b7a27494d6ac5051b298c014 Reviewed-by: Eike Ziller --- .../images/qtcreator-add-online-doc.png | Bin 11916 -> 0 bytes .../images/qtcreator-add-online-doc.webp | Bin 0 -> 8250 bytes .../images/qtcreator-locator-customize.png | Bin 22905 -> 0 bytes .../images/qtcreator-locator-customize.webp | Bin 0 -> 16400 bytes .../images/qtcreator-locator-example.png | Bin 26022 -> 0 bytes .../images/qtcreator-locator-example.webp | Bin 0 -> 10848 bytes .../images/qtcreator-locator-open.png | Bin 11910 -> 0 bytes .../images/qtcreator-locator-open.webp | Bin 0 -> 5444 bytes doc/qtcreator/images/qtcreator-locator.png | Bin 13532 -> 0 bytes doc/qtcreator/images/qtcreator-locator.webp | Bin 0 -> 8168 bytes .../src/editors/creator-locator.qdoc | 219 +++++++----------- 11 files changed, 82 insertions(+), 137 deletions(-) delete mode 100644 doc/qtcreator/images/qtcreator-add-online-doc.png create mode 100644 doc/qtcreator/images/qtcreator-add-online-doc.webp delete mode 100644 doc/qtcreator/images/qtcreator-locator-customize.png create mode 100644 doc/qtcreator/images/qtcreator-locator-customize.webp delete mode 100644 doc/qtcreator/images/qtcreator-locator-example.png create mode 100644 doc/qtcreator/images/qtcreator-locator-example.webp delete mode 100644 doc/qtcreator/images/qtcreator-locator-open.png create mode 100644 doc/qtcreator/images/qtcreator-locator-open.webp delete mode 100644 doc/qtcreator/images/qtcreator-locator.png create mode 100644 doc/qtcreator/images/qtcreator-locator.webp diff --git a/doc/qtcreator/images/qtcreator-add-online-doc.png b/doc/qtcreator/images/qtcreator-add-online-doc.png deleted file mode 100644 index 761b3c74f8749a49a740699382836a19e84508e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11916 zcmeAS@N?(olHy`uVBq!ia0y~yV2WX2VEDJe;AlY1tGoDCAT+{o$2 zwsf1B=Ai}MJS`oo6csr=bxxkqxXINh@W>(0?dHmxcW0h`r>41W*|xI!Q}gPqYwzvK zzdwE7q&)lizoy*%Uh@5Av0wbx;`1-xecqe(_ExF)i>s@{*RS>6F1zFY<;L4zo}8^c z{`kv>=Iv{8mh&sz_& zeHTbGt=)U@&MGsl*sV?rR|M)j3u+Ml+T1GNZE;ZSU8P;%l>WDyZ`;!p&s=6K3^ zwEk!Pe%o*7+^g%Y<~&OO_p|brh+@kHp;xO`ud908YyPHWqDEM1)1$0-&D(!J|Nr|w zv~vc}(Qx@4TG#rx_y2pmUjNO9|KGz|xl2!<_CC4Gjn!4y`k3n}$DOI`LjJ8*o{~vj<$k=e{@)w$^yVvje{pHy8y#4RzZk)g8|26-A-=qJ({5!ud zrZOPl!{+Y!^Zy>c|Np`F>Hix`cZ}OsKf*U+tPRP4V$NK4kg+uJ)*TaCOc( z@5g)Aul?qgD#Uj;qj>9zI1a@tF?wk#NxT6ypXUBAIQx0_zMuZT^IegEh6^8S6F)3^Ws^5C6${}!39d#3vgmprYiJufNOcdL8Jlw&!2b~Y$E zWjrl3v=+>6e)Ltp?B9>_{5OBDJ=m(BBR9+X-{bH1D<0hSKl4A)QNZx?_H9~J_;cM; zwVRV14DD8YJ{HFuux8=vi2JrjuT1k_FCO5+p_{K{Wgpi5=Ey_ib2|{73hp)#@H=w(BprAG$`$UiOyPJZn+2D(2tgOPS5Rr`m3| z`v;#2i>)$V*+1>tt(cR#@q6Q5UUlSHsH&Fa8*}E@r+r+m52fQ@?RwW5&7<^B++5Ju z$xv$PX1V(wGIpU63HvI<)vXeP|GGU3eb#JtO5+hT|BkZh{Leewecnh}wrgBIJ#MU$1)Nq~%{p}Yx6kKkXXf0wmwaaFmOYdE1)RQeYb@(L zt|92ep>fG}P3|)jB62jNYm0yrhXxafatL%P)OF%e49S3s5>q4~DRpglwBMOS@rsJ2 z{^sm!YhJ#1v18ZWtyx!BnKeH0HP3%5v#b2}yx)e$B(6U^x3Kz1>lIE{N0*8Bu3j~@ zu-LJ^c5C(bcVAy$=l-^xS;U(C{msH?{bLf3cj@jD^V8t+<51$`<;}glEjRo3s@=Pz z7X*G0pUr#p;!3a7tdO53)`46>%0D@smUc#_o_1TXqx8kUbk`fXe z5*Ba1yEXm%yf7!jl!fhw5;j%_yph>e|9kCTiR7NwW$8vDth!d*3zjw}opF-x+GH=8 zvpRh$-_cy_>e~8WJLC8MDcCWmTfXk2`FUHhTAP1Uy{GRl(wNUIyX(VZZ}E4Am*uN} zdgZz2Y{}`3zVhy<|83s7r{VKnTRpOUuK#=YX}8V(Gd+G@?LQ|U|48j<#mTu$u7+j1 zmNE!kjaf7=X~Vsiq&?4HxSS2RvupG5?-f78jrm(oUs8Uqr$5I!PyhP6$CK^%*i@!} z`M6MA{B-}-*`cQQD-$2Ki@Oz_+GA)fy;HI-=b5;EpY(AnakD0ijI-)~TM`SJo*Z)4 zUp2Es|L`Myz4KF~e|ja{(Ti&fsCki;`mfXaa&VZQi1Nv)Y9f2jPrbz+!mLsD?!`x2 zyRY}o%q)nkdcysgJKiEq|N5I|e?1@DTf*|$b)O#eS#3U5v_{^>^3u%ce_wxJoVkbV z+lw>S`aSAvO6T2N^ISWoVEUeg>sgMyeVn4v_1rK2WFY(b^Wj>bpYum)pNlb>{C0|( zSBNpY#;X;^)m^WmzS|yUm~XluaL!R(=kNJ9FFvmRbMt%JF}b-ve^z%NI&Y^H=Ik)2p}HSbhGh?tbLZ4epEk zk{*9Q#M?GMrs7-ReuInd?>mfy0}uUJys3JI#Jf*_)sHVe!csv_<@+yC#` zez4<=uGYM1vo$JjNCom`ZM*j_%DYXjI`QG>UP7*8Q6|zcWx} ze_5cKS8(-O5m}RrGY02Rrf)r)?ooq$za&lu{ho6gnM)cILl|D1Kg_B9JD z4u4a8xOHo(=+jL_{(*Y84lh5pA?w-0;6lCpm#;qB{xg5Cx9{(t9ozqO&fNZ7jlZH( zIsLiVIXPalfNA}H`@X$iAjx<<;*+&^jUX4R`~fzhUCF6g%$JPt zesk-c_IGwXKiJ)U-sX||zoL)T{yi>|$Lc;TI&O zd77uO|3G2)Umd$eH{xn~WOLNE^#?WGnc_6d^-}Po)U_+J7<;sqTiV1YRqr=ARe62C zoP_xGM^3v$0(vqm%+@j$RGo?Ly7XqsRMw-@_V3X@_jK7?+kMCP|2sXifA(qR`Lknx z+?l8l7-?tp^X|=)wGWTk%J1Lt_x-X}7 zq_xh)-#l|OAnWrfS@HXyuC3}_W3o6tN_D#h`)ZHEw`Wq1R-L~6w9q=Etnf%e{LX}H zB9ED@S-X}7Wd{36***VwF8WhNd0vEX=cG4NYE)L;v6>)ZS-@UIcE56pYBcJ4e*vmZCU z94g;(_-se0JoopgAANTMpXihcwtwhXE&F-y=R^Zrt4Fgh9=lhxC3S;B(4n`FQw!G| zT`^(NyY9e6@e*4%-EJzj>)is$d?ey!TL=(x3O9t+dasD(Q!Km6mpT~*Ux z|Mt|G6K^uLcjx=`XP<6Y-(Q>gEPJ}x-u`egIr}&7zkcZXA9&;b_1kGh8MjY7 zo}RMpp4ojn`%R8@JZ6)Ri&|FfZdtwO@XzC-a&zNC%0w#l>fRz|3= zQoLb(Rnrp8l)GgmKMVH_BAv3l{eQP%sK&*yJ#%9{26k-gZWSrXe1&G!1f zWzX^*d#>08{5jCJR@(b}j?|9*X7_)e3BF&mZ2z^r(>D6od_7e>o$3GInbo(K$DOQu zq_6+?ZD*s>6_Lj^dpG`{$A9O}OqQej_U)U^tq^$DtntyUQuCx9!@LU)f*MIZhU@r_ z^0Ep99Fa(lk?q=D_Et!+tx+l9h{WSX&V^T3g}%PF_I4}-=ZEd`BL2RirxsV%WxAbC zdbRV#;{!Ku?%cdo^vhE5rTX);9tsv)$uJQw3cI4=OA*F;t(P z>Xn*0H?LDd?5%ouqW@=8@s($2TaTfIQ>{Z-1p0-OAA-X zot9t;`=J}{xouv?y@a1r`m`g@TCBE+-u!ymmuI?XR`g0T-;)viD(zyH@WM6^?6FOR`O}L z$y$H?mS$^Imrh-E!_Ru5VeQs~Z{L)g9~Lay`j`V03P)QP8Esh++i_WLBj+a@)2Fc$ z|7LGw@!W7d!*a*DE*H)X4~%T1rj>8#v7Ykl?8R9NS8P7ZdbGv8WzFnOrH&W>zF3y* za_dEd)$dK;WRLKecYa-*(w0;p_U3tBgA!ZU3XXs^D^9ENJgGe%wADRl&(^0!8yX$1 ztSQ^^DJ0VFf`$3&Z}X4nUG!LQ-m$9a3VV-J>#jC`(Xg9`mp@aUb*gYP@BC#BhKVdj zcP_manPqRW=+2Xip*@jHeJvN>`mnN!+xYZ{%rBprG?Esq$UHmC)U`s}dC$a~%lL0a zoPL-r^-5V<@x!U$;$KG%_ho2pXAqX#SQvM$S2}@h&X-27ud8yu$4^}zsAlqEiA`|u z#g!92E$H3UUH{_8j*oq29$VORCoRaZF-$R8Y1p)i|9O|Zz|A z?ATuaHh;r_kPeMYyLatkV`u-qZT*qczh7TpFaAdVLyy_b^@UQbpQ|q`Y#09*^}A}( z@7gxi(!6}1q&xotMCJ&%$Vf>E3Gd6vjV~=P=Qa_mp0!={^WpfH?$>^X-S?WE!l03~ zCuf0%g`t6g!iI}C-`(1r&L0r7FCZlD?rQGLQ!~_U7`i0PnOq&a&oQm|04h1=Fm@%q zDe-1hS;Z-0cua!XbwP*WF$-ytqs7a&Us-J|{y2QWv-9$MQYF1Zgh6G_Iq@zj#Ty^$w5>S>6|bzzfle;#i&+h^y$>#tL{{m}y&*8^gfEcZ9RzItP( zCByOpR%WwiK-Gx6PlsU%~RZ zz6S^2Z`-qptzDCec8FDLR zeTw`!<;V#pHFd6y>HiTGPCvWybG=o-56 z+hmVt@-@zPj2RhSc|@`s7WHeg-$}a4cC=9@`}eQ+>#Hs9YnXp6is%qN z-`UD6_tfw8Y8-*|Rxs?08rQ}qU^5kCy8-+p_-_m)Q^*H>?ymiV6t(H40x5-QX z+7x$XNxbn(J~yT-eaZnx95yOyX#KDf=wEOyym8T{k6WJ1J$0}k*;0yIWV+3~Mfik^>S00huVGbKJKZ=}&SJB9}eUi1(#Z4E#&(b(vICqM4U1z|W z#2+D+N!uP?7SUK{w_;Ih2H(R|i&sZ%y=As>d4yq`|Jws`nTMBey5S(m?0T>hR!uiK z7(TD)D%<0bZIovnx8NSXv6DntD{EJ67_bP4Mz-b*ShbLXLj`b zve=xX`SVuu#p_q1t+hq=-Z`T%WoDd0;tvsK*9AK!Eu3-wbg{RrzhS9Of#mJJV?M=+ zdyE$DSjfQCrEN07>Z4$z(lOoEN9$sDyR;-O;1HSq^y}Oo9S(wz#hj4a0pikK63IQQ z9RpV^Ui|n~QpVR;R~-bCdkUpQ1VJUif{q3yPyukI@4e=;N6(H2pLuUM;lWh9z(Y^J zEb-)K)|R@w=KAL;>&?#Zs4knwrZh2;N2D=H@R8=Vvb*QIBQk^A^=C#)Miky%$@zTu zpP9xyev52(`}X+ce_~(I(Wn%lqa|W|ESRP1rj)_=c}dET+0{hu3JaQiljcrdz#$UN zcvQ7_`3iUQ5*CG!XJ((*FP{|Q)uL?tZ;_el>OBI{2RZhxIrqzU#(JMspO0mJUiRwp zDoxQVYLCq-=2s`UX0Om+w7Zpw~# z=g*$v^yqavVZI?LOJQvrlXlcW|0(edH<`87$_pBm^6E9Xl(-V!+}T-NP*9Nn+iTAr z`G)-*!cE)F<}G4$O)V-|{aSOQ`SPISyULfAYAoj7qAigqnsfVdG5f`dS{FY&Sed}w z%=nW%EacZ*uj?Bm8%4Kj%}zIXeD~~!nANiG3p%)2TpPI@k1SlMX!!8-wQr&2<=Y*U z1I{SUTeQpU-P&Vs4D;W&286W#hza0Xy}0Dfo8Kv=j)oD@voyMUYh`8`&wDN(aj|il z43qXN_mezFAC%kxrTiEH4K6<(9v+UIl5M-cy}21&q47-6Kk#6)QH6%G_$o!7-iMbr z7@T`}`9o36wY-#B)Bj~L?^*Zo@&c=;D>v;qYGIzuQ}j$O;$ol1%{2$QZUwBenl`)i zhsmyD9+AR{3pFw>Mly)9cX^BW8&)_dN0~nD$X?N3sdae6vl9zvv#d*K34K?k#XPm@ z_;uHbVQgU`?g6Tu()?>O?i>u2^PP3#Qn1NBKc4xInw$cA=H_WOxR~DN@A|pNc>A44 zn(Hj|Cm-n2txOgIrI_2YT|54sxp~~e7*bg+yv={7_WOy6m;AmTuiCn~bl7iKbpA7Ys5i0fi@e~?cN6CG z-GBS`RqBrV_zm8BwwZNiF}d~_9y-#uA7Ddh)W-&wz$e8zp&bfs-JJNKI> zJUXfTPwls}&#x`7&$1k~IA6OLoD=N=bf$XEeihK)kW@eYM|{bHMXc}tud6$_Q?7op zp5u<%z4!h%rP%({yXRg%eexyuJ#&>ScgsxUyx8Y8?_prp^c87h8hMOe63ILwuiF+y zaQydgN!p=ccH??5Z;sJz)uu=1c(pmZeEXM2JU7wME&j0W-lpn@3%`|{Np(G*Xi~b? z?ssF6(^|<4)#QeA%N%zVYn zykF1$E>$;6__HbJo?}|puUSteUK(?D{r&q_`gOqfeZuX(wyox@_W#9cTkSvR&TU8e|iG?XWX8-R%lMqgDWel zlQiGYeW0nlrkwAnUxvf;DG}cMM`M(0w{dkb9`>6jaPRiw4Ss)LkXfVq(>=y*ADb( zEQz{O(=}JJ>t`&ZR6|m*a;=$U*V>Rf!E55*avybjq$#!7>ers6kJHZ!#uwxznatUL z_FvztgG^hUvM$HX?yTD;oVr`jXhFM?`&`R6&;GBRe>Ev{X7Ea>Qt$c(hS3Sn&y5X>tCitoZ7N_!_MB#H_qud$njkkd=R|) z!GYeJO~JE%gfkt=nEW>M_wTGYgL4M)s&3JjStb8Eo^M!yl|_xLjuMthq<~-jc#P*%aS>lizk(DRDpG z^3H5~dMW+*RlS4jlGIz?t}$X59bQ_HqYRW4and!c1wbomkO@BKV)#ocO-eCfS<^5)^a zi{_uy68ZXI%CD3cMt3<*q?$E}2_BuX;LbdWyT4Z2W!+&jcFsPT`giw2w!|{l=d0LU z%Og(lFqem&*lbaMT>QY-=}G68zhCuW*Ov!VemzzUb@NT#Sj=^765bAI%@&VfGztUl{#Pi6?}0)#=5m)Nf$1L z^Js(%DeBh+8ZHj~G!WT-t)-4`a-7YNh+clp#$4+E2yXb0% zjq9E}u9=W-CDNwjIhYSLAQf!X?5SsR2%w6?XF1fk1dlv zEq|xAdG*>LXZ2f)*UxP8zieI4c{t!)UaCM~kX@m9_Wykwn}W5%|4g}Xw)1fFtq++; z3qOXo`)}pmB@}pim)fc`9$dFVpMO}{dbLGy$Hh&uX_rECzKb8YsafdCZ@Th5k6)ye z?b1E76X%OBwYl1ryDjDKL5r_l?Hzs$oB!Uu(C#odp5eQ0%I8B zNOs>{)(H&uA4S$ybbVqkx}9+0JWV>|+6IRYKw&n^w9@RU$^;>mRS-~lTqZM+BqFuL~1=5%I z7|gs_8FE9w$lk1t%H-INmrL)sZgxt3Wp285!xYJTZC7@cr~W=` z^E!I@yo|N$)7<%erCwcd|8vIi`jqd!a~U0rxsJX3@vJ@6k87dSeD_F|_kV5$l*9>V zz0`ar`tma8(FL0$1ZqDt%d3=x+;TqOH@myiw(jniO!jH}qrZ1~fBMW(d3MEwpSFKf zMHW}w+}qYY{dkWVhsHC0<^?ydv2{skFu5)O_4SW92x=H9T7X)HApSA1M2F!q2SE)` zJ*Oupa(zwY<%<^!OLu2qT^0J4{pcO}@It?^OH0l?^*(+sa>1*5CFk0Dz56G+XG$N* zKla9vclI|2ui_@DZQIsvDZe-=-LAMr?#K?w01+3Fm$9+2&CSi#x5FPj{R^Jt5@+n< zJreA*cf!+eTjD0md#y3%$gMlE^5=1v(+e}$O=E&IPQ9#H#G0KH_mQt+rwzAAAs?2G za@RklfHl8mKm5688^18%%q@kj`@Qb}nwRwN{aX_T*K+1cnWpZaCb4^tv%hIt?pZWxp;>OBMe9__f9A-4Of{ z@V@Lu@CDx!AFPU)?H%SybzGct?i63m3e&}L@w<0EI=Snd6yyFaFWAE-sI}Jna%H{9 zO0-?}pm$wHQ`K(Chw59`$D2Ok*Es6kb&^MGiSLpI4yWlI`mljx9 zr=Jm6`$eSJd-Gz3TOMgnA7*V?`TeWxSH8)g*R8sxpxMa3HLZkgLf2yfOC_7#%~EW! zCYw*+zO$gsOD4+mPM00~7Tb-bNxNri-mDZeIo+^29yHv>(v|(WbGd}O*Xd6ky~;ds zuVQ`be_wL3+-3Ph#&1oB-88wC3Zh+Q7TZlUw9apm`W@Dqdv|1_f>>=lkkGedU#2sD4?R!hvtk0wR<-{dN-YISC>-lS9{#wG1 zr``YR?%>78UM#h$d8N^CP4miv75CdOyX6VD`(F*adTjpT)%)u#{kUpo2z=6AxO2-6 z8&A`%b&?v2#j_=^1f;M1`>$Dh)&j}<>L1gm#rVnEOgwZ`H{i#9K) z_}IgA;stX+4o}zCBf%z0OIIp4a^BTUzH_Fl@m+`G`a3!$_l|Ux_y2N;^1sNnJ44)| z+Tcjt1-HC+N6#A{ntuD>+n)5Qr)-}brFT2tY2@!!h*=qMWnPNqYn?cg5*hcD(3dyv zENH7@aZF}0)tt59UY^^JlTp=OX)|Kl{0qH7vsSA%W*$7S@$=`)$^Y748rmmXM2Ua< za^(5L&!3B0x4(IBpkv+g?|4KJ_fw6-v#;77Vs3l+@mu1g@Atoa*`uA`4r#*M2&)!hGn@5j(8?{Ep>pTW@&5jQ zn)U5}->^#`c2@ph{3CvEvVrZgl-Fy6g%0(5WzBi?^l53}(M28t$3JZE;9oDI61ZrV zgP_JWWAWHW)_o3wkDZ(YbzJ_dI~hhuaL>$W@}Im>@7PMlqYO<4H`;2=>o#Hs^`K|- zf`>;|TD?_#-k|)jVL{l2XIsplRYt87;VQRy`(5ww)8Z(-d-opN{VV$6n6~tJp1#)8 zOv*$>QD0>{8V`M4u@!Tzs_=W2yX)C47Vh{Pi4H|&kF4FZ@5i|z3!%F1$ zuU~n34KAjQO2;HXJs!hj66tM^+L$;%199v4j>hgT>*P2Lo(m|vxNt|-)m5dhuf5f4 zVEF;k@z_LztF)vfCYEPy++Hb=7QbdCCUEZnrN7_74zd?A@CPc~d%$ITQjZ~97pPNW z7{CJZG)M*Hh^yZiKY zoH#_qyUt`BZV>@3?Q-s%=p3Q(b}JiriPz)>8g4VfQw6rG2s&|SY_k_({c!EhhHa~k zrq$dObjs*lXkiul(Zo8CscWaB;pu(7P8&@Oqi0I3t=qPG-b*ZQ6~@eP{do(p!A z*dCR-upwt*g!H`zB_|Dejkf9H_NiG~uPoXYFLiwHT(`ofR_(?`Z%+MO!H~T?lk_J! zY;+CiIluT)aSuD&GPkG84Cg*lO=VHM75Q6jM#QXHUF~vn^>ab}{mP2vDjGfD0#K(#F?b366X0giS()#6*3oHuCwgt`8>OLJ&DWdU=>FAI0 z-l|n+d~-F9?L1L>&D^m$Y0t#%3TBgcYri^5FPQOKTT;(vm;9E_cc;+g#2n6`F zDdoj$7)|RGVCr(%=qcP3Umm-R^I+%E4gn{Ji5CJn6kBewbg@XPoiK3XU_2V2#Pz`R zdJH#TtE;tuu%KcK7q9EW*XwrseVMQhlzJUpTJSAGgs(Wdu<1fuY&HA*U+uN$_uRj? z?{Bca`ql%pOtY=5tZw}~y6wzoduG>`fX2=p-&gOyyZ8N#g^$0>Sr*psuKK@Fc(?qI zL;IH3zgJmQ!Mkhq>TK{pSJwA;cfnH@>|Gp+Q#3BR|M{?QaZ|_M+Un}E_nG0}-`ke_ zI8wW4f5!HP2Q3PZE?l^aK-pwkt*;k%dM9|4~>VqQ(la-mI@5;+%<;(AT z9j7kBs?Ns7#$sl5JGT1U8^$gU#Sqr6Cb3-qBPAMKQ6*vypmmq4oIhUpSY3A4@WwZ> zt3FMOB&_cSF@VNgS_D?H9Zgo=ZD(@fo7mNunXuJ6jY>`&TUolw<)nAMb!N8wy;(oR zDfZuMdtRaUzh3WOUGsSJ!B5He1+w@3jF^|Y!&tKG(ay`!vlcf$f4;aX?Adww9Itul zdS;s1fxe)%omUrBe0g^}Pygx5^BhY1KCDdmsVpA1KIY#i_amQTq+d- zX$w_W%`_INRf@Awj=ZL#1zI_lr6|HLxA*t8+rK}5E}UO^JoVJ_I4--Ym-l~c`BRa7 z&Ta;e>&GuIpB*#RnPFl3%!B9Y`p@RG=JD;GboiOu!GFn@H*L0jQ$H!%Oa<Z$JeeZhXe0^Yo|R$CBJ`I0p`HxCrTpox+z z8`{ouZksDzrt1FJZsWDz7Pew*KTLZx#bMKIiMNj(FP_`Z2aN)*qr%qJWzU}{$Jg!s z^egyy$|?1DkRSE?-oM%De;e=6}n(_CLuL&QY4aD6}tzZ;o|&)#5XY1EKC>I{LT${i|313eL&Z$L*W+acOn) z5r(dZZ1w+wjy_K6OBJ|!MzTxr;-dC6KW)x?hfO&HLcVhe`T4J&$>7=|kfkcZFZ=#h zsr&8d5aW6cy=+kCTE%y?wp{Lh-EG<2{J^u2;gJ|vQsg?Cd^`Vl!0qS|VeqQKRcuF_ z-M8PZss@?B+9l1U0P^tFg*VJA7Ci53RC0#(oLRa!7A|`I&42G5+fUQ0+xxfd-Thvo zzzKOEpV_rVVAZwAnqS}VDP%G3d3$2Mb@T$HF@41rfm3=Q<2gXibmAat%`#Z22D^sY zFVdQ&MBb@0Nldn1ONa4 diff --git a/doc/qtcreator/images/qtcreator-add-online-doc.webp b/doc/qtcreator/images/qtcreator-add-online-doc.webp new file mode 100644 index 0000000000000000000000000000000000000000..94872a519fd6a4ac5079f80547f47b6c8a6bc284 GIT binary patch literal 8250 zcmWIYbaOLOU|gKR( z)6Dlz;+_hzH8Ah4*g9#U^wjRvhYw!)wr19rk~b?;Po+Me^X+`)$*XR<4`sD@e70*{ zUf7Zoef#6G@AaIrTa9mT%e~!^`~QS_RrYPO$4_QoeSf4kH~M(7+ibxltqx$EjgtHNB5YujY=-(}{y#0N`zp2}x0b&qx0zJxd9NmnJLX)b^SDP#;&C{%641W1mqkMLem4#*7mCW-q1x_(JR_z3uGMl-umL zU+!)2^zRXw@JpX_(vuy%%W4iqtY|Z=ddI@_qw}CD6Jw9F^c4riCr!zg4l8aq#II~{ zojUuNvUG%1Vbu4>K|J%yERJSRXNhq-pr_GjH-k-dMuObRt#4;1ykvB#}S6neIr#gnyT*} zeoUQv`|Y>WVnyHID5b6`+E^keCH1*xtB-N{9{s)h^!r0Q#bpEbMd*G8%bGnN!& z9qF~-#QryBQp)Ad^Zm2OzUU9)Og`E-f=La&aSMl3%hIBq&*Y76M4=(2B8 ziBdgX@FRFFBgbSeJ`MK3?;L*vY$k|s|6}2|-Bhc0^Y?DMsX}MU&TPBwI9qVNP;c>` zv#e{yOb*@ESAO34bX^3iPU%LQb(wp1E;iFSqBF(A&_i=++_I^1Z8{zPtvWj{Yh-!Z zEB-6dpLXH6esS^rJ^RYT1U~YAO;euhIaTG+Hs6JoGPABPyeaWfev8X)_1SAOI%7X& zdgTOd=~UCZeCzeWnHwq=Db8Q9g7a_60mD>>>{I3Q-~BiG|L*kka{fEJ{~Z3#-t^b> zfVZA-R?Z@WHo^ckQ1-kYBv zA6!5CY`*o~gj}olz2>Xfq87Vf{U2XceN9b?*G$(uDbhnBtuCQ>PF88I9;8!{#& z_paW}kledkKl;SayQ;GvF)j&hjnlrddE&ds%iC4>`#NS_@$c*x6b@=BdU3H=zJ9OF z{56kxwARP2y(-7PS1cl2o$bJ);5Uzig0&|4eNE{|eL79?!IW!XHgb4;-x9y=!tYH+ zOkWd3W`_N&Gg0(x@nloKa&U#_UymA|2lqd?bbh~J=a^;i{paRr$+GMzN?R{S$p<`I zSi1Rx$aI~9@sC0(8!jyB;Cke}&!P9UtLWlM?=%~4oap%}G5e%e4d0{lt7rTU|54HL zVY%pkF8Snu{g3Kar|qe=tvX*M#O~c#F|DGlVoyRy+WepETcQSMC3IKut0_}M?`~N2O}6Ly z%3UD`fAe0w?c^r&tXV4|wC94)-L{<@wbWBrvjr^DJNa{=v%x&EDZfJ7g|Bu`n5Fu1 zHpf!q55~Hd@v%}L_Z7VRGj*X;#{A4krrAf?Raaj!Xr3`iaDtQQsjM{?%MxsaCG-`f zgmY%B_Kf{@^~1iHpr?;^BiQ$yf= zok2Ti$c(fKhQ8yI9x}cS_%J7M;-<_s77JNTBABI@x)_KkJL`XUe0-ogSkS4I2VNf5Fwrh2qYD~yLN{KIyEEHt)r1vC_U~%Q3e|4) zHI@z2_lshiv;F#z2~-RO5NbN zizDa9_AZT*ixEFcxp`wkmj2llx_(Kp-{}eKEqTRVta+nkHacYgaC)0s0}nt z^|aBgf3d>p#Vcpb@ZAt+#hFtwV~z8xmzo(5mS{b_ytYbpuF>+w)4PdH;2u4yn5@ogC8!ZpVYyWEu)HGXV7SocA3O@-4_CxhsAuS^G#C&Cdc zxAZn{4N@@>e3zQI)N=m@_pEn!by5r-RTfOVW>Iv{XK~cY*HgAmO0$&NQWpK-YH^aR z?UcQe+)};1y0ZkzS41#nFL6k4TwvPA!sd7&p;g9a_EXJ=Hg8@@`Y#JyyF|65H-&rt zq|#D*E-_#4tb9DMB3F(7i^31 zG!O}POMJl1T{+c0NNpqM?B$*OCrVpHS(qn^cdI2n;8xZNQrp;hyZ-;5dOL-4O`BO~ z8~y+A`GKU8%ArrKf@xdTHY)Q?TmJZw%;HTJubrBf>+?u%pYXeTmXOsZmbvlMvV^Q3 z{h0oA_Cb!G+Qb(J%uDJo24`&vdb9HE%-KhBrp-PmVpE$qWiMN0$%QEsW;pPd)O|GX zJjx*P>(G{iRWU3+N#FSW<0YgV-szjDW-(apkC=TVXL`o(LlX+Qckcf%MaaMJ(QiS6 z&YRj7zqj&=NA0?2;BDF|n>dTv{gAIf?RURxvaPRpl@BZ`elRD&WrmqSXud>rjyZc@ zi&Ze6%;YQ4MGtN;hs|O>F16v3jD^vnSKQ5)eAnD@KP8pcYFUs{@V&Lwf6AJ~YYi@` zZN>j)t>G2AQ=9luSTlPD?~?-uBlB+UvTRFV$8+j<+hwC4zYg)t+V(*4i-Yck)+;C0 zB;~A0^l08>dWNm&!2%ug1((lmO!Q+*j-O$9c^dPhO-!$x7*DQAidmDmqU_4r#BCE+ zvIM&By0hin(@h&**kl}@9XaLb%8=C&(<)cr>noBAyR}5grd?y&V%Kv^q7HOz4eor+ zk{mz7@UmEr-`tsk3%!qCIDAy9E!+L5RGRpNhqghhr*Ui7Y8e|^p2(lsykv**&U=h9 z<#u;@gqGW;O>GW4Q>bk4tyR)A*YuMcU+Kz2V7)h`(l{*(95zYIL>sc(1s_v5vHHR^ z^OP9f!{29wcHc`YOwmt$dZXhx|cj}PExx;%Sry6qHTWK;ipkH_*S71?q(rwpiHyE{TZ3}KV8ErTyk!0BO_Su1z zrX88#oGZI|w#{DYa?GV#<<7d5`cDsR6kcP<-ZwR2v1P%eM6;@W2F#0u@9WN9Gt=#g zR9d5Dfr`sPakVKkmlzAkbzP}in|Q6maN@zc;%QPwQ#_&$znQG@B=ygAh3D_3u5>vj&bGXz-*5e@(vXCHag$a@ zdB5}tkJXoOrT=_1Z|~`_&IWxRroT})0)rQ7sn4;vAj0MwtHd+2w*ADXqxRL)dxd!8 zC9-0?tqq#FzHxE{&nWg|RXQy$oGsBf$@Gj+=K}pTGoAK}8BR#E{8q8^VbN11hSSq{ zK&E$jebf7Wx>5NdTSuF|&fz-UL#wx%yqeZ~;g_h%?tR4}U3#}9+|qt_d3@8`eWr2q z_UT_MMI-lE=4>v%nawA&jwi$EKwR;I8w}fKF}r)!YO?qB{0ice$v((c{NRe|gcWBF z@ZQ*y8YZ!;A?qtkp`%%uR`!jC?EAkoclS*GapAK?HVb$8btguLI|X)Ab3I<+JUvo$AHsL@H*4MP8M0zv8!2VsET~ zL4>SF;j0(iSs9ZWD)*W#5#*K2WoXYfb-jE%YWjhhJA9nlZw4OreX*Ol&tLzee)lGY z-y1xa*X+7@{R>-)0psJwHx{2_RC6Ww)FcXd&tMMIuW^h%XL)H!Yl-vcX&1t`-8}GH zMvFDd*Exy7g3PS>udT+X|;FZc|+?eJL!=OmfZR(5jIE2gsDaGRKs8z22_bxX*f6`cHY?tD)ZnxFS=Mrhxg z!)$Zc2UW)U=4UKx4y&tQbo}dq)8c9yTM}1?%dd-^ptkm5jhBz+@n5qv7n)4ZY&*W$ zcW%nWD~=JTm?j9Xo%u+rQSssCu!RPwP# z)T$C_`fP$ z2YDIE%%=w;W1c+ao*Z!~B}|`vtx1HUsp=B{SjXj^I`+%_HhH{K&`E6&w!F$AvaYS` z!(`ElK(}KpuT5TB3wi17mAY_5luK1G)HmX4hVm@$C`}uo`|gWOYjZa&`@H6YU)!>$ z)tAqPFhx)1m~tX)O9!Y*m6&z!js3QLPl_E^aD1BH!JRcRP3s}YxenL9-slZd-iw=N z30+#etbxt*;?{Og1)bEnXWsJCIR`( z?`@-|nE#r!Z`%@UrZ$mU{yCf8pOyJ$!oPaf%9m$FU(Y@0dP`>4q8Dr&Gw+rL2*>R+ zxFw{vxhgSQJgj3`i>dYUbq-25GH)MNxu9Oa;%B15=REI*;4v1q7O7Q19-@cB)R<4Y zdfRNgxXa|!$|_z3HjdR&sV=t*lDc!2u?no6{eUNDtNMSl_Qj9Xojdwtyt%M793bu%_kn(DOTKykW&)hwYkTv;OTfA4Tw zsB(zSJ?g5IWz78cXuHV1w2jPyjmy^ac5vN`xPQ06XxZDw%OCa@o@)He_ch#n-}PyA zT2Bv5Ja{~LVFqV#NJmT2miCVyCY;nd8X+My4;uTLCb{J&8RuP_}{VX zS%E0 z_R@5|VAJfAdqNJY?aP?PBfq)PJ)t3yXVs+G;P4x1>jQGawy_-E6Fcjff$QdJN4#Al zw?5d@^{wG4U+j)O9#>tD3T(Tn%`B}sAF0N7i95h!_QTM`U7wb}u+wqfv z4O{ZQah*&vE&LEvA#>!g0?&~LszGd@_r!AXI$vC)`Y}jx!%VNK3I;}P6VAphytyXJ z{>4YN%r$Zr`A4QNU}>w|U2-PzRhn++bS_=zOyf|42A>p*_tW0Y+T~azHMr*{eSvQ(F21+4$O&73%eg}ve@zTz{-s);zXvq9@1s!W4^alYHh)y zseUrwPkAl3I9PDH@o)X)ug7Kvf3FFs}vUZZ07gm;CP0o z2MQs#5*_(~-NE z@5}rCJZp0L`fm2Tle=3Vx5k~|`1;sn;od93F8%KP*Wdek7zICF{`c?PbJuOJN0yx~ z$ZuZek}{d^w8WH^EEBm@lWnIjT;eXHwn$+@!HW`G`7>1^3l9hs6fuAAXmU_8FUX%I zJ%{Vd_Z9puN-TdZ6~YXBm6+H1lrJ(X;P>&{_51h7W0ptQ`R57$?Kht4u|v#>bAqAtUq7GZq`-1TtE%a? zu5(2eJ9K?XVW_&Y+)rF!Wq^~C09W$Eb+f;#t&EP^=Gxy9RBFz!W=8bfRXy`LL}aX% z9SPj_o*a|foD46om1n=QUye%JK)fZ|HlQ;o`#xOOh=<1byo^yH}Bj=Lqyzun^% zTH>BOm?P0LNB$)H1^;{8igt?W>DOKVIw#)SAARwe`9>|Jmt_ar_9cY8;jXgn=)cfX z^q_zt^svpUyeX5i?QPedadxaJxV+$%o2H{<$gZIJlNI5o9C~e5E&I4VaOtJGoq6+b zb@ykK2t4~N@ALlL^MiZV-OQS&Vb+oVv+Yl!xN#LrfT_wH>2LwAER$LD=A8<@{`-jh zGh_Scl|Czj7Ef~E?`=CGtfrRo#c!gJW5<+bOC@CvpDh>lHg@3UQWX5inQG4|)_Yv2 z#ktjmN3=$C`$d~8L5AKX2M;TskI;O%u;x-DL#mdb2kYd(N6ikG-tX9_|Djp@SKgE zS!_o5(=gMz7XCbm*Ujd;yQ^4qxHZDXHy3B5IGZeFJK_E@VvC30s+bO*3ybHyNSD%g zIZ*chy3KWWxBp937YTHF6!7pfE_KnBmHhki=QDwTzyEjd+vlj`;&DVEqx|XWrMFMn zYsj^za@(}+xEMSw_2BdAB>{)x>K8Q~(7kh8OK zApe#(t#chtntT;Z$xLPFFJM9%ADux0`-48XS-GLPZo0QP{>%=)5ECgDzxz1KK1OLOQG8P>Mx6M zoBFybory49z0=fJM_6_4YE@Y`iM;E{$`7R;I4x>vT2;~28kFPmc_N4L0wss3NBaU- zh$`>ac_GMf%RG}ea+$?0!(!7_vuBjwT6oHJExVTaH!~)t{+g@Rx-1hL1RO6oC`mdm z5NW(+9&mTx=ij@v?ds?LcJX*6(J8xo2CJd>8Rf@D57MB>i6S*@a5TUnGQ z8I|k_SKK6h*-9fajH$HGW#TlJ8R5!PU5}S?To7tz74fW9a}A&K;JSRoMnUn-7ydC7 zU%b%0gs0{?OHfOX_5S_4`zLk?Bwh$m5@inYV*2veBBErC_Og=TI!4)`wc7+dXUn8m#4^0tnfQ8p6_;{GqvpZ?GI%`+RPt~1l}XN%h}8+!ofAX`6g<^7h?^k5UilvY%V{K``s! zrnC)fRDY*LYTL*B-CFnI{ibO)-!?okG6;&g=4H3?44?epSH8xTpFTJq={}m>va#yH z9;rAMp+|MgCW$}10;(n#R)(uL)W6L8Jb&#yL2m7T-5R&G|J{COfBR4R?EgNu6t>;Z z{+l6i{q(gbJGfqj|7krW^+UyF#hk9&b4moY)VC`gUU%!n%7|^I8)H8QbbWcUgvn*P zy36X9wD;J4^8y^Q^reGIpVZJPZ%=x>>qvFP0o0WVnov9LyN4r&sA zBXaWg&CF%O@@KEaRfe!es()zSmw3>wQT47M;{>tFl)D#~TRA(Ir>_xZ_^s0R-g;7T zg!sj?wX2MOG*(=hU1NQxf0@yO3!F7KxRp4Y_lVg9-n|(9`heiO1rqPFB@2T!ChDz9 zQ(bj&a;?#aI<_x)zSsB-7d;Pq5*)?tuvO_-`_jvE4FlY-)Vdd)^DJQ$dcT@wcWcJ- zkn(+5Hr%?a%$l!1;4NwJcydVEHS_#}x{j0VSt3UoGPZe6Rd{`FMloM$EYH0!+*u6Q zbP88bnvliqc8P!E-3|T;Te(*~Pwf2uynVrLV>Y%GyG>?(Z7f*Qy(+R`^`r$^KfKbq z7hm~T`#&b1YpJYJqa3IFJWc7>Qt#$&$mdG6JuPmQ+2+Z$zc=i2U2|FVNt>;Pm3eV? z*Qc^2{hK=dXy41&QkGc+qRpGJ=kF`&k(55sS#6IZuDdpMLv}2a_+PV4nr`5DB)|*haU3I?8*_!-Y zo2*_b2g>w5lVIuhi^vq(#e661ctof8%TFmw*Un6S@h7wV=+ns=`S%ppp1%B4JIA{I zR_x8ov85iTbt*+RJFcoby`my~%gR}2vV}_{^`*97HRLdz=b%1GP+jffy*;6?gw_3i zgn7%@7i(D+)?QVQbyvTw{FXCKZuYg`+XCl`xWC;KdRvj*-j;as zC8L#6*VBxHm8g{gZDrGKIY4j*sFJ)6k&(S2opDyooqf&eSNJTd~-qGB& z*;}}va_zFrS*w^!_PDICSp5C-w3YjQ_U<@&&Oz{GNBPnt)?rsv{`(zqd3R7dTJZXf zGTq05_g;#*su&+%{&in&NY#SAhG{#Qnjc8aF~6J<|FP}b*?f(<+baS#D+f3jDLq)( zt(z6CH{DiS_1?y&WevM;SoLQ`OC5dl(@6XGvaS1sgRT}@HeD`OS^i>0?NR9{^Zg5d z*v2@V3ia!)ujH7VjoL( zY0Nn;(KpxXSn6(u@_m7KRr(j^@Rume%*>lI=X2UtS*fB2?`*ecwYOPWM_x2^bUSW) zIqJTdmW7LZRaxH?7TMH?Pa<|~?mcFj?{lHJrqM*;yKGI%>)6ts zbenxUKR?P+m|IkQ;90O#+y5Wt^W4_&(0W!CE}MMI^1J-~8&+E`159dE%|B+DJHMQb?qt+j> zeY~Zb^R)T@vHh`s_`ZODuHOad8$? z^S;lm{?FLH{Xbt`v-E?a9U^*d-3-$_67-mUl-RwPGQY|1C+7q$8IG^cD|SAO+5a(l j!W1d)&Yed7(_iZ>iO_K1`>mb${`|uq-}WDNVrKvVlD3hX literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-locator-customize.png b/doc/qtcreator/images/qtcreator-locator-customize.png deleted file mode 100644 index 8b28fa80fe5715ef4e68b5264f1ab6360f32b977..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22905 zcmeAS@N?(olHy`uVBq!ia0y~yV3J^9V7kk}#K6Gt@NlmK14E>Pr;B4q#jUq13}59PNSlzlk#B=inE0wzwwqiVo_=gj(Ogs|@$>BN zCPr3`U1>8a6Bn0C#+xs@b+2|pk6c>qdX9GYY03BBd`u1B_NU?7lecs3?@S2`3k?gM zcjmnQKEug#r%s=|{qxDs)|GYpx62+h;5od3^-b;^CZ5C7vdr(6T(-XVu}?b5Ak;53 zN>5VZpuw70k;?14?|nVM%%78+o4fsX2xq8e{=T2j%J+Sq8?)o4!y><#yDr%aZeIB* zUEFR_a_7b~wbn|0-pa?<-TN5&_RnSezn9C8C#;&YYRjrKfie2EORJ2w|F3#!e1~n? z9$(R?|9-!>m)gAY)9S?m1${3fl5~pi_jO#pbYf$=!cJ|u(+)yMzg{Z8{>yREhHH({ zVY01RFOHVNjE($rLz&f6=eqXp-PibquDZNB@OM?8)7-N=`c#h@eSh0wq1!EAy+on& zX;o^uxB{a}1Iq*kAqOUpim;XO44lhZCooK!dSh|=vB^iy*&p7#>x+?nah;Lf=Zxg* zYp0e|lwP@Bd#iEaL=7Y;!o|5MW!l$maBnQU== z^Qu#ZD{U5uita9(>B@Pjd*iDlbAF*>POtkqQaby0Yo@>ddOvp>@1!?@ms1VvUkSao z_pv-P|Ci_2_wRP{OHK%h*DIcsZL7MpJm77*&MPs`r-9dOSwGKTwQT;?M?rSQ`}``S zSSBs8T2ak)n{QHPYqXNbvwKIi9E{}pKNqk47Zf(9a`XEXubKNgC%2k-EQ?v5y6=oB z@1&Hltg3zUCZDVN=5+AL;mztt^KX7Sy8dMT(Qo=O6QY?_UbA=>shyi|uBY`;Y>M8( z_}Y@I({=yZ@Bg{~2!Eqn}0F|J;6aggEwyd{QR?|@ve7i zYs&6UI&G{{e|q^{?$ou(rUgyMljF~voa8uZn(}SeZzXjLKW%xP9Bj|lXI$Wajj6M` zY>%bb#n<=e8sD44#e36mzWwJjGleFo?0<56+P%fa4Jp^E)#5Mi6!B*EWNIpL`{eD# zZ2K@`dLoS&_3J{-m_z z760veyC=K)cILUQQ{#;{Uwm@Z-+p1%ww<HB7`y8H3Q z>Mv`IRsQ>lo218GGgj4|{YX7aq&b*nq z`Sr<1zkb?fG&=46$9-4Po6+;zvKRZcs?(#wca?3NJ2}VjP^IxFi%nYBr`>f9D80qJ z_QWRBtmY&3)=P`$tm}C;`}DQno-do1um1ZpO6A(?fTOm__tVcE-e@;rhMW6G=Wd6j z_|2PEYh)id6}6>bp|H=IL+EFeu^!{eo_TjF?Rqxysg??KEWa>e*(#@4Nsl#L%6len zv8p&$Te+U4vtp~={k#b`cCTmaED!N*cG+Ye?<*m2y@J-vEvwHqiB0)I^F?)X)Ed~b>3Z_|WK-CMj9 zZp{DB_AY&O|IRz_@W9$4fy}un+NxF8r-)uL}c~~@;&9irV}nGG(Unqb)jrZ&b5Q`g$i8Rw6QZK2Zp)47?}1|K%M=u#zpWAZ6=n z-Ojan2MlnWL0+r3tc{`sTlg?LRV`xjPH4go{l1m^&hfAnb=>Eq(>HNCux*UpEoL6!QOw-{K zVtt}4J)1-EO7zMsfhZjop{qL{n>lfOja((wBG$m7*uuc6;K-rqz~mv|#4&+k(u8~8 zx%Yo+^|v{4w@rXar6GmOLnxu3iLi;w-iAGGHxS6I!C= z8dwxrJQz;aC~S;US+w`lN8wl3`D<tq$WE93cfXM9EeEv1FJO&|v>vGb70VGwE&P+(Ls zZg{eYTFS;@JZM@De4+c&rjtK?|f*?<^LHr}sBEY2bv7zNi z7{|hS-ABT@n^e5Fo}Swx@M^io*4qpoM$+(-Qn`zh3eGd&NI6ZOvaX7EiZ{ zzu)c7Pfve-@!c(Fe%mE|U*6`||6Zi9@L`+oO3OVvcY4m;_$_*a)ESLW9}e^H|GxKq zt$+F3Ms~RXi~rwsOA>lZSy; zszZ}5tIDdjz1!K@pj>X1Q|n9p`F&*76b`PK!pJEm>{0jg>&b`twL7Z(_9*<^x%u(Q zCx=X`8)QeqJi=UMcqcWtO$a zmG4oyOx@GM_wDERy*u~q`I<{t63rMUSr`4jDSqsf+H?EhGdms|KR>Sj z=Z&mHSnB+LUzY2~?RjxNeCnrT$J+Mn{xsXu_tfq+caB(TZ@OfZzI2_|xAb$@tu^W& zueSF&vvFyIOW~6bU$65sH@vX(i2KpAXC)(NShv#5tLvt`zBXqq)5$HL7$)&Gxzuhg z{l2FxsPKul`sVtxYZlecKL6$Un!{HT&3Grx_m%5-wC$RL=lx?wr{$-8*%uKB zIpP*O*{)@F{m_}oH|dF5mEunSP4S;@YyQ7{$KjR##Pk?Zyq?QM(!8+!u1eEqzF=Rp zg7eE^-T4P1?_b#vq4{XTk}W}E->cJxx2HS6pC%Bi1@)PCLeF!8RDXlZU$vF^)hv-l>x*~xL|9-q#sd14NixF@Le z2#6g!X63Nx%)%2!j+3_Qa!rW1w{DigLQy6UE$ye1!cKh2W4Xu@S2(l#xk5$t>1Ccr zFEe>0F`eAA@UpzOK;fz%uS1+Vk5Br)Y39lGCwmUa7;9T>-E+dho5}Md@APkB(&_oK z6I8N4%-l^p`%>dK`}6U0=lm#E zVmtYEXX^LQZ*P54Uq0iE)T`%{kE_m}{4d^AbJoA@$$O1OL%*DusGM3py?A$uH%I$~ zy?%C6uRl2YS2ZjyY^HAh?AVg$-^|z_+v_f@eAM#fcjmu>4YRJ5bgS(9v5L2eo-L)PKr|4$#~dc&2cf7&QmGt>>gIHU|*JSlfk1eCr7CzAU||kVN9yg zdrq&_#y-qKEdsNIRV0u~(J!1T*3QN}6(%bpiVSA;eBWkfw!Q7K_Tjm&&aO&buGg#- z*i+6?ZmMuFjCaz<0_&M!=P#vfu`U(;d?NRKtf#zF-ivk3D!Z&(c1ul2_}uhly4|;p z>-YUww0>59%vtvi_jTJ9I-m1BT*szzgGpCtzUo(b%d18AdCZ%<*(>*!q=AM(kT-Tga z4*&U1O>Sq>=99`%FW0)geXrd4jPK#PclsViU3bdw*IHX!_m^G2(%@3MBPjX*p{n#UEr}K{0)x1JaukTvU zzKn13f?f_#b;Rk!v6WxtRrT7(pKqndU(daH@?p4~{k^2%c1{lgrxm>lCx3qY5zcqJ zSID7Bz{&eh*6VkbZ*OvU$*EsHIk`(keBRZ`GnX1)ir0%dkuGBY?DVYG%aU2mzr^=` zOxJ(mcK+nf?p1uk6BM@S+^u-*Yae*{O41x{hafJY!-A$$&!4XM4V?IAnqP+55@9JB z^~+*sJspKMcHG<0#-rf4A~a}1#dTfxWnQ|+cD_=96am*uq7_&E-5d$(PqnPPd2-I1 z>n*(L{#}}%C(qOQ=l?VDy;A1nl-1`GUl}lRI(f5rHg_-F*Qm1g7PEtanY72J&L-ug zxkuL|D|qhPyk8c2?yL}~+~~ge71wsZ zYYQq>n&V8=h4styCd5eg=Wb9t2d`xG8HNb7Q)-S5bjcMT2d^k*Rr0j1_L4TYWXTJ~B4W4qUH$QRPtOE+H zo`$F2#Ogm`P4$|%Q~Pk5$ZuVTB%`<)JN$PgxMr#zNNbCHETU;0;m~x8bCR&S-<_Mx z!R2PdOgWyP`Ly^+=0%5F8(zilSXY>boS zSNYYl<MESq%oW*oQ5Pr20lZF{GE$qTjm=%VcTu29J5L6&%szS-N$uSEA6Ubxw(#Mo&x z_2i$nx*N})sVUzUWKvmC2`YORx|Tln{n})9&*g%f1Cz&&$pTIdEX*pB zKC>)jwZ47Qoyo(%q3J@YqwEH6V zbQZVFGiH9fzXj|#Q1DBWnQiaShZnUz3Ap?@Wc7QMtjGchy~jsCWvwpp*>J*PQ|0U2 z_4|IkTIxMLuljqS!==y(DIz=H@B3X=Rwnm$-AcyJR~}b8X1;r-+{vS2^dLFt(89
Qz5uZM%ox?#WyZgyvf1ARepPoLSS3gh8v)yr0;FE{#@?p&T?_Z9s ze$dD+;%7CtUqx?1NXQ*4g&94!Zr|{>RfuHuFf+@adUj%SbMxcl?-^BO**aH6Z{NN> zG_*SZ`rC=_axY8lCPgW%ocb!+OTby!J>`7E5$_+0e>@g1WS_(pmfB-uWNJ8FxFJX` zN3+gmLW|!lyM0OTe>sG`jQlit_Zs`Y6xj(H33DtzAG++%-*i^c;Zov+6;j{s$wjm~ z1WoH-BIdCtMBa+MGx~J9gA%jCvcBau&-Tpz;9T}l#d_<+fQwTMt><1cm?f+tygK}t zb!O7?O2z3@Gm6+2{dgI4i+j@I?e_~mK00cCuj28$$KQWI%-7g|&DPeSbVlqscO&QS zBlC8K-iqOHf4KKic^ZpQUBuR(VSmLsZ`AebRqf_|BBFeuVa6?`n}yrviWC`e9k~>L z_H~o!5+l9|8n!>51g{b;`t>Dqza^6g!^uP69^SW_v*+LGh9!*d|5YYD&5WDCa+q^^ zupA3d#!*_XX~%gQO&UTK%)b|&-3_JuXOlup=F^6t*l zD|4Q4D7-WPw_ay&I=?S3v~YcW*q?7d!uc*sX3adj-X`x~{KS=q-xS$R+UfY{`MnjV z&MW>+xU}_Y*ruer4cVt>@7%k6{jylI9r0yvPsdNc>^@2E#XBE)L;aV@To3p5@ThqH z+`ip-g2h=u2PThKO-n@hSUq0paC^L}51RU1d8V|=rN}2sOnII@H{d>fu1x=7`m0$|0c~iEVR2 zbcL8F3B6ztYFQ-m)1!)S(%Q9achB0y!k6yf_I!@b?1m#}K2DEawem0vEEj?*%d1nL z=agwR9!@Sgm&_%9Q|IgLCxfQN$j3>JR4LlaDYc5*D|Vq^qF=?k!8CW{tGoqxE_qcN; ztnSL~13vmoYP=RZKGQ$V^gSxmz-5Avq+7uZ7l%NOiwd63olgp{zjcwyh?^j?+>R@R zd6HeTORCZR8#gMzjk%q6LNi%i_8)k)qwC;IOAnWTqij?oV~L% zO#1%nl4wVz;Ha%u(bfu#DyKr!K1=^foIQK?+~Qo(M%L6Fhu0kAKX)c;sdn)yEOXD8&)#3@H)!}arp!zDQ7mi3q{13Ys^gjQVO*^lcAv=8!FjLQ+LdkjTF4ICiY@51E<2l zKG*sEOV~Uvo#@(~rflZ1#w7AyO|xX^LD82RwjFBWUTVWBwsn!~qV#3&w(Vh6b8=p` z#bdd%bpL+WM{HSFDi7<}%$_i-frU}X!DxH7H~X)-d_r3nRXEF^xuRtFb?fKlckSaR zeR9!B_^8h!v~f*!Mj2;!nSaLPi_J@3z0#SHEjaw4qj^7<{Wza8ZEtlSP zy{!tZsdG8Gt7_v#jT;Xx?2n%N_TRD3^IpxczJ1p5<+(CQGCI3&^JK|+=j#O(7*#Uz zIL&3VT2Fv$ZlUWJx;*D9{sj-vfQOZYTB;u1f+afcvTc(gmA&G=TTTs2>=iyXOPlR= zWO||G(8S=G?wG_@nl68cPh8ed@Qwn=_l%R)H7)u0r}-f-lMsuCfWk`+k5$YHd2gmY zogLK4clhEuFS8YnLLToIE-trt=)cAxqG(Gy=j%)J{z!i0nboO$fm?x5CBj5u=Cyzs zk}9dvI{XgWhxzlX>Z7!u74BMgfS+}C=hH+zMo!Rpm!__ex^DZ*wvvFOlV)^Yj#9ZM z)>UyJY`)h6|LXFWr%n4dJ-am*5}qrLFFthLaCi3VlxC&wPLBYM<}=ZntIo_%ohfEq zFTQTA8cgAgOHVfMV!JQdr(&7L?s<~!^DdnkFIC=LIrZPCAy90(xcqgV_1rtQfrhxe z|1;h2^}O_kZLQDyuw}xRi{naW?(j2ycvnlv!tHAQ9kKUfbKin;QOl1%;*bd&fmN!X zCNc=|Oi*Y6nE-84ZQQjD5*tkyn&!TJqRa^DqIRs`CZO<=-(%ObewSl~nQt9z%va5@ z{g-y>^TuhQ{_*h>?whXFsPrB`7BB13p~wcxlCmCFGy6evL!j}!Q&-N`sMvX2vOGGi zHh;Fxy{QlLw*5`%+uKzzYiE1D(*%*DeusUQtkb1xJI6SWu=)EWM~8ixC~|NT zcv!YU<&v1^ou3|FQ7Yd`D!WsTyUtqIarsiqY{y5xnPle$>8}*j=-Rt^ml)?dU63m$ z?Z5si&Ti7u#v>cf+SL?ZF*>)AS!lK}sF-uOG~?s`=TsQarJ5cb=P(@um4sR|M+j< zTCq+`z3p*)Ia&-tuMaowjf&5mdG6;$J8&g7!C+IZ=Up3>J4d&+f{NYl9nX}!mAYSb zK#N&u4;54d2dn|tsh~LAl8|ow(}RJN%|qbPYF!qOU(A!#K2LmeVvf|=+8NqyN0c3y zJQz3?GDSURopTrJ__OiEit1w>;7XFg^R(lo3Kn%x_GD7o%jEg^r$^0%6F+2(dfsJh z=lCz!@pZLQ>kUaemJdvQI~;aR?7E})ce0KBD-*GI$Hk8OGO9GNSYNwcqf#dCIk82V zV^ZhI+lfVuH$sGUC&db8dL7#muTkzX-(k{x`H2OtE-fse;(XGxXqDpU$}^X`CQVm- zAk5ux#OtNv;>+z#zx_V+RPy;0KD+$}+^?~|cE3jDbF<2Y=*UKSK0pt@7h?msKI3KeS6a)H)hpfP0VFth+sdae86^4^S z>$oAly}0;Nft}Fv+*@6t^Q>oGy3pIK)8Z-jPvvvVTd4^=T=}#A&U@D)b4_7lr%%(? zGOLZzliC-v#4dfP_We@Co5}~%7V@3RvuUwpzVs;4U47BT8*@JBwInY2u;Z)xFBJtw zl^Yx7o-5zHqPW?|R)aGzWXH|A%U(vSgGyPB&0REWnvB<~$4nkz-ul%f%+rSiN~w z*p;1&!mgfW+Fd(gYQS2h)0$aXy)z#)-q4*iSE%OPEv1{h0w*k!Umm*jdD-&pW);mz zQ4vP#?RT~_f-2#!7V@48iq2#?2dkU$3k6RN-?i}rJZPNM^A1t^%QWBfi zt$pBfRQ>eT{h&I6!P7aO!F)#l5&2%ln*pF!kksyV#)dbJzRfYWXAN3-g{kxLR_#|` zG-rm)IVbw??j>6XJCCkQRde4mx+k5y3d#u+7$*Je&6)qOI}S8Qa*)Au#pV{1)(kO7 zNA<|ZlCM=cvY-hN@Ek(}%fcNo(a>TxWgV9I3s!)GK#*Z(hb z5Yad7D6?gC3cUF`YNkiedk_8TEN{4SUHZzlY%X7NG2q*#8wXSagM56%OHY(dTr=P4 z`SK+P7Hyq=UZ&@Yi$a{Y!pV(i3X_h?M`r{qpRUacZo^1@&StIs`!Bk3vEar0B}Yp*8Fy!5VTO)9eo1Lw85Vx8irF4UTe?VP=4d-dmObM*wv#C8@+ zs7~v8`6YH=-)i;V$-7@St4OTg*wX!NV>e68Q-zOQG9P5#iA?O@Y~MXMs$EPcXwzBk z$E}~Yn@{*J0e0~!8#&Qhl}EnUx{Keb9Xwm>_^``vY3JX`H%bHB*Z zP2XRIyREo?@7Qzn)M{hllY#6r`LCW9DrLNW?cKiC?OGG2yxDkXYv@0>czG31#$#p& zj%{jId2wq~l*+frsog(MhwssQaLWnQy8FwWu-ZN*eA%wgmGx6Xmz`U{`}p*y-|N&} z`|R~?J0G)qZ|a}YbmY}N{*rC&lUAm*@|b1Jv2ANxm~woLS9aCC(|6)8J3b0~#K-L_ zC3N$q-G``zR_;Q*2@%$dHp_x47=ii!A&qoSr>n4b7zbDaWIevde_X>6uB;&QSGgGu z70u02V$yAI`EzHQwW)3Upa{*YW)sfXJ*!NcaK&f;MFx+Qn!`HVPdPnLpLxOs+)ldW zG{I!<0p#}_nd}vb){fm>KrdlAz9YbC38xax+*1Au|A&12y%(%TC#(OO%{oVHy=0=2&liRPTzB>dT-vabHSw=lcjHG_GlNOaZk{ITcpk zUpe9G=CEzC%X@=Zg&xWnZ{5H;Da$;Nv9s&#i?vgicyHuCdtX_B5nMN_mTyzfop^EI ziG%N+oxgB3TOqM?<(<;m2MTjTe}$G*Hr@6#G?wc8WKn(o^GcbCGd%01uP}7p;a;Z; zs=^g!rpt7G(VTg``0jI?u#%0ALLL!Ge-gUf&Lvs-?wam+Bz9SjwO#-|o z-<(@c8+V24PiH=P`sgIt2MV{R+XP9f+n>*#v?l1!n|5tIGY#&{uEa(Ac~Z}u`d|rZ zhD`f1F{QLu+9W(=lhUvCSGxrmI`=MG(Db`5Htcw-!=tUzYj{+bRbA!q$&M3d^pRiC z+}mYzB6*9Reycw&FW1{y!9my--z{bn{ef3u$ZKgrNq{i*V!j1I9#f| z9`-Hky}Gz&+|0dFxl$f3(Ffn3nzzt()7<5zJZr2aPX1Kdp1e_zap9{2pRQF-xMNiK zsk>P;fTwk_e(a^w3NPheCaCCj@!Yb1&n^hg7MmW~34QE~nYSUuY{Hc4pRLBZtFljr z9LdYhG@Q_KdIQS@mPxx=`mWeL|8~u*Yw#ezL|TPMG7i;dpu5ERsAbp6^N1rbJq$DLsPu^^4@VKi5RE?DB z+^bPxlU}xL^68F0AqV^N=59_od~UAZ-sr|}?eph`e|f%ICwf=^k;1-{u`EUtudsW1 zO1f-ZZnY+B=QbwwtXt`<&KGCRG}aXbrv`;1C(0mgQpXkhpj{5o;4Z8?a`Y9>o?rcA zk4X#Jtop9mFczjuuYbT>DzY%(&O)I&pAA+ZJo6jTzYtJR=$1r z;$!d2@Ak>;wUAXwD!3mc(ezwhR%pkEb+=_U$$<;~BqmQO+0%XB0{K-=b9LFt zsLpKBh;F&q_DED+IWV3J=9RcdC1ZH6`sz zORv^&4@;H!sjI%c%WB;Ly{zUV&sN7C^*?)8$#GFtr;DUZOMoAoqr<>OnQ z9E5Haz5Q4Jk+-lkNdlbrBcsxHf9PJq{kzgJjj=QSqp0a!CWV_bCiS~iZQsLkKutJ& z#pb);I&)c8RRo$|KXG?b`K0bW@9NTjAFvO9H!a=Mf6;fNTgzR+<5t}D7rQ|b*uY|# zwD>io8augb>h86Veq0e%1dmsNTl)*cc4F!KW@yIe?)`s||4!u_y?vmewk2~nZo4+G zKc#PdwYsWu)T-YPf2vu8O~|=db$j*teN`_nExmoORs__?cCr()mp{pL*u_O;Lfig- zQOD9Q?os&pLfAiMU(L^*&*v|91@%A_IG-s;rtEoGbWDzEl2}7Z^5?LdGL{w=7IlB* zKpDg{MKLIBR{xTYk|3A+o19{A&gN=RQN4VxE-*w;QdPkChP9rgd8!GAibZG0#%Icb z2P}%8wJx78$1+S@XQR(sF0rB@XGk#iv|1shYE?Gvn>M z!k@ce@OUgb>;CD^n4H!pkG%|yL^yQVR97RNO5&CY93 zc~+ycs`<&%;^%tHpP9gn|7b6z_tM6H*VFIcm{VskO{K9|RvN$gg)?>@fufnPV@#`WG!xmr7+r?-M+Rs4!U!wwFI zPJH`m_xWk}y?y;T?BMR*Bv%{bvpKnq6SXs3A<4jVvE9sNQUW_~cm2=+S8U)Ch(V}j z74Am4-nDC8pC`^>P+$GO$LpB;%%ukkSyq9EC?{>@^U#sqdT+&~t~+navv-(Byk+e2 zQ1m|JZ1PYLoFP=)Cal>sX)f0!)zj}i2J=f z<&3-bT+d9oJ_e6VLA>rq9VR;%2^k)UTc%rRTl$J;i|+sS(zHbq{hS^QoMk;VDxp6; zyu$REPr5w2Jk@a{%kxXE%rAYGZTBeo7-ZHl)5zP)?5*oI^P?ZE+oP^338t$}ng>c- z8O{)*ViKK})}>O!@dXO0I=*zr&**XG1x;RRZD&IL&i*!x!GDj4eYD|zsM zx{8LMCWbsy=G-rGo=a%G*&JS#caCRSgqFLCW+a1Jh76nvk#TlH#}lW9ymn>H{S!Dj zYr>MVO_$E>?rut1m7V=)@y567)~ePoW%B?HJ58PY_UtodL6w54&86*UE9y;_x<0Dd zuJtMDY4_CfZSAsojgKOCZc{s_AaVKcJo%i0{n$&^^pNk8{023)Nub))%Dk#_g+56Hh28A6-ybeIfpBlDlBj z2Gjf8E|;J3fkWEhQ?O&uq1jOifvaa*OgcO%@cZ4L73C|{Wx%z^FOEq&7xhD%FOh;C zVH5gQ0@i2Ng*^XrL*%KTvG0U+zHe18-`kw>{@7HtMR!hrTFyROe`#Og?k!Iy1}*VD z83-z;V&5r8hT2VXI90;0(l|#xj{ESEEkYJ&#J)Y=HM`fNENbFIU%fS-CS6v7G!|z@ ztDJqVyz;Wr$Ktw{Q|pz5vu}w;Pg^-hX2Oe*wlWDX!G%TwO9i3LXeH1PgQx9;E1wR( z=zafA{ph)WTcdO>Kj=)Ts9;cmG%#!?=qSsdESbPkRM)Y$=Z@UOlG%?R7KF@_zgLu7 zc~%p&=1+l9#rthezKy)++H+<0&)Y9MKKk>rgH`2a}^yf?T(1%t^1mCjB{I3 zL67|Ni}F>QS_&mDU*B}dSIL3NV?!Q~$D2bdwi|e?>p5QMFkSm`(S#Ov&9X`f@Idec zhDlx%dfdW15=?*9ZZQXqPcRBOTq>BWeZ2j3=FD}6e>AOGBd7G#UCPE#;N=m%dvRyZ zufBEZjq;(NYL5^6KI!+RPspal!RXG^&zGb2+5GK{eUp@^zPg=rYf{(3?Z)?{#S}J9 zTHF#5DzaYd%EzR6ZncN5UVN*Q>)yb^IBDPai8~mt>Q3}p!EEleyw#>zI+21D` ziW5#OiT2%|e1FR{3_u!NFNxW!0@op;JA?7F{>>_EUT6S-qz&ZKgyGer6CNg0KW+mo+eIcNbHZ&}lT1XLPt>1M9%IMcRNS7@f#_Cs5j{x+DS5`OTD`c(zZ(p=Ho7uV@l=6MS- zgf|~4S3h@x0aD$+W%s*vcC-Deg51d1vz4_epH|GCm3_M8P{qtkN4IzsZj%1+e!2ad z>DxWl$WATW_WI1{g_Bq=&7UEnra0lmzn=l~_rJ^GS8)f8zc329ZBqt~_A{z*Yz>2s ztRPP*B$eV!Wv2^O&P9}XiyAIo*6SNt;ko6(iEon{b->wz$>Tx^?>8Td(;lBPK;;}L z0r@TJIkZt3T(YNlDim(c$e0lE(z8bBM8*59!tE9>9o|fc_hmPHv-H(Ic5p-V%xT1mwH1NSYp~7ypnuCy^Owgq_0+pPC(C&KDYh}Ze9!&}p z6Hl&=iT*0o-g2q&!L6(vuFyHaPv^>B-rXcTTYc*9jQD>c@+zsF&T~o>+Cm$7qCk@b z4on_O@;Cjo8NoeXP6fwY*Z?TzCBd(HL8SNMZWe?=jrMC_TT?}-U1ridTHnpCV6HLn@3+n zVIQNXwBx3Ym8*05WMpJy?CbbJBkD`;uG1AhT5H~)rX($ptbMDdLEz<)1rf$Fj;mKK zyL|cN5rbYA`#XN8Ew4O$y*DXBGw9M)@4e}9YqKhn_rxul5H>F=vd&ibe5m04qjs*l z41Uh^Ih~-Z#&pT#eQvj?3YSFsxji4gTy9Q)G&_VCJ-W0kRzBV{;XvG76~~~EBPZS7 zWNm!%bw7{FE+_xjH*10yCUuBtstJbe74zH}vB_F8-RJuIO$SmHG|z>4&COZ9YrCh& z;t16(61qbCD(?CFA3r+UoxkVfvAf6Le}uH@CTT>eSU0}%U&6aFY)iCCv})g)$Y_;j z2TSLp6V6G8D95#^^n-%fHqZ6D_#RFG?nx@dw^p;JWV z>DNHp2~%oB&9puCB%R@(wCJoLOXv31pAL^U3QxGg+WAVM^5vbKr&n5n*DEl1_9(3E zc@Zb9GHtTf+Q*YJA37Q_J~{0mq;+hL!o*h2UE7|V@jWkWx{_H)yOvvF=HAV<+11v} zotI@mS#-h{!}Q%gDxx)Cx83pLQ+(C5MKL*i!N1sm{E29OmC zUqTvq(D4dzvku>I)x8Fnz9J3T{2Ny?L=6uez8(Iw;rNFaPAnc4pym8q8kLgHBv^6n zzWB>Z_JaDO2k)L9?EZjF1?yZ@4^oUDCc@ocQjwn~*;}%c% zT<9`l>An$hkIn0p&6S7me6LJadFr`QbMLghK67qXzFlqR%ry06)eTVdPmI^2Y5m*A zIg%$!q86UG5$Sq%-Ze`rt1!=;p9&sFtoPkox#}p>(?TVKF10B!H}b!;@cZhk8NcDm zpV#?N!)yh&WPbONy?U30S7iKQzqJNj))}pJopkl3U$WBr>8@K`|2FAs7p`|&pEI$7 z@zvWG?Qs!qSDPO#iPq=d|DxeY_c4h_EjEhQetd%Z>%&7cDyn&({1kZ0Fmcv}b4~N~ z?4@E0jruy~d|0FtCp!PV$?MKSgTqCJCmTz1PYETu49{^i#in^{l5MK zbGh8^?)BRkI2AgRWIR7h&;Q^n62+r}r9k|mD&Hypd6jOw+f=qGE^k>+y3en8^y%s8 z^S1wObU}+K7IkdhI!CeY?aFyzKl4(fh|7K^Iivf}!2HIIAE-`Umm z--l%SFDmk$0xFev9PGm?LqDs|NI2DJ{9>8W6kfjC8Ad-ApUJ)YF!2wwc4MK)$0H_+ z^J+e6Ugff^{j~+5y)!&l)bVb!0_RfWnanEpq`#X?5Ly39wlw!BkI+@ePnUKUPY*7h z1@84u+V@0x<0{>mvsGT)nq+Kl<9}rdpNEtDysJ!}<+U*vcWwI=oq<#!fdbgJ??{u2 z!OPZ}Gp~NyHNC>-*7~bTH+hx_aW*Z9$f-}5_CANFvhb?XtDNgW>vXR=K7w{&UH-df z%$xWY+|_nyx=;d{=YdWgLfRc&SGT%CrxnHCfY&*J7SYsfZDsJ(KR&TzVNFrNBHMjV|$PDSUiZ!Y%?T|IU-g8|#Uh=kt2OC4*`YVi{$)TQsCw+ zg_VL?c2iEMtbF_?As|Wr=(@FE4(xiYGNEM2>rS^chLcC;?79@p3vRjaZuPiR@#d$| zx%s|ZJ>JY@oFBoU(me4!Mx0;sxv=h?anj6NbE2_e{L6=47 zvt3^{H`w{pmVByFIi^3Q)FXrax{QLLoyp{9DlXzPSyIcche@c+-ut}}+&Vd_b$p`F zpPrUX-zQ76#P>dmo7TOdUF$vD{q-3WBmQdtytmmeY5C^ZC)YVbCLWT#{?$dfq2-kX zXkc4&{qdKJ-N5;{DPRj}^+jEu@<*j*Av!Vj1#W_WR?T$UR`$i2lDErNuzb_`Jj0p&DM?agzj(Sc z-#YCvx)ZHj2VSmJsw98%%Cts5rAZqc&s@otyg$9;WW*I;*QZaXFU;8=XR<-SW0G0e zMhB@0mw0*ZToya&a>3kI-EqQ_d1oC@Jm&;Qpz#)uWlcw3f7$j?!Cd20)03BOYL_k$snSF7c?&{4f-~{nZ!d)r*-kR!ddp6ttd8PFyyb;ujHIm%&=Bf8L zX^H(wzplFfo>qMSU5>f!kH3HNEOt8lR{mbhe0jZ{)XQs~KRz^`D+8_a_;YUEv(FRP zXtoE{%-_51wO>ShU6KQnhk?_QEsLD^>n68_iS;B1Lb9<-+1>RPm)CkQ?Aa&&sv}x) zYx7eD(1J7QEQmWiTfari)()GLk5AC~(3%%~JMu}g!D^n#lJ-e)m)TE&n%8T%6*RMM zw|=U*!twUrpB*ie)^|OZ+6Nk7U{YyFDP+)@^qhGDB)J%h)*75|pL+Sw>f+c59S0jS zeU|&rVC1^FOKHN%b@zT3OmQ{je0SQvIEY=P@rlM|qh%$&@3!7x14oAH*NHQpIZ1kS zdBwMUS-ppCedB0keX;Mh^R>s4Ye0?{ zTb`Zm#dZ6pW0LB#V#i08UE4}*4t~topVpnC zJVz$g>)4cYnkBlRK5zqzB4YW*Dbkj2*fMrXUNDU3`8nyJOz`nFEh=s6uiw0NgzNVX zr`*Vy{*NSPGJ-S2>4|3?H|;f-StF^kStPngUgnMNdM$pwkSUJpcMpLg%5%SiQTVIA zt<5P@7hhQ3oRTcLG7LO=8ey_-t;&ZfD}-IA=)TSH%0B7%?2PBC(@Hbjdp<<`IIdM( zmoY(N{ghz$*IZU>_sx~{b)Md`Xr7wS% zYVo3l$$tWa9fUYm*y)3paOhfY)`$zun=0V(MXP9$Ub503F@^~YLT@6TSl*sI^V;*Z zm!njEE3f}-GvTvynM#ZMx+|o>>#IJ#!>hfj>R zjeX^PD)U4^o6La}y2)e?*Mdfj~xvRBp+GH&UseX2&Ks9)*QBb`=I?*-Itjwx2zSEG_- zeR4*wtwl}SVVL-oq%-bHN?Uo{vYh^FD(#r^#`dh660_#3imz&2p1Z79Gc?XP*w#@s zk7NGUj@1R0Z~dH>fYy*sv*$3JSEG{jruH1O`L2SS_tgD(v@h;|v~9Huqf3wLde!G; zuY5QSK*I`5DzX2vv=`N=R4uo5?RfOYKk!qg;~QbKp1W~Xk`l*mt+ZtJ>p2}@lWcyL zb1JC7SYki_zuV;gB{M9ie64=9%_#B1>&7E1Ul^~SQkZM0AXvA*rtiA_m3d(tkV1e* zF7TQ1$!RjPmneLjfBAb}OmyC2#q{Qr8A&nG$4)K_pVBR=krn?SB_d66Z$`BOn!BK&Y$?BH;%PV>CN13 zK5xp0Q=mQ&sK!uO$th%fZjZzXUFSWZ5`$AAQqyBjiIh@n(yNAFOFp*Ue8bt`lApE5 zTx8u^n-f!ScyG+>TH&~F+QFW0vs5bzB&RWDUgxe~bXfCU3)dRvMK3mdt5*A!ukg|% zlWD5QlsUbLay)MHo;+dbKAbCF4q7y|h}BbLuG_tm51*$@`94wP;S1L_cRE>xmb)rB z1YLP1m0+}Nns9*kwj7_2W#5|%E8lL3661f8mioL)&-sgCZR)R0vg|WOYs10qBO_~% zLoZF{Jbd>xCb~@L`@t1z9x2KP&NpohzNB>XVqo=L`?<|t-yXRei0n2v_&N39Dd80^ zSClwo_7zz8L7F`RDhtE&XXxoO>6%l%&9G3!Zn zW!tP@n)n>enl$A}?9;gP-G;{lpOtRwURSYxbM5W5?|shKWTx+CoAfUY7rPkrtVX-=_BW`iuyVwtdIYyT0JGaiq-Pei<~YY`GWwyHx) z=*;Zb{69XJJzCB=(bCw=S<|`f_DoCVNgFLb-GQuSyL?y0=-n>PIr9!Fh(sB#edPOA ze#PuL2{8+Mf2b4}r&VY=N6oTSp5{2WaIOhx5PikITc`H8S=D-cOMmE9Bs68mN;|FQ zze_*Loi=;4lyluDgNS_3wIPzG*YciPBotUD zzX=I>s_6`_02^2)Y~fYuEPmM~yZ>+38-+q^n-n|#`&+l}&aY()Q(@g`9yCeKCA{o% zP#c2~xVTlwyxQQhd{KGT=~iy9@-&s5wx`^>SUy#@m_J&=xlwy}*A(aiA|?-sn|%V{ zGDTsF3nZe5?squ|-REFFVga?%F(wt9OhHTLL8YaSXtKJvprPNVC-Rvo$7}^{Xdn*xvcIv221%8CZ7Fs~q!A%`Ox7lXH@8m0a3oD%f>qx9C-H2tEEB-vVja zE&SREU2IF_nrChybra!NOQLGQmh8H$6u9`>orC9B6lXmI8x86jgT~>jB$QIOgu95B z7l-(CY!cm_v>P1Wg>1P#St6^u7P?*%bcJ}M@950_l;f4*tSWai`;I^y4-#XUP!eny z2adcQG0{frEEHa@%GTZliSyv}-Bq!=uiH%LZYkMz{Juu#Yb{XA#`V|F^(!I+rXN>y zD*!ui5sT-iOIf>80?TKs8OEf7Y9<|}2`jz_vvq%2D0(Q=4IbAGEDLwxtfqclx_M50 zf6XUuaD4|VuR#?~D9$ z-pS$GnX$|sR)z|OQ0bM~+Vi(9?tA?E)r@TIK8O}`k2eb*fm8EOaDaA8s~r2?n7w+p zLMBu|M&;#et+{Vy**$kd5=gt-w$)Fnj>bE_Qe>s`!3UoUCxN(nT-dT6x|Xk5gV zZ<5N<^28;(UKMD!tnL9VdIy)ZJ0=ToVOx>`-j0BrxIyzVpvh!VVI!_$?dr!RdPslf zw3Aws9J5}|c<#9GLdA}=YvmU|g2eO32AAHmYi>opV%rP z3P~v4>?(`cJVRZ+1b^Oq%f&5G>0Q{8t`Cs#yyiY>Y0TL>vXQg6Ca+Fn;I4-RmUY3%tv6 zXgbR|DgM`ufWcN?$=jAr z4te7LrfGueG!FsPgvR`ty%HdT287*wWRCd)%)y zig{+g13Po=md&=6t3T~MnW*mY??A_P1G$}bHS0xhLyQrv-#XRC_X7r*_Nl&GVGod9H?0 z<|f!U22SPMf=Dx1iY=gRL!ZvY|5=}X@mcWmcXp*8=cVf}^n3MVv-nljxa)UY18Ny3 zbvPD%PuJV`{Bpdz?6h4+0C1a}*DvPtj(xP^ zwK!{M`Q4(FRac<$yei+{)XA1c$TE1&4FCI=zwW`gwYQq* z=d?}Kd@gn_uTTSd~rX2zg}NsIn(a%-tGS$h}zm;oxc9x z*Zc9cNeSnDz8=}W{{PqQ{O|bwsyun){bFkN|M%7HS9d#XUb$FzQor5DBTr9HpI`m2 zG72*xEX_|*S9yS?sxD#!=x{ypVi_pfQj zXYTvE{!PDcH9`2L*u7uZ8mAbApEcwf~i$1Jk3<$(`@Z&mrRRD7uSZwc|NFbzUjNyjKj!QH|1{@2(sJuo z^#7bG`KwamlbZEoe?NaOXSF+kRbY0N_RW3a3?a*s=Q4C&n(S}4G)i%~|NL*z=|Ix<3zo zea#M+*MC<3`{?yANuB!&zWR5^fBjTnRiL28_wV-B?VBtWW$S*oU!TXF_u*)ErQ{L4 zl*Ch94X08XpNQB0umAHy{(P<7%(^cRxsJCDZge#;%cK5qA~88bfLIQVrnJA2WiZT>QK zpWBaKd((P({+VxUdG}SkmETva!9DqH)YOF)Yhd|aI4oUR6e`3R=%FMG~$&|d1(r0Z*apBQH7mT1KfQXz;a$n!zpi*a zUHX2kcE;kUo?W1U>aQ_-dezV0{rA$l+@^Wg%G>4o_da>IOmuHpBCnvhme;A{NSK6z zmns(3uaQy0m%8!K0vR();SWe<>yg_3wC& zKYmzdWGmsjC06p?6X(Ni$+o&npZVu->uoFe2vXU=GQov)(%;57wfT{3la^ln9V#uN z3SFL`HDN|3sQvJt;pWA6>uRjCx)}VTF?L2R)M$>o&cwM^0OV?g$mx@||6C;Ix9`!{SFdxd z9v|0Pr~97!!ApgY`-M-}`*Nl2iIejX`ak1{BD7Cx?!|Oh@tS#{t8Z?vIA_I#l+{iZ z+c&9ZZ}Ir%UiQD{K=?GBtZHW?WAQ{Nn zXedY3b)M{#vt4DUvR~0@_seCochpFvN?Dw1C@tb~&-kod#RJAx;jJp-f`<(pHu(jM7IHWLXL0`@S)^{}?E236E zGC#UzX2n$-kFvJMUut^3Z@Xj}{qz3hzXy2?Bzn}s+pHT{4sWn)P+6Zd+0A`%>F+tZ zlS-Ri7!!9J`}dOG`r1c_@(6HZ9oF$uZSzcX6< zuX60aL#>N`E~-BjzU80U>0fq+d+(<#7uS<{B{uP9wItKGER#`Bt-=k9;_`?u4p`&(`^VH*7X@E0wLE{ykdm=euW2ClgX)Y9;NL zHLB$9TO$1J6O+nKmrXvt>C?5Y-Zjmsu9gNlpKZd8UasZ$mt;)ln84A;5zL*U{YvV# z&TH$LYs5N_a!rp4b6mqKxkJQNT(wAi-RoPQHX3eqHQG?^!ldA7o4onUECwN-!%8_5 zE$Vc4GwHEwaC0piu)J&X;Nzr|$dr=lbCT zLXJw@KR4xmVqzBJIed+G(!JFPa!wYhnDMXZKANQXLt yq$S#r4|PPG`Uo--divm6c@@w(kY?Ne)~EYy>rXV&J(=+b5V8`e)LKKD*8^L*63ddX|XscC6jtV&Ob_ z%Uz!P?9d%GP2=M1h)IWXwjC}zDIn!EbLP&!)2_b~Fj?}?yGg|}Xfa3Z^R2E3Hpof z3C(~0{r}(jpXUT$E$w46-(;}WauX}ZUdJmEUo6=D@^7~|7C2d(ln33vpx68~cZIot z-jvU6Os71VFHKzGo8x}S{YX^lXOFgTeT!v9s@9)se0TQkf@5m0bauBtzIWjOSC;3w zZObQ?%*-l_v7Ina);PlJ|6!ii|A(AUr~OdP@4hxIJX1bFCAx_3qpas7W`n*Zf6}J= z@Ls+e=VxiWXo*x2-(+v!iI>@uGIjIzW}SOyRr$5*=9b{&`}SN7G?HbQ6SmfJ;5YdxOtx2`#T_RsS-GCIfJu3YYZ z*VgXEt6yQ=U&>zmOf>g8@AN9=c>K*ruO{3*ytgmZJ8g%Cq-W;e4<$@y)ko)5&41G$ z$b2+d^X1wbw?pdNQ?)itu)6s%eA^DKdH0WgZQE^{`L}%jq=vI`8<%&np7pr#aMzc# z@HY<~!;j{O1*u#AJ0%ug=DM}>$ekZkSaQB~*{(g|_AN9lMX_|#VW~ zH~ILc(56ejlD~@{)e7Co==bW7k5pp2*!QQFYc~0vZnw+#noz5eFWXa7q|qWYOTMFj zzSh>i-RX<3tv#>)JMB|c&bFv75!TS)77nkqEdq91WIdI%>)$rASly%I<2Kq<3QGwud!EYAqWUtWmYZuF&I`w0=eIw{Y*JKO3)I<)7QTCHL9vV(+yQfhvVBCr&ZW zoL5;C|ML7{H^v=Z>gTmJ*Yiv;ae3a8`}=v=8kdD4eSCeB?_KkVI2RbFE4uT-A+?tm zRxCDO6H)nTPdMK}J6Y}Yu&Ak%u5bH0$@g>iMVrh-tw~OkN)8AnNvvb!VOcZj**l@% zKI^Tg3dFUapBpqqz%Km6OP_su%Y=4W`>j{yTKjc-RQ^5l*XNBLdX%f8yU)z_k1x2Z zJ<0j^uky3A1g5>|zS4Em@$mPX#{v$$zf{kecyiyjbq~1Dv4)5|O|9`%d2!+UeXAJ~ zGv#mPeNwP130v37o$eIT)xdctkKsb)>w_#u?_1s2k~Q7IYsZB{EHg@EI1Y2{Ts>uC z<>!~Gt7A?+{(iS=1Lw)392OEYIW90o_8sa@pZ!eX^Rx8*3<_EyaW=Cxb{@W=IA_J2 z;%EGg%PpE->+bq`!$mo(M?rJ>=dJCwXX?CMx}@2Qd}ar?D9g!hICnR+E}}E%aqI$4 zV`&eT=H4k=OgT>Pb1_IQNuE^epBH}Z$n+Tjiqf-0Jw=22Ct4l)t^9c5``?U`zZR;_ z=G*rDw%HA#E~Pz>W?qSFcr$-D!|ew4kAJuGxwZRTXkYZU=php)@6qV3&q_}3TNnG+ z`g!0K-*(ZWXAvUzB;NRadbdASYV$Pri7`D5j1xC9@V197+GjS`nCbh}PuC8rIfN!0 z2%0^~dZr)$=H(Wje#I#i9O8fBF|B`*UW?Eq*HbTj%xo04O}k;Ca(tq6Z^c$y=C?DN zIEBx8uqkho&&*cRS=E#4b2`yR^uSr|P-~8X5>$B_kz4XB&)j86(&GthMR#75DSC4Avr3}T{StYVT;Bzn z!e?90-6#`%6zim@8++=~mMVuM8G>5({;X+rdEZp@z+!Vr8fRVRz5`7kj#O^;?!FMP z=jqwysuLLgTeR^By0Bal>om9j9nN>8&qI`N#}mHoZHK(wKi~d-Jf%xS`?X3L!@c)s zu77d)*r2?ABCmkvs&{;nvsbtsaerI>JMgZZ?Emljxl)cneOKMor6;v0sL4dJxoIto ze*J;}$R`8e8O%%8x-!du<6fd=cgCCT>4e&khgnx^2+9B2V{?Dgr*-eN&+gl1-_Oo3 z*y0|Q&Ud6^VdTdJl2Hex^>3tGslXcG&(6FSVL0L)od`r_g9oO#D^QsktTA8!n zxk#i>Q)>9D=hge1-G0AV>7iVWP|>1`R_S%&mfH_) zzcw>j=XhSPTPW{z56v(u-x-H@vSwzp-7w~py)4f6pTV*&_V3}O-C7*6E+@~P#^r@yg#Az|fm;NS@ZhdXQEcov)7+mnCoPea411KFF5y7_i;YYX&s{r7Br zBwy&dWJh62U*s?4xcIgw^ACsKRd3y4PKRIe)lcVjsXadYX8nc-kK;d72!*Iy|ML>R z{&@bUNf&dflONA@TJ^>L+bP?XT?gjx-1z?J;mkcpRx}1pcwf6J{_D+S%7KDExZ?h< zd*7e5Y=Y=s>nFQ;o7QpvI$!fibMEQo)5{f4{g1Ny;oI@4U;fMdk3BYvU+cw`ny$9A zWbIqdCd0eC?<*tk`98fh_jxvO+zBhY^5IZT?!)yw8Efk2O-{~UH@kah-)hTs%ceX( zv3YUY;i{uC2C;mH<+hyq-Ecks>gW4^-XFPg)&FczI@5#m&-(q();PO$zm7Om?{hN8 z@%YIs!(8{!M@l;;eB8IW+@QAMyXN-;x36qgXmh#C@80X8ceb#?abvUGk{w#Mt| z2d33Fz3zt+qCXe$_;${cda`NeC+VqOQKv4;mrqO1$l{U^T-Kt0YRXyeqaM7QSbGeD z_j$OpoY(M|m(R)e>s!cqDrAl3z5913#~HbLeBAu=t3dES2XB`51%fmCtU46L6RT$j zR*7s;>TTgLGvMiaBz9=Z(|8{9yW4O7w%+=I!*@$ypU0t2<(#$#-YbH+r@ohezhiuK z_w6r}G<`Nr@4VXN^HW>)_dDr>mdkf>YDybc>=*m3WxZLwy1F*fOmKmS0Nd?3%Izy; zj^*u=Zv0w``Fyj&$@IMNAZ`N z{prVpilrpnS}*%;-KttXJ0#-JN!#5o@6En<@Q~*_vzL2X9Fme0A`SFobM&Pp<4*L3 z{SoPVy!-KlGxOaiaxR*BEB|Dy{eO=yR$aR`KU28>sP)9s!-s;d>a3|DdzP6&QxO+Twv!{*v?x~MttjL_rYwK9kP`F)j^ z3GSUEyG7nGIOa>v%A2y&J}cOZ#-2UY^-iqNZA!qStWAZN%vSkK3E11#t`S*We)ox< z*EIgSPYg~u&-(U4_t=dmAGZJcqkJ)1MQ;9sn=hxxzst|xF85#6w!&en^0LKd8|Np! z@r^OxQ!2gt`}#zQe_35#cDy`~Uq9{msF>bv@8d3Uu4C0R-8;H}dIOS@6ecr9IdVr$ ziFw+VvPSXJv2QVbyS`SsU$Uukem_s}TtIu9@wb&9bzfa5aGSH*b22N+%X_otY$=H{ok!(G)(_ewTB6^)u$2DX!cjB6VEUOUG!!jwL6T z*7&eq&90EReKc8^ckSZO;^mW>S95=?H2d5q^5Mv#k2l<%)NlH*|M!ZjF8{Z$_QvlC z53lZz*6RE`_q2R)nx;U8^%6zf|BCI==l{Q4;j#66(9s(T|Np4l{eJQL-rE!Y@zK8* z{CnW~_aOiN73;Jd=``>(fd82M}^hck2`)XoU zxcF4bwbDAcq#t*xP^V2>=V_`H`VvOytuzEfxY8g5y$&;@=LomI@UjBBf}XMRLiw_y_>6szpK1A*UoOA%`t;eWnohc=Fw_mmx-;Wf`|v)o0u5+*LcbWtQG;_A;*44aSn@HeKHi9LP3a zvo-kNau06*oAnlIzN%MlM|htIQdsl%f5E2<>Pv*4999kRcbdj^C~A8~+-pnQH^C(( zzvjuOt)2U6y<7EjBzCA4wfh{Pbbc=+g7^q zF3|1udGc_*q{Rh0(RE*2*sdE3%wJ@CAi_E|r0Y;)?x}Zsr&#YTV^}ujNQYUq%dd6p zZ#!JX--=$lrTMq;^Q?QzHZ3}#zAZlO=(X#AcJBY4{{Bm3;qq195A3J=cPwR6yTWkm z(upr?-z>nFDHDps(-zl9kNmE(5dx%&&;d)b-!%`_tzuGw?fDka_eb4WL+rIRd!0k)O1s{1`D%j_v%|G)T4Z~0s^J#Rf?Mz%{7Yh?0q7_ z#bm!xuh;(7#MxI2?)r+dbT#eQuzXqYiIw3}*Qu;m8wFAo);8!^I2|s`vFN+HLS@&_ z35y(7RHX*8AC>&6y}pP0uoPd>)3(4O3sDK_EDN!TrkixJx_v&Mbe6Tnp+D*O7x{2{COaF2&dG^B9VBP|b<-(E zSL>yrUKVd+{^^|2|JdiSQ7s`M+~XWxR?jV3 zuyy6!$b{`v?|x{zcxyV-{f7s1A{mzoxa%4OOjvfv^+-l-?)u3B-M`vVC-L%K3A@coH zzB9Y3W%a!Th0IT8a#l{6yWxODVeV=%{ovC(@BA%G_jgH2Igq$(tNCM%#zRh;A7*qb zUiolF+1+v3(%XwGB~Evo4{>_az_B3o)JEm<{d2lz+Mxjy{btB3p#>(|b+{(Hr+{OtAJ_ib9{7`ffJ=&JLE@1EilfoF@K z9tyo&<8))y(FGnSUs*8!mr+~krPV4l!E#THm8!5sevWw~-I`3M z_nTaNp~C&oWYHueJrTa2Z=N}GHK?rn`}v~ng&v0YLeD?=xVv+fMQ>crHaqON*c_Fd zTi^R0>b~kf9UFK3NW-31!}jBAh1AM5Ty%OY_vhSOBc?7@dZm5i-bqP$tM%d{m8S{U zr?DqH3Z6*g*!pnB(Lkovz3)ZWPX5Ba zs`0kpAxpHjN!wgfEKa0xpuz2d+9f=<6v z4hh$d)g1#n_F3b z?)~od6N?rVbh6Yp_Ye)8(>4mcCX|3P}XCb!y( zq%}4zr)2pYSsIKq1!n)f>wSX9{kTq9fJ_%d8G8)d#$f#u&XpVoA4cW1#3Tsu8Zk3< zG;>V8xGJ59&+;(~V)7UQg^%TKZQmq~-k1}dMCY?F5qS5mIKg%xF%ky96 zEHBybGG~uP%=$l?SxT|~C8AP4t&&=2K9&CN`|DX&pZ)&nGya_^JQ#25pCGgG!-q#Z zoF3;MUo-ve8NE#n)U1l{be`5-#PK6dHT$Kd%thD z=xf+n=Jne;zvoEm&fL@2=GvdRs9(0tmvfUE)2&;YCzpP*_?dC&dHU@*s~5-ayxCvB z>`%e<-y!yD%$du5E^gVk%J{3(oEgkI{(gU7Cf?57o|}?nG@gnyIM$Bzd!&OJSQZ_D-Kd_&zk9&WCMF|Bv}K;4dSJWF*IW{R_Er@fv;H6HBtWxt8=rihS+LdUQ>gFT<)<^;EU%#;EH);wcwGMFQ8C zbp^$D1!-z;UvpY(N~^l{#`d7})h-v;YK5Gd4e{)oI@PXr%PznA&QEcHYp$Ah+gPfs zyp>?H`plR5sH$zk)jR!mili)5@#uG?_lM$Y-?2etnOk2cRud_Co_ zhJv=PUVXvUALe! zFz5F!k0wK#@*PfX-FF2y#gt{d61(=S{zZ4XP;KZ2tBuZwR$jQDDe)^h(Y9sX#LcHa zZxt+4c-avCRp8gnTZaR!V-nZq?_TF%clk(elHT{;X|^27Zl=!6zoQw;m$)@fnsry_ zbiO1JV*MYop1f8oHsFy$S;^BzTCAwqCw?Hys~ypMQTF5RIS?K4zua{eG=>(qKW(& z{prn9wj7>d>v+E6{!Qy2oMt+|UViB}4*#R1_)ay&Wp=F4vc0h#_nyw3J!5Xt8ZZ5( zs_Ab5yzcEQ{3B7bf z({G!T@WeiErAJ3uo*nQxZ@O|EKGOKpq11OYYs%Xv2D)iVa$G`^giaDhc~ zqRWXQfprc?F6wOCpZ1_*asuP@MGsU=m%UxQNpS0<-CdD0TFR2l_!*44Zf}{XcWe3+ zv)jrhhrH?~&6p$>NHRDo-0c0fq=hwPOL@m_4T-m&tQ{RnDV7}J3XcrJd_H#=dcR^? z#I>wI^HkI1D?7IJ3k8T=llu04djIzwu|GujUo~-lA*Fb|tYCxwifedU{`)se#b*6I zWN)mzCgkDNSu^8aX>%CWFVD1MJj6fg^Ued|C7PWY=Z%h9O3E55uMs-yqkpP(<;;7v z&kM8<`35BFth8&BXo=A9>kGR*d*y?Wmf1@VMFiIN7;&vi$qR*&e_ z<4SCb*QR~mb^Tit*E-i7oZ3Be_g*VLymOm)Sb@$V-=M@bE9}%RuztT4*Wjpo$k!)P zCnU@HtD$37UR%f3y{r4bY?@O3O)E$+FU)y!e9HDOdhv74Rd6@GbMG;73%{vtzjph# z;&Q&fHKi>+_WrUrPsHr+xpPdvw&2_QNiW0gcmG*EKhExj{r7iH)z79>xF_u8Ydlw- zV*c$`oTDsX`;FS^PScw8=LDR-q_8&rb(|vW&ECE2A#cv^;i#S=tmh;nk{Wd*?d_Q> zMS4fx@bT;o`#N3R$m7-LPcI8RUtW$oD0@zNx>2ycjB!qz0l!p#v+pcr*%r-T;qF#j z+H2g`+UH$KiQ<=knPKrIbN$pUGo?irKS>N{DlOlUecJL}p=ni&c8gd*_rImhYp?ZsHNDG1LtFKMIqTQov-lTfS08Qip8xI9$31DGlk)c5+_GHN zv~f{~j?DVhIGOgmjfdC072WYAbA3T}dOgp}W3x41{IcJ;Ktsywp+>gxnRM+Gj;z|x z)AnwvESaLPIyGyj)LV}9OLyP=f35DcPts0-5dMmrNm3uduIinrJgsv@bAr1+iTpDgf2YX^EJk1uBr7sDemj%${cns z&8t3tJ$e0?W&4ACG~XRxaAMyJ+s<1uzhukUyy~XNy*8aR>B7T3#@$V=ug#8amR7=cWM9*H<38HV6Eh`D`m|^?IG8 z^p zy_aU6i)_0r_{OuX%I{YR&#v9!W%A8y+SC8uT>U*FU#`6U^P}LC=iaS&F1AwUSDJ3i zgU#Vpm*qBn%sKLGWo%L3R)01nuXWb3*F4^;Y`cB()lY++HhX3$*0|03o~Qo#=EFUm zsoH1K_sDyv*o&AwconHnp)@X1(>T3jeQccG-yi(}7?61GhgIrjB?O4xO$7vb&}lA$yATEwo@ zG3wd8ENYeMn!?{)ZlW;)Avb?tb-by4Yx)%VhN5zbSK_Z-)YdFNJ?-yx1)trGJP-f- zy7}4cKg*SRhg0U81@o)yq#%PQvF<^wp~lA@kG>CYzsy|jkhi)2(XHt%N}=1{%x`mY zYc!fwt6KE(=i5rx6#<*A3@7}WRV#RP_OimTzd;{=Uw!ztsdV)+?Rtirb7$3x@EE7$w?j%~n#Lyk&oC^EcP_FMrHd zDqLBUCsL9qg5_D54;g)a1zxz+LE`65vn&x4;S~^I6 zBPY9Jc(T~NRkO>#?TJ?^*~_&Z*G*2_?-?%_8^oHvdRwUX_8s?jSh@%$8n;xMa4^2U_}ikr*?dBu zXyX1lm90VxwWnPAA-nwZsR#XwOLab`3ihh3lknZgIX6MXuVLA#wy%rh6Ay{Z>MPk| z9n+rT=O49;dG5BI4l0>vW%gOguTg*hSmx}x*?SsGSgv@rtTK4wG^^luIA zkhU?`;trQ3SigUR)BP1)2cOI~t_aGV8MRHbaL3_Nk7r+&EZwaiEP z5?8yue=H;3veLY-*~xd-=|kbAAxASl`FaG4e<*4@$@;=Jt{A4%dd1~!9+NtbZrf$s zaH#5w-8sYD$uXv4yt2M~3zs-G>Akh6>8;*$s%u$=h0LOp=2AE07jAy|Y>()N^-d?+ zX9&IJyRJC%^5kiL6QEGJPC-?2xo1>>@{A{{pC#oh`WUJ=-s5ySk`BRSyY>v!% z+dKJ3Ua-=st3A`Jo5f8YC(f(gy8)qM!Adx51zBX#pja8vLE3&Ji zH(Y#ls9J5#cb5HUN*5XF9M|N$7Q0HPB$?~!p&6eKf9%y-tgyo89kcAxxm*3LdM;;M z{95_5VDgEUuO>GSD@x@TOP@^CPTlYUd^2<-a#Geq#G} zzpwCee$cXo=RPkcFa&x;y~n@c&56oD}&p_8@D}{?^;mvj(P6k z?i!!2r~CrDC%5wL*%0eL)pm+gjC;|I6U7Xo=XCf~m26kI8*-_e$i+S3<~A?6obQrm zJH7H!Pz%R&f6hI5oob8u&QHn z!(a2GUuI9qoKSfw*roHJZ%oSKf>6$<#quwB+N0OaKhse3+ETV6@q$;X{+$WGoZeYY zI_xy>N3u_7tW-|&>I81ppEIJanaJ6)Tyf5uy(aCK?%KK$9z9|I*1C-Sy9%oi`ooXl)l??Q-nlr$>tyvrKbo6=aW2 zw442_VSn?#-v!n$_VaJQx>dmGu&i-R$jqhu=6Q){LIaPzIDFPVav8rl(?81}rzQ$p zw>o7!IC+-u{WYf->->0*l$(o8Ixsa_?Zx3<{@vSB)<&DG&ELazdtyOB*U}|v=GI>x zJ~I$L-(s}0zmNCqMe%*+?LJ=IAgZSN>)Cd*&8{WQ&=_w@Hmpg{n>+ofy6C(P7`l9?n@Vl05f|3ZG0{`=em-oIanO z7DcBGYIe9LZHkyHutlA_lu=XMJx{Wo-~73~nfIElp7}XBqB);apPtY)HHxz?^6u^F z@4FME^LUZ+c6jKnxz|2>ax3Q_r_bxOqT=_wc=Z14V&m;cChx1=v31|7WR{-?%5C^& zweFr!$*$ymj^)P2gNNtMTeO*9>DXg#iP?))CZDR^(O5oTGqI?*BFmcL^KP*sZi}eH zZ9R53L$o6`Uc}2vZjI}SxIK~Y)aK=ypE-`SPwXiCDOmOM!=D$EgdMxSK4e>KF2Crc z>8q8zf7f~L&PmAg{eH6TqlV1-gMJ;(SKa>Z3N#Qp8!Ox!K5@=Qs)+T#P>Epjv9%ZMmd^(kM>^0kK#=8xxmxQk5HzDG$=c%_lCsz6H53W4gd+zmv zLfu^St)lHA4-fZhIA6}bZt5pg(w`le*B6&|h&N>6G7pU? z)fL;ECTi8}5KK*|>Q#tcHIeo1tnVJO;j<>BG8TFu|Q z9j9ldh^qHzn|UcZ%}P0Z;9$#ahNT9zE_W|FCyB0_x@dK5#iq$lo)I^1+pjAToh`}! zwPwcMP07uRub%!d|K)!BZO8w$J5n9&?kLqu-_iJ{dn9gJtNQi4*R>0G-MspUflrCo zF1lum{Og^o%lKHoixwD|+`e!kuV%;5wjF`ef1B<yQ(EseEaFoTb7GcOOp=V*~NMF&dF%T?KKat-acY$bSUfV#CaP&shO-_ zw=iIjs-o)(R$r&KhUW*Nl+zU}JPI>X&Y2ZBp8zA)dYmB}$T-MuU2kNE2QwtKs8 zwrQ-{v+&vNBN6ZYV(Yw}Rymp&wa$EhFg?4?!6$KMZ13E-E&hV$$$V|cd$Kw&wEkao z(^UJc8P`$Xo9W#hf%mH9g%}-AsHAY%-Pyx$C%vMGp|$j`<5j*b_qR;m8Na1`X+i0N z4d29fDf!que(Aho(($UBP5kEXo6obYQptJvc3Y)6%b_jO)`uOg@_o@;e`D^EIlD8$ z?p>2^?YXh4F(6eSyZ6fb!@BnlrZa~wd1}ra>00wMe>c;tvgEwGEm^FY(;4?4HQM@# zZDRbL#1mXcqlJW=MI94_f(#!w_w$8oCx7pKy1@7GC9%y5SxSBjPM&Y}_`o8aUY#|0 zOHLGKdh=XVn)%YQTQ^?op>QLc=GFGu%P*#1?%CRSA^W{Z*1E4bD%b39=c+Xn>LktX z-C5jS_5ZV#>y=|1*O<8{aim&0Ue3Gr^!7`}%Yh=hXH>cVuAE)AB4ye48B0QSVh(Ja zq33tIBWMP{`TWJ_mq}$u|9$r|>FY!}jw#1Kb~f(WD{iS#Cq$mQ$(5Ywwoce%@5CkORm^nY{)A;#NAe1) z0u0s{JbE^{Wy-(rrz1|BDHb{KBwDm5{|m3JxMtzDjQNj4Xa3!=t2s2#WOrVWQD9f; z?M4N^AfclNBWicZewkk#`_XJcPT+p|b*oObCvU$duAk;vaf36YL{{ou-`zR;H4CqG z{C-fDQsS{W_s7)Qoz~K;na|u^z;4Doaj{2h;CdmpTNes%FDiYl_GeRSEWiBA1vky^ zs7tsUpTP4?YVzTwP08j(%`dO6i8A!cxp{+WR&Mjgc;O85IF+gdV*|?=EvvHPk5b!a zD&M?TD`hFubkj`cw`pV1V^^ce{XTqCyG}iqoe?FL68$~%NkPV$ZEtxu9zIsb>$^eI zJT9g8uV07ro?}ZFC7XY^yJA=A={**51$+3Ozr3-YQ#fZu@{Z2cEtPwgd$!uRzA9X( z)e=+sdYk04%@OH3Un<|b_Zo%H;@p?tGIitcH99@!rlO~||NZ{%N7ibw!?lyb!)4_1 zukI0QzGZl*&;Ks>b?t@HOQJ-==_c4+G< z|D*aGQu!7pUJ1OKor=-I=Q4K4o3|GxFwf3;v32dd=Ed9Er@00iY8-Hkadyz;^{slI z_t%ACb?*FG`VK6Y45g3#{IIA{>PUNKuPguSpR&u$9vb+)5PA9NXUP`U># zd)49F>#xW5C@(GW(YxckUmT`R_;8D@-Qjl{$5fLw&#yh_oqbm4(uD_RnW=|Oqt3gs zWX$k9l9?hewJ9-f@x^9S_49|Xq$QO|1Z=DF`}{JC+mBaVAk&ZcPQu~LF#g2W2XBt| z-djEKQ1B;u}_zFDJ%5zIgj<4S(?MGm8#4 zY`R)J%RfB2z-vb)>&2uay@HxEBCq`2@$&HjHA~GM=Ts6Eie(u)8$24sdScS&xTMV4 zb|;u4sqM~<4clF%mu>5qP;#+m*R7`D!>w;8dNGLSe!cT=tCD3}&H^T}DS^?>r41i$ zsU=QwQBcxTY;Q|*+K|rbFW|zmL*db!U&j}hyp``4+5mFU;i|aym1n!kz<#Sewi9Zi zTEg60244>;Np3PV+4}6oabL+*rVqESows;I3JN%A2>f( zu|4#J!Fo^AoEx|Q@CQfFaG$FZdnbL)VqFW{m^*SuZbWbOVcqof+54vAH_6h|enbT6 zeyy1y7`ScQ9W6=r)n6Z$U8sNO+s1!n>icS|OPfzf>`Ss;V_?{!b2^phcF5g8_C31R zOUie?UuONPVS8%A7d`Ve(l!rEeIpX3C49GcMsqLh7Q12cJmOnn(l*|+TP`wweR!Yy zo}bB&s+;Y7bhE9}gR^WO&d>ag8B7hAE$y(X*Z zfYEGijZ5t7p504xwvTqyS<|U6y_V1Yc9iqyH)7vayKNX+rN`%s&z0gH#Onr9iOd%l9RkQr51a#^61Y#$97v= z)vxdF3QIFl%}ENEmsDO#c6g=HwSN1JO-^Q=X`g+)LL5B%a$FvMS@5fBk?=Q-wLChr zXRkDKZ7W!*7QJnPN=E(ZwjA$Ek7r3kjZvEvT@Wm_lWj@gq1wGir;Bd#TyfT1SABA; zn1a?du|*f>tvMB@DJOHGF}2v_>ar68dRJ%FmYg}JD!L>)Zq}RpmR%2@+~}Q|EUakR zs-xmGOXEnQwAQgJGsBiOncanXPggxwYC(X`fBf1ZZC-z2>EvSbQqu59iw|zkJxLLlt;!~o|8La)@|*+>j(c_=X0OzdvDIuu2~DE zSI+VgKG^>D-=yFAeb18CO`daP%C@s+H7AO%Tzlhw-|VW0`i76a8JoQ``qh7)TdlJ2 zX!p5}sOa}KKShs3${upzw0s&o-STqr<)n_d_mQ!UuA=A9e>*)-xV7HTM0%yX#wX_G zKmE>RF+0}$I^6mzr>DJjp2yWatX;Avf}$_!^RM0{G;_*1v$yIz=3Px8S6*G+5yP^u zqJY6c&fwb32LbbT%eg4IT+Msb)fJiVc;ZmH=K9X)OtXx``8j56*VsD~DsFWxT6xVs z+)?iFTjpnHLN|z=DLH%Sb@A-l>W zsjsf#v7V{A>ghA2T`%U`5PM?q`0LIKro3(1t_yh%=C@?U8TIU6b7kAjbg8aypEo_1 z(Fof*WpT)3t))BvEt|K;+I-|$v)2A)kX&7qP`~x*!A8I8NtgajsOKIO+NR0tDCZs@qEOV`PaiAe%)ENTWOP;SZBc5>}1A`d$hz&KX^S6 z_$9KJ&-{z)bW07TF!`5)Ro+EY7fDVDdT7VLHABeqq?VSLgRB|zQ_hHEyUeogH0>x1 z)bO3nma?WMopalzMXkJ^xlRi!H2&=PaHufSj$7#6&E|d0Hx*ZX+PnGs5v_v`OE|tH zYzSLh``uPRNFcpFKh4`g^zjvWoih^V30lAXuZAQnkd?_NKh! z-umK}?e`_q&qNh;$1Tf=i|A&E@ptR1pU8S`X-&4)EbiN9-%i^)Wnb+5oOd4`r(e(6 z*L7o$Rw|em6GC2y8kkugi4mp4dH?6sPDZw&jO; z%1_TXo2YakEB?XXTYIj%g@4=jQSC@e-NKKbrWro5zVe|}t-PRx`~A-6a!Ti_7cSUj z{=~O~)Aezc;>7Q9Qgv%uee`F>*LC)Pd0b_GE$G|77rq^we?OfTn7Mt9;=KiJ0lGUk zf7sVj{phrAj^3X2o5~aOoqS%*`?DwY{62%j`#!0^c2L~>spngo?20#MZ`Isr4t;MK za%**upvb~6xplj~heT!k6e_j^pvW)8@%N!f&x!;aalRd z2tPQrDXpbomVf_|x|NB1aheG&oXh`x@p$uH=}ghzub=_hU$Jfr8&PIGjELV zn$OC=&3wLBpc99@Qp=_>TF$gxPla`d_yM-o2al^NFotZroO_b$R*I z-g7?8vHLmk^egGZkDU_jD!*^qda7qn^@mKpC6W_W|JTBnO`A`ME5V~?Bh~8eZFJ4@&9+1dnX)k?Rq|sF*bhdhda+g4_>!3 z{yyh!s9h|_R;9Ijs{5YmybINvG4+}>%d689dn4z&P3d9DWm1&43wU*F^|v3ghm4c* z1+?rw^p=-<7g;%fX&iqKi7SQk@42^G{n9iG`RH$=Cf=;q(+gxY zQYKc|EN8y6@uTsz??+uu@~9_t`c(anQ~&*IjvULLblvZUrUBklZ^_A*q%r2lA8Gn$ JeBZx`0RYS++4uke literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-locator-example.png b/doc/qtcreator/images/qtcreator-locator-example.png deleted file mode 100644 index 8c23d94f7211be5d59f1758c900f73740ff74fc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26022 zcmeAS@N?(olHy`uVBq!ia0y~yVD4jJVD#Z&Vqjq4)+!BUU`WmNba4!+xb=4L?f#UT zu?tS`H{id_@o;y^s?%k+Z*u{;$#5e@|>pU(cMwzkBy?8U+uo`qfYuYDE# zc}3QT5bw!ryPo}jEp7kfeLm0gx4-89d(eLW_q|v1u6&sP|0(u-(~;j+W&9o|6h8(or~c>*veP(GaujETm3i0^z#+5=-7#?^kP!Pm#>O@ zaHUmz$KTUISKr&%l!o8^d8_=~`T6(a`&QkXU*#OSet+7W8UJG+zIt3=xcA5O|Ftvg zPsP0{*Jn8Jbmc4g&cnB|)I<0Fl;8Jf?V(^@t$fkYT%jG^C++tu;3aqb zjp>E$tL@jGs^#7D(KhjD*@d5-LQk(gQ!vkFvRmle)=!o# z*Pk7ozl-ay@ygPxB`3E&d=n#H?L0pubZ1!3_S^|Yuh_1s$5$I|ZT_(={GD#V)n8n- z>!m`!?hKA^-ckPDBxP=$!oI5Ik9N*9cP&-mzR4DvTPOd2fBs*EN`+kwKZ=)r>!_P? zKlxHmgxpIykruwzPQXszv5$I!3q17DW?DwPY# z2n|(idS|}lf=FWfKG)B`ZGWoDtvcnST9UkM)hnx|m9wwA7KA@p6}Er!l2ui?Qf)`J zdWAoAShznpR%hew6|15cYx`D~U0blqzNh@*x~o;{a;39Z*;Ps0*Qr0f@!XGnA@4)> z{Qg(FajO43HOY;}_m2Nq@pu0ze~+)5Mec_+`D|cYvj5Ae!p>+LLo zp$s?lLPH<_4)qWH$zYzoo2m&){ARFEt+^Q16R_v^(d(b5Pm*EIUR}OxU;o3$DoZSXo)T|d@!_A>Mz#p=P~AV9 zepxU7#qImYwtp29L*UhIQ&;_3ktH*2t-t<@g{zM0KaE@^wRm$-!?S=;!(VgM8IEx2 zuUh5mm9cr%vUQb-pz3#6x49T%!~V@TTm{+>tSkO|tzr4m z&7bwtdihKKTP4>PSRdY^#Sl?FrDose+lI-pp;KqB`V^Lb?o&wF>RmCLOjkYn^Y`C% zy>xBO@1bY&LN_d3lMx%r(9ruZ_I=fLrbVmvK3KSTRqp-EYOk7C9TH;?ySbK&K_UDq z_tRC2R;_q-)Mk^!HTO_P1_lODQOeMuy>!*}d3*Ul#qkCvvBj&*^Xh0$B`@f{@xqmt=FchROV$mu#|E*KD{krtq zzGoE^Na?Cj)6Z9eLhb+m>AwH}M)Up3f2!a@m?3QWs-?^S9i4x->YZ)=@9XFPtaw^{ zzBZLRG|K@)b_P_FlJd6G2 z7W=kO77tTD{PDqqw7{$H_C7usS9eT)z1$t0sQr~66fEnV|K5qXQFe9PYP~h337Y+` zCL(@zJF1;U?ggGddjCgXg)kOBUZdywi^1=bBWs%cYw`m#(_J-nPo`#TxCfoxQi!(=Shs=3TXF{a3b{Ur!#o zTrV)Ol9&JVjrqW=#3@R3sqbW5vNiYp*t*Q6y5pKgsrrAWJVCz8Uz!g(hy=t*zdq^n zVwq-L{sY!LzNs&Nro4Oiq)(!Hsa#+7-5oy?0xYU_+n81@FLeAYpjXx`9)8tMzF~>w zXTPJ%HPNU-Sq^_8o>dF)+S z^X1Bw0O8Q7-B-VdhA!P-wECC+!c`0#Iv2`*ZPnd(ck!I5@&6yKj^&(orS;A6Zx3dM z^s)s`-gs>9!ArGDwO&ExMzdGW3gG7!>3{7|@&Awc4u;UT9~mc{{W|H8!`vP-|sS>?8N``KCR-aWeKIP+D4v=IM>JqM-t>DF5-DcMcv6x&z* z>8(e0S^skf5ssTu?|ioNH=N+waDJQRggH-V&amQt_tV(i`C5ba1l!PwMuh@VE9aiE zFE!+Lz3-%I>3FZ=n*ZJQ-D->Ghl$DuYU~xy&$=GAXtwtKl|O!d+?wlmk7?DdQr3p= zns2gKt}64p`h2!+sABuG?iZPhSGApg|cH6G&S+jXGS(H|-@(q?w-=VVp z&fO9`D`{3K8CBd)5FEyHleto&& zU#%e9oc)@z_6#3go%ssq=?dgon(ncg>tOx2uOcJJ|L^Xwd25bFO8=W?P#*5h?f1p@ z-}`_{m#Ow2gw~(ExAIiF!n3^xLIXoRm#vzX{yqMcXlQP5sJZ4VjTYCrk!q`U$uC}a zd2(>%PQLYiYD-sf+1gHbUlHS$m>cr7Y+gmcDqV&HN{d#l><(edF%Aj+arTYlRqmCm zLS~w9E?g0OE3s;yz*e?{uU4+Q+Wz6q*P!2P{NA20NURCiDm^84=k=$%FE3kl^1jfe z_@{zCyH2w^*z{I~nAS>}y5I3mUwpLZ$&ZLjIV|Fb^!=9!-kA}kb19wuWp3C0+^khv zU$%VeIC8{MURtkshxgX0^W`ToZu1FUU;l0E_kUOK@BbaXzv5#|=zNIWp8p@bpSu!JJpK%5k_toN1>HSsdtF!LMT-|bm zC$#tR9z~v&aV?XkK0C$t{bXqF+08naB;xwAruO=V=WSTD>M3)6;8i7~yH?$+FS9$8 zEa-S&7Jl`X`^Kv43&XEYeiW>G_^_+Q?q}<_txXGEYtv|B)4yubD&AFDmB*LcueP}w zv^CWHslA>{s@RHEYZ(N(ZL1{i1oH2HzN$*ZC9K_}ca`5fHtB0$x35?wdBH!}@2aHY z!4+BzI#VtFWs7D71WQglCCQvtl(1#PE+gMyzR>GymS(axyouf;W~cLIQDEqNUvcdV zuQ@wrq*@(_Ek1jTi=i}huA=#Gy*Gu;+U@>LKlaFqXG%Xz`6JS4HM!@B1cRS^lrFn+^{t~!;)fcn zSFZA~a17n<96G=9nfw25x9@N34y}Fo{@=r$`E}|mUVT0P$1ODUb7|<~Kg&yELno>W zJhSXQcF^eVg8f~~+Z_LF{&>SRG4-o*cR?zLxHqTSon%p-zBE%&R>3{#!HO7>3m))_o1%R^5x=6#&* zHl4p=x9rCo-7iaiI#mA5>pHbsFxznH%Y=YE${$lQV)a_nw5NZbb4V!p=3;OA^DnKV zZ5Ca4Ufs;Ns%zD?ir2UA{p;ym{_h93JoltkwqG}|zbeddYVDFaVap;{y$NGwFwlN` zsrIRP%IcHB^YYIx|`%2jiNuZsA)f|>{cp$(@)z*Rg0r1lQD+PX@M6IACjG^|>* z3dC6PYV&pbKlk|mOz;2m$Nk>#$t$!#!Z9(SZ#Sy<-F@@|+$H;YX!-vC8`;lJlD(qLD}A+B=;L{znw+TWU8 zLmAg`)ZIUk(|lQ#ZkNKR@|&PKMdbR;`-!C;of;<(D7KR&f<9?YKR^?8Y{^P*#SJt&>-UJzhC? z(W-v+q$BohVZD={ty;DB+7iZ&!h+=dsK<8}p7l8{{dS?RU;K(F%juzaTMpDtA2=)Ea3I{Kz$pilOS z6=z?s%rt-5SrOpY8ZH{n*3h?P;+3M!r=+d=OZ7GDWlF+MuBgpjb44upP?na?CC-jj zOb4#5SS59TebuT{>;aLC#?Nf7E?Skl>Xn*ntHeTnE*uqx4QFN7#PW-ISJk|G%ao-3 zj$KQho+M+=`B!f0swl(2K%H$axSzDL;d2b2lW$)_1R(#rXFM2dMOo4cR)4LE%()S?RWnDJN7I zAMBanJ$d;Ax4!OzoJp*+RT!SU>t4l_leBJC*;zkMhSE?`tL{}y2h3K!+B#4Bzjx@_ z>!H1$=U*xfb)DxRAur$CoVv@ge)hGO$Ic#477s1$T=k11o8yMpsg0#GnFWl4eUH06 zemQ5Am2CgAlWUgQtPkn=-R^bn{AX{eYoWf=`2;Q>dbCArCUZibSSV|RcZ=h-aE1=! zMKLy4{pX)r9=dc@m2%9p*CpvQ!dMxi7p=N}rYck`zcj5bYvn3VKkdspS6A7t9N{fr8G1vS8-vqEStX-3_U29{rHp2n46{~LfeEA$w&IPkovp=xT zXGBFGF|*I)4_$uF@Wb^tA8#-|=vw{i&b(C$Qu zJ2b!gpS;_7&b)mxW5Q<-<&~$r_GVb+y|B5qcgdf^3z4dezir(Z6z#*gdgTTWb%j-2 z4AF~MW!3C|wNgvoA(i#ajL#w6tG2CNHCse9smt!v42j!yJ-ht;{ZgM=?Xj9UWtG;N zk1=u!izHilwPtRMUX{DTxW(If_tv(W=^=Ap`c{6QdU@@n?vok}H~2zz{}g?nClc^} zv60E^_}L1pSMY|iHoWayRTjB&RsOnF{yYJPzq<;UXf2lTG*|cUe#10%`>jQ*cII_u z{`eRFdu5i^tiaIIhqk5Yyw?&xE9l93BP(<&->u-#syZIzFh9!kz3^)2>Lf_7sE5z_>l~##ZC~HG*(A8|)@PE@+&04=&>bd>W z*Q>g08V%$#O{V>vn->*2=dg*~?iH)NL$104+ZquQSADyixOG!>=$)xrch_p=?X&7% z^{O_~_3xh73>((XC=D&Ij#*R|{dQxd!;QOH8>WXQo&U0$mm#4UG`6a@?Uik*(MPFO zb1&Uo6?An+`c$2;m0oWgqw)_)e|R~$T{zbH&exL7p5?8q4ZX+Thi%oEQswqBbZWR+ zw(0C0Zk1DiZ(?GI5e*Ifz0$7sp~2^n?o-jZA)$MFvmm|Wt;c>on`~XYV%4SlFCXhL zGKBihkJ~$Gap2)#)&|v$#uWtxpMMpFgdWX)J@vI4{~{&zGH!+f){w1I{%=J>Yi$IT z{~2z`nqm?j`gW@t?}KXwDm)T*LzX?Qmy?yMEAv`{AyfGmY+_0~Q@P4D^mfQq-!3bz#6b1*&QcEIu3UBL!xKTR>46c_p?l}5%T39Wel_LRa~HGH?CMR|s-~?7xKr_F&#Ta|p#L|n zXqN|14OpGoR9N5O9TvKDxl&@u_UaH*`S1Rrp=~)+Pj^iL)hyez5Df$e-uvQ?7c%N@ z1<#e5HF>#fS>vhb+`y|bZ=6mT|9dSIx^;!)s#k$ek3A0yotPh>c|l_n!v?8P-{)q! zE}@^_G_kYm|Gvu5mpYGO6&FLeEzV*i>x-rA5~Nb&WJ0ZlvdWI`Rb_q*0#m1`dWVW$ zlF8rW%;Ye8)v{J?CGQH+2a}3Ik1h%{WOVR(cwN1E)v6VnW4Ib(LK$`(T2;07`KkXw zD7_>#{@!Co%U(QFZ%zDy(MQraeMMyRTqmo8CEyaobMB`@A2VjnTeD@J3d5DWJIh#Z zNKHD^{w+eEVU23hqU-bRnZ=y9P2E*o~|g1WMp7iw*^a4vi@FP z=-JiTj0eJkdo$LVoH@B`6+?k*Xer;e@?_AojTG~0*MQ>IRj2Yo!99)@S`0B3SGX7& zR_R59t9@vh;SlNxZXhr~W{4OZLVvGZ6_p&iHtK5Tb}dL-B5c{Jz2BG|z}gaASKTUa zzj`V!v@m>C$@Wz{e!j9Wg*vJ5{TU(AY7t+Wc+Gne*!VE(nN zM&@IE!FRW_Uax&OTZ%EnsD{qH9V}Xuv9DvE*{ZA^cPehwC5K#fk$JrJ)&nOl$7d7o zDY#BB3e$UY*5Ya1v#nt!SG}X{!b4+^ZC|?9>Q(8R8jYFT*J)Xv-!<`zZ%opy&gr+W zAIp1vEc4g9e4Dj48`BvgB+cLNdo?#Gdf8{!$7}9}e7*59P2#M-^O99{ulJcp3&**d zGccINgudIE0 zGU|2YBB#Q~8$YiKkM#VT9K8OHZ>ZDSWt_+UGU`Q!PMz1)a`EoFz^gTP_M6RGe>Yr( z;e|s^5L+l~gSLF=+f6~C_haBANhbDhSNiduJ$YGax5Lx5+g4=hl_@@v{9oF+D(Z?t z=+_lRkBe8YI$^#-Bts;UA)#8hmh9gP+ za`QUZTyP3qeEy}v(!i@HFDD${^-nC+m+kdoNyUS)AzO=?8dfaPiCnd6!n2CUvO)~E zLQHjI1S1cvW|%%@wU*nHWTu9)YZ7I)@0PDJ|6Z2&?C{@H<=RT#>$DhR3`6%`D}GwP za@EgWs|x=G?^?I&gfPeCcDH27;F8ai4;lQrS@CAkD!sr^`9xmE=+60JrBhO~x^DU@ zf<|5Zp9fxD;#c{w!o=4?Y)sV>8ftW|<% zr?y!}hKn++Te0fg!EbqMx>hkcBqwa;$XXW=3Tm-HCY2kw+oKp60my!t6K`!;V+0W>sd1M}M7XHM4^Es^80; z(3M$tHhYP!4!OF=XXWl|utv+K#FuQ7-*Is>NS|LcJ>YCv^wywi=hq+Z8O>s5hzKUP zENMDC$0;;)&$aNn&+k_Azq?n^7`iQxwPE$TRaYyrmalmAxKrX|e`Dz4B|BGTtvAhN z*xsg?c;Lk{Bi;X>UtG8`+j`mI+iHvsTZ{Bo@3Q}-damvFv2T7QQ^QUldV24YOYOHa z{|c;Rq2m_C@n09eYuoa0i}%5`{C|6Ae9H8^K5bn}hShStGx>W~YU=n&zCt$T%AOC-f0q5}lYeh-mZY_K)j~PR zGFFBiO|);QByG4Hu}pfF`MF!Zp{G@@Tyfd^ugkGMQk~&|Xb64UCQqj%#neICCgSQx zRkT7EmM4LF9)=V*O@ckd7p*$UvueinF3FjX4sfWou091_I#1Hi|3Ca4_y4&vTCtT zaPXNju9qyAFIHIfuTm>L#eIBnX4R%kRg)M3b{EbTO33ywlE0O_mtn)S4$ohOyjLvN zdY#)U#bf0fy7lg_%+PmR*M3g3oXE}a;MJ;ErkmrYo{FA3bAHsStftGSOuWCodK-3i z&n_{B9Mh|A<%YuVixGA6vCTi@}5~tXuGBDyJ%F=wekDXe89(jW9!k za46n>54nRD;Q3GOt)-#Sg3%kw*4pdJmmdhqUh{1YFGE5x&OXno%9%msYt0{AR_9mW z)s}Mj60h1_Q85Oyd9L~kwaTOSE}U!f?!>KxV>w&77{UWXuhy;dkGD8ub9K?DFzL|H z{KZnXrlwb1Lf01V`}yRY%&Jvi%70mSGdP4^ULL;wNyZU7R)*E7=^GxrUA$x!TVn63 zDC5VUgcusmhF#6F*%}=3^`lGAkK+ec1zw5?-FkhNNkjDE2?hxz!851*uPn)Ub5<5( zOe48keV5nj)Q3g+nTzbI)9Nke^6}>`-o+VzVCVW@f#uG(3T`cZaIO8Ho6pZJOR~Mg zjZEeSi$61u3yCfXjW05@x%fSL`o+H$k2ROA(oX!$FuSEEqpR>Iv-*@vMu%S~OncV4 z>Y&WBKYhO)uNHoH^9{ZF`ryI4;hT+e`dAslJwu;=3u%>^rN3x-?r_jK^Bs6iU)-Fbd4IfvnI`)0_yj7nVL&6U9So&{Wku`hOF3&)BMV(hqbONvbm8h9B zZ_cSxr4^+{nxUam^K6`+8gXSWUbX%6k>;RW=ea?@=bTuUm+OBm>b#I>mvsN!@V%$J zUdhj{dYZRND9hB>;2nR#$yKYqgsAkqE9+nNtoes==+;R*4Xc1DQ4dTgdXZ zXHPOG#xD3279C9vP|A-5&$vRT-d)AO5b6pV)Z9_9LX?3aGtvh_XRYAkao&tuseN|$b1m!(}B z=EQ5Aa8>;0{g40Wlqlrw<6_uwlCm~PT=L~pzDM2GTtBrpf|0?@kJz&0MpdY-%zWPO zul$`i;M4DwW?z6`aKga?ppQkUU6HLENRWis&7$~*$T2HgxGrWw03{8@8|2?yEEBpPp%L{i1zbMt9~oTJH4K@4b-`rdbeO_ zc|4h&8(o$!)7EcWw11N~!v?D>47Czj*Jm<3t0*XVpc3R}e)zS*;%BY$kIbJQZuqxR z&{r~at(#};&xECpp-Z1JG2~2Jb?)s-E=!Ym7k}x{&{Na6dBYa3QhOw^{wkYz5QkC! zmt$&8Q#Ka$mtO#loLpUrb>t+j%|7}55!GdLD|XiA)@)I&(|Mey?1Lw( zb=smdli$xuVQ4rV82WTdlG^3G?<=zMraeme5+0jqwqQQb$J;AotC<7A-5pWF-JM*t z?v8k1=xn`!Q!A!kX}c585Yf5nlurZe$}FSA)e;xZFDssTV^v9Th$zE4zjaye{=CKW zjyQ#+HLkkF#jx?l;`VeU?JWUUUldz;WQLS}GP$u~-G0~5$p?QGxOo(ahrXS|prEDc zJ#CfN63crP?JNzuR+*hWo;7a)8^h`|p`zXaM_CvId9SMfUb$+Uzu{V~=z6bz*&b23 zfzb>NyjX{0D>F={8M>O=Yw|3f-+Nqd)hnUUuY%VEHcb7I8S4HrMcL3(dzrA0`{S23 zt7cu%)R*aB_VT3HYfmPJx5sk58rCYFtjXyA%5)$~sn=jlBU0z*q{CO^rEjvMpP$WI zx60b*>^j|8er*PZ1It!pZ^F2K5Mo#ray>NmOVaAv#Mn@V9bBud*l+LN2r8m`8?P#9 ze<^|&L5vK)TItgRQredAHmW|#?p?#xZLL=m-ZS+wF|27^l{W9z(XhSC{nX-|w+359 zhpv+PzGl)4;zMC>}aWcMMa1IISMPz`ySx7vKm&7~OZI#7s>451BTqhXcsqO6bWI_KCI|P>RDNBC8$8IvEUTvIic76=3-vu> z7`K{NZ;3#P+{<2H7R_YX{LSiM=={z7Y1>|{xW4i8!jyZvRz2CnQ-5qnbW_j%X`(!`k1hM+3A|-^5PlVJNU%wdzekN)xz=^Z1`}=vGTfg_HhQ zE7vveRk3FbWo&dXuSJLt7H10@fS1S(B}!&=3%a(j0+4mM7d~R_lJ+aFf^ql*~-@9{jwej|c zcXubrU*E9&b*bW}GHT-RVw0T*9m8*MKt=b;gJ8za$)}mF{ zEbiA7rSpY`{<5x}qsox8ca>b<`L^F*)jNMP#mHGVUlJEzx@w{{JAc=V49&%%p?9Ti zc2qCkna0pi8iK!vb#p4#9#+)#EpO-IST*^4-z)dKyqSkHr#D5*|B^O*dU?`1-Pn^C zO8jDH+^-1Cy%<`1^5zGZ`}v9sw%2SG{W~?5so|=k^Hi&EnSJc+?0Q$UM2+|Goyv&& z!B`t?*Y~4(|C@xRS6Ld^4Sz_jN&=Na9CR*){LCL`)Cv6#`Ko@;()fEw_xptFB?roU zUafqg%W&Y=D(s6(WLr0^n7r8~^n3D$!m1)I?duP(o?H?VnpyFQW9n&*HNC6uofGEw z+R9scieo8`G2cxRSxbBNW=~>d&~p!+D%&OT9MlrBdlxUg?D{LsBUgT9ls1J=xg~A2 zzf}LEze6ZvLh<5Nv0Zw0=({IscwtS_6t{ZU$#b(z&ma_gj96Ml0uXa`;`v8X$^>eiirXfFp^l|?-#xZOj}NgZBy z{BOwDXZOyXt=SR(Gw<`26(&Dk(WyYHj`(Qew|Y|XTDE4tz|iG0q6!`ht#UMcyhpoO zJHF(#2v}4s_ex{{u}r?3AA25CiLnC)v0$rn*LU2Xz&dP z-8%o(WpO@Z|E(+bTy+b*dV7VNzb~(8U}*N7e7l{-?W?r@&b2!y#IP+cl>d18;lIBo zAE{;3>!0hG*1{cfHOSm`G5hyjD_`9^a5_)vAOpkeHTXw~H)&%XCEl_w^S1TH(5Rcd z)2qLWe!Xe@`|!(>iVW$izCW1G)n4u2C4H&wvL5SpyD#QRr)m@a3Fc2KzrQ zy0vKauSuI9cJ90Heh-?LEB<7Hb|ik z`j~+ReX92~ze|tHUhB7a%hTe}tEn~7w^l8VJASTxQswJalRg{$k^HTuXZZHW>9^UB z7wdjZF4Wh2c5a=^1IdKu0OpTMX)j$bAVz#nruNj%3al&NStsi?OMJI)U})*imkn=c z=%`h3Gi=yLr!HD*yOJ>a{B}dvDm6}K^DjB;soYB94!ml!`@zA3r|Zi8Z#*NMG0Q@< zdG`t}hMcl>)b6aUcI0&L3I6f*}vmbwLtt_R{^aAy-vby;5GIn4taf@~XZ|C*6`Jh54w@ z=sR|~GQ@OcaGZsl@8!u;uT5rYxYc`m3PZH>q@Ne$Ub8lAb?Mvrn=|NmQB~cXY*UGn zu2oh?MVe+yr_U~Lv)dt+cjNWnIl5sC3=O?F=Bv6Ms4|4C)OtMdt)=yEX9wo#J^jA# zRpYJ}*;Nc?V%yiPx+k8s!F+ekPFF2ZiFXw10^6mlo~3%--FmOVf4wV{4z-XYkr6S z)rQu`p&+M4i$8^r|7@LfGqQKptO+T5!d6FmC<+9I<~BMh?cHm-ycbl$>@`T~NLw}Q zdT_Rqr$_JiN7j)$k9;{e_l)w9P4h2RIY&RgxX_hFoI!8y?DF`poy&tlr!JZmu-ZHM z?BZ3wYL-XnFdQ($(XeT?SbBY{OQ@>`aMVp&DhM!usZx|!qTgt1>Or*?L}&~yz4)u0NVYKThw(4 zK3sg=_wCAcOFA;X1zw%ux?ue(vC~s7PP3HR9hNnHiRRja%Y{F>hBAT{d=-WMULQF1 zEVc>j#|yUcxk-i2wc#~e^Ey8;RG86sdGtzSr>5O2vL>#cwM=`8@03$3R?j_VQTTL{ zQ>d%jfio-&A)*PFi$ZUQPK^m=a0pFb%WxqZeSSK)$L(>#%)ATn=M1edGX0VO_^tr| z=K)tE7HZ5idzkLK)RM<&Qq=3vfU7h31UIGaZ4jF&v_k7Zljp5Yqz{^+T9{7WsJ z-jo%vGTh)Ie$tt>p)@7^0q>`0cf+Ue;1vaJLSBNu?eHn&|K}GUer-Lx@xN#P?AP3( z&@tUdIXl*$?)NX58ispBW%I+7ANT$TuL&+cu=-m;j`mId@9M8Uy6L_D68V4qKC5~m z2D2#`%U?NeZ=6MV`Rl33rLUd_hQ3|k{xRxpkz%XEkNMwh@+Uu=wC7X0@x?pm_n6&S zt~-C#sx`;wavplM=KHqdfbyU(j&Z4{SYGq8)hyY1ds?`-S<5uW1Y=4T!j_60T6FG` zP-t(U=hD38n~G%P=K6SridI$W^#|fh{VE}{EY zzx(8KIaQ50l9wSoI+T0=oxSR;SAMVHIs5Cn+6k>J=TOFk-5B}WR<}vdCesgjSJR^x zUcc(!u3WXQW`|eIy*b(0OD#Pa96}kl#fC0z{uXj|hD`!5s70-NF7)k-m5JvjM|7Oh z2?&j5R1mBF^1&yiRcw`1vGdlql8CHrykP#VIGNDvparp;Ss0>E-i#VQVZU!|VCa;Qnz4O!lkgGMZS1tZ)#)gMJ;cT(=TwJ)p z$9&Z~8AF~&+16VEL#MA;)xV*wVeJwB)mEnt%}kmWB(Z*e-?7VD6n?K&|+2mc$8PMHwFTXo&lNy}bNWX6VXQ_c*5iw7M&~ER^xUG%URf z&}2@6cf`eAs~8w=FJD!B;Mgh#hSWP#Kyy5xa*hEMLZFTWj8mL9{!O1B^6$;R zE5vX@03>@OD>QW8ujlc5YrlP+KCkC{^-a)lEdv9CcgWQTE2muwi?90M4p{{sv2|72 zyr@;Lp3koje9Qg8`uzSD$TZNakgZ>??EkSj`uyJKx&MF7l;2wOZfAe{-LTc$qL3D+ ztgTGh^*E$Hv^Tf)?HWCoeUC*L9MZp(t-Q$=a{aV!(BG2bgyUC#PN_(FP@^q!m9Z*RZ4 zef>gj760>J3?lCzf86u>>$#2UtyP~MG1pwYrS~NyF*`K$>|(A-R)3G3uKzrJ|A%Mg z%l^OUe{cKem3{4>Vy@Mz_W%6T9qMZWUK%skhIiYlFNW_TRl9X#LPHl{3;6n4{Z{AX zxqjMP@)B3A26N5%JFoARSper@0@zkjj!7I7?l$==+k zv0#tcwaGIl+2OCLXY=l8B-WB99wC+4QHH&+yY~U4R^QHebovV_$B&uP0vEE)d7AArHa2d-c?+ZWwN8S z$MhX<)v7bD^C$I4rYmiY4!$ZUrXhE|@x#BL`2~!tZarpJn0Cgd!c`qfBW{YC!-I) zyjgJHOeL;8d->so`&RY5S=Dy#oaHo=8Ua+{)6~uxiz=1()p}uW<`C^_u1CmSek0%D-#Hs*Z)zoNTn*{@2d@TOq!V zEpU1M2@buR>lmUx$YX`&&9{$wEI+r*!|KAaRd%x1_Uj*N_-wxP zF}uRPj1!9IHnSemZGS%D*y-flhmx<_)xKWYpM7=m_p(#bVz;uS*REXUGtW<0Zj-s5 z+G>VXw{}H`B5$gV{qgTbjGWt#NrvU=ji#ZZO)q2(vv1wXTDGciS_n_QRkO&$px^J^ zGv_&MxGK@THMPZdwqECr+zgLCb4TiI#;dliz(}6!2dx z7wS8|t$xzXd1{j{HiaEKJ}FIkhd|xel%T2aBEIfjy)x_5wtFkwLOt0WLiJayx^Dmb zR`vf^@9+Oz9lxhy-70^c9q}iH->zDf*_XL+)xyA)t5!`}@7{OCJv4XoNeRQVNh|D1 zq@-3IEes58c)RHEl20E>?-_<~{TN-dZPmB4p}yT`1Fl*ekUccvm8(W%=DIfp^JA`F zvpKEQ`|#|H^YIYT8dxqkEcc`DF(I?FDqqLef_{fXR{kg(QH%)l{zgBB0{IxUKi2cBhv^if( z^_(`ZI}pLrV0?C}B}3*U28Nu_V_8A?4K1s@}ibWygRSXaMmm3OL^4n)gd~!X5C5f4ShOiNlMhz zm{ny3@2^_Sik}&#TFlV$s`Mwrj@yF$duRBmhu!d97JApm*zvSy#Y4HHYt~yduc``q z#!#Vsb^H8qx%2>Dt?O->p)0gjRWXLvV&8E)cTtH~gUB`2Jk?a!33pd9Bs>m^n%&l> zed$^zOU=bhtlMsNiqAA={#)_NH8iy7@4x106Ia?Yae$55=XG#PudaKyvtQePYe?=^r2RR!4hkN1TgDxH zb;shXDVM@SAB(O3T%_@B$1a6D|23_)@(d9MN!jun83Ia;<#t8}=4#HbslS-gzv!0H zr=MlB3bU8qn)NxU{@kf;q2ARxFU>YTE%SPLEc~X{s^h-5!%Rb-Zf97V%XvF_=J|8g znx=VcOs}&m{IxLM*Ux)GHeTG}XXcukKW2%pt6JB7*roV=_r+DKo&~ac&aHd=bpOxO z@fDw~FV}xL{#~x_>wLR^maU;z@7Mf0x{6iGzx31c8K720h$*O55$hBZ`hMY4>z^+k zUY9d3eVid88nADl!P`}<-fZ5?wR+Z@rcDeR+9XVS?l)PpUySNns{MKI-T0}u*IVB` z`B&|>`PPhI2NM*yG`4qqO}W1^ZT&g+?`-^!`o8ToS@D1J&fSx{o!(5XvRGI8_))Xt z-7cx=|8u7BKW=)a81sfrf8DBDJBCd=mpFZ1r+dLp{Ext{mA7-A=KlV_`uyx2Z+fEx zuU>Tvb+!rhT=nby@%vx*3HXQB?0dHI7SmFuV+pIk%k0`XAR zhNZRBm;bJGv((;yC|~XO3Ge+U>vI0$>{{aCna!xr>bhFCoVPdsZg@Urv!3~ix5u}( z?$R_aR&D>c3;zGT%2E52Q|RVA4Rc=8KhrAq%DZm9SF)qP zM#eAp^+NMS=f6rl+Pi!C#Tw@L6SJ1c)7_vgY_NilJz(<7#fOI_xZ?VHQO{uWnO%1^P)oagp$Th}C`J9Xs=r_cN_nKk>?*S()g)%JEt z>g@Wr=aW*gTby+K?B8eeuC>m2{PdIIzL@$YU$@&``TXF)fqK5r+k^IW{;QjArLpnq zs;r!^wOqfWR;`*F{Pky=f9Q+Ezli3^<%e%oie|cV?FDT(U%Hv?t#DYnuJ4r%?_Zg7 zt?*0Rx%u+(cgHtL_XdV)&Z@k8i*>JNR{0lo=cmTmC$8>!={9Tes(q^~``*{Rm19ik zG+Zt@@$}tlC)raKK4;sv2!tq^8_g~bTs5oZZ;v_4a?5jVZ;b0#y-4`VHkUm@@a4)? zx`7+_I)0gYVcq_%K6idF01roB3{ zYwfZU!I=kTHuGuaXRp0$vwZ2p%NcSD&T4VqlCtA`DLvh8=HpMfQ}cZ%FMED<*<s>?B--bYkS_jQKxTtTGH**p_SR5t_Su zVo+%Q(M#_PkA27zdN=hu2ZMIss%3gXoEy#tgg!Li%sxwh$tpFQNU5N;ewpnre>z>s z+Pve}>a4GdN3uWPDBxM}Z09`Fc+Ont@gbdiRom425-!EsF>DSAy+3P4!t=$omqeZl z`^|gXtFmg=t~9GwZ5I8>>iYLN0`FND{+xKaI&}Jv8m_r{yUx7!u%Vr3pAY@o$@pFRQ1!J-DNGJhv*#>a z)!KeF)bz>Pu-zBqLxcN$QZLR((q&u_8Y-Qy5*+$= z^;pBBoY1$kS4Z*aZC{xs^MEhW<2B_g zx>t!!e0eQ0X09DW?y6UN_q=?sw7TDjQDJRj+bS{nRgc_`EIu(m>vO#OqHy0;T5=t^ zi%%HRM>*x4s*mY7#k1*p7=yskcO8PC z+bo@p7!P#EPGShSG4J2?oO_c(t{xY*fA@cmf7FVy#df7$!@Lfc3gOAu|O^wq&z*D+i$%9(YncK3>`Z4r%e{th=B zkWM2pR9EY}KD}Od%Btyi6OM+T`okspzQ=P;Vs4{Kt2v+E^~#qK=czwFtHSF1w4&P=cSlE43N?(T@I;{V>s&-?wXylGY3|1GU{a_#SM>+ zOkAdTWtm`TqSo70QJfn>L$+@7$XZuk*m7&8OVRq>nKP4i*jrvUT5Gre@~xPqNf)m@ zVawj9^!!Ci@{7Wiw+`+NZ(Tk0@~RZRh6&sB%MJ0R=U6l+_E~FD{T5+>(}Z# zYrCc{VOZepm3{d_f$J@+-UfZE-o$%bTg=q_p{JTKG5>%2dT#0J6zwfJH@kTkull@V z)stU;*>yi&DdUbgbZk}8oZ8sX(uK2g7#SS08McaLv~VvEb}ro|w`MV@W9a+wis;I$ zGdwfwpBLR+rSI+?rTl~ZVG>&{i(?^Wbw85kHE zL|42j-pm&QK9-VUhtR5D55Lzv*kAMHx&5bm^IgEpSrU3fLMvaH$N%{9-TvEy_5a^q z^oa(auEMaOb^D&Dy6@kVoe2XC?aV|OoO%18gFAM?m9Nh~9w|>Xnwfld4R_vGllT8v zdHJ9JsZr(LaZgA(z4PDczgw#Enzr^VO+Ol!-u~Ir z>Xv(X*fzy!AFupi*&=W(H{mhYrpS$<%CVono!s#8q|V#9b3fkun$f-X+&YfBYPWAY z85t(5`sG+$;~-=Iu>bq)6>hbKMuyl;P3Bep}-ljBjN%&cGBf$#pD zyO;MrptWk*;e{3KPlfqRL#*cScl_Bqqdakizu)oyuh*2D{jOi~X+@%JfVE*;Vf|Fj z1LqtV7{tS_?z9bE*#4C}^y|gTYN30TU5;}G%lUtb|Nm=stX04UuEf%B)lpX-xSp!n zx_WZtyEk7p{@(b;E&0t`gNswPWab(NoqlC>Jv${xmW%~BLn}4}p%6nRTDF1M&Lhq7QcXe*g5M)qT@k;;yC;k6{Z)Yq-KB++> zdOcFbEi5JJx_agLuR09Vv=Xc?KEK1=t2w{SzdgKnZP>1ho}r(Y2|wqyDzfly7fhmgZ0cm4#8MkDbb51KP4x)3vr!Y ztJlBqTwQv4&59$rznFen&vpyVf13F0M%YugOZ@()t)utIZgoGK?;Ik^knnc#s`YmC?>^`Oq#=6v06uT;<2g}XzSJpG)yYEE1@xSGw?;#o6~;lip_z2=iRdpYjz zT-~)HX1dGC#S=NWmT5}H7Kcg;Gf%qHqr#~0_7zX)S=%+5wp+d(KipHk?XC0FYm-kb zs!0F6BCGg9$uaBbKY~swpz`6y6&8lf)y2Byb%(rUk3vl(w={w0@ASu6+ z$)T=4wm9@Dv%lMcV*g1;wdS6`H8pF7%38Bkt9+PN+DtfHDAf7oy~p+PZN8yLh5hpO zdz^otfk{ll&1%tp3k^*6$8WSv!PqJ-O6Weh|~VBKKb?L(ojSvzr#%W zNv@p0`DLM^8}%$zW>xs#lhnVKYJNy#t;CV_KC4%Cq}i?2DpNbRDQl(T$!$4%Cf3Zb z*kUc)zsLGmuvAMKd&%-?W#rnr_$y<6~3wN7QIYhO}NTb&2J104AN^>olf|8@Z8ly z>Ou?*3<|-a)o(hJw_D6vg>)41!;i}L#}2~4#%b+gSIhUkj(vT``rglTdVjWm{;YME zTc^{se$Q#;niF<^U;2NpmttpUXFs0QUw?Gtf@I^6uUt=7{hR;)`2V=2)r>`<;vB0^ zfy`?JAM%+KI+t@*7sN);I;B-s{QuAY|63n>K_qiGSVyi;KhUetMR&h2E75{d<7DzNp~+y^|*o+nXFedAR-iyIQZgE}@nd78Vu( zp&?%RGxy@qq`%cs-re_a%htNZzU%I1IH^8bI!$`K9STk`JD8}Ix*ACJ}R z@s)l$H+Q}(Lc39D=+WS*%k94J``&K+>Z`JFv}@@4J*%|*|DIp#K6&k;Ro=FCzgqKa zzW0Wk?d?pJS--&Fyy>8dCYMoPPu8pa6X7Xz8 zt&9FX+_Gt<)vBtUkN+vo`<1=_+iR`Ahxdi)U+Gue7Il{8#oAS`!mq8-H~kxZR_67m zx8hb;mU_R6{=J*~b=_t5eTP>UVipl)e+r4jJ z=5|+pkdRvp^+?C-X?u2sjX-+$`%{{QpSG3om+O4)1c72|B) zE#H6OZ|qjP58eTxSC{-sE(+WHtlmK}qWgF7hR3^QxKFn4WLtIXss8G|Hu3SLq(m>E?#B-{eAua@AdMbdvC4!_2J=kCyA@CUar0U`?q~^ z{GG7+)i>%xH?I*B2z~p_Q*8dfAJ^wvPW&g4E&R1@fy1BWuB{W(zV7?Qy>p}eyOy0V zdd>gHo_h3gzSdsxxf9=RyH}?(Ln}*4=hVEPllCvnSrFTD`)jXesi>^Rd}ql}-}lzF zCq6Cz9}%bYcrCBL_4MHXAG+CRncOK*e-ygi;jxeZTcMk4_KPoM{y6i8-fd|Qd#{&o zrvzR-*6*jbe4+8r|A$U8Yu=yu?fKrA(A>SP;d8FO+<&R2S2omi|LQl_W4}#Y^Y`59 zp5Id*OWo9O`;ev`uHf2b+xSQV$1wWvh3h4{V?UjLHcUf=fnk>9>kF&`dti-%qf-^IFalKz%G_D{{@h2D7W=X-1)dMMzk z;akb=_m`~txqWHPiPN%^_%szyR?p;GS;03`#xr)sKfABbPq&NaZ>~{3b?cMy*W=Sp zh991L<$lA?`9(jE-+D74p)mSkyz}(eKi``?Av<94rDRrce)_Rkw_<=bCQzVl^nioKR`NND8C_kZub*YpkCwkm0L z)}8;)|NZ^H!scstyiMJ=U%RVUtO^TSzWi9^+3e6acie+Y89ztum5>(i(Ri)+oOMOk2*>);7}ik@J2%cW3Zadl{)q zx1WVy{Zbp>v}#**RDbk@Y4+1sO*_B7hT$o5wyyF~lfP3!ti!8Wa^)v|nY;eatd%uE z`>g%DY7ZCu?)kAQAawn9Kb`%vPvosRwqL06^!sBDtInu+FwO2=CB=Jv{tB~u)2_}k z{kl-aN?OJ0Qk;Ed<|aFA)i-F zS@2@#|MfMS&IV^|*oGHSYno%{N?T5avp zPua^JPA=LQ6ROx|yzE}O)@v_u@vEVxr3sa8E_U(r7q0r{>Z9<(CAoj?!8WzS{jR~K zp=*EaGQF{A?b4dJk>R|{ZvFGj`?29nK&a`X|Mq|1z1I@_`Dyz8Kf&k!&*t{(=bAcg z)v7;R7p+o?ZeVFR?Yj2!{nV(d`hPDyFcM<8=OKJ^lKkW8?nX+Y|LcDq(oSqU&)Tz~ z+Q!sReUj3oFX|_AHDXlf{=DQH`uXF&ZMXTi2W`=tUA6f3grd{T)y^sxw_OeNJ?Z~$ znara#Cj&1Rb3fm$#$Zw(@uVTMCf4r4vG1yqhHLl#)jr|pxjZ!Vcv<@DEW0()M?|%M zn!R-2EW_*bPh4-`$0yZS{_J^PofoU_yX}rsRjhxg?b1=^Z=TdY{NZrw-8TF8-2dL+{n-EF)c*&)t8Q(%<9|6RG%`Pnf5Fej(C2y6gy-+G zR^E5>)BpH?ikiXpPkhcxUS74&I)7c3*}VIyf(uG$L*rKAK`d2@n zuNGQ-?LYs@uKho}_g_hk3Z3Dgx;(UXXINoWs7Cs!1*@j-VLdQ+e(rsy2S=^TZ!k3^ zo4Ws0-L+DCVf@CWAH(acU;o;-K68KCU)$XW*?0SVjkx#VRW9R#MXUCInt9&lzLfvg zZBZYu+>|*g%5Yk!m7&QFvAx>uj(T>}T2`(5d@Z8a z@UrfWwX0hD|L?9hzuvmy)w5Kl6{Y|D{rvu2ka^X5%71O&@5QTRKw!nIG}-XT(C4h7 zdw(r}3Tds{wQ$uf{t(g7rw>5DA#{6G==GW9dp^$kvcLJQRF zWna~`O3xv5{kM<*e>MMK4Q_i{SXh|7{_&sDtTs|U@-0g&Xzh%rtDnm{r-UW|Zi*VB diff --git a/doc/qtcreator/images/qtcreator-locator-example.webp b/doc/qtcreator/images/qtcreator-locator-example.webp new file mode 100644 index 0000000000000000000000000000000000000000..3de6d262eb110f3437e6953509e9113a6b9b5fd2 GIT binary patch literal 10848 zcmWIYbaRW)Vqge&bqWXzu<-HGVqnm}c_@e>De%s=Ug!7r-@g9p>)=$Fn0xZx?U@I< z&YZZn+cvs-`@_iHi=E$#Sw~quz5nupx(iQwnWJ0az5o9wJjuy?v~l-Zr$6Qd;c}xBnAeSS@JiwO?^8nx8>%x+|Mcb z=C?u0e(`taD!WgL$qQ+hjJdU^b>H8ls%?MwN}I=3%{)JW-@twIsdK5*@7+$hJ>%V? zQif&Ux1Bk)cYV;zbw4?L$|F;!FP(7j^!wWT&%ghB_5aU#5p$)GIc1ml14TOHoGV`CJx3keG_J!G6~;xW=XgsgXjl)i%g$~&n|3O^yQh7X6vNxKk7$3 z{oOt=t=gQsZpzdG!M!K`KDW3c=KelQ=V|-fRGF{pH&-1Cau2$yqApp#?!odZnIfn4 zkrwCw?ezVjpsAem^R}?h@h*$bdwiF>-(K*1KlNVq^CKBICg{xFbl2R&U&qZ%tvk;3 zf9Az)qT71cN&7yvn)RFG#-<}5owvmEa(i9M&i(!WJ_l1kwqU`fCZ5ad-mPJNxa4yP zW8O~g|G%Qz581rh@$Jcme-gpBwg;vcv?nLN^H^{q;n>ELW(B)HY}Pbcc3i;b)eg7K z5gT_|{Ag~T?Hdxj`l|ioo}f!s_ir|ZS)ZI~npt3MB$K-ORZU;a`rJTm;VB09gWQ+Z zFf@A368|UUYQm5^^`m3g_U%HMDht+0H?Rlh`7mCtgH zZk*1x^RAu0V)Ch2+2sD&D(jn7@)`IoI&LQSvZM*daGzLEb&ne>{hxpR#d!YoUH!lE6B8$=HV7Krk92%~ zmgz<6lb44l+Et`QMpu7t{=C;t>}VPrtMU2m@1BSA&X6)&6MsZXGUVfQw-v7^PM_uw zx+kf0YF1r(gTYmmhf6L`&RxL%YE|LYm3NePO*vCMnb*Oc&BIKzCMDqHlY>G>jwl@K zUwewf#v|Nf!4nhSU6ZL333ZGo~IgJ}SZv!ZlV7cQ%r8Klo!nqI9u z-OByw-{Q%CR#tCwm(y`PGp{{mwbE+k>AxoKDp>L4itevV4Y%wimrh`CXP8ksOYV$e zn~$zTpH|I-4Vh6fzuRKVW^6v}BQ2S6Amq7j_Lf!mE^WPX=}0fn?~58ocw=;W6!xzC zB);WVpB3YWOW`?b0)>0GrS_gNF-pkUyEOXMmz5{iT%H!Uf7_P_Sub_dC4L@#cD>zq z+p4@H!K}aI11w)xy}Pk$<-#jbKR&;yTvfg0Zrn4!f2C8taW*jC(|ERHW#?ag-IM3H z$4ez{yZdfq?ZoMBB}vS#UT%Ord5BDIXUMH@1*QWWsyr5 z6_UH&A33wNddv57tA5@wdRuG4Ap5d0R#v0vxK5*j&(h@wo>#>zW^S2is&Y$xW^97q zv#PE`jH>S6+}@?de9OuRoWZuNZ|$XN-?}v%I!yWc4hgOeoASoiT*=D0xu5NzY%2*=VsL-RSEZNBO;1h3mkFlKi z-sn&fzNvF`9J9`Tv0~8Wx_n~F4WaF9PHS`z7QVOL>D1p9aM#P#PuueD;u4wf8!B~# z^UbHZr39Y*`Aqzobu`1TeS5ub{t?@m@m^y8_04arjMcSH#(wi_b$z?ks4lJggpC0w z|A!C{W)q8Bd7BSw&OOzwH~pAs`R!JnDAk%K4G|}|2*YEmA3W$|`IEncvH#HdefKIm z8_qmkAGf&KSY>m0vlO#|<13z-Q4IV1KD63hpD|Ipn|=B#z1t>VqQ9(qe(Oy~Tjay{ zU)h#DI(FcbVBL=9ITIM;I2#%3GFp9ZhFnhGu2rdhO1ftEBgwh5S&}|p-P+MsW81>2 zbL8)r2^)8^ZZNvF`gK&G#eyelZrYM6n>50gth_ky!?CrQVQ$qi54LK!T|KJ#pjZ0h z>sq5{%O=laEKwG9tdWzwvo=0Dy88Or&#PAPU3R{}*K?MohG*9Q$P4YU*Zg*g+O}*f zQC?QF@Jsb#pKY`BpZQ+AYieEyn+&u;x$ ztFU!(XW-)=ri|}9Jk>TSf1gq*5TnE-$x^QSNLpcLF6W+~G74)nWg?5VEM<-RJ<&B& zYKD}9`0x2AH7Yuu+!LD9@pGQ^#8rukCm$q)%UzXjnD?YYbMp;Rfzw1`}VXMV(HRG)w+n&u@k*tGQn$%s5^gR{y!{ZmH&ujmw{Zv%S3X z5?5#J#wSPT)oki>eskd0OEZ;}fnXRT*oiAnm zD~Kx(-F+bMdSL2_u*DNKP8)}QT({-TlNX}9W1CoR%{jj{ZMv;o@3j?-84i;|%Qp+o zu@L#v+hLoqWp3OnCFyRH$ayO-cVBUHnY}ZxP4Ab%-ux366%YR^otwNT>51a%yxtR` zo0(ny)i@lhmV0_{Tg+R|)~;#gJg1v|N(9f%UY93cw?ZyJ{n)37Dh87UsVk1Hct35w z`1I{1y1|z#ujQ=g)40d2Wy;!f?aLRxm?bjVlaedrkk0b%P@@#b&MQpo9tLnfZe`~vPFiMWyIz`eOX#U>pFdyP{^G!q>pPxu zayd(^%l@7r-M}KIQtRt=OD$o`vrxm_LTlS;?b%(~S+k-}hLrAkFPDQEu7=)sh3sFKSN^=EZZSo;v+h3=mqQBQ^j2LrL)>17NyO!>0e;vidj@YP9b1ycJOf2Fr`pd&wS#{BS!cGzA z$Py#9Y5VOuruE-=q8Qc3swtv(i$|wouBGBM_O%<tiXO3M`n`)<5!NEmuKdlN#VL7WdxoT#O6|g_6E3RNo3EeVE|grk z<456_$A4$ZT%PUsUBUdO+OlV#x%oKFibD3Z$84BrDKk}YpTpAJeAP^luLC zk!e}87F#Ygw(q;TyQ6=$!hHTD-pzN{Nvt^XLSBwlCp?U4+Y-yfeYx^eZ^^rtWSCZe znX#Jj+c(<+^Z#W=se4MFduP_k%r0mAS0H>yU0+LJeGk(#ZS!=`S(97;Se!ZeOz6$x zvu`yYw4GgA%Rf(V>CeJ9FY`szc2qNHMSAiCay@8Qd80C4{l{8<=drrMG~4ar+Y9Qy!@y&IcrzRv*QQvHMVeiZ{P?K3cQhW-`?BK z-f!;~T5eKY9vJOR!wwa*^X02iFvipkF@= zZSH#fHJUAd{9o9zb0KweW`yQ_e!L-e`J6A@^`AVS{Z|QH(azU!zxXke_9I1h^WG@# z6{R|*EozI+QgkgJUc4BQ)%$AJMt5HI_OHih8fdu8Jt*7fDkdD=#gjJY%SpdH@w%7B zb6th53ViH~lbt-beb(IBRj=3H+?jdy%c~hALZH~>@wprs& z2j8S=X~M}%!X6)7Jk9+Do9(SKv%CeWZf`ZdoU*OHy|$29SJL0%M4I7BFC{(g!ld@A zDm~MSK3#HL77@4eczJbh-uGuW-tPT&>hYyhr*6KTw!g?RY1h*ohGu5l&c0u}W{raS zZLViG%JOA4NK~}T*_oAjf0GP;cPsHt;p8W!yPsP(vdbJX{`X|+@$dV})z=Gr%UWEp zP+Mlxp1HnSmH`{{7JLurw76oG9~$!9V1-+T(W77UFJDr(T>N3hQ%7#Uw=0(D_9X>P zby+h>w9TR_KDW50XHJa?$Al)!(wo*1CvD!zZgB~%X}cP_>Zdi|MSf35)-c8 z+HuS9@tWZ26DspQvG(75wsYn4<=c$a`KKwI%iI2J{+>@eRFpp`#6IkpwSVn_NNuKj zck=J8TH)6y?y=5)^98llja*9?fSmB?ir+);Rh?bC0~L2hKb?5_eYykpjbqi?+95Ab zo_)Ku@IZ&PWp(xHigzF33petgWc7(=)sFN#m$J5}zpY%p?u&Bi z!vm9?S!ZY}GWIbnN$DtUv1IFylH+>!Mo%kbCg<}v>&h?ON=>c~J21_qvA_511@2D^ zH>;m{9O1gNXU&|urQTP2^Yy0PYHr76KPx01E9X`c{JU*?{qFx5IKCe0^R~44xw=2!O=J-6(Ooon` zi{=-W=kWh!*xi2Q^oc&npNG|E2R!MEWOAIbtA3R~WAR)Il{K2LPU;@--FwEhynk82 zi66$tz8!Kq?A5YcblJv;j)kjMXgpv3j;E@PLs|7{@2|f_iRqOKRJI;Im3_SDhS2m1 zwU>RJM$f~R?A^SZPo(`qKpgWopIre5IE$5e7z~5I9G+}{?(~m+eH)dV7HVY)Uj37M z&49^KBG^rdDMDYz=v+n2m%Pwmi!;w|#s-|3U2?mA-dU0LO$S%4(0Q(LWq-iG#rNx; zxZLTDlv}N`Rr%YuAJcTKzP^6;bn}ar*7BR*`pVBll+B$fJoSm*?>4yssopw6a)Webc#6le(o#OHa$z9$x%ZpY^nJ z>B7@dTbGobo0nkkvr+ZWrE5#YtxtR3UjJT4BGmt6&!(UE-&g&-G4I*`+q;tA+&;rq ze|r02iHd{Cd}|Bl?wZ8&!Hb>egtPYYbz3r9<*KWnZQov_et%ts+jF(Xh#GBeC8?d# zWv{$6HYjC@-I%{HTr%{b&Eu8U3%vuCwuxqRg&!0Mol@QHeC$hrd z9{hCS^wsa1B~-T-mtEg~@i)&#RmuOH$&Xn3C3o+AzJ2?##;LLo-k!L}tbJ4^bMN}| z^FK$|Z<1{_OFIAVkHFV^%-Ua^ll)FdT#e0GU~Oi0c>bD&Ju{cTOZi&U`hSCF!$#XX zD#AA>{yt{Ip(ohL)3jUcW3Bz|Nj3adWgg)cv10P8+Mo39W?eQ>Gmf=3{GvrkZv-== zxY$+|Wh)P}ux{ywy2v>XTy**m@AQ{j^*t@fWRl&ppPs)@&;I*PF7oboxe0zTxx4QF zVUt->5VPl?RK=_7qWPx6YZk@-wVUhNr@vT!q0S8LbFa)TqyE2Ge*C!h)QQs7ZgSoa zBP0ZFr=M!PwsT+K_j}Qq(?ZlIb0jRD|9+B)=+_^|?dR=UYr_3E^oAdQ_CCuCzaP|h zb*-2o{yoI?jLFZKevzps8_%1_cenH#T@ZdPwNdI~7)z;U0r$O{QiIK2g16@jm(RFu zS!fZ?!TWHB*S(g0BZrl>Vb2@4*!LwcpGfEBlil9XYpCGP%j<8TX{vGLA{y3pF@%n6%-Cn%wWlCf-TArIM$3%ZHx~bY8sZi_+b#=dIag zwp_m~8g0~Xzf+ZA@uW%e%PS`tvS@tqu%7s$$}+`g>yCA{M(LMr=O22nr~R`~zmfd$knGPN0rStUTC~TCi@(Y8(WE=LF@eq?E%8DHqG{U*%(L8~}6^E9;TTuJh&HrNy$$ z6GeRMWL~QuKV9`AwCF>|#usjq*UAN6aC=U=6UY)Jv+AN7n@p(G_0Sh?^;-F^bLG|Z zj!uzx=VN}W8{6{fF2~0j3;pP9%N*Z6JCj%IThUp+edl~w6AZ}HowLV1f$_A|FNvW2_Y$zB{g)%jVtOKfi9d})32-Pwh;Cv@Jf z+r261Q;KCmYwDhf&F;zXj!gKM;obGbs<7U;J%9kHrugN}< z@w4tu=5+VJdfT~d?fE!P&J$x#JuG3`4&rx9k|1_t#4uM9b@Bbi5-D z&C^JTi&5g5A6bwD4w*F3Y^VE%DH+PlrQ&ZaKHO#7dC2(QiGzy`%fC%Ez8t2gt(48T zLG5nl7J=-R%?mXFO3%nviv12K&)T z^6b3KxtnKg@9eM6`M~>SWFu zTu9pW^F;gGn7QWD-}o^UUkRV{n@2L2C5!3PV~e{-&Pjfr9#%I;#jRZ|==E-~z4NYa zcbz?h%f`M>yfa*9*^*C>ml#@YIZ%3gb*Wq%r z9b>t|o}+&Mm$)-djhnVSjN{i9t*T$@mRu{YY_hqtQl>^~!k11}kO~!uZ6RrfKTH%} z2!~WX)V2F{eAyF?1(%L|T2je<*==L9%BZFzdKjj7PWa$!T%3>|+K z+l_iMM?W1gC^&ZQTIn4VQLU9a{*xDMI`zqfJhD?kvlyqbpM7zl`Gok+36u31dVLuVxw|M9%7yhcygSJX)?>ll>~#94>3tFV z(}$TJ&T~tBuVeR<>5xRnl-Zm70;IAJb-eSO_ms2lr+JZkcdN3~>0hSzMeI%=-Y6UC zb%#}7xz+F;gIi#^*6SyWm!A97vj2~?q8uN;?(^$4msvL0@Z4s6q!%HX*<;8aq_E*; zS?d(eY3g5|-Y@y3Bx9zlaw~hErsws-!+ICkI(8>8^dFNbS6C!a(O>%MqS3)mEOUYw z1t)W~`#<%bw*Kcb&xFb&J$wv>9qsW|yN^mJ)l`Tuz2E3>7xhZVzh-*<=A9|l%Oa1h zd%Wyh-ICadz8OzXy48zr{#vujGpX{(=_%r_XFjDkJ`xtq(TcuaxR||S&x)yMKgG=O zI5|0JZH_79=iX~YV)IVS3fufRA;ceJ5k7>rur+iLa(43+JE?YR6r;QXQkjRD{07&mcfS$uqTT$^q0isrbLb0R0+UH@)p<1+cPW_Q!M zf=<btCb&sO3bdp&ID zgrGAEbcK0^RF+QJ^pjWVv~iPa(OynA;k(6$(+zKkpA%mG%<6uI*0ke3+gn(V3M%xU zo#d-z+*ix`*ukLs+_EEG+#mB=j$L?dep@-A^@~G#9Of%Sa z*keInY9+^!#)5BijyC_veN$stC+(E{$}-II?z3Gx*JZoR*7VT)ev*B{5|L0di(JP4 zyXJd7pWbBZnB?d_Eoh5)!um4(HoyLvvEO2Oe%!vJ?sqnK-$kLb{lOcKUlf#j{JHtG zRVdGrDL0w}?l9GznzD)EZ^XA4o*x!fCtr4&zAiGTcz0vf>Dx^n=U$cTOtfT`{LL%Y zyuWz<>5^MpLcSRGys|WB`uLOU#1U)R5T3O;j~+H9PEBK4JasKgq+FL@+BK>5+6wZ)2Ygt>grsWaY0gi z-!aK&oTtT(@_e3RHjUl#TadxV&!(jb+cXr;1P4XVd-K7x@#dle1OJ)Hm7fk@UvfZf z>!!|j?#*5$RbSt2HeHVhnbL!wGWZ0mEM?Ym_qav4O#D4nPCH2R*c}Vi8BZPEt~xth zc6*p`ytyyVh;PZUu8?k(;>S}Qrm=f2TjuFewZ>y9h;Kjbx%-JrGScNeOR97-y6*_} zIZdz;tM|D+$)hyXbip#NMb8$t$xr*#EGn4sr?&d?ncm=k5ptW3AFV3WyddUy`Nm>{ z#+!dO9$c_;-6}SZAHv-II}2}=9+vSlGWY9Du3S){Z_CQy5Pc|6;idzl+S|~pS4w;D zbcyyy2-cdpl$K7~S?DEk`fGnqmw%1HL(;LhbDYqp_mPtya!)bHT zPqt~VR%J1~Ntk^6j)l8?)eVi4cPvsTJbihh{YF~@+x)cBKnd+b@*qWTqO21tJJ{D` z^oFhXGdB0TnO6BHHnewt@%(K{1(x3>Q}gCb<34TtX+r3-ALm{jpCP^c>w!-dJ6Fw` z(qb?#%rn~iu?3suWRP1%}+1J?&>|=!zpsSu;k>f56QJJ zdG*iop6NVYkmAzs50a1B)q7u3_{962{;z#CERxD z`||ZxllJM$&h4K3HE?;OYh8rg%?YiJ`NnD!d_SIA{y+MzPf0~)UxME<_ql3Q<)^X7 z?CLdmk$H?|lef(W?pcBkT)(PAe99^^{Sy4inmP3PtZC=UHuhxYYF|$4_G!>5IWFwj0gX-(z@6+m@?IU45y&ZyI|!M~{<+O}S`E-JAmuRdYYJ{kkFk zm4n+{toQ$^p9g{^x7w_@%2}5l8)0n5A9nTiY)zvVf{#9)WEHKfo73?B6LU?F(~6Fe zE4-yoY^zT0XyQG^{Yu!oPUiO=)-~SQGQ4X1a*A^EV*(~VKhF7G-~NEMs>-+EDOY-@ zKvZ&{PM*D+A%k}#2dXkraJ%W$LT!BWmj{a`c&cdN!aE4?p<#- z+hiR$W*;Uz<>|+%Pufo>Z+LU~hqvA7#Y{O&iKdQ`a`B#ZOeZ3Af9v#%A7B%m$PHFG z?aA>kH8tM@{@cwz81!k%r}LjG7;=u(bt!{or$1?T>wIE-WAWjKKfm(nWUJ13`jPhr z!{ojQ-+*by<0r`{Y1go7haQTQo8Qpu3KyMJydi9A{WN#Z8yS&u;%n42PCwQ^$$v6^ zLrFPz!_$k5W>M3Qvx40I!~2u-CrO>!=%4A8P2Zg4ch)Fpw0~E4ZfDDOx^MCH`f2Jp z#Wve!-HNOgT(iA+{?o}%J$YAq`r6!>@Hh0uM!hFm>jO5&Pq~R2I8SFja%jVG3_emm1DYvOqPq%8WA7V=zEl0W#UUnGZfgN?^&_f;(ga@{gbyb8&oC6Ssp zb^4EYA6%I&lQ74EKlTytYq{#ln?J9z+VgCVQu_Lj6_YiJPVV?FVwpPY>Bka7i!O%8 zM=O7*-jk8#+Z?|B>;Csu>|)PFEZyaQ-P!t^ceC9)TUS5rhNq6xE-*=U3O{$8UZE^B z$zu75hZ@horp$R-xF>pHMWNihdG04PUHPUIZ}{e#nO12N&%<{>wt`{eBO7=5Dv6V( zu6;2dg>?4q4%uuYr_aXTk-oZ9`1!*21)|SIEY%eGZI5_w_;5RlO~*gT!hb{YeE<79 zuOB}zEbp%WQOEy~g}+8%p5uAVqEkGlCtJ@^H;v8T{4xLKV#RAwH;){i`}aC7bks6S zyh`_^>+C1U9EKP8n*ci+Dq^XcHXOZ{cjtE)B~`n-5*+`KiP ze&uZ4F1~#2$A4LC`^~fKcf~&c9DCu{eL4GYPk%m+i?{pt_N%b{J^S~Q?duGJ5XbeM{@78PZg&f>yF;t$!+&^jcbU} z_Px9Q?&aTmw*E)$N6mcQ!usr$?bfGl?m0*Ny{p>jUr}$o%X_sy->V(hY}X_o)jB4T zU|sjkIplfIg+LpZ(6ZZg-|llOU-LS_*Br~Hw~}f);xu}PmU+7Z+mO2owjZ6 z$$iDbC0f=how^?H)b;H)Sh5H6*Is=ld$#V4wZ5N#^76eWe=Cm;XRPoMPTG{VNuYJjRDpX5YZe?#(0H-c^id~|xW)tl-D?~?4(G1S zS$tFA>P;pK?oV>TPR=H?CKNl~+P?a))FyjP-ety`En;t*`&bIL(&5^aqhBV8b*{Mn<%C=7QXV#CkDJ_*KOZ|-IbY$K{(iqk zr0|Wz4c?s(Z+Cm|dG={WZS*$JKWW!Jr|p@S9C`81+~`Pc#q`GZU*|gC8(WJ7-rxB# ztc&A<<^}%6#x7?Ie*WX0Y~p)ftkHJd|5k2h#Fr^TcHA~k zn){AB|9o`J(R|_aDFxSCYs3^kY`o32-*3~LoELZb&d23!i7S?|-OhjVv#0Q*qTcRP z5(a-|K6k##Gq&vTTVBoQDwq8JNYt0IzoAUobvx{Yo^o@?$+qsw?0WF;Zfk2R1R*($F!g6?b`b+-0mfx zVE?!}K|J>OubZorC6$jDXVpy35Br%amiEZ(+__h?@7I?Lew%mIR8=wmz}KaIcJqxN zrpz__e(3t@g&NxXtzy5P{dx1l-OaD-c0PYmbL+kT$FBCctW7(^PTJW%J^BA(@cnIj z|7q|4v~#~r@Q%NSo_^l__LsHa#tW-@Srq1apL4$%o)hqT%IcSz+gCo=fA6iKWlCG` zJqgJT4-#*x|K3pi%~K*?>ubD2>YDh9gY{eAcu8;Eobv6jr_gkUKASHGYMTYzN~+>^ zKGN_0d)jxpkx%Wvp4qighjw<N#=V#(Y*jyLx!j{bapxcKBnk;nR+ E06S|YaR2}S literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-locator-open.png b/doc/qtcreator/images/qtcreator-locator-open.png deleted file mode 100644 index 186cc6504b9560544ed9d3b5e3005ae5ab108ba0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11910 zcmeAS@N?(olHy`uVBq!ia0y~yVD4jJV07nTVqjoMeA_yWfkDsL)5S5Q;?~={zx!pc zC(3{LBmL`O$83ge!5W2^j!dm9s>{^roHD~AbA?&y%IoWtxbmcDv_)?T+scge_VzaAaE zKEL)`N`A=S7oScg_xtuOJeyPdIX~lTU(Al8e>J}z{0rY-{qU-_Sw!JcRpyeF=WN1{ zT@H4ib^N@2>C;2U&FkjvG&|?9SG)SISbnfr_3_UAzu$E}f3|5t|9t-P6Qx>uDQ&9Z z)*p`De)=-%XK7gMLxI)Xa!mi;efan9>G?(M8ELn-99|NkTkPpl9C^ZO(W|@swV7`} zJ=I#W&GPG|rRL%6|Nfo5dU^Tzj#Z1a3~JSO2$|T++h3g5^lR2<$#cfRruoGu&5QX> zX5V>p_QHqdM`y29IWN0!!m?>Ig>QfPYS14g^`8H8#yK;o(C2H4qkSy6er1{7ooF?E zvYt!G-7PDsuB-EhhyM?6p0jJ0RoAN3p&_=VzqYKGrRx)!xm!C@X4@rR&v|*Q&l%{rK_ooQYZT^_$9u4I-^|Y| zg)8Uw?fS^>Z5i{v=5TV(pNg&JeAcc_>*@kUZ(Ojxt#(sIaQUyVr+(xVFRD$d<&v6r zlWqB$Z<>!CCTtNqThYwDUd~Q_-jQ`NnbAkI!@a@{9zW!2o_RQI=g-O?hkx$c;yAys zc9X1qYQ%=a&)q-!MBU7p;j-t^;pOvp1pMDxStZ-qcV&Nn_^Qa`+P*U%d%e($3!7B3 zcM(^PchGd>n!G*NG8MhA-v0aQZR@9${aIqw|E^|Sw=#;l@?c_>;^WeO^QXmoyQQ8j z|M+-uR~OgiWtVb}cbk`NTk7VWaee8Q|NQ@FiR{~R#<9`;v=3AK!m0k|ErLC0jY%PA%cky_cl+%OIh}_>v#dBz**|yL5*qk5 z{@?G!kX+}i*}>Z9=h;;L^50*6SlNA^?f?H)i(Z{Nby;54{d}Oo+Byl_Pak^w?e^8Y z`xx80!s^7z(lpzW4|hI1Pdgm)@yqUqhQ_O2f3UIpW4Y@>*n7QZ_QSd&S6?QS^ZVPL zZIjeb-?4w&@|_P(Tx4T@EgSYD=7-&$nTi%`d7~fw;t@M%kfqhM`Pz>j@h?w#{8AH3 zGNLy9ifnHE{-r|oZ(?kqDNpp`MRhh_>bXoD(J%f@?VYu^gd^D?ddmMzeJj3+-2JDS z!*NTsT>Smr!prm4gl~&n%sb0W;Hcle1+Ax6n^%6_v$4C%nLS%@&#$R!tJoq9JoZL9 z+5Qg+Hh$_lSH7IV_4eMo-LHOWzN`2-?Nrr**Q+$%3$-4azO63$))L_@cTS0ao96kq zFR?tc#-#T?C(HU9Zzkkk-CBKj;)~c91(uN^vTOWy)GjvfZI;*j6C1Jj>0RqJldD{x z&F|QzwMy^LulFJHVP9`a=hwaex_@uU&ri1xez|r#KYmZe$DjYdiid`*{WsTyA>mK4 zsDJpOOo8ajE27R`E<0#f^Ela`zbfUmu9d|EJG)z-kBJ9Q$`*UPR(h`8t-baZTAvD4 z4z4eEd9S!>@`H)oi?j^he{?z8O1S)f$+qJou&?cNEV*`5$>`P6mlt%C{7TVsE>%C6tA^wtYuUE|kv z=cMnb2|bCnx4dxc(3I$(hwcfz=Q&t-eO+~;w`uLkgR9vcEo{QUJ>^V*Q!@BjW7&0N8i z^KS2dVYd0Ky;YX0(rgzjz8rPQTJ+2DFYZ@Yo=aHVwx^!KK`wOjLzYP6Yx_49x_D2! zc6+i^ndo-znWn3bU5~K#7Fss*kwaghOr}}P-WyJe*JVSyy(8j7bjv=TlLBKudRg%_aokbyMr_FqK^{KB+&xNyQC4bB`_ZLjuO<$+Z*IU&W z{_0O~srWtF(yDn@tMZ(bZmn8T_3!_mpZ))iZRD>1d`x3W-@m_`_y0Qh;(od8k6UX3 zO?U0MUm6{n$#5Wp*{1ZLQ}Kh^?@q<{H2E1c$x|t+gz{3dh>HQf=hgV{%L(uH+NShH{0fE>4`hwuN1c46;XG?_#-MTO1^oK6!yazj5B_;8piD*%(-U zTGv>M@G{J>T4mO_W6z40i?S+@pWYslzDVo6Q0t1QsI=!hx|6iyZwVCIR~f9?)_e5f zfeY^#86HM24!YDkJ#ydLRVEAxF%6%^H#JVY%gnGT?rM?}mv-4Rmo2G#SNZS%b25Mb zhr{gq|Ghgew^r$8^x+j!|E!BcdXF>kRQq#p4`uz_lec=8q2xLd`K3R%&MOM(Jr+Oz z#Jx5)a{-xatGRN{bzFTDRJu}JWl!XDmxsqLJlIvEna9S=yzWW)_MY>lZ)a>?cYD>X z>8JC`DqqzIl&o4a=gw>4Snc)k8o9@Qg_rGV`BJv%k5FWV=nmQK1~STlqB{GURV0eS zcdUKYch36Wx+mKUVm;SARNH>5=iQ6FlkVk;^=kTXN3OVcF8sWE-WF#M@9m+!(xHy|Sd&!4mC_BO8Vp{eSYFjufDqV z)Ld`vSC^~yKOX}~H>pSxQ&+q?nZ1ex!*=&KL4k4nUu2*;VO}@EnJ^zDQ-K#Ed4rFAwF=a*6 zUv375+o%34epSQHaKnj#VNuqX7mxma-~Z{9w*LM-=^@7&>6wI3h7 zK5tjO$$VAY{jjTxKjelM_pPe#Un^5>P+M@kF?|~UooxrZwDlwxoIYD#my>Cud*_l( z-Rnb_9<}e9S9JQ(r9*3jb!&cEZV!5YDsKDH+n2V=y^}D1d++X^TnqQaazwB8RUz?L^p$h2^UP+Keg7(cIobaoZ~QxWxxDY0{jTyqKQ8WVKH3+zOt)tR*P8#YYA&;> z^d9`N>cxXukKcXkG{4%!S&u%?kTmDY&+y%YFIc%$1Tg1(Gw`udF z@y)*R?D<3f?bp0{fAze6+Be@w=f=C%i#C(P%%s%>*Z=tN^6H$&`|sWP_i@^;RhPB5 z1txC7Xaa7zmbka~x8~wR#gmI(&6#p0>`cweSI6tQ$`7TTYqehd_rtV{QT%c%ub0OJ zek|K>dGnh0;#&QCxtGq0i@iVGeXuR#m3qgjn~OI6I)C{|#lO3`tMXRuE!k1}=E-5B zdAZ-*R~@Ugwf*Z$WNh6JZuyn? z<-}ogyI(&(?L1yCy6Ba{@@q4{UN~5Mcz*lDLK*-0lE<%UIm+F(_L^TBC*yMR;rYWp zmOrv3G}!sK8E!wj)!BNrecz*(8k@}mOZUuKCBCh0L#1e-=#7Yc-wSMaHc4##``E)U z$9U7Z8T?mw8guygM&C2hYEHAx*){8i__iswwtBYWR^7V49y~96AA4uYJsHu2SyOwB z%C9!L{hf6%Cs29T*JE2xuK9a;!Gxcac6U!-(w?$+(^;w93t!H9Zn&}FUfau6os%;8 z^CTW@y7_CjIya~33trhZMFCfqsvXwd%FWMIH7(%vpD9;-Ha$G{e&w!h-a*?eRz2&U zb>XnBM$Hegq^=cGd+&F)1>TYm25$NOsKxwjYX*n2Cf z{kYR+(NpYoAO5M-a0~89UE6(qx7BU^RrmfMV7}TOy7$|$+4rme=Ih7q`%`AH_v^RY z;`(tl4_n1ot%&+-oylsl@=Y+Dw%b=LB?O|?Ic9iJ!n<;1mx9}X@)&Hn9O zyxfs%TGo7WE0xk@J@4OscK!CNyo&|_W_vd*Wn^epHQ#?v?CUBw?>?bbE4Xr2gqyw- z$og&2v~2I*s@)=f&24KlcOK5T`bQ>ySG_P_inWjC)xr}X=(douBgyuZ3; z$u0P@Rc%djtHi`apM2e? ztRcDjf^6vK#YG?1)c(FSN9yR2dA>LQ#N5)oyh3W~wv}%SefhSXTf5jfdC$p3Z$o2t zKe*)e@_>G?;4afwp=Y=G{k`*6HgtdGpN~tI|9i4`{_nf<|E8tfE$7l-wcIjgPsG@qYZZxQV!R9yr)Hm7#TXs&C*qoMNc-#+?fTh~&D^b*Q(lHT37zpPCR;r&0?a@Db9hPJ)STW_yws&v~PdUwX10MWK{ zfv0rthHW+8?Z1ES=ACO-%`LW&+FBAlbp_X%+#^|KD|cNvDSmIwX6r1=OV(*!g~o3d zo_xPf;(pP^C5`7m%}DR{I`5++I5v4tojTp>y=LU86V_2SNym%k4@GU)kaQ)r)2X;NvWwnTfC82_KLa}Ta< zv0mREclEaz`~9%3yUKp{dS}}Pem$xFe}hQq`iJ?eyC&%!2$i{HHJyLc$=yw6FN zznrxGc`9#pzTu3^+je+$&wabO{ZpXu>(fdfL*HaSa69%oCphnd*?+sfmy2GluX&=p z98U}K{SDPsOgWz)vftKQweI;dV>8V?dEI%NXS!dR^4ofSSjgUIvEqSS3x9l=KCk}Y z&wM$1yT3xNp$vhcA)=w{Z^wlOmPWgVGB5~)GBPAgUi`|`mVtqx;jLV#`1}3;r-sK> z{(L$;zUt@GV*R}(-`?yLKR>Vb`{nOf{+3;&#lR3P7Ah_#zFI#l7Hu3cG{&|( z?|9#Bkm=jhR^8if@FV7GVTkOrD_6an*Zevn>_5k%@X?8h%3xDOL&f#t>$Kkl#m4Rp z+4z9y#6a>L~9 z_Ln02J9nr2I-kGG%?hh|p?^bIk*VdKX+4B1w|JIqM z0UJ_M*PmUnOO*Yqnk&JU;^pr;>EBj~&bg70^Vfax_cbU@#dpU~?awRU>#6rQ>)LCJ zRbpIX`Cfsg-HTt{{eH)|W7XmAf1ZA8=h&3~y0B1xj$QGy%k%&Fq=)={m8^X@^XKZ) zcWdM$Evr9VT({!Zna!L2{BB?6UiLOV?%saoy$<`o-}rIx)yArCALqBlo0mSw`061V z)V$)>naYy-?+gtO&m2~@*-^hUHs`B{bmeTGsJ{krPb`$fxFvLIQlHMe|L^TDe{J{g zecqwxt>gSYpV+X)^VFTl|Am$R|2eH>yT3ei{rQZai?nj$p9+^u&Y9FYLP}t%pI4f8+P;#nkL_En6OErAntQRX;&jGZ_Wmoc zt=Fxn*nNLa&g-QY_ldtZd-;sJ`}@PA3C<>8g^q`|D9Q=`PDe9J62_% z5@$YcUSzw&%KT|i^_Qt-r%hI+MO#|btv1d5zHv*^;lE34#cu7HA^Su4oXun1eIeH) zeoxuqbV;`8`-W*^-;P;3JX{lGxA3g`s(Yp14OVRfCCsVm{_|{#pY4>Evn+abWo6%r zU7J3AaX)^sSj1L zr)8BACK8F4uO8XAVd6!OCy|_tolfIrZ%iiL6S!%*N1DzwXgXFALtJY^l)ImACY6wCC5n zdFj}nBg-Ohv#TcI{lBM<=T-+jcra1xSnI=_Iad$GNVJ^TmA&o%wpH8y7d@|jG$m5~ z*)P}I@9u2-yw&sS$<->K!?^e4Zc%!g{rzK=sMprbZ!`1aT|-*4S3?@7Iq=4*+ag5c z^wy+pS5Hd+TXsDAN5!R$SMIK^Dz0fYd7+(E)o|(htPPuF89&x8t&s9_d_BAD^OHb3 zze`Uasn%xRtYWRy)4gq=dc<*CY|fuH#R@NpbBpx07<^dzQvGzz$5;1-O3#?jt#Q0* zwM%;QrDGFSUtj6(jultna5i?mdT3G8o_pmis>!0e7H5@(@XgzrA3rO2@r)arHD}NF z-kmBHy7*Gt%DgS{ywzF9W%qtnHs8NI|80}E_EP5huGf}J%eiCK=l_uPSmE8Lj@BIH?GhgKqrF!Mn{qOZ3zt{cTXus;;-y_?nT^9^(w_RDA z9C|viROC>ZjD^*!(>C7{=6+t*zshl2bbg5J|E-dN0aC2Dg+rSYX4y|#a^^>Ppy;~x z>i_CJ2e@}>p9(b1E^_nrF0$P_CAllGbd_21l76jYE%)Z<@Ez>W+(TP2_2*7>zk<&f9;k+*>9&O-qJh!Zx=`=4-n* zdHS7VV{l1+a0$J2o0Zyqap48C>)mhrSNZy~-CiLQ+Wg(V^rqM9`DxSBJlysk$Y3~d zCD8PRZnyQ-U3vFr-H@D9`ck*_{^GEX{)eW&zI`g$-Mp2X=lIeR9tMs5+cn=PE?qI} z{j^{{28plN_4IU1c0b)$X0OA~aN_s2)9n9z0!w$4b#u=>o=_g5J2$lJc*Sk@Id9I~ zJ#1rD1?mM&zF+sSoxkqy-TAgru9vpA1)BaTf3`xZpHbr5Jh8mhT+bx$hLt8O-q?C~ z=GnLICv!usH~TYWJfHJ!+bWw?X`RM9*2(h=b({+0-;x_{yHjz^-nCk%<{rJh$|ZEi zGW+#fJ40e$J>h=ueM9zZ?9%cxB9GH?V(%sr^iL!+rB{{WxAHO ze(Am7O;>LI`LaIebK&et&rfkrmgd|!^uZ`Kbb~=E+s&mF(N}$Kn}2SK-Z5+5vx+5- ze?3b62i!O~?fY}l%Zb(17o7apXKm2q=FS!J3b)@sTWg;2-nCh`R!Dunpzqoo^H}@n z$+HfN-6wf}Sc={Z4!x-zeYV0_HQVIZmg^-~+@CM=xz8@vo;c-s=WoZ;i%(uQRE!PW z`uMb!yuh#fjvm||x^`V`-Q!D9{voxWPTK3ZhTab| zwLg0PHq*M}iffC1D$L%aoiW*NbDHz~J(JhJ+4f7U*)q3#^_ClwOXN+jewU0Ewr9+;Ta z%qpsXezj}Wb??~N+vu(1udBLNHLTED)wSw+?s~1;TC12C8dh*IFo4>rAPgGm1Yw0$ zObiOEx>hkTAb1d^aOEHg5QZp)Na8RDk0i)A5XPz#Bmu%GlF0TUBv*AYFgS#;GB5;+ zLa<9H0|N+y8vh^(5Jr>4rWB?eO(~=k0Wt%GiI)T!2f`p-APmtN8q2@{@&?HHAWV$^ zR&e2tDUcZ;OoTaFB*tjNidA}eJP-042!s3v!chN(u#y-VATvN1WCjRB%n?OIA%-L< zZb29%0m2|%APm+Ck^o_l1PH?=Kv52o0AY}XKq#mShu|@S-3?a`k^o_dQivqj0!(x8 zNP>(5VXQhq5+IBsiEJN2GIRifHDUAOSG?wTK&f>@?c!A@Q;cT%s7*e(7$B z`1|#8BB8!&lTW4?SpXI)4K0oj8u%kQ5o&5gJy|+?( zZP%*VR<$1%s>fUIc^*~Yd3MG(nYyPZ+wC&=H=532SkuA$KvpEw{qM??&5QS4eV6|B z&i*}n>fL{z$o)ON|J~aem5?c*u)iC=-#E3Aed*!c(!2X#`u{zm{x8?`Px6=Iug+hy zFK>^M;WQ`?S?d=$x$ot{$Xtuu>CO8!FPONl@{3x3X6=u?>Oa0sHTx9x)%(nLUCvWx zN1fV5ZEkDz+-_UxeRrFxbi~D%+urt^y;h@DcS?(=>}ln@`N8XoKD@Hcw#jbIF;Qzd ze({L7-r7S2jJblh;;X&Po_6PX9^yW2wqAVx@2)G-NnO77^M#-G{C=>a=B$?b{y6FP zx^XkpFc+)Ztved>wQLZ zR>`l5pS@+*h7CJ5uCO|MGPQay`~BjIm}!n1tGwmUU9ia(UYs>y-?eJKds9~2TKC&T zeci#^(+{`LpOeX(W~-RD=XUai2UoMNMn8-e2wgpW%{?E#s+$iPC0N${G`$_1_q1%; z2BYncA#*?dlwEBQabU9lw&S&5Kbr)aMg<+O3IFdRA-b&Ur{&&XbHbP8|9^S&`RaK7 ze6KKF_p4d%8PR$9%5&-%9N-y{9nf1l@zhpx|O=dauL z(oOd0<=bU%?o|GM(Jp(ndg{ga)w|a`yRh2o?mU?{f8Xxj{gCy%?v&{|b3b!kul@8|>SX7_n==9hPrJUm>1j1>p54;V4tMX|xow#q z)A4BH{hgYNj8k@rA75`%XK&$gqIy@h!hIvpo0FWi?%#QtXujY0hsf5sTkM`Hxn8|~ zQO#F8^!?87_wN5Wd!Og{s((NH_x$IM|8Z!ZZTVXLRbibaCbpaF)5Ak@pG8Xk?OYph z_s#tt&$X9cX)FoL+q?Gc%Eg8Z;r6SxaXxJ3x80)tcWcQlIrBS#!DjFNRAej;EInT$ z8-DSpqOSkFPp3V;ziD@^R|yXxP3nb6fCzfLIkhZrvPS{-^ntMu-F@%oqZ z!z{l(Y@dGb_dfa8y{oiOnsluSWm{{UEt|d>vW#l2(Ykfl)(YMGvH$L(tnU^Zq)*xM zT$I?bZF(ACcwE|!Q+8Eniz+{D+xTbMm$o4JJ4e*YF1_*>4!!Jk?~d2&>~w1`@h!Y} zn^h;@IyqfZ{Z!HP&oYa$p3gd?x@wv7sVc4ATQnzyNQ8R7pT+81^Xb^a z>Otj(lZUi5j&4q=3n|O%+LOH5c-1z+wVT=0db51vR@L|%Nu7INvS!!j;0t#re0wFf zYJGD0%6T@5tHLb58u!}-rB2M^aWKuU189>>Z;B0 zZ`-=7KD_Yyp&jo3)p6DB3I+$EzmMX(1GhfT{c?=y^_jPcGAq5(&j*FgG+edJ_xF*j z^R-q@dsVa9uk@tl+Qkd!nyz{_b4{)9wWokyLoYeruF*M#q+LxH~tvJwR~ouZED``UoB5nO>dP4%_|96*1TrX z_v?29w@SXZUdT2{Y}HTG>XrMF7p*>=a(VXNz_8p&uUcMdzt<67lvR54|K<5VeMDXM z{Wz-s?+p9Dk3E{p)mORoPiJH3SasX=tL6X8cfv~V*K$W2GCU}#Nmc%})wXZ3cF^08 zpDxUM#y6i=rRnAG;M=!5H<@33DA87SCATW<%sZwTN~@M#|NSe>eplBOONIv@N~TY# z)_PN5&{6hlnTqZE>FX<}9tsTKYufK`&9I<4ol}3tHv8wIw|2%Z(q8uTY`v)4@*~?r zMc2Re>s$3Q_3oPZjRyDB?wNjG-FQ)P&en>DX0O)0|9bWI7IWWkYn=Y6->&M%U;CfIpMSD6WZJD+RIXM}zU}sFm&B*r zt7cuzk(*Hx9eV%wtVg;wH?_Cwhek|3^e6Xd{xm;ZS6 zbLo|D0(sgh`g!%W`5!*a`{Y~lkl}sLs#y8&m%k>4wyxeAYku{KXxN@|%>?)%aY}G_2uS5k(Rsl_dLIy(6++rrO4c{ry;Yg<@+~$ z+`TI8cg)Njjr{VjqG1)6aznrWf3-eLbBWaCU&iu391M?y%>RF%Cv?yEeZSLouGNxZ zHh80_dnZiv%;RmV*8b&ch_%1}UzDNz&8?@}3_juMvmWiKKfCT^>9$0(%3JGh*Up}n zed%}P?|hP+0k!A;H!`#DGXXUO zKCV3a`rjf*J8{`tp-@;WQDv3Vs#&0xV@lO>x6m2Zu-2apR4t@U`JaEr`5F_Eooh20 Q7#J8lUHx3vIVCg!0PA;0wEzGB diff --git a/doc/qtcreator/images/qtcreator-locator-open.webp b/doc/qtcreator/images/qtcreator-locator-open.webp new file mode 100644 index 0000000000000000000000000000000000000000..eb8005b35ef0e2d37c7dcc7765affcf9048622b5 GIT binary patch literal 5444 zcmWIYbaS&2Wnc(*bqWXzu<+3rWnj?1ekh3H>yO3T;-}vJ_J7%#xAV`OnOwAbS))Pw|SD$=CwgHx`V@3FZ+`gG}GFXd6ui?S>UD1a)9toZ^13S@q#g}k?9?@DVq&P?Z{3r(wmr>!r(%5P z;s4|vyFb5Qa4)co;rGhj=k7Q!D=q)7^s+zNX>YB(=eBKYb3fbcKODj)>BoGyM`rrW zJ)HR~ZBmQcEn^vr51-wv{W!>s>SQD@beA`h=$d^txpXMVvU=YQpk&Oh)v z(_FNl<#Kl8vDYF#O_eW{{{P$9^?GgM#_|g9Ls5b(KfkM=3fir$5F94@eEs*Omup3@ zKdxEc|9)cE>lCAzvQpDHzPvYGuzDer>I&J_#UVW1y|1R3WqY`CN|b#|ILeaq&E&m6 zR1#bD9R2Nr)kho})~yUyx)yf#!JPW`{9mi?JN@&O5t;Q}BhIYz*~evE6lzg$L z*wm(Yk+kuiKeYzV0%dD=PW52aP&zw%# zaYSxr4Qt`P;-2mhp9z(T*?bK=zm~lf&Hc09N>AywzBsBj^3 zLc8p5t$K^)I;q+X{+rbFCiSHnRe#Z0zVa@s=&Vb%1*Xs+sOFJ;ey5mYpoLR z*+xsAxGCKDXI1mC{Kxj3cdwtBGafmZ^7-C$&XC5dpPilGnSNxS(0cI9nas{3*=gU_ zBseGafBq@!v{d->b@jAupU&HSyLhNdL?+7rjjO!WiH6?`er;&bz4nPo&Hv_aiT5kN zDBL)ZpjO=R?46VKwECR%V`kgUChltCW9WwjiKeqx-W$*K?bgcH^0)pjdA$2st?)D3 zk2ltd$KCn%eES`#iwx%%wy+ha@pbo3+uJWbeQDI;f3h|kw|5;BU%m3#?;e&jTP=;Z z&iu^GH?K|DD7Qs#;o`=7fr)drga){6JN)nN{J-;ls~P+&+?oB__UF#q?>e_w)+kjw zH|gwHzEu5#^Aow57pAbWpZx#a-Qkmhr$meFwT(P!2X0p=-nEfq1!CR|PD{oK#ZK9QlT-|UUro!##v z7iYSS>GsCvKT-^@{IZvpJm_;>?C^fY1>M|J6DGxe4L_UDbkNRwr@>F_?u|CZ}J+?xu4)$#GF6T zcllDcZB2LjqgHW7RJW+#+^@c&-p&1xeyU`8s>I~KEDvj>cC?9bi7xH<-EO6R;K$qE zC7LQFE;l|_7TtW~A{HpxQPbwm`k((qPiuPGkFT#z&+~7dzH#2ITenv5eD!8q!Wz9k zA@+HS#_!jU7wJr>w3>Zknpn=-y$x*Nmzh@=xqo4eSt-B2k8S>vY+kdi7mAyAY%tqo zKBM#T`6YAs@7(_>ajLGt;P%!f5r<>1cE>Mm_@6uVLwJzV1NDC$x3sdRUQJT?ovS6@ zXy>%*ZH#yL;Vny#{M=gAjwWh@!O=Pc=J`2 z<^Nat*VjfpTtBzv$`9#D+83+KQ{O+SWpSuaycc!V;Vb(l&*g?+&WkUt-{&%;==6`@ zcZ>eV>|M7t{oMT7$M3&qUG04&N|?RL_{p|6ON*{-mnn?jZeUk_|6h3Yz12^OqQ9Nf z2>rBR&grRN&J;#9`M-D^<|y`e9)m5XZE^d7J&`d%rpI-QV-~qwRM}ttr6Y2MYsu{@ zHPc_FQNJvbvaA{teSd7-c|v~Q+}-Q0&Cn8gs{W5D)R|#UnwihF6Y`uXg^#v-Kffu- z5wc_MZoU`xS`3Vn&P7ard?eY`E?6|PrA@wQ_gw9U4^6wKOcM_0ExgBPc5kA)fAzvP zCY664oSv7D?CS8ZTH?QbssQWW1tQno|1Mf_&oM8>|Ixa+w~D=tb9!&yb=lIJWzM_e z_QEfl_irn`k=U+VTk-OFtU&Do{*b$U4c#}D+FCzQG zrQ?Eg)Js1zRtZ(T`V|tZ8Fs37_W9czEG#B(GCTA9vf$Q^yxTRQJ3oa*n9a4lAI;>~ z^3X%t*z)NH&axc!@P_AaYJ8T?5wTGBwDeL`=2DOe-|qdKxu%)nXR`G|y`@J(W>&A_ zkeOOC!Tr2upVE@n#$O@PnHQ%tOT97(buUb0|ISykxLQb_EsXQFsQX&O-LpHk1-`wO zcFOeirRVPJ_vlpp+c1yy`Wjz8ffxIi>ikGP^wQY-;jdjW>m~+znZ!5p|BI2=c;WdX z@s%q7BFoc%H(tDS{9KgGoXC{Ph3^DDx$9oak`CTnv`%mO-7>BJ6%Q7hi!!7O%B??= z>EJx)puNi6Xa5%eXn3i4N^P>J(WM3ZJ6L`^I3MNu!b!Kl>9Rn2S?kM%rk~ua{;?^#Wr9?%rFD`c{}(EHBw&Q@2R!_7^P53FYYyvtMbj@gww zL#^zpikGtorfV^Tp58irKu=ywb(~ZU0iZE9}RCPfI8AhffNh zxP4Zi9Cx9CP_pT*BfBgrR@~8>TmGmfgfS_$Nq~9Eg{ul-o4qQQXw3e>Z6^Nne)vg! zv57uv>?4z0eb#7Gpk>i-Vys&nY zZ@HMLxHxO`nYVXT?f6k)|MJQH%kn4clo{E-{_{~cYUp14!&A@bk-FweS0&bZp!%=Vy&8O1jKfjV7GtjWoNi z{cG>LqW@B&(x=V-O_Mjaye8VP=+ArCNR0!o5_{ZcbNPwQ3g+8!p!;fq@=+fy*;|4> zP5Yj>?E28cWZCd>f0EXUcDVxq(Z596rGp%5cdc#Fc)`jc(zp2g$_U<~#frPku9>D8 zW%QoB+rs;z?Daag`%G~D+wz+x9@B3gXTxUPrXjPeqZ|g zfV-~Ay@mqz@*_u23iLL;4R?>5!}59Yo_%p2UKMP*_WU99bZ-%Z{VG#-8Sk1KEi(Tf ziv!!ui^}$UzE=KtaOIKj_n7TJN+R`QSV|SQXGj>|JhE|}$XD~L44&x{3!eYGaklyG zUZ%N4o0?Cio!8^u&>i9H_4cUwDc<*C&hw>|&F-5OslddZB+*k z9`@Alx4(Px-@7&WJ*Q@U`nBu)>M82go7$T=59|J_4Y4?(P@QpaZq|$7%gLtqCIzgL z{3!U^C`m44t+;0EM%K9V{Jih>^2xTX`OtgC>2a?B@AtUd>w9-tM8?IRUwkWYL+!uw z#?JHSJyrcTMZG$!HZC{FD6;a(iN3t&2C^kK4s3VWuX=ZI=<6`pw8!u|*?3P;kAJo` zT>P1;+iCl2>18M8aG3ia-xHmUNT7Z-lu`#Tj4ou}&NDUAjbq$lRh z>tkuWzG6dzOpTAM^rD03pH|xL(92bP=2P^fZP)4bL7dI6tiMj}UK4Q2x6P5`jKWEQ zkI!DZd~mr@X%+fGEdSP&|B@xA?@4Aq(Q1vi5IS|)(1`K)lV!8M$0l`s?cG>uWwcQB zN6N(er<@WJAMzEbOj)ixuR)pd!;!R0ZO>kwXxU}A^w`<$ekoIyE6-_A<_m$K99>cHc z<%@m?7FKnbi%~7dB)BNp}Dvyol;VDFkg%OduuUJfb}VE!DK z%;EX4ML`#2)I=ryrMcf@E9$ovd@M9xdFE3Ii%`J{xmWRx+f&Md{R%H=kNXyMrW?8pvOG)zLyCs*!qo_H@Vj*kD<~@g28Sj?k++G@r=A7Z(w&ckR7Spx~B5td1Sxt#xDl~$VVFT}1`KdcYmu9)TaemK-YJ z@w_7Vy|H6vR+7uSKA*T%h9_RSMhS8Xylj1I|NrH5f%Bh)*2kE?_uHyG^USYfSqnpi zZQh(u<=<{%;3@GUYgLBrL6_%`6HZUoKRY!~{CXGH0r_pkSw@l8pAM%?vR67g<476f z_G7`mbA@`ByRCiE^|+a-T4vc+3TDUt*Vlgk$h&(f&E~gt*MT#9K9^pz zU9AcDuQp}Z=h>bgf@jyQGYe1ff8geP@AbF36H_L>n<)F@;O#hb7Ta~v?;r0j^`8Cd z&HELHxo6l^zP-v<6ZNo>w_@GuzjMOAEJ^yd@ob;sR=fVZpy?MF9~>`zU0bs~FEe=F zU)kOj&zPsNoY}gr#VodvZ(iHqcPk+sf#c=U>aw|wvn<^|J8jy=%g8Nfe_Qe4a```; zcTOe&6J8UKB0={I2KO*8dl! zR&uS3z5VaaB4-(NI4zKk+iv(j+%UHJkW1#@ zy@I?yfA3{%N&QpJcJcM^wf_#wgo$-z)yBledB#P>#l(d0LTgXIsK8bQDRLN${6nC$=m3{SjvT~X{e+lCoTN-SaG*C$UC?5RGX!F)>T(S7Sk z-&tq8ABMkg{C@DoOZm3`1MZ9;_#Hm5CYZQ>-?4E|x22&`s%oWwV9)usq(c5VYVLUo z@0GVTryuyT@%zC-vBRf6eQaSqdsZ}Tnv+$CONP&Fr;;3vJUw$EV{>**J?V~g2hN5W z^YmSIOr2uB`qbGc|DNr878tFyMv3)WvyTA#ES)-gEu+W#t=DN!4Vr8G*eJ$U=~F8M zzguT|qPYr~H?D6z{jf*Uc-s5qce&fPzt29VWNc+7(sjHof=2?@ftjkL zI-^~u?$p1(9&5hu`So+2dF>oC#vOat1hK4>Ejwhua^rl@$M0{mr5yJ4M6B4qlSQXq z>{S2b8>_Az{`IRT>Ga;f2HypfuA0V${&@ZSz34rY4xbgB3331UHweDt`IKD!!RFiM z(j!$)YkTj1-?Nd)M(j|s$oh4Y+g`S^u09c%vgFL-W1TS?0{$!kwleP&HJ-7ga~zts z*Vs!}Za(*>7vEb7+V2ERZQs9qpYzJCtkHX4GFc=RB?Y&7`kH%APTTG{yi3i?%hPhq(Oa({nV4TZ#}Z-!_j^tQ zuf_`u=M_~&>pcE@DbD(}Ept*u<&;Bl&+5d!8CSl^-}GqTv&Fu9^?zOKU@j6}n%c0} zF_6`4f6AtX%MX7wjM;BKKWyr%^}6eO!i9_j&iwXPQa!Y_@XCrnQvqA;UH4x#Z)kWh zUxD}Kwvu<<_tt-u`fjs6K;S@jNQ48QV-V+``cJLyM}BQu^?z=0)YTgT`zOrZy?$rE zW%al1Nx!bmiu&`3^M^>oZw^<7?xp)gI;RFc?ARPyHBo;aW+6`!=3*I4hM7FWz;=FOy)0aTUEd02Jb!IsUJ$(`Wf}l{9||UIab5FsxabD75h&a z3l5DKx2ktD9vd~h?=oC!H8ni*?Q7qslM~8M2;Nr8%vcbSv(h3==-R$}j&B&&Hyj5Poj2$wzgN7`<3=D+xPST{&W8q_U7?3Ffb%2{t(D#WME)W(3@nO0|k?BFVoZ8 z|8whq6Sddt|L`y{FgP^qU|?Wicod|jxBvV4e-qD4KJM=p z5NBXuh-m0I{he?A-_`TW_kGNdcZ>nq!I%~E@3eIIzfbAe@xQOH4-=ctU-xmlf85h# z=7`uM`ixuuK6<-t*~io7^HL^Pd|G|KHudOo!Cy=MJ?mwzOG?~%G>sSGCh8h2!ZuoS9egChm?|j(zS3Q1frgpzZs)JiWFZoXBmn)y!_y1V`_qhGd zAD6DaSI}cH`2I+#S;kk{R(Q@Ii^~o%426>K%U%@g|7~ag|5x7jk9__9|DSk|urj=g z;d}b^_x1OGgY4>ld(P79bQbjd^(0h%sZjizua1+BN3p$X=D+s0`AH$)`+UW6pVvEB z+fRt9)IGfY^7EsU_iNwhPm;Yd#->=x8J()ax&-Wwq;>y0n@BglSfA#@> zgEb3woQahaXSlVh&~x3LllP5(#+%M^*z;Fq--4{7U=_)G>Yp7=bU*wT`?NP^M@ZGo z@9!qZo_KoHZoYHa+E3qvRari5eC&TP(?nw1r^4Rt+LI-U=RA3_@mIxtmWHGLqIXwM z)cW;QT3$hq!6oL5`s3`iWm~VA6`uUUqJHYgQQ0MtM^xq9Kg+!q$dVB}&(YGvlrB5V z?Qo*D%=fo@cr5-1IWKq0XF9M*{Q17v)fVCm0@H&EHGSWO2u=?OvkHk3`qHEFHi`Sl zj7LJVj!ik@%B$TM9USwkcS-rK%RR_mxZew&~tg)ZS40>4~_%msiujYg*?@@3Azriil79!_L6a;M%q0 zLW&>*1B2L`bxKEA85kJA3D_a#Rrl$T;~*7NnLx>$;mA^-n0 z|8pD+Sr_Z`w#?64eDKoBR2%>KoJR4OUrQS#rPq*77ymE-pCV zuezpXht1cJ?{{av{{Oyy-oksV46Bs%-~PVX_v_QnxrXkiYnJ{Dm@GVf+r9Q%#n`}R(@RPMfQ@ykbS@@xztorW&Ldz`upPO~J5ZWf>Jxt~9| zv-@Rz2e;1l9USN8zqYe@XS3(>&I|89RWdkSW$650^zLuoi=QS@3sS9o6g{@8?Gt#% zGigiDk9T3e4C)tdY?fMUf5O=E=8T`Fp{bQV|4)>6$n&)Qi}CqTyMakDYlVi?(VYf= zH`*OeG5NkA%IieO%7~%`d-LaQE<0~-asJTv$~m0OkD7KcIA}i#5>d!h(0es&R$OZ9 zniTOpZ#DLxN^?~ybo8l`o!bBTbo#btt)PkiS=Wo+-nwJnCuG2{`+pH%$S=E=7Kd`3 z%iDjwj9k5XU+o1hL2*^Rdz+`-H@&NEaemYHogZ5m3unfxdhzd~)Ji1=3GGLV{!Y#R zvsS)p--;BMm~We2$7`|QTfIhD>%_V#E8ooszAB?}&)9Cx`ej$Gmldn7lP~+C>%dHEX!_6SP>TQNtq36WT&L8>TbtTWe zQ2(EIMQnOb+tEjp`A@H-$p=G8Bk$llXejxGhcOENlU*WPg!oE$65phPwbqLXreW3s)L?eY|Ppvo%Y=eUk2(Ha_;4y zb>W1pSL=c#w&j1;DXr}|Zkuf$8d5$l?;LlbV@#T!Ua!~!=NN_qK9W7v{uB03E4IG0 ze~n0Cr*_`<%IlA-J4L_;VwQ+CP|MWUq z$#yCFs~S(o>54~(CjDnHIG-|8mcb#$Xhk+-!_htEoD5+<)+sSGRBHdbyWEM10i0JH zK;=C{A-LFQC|qbE4$5CXF*{_XKn%@CmogZw7#J8FVxm?R?ks(qb5`{~W5QF;b(Ya{ zUwI#z{&uC5LbzhCvu!79z4V+-+b*qLzEhduQIKOy%H*T7UzjXMRkzc7 z@67fn9p5{Fr=q#fUM~8vMXc$lp!mUOY47g^KL2>vc)DKRheQU4${ndp8@q0Hdlv@3 zmhA4{e%9y_Q-`-{q2L_*>$L@UDl3*3FTDTsGeg6rDeco<8nh~0o%O?M$Ki=kzKf(~ta!n!%FxsA!onZ#zl%1SbJ73b-4(iek#818#C%c~Ti)gL zNN7#rN^QN;+C^)QrM`M}sp1gBXLY^1aqqwNex0@5Io`Ier0Or1y!3%nV$b!c;+_xT4^<8FBE}H42T&^M7)FnCR)9$Vd~X8zCKaa zCn6Oaq(c(1t|d4p8BO{@oyy||y1RFbrOgU={}bx$&e>E^JXfuoA>eb- z3$wp7e>512O}E^2K>yRukeMe%(lW|Vzq;6vnR(Q8!_J$#%db?{d_S|aTe?PqAwbo{ z=;92Qsr$}$a6bxaxjbK{Fft1@UF+VgeE;O)%Y&(QW(`yMwnyah>2iOpGyhU^u)&Yp z;VNsu)2T_1H}1P)&Alq^bZe%!f{1>4Ro7ntE+w%}qyfSTU2&0TtvjJz}U%zwAx_q_RHhJMpTgF3za zzn|SCzl6=+5*(tR_4Qm`b$gE-wNLm_q_?i1%C!0G(tn5MF5L6!rnN};OqI_)^F8BK zZyP=Luc}pAeY#WHV)^x3e?q_Z&5Kbu%)V*4%K9~FOFcepy|vZSCSmDKu`}+n8e%&( zb##~QSmVF^Tb)#}seSPO{(v+C#zM`Xj#-~3H}BXoMQd067PnO#49B{5WYk|^|JTC% z=V_GUqe&c&pTsM|@-qMHzWaUI=J)Mew-V3Ha9^sv_R)ovvUfkfoBDp4rqkS;QS+T% zJe@bg{ov28<1;`0=-PC7<*xZFC##>5mu6g8_f~$%EPKliZ|$Qy+p|TUGaYEjih1Q8 zs~N+Z;G$!JX1~ zp_>jRPpzLY>(3Jfz0IQ2^VXODK328&_CillMu$J?*$>t&VtXVc70~_sb|>@s`L}LO z|K#=TulCJb`}bL8^r=3NagNE7+xx3=*3vF6qxi;~Rd%hDm_xlpEAu!m+1VwpdT23W zV%C}aR_-yU>L*A+Em7mXps2@?z2CboHd2Q(kuS(=v3)%a0!%3fE|uHvnm;-~(d zc)xei#JLe$?1JBJofedGQ^`Ci^jmYtugT1BySTmoF(1g9r0Ny+@kRHC&H`!UM^2Mn z85ka)|10*tD)0LX?!x&}kD7LbfUAoIQ=Q)bUGz!`Ql&uKW>8Aw94n~*AtavH&IW19 znM5}5ftqmBw`IlT#ac(_pR8wS;M7r%`aA9VCfm7BZ|@b+EezYrY_R<$)0xH{C)B#l zuV-%JU2x|i05m$`-md7BR;b&4@cyU^~=rSSR zBlVrfC3>3##T!@!#1H-~zRP}mZhN_v_^-Q@=4Ni<*zhVswq&c_F|X`L*?;_Qt@o=b z*UpZezW2fn$KGXIcbq;}V)f*0^xnENaaGL^_n9u6m2THpF+qRt`n3n;EvoK(@PCtR z;?Vcl{MwX1>RV-Zu4SBC9N4~0kwHPPgPXx;#+O~Q<4U&b_=I^0#owCD;T|I}IqvAw z$1&oYWJ4x))dcOHFneun^Hhy>{x8^zPREoj{;}isMAMuXFP7zeH4WUn{E4k*`Me^Q z%d2~?ox1udjA8X$SVnmzzWd3nNiRKS^;_E!9x2y;a8w7F76eHc*u)eA#~4 zsxv)h+r%l`RxnL}v^YJv&#kP+WA>!?OM0T7{c-VGc}dAOErE@p@S_;Ck;FTJQ(-;J z72)YRZGr3fGEc442n|utE1Y?Hn?~Nr!&(;|M0bP;O}`Q2v+=^RkeZ;#b*J?8QaTt4 zS1LfOma6T}leL&4zCOCsSeG02uOrUC?-D0dD?f#vKglzM$>u)2^Y>NvIp6nT4>!8= ztvmVp@a1ok423fnA`)@1SnIC!tM>h`c(lme;tl`2+nKi)F$he*w7bj9y!v~eRsZ{W zJ4*_i`I#BQykkD8brcKzV|0jFb%(F^U(EM|h0h<(J=a<{{X8?ntC-nOPwmu7oKkt9 zEM+T?PG)PyyZ2uTLu@(j=J;hycqLqHZJa(=@N!JVJ=;K;yEYT&mLye{XGp0sJu*sv zRP^-0mx&u?-+vTjT9ec3y+-g5=cdu>omcOx`7}FyF(it$PdWTz~9z##?v5l&;oxe}6Kid^9xOatup6l;w-$Ul| z=M_TL(&n^oS)}%8((HG-#t~LWjB3nwRxeUbXIO z_Ur3Uuve@1`|;0vc9_{AMnIh5NNU+5r5ktN+_ipXv#Xb$`LrXd)mO`=bamK2x>Vj4 zDmbMnS#@1)FvQ9O)RtFb%0I))(x0hnu%y z$B(y1R>gm;J^kK1v5<3F*PY~vT1*jHg_%1TWFIj#?3g0{yeh~wa7x`}&MuK|Zz(TM z@#kHF^Urn{FTE2mhkHZKBT#?o!m4)+43C10A34QxGbrdWZ14cJAv?fq28M^OY`sd?E3YhHRmnwR=N`5Cl(FUm&gg{|IYdwu`&o0m0rb-dMhy?lk5 zu+$ zdSBRerqf&0ez!5NnYV)jy|8!|7PBp7`ir_x`MQNOZyoVEs(Rt5R3YP$R2j5Z=H1Ho zPXc$%jd==6Jb%6|uu@Q){`Oz-&Fg9HuAjFyFPxhg*dh4HHua7w|NJYW)Aw9Yw$Wbe zn{2kaDR{#DRy?Meulc&!WvcM8EPw)DyN+3dh+;-&^yh`g?@_rKFoFt zRebbFT)dWVYoE}p&DIHD`xz1#Vd*F21ZyFq!lOsKBeDV;O+p0hA9pXVID1%`rK-)N z%cF{SUBsN(*%L%31XQVb z^~lmk?hG3&9$k9-HSd1J`f}?n9NXu}#rW~EfsI(H^k4paT4ru)pc ztt$fJf>9gRZH?TPAyar!{iXGmQm(WI>KohNo`|0FI@Vsz;OZ`S&3VO>`xz1(kF=`( zXJn{}I#w#15T~rCW5v#pknns7L&CpzT1*TLIvWoK<%2r3pwVJ*?+BcR8AP6gx=W8P z;pyk^1@-f<8s1_%$(n1scB=N`xMw z=PHk0OUe=h)qKn5gKEAo<|)Us?E1IKIU;(Q+P?7C)rot;0=;9-dPw zP6zKvYF3tN&;s(9=G3_hCofp3sHgNPF*9JAF4sP-4UfE6?s#F$uQ4&UZuKI^&W}0n zBF~u~8L<{7o~&nxNSd?hj$!QC$v>GKV$x&_6E9jaMELbYFFStBFN9G+@2%)_CI%hx zldH6ZR~dNkoNb4QJ_{eA-}Z zyMj?*`iJsV&={2IEFC6>lD%ge#C&5OnMPfCwd?P}V(VQOB(ndomu0KzE#y?zYuFJY zfH@K+TJv_gxOdDavtCAB@58#SyA|~sc5G47Yx?|r7k{5M|N9cXFT0mocmKQavaHCo z?%6BDl}Zg)mAE}5v|on{PX7_zywGck#ZHOM&x?2bEVepy;QBv<$tv&jUPU`j7jk-L z(!sZv|K9tydGD|02hQwC-fPd$;VoNu@?|?MRtwxG8?iF0I*T z=XW1<<(m|@0(cEwE|vqF3nmlF+uM&@0_)Yk>lXB zjn{tk$aZ?|>9-7FJ1xE!taU3~x2OF@ioadmuV0#vm^L&?7&7b5y|`<~jAoH;?+q2M z{fbks?eI|#71^-VBF|+NM;NSr{+ib=_Hf$e=F_o%^)imICQKE`gf!oqdW7Csc$n3off_0w#$1hExmKS z=T+;4U)`OOH<`ZB;M$nNXPz4XF`578^^r-9I z;p1gsVCWVp%-q5t3!Zk0da;E%3Qol7(wce z38QvNy&i2UpHLQMQ!(p2e?sX|SCjvzt2MK08NbGzIyc#kKjrG&LiM}BZ?;X{tMUHX z4%wM^g&$9Mxu}t6^@2~M+ROZG3gZExu5OWOryqS3U8wI8&k(lrnCf}qlj_0V6E-dK zIrM!=g~DB@;F)V)7u{jA{3`nM#wlmXzDb$A#tYU3Gi;c$a?x-1?6X0x)$09y-+yp0 zg0$D=i0$rR=q%xQKl$TncV$su&gb*aT=3iV^4sDvW44~dHn)B-Y)Ao(toU{p&)-+q zwS!?zQLney^A+lP8#7ic@R+${Md6W$dmbh6YIuI~UDCxc%_{~nuKqQ@{hU{H%BmMB z{rv(B9o=(9y=;`fEUD@IAYpu6SWH|n&r`^=Y~RTnzS03ZxeLV`mI{Fiv6CIAKY9ku z_TIsoa5Ot+%k9b#*}RXFcNQN}-EzspE7&!1xtn{tGc!bsl&%9i0|P^cx3{U@ z_H}dD?tfx0yO1$#?%EpHn41C_+Y6o_@Y;QJ#nr#ki{+;;b7eTKq_^qhqqAR^`HC?n zq^>>sV&06M-TQ?0>j}J^{HfLR`a;g&qL|fpl^Jw4ptk3j3mF@@HVSw%?eU$xH|*iv z#9xn$);?xZ(97-Ue(-1KyXME|4qMOV{+p*-c+=Wrm(H@>MZB{w%Eg~7w{|FJn8tGP z(1nw{N9WF*-}&dH@_L68?158U^Fs8G*(^^!>b+)JXXI_yo&WQG7G9mhY&Kao$wcDD zTv<^r)k}?_PlaLUC$|7 zXusk?mJM$NryCV&if|ZzS7|ce=$vBx<*U&Hi)D{ahK8;zESwy9OEKhWZ(&SuKSP2a zsMR)0?71DdwYK2c(yCtX%BO4mW6m5l6_{?}k<1gVrMHS_W{BW{J00HJukWr+-uv(E zg~-fqAJMsQB-t+C7I2gZa%J#7TQ=v}%}b|!SKSR2(W|)_?Akd+qEg2AQ=o0=6StV6 z=1ymK)|E=uGmbpxGhhc#d`Mbb+Ie>68Ap27s^0VS3n@^op7bcDL3K^Z$F=7+$%=|U zXPX!DbHSohk+~^T>%3Z&3u5m7GQ1Q%X>PmQ*L9(DX1_mHdxfD`NzXX;Q~c31h6K&Y z?xkYWSGQc~GwW#-jc0gf`N(LqT6f_ujrHY>3@ZYdY^E-Km6dvsA>m(F@$yccnv-US zbQvxr{aGflHHEuVu_06pG(iLI@PQ^}Kt&aJXpP}Ws!id{m*BDPh8;bU7^T&-N&gub zY#)m~I;m6hi0?&gkvKybw8v38ONZ&eDPjGsi=z0yv7dkIlk5QMzkb|^ZTPzFnGeUI#{5Wxed zgpb=Zm5Z7ROux_&m85Y})l=DUl6$n#=_}>?MD)KL4`1__G2!5mr7xLE!u#a|=Wsh5 z%2@PzM+MuNVAsgZw;2+>MpG|l=daaYd(mapiMxypVt(L30tN;#%}0k86@%v?z%>i* zHo4I@q=wK-rV>a)C=lEbn&thEnc>TotZnmJ^PY3vUz4_f!n(_A4xBDqvOUNsJ#Op4 zuQhdC4Lf}NAU#QN!{-S1EB0vavpaXZ(3Ma({(N%ojy&}=_t&RlrwNEhlwr2ZLpryL zm=@0~E<71+=9lwqvh~M(S0=AL6SAoBN4|OWd2KnS!bVZF(NnJEQ*0MaB3U9H7Id2* zUZgiu>FGi#nOT)fZ&a+&|2nVZ-T(7O#x?79{J8D-{+Ebi_OmtD({DVLy2V}I_9-YT z?)<~Jd6Q2~{bMvgE_?f`L;`TGC=3V!n zyggCHe061JsqwoxTUX3@e)rs|Nj6i>L;W{L-QyCNzH({TJNdPtzM`?dy0&HmF9x$fcLqWJ#k2aoMSm=W!x!A})%V!xPb=%K2uPRD7@18bq*>A&-|Ct_LiYk2fFsk=a%n{ZG zsp*fT#7oZ_YZ*U!&|bChmr;V#wSUi2t>r6u3O)HIE^Sv+)>}9;Tzq=Pr`wBmsPeCN zVg70s1{1^WjW=-nbqCivyK_LxSZCAT)D``G_7BA&aoFd{~pC?-=8>b*{zG>xvMT3Y)W+sJ-K2!dwN`KOw!Fut2&-MsQTfu zH~eVeq91#O9^VK)rCs?|Oa6QB*E!4n8h)&2d}Ndi?v*rLZT`J9aU!IN*RX>@=SHk6 zsLz4B?*W=F2N#?hJOrmNgN@?2K}K;vlZ4uR+djS7w>>kktv<1?R_1-}&YN26j?LOL zZ)p_s-1*(?>bu@@|yx#Q^q--aDN zzA-GbXYZ|cpL@Lge9W#L2iqALO4pqdU4KFJ=+YJMw`8nOHjgp+#jdEwpskGB*$_Q8 zg?G_bweCgFAHDp#xB2p$nWtYm&+=f_*}cP~`Udaqp7om(uB|wK`JaKre$P0)e`oh= zi>Ozs$tGHFn)P3D?xM@;q5TejHOkJrz7Hr2KlCH?-cM=e>RA>{3VOO--CM*idpt_J zxSW0Z(Z_p*pK5>lcv4Q@;DFKf9Z%Q-0%M+JPoB}W+{rcO-_~^})@gAr4an_!I&b&B zbLW2veii6@81439nTmqS^Eq$d&)sir1nwu#0r!(lLrYv+f^}p&mG#2Ax)N=#8z8~7cxd1l@gC{bG`fKvG%#MWuHZ! z@3NHD-ZY8L>CT~9IWMPQG}v@l<>U4#-9JvJU2cl`nQ}1T;ZJMjZ01kQ%pIp&j(~@5 zW(Ak>N;4cuEfN$Lo6F3Qaja|#dkcfW^qcoWSr{0uUbrPFkjDrgMMexJ3y6bfBNz$| zACzT)R`D(A067iR9w^LQeC+A9t(#4!|6ymiU@h2o?V`N!+hfUF>(-^~M%BM=5Sez5 zJ;JJRqOVx~y6d1O@Pb`}OWO<+%R9p_d@s|H>eUhS{KfC%5~G%9nIWv87mTHAJT;=@ z;^E3e-S@@6cJ#S0E5=T0aawuJql5cE7FzSP)iAX=WB18N_YP)$JM;9*!fP(SyuO9} z5@Lvmu$iS4;{4iu$K*1ZkhXm~b?c-y93WZ>4*E9;+U<0cfpHdH&!Kl?>Quu1QPNcG@go5#|OJPSoKZPe~w z=FN$SUHMg@&wAz~hR%g{H~)PqG+Gdr_}JE0Nv{Fa$%V8)PS|0^PJQjK{S$)YbkAIhy3i~BjEwkw{ z0bQpGeM~>{glg%rF6V66;o}7DKAGmXe_PhYb@Zs8XyiR+hVF{+z`BXsiZxy)A5Qyr z*i-WURolL@iuYQVl(la;K7M|5a-+`FjC^l%3?Z`c*D}d={nk*lJEaWwqL(I&@0&Wo%fm(UQ!$v&uaD`QTffUZ0#dd z@4d5Qe~y{%iK+f#JgIZ)7Fb+g^I@rlxWM$z4p4vVz>>(l5{FyzS=k-Hy{?YaS8nuu zY7k&}WVCvB7XyR9^j%L+{+@R<0Ww>xIm`#eA~Q zWt_XMnXO@JviYT1oTpsh{eAr?+<9-=DfUqBzeUW(2b8+OD>wGKO?KV;QGj91iXAO3 ziB+$6^ppqG*52Oo`J#n8i$lyUVbpP;5Ml9Oyo?HZ+^Tw&myev35o9RL42@xVe!f&* zrd;mc%a|AC-iLKFH@hr$G+|h?X~&cEZ+=#r-C%)B9a zDtqSy=K9Gge^qCyo~RP(ue@Tn!qDlJ>dN&Qp9TN6J(>KChgo;c<%y4fsszs2QKe=( zC;b^{U^WOe=i(vCc;JYVo|fH2R^3PGH5WPNmx;(OI_LQJsNT-+DH|srv4103#ccWW z#KN1C5}1ypvVl`#Hz*|@S$aj$rmVcgiIxCOvN3(o>ALJliZk z!|V}L$7vq;g3+MWerD&^vP=)0xnPF{``2kFGR}9u68pN;_%LY5+j|v9189)@mV)l- zr)wD^rgU)oiZLdXPF%TYSNCoPhufeA^=kK`Y!ge_hGma7nVsbY6_X9FLgHo+u+1~~ zvM8LxnHMZR{r;~z&l%Dj{waSyn_qYNm*O95+|{I=N0rCz$WUp?BIy6eAp^}uk!ia>G5?p zOQ(0Wug;T|=i2*k?xwYic8hd(7fiXn@3ZVf?fw7H7>n!IeVmy-Pn7NRt?c!pJGdV) zfn9TZPDi)FRPp#4!*b^9v072yrLRA9pH8>?Ecu%C(T)8Rb02N2aC>9CZ%0Q&_l9Zp z8-7~SV=FO&9He7^nr_xhJTZ1FQ5ng(q#{C(}rv^{sEYP?^c`qui~?Pg^E zzD=grRKChSN?d&RZN{ys+)g2W1Eu5k#F&;9c_Om5--seyVLk3Rm(UZooS zU;F%95uQ-z7?XHGw$E!>W83!Z+fnoNxBbt_`XYb!|7f-UdGhzkZ-3YOg~jaq@^=0* z<^BIJ=htUG+ut2mV{HBFcmBQ`kKVgj_KTg1xBeS;uP&Esv;CfLi?3heZH4n9_;bH^UARbv$LU8(ucGwoK6YQ5td#zxS^f`0q2NO?U(LABrjumD zW6pH=avh2&+{KrpXvuD*J zhWf7_UD94G^0B-;Wy+xws$VasfBW8k`&g)r_d%8Exm#zi=AI?|qdb^%?h{YJOBdMm zEvDJ28vj%LzH#4czi2<5u6?5Y$(`L2r>ZLV98SnsKIeCde2<# zaO?03U$)$~{5|dH)1&6me~$bW|5$cpX{&$y{}<7}4J)p1*X`O-v*^>dCyzco^470? zUw!{_c8pp5bNPFFDnGxDuixi(#I;+P!@HwwQ+HJn@3ip0DgKXD(`?)8mQG*q>*})i z+TF{$XK$J2u(ac!)87cz;8QuuFND8s*(|uK!`tI@jI&eBGG)EBmEJ<@^RGrlS=Ub0 z%Chvop7mhq-VWz~d}sds_~p6%+y8s_zvgl)>N&Z$9e&tf|L5_eUy&P~MO=HcW5gU{ zS{BFbuZvCTZrRcJ(U1RT}&6ymNcWdT&S3aw(+N4{L7R@_3SD|7}!H30Oz1}YhEkdvOFFAE;mSEw`#vNPobc-jL zW|{|HJNNMG_B~ra=f7<~Z}B+H{@*vgeLGezii!DFbNjg6w~Z>EDoh^U+ImXnU*4~e z6~0zfQBm>l^Zy+ePwjlRHBv3O?c#~)=7B{E)Puc>^rHAQ3Qm51|7=NDS(~fm>P4C} z5B6K+1XqLyDi?ab+i~rE?4o0-w;n0|f0O+-{M+<>f78ldY zs@@{;@}ldyHmE7_0HpuJ5F0% z3n~boxTZ05<+MFPUrk?E*?)STx=AQ%cfz%^vnzycf90)8GqcMJTfMq6^g+b8DO(sO z8UOUr-?EVF$kHd~6?mMR6x}#)nY1pz($xTi%0^(+7+cbBb{^MUXZNGGO zxI4!o$@5f$y}FtZx=|7*|wcx)1z+x>EdPp6}iXSc7W;)NOjZU9TCHj n1``L>P8&CF+<5llxBraZ3*;1>ZWrAEHJdzL{an^LB{Ts5hL}oI diff --git a/doc/qtcreator/images/qtcreator-locator.webp b/doc/qtcreator/images/qtcreator-locator.webp new file mode 100644 index 0000000000000000000000000000000000000000..c97a1a7634eca7a565ef85112a4c30916f1ef37e GIT binary patch literal 8168 zcmWIYbaQ(k&%hAw>J$(bVBvFFo`FICMpF<&QsRYe6IG_$zo}kkUCyAC#FS#p&2ygj zziwmh*=Z`PpDb{S((6{W3iwrMa^aVn@?qA>?|%YJ&J=#Sl>5aw?R@4Um;d`ScY6j^ z%iZ3V`}xVyHMzI9LD1gwcE9J;o&i$>#$#B4E(vK~MWy|iayati@chl_r zx4ZLlZ9mc;0{w;=CirE7lHnzALu zaVx|5rW7x6wibLV=g{zAPVu>I35VVpo$4%a*ykADaNw>Ad)(axx0_2|J*$y@=yvaNNA7nQupQ(bkFE$7;dH>^uzv#mv^=XcHg`Q?-N&e^ZF z8-FfLlaTI}K2u!1tERX#NlLm`xc%Fw#dnOBd`+1#^Sk>}n?EXwf7@jo)hnH}J2$>f zzkS4NRc3lgOwjGS3Qrq%_$tV{m|6GS=lJ}ArCj2t>7Aao({{T==G+O5gPwD-Bk+wH#ucNW;^G8dWSd3ePnNR*N{GFt=qI z_s%sQ4;Iw*hcQl)7klVC=Rv{EcNb4AsjT1G%~_Kytt~dmVP@9HIo<51PITD0fv4QaRKwi-;D;lTG%Z>z4(n$(ikm?&R{ zL%UwDnq~Ym+v}Xdz72MFyw$5OiKm>DWxJ{IF{AV2#Y2heY*K2rQri?eG>@_!x|rh| zcle3AbI)VXg9X}QQ)GH2j(?P>HV?3n-16V^nTx+BuVR?(teL-GWe7+cEwh{TSmVg- zMDH^t{+??UvKAaT@$gHs;M0o-r@wrBZ?Rg^YR5mK_nxoy`t@F?yWm^hvtc;qkeT)5R$MSAF)C+i2*E$LlM1OMjR>_gCMqqq;k0 zsBQgPr+%*Hc}C(o!ByqCYFk65KbvYYQ+?G}lUdhP7VEE=_L7H7Vs6iam#o@ClkYY5 zJWhSAtizG7mBxY$6JK6q#*TthN6=HJL6t{P*X6BxF*f(+M zhI_vwSBXn4+x&9h?mOFetaRhFdYrP)>g1djQ`W0Se_!*nPSc;T$-{c`Q)|ONGyX+e zxpx;zE}kaob-d{a3-gK7-fn!Wg`Fi9-{;}h`?hC`#(|_0I`Vz@`4tLg#7=wG^!Rz# zDutAW3Cr9yUlsB{UY_ib)Fh+%>64Lzm_zW-uO_S3)r8)?*}q`*X(!3wf2Et|%v&V) zBj(LHS>eyV0xGfUr>7aJe^pI*xboiC%$<`eZ2Op97yD_wT6H62+tl?;v+|h~BZIDI zxpADzn{02O8?vYIMaZ6Wvc;c$3zmG+U7^LPRm|4j8{jaT(o(Vpe+WN+~Cn$4XTkYpbH<3g|h zOqCZqAAet5&A!dKnRiEJ&%OUQZ6|(x){?f3EoqfNr{c4g$u$fHk80fa%}bh;5K(Qu zWyX}rLb+l2OrH`bw;s&O^{mj^Ri0oy>-w$2EKi4wXeGlVcOqU`KRV;~#yyB=UTtui}>8D!09P2Tk^80@ckBJlN$`}6Mc9r*;<5Vc|PFY>Ct1To{_{*>)vxy zBUyUO3t5k;Gp0-y&b>BIf=MEKA7@KTubmIqf2q6H8)T(&CM54YFC(fx^T3e_&YY5- z8Apx>r<+yocX_k-_>9eh(goaKWDC=jAGw~|bKOx@?dcPjZZp59*Dr5M;9IqPLh$0H zr@~Lx7SC=`t@Yr1vgvAS?7eaptF>o#8b7bQZ_f5Sxg^xN^JdJ&%=_kZY7^;Gx!=2psI=j~E_QTzGHK1;=xclif880OvID0Z%V}=iM;xw!X#XfS&tm%4&uNCk1NWFZJ3u_e`9^tk=KU{x5LeB`%o5Iay}q z;r0i@x6gPi)&5I=IYs`wyy@Yc zl_tOTC2D<9H4T-U^vCQ-%ml%j4QDSn=oU8!JHOJJv@ieG>)MPLovKHY{`|`Dep{^a zBVo4UKbewiE{@ATr7vCUX7xyd^;>Q5rY@%6`#4$8{(OJOQun~lY5P9}ZK6z(X@$ufH7UjQo)l2THn)2R`tyeTHm`jp-Q59#>&ZA_nh`Rwmf)aCd1d? z^-X@ARnDc{N%JyfR6mqW=UY(B{%d;T(J$tQZ{}La$cetOXJdY@bgiQ!UwFgR#Q#QX zX8cRD*v;F1c=4jY>?)DJIt}$vf49L(rCAneczq=|kivOOTFfS9Vwm0o? zUP?vCmj4~LH&Tv#e(a;(HfOeQ@Gn8%trEZ0bvrhJm3BN_#y8tRVddWaF9qEl)(Wn& z@N<3bZ~JcNrIj_$*EasYCjXW(TrX;;_fzfSiE3p(879qM;AYBvr22i_qS+IcWjwkz zzbWhT{QXK)}-Q%Aa1@!W*YrA1*PwyFAnPaunZu zj@6e=+g0Tp%|8~rLN%kL#9(KB+!5w>y{C6>dYu3L$JhT7XKK@}2d~SExHu0V>6~M& z-eY}5_+G^lHHrILcjwI5RL`QIZ|oIwbZ7E~hKUtZZG4>V(8iWp;;G?L5e8 zzDl?6Z26-rf6WXlckYbcY5L*8pU=UY=KRx^b@cmQ)4S31gTTfGfu-haW=S&_=3IMf zcTV>IwwFP5vo3a>KgXuJpfc9^xz()(q2%YrXJ$z|N+{$A6zmapezu6&Yt7vA8?y3P ze){>CcXDr9YL>bFyX@zXeVe@wbLCxMTl4f1m#gEdU5aO|w>CZcd9bs?v7Q|ENeVbt4x zY>&0fL~9rA_(a=)duH1U42@&Xe*9K-|K1r^iOH=M_s#Fjjb1%>t8pOL)xHE1>t#hO z&4+#cFKt;SlGUWYrD<<~FiZNKmEMn1dmhP7E?iV7Zk)WJ#V5jHP8FNX`ekl&b~2pO znDnvPPgqH=Zm!kJ{0+APx8}3dTDb3km?w8|zdpOUw%B0p}ZSnC1o96FqWM8;l|Ju^xnCE>O*=%y=lD4zt zWUlW_)^d%paqT=OtFqA9eRJ9aO~2)S7iSl@&kb*A>R!pp++P!j&WjP0@obUGZ2ZhUnfBLWqsur_c?^Eo)yH+;1(%@YEyW(S; z=dl@nII#K0DaIMAEY7s7y}j^i*3Mb0tbaT5*u2o0zO`j-X;s9zYYO2#`I}l>3xhK= zCHBS@zc9Kq?^>VY>_o}-gA)T@n{NzW>;EP`A|hI{NxI#7OKEWCmz6SpuD%RbHL3rr za+xG6HUwWk`e|jC?b>Uu*)!rJw*I(d8oJOJR6M?#9~*pIRbV1Z#_RQeyJgQ`ybu`n zR9m}os$##4BMML-_Q#|-FiFxLv5_nEJ_~E z{ax2(Ve=}4cjLcc(S*?UJJ046EtcK*e!luz|2OxUX=GpQ<*Ts%58LMo+rZvn`E1Q%T zyhuP{NulxRsbD#g}rk$-cpKlt!_ve;>S54*fb1cfANU@8DG6+oUN)~Y8 zTk#_}$062fA8x&_j{jZ$o=I{*1Rn;&WKs5tK_)jzf^h{gMeb8 zPICqm`*FrO*6VcMD|lQg?>WKpz{uF*!>u2G|18S%RiDziSj)o0eB#t!j9ZfeYge*g zpV9ODy2@6$y|yMLLg$}w+8w@FGJnC*pAK(}Zg1tfT(%=UI{MzXilZ#N=j3euGGC6J z*|O|)__R6)k4?Ve^IYf8d~^QK8$I@*^M0ICZ^CChFn+_9Z_at=i%RaBr5ha9(XLxGSx>B)X3-}&Q-ST~=G7ZkXlc#=c~iw*W{Xm6fAI|+pAV8Vme>5M zUaB9RTiMZKoJaXMDsmKeBJ}m)gVZajVvcER}d$T!V{hCtE#=eNRkOc`lZ+;M>gkqA_P8Chp`B zQ2)WRt5Y$v@bbRk$t{6X%67_caj$4zqpq7%JKJ%sx{mO%r5(AIlXtA+Vch@cXP#Q! z*A{=Ky|SOyZEeW%&tCQDLY`u&MvvR?_37FZXDDe&2hZAc$H`bTX_;q{;U$+#N}Oj^ zc391|TDs!VPty{y^Y1)epBp*Md0>2J*(dMivF~J^%?@vivy@x*HP`E);lv#x8+G$9 ziS1~L$-elb({sVL#cwsUwVd*2SXuLJeyHyule(>^s2K#gt$1p3OLEwbZV)zv}~Bo1c}Ta^@r=% zIjt+X_4JtXJsbJV+Ulo{4%z=MPwd_!wlK0T-gL1*dC9vCi?RZ2_BZHrJS_?5 zQMNgy!s&b6y0avP(faL?JsZtJo;Dr*9vb}D>0RErxeB)|1=@liIPfT2+;MmmVOO8f z7X6Ty4{-o=|Iu%RTJH=Pc6xe{xY{|#c9iOks$9dACpkQ zw%(ZwR~8nVu36&ce3zj|jD&1$S-5BhoR!j{KZZqBj3HFeuWudCTN?brVh|995zebf41Rq|=JKBo_r zUOmCRF4v`ft5R#{-@DBD^rqCK}&f z|2^}wUftZ^d*9^QdCS;C9LkF>-~2LP^upXbCFZOq79HxA;aU@|cfQPd^uIDwwMgAu zR$buCPUWkLYdqdPS$4bQy@;piskwJbBn!jdaWry0^~>AUqhoGZ@?!o~wW%jS5}mJC z{#kWPJl^%%r}VD1_Mv`OzIE=8b`>qxx-!*THSN6O5=Z~)wqLvt)?|rjm46BT>y+oW zc5%{gwgR`{bFy;{bh+3jyp=v6DQa21=4LUIeGh}D?%{1c)g^N0C*@6kt-Ab49z(jz zqdObF9bjgum0)~u-ImqG=xF*S+uJ%jr4LBXv?$lPS*&Bz!?5qy!zm8}3g>oCxx@RQ z$77E5wKtZH@@@=!e7-Sgt(86?IoASaMFn@(iVfN_+pYvfnKu|;DtISye4g-!L>7hW z&p#xX4PqY_?0o_@rNaN|<8+@Dq5Fic`5ewaSO46P<-wi6$2kQD>~8Cx*LL{2?rcIu zPxkS@v-Iu0oY(HFUSajpO!u+jy1A3A-pQUjCu`d`x6AQSg^bG1U~xsKtE;D5t(lZ( zd_rcy%txK)0}m9u{#jXA7jQ0iH?Pi|vP8S}3~Fi8&Nd${xf1r+SsY}1v-P%uQN?a= z_9;wf8D}ZZ`ys;`aGW;J0IUkT5Hwh z^MPmHVumHG=c3d&Cv_@*7t6jXn9^~4N7;p@<}IZ+T(~&yuKZIa6&k*8)w?&=`K32c zeTuZ3{rUdR;7;rEhIyx^uiLncMLyPd;`Se2RzHoiQV?Z*9_!9~$$()};%rj)WVn+2`BX2bW)FU@!P-klle=cN@g zE55(8@b$zuIlk4KpVU84x!-p7%u=(1(?4!87yo?ovd*GI*LF7Rf6mO;d$xJ`OE2{{ z2C@^8-nb90UNmcN^_!q$Dog`n4sx8CQ^x*{d+krO||cge#$nv1#* zZrgSK=-oioyUSLB1UW3rduA~4wB7#y{qBQJwTWhe-Nnm2zRh_Mo_zW5h1%k&@^&qI z_^rGTPhP$9;JE^gl#{VDd|Mve(LC$EMKbagSMl?L)v@nhF8O%j@!9609)`JkTPE!` zn7!iQ&R~&hzYD83Dhhm^^8Sun55r7|%%|6P3>8{dZ!`>fzmos<&GZM%E4JvJQ7bBV zCvtM0@SCihj7pVrE$4EVa9sEllo>n2SLERx&5iC`X09qvJXgBN`Qc0s2N8DFA1yg< z`<8zy-N)U0D*Vta%?+FnpKfB6`G5U~;{Wxo=T~fx{?ef{^}cPQ zzx+G7vtR#AbyeoS&)VFvvGGry6&j zSL60aJ$^ge^#0!1*ME0kzV`P^;okG}ul@g2*}Oj9?AO2C`Mvcu_n$oP_pSfCCOm)h z{ry>aAHVmnem(8~zezV<{kPZJ#`f>A*hJASb9)rNiSW+pvcHiVuCi|0%5!e7XaC6B zxA`=8Ow8SDN!#;v3%{QW`u;vJtoG}q#KZaVopV{|N4#>|DdTKs7Inz$;m^Cuzce#t zHx+J}|7cpxJ3-M8g287uynb>ia+_c2{IH)p6%U<~yQJ+mRcEiz%jnc?pVnQet*T@# zIdakDrQX(>Wxc}2Yh-_KINtN>hSV{sC#Bs9tq%jfUGex7wJh^r@XO>1mkF0S+!~r5 zI2th7H?3(?yW-v38SKAsol0co_uxy5t_ZDO^7@I8<*`NEiw>0wzcDtuBKJPzYVYh1 zg>`j{oaY~XDp>WivblQ7MfuBtZpHowBE18=crF^8_&8aK!E@7rZH)$k7r$TiHSBZP zv%aq)&><}-yGr<;oiN`cpA)+uYtCF-`%5ox+wxoAKkTiMZ17oX@A-%0;~t}Bd+pQW z-xogeIkNSM(U+fFI}t2dziB^x2IH1Lh;|jdFLfR{n#2xGhiDE!fb|+jJ=1p)@$wSGP_$t7fkgEg z(GoAJf3#fPsgnIKHf~$VjdQ2o)<1JE_rG3S*%CgT)3tHqo%Q?qlso#7jTVZ_6wjaA~W-|Qxu-iW3nmqgG=Lgf7D<8}2EaqVO zX&|9^?tK0$o|Xj~dlxKv-RPY=+a~=;^6&Hy%u91LS511i7l-+I)XUXyt^ER*Q{uX}i+s0xMuloC+ z2j)MOP!N!iP&9g~%Cc0R@%*fIdE=@1{};yJ3;QqM!@+vAdA(@hQ{{WVpU13>sM-4A zYi|iw0qc5fL1wmuV&|Kgtd@5A5s_4SM?PuZVmHWc2ldD14I*m;cq1NTdQJLgZb zP7lm4rEcBa*(bc=e89G!pHK8Fev|(t)#26gK>nBVkVbPUF4_1`}13+nTf@D@$kOneK!`l zUul_qdj4L|facwKOGOWed|!X}C%@fe$JC1t9#}lFK&DCt8J}QmWY}r~91^`hc?I{2N literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/editors/creator-locator.qdoc b/doc/qtcreator/src/editors/creator-locator.qdoc index 232b5587274..e5a55f8d6a9 100644 --- a/doc/qtcreator/src/editors/creator-locator.qdoc +++ b/doc/qtcreator/src/editors/creator-locator.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -15,7 +15,9 @@ To open it as a centered popup, click \inlineimage icons/magnifier.png (\uicontrol Options) in it and select \uicontrol {Open as Centered Popup}. - \image qtcreator-locator.png "List of locator filters" + \image qtcreator-locator.webp "List of locator filters" + + \section1 Activating the Locator To activate the locator: @@ -32,43 +34,35 @@ \endlist - To open a QML file called \e HelloWorld.qml in the currently open project - using the locator: + \section1 Using Locator Filters - \list 1 + You can locate not only files, but any items defined by \e{locator filters}, + as well as trigger global actions and perform other tasks, such as build + projects or run external tools. - \li Activate the locator by pressing \key {Ctrl+K}. + The filters that are available depend on the file type. For more information + about what a particular locator filter does, see the tooltips that appear + when you hover over a filter in the locator. For longer descriptions of the + filters, select \uicontrol Configure to open the \uicontrol Locator + \l{Creating Locator Filters}{preferences}. - \li Start typing the filename. + To use a locator filter, type its prefix followed by \key Space. The prefix + is usually short, from one to three characters. Then type the search string + (for example, a filename or class name) or the command to execute. - \image qtcreator-locator-open.png "List of files found in the locator" + You can also double-click a locator filter in the filter list to use it. Use + the up and down arrow keys or the \key Ctrl+P and \key Ctrl+N + keyboard shortcuts to move up and down the list, and then press \key Enter + to use the selected filter. - \li Move to the filename in the list and press \key Enter. - - The file opens in the editor. - - \li To move to a line in the file, enter the line number in the locator. - - \endlist - - To move directly to a particular line and column in the document when you - open the document, append them to the file name in the locator, separated by - plus signs (+) or colons (:). For example, to open \e HelloWorld.qml to line - 41 and column 2, enter: \c {HelloWorld.qml:41:2}. - - If the path to a file is very long, it might not fit into the locator - window. To view the full path, press \key Alt when the filename is selected - or use the handle next to the locator window to increase the window width. - - It is also possible to enter only a part of a search string. As you type, + As you type a search string, the locator shows the occurrences of that string regardless of where in the name of an component it appears. Some locator filters, such as colon, \c m, and \c t, support \e fuzzy matching, which means that you can enter the uppercase letters to locate a symbol when using camel case or the letters after the underscore when using snake case. - To narrow down the search results, you can use the following wildcard - characters: + To narrow down the search results, use the following wildcard characters: \list @@ -78,117 +72,69 @@ \endlist - \section1 Using Locator Filters + \section2 Locating Files - The locator enables you to browse not only files, but any items defined by - \b{locator filters}. The filters that are available depend on the file type: + For example, to open a QML file called \e HelloWorld.qml in the currently + open project using the locator: - \list + \list 1 - \li Locating any open document (\c {o}) + \li Press \key {Ctrl+K} to activate the locator. - \li Locating files anywhere on your file system (\c {f}). You can use - environment variables in the \c {f} filter. For example, use - \c {f $ENVVAR} to expand the environment variable \c ENVVAR on Unix - systems and \c {f %ENVVAR%} to expand it on Windows systems. + \li Start typing the filename. - \li Locating files belonging to your project (\c {p}), such as source, - header, resource, and \c {.ui} files, or to any project (\c {a}) + \image qtcreator-locator-open.webp "List of files found in the locator" - \if defined(qtcreator) - \li Locating bookmarks (\c {b}). - For more information, see \l{Using Bookmarks}. + \li Use the arrow keys to move to the filename in the list and press + \key Enter. - \li Locating class (\c {c}), enum, function (\c {m}), and type alias - definitions in your project or anywhere referenced from your - project (\c {:}) - \endif + The file opens in the editor. - \li Locating QML methods (\c {m}) - - \li Locating symbols in the current document (\c {.}) - - \li Locating a specific line and column in the document displayed in - your editor (\c {l :}) - - \li Opening help topics, including Qt documentation (\c {?}) - - \li Performing web searches (\c {r}) - - \if defined(qtcreator) - \li Running text editing macros that you record and save (\c {rm}). For - more information, see \l{Using Text Editing Macros} - \endif - - \li Executing JavaScript (\c {=}), especially useful for calculations. - For more information, see \l{Executing JavaScript}. - - \li Executing shell commands (\c {!}) - - \li Executing version control system commands - \if defined(qtcreator) - (\c {bzr}, \c {cvs}, \c {git}, \c {hg}, or \c {svn}). - For more information, see \l{Using Version Control Systems}. - \else - (\c {git}). For more information, see \l{Using Git}. - \endif - - \li Triggering actions (\c {t}) - - \li Searching for issues from the \l{https://bugreports.qt.io/} - {Qt Project Bug Tracker} (\c bug). - - \li Searching for applications, documents, and other files by using - platform-specific external tools or commands (\c md). The following - tools are used by default, but you can configure the locator to - use any other command: - - \list - \li On \macOS: using Spotlight - \li On Windows: using \l{https://www.voidtools.com/downloads/} - {Everything} - \li On Linux: using the \c Locate command - \endlist - - \if defined(qtcreator) - \li Running external tools (\c x) - \li Using CMake to build the project for the current run configuration - (\c {cm}). For more information, see \l {Setting up CMake}. - \li Opening the CMakeLists.txt file for the current run configuration in - the editor (\c {cmo}). This is the same build target as when you - select \uicontrol Build > \uicontrol {Build for Run Configuration}. - \li Running a particular run configuration (\c {rr} \e {}) - \li Switching to a particular run configuration (\c {sr} \e {}) - \endif + \li To move to a line in the file, enter the line number in the locator. \endlist - To use a specific locator filter, type the assigned prefix followed by - \key Space. The prefix is usually a single character. Then type the search - string (typically, a filename or class name) or the command to execute. - - You can also double-click a locator filter in the filter list to use it. You - can use the up and down arrow keys or the \key Ctrl+P and \key Ctrl+N - keyboard shortcuts to move up and down the list, and then press \key Enter - to use the selected filter. + If the path to a file is very long, it might not fit into the locator + window. To view the full path, press \key Alt when the filename is selected + or use the handle next to the locator window to increase the window width. \if defined(qtcreator) - For example, to locate symbols matching QDataStream: + If the locator does not find some files, see \l{Specifying Project Contents} + for how to make them known to the locator. + \endif + + \section2 Locating Lines and Columns + + To move directly to a particular line and column in the document when you + open the document, append the line and column number to the file name in + the locator, separated by plus signs (+) or colons (:). + + For example, to open \e HelloWorld.qml to line + 41 and column 2, enter: + + \code + HelloWorld.qml:41:2 + \endcode + + \if defined(qtcreator) + \section2 Locating Symbols + + For example, to locate symbols matching \c {QGuiApplication}: \list 1 \li Activate the locator. \li Enter a colon (:) followed by a space and the upper case letters in - the symbol name (QDataStream): + the symbol name (here, \c {QGuiApplication}): \code - : qds + : qga \endcode The locator lists the results. - \image qtcreator-locator-example.png "List of files matching the locator filter" + \image qtcreator-locator-example.webp "List of files matching the locator filter" \endlist @@ -197,16 +143,21 @@ such as \c {Utils::*View}. \endif - For example, to create a new file and open it in the editor, type \c f + \section2 Creating Files from Locator + + To create a new file and open it in the editor, type \c f followed by \key Space, followed by path and file name, and then press \key Enter. - You can use the filter that triggers menu commands to open sessions. Enter + You can use the filter that triggers menu commands to open + \l{Managing Sessions}{sessions}. Enter \c {t yoursess} or \c {t sess yoursess} to trigger \uicontrol File > \uicontrol Sessions > \e yoursessionname. - By default, the following filters are enabled and you do not need to use - their prefixes explicitly: + \section2 Default Filters + + By default, you can use the following preset locator filters without a + prefix: \list @@ -218,16 +169,11 @@ \endlist - \if defined(qtcreator) - If locator does not find some files, see \l{Specifying Project Contents} - for how to make them known to the locator. - \endif + \section1 Changing Locator Filters - \section1 Configuring Locator Filters - - If the default filters do not match your use case, you can check whether you - can change them. For all filters, you can change the filter prefix and - restrict the search to items that match the filter. + You can change the preset locator filters to match your use case. For + example, you can change the filter prefix and restrict the search to + items that match the filter. To configure a locator filter: @@ -266,11 +212,11 @@ \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Environment > \uicontrol Locator > - \uicontrol {Web Search (prefix: r)} > \uicontrol Edit. + \uicontrol {Web Search} > \uicontrol Edit. \li Select \uicontrol Add to add a new entry to the list. - \image qtcreator-add-online-doc.png "List of URLs in Filter Configuration dialog" + \image qtcreator-add-online-doc.webp "List of URLs in Filter Configuration dialog" \li Double-click the new entry to specify a URL and a search command. For example, \c {http://www.google.com/search?q=%1}. @@ -281,7 +227,7 @@ \section1 Creating Locator Filters - You can create custom locator filters for finding in a directory structure + You can create custom locator filters for searching in a directory structure or on the web. To quickly access files not directly mentioned in your project, you can @@ -295,7 +241,7 @@ \li In the locator, select \uicontrol Options > \uicontrol Configure to open the \uicontrol Locator preferences. - \image qtcreator-locator-customize.png "Locator preferences" + \image qtcreator-locator-customize.webp "Locator preferences" \li Select \uicontrol Add > \uicontrol {Files in Directories} to add a directory filter or \uicontrol {URL Template} to add a URL @@ -310,7 +256,7 @@ \li In the \uicontrol {File pattern} field, specify file patterns to restrict the search to files that match the pattern. - Use a comma separated list. For example, to search for all + Separate the patterns with commas. For example, to search for all \c {.qml} and \c {.ui.qml} files, enter \c{*.qml,*.ui.qml} \li In the \uicontrol {Exclusion pattern} field, specify file @@ -329,9 +275,9 @@ \section1 Configuring Locator Cache The locator searches the files matching your file pattern in the directories - you have selected and caches that information. The cache for all default - filters is updated as you write your code. By default, \QC updates the - filters created by you once an hour. + you have selected and caches that information. \QC updates the cache for all + preset filters as you write code. By default, \QC updates your custom + filters once an hour. To update the cached information manually, select \uicontrol Options > \uicontrol Refresh in the locator. @@ -349,8 +295,7 @@ \section1 Executing JavaScript - The locator has a JavaScript interpreter that you can use to - perform calculations. + The locator has a JavaScript interpreter for performing calculations. Beside simple mathematical operations, like ((1 + 2) * 3), the following built-in functions exist: From 1c60f57340bb2808d08169586e11e20ffcd0c987 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 19 Apr 2023 11:15:33 +0200 Subject: [PATCH 0590/1447] C++ editor: Make generated Q_PROPERTYs FINAL by default It's bad style to omit the FINAL because such properties can be shadowed, causing problems in QML. Change-Id: I9083c69128f6335f584f0a1d28f1fe1e54a02eaf Reviewed-by: Christian Kandeler Reviewed-by: Jarek Kobus --- share/qtcreator/snippets/cpp.xml | 2 +- src/plugins/cppeditor/cppquickfix_test.cpp | 22 ++++++++++----------- src/plugins/cppeditor/cppquickfixes.cpp | 2 +- src/plugins/texteditor/snippets/snippet.cpp | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/share/qtcreator/snippets/cpp.xml b/share/qtcreator/snippets/cpp.xml index 82a62b36e6a..ca62a37998a 100644 --- a/share/qtcreator/snippets/cpp.xml +++ b/share/qtcreator/snippets/cpp.xml @@ -204,5 +204,5 @@ case $value$: default: break; } -Q_PROPERTY($type$ $name$ READ $name$ WRITE set$name:c$ NOTIFY $name$Changed) +Q_PROPERTY($type$ $name$ READ $name$ WRITE set$name:c$ NOTIFY $name$Changed FINAL) diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 560a27fe240..9c2c011dc5a 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -2315,7 +2315,7 @@ signals: void newFooBarTestValue(); private: - Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue) + Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue FINAL) }; )-"; QTest::addRow("create right names") << QByteArrayList{originalSource, expectedSource} << 4; @@ -2346,7 +2346,7 @@ signals: void newFooBarTestValue(); private: - Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue) + Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue FINAL) }; )-"; expectedSource = ""; @@ -2355,7 +2355,7 @@ private: // create from Q_PROPERTY with custom names originalSource = R"-( class Test { - Q_PROPER@TY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue) + Q_PROPER@TY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue FINAL) public: int give_me_foo_bar_test() const @@ -2380,7 +2380,7 @@ signals: )-"; expectedSource = R"-( class Test { - Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue) + Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue FINAL) public: int give_me_foo_bar_test() const @@ -2411,14 +2411,14 @@ private: // create from Q_PROPERTY with custom names originalSource = R"-( class Test { - Q_PROPE@RTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue) + Q_PROPE@RTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue FINAL) int mem_fooBar_test; public: }; )-"; expectedSource = R"-( class Test { - Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue) + Q_PROPERTY(int fooBar_test READ give_me_foo_bar_test WRITE Seet_FooBar_test RESET set_fooBarTest_toDefault NOTIFY newFooBarTestValue FINAL) int mem_fooBar_test; public: int give_me_foo_bar_test() const @@ -2766,7 +2766,7 @@ public: signals: void barChanged(N2::test *bar); private: - Q_PROPERTY(N2::test *bar READ getBar NOTIFY barChanged) + Q_PROPERTY(N2::test *bar READ getBar NOTIFY barChanged FINAL) }; })--"; testDocuments << CppTestDocument::create("file.h", original, expected); @@ -3303,7 +3303,7 @@ void QuickfixTest::testGenerateGetterSetterAnonymousClass() void fooChanged(); private: - Q_PROPERTY(int foo READ foo WRITE setFoo RESET resetFoo NOTIFY fooChanged) + Q_PROPERTY(int foo READ foo WRITE setFoo RESET resetFoo NOTIFY fooChanged FINAL) } bar; )"; testDocuments << CppTestDocument::create("file.h", original, expected); @@ -3334,7 +3334,7 @@ public: signals: void barChanged(); private: - Q_PROPERTY(int bar READ getBar WRITE setBar RESET resetBar NOTIFY barChanged) + Q_PROPERTY(int bar READ getBar WRITE setBar RESET resetBar NOTIFY barChanged FINAL) }; inline int Foo::getBar() const @@ -3560,8 +3560,8 @@ private: int m_bar; int bar2_; QString bar3; - Q_PROPERTY(int bar2 READ getBar2 WRITE setBar2 RESET resetBar2 NOTIFY bar2Changed) - Q_PROPERTY(QString bar3 READ getBar3 WRITE setBar3 RESET resetBar3 NOTIFY bar3Changed) + Q_PROPERTY(int bar2 READ getBar2 WRITE setBar2 RESET resetBar2 NOTIFY bar2Changed FINAL) + Q_PROPERTY(QString bar3 READ getBar3 WRITE setBar3 RESET resetBar3 NOTIFY bar3Changed FINAL) }; inline void Foo::resetBar() { diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index dad99ff1344..1c76f8f2c57 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -4182,7 +4182,7 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d propertyDeclaration.append(QLatin1String(" NOTIFY ")).append(data.signalName); } - propertyDeclaration.append(QLatin1String(")\n")); + propertyDeclaration.append(QLatin1String(" FINAL)\n")); addHeaderCode(InsertionPointLocator::Private, propertyDeclaration); } } diff --git a/src/plugins/texteditor/snippets/snippet.cpp b/src/plugins/texteditor/snippets/snippet.cpp index f41156c4cee..74a4dc543c3 100644 --- a/src/plugins/texteditor/snippets/snippet.cpp +++ b/src/plugins/texteditor/snippets/snippet.cpp @@ -330,7 +330,7 @@ void Internal::TextEditorPlugin::testSnippetParsing_data() << QString::fromLatin1("\\\\$test\\\\\\\\$\\\\") << false << Parts(); QTest::newRow("Q_PROPERTY") << QString( - "Q_PROPERTY($type$ $name$ READ $name$ WRITE set$name:c$ NOTIFY $name$Changed)") + "Q_PROPERTY($type$ $name$ READ $name$ WRITE set$name:c$ NOTIFY $name$Changed FINAL)") << true << Parts{SnippetPart("Q_PROPERTY("), SnippetPart("type", 0), @@ -342,7 +342,7 @@ void Internal::TextEditorPlugin::testSnippetParsing_data() SnippetPart("name", 1, TCMANGLER_ID), SnippetPart(" NOTIFY "), SnippetPart("name", 1), - SnippetPart("Changed)")}; + SnippetPart("Changed FINAL)")}; QTest::newRow("open identifier") << QString("$test") << false << Parts(); QTest::newRow("wrong mangler") << QString("$test:X$") << false << Parts(); From 71f9e536c51818e0850b78ff2b62446339fa8c01 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 19 Apr 2023 15:09:49 +0200 Subject: [PATCH 0591/1447] Markdown: Fix that text editing actions were not available Add the TextEditorActionHandler and point it to the text editor. Change-Id: I2c84d6b0160c7402ea32d56ed4dbc72d512072a1 Reviewed-by: David Schulz Reviewed-by: --- src/plugins/texteditor/markdowneditor.cpp | 43 +++++++++++++++++------ src/plugins/texteditor/markdowneditor.h | 5 +++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index c04dcf0942d..94ccde4b3ae 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -21,6 +21,7 @@ namespace TextEditor::Internal { const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; +const char MARKDOWNVIEWER_TEXT_CONTEXT[] = "Editors.MarkdownViewer.Text"; const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown"; class MarkdownEditor : public Core::IEditor @@ -38,10 +39,14 @@ public: new Utils::MarkdownHighlighter(browser->document()); // Right side (hidable) - auto editor = new TextEditorWidget(&m_widget); - editor->setTextDocument(m_document); - editor->setupGenericHighlighter(); - editor->setMarksVisible(false); + m_textEditorWidget = new TextEditorWidget(&m_widget); + m_textEditorWidget->setTextDocument(m_document); + m_textEditorWidget->setupGenericHighlighter(); + m_textEditorWidget->setMarksVisible(false); + auto context = new Core::IContext(this); + context->setWidget(m_textEditorWidget); + context->setContext(Core::Context(MARKDOWNVIEWER_TEXT_CONTEXT)); + Core::ICore::addContextObject(context); setContext(Core::Context(MARKDOWNVIEWER_ID)); setWidget(&m_widget); @@ -60,13 +65,21 @@ public: connect(m_document.data(), &TextDocument::mimeTypeChanged, m_document.data(), &TextDocument::changed); - connect(toggleEditorVisible, &QToolButton::toggled, - editor, [editor, toggleEditorVisible](bool editorVisible) { - if (editor->isVisible() == editorVisible) - return; - editor->setVisible(editorVisible); - toggleEditorVisible->setText(editorVisible ? Tr::tr("Hide Editor") : Tr::tr("Show Editor")); - }); + connect(toggleEditorVisible, + &QToolButton::toggled, + m_textEditorWidget, + [this, browser, toggleEditorVisible](bool editorVisible) { + if (m_textEditorWidget->isVisible() == editorVisible) + return; + m_textEditorWidget->setVisible(editorVisible); + if (editorVisible) + m_textEditorWidget->setFocus(); + else + browser->setFocus(); + + toggleEditorVisible->setText(editorVisible ? Tr::tr("Hide Editor") + : Tr::tr("Show Editor")); + }); connect(m_document->document(), &QTextDocument::contentsChanged, this, [this, browser] { QHash positions; @@ -87,14 +100,22 @@ public: QWidget *toolBar() override { return &m_toolbar; } Core::IDocument *document() const override { return m_document.data(); } + TextEditorWidget *textEditorWidget() const { return m_textEditorWidget; } private: Core::MiniSplitter m_widget; + TextEditorWidget *m_textEditorWidget; TextDocumentPtr m_document; QWidget m_toolbar; }; MarkdownEditorFactory::MarkdownEditorFactory() + : m_actionHandler(MARKDOWNVIEWER_ID, + MARKDOWNVIEWER_TEXT_CONTEXT, + TextEditor::TextEditorActionHandler::None, + [](Core::IEditor *editor) { + return static_cast(editor)->textEditorWidget(); + }) { setId(MARKDOWNVIEWER_ID); setDisplayName(::Core::Tr::tr("Markdown Viewer")); diff --git a/src/plugins/texteditor/markdowneditor.h b/src/plugins/texteditor/markdowneditor.h index 21944657bc4..de87c558e1b 100644 --- a/src/plugins/texteditor/markdowneditor.h +++ b/src/plugins/texteditor/markdowneditor.h @@ -5,12 +5,17 @@ #include +#include + namespace TextEditor::Internal { class MarkdownEditorFactory final : public Core::IEditorFactory { public: MarkdownEditorFactory(); + +private: + TextEditor::TextEditorActionHandler m_actionHandler; }; } // TextEditor::Internal From f5cccab95b6b6f7c4b34b25ab31ce703bd15199f Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Tue, 18 Apr 2023 18:01:27 +0300 Subject: [PATCH 0592/1447] MacroExpander: Fix Path and FilePath on Windows They should have / separator. Amends commit 4fbc56d453ef2fa73e494f371bd44285e3ac0d50. Change-Id: I7218c345b271360f24c03aea5ee62be05342afe0 Reviewed-by: Eike Ziller --- src/libs/utils/macroexpander.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 2fe340efc6d..b1ce40d25aa 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -380,13 +380,13 @@ void MacroExpander::registerFileVariables(const QByteArray &prefix, registerVariable( prefix + kFilePathPostfix, Tr::tr("%1: Full path including file name.").arg(heading), - [base] { return base().toUserOutput(); }, + [base] { return base().path(); }, visibleInChooser); registerVariable( prefix + kPathPostfix, Tr::tr("%1: Full path excluding file name.").arg(heading), - [base] { return base().parentDir().toUserOutput(); }, + [base] { return base().parentDir().path(); }, visibleInChooser); registerVariable( From 99b5d93cfb1a4a71290dda280ad290c99ac5fa9c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 15:02:36 +0200 Subject: [PATCH 0593/1447] LocatorMatcher: Introduce MatcherType enum Use it for registering/getting different kinds of matchers. Change-Id: I6f944e0332bf8c512892a00b8ba88f9939f34682 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler Reviewed-by: --- .../clangmodelmanagersupport.cpp | 8 ++-- .../coreplugin/locator/ilocatorfilter.cpp | 38 +++---------------- .../coreplugin/locator/ilocatorfilter.h | 15 ++++---- src/plugins/cppeditor/cpplocatorfilter.cpp | 2 +- src/plugins/cppeditor/cpplocatorfilter.h | 2 +- .../cppeditor/cpplocatorfilter_test.cpp | 35 ++++++++--------- src/plugins/cppeditor/cppmodelmanager.cpp | 11 ++++-- src/plugins/languageclient/locatorfilter.cpp | 2 +- src/plugins/languageclient/locatorfilter.h | 4 +- .../jsonwizard/jsonfieldpage.cpp | 2 +- 10 files changed, 46 insertions(+), 73 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 43b41e54f9b..40619bc8ed1 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -214,11 +214,11 @@ ClangModelManagerSupport::ClangModelManagerSupport() matchers << creator(client, 10000); return matchers; }; - LocatorMatcher::addLocatorMatcherCreator( - [matcherCreator] { return matcherCreator(&LanguageClient::workspaceLocatorMatcher); }); - LocatorMatcher::addClassMatcherCreator( + LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, + [matcherCreator] { return matcherCreator(&LanguageClient::workspaceAllSymbolsMatcher); }); + LocatorMatcher::addMatcherCreator(MatcherType::Classes, [matcherCreator] { return matcherCreator(&LanguageClient::workspaceClassMatcher); }); - LocatorMatcher::addFunctionMatcherCreator( + LocatorMatcher::addMatcherCreator(MatcherType::Functions, [matcherCreator] { return matcherCreator(&LanguageClient::workspaceFunctionMatcher); }); EditorManager *editorManager = EditorManager::instance(); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index bd68d602f1f..8b7c924a2ff 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -427,51 +427,23 @@ LocatorMatcherTask::OutputData LocatorMatcher::runBlocking(const QList s_locatorMatcherCreators = {}; -static QList s_classMatcherCreators = {}; -static QList s_functionMatcherCreators = {}; +static QHash> s_matcherCreators = {}; -void LocatorMatcher::addLocatorMatcherCreator(const LocatorMatcherTaskCreator &creator) +void LocatorMatcher::addMatcherCreator(MatcherType type, const LocatorMatcherTaskCreator &creator) { QTC_ASSERT(creator, return); - s_locatorMatcherCreators.append(creator); + s_matcherCreators[type].append(creator); } -void LocatorMatcher::addClassMatcherCreator(const LocatorMatcherTaskCreator &creator) -{ - QTC_ASSERT(creator, return); - s_classMatcherCreators.append(creator); -} - -void LocatorMatcher::addFunctionMatcherCreator(const LocatorMatcherTaskCreator &creator) -{ - QTC_ASSERT(creator, return); - s_functionMatcherCreators.append(creator); -} - -static QList matchers(const QList &creators) +QList LocatorMatcher::matchers(MatcherType type) { + const QList creators = s_matcherCreators.value(type); QList result; for (const LocatorMatcherTaskCreator &creator : creators) result << creator(); return result; } -QList LocatorMatcher::locatorMatchers() -{ - return matchers(s_locatorMatcherCreators); -} - -QList LocatorMatcher::classMatchers() -{ - return matchers(s_classMatcherCreators); -} - -QList LocatorMatcher::functionMatchers() -{ - return matchers(s_functionMatcherCreators); -} - static QList g_locatorFilters; /*! diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index bf94650443d..848321daaf1 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -145,6 +145,12 @@ public: using LocatorMatcherTaskCreator = std::function()>; class LocatorMatcherPrivate; +enum class MatcherType { + AllSymbols, + Classes, + Functions +}; + class CORE_EXPORT LocatorMatcher final : public QObject { Q_OBJECT @@ -167,13 +173,8 @@ public: const LocatorMatcherTask::InputData &input, int parallelLimit = 0); - static void addLocatorMatcherCreator(const LocatorMatcherTaskCreator &creator); - static void addClassMatcherCreator(const LocatorMatcherTaskCreator &creator); - static void addFunctionMatcherCreator(const LocatorMatcherTaskCreator &creator); - - static QList locatorMatchers(); - static QList classMatchers(); - static QList functionMatchers(); + static void addMatcherCreator(MatcherType type, const LocatorMatcherTaskCreator &creator); + static QList matchers(MatcherType type); signals: void serialOutputDataReady(const LocatorMatcherTask::OutputData &serialOutputData); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 6a9f50a9c83..9895e23a26d 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -110,7 +110,7 @@ LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex return {Async(onSetup, onDone, onDone), storage}; } -LocatorMatcherTask cppLocatorMatcher() +LocatorMatcherTask cppAllSymbolsMatcher() { const auto converter = [](const IndexItem::Ptr &info) { // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index b484a9c7687..799bafc553a 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -10,7 +10,7 @@ namespace CppEditor { -Core::LocatorMatcherTask CPPEDITOR_EXPORT cppLocatorMatcher(); +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppAllSymbolsMatcher(); Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher(); Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher(); diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index 7c70ee35bae..fd68b4c1cfd 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -127,7 +127,7 @@ void LocatorFilterTest::testLocatorFilter() { QFETCH(QString, testFile); QFETCH(ILocatorFilter *, filter); - QFETCH(MatcherCreator, matcherCreator); + QFETCH(MatcherType, matcherType); QFETCH(QString, searchText); QFETCH(ResultDataList, expectedResults); @@ -138,7 +138,8 @@ void LocatorFilterTest::testLocatorFilter() { Tests::VerifyCleanCppModelManager verify; - CppLocatorFilterTestCase(nullptr, matcherCreator(), testFile, searchText, expectedResults); + CppLocatorFilterTestCase(nullptr, LocatorMatcher::matchers(matcherType), testFile, + searchText, expectedResults); } } @@ -146,7 +147,7 @@ void LocatorFilterTest::testLocatorFilter_data() { QTest::addColumn("testFile"); QTest::addColumn("filter"); - QTest::addColumn("matcherCreator"); + QTest::addColumn("matcherType"); QTest::addColumn("searchText"); QTest::addColumn("expectedResults"); @@ -155,10 +156,6 @@ void LocatorFilterTest::testLocatorFilter_data() ILocatorFilter *cppClassesFilter = cppModelManager->classesFilter(); ILocatorFilter *cppLocatorFilter = cppModelManager->locatorFilter(); - const MatcherCreator functionMatcherCreator = &LocatorMatcher::functionMatchers; - const MatcherCreator classMatcherCreator = &LocatorMatcher::classMatchers; - const MatcherCreator locatorMatcherCreator = &LocatorMatcher::locatorMatchers; - MyTestDataDir testDirectory("testdata_basic"); QString testFile = testDirectory.file("file1.cpp"); testFile[0] = testFile[0].toLower(); // Ensure Windows path sorts after scope names. @@ -169,7 +166,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter") << testFile << cppFunctionsFilter - << functionMatcherCreator + << MatcherType::Functions << "function" << ResultDataList{ ResultData("functionDefinedInClass(bool, int)", @@ -192,7 +189,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-Sorting") << testFile << cppFunctionsFilter - << functionMatcherCreator + << MatcherType::Functions << "pos" << ResultDataList{ ResultData("positiveNumber()", testFileShort), @@ -204,7 +201,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-arguments") << testFile << cppFunctionsFilter - << functionMatcherCreator + << MatcherType::Functions << "function*bool" << ResultDataList{ ResultData("functionDefinedInClass(bool, int)", @@ -221,7 +218,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-WithNamespacePrefix") << testFile << cppFunctionsFilter - << functionMatcherCreator + << MatcherType::Functions << "mynamespace::" << ResultDataList{ ResultData("MyClass()", "MyNamespace::MyClass (file1.cpp)"), @@ -237,7 +234,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-WithClassPrefix") << testFile << cppFunctionsFilter - << functionMatcherCreator + << MatcherType::Functions << "MyClass::func" << ResultDataList{ ResultData("functionDefinedInClass(bool, int)", @@ -259,7 +256,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter") << testFile << cppClassesFilter - << classMatcherCreator + << MatcherType::Classes << "myclass" << ResultDataList{ ResultData("MyClass", ""), @@ -270,7 +267,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter-WithNamespacePrefix") << testFile << cppClassesFilter - << classMatcherCreator + << MatcherType::Classes << "mynamespace::" << ResultDataList{ ResultData("MyClass", "MyNamespace") @@ -280,7 +277,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppLocatorFilter-filtered") << testFile << cppLocatorFilter - << locatorMatcherCreator + << MatcherType::AllSymbols << "my" << ResultDataList{ ResultData("MyClass", testFileShort), @@ -307,7 +304,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter-ObjC") << objTestFile << cppClassesFilter - << classMatcherCreator + << MatcherType::Classes << "M" << ResultDataList{ ResultData("MyClass", objTestFileShort), @@ -319,7 +316,7 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-ObjC") << objTestFile << cppFunctionsFilter - << functionMatcherCreator + << MatcherType::Functions << "M" << ResultDataList{ ResultData("anotherMethod", "MyClass (file1.mm)"), @@ -428,8 +425,8 @@ void LocatorFilterTest::testFunctionsFilterHighlighting() { Tests::VerifyCleanCppModelManager verify; - const MatcherCreator matcherCreator = &LocatorMatcher::functionMatchers; - CppLocatorFilterTestCase(nullptr, matcherCreator(), testFile, searchText, expectedResults); + CppLocatorFilterTestCase(nullptr, LocatorMatcher::matchers(MatcherType::Functions), + testFile, searchText, expectedResults); } } diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 78e3453460c..f4aacf74da1 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -535,7 +535,7 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) // Step 1: Employ locator to find all functions LocatorMatcher *matcher = new LocatorMatcher; - matcher->setTasks(LocatorMatcher::functionMatchers()); + matcher->setTasks(LocatorMatcher::matchers(MatcherType::Functions)); const QPointer search = SearchResultWindow::instance()->startNewSearch(Tr::tr("Find Unused Functions"), {}, @@ -897,9 +897,12 @@ void CppModelManager::initCppTools() setSymbolsFindFilter(std::make_unique(this)); setCurrentDocumentFilter(std::make_unique()); // Setup matchers - LocatorMatcher::addLocatorMatcherCreator([] { return QList{CppEditor::cppLocatorMatcher()}; }); - LocatorMatcher::addClassMatcherCreator([] { return QList{CppEditor::cppClassMatcher()}; }); - LocatorMatcher::addFunctionMatcherCreator([] { return QList{CppEditor::cppFunctionMatcher()}; }); + LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, + [] { return QList{CppEditor::cppAllSymbolsMatcher()}; }); + LocatorMatcher::addMatcherCreator(MatcherType::Classes, + [] { return QList{CppEditor::cppClassMatcher()}; }); + LocatorMatcher::addMatcherCreator(MatcherType::Functions, + [] { return QList{CppEditor::cppFunctionMatcher()}; }); } CppModelManager::CppModelManager() diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 563f418e2a7..8acc21feeb1 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -94,7 +94,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, return {root, storage}; } -LocatorMatcherTask workspaceLocatorMatcher(Client *client, int maxResultCount) +LocatorMatcherTask workspaceAllSymbolsMatcher(Client *client, int maxResultCount) { return locatorMatcher(client, maxResultCount, {}); } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index d1c000331a9..4a312599af9 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -20,8 +20,8 @@ namespace Core { class IEditor; } namespace LanguageClient { // TODO: Could be public methods of Client instead -Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceLocatorMatcher(Client *client, - int maxResultCount = 0); +Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceAllSymbolsMatcher(Client *client, + int maxResultCount = 0); Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceClassMatcher(Client *client, int maxResultCount = 0); Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceFunctionMatcher(Client *client, diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index 3fc9d9aea6c..d57c0bacc5f 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -647,7 +647,7 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) lineEdit->setSpecialCompleter(new QCompleter(completionList, lineEdit)); }; LocatorMatcher *matcher = new LocatorMatcher; - matcher->setTasks(LocatorMatcher::classMatchers()); + matcher->setTasks(LocatorMatcher::matchers(MatcherType::Classes)); QObject::connect(matcher, &LocatorMatcher::serialOutputDataReady, lineEdit, handleResults); QObject::connect(matcher, &LocatorMatcher::done, matcher, &QObject::deleteLater); matcher->start(); From 3726bfc77972a564c84c991ea516097d7bb3b79d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 00:11:40 +0200 Subject: [PATCH 0594/1447] MacroLocatorFilter: Use Acceptor for LocatorFilterEntry Change-Id: Ie7aa7d81e1b81190b2966de09dc04b3ffb2691ea Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/macros/macrolocatorfilter.cpp | 41 ++++++++++------------- src/plugins/macros/macrolocatorfilter.h | 5 --- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 5749b187eee..8c90cccd156 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -8,11 +8,10 @@ #include "macrostr.h" #include -#include -#include #include +using namespace Core; using namespace Macros; using namespace Macros::Internal; @@ -28,11 +27,11 @@ MacroLocatorFilter::MacroLocatorFilter() MacroLocatorFilter::~MacroLocatorFilter() = default; -QList MacroLocatorFilter::matchesFor(QFutureInterface &future, const QString &entry) +QList MacroLocatorFilter::matchesFor(QFutureInterface &future, const QString &entry) { Q_UNUSED(future) - QList goodEntries; - QList betterEntries; + QList goodEntries; + QList betterEntries; const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); @@ -43,17 +42,27 @@ QList MacroLocatorFilter::matchesFor(QFutureInterface< const QString description = it.value()->description(); int index = displayName.indexOf(entry, 0, entryCaseSensitivity); - Core::LocatorFilterEntry::HighlightInfo::DataType hDataType = Core::LocatorFilterEntry::HighlightInfo::DisplayName; + LocatorFilterEntry::HighlightInfo::DataType hDataType + = LocatorFilterEntry::HighlightInfo::DisplayName; if (index < 0) { index = description.indexOf(entry, 0, entryCaseSensitivity); - hDataType = Core::LocatorFilterEntry::HighlightInfo::ExtraInfo; + hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo; } if (index >= 0) { - Core::LocatorFilterEntry filterEntry(this, displayName); + LocatorFilterEntry filterEntry; + filterEntry.displayName = displayName; + filterEntry.acceptor = [displayName] { + IEditor *editor = EditorManager::currentEditor(); + if (editor) + editor->widget()->setFocus(Qt::OtherFocusReason); + + MacroManager::instance()->executeMacro(displayName); + return AcceptResult(); + }; filterEntry.displayIcon = m_icon; filterEntry.extraInfo = description; - filterEntry.highlightInfo = Core::LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); + filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); if (index == 0) betterEntries.append(filterEntry); @@ -64,17 +73,3 @@ QList MacroLocatorFilter::matchesFor(QFutureInterface< betterEntries.append(goodEntries); return betterEntries; } - -void MacroLocatorFilter::accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - // Give the focus back to the editor - Core::IEditor *editor = Core::EditorManager::currentEditor(); - if (editor) - editor->widget()->setFocus(Qt::OtherFocusReason); - - MacroManager::instance()->executeMacro(selection.displayName); -} diff --git a/src/plugins/macros/macrolocatorfilter.h b/src/plugins/macros/macrolocatorfilter.h index 61fa7a34db4..3807548f69e 100644 --- a/src/plugins/macros/macrolocatorfilter.h +++ b/src/plugins/macros/macrolocatorfilter.h @@ -5,8 +5,6 @@ #include -#include - namespace Macros { namespace Internal { @@ -20,9 +18,6 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: const QIcon m_icon; }; From c118f8cae435d37dfa8afb82e6a16ddb60e4ed5b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 00:20:13 +0200 Subject: [PATCH 0595/1447] UrlLocatorFilter: Use Acceptor for LocatorFilterEntry Change-Id: Id4b97a10bc01ab4392d7e7fc6e5890dcd3d42be9 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../coreplugin/locator/urllocatorfilter.cpp | 23 ++++++------------- .../coreplugin/locator/urllocatorfilter.h | 2 -- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index 70651e74eea..a0345cfc5fd 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -19,7 +18,6 @@ #include #include #include -#include using namespace Utils; @@ -176,26 +174,19 @@ QList UrlLocatorFilter::matchesFor( if (future.isCanceled()) break; const QString name = url.arg(entry); - Core::LocatorFilterEntry filterEntry(this, name); + Core::LocatorFilterEntry filterEntry; + filterEntry.displayName = name; + filterEntry.acceptor = [name] { + if (!name.isEmpty()) + QDesktopServices::openUrl(name); + return AcceptResult(); + }; filterEntry.highlightInfo = {int(name.lastIndexOf(entry)), int(entry.length())}; entries.append(filterEntry); } return entries; } -void UrlLocatorFilter::accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - const QString &url = selection.displayName; - if (!url.isEmpty()) - QDesktopServices::openUrl(url); -} - const char kDisplayNameKey[] = "displayName"; const char kRemoteUrlsKey[] = "remoteUrls"; diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.h b/src/plugins/coreplugin/locator/urllocatorfilter.h index befe162d60e..9c438a147c0 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.h +++ b/src/plugins/coreplugin/locator/urllocatorfilter.h @@ -30,8 +30,6 @@ public: // ILocatorFilter QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; From 71eb0ab9f8e98df9bd021c1c49d7ec00a66492cb Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 6 Apr 2023 15:30:13 +0200 Subject: [PATCH 0596/1447] CMakePM: Add CMake source file parser Files taken from the CMake repository https://gitlab.kitware.com/cmake/cmake.git 624461526f4707a2406ebbd40245a605b6bd41fa (tag: v3.26.3) Change-Id: I9ef388908cd22eb2748b5c17d039848ee23585b9 Reviewed-by: hjk Reviewed-by: Eike Ziller --- README.md | 37 ++ .../overview/creator-acknowledgements.qdoc | 42 ++ .../3rdparty/cmake/Copyright.txt | 136 +++++ .../3rdparty/cmake/README.md | 4 + .../3rdparty/cmake/cmListFileCache.cxx | 508 ++++++++++++++++ .../3rdparty/cmake/cmListFileCache.h | 246 ++++++++ .../3rdparty/cmake/cmListFileLexer.h | 68 +++ .../3rdparty/cmake/cmListFileLexer.in.l | 560 ++++++++++++++++++ .../3rdparty/cmake/cmStandardLexer.h | 89 +++ 9 files changed, 1690 insertions(+) create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/Copyright.txt create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/README.md create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h diff --git a/README.md b/README.md index 4a97db2efcc..410d8f03e8d 100644 --- a/README.md +++ b/README.md @@ -867,3 +867,40 @@ SQLite (https://www.sqlite.org) is in the Public Domain. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +### cmake + + The CMake project manager uses the CMake lexer code for parsing CMake files + + https://gitlab.kitware.com/cmake/cmake.git + + CMake - Cross Platform Makefile Generator + Copyright 2000-2023 Kitware, Inc. and Contributors + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Kitware, Inc. nor the names of Contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc index 820e97247d5..7f193d124dc 100644 --- a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc +++ b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc @@ -1059,5 +1059,47 @@ \include license-mit.qdocinc + \li \b cmake + + The CMake project manager uses the CMake lexer code for parsing CMake files. + + \list + \li \l https://gitlab.kitware.com/cmake/cmake.git + \endlist + + CMake - Cross Platform Makefile Generator + Copyright 2000-2023 Kitware, Inc. and Contributors + All rights reserved. + + \badcode + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Kitware, Inc. nor the names of Contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + \endcode + + \endlist */ diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/Copyright.txt b/src/plugins/cmakeprojectmanager/3rdparty/cmake/Copyright.txt new file mode 100644 index 00000000000..515e403a2d4 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/Copyright.txt @@ -0,0 +1,136 @@ +CMake - Cross Platform Makefile Generator +Copyright 2000-2023 Kitware, Inc. and Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Kitware, Inc. nor the names of Contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------ + +The following individuals and institutions are among the Contributors: + +* Aaron C. Meadows +* Adriaan de Groot +* Aleksey Avdeev +* Alexander Neundorf +* Alexander Smorkalov +* Alexey Sokolov +* Alex Merry +* Alex Turbov +* Andreas Pakulat +* Andreas Schneider +* André Rigland Brodtkorb +* Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf +* Benjamin Eikel +* Bjoern Ricks +* Brad Hards +* Christopher Harvey +* Christoph Grüninger +* Clement Creusot +* Daniel Blezek +* Daniel Pfeifer +* Dawid Wróbel +* Enrico Scholz +* Eran Ifrah +* Esben Mose Hansen, Ange Optimization ApS +* Geoffrey Viola +* Google Inc +* Gregor Jasny +* Helio Chissini de Castro +* Ilya Lavrenov +* Insight Software Consortium +* Intel Corporation +* Jan Woetzel +* Jordan Williams +* Julien Schueller +* Kelly Thompson +* Konstantin Podsvirov +* Laurent Montel +* Mario Bensi +* Martin Gräßlin +* Mathieu Malaterre +* Matthaeus G. Chajdas +* Matthias Kretz +* Matthias Maennich +* Michael Hirsch, Ph.D. +* Michael Stürmer +* Miguel A. Figueroa-Villanueva +* Mike Durso +* Mike Jackson +* Mike McQuaid +* Nicolas Bock +* Nicolas Despres +* Nikita Krupen'ko +* NVIDIA Corporation +* OpenGamma Ltd. +* Patrick Stotko +* Per Øyvind Karlsen +* Peter Collingbourne +* Petr Gotthard +* Philip Lowman +* Philippe Proulx +* Raffi Enficiaud, Max Planck Society +* Raumfeld +* Roger Leigh +* Rolf Eike Beer +* Roman Donchenko +* Roman Kharitonov +* Ruslan Baratov +* Sebastian Holtermann +* Stephen Kelly +* Sylvain Joubert +* The Qt Company Ltd. +* Thomas Sondergaard +* Tobias Hunger +* Todd Gamblin +* Tristan Carel +* University of Dundee +* Vadim Zhukov +* Will Dicharry + +See version control history for details of individual contributions. + +The above copyright and license notice applies to distributions of +CMake in source and binary form. Third-party software packages supplied +with CMake under compatible licenses provide their own copyright notices +documented in corresponding subdirectories or source files. + +------------------------------------------------------------------------------ + +CMake was initially developed by Kitware with the following sponsorship: + + * National Library of Medicine at the National Institutes of Health + as part of the Insight Segmentation and Registration Toolkit (ITK). + + * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel + Visualization Initiative. + + * National Alliance for Medical Image Computing (NAMIC) is funded by the + National Institutes of Health through the NIH Roadmap for Medical Research, + Grant U54 EB005149. + + * Kitware, Inc. diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/README.md b/src/plugins/cmakeprojectmanager/3rdparty/cmake/README.md new file mode 100644 index 00000000000..92a4d869a66 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/README.md @@ -0,0 +1,4 @@ +Files taken from the CMake repository https://gitlab.kitware.com/cmake/cmake.git + +624461526f4707a2406ebbd40245a605b6bd41fa (tag: v3.26.3) + diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx new file mode 100644 index 00000000000..6270c825f2b --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx @@ -0,0 +1,508 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#define cmListFileCache_cxx +#include "cmListFileCache.h" + +#include +#include +#include + +#ifdef _WIN32 +# include +#endif + +#include "cmListFileLexer.h" +#include "cmMessageType.h" +#include "cmMessenger.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +struct cmListFileParser +{ + cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, + cmMessenger* messenger); + ~cmListFileParser(); + cmListFileParser(const cmListFileParser&) = delete; + cmListFileParser& operator=(const cmListFileParser&) = delete; + void IssueFileOpenError(std::string const& text) const; + void IssueError(std::string const& text) const; + bool ParseFile(const char* filename); + bool ParseString(const char* str, const char* virtual_filename); + bool Parse(); + bool ParseFunction(const char* name, long line); + bool AddArgument(cmListFileLexer_Token* token, + cmListFileArgument::Delimiter delim); + cm::optional CheckNesting() const; + cmListFile* ListFile; + cmListFileBacktrace Backtrace; + cmMessenger* Messenger; + const char* FileName = nullptr; + cmListFileLexer* Lexer; + std::string FunctionName; + long FunctionLine; + long FunctionLineEnd; + std::vector FunctionArguments; + enum + { + SeparationOkay, + SeparationWarning, + SeparationError + } Separation; +}; + +cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, + cmMessenger* messenger) + : ListFile(lf) + , Backtrace(std::move(lfbt)) + , Messenger(messenger) + , Lexer(cmListFileLexer_New()) +{ +} + +cmListFileParser::~cmListFileParser() +{ + cmListFileLexer_Delete(this->Lexer); +} + +void cmListFileParser::IssueFileOpenError(const std::string& text) const +{ + this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text, + this->Backtrace); +} + +void cmListFileParser::IssueError(const std::string& text) const +{ + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer); + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text, lfbt); + cmSystemTools::SetFatalErrorOccurred(); +} + +bool cmListFileParser::ParseFile(const char* filename) +{ + this->FileName = filename; + +#ifdef _WIN32 + std::string expandedFileName = cmsys::Encoding::ToNarrow( + cmSystemTools::ConvertToWindowsExtendedPath(filename)); + filename = expandedFileName.c_str(); +#endif + + // Open the file. + cmListFileLexer_BOM bom; + if (!cmListFileLexer_SetFileName(this->Lexer, filename, &bom)) { + this->IssueFileOpenError("cmListFileCache: error can not open file."); + return false; + } + + if (bom == cmListFileLexer_BOM_Broken) { + cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr); + this->IssueFileOpenError("Error while reading Byte-Order-Mark. " + "File not seekable?"); + return false; + } + + // Verify the Byte-Order-Mark, if any. + if (bom != cmListFileLexer_BOM_None && bom != cmListFileLexer_BOM_UTF8) { + cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr); + this->IssueFileOpenError( + "File starts with a Byte-Order-Mark that is not UTF-8."); + return false; + } + + return this->Parse(); +} + +bool cmListFileParser::ParseString(const char* str, + const char* virtual_filename) +{ + this->FileName = virtual_filename; + + if (!cmListFileLexer_SetString(this->Lexer, str)) { + this->IssueFileOpenError("cmListFileCache: cannot allocate buffer."); + return false; + } + + return this->Parse(); +} + +bool cmListFileParser::Parse() +{ + // Use a simple recursive-descent parser to process the token + // stream. + bool haveNewline = true; + while (cmListFileLexer_Token* token = cmListFileLexer_Scan(this->Lexer)) { + if (token->type == cmListFileLexer_Token_Space) { + } else if (token->type == cmListFileLexer_Token_Newline) { + haveNewline = true; + } else if (token->type == cmListFileLexer_Token_CommentBracket) { + haveNewline = false; + } else if (token->type == cmListFileLexer_Token_Identifier) { + if (haveNewline) { + haveNewline = false; + if (this->ParseFunction(token->text, token->line)) { + this->ListFile->Functions.emplace_back( + std::move(this->FunctionName), this->FunctionLine, + this->FunctionLineEnd, std::move(this->FunctionArguments)); + } else { + return false; + } + } else { + std::ostringstream error; + error << "Parse error. Expected a newline, got " + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) + << " with text \"" << token->text << "\"."; + this->IssueError(error.str()); + return false; + } + } else { + std::ostringstream error; + error << "Parse error. Expected a command name, got " + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) + << " with text \"" << token->text << "\"."; + this->IssueError(error.str()); + return false; + } + } + + // Check if all functions are nested properly. + if (auto badNesting = this->CheckNesting()) { + this->Messenger->IssueMessage( + MessageType::FATAL_ERROR, + "Flow control statements are not properly nested.", + this->Backtrace.Push(*badNesting)); + cmSystemTools::SetFatalErrorOccurred(); + return false; + } + + return true; +} + +bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger, + cmListFileBacktrace const& lfbt) +{ + if (!cmSystemTools::FileExists(filename) || + cmSystemTools::FileIsDirectory(filename)) { + return false; + } + + bool parseError = false; + + { + cmListFileParser parser(this, lfbt, messenger); + parseError = !parser.ParseFile(filename); + } + + return !parseError; +} + +bool cmListFile::ParseString(const char* str, const char* virtual_filename, + cmMessenger* messenger, + const cmListFileBacktrace& lfbt) +{ + bool parseError = false; + + { + cmListFileParser parser(this, lfbt, messenger); + parseError = !parser.ParseString(str, virtual_filename); + } + + return !parseError; +} + +bool cmListFileParser::ParseFunction(const char* name, long line) +{ + // Ininitialize a new function call. + this->FunctionName = name; + this->FunctionLine = line; + + // Command name has already been parsed. Read the left paren. + cmListFileLexer_Token* token; + while ((token = cmListFileLexer_Scan(this->Lexer)) && + token->type == cmListFileLexer_Token_Space) { + } + if (!token) { + std::ostringstream error; + /* clang-format off */ + error << "Unexpected end of file.\n" + << "Parse error. Function missing opening \"(\"."; + /* clang-format on */ + this->IssueError(error.str()); + return false; + } + if (token->type != cmListFileLexer_Token_ParenLeft) { + std::ostringstream error; + error << "Parse error. Expected \"(\", got " + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) + << " with text \"" << token->text << "\"."; + this->IssueError(error.str()); + return false; + } + + // Arguments. + unsigned long parenDepth = 0; + this->Separation = SeparationOkay; + while ((token = cmListFileLexer_Scan(this->Lexer))) { + if (token->type == cmListFileLexer_Token_Space || + token->type == cmListFileLexer_Token_Newline) { + this->Separation = SeparationOkay; + continue; + } + if (token->type == cmListFileLexer_Token_ParenLeft) { + parenDepth++; + this->Separation = SeparationOkay; + if (!this->AddArgument(token, cmListFileArgument::Unquoted)) { + return false; + } + } else if (token->type == cmListFileLexer_Token_ParenRight) { + if (parenDepth == 0) { + this->FunctionLineEnd = token->line; + return true; + } + parenDepth--; + this->Separation = SeparationOkay; + if (!this->AddArgument(token, cmListFileArgument::Unquoted)) { + return false; + } + this->Separation = SeparationWarning; + } else if (token->type == cmListFileLexer_Token_Identifier || + token->type == cmListFileLexer_Token_ArgumentUnquoted) { + if (!this->AddArgument(token, cmListFileArgument::Unquoted)) { + return false; + } + this->Separation = SeparationWarning; + } else if (token->type == cmListFileLexer_Token_ArgumentQuoted) { + if (!this->AddArgument(token, cmListFileArgument::Quoted)) { + return false; + } + this->Separation = SeparationWarning; + } else if (token->type == cmListFileLexer_Token_ArgumentBracket) { + if (!this->AddArgument(token, cmListFileArgument::Bracket)) { + return false; + } + this->Separation = SeparationError; + } else if (token->type == cmListFileLexer_Token_CommentBracket) { + this->Separation = SeparationError; + } else { + // Error. + std::ostringstream error; + error << "Parse error. Function missing ending \")\". " + << "Instead found " + << cmListFileLexer_GetTypeAsString(this->Lexer, token->type) + << " with text \"" << token->text << "\"."; + this->IssueError(error.str()); + return false; + } + } + + std::ostringstream error; + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = line; + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + error << "Parse error. Function missing ending \")\". " + << "End of file reached."; + this->Messenger->IssueMessage(MessageType::FATAL_ERROR, error.str(), lfbt); + return false; +} + +bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, + cmListFileArgument::Delimiter delim) +{ + this->FunctionArguments.emplace_back(token->text, delim, token->line); + if (this->Separation == SeparationOkay) { + return true; + } + bool isError = (this->Separation == SeparationError || + delim == cmListFileArgument::Bracket); + std::ostringstream m; + cmListFileContext lfc; + lfc.FilePath = this->FileName; + lfc.Line = token->line; + cmListFileBacktrace lfbt = this->Backtrace; + lfbt = lfbt.Push(lfc); + + m << "Syntax " << (isError ? "Error" : "Warning") << " in cmake code at " + << "column " << token->column << "\n" + << "Argument not separated from preceding token by whitespace."; + /* clang-format on */ + if (isError) { + this->Messenger->IssueMessage(MessageType::FATAL_ERROR, m.str(), lfbt); + return false; + } + this->Messenger->IssueMessage(MessageType::AUTHOR_WARNING, m.str(), lfbt); + return true; +} + +namespace { +enum class NestingStateEnum +{ + If, + Else, + While, + Foreach, + Function, + Macro, + Block +}; + +struct NestingState +{ + NestingStateEnum State; + cmListFileContext Context; +}; + +bool TopIs(std::vector& stack, NestingStateEnum state) +{ + return !stack.empty() && stack.back().State == state; +} +} + +cm::optional cmListFileParser::CheckNesting() const +{ + std::vector stack; + + for (auto const& func : this->ListFile->Functions) { + auto const& name = func.LowerCaseName(); + if (name == "if") { + stack.push_back({ + NestingStateEnum::If, + cmListFileContext::FromListFileFunction(func, this->FileName), + }); + } else if (name == "elseif") { + if (!TopIs(stack, NestingStateEnum::If)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.back() = { + NestingStateEnum::If, + cmListFileContext::FromListFileFunction(func, this->FileName), + }; + } else if (name == "else") { + if (!TopIs(stack, NestingStateEnum::If)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.back() = { + NestingStateEnum::Else, + cmListFileContext::FromListFileFunction(func, this->FileName), + }; + } else if (name == "endif") { + if (!TopIs(stack, NestingStateEnum::If) && + !TopIs(stack, NestingStateEnum::Else)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.pop_back(); + } else if (name == "while") { + stack.push_back({ + NestingStateEnum::While, + cmListFileContext::FromListFileFunction(func, this->FileName), + }); + } else if (name == "endwhile") { + if (!TopIs(stack, NestingStateEnum::While)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.pop_back(); + } else if (name == "foreach") { + stack.push_back({ + NestingStateEnum::Foreach, + cmListFileContext::FromListFileFunction(func, this->FileName), + }); + } else if (name == "endforeach") { + if (!TopIs(stack, NestingStateEnum::Foreach)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.pop_back(); + } else if (name == "function") { + stack.push_back({ + NestingStateEnum::Function, + cmListFileContext::FromListFileFunction(func, this->FileName), + }); + } else if (name == "endfunction") { + if (!TopIs(stack, NestingStateEnum::Function)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.pop_back(); + } else if (name == "macro") { + stack.push_back({ + NestingStateEnum::Macro, + cmListFileContext::FromListFileFunction(func, this->FileName), + }); + } else if (name == "endmacro") { + if (!TopIs(stack, NestingStateEnum::Macro)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.pop_back(); + } else if (name == "block") { + stack.push_back({ + NestingStateEnum::Block, + cmListFileContext::FromListFileFunction(func, this->FileName), + }); + } else if (name == "endblock") { + if (!TopIs(stack, NestingStateEnum::Block)) { + return cmListFileContext::FromListFileFunction(func, this->FileName); + } + stack.pop_back(); + } + } + + if (!stack.empty()) { + return stack.back().Context; + } + + return cm::nullopt; +} + +#include "cmConstStack.tcc" +template class cmConstStack; + +std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) +{ + os << lfc.FilePath; + if (lfc.Line > 0) { + os << ":" << lfc.Line; + if (!lfc.Name.empty()) { + os << " (" << lfc.Name << ")"; + } + } else if (lfc.Line == cmListFileContext::DeferPlaceholderLine) { + os << ":DEFERRED"; + } + return os; +} + +bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs) +{ + if (lhs.Line != rhs.Line) { + return lhs.Line < rhs.Line; + } + return lhs.FilePath < rhs.FilePath; +} + +bool operator==(const cmListFileContext& lhs, const cmListFileContext& rhs) +{ + return lhs.Line == rhs.Line && lhs.FilePath == rhs.FilePath; +} + +bool operator!=(const cmListFileContext& lhs, const cmListFileContext& rhs) +{ + return !(lhs == rhs); +} + +std::ostream& operator<<(std::ostream& os, BT const& s) +{ + return os << s.Value; +} + +std::vector> cmExpandListWithBacktrace( + std::string const& list, cmListFileBacktrace const& bt, bool emptyArgs) +{ + std::vector> result; + std::vector tmp = cmExpandedList(list, emptyArgs); + result.reserve(tmp.size()); + for (std::string& i : tmp) { + result.emplace_back(std::move(i), bt); + } + return result; +} diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h new file mode 100644 index 00000000000..05539892c93 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h @@ -0,0 +1,246 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include +#include +#include +#include +#include + +#include + +#include "cmConstStack.h" +#include "cmSystemTools.h" + +/** \class cmListFileCache + * \brief A class to cache list file contents. + * + * cmListFileCache is a class used to cache the contents of parsed + * cmake list files. + */ + +class cmMessenger; + +struct cmListFileArgument +{ + enum Delimiter + { + Unquoted, + Quoted, + Bracket + }; + cmListFileArgument() = default; + cmListFileArgument(std::string v, Delimiter d, long line) + : Value(std::move(v)) + , Delim(d) + , Line(line) + { + } + bool operator==(const cmListFileArgument& r) const + { + return (this->Value == r.Value) && (this->Delim == r.Delim); + } + bool operator!=(const cmListFileArgument& r) const { return !(*this == r); } + std::string Value; + Delimiter Delim = Unquoted; + long Line = 0; +}; + +class cmListFileFunction +{ +public: + cmListFileFunction(std::string name, long line, long lineEnd, + std::vector args) + : Impl{ std::make_shared(std::move(name), line, lineEnd, + std::move(args)) } + { + } + + std::string const& OriginalName() const noexcept + { + return this->Impl->OriginalName; + } + + std::string const& LowerCaseName() const noexcept + { + return this->Impl->LowerCaseName; + } + + long Line() const noexcept { return this->Impl->Line; } + long LineEnd() const noexcept { return this->Impl->LineEnd; } + + std::vector const& Arguments() const noexcept + { + return this->Impl->Arguments; + } + +private: + struct Implementation + { + Implementation(std::string name, long line, long lineEnd, + std::vector args) + : OriginalName{ std::move(name) } + , LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) } + , Line{ line } + , LineEnd{ lineEnd } + , Arguments{ std::move(args) } + { + } + + std::string OriginalName; + std::string LowerCaseName; + long Line = 0; + long LineEnd = 0; + std::vector Arguments; + }; + + std::shared_ptr Impl; +}; + +class cmListFileContext +{ +public: + std::string Name; + std::string FilePath; + long Line = 0; + static long const DeferPlaceholderLine = -1; + cm::optional DeferId; + + cmListFileContext() = default; + // This move constructor is marked `noexcept` yet `clang-tidy` 14 reports it + // as being able to throw an exception. Suppress the warning as there doesn't + // seem to be any way for this to happen given the member types. + // NOLINTNEXTLINE(bugprone-exception-escape) + cmListFileContext(cmListFileContext&& /*other*/) noexcept = default; + cmListFileContext(const cmListFileContext& /*other*/) = default; + cmListFileContext& operator=(const cmListFileContext& /*other*/) = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept = + default; +#else + // The move assignment operators for several STL classes did not become + // noexcept until C++17, which causes some tools to warn about this move + // assignment operator throwing an exception when it shouldn't. + cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept = + delete; +#endif + + cmListFileContext(std::string name, std::string filePath, long line) + : Name(std::move(name)) + , FilePath(std::move(filePath)) + , Line(line) + { + } + + static cmListFileContext FromListFilePath(std::string const& filePath) + { + // We are entering a file-level scope but have not yet reached + // any specific line or command invocation within it. This context + // is useful to print when it is at the top but otherwise can be + // skipped during call stack printing. + cmListFileContext lfc; + lfc.FilePath = filePath; + return lfc; + } + + static cmListFileContext FromListFileFunction( + cmListFileFunction const& lff, std::string const& fileName, + cm::optional deferId = {}) + { + cmListFileContext lfc; + lfc.FilePath = fileName; + lfc.Line = lff.Line(); + lfc.Name = lff.OriginalName(); + lfc.DeferId = std::move(deferId); + return lfc; + } +}; + +std::ostream& operator<<(std::ostream&, cmListFileContext const&); +bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs); +bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs); +bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs); + +// Represent a backtrace (call stack) with efficient value semantics. +class cmListFileBacktrace + : public cmConstStack +{ + using cmConstStack::cmConstStack; + friend class cmConstStack; +}; +#ifndef cmListFileCache_cxx +extern template class cmConstStack; +#endif + +// Wrap type T as a value with a backtrace. For purposes of +// ordering and equality comparison, only the original value is +// used. The backtrace is considered incidental. +template +class BT +{ +public: + BT(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace()) + : Value(std::move(v)) + , Backtrace(std::move(bt)) + { + } + T Value; + cmListFileBacktrace Backtrace; + friend bool operator==(BT const& l, BT const& r) + { + return l.Value == r.Value; + } + friend bool operator<(BT const& l, BT const& r) + { + return l.Value < r.Value; + } + friend bool operator==(BT const& l, T const& r) { return l.Value == r; } + friend bool operator==(T const& l, BT const& r) { return l == r.Value; } +}; + +std::ostream& operator<<(std::ostream& os, BT const& s); + +// Wrap type T as a value with potentially multiple backtraces. For purposes +// of ordering and equality comparison, only the original value is used. The +// backtrace is considered incidental. +template +class BTs +{ +public: + BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace()) + : Value(std::move(v)) + { + this->Backtraces.emplace_back(std::move(bt)); + } + T Value; + std::vector Backtraces; + friend bool operator==(BTs const& l, BTs const& r) + { + return l.Value == r.Value; + } + friend bool operator<(BTs const& l, BTs const& r) + { + return l.Value < r.Value; + } + friend bool operator==(BTs const& l, T const& r) { return l.Value == r; } + friend bool operator==(T const& l, BTs const& r) { return l == r.Value; } +}; + +std::vector> cmExpandListWithBacktrace( + std::string const& list, + cmListFileBacktrace const& bt = cmListFileBacktrace(), + bool emptyArgs = false); + +struct cmListFile +{ + bool ParseFile(const char* path, cmMessenger* messenger, + cmListFileBacktrace const& lfbt); + + bool ParseString(const char* str, const char* virtual_filename, + cmMessenger* messenger, cmListFileBacktrace const& lfbt); + + std::vector Functions; +}; diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h new file mode 100644 index 00000000000..3c89f63416a --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h @@ -0,0 +1,68 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* NOLINTNEXTLINE(modernize-use-using) */ +typedef enum cmListFileLexer_Type_e +{ + cmListFileLexer_Token_None, + cmListFileLexer_Token_Space, + cmListFileLexer_Token_Newline, + cmListFileLexer_Token_Identifier, + cmListFileLexer_Token_ParenLeft, + cmListFileLexer_Token_ParenRight, + cmListFileLexer_Token_ArgumentUnquoted, + cmListFileLexer_Token_ArgumentQuoted, + cmListFileLexer_Token_ArgumentBracket, + cmListFileLexer_Token_CommentBracket, + cmListFileLexer_Token_BadCharacter, + cmListFileLexer_Token_BadBracket, + cmListFileLexer_Token_BadString +} cmListFileLexer_Type; + +/* NOLINTNEXTLINE(modernize-use-using) */ +typedef struct cmListFileLexer_Token_s cmListFileLexer_Token; +struct cmListFileLexer_Token_s +{ + cmListFileLexer_Type type; + char* text; + int length; + int line; + int column; +}; + +enum cmListFileLexer_BOM_e +{ + cmListFileLexer_BOM_None, + cmListFileLexer_BOM_Broken, + cmListFileLexer_BOM_UTF8, + cmListFileLexer_BOM_UTF16BE, + cmListFileLexer_BOM_UTF16LE, + cmListFileLexer_BOM_UTF32BE, + cmListFileLexer_BOM_UTF32LE +}; + +/* NOLINTNEXTLINE(modernize-use-using) */ +typedef enum cmListFileLexer_BOM_e cmListFileLexer_BOM; + +/* NOLINTNEXTLINE(modernize-use-using) */ +typedef struct cmListFileLexer_s cmListFileLexer; + +cmListFileLexer* cmListFileLexer_New(void); +int cmListFileLexer_SetFileName(cmListFileLexer*, const char*, + cmListFileLexer_BOM* bom); +int cmListFileLexer_SetString(cmListFileLexer*, const char*); +cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer*); +long cmListFileLexer_GetCurrentLine(cmListFileLexer*); +long cmListFileLexer_GetCurrentColumn(cmListFileLexer*); +const char* cmListFileLexer_GetTypeAsString(cmListFileLexer*, + cmListFileLexer_Type); +void cmListFileLexer_Delete(cmListFileLexer*); + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l new file mode 100644 index 00000000000..94cf8a59430 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l @@ -0,0 +1,560 @@ +%{ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +/* + +This file must be translated to C and modified to build everywhere. + +Run flex >= 2.6 like this: + + flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l + +Modify cmListFileLexer.c: + - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c + - remove blank lines at end of file: sed -i '${/^$/d;}' cmListFileLexer.c + - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmListFileLexer.c + +*/ + +/* IWYU pragma: no_forward_declare yyguts_t */ + +#ifdef _WIN32 +#include "cmsys/Encoding.h" +#endif + +/* Setup the proper cmListFileLexer_yylex declaration. */ +#define YY_EXTRA_TYPE cmListFileLexer* +#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer) + +#include "cmListFileLexer.h" + +/*--------------------------------------------------------------------------*/ +struct cmListFileLexer_s +{ + cmListFileLexer_Token token; + int bracket; + int comment; + int line; + int column; + int size; + FILE* file; + size_t cr; + char* string_buffer; + char* string_position; + int string_left; + yyscan_t scanner; +}; + +static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text, + int length); +static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, + int length); +static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer, + size_t bufferSize); +static void cmListFileLexerInit(cmListFileLexer* lexer); +static void cmListFileLexerDestroy(cmListFileLexer* lexer); + +/* Replace the lexer input function. */ +#undef YY_INPUT +#define YY_INPUT(buf, result, max_size) \ + do { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); } while (0) + +/*--------------------------------------------------------------------------*/ +%} + +%option prefix="cmListFileLexer_yy" + +%option reentrant +%option yylineno +%option noyywrap +%pointer +%x STRING +%x BRACKET +%x BRACKETEND +%x COMMENT + +MAKEVAR \$\([A-Za-z0-9_]*\) +UNQUOTED ([^ \0\t\r\n\(\)#\\\"[=]|\\[^\0\n]) +LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\" + +%% + +\n { + lexer->token.type = cmListFileLexer_Token_Newline; + cmListFileLexerSetToken(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; + BEGIN(INITIAL); + return 1; +} + +#?\[=*\[\n? { + const char* bracket = yytext; + lexer->comment = yytext[0] == '#'; + if (lexer->comment) { + lexer->token.type = cmListFileLexer_Token_CommentBracket; + bracket += 1; + } else { + lexer->token.type = cmListFileLexer_Token_ArgumentBracket; + } + cmListFileLexerSetToken(lexer, "", 0); + lexer->bracket = strchr(bracket+1, '[') - bracket; + if (yytext[yyleng-1] == '\n') { + ++lexer->line; + lexer->column = 1; + } else { + lexer->column += yyleng; + } + BEGIN(BRACKET); +} + +# { + lexer->column += yyleng; + BEGIN(COMMENT); +} + +[^\0\n]* { + lexer->column += yyleng; +} + +\( { + lexer->token.type = cmListFileLexer_Token_ParenLeft; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +\) { + lexer->token.type = cmListFileLexer_Token_ParenRight; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +[A-Za-z_][A-Za-z0-9_]* { + lexer->token.type = cmListFileLexer_Token_Identifier; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +\]=* { + /* Handle ]]====]=======]*/ + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; + if (yyleng == lexer->bracket) { + BEGIN(BRACKETEND); + } +} + +\] { + lexer->column += yyleng; + /* Erase the partial bracket from the token. */ + lexer->token.length -= lexer->bracket; + lexer->token.text[lexer->token.length] = 0; + BEGIN(INITIAL); + return 1; +} + +([^]\0\n])+ { + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; +} + +\n { + cmListFileLexerAppend(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; + BEGIN(BRACKET); +} + +[^\0\n] { + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; + BEGIN(BRACKET); +} + +<> { + lexer->token.type = cmListFileLexer_Token_BadBracket; + BEGIN(INITIAL); + return 1; +} + +({UNQUOTED}|=|\[=*{UNQUOTED})({UNQUOTED}|[[=])* { + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +({MAKEVAR}|{UNQUOTED}|=|\[=*{LEGACY})({LEGACY}|[[=])* { + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +\[ { + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +\" { + lexer->token.type = cmListFileLexer_Token_ArgumentQuoted; + cmListFileLexerSetToken(lexer, "", 0); + lexer->column += yyleng; + BEGIN(STRING); +} + +([^\\\0\n\"]|\\[^\0\n])+ { + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; +} + +\\\n { + /* Continuation: text is not part of string */ + ++lexer->line; + lexer->column = 1; +} + +\n { + cmListFileLexerAppend(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; +} + +\" { + lexer->column += yyleng; + BEGIN(INITIAL); + return 1; +} + +[^\0\n] { + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; +} + +<> { + lexer->token.type = cmListFileLexer_Token_BadString; + BEGIN(INITIAL); + return 1; +} + +[ \t\r]+ { + lexer->token.type = cmListFileLexer_Token_Space; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +. { + lexer->token.type = cmListFileLexer_Token_BadCharacter; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + +<> { + lexer->token.type = cmListFileLexer_Token_None; + cmListFileLexerSetToken(lexer, 0, 0); + return 0; +} + +%% + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text, + int length) +{ + /* Set the token line and column number. */ + lexer->token.line = lexer->line; + lexer->token.column = lexer->column; + + /* Use the same buffer if possible. */ + if (lexer->token.text) { + if (text && length < lexer->size) { + strcpy(lexer->token.text, text); + lexer->token.length = length; + return; + } + free(lexer->token.text); + lexer->token.text = 0; + lexer->size = 0; + } + + /* Need to extend the buffer. */ + if (text) { + lexer->token.text = strdup(text); + lexer->token.length = length; + lexer->size = length + 1; + } else { + lexer->token.length = 0; + } +} + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, + int length) +{ + char* temp; + int newSize; + + /* If the appended text will fit in the buffer, do not reallocate. */ + newSize = lexer->token.length + length + 1; + if (lexer->token.text && newSize <= lexer->size) { + strcpy(lexer->token.text + lexer->token.length, text); + lexer->token.length += length; + return; + } + + /* We need to extend the buffer. */ + temp = malloc(newSize); + if (lexer->token.text) { + memcpy(temp, lexer->token.text, lexer->token.length); + free(lexer->token.text); + } + memcpy(temp + lexer->token.length, text, length); + temp[lexer->token.length + length] = 0; + lexer->token.text = temp; + lexer->token.length += length; + lexer->size = newSize; +} + +/*--------------------------------------------------------------------------*/ +static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer, + size_t bufferSize) +{ + if (lexer) { + if (lexer->file) { + /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode + does not convert newlines on all platforms. Move any + trailing CR to the start of the buffer for the next read. */ + size_t cr = lexer->cr; + size_t n; + buffer[0] = '\r'; + n = fread(buffer + cr, 1, bufferSize - cr, lexer->file); + if (n) { + char* o = buffer; + const char* i = buffer; + const char* e; + n += cr; + cr = (buffer[n - 1] == '\r') ? 1 : 0; + e = buffer + n - cr; + while (i != e) { + if (i[0] == '\r' && i[1] == '\n') { + ++i; + } + *o++ = *i++; + } + n = o - buffer; + } else { + n = cr; + cr = 0; + } + lexer->cr = cr; + return n; + } else if (lexer->string_left) { + int length = lexer->string_left; + if ((int)bufferSize < length) { + length = (int)bufferSize; + } + memcpy(buffer, lexer->string_position, length); + lexer->string_position += length; + lexer->string_left -= length; + return length; + } + } + return 0; +} + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerInit(cmListFileLexer* lexer) +{ + if (lexer->file || lexer->string_buffer) { + cmListFileLexer_yylex_init(&lexer->scanner); + cmListFileLexer_yyset_extra(lexer, lexer->scanner); + } +} + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerDestroy(cmListFileLexer* lexer) +{ + cmListFileLexerSetToken(lexer, 0, 0); + if (lexer->file || lexer->string_buffer) { + cmListFileLexer_yylex_destroy(lexer->scanner); + if (lexer->file) { + fclose(lexer->file); + lexer->file = 0; + } + if (lexer->string_buffer) { + free(lexer->string_buffer); + lexer->string_buffer = 0; + lexer->string_left = 0; + lexer->string_position = 0; + } + } +} + +/*--------------------------------------------------------------------------*/ +cmListFileLexer* cmListFileLexer_New(void) +{ + cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer)); + if (!lexer) { + return 0; + } + memset(lexer, 0, sizeof(*lexer)); + lexer->line = 1; + lexer->column = 1; + return lexer; +} + +/*--------------------------------------------------------------------------*/ +void cmListFileLexer_Delete(cmListFileLexer* lexer) +{ + cmListFileLexer_SetFileName(lexer, 0, 0); + free(lexer); +} + +/*--------------------------------------------------------------------------*/ +static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f) +{ + unsigned char b[2]; + if (fread(b, 1, 2, f) == 2) { + if (b[0] == 0xEF && b[1] == 0xBB) { + if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) { + return cmListFileLexer_BOM_UTF8; + } + } else if (b[0] == 0xFE && b[1] == 0xFF) { + /* UTF-16 BE */ + return cmListFileLexer_BOM_UTF16BE; + } else if (b[0] == 0 && b[1] == 0) { + if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) { + return cmListFileLexer_BOM_UTF32BE; + } + } else if (b[0] == 0xFF && b[1] == 0xFE) { + fpos_t p; + fgetpos(f, &p); + if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) { + return cmListFileLexer_BOM_UTF32LE; + } + if (fsetpos(f, &p) != 0) { + return cmListFileLexer_BOM_Broken; + } + return cmListFileLexer_BOM_UTF16LE; + } + } + if (fseek(f, 0, SEEK_SET) != 0) { + return cmListFileLexer_BOM_Broken; + } + return cmListFileLexer_BOM_None; +} + +/*--------------------------------------------------------------------------*/ +int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name, + cmListFileLexer_BOM* bom) +{ + int result = 1; + cmListFileLexerDestroy(lexer); + if (name) { +#ifdef _WIN32 + wchar_t* wname = cmsysEncoding_DupToWide(name); + lexer->file = _wfopen(wname, L"rb"); + free(wname); +#else + lexer->file = fopen(name, "rb"); +#endif + if (lexer->file) { + if (bom) { + *bom = cmListFileLexer_ReadBOM(lexer->file); + } + } else { + result = 0; + } + } + cmListFileLexerInit(lexer); + return result; +} + +/*--------------------------------------------------------------------------*/ +int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text) +{ + int result = 1; + cmListFileLexerDestroy(lexer); + if (text) { + int length = (int)strlen(text); + lexer->string_buffer = (char*)malloc(length + 1); + if (lexer->string_buffer) { + strcpy(lexer->string_buffer, text); + lexer->string_position = lexer->string_buffer; + lexer->string_left = length; + } else { + result = 0; + } + } + cmListFileLexerInit(lexer); + return result; +} + +/*--------------------------------------------------------------------------*/ +cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) +{ + if (!lexer->file && !lexer->string_buffer) { + return 0; + } + if (cmListFileLexer_yylex(lexer->scanner, lexer)) { + return &lexer->token; + } else { + cmListFileLexer_SetFileName(lexer, 0, 0); + return 0; + } +} + +/*--------------------------------------------------------------------------*/ +long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer) +{ + return lexer->line; +} + +/*--------------------------------------------------------------------------*/ +long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer) +{ + return lexer->column; +} + +/*--------------------------------------------------------------------------*/ +const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, + cmListFileLexer_Type type) +{ + (void)lexer; + switch (type) { + case cmListFileLexer_Token_None: + return "nothing"; + case cmListFileLexer_Token_Space: + return "space"; + case cmListFileLexer_Token_Newline: + return "newline"; + case cmListFileLexer_Token_Identifier: + return "identifier"; + case cmListFileLexer_Token_ParenLeft: + return "left paren"; + case cmListFileLexer_Token_ParenRight: + return "right paren"; + case cmListFileLexer_Token_ArgumentUnquoted: + return "unquoted argument"; + case cmListFileLexer_Token_ArgumentQuoted: + return "quoted argument"; + case cmListFileLexer_Token_ArgumentBracket: + return "bracket argument"; + case cmListFileLexer_Token_CommentBracket: + return "bracket comment"; + case cmListFileLexer_Token_BadCharacter: + return "bad character"; + case cmListFileLexer_Token_BadBracket: + return "unterminated bracket"; + case cmListFileLexer_Token_BadString: + return "unterminated string"; + } + return "unknown token"; +} diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h new file mode 100644 index 00000000000..27225280d6f --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h @@ -0,0 +1,89 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#if defined(__linux) +/* Needed for glibc < 2.12 */ +// NOLINTNEXTLINE(bugprone-reserved-identifier) +# define _XOPEN_SOURCE 600 +#endif +#if !defined(_POSIX_C_SOURCE) && !defined(_WIN32) && !defined(__sun) && \ + !defined(__OpenBSD__) +/* POSIX APIs are needed */ +// NOLINTNEXTLINE(bugprone-reserved-identifier) +# define _POSIX_C_SOURCE 200809L +#endif +#if defined(__sun) && defined(__GNUC__) && !defined(__cplusplus) +/* C sources: for fileno and strdup */ +// NOLINTNEXTLINE(bugprone-reserved-identifier) +# define _XOPEN_SOURCE 600 +#endif +#if defined(__FreeBSD__) || defined(__NetBSD__) +/* For isascii */ +// NOLINTNEXTLINE(bugprone-reserved-identifier) +# define _XOPEN_SOURCE 700 +#endif + +#include "cmsys/Configure.h" // IWYU pragma: keep + +/* Disable some warnings. */ +#if defined(_MSC_VER) +# pragma warning(disable : 4018) +# pragma warning(disable : 4127) +# pragma warning(disable : 4131) +# pragma warning(disable : 4244) +# pragma warning(disable : 4251) +# pragma warning(disable : 4267) +# pragma warning(disable : 4305) +# pragma warning(disable : 4309) +# pragma warning(disable : 4706) +# pragma warning(disable : 4786) +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-compare" +# endif +# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 403 +# pragma GCC diagnostic ignored "-Wsign-conversion" +# endif +#endif + +#if defined(__LCC__) +# pragma diag_suppress 1873 /* comparison between signed and unsigned */ +#endif + +#if defined(__NVCOMPILER) +# pragma diag_suppress 111 /* statement is unreachable */ +# pragma diag_suppress 550 /* variable set but never used */ +#endif + +/* Make sure isatty is available. */ +#if defined(_WIN32) && !defined(__CYGWIN__) +# include +# if defined(_MSC_VER) +# define isatty _isatty +# endif +#else +# include // IWYU pragma: export +#endif + +/* Make sure malloc and free are available on QNX. */ +#ifdef __QNX__ +# include +#endif + +/* Disable features we do not need. */ +#define YY_NEVER_INTERACTIVE 1 +#define YY_NO_INPUT 1 +#define YY_NO_UNPUT 1 +#define ECHO + +#include +typedef KWIML_INT_int8_t flex_int8_t; +typedef KWIML_INT_uint8_t flex_uint8_t; +typedef KWIML_INT_int16_t flex_int16_t; +typedef KWIML_INT_uint16_t flex_uint16_t; +typedef KWIML_INT_int32_t flex_int32_t; +typedef KWIML_INT_uint32_t flex_uint32_t; From d41365610ff80478d8c6c2812299d95d139561ec Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 6 Apr 2023 15:49:30 +0200 Subject: [PATCH 0597/1447] CMakePM: Integrate CMake's lexer Kept only the needed bits to parse the CMake files. Change-Id: I7c4aa0779846fcee91469a38f84d801513e3aa63 Reviewed-by: Reviewed-by: Eike Ziller --- .../3rdparty/cmake/cmListFileCache.cxx | 316 +- .../3rdparty/cmake/cmListFileCache.h | 171 +- .../3rdparty/cmake/cmListFileLexer.c | 2835 +++++++++++++++++ .../3rdparty/cmake/cmListFileLexer.h | 5 +- .../3rdparty/cmake/cmListFileLexer.in.l | 30 +- .../3rdparty/cmake/cmStandardLexer.h | 17 +- .../cmakeprojectmanager/CMakeLists.txt | 4 + 7 files changed, 2905 insertions(+), 473 deletions(-) create mode 100644 src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.c diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx index 6270c825f2b..86175b69e16 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx @@ -7,41 +7,29 @@ #include #include -#ifdef _WIN32 -# include -#endif - #include "cmListFileLexer.h" -#include "cmMessageType.h" -#include "cmMessenger.h" -#include "cmStringAlgorithms.h" -#include "cmSystemTools.h" struct cmListFileParser { - cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, - cmMessenger* messenger); + cmListFileParser(cmListFile* lf, std::string &error); ~cmListFileParser(); cmListFileParser(const cmListFileParser&) = delete; cmListFileParser& operator=(const cmListFileParser&) = delete; - void IssueFileOpenError(std::string const& text) const; void IssueError(std::string const& text) const; bool ParseFile(const char* filename); - bool ParseString(const char* str, const char* virtual_filename); + bool ParseString(const std::string &str, const std::string &virtual_filename); bool Parse(); bool ParseFunction(const char* name, long line); bool AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim); - cm::optional CheckNesting() const; cmListFile* ListFile; - cmListFileBacktrace Backtrace; - cmMessenger* Messenger; const char* FileName = nullptr; cmListFileLexer* Lexer; std::string FunctionName; long FunctionLine; long FunctionLineEnd; std::vector FunctionArguments; + std::string &Error; enum { SeparationOkay, @@ -50,12 +38,10 @@ struct cmListFileParser } Separation; }; -cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, - cmMessenger* messenger) - : ListFile(lf) - , Backtrace(std::move(lfbt)) - , Messenger(messenger) - , Lexer(cmListFileLexer_New()) +cmListFileParser::cmListFileParser(cmListFile *lf, std::string &error) + : ListFile(lf) + , Lexer(cmListFileLexer_New()) + , Error(error) { } @@ -64,65 +50,19 @@ cmListFileParser::~cmListFileParser() cmListFileLexer_Delete(this->Lexer); } -void cmListFileParser::IssueFileOpenError(const std::string& text) const -{ - this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text, - this->Backtrace); -} - void cmListFileParser::IssueError(const std::string& text) const { - cmListFileContext lfc; - lfc.FilePath = this->FileName; - lfc.Line = cmListFileLexer_GetCurrentLine(this->Lexer); - cmListFileBacktrace lfbt = this->Backtrace; - lfbt = lfbt.Push(lfc); - this->Messenger->IssueMessage(MessageType::FATAL_ERROR, text, lfbt); - cmSystemTools::SetFatalErrorOccurred(); + Error += text; + Error += "\n"; } -bool cmListFileParser::ParseFile(const char* filename) +bool cmListFileParser::ParseString(const std::string &str, + const std::string &virtual_filename) { - this->FileName = filename; + this->FileName = virtual_filename.c_str(); -#ifdef _WIN32 - std::string expandedFileName = cmsys::Encoding::ToNarrow( - cmSystemTools::ConvertToWindowsExtendedPath(filename)); - filename = expandedFileName.c_str(); -#endif - - // Open the file. - cmListFileLexer_BOM bom; - if (!cmListFileLexer_SetFileName(this->Lexer, filename, &bom)) { - this->IssueFileOpenError("cmListFileCache: error can not open file."); - return false; - } - - if (bom == cmListFileLexer_BOM_Broken) { - cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr); - this->IssueFileOpenError("Error while reading Byte-Order-Mark. " - "File not seekable?"); - return false; - } - - // Verify the Byte-Order-Mark, if any. - if (bom != cmListFileLexer_BOM_None && bom != cmListFileLexer_BOM_UTF8) { - cmListFileLexer_SetFileName(this->Lexer, nullptr, nullptr); - this->IssueFileOpenError( - "File starts with a Byte-Order-Mark that is not UTF-8."); - return false; - } - - return this->Parse(); -} - -bool cmListFileParser::ParseString(const char* str, - const char* virtual_filename) -{ - this->FileName = virtual_filename; - - if (!cmListFileLexer_SetString(this->Lexer, str)) { - this->IssueFileOpenError("cmListFileCache: cannot allocate buffer."); + if (!cmListFileLexer_SetString(this->Lexer, str.c_str(), (int)str.size())) { + this->IssueError("cmListFileCache: cannot allocate buffer."); return false; } @@ -138,7 +78,8 @@ bool cmListFileParser::Parse() if (token->type == cmListFileLexer_Token_Space) { } else if (token->type == cmListFileLexer_Token_Newline) { haveNewline = true; - } else if (token->type == cmListFileLexer_Token_CommentBracket) { + } else if (token->type == cmListFileLexer_Token_CommentBracket + || token->type == cmListFileLexer_Token_CommentLine) { haveNewline = false; } else if (token->type == cmListFileLexer_Token_Identifier) { if (haveNewline) { @@ -168,45 +109,15 @@ bool cmListFileParser::Parse() } } - // Check if all functions are nested properly. - if (auto badNesting = this->CheckNesting()) { - this->Messenger->IssueMessage( - MessageType::FATAL_ERROR, - "Flow control statements are not properly nested.", - this->Backtrace.Push(*badNesting)); - cmSystemTools::SetFatalErrorOccurred(); - return false; - } - return true; } -bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger, - cmListFileBacktrace const& lfbt) -{ - if (!cmSystemTools::FileExists(filename) || - cmSystemTools::FileIsDirectory(filename)) { - return false; - } - - bool parseError = false; - - { - cmListFileParser parser(this, lfbt, messenger); - parseError = !parser.ParseFile(filename); - } - - return !parseError; -} - -bool cmListFile::ParseString(const char* str, const char* virtual_filename, - cmMessenger* messenger, - const cmListFileBacktrace& lfbt) +bool cmListFile::ParseString(const std::string &str, const std::string& virtual_filename, std::string &error) { bool parseError = false; { - cmListFileParser parser(this, lfbt, messenger); + cmListFileParser parser(this, error); parseError = !parser.ParseString(str, virtual_filename); } @@ -279,6 +190,11 @@ bool cmListFileParser::ParseFunction(const char* name, long line) return false; } this->Separation = SeparationWarning; + } else if (token->type == cmListFileLexer_Token_CommentLine) { + if (!this->AddArgument(token, cmListFileArgument::Comment)) { + return false; + } + this->Separation = SeparationWarning; } else if (token->type == cmListFileLexer_Token_ArgumentBracket) { if (!this->AddArgument(token, cmListFileArgument::Bracket)) { return false; @@ -299,210 +215,30 @@ bool cmListFileParser::ParseFunction(const char* name, long line) } std::ostringstream error; - cmListFileContext lfc; - lfc.FilePath = this->FileName; - lfc.Line = line; - cmListFileBacktrace lfbt = this->Backtrace; - lfbt = lfbt.Push(lfc); error << "Parse error. Function missing ending \")\". " << "End of file reached."; - this->Messenger->IssueMessage(MessageType::FATAL_ERROR, error.str(), lfbt); + IssueError(error.str()); return false; } bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim) { - this->FunctionArguments.emplace_back(token->text, delim, token->line); + this->FunctionArguments.emplace_back(token->text, delim, token->line, token->column); if (this->Separation == SeparationOkay) { return true; } bool isError = (this->Separation == SeparationError || delim == cmListFileArgument::Bracket); std::ostringstream m; - cmListFileContext lfc; - lfc.FilePath = this->FileName; - lfc.Line = token->line; - cmListFileBacktrace lfbt = this->Backtrace; - lfbt = lfbt.Push(lfc); m << "Syntax " << (isError ? "Error" : "Warning") << " in cmake code at " << "column " << token->column << "\n" << "Argument not separated from preceding token by whitespace."; /* clang-format on */ if (isError) { - this->Messenger->IssueMessage(MessageType::FATAL_ERROR, m.str(), lfbt); + IssueError(m.str()); return false; } - this->Messenger->IssueMessage(MessageType::AUTHOR_WARNING, m.str(), lfbt); return true; } - -namespace { -enum class NestingStateEnum -{ - If, - Else, - While, - Foreach, - Function, - Macro, - Block -}; - -struct NestingState -{ - NestingStateEnum State; - cmListFileContext Context; -}; - -bool TopIs(std::vector& stack, NestingStateEnum state) -{ - return !stack.empty() && stack.back().State == state; -} -} - -cm::optional cmListFileParser::CheckNesting() const -{ - std::vector stack; - - for (auto const& func : this->ListFile->Functions) { - auto const& name = func.LowerCaseName(); - if (name == "if") { - stack.push_back({ - NestingStateEnum::If, - cmListFileContext::FromListFileFunction(func, this->FileName), - }); - } else if (name == "elseif") { - if (!TopIs(stack, NestingStateEnum::If)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.back() = { - NestingStateEnum::If, - cmListFileContext::FromListFileFunction(func, this->FileName), - }; - } else if (name == "else") { - if (!TopIs(stack, NestingStateEnum::If)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.back() = { - NestingStateEnum::Else, - cmListFileContext::FromListFileFunction(func, this->FileName), - }; - } else if (name == "endif") { - if (!TopIs(stack, NestingStateEnum::If) && - !TopIs(stack, NestingStateEnum::Else)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.pop_back(); - } else if (name == "while") { - stack.push_back({ - NestingStateEnum::While, - cmListFileContext::FromListFileFunction(func, this->FileName), - }); - } else if (name == "endwhile") { - if (!TopIs(stack, NestingStateEnum::While)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.pop_back(); - } else if (name == "foreach") { - stack.push_back({ - NestingStateEnum::Foreach, - cmListFileContext::FromListFileFunction(func, this->FileName), - }); - } else if (name == "endforeach") { - if (!TopIs(stack, NestingStateEnum::Foreach)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.pop_back(); - } else if (name == "function") { - stack.push_back({ - NestingStateEnum::Function, - cmListFileContext::FromListFileFunction(func, this->FileName), - }); - } else if (name == "endfunction") { - if (!TopIs(stack, NestingStateEnum::Function)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.pop_back(); - } else if (name == "macro") { - stack.push_back({ - NestingStateEnum::Macro, - cmListFileContext::FromListFileFunction(func, this->FileName), - }); - } else if (name == "endmacro") { - if (!TopIs(stack, NestingStateEnum::Macro)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.pop_back(); - } else if (name == "block") { - stack.push_back({ - NestingStateEnum::Block, - cmListFileContext::FromListFileFunction(func, this->FileName), - }); - } else if (name == "endblock") { - if (!TopIs(stack, NestingStateEnum::Block)) { - return cmListFileContext::FromListFileFunction(func, this->FileName); - } - stack.pop_back(); - } - } - - if (!stack.empty()) { - return stack.back().Context; - } - - return cm::nullopt; -} - -#include "cmConstStack.tcc" -template class cmConstStack; - -std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) -{ - os << lfc.FilePath; - if (lfc.Line > 0) { - os << ":" << lfc.Line; - if (!lfc.Name.empty()) { - os << " (" << lfc.Name << ")"; - } - } else if (lfc.Line == cmListFileContext::DeferPlaceholderLine) { - os << ":DEFERRED"; - } - return os; -} - -bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs) -{ - if (lhs.Line != rhs.Line) { - return lhs.Line < rhs.Line; - } - return lhs.FilePath < rhs.FilePath; -} - -bool operator==(const cmListFileContext& lhs, const cmListFileContext& rhs) -{ - return lhs.Line == rhs.Line && lhs.FilePath == rhs.FilePath; -} - -bool operator!=(const cmListFileContext& lhs, const cmListFileContext& rhs) -{ - return !(lhs == rhs); -} - -std::ostream& operator<<(std::ostream& os, BT const& s) -{ - return os << s.Value; -} - -std::vector> cmExpandListWithBacktrace( - std::string const& list, cmListFileBacktrace const& bt, bool emptyArgs) -{ - std::vector> result; - std::vector tmp = cmExpandedList(list, emptyArgs); - result.reserve(tmp.size()); - for (std::string& i : tmp) { - result.emplace_back(std::move(i), bt); - } - return result; -} diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h index 05539892c93..caffba4b851 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h @@ -2,19 +2,13 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once -#include "cmConfigure.h" // IWYU pragma: keep - +#include #include #include #include #include #include -#include - -#include "cmConstStack.h" -#include "cmSystemTools.h" - /** \class cmListFileCache * \brief A class to cache list file contents. * @@ -22,21 +16,21 @@ * cmake list files. */ -class cmMessenger; - struct cmListFileArgument { enum Delimiter { Unquoted, Quoted, - Bracket + Bracket, + Comment }; cmListFileArgument() = default; - cmListFileArgument(std::string v, Delimiter d, long line) + cmListFileArgument(std::string v, Delimiter d, long line, long column) : Value(std::move(v)) , Delim(d) , Line(line) + , Column(column) { } bool operator==(const cmListFileArgument& r) const @@ -47,6 +41,7 @@ struct cmListFileArgument std::string Value; Delimiter Delim = Unquoted; long Line = 0; + long Column = 0; }; class cmListFileFunction @@ -83,13 +78,25 @@ private: Implementation(std::string name, long line, long lineEnd, std::vector args) : OriginalName{ std::move(name) } - , LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) } + , LowerCaseName{ tolower(this->OriginalName) } , Line{ line } , LineEnd{ lineEnd } , Arguments{ std::move(args) } { } + // taken from yaml-cpp + static bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; } + static bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; } + static char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; } + + std::string tolower(const std::string& str) + { + std::string s(str); + std::transform(s.begin(), s.end(), s.begin(), ToLower); + return s; + } + std::string OriginalName; std::string LowerCaseName; long Line = 0; @@ -100,147 +107,9 @@ private: std::shared_ptr Impl; }; -class cmListFileContext -{ -public: - std::string Name; - std::string FilePath; - long Line = 0; - static long const DeferPlaceholderLine = -1; - cm::optional DeferId; - - cmListFileContext() = default; - // This move constructor is marked `noexcept` yet `clang-tidy` 14 reports it - // as being able to throw an exception. Suppress the warning as there doesn't - // seem to be any way for this to happen given the member types. - // NOLINTNEXTLINE(bugprone-exception-escape) - cmListFileContext(cmListFileContext&& /*other*/) noexcept = default; - cmListFileContext(const cmListFileContext& /*other*/) = default; - cmListFileContext& operator=(const cmListFileContext& /*other*/) = default; -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) - cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept = - default; -#else - // The move assignment operators for several STL classes did not become - // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. - cmListFileContext& operator=(cmListFileContext&& /*other*/) noexcept = - delete; -#endif - - cmListFileContext(std::string name, std::string filePath, long line) - : Name(std::move(name)) - , FilePath(std::move(filePath)) - , Line(line) - { - } - - static cmListFileContext FromListFilePath(std::string const& filePath) - { - // We are entering a file-level scope but have not yet reached - // any specific line or command invocation within it. This context - // is useful to print when it is at the top but otherwise can be - // skipped during call stack printing. - cmListFileContext lfc; - lfc.FilePath = filePath; - return lfc; - } - - static cmListFileContext FromListFileFunction( - cmListFileFunction const& lff, std::string const& fileName, - cm::optional deferId = {}) - { - cmListFileContext lfc; - lfc.FilePath = fileName; - lfc.Line = lff.Line(); - lfc.Name = lff.OriginalName(); - lfc.DeferId = std::move(deferId); - return lfc; - } -}; - -std::ostream& operator<<(std::ostream&, cmListFileContext const&); -bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs); -bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs); -bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs); - -// Represent a backtrace (call stack) with efficient value semantics. -class cmListFileBacktrace - : public cmConstStack -{ - using cmConstStack::cmConstStack; - friend class cmConstStack; -}; -#ifndef cmListFileCache_cxx -extern template class cmConstStack; -#endif - -// Wrap type T as a value with a backtrace. For purposes of -// ordering and equality comparison, only the original value is -// used. The backtrace is considered incidental. -template -class BT -{ -public: - BT(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace()) - : Value(std::move(v)) - , Backtrace(std::move(bt)) - { - } - T Value; - cmListFileBacktrace Backtrace; - friend bool operator==(BT const& l, BT const& r) - { - return l.Value == r.Value; - } - friend bool operator<(BT const& l, BT const& r) - { - return l.Value < r.Value; - } - friend bool operator==(BT const& l, T const& r) { return l.Value == r; } - friend bool operator==(T const& l, BT const& r) { return l == r.Value; } -}; - -std::ostream& operator<<(std::ostream& os, BT const& s); - -// Wrap type T as a value with potentially multiple backtraces. For purposes -// of ordering and equality comparison, only the original value is used. The -// backtrace is considered incidental. -template -class BTs -{ -public: - BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace()) - : Value(std::move(v)) - { - this->Backtraces.emplace_back(std::move(bt)); - } - T Value; - std::vector Backtraces; - friend bool operator==(BTs const& l, BTs const& r) - { - return l.Value == r.Value; - } - friend bool operator<(BTs const& l, BTs const& r) - { - return l.Value < r.Value; - } - friend bool operator==(BTs const& l, T const& r) { return l.Value == r; } - friend bool operator==(T const& l, BTs const& r) { return l == r.Value; } -}; - -std::vector> cmExpandListWithBacktrace( - std::string const& list, - cmListFileBacktrace const& bt = cmListFileBacktrace(), - bool emptyArgs = false); - struct cmListFile { - bool ParseFile(const char* path, cmMessenger* messenger, - cmListFileBacktrace const& lfbt); - - bool ParseString(const char* str, const char* virtual_filename, - cmMessenger* messenger, cmListFileBacktrace const& lfbt); + bool ParseString(const std::string &str, const std::string &virtual_filename, std::string &error); std::vector Functions; }; diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.c b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.c new file mode 100644 index 00000000000..fae62886a73 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.c @@ -0,0 +1,2835 @@ +#include "cmStandardLexer.h" + +#define FLEXINT_H 1 +#define YY_INT_ALIGNED short int + +/* A lexical scanner created by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define cmListFileLexer_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer cmListFileLexer_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define cmListFileLexer_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer cmListFileLexer_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define cmListFileLexer_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer cmListFileLexer_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define cmListFileLexer_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string cmListFileLexer_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define cmListFileLexer_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes cmListFileLexer_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define cmListFileLexer_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer cmListFileLexer_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define cmListFileLexer_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer cmListFileLexer_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define cmListFileLexer_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state cmListFileLexer_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define cmListFileLexer_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer cmListFileLexer_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define cmListFileLexer_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state cmListFileLexer_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define cmListFileLexer_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state cmListFileLexer_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define cmListFileLexer_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack cmListFileLexer_yyensure_buffer_stack +#endif + +#ifdef yylex +#define cmListFileLexer_yylex_ALREADY_DEFINED +#else +#define yylex cmListFileLexer_yylex +#endif + +#ifdef yyrestart +#define cmListFileLexer_yyrestart_ALREADY_DEFINED +#else +#define yyrestart cmListFileLexer_yyrestart +#endif + +#ifdef yylex_init +#define cmListFileLexer_yylex_init_ALREADY_DEFINED +#else +#define yylex_init cmListFileLexer_yylex_init +#endif + +#ifdef yylex_init_extra +#define cmListFileLexer_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra cmListFileLexer_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define cmListFileLexer_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy cmListFileLexer_yylex_destroy +#endif + +#ifdef yyget_debug +#define cmListFileLexer_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug cmListFileLexer_yyget_debug +#endif + +#ifdef yyset_debug +#define cmListFileLexer_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug cmListFileLexer_yyset_debug +#endif + +#ifdef yyget_extra +#define cmListFileLexer_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra cmListFileLexer_yyget_extra +#endif + +#ifdef yyset_extra +#define cmListFileLexer_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra cmListFileLexer_yyset_extra +#endif + +#ifdef yyget_in +#define cmListFileLexer_yyget_in_ALREADY_DEFINED +#else +#define yyget_in cmListFileLexer_yyget_in +#endif + +#ifdef yyset_in +#define cmListFileLexer_yyset_in_ALREADY_DEFINED +#else +#define yyset_in cmListFileLexer_yyset_in +#endif + +#ifdef yyget_out +#define cmListFileLexer_yyget_out_ALREADY_DEFINED +#else +#define yyget_out cmListFileLexer_yyget_out +#endif + +#ifdef yyset_out +#define cmListFileLexer_yyset_out_ALREADY_DEFINED +#else +#define yyset_out cmListFileLexer_yyset_out +#endif + +#ifdef yyget_leng +#define cmListFileLexer_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng cmListFileLexer_yyget_leng +#endif + +#ifdef yyget_text +#define cmListFileLexer_yyget_text_ALREADY_DEFINED +#else +#define yyget_text cmListFileLexer_yyget_text +#endif + +#ifdef yyget_lineno +#define cmListFileLexer_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno cmListFileLexer_yyget_lineno +#endif + +#ifdef yyset_lineno +#define cmListFileLexer_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno cmListFileLexer_yyset_lineno +#endif + +#ifdef yyget_column +#define cmListFileLexer_yyget_column_ALREADY_DEFINED +#else +#define yyget_column cmListFileLexer_yyget_column +#endif + +#ifdef yyset_column +#define cmListFileLexer_yyset_column_ALREADY_DEFINED +#else +#define yyset_column cmListFileLexer_yyset_column +#endif + +#ifdef yywrap +#define cmListFileLexer_yywrap_ALREADY_DEFINED +#else +#define yywrap cmListFileLexer_yywrap +#endif + +#ifdef yyalloc +#define cmListFileLexer_yyalloc_ALREADY_DEFINED +#else +#define yyalloc cmListFileLexer_yyalloc +#endif + +#ifdef yyrealloc +#define cmListFileLexer_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc cmListFileLexer_yyrealloc +#endif + +#ifdef yyfree +#define cmListFileLexer_yyfree_ALREADY_DEFINED +#else +#define yyfree cmListFileLexer_yyfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define cmListFileLexer_yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 24 +#define YY_END_OF_BUFFER 25 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[79] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, + 25, 13, 22, 1, 16, 3, 13, 5, 6, 7, + 15, 23, 23, 17, 19, 20, 21, 24, 10, 11, + 8, 12, 9, 4, 13, 0, 13, 0, 22, 0, + 0, 7, 13, 0, 13, 0, 2, 0, 13, 17, + 0, 18, 10, 8, 4, 0, 14, 0, 0, 0, + 0, 14, 0, 0, 14, 0, 0, 0, 2, 14, + 0, 0, 0, 0, 0, 0, 0, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 5, 6, 7, 1, 1, 1, 8, + 9, 1, 1, 1, 1, 1, 1, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, + 11, 1, 1, 1, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 13, 14, 15, 1, 12, 1, 12, 12, 12, 12, + + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[17] = + { 0, + 1, 1, 2, 3, 4, 3, 1, 3, 5, 6, + 1, 6, 1, 1, 7, 2 + } ; + +static const flex_int16_t yy_base[97] = + { 0, + 0, 0, 14, 28, 42, 56, 70, 84, 18, 19, + 68, 100, 16, 298, 298, 54, 58, 298, 298, 13, + 115, 0, 298, 51, 298, 298, 21, 298, 0, 298, + 53, 298, 298, 0, 0, 126, 55, 0, 25, 25, + 53, 0, 0, 136, 53, 0, 57, 0, 0, 42, + 50, 298, 0, 43, 0, 146, 160, 45, 172, 43, + 26, 0, 42, 177, 0, 42, 188, 40, 298, 40, + 0, 38, 37, 34, 32, 31, 23, 298, 197, 204, + 211, 218, 225, 232, 239, 245, 252, 259, 262, 268, + 275, 278, 280, 286, 289, 291 + + } ; + +static const flex_int16_t yy_def[97] = + { 0, + 78, 1, 79, 79, 80, 80, 81, 81, 82, 82, + 78, 78, 78, 78, 78, 78, 12, 78, 78, 12, + 78, 83, 78, 84, 78, 78, 84, 78, 85, 78, + 78, 78, 78, 86, 12, 87, 12, 88, 78, 78, + 89, 20, 12, 90, 12, 21, 78, 91, 12, 84, + 84, 78, 85, 78, 86, 87, 78, 56, 87, 92, + 78, 57, 89, 90, 57, 64, 90, 93, 78, 57, + 94, 95, 92, 96, 93, 95, 96, 0, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78 + + } ; + +static const flex_int16_t yy_nxt[315] = + { 0, + 12, 13, 14, 13, 15, 16, 17, 18, 19, 12, + 12, 20, 21, 22, 12, 23, 25, 39, 26, 39, + 14, 14, 42, 52, 42, 50, 39, 27, 39, 28, + 25, 64, 26, 28, 28, 61, 61, 47, 47, 56, + 65, 27, 64, 28, 30, 57, 56, 60, 65, 74, + 62, 57, 72, 54, 50, 51, 31, 28, 30, 69, + 68, 62, 60, 54, 51, 41, 40, 78, 78, 78, + 31, 28, 30, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 33, 28, 30, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 33, 28, + + 35, 78, 78, 78, 36, 78, 37, 78, 78, 35, + 35, 35, 35, 38, 35, 43, 78, 78, 78, 44, + 78, 45, 78, 78, 43, 46, 43, 47, 48, 43, + 57, 78, 58, 78, 78, 78, 78, 78, 78, 59, + 65, 78, 66, 78, 78, 78, 78, 78, 78, 67, + 57, 78, 58, 78, 78, 78, 78, 78, 78, 59, + 57, 78, 78, 78, 36, 78, 70, 78, 78, 57, + 57, 57, 57, 71, 57, 56, 78, 56, 78, 56, + 56, 65, 78, 66, 78, 78, 78, 78, 78, 78, + 67, 64, 78, 64, 78, 64, 64, 24, 24, 24, + + 24, 24, 24, 24, 29, 29, 29, 29, 29, 29, + 29, 32, 32, 32, 32, 32, 32, 32, 34, 34, + 34, 34, 34, 34, 34, 49, 78, 49, 49, 49, + 49, 49, 50, 78, 50, 78, 50, 50, 50, 53, + 78, 53, 53, 53, 53, 55, 78, 55, 55, 55, + 55, 55, 56, 78, 78, 56, 78, 56, 56, 35, + 78, 35, 35, 35, 35, 35, 63, 63, 64, 78, + 78, 64, 78, 64, 64, 43, 78, 43, 43, 43, + 43, 43, 73, 73, 75, 75, 57, 78, 57, 57, + 57, 57, 57, 76, 76, 77, 77, 11, 78, 78, + + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78 + } ; + +static const flex_int16_t yy_chk[315] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 13, 3, 13, + 9, 10, 20, 27, 20, 27, 39, 3, 39, 3, + 4, 77, 4, 9, 10, 40, 61, 40, 61, 76, + 75, 4, 74, 4, 5, 73, 72, 70, 68, 66, + 63, 60, 58, 54, 51, 50, 5, 5, 6, 47, + 45, 41, 37, 31, 24, 17, 16, 11, 0, 0, + 6, 6, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, + + 12, 0, 0, 0, 12, 0, 12, 0, 0, 12, + 12, 12, 12, 12, 12, 21, 0, 0, 0, 21, + 0, 21, 0, 0, 21, 21, 21, 21, 21, 21, + 36, 0, 36, 0, 0, 0, 0, 0, 0, 36, + 44, 0, 44, 0, 0, 0, 0, 0, 0, 44, + 56, 0, 56, 0, 0, 0, 0, 0, 0, 56, + 57, 0, 0, 0, 57, 0, 57, 0, 0, 57, + 57, 57, 57, 57, 57, 59, 0, 59, 0, 59, + 59, 64, 0, 64, 0, 0, 0, 0, 0, 0, + 64, 67, 0, 67, 0, 67, 67, 79, 79, 79, + + 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, + 80, 81, 81, 81, 81, 81, 81, 81, 82, 82, + 82, 82, 82, 82, 82, 83, 0, 83, 83, 83, + 83, 83, 84, 0, 84, 0, 84, 84, 84, 85, + 0, 85, 85, 85, 85, 86, 0, 86, 86, 86, + 86, 86, 87, 0, 0, 87, 0, 87, 87, 88, + 0, 88, 88, 88, 88, 88, 89, 89, 90, 0, + 0, 90, 0, 90, 90, 91, 0, 91, 91, 91, + 91, 91, 92, 92, 93, 93, 94, 0, 94, 94, + 94, 94, 94, 95, 95, 96, 96, 78, 78, 78, + + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78 + } ; + +/* Table of booleans, true if rule could match eol. */ +static const flex_int32_t yy_rule_can_match_eol[25] = + { 0, +1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +/* + +This file must be translated to C and modified to build everywhere. + +Run flex >= 2.6 like this: + + flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l + +Modify cmListFileLexer.c: + - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c + - remove blank lines at end of file: sed -i '${/^$/d;}' cmListFileLexer.c + - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmListFileLexer.c + +*/ + +/* IWYU pragma: no_forward_declare yyguts_t */ + +/* Setup the proper cmListFileLexer_yylex declaration. */ +#define YY_EXTRA_TYPE cmListFileLexer* +#define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer) + +#include "cmListFileLexer.h" + +/*--------------------------------------------------------------------------*/ +struct cmListFileLexer_s +{ + cmListFileLexer_Token token; + int bracket; + int comment; + int line; + int column; + int size; + FILE* file; + size_t cr; + char* string_buffer; + char* string_position; + int string_left; + yyscan_t scanner; +}; + +static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text, + int length); +static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, + int length); +static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer, + size_t bufferSize); +static void cmListFileLexerInit(cmListFileLexer* lexer); +static void cmListFileLexerDestroy(cmListFileLexer* lexer); + +/* Replace the lexer input function. */ +#undef YY_INPUT +#define YY_INPUT(buf, result, max_size) \ + do { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); } while (0) + +/*--------------------------------------------------------------------------*/ + +#define INITIAL 0 +#define STRING 1 +#define BRACKET 2 +#define BRACKETEND 3 +#define COMMENT 4 + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 79 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 298 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_Newline; + cmListFileLexerSetToken(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; + BEGIN(INITIAL); + return 1; +} + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +{ + const char* bracket = yytext; + lexer->comment = yytext[0] == '#'; + if (lexer->comment) { + lexer->token.type = cmListFileLexer_Token_CommentBracket; + bracket += 1; + } else { + lexer->token.type = cmListFileLexer_Token_ArgumentBracket; + } + cmListFileLexerSetToken(lexer, "", 0); + lexer->bracket = strchr(bracket+1, '[') - bracket; + if (yytext[yyleng-1] == '\n') { + ++lexer->line; + lexer->column = 1; + } else { + lexer->column += yyleng; + } + BEGIN(BRACKET); +} + YY_BREAK +case 3: +YY_RULE_SETUP +{ + lexer->column += yyleng; + BEGIN(COMMENT); +} + YY_BREAK +case 4: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_CommentLine; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 5: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_ParenLeft; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 6: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_ParenRight; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 7: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_Identifier; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 8: +YY_RULE_SETUP +{ + /* Handle ]]====]=======]*/ + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; + if (yyleng == lexer->bracket) { + BEGIN(BRACKETEND); + } +} + YY_BREAK +case 9: +YY_RULE_SETUP +{ + lexer->column += yyleng; + /* Erase the partial bracket from the token. */ + lexer->token.length -= lexer->bracket; + lexer->token.text[lexer->token.length] = 0; + BEGIN(INITIAL); + return 1; +} + YY_BREAK +case 10: +YY_RULE_SETUP +{ + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; +} + YY_BREAK +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +{ + cmListFileLexerAppend(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; + BEGIN(BRACKET); +} + YY_BREAK +case 12: +YY_RULE_SETUP +{ + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; + BEGIN(BRACKET); +} + YY_BREAK +case YY_STATE_EOF(BRACKET): +case YY_STATE_EOF(BRACKETEND): +{ + lexer->token.type = cmListFileLexer_Token_BadBracket; + BEGIN(INITIAL); + return 1; +} + YY_BREAK +case 13: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 14: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 15: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 16: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_ArgumentQuoted; + cmListFileLexerSetToken(lexer, "", 0); + lexer->column += yyleng; + BEGIN(STRING); +} + YY_BREAK +case 17: +YY_RULE_SETUP +{ + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; +} + YY_BREAK +case 18: +/* rule 18 can match eol */ +YY_RULE_SETUP +{ + /* Continuation: text is not part of string */ + ++lexer->line; + lexer->column = 1; +} + YY_BREAK +case 19: +/* rule 19 can match eol */ +YY_RULE_SETUP +{ + cmListFileLexerAppend(lexer, yytext, yyleng); + ++lexer->line; + lexer->column = 1; +} + YY_BREAK +case 20: +YY_RULE_SETUP +{ + lexer->column += yyleng; + BEGIN(INITIAL); + return 1; +} + YY_BREAK +case 21: +YY_RULE_SETUP +{ + cmListFileLexerAppend(lexer, yytext, yyleng); + lexer->column += yyleng; +} + YY_BREAK +case YY_STATE_EOF(STRING): +{ + lexer->token.type = cmListFileLexer_Token_BadString; + BEGIN(INITIAL); + return 1; +} + YY_BREAK +case 22: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_Space; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case 23: +YY_RULE_SETUP +{ + lexer->token.type = cmListFileLexer_Token_BadCharacter; + cmListFileLexerSetToken(lexer, yytext, yyleng); + lexer->column += yyleng; + return 1; +} + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMENT): +{ + lexer->token.type = cmListFileLexer_Token_None; + cmListFileLexerSetToken(lexer, 0, 0); + return 0; +} + YY_BREAK +case 24: +YY_RULE_SETUP +ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 16); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 79 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 16; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 79 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 78); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) +{ + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = yyg->yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + if ( c == '\n' ){ + --yylineno; + } + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text, + int length) +{ + /* Set the token line and column number. */ + lexer->token.line = lexer->line; + lexer->token.column = lexer->column; + + /* Use the same buffer if possible. */ + if (lexer->token.text) { + if (text && length < lexer->size) { + strcpy(lexer->token.text, text); + lexer->token.length = length; + return; + } + free(lexer->token.text); + lexer->token.text = 0; + lexer->size = 0; + } + + /* Need to extend the buffer. */ + if (text) { + lexer->token.text = strdup(text); + lexer->token.length = length; + lexer->size = length + 1; + } else { + lexer->token.length = 0; + } +} + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, + int length) +{ + char* temp; + int newSize; + + /* If the appended text will fit in the buffer, do not reallocate. */ + newSize = lexer->token.length + length + 1; + if (lexer->token.text && newSize <= lexer->size) { + strcpy(lexer->token.text + lexer->token.length, text); + lexer->token.length += length; + return; + } + + /* We need to extend the buffer. */ + temp = malloc(newSize); + if (lexer->token.text) { + memcpy(temp, lexer->token.text, lexer->token.length); + free(lexer->token.text); + } + memcpy(temp + lexer->token.length, text, length); + temp[lexer->token.length + length] = 0; + lexer->token.text = temp; + lexer->token.length += length; + lexer->size = newSize; +} + +/*--------------------------------------------------------------------------*/ +static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer, + size_t bufferSize) +{ + if (lexer) { + if (lexer->file) { + /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode + does not convert newlines on all platforms. Move any + trailing CR to the start of the buffer for the next read. */ + size_t cr = lexer->cr; + size_t n; + buffer[0] = '\r'; + n = fread(buffer + cr, 1, bufferSize - cr, lexer->file); + if (n) { + char* o = buffer; + const char* i = buffer; + const char* e; + n += cr; + cr = (buffer[n - 1] == '\r') ? 1 : 0; + e = buffer + n - cr; + while (i != e) { + if (i[0] == '\r' && i[1] == '\n') { + ++i; + } + *o++ = *i++; + } + n = o - buffer; + } else { + n = cr; + cr = 0; + } + lexer->cr = cr; + return n; + } else if (lexer->string_left) { + int length = lexer->string_left; + if ((int)bufferSize < length) { + length = (int)bufferSize; + } + memcpy(buffer, lexer->string_position, length); + lexer->string_position += length; + lexer->string_left -= length; + return length; + } + } + return 0; +} + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerInit(cmListFileLexer* lexer) +{ + if (lexer->file || lexer->string_buffer) { + cmListFileLexer_yylex_init(&lexer->scanner); + cmListFileLexer_yyset_extra(lexer, lexer->scanner); + } +} + +/*--------------------------------------------------------------------------*/ +static void cmListFileLexerDestroy(cmListFileLexer* lexer) +{ + cmListFileLexerSetToken(lexer, 0, 0); + if (lexer->file || lexer->string_buffer) { + cmListFileLexer_yylex_destroy(lexer->scanner); + if (lexer->file) { + fclose(lexer->file); + lexer->file = 0; + } + if (lexer->string_buffer) { + lexer->string_buffer = 0; + lexer->string_left = 0; + lexer->string_position = 0; + } + } +} + +/*--------------------------------------------------------------------------*/ +cmListFileLexer* cmListFileLexer_New(void) +{ + cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer)); + if (!lexer) { + return 0; + } + memset(lexer, 0, sizeof(*lexer)); + lexer->line = 1; + lexer->column = 1; + return lexer; +} + +/*--------------------------------------------------------------------------*/ +void cmListFileLexer_Delete(cmListFileLexer* lexer) +{ + cmListFileLexer_SetFileName(lexer, 0, 0); + free(lexer); +} + +/*--------------------------------------------------------------------------*/ +static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f) +{ + unsigned char b[2]; + if (fread(b, 1, 2, f) == 2) { + if (b[0] == 0xEF && b[1] == 0xBB) { + if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) { + return cmListFileLexer_BOM_UTF8; + } + } else if (b[0] == 0xFE && b[1] == 0xFF) { + /* UTF-16 BE */ + return cmListFileLexer_BOM_UTF16BE; + } else if (b[0] == 0 && b[1] == 0) { + if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) { + return cmListFileLexer_BOM_UTF32BE; + } + } else if (b[0] == 0xFF && b[1] == 0xFE) { + fpos_t p; + fgetpos(f, &p); + if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) { + return cmListFileLexer_BOM_UTF32LE; + } + if (fsetpos(f, &p) != 0) { + return cmListFileLexer_BOM_Broken; + } + return cmListFileLexer_BOM_UTF16LE; + } + } + if (fseek(f, 0, SEEK_SET) != 0) { + return cmListFileLexer_BOM_Broken; + } + return cmListFileLexer_BOM_None; +} + +/*--------------------------------------------------------------------------*/ +int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name, + cmListFileLexer_BOM* bom) +{ + int result = 1; + cmListFileLexerDestroy(lexer); + if (name) { + lexer->file = fopen(name, "rb"); + if (lexer->file) { + if (bom) { + *bom = cmListFileLexer_ReadBOM(lexer->file); + } + } else { + result = 0; + } + } + cmListFileLexerInit(lexer); + return result; +} + +/*--------------------------------------------------------------------------*/ +int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text, int length) +{ + int result = 1; + cmListFileLexerDestroy(lexer); + if (text) { + lexer->string_buffer = (char *) text; + lexer->string_position = lexer->string_buffer; + lexer->string_left = length; + } + cmListFileLexerInit(lexer); + return result; +} + +/*--------------------------------------------------------------------------*/ +cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) +{ + if (!lexer->file && !lexer->string_buffer) { + return 0; + } + if (cmListFileLexer_yylex(lexer->scanner, lexer)) { + return &lexer->token; + } else { + cmListFileLexer_SetFileName(lexer, 0, 0); + return 0; + } +} + +/*--------------------------------------------------------------------------*/ +long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer) +{ + return lexer->line; +} + +/*--------------------------------------------------------------------------*/ +long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer) +{ + return lexer->column; +} + +/*--------------------------------------------------------------------------*/ +const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, + cmListFileLexer_Type type) +{ + (void)lexer; + switch (type) { + case cmListFileLexer_Token_None: + return "nothing"; + case cmListFileLexer_Token_Space: + return "space"; + case cmListFileLexer_Token_Newline: + return "newline"; + case cmListFileLexer_Token_Identifier: + return "identifier"; + case cmListFileLexer_Token_ParenLeft: + return "left paren"; + case cmListFileLexer_Token_ParenRight: + return "right paren"; + case cmListFileLexer_Token_ArgumentUnquoted: + return "unquoted argument"; + case cmListFileLexer_Token_ArgumentQuoted: + return "quoted argument"; + case cmListFileLexer_Token_ArgumentBracket: + return "bracket argument"; + case cmListFileLexer_Token_CommentBracket: + return "bracket comment"; + case cmListFileLexer_Token_BadCharacter: + return "bad character"; + case cmListFileLexer_Token_BadBracket: + return "unterminated bracket"; + case cmListFileLexer_Token_BadString: + return "unterminated string"; + case cmListFileLexer_Token_CommentLine: + return "line comment"; + } + return "unknown token"; +} diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h index 3c89f63416a..199530f16c3 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h @@ -21,7 +21,8 @@ typedef enum cmListFileLexer_Type_e cmListFileLexer_Token_CommentBracket, cmListFileLexer_Token_BadCharacter, cmListFileLexer_Token_BadBracket, - cmListFileLexer_Token_BadString + cmListFileLexer_Token_BadString, + cmListFileLexer_Token_CommentLine } cmListFileLexer_Type; /* NOLINTNEXTLINE(modernize-use-using) */ @@ -55,7 +56,7 @@ typedef struct cmListFileLexer_s cmListFileLexer; cmListFileLexer* cmListFileLexer_New(void); int cmListFileLexer_SetFileName(cmListFileLexer*, const char*, cmListFileLexer_BOM* bom); -int cmListFileLexer_SetString(cmListFileLexer*, const char*); +int cmListFileLexer_SetString(cmListFileLexer*, const char*, int length); cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer*); long cmListFileLexer_GetCurrentLine(cmListFileLexer*); long cmListFileLexer_GetCurrentColumn(cmListFileLexer*); diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l index 94cf8a59430..2cf9f8cf2cb 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l @@ -18,10 +18,6 @@ Modify cmListFileLexer.c: /* IWYU pragma: no_forward_declare yyguts_t */ -#ifdef _WIN32 -#include "cmsys/Encoding.h" -#endif - /* Setup the proper cmListFileLexer_yylex declaration. */ #define YY_EXTRA_TYPE cmListFileLexer* #define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer) @@ -114,7 +110,10 @@ LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\" } [^\0\n]* { + lexer->token.type = cmListFileLexer_Token_CommentLine; + cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; + return 1; } \( { @@ -389,7 +388,6 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer) lexer->file = 0; } if (lexer->string_buffer) { - free(lexer->string_buffer); lexer->string_buffer = 0; lexer->string_left = 0; lexer->string_position = 0; @@ -458,13 +456,7 @@ int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name, int result = 1; cmListFileLexerDestroy(lexer); if (name) { -#ifdef _WIN32 - wchar_t* wname = cmsysEncoding_DupToWide(name); - lexer->file = _wfopen(wname, L"rb"); - free(wname); -#else lexer->file = fopen(name, "rb"); -#endif if (lexer->file) { if (bom) { *bom = cmListFileLexer_ReadBOM(lexer->file); @@ -478,20 +470,14 @@ int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name, } /*--------------------------------------------------------------------------*/ -int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text) +int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text, int length) { int result = 1; cmListFileLexerDestroy(lexer); if (text) { - int length = (int)strlen(text); - lexer->string_buffer = (char*)malloc(length + 1); - if (lexer->string_buffer) { - strcpy(lexer->string_buffer, text); - lexer->string_position = lexer->string_buffer; - lexer->string_left = length; - } else { - result = 0; - } + lexer->string_buffer = (char *) text; + lexer->string_position = lexer->string_buffer; + lexer->string_left = length; } cmListFileLexerInit(lexer); return result; @@ -555,6 +541,8 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, return "unterminated bracket"; case cmListFileLexer_Token_BadString: return "unterminated string"; + case cmListFileLexer_Token_CommentLine: + return "line comment"; } return "unknown token"; } diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h index 27225280d6f..08088613428 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmStandardLexer.h @@ -24,8 +24,6 @@ # define _XOPEN_SOURCE 700 #endif -#include "cmsys/Configure.h" // IWYU pragma: keep - /* Disable some warnings. */ #if defined(_MSC_VER) # pragma warning(disable : 4018) @@ -38,6 +36,7 @@ # pragma warning(disable : 4309) # pragma warning(disable : 4706) # pragma warning(disable : 4786) +# pragma warning(disable : 4996) #endif #if defined(__GNUC__) && !defined(__INTEL_COMPILER) @@ -80,10 +79,10 @@ #define YY_NO_UNPUT 1 #define ECHO -#include -typedef KWIML_INT_int8_t flex_int8_t; -typedef KWIML_INT_uint8_t flex_uint8_t; -typedef KWIML_INT_int16_t flex_int16_t; -typedef KWIML_INT_uint16_t flex_uint16_t; -typedef KWIML_INT_int32_t flex_int32_t; -typedef KWIML_INT_uint32_t flex_uint32_t; +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; diff --git a/src/plugins/cmakeprojectmanager/CMakeLists.txt b/src/plugins/cmakeprojectmanager/CMakeLists.txt index 683a2a407a8..e12c9656a83 100644 --- a/src/plugins/cmakeprojectmanager/CMakeLists.txt +++ b/src/plugins/cmakeprojectmanager/CMakeLists.txt @@ -2,6 +2,7 @@ add_qtc_plugin(CMakeProjectManager PLUGIN_CLASS CMakeProjectPlugin DEPENDS QmlJS PLUGIN_DEPENDS Core CppEditor ProjectExplorer TextEditor QtSupport + INCLUDES 3dparty/cmake SOURCES builddirparameters.cpp builddirparameters.h cmake_global.h @@ -44,4 +45,7 @@ add_qtc_plugin(CMakeProjectManager presetsparser.cpp presetsparser.h presetsmacros.cpp presetsmacros.h projecttreehelper.cpp projecttreehelper.h + 3rdparty/cmake/cmListFileCache.cxx + 3rdparty/cmake/cmListFileLexer.c + 3rdparty/cmake/cmListFileCache.h ) From 35df3812f7797bff5fd4ce4290f768f9bb8ca4c3 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 19 Apr 2023 08:23:17 +0200 Subject: [PATCH 0598/1447] Debugger: Improve detection for the need of Qml Debugger By default QC performs an educated guess whether to enable QML debugging or not. Improve this as the detection may fail and leave the user without a special hint depending on the project structure. Fixes: QTCREATORBUG-28627 Change-Id: Ibd461aff2bf9be7058bdf33c8740ef07a457c365 Reviewed-by: hjk --- .../debuggerrunconfigurationaspect.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index d8ebd2e9b1d..729857e9b20 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -5,6 +5,8 @@ #include "debuggertr.h" +#include + #include #include #include @@ -251,12 +253,26 @@ bool DebuggerRunConfigurationAspect::useCppDebugger() const return m_cppAspect->m_value == EnabledLanguage; } +static bool projectHasQmlDefines(ProjectExplorer::Project *project) +{ + auto projectInfo = CppEditor::CppModelManager::instance()->projectInfo(project); + QTC_ASSERT(projectInfo, return false); + return Utils::anyOf(projectInfo->projectParts(), + [](const CppEditor::ProjectPart::ConstPtr &part){ + return Utils::anyOf(part->projectMacros, [](const Macro ¯o){ + return macro.key == "QT_DECLARATIVE_LIB" + || macro.key == "QT_QUICK_LIB" + || macro.key == "QT_QML_LIB"; + }); + }); +} + bool DebuggerRunConfigurationAspect::useQmlDebugger() const { if (m_qmlAspect->m_value == AutoEnabledLanguage) { const Core::Context languages = m_target->project()->projectLanguages(); if (!languages.contains(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID)) - return false; + return projectHasQmlDefines(m_target->project()); // // Try to find a build configuration to check whether qml debugging is enabled there From e0219fad4d9b540145739832a5d91045a3f3fd0e Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 20 Apr 2023 11:00:50 +0200 Subject: [PATCH 0599/1447] Debugger: Make debugger aspect more explicit There are basically 3 states for the decision whether to start a debugger or not. But these had been under-represented by just displaying 2 states. Enabled (checked) and disabled (unchecked) are obvious, but the default of Auto (represented as checked) is there for convenience of the user, but it has some drawbacks of failing its guess whether to enable the debugger or not. Turn the former check boxes into a tri-state combo boxes and explicitly display the consequences inside the summary. Task-number: QTCREATORBUG-28627 Change-Id: Ieffed5b227ae978555258097385d6e80dfad3ac6 Reviewed-by: Leena Miettinen Reviewed-by: hjk --- .../debuggerrunconfigurationaspect.cpp | 179 ++++-------------- .../debugger/debuggerrunconfigurationaspect.h | 6 +- 2 files changed, 44 insertions(+), 141 deletions(-) diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 729857e9b20..3c43ee18f2f 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -31,121 +31,10 @@ #include #include -using namespace Debugger::Internal; using namespace ProjectExplorer; using namespace Utils; namespace Debugger { -namespace Internal { - -enum DebuggerLanguageStatus { - DisabledLanguage = 0, - EnabledLanguage, - AutoEnabledLanguage -}; - -class DebuggerLanguageAspect : public BaseAspect -{ -public: - DebuggerLanguageAspect() = default; - - void addToLayout(Layouting::LayoutBuilder &builder) override; - - bool value() const; - void setValue(bool val); - - void setAutoSettingsKey(const QString &settingsKey); - void setLabel(const QString &label); - void setInfoLabelText(const QString &text) { m_infoLabelText = text; } - - void setClickCallBack(const std::function &clickCallBack) - { - m_clickCallBack = clickCallBack; - } - - void fromMap(const QVariantMap &map) override; - void toMap(QVariantMap &map) const override; - -public: - DebuggerLanguageStatus m_value = AutoEnabledLanguage; - bool m_defaultValue = false; - QString m_label; - QString m_infoLabelText; - QPointer m_checkBox; // Owned by configuration widget - QPointer m_infoLabel; // Owned by configuration widget - QString m_autoSettingsKey; - - std::function m_clickCallBack; -}; - -void DebuggerLanguageAspect::addToLayout(Layouting::LayoutBuilder &builder) -{ - QTC_CHECK(!m_checkBox); - m_checkBox = new QCheckBox(m_label); - m_checkBox->setChecked(m_value); - m_checkBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); - - QTC_CHECK(m_clickCallBack); - connect(m_checkBox, &QAbstractButton::clicked, this, m_clickCallBack, Qt::QueuedConnection); - - connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] { - m_value = m_checkBox->isChecked() ? EnabledLanguage : DisabledLanguage; - emit changed(); - }); - builder.addItem(QString()); - builder.addItem(m_checkBox.data()); - - if (!m_infoLabelText.isEmpty()) { - QTC_CHECK(!m_infoLabel); - m_infoLabel = new QLabel(m_infoLabelText); - connect(m_infoLabel, &QLabel::linkActivated, [](const QString &link) { - Core::HelpManager::showHelpUrl(link); - }); - builder.addItem(m_infoLabel.data()); - } -} - -void DebuggerLanguageAspect::setAutoSettingsKey(const QString &settingsKey) -{ - m_autoSettingsKey = settingsKey; -} - -void DebuggerLanguageAspect::fromMap(const QVariantMap &map) -{ - const bool val = map.value(settingsKey(), false).toBool(); - const bool autoVal = map.value(m_autoSettingsKey, false).toBool(); - m_value = autoVal ? AutoEnabledLanguage : val ? EnabledLanguage : DisabledLanguage; -} - -void DebuggerLanguageAspect::toMap(QVariantMap &data) const -{ - data.insert(settingsKey(), m_value == EnabledLanguage); - data.insert(m_autoSettingsKey, m_value == AutoEnabledLanguage); -} - - -bool DebuggerLanguageAspect::value() const -{ - return m_value; -} - -void DebuggerLanguageAspect::setValue(bool value) -{ - const DebuggerLanguageStatus status = value ? EnabledLanguage : DisabledLanguage; - const bool didChange = status != m_value; - m_value = status; - if (m_checkBox) - m_checkBox->setChecked(m_value); - if (didChange) - emit changed(); -} - -void DebuggerLanguageAspect::setLabel(const QString &label) -{ - m_label = label; -} - -} // Internal /*! \class Debugger::DebuggerRunConfigurationAspect @@ -158,9 +47,16 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) setDisplayName(Tr::tr("Debugger settings")); setConfigWidgetCreator([this] { - Layouting::Form builder; + Layouting::Grid builder; builder.addRow(m_cppAspect); - builder.addRow(m_qmlAspect); + auto info = new QLabel( + Tr::tr("What are the prerequisites?")); + builder.addRow({m_qmlAspect, info}); + connect(info, &QLabel::linkActivated, [](const QString &link) { + Core::HelpManager::showHelpUrl(link); + }); builder.addRow(m_overrideStartupAspect); static const QString env = qtcEnvironmentVariable("QTC_DEBUGGER_MULTIPROCESS"); @@ -175,10 +71,16 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) const auto setSummaryText = [this, details] { QStringList items; - if (m_cppAspect->value()) - items.append(m_cppAspect->m_label); - if (m_qmlAspect->value()) - items.append(m_qmlAspect->m_label); + if (m_cppAspect->value() == TriState::Enabled) + items.append(Tr::tr("Enable C++ debugger")); + else if (m_cppAspect->value() == TriState::Default) + items.append(Tr::tr("Try to determine need for C++ debugger")); + + if (m_qmlAspect->value() == TriState::Enabled) + items.append(Tr::tr("Enable QML debugger")); + else if (m_qmlAspect->value() == TriState::Default) + items.append(Tr::tr("Try to determine need for QML debugger")); + items.append(m_overrideStartupAspect->value().isEmpty() ? Tr::tr("Without additional startup commands") : Tr::tr("With additional startup commands")); @@ -198,29 +100,25 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) addDataExtractor(this, &DebuggerRunConfigurationAspect::useMultiProcess, &Data::useMultiProcess); addDataExtractor(this, &DebuggerRunConfigurationAspect::overrideStartup, &Data::overrideStartup); - m_cppAspect = new DebuggerLanguageAspect; - m_cppAspect->setLabel(Tr::tr("Enable C++")); + m_cppAspect = new TriStateAspect(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); + m_cppAspect->setLabelText(Tr::tr("C++ debugger:")); m_cppAspect->setSettingsKey("RunConfiguration.UseCppDebugger"); - m_cppAspect->setAutoSettingsKey("RunConfiguration.UseCppDebuggerAuto"); - m_qmlAspect = new DebuggerLanguageAspect; - m_qmlAspect->setLabel(Tr::tr("Enable QML")); + m_qmlAspect = new TriStateAspect(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); + m_qmlAspect->setLabelText(Tr::tr("QML debugger:")); m_qmlAspect->setSettingsKey("RunConfiguration.UseQmlDebugger"); - m_qmlAspect->setAutoSettingsKey("RunConfiguration.UseQmlDebuggerAuto"); - m_qmlAspect->setInfoLabelText(Tr::tr("What are the prerequisites?")); // Make sure at least one of the debuggers is set to be active. - m_cppAspect->setClickCallBack([this](bool on) { - if (!on && !m_qmlAspect->value()) - m_qmlAspect->setValue(true); + connect(m_cppAspect, &TriStateAspect::changed, this, [this]{ + if (m_cppAspect->value() == TriState::Disabled && m_qmlAspect->value() == TriState::Disabled) + m_qmlAspect->setValue(TriState::Default); }); - m_qmlAspect->setClickCallBack([this](bool on) { - if (!on && !m_cppAspect->value()) - m_cppAspect->setValue(true); + connect(m_qmlAspect, &TriStateAspect::changed, this, [this]{ + if (m_qmlAspect->value() == TriState::Disabled && m_cppAspect->value() == TriState::Disabled) + m_cppAspect->setValue(TriState::Default); }); + m_multiProcessAspect = new BoolAspect; m_multiProcessAspect->setSettingsKey("RunConfiguration.UseMultiProcess"); m_multiProcessAspect->setLabel(Tr::tr("Enable Debugging of Subprocesses"), @@ -242,15 +140,15 @@ DebuggerRunConfigurationAspect::~DebuggerRunConfigurationAspect() void DebuggerRunConfigurationAspect::setUseQmlDebugger(bool value) { - m_qmlAspect->setValue(value); + m_qmlAspect->setValue(value ? TriState::Enabled : TriState::Disabled); } bool DebuggerRunConfigurationAspect::useCppDebugger() const { - if (m_cppAspect->m_value == AutoEnabledLanguage) + if (m_cppAspect->value() == TriState::Default) return m_target->project()->projectLanguages().contains( ProjectExplorer::Constants::CXX_LANGUAGE_ID); - return m_cppAspect->m_value == EnabledLanguage; + return m_cppAspect->value() == TriState::Enabled; } static bool projectHasQmlDefines(ProjectExplorer::Project *project) @@ -269,7 +167,7 @@ static bool projectHasQmlDefines(ProjectExplorer::Project *project) bool DebuggerRunConfigurationAspect::useQmlDebugger() const { - if (m_qmlAspect->m_value == AutoEnabledLanguage) { + if (m_qmlAspect->value() == TriState::Default) { const Core::Context languages = m_target->project()->projectLanguages(); if (!languages.contains(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID)) return projectHasQmlDefines(m_target->project()); @@ -283,7 +181,7 @@ bool DebuggerRunConfigurationAspect::useQmlDebugger() const return !languages.contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID); } - return m_qmlAspect->m_value == EnabledLanguage; + return m_qmlAspect->value() == TriState::Enabled; } bool DebuggerRunConfigurationAspect::useMultiProcess() const @@ -323,6 +221,13 @@ void DebuggerRunConfigurationAspect::fromMap(const QVariantMap &map) { m_cppAspect->fromMap(map); m_qmlAspect->fromMap(map); + + // respect old project settings + if (map.value("RunConfiguration.UseCppDebuggerAuto", false).toBool()) + m_cppAspect->setValue(TriState::Default); + if (map.value("RunConfiguration.UseQmlDebuggerAuto", false).toBool()) + m_qmlAspect->setValue(TriState::Default); + m_multiProcessAspect->fromMap(map); m_overrideStartupAspect->fromMap(map); } diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.h b/src/plugins/debugger/debuggerrunconfigurationaspect.h index 2534d4f81ca..53b9c1f54d2 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.h +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.h @@ -10,8 +10,6 @@ namespace Debugger { -namespace Internal { class DebuggerLanguageAspect; } - class DEBUGGER_EXPORT DebuggerRunConfigurationAspect : public ProjectExplorer::GlobalOrProjectAspect { @@ -40,8 +38,8 @@ public: }; private: - Internal::DebuggerLanguageAspect *m_cppAspect; - Internal::DebuggerLanguageAspect *m_qmlAspect; + Utils::TriStateAspect *m_cppAspect; + Utils::TriStateAspect *m_qmlAspect; Utils::BoolAspect *m_multiProcessAspect; Utils::StringAspect *m_overrideStartupAspect; ProjectExplorer::Target *m_target; From 7f49d93fc1a1b90c7cda44ea0c31c8a7798fb1d3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 15:11:49 +0200 Subject: [PATCH 0600/1447] FileSystemFilter: Use Acceptor for LocatorFilterEntry Change-Id: I64059f0b02f8b893ba092b8ccea6c85453463078 Reviewed-by: Eike Ziller --- .../coreplugin/locator/filesystemfilter.cpp | 103 +++++++++--------- .../coreplugin/locator/filesystemfilter.h | 2 - 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index fdc127e5d92..37b3ede81dd 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -64,6 +64,37 @@ void FileSystemFilter::prepareSearch(const QString &entry) m_currentIncludeHidden = m_includeHidden; } +static const char kAlwaysCreate[] = "Locator/FileSystemFilter/AlwaysCreate"; + +static void createAndOpen(const FilePath &filePath) +{ + if (!filePath.exists()) { + if (CheckableMessageBox::shouldAskAgain(ICore::settings(), kAlwaysCreate)) { + CheckableMessageBox messageBox(ICore::dialogParent()); + messageBox.setWindowTitle(Tr::tr("Create File")); + messageBox.setIcon(QMessageBox::Question); + messageBox.setText(Tr::tr("Create \"%1\"?").arg(filePath.shortNativePath())); + messageBox.setCheckBoxVisible(true); + messageBox.setCheckBoxText(Tr::tr("Always create")); + messageBox.setChecked(false); + messageBox.setStandardButtons(QDialogButtonBox::Cancel); + QPushButton *createButton = messageBox.addButton(Tr::tr("Create"), + QDialogButtonBox::AcceptRole); + messageBox.setDefaultButton(QDialogButtonBox::Cancel); + messageBox.exec(); + if (messageBox.clickedButton() != createButton) + return; + if (messageBox.isChecked()) + CheckableMessageBox::doNotAskAgain(ICore::settings(), kAlwaysCreate); + } + QFile file(filePath.toFSPathString()); + file.open(QFile::WriteOnly); + file.close(); + VcsManager::promptToAdd(filePath.absolutePath(), {filePath}); + } + EditorManager::openEditor(filePath); +} + QList FileSystemFilter::matchesFor(QFutureInterface &future, const QString &entry) { @@ -112,7 +143,13 @@ QList FileSystemFilter::matchesFor(QFutureInterface FileSystemFilter::matchesFor(QFutureInterface FileSystemFilter::matchesFor(QFutureInterface()); } -const char kAlwaysCreate[] = "Locator/FileSystemFilter/AlwaysCreate"; - -void FileSystemFilter::accept(const LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const -{ - Q_UNUSED(selectionLength) - if (selection.filePath.isDir()) { - const QString value - = shortcutString() + ' ' - + selection.filePath.absoluteFilePath().cleanPath().pathAppended("/").toUserOutput(); - *newText = value; - *selectionStart = value.length(); - } else { - // Don't block locator filter execution with dialog - QMetaObject::invokeMethod(EditorManager::instance(), [selection] { - if (!selection.filePath.exists()) { - if (CheckableMessageBox::shouldAskAgain(ICore::settings(), kAlwaysCreate)) { - CheckableMessageBox messageBox(ICore::dialogParent()); - messageBox.setWindowTitle(Tr::tr("Create File")); - messageBox.setIcon(QMessageBox::Question); - messageBox.setText(Tr::tr("Create \"%1\"?").arg(selection.filePath.shortNativePath())); - messageBox.setCheckBoxVisible(true); - messageBox.setCheckBoxText(Tr::tr("Always create")); - messageBox.setChecked(false); - messageBox.setStandardButtons(QDialogButtonBox::Cancel); - QPushButton *createButton = messageBox.addButton(Tr::tr("Create"), - QDialogButtonBox::AcceptRole); - messageBox.setDefaultButton(QDialogButtonBox::Cancel); - messageBox.exec(); - if (messageBox.clickedButton() != createButton) - return; - if (messageBox.isChecked()) - CheckableMessageBox::doNotAskAgain(ICore::settings(), kAlwaysCreate); - } - QFile file(selection.filePath.toFSPathString()); - file.open(QFile::WriteOnly); - file.close(); - VcsManager::promptToAdd(selection.filePath.absolutePath(), {selection.filePath}); - } - EditorManager::openEditor(selection); - }, Qt::QueuedConnection); - } -} - class FileSystemFilterOptions : public QDialog { public: diff --git a/src/plugins/coreplugin/locator/filesystemfilter.h b/src/plugins/coreplugin/locator/filesystemfilter.h index fea41e5779e..f2983ad40af 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.h +++ b/src/plugins/coreplugin/locator/filesystemfilter.h @@ -22,8 +22,6 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; From 0b5db8e5583df77788cb223c71aec6128242faf1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 15:47:47 +0200 Subject: [PATCH 0601/1447] ExecuteFilter: Use Acceptor for LocatorFilterEntry Change-Id: I44bac91b192f8f9eb15b3151cd3d0d21caed0312 Reviewed-by: Eike Ziller --- .../coreplugin/locator/executefilter.cpp | 113 +++++++++--------- .../coreplugin/locator/executefilter.h | 4 +- 2 files changed, 56 insertions(+), 61 deletions(-) diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 6be23fff3f5..723e9f60808 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -39,12 +39,54 @@ ExecuteFilter::~ExecuteFilter() removeProcess(); } -QList ExecuteFilter::matchesFor(QFutureInterface &future, - const QString &entry) +void ExecuteFilter::acceptCommand(const QString &cmd) { - QList value; - if (!entry.isEmpty()) // avoid empty entry - value.append(LocatorFilterEntry(this, entry)); + const QString displayName = cmd.trimmed(); + const int index = m_commandHistory.indexOf(displayName); + if (index != -1 && index != 0) + m_commandHistory.removeAt(index); + if (index != 0) + m_commandHistory.prepend(displayName); + static const int maxHistory = 100; + while (m_commandHistory.size() > maxHistory) + m_commandHistory.removeLast(); + + bool found; + QString workingDirectory = globalMacroExpander()->value("CurrentDocument:Path", &found); + if (!found || workingDirectory.isEmpty()) + workingDirectory = globalMacroExpander()->value("CurrentDocument:Project:Path", &found); + + const ExecuteData data{CommandLine::fromUserInput(displayName, globalMacroExpander()), + FilePath::fromString(workingDirectory)}; + if (m_process) { + const QString info(Tr::tr("Previous command is still running (\"%1\").\n" + "Do you want to kill it?").arg(headCommand())); + const auto result = QMessageBox::question(ICore::dialogParent(), + Tr::tr("Kill Previous Process?"), info, + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Yes); + if (result == QMessageBox::Cancel) + return; + if (result == QMessageBox::No) { + m_taskQueue.enqueue(data); + return; + } + removeProcess(); + } + m_taskQueue.enqueue(data); + runHeadCommand(); +} + +QList ExecuteFilter::matchesFor(QFutureInterface &future, + const QString &entry) +{ + QList results; + if (!entry.isEmpty()) { // avoid empty entry + LocatorFilterEntry filterEntry; + filterEntry.displayName = entry; + filterEntry.acceptor = [this, entry] { acceptCommand(entry); return AcceptResult(); }; + results.append(filterEntry); + } QList others; const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); for (const QString &cmd : std::as_const(m_commandHistory)) { @@ -52,64 +94,19 @@ QList ExecuteFilter::matchesFor(QFutureInterface= 0) { filterEntry.highlightInfo = {index, int(entry.length())}; - value.append(filterEntry); + results.append(filterEntry); } else { others.append(filterEntry); } } - value.append(others); - return value; -} - -void ExecuteFilter::accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - auto p = const_cast(this); - - const QString value = selection.displayName.trimmed(); - - const int index = m_commandHistory.indexOf(value); - if (index != -1 && index != 0) - p->m_commandHistory.removeAt(index); - if (index != 0) - p->m_commandHistory.prepend(value); - static const int maxHistory = 100; - while (p->m_commandHistory.size() > maxHistory) - p->m_commandHistory.removeLast(); - - bool found; - QString workingDirectory = Utils::globalMacroExpander()->value("CurrentDocument:Path", &found); - if (!found || workingDirectory.isEmpty()) - workingDirectory = Utils::globalMacroExpander()->value("CurrentDocument:Project:Path", &found); - - ExecuteData d; - d.command = CommandLine::fromUserInput(value, Utils::globalMacroExpander()); - d.workingDirectory = FilePath::fromString(workingDirectory); - - if (m_process) { - const QString info(Tr::tr("Previous command is still running (\"%1\").\nDo you want to kill it?") - .arg(p->headCommand())); - int r = QMessageBox::question(ICore::dialogParent(), Tr::tr("Kill Previous Process?"), info, - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::Yes); - if (r == QMessageBox::Cancel) - return; - if (r == QMessageBox::No) { - p->m_taskQueue.enqueue(d); - return; - } - p->removeProcess(); - } - - p->m_taskQueue.enqueue(d); - p->runHeadCommand(); + results.append(others); + return results; } void ExecuteFilter::done() @@ -163,8 +160,8 @@ void ExecuteFilter::createProcess() if (m_process) return; - m_process = new Utils::QtcProcess; - m_process->setEnvironment(Utils::Environment::systemEnvironment()); + m_process = new QtcProcess; + m_process->setEnvironment(Environment::systemEnvironment()); connect(m_process, &QtcProcess::done, this, &ExecuteFilter::done); connect(m_process, &QtcProcess::readyReadStandardOutput, this, &ExecuteFilter::readStandardOutput); connect(m_process, &QtcProcess::readyReadStandardError, this, &ExecuteFilter::readStandardError); diff --git a/src/plugins/coreplugin/locator/executefilter.h b/src/plugins/coreplugin/locator/executefilter.h index 0d499e88606..e6628c100cc 100644 --- a/src/plugins/coreplugin/locator/executefilter.h +++ b/src/plugins/coreplugin/locator/executefilter.h @@ -31,10 +31,8 @@ public: ~ExecuteFilter() override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - private: + void acceptCommand(const QString &cmd); void done(); void readStandardOutput(); void readStandardError(); From 64f946445cda78be84d70c322ee6811a5cda8d79 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 16:03:41 +0200 Subject: [PATCH 0602/1447] CppLocatorFilter: Add cppCurrentDocumentMatcher() Add also a test for it. Change-Id: I324b1a2cbe89c0a1258dde93524689cb85e06737 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler Reviewed-by: --- .../coreplugin/locator/ilocatorfilter.h | 3 +- .../cppeditor/cppcurrentdocumentfilter.cpp | 4 +- src/plugins/cppeditor/cpplocatorfilter.cpp | 152 ++++++++++++++++++ src/plugins/cppeditor/cpplocatorfilter.h | 1 + .../cppeditor/cpplocatorfilter_test.cpp | 22 ++- src/plugins/cppeditor/cppmodelmanager.cpp | 2 + 6 files changed, 178 insertions(+), 6 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 848321daaf1..a6571d186e2 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -148,7 +148,8 @@ class LocatorMatcherPrivate; enum class MatcherType { AllSymbols, Classes, - Functions + Functions, + CurrentDocumentSymbols }; class CORE_EXPORT LocatorMatcher final : public QObject diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index 6777ca1c11d..e3f4bbb777b 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -52,7 +52,7 @@ void CppCurrentDocumentFilter::makeAuxiliary() } QList CppCurrentDocumentFilter::matchesFor( - QFutureInterface &future, const QString & entry) + QFutureInterface &future, const QString &entry) { const QRegularExpression regexp = createRegExp(entry); if (!regexp.isValid()) @@ -180,7 +180,7 @@ QList CppCurrentDocumentFilter::itemsOfCurrentDocument() const Snapshot snapshot = m_modelManager->snapshot(); if (const Document::Ptr thisDocument = snapshot.document(m_currentFileName)) { IndexItem::Ptr rootNode = search(thisDocument); - rootNode->visitAllChildren([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult { + rootNode->visitAllChildren([&](const IndexItem::Ptr &info) { m_itemsOfCurrentDoc.append(info); return IndexItem::Recurse; }); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 9895e23a26d..d23d81e2d51 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -7,13 +7,19 @@ #include "cppeditorplugin.h" #include "cppeditortr.h" #include "cpplocatordata.h" +#include "cppmodelmanager.h" + +#include +#include #include #include +#include #include using namespace Core; +using namespace CPlusPlus; using namespace Utils; namespace CppEditor { @@ -163,6 +169,152 @@ LocatorMatcherTask cppFunctionMatcher() return locatorMatcher(IndexItem::Function, converter); } +QList itemsOfCurrentDocument(const FilePath ¤tFileName) +{ + if (currentFileName.isEmpty()) + return {}; + + QList results; + const Snapshot snapshot = CppModelManager::instance()->snapshot(); + if (const Document::Ptr thisDocument = snapshot.document(currentFileName)) { + SearchSymbols search; + search.setSymbolsToSearchFor(SymbolSearcher::Declarations | + SymbolSearcher::Enums | + SymbolSearcher::Functions | + SymbolSearcher::Classes); + IndexItem::Ptr rootNode = search(thisDocument); + rootNode->visitAllChildren([&](const IndexItem::Ptr &info) { + results.append(info); + return IndexItem::Recurse; + }); + } + return results; +} + +LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &match, + LocatorFilterEntry::HighlightInfo::DataType dataType) +{ + const FuzzyMatcher::HighlightingPositions positions = + FuzzyMatcher::highlightingPositions(match); + + return LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, dataType); +} + +void matchesForCurrentDocument(QPromise &promise, + const QString &entry, const FilePath ¤tFileName) +{ + const QRegularExpression regexp = FuzzyMatcher::createRegExp(entry, Qt::CaseInsensitive, false); + if (!regexp.isValid()) + return; + + struct Entry + { + LocatorFilterEntry entry; + IndexItem::Ptr info; + }; + QList goodEntries; + QList betterEntries; + const QList items = itemsOfCurrentDocument(currentFileName); + for (const IndexItem::Ptr &info : items) { + if (promise.isCanceled()) + break; + + QString matchString = info->symbolName(); + if (info->type() == IndexItem::Declaration) + matchString = info->representDeclaration(); + else if (info->type() == IndexItem::Function) + matchString += info->symbolType(); + + QRegularExpressionMatch match = regexp.match(matchString); + if (match.hasMatch()) { + const bool betterMatch = match.capturedStart() == 0; + QString name = matchString; + QString extraInfo = info->symbolScope(); + if (info->type() == IndexItem::Function) { + if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) { + name += info->symbolType(); + match = regexp.match(name); + } + } + + // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. + LocatorFilterEntry filterEntry(nullptr, name); + filterEntry.displayIcon = info->icon(); + filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; + filterEntry.extraInfo = extraInfo; + if (match.hasMatch()) { + filterEntry.highlightInfo = highlightInfo(match, + LocatorFilterEntry::HighlightInfo::DisplayName); + } else { + match = regexp.match(extraInfo); + filterEntry.highlightInfo = + highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo); + } + + if (betterMatch) + betterEntries.append({filterEntry, info}); + else + goodEntries.append({filterEntry, info}); + } + } + + // entries are unsorted by design! + betterEntries += goodEntries; + + QHash> possibleDuplicates; + for (const Entry &e : std::as_const(betterEntries)) + possibleDuplicates[e.info->scopedSymbolName() + e.info->symbolType()] << e; + for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { + const QList &duplicates = it.value(); + if (duplicates.size() == 1) + continue; + QList declarations; + QList definitions; + for (const Entry &candidate : duplicates) { + const IndexItem::Ptr info = candidate.info; + if (info->type() != IndexItem::Function) + break; + if (info->isFunctionDefinition()) + definitions << candidate; + else + declarations << candidate; + } + if (definitions.size() == 1 + && declarations.size() + definitions.size() == duplicates.size()) { + for (const Entry &decl : std::as_const(declarations)) { + Utils::erase(betterEntries, [&decl](const Entry &e) { + return e.info == decl.info; + }); + } + } + } + promise.addResult(Utils::transform(betterEntries, + [](const Entry &entry) { return entry.entry; })); +} + +FilePath currentFileName() +{ + IEditor *currentEditor = EditorManager::currentEditor(); + return currentEditor ? currentEditor->document()->filePath() : FilePath(); +} + +LocatorMatcherTask cppCurrentDocumentMatcher() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [=](AsyncTask &async) { + async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); + async.setConcurrentCallData(matchesForCurrentDocument, storage->input, currentFileName()); + }; + const auto onDone = [storage](const AsyncTask &async) { + if (async.isResultAvailable()) + storage->output = async.result(); + }; + return {Async(onSetup, onDone, onDone), storage}; +} + CppLocatorFilter::CppLocatorFilter() { setId(Constants::LOCATOR_FILTER_ID); diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 799bafc553a..33ebce05f41 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -13,6 +13,7 @@ namespace CppEditor { Core::LocatorMatcherTask CPPEDITOR_EXPORT cppAllSymbolsMatcher(); Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher(); Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher(); +Core::LocatorMatcherTask CPPEDITOR_EXPORT cppCurrentDocumentMatcher(); class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter { diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index fd68b4c1cfd..f81ab6c40f6 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -77,6 +77,7 @@ class CppCurrentDocumentFilterTestCase { public: CppCurrentDocumentFilterTestCase(const FilePath &filePath, + const QList &matchers, const ResultDataList &expectedResults, const QString &searchText = QString()) : BasicLocatorFilterTest(CppModelManager::instance()->currentDocumentFilter()) @@ -85,7 +86,16 @@ public: QVERIFY(succeededSoFar()); QVERIFY(!m_filePath.isEmpty()); - ResultDataList results = ResultData::fromFilterEntryList(matchesFor(searchText)); + const auto runMatcher = [this, matchers, searchText] { + CppCurrentDocumentFilterTestCase::doBeforeLocatorRun(); + const auto result = LocatorMatcher::runBlocking(matchers, searchText); + CppCurrentDocumentFilterTestCase::doAfterLocatorRun(); + return result; + }; + + const QList entries = matchers.isEmpty() ? matchesFor(searchText) + : runMatcher(); + ResultDataList results = ResultData::fromFilterEntryList(entries); if (debug) { ResultData::printFilterEntries(expectedResults, "Expected:"); ResultData::printFilterEntries(results, "Results:"); @@ -371,7 +381,10 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("main()", ""), }; - CppCurrentDocumentFilterTestCase(testFile, expectedResults); + CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults); + CppCurrentDocumentFilterTestCase(testFile, + LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols), + expectedResults); } void LocatorFilterTest::testCurrentDocumentHighlighting() @@ -395,7 +408,10 @@ void LocatorFilterTest::testCurrentDocumentHighlighting() Tests::VerifyCleanCppModelManager verify; - CppCurrentDocumentFilterTestCase(testFile, expectedResults, searchText); + CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults, searchText); + CppCurrentDocumentFilterTestCase(testFile, + LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols), + expectedResults, searchText); } void LocatorFilterTest::testFunctionsFilterHighlighting() diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index f4aacf74da1..17a702170e8 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -903,6 +903,8 @@ void CppModelManager::initCppTools() [] { return QList{CppEditor::cppClassMatcher()}; }); LocatorMatcher::addMatcherCreator(MatcherType::Functions, [] { return QList{CppEditor::cppFunctionMatcher()}; }); + LocatorMatcher::addMatcherCreator(MatcherType::CurrentDocumentSymbols, + [] { return QList{CppEditor::cppCurrentDocumentMatcher()}; }); } CppModelManager::CppModelManager() From 107d16fe34a8a4b93ff0d810799a6f7a0ed79cdf Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 22:42:25 +0200 Subject: [PATCH 0603/1447] ExternalToolsFilter: Use Acceptor for LocatorFilterEntry Change-Id: I1d9073f9849be7ada05a9f12237db2a32a5c802b Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- .../locator/externaltoolsfilter.cpp | 37 ++++++++----------- .../coreplugin/locator/externaltoolsfilter.h | 5 +-- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index 7828cc13724..1478cbbc718 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -4,6 +4,7 @@ #include "externaltoolsfilter.h" #include "../coreconstants.h" +#include "../coreplugin.h" #include "../coreplugintr.h" #include "../externaltool.h" #include "../externaltoolmanager.h" @@ -30,26 +31,6 @@ QList ExternalToolsFilter::matchesFor(QFutureInterface(); - QTC_ASSERT(tool, return); - - auto runner = new ExternalToolRunner(tool); - if (runner->hasError()) - MessageManager::writeFlashing(runner->errorString()); -} - void ExternalToolsFilter::prepareSearch(const QString &entry) { QList bestEntries; @@ -66,8 +47,14 @@ void ExternalToolsFilter::prepareSearch(const QString &entry) } if (index >= 0) { - LocatorFilterEntry filterEntry(this, tool->displayName()); - filterEntry.internalData = QVariant::fromValue(tool); + LocatorFilterEntry filterEntry; + filterEntry.displayName = tool->displayName(); + filterEntry.acceptor = [tool] { + auto runner = new ExternalToolRunner(tool); + if (runner->hasError()) + MessageManager::writeFlashing(runner->errorString()); + return AcceptResult(); + }; filterEntry.extraInfo = tool->description(); filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); @@ -81,6 +68,12 @@ void ExternalToolsFilter::prepareSearch(const QString &entry) } LocatorFilterEntry configEntry(this, "Configure External Tool..."); configEntry.extraInfo = "Opens External Tool settings"; + configEntry.acceptor = [] { + QMetaObject::invokeMethod(CorePlugin::instance(), [] { + ICore::showOptionsDialog(Constants::SETTINGS_ID_TOOLS); + }, Qt::QueuedConnection); + return AcceptResult(); + }; m_results = {}; m_results << bestEntries << betterEntries << goodEntries << configEntry; } diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.h b/src/plugins/coreplugin/locator/externaltoolsfilter.h index 74d5214aa38..e97c04c2768 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.h +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.h @@ -14,12 +14,9 @@ class ExternalToolsFilter : public ILocatorFilter public: ExternalToolsFilter(); + void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, int *selectionLength) const override; - void prepareSearch(const QString &entry) override; - private: QList m_results; }; From 74322dfedff042f0d4e8d4295d665e03b349edb4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 11 Apr 2023 23:23:34 +0200 Subject: [PATCH 0604/1447] LocatorFilterEntry: Get rid of internalData Change-Id: I2bcd64c39bdaf0fe8504b68ba4aaaef7cdcab475 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 1 - src/plugins/coreplugin/locator/ilocatorfilter.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 593bd4c6669..3e24d4c57c2 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -225,7 +225,6 @@ private: entry.displayName = ClangdClient::displayNameFromDocumentSymbol( static_cast(info.kind()), info.name(), info.detail().value_or(QString())); - entry.internalData = QVariant::fromValue(info); entry.linkForEditor = linkForDocSymbol(info); entry.extraInfo = parent.extraInfo; if (!entry.extraInfo.isEmpty()) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index a6571d186e2..c116209be7e 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -99,9 +99,6 @@ public: /* called by locator widget on accept. By default, when acceptor is empty, EditorManager::openEditor(LocatorFilterEntry) will be used instead. */ Acceptor acceptor; - /* can be used by the filter to save more information about the entry */ - /* Replaced by acceptor - DON'T USE IN NEW CODE, IT'S GOING TO BE REMOVED, SOON... */ - QVariant internalData; /* icon to display along with the entry */ std::optional displayIcon; /* file path, if the entry is related to a file, is used e.g. for resolving a file icon */ From d74c2369eef12e979eb22c2abdfed2b093719731 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 09:55:15 +0200 Subject: [PATCH 0605/1447] AutoTest: Take advantage of IOptionPage::setWidgetCreator() Less boilerplate for the implementation and user code access to IOptionPage::{apply,finish} is planned to be removed. Change-Id: I1d914d21c62a983a212d9696d14890cfd0e643c7 Reviewed-by: Christian Stenger --- src/plugins/autotest/testsettingspage.cpp | 90 ++++++++++------------- src/plugins/autotest/testsettingspage.h | 18 +---- 2 files changed, 41 insertions(+), 67 deletions(-) diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp index 1cd6e2d1ae4..6ba73675f7a 100644 --- a/src/plugins/autotest/testsettingspage.cpp +++ b/src/plugins/autotest/testsettingspage.cpp @@ -27,19 +27,18 @@ #include #include #include -#include using namespace Utils; -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { -class TestSettingsWidget : public QWidget +class TestSettingsWidget : public Core::IOptionsPageWidget { public: - explicit TestSettingsWidget(QWidget *parent = nullptr); + explicit TestSettingsWidget(TestSettings *settings); + + void apply() final; - void setSettings(const TestSettings &settings); TestSettings settings() const; private: @@ -49,6 +48,7 @@ private: void testToolsSettings(TestSettings &settings) const; void onFrameworkItemChanged(); + TestSettings *m_settings; QCheckBox *m_omitInternalMsgCB; QCheckBox *m_omitRunConfigWarnCB; QCheckBox *m_limitResultOutputCB; @@ -66,8 +66,8 @@ private: InfoLabel *m_frameworksWarn; }; -TestSettingsWidget::TestSettingsWidget(QWidget *parent) - : QWidget(parent) +TestSettingsWidget::TestSettingsWidget(TestSettings *settings) + : m_settings(settings) { resize(586, 469); @@ -203,25 +203,23 @@ TestSettingsWidget::TestSettingsWidget(QWidget *parent) m_openResultsOnFailCB, &QCheckBox::setEnabled); connect(m_limitResultDescriptionCb, &QCheckBox::toggled, m_limitResultDescriptionSpinBox, &QSpinBox::setEnabled); -} -void TestSettingsWidget::setSettings(const TestSettings &settings) -{ - m_timeoutSpin->setValue(settings.timeout / 1000); // we store milliseconds - m_omitInternalMsgCB->setChecked(settings.omitInternalMssg); - m_omitRunConfigWarnCB->setChecked(settings.omitRunConfigWarn); - m_limitResultOutputCB->setChecked(settings.limitResultOutput); - m_limitResultDescriptionCb->setChecked(settings.limitResultDescription); - m_limitResultDescriptionSpinBox->setEnabled(settings.limitResultDescription); - m_limitResultDescriptionSpinBox->setValue(settings.resultDescriptionMaxSize); - m_autoScrollCB->setChecked(settings.autoScroll); - m_processArgsCB->setChecked(settings.processArgs); - m_displayAppCB->setChecked(settings.displayApplication); - m_openResultsOnStartCB->setChecked(settings.popupOnStart); - m_openResultsOnFinishCB->setChecked(settings.popupOnFinish); - m_openResultsOnFailCB->setChecked(settings.popupOnFail); - m_runAfterBuildCB->setCurrentIndex(int(settings.runAfterBuild)); - populateFrameworksListWidget(settings.frameworks, settings.tools); + + m_timeoutSpin->setValue(settings->timeout / 1000); // we store milliseconds + m_omitInternalMsgCB->setChecked(settings->omitInternalMssg); + m_omitRunConfigWarnCB->setChecked(settings->omitRunConfigWarn); + m_limitResultOutputCB->setChecked(settings->limitResultOutput); + m_limitResultDescriptionCb->setChecked(settings->limitResultDescription); + m_limitResultDescriptionSpinBox->setEnabled(settings->limitResultDescription); + m_limitResultDescriptionSpinBox->setValue(settings->resultDescriptionMaxSize); + m_autoScrollCB->setChecked(settings->autoScroll); + m_processArgsCB->setChecked(settings->processArgs); + m_displayAppCB->setChecked(settings->displayApplication); + m_openResultsOnStartCB->setChecked(settings->popupOnStart); + m_openResultsOnFinishCB->setChecked(settings->popupOnFinish); + m_openResultsOnFailCB->setChecked(settings->popupOnFail); + m_runAfterBuildCB->setCurrentIndex(int(settings->runAfterBuild)); + populateFrameworksListWidget(settings->frameworks, settings->tools); } TestSettings TestSettingsWidget::settings() const @@ -343,30 +341,9 @@ void TestSettingsWidget::onFrameworkItemChanged() || (mixed == (ITestBase::Framework | ITestBase::Tool))); } -TestSettingsPage::TestSettingsPage(TestSettings *settings) - : m_settings(settings) +void TestSettingsWidget::apply() { - setId(Constants::AUTOTEST_SETTINGS_ID); - setDisplayName(Tr::tr("General")); - setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Testing")); - setCategoryIconPath(":/autotest/images/settingscategory_autotest.png"); -} - -QWidget *TestSettingsPage::widget() -{ - if (!m_widget) { - m_widget = new TestSettingsWidget; - m_widget->setSettings(*m_settings); - } - return m_widget; -} - -void TestSettingsPage::apply() -{ - if (!m_widget) // page was not shown at all - return; - const TestSettings newSettings = m_widget->settings(); + const TestSettings newSettings = settings(); const QList changedIds = Utils::filtered(newSettings.frameworksGrouping.keys(), [newSettings, this](const Id &id) { return newSettings.frameworksGrouping[id] != m_settings->frameworksGrouping[id]; @@ -388,5 +365,16 @@ void TestSettingsPage::apply() TestTreeModel::instance()->rebuild(changedIds); } -} // namespace Internal -} // namespace Autotest +// TestSettingsPage + +TestSettingsPage::TestSettingsPage(TestSettings *settings) +{ + setId(Constants::AUTOTEST_SETTINGS_ID); + setDisplayName(Tr::tr("General")); + setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("Testing")); + setCategoryIconPath(":/autotest/images/settingscategory_autotest.png"); + setWidgetCreator([settings] { return new TestSettingsWidget(settings); }); +} + +} // Autotest::Internal diff --git a/src/plugins/autotest/testsettingspage.h b/src/plugins/autotest/testsettingspage.h index 064a9504c97..46338e7f890 100644 --- a/src/plugins/autotest/testsettingspage.h +++ b/src/plugins/autotest/testsettingspage.h @@ -5,28 +5,14 @@ #include -#include - -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { struct TestSettings; -class TestSettingsWidget; class TestSettingsPage : public Core::IOptionsPage { - Q_OBJECT public: explicit TestSettingsPage(TestSettings *settings); - - QWidget *widget() override; - void apply() override; - void finish() override { } - -private: - TestSettings *m_settings; - QPointer m_widget; }; -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal From d8be2491a5f5cfdc512f63c766a550dd43694063 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 13 Apr 2023 12:52:39 +0200 Subject: [PATCH 0606/1447] CMakePM: Add new / existing source files to project This will add the new added source files (.cpp, .h, .qrc, .ui) to the corresponding CMake source file as last arguments for known CMake functions like add_executable, add_library as well for the Qt counterprarts qt_add_executable or qt_add_library. For custom functions the code will insert a target_sources() call. Subsequent calls will add the files to the last target_sources. The previous copy to clipboard mechanism and settings have been removed. Fixes: QTCREATORBUG-26006 Fixes: QTCREATORBUG-27213 Fixes: QTCREATORBUG-28493 Fixes: QTCREATORBUG-29006 Change-Id: Ia6e075e4e5718e4106c1236673d469139611a677 Reviewed-by: hjk --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 180 ++++++++++-------- .../cmakeprojectmanager/cmakebuildsystem.h | 1 + .../cmakespecificsettings.cpp | 14 -- .../cmakespecificsettings.h | 7 - .../fileapidataextractor.cpp | 15 ++ .../fileapidataextractor.h | 2 + .../cmakeprojectmanager/fileapireader.cpp | 7 + .../cmakeprojectmanager/fileapireader.h | 1 + .../hello-widgets/CMakeLists.txt | 32 ++++ .../hello-widgets/README.md | 4 + .../hello-widgets/main.cpp | 15 ++ .../hello-widgets/mainwindow.cpp | 20 ++ .../hello-widgets/mainwindow.h | 28 +++ .../hello-widgets/mainwindow.ui | 22 +++ .../hello-widgets/my_add_executable.cmake | 5 + .../hello-widgets/myclass.cpp | 10 + .../hello-widgets/myclass.h | 16 ++ 17 files changed, 283 insertions(+), 96 deletions(-) create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/README.md create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/main.cpp create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.cpp create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.h create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.ui create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/my_add_executable.cmake create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/myclass.cpp create mode 100644 tests/manual/cmakeprojectmanager/hello-widgets/myclass.h diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 68b3cb20a6c..ce56c305af5 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -30,6 +32,9 @@ #include #include +#include +#include + #include #include #include @@ -51,74 +56,11 @@ #include using namespace ProjectExplorer; +using namespace TextEditor; using namespace Utils; namespace CMakeProjectManager::Internal { -static void copySourcePathsToClipboard(const FilePaths &srcPaths, const ProjectNode *node) -{ - QClipboard *clip = QGuiApplication::clipboard(); - - QString data = Utils::transform(srcPaths, [projDir = node->filePath()](const FilePath &path) { - return path.relativePathFrom(projDir).cleanPath().toString(); - }).join(" "); - clip->setText(data); -} - -static void noAutoAdditionNotify(const FilePaths &filePaths, const ProjectNode *node) -{ - const FilePaths srcPaths = Utils::filtered(filePaths, [](const FilePath &file) { - const auto mimeType = Utils::mimeTypeForFile(file).name(); - return mimeType == CppEditor::Constants::C_SOURCE_MIMETYPE || - mimeType == CppEditor::Constants::C_HEADER_MIMETYPE || - mimeType == CppEditor::Constants::CPP_SOURCE_MIMETYPE || - mimeType == CppEditor::Constants::CPP_HEADER_MIMETYPE || - mimeType == ProjectExplorer::Constants::FORM_MIMETYPE || - mimeType == ProjectExplorer::Constants::RESOURCE_MIMETYPE || - mimeType == ProjectExplorer::Constants::SCXML_MIMETYPE; - }); - - if (!srcPaths.empty()) { - auto settings = CMakeSpecificSettings::instance(); - switch (settings->afterAddFileSetting.value()) { - case AskUser: { - bool checkValue{false}; - QDialogButtonBox::StandardButton reply = CheckableMessageBox::question( - Core::ICore::dialogParent(), - Tr::tr("Copy to Clipboard?"), - Tr::tr("Files are not automatically added to the " - "CMakeLists.txt file of the CMake project." - "\nCopy the path to the source files to the clipboard?"), - "Remember My Choice", - &checkValue, - QDialogButtonBox::Yes | QDialogButtonBox::No, - QDialogButtonBox::Yes); - if (checkValue) { - if (QDialogButtonBox::Yes == reply) - settings->afterAddFileSetting.setValue(CopyFilePath); - else if (QDialogButtonBox::No == reply) - settings->afterAddFileSetting.setValue(NeverCopyFilePath); - - settings->writeSettings(Core::ICore::settings()); - } - - if (QDialogButtonBox::Yes == reply) - copySourcePathsToClipboard(srcPaths, node); - - break; - } - - case CopyFilePath: { - copySourcePathsToClipboard(srcPaths, node); - break; - } - - case NeverCopyFilePath: - break; - } - } -} - static Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg); // -------------------------------------------------------------------- @@ -258,24 +200,110 @@ void CMakeBuildSystem::triggerParsing() bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const { if (dynamic_cast(context)) - return action == ProjectAction::AddNewFile; - - if (dynamic_cast(context)) - return action == ProjectAction::AddNewFile; + return action == ProjectAction::AddNewFile || action == ProjectAction::AddExistingFile; return BuildSystem::supportsAction(context, action, node); } bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *notAdded) { - if (auto n = dynamic_cast(context)) { - noAutoAdditionNotify(filePaths, n); - return true; // Return always true as autoadd is not supported! - } - if (auto n = dynamic_cast(context)) { - noAutoAdditionNotify(filePaths, n); - return true; // Return always true as autoadd is not supported! + const QString targetName = n->buildKey(); + auto target = Utils::findOrDefault(buildTargets(), + [targetName](const CMakeBuildTarget &target) { + return target.title == targetName; + }); + + if (target.backtrace.isEmpty()) { + *notAdded = filePaths; + return false; + } + const FilePath targetCMakeFile = target.backtrace.last().path; + const int targetDefinitionLine = target.backtrace.last().line; + + auto cmakeListFile + = Utils::findOrDefault(m_cmakeFiles, [targetCMakeFile](const CMakeFileInfo &info) { + return info.path == targetCMakeFile; + }).cmakeListFile; + + auto function = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [targetDefinitionLine](const auto &func) { + return func.Line() == targetDefinitionLine; + }); + + if (function == cmakeListFile.Functions.end()) { + *notAdded = filePaths; + return false; + } + + const QString newSourceFiles = Utils::transform(filePaths, + [projDir = n->filePath().canonicalPath()]( + const FilePath &path) { + return path.canonicalPath() + .relativePathFrom(projDir) + .cleanPath() + .toString(); + }) + .join(" "); + + static QSet knownFunctions{"add_executable", + "add_library", + "qt_add_executable", + "qt_add_library", + "qt6_add_executable", + "qt6_add_library"}; + + int line = 0; + int column = 0; + QString snippet; + + auto afterFunctionLastArgument = [&line, &column, &snippet, newSourceFiles](const auto &f) { + auto lastArgument = f->Arguments().back(); + + line = lastArgument.Line; + column = lastArgument.Column + static_cast(lastArgument.Value.size()) - 1; + snippet = QString("\n%1").arg(newSourceFiles); + }; + + if (knownFunctions.contains(function->LowerCaseName())) { + afterFunctionLastArgument(function); + } else { + const std::string target_name = targetName.toStdString(); + auto targetSourcesFunc = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [target_name](const auto &func) { + return func.LowerCaseName() + == "target_sources" + && func.Arguments().front().Value + == target_name; + }); + + if (targetSourcesFunc == cmakeListFile.Functions.end()) { + line = function->LineEnd() + 1; + column = 0; + snippet = QString("\ntarget_sources(%1\n PRIVATE\n %2\n)\n") + .arg(targetName) + .arg(newSourceFiles); + } else { + afterFunctionLastArgument(targetSourcesFunc); + } + } + + BaseTextEditor *editor = qobject_cast( + Core::EditorManager::openEditorAt({targetCMakeFile, line, column}, + Constants::CMAKE_EDITOR_ID, + Core::EditorManager::DoNotMakeVisible)); + if (!editor) { + *notAdded = filePaths; + return false; + } + + editor->insert(snippet); + editor->editorWidget()->autoIndent(); + Core::DocumentManager::saveDocument(editor->document()); + + return true; } return BuildSystem::addFiles(context, filePaths, notAdded); @@ -735,6 +763,8 @@ void CMakeBuildSystem::handleParsingSucceeded(bool restoredFromBackup) return result; }); m_buildTargets += m_reader.takeBuildTargets(errorMessage); + m_cmakeFiles = m_reader.takeCMakeFileInfos(errorMessage); + checkAndReportError(errorMessage); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index f3b26b8b4f6..eea894f5e92 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -199,6 +199,7 @@ private: CppEditor::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; QList m_extraCompilers; QList m_buildTargets; + QSet m_cmakeFiles; // Parsing state: BuildDirParameters m_parameters; diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index b29351d1752..d7c8775bd18 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -30,16 +30,6 @@ CMakeSpecificSettings::CMakeSpecificSettings() autorunCMake.setToolTip(::CMakeProjectManager::Tr::tr( "Automatically run CMake after changes to CMake project files.")); - registerAspect(&afterAddFileSetting); - afterAddFileSetting.setSettingsKey("ProjectPopupSetting"); - afterAddFileSetting.setDefaultValue(AfterAddFileAction::AskUser); - afterAddFileSetting.addOption(::CMakeProjectManager::Tr::tr("Ask about copying file paths")); - afterAddFileSetting.addOption(::CMakeProjectManager::Tr::tr("Do not copy file paths")); - afterAddFileSetting.addOption(::CMakeProjectManager::Tr::tr("Copy file paths")); - afterAddFileSetting.setToolTip(::CMakeProjectManager::Tr::tr("Determines whether file paths are copied " - "to the clipboard for pasting to the CMakeLists.txt file when you " - "add new files to CMake projects.")); - registerAspect(&ninjaPath); ninjaPath.setSettingsKey("NinjaPath"); // never save this to the settings: @@ -95,10 +85,6 @@ CMakeSpecificSettingsPage::CMakeSpecificSettingsPage() CMakeSpecificSettings &s = *settings; using namespace Layouting; Column { - Group { - title(::CMakeProjectManager::Tr::tr("Adding Files")), - Column { s.afterAddFileSetting } - }, s.autorunCMake, s.packageManagerAutoSetup, s.askBeforeReConfigureInitialParams, diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h index d0b19bee426..830f1050c24 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h @@ -9,12 +9,6 @@ namespace CMakeProjectManager::Internal { -enum AfterAddFileAction : int { - AskUser, - CopyFilePath, - NeverCopyFilePath -}; - class CMakeSpecificSettings final : public Utils::AspectContainer { public: @@ -23,7 +17,6 @@ public: static CMakeSpecificSettings *instance(); Utils::BoolAspect autorunCMake; - Utils::SelectionAspect afterAddFileSetting; Utils::StringAspect ninjaPath; Utils::BoolAspect packageManagerAutoSetup; Utils::BoolAspect askBeforeReConfigureInitialParams; diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 399ed7385c7..074ee26a671 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -27,6 +27,8 @@ using namespace CMakeProjectManager::Internal::FileApiDetails; namespace CMakeProjectManager::Internal { +static Q_LOGGING_CATEGORY(cmakeLogger, "qtc.cmake.fileApiExtractor", QtWarningMsg); + // -------------------------------------------------------------------- // Helpers: // -------------------------------------------------------------------- @@ -53,7 +55,20 @@ CMakeFileResult extractCMakeFilesData(const std::vector &cmakefil const int oldCount = result.cmakeFiles.count(); CMakeFileInfo absolute(info); absolute.path = sfn; + + expected_str fileContent = sfn.fileContents(); + std::string errorString; + if (fileContent) { + fileContent = fileContent->replace("\r\n", "\n"); + if (!absolute.cmakeListFile.ParseString(fileContent->toStdString(), + sfn.fileName().toStdString(), + errorString)) + qCWarning(cmakeLogger) + << "Failed to parse:" << sfn.path() << QString::fromLatin1(errorString); + } + result.cmakeFiles.insert(absolute); + if (oldCount < result.cmakeFiles.count()) { if (info.isCMake && !info.isCMakeListsDotTxt) { // Skip files that cmake considers to be part of the installation -- but include diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.h b/src/plugins/cmakeprojectmanager/fileapidataextractor.h index 04f4ecea43f..e4ed3aa778c 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.h +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.h @@ -5,6 +5,7 @@ #include "cmakebuildtarget.h" #include "cmakeprojectnodes.h" +#include "3rdparty/cmake/cmListFileCache.h" #include @@ -32,6 +33,7 @@ public: bool isCMakeListsDotTxt = false; bool isExternal = false; bool isGenerated = false; + cmListFile cmakeListFile; }; class FileApiQtcData diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 2d8d4c5345c..42fca8b06ac 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -179,6 +179,13 @@ QList FileApiReader::takeBuildTargets(QString &errorMessage){ return std::exchange(m_buildTargets, {}); } +QSet FileApiReader::takeCMakeFileInfos(QString &errorMessage) +{ + Q_UNUSED(errorMessage) + + return std::exchange(m_cmakeFiles, {}); +} + CMakeConfig FileApiReader::takeParsedConfiguration(QString &errorMessage) { if (m_lastCMakeExitCode != 0) diff --git a/src/plugins/cmakeprojectmanager/fileapireader.h b/src/plugins/cmakeprojectmanager/fileapireader.h index c854ce20400..cb90af8477d 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.h +++ b/src/plugins/cmakeprojectmanager/fileapireader.h @@ -46,6 +46,7 @@ public: QSet projectFilesToWatch() const; QList takeBuildTargets(QString &errorMessage); + QSet takeCMakeFileInfos(QString &errorMessage); CMakeConfig takeParsedConfiguration(QString &errorMessage); QString ctestPath() const; ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage); diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt b/tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt new file mode 100644 index 00000000000..4400c291ef0 --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.18) + +project(hello-widgets) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Widgets) + +qt_add_executable(hello-widgets + main.cpp + mainwindow.cpp + mainwindow.h + mainwindow.ui +) + +target_link_libraries(hello-widgets PRIVATE Qt6::Widgets) + +include(my_add_executable.cmake) + +my_add_executable(hello-my-widgets + main.cpp + mainwindow.cpp + mainwindow.h + mainwindow.ui +) + +target_link_libraries(hello-my-widgets PRIVATE Qt6::Widgets) diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/README.md b/tests/manual/cmakeprojectmanager/hello-widgets/README.md new file mode 100644 index 00000000000..52da33ef8ac --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/README.md @@ -0,0 +1,4 @@ +Qt6 Widgets project to test adding new or existing files to a CMake project. + +The project uses both custom CMake API and normal Qt6 qt_add_executable API +function call. diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/main.cpp b/tests/manual/cmakeprojectmanager/hello-widgets/main.cpp new file mode 100644 index 00000000000..a0ccba3ce92 --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/main.cpp @@ -0,0 +1,15 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "mainwindow.h" + +#include + + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.cpp b/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.cpp new file mode 100644 index 00000000000..c36872995c3 --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.cpp @@ -0,0 +1,20 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "mainwindow.h" +#include "./ui_mainwindow.h" + + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + + diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.h b/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.h new file mode 100644 index 00000000000..35d90b0cfd3 --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.h @@ -0,0 +1,28 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + + + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow + +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.ui b/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.ui new file mode 100644 index 00000000000..b232854ba81 --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/mainwindow.ui @@ -0,0 +1,22 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + + diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/my_add_executable.cmake b/tests/manual/cmakeprojectmanager/hello-widgets/my_add_executable.cmake new file mode 100644 index 00000000000..dca664be47b --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/my_add_executable.cmake @@ -0,0 +1,5 @@ +function(my_add_executable targetName) + add_executable(${targetName} + ${ARGN} + ) +endfunction() diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/myclass.cpp b/tests/manual/cmakeprojectmanager/hello-widgets/myclass.cpp new file mode 100644 index 00000000000..ce14aae2ce5 --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/myclass.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "myclass.h" + +myclass::myclass() +{ + +} + diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/myclass.h b/tests/manual/cmakeprojectmanager/hello-widgets/myclass.h new file mode 100644 index 00000000000..98e0e47cb1c --- /dev/null +++ b/tests/manual/cmakeprojectmanager/hello-widgets/myclass.h @@ -0,0 +1,16 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef MYCLASS_H +#define MYCLASS_H + + + + +class myclass +{ +public: + myclass(); +}; + +#endif // MYCLASS_H From 28d1d3ffe1615d5f699050a05525ded7a1c2531f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 14 Apr 2023 09:36:26 +0200 Subject: [PATCH 0607/1447] Debugger: support piping the python dumper to cdb Fixes: QTCREATORBUG-29000 Change-Id: I7454ded07829d06a33dc1b2ec95a838ca977ca95 Reviewed-by: Reviewed-by: hjk --- share/qtcreator/debugger/loadorder.txt | 2 +- src/plugins/debugger/cdb/cdbengine.cpp | 71 ++++++++++++++++++++++---- src/plugins/debugger/cdb/cdbengine.h | 6 +-- src/plugins/debugger/gdb/gdbengine.cpp | 6 ++- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/share/qtcreator/debugger/loadorder.txt b/share/qtcreator/debugger/loadorder.txt index e348970ced0..23d4dbf3a4a 100644 --- a/share/qtcreator/debugger/loadorder.txt +++ b/share/qtcreator/debugger/loadorder.txt @@ -1,7 +1,7 @@ utils gdbtracepoint dumper -gdbbridge +***bridge*** boosttypes creatortypes libcpp_stdtypes diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index a45dfdeb200..0bda7399ec3 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -954,9 +954,11 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd) return; } - if (dbgCmd.flags == ScriptCommand) { + if (dbgCmd.flags & ScriptCommand) { // repack script command into an extension command DebuggerCommand newCmd("script", ExtensionCommand, dbgCmd.callback); + if (dbgCmd.flags & DebuggerCommand::Silent) + newCmd.flags |= DebuggerCommand::Silent; if (!dbgCmd.args.isNull()) newCmd.args = QString{dbgCmd.function + '(' + dbgCmd.argsToPython() + ')'}; else @@ -975,7 +977,7 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd) } else { const int token = ++m_nextCommandToken; StringInputStream str(fullCmd); - if (dbgCmd.flags == BuiltinCommand) { + if (dbgCmd.flags & BuiltinCommand) { // Post a built-in-command producing free-format output with a callback. // In order to catch the output, it is enclosed in 'echo' commands // printing a specially formatted token to be identifiable in the output. @@ -986,7 +988,7 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd) showMessage("Command is longer than 4096 characters execution will likely fail.", LogWarning); } - } else if (dbgCmd.flags == ExtensionCommand) { + } else if (dbgCmd.flags & ExtensionCommand) { // Post an extension command producing one-line output with a callback, // pass along token for identification in hash. @@ -1020,7 +1022,8 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd) if (debug) { qDebug("CdbEngine::postCommand: resulting command '%s'\n", qPrintable(fullCmd)); } - showMessage(cmd, LogInput); + if (!(dbgCmd.flags & DebuggerCommand::Silent)) + showMessage(cmd, LogInput); m_process.write(fullCmd); } @@ -2766,12 +2769,60 @@ void CdbEngine::setupScripting(const DebuggerResponse &response) return; } - QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput(); - dumperPath.replace('\\', "\\\\"); - runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand}); - runCommand({"from cdbbridge import Dumper", ScriptCommand}); - runCommand({"print(dir())", ScriptCommand}); - runCommand({"theDumper = Dumper()", ScriptCommand}); + + if (runParameters().startMode == AttachToRemoteServer) { + FilePath dumperPath = Core::ICore::resourcePath("debugger"); + const FilePath loadOrderFile = dumperPath / "loadorder.txt"; + const expected_str toLoad = loadOrderFile.fileContents(); + if (!toLoad) { + Core::AsynchronousMessageBox::critical( + Tr::tr("Cannot Find Debugger Initialization Script"), + Tr::tr("Cannot read %1: %2").arg(loadOrderFile.toUserOutput(), toLoad.error())); + notifyEngineSetupFailed(); + return; + } + + runCommand({"import sys, types", ScriptCommand}); + QStringList moduleList; + for (const QByteArray &rawModuleName : toLoad->split('\n')) { + QString module = QString::fromUtf8(rawModuleName).trimmed(); + if (module.startsWith('#') || module.isEmpty()) + continue; + if (module == "***bridge***") + module = "cdbbridge"; + + const FilePath codeFile = dumperPath / (module + ".py"); + const expected_str code = codeFile.fileContents(); + if (!code) { + qDebug() << Tr::tr("Cannot read %1: %2").arg(codeFile.toUserOutput(), code.error()); + continue; + } + + showMessage("Reading " + codeFile.toUserOutput(), LogInput); + runCommand({QString("module = types.ModuleType('%1')").arg(module), ScriptCommand}); + runCommand({QString("code = bytes.fromhex('%1').decode('utf-8')") + .arg(QString::fromUtf8(code->toHex())), ScriptCommand | DebuggerCommand::Silent}); + runCommand({QString("exec(code, module.__dict__)"), ScriptCommand}); + runCommand({QString("sys.modules['%1'] = module").arg(module), ScriptCommand}); + runCommand({QString("import %1").arg(module), ScriptCommand}); + + if (module.endsWith("types")) + moduleList.append('"' + module + '"'); + } + + runCommand({"from cdbbridge import Dumper", ScriptCommand}); + runCommand({"print(dir())", ScriptCommand}); + runCommand({"theDumper = Dumper()", ScriptCommand}); + runCommand({QString("theDumper.dumpermodules = [%1]").arg(moduleList.join(',')), ScriptCommand}); + + } else { + QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput(); + dumperPath.replace('\\', "\\\\"); + runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand}); + runCommand({"from cdbbridge import Dumper", ScriptCommand}); + runCommand({"print(dir())", ScriptCommand}); + runCommand({"theDumper = Dumper()", ScriptCommand}); + } const QString path = debuggerSettings()->extraDumperFile.value(); if (!path.isEmpty() && QFileInfo(path).isReadable()) { diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index a231ce39c23..f0c098e415a 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -110,9 +110,9 @@ private: }; enum CommandFlags { NoFlags = 0, - BuiltinCommand, - ExtensionCommand, - ScriptCommand + BuiltinCommand = DebuggerCommand::Silent << 1, + ExtensionCommand = DebuggerCommand::Silent << 2, + ScriptCommand = DebuggerCommand::Silent << 3 }; void init(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 532c9ef0695..d02b356a95b 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3986,9 +3986,11 @@ void GdbEngine::handleGdbStarted() runCommand({"python import sys, types"}); QStringList moduleList; for (const QByteArray &rawModuleName : toLoad->split('\n')) { - const QString module = QString::fromUtf8(rawModuleName).trimmed(); - if (module.startsWith('#')) + QString module = QString::fromUtf8(rawModuleName).trimmed(); + if (module.startsWith('#') || module.isEmpty()) continue; + if (module == "***bridge***") + module = "gdbbridge"; const FilePath codeFile = dumperPath / (module + ".py"); const expected_str code = codeFile.fileContents(); From c0bbd299338fbed332a2b8cde730bd4670d36fa0 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:01:18 +0200 Subject: [PATCH 0608/1447] Git: Use IOptionPage::setWidgetCreator() for gerrit settings Change-Id: I7402f3342bb11726ec7383c807fa98052cb38bd8 Reviewed-by: Orgad Shaneh --- src/plugins/git/gerrit/gerritoptionspage.cpp | 181 +++++++++---------- src/plugins/git/gerrit/gerritoptionspage.h | 41 +---- 2 files changed, 86 insertions(+), 136 deletions(-) diff --git a/src/plugins/git/gerrit/gerritoptionspage.cpp b/src/plugins/git/gerrit/gerritoptionspage.cpp index 61aa7047b7a..3b96d160bd0 100644 --- a/src/plugins/git/gerrit/gerritoptionspage.cpp +++ b/src/plugins/git/gerrit/gerritoptionspage.cpp @@ -16,108 +16,95 @@ #include #include -namespace Gerrit { -namespace Internal { +namespace Gerrit::Internal { -GerritOptionsPage::GerritOptionsPage(const QSharedPointer &p, - QObject *parent) +class GerritOptionsWidget : public Core::IOptionsPageWidget +{ +public: + GerritOptionsWidget(GerritOptionsPage *page, const QSharedPointer &p) + : m_page(page) + , m_hostLineEdit(new QLineEdit(this)) + , m_userLineEdit(new QLineEdit(this)) + , m_sshChooser(new Utils::PathChooser) + , m_curlChooser(new Utils::PathChooser) + , m_portSpinBox(new QSpinBox(this)) + , m_httpsCheckBox(new QCheckBox(Git::Tr::tr("HTTPS"))) + , m_parameters(p) + { + m_hostLineEdit->setText(p->server.host); + m_userLineEdit->setText(p->server.user.userName); + m_sshChooser->setFilePath(p->ssh); + m_curlChooser->setFilePath(p->curl); + m_portSpinBox->setValue(p->server.port); + m_httpsCheckBox->setChecked(p->https); + + auto formLayout = new QFormLayout(this); + formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + formLayout->addRow(Git::Tr::tr("&Host:"), m_hostLineEdit); + formLayout->addRow(Git::Tr::tr("&User:"), m_userLineEdit); + m_sshChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); + m_sshChooser->setCommandVersionArguments({"-V"}); + m_sshChooser->setHistoryCompleter("Git.SshCommand.History"); + formLayout->addRow(Git::Tr::tr("&ssh:"), m_sshChooser); + m_curlChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); + m_curlChooser->setCommandVersionArguments({"-V"}); + formLayout->addRow(Git::Tr::tr("cur&l:"), m_curlChooser); + m_portSpinBox->setMinimum(1); + m_portSpinBox->setMaximum(65535); + formLayout->addRow(Git::Tr::tr("SSH &Port:"), m_portSpinBox); + formLayout->addRow(Git::Tr::tr("P&rotocol:"), m_httpsCheckBox); + m_httpsCheckBox->setToolTip(Git::Tr::tr( + "Determines the protocol used to form a URL in case\n" + "\"canonicalWebUrl\" is not configured in the file\n" + "\"gerrit.config\".")); + setTabOrder(m_sshChooser, m_curlChooser); + setTabOrder(m_curlChooser, m_portSpinBox); + } + +private: + void apply() final; + + GerritOptionsPage *m_page; + QLineEdit *m_hostLineEdit; + QLineEdit *m_userLineEdit; + Utils::PathChooser *m_sshChooser; + Utils::PathChooser *m_curlChooser; + QSpinBox *m_portSpinBox; + QCheckBox *m_httpsCheckBox; + const QSharedPointer &m_parameters; +}; + +void GerritOptionsWidget::apply() +{ + GerritParameters newParameters; + newParameters.server = GerritServer(m_hostLineEdit->text().trimmed(), + static_cast(m_portSpinBox->value()), + m_userLineEdit->text().trimmed(), + GerritServer::Ssh); + newParameters.ssh = m_sshChooser->filePath(); + newParameters.curl = m_curlChooser->filePath(); + newParameters.https = m_httpsCheckBox->isChecked(); + + if (newParameters != *m_parameters) { + if (m_parameters->ssh == newParameters.ssh) + newParameters.portFlag = m_parameters->portFlag; + else + newParameters.setPortFlagBySshType(); + *m_parameters = newParameters; + m_parameters->toSettings(Core::ICore::settings()); + emit m_page->settingsChanged(); + } +} + +// GerritOptionsPage + +GerritOptionsPage::GerritOptionsPage(const QSharedPointer &p, QObject *parent) : Core::IOptionsPage(parent) - , m_parameters(p) { setId("Gerrit"); setDisplayName(Git::Tr::tr("Gerrit")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); + setWidgetCreator([this, p] { return new GerritOptionsWidget(this, p); }); } -GerritOptionsPage::~GerritOptionsPage() -{ - delete m_widget; -} - -QWidget *GerritOptionsPage::widget() -{ - if (!m_widget) { - m_widget = new GerritOptionsWidget; - m_widget->setParameters(*m_parameters); - } - return m_widget; -} - -void GerritOptionsPage::apply() -{ - if (GerritOptionsWidget *w = m_widget.data()) { - GerritParameters newParameters = w->parameters(); - if (newParameters != *m_parameters) { - if (m_parameters->ssh == newParameters.ssh) - newParameters.portFlag = m_parameters->portFlag; - else - newParameters.setPortFlagBySshType(); - *m_parameters = newParameters; - m_parameters->toSettings(Core::ICore::settings()); - emit settingsChanged(); - } - } -} - -void GerritOptionsPage::finish() -{ - delete m_widget; -} - -GerritOptionsWidget::GerritOptionsWidget(QWidget *parent) - : QWidget(parent) - , m_hostLineEdit(new QLineEdit(this)) - , m_userLineEdit(new QLineEdit(this)) - , m_sshChooser(new Utils::PathChooser) - , m_curlChooser(new Utils::PathChooser) - , m_portSpinBox(new QSpinBox(this)) - , m_httpsCheckBox(new QCheckBox(Git::Tr::tr("HTTPS"))) -{ - auto formLayout = new QFormLayout(this); - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - formLayout->addRow(Git::Tr::tr("&Host:"), m_hostLineEdit); - formLayout->addRow(Git::Tr::tr("&User:"), m_userLineEdit); - m_sshChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_sshChooser->setCommandVersionArguments({"-V"}); - m_sshChooser->setHistoryCompleter("Git.SshCommand.History"); - formLayout->addRow(Git::Tr::tr("&ssh:"), m_sshChooser); - m_curlChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_curlChooser->setCommandVersionArguments({"-V"}); - formLayout->addRow(Git::Tr::tr("cur&l:"), m_curlChooser); - m_portSpinBox->setMinimum(1); - m_portSpinBox->setMaximum(65535); - formLayout->addRow(Git::Tr::tr("SSH &Port:"), m_portSpinBox); - formLayout->addRow(Git::Tr::tr("P&rotocol:"), m_httpsCheckBox); - m_httpsCheckBox->setToolTip(Git::Tr::tr( - "Determines the protocol used to form a URL in case\n" - "\"canonicalWebUrl\" is not configured in the file\n" - "\"gerrit.config\".")); - setTabOrder(m_sshChooser, m_curlChooser); - setTabOrder(m_curlChooser, m_portSpinBox); -} - -GerritParameters GerritOptionsWidget::parameters() const -{ - GerritParameters result; - result.server = GerritServer(m_hostLineEdit->text().trimmed(), - static_cast(m_portSpinBox->value()), - m_userLineEdit->text().trimmed(), - GerritServer::Ssh); - result.ssh = m_sshChooser->filePath(); - result.curl = m_curlChooser->filePath(); - result.https = m_httpsCheckBox->isChecked(); - return result; -} - -void GerritOptionsWidget::setParameters(const GerritParameters &p) -{ - m_hostLineEdit->setText(p.server.host); - m_userLineEdit->setText(p.server.user.userName); - m_sshChooser->setFilePath(p.ssh); - m_curlChooser->setFilePath(p.curl); - m_portSpinBox->setValue(p.server.port); - m_httpsCheckBox->setChecked(p.https); -} - -} // namespace Internal -} // namespace Gerrit +} // Gerrit::Internal diff --git a/src/plugins/git/gerrit/gerritoptionspage.h b/src/plugins/git/gerrit/gerritoptionspage.h index d5b220eb335..6e6695ae367 100644 --- a/src/plugins/git/gerrit/gerritoptionspage.h +++ b/src/plugins/git/gerrit/gerritoptionspage.h @@ -6,57 +6,20 @@ #include #include -#include -QT_BEGIN_NAMESPACE -class QLineEdit; -class QSpinBox; -class QCheckBox; -QT_END_NAMESPACE - -namespace Utils { class PathChooser; } -namespace Gerrit { -namespace Internal { +namespace Gerrit::Internal { class GerritParameters; -class GerritOptionsWidget : public QWidget -{ - Q_OBJECT -public: - explicit GerritOptionsWidget(QWidget *parent = nullptr); - - GerritParameters parameters() const; - void setParameters(const GerritParameters &); - -private: - QLineEdit *m_hostLineEdit; - QLineEdit *m_userLineEdit; - Utils::PathChooser *m_sshChooser; - Utils::PathChooser *m_curlChooser; - QSpinBox *m_portSpinBox; - QCheckBox *m_httpsCheckBox; -}; - class GerritOptionsPage : public Core::IOptionsPage { Q_OBJECT public: GerritOptionsPage(const QSharedPointer &p, QObject *parent = nullptr); - ~GerritOptionsPage() override; - - QWidget *widget() override; - void apply() override; - void finish() override; signals: void settingsChanged(); - -private: - const QSharedPointer &m_parameters; - QPointer m_widget; }; -} // namespace Internal -} // namespace Gerrit +} // Gerrit::Internal From 21ca06fc7cbb2be37c3c8face1d43cf2cbda3b4f Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Thu, 20 Apr 2023 11:04:06 +0200 Subject: [PATCH 0609/1447] Codeformatter: Support indenting of type annotated function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QTCREATORBUG-29046 Change-Id: Ie4a4d85b7aa00ddf4dd3ea4bade6ffa57af7b4e0 Reviewed-by: Mikołaj Boc Reviewed-by: Ulf Hermann Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: Fabian Kosmale --- src/libs/qmljs/qmljscodeformatter.cpp | 7 +++++++ src/libs/qmljs/qmljscodeformatter.h | 1 + .../qmlcodeformatter/tst_qmlcodeformatter.cpp | 13 +++++++++++++ 3 files changed, 21 insertions(+) diff --git a/src/libs/qmljs/qmljscodeformatter.cpp b/src/libs/qmljs/qmljscodeformatter.cpp index 55ed2e6190c..a2f944700f9 100644 --- a/src/libs/qmljs/qmljscodeformatter.cpp +++ b/src/libs/qmljs/qmljscodeformatter.cpp @@ -253,9 +253,16 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) case function_arglist_closed: switch (kind) { case LeftBrace: turnInto(jsblock_open); break; + case Colon: turnInto(function_type_annotated_return); break; default: leave(true); continue; // error recovery } break; + case function_type_annotated_return: + switch (kind) { + case LeftBrace: turnInto(jsblock_open); break; + default: break; + } break; + case expression_or_objectdefinition: switch (kind) { case Dot: diff --git a/src/libs/qmljs/qmljscodeformatter.h b/src/libs/qmljs/qmljscodeformatter.h index 4800fccfdf0..abef85a782d 100644 --- a/src/libs/qmljs/qmljscodeformatter.h +++ b/src/libs/qmljs/qmljscodeformatter.h @@ -99,6 +99,7 @@ public: // must be public to make Q_GADGET introspection work function_start, // after 'function' function_arglist_open, // after '(' starting function argument list function_arglist_closed, // after ')' in argument list, expecting '{' + function_type_annotated_return, // after ':' expecting a type binding_or_objectdefinition, // after an identifier diff --git a/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp b/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp index 8d2194086b2..934bf5d317d 100644 --- a/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp +++ b/tests/auto/qml/qmleditor/qmlcodeformatter/tst_qmlcodeformatter.cpp @@ -83,6 +83,7 @@ private Q_SLOTS: void bug1(); void bug2(); void bug3(); + void indentFunctionWithReturnTypeAnnotation(); }; enum { DontCheck = -2, DontIndent = -1 }; @@ -1564,6 +1565,18 @@ void tst_QMLCodeFormatter::bug3() checkIndent(data); } + +void tst_QMLCodeFormatter::indentFunctionWithReturnTypeAnnotation() +{ + QList data; + data << Line("function test() : void {", 0) + << Line("", 4) + << Line(" }", 0) + ; + checkIndent(data); +} + + QTEST_GUILESS_MAIN(tst_QMLCodeFormatter) #include "tst_qmlcodeformatter.moc" From 900dc154be0709240a78636b47573029ff048c04 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 09:46:03 +0200 Subject: [PATCH 0610/1447] RunConfigurationLocatorFilter: Use Acceptor for LocatorFilterEntry Change-Id: Ia48aa149ee2c4cd3653ba7a4313f1578034ad9d8 Reviewed-by: Eike Ziller --- .../projectexplorer/projectexplorer.cpp | 100 +++++++----------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 57fe61080e1..998b3d606e4 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -41,6 +41,7 @@ #include "devicesupport/sshsettings.h" #include "devicesupport/sshsettingspage.h" #include "editorsettingspropertiespage.h" +#include "environmentaspect.h" #include "filesinallprojectsfind.h" #include "jsonwizard/jsonwizardfactory.h" #include "jsonwizard/jsonwizardgeneratorfactory.h" @@ -65,7 +66,6 @@ #include "projecttreewidget.h" #include "projectwindow.h" #include "removetaskhandler.h" -#include "runconfigurationaspects.h" #include "sanitizerparser.h" #include "selectablefilesmodel.h" #include "session.h" @@ -416,32 +416,26 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; +protected: + using RunAcceptor = std::function; + void setRunAcceptor(const RunAcceptor &acceptor) { m_acceptor = acceptor; } private: void targetListUpdated(); QList m_result; + RunAcceptor m_acceptor; }; class RunRunConfigurationLocatorFilter final : public RunConfigurationLocatorFilter { public: RunRunConfigurationLocatorFilter(); - - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const final; }; class SwitchToRunConfigurationLocatorFilter final : public RunConfigurationLocatorFilter { public: SwitchToRunConfigurationLocatorFilter(); - - void accept(const Core::LocatorFilterEntry &selection, - QString *newText, - int *selectionStart, - int *selectionLength) const final; }; class ProjectExplorerPluginPrivate : public QObject @@ -4400,6 +4394,17 @@ RunConfigurationLocatorFilter::RunConfigurationLocatorFilter() targetListUpdated(); } +static RunConfiguration *runConfigurationForDisplayName(const QString &displayName) +{ + const Target *target = ProjectManager::startupTarget(); + if (!target) + return nullptr; + const QList runconfigs = target->runConfigurations(); + return Utils::findOrDefault(runconfigs, [displayName](RunConfiguration *rc) { + return rc->displayName() == displayName; + }); +} + void RunConfigurationLocatorFilter::prepareSearch(const QString &entry) { m_result.clear(); @@ -4407,8 +4412,18 @@ void RunConfigurationLocatorFilter::prepareSearch(const QString &entry) if (!target) return; for (auto rc : target->runConfigurations()) { - if (rc->displayName().contains(entry, Qt::CaseInsensitive)) - m_result.append(LocatorFilterEntry(this, rc->displayName())); + if (rc->displayName().contains(entry, Qt::CaseInsensitive)) { + LocatorFilterEntry entry; + entry.displayName = rc->displayName(); + entry.acceptor = [name = entry.displayName, acceptor = m_acceptor] { + RunConfiguration *config = runConfigurationForDisplayName(name); + if (!config) + return AcceptResult(); + acceptor(config); + return AcceptResult(); + }; + m_result.append(entry); + } } } @@ -4425,17 +4440,6 @@ void RunConfigurationLocatorFilter::targetListUpdated() setEnabled(ProjectManager::startupProject()); // at least one project opened } -static RunConfiguration *runConfigurationForDisplayName(const QString &displayName) -{ - const Project *project = ProjectManager::instance()->startupProject(); - if (!project) - return nullptr; - const QList runconfigs = project->activeTarget()->runConfigurations(); - return Utils::findOrDefault(runconfigs, [displayName](RunConfiguration *rc) { - return rc->displayName() == displayName; - }); -} - RunRunConfigurationLocatorFilter::RunRunConfigurationLocatorFilter() { setId("Run run configuration"); @@ -4443,20 +4447,10 @@ RunRunConfigurationLocatorFilter::RunRunConfigurationLocatorFilter() setDescription(Tr::tr("Runs a run configuration of the active project.")); setDefaultShortcutString("rr"); setPriority(Medium); -} - -void RunRunConfigurationLocatorFilter::accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - - RunConfiguration *toStart = runConfigurationForDisplayName(selection.displayName); - if (!toStart) - return; - if (!BuildManager::isBuilding(toStart->project())) - ProjectExplorerPlugin::runRunConfiguration(toStart, Constants::NORMAL_RUN_MODE, true); + setRunAcceptor([](RunConfiguration *config) { + if (!BuildManager::isBuilding(config->project())) + ProjectExplorerPlugin::runRunConfiguration(config, Constants::NORMAL_RUN_MODE, true); + }); } SwitchToRunConfigurationLocatorFilter::SwitchToRunConfigurationLocatorFilter() @@ -4466,27 +4460,15 @@ SwitchToRunConfigurationLocatorFilter::SwitchToRunConfigurationLocatorFilter() setDescription(Tr::tr("Switches the active run configuration of the active project.")); setDefaultShortcutString("sr"); setPriority(Medium); -} - -void SwitchToRunConfigurationLocatorFilter::accept(const LocatorFilterEntry &selection, - QString *newText, int *selectionStart, - int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - - RunConfiguration *toSwitchTo = runConfigurationForDisplayName(selection.displayName); - if (!toSwitchTo) - return; - - ProjectManager::startupTarget()->setActiveRunConfiguration(toSwitchTo); - QTimer::singleShot(200, this, [displayName = selection.displayName] { - if (auto ks = ICore::mainWindow()->findChild("KitSelector.Button")) { - Utils::ToolTip::show(ks->mapToGlobal(QPoint{25, 25}), - Tr::tr("Switched run configuration to\n%1").arg(displayName), - ICore::dialogParent()); - } + setRunAcceptor([](RunConfiguration *config) { + ProjectManager::startupTarget()->setActiveRunConfiguration(config); + QTimer::singleShot(200, ICore::mainWindow(), [displayName = config->displayName()] { + if (auto ks = ICore::mainWindow()->findChild("KitSelector.Button")) { + Utils::ToolTip::show(ks->mapToGlobal(QPoint{25, 25}), + Tr::tr("Switched run configuration to\n%1").arg(displayName), + ICore::dialogParent()); + } + }); }); } From 7e919a07b6a74914d0851076afcb70c05f3746cc Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 13:35:03 +0200 Subject: [PATCH 0611/1447] CMake: Remove odd but unused assignment Change-Id: I052baddc82b7bef24e656c35be1a4edd97a85007 Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx index 86175b69e16..e3ffd23cc4c 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx @@ -23,7 +23,6 @@ struct cmListFileParser bool AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim); cmListFile* ListFile; - const char* FileName = nullptr; cmListFileLexer* Lexer; std::string FunctionName; long FunctionLine; @@ -57,10 +56,8 @@ void cmListFileParser::IssueError(const std::string& text) const } bool cmListFileParser::ParseString(const std::string &str, - const std::string &virtual_filename) + const std::string &/*virtual_filename*/) { - this->FileName = virtual_filename.c_str(); - if (!cmListFileLexer_SetString(this->Lexer, str.c_str(), (int)str.size())) { this->IssueError("cmListFileCache: cannot allocate buffer."); return false; From fc8181672c5f54eb8b60d2d30605a2fce4dfa8ec Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:52:47 +0200 Subject: [PATCH 0612/1447] Gitlab: Use IOptionPage::setWidgetCreator() for settings Change-Id: If5e0cead9092836f23bc8551bb0f1495fe41a400 Reviewed-by: Christian Stenger --- src/plugins/gitlab/gitlaboptionspage.cpp | 123 ++++++++++++++--------- src/plugins/gitlab/gitlaboptionspage.h | 72 +------------ 2 files changed, 79 insertions(+), 116 deletions(-) diff --git a/src/plugins/gitlab/gitlaboptionspage.cpp b/src/plugins/gitlab/gitlaboptionspage.cpp index 4f519e77886..6fb05063118 100644 --- a/src/plugins/gitlab/gitlaboptionspage.cpp +++ b/src/plugins/gitlab/gitlaboptionspage.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -44,6 +45,25 @@ static bool hostValid(const QString &host) return (host == "localhost") || dn.match(host).hasMatch(); } +class GitLabServerWidget : public QWidget +{ +public: + enum Mode { Display, Edit }; + explicit GitLabServerWidget(Mode m, QWidget *parent = nullptr); + + GitLabServer gitLabServer() const; + void setGitLabServer(const GitLabServer &server); + +private: + Mode m_mode = Display; + Id m_id; + StringAspect m_host; + StringAspect m_description; + StringAspect m_token; + IntegerAspect m_port; + BoolAspect m_secure; +}; + GitLabServerWidget::GitLabServerWidget(Mode m, QWidget *parent) : QWidget(parent) , m_mode(m) @@ -108,8 +128,43 @@ void GitLabServerWidget::setGitLabServer(const GitLabServer &server) m_secure.setValue(server.secure); } -GitLabOptionsWidget::GitLabOptionsWidget(QWidget *parent) - : QWidget(parent) +class GitLabOptionsWidget : public Core::IOptionsPageWidget +{ +public: + explicit GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParameters *parameters); + + GitLabParameters parameters() const; + + void apply() final + { + GitLabParameters newParameters = parameters(); + if (newParameters != *m_parameters) { + *m_parameters = newParameters; + m_parameters->toSettings(Core::ICore::settings()); + emit m_page->settingsChanged(); + } + } + +private: + void showEditServerDialog(); + void showAddServerDialog(); + void removeCurrentTriggered(); + void addServer(const GitLabServer &newServer); + void modifyCurrentServer(const GitLabServer &newServer); + void updateButtonsState(); + + GitLabOptionsPage *m_page = nullptr; + GitLabParameters *m_parameters = nullptr; + GitLabServerWidget *m_gitLabServerWidget = nullptr; + QPushButton *m_edit = nullptr; + QPushButton *m_remove = nullptr; + QPushButton *m_add = nullptr; + QComboBox *m_defaultGitLabServer = nullptr; + Utils::StringAspect m_curl; +}; + +GitLabOptionsWidget::GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParameters *params) + : m_page(page), m_parameters(params) { auto defaultLabel = new QLabel(Tr::tr("Default:"), this); m_defaultGitLabServer = new QComboBox(this); @@ -136,6 +191,20 @@ GitLabOptionsWidget::GitLabOptionsWidget(QWidget *parent) }, Column { m_add, m_edit, m_remove, st }, }.attachTo(this); + m_curl.setFilePath(params->curl); + + for (const auto &gitLabServer : params->gitLabServers) { + m_defaultGitLabServer->addItem(gitLabServer.displayString(), + QVariant::fromValue(gitLabServer)); + } + + const GitLabServer found = params->currentDefaultServer(); + if (found.id.isValid()) { + m_defaultGitLabServer->setCurrentIndex(m_defaultGitLabServer->findData( + QVariant::fromValue(found))); + } + updateButtonsState(); + connect(m_edit, &QPushButton::clicked, this, &GitLabOptionsWidget::showEditServerDialog); connect(m_remove, &QPushButton::clicked, this, &GitLabOptionsWidget::removeCurrentTriggered); connect(m_add, &QPushButton::clicked, this, &GitLabOptionsWidget::showAddServerDialog); @@ -157,23 +226,6 @@ GitLabParameters GitLabOptionsWidget::parameters() const return result; } -void GitLabOptionsWidget::setParameters(const GitLabParameters ¶ms) -{ - m_curl.setFilePath(params.curl); - - for (const auto &gitLabServer : params.gitLabServers) { - m_defaultGitLabServer->addItem(gitLabServer.displayString(), - QVariant::fromValue(gitLabServer)); - } - - const GitLabServer found = params.currentDefaultServer(); - if (found.id.isValid()) { - m_defaultGitLabServer->setCurrentIndex(m_defaultGitLabServer->findData( - QVariant::fromValue(found))); - } - updateButtonsState(); -} - void GitLabOptionsWidget::showEditServerDialog() { const GitLabServer old = m_defaultGitLabServer->currentData().value(); @@ -253,39 +305,14 @@ void GitLabOptionsWidget::updateButtonsState() m_remove->setEnabled(hasItems); } -GitLabOptionsPage::GitLabOptionsPage(GitLabParameters *p, QObject *parent) - : Core::IOptionsPage{parent} - , m_parameters(p) +// GitLabOptionsPage + +GitLabOptionsPage::GitLabOptionsPage(GitLabParameters *p) { setId(Constants::GITLAB_SETTINGS); setDisplayName(Tr::tr("GitLab")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); -} - -QWidget *GitLabOptionsPage::widget() -{ - if (!m_widget) { - m_widget = new GitLabOptionsWidget; - m_widget->setParameters(*m_parameters); - } - return m_widget; -} - -void GitLabOptionsPage::apply() -{ - if (GitLabOptionsWidget *w = m_widget.data()) { - GitLabParameters newParameters = w->parameters(); - if (newParameters != *m_parameters) { - *m_parameters = newParameters; - m_parameters->toSettings(Core::ICore::settings()); - emit settingsChanged(); - } - } -} - -void GitLabOptionsPage::finish() -{ - delete m_widget; + setWidgetCreator([this, p] { return new GitLabOptionsWidget(this, p); }); } } // namespace GitLab diff --git a/src/plugins/gitlab/gitlaboptionspage.h b/src/plugins/gitlab/gitlaboptionspage.h index 327cc1128a7..04aecf21998 100644 --- a/src/plugins/gitlab/gitlaboptionspage.h +++ b/src/plugins/gitlab/gitlaboptionspage.h @@ -6,84 +6,20 @@ #include "gitlabparameters.h" #include -#include - -#include - -QT_BEGIN_NAMESPACE -class QComboBox; -class QPushButton; -QT_END_NAMESPACE namespace GitLab { -namespace Constants { -const char GITLAB_SETTINGS[] = "GitLab"; -} // namespace Constants - -class GitLabServerWidget : public QWidget -{ -public: - enum Mode { Display, Edit }; - explicit GitLabServerWidget(Mode m, QWidget *parent = nullptr); - - GitLabServer gitLabServer() const; - void setGitLabServer(const GitLabServer &server); - - bool isValid() const; -private: - Mode m_mode = Display; - Utils::Id m_id; - Utils::StringAspect m_host; - Utils::StringAspect m_description; - Utils::StringAspect m_token; - Utils::IntegerAspect m_port; - Utils::BoolAspect m_secure; -}; - -class GitLabOptionsWidget : public QWidget -{ - Q_OBJECT -public: - explicit GitLabOptionsWidget(QWidget *parent = nullptr); - - GitLabParameters parameters() const; - void setParameters(const GitLabParameters ¶ms); - -private: - void showEditServerDialog(); - void showAddServerDialog(); - void removeCurrentTriggered(); - void addServer(const GitLabServer &newServer); - void modifyCurrentServer(const GitLabServer &newServer); - void updateButtonsState(); - - GitLabServerWidget *m_gitLabServerWidget = nullptr; - QPushButton *m_edit = nullptr; - QPushButton *m_remove = nullptr; - QPushButton *m_add = nullptr; - QComboBox *m_defaultGitLabServer = nullptr; - Utils::StringAspect m_curl; -}; +namespace Constants { const char GITLAB_SETTINGS[] = "GitLab"; } class GitLabOptionsPage : public Core::IOptionsPage { Q_OBJECT -public: - explicit GitLabOptionsPage(GitLabParameters *p, QObject *parent = nullptr); - QWidget *widget() final; - void apply() final; - void finish() final; +public: + explicit GitLabOptionsPage(GitLabParameters *p); signals: void settingsChanged(); - -private: - void addServer(); - - GitLabParameters *m_parameters; - QPointer m_widget; }; -} // namespace GitLab +} // GitLab From f13c39c91214d331ceddd832acdf81d9f8dec903 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 16:25:58 +0200 Subject: [PATCH 0613/1447] ILocatorFilter: Get rid of accept() method Change-Id: I3ad3c2cd5cb7a08b7539918b7713bfcd27fde297 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- .../coreplugin/locator/ilocatorfilter.cpp | 18 ------------------ .../coreplugin/locator/ilocatorfilter.h | 3 --- .../coreplugin/locator/locatorwidget.cpp | 10 ++-------- 3 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 8b7c924a2ff..a2d8d847f52 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -516,24 +516,6 @@ std::optional ILocatorFilter::refreshRecipe() const return m_refreshRecipe; } -/*! - Called with the entry specified by \a selection when the user activates it - in the result list. - Implementations can return a new search term \a newText, which has \a selectionLength characters - starting from \a selectionStart preselected, and the cursor set to the end of the selection. - - The default implementation tries to open an editor for \a selections's linkForEditor, - if it exists. -*/ -void ILocatorFilter::accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const -{ - Q_UNUSED(newText) - Q_UNUSED(selectionStart) - Q_UNUSED(selectionLength) - EditorManager::openEditor(selection); -} - /*! Sets the default \a shortcut string that can be used to explicitly choose this filter in the locator input field. Call for example from the diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index c116209be7e..b1a20dd67f8 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -225,9 +225,6 @@ public: virtual QList matchesFor(QFutureInterface &future, const QString &entry) = 0; - virtual void accept(const LocatorFilterEntry &selection, QString *newText, - int *selectionStart, int *selectionLength) const; - virtual QByteArray saveState() const; virtual void restoreState(const QByteArray &state); diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 889223e440a..cd98f8e5dd1 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -1018,15 +1018,9 @@ void LocatorWidget::acceptEntry(int row) return; const LocatorFilterEntry entry = m_locatorModel->data(index, LocatorEntryRole).value(); QWidget *focusBeforeAccept = QApplication::focusWidget(); - AcceptResult result; - if (entry.acceptor) { - result = entry.acceptor(); - } else if (entry.filter) { - entry.filter->accept(entry, &result.newText, &result.selectionStart, - &result.selectionLength); - } else { + if (!entry.acceptor) EditorManager::openEditor(entry); - } + const AcceptResult result = entry.acceptor ? entry.acceptor() : AcceptResult(); if (result.newText.isEmpty()) { emit hidePopup(); if (QApplication::focusWidget() == focusBeforeAccept) From c09951d1b7144d63d1fc830cfd0487f4b945a4c0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 16:39:21 +0200 Subject: [PATCH 0614/1447] LocatorFilterEntry: Get rid of filter field Remove also c'tor taking a pointer to filter. Change-Id: Ic0fe62daeb6e79a729bee24d07d7eb77559e19c4 Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- .../clangcodemodel/clangdlocatorfilters.cpp | 1 - .../coreplugin/locator/basefilefilter.cpp | 3 ++- .../locator/externaltoolsfilter.cpp | 3 ++- .../coreplugin/locator/ilocatorfilter.h | 7 ------ .../coreplugin/locator/javascriptfilter.cpp | 7 +++++- .../locator/opendocumentsfilter.cpp | 3 ++- .../cppeditor/cppcurrentdocumentfilter.cpp | 3 ++- src/plugins/cppeditor/cpplocatorfilter.cpp | 25 +++++++++++-------- src/plugins/languageclient/locatorfilter.cpp | 11 +++----- .../qmljstools/qmljsfunctionfilter.cpp | 3 ++- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 3e24d4c57c2..19fab25d0c7 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -221,7 +221,6 @@ private: const auto docSymbolGenerator = [&](const DocumentSymbol &info, const LocatorFilterEntry &parent) { LocatorFilterEntry entry; - entry.filter = this; entry.displayName = ClangdClient::displayNameFromDocumentSymbol( static_cast(info.kind()), info.name(), info.detail().value_or(QString())); diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 3f8e87af20f..d7f96b8ec16 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -153,7 +153,8 @@ QList BaseFileFilter::matchesFor(QFutureInterface; - /* backpointer to creating filter */ - ILocatorFilter *filter = nullptr; /* displayed string */ QString displayName; /* extra information displayed in parentheses and light-gray next to display name (optional)*/ diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index a0fb181b56d..5104ee81394 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -75,7 +75,12 @@ QList JavaScriptFilter::matchesFor( }; }; const QString expression = entry + " = " + result; - entries.append({this, expression}); + + LocatorFilterEntry entry; + entry.displayName = expression; + entry.acceptor = [] { return AcceptResult(); }; + entries.append(entry); + LocatorFilterEntry resultEntry; resultEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(result); resultEntry.acceptor = acceptor(result); diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index b68142bbb3f..aa94c5f5f58 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -96,7 +96,8 @@ QList OpenDocumentsFilter::matchesFor(QFutureInterface CppCurrentDocumentFilter::matchesFor( } } - LocatorFilterEntry filterEntry(this, name); + LocatorFilterEntry filterEntry; + filterEntry.displayName = name; filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index d23d81e2d51..7eaee38b84f 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -119,8 +119,8 @@ LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex LocatorMatcherTask cppAllSymbolsMatcher() { const auto converter = [](const IndexItem::Ptr &info) { - // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. - LocatorFilterEntry filterEntry(nullptr, info->scopedSymbolName()); + LocatorFilterEntry filterEntry; + filterEntry.displayName = info->scopedSymbolName(); filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) @@ -135,8 +135,8 @@ LocatorMatcherTask cppAllSymbolsMatcher() LocatorMatcherTask cppClassMatcher() { const auto converter = [](const IndexItem::Ptr &info) { - // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. - LocatorFilterEntry filterEntry(nullptr, info->symbolName()); + LocatorFilterEntry filterEntry; + filterEntry.displayName = info->symbolName(); filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = info->symbolScope().isEmpty() @@ -158,8 +158,8 @@ LocatorMatcherTask cppFunctionMatcher() extraInfo = info->shortNativeFilePath(); else extraInfo.append(" (" + info->filePath().fileName() + ')'); - // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. - LocatorFilterEntry filterEntry(nullptr, name + info->symbolType()); + LocatorFilterEntry filterEntry; + filterEntry.displayName = name + info->symbolType(); filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; @@ -237,8 +237,8 @@ void matchesForCurrentDocument(QPromise &promise } } - // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. - LocatorFilterEntry filterEntry(nullptr, name); + LocatorFilterEntry filterEntry; + filterEntry.displayName = name; filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; @@ -326,7 +326,8 @@ CppLocatorFilter::CppLocatorFilter() LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { - LocatorFilterEntry filterEntry(this, info->scopedSymbolName()); + LocatorFilterEntry filterEntry; + filterEntry.displayName = info->scopedSymbolName(); filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) @@ -423,7 +424,8 @@ CppClassesFilter::CppClassesFilter() LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { - LocatorFilterEntry filterEntry(this, info->symbolName()); + LocatorFilterEntry filterEntry; + filterEntry.displayName = info->symbolName(); filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = info->symbolScope().isEmpty() @@ -453,7 +455,8 @@ LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr i extraInfo.append(" (" + info->filePath().fileName() + ')'); } - LocatorFilterEntry filterEntry(this, name + info->symbolType()); + LocatorFilterEntry filterEntry; + filterEntry.displayName = name + info->symbolType(); filterEntry.displayIcon = info->icon(); filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; filterEntry.extraInfo = extraInfo; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 8acc21feeb1..83c13002d21 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -38,8 +38,6 @@ void filterResults(QPromise &promise, Client *cl : Utils::filtered(results, doFilter); const auto generateEntry = [client](const SymbolInformation &info) { LocatorFilterEntry entry; - // TODO: Passing nullptr for filter -> accept won't work now. Replace with accept function. - entry.filter = nullptr; entry.displayName = info.name(); if (std::optional container = info.containerName()) entry.extraInfo = container.value_or(QString()); @@ -170,11 +168,9 @@ void DocumentLocatorFilter::resetSymbols() } static LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, - ILocatorFilter *filter, DocumentUri::PathMapper pathMapper) { LocatorFilterEntry entry; - entry.filter = filter; entry.displayName = info.name(); if (std::optional container = info.containerName()) entry.extraInfo = container.value_or(QString()); @@ -190,7 +186,7 @@ QList DocumentLocatorFilter::entriesForSymbolsInfo( QList entries; for (const SymbolInformation &info : infoList) { if (regexp.match(info.name()).hasMatch()) - entries << LanguageClient::generateLocatorEntry(info, this, m_pathMapper); + entries << LanguageClient::generateLocatorEntry(info, m_pathMapper); } return entries; } @@ -228,7 +224,6 @@ QList DocumentLocatorFilter::matchesFor( const LocatorFilterEntry &parent) { Q_UNUSED(parent) LocatorFilterEntry entry; - entry.filter = this; entry.displayName = info.name(); if (std::optional detail = info.detail()) entry.extraInfo = detail.value_or(QString()); @@ -362,8 +357,8 @@ QList WorkspaceLocatorFilter::matchesFor( return m_filterKinds.contains(SymbolKind(info.symbol.kind())); }); } - auto generateEntry = [this](const SymbolInfoWithPathMapper &info) { - return generateLocatorEntry(info.symbol, this, info.mapper); + auto generateEntry = [](const SymbolInfoWithPathMapper &info) { + return generateLocatorEntry(info.symbol, info.mapper); }; return Utils::transform(m_results, generateEntry).toList(); } diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 22050f7a9c7..e39ba3de132 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -48,7 +48,8 @@ QList FunctionFilter::matchesFor(QFutureInterface Date: Thu, 20 Apr 2023 15:55:35 +0200 Subject: [PATCH 0615/1447] CMakePM: Only parse CMake files with the CMake parser Change-Id: Ifc962a54ec9bf6ba0db4ec7813cb81d7c81a7d2c Reviewed-by: Jarek Kobus --- .../fileapidataextractor.cpp | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 074ee26a671..0fc4de0b9cc 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -3,6 +3,7 @@ #include "fileapidataextractor.h" +#include "cmakeprojectconstants.h" #include "cmakeprojectmanagertr.h" #include "cmakeprojectplugin.h" #include "cmakespecificsettings.h" @@ -56,15 +57,19 @@ CMakeFileResult extractCMakeFilesData(const std::vector &cmakefil CMakeFileInfo absolute(info); absolute.path = sfn; - expected_str fileContent = sfn.fileContents(); - std::string errorString; - if (fileContent) { - fileContent = fileContent->replace("\r\n", "\n"); - if (!absolute.cmakeListFile.ParseString(fileContent->toStdString(), - sfn.fileName().toStdString(), - errorString)) - qCWarning(cmakeLogger) - << "Failed to parse:" << sfn.path() << QString::fromLatin1(errorString); + const auto mimeType = Utils::mimeTypeForFile(info.path); + if (mimeType.matchesName(Constants::CMAKE_MIMETYPE) + || mimeType.matchesName(Constants::CMAKE_PROJECT_MIMETYPE)) { + expected_str fileContent = sfn.fileContents(); + std::string errorString; + if (fileContent) { + fileContent = fileContent->replace("\r\n", "\n"); + if (!absolute.cmakeListFile.ParseString(fileContent->toStdString(), + sfn.fileName().toStdString(), + errorString)) + qCWarning(cmakeLogger) + << "Failed to parse:" << sfn.path() << QString::fromLatin1(errorString); + } } result.cmakeFiles.insert(absolute); From 4e847cfb498d27a07e4542ef629eef7277a0c9c5 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 16:05:06 +0200 Subject: [PATCH 0616/1447] QbsProjectManager: Fix warning "this statement may fall through [-Wimplicit-fallthrough=]" Change-Id: I3497a25834b77a2266e9b46d1f7365b5fdf72239 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index 46433eca5a4..d64ecc47e7e 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -156,7 +156,7 @@ static QString architecture(const ProjectExplorer::Abi &targetAbi) switch (targetAbi.architecture()) { case ProjectExplorer::Abi::X86Architecture: architecture.append(QLatin1Char('_')); - // fall through + [[fallthrough]]; case ProjectExplorer::Abi::ArmArchitecture: // ARM sub-architectures are currently not handled, which is kind of problematic case ProjectExplorer::Abi::MipsArchitecture: From 97ee619876840ace749aa2c976418f118614ae39 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 22:03:06 +0200 Subject: [PATCH 0617/1447] ProjectExplorer: Drop known namespaces Change-Id: I969a7f6c8e54c89b047611890a7ba80f4829d73b Reviewed-by: Christian Kandeler Reviewed-by: Reviewed-by: Qt CI Bot --- .../projectexplorer/projectexplorer.cpp | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 998b3d606e4..33b0b4130d4 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -306,12 +306,12 @@ static const RunConfiguration *runConfigForNode(const Target *target, const Proj static bool hideBuildMenu() { - return Core::ICore::settings()->value(Constants::SETTINGS_MENU_HIDE_BUILD, false).toBool(); + return ICore::settings()->value(Constants::SETTINGS_MENU_HIDE_BUILD, false).toBool(); } static bool hideDebugMenu() { - return Core::ICore::settings()->value(Constants::SETTINGS_MENU_HIDE_DEBUG, false).toBool(); + return ICore::settings()->value(Constants::SETTINGS_MENU_HIDE_DEBUG, false).toBool(); } static bool canOpenTerminalWithRunEnv(const Project *project, const ProjectNode *node) @@ -408,13 +408,13 @@ protected: void restoreState(const QJsonObject &object) override; }; -class RunConfigurationLocatorFilter : public Core::ILocatorFilter +class RunConfigurationLocatorFilter : public ILocatorFilter { public: RunConfigurationLocatorFilter(); void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, + QList matchesFor(QFutureInterface &future, const QString &entry) override; protected: using RunAcceptor = std::function; @@ -422,7 +422,7 @@ protected: private: void targetListUpdated(); - QList m_result; + QList m_result; RunAcceptor m_acceptor; }; @@ -489,7 +489,7 @@ public: void deleteFile(); void handleRenameFile(); void handleSetStartupProject(); - void setStartupProject(ProjectExplorer::Project *project); + void setStartupProject(Project *project); bool closeAllFilesInProject(const Project *project); void updateRecentProjectMenu(); @@ -501,11 +501,11 @@ public: void openTerminalHere(const EnvironmentGetter &env); void openTerminalHereWithRunEnv(); - void invalidateProject(ProjectExplorer::Project *project); + void invalidateProject(Project *project); - void projectAdded(ProjectExplorer::Project *pro); - void projectRemoved(ProjectExplorer::Project *pro); - void projectDisplayNameChanged(ProjectExplorer::Project *pro); + void projectAdded(Project *pro); + void projectRemoved(Project *pro); + void projectDisplayNameChanged(Project *pro); void doUpdateRunActions(); @@ -744,7 +744,7 @@ static void openProjectsInDirectory(const FilePath &filePath) { const FilePaths projectFiles = projectsInDirectory(filePath); if (!projectFiles.isEmpty()) - Core::ICore::openFiles(projectFiles); + ICore::openFiles(projectFiles); } static QStringList projectNames(const QVector &folders) @@ -767,7 +767,7 @@ static QVector renamableFolderNodes(const FilePath &before, const return folderNodes; } -static QVector removableFolderNodes(const Utils::FilePath &filePath) +static QVector removableFolderNodes(const FilePath &filePath) { QVector folderNodes; ProjectTree::forEachNode([&](Node *node) { @@ -1611,7 +1611,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er Command * const expandCmd = ActionManager::registerAction( dd->m_projectTreeExpandAllAction, Constants::PROJECTTREE_EXPAND_ALL, projectTreeContext); - for (Core::ActionContainer * const ac : {mfileContextMenu, msubProjectContextMenu, + for (ActionContainer * const ac : {mfileContextMenu, msubProjectContextMenu, mfolderContextMenu, mprojectContextMenu, msessionContextMenu}) { ac->addSeparator(treeGroup); ac->addAction(expandNodeCmd, treeGroup); @@ -1714,7 +1714,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er if (tmp < 0 || tmp > int(StopBeforeBuild::SameApp)) tmp = int(defaultSettings.stopBeforeBuild); dd->m_projectExplorerSettings.stopBeforeBuild = StopBeforeBuild(tmp); - dd->m_projectExplorerSettings.terminalMode = static_cast( + dd->m_projectExplorerSettings.terminalMode = static_cast( s->value(Constants::TERMINAL_MODE_SETTINGS_KEY, int(defaultSettings.terminalMode)).toInt()); dd->m_projectExplorerSettings.closeSourceFilesWithProject = s->value(Constants::CLOSE_FILES_WITH_PROJECT_SETTINGS_KEY, @@ -2128,13 +2128,13 @@ void ProjectExplorerPlugin::extensionsInitialized() Tr::tr("Sanitizer", "Category for sanitizer issues listed under 'Issues'")); TaskHub::addCategory(Constants::TASK_CATEGORY_TASKLIST_ID, Tr::tr("My Tasks")); - SshSettings::loadSettings(Core::ICore::settings()); + SshSettings::loadSettings(ICore::settings()); const auto searchPathRetriever = [] { - FilePaths searchPaths = {Core::ICore::libexecPath()}; + FilePaths searchPaths = {ICore::libexecPath()}; if (HostOsInfo::isWindowsHost()) { - const QString gitBinary = Core::ICore::settings()->value("Git/BinaryPath", "git") + const QString gitBinary = ICore::settings()->value("Git/BinaryPath", "git") .toString(); - const QStringList rawGitSearchPaths = Core::ICore::settings()->value("Git/Path") + const QStringList rawGitSearchPaths = ICore::settings()->value("Git/Path") .toString().split(':', Qt::SkipEmptyParts); const FilePaths gitSearchPaths = Utils::transform(rawGitSearchPaths, [](const QString &rawPath) { return FilePath::fromString(rawPath); }); @@ -2914,10 +2914,9 @@ void ProjectExplorerPluginPrivate::extendFolderNavigationWidgetFactory() "The file \"%1\" was renamed to \"%2\", " "but the following projects could not be automatically changed: %3") .arg(before.toUserOutput(), after.toUserOutput(), projects); - QTimer::singleShot(0, Core::ICore::instance(), [errorMessage] { - QMessageBox::warning(Core::ICore::dialogParent(), - Tr::tr("Project Editing Failed"), - errorMessage); + QTimer::singleShot(0, ICore::instance(), [errorMessage] { + QMessageBox::warning(ICore::dialogParent(), + Tr::tr("Project Editing Failed"), errorMessage); }); } }); @@ -2935,8 +2934,8 @@ void ProjectExplorerPluginPrivate::extendFolderNavigationWidgetFactory() const QString errorMessage = Tr::tr("The following projects failed to automatically remove the file: %1") .arg(projects); - QTimer::singleShot(0, Core::ICore::instance(), [errorMessage] { - QMessageBox::warning(Core::ICore::dialogParent(), + QTimer::singleShot(0, ICore::instance(), [errorMessage] { + QMessageBox::warning(ICore::dialogParent(), Tr::tr("Project Editing Failed"), errorMessage); }); @@ -3583,9 +3582,7 @@ void ProjectExplorerPluginPrivate::updateLocationSubMenus() : Tr::tr("%1 in %2").arg(li.displayName).arg(li.path.toUserOutput()); auto *action = new QAction(displayName, nullptr); connect(action, &QAction::triggered, this, [line, path] { - Core::EditorManager::openEditorAt(Link(path, line), - {}, - Core::EditorManager::AllowExternalEditor); + EditorManager::openEditorAt(Link(path, line), {}, EditorManager::AllowExternalEditor); }); projectMenu->addAction(action); @@ -3884,7 +3881,7 @@ void ProjectExplorerPluginPrivate::removeFile() if (!siblings.isEmpty()) { const QMessageBox::StandardButton reply = QMessageBox::question( - Core::ICore::dialogParent(), Tr::tr("Remove More Files?"), + ICore::dialogParent(), Tr::tr("Remove More Files?"), Tr::tr("Remove these files as well?\n %1") .arg(Utils::transform(siblings, [](const NodeAndPath &np) { return np.second.fileName(); @@ -4245,7 +4242,7 @@ void ProjectExplorerPlugin::updateActions() void ProjectExplorerPlugin::activateProjectPanel(Id panelId) { - Core::ModeManager::activateMode(Constants::MODE_SESSION); + ModeManager::activateMode(Constants::MODE_SESSION); dd->m_proWindow->activateProjectPanel(panelId); } @@ -4274,9 +4271,8 @@ RecentProjectsEntries ProjectExplorerPlugin::recentProjects() return dd->recentProjects(); } -void ProjectExplorerPlugin::renameFilesForSymbol( - const QString &oldSymbolName, const QString &newSymbolName, const Utils::FilePaths &files, - bool preferLowerCaseFileNames) +void ProjectExplorerPlugin::renameFilesForSymbol(const QString &oldSymbolName, + const QString &newSymbolName, const FilePaths &files, bool preferLowerCaseFileNames) { static const auto isAllLowerCase = [](const QString &text) { return text.toLower() == text; }; @@ -4427,8 +4423,8 @@ void RunConfigurationLocatorFilter::prepareSearch(const QString &entry) } } -QList RunConfigurationLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) +QList RunConfigurationLocatorFilter::matchesFor( + QFutureInterface &future, const QString &entry) { Q_UNUSED(future) Q_UNUSED(entry) @@ -4464,9 +4460,9 @@ SwitchToRunConfigurationLocatorFilter::SwitchToRunConfigurationLocatorFilter() ProjectManager::startupTarget()->setActiveRunConfiguration(config); QTimer::singleShot(200, ICore::mainWindow(), [displayName = config->displayName()] { if (auto ks = ICore::mainWindow()->findChild("KitSelector.Button")) { - Utils::ToolTip::show(ks->mapToGlobal(QPoint{25, 25}), - Tr::tr("Switched run configuration to\n%1").arg(displayName), - ICore::dialogParent()); + ToolTip::show(ks->mapToGlobal(QPoint{25, 25}), + Tr::tr("Switched run configuration to\n%1").arg(displayName), + ICore::dialogParent()); } }); }); From 039baab6e70160bc8130ef95e499141f7c875225 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 20 Apr 2023 18:55:16 +0200 Subject: [PATCH 0618/1447] CMakePM: Add new / existing files for QtQuick projects Fixes: QTCREATORBUG-28904 Fixes: QTCREATORBUG-28985 Change-Id: Id05f13cc69b8afffafba1b956ee1c90dc88c6d57 Reviewed-by: Alessandro Portale --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 79 ++++++++++++++++--- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index ce56c305af5..9cb3692d765 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -205,6 +206,53 @@ bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const return BuildSystem::supportsAction(context, action, node); } +static QString newFilesForFunction(const std::string &cmakeFunction, + const FilePaths &filePaths, + const FilePath &projDir) +{ + auto relativeFilePaths = [projDir](const FilePaths &filePaths) { + return Utils::transform(filePaths, [projDir](const FilePath &path) { + return path.canonicalPath().relativePathFrom(projDir).cleanPath().toString(); + }); + }; + + if (cmakeFunction == "qt_add_qml_module" || cmakeFunction == "qt6_add_qml_module") { + FilePaths sourceFiles; + FilePaths resourceFiles; + FilePaths qmlFiles; + + for (const auto &file : filePaths) { + const auto mimeType = Utils::mimeTypeForFile(file); + if (mimeType.matchesName(CppEditor::Constants::CPP_SOURCE_MIMETYPE) + || mimeType.matchesName(CppEditor::Constants::CPP_HEADER_MIMETYPE) + || mimeType.matchesName(CppEditor::Constants::OBJECTIVE_C_SOURCE_MIMETYPE) + || mimeType.matchesName(CppEditor::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)) { + sourceFiles << file; + } else if (mimeType.matchesName(QmlJSTools::Constants::QML_MIMETYPE) + || mimeType.matchesName(QmlJSTools::Constants::QMLUI_MIMETYPE) + || mimeType.matchesName(QmlJSTools::Constants::QMLPROJECT_MIMETYPE) + || mimeType.matchesName(QmlJSTools::Constants::JS_MIMETYPE) + || mimeType.matchesName(QmlJSTools::Constants::JSON_MIMETYPE)) { + qmlFiles << file; + } else { + resourceFiles << file; + } + } + + QStringList result; + if (!sourceFiles.isEmpty()) + result << QString("SOURCES %1").arg(relativeFilePaths(sourceFiles).join(" ")); + if (!resourceFiles.isEmpty()) + result << QString("RESOURCES %1").arg(relativeFilePaths(resourceFiles).join(" ")); + if (!qmlFiles.isEmpty()) + result << QString("QML_FILES %1").arg(relativeFilePaths(qmlFiles).join(" ")); + + return result.join("\n"); + } + + return relativeFilePaths(filePaths).join(" "); +} + bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *notAdded) { if (auto n = dynamic_cast(context)) { @@ -237,22 +285,32 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP return false; } - const QString newSourceFiles = Utils::transform(filePaths, - [projDir = n->filePath().canonicalPath()]( - const FilePath &path) { - return path.canonicalPath() - .relativePathFrom(projDir) - .cleanPath() - .toString(); - }) - .join(" "); + // Special case: when qt_add_executable and qt_add_qml_module use the same target name + // then qt_add_qml_module function should be used + const std::string target_name = targetName.toStdString(); + auto add_qml_module_func + = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [target_name](const auto &func) { + return (func.LowerCaseName() == "qt_add_qml_module" + || func.LowerCaseName() == "qt6_add_qml_module") + && func.Arguments().front().Value == target_name; + }); + if (add_qml_module_func != cmakeListFile.Functions.end()) + function = add_qml_module_func; + + const QString newSourceFiles = newFilesForFunction(function->LowerCaseName(), + filePaths, + n->filePath().canonicalPath()); static QSet knownFunctions{"add_executable", "add_library", "qt_add_executable", "qt_add_library", "qt6_add_executable", - "qt6_add_library"}; + "qt6_add_library", + "qt_add_qml_module", + "qt6_add_qml_module"}; int line = 0; int column = 0; @@ -269,7 +327,6 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP if (knownFunctions.contains(function->LowerCaseName())) { afterFunctionLastArgument(function); } else { - const std::string target_name = targetName.toStdString(); auto targetSourcesFunc = std::find_if(cmakeListFile.Functions.begin(), cmakeListFile.Functions.end(), [target_name](const auto &func) { From 128d40e1794691819267914847b78418ec1f1ae7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 21 Apr 2023 06:58:19 +0200 Subject: [PATCH 0619/1447] CMakePM: Fix qbs build Change-Id: I96ea5f4130c9a5449ad7c0f97f63494ecf5b0e01 Reviewed-by: hjk --- .../cmakeprojectmanager/cmakeprojectmanager.qbs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs index 89e449ae402..f3eca551292 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs @@ -93,4 +93,18 @@ QtcPlugin { "projecttreehelper.cpp", "projecttreehelper.h" ] + + Group { + name: "3rdparty" + cpp.includePaths: base.concat("3rdparty/cmake") + + prefix: "3rdparty/cmake/" + files: [ + "cmListFileCache.cxx", + "cmListFileCache.h", + "cmListFileLexer.c", + "cmListFileLexer.h", + "cmStandardLexer.h", + ] + } } From c6a98002fd19f0f476c39f604a4c7a0538ea7a8c Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 20 Apr 2023 16:58:54 +0200 Subject: [PATCH 0620/1447] Doc: Remove info about manually adding files to CMakeLists.txt It is now done automatically. Task-number: QTCREATORBUG-28996 Change-Id: I25844b087575eba11cdce1c8a2f5040c92dae80e Reviewed-by: Cristian Adam --- .../images/qtcreator-add-resource-wizard4.png | Bin 5671 -> 0 bytes .../src/widgets/qtdesigner-app-tutorial.qdoc | 8 +------- 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 doc/qtcreator/images/qtcreator-add-resource-wizard4.png diff --git a/doc/qtcreator/images/qtcreator-add-resource-wizard4.png b/doc/qtcreator/images/qtcreator-add-resource-wizard4.png deleted file mode 100644 index ea985fc5ea056ac52a1712451f1ae665cff0d016..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5671 zcmeAS@N?(olHy`uVBq!ia0y~yV9a7*U|7Jx#K6F?YTw373=E?0JY5_^DsH`KBj)bU z3zmjEIh-w)Yjwun+{M5sG}K8%hS@U zmd$_nGWP76GWY-Wr3Y7(FIzr;-n;uH-_O|0U9n<^DqG^gCf4oe=ErYIlw&y>$eC3w z?><6 z|Ljf18i#r6{bp@R%q%dG_vY!>p5)CSI+sIuvz^s(cLB3W$B*CHSsZGA-gd`>U(MTX|Nh!M z{oen`|L4n1;$PYR`*yPXeSF^jn)BxO{+xR<|6lcM{e2EsGIm|L{o%5loczqH*VjIr zoH+5~h3EyDpC@igoZ&R(hlK3MNjmAlmws&gAGAd9oNC7+fdxq_9g5aH9}M4TJYD%; z_V)i<+wCj&tol{+y6?*3{XZ^0nfAZxgM0q`s&{iY{+eHw&947)mbHb{#H%~ETIfl; zHt;KUyFE|vDdbE2EO||p!7h!(@yyM{mj2uQy7f=@hX4O~Y4R4|g^zRUUp1dR9#^0A z=5DcjeZ5k`JLlli)_Wyo{XVR+TOZGLY<+I`IxJ!N`T4fC0i%9X~t${ z`5Ke?F`sX-PqvP$`|`y)?Z<=Y)(elzp354QUb$7G)OtL%cVqRG?ml(?&+_8|yS|v+wVqtHnv%Ki z?7tk_=)B)@+moZaKfSE=*xPk5a9R1p-Ywt0T+crLucqneH#;?6qh(f$tLIM>`m!a( zzdN-^y_DT#Z$Co~%Z+!lJAEylt~FM9@yStQPs(z?;Pd}xLSp7vx}_T32XoAVm^IkY@$90WqLenjl4Fyvxt zT2S-h;=Ox)O$`bh&EgzQTpj(d*X`zGWpoU%`*C4UDVL)FON|2u1KQO9lnsryc@Tv}VSJ7Q@Yf7T!Q z^>Pa?dfiMvzxmCMtPdi*(Wlt`rriC$=WySVZ6zAgR@UiHAD8T4bTn~|pYvme*SbX; zG~SzZi^)IxDfs=&-7X%Xm;e)Ae*T*;CoIuf>U8Y*ly5p2t534aU#U&F8My81nKxH| z+ui&=_27D$J74Ec7O5(;GhY7nba<{^=0@d>Z;u|S)sJFX=+eOdV6n!>iEZsyPHwpD zskZmef*mPFoHaAfmtUCSnsz+&`@E*h1PsoZNCZFOya zMcH{p>v>9ZV~=cUNv_H4QvW)8)wzXRALja9N}b48etv?c#s8^E%6FS@-qqS6l;+iW z_i}K_9nmjxYZtXwZ*;LO%<-=8YjlCEy-RD7uZ?Pc*Y8<#J&ZSmiLVb> z^@{16$eIg5UncHLN-q!os`(@+=$+T*kE*$Fda+6Jsw%hH@A4{c zIyO#7JlnS9%zGA~c~kRDZ3puNu2kD6*6;uQ%MF-5@BMsk(Wc!tXDVBz zp3DootUF!!`L<@>5T3Xa_Nv*dP4ZXR-KqI-$Y;qD(~65*JfDh&n5o@Yj(T{q`^M=H z{WVurUs?wlSthhaym)8u<=elIHO=Bu85gRTuKI5MBz=oXxYhEnoU^P{YcA|)Q?ssl zv%p~W@90+_z1IaV*WA742d7fH+qq2UdtYi_vV^&m*PnlDbhNa3&vVgTI}R<``#eJJ zq;G^y40nQLY8_*MGC503I1E?B>8eBWmI=EsR&%_dJ1 z&(>bJ98-1cQL=l|>7So??U$rzF9-_wu*SsX@Dygd7s3|LtEVNDeNmfRdAZhI{msPg z>9QiH*p6#P#;R&)PPakejuKaY!{r0|7o0MhW*|OJ6VX`#Q4|6); z&i8{Of!%h&(&@ggWmE22FHBix zT&c6qGsp{w)YmLo?q@#t!sccs+uV)2uA618;*@t@+^E@o2}D564(qd-=2fB<-KMF2Vhm^Nw}Pb8FW8Gv~DyYCeBH@BZY+>cygo zKQ?f1%d>vtVytmc?c@L5{P&-*R@stjd0qb<&Elrkr+)Xnw7=oMY5m7nHnks|x#k=5 z{eSMF`dIYP?0xq0weG9lc^>3*N@~B5fQXQtmQJ~&ul31fiPL3#&!ei(mHe8G^Cvh5c>LH9t19fcX8nUD z?=wu3#kys8?)EbK`bCh@uIq?4%k1>@{c}DDT5vJjEjaNZ@S)C?3tKM#YjWQ) zd0LEE)&>4J6FI9ha|)+S3gui?;~H#EvZ^R#Z5b6iIL6I>+>G2Vb-#%u@E>Ybknt$|BK>+MMv2~ z_Wan;uGPQ}YeG#g@e*GPjJAwRy_rL;>eT+Pt0y2!#+)5e$cdb0Pz)9y8) z*HgYe(lC0zj?;vt=1C*p%dO`wybf~_z4b@rnWV_^!iieSoT%PI_snU zg~&DKU5}2nUs}la`n=LnotK&>+;6$w?5z0pz&3Bg;;_G(Q)W(F!>xS#pAyHHu0wUH z%m41{(_9f_vrQv@jlRdv7e1fQxfGlWGkM*@9x8M!u=}`ip5XfT;Z1w_o8NzIJ(06C z@mkcm>zCQ<_3m}MUtqc(#FHN@ar2vHHlLnbXuadVd-s3*TG6zWZzOQWHBiHa4%!cgj2N{kF|2_%W|*IsdzuJ>vbD2iw=Ji#+Qd zyZ`gyc2CEdRXK&l5f46{l$4*dS#+7*2A_voom}#+YaZ2oT2!*);IGXS_9jG3Kk|P2 zjTQ5rzAAKndsNxH=EJqtNxAnIOt76;;AO5_|9L`t(W|CY$CJBTejl3B|MEd=@wP+m zzdlRGc#1SnPkLJ?^0!*P$C-DjJ@-j&H`mrj4-=10v8mngeA3ZH9P8OR3?H~-9v0_wG*932G4RDVEq)R`yiCqd@`{co= z!{4f3=-91_YxdfGKy-V-#I&8u=1fa%TCn4rUCnFtAK|Z0CO66pumAJrm+h>Q9XZtn zifZd3n!WD-zOc^bk-c}`X(Pvg8g~76v6lU!R-a<7C@1`t`#Pni;{W*`izUm|Uzx7( zd1kk)iQj;ER%5aJuB%m_A|9wucfR3T+wtjX6GT+%5xnm#G|tCw-bK^7eo z;g5=2*#2kPvSn|2TI2EHmn~bf_-}^7-jeeT9ydi3#CC9P@lNe~xXDLA#JuK6r0bq4 zLl#k9yALO2?(aXK!Ng=2Ah2_?a;qi>#}5Xyt_G;<0q<%wAi5n%TXJq+_C1__dtR;n zu|}SlO+R>zp+11uKZF7keU>)X7qro3wn`BD^SdLBEa z>aaaEE2_7*w>wGKXu=tl4n*zj><-s4T8tCQq+ZQa}Nf1Y9CcShHy z{-xSsN9`Eo53q|c+Eu-ejM{GWt?>+tT?4;HN=?bvyojLdGOiUb3bK;krPd$!`7sK|*kFApF8@nZ+aghj`WANu9?fZ6Ei@mE`Gub!T* z#PyQzMDXlOxA}vwKi>GlPekH`kEmVPx|qu9mRp4irD@;$?xvr6^G+n$DqnxY37^IH z+)H&oFiJj7_Kh#iO%6#sysxvf_H`D!n_5u2oS4#E)!aUtDSe**vrgVsf8&tmr*3EE zn#M7E?(Xv`)4yA8SZwjZ@I4>M0q*Jk@u9xSB@YiCUg=zYN#NzyWI5X@R=>CIJM&Gv z-{+0wg8JZg`Cb!#5s-^!&7Pg#9q_&0y!6>gzN>Dpc7IR*_NwAjkF4a>6Fxq3ofbY$ zt_}5dZfShsaJNf8?f;wNU2>9w7Dk4`)xVU_vdy%-`{P8;vdoFSp2~-pwf|QBz&KUF z&T7~7aJ}pfqm*6JuQ%7PyKg?v>eGTPw{O{|>z;C%!fRCg>tiDG;uRk+)*okjz-)B< z_}!_eUoGZ|KlQ-*kFn{#a~wL>E(CVqtXX0%8r)(x_g^}p5NUYr!O_m`=E_1d zJMXcJ7}?$0ef{pv64xn;z5VrjqdRt1zu#e8@$=sFcYh8|d?W8J*P$bwk{0;jFq?`}Ap7Tm^&XD1p<* za#nfGtquGuo_s94{_5V*tEC(HQ*w15hm(X+kl85kHCJYD@<);T3K0RZ@d B=HmbW diff --git a/doc/qtcreator/src/widgets/qtdesigner-app-tutorial.qdoc b/doc/qtcreator/src/widgets/qtdesigner-app-tutorial.qdoc index fb0dc11b4bd..d211b570d22 100644 --- a/doc/qtcreator/src/widgets/qtdesigner-app-tutorial.qdoc +++ b/doc/qtcreator/src/widgets/qtdesigner-app-tutorial.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -294,12 +294,6 @@ and select \uicontrol{Finish} or \uicontrol Done to open the file in the code editor. - \li In the \uicontrol Copy to Clipboard dialog, select \uicontrol Yes to - copy the path to the resource file to the clipboard for adding it - to the CMakeLists.txt file. - - \image qtcreator-add-resource-wizard4.png "Copy to Clipboard dialog" - \li Select \uicontrol Add > \uicontrol {Add Prefix}. \li In the \uicontrol{Prefix} field, replace the default prefix with a slash From ce7b99bc8887af995e1d34f00ba1831bd08c7d97 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 17:59:26 +0200 Subject: [PATCH 0621/1447] RemoteLinux: Honor working directory setting again Fixes: QTCREATORBUG-28900 Change-Id: I163877a749f378b2aa7579c1985e58f8a9d87e2c Reviewed-by: Jarek Kobus --- .../remotelinux/filesystemaccess_test.cpp | 16 ++++++++++++++++ src/plugins/remotelinux/filesystemaccess_test.h | 1 + src/plugins/remotelinux/linuxdevice.cpp | 14 +++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index 13e46619ff3..edcb8d4d01c 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -181,6 +182,21 @@ void FileSystemAccessTest::testCreateRemoteFile() QVERIFY(!testFilePath.exists()); } +void FileSystemAccessTest::testWorkingDirectory() +{ + const FilePath dir = baseFilePath() / "testdir with space and 'various' \"quotes\" here"; + QVERIFY(dir.ensureWritableDir()); + QtcProcess proc; + proc.setCommand({"pwd", {}}); + proc.setWorkingDirectory(dir); + proc.start(); + QVERIFY(proc.waitForFinished()); + const QString out = proc.readAllStandardOutput().trimmed(); + QCOMPARE(out, dir.path()); + const QString err = proc.readAllStandardOutput(); + QVERIFY(err.isEmpty()); +} + void FileSystemAccessTest::testDirStatus() { FilePath filePath = baseFilePath(); diff --git a/src/plugins/remotelinux/filesystemaccess_test.h b/src/plugins/remotelinux/filesystemaccess_test.h index 84321db6ce8..087eabbcad9 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.h +++ b/src/plugins/remotelinux/filesystemaccess_test.h @@ -24,6 +24,7 @@ private slots: void testCreateRemoteFile_data(); void testCreateRemoteFile(); + void testWorkingDirectory(); void testDirStatus(); void testBytesAvailable(); void testFileActions(); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 97b6412e6c2..583a6bdeaf5 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -612,13 +612,17 @@ void SshProcessInterfacePrivate::start() cmd.addArg("-tt"); const CommandLine full = q->m_setup.m_commandLine; - if (!full.isEmpty()) { + if (!full.isEmpty()) { // Empty is ok in case of opening a terminal. + CommandLine inner; + const QString wd = q->m_setup.m_workingDirectory.path(); + if (!wd.isEmpty()) + inner.addCommandLineWithAnd({"cd", {wd}}); if (!useTerminal) { - // Empty is ok in case of opening a terminal. - cmd.addArgs(QString("echo ") + s_pidMarker + "\\$\\$" + s_pidMarker + " \\&\\& ", - CommandLine::Raw); + const QString pidArg = QString("%1\\$\\$%1").arg(QString::fromLatin1(s_pidMarker)); + inner.addCommandLineWithAnd({"echo", pidArg, CommandLine::Raw}); } - cmd.addCommandLineAsArgs(full, CommandLine::Raw); + inner.addCommandLineWithAnd(full); + cmd.addCommandLineAsSingleArg(inner); } m_process.setProcessImpl(q->m_setup.m_processImpl); From 28c20b24aa633334b67ecb5402fc61e98d7b4c5b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 20 Apr 2023 16:15:37 +0300 Subject: [PATCH 0622/1447] VCS: Fix jumping to last line on some editors I'm still not sure what causes this. Fixes: QTCREATORBUG-29063 Change-Id: I861d91f1aa9a2fb36054d9f0a8e5e8e2f8fae872 Reviewed-by: David Schulz --- src/plugins/vcsbase/vcsbaseclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index a73758b15ea..1bd13f312ab 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -235,6 +235,7 @@ VcsBaseEditorWidget *VcsBaseClientImpl::createVcsEditor(Id kind, QString title, connect(baseEditor, &VcsBaseEditorWidget::annotateRevisionRequested, this, &VcsBaseClientImpl::annotateRevisionRequested); baseEditor->setSource(source); + baseEditor->setDefaultLineNumber(1); if (codec) baseEditor->setCodec(codec); } From 44aaad4c2f31e8bb6cf673f18facb59584d3fa5f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 13 Apr 2023 16:22:10 +0200 Subject: [PATCH 0623/1447] COIN/GitHub: Bump to Qt 6.5.0 Change-Id: I8c2122b7f35d049f0249631fc6e045b79dff9fbc Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz --- .github/workflows/build_cmake.yml | 4 ++-- coin/instructions/build.yaml | 3 +++ coin/instructions/common_environment.yaml | 5 ++++- coin/product_dependencies.yaml | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 8a623779f16..17cb3ea370c 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -7,8 +7,8 @@ on: - 'doc/**' env: - QT_VERSION: 6.4.3 - MACOS_DEPLOYMENT_TARGET: 10.14 + QT_VERSION: 6.5.0 + MACOS_DEPLOYMENT_TARGET: 10.15 CLANG_VERSION: 16.0.0 ELFUTILS_VERSION: 0.175 CMAKE_VERSION: 3.21.1 diff --git a/coin/instructions/build.yaml b/coin/instructions/build.yaml index 23461dbcf4e..75818065a40 100644 --- a/coin/instructions/build.yaml +++ b/coin/instructions/build.yaml @@ -66,6 +66,9 @@ instructions: userMessageOnFailure: "Failed to run build.py, check logs." - type: ChangeDirectory directory: "{{.AgentWorkingDir}}/build/qtsdk/packaging-tools" + - type: EnvironmentVariable + variableName: MACOSX_DEPLOYMENT_TARGET + variableValue: "{{.Env.SDKTOOL_MACOSX_DEPLOYMENT_TARGET}}" - type: ExecuteCommand command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command make" maxTimeInSeconds: 36000 diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index d3c072f0a94..b8be5f5c4a4 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -10,12 +10,15 @@ instructions: variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_16.0.0-based - type: EnvironmentVariable variableName: QTC_QT_BASE_URL - variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.4/6.4.3-released/Qt" + variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-released/Qt" - type: EnvironmentVariable variableName: QTC_QT_MODULES variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations qtwebengine" - type: EnvironmentVariable variableName: MACOSX_DEPLOYMENT_TARGET + variableValue: 10.15 + - type: EnvironmentVariable + variableName: SDKTOOL_MACOSX_DEPLOYMENT_TARGET variableValue: 10.14 - type: EnvironmentVariable variableName: QTC_SDKTOOL_QT_BASE_URL diff --git a/coin/product_dependencies.yaml b/coin/product_dependencies.yaml index cbcc2bbf7e1..4212b9b2e24 100644 --- a/coin/product_dependencies.yaml +++ b/coin/product_dependencies.yaml @@ -1,4 +1,4 @@ dependencies: - ../../qt/tqtc-qt5.git: - ref: "tqtc/lts-6.2" + ../../qt/qt5.git: + ref: "6.5" From 422d422debaa27b52a6108fd7b45a38c4c748bd3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 18:09:04 +0200 Subject: [PATCH 0624/1447] LocatorMatcherTask: Get rid of Input/OutputData typedefs Introduce LocatorFilterEntries instead. Change-Id: I082e0405441aa4b70a5e8fb796aa5c4fa3879265 Reviewed-by: Eike Ziller Reviewed-by: --- .../coreplugin/locator/ilocatorfilter.cpp | 58 +++++++++---------- .../coreplugin/locator/ilocatorfilter.h | 19 +++--- src/plugins/cppeditor/cpplocatorfilter.cpp | 20 +++---- .../cppeditor/cpplocatorfilter_test.cpp | 4 +- src/plugins/languageclient/locatorfilter.cpp | 8 +-- .../jsonwizard/jsonfieldpage.cpp | 2 +- 6 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index a2d8d847f52..fc8b7126788 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -5,7 +5,6 @@ #include "../coreplugin.h" #include "../coreplugintr.h" -#include "../editormanager/editormanager.h" #include #include @@ -22,6 +21,7 @@ #include #include #include +#include #include @@ -61,29 +61,29 @@ class OutputDataProvider struct WorkingData { WorkingData() = default; - WorkingData(const LocatorMatcherTask::OutputData &entries, std::atomic &state) { + WorkingData(const LocatorFilterEntries &entries, std::atomic &state) { mergeWith(entries, state); } - LocatorMatcherTask::OutputData mergeWith(const LocatorMatcherTask::OutputData &entries, - std::atomic &state) { - LocatorMatcherTask::OutputData results; + LocatorFilterEntries mergeWith(const LocatorFilterEntries &entries, + std::atomic &state) { + LocatorFilterEntries results; results.reserve(entries.size()); for (const LocatorFilterEntry &entry : entries) { if (state == State::Canceled) - return LocatorMatcherTask::OutputData(); + return {}; const auto &link = entry.linkForEditor; if (!link || m_cache.emplace(*link).second) results.append(entry); } if (state == State::Canceled) - return LocatorMatcherTask::OutputData(); + return {}; m_data += results; return results; } - LocatorMatcherTask::OutputData entries() const { return m_data; } + LocatorFilterEntries entries() const { return m_data; } private: - LocatorMatcherTask::OutputData m_data; + LocatorFilterEntries m_data; std::unordered_set m_cache; }; @@ -93,7 +93,7 @@ public: , m_outputData(filterCount, {}) {} - void addOutputData(int index, const LocatorMatcherTask::OutputData &outputData) + void addOutputData(int index, const LocatorFilterEntries &outputData) { QTC_ASSERT(index >= 0, return); @@ -115,9 +115,9 @@ public: } // Called from separate thread (OutputFilter's thread) - void run(QPromise &promise) + void run(QPromise &promise) { - QList> data; + QList> data; QList> workingList(m_filterCount, {}); while (waitForData(&data)) { // Emit new results only when new data is reachable from the beginning (i.e. no gaps) @@ -137,13 +137,13 @@ public: const auto &workingData = workingList.at(currentIndex); if (!workingData.has_value()) { const bool mergeToCurrent = currentIndex == mergeToIndex; - const LocatorMatcherTask::OutputData dataForIndex = mergeToCurrent - ? *outputData : LocatorMatcherTask::OutputData(); + const LocatorFilterEntries dataForIndex = mergeToCurrent ? *outputData + : LocatorFilterEntries(); workingList[currentIndex] = std::make_optional(WorkingData(dataForIndex, m_state)); if (m_state == State::Canceled) return; - const LocatorMatcherTask::OutputData newData = mergeToCurrent + const LocatorFilterEntries newData = mergeToCurrent ? workingList[currentIndex]->entries() : workingList[mergeToIndex]->mergeWith(*outputData, m_state); if (m_state == State::Canceled) @@ -151,7 +151,7 @@ public: if (!hasGap && !newData.isEmpty()) promise.addResult(newData); } else if (currentIndex != mergeToIndex) { - const LocatorMatcherTask::OutputData newData + const LocatorFilterEntries newData = workingList[mergeToIndex]->mergeWith(workingData->entries(), m_state); workingList[currentIndex] = std::make_optional({}); if (m_state == State::Canceled) @@ -168,7 +168,7 @@ public: } private: - bool waitForData(QList> *data) + bool waitForData(QList> *data) { QMutexLocker locker(&m_mutex); if (m_state == State::Canceled) @@ -191,7 +191,7 @@ private: QWaitCondition m_waitCondition; const int m_filterCount = 0; std::atomic m_state = State::Awaiting; - QList> m_outputData; + QList> m_outputData; }; class OutputFilter : public QObject @@ -202,18 +202,18 @@ public: ~OutputFilter(); void setFilterCount(int count); // When last index is added it ends automatically (asynchronously) - void addOutputData(int index, const LocatorMatcherTask::OutputData &outputData); + void addOutputData(int index, const LocatorFilterEntries &outputData); void start(); bool isRunning() const { return m_watcher.get(); } signals: - void serialOutputDataReady(const LocatorMatcherTask::OutputData &serialOutputData); + void serialOutputDataReady(const LocatorFilterEntries &serialOutputData); void done(); private: int m_filterCount = 0; - std::unique_ptr> m_watcher; + std::unique_ptr> m_watcher; std::shared_ptr m_dataProvider; }; @@ -234,7 +234,7 @@ void OutputFilter::setFilterCount(int count) m_filterCount = count; } -void OutputFilter::addOutputData(int index, const LocatorMatcherTask::OutputData &outputData) +void OutputFilter::addOutputData(int index, const LocatorFilterEntries &outputData) { QTC_ASSERT(isRunning(), return); @@ -251,7 +251,7 @@ void OutputFilter::start() } m_dataProvider.reset(new OutputDataProvider(m_filterCount)); - m_watcher.reset(new QFutureWatcher); + m_watcher.reset(new QFutureWatcher); connect(m_watcher.get(), &QFutureWatcherBase::resultReadyAt, this, [this](int index) { emit serialOutputDataReady(m_watcher->resultAt(index)); }); @@ -262,7 +262,7 @@ void OutputFilter::start() }); // TODO: When filterCount == 1, deliver results directly and finish? - auto filter = [](QPromise &promise, + auto filter = [](QPromise &promise, const std::shared_ptr &dataProvider) { dataProvider->run(promise); }; @@ -303,7 +303,7 @@ void LocatorMatcher::setTasks(const QList &tasks) d->m_tasks = tasks; } -void LocatorMatcher::setInputData(const LocatorMatcherTask::InputData &inputData) +void LocatorMatcher::setInputData(const QString &inputData) { d->m_storage.input = inputData; } @@ -331,7 +331,7 @@ void LocatorMatcher::start() filterStorage->m_filter = &filter; filter.setFilterCount(filterCount); connect(&filter, &OutputFilter::serialOutputDataReady, - this, [this](const LocatorMatcherTask::OutputData &serialOutputData) { + this, [this](const LocatorFilterEntries &serialOutputData) { d->m_storage.output += serialOutputData; emit serialOutputDataReady(serialOutputData); }); @@ -406,13 +406,13 @@ bool LocatorMatcher::isRunning() const return d->m_taskTree.get() && d->m_taskTree->isRunning(); } -LocatorMatcherTask::OutputData LocatorMatcher::outputData() const +LocatorFilterEntries LocatorMatcher::outputData() const { return d->m_storage.output; } -LocatorMatcherTask::OutputData LocatorMatcher::runBlocking(const QList &tasks, - const LocatorMatcherTask::InputData &input, int parallelLimit) +LocatorFilterEntries LocatorMatcher::runBlocking(const QList &tasks, + const QString &input, int parallelLimit) { LocatorMatcher tree; tree.setTasks(tasks); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 77dc59b2d08..e8428e5eb36 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -112,16 +112,16 @@ public: } }; +using LocatorFilterEntries = QList; + class CORE_EXPORT LocatorMatcherTask final { public: - using InputData = QString; - using OutputData = QList; class Storage { public: - InputData input; - OutputData output; + QString input; + LocatorFilterEntries output; }; // The main task. Initial data taken from storage.input field. // Results reporting is done through the storage.output field. @@ -150,25 +150,24 @@ public: LocatorMatcher(); ~LocatorMatcher(); void setTasks(const QList &tasks); - void setInputData(const LocatorMatcherTask::InputData &inputData); + void setInputData(const QString &inputData); void setParallelLimit(int limit); // by default 0 = parallel void start(); void stop(); bool isRunning() const; // Total data collected so far, even when running. - LocatorMatcherTask::OutputData outputData() const; + LocatorFilterEntries outputData() const; // Note: Starts internal event loop. - static LocatorMatcherTask::OutputData runBlocking(const QList &tasks, - const LocatorMatcherTask::InputData &input, - int parallelLimit = 0); + static LocatorFilterEntries runBlocking(const QList &tasks, + const QString &input, int parallelLimit = 0); static void addMatcherCreator(MatcherType type, const LocatorMatcherTaskCreator &creator); static QList matchers(MatcherType type); signals: - void serialOutputDataReady(const LocatorMatcherTask::OutputData &serialOutputData); + void serialOutputDataReady(const LocatorFilterEntries &serialOutputData); void done(bool success); private: diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 7eaee38b84f..13320c2ae62 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -26,10 +26,10 @@ namespace CppEditor { using EntryFromIndex = std::function; -void matchesFor(QPromise &promise, const QString &entry, +void matchesFor(QPromise &promise, const QString &entry, IndexItem::ItemType wantedType, const EntryFromIndex &converter) { - QList entries[int(ILocatorFilter::MatchLevel::Count)]; + LocatorFilterEntries entries[int(ILocatorFilter::MatchLevel::Count)]; const Qt::CaseSensitivity caseSensitivityForPrefix = ILocatorFilter::caseSensitivity(entry); const QRegularExpression regexp = ILocatorFilter::createRegExp(entry); if (!regexp.isValid()) @@ -96,7 +96,7 @@ void matchesFor(QPromise &promise, const QString } promise.addResult(std::accumulate(std::begin(entries), std::end(entries), - QList())); + LocatorFilterEntries())); } LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex &converter) @@ -105,15 +105,15 @@ LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex TreeStorage storage; - const auto onSetup = [=](AsyncTask &async) { + const auto onSetup = [=](AsyncTask &async) { async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); async.setConcurrentCallData(matchesFor, storage->input, type, converter); }; - const auto onDone = [storage](const AsyncTask &async) { + const auto onDone = [storage](const AsyncTask &async) { if (async.isResultAvailable()) storage->output = async.result(); }; - return {Async(onSetup, onDone, onDone), storage}; + return {Async(onSetup, onDone, onDone), storage}; } LocatorMatcherTask cppAllSymbolsMatcher() @@ -200,7 +200,7 @@ LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &m return LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, dataType); } -void matchesForCurrentDocument(QPromise &promise, +void matchesForCurrentDocument(QPromise &promise, const QString &entry, const FilePath ¤tFileName) { const QRegularExpression regexp = FuzzyMatcher::createRegExp(entry, Qt::CaseInsensitive, false); @@ -304,15 +304,15 @@ LocatorMatcherTask cppCurrentDocumentMatcher() TreeStorage storage; - const auto onSetup = [=](AsyncTask &async) { + const auto onSetup = [=](AsyncTask &async) { async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); async.setConcurrentCallData(matchesForCurrentDocument, storage->input, currentFileName()); }; - const auto onDone = [storage](const AsyncTask &async) { + const auto onDone = [storage](const AsyncTask &async) { if (async.isResultAvailable()) storage->output = async.result(); }; - return {Async(onSetup, onDone, onDone), storage}; + return {Async(onSetup, onDone, onDone), storage}; } CppLocatorFilter::CppLocatorFilter() diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index f81ab6c40f6..7edb0c9d50e 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -53,7 +53,7 @@ public: return result; }; - const QList entries = filter ? matchesFor(searchText) : runMatcher(); + const LocatorFilterEntries entries = filter ? matchesFor(searchText) : runMatcher(); const ResultDataList results = ResultData::fromFilterEntryList(entries); if (debug) { ResultData::printFilterEntries(expectedResults, "Expected:"); @@ -93,7 +93,7 @@ public: return result; }; - const QList entries = matchers.isEmpty() ? matchesFor(searchText) + const LocatorFilterEntries entries = matchers.isEmpty() ? matchesFor(searchText) : runMatcher(); ResultDataList results = ResultData::fromFilterEntryList(entries); if (debug) { diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 83c13002d21..a0229b11869 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -28,7 +28,7 @@ using namespace Utils; namespace LanguageClient { -void filterResults(QPromise &promise, Client *client, +void filterResults(QPromise &promise, Client *client, const QList &results, const QList &filter) { const auto doFilter = [&](const SymbolInformation &info) { @@ -71,7 +71,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, *resultStorage = result->toList(); }; - const auto onFilterSetup = [=](AsyncTask &async) { + const auto onFilterSetup = [=](AsyncTask &async) { const QList results = *resultStorage; if (results.isEmpty()) return TaskAction::StopWithDone; @@ -79,7 +79,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, async.setConcurrentCallData(filterResults, client, results, filter); return TaskAction::Continue; }; - const auto onFilterDone = [storage](const AsyncTask &async) { + const auto onFilterDone = [storage](const AsyncTask &async) { if (async.isResultAvailable()) storage->output = async.result(); }; @@ -87,7 +87,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, const Group root { Storage(resultStorage), SymbolRequest(onQuerySetup, onQueryDone), - Async(onFilterSetup, onFilterDone) + Async(onFilterSetup, onFilterDone) }; return {root, storage}; } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index d57c0bacc5f..2837fe844c8 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -599,7 +599,7 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) using namespace Utils; if (m_completion == Completion::None) return; - const auto handleResults = [this, lineEdit](const QList &entries) { + const auto handleResults = [this, lineEdit](const LocatorFilterEntries &entries) { QSet namespaces; QStringList classes; Project * const project = ProjectTree::currentProject(); From 38d4f3fef3258140a483fd61680c54244c820f6a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 20:12:57 +0200 Subject: [PATCH 0625/1447] LocatorFilter: Introduce LocatorMatcherTasks Change-Id: I775c88b8ac7d7bb0719a6b20d1e5171dbd62a94d Reviewed-by: Reviewed-by: Eike Ziller --- .../clangcodemodel/clangmodelmanagersupport.cpp | 2 +- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 10 +++++----- src/plugins/coreplugin/locator/ilocatorfilter.h | 9 +++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 40619bc8ed1..c1d8b59196b 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -209,7 +209,7 @@ ClangModelManagerSupport::ClangModelManagerSupport() using WorkspaceMatcherCreator = std::function; const auto matcherCreator = [](const WorkspaceMatcherCreator &creator) { const QList clients = clientsForOpenProjects(); - QList matchers; + LocatorMatcherTasks matchers; for (Client *client : clients) matchers << creator(client, 10000); return matchers; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index fc8b7126788..9628fc49fde 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -287,7 +287,7 @@ namespace Core { class LocatorMatcherPrivate { public: - QList m_tasks; + LocatorMatcherTasks m_tasks; LocatorMatcherTask::Storage m_storage; int m_parallelLimit = 0; std::unique_ptr m_taskTree; @@ -298,7 +298,7 @@ LocatorMatcher::LocatorMatcher() LocatorMatcher::~LocatorMatcher() = default; -void LocatorMatcher::setTasks(const QList &tasks) +void LocatorMatcher::setTasks(const LocatorMatcherTasks &tasks) { d->m_tasks = tasks; } @@ -411,7 +411,7 @@ LocatorFilterEntries LocatorMatcher::outputData() const return d->m_storage.output; } -LocatorFilterEntries LocatorMatcher::runBlocking(const QList &tasks, +LocatorFilterEntries LocatorMatcher::runBlocking(const LocatorMatcherTasks &tasks, const QString &input, int parallelLimit) { LocatorMatcher tree; @@ -435,10 +435,10 @@ void LocatorMatcher::addMatcherCreator(MatcherType type, const LocatorMatcherTas s_matcherCreators[type].append(creator); } -QList LocatorMatcher::matchers(MatcherType type) +LocatorMatcherTasks LocatorMatcher::matchers(MatcherType type) { const QList creators = s_matcherCreators.value(type); - QList result; + LocatorMatcherTasks result; for (const LocatorMatcherTaskCreator &creator : creators) result << creator(); return result; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index e8428e5eb36..e89bdc0885c 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -132,7 +132,8 @@ public: Utils::Tasking::TreeStorage storage; }; -using LocatorMatcherTaskCreator = std::function()>; +using LocatorMatcherTasks = QList; +using LocatorMatcherTaskCreator = std::function; class LocatorMatcherPrivate; enum class MatcherType { @@ -149,7 +150,7 @@ class CORE_EXPORT LocatorMatcher final : public QObject public: LocatorMatcher(); ~LocatorMatcher(); - void setTasks(const QList &tasks); + void setTasks(const LocatorMatcherTasks &tasks); void setInputData(const QString &inputData); void setParallelLimit(int limit); // by default 0 = parallel void start(); @@ -160,11 +161,11 @@ public: LocatorFilterEntries outputData() const; // Note: Starts internal event loop. - static LocatorFilterEntries runBlocking(const QList &tasks, + static LocatorFilterEntries runBlocking(const LocatorMatcherTasks &tasks, const QString &input, int parallelLimit = 0); static void addMatcherCreator(MatcherType type, const LocatorMatcherTaskCreator &creator); - static QList matchers(MatcherType type); + static LocatorMatcherTasks matchers(MatcherType type); signals: void serialOutputDataReady(const LocatorFilterEntries &serialOutputData); From 8745813721375d02c1c8e5b8d06230ccf8486af6 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 17 Apr 2023 12:48:24 +0200 Subject: [PATCH 0626/1447] Editor: add option to switch markdown viewer panes Task-number: QTCREATORBUG-27883 Change-Id: I18daa688ff7751f984a95132737cfcc219b92108 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: David Schulz --- src/plugins/texteditor/markdowneditor.cpp | 38 +++++++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 94ccde4b3ae..b6993dacd57 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -23,6 +23,8 @@ namespace TextEditor::Internal { const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; const char MARKDOWNVIEWER_TEXT_CONTEXT[] = "Editors.MarkdownViewer.Text"; const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown"; +const char MARKDOWNVIEWER_TEXTEDITOR_RIGHT[] = "Markdown.TextEditorRight"; +const bool kTextEditorRightDefault = true; class MarkdownEditor : public Core::IEditor { @@ -32,14 +34,18 @@ public: { m_document->setMimeType(MARKDOWNVIEWER_MIME_TYPE); + QSettings *s = Core::ICore::settings(); + const bool textEditorRight + = s->value(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, kTextEditorRightDefault).toBool(); + // Left side - auto browser = new QTextBrowser(&m_widget); + auto browser = new QTextBrowser(); browser->setOpenExternalLinks(true); browser->setFrameShape(QFrame::NoFrame); new Utils::MarkdownHighlighter(browser->document()); // Right side (hidable) - m_textEditorWidget = new TextEditorWidget(&m_widget); + m_textEditorWidget = new TextEditorWidget; m_textEditorWidget->setTextDocument(m_document); m_textEditorWidget->setupGenericHighlighter(); m_textEditorWidget->setMarksVisible(false); @@ -48,6 +54,14 @@ public: context->setContext(Core::Context(MARKDOWNVIEWER_TEXT_CONTEXT)); Core::ICore::addContextObject(context); + if (textEditorRight) { + m_widget.addWidget(browser); + m_widget.addWidget(m_textEditorWidget); + } else { + m_widget.addWidget(m_textEditorWidget); + m_widget.addWidget(browser); + } + setContext(Core::Context(MARKDOWNVIEWER_ID)); setWidget(&m_widget); @@ -56,11 +70,15 @@ public: toggleEditorVisible->setCheckable(true); toggleEditorVisible->setChecked(true); + auto swapViews = new QToolButton; + swapViews->setText(Tr::tr("Swap Views")); + auto layout = new QHBoxLayout(&m_toolbar); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); layout->addStretch(); layout->addWidget(toggleEditorVisible); + layout->addWidget(swapViews); connect(m_document.data(), &TextDocument::mimeTypeChanged, m_document.data(), &TextDocument::changed); @@ -81,6 +99,20 @@ public: : Tr::tr("Show Editor")); }); + connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this] { + QTC_ASSERT(m_widget.count() > 1, return); + auto placeholder = std::make_unique(); + auto second = m_widget.replaceWidget(1, placeholder.get()); + auto first = m_widget.replaceWidget(0, second); + m_widget.replaceWidget(1, first); + Utils::QtcSettings *s = Core::ICore::settings(); + s->setValueWithDefault(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, + !s->value(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, + kTextEditorRightDefault) + .toBool(), + kTextEditorRightDefault); + }); + connect(m_document->document(), &QTextDocument::contentsChanged, this, [this, browser] { QHash positions; const auto scrollBars = browser->findChildren(); @@ -123,4 +155,4 @@ MarkdownEditorFactory::MarkdownEditorFactory() setEditorCreator([] { return new MarkdownEditor; }); } -} // TextEditor::Internal +} // namespace TextEditor::Internal From 8d1307552bd32a0e36207ab26156a1a2a83ad7aa Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:40:54 +0200 Subject: [PATCH 0627/1447] Copilot: Take advantage of IOptionPage::setWidgetCreator() Less boilerplate for the implementation add user code access to IOptionPage::{apply,finish} is planned to be removed. Change-Id: I03bbde071fdf673bee0568baa9ae9fab8d816590 Reviewed-by: David Schulz --- src/plugins/copilot/copilotoptionspage.cpp | 29 +++++++--------------- src/plugins/copilot/copilotoptionspage.h | 9 +------ src/plugins/copilot/copilotplugin.cpp | 2 +- src/plugins/copilot/copilotplugin.h | 2 -- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index feb807d7f1e..33d0c4361a4 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -17,11 +17,10 @@ using namespace LanguageClient; namespace Copilot { -class CopilotOptionsPageWidget : public QWidget +class CopilotOptionsPageWidget : public Core::IOptionsPageWidget { public: - CopilotOptionsPageWidget(QWidget *parent = nullptr) - : QWidget(parent) + CopilotOptionsPageWidget() { using namespace Layouting; @@ -73,6 +72,12 @@ file from the Copilot neovim plugin. updateAuthWidget); updateAuthWidget(); } + + void apply() final + { + CopilotSettings::instance().apply(); + CopilotSettings::instance().writeSettings(Core::ICore::settings()); + } }; CopilotOptionsPage::CopilotOptionsPage() @@ -82,25 +87,9 @@ CopilotOptionsPage::CopilotOptionsPage() setCategory("ZY.Copilot"); setDisplayCategory("Copilot"); setCategoryIconPath(":/copilot/images/settingscategory_copilot.png"); + setWidgetCreator([] { return new CopilotOptionsPageWidget; }); } -CopilotOptionsPage::~CopilotOptionsPage() {} - -void CopilotOptionsPage::init() {} - -QWidget *CopilotOptionsPage::widget() -{ - return new CopilotOptionsPageWidget(); -} - -void CopilotOptionsPage::apply() -{ - CopilotSettings::instance().apply(); - CopilotSettings::instance().writeSettings(Core::ICore::settings()); -} - -void CopilotOptionsPage::finish() {} - CopilotOptionsPage &CopilotOptionsPage::instance() { static CopilotOptionsPage settingsPage; diff --git a/src/plugins/copilot/copilotoptionspage.h b/src/plugins/copilot/copilotoptionspage.h index 1124f74dea6..103e975b634 100644 --- a/src/plugins/copilot/copilotoptionspage.h +++ b/src/plugins/copilot/copilotoptionspage.h @@ -11,15 +11,8 @@ class CopilotOptionsPage : public Core::IOptionsPage { public: CopilotOptionsPage(); - ~CopilotOptionsPage() override; static CopilotOptionsPage &instance(); - - void init(); - - QWidget *widget() override; - void apply() override; - void finish() override; }; -} // namespace Copilot +} // Copilot diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 67e07b170c5..3acbc705854 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -50,7 +50,7 @@ void CopilotPlugin::initialize() void CopilotPlugin::extensionsInitialized() { - CopilotOptionsPage::instance().init(); + (void)CopilotOptionsPage::instance(); } void CopilotPlugin::restartClient() diff --git a/src/plugins/copilot/copilotplugin.h b/src/plugins/copilot/copilotplugin.h index 5d915030653..09a6caecb20 100644 --- a/src/plugins/copilot/copilotplugin.h +++ b/src/plugins/copilot/copilotplugin.h @@ -9,8 +9,6 @@ #include -namespace TextEditor { class TextEditorWidget; } - namespace Copilot { namespace Internal { From 69d53245f25d566566794e8c81ace2b779551867 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:54:44 +0200 Subject: [PATCH 0628/1447] Python: Avoid IOptionPageWidget::widget() in settings This is planned to become inaccessible for user code. Change-Id: I2530a6ccf9f46cedff68ae62e8ac3d42d6792e0a Reviewed-by: David Schulz --- src/plugins/python/pythonsettings.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index ff3a18ef149..714b8158189 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -318,34 +318,37 @@ public: setCategory(Constants::C_PYTHON_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr("Python")); setCategoryIconPath(":/python/images/settingscategory_python.png"); - setWidgetCreator([]() { return new InterpreterOptionsWidget(); }); + setWidgetCreator([this] { m_widget = new InterpreterOptionsWidget; return m_widget; }); } QList interpreters() { - if (auto w = static_cast(widget())) - return w->interpreters(); + if (m_widget) + return m_widget->interpreters(); return {}; } void addInterpreter(const Interpreter &interpreter) { - if (auto w = static_cast(widget())) - w->addInterpreter(interpreter); + if (m_widget) + m_widget->addInterpreter(interpreter); } void removeInterpreterFrom(const QString &detectionSource) { - if (auto w = static_cast(widget())) - w->removeInterpreterFrom(detectionSource); + if (m_widget) + m_widget->removeInterpreterFrom(detectionSource); } QList interpreterFrom(const QString &detectionSource) { - if (auto w = static_cast(widget())) - return w->interpreterFrom(detectionSource); + if (m_widget) + return m_widget->interpreterFrom(detectionSource); return {}; } + +private: + InterpreterOptionsWidget *m_widget = nullptr; }; static bool alreadyRegistered(const QList &pythons, const FilePath &pythonExecutable) From 214742e9430e8fe7be6bdcc33b257da783a5e958 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:53:02 +0200 Subject: [PATCH 0629/1447] Haskell: Use IOptionPage::setWidgetCreator() for settings Change-Id: I4565cfca2bc58fd78e4c35fa1abda43532c113b6 Reviewed-by: Eike Ziller --- src/plugins/haskell/optionspage.cpp | 55 ++++++++++++++--------------- src/plugins/haskell/optionspage.h | 19 ++-------- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/src/plugins/haskell/optionspage.cpp b/src/plugins/haskell/optionspage.cpp index ac33b757eb9..540656ba4f4 100644 --- a/src/plugins/haskell/optionspage.cpp +++ b/src/plugins/haskell/optionspage.cpp @@ -7,31 +7,24 @@ #include "haskellmanager.h" #include "haskelltr.h" +#include + #include #include #include #include -#include -namespace Haskell { -namespace Internal { +using namespace Utils; -OptionsPage::OptionsPage() +namespace Haskell::Internal { + +class HaskellOptionsPageWidget : public Core::IOptionsPageWidget { - setId(Constants::OPTIONS_GENERAL); - setDisplayName(Tr::tr("General")); - setCategory("J.Z.Haskell"); - setDisplayCategory(Tr::tr("Haskell")); - setCategoryIconPath(":/haskell/images/settingscategory_haskell.png"); -} - -QWidget *OptionsPage::widget() -{ - using namespace Utils; - if (!m_widget) { - m_widget = new QWidget; +public: + HaskellOptionsPageWidget() + { auto topLayout = new QVBoxLayout; - m_widget->setLayout(topLayout); + setLayout(topLayout); auto generalBox = new QGroupBox(Tr::tr("General")); topLayout->addWidget(generalBox); topLayout->addStretch(10); @@ -45,19 +38,23 @@ QWidget *OptionsPage::widget() m_stackPath->setCommandVersionArguments({"--version"}); boxLayout->addWidget(m_stackPath); } - return m_widget; -} -void OptionsPage::apply() + void apply() final + { + HaskellManager::setStackExecutable(m_stackPath->rawFilePath()); + } + + QPointer m_stackPath; +}; + +OptionsPage::OptionsPage() { - if (!m_widget) - return; - HaskellManager::setStackExecutable(m_stackPath->rawFilePath()); + setId(Constants::OPTIONS_GENERAL); + setDisplayName(Tr::tr("General")); + setCategory("J.Z.Haskell"); + setDisplayCategory(Tr::tr("Haskell")); + setCategoryIconPath(":/haskell/images/settingscategory_haskell.png"); + setWidgetCreator([] { return new HaskellOptionsPageWidget; }); } -void OptionsPage::finish() -{ -} - -} // namespace Internal -} // namespace Haskell +} // Haskell::Internal diff --git a/src/plugins/haskell/optionspage.h b/src/plugins/haskell/optionspage.h index a477d72dfce..4328be44e7b 100644 --- a/src/plugins/haskell/optionspage.h +++ b/src/plugins/haskell/optionspage.h @@ -4,28 +4,13 @@ #pragma once #include -#include -#include - -namespace Haskell { -namespace Internal { +namespace Haskell::Internal { class OptionsPage : public Core::IOptionsPage { - Q_OBJECT - public: OptionsPage(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - QPointer m_widget; - QPointer m_stackPath; }; -} // namespace Internal -} // namespace Haskell +} // Haskell::Internal From 61aef4aba5a20a03cee89844e614074e0b892d0b Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:51:15 +0200 Subject: [PATCH 0630/1447] Core: Use IOptionPage::setWidgetCreator() for mime settings Less boilerplate for the implementation add user code access to IOptionPage::{apply,finish} is planned to be removed. Change-Id: I75c9ca893f49d66b72f6108f2451f3b0cb46722a Reviewed-by: Eike Ziller --- src/plugins/coreplugin/mimetypesettings.cpp | 49 +++++++++++---------- src/plugins/coreplugin/mimetypesettings.h | 5 +-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/plugins/coreplugin/mimetypesettings.cpp b/src/plugins/coreplugin/mimetypesettings.cpp index a4efe1c30ef..d01abeffd21 100644 --- a/src/plugins/coreplugin/mimetypesettings.cpp +++ b/src/plugins/coreplugin/mimetypesettings.cpp @@ -291,6 +291,31 @@ MimeTypeSettingsPrivate::MimeTypeSettingsPrivate() MimeTypeSettingsPrivate::~MimeTypeSettingsPrivate() = default; +class MimeTypeSettingsWidget : public IOptionsPageWidget +{ +public: + MimeTypeSettingsWidget(MimeTypeSettingsPrivate *d) + : d(d) + { + d->configureUi(this); + } + + void apply() final + { + MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(d->m_pendingModifiedMimeTypes); + Core::Internal::setUserPreferredEditorTypes(d->m_model->m_userDefault); + d->m_pendingModifiedMimeTypes.clear(); + d->m_model->load(); + } + + void finish() final + { + d->m_pendingModifiedMimeTypes.clear(); + } + + MimeTypeSettingsPrivate *d; +}; + void MimeTypeSettingsPrivate::configureUi(QWidget *w) { auto filterLineEdit = new FancyLineEdit; @@ -713,6 +738,7 @@ MimeTypeSettings::MimeTypeSettings() setId(Constants::SETTINGS_ID_MIMETYPES); setDisplayName(Tr::tr("MIME Types")); setCategory(Constants::SETTINGS_CATEGORY_CORE); + setWidgetCreator([this] { return new MimeTypeSettingsWidget(d); }); } MimeTypeSettings::~MimeTypeSettings() @@ -720,29 +746,6 @@ MimeTypeSettings::~MimeTypeSettings() delete d; } -QWidget *MimeTypeSettings::widget() -{ - if (!d->m_widget) { - d->m_widget = new QWidget; - d->configureUi(d->m_widget); - } - return d->m_widget; -} - -void MimeTypeSettings::apply() -{ - MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(d->m_pendingModifiedMimeTypes); - Core::Internal::setUserPreferredEditorTypes(d->m_model->m_userDefault); - d->m_pendingModifiedMimeTypes.clear(); - d->m_model->load(); -} - -void MimeTypeSettings::finish() -{ - d->m_pendingModifiedMimeTypes.clear(); - delete d->m_widget; -} - void MimeTypeSettings::restoreSettings() { MimeTypeSettingsPrivate::UserMimeTypeHash mimetypes diff --git a/src/plugins/coreplugin/mimetypesettings.h b/src/plugins/coreplugin/mimetypesettings.h index f676de53e62..57dee3a732b 100644 --- a/src/plugins/coreplugin/mimetypesettings.h +++ b/src/plugins/coreplugin/mimetypesettings.h @@ -17,11 +17,8 @@ public: MimeTypeSettings(); ~MimeTypeSettings() override; - QWidget *widget() override; - void apply() override; - void finish() override; - static void restoreSettings(); + private: MimeTypeSettingsPrivate *d; }; From 0ab1eaa31c3602666742cd2a422e8db7e10da9dc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 13 Apr 2023 18:18:02 +0200 Subject: [PATCH 0631/1447] LocatorMatcherTask: Refactor the storage class Considering the case that a locator task is running its task in a separate thread, at least 3 threads are involved: 1. Main thread 2. Task's thread 3. OutputFilter's thread (the thread that removes duplicates from tasks' results) State before this patch: The task (2) was always delivering the results into the main thread (1), and when main thread received the result it was passed to the OutputFilter's thread (3). The drawback is that we needlessly block the main thread for intermediate handling. State after this patch: The task (2) is delivering the results directly to the OutputFilter's thread (3), without blocking the main thread (1). Currently the common object shared between all 3 threads is OutputDataProvider. Rename addOutput() into reportOutput(). Make ILocatorFilter::matchers() private. Change-Id: Ie8ad7d82ae02825e232f65b82fe329e780f58626 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../coreplugin/locator/ilocatorfilter.cpp | 111 ++++++++++++++---- .../coreplugin/locator/ilocatorfilter.h | 33 ++++-- src/plugins/cppeditor/cpplocatorfilter.cpp | 50 ++++---- src/plugins/languageclient/locatorfilter.cpp | 20 ++-- 4 files changed, 138 insertions(+), 76 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 9628fc49fde..bb4795fcc16 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -93,13 +93,16 @@ public: , m_outputData(filterCount, {}) {} - void addOutputData(int index, const LocatorFilterEntries &outputData) + void reportOutput(int index, const LocatorFilterEntries &outputData) { QTC_ASSERT(index >= 0, return); QMutexLocker locker(&m_mutex); + // It may happen that the task tree was canceled, while tasks are still running in other + // threads and are about to be canceled. In this case we just ignore the call. + if (m_state == State::Canceled) + return; QTC_ASSERT(index < m_filterCount, return); - QTC_ASSERT(m_state != State::Canceled, return); QTC_ASSERT(!m_outputData.at(index).has_value(), return); m_outputData[index] = outputData; @@ -201,12 +204,12 @@ class OutputFilter : public QObject public: ~OutputFilter(); void setFilterCount(int count); - // When last index is added it ends automatically (asynchronously) - void addOutputData(int index, const LocatorFilterEntries &outputData); void start(); bool isRunning() const { return m_watcher.get(); } + std::shared_ptr dataProvider() const { return m_dataProvider; } + signals: void serialOutputDataReady(const LocatorFilterEntries &serialOutputData); void done(); @@ -234,13 +237,6 @@ void OutputFilter::setFilterCount(int count) m_filterCount = count; } -void OutputFilter::addOutputData(int index, const LocatorFilterEntries &outputData) -{ - QTC_ASSERT(isRunning(), return); - - m_dataProvider->addOutputData(index, outputData); -} - void OutputFilter::start() { QTC_ASSERT(!m_watcher, return); @@ -284,11 +280,72 @@ QTC_DECLARE_CUSTOM_TASK(Filter, Core::OutputFilterAdapter); namespace Core { +class LocatorStoragePrivate +{ +public: + LocatorStoragePrivate(const QString &input, int index, + const std::shared_ptr &dataProvider) + : m_input(input) + , m_index(index) + , m_dataProvider(dataProvider) + {} + + QString input() const { return m_input; } + + void reportOutput(const LocatorFilterEntries &outputData) + { + QMutexLocker locker(&m_mutex); + QTC_ASSERT(m_dataProvider, return); + reportOutputImpl(outputData); + } + + void finalize() + { + QMutexLocker locker(&m_mutex); + if (m_dataProvider) + reportOutputImpl({}); + } + +private: + // Call me with mutex locked + void reportOutputImpl(const LocatorFilterEntries &outputData) + { + QTC_ASSERT(m_index >= 0, return); + m_dataProvider->reportOutput(m_index, outputData); + // Deliver results only once for all copies of the storage, drop ref afterwards + m_dataProvider.reset(); + } + + const QString m_input; + const int m_index = -1; + std::shared_ptr m_dataProvider; + QMutex m_mutex = {}; +}; + +QString LocatorStorage::input() const +{ + QTC_ASSERT(d, return {}); + return d->input(); +} + +void LocatorStorage::reportOutput(const LocatorFilterEntries &outputData) const +{ + QTC_ASSERT(d, return); + d->reportOutput(outputData); +} + +void LocatorStorage::finalize() const +{ + QTC_ASSERT(d, return); + d->finalize(); +} + class LocatorMatcherPrivate { public: LocatorMatcherTasks m_tasks; - LocatorMatcherTask::Storage m_storage; + QString m_input; + LocatorFilterEntries m_output; int m_parallelLimit = 0; std::unique_ptr m_taskTree; }; @@ -305,7 +362,7 @@ void LocatorMatcher::setTasks(const LocatorMatcherTasks &tasks) void LocatorMatcher::setInputData(const QString &inputData) { - d->m_storage.input = inputData; + d->m_input = inputData; } void LocatorMatcher::setParallelLimit(int limit) @@ -316,7 +373,7 @@ void LocatorMatcher::setParallelLimit(int limit) void LocatorMatcher::start() { QTC_ASSERT(!isRunning(), return); - d->m_storage.output = {}; + d->m_output = {}; d->m_taskTree.reset(new TaskTree); using namespace Tasking; @@ -332,7 +389,7 @@ void LocatorMatcher::start() filter.setFilterCount(filterCount); connect(&filter, &OutputFilter::serialOutputDataReady, this, [this](const LocatorFilterEntries &serialOutputData) { - d->m_storage.output += serialOutputData; + d->m_output += serialOutputData; emit serialOutputDataReady(serialOutputData); }); }; @@ -343,27 +400,29 @@ void LocatorMatcher::start() QList parallelTasks { ParallelLimit(d->m_parallelLimit) }; - const auto onGroupSetup = [this](const TreeStorage &storage) { - return [this, storage] { storage->input = d->m_storage.input; }; - }; - const auto onGroupDone = [filterStorage] - (const TreeStorage &storage, int index) { - return [filterStorage, storage, index] { + const auto onGroupSetup = [this, filterStorage](const TreeStorage &storage, + int index) { + return [this, filterStorage, storage, index] { OutputFilter *outputFilter = filterStorage->m_filter; QTC_ASSERT(outputFilter, return); - outputFilter->addOutputData(index, storage->output); + *storage = std::make_shared(d->m_input, index, + outputFilter->dataProvider()); }; }; + const auto onGroupDone = [](const TreeStorage &storage) { + return [storage] { storage->finalize(); }; + }; + int index = 0; for (const LocatorMatcherTask &task : std::as_const(d->m_tasks)) { const auto storage = task.storage; const Group group { optional, Storage(storage), - OnGroupSetup(onGroupSetup(storage)), - OnGroupDone(onGroupDone(storage, index)), - OnGroupError(onGroupDone(storage, index)), + OnGroupSetup(onGroupSetup(storage, index)), + OnGroupDone(onGroupDone(storage)), + OnGroupError(onGroupDone(storage)), task.task }; parallelTasks << group; @@ -408,7 +467,7 @@ bool LocatorMatcher::isRunning() const LocatorFilterEntries LocatorMatcher::outputData() const { - return d->m_storage.output; + return d->m_output; } LocatorFilterEntries LocatorMatcher::runBlocking(const LocatorMatcherTasks &tasks, diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index e89bdc0885c..e2866d17519 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -25,6 +25,7 @@ namespace Core { namespace Internal { class Locator; } class ILocatorFilter; +class LocatorStoragePrivate; class AcceptResult { @@ -114,22 +115,29 @@ public: using LocatorFilterEntries = QList; +class CORE_EXPORT LocatorStorage final +{ +public: + LocatorStorage() = default; + QString input() const; + void reportOutput(const LocatorFilterEntries &outputData) const; + +private: + friend class LocatorMatcher; + LocatorStorage(const std::shared_ptr &priv) { d = priv; } + void finalize() const; + std::shared_ptr d; +}; + class CORE_EXPORT LocatorMatcherTask final { public: - class Storage - { - public: - QString input; - LocatorFilterEntries output; - }; - // The main task. Initial data taken from storage.input field. - // Results reporting is done through the storage.output field. + // The main task. Initial data (searchTerm) should be taken from storage.input(). + // Results reporting is done via the storage.reportOutput(). Utils::Tasking::TaskItem task = Utils::Tasking::Group{}; - // When setting up the task, take the input data from storage.input field. - // When task is done, report results by updating the storage.output field. + // When constructing the task, don't place the storage inside the task above. - Utils::Tasking::TreeStorage storage; + Utils::Tasking::TreeStorage storage; }; using LocatorMatcherTasks = QList; @@ -267,6 +275,9 @@ protected: static bool isOldSetting(const QByteArray &state); private: + // TODO: Make pure virtual when all subclasses implement it. + virtual LocatorMatcherTasks matchers() { return {}; } + friend class Internal::Locator; static const QList allLocatorFilters(); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 13320c2ae62..0435f03c9ae 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -26,18 +26,19 @@ namespace CppEditor { using EntryFromIndex = std::function; -void matchesFor(QPromise &promise, const QString &entry, +void matchesFor(QPromise &promise, const LocatorStorage &storage, IndexItem::ItemType wantedType, const EntryFromIndex &converter) { + const QString input = storage.input(); LocatorFilterEntries entries[int(ILocatorFilter::MatchLevel::Count)]; - const Qt::CaseSensitivity caseSensitivityForPrefix = ILocatorFilter::caseSensitivity(entry); - const QRegularExpression regexp = ILocatorFilter::createRegExp(entry); + const Qt::CaseSensitivity caseSensitivityForPrefix = ILocatorFilter::caseSensitivity(input); + const QRegularExpression regexp = ILocatorFilter::createRegExp(input); if (!regexp.isValid()) return; - const bool hasColonColon = entry.contains("::"); + const bool hasColonColon = input.contains("::"); const QRegularExpression shortRegexp = hasColonColon - ? ILocatorFilter::createRegExp(entry.mid(entry.lastIndexOf("::") + 2)) : regexp; + ? ILocatorFilter::createRegExp(input.mid(input.lastIndexOf("::") + 2)) : regexp; CppLocatorData *locatorData = CppModelManager::instance()->locatorData(); locatorData->filterAllFiles([&](const IndexItem::Ptr &info) { if (promise.isCanceled()) @@ -76,9 +77,9 @@ void matchesFor(QPromise &promise, const QString &entry, if (matchInParameterList) entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); - else if (filterEntry.displayName.startsWith(entry, caseSensitivityForPrefix)) + else if (filterEntry.displayName.startsWith(input, caseSensitivityForPrefix)) entries[int(ILocatorFilter::MatchLevel::Best)].append(filterEntry); - else if (filterEntry.displayName.contains(entry, caseSensitivityForPrefix)) + else if (filterEntry.displayName.contains(input, caseSensitivityForPrefix)) entries[int(ILocatorFilter::MatchLevel::Better)].append(filterEntry); else entries[int(ILocatorFilter::MatchLevel::Good)].append(filterEntry); @@ -95,7 +96,7 @@ void matchesFor(QPromise &promise, const QString &entry, Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); } - promise.addResult(std::accumulate(std::begin(entries), std::end(entries), + storage.reportOutput(std::accumulate(std::begin(entries), std::end(entries), LocatorFilterEntries())); } @@ -103,17 +104,13 @@ LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex { using namespace Tasking; - TreeStorage storage; + TreeStorage storage; - const auto onSetup = [=](AsyncTask &async) { + const auto onSetup = [=](AsyncTask &async) { async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); - async.setConcurrentCallData(matchesFor, storage->input, type, converter); + async.setConcurrentCallData(matchesFor, *storage, type, converter); }; - const auto onDone = [storage](const AsyncTask &async) { - if (async.isResultAvailable()) - storage->output = async.result(); - }; - return {Async(onSetup, onDone, onDone), storage}; + return {Async(onSetup), storage}; } LocatorMatcherTask cppAllSymbolsMatcher() @@ -200,10 +197,11 @@ LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &m return LocatorFilterEntry::HighlightInfo(positions.starts, positions.lengths, dataType); } -void matchesForCurrentDocument(QPromise &promise, - const QString &entry, const FilePath ¤tFileName) +void matchesForCurrentDocument(QPromise &promise, const LocatorStorage &storage, + const FilePath ¤tFileName) { - const QRegularExpression regexp = FuzzyMatcher::createRegExp(entry, Qt::CaseInsensitive, false); + const QString input = storage.input(); + const QRegularExpression regexp = FuzzyMatcher::createRegExp(input, Qt::CaseInsensitive, false); if (!regexp.isValid()) return; @@ -288,7 +286,7 @@ void matchesForCurrentDocument(QPromise &promise, } } } - promise.addResult(Utils::transform(betterEntries, + storage.reportOutput(Utils::transform(betterEntries, [](const Entry &entry) { return entry.entry; })); } @@ -302,17 +300,13 @@ LocatorMatcherTask cppCurrentDocumentMatcher() { using namespace Tasking; - TreeStorage storage; + TreeStorage storage; - const auto onSetup = [=](AsyncTask &async) { + const auto onSetup = [=](AsyncTask &async) { async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); - async.setConcurrentCallData(matchesForCurrentDocument, storage->input, currentFileName()); + async.setConcurrentCallData(matchesForCurrentDocument, *storage, currentFileName()); }; - const auto onDone = [storage](const AsyncTask &async) { - if (async.isResultAvailable()) - storage->output = async.result(); - }; - return {Async(onSetup, onDone, onDone), storage}; + return {Async(onSetup), storage}; } CppLocatorFilter::CppLocatorFilter() diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index a0229b11869..0fe00c23879 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -28,12 +28,14 @@ using namespace Utils; namespace LanguageClient { -void filterResults(QPromise &promise, Client *client, +void filterResults(QPromise &promise, const LocatorStorage &storage, Client *client, const QList &results, const QList &filter) { const auto doFilter = [&](const SymbolInformation &info) { return filter.contains(SymbolKind(info.kind())); }; + if (promise.isCanceled()) + return; const QList filteredResults = filter.isEmpty() ? results : Utils::filtered(results, doFilter); const auto generateEntry = [client](const SymbolInformation &info) { @@ -45,7 +47,7 @@ void filterResults(QPromise &promise, Client *client, entry.linkForEditor = info.location().toLink(client->hostPathMapper()); return entry; }; - promise.addResult(Utils::transform(filteredResults, generateEntry)); + storage.reportOutput(Utils::transform(filteredResults, generateEntry)); } LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, @@ -53,13 +55,13 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, { using namespace Tasking; - TreeStorage storage; + TreeStorage storage; TreeStorage> resultStorage; const auto onQuerySetup = [=](WorkspaceSymbolRequestTask &request) { request.setClient(client); WorkspaceSymbolParams params; - params.setQuery(storage->input); + params.setQuery(storage->input()); if (maxResultCount > 0) params.setLimit(maxResultCount); request.setParams(params); @@ -71,23 +73,19 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, *resultStorage = result->toList(); }; - const auto onFilterSetup = [=](AsyncTask &async) { + const auto onFilterSetup = [=](AsyncTask &async) { const QList results = *resultStorage; if (results.isEmpty()) return TaskAction::StopWithDone; async.setFutureSynchronizer(LanguageClientPlugin::futureSynchronizer()); - async.setConcurrentCallData(filterResults, client, results, filter); + async.setConcurrentCallData(filterResults, *storage, client, results, filter); return TaskAction::Continue; }; - const auto onFilterDone = [storage](const AsyncTask &async) { - if (async.isResultAvailable()) - storage->output = async.result(); - }; const Group root { Storage(resultStorage), SymbolRequest(onQuerySetup, onQueryDone), - Async(onFilterSetup, onFilterDone) + Async(onFilterSetup) }; return {root, storage}; } From f21e2ff65c30b71bfb29edac6d3800c1ea1c248a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 07:49:45 +0200 Subject: [PATCH 0632/1447] LocatorMatcher: Add more comments, do some renaming Rename: OutputDataProvider -> ResultsDeduplicator OutputFilter -> ResultsCollector Change-Id: If29ae29a2fa6895ad36d94577824fbb2e6b65a4d Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../coreplugin/locator/ilocatorfilter.cpp | 148 ++++++++++++------ 1 file changed, 98 insertions(+), 50 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index bb4795fcc16..58b4024639d 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -51,14 +51,39 @@ using namespace Utils; namespace Core { -class OutputDataProvider +// ResultsDeduplicator squashes upcoming results from various filters and removes +// duplicated entries. It also reports intermediate results (to be displayed in LocatorWidget). +// +// Assuming the results from filters come in this order (numbers are indices to filter results): +// 2, 4, 3, 1 - the various strategies are possible. The current strategy looks like this: +// - When 2nd result came - the result is stored +// - When 4th result came - the result is stored +// - When 3rd result came - it's being squased to the 2nd result and afterwards the 4th result +// result is being squashed into the common result list. +// - When 1st result came - the stored common list is squashed into the 1st result +// and intermediate results are reported (for 1-4 results). +// If the filterCount is 4, the deduplicator finishes now. +// If the filterCount is greater than 4, it waits for the remaining +// results. +// +// TODO: The other possible startegy would be to just store the newly reported data +// and do the actual deduplication only when new results are reachable from 1st index +// (i.e. skip the intermediate deduplication). +class ResultsDeduplicator { enum class State { - Awaiting, - NewData, - Canceled + Awaiting, // Waiting in a separate thread for new data, or fetched the last new data and + // is currently deduplicating. + // This happens when all previous data were squashed in the separate thread but + // still some data needs to come (reportOutput wasn't called for all filters, + // yet). The expected number of calls to reportOutput equals m_filterCount. + NewData, // The new data came and the separate thread is being awaken in order to squash + // it. After the separate thread is awaken it transitions to Awaiting state. + Canceled // The Deduplicator task has been canceled. }; + // A separate item for keeping squashed entries. Call mergeWith() to squash a consecutive + // results into this results. struct WorkingData { WorkingData() = default; WorkingData(const LocatorFilterEntries &entries, std::atomic &state) { @@ -88,12 +113,17 @@ class OutputDataProvider }; public: - OutputDataProvider(int filterCount) + // filterCount is the expected numbers of running filters. The separate thread executing run() + // will stop after reportOutput was called filterCount times, for all different indices + // in range [0, filterCount). + ResultsDeduplicator(int filterCount) : m_filterCount(filterCount) , m_outputData(filterCount, {}) {} void reportOutput(int index, const LocatorFilterEntries &outputData) + // Called directly by running filters. The calls may come from main thread in case of + // e.g. Sync task or directly from other threads when AsyncTask was used. { QTC_ASSERT(index >= 0, return); @@ -110,6 +140,8 @@ public: m_waitCondition.wakeOne(); } + // Called when the LocatorMatcher was canceled. It wakes the separate thread in order to + // finish it, soon. void cancel() { QMutexLocker locker(&m_mutex); @@ -117,7 +149,7 @@ public: m_waitCondition.wakeOne(); } - // Called from separate thread (OutputFilter's thread) + // Called from the separate thread (ResultsCollector's thread) void run(QPromise &promise) { QList> data; @@ -171,13 +203,18 @@ public: } private: + // Called from the separate thread, exclusively by run(). Checks if the new data already + // came before sleeping with wait condition. If so, it doesn't sleep with wait condition, + // but returns the data collected in meantime. Otherwise, it calls wait() on wait condition. bool waitForData(QList> *data) { QMutexLocker locker(&m_mutex); if (m_state == State::Canceled) return false; if (m_state == State::NewData) { - m_state = State::Awaiting; + m_state = State::Awaiting; // Mark the state as awaiting to detect new calls to + // setOutputData while the separate thread deduplicates the + // new data. *data = m_outputData; return true; } @@ -185,7 +222,9 @@ private: QTC_ASSERT(m_state != State::Awaiting, return false); if (m_state == State::Canceled) return false; - m_state = State::Awaiting; + m_state = State::Awaiting; // Mark the state as awaiting to detect new calls to + // setOutputData while the separate thread deduplicates the + // new data. *data = m_outputData; return true; } @@ -197,18 +236,26 @@ private: QList> m_outputData; }; -class OutputFilter : public QObject +// This instance of this object is created by LocatorMatcher tree. +// It starts a separate thread which collects and deduplicates the results reported +// by LocatorStorage instances. The ResultsCollector is started as a first task in +// LocatorMatcher and runs in parallel to all the filters started by LocatorMatcher. +// When all the results are reported (the expected number of reports is set with setFilterCount()), +// the ResultsCollector finishes. The intermediate results are reported with +// serialOutputDataReady() signal. +// The object of ResultsCollector is registered in Tasking namespace with Tasking::Collector name. +class ResultsCollector : public QObject { Q_OBJECT public: - ~OutputFilter(); + ~ResultsCollector(); void setFilterCount(int count); void start(); bool isRunning() const { return m_watcher.get(); } - std::shared_ptr dataProvider() const { return m_dataProvider; } + std::shared_ptr deduplicator() const { return m_deduplicator; } signals: void serialOutputDataReady(const LocatorFilterEntries &serialOutputData); @@ -217,19 +264,19 @@ signals: private: int m_filterCount = 0; std::unique_ptr> m_watcher; - std::shared_ptr m_dataProvider; + std::shared_ptr m_deduplicator; }; -OutputFilter::~OutputFilter() +ResultsCollector::~ResultsCollector() { if (!isRunning()) return; - m_dataProvider->cancel(); + m_deduplicator->cancel(); Internal::CorePlugin::futureSynchronizer()->addFuture(m_watcher->future()); } -void OutputFilter::setFilterCount(int count) +void ResultsCollector::setFilterCount(int count) { QTC_ASSERT(!isRunning(), return); QTC_ASSERT(count >= 0, return); @@ -237,7 +284,7 @@ void OutputFilter::setFilterCount(int count) m_filterCount = count; } -void OutputFilter::start() +void ResultsCollector::start() { QTC_ASSERT(!m_watcher, return); QTC_ASSERT(!isRunning(), return); @@ -246,7 +293,7 @@ void OutputFilter::start() return; } - m_dataProvider.reset(new OutputDataProvider(m_filterCount)); + m_deduplicator.reset(new ResultsDeduplicator(m_filterCount)); m_watcher.reset(new QFutureWatcher); connect(m_watcher.get(), &QFutureWatcherBase::resultReadyAt, this, [this](int index) { emit serialOutputDataReady(m_watcher->resultAt(index)); @@ -254,29 +301,29 @@ void OutputFilter::start() connect(m_watcher.get(), &QFutureWatcherBase::finished, this, [this] { emit done(); m_watcher.release()->deleteLater(); - m_dataProvider.reset(); + m_deduplicator.reset(); }); // TODO: When filterCount == 1, deliver results directly and finish? - auto filter = [](QPromise &promise, - const std::shared_ptr &dataProvider) { - dataProvider->run(promise); + auto deduplicate = [](QPromise &promise, + const std::shared_ptr &deduplicator) { + deduplicator->run(promise); }; - m_watcher->setFuture(Utils::asyncRun(filter, m_dataProvider)); + m_watcher->setFuture(Utils::asyncRun(deduplicate, m_deduplicator)); } -class OutputFilterAdapter : public Tasking::TaskAdapter +class ResultsCollectorAdapter : public Tasking::TaskAdapter { public: - OutputFilterAdapter() { - connect(task(), &OutputFilter::done, this, [this] { emit done(true); }); + ResultsCollectorAdapter() { + connect(task(), &ResultsCollector::done, this, [this] { emit done(true); }); } void start() final { task()->start(); } }; } // namespace Core -QTC_DECLARE_CUSTOM_TASK(Filter, Core::OutputFilterAdapter); +QTC_DECLARE_CUSTOM_TASK(Collector, Core::ResultsCollectorAdapter); namespace Core { @@ -284,10 +331,10 @@ class LocatorStoragePrivate { public: LocatorStoragePrivate(const QString &input, int index, - const std::shared_ptr &dataProvider) + const std::shared_ptr &deduplicator) : m_input(input) , m_index(index) - , m_dataProvider(dataProvider) + , m_deduplicator(deduplicator) {} QString input() const { return m_input; } @@ -295,14 +342,14 @@ public: void reportOutput(const LocatorFilterEntries &outputData) { QMutexLocker locker(&m_mutex); - QTC_ASSERT(m_dataProvider, return); + QTC_ASSERT(m_deduplicator, return); reportOutputImpl(outputData); } void finalize() { QMutexLocker locker(&m_mutex); - if (m_dataProvider) + if (m_deduplicator) reportOutputImpl({}); } @@ -311,14 +358,14 @@ private: void reportOutputImpl(const LocatorFilterEntries &outputData) { QTC_ASSERT(m_index >= 0, return); - m_dataProvider->reportOutput(m_index, outputData); + m_deduplicator->reportOutput(m_index, outputData); // Deliver results only once for all copies of the storage, drop ref afterwards - m_dataProvider.reset(); + m_deduplicator.reset(); } const QString m_input; const int m_index = -1; - std::shared_ptr m_dataProvider; + std::shared_ptr m_deduplicator; QMutex m_mutex = {}; }; @@ -378,35 +425,36 @@ void LocatorMatcher::start() using namespace Tasking; - struct FilterStorage + struct CollectorStorage { - OutputFilter *m_filter = nullptr; + ResultsCollector *m_collector = nullptr; }; - TreeStorage filterStorage; + TreeStorage collectorStorage; - const auto onFilterSetup = [this, filterCount = d->m_tasks.size(), filterStorage](OutputFilter &filter) { - filterStorage->m_filter = &filter; - filter.setFilterCount(filterCount); - connect(&filter, &OutputFilter::serialOutputDataReady, + const int filterCount = d->m_tasks.size(); + const auto onCollectorSetup = [this, filterCount, collectorStorage](ResultsCollector &collector) { + collectorStorage->m_collector = &collector; + collector.setFilterCount(filterCount); + connect(&collector, &ResultsCollector::serialOutputDataReady, this, [this](const LocatorFilterEntries &serialOutputData) { d->m_output += serialOutputData; emit serialOutputDataReady(serialOutputData); }); }; - const auto onFilterDone = [filterStorage](const OutputFilter &filter) { - Q_UNUSED(filter) - filterStorage->m_filter = nullptr; + const auto onCollectorDone = [collectorStorage](const ResultsCollector &collector) { + Q_UNUSED(collector) + collectorStorage->m_collector = nullptr; }; QList parallelTasks { ParallelLimit(d->m_parallelLimit) }; - const auto onGroupSetup = [this, filterStorage](const TreeStorage &storage, + const auto onGroupSetup = [this, collectorStorage](const TreeStorage &storage, int index) { - return [this, filterStorage, storage, index] { - OutputFilter *outputFilter = filterStorage->m_filter; - QTC_ASSERT(outputFilter, return); + return [this, collectorStorage, storage, index] { + ResultsCollector *collector = collectorStorage->m_collector; + QTC_ASSERT(collector, return); *storage = std::make_shared(d->m_input, index, - outputFilter->dataProvider()); + collector->deduplicator()); }; }; @@ -431,8 +479,8 @@ void LocatorMatcher::start() const Group root { parallel, - Storage(filterStorage), - Filter(onFilterSetup, onFilterDone, onFilterDone), + Storage(collectorStorage), + Collector(onCollectorSetup, onCollectorDone, onCollectorDone), Group { parallelTasks } From 16100acdc9654c588a813f397d00d55bcf30bdc8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 21 Apr 2023 10:19:53 +0200 Subject: [PATCH 0633/1447] JsonFieldPage: Fix collecting the results from all matchers Connect to LocatorMatcher::done() signal instead of to serialOutputDataReady() in order to get all the results available (not just 1st partial results). Give locator matcher a parent to avoid possible leak. Amends 1cc7342ef16cf904915355de9ee88c0250bca852 Change-Id: Ie4a73a5b2dd25f22616bd30a13eb7393c96a890f Reviewed-by: Christian Kandeler --- .../projectexplorer/jsonwizard/jsonfieldpage.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index 2837fe844c8..49a95711893 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -599,10 +599,14 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) using namespace Utils; if (m_completion == Completion::None) return; - const auto handleResults = [this, lineEdit](const LocatorFilterEntries &entries) { + LocatorMatcher *matcher = new LocatorMatcher; + matcher->setParent(lineEdit); + matcher->setTasks(LocatorMatcher::matchers(MatcherType::Classes)); + const auto handleResults = [lineEdit, matcher, completion = m_completion] { QSet namespaces; QStringList classes; Project * const project = ProjectTree::currentProject(); + const LocatorFilterEntries entries = matcher->outputData(); for (const LocatorFilterEntry &entry : entries) { static const auto isReservedName = [](const QString &name) { static const QRegularExpression rx1("^_[A-Z].*"); @@ -623,7 +627,7 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) if (hasNamespace) { if (isBaseClassCandidate) classes << (entry.extraInfo + "::" + entry.displayName); - if (m_completion == Completion::Namespaces) { + if (completion == Completion::Namespaces) { if (!project || entry.filePath.startsWith(project->projectDirectory().toString())) { namespaces << entry.extraInfo; @@ -632,7 +636,7 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) } } QStringList completionList; - if (m_completion == Completion::Namespaces) { + if (completion == Completion::Namespaces) { completionList = toList(namespaces); completionList = filtered(completionList, [&classes](const QString &ns) { return !classes.contains(ns); @@ -646,9 +650,7 @@ void LineEditField::setupCompletion(FancyLineEdit *lineEdit) completionList.sort(); lineEdit->setSpecialCompleter(new QCompleter(completionList, lineEdit)); }; - LocatorMatcher *matcher = new LocatorMatcher; - matcher->setTasks(LocatorMatcher::matchers(MatcherType::Classes)); - QObject::connect(matcher, &LocatorMatcher::serialOutputDataReady, lineEdit, handleResults); + QObject::connect(matcher, &LocatorMatcher::done, lineEdit, handleResults); QObject::connect(matcher, &LocatorMatcher::done, matcher, &QObject::deleteLater); matcher->start(); } From 977689b4a9a71c06af179c73cf0d508e13b758c5 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:58:51 +0200 Subject: [PATCH 0634/1447] QmlProfiler: Use IOptionPage::setWidgetCreator() for settings Change-Id: If9371820abf4e86e7041a7a5555c0a043de5ae3f Reviewed-by: Christian Stenger --- .../qmlprofiler/qmlprofilersettings.cpp | 56 ++++++++----------- src/plugins/qmlprofiler/qmlprofilersettings.h | 17 +----- 2 files changed, 26 insertions(+), 47 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.cpp b/src/plugins/qmlprofiler/qmlprofilersettings.cpp index 481a88ab323..f7f955c87bf 100644 --- a/src/plugins/qmlprofiler/qmlprofilersettings.cpp +++ b/src/plugins/qmlprofiler/qmlprofilersettings.cpp @@ -17,24 +17,32 @@ using namespace Utils; -namespace QmlProfiler { -namespace Internal { +namespace QmlProfiler::Internal { -static QWidget *createQmlConfigWidget(QmlProfilerSettings *settings) +class QmlProfilerOptionsPageWidget : public Core::IOptionsPageWidget { - QmlProfilerSettings &s = *settings; - using namespace Layouting; +public: + explicit QmlProfilerOptionsPageWidget(QmlProfilerSettings *settings) + { + QmlProfilerSettings &s = *settings; - return Form { - s.flushEnabled, - s.flushInterval, - s.aggregateTraces - }.emerge(); -} + using namespace Layouting; + Form { + s.flushEnabled, + s.flushInterval, + s.aggregateTraces + }.attachTo(this); + } + + void apply() final + { + QmlProfilerPlugin::globalSettings()->writeGlobalSettings(); + } +}; QmlProfilerSettings::QmlProfilerSettings() { - setConfigWidgetCreator([this] { return createQmlConfigWidget(this); }); + setConfigWidgetCreator([this] { return new QmlProfilerOptionsPageWidget(this); }); setSettingsGroup(Constants::ANALYZER); @@ -85,25 +93,9 @@ QmlProfilerOptionsPage::QmlProfilerOptionsPage() setCategory("T.Analyzer"); setDisplayCategory(::Debugger::Tr::tr("Analyzer")); setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); + setWidgetCreator([] { + return new QmlProfilerOptionsPageWidget(QmlProfilerPlugin::globalSettings()); + }); } -QWidget *QmlProfilerOptionsPage::widget() -{ - // We cannot parent the widget to the options page as it expects a QWidget as parent - if (!m_widget) - m_widget = createQmlConfigWidget(QmlProfilerPlugin::globalSettings()); - return m_widget; -} - -void QmlProfilerOptionsPage::apply() -{ - QmlProfilerPlugin::globalSettings()->writeGlobalSettings(); -} - -void QmlProfilerOptionsPage::finish() -{ - delete m_widget; -} - -} // Internal -} // QmlProfiler +} // QmlProfiler::Internal diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.h b/src/plugins/qmlprofiler/qmlprofilersettings.h index 3b4481cac88..14e35676215 100644 --- a/src/plugins/qmlprofiler/qmlprofilersettings.h +++ b/src/plugins/qmlprofiler/qmlprofilersettings.h @@ -7,15 +7,10 @@ #include -#include - -namespace QmlProfiler { -namespace Internal { +namespace QmlProfiler::Internal { class QmlProfilerSettings : public ProjectExplorer::ISettingsAspect { - Q_OBJECT - public: QmlProfilerSettings(); @@ -31,14 +26,6 @@ class QmlProfilerOptionsPage final : public Core::IOptionsPage { public: QmlProfilerOptionsPage(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - QPointer m_widget; }; -} // Internal -} // QmlProfiler +} // QmlProfiler::Internal From 55d51e8b5ea6d948ae356f10a1f8d820b047bbbe Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 19 Apr 2023 13:53:58 +0200 Subject: [PATCH 0635/1447] QmlJS: Improve QtQuick Controls completion Fixes: QTCREATORBUG-28648 Change-Id: I14c402c8a486d5afa7ee500b2d8a06951540e1bd Reviewed-by: Fabian Kosmale --- .../qt5QtQuick2-bundle.json | 23 +++++++++++++++++++ .../qt5QtQuick2ext-macos-bundle.json | 10 ++++++++ .../qt5QtQuick2ext-win-bundle.json | 9 ++++++++ .../qmljstools/qmljsbundleprovider.cpp | 15 ++++++++---- src/plugins/qmljstools/qmljsbundleprovider.h | 2 +- 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-macos-bundle.json create mode 100644 share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-win-bundle.json diff --git a/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json b/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json index 51bdff39b61..42222fd2dd3 100644 --- a/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json +++ b/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json @@ -199,6 +199,29 @@ "QtQuick.Controls.Styles 1.2", "QtQuick.Controls.Styles 1.3", "QtQuick.Controls.Styles 1.4", + "QtQuick.Controls.Basic 2.0", + "QtQuick.Controls.Basic 2.1", + "QtQuick.Controls.Basic 2.2", + "QtQuick.Controls.Basic 2.3", + "QtQuick.Controls.Basic 2.12", + "QtQuick.Controls.Basic 2.13", + "QtQuick.Controls.Basic 2.14", + "QtQuick.Controls.Basic 2.15", + "QtQuick.Controls.Fusion 2.0", + "QtQuick.Controls.Fusion 2.1", + "QtQuick.Controls.Fusion 2.2", + "QtQuick.Controls.Fusion 2.3", + "QtQuick.Controls.Fusion 2.12", + "QtQuick.Controls.Fusion 2.13", + "QtQuick.Controls.Fusion 2.14", + "QtQuick.Controls.Imagine 2.0", + "QtQuick.Controls.Imagine 2.1", + "QtQuick.Controls.Imagine 2.2", + "QtQuick.Controls.Imagine 2.3", + "QtQuick.Controls.Imagine 2.12", + "QtQuick.Controls.Imagine 2.13", + "QtQuick.Controls.Imagine 2.14", + "QtQuick.Controls.Imagine 2.15", "QtQuick.Dialogs 1.0", "QtQuick.Dialogs 1.1", "QtQuick.Dialogs 1.2", diff --git a/share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-macos-bundle.json b/share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-macos-bundle.json new file mode 100644 index 00000000000..5d34b4f2bf4 --- /dev/null +++ b/share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-macos-bundle.json @@ -0,0 +1,10 @@ +{ + "name": "QtQuickControlsMacOS", + "searchPaths": [], + "installPaths": [], + "implicitImports": [], + "supportedImports": [ + "QtQuick.Controls.macOS", + "QtQuick.Controls.iOS" + ] +} diff --git a/share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-win-bundle.json b/share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-win-bundle.json new file mode 100644 index 00000000000..2d908c5841a --- /dev/null +++ b/share/qtcreator/qml-type-descriptions/qt5QtQuick2ext-win-bundle.json @@ -0,0 +1,9 @@ +{ + "name": "QtQuickControlsWin", + "searchPaths": [], + "installPaths": [], + "implicitImports": [], + "supportedImports": [ + "QtQuick.Controls.Windows" + ] +} diff --git a/src/plugins/qmljstools/qmljsbundleprovider.cpp b/src/plugins/qmljstools/qmljsbundleprovider.cpp index b4902aa960c..f44070b75e4 100644 --- a/src/plugins/qmljstools/qmljsbundleprovider.cpp +++ b/src/plugins/qmljstools/qmljsbundleprovider.cpp @@ -45,9 +45,16 @@ QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName) return res; } -QmlBundle BasicBundleProvider::defaultQt5QtQuick2Bundle() +QmlBundle BasicBundleProvider::defaultQt5QtQuick2Bundle(bool enhance) { - return defaultBundle(QLatin1String("qt5QtQuick2-bundle.json")); + QmlBundle result = defaultBundle(QLatin1String("qt5QtQuick2-bundle.json")); + if (!enhance) + return result; + if (Utils::HostOsInfo::isMacHost()) + result.merge(defaultBundle(QLatin1String("qt5QtQuick2ext-macos-bundle.json"))); + if (Utils::HostOsInfo::isWindowsHost()) + result.merge(defaultBundle(QLatin1String("qt5QtQuick2ext-win-bundle.json"))); + return result; } QmlBundle BasicBundleProvider::defaultQbsBundle() @@ -77,7 +84,7 @@ void BasicBundleProvider::mergeBundlesForKit(ProjectExplorer::Kit *kit QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit); if (!qtVersion) { - QmlBundle b2(defaultQt5QtQuick2Bundle()); + QmlBundle b2(defaultQt5QtQuick2Bundle(false)); bundles.mergeBundleForLanguage(Dialect::Qml, b2); bundles.mergeBundleForLanguage(Dialect::QmlQtQuick2, b2); bundles.mergeBundleForLanguage(Dialect::QmlQtQuick2Ui, b2); @@ -100,7 +107,7 @@ void BasicBundleProvider::mergeBundlesForKit(ProjectExplorer::Kit *kit } if (!qtQuick2Bundle.supportedImports().contains(QLatin1String("QtQuick 2."), PersistentTrie::Partial)) { - qtQuick2Bundle.merge(defaultQt5QtQuick2Bundle()); + qtQuick2Bundle.merge(defaultQt5QtQuick2Bundle(qtVersion->qtVersion().majorVersion() >= 6)); } qtQuick2Bundle.replaceVars(myReplacements); bundles.mergeBundleForLanguage(Dialect::Qml, qtQuick2Bundle); diff --git a/src/plugins/qmljstools/qmljsbundleprovider.h b/src/plugins/qmljstools/qmljsbundleprovider.h index 1f7e6868d0c..392055b0329 100644 --- a/src/plugins/qmljstools/qmljsbundleprovider.h +++ b/src/plugins/qmljstools/qmljsbundleprovider.h @@ -44,7 +44,7 @@ public: const QHash &replacements) override; static QmlJS::QmlBundle defaultBundle(const QString &bundleInfoName); - static QmlJS::QmlBundle defaultQt5QtQuick2Bundle(); + static QmlJS::QmlBundle defaultQt5QtQuick2Bundle(bool enhance); static QmlJS::QmlBundle defaultQbsBundle(); static QmlJS::QmlBundle defaultQmltypesBundle(); static QmlJS::QmlBundle defaultQmlprojectBundle(); From 498bad56b23c7ee0686a409a0afd972fa7b7eccd Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:56:28 +0200 Subject: [PATCH 0636/1447] Qbs: Use IOptionPage::setWidgetCreator() for settings Change-Id: Idae8c17a8922b60ad9dee3595176d11e0b96fee8 Reviewed-by: Christian Stenger --- .../qbsprofilessettingspage.cpp | 28 ++++------------ .../qbsprofilessettingspage.h | 14 ++------ src/plugins/qbsprojectmanager/qbssettings.cpp | 32 ++++--------------- src/plugins/qbsprojectmanager/qbssettings.h | 23 ++++--------- 4 files changed, 20 insertions(+), 77 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp index 64c73ed5f0e..4062f6bb705 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp @@ -26,8 +26,7 @@ using namespace ProjectExplorer; -namespace QbsProjectManager { -namespace Internal { +namespace QbsProjectManager::Internal { class ProfileTreeItem : public Utils::TypedTreeItem { @@ -53,7 +52,6 @@ private: class ProfileModel : public Utils::TreeModel { - Q_OBJECT public: ProfileModel() : TreeModel(static_cast(nullptr)) { @@ -91,13 +89,14 @@ public: } }; -class QbsProfilesSettingsWidget : public QWidget +class QbsProfilesSettingsWidget : public Core::IOptionsPageWidget { - Q_OBJECT public: QbsProfilesSettingsWidget(); private: + void apply() final {} + void refreshKitsList(); void displayCurrentProfile(); @@ -112,19 +111,7 @@ QbsProfilesSettingsPage::QbsProfilesSettingsPage() setId("Y.QbsProfiles"); setDisplayName(Tr::tr("Profiles")); setCategory(Constants::QBS_SETTINGS_CATEGORY); -} - -QWidget *QbsProfilesSettingsPage::widget() -{ - if (!m_widget) - m_widget = new QbsProfilesSettingsWidget; - return m_widget; -} - -void QbsProfilesSettingsPage::finish() -{ - delete m_widget; - m_widget = nullptr; + setWidgetCreator([] { return new QbsProfilesSettingsWidget; }); } QbsProfilesSettingsWidget::QbsProfilesSettingsWidget() @@ -211,7 +198,4 @@ void QbsProfilesSettingsWidget::displayCurrentProfile() } } -} // namespace Internal -} // namespace QbsProjectManager - -#include "qbsprofilessettingspage.moc" +} // QbsProjectManager::Internal diff --git a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.h b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.h index 4ffab9bce9f..db63e323549 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.h +++ b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.h @@ -5,22 +5,12 @@ #include -namespace QbsProjectManager { -namespace Internal { -class QbsProfilesSettingsWidget; +namespace QbsProjectManager::Internal { class QbsProfilesSettingsPage : public Core::IOptionsPage { public: QbsProfilesSettingsPage(); - -private: - QWidget *widget() override; - void apply() override { } - void finish() override; - - QbsProfilesSettingsWidget *m_widget = nullptr; }; -} // namespace Internal -} // namespace QbsProjectManager +} // QbsProjectManager::Internal diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp index 78eac2b308c..2168d56d9e5 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.cpp +++ b/src/plugins/qbsprojectmanager/qbssettings.cpp @@ -21,8 +21,7 @@ using namespace Utils; -namespace QbsProjectManager { -namespace Internal { +namespace QbsProjectManager::Internal { const char QBS_EXE_KEY[] = "QbsProjectManager/QbsExecutable"; const char QBS_DEFAULT_INSTALL_DIR_KEY[] = "QbsProjectManager/DefaultInstallDir"; @@ -142,10 +141,10 @@ void QbsSettings::storeSettings() const s->setValue(USE_CREATOR_SETTINGS_KEY, m_settings.useCreatorSettings); } -class QbsSettingsPage::SettingsWidget : public QWidget +class QbsSettingsPageWidget : public Core::IOptionsPageWidget { public: - SettingsWidget() + QbsSettingsPageWidget() { m_qbsExePathChooser.setExpectedKind(PathChooser::ExistingCommand); m_qbsExePathChooser.setFilePath(QbsSettings::qbsExecutableFilePath()); @@ -166,7 +165,7 @@ public: }); } - void apply() + void apply() final { QbsSettingsData settings = QbsSettings::rawSettingsData(); if (m_qbsExePathChooser.filePath() != QbsSettings::qbsExecutableFilePath()) @@ -197,26 +196,7 @@ QbsSettingsPage::QbsSettingsPage() setCategory(Constants::QBS_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr(Constants::QBS_SETTINGS_TR_CATEGORY)); setCategoryIconPath(":/qbsprojectmanager/images/settingscategory_qbsprojectmanager.png"); + setWidgetCreator([] { return new QbsSettingsPageWidget; }); } -QWidget *QbsSettingsPage::widget() -{ - if (!m_widget) - m_widget = new SettingsWidget; - return m_widget; - -} - -void QbsSettingsPage::apply() -{ - if (m_widget) - m_widget->apply(); -} - -void QbsSettingsPage::finish() -{ - delete m_widget; -} - -} // namespace Internal -} // namespace QbsProjectManager +} // QbsProjectManager::Internal diff --git a/src/plugins/qbsprojectmanager/qbssettings.h b/src/plugins/qbsprojectmanager/qbssettings.h index 8b30e4b247e..a91a9059653 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.h +++ b/src/plugins/qbsprojectmanager/qbssettings.h @@ -4,16 +4,15 @@ #pragma once #include -#include -#include -#include +#include + #include -namespace QbsProjectManager { -namespace Internal { +namespace QbsProjectManager::Internal { -class QbsSettingsData { +class QbsSettingsData +{ public: Utils::FilePath qbsExecutableFilePath; QString defaultInstallDirTemplate; @@ -51,18 +50,8 @@ private: class QbsSettingsPage : public Core::IOptionsPage { - Q_OBJECT public: QbsSettingsPage(); - -private: - QWidget *widget() override; - void apply() override; - void finish() override; - - class SettingsWidget; - QPointer m_widget; }; -} // namespace Internal -} // namespace QbsProjectManager +} // QbsProjectManager::Internal From 4acffc7cce80eea3561f0d4cb8b41243efd9b2ef Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:57:15 +0200 Subject: [PATCH 0637/1447] TextEditor: Use IOptionPage::setWidgetCreator() for snippets settings Change-Id: I9aa91edef20f325f1a2fc93388aecb5776b970d6 Reviewed-by: David Schulz --- .../snippets/snippetscollection.cpp | 4 +- .../snippets/snippetssettingspage.cpp | 200 +++++++----------- .../snippets/snippetssettingspage.h | 16 +- 3 files changed, 83 insertions(+), 137 deletions(-) diff --git a/src/plugins/texteditor/snippets/snippetscollection.cpp b/src/plugins/texteditor/snippets/snippetscollection.cpp index be658c14777..f799b3fe424 100644 --- a/src/plugins/texteditor/snippets/snippetscollection.cpp +++ b/src/plugins/texteditor/snippets/snippetscollection.cpp @@ -78,9 +78,7 @@ SnippetsCollection::SnippetsCollection() m_builtInSnippetsFiles(Core::ICore::resourcePath("snippets") .dirEntries(FileFilter({"*.xml"}))) { - - connect(Core::ICore::instance(), &Core::ICore::coreOpened, - this, &SnippetsCollection::identifyGroups); + identifyGroups(); } SnippetsCollection::~SnippetsCollection() = default; diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.cpp b/src/plugins/texteditor/snippets/snippetssettingspage.cpp index b64910a0f1d..a9a337a70f3 100644 --- a/src/plugins/texteditor/snippets/snippetssettingspage.cpp +++ b/src/plugins/texteditor/snippets/snippetssettingspage.cpp @@ -35,15 +35,14 @@ #include #include -namespace TextEditor { -namespace Internal { +namespace TextEditor::Internal { // SnippetsTableModel + class SnippetsTableModel : public QAbstractTableModel { - Q_OBJECT public: - SnippetsTableModel(QObject *parent); + SnippetsTableModel(); ~SnippetsTableModel() override = default; int rowCount(const QModelIndex &parent = QModelIndex()) const override; @@ -74,9 +73,8 @@ private: QString m_activeGroupId; }; -SnippetsTableModel::SnippetsTableModel(QObject *parent) : - QAbstractTableModel(parent), - m_collection(SnippetsCollection::instance()) +SnippetsTableModel::SnippetsTableModel() + : m_collection(SnippetsCollection::instance()) {} int SnippetsTableModel::rowCount(const QModelIndex &) const @@ -244,19 +242,15 @@ void SnippetsTableModel::replaceSnippet(const Snippet &snippet, const QModelInde } } -// SnippetsSettingsPagePrivate -class SnippetsSettingsPagePrivate : public QObject +// SnippetsSettingsWidget + +class SnippetsSettingsWidget : public Core::IOptionsPageWidget { public: - SnippetsSettingsPagePrivate(); - ~SnippetsSettingsPagePrivate() override { delete m_model; } + SnippetsSettingsWidget(); - void configureUi(QWidget *parent); - - void apply(); - void finish(); - - QPointer m_widget; + void apply() final; + void finish() final; private: void loadSnippetGroup(int index); @@ -279,9 +273,9 @@ private: bool settingsChanged() const; void writeSettings(); - const QString m_settingsPrefix; - SnippetsTableModel *m_model; - bool m_snippetsCollectionChanged; + const QString m_settingsPrefix{QLatin1String("Text")}; + SnippetsTableModel m_model; + bool m_snippetsCollectionChanged = false; SnippetsSettings m_settings; QStackedWidget *m_snippetsEditorStack; @@ -290,38 +284,22 @@ private: QPushButton *m_revertButton; }; -SnippetsSettingsPagePrivate::SnippetsSettingsPagePrivate() : - m_settingsPrefix(QLatin1String("Text")), - m_model(new SnippetsTableModel(nullptr)), - m_snippetsCollectionChanged(false) -{} - -SnippetEditorWidget *SnippetsSettingsPagePrivate::currentEditor() const -{ - return editorAt(m_snippetsEditorStack->currentIndex()); -} - -SnippetEditorWidget *SnippetsSettingsPagePrivate::editorAt(int i) const -{ - return static_cast(m_snippetsEditorStack->widget(i)); -} - -void SnippetsSettingsPagePrivate::configureUi(QWidget *w) +SnippetsSettingsWidget::SnippetsSettingsWidget() { m_groupCombo = new QComboBox; m_snippetsEditorStack = new QStackedWidget; for (const SnippetProvider &provider : SnippetProvider::snippetProviders()) { m_groupCombo->addItem(provider.displayName(), provider.groupId()); - auto snippetEditor = new SnippetEditorWidget(w); + auto snippetEditor = new SnippetEditorWidget(this); SnippetProvider::decorateEditor(snippetEditor, provider.groupId()); m_snippetsEditorStack->insertWidget(m_groupCombo->count() - 1, snippetEditor); connect(snippetEditor, &SnippetEditorWidget::snippetContentChanged, - this, &SnippetsSettingsPagePrivate::setSnippetContent); + this, &SnippetsSettingsWidget::setSnippetContent); } m_snippetsTable = new Utils::TreeView; m_snippetsTable->setRootIsDecorated(false); - m_snippetsTable->setModel(m_model); + m_snippetsTable->setModel(&m_model); m_revertButton = new QPushButton(Tr::tr("Revert Built-in")); m_revertButton->setEnabled(false); @@ -350,40 +328,50 @@ void SnippetsSettingsPagePrivate::configureUi(QWidget *w) st, } } - }.attachTo(w); + }.attachTo(this); loadSettings(); loadSnippetGroup(m_groupCombo->currentIndex()); - connect(m_model, &QAbstractItemModel::rowsInserted, - this, &SnippetsSettingsPagePrivate::selectSnippet); - connect(m_model, &QAbstractItemModel::rowsInserted, - this, &SnippetsSettingsPagePrivate::markSnippetsCollection); - connect(m_model, &QAbstractItemModel::rowsRemoved, - this, &SnippetsSettingsPagePrivate::markSnippetsCollection); - connect(m_model, &QAbstractItemModel::rowsMoved, - this, &SnippetsSettingsPagePrivate::selectMovedSnippet); - connect(m_model, &QAbstractItemModel::rowsMoved, - this, &SnippetsSettingsPagePrivate::markSnippetsCollection); - connect(m_model, &QAbstractItemModel::dataChanged, - this, &SnippetsSettingsPagePrivate::markSnippetsCollection); - connect(m_model, &QAbstractItemModel::modelReset, + connect(&m_model, &QAbstractItemModel::rowsInserted, + this, &SnippetsSettingsWidget::selectSnippet); + connect(&m_model, &QAbstractItemModel::rowsInserted, + this, &SnippetsSettingsWidget::markSnippetsCollection); + connect(&m_model, &QAbstractItemModel::rowsRemoved, + this, &SnippetsSettingsWidget::markSnippetsCollection); + connect(&m_model, &QAbstractItemModel::rowsMoved, + this, &SnippetsSettingsWidget::selectMovedSnippet); + connect(&m_model, &QAbstractItemModel::rowsMoved, + this, &SnippetsSettingsWidget::markSnippetsCollection); + connect(&m_model, &QAbstractItemModel::dataChanged, + this, &SnippetsSettingsWidget::markSnippetsCollection); + connect(&m_model, &QAbstractItemModel::modelReset, this, [this] { this->updateCurrentSnippetDependent(); }); - connect(m_model, &QAbstractItemModel::modelReset, - this, &SnippetsSettingsPagePrivate::markSnippetsCollection); + connect(&m_model, &QAbstractItemModel::modelReset, + this, &SnippetsSettingsWidget::markSnippetsCollection); connect(m_groupCombo, &QComboBox::currentIndexChanged, - this, &SnippetsSettingsPagePrivate::loadSnippetGroup); + this, &SnippetsSettingsWidget::loadSnippetGroup); connect(m_revertButton, &QAbstractButton::clicked, - this, &SnippetsSettingsPagePrivate::revertBuiltInSnippet); + this, &SnippetsSettingsWidget::revertBuiltInSnippet); connect(m_snippetsTable->selectionModel(), &QItemSelectionModel::currentChanged, - this, &SnippetsSettingsPagePrivate::updateCurrentSnippetDependent); + this, &SnippetsSettingsWidget::updateCurrentSnippetDependent); connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, - this, &SnippetsSettingsPagePrivate::decorateEditors); + this, &SnippetsSettingsWidget::decorateEditors); } -void SnippetsSettingsPagePrivate::apply() +SnippetEditorWidget *SnippetsSettingsWidget::currentEditor() const +{ + return editorAt(m_snippetsEditorStack->currentIndex()); +} + +SnippetEditorWidget *SnippetsSettingsWidget::editorAt(int i) const +{ + return static_cast(m_snippetsEditorStack->widget(i)); +} + +void SnippetsSettingsWidget::apply() { if (settingsChanged()) writeSettings(); @@ -402,7 +390,7 @@ void SnippetsSettingsPagePrivate::apply() } } -void SnippetsSettingsPagePrivate::finish() +void SnippetsSettingsWidget::finish() { if (m_snippetsCollectionChanged) { SnippetsCollection::instance()->reload(); @@ -412,7 +400,7 @@ void SnippetsSettingsPagePrivate::finish() disconnect(TextEditorSettings::instance(), nullptr, this, nullptr); } -void SnippetsSettingsPagePrivate::loadSettings() +void SnippetsSettingsWidget::loadSettings() { if (m_groupCombo->count() == 0) return; @@ -426,7 +414,7 @@ void SnippetsSettingsPagePrivate::loadSettings() m_groupCombo->setCurrentIndex(0); } -void SnippetsSettingsPagePrivate::writeSettings() +void SnippetsSettingsWidget::writeSettings() { if (m_groupCombo->count() == 0) return; @@ -435,72 +423,72 @@ void SnippetsSettingsPagePrivate::writeSettings() m_settings.toSettings(m_settingsPrefix, Core::ICore::settings()); } -bool SnippetsSettingsPagePrivate::settingsChanged() const +bool SnippetsSettingsWidget::settingsChanged() const { if (m_settings.lastUsedSnippetGroup() != m_groupCombo->currentText()) return true; return false; } -void SnippetsSettingsPagePrivate::loadSnippetGroup(int index) +void SnippetsSettingsWidget::loadSnippetGroup(int index) { if (index == -1) return; m_snippetsEditorStack->setCurrentIndex(index); currentEditor()->clear(); - m_model->load(m_groupCombo->itemData(index).toString()); + m_model.load(m_groupCombo->itemData(index).toString()); } -void SnippetsSettingsPagePrivate::markSnippetsCollection() +void SnippetsSettingsWidget::markSnippetsCollection() { if (!m_snippetsCollectionChanged) m_snippetsCollectionChanged = true; } -void SnippetsSettingsPagePrivate::addSnippet() +void SnippetsSettingsWidget::addSnippet() { - const QModelIndex &modelIndex = m_model->createSnippet(); + const QModelIndex &modelIndex = m_model.createSnippet(); selectSnippet(QModelIndex(), modelIndex.row()); m_snippetsTable->edit(modelIndex); } -void SnippetsSettingsPagePrivate::removeSnippet() +void SnippetsSettingsWidget::removeSnippet() { const QModelIndex &modelIndex = m_snippetsTable->selectionModel()->currentIndex(); if (!modelIndex.isValid()) { QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Error"), Tr::tr("No snippet selected.")); return; } - m_model->removeSnippet(modelIndex); + m_model.removeSnippet(modelIndex); } -void SnippetsSettingsPagePrivate::restoreRemovedBuiltInSnippets() +void SnippetsSettingsWidget::restoreRemovedBuiltInSnippets() { - m_model->restoreRemovedBuiltInSnippets(); + m_model.restoreRemovedBuiltInSnippets(); } -void SnippetsSettingsPagePrivate::revertBuiltInSnippet() +void SnippetsSettingsWidget::revertBuiltInSnippet() { - m_model->revertBuitInSnippet(m_snippetsTable->selectionModel()->currentIndex()); + m_model.revertBuitInSnippet(m_snippetsTable->selectionModel()->currentIndex()); } -void SnippetsSettingsPagePrivate::resetAllSnippets() +void SnippetsSettingsWidget::resetAllSnippets() { - m_model->resetSnippets(); + m_model.resetSnippets(); } -void SnippetsSettingsPagePrivate::selectSnippet(const QModelIndex &parent, int row) +void SnippetsSettingsWidget::selectSnippet(const QModelIndex &parent, int row) { - QModelIndex topLeft = m_model->index(row, 0, parent); - QModelIndex bottomRight = m_model->index(row, 1, parent); + QModelIndex topLeft = m_model.index(row, 0, parent); + QModelIndex bottomRight = m_model.index(row, 1, parent); QItemSelection selection(topLeft, bottomRight); m_snippetsTable->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); m_snippetsTable->setCurrentIndex(topLeft); m_snippetsTable->scrollTo(topLeft); } -void SnippetsSettingsPagePrivate::selectMovedSnippet(const QModelIndex &, +void SnippetsSettingsWidget::selectMovedSnippet(const QModelIndex &, int sourceRow, int, const QModelIndex &destinationParent, @@ -508,17 +496,17 @@ void SnippetsSettingsPagePrivate::selectMovedSnippet(const QModelIndex &, { QModelIndex modelIndex; if (sourceRow < destinationRow) - modelIndex = m_model->index(destinationRow - 1, 0, destinationParent); + modelIndex = m_model.index(destinationRow - 1, 0, destinationParent); else - modelIndex = m_model->index(destinationRow, 0, destinationParent); + modelIndex = m_model.index(destinationRow, 0, destinationParent); m_snippetsTable->scrollTo(modelIndex); - currentEditor()->setPlainText(m_model->snippetAt(modelIndex).content()); + currentEditor()->setPlainText(m_model.snippetAt(modelIndex).content()); } -void SnippetsSettingsPagePrivate::updateCurrentSnippetDependent(const QModelIndex &modelIndex) +void SnippetsSettingsWidget::updateCurrentSnippetDependent(const QModelIndex &modelIndex) { if (modelIndex.isValid()) { - const Snippet &snippet = m_model->snippetAt(modelIndex); + const Snippet &snippet = m_model.snippetAt(modelIndex); currentEditor()->setPlainText(snippet.content()); m_revertButton->setEnabled(snippet.isBuiltIn()); } else { @@ -527,16 +515,16 @@ void SnippetsSettingsPagePrivate::updateCurrentSnippetDependent(const QModelInde } } -void SnippetsSettingsPagePrivate::setSnippetContent() +void SnippetsSettingsWidget::setSnippetContent() { const QModelIndex &modelIndex = m_snippetsTable->selectionModel()->currentIndex(); if (modelIndex.isValid()) { - m_model->setSnippetContent(modelIndex, currentEditor()->toPlainText()); + m_model.setSnippetContent(modelIndex, currentEditor()->toPlainText()); markSnippetsCollection(); } } -void SnippetsSettingsPagePrivate::decorateEditors(const TextEditor::FontSettings &fontSettings) +void SnippetsSettingsWidget::decorateEditors(const TextEditor::FontSettings &fontSettings) { for (int i = 0; i < m_groupCombo->count(); ++i) { SnippetEditorWidget *snippetEditor = editorAt(i); @@ -550,41 +538,13 @@ void SnippetsSettingsPagePrivate::decorateEditors(const TextEditor::FontSettings // SnippetsSettingsPage SnippetsSettingsPage::SnippetsSettingsPage() - : d(new SnippetsSettingsPagePrivate) { setId(Constants::TEXT_EDITOR_SNIPPETS_SETTINGS); setDisplayName(Tr::tr("Snippets")); setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr("Text Editor")); setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); + setWidgetCreator([] { return new SnippetsSettingsWidget; }); } -SnippetsSettingsPage::~SnippetsSettingsPage() -{ - delete d; -} - -QWidget *SnippetsSettingsPage::widget() -{ - if (!d->m_widget) { - d->m_widget = new QWidget; - d->configureUi(d->m_widget); - } - return d->m_widget; -} - -void SnippetsSettingsPage::apply() -{ - d->apply(); -} - -void SnippetsSettingsPage::finish() -{ - d->finish(); - delete d->m_widget; -} - -} // Internal -} // TextEditor - -#include "snippetssettingspage.moc" +} // TextEditor::Internal diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.h b/src/plugins/texteditor/snippets/snippetssettingspage.h index f7c4b8c3ebb..31216d3d304 100644 --- a/src/plugins/texteditor/snippets/snippetssettingspage.h +++ b/src/plugins/texteditor/snippets/snippetssettingspage.h @@ -5,24 +5,12 @@ #include -namespace TextEditor { -namespace Internal { - -class SnippetsSettingsPagePrivate; +namespace TextEditor::Internal { class SnippetsSettingsPage final : public Core::IOptionsPage { public: SnippetsSettingsPage(); - ~SnippetsSettingsPage() override; - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - SnippetsSettingsPagePrivate *d; }; -} // Internal -} // TextEditor +} // TextEditor::Internal From 54177ebccd36d2548dd15e1d81c5f9844f6de278 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Apr 2023 11:27:38 +0200 Subject: [PATCH 0638/1447] Locator: Fix opening of remote files Opening remote files can pop up a ssh prompt, and before that happens we need to hide the locator popup, which otherwise can stay on front of that ssh prompt window, preventing the user from entering their password and opening the file. Otherwise for example modal error dialogs could also be shown. So, delay the EditorManager::open call to after the popup is hidden. Amends 07b1e1c5fe03806f7c8d78e1ae72ebd38a1b9849 and 7f49d93fc1a1b90c7cda44ea0c31c8a7798fb1d3 Change-Id: If2dd9e745d5d98615b851ee4315e7de9a75afb00 Reviewed-by: Jarek Kobus --- src/plugins/coreplugin/locator/locatorwidget.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index cd98f8e5dd1..97ffcd8d4ba 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -1016,10 +1016,17 @@ void LocatorWidget::acceptEntry(int row) const QModelIndex index = m_locatorModel->index(row, 0); if (!index.isValid()) return; - const LocatorFilterEntry entry = m_locatorModel->data(index, LocatorEntryRole).value(); + const LocatorFilterEntry entry + = m_locatorModel->data(index, LocatorEntryRole).value(); + if (!entry.acceptor) { + // Opening editors can open dialogs (e.g. the ssh prompt, or showing erros), so delay until + // we have hidden the popup with emit hidePopup below and Qt actually processed that + QMetaObject::invokeMethod( + EditorManager::instance(), + [entry] { EditorManager::openEditor(entry); }, + Qt::QueuedConnection); + } QWidget *focusBeforeAccept = QApplication::focusWidget(); - if (!entry.acceptor) - EditorManager::openEditor(entry); const AcceptResult result = entry.acceptor ? entry.acceptor() : AcceptResult(); if (result.newText.isEmpty()) { emit hidePopup(); From 30bd12d8dc668631ab21831ac32588a5a304f533 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Apr 2023 12:02:16 +0200 Subject: [PATCH 0639/1447] Build: Add SOURCES_PROPERTIES to extend_qtc_target This way the check if the target is enabled and the condition is met doesn't have to be done manually. Change-Id: If490a84fd5f1ede2d032c3800f69ede4f755bc2c Reviewed-by: Marco Bubke --- cmake/QtCreatorAPIInternal.cmake | 6 +++++- src/plugins/projectexplorer/CMakeLists.txt | 15 ++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index 479a6fb179b..bbb4db462e7 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -465,7 +465,7 @@ function(extend_qtc_target target_name) cmake_parse_arguments(_arg "" "SOURCES_PREFIX;SOURCES_PREFIX_FROM_TARGET;FEATURE_INFO" - "CONDITION;DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS;PROPERTIES" + "CONDITION;DEPENDS;PUBLIC_DEPENDS;DEFINES;PUBLIC_DEFINES;INCLUDES;PUBLIC_INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;EXTRA_TRANSLATIONS;PROPERTIES;SOURCES_PROPERTIES" ${ARGN} ) @@ -547,4 +547,8 @@ function(extend_qtc_target target_name) if (_arg_PROPERTIES) set_target_properties(${target_name} PROPERTIES ${_arg_PROPERTIES}) endif() + + if (_arg_SOURCES_PROPERTIES) + set_source_files_properties(${_arg_SOURCES} PROPERTIES ${_arg_SOURCES_PROPERTIES}) + endif() endfunction() diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index e2bf33309ef..1ed25adadac 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -216,9 +216,14 @@ extend_qtc_plugin(ProjectExplorer extend_qtc_plugin(ProjectExplorer CONDITION WITH_TESTS SOURCES - jsonwizard/jsonwizard_test.cpp outputparser_test.cpp outputparser_test.h ) +extend_qtc_plugin(ProjectExplorer + CONDITION WITH_TESTS + SOURCES + jsonwizard/jsonwizard_test.cpp + SOURCES_PROPERTIES HEADER_FILE_ONLY ON +) file(GLOB_RECURSE test_resources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} testdata/*) qtc_add_resources(ProjectExplorer "testdata" @@ -227,11 +232,3 @@ qtc_add_resources(ProjectExplorer "testdata" BASE "." FILES ${test_resources} ) - -qtc_plugin_enabled(_projectexplorer_enabled ProjectExplorer) -if (WITH_TESTS AND _projectexplorer_enabled) - set_source_files_properties(jsonwizard/jsonwizard_test.cpp - PROPERTIES HEADER_FILE_ONLY ON - ) -endif() - From e7e063fda50a737220ed75d856efe0f85efe7520 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 21 Apr 2023 10:33:12 +0200 Subject: [PATCH 0640/1447] Debugger: Add automatic source path mapping for Qt Packages Change-Id: Iae2a02fc134ac05a30241d7a69302294137d3844 Reviewed-by: Christian Stenger --- src/plugins/debugger/cdb/cdbengine.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 0bda7399ec3..0f316faa764 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -224,7 +225,8 @@ void CdbEngine::init() } } - const SourcePathMap &sourcePathMap = debuggerSettings()->sourcePathMap.value(); + const SourcePathMap &sourcePathMap + = mergePlatformQtPath(runParameters(), debuggerSettings()->sourcePathMap.value()); if (!sourcePathMap.isEmpty()) { for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) { m_sourcePathMappings.push_back({QDir::toNativeSeparators(it.key()), From 60f6ff5147034b92ebcc2e3f1ccb0b65ecdb5881 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 21 Apr 2023 11:30:35 +0200 Subject: [PATCH 0641/1447] Doc: Replace Manual front page icons with Qt Creator icons To create connections between the UI and the different chapters of the manual. Remove the SVG source files for the old front page icons. Task-number: QTCREATORBUG-28996 Change-Id: I9bd977df1005a4f8d6d60b438a66ec02ebb2bfb3 Reviewed-by: Eike Ziller --- doc/qtcreator/images/creator_advanceduse.svg | 27 ----------- .../images/creator_buildingrunning.svg | 39 --------------- doc/qtcreator/images/creator_coding.svg | 37 -------------- .../images/creator_designinguserinterface.svg | 45 ------------------ doc/qtcreator/images/creator_gettinghelp.svg | 16 ------- .../images/creator_gettingstarted.svg | 22 --------- .../images/creator_managingprojects.svg | 26 ---------- doc/qtcreator/images/creator_publishing.svg | 40 ---------------- doc/qtcreator/images/creator_testing.svg | 34 ------------- doc/qtcreator/images/front-advanced.png | Bin 4873 -> 355 bytes doc/qtcreator/images/front-coding.png | Bin 6045 -> 125 bytes doc/qtcreator/images/front-gs.png | Bin 5150 -> 2940 bytes doc/qtcreator/images/front-help.png | Bin 1937 -> 1032 bytes doc/qtcreator/images/front-preview.png | Bin 4789 -> 430 bytes doc/qtcreator/images/front-projects.png | Bin 2712 -> 676 bytes doc/qtcreator/images/front-publishing.png | Bin 5101 -> 715 bytes doc/qtcreator/images/front-testing.png | Bin 2480 -> 905 bytes doc/qtcreator/images/front-ui.png | Bin 3491 -> 448 bytes 18 files changed, 286 deletions(-) delete mode 100644 doc/qtcreator/images/creator_advanceduse.svg delete mode 100644 doc/qtcreator/images/creator_buildingrunning.svg delete mode 100644 doc/qtcreator/images/creator_coding.svg delete mode 100644 doc/qtcreator/images/creator_designinguserinterface.svg delete mode 100644 doc/qtcreator/images/creator_gettinghelp.svg delete mode 100644 doc/qtcreator/images/creator_gettingstarted.svg delete mode 100644 doc/qtcreator/images/creator_managingprojects.svg delete mode 100644 doc/qtcreator/images/creator_publishing.svg delete mode 100644 doc/qtcreator/images/creator_testing.svg diff --git a/doc/qtcreator/images/creator_advanceduse.svg b/doc/qtcreator/images/creator_advanceduse.svg deleted file mode 100644 index 7a7b77186b4..00000000000 --- a/doc/qtcreator/images/creator_advanceduse.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - diff --git a/doc/qtcreator/images/creator_buildingrunning.svg b/doc/qtcreator/images/creator_buildingrunning.svg deleted file mode 100644 index 3d4808cdb58..00000000000 --- a/doc/qtcreator/images/creator_buildingrunning.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - 1 - 2 - 3 - - - - - - - - - - - - 1 - 2 - 3 - - - diff --git a/doc/qtcreator/images/creator_coding.svg b/doc/qtcreator/images/creator_coding.svg deleted file mode 100644 index 39149cdf397..00000000000 --- a/doc/qtcreator/images/creator_coding.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -// main.cpp -#include <QApplication> -#include <QTableView> -#include "mymodel.h" -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - QTableView tableView; - MyModel myModel; -} - diff --git a/doc/qtcreator/images/creator_designinguserinterface.svg b/doc/qtcreator/images/creator_designinguserinterface.svg deleted file mode 100644 index b3aff292403..00000000000 --- a/doc/qtcreator/images/creator_designinguserinterface.svg +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - -1 -2 -3 - - - ON - - - - - - - - - - - - - - diff --git a/doc/qtcreator/images/creator_gettinghelp.svg b/doc/qtcreator/images/creator_gettinghelp.svg deleted file mode 100644 index 6663ed53eb9..00000000000 --- a/doc/qtcreator/images/creator_gettinghelp.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - -? - diff --git a/doc/qtcreator/images/creator_gettingstarted.svg b/doc/qtcreator/images/creator_gettingstarted.svg deleted file mode 100644 index 779ae13947f..00000000000 --- a/doc/qtcreator/images/creator_gettingstarted.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/doc/qtcreator/images/creator_managingprojects.svg b/doc/qtcreator/images/creator_managingprojects.svg deleted file mode 100644 index fb934268a09..00000000000 --- a/doc/qtcreator/images/creator_managingprojects.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - -C++ -qml - - - - - diff --git a/doc/qtcreator/images/creator_publishing.svg b/doc/qtcreator/images/creator_publishing.svg deleted file mode 100644 index 4954f8930c2..00000000000 --- a/doc/qtcreator/images/creator_publishing.svg +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - 2 - 3 - - - diff --git a/doc/qtcreator/images/creator_testing.svg b/doc/qtcreator/images/creator_testing.svg deleted file mode 100644 index 14e75f3489f..00000000000 --- a/doc/qtcreator/images/creator_testing.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/doc/qtcreator/images/front-advanced.png b/doc/qtcreator/images/front-advanced.png index 87780aa3863bd3f1d8fff9778e0d66d4fe686801..99422ed74f00acad801723a8a4d67ed462cc19d4 100644 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0y~yU~mCp4rT@h2L7|j4Gatn$pJngt_%ze{}~u2O`6ou z(6B#C^hB=E{sMu+nf!-xC0bfqj%5h%&lPHJZa$nXvOi1oNUmsGTU$qSV|#o1!EE6} z*~0DZ?T4~O4rPmiNf8Ly1_JGEZ6I_gTjWw~h(7}ZgJMaLUoZnBI~Nb1fS{c-7GcYpo#nLxRkN@ABsJf$3hIko81l$ws3 zgHIGgSMJdAzPWDJrzJwxPb;+Ks?9Q80v~B5WiHr$Whd`~-50-`Nhv5!tUVv-=rDhu z^z0uW?>xOz+}r>EU%s-B>Q5Dwp!yR_eP1u#o^r|~aI4AMMOKl=nzni7YrpOmTPb#J zx^|-D?V_W)YxKYJOwXCUN5hkC=Bgv-4dVk>KG(aLK6~k}Nol1^_cs@JE|))h=-3LW zBLO-&(#{jtzOZw2ls|Lmmju_;ti)QLqkmhO4ka0g6kD}9g|_JhC|sVJq#@DOWK`0` zlxZNr1rp5*NZ?{~J{Yj#)CEBc9K^%w92hX&B=_qAhqAD)g$Wv5 zuO=;9t0v;Xb{{5Hy3m0Kq*>&Os&90zM!*xHO+n2PT$z$QtxrDjISa0gaSF>4a8}f9 zUN|AD2Ln>R@U+$i zD5M)oboIV zoG|TRfQR0DOOXkF*NsGYj!w#*Z2tP66XVS_A%U4Zt&1$$76k<;L_N_y8sKp{K|^J_ zXcLphr>QXOyBr;pj75T4xAcTAFqk8dX4??SotWR>c;U#0*Bti_~Fj(4^@7U@;iL+#S*^vr_ODgxX>fSyoE{902IL7^IHWE-IPC&^W&z{B91_Tg9g2v zDx0jB5^euvOD}%h#?qyI!0T^Z6UXC!5@qHNk7cFbeU{qeJ$s?Y>O4j+6+K0s)-^pw z=aq_nb)1>_YiG;Eij^(zBBkYK-G6_$WDwi+d-T zDfV2jF?nDTEivbk_`LDfJJlgyR{@gg6X_fKLB=Gi%gPAJM`>J-gO}@W3#H3=~na-~_>dK|J`tmoY zH&h3C*E#aIe$4fZn!PYUWIL0{W@|^5?_RmKYi70fvP);=nI1`>dByy7M$WZ|`{XoV zdwPHW8@uKEZKutDH4Z$;>DV0a{$U+Y+oBiS7TN7KV07MS;i&OH$vMgP#onvAi?-el zdggih+F{)ts%zL74O^Rz6zP=knQ!=bnd7>;^PXQSE(Utvt53ybaj|k8er_PbE!>eF z$iNnKZSmgg$L@XKy>#J$BUwxKe=y2?XV$uP0%z%Uv;L@x_wR4L_;(^vLu{Mw&xcPR z7E5%sa!$!+=UO=Rb!f`#hs%t@*S^(Q=)ui+srJ%=!~3%iWuD*Kyl}?l2iD zb$HTWhSkoFk9O8|hE#5Rz3ocYjBTCl{&EMloMOIyYxBn+`Lk~PnJ26*(Pdd%RQ$1y zM^@K$HT&}yGG~uFU-@nmu~xxz7n6wj)XLQxxkNVa>Fa#QpUvayC!ea<&3@m?DY0Mh zCi4$v=6^4w&c0R4sunwR!QqDaLw+BYFGb<6rPeB?m|D5Z#>mHa-?>t|YU`Y-r(f4v zKi}8Xl)t(y;6i;_pxWPKB7%#qS?)AA%3V0E@!`{e8bj&1Y-ju!b_+-MOKPm^-W{N%f<8k0&f6W&+ z+eF(8ttm%L7ISK_y-H+1+^x9h;iIXqLR)wF{7gnm$ zLE>JaB9@H5HVQA;Ah+C>C2oSZ`#agWhx;n#PY;;%FSo<|!-b!X?bn?7+f*wRcv>gC zVf-=6$&oqlaMYipbGOU=yW!q^$7)W>ME_LV7y4ggCj{!38D`3~-1zlS!cYC_rgH&j zR6ee|D$4aM``(VAH(MvC%E6Aj0L7zI036MYHChYe{i@^K4F7FhuonX0Pr$7G}dYqsghS zq51Q|7hQXE10&ZSb8NWf*YQtWY|rZy|DEds94fBA;$hun9GKd=%m2ym5S7dTv;CVp z6aIWVF7deO-JA__^1f@18*?vQvvZb1V~zpK-vt8VeXBJ>blvT(Vyya4?fv7+8EJ5{ zg;DL^jx9=lm+Brd_%}SB-~OSB`J6VJ0;=64L zR?{}5%{a42v;JKFF^ix6;eU0sd035}*SuzHtuSu9{+pvVl(q6^-Ih?Rx3NOAI2Oz_ zlKLzl;2JO?XYc&Kvu9S%5N%^h?K7TsZyl4!<#@l8LvLi2ilkrdQrqzs`a)L6E? z_u;gP&elDa%N?YmUnJ=+yJR)1+iVf1h{mlIOQc1NKh9#}yVx`3>kXSX8d9OL3*Uvj zK5&hX>q+u;txvC*j)rjb9dNs0CCquE^1ZL$cD{Jl9ltJh?@h24H<(lLbkDv(;n(US zDi3|n_H5f41gUNN&js}RqKPxw-$V#awfZDDEGb^gLn+TzT& z^bIp-zl=PGcag~ta zs&lLJ-?Fqs)@T>c$1m~h9DAG64F!wzE&m>#+3@6``|s?`^C5G1mH$R;X<&NU>&4@` zX8SD0EOtGf>Rqq0J2V=@?jHJjdftUQW-_N8CQf@Tetl8(R=?AM_dVaHUS{F)VZYDA z%EIw=G2^TIl1mnNwA@k4@P7H>($UNDw!2N2AGpB%@sGH(s)*a#8?k@?tmfXhx9sgA zL6HgbKCe|2Id_iZt2=YV+a!1US?g3^JKm0+|Nqy|wFe46R>$|~F3B}su{k=1eQV<} znb(sJcFym2HJ#e!)L3*}@_Bv;E7vPCQ~B=?-}D`od$&o*`flWpZ~NzUC!8{$*!^F6 z_1cKVF?VkL%lz+_JHgX}@8h58&NY9}|6ODJFhq-oby3j9?A4sEZ!ybgC{`Y+67SXpH=@^7yX0o%nNQ1ej{2o;7gzV{ zkS+hTUynk0xmNTWpSvEUs^JoR$l`|4->d7lPWvA;`9ea?>$$!!EhSP@N;D-e3y8>y zhh26TS!W+7s&;qTWPkS^e;!v{V_TWQ#QNm8$Hl$ zwSxQ2lM}lpU28sY)8d9h_4*o(|4J+0M|{-Uek023c_n}1jg3ncv_;w!d48o!x3hwyAJ`{Vk{G z6O+v6FAGq(xnhZ=$i*k21yYkX$klE56p|ykP;%|HykfS4e}40bFdwS&X%zUbHer%= z$K4bBqNlkIe*B=Wn^SA>-8hSf)u?)(xakV703VZy(K4nrQWm*$o!SpwkWk`1%)@2P zeP++s1qOE2@+J98OW)VrIr4A5xe9;IqDvfHPn=4`Le^wGscm&SvBSdS(`=4OZehv4 zFK+uWXS0-Bj^vT-b5$2CUc5Mdy8WZ(q`mg5xgDOlnrlp8bGFv-V9I{@aFVOzsXXr& z0yExK?=IwtVXl0gn6mcxGwazFe=avm>-(K**%iY7e-rC!vqJOh0-#oKX>-z|uBxMq zd^X?D9+|tekcsz``M29l0yDoZ$P<6Nf5GA8Ym7%jtlnEyd|$807Fso7J-^73?WJu_ z9Hq-oWX&i#A5~-=UusnnsmQS`y)5{OLzkSycGIZaEDc^#vC`+-IvbW1nKm;W)l*EB zDmlM!M%=ve#%By}yQh1(?*q)L%9;C$zAAh^Ks8=zN0=)!Ve?G1MRKfMI5hd->vgd0?wHe+1v|TBxWX{IEfHRl;*0f)I z)%@?G*AL&Y8SlF%Y_<4*f8wW|FBw?7`i!qhbxmnHCUPjj?>Ow>p^ znH!R%@od3@*6me0Gh~Br?qI(5=o7yjn|@71U*olfx=9zd@#$~Tj-VT=p zxX$E`h37?b9QpYv&To(CvE01 zZDo2HsoCbl*BZb(+ra9n)6Fa9ugV|y*d5*M;n1nh*|J%oe11`;Z<|u|#5ZD%iq}lN zavnsNyL<_CeX8ocaWRu;0NY9T+yxGHF6zz;eY{^wsq+i)cJ1~oPkhk3Qguehx^<6N zJ2k#pBjOymEcarm^h52PUkjwZol4AErj&HiZf~W|tz&t6vd#zS@UsdTNOYy%Qd@Jp zo4w;#_Znl7rMIW;<5_>3BTntw<7IbOOrLx> z)8pKJi~WI-6JK?KdJ0o4&sj{Lzwm^awuykud+y_hpM86k5b*uw*FvMuuJe~qxZ?w| z$ZYDN$34YACA)T}shXdxs`={wcj~u}{r{>urtjZ-=H>bQdm?tNSz{n_dW-JgjRlK^ zoE3M5{B2V@@Y?mqC;8Ypf5SFKESqrAwPCVx6{P1$?dNnq<^$5 z+g%^z{Ci?+)a^r?>lZUe)%@H%KcfG{+Jkpqb>CcdT;6_~S$IVIayvcy?~gu-ZSk#| zz0f1}NcguP{_ceudd{Ywb&tuHSafsOa0yO3_L}umykFGwXpVDc5BZL5X8w`cE?at$ zO`qu@ueAH88RsMZY&I0>y1mjVr?Saa)Iem@A1#e%OL;^xIoVBR{=0WP{_yq8`cCop z*VtK?C4f5erjCa5cf1i-ESSvQmb5oO;knC+fIFTVMp|u3fonOrT)GcEHxN0RY9JyR z8@hnONL@=b^gzIgPsSph>%0OSUTPl=5Se~3Af+UXz{?RjWR9VTah!b*UN>T%rH8oEsNK zYPK~k40yWUN+bYOZb)#2*2ykt$N`VPg#0XRWSacAr~XjD31MTAN#48*7#jYwZ+j*A V(P7j3s|*Yb44$rjF6*2UngH#*@=^c* diff --git a/doc/qtcreator/images/front-coding.png b/doc/qtcreator/images/front-coding.png index edfc5509c524097bd515bde23f6834b27f1bb7bf..b39a8c33db09a0471a90aa3de94c27046b53b2ce 100644 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0y~yU~mCpMrH;E2By1=9~l@J*aCb)Tp1V`va;^Bhu^9N zNt6Wn1vC89nI@#nz`&s5>Ealo5uBVL;nVQbUZ7@y;cI?oW_zn{r&0->su}L7*B-Dj ZY*kr!QGNHre+&!^44$rjF6*2UngHgWA}#;` literal 6045 zcmeAS@N?(olHy`uVBq!ia0y~yU^vFWz);7*#=yW(&y?rNz`(#+;1OBOz`%S9gc${Q zF4)7sAnxz!;uumf=WT3!j?D2|xqpJHA2noEyO(K%CS|$$X)F-pIlcC&LQ%I`-kU9q zZ>$^}uH{YGcY{B-(S$Wi+%ZPPSMJr9g>@%`ysjVIrFpkiF2``&gSS`yy^3_5`BydSghceBooD_X$&V<= zdAN*;zoo0FhJXL!nEllYZ0y!-@s!d(ZOgv*)Su!VPZKV&Em?9xX7(hddl$=;SpP}n z-JCy3X|2X)d)1@gR9iP{w@o^v9UQb|tD(jcgNu0C*Y{h+!UYSsVkOClpMJ##=A1)p79U=x~k1rH`H z^#_G>zf{i8w6{&H`_SvXjei1b_ynQzT5RG||5l$pvTui{N6?hX#XmD#yOa(*Ich(7 zQ&hpFO?>vJckOu|pISR1_2Jf|$BK76QdqwvpygSOlh)Ps43SH=c+ayI;hN9hn!8kC z)!#e9^17k@j1#rK{bITI?tDB^w~uneTq~tG9L-&!1Pt&(|6x{Jr*jo4&^y4G{KKF4x1i|E`ta&$M~{TK>aKA+=Yg3Wtssi~oO^8{OyGT{OqM;Ax_a z@C^1UpQt~*8yB9F)et}KuJiDMeV9mJ^ZAB=Nh|){xNxm;=PFg@dA6UIT1L-LR++gV z*>PvyS1TU>BxwWA%(GKwzU;c|W&8i?`{_mnUOgYe=FXYxap(Awqem1QqkLx+F6W;( zUp-yB?5JU0baN+XPy*{Atx!QLo(Y@>Sf1T~@%z^wuf_jOF6w<%Rg~@i&-3cxZz=!p zO+`KO$xp<5E=Cr7>zA?oI#FE8);j3Qy-07_Gv4MZ|&H9@D$UOy@ z?|klTE-Tvq{oMbV->=&n{O*6hb$IJhvf6!+m}=U+?URvWLIP9ZTK+`qVDj{HsFMC$9ZZ z*qfK9f8Q{9s%+Z-_V2e07yRA$G0^(h*IU20_1x#Z?z!D7u{3&5#5$$WiG3UITA#h~ zE_UPD%NJ%YpDX9QM&$jzkNa2lCLDcWxp=DBo{ns7HRgM-g3f52UQ)-j`asv^u;BTP z#*E)Td@?STP?(W(`+arRx-7mqD{gU~th(d&(YMde{%bk^4J(DhS^HY@>mQfs99tV> z(|zLnF;1Z;c}y!VA=4$ zc;?1FmL+nJxzF#rv@O#^|E1vu-zJl+%EYVRIGG-FozD?jPBPu=n9jqqG^ zH|fU@B|b1k%!=Q5?TD$iVE2*BMWI0@jEa*dC@oQVXKk6gPVbu6#_6wAZP_>q5>{q; zc5(7-)IQN{#qx#6wERMQpi-&OM9bgn+9sXrijkj}*Yoh8{@e{N4Jlo_cxujPw9d@! z$P(S#ct}lg{h!yjuLW{m()^PxzIVy-16>N9Y(*a4(RcK^rs(OqrYTB}$df_~gJ)^y}(D$`*u1%3l z(09dB*{*v`<-x6g4HJs`>J9Amnde?fULez6D$|sDyC=HU*^u$#s;jYA%;xYt%8TZ| zmH*28$&3K;?@3kM=6zFJdDD;WyUbR!qxA2#we6cbvo2S&8-=?k*7IcSOAP&ese8Uj z{g%c2m0Gso8cIwxAq(a(3|>LfKA4O_>7nmo!qfB@Hc~|X{p#F*MGxkKR%~)3WwO88k`W4aV@4D(9+BexP*qP?A zBVc~|{!iMu|NXjjT@udm+y1EbE!6ca{9ChahnTjTHf#L)*M>Fr9NXGG`*rWs|9QLA zZKllR`|8J!*rm)@33;(wql*3U)xBXU+7}htVl+PqD0ANq?QdKwqPG5)E-#GX{w>KGTip07`Xic4_Va+Ka=w!7t;0y1e zpp}1?INX@?Jg(wwSI$(KuDYWcfz;lSv+#vw&M}oI@AsEpj6415L9j*@ zmtMS2;^YaNjI}gHY?&vztbBi2GJ6T1t6s&-qg>04)85?LN%DO>7a>b-v4B;F^Bl%;#Lp){FaDelPX3 zaeix%YjoLQb8Pk|JMp8NnhcfRtaJKmaBh|Hx|I1pY$XI`ukCsYQYk*mX}|H7|H+ zam(>Tddo4xb1^lSmfG{#3+uP<6$#ca?var{``Ym3!+yudp8MmzI!`_3CGg7pXY{)> zYZjkyvXxX-$v)U1!j%;D!jR9;KjQNQBS+!leTu0`Rc(*cW%tZAyqL-s-jvzz?D1Mz zWS_k7w3EpRA`)KxIWjw)Gbg_ce$+qloM(ijgn?DadA6BlVn?>zy<~hjY|+l;QhJMy zHFStAdlp~wYRT5=R^Na9&v|LE`P-{&?;l=s)8cdxXxnn~m9nmDQHr2-(#e)@Gvp-m zOZS~kt-NR`wz7Sy&RND&9WP#WomHs2An|MK`Fg8|O@)sSRqIM0Gh21$gQd}&eJ0H2 zao0lM&95~sQ9g9bBRD_CFmnBz=q=H!*4Q~|PAc4y`b>Gx){p!yjlolGvQL;W7?qsc zW&OOMXP@ToKfHgcj{Ph;Q~$i{Zj_>u(y_MOslCf8-ra2z7M+*6#nsiY=l$K}W8bUN zp6~zl(_j72^E*3k%#x_Qp#QMgfH8ed{WrI8HMyl>+Ksw%7Rj`97#h6nG3Q<!Ngl&&M@9xLmB+1q2+|W{cJ~uhCGf z?D+IT`M4BIpvE@aJ(ly&e3s?f@R%`>LvfjHed5Mc+twuOrp@=QYtr?_H%v~7(QI8b z|3Z(lsCCVA`KF8-A?<>7zc`J7w1 zLcd7q7=Ds7-jMWW<(mywJQG+pE-}>$pyL+kCbKQ-dcu zT`bH|TP$>B%ZWutL>N*#a&tdTJH54Sf3wp?Q;v@zpF-z4icEN@uKL<=Lbubx7g{zm z*Df1SY|n+-R+(?6WM&S)LL%(a3yXz z-yuJj>DQHrz_~3aKF6Ar>3)?sak%}p_`KSsZ;RPPs%Nl#2x(qye@?PvMx)PKj_Jyu zU!An@^-=E$usHMN)Q{kfvn>zUEUrA3Y`gC$-@~UAEOa^|#7E|^kq!U#Fc*!9g=@0B zv(5BGoE}I_ubY|tL?T5q0$?#92FMW@d# zkTd5z$?vh~->;+cH)aH-Dtdi*5hS%cL$SiS$-t;VqC9q?$#r`24D05y_ieCa<|Q;|0sR z#d5a}s~l%pzoWo3qV>i!AI}=qgs!CdqURUKuHmUnvM=Q6VLVzqNyYN`#ENUV*Z+Ju zJ=gBOMvr9GgOkUPtW->Y>(>nqpI%kwcO#7|bnJT04?y00YSE)n98nKGQ?T;dUZk*rK?c2I>-_Nu1 z=3#Q{{MJ5lTWG&V$xP6GTfy|~gAqHsK5eK@>i?^LQKgOJ$h9ts%D}J~&Ae=hYeM-+ z{}XQKZV~?N`Pi*go-^r+Cyzc)mA;_!!W&sfIv#cy6ji+Y!M)G@*xRLFBRIGD^V=1i z$eUlVuj0-2zL^_03Kp+*oibtT?Vl%Gw?EUbPdfJQ`FHvI+5eZ7aHR`G=BMOX+!E^T zpVeRUYjp zzPs;m(e{nR?acp2Wu^+{dEI*`-Jbj8NP@!i^?#qPzg_gg@RY#ypngy-K2c@Gw#4sG zE-tJ*>*w;yP$TK6@r~EFowwc1k}Wg(FQ}dL)%macqq~QBUFFwZQTAZheDnFH*!nl^ z=NIeB9GRVKcD(S)R@c2Ox2F9)@vk!U3&*9UL5*9CI^;_eFV?)xkK0~<`HhSqhoHd2 z$MV_tyU$-wc4>cXsvWoV^Q84RkGU*KVP`L9V2_oFG1M&N&+WBVReY^*{b*0{w}~tY z$r(*S@rs2}8H;YJoid2y;MdTcUGj^w#=J*#$%1>VPkY+Co69fecy;MIB-}IqT(i6* z^K#QF-;iTo8`pjPDiL%}{#2ynC4q0fwcp-(WY=Wg^qLUxEWa~nZuI+TP5#%Lb61AC zNiU2M)%Y&Fd4unr*@aQLH{UP0+SzmD_3k=Dz8C6$3bm>jN`KWnzfu=m{_(50oEba6 z-;_!6hp#7lT>czzjw`;saVq08$$)K*CNoy7IQ;v@v_zvvcBiIIoW`Sh@Y&+4nUOwc zUgQ`_UkP_GS3ItEdr6$jw$}Hp8*dcG?$2HSu`Yb>w3yn!Dy}|m=jHP&OdPvse?GZg zqSoMy*wf<^s(6%(5>Ct!J+@XrkkL%4ihZU0f_KgNNq#m{Jm<2Na@t&$n7CN!)VwQK z!hgK=mhE1zo@uHV-_FFy_(i7cT~hf`&!s7kX6!kl!6kZKYa6$Yp_Z?$n~}@%!1+8! z6O`vL*td$@usZ27r9(4xnmt>s{+qDm8j~086PNQj8m|6dqg~${Aid?()Y|87^+T4u zs6Fv={!9zDmLG3~i+f)vTu5KQ^XQfllePP!t69$P1!h*bR~N~Yy%ZN*b@+Lvc`K)9 z@E7ZA_cAWsTYT>z$9@js6O!lt+`4+x<4YH_iAuH%irC0-76;8dz_QhH&+}Ehg}SwBGwxf3wD04&;BPR|MzK^}DAV%r;yn+1 zKP}{sx+3KIJJ|Npok#tuG> z1!mi_G3;Jx^i`scFaL3q?fLzC1ZH+^Iq~_fO} z*>o{$^~IB(U7}8&3pJ*ki+E*NpliHNWQm`Yz2`+?jY;PsekDtkZ!PKE&-?wo-^8X|VH zu5I<=YE@#&T{=aCtCe|akYZ5JyS%ynYW)h?Yc`$c;obT(d%NR}Y5m*&DtTlktd28~ zJeQKX_3q6wVYj=gTcc$TD=+Tc*8H+ZyPerE^mSw5($w?r(#FOg7j4m>qLE)VrA&Ku z?~e^m=9AB}&-T;i@x5~A{`vp9MrpOT-cI{_^|D=BpYEUNC4U?;?Q_%WEzfOjt?T|E z!z1?e)%tnHa|<1VRJx{!oK;eF-MqrxGqGr9i-u;?)Tttk{k2Y9!RJ364+vt>*4AW_ z|J@<7Y^i~)omE*7S}uBA za`g)1b1S~eyDztTEFW<6mS&SG%Pdxp2%$}a+mcu`L(H_d1gzF=Tp6Jqb~@~0kk*W& zB2GdlzIiyEaN4%Lefpj!srRo>w^dBBp7*~0&Xc59nLb31lld&Ozz04o>Pm zh2^S=ryiIn$uW6>{;pMjomhC*zO6piQ^k?6gIhxS#M!=tGaLeb3l16Eyg6f>#?rC8 zv$*Y+{*}dF9wzF9{+uwmh^}P4{$#Xgcjdk2b%*0TyQi!^ekJmy@4HtG>g-2+ z-+tFl$;h@n?E3WdybY7KiT#VBXCRAixyZr6Y-!EPd85c_DyHy6K+m6|--# zSs$^ODWmycxVr2469+e)#ycqra@+V>%;jh7Z@$HLE43}HT;t{0N#&Wb|H`7)-ahkK z`^)P|_XGWwdzr0&na92MD(gj|t5K0Ja`*hz;_c_@KkIF>{1W%h)0R0kZdb3HH7fAe z#E2^y8=ahU%=3cxjvbp%%?_WoHR(vY%<^rir=HDU^KXV&kKNzYS*1yS0SDtG1!9D? zr&|Bt7bC23l`pX=}{b_37o-N84WtsAs8U%Xpi1pJg~W*)I6=$}ajGmdJ-UtCn4ytT{I&gLNw)BLTql&`?D(h2 zOr87v`mOpK))T6CK8T53amL`tep9(mvoGC0ojq|@@i$%qqg+xu$jj2RK~ z;^O6XQQwU!%#&Z~%J2TTtS`Tv%>r=o3tavi=We8M{Zi?hnba`CRb86l-iJW@`z z&b7(KMz@MxW+xgRj!`OktIU|V{zsaV)1l5MPo6yd@#9C?w+Z>a(gHTRIai&f^-kZh z-=rCK$EK+D^NX{|Q@B>0SY~mvW=+VnPKnR8UmTMrt8?~UOpQJ`*F;|L)&-*tY$rCI z;{BpL_c!C^&K)-c0|Tqq$M27uHf@@lq@?7LpN}tW$^S3-UATPx1d-ylh^CF1pRfH5 z>G}P$xG1_UXWq=;8jNoO&uQsLvh(ROoZc|WtZ`|rC{KI&?z^muLJcD0S@^R$({wE} zuU+u^t5)S*_{1%$Cd;j^&Q5cx*Qv8-RloIc@y%TCZ#|*<^b4=LQ;C!F4sFQImozAz z_wsN5{Wc4CnYl}n)z-SaSa#R{LSyve+e!yK1*T=~xV--9xqY|VYc@5%2>6u9749UGBGS@jh#t19C|U`fQs#_WqJ%X?r+#bL+Pya!dBB%v;tng+=R{SYUYe@`gqM zO__8s%w+V*U9*akiI=P~-9{O^0MSN}iloYuL(nj)sm&88uVI?JcEiM@LFPORy^`>8Xudbd%*}y{-HfdOmCkJ+wk|$*fCRS?lr__4V<+dh<$zjoBkV zUw`G*ED8NXOZV=LJ+pG{+NIjz>*mbccuIk%e8FE%F4=FG;Nxg(d@HM(b3Vac?<$C)<$pFu(h2#YxeA;Ha$P)e)fp> z@HoMr%f=yc_bdPE|7s2j%a?3V@7{E`a*G!$PkOI-?&&-3ik*o|PKE^T+}QK#$IENi zuLnCjHwW1KT((RtQK#Vmv%#`u%Yw?vw*BBOHV_XGFpDX7IrHM#yFih?hT`a7kue(?5+BGXHE9=;?C~gBGffg2?XRjuQXia5kJbx+X zO!M`Y_V(R3WF~x^9=O_N@rg~={1Vce%P(#H5utU;JSa4DYJ}_p3pNo6&SX`6#-2@^ zj2_8qzbvu(DE-WnOF`nM^`t+4{@8s#;Se+RpZn3%?<9YPtDCRg|7UZbV`lBkmPg8` z&R-0!tlViJvRGB1qLYP1u}P`>HP^;P56aK1U9(1{tC&GR@yNZ6X~%vmUS4^~dQ%xs z(o7T4nJ$8?QyV~FirHA&D+R- zpJcZ0+1l?a{@V8Woc_H9Udyj>Df_5RKI3rGd&z{8XU>S2x&;PKoYDR>U=H`u$_vuw zc|7sEN-~e?R8RRa<41->M&=wAR)+_&A4F9AuSm?`HkIm4K7M1hL*cxG2@ZEZ&Wt_O z(b4fkX!rg=BaSRimY!|DK&7b zx-@CJLdb_LJFlucu^xNeMMAg)LEQ19UbA)UZ!okYOUF60}EtW3=4nLx&F49dI}k2bTM5;w=rimmx(3OykGpoLQ{mpbX?%m%v%NV7dX6Za~a;`3;vcA55$*v1e4jL|a zAd#@(gG5830NcHL^~cvGI_$XrGuE%^>j$1Ej3M*x2#Om7L@34-@UTiaOg!LGAmPT> z{CD2n!xF5YLfHbkWE$G|zFV`hsJMH6lq^s&5E9_qs@PVjW@2(>-{F)+8v?B)I_uh5 zm@Qelk~!IISnh9h|7vhV;~Up+ojuEh);XJPPIuWjQL8QZ=;E1MXZOGVaN}gMZoib@ zrinFs`lXM4{-^HfGi7u7`8qlM2^CvsoIYlM{4w{RO1b{?1`}@n7Z;FuByf9LJ@fJt XJDCMoKTTj@U|{fc^>bP0l+XkKKx2BI literal 5150 zcmeAS@N?(olHy`uVBq!ia0y~yU^vFWz);7*#=yW(&y?rNz`(#+;1OBOz`%S9gc${Q zF4)7sAbi2o#WAE}&fB?_IkLxVkMDoK&%^GXkm{)=x~Hxsdh+s|EXq9^)U<5d6g7h= zao3AxdRcHi$CkG4Pg^wx0m?)RNjew5Y6KbW|Cv+@3!+w<*y&z?E=E~m}k>iFOVEB7t+ znwTH)=+)uYc9+I3mF&bA&$2}=W~st*)1EE2V6}XfzVShTS-0i!KPAsM9Ng6D%PG{+ z6jQ@r?6&UQZiPD$I+3cTZ9CUBFFSE7?ZP&LO-zO&eW}SBJ(636M79WSIorQ*0;}b- z;{jXrL;`HtoD;c{HB!v}FtPIZYPK~k+_3SXy2b+b=7k9$Q8rc+0|~A+r?kWU0TY^d zSe+F&KMdDMke!;OA;C3!PfOumcGjN7K|HL^iIb-rtTSKeu=n%X00R-TO3ues;#@in z2Vop(t{c9bnX4RlS}(9UE8d7b8lbUBQ_)wnW1+yU1Pzwmt7W)4mbI9KDzrIeG%pl* zvyDN-z#mCNuAqiSlPFKyA%SxNKlr&KY}lL=Inp)$aI&6R9K_>l`^V97qL<5t(q#Rh zj~%&nJV#GCGX7m5;vC3dKVjaZ1NVA=e3Q3p&abK6eTB_=8VK?uO9LXaeWeF z-?t<1Ze7`R=NGU2q9z%NX!Eo3Y|fs`btHfzS4UhV;)|GPtnjO&>vPOhvPHOzJn`Y1 zeA%++?wrF57mH6kJALWTy+7`V?fG%1Y5T=JZGU$rXqG^fX zudkZ=|9F1fp@si*wqS~@h;HE&Ws+8-mt?O;nJY%NwaQTMZeEBM0{gXzT#)8jMenG#L z>vxIY|G9bZi`RZ9_FFk`RJl7vpv@`e@SmwG&i?CNpL@JK{@!x4xpPt^)=qljE?cgy zd-u)csW)4<^?iAC)&9Sc^TU!Ic3_(f>Q!?qzWq#>o2ara>-sjv+nacIH#A-GPneOD zBmJ`UP4Wv@xo00XYV)+-eRy=PfwST^#caE;x9$`RygV9zZ;jdVmb0p?ZJF{{rd!nf z(dv`g-xPbB{lg`0>uFZcqRqcO{PSXpqUGK71&g`Emwouw`P$;!ztXlt?>6MAZ%KT< zc>N964ZNQPMV3TQ{`}+oce{fz%R0_|ld!t|SSY#F^^oG$-ugdNR_braD8C%Aor{t8 zdEI+<`3GN?o)27i<%-?W+4j4a<=NZJI5x9eSYof;-YIizjym3q&7IpPv%6{k-+!K8 zMeXRS>V}AQXhP-?icTT8v^mMh@k+Pd{0pGlSODDD=WnzwJF z+LmQgSh{kRZEsjzN zFW5;XHAQ3EwsY}wjT#&S{#@QafAd-YCz>2wuli@W{$=LnG2fgL|NA-r)n&8IM4#O1 zwakp!U10Cbc>DTu1Cc(#7cntAqTUO{?>9|vbowk&7I4EeTd8xwg20u|_p2H2|N3it zV{dZ8$rsx7-}`Ruu`0dxPp(Vn&ijB1@+YSVcuKV`+P8Iwr|9?Q&)Y*8Ug(*X@XKTh zv&PpxZmGJOFT$mBk6}t>SFJza%Kt0l9p$BdT9tkitNZm$wC3~f|GA%SpFHF_dg$PW z9}7-1{gmPIUH|`s@>hei-izFWURrYPeKE6Z@~*n37u8h;L>ih35>oep1D|f@Z z>1U0ky;adgf$+4$n@$I;*tAF0Wk%b=75SWx(uz~B7VlAMVCv?VS;{l{=NdP)_c#2x z4X5`$vr~0FAGJa@@AVhKiM*%voHuTH{o`F!+aWow+B=8e$B4Q_O!%cT?+y2h$!VDfR-)HQTOfI@O9*(y6F;i19&S?%*xU^7VXd z3A}ToSKrvU|87?IvMEnazq-QTc4%eJw*ZH4@1oikS!!s^d1rlM@39WWb;|;L4(7Pt z`T0&_<)UJ5(OhR!74~c`mFTvr)CUE|Hd zhE&Fywnh7{vWP5P(&VwbDaWSy|IUKDLTk4hcP=mEUvXBcOWf}i&$UwZ>@O;|D@E9L zTj_rEiVdO7 zuIy)WR=lG(mvDd(Pp@IbG zg8Fa?j*x&;Q&l8Q*3F-1y}oHeheZC7w=yyP-|Z!fx0uh}`c1!#C+dB?jCJwNYkpH3 zy3Z+YQ*1gl*DR#i>X0PY!rld{SJDGqE<3KNw(3iX7dd%P<<|9W%9A>{gv|6laplKK zZC&zv(#h@HZ?TTbk}g$Avbdg(egcMb)xC?A-m{`f`JnY*hE zl}~b5T`N_X=V!uu;$iV~-M_4Xn@{NMWmnWsez*G1lP52iomxEIs%dG8;9Y~>8@HNX zE-+|)zA#|UG-I)4xrrK!UN+n+@miakP>~tBB5d7xe9#=xtqOs_P3?%+SGbSwCismO-ta}hJPwJ!AFWzqfH=_bm< zI`Ku<;@SnVtV;whYD~GBE%BRYv9NGZcUp(b+09P_w#GCH?e6~ZK}YFj*T@suD`7PX=#W{h^eZ!eJXW3J|R^~5PEcTOg6RzZbb!Gh$4uLIal?-!a4}P)| znP9u(iKqrgi>d#ynD6RRQ_Y&LUc3G*i=}(du@^^{D4tnox%8`HS)M`FG~@YqMeZrY za2~aCdew8UH~xLV+TV;^E6&%<7OG_B$};*|uUO^ptG=B}{ZNMYmW5Mv7thdK5GCZ# zaU{w8&r|*P(YKaYOKqB6`}5PGvu>Z496bD7Pbd3lu&rmyqQny0E1d;8Eg}A1vQxWf z%oCXNKjh$#^TzYqnYuC`O6Z%;f5H~-7c%oj@C@xmQ*`xwP8z&?d|o|t{l=B`iRXlS z%`Ud@VU{)So)z`$XE4jepU37)m-3V-I5B+Rs(4S(d5vzHOZuLL6SwuA|C;n|vJKZ} z(btarj*Nc~8OAj)GFkrM*hZUOa@|UM4fo{y-#i!#zf?uDd*vPu;i01D2bX!w~Kk0Tp--E-~?TwFpk`TF&cD?Fq z@P&Tk+LbN4=TE!1+jiN#m;2@~;;UMt-1R7i^XSiCwoIRRN}k@|Y{9bIor&$}?`D0w zU0dv}EIXx-R+g-J>!2cb@W8c>sF%VopRWGnmlZ92^uxcrp1roZ7T>>qUUyqK&q}VY zA>hELEy!;OS=wuSIRs3Qv=xkB>e^0wr(^XmbEx8LjL(l1dkzO%>L8GJj zyA#G2N=l>(7yWfw+B9#WT#cO8qrEGoCHS8dhHEB%;67*079QpNd$)o0wD8%XX_bsz zK?&dUWlWx?#7o>}TI;0YQn-8jo&V3Ks=b;q{c|b{Go#J^Ty3+mvgA!+2aeCo^l|HY z(XC<-xh-tR)n#4_+l1?jWB;x{sT~jyAG4>YApH|8*Zc+s(RlW$AvC!a^Zo@ns?FFTQ$pchaE; z`pazDS(g+qwc%?O^ZWm4a%hk2*~ByxZJD@OKS7b1x4HdqrKU?&e14#H?ZUsjExbq8 zsPAcA*ihruVZY!)yKn!w$D1dcPnetaN3K!&<-!GjynY&S&3x4Lq}1NkdB^Pft@nci zG#+Ux{%dyPUMZp_VgK7Q@9&>&yY|KyIV=pmmMHl+Opy0spNxrKxx#PTC`PV``?0U% zHNKoW|D^D5`uwD4x6as_uTKe>uxjcm^*wBvA6EL6@Tsq1j}qXLSl(hFlI9yf`{3Q% zl3(m@Ew(#(eZ`vv7hK|$@5yD~_?9KWd-dFXy`;K59bWs=BzBq3{}9&1^i@-lr`0Fw zv)09_4*#dwT|eKryOF6ouG#9*O19~q`{u8jqNQ;*+_2E9{ZNi%>rAe+^)F{N%4OQU zJbaj^wYk?d^X%$(?Yk%3o3L$e(?c;X-<>yYCcShC_Gi-OmZ8YGqO3SmE>{RWvH4&l?d04*mE~t2W*%%p?zV) z?591FT+{CE{Gue%HM{(}k%-RConN#>3aZL=oexf$>#gt1xV!xNFFvleqg(gzv8M2A z8H(u4{KLTN0_qNXtL=AS{JcWM`QW6J{s9j5T1Nv6RM$OW)>zQ%Whlbas{NCND`>*P z1dW)J?g0ljo!cJ2Fu`orWcP&)iF5Pioe##CDDpcqx<)^ry)eO4so$B={Iq2BC1a6) z)A$!OTrN5`?Mqx+lV;&G{{;bWrWtQrlCBY9*T_@`aRl5so4LwYZL^>FrDmIgNXn5< z3ns-cT=8^Lz$Q^?Fymy7Ct^REC_oKF^7Bf!Tbg(oN}%0@J=u`N_f+anI$& zr5Wn8{iA*;DV#Vi=<`&-LqvtMMor$4ac%#>fQa&`UL03uHj2b>uV}bZWXN*6m_u#v#tSN9`7c7fPaXQdsOjeEruWYRH4+$` z7jD?D`1@=oOZGC^t-C#2c0Cj9*m}%+=GIg5cgH#|jR^jJdZv_@szuormi$$+9>4o_Gc)gM`G2(F8`_VpBX|vo}T&Z6Vs;o9GeRIof%zk zfcmR1=PtOwuGPw+)ymPdQmIMSlEvx!wy+(OGah=Z`oq!~_40YPhL3IqbKy+Uo9jM* z|I8?|K~LszK*uF>rdGQ>vwBy~4~S-5*muXaH(}+}`j1`yqW5Eds@gAJaE7N!w9hZK%&&J-sdeSAMpRGn~tPQ~zzjjD;88n((up;eKE&@^wRM ztCRe08JCA*wXfziFN}xlb=jXCF8oiBRaY-yj)$dysNRHCa&!a0!tv$jY; z`gJ3bPkWa9G!)tNC9Z+VFP~Ge)mVh5RcCMbf(5eIPfK!NG7{mP#>?aC?ZCMGv}E^X zBaz-IygaU_9YBd1&h>U=G=IM?RYQU+vTD84LJLrrB0(eNmdK II;Vst0J_SUVgLXD diff --git a/doc/qtcreator/images/front-help.png b/doc/qtcreator/images/front-help.png index d2f9d42fecec83c8c9ae3bf9e2a3a6f5f5f85bb4..f9640f48634b9c10a4f76c9f997558e2da9f8339 100644 GIT binary patch literal 1032 zcmeAS@N?(olHy`uVBq!ia0y~yU~mCp4rT@h2L7|j4Gav7@c}*|t_%ze|Nk@mZ(#Vp zD)j$;hyU9=|Ic^$zsmCeDu@5;9sV!10kPMa{aM^};OrwGwROatp9)kxc-LgB=5Q4@f)6Shy`vlaaMxVY9FVW-~A_l$Hef1v4-* zF|)99aPkNU3JHsdOGrvd%g8FLYG~`~8a-a%XU$o(YR$&YTX*i>vv=QtlV>knynN-}gNKhEKY8); z)$2EJKYsr5?fZ|PzyJLG_u=ynHUZO0~ z%xL>8;rBLh!|a|#!GBk)sirOCm#tj3xwTpSgZ`9MX>G?JBKH!aTMcSBa|0F%w8%$t z{rmgp&&SJQy?s126@Kj-EgITBT#3J>_HbqV^0((XX0dhUtom~3v{vrd=mHo1n_GDJ z53A*JZ^+o^AKOxu)T)z9p2%KVq;@xsz2Gf- z?5pMv6BeE}k63qEl~=!(U8L6GupsMi!HO!ci{%k{!6uCIVH#ESoaWvlOCGv!aG1E! z`(l;Az83DB?7i%Etj0OYvMu$KMYnCRZ|wV`Cq3oLWxo3IhWJgQu&X%Q~loCIGFG1?d0) literal 1937 zcmeAS@N?(olHy`uVBq!ia0y~yU^vFWz);7*#=yW(&y?rNz`(#+;1OBOz`%S9gc${Q zF4)7s!0znn;uumf=k46n{UWY14fWPMyWRa7QCm4`lC$N4TAH{nJ9mBaQhX`QtU1SE3CB^vZjq$DUW%+iJ)O#GnkxEi zK?<%KeK(d&@ZnkF&=nwK=#}_FfiMD?+XrVm zecYL2U#Y|`tI9vwBhaeANz+Mv+0;cYLFaW{9rv_8O#Od6RMpj>=xKqFrq{96sX9~6 z?E8E7i@N;1uj_nV{zcxNqu_4U?EZaOA9I43jKz)V%oAm=dPftQQGl_%YY-ix*>$tdNoisSx*RtNryKZd@JW<*WYYJ>H#g$<{%q2c*=Y%Pf#nQz2`M zqGD^dEaMsDTN4D9Fnmb#;Ar4J{hYz#%{s|jxw}PvPv2Ga>Cr^CCoE|P&uYK^x^z;s z$M)6pbJ*Rw%I&PR_2<6`)Kp$*W;kc+gJ^4cX3YgrZ{AnNzFwiaBWO+ie#Pticlf%_ z489j(tGGP8|NN8w({eIvvul)DuekopT^0J-a01h-Lzzii(%(icY1mb;RKT}qS)ZLd z*NWanp-!`GRFx+`y7#r+gK?{|RP60Z+m7uo-!3(Qdq(!AIL*@22@Mh_tCmh+N)X>0 zuC*o5%z@>_-XIUg3Co*B82CKR!nic0I)AR%S+h;w`*e5F3!nNKN7JKk8|~PvDQzyd z^nWXt=O)J%kBc5*dNR|@?JXqF+`3rI{`Ac6^(W`9u0O3my}o3aSD8mHxQY^AsR({J1B zkHn>%@85KHo-SLE37c~3&ySKFF?Tu7JTb_f_|L2Vn_H^NKP|-_7y16}`gY*db8g%J z5BbkKKk^T8>iTve-ZJ6o*O$-A-na%aE-qii7qo@{^Q$dI4@0%@?{V|>e#Fn|*!3-8 zNyYEWn_q74<++^7efh!meY@w0L|lsK;dyRnIoE89@tNcMwyuA7EY4)A^ZF2P1EU%0 zt(8eBGp;Y6um6A6DMryrTS|V;xp5+H{->Znm2Vw?9hKJ9O1sW{%xi1I)N=mnpg%u; zuD#K{wCcvW9e3B%`p#Zd)D_0*IOW;Ktsifknq18j{OHP0m;9P!x620W{k&~d)11P7 z&pl=yWFpGOdF}j$Z?}b~PFS>Z#(VL!f39tnO&_d6bt^SfOaeJIXZhs+JX#VIbnL;o z`i?-wbs|Y;e||g9c;xVoI88Y@2J0Kr50qIQyl(w)>q<*b`&9e+BmYM6!*4t`@qU=d zl+bSWZUsw#_Re>jZ7mEP_tS6RdfUUO<@|HP!?i+87fg0}|4y5*_>SHE+&kwa9z8np zGu5*4p0yk^H<4978ZAFh>e;7X)4#skJL8746T_@_wWGhvrHv;#i8rfryfNH7 z&FS##sfW04c+XO3-2qBc)tyEyc6b9$lMyUwQ)fipd9mExYsk<-<3pBUXOD`*3EPy=GoqWWIx* z0@tLRbLQ*)8LSOdSPnEQDl+g{Y6`WrFx+?n^16%9zF)?HoCnta^L*qVa)`f!H=L^w zRB|m+GuJ#E*D0V7HfN^SKfC)9OdB8i-T%xcsKn}!XV<2{>Ts&SqeFq!f$O#;v&9B4 z4hKUXPR0Tc2_dG0$#2CMo9r`Wd8D$xGl*T2;m_M|MY%jn8aggkFMYF@kztY3%FnV( z7(Ph$u5;yTklhrgxrE_{YV_`~$%}qp`f=3xR7uL-3(-?rTQ$9_xe|}xv-)b!(#Y}Z z7yGhvCsT}16klW&PF>jcr|etrHQ6&Ss=`&3_9k~9|dqIsozqLbwuVa+84*2zl(^xe3g7W6Hd zu<^6u1gE_cno|y2PFCVv7uzlJ>Zr#;nR5$8jPe!<1u3|`_*XgI$w_$X1SURq#IpJE8l24H7xJ^8+2;X4mnQotqCXg zf2T0Q-Mjbp?cICZYj?Hlf8>mxpct|7 zsRoNOlVN8kOT9wUk`pY7ia+>W6`B5V2>n<1p{&&Bkf7qwIi)#4<&Oi`g9n?Ft@l~a zpS=6--p%><=>1{X6A70<~GxDw2*0bw1Tg`r7n-X*TPu97_ z_TOrLUK<)SCN@9LICJ7+rMS-e`?|ZGqV}IDl+20P`6n!Qr*WCJOVF0P=93oLDVuv9 zythL4v$EzJv8`wOmlUiQd0@)sd2vI}k`3O;K}#I&E*0@~4BFz6JZXu;S_u_a&&27+ zmUuR9f-+US4qn(jRcZ2>qFr?**8O?h9aO zoavzYws1m|?)BX3IU6rNtDb#hxAexy#u+M;esdn#_T8|!hHqDX* zidNBY1sp97J`Gx+>9V}}2*)DXyy;A(idM2JW?eIk<6g{r7WX{rhSlLCp8s~{FrJKk z&d*TVysYxU$1mSwGG_JVm^@E7`|atDo>kfxdZv|&E%9nR#y&Ml)ohi8uFu8ZCjtEl zGk$JPkKD6QL4KD#$0oz}gF;pgfedG_Eck8uZ{Pf&1*tz|cGVQwb}c$2Z($;Kexre4 zQK!wPmrORnR_k58?q6A>a_hpg*VCqFPxJjT$8cIxZ?x1Af!-3Eb|0PF-)r6^1hF(3 z|GAVlXTv8kqu-Gdm*rM$ZC4BA;yC>LMvjRdb8fmkN8-c9# z{$5U2cV*>1A@?MqrL-Lu=h}&fiiCDgTT&q3 zW^N#Oe5N;7lBV|rrn1YD;bDt**R4yrlikfF7I31=_k}Ch4ZD8FpdDgm>ysvFqSR-Is4f+NFZ-9f6#)wdHIu?B*d$x zEP6XZAgf4VopX~&*lI;Z71oDVDxQqHp)9Y)Fn+CxA}z9A>ke?dyztk`WIfl_6?Wd| zcKzqh{Km1WHOHhoM(OzcU9Yt#Ep5oKN`AO4<>ZmW^EQ5yHA|5D_Njs8>7jJTmD6T_ z%FevSeA(z{_)izPm2*vutXJB3Dur`h@on%A5@3qx6|i~uIB0>2qqpXoOE2!7s^SU> zZm$n)ue{QKC5`LlT97RN+$DJUR29$q`?s8wBD;*2uKFPR_3#YiiT65`_p0hInc$-tFz;N% z4qZ>fjTKB%%jCZ}^Jj=^{%Py;uYIE;x4VR=ZhoKnz59pGUgZcgTja5%D29n`a_jzi zJdcI>^&fc8-`OyGb#=wpwWfcrN58hQbq#(H&EdrVb3(+;*E_#W&}BW9%i|t2K|`2v za?-P)3F2{K9e?Ba>;9ecta)`x=-zJWgZKBBaOdB-^=P?M$HG`Ny69bB^8L_ak{vUGePrw#+(yrsvNl>=1TTd}>g&kmDpMx21O<>G*hj zj(LS|W6;9*S^N*b&)e7Y_OHsnH?7%!KCRg18+bx=LTB29&ZUV@xsFOF&tkKE(R%!S z>#Efq>Yw*4tN7afy5i5LK%4K{;st*{$^H9v`@Q0{Q;vb6Km5-tY}|8uu1xI&rn0?3 zXHTE#DQv$gvhcE+y;s-^`Q2MO(&txk{Qq!C_s{Xy<=VWtYR);jT|c6xa9`x|KhS+3 zNn)R581u@QzW=*-Hb1wkmW!`{$F=X@q1_RY-Jf@7K3gfN625E7;)!xgSD5WHv<%wt zqG2QBk%_WtB8U7EZT+`S_xI_Fum2?T??v?bhwt3BC>{M*#KQjl+YTAO6UQ#!sIH%T zUFM+h<`4R36y}{NRGe4&NaWv-?Rt;3@7G9cXB#?%KCl*a`*eV?Kpe&9D2t(tD3@;4~#s&!pFLOIKEIa{Kk}>u!$t zn5MLxJ$8Lwt;G47Pb%~FSIwSodj6rnr;8!%on6yQwOdv5YPgq3BpPSb^}PG2 zU-5IR?QZ{%H~Z}mRL?)fn_Ko%CA!Nf%&z}L@9r6U|0ukl`s;N4&er`u?#@5NzwZ5m zySIM_*hp=e(D}!4`tvpJniphtUyBVA*n9A3L(|R)C*KFxJdR%Gy9OSj>Mm z?9_rJt2s)(n?y3WE^0+g?e z@QdevD7BkCT}HEFy@;pb!YOs}-xgfd+PyGc^90`l^;3OLR;SA~=bd!aeT z;;?xl8MZ1ZH4A1}^G>OYzxY|?u+sdKA5JgdI#=Y-()43&}(z+B*Hn!_3W>w4X>e z$y6<{;As&(VWnxc)=v20^D>-Qs_h7GP9I{){XhkY-2cx7Rh{?&;W4)6!e=QC}6 z@o+us>B?TkKrW8?#~XS@oWCs!IH5fKG*7wuv5puc_Os6)7S8|oU}pcL_i=v=_wV_1 zmThBwdUgW)DZRyCR%#|1m}@`%Fq7wG(1CZ3O9Ll2O+2acQ(m$COBvgXes}we<2@Ja-LY%GIP&^_9`-e?$u6US`@c3a7xnz|1|yJpSkh1*|Pq& zRf~cgmie9e#K88q?W)+ZH*+Gmz8T)US>Lj0i9<3dHZ4VrDxV}p*8TkQe*N9UM<=%z zY`k(UU@u$K@#nwl^v*m!zHo&ZXwxPK^D_KQZ=AHNjZ)n(e=zi3)3(xG0pum0kmJ3B=jDg_eXnwv@gTz1B< zY;pnT$?Cue%Wm;=`+t3_{&94^W#4=|`{UJ}5sX}OBOCJl=EEaC@4w~OWhA%1@rWN!*mLHmos0`t zN%1V+{Qp42o`|Ct7W^z(v*!3l@zamK*S}>_x|n0QZ4GONo&K4_i5jcAY^0Um8T6feH5!OkCjQ5n?7yM-Y7P~1`^HJe~%ibCjC4`ndco|puOZ>>}$V1!zIIB%` zODSbvna7+YSnGV9m!-)#R{ec6kK=5!%EY<$PYzGFFX#K5sK2lBt65#aUJ2VJK^MIG z7l(204f?*fU`G2~kvBrCxI_Axw#sw{O%mB4y0}$j>yt~CDUUMsx)%4m-SEatQ00>A zuD*S*v|`z%OK*L?`}$*~mdWbvjSa^x3fLspFEz0LctWt|;mP1XyX*g)50x{VV4JD# z+U3F0;kx_Y^)3mar5jq3ET$~F%5_LKYxCr@o|cmj{X7_MT%^;g`XfWV^{gTH-Gm{%teo*|EG?{Nm|* zK2QF8s&30vrRnWkcXKbX?g-Rw=nmZJt?$mYWtK(T5`h|-Ld}#zO+Xqgs&p(v^>c@$hnRBef4lJIYCip?Ldi4y6+@%S*6C-%SOss_V`j@5di%Om# zvhDO;mDV*D<`NVWgs%owpM>h4oNz4=9!5g%J@6umZdyj^omL)n>Yn#biMhAOQO z7H4O1oxJL1c{N9F=Uk2d!OV7YuRD7WrLNaq>XDkT^wNe&oC=r!OD;?CY`pcdXLfkT zbVg6bTXlDqWGoTzXZ$Flb^hu~Es@1_I|L>tUN|v@X=^UeB&QD-dxLn6^=q{r3UFEB zx=mz7x62Cy!%0qi{GTo3X;tyJoDWK@-7}UdT>&3V__J_=*MWs?IM_(v9axDl& z@I1LJx?{bAI=0D2YN~~bbOtTZlyEBM(!H#tdF!cr5D&}AparFGq9!?QvGp`e`r^oS z+OAC3Q}Nb4-XNb<@}eppjD=9yhfFG-jn9smdn(?Vx1@kkXsJW6L5o=CM3J|jlr`Jh zQZxfZo0kaWzPHj;yCV=8w4jiwX40ZvJxdD2jg~sxwYjg-S{t|RXYV|btYnRuhVGej zmiae{XngmYC~`G*-Fi(Chd^}?zNKa*eKMK{+^>c?sko~DZgcbubh;?|;#oypkfCBl?nQOY2Ptq#M(@CXE2Ol(G_a-i z{CQy7dM{q{f`qEe7D3O4ewwE~?C=h@;+o0C70KPY=XcuaN3#B_E?qZsecb)Fsr`7BI(r1nO>NQd1v2yF@V#lB< zg5SI*im0^S{We*F)n#uGXuM?m-z6Rg#Wt876IN-hNS);Lp^#|_!-s4CnNNpFvaZ}9 SH-~|Nfx*+&&t;ucLK6TY{vk~O diff --git a/doc/qtcreator/images/front-projects.png b/doc/qtcreator/images/front-projects.png index 69414f48626f9d19136f9bfbef688fd27c421aa9..bd3412e8489a20f81e3c81bd7848bde1de66abc9 100644 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0y~yU~mCp4rT@h2L7|j4Gatne*%0$Tp1V`82&RfG%z^q zXUN^Ak}zK(bd^lnW~ro&BGF5P;?_wgu98StB^tL%IChnI{0gzSHDXb#MB~gKjD>}Vt`S-N_$1QEH8poQt%vzRNe|mdu*zY6JrNIer_AoFM>`w4GGv6ua zOzcTst%?K}_M+x>>c@&55_E1i%hXz@C~5w7HR{`ZV)gv?DLGG$C7K96RTMXCa&B+r zl`Hz!+QXN|cCFGwFgUe7t6=@+_L)JP`b(o3E^MwiktA=wJ9(YOjRMC>K93I`t@w1Z zH_s=Jr!3O##MvJ=grpCj7EM;3Zc$m2Z~E@@>Sxs_rT-}_nqK*#dOA@?S}Nq*fd#vM z=(${(cHS}M>wyJJ*x3TNF>f(eIn%ZNr|0D@_17eF^rr9IiwVf73*$0O-8`xLtbPG+@U&k4F3U!4uMgEO z#$F|NXMQNyxWr3}&pU=)d1AJ{_qjtJtW6>tQ=3H|_H?PVRt6S5W7k}=;Km;X*TSU= z|N9sVG|ap5j0&SsI!Q*MpfiM*VJ>38B{YJMlx z%v5YO=JgQd;A)xr=J31od*?>X+UFI%eElhLh9HZ}4I+&TPPlG4s?i~0s<%J7FvP|~ zaVeuFljE7^f?|skf+YT#@AoMdPe0r^;m}OBB^)fA^W81CIj}z1FFbwao!hd-tdn9j z{zX}=^AQU=vP4>X-lOKzE?kC%&vKcb76=$o#PVkI)i^1M5ELtQTQemGElMRc+RWGR+g( zFCsJa>{Db7V7r_womq3dM*23xY&P=?Cl<;+S#9xSuNO;9M^p8$BV|qUH|vh{^L&&aMNRHYk8u6^ugM{B@bp-XZ*U) zZDMfC-I_md@nd@%U*+=mAGH6k6#wV^Sby&4`1{|U&d%Jp$>p*z_rKStR!aW2^*DdA zo$tcMcD_q*YQFwDdrtqd{J$T3>r!}+7tGtLsQA+}@y7219KHKX?ydjxOt0|8$J-e- zOU~Py8E<@WU-8Vwx7)w{e!ts1cDl3Xmya|3?>e2g{cmOa{m;h>@Bcltb^iDNzs=uy z#y;G41hxgOx@z<4NXVC|t)c%@fO-M-D{J(DDCYRZ4)qjt#Y@BGfYLDsKy>{ux zrs?iAG2fn}`u*qmx1Z}D9Wqh4`qN1G+LiYvVPfHb-Phdx{_fL#{jfLuLMhFHPjAZG zdPJLt-!579_u~iix|3~%PNh=otl~EvDw>eAaFfs9#aG?cKWn7E<6HJN;PIuElK%@| z{dqloZSmQ=$Bw+e7qYF7(fs-O^OtVixUkh?*{1)0#E<_yuKGDS&O32c!mFB{lI30H z@pjM6_pyKf7F-^GGvA*@`ifh}L}%yhx7`~Umf0rFsQ9Wh_s>nqSow(N8Q+cu`^$WL z&%_q|vi|e!`XA+d&6Tmg?WLBnEj(9V`{+gORcD`;kN4-Fd-G`qSN;-%exGHvA74#Y zU+staBeRQx{cIdj?j z*#B$U?`aZ>Syv8S^u2BIY@^5B#evFee62;=TAs`*00FE&NM-?M+Uh(JCUslJ@&v-TU@sb5ABraLa>rGm6qxi|PUBN#u*jm55VVu8g z+Tw{eyz290m!Gs>zFy{S!^B4u*I$YE-2bKZ_RHw|m5N(sdY@$8*jznfUd^wmZI?V+ z1I}JIKahX*!!4GQ{5^f|YQ89MDc!Mt<bPWx!roU*7i&DdwYlNZ}Q%~ zum7>R`sK&t?=t<;`buk7FV42qytQU7qvfoAF3Uw%s+M*sxbmL3SQB#c;CHXB+eJ(j z+&^FZ5fRGODz;?ywG$iPAH2BidG?bFT@xSgzHfKs%l&&N602?$wZ`w>77@fSLG#?! zY(>@!9SW`CU*7gGo|tk#&FfLwF@_aNn>Np|2;|ITFg3XScBAlA1=axO-Rw)#{X?2W z9E9hHgsm4@!Z2&Xk_8Ftr-*V+V+d`Tzw(W$)lCKlE6Lpp6W@R4)ojqZam{?%dB#}} zmn!6>^MpK(XuZ5~?#6Gc*{%p?)pQ3P;90;?XXnP?!MH_mF^OC9Xu6AL0$YGn2p8AcpL}x7A`YB$L{fAwo^(0U4kge}8WM_tDKa^)s73d>4M+@j`#5SlO#XIXQFW|C`*lnfxr8f09Vsy8haaA9nFi z`a z7SECy4wU$>Ex-Ou!&Pv*RP@eWUg>c&SN;AIcDZZqv8b(kBb^O`W~??kgXu87_n^!A=1tK}?z_0x)Pv*l;42$>=& zx%O7pnG*}AhUJ*1ecJPTvib9A`&3*r7EMxR-FKNmiu0S7BNu}bDE=7EJuOyX4d}X~ z&8pcD^aK>|0bRv!qjJ)D9Hy!`J23>bim&@OV+D(Y3s;eENRzw+tJB{0kEVJQy7=z3pKPaG4b9l)w?ddjH$BYwOO2b)8IpAG%%o^n|HL z{~uQ?dsCgCHY01oC$8{d!d3T7!s#@Flq^sveA6 z9^G17QCp(BgyB|4^zLa>L2hDe7UH5dQAFcP9$7DKT+vh87r*%{&T;F=4xGh!q zl#IAysGyNfet7uw8D%%SWG!|i=S&yP`~J@B{v?+sq4n`w=S?ip(CaPOxTE>o&zws^ z3gLmlYtBEtDSk21?Ar!od;cowXtRG&9O53kwru>VnsI&EE-}v635zy`-dDMOP9kW- zL`Bxm+nARqWKI=$rvhqYe75%G`V{lo@X*Ic#f>88OcY!Tmn=}pzV5{3p*Z*c%Akru z82e<IsVGB@@nFS70sN8w6_PJkOqZh-HTU4?AAXA15X>Rjzj6 dQd-2%aI)rtf10|p0|NsCgQu&X%Q~loCIBKl9{2zN diff --git a/doc/qtcreator/images/front-publishing.png b/doc/qtcreator/images/front-publishing.png index d6bf6582150898b3be6ce2be23f22499923fdb3d..9946aa36cd3d87afa2ea864171b4cc44ef9f9e69 100644 GIT binary patch literal 715 zcmeAS@N?(olHy`uVBq!ia0y~yU~mCp4rT@h2L7|j4GatnR|9-PT>t<7&p-rlb8};0 zU~qJF#IIIfUVhc8RdRB23l}b&w`kF-RjUjP45rVTWo&FbbLPzHt5!{&F{87mr+?C< z-U$<0+uIwOo12=Ns;jG4ty*7MSy^0Kx_b56RjXFz<>lq(=V#^QWM*e)WM%E%y?gKe z!`E)yxpC{x`HPn?UAeY<_wF_8)@|OlZR5r*yZ7z8diBPW=g)87yZ7wnOUJW8>Pw2x zFfcHEaj?aro`@?w}?I5r>0b zJf_;81E-|C3u<&qT(sBt>%af%TNm(H98TV8HaU4t;ya@=Z)T>-mzT3DK9^S#^KLhs z(xo(iaX@XP15fw!tj5){TP0NtR)5^$TGi@uPld0ONArZtq@r0%&M2;2;;FSq$hXtw zwCZh@ol)8alioR$a+h8>>V1XNCdlapvrovLCt?q7SHJrpbaaMZ`mZYo{`;lBSwFpy zU3Xz|ywP$G&ZV}=PbzFAZM_VIP9<&lcT?NZBcioV;pOl9MJL~Rbfms)d~$D-!Dko4 zvma87eV^P?bZ(fKYt3MGa5?DTU{&Xx%+C)8}67lvRBV1t&lIaD%#d2KT9gb>w~`3T~I3X MboFyt=akR{0RKHG5dZ)H literal 5101 zcmeAS@N?(olHy`uVBq!ia0y~yU^vFWz);7*#=yW(&y?rNz`(#+;1OBOz`%S9gc${Q zF4)7sAUxmG#WAE}&fB?_J<``}kMCD$|E~9aS=jL`)wOF6Pm{SiElGV-;uWqYm0oF$ z6~fGHvlz^{mM}(b(U?%rWuhCfz~i@n;1<__17GEHCs?`O+O;lt_td*?ep%7`Qevk) zjm_M8>-QtQ_r+c2F>;41iwkzvsI>3bSIBsNc29Hv=ZC-dzWy$gKJRa-q-yBDAeGnu z7glbwnp52^uJJnMY;Bmjb(~A{ro#N!&(vqL&V07q^Wc)4SxW7>hv-HF5yP; zl!wJv(o$C5vwZj}>E+%fuMAGVPdIycsr}rx){EK#j)_rbO-^$I)g2H1E0B8T9`J&7 z<}>$z5+r2Wd< zuR7dn3tXM|%en4H6?1`SkoUrbpyrEA8j~ini0PfzESRt>dZr84#ihJ0ZtM@ClauBovCNea`*Xb%C>mkT^*vcuy!Mh1LM1bwG0|J zoM%SN`mfL#qIz_W*4~Jw1q}Hir!=UIp6Fl&jn{XX9E150ODm`yZ4w}Umn zfw6gkf@xswZ{}sot~~R(vxPxv;RMrKo)U8rxqf-S<^R^to;&q)>Xdrxwa0ulKL$A5 z{`v0Rv_o${I#0664VWaRA)3u4(K{<>Z3EM*Uau6piMK+U7Ov>=+M4mw;^aT8e_t4b zgI`UruM6ET7sbHZH8;Ph>59$SKSiFEKffNax?j5bWWa)5{fa_dNsFsf>?*^Tvp6vJ zcKdO6&J^odpkV6Vw4fnPP|?vbE1a{1Y1zAC4z3_;4+9Z{lKGc?G&+QWn6u180_G?R zi0Do~{Io%2&6%yw9$B8KT%|G3#ewnPqzP7BE&*3`+n+S#AK)!N!K?YA=}Ea`+v1?~ zr~hS7s1}`2|8&A_^9dKDSpIGejf6~lHph+1pT2m0=&g7l|52+n@R!_|1qqY>2*uQK z&U2J!dhB2}$uUc_Ge+n3PSK6Noh?r5z6u@cbq+95DZkKqueokVb!4cuNkC6~wcv*^ zom)a8+7nf#DV>pQSo~+t?(@u=PeKoP=pNb4CU7yp!R%K5MIVh_EK@Ex+B5Cm8~rt+ zC27U^{`PmW2c5sS6_)&G5PB)IOg!7{@96_SGS+{3zV)`?p5Gsh^zKEt*+j+^Jm=aa zIOm0Xm1XCbq&wHt!n7AOysPV3=A4*s6ceY;*2gy0&V{q<;RN~Ta<(n*{qGO{HlP0S z^Xbn&9-h9wLB><7&`Z~KscT`vj{EJw?d~6boV@$vtp45ZZu#{O)bsBgDq8X)?3l4k zgZ2x@tTf@DA?v2fM>ZUBJou#I$;|ax_tO~zd}4ous2{whdBga|hfT$4R=jfW1Knmt z*s|@(n`3R=p2J~V3l^;Sx9G;-iFNXIk3TkB)RsuB-%~2Czprq2 z&Hf3KC+^tV=fqsFB-n6C(A(!bQxozfKEFlzv*%^5MIWhn|)mzWuzte1o{($;PE$ zMgBdDU;p^PI=MgJb|!Nv*#EdFs(R;P(V_YTfs?nhc@JLvCd9&;70oj-;Ktgc3Ht9( zI4?93>6g9VoqkU4p#S|jM^=l!pW;5hXr+u&aCV3OhdG@epYpd0aC|=~{Av2-pYN{s zYZd&t_<4Fk_PQV5=YL6^yuIe>iv7X&zUj6(Xv~QDEobqkmZPmH*7e<*mn!$HOgC*U zeXwudqd7;!M9$Yft=seAR_UI92VZNdZ_^eBM`bufj#$RQpo<7P{nQk`G|M>%6 z)&~VvAI@zRbxDf+bI-i*Ve{}*(eeihx`kKkxwwY)e1E0i>pyrOKl8|Zo8OW>JU^yZmHtrK(O#{yaa)^wfM)BYJdv+Kdz)vLK=R6pOiDxZ_}?~sZFSA^xc8P&T3HFB7` z^0OTkqMsd%>iJ*uy|3tOROi{59TSXH#IFaOND=+~@_xNxx4Qh@;5~}g58hn-&Tzvp zi&13L&B9}McCfT6ZM$>$sb-jb^zV{~pKOFqK6)Z0UAyXfOOoHoZ*_SmE?CZ-_h_^B zsktj}T1>lkx#H2ni%F)|a|*)FOOZK0yFL}AB}t~1?Uws{s$A`Xyw15Dn?0S_JZyE@Uw1se z@zQw{^K^CdfiUt(ukE-@$k=`>*D{~qP1J>6s4{wLAJg>z=S2#zvnPho!lwrSyo9xu-3 zLu?y1h&6i}E?##1wD<8~!PmOSE-pXD^M3x1Z#$lDc~Y}5$8O^_?`yyP-Y!yeYJ3%_ zIWgeI)6=VTmalxXe8Vc{^vLdnJodM~FGHs5-2ZJ}`ZAlJPyOl{eLL{3-m*~crC%_U;?L-e$3@u}xK%=Y$ujJ5snyX&*m zJiFS>?Pq;ASaxMSz5FL|&8>peh;om5zeBQIQ=`|un&xzF)|{?eoI*UT39oifTW~@6 zvrt5p;BxWg9r-m5m6skC9W+1kK4kOs-Pc-X{oNn>ZgcQ@y;bWXZPJ=P9yz1Yemr*O zZVktS>o&{2t6s$#;84C+#4%Cpnc3zPJH!3{%lmnzx98M0M;Y9h!!mpJifgyj4R!XM zkI&ihFO$c6`W5ScGdPb$>phZ`d**!bpZ^u}hd1hk_*uV9ZxIklOX_1cl9qg0{P+FR z$~jh6O$*lV*gMryf5p3O4KqYKp=E?I4uwy5mp@#XsG zlZ%i2xNfs^R^YtVV#X``?6$6#d2~Bg=G)VsE3}TB<)8MRrL&FcR&z2(SJjkA@2S=& z&p1B_m%G`%;8FWEM*n;U+vLM{QsqyYzU5x8ZYFfpXI<9Dr!UW#6!Y^qB+bp^6DeBA zaD#>CVt~V56&D2&vnJK869VFVo+VG)dEw8woykwni{G(sVV^hm!jYYS4wb}Ke(+hx zzOR;Huki0LdnMhH9Tr;N&T3u78nEEfPc@Bg+Dor`h_&a%|G2q)$A1U=y0^tg#m#Ew zOWQ8a63+TndW|Wfd>dQp9U!t)k4-r*rYXuX203&$I_<#Psi)< z@uHNwa%)-rnHD(YK93d=DSOT_K+E@d`s6)T(K zpb-$I?Hcf=C#c+fYFN^rjf|mHLUTM~wCk#lN=D@~1o<-@EL5;K5x?o-ZR4&9=cDsD zH<+qefA*7mnCutwd)~eO8-%sZgFFnwt;(h(XiN!QIn5z4+38#DwZ(=D4_%D=^I#|Y z$FrN+1>`=2hV9v8do%9eFZJp7*Ecq4&MtcJtbS$Uq&){FZr+f-e-Ued!*>_erljas z^FJhB*Zf*E;YAIj{@>$FcDH1M=PdmDp?dkpZ(Bq6)TZ+0$Ht}#^Zkl^sq;Bv?v#yI zs>v?`SP$%Tw&RiIPx$J!NcYvEOd$r=km`N9E=n3-RDaI3`17UX*}pIURi=o~dVBca zX>t35`G0S^#>~8PKzR9~9~b5Ao9ru|aoC?V;#vCts`IAc=a)|`y&_umfoYz1BZ zOV)jg(I~P!AwApU*y9;>rY)W8d8f{wUgP)l*RlTG8`lLmShsjPtr6*1up;!l9RIQX zE8@ON%|D&+YwIJ9z&hp5FKbm((ymRo?ZXh-$NelU=#EKffC$$qt(%8FaXs1j^HWg& zP43w@W`rD1UnXPxGDr1bz=^P$>t?K6vm1+AlAV12%`ThosyNdv&#>vs6{e!it52-Y zSs?KEyrqW1np}st7^lQEu}`14%Ih8-v(JofKWt{a(#4t4`2JRw)}7z%#GDHHt5Q1u zPI6cKsq5&;GwF{TPpj|0o#mg>cs`|FDap>t(p^3y=W3Fgtnu473&I>2l|ed9d*_8& zyLzvEeoAeM#>PK0UWVzW-MYD6S&xnDMQ%uzoya#um9WoFM#5UtMeOGvFut3`&TJL^ zXaPh1Vj;)C`AM5ygO}g9*|#M}u5o4_PhU{_oWJqhxzD|HL;`rP3yIvm^k}!?QvZv5 zNl!JV9yQOHe$B~7WQE*RA=u|6a%Q!$iliZS%rZsBeq0HWQo}{ z1&sxk&u1@C*t(jEf?WtydcLZ(7iTM`I6k? zSlv+W1r1Xl_n3an7METS2@w+-K@`-Se+PmrY)XS$Y#y$TIzBC9plq@t65HJ6CD-vA9BPsU(`Fh zw#x08&vEvv=dYQ*I97Q>{t>^^4`l9T>7?udMEzqxA&g=`mvui z;lPu&Rdw6H%=)$~jwLT_*83v@T&GJf&YD~9mKe6M;bY-3G43tS0U1rZ7`Rp|X&iB4 z+^nj|!fJ2l7|6LJe*m(mX_3&i+yIBIyQVF;aNgT|zidO2dmPJR z6OOK`g$|h^T?9q{7$(%B%>@ACy5sPXJDo3r3XriKrP zqQ;KIvn@=siuZAHP5#5dwf9F^6H{2f@w4Nq8m}~^U$r{D_iS49YLR8Yfm4OY{_J3J zwM}gn6uBnN+vFsA&qgERXt}PVW5A1}+qFeD&3qpP8Yk+`PuEB=(Q*yg!pHS_lc0#( zN9k5bLTqx$M$!Dwt65n8CxS+RSOXY- deE833$tZqu@9tB37#J8BJYD@<);T3K0RZZTkWByp diff --git a/doc/qtcreator/images/front-testing.png b/doc/qtcreator/images/front-testing.png index 1bdbe4dc052c9ac222427868ac1b1e2b4cbb2ae3..69b1fe45d56df3832ea96ef7e20b36facb741f79 100644 GIT binary patch literal 905 zcmeAS@N?(olHy`uVBq!ia0y~yU~mCp4rT@h2L7|j4Gav7`T;&6t_&dXzoFrOXz2gk z+}jBW_X`Ujr=>m1%DS4AbR#Y8Zb8BQxwkVi?&Rm+%gVZ+lk+Gm>rO_-{p{@9 zIXQQ8a_(eh-ObFrmz8xVJNs^S_PwmEdzqPcv$OAl8TYcY@8slw*xA`2c4p>Xi2BS- zkowF_h+dFXR@R-YtUC||Fzp~U5OJ``U9jxE>}(JtJNsT{Cdl@zERgwNV?l<4)k7E% zWl(lj*1fDOki)=+zy;w9kSy3JxClDK{qI@kSirD?92I*!BGH{Da*QO(&j}&-{4kf?JWEXYW=_q*jZ(?K8dXmI*34a$);|B{HCLrADZ%F@Hc8dUUU8Zh?>!-P zZ}dyw8p-Fi`*&{Iclge^?+i11X1NpzIh@~9xoq)0G0Qqh#sKML#aE24nlg=K*D%{$ zWJ=!3;1_UBZh~RzlY*PI63JiZ@;q)Y^HReRmvnDRhZ5bh- zWCf=Qg(=ejOtyOL@BbxvX%fiK_mZH`u;m>jG*!N|h)8uY$3jeLN_T3U|&)@&g z-npUfed}uE{^+-_FaLORdp(P*%wI93H~TYwpSs;!Z+*F^9ITH&MY^QNx1c-KsL+CZ~pGYYMbb7vrYD${V5kx)>oIS zmUe8KqQ}Hp<{pCnE4+d}=$}3EMWHn}IIC*HqFq4&5lIeQsnSa}%sniwsqsyNRa3$B zkY&xJrW8X3R*l=a|+#Pd^p`WipmtAB6lvRMDLJN41$XJ=TR``K(+(LK#hHv%xBP$NRO;P7EJJ6QzZi8qNm= z?D@pI?C77G_NdR?Cg$e;#l>qogJgS|q{AM~wU zucOzNY|nav&EBfe(@@t!_ku`T)+}9b=&t7^uJ1Mvd*_BTFdBbo;pR$dF(4_4mUnl3BTij~op2@eBf|#) zo%zfST+_}oIy_8JjOF2ERB(!lm0I1x;PA`q!!0dEhKhEjR)?q343`e;F8IWIK(Odw z`B}pygFp!!ELYGb=arNO<443M)XpbH|zz zSWgzY@%*fYZaM%ps2uB+1vBu>$mC;xu-B(uI*P;{Mm4Pxs>7} z$Ce394Yf-Yyd+LAGrWBGO~K8vU~lv6qMb>6UVVypDa{PWJ+@IQ5au{NmS zu&kWlxY_SKn%)i;QQs>fYCAT&4m!>7XOQFGO5fBda` zDistWyZ77OOG_G5SLWQg%UNz&pK3Z~@qeWTkx;gWJ)fPYEoRkx#d=86-%W-6{P`0~ zNB^?VE@@7)UpnP8qlmyc3;BpX4}tJ^_7!sb98Nk|Br}NkG$u2AkXmTnv^AS?!Ugy1 zv%=;wB_IAPJ^x>UUQ8fMNb}*{@kg}oPf*g2;CgrefuDo$^>yo#4{n{L=VPZ)I$BCEU`!jz#c5zL-%etzT%&- z=#a|V*lu;L@_)NFi@rO3*fE07BQR0tdrid8Hj$eXj(dL8e(~0^%Sv$(!;c9{#ySk$ z2OPSj3N6C8f_i#&oWwLM=9NmaeMnSwVqICu)tIc7GAD>>VvkqHrL=BEMFt5gBY|@g z4FZ}=46m)z71P-kCi*ByK(>o;KWz+k zdeACu)9~R*_1uD)=MG2IOju-hLU^h|t98uGXO7J>GbZtcskMlhI?h|cqPgjyxgGZb zr42F@7O9;Oo@(HmX_I29;L012_xD)q`u#Rh?_&gV|KD7kP;PRuwe0u*iwkbAzxsUJ zmYS|8-MxqPUL9FITO?Zlzow&J*Yc}*mpiALZ!PJ2RI_-41ospnQx})weTu9MzgK{w zQqHu1hvA;G=R*C9GliGwl`(jAE49WYJ!oUwmpGxxAds`6Hfj5Qff*}U8njqft_}LY zT+th1*|*+>qhY;gT92bK(Q_YKAn+lHIl;o?9tC{@Cl#lJM(36x?2~#J0eEBXf)b#baFS~vf z*>7cE-QwdWz_a51>i0qaV}f{UYkMXMNC-`u8<)R)+Wl33|E&{OO_B=SBcVB`kcG!{ z@%?()X>xOqK0fwxU8s^4>(AxyPdHAAnvi7UwpelRy-LTk&t%S?FJEynBSh=J6Gy(3 zNKAlow`cZsr>?>W(%s$y0kJ+0zwy12n7~xgvorM69v&+OyUQ&i3>q%UOBGld*j?5J ztrD4g)vR;kQ4zu4i4~jAI~Cme@gPk!;I>?}%thWri)O_a3v|zi_540&oaU|eam%^+ zt+jDQMe}6WTmFofy+3J^`Kd3F7B+{hmpq^0QZspr?X_7mL;^F{UoH zp!CyO2M%Shjth*G1#+qqR12rdFCLA z@-~sS?WU8RBBsA+fhy!(x?oAC*94}Z8-43{i=@n6!J?_q`nE!Ti9+ydktGcx+aA|W tY~oYXs^!x>W9`g!IGTTng3>Q}<6(BJt_%zet3nyhq%myE zW!RsD+%%oW?*Jz=in6(6cUz| zSJg7Ia&`9#2`{VepE_f~+KpRx9zJsB-1%#F?%uoq^xOAe|D4zF-owDau-((eF(l&f z+p9PEnhXS59|nd5h#^IGdoNi0XRfi#ygbF@@)rB7Enf?ipYCm! z?$KJxsCBGi$}NT|$EN1)UKYS9+#OTXX^`{u)MB$;LdkRFik6li=1E(9f_L#9!^J@< z$DV}FO<&l;xM^|F23c2cr*eb&%%)cY9{=t=c>K0~=RdZn2i6@)>~89Zd1qM~WIR5w zU^%n0k;|q}N8Kt9-Yk?844SiMc`noI$;&eBuS-8J_xp77U8^1g0|SGntDnm{r-UW| D;Z3zM literal 3491 zcmeAS@N?(olHy`uVBq!ia0y~yU^vFWz);7*#=yW(&y?rNz`(#+;1OBOz`%S9gc${Q zF4)7sz#Ho6;uumf=k46H*)q>%kJm@7Pu;s#H!@5$(kRz3Q=u%EqtI}QNX^Nm7vi|y zF1--oaboS4YxWD?u6-hQ$(w8MlL_AZZx!3w9(ivFc8=M3)YCU8B{D2Ga@yBzlfq|y zs@-z_-5#6s=icmj`{vwtW+&^-=g*xvXLrByUY)-4{r^wWZCyZ-vV zN6jvocZILy&%W~BT^8=%_Vme_kb?d7{4Rwb)=d1;#pV9^gTt%nYUb~IJ-mLHgmhl1 zRZ5v)c%^!^Cx>F{(Ty`(1cK56J5H*!OxW~jUgzo!Vgf=jVjNt}x*VF4%eES=H`o=m z{DuCCav{In(<;)IMpSxKe${wLs@@wSI@6$^y@BH5NeEXw6{mV6ZCh^P{SXIc!7Wn7&UelX(1pyuLivt-7 zC)pjlU{%p7xbf$W`b!+5uBBU)jHmbSidwOw-|lweRmH!JlP9hfaryXZy;#b>EZ=i6 za?^LNHr@KZdcWoJf9^kPu54;q;+6eD_oe@*@Z(xWMzK?+_s38D^=l%hwM$d&{eKTL zBmbs&=Vni{uhI(E@6l2WIo_vvxxD=5+uy(ceDwTQ@yF0;#`4@Zb!)YZqk4PKe^2?j z`0O-?SFg`6-B^BO)tijKXY1$Xl{`~i-ShusNM0!2_4jxv-zm@hjXz#)O@$+FJ+(6a~DcN^KXzOCIJZgcy=x83|x z6*lm0d|-Mc`B3b%2|9*H=dXxzzOzJu&t9VX#Zimz*}{qMg(tCX3vfFqFt?WNn7+E- z@u&mpM>M!NTVA|z4veYGo>vy6BB?fc!i5zTY#&*lF%pOu|o z-^wGlE^_6I`>#KLmlu7cwnqQ0$gv3%c?A4?CQn%Y{nZ+_6oX8*OQ}C(oJ`iexYQ%$ z)WM>BkbO~$K#*0E#wSWKa?5*X|S}lI|+{rbMN*LEE)k^g;-@I8D^rrjG3=6eI zUw=-#9Jt|-vxxuuwTbgLGRn;-g2{@>IOHfQ&LjbPIa*~@OH zxR-%n^}mbz`UA}Z*UtX++i=VJqs-I|mw2G_xbDL-@#^LeSBnpD&T1)m zn{D7=B)25q;#5%RE2J@Il?kIz&2Hu>Pz9-c?6qQ8#4 zpBB2>;OE@H%9qdY2dr&b(Y1f+G5Hs1z4PqWeaq}-OgUS+UG10gQk6`rWS^<8TKC2A z>?_RUVE+6f=4)Pab<>{qML{0(zwBwx-NLcmJ|cH%rLx|nWyZ&(*urLSJaB!rSLap{ zpTt)Ib|S|E^-5C?O-)<(_33{5(9JZ~hb{Vt7$ti{s&6Pu|)s45W)a+(V47?z$U(P)#Qk(bAq6yy~SpQ>UJ0_F(adCn-YvYH`c|0}^ zKKl&zGF;SPUwZnfc&kk5Qkmj~9X|0A-6E_7@4R{sc`&F+Rf$IK6PdBNMMiM>-5C)U zf-CP-IM#4*a9+?X%e^Bf`gg5oeDccAxvy`{INY=Re`ngYJ%?E>F6k$PX+69VeeL}l zw^`e&D>fhbX1=7pV|L(4{$*Z=|I}TKDtO?_)t_CpDtofPJh}lE&0|x_lTZolYl~C5AR#%zWp{X2X_Ri z$i`^)K0dO}we|RA$%QdhcUv`+V>BnR#szxB)bsFcOMJBOv6tf68;O0-7>~PYYpoO6 zm7Ch7?Yc=pgRAp#|H6X{s@`7CwJfc3Q9I`r{nu~u*QIkCJDS|P8tw1K1xUnhQIK$c z;b`vZ_AvP0u_KSH+6hs_eL_XK(ei2=JG=Fa0u`FXT)9UbCf6w_P|p z7#t6H^S;|;CC;KaGr2tEl$%JpUf*eZo{#f37_|5JL~M1lwAY$&`;^^L$ExPVpKF%u zaPe#?UE*Y)!FwULX}yIQyWqEDDtx)i`b5i|ij;Nhd4wf`6GCrEWIdl6m2iJf;{1%u zljY|uinKh*UjJx@$;D3L+{^1ZT;*@1e`ILcP%_2Q$>^vmmpXUinYfjj+2PU~)_>wo ze41QcIb*W&7e2+A4~1J(5`~(?7GDn0j$%Axvru$JpIq=mQ|qXIcB`RSI7oy)$VxjX!Ai9+ zaLJ9T1x|;>o!z-xc2-JgaG#Fp(SC5}h@QwxRzEQ{#kvbcK4yRQ5^OpmSI?c=Jgt(Q zg?WFzh3UfIEX*!!LCSlbo_A-ua%N86=M*yGd3o4Wjt2``UdGJTV@Pr=V2QY4lw|o* z^__~>)itgU*sVqSe)uRu;J^Y7d0T{RWQH@x(+vZ#reY?!XIH2YiJ48`q< zKN6MibMKDd^!GvAq`Py@@3{Rb`G%ix)k48t9|X^de-ybFyY8>Ev-7b}jZa@B9~N63 zv05W1{rlTjULwxV?kher{Ilr5$G(-vKJNIMcKcO*#KQ|+0#*7>S$p5U?R#FFGkf9n zw0+{5oreMxrn0xZR1kDY)PL_{!g(@OWZHejZ5mE}j)4{50!7@VAO4dNY29exns`G- zAkZVjD!J=W#EeA-IeZf|mMpesb4}Fo36wBn_Yvtcby0`$0z@vI4D4LAKqF_qd`V!( zStwh-S>uR_wrgO3$hPy-T}3XHgzRz)oWUI|(sov;!^!2ze;2+PZ(gciImE!gz~JfX K=d#Wzp$Pyn+J&nC From 79ad71a9deb94858169b9cde260d3cf7df926b3b Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:59:33 +0200 Subject: [PATCH 0642/1447] QmlJSTools: Use IOptionPage::setWidgetCreator() for settings Change-Id: I57442416da54acd49cfcfd172fc67f28fee4f7b8 Reviewed-by: Christian Stenger --- .../qmljstools/qmljscodestylesettingspage.cpp | 100 +++++++++--------- .../qmljstools/qmljscodestylesettingspage.h | 16 --- 2 files changed, 50 insertions(+), 66 deletions(-) diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index cef7df08c3d..09ea4191a3f 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -5,7 +5,6 @@ #include "qmljscodestylepreferences.h" #include "qmljscodestylepreferenceswidget.h" -#include "qmljsindenter.h" #include "qmljsqtstylecodeformatter.h" #include "qmljstoolsconstants.h" #include "qmljstoolssettings.h" @@ -25,13 +24,13 @@ #include #include +#include using namespace TextEditor; -namespace QmlJSTools { -namespace Internal { +namespace QmlJSTools::Internal { -// ------------------ CppCodeStyleSettingsWidget +// QmlJSCodeStylePreferencesWidget QmlJSCodeStylePreferencesWidget::QmlJSCodeStylePreferencesWidget( const TextEditor::ICodeStylePreferencesFactory *factory, QWidget *parent) @@ -120,7 +119,51 @@ void QmlJSCodeStylePreferencesWidget::updatePreview() tc.endEditBlock(); } -// ------------------ CppCodeStyleSettingsPage +// QmlJSCodeStyleSettingsPageWidget + +class QmlJSCodeStyleSettingsPageWidget : public Core::IOptionsPageWidget +{ +public: + QmlJSCodeStyleSettingsPageWidget() + { + + QmlJSCodeStylePreferences *originalPreferences + = QmlJSToolsSettings::globalCodeStyle(); + m_preferences.setDelegatingPool(originalPreferences->delegatingPool()); + m_preferences.setCodeStyleSettings(originalPreferences->codeStyleSettings()); + m_preferences.setTabSettings(originalPreferences->tabSettings()); + m_preferences.setCurrentDelegate(originalPreferences->currentDelegate()); + m_preferences.setId(originalPreferences->id()); + + auto vbox = new QVBoxLayout(this); + vbox->addWidget(new CodeStyleEditor( + TextEditorSettings::codeStyleFactory(QmlJSTools::Constants::QML_JS_SETTINGS_ID), + &m_preferences)); + } + + void apply() final + { + QSettings *s = Core::ICore::settings(); + + QmlJSCodeStylePreferences *originalPreferences = QmlJSToolsSettings::globalCodeStyle(); + if (originalPreferences->codeStyleSettings() != m_preferences.codeStyleSettings()) { + originalPreferences->setCodeStyleSettings(m_preferences.codeStyleSettings()); + originalPreferences->toSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); + } + if (originalPreferences->tabSettings() != m_preferences.tabSettings()) { + originalPreferences->setTabSettings(m_preferences.tabSettings()); + originalPreferences->toSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); + } + if (originalPreferences->currentDelegate() != m_preferences.currentDelegate()) { + originalPreferences->setCurrentDelegate(m_preferences.currentDelegate()); + originalPreferences->toSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); + } + } + + QmlJSCodeStylePreferences m_preferences; +}; + +// QmlJSCodeStyleSettingsPage QmlJSCodeStyleSettingsPage::QmlJSCodeStyleSettingsPage() { @@ -129,50 +172,7 @@ QmlJSCodeStyleSettingsPage::QmlJSCodeStyleSettingsPage() setCategory(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML); setDisplayCategory(Tr::tr("Qt Quick")); setCategoryIconPath(":/qmljstools/images/settingscategory_qml.png"); + setWidgetCreator([] { return new QmlJSCodeStyleSettingsPageWidget; }); } -QWidget *QmlJSCodeStyleSettingsPage::widget() -{ - if (!m_widget) { - QmlJSCodeStylePreferences *originalPreferences - = QmlJSToolsSettings::globalCodeStyle(); - m_preferences = new QmlJSCodeStylePreferences(m_widget); - m_preferences->setDelegatingPool(originalPreferences->delegatingPool()); - m_preferences->setCodeStyleSettings(originalPreferences->codeStyleSettings()); - m_preferences->setTabSettings(originalPreferences->tabSettings()); - m_preferences->setCurrentDelegate(originalPreferences->currentDelegate()); - m_preferences->setId(originalPreferences->id()); - m_widget = new CodeStyleEditor(TextEditorSettings::codeStyleFactory(QmlJSTools::Constants::QML_JS_SETTINGS_ID), - m_preferences); - } - return m_widget; -} - -void QmlJSCodeStyleSettingsPage::apply() -{ - if (m_widget) { - QSettings *s = Core::ICore::settings(); - - QmlJSCodeStylePreferences *originalPreferences = QmlJSToolsSettings::globalCodeStyle(); - if (originalPreferences->codeStyleSettings() != m_preferences->codeStyleSettings()) { - originalPreferences->setCodeStyleSettings(m_preferences->codeStyleSettings()); - originalPreferences->toSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); - } - if (originalPreferences->tabSettings() != m_preferences->tabSettings()) { - originalPreferences->setTabSettings(m_preferences->tabSettings()); - originalPreferences->toSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); - } - if (originalPreferences->currentDelegate() != m_preferences->currentDelegate()) { - originalPreferences->setCurrentDelegate(m_preferences->currentDelegate()); - originalPreferences->toSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); - } - } -} - -void QmlJSCodeStyleSettingsPage::finish() -{ - delete m_widget; -} - -} // namespace Internal -} // namespace QmlJSTools +} // QmlJSTools::Internal diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.h b/src/plugins/qmljstools/qmljscodestylesettingspage.h index e9b244865ba..853d482b95e 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.h +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.h @@ -6,16 +6,8 @@ #include #include -#include -#include - -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE - namespace TextEditor { class FontSettings; - class CodeStyleEditor; class SimpleCodeStylePreferencesWidget; class SnippetEditorWidget; } @@ -54,14 +46,6 @@ class QmlJSCodeStyleSettingsPage : public Core::IOptionsPage { public: QmlJSCodeStyleSettingsPage(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - QmlJSCodeStylePreferences *m_preferences = nullptr; - QPointer m_widget; }; } // namespace Internal From 6d8ab1b4d5b91dd2d8d3f35b4189691f42d76872 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 13 Apr 2023 22:25:47 +0200 Subject: [PATCH 0643/1447] Introduce CurrentSymbolsRequestTask It's going to be used as task item inside a filter for LanguageClient::DocumentLocatorFilter. Change-Id: Icf091af83e9e6979628a7c01f3fcc5bd4cd95a9a Reviewed-by: David Schulz --- src/plugins/languageclient/CMakeLists.txt | 1 + .../currentdocumentsymbolsrequesttask.cpp | 83 +++++++++++++++++++ .../currentdocumentsymbolsrequesttask.h | 52 ++++++++++++ src/plugins/languageclient/languageclient.qbs | 2 + 4 files changed, 138 insertions(+) create mode 100644 src/plugins/languageclient/currentdocumentsymbolsrequesttask.cpp create mode 100644 src/plugins/languageclient/currentdocumentsymbolsrequesttask.h diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt index 20f7c680fbc..ab195c3d764 100644 --- a/src/plugins/languageclient/CMakeLists.txt +++ b/src/plugins/languageclient/CMakeLists.txt @@ -11,6 +11,7 @@ add_qtc_plugin(LanguageClient callhierarchy.cpp callhierarchy.h client.cpp client.h clientrequesttask.cpp clientrequesttask.h + currentdocumentsymbolsrequesttask.cpp currentdocumentsymbolsrequesttask.h diagnosticmanager.cpp diagnosticmanager.h documentsymbolcache.cpp documentsymbolcache.h dynamiccapabilities.cpp dynamiccapabilities.h diff --git a/src/plugins/languageclient/currentdocumentsymbolsrequesttask.cpp b/src/plugins/languageclient/currentdocumentsymbolsrequesttask.cpp new file mode 100644 index 00000000000..9221d65c17c --- /dev/null +++ b/src/plugins/languageclient/currentdocumentsymbolsrequesttask.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "currentdocumentsymbolsrequesttask.h" + +#include "documentsymbolcache.h" +#include "languageclientmanager.h" + +#include + +using namespace Core; +using namespace LanguageServerProtocol; +using namespace TextEditor; +using namespace Utils; + +namespace LanguageClient { + +void CurrentDocumentSymbolsRequestTask::start() +{ + QTC_ASSERT(!isRunning(), return); + + m_currentDocumentSymbolsData = {}; + + TextDocument *document = TextDocument::currentTextDocument(); + Client *client = LanguageClientManager::clientForDocument(document); + if (!client) { + emit done(false); + return; + } + + DocumentSymbolCache *symbolCache = client->documentSymbolCache(); + DocumentUri currentUri = client->hostPathToServerUri(document->filePath()); + DocumentUri::PathMapper pathMapper = client->hostPathMapper(); + + const auto reportFailure = [this] { + clearConnections(); + emit done(false); + }; + + const auto updateSymbols = [this, currentUri, pathMapper](const DocumentUri &uri, + const DocumentSymbolsResult &symbols) + { + if (uri != currentUri) // We might get updates for not current editor + return; + + const FilePath filePath = pathMapper ? currentUri.toFilePath(pathMapper) : FilePath(); + m_currentDocumentSymbolsData = {filePath, pathMapper, symbols}; + clearConnections(); + emit done(true); + }; + + m_connections.append(connect(EditorManager::instance(), &EditorManager::currentEditorChanged, + this, reportFailure)); + m_connections.append(connect(client, &Client::finished, this, reportFailure)); + m_connections.append(connect(document, &IDocument::contentsChanged, this, reportFailure)); + m_connections.append(connect(symbolCache, &DocumentSymbolCache::gotSymbols, + this, updateSymbols)); + symbolCache->requestSymbols(currentUri, Schedule::Now); +} + +bool CurrentDocumentSymbolsRequestTask::isRunning() const +{ + return !m_connections.isEmpty(); +} + +void CurrentDocumentSymbolsRequestTask::clearConnections() +{ + for (const QMetaObject::Connection &connection : std::as_const(m_connections)) + disconnect(connection); + m_connections.clear(); +} + +CurrentDocumentSymbolsRequestTaskAdapter::CurrentDocumentSymbolsRequestTaskAdapter() +{ + connect(task(), &CurrentDocumentSymbolsRequestTask::done, this, &TaskInterface::done); +} + +void CurrentDocumentSymbolsRequestTaskAdapter::start() +{ + task()->start(); +} + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/currentdocumentsymbolsrequesttask.h b/src/plugins/languageclient/currentdocumentsymbolsrequesttask.h new file mode 100644 index 00000000000..2c10b239689 --- /dev/null +++ b/src/plugins/languageclient/currentdocumentsymbolsrequesttask.h @@ -0,0 +1,52 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "languageclient_global.h" + +#include +#include +#include + +namespace LanguageClient { + +class LANGUAGECLIENT_EXPORT CurrentDocumentSymbolsData +{ +public: + Utils::FilePath m_filePath; + LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper; + LanguageServerProtocol::DocumentSymbolsResult m_symbols; +}; + +class LANGUAGECLIENT_EXPORT CurrentDocumentSymbolsRequestTask : public QObject +{ + Q_OBJECT + +public: + void start(); + bool isRunning() const; + CurrentDocumentSymbolsData currentDocumentSymbolsData() const { return m_currentDocumentSymbolsData; } + +signals: + void done(bool success); + +private: + void clearConnections(); + + CurrentDocumentSymbolsData m_currentDocumentSymbolsData; + QList m_connections; +}; + +class LANGUAGECLIENT_EXPORT CurrentDocumentSymbolsRequestTaskAdapter + : public Utils::Tasking::TaskAdapter +{ +public: + CurrentDocumentSymbolsRequestTaskAdapter(); + void start() final; +}; + +} // namespace LanguageClient + +QTC_DECLARE_CUSTOM_TASK(CurrentDocumentSymbolsRequest, + LanguageClient::CurrentDocumentSymbolsRequestTaskAdapter); diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index 649308b9b9b..e0de5f6fb1b 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -26,6 +26,8 @@ QtcPlugin { "client.h", "clientrequesttask.cpp", "clientrequesttask.h", + "currentdocumentsymbolsrequesttask.cpp", + "currentdocumentsymbolsrequesttask.h", "diagnosticmanager.cpp", "diagnosticmanager.h", "documentsymbolcache.cpp", From 4659053df4cbea7c71e089d5b3f6f2a86b44e014 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:57:51 +0200 Subject: [PATCH 0644/1447] TextEditor: Use IOptionPage::setWidgetCreator() for higlighter settings Change-Id: I4e06e1606a66d00294899d26c0cb385d81ccea2d Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- .../texteditor/highlightersettingspage.cpp | 177 +++++++----------- .../texteditor/highlightersettingspage.h | 4 - 2 files changed, 66 insertions(+), 115 deletions(-) diff --git a/src/plugins/texteditor/highlightersettingspage.cpp b/src/plugins/texteditor/highlightersettingspage.cpp index ceb8f7d48f1..ac10982de3d 100644 --- a/src/plugins/texteditor/highlightersettingspage.cpp +++ b/src/plugins/texteditor/highlightersettingspage.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -24,24 +23,51 @@ using namespace Utils; namespace TextEditor { -namespace Internal { -class HighlighterSettingsPageWidget : public QWidget +class HighlighterSettingsPageWidget; + +class HighlighterSettingsPagePrivate { public: - QLabel *definitionsInfolabel; - QPushButton *downloadDefinitions; - QLabel *updateStatus; - PathChooser *definitionFilesPath; - QPushButton *reloadDefinitions; - QPushButton *resetCache; - QLineEdit *ignoreEdit; - - HighlighterSettingsPageWidget() + void ensureInitialized() { + if (m_initialized) + return; + m_initialized = true; + m_settings.fromSettings(m_settingsPrefix, Core::ICore::settings()); + migrateGenericHighlighterFiles(); + } + + void migrateGenericHighlighterFiles() + { + QDir userDefinitionPath(m_settings.definitionFilesPath().toString()); + if (userDefinitionPath.mkdir("syntax")) { + const auto link = Utils::HostOsInfo::isAnyUnixHost() + ? static_cast(&QFile::link) + : static_cast(&QFile::copy); + + for (const QFileInfo &file : userDefinitionPath.entryInfoList({"*.xml"}, QDir::Files)) + link(file.filePath(), file.absolutePath() + "/syntax/" + file.fileName()); + } + } + + bool m_initialized = false; + const QString m_settingsPrefix{"Text"}; + + HighlighterSettings m_settings; + + QPointer m_widget; +}; + +class HighlighterSettingsPageWidget : public Core::IOptionsPageWidget +{ +public: + HighlighterSettingsPageWidget(HighlighterSettingsPagePrivate *d) : d(d) + { + d->ensureInitialized(); resize(521, 332); - definitionsInfolabel = new QLabel(this); + auto definitionsInfolabel = new QLabel(this); definitionsInfolabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); definitionsInfolabel->setTextFormat(Qt::RichText); definitionsInfolabel->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); @@ -51,24 +77,25 @@ public: "" "KSyntaxHighlighting engine.

")); - downloadDefinitions = new QPushButton(Tr::tr("Download Definitions")); + auto downloadDefinitions = new QPushButton(Tr::tr("Download Definitions")); downloadDefinitions->setToolTip(Tr::tr("Download missing and update existing syntax definition files.")); - updateStatus = new QLabel; + auto updateStatus = new QLabel; updateStatus->setObjectName("updateStatus"); - definitionFilesPath = new PathChooser; - definitionFilesPath->setExpectedKind(PathChooser::ExistingDirectory); - definitionFilesPath->setHistoryCompleter("TextEditor.Highlighter.History"); + m_definitionFilesPath = new PathChooser; + m_definitionFilesPath->setFilePath(d->m_settings.definitionFilesPath()); + m_definitionFilesPath->setExpectedKind(PathChooser::ExistingDirectory); + m_definitionFilesPath->setHistoryCompleter("TextEditor.Highlighter.History"); - reloadDefinitions = new QPushButton(Tr::tr("Reload Definitions")); + auto reloadDefinitions = new QPushButton(Tr::tr("Reload Definitions")); reloadDefinitions->setToolTip(Tr::tr("Reload externally modified definition files.")); - resetCache = new QPushButton(Tr::tr("Reset Remembered Definitions")); + auto resetCache = new QPushButton(Tr::tr("Reset Remembered Definitions")); resetCache->setToolTip(Tr::tr("Reset definitions remembered for files that can be " "associated with more than one highlighter definition.")); - ignoreEdit = new QLineEdit; + m_ignoreEdit = new QLineEdit(d->m_settings.ignoredFilesPatterns()); using namespace Layouting; Column { @@ -79,11 +106,11 @@ public: Column { Row { downloadDefinitions, updateStatus, st }, Row { Tr::tr("User Highlight Definition Files"), - definitionFilesPath, reloadDefinitions }, + m_definitionFilesPath, reloadDefinitions }, Row { st, resetCache } } }, - Row { Tr::tr("Ignored file patterns:"), ignoreEdit }, + Row { Tr::tr("Ignored file patterns:"), m_ignoreEdit }, st }.attachTo(this); @@ -102,53 +129,25 @@ public: Highlighter::clearDefinitionForDocumentCache(); }); } -}; -} // Internal + void apply() final + { + bool changed = d->m_settings.definitionFilesPath() != m_definitionFilesPath->filePath() + || d->m_settings.ignoredFilesPatterns() != m_ignoreEdit->text(); -using namespace Internal; - -class HighlighterSettingsPagePrivate -{ -public: - HighlighterSettingsPagePrivate() = default; - - void ensureInitialized(); - void migrateGenericHighlighterFiles(); - - void settingsFromUI(); - void settingsToUI(); - bool settingsChanged(); - - bool m_initialized = false; - const QString m_settingsPrefix{"Text"}; - - HighlighterSettings m_settings; - - QPointer m_widget; -}; - -void HighlighterSettingsPagePrivate::migrateGenericHighlighterFiles() -{ - QDir userDefinitionPath(m_settings.definitionFilesPath().toString()); - if (userDefinitionPath.mkdir("syntax")) { - const auto link = Utils::HostOsInfo::isAnyUnixHost() - ? static_cast(&QFile::link) - : static_cast(&QFile::copy); - - for (const QFileInfo &file : userDefinitionPath.entryInfoList({"*.xml"}, QDir::Files)) - link(file.filePath(), file.absolutePath() + "/syntax/" + file.fileName()); + if (changed) { + d->m_settings.setDefinitionFilesPath(m_definitionFilesPath->filePath()); + d->m_settings.setIgnoredFilesPatterns(m_ignoreEdit->text()); + d->m_settings.toSettings(d->m_settingsPrefix, Core::ICore::settings()); + } } -} -void HighlighterSettingsPagePrivate::ensureInitialized() -{ - if (m_initialized) - return; - m_initialized = true; - m_settings.fromSettings(m_settingsPrefix, Core::ICore::settings()); - migrateGenericHighlighterFiles(); -} + PathChooser *m_definitionFilesPath; + QLineEdit *m_ignoreEdit; + HighlighterSettingsPagePrivate *d; +}; + +// HighlighterSettingsPage HighlighterSettingsPage::HighlighterSettingsPage() : d(new HighlighterSettingsPagePrivate) @@ -158,6 +157,7 @@ HighlighterSettingsPage::HighlighterSettingsPage() setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr("Text Editor")); setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); + setWidgetCreator([this] { return new HighlighterSettingsPageWidget(d); }); } HighlighterSettingsPage::~HighlighterSettingsPage() @@ -165,55 +165,10 @@ HighlighterSettingsPage::~HighlighterSettingsPage() delete d; } -QWidget *HighlighterSettingsPage::widget() -{ - if (!d->m_widget) { - d->m_widget = new HighlighterSettingsPageWidget; - d->settingsToUI(); - } - return d->m_widget; -} - -void HighlighterSettingsPage::apply() -{ - if (!d->m_widget) // page was not shown - return; - if (d->settingsChanged()) - d->settingsFromUI(); -} - -void HighlighterSettingsPage::finish() -{ - delete d->m_widget; - d->m_widget = nullptr; -} - const HighlighterSettings &HighlighterSettingsPage::highlighterSettings() const { d->ensureInitialized(); return d->m_settings; } -void HighlighterSettingsPagePrivate::settingsFromUI() -{ - ensureInitialized(); - m_settings.setDefinitionFilesPath(m_widget->definitionFilesPath->filePath()); - m_settings.setIgnoredFilesPatterns(m_widget->ignoreEdit->text()); - m_settings.toSettings(m_settingsPrefix, Core::ICore::settings()); -} - -void HighlighterSettingsPagePrivate::settingsToUI() -{ - ensureInitialized(); - m_widget->definitionFilesPath->setFilePath(m_settings.definitionFilesPath()); - m_widget->ignoreEdit->setText(m_settings.ignoredFilesPatterns()); -} - -bool HighlighterSettingsPagePrivate::settingsChanged() -{ - ensureInitialized(); - return m_settings.definitionFilesPath() != m_widget->definitionFilesPath->filePath() - || m_settings.ignoredFilesPatterns() != m_widget->ignoreEdit->text(); -} - } // TextEditor diff --git a/src/plugins/texteditor/highlightersettingspage.h b/src/plugins/texteditor/highlightersettingspage.h index c56e6d2238c..94407c9020b 100644 --- a/src/plugins/texteditor/highlightersettingspage.h +++ b/src/plugins/texteditor/highlightersettingspage.h @@ -15,10 +15,6 @@ public: HighlighterSettingsPage(); ~HighlighterSettingsPage() override; - QWidget *widget() override; - void apply() override; - void finish() override; - const HighlighterSettings &highlighterSettings() const; private: From 654dae486ac926c81c4ec87a33ae03815f0c9621 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:01:48 +0200 Subject: [PATCH 0645/1447] CppCheck: Use IOptionPage::setWidgetCreator() for settings Change-Id: I0c2b9d96e53ddcecc3d25e519c3df21b1d09ddf7 Reviewed-by: Christian Stenger --- src/plugins/cppcheck/cppcheckoptions.cpp | 50 ++++++++++++++---------- src/plugins/cppcheck/cppcheckoptions.h | 10 +---- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp index 11563430cc1..9a16319bb29 100644 --- a/src/plugins/cppcheck/cppcheckoptions.cpp +++ b/src/plugins/cppcheck/cppcheckoptions.cpp @@ -120,6 +120,33 @@ void OptionsWidget::save(CppcheckOptions &options) const options.guessArguments = m_guessArguments->isChecked(); } +class CppcheckOptionsPageWidget : public Core::IOptionsPageWidget +{ +public: + CppcheckOptionsPageWidget(CppcheckOptionsPage *page) + : m_page(page) + { + m_optionWidget = new OptionsWidget; + + auto vbox = new QVBoxLayout(this); + vbox->addWidget(m_optionWidget); + + m_optionWidget->load(m_page->m_tool.options()); + } + + void apply() final + { + CppcheckOptions options; + m_optionWidget->save(options); + m_page->save(options); + m_page->m_tool.updateOptions(options); + m_page->m_trigger.recheck(); + } + + OptionsWidget *m_optionWidget; + CppcheckOptionsPage *m_page; +}; + CppcheckOptionsPage::CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &trigger): m_tool(tool), m_trigger(trigger) @@ -130,6 +157,8 @@ CppcheckOptionsPage::CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &tr setDisplayCategory(::Debugger::Tr::tr("Analyzer")); setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); + setWidgetCreator([this] { return new CppcheckOptionsPageWidget(this); }); + CppcheckOptions options; if (HostOsInfo::isAnyUnixHost()) { options.binary = "cppcheck"; @@ -145,27 +174,6 @@ CppcheckOptionsPage::CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &tr m_tool.updateOptions(options); } -QWidget *CppcheckOptionsPage::widget() -{ - if (!m_widget) - m_widget = new OptionsWidget; - m_widget->load(m_tool.options()); - return m_widget.data(); -} - -void CppcheckOptionsPage::apply() -{ - CppcheckOptions options; - m_widget->save(options); - save(options); - m_tool.updateOptions(options); - m_trigger.recheck(); -} - -void CppcheckOptionsPage::finish() -{ -} - void CppcheckOptionsPage::save(const CppcheckOptions &options) const { QSettings *s = Core::ICore::settings(); diff --git a/src/plugins/cppcheck/cppcheckoptions.h b/src/plugins/cppcheck/cppcheckoptions.h index 7c23d69f605..48526cd540f 100644 --- a/src/plugins/cppcheck/cppcheckoptions.h +++ b/src/plugins/cppcheck/cppcheckoptions.h @@ -6,10 +6,6 @@ #include #include -#include -#include -#include - QT_BEGIN_NAMESPACE class QLineEdit; class QCheckBox; @@ -75,17 +71,13 @@ class CppcheckOptionsPage final : public Core::IOptionsPage public: explicit CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &trigger); - QWidget *widget() final; - void apply() final; - void finish() final; - private: + friend class CppcheckOptionsPageWidget; void save(const CppcheckOptions &options) const; void load(CppcheckOptions &options) const; CppcheckTool &m_tool; CppcheckTrigger &m_trigger; - QPointer m_widget; }; } // Cppcheck::Internal From e596ee2b68f359397c7828c71f206e906d81cbe7 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Apr 2023 13:41:58 +0200 Subject: [PATCH 0646/1447] Examples/Marketplace: Put horizontal ruler into the heading Avoid the separate line above the heading, which also doesn't make much sense for the first item. Change-Id: I2cb4aa270f805552215f4f3dc114103f9f3c313f Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/welcomepagehelper.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index bc3afe89ee1..62f8ef6054a 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -747,7 +747,11 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList" + Tr::tr("Show All") + " >", this); seeAllLink->setVisible(gridView->maxRows().has_value()); connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); }); - QWidget *sectionLabel = Column{hr, Row{section.name, st, seeAllLink, Space(HSpacing)}}.emerge( + QWidget *line = createHr(this); + QSizePolicy linePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored); + linePolicy.setHorizontalStretch(2); + line->setSizePolicy(linePolicy); + QWidget *sectionLabel = Row{section.name, line, seeAllLink, Space(HSpacing)}.emerge( Layouting::WithoutMargins); m_sectionLabels.append(sectionLabel); sectionLabel->setContentsMargins(0, ItemGap, 0, 0); From 51d6b75fb073a5855d0c46452c0f14d229b20482 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 21 Apr 2023 10:16:10 +0200 Subject: [PATCH 0647/1447] Doc: Fix references to locator screenshots in How-tos They are now in WEBP format. Also, move some text and images around and add a reference to screenshot that shows a list of found files. Change-Id: I219e2b94fe22ffc6d36b0de34529d3849a76ff1b Reviewed-by: Eike Ziller --- .../src/howto/creator-only/creator-how-tos.qdoc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc index da32fd41263..e380c1e6e84 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -171,16 +171,17 @@ Use the \uicontrol Locator to browse through projects, files, classes, functions, documentation, and file systems. + + \image qtcreator-locator-open.webp "List of found files" + To quickly access files not directly mentioned in your project, you can create your own locator filters. That way you can locate files in a directory structure you have defined. - \image qtcreator-locator.png "List of locator filters" - To create locator filters, select \uicontrol Edit > \uicontrol Preferences > \uicontrol Environment > \uicontrol Locator > \uicontrol Add. - \image qtcreator-locator-customize.png "Locator preferences" + \image qtcreator-locator-customize.webp "Locator preferences" For more information, see \l{Creating Locator Filters}. @@ -190,6 +191,8 @@ You can now do basic calculations, with options to copy the results to the clipboard by navigating through the entries and pressing \key {Enter}. + \image qtcreator-locator.webp "List of locator filters" + For more information, see \l{Executing JavaScript}. \section1 Jump to a function in QML code From 6f7a56c31ce3450cdb096dac59e9c0fcc28e3c85 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:52:15 +0200 Subject: [PATCH 0648/1447] Designer: Use IOptionPage::setWidgetCreator() for settings Change-Id: I731905a84110966640cef0bfd8cf7eeb9e7527cc Reviewed-by: Christian Stenger --- src/plugins/designer/settingspage.cpp | 52 +++++++++++++-------------- src/plugins/designer/settingspage.h | 21 ++--------- 2 files changed, 27 insertions(+), 46 deletions(-) diff --git a/src/plugins/designer/settingspage.cpp b/src/plugins/designer/settingspage.cpp index a3e3ce3808f..64b79940f56 100644 --- a/src/plugins/designer/settingspage.cpp +++ b/src/plugins/designer/settingspage.cpp @@ -11,38 +11,34 @@ #include #include +#include + +namespace Designer::Internal { + +class SettingsPageWidget : public Core::IOptionsPageWidget +{ +public: + explicit SettingsPageWidget(QDesignerOptionsPageInterface *designerPage) + : m_designerPage(designerPage) + { + auto vbox = new QVBoxLayout(this); + vbox->addWidget(m_designerPage->createPage(nullptr)); + } + + void apply() { m_designerPage->apply(); } + void finish() { m_designerPage->finish(); } + + QDesignerOptionsPageInterface *m_designerPage; +}; -using namespace Designer::Internal; SettingsPage::SettingsPage(QDesignerOptionsPageInterface *designerPage) : - Core::IOptionsPage(nullptr, false), - m_designerPage(designerPage) + Core::IOptionsPage(nullptr, false) { - setId(Utils::Id::fromString(m_designerPage->name())); - setDisplayName(m_designerPage->name()); + setId(Utils::Id::fromString(designerPage->name())); + setDisplayName(designerPage->name()); setCategory(Designer::Constants::SETTINGS_CATEGORY); -} - -QWidget *SettingsPage::widget() -{ - m_initialized = true; - if (!m_widget) - m_widget = m_designerPage->createPage(nullptr); - return m_widget; - -} - -void SettingsPage::apply() -{ - if (m_initialized) - m_designerPage->apply(); -} - -void SettingsPage::finish() -{ - if (m_initialized) - m_designerPage->finish(); - delete m_widget; + setWidgetCreator([designerPage] { return new SettingsPageWidget(designerPage); }); } SettingsPageProvider::SettingsPageProvider() @@ -102,3 +98,5 @@ bool SettingsPageProvider::matches(const QRegularExpression ®ex) const } return false; } + +} // Designer::Internal diff --git a/src/plugins/designer/settingspage.h b/src/plugins/designer/settingspage.h index cdfb32c003c..5efc062fcba 100644 --- a/src/plugins/designer/settingspage.h +++ b/src/plugins/designer/settingspage.h @@ -5,32 +5,16 @@ #include -#include - QT_BEGIN_NAMESPACE class QDesignerOptionsPageInterface; QT_END_NAMESPACE -namespace Designer { -namespace Internal { - -class SettingsPageWidget; +namespace Designer::Internal { class SettingsPage : public Core::IOptionsPage { - Q_OBJECT - public: explicit SettingsPage(QDesignerOptionsPageInterface *designerPage); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - QDesignerOptionsPageInterface *m_designerPage; - bool m_initialized = false; - QPointer m_widget; }; class SettingsPageProvider : public Core::IOptionsPageProvider @@ -48,5 +32,4 @@ private: mutable QStringList m_keywords; }; -} // namespace Internal -} // namespace Designer +} // Designer::Internal From b1e65195acf69022a52453a133a35b3557d348e0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 13 Apr 2023 10:39:20 +0200 Subject: [PATCH 0649/1447] CppEditor/LanguageClient: Reuse MatcherType enum Change-Id: I95a8c902ddf6d7525543ccbc2acf45fe273a12f4 Reviewed-by: Christian Kandeler Reviewed-by: Reviewed-by: Qt CI Bot --- .../clangmodelmanagersupport.cpp | 26 +++++++--------- src/plugins/cppeditor/cpplocatorfilter.cpp | 29 ++++++++++++++--- src/plugins/cppeditor/cpplocatorfilter.h | 5 +-- src/plugins/cppeditor/cppmodelmanager.cpp | 20 +++++++----- src/plugins/languageclient/locatorfilter.cpp | 31 +++++++++++++++++-- src/plugins/languageclient/locatorfilter.h | 10 ++---- 6 files changed, 81 insertions(+), 40 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index c1d8b59196b..5b3b9fc783d 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -206,20 +206,18 @@ ClangModelManagerSupport::ClangModelManagerSupport() cppModelManager()->setClassesFilter(std::make_unique()); cppModelManager()->setFunctionsFilter(std::make_unique()); // Setup matchers - using WorkspaceMatcherCreator = std::function; - const auto matcherCreator = [](const WorkspaceMatcherCreator &creator) { - const QList clients = clientsForOpenProjects(); - LocatorMatcherTasks matchers; - for (Client *client : clients) - matchers << creator(client, 10000); - return matchers; - }; - LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, - [matcherCreator] { return matcherCreator(&LanguageClient::workspaceAllSymbolsMatcher); }); - LocatorMatcher::addMatcherCreator(MatcherType::Classes, - [matcherCreator] { return matcherCreator(&LanguageClient::workspaceClassMatcher); }); - LocatorMatcher::addMatcherCreator(MatcherType::Functions, - [matcherCreator] { return matcherCreator(&LanguageClient::workspaceFunctionMatcher); }); + LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, [] { + return LanguageClient::workspaceMatchers(clientsForOpenProjects(), MatcherType::AllSymbols, + 10000); + }); + LocatorMatcher::addMatcherCreator(MatcherType::Classes, [] { + return LanguageClient::workspaceMatchers(clientsForOpenProjects(), MatcherType::Classes, + 10000); + }); + LocatorMatcher::addMatcherCreator(MatcherType::Functions, [] { + return LanguageClient::workspaceMatchers(clientsForOpenProjects(), MatcherType::Functions, + 10000); + }); EditorManager *editorManager = EditorManager::instance(); connect(editorManager, &EditorManager::editorOpened, diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 0435f03c9ae..c7373d86bd7 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -113,7 +113,7 @@ LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex return {Async(onSetup), storage}; } -LocatorMatcherTask cppAllSymbolsMatcher() +LocatorMatcherTask allSymbolsMatcher() { const auto converter = [](const IndexItem::Ptr &info) { LocatorFilterEntry filterEntry; @@ -129,7 +129,7 @@ LocatorMatcherTask cppAllSymbolsMatcher() return locatorMatcher(IndexItem::All, converter); } -LocatorMatcherTask cppClassMatcher() +LocatorMatcherTask classMatcher() { const auto converter = [](const IndexItem::Ptr &info) { LocatorFilterEntry filterEntry; @@ -145,7 +145,7 @@ LocatorMatcherTask cppClassMatcher() return locatorMatcher(IndexItem::Class, converter); } -LocatorMatcherTask cppFunctionMatcher() +LocatorMatcherTask functionMatcher() { const auto converter = [](const IndexItem::Ptr &info) { QString name = info->symbolName(); @@ -296,7 +296,7 @@ FilePath currentFileName() return currentEditor ? currentEditor->document()->filePath() : FilePath(); } -LocatorMatcherTask cppCurrentDocumentMatcher() +LocatorMatcherTask currentDocumentMatcher() { using namespace Tasking; @@ -309,6 +309,27 @@ LocatorMatcherTask cppCurrentDocumentMatcher() return {Async(onSetup), storage}; } +using MatcherCreator = std::function; + +static MatcherCreator creatorForType(MatcherType type) +{ + switch (type) { + case MatcherType::AllSymbols: return &allSymbolsMatcher; + case MatcherType::Classes: return &classMatcher; + case MatcherType::Functions: return &functionMatcher; + case MatcherType::CurrentDocumentSymbols: return ¤tDocumentMatcher; + } + return {}; +} + +LocatorMatcherTasks cppMatchers(MatcherType type) +{ + const MatcherCreator creator = creatorForType(type); + if (!creator) + return {}; + return {creator()}; +} + CppLocatorFilter::CppLocatorFilter() { setId(Constants::LOCATOR_FILTER_ID); diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 33ebce05f41..2328fc06f8b 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -10,10 +10,7 @@ namespace CppEditor { -Core::LocatorMatcherTask CPPEDITOR_EXPORT cppAllSymbolsMatcher(); -Core::LocatorMatcherTask CPPEDITOR_EXPORT cppClassMatcher(); -Core::LocatorMatcherTask CPPEDITOR_EXPORT cppFunctionMatcher(); -Core::LocatorMatcherTask CPPEDITOR_EXPORT cppCurrentDocumentMatcher(); +Core::LocatorMatcherTasks CPPEDITOR_EXPORT cppMatchers(Core::MatcherType type); class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter { diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 17a702170e8..bc67f432f12 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -897,14 +897,18 @@ void CppModelManager::initCppTools() setSymbolsFindFilter(std::make_unique(this)); setCurrentDocumentFilter(std::make_unique()); // Setup matchers - LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, - [] { return QList{CppEditor::cppAllSymbolsMatcher()}; }); - LocatorMatcher::addMatcherCreator(MatcherType::Classes, - [] { return QList{CppEditor::cppClassMatcher()}; }); - LocatorMatcher::addMatcherCreator(MatcherType::Functions, - [] { return QList{CppEditor::cppFunctionMatcher()}; }); - LocatorMatcher::addMatcherCreator(MatcherType::CurrentDocumentSymbols, - [] { return QList{CppEditor::cppCurrentDocumentMatcher()}; }); + LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, [] { + return cppMatchers(MatcherType::AllSymbols); + }); + LocatorMatcher::addMatcherCreator(MatcherType::Classes, [] { + return cppMatchers(MatcherType::Classes); + }); + LocatorMatcher::addMatcherCreator(MatcherType::Functions, [] { + return cppMatchers(MatcherType::Functions); + }); + LocatorMatcher::addMatcherCreator(MatcherType::CurrentDocumentSymbols, [] { + return cppMatchers(MatcherType::CurrentDocumentSymbols); + }); } CppModelManager::CppModelManager() diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 0fe00c23879..8de4c7fe4d8 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -90,22 +90,47 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, return {root, storage}; } -LocatorMatcherTask workspaceAllSymbolsMatcher(Client *client, int maxResultCount) +LocatorMatcherTask allSymbolsMatcher(Client *client, int maxResultCount) { return locatorMatcher(client, maxResultCount, {}); } -LocatorMatcherTask workspaceClassMatcher(Client *client, int maxResultCount) +LocatorMatcherTask classMatcher(Client *client, int maxResultCount) { return locatorMatcher(client, maxResultCount, {SymbolKind::Class, SymbolKind::Struct}); } -LocatorMatcherTask workspaceFunctionMatcher(Client *client, int maxResultCount) +LocatorMatcherTask functionMatcher(Client *client, int maxResultCount) { return locatorMatcher(client, maxResultCount, {SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}); } +using MatcherCreator = std::function; + +static MatcherCreator creatorForType(MatcherType type) +{ + switch (type) { + case MatcherType::AllSymbols: return &allSymbolsMatcher; + case MatcherType::Classes: return &classMatcher; + case MatcherType::Functions: return &functionMatcher; + case MatcherType::CurrentDocumentSymbols: return {}; // TODO: implement me + } + return {}; +} + +LocatorMatcherTasks workspaceMatchers(const QList &clients, MatcherType type, + int maxResultCount) +{ + const MatcherCreator creator = creatorForType(type); + if (!creator) + return {}; + LocatorMatcherTasks matchers; + for (Client *client : clients) + matchers << creator(client, maxResultCount); + return matchers; +} + DocumentLocatorFilter::DocumentLocatorFilter() { setId(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_ID); diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 4a312599af9..fa59b7931cb 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -19,13 +19,9 @@ namespace Core { class IEditor; } namespace LanguageClient { -// TODO: Could be public methods of Client instead -Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceAllSymbolsMatcher(Client *client, - int maxResultCount = 0); -Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceClassMatcher(Client *client, - int maxResultCount = 0); -Core::LocatorMatcherTask LANGUAGECLIENT_EXPORT workspaceFunctionMatcher(Client *client, - int maxResultCount = 0); +Core::LocatorMatcherTasks LANGUAGECLIENT_EXPORT workspaceMatchers(const QList &clients, + Core::MatcherType type, + int maxResultCount = 0); class LanguageClientManager; From 2839d019b827f654cb8931ec228451fc07245c3d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 23 Apr 2023 10:34:37 +0200 Subject: [PATCH 0650/1447] LanguageClient: Use Q_DISABLE_COPY_MOVE Change-Id: Iee54086810442b64cb8b7aa68a48341909481787 Reviewed-by: David Schulz Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/languageclient/client.h | 6 +----- src/plugins/languageclient/languageclientinterface.h | 7 ++----- src/plugins/languageclient/languageclientmanager.h | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 51f72cc7d4a..27f48abc415 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -48,16 +48,12 @@ class SymbolSupport; class LANGUAGECLIENT_EXPORT Client : public QObject { Q_OBJECT + Q_DISABLE_COPY_MOVE(Client) public: explicit Client(BaseClientInterface *clientInterface, const Utils::Id &id = {}); // takes ownership ~Client() override; - Client(const Client &) = delete; - Client(Client &&) = delete; - Client &operator=(const Client &) = delete; - Client &operator=(Client &&) = delete; - // basic properties Utils::Id id() const; void setName(const QString &name); diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 79401f889a1..e0d4789e1d8 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -52,15 +52,12 @@ private: class LANGUAGECLIENT_EXPORT StdIOClientInterface : public BaseClientInterface { Q_OBJECT + Q_DISABLE_COPY_MOVE(StdIOClientInterface) + public: StdIOClientInterface(); ~StdIOClientInterface() override; - StdIOClientInterface(const StdIOClientInterface &) = delete; - StdIOClientInterface(StdIOClientInterface &&) = delete; - StdIOClientInterface &operator=(const StdIOClientInterface &) = delete; - StdIOClientInterface &operator=(StdIOClientInterface &&) = delete; - void startImpl() override; // These functions only have an effect if they are called before start diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index dd36da935e8..fdbbec98b6f 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -30,9 +30,9 @@ class LanguageClientMark; class LANGUAGECLIENT_EXPORT LanguageClientManager : public QObject { Q_OBJECT + Q_DISABLE_COPY_MOVE(LanguageClientManager) + public: - LanguageClientManager(const LanguageClientManager &other) = delete; - LanguageClientManager(LanguageClientManager &&other) = delete; ~LanguageClientManager() override; static void init(); From dfa1dafd490aabda9d3331ae1ebcec9b036d5814 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 23 Apr 2023 10:45:02 +0200 Subject: [PATCH 0651/1447] PerfProfiler: Use Q_DISABLE_COPY_MOVE Change-Id: I7abe582d2fb092bf87ac14690f588ae3524abc3d Reviewed-by: Qt CI Bot Reviewed-by: Ulf Hermann Reviewed-by: --- src/plugins/perfprofiler/perfprofilerflamegraphmodel.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h index d213bba0993..4347728536d 100644 --- a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h +++ b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h @@ -19,10 +19,9 @@ class PerfProfilerFlameGraphModel : public QAbstractItemModel Q_OBJECT QML_ELEMENT QML_UNCREATABLE("use the context property") - Q_DISABLE_COPY(PerfProfilerFlameGraphModel); + Q_DISABLE_COPY_MOVE(PerfProfilerFlameGraphModel); + public: - PerfProfilerFlameGraphModel(PerfProfilerFlameGraphModel &&) = delete; - PerfProfilerFlameGraphModel &operator=(PerfProfilerFlameGraphModel &&) = delete; enum Role { TypeIdRole = Qt::UserRole + 1, // Sort by data, not by displayed string From 9a1be79c0d4390e95c843b16520f38a0e2c83f9c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 20:12:57 +0200 Subject: [PATCH 0652/1447] LocatorWidget: Reuse LocatorMatcher in LocatorWidget Introduce QTC_USE_MATCHER env var temporarily. When this var is set, the locator will use LocatorMatcher internally. It's very hard to migrate all the matchesFor() implementations into the LocatorMatcherTask in one patch, so this var is going to be removed when all filters are migrated. Whenever a new patch providing the filter's migration is added, it may be tested by setting this env var. Add a temporary printout with info about which implementation is selected in runtime. Change-Id: If2d6006a89f3669ea4f6f8f171e59e00917419c4 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../coreplugin/locator/ilocatorfilter.h | 6 +- .../coreplugin/locator/locatorwidget.cpp | 77 ++++++++++++++++++- .../coreplugin/locator/locatorwidget.h | 2 + 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index e2866d17519..7c89b69ee35 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -22,7 +22,10 @@ namespace Utils::Tasking { class TaskItem; } namespace Core { -namespace Internal { class Locator; } +namespace Internal { +class Locator; +class LocatorWidget; +} class ILocatorFilter; class LocatorStoragePrivate; @@ -279,6 +282,7 @@ private: virtual LocatorMatcherTasks matchers() { return {}; } friend class Internal::Locator; + friend class Internal::LocatorWidget; static const QList allLocatorFilters(); Utils::Id m_id; diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 97ffcd8d4ba..01ea7f5b6ab 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,8 @@ const int LocatorEntryRole = int(HighlightingItemRole::User); namespace Core { namespace Internal { +static bool isUsingLocatorMatcher() { return qtcEnvironmentVariableIsSet("QTC_USE_MATCHER"); } + bool LocatorWidget::m_shuttingDown = false; QFuture LocatorWidget::m_sharedFuture; LocatorWidget *LocatorWidget::m_sharedFutureOrigin = nullptr; @@ -917,11 +920,80 @@ void LocatorWidget::setProgressIndicatorVisible(bool visible) m_progressIndicator->show(); } +void LocatorWidget::runMatcher(const QString &text) +{ + QString searchText; + const QList filters = filtersFor(text, searchText); + + LocatorMatcherTasks tasks; + for (ILocatorFilter *filter : filters) + tasks += filter->matchers(); + + m_locatorMatcher.reset(new LocatorMatcher); + m_locatorMatcher->setTasks(tasks); + m_locatorMatcher->setInputData(searchText); + + connect(m_locatorMatcher.get(), &LocatorMatcher::done, this, [this] { + m_showProgressTimer.stop(); + setProgressIndicatorVisible(false); + m_updateRequested = false; + m_locatorMatcher.release()->deleteLater(); + if (m_rowRequestedForAccept) { + acceptEntry(m_rowRequestedForAccept.value()); + m_rowRequestedForAccept.reset(); + return; + } + if (m_needsClearResult) { + m_locatorModel->clear(); + m_needsClearResult = false; + } + }); + connect(m_locatorMatcher.get(), &LocatorMatcher::serialOutputDataReady, + this, [this](const LocatorFilterEntries &serialOutputData) { + if (m_needsClearResult) { + m_locatorModel->clear(); + m_needsClearResult = false; + } + const bool selectFirst = m_locatorModel->rowCount() == 0; + m_locatorModel->addEntries(serialOutputData); + if (selectFirst) { + emit selectRow(0); + if (m_rowRequestedForAccept) + m_rowRequestedForAccept = 0; + } + }); + + m_showProgressTimer.start(); + m_needsClearResult = true; + m_updateRequested = true; + m_locatorMatcher->start(); +} + +// TODO: Remove when switched the default into new implementation. +static void printMatcherInfo() +{ + static bool printed = false; + if (printed) + return; + if (isUsingLocatorMatcher()) + qDebug() << "QTC_USE_MATCHER env var set, using new LocatorMatcher implementation."; + else + qDebug() << "QTC_USE_MATCHER env var not set, using old matchesFor implementation."; + printed = true; +} + void LocatorWidget::updateCompletionList(const QString &text) { if (m_shuttingDown) return; + printMatcherInfo(); + + if (isUsingLocatorMatcher()) { + runMatcher(text); + return; + } + m_updateRequested = true; if (m_sharedFuture.isRunning()) { // Cancel the old future. We may not just block the UI thread to wait for the search to @@ -987,7 +1059,10 @@ void LocatorWidget::scheduleAcceptEntry(const QModelIndex &index) // accept will be called after the update finished m_rowRequestedForAccept = index.row(); // do not wait for the rest of the search to finish - m_entriesWatcher->future().cancel(); + if (isUsingLocatorMatcher()) + m_locatorMatcher.reset(); + else + m_entriesWatcher->future().cancel(); } else { acceptEntry(index.row()); } diff --git a/src/plugins/coreplugin/locator/locatorwidget.h b/src/plugins/coreplugin/locator/locatorwidget.h index efc90c3a517..4f6c1560ce5 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.h +++ b/src/plugins/coreplugin/locator/locatorwidget.h @@ -69,6 +69,7 @@ private: void updatePreviousFocusWidget(QWidget *previous, QWidget *current); bool eventFilter(QObject *obj, QEvent *event) override; + void runMatcher(const QString &text); void updateCompletionList(const QString &text); static QList filtersFor(const QString &text, QString &searchText); void setProgressIndicatorVisible(bool visible); @@ -95,6 +96,7 @@ private: QTimer m_showProgressTimer; std::optional m_rowRequestedForAccept; QPointer m_previousFocusWidget; + std::unique_ptr m_locatorMatcher; }; class LocatorPopup : public QWidget From bb9ba4349af79519a72f36148d68fd65761162f2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 23 Apr 2023 10:02:04 +0200 Subject: [PATCH 0653/1447] Utils: Use Q_DISABLE_COPY / Q_DISABLE_COPY_MOVE Change-Id: If9ea6220700769cd99ede3ebaacc4d75cb673e89 Reviewed-by: Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/utils/delegates.h | 8 ++------ src/libs/utils/layoutbuilder.h | 4 ++-- src/libs/utils/terminalhooks.h | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/libs/utils/delegates.h b/src/libs/utils/delegates.h index 97f1c774c38..ff012152f5f 100644 --- a/src/libs/utils/delegates.h +++ b/src/libs/utils/delegates.h @@ -62,18 +62,14 @@ private: class QTCREATOR_UTILS_EXPORT CompleterDelegate : public QStyledItemDelegate { + Q_DISABLE_COPY_MOVE(CompleterDelegate) + public: CompleterDelegate(const QStringList &candidates, QObject *parent = nullptr); CompleterDelegate(QAbstractItemModel *model, QObject *parent = nullptr); CompleterDelegate(QCompleter *completer, QObject *parent = nullptr); ~CompleterDelegate() override; - CompleterDelegate(const CompleterDelegate &other) = delete; - CompleterDelegate(CompleterDelegate &&other) = delete; - - CompleterDelegate &operator=(const CompleterDelegate &other) = delete; - CompleterDelegate &operator=(CompleterDelegate &&other) = delete; - QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 2f534cb488d..d34a8f6cf44 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -162,6 +162,8 @@ QTCREATOR_UTILS_EXPORT QWidget *createHr(QWidget *parent = nullptr); class QTCREATOR_UTILS_EXPORT LayoutBuilder { + Q_DISABLE_COPY(LayoutBuilder) + public: enum LayoutType { HBoxLayout, @@ -175,9 +177,7 @@ public: explicit LayoutBuilder(LayoutType layoutType, const LayoutItems &items = {}); - LayoutBuilder(const LayoutBuilder &) = delete; LayoutBuilder(LayoutBuilder &&) = default; - LayoutBuilder &operator=(const LayoutBuilder &) = delete; LayoutBuilder &operator=(LayoutBuilder &&) = default; ~LayoutBuilder(); diff --git a/src/libs/utils/terminalhooks.h b/src/libs/utils/terminalhooks.h index 5a614400f4f..b37c51517c0 100644 --- a/src/libs/utils/terminalhooks.h +++ b/src/libs/utils/terminalhooks.h @@ -17,15 +17,13 @@ class ProcessInterface; template class Hook { + Q_DISABLE_COPY_MOVE(Hook) + public: using Callback = std::function; public: Hook() = delete; - Hook(const Hook &other) = delete; - Hook(Hook &&other) = delete; - Hook &operator=(const Hook &other) = delete; - Hook &operator=(Hook &&other) = delete; explicit Hook(Callback defaultCallback) { set(defaultCallback); } From e9ae45bfccecb2ab890b7fe9e497d34f2b985bed Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 18 Apr 2023 01:42:42 +0200 Subject: [PATCH 0654/1447] FileSystemFilter: Reimplement matchers() Change-Id: I47547713cadfe9aa1212336ffbfbdace3dd84430 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- .../coreplugin/locator/filesystemfilter.cpp | 173 +++++++++++++++--- .../coreplugin/locator/filesystemfilter.h | 2 +- 2 files changed, 148 insertions(+), 27 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 37b3ede81dd..a878bab74d1 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -3,12 +3,14 @@ #include "filesystemfilter.h" +#include "../coreplugin.h" #include "../coreplugintr.h" #include "../documentmanager.h" #include "../editormanager/editormanager.h" #include "../icore.h" #include "../vcsmanager.h" +#include #include #include #include @@ -30,42 +32,24 @@ using namespace Utils; namespace Core { namespace Internal { -ILocatorFilter::MatchLevel FileSystemFilter::matchLevelFor(const QRegularExpressionMatch &match, - const QString &matchText) +static const char kAlwaysCreate[] = "Locator/FileSystemFilter/AlwaysCreate"; + +static ILocatorFilter::MatchLevel matchLevelFor(const QRegularExpressionMatch &match, + const QString &matchText) { const int consecutivePos = match.capturedStart(1); if (consecutivePos == 0) - return MatchLevel::Best; + return ILocatorFilter::MatchLevel::Best; if (consecutivePos > 0) { const QChar prevChar = matchText.at(consecutivePos - 1); if (prevChar == '_' || prevChar == '.') - return MatchLevel::Better; + return ILocatorFilter::MatchLevel::Better; } if (match.capturedStart() == 0) - return MatchLevel::Good; - return MatchLevel::Normal; + return ILocatorFilter::MatchLevel::Good; + return ILocatorFilter::MatchLevel::Normal; } -FileSystemFilter::FileSystemFilter() -{ - setId("Files in file system"); - setDisplayName(Tr::tr("Files in File System")); - setDescription(Tr::tr("Opens a file given by a relative path to the current document, or absolute " - "path. \"~\" refers to your home directory. You have the option to create a " - "file if it does not exist yet.")); - setDefaultShortcutString("f"); - setDefaultIncludedByDefault(false); -} - -void FileSystemFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - m_currentDocumentDirectory = DocumentManager::fileDialogInitialDirectory(); - m_currentIncludeHidden = m_includeHidden; -} - -static const char kAlwaysCreate[] = "Locator/FileSystemFilter/AlwaysCreate"; - static void createAndOpen(const FilePath &filePath) { if (!filePath.exists()) { @@ -95,6 +79,143 @@ static void createAndOpen(const FilePath &filePath) EditorManager::openEditor(filePath); } +FileSystemFilter::FileSystemFilter() +{ + setId("Files in file system"); + setDisplayName(Tr::tr("Files in File System")); + setDescription(Tr::tr("Opens a file given by a relative path to the current document, or absolute " + "path. \"~\" refers to your home directory. You have the option to create a " + "file if it does not exist yet.")); + setDefaultShortcutString("f"); + setDefaultIncludedByDefault(false); +} + +static void matches(QPromise &promise, const LocatorStorage &storage, + const QString &shortcutString, const FilePath ¤tDocumentDir, + bool includeHidden) +{ + const QString input = storage.input(); + LocatorFilterEntries entries[int(ILocatorFilter::MatchLevel::Count)]; + + const Environment env = Environment::systemEnvironment(); + const QString expandedEntry = env.expandVariables(input); + const auto expandedEntryPath = FilePath::fromUserInput(expandedEntry); + const auto absoluteEntryPath = currentDocumentDir.isEmpty() ? expandedEntryPath + : currentDocumentDir.resolvePath(expandedEntryPath); + + // Consider the entered path a directory if it ends with slash/backslash. + // If it is a dir but doesn't end with a backslash, we want to still show all (other) matching + // items from the same parent directory. + // Unfortunately fromUserInput removes slash/backslash at the end, so manually check the original. + const bool isDir = expandedEntry.isEmpty() || expandedEntry.endsWith('/') + || expandedEntry.endsWith('\\'); + const FilePath directory = isDir ? absoluteEntryPath : absoluteEntryPath.parentDir(); + const QString entryFileName = isDir ? QString() : absoluteEntryPath.fileName(); + + QDir::Filters dirFilter = QDir::Dirs | QDir::Drives | QDir::NoDot | QDir::NoDotDot; + QDir::Filters fileFilter = QDir::Files; + if (includeHidden) { + dirFilter |= QDir::Hidden; + fileFilter |= QDir::Hidden; + } + // use only 'name' for case sensitivity decision, because we need to make the path + // match the case on the file system for case-sensitive file systems + const Qt::CaseSensitivity caseSensitivity = ILocatorFilter::caseSensitivity(entryFileName); + const FilePaths dirs = FilePaths({directory / ".."}) + + directory.dirEntries({{}, dirFilter}, + QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); + const FilePaths files = directory.dirEntries({{}, fileFilter}, + QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); + + QRegularExpression regExp = ILocatorFilter::createRegExp(entryFileName, caseSensitivity); + if (!regExp.isValid()) + return; + + for (const FilePath &dir : dirs) { + if (promise.isCanceled()) + return; + + const QString dirString = dir.relativeChildPath(directory).nativePath(); + const QRegularExpressionMatch match = regExp.match(dirString); + if (match.hasMatch()) { + const ILocatorFilter::MatchLevel level = matchLevelFor(match, dirString); + LocatorFilterEntry filterEntry; + filterEntry.displayName = dirString; + filterEntry.acceptor = [shortcutString, dir] { + const QString value = shortcutString + ' ' + + dir.absoluteFilePath().cleanPath().pathAppended("/").toUserOutput(); + return AcceptResult{value, int(value.length())}; + }; + filterEntry.filePath = dir; + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + + entries[int(level)].append(filterEntry); + } + } + // file names can match with +linenumber or :linenumber + const Link link = Link::fromString(entryFileName, true); + regExp = ILocatorFilter::createRegExp(link.targetFilePath.toString(), caseSensitivity); + if (!regExp.isValid()) + return; + for (const FilePath &file : files) { + if (promise.isCanceled()) + return; + + const QString fileString = file.relativeChildPath(directory).nativePath(); + const QRegularExpressionMatch match = regExp.match(fileString); + if (match.hasMatch()) { + const ILocatorFilter::MatchLevel level = matchLevelFor(match, fileString); + LocatorFilterEntry filterEntry; + filterEntry.displayName = fileString; + filterEntry.filePath = file; + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + filterEntry.linkForEditor = Link(filterEntry.filePath, link.targetLine, + link.targetColumn); + entries[int(level)].append(filterEntry); + } + } + + // "create and open" functionality + const FilePath fullFilePath = directory / entryFileName; + const bool containsWildcard = expandedEntry.contains('?') || expandedEntry.contains('*'); + if (!containsWildcard && !fullFilePath.exists() && directory.exists()) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = Tr::tr("Create and Open \"%1\"").arg(expandedEntry); + filterEntry.acceptor = [fullFilePath] { + QMetaObject::invokeMethod(EditorManager::instance(), + [fullFilePath] { createAndOpen(fullFilePath); }, Qt::QueuedConnection); + return AcceptResult(); + }; + filterEntry.filePath = fullFilePath; + filterEntry.extraInfo = directory.absoluteFilePath().shortNativePath(); + entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); + } + storage.reportOutput(std::accumulate(std::begin(entries), std::end(entries), + LocatorFilterEntries())); +} + +LocatorMatcherTasks FileSystemFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [this, storage](AsyncTask &async) { + async.setFutureSynchronizer(CorePlugin::futureSynchronizer()); + async.setConcurrentCallData(matches, *storage, shortcutString(), + DocumentManager::fileDialogInitialDirectory(), m_includeHidden); + }; + + return {{Async(onSetup), storage}}; +} + +void FileSystemFilter::prepareSearch(const QString &entry) +{ + Q_UNUSED(entry) + m_currentDocumentDirectory = DocumentManager::fileDialogInitialDirectory(); + m_currentIncludeHidden = m_includeHidden; +} + QList FileSystemFilter::matchesFor(QFutureInterface &future, const QString &entry) { diff --git a/src/plugins/coreplugin/locator/filesystemfilter.h b/src/plugins/coreplugin/locator/filesystemfilter.h index f2983ad40af..20f6ecd1486 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.h +++ b/src/plugins/coreplugin/locator/filesystemfilter.h @@ -30,7 +30,7 @@ protected: void restoreState(const QJsonObject &object) final; private: - static MatchLevel matchLevelFor(const QRegularExpressionMatch &match, const QString &matchText); + LocatorMatcherTasks matchers() final; static const bool kIncludeHiddenDefault = true; bool m_includeHidden = kIncludeHiddenDefault; From 90c09c65f9e478474cda224c8d5ad4385e12bd91 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 09:27:47 +0200 Subject: [PATCH 0655/1447] DiffEditor: Fix jumping to context line immediately on git show Fixes: QTCREATORBUG-29081 Change-Id: I7a4658209f95e98cb485e725dee07074dae5c163 Reviewed-by: Orgad Shaneh --- src/plugins/diffeditor/diffeditor.cpp | 85 +++++++++---------- src/plugins/diffeditor/diffeditor.h | 1 + src/plugins/diffeditor/diffview.cpp | 27 +++--- src/plugins/diffeditor/diffview.h | 9 +- .../vcsbase/vcsbasediffeditorcontroller.cpp | 1 + 5 files changed, 61 insertions(+), 62 deletions(-) diff --git a/src/plugins/diffeditor/diffeditor.cpp b/src/plugins/diffeditor/diffeditor.cpp index 5274214f92b..929c30c3398 100644 --- a/src/plugins/diffeditor/diffeditor.cpp +++ b/src/plugins/diffeditor/diffeditor.cpp @@ -185,7 +185,7 @@ DiffEditor::DiffEditor() policy.setHorizontalPolicy(QSizePolicy::Expanding); m_entriesComboBox->setSizePolicy(policy); connect(m_entriesComboBox, &QComboBox::currentIndexChanged, - this, &DiffEditor::setCurrentDiffFileIndex); + this, &DiffEditor::currentIndexChanged); m_toolBar->addWidget(m_entriesComboBox); QLabel *contextLabel = new QLabel(m_toolBar); @@ -309,7 +309,6 @@ TextEditorWidget *DiffEditor::sideEditorWidget(DiffSide side) const return m_sideBySideView->sideEditorWidget(side); } - void DiffEditor::documentHasChanged() { GuardLocker guard(m_ignoreChanges); @@ -319,7 +318,10 @@ void DiffEditor::documentHasChanged() currentView()->setDiff(diffFileList); m_entriesComboBox->clear(); - for (const FileData &diffFile : diffFileList) { + const QString startupFile = m_document->startupFile(); + int startupFileIndex = -1; + for (int i = 0, total = diffFileList.count(); i < total; ++i) { + const FileData &diffFile = diffFileList.at(i); const DiffFileInfo &leftEntry = diffFile.fileInfo[LeftSide]; const DiffFileInfo &rightEntry = diffFile.fileInfo[RightSide]; const QString leftShortFileName = FilePath::fromString(leftEntry.fileName).fileName(); @@ -332,30 +334,20 @@ void DiffEditor::documentHasChanged() if (leftEntry.typeInfo.isEmpty() && rightEntry.typeInfo.isEmpty()) { itemToolTip = leftEntry.fileName; } else { - itemToolTip = Tr::tr("[%1] vs. [%2] %3") - .arg(leftEntry.typeInfo, - rightEntry.typeInfo, - leftEntry.fileName); + itemToolTip = Tr::tr("[%1] vs. [%2] %3").arg( + leftEntry.typeInfo, rightEntry.typeInfo, leftEntry.fileName); } } else { - if (leftShortFileName == rightShortFileName) { + if (leftShortFileName == rightShortFileName) itemText = leftShortFileName; - } else { - itemText = Tr::tr("%1 vs. %2") - .arg(leftShortFileName, - rightShortFileName); - } + else + itemText = Tr::tr("%1 vs. %2").arg(leftShortFileName, rightShortFileName); if (leftEntry.typeInfo.isEmpty() && rightEntry.typeInfo.isEmpty()) { - itemToolTip = Tr::tr("%1 vs. %2") - .arg(leftEntry.fileName, - rightEntry.fileName); + itemToolTip = Tr::tr("%1 vs. %2").arg(leftEntry.fileName, rightEntry.fileName); } else { - itemToolTip = Tr::tr("[%1] %2 vs. [%3] %4") - .arg(leftEntry.typeInfo, - leftEntry.fileName, - rightEntry.typeInfo, - rightEntry.fileName); + itemToolTip = Tr::tr("[%1] %2 vs. [%3] %4").arg(leftEntry.typeInfo, + leftEntry.fileName, rightEntry.typeInfo, rightEntry.fileName); } } m_entriesComboBox->addItem(itemText); @@ -365,7 +357,21 @@ void DiffEditor::documentHasChanged() rightEntry.fileName, Qt::UserRole + 1); m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1, itemToolTip, Qt::ToolTipRole); + if (startupFileIndex < 0) { + const bool isStartup = m_currentFileChunk.first.isEmpty() + && m_currentFileChunk.second.isEmpty() + && startupFile.endsWith(rightEntry.fileName); + const bool isSame = m_currentFileChunk.first == leftEntry.fileName + && m_currentFileChunk.second == rightEntry.fileName; + if (isStartup || isSame) + startupFileIndex = i; + } } + + currentView()->endOperation(); + m_currentFileChunk = {}; + if (startupFileIndex >= 0) + setCurrentDiffFileIndex(startupFileIndex); } void DiffEditor::toggleDescription() @@ -439,6 +445,7 @@ void DiffEditor::prepareForReload() m_whitespaceButtonAction->setChecked(m_document->ignoreWhitespace()); } currentView()->beginOperation(); + currentView()->setMessage(Tr::tr("Waiting for data...")); } void DiffEditor::reloadHasFinished(bool success) @@ -446,29 +453,8 @@ void DiffEditor::reloadHasFinished(bool success) if (!currentView()) return; - currentView()->endOperation(success); - - int index = -1; - const QString startupFile = m_document->startupFile(); - const QList &diffFileList = m_document->diffFiles(); - const int count = diffFileList.count(); - for (int i = 0; i < count; i++) { - const FileData &diffFile = diffFileList.at(i); - const DiffFileInfo &leftEntry = diffFile.fileInfo[LeftSide]; - const DiffFileInfo &rightEntry = diffFile.fileInfo[RightSide]; - if ((m_currentFileChunk.first.isEmpty() - && m_currentFileChunk.second.isEmpty() - && startupFile.endsWith(rightEntry.fileName)) - || (m_currentFileChunk.first == leftEntry.fileName - && m_currentFileChunk.second == rightEntry.fileName)) { - index = i; - break; - } - } - - m_currentFileChunk = {}; - if (index >= 0) - setCurrentDiffFileIndex(index); + if (!success) + currentView()->setMessage(Tr::tr("Retrieving data failed.")); } void DiffEditor::updateEntryToolTip() @@ -478,14 +464,19 @@ void DiffEditor::updateEntryToolTip() m_entriesComboBox->setToolTip(toolTip); } -void DiffEditor::setCurrentDiffFileIndex(int index) +void DiffEditor::currentIndexChanged(int index) { if (m_ignoreChanges.isLocked()) return; + GuardLocker guard(m_ignoreChanges); + setCurrentDiffFileIndex(index); +} + +void DiffEditor::setCurrentDiffFileIndex(int index) +{ QTC_ASSERT((index < 0) != (m_entriesComboBox->count() > 0), return); - GuardLocker guard(m_ignoreChanges); m_currentDiffFileIndex = index; currentView()->setCurrentDiffFileIndex(index); @@ -563,7 +554,7 @@ void DiffEditor::addView(IDiffView *view) if (m_views.count() == 1) setCurrentView(view); - connect(view, &IDiffView::currentDiffFileIndexChanged, this, &DiffEditor::setCurrentDiffFileIndex); + connect(view, &IDiffView::currentDiffFileIndexChanged, this, &DiffEditor::currentIndexChanged); } IDiffView *DiffEditor::currentView() const diff --git a/src/plugins/diffeditor/diffeditor.h b/src/plugins/diffeditor/diffeditor.h index a801ee953b2..49922d323eb 100644 --- a/src/plugins/diffeditor/diffeditor.h +++ b/src/plugins/diffeditor/diffeditor.h @@ -53,6 +53,7 @@ private: void ignoreWhitespaceHasChanged(); void prepareForReload(); void reloadHasFinished(bool success); + void currentIndexChanged(int index); void setCurrentDiffFileIndex(int index); void documentStateChanged(); diff --git a/src/plugins/diffeditor/diffview.cpp b/src/plugins/diffeditor/diffview.cpp index 8ff444066ac..686f9798b23 100644 --- a/src/plugins/diffeditor/diffview.cpp +++ b/src/plugins/diffeditor/diffview.cpp @@ -117,7 +117,6 @@ void UnifiedView::beginOperation() DiffEditorDocument *document = m_widget->diffDocument(); if (document && document->state() == DiffEditorDocument::LoadOK) m_widget->saveState(); - m_widget->clear(Tr::tr("Waiting for data...")); } void UnifiedView::setDiff(const QList &diffFileList) @@ -126,13 +125,15 @@ void UnifiedView::setDiff(const QList &diffFileList) m_widget->setDiff(diffFileList); } -void UnifiedView::endOperation(bool success) +void UnifiedView::setMessage(const QString &message) +{ + m_widget->clear(message); +} + +void UnifiedView::endOperation() { QTC_ASSERT(m_widget, return); - if (success) - m_widget->restoreState(); - else - m_widget->clear(Tr::tr("Retrieving data failed.")); + m_widget->restoreState(); } void UnifiedView::setCurrentDiffFileIndex(int index) @@ -197,7 +198,6 @@ void SideBySideView::beginOperation() DiffEditorDocument *document = m_widget->diffDocument(); if (document && document->state() == DiffEditorDocument::LoadOK) m_widget->saveState(); - m_widget->clear(Tr::tr("Waiting for data...")); } void SideBySideView::setCurrentDiffFileIndex(int index) @@ -212,13 +212,16 @@ void SideBySideView::setDiff(const QList &diffFileList) m_widget->setDiff(diffFileList); } -void SideBySideView::endOperation(bool success) +void SideBySideView::setMessage(const QString &message) { QTC_ASSERT(m_widget, return); - if (success) - m_widget->restoreState(); - else - m_widget->clear(Tr::tr("Retrieving data failed.")); + m_widget->clear(message); +} + +void SideBySideView::endOperation() +{ + QTC_ASSERT(m_widget, return); + m_widget->restoreState(); } void SideBySideView::setSync(bool sync) diff --git a/src/plugins/diffeditor/diffview.h b/src/plugins/diffeditor/diffview.h index b1e4f21227f..9028f83c636 100644 --- a/src/plugins/diffeditor/diffview.h +++ b/src/plugins/diffeditor/diffview.h @@ -44,7 +44,8 @@ public: virtual void beginOperation() = 0; virtual void setCurrentDiffFileIndex(int index) = 0; virtual void setDiff(const QList &diffFileList) = 0; - virtual void endOperation(bool success) = 0; + virtual void setMessage(const QString &message) = 0; + virtual void endOperation() = 0; virtual void setSync(bool) = 0; @@ -81,7 +82,8 @@ public: void beginOperation() override; void setCurrentDiffFileIndex(int index) override; void setDiff(const QList &diffFileList) override; - void endOperation(bool success) override; + void setMessage(const QString &message) override; + void endOperation() override; void setSync(bool sync) override; @@ -104,7 +106,8 @@ public: void beginOperation() override; void setCurrentDiffFileIndex(int index) override; void setDiff(const QList &diffFileList) override; - void endOperation(bool success) override; + void setMessage(const QString &message) override; + void endOperation() override; void setSync(bool sync) override; diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index 65e425cf64b..dbc220302b3 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -57,6 +57,7 @@ Tasking::TaskItem VcsBaseDiffEditorController::postProcessTask() }; const auto onDiffProcessorDone = [this](const AsyncTask> &async) { setDiffFiles(async.isResultAvailable() ? async.result() : QList()); + // TODO: We should set the right starting line here }; const auto onDiffProcessorError = [this](const AsyncTask> &) { setDiffFiles({}); From 21c71cded7be1f19aefa4b3932a7d695d4f3ecb4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 18:02:55 +0200 Subject: [PATCH 0656/1447] DocumentLocatorFilter: Make internals reusable in LocatorMatcher Prepare for LocatorMatcher implementation. Change-Id: I3d78045a06c8ebefacb033f0eabb5f7a2457ab06 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- .../clangcodemodel/clangdlocatorfilters.cpp | 12 ++-- src/plugins/languageclient/locatorfilter.cpp | 61 +++++++++---------- src/plugins/languageclient/locatorfilter.h | 17 ++---- 3 files changed, 38 insertions(+), 52 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 19fab25d0c7..973156c038a 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -218,25 +218,23 @@ private: }; QList docEntries; - const auto docSymbolGenerator = [&](const DocumentSymbol &info, - const LocatorFilterEntry &parent) { - LocatorFilterEntry entry; + const auto docSymbolModifier = [&docEntries](LocatorFilterEntry &entry, + const DocumentSymbol &info, + const LocatorFilterEntry &parent) { entry.displayName = ClangdClient::displayNameFromDocumentSymbol( static_cast(info.kind()), info.name(), info.detail().value_or(QString())); - entry.linkForEditor = linkForDocSymbol(info); entry.extraInfo = parent.extraInfo; if (!entry.extraInfo.isEmpty()) entry.extraInfo.append("::"); entry.extraInfo.append(parent.displayName); // TODO: Can we extend clangd to send visibility information? - entry.displayIcon = LanguageClient::symbolIcon(info.kind()); docEntries.append({entry, info}); - return entry; }; - QList allMatches = matchesForImpl(future, entry, docSymbolGenerator); + const QList allMatches = matchesForImpl(future, entry, + docSymbolModifier); if (docEntries.isEmpty()) return allMatches; // SymbolInformation case diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 8de4c7fe4d8..324a1cec338 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -190,8 +190,8 @@ void DocumentLocatorFilter::resetSymbols() m_currentSymbols.reset(); } -static LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, - DocumentUri::PathMapper pathMapper) +static LocatorFilterEntry entryForSymbolInfo(const SymbolInformation &info, + DocumentUri::PathMapper pathMapper) { LocatorFilterEntry entry; entry.displayName = info.name(); @@ -202,30 +202,37 @@ static LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, return entry; } -QList DocumentLocatorFilter::entriesForSymbolsInfo( - const QList &infoList, const QRegularExpression ®exp) +LocatorFilterEntries entriesForSymbolsInfo(const QList &infoList, + const QRegularExpression ®exp, const DocumentUri::PathMapper &pathMapper) { - QTC_ASSERT(m_pathMapper, return {}); - QList entries; + QTC_ASSERT(pathMapper, return {}); + LocatorFilterEntries entries; for (const SymbolInformation &info : infoList) { if (regexp.match(info.name()).hasMatch()) - entries << LanguageClient::generateLocatorEntry(info, m_pathMapper); + entries << LanguageClient::entryForSymbolInfo(info, pathMapper); } return entries; } -QList DocumentLocatorFilter::entriesForDocSymbols( - const QList &infoList, const QRegularExpression ®exp, - const DocSymbolGenerator &docSymbolGenerator, const LocatorFilterEntry &parent) +LocatorFilterEntries entriesForDocSymbols(const QList &infoList, + const QRegularExpression ®exp, const FilePath &filePath, + const DocSymbolModifier &docSymbolModifier, const LocatorFilterEntry &parent = {}) { - QList entries; + LocatorFilterEntries entries; for (const DocumentSymbol &info : infoList) { const QList children = info.children().value_or(QList()); const bool hasMatch = regexp.match(info.name()).hasMatch(); - const LocatorFilterEntry entry = hasMatch ? docSymbolGenerator(info, parent) : parent; - if (hasMatch) + LocatorFilterEntry entry; + if (hasMatch) { + entry.displayIcon = LanguageClient::symbolIcon(info.kind()); + const Position &pos = info.range().start(); + entry.linkForEditor = {filePath, pos.line() + 1, pos.character()}; + docSymbolModifier(entry, info, parent); entries << entry; - entries << entriesForDocSymbols(children, regexp, docSymbolGenerator, entry); + } else { + entry = parent; + } + entries << entriesForDocSymbols(children, regexp, filePath, docSymbolModifier, entry); } return entries; } @@ -243,29 +250,19 @@ void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) QList DocumentLocatorFilter::matchesFor( QFutureInterface &future, const QString &entry) { - const auto docSymbolGenerator = [this](const DocumentSymbol &info, - const LocatorFilterEntry &parent) { + const auto docSymbolModifier = [](LocatorFilterEntry &entry, const DocumentSymbol &info, + const LocatorFilterEntry &parent) { Q_UNUSED(parent) - LocatorFilterEntry entry; entry.displayName = info.name(); if (std::optional detail = info.detail()) - entry.extraInfo = detail.value_or(QString()); - entry.displayIcon = symbolIcon(info.kind()); - entry.linkForEditor = linkForDocSymbol(info); - return entry; + entry.extraInfo = *detail; }; - return matchesForImpl(future, entry, docSymbolGenerator); -} - -Link DocumentLocatorFilter::linkForDocSymbol(const DocumentSymbol &info) const -{ - const Position &pos = info.range().start(); - return {m_currentFilePath, pos.line() + 1, pos.character()}; + return matchesForImpl(future, entry, docSymbolModifier); } QList DocumentLocatorFilter::matchesForImpl( QFutureInterface &future, const QString &entry, - const DocSymbolGenerator &docSymbolGenerator) + const DocSymbolModifier &docSymbolModifier) { const FuzzyMatcher::CaseSensitivity caseSensitivity = ILocatorFilter::caseSensitivity(entry) == Qt::CaseSensitive @@ -293,9 +290,9 @@ QList DocumentLocatorFilter::matchesForImpl( QTC_ASSERT(m_currentSymbols.has_value(), return {}); if (auto list = std::get_if>(&*m_currentSymbols)) - return entriesForDocSymbols(*list, regExp, docSymbolGenerator); + return entriesForDocSymbols(*list, regExp, m_currentFilePath, docSymbolModifier); else if (auto list = std::get_if>(&*m_currentSymbols)) - return entriesForSymbolsInfo(*list, regExp); + return entriesForSymbolsInfo(*list, regExp, m_pathMapper); return {}; } @@ -381,7 +378,7 @@ QList WorkspaceLocatorFilter::matchesFor( }); } auto generateEntry = [](const SymbolInfoWithPathMapper &info) { - return generateLocatorEntry(info.symbol, info.mapper); + return entryForSymbolInfo(info.symbol, info.mapper); }; return Utils::transform(m_results, generateEntry).toList(); } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index fa59b7931cb..52445e19c38 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -19,6 +19,9 @@ namespace Core { class IEditor; } namespace LanguageClient { +using DocSymbolModifier = std::function; + Core::LocatorMatcherTasks LANGUAGECLIENT_EXPORT workspaceMatchers(const QList &clients, Core::MatcherType type, int maxResultCount = 0); @@ -42,13 +45,9 @@ protected: Utils::FilePath m_currentFilePath; - using DocSymbolGenerator = std::function; - - Utils::Link linkForDocSymbol(const LanguageServerProtocol::DocumentSymbol &info) const; QList matchesForImpl( QFutureInterface &future, const QString &entry, - const DocSymbolGenerator &docSymbolGenerator); + const DocSymbolModifier &docSymbolModifier); private: void updateCurrentClient(); @@ -56,14 +55,6 @@ private: const LanguageServerProtocol::DocumentSymbolsResult &symbols); void resetSymbols(); - QList entriesForSymbolsInfo( - const QList &infoList, - const QRegularExpression ®exp); - QList entriesForDocSymbols( - const QList &infoList, - const QRegularExpression ®exp, const DocSymbolGenerator &docSymbolGenerator, - const Core::LocatorFilterEntry &parent = {}); - QMutex m_mutex; QMetaObject::Connection m_updateSymbolsConnection; QMetaObject::Connection m_resetSymbolsConnection; From afcbe845ceec7aaf5fd4a5213ba1370183629a4f Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 18 Apr 2023 15:09:01 +0200 Subject: [PATCH 0657/1447] Copilot: Add setting for automatic completion Can be used to turn off the automatic completion insertion, so a user only can request suggestions explicitly via the shortcut. Change-Id: I0c4d9e2f41d30312b0870facdd80dc1d3d03d809 Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotclient.cpp | 3 +++ src/plugins/copilot/copilotoptionspage.cpp | 1 + src/plugins/copilot/copilotsettings.cpp | 7 +++++++ src/plugins/copilot/copilotsettings.h | 1 + 4 files changed, 12 insertions(+) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 5d2a6aa4b7b..5ea53b1d7c8 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "copilotclient.h" +#include "copilotsettings.h" #include "copilotsuggestion.h" #include @@ -80,6 +81,8 @@ void CopilotClient::openDocument(TextDocument *document) this, [this, document](int position, int charsRemoved, int charsAdded) { Q_UNUSED(charsRemoved) + if (!CopilotSettings::instance().autoComplete.value()) + return; auto textEditor = BaseTextEditor::currentTextEditor(); if (!textEditor || textEditor->document() != document) return; diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index 33d0c4361a4..8092e68bb17 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -49,6 +49,7 @@ file from the Copilot neovim plugin. authWidget, br, CopilotSettings::instance().nodeJsPath, br, CopilotSettings::instance().distPath, br, + CopilotSettings::instance().autoComplete, br, helpLabel, br, st }.attachTo(this); diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index ed298a0ab78..a566180ac78 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -58,8 +58,15 @@ CopilotSettings::CopilotSettings() distPath.setHistoryCompleter("Copilot.DistPath.History"); distPath.setDisplayName(Tr::tr("Agent.js path")); + autoComplete.setDisplayName(Tr::tr("Auto Complete")); + autoComplete.setLabelText(Tr::tr("Request completions automatically")); + autoComplete.setDefaultValue(true); + autoComplete.setToolTip(Tr::tr("Automatically request suggestions for the current text cursor " + "position after changes to the document")); + registerAspect(&nodeJsPath); registerAspect(&distPath); + registerAspect(&autoComplete); } } // namespace Copilot diff --git a/src/plugins/copilot/copilotsettings.h b/src/plugins/copilot/copilotsettings.h index d089410216b..44ce178ea5c 100644 --- a/src/plugins/copilot/copilotsettings.h +++ b/src/plugins/copilot/copilotsettings.h @@ -16,6 +16,7 @@ public: Utils::StringAspect nodeJsPath; Utils::StringAspect distPath; + Utils::BoolAspect autoComplete; }; } // namespace Copilot From 4a3495c8b979fd96249685254656ce9050c792fe Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 21 Apr 2023 18:00:40 +0200 Subject: [PATCH 0658/1447] LanguageClient: Reorder arguments in workspaceMatchers Provide a default empty list for clients. It's going to be used for MatcherType::CurrentDocumentSymbols. Change-Id: Ib3ba2ec8fa08b9a55eb097ac3cce8bcd513eb5ae Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/clangcodemodel/clangmodelmanagersupport.cpp | 6 +++--- src/plugins/languageclient/locatorfilter.cpp | 2 +- src/plugins/languageclient/locatorfilter.h | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 5b3b9fc783d..0ca9af11a0d 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -207,15 +207,15 @@ ClangModelManagerSupport::ClangModelManagerSupport() cppModelManager()->setFunctionsFilter(std::make_unique()); // Setup matchers LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, [] { - return LanguageClient::workspaceMatchers(clientsForOpenProjects(), MatcherType::AllSymbols, + return LanguageClient::workspaceMatchers(MatcherType::AllSymbols, clientsForOpenProjects(), 10000); }); LocatorMatcher::addMatcherCreator(MatcherType::Classes, [] { - return LanguageClient::workspaceMatchers(clientsForOpenProjects(), MatcherType::Classes, + return LanguageClient::workspaceMatchers(MatcherType::Classes, clientsForOpenProjects(), 10000); }); LocatorMatcher::addMatcherCreator(MatcherType::Functions, [] { - return LanguageClient::workspaceMatchers(clientsForOpenProjects(), MatcherType::Functions, + return LanguageClient::workspaceMatchers(MatcherType::Functions, clientsForOpenProjects(), 10000); }); diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 324a1cec338..55aca73b819 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -119,7 +119,7 @@ static MatcherCreator creatorForType(MatcherType type) return {}; } -LocatorMatcherTasks workspaceMatchers(const QList &clients, MatcherType type, +LocatorMatcherTasks workspaceMatchers(MatcherType type, const QList &clients, int maxResultCount) { const MatcherCreator creator = creatorForType(type); diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 52445e19c38..f3c48542560 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -22,9 +22,8 @@ namespace LanguageClient { using DocSymbolModifier = std::function; -Core::LocatorMatcherTasks LANGUAGECLIENT_EXPORT workspaceMatchers(const QList &clients, - Core::MatcherType type, - int maxResultCount = 0); +Core::LocatorMatcherTasks LANGUAGECLIENT_EXPORT workspaceMatchers(Core::MatcherType type, + const QList &clients = {}, int maxResultCount = 0); class LanguageClientManager; From 9a25a8849ba98dcd3e5eab321b0baf059695dccd Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 24 Apr 2023 09:26:39 +0200 Subject: [PATCH 0659/1447] ClangTools: Check if executable is valid Previously "getClangIncludeDirAndVersion" would fail on the QTC_CHECK and print out a warning each time. Change-Id: Id67b0c7f4c4e52b030d52ad5140f48e0a19770e0 Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/clangtools/documentclangtoolrunner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index 6683929011f..cc1016fb420 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -196,8 +196,10 @@ void DocumentClangToolRunner::run() if (!config.isEnabled(tool) && !runSettings.hasConfigFileForSourceFile(m_fileInfo.file)) return; const FilePath executable = toolExecutable(tool); + if (executable.isEmpty() || !executable.isExecutableFile()) + return; const auto [includeDir, clangVersion] = getClangIncludeDirAndVersion(executable); - if (!executable.isExecutableFile() || includeDir.isEmpty() || clangVersion.isEmpty()) + if (includeDir.isEmpty() || clangVersion.isEmpty()) return; const AnalyzeUnit unit(m_fileInfo, includeDir, clangVersion); const AnalyzeInputData input{tool, runSettings, config, m_temporaryDir.path(), env, unit, From 5bc60ac8de01372505c870469063723b3aaa3955 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 21 Apr 2023 08:14:54 +0200 Subject: [PATCH 0660/1447] QmlJS: Stop suggesting versions for imports if possible Fixes: QTCREATORBUG-28649 Change-Id: I918b229855c18519800a54a73b56eaffa40524e5 Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann Reviewed-by: --- src/libs/qmljs/qmljsbundle.cpp | 19 ++++++++---- src/libs/qmljs/qmljsbundle.h | 5 ++-- .../qmljstools/qmljsbundleprovider.cpp | 29 ++++++++++--------- src/plugins/qmljstools/qmljsbundleprovider.h | 9 ++++-- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/libs/qmljs/qmljsbundle.cpp b/src/libs/qmljs/qmljsbundle.cpp index c55edcdf5e7..e4d536a3da2 100644 --- a/src/libs/qmljs/qmljsbundle.cpp +++ b/src/libs/qmljs/qmljsbundle.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -186,8 +187,10 @@ QString QmlBundle::toString(const QString &indent) } QStringList QmlBundle::maybeReadTrie(Trie &trie, Utils::JsonObjectValue *config, - const QString &path, const QString &propertyName, bool required) + const QString &path, const QString &propertyName, + bool required, bool stripVersions) { + static const QRegularExpression versionNumberAtEnd("^(.+)( \\d+\\.\\d+)$"); QStringList res; if (!config->hasMember(propertyName)) { if (required) @@ -202,7 +205,13 @@ QStringList QmlBundle::maybeReadTrie(Trie &trie, Utils::JsonObjectValue *config, for (Utils::JsonValue *v : elements) { Utils::JsonStringValue *impStr = ((v != nullptr) ? v->toString() : nullptr); if (impStr != nullptr) { - trie.insert(impStr->value()); + QString value = impStr->value(); + if (stripVersions) { + const QRegularExpressionMatch match = versionNumberAtEnd.match(value); + if (match.hasMatch()) + value = match.captured(1); + } + trie.insert(value); } else { res.append(QString::fromLatin1("Expected all elements of array in property \"%1\" " "to be strings in QmlBundle at %2.") @@ -217,7 +226,7 @@ QStringList QmlBundle::maybeReadTrie(Trie &trie, Utils::JsonObjectValue *config, return res; } -bool QmlBundle::readFrom(QString path, QStringList *errors) +bool QmlBundle::readFrom(QString path, bool stripVersions, QStringList *errors) { Utils::JsonMemoryPool pool; @@ -249,8 +258,8 @@ bool QmlBundle::readFrom(QString path, QStringList *errors) } errs << maybeReadTrie(m_searchPaths, config, path, QLatin1String("searchPaths")); errs << maybeReadTrie(m_installPaths, config, path, QLatin1String("installPaths")); - errs << maybeReadTrie(m_supportedImports, config, path, QLatin1String("supportedImports") - , true); + errs << maybeReadTrie(m_supportedImports, config, path, QLatin1String("supportedImports"), + true, stripVersions); errs << maybeReadTrie(m_implicitImports, config, path, QLatin1String("implicitImports")); if (errors) (*errors) << errs; diff --git a/src/libs/qmljs/qmljsbundle.h b/src/libs/qmljs/qmljsbundle.h index 8cf31456717..5d2058eef48 100644 --- a/src/libs/qmljs/qmljsbundle.h +++ b/src/libs/qmljs/qmljsbundle.h @@ -53,14 +53,15 @@ public: bool writeTo(const QString &path) const; bool writeTo(QTextStream &stream, const QString &indent = QString()) const; QString toString(const QString &indent = QString()); - bool readFrom(QString path, QStringList *errors); + bool readFrom(QString path, bool stripVersions, QStringList *errors); bool operator==(const QmlBundle &o) const; bool operator!=(const QmlBundle &o) const; private: static void printEscaped(QTextStream &s, const QString &str); static void writeTrie(QTextStream &stream, const Trie &t, const QString &indent); QStringList maybeReadTrie(Trie &trie, Utils::JsonObjectValue *config, const QString &path, - const QString &propertyName, bool required = false); + const QString &propertyName, bool required = false, + bool stripVersions = false); QString m_name; Trie m_searchPaths; diff --git a/src/plugins/qmljstools/qmljsbundleprovider.cpp b/src/plugins/qmljstools/qmljsbundleprovider.cpp index f44070b75e4..623a6f4684c 100644 --- a/src/plugins/qmljstools/qmljsbundleprovider.cpp +++ b/src/plugins/qmljstools/qmljsbundleprovider.cpp @@ -25,7 +25,8 @@ BasicBundleProvider::BasicBundleProvider(QObject *parent) : IBundleProvider(parent) { } -QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName) +QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName, + QtSupport::QtVersion *qtVersion) { static bool wroteErrors = false; QmlBundle res; @@ -37,7 +38,8 @@ QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName) return res; } QStringList errors; - if (!res.readFrom(defaultBundlePath.toString(), &errors) && !wroteErrors) { + bool stripVersions = qtVersion && qtVersion->qtVersion().majorVersion() > 5; + if (!res.readFrom(defaultBundlePath.toString(), stripVersions, &errors) && !wroteErrors) { qWarning() << "BasicBundleProvider: ERROR reading " << defaultBundlePath << " : " << errors; wroteErrors = true; @@ -45,31 +47,31 @@ QmlBundle BasicBundleProvider::defaultBundle(const QString &bundleInfoName) return res; } -QmlBundle BasicBundleProvider::defaultQt5QtQuick2Bundle(bool enhance) +QmlBundle BasicBundleProvider::defaultQt5QtQuick2Bundle(QtSupport::QtVersion *qtVersion) { - QmlBundle result = defaultBundle(QLatin1String("qt5QtQuick2-bundle.json")); - if (!enhance) + QmlBundle result = defaultBundle(QLatin1String("qt5QtQuick2-bundle.json"), qtVersion); + if (!qtVersion || qtVersion->qtVersion().majorVersion() < 6) return result; if (Utils::HostOsInfo::isMacHost()) - result.merge(defaultBundle(QLatin1String("qt5QtQuick2ext-macos-bundle.json"))); + result.merge(defaultBundle(QLatin1String("qt5QtQuick2ext-macos-bundle.json"), qtVersion)); if (Utils::HostOsInfo::isWindowsHost()) - result.merge(defaultBundle(QLatin1String("qt5QtQuick2ext-win-bundle.json"))); + result.merge(defaultBundle(QLatin1String("qt5QtQuick2ext-win-bundle.json"), qtVersion)); return result; } QmlBundle BasicBundleProvider::defaultQbsBundle() { - return defaultBundle(QLatin1String("qbs-bundle.json")); + return defaultBundle(QLatin1String("qbs-bundle.json"), nullptr); } QmlBundle BasicBundleProvider::defaultQmltypesBundle() { - return defaultBundle(QLatin1String("qmltypes-bundle.json")); + return defaultBundle(QLatin1String("qmltypes-bundle.json"), nullptr); } QmlBundle BasicBundleProvider::defaultQmlprojectBundle() { - return defaultBundle(QLatin1String("qmlproject-bundle.json")); + return defaultBundle(QLatin1String("qmlproject-bundle.json"), nullptr); } void BasicBundleProvider::mergeBundlesForKit(ProjectExplorer::Kit *kit @@ -84,7 +86,7 @@ void BasicBundleProvider::mergeBundlesForKit(ProjectExplorer::Kit *kit QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit); if (!qtVersion) { - QmlBundle b2(defaultQt5QtQuick2Bundle(false)); + QmlBundle b2(defaultQt5QtQuick2Bundle(qtVersion)); bundles.mergeBundleForLanguage(Dialect::Qml, b2); bundles.mergeBundleForLanguage(Dialect::QmlQtQuick2, b2); bundles.mergeBundleForLanguage(Dialect::QmlQtQuick2Ui, b2); @@ -97,17 +99,18 @@ void BasicBundleProvider::mergeBundlesForKit(ProjectExplorer::Kit *kit qtQuick2Bundles.setNameFilters(QStringList(QLatin1String("*-bundle.json"))); QmlBundle qtQuick2Bundle; QFileInfoList list = qtQuick2Bundles.entryInfoList(); + bool stripVersions = qtVersion->qtVersion().majorVersion() > 5; for (int i = 0; i < list.size(); ++i) { QmlBundle bAtt; QStringList errors; - if (!bAtt.readFrom(list.value(i).filePath(), &errors)) + if (!bAtt.readFrom(list.value(i).filePath(), stripVersions, &errors)) qWarning() << "BasicBundleProvider: ERROR reading " << list[i].filePath() << " : " << errors; qtQuick2Bundle.merge(bAtt); } if (!qtQuick2Bundle.supportedImports().contains(QLatin1String("QtQuick 2."), PersistentTrie::Partial)) { - qtQuick2Bundle.merge(defaultQt5QtQuick2Bundle(qtVersion->qtVersion().majorVersion() >= 6)); + qtQuick2Bundle.merge(defaultQt5QtQuick2Bundle(qtVersion)); } qtQuick2Bundle.replaceVars(myReplacements); bundles.mergeBundleForLanguage(Dialect::Qml, qtQuick2Bundle); diff --git a/src/plugins/qmljstools/qmljsbundleprovider.h b/src/plugins/qmljstools/qmljsbundleprovider.h index 392055b0329..d8cd8351508 100644 --- a/src/plugins/qmljstools/qmljsbundleprovider.h +++ b/src/plugins/qmljstools/qmljsbundleprovider.h @@ -19,6 +19,10 @@ class QmlLanguageBundles; class QmlBundle; } // namespace QmlJS +namespace QtSupport { +class QtVersion; +} + namespace QmlJSTools { class QMLJSTOOLS_EXPORT IBundleProvider : public QObject @@ -43,8 +47,9 @@ public: void mergeBundlesForKit(ProjectExplorer::Kit *kit, QmlJS::QmlLanguageBundles &bundles, const QHash &replacements) override; - static QmlJS::QmlBundle defaultBundle(const QString &bundleInfoName); - static QmlJS::QmlBundle defaultQt5QtQuick2Bundle(bool enhance); + static QmlJS::QmlBundle defaultBundle(const QString &bundleInfoName, + QtSupport::QtVersion *qtVersion); + static QmlJS::QmlBundle defaultQt5QtQuick2Bundle(QtSupport::QtVersion *qtVersion); static QmlJS::QmlBundle defaultQbsBundle(); static QmlJS::QmlBundle defaultQmltypesBundle(); static QmlJS::QmlBundle defaultQmlprojectBundle(); From e58dd4381f30b0a3bb792cf3d64eea8d4127326c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 14 Apr 2023 14:15:08 +0200 Subject: [PATCH 0661/1447] Copilot: set the correct suggestion document for inline suggestions Change-Id: Idbccf2eb68b4d1e2bd3751e851310cc74cac2694 Reviewed-by: Marcus Tillmanns Reviewed-by: Artem Sokolovskii Reviewed-by: --- src/plugins/copilot/copilotsuggestion.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plugins/copilot/copilotsuggestion.cpp b/src/plugins/copilot/copilotsuggestion.cpp index de5660c02d1..28da286f1f7 100644 --- a/src/plugins/copilot/copilotsuggestion.cpp +++ b/src/plugins/copilot/copilotsuggestion.cpp @@ -9,6 +9,7 @@ using namespace Utils; using namespace TextEditor; +using namespace LanguageServerProtocol; namespace Copilot::Internal { @@ -19,7 +20,14 @@ CopilotSuggestion::CopilotSuggestion(const QList &completions, , m_currentCompletion(currentCompletion) { const Completion completion = completions.value(currentCompletion); - document()->setPlainText(completion.text()); + const Position start = completion.range().start(); + const Position end = completion.range().end(); + QString text = start.toTextCursor(origin).block().text(); + int length = text.length() - start.character(); + if (start.line() == end.line()) + length = end.character() - start.character(); + text.replace(start.character(), length, completion.text()); + document()->setPlainText(text); m_start = completion.position().toTextCursor(origin); m_start.setKeepPositionOnInsert(true); setCurrentPosition(m_start.position()); From cc14eaf570e7087aaf28b62325b5a86007a18897 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 24 Apr 2023 13:09:44 +0200 Subject: [PATCH 0662/1447] CoPilot: Fix leak in authwidget Also fixes a crash when the state check returns after the widget was already deleted. Change-Id: I04256e6ba686469f18ebdb75c73e12cecf330bed Reviewed-by: David Schulz Reviewed-by: --- src/plugins/copilot/authwidget.cpp | 6 ++++++ src/plugins/copilot/authwidget.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp index cba1f178d31..da59bc06c64 100644 --- a/src/plugins/copilot/authwidget.cpp +++ b/src/plugins/copilot/authwidget.cpp @@ -48,6 +48,12 @@ AuthWidget::AuthWidget(QWidget *parent) }); } +AuthWidget::~AuthWidget() +{ + if (m_client) + LanguageClientManager::shutdownClient(m_client); +} + void AuthWidget::setState(const QString &buttonText, bool working) { m_button->setText(buttonText); diff --git a/src/plugins/copilot/authwidget.h b/src/plugins/copilot/authwidget.h index 0d5406591e0..acb18810fe4 100644 --- a/src/plugins/copilot/authwidget.h +++ b/src/plugins/copilot/authwidget.h @@ -25,6 +25,8 @@ class AuthWidget : public QWidget public: explicit AuthWidget(QWidget *parent = nullptr); + ~AuthWidget() override; + void updateClient(const Utils::FilePath &nodeJs, const Utils::FilePath &agent); private: From e849c19a337201fad8a9888d0ac608ebc704d294 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 23 Apr 2023 15:29:11 +0200 Subject: [PATCH 0663/1447] AutoTest: Optimize TestCodeParser::scanForTests In case of loading a Creator project, after the Scanning For Tests finished, the scanForTests() called by TestCodeParser::onFinished() freezed the main thread for about 1 second. In this case requestRemoval() signal was emitted nearly 1000 times. Optimize the internals: 1. Don't emit requestRemoval() for every single file but emit it just once passing a QSet instead. 2. Adapt some other callees and callers to work on QSet instead on a single FilePath. This change constraints the freeze to about 2 ms. Change-Id: If23b85b495c125d82eb3c8b5a6912349df122745 Reviewed-by: Christian Stenger --- .../autotest/quick/quicktesttreeitem.cpp | 20 +++++++------ .../autotest/quick/quicktesttreeitem.h | 2 +- src/plugins/autotest/testcodeparser.cpp | 14 ++++------ src/plugins/autotest/testcodeparser.h | 2 +- src/plugins/autotest/testtreeitem.cpp | 8 +++--- src/plugins/autotest/testtreeitem.h | 2 +- src/plugins/autotest/testtreemodel.cpp | 28 ++++++------------- src/plugins/autotest/testtreemodel.h | 3 +- 8 files changed, 33 insertions(+), 46 deletions(-) diff --git a/src/plugins/autotest/quick/quicktesttreeitem.cpp b/src/plugins/autotest/quick/quicktesttreeitem.cpp index 6afe3846d7e..88f43e15419 100644 --- a/src/plugins/autotest/quick/quicktesttreeitem.cpp +++ b/src/plugins/autotest/quick/quicktesttreeitem.cpp @@ -389,17 +389,19 @@ QSet internalTargets(const FilePath &proFile) return result; } -void QuickTestTreeItem::markForRemovalRecursively(const FilePath &filePath) +void QuickTestTreeItem::markForRemovalRecursively(const QSet &filePaths) { - TestTreeItem::markForRemovalRecursively(filePath); + TestTreeItem::markForRemovalRecursively(filePaths); auto parser = static_cast(framework()->testParser()); - const FilePath proFile = parser->projectFileForMainCppFile(filePath); - if (!proFile.isEmpty()) { - TestTreeItem *root = framework()->rootNode(); - root->forAllChildItems([proFile](TestTreeItem *it) { - if (it->proFile() == proFile) - it->markForRemoval(true); - }); + for (const FilePath &filePath : filePaths) { + const FilePath proFile = parser->projectFileForMainCppFile(filePath); + if (!proFile.isEmpty()) { + TestTreeItem *root = framework()->rootNode(); + root->forAllChildItems([proFile](TestTreeItem *it) { + if (it->proFile() == proFile) + it->markForRemoval(true); + }); + } } } diff --git a/src/plugins/autotest/quick/quicktesttreeitem.h b/src/plugins/autotest/quick/quicktesttreeitem.h index adbf95fa8bc..c09bd97b984 100644 --- a/src/plugins/autotest/quick/quicktesttreeitem.h +++ b/src/plugins/autotest/quick/quicktesttreeitem.h @@ -35,7 +35,7 @@ public: bool removeOnSweepIfEmpty() const override; TestTreeItem *createParentGroupNode() const override; bool isGroupable() const override; - void markForRemovalRecursively(const Utils::FilePath &filePath) override; + void markForRemovalRecursively(const QSet &filePaths) override; private: TestTreeItem *findChildByFileNameAndType(const Utils::FilePath &filePath, const QString &name, Type tType); diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 55fc5ec9079..b93f0aba1a7 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -307,24 +307,20 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QListupdateCheckStateCache(); if (isFullParse) { // remove qml files as they will be found automatically by the referencing cpp file - list = Utils::filtered(list, [](const FilePath &fn) { - return !fn.endsWith(".qml"); - }); + list = Utils::filtered(list, [](const FilePath &fn) { return !fn.endsWith(".qml"); }); if (!parsers.isEmpty()) { - for (ITestParser *parser : parsers) { + for (ITestParser *parser : parsers) parser->framework()->rootNode()->markForRemovalRecursively(true); - } } else { emit requestRemoveAllFrameworkItems(); } } else if (!parsers.isEmpty()) { + const auto set = Utils::toSet(list); for (ITestParser *parser: parsers) { - for (const FilePath &filePath : std::as_const(list)) - parser->framework()->rootNode()->markForRemovalRecursively(filePath); + parser->framework()->rootNode()->markForRemovalRecursively(set); } } else { - for (const FilePath &filePath : std::as_const(list)) - emit requestRemoval(filePath); + emit requestRemoval(Utils::toSet(list)); } QTC_ASSERT(!(isFullParse && list.isEmpty()), onFinished(true); return); diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index b9b8ef044b6..324b7731f9d 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -53,7 +53,7 @@ signals: void parsingStarted(); void parsingFinished(); void parsingFailed(); - void requestRemoval(const Utils::FilePath &filePath); + void requestRemoval(const QSet &filePaths); void requestRemoveAllFrameworkItems(); public: diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp index 884544e3b24..f18adb812d4 100644 --- a/src/plugins/autotest/testtreeitem.cpp +++ b/src/plugins/autotest/testtreeitem.cpp @@ -224,11 +224,11 @@ void TestTreeItem::markForRemovalRecursively(bool mark) childItem(row)->markForRemovalRecursively(mark); } -void TestTreeItem::markForRemovalRecursively(const FilePath &filepath) +void TestTreeItem::markForRemovalRecursively(const QSet &filePaths) { - bool mark = filePath() == filepath; - forFirstLevelChildItems([&mark, &filepath](TestTreeItem *child) { - child->markForRemovalRecursively(filepath); + bool mark = filePaths.contains(filePath()); + forFirstLevelChildItems([&mark, &filePaths](TestTreeItem *child) { + child->markForRemovalRecursively(filePaths); mark &= child->markedForRemoval(); }); markForRemoval(mark); diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h index e51f48b211c..3737d2a3607 100644 --- a/src/plugins/autotest/testtreeitem.h +++ b/src/plugins/autotest/testtreeitem.h @@ -115,7 +115,7 @@ public: void setProFile(const Utils::FilePath &proFile) { m_proFile = proFile; } void markForRemoval(bool mark); void markForRemovalRecursively(bool mark); - virtual void markForRemovalRecursively(const Utils::FilePath &filepath); + virtual void markForRemovalRecursively(const QSet &filePaths); virtual bool removeOnSweepIfEmpty() const { return type() == GroupNode; } bool markedForRemoval() const { return m_status == MarkedForRemoval; } bool newlyAdded() const { return m_status == NewlyAdded; } diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index 4e3d010ad45..5e7fcb85a86 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -100,8 +100,8 @@ void TestTreeModel::setupParsingConnections() m_parser, &TestCodeParser::onCppDocumentUpdated, Qt::QueuedConnection); connect(cppMM, &CppEditor::CppModelManager::aboutToRemoveFiles, this, [this](const QStringList &files) { - const FilePaths filesToRemove = FileUtils::toFilePathList(files); - removeFiles(filesToRemove); + markForRemoval(transform(files, &FilePath::fromString)); + sweep(); }, Qt::QueuedConnection); connect(cppMM, &CppEditor::CppModelManager::projectPartsUpdated, m_parser, &TestCodeParser::onProjectPartsUpdated); @@ -109,11 +109,11 @@ void TestTreeModel::setupParsingConnections() QmlJS::ModelManagerInterface *qmlJsMM = QmlJS::ModelManagerInterface::instance(); connect(qmlJsMM, &QmlJS::ModelManagerInterface::documentUpdated, m_parser, &TestCodeParser::onQmlDocumentUpdated, Qt::QueuedConnection); - connect(qmlJsMM, - &QmlJS::ModelManagerInterface::aboutToRemoveFiles, - this, - &TestTreeModel::removeFiles, - Qt::QueuedConnection); + connect(qmlJsMM, &QmlJS::ModelManagerInterface::aboutToRemoveFiles, + this, [this](const FilePaths &filePaths) { + markForRemoval(Utils::toSet(filePaths)); + sweep(); + }, Qt::QueuedConnection); connectionsInitialized = true; } @@ -463,13 +463,6 @@ void TestTreeModel::clearFailedMarks() m_failedStateCache.clear(); } -void TestTreeModel::removeFiles(const FilePaths &files) -{ - for (const FilePath &file : files) - markForRemoval(file); - sweep(); -} - void TestTreeModel::markAllFrameworkItemsForRemoval() { for (TestTreeItem *frameworkRoot : frameworkRootNodes()) { @@ -479,15 +472,12 @@ void TestTreeModel::markAllFrameworkItemsForRemoval() } } -void TestTreeModel::markForRemoval(const FilePath &filePath) +void TestTreeModel::markForRemoval(const QSet &filePaths) { - if (filePath.isEmpty()) - return; - for (TestTreeItem *frameworkRoot : frameworkRootNodes()) { for (int childRow = frameworkRoot->childCount() - 1; childRow >= 0; --childRow) { TestTreeItem *child = frameworkRoot->childItem(childRow); - child->markForRemovalRecursively(filePath); + child->markForRemovalRecursively(filePaths); } } } diff --git a/src/plugins/autotest/testtreemodel.h b/src/plugins/autotest/testtreemodel.h index b8104e8b433..c48c957d999 100644 --- a/src/plugins/autotest/testtreemodel.h +++ b/src/plugins/autotest/testtreemodel.h @@ -66,7 +66,7 @@ public: #endif void markAllFrameworkItemsForRemoval(); - void markForRemoval(const Utils::FilePath &filePath); + void markForRemoval(const QSet &filePaths); void sweep(); signals: @@ -83,7 +83,6 @@ private: void handleParseResult(const TestParseResult *result, TestTreeItem *rootNode); void removeAllTestItems(); void removeAllTestToolItems(); - void removeFiles(const Utils::FilePaths &files); bool sweepChildren(TestTreeItem *item); void insertItemInParent(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled); void revalidateCheckState(ITestTreeItem *item); From ec9680d42ea0ac76704cef340b0f8df93b9075ef Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 24 Apr 2023 13:10:08 +0200 Subject: [PATCH 0664/1447] Markdown: Add option for hiding preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it possible to hide the preview, by having a toggle button for "Show Preview" and "Show Editor", and ensure that at least one is always on and they are in the order as the views themselves. Disable the "Swap Views" button if only one is shown. Change-Id: I0ec1e06c2a8ec94e34bf52eae45ba009fd8cd1b5 Reviewed-by: David Schulz Reviewed-by: André Hartmann Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/texteditor/markdowneditor.cpp | 70 ++++++++++++++++------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index b6993dacd57..afdda1bfb4d 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -65,46 +65,76 @@ public: setContext(Core::Context(MARKDOWNVIEWER_ID)); setWidget(&m_widget); + auto togglePreviewVisible = new QToolButton; + togglePreviewVisible->setText(Tr::tr("Show Preview")); + togglePreviewVisible->setCheckable(true); + togglePreviewVisible->setChecked(true); + auto toggleEditorVisible = new QToolButton; - toggleEditorVisible->setText(Tr::tr("Hide Editor")); + toggleEditorVisible->setText(Tr::tr("Show Editor")); toggleEditorVisible->setCheckable(true); toggleEditorVisible->setChecked(true); auto swapViews = new QToolButton; swapViews->setText(Tr::tr("Swap Views")); - auto layout = new QHBoxLayout(&m_toolbar); - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - layout->addStretch(); - layout->addWidget(toggleEditorVisible); - layout->addWidget(swapViews); + auto toolbarLayout = new QHBoxLayout(&m_toolbar); + toolbarLayout->setSpacing(0); + toolbarLayout->setContentsMargins(0, 0, 0, 0); + toolbarLayout->addStretch(); + if (textEditorRight) { + toolbarLayout->addWidget(togglePreviewVisible); + toolbarLayout->addWidget(toggleEditorVisible); + } else { + toolbarLayout->addWidget(toggleEditorVisible); + toolbarLayout->addWidget(togglePreviewVisible); + } + toolbarLayout->addWidget(swapViews); connect(m_document.data(), &TextDocument::mimeTypeChanged, m_document.data(), &TextDocument::changed); + const auto viewToggled = + [swapViews](QWidget *view, bool visible, QWidget *otherView, QToolButton *otherButton) { + if (view->isVisible() == visible) + return; + view->setVisible(visible); + if (visible) { + view->setFocus(); + } else if (otherView->isVisible()) { + otherView->setFocus(); + } else { + // make sure at least one view is visible + otherButton->toggle(); + } + swapViews->setEnabled(view->isVisible() && otherView->isVisible()); + }; + connect(toggleEditorVisible, &QToolButton::toggled, - m_textEditorWidget, - [this, browser, toggleEditorVisible](bool editorVisible) { - if (m_textEditorWidget->isVisible() == editorVisible) - return; - m_textEditorWidget->setVisible(editorVisible); - if (editorVisible) - m_textEditorWidget->setFocus(); - else - browser->setFocus(); - - toggleEditorVisible->setText(editorVisible ? Tr::tr("Hide Editor") - : Tr::tr("Show Editor")); + this, + [this, browser, togglePreviewVisible, viewToggled](bool visible) { + viewToggled(m_textEditorWidget, visible, browser, togglePreviewVisible); + }); + connect(togglePreviewVisible, + &QToolButton::toggled, + this, + [this, browser, toggleEditorVisible, viewToggled](bool visible) { + viewToggled(browser, visible, m_textEditorWidget, toggleEditorVisible); }); - connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this] { + connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this, toolbarLayout] { QTC_ASSERT(m_widget.count() > 1, return); + // switch views auto placeholder = std::make_unique(); auto second = m_widget.replaceWidget(1, placeholder.get()); auto first = m_widget.replaceWidget(0, second); m_widget.replaceWidget(1, first); + // switch buttons + const int rightIndex = toolbarLayout->count() - 2; + QLayoutItem *right = toolbarLayout->takeAt(rightIndex); + toolbarLayout->insertItem(rightIndex - 1, right); + // save settings Utils::QtcSettings *s = Core::ICore::settings(); s->setValueWithDefault(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, !s->value(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, From 57d982e5caff67375f4798c341b16e8b472e51c8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 22:39:31 +0200 Subject: [PATCH 0665/1447] OpenDocumentsFilter: Reimplement matchers() Change-Id: Ie458d74321286d720b3eef62b7b3273c5c222e44 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- .../locator/opendocumentsfilter.cpp | 55 ++++++++++++++++++- .../coreplugin/locator/opendocumentsfilter.h | 16 +++--- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index aa94c5f5f58..4a510ad83f7 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -3,11 +3,13 @@ #include "opendocumentsfilter.h" +#include "../coreplugin.h" #include "../coreplugintr.h" +#include +#include #include #include -#include #include #include @@ -25,6 +27,7 @@ OpenDocumentsFilter::OpenDocumentsFilter() setDefaultShortcutString("o"); setPriority(High); setDefaultIncludedByDefault(true); + // TODO: Remove the refresh recipe setRefreshRecipe(Tasking::Sync([this] { refreshInternally(); return true; })); connect(DocumentModel::model(), &QAbstractItemModel::dataChanged, @@ -35,6 +38,56 @@ OpenDocumentsFilter::OpenDocumentsFilter() this, &OpenDocumentsFilter::slotRowsRemoved); } +static void matchEditors(QPromise &promise, const LocatorStorage &storage, + const QList &editorsData) +{ + const Link link = Link::fromString(storage.input(), true); + const QRegularExpression regexp = ILocatorFilter::createRegExp(link.targetFilePath.toString()); + if (!regexp.isValid()) + return; + + LocatorFilterEntries goodEntries; + LocatorFilterEntries betterEntries; + + for (const OpenDocumentsFilter::Entry &editorData : editorsData) { + if (promise.isCanceled()) + return; + if (editorData.fileName.isEmpty()) + continue; + const QRegularExpressionMatch match = regexp.match(editorData.displayName); + if (match.hasMatch()) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = editorData.displayName; + filterEntry.filePath = editorData.fileName; + filterEntry.extraInfo = filterEntry.filePath.shortNativePath(); + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + filterEntry.linkForEditor = Link(filterEntry.filePath, link.targetLine, + link.targetColumn); + if (match.capturedStart() == 0) + betterEntries.append(filterEntry); + else + goodEntries.append(filterEntry); + } + } + storage.reportOutput(betterEntries + goodEntries); +} + +LocatorMatcherTasks OpenDocumentsFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage](AsyncTask &async) { + const QList editorsData = Utils::transform(DocumentModel::entries(), + [](const DocumentModel::Entry *e) { return Entry{e->filePath(), e->displayName()}; }); + async.setFutureSynchronizer(CorePlugin::futureSynchronizer()); + async.setConcurrentCallData(matchEditors, *storage, editorsData); + }; + + return {{Async(onSetup), storage}}; +} + void OpenDocumentsFilter::slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index 7bbd98698fa..c75c4da1db7 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -20,13 +20,7 @@ public: OpenDocumentsFilter(); QList matchesFor(QFutureInterface &future, const QString &entry) override; -public slots: - void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector &roles); - void slotRowsInserted(const QModelIndex &, int first, int last); - void slotRowsRemoved(const QModelIndex &, int first, int last); - -private: + // TODO: Move to cpp when matchesFor() is removed class Entry { public: @@ -34,6 +28,14 @@ private: QString displayName; }; +public slots: + void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector &roles); + void slotRowsInserted(const QModelIndex &, int first, int last); + void slotRowsRemoved(const QModelIndex &, int first, int last); + +private: + LocatorMatcherTasks matchers() final; QList editors() const; void refreshInternally(); From ca3d88983153d3093436247223ee141950f8ebb5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 24 Apr 2023 16:00:18 +0200 Subject: [PATCH 0666/1447] AutoTest: Only handle document updates if necessary Do not send qml document updated unnecessarily in case we know that nothing had changed at all. Change-Id: I1d6b94dcd68753e0f451a2812a752ff92f4860af Reviewed-by: David Schulz Reviewed-by: Jarek Kobus --- src/plugins/autotest/testcodeparser.cpp | 15 +++++++++++++-- src/plugins/autotest/testcodeparser.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index b93f0aba1a7..a88860860f0 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -7,6 +7,7 @@ #include "autotesttr.h" #include "testtreemodel.h" +#include #include #include #include @@ -47,6 +48,11 @@ TestCodeParser::TestCodeParser() connect(progressManager, &ProgressManager::allTasksFinished, this, &TestCodeParser::onAllTasksFinished); connect(this, &TestCodeParser::parsingFinished, this, &TestCodeParser::releaseParserInternals); + connect(EditorManager::instance(), &EditorManager::documentClosed, this, [this](IDocument *doc){ + QTC_ASSERT(doc, return); + if (FilePath filePath = doc->filePath(); filePath.endsWith(".qml")) + m_qmlEditorRev.remove(filePath); + }); m_reparseTimer.setSingleShot(true); connect(&m_reparseTimer, &QTimer::timeout, this, &TestCodeParser::parsePostponedFiles); m_threadPool->setMaxThreadCount(std::max(QThread::idealThreadCount()/4, 1)); @@ -169,12 +175,17 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document) { static const QStringList ignoredSuffixes{ "qbs", "ui.qml" }; const FilePath fileName = document->fileName(); - if (!ignoredSuffixes.contains(fileName.suffix())) - onDocumentUpdated(fileName, true); + int editorRevision = document->editorRevision(); + if (editorRevision != m_qmlEditorRev.value(fileName, 0)) { + m_qmlEditorRev.insert(fileName, editorRevision); + if (!ignoredSuffixes.contains(fileName.suffix())) + onDocumentUpdated(fileName, true); + } } void TestCodeParser::onStartupProjectChanged(Project *project) { + m_qmlEditorRev.clear(); if (m_parserState == FullParse || m_parserState == PartialParse) { qCDebug(LOG) << "Canceling scanForTest (startup project changed)"; ProgressManager::cancelTasks(Constants::TASK_PARSE); diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index 324b7731f9d..e9b3832f449 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -97,6 +97,7 @@ private: QThreadPool *m_threadPool = nullptr; Utils::FutureSynchronizer m_futureSynchronizer; std::unique_ptr m_taskTree; + QHash m_qmlEditorRev; }; } // namespace Internal From daf1b29b2d83f8a8ec7b8d9439f886cb81d0ac42 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 19 Apr 2023 16:56:58 +0200 Subject: [PATCH 0667/1447] Core: Try not to evict still-running searches ... when the maximum number of searches has been reached. Task-number: QTCREATORBUG-28976 Change-Id: I12bad860ce61f71aad9ba2fec93333a5d98bc61d Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- .../coreplugin/find/searchresultwidget.h | 1 + .../coreplugin/find/searchresultwindow.cpp | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/plugins/coreplugin/find/searchresultwidget.h b/src/plugins/coreplugin/find/searchresultwidget.h index f10bd5dd673..8ec0096a601 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.h +++ b/src/plugins/coreplugin/find/searchresultwidget.h @@ -36,6 +36,7 @@ public: void addResults(const QList &items, SearchResult::AddMode mode); int count() const; + bool isSearching() const { return m_searching; } void setSupportsReplace(bool replaceSupported, const QString &group); bool supportsReplace() const; diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 3b2ea6e8ae9..075084810d9 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -90,6 +90,7 @@ namespace Internal { void popupRequested(SearchResultWidget *widget, bool focus); void handleExpandCollapseToolButton(bool checked); void updateFilterButton(); + int indexOfSearchToEvict() const; QList toolBarWidgets(); SearchResultWindow *q; @@ -473,11 +474,14 @@ SearchResult *SearchResultWindow::startNewSearch(const QString &label, // temporarily set the index to the last but one existing d->m_currentIndex = d->m_recentSearchesBox->count() - 2; } - d->m_searchResultWidgets.last()->notifyVisibilityChanged(false); + const int toRemoveIndex = d->indexOfSearchToEvict(); + SearchResultWidget * const widgetToRemove + = d->m_searchResultWidgets.takeAt(toRemoveIndex); + widgetToRemove->notifyVisibilityChanged(false); // widget first, because that might send interesting signals to SearchResult - delete d->m_searchResultWidgets.takeLast(); - delete d->m_searchResults.takeLast(); - d->m_recentSearchesBox->removeItem(d->m_recentSearchesBox->count() - 1); + delete widgetToRemove; + delete d->m_searchResults.takeAt(toRemoveIndex); + d->m_recentSearchesBox->removeItem(toRemoveIndex + 1); } d->m_recentSearchesBox->insertItem(1, Tr::tr("%1 %2").arg(label, searchTerm)); } @@ -616,6 +620,16 @@ void SearchResultWindowPrivate::updateFilterButton() && m_searchResultWidgets.at(visibleSearchIndex())->hasFilter()); } +int SearchResultWindowPrivate::indexOfSearchToEvict() const +{ + const int lastIndex = m_searchResultWidgets.size() - 1; + for (int i = lastIndex; i >= 0; --i) { + if (!m_searchResultWidgets.at(i)->isSearching()) + return i; + } + return lastIndex; +} + QList SearchResultWindowPrivate::toolBarWidgets() { if (!m_historyLabel) From d13d48a28134a083dc75574917a9dd953beebda6 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 13:49:37 +0200 Subject: [PATCH 0668/1447] FakeVim: Use IOptionPage::setWidgetCreator() for user command settings Change-Id: Ic5d895634cb5ef1b2e1a6fa465cd800a213a7d41 Reviewed-by: Christian Stenger --- src/plugins/fakevim/fakevimplugin.cpp | 121 ++++++++++++-------------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 02207de8728..c56f1c3acb7 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -862,6 +862,60 @@ public: } }; +class FakeVimUserCommandsPageWidget : public IOptionsPageWidget +{ +public: + FakeVimUserCommandsPageWidget(FakeVimUserCommandsModel *model) + : m_model(model) + { + auto widget = new QTreeView; + widget->setModel(m_model); + widget->resizeColumnToContents(0); + + auto delegate = new FakeVimUserCommandsDelegate(widget); + widget->setItemDelegateForColumn(1, delegate); + + auto layout = new QGridLayout(this); + layout->addWidget(widget, 0, 0); + setLayout(layout); + } + +private: + void apply() final + { + // now save the mappings if necessary + const UserCommandMap ¤t = m_model->commandMap(); + UserCommandMap &userMap = dd->m_userCommandMap; + + if (current != userMap) { + QSettings *settings = ICore::settings(); + settings->beginWriteArray(userCommandMapGroup); + int count = 0; + using Iterator = UserCommandMap::const_iterator; + const Iterator end = current.constEnd(); + for (Iterator it = current.constBegin(); it != end; ++it) { + const int key = it.key(); + const QString cmd = it.value(); + + if ((dd->m_defaultUserCommandMap.contains(key) + && dd->m_defaultUserCommandMap[key] != cmd) + || (!dd->m_defaultUserCommandMap.contains(key) && !cmd.isEmpty())) { + settings->setArrayIndex(count); + settings->setValue(idKey, key); + settings->setValue(cmdKey, cmd); + ++count; + } + } + settings->endArray(); + userMap.clear(); + userMap.insert(dd->m_defaultUserCommandMap); + userMap.insert(current); + } + } + + FakeVimUserCommandsModel *m_model; +}; + class FakeVimUserCommandsPage : public IOptionsPage { public: @@ -870,76 +924,13 @@ public: setId(SETTINGS_USER_CMDS_ID); setDisplayName(Tr::tr("User Command Mapping")); setCategory(SETTINGS_CATEGORY); + setWidgetCreator([this] { return new FakeVimUserCommandsPageWidget(&m_model); }); } - void apply() override; - void finish() override {} - - QWidget *widget() override; - void initialize() {} - UserCommandMap currentCommandMap() { return m_model->commandMap(); } - private: - QPointer m_widget; - FakeVimUserCommandsModel *m_model = nullptr; + FakeVimUserCommandsModel m_model; }; -QWidget *FakeVimUserCommandsPage::widget() -{ - if (!m_widget) { - m_widget = new QWidget; - - m_model = new FakeVimUserCommandsModel; - auto widget = new QTreeView; - m_model->setParent(widget); - widget->setModel(m_model); - widget->resizeColumnToContents(0); - - auto delegate = new FakeVimUserCommandsDelegate(widget); - widget->setItemDelegateForColumn(1, delegate); - - auto layout = new QGridLayout(m_widget); - layout->addWidget(widget, 0, 0); - m_widget->setLayout(layout); - } - return m_widget; -} - -void FakeVimUserCommandsPage::apply() -{ - if (!m_widget) // page has not been shown at all - return; - - // now save the mappings if necessary - const UserCommandMap ¤t = currentCommandMap(); - UserCommandMap &userMap = dd->m_userCommandMap; - - if (current != userMap) { - QSettings *settings = ICore::settings(); - settings->beginWriteArray(userCommandMapGroup); - int count = 0; - using Iterator = UserCommandMap::const_iterator; - const Iterator end = current.constEnd(); - for (Iterator it = current.constBegin(); it != end; ++it) { - const int key = it.key(); - const QString cmd = it.value(); - - if ((dd->m_defaultUserCommandMap.contains(key) - && dd->m_defaultUserCommandMap[key] != cmd) - || (!dd->m_defaultUserCommandMap.contains(key) && !cmd.isEmpty())) { - settings->setArrayIndex(count); - settings->setValue(idKey, key); - settings->setValue(cmdKey, cmd); - ++count; - } - } - settings->endArray(); - userMap.clear(); - userMap.insert(dd->m_defaultUserCommandMap); - userMap.insert(current); - } -} - /////////////////////////////////////////////////////////////////////// // From c2ea7bc41598d4943363ac2bf4633369e25cb0a2 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 14:07:21 +0200 Subject: [PATCH 0669/1447] FakeVim: Re-organize ExCommand settings page setup Change-Id: I085a86529fc840472aabf7ae62d6565f454256ae Reviewed-by: Christian Stenger --- src/plugins/fakevim/fakevimplugin.cpp | 214 +++++++++++++------------- 1 file changed, 103 insertions(+), 111 deletions(-) diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index c56f1c3acb7..789ceaa9d16 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -568,12 +568,21 @@ public: enum { CommandRole = Qt::UserRole }; -class FakeVimExCommandsWidget : public CommandMappings +const char exCommandMapGroup[] = "FakeVimExCommand"; +const char userCommandMapGroup[] = "FakeVimUserCommand"; +const char reKey[] = "RegEx"; +const char cmdKey[] = "Cmd"; +const char idKey[] = "Command"; + +class FakeVimExCommandsMappings : public CommandMappings { public: - FakeVimExCommandsWidget(); + FakeVimExCommandsMappings(); + void apply(); protected: + ExCommandMap exCommandMapFromWidget(); + void commandChanged(); void resetToDefault(); void defaultAction() override; @@ -581,24 +590,18 @@ protected: void handleCurrentCommandChanged(QTreeWidgetItem *current); private: - void initialize(); - - ExCommandMap exCommandMapFromWidget(); - QGroupBox *m_commandBox; FancyLineEdit *m_commandEdit; - - friend class FakeVimExCommandsPage; // allow the page accessing the ExCommandMaps }; -FakeVimExCommandsWidget::FakeVimExCommandsWidget() +FakeVimExCommandsMappings::FakeVimExCommandsMappings() { setPageTitle(Tr::tr("Ex Command Mapping")); setTargetHeader(Tr::tr("Ex Trigger Expression")); setImportExportEnabled(false); - connect(this, &FakeVimExCommandsWidget::currentCommandChanged, - this, &FakeVimExCommandsWidget::handleCurrentCommandChanged); + connect(this, &FakeVimExCommandsMappings::currentCommandChanged, + this, &FakeVimExCommandsMappings::handleCurrentCommandChanged); m_commandBox = new QGroupBox(Tr::tr("Ex Command"), this); m_commandBox->setEnabled(false); @@ -607,87 +610,17 @@ FakeVimExCommandsWidget::FakeVimExCommandsWidget() m_commandEdit->setFiltering(true); m_commandEdit->setPlaceholderText(QString()); connect(m_commandEdit, &FancyLineEdit::textChanged, - this, &FakeVimExCommandsWidget::commandChanged); + this, &FakeVimExCommandsMappings::commandChanged); auto resetButton = new QPushButton(Tr::tr("Reset"), m_commandBox); resetButton->setToolTip(Tr::tr("Reset to default.")); connect(resetButton, &QPushButton::clicked, - this, &FakeVimExCommandsWidget::resetToDefault); + this, &FakeVimExCommandsMappings::resetToDefault); boxLayout->addWidget(new QLabel(Tr::tr("Regular expression:"))); boxLayout->addWidget(m_commandEdit); boxLayout->addWidget(resetButton); layout()->addWidget(m_commandBox); - initialize(); -} - -class FakeVimExCommandsPage : public IOptionsPage -{ -public: - FakeVimExCommandsPage() - { - setId(SETTINGS_EX_CMDS_ID); - setDisplayName(Tr::tr("Ex Command Mapping")); - setCategory(SETTINGS_CATEGORY); - } - - QWidget *widget() override - { - if (!m_widget) - m_widget = new FakeVimExCommandsWidget; - return m_widget; - } - - void apply() override; - void finish() override {} - -private: - QPointer m_widget; -}; - - -const char exCommandMapGroup[] = "FakeVimExCommand"; -const char userCommandMapGroup[] = "FakeVimUserCommand"; -const char reKey[] = "RegEx"; -const char cmdKey[] = "Cmd"; -const char idKey[] = "Command"; - -void FakeVimExCommandsPage::apply() -{ - if (!m_widget) // page has not been shown at all - return; - // now save the mappings if necessary - const ExCommandMap &newMapping = m_widget->exCommandMapFromWidget(); - ExCommandMap &globalCommandMapping = dd->m_exCommandMap; - - if (newMapping != globalCommandMapping) { - const ExCommandMap &defaultMap = dd->m_defaultExCommandMap; - QSettings *settings = ICore::settings(); - settings->beginWriteArray(exCommandMapGroup); - int count = 0; - using Iterator = ExCommandMap::const_iterator; - const Iterator end = newMapping.constEnd(); - for (Iterator it = newMapping.constBegin(); it != end; ++it) { - const QString id = it.key(); - const QRegularExpression re = it.value(); - - if ((defaultMap.contains(id) && defaultMap[id] != re) - || (!defaultMap.contains(id) && !re.pattern().isEmpty())) { - settings->setArrayIndex(count); - settings->setValue(idKey, id); - settings->setValue(reKey, re.pattern()); - ++count; - } - } - settings->endArray(); - globalCommandMapping.clear(); - globalCommandMapping.insert(defaultMap); - globalCommandMapping.insert(newMapping); - } -} - -void FakeVimExCommandsWidget::initialize() -{ QMap sections; const QList commands = ActionManager::commands(); @@ -727,7 +660,28 @@ void FakeVimExCommandsWidget::initialize() handleCurrentCommandChanged(nullptr); } -void FakeVimExCommandsWidget::handleCurrentCommandChanged(QTreeWidgetItem *current) +ExCommandMap FakeVimExCommandsMappings::exCommandMapFromWidget() +{ + ExCommandMap map; + int n = commandList()->topLevelItemCount(); + for (int i = 0; i != n; ++i) { + QTreeWidgetItem *section = commandList()->topLevelItem(i); + int m = section->childCount(); + for (int j = 0; j != m; ++j) { + QTreeWidgetItem *item = section->child(j); + const QString name = item->data(0, CommandRole).toString(); + const QString regex = item->data(2, Qt::DisplayRole).toString(); + const QString pattern = dd->m_defaultExCommandMap.value(name).pattern(); + if ((regex.isEmpty() && pattern.isEmpty()) + || (!regex.isEmpty() && pattern == regex)) + continue; + map[name] = QRegularExpression(regex); + } + } + return map; +} + +void FakeVimExCommandsMappings::handleCurrentCommandChanged(QTreeWidgetItem *current) { if (current) { m_commandEdit->setText(current->text(2)); @@ -738,7 +692,7 @@ void FakeVimExCommandsWidget::handleCurrentCommandChanged(QTreeWidgetItem *curre } } -void FakeVimExCommandsWidget::commandChanged() +void FakeVimExCommandsMappings::commandChanged() { QTreeWidgetItem *current = commandList()->currentItem(); if (!current) @@ -753,7 +707,7 @@ void FakeVimExCommandsWidget::commandChanged() setModified(current, regex != dd->m_defaultExCommandMap[name].pattern()); } -void FakeVimExCommandsWidget::resetToDefault() +void FakeVimExCommandsMappings::resetToDefault() { QTreeWidgetItem *current = commandList()->currentItem(); if (!current) @@ -765,12 +719,12 @@ void FakeVimExCommandsWidget::resetToDefault() m_commandEdit->setText(regex); } -void FakeVimExCommandsWidget::defaultAction() +void FakeVimExCommandsMappings::defaultAction() { - int n = commandList()->topLevelItemCount(); + const int n = commandList()->topLevelItemCount(); for (int i = 0; i != n; ++i) { QTreeWidgetItem *section = commandList()->topLevelItem(i); - int m = section->childCount(); + const int m = section->childCount(); for (int j = 0; j != m; ++j) { QTreeWidgetItem *item = section->child(j); const QString name = item->data(0, CommandRole).toString(); @@ -785,6 +739,66 @@ void FakeVimExCommandsWidget::defaultAction() } } +void FakeVimExCommandsMappings::apply() +{ + // now save the mappings if necessary + const ExCommandMap &newMapping = exCommandMapFromWidget(); + ExCommandMap &globalCommandMapping = dd->m_exCommandMap; + + if (newMapping != globalCommandMapping) { + const ExCommandMap &defaultMap = dd->m_defaultExCommandMap; + QSettings *settings = ICore::settings(); + settings->beginWriteArray(exCommandMapGroup); + int count = 0; + using Iterator = ExCommandMap::const_iterator; + const Iterator end = newMapping.constEnd(); + for (Iterator it = newMapping.constBegin(); it != end; ++it) { + const QString id = it.key(); + const QRegularExpression re = it.value(); + + if ((defaultMap.contains(id) && defaultMap[id] != re) + || (!defaultMap.contains(id) && !re.pattern().isEmpty())) { + settings->setArrayIndex(count); + settings->setValue(idKey, id); + settings->setValue(reKey, re.pattern()); + ++count; + } + } + settings->endArray(); + globalCommandMapping.clear(); + globalCommandMapping.insert(defaultMap); + globalCommandMapping.insert(newMapping); + } +} + +class FakeVimExCommandsPageWidget : public IOptionsPageWidget +{ +public: + FakeVimExCommandsPageWidget() + { + m_exCommands = new FakeVimExCommandsMappings; + auto vbox = new QVBoxLayout(this); + vbox->addWidget(m_exCommands); + } + +private: + void apply() final { m_exCommands->apply(); } + + FakeVimExCommandsMappings *m_exCommands; +}; + +class FakeVimExCommandsPage : public IOptionsPage +{ +public: + FakeVimExCommandsPage() + { + setId(SETTINGS_EX_CMDS_ID); + setDisplayName(Tr::tr("Ex Command Mapping")); + setCategory(SETTINGS_CATEGORY); + setWidgetCreator([] { return new FakeVimExCommandsPageWidget; }); + } +}; + /////////////////////////////////////////////////////////////////////// // // FakeVimUserCommandsPage @@ -2087,28 +2101,6 @@ void FakeVimPluginPrivate::switchToFile(int n) EditorManager::activateEditorForEntry(DocumentModel::entries().at(n)); } -ExCommandMap FakeVimExCommandsWidget::exCommandMapFromWidget() -{ - ExCommandMap map; - int n = commandList()->topLevelItemCount(); - for (int i = 0; i != n; ++i) { - QTreeWidgetItem *section = commandList()->topLevelItem(i); - int m = section->childCount(); - for (int j = 0; j != m; ++j) { - QTreeWidgetItem *item = section->child(j); - const QString name = item->data(0, CommandRole).toString(); - const QString regex = item->data(2, Qt::DisplayRole).toString(); - const QString pattern = dd->m_defaultExCommandMap.value(name).pattern(); - if ((regex.isEmpty() && pattern.isEmpty()) - || (!regex.isEmpty() && pattern == regex)) - continue; - map[name] = QRegularExpression(regex); - } - } - return map; -} - - /////////////////////////////////////////////////////////////////////// // From 08f3d57aa1f902fe513410d25c4f47eb977d9984 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 13 Apr 2023 07:30:32 +0200 Subject: [PATCH 0670/1447] CppEditor filters: Reimplement matchers() They are used only when ClangCodeModel plugin is disabled. Activated with '.', ':', 'c' and 'm' shortcuts. Change-Id: I131473c419e0cb302492cc6d4263bd8ad80769e4 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- .../clangcodemodel/clangdlocatorfilters.cpp | 4 +++- .../cppeditor/cppcurrentdocumentfilter.cpp | 6 ++++++ src/plugins/cppeditor/cppcurrentdocumentfilter.h | 2 ++ src/plugins/cppeditor/cpplocatorfilter.cpp | 15 +++++++++++++++ src/plugins/cppeditor/cpplocatorfilter.h | 11 +++++++++++ src/plugins/modeleditor/elementtasks.cpp | 1 - 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 973156c038a..e785402084e 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -32,6 +32,7 @@ namespace Internal { const int MaxResultCount = 10000; +// TODO: Remove this class, it's used only internally by ClangGlobalSymbolFilter class CppLocatorFilter : public CppEditor::CppLocatorFilter { public: @@ -65,7 +66,7 @@ public: } }; - +// TODO: Remove this class, it's used only internally by ClangClassesFilter class CppClassesFilter : public CppEditor::CppClassesFilter { public: @@ -98,6 +99,7 @@ public: } }; +// TODO: Remove this class, it's used only internally by ClangFunctionsFilter class CppFunctionsFilter : public CppEditor::CppFunctionsFilter { public: diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index f75eb203b8d..ba7cdfda713 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -5,6 +5,7 @@ #include "cppeditorconstants.h" #include "cppeditortr.h" +#include "cpplocatorfilter.h" #include "cppmodelmanager.h" #include @@ -42,6 +43,11 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter() this, &CppCurrentDocumentFilter::onEditorAboutToClose); } +LocatorMatcherTasks CppCurrentDocumentFilter::matchers() +{ + return CppEditor::cppMatchers(MatcherType::CurrentDocumentSymbols); +} + void CppCurrentDocumentFilter::makeAuxiliary() { setId({}); diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.h b/src/plugins/cppeditor/cppcurrentdocumentfilter.h index cd53f37b810..5327851e6ff 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.h +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.h @@ -15,6 +15,7 @@ class CppModelManager; namespace Internal { +// TODO: Move the class into cpplocatorfilter.h class CppCurrentDocumentFilter : public Core::ILocatorFilter { Q_OBJECT @@ -28,6 +29,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final; void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void onCurrentEditorChanged(Core::IEditor *currentEditor); void onEditorAboutToClose(Core::IEditor *currentEditor); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index c7373d86bd7..6ec6602f62e 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -339,6 +339,11 @@ CppLocatorFilter::CppLocatorFilter() setDefaultIncludedByDefault(false); } +LocatorMatcherTasks CppLocatorFilter::matchers() +{ + return {allSymbolsMatcher()}; +} + LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { LocatorFilterEntry filterEntry; @@ -437,6 +442,11 @@ CppClassesFilter::CppClassesFilter() setDefaultIncludedByDefault(false); } +LocatorMatcherTasks CppClassesFilter::matchers() +{ + return {classMatcher()}; +} + LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { LocatorFilterEntry filterEntry; @@ -459,6 +469,11 @@ CppFunctionsFilter::CppFunctionsFilter() setDefaultIncludedByDefault(false); } +LocatorMatcherTasks CppFunctionsFilter::matchers() +{ + return {functionMatcher()}; +} + LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr info) { QString name = info->symbolName(); diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 2328fc06f8b..65bc5fa2d13 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -24,8 +24,12 @@ public: protected: virtual IndexItem::ItemType matchTypes() const { return IndexItem::All; } virtual Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info); + +private: + Core::LocatorMatcherTasks matchers() override; }; +// TODO: Don't derive, flatten the hierarchy class CPPEDITOR_EXPORT CppClassesFilter : public CppLocatorFilter { Q_OBJECT @@ -36,8 +40,12 @@ public: protected: IndexItem::ItemType matchTypes() const override { return IndexItem::Class; } Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info) override; + +private: + Core::LocatorMatcherTasks matchers() final; }; +// TODO: Don't derive, flatten the hierarchy class CPPEDITOR_EXPORT CppFunctionsFilter : public CppLocatorFilter { Q_OBJECT @@ -48,6 +56,9 @@ public: protected: IndexItem::ItemType matchTypes() const override { return IndexItem::Function; } Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info) override; + +private: + Core::LocatorMatcherTasks matchers() final; }; } // namespace CppEditor diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp index 620ee66d2c6..d54cc2e6c84 100644 --- a/src/plugins/modeleditor/elementtasks.cpp +++ b/src/plugins/modeleditor/elementtasks.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include From f5d7765094b814996a479fbfbcb37853580a4c2f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 13 Apr 2023 10:06:16 +0200 Subject: [PATCH 0671/1447] LanguageClient/ClangCodeModel: Reimplement matchers() Don't assert when ClientRequestTask::preStartCheck() failed. Change-Id: I157fe8fc15aa055b70823d6a54454c6eec692f88 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz --- .../clangcodemodel/clangdlocatorfilters.cpp | 24 +++++++++++++++++++ .../clangcodemodel/clangdlocatorfilters.h | 9 +++++++ .../languageclient/clientrequesttask.h | 7 +++--- src/plugins/languageclient/locatorfilter.cpp | 18 ++++++++++++++ src/plugins/languageclient/locatorfilter.h | 9 +++++++ 5 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index e785402084e..70b5c1c1ec3 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -47,6 +47,7 @@ public: } }; +// TODO: Remove this class, it's used only internally by ClangGlobalSymbolFilter class LspWorkspaceFilter : public WorkspaceLocatorFilter { public: @@ -81,6 +82,7 @@ public: } }; +// TODO: Remove this class, it's used only internally by ClangClassesFilter class LspClassesFilter : public WorkspaceClassLocatorFilter { public: @@ -114,6 +116,7 @@ public: } }; +// TODO: Remove this class, it's used only internally by ClangFunctionsFilter class LspFunctionsFilter : public WorkspaceMethodLocatorFilter { public: @@ -156,6 +159,13 @@ ClangGlobalSymbolFilter::~ClangGlobalSymbolFilter() delete m_lspFilter; } +LocatorMatcherTasks ClangGlobalSymbolFilter::matchers() +{ + return CppEditor::cppMatchers(MatcherType::AllSymbols) + + LanguageClient::workspaceMatchers(MatcherType::AllSymbols, + ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); +} + void ClangGlobalSymbolFilter::prepareSearch(const QString &entry) { m_cppFilter->prepareSearch(entry); @@ -178,6 +188,13 @@ ClangClassesFilter::ClangClassesFilter() setDefaultIncludedByDefault(false); } +LocatorMatcherTasks ClangClassesFilter::matchers() +{ + return CppEditor::cppMatchers(MatcherType::Classes) + + LanguageClient::workspaceMatchers(MatcherType::Classes, + ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); +} + ClangFunctionsFilter::ClangFunctionsFilter() : ClangGlobalSymbolFilter(new CppFunctionsFilter, new LspFunctionsFilter) { @@ -188,6 +205,13 @@ ClangFunctionsFilter::ClangFunctionsFilter() setDefaultIncludedByDefault(false); } +LocatorMatcherTasks ClangFunctionsFilter::matchers() +{ + return CppEditor::cppMatchers(MatcherType::Functions) + + LanguageClient::workspaceMatchers(MatcherType::Functions, + ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); +} + class LspCurrentDocumentFilter : public DocumentLocatorFilter { public: diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index 70afd4cce2e..384edeab588 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -19,6 +19,7 @@ public: ~ClangGlobalSymbolFilter() override; private: + Core::LocatorMatcherTasks matchers() override; void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; @@ -26,16 +27,24 @@ private: Core::ILocatorFilter * const m_lspFilter; }; +// TODO: Don't derive, flatten the hierarchy class ClangClassesFilter : public ClangGlobalSymbolFilter { public: ClangClassesFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; +// TODO: Don't derive, flatten the hierarchy class ClangFunctionsFilter : public ClangGlobalSymbolFilter { public: ClangFunctionsFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; class ClangdCurrentDocumentFilter : public Core::ILocatorFilter diff --git a/src/plugins/languageclient/clientrequesttask.h b/src/plugins/languageclient/clientrequesttask.h index dc14d5bf2ff..9f92bc9047b 100644 --- a/src/plugins/languageclient/clientrequesttask.h +++ b/src/plugins/languageclient/clientrequesttask.h @@ -14,7 +14,6 @@ namespace LanguageClient { - template class LANGUAGECLIENT_EXPORT ClientRequestTask { @@ -32,8 +31,10 @@ public: void start() { QTC_ASSERT(!isRunning(), return); - QTC_ASSERT(preStartCheck(), m_callback({}); return); - + if (!preStartCheck()) { + m_callback({}); + return; + } Request request(m_params); request.setResponseCallback([this](const typename Request::Response &response) { m_response = response; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 55aca73b819..dd83f7ea93f 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -301,6 +301,12 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter() : WorkspaceLocatorFilter(QVector()) {} +LocatorMatcherTasks WorkspaceLocatorFilter::matchers() +{ + return workspaceMatchers(MatcherType::AllSymbols, + Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); +} + WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter) : m_filterKinds(filter) { @@ -407,6 +413,12 @@ WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter() setDefaultShortcutString("c"); } +LocatorMatcherTasks WorkspaceClassLocatorFilter::matchers() +{ + return workspaceMatchers(MatcherType::Classes, + Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); +} + WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() : WorkspaceLocatorFilter({SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}) { @@ -416,4 +428,10 @@ WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() setDefaultShortcutString("m"); } +LocatorMatcherTasks WorkspaceMethodLocatorFilter::matchers() +{ + return workspaceMatchers(MatcherType::Functions, + Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); +} + } // namespace LanguageClient diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index f3c48542560..f6c3382c411 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -85,6 +85,7 @@ protected: void setMaxResultCount(qint64 limit) { m_maxResultCount = limit; } private: + Core::LocatorMatcherTasks matchers() override; void handleResponse(Client *client, const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); @@ -102,16 +103,24 @@ private: qint64 m_maxResultCount = 0; }; +// TODO: Don't derive, flatten the hierarchy class LANGUAGECLIENT_EXPORT WorkspaceClassLocatorFilter : public WorkspaceLocatorFilter { public: WorkspaceClassLocatorFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; +// TODO: Don't derive, flatten the hierarchy class LANGUAGECLIENT_EXPORT WorkspaceMethodLocatorFilter : public WorkspaceLocatorFilter { public: WorkspaceMethodLocatorFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; } // namespace LanguageClient From 54af6bd5b3f5ba5e3396f5cb9eb539f198abafff Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 21 Apr 2023 22:08:45 +0200 Subject: [PATCH 0672/1447] CMakePM: Allow files to be renamed in project view This includes both with source files explicitly specified or resulted from a file(GLOB|GLOB_RECOURSE) call. Fixes: QTCREATORBUG-27538 Change-Id: I5ee113af168bdb8cd0a96e8ab2ae603c0607fb0b Reviewed-by: hjk Reviewed-by: --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 147 +++++++++++++++++- .../cmakeprojectmanager/cmakebuildsystem.h | 16 ++ .../hello-widgets/CMakeLists.txt | 5 + 3 files changed, 167 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 9cb3692d765..052ef4deeee 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -201,7 +201,8 @@ void CMakeBuildSystem::triggerParsing() bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const { if (dynamic_cast(context)) - return action == ProjectAction::AddNewFile || action == ProjectAction::AddExistingFile; + return action == ProjectAction::AddNewFile || action == ProjectAction::AddExistingFile + || action == ProjectAction::Rename; return BuildSystem::supportsAction(context, action, node); } @@ -366,6 +367,150 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP return BuildSystem::addFiles(context, filePaths, notAdded); } +bool CMakeBuildSystem::canRenameFile(Node *context, + const FilePath &oldFilePath, + const FilePath &newFilePath) +{ + // "canRenameFile" will cause an actual rename after the function call. + // This will make the a sequence like + // canonicalPath().relativePathFrom(projDir).cleanPath().toString() + // to fail if the file doesn't exist on disk + // therefore cache the results for the subsequent "renameFile" call + // where oldFilePath has already been renamed as newFilePath. + + if (auto n = dynamic_cast(context)) { + const FilePath projDir = n->filePath().canonicalPath(); + const QString oldRelPathName + = oldFilePath.canonicalPath().relativePathFrom(projDir).cleanPath().toString(); + + const QString targetName = n->buildKey(); + auto target = Utils::findOrDefault(buildTargets(), + [targetName](const CMakeBuildTarget &target) { + return target.title == targetName; + }); + + if (target.backtrace.isEmpty()) { + return false; + } + const FilePath targetCMakeFile = target.backtrace.last().path; + + // Have a fresh look at the CMake file, not relying on a cached value + expected_str fileContent = targetCMakeFile.fileContents(); + cmListFile cmakeListFile; + std::string errorString; + if (fileContent) { + fileContent = fileContent->replace("\r\n", "\n"); + if (!cmakeListFile.ParseString(fileContent->toStdString(), + targetCMakeFile.fileName().toStdString(), + errorString)) + return false; + } + + const int targetDefinitionLine = target.backtrace.last().line; + + auto function = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [targetDefinitionLine](const auto &func) { + return func.Line() == targetDefinitionLine; + }); + + const std::string target_name = targetName.toStdString(); + auto targetSourcesFunc + = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [target_name = targetName.toStdString()](const auto &func) { + return func.LowerCaseName() == "target_sources" + && func.Arguments().front().Value == target_name; + }); + + for (const auto &func : {function, targetSourcesFunc}) { + if (func == cmakeListFile.Functions.end()) + continue; + auto filePathArgument + = Utils::findOrDefault(func->Arguments(), + [fileName = oldRelPathName.toStdString()](const auto &arg) { + return arg.Delim != cmListFileArgument::Comment + && arg.Value == fileName; + }); + + const QString key + = QStringList{projDir.path(), targetName, oldFilePath.path(), newFilePath.path()} + .join(";"); + + if (!filePathArgument.Value.empty()) { + m_filesToBeRenamed.insert(key, {filePathArgument, targetCMakeFile, oldRelPathName}); + return true; + } else { + const auto globFunctions = std::get<0>( + Utils::partition(cmakeListFile.Functions, [](const auto &f) { + return f.LowerCaseName() == "file" && f.Arguments().size() > 2 + && (f.Arguments().front().Value == "GLOB" + || f.Arguments().front().Value == "GLOB_RECURSE"); + })); + + const auto globVariables + = Utils::transform(globFunctions, [](const auto &func) { + return std::string("${") + func.Arguments()[1].Value + "}"; + }); + + const auto haveGlobbing + = Utils::anyOf(func->Arguments(), [globVariables](const auto &arg) { + return globVariables.contains(arg.Value) + && arg.Delim != cmListFileArgument::Comment; + }); + + if (haveGlobbing) { + m_filesToBeRenamed + .insert(key, {filePathArgument, targetCMakeFile, oldRelPathName, true}); + return true; + } + } + } + } + return false; +} + +bool CMakeBuildSystem::renameFile(Node *context, + const FilePath &oldFilePath, + const FilePath &newFilePath) +{ + if (auto n = dynamic_cast(context)) { + const FilePath projDir = n->filePath().canonicalPath(); + const QString newRelPathName + = newFilePath.canonicalPath().relativePathFrom(projDir).cleanPath().toString(); + + const QString targetName = n->buildKey(); + const QString key + = QStringList{projDir.path(), targetName, oldFilePath.path(), newFilePath.path()}.join( + ";"); + + auto fileToRename = m_filesToBeRenamed.take(key); + if (!fileToRename.cmakeFile.exists()) + return false; + + BaseTextEditor *editor = qobject_cast( + Core::EditorManager::openEditorAt({fileToRename.cmakeFile, + static_cast(fileToRename.argumentPosition.Line), + static_cast(fileToRename.argumentPosition.Column + - 1)}, + Constants::CMAKE_EDITOR_ID, + Core::EditorManager::DoNotMakeVisible)); + if (!editor) + return false; + + if (!fileToRename.fromGlobbing) + editor->replace(fileToRename.oldRelativeFileName.length(), newRelPathName); + + editor->editorWidget()->autoIndent(); + if (!Core::DocumentManager::saveDocument(editor->document())) + return false; + + return true; + } + + return false; +} + FilePaths CMakeBuildSystem::filesGeneratedFrom(const FilePath &sourceFile) const { FilePath project = projectDirectory(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index eea894f5e92..9566df6ada5 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -48,6 +48,13 @@ public: bool addFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths, Utils::FilePaths *) final; + bool canRenameFile(ProjectExplorer::Node *context, + const Utils::FilePath &oldFilePath, + const Utils::FilePath &newFilePath) final; + bool renameFile(ProjectExplorer::Node *context, + const Utils::FilePath &oldFilePath, + const Utils::FilePath &newFilePath) final; + Utils::FilePaths filesGeneratedFrom(const Utils::FilePath &sourceFile) const final; QString name() const final { return QLatin1String("cmake"); } @@ -201,6 +208,15 @@ private: QList m_buildTargets; QSet m_cmakeFiles; + struct FileToBeRenamed + { + cmListFileArgument argumentPosition; + Utils::FilePath cmakeFile; + QString oldRelativeFileName; + bool fromGlobbing = false; + }; + QHash m_filesToBeRenamed; + // Parsing state: BuildDirParameters m_parameters; int m_reparseParameters = REPARSE_DEFAULT; diff --git a/tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt b/tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt index 4400c291ef0..8c0c413d663 100644 --- a/tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt +++ b/tests/manual/cmakeprojectmanager/hello-widgets/CMakeLists.txt @@ -30,3 +30,8 @@ my_add_executable(hello-my-widgets ) target_link_libraries(hello-my-widgets PRIVATE Qt6::Widgets) + +file(GLOB SOURCE_FILES CONFIGURE_DEPENDS *.cpp *.h *.ui) + +add_executable(hello-widgets-glob ${SOURCE_FILES}) +target_link_libraries(hello-widgets-glob PRIVATE Qt6::Widgets) From 411b2e05b8ac4442d1ef179381dc7c37492ab37b Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 24 Apr 2023 20:28:10 +0200 Subject: [PATCH 0673/1447] CMakePM: Allow project files to be removed in project view Removal of a project file is done as a rename with an empty filename. Fixes: QTCREATORBUG-25922 Change-Id: I4443d4a31723eb1ac93f02bad633bcfaf99a9573 Reviewed-by: Reviewed-by: hjk --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 228 +++++++++++------- .../cmakeprojectmanager/cmakebuildsystem.h | 24 +- 2 files changed, 163 insertions(+), 89 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 052ef4deeee..c49dc50a770 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -202,7 +202,7 @@ bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const { if (dynamic_cast(context)) return action == ProjectAction::AddNewFile || action == ProjectAction::AddExistingFile - || action == ProjectAction::Rename; + || action == ProjectAction::Rename || action == ProjectAction::RemoveFile; return BuildSystem::supportsAction(context, action, node); } @@ -367,6 +367,143 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP return BuildSystem::addFiles(context, filePaths, notAdded); } +std::optional +CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const QString &fileName) +{ + auto target = Utils::findOrDefault(buildTargets(), [targetName](const CMakeBuildTarget &target) { + return target.title == targetName; + }); + + if (target.backtrace.isEmpty()) + return std::nullopt; + + const FilePath targetCMakeFile = target.backtrace.last().path; + + // Have a fresh look at the CMake file, not relying on a cached value + expected_str fileContent = targetCMakeFile.fileContents(); + cmListFile cmakeListFile; + std::string errorString; + if (fileContent) { + fileContent = fileContent->replace("\r\n", "\n"); + if (!cmakeListFile.ParseString(fileContent->toStdString(), + targetCMakeFile.fileName().toStdString(), + errorString)) + return std::nullopt; + } + + const int targetDefinitionLine = target.backtrace.last().line; + + auto function = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [targetDefinitionLine](const auto &func) { + return func.Line() == targetDefinitionLine; + }); + + const std::string target_name = targetName.toStdString(); + auto targetSourcesFunc + = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [target_name = targetName.toStdString()](const auto &func) { + return func.LowerCaseName() == "target_sources" + && func.Arguments().front().Value == target_name; + }); + + for (const auto &func : {function, targetSourcesFunc}) { + if (func == cmakeListFile.Functions.end()) + continue; + auto filePathArgument + = Utils::findOrDefault(func->Arguments(), + [file_name = fileName.toStdString()](const auto &arg) { + return arg.Delim != cmListFileArgument::Comment + && arg.Value == file_name; + }); + + if (!filePathArgument.Value.empty()) { + return ProjectFileArgumentPosition{filePathArgument, targetCMakeFile, fileName}; + } else { + const auto globFunctions = std::get<0>( + Utils::partition(cmakeListFile.Functions, [](const auto &f) { + return f.LowerCaseName() == "file" && f.Arguments().size() > 2 + && (f.Arguments().front().Value == "GLOB" + || f.Arguments().front().Value == "GLOB_RECURSE"); + })); + + const auto globVariables = Utils::transform(globFunctions, [](const auto &func) { + return std::string("${") + func.Arguments()[1].Value + "}"; + }); + + const auto haveGlobbing = Utils::anyOf(func->Arguments(), + [globVariables](const auto &arg) { + return globVariables.contains(arg.Value) + && arg.Delim + != cmListFileArgument::Comment; + }); + + if (haveGlobbing) + return ProjectFileArgumentPosition{filePathArgument, + targetCMakeFile, + fileName, + true}; + } + } + + return std::nullopt; +} + +RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context, + const FilePaths &filePaths, + FilePaths *notRemoved) +{ + FilePaths badFiles; + if (auto n = dynamic_cast(context)) { + const FilePath projDir = n->filePath().canonicalPath(); + const QString targetName = n->buildKey(); + + for (const auto &file : filePaths) { + const QString fileName + = file.canonicalPath().relativePathFrom(projDir).cleanPath().toString(); + + auto filePos = projectFileArgumentPosition(targetName, fileName); + if (filePos) { + if (!filePos.value().cmakeFile.exists()) { + badFiles << file; + continue; + } + + BaseTextEditor *editor = qobject_cast( + Core::EditorManager::openEditorAt({filePos.value().cmakeFile, + static_cast(filePos.value().argumentPosition.Line), + static_cast(filePos.value().argumentPosition.Column + - 1)}, + Constants::CMAKE_EDITOR_ID, + Core::EditorManager::DoNotMakeVisible)); + if (!editor) { + badFiles << file; + continue; + } + + if (!filePos.value().fromGlobbing) + editor->replace(filePos.value().relativeFileName.length(), ""); + + editor->editorWidget()->autoIndent(); + if (!Core::DocumentManager::saveDocument(editor->document())) { + badFiles << file; + continue; + } + } else { + badFiles << file; + } + } + + if (notRemoved && !badFiles.isEmpty()) + *notRemoved = badFiles; + + return badFiles.isEmpty() ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error; + } + + return RemovedFilesFromProject::Error; +} + bool CMakeBuildSystem::canRenameFile(Node *context, const FilePath &oldFilePath, const FilePath &newFilePath) @@ -384,88 +521,17 @@ bool CMakeBuildSystem::canRenameFile(Node *context, = oldFilePath.canonicalPath().relativePathFrom(projDir).cleanPath().toString(); const QString targetName = n->buildKey(); - auto target = Utils::findOrDefault(buildTargets(), - [targetName](const CMakeBuildTarget &target) { - return target.title == targetName; - }); - if (target.backtrace.isEmpty()) { + const QString key + = QStringList{projDir.path(), targetName, oldFilePath.path(), newFilePath.path()} + .join(";"); + + auto filePos = projectFileArgumentPosition(targetName, oldRelPathName); + if (!filePos) return false; - } - const FilePath targetCMakeFile = target.backtrace.last().path; - // Have a fresh look at the CMake file, not relying on a cached value - expected_str fileContent = targetCMakeFile.fileContents(); - cmListFile cmakeListFile; - std::string errorString; - if (fileContent) { - fileContent = fileContent->replace("\r\n", "\n"); - if (!cmakeListFile.ParseString(fileContent->toStdString(), - targetCMakeFile.fileName().toStdString(), - errorString)) - return false; - } - - const int targetDefinitionLine = target.backtrace.last().line; - - auto function = std::find_if(cmakeListFile.Functions.begin(), - cmakeListFile.Functions.end(), - [targetDefinitionLine](const auto &func) { - return func.Line() == targetDefinitionLine; - }); - - const std::string target_name = targetName.toStdString(); - auto targetSourcesFunc - = std::find_if(cmakeListFile.Functions.begin(), - cmakeListFile.Functions.end(), - [target_name = targetName.toStdString()](const auto &func) { - return func.LowerCaseName() == "target_sources" - && func.Arguments().front().Value == target_name; - }); - - for (const auto &func : {function, targetSourcesFunc}) { - if (func == cmakeListFile.Functions.end()) - continue; - auto filePathArgument - = Utils::findOrDefault(func->Arguments(), - [fileName = oldRelPathName.toStdString()](const auto &arg) { - return arg.Delim != cmListFileArgument::Comment - && arg.Value == fileName; - }); - - const QString key - = QStringList{projDir.path(), targetName, oldFilePath.path(), newFilePath.path()} - .join(";"); - - if (!filePathArgument.Value.empty()) { - m_filesToBeRenamed.insert(key, {filePathArgument, targetCMakeFile, oldRelPathName}); - return true; - } else { - const auto globFunctions = std::get<0>( - Utils::partition(cmakeListFile.Functions, [](const auto &f) { - return f.LowerCaseName() == "file" && f.Arguments().size() > 2 - && (f.Arguments().front().Value == "GLOB" - || f.Arguments().front().Value == "GLOB_RECURSE"); - })); - - const auto globVariables - = Utils::transform(globFunctions, [](const auto &func) { - return std::string("${") + func.Arguments()[1].Value + "}"; - }); - - const auto haveGlobbing - = Utils::anyOf(func->Arguments(), [globVariables](const auto &arg) { - return globVariables.contains(arg.Value) - && arg.Delim != cmListFileArgument::Comment; - }); - - if (haveGlobbing) { - m_filesToBeRenamed - .insert(key, {filePathArgument, targetCMakeFile, oldRelPathName, true}); - return true; - } - } - } + m_filesToBeRenamed.insert(key, filePos.value()); + return true; } return false; } @@ -499,7 +565,7 @@ bool CMakeBuildSystem::renameFile(Node *context, return false; if (!fileToRename.fromGlobbing) - editor->replace(fileToRename.oldRelativeFileName.length(), newRelPathName); + editor->replace(fileToRename.relativeFileName.length(), newRelPathName); editor->editorWidget()->autoIndent(); if (!Core::DocumentManager::saveDocument(editor->document())) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 9566df6ada5..b36b85d98f2 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -48,6 +48,11 @@ public: bool addFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths, Utils::FilePaths *) final; + ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context, + const Utils::FilePaths &filePaths, + Utils::FilePaths *notRemoved + = nullptr) final; + bool canRenameFile(ProjectExplorer::Node *context, const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) final; @@ -192,6 +197,16 @@ private: void runCTest(); + struct ProjectFileArgumentPosition + { + cmListFileArgument argumentPosition; + Utils::FilePath cmakeFile; + QString relativeFileName; + bool fromGlobbing = false; + }; + std::optional projectFileArgumentPosition( + const QString &targetName, const QString &fileName); + ProjectExplorer::TreeScanner m_treeScanner; std::shared_ptr m_allFiles; QHash m_mimeBinaryCache; @@ -208,14 +223,7 @@ private: QList m_buildTargets; QSet m_cmakeFiles; - struct FileToBeRenamed - { - cmListFileArgument argumentPosition; - Utils::FilePath cmakeFile; - QString oldRelativeFileName; - bool fromGlobbing = false; - }; - QHash m_filesToBeRenamed; + QHash m_filesToBeRenamed; // Parsing state: BuildDirParameters m_parameters; From dad415b884b17df7e54e077c3fc5202237278dba Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 19 Apr 2023 20:00:04 +0200 Subject: [PATCH 0674/1447] Terminal: add cmd shell integration when using clink The script was provided at https://github.com/chrisant996/clink/discussions/453 If clink is not installed cmd will not have any issues, since only the environment variable CLINK_PATH will be set. Change-Id: I9f1d16933ae6bbcb3da1243e8704af6dc86b9a4d Reviewed-by: Cristian Adam Reviewed-by: --- README.md | 28 ++++++++++ .../overview/creator-acknowledgements.qdoc | 12 +++++ src/plugins/terminal/shellintegration.cpp | 16 ++++++ .../shellintegration-clink.lua | 52 +++++++++++++++++++ src/plugins/terminal/terminal.qrc | 27 +++++----- 5 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 src/plugins/terminal/shellintegrations/shellintegration-clink.lua diff --git a/README.md b/README.md index 410d8f03e8d..5a5301b3b52 100644 --- a/README.md +++ b/README.md @@ -868,6 +868,34 @@ SQLite (https://www.sqlite.org) is in the Public Domain. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +### terminal/shellintegrations/clink + + The Terminal plugin uses a lua script to integrate with the cmd shell when using clink. + + https://github.com/chrisant996/clink-gizmos + + MIT License + + Copyright (c) 2023 Chris Antos + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + ### cmake The CMake project manager uses the CMake lexer code for parsing CMake files diff --git a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc index 7f193d124dc..7f607374759 100644 --- a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc +++ b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc @@ -1059,6 +1059,18 @@ \include license-mit.qdocinc + \li \b terminal/shellintegrations/clink + + The Terminal plugin uses a lua script to integrate with the cmd shell when using clink. + + \list + \li \l https://github.com/chrisant996/clink-gizmos + \endlist + + Distributed under the MIT license. + + \include license-mit.qdocinc + \li \b cmake The CMake project manager uses the CMake lexer code for parsing CMake files. diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp index fd4c1364696..00f1b75cd69 100644 --- a/src/plugins/terminal/shellintegration.cpp +++ b/src/plugins/terminal/shellintegration.cpp @@ -41,6 +41,10 @@ struct { FilePath script{":/terminal/shellintegrations/shellintegration.ps1"}; } pwsh; + struct + { + FilePath script{":/terminal/shellintegrations/shellintegration-clink.lua"}; + } clink; } filesToCopy; // clang-format on @@ -64,6 +68,9 @@ bool ShellIntegration::canIntegrate(const Utils::CommandLine &cmdLine) return true; } + if (cmdLine.executable().baseName() == "cmd") + return true; + return false; } @@ -105,6 +112,7 @@ void ShellIntegration::prepareProcess(Utils::QtcProcess &process) return; env.set("VSCODE_INJECTION", "1"); + env.set("TERM_PROGRAM", "vscode"); if (cmd.executable().baseName() == "bash") { const FilePath rcPath = filesToCopy.bash.rcFile; @@ -134,6 +142,14 @@ void ShellIntegration::prepareProcess(Utils::QtcProcess &process) cmd.addArgs(QString("-noexit -command try { . \"%1\" } catch {}{1}").arg(tmpRc.nativePath()), CommandLine::Raw); + } else if (cmd.executable().baseName() == "cmd") { + const FilePath rcPath = filesToCopy.clink.script; + const FilePath tmpRc = FilePath::fromUserInput( + m_tempDir.filePath(filesToCopy.clink.script.fileName())); + rcPath.copyFile(tmpRc); + + env.set("CLINK_HISTORY_LABEL", "QtCreator"); + env.appendOrSet("CLINK_PATH", tmpRc.parentDir().nativePath(), ";"); } process.setCommand(cmd); diff --git a/src/plugins/terminal/shellintegrations/shellintegration-clink.lua b/src/plugins/terminal/shellintegrations/shellintegration-clink.lua new file mode 100644 index 00000000000..ff9d5f3facc --- /dev/null +++ b/src/plugins/terminal/shellintegrations/shellintegration-clink.lua @@ -0,0 +1,52 @@ +-- Copyright (c) 2023 Chris Antos +-- SPDX-License-Identifier: MIT + +-- luacheck: globals vscode_shell_integration NONL +if vscode_shell_integration == nil then + vscode_shell_integration = true +end + +if not vscode_shell_integration then + return +end + +local function is_vscode() + local term_program = os.getenv("term_program") or "" + if term_program:lower() == "vscode" then + return true + end +end + +local function send_context() + if is_vscode() then + local codes = "" + codes = codes .. "\027]633;D;" .. os.geterrorlevel() .. "\a" -- send command exit code + codes = codes .. "\027]633;P;Cwd=" .. os.getcwd() .. "\a" -- send cwd as title + clink.print(codes, NONL) + end +end + +local p = clink.promptfilter(-999) + +function p:filter() -- luacheck: no unused + -- Nothing to do here, but the filter function must be defined. +end + +function p:surround() -- luacheck: no unused + if is_vscode() then + local pre, suf + local rpre, rsuf + + -- ESC codes surrounding prompt string + pre = "\027]633;A\a" -- copied from shellIntegration-rc.zsh + suf = "\027]633;B\a" -- copied from shellIntegration-rc.zsh + + -- ESC codes surrounding right side prompt string + rpre = "\027]633;H\a" -- copied from shellIntegration-rc.zsh + rsuf = "\027]633;I\a" -- copied from shellIntegration-rc.zsh + + return pre, suf, rpre, rsuf + end +end + +clink.onbeginedit(send_context) diff --git a/src/plugins/terminal/terminal.qrc b/src/plugins/terminal/terminal.qrc index 50fcff4f2f0..63c28169dfd 100644 --- a/src/plugins/terminal/terminal.qrc +++ b/src/plugins/terminal/terminal.qrc @@ -1,15 +1,16 @@ - - images/settingscategory_terminal.png - images/settingscategory_terminal@2x.png - images/terminal.png - images/terminal@2x.png - shellintegrations/shellintegration-bash.sh - shellintegrations/shellintegration-env.zsh - shellintegrations/shellintegration-login.zsh - shellintegrations/shellintegration-profile.zsh - shellintegrations/shellintegration-rc.zsh - shellintegrations/shellintegration.fish - shellintegrations/shellintegration.ps1 - + + images/settingscategory_terminal.png + images/settingscategory_terminal@2x.png + images/terminal.png + images/terminal@2x.png + shellintegrations/shellintegration-bash.sh + shellintegrations/shellintegration-env.zsh + shellintegrations/shellintegration-login.zsh + shellintegrations/shellintegration-profile.zsh + shellintegrations/shellintegration-rc.zsh + shellintegrations/shellintegration.fish + shellintegrations/shellintegration.ps1 + shellintegrations/shellintegration-clink.lua + From b7ca84c5eef0eeb50cd9e86dad7482ab6f19cdd8 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 24 Apr 2023 17:06:32 +0200 Subject: [PATCH 0675/1447] Utils: Remove one LayoutBuilder::addRow() overload The flexibility here is getting in the way later when trying to remove the dependency on aspects. Change-Id: I7221e80f2067292c7c80aead8f6d739fb7878f7e Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/libs/utils/layoutbuilder.cpp | 11 ----------- src/libs/utils/layoutbuilder.h | 1 - src/plugins/android/androiddeployqtstep.cpp | 4 ++-- .../cmakeprojectmanager/cmakebuildstep.cpp | 10 +++++----- .../cmakeprojectmanager/cmakeinstallstep.cpp | 2 +- src/plugins/coreplugin/generalsettings.cpp | 2 +- src/plugins/coreplugin/systemsettings.cpp | 15 +++++++-------- .../debugger/debuggerrunconfigurationaspect.cpp | 6 +++--- .../debugger/debuggersourcepathmappingwidget.cpp | 2 +- src/plugins/projectexplorer/makestep.cpp | 8 ++++---- src/plugins/qbsprojectmanager/qbsbuildstep.cpp | 12 ++++++------ src/plugins/qbsprojectmanager/qbsinstallstep.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 6 +++--- 13 files changed, 34 insertions(+), 47 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index e7136c5a900..f4b1dda3ee6 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -341,17 +341,6 @@ LayoutBuilder &LayoutBuilder::finishRow() return *this; } -/*! - This starts a new row containing the \a item. The row can be further extended by - other items using \c addItem() or \c addItems(). - - \sa finishRow(), addItem(), addItems() - */ -LayoutBuilder &LayoutBuilder::addRow(const LayoutItem &item) -{ - return finishRow().addItem(item); -} - /*! This starts a new row containing \a items. The row can be further extended by other items using \c addItem() or \c addItems(). diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index d34a8f6cf44..b32668e22d3 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -188,7 +188,6 @@ public: LayoutBuilder &addItems(const LayoutItems &items); LayoutBuilder &finishRow(); - LayoutBuilder &addRow(const LayoutItem &item); LayoutBuilder &addRow(const LayoutItems &items); LayoutType layoutType() const { return m_layoutType; } diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 88092aef529..8b2bf8fb09f 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -603,8 +603,8 @@ QWidget *AndroidDeployQtStep::createConfigWidget() }); Layouting::Form builder; - builder.addRow(m_uninstallPreviousPackage); - builder.addRow(installCustomApkButton); + builder.addRow({m_uninstallPreviousPackage}); + builder.addRow({installCustomApkButton}); builder.attachTo(widget, Layouting::WithoutMargins); return widget; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 1e70c034ecd..bbf321cd70b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -560,17 +560,17 @@ QWidget *CMakeBuildStep::createConfigWidget() envWidget->setBaseEnvironmentText(baseEnvironmentText()); }); - builder.addRow(clearBox); - builder.addRow(envWidget); + builder.addRow({clearBox}); + builder.addRow({envWidget}); }; Layouting::Form builder; - builder.addRow(m_cmakeArguments); - builder.addRow(m_toolArguments); + builder.addRow({m_cmakeArguments}); + builder.addRow({m_toolArguments}); builder.addRow({Tr::tr("Stage for installation:"), Layouting::Row{m_useStaging, m_stagingDir}}); if (m_useiOSAutomaticProvisioningUpdates) - builder.addRow(m_useiOSAutomaticProvisioningUpdates); + builder.addRow({m_useiOSAutomaticProvisioningUpdates}); builder.addRow({new QLabel(Tr::tr("Targets:")), frame}); diff --git a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp index 445bfd9c145..97c29631c47 100644 --- a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp @@ -107,7 +107,7 @@ QWidget *CMakeInstallStep::createConfigWidget() setDisplayName(Tr::tr("Install", "ConfigWidget display name.")); Layouting::Form builder; - builder.addRow(m_cmakeArguments); + builder.addRow({m_cmakeArguments}); auto widget = builder.emerge(Layouting::WithoutMargins); diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp index ae5139b95c8..e12cb1ccc2c 100644 --- a/src/plugins/coreplugin/generalsettings.cpp +++ b/src/plugins/coreplugin/generalsettings.cpp @@ -114,7 +114,7 @@ GeneralSettingsWidget::GeneralSettingsWidget(GeneralSettings *q) } form.addRow({empty, m_showShortcutsInContextMenus}); - form.addRow(Row{m_resetWarningsButton, st}); + form.addRow({Row{m_resetWarningsButton, st}}); form.addRow({Tr::tr("Text codec for tools:"), m_codecBox, st}); Column{Group{title(Tr::tr("User Interface")), form}}.attachTo(this); diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index a65f7fee8b1..5d9a5fd3f9f 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -170,19 +170,18 @@ public: {Tr::tr("When files are externally modified:"), Span(2, Row{m_reloadBehavior, st})}); form.addRow( {m_autoSaveCheckBox, Span(2, Row{Tr::tr("Interval:"), m_autoSaveInterval, st})}); - form.addRow(Span(3, m_autoSaveRefactoringCheckBox)); + form.addRow({Span(3, m_autoSaveRefactoringCheckBox)}); form.addRow({m_autoSuspendCheckBox, Span(2, Row{autoSuspendLabel, m_autoSuspendMinDocumentCount, st})}); - form.addRow(Span(3, Row{m_warnBeforeOpeningBigFiles, m_bigFilesLimitSpinBox, st})); - form.addRow(Span(3, + form.addRow({Span(3, Row{m_warnBeforeOpeningBigFiles, m_bigFilesLimitSpinBox, st})}); + form.addRow({Span(3, Row{Tr::tr("Maximum number of entries in \"Recent Files\":"), m_maxRecentFilesSpinBox, - st})); - form.addRow(m_askBeforeExitCheckBox); + st})}); + form.addRow({m_askBeforeExitCheckBox}); #ifdef ENABLE_CRASHPAD - form.addRow( - Span(3, Row{m_enableCrashReportingCheckBox, helpCrashReportingButton, st})); - form.addRow(Span(3, Row{m_clearCrashReportsButton, m_crashReportsSizeText, st})); + form.addRow({Span(3, Row{m_enableCrashReportingCheckBox, helpCrashReportingButton, st})}); + form.addRow({Span(3, Row{m_clearCrashReportsButton, m_crashReportsSizeText, st})}); #endif Column { diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 3c43ee18f2f..3c636c66924 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -48,7 +48,7 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) setConfigWidgetCreator([this] { Layouting::Grid builder; - builder.addRow(m_cppAspect); + builder.addRow({m_cppAspect}); auto info = new QLabel( Tr::tr("setState(DetailsWidget::Expanded); diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index 33417b55a01..8aa30b3c630 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -496,7 +496,7 @@ void SourcePathMapAspect::addToLayout(Layouting::LayoutBuilder &builder) QTC_CHECK(!d->m_widget); d->m_widget = createSubWidget(); d->m_widget->setSourcePathMap(value()); - builder.addRow(d->m_widget.data()); + builder.addRow({d->m_widget.data()}); } QVariant SourcePathMapAspect::volatileValue() const diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index c50e2091cb0..3024eb65f75 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -318,12 +318,12 @@ CommandLine MakeStep::effectiveMakeCommand(MakeCommandType type) const QWidget *MakeStep::createConfigWidget() { Layouting::Form builder; - builder.addRow(m_makeCommandAspect); - builder.addRow(m_userArgumentsAspect); + builder.addRow({m_makeCommandAspect}); + builder.addRow({m_userArgumentsAspect}); builder.addRow({m_userJobCountAspect, m_overrideMakeflagsAspect, m_nonOverrideWarning}); if (m_disablingForSubDirsSupported) - builder.addRow(m_disabledForSubdirsAspect); - builder.addRow(m_buildTargetsAspect); + builder.addRow({m_disabledForSubdirsAspect}); + builder.addRow({m_buildTargetsAspect}); auto widget = builder.emerge(Layouting::WithoutMargins); diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index f8fad01ff70..acea24b0763 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -659,23 +659,23 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) installDirChooser->setExpectedKind(PathChooser::Directory); Layouting::Form builder; - builder.addRow(m_qbsStep->m_buildVariant); - builder.addRow(m_qbsStep->m_selectedAbis); - builder.addRow(m_qbsStep->m_maxJobCount); + builder.addRow({m_qbsStep->m_buildVariant}); + builder.addRow({m_qbsStep->m_selectedAbis}); + builder.addRow({m_qbsStep->m_maxJobCount}); builder.addRow({QbsProjectManager::Tr::tr("Properties:"), propertyEdit}); - builder.addRow(QbsProjectManager::Tr::tr("Flags:")); + builder.addRow({QbsProjectManager::Tr::tr("Flags:")}); m_qbsStep->m_keepGoing->addToLayout(builder); m_qbsStep->m_showCommandLines->addToLayout(builder); m_qbsStep->m_forceProbes->addToLayout(builder); - builder.addRow(QbsProjectManager::Tr::tr("Installation flags:")); + builder.addRow({QbsProjectManager::Tr::tr("Installation flags:")}); m_qbsStep->m_install->addToLayout(builder); m_qbsStep->m_cleanInstallDir->addToLayout(builder); builder.addItem(defaultInstallDirCheckBox); builder.addRow({QbsProjectManager::Tr::tr("Installation directory:"), installDirChooser}); - builder.addRow(m_qbsStep->m_commandLine); + builder.addRow({m_qbsStep->m_commandLine}); builder.attachTo(this, Layouting::WithoutMargins); propertyEdit->setToolTip(QbsProjectManager::Tr::tr("Properties to pass to the project.")); diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index 1aeee5be65b..179928c1795 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -174,7 +174,7 @@ QWidget *QbsInstallStep::createConfigWidget() Layouting::Form builder; builder.addRow({Tr::tr("Install root:"), installRootValueLabel}); - builder.addRow(Tr::tr("Flags:")); + builder.addRow({Tr::tr("Flags:")}); m_dryRun->addToLayout(builder); m_keepGoing->addToLayout(builder); m_cleanInstallRoot->addToLayout(builder); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 344acf25ba0..62c0f78dc99 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -481,9 +481,9 @@ QWidget *QMakeStep::createConfigWidget() abisListWidget = new QListWidget; Layouting::Form builder; - builder.addRow(m_buildType); - builder.addRow(m_userArgs); - builder.addRow(m_effectiveCall); + builder.addRow({m_buildType}); + builder.addRow({m_userArgs}); + builder.addRow({m_effectiveCall}); builder.addRow({abisLabel, abisListWidget}); auto widget = builder.emerge(Layouting::WithoutMargins); From 6738616378467bbc48f9d3a6050729d2bd5cb0f9 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 25 Apr 2023 11:03:16 +0200 Subject: [PATCH 0676/1447] Core: Never auto-remove a running search Change-Id: I03db560fae250ee3c799890179dd8c4618431efb Reviewed-by: Eike Ziller --- .../coreplugin/find/searchresultwindow.cpp | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 075084810d9..bd3fcc97d07 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -8,7 +8,6 @@ #include "../actionmanager/actionmanager.h" #include "../actionmanager/command.h" #include "../coreplugintr.h" -#include "../icontext.h" #include "../icore.h" #include @@ -28,6 +27,9 @@ static const char SETTINGSKEYSECTIONNAME[] = "SearchResults"; static const char SETTINGSKEYEXPANDRESULTS[] = "ExpandResults"; + +// Note that this is a soft limit: If all searches are still running, none of them will be +// removed when a new one is started. static const int MAX_SEARCH_HISTORY = 12; namespace Core { @@ -474,14 +476,15 @@ SearchResult *SearchResultWindow::startNewSearch(const QString &label, // temporarily set the index to the last but one existing d->m_currentIndex = d->m_recentSearchesBox->count() - 2; } - const int toRemoveIndex = d->indexOfSearchToEvict(); - SearchResultWidget * const widgetToRemove - = d->m_searchResultWidgets.takeAt(toRemoveIndex); - widgetToRemove->notifyVisibilityChanged(false); - // widget first, because that might send interesting signals to SearchResult - delete widgetToRemove; - delete d->m_searchResults.takeAt(toRemoveIndex); - d->m_recentSearchesBox->removeItem(toRemoveIndex + 1); + if (const int toRemoveIndex = d->indexOfSearchToEvict(); toRemoveIndex != -1) { + SearchResultWidget * const widgetToRemove + = d->m_searchResultWidgets.takeAt(toRemoveIndex); + widgetToRemove->notifyVisibilityChanged(false); + // widget first, because that might send interesting signals to SearchResult + delete widgetToRemove; + delete d->m_searchResults.takeAt(toRemoveIndex); + d->m_recentSearchesBox->removeItem(toRemoveIndex + 1); + } } d->m_recentSearchesBox->insertItem(1, Tr::tr("%1 %2").arg(label, searchTerm)); } @@ -622,12 +625,11 @@ void SearchResultWindowPrivate::updateFilterButton() int SearchResultWindowPrivate::indexOfSearchToEvict() const { - const int lastIndex = m_searchResultWidgets.size() - 1; - for (int i = lastIndex; i >= 0; --i) { + for (int i = m_searchResultWidgets.size() - 1; i >= 0; --i) { if (!m_searchResultWidgets.at(i)->isSearching()) return i; } - return lastIndex; + return -1; } QList SearchResultWindowPrivate::toolBarWidgets() From 72d72251d84c0393eef8a30dab7839a66009dd1a Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 24 Apr 2023 16:40:01 +0200 Subject: [PATCH 0677/1447] Utils: Start decoupling LayoutBuilder from Aspects Makes it easier reusable elsewhere. Change-Id: I86ff9f40229a33690f854f5fda692bc06d6976ef Reviewed-by: Eike Ziller --- src/libs/utils/aspects.cpp | 9 +- src/libs/utils/aspects.h | 8 +- src/libs/utils/layoutbuilder.cpp | 83 ++++--------------- src/libs/utils/layoutbuilder.h | 119 +++++++++++++++++---------- tests/manual/tasktree/taskwidget.cpp | 10 ++- tests/manual/tasktree/taskwidget.h | 7 +- 6 files changed, 121 insertions(+), 115 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index aed8c851d17..28de4dd4cab 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -421,10 +421,17 @@ QAction *BaseAspect::action() Adds the visual representation of this aspect to a layout using a layout builder. */ -void BaseAspect::addToLayout(Layouting::LayoutBuilder &) +void BaseAspect::addToLayout(LayoutBuilder &) { } +void doLayout(const BaseAspect &aspect, LayoutBuilder &builder) +{ + const_cast(aspect).addToLayout(builder); + if (builder.layoutType() == LayoutBuilder::FormLayout || builder.layoutType() == LayoutBuilder::VBoxLayout) + builder.finishRow(); +} + /*! Updates this aspect's value from user-initiated changes in the widget. diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 0b9a5606596..1e58c737736 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -25,7 +25,11 @@ namespace Utils { class AspectContainer; class BoolAspect; -namespace Layouting { class LayoutBuilder; } + +namespace Layouting { +class LayoutBuilder; +class LayoutItem; +} // Layouting namespace Internal { class AspectContainerPrivate; @@ -206,6 +210,8 @@ private: std::unique_ptr d; }; +QTCREATOR_UTILS_EXPORT void doLayout(const BaseAspect &aspect, Layouting::LayoutBuilder &builder); + class QTCREATOR_UTILS_EXPORT BoolAspect : public BaseAspect { Q_OBJECT diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index f4b1dda3ee6..99b726ec4ce 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -9,12 +9,12 @@ #include #include #include +#include #include #include #include #include #include -#include namespace Utils::Layouting { @@ -51,42 +51,23 @@ LayoutItem::LayoutItem() /*! - Constructs a layout item proxy for \a layout. + \fn template LayoutItem(const T &t) + + Constructs a layout item proxy for \a t. + + T could be + \list + \li \c {QString} + \li \c {QWidget *} + \li \c {QLayout *} + \endlist */ -LayoutItem::LayoutItem(QLayout *layout) - : layout(layout) -{} + /*! - Constructs a layout item proxy for \a widget. + Constructs a layout item representing something that knows how to add it + to a layout by itself. */ -LayoutItem::LayoutItem(QWidget *widget) - : widget(widget) -{} - -/*! - Constructs a layout item representing a \c BaseAspect. - - This ultimately uses the \a aspect's \c addToLayout(LayoutBuilder &) function, - which in turn can add one or more layout items to the target layout. - - \sa BaseAspect::addToLayout() - */ -LayoutItem::LayoutItem(BaseAspect &aspect) - : aspect(&aspect) -{} - -LayoutItem::LayoutItem(BaseAspect *aspect) - : aspect(aspect) -{} - -/*! - Constructs a layout item containing some static \a text. - */ -LayoutItem::LayoutItem(const QString &text) - : text(text) -{} - QLayout *LayoutBuilder::createLayout() const { QLayout *layout = nullptr; @@ -276,7 +257,7 @@ static void doLayoutHelper(QLayout *layout, /*! Constructs a layout item from the contents of another LayoutBuilder */ -LayoutItem::LayoutItem(const LayoutBuilder &builder) +void LayoutItem::setBuilder(const LayoutBuilder &builder) { layout = builder.createLayout(); doLayoutHelper(layout, builder.m_items, Layouting::WithoutMargins); @@ -357,10 +338,8 @@ LayoutBuilder &LayoutBuilder::addRow(const LayoutItems &items) */ LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item) { - if (item.aspect) { - item.aspect->addToLayout(*this); - if (m_layoutType == FormLayout || m_layoutType == VBoxLayout) - finishRow(); + if (item.onAdd) { + item.onAdd(*this); } else { m_items.push_back(item); } @@ -427,29 +406,6 @@ LayoutExtender::~LayoutExtender() // Special items -Break::Break() -{ - specialType = SpecialType::Break; -} - -Stretch::Stretch(int stretch) -{ - specialType = SpecialType::Stretch; - specialValue = stretch; -} - -Space::Space(int space) -{ - specialType = SpecialType::Space; - specialValue = space; -} - -Span::Span(int span_, const LayoutItem &item) -{ - LayoutItem::operator=(item); - span = span_; -} - Tab::Tab(const QString &tabName, const LayoutBuilder &item) { text = tabName; @@ -457,11 +413,6 @@ Tab::Tab(const QString &tabName, const LayoutBuilder &item) item.attachTo(widget); } -HorizontalRule::HorizontalRule() -{ - specialType = SpecialType::HorizontalRule; -} - // "Widgets" static void applyItems(QWidget *widget, const QList &items) diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index b32668e22d3..76106ffc76d 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -18,10 +18,7 @@ class QTabWidget; class QWidget; QT_END_NAMESPACE -namespace Utils { -class BaseAspect; -class BoolAspect; -} // Utils +namespace Utils { class BoolAspect; } namespace Utils::Layouting { @@ -32,6 +29,43 @@ enum AttachType { }; class LayoutBuilder; +class LayoutItem; + +// Special items + +class QTCREATOR_UTILS_EXPORT Space +{ +public: + explicit Space(int space) : space(space) {} + const int space; +}; + +class QTCREATOR_UTILS_EXPORT Stretch +{ +public: + explicit Stretch(int stretch = 1) : stretch(stretch) {} + const int stretch; +}; + +class QTCREATOR_UTILS_EXPORT Break +{ +public: + Break() {} +}; + +class QTCREATOR_UTILS_EXPORT Span +{ +public: + Span(int span, const LayoutItem &item) : span(span), item(item) {} + const int span; + const LayoutItem &item; +}; + +class QTCREATOR_UTILS_EXPORT HorizontalRule +{ +public: + HorizontalRule() {} +}; // LayoutItem @@ -52,18 +86,49 @@ public: }; using Setter = std::function; + using OnAdder = std::function; + LayoutItem(); - LayoutItem(QLayout *layout); - LayoutItem(QWidget *widget); - LayoutItem(BaseAspect *aspect); // Remove - LayoutItem(BaseAspect &aspect); - LayoutItem(const QString &text); - LayoutItem(const LayoutBuilder &builder); - LayoutItem(const Setter &setter) { this->setter = setter; } + + template LayoutItem(const T &t) + { + if constexpr (std::is_same_v) { + text = t; + } else if constexpr (std::is_same_v) { + specialType = LayoutItem::SpecialType::Space; + specialValue = t.space; + } else if constexpr (std::is_same_v) { + specialType = LayoutItem::SpecialType::Stretch; + specialValue = t.stretch; + } else if constexpr (std::is_same_v) { + specialType = LayoutItem::SpecialType::Break; + } else if constexpr (std::is_same_v) { + LayoutItem::operator=(t.item); + span = t.span; + } else if constexpr (std::is_same_v) { + specialType = SpecialType::HorizontalRule; + } else if constexpr (std::is_base_of_v) { + setBuilder(t); + } else if constexpr (std::is_base_of_v) { + LayoutItem::operator=(t); + } else if constexpr (std::is_base_of_v) { + setter = t; + } else if constexpr (std::is_base_of_v>) { + layout = t; + } else if constexpr (std::is_base_of_v>) { + widget = t; + } else if constexpr (std::is_pointer_v) { + onAdd = [t](LayoutBuilder &builder) { doLayout(*t, builder); }; + } else { + onAdd = [&t](LayoutBuilder &builder) { doLayout(t, builder); }; + } + } + + void setBuilder(const LayoutBuilder &builder); QLayout *layout = nullptr; QWidget *widget = nullptr; - BaseAspect *aspect = nullptr; + OnAdder onAdd; QString text; // FIXME: Use specialValue for that int span = 1; @@ -73,42 +138,12 @@ public: QVariant specialValue; }; -class QTCREATOR_UTILS_EXPORT Space : public LayoutItem -{ -public: - explicit Space(int space); -}; - -class QTCREATOR_UTILS_EXPORT Span : public LayoutItem -{ -public: - Span(int span, const LayoutItem &item); -}; - -class QTCREATOR_UTILS_EXPORT Stretch : public LayoutItem -{ -public: - explicit Stretch(int stretch = 1); -}; - class QTCREATOR_UTILS_EXPORT Tab : public LayoutItem { public: Tab(const QString &tabName, const LayoutBuilder &item); }; -class QTCREATOR_UTILS_EXPORT Break : public LayoutItem -{ -public: - Break(); -}; - -class QTCREATOR_UTILS_EXPORT HorizontalRule : public LayoutItem -{ -public: - HorizontalRule(); -}; - class QTCREATOR_UTILS_EXPORT Group : public LayoutItem { public: diff --git a/tests/manual/tasktree/taskwidget.cpp b/tests/manual/tasktree/taskwidget.cpp index cca5394bbba..d5420defe59 100644 --- a/tests/manual/tasktree/taskwidget.cpp +++ b/tests/manual/tasktree/taskwidget.cpp @@ -184,7 +184,11 @@ Tasking::WorkflowPolicy GroupWidget::workflowPolicy() const return m_workflowPolicy; } -TaskGroup::TaskGroup(QWidget *group, std::initializer_list items) - : Row({ group, Group { Column { items } } }) -{} + +void doLayout(const TaskGroup &taskGroup, LayoutBuilder &builder) +{ + builder.addItem(taskGroup.group); + builder.addItem(Group { taskGroup.items }); + builder.finishRow(); +} diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasktree/taskwidget.h index 1f867dfeaec..8dbaded738a 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasktree/taskwidget.h @@ -76,8 +76,11 @@ private: Utils::Tasking::WorkflowPolicy m_workflowPolicy = Utils::Tasking::WorkflowPolicy::StopOnError; }; -class TaskGroup : public Utils::Layouting::Row +class TaskGroup { public: - TaskGroup(QWidget *group, std::initializer_list items); + QWidget *group; + Utils::Layouting::Column items; }; + +void doLayout(const TaskGroup &taskGroup, Utils::Layouting::LayoutBuilder &builder); From b19b4482c133ad6a376da62bad257211267a9a63 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 18 Apr 2023 00:25:35 +0200 Subject: [PATCH 0678/1447] HelpIndexFilter: Reimplement matchers() Change-Id: I47bf8eee25b91ac5ae7d8fd2c06a34370d5d433f Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/help/helpindexfilter.cpp | 70 +++++++++++++++++++++++++++- src/plugins/help/helpindexfilter.h | 1 + src/plugins/help/helpplugin.cpp | 14 ++++-- src/plugins/help/helpplugin.h | 3 ++ 4 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index fc6e5b8e24f..2d005079973 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -21,6 +21,7 @@ using namespace Core; using namespace Help; using namespace Help::Internal; +using namespace Utils; HelpIndexFilter::HelpIndexFilter() { @@ -42,6 +43,73 @@ HelpIndexFilter::HelpIndexFilter() this, &HelpIndexFilter::invalidateCache); } +static void matches(QPromise &promise, const LocatorStorage &storage, + const QStringList &cache, const QIcon &icon) +{ + const QString input = storage.input(); + const Qt::CaseSensitivity cs = ILocatorFilter::caseSensitivity(input); + QStringList bestKeywords; + QStringList worseKeywords; + bestKeywords.reserve(cache.size()); + worseKeywords.reserve(cache.size()); + for (const QString &keyword : cache) { + if (promise.isCanceled()) + return; + if (keyword.startsWith(input, cs)) + bestKeywords.append(keyword); + else if (keyword.contains(input, cs)) + worseKeywords.append(keyword); + } + const QStringList lastIndicesCache = bestKeywords + worseKeywords; + + LocatorFilterEntries entries; + for (const QString &key : lastIndicesCache) { + if (promise.isCanceled()) + return; + const int index = key.indexOf(input, 0, cs); + LocatorFilterEntry filterEntry; + filterEntry.displayName = key; + filterEntry.acceptor = [key] { + HelpPlugin::showLinksInCurrentViewer(LocalHelpManager::linksForKeyword(key), key); + return AcceptResult(); + }; + filterEntry.displayIcon = icon; + filterEntry.highlightInfo = {index, int(input.length())}; + entries.append(filterEntry); + } + storage.reportOutput(entries); + promise.addResult(lastIndicesCache); +} + +LocatorMatcherTasks HelpIndexFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [this, storage](AsyncTask &async) { + if (m_needsUpdate) { + m_needsUpdate = false; + LocalHelpManager::setupGuiHelpEngine(); + m_allIndicesCache = LocalHelpManager::filterEngine()->indices({}); + m_lastIndicesCache.clear(); + m_lastEntry.clear(); + } + const QStringList cache = m_lastEntry.isEmpty() || !storage->input().contains(m_lastEntry) + ? m_allIndicesCache : m_lastIndicesCache; + async.setFutureSynchronizer(HelpPlugin::futureSynchronizer()); + async.setConcurrentCallData(matches, *storage, cache, m_icon); + }; + const auto onDone = [this, storage](const AsyncTask &async) { + if (async.isResultAvailable()) { + m_lastIndicesCache = async.result(); + m_lastEntry = storage->input(); + } + }; + + return {{Async(onSetup, onDone), storage}}; +} + void HelpIndexFilter::prepareSearch(const QString &entry) { Q_UNUSED(entry) diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h index 653d6ff9b7c..489f7078c18 100644 --- a/src/plugins/help/helpindexfilter.h +++ b/src/plugins/help/helpindexfilter.h @@ -19,6 +19,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final; void invalidateCache(); QStringList m_allIndicesCache; diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index c3a743043c9..045035d093f 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -97,7 +98,7 @@ class HelpPluginPrivate : public QObject public: HelpPluginPrivate(); - void modeChanged(Utils::Id mode, Utils::Id old); + void modeChanged(Id mode, Id old); void requestContextHelp(); void showContextHelp(const HelpItem &contextHelp); @@ -142,6 +143,7 @@ public: LocalHelpManager m_localHelpManager; HelpIndexFilter helpIndexFilter; + FutureSynchronizer m_futureSynchronizer; }; static HelpPluginPrivate *dd = nullptr; @@ -395,6 +397,12 @@ HelpWidget *HelpPlugin::modeHelpWidget() return dd->m_centralWidget; } +FutureSynchronizer *HelpPlugin::futureSynchronizer() +{ + QTC_ASSERT(dd, return nullptr); + return &dd->m_futureSynchronizer; +} + void HelpPluginPrivate::showLinksInCurrentViewer(const QMultiMap &links, const QString &key) { if (links.size() < 1) @@ -403,7 +411,7 @@ void HelpPluginPrivate::showLinksInCurrentViewer(const QMultiMap widget->showLinks(links, key); } -void HelpPluginPrivate::modeChanged(Utils::Id mode, Utils::Id old) +void HelpPluginPrivate::modeChanged(Id mode, Id old) { Q_UNUSED(old) if (mode == m_mode.id()) { @@ -503,7 +511,7 @@ HelpViewer *HelpPluginPrivate::viewerForContextHelp() void HelpPluginPrivate::requestContextHelp() { // Find out what to show - const QVariant tipHelpValue = Utils::ToolTip::contextHelp(); + const QVariant tipHelpValue = ToolTip::contextHelp(); const HelpItem tipHelp = tipHelpValue.canConvert() ? tipHelpValue.value() : HelpItem(tipHelpValue.toString()); diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h index 96d14a152b8..bd483ae3da8 100644 --- a/src/plugins/help/helpplugin.h +++ b/src/plugins/help/helpplugin.h @@ -10,6 +10,8 @@ QT_BEGIN_NAMESPACE class QUrl; QT_END_NAMESPACE +namespace Utils { class FutureSynchronizer; } + namespace Help { namespace Internal { @@ -30,6 +32,7 @@ public: const QString &key); static HelpViewer *createHelpViewer(); static HelpWidget *modeHelpWidget(); + static Utils::FutureSynchronizer *futureSynchronizer(); private: void initialize() final; From a3f025063f7f11dbdd02db08afb05fa7eb176751 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:00:48 +0200 Subject: [PATCH 0679/1447] Help: Use IOptionPage::setWidgetCreator() for general settings Change-Id: I71a500cc349fed92c38368989fc258902c942e29 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/help/generalsettingspage.cpp | 288 ++++++++++++----------- src/plugins/help/generalsettingspage.h | 43 +--- 2 files changed, 150 insertions(+), 181 deletions(-) diff --git a/src/plugins/help/generalsettingspage.cpp b/src/plugins/help/generalsettingspage.cpp index a05a0db3eed..d5f5756ed69 100644 --- a/src/plugins/help/generalsettingspage.cpp +++ b/src/plugins/help/generalsettingspage.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -35,19 +36,42 @@ #include #include -#include - using namespace Core; using namespace Utils; -namespace Help { -namespace Internal { +namespace Help::Internal { -class GeneralSettingsPageWidget : public QWidget +class GeneralSettingsPageWidget : public IOptionsPageWidget { public: GeneralSettingsPageWidget(); +private: + void apply() final; + + void setCurrentPage(); + void setBlankPage(); + void setDefaultPage(); + void importBookmarks(); + void exportBookmarks(); + + void updateFontSizeSelector(); + void updateFontStyleSelector(); + void updateFontFamilySelector(); + void updateFont(); + int closestPointSizeIndex(int desiredPointSize) const; + + QFont m_font; + int m_fontZoom = 100; + QFontDatabase m_fontDatabase; + + QString m_homePage; + int m_contextOption; + + int m_startOption; + bool m_returnOnClose; + bool m_scrollWheelZoomingEnabled; + QSpinBox *zoomSpinBox; QFontComboBox *familyComboBox; QComboBox *styleComboBox; @@ -62,7 +86,7 @@ public: QPushButton *importButton; QPushButton *exportButton; QCheckBox *scrollWheelZooming; - QCheckBox *m_returnOnClose; + QCheckBox *m_returnOnCloseCheckBox; QComboBox *viewerBackend; }; @@ -152,8 +176,8 @@ GeneralSettingsPageWidget::GeneralSettingsPageWidget() auto behaviourGroupBox = new QGroupBox(Tr::tr("Behaviour")); scrollWheelZooming = new QCheckBox(Tr::tr("Enable scroll wheel zooming")); - m_returnOnClose = new QCheckBox(Tr::tr("Return to editor on closing the last page")); - m_returnOnClose->setToolTip( + m_returnOnCloseCheckBox = new QCheckBox(Tr::tr("Return to editor on closing the last page")); + m_returnOnCloseCheckBox->setToolTip( Tr::tr("Switches to editor context after last help page is closed.")); auto viewerBackendLabel = new QLabel(Tr::tr("Viewer backend:")); @@ -172,7 +196,7 @@ GeneralSettingsPageWidget::GeneralSettingsPageWidget() auto behaviourGroupBoxLayout = new QVBoxLayout; behaviourGroupBox->setLayout(behaviourGroupBoxLayout); behaviourGroupBoxLayout->addWidget(scrollWheelZooming); - behaviourGroupBoxLayout->addWidget(m_returnOnClose); + behaviourGroupBoxLayout->addWidget(m_returnOnCloseCheckBox); behaviourGroupBoxLayout->addLayout(viewerBackendLayout); // bookmarks @@ -203,167 +227,145 @@ GeneralSettingsPageWidget::GeneralSettingsPageWidget() mainLayout->addWidget(behaviourGroupBox); mainLayout->addLayout(bookmarksLayout); mainLayout->addStretch(1); -} -GeneralSettingsPage::GeneralSettingsPage() -{ - setId("A.General settings"); - setDisplayName(Tr::tr("General")); - setCategory(Help::Constants::HELP_CATEGORY); - setDisplayCategory(Tr::tr("Help")); - setCategoryIconPath(":/help/images/settingscategory_help.png"); -} + m_font = LocalHelpManager::fallbackFont(); + m_fontZoom = LocalHelpManager::fontZoom(); + zoomSpinBox->setValue(m_fontZoom); -QWidget *GeneralSettingsPage::widget() -{ - if (!m_widget) { - m_widget = new GeneralSettingsPageWidget; + updateFontSizeSelector(); + updateFontStyleSelector(); + updateFontFamilySelector(); - m_font = LocalHelpManager::fallbackFont(); - m_fontZoom = LocalHelpManager::fontZoom(); - m_widget->zoomSpinBox->setValue(m_fontZoom); - - updateFontSizeSelector(); + connect(familyComboBox, &QFontComboBox::currentFontChanged, this, [this] { + updateFont(); updateFontStyleSelector(); - updateFontFamilySelector(); + updateFontSizeSelector(); + updateFont(); // changes that might have happened when updating the selectors + }); - connect(m_widget->familyComboBox, &QFontComboBox::currentFontChanged, this, [this] { - updateFont(); - updateFontStyleSelector(); - updateFontSizeSelector(); - updateFont(); // changes that might have happened when updating the selectors - }); + connect(styleComboBox, &QComboBox::currentIndexChanged, this, [this] { + updateFont(); + updateFontSizeSelector(); + updateFont(); // changes that might have happened when updating the selectors + }); - connect(m_widget->styleComboBox, &QComboBox::currentIndexChanged, this, [this] { - updateFont(); - updateFontSizeSelector(); - updateFont(); // changes that might have happened when updating the selectors - }); + connect(sizeComboBox, &QComboBox::currentIndexChanged, + this, &GeneralSettingsPageWidget::updateFont); - connect(m_widget->sizeComboBox, &QComboBox::currentIndexChanged, - this, &GeneralSettingsPage::updateFont); + connect(zoomSpinBox, &QSpinBox::valueChanged, + this, [this](int value) { m_fontZoom = value; }); - connect(m_widget->zoomSpinBox, &QSpinBox::valueChanged, - this, [this](int value) { m_fontZoom = value; }); + m_homePage = LocalHelpManager::homePage(); + homePageLineEdit->setText(m_homePage); - m_homePage = LocalHelpManager::homePage(); - m_widget->homePageLineEdit->setText(m_homePage); + m_startOption = LocalHelpManager::startOption(); + helpStartComboBox->setCurrentIndex(m_startOption); - m_startOption = LocalHelpManager::startOption(); - m_widget->helpStartComboBox->setCurrentIndex(m_startOption); + m_contextOption = LocalHelpManager::contextHelpOption(); + contextHelpComboBox->setCurrentIndex(m_contextOption); - m_contextOption = LocalHelpManager::contextHelpOption(); - m_widget->contextHelpComboBox->setCurrentIndex(m_contextOption); + connect(currentPageButton, &QPushButton::clicked, + this, &GeneralSettingsPageWidget::setCurrentPage); + connect(blankPageButton, &QPushButton::clicked, + this, &GeneralSettingsPageWidget::setBlankPage); + connect(defaultPageButton, &QPushButton::clicked, + this, &GeneralSettingsPageWidget::setDefaultPage); - connect(m_widget->currentPageButton, &QPushButton::clicked, - this, &GeneralSettingsPage::setCurrentPage); - connect(m_widget->blankPageButton, &QPushButton::clicked, - this, &GeneralSettingsPage::setBlankPage); - connect(m_widget->defaultPageButton, - &QPushButton::clicked, - this, - &GeneralSettingsPage::setDefaultPage); + HelpViewer *viewer = HelpPlugin::modeHelpWidget()->currentViewer(); + if (!viewer) + currentPageButton->setEnabled(false); - HelpViewer *viewer = HelpPlugin::modeHelpWidget()->currentViewer(); - if (!viewer) - m_widget->currentPageButton->setEnabled(false); + errorLabel->setVisible(false); + connect(importButton, &QPushButton::clicked, + this, &GeneralSettingsPageWidget::importBookmarks); + connect(exportButton, &QPushButton::clicked, + this, &GeneralSettingsPageWidget::exportBookmarks); - m_widget->errorLabel->setVisible(false); - connect(m_widget->importButton, &QPushButton::clicked, - this, &GeneralSettingsPage::importBookmarks); - connect(m_widget->exportButton, &QPushButton::clicked, - this, &GeneralSettingsPage::exportBookmarks); + m_returnOnClose = LocalHelpManager::returnOnClose(); + m_returnOnCloseCheckBox->setChecked(m_returnOnClose); - m_returnOnClose = LocalHelpManager::returnOnClose(); - m_widget->m_returnOnClose->setChecked(m_returnOnClose); + m_scrollWheelZoomingEnabled = LocalHelpManager::isScrollWheelZoomingEnabled(); + scrollWheelZooming->setChecked(m_scrollWheelZoomingEnabled); - m_scrollWheelZoomingEnabled = LocalHelpManager::isScrollWheelZoomingEnabled(); - m_widget->scrollWheelZooming->setChecked(m_scrollWheelZoomingEnabled); - - m_widget->viewerBackend->addItem( - Tr::tr("Default (%1)", "Default viewer backend") - .arg(LocalHelpManager::defaultViewerBackend().displayName)); - const QByteArray currentBackend = LocalHelpManager::viewerBackendId(); - const QVector backends = LocalHelpManager::viewerBackends(); - for (const HelpViewerFactory &f : backends) { - m_widget->viewerBackend->addItem(f.displayName, f.id); - if (f.id == currentBackend) - m_widget->viewerBackend->setCurrentIndex(m_widget->viewerBackend->count() - 1); - } - if (backends.size() == 1) - m_widget->viewerBackend->setEnabled(false); + viewerBackend->addItem( + Tr::tr("Default (%1)", "Default viewer backend") + .arg(LocalHelpManager::defaultViewerBackend().displayName)); + const QByteArray currentBackend = LocalHelpManager::viewerBackendId(); + const QVector backends = LocalHelpManager::viewerBackends(); + for (const HelpViewerFactory &f : backends) { + viewerBackend->addItem(f.displayName, f.id); + if (f.id == currentBackend) + viewerBackend->setCurrentIndex(viewerBackend->count() - 1); } - return m_widget; + if (backends.size() == 1) + viewerBackend->setEnabled(false); } -void GeneralSettingsPage::apply() +void GeneralSettingsPageWidget::apply() { - if (!m_widget) // page was never shown - return; - if (m_font != LocalHelpManager::fallbackFont()) LocalHelpManager::setFallbackFont(m_font); if (m_fontZoom != LocalHelpManager::fontZoom()) LocalHelpManager::setFontZoom(m_fontZoom); - QString homePage = QUrl::fromUserInput(m_widget->homePageLineEdit->text()).toString(); + QString homePage = QUrl::fromUserInput(homePageLineEdit->text()).toString(); if (homePage.isEmpty()) homePage = Help::Constants::AboutBlank; - m_widget->homePageLineEdit->setText(homePage); + homePageLineEdit->setText(homePage); if (m_homePage != homePage) { m_homePage = homePage; LocalHelpManager::setHomePage(homePage); } - const int startOption = m_widget->helpStartComboBox->currentIndex(); + const int startOption = helpStartComboBox->currentIndex(); if (m_startOption != startOption) { m_startOption = startOption; LocalHelpManager::setStartOption(LocalHelpManager::StartOption(m_startOption)); } - const int helpOption = m_widget->contextHelpComboBox->currentIndex(); + const int helpOption = contextHelpComboBox->currentIndex(); if (m_contextOption != helpOption) { m_contextOption = helpOption; LocalHelpManager::setContextHelpOption(HelpManager::HelpViewerLocation(m_contextOption)); } - const bool close = m_widget->m_returnOnClose->isChecked(); + const bool close = m_returnOnCloseCheckBox->isChecked(); if (m_returnOnClose != close) { m_returnOnClose = close; LocalHelpManager::setReturnOnClose(m_returnOnClose); } - const bool zoom = m_widget->scrollWheelZooming->isChecked(); + const bool zoom = scrollWheelZooming->isChecked(); if (m_scrollWheelZoomingEnabled != zoom) { m_scrollWheelZoomingEnabled = zoom; LocalHelpManager::setScrollWheelZoomingEnabled(m_scrollWheelZoomingEnabled); } - const QByteArray viewerBackendId = m_widget->viewerBackend->currentData().toByteArray(); + const QByteArray viewerBackendId = viewerBackend->currentData().toByteArray(); LocalHelpManager::setViewerBackendId(viewerBackendId); } -void GeneralSettingsPage::setCurrentPage() +void GeneralSettingsPageWidget::setCurrentPage() { HelpViewer *viewer = HelpPlugin::modeHelpWidget()->currentViewer(); if (viewer) - m_widget->homePageLineEdit->setText(viewer->source().toString()); + homePageLineEdit->setText(viewer->source().toString()); } -void GeneralSettingsPage::setBlankPage() +void GeneralSettingsPageWidget::setBlankPage() { - m_widget->homePageLineEdit->setText(Help::Constants::AboutBlank); + homePageLineEdit->setText(Help::Constants::AboutBlank); } -void GeneralSettingsPage::setDefaultPage() +void GeneralSettingsPageWidget::setDefaultPage() { - m_widget->homePageLineEdit->setText(LocalHelpManager::defaultHomePage()); + homePageLineEdit->setText(LocalHelpManager::defaultHomePage()); } -void GeneralSettingsPage::importBookmarks() +void GeneralSettingsPageWidget::importBookmarks() { - m_widget->errorLabel->setVisible(false); + errorLabel->setVisible(false); FilePath filePath = FileUtils::getOpenFilePath(nullptr, Tr::tr("Import Bookmarks"), @@ -381,13 +383,13 @@ void GeneralSettingsPage::importBookmarks() return; } - m_widget->errorLabel->setVisible(true); - m_widget->errorLabel->setText(Tr::tr("Cannot import bookmarks.")); + errorLabel->setVisible(true); + errorLabel->setText(Tr::tr("Cannot import bookmarks.")); } -void GeneralSettingsPage::exportBookmarks() +void GeneralSettingsPageWidget::exportBookmarks() { - m_widget->errorLabel->setVisible(false); + errorLabel->setVisible(false); FilePath filePath = FileUtils::getSaveFilePath(nullptr, Tr::tr("Save File"), @@ -405,12 +407,12 @@ void GeneralSettingsPage::exportBookmarks() saver.setResult(&writer); } if (!saver.finalize()) { - m_widget->errorLabel->setVisible(true); - m_widget->errorLabel->setText(saver.errorString()); + errorLabel->setVisible(true); + errorLabel->setText(saver.errorString()); } } -void GeneralSettingsPage::updateFontSizeSelector() +void GeneralSettingsPageWidget::updateFontSizeSelector() { const QString &family = m_font.family(); const QString &fontStyle = m_fontDatabase.styleString(m_font); @@ -419,81 +421,81 @@ void GeneralSettingsPage::updateFontSizeSelector() if (pointSizes.empty()) pointSizes = QFontDatabase::standardSizes(); - QSignalBlocker blocker(m_widget->sizeComboBox); - m_widget->sizeComboBox->clear(); - m_widget->sizeComboBox->setCurrentIndex(-1); - m_widget->sizeComboBox->setEnabled(!pointSizes.empty()); + QSignalBlocker blocker(sizeComboBox); + sizeComboBox->clear(); + sizeComboBox->setCurrentIndex(-1); + sizeComboBox->setEnabled(!pointSizes.empty()); // try to maintain selection or select closest. if (!pointSizes.empty()) { QString n; for (int pointSize : std::as_const(pointSizes)) - m_widget->sizeComboBox->addItem(n.setNum(pointSize), QVariant(pointSize)); + sizeComboBox->addItem(n.setNum(pointSize), QVariant(pointSize)); const int closestIndex = closestPointSizeIndex(m_font.pointSize()); if (closestIndex != -1) - m_widget->sizeComboBox->setCurrentIndex(closestIndex); + sizeComboBox->setCurrentIndex(closestIndex); } } -void GeneralSettingsPage::updateFontStyleSelector() +void GeneralSettingsPageWidget::updateFontStyleSelector() { const QString &fontStyle = m_fontDatabase.styleString(m_font); const QStringList &styles = m_fontDatabase.styles(m_font.family()); - QSignalBlocker blocker(m_widget->styleComboBox); - m_widget->styleComboBox->clear(); - m_widget->styleComboBox->setCurrentIndex(-1); - m_widget->styleComboBox->setEnabled(!styles.empty()); + QSignalBlocker blocker(styleComboBox); + styleComboBox->clear(); + styleComboBox->setCurrentIndex(-1); + styleComboBox->setEnabled(!styles.empty()); if (!styles.empty()) { int normalIndex = -1; const QString normalStyle = "Normal"; for (const QString &style : styles) { // try to maintain selection or select 'normal' preferably - const int newIndex = m_widget->styleComboBox->count(); - m_widget->styleComboBox->addItem(style); + const int newIndex = styleComboBox->count(); + styleComboBox->addItem(style); if (fontStyle == style) { - m_widget->styleComboBox->setCurrentIndex(newIndex); + styleComboBox->setCurrentIndex(newIndex); } else { if (fontStyle == normalStyle) normalIndex = newIndex; } } - if (m_widget->styleComboBox->currentIndex() == -1 && normalIndex != -1) - m_widget->styleComboBox->setCurrentIndex(normalIndex); + if (styleComboBox->currentIndex() == -1 && normalIndex != -1) + styleComboBox->setCurrentIndex(normalIndex); } } -void GeneralSettingsPage::updateFontFamilySelector() +void GeneralSettingsPageWidget::updateFontFamilySelector() { - m_widget->familyComboBox->setCurrentFont(m_font); + familyComboBox->setCurrentFont(m_font); } -void GeneralSettingsPage::updateFont() +void GeneralSettingsPageWidget::updateFont() { - const QString &family = m_widget->familyComboBox->currentFont().family(); + const QString &family = familyComboBox->currentFont().family(); m_font.setFamily(family); int fontSize = 14; - int currentIndex = m_widget->sizeComboBox->currentIndex(); + int currentIndex = sizeComboBox->currentIndex(); if (currentIndex != -1) - fontSize = m_widget->sizeComboBox->itemData(currentIndex).toInt(); + fontSize = sizeComboBox->itemData(currentIndex).toInt(); m_font.setPointSize(fontSize); - currentIndex = m_widget->styleComboBox->currentIndex(); + currentIndex = styleComboBox->currentIndex(); if (currentIndex != -1) - m_font.setStyleName(m_widget->styleComboBox->itemText(currentIndex)); + m_font.setStyleName(styleComboBox->itemText(currentIndex)); } -int GeneralSettingsPage::closestPointSizeIndex(int desiredPointSize) const +int GeneralSettingsPageWidget::closestPointSizeIndex(int desiredPointSize) const { // try to maintain selection or select closest. int closestIndex = -1; int closestAbsError = 0xFFFF; - const int pointSizeCount = m_widget->sizeComboBox->count(); + const int pointSizeCount = sizeComboBox->count(); for (int i = 0; i < pointSizeCount; i++) { - const int itemPointSize = m_widget->sizeComboBox->itemData(i).toInt(); + const int itemPointSize = sizeComboBox->itemData(i).toInt(); const int absError = qAbs(desiredPointSize - itemPointSize); if (absError < closestAbsError) { closestIndex = i; @@ -508,10 +510,16 @@ int GeneralSettingsPage::closestPointSizeIndex(int desiredPointSize) const return closestIndex; } -void GeneralSettingsPage::finish() +// GeneralSettingPage + +GeneralSettingsPage::GeneralSettingsPage() { - delete m_widget; + setId("A.General settings"); + setDisplayName(Tr::tr("General")); + setCategory(Help::Constants::HELP_CATEGORY); + setDisplayCategory(Tr::tr("Help")); + setCategoryIconPath(":/help/images/settingscategory_help.png"); + setWidgetCreator([] { return new GeneralSettingsPageWidget; }); } -} // Internal -} // Help +} // Help::Interal diff --git a/src/plugins/help/generalsettingspage.h b/src/plugins/help/generalsettingspage.h index 4965cac9ea3..ff5f6313ac8 100644 --- a/src/plugins/help/generalsettingspage.h +++ b/src/plugins/help/generalsettingspage.h @@ -5,51 +5,12 @@ #include -#include -#include - -namespace Help { -namespace Internal { - -class GeneralSettingsPageWidget; +namespace Help::Internal { class GeneralSettingsPage : public Core::IOptionsPage { - Q_OBJECT - public: GeneralSettingsPage(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - void setCurrentPage(); - void setBlankPage(); - void setDefaultPage(); - void importBookmarks(); - void exportBookmarks(); - - void updateFontSizeSelector(); - void updateFontStyleSelector(); - void updateFontFamilySelector(); - void updateFont(); - int closestPointSizeIndex(int desiredPointSize) const; - - QFont m_font; - int m_fontZoom = 100; - QFontDatabase m_fontDatabase; - - QString m_homePage; - int m_contextOption; - - int m_startOption; - bool m_returnOnClose; - bool m_scrollWheelZoomingEnabled; - - QPointer m_widget; }; - } // Internal -} // Help +} // Help::Internal From 0a39d20651b0ecd3cf6fe4b320f1712df2e1ae36 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 21:18:06 +0200 Subject: [PATCH 0680/1447] BookmarkFilter: Reimplement matchers() Change-Id: I703cea015bf696acfb3aa7cafc38c9ee22b683ce Reviewed-by: Eike Ziller --- src/plugins/bookmarks/bookmarkfilter.cpp | 98 ++++++++++++++---------- src/plugins/bookmarks/bookmarkfilter.h | 3 + 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index f5af4c9b5fb..220d5d308b0 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -25,83 +25,99 @@ BookmarkFilter::BookmarkFilter(BookmarkManager *manager) setDefaultShortcutString("b"); } -void BookmarkFilter::prepareSearch(const QString &entry) +LocatorMatcherTasks BookmarkFilter::matchers() { - m_results = {}; - if (m_manager->rowCount() == 0) - return; + using namespace Tasking; - auto match = [this](const QString &name, BookmarkManager::Roles role) { + TreeStorage storage; + + const auto onSetup = [=] { + storage->reportOutput(match(storage->input())); + return true; + }; + return {{Sync(onSetup), storage}}; +} + +LocatorFilterEntries BookmarkFilter::match(const QString &input) const +{ + if (m_manager->rowCount() == 0) + return {}; + const auto match = [this](const QString &name, BookmarkManager::Roles role) { return m_manager->match(m_manager->index(0, 0), role, name, -1, Qt::MatchContains | Qt::MatchWrap); }; - int colonIndex = entry.lastIndexOf(':'); + const int colonIndex = input.lastIndexOf(':'); QModelIndexList fileNameLineNumberMatches; if (colonIndex >= 0) { // Filter by "fileName:lineNumber" pattern - const QString fileName = entry.left(colonIndex); - const QString lineNumber = entry.mid(colonIndex + 1); + const QString fileName = input.left(colonIndex); + const QString lineNumber = input.mid(colonIndex + 1); fileNameLineNumberMatches = match(fileName, BookmarkManager::Filename); - fileNameLineNumberMatches = - Utils::filtered(fileNameLineNumberMatches, [lineNumber](const QModelIndex &index) { - return index.data(BookmarkManager::LineNumber).toString().contains(lineNumber); - }); + fileNameLineNumberMatches = Utils::filtered( + fileNameLineNumberMatches, [lineNumber](const QModelIndex &index) { + return index.data(BookmarkManager::LineNumber).toString().contains(lineNumber); + }); } - const QModelIndexList matches = filteredUnique(fileNameLineNumberMatches - + match(entry, BookmarkManager::Filename) - + match(entry, BookmarkManager::LineNumber) - + match(entry, BookmarkManager::Note) - + match(entry, BookmarkManager::LineText)); - + + match(input, BookmarkManager::Filename) + + match(input, BookmarkManager::LineNumber) + + match(input, BookmarkManager::Note) + + match(input, BookmarkManager::LineText)); + LocatorFilterEntries entries; for (const QModelIndex &idx : matches) { const Bookmark *bookmark = m_manager->bookmarkForIndex(idx); const QString filename = bookmark->filePath().fileName(); - LocatorFilterEntry filterEntry; - filterEntry.displayName = QString("%1:%2").arg(filename).arg(bookmark->lineNumber()); + LocatorFilterEntry entry; + entry.displayName = QString("%1:%2").arg(filename).arg(bookmark->lineNumber()); // TODO: according to QModelIndex docs, we shouldn't store model indexes: // Model indexes should be used immediately and then discarded. - // You should not rely on indexes to remain valid after calling model functions that change - // the structure of the model or delete items. - filterEntry.acceptor = [manager = m_manager, idx] { + // You should not rely on indexes to remain valid after calling model functions + // that change the structure of the model or delete items. + entry.acceptor = [manager = m_manager, idx] { if (Bookmark *bookmark = manager->bookmarkForIndex(idx)) manager->gotoBookmark(bookmark); return AcceptResult(); }; if (!bookmark->note().isEmpty()) - filterEntry.extraInfo = bookmark->note(); + entry.extraInfo = bookmark->note(); else if (!bookmark->lineText().isEmpty()) - filterEntry.extraInfo = bookmark->lineText(); + entry.extraInfo = bookmark->lineText(); else - filterEntry.extraInfo = bookmark->filePath().toString(); - int highlightIndex = filterEntry.displayName.indexOf(entry, 0, Qt::CaseInsensitive); + entry.extraInfo = bookmark->filePath().toString(); + int highlightIndex = entry.displayName.indexOf(input, 0, Qt::CaseInsensitive); if (highlightIndex >= 0) { - filterEntry.highlightInfo = {highlightIndex, int(entry.length())}; + entry.highlightInfo = {highlightIndex, int(input.length())}; } else { - highlightIndex = filterEntry.extraInfo.indexOf(entry, 0, Qt::CaseInsensitive); + highlightIndex = entry.extraInfo.indexOf(input, 0, Qt::CaseInsensitive); if (highlightIndex >= 0) { - filterEntry.highlightInfo = {highlightIndex, int(entry.length()), - LocatorFilterEntry::HighlightInfo::ExtraInfo}; + entry.highlightInfo = {highlightIndex, int(input.length()), + LocatorFilterEntry::HighlightInfo::ExtraInfo}; } else if (colonIndex >= 0) { - const QString fileName = entry.left(colonIndex); - const QString lineNumber = entry.mid(colonIndex + 1); - highlightIndex = filterEntry.displayName.indexOf(fileName, 0, Qt::CaseInsensitive); + const QString fileName = input.left(colonIndex); + const QString lineNumber = input.mid(colonIndex + 1); + highlightIndex = entry.displayName.indexOf(fileName, 0, + Qt::CaseInsensitive); if (highlightIndex >= 0) { - filterEntry.highlightInfo = {highlightIndex, int(fileName.length())}; - highlightIndex = filterEntry.displayName.indexOf( + entry.highlightInfo = {highlightIndex, int(fileName.length())}; + highlightIndex = entry.displayName.indexOf( lineNumber, highlightIndex, Qt::CaseInsensitive); if (highlightIndex >= 0) { - filterEntry.highlightInfo.startsDisplay += highlightIndex; - filterEntry.highlightInfo.lengthsDisplay += lineNumber.length(); + entry.highlightInfo.startsDisplay += highlightIndex; + entry.highlightInfo.lengthsDisplay += lineNumber.length(); } } } } - - filterEntry.displayIcon = bookmark->icon(); - m_results.append(filterEntry); + entry.displayIcon = bookmark->icon(); + entries.append(entry); } + return entries; +} + +void BookmarkFilter::prepareSearch(const QString &entry) +{ + m_results = match(entry); } QList BookmarkFilter::matchesFor(QFutureInterface &future, diff --git a/src/plugins/bookmarks/bookmarkfilter.h b/src/plugins/bookmarks/bookmarkfilter.h index 5745669dc2b..9c3b6d1d9aa 100644 --- a/src/plugins/bookmarks/bookmarkfilter.h +++ b/src/plugins/bookmarks/bookmarkfilter.h @@ -17,6 +17,9 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final; + Core::LocatorFilterEntries match(const QString &input) const; + BookmarkManager *m_manager = nullptr; // not owned QList m_results; }; From 755f57d450ce4ba9772891a93a3017df192abca9 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 24 Apr 2023 13:43:28 +0200 Subject: [PATCH 0681/1447] FileSystemFilter: Share implementation between old and new API, so I can continue with changes on top. Change-Id: Ic7b807c9b57296499f1a622bc4e3bc60fbba6865 Reviewed-by: Jarek Kobus --- .../coreplugin/locator/filesystemfilter.cpp | 142 ++++-------------- 1 file changed, 33 insertions(+), 109 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index a878bab74d1..646ab366c81 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -90,11 +90,13 @@ FileSystemFilter::FileSystemFilter() setDefaultIncludedByDefault(false); } -static void matches(QPromise &promise, const LocatorStorage &storage, - const QString &shortcutString, const FilePath ¤tDocumentDir, - bool includeHidden) +template +static LocatorFilterEntries matchesImpl(Promise &promise, + const QString &input, + const QString &shortcutString, + const FilePath ¤tDocumentDir, + bool includeHidden) { - const QString input = storage.input(); LocatorFilterEntries entries[int(ILocatorFilter::MatchLevel::Count)]; const Environment env = Environment::systemEnvironment(); @@ -129,11 +131,11 @@ static void matches(QPromise &promise, const LocatorStorage &storage, QRegularExpression regExp = ILocatorFilter::createRegExp(entryFileName, caseSensitivity); if (!regExp.isValid()) - return; + return {}; for (const FilePath &dir : dirs) { if (promise.isCanceled()) - return; + return {}; const QString dirString = dir.relativeChildPath(directory).nativePath(); const QRegularExpressionMatch match = regExp.match(dirString); @@ -156,10 +158,10 @@ static void matches(QPromise &promise, const LocatorStorage &storage, const Link link = Link::fromString(entryFileName, true); regExp = ILocatorFilter::createRegExp(link.targetFilePath.toString(), caseSensitivity); if (!regExp.isValid()) - return; + return {}; for (const FilePath &file : files) { if (promise.isCanceled()) - return; + return {}; const QString fileString = file.relativeChildPath(directory).nativePath(); const QRegularExpressionMatch match = regExp.match(fileString); @@ -190,8 +192,19 @@ static void matches(QPromise &promise, const LocatorStorage &storage, filterEntry.extraInfo = directory.absoluteFilePath().shortNativePath(); entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); } - storage.reportOutput(std::accumulate(std::begin(entries), std::end(entries), - LocatorFilterEntries())); + return std::accumulate(std::begin(entries), std::end(entries), LocatorFilterEntries()); +} + +static void matches(QPromise &promise, + const LocatorStorage &storage, + const QString &shortcutString, + const FilePath ¤tDocumentDir, + bool includeHidden) +{ + const LocatorFilterEntries result + = matchesImpl(promise, storage.input(), shortcutString, currentDocumentDir, includeHidden); + if (!result.isEmpty()) + storage.reportOutput(result); } LocatorMatcherTasks FileSystemFilter::matchers() @@ -202,8 +215,11 @@ LocatorMatcherTasks FileSystemFilter::matchers() const auto onSetup = [this, storage](AsyncTask &async) { async.setFutureSynchronizer(CorePlugin::futureSynchronizer()); - async.setConcurrentCallData(matches, *storage, shortcutString(), - DocumentManager::fileDialogInitialDirectory(), m_includeHidden); + async.setConcurrentCallData(matches, + *storage, + shortcutString(), + DocumentManager::fileDialogInitialDirectory(), + m_includeHidden); }; return {{Async(onSetup), storage}}; @@ -219,103 +235,11 @@ void FileSystemFilter::prepareSearch(const QString &entry) QList FileSystemFilter::matchesFor(QFutureInterface &future, const QString &entry) { - QList entries[int(MatchLevel::Count)]; - - Environment env = Environment::systemEnvironment(); - const QString expandedEntry = env.expandVariables(entry); - const auto expandedEntryPath = FilePath::fromUserInput(expandedEntry); - const auto absoluteEntryPath = m_currentDocumentDirectory.isEmpty() - ? expandedEntryPath - : m_currentDocumentDirectory.resolvePath(expandedEntryPath); - - // Consider the entered path a directory if it ends with slash/backslash. - // If it is a dir but doesn't end with a backslash, we want to still show all (other) matching - // items from the same parent directory. - // Unfortunately fromUserInput removes slash/backslash at the end, so manually check the original. - const bool isDir = expandedEntry.isEmpty() || expandedEntry.endsWith('/') - || expandedEntry.endsWith('\\'); - const FilePath directory = isDir ? absoluteEntryPath : absoluteEntryPath.parentDir(); - const QString entryFileName = isDir ? QString() : absoluteEntryPath.fileName(); - - QDir::Filters dirFilter = QDir::Dirs | QDir::Drives | QDir::NoDot | QDir::NoDotDot; - QDir::Filters fileFilter = QDir::Files; - if (m_currentIncludeHidden) { - dirFilter |= QDir::Hidden; - fileFilter |= QDir::Hidden; - } - // use only 'name' for case sensitivity decision, because we need to make the path - // match the case on the file system for case-sensitive file systems - const Qt::CaseSensitivity caseSensitivity_ = caseSensitivity(entryFileName); - const FilePaths dirs = FilePaths({directory / ".."}) - + directory.dirEntries({{}, dirFilter}, - QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); - const FilePaths files = directory.dirEntries({{}, fileFilter}, - QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); - - QRegularExpression regExp = createRegExp(entryFileName, caseSensitivity_); - if (!regExp.isValid()) - return {}; - - for (const FilePath &dir : dirs) { - if (future.isCanceled()) - break; - - const QString dirString = dir.relativeChildPath(directory).nativePath(); - const QRegularExpressionMatch match = regExp.match(dirString); - if (match.hasMatch()) { - const MatchLevel level = matchLevelFor(match, dirString); - LocatorFilterEntry filterEntry; - filterEntry.displayName = dirString; - filterEntry.acceptor = [this, dir] { - const QString value = shortcutString() + ' ' - + dir.absoluteFilePath().cleanPath().pathAppended("/").toUserOutput(); - return AcceptResult{value, int(value.length())}; - }; - filterEntry.filePath = dir; - filterEntry.highlightInfo = highlightInfo(match); - - entries[int(level)].append(filterEntry); - } - } - // file names can match with +linenumber or :linenumber - const Link link = Link::fromString(entryFileName, true); - regExp = createRegExp(link.targetFilePath.toString(), caseSensitivity_); - if (!regExp.isValid()) - return {}; - for (const FilePath &file : files) { - if (future.isCanceled()) - break; - - const QString fileString = file.relativeChildPath(directory).nativePath(); - const QRegularExpressionMatch match = regExp.match(fileString); - if (match.hasMatch()) { - const MatchLevel level = matchLevelFor(match, fileString); - LocatorFilterEntry filterEntry; - filterEntry.displayName = fileString; - filterEntry.filePath = file; - filterEntry.highlightInfo = highlightInfo(match); - filterEntry.linkForEditor = Link(filterEntry.filePath, link.targetLine, - link.targetColumn); - entries[int(level)].append(filterEntry); - } - } - - // "create and open" functionality - const FilePath fullFilePath = directory / entryFileName; - const bool containsWildcard = expandedEntry.contains('?') || expandedEntry.contains('*'); - if (!containsWildcard && !fullFilePath.exists() && directory.exists()) { - LocatorFilterEntry filterEntry; - filterEntry.displayName = Tr::tr("Create and Open \"%1\"").arg(expandedEntry); - filterEntry.acceptor = [fullFilePath] { - QMetaObject::invokeMethod(EditorManager::instance(), - [fullFilePath] { createAndOpen(fullFilePath); }, Qt::QueuedConnection); - return AcceptResult(); - }; - filterEntry.filePath = fullFilePath; - filterEntry.extraInfo = directory.absoluteFilePath().shortNativePath(); - entries[int(MatchLevel::Normal)].append(filterEntry); - } - return std::accumulate(std::begin(entries), std::end(entries), QList()); + return matchesImpl(future, + entry, + shortcutString(), + m_currentDocumentDirectory, + m_currentIncludeHidden); } class FileSystemFilterOptions : public QDialog From e03081a008f7ba39da04ffea87b1f41149ebe30c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 19:17:34 +0200 Subject: [PATCH 0682/1447] LanguageClient: Reimplement matchers() Change-Id: Iad31279b1563022132b5c2f971ceeb96f19a5eaf Reviewed-by: David Schulz --- .../clangcodemodel/clangdlocatorfilters.cpp | 6 +- .../clangmodelmanagersupport.cpp | 12 +-- src/plugins/languageclient/locatorfilter.cpp | 82 +++++++++++++++++-- src/plugins/languageclient/locatorfilter.h | 10 ++- 4 files changed, 93 insertions(+), 17 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 70b5c1c1ec3..097b9f495a8 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -162,7 +162,7 @@ ClangGlobalSymbolFilter::~ClangGlobalSymbolFilter() LocatorMatcherTasks ClangGlobalSymbolFilter::matchers() { return CppEditor::cppMatchers(MatcherType::AllSymbols) - + LanguageClient::workspaceMatchers(MatcherType::AllSymbols, + + LanguageClient::languageClientMatchers(MatcherType::AllSymbols, ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); } @@ -191,7 +191,7 @@ ClangClassesFilter::ClangClassesFilter() LocatorMatcherTasks ClangClassesFilter::matchers() { return CppEditor::cppMatchers(MatcherType::Classes) - + LanguageClient::workspaceMatchers(MatcherType::Classes, + + LanguageClient::languageClientMatchers(MatcherType::Classes, ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); } @@ -208,7 +208,7 @@ ClangFunctionsFilter::ClangFunctionsFilter() LocatorMatcherTasks ClangFunctionsFilter::matchers() { return CppEditor::cppMatchers(MatcherType::Functions) - + LanguageClient::workspaceMatchers(MatcherType::Functions, + + LanguageClient::languageClientMatchers(MatcherType::Functions, ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); } diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 0ca9af11a0d..87bd7bdef6a 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -207,16 +207,16 @@ ClangModelManagerSupport::ClangModelManagerSupport() cppModelManager()->setFunctionsFilter(std::make_unique()); // Setup matchers LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, [] { - return LanguageClient::workspaceMatchers(MatcherType::AllSymbols, clientsForOpenProjects(), - 10000); + return LanguageClient::languageClientMatchers( + MatcherType::AllSymbols, clientsForOpenProjects(), 10000); }); LocatorMatcher::addMatcherCreator(MatcherType::Classes, [] { - return LanguageClient::workspaceMatchers(MatcherType::Classes, clientsForOpenProjects(), - 10000); + return LanguageClient::languageClientMatchers( + MatcherType::Classes, clientsForOpenProjects(), 10000); }); LocatorMatcher::addMatcherCreator(MatcherType::Functions, [] { - return LanguageClient::workspaceMatchers(MatcherType::Functions, clientsForOpenProjects(), - 10000); + return LanguageClient::languageClientMatchers( + MatcherType::Functions, clientsForOpenProjects(), 10000); }); EditorManager *editorManager = EditorManager::instance(); diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index dd83f7ea93f..2e61204a62f 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -4,6 +4,7 @@ #include "locatorfilter.h" #include "clientrequesttask.h" +#include "currentdocumentsymbolsrequesttask.h" #include "documentsymbolcache.h" #include "languageclient_global.h" #include "languageclientmanager.h" @@ -106,6 +107,49 @@ LocatorMatcherTask functionMatcher(Client *client, int maxResultCount) {SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}); } +static void filterCurrentResults(QPromise &promise, const LocatorStorage &storage, + const CurrentDocumentSymbolsData ¤tSymbolsData) +{ + Q_UNUSED(promise) + const auto docSymbolModifier = [](LocatorFilterEntry &entry, const DocumentSymbol &info, + const LocatorFilterEntry &parent) { + Q_UNUSED(parent) + entry.displayName = info.name(); + if (std::optional detail = info.detail()) + entry.extraInfo = *detail; + }; + // TODO: Pass promise into currentSymbols + storage.reportOutput(LanguageClient::currentDocumentSymbols(storage.input(), currentSymbolsData, + docSymbolModifier)); +} + +LocatorMatcherTask currentDocumentMatcher() +{ + using namespace Tasking; + + TreeStorage storage; + TreeStorage resultStorage; + + const auto onQuerySetup = [=](CurrentDocumentSymbolsRequestTask &request) { + Q_UNUSED(request) + }; + const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequestTask &request) { + *resultStorage = request.currentDocumentSymbolsData(); + }; + + const auto onFilterSetup = [=](AsyncTask &async) { + async.setFutureSynchronizer(LanguageClientPlugin::futureSynchronizer()); + async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage); + }; + + const Group root { + Storage(resultStorage), + CurrentDocumentSymbolsRequest(onQuerySetup, onQueryDone), + Async(onFilterSetup) + }; + return {root, storage}; +} + using MatcherCreator = std::function; static MatcherCreator creatorForType(MatcherType type) @@ -114,14 +158,16 @@ static MatcherCreator creatorForType(MatcherType type) case MatcherType::AllSymbols: return &allSymbolsMatcher; case MatcherType::Classes: return &classMatcher; case MatcherType::Functions: return &functionMatcher; - case MatcherType::CurrentDocumentSymbols: return {}; // TODO: implement me + case MatcherType::CurrentDocumentSymbols: QTC_CHECK(false); return {}; } return {}; } -LocatorMatcherTasks workspaceMatchers(MatcherType type, const QList &clients, - int maxResultCount) +LocatorMatcherTasks languageClientMatchers(MatcherType type, const QList &clients, + int maxResultCount) { + if (type == MatcherType::CurrentDocumentSymbols) + return {currentDocumentMatcher()}; const MatcherCreator creator = creatorForType(type); if (!creator) return {}; @@ -145,6 +191,11 @@ DocumentLocatorFilter::DocumentLocatorFilter() this, &DocumentLocatorFilter::updateCurrentClient); } +LocatorMatcherTasks DocumentLocatorFilter::matchers() +{ + return {currentDocumentMatcher()}; +} + void DocumentLocatorFilter::updateCurrentClient() { resetSymbols(); @@ -237,6 +288,25 @@ LocatorFilterEntries entriesForDocSymbols(const QList &infoList, return entries; } +Core::LocatorFilterEntries currentDocumentSymbols(const QString &input, + const CurrentDocumentSymbolsData ¤tSymbolsData, + const DocSymbolModifier &docSymbolModifier) +{ + const FuzzyMatcher::CaseSensitivity caseSensitivity + = ILocatorFilter::caseSensitivity(input) == Qt::CaseSensitive + ? FuzzyMatcher::CaseSensitivity::CaseSensitive + : FuzzyMatcher::CaseSensitivity::CaseInsensitive; + const QRegularExpression regExp = FuzzyMatcher::createRegExp(input, caseSensitivity); + if (!regExp.isValid()) + return {}; + + if (auto list = std::get_if>(¤tSymbolsData.m_symbols)) + return entriesForDocSymbols(*list, regExp, currentSymbolsData.m_filePath, docSymbolModifier); + else if (auto list = std::get_if>(¤tSymbolsData.m_symbols)) + return entriesForSymbolsInfo(*list, regExp, currentSymbolsData.m_pathMapper); + return {}; +} + void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) { QMutexLocker locker(&m_mutex); @@ -303,7 +373,7 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter() LocatorMatcherTasks WorkspaceLocatorFilter::matchers() { - return workspaceMatchers(MatcherType::AllSymbols, + return languageClientMatchers(MatcherType::AllSymbols, Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); } @@ -415,7 +485,7 @@ WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter() LocatorMatcherTasks WorkspaceClassLocatorFilter::matchers() { - return workspaceMatchers(MatcherType::Classes, + return languageClientMatchers(MatcherType::Classes, Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); } @@ -430,7 +500,7 @@ WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() LocatorMatcherTasks WorkspaceMethodLocatorFilter::matchers() { - return workspaceMatchers(MatcherType::Functions, + return languageClientMatchers(MatcherType::Functions, Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index f6c3382c411..286e064c509 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -19,11 +19,16 @@ namespace Core { class IEditor; } namespace LanguageClient { +class CurrentDocumentSymbolsData; + using DocSymbolModifier = std::function; -Core::LocatorMatcherTasks LANGUAGECLIENT_EXPORT workspaceMatchers(Core::MatcherType type, - const QList &clients = {}, int maxResultCount = 0); +Core::LocatorFilterEntries LANGUAGECLIENT_EXPORT currentDocumentSymbols(const QString &input, + const CurrentDocumentSymbolsData ¤tSymbolsData, const DocSymbolModifier &docSymbolModifier); + +Core::LocatorMatcherTasks LANGUAGECLIENT_EXPORT languageClientMatchers( + Core::MatcherType type, const QList &clients = {}, int maxResultCount = 0); class LanguageClientManager; @@ -49,6 +54,7 @@ protected: const DocSymbolModifier &docSymbolModifier); private: + Core::LocatorMatcherTasks matchers() final; void updateCurrentClient(); void updateSymbols(const LanguageServerProtocol::DocumentUri &uri, const LanguageServerProtocol::DocumentSymbolsResult &symbols); From 72bddf9f51fedd064f551bcb4ced5feeb46fdfc1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 14:07:03 +0200 Subject: [PATCH 0683/1447] PluginManager: Introduce global future synchronizer The global synchronizer will be destructed after the asynchronous shutdown phase and prior to deleting all the plugins (i.e. synchronously). It's assumed that between deleting the synchronizer and the point when all plugin destructors are finished no new futures are added to the global future synchronizer. Change-Id: Ibc839b04f2c2bbd35980b8baed51b29c2c4f7c76 Reviewed-by: Eike Ziller --- src/libs/extensionsystem/pluginmanager.cpp | 9 +++++++++ src/libs/extensionsystem/pluginmanager.h | 4 ++++ src/libs/extensionsystem/pluginmanager_p.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index aec053b6a8f..9d478453ea9 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -422,6 +423,11 @@ QString PluginManager::systemInformation() return result; } +static FutureSynchronizer *futureSynchronizer() +{ + return d->m_futureSynchronizer.get(); +} + /*! The list of paths were the plugin manager searches for plugins. @@ -976,6 +982,8 @@ void PluginManagerPrivate::nextDelayedInitialize() PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) : q(pluginManager) { + m_futureSynchronizer.reset(new FutureSynchronizer); + m_futureSynchronizer->setCancelOnWait(true); } @@ -1043,6 +1051,7 @@ void PluginManagerPrivate::stopAll() */ void PluginManagerPrivate::deleteAll() { + m_futureSynchronizer.reset(); // Synchronize all futures from all plugins Utils::reverseForeach(loadQueue(), [this](PluginSpec *spec) { loadPlugin(spec, PluginSpec::Deleted); }); diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h index 8dac9544cca..a56cb7ba9d4 100644 --- a/src/libs/extensionsystem/pluginmanager.h +++ b/src/libs/extensionsystem/pluginmanager.h @@ -15,6 +15,8 @@ QT_BEGIN_NAMESPACE class QTextStream; QT_END_NAMESPACE +namespace Utils { class FutureSynchronizer; } + namespace ExtensionSystem { class IPlugin; class PluginSpec; @@ -133,6 +135,8 @@ public: static QString systemInformation(); + static Utils::FutureSynchronizer *futureSynchronizer(); + signals: void objectAdded(QObject *obj); void aboutToRemoveObject(QObject *obj); diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h index decd6271778..86c3a6c3624 100644 --- a/src/libs/extensionsystem/pluginmanager_p.h +++ b/src/libs/extensionsystem/pluginmanager_p.h @@ -26,6 +26,7 @@ class QEventLoop; QT_END_NAMESPACE namespace Utils { +class FutureSynchronizer; class QtcSettings; } @@ -133,6 +134,7 @@ public: QWaitCondition m_scenarioWaitCondition; PluginManager::ProcessData m_creatorProcessData; + std::unique_ptr m_futureSynchronizer; private: PluginManager *q; From b9ca680b0384bbe4cba7a11df549c31177d0fff1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 23 Apr 2023 17:25:46 +0200 Subject: [PATCH 0684/1447] AutoTest: Further optimize TestCodeParser::scanForTests() When loading a Qt project, after the Scanning For Tests finished, the scanForTests() blocks the main thread for about 3.5 seconds on the calls to parser->init(). Refactor the code so that it operates on QSet instead of QList. This patch constraints the freeze to about 40 ms. Change-Id: I219b3e2abf2b7e5166eec08d83f4cdcb8e4a8098 Reviewed-by: Jarek Kobus Reviewed-by: Christian Stenger --- src/plugins/autotest/itestparser.cpp | 2 +- src/plugins/autotest/itestparser.h | 4 +- src/plugins/autotest/qtest/qttest_utils.cpp | 7 ++- src/plugins/autotest/qtest/qttest_utils.h | 4 +- src/plugins/autotest/qtest/qttestparser.cpp | 2 +- src/plugins/autotest/qtest/qttestparser.h | 2 +- .../autotest/quick/quicktest_utils.cpp | 3 +- src/plugins/autotest/quick/quicktest_utils.h | 2 +- .../autotest/quick/quicktestparser.cpp | 2 +- src/plugins/autotest/quick/quicktestparser.h | 2 +- src/plugins/autotest/testcodeparser.cpp | 59 +++++++++---------- src/plugins/autotest/testcodeparser.h | 4 +- 12 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/plugins/autotest/itestparser.cpp b/src/plugins/autotest/itestparser.cpp index d8f1d6953b3..27408ee933e 100644 --- a/src/plugins/autotest/itestparser.cpp +++ b/src/plugins/autotest/itestparser.cpp @@ -24,7 +24,7 @@ CppParser::CppParser(ITestFramework *framework) { } -void CppParser::init(const FilePaths &filesToParse, bool fullParse) +void CppParser::init(const QSet &filesToParse, bool fullParse) { Q_UNUSED(filesToParse) Q_UNUSED(fullParse) diff --git a/src/plugins/autotest/itestparser.h b/src/plugins/autotest/itestparser.h index 24b132c610c..93233bd7a97 100644 --- a/src/plugins/autotest/itestparser.h +++ b/src/plugins/autotest/itestparser.h @@ -45,7 +45,7 @@ class ITestParser public: explicit ITestParser(ITestFramework *framework) : m_framework(framework) {} virtual ~ITestParser() { } - virtual void init(const Utils::FilePaths &filesToParse, bool fullParse) = 0; + virtual void init(const QSet &filesToParse, bool fullParse) = 0; virtual bool processDocument(QPromise &futureInterface, const Utils::FilePath &fileName) = 0; @@ -63,7 +63,7 @@ class CppParser : public ITestParser { public: explicit CppParser(ITestFramework *framework); - void init(const Utils::FilePaths &filesToParse, bool fullParse) override; + void init(const QSet &filesToParse, bool fullParse) override; static bool selectedForBuilding(const Utils::FilePath &fileName); QByteArray getFileContent(const Utils::FilePath &filePath) const; void release() override; diff --git a/src/plugins/autotest/qtest/qttest_utils.cpp b/src/plugins/autotest/qtest/qttest_utils.cpp index 1069280bee1..ab6048da084 100644 --- a/src/plugins/autotest/qtest/qttest_utils.cpp +++ b/src/plugins/autotest/qtest/qttest_utils.cpp @@ -4,7 +4,6 @@ #include "qttest_utils.h" #include "qttesttreeitem.h" #include "../autotestplugin.h" -#include "../testframeworkmanager.h" #include "../testsettings.h" #include @@ -27,7 +26,8 @@ bool isQTestMacro(const QByteArray ¯o) return valid.contains(macro); } -QHash testCaseNamesForFiles(ITestFramework *framework, const FilePaths &files) +QHash testCaseNamesForFiles(ITestFramework *framework, + const QSet &files) { QHash result; TestTreeItem *rootNode = framework->rootNode(); @@ -49,7 +49,8 @@ QHash testCaseNamesForFiles(ITestFramework *framework, cons return result; } -QMultiHash alternativeFiles(ITestFramework *framework, const FilePaths &files) +QMultiHash alternativeFiles(ITestFramework *framework, + const QSet &files) { QMultiHash result; TestTreeItem *rootNode = framework->rootNode(); diff --git a/src/plugins/autotest/qtest/qttest_utils.h b/src/plugins/autotest/qtest/qttest_utils.h index 6f5a587df3d..8f077345412 100644 --- a/src/plugins/autotest/qtest/qttest_utils.h +++ b/src/plugins/autotest/qtest/qttest_utils.h @@ -26,9 +26,9 @@ namespace QTestUtils { bool isQTestMacro(const QByteArray ¯o); QHash testCaseNamesForFiles(ITestFramework *framework, - const Utils::FilePaths &files); + const QSet &files); QMultiHash alternativeFiles(ITestFramework *framework, - const Utils::FilePaths &files); + const QSet &files); QStringList filterInterfering(const QStringList &provided, QStringList *omitted, bool isQuickTest); Utils::Environment prepareBasicEnvironment(const Utils::Environment &env); diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp index a532a13cb3d..f68a87d7bf3 100644 --- a/src/plugins/autotest/qtest/qttestparser.cpp +++ b/src/plugins/autotest/qtest/qttestparser.cpp @@ -414,7 +414,7 @@ QtTestParseResult *QtTestParser::createParseResult( return parseResult; } -void QtTestParser::init(const FilePaths &filesToParse, bool fullParse) +void QtTestParser::init(const QSet &filesToParse, bool fullParse) { if (!fullParse) { // in a full parse cached information might lead to wrong results m_testCases = QTestUtils::testCaseNamesForFiles(framework(), filesToParse); diff --git a/src/plugins/autotest/qtest/qttestparser.h b/src/plugins/autotest/qtest/qttestparser.h index 9dafcdc77e1..abd8b2b0aaa 100644 --- a/src/plugins/autotest/qtest/qttestparser.h +++ b/src/plugins/autotest/qtest/qttestparser.h @@ -34,7 +34,7 @@ class QtTestParser : public CppParser public: explicit QtTestParser(ITestFramework *framework) : CppParser(framework) {} - void init(const Utils::FilePaths &filesToParse, bool fullParse) override; + void init(const QSet &filesToParse, bool fullParse) override; void release() override; bool processDocument(QPromise &promise, const Utils::FilePath &fileName) override; diff --git a/src/plugins/autotest/quick/quicktest_utils.cpp b/src/plugins/autotest/quick/quicktest_utils.cpp index 09d2453c96a..d5ffc26038f 100644 --- a/src/plugins/autotest/quick/quicktest_utils.cpp +++ b/src/plugins/autotest/quick/quicktest_utils.cpp @@ -22,7 +22,8 @@ bool isQuickTestMacro(const QByteArray ¯o) return valid.contains(macro); } -QHash proFilesForQmlFiles(ITestFramework *framework, const FilePaths &files) +QHash proFilesForQmlFiles(ITestFramework *framework, + const QSet &files) { QHash result; TestTreeItem *rootNode = framework->rootNode(); diff --git a/src/plugins/autotest/quick/quicktest_utils.h b/src/plugins/autotest/quick/quicktest_utils.h index fb1dbb26753..731f7c6864c 100644 --- a/src/plugins/autotest/quick/quicktest_utils.h +++ b/src/plugins/autotest/quick/quicktest_utils.h @@ -16,7 +16,7 @@ namespace QuickTestUtils { bool isQuickTestMacro(const QByteArray ¯o); QHash proFilesForQmlFiles(ITestFramework *framework, - const Utils::FilePaths &files); + const QSet &files); } // namespace QuickTestUtils } // namespace Internal diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index de0003b2ffc..a4cf0967b6c 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -338,7 +338,7 @@ QuickTestParser::QuickTestParser(ITestFramework *framework) this, &QuickTestParser::handleDirectoryChanged); } -void QuickTestParser::init(const FilePaths &filesToParse, bool fullParse) +void QuickTestParser::init(const QSet &filesToParse, bool fullParse) { m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot(); if (!fullParse) { diff --git a/src/plugins/autotest/quick/quicktestparser.h b/src/plugins/autotest/quick/quicktestparser.h index bf3727feca3..dfd71333ead 100644 --- a/src/plugins/autotest/quick/quicktestparser.h +++ b/src/plugins/autotest/quick/quicktestparser.h @@ -24,7 +24,7 @@ class QuickTestParser : public QObject, public CppParser Q_OBJECT public: explicit QuickTestParser(ITestFramework *framework); - void init(const Utils::FilePaths &filesToParse, bool fullParse) override; + void init(const QSet &filesToParse, bool fullParse) override; void release() override; bool processDocument(QPromise &promise, const Utils::FilePath &fileName) override; diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index a88860860f0..a25d28e673f 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -87,7 +87,7 @@ void TestCodeParser::setState(State state) m_postponedUpdateType = UpdateType::NoUpdate; qCDebug(LOG) << "calling scanForTests with postponed files (setState)"; if (!m_reparseTimer.isActive()) - scanForTests(Utils::toList(m_postponedFiles)); + scanForTests(m_postponedFiles); } } } @@ -213,27 +213,28 @@ void TestCodeParser::aboutToShutdown() m_futureSynchronizer.waitForFinished(); } -bool TestCodeParser::postponed(const FilePaths &fileList) +bool TestCodeParser::postponed(const QSet &filePaths) { switch (m_parserState) { case Idle: - if (fileList.size() == 1) { + if (filePaths.size() == 1) { if (m_reparseTimerTimedOut) return false; + const FilePath filePath = *filePaths.begin(); switch (m_postponedFiles.size()) { case 0: - m_postponedFiles.insert(fileList.first()); + m_postponedFiles.insert(filePath); m_reparseTimer.setInterval(1000); m_reparseTimer.start(); return true; case 1: - if (m_postponedFiles.contains(fileList.first())) { + if (m_postponedFiles.contains(filePath)) { m_reparseTimer.start(); return true; } Q_FALLTHROUGH(); default: - m_postponedFiles.insert(fileList.first()); + m_postponedFiles.insert(filePath); m_reparseTimer.stop(); m_reparseTimer.setInterval(0); m_reparseTimerTimedOut = false; @@ -245,7 +246,7 @@ bool TestCodeParser::postponed(const FilePaths &fileList) case PartialParse: case FullParse: // parse is running, postponing a full parse - if (fileList.isEmpty()) { + if (filePaths.isEmpty()) { m_postponedFiles.clear(); m_postponedUpdateType = UpdateType::FullUpdate; qCDebug(LOG) << "Canceling scanForTest (full parse triggered while running a scan)"; @@ -255,8 +256,7 @@ bool TestCodeParser::postponed(const FilePaths &fileList) if (m_postponedUpdateType == UpdateType::FullUpdate) return true; // partial parse triggered, postpone or add current files to already postponed partial - for (const FilePath &file : fileList) - m_postponedFiles.insert(file); + m_postponedFiles += filePaths; m_postponedUpdateType = UpdateType::PartialUpdate; } return true; @@ -277,31 +277,32 @@ static void parseFileForTests(QPromise &promise, } } -void TestCodeParser::scanForTests(const FilePaths &fileList, const QList &parsers) +void TestCodeParser::scanForTests(const QSet &filePaths, + const QList &parsers) { if (m_parserState == Shutdown || m_testCodeParsers.isEmpty()) return; - if (postponed(fileList)) + if (postponed(filePaths)) return; + QSet files = filePaths; // avoid getting cleared if m_postponedFiles have been passed m_reparseTimer.stop(); m_reparseTimerTimedOut = false; m_postponedFiles.clear(); - bool isFullParse = fileList.isEmpty(); + const bool isFullParse = files.isEmpty(); Project *project = ProjectManager::startupProject(); if (!project) return; - FilePaths list; if (isFullParse) { - list = project->files(Project::SourceFiles); - if (list.isEmpty()) { + files = Utils::toSet(project->files(Project::SourceFiles)); + if (files.isEmpty()) { // at least project file should be there, but might happen if parsing current project // takes too long, especially when opening sessions holding multiple projects qCDebug(LOG) << "File list empty (FullParse) - trying again in a sec"; emitUpdateTestTree(); return; - } else if (list.size() == 1 && list.first() == project->projectFilePath()) { + } else if (files.size() == 1 && *files.constBegin() == project->projectFilePath()) { qCDebug(LOG) << "File list contains only the project file."; return; } @@ -309,7 +310,6 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QListupdateCheckStateCache(); if (isFullParse) { // remove qml files as they will be found automatically by the referencing cpp file - list = Utils::filtered(list, [](const FilePath &fn) { return !fn.endsWith(".qml"); }); + files = Utils::filtered(files, [](const FilePath &fn) { return !fn.endsWith(".qml"); }); if (!parsers.isEmpty()) { for (ITestParser *parser : parsers) parser->framework()->rootNode()->markForRemovalRecursively(true); @@ -326,15 +326,14 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QListframework()->rootNode()->markForRemovalRecursively(set); + parser->framework()->rootNode()->markForRemovalRecursively(files); } } else { - emit requestRemoval(Utils::toSet(list)); + emit requestRemoval(files); } - QTC_ASSERT(!(isFullParse && list.isEmpty()), onFinished(true); return); + QTC_ASSERT(!(isFullParse && files.isEmpty()), onFinished(true); return); // use only a single parser or all current active? const QList codeParsers = parsers.isEmpty() ? m_testCodeParsers : parsers; @@ -343,14 +342,14 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QListsnapshot(); for (ITestParser *parser : codeParsers) { - parser->init(list, isFullParse); + parser->init(files, isFullParse); for (const QString &ext : parser->supportedExtensions()) extensions.insert(ext); } // We are only interested in files that have been either parsed by the c++ parser, // or have an extension that one of the parsers is specifically interested in. - const FilePaths filteredList - = Utils::filtered(list, [&extensions, &cppSnapshot](const FilePath &fn) { + const QSet filteredFiles + = Utils::filtered(files, [&extensions, &cppSnapshot](const FilePath &fn) { const bool isSupportedExtension = Utils::anyOf(extensions, [&fn](const QString &ext) { return fn.suffix() == ext; }); @@ -359,13 +358,13 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList tasks{parallel}; // TODO: use ParallelLimit(N) and add to settings? - for (const FilePath &file : filteredList) { + for (const FilePath &file : filteredFiles) { const auto setup = [this, codeParsers, file](AsyncTask &async) { async.setConcurrentCallData(parseFileForTests, codeParsers, file); async.setThreadPool(m_threadPool); @@ -384,7 +383,7 @@ void TestCodeParser::scanForTests(const FilePaths &fileList, const QList 5) { + if (filteredFiles.size() > 5) { auto progress = new TaskProgress(m_taskTree.get()); progress->setDisplayName(Tr::tr("Scanning for Tests")); progress->setId(Constants::TASK_PARSE); @@ -467,7 +466,7 @@ void TestCodeParser::onPartialParsingFinished() case UpdateType::PartialUpdate: qCDebug(LOG) << "calling scanForTests with postponed files (onPartialParsingFinished)"; if (!m_reparseTimer.isActive()) - scanForTests(Utils::toList(m_postponedFiles)); + scanForTests(m_postponedFiles); break; case UpdateType::NoUpdate: m_dirty |= m_codeModelParsing; @@ -491,7 +490,7 @@ void TestCodeParser::onPartialParsingFinished() void TestCodeParser::parsePostponedFiles() { m_reparseTimerTimedOut = true; - scanForTests(Utils::toList(m_postponedFiles)); + scanForTests(m_postponedFiles); } void TestCodeParser::releaseParserInternals() diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index e9b3832f449..8effd3b5772 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -66,8 +66,8 @@ public: void aboutToShutdown(); private: - bool postponed(const Utils::FilePaths &fileList); - void scanForTests(const Utils::FilePaths &fileList = Utils::FilePaths(), + bool postponed(const QSet &fileList); + void scanForTests(const QSet &filePaths = {}, const QList &parsers = {}); // qml files must be handled slightly different From f46f9ac43253f486cccefd7b453142630d10a612 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 23 Apr 2023 18:58:31 +0200 Subject: [PATCH 0685/1447] AutoTest: Optimize starting task tree in TestCodeParser::scanForTests() When loading a Qt project, after the Scanning For Tests finished, the scanForTests() blocks the main thread for about 2.5 seconds on the call to m_taskTree->start(). The reason is that created task tree contains about 8000 asynchronous tasks. If all they run in parallel it means that we start them all synchronously. Don't use internal QThreadPool, as it doesn't prevent the freeze when more than maxTreadCount() threads are started. Instead, use the parallel limit with the same constraint that was used for thread pool. It means that only constrained number of tasks are being run in parallel and the rest is being postponed until some of the running tasks finished. In this way starting the constrained number of tasks reduces the GUI freeze to ~0 ms on task tree start(). In general: this patch divides the overall freeze of 2.5 seconds evenly into many very small pieces and distributes them evenly in time, so the GUI stays responsive. This patch, when applied together with 2 bottom patches, reduces the GUI freeze spent inside scanForTests() after loading a Qt project and after Scanning For Tests finished from about 23 seconds into 160 ms. Change-Id: If33076d4f042c3d96434b9f3cc305776fb30906d Reviewed-by: Christian Stenger --- src/plugins/autotest/testcodeparser.cpp | 7 ++----- src/plugins/autotest/testcodeparser.h | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index a25d28e673f..afa4f8ca5e8 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -39,7 +39,6 @@ static bool isProjectParsing() } TestCodeParser::TestCodeParser() - : m_threadPool(new QThreadPool(this)) { // connect to ProgressManager to postpone test parsing when CppModelManager is parsing ProgressManager *progressManager = ProgressManager::instance(); @@ -55,8 +54,6 @@ TestCodeParser::TestCodeParser() }); m_reparseTimer.setSingleShot(true); connect(&m_reparseTimer, &QTimer::timeout, this, &TestCodeParser::parsePostponedFiles); - m_threadPool->setMaxThreadCount(std::max(QThread::idealThreadCount()/4, 1)); - m_threadPool->setThreadPriority(QThread::LowestPriority); m_futureSynchronizer.setCancelOnWait(true); } @@ -363,11 +360,11 @@ void TestCodeParser::scanForTests(const QSet &filePaths, using namespace Tasking; - QList tasks{parallel}; // TODO: use ParallelLimit(N) and add to settings? + QList tasks{ParallelLimit(std::max(QThread::idealThreadCount() / 4, 1))}; for (const FilePath &file : filteredFiles) { const auto setup = [this, codeParsers, file](AsyncTask &async) { async.setConcurrentCallData(parseFileForTests, codeParsers, file); - async.setThreadPool(m_threadPool); + async.setPriority(QThread::LowestPriority); async.setFutureSynchronizer(&m_futureSynchronizer); }; const auto onDone = [this](const AsyncTask &async) { diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index 8effd3b5772..c86de52b943 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -94,7 +94,6 @@ private: QList m_testCodeParsers; // ptrs are still owned by TestFrameworkManager QTimer m_reparseTimer; QSet m_updateParsers; - QThreadPool *m_threadPool = nullptr; Utils::FutureSynchronizer m_futureSynchronizer; std::unique_ptr m_taskTree; QHash m_qmlEditorRev; From 1fe09a00d7bdefc2e7a675f265797739a4d5986a Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 24 Apr 2023 14:24:48 +0200 Subject: [PATCH 0686/1447] FSEngine: Fix thread safety Change-Id: I5223cef1a70ffcb92e886733af2b1d8061c4dbf0 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/libs/utils/fsengine/fsengine.cpp | 57 ++++++++++++++------- src/libs/utils/fsengine/fsengine.h | 4 -- src/libs/utils/fsengine/fsenginehandler.cpp | 2 +- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/libs/utils/fsengine/fsengine.cpp b/src/libs/utils/fsengine/fsengine.cpp index cc622b87860..fd343aaad11 100644 --- a/src/libs/utils/fsengine/fsengine.cpp +++ b/src/libs/utils/fsengine/fsengine.cpp @@ -10,6 +10,8 @@ class Utils::Internal::FSEngineHandler {}; #endif +#include + #include namespace Utils { @@ -29,46 +31,65 @@ bool FSEngine::isAvailable() #endif } +template +class Locked +{ +public: + Locked(QMutex *mutex, T &object) + : m_object(object) + , m_locker(mutex) + {} + + T *operator->() const noexcept { return &m_object; } + const T operator*() const noexcept { return m_object; } + +private: + T &m_object; + QMutexLocker m_locker; +}; + +static Locked deviceRoots() +{ + static FilePaths g_deviceRoots; + static QMutex mutex; + return {&mutex, g_deviceRoots}; +} + +static Locked deviceSchemes() +{ + static QStringList g_deviceSchemes{"device"}; + static QMutex mutex; + return {&mutex, g_deviceSchemes}; +} + FilePaths FSEngine::registeredDeviceRoots() { - return FSEngine::deviceRoots(); + return *deviceRoots(); } void FSEngine::addDevice(const FilePath &deviceRoot) { - deviceRoots().append(deviceRoot); + deviceRoots()->append(deviceRoot); } void FSEngine::removeDevice(const FilePath &deviceRoot) { - deviceRoots().removeAll(deviceRoot); -} - -FilePaths &FSEngine::deviceRoots() -{ - static FilePaths g_deviceRoots; - return g_deviceRoots; -} - -QStringList &FSEngine::deviceSchemes() -{ - static QStringList g_deviceSchemes{"device"}; - return g_deviceSchemes; + deviceRoots()->removeAll(deviceRoot); } void FSEngine::registerDeviceScheme(const QStringView scheme) { - deviceSchemes().append(scheme.toString()); + deviceSchemes()->append(scheme.toString()); } void FSEngine::unregisterDeviceScheme(const QStringView scheme) { - deviceSchemes().removeAll(scheme.toString()); + deviceSchemes()->removeAll(scheme.toString()); } QStringList FSEngine::registeredDeviceSchemes() { - return FSEngine::deviceSchemes(); + return *deviceSchemes(); } } // namespace Utils diff --git a/src/libs/utils/fsengine/fsengine.h b/src/libs/utils/fsengine/fsengine.h index 52c03e9cee5..4c486ead6ee 100644 --- a/src/libs/utils/fsengine/fsengine.h +++ b/src/libs/utils/fsengine/fsengine.h @@ -33,10 +33,6 @@ public: static void unregisterDeviceScheme(const QStringView scheme); static QStringList registeredDeviceSchemes(); -private: - static Utils::FilePaths &deviceRoots(); - static QStringList &deviceSchemes(); - private: std::unique_ptr m_engineHandler; }; diff --git a/src/libs/utils/fsengine/fsenginehandler.cpp b/src/libs/utils/fsengine/fsenginehandler.cpp index c5fa71e7861..e020eebddac 100644 --- a/src/libs/utils/fsengine/fsenginehandler.cpp +++ b/src/libs/utils/fsengine/fsenginehandler.cpp @@ -56,7 +56,7 @@ QAbstractFileEngine *FSEngineHandler::create(const QString &fileName) const const QStringList deviceSchemes = FSEngine::registeredDeviceSchemes(); for (const QString &scheme : deviceSchemes) { if (fixedFileName == rootFilePath.pathAppended(scheme).toString()) { - const FilePaths filteredRoots = Utils::filtered(FSEngine::deviceRoots(), + const FilePaths filteredRoots = Utils::filtered(FSEngine::registeredDeviceRoots(), [scheme](const FilePath &root) { return root.scheme() == scheme; }); From 68c92f6dfa2f431e784b3aebf38bc3f76a7cb0ce Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 23 Feb 2023 11:18:48 +0100 Subject: [PATCH 0687/1447] Provide device roots in filesystem locator filter Check if the full search text matches a device root and suggest them at the end of the results. Change-Id: I6e6e201597a9824b5e0c342cbc930baf2ac5ffea Reviewed-by: Marcus Tillmanns --- .../coreplugin/locator/filesystemfilter.cpp | 145 ++++++++++++------ 1 file changed, 102 insertions(+), 43 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 646ab366c81..75bbcba1511 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -11,12 +11,14 @@ #include "../vcsmanager.h" #include +#include #include #include #include #include #include +#include #include #include #include @@ -26,12 +28,15 @@ #include #include #include +#include using namespace Utils; namespace Core { namespace Internal { +Q_GLOBAL_STATIC(QIcon, sDeviceRootIcon); + static const char kAlwaysCreate[] = "Locator/FileSystemFilter/AlwaysCreate"; static ILocatorFilter::MatchLevel matchLevelFor(const QRegularExpressionMatch &match, @@ -79,6 +84,20 @@ static void createAndOpen(const FilePath &filePath) EditorManager::openEditor(filePath); } +static FilePaths deviceRoots() +{ + const QString rootPath = FilePath::specialRootPath(); + const QStringList roots = QDir(rootPath).entryList(); + FilePaths devices; + for (const QString &root : roots) { + const QString prefix = rootPath + '/' + root; + devices += Utils::transform(QDir(prefix).entryList(), [prefix](const QString &s) { + return FilePath::fromString(prefix + '/' + s); + }); + } + return devices; +} + FileSystemFilter::FileSystemFilter() { setId("Files in file system"); @@ -88,6 +107,7 @@ FileSystemFilter::FileSystemFilter() "file if it does not exist yet.")); setDefaultShortcutString("f"); setDefaultIncludedByDefault(false); + *sDeviceRootIcon = qApp->style()->standardIcon(QStyle::SP_DriveHDIcon); } template @@ -102,8 +122,12 @@ static LocatorFilterEntries matchesImpl(Promise &promise, const Environment env = Environment::systemEnvironment(); const QString expandedEntry = env.expandVariables(input); const auto expandedEntryPath = FilePath::fromUserInput(expandedEntry); - const auto absoluteEntryPath = currentDocumentDir.isEmpty() ? expandedEntryPath - : currentDocumentDir.resolvePath(expandedEntryPath); + const FilePath absoluteEntryPath = currentDocumentDir.isEmpty() + ? expandedEntryPath + : currentDocumentDir.resolvePath(expandedEntryPath); + // The case of e.g. "ssh://", "ssh://*p", etc + const bool isPartOfDeviceRoot = expandedEntryPath.needsDevice() + && expandedEntryPath.path().isEmpty(); // Consider the entered path a directory if it ends with slash/backslash. // If it is a dir but doesn't end with a backslash, we want to still show all (other) matching @@ -123,57 +147,92 @@ static LocatorFilterEntries matchesImpl(Promise &promise, // use only 'name' for case sensitivity decision, because we need to make the path // match the case on the file system for case-sensitive file systems const Qt::CaseSensitivity caseSensitivity = ILocatorFilter::caseSensitivity(entryFileName); - const FilePaths dirs = FilePaths({directory / ".."}) - + directory.dirEntries({{}, dirFilter}, - QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); - const FilePaths files = directory.dirEntries({{}, fileFilter}, - QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); + const FilePaths dirs = isPartOfDeviceRoot + ? FilePaths() + : FilePaths({directory / ".."}) + + directory.dirEntries({{}, dirFilter}, + QDir::Name | QDir::IgnoreCase + | QDir::LocaleAware); + const FilePaths files = isPartOfDeviceRoot ? FilePaths() + : directory.dirEntries({{}, fileFilter}, + QDir::Name | QDir::IgnoreCase + | QDir::LocaleAware); + // directories QRegularExpression regExp = ILocatorFilter::createRegExp(entryFileName, caseSensitivity); - if (!regExp.isValid()) - return {}; + if (regExp.isValid()) { + for (const FilePath &dir : dirs) { + if (promise.isCanceled()) + return {}; - for (const FilePath &dir : dirs) { - if (promise.isCanceled()) - return {}; + const QString dirString = dir.relativeChildPath(directory).nativePath(); + const QRegularExpressionMatch match = regExp.match(dirString); + if (match.hasMatch()) { + const ILocatorFilter::MatchLevel level = matchLevelFor(match, dirString); + LocatorFilterEntry filterEntry; + filterEntry.displayName = dirString; + filterEntry.acceptor = [shortcutString, dir] { + const QString value + = shortcutString + ' ' + + dir.absoluteFilePath().cleanPath().pathAppended("/").toUserOutput(); + return AcceptResult{value, int(value.length())}; + }; + filterEntry.filePath = dir; + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); - const QString dirString = dir.relativeChildPath(directory).nativePath(); - const QRegularExpressionMatch match = regExp.match(dirString); - if (match.hasMatch()) { - const ILocatorFilter::MatchLevel level = matchLevelFor(match, dirString); - LocatorFilterEntry filterEntry; - filterEntry.displayName = dirString; - filterEntry.acceptor = [shortcutString, dir] { - const QString value = shortcutString + ' ' - + dir.absoluteFilePath().cleanPath().pathAppended("/").toUserOutput(); - return AcceptResult{value, int(value.length())}; - }; - filterEntry.filePath = dir; - filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); - - entries[int(level)].append(filterEntry); + entries[int(level)].append(filterEntry); + } } } // file names can match with +linenumber or :linenumber const Link link = Link::fromString(entryFileName, true); regExp = ILocatorFilter::createRegExp(link.targetFilePath.toString(), caseSensitivity); - if (!regExp.isValid()) - return {}; - for (const FilePath &file : files) { - if (promise.isCanceled()) - return {}; + if (regExp.isValid()) { + for (const FilePath &file : files) { + if (promise.isCanceled()) + return {}; - const QString fileString = file.relativeChildPath(directory).nativePath(); - const QRegularExpressionMatch match = regExp.match(fileString); - if (match.hasMatch()) { - const ILocatorFilter::MatchLevel level = matchLevelFor(match, fileString); - LocatorFilterEntry filterEntry; - filterEntry.displayName = fileString; - filterEntry.filePath = file; - filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); - filterEntry.linkForEditor = Link(filterEntry.filePath, link.targetLine, - link.targetColumn); - entries[int(level)].append(filterEntry); + const QString fileString = file.relativeChildPath(directory).nativePath(); + const QRegularExpressionMatch match = regExp.match(fileString); + if (match.hasMatch()) { + const ILocatorFilter::MatchLevel level = matchLevelFor(match, fileString); + LocatorFilterEntry filterEntry; + filterEntry.displayName = fileString; + filterEntry.filePath = file; + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + filterEntry.linkForEditor = Link(filterEntry.filePath, + link.targetLine, + link.targetColumn); + entries[int(level)].append(filterEntry); + } + } + } + // device roots + // check against full search text + regExp = ILocatorFilter::createRegExp(expandedEntryPath.toUserOutput(), caseSensitivity); + if (regExp.isValid()) { + const FilePaths roots = deviceRoots(); + for (const FilePath &root : roots) { + if (promise.isCanceled()) + return {}; + + const QString displayString = root.toUserOutput(); + const QRegularExpressionMatch match = regExp.match(displayString); + if (match.hasMatch()) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = displayString; + filterEntry.acceptor = [shortcutString, root] { + const QString value + = shortcutString + ' ' + + root.absoluteFilePath().cleanPath().pathAppended("/").toUserOutput(); + return AcceptResult{value, int(value.length())}; + }; + filterEntry.filePath = root; + filterEntry.displayIcon = *sDeviceRootIcon; + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + + entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); + } } } From 8cf500c5bc2d2171f80f392d325ddcf5107e184c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Apr 2023 10:15:07 +0200 Subject: [PATCH 0688/1447] Utils: Make Layouting a top level namespace The whole machinery is now almost only layoutbuilder.{h,cpp}, mostly independent of the rest of Utils. Idea is to finish the separation to make it stand-alone usable also outside creator. Change-Id: I958aa667d17ae26b21209f22412309c5307a579c Reviewed-by: Eike Ziller Reviewed-by: Alessandro Portale --- .../advanceddockingsystem/workspacedialog.cpp | 4 ++-- src/libs/extensionsystem/plugindetailsview.cpp | 2 +- src/libs/extensionsystem/pluginerroroverview.cpp | 2 +- src/libs/extensionsystem/pluginerrorview.cpp | 2 +- .../qmleditorwidgets/contextpanetextwidget.cpp | 2 +- .../qmleditorwidgets/contextpanewidgetimage.cpp | 4 ++-- .../contextpanewidgetrectangle.cpp | 2 +- .../easingpane/easingcontextpane.cpp | 2 +- src/libs/utils/aspects.cpp | 2 +- src/libs/utils/aspects.h | 10 +++++----- src/libs/utils/layoutbuilder.cpp | 6 +++--- src/libs/utils/layoutbuilder.h | 15 ++++++++++----- src/plugins/autotest/ctest/ctestsettings.cpp | 2 +- src/plugins/bazaar/bazaarcommitwidget.cpp | 2 +- src/plugins/bazaar/bazaarplugin.cpp | 2 +- src/plugins/bazaar/pullorpushdialog.cpp | 2 +- .../artisticstyle/artisticstyleoptionspage.cpp | 2 +- .../clangformat/clangformatoptionspage.cpp | 2 +- src/plugins/beautifier/configurationdialog.cpp | 2 +- src/plugins/beautifier/configurationpanel.cpp | 2 +- src/plugins/beautifier/generaloptionspage.cpp | 2 +- .../uncrustify/uncrustifyoptionspage.cpp | 2 +- .../clangtoolsprojectsettingswidget.cpp | 2 +- src/plugins/clangtools/filterdialog.cpp | 2 +- src/plugins/clearcase/checkoutdialog.cpp | 4 ++-- .../clearcase/clearcasesubmiteditorwidget.cpp | 2 +- src/plugins/clearcase/versionselector.cpp | 2 +- .../cmakeformatteroptionspage.cpp | 2 +- .../cmakeprojectmanager/cmakekitinformation.cpp | 2 +- src/plugins/copilot/authwidget.cpp | 2 +- src/plugins/coreplugin/dialogs/addtovcsdialog.cpp | 2 +- src/plugins/coreplugin/dialogs/openwithdialog.cpp | 2 +- .../coreplugin/dialogs/saveitemsdialog.cpp | 2 +- src/plugins/coreplugin/mimetypemagicdialog.cpp | 2 +- src/plugins/cpaster/pasteselectdialog.cpp | 2 +- src/plugins/cpaster/pasteview.cpp | 2 +- .../cppeditor/cppcodemodelinspectordialog.cpp | 2 +- .../cppeditor/cppcodemodelsettingspage.cpp | 4 ++-- .../cppeditor/cppcodestylesettingspage.cpp | 2 +- src/plugins/debugger/debuggeractions.h | 2 +- src/plugins/debugger/debuggerkitinformation.cpp | 2 +- src/plugins/designer/cpp/newclasswidget.cpp | 2 +- src/plugins/fossil/configuredialog.cpp | 2 +- src/plugins/fossil/fossilplugin.cpp | 2 +- src/plugins/fossil/pullorpushdialog.cpp | 2 +- src/plugins/git/branchadddialog.cpp | 2 +- src/plugins/git/branchcheckoutdialog.cpp | 2 +- src/plugins/git/gerrit/gerritpushdialog.cpp | 2 +- src/plugins/gitlab/gitlaboptionspage.cpp | 2 +- src/plugins/incredibuild/commandbuilderaspect.h | 2 +- src/plugins/ios/createsimulatordialog.cpp | 2 +- src/plugins/ios/iosrunconfiguration.h | 2 +- src/plugins/ios/iossettingswidget.cpp | 2 +- src/plugins/ios/simulatoroperationdialog.cpp | 2 +- src/plugins/macros/macrooptionswidget.cpp | 2 +- src/plugins/mcusupport/mcukitinformation.cpp | 2 +- src/plugins/mercurial/authenticationdialog.cpp | 2 +- src/plugins/mercurial/mercurialcommitwidget.cpp | 4 ++-- src/plugins/mesonprojectmanager/settings.cpp | 2 +- .../mesonprojectmanager/toolkitaspectwidget.h | 2 +- .../settings/nimcodestylepreferenceswidget.cpp | 2 +- src/plugins/perforce/changenumberdialog.cpp | 2 +- src/plugins/perforce/pendingchangesdialog.cpp | 2 +- src/plugins/perfprofiler/perftracepointdialog.cpp | 2 +- src/plugins/projectexplorer/buildaspects.h | 2 +- .../codestylesettingspropertiespage.cpp | 2 +- .../projectexplorer/customparserconfigdialog.cpp | 2 +- .../devicefactoryselectiondialog.cpp | 2 +- .../devicesupport/devicesettingswidget.cpp | 2 +- .../devicesupport/devicetestdialog.cpp | 2 +- .../editorsettingspropertiespage.cpp | 2 +- src/plugins/projectexplorer/kitinformation.cpp | 2 +- .../projectexplorersettingspage.cpp | 2 +- src/plugins/projectexplorer/projectwizardpage.cpp | 2 +- .../projectexplorer/runconfigurationaspects.cpp | 2 +- .../projectexplorer/runconfigurationaspects.h | 10 +++++----- src/plugins/projectexplorer/sessiondialog.cpp | 4 ++-- src/plugins/python/pythonwizardpage.cpp | 2 +- .../customqbspropertiesdialog.cpp | 2 +- .../qbsprojectmanager/qbskitinformation.cpp | 2 +- .../qbsprojectmanager/qbsprofilessettingspage.cpp | 2 +- .../customwidgetwizard/classdefinition.cpp | 2 +- .../customwidgetpluginwizardpage.cpp | 2 +- .../customwidgetwidgetswizardpage.cpp | 2 +- src/plugins/qmldesigner/openuiqmlfiledialog.cpp | 2 +- src/plugins/qmldesigner/settingspage.cpp | 2 +- .../qmljseditor/qmljscomponentnamedialog.cpp | 2 +- .../qmljseditor/qmljseditingsettingspage.cpp | 2 +- .../qmljstools/qmljscodestylesettingspage.cpp | 2 +- .../qmljstools/qmljscodestylesettingswidget.cpp | 2 +- src/plugins/qmlprojectmanager/qmlmainfileaspect.h | 2 +- src/plugins/qtsupport/codegensettingspage.cpp | 2 +- src/plugins/qtsupport/qtbuildaspects.h | 4 ++-- src/plugins/qtsupport/qtoptionspage.cpp | 2 +- .../resourceeditor/qrceditor/qrceditor.cpp | 2 +- src/plugins/scxmleditor/common/colorpicker.cpp | 2 +- src/plugins/scxmleditor/common/colorsettings.cpp | 2 +- .../scxmleditor/common/colorthemedialog.cpp | 2 +- .../scxmleditor/common/navigatorslider.cpp | 2 +- src/plugins/scxmleditor/common/search.cpp | 2 +- src/plugins/scxmleditor/common/shapestoolbox.cpp | 2 +- src/plugins/scxmleditor/common/stateview.cpp | 2 +- src/plugins/scxmleditor/common/statistics.cpp | 2 +- .../scxmleditor/common/statisticsdialog.cpp | 2 +- src/plugins/squish/deletesymbolicnamedialog.cpp | 2 +- src/plugins/squish/objectsmapeditorwidget.cpp | 2 +- src/plugins/squish/opensquishsuitesdialog.cpp | 2 +- src/plugins/squish/squishfilehandler.cpp | 2 +- src/plugins/texteditor/behaviorsettingswidget.cpp | 2 +- .../texteditor/codestyleselectorwidget.cpp | 2 +- src/plugins/texteditor/colorschemeedit.cpp | 2 +- src/plugins/texteditor/displaysettingspage.cpp | 2 +- .../texteditor/snippets/snippetssettingspage.cpp | 2 +- src/plugins/texteditor/tabsettingswidget.cpp | 2 +- src/plugins/todo/keyworddialog.cpp | 2 +- src/plugins/todo/optionsdialog.cpp | 2 +- src/plugins/todo/todoprojectsettingswidget.cpp | 2 +- src/plugins/updateinfo/settingspage.cpp | 2 +- src/plugins/valgrind/valgrindsettings.h | 2 +- src/plugins/vcpkg/vcpkgsearch.cpp | 2 +- src/plugins/vcpkg/vcpkgsettings.cpp | 2 +- .../webassemblyrunconfigurationaspects.h | 2 +- src/shared/help/bookmarkmanager.cpp | 2 +- src/shared/help/topicchooser.cpp | 2 +- .../qtcreatorcrashhandler/crashhandlerdialog.cpp | 2 +- tests/manual/tasktree/taskwidget.h | 4 ++-- .../tst_manual_widgets_layoutbuilder.cpp | 2 +- 127 files changed, 154 insertions(+), 149 deletions(-) diff --git a/src/libs/advanceddockingsystem/workspacedialog.cpp b/src/libs/advanceddockingsystem/workspacedialog.cpp index e4f92d92bae..e99ec6946ac 100644 --- a/src/libs/advanceddockingsystem/workspacedialog.cpp +++ b/src/libs/advanceddockingsystem/workspacedialog.cpp @@ -79,7 +79,7 @@ WorkspaceNameInputDialog::WorkspaceNameInputDialog(DockManager *manager, QWidget connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); - using namespace Utils::Layouting; + using namespace Layouting; Column { label, @@ -137,7 +137,7 @@ WorkspaceDialog::WorkspaceDialog(DockManager *manager, QWidget *parent) connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp index 8242d8dac60..8fd9e7b5efc 100644 --- a/src/libs/extensionsystem/plugindetailsview.cpp +++ b/src/libs/extensionsystem/plugindetailsview.cpp @@ -53,7 +53,7 @@ public: , license(createTextEdit()) , dependencies(new QListWidget(q)) { - using namespace Utils::Layouting; + using namespace Layouting; // clang-format off Form { diff --git a/src/libs/extensionsystem/pluginerroroverview.cpp b/src/libs/extensionsystem/pluginerroroverview.cpp index 20e6f5ac900..69562e504df 100644 --- a/src/libs/extensionsystem/pluginerroroverview.cpp +++ b/src/libs/extensionsystem/pluginerroroverview.cpp @@ -42,7 +42,7 @@ PluginErrorOverview::PluginErrorOverview(QWidget *parent) QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - using namespace Utils::Layouting; + using namespace Layouting; auto createLabel = [this](const QString &text) { QLabel *label = new QLabel(text, this); diff --git a/src/libs/extensionsystem/pluginerrorview.cpp b/src/libs/extensionsystem/pluginerrorview.cpp index fac7fd9a427..42374b03768 100644 --- a/src/libs/extensionsystem/pluginerrorview.cpp +++ b/src/libs/extensionsystem/pluginerrorview.cpp @@ -41,7 +41,7 @@ public: errorString->setTabChangesFocus(true); errorString->setReadOnly(true); - using namespace Utils::Layouting; + using namespace Layouting; Form { Tr::tr("State:"), state, br, diff --git a/src/libs/qmleditorwidgets/contextpanetextwidget.cpp b/src/libs/qmleditorwidgets/contextpanetextwidget.cpp index 1a7d5272948..a7f9e31f02e 100644 --- a/src/libs/qmleditorwidgets/contextpanetextwidget.cpp +++ b/src/libs/qmleditorwidgets/contextpanetextwidget.cpp @@ -80,7 +80,7 @@ ContextPaneTextWidget::ContextPaneTextWidget(QWidget *parent) : vAlignButtons->addButton(m_centerVAlignmentButton); vAlignButtons->addButton(m_bottomAlignmentButton); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { m_fontComboBox, m_colorButton, m_fontSizeSpinBox, }, Row { diff --git a/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp b/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp index f4ba3a6a5c0..12ec4da3d51 100644 --- a/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp +++ b/src/libs/qmleditorwidgets/contextpanewidgetimage.cpp @@ -97,7 +97,7 @@ ContextPaneWidgetImage::ContextPaneWidgetImage(QWidget *parent, bool borderImage vRadioButtons->addButton(m_borderImage.verticalStretchRadioButton); vRadioButtons->addButton(m_borderImage.verticalTileRadioButtonNoCrop); - using namespace Utils::Layouting; + using namespace Layouting; Row { Column { m_previewLabel, m_sizeLabel, }, Column { @@ -146,7 +146,7 @@ ContextPaneWidgetImage::ContextPaneWidgetImage(QWidget *parent, bool borderImage m_image.cropAspectFitRadioButton = radioButton("aspect-crop-icon", Tr::tr("The image is scaled uniformly to fill, cropping if necessary.")); - using namespace Utils::Layouting; + using namespace Layouting; Row { Column { m_previewLabel, m_sizeLabel, }, Column { diff --git a/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp b/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp index 52afeff187c..0a8c1242e57 100644 --- a/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp +++ b/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp @@ -56,7 +56,7 @@ ContextPaneWidgetRectangle::ContextPaneWidgetRectangle(QWidget *parent) borderButtons->addButton(m_borderSolid); borderButtons->addButton(m_borderNone); - using namespace Utils::Layouting; + using namespace Layouting; Grid { m_gradientLabel, m_gradientLine, br, Tr::tr("Color"), Row { m_colorColorButton, m_colorSolid, m_colorGradient, m_colorNone, st, }, br, diff --git a/src/libs/qmleditorwidgets/easingpane/easingcontextpane.cpp b/src/libs/qmleditorwidgets/easingpane/easingcontextpane.cpp index e61f3c2592c..c35f6d792c0 100644 --- a/src/libs/qmleditorwidgets/easingpane/easingcontextpane.cpp +++ b/src/libs/qmleditorwidgets/easingpane/easingcontextpane.cpp @@ -145,7 +145,7 @@ EasingContextPane::EasingContextPane(QWidget *parent) spinBox->setMaximum(999999.9); } - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { m_graphicsView, m_playButton, }, Row { diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 28de4dd4cab..ea4a2f1848a 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -30,7 +30,7 @@ #include #include -using namespace Utils::Layouting; +using namespace Layouting; namespace Utils { namespace Internal { diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 1e58c737736..81a67eb5d5d 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -21,16 +21,16 @@ class QGroupBox; class QSettings; QT_END_NAMESPACE -namespace Utils { - -class AspectContainer; -class BoolAspect; - namespace Layouting { class LayoutBuilder; class LayoutItem; } // Layouting +namespace Utils { + +class AspectContainer; +class BoolAspect; + namespace Internal { class AspectContainerPrivate; class BaseAspectPrivate; diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 99b726ec4ce..12eb4003b97 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -16,7 +16,7 @@ #include #include -namespace Utils::Layouting { +namespace Layouting { /*! \enum Utils::LayoutBuilder::LayoutType @@ -464,7 +464,7 @@ TabWidget::TabWidget(QTabWidget *tabWidget, std::initializer_list tabs) // "Properties" -LayoutItem::Setter title(const QString &title, BoolAspect *checker) +LayoutItem::Setter title(const QString &title, Utils::BoolAspect *checker) { return [title, checker](QObject *target) { if (auto groupBox = qobject_cast(target)) { @@ -528,4 +528,4 @@ Stretch st; Space empty(0); HorizontalRule hr; -} // Utils::Layouting +} // Layouting diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 76106ffc76d..74b4ff3e0a7 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -3,14 +3,19 @@ #pragma once -#include "utils_global.h" - #include #include #include +#include #include +#if defined(UTILS_LIBRARY) +# define QTCREATOR_UTILS_EXPORT Q_DECL_EXPORT +#else +# define QTCREATOR_UTILS_EXPORT Q_DECL_IMPORT +#endif + QT_BEGIN_NAMESPACE class QLayout; class QSplitter; @@ -20,7 +25,7 @@ QT_END_NAMESPACE namespace Utils { class BoolAspect; } -namespace Utils::Layouting { +namespace Layouting { enum AttachType { WithMargins, @@ -180,7 +185,7 @@ QTCREATOR_UTILS_EXPORT extern HorizontalRule hr; // "Properties" QTCREATOR_UTILS_EXPORT LayoutItem::Setter title(const QString &title, - BoolAspect *checker = nullptr); + Utils::BoolAspect *checker = nullptr); QTCREATOR_UTILS_EXPORT LayoutItem::Setter text(const QString &text); QTCREATOR_UTILS_EXPORT LayoutItem::Setter tooltip(const QString &toolTip); @@ -289,4 +294,4 @@ public: Stack(std::initializer_list items) : LayoutBuilder(StackLayout, items) {} }; -} // Utils::Layouting +} // Layouting diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index 5de02b84801..69ad17d43f2 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -125,7 +125,7 @@ CTestSettingsPage::CTestSettingsPage(CTestSettings *settings, Utils::Id settings setLayouter([settings](QWidget *widget) { CTestSettings &s = *settings; - using namespace Utils::Layouting; + using namespace Layouting; Form form { Row {s.outputOnFail}, br, diff --git a/src/plugins/bazaar/bazaarcommitwidget.cpp b/src/plugins/bazaar/bazaarcommitwidget.cpp index 79d0b56b5a2..34cf2bb7ac4 100644 --- a/src/plugins/bazaar/bazaarcommitwidget.cpp +++ b/src/plugins/bazaar/bazaarcommitwidget.cpp @@ -49,7 +49,7 @@ public: emailLineEdit = new QLineEdit; fixedBugsLineEdit = new QLineEdit; - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(Tr::tr("General Information")), diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index a0f980606d0..964f5241b39 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -286,7 +286,7 @@ public: dryRunBtn->setToolTip(Tr::tr("Test the outcome of removing the last committed revision, without actually removing anything.")); buttonBox->addButton(dryRunBtn, QDialogButtonBox::ApplyRole); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { keepTagsCheckBox, br, diff --git a/src/plugins/bazaar/pullorpushdialog.cpp b/src/plugins/bazaar/pullorpushdialog.cpp index 10a4ce0452a..4c2cd99e7c5 100644 --- a/src/plugins/bazaar/pullorpushdialog.cpp +++ b/src/plugins/bazaar/pullorpushdialog.cpp @@ -72,7 +72,7 @@ PullOrPushDialog::PullOrPushDialog(Mode mode, QWidget *parent) m_localCheckBox->setVisible(false); } - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(Tr::tr("Branch Location")), diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp index 0c0735be0ed..9d2741209ed 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp @@ -84,7 +84,7 @@ ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSett Tr::tr(Constants::ARTISTICSTYLE_DISPLAY_NAME))); m_command->setFilePath(m_settings->command()); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_useOtherFiles, diff --git a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp b/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp index 9423aa54a82..fd79826846a 100644 --- a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp +++ b/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp @@ -86,7 +86,7 @@ ClangFormatOptionsPageWidget::ClangFormatOptionsPageWidget(ClangFormatSettings * else useCustomizedStyle->setChecked(true); - using namespace Utils::Layouting; + using namespace Layouting; Form { m_usePredefinedStyle, m_predefinedStyle, br, diff --git a/src/plugins/beautifier/configurationdialog.cpp b/src/plugins/beautifier/configurationdialog.cpp index 8b2c61e7204..09e8c595f30 100644 --- a/src/plugins/beautifier/configurationdialog.cpp +++ b/src/plugins/beautifier/configurationdialog.cpp @@ -40,7 +40,7 @@ ConfigurationDialog::ConfigurationDialog(QWidget *parent) m_buttonBox->setOrientation(Qt::Horizontal); m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { diff --git a/src/plugins/beautifier/configurationpanel.cpp b/src/plugins/beautifier/configurationpanel.cpp index 6aa0f5b2d9f..5e40c55f2b2 100644 --- a/src/plugins/beautifier/configurationpanel.cpp +++ b/src/plugins/beautifier/configurationpanel.cpp @@ -26,7 +26,7 @@ ConfigurationPanel::ConfigurationPanel(QWidget *parent) m_remove = new QPushButton(Tr::tr("Remove")); auto add = new QPushButton(Tr::tr("Add")); - using namespace Utils::Layouting; + using namespace Layouting; Row { m_configurations, diff --git a/src/plugins/beautifier/generaloptionspage.cpp b/src/plugins/beautifier/generaloptionspage.cpp index 859f323e244..be10d126fbb 100644 --- a/src/plugins/beautifier/generaloptionspage.cpp +++ b/src/plugins/beautifier/generaloptionspage.cpp @@ -60,7 +60,7 @@ GeneralOptionsPageWidget::GeneralOptionsPageWidget(const QStringList &toolIds) const int index = m_autoFormatTool->findText(settings->autoFormatTool()); m_autoFormatTool->setCurrentIndex(qMax(index, 0)); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { diff --git a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp index 2102dd311f8..433f52506b5 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp @@ -86,7 +86,7 @@ UncrustifyOptionsPageWidget::UncrustifyOptionsPageWidget(UncrustifySettings *set auto options = new QGroupBox(Tr::tr("Options")); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_useOtherFiles, diff --git a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp index 5fe14872591..4db61677223 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp @@ -68,7 +68,7 @@ ClangToolsProjectSettingsWidget::ClangToolsProjectSettingsWidget(ProjectExplorer m_removeSelectedButton = new QPushButton(Tr::tr("Remove Selected"), this); m_removeAllButton = new QPushButton(Tr::tr("Remove All")); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { m_restoreGlobal, st, gotoClangTidyModeLabel, gotoClazyModeLabel }, diff --git a/src/plugins/clangtools/filterdialog.cpp b/src/plugins/clangtools/filterdialog.cpp index 4c59b44b554..bcb81346d03 100644 --- a/src/plugins/clangtools/filterdialog.cpp +++ b/src/plugins/clangtools/filterdialog.cpp @@ -86,7 +86,7 @@ FilterDialog::FilterDialog(const Checks &checks, QWidget *parent) m_view->setSelectionBehavior(QAbstractItemView::SelectRows); m_view->setIndentation(0); - using namespace Utils::Layouting; + using namespace Layouting; Column { Tr::tr("Select the diagnostics to display."), diff --git a/src/plugins/clearcase/checkoutdialog.cpp b/src/plugins/clearcase/checkoutdialog.cpp index 8c3a5b82041..df8c43a4e1a 100644 --- a/src/plugins/clearcase/checkoutdialog.cpp +++ b/src/plugins/clearcase/checkoutdialog.cpp @@ -48,7 +48,7 @@ CheckOutDialog::CheckOutDialog(const QString &fileName, bool isUcm, bool showCom auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; Column { lblFileName, @@ -67,7 +67,7 @@ CheckOutDialog::CheckOutDialog(const QString &fileName, bool isUcm, bool showCom m_actSelector = new ActivitySelector(this); m_verticalLayout->insertWidget(0, m_actSelector); - m_verticalLayout->insertWidget(1, Utils::Layouting::createHr()); + m_verticalLayout->insertWidget(1, Layouting::createHr()); } if (!showComment) diff --git a/src/plugins/clearcase/clearcasesubmiteditorwidget.cpp b/src/plugins/clearcase/clearcasesubmiteditorwidget.cpp index 44c3fd1b44c..8708e566f3b 100644 --- a/src/plugins/clearcase/clearcasesubmiteditorwidget.cpp +++ b/src/plugins/clearcase/clearcasesubmiteditorwidget.cpp @@ -69,7 +69,7 @@ void ClearCaseSubmitEditorWidget::addActivitySelector(bool isUcm) m_actSelector = new ActivitySelector; m_verticalLayout->insertWidget(0, m_actSelector); - m_verticalLayout->insertWidget(1, Utils::Layouting::createHr()); + m_verticalLayout->insertWidget(1, Layouting::createHr()); } QString ClearCaseSubmitEditorWidget::commitName() const diff --git a/src/plugins/clearcase/versionselector.cpp b/src/plugins/clearcase/versionselector.cpp index 2c0d46a6a30..4d3dd16059f 100644 --- a/src/plugins/clearcase/versionselector.cpp +++ b/src/plugins/clearcase/versionselector.cpp @@ -51,7 +51,7 @@ VersionSelector::VersionSelector(const QString &fileName, const QString &message "the changes (not supported by the plugin)") + "

"); - using namespace Utils::Layouting; + using namespace Layouting; Column { headerLabel, diff --git a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp b/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp index a82e7be07af..8fe970404e9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp @@ -59,7 +59,7 @@ CMakeFormatterOptionsPageWidget::CMakeFormatterOptionsPageWidget() m_command->setPromptDialogTitle(Tr::tr("%1 Command").arg(Tr::tr("Formatter"))); m_command->setFilePath(settings->command()); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 971b4c87445..46222ed76ae 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -49,7 +49,7 @@ using namespace ProjectExplorer; using namespace Utils; -using namespace Utils::Layouting; +using namespace Layouting; namespace CMakeProjectManager { diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp index da59bc06c64..ed2870e85e1 100644 --- a/src/plugins/copilot/authwidget.cpp +++ b/src/plugins/copilot/authwidget.cpp @@ -22,7 +22,7 @@ namespace Copilot { AuthWidget::AuthWidget(QWidget *parent) : QWidget(parent) { - using namespace Utils::Layouting; + using namespace Layouting; m_button = new QPushButton(Tr::tr("Sign in")); m_button->setEnabled(false); diff --git a/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp b/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp index 7750cfcc17d..bb98305910e 100644 --- a/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp @@ -22,7 +22,7 @@ AddToVcsDialog::AddToVcsDialog(QWidget *parent, const QString &vcsDisplayName) : QDialog(parent) { - using namespace Utils::Layouting; + using namespace Layouting; resize(363, 375); setMinimumSize({200, 200}); diff --git a/src/plugins/coreplugin/dialogs/openwithdialog.cpp b/src/plugins/coreplugin/dialogs/openwithdialog.cpp index ddec97928bf..ff8db72ddbf 100644 --- a/src/plugins/coreplugin/dialogs/openwithdialog.cpp +++ b/src/plugins/coreplugin/dialogs/openwithdialog.cpp @@ -25,7 +25,7 @@ OpenWithDialog::OpenWithDialog(const Utils::FilePath &filePath, QWidget *parent) buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); - using namespace Utils::Layouting; + using namespace Layouting; // clang-format off Column { Tr::tr("Open file \"%1\" with:").arg(filePath.fileName()), diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp index 87953b3ab92..3b9034ddd71 100644 --- a/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp @@ -59,7 +59,7 @@ SaveItemsDialog::SaveItemsDialog(QWidget *parent, const QList &item m_saveBeforeBuildCheckBox->setVisible(false); - using namespace Utils::Layouting; + using namespace Layouting; // clang-format off Column { m_msgLabel, diff --git a/src/plugins/coreplugin/mimetypemagicdialog.cpp b/src/plugins/coreplugin/mimetypemagicdialog.cpp index 475cc57dd34..2a55539bf76 100644 --- a/src/plugins/coreplugin/mimetypemagicdialog.cpp +++ b/src/plugins/coreplugin/mimetypemagicdialog.cpp @@ -78,7 +78,7 @@ MimeTypeMagicDialog::MimeTypeMagicDialog(QWidget *parent) : auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { diff --git a/src/plugins/cpaster/pasteselectdialog.cpp b/src/plugins/cpaster/pasteselectdialog.cpp index 5b4c164c3b1..2df87e71370 100644 --- a/src/plugins/cpaster/pasteselectdialog.cpp +++ b/src/plugins/cpaster/pasteselectdialog.cpp @@ -54,7 +54,7 @@ PasteSelectDialog::PasteSelectDialog(const QList &protocols, QWidget listFont.setStyleHint(QFont::TypeWriter); m_listWidget->setFont(listFont); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { Tr::tr("Protocol:"), m_protocolBox, br, diff --git a/src/plugins/cpaster/pasteview.cpp b/src/plugins/cpaster/pasteview.cpp index 02ae0f65305..c575fa582b7 100644 --- a/src/plugins/cpaster/pasteview.cpp +++ b/src/plugins/cpaster/pasteview.cpp @@ -100,7 +100,7 @@ PasteView::PasteView(const QList &protocols, m_uiPatchList->setSortingEnabled(false); m_uiPatchList->setSortingEnabled(__sortingEnabled); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_uiPatchList, diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp index 8b9cba0d630..9d5137b9389 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp @@ -1484,7 +1484,7 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) Column { Form { QString("Sn&apshot:"), m_snapshotSelector }, m_snapshotView, - }.emerge(Utils::Layouting::WithoutMargins), + }.emerge(Layouting::WithoutMargins), m_docTab, }, } diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 570bd144bd1..00224f5d90b 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -103,7 +103,7 @@ CppCodeModelSettingsWidget::CppCodeModelSettingsWidget(CppCodeModelSettings *s) m_ignorePchCheckBox->setChecked(m_settings->pchUsage() == CppCodeModelSettings::PchUse_None); m_useBuiltinPreprocessorCheckBox->setChecked(m_settings->useBuiltinPreprocessor()); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { @@ -401,7 +401,7 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD else Core::EditorManager::openEditor(Utils::FilePath::fromString(link)); }); - layout->addWidget(Utils::Layouting::createHr()); + layout->addWidget(Layouting::createHr()); layout->addWidget(configFilesHelpLabel); layout->addStretch(1); diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index ebb4a37485d..aa7279aeb81 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -175,7 +175,7 @@ public: QObject::connect(m_tabSettingsWidget, &TabSettingsWidget::settingsChanged, q, &CppCodeStylePreferencesWidget::slotTabSettingsChanged); - using namespace Utils::Layouting; + using namespace Layouting; const Group contentGroup { title(Tr::tr("Indent")), diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index f01ef74aa99..be11fd2be4a 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -30,7 +30,7 @@ public: void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index f3d01a1cc37..7002437fb2f 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -60,7 +60,7 @@ public: } private: - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override + void addToLayout(Layouting::LayoutBuilder &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); diff --git a/src/plugins/designer/cpp/newclasswidget.cpp b/src/plugins/designer/cpp/newclasswidget.cpp index b659854777b..e6b24e55617 100644 --- a/src/plugins/designer/cpp/newclasswidget.cpp +++ b/src/plugins/designer/cpp/newclasswidget.cpp @@ -66,7 +66,7 @@ NewClassWidget::NewClassWidget(QWidget *parent) : setNamesDelimiter(QLatin1String("::")); - using namespace Utils::Layouting; + using namespace Layouting; Form { Tr::tr("&Class name:"), d->m_classLineEdit, br, Tr::tr("&Header file:"), d->m_headerFileLineEdit, br, diff --git a/src/plugins/fossil/configuredialog.cpp b/src/plugins/fossil/configuredialog.cpp index 69c74ad8c84..e5b6c8f3e77 100644 --- a/src/plugins/fossil/configuredialog.cpp +++ b/src/plugins/fossil/configuredialog.cpp @@ -67,7 +67,7 @@ ConfigureDialog::ConfigureDialog(QWidget *parent) : QDialog(parent), connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(Tr::tr("Repository User")), diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 0840841416b..8d771eeee19 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -1094,7 +1094,7 @@ RevertDialog::RevertDialog(const QString &title, QWidget *parent) connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - using namespace Utils::Layouting; + using namespace Layouting; Form { Tr::tr("Revision"), m_revisionLineEdit, br, }.attachTo(groupBox); diff --git a/src/plugins/fossil/pullorpushdialog.cpp b/src/plugins/fossil/pullorpushdialog.cpp index 05bdf136f18..cd72f2bd01b 100644 --- a/src/plugins/fossil/pullorpushdialog.cpp +++ b/src/plugins/fossil/pullorpushdialog.cpp @@ -52,7 +52,7 @@ PullOrPushDialog::PullOrPushDialog(Mode mode, QWidget *parent) connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(Tr::tr("Remote Location")), diff --git a/src/plugins/git/branchadddialog.cpp b/src/plugins/git/branchadddialog.cpp index 3dfd7ad946d..011a01ea1e1 100644 --- a/src/plugins/git/branchadddialog.cpp +++ b/src/plugins/git/branchadddialog.cpp @@ -125,7 +125,7 @@ BranchAddDialog::BranchAddDialog(const QStringList &localBranches, Type type, QW break; } - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { branchNameLabel, m_branchNameEdit }, diff --git a/src/plugins/git/branchcheckoutdialog.cpp b/src/plugins/git/branchcheckoutdialog.cpp index 9fa2e83a0b4..9615c28ff68 100644 --- a/src/plugins/git/branchcheckoutdialog.cpp +++ b/src/plugins/git/branchcheckoutdialog.cpp @@ -45,7 +45,7 @@ BranchCheckoutDialog::BranchCheckoutDialog(QWidget *parent, auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_makeStashRadioButton, diff --git a/src/plugins/git/gerrit/gerritpushdialog.cpp b/src/plugins/git/gerrit/gerritpushdialog.cpp index fa45e2591f8..87961c5945a 100644 --- a/src/plugins/git/gerrit/gerritpushdialog.cpp +++ b/src/plugins/git/gerrit/gerritpushdialog.cpp @@ -136,7 +136,7 @@ GerritPushDialog::GerritPushDialog(const Utils::FilePath &workingDir, const QStr connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - using namespace Utils::Layouting; + using namespace Layouting; Grid { ::Git::Tr::tr("Push:"), workingDir.toUserOutput(), m_localBranchComboBox, br, diff --git a/src/plugins/gitlab/gitlaboptionspage.cpp b/src/plugins/gitlab/gitlaboptionspage.cpp index 6fb05063118..447b9111a83 100644 --- a/src/plugins/gitlab/gitlaboptionspage.cpp +++ b/src/plugins/gitlab/gitlaboptionspage.cpp @@ -181,7 +181,7 @@ GitLabOptionsWidget::GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParamete m_add = new QPushButton(Tr::tr("Add..."), this); m_add->setToolTip(Tr::tr("Add new GitLab server configuration.")); - using namespace Utils::Layouting; + using namespace Layouting; Grid { Form { diff --git a/src/plugins/incredibuild/commandbuilderaspect.h b/src/plugins/incredibuild/commandbuilderaspect.h index 7c6d04c93b6..c880fa7d529 100644 --- a/src/plugins/incredibuild/commandbuilderaspect.h +++ b/src/plugins/incredibuild/commandbuilderaspect.h @@ -23,7 +23,7 @@ public: QString fullCommandFlag(bool keepJobNum) const; private: - void addToLayout(Utils::Layouting::LayoutBuilder &builder) final; + void addToLayout(Layouting::LayoutBuilder &builder) final; void fromMap(const QVariantMap &map) final; void toMap(QVariantMap &map) const final; diff --git a/src/plugins/ios/createsimulatordialog.cpp b/src/plugins/ios/createsimulatordialog.cpp index 3eb4c2cc40d..d042529c555 100644 --- a/src/plugins/ios/createsimulatordialog.cpp +++ b/src/plugins/ios/createsimulatordialog.cpp @@ -32,7 +32,7 @@ CreateSimulatorDialog::CreateSimulatorDialog(QWidget *parent) auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { diff --git a/src/plugins/ios/iosrunconfiguration.h b/src/plugins/ios/iosrunconfiguration.h index 161b0703c54..d348dd61cab 100644 --- a/src/plugins/ios/iosrunconfiguration.h +++ b/src/plugins/ios/iosrunconfiguration.h @@ -27,7 +27,7 @@ public: void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; IosDeviceType deviceType() const; void setDeviceType(const IosDeviceType &deviceType); diff --git a/src/plugins/ios/iossettingswidget.cpp b/src/plugins/ios/iossettingswidget.cpp index 2d13c4952ab..81a2cb5db62 100644 --- a/src/plugins/ios/iossettingswidget.cpp +++ b/src/plugins/ios/iossettingswidget.cpp @@ -94,7 +94,7 @@ IosSettingsWidget::IosSettingsWidget() m_pathWidget->addButton(Tr::tr("Screenshot"), this, std::bind(&IosSettingsWidget::onScreenshot, this)); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(Tr::tr("Devices")), diff --git a/src/plugins/ios/simulatoroperationdialog.cpp b/src/plugins/ios/simulatoroperationdialog.cpp index 56e2d3b69fe..180b28d76e4 100644 --- a/src/plugins/ios/simulatoroperationdialog.cpp +++ b/src/plugins/ios/simulatoroperationdialog.cpp @@ -40,7 +40,7 @@ SimulatorOperationDialog::SimulatorOperationDialog(QWidget *parent) : m_formatter = new Utils::OutputFormatter; m_formatter->setPlainTextEdit(messageEdit); - using namespace Utils::Layouting; + using namespace Layouting; Column { messageEdit, diff --git a/src/plugins/macros/macrooptionswidget.cpp b/src/plugins/macros/macrooptionswidget.cpp index c6a94d44980..cd11ab64ef3 100644 --- a/src/plugins/macros/macrooptionswidget.cpp +++ b/src/plugins/macros/macrooptionswidget.cpp @@ -49,7 +49,7 @@ MacroOptionsWidget::MacroOptionsWidget() m_macroGroup = new QGroupBox(Tr::tr("Macro"), this); - using namespace Utils::Layouting; + using namespace Layouting; Row { Tr::tr("Description:"), m_description diff --git a/src/plugins/mcusupport/mcukitinformation.cpp b/src/plugins/mcusupport/mcukitinformation.cpp index 801b7cdeccb..0b156e1ab47 100644 --- a/src/plugins/mcusupport/mcukitinformation.cpp +++ b/src/plugins/mcusupport/mcukitinformation.cpp @@ -22,7 +22,7 @@ public: void makeReadOnly() override {} void refresh() override {} - void addToLayout(Utils::Layouting::LayoutBuilder &) override {} + void addToLayout(Layouting::LayoutBuilder &) override {} }; } // anonymous namespace diff --git a/src/plugins/mercurial/authenticationdialog.cpp b/src/plugins/mercurial/authenticationdialog.cpp index 8538fd2812c..d9d552274d0 100644 --- a/src/plugins/mercurial/authenticationdialog.cpp +++ b/src/plugins/mercurial/authenticationdialog.cpp @@ -24,7 +24,7 @@ AuthenticationDialog::AuthenticationDialog(const QString &username, const QStrin auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { diff --git a/src/plugins/mercurial/mercurialcommitwidget.cpp b/src/plugins/mercurial/mercurialcommitwidget.cpp index 7fcd3339307..0f57581aed0 100644 --- a/src/plugins/mercurial/mercurialcommitwidget.cpp +++ b/src/plugins/mercurial/mercurialcommitwidget.cpp @@ -101,7 +101,7 @@ public: m_authorLineEdit = new QLineEdit; m_emailLineEdit = new QLineEdit; - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { @@ -120,7 +120,7 @@ public: }, } } - }.attachTo(this, Utils::Layouting::WithoutMargins); + }.attachTo(this, Layouting::WithoutMargins); } QLabel *m_repositoryLabel; diff --git a/src/plugins/mesonprojectmanager/settings.cpp b/src/plugins/mesonprojectmanager/settings.cpp index b26e09f29b6..6a211a375a7 100644 --- a/src/plugins/mesonprojectmanager/settings.cpp +++ b/src/plugins/mesonprojectmanager/settings.cpp @@ -45,7 +45,7 @@ GeneralSettingsPage::GeneralSettingsPage() setLayouter([](QWidget *widget) { Settings &s = *Settings::instance(); - using namespace Utils::Layouting; + using namespace Layouting; Column { s.autorunMeson, diff --git a/src/plugins/mesonprojectmanager/toolkitaspectwidget.h b/src/plugins/mesonprojectmanager/toolkitaspectwidget.h index b403afd0578..beb9440add0 100644 --- a/src/plugins/mesonprojectmanager/toolkitaspectwidget.h +++ b/src/plugins/mesonprojectmanager/toolkitaspectwidget.h @@ -36,7 +36,7 @@ private: void makeReadOnly() override { m_toolsComboBox->setEnabled(false); } - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override + void addToLayout(Layouting::LayoutBuilder &builder) override { addMutableAction(m_toolsComboBox); builder.addItem(m_toolsComboBox); diff --git a/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp b/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp index beefeb56ace..7d13950b672 100644 --- a/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp +++ b/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp @@ -37,7 +37,7 @@ NimCodeStylePreferencesWidget::NimCodeStylePreferencesWidget(ICodeStylePreferenc m_previewTextEdit = new SnippetEditorWidget; m_previewTextEdit->setPlainText(Nim::Constants::C_NIMCODESTYLEPREVIEWSNIPPET); - using namespace Utils::Layouting; + using namespace Layouting; Row { Column { tabPreferencesWidget, diff --git a/src/plugins/perforce/changenumberdialog.cpp b/src/plugins/perforce/changenumberdialog.cpp index b5a0aa27870..5ba8dcced07 100644 --- a/src/plugins/perforce/changenumberdialog.cpp +++ b/src/plugins/perforce/changenumberdialog.cpp @@ -27,7 +27,7 @@ ChangeNumberDialog::ChangeNumberDialog(QWidget *parent) connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { Tr::tr("Change number:"), m_lineEdit }, diff --git a/src/plugins/perforce/pendingchangesdialog.cpp b/src/plugins/perforce/pendingchangesdialog.cpp index 589d17b276e..84b10a8a072 100644 --- a/src/plugins/perforce/pendingchangesdialog.cpp +++ b/src/plugins/perforce/pendingchangesdialog.cpp @@ -48,7 +48,7 @@ PendingChangesDialog::PendingChangesDialog(const QString &data, QWidget *parent) submitButton->setEnabled(false); } - using namespace Utils::Layouting; + using namespace Layouting; Column { m_listWidget, diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index f276431ab5e..1a2e2c346ad 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -41,7 +41,7 @@ PerfTracePointDialog::PerfTracePointDialog() m_privilegesChooser->addItems({ELEVATE_METHOD_NA, ELEVATE_METHOD_PKEXEC, ELEVATE_METHOD_SUDO}); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_label, m_textEdit, diff --git a/src/plugins/projectexplorer/buildaspects.h b/src/plugins/projectexplorer/buildaspects.h index 9788cc69cad..968642f11f8 100644 --- a/src/plugins/projectexplorer/buildaspects.h +++ b/src/plugins/projectexplorer/buildaspects.h @@ -23,7 +23,7 @@ public: bool isShadowBuild() const; void setProblem(const QString &description); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; static Utils::FilePath fixupDir(const Utils::FilePath &dir); diff --git a/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp b/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp index 2ff0285a61b..85cd9772625 100644 --- a/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp @@ -48,7 +48,7 @@ CodeStyleSettingsWidget::CodeStyleSettingsWidget(Project *project) connect(languageComboBox, &QComboBox::currentIndexChanged, stackedWidget, &QStackedWidget::setCurrentIndex); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { new QLabel(Tr::tr("Language:")), languageComboBox, st }, diff --git a/src/plugins/projectexplorer/customparserconfigdialog.cpp b/src/plugins/projectexplorer/customparserconfigdialog.cpp index 4ebc880c140..cbfd1adfbc7 100644 --- a/src/plugins/projectexplorer/customparserconfigdialog.cpp +++ b/src/plugins/projectexplorer/customparserconfigdialog.cpp @@ -101,7 +101,7 @@ CustomParserConfigDialog::CustomParserConfigDialog(QWidget *parent) auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; auto tabWarning = new QWidget; Column { diff --git a/src/plugins/projectexplorer/devicesupport/devicefactoryselectiondialog.cpp b/src/plugins/projectexplorer/devicesupport/devicefactoryselectiondialog.cpp index ed47999432b..987f2e0c39b 100644 --- a/src/plugins/projectexplorer/devicesupport/devicefactoryselectiondialog.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicefactoryselectiondialog.cpp @@ -24,7 +24,7 @@ DeviceFactorySelectionDialog::DeviceFactorySelectionDialog(QWidget *parent) : m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); m_buttonBox->button(QDialogButtonBox::Ok)->setText(Tr::tr("Start Wizard")); - using namespace Utils::Layouting; + using namespace Layouting; Column { Tr::tr("Available device types:"), m_listWidget, diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index f51a0607bd1..9094c992106 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -143,7 +143,7 @@ void DeviceSettingsWidget::initGui() scrollArea->setWidgetResizable(true); scrollArea->setWidget(scrollAreaWidget); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_generalGroupBox, m_osSpecificGroupBox, diff --git a/src/plugins/projectexplorer/devicesupport/devicetestdialog.cpp b/src/plugins/projectexplorer/devicesupport/devicetestdialog.cpp index 91a83531b49..0277fc827a0 100644 --- a/src/plugins/projectexplorer/devicesupport/devicetestdialog.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicetestdialog.cpp @@ -43,7 +43,7 @@ DeviceTestDialog::DeviceTestDialog(const IDevice::Ptr &deviceConfiguration, d->textEdit->setReadOnly(true); d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel); - using namespace Utils::Layouting; + using namespace Layouting; Column { d->textEdit, d->buttonBox, diff --git a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp index 52450b2bc89..c32912f7444 100644 --- a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp @@ -48,7 +48,7 @@ EditorSettingsWidget::EditorSettingsWidget(Project *project) : m_project(project m_behaviorSettings = new TextEditor::BehaviorSettingsWidget(this); - using namespace Utils::Layouting; + using namespace Layouting; Row { m_showWrapColumn, diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index 9acfa27e69c..52eae5f9b86 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -34,7 +34,7 @@ #include using namespace Utils; -using namespace Utils::Layouting; +using namespace Layouting; namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.cpp b/src/plugins/projectexplorer/projectexplorersettingspage.cpp index 30eb850cd0c..5a00e272b21 100644 --- a/src/plugins/projectexplorer/projectexplorersettingspage.cpp +++ b/src/plugins/projectexplorer/projectexplorersettingspage.cpp @@ -117,7 +117,7 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget(QWidget *parent) : "Disable it if you experience problems with your builds."); jomLabel->setWordWrap(true); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(Tr::tr("Projects Directory")), diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp index b13bde370bc..83fd4d2cba8 100644 --- a/src/plugins/projectexplorer/projectwizardpage.cpp +++ b/src/plugins/projectexplorer/projectwizardpage.cpp @@ -288,7 +288,7 @@ ProjectWizardPage::ProjectWizardPage(QWidget *parent) scrollArea->setWidgetResizable(true); scrollArea->setWidget(m_filesLabel); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { m_projectLabel, m_projectComboBox, br, diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index c64fa4431aa..c1fceb613c1 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -33,7 +33,7 @@ #include using namespace Utils; -using namespace Utils::Layouting; +using namespace Layouting; namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index 9656c2f5bdb..0a7d4b54fbd 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -29,7 +29,7 @@ class PROJECTEXPLORER_EXPORT TerminalAspect : public Utils::BaseAspect public: TerminalAspect(); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; bool useTerminal() const; void setUseTerminalHint(bool useTerminal); @@ -62,7 +62,7 @@ public: explicit WorkingDirectoryAspect(const Utils::MacroExpander *expander, EnvironmentAspect *envAspect); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; Utils::FilePath workingDirectory() const; Utils::FilePath defaultWorkingDirectory() const; @@ -91,7 +91,7 @@ class PROJECTEXPLORER_EXPORT ArgumentsAspect : public Utils::BaseAspect public: explicit ArgumentsAspect(const Utils::MacroExpander *macroExpander); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; QString arguments() const; QString unexpandedArguments() const; @@ -163,7 +163,7 @@ public: void setSettingsKey(const QString &key); void makeOverridable(const QString &overridingKey, const QString &useOverridableKey); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; void setLabelText(const QString &labelText); void setPlaceHolderText(const QString &placeHolderText); void setHistoryCompleter(const QString &historyCompleterKey); @@ -235,7 +235,7 @@ public: void fromMap(const QVariantMap &) override; void toMap(QVariantMap &) const override; - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; struct Data : Utils::BaseAspect::Data { Interpreter interpreter; }; diff --git a/src/plugins/projectexplorer/sessiondialog.cpp b/src/plugins/projectexplorer/sessiondialog.cpp index 745a876230a..336da285a45 100644 --- a/src/plugins/projectexplorer/sessiondialog.cpp +++ b/src/plugins/projectexplorer/sessiondialog.cpp @@ -77,7 +77,7 @@ SessionNameInputDialog::SessionNameInputDialog(QWidget *parent) m_usedSwitchTo = true; }); - using namespace Utils::Layouting; + using namespace Layouting; Column { Tr::tr("Enter the name of the session:"), m_newSessionLineEdit, @@ -150,7 +150,7 @@ SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent) "What is a Session?")); whatsASessionLabel->setOpenExternalLinks(true); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { diff --git a/src/plugins/python/pythonwizardpage.cpp b/src/plugins/python/pythonwizardpage.cpp index b13cf3c346d..0f0d907f621 100644 --- a/src/plugins/python/pythonwizardpage.cpp +++ b/src/plugins/python/pythonwizardpage.cpp @@ -85,7 +85,7 @@ bool PythonWizardPageFactory::validateData(Id typeId, const QVariant &data, QStr PythonWizardPage::PythonWizardPage(const QList> &pySideAndData, const int defaultPyside) { - using namespace Utils::Layouting; + using namespace Layouting; m_interpreter.setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID); connect(PythonSettings::instance(), &PythonSettings::interpretersChanged, diff --git a/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp b/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp index 4f3d88907ad..78e0634bc5f 100644 --- a/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp +++ b/src/plugins/qbsprojectmanager/customqbspropertiesdialog.cpp @@ -43,7 +43,7 @@ CustomQbsPropertiesDialog::CustomQbsPropertiesDialog(const QVariantMap &properti m_removeButton = new QPushButton(Tr::tr("&Remove")); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { m_propertiesTable, diff --git a/src/plugins/qbsprojectmanager/qbskitinformation.cpp b/src/plugins/qbsprojectmanager/qbskitinformation.cpp index 8bdd801261b..800765bb368 100644 --- a/src/plugins/qbsprojectmanager/qbskitinformation.cpp +++ b/src/plugins/qbsprojectmanager/qbskitinformation.cpp @@ -35,7 +35,7 @@ private: void makeReadOnly() override { m_changeButton->setEnabled(false); } void refresh() override { m_contentLabel->setText(QbsKitAspect::representation(kit())); } - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override + void addToLayout(Layouting::LayoutBuilder &builder) override { addMutableAction(m_contentLabel); builder.addItem(m_contentLabel); diff --git a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp index 4062f6bb705..fb048f94751 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilessettingspage.cpp @@ -120,7 +120,7 @@ QbsProfilesSettingsWidget::QbsProfilesSettingsWidget() m_profileValueLabel = new QLabel; m_propertiesView = new QTreeView; - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { Tr::tr("Kit:"), m_kitsComboBox, br, diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp index 05c7c25d78d..22958e08197 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/classdefinition.cpp @@ -21,7 +21,7 @@ ClassDefinition::ClassDefinition(QWidget *parent) : QTabWidget(parent), m_domXmlChanged(false) { - using namespace Utils::Layouting; + using namespace Layouting; // "Sources" tab auto sourceTab = new QWidget; diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp index 851f07ce71d..d0885dfc839 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp @@ -34,7 +34,7 @@ CustomWidgetPluginWizardPage::CustomWidgetPluginWizardPage(QWidget *parent) : m_pluginNameEdit = new QLineEdit; m_resourceFileEdit = new QLineEdit(Tr::tr("icons.qrc")); - using namespace Utils::Layouting; + using namespace Layouting; Column { Tr::tr("Specify the properties of the plugin library and the collection class."), Space(10), diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp index 8265f0a8b47..20fe10ac13e 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp @@ -39,7 +39,7 @@ CustomWidgetWidgetsWizardPage::CustomWidgetWidgetsWizardPage(QWidget *parent) : dummy->setEnabled(false); m_tabStackLayout->addWidget(dummy); - using namespace Utils::Layouting; + using namespace Layouting; Column { Tr::tr("Specify the list of custom widgets and their properties."), Space(10), diff --git a/src/plugins/qmldesigner/openuiqmlfiledialog.cpp b/src/plugins/qmldesigner/openuiqmlfiledialog.cpp index 6c1dcf132c0..eacb81aa000 100644 --- a/src/plugins/qmldesigner/openuiqmlfiledialog.cpp +++ b/src/plugins/qmldesigner/openuiqmlfiledialog.cpp @@ -30,7 +30,7 @@ OpenUiQmlFileDialog::OpenUiQmlFileDialog(QWidget *parent) : m_listWidget = new QListWidget; - using namespace Utils::Layouting; + using namespace Layouting; Column { tr("You are opening a .qml file in the designer. Do you want to open a .ui.qml file instead?"), diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 6acb2284217..873811ee28b 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -196,7 +196,7 @@ SettingsPageWidget::SettingsPageWidget(ExternalDependencies &externalDependencie m_debugPuppetComboBox = new QComboBox; - using namespace Utils::Layouting; + using namespace Layouting; Column { m_useDefaultPuppetRadioButton, diff --git a/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp b/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp index ad370633bdd..91bcc0ac89d 100644 --- a/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp +++ b/src/plugins/qmljseditor/qmljscomponentnamedialog.cpp @@ -34,7 +34,7 @@ ComponentNameDialog::ComponentNameDialog(QWidget *parent) : m_checkBox = new QCheckBox(Tr::tr("ui.qml file")); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { Tr::tr("Component name:"), m_componentNameEdit, br, diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 91ec37fcd65..8d168d440a4 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -246,7 +246,7 @@ public: QObject::connect(useQmlls, &QCheckBox::stateChanged, this, [this](int checked) { useLatestQmlls->setEnabled(checked != Qt::Unchecked); }); - using namespace Utils::Layouting; + using namespace Layouting; // clang-format off const auto formattingGroup = Group { diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index 09ea4191a3f..4a9f26b7105 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -46,7 +46,7 @@ QmlJSCodeStylePreferencesWidget::QmlJSCodeStylePreferencesWidget( decorateEditor(TextEditorSettings::fontSettings()); - using namespace Utils::Layouting; + using namespace Layouting; Row { Column { m_tabPreferencesWidget, diff --git a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp index 455ffcd0f80..a732ddc0324 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp @@ -19,7 +19,7 @@ QmlJSCodeStyleSettingsWidget::QmlJSCodeStyleSettingsWidget(QWidget *parent) m_lineLengthSpinBox->setMinimum(0); m_lineLengthSpinBox->setMaximum(999); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(Tr::tr("Qml JS Code Style")), diff --git a/src/plugins/qmlprojectmanager/qmlmainfileaspect.h b/src/plugins/qmlprojectmanager/qmlmainfileaspect.h index b71fa6784b8..24ffcf94c6e 100644 --- a/src/plugins/qmlprojectmanager/qmlmainfileaspect.h +++ b/src/plugins/qmlprojectmanager/qmlmainfileaspect.h @@ -42,7 +42,7 @@ public: Utils::FilePath currentFile; }; - void addToLayout(Utils::Layouting::LayoutBuilder &builder) final; + void addToLayout(Layouting::LayoutBuilder &builder) final; void toMap(QVariantMap &map) const final; void fromMap(const QVariantMap &map) final; diff --git a/src/plugins/qtsupport/codegensettingspage.cpp b/src/plugins/qtsupport/codegensettingspage.cpp index 8e0a3cfca08..99d6a6976ca 100644 --- a/src/plugins/qtsupport/codegensettingspage.cpp +++ b/src/plugins/qtsupport/codegensettingspage.cpp @@ -44,7 +44,7 @@ CodeGenSettingsPageWidget::CodeGenSettingsPageWidget() CodeGenSettings parameters; parameters.fromSettings(Core::ICore::settings()); - using namespace Utils::Layouting; + using namespace Layouting; m_ptrAggregationRadioButton = new QRadioButton(Tr::tr("Aggregation as a pointer member")); m_ptrAggregationRadioButton->setChecked diff --git a/src/plugins/qtsupport/qtbuildaspects.h b/src/plugins/qtsupport/qtbuildaspects.h index e66fe9bbceb..8ba97afdbba 100644 --- a/src/plugins/qtsupport/qtbuildaspects.h +++ b/src/plugins/qtsupport/qtbuildaspects.h @@ -18,7 +18,7 @@ class QTSUPPORT_EXPORT QmlDebuggingAspect : public Utils::TriStateAspect public: explicit QmlDebuggingAspect(ProjectExplorer::BuildConfiguration *buildConfig); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; private: const ProjectExplorer::BuildConfiguration *m_buildConfig = nullptr; @@ -32,7 +32,7 @@ public: QtQuickCompilerAspect(ProjectExplorer::BuildConfiguration *buildConfig); private: - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; const ProjectExplorer::BuildConfiguration *m_buildConfig = nullptr; }; diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 25a9f5f3a78..618f322a6a7 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -261,7 +261,7 @@ QtOptionsPageWidget::QtOptionsPageWidget() m_errorLabel = new QLabel; - using namespace Utils::Layouting; + using namespace Layouting; auto versionInfoWidget = new QWidget; // clang-format off diff --git a/src/plugins/resourceeditor/qrceditor/qrceditor.cpp b/src/plugins/resourceeditor/qrceditor/qrceditor.cpp index 86679c52b74..e08f52340fd 100644 --- a/src/plugins/resourceeditor/qrceditor/qrceditor.cpp +++ b/src/plugins/resourceeditor/qrceditor/qrceditor.cpp @@ -43,7 +43,7 @@ QrcEditor::QrcEditor(RelativeResourceModel *model, QWidget *parent) m_languageLabel = new QLabel(Tr::tr("Language:")); m_languageText = new QLineEdit; - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { addPrefixButton, diff --git a/src/plugins/scxmleditor/common/colorpicker.cpp b/src/plugins/scxmleditor/common/colorpicker.cpp index 04e415224bf..32c3f6d6c46 100644 --- a/src/plugins/scxmleditor/common/colorpicker.cpp +++ b/src/plugins/scxmleditor/common/colorpicker.cpp @@ -34,7 +34,7 @@ ColorPicker::ColorPicker(const QString &key, QWidget *parent) m_lastUsedColorContainer = new QHBoxLayout(lastUsedColorContainer); m_lastUsedColorContainer->setContentsMargins(0, 0, 0, 0); - using namespace Utils::Layouting; + using namespace Layouting; Grid colorGrid; for (int i = 0; i < colors.count(); ++i) { QWidget *button = createButton(colors[i]); diff --git a/src/plugins/scxmleditor/common/colorsettings.cpp b/src/plugins/scxmleditor/common/colorsettings.cpp index c2ad9f22ce2..22761b7f02b 100644 --- a/src/plugins/scxmleditor/common/colorsettings.cpp +++ b/src/plugins/scxmleditor/common/colorsettings.cpp @@ -36,7 +36,7 @@ ColorSettings::ColorSettings(QWidget *parent) s->value(Constants::C_SETTINGS_COLORSETTINGS_CURRENTCOLORTHEME).toString()); selectTheme(m_comboColorThemes->currentIndex()); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { m_comboColorThemes, diff --git a/src/plugins/scxmleditor/common/colorthemedialog.cpp b/src/plugins/scxmleditor/common/colorthemedialog.cpp index 00f224d1f98..2f2b209b779 100644 --- a/src/plugins/scxmleditor/common/colorthemedialog.cpp +++ b/src/plugins/scxmleditor/common/colorthemedialog.cpp @@ -21,7 +21,7 @@ ColorThemeDialog::ColorThemeDialog(QWidget *parent) QDialogButtonBox::Cancel | QDialogButtonBox::Apply); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_colorSettings, buttonBox, diff --git a/src/plugins/scxmleditor/common/navigatorslider.cpp b/src/plugins/scxmleditor/common/navigatorslider.cpp index 5f3fc345e1f..68d74dd1bed 100644 --- a/src/plugins/scxmleditor/common/navigatorslider.cpp +++ b/src/plugins/scxmleditor/common/navigatorslider.cpp @@ -29,7 +29,7 @@ NavigatorSlider::NavigatorSlider(QWidget *parent) btn->setAutoRepeatInterval(10); } - using namespace Utils::Layouting; + using namespace Layouting; Row { zoomOut, m_slider, diff --git a/src/plugins/scxmleditor/common/search.cpp b/src/plugins/scxmleditor/common/search.cpp index acfc5cda131..34f26017333 100644 --- a/src/plugins/scxmleditor/common/search.cpp +++ b/src/plugins/scxmleditor/common/search.cpp @@ -45,7 +45,7 @@ Search::Search(QWidget *parent) m_searchView->setModel(m_proxyModel); m_searchView->setFrameShape(QFrame::NoFrame); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_searchEdit, m_searchView, diff --git a/src/plugins/scxmleditor/common/shapestoolbox.cpp b/src/plugins/scxmleditor/common/shapestoolbox.cpp index 988c762c347..1343859cc62 100644 --- a/src/plugins/scxmleditor/common/shapestoolbox.cpp +++ b/src/plugins/scxmleditor/common/shapestoolbox.cpp @@ -29,7 +29,7 @@ ShapesToolbox::ShapesToolbox(QWidget *parent) m_shapeGroupsLayout->setContentsMargins(0, 0, 0, 0); m_shapeGroupsLayout->setSpacing(0); - using namespace Utils::Layouting; + using namespace Layouting; Column { scrollArea, }.setSpacing(0).attachTo(this, WithoutMargins); diff --git a/src/plugins/scxmleditor/common/stateview.cpp b/src/plugins/scxmleditor/common/stateview.cpp index 1ee99034417..57759263fd4 100644 --- a/src/plugins/scxmleditor/common/stateview.cpp +++ b/src/plugins/scxmleditor/common/stateview.cpp @@ -31,7 +31,7 @@ StateView::StateView(StateItem *state, QWidget *parent) m_graphicsView = new GraphicsView; - using namespace Utils::Layouting; + using namespace Layouting; Row { PushButton{ text("Back"), onClicked([this] { closeView(); }, this) }, stateNameLabel, diff --git a/src/plugins/scxmleditor/common/statistics.cpp b/src/plugins/scxmleditor/common/statistics.cpp index 06c62f70b2a..ff1811eadd4 100644 --- a/src/plugins/scxmleditor/common/statistics.cpp +++ b/src/plugins/scxmleditor/common/statistics.cpp @@ -135,7 +135,7 @@ Statistics::Statistics(QWidget *parent) m_statisticsView->setAlternatingRowColors(true); m_statisticsView->setSortingEnabled(true); - using namespace Utils::Layouting; + using namespace Layouting; Grid { Tr::tr("File"), m_fileNameLabel, br, Tr::tr("Time"), m_timeLabel, br, diff --git a/src/plugins/scxmleditor/common/statisticsdialog.cpp b/src/plugins/scxmleditor/common/statisticsdialog.cpp index 7cfb6cd4637..d9a20dd81de 100644 --- a/src/plugins/scxmleditor/common/statisticsdialog.cpp +++ b/src/plugins/scxmleditor/common/statisticsdialog.cpp @@ -21,7 +21,7 @@ StatisticsDialog::StatisticsDialog(QWidget *parent) m_statistics = new Statistics; auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_statistics, buttonBox, diff --git a/src/plugins/squish/deletesymbolicnamedialog.cpp b/src/plugins/squish/deletesymbolicnamedialog.cpp index 44a3b507d58..dbb6804fb5a 100644 --- a/src/plugins/squish/deletesymbolicnamedialog.cpp +++ b/src/plugins/squish/deletesymbolicnamedialog.cpp @@ -63,7 +63,7 @@ DeleteSymbolicNameDialog::DeleteSymbolicNameDialog(const QString &symbolicName, updateDetailsLabel(symbolicName); populateSymbolicNamesList(names); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_detailsLabel, diff --git a/src/plugins/squish/objectsmapeditorwidget.cpp b/src/plugins/squish/objectsmapeditorwidget.cpp index 7e215d0d77f..e689a5a2962 100644 --- a/src/plugins/squish/objectsmapeditorwidget.cpp +++ b/src/plugins/squish/objectsmapeditorwidget.cpp @@ -88,7 +88,7 @@ void ObjectsMapEditorWidget::initUi() m_stackedLayout->addWidget(validPropertiesWidget); m_stackedLayout->addWidget(invalidPropertiesWidget); - using namespace Utils::Layouting; + using namespace Layouting; Row { m_propertiesTree, diff --git a/src/plugins/squish/opensquishsuitesdialog.cpp b/src/plugins/squish/opensquishsuitesdialog.cpp index f36d402dcab..c32e9d0a39b 100644 --- a/src/plugins/squish/opensquishsuitesdialog.cpp +++ b/src/plugins/squish/opensquishsuitesdialog.cpp @@ -40,7 +40,7 @@ OpenSquishSuitesDialog::OpenSquishSuitesDialog(QWidget *parent) m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Open); m_buttonBox->button(QDialogButtonBox::Open)->setEnabled(false); - using namespace Utils::Layouting; + using namespace Layouting; Column { new QLabel(Tr::tr("Base directory:")), diff --git a/src/plugins/squish/squishfilehandler.cpp b/src/plugins/squish/squishfilehandler.cpp index 918120a4063..6e48c917b86 100644 --- a/src/plugins/squish/squishfilehandler.cpp +++ b/src/plugins/squish/squishfilehandler.cpp @@ -53,7 +53,7 @@ public: QWidget *widget = new QWidget(this); auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - using namespace Utils::Layouting; + using namespace Layouting; Form { label, &aut, br, arguments, diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index 518f09c8a57..3f7255219f2 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -165,7 +165,7 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) d->groupBoxMouse = new QGroupBox(Tr::tr("Mouse and Keyboard")); - using namespace Utils::Layouting; + using namespace Layouting; const auto indent = [](QWidget *inner) { return Row { Space(30), inner }; }; diff --git a/src/plugins/texteditor/codestyleselectorwidget.cpp b/src/plugins/texteditor/codestyleselectorwidget.cpp index 56b8ca4c055..e1090078da5 100644 --- a/src/plugins/texteditor/codestyleselectorwidget.cpp +++ b/src/plugins/texteditor/codestyleselectorwidget.cpp @@ -48,7 +48,7 @@ CodeStyleSelectorWidget::CodeStyleSelectorWidget(ICodeStylePreferencesFactory *f m_importButton = new QPushButton(Tr::tr("Import...")); m_importButton->setEnabled(false); - using namespace Utils::Layouting; + using namespace Layouting; Column { Grid { diff --git a/src/plugins/texteditor/colorschemeedit.cpp b/src/plugins/texteditor/colorschemeedit.cpp index bd4c5b97ae4..96e7c3a2ad5 100644 --- a/src/plugins/texteditor/colorschemeedit.cpp +++ b/src/plugins/texteditor/colorschemeedit.cpp @@ -202,7 +202,7 @@ ColorSchemeEdit::ColorSchemeEdit(QWidget *parent) : auto bottomSpacer = new QWidget; bottomSpacer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding); - using namespace Utils::Layouting; + using namespace Layouting; Row { m_itemList, diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index 58f9e04068d..49927710bba 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -113,7 +113,7 @@ public: displayAnnotations = new QGroupBox(Tr::tr("Line annotations")), displayAnnotations->setCheckable(true); - using namespace Utils::Layouting; + using namespace Layouting; Column { leftAligned, diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.cpp b/src/plugins/texteditor/snippets/snippetssettingspage.cpp index a9a337a70f3..e4bfdf7df84 100644 --- a/src/plugins/texteditor/snippets/snippetssettingspage.cpp +++ b/src/plugins/texteditor/snippets/snippetssettingspage.cpp @@ -310,7 +310,7 @@ SnippetsSettingsWidget::SnippetsSettingsWidget() snippetSplitter->addWidget(m_snippetsTable); snippetSplitter->addWidget(m_snippetsEditorStack); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { Tr::tr("Group:"), m_groupCombo, st }, Row { diff --git a/src/plugins/texteditor/tabsettingswidget.cpp b/src/plugins/texteditor/tabsettingswidget.cpp index f55d8d6f441..d8096102488 100644 --- a/src/plugins/texteditor/tabsettingswidget.cpp +++ b/src/plugins/texteditor/tabsettingswidget.cpp @@ -87,7 +87,7 @@ TabSettingsWidget::TabSettingsWidget(QWidget *parent) : tabSizeLabel->setBuddy(m_tabSize); indentSizeLabel->setBuddy(m_indentSize); - using namespace Utils::Layouting; + using namespace Layouting; const auto indent = [](QWidget *inner) { return Row { Space(30), inner }; }; Column { diff --git a/src/plugins/todo/keyworddialog.cpp b/src/plugins/todo/keyworddialog.cpp index 0f92091a1f5..cebeb7b692f 100644 --- a/src/plugins/todo/keyworddialog.cpp +++ b/src/plugins/todo/keyworddialog.cpp @@ -47,7 +47,7 @@ KeywordDialog::KeywordDialog(const Keyword &keyword, const QSet &alread m_buttonBox->setOrientation(Qt::Horizontal); m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - using namespace Utils::Layouting; + using namespace Layouting; Column { new QLabel(Tr::tr("Icon")), diff --git a/src/plugins/todo/optionsdialog.cpp b/src/plugins/todo/optionsdialog.cpp index f536ca51edb..3b300a7d10c 100644 --- a/src/plugins/todo/optionsdialog.cpp +++ b/src/plugins/todo/optionsdialog.cpp @@ -73,7 +73,7 @@ OptionsDialog::OptionsDialog(Settings *settings, const std::function &o m_scanInSubprojectRadioButton = new QRadioButton(Tr::tr("Scan the current subproject")); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { diff --git a/src/plugins/todo/todoprojectsettingswidget.cpp b/src/plugins/todo/todoprojectsettingswidget.cpp index 0d0e0d732a4..6f68ccc37ba 100644 --- a/src/plugins/todo/todoprojectsettingswidget.cpp +++ b/src/plugins/todo/todoprojectsettingswidget.cpp @@ -32,7 +32,7 @@ TodoProjectSettingsWidget::TodoProjectSettingsWidget(ProjectExplorer::Project *p auto addExcludedPatternButton = new QPushButton(Tr::tr("Add")); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { diff --git a/src/plugins/updateinfo/settingspage.cpp b/src/plugins/updateinfo/settingspage.cpp index 587102bce75..18d070092e7 100644 --- a/src/plugins/updateinfo/settingspage.cpp +++ b/src/plugins/updateinfo/settingspage.cpp @@ -45,7 +45,7 @@ public: m_nextCheckDateLabel = new QLabel; m_checkForNewQtVersions = new QCheckBox(Tr::tr("Check for new Qt versions")); - using namespace Utils::Layouting; + using namespace Layouting; Column { m_infoLabel, diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h index 22952d0978d..d2a4bed606e 100644 --- a/src/plugins/valgrind/valgrindsettings.h +++ b/src/plugins/valgrind/valgrindsettings.h @@ -23,7 +23,7 @@ public: Utils::FilePaths value() const; void setValue(const Utils::FilePaths &val); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) final; + void addToLayout(Layouting::LayoutBuilder &builder) final; void fromMap(const QVariantMap &map) final; void toMap(QVariantMap &map) const final; diff --git a/src/plugins/vcpkg/vcpkgsearch.cpp b/src/plugins/vcpkg/vcpkgsearch.cpp index dc3fe7a0c6c..a2ec2c66c28 100644 --- a/src/plugins/vcpkg/vcpkgsearch.cpp +++ b/src/plugins/vcpkg/vcpkgsearch.cpp @@ -76,7 +76,7 @@ VcpkgPackageSearchDialog::VcpkgPackageSearchDialog(QWidget *parent) m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { Column { diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp index bea6c8ed6c7..9900f54afdb 100644 --- a/src/plugins/vcpkg/vcpkgsettings.cpp +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -54,7 +54,7 @@ VcpkgSettingsPage::VcpkgSettingsPage() websiteButton->setIcon(Utils::Icons::ONLINE.icon()); websiteButton->setToolTip(Constants::WEBSITE_URL); - using namespace Utils::Layouting; + using namespace Layouting; Column { Group { title(tr("Vcpkg installation")), diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.h b/src/plugins/webassembly/webassemblyrunconfigurationaspects.h index 1d713274edc..8b0d5128825 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.h +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.h @@ -20,7 +20,7 @@ class WebBrowserSelectionAspect : public Utils::BaseAspect public: WebBrowserSelectionAspect(ProjectExplorer::Target *target); - void addToLayout(Utils::Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutBuilder &builder) override; void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; diff --git a/src/shared/help/bookmarkmanager.cpp b/src/shared/help/bookmarkmanager.cpp index 6a3ed6e14ea..72bd5db3214 100644 --- a/src/shared/help/bookmarkmanager.cpp +++ b/src/shared/help/bookmarkmanager.cpp @@ -75,7 +75,7 @@ BookmarkDialog::BookmarkDialog(BookmarkManager *manager, const QString &title, m_newFolderButton = new QPushButton(::Help::Tr::tr("New Folder")); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - using namespace Utils::Layouting; + using namespace Layouting; Column { Form { ::Help::Tr::tr("Bookmark:"), m_bookmarkEdit, br, diff --git a/src/shared/help/topicchooser.cpp b/src/shared/help/topicchooser.cpp index efa3705b14b..93a4bf47be9 100644 --- a/src/shared/help/topicchooser.cpp +++ b/src/shared/help/topicchooser.cpp @@ -52,7 +52,7 @@ TopicChooser::TopicChooser(QWidget *parent, const QString &keyword, auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - using namespace Utils::Layouting; + using namespace Layouting; Column { ::Help::Tr::tr("Choose a topic for %1:").arg(keyword), m_lineEdit, diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp index ff1d503a6e6..acbc3fa28f7 100644 --- a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp @@ -161,7 +161,7 @@ public: QCoreApplication::quit(); }); - using namespace Utils::Layouting; + using namespace Layouting; Column { Row { m_iconLabel, m_introLabel, st }, diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasktree/taskwidget.h index 8dbaded738a..8caebf658b2 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasktree/taskwidget.h @@ -80,7 +80,7 @@ class TaskGroup { public: QWidget *group; - Utils::Layouting::Column items; + Layouting::Column items; }; -void doLayout(const TaskGroup &taskGroup, Utils::Layouting::LayoutBuilder &builder); +void doLayout(const TaskGroup &taskGroup, Layouting::LayoutBuilder &builder); diff --git a/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp b/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp index 4f6bf710b2f..03a1cbc4bef 100644 --- a/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp +++ b/tests/manual/widgets/layoutbuilder/tst_manual_widgets_layoutbuilder.cpp @@ -7,7 +7,7 @@ #include #include -using namespace Utils::Layouting; +using namespace Layouting; int main(int argc, char *argv[]) { From fde32a206ba06f6025a77beb3ce6b7a4ce9c663d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 20:12:57 +0200 Subject: [PATCH 0689/1447] LineNumberFilter: Reimplement matchers() Change-Id: I5c4905aabaee81c7870994ca9019e451a7c23119 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/texteditor/linenumberfilter.cpp | 45 +++++++++++++++++++++ src/plugins/texteditor/linenumberfilter.h | 1 + 2 files changed, 46 insertions(+) diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index b22c73bfd8b..1a7003877ee 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -6,6 +6,7 @@ #include "texteditortr.h" #include +#include using namespace Core; using namespace Utils; @@ -24,6 +25,50 @@ LineNumberFilter::LineNumberFilter(QObject *parent) setDefaultIncludedByDefault(true); } +LocatorMatcherTasks LineNumberFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [=] { + const QStringList lineAndColumn = storage->input().split(':'); + int sectionCount = lineAndColumn.size(); + int line = 0; + int column = 0; + bool ok = false; + if (sectionCount > 0) + line = lineAndColumn.at(0).toInt(&ok); + if (ok && sectionCount > 1) + column = lineAndColumn.at(1).toInt(&ok); + if (!ok) + return true; + if (EditorManager::currentEditor() && (line > 0 || column > 0)) { + QString text; + if (line > 0 && column > 0) + text = Tr::tr("Line %1, Column %2").arg(line).arg(column); + else if (line > 0) + text = Tr::tr("Line %1").arg(line); + else + text = Tr::tr("Column %1").arg(column); + LocatorFilterEntry entry; + entry.displayName = text; + entry.acceptor = [line, targetColumn = column - 1] { + IEditor *editor = EditorManager::currentEditor(); + if (!editor) + return AcceptResult(); + EditorManager::addCurrentPositionToNavigationHistory(); + editor->gotoLine(line < 1 ? editor->currentLine() : line, targetColumn); + EditorManager::activateEditor(editor); + return AcceptResult(); + }; + storage->reportOutput({entry}); + } + return true; + }; + return {{Sync(onSetup), storage}}; +} + void LineNumberFilter::prepareSearch(const QString &entry) { Q_UNUSED(entry) diff --git a/src/plugins/texteditor/linenumberfilter.h b/src/plugins/texteditor/linenumberfilter.h index 70d2c1b6f01..5717da176dd 100644 --- a/src/plugins/texteditor/linenumberfilter.h +++ b/src/plugins/texteditor/linenumberfilter.h @@ -21,6 +21,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final; bool m_hasCurrentEditor = false; }; From c67dc5e8d483010b5a0cf5d35096fb0f366119c1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 15:32:10 +0200 Subject: [PATCH 0690/1447] All Plugins: Use global future synchronizer Instead of using plugin's own synchronizers. The global synchronizer does the synchronization just before all the plugins' destructors run (in sync), so this should be the right equivalent. Change-Id: I8d09c9ea4a11b7a703684ad5319191ce310d992e Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 6 ------ src/plugins/coreplugin/coreplugin.h | 3 --- .../coreplugin/locator/filesystemfilter.cpp | 5 +++-- .../coreplugin/locator/ilocatorfilter.cpp | 5 +++-- .../coreplugin/locator/opendocumentsfilter.cpp | 5 +++-- src/plugins/cppeditor/cppeditorplugin.cpp | 8 -------- src/plugins/cppeditor/cppeditorplugin.h | 6 +----- src/plugins/cppeditor/cpplocatorfilter.cpp | 6 ++++-- src/plugins/diffeditor/diffeditorplugin.cpp | 16 +++++----------- src/plugins/diffeditor/diffeditorplugin.h | 4 ---- .../diffeditor/sidebysidediffeditorwidget.cpp | 5 +++-- .../diffeditor/unifieddiffeditorwidget.cpp | 5 +++-- src/plugins/help/helpindexfilter.cpp | 2 +- src/plugins/help/helpplugin.cpp | 8 -------- src/plugins/help/helpplugin.h | 3 --- .../languageclient/languageclientplugin.cpp | 6 ------ .../languageclient/languageclientplugin.h | 4 ---- src/plugins/languageclient/locatorfilter.cpp | 7 ++++--- src/plugins/projectexplorer/extracompiler.cpp | 10 +++------- src/plugins/projectexplorer/extracompiler.h | 6 +----- src/plugins/python/pythonplugin.cpp | 8 -------- src/plugins/python/pythonplugin.h | 3 --- src/plugins/python/pythonrunconfiguration.cpp | 5 +++-- .../vcsbase/vcsbasediffeditorcontroller.cpp | 5 +++-- src/plugins/vcsbase/vcsplugin.cpp | 8 -------- src/plugins/vcsbase/vcsplugin.h | 4 ---- 26 files changed, 40 insertions(+), 113 deletions(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 83f21201678..043bdba74d1 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -313,12 +313,6 @@ QObject *CorePlugin::remoteCommand(const QStringList & /* options */, return res; } -FutureSynchronizer *CorePlugin::futureSynchronizer() -{ - QTC_ASSERT(m_instance, return nullptr); - return &m_instance->m_futureSynchronizer; -} - Environment CorePlugin::startupSystemEnvironment() { return m_instance->m_startupSystemEnvironment; diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index b415ba146e3..3f535be8a65 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -8,7 +8,6 @@ #include #include -#include QT_BEGIN_NAMESPACE class QMenu; @@ -47,7 +46,6 @@ public: const QString &workingDirectory, const QStringList &args) override; - static Utils::FutureSynchronizer *futureSynchronizer(); static Utils::Environment startupSystemEnvironment(); static Utils::EnvironmentItems environmentChanges(); static void setEnvironmentChanges(const Utils::EnvironmentItems &changes); @@ -79,7 +77,6 @@ private: FolderNavigationWidgetFactory *m_folderNavigationWidgetFactory = nullptr; Utils::Environment m_startupSystemEnvironment; Utils::EnvironmentItems m_environmentChanges; - Utils::FutureSynchronizer m_futureSynchronizer; }; } // namespace Internal diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 75bbcba1511..8facb0304a8 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -3,13 +3,14 @@ #include "filesystemfilter.h" -#include "../coreplugin.h" #include "../coreplugintr.h" #include "../documentmanager.h" #include "../editormanager/editormanager.h" #include "../icore.h" #include "../vcsmanager.h" +#include + #include #include #include @@ -273,7 +274,7 @@ LocatorMatcherTasks FileSystemFilter::matchers() TreeStorage storage; const auto onSetup = [this, storage](AsyncTask &async) { - async.setFutureSynchronizer(CorePlugin::futureSynchronizer()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matches, *storage, shortcutString(), diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 58b4024639d..7a6e761b2a5 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -3,9 +3,10 @@ #include "ilocatorfilter.h" -#include "../coreplugin.h" #include "../coreplugintr.h" +#include + #include #include #include @@ -273,7 +274,7 @@ ResultsCollector::~ResultsCollector() return; m_deduplicator->cancel(); - Internal::CorePlugin::futureSynchronizer()->addFuture(m_watcher->future()); + ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(m_watcher->future()); } void ResultsCollector::setFilterCount(int count) diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 4a510ad83f7..9cfccb8ca67 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -3,9 +3,10 @@ #include "opendocumentsfilter.h" -#include "../coreplugin.h" #include "../coreplugintr.h" +#include + #include #include #include @@ -81,7 +82,7 @@ LocatorMatcherTasks OpenDocumentsFilter::matchers() const auto onSetup = [storage](AsyncTask &async) { const QList editorsData = Utils::transform(DocumentModel::entries(), [](const DocumentModel::Entry *e) { return Entry{e->filePath(), e->displayName()}; }); - async.setFutureSynchronizer(CorePlugin::futureSynchronizer()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matchEditors, *storage, editorsData); }; diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 53d6ef55bda..2d4cabe726e 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -85,7 +85,6 @@ #include #include #include -#include #include #include #include @@ -199,7 +198,6 @@ public: ClangdSettingsPage *m_clangdSettingsPage = nullptr; CppCodeStyleSettingsPage m_cppCodeStyleSettingsPage; CppProjectUpdaterFactory m_cppProjectUpdaterFactory; - FutureSynchronizer m_futureSynchronizer; }; static CppEditorPlugin *m_instance = nullptr; @@ -633,12 +631,6 @@ bool CppEditorPlugin::usePragmaOnce() return m_instance->d->m_fileSettings.headerPragmaOnce; } -FutureSynchronizer *CppEditorPlugin::futureSynchronizer() -{ - QTC_ASSERT(m_instance, return nullptr); - return &m_instance->d->m_futureSynchronizer; -} - const QStringList &CppEditorPlugin::headerSearchPaths() { return m_instance->d->m_fileSettings.headerSearchPaths; diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index b24bc927f65..c28ee16b1e1 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -5,10 +5,7 @@ #include -namespace Utils { -class FilePath; -class FutureSynchronizer; -} +namespace Utils { class FilePath; } namespace CppEditor { class CppCodeModelSettings; @@ -40,7 +37,6 @@ public: static Utils::FilePath licenseTemplatePath(); static QString licenseTemplate(); static bool usePragmaOnce(); - static Utils::FutureSynchronizer *futureSynchronizer(); void openDeclarationDefinitionInNextSplit(); void openTypeHierarchy(); diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 6ec6602f62e..c13948bb3e9 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include #include #include @@ -107,7 +109,7 @@ LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex TreeStorage storage; const auto onSetup = [=](AsyncTask &async) { - async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matchesFor, *storage, type, converter); }; return {Async(onSetup), storage}; @@ -303,7 +305,7 @@ LocatorMatcherTask currentDocumentMatcher() TreeStorage storage; const auto onSetup = [=](AsyncTask &async) { - async.setFutureSynchronizer(Internal::CppEditorPlugin::futureSynchronizer()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matchesForCurrentDocument, *storage, currentFileName()); }; return {Async(onSetup), storage}; diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 6ae5f816c30..eed5a6d0e4a 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -13,12 +13,13 @@ #include #include +#include + #include #include #include #include -#include #include #include @@ -114,8 +115,9 @@ DiffFilesController::DiffFilesController(IDocument *document) QList> *outputList = storage.activeStorage(); const auto setupDiff = [this](AsyncTask &async, const ReloadInput &reloadInput) { - async.setConcurrentCallData(DiffFile(ignoreWhitespace(), contextLineCount()), reloadInput); - async.setFutureSynchronizer(Internal::DiffEditorPlugin::futureSynchronizer()); + async.setConcurrentCallData( + DiffFile(ignoreWhitespace(), contextLineCount()), reloadInput); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); }; const auto onDiffDone = [outputList](const AsyncTask &async, int i) { if (async.isResultAvailable()) @@ -415,12 +417,10 @@ public: DiffEditorFactory m_editorFactory; DiffEditorServiceImpl m_service; - FutureSynchronizer m_futureSynchronizer; }; DiffEditorPluginPrivate::DiffEditorPluginPrivate() { - m_futureSynchronizer.setCancelOnWait(true); //register actions ActionContainer *toolsContainer = ActionManager::actionContainer(Core::Constants::M_TOOLS); toolsContainer->insertGroup(Core::Constants::G_TOOLS_DEBUG, Constants::G_TOOLS_DIFF); @@ -535,12 +535,6 @@ void DiffEditorPlugin::initialize() d = new DiffEditorPluginPrivate; } -FutureSynchronizer *DiffEditorPlugin::futureSynchronizer() -{ - QTC_ASSERT(s_instance, return nullptr); - return &s_instance->d->m_futureSynchronizer; -} - } // namespace Internal } // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffeditorplugin.h b/src/plugins/diffeditor/diffeditorplugin.h index 66849a7387e..17b6a2d430d 100644 --- a/src/plugins/diffeditor/diffeditorplugin.h +++ b/src/plugins/diffeditor/diffeditorplugin.h @@ -6,8 +6,6 @@ #include #include -namespace Utils { class FutureSynchronizer; } - namespace DiffEditor { namespace Internal { @@ -34,8 +32,6 @@ public: void initialize() final; - static Utils::FutureSynchronizer *futureSynchronizer(); - private: class DiffEditorPluginPrivate *d = nullptr; diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index 6847bf0e3a2..f1467f6ea27 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -5,7 +5,6 @@ #include "diffeditorconstants.h" #include "diffeditordocument.h" -#include "diffeditorplugin.h" #include "diffeditortr.h" #include @@ -13,6 +12,8 @@ #include #include +#include + #include #include #include @@ -869,7 +870,7 @@ void SideBySideDiffEditorWidget::restoreState() void SideBySideDiffEditorWidget::showDiff() { m_asyncTask.reset(new AsyncTask()); - m_asyncTask->setFutureSynchronizer(DiffEditorPlugin::futureSynchronizer()); + m_asyncTask->setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); m_controller.setBusyShowing(true); connect(m_asyncTask.get(), &AsyncTaskBase::done, this, [this] { diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index cb113612c20..d914ef59cb5 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -5,12 +5,13 @@ #include "diffeditorconstants.h" #include "diffeditordocument.h" -#include "diffeditorplugin.h" #include "diffeditortr.h" #include #include +#include + #include #include #include @@ -452,7 +453,7 @@ void UnifiedDiffEditorWidget::showDiff() } m_asyncTask.reset(new AsyncTask()); - m_asyncTask->setFutureSynchronizer(DiffEditorPlugin::futureSynchronizer()); + m_asyncTask->setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); m_controller.setBusyShowing(true); connect(m_asyncTask.get(), &AsyncTaskBase::done, this, [this] { if (m_asyncTask->isCanceled() || !m_asyncTask->isResultAvailable()) { diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 2d005079973..4c4b5be0251 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -97,7 +97,7 @@ LocatorMatcherTasks HelpIndexFilter::matchers() } const QStringList cache = m_lastEntry.isEmpty() || !storage->input().contains(m_lastEntry) ? m_allIndicesCache : m_lastIndicesCache; - async.setFutureSynchronizer(HelpPlugin::futureSynchronizer()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matches, *storage, cache, m_icon); }; const auto onDone = [this, storage](const AsyncTask &async) { diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 045035d093f..e46effd10b7 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -43,7 +43,6 @@ #include #include -#include #include #include #include @@ -143,7 +142,6 @@ public: LocalHelpManager m_localHelpManager; HelpIndexFilter helpIndexFilter; - FutureSynchronizer m_futureSynchronizer; }; static HelpPluginPrivate *dd = nullptr; @@ -397,12 +395,6 @@ HelpWidget *HelpPlugin::modeHelpWidget() return dd->m_centralWidget; } -FutureSynchronizer *HelpPlugin::futureSynchronizer() -{ - QTC_ASSERT(dd, return nullptr); - return &dd->m_futureSynchronizer; -} - void HelpPluginPrivate::showLinksInCurrentViewer(const QMultiMap &links, const QString &key) { if (links.size() < 1) diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h index bd483ae3da8..96d14a152b8 100644 --- a/src/plugins/help/helpplugin.h +++ b/src/plugins/help/helpplugin.h @@ -10,8 +10,6 @@ QT_BEGIN_NAMESPACE class QUrl; QT_END_NAMESPACE -namespace Utils { class FutureSynchronizer; } - namespace Help { namespace Internal { @@ -32,7 +30,6 @@ public: const QString &key); static HelpViewer *createHelpViewer(); static HelpWidget *modeHelpWidget(); - static Utils::FutureSynchronizer *futureSynchronizer(); private: void initialize() final; diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index b1001137662..7332f03e2b1 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -33,12 +33,6 @@ LanguageClientPlugin *LanguageClientPlugin::instance() return m_instance; } -Utils::FutureSynchronizer *LanguageClientPlugin::futureSynchronizer() -{ - QTC_ASSERT(m_instance, return nullptr); - return &m_instance->m_futureSynchronizer; -} - void LanguageClientPlugin::initialize() { using namespace Core; diff --git a/src/plugins/languageclient/languageclientplugin.h b/src/plugins/languageclient/languageclientplugin.h index 52e8dde9072..b8eb3ac00a2 100644 --- a/src/plugins/languageclient/languageclientplugin.h +++ b/src/plugins/languageclient/languageclientplugin.h @@ -8,8 +8,6 @@ #include -#include - namespace LanguageClient { class LanguageClientPlugin : public ExtensionSystem::IPlugin @@ -21,7 +19,6 @@ public: ~LanguageClientPlugin() override; static LanguageClientPlugin *instance(); - static Utils::FutureSynchronizer *futureSynchronizer(); // IPlugin interface private: @@ -32,7 +29,6 @@ private: private: LanguageClientOutlineWidgetFactory m_outlineFactory; CallHierarchyFactory m_callHierarchyFactory; - Utils::FutureSynchronizer m_futureSynchronizer; #ifdef WITH_TESTS private slots: diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 2e61204a62f..16c0d52c72d 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -8,11 +8,12 @@ #include "documentsymbolcache.h" #include "languageclient_global.h" #include "languageclientmanager.h" -#include "languageclientplugin.h" #include "languageclienttr.h" #include +#include + #include #include @@ -78,7 +79,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, const QList results = *resultStorage; if (results.isEmpty()) return TaskAction::StopWithDone; - async.setFutureSynchronizer(LanguageClientPlugin::futureSynchronizer()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(filterResults, *storage, client, results, filter); return TaskAction::Continue; }; @@ -138,7 +139,7 @@ LocatorMatcherTask currentDocumentMatcher() }; const auto onFilterSetup = [=](AsyncTask &async) { - async.setFutureSynchronizer(LanguageClientPlugin::futureSynchronizer()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage); }; diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index ccf2971774c..7fe408a362e 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include #include @@ -45,7 +47,6 @@ public: QTimer timer; - FutureSynchronizer m_futureSynchronizer; std::unique_ptr m_taskTree; }; @@ -291,11 +292,6 @@ Environment ExtraCompiler::buildEnvironment() const return env; } -FutureSynchronizer *ExtraCompiler::futureSynchronizer() const -{ - return &d->m_futureSynchronizer; -} - void ExtraCompiler::setContent(const FilePath &file, const QByteArray &contents) { qCDebug(log).noquote() << Q_FUNC_INFO << contents; @@ -333,9 +329,9 @@ Tasking::TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &prov { const auto setupTask = [=](AsyncTask &async) { async.setThreadPool(extraCompilerThreadPool()); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(&ProcessExtraCompiler::runInThread, this, command(), workingDirectory(), arguments(), provider, buildEnvironment()); - async.setFutureSynchronizer(futureSynchronizer()); }; const auto taskDone = [=](const AsyncTask &async) { if (!async.isResultAvailable()) diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h index 4f0e6da47b3..889a79f858e 100644 --- a/src/plugins/projectexplorer/extracompiler.h +++ b/src/plugins/projectexplorer/extracompiler.h @@ -25,10 +25,7 @@ class QPromise; class QThreadPool; QT_END_NAMESPACE -namespace Utils { -class FutureSynchronizer; -class QtcProcess; -} +namespace Utils { class QtcProcess; } namespace ProjectExplorer { @@ -64,7 +61,6 @@ signals: protected: static QThreadPool *extraCompilerThreadPool(); - Utils::FutureSynchronizer *futureSynchronizer() const; void setContent(const Utils::FilePath &file, const QByteArray &content); void updateCompileTime(); Utils::Environment buildEnvironment() const; diff --git a/src/plugins/python/pythonplugin.cpp b/src/plugins/python/pythonplugin.cpp index 1fd12def06e..67857aec236 100644 --- a/src/plugins/python/pythonplugin.cpp +++ b/src/plugins/python/pythonplugin.cpp @@ -18,7 +18,6 @@ #include #include -#include #include using namespace ProjectExplorer; @@ -38,7 +37,6 @@ public: PySideBuildConfigurationFactory buildConfigFactory; SimpleTargetRunnerFactory runWorkerFactory{{runConfigFactory.runConfigurationId()}}; PythonSettings settings; - FutureSynchronizer m_futureSynchronizer; }; PythonPlugin::PythonPlugin() @@ -57,12 +55,6 @@ PythonPlugin *PythonPlugin::instance() return m_instance; } -FutureSynchronizer *PythonPlugin::futureSynchronizer() -{ - QTC_ASSERT(m_instance, return nullptr); - return &m_instance->d->m_futureSynchronizer; -} - void PythonPlugin::initialize() { d = new PythonPluginPrivate; diff --git a/src/plugins/python/pythonplugin.h b/src/plugins/python/pythonplugin.h index 7c8ca121f3c..ef0860bbca4 100644 --- a/src/plugins/python/pythonplugin.h +++ b/src/plugins/python/pythonplugin.h @@ -5,8 +5,6 @@ #include -namespace Utils { class FutureSynchronizer; } - namespace Python::Internal { class PythonPlugin final : public ExtensionSystem::IPlugin @@ -19,7 +17,6 @@ public: ~PythonPlugin() final; static PythonPlugin *instance(); - static Utils::FutureSynchronizer *futureSynchronizer(); private: void initialize() final; diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 552d41128b3..537da98125f 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -9,7 +9,6 @@ #include "pysideuicextracompiler.h" #include "pythonconstants.h" #include "pythonlanguageclient.h" -#include "pythonplugin.h" #include "pythonproject.h" #include "pythonsettings.h" #include "pythontr.h" @@ -17,6 +16,8 @@ #include #include +#include + #include #include @@ -248,7 +249,7 @@ void PythonRunConfigurationPrivate::checkForPySide(const FilePath &python, }); const auto future = Pip::instance(python)->info(package); m_watcher.setFuture(future); - PythonPlugin::futureSynchronizer()->addFuture(future); + ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(future); } void PythonRunConfigurationPrivate::handlePySidePackageInfo(const PipPackageInfo &pySideInfo, diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index dbc220302b3..0735fee7296 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -2,7 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "vcsbasediffeditorcontroller.h" -#include "vcsplugin.h" + +#include #include #include @@ -52,8 +53,8 @@ Tasking::TaskItem VcsBaseDiffEditorController::postProcessTask() QTC_ASSERT(storage, qWarning("Using postProcessTask() requires putting inputStorage() " "into task tree's root group.")); const QString inputData = storage ? *storage : QString(); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(&DiffUtils::readPatchWithPromise, inputData); - async.setFutureSynchronizer(Internal::VcsPlugin::futureSynchronizer()); }; const auto onDiffProcessorDone = [this](const AsyncTask> &async) { setDiffFiles(async.isResultAvailable() ? async.result() : QList()); diff --git a/src/plugins/vcsbase/vcsplugin.cpp b/src/plugins/vcsbase/vcsplugin.cpp index e5108942f57..77da3af71c1 100644 --- a/src/plugins/vcsbase/vcsplugin.cpp +++ b/src/plugins/vcsbase/vcsplugin.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -41,7 +40,6 @@ class VcsPluginPrivate public: CommonOptionsPage m_settingsPage; QStandardItemModel *m_nickNameModel = nullptr; - FutureSynchronizer m_futureSynchronizer; }; static VcsPlugin *m_instance = nullptr; @@ -123,12 +121,6 @@ CommonVcsSettings &VcsPlugin::settings() const return d->m_settingsPage.settings(); } -FutureSynchronizer *VcsPlugin::futureSynchronizer() -{ - QTC_ASSERT(m_instance, return nullptr); - return &m_instance->d->m_futureSynchronizer; -} - /* Delayed creation/update of the nick name model. */ QStandardItemModel *VcsPlugin::nickNameModel() { diff --git a/src/plugins/vcsbase/vcsplugin.h b/src/plugins/vcsbase/vcsplugin.h index 83157fc1408..99c3d74bbe8 100644 --- a/src/plugins/vcsbase/vcsplugin.h +++ b/src/plugins/vcsbase/vcsplugin.h @@ -11,8 +11,6 @@ QT_BEGIN_NAMESPACE class QStandardItemModel; QT_END_NAMESPACE -namespace Utils { class FutureSynchronizer; } - namespace VcsBase { class VcsBaseSubmitEditor; @@ -36,8 +34,6 @@ public: CommonVcsSettings &settings() const; - static Utils::FutureSynchronizer *futureSynchronizer(); - // Model of user nick names used for the submit // editor. Stored centrally here to achieve delayed // initialization and updating on settings change. From 65d704854e97c7dbec1ab4df20c2c65acbf40d5d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 16:02:35 +0200 Subject: [PATCH 0691/1447] PluginManager: Fix an obvious linkage error Amends 72bddf9f51fedd064f551bcb4ced5feeb46fdfc1 Change-Id: I238bea72821252f37ebba02903ca68de8633500e Reviewed-by: Eike Ziller --- src/libs/extensionsystem/pluginmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 9d478453ea9..cb0323798b8 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -423,7 +423,7 @@ QString PluginManager::systemInformation() return result; } -static FutureSynchronizer *futureSynchronizer() +static FutureSynchronizer *PluginManager::futureSynchronizer() { return d->m_futureSynchronizer.get(); } From fe3887e2bf41efb4d62d62b2e94e81471323b95b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Apr 2023 16:09:12 +0200 Subject: [PATCH 0692/1447] ExtensionsSystem: Future #3 Change-Id: Ie1e8230ac044b6c79e1125fb39bab0e68d0d6e6d Reviewed-by: Jarek Kobus --- src/libs/extensionsystem/pluginmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index cb0323798b8..588afe661de 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -423,7 +423,7 @@ QString PluginManager::systemInformation() return result; } -static FutureSynchronizer *PluginManager::futureSynchronizer() +FutureSynchronizer *PluginManager::futureSynchronizer() { return d->m_futureSynchronizer.get(); } From b4a6af026e5bce2340a900a92250e61d9205e511 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 18 Apr 2023 13:36:45 +0200 Subject: [PATCH 0693/1447] Utils: Remove displayName from SettingsAccessors It was not used. Change-Id: I7c0927698bf31548ec076c39881561d72e8495e6 Reviewed-by: Christian Stenger --- src/libs/utils/settingsaccessor.cpp | 24 ++++++------------- src/libs/utils/settingsaccessor.h | 16 +++++-------- .../cmaketoolsettingsaccessor.cpp | 4 +--- .../toolssettingsaccessor.cpp | 4 +--- src/plugins/projectexplorer/extraabi.cpp | 4 +--- .../toolchainsettingsaccessor.cpp | 4 +--- .../projectexplorer/userfileaccessor.cpp | 4 ++-- tests/auto/utils/settings/tst_settings.cpp | 3 +-- 8 files changed, 20 insertions(+), 43 deletions(-) diff --git a/src/libs/utils/settingsaccessor.cpp b/src/libs/utils/settingsaccessor.cpp index dc3cd0711e4..24f922bf983 100644 --- a/src/libs/utils/settingsaccessor.cpp +++ b/src/libs/utils/settingsaccessor.cpp @@ -39,15 +39,10 @@ QMessageBox::StandardButtons SettingsAccessor::Issue::allButtons() const /*! * The SettingsAccessor can be used to read/write settings in XML format. */ -SettingsAccessor::SettingsAccessor(const QString &docType, - const QString &displayName, - const QString &applicationDisplayName) : -docType(docType), -displayName(displayName), -applicationDisplayName(applicationDisplayName) +SettingsAccessor::SettingsAccessor(const QString &docType, const QString &applicationDisplayName) + : docType(docType), applicationDisplayName(applicationDisplayName) { QTC_CHECK(!docType.isEmpty()); - QTC_CHECK(!displayName.isEmpty()); QTC_CHECK(!applicationDisplayName.isEmpty()); } @@ -227,16 +222,14 @@ std::optional BackUpStrategy::backupName(const QVariantMap &oldData, } BackingUpSettingsAccessor::BackingUpSettingsAccessor(const QString &docType, - const QString &displayName, const QString &applicationDisplayName) : - BackingUpSettingsAccessor(std::make_unique(), docType, displayName, applicationDisplayName) + BackingUpSettingsAccessor(std::make_unique(), docType, applicationDisplayName) { } BackingUpSettingsAccessor::BackingUpSettingsAccessor(std::unique_ptr &&strategy, const QString &docType, - const QString &displayName, const QString &applicationDisplayName) : - SettingsAccessor(docType, displayName, applicationDisplayName), + SettingsAccessor(docType, applicationDisplayName), m_strategy(std::move(strategy)) { } @@ -411,17 +404,15 @@ QVariantMap VersionUpgrader::renameKeys(const QList &changes, QVariantMa * upgrade the settings on load to the latest supported version (if possible). */ UpgradingSettingsAccessor::UpgradingSettingsAccessor(const QString &docType, - const QString &displayName, const QString &applicationDisplayName) : UpgradingSettingsAccessor(std::make_unique(this), docType, - displayName, applicationDisplayName) + applicationDisplayName) { } UpgradingSettingsAccessor::UpgradingSettingsAccessor(std::unique_ptr &&strategy, const QString &docType, - const QString &displayName, const QString &applicationDisplayName) : - BackingUpSettingsAccessor(std::move(strategy), docType, displayName, applicationDisplayName) + BackingUpSettingsAccessor(std::move(strategy), docType, applicationDisplayName) { } int UpgradingSettingsAccessor::currentVersion() const @@ -579,9 +570,8 @@ UpgradingSettingsAccessor::validateVersionRange(const RestoreData &data) const */ MergingSettingsAccessor::MergingSettingsAccessor(std::unique_ptr &&strategy, const QString &docType, - const QString &displayName, const QString &applicationDisplayName) : - UpgradingSettingsAccessor(std::move(strategy), docType, displayName, applicationDisplayName) + UpgradingSettingsAccessor(std::move(strategy), docType, applicationDisplayName) { } SettingsAccessor::RestoreData MergingSettingsAccessor::readData(const FilePath &path, diff --git a/src/libs/utils/settingsaccessor.h b/src/libs/utils/settingsaccessor.h index f1bbb3594e8..0c0af485008 100644 --- a/src/libs/utils/settingsaccessor.h +++ b/src/libs/utils/settingsaccessor.h @@ -51,8 +51,7 @@ using SettingsMergeResult = std::optional>; class QTCREATOR_UTILS_EXPORT SettingsAccessor { public: - SettingsAccessor(const QString &docType, const QString &displayName, - const QString &applicationDisplayName); + SettingsAccessor(const QString &docType, const QString &applicationDisplayName); virtual ~SettingsAccessor(); enum ProceedInfo { Continue, DiscardAndContinue }; @@ -96,7 +95,6 @@ public: bool saveSettings(const QVariantMap &data, QWidget *parent) const; const QString docType; - const QString displayName; const QString applicationDisplayName; void setBaseFilePath(const FilePath &baseFilePath) { m_baseFilePath = baseFilePath; } @@ -148,10 +146,9 @@ public: class QTCREATOR_UTILS_EXPORT BackingUpSettingsAccessor : public SettingsAccessor { public: - BackingUpSettingsAccessor(const QString &docType, const QString &displayName, - const QString &applicationDisplayName); + BackingUpSettingsAccessor(const QString &docType, const QString &applicationDisplayName); BackingUpSettingsAccessor(std::unique_ptr &&strategy, const QString &docType, - const QString &displayName, const QString &applicationDisplayName); + const QString &applicationDisplayName); RestoreData readData(const FilePath &path, QWidget *parent) const override; std::optional writeData(const FilePath &path, @@ -220,10 +217,9 @@ class MergingSettingsAccessor; class QTCREATOR_UTILS_EXPORT UpgradingSettingsAccessor : public BackingUpSettingsAccessor { public: - UpgradingSettingsAccessor(const QString &docType, - const QString &displayName, const QString &applicationDisplayName); + UpgradingSettingsAccessor(const QString &docType, const QString &applicationDisplayName); UpgradingSettingsAccessor(std::unique_ptr &&strategy, const QString &docType, - const QString &displayName, const QString &appDisplayName); + const QString &appDisplayName); int currentVersion() const; int firstSupportedVersion() const; @@ -264,7 +260,7 @@ public: }; MergingSettingsAccessor(std::unique_ptr &&strategy, - const QString &docType, const QString &displayName, + const QString &docType, const QString &applicationDisplayName); RestoreData readData(const FilePath &path, QWidget *parent) const final; diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp index 43f1915709f..fe66c4b4902 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp @@ -139,9 +139,7 @@ mergeTools(std::vector> &sdkTools, // -------------------------------------------------------------------- CMakeToolSettingsAccessor::CMakeToolSettingsAccessor() : - UpgradingSettingsAccessor("QtCreatorCMakeTools", - Tr::tr("CMake"), - Core::Constants::IDE_DISPLAY_NAME) + UpgradingSettingsAccessor("QtCreatorCMakeTools", Core::Constants::IDE_DISPLAY_NAME) { setBaseFilePath(Core::ICore::userResourcePath(CMAKE_TOOL_FILENAME)); diff --git a/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp b/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp index fff0259741b..8cc7b10d8f2 100644 --- a/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp +++ b/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp @@ -26,9 +26,7 @@ static QString entryName(int index) } ToolsSettingsAccessor::ToolsSettingsAccessor() - : UpgradingSettingsAccessor("QtCreatorMesonTools", - Tr::tr("Meson"), - Core::Constants::IDE_DISPLAY_NAME) + : UpgradingSettingsAccessor("QtCreatorMesonTools", Core::Constants::IDE_DISPLAY_NAME) { setBaseFilePath(Core::ICore::userResourcePath(Constants::ToolsSettings::FILENAME)); } diff --git a/src/plugins/projectexplorer/extraabi.cpp b/src/plugins/projectexplorer/extraabi.cpp index 24a28611033..768c133a266 100644 --- a/src/plugins/projectexplorer/extraabi.cpp +++ b/src/plugins/projectexplorer/extraabi.cpp @@ -4,7 +4,6 @@ #include "extraabi.h" #include "abi.h" -#include "projectexplorertr.h" #include @@ -40,8 +39,7 @@ public: }; AbiFlavorAccessor::AbiFlavorAccessor() : - UpgradingSettingsAccessor("QtCreatorExtraAbi", Tr::tr("ABI"), - Core::Constants::IDE_DISPLAY_NAME) + UpgradingSettingsAccessor("QtCreatorExtraAbi", Core::Constants::IDE_DISPLAY_NAME) { setBaseFilePath(Core::ICore::installerResourcePath("abi.xml")); diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp index d7db868e856..5077083ac81 100644 --- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp +++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp @@ -170,9 +170,7 @@ static ToolChainOperations mergeToolChainLists(const Toolchains &systemFileTcs, // -------------------------------------------------------------------- ToolChainSettingsAccessor::ToolChainSettingsAccessor() : - UpgradingSettingsAccessor("QtCreatorToolChains", - Tr::tr("Tool Chains"), - Core::Constants::IDE_DISPLAY_NAME) + UpgradingSettingsAccessor("QtCreatorToolChains", Core::Constants::IDE_DISPLAY_NAME) { setBaseFilePath(Core::ICore::userResourcePath(TOOLCHAIN_FILENAME)); diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index cf347e032f2..bd0f60276c0 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -285,7 +285,7 @@ FilePaths UserFileBackUpStrategy::readFileCandidates(const FilePath &baseFileNam UserFileAccessor::UserFileAccessor(Project *project) : MergingSettingsAccessor(std::make_unique(this), - "QtCreatorProject", project->displayName(), + "QtCreatorProject", Core::Constants::IDE_DISPLAY_NAME), m_project(project) { @@ -295,7 +295,7 @@ UserFileAccessor::UserFileAccessor(Project *project) : setBaseFilePath(externalUser.isEmpty() ? projectUser : externalUser); auto secondary - = std::make_unique(docType, displayName, applicationDisplayName); + = std::make_unique(docType, applicationDisplayName); secondary->setBaseFilePath(sharedFile()); secondary->setReadOnly(); setSecondaryAccessor(std::move(secondary)); diff --git a/tests/auto/utils/settings/tst_settings.cpp b/tests/auto/utils/settings/tst_settings.cpp index a436ac45e81..433401b9e12 100644 --- a/tests/auto/utils/settings/tst_settings.cpp +++ b/tests/auto/utils/settings/tst_settings.cpp @@ -10,7 +10,6 @@ using namespace Utils; -const char TESTACCESSOR_DN[] = "Test Settings Accessor"; const char TESTACCESSOR_APPLICATION_DN[] = "SettingsAccessor Test (Basic)"; const char TESTACCESSOR_DEFAULT_ID[] = "testId"; @@ -145,7 +144,7 @@ public: BasicTestSettingsAccessor::BasicTestSettingsAccessor(const FilePath &baseName, const QByteArray &id) : Utils::MergingSettingsAccessor(std::make_unique(this), - "TestData", TESTACCESSOR_DN, TESTACCESSOR_APPLICATION_DN) + "TestData", TESTACCESSOR_APPLICATION_DN) { setSettingsId(id); setBaseFilePath(baseName); From aeac83af7813f6ca5c67281c6cd91fc77351830e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 18 Apr 2023 14:14:39 +0200 Subject: [PATCH 0694/1447] Utils: Collapse the two SettingsAccessor constructor hierarchies Change-Id: I7b659c9e3c66700cfc92f9cfbd9df0535a1ca655 Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/utils/settingsaccessor.cpp | 31 +++++++------------ src/libs/utils/settingsaccessor.h | 9 ++---- .../projectexplorer/userfileaccessor.cpp | 6 ++-- tests/auto/utils/settings/tst_settings.cpp | 4 +-- 4 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/libs/utils/settingsaccessor.cpp b/src/libs/utils/settingsaccessor.cpp index 24f922bf983..0562f5cf982 100644 --- a/src/libs/utils/settingsaccessor.cpp +++ b/src/libs/utils/settingsaccessor.cpp @@ -223,14 +223,8 @@ std::optional BackUpStrategy::backupName(const QVariantMap &oldData, BackingUpSettingsAccessor::BackingUpSettingsAccessor(const QString &docType, const QString &applicationDisplayName) : - BackingUpSettingsAccessor(std::make_unique(), docType, applicationDisplayName) -{ } - -BackingUpSettingsAccessor::BackingUpSettingsAccessor(std::unique_ptr &&strategy, - const QString &docType, - const QString &applicationDisplayName) : SettingsAccessor(docType, applicationDisplayName), - m_strategy(std::move(strategy)) + m_strategy(std::make_unique()) { } SettingsAccessor::RestoreData @@ -272,6 +266,11 @@ std::optional BackingUpSettingsAccessor::writeData(cons return SettingsAccessor::writeData(path, data, parent); } +void BackingUpSettingsAccessor::setStrategy(std::unique_ptr &&strategy) +{ + m_strategy = std::move(strategy); +} + FilePaths BackingUpSettingsAccessor::readFileCandidates(const FilePath &path) const { FilePaths result = filteredUnique(m_strategy->readFileCandidates(path)); @@ -405,15 +404,10 @@ QVariantMap VersionUpgrader::renameKeys(const QList &changes, QVariantMa */ UpgradingSettingsAccessor::UpgradingSettingsAccessor(const QString &docType, const QString &applicationDisplayName) : - UpgradingSettingsAccessor(std::make_unique(this), docType, - applicationDisplayName) -{ } - -UpgradingSettingsAccessor::UpgradingSettingsAccessor(std::unique_ptr &&strategy, - const QString &docType, - const QString &applicationDisplayName) : - BackingUpSettingsAccessor(std::move(strategy), docType, applicationDisplayName) -{ } + BackingUpSettingsAccessor(docType, applicationDisplayName) +{ + setStrategy(std::make_unique(this)); +} int UpgradingSettingsAccessor::currentVersion() const { @@ -568,10 +562,9 @@ UpgradingSettingsAccessor::validateVersionRange(const RestoreData &data) const * MergingSettingsAccessor allows to merge secondary settings into the main settings. * This is useful to e.g. handle .shared files together with .user files. */ -MergingSettingsAccessor::MergingSettingsAccessor(std::unique_ptr &&strategy, - const QString &docType, +MergingSettingsAccessor::MergingSettingsAccessor(const QString &docType, const QString &applicationDisplayName) : - UpgradingSettingsAccessor(std::move(strategy), docType, applicationDisplayName) + UpgradingSettingsAccessor(docType, applicationDisplayName) { } SettingsAccessor::RestoreData MergingSettingsAccessor::readData(const FilePath &path, diff --git a/src/libs/utils/settingsaccessor.h b/src/libs/utils/settingsaccessor.h index 0c0af485008..5ad37bd59c7 100644 --- a/src/libs/utils/settingsaccessor.h +++ b/src/libs/utils/settingsaccessor.h @@ -147,8 +147,6 @@ class QTCREATOR_UTILS_EXPORT BackingUpSettingsAccessor : public SettingsAccessor { public: BackingUpSettingsAccessor(const QString &docType, const QString &applicationDisplayName); - BackingUpSettingsAccessor(std::unique_ptr &&strategy, const QString &docType, - const QString &applicationDisplayName); RestoreData readData(const FilePath &path, QWidget *parent) const override; std::optional writeData(const FilePath &path, @@ -156,6 +154,7 @@ public: QWidget *parent) const override; BackUpStrategy *strategy() const { return m_strategy.get(); } + void setStrategy(std::unique_ptr &&strategy); private: FilePaths readFileCandidates(const FilePath &path) const; @@ -218,8 +217,6 @@ class QTCREATOR_UTILS_EXPORT UpgradingSettingsAccessor : public BackingUpSetting { public: UpgradingSettingsAccessor(const QString &docType, const QString &applicationDisplayName); - UpgradingSettingsAccessor(std::unique_ptr &&strategy, const QString &docType, - const QString &appDisplayName); int currentVersion() const; int firstSupportedVersion() const; @@ -259,9 +256,7 @@ public: QString key; }; - MergingSettingsAccessor(std::unique_ptr &&strategy, - const QString &docType, - const QString &applicationDisplayName); + MergingSettingsAccessor(const QString &docType, const QString &applicationDisplayName); RestoreData readData(const FilePath &path, QWidget *parent) const final; diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index bd0f60276c0..7d7a07a6517 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -284,11 +284,11 @@ FilePaths UserFileBackUpStrategy::readFileCandidates(const FilePath &baseFileNam // -------------------------------------------------------------------- UserFileAccessor::UserFileAccessor(Project *project) : - MergingSettingsAccessor(std::make_unique(this), - "QtCreatorProject", - Core::Constants::IDE_DISPLAY_NAME), + MergingSettingsAccessor("QtCreatorProject", Core::Constants::IDE_DISPLAY_NAME), m_project(project) { + setStrategy(std::make_unique(this)); + // Setup: const FilePath externalUser = externalUserFile(); const FilePath projectUser = projectUserFile(); diff --git a/tests/auto/utils/settings/tst_settings.cpp b/tests/auto/utils/settings/tst_settings.cpp index 433401b9e12..9f723b916ba 100644 --- a/tests/auto/utils/settings/tst_settings.cpp +++ b/tests/auto/utils/settings/tst_settings.cpp @@ -143,9 +143,9 @@ public: }; BasicTestSettingsAccessor::BasicTestSettingsAccessor(const FilePath &baseName, const QByteArray &id) : - Utils::MergingSettingsAccessor(std::make_unique(this), - "TestData", TESTACCESSOR_APPLICATION_DN) + Utils::MergingSettingsAccessor("TestData", TESTACCESSOR_APPLICATION_DN) { + setStrategy(std::make_unique(this)); setSettingsId(id); setBaseFilePath(baseName); } From 0b92e7f2f443dfe2c4e18a13b89015cd145cd801 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Apr 2023 11:01:23 +0200 Subject: [PATCH 0695/1447] Subversion: Code cosmetic Change-Id: Ibe085e2ca5c754a95d50d6eeb7f0182736443d99 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/subversion/subversionsettings.cpp | 11 ++--------- src/plugins/subversion/subversionsettings.h | 7 +++---- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index 5a275129124..36a65eff0c3 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -3,13 +3,8 @@ #include "subversionsettings.h" -#include "subversionclient.h" -#include "subversionplugin.h" #include "subversiontr.h" -#include -#include - #include #include #include @@ -22,8 +17,7 @@ using namespace Utils; using namespace VcsBase; -namespace Subversion { -namespace Internal { +namespace Subversion::Internal { // SubversionSettings @@ -122,5 +116,4 @@ SubversionSettingsPage::SubversionSettingsPage(SubversionSettings *settings) }); } -} // Internal -} // Subversion +} // Subversion::Internal diff --git a/src/plugins/subversion/subversionsettings.h b/src/plugins/subversion/subversionsettings.h index 01e30916956..206a19d59ff 100644 --- a/src/plugins/subversion/subversionsettings.h +++ b/src/plugins/subversion/subversionsettings.h @@ -4,10 +4,10 @@ #pragma once #include + #include -namespace Subversion { -namespace Internal { +namespace Subversion::Internal { class SubversionSettings : public VcsBase::VcsBaseSettings { @@ -29,5 +29,4 @@ public: explicit SubversionSettingsPage(SubversionSettings *settings); }; -} // namespace Internal -} // namespace Subversion +} // Subversion::Internal From 39dd0f8c0c24aa07fc51f7964c5009fb5ea26fd8 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:01:01 +0200 Subject: [PATCH 0696/1447] Help: Use IOptionPage::setWidgetCreator() for filter settings Change-Id: I2107386b8440b94812426abbf9a9b2713fcb29d4 Reviewed-by: Christian Stenger --- src/plugins/help/filtersettingspage.cpp | 91 ++++++++++++++----------- src/plugins/help/filtersettingspage.h | 22 +----- 2 files changed, 52 insertions(+), 61 deletions(-) diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp index 771c39fc689..7f6ca802e9f 100644 --- a/src/plugins/help/filtersettingspage.cpp +++ b/src/plugins/help/filtersettingspage.cpp @@ -9,54 +9,63 @@ #include #include +#include #include -using namespace Help::Internal; +namespace Help::Internal { + +class FilterSettingsPageWidget : public Core::IOptionsPageWidget +{ +public: + FilterSettingsPageWidget(FilterSettingsPage *page) : m_page(page) + { + LocalHelpManager::setupGuiHelpEngine(); + m_widget = new QHelpFilterSettingsWidget; + m_widget->readSettings(LocalHelpManager::filterEngine()); + + auto vbox = new QVBoxLayout(this); + vbox->addWidget(m_widget); + + connect(Core::HelpManager::Signals::instance(), + &Core::HelpManager::Signals::documentationChanged, + this, + &FilterSettingsPageWidget::updateFilterPage); + + updateFilterPage(); + } + + void apply() final + { + if (m_widget->applySettings(LocalHelpManager::filterEngine())) + emit m_page->filtersChanged(); + + m_widget->readSettings(LocalHelpManager::filterEngine()); + } + + void finish() final + { + disconnect(Core::HelpManager::Signals::instance(), + &Core::HelpManager::Signals::documentationChanged, + this, + &FilterSettingsPageWidget::updateFilterPage); + } + + void updateFilterPage() + { + m_widget->setAvailableComponents(LocalHelpManager::filterEngine()->availableComponents()); + m_widget->setAvailableVersions(LocalHelpManager::filterEngine()->availableVersions()); + } + + FilterSettingsPage *m_page; + QHelpFilterSettingsWidget *m_widget; +}; FilterSettingsPage::FilterSettingsPage() { setId("D.Filters"); setDisplayName(Tr::tr("Filters")); setCategory(Help::Constants::HELP_CATEGORY); + setWidgetCreator([this] { return new FilterSettingsPageWidget(this); }); } -QWidget *FilterSettingsPage::widget() -{ - if (!m_widget) { - LocalHelpManager::setupGuiHelpEngine(); - m_widget = new QHelpFilterSettingsWidget(nullptr); - m_widget->readSettings(LocalHelpManager::filterEngine()); - - connect(Core::HelpManager::Signals::instance(), - &Core::HelpManager::Signals::documentationChanged, - this, - &FilterSettingsPage::updateFilterPage); - - updateFilterPage(); - } - return m_widget; -} - -void FilterSettingsPage::apply() -{ - if (m_widget->applySettings(LocalHelpManager::filterEngine())) - emit filtersChanged(); - - m_widget->readSettings(LocalHelpManager::filterEngine()); -} - -void FilterSettingsPage::finish() -{ - disconnect(Core::HelpManager::Signals::instance(), - &Core::HelpManager::Signals::documentationChanged, - this, - &FilterSettingsPage::updateFilterPage); - delete m_widget; -} - -void FilterSettingsPage::updateFilterPage() -{ - m_widget->setAvailableComponents(LocalHelpManager::filterEngine()->availableComponents()); - m_widget->setAvailableVersions(LocalHelpManager::filterEngine()->availableVersions()); -} - +} // Help::Internal diff --git a/src/plugins/help/filtersettingspage.h b/src/plugins/help/filtersettingspage.h index 308a489f26b..112726c1af9 100644 --- a/src/plugins/help/filtersettingspage.h +++ b/src/plugins/help/filtersettingspage.h @@ -5,14 +5,7 @@ #include -#include - -QT_BEGIN_NAMESPACE -class QHelpFilterSettingsWidget; -QT_END_NAMESPACE - -namespace Help { -namespace Internal { +namespace Help::Internal { class FilterSettingsPage : public Core::IOptionsPage { @@ -21,19 +14,8 @@ class FilterSettingsPage : public Core::IOptionsPage public: FilterSettingsPage(); - QWidget *widget() override; - void apply() override; - void finish() override; - signals: void filtersChanged(); - -private: - - void updateFilterPage(); - QPointer m_widget; - }; -} // namespace Help -} // namespace Internal +} // Help::Internal From 3edc491b2ab5b2177503cf58e7d04c6ef7f61080 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 18 Apr 2023 14:36:46 +0200 Subject: [PATCH 0697/1447] Utils: Simplify SettingsAccessor constructors Use setters instead. Change-Id: I912234fa832eeb80519740ca011921f1e71d70b4 Reviewed-by: Christian Stenger --- src/libs/utils/settingsaccessor.cpp | 45 ++++++++----------- src/libs/utils/settingsaccessor.h | 17 ++++--- .../cmaketoolsettingsaccessor.cpp | 5 ++- .../toolssettingsaccessor.cpp | 6 +-- src/plugins/projectexplorer/extraabi.cpp | 15 +++---- .../toolchainsettingsaccessor.cpp | 5 ++- .../projectexplorer/userfileaccessor.cpp | 12 ++--- tests/auto/utils/settings/tst_settings.cpp | 5 ++- 8 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/libs/utils/settingsaccessor.cpp b/src/libs/utils/settingsaccessor.cpp index 0562f5cf982..275290674fd 100644 --- a/src/libs/utils/settingsaccessor.cpp +++ b/src/libs/utils/settingsaccessor.cpp @@ -39,12 +39,7 @@ QMessageBox::StandardButtons SettingsAccessor::Issue::allButtons() const /*! * The SettingsAccessor can be used to read/write settings in XML format. */ -SettingsAccessor::SettingsAccessor(const QString &docType, const QString &applicationDisplayName) - : docType(docType), applicationDisplayName(applicationDisplayName) -{ - QTC_CHECK(!docType.isEmpty()); - QTC_CHECK(!applicationDisplayName.isEmpty()); -} +SettingsAccessor::SettingsAccessor() = default; SettingsAccessor::~SettingsAccessor() = default; @@ -63,6 +58,9 @@ QVariantMap SettingsAccessor::restoreSettings(QWidget *parent) const */ bool SettingsAccessor::saveSettings(const QVariantMap &data, QWidget *parent) const { + QTC_CHECK(!m_docType.isEmpty()); + QTC_CHECK(!m_applicationDisplayName.isEmpty()); + const std::optional result = writeData(m_baseFilePath, data, parent); const ProceedInfo pi = result ? reportIssues(result.value(), m_baseFilePath, parent) : ProceedInfo::Continue; @@ -94,6 +92,9 @@ std::optional SettingsAccessor::writeData(const FilePat QVariantMap SettingsAccessor::restoreSettings(const FilePath &settingsPath, QWidget *parent) const { + QTC_CHECK(!m_docType.isEmpty()); + QTC_CHECK(!m_applicationDisplayName.isEmpty()); + const RestoreData result = readData(settingsPath, parent); const ProceedInfo pi = result.hasIssue() ? reportIssues(result.issue.value(), result.path, parent) @@ -118,7 +119,7 @@ SettingsAccessor::RestoreData SettingsAccessor::readFile(const FilePath &path) c const QVariantMap data = reader.restoreValues(); if (!m_readOnly && path == m_baseFilePath) { if (!m_writer) - m_writer = std::make_unique(m_baseFilePath, docType); + m_writer = std::make_unique(m_baseFilePath, m_docType); m_writer->setContents(data); } @@ -141,7 +142,7 @@ std::optional SettingsAccessor::writeFile(const FilePat QString errorMessage; if (!m_readOnly && (!m_writer || m_writer->fileName() != path)) - m_writer = std::make_unique(path, docType); + m_writer = std::make_unique(path, m_docType); if (!m_writer->save(data, &errorMessage)) { return Issue(Tr::tr("Failed to Write File"), @@ -151,8 +152,7 @@ std::optional SettingsAccessor::writeFile(const FilePat } SettingsAccessor::ProceedInfo -SettingsAccessor::reportIssues(const SettingsAccessor::Issue &issue, const FilePath &path, - QWidget *parent) +SettingsAccessor::reportIssues(const Issue &issue, const FilePath &path, QWidget *parent) { if (!path.exists()) return Continue; @@ -221,10 +221,8 @@ std::optional BackUpStrategy::backupName(const QVariantMap &oldData, return path.stringAppended(".bak"); } -BackingUpSettingsAccessor::BackingUpSettingsAccessor(const QString &docType, - const QString &applicationDisplayName) : - SettingsAccessor(docType, applicationDisplayName), - m_strategy(std::make_unique()) +BackingUpSettingsAccessor::BackingUpSettingsAccessor() + : m_strategy(std::make_unique()) { } SettingsAccessor::RestoreData @@ -246,7 +244,7 @@ BackingUpSettingsAccessor::readData(const FilePath &path, QWidget *parent) const "for instance because they were written by an incompatible " "version of %2, or because a different settings path " "was used.

") - .arg(path.toUserOutput(), applicationDisplayName), Issue::Type::ERROR); + .arg(path.toUserOutput(), m_applicationDisplayName), Issue::Type::ERROR); i.buttons.insert(QMessageBox::Ok, DiscardAndContinue); result.issue = i; } @@ -402,9 +400,7 @@ QVariantMap VersionUpgrader::renameKeys(const QList &changes, QVariantMa * The UpgradingSettingsAccessor keeps version information in the settings file and will * upgrade the settings on load to the latest supported version (if possible). */ -UpgradingSettingsAccessor::UpgradingSettingsAccessor(const QString &docType, - const QString &applicationDisplayName) : - BackingUpSettingsAccessor(docType, applicationDisplayName) +UpgradingSettingsAccessor::UpgradingSettingsAccessor() { setStrategy(std::make_unique(this)); } @@ -526,7 +522,7 @@ UpgradingSettingsAccessor::validateVersionRange(const RestoreData &data) const "version of %2 was used are ignored, and " "changes made now will not be propagated to " "the newer version.

") - .arg(result.path.toUserOutput(), applicationDisplayName), Issue::Type::WARNING); + .arg(result.path.toUserOutput(), m_applicationDisplayName), Issue::Type::WARNING); i.buttons.insert(QMessageBox::Ok, Continue); result.issue = i; return result; @@ -535,13 +531,13 @@ UpgradingSettingsAccessor::validateVersionRange(const RestoreData &data) const const QByteArray readId = settingsIdFromMap(result.data); if (!settingsId().isEmpty() && !readId.isEmpty() && readId != settingsId()) { Issue i(Tr::tr("Settings File for \"%1\" from a Different Environment?") - .arg(applicationDisplayName), + .arg(m_applicationDisplayName), Tr::tr("

No settings file created by this instance " "of %1 was found.

" "

Did you work with this project on another machine or " "using a different settings path before?

" "

Do you still want to load the settings file \"%2\"?

") - .arg(applicationDisplayName, result.path.toUserOutput()), Issue::Type::WARNING); + .arg(m_applicationDisplayName, result.path.toUserOutput()), Issue::Type::WARNING); i.defaultButton = QMessageBox::No; i.escapeButton = QMessageBox::No; i.buttons.clear(); @@ -562,10 +558,7 @@ UpgradingSettingsAccessor::validateVersionRange(const RestoreData &data) const * MergingSettingsAccessor allows to merge secondary settings into the main settings. * This is useful to e.g. handle .shared files together with .user files. */ -MergingSettingsAccessor::MergingSettingsAccessor(const QString &docType, - const QString &applicationDisplayName) : - UpgradingSettingsAccessor(docType, applicationDisplayName) -{ } +MergingSettingsAccessor::MergingSettingsAccessor() = default; SettingsAccessor::RestoreData MergingSettingsAccessor::readData(const FilePath &path, QWidget *parent) const @@ -597,7 +590,7 @@ SettingsAccessor::RestoreData MergingSettingsAccessor::readData(const FilePath & secondaryData.issue = Issue(Tr::tr("Unsupported Merge Settings File"), Tr::tr("\"%1\" is not supported by %2. " "Do you want to try loading it anyway?") - .arg(secondaryData.path.toUserOutput(), applicationDisplayName), + .arg(secondaryData.path.toUserOutput(), m_applicationDisplayName), Issue::Type::WARNING); secondaryData.issue->buttons.clear(); secondaryData.issue->buttons.insert(QMessageBox::Yes, Continue); diff --git a/src/libs/utils/settingsaccessor.h b/src/libs/utils/settingsaccessor.h index 5ad37bd59c7..683743ac62f 100644 --- a/src/libs/utils/settingsaccessor.h +++ b/src/libs/utils/settingsaccessor.h @@ -51,7 +51,7 @@ using SettingsMergeResult = std::optional>; class QTCREATOR_UTILS_EXPORT SettingsAccessor { public: - SettingsAccessor(const QString &docType, const QString &applicationDisplayName); + SettingsAccessor(); virtual ~SettingsAccessor(); enum ProceedInfo { Continue, DiscardAndContinue }; @@ -94,9 +94,6 @@ public: QVariantMap restoreSettings(QWidget *parent) const; bool saveSettings(const QVariantMap &data, QWidget *parent) const; - const QString docType; - const QString applicationDisplayName; - void setBaseFilePath(const FilePath &baseFilePath) { m_baseFilePath = baseFilePath; } void setReadOnly() { m_readOnly = true; } FilePath baseFilePath() const { return m_baseFilePath; } @@ -106,6 +103,9 @@ public: const QVariantMap &data, QWidget *parent) const; + void setDocType(const QString &docType) { m_docType = docType; } + void setApplicationDisplayName(const QString &name) { m_applicationDisplayName = name; } + protected: // Report errors: QVariantMap restoreSettings(const FilePath &settingsPath, QWidget *parent) const; @@ -117,6 +117,9 @@ protected: virtual RestoreData readFile(const FilePath &path) const; virtual std::optional writeFile(const FilePath &path, const QVariantMap &data) const; + QString m_docType; + QString m_applicationDisplayName; + private: FilePath m_baseFilePath; mutable std::unique_ptr m_writer; @@ -146,7 +149,7 @@ public: class QTCREATOR_UTILS_EXPORT BackingUpSettingsAccessor : public SettingsAccessor { public: - BackingUpSettingsAccessor(const QString &docType, const QString &applicationDisplayName); + BackingUpSettingsAccessor(); RestoreData readData(const FilePath &path, QWidget *parent) const override; std::optional writeData(const FilePath &path, @@ -216,7 +219,7 @@ class MergingSettingsAccessor; class QTCREATOR_UTILS_EXPORT UpgradingSettingsAccessor : public BackingUpSettingsAccessor { public: - UpgradingSettingsAccessor(const QString &docType, const QString &applicationDisplayName); + UpgradingSettingsAccessor(); int currentVersion() const; int firstSupportedVersion() const; @@ -256,7 +259,7 @@ public: QString key; }; - MergingSettingsAccessor(const QString &docType, const QString &applicationDisplayName); + MergingSettingsAccessor(); RestoreData readData(const FilePath &path, QWidget *parent) const final; diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp index fe66c4b4902..614183352c3 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp @@ -138,9 +138,10 @@ mergeTools(std::vector> &sdkTools, // CMakeToolSettingsAccessor: // -------------------------------------------------------------------- -CMakeToolSettingsAccessor::CMakeToolSettingsAccessor() : - UpgradingSettingsAccessor("QtCreatorCMakeTools", Core::Constants::IDE_DISPLAY_NAME) +CMakeToolSettingsAccessor::CMakeToolSettingsAccessor() { + setDocType("QtCreatorCMakeTools"); + setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME); setBaseFilePath(Core::ICore::userResourcePath(CMAKE_TOOL_FILENAME)); addVersionUpgrader(std::make_unique()); diff --git a/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp b/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp index 8cc7b10d8f2..a67175742bb 100644 --- a/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp +++ b/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp @@ -21,13 +21,13 @@ namespace Internal { static QString entryName(int index) { - using namespace Constants; - return QString("%1%2").arg(ToolsSettings::ENTRY_KEY).arg(index); + return QString("%1%2").arg(Constants::ToolsSettings::ENTRY_KEY).arg(index); } ToolsSettingsAccessor::ToolsSettingsAccessor() - : UpgradingSettingsAccessor("QtCreatorMesonTools", Core::Constants::IDE_DISPLAY_NAME) { + setDocType("QtCreatorMesonTools"); + setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME); setBaseFilePath(Core::ICore::userResourcePath(Constants::ToolsSettings::FILENAME)); } diff --git a/src/plugins/projectexplorer/extraabi.cpp b/src/plugins/projectexplorer/extraabi.cpp index 768c133a266..19f970b11a6 100644 --- a/src/plugins/projectexplorer/extraabi.cpp +++ b/src/plugins/projectexplorer/extraabi.cpp @@ -35,16 +35,15 @@ public: class AbiFlavorAccessor : public UpgradingSettingsAccessor { public: - AbiFlavorAccessor(); + AbiFlavorAccessor() + { + setDocType("QtCreatorExtraAbi"); + setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME); + setBaseFilePath(Core::ICore::installerResourcePath("abi.xml")); + addVersionUpgrader(std::make_unique()); + } }; -AbiFlavorAccessor::AbiFlavorAccessor() : - UpgradingSettingsAccessor("QtCreatorExtraAbi", Core::Constants::IDE_DISPLAY_NAME) -{ - setBaseFilePath(Core::ICore::installerResourcePath("abi.xml")); - - addVersionUpgrader(std::make_unique()); -} // -------------------------------------------------------------------- // ExtraAbi: diff --git a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp index 5077083ac81..35224e4d02a 100644 --- a/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp +++ b/src/plugins/projectexplorer/toolchainsettingsaccessor.cpp @@ -169,9 +169,10 @@ static ToolChainOperations mergeToolChainLists(const Toolchains &systemFileTcs, // ToolChainSettingsAccessor: // -------------------------------------------------------------------- -ToolChainSettingsAccessor::ToolChainSettingsAccessor() : - UpgradingSettingsAccessor("QtCreatorToolChains", Core::Constants::IDE_DISPLAY_NAME) +ToolChainSettingsAccessor::ToolChainSettingsAccessor() { + setDocType("QtCreatorToolChains"); + setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME); setBaseFilePath(Core::ICore::userResourcePath(TOOLCHAIN_FILENAME)); addVersionUpgrader(std::make_unique()); diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index 7d7a07a6517..646e336643e 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -283,19 +283,21 @@ FilePaths UserFileBackUpStrategy::readFileCandidates(const FilePath &baseFileNam // UserFileAccessor: // -------------------------------------------------------------------- -UserFileAccessor::UserFileAccessor(Project *project) : - MergingSettingsAccessor("QtCreatorProject", Core::Constants::IDE_DISPLAY_NAME), - m_project(project) +UserFileAccessor::UserFileAccessor(Project *project) + : m_project(project) { setStrategy(std::make_unique(this)); + setDocType("QtCreatorProject"); + setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME); // Setup: const FilePath externalUser = externalUserFile(); const FilePath projectUser = projectUserFile(); setBaseFilePath(externalUser.isEmpty() ? projectUser : externalUser); - auto secondary - = std::make_unique(docType, applicationDisplayName); + auto secondary = std::make_unique(); + secondary->setDocType(m_docType); + secondary->setApplicationDisplayName(m_applicationDisplayName); secondary->setBaseFilePath(sharedFile()); secondary->setReadOnly(); setSecondaryAccessor(std::move(secondary)); diff --git a/tests/auto/utils/settings/tst_settings.cpp b/tests/auto/utils/settings/tst_settings.cpp index 9f723b916ba..d45d673e4d3 100644 --- a/tests/auto/utils/settings/tst_settings.cpp +++ b/tests/auto/utils/settings/tst_settings.cpp @@ -142,9 +142,10 @@ public: using Utils::MergingSettingsAccessor::upgradeSettings; }; -BasicTestSettingsAccessor::BasicTestSettingsAccessor(const FilePath &baseName, const QByteArray &id) : - Utils::MergingSettingsAccessor("TestData", TESTACCESSOR_APPLICATION_DN) +BasicTestSettingsAccessor::BasicTestSettingsAccessor(const FilePath &baseName, const QByteArray &id) { + setDocType("TestData"); + setApplicationDisplayName(TESTACCESSOR_APPLICATION_DN); setStrategy(std::make_unique(this)); setSettingsId(id); setBaseFilePath(baseName); From aeb2b458d075431f8cf9832132935f23d93c6b74 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 25 Apr 2023 14:59:18 +0200 Subject: [PATCH 0698/1447] Terminal: Allow dropping files Change-Id: I978ea72d6de7df6c31d1d2d2368e7aadf835279d Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 21 +++++++++++++++++++++ src/plugins/terminal/terminalwidget.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 67d7cae59d6..6e13960bccf 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -90,6 +91,7 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op setAttribute(Qt::WA_InputMethodEnabled); setAttribute(Qt::WA_MouseTracking); + setAcceptDrops(true); setCursor(Qt::IBeamCursor); @@ -1439,6 +1441,25 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event) event->accept(); } +void TerminalWidget::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasUrls()) { + event->setDropAction(Qt::CopyAction); + event->accept(); + } +} + +void TerminalWidget::dropEvent(QDropEvent *event) +{ + QString urls = Utils::transform(event->mimeData()->urls(), [](const QUrl &url) { + return QString("\"%1\"").arg(url.toDisplayString(QUrl::PreferLocalFile)); + }).join(" "); + + writeToPty(urls.toUtf8()); + event->setDropAction(Qt::CopyAction); + event->accept(); +} + void TerminalWidget::showEvent(QShowEvent *event) { Q_UNUSED(event); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 5833d17979e..4e1f2906b09 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -103,6 +103,9 @@ protected: void mouseReleaseEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dropEvent(QDropEvent *event) override; + void showEvent(QShowEvent *event) override; bool event(QEvent *event) override; From ea5e78e822c83ff072202a2710a86fbabe03d8c6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 25 Apr 2023 13:53:56 +0200 Subject: [PATCH 0699/1447] Examples/Marketplace: Put separator into heading for expanded view too Amends e596ee2b68f359397c7828c71f206e906d81cbe7 Change-Id: I888942bab2d330e8e8028e01017e7599a8fa567d Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/welcomepagehelper.cpp | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 62f8ef6054a..4826984d3d9 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -723,6 +723,15 @@ void SectionedGridView::setSearchString(const QString &searchString) filterModel->setSearchString(searchString); } +static QWidget *createSeparator(QWidget *parent) +{ + QWidget *line = Layouting::createHr(parent); + QSizePolicy linePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored); + linePolicy.setHorizontalStretch(2); + line->setSizePolicy(linePolicy); + return line; +} + ListModel *SectionedGridView::addSection(const Section §ion, const QList &items) { auto model = new ListModel(this); @@ -747,12 +756,8 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList" + Tr::tr("Show All") + " >", this); seeAllLink->setVisible(gridView->maxRows().has_value()); connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); }); - QWidget *line = createHr(this); - QSizePolicy linePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored); - linePolicy.setHorizontalStretch(2); - line->setSizePolicy(linePolicy); - QWidget *sectionLabel = Row{section.name, line, seeAllLink, Space(HSpacing)}.emerge( - Layouting::WithoutMargins); + QWidget *sectionLabel = Row{section.name, createSeparator(this), seeAllLink, Space(HSpacing)} + .emerge(Layouting::WithoutMargins); m_sectionLabels.append(sectionLabel); sectionLabel->setContentsMargins(0, ItemGap, 0, 0); sectionLabel->setFont(Core::WelcomePageHelpers::brandFont()); @@ -804,8 +809,8 @@ void SectionedGridView::zoomInSection(const Section §ion) delete zoomedInWidget; setCurrentIndex(0); }); - QWidget *sectionLabel = Column{hr, Row{section.name, st, backLink, Space(HSpacing)}}.emerge( - Layouting::WithoutMargins); + QWidget *sectionLabel = Row{section.name, createSeparator(this), backLink, Space(HSpacing)} + .emerge(Layouting::WithoutMargins); sectionLabel->setContentsMargins(0, ItemGap, 0, 0); sectionLabel->setFont(Core::WelcomePageHelpers::brandFont()); From d42e48f42415182a94caefc10d8dd0dd560caf4a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 25 Apr 2023 15:36:40 +0200 Subject: [PATCH 0700/1447] Examples: Hide "Show All" link if items fit It doesn't make sense to indicate to the user that there are more items, if there aren't. Change-Id: I80a3a113dc5f7aea693c054bb1755923cb02944c Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/welcomepagehelper.cpp | 29 +++++++++++++++++++- src/plugins/coreplugin/welcomepagehelper.h | 6 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 4826984d3d9..1d13b1a8c6b 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -158,6 +158,26 @@ void SectionGridView::wheelEvent(QWheelEvent *e) GridView::wheelEvent(e); } +bool SectionGridView::event(QEvent *e) +{ + if (e->type() == QEvent::Resize) { + const auto itemsFit = [this](const QSize &size) { + const int maxColumns = std::max(size.width() / ListItemDelegate::GridItemWidth, 1); + const int maxRows = std::max(size.height() / ListItemDelegate::GridItemHeight, 1); + const int maxItems = maxColumns * maxRows; + const int items = model()->rowCount(); + return maxItems >= items; + }; + auto resizeEvent = static_cast(e); + const bool itemsCurrentyFit = itemsFit(size()); + if (!resizeEvent->oldSize().isValid() + || itemsFit(resizeEvent->oldSize()) != itemsCurrentyFit) { + emit itemsFitChanged(itemsCurrentyFit); + } + } + return GridView::event(e); +} + const QSize ListModel::defaultImageSize(214, 160); ListModel::ListModel(QObject *parent) @@ -754,7 +774,14 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList" + Tr::tr("Show All") + " >", this); - seeAllLink->setVisible(gridView->maxRows().has_value()); + if (gridView->maxRows().has_value()) { + seeAllLink->setVisible(true); + connect(gridView, &SectionGridView::itemsFitChanged, seeAllLink, [seeAllLink](bool fits) { + seeAllLink->setVisible(!fits); + }); + } else { + seeAllLink->setVisible(false); + } connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); }); QWidget *sectionLabel = Row{section.name, createSeparator(this), seeAllLink, Space(HSpacing)} .emerge(Layouting::WithoutMargins); diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 8308d65311b..9baa341011d 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -48,6 +48,8 @@ protected: class CORE_EXPORT SectionGridView : public GridView { + Q_OBJECT + public: explicit SectionGridView(QWidget *parent); @@ -58,6 +60,10 @@ public: int heightForWidth(int width) const override; void wheelEvent(QWheelEvent *e) override; + bool event(QEvent *e) override; + +signals: + void itemsFitChanged(bool fit); private: std::optional m_maxRows; From 20f1ff22d7892294e0660935d9b29c81039782b6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 22:53:27 +0200 Subject: [PATCH 0701/1447] UrlLocatorFilter: Reimplement matchers() Change-Id: I4f81eba8ddfef6bdea31b60309642f167fce33a7 Reviewed-by: Eike Ziller --- .../coreplugin/locator/urllocatorfilter.cpp | 28 +++++++++++++++++++ .../coreplugin/locator/urllocatorfilter.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index a0345cfc5fd..2ab1d6f62cc 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -165,6 +165,34 @@ UrlLocatorFilter::UrlLocatorFilter(const QString &displayName, Id id) UrlLocatorFilter::~UrlLocatorFilter() = default; +LocatorMatcherTasks UrlLocatorFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage, urls = remoteUrls()] { + const QString input = storage->input(); + LocatorFilterEntries entries; + for (const QString &url : urls) { + const QString name = url.arg(input); + LocatorFilterEntry entry; + entry.displayName = name; + entry.acceptor = [name] { + if (!name.isEmpty()) + QDesktopServices::openUrl(name); + return AcceptResult(); + }; + entry.highlightInfo = {int(name.lastIndexOf(input)), int(input.length())}; + entries.append(entry); + } + storage->reportOutput(entries); + return true; + }; + + return {{Sync(onSetup), storage}}; +} + QList UrlLocatorFilter::matchesFor( QFutureInterface &future, const QString &entry) { diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.h b/src/plugins/coreplugin/locator/urllocatorfilter.h index 9c438a147c0..dbd4bef45b7 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.h +++ b/src/plugins/coreplugin/locator/urllocatorfilter.h @@ -44,6 +44,8 @@ protected: void restoreState(const QJsonObject &object) final; private: + LocatorMatcherTasks matchers() final; + QString m_defaultDisplayName; QStringList m_defaultUrls; QStringList m_remoteUrls; From 070bfe9387503688e154451c28fe278841012ac4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 17:48:43 +0200 Subject: [PATCH 0702/1447] FutureSynchronizer: Change the default value of cancelOnWait to true The "false" default wasn't really useful. This changes the default value to the following usages: 1. AndroidDeployQtStep Introduced in 91f136ef3ab75471cabcaed9dc16dad9f504add8 The synchronizer was used to cancel the running tasks inside the doCancel(), so the similar behavior should be expected when destructing the AndroidDeployQtStep. 2. GitClient Introduced in f3106ebafe9a02904e822e9698c8b4cbb6c7e0f5 Is used only inside the last line of GitSubmitEditor::updateFileModel(). The running function (CommitDataFetchResult::fetch) doesn't take QPromise<>, so it can't detect if the future was canceled or not. In this case this change is no-op. 3. ExtraCompiler Introduced in c99ce1f455189864de9a2043730f704d7b024abf The intention was to make it cancellable and finish early on cancel. 4. PluginManager global future synchronizer Introduced in 72bddf9f51fedd064f551bcb4ced5feeb46fdfc1 The intention was to make it cancellable and finish early on cancel. The relevant places in code are marked explicitly for points: 1, 2 and 3. Change-Id: I1a52deb8d1f81d355950c8772bbaa6d0a202fd7e Reviewed-by: Eike Ziller --- src/libs/extensionsystem/pluginmanager.cpp | 1 - src/libs/utils/futuresynchronizer.h | 7 ++++--- src/plugins/android/androiddeployqtstep.cpp | 1 + src/plugins/autotest/testcodeparser.cpp | 1 - src/plugins/clangcodemodel/clangmodelmanagersupport.cpp | 1 - src/plugins/cppeditor/cppindexingsupport.cpp | 7 ------- src/plugins/cppeditor/cppindexingsupport.h | 3 --- src/plugins/cppeditor/cppprojectupdater.cpp | 6 +----- src/plugins/cppeditor/cpptypehierarchy.cpp | 2 -- src/plugins/git/gitclient.h | 1 + src/plugins/ios/createsimulatordialog.cpp | 1 - src/plugins/ios/iostoolhandler.cpp | 1 - src/plugins/ios/simulatorinfomodel.cpp | 2 -- src/plugins/projectexplorer/extracompiler.cpp | 1 + src/plugins/qmljseditor/qmljsfindreferences.cpp | 1 - src/plugins/qmljseditor/qmljssemantichighlighter.cpp | 1 - src/plugins/remotelinux/tarpackagecreationstep.cpp | 1 - src/plugins/texteditor/basefilefind.cpp | 2 -- tests/auto/utils/asynctask/tst_asynctask.cpp | 1 + tests/manual/tasktree/main.cpp | 1 - 20 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 588afe661de..6ca6ef114c5 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -983,7 +983,6 @@ PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) : q(pluginManager) { m_futureSynchronizer.reset(new FutureSynchronizer); - m_futureSynchronizer->setCancelOnWait(true); } diff --git a/src/libs/utils/futuresynchronizer.h b/src/libs/utils/futuresynchronizer.h index 6a8192f0eb0..29b1f5e4563 100644 --- a/src/libs/utils/futuresynchronizer.h +++ b/src/libs/utils/futuresynchronizer.h @@ -31,14 +31,15 @@ public: void clearFutures(); void setCancelOnWait(bool enabled); - bool isCancelOnWait() const; // TODO: The original contained cancelOnWait, what suggests action, not a getter + // Note: The QFutureSynchronizer contains cancelOnWait(), what suggests action, not a getter. + bool isCancelOnWait() const; void flushFinishedFutures(); private: - QList> m_futures; - bool m_cancelOnWait = false; // TODO: True default makes more sense... + // Note: This default value is different than QFutureSynchronizer's one. True makes more sense. + bool m_cancelOnWait = true; }; } // namespace Utils diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 8b2bf8fb09f..1fef6615690 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -133,6 +133,7 @@ private: Environment m_environment; AndroidDeviceInfo m_deviceInfo; + // The synchronizer has cancelOnWait set to true by default. FutureSynchronizer m_synchronizer; }; diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index afa4f8ca5e8..b6a87c20383 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -54,7 +54,6 @@ TestCodeParser::TestCodeParser() }); m_reparseTimer.setSingleShot(true); connect(&m_reparseTimer, &QTimer::timeout, this, &TestCodeParser::parsePostponedFiles); - m_futureSynchronizer.setCancelOnWait(true); } TestCodeParser::~TestCodeParser() = default; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 87bd7bdef6a..5feca5c1a0b 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -260,7 +260,6 @@ ClangModelManagerSupport::ClangModelManagerSupport() if (ClangdSettings::instance().useClangd()) new ClangdClient(nullptr, {}); - m_generatorSynchronizer.setCancelOnWait(true); new ClangdQuickFixFactory(); // memory managed by CppEditor::g_cppQuickFixFactories } diff --git a/src/plugins/cppeditor/cppindexingsupport.cpp b/src/plugins/cppeditor/cppindexingsupport.cpp index 4b415058862..042caf227c1 100644 --- a/src/plugins/cppeditor/cppindexingsupport.cpp +++ b/src/plugins/cppeditor/cppindexingsupport.cpp @@ -298,13 +298,6 @@ void SymbolSearcher::runSearch(QPromise &promise) promise.suspendIfRequested(); } -CppIndexingSupport::CppIndexingSupport() -{ - m_synchronizer.setCancelOnWait(true); -} - -CppIndexingSupport::~CppIndexingSupport() = default; - bool CppIndexingSupport::isFindErrorsIndexingActive() { return Utils::qtcEnvironmentVariable("QTC_FIND_ERRORS_INDEXING") == "1"; diff --git a/src/plugins/cppeditor/cppindexingsupport.h b/src/plugins/cppeditor/cppindexingsupport.h index 690c1be9b42..0c2f631aae3 100644 --- a/src/plugins/cppeditor/cppindexingsupport.h +++ b/src/plugins/cppeditor/cppindexingsupport.h @@ -55,9 +55,6 @@ private: class CPPEDITOR_EXPORT CppIndexingSupport { public: - CppIndexingSupport(); - ~CppIndexingSupport(); - static bool isFindErrorsIndexingActive(); QFuture refreshSourceFiles(const QSet &sourceFiles, diff --git a/src/plugins/cppeditor/cppprojectupdater.cpp b/src/plugins/cppeditor/cppprojectupdater.cpp index cb64ea61bc8..6bab2ec3c3c 100644 --- a/src/plugins/cppeditor/cppprojectupdater.cpp +++ b/src/plugins/cppeditor/cppprojectupdater.cpp @@ -23,11 +23,7 @@ using namespace Utils; namespace CppEditor { -CppProjectUpdater::CppProjectUpdater() -{ - m_futureSynchronizer.setCancelOnWait(true); -} - +CppProjectUpdater::CppProjectUpdater() = default; CppProjectUpdater::~CppProjectUpdater() = default; void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo) diff --git a/src/plugins/cppeditor/cpptypehierarchy.cpp b/src/plugins/cppeditor/cpptypehierarchy.cpp index 27ef5751d10..837375b6f37 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.cpp +++ b/src/plugins/cppeditor/cpptypehierarchy.cpp @@ -154,8 +154,6 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget() this, &CppTypeHierarchyWidget::perform); connect(&m_futureWatcher, &QFutureWatcher::finished, this, &CppTypeHierarchyWidget::displayHierarchy); - - m_synchronizer.setCancelOnWait(true); } void CppTypeHierarchyWidget::perform() diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 5709a53b862..a43c25a7426 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -402,6 +402,7 @@ private: QString m_diffCommit; Utils::FilePaths m_updatedSubmodules; bool m_disableEditor = false; + // The synchronizer has cancelOnWait set to true by default. Utils::FutureSynchronizer m_synchronizer; // for commit updates }; diff --git a/src/plugins/ios/createsimulatordialog.cpp b/src/plugins/ios/createsimulatordialog.cpp index d042529c555..c2df6020f5c 100644 --- a/src/plugins/ios/createsimulatordialog.cpp +++ b/src/plugins/ios/createsimulatordialog.cpp @@ -60,7 +60,6 @@ CreateSimulatorDialog::CreateSimulatorDialog(QWidget *parent) enableOk(); }); - m_futureSync.setCancelOnWait(true); m_futureSync.addFuture(Utils::onResultReady(SimulatorControl::updateDeviceTypes(this), this, &CreateSimulatorDialog::populateDeviceTypes)); diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 08e937d5ccf..471d13f239a 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -787,7 +787,6 @@ IosSimulatorToolHandlerPrivate::IosSimulatorToolHandlerPrivate(const IosDeviceTy { QObject::connect(&outputLogger, &LogTailFiles::logMessage, std::bind(&IosToolHandlerPrivate::appOutput, this, _1)); - futureSynchronizer.setCancelOnWait(true); } void IosSimulatorToolHandlerPrivate::requestTransferApp(const QString &appBundlePath, diff --git a/src/plugins/ios/simulatorinfomodel.cpp b/src/plugins/ios/simulatorinfomodel.cpp index 4db3994f4b9..a4627f56293 100644 --- a/src/plugins/ios/simulatorinfomodel.cpp +++ b/src/plugins/ios/simulatorinfomodel.cpp @@ -23,8 +23,6 @@ const int deviceUpdateInterval = 1000; // Update simulator state every 1 sec. SimulatorInfoModel::SimulatorInfoModel(QObject *parent) : QAbstractItemModel(parent) { - m_fetchFuture.setCancelOnWait(true); - requestSimulatorInfo(); auto updateTimer = new QTimer(this); diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index 7fe408a362e..0f0953cb3e7 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -329,6 +329,7 @@ Tasking::TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &prov { const auto setupTask = [=](AsyncTask &async) { async.setThreadPool(extraCompilerThreadPool()); + // The passed synchronizer has cancelOnWait set to true by default. async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(&ProcessExtraCompiler::runInThread, this, command(), workingDirectory(), arguments(), provider, buildEnvironment()); diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index c8ae1f8b8b0..ff8ac54e931 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -803,7 +803,6 @@ FindReferences::FindReferences(QObject *parent) m_watcher.setPendingResultsLimit(1); connect(&m_watcher, &QFutureWatcherBase::resultsReadyAt, this, &FindReferences::displayResults); connect(&m_watcher, &QFutureWatcherBase::finished, this, &FindReferences::searchFinished); - m_synchronizer.setCancelOnWait(true); } FindReferences::~FindReferences() = default; diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp index 56f8dfd0bb8..cb60b29941b 100644 --- a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp +++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp @@ -542,7 +542,6 @@ SemanticHighlighter::SemanticHighlighter(QmlJSEditorDocument *document) this, &SemanticHighlighter::applyResults); connect(&m_watcher, &QFutureWatcherBase::finished, this, &SemanticHighlighter::finished); - m_futureSynchronizer.setCancelOnWait(true); } void SemanticHighlighter::rerun(const QmlJSTools::SemanticInfo &semanticInfo) diff --git a/src/plugins/remotelinux/tarpackagecreationstep.cpp b/src/plugins/remotelinux/tarpackagecreationstep.cpp index 80aec8053de..7d36c4d83be 100644 --- a/src/plugins/remotelinux/tarpackagecreationstep.cpp +++ b/src/plugins/remotelinux/tarpackagecreationstep.cpp @@ -94,7 +94,6 @@ private: TarPackageCreationStep::TarPackageCreationStep(BuildStepList *bsl, Id id) : BuildStep(bsl, id) { - m_synchronizer.setCancelOnWait(true); connect(target(), &Target::deploymentDataChanged, this, [this] { m_deploymentDataModified = true; }); diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 29cccc6c10d..f23d52ccb5e 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -91,8 +91,6 @@ public: class BaseFileFindPrivate { public: - BaseFileFindPrivate() { m_futureSynchronizer.setCancelOnWait(true); } - QPointer m_currentFindSupport; Utils::FutureSynchronizer m_futureSynchronizer; diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/asynctask/tst_asynctask.cpp index 5118b5555af..37e33d5dcff 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/asynctask/tst_asynctask.cpp @@ -400,6 +400,7 @@ void tst_AsyncTask::futureSynchonizer() }; FutureSynchronizer synchronizer; + synchronizer.setCancelOnWait(false); { AsyncTask task; task.setConcurrentCallData(lambda); diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index 4dc6da3fee7..22514300592 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -148,7 +148,6 @@ int main(int argc, char *argv[]) std::unique_ptr taskTree; FutureSynchronizer synchronizer; - synchronizer.setCancelOnWait(true); auto treeRoot = [&] { using namespace Tasking; From 52246b8760468c8e105a2a30c1eee0d8722612e0 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 16:09:22 +0200 Subject: [PATCH 0703/1447] Qnx: Also add target architectures in the info box I always get confused by Qnx's 'Target' names. This reminds me there is more... Change-Id: I6b7197b7199180d895b695de81b75270643526f6 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/qnx/qnxsettingspage.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 119c7a3e2a0..c12da720c89 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -112,6 +112,11 @@ public: void ensureContents() const; void mutableEnsureContents(); + QString architectureNames() const + { + return transform(m_targets, &QnxTarget::shortDescription).join(", "); + } + EnvironmentItems qnxEnvironmentItems() const; QnxQtVersion *qnxQtVersion(const QnxTarget &target) const; @@ -518,6 +523,7 @@ private: QLabel *m_configVersion = new QLabel; QLabel *m_configHost = new QLabel; QLabel *m_configTarget = new QLabel; + QLabel *m_architecturesLabel = new QLabel; QList m_changedConfigs; }; @@ -539,7 +545,8 @@ QnxSettingsWidget::QnxSettingsWidget() Tr::tr("Name:"), m_configName, br, Tr::tr("Version:"), m_configVersion, br, Tr::tr("Host:"), m_configHost, br, - Tr::tr("Target:"), m_configTarget + Tr::tr("Target:"), m_configTarget, br, + Tr::tr("Architectures:"), m_architecturesLabel } }, st @@ -641,13 +648,14 @@ void QnxSettingsWidget::updateInformation() m_configVersion->setText(config->m_version.toString()); m_configHost->setText(config->m_qnxHost.toString()); m_configTarget->setText(config->m_qnxTarget.toString()); + m_architecturesLabel->setText(config->architectureNames()); } else { m_generateKitsCheckBox->setEnabled(false); m_generateKitsCheckBox->setChecked(false); m_configName->setText({}); m_configVersion->setText({}); m_configHost->setText({}); - m_configTarget->setText({}); + m_architecturesLabel->setText({}); } } From 8903e7f387e1c96a51f13ab66d3a247bfcbf398d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 23:05:06 +0200 Subject: [PATCH 0704/1447] ExecuteFilter: Reimplement matchers() Change-Id: I4a916164d1a81e0bed678ed1579a5da1cbb57f50 Reviewed-by: Eike Ziller --- .../coreplugin/locator/executefilter.cpp | 37 +++++++++++++++++++ .../coreplugin/locator/executefilter.h | 1 + 2 files changed, 38 insertions(+) diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 723e9f60808..3d1bfb51ed4 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -39,6 +39,43 @@ ExecuteFilter::~ExecuteFilter() removeProcess(); } +LocatorMatcherTasks ExecuteFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [=] { + const QString input = storage->input(); + LocatorFilterEntries entries; + if (!input.isEmpty()) { // avoid empty entry + LocatorFilterEntry entry; + entry.displayName = input; + entry.acceptor = [this, input] { acceptCommand(input); return AcceptResult(); }; + entries.append(entry); + } + LocatorFilterEntries others; + const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(input); + for (const QString &cmd : std::as_const(m_commandHistory)) { + if (cmd == input) // avoid repeated entry + continue; + LocatorFilterEntry entry; + entry.displayName = cmd; + entry.acceptor = [this, cmd] { acceptCommand(cmd); return AcceptResult(); }; + const int index = cmd.indexOf(input, 0, entryCaseSensitivity); + if (index >= 0) { + entry.highlightInfo = {index, int(input.length())}; + entries.append(entry); + } else { + others.append(entry); + } + } + storage->reportOutput(entries + others); + return true; + }; + return {{Sync(onSetup), storage}}; +} + void ExecuteFilter::acceptCommand(const QString &cmd) { const QString displayName = cmd.trimmed(); diff --git a/src/plugins/coreplugin/locator/executefilter.h b/src/plugins/coreplugin/locator/executefilter.h index e6628c100cc..525c7250283 100644 --- a/src/plugins/coreplugin/locator/executefilter.h +++ b/src/plugins/coreplugin/locator/executefilter.h @@ -32,6 +32,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + LocatorMatcherTasks matchers() final; void acceptCommand(const QString &cmd); void done(); void readStandardOutput(); From 02d86516c7adb26617bb26dbb50e13da3af7882f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 24 Apr 2023 17:25:13 +0200 Subject: [PATCH 0705/1447] ProjectExplorer: Optionally show run environment in app output pane Fixes: QTCREATORBUG-28427 Change-Id: I1022a377d3728ad5e91fa62514082110b86db9f4 Reviewed-by: hjk Reviewed-by: Qt CI Bot Reviewed-by: --- .../cmakebuildconfiguration.cpp | 1 + .../projectexplorer/environmentaspect.cpp | 3 +++ .../projectexplorer/environmentaspect.h | 7 +++++++ .../environmentaspectwidget.cpp | 9 +++++++++ .../projectexplorer/runconfiguration.cpp | 7 +++++++ .../projectexplorer/runconfiguration.h | 1 + src/plugins/projectexplorer/runcontrol.cpp | 19 +++++++++++++++++-- src/plugins/projectexplorer/runcontrol.h | 1 + 8 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index eebaada63ba..a56564a8c0a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -2284,6 +2284,7 @@ public: ConfigureEnvironmentAspect::ConfigureEnvironmentAspect(ProjectExplorer::Target *target) { setIsLocal(true); + setAllowPrintOnRun(false); setConfigWidgetCreator( [this, target] { return new ConfigureEnvironmentAspectWidget(this, target); }); addSupportedBaseEnvironment(Tr::tr("Clean Environment"), {}); diff --git a/src/plugins/projectexplorer/environmentaspect.cpp b/src/plugins/projectexplorer/environmentaspect.cpp index 66a2b3bc990..dc3abedbe74 100644 --- a/src/plugins/projectexplorer/environmentaspect.cpp +++ b/src/plugins/projectexplorer/environmentaspect.cpp @@ -12,6 +12,7 @@ using namespace Utils; namespace ProjectExplorer { +const char PRINT_ON_RUN_KEY[] = "PE.EnvironmentAspect.PrintOnRun"; // -------------------------------------------------------------------- // EnvironmentAspect: @@ -105,12 +106,14 @@ void EnvironmentAspect::fromMap(const QVariantMap &map) { m_base = map.value(QLatin1String(BASE_KEY), -1).toInt(); m_userChanges = Utils::EnvironmentItem::fromStringList(map.value(QLatin1String(CHANGES_KEY)).toStringList()); + m_printOnRun = map.value(PRINT_ON_RUN_KEY).toBool(); } void EnvironmentAspect::toMap(QVariantMap &data) const { data.insert(QLatin1String(BASE_KEY), m_base); data.insert(QLatin1String(CHANGES_KEY), Utils::EnvironmentItem::toStringList(m_userChanges)); + data.insert(PRINT_ON_RUN_KEY, m_printOnRun); } QString EnvironmentAspect::currentDisplayName() const diff --git a/src/plugins/projectexplorer/environmentaspect.h b/src/plugins/projectexplorer/environmentaspect.h index 5b1d0d1c41a..9ba2f8a9835 100644 --- a/src/plugins/projectexplorer/environmentaspect.h +++ b/src/plugins/projectexplorer/environmentaspect.h @@ -48,6 +48,10 @@ public: bool isLocal() const { return m_isLocal; } + bool isPrintOnRunAllowed() const { return m_allowPrintOnRun; } + bool isPrintOnRunEnabled() const { return m_printOnRun; } + void setPrintOnRun(bool enabled) { m_printOnRun = enabled; } + struct Data : BaseAspect::Data { Utils::Environment environment; @@ -66,6 +70,7 @@ protected: void toMap(QVariantMap &map) const override; void setIsLocal(bool local) { m_isLocal = local; } + void setAllowPrintOnRun(bool allow) { m_allowPrintOnRun = allow; } static constexpr char BASE_KEY[] = "PE.EnvironmentAspect.Base"; static constexpr char CHANGES_KEY[] = "PE.EnvironmentAspect.Changes"; @@ -84,6 +89,8 @@ private: QList m_baseEnvironments; int m_base = -1; bool m_isLocal = false; + bool m_allowPrintOnRun = true; + bool m_printOnRun = false; }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/environmentaspectwidget.cpp b/src/plugins/projectexplorer/environmentaspectwidget.cpp index 18babfcf615..34e48af42c9 100644 --- a/src/plugins/projectexplorer/environmentaspectwidget.cpp +++ b/src/plugins/projectexplorer/environmentaspectwidget.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,14 @@ EnvironmentAspectWidget::EnvironmentAspectWidget(EnvironmentAspect *aspect) m_environmentWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); topLayout->addWidget(m_environmentWidget); + if (m_aspect->isPrintOnRunAllowed()) { + const auto printOnRunCheckBox = new QCheckBox(Tr::tr("Show in output pane when running")); + printOnRunCheckBox->setChecked(m_aspect->isPrintOnRunEnabled()); + connect(printOnRunCheckBox, &QCheckBox::toggled, + m_aspect, &EnvironmentAspect::setPrintOnRun); + topLayout->addWidget(printOnRunCheckBox); + } + connect(m_environmentWidget, &EnvironmentWidget::userChangesChanged, this, &EnvironmentAspectWidget::userChangesEdited); diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 928ca9db58d..32740d6c33c 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -298,6 +298,13 @@ CommandLine RunConfiguration::commandLine() const return m_commandLineGetter(); } +bool RunConfiguration::isPrintEnvironmentEnabled() const +{ + if (const auto envAspect = aspect()) + return envAspect->isPrintOnRunEnabled(); + return false; +} + void RunConfiguration::setRunnableModifier(const RunnableModifier &runnableModifier) { m_runnableModifier = runnableModifier; diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index 32f61b5a306..a0d83ebb488 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -116,6 +116,7 @@ public: using CommandLineGetter = std::function; void setCommandLineGetter(const CommandLineGetter &cmdGetter); Utils::CommandLine commandLine() const; + bool isPrintEnvironmentEnabled() const; using RunnableModifier = std::function; void setRunnableModifier(const RunnableModifier &extraModifier); diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 96bbc302ac5..b43c7fe3e83 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -255,9 +255,9 @@ public: // A handle to the actual application process. ProcessHandle applicationProcessHandle; - RunControlState state = RunControlState::Initialized; - QList> m_workers; + RunControlState state = RunControlState::Initialized; + bool printEnvironment = false; }; class RunControlPrivate : public QObject, public RunControlPrivateData @@ -334,6 +334,7 @@ void RunControl::copyDataFromRunConfiguration(RunConfiguration *runConfig) d->buildKey = runConfig->buildKey(); d->settingsData = runConfig->settingsData(); d->aspectData = runConfig->aspectData(); + d->printEnvironment = runConfig->isPrintEnvironmentEnabled(); setTarget(runConfig->target()); @@ -817,6 +818,11 @@ Utils::Id RunControl::runMode() const return d->runMode; } +bool RunControl::isPrintEnvironmentEnabled() const +{ + return d->printEnvironment; +} + const Runnable &RunControl::runnable() const { return d->runnable; @@ -1436,6 +1442,15 @@ void SimpleTargetRunner::start() const QString msg = Tr::tr("Starting %1...").arg(d->m_command.displayName()); appendMessage(msg, NormalMessageFormat); + if (runControl()->isPrintEnvironmentEnabled()) { + appendMessage(Tr::tr("Environment:"), NormalMessageFormat); + runControl()->runnable().environment + .forEachEntry([this](const QString &key, const QString &value, bool enabled) { + if (enabled) + appendMessage(key + '=' + value, StdOutFormat); + }); + appendMessage({}, StdOutFormat); + } const bool isDesktop = !d->m_command.executable().needsDevice(); if (isDesktop && d->m_command.isEmpty()) { diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index d779b693a84..d33d7071625 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -205,6 +205,7 @@ public: void setupFormatter(Utils::OutputFormatter *formatter) const; Utils::Id runMode() const; + bool isPrintEnvironmentEnabled() const; const Runnable &runnable() const; From 963ae0a1927f80347cc643f46e60d3e5a1304008 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 25 Apr 2023 14:56:46 +0200 Subject: [PATCH 0706/1447] ProjectExplorer: Keep "Run" entry in top-level project node visible Enable/disable instead of show/hide, for more stable UI. Fixes: QTCREATORBUG-29042 Change-Id: Ie2c37b3cb127f9dffaf42570f11b2cca6accd3fd Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/projectexplorer/projectexplorer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 33b0b4130d4..e58f00bd056 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3409,7 +3409,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions(Node *currentNode) m_removeFileAction->setVisible(true); m_duplicateFileAction->setVisible(false); m_deleteFileAction->setVisible(true); - m_runActionContextMenu->setVisible(false); + m_runActionContextMenu->setEnabled(false); m_defaultRunConfiguration.clear(); m_diffFileAction->setVisible(DiffService::instance()); @@ -3438,7 +3438,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions(Node *currentNode) if (pn && project) { if (pn == project->rootProjectNode()) { - m_runActionContextMenu->setVisible(true); + m_runActionContextMenu->setEnabled(true); } else { QList runConfigs; if (Target *t = project->activeTarget()) { @@ -3449,7 +3449,7 @@ void ProjectExplorerPluginPrivate::updateContextMenuActions(Node *currentNode) } } if (runConfigs.count() == 1) { - m_runActionContextMenu->setVisible(true); + m_runActionContextMenu->setEnabled(true); m_defaultRunConfiguration = runConfigs.first(); } else if (runConfigs.count() > 1) { runMenu->menu()->menuAction()->setVisible(true); From 382168364785582763d68afc64c832858e87b833 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 21 Apr 2023 22:10:24 +0200 Subject: [PATCH 0707/1447] StyleHelper: Add setter for "panelwidget[_singlerow]" 20 string duplications warrant a centralized setter. A couple more of them will come with the upcoming toolbar changes. Change-Id: Ide8c680da21d5be09f968bcc0a774e062c6f0260 Reviewed-by: Eike Ziller --- src/libs/utils/styledbar.cpp | 8 +++++--- src/libs/utils/stylehelper.cpp | 10 ++++++++++ src/libs/utils/stylehelper.h | 2 ++ src/plugins/debugger/debuggermainwindow.cpp | 10 +++++----- src/plugins/perfprofiler/perfprofilertool.cpp | 5 +++-- .../miniprojecttargetselector.cpp | 2 +- .../curveeditor/curveeditortoolbar.cpp | 8 +++++--- .../components/formeditor/seekerslider.cpp | 5 +++-- .../components/formeditor/toolbox.cpp | 16 +++++++++------- .../timelineeditor/timelinetoolbar.cpp | 5 +++-- .../transitioneditor/transitioneditortoolbar.cpp | 5 +++-- src/plugins/qmlprofiler/qmlprofilertool.cpp | 3 ++- 12 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/libs/utils/styledbar.cpp b/src/libs/utils/styledbar.cpp index a20aba6e1ae..7b00c4b4953 100644 --- a/src/libs/utils/styledbar.cpp +++ b/src/libs/utils/styledbar.cpp @@ -3,6 +3,8 @@ #include "styledbar.h" +#include "stylehelper.h" + #include #include @@ -11,14 +13,14 @@ using namespace Utils; StyledBar::StyledBar(QWidget *parent) : QWidget(parent) { - setProperty("panelwidget", true); - setProperty("panelwidget_singlerow", true); + StyleHelper::setPanelWidget(this); + StyleHelper::setPanelWidgetSingleRow(this); setProperty("lightColored", false); } void StyledBar::setSingleRow(bool singleRow) { - setProperty("panelwidget_singlerow", singleRow); + StyleHelper::setPanelWidgetSingleRow(this, singleRow); } bool StyledBar::isSingleRow() const diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index 9f849b9a612..f27fb2f8fcb 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -634,6 +634,16 @@ QLinearGradient StyleHelper::statusBarGradient(const QRect &statusBarRect) return grad; } +void StyleHelper::setPanelWidget(QWidget *widget, bool value) +{ + widget->setProperty("panelwidget", value); +} + +void StyleHelper::setPanelWidgetSingleRow(QWidget *widget, bool value) +{ + widget->setProperty("panelwidget_singlerow", value); +} + bool StyleHelper::isQDSTheme() { return creatorTheme() ? creatorTheme()->flag(Theme::QDSTheme) : false; diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h index da93bb3c3a5..c7766b0ffeb 100644 --- a/src/libs/utils/stylehelper.h +++ b/src/libs/utils/stylehelper.h @@ -72,6 +72,8 @@ public: static void tintImage(QImage &img, const QColor &tintColor); static QLinearGradient statusBarGradient(const QRect &statusBarRect); + static void setPanelWidget(QWidget *widget, bool value = true); + static void setPanelWidgetSingleRow(QWidget *widget, bool value = true); static bool isQDSTheme(); diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 047fc3ec89b..8dfe23d8b14 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -162,13 +162,13 @@ DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent) { m_centralWidgetStack = new QStackedWidget; m_statusLabel = new Utils::StatusLabel; - m_statusLabel->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(m_statusLabel); m_statusLabel->setIndent(2 * QFontMetrics(q->font()).horizontalAdvance(QChar('x'))); m_editorPlaceHolder = new EditorManagerPlaceHolder; m_perspectiveChooser = new QComboBox; m_perspectiveChooser->setObjectName("PerspectiveChooser"); - m_perspectiveChooser->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(m_perspectiveChooser); m_perspectiveChooser->setSizeAdjustPolicy(QComboBox::AdjustToContents); connect(m_perspectiveChooser, &QComboBox::activated, this, [this](int item) { Perspective *perspective = Perspective::findPerspective(m_perspectiveChooser->itemData(item).toString()); @@ -507,7 +507,7 @@ QWidget *DebuggerMainWindow::centralWidgetStack() void DebuggerMainWindow::addSubPerspectiveSwitcher(QWidget *widget) { widget->setVisible(false); - widget->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(widget); d->m_subPerspectiveSwitcherLayout->addWidget(widget); } @@ -810,7 +810,7 @@ QToolButton *PerspectivePrivate::setupToolButton(QAction *action) { QTC_ASSERT(action, return nullptr); auto toolButton = new QToolButton(m_innerToolBar); - toolButton->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(toolButton); toolButton->setDefaultAction(action); toolButton->setToolTip(action->toolTip()); m_innerToolBarLayout->addWidget(toolButton); @@ -833,7 +833,7 @@ void Perspective::addToolBarWidget(QWidget *widget) { QTC_ASSERT(widget, return); // QStyle::polish is called before it is added to the toolbar, explicitly make it a panel widget - widget->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(widget); widget->setParent(d->m_innerToolBar); d->m_innerToolBarLayout->addWidget(widget); } diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 8362ccc4ed8..b199f227481 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -151,9 +152,9 @@ PerfProfilerTool::PerfProfilerTool() m_filterMenu = new QMenu(m_filterButton); m_aggregateButton = new QToolButton; m_recordedLabel = new QLabel; - m_recordedLabel->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(m_recordedLabel); m_delayLabel = new QLabel; - m_delayLabel->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(m_delayLabel); m_objectsToDelete << m_recordButton << m_clearButton << m_filterButton << m_aggregateButton << m_recordedLabel << m_delayLabel; diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index af9fdf5c50b..558e4fa7122 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -653,7 +653,7 @@ MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorActi QWidget(parent), m_projectAction(targetSelectorAction) { - setProperty("panelwidget", true); + StyleHelper::setPanelWidget(this); setContentsMargins(QMargins(0, 1, 1, 8)); setWindowFlags(Qt::Popup); diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp index 452940aa5f1..27a14968c61 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp @@ -8,7 +8,9 @@ #include "coreplugin/actionmanager/actionmanager.h" #include "coreplugin/icontext.h" #include "theme.h" -#include "utils/id.h" + +#include +#include #include #include @@ -154,8 +156,8 @@ CurveEditorToolBar::CurveEditorToolBar(CurveEditorModel *model, QWidget* parent) m_zoomSlider = new QSlider(Qt::Horizontal); m_zoomSlider->setRange(0, 100); - m_zoomSlider->setProperty("panelwidget", true); - m_zoomSlider->setProperty("panelwidget_singlerow", true); + Utils::StyleHelper::setPanelWidget(m_zoomSlider); + Utils::StyleHelper::setPanelWidgetSingleRow(m_zoomSlider); m_zoomSlider->setFixedWidth(120); connect(m_zoomSlider, &QSlider::valueChanged, [this](int value) { diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp index caa7dcbd307..804f061657a 100644 --- a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp +++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp @@ -4,6 +4,7 @@ #include "seekerslider.h" #include +#include #include #include @@ -15,8 +16,8 @@ namespace QmlDesigner { SeekerSlider::SeekerSlider(QWidget *parent) : QSlider(parent) { - setProperty("panelwidget", true); - setProperty("panelwidget_singlerow", true); + Utils::StyleHelper::setPanelWidget(this); + Utils::StyleHelper::setPanelWidgetSingleRow(this); setOrientation(Qt::Horizontal); setFixedWidth(120); setMaxValue(30); diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp index d10e14e7cb7..acd0b7401b0 100644 --- a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp +++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include #include @@ -17,7 +19,7 @@ ToolBox::ToolBox(QWidget *parentWidget) , m_leftToolBar(new QToolBar(QLatin1String("LeftSidebar"), this)) , m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this)) { - setProperty("panelwidget", false); + Utils::StyleHelper::setPanelWidget(this, false); m_leftToolBar->setFloatable(true); m_leftToolBar->setMovable(true); @@ -29,18 +31,18 @@ ToolBox::ToolBox(QWidget *parentWidget) setFixedHeight(Theme::toolbarSize()); - m_leftToolBar->setProperty("panelwidget", false); - m_leftToolBar->setProperty("panelwidget_singlerow", false); + Utils::StyleHelper::setPanelWidget(m_leftToolBar, false); + Utils::StyleHelper::setPanelWidgetSingleRow(m_leftToolBar, false); m_leftToolBar->setFixedHeight(Theme::toolbarSize()); - m_rightToolBar->setProperty("panelwidget", false); - m_rightToolBar->setProperty("panelwidget_singlerow", false); + Utils::StyleHelper::setPanelWidget(m_rightToolBar, false); + Utils::StyleHelper::setPanelWidgetSingleRow(m_rightToolBar, false); m_rightToolBar->setFixedHeight(Theme::toolbarSize()); m_rightToolBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); auto stretchToolbar = new QToolBar(this); - stretchToolbar->setProperty("panelwidget", false); - stretchToolbar->setProperty("panelwidget_singlerow", false); + Utils::StyleHelper::setPanelWidget(stretchToolbar, false); + Utils::StyleHelper::setPanelWidgetSingleRow(stretchToolbar, false); stretchToolbar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_rightToolBar->setOrientation(Qt::Horizontal); diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp index c920b8b4288..b4ab0583c70 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -430,8 +431,8 @@ void TimelineToolBar::createRightControls() m_scale = new QSlider(this); m_scale->setOrientation(Qt::Horizontal); - m_scale->setProperty("panelwidget", true); - m_scale->setProperty("panelwidget_singlerow", true); + Utils::StyleHelper::setPanelWidget(m_scale); + Utils::StyleHelper::setPanelWidgetSingleRow(m_scale); m_scale->setMaximumWidth(200); m_scale->setMinimumWidth(100); m_scale->setMinimum(0); diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp index 81d6b9a11b0..194a4ad221a 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -249,8 +250,8 @@ void TransitionEditorToolBar::createRightControls() addSpacing(10); m_scale = new QSlider(this); - m_scale->setProperty("panelwidget", true); - m_scale->setProperty("panelwidget_singlerow", true); + Utils::StyleHelper::setPanelWidget(m_scale); + Utils::StyleHelper::setPanelWidgetSingleRow(m_scale); m_scale->setOrientation(Qt::Horizontal); m_scale->setMaximumWidth(200); m_scale->setMinimumWidth(100); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index dc33663e895..a82b6d74e0e 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -197,7 +198,7 @@ QmlProfilerTool::QmlProfilerTool() this, &QmlProfilerTool::toggleVisibleFeature); d->m_timeLabel = new QLabel(); - d->m_timeLabel->setProperty("panelwidget", true); + StyleHelper::setPanelWidget(d->m_timeLabel); d->m_timeLabel->setIndent(10); updateTimeDisplay(); connect(d->m_timeLabel, &QObject::destroyed, &d->m_recordingTimer, &QTimer::stop); From 5e73bacb0ef260c841fb62875948b8f2f9770ca3 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 25 Apr 2023 17:51:25 +0200 Subject: [PATCH 0708/1447] CppEditor: Merge two factories They are closely related, and we might want to add more variants of this functionality. Change-Id: Ida83cce018fad5a84d5f6d24a0fa4ff2bca5a67b Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfix_test.cpp | 4 +- src/plugins/cppeditor/cppquickfixes.cpp | 107 +++++++++++---------- src/plugins/cppeditor/cppquickfixes.h | 26 +---- 3 files changed, 62 insertions(+), 75 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 9c2c011dc5a..badf896a5c9 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -1725,7 +1725,7 @@ void QuickfixTest::testGeneric_data() << _(R"(const char *str = @"\xc3\xa0""f23\xd0\xb1g\xd0\xb1""1";)") << _(R"(const char *str = "àf23бgб1";)"); QTest::newRow("AddLocalDeclaration_QTCREATORBUG-26004") - << CppQuickFixFactoryPtr(new AddLocalDeclaration) + << CppQuickFixFactoryPtr(new AddDeclarationForUndeclaredIdentifier) << _("void func() {\n" " QStringList list;\n" " @it = list.cbegin();\n" @@ -3863,7 +3863,7 @@ void QuickfixTest::testInsertMemberFromInitialization() CppTestDocument::create("file.h", original, expected) }); - InsertMemberFromInitialization factory; + AddDeclarationForUndeclaredIdentifier factory; QuickFixOperationTest(testDocuments, &factory); } diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 1c76f8f2c57..e0671d6412f 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -1646,42 +1646,6 @@ private: } // anonymous namespace -void AddLocalDeclaration::match(const CppQuickFixInterface &interface, QuickFixOperations &result) -{ - const QList &path = interface.path(); - CppRefactoringFilePtr file = interface.currentFile(); - - for (int index = path.size() - 1; index != -1; --index) { - if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) { - if (binary->left_expression && binary->right_expression - && file->tokenAt(binary->binary_op_token).is(T_EQUAL)) { - IdExpressionAST *idExpr = binary->left_expression->asIdExpression(); - if (interface.isCursorOn(binary->left_expression) && idExpr - && idExpr->name->asSimpleName() != nullptr) { - SimpleNameAST *nameAST = idExpr->name->asSimpleName(); - const QList results = interface.context().lookup(nameAST->name, file->scopeAt(nameAST->firstToken())); - Declaration *decl = nullptr; - for (const LookupItem &r : results) { - if (!r.declaration()) - continue; - if (Declaration *d = r.declaration()->asDeclaration()) { - if (!d->type()->asFunctionType()) { - decl = d; - break; - } - } - } - - if (!decl) { - result << new AddLocalDeclarationOp(interface, index, binary, nameAST); - return; - } - } - } - } - } -} - namespace { class ConvertToCamelCaseOp: public CppQuickFixOperation @@ -2980,25 +2944,64 @@ private: const QString m_type; }; -void InsertMemberFromInitialization::match(const CppQuickFixInterface &interface, +void AddDeclarationForUndeclaredIdentifier::match(const CppQuickFixInterface &interface, QuickFixOperations &result) { - // First check whether we are on a member initialization. + if (!checkForMemberInitializer(interface, result)) + return; + + const CppRefactoringFilePtr &file = interface.currentFile(); const QList path = interface.path(); + for (int index = path.size() - 1; index != -1; --index) { + if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) { + if (binary->left_expression && binary->right_expression + && file->tokenAt(binary->binary_op_token).is(T_EQUAL)) { + IdExpressionAST *idExpr = binary->left_expression->asIdExpression(); + if (interface.isCursorOn(binary->left_expression) && idExpr + && idExpr->name->asSimpleName() != nullptr) { + SimpleNameAST *nameAST = idExpr->name->asSimpleName(); + const QList results = interface.context().lookup( + nameAST->name, file->scopeAt(nameAST->firstToken())); + Declaration *decl = nullptr; + for (const LookupItem &r : results) { + if (!r.declaration()) + continue; + if (Declaration *d = r.declaration()->asDeclaration()) { + if (!d->type()->asFunctionType()) { + decl = d; + break; + } + } + } + + if (!decl) { + result << new AddLocalDeclarationOp(interface, index, binary, nameAST); + return; + } + } + } + } + } +} + +bool AddDeclarationForUndeclaredIdentifier::checkForMemberInitializer( + const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) +{ + const QList &path = interface.path(); const int size = path.size(); if (size < 4) - return; + return true; const SimpleNameAST * const name = path.at(size - 1)->asSimpleName(); if (!name) - return; + return true; const MemInitializerAST * const memInitializer = path.at(size - 2)->asMemInitializer(); if (!memInitializer) - return; + return true; if (!path.at(size - 3)->asCtorInitializer()) - return; + return true; const FunctionDefinitionAST * ctor = path.at(size - 4)->asFunctionDefinition(); if (!ctor) - return; + return false; // Now find the class. const Class *theClass = nullptr; @@ -3011,30 +3014,31 @@ void InsertMemberFromInitialization::match(const CppQuickFixInterface &interface // Out-of-line constructor. We need to find the class. SymbolFinder finder; const QList matches = finder.findMatchingDeclaration( - LookupContext(interface.currentFile()->cppDocument(), interface.snapshot()), - ctor->symbol); + LookupContext(interface.currentFile()->cppDocument(), interface.snapshot()), + ctor->symbol); if (!matches.isEmpty()) theClass = matches.first()->enclosingClass(); } if (!theClass) - return; + return false; // Check whether the member exists already. if (theClass->find(interface.currentFile()->cppDocument()->translationUnit()->identifier( - name->identifier_token))) { - return; + name->identifier_token))) { + return false; } const QString type = getType(interface, memInitializer, ctor); const Identifier * const memberId = interface.currentFile()->cppDocument() - ->translationUnit()->identifier(name->identifier_token); + ->translationUnit()->identifier(name->identifier_token); const QString member = QString::fromUtf8(memberId->chars(), memberId->size()); result << new InsertMemberFromInitializationOp(interface, theClass, member, type); + return false; } -QString InsertMemberFromInitialization::getType( +QString AddDeclarationForUndeclaredIdentifier::getType( const CppQuickFixInterface &interface, const MemInitializerAST *memInitializer, const FunctionDefinitionAST *ctor) const @@ -9072,7 +9076,6 @@ void createCppQuickFixes() new SplitIfStatement; new SplitSimpleDeclaration; - new AddLocalDeclaration; new AddBracesToIf; new RearrangeParamDeclarationList; new ReformatPointerDeclaration; @@ -9089,7 +9092,7 @@ void createCppQuickFixes() new GenerateGettersSettersForClass; new InsertDeclFromDef; new InsertDefFromDecl; - new InsertMemberFromInitialization; + new AddDeclarationForUndeclaredIdentifier; new InsertDefsFromDecls; new MoveFuncDefOutside; diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h index 376bfa99bf4..c6d4c8eb136 100644 --- a/src/plugins/cppeditor/cppquickfixes.h +++ b/src/plugins/cppeditor/cppquickfixes.h @@ -284,23 +284,6 @@ public: void match(const CppQuickFixInterface &interface, QuickFixOperations &result) override; }; -/*! - Rewrites - a = foo(); - - As - Type a = foo(); - - Where Type is the return type of foo() - - Activates on: the assignee, if the type of the right-hand side of the assignment is known. -*/ -class AddLocalDeclaration: public CppQuickFixFactory -{ -public: - void match(const CppQuickFixInterface &interface, QuickFixOperations &result) override; -}; - /*! Add curly braces to a if statement that doesn't already contain a compound statement. I.e. @@ -374,16 +357,17 @@ public: void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override; }; -/*! - Adds a class member from an initialization in the constructor. - */ -class InsertMemberFromInitialization : public CppQuickFixFactory +class AddDeclarationForUndeclaredIdentifier : public CppQuickFixFactory { public: void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override; private: + // Returns whether to still do other checks. + bool checkForMemberInitializer(const CppQuickFixInterface &interface, + TextEditor::QuickFixOperations &result); + QString getType( const CppQuickFixInterface &interface, const CPlusPlus::MemInitializerAST *memInitializer, From 0ec89bc10f3527e1c78ec0b3c9968a2bfaa6c85e Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 17:09:06 +0200 Subject: [PATCH 0709/1447] Qnx: Allow kit creator creation per target architecture So far there were always kits for "all" (usually three?) archs created, leaving n-1 of them in an typically unused but expensive to validate state. Change-Id: I78c7ed3faea0829104dc62bf358e9e1c62082b01 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/qnx/qnxsettingspage.cpp | 59 +++++++++++++++++++---------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index c12da720c89..615851eeb3a 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -483,6 +484,32 @@ static QnxSettingsPagePrivate *dd = nullptr; // QnxSettingsWidget + +class ArchitecturesList final : public QWidget +{ +public: + void setConfiguration(const FilePath &envFile) + { + m_envFile = envFile; + delete layout(); + + QnxConfiguration *config = dd->configurationFromEnvFile(envFile); + if (!config) + return; + + auto l = new QHBoxLayout(this); + for (const QnxTarget &target : config->m_targets) { + auto button = new QPushButton(tr("Create Kit for %1").arg(target.cpuDir())); + connect(button, &QPushButton::clicked, this, [config, target] { + config->createKit(target); + }); + l->addWidget(button); + } + } + + FilePath m_envFile; +}; + class QnxSettingsWidget final : public Core::IOptionsPageWidget { public: @@ -510,7 +537,6 @@ public: void addConfiguration(); void removeConfiguration(); - void generateKits(bool checked); void updateInformation(); void populateConfigsCombo(); @@ -518,12 +544,14 @@ public: private: QComboBox *m_configsCombo = new QComboBox; - QCheckBox *m_generateKitsCheckBox = new QCheckBox(Tr::tr("Generate kits")); QLabel *m_configName = new QLabel; QLabel *m_configVersion = new QLabel; QLabel *m_configHost = new QLabel; QLabel *m_configTarget = new QLabel; - QLabel *m_architecturesLabel = new QLabel; + QLabel *m_compiler = new QLabel; + QLabel *m_architectures = new QLabel; + + ArchitecturesList *m_kitCreation = new ArchitecturesList; QList m_changedConfigs; }; @@ -538,7 +566,6 @@ QnxSettingsWidget::QnxSettingsWidget() Row { Column { m_configsCombo, - Row { m_generateKitsCheckBox, st }, Group { title(Tr::tr("Configuration Information:")), Form { @@ -546,9 +573,11 @@ QnxSettingsWidget::QnxSettingsWidget() Tr::tr("Version:"), m_configVersion, br, Tr::tr("Host:"), m_configHost, br, Tr::tr("Target:"), m_configTarget, br, - Tr::tr("Architectures:"), m_architecturesLabel + Tr::tr("Compiler:"), m_compiler, br, + Tr::tr("Architectures:"), m_architectures } }, + Row { m_kitCreation, st }, st }, Column { @@ -566,8 +595,6 @@ QnxSettingsWidget::QnxSettingsWidget() this, &QnxSettingsWidget::removeConfiguration); connect(m_configsCombo, &QComboBox::currentIndexChanged, this, &QnxSettingsWidget::updateInformation); - connect(m_generateKitsCheckBox, &QAbstractButton::toggled, - this, &QnxSettingsWidget::generateKits); connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged, this, &QnxSettingsWidget::updateInformation); } @@ -630,32 +657,26 @@ void QnxSettingsWidget::removeConfiguration() } } -void QnxSettingsWidget::generateKits(bool checked) -{ - const FilePath envFile = m_configsCombo->currentData().value(); - setConfigState(envFile, checked ? Activated : Deactivated); -} - void QnxSettingsWidget::updateInformation() { const FilePath envFile = m_configsCombo->currentData().value(); if (QnxConfiguration *config = dd->configurationFromEnvFile(envFile)) { config->ensureContents(); - m_generateKitsCheckBox->setEnabled(config->isValid()); - m_generateKitsCheckBox->setChecked(config->isActive()); m_configName->setText(config->m_configName); m_configVersion->setText(config->m_version.toString()); m_configHost->setText(config->m_qnxHost.toString()); m_configTarget->setText(config->m_qnxTarget.toString()); - m_architecturesLabel->setText(config->architectureNames()); + m_compiler->setText(config->m_qccCompiler.toUserOutput()); + m_architectures->setText(config->architectureNames()); + m_kitCreation->setConfiguration(envFile); } else { - m_generateKitsCheckBox->setEnabled(false); - m_generateKitsCheckBox->setChecked(false); m_configName->setText({}); m_configVersion->setText({}); m_configHost->setText({}); - m_architecturesLabel->setText({}); + m_compiler->setText({}); + m_architectures->setText({}); + m_kitCreation->setConfiguration({}); } } From 5a341e087fca1c20e14d5281daea3f42ebcf2dbf Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 20:55:18 +0200 Subject: [PATCH 0710/1447] LocatorFiltersFilter: Reimplement matchers() Change-Id: I59d7f005e9e044b0375cb94254392f23a330f3f0 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../locator/locatorfiltersfilter.cpp | 44 +++++++++++++++++++ .../coreplugin/locator/locatorfiltersfilter.h | 2 + 2 files changed, 46 insertions(+) diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index b8c05aae97e..4ac12091ffc 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -12,6 +12,8 @@ Q_DECLARE_METATYPE(Core::ILocatorFilter*) +using namespace Utils; + namespace Core::Internal { LocatorFiltersFilter::LocatorFiltersFilter(): @@ -25,6 +27,48 @@ LocatorFiltersFilter::LocatorFiltersFilter(): setConfigurable(false); } +LocatorMatcherTasks LocatorFiltersFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [=] { + if (!storage->input().isEmpty()) + return true; + + QMap uniqueFilters; + const QList allFilters = Locator::filters(); + for (ILocatorFilter *filter : allFilters) { + const QString filterId = filter->shortcutString() + ',' + filter->displayName(); + uniqueFilters.insert(filterId, filter); + } + + LocatorFilterEntries entries; + for (ILocatorFilter *filter : std::as_const(uniqueFilters)) { + const QString shortcutString = filter->shortcutString(); + if (!shortcutString.isEmpty() && !filter->isHidden() && filter->isEnabled()) { + LocatorFilterEntry entry; + entry.displayName = shortcutString; + entry.acceptor = [shortcutString] { + return AcceptResult{shortcutString + ' ', int(shortcutString.size() + 1)}; + }; + entry.displayIcon = m_icon; + entry.extraInfo = filter->displayName(); + entry.toolTip = filter->description(); + QString keyboardShortcut; + if (auto command = ActionManager::command(filter->actionId())) + keyboardShortcut = command->keySequence().toString(QKeySequence::NativeText); + entry.displayExtra = keyboardShortcut; + entries.append(entry); + } + } + storage->reportOutput(entries); + return true; + }; + return {{Sync(onSetup), storage}}; +} + void LocatorFiltersFilter::prepareSearch(const QString &entry) { m_filterShortcutStrings.clear(); diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.h b/src/plugins/coreplugin/locator/locatorfiltersfilter.h index 7ad19f8c4dd..e1cf75a75bf 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.h +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.h @@ -28,6 +28,8 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + LocatorMatcherTasks matchers() final; + QStringList m_filterShortcutStrings; QStringList m_filterDisplayNames; QStringList m_filterDescriptions; From eb41e98b00c7bb10e246f343d85b031c6e23c3d1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 21:04:20 +0200 Subject: [PATCH 0711/1447] ClangCodeModel: Reimplement matchers() Change-Id: I2d541e24347aa47ec41f88cd7d18004dee7197cf Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler Reviewed-by: --- .../clangcodemodel/clangdlocatorfilters.cpp | 129 +++++++++++++++++- .../clangcodemodel/clangdlocatorfilters.h | 1 + 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 097b9f495a8..1f4db567def 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -12,12 +12,15 @@ #include #include #include +#include +#include #include #include #include #include -#include #include +#include +#include #include @@ -25,6 +28,7 @@ using namespace Core; using namespace LanguageClient; using namespace LanguageServerProtocol; using namespace ProjectExplorer; +using namespace TextEditor; using namespace Utils; namespace ClangCodeModel { @@ -212,6 +216,7 @@ LocatorMatcherTasks ClangFunctionsFilter::matchers() ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); } +// TODO: Remove this class, it's used only internally by ClangdCurrentDocumentFilter class LspCurrentDocumentFilter : public DocumentLocatorFilter { public: @@ -341,6 +346,128 @@ ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private) ClangdCurrentDocumentFilter::~ClangdCurrentDocumentFilter() { delete d; } +static void filterCurrentResults(QPromise &promise, const LocatorStorage &storage, + const CurrentDocumentSymbolsData ¤tSymbolsData, + const QString &contents) +{ + Q_UNUSED(promise) + struct Entry + { + LocatorFilterEntry entry; + DocumentSymbol symbol; + }; + QList docEntries; + + const auto docSymbolModifier = [&docEntries](LocatorFilterEntry &entry, + const DocumentSymbol &info, + const LocatorFilterEntry &parent) { + entry.displayName = ClangdClient::displayNameFromDocumentSymbol( + static_cast(info.kind()), info.name(), + info.detail().value_or(QString())); + entry.extraInfo = parent.extraInfo; + if (!entry.extraInfo.isEmpty()) + entry.extraInfo.append("::"); + entry.extraInfo.append(parent.displayName); + + // TODO: Can we extend clangd to send visibility information? + docEntries.append({entry, info}); + return entry; + }; + // TODO: Pass promise into currentSymbols + const LocatorFilterEntries allMatches = LanguageClient::currentDocumentSymbols(storage.input(), + currentSymbolsData, docSymbolModifier); + if (docEntries.isEmpty()) { + storage.reportOutput(allMatches); + return; // SymbolInformation case + } + + QTC_CHECK(docEntries.size() == allMatches.size()); + QHash> possibleDuplicates; + for (const Entry &e : std::as_const(docEntries)) + possibleDuplicates[e.entry.displayName + e.entry.extraInfo] << e; + const QTextDocument doc(contents); + for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { + const QList &duplicates = it.value(); + if (duplicates.size() == 1) + continue; + QList declarations; + QList definitions; + for (const Entry &candidate : duplicates) { + const DocumentSymbol symbol = candidate.symbol; + const SymbolKind kind = static_cast(symbol.kind()); + if (kind != SymbolKind::Class && kind != SymbolKind::Function) + break; + const Range range = symbol.range(); + const Range selectionRange = symbol.selectionRange(); + if (kind == SymbolKind::Class) { + if (range.end() == selectionRange.end()) + declarations << candidate; + else + definitions << candidate; + continue; + } + const int startPos = selectionRange.end().toPositionInDocument(&doc); + const int endPos = range.end().toPositionInDocument(&doc); + const QString functionBody = contents.mid(startPos, endPos - startPos); + + // Hacky, but I don't see anything better. + if (functionBody.contains('{') && functionBody.contains('}')) + definitions << candidate; + else + declarations << candidate; + } + if (definitions.size() == 1 + && declarations.size() + definitions.size() == duplicates.size()) { + for (const Entry &decl : std::as_const(declarations)) { + Utils::erase(docEntries, [&decl](const Entry &e) { + return e.symbol == decl.symbol; + }); + } + } + } + storage.reportOutput(Utils::transform(docEntries, + [](const Entry &entry) { return entry.entry; })); +} + +LocatorMatcherTask currentDocumentMatcher() +{ + using namespace Tasking; + + TreeStorage storage; + TreeStorage resultStorage; + + const auto onQuerySetup = [=](CurrentDocumentSymbolsRequestTask &request) { + Q_UNUSED(request) + }; + const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequestTask &request) { + *resultStorage = request.currentDocumentSymbolsData(); + }; + + const auto onFilterSetup = [=](AsyncTask &async) { + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage, + TextDocument::currentTextDocument()->plainText()); + }; + + const Group root { + Storage(resultStorage), + CurrentDocumentSymbolsRequest(onQuerySetup, onQueryDone), + Async(onFilterSetup) + }; + return {root, storage}; +} + +LocatorMatcherTasks ClangdCurrentDocumentFilter::matchers() +{ + const auto doc = TextDocument::currentTextDocument(); + QTC_ASSERT(doc, return {}); + if (const ClangdClient *client = ClangModelManagerSupport::clientForFile(doc->filePath()); + client && client->reachable()) { + return {currentDocumentMatcher()}; + } + return CppEditor::cppMatchers(MatcherType::CurrentDocumentSymbols); +} + void ClangdCurrentDocumentFilter::prepareSearch(const QString &entry) { const auto doc = TextEditor::TextDocument::currentTextDocument(); diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index 384edeab588..8074c95c9ac 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -54,6 +54,7 @@ public: ~ClangdCurrentDocumentFilter() override; private: + Core::LocatorMatcherTasks matchers() final; void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; From e7b5e64a706fd20d3eaa0cdbf340b6322942ada8 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 25 Apr 2023 16:12:45 +0200 Subject: [PATCH 0712/1447] Doc: Remove detailed info about wizard templates Improve descriptions of some wizard templates. Task-number: QTCREATORBUG-28996 Change-Id: Ib53fa38918120af60a03f3850fed7db1e6f0c391 Reviewed-by: Eike Ziller --- doc/qtcreator/images/qtcreator-new-file.webp | Bin 0 -> 17272 bytes .../src/howto/creator-keyboard-shortcuts.qdoc | 2 +- .../creator-only/creator-files-creating.qdoc | 145 +++------------- .../creator-projects-build-systems.qdocinc | 16 +- .../creator-projects-creating.qdoc | 163 ++++-------------- .../src/python/creator-python-project.qdocinc | 4 +- .../creator-only/qt-design-viewer.qdoc | 2 +- .../creator-only/qtquick-creating.qdoc | 60 ++----- ...uick-tutorial-create-empty-project.qdocinc | 2 +- .../src/qtquick/qtquick-live-preview.qdoc | 2 +- .../templates/wizards/codesnippet/wizard.json | 2 +- .../wizards/projects/consoleapp/wizard.json | 2 +- .../wizards/projects/cpplibrary/wizard.json | 2 +- .../projects/qtquickapplication/wizard.json | 2 +- .../projects/qtquickuiprototype/wizard.json | 2 +- .../projects/qtwidgetsapplication/wizard.json | 2 +- .../mcusupport/wizards/qmlproject/wizard.json | 2 +- 17 files changed, 99 insertions(+), 311 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-new-file.webp diff --git a/doc/qtcreator/images/qtcreator-new-file.webp b/doc/qtcreator/images/qtcreator-new-file.webp new file mode 100644 index 0000000000000000000000000000000000000000..4429f37cd3c6315bfbc791a0c90c6aee2ff914eb GIT binary patch literal 17272 zcmWIYbaN|kW?%?+bqWXzu<%KCW?;}ic=QItSH8z)lSD$xpUZzWlCe=vVsfai)-TDL z=C$to7qczeoy(Yy$ax&vl2+9^<(_1Qi0-)yMe7$%dyRlg2*IQ+cMH5EH*Ga6`!STFynD zNe{0!tzM}9d4q2kmusuk#fYzO-j;bs_c?e@%D%no@f$^v@Y>x5JZaItF3ondSbU=9 zlCQCD+M7i)Wz*8q{zR8;%gw%R(;vvaWBMbb$&raO7F0|Tv6gA^%TY1Xz zR{Noo6P);r-RFL+uQ;~wqsO*wXLD!$=Zcx2Gx?se@uVFGzNB0|J!zBgT}JQC-u$vx zj(PcKm}{yVizDWvUp(q@0tC@_N^3)x1>Fd1`ah z`i1|CZn#ZS(Jc9Y_RWU#FK)?x_VK)JFS+eAWAWx)HhZ?^-riT-`{F_LJxkkKfv~Jc zn|JMw(7vj+?d;TZle;#1mu-7!ux+i{tNq5Y59-fErm3cTIn3CW+q~ge;k9~;2`ZLd zMSK@OB&eVb2?zFs0Ay`Q#S$czhJ`@?qe- z@l>f-hQVFr;~i7`FqXFOwLKFa-kl%D;OX@x^^er4Enyq}-`VV+b)fiq41c~?TL$Z@ zc8#?=Kbx=|zrJR#)F}au+a@({uNJ?z+jv;+Quq>+4XU;(hi3Hn*c`p|;H%ZI|IDRF zCmSi93Mg7~F2d+S#;@1Bv+dUiYN|>!Z~g6mB4DawKxRi!uZ7(n>zOlW-rSz=n!tL7 zC)AtY$oxw*RXb z+oEKjtjsZF+@28N(r_kxZKLtbM7O=EPkwi=omRv(yHp}Ov-o@VoSQbAGr3O2GFF?+ zxGfQpI`Lqf_x>yg!Rh|mDa;LBU z>#ofUKK$-7RiAfBW+s;s_lw!-T0C{StX+Jw&xcRyILG6ueqeuq#8z{S4fCtH&Ac*q zKZSC8WjNi>`gv#7<_jgeWaT*c+=FDSCQE)0>FQZt;(PX{ z5lgg7_+oXV!|Fd!OMo2*WI_fAD&5l_fUW!bLjI?3xa|&#_Xp?%rBmJSP`X6zV zmGjo`J9vh3sy=^c|6VuSFTxUzB`z9!qt5Jgby~~)Lh9u=!Pd{zEYGtTIMFT?^wXHqYq#6oY`)mvw?Hs{vTJX z)ky9)o5xY~-}ZR3pp$Y3TaKDlTjkd~yZsOC@mXeE?Bw)Pr1#Yt>93Ba0)40WZconm zt)74PPvP^k@%8`b{GET#;qbB$LOiL$?pl#gx?Q;RdbYE)mG7khM)?ZeK5>2f=mH6{dXTv{7BgGIc( zS9Pi1L${SW8sZkFqbf(VRu%PefY#V2TEB6@4wO`CCrU;*_hgBWV)BcO^t}ylZeC}ue zXZh#$a2bQgw!-&4?>XM{Q~P3aqju}pqq|kl9dG!OmsMH#_0NNxnniV8^VW;MYMEPh zKK|#VgSSs!EfasQ@;UwWWuMrDtS0~Kd$a1c-#wb}kF%QQKLFW@V;cEiSRAiH;|xOD1FzxZyaWB(WIQ@gcFJ9_bgOSg7jtk%!^ z|A6)Porc?6D;xQDIZHSl5%b$AxjE82EXw?`#lPLsmabRKvNL<)BJNgYTO9g(Bq;E? z%Hp2;))D%9wzn^i4GWFp&D*j3u*Tixr_xHf>sG&>SY<01@O;azuZKN0zmtA4<-7LY zO&#ZZ-mx4z+q+=;vdZZ4ZXHcdGp)}WCt812PI-Fjhq=Da#`+Hpexe_`ZZI*Y-Fo}u z&_u(4hOVo5bGK!=NSli)+L_0cm zJu=BEx|c&#wXMWw?$USLrK1Fe9^GH0J88n&l`-w#vz|Hx9CQ_^J@dE1^MCd4gk1G6 zj#?X=gEGJEZFW!%HNPG5DSUdhSI?%7*>PVNa%HgpJjpz{D2Z#LX)POD=g0i#!nbPv zR=J%o^Zs@t&*ja{a}3k3D7u9t88BYnY}a-0=AW}pmskoK7bur3T;$^N>@}~#*6FH$ zw@XKvI%GRWseF}7J&|yGRa=*XT%ocL(|5B2t0zp!WC#@s+v)l>v^I;iHTUvajT?L{ zg3d>UIFA?n*x48*a$s4)(wk>K&SbRf6Vv2c-Wimmx@h9;rhw&@o}3vftU>(>4N>n| z{v_`;>grgrLg5Od&w-K)&z)HfW@M*)<>4-tDdS79xWVJ?ac*D0KK968P7}YJIpe|? zoiQ!K+I@e{YIWmBVN9XBw4!2_l9ucgoKO)jw11MKTYT@-$DU08mH85;9(lF3W$7o? z&C1uRnV-gT`x-x?5?bnZ=qfb*{9CTAKmrwF>R z&E=34e0(qN%=$%_Z7yps-gLP`*z)q}otzU6o}9uMe%#2I54%3Y|Q0Ijglu!nJ_P zoS2+4DgEZd2g8)k`Y9#la`dXUG2K;`><0k#dgd zU4yKgV!@Xb2a`Kh=UAUSczUDAr>Oq+)7OmCGOx4ky70DEkumP9*PGWY8SaN?3q4xm zV$hmxyY!iw8k?tCO%GUZvP_BMeSLe;eeo&zd#|WI(NHKB-&CN| zUZvU_*m0`BU~5jaHsdYD-btn#cFw)G$+EmUxY@ks^Wn*Jf;o6%cqeR5-pIx{kK_8Q zPmlVyOgQjW?DV!3N}3Mu=5ES-K68sxVDG-Db*fL|nErUJF=A;nS~Phr=ZUfMVbUO`JEKKeDG{*nd=q*bqt>-uA0Q9Xf)&3 zFFpQ|?-Lbe$8E8AWyp7JuIGsx=bhv3zR+p`N@ zbQdZ_vv{3iX_T~>ptM>-Z)!8MYU_qdGj*edrwo{P9{(-MSynLFyFkZ%SKOy>5^~A; zPkl~rxcA0tn&JCdvm?DXykD4OmYld&H~m20`UP24J11w5e%JjP6|4EafP1J5eSOsyaX3tLX91+nn#7-_ea+e*4Xg z+kf8h8C#o*%W=GUu)XTjo|`&*DYG@ssWu+!N|feu3<~QA+kP$R zM%p}u=!k-U!RkE>*<21mVGZ9huJp6!<_V|#{Nves|(+nOx5Uww0X!{aG`UF(x177EF$WPRB--TYSE9)@d`w+#$LmNk8r zXE817UK{P7yJ7FTrVp+g&Y3rDi_ZEHwfk9lbbL7TKerpfe-oV(4kwtF)o*=&aP770 zR~znsHk$D7uYFO$dE3wL>vp8wpY620t6g<2w6Yg@{;>Cefbg@=2LvX6n4WUu{IGG(NwUwvL8e)Zz^n*YykRCvfOy|eYv{*7BLZe8UzxDqK+Ul{Vit;EKj;^{3C16BaCu^JkF|3X|yE8ocp}-J8wR-CLLMV#xn?!p!)PLmI33@j~Ha zdr!^KwfkLlLDfO{;fc6=c3Vo+E|jPpEw$Nb5HE1)=-*BM-`vSq$ahJwzOanRWR7R@ z7pW#y|C+$pb@6I(9i5s=9>)*q?6i93d?o)t$o#u&e@u7y_DexF<Q#jp#J}A=9VdFZlj$Ynz9gX;rx%`?BFDU<=J1yLqR$P5Plh#3J;yNX+=3t7hYv~5514U&kYs8{gj$vOWgGV+_jy9z@tbfjVs0!> z7ufjdtAp^i?ET+Ee$}17tfxBZhJ^K`(8dX+!lI7f)~U3!X9z4j_bBaI=z`cg-5dq+ zUoXhro;3UUk}dO}+&STyQM{QidRP9QxHRwY3vF}uGTb_9`u%f5_H&0Mz0~QxoM&%p zW;ELWa4+C4uNG9D-nIK%T)lCb)!&!~3;A~;3t}_E1QIPSMke|?d8ggj;=X?E`uV%d zzC=x0+#~JxzIVTeW6O!R&zBgmF{WtDE^Ev`bw_t`{`LPq+;Xn-?zebS^~{-R?V0U8 z`+Ps`)ZOo~r+sZjTSV_PkpZce6gMPGZly z5~Xde#s5Sm1mv(pb@p{{I^FyC@@avMK3~44E<5;I?*AgYUu;S*#naNn_i727255Lk zPc>2f@S9ClYw>|H##+lw2fmB%Xh~o@+LK~^;PbcrmbR^zoQn(IaE7?eKT+V>IH}s; zgrKN2=bbe*$qXC1cX$5`zHnEd_xpxOf!jAbryYBIWrm86`2H7y%aZpTi(0<)YV*{4 z>sM`YV9q{QDd4-m?b^H-Z@T%n?6O<%>b%+WDi0gqT{rW#?B$Z0TWiR8p`Z5~%fv6) zE7UH2%ScN3c9dm_9KXbUJ1!oBnMN1CWM{nXJZBd@x!|uZBJzI8lB+dk~&>iTUVGJR_{hvu!VP2Vdt-Z%uNXrF&3Y&4l^fsLNc#|_P~LF-jo zH)uX)(Dj+2Vl#R7n!HTOzf8BLsxHAmZtBt=RpKw~f`6#QV$TK6_+W7s$-o@VfMJHqae8_j4 zqj;!}SGIQRlE0Ikjn=E2_@n$HG~mMVg%f(R&TptSU9@xBh5)xsJ0Eyw@!jB?9sK%W zm*>K(#fv1jElyGOj1hX}8@NvLaE-_;Th5CYqJAft2<)m1X+K>1?v>F}-Nm)vR7=*2 z3!FZ9ck|51|C#TvEnN`wW#|9pvNv~sG4y)7)JI;9^<(>ss-u^t?>K%wDBkVD>IF&t z=Qvf(b|~z1W4RRRYQL9HL{;tbrrKxjCRKhR>s3^~&P)+5c06OBC4Q1Sc7j@I-z+w} z#a$w<;0$0L}m}klI^u>6{mr8*;tr(u|qxUeFz~ zpY4qA13j%sJjT7ORU%y!)=mT=ZH z-L9SCbGu=>PGz}Bf#z!e=qUXOB0tan&wQ(rX1g|Wg5WHVD$yy=9<#_czDTj= zE`QEEy(8*MZ>|SyJmrI@9!+ud;d7My;`^G zM(CDZS3dlI&3*Umk^|xfwMHIqJ|;NK30{5rb1KK|;sU!*Nh-?(9k-k`K4tE#aAvdN z(RSIyyXDD6mFlb%*x~E*54BNh9_i^mD%Jq>E*LcT;&09}`V`(JpZ!d$z#USwcBOPCapNFe!YC!>|F=f&(5x|&tbitnxlJVt#I$;bmquo zmlDfe=3jnRByxXF$yNP}JM_-lzcTK8Y;?M+fmed}{14`HeFrQ1oNsL0bw_%BM(ODn z^-P6vJ&6|YuSm!VeA#(@uJ@OPYr};tQ}ZlyI^v9^t8zqVcTVw}seZ1E|7^*oKl^^Q zQygZ9g}jr zG2y<=ii^hS$%me=S4lqgT-@1b*{N&mR<101nDj>c>enSQdP0sug8SRe%i{`8=Ev{b zVHCFfzp!Pa*~!3d2Skn^eBv4DH#a7r=s1_r@nY`2ReWX~eVZEBd@u>nPsrrYaO&ET z{iaw`t;g=Bxv8Wa`e*}MKNktPw=N6$r!i&b z*^;ia9vz};?;Q_2*k?5uCZ1S6M{co(w)$0X@56^1?8?8Kl$)oq^?)Xy@ocTsZ)NYo zJpWaE{?rrJ-V(d@wF{5ddq$HVFW-89d~$H5e&n1@PCXAEGIK5eX`_FY-Em*%D@IKl z!(y$Lxlg$ZkBLZ4dlr*%%1^7`Oub=7$db(p+jo5se-Np0rc$IkfXiRHH@CHjn{~n! zX@?>SgW^-?*RBy1+$r+u-;Ae+L%%Q8nIBR<&9Kj_cH)93pScx}1uxxydxFE_<>#f6 z~^XF*yFeNY9@nHGR<)3q(xW@Lc(r>rt%N4nH@R+IAbNyp=MMcbW6xEMy5L|kF zxjySl%ZoEVJ~$O^-+5g8op1aK<@byZjj0P%x$n;|u#X5iYS?7_WWj!6vFi)YR}{Lv znz?{S-(tF#AnS2~zQc^`f4N+~b#757`xAj^$<;0Vqxdrh%g#{M9eKs+9+QA(cTmym?EZPcY1unku-E@Ku zE9;wk)sh?bP26;|eNzUbZ9a$h>%cQk3@5MMnV#^^`FD}vGS!~mT^TKmwrrLE4Bne0 z*ga3@YnAvM^R_Ta%r5w;!}PAIwONmD99q1}+*F^<$nKV&aK!mfattmf6ob7qr(X*G z(lqmGm$7ANV^XTkC!Kep1{NDkpUp5zNM88Yh>v@#FMHit0T?Knew|-gl=?Ps+BXJ!gT6B!3bUq9t7iUM^XRm}l2gKp-Nn0XCst3q@Z`$gB^-*! z)$Fv5Ocse;XT2E}og%$->jXn<0hX38RY9jdO}$~=y)jm%SdZ!84D++k^^Z^0cK6?Y zgdup^`H=EH{Wu#omiE=zfs*n@(+(TTY5%=>;m*mV(p}5bIwE7V^2%a1PJKPW<#EjQ zSv#Gg@+_K6M{* zG_J2*Rd+C1hu`|ZGxKfwJU7CET3SA)YFubYQEqv4`k2n<4F~sEhI~48vVYn%a}J;R zyC>k`tuK9JLNnLGsCwA-$Fjp05S8GY;IR3C< zxnxWm+diM?v-PK@eis%h)Sr8$pW`C0x=T3gjNk)5OJCKxskJN;x&F5;_o%q9#??$0 zf%i&29@a`lF;-WkH$2|hW9hU!-#UQP?W*T7c1bgj2j9*t(p5UbA?N7u(8N0R=Kcxq zx9+O=t=y$Jhat!B=e8)%e8t~dtMa~X?$~Yp-Z&?5f+zR3Uz2_*^jQv@rcE_jwcxug2p&86?|jJ87?dG+J@y|Se0eU@Z4?f6-FTtQGJ zn=M9hgP^1Dr4-pUem==u%r`$7{^`&y?Do%l#;f0}c~9p%(|66@$eI}Y|DJ0Pe7KbG zN%CuI<>kEXxAnx%y?n+#|Hir5vg+*orvEGp&L8-2$(CIyv4_RiCv0oi@fn<9S<(qo z-sOLeYW-JamU-;?Sm1L^kj&zYy?+~Xf{wju47|48$Le-Yi88Z;LOsuZR^?AAweqHV zPcmv(+2!&YUg^94!sd+BTRrY`9WyT*t2}>m=S#0M$J6wu7qfCY^79m~^xfA;IoQ;= zczS@r#=VZrllZTlxZM6a`Kh|%kB6r}OjxM6XJ=!Ab=~7@m1iWjaLQG_u?d~Oo!de_ z<3Uj9)$NbwJ1qZP`e|QQ!H-GpE7ZFMBIf={bR0 z*JrKB)hXsHv-6izt+u+akY<`78}PTQ#yX_`;>&aU-J6@mZzx<~SkjVpwr0Vr?`&2N zuQ6UUf4tr?)YkPMgZ2D&wze1(GhU*HhXq|q*~jxUom5ZB*BoqmtJc(IHao!UtI9qD(;Bu=3G3BMKA(&Ty_%k| z{PWVJ7?1osg}w{d?&rwH?wX+?QD(t^dp1i<*^|8Pn_vyq{mw@_7DQ-toD8 z=SBf7bBzvhj!!HdQuD1i=h<`Us`#lg#jZT`VBguki0`UJEXsK^topB<+vc@2{h_?m zbNdAo7f#NaW-lS-c>3dawhY$`S1iS?#T7(9ltjL%5tY(-k|ozOZR*AcyLJV|3oY^9 z{eZQ6DO1KPUWqU7C#^HTwCu%m?S3!kN8HAbk~b88jkk|(`^x!gH``Chf`h~%w>nIDfowft0Bk^cPhQJu`S z%iQ(%T*?W2U1l?(-s=$m#FOR|)4we3TIJur=@~bVg;ey_=Stq6f`T8J{MGm)Q8S}v z(Y}YCzh-`t|DgV$f8po&jm6I`Gp3cCy!XG2doLSz(F9qh_^<_Eg(r4Rc{gQ2NI<#b zBjbIqnRew|u<3KQl3zK0@qbpUx$v-DITt(JPUdaSLz#n z;F{OE@4B)6sw|HG#wAw&PuFz(*;99n`=j`as^b?Qv3yjMYJc-lC-Z`IK-%mlkA%+l zuKHE@qK4ZfYN4Iu(~pzc?p*k3nzO^n#^GL$@&Sg0<_8vNt$nD`)3=!av<-EL;omkgR^muJz)S4;CR^?%q)Mv_V^?TJ0 z^}zfFzV&WpzuRXyG5(G_zsPl~As>_ZT&8lBy^Q)D>wkqzw#!JruxRd$Wj)6u9zL<# zyhX68`{pe*-513NH_Y6a!OGyYXyf+G=QaYt(z7$Rh2%@TNF>ykUBOXf_O z7tpoeu5-$qxqDJ_+kY+GqR1{(XgPOYq|2L06Eg&wO}3>l%62pdu0MNaglWS1-pa=^Gwn2Z?jER<8g*yi8|E3?9CY{C{M>LrcXcao$AwPijGR}2Sq!Hy zPqkPnu3xkA@L!k9mo}xByGZY|`T1eVoy$|o6gIz?y%OlOUTLx0mYY|(I&5DqY8L2a zpEluFP_mOG%T&S8zlX$J(sR6acwawOXjde!9Q$2do8i&Jw#)zz?(c`5o@{T?U>0{w z`fYpGre)cLE7P|&>)mvoJZ)O3!^KUf;|~2+dcrV|y-Z={d6Vo(>ibq)Wzb*0(ZACm zuUCXsJnS0R1Gyp-0k-(8%1#cAHM^@`Y;UpFtK<_~@bi$xs{V*zu1t{|`A6lhtNVY{ zaCN!BC%f(a4`mML)vqh{;uh5E7S`s4%>Rn9nl}2z*EIzCr`YK`U4JROrN#Z#X@M!1?)pbAtcv)sW)pLxWz9+v zkwyNUHOqg-ocbO7q9Wq<{ZJXlEKYrYyIFgG2AgdQbq~?}nwtFKO`iAZFE{>87H}z< z`+?W7Xy>H7IG=eFeyqve^km_w-9>+0eHXHFJkl$=+R7p;mMqj-wp(_yXJqo_9?g<% zv!_p-P$l0zaTWjOtmG-44Yr;CB+j(3Ts2%JeM0TSiNGX@s;~|79~(cI6O&NB&rMaw z+U?3k|9kFSn`R3g>YB24!I9*kcn+l>Ol}uDRMgjp>ZRx|Hawj(d48WJ&x#VeZ%VRP znB-pWY&?0%=uF>ny)%tdH_E=B|Ejg+TjC1l{J)AZe}sRyTJW!aW&QNY%U@4F-F{Hd zIj?hhCabB0sGT!+<)4Um_onNtUiQ_`K~LVJ`S!I8Rr3qHmtO^N99p-1t=^QG0uwJ@ zc=hR#N{TBV*USssLR4(|=c(H|`aYL5pEThU?~#?~lcd(JTUoSkU*^Z-A9ttzTGlXs zity$2e;6ZT_Bd#*IJkl>BuuVpbp)&Au`H#P$GD=Grr$BUb<}%FjD%L!{Jn-YG3zcZ z@NU|+%P8+l&%{SfZ!P8|vY8RV`?5o`)_uthbeATO2=chN^Z=Zjpf8wfN$K%`P zAM6iWb8w2o^J&*ycTCma!4sC&my%NBy@nwq%xUHOO2dZCI{3=+jJzJK?GBx9w z=#%K4>RTQ^l_G1}j9AV88rlS}m>|7@jkoPeh}x0Q&+a*}hwQwN&SwF|aQD)WxCiQmAc`;WyZ)qhcocz1>!Z@wwREN9_T$!b|~&lkJ~H@a@B zO_p47UCsHn$IS8z44f}{AG}dW+Q}Cuw1g$NE%f$0RkuXWsLx-lr{&r`_7ooN&|3MQ1&uQL%2v<%a>`VoX_z8~S%D zHSD;=(4&!becytt$tFK;Yusu(V$7Kr3F>Qs4@=_#(|WZ1#!S?ln` z;J(Ouh5weu1vX;$D&MA^bU$%%e$!)_sJ_jA56n;IU3TPB*0U)r6RsvOqe&nPDmeevxH>zr0?4*BXkdG#`Lman4xHHvIM7O!8kYH#;_HRmqV8NwU#6i;dY zXnFFgX~(n5E>ou+2PVBv+u!c1!PMZ$mDRdOi|K8DLu!I^&&&xcP4=t{ESgoPDpzs& z`{VulUaEyAZGO1@;qIp?&&40Ew~yG!cDX6_R1W)`t1cR=*xM*LCy!x9?pd;X$e zL`==o!V(UgNm5!=G4qch!zQ=GKP?}gHZjS#)cH|gS$JOPWoDEZFD#xA;HPWRc$_QNQE!md^Xk4_aGx?Z1ceuYZi2)_-UH8~OA9WG0h_ z_wovtmpj({XOOh(ee|1s#X|2xNwco)_%?ZIs=&vLN8HT&>KmlCt7zzycC{^PN;>eJ zU*OuJ>kpj7zbKmQ%GhRgz~JF;c8*L{3m=0{k(Pz>d>>4Q9(L6sKk0{C(-kgZD@BCD(p!zQwfpC! z{cY~czIEL^=i##7U~glY+?su@%dg%4P*B$p_d4{|p0HD;VWIz6*B$&45%taPvTpi$ z<8RlmN?#E(nIpeoudKg(^-{O3-nD5t8RmC_n_QkO;1y@F-Phjsnc3uNe}K+D@#drtNwK3={rVU4QJ6!{0b z$8Sncm>x9ic*Sp{saMvDG|bt))N8Szvz$k*+MOJWy^Jfi%xQ89NX%Q9@p|9pc@NIc zyOMDv!@ZJOF0ER4(Oj;JcU8Ey1h!_RHg>8USS7mhuh;LbvV~5ZZ#J60GTafYAZy*o zU?lWR=ERN+o9b!b?gf|MtK{-CZLeLEKGmqM>34+A_n9m!B^Gl^G^Bjfy|i+F#l~F> zLQ^aJW(4k7#-`k@cIMJ1{e>)y0se*`IWnChXD@L1yzJ`cEXMBl1*Qy2dv{;82%1@Y zaoK^eS+Re0Hszl@m?@JPTh#L5U6}BLI;DUU53QTiUcI!RTzY?r#s5s}ukYm-eE9g% z_2&O&X0QJ;Px-|&k8_jXieEceuXuO0R{m$`b&i<+o&UlO_YJd?67ShNJQfIh`Ip%w zZKK+I`2|)CqVJ7sExT7czvi`^ze(A8VKp}gQ#vOr$Nbz|z2Er*WEq&_Pj$G~c(47^ zHm7}(*P*wk?YLIiSx=ssTlJq|soeJ$s@?LF_NhMqc)K{xqS29ak)|h;?u&a&TIl<^sIVm}8$M~p zGApwt_5S$H?or=R%~SJUda{v}Qh?QV{eAa?y2>JUusoamh;3g-L)i8wUMp8$cC-hAf11RXToak}Ym=Ra=`Yh>hc~Pb7-YGgaXayIG%oe~P}u$Y&W8K@dY0T1+$Xu> zBHKitTZRYIdq4kX*DxyD6*KFae4%3A$EB(7K5u>z;oJYWed*KEoLg6>8%XW@&L1#$ zg5z?L6Kp?%7$gKlRT$pi5ZJ!MLr8Ged~LQL{TF#WYtsIF=MQ*$@TT3>1sl(9c@-?` zdSyb6u9?dnO^0i%X7FuGQd!BM9ktY@@1J#$pl0;uuIDOm{1?m3u-Q@Hkj1uso=2T{ zUG=%g20gW!dyZBtTKp=w(lg)Sq5Iw*M>z%7zppe_PFR>19W&jlma*gK+gU;EK4N$5 z9ZXwtGM~zk2tN(P-n2qpB<7 zJGde~x;{_+I5+0;{W;>NGWT4q3fjlY6&oUcLnl;95$?{(tEh|fzN{2;3ZMLMk@+>52i?o74O$o-ygk~%8sPHJUp)6btjxo*jPPK_Dr3)#~rUij1S z(s}+r1-7GCCWKv`_;){>{Mv^Wml9kpGP$NLWW3REs9{mQ`O3!H&C(Led`f;tbkEg$=L-n^xc78JYln1U_vHi^>9cc|35yk~52rXzaJ)4wxCc%rP+7wQ{Kn-R`1cgh^s3ppPr{cz%7UY*1 z3gUmyYnlHN`mptF8nHy64<=!~+ z`mX;1^Wv8qia&3RpYW;q?ClFNpYJ(}74f|MlzMGX><8zft7UajHerS5lDc2= z7W8<0Gk)PPHAUcM;{U~8c`_8;u86MOQ7gVSBjT{k1*39-FAk2^*dwarZ=QX!FNO6D z&nl%K8@4~y-!v~WD$VuXo`qRImNN_R?wL5h=4zJOch(tkroXZ(d%`UI|Lp%}{Ls1R zYE)XLQP(&xmsqD&D*1qc>`709@g@3h)3V81E<;^cCnk{`V=Fm0smHMmgvZS9^UYoO; zWufxt;tQ3&Pl_fB7cG5o?Sr`~(|0A#l+>#2{l7j~GxkRNdG1x`mzFScd&K?l@ZlCt z>#zs2AFNzpnx3(lS@xc*^sN0`8a(%$zwzZow&FgAwL$ZKH=SH6-gth!=$;MLj=VE? zXIad)oZPft=0p5}+3NFFHp%}9GBbFvU3AM|6@$&b47-**S>^ArH#zyIo$g8n**A&V z%z4|+-~7(k#>g9Sddsf8I}gZaDEB7GGTX0TI#Xb4{6vm<0r?5K!Cz}1um;F`aviYk zWHP*FaWRniN1*!axm#Y&`G4ole^3wNV8(j;qWl{- z>$59Ae0viRu-Eja+UI$l?^WI_q?>X|< zFYR8r_3*aa_X1@+7XLly{%M1ji?S=ztFGk#f3G!f-}}FR%7@QLyI3ryz<051<2%{C z);`?8$ouO{U-sBa)*w)Cnz+NB#zT0IRUtPUqcIIb6$E|<$^J*@38_b=Xn($b6 zHtW?Z3upeUtY)9TgRAiG&9BMoEAD->|2MyuAVhN9dcmSa*ow+Z|BNs&3IZHdFYkt`p9~{r#`{*(>Cn- z zjN9hNmoHzL@-qH^=rLxi(1g^+Gm9T{AK&(ICS-q1%hXdpD`&I!zsQ@Ky6Hk$r)^en zjGKzC%=}qzreuD9cWaT-i=~MNzU01a47R-fsYgcCE&E1)2cxJZJGaueHNHL@C0F)8 zE>v4~LodN)sadmYPUDgZeIEi|1~S+Djatt$(N;?Cwy)>rnV;D{dhEJ-YL1_VQt{8S ztlAXYQ!PLG&i481_ABWwQ3_GiS@4TRq|0PNIg3EVoTGP(`;UQku_Po;Ty&t}8r^Ee(He+uuSJH&NUdRs1E?aI5Hre@7y`l@(3N_UJf7LNvEGXqXQxWTwtlZgV zSEuaV+jpLa?egiFMm2lA)}P4)??9RDAt-UlHd5j1hmF-rbu2BNQ+lRfULE%8PF&=i zoqwc7*-DKHa*oMW9-7#%;$3~^<15Yi{CU+)2`1+ywapgCyH7h;A=Po@R-gQO!*6R` z_A4>Ov&Ss!;Q6akpRfPhl}Y8mdfu?5p=+;XuGTRMuW^*+m6?5Uef2liijL-cbFEfa zdd{1$a1mqfO%5Ze0>Q&4Ww&fQ+@9*?xR+;*x7)q!(}ry#lD+p#=k`1?mu0D z;|tK$`_t9Q}y2Ow~`LLctFsT>-cK7A50&wo}7~% znRYrVK)JZsMBhAh$pWJzt`km7TfKQ3yW9%NH+S#9P*J?jcWj=(nbkiod#Q8JI&tgW z{Dc3PmqxBVvh%;^qcf_W)mNtVJhncR`Lf~*OT5CqIV!Jjzumh=Pv6%<*;UUyq9bJI zw9Om*EVFmNRGSIfRuU0m@Lj^hcD~>?)uagb1s`Xh{rlbf%9;y%G`23BHd#9-v+K9| zrG_UR8rz`dD?YoYx#NPo>FgkE$`ZJ-(=X_~UCm@4mL30grET{yOpL zQcI6WfWVzk8QyLU7In8ayDww0QDWr&{3WY4#gExvabaYlw_)s(glCTzcQ6Mrus`?!}QK^eIkh>xRVI*=Li*2@#7ZB1I9sWO}pwc`^w_)bt$WsKWEl`wLIaz`ldc%o<8>jCaXoetzvb!x$>$i zZkPIY2%KPO<=MxuvIUubXZ;JI}4b$dhmo%mx!RAzX3gHLS~=@o z#LCBEw>BPrmbl`@g~f}a-uEpw^1mo6eN5ZzjYaC`3-KmrJVk2*R90-e^G9mt@rS`5 z1%DXGEWh;alUsFr|E{^!fr{C80}`{QcYNC(&1d^GKWl!CXp8i+c}o2kj<&zFm?9Rv zecmmD|KAec$8^4_cCTJ_*(&ktwa1^Po~WC#ZP~H4S8kc^zkP3~)Q9pX?C)28lYjf% zST74;u9YRpf>LHcyx^o9(>>0{|*=UpxQ+ literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc b/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc index 75036e6cd55..94cced414bd 100644 --- a/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc +++ b/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc @@ -438,7 +438,7 @@ Works with namespaces, classes, functions, variables, include statements, and macros. Also, opens URLs in the default browser - and Qt resource files (.qrc) in the \l{Creating Resource Files} + and Qt resource files (.qrc) in the \l{Resource Files} {resource editor} \li F2 \row diff --git a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc index 646fdce899b..b0f188c0834 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -8,122 +8,33 @@ \title Creating Files - You can use wizard templates to add individual files to your - \l{Creating Projects}{projects}. - The following table lists the wizard templates for creating files. + \image qtcreator-new-file.webp {New File wizard} - \table - \header - \li Category - \li Wizard Template - \li Purpose - \row - \li {1,3} C/C++ - \li C++ Class - \li C++ header and source file for a new class that you can add to - a C++ project. - \row - \li C/C++ Source File - \li C++ source file that you can add to a C++ project. - \row - \li C/C++ Header File - \li C++ header file that you can add to a C++ project. - \row - \li {1,3} Modeling - \li State Chart - \li State Chart XML (SCXML) file that has boilerplate - code for state machines. You can use the classes in the - \l {Qt SCXML} module to embed state machines created from - the files in Qt applications. - \row - \li Model - \li Universal Modeling Language (UML) style model with a structured - diagram. However, the model editor uses a variant of UML and - has only a subset of properties for specifying the - appearance of model elements. For more information, see - \l {Modeling}. - \row - \li Scratch Model - \li Scratch model using a temporary file. - \row - \li {1,7} Qt - \li Qt Item Model - \li Source and header files that you can use to create classes - derived from QAbstractItemModel, QAbstractTableModel, or - QAbstractListModel. - \row - \li \QD Form Class - \li \QD form and a matching class for implementing a UI based - on Qt widgets. - \row - \li \QD Form - \li \QD form for Qt widget based projects. This is useful - if you already have an existing class for the UI logic. - \row - \li Qt Resource File - \li Resource file for storing binary files in the application - executable. - \row - \li QML File (Qt Quick 2) - \li QML file that imports Qt Quick 2.0 for use in Qt Quick projects. - \row - \li Qt Quick UI File - \li \l{UI Files}{UI file} (\e .ui.qml) and the corresponding - implementation file (\e .qml) for use in Qt Quick projects. - \row - \li JS File - \li JavaScript file that you can use to write the application logic - in Qt Quick projects. - \row - \li {1,4} GLSL - \li Fragment Shader (OpenGL/ES 2.0) - \li Fragment shader that generates the final pixel colors for - triangles, points, and lines rendered with OpenGL. You can use - it in both Qt Quick projects and Qt widget based projects. - \row - \li Vertex Shader (OpenGL/ES 2.0) - \li Vertex shader that transforms the positions, normals, and - texture coordinates of triangles, points, and lines rendered - with OpenGL. You can use it in both Qt Quick projects and Qt - widget based projects. - \row - \li Fragment Shader (Desktop OpenGL) - \li Fragment shader for use in both Qt Quick projects and Qt - widget based projects. - \row - \li Vertex Shader (Desktop OpenGL) - \li Vertex shader for use in both Qt Quick projects and Qt - widget based projects. - \row - \li {1,2} General - \li Empty File - \li Empty file that you can save with any filename extension. - \row - \li Scratch Buffer - \li Scratch buffer that uses temporary files. You can - create this type of files for temporarily storing information - that you do not intend to save - \row - \li Java - \li Java File - \li Java class files that you can use to create Java classes. - \row - \li {1,2} Python - \li Python Class - \li Python class file. - \row - \li Python File - \li Python script file using UTF-8 encoding. - \row - \li {1,2} Nim (experimental) - \li Nim Script File - \li Empty Nim script file using UTF-8 encoding. - \row - \li Nim File - \li Empty Nim source file using UTF-8 encoding. - \endtable + Use wizard templates to add individual files to your \l{Creating Projects} + {projects}: - \section1 Creating C++ Classes + \list + \li \uicontrol {C/C++}: header and source files for new classes. + \li \uicontrol {Modeling}: State Chart XML (SCXML) files, + Universal Modeling Language (UML) style \l {Modeling}{models}, + and scratch models that use a temporary file. + \li \uicontrol {Qt}: source and header files for item, table, + or list models, \QD forms and a matching classes for Qt Widgets + projects, Qt resource files, as well as QML and JavaScript files + for Qt Quick projects. + \li \uicontrol {GLSL}: fragment and vertex shaders. + \li \uicontrol {General}: markdown files, empty files that you can save + with any filename extension, and scratch buffers that use temporary + files. + \li \uicontrol {Java}: class files. + \li \uicontrol {Python}: class and script files for Python projects. + \li \uicontrol {Nim} (experimental): empty Nim source and script files. + \endlist + + The \uicontrol {New File} dialog shows detailed information about each file + wizard template. + + \section1 C++ Classes The \uicontrol {C++ Class Wizard} allows you to create a C++ header and source file for a new class that you can add to a C++ project. Specify the class @@ -149,7 +60,7 @@ You can create your own project and class wizards. For more information, see \l{Adding New Custom Wizards}. - \section1 Creating Resource Files + \section1 Resource Files \QC supports the \l{The Qt Resource System}{Qt Resource System}, which is a platform-independent mechanism for storing files in the application's @@ -187,7 +98,7 @@ The above functions are also available in the context menu in the \uicontrol Projects view. - \section1 Creating OpenGL Fragment and Vertex Shaders + \section1 OpenGL Fragment and Vertex Shaders Qt supports integration with OpenGL implementations on all platforms, which allows you to display hardware accelerated 3D graphics diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-build-systems.qdocinc b/doc/qtcreator/src/projects/creator-only/creator-projects-build-systems.qdocinc index b3300865dd6..05a340d0df2 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-build-systems.qdocinc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-build-systems.qdocinc @@ -1,4 +1,4 @@ -// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -12,29 +12,33 @@ \section1 Selecting the Build System - You can use several build systems to build your projects. + You can use several build systems to build your projects: - \l{qmake Manual}{qmake} is a cross-platform system for build automation + \list + + \li \l{qmake Manual}{qmake} is a cross-platform system for build automation that helps simplify the build process for development projects across different platforms. qmake automates the generation of build configurations so that you need only a few lines of information to create each configuration. Qt installers install and configure qmake. To use one of the other supported build systems, you need to set it up. - \l {Build with CMake}{CMake} is an alternative to qmake for automating the + \li \l {Build with CMake}{CMake} is an alternative to qmake for automating the generation of build configurations. For more information, see \l {Setting Up CMake}. - \l {https://mesonbuild.com/}{Meson} Meson is a fast and user-friendly + \li \l {https://mesonbuild.com/}{Meson} is a fast and user-friendly open-source build system that aims to minimize the time developers spend writing or debugging build definitions and waiting for the build system to start compiling code. For more information, see \l {Setting Up Meson}. - \l{Qbs Manual}{Qbs} is an all-in-one build tool that generates a build graph + \li \l{Qbs Manual}{Qbs} is an all-in-one build tool that generates a build graph from a high-level project description (like qmake or CMake do) and executes the commands in the low-level build graph (like make does). For more information, see \l{Setting Up Qbs}. + \endlist + To export a project to some other build system, such as Microsoft Visual Studio, select \uicontrol Build > \uicontrol {Run Generator}, and select a generator in the list. \QC generates the build files, such as .vcxproj, diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc index 141e6eab2ad..6ea2b20b036 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -49,7 +49,7 @@ The installers create \l{glossary-buildandrun-kit}{kits} and specify build and run settings for the installed device types. However, you might need to install and configure some additional software on the devices to be able to - connect to them from the development PC. + \l{Connecting Devices}{connect} to them from the development PC. \include creator-projects-build-systems.qdocinc build systems @@ -71,146 +71,49 @@ \section1 Selecting Project Type - The following table lists the wizard templates for creating projects. + The following table lists the types of wizard templates that you can use + for creating projects. The \uicontrol {New Project} dialog shows detailed + information about each project wizard template. \table \header \li Category - \li Wizard Template \li Purpose \row - \li Application (Qt for MCU) - \li MCU Support Application - \li Creates an application that uses a subset of Qt QML and - Qt Quick Controls types (as supported by Qt for MCUs) that - you can deploy, run, and debug on MCU boards. For more - information, see \l {Connecting MCUs}. + \li Application + \li Use many UI technologies (Qt Widgets and Qt Quick) and + programming languages (C++, QML, and Python) to create + applications for different purposes that you can run on + many target platforms (desktop, mobile, and embedded). \row - \li {1,3} Application (Qt) - \li Qt Widgets Application - \li Uses \QD forms to design a Qt widget based user interface for - the desktop and C++ to implement the application logic. + \li Library or plugin + \li Create a shared or static C++ library, a C++ plugin for Qt Quick + application extensions, or a \QC plugin. \row - \li Qt Console Application - \li Uses a single main.cpp file. + \li Other project + \li Create custom \l{Developing Widget Based Applications}{\QD} + widgets or widget collections, + \l{Qt Quick UI Projects}{Qt Quick UI projects}, + \l {Creating Tests}{auto-test projects}, + \l{Adding Subprojects to Projects}{subprojects}, + empty qmake projects, or qmake projects for testing + code snippets. \row - \li Qt Quick Application - \li Creates a Qt Quick application project that can have both - QML and C++ code. You can build the application and deploy it - to desktop, embedded, and mobile target platforms. + \li Non-Qt project + \li Create plain C or C++ applications or \l {Setting Up Nimble} + {Nim or Nimble} applications (experimental) + \row + \li Imported project + \li Import projects from a supported \l{Using Version Control Systems} + {version control system}, such as Bazaar, CVS, Git, Mercurial, or + Subversion. - You can select an option to create a project that you can open - in \QDS, which has a visual editor for Qt Quick UIs. - \row - \li {1,4} Application (Qt for Python) - \li Empty Application - \li Creates a \l{https://doc.qt.io/qtforpython/index.html} - {Qt for Python} application that has only the main - code for a QApplication. - \row - \li Empty Window - \li Creates a Qt for Python application that has an empty - window. - \row - \li Window UI - \li Creates a Qt for Python application that has an empty - window with a widget-based UI. Preferred approach that requires - you to generate a Python file from the .ui file, to import - it directly into your application. - \row - \li Qt Quick Application - Empty - \li Creates a Python project that has an empty Qt Quick - Application. - \row - \li {1,3} Library - \li C++ Library - \li A shared or static C++ library based on qmake. - \row - \li Qt Quick 2 Extension Plugin - \li Creates a C++ plugin that makes it possible to offer extensions - that the QQmlEngine class can load dynamically into Qt Quick - applications. - \row - \li \QC Plugin - \li Creates a \QC plugin. - \row - \li {1,6} Other Project - \li Qt Custom Designer Widget - \li Creates a custom \QD widget or widget collection. - \row - \li Qt Quick UI Prototype - \li Creates a \l{Creating Qt Quick UI Projects}{Qt Quick UI project} - with a single QML file that has the main view. You can - preview Qt Quick UI projects in the - \l{Validating with Target Hardware}{QML Scene preview tool}. - You do not need to build them because they do not have any - C++ code. - - Use this template only if you are prototyping. You cannot create - a full application by using this template. - - You cannot deploy Qt Quick UI projects to embedded or mobile - target platforms. For those platforms, create a Qt Quick - application instead. - \row - \li Auto Test Project - \li Creates a project with boilerplate code for a Qt or Google - test. For more information, see \l {Creating Tests}. - \row - \li Subdirs Project - \li Creates a subproject that enables you to structure your qmake - projects as a tree hierarchy. - \row - \li Empty qmake Project - \li Creates an empty qmake project that uses qmake as the build - system but does not use any default classes. - \row - \li Code Snippet - \li Creates a qmake project from a code snippet. When working on - bug reports that have a code snippet, you can place the code - snippet into a project to compile and check it. - \row - \li {1,4} Non-Qt Project - \li Plain C Application - \li Creates a plain C application that uses qmake, Qbs, or CMake - but does not use the Qt library. - \row - \li Plain C++ Application - \li Creates a plain C++ application that uses qmake, Qbs, or CMake - but does not use the Qt library. - \row - \li Nim Application (experimental) - \li Creates a Nim application that uses Nimble, but does not use the - Qt library. For more information, see \l {Setting Up Nimble}. - \row - \li Nimble Application (experimental) - \li Creates a Nimble application that uses Nimble, but does not use - the Qt library. For more information, see - \l {Setting Up Nimble}. - \row - \li {1,3} Import Project - \li Project from version control - \li Imports a project from a supported version control system, such - as Bazaar, CVS, Git, Mercurial, or Subversion. For more - information about how \QC integrates version control systems, - see \l{Using Version Control Systems}. - \row - \li Import as qmake or CMake Project (Limited Functionality) - \li Imports an existing project that does not use any of the - supported build systems: qmake, Qbs, CMake, or Autotools. The - template creates a project file, which enables you to use - \QC as a code editor and as a launcher for debugging and - analysis tools. However, if you want to build the project, - you might need to edit the generated project file. - \row - \li Import Existing Project - \li Imports an existing project that does not use any of the - supported build systems: qmake, Qbs, CMake, or Autotools. - This enables you to use \QC as a code editor. + You can also import existing projects that do not use any of the + supported build systems to use \QC as a code editor and as a + launcher for debugging and analysis tools. \row \li Squish - \li Squish Test Suite - \li Creates a new \l {Using Squish}{Squish test suite}. + \li Create new \l {Using Squish}{Squish test suites}. \endtable diff --git a/doc/qtcreator/src/python/creator-python-project.qdocinc b/doc/qtcreator/src/python/creator-python-project.qdocinc index 436e712f0b1..0ef6bb2d3fd 100644 --- a/doc/qtcreator/src/python/creator-python-project.qdocinc +++ b/doc/qtcreator/src/python/creator-python-project.qdocinc @@ -140,7 +140,7 @@ For more information about the \uicontrol {Qt for Python - Qt Quick Application - Empty} wizard, see - \l {Creating Qt Quick Based Python Applications}. + \l {Qt Quick Based Python Applications}. For examples of creating Qt for Python applications, see \l {https://doc.qt.io/qtforpython/tutorials/index.html} @@ -151,7 +151,7 @@ //! [python qml project wizards] - \section1 Creating Qt Quick Based Python Applications + \section1 Qt Quick Based Python Applications The \uicontrol {Qt for Python - Qt Quick Application - Empty} wizard enables you to create a Python project that has a main QML file. Specify the diff --git a/doc/qtcreator/src/qtquick/creator-only/qt-design-viewer.qdoc b/doc/qtcreator/src/qtquick/creator-only/qt-design-viewer.qdoc index 3cb1c61e1b7..dd1178e5e39 100644 --- a/doc/qtcreator/src/qtquick/creator-only/qt-design-viewer.qdoc +++ b/doc/qtcreator/src/qtquick/creator-only/qt-design-viewer.qdoc @@ -19,7 +19,7 @@ However, the actual performance of the application once started is indistinguishable from the same application running on the desktop. - You can run \l{Creating Qt Quick UI Projects}{Qt Quick UI projects}, which + You can run \l{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. diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc b/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc index af5f9ac321b..f92d29625b1 100644 --- a/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc +++ b/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -14,58 +14,28 @@ \title Creating Qt Quick Projects - The following table lists the wizard templates for creating a new - Qt Quick project from scratch. + Use the following wizard templates to create new Qt Quick projects: - \table - \header - \li Category - \li Wizard Template - \li Purpose - \row - \li Application (Qt) - \li Qt Quick Application - \li Creates a Qt Quick application project that can have both - QML and C++ code. You can build the application and deploy it - to desktop, embedded, and mobile target platforms. + \list + \li \uicontrol {Application (Qt)} > \uicontrol {Qt Quick Application} + \li \uicontrol {Application (Qt for Python)} > + \uicontrol {Qt for Python - Qt Quick Application} + \li \uicontrol {Other Project} > \uicontrol {Qt Quick UI Prototype} + \li \uicontrol {Library} > \uicontrol {Qt Quick 2 Extension Plugin} + \endlist - You can select an option to create a project that you can open - in \QDS. - \row - \li Application (Qt for Python) - \li Qt for Python - Qt Quick Application - \li Creates a Python project that has an empty Qt Quick - Application. - \row - \li Other Project - \li Qt Quick UI Prototype - \li Creates a Qt Quick UI project with a single QML file that - has the main view. You can preview Qt Quick UI projects - in the QML Scene preview tool. You do not need to build them - because they do not have any C++ code. - - This project type is compatible with \QDS. However, use this - template only if you are prototyping. You cannot create - a full application by using this template. - - You cannot deploy Qt Quick UI projects to embedded or - mobile target platforms. For those platforms, create a Qt Quick - application instead. - \row - \li Library - \li Qt Quick 2 Extension Plugin - \li Creates C++ plugins that make it possible to offer extensions - that can be loaded dynamically into Qt Quick applications. - \endtable + The \uicontrol {New Project} dialog shows detailed information about each + project wizard template. \note The SDK for a particular target platform might install additional templates for that platform. For example, the QNX templates are installed as part of the QNX SDK. \QC creates the necessary boilerplate files. Some of the files are - specific to a particular target platform. + specific to a particular target platform. You can use wizard templates + also to \l{Creating Files}{add files} to the projects. - \section1 Creating Qt Quick Applications + \section1 Qt Quick Applications \list 1 @@ -138,7 +108,7 @@ \include creator-python-project.qdocinc python qml project wizards - \section1 Creating Qt Quick UI Projects + \section1 Qt Quick UI Projects Qt Quick UI Prototype projects are useful for testing or prototyping user interfaces, diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc b/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc index 5c933d5305d..9fd1af9b34a 100644 --- a/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc +++ b/doc/qtcreator/src/qtquick/creator-only/qtquick-tutorial-create-empty-project.qdocinc @@ -69,7 +69,7 @@ \endlist For more information about the settings that you skipped and the other - wizard templates available, see \l{Creating Qt Quick Applications}. + wizard templates available, see \l{Qt Quick Applications}. //! [qtquick empty application] */ diff --git a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc index 95cd83edea5..01aaa637c4c 100644 --- a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc @@ -22,7 +22,7 @@ In addition, you can use \QDV to run \if defined(qtcreator) - \l{Creating Qt Quick UI Projects}{Qt Quick UI projects} + \l{Qt Quick UI Projects}{Qt Quick UI projects} \else applications \endif diff --git a/share/qtcreator/templates/wizards/codesnippet/wizard.json b/share/qtcreator/templates/wizards/codesnippet/wizard.json index 40757cf5715..c64ad36822e 100644 --- a/share/qtcreator/templates/wizards/codesnippet/wizard.json +++ b/share/qtcreator/templates/wizards/codesnippet/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ], "id": "Z.Snippet", "category": "H.Project", - "trDescription": "Creates a CMake-based test project for which a code snippet can be entered.", + "trDescription": "Creates a CMake-based test project where you can enter a code snippet to compile and check it.", "trDisplayName": "Code Snippet", "trDisplayCategory": "Other Project", "featuresRequired": [ "QtSupport.Wizards.FeatureQt" ], diff --git a/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json b/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json index fa801e67f4f..1817b79d938 100644 --- a/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json +++ b/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "MesonProjectManager.MesonProject", "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ], "id": "E.QtCore", "category": "D.ApplicationQt", - "trDescription": "Creates a project containing a single main.cpp file with a stub implementation.\n\nPreselects a desktop Qt for building the application if available.", + "trDescription": "Creates a project containing a single main.cpp file with a stub implementation and no graphical UI.\n\nPreselects a desktop Qt for building the application if available.", "trDisplayName": "Qt Console Application", "trDisplayCategory": "Application (Qt)", "icon": "../../global/consoleapplication.png", diff --git a/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json b/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json index 0a9bb685b7b..28e2242f7de 100644 --- a/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json +++ b/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "MesonProjectManager.MesonProject", "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ], "id": "H.CppLibrary", "category": "G.Library", - "trDescription": "Creates a C++ library. This can be used to create:
  • a shared C++ library for use with QPluginLoader and runtime (Plugins)
  • a shared or static C++ library for use with another project at linktime
", + "trDescription": "Creates a C++ library. You can create:
  • a shared C++ library for use with QPluginLoader and runtime (Plugins)
  • a shared or static C++ library for use with another project at linktime
", "trDisplayName": "C++ Library", "trDisplayCategory": "Library", "icon": "../../global/lib.png", diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index 88d63e19f9a..205f5ddafd0 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject", "QbsProjectManager.QbsProject" ], "id": "U.QtQuickApplicationEmpty", "category": "D.ApplicationQt", - "trDescription": "Creates a Qt Quick application that contains an empty window. Optionally, you can create a Qt Design Studio project.", + "trDescription": "Creates a Qt Quick application that can have both QML and C++ code. You can build the application and deploy it to desktop, embedded, and mobile target platforms.\n\nYou can select an option to create a project that you can open in Qt Design Studio, which has a visual editor for Qt Quick UIs.", "trDisplayName": "Qt Quick Application", "trDisplayCategory": "Application (Qt)", "icon": "icon.png", diff --git a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json index aba8309365b..251500b4949 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickuiprototype/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "QmlProjectManager.QmlProject" ], "id": "QA.QtQuickUi", "category": "H.Project", - "trDescription": "Creates a Qt Quick 2 UI project with a QML entry point. To use it, you need to have a QML runtime environment.\n\nUse this only if you are prototyping. You cannot create a full application with this. Consider using a Qt Quick Application project instead.", + "trDescription": "Creates a Qt Quick UI project for previewing and prototyping designs.\n\nTo develop a full application, create a Qt Quick Application project instead.", "trDisplayName": "Qt Quick UI Prototype", "trDisplayCategory": "Other Project", "icon": "qtquickuiprototype.png", diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json index e9d005507dc..58abd94344d 100644 --- a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "MesonProjectManager.MesonProject","CMakeProjectManager.CMakeProject", "Qt4ProjectManager.Qt4Project", "Qbs.QbsProject" ], "id": "C.QtWidgets", "category": "D.ApplicationQt", - "trDescription": "Creates a widget-based Qt application that contains a Qt Designer-based main window.\n\nPreselects a desktop Qt for building the application if available.", + "trDescription": "Creates a widget-based Qt application that contains a Qt Designer-based main window and C++ source and header files to implement the application logic.\n\nPreselects a desktop Qt for building the application if available.", "trDisplayName": "Qt Widgets Application", "trDisplayCategory": "Application (Qt)", "icon": "../../global/guiapplication.png", diff --git a/src/plugins/mcusupport/wizards/qmlproject/wizard.json b/src/plugins/mcusupport/wizards/qmlproject/wizard.json index 173c430eeb4..4fcf4f6fd31 100644 --- a/src/plugins/mcusupport/wizards/qmlproject/wizard.json +++ b/src/plugins/mcusupport/wizards/qmlproject/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ], "id": "M.McuSupportApplication", "category": "D.ApplicationMCU", - "trDescription": "Suitable for Qt for MCUs versions 2.4 and later. Creates a Qt for MCUs application with a simple UI, based on qmlproject.", + "trDescription": "Suitable for Qt for MCUs versions 2.4 and later. Creates an application that uses a subset of Qt QML and Qt Quick Controls types (as supported by Qt for MCUs) that you can deploy, run, and debug on MCU boards.", "trDisplayName": "Qt for MCUs Application", "trDisplayCategory": "QmlProject Application (Qt for MCUs)", "icon": "../icon.png", From 2d91be25f22c162aa71eb767c940ba7fdb6ab5ca Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 21 Apr 2023 14:10:36 +0200 Subject: [PATCH 0713/1447] Doc: Try to make All Topics more visible And provide some tips for searching. Task-number: QTCREATORBUG-28996 Change-Id: I35d611326555ccc568c98c49e092380d206fce6b Reviewed-by: hjk Reviewed-by: Eike Ziller --- doc/qtcreator/config/style/qt5-sidebar.html | 2 +- doc/qtcreator/src/qtcreator-toc.qdoc | 8 +++++++- doc/qtcreator/src/qtcreator.qdoc | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/qtcreator/config/style/qt5-sidebar.html b/doc/qtcreator/config/style/qt5-sidebar.html index e38e76483a8..48111154eb8 100644 --- a/doc/qtcreator/config/style/qt5-sidebar.html +++ b/doc/qtcreator/config/style/qt5-sidebar.html @@ -1,6 +1,6 @@
diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index e2299cd05c0..dc4256e2622 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only @@ -7,6 +7,12 @@ \title All Topics + \note The following list has links to all the individual topics (HTML files) + in the \QC Manual. Use your browser's page search to find a link to a + particular topic in the list. For a more extensive search, use the + \uicontrol Search function in the \l{https://doc.qt.io/qtcreator/} + {Qt documentation} portal or in the \l {Using the Help Mode}{Help} mode. + \list \li \l{Getting Started} \list diff --git a/doc/qtcreator/src/qtcreator.qdoc b/doc/qtcreator/src/qtcreator.qdoc index 50cbe7024e6..280a65ab19b 100644 --- a/doc/qtcreator/src/qtcreator.qdoc +++ b/doc/qtcreator/src/qtcreator.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -29,9 +29,11 @@ appropriate \l{http://qt.io/licensing/}{Qt license}. For more information, see \l{Commercial Features}. + + \table \row - \li {4,1} \b {\l{All Topics}} + \li {4,1} \b {\l{All Topics}{Click Here for a List of All Topics}} \row \li \inlineimage front-gs.png \li \inlineimage front-projects.png From b024ebda0e6d19aa01f37e77ebf90e6fde8dcf8c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 25 Apr 2023 12:59:05 +0200 Subject: [PATCH 0714/1447] ProjectExplorer: Support moving to different dir when renaming ... files in the project tree. Fixes: QTCREATORBUG-15981 Change-Id: Id704ec0638046e2191638b59e0a597b984d4822a Reviewed-by: Christian Stenger Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/plugins/coreplugin/fileutils.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index a48cd34da70..c98d5269f1c 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -170,8 +170,11 @@ bool FileUtils::renameFile(const FilePath &orgFilePath, const FilePath &newFileP if (orgFilePath == newFilePath) return false; - FilePath dir = orgFilePath.absolutePath(); + const FilePath dir = orgFilePath.absolutePath(); IVersionControl *vc = VcsManager::findVersionControlForDirectory(dir); + const FilePath newDir = newFilePath.absolutePath(); + if (newDir != dir && !newDir.ensureWritableDir()) + return false; bool result = false; if (vc && vc->supportsOperation(IVersionControl::MoveOperation)) From 9d9f1f9c23c53512cb58f06f23b75f5ef9cdc152 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 17 Apr 2023 23:14:57 +0200 Subject: [PATCH 0715/1447] MacroLocatorFilter: Reimplement matchers() Change-Id: I90e638e68414e8b6fc38cc98d85720d05a78df50 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/plugins/macros/macrolocatorfilter.cpp | 51 ++++++++++++++++++++++- src/plugins/macros/macrolocatorfilter.h | 3 +- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 8c90cccd156..dacb522f266 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -14,6 +14,7 @@ using namespace Core; using namespace Macros; using namespace Macros::Internal; +using namespace Utils; MacroLocatorFilter::MacroLocatorFilter() : m_icon(QPixmap(":/macros/images/macro.png")) @@ -25,7 +26,55 @@ MacroLocatorFilter::MacroLocatorFilter() setDefaultShortcutString("rm"); } -MacroLocatorFilter::~MacroLocatorFilter() = default; +LocatorMatcherTasks MacroLocatorFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage, icon = m_icon] { + const QString input = storage->input(); + const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(input); + const QMap ¯os = MacroManager::macros(); + LocatorFilterEntries goodEntries; + LocatorFilterEntries betterEntries; + for (auto it = macros.cbegin(); it != macros.cend(); ++it) { + const QString displayName = it.key(); + const QString description = it.value()->description(); + int index = displayName.indexOf(input, 0, entryCaseSensitivity); + LocatorFilterEntry::HighlightInfo::DataType hDataType + = LocatorFilterEntry::HighlightInfo::DisplayName; + if (index < 0) { + index = description.indexOf(input, 0, entryCaseSensitivity); + hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo; + } + + if (index >= 0) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = displayName; + filterEntry.acceptor = [displayName] { + IEditor *editor = EditorManager::currentEditor(); + if (editor) + editor->widget()->setFocus(Qt::OtherFocusReason); + MacroManager::instance()->executeMacro(displayName); + return AcceptResult(); + }; + filterEntry.displayIcon = icon; + filterEntry.extraInfo = description; + filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, input.length(), + hDataType); + if (index == 0) + betterEntries.append(filterEntry); + else + goodEntries.append(filterEntry); + } + } + storage->reportOutput(betterEntries + goodEntries); + return true; + }; + + return {{Sync(onSetup), storage}}; +} QList MacroLocatorFilter::matchesFor(QFutureInterface &future, const QString &entry) { diff --git a/src/plugins/macros/macrolocatorfilter.h b/src/plugins/macros/macrolocatorfilter.h index 3807548f69e..189cfcc6973 100644 --- a/src/plugins/macros/macrolocatorfilter.h +++ b/src/plugins/macros/macrolocatorfilter.h @@ -14,11 +14,12 @@ class MacroLocatorFilter : public Core::ILocatorFilter public: MacroLocatorFilter(); - ~MacroLocatorFilter() override; QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final; + const QIcon m_icon; }; From 836cffc16192fa61a849f8b5d5004f981a22db25 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 23:42:47 +0200 Subject: [PATCH 0716/1447] ExternalToolsFilter: Reimplement matchers() Change-Id: I158558688f3013329a8970e29744527003070f7e Reviewed-by: Marcus Tillmanns --- .../locator/externaltoolsfilter.cpp | 59 +++++++++++++++++++ .../coreplugin/locator/externaltoolsfilter.h | 2 + 2 files changed, 61 insertions(+) diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index f19ec49a69d..d62a9903071 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -25,6 +25,65 @@ ExternalToolsFilter::ExternalToolsFilter() setPriority(Medium); } +LocatorMatcherTasks ExternalToolsFilter::matchers() +{ + using namespace Utils::Tasking; + + TreeStorage storage; + + const auto onSetup = [storage] { + const QString input = storage->input(); + + LocatorFilterEntries bestEntries; + LocatorFilterEntries betterEntries; + LocatorFilterEntries goodEntries; + const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(input); + const QMap externalToolsById = ExternalToolManager::toolsById(); + for (ExternalTool *tool : externalToolsById) { + int index = tool->displayName().indexOf(input, 0, entryCaseSensitivity); + LocatorFilterEntry::HighlightInfo::DataType hDataType = LocatorFilterEntry::HighlightInfo::DisplayName; + if (index < 0) { + index = tool->description().indexOf(input, 0, entryCaseSensitivity); + hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo; + } + + if (index >= 0) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = tool->displayName(); + filterEntry.acceptor = [tool] { + auto runner = new ExternalToolRunner(tool); + if (runner->hasError()) + MessageManager::writeFlashing(runner->errorString()); + return AcceptResult(); + }; + filterEntry.extraInfo = tool->description(); + filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, input.length(), hDataType); + + if (filterEntry.displayName.startsWith(input, entryCaseSensitivity)) + bestEntries.append(filterEntry); + else if (filterEntry.displayName.contains(input, entryCaseSensitivity)) + betterEntries.append(filterEntry); + else + goodEntries.append(filterEntry); + } + } + LocatorFilterEntry configEntry; + configEntry.displayName = "Configure External Tool..."; + configEntry.extraInfo = "Opens External Tool settings"; + configEntry.acceptor = [] { + QMetaObject::invokeMethod(CorePlugin::instance(), [] { + ICore::showOptionsDialog(Constants::SETTINGS_ID_TOOLS); + }, Qt::QueuedConnection); + return AcceptResult(); + }; + + storage->reportOutput(bestEntries + betterEntries + goodEntries + + LocatorFilterEntries{configEntry}); + return true; + }; + return {{Sync(onSetup), storage}}; +} + QList ExternalToolsFilter::matchesFor(QFutureInterface &, const QString &) { diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.h b/src/plugins/coreplugin/locator/externaltoolsfilter.h index e97c04c2768..74c83112b50 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.h +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.h @@ -18,6 +18,8 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + LocatorMatcherTasks matchers() final; + QList m_results; }; From e18c1dceb236d5aed2ddf70e651da1435bb7530e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Apr 2023 16:58:21 +0200 Subject: [PATCH 0717/1447] Layouting: Add QTextEdit Change-Id: I3a74dce8ee7874b73cb11acab52092c4053722b8 Reviewed-by: Christian Stenger Reviewed-by: --- src/libs/utils/layoutbuilder.cpp | 9 +++++++++ src/libs/utils/layoutbuilder.h | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 12eb4003b97..9308ba96ce4 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace Layouting { @@ -442,6 +443,12 @@ PushButton::PushButton(std::initializer_list items) applyItems(widget, items); } +TextEdit::TextEdit(std::initializer_list items) +{ + widget = new QTextEdit; + applyItems(widget, items); +} + Splitter::Splitter(std::initializer_list items) : Splitter(new QSplitter(Qt::Vertical), items) {} @@ -497,6 +504,8 @@ LayoutItem::Setter text(const QString &text) return [text](QObject *target) { if (auto button = qobject_cast(target)) { button->setText(text); + } else if (auto textEdit = qobject_cast(target)) { + textEdit->setText(text); } else { QTC_CHECK(false); } diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 74b4ff3e0a7..06f0ae525d0 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -20,6 +20,7 @@ QT_BEGIN_NAMESPACE class QLayout; class QSplitter; class QTabWidget; +class QTextEdit; class QWidget; QT_END_NAMESPACE @@ -155,6 +156,12 @@ public: Group(std::initializer_list items); }; +class QTCREATOR_UTILS_EXPORT TextEdit : public LayoutItem +{ +public: + TextEdit(std::initializer_list items); +}; + class QTCREATOR_UTILS_EXPORT PushButton : public LayoutItem { public: From 7612ef1d0f7577f01187ad1d3f7f4ef21f341cbc Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 17:29:17 +0200 Subject: [PATCH 0718/1447] QNX: Mark toolchains detected by manual operation as "manual" Change-Id: I9683c4e7f471b9c6485f48ad14fce029522722b3 Reviewed-by: Christian Stenger --- src/plugins/qnx/qnxsettingspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 615851eeb3a..26da82ab7d9 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -232,7 +232,7 @@ Toolchains QnxConfiguration::createToolChains(const QnxTarget &target) for (const Id language : {ProjectExplorer::Constants::C_LANGUAGE_ID, ProjectExplorer::Constants::CXX_LANGUAGE_ID}) { auto toolChain = new QnxToolChain; - toolChain->setDetection(ToolChain::AutoDetection); + toolChain->setDetection(ToolChain::ManualDetection); toolChain->setLanguage(language); toolChain->setTargetAbi(target.m_abi); toolChain->setDisplayName(Tr::tr("QCC for %1 (%2)") From 3d354290be78e9be5c91478e36c119f55697034a Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:56:47 +0200 Subject: [PATCH 0719/1447] Terminal: Use IOptionPage::setWidgetCreator() for settings Less boilerplate for the implementation add user code access to IOptionPage::{apply,finish} is planned to be removed. Change-Id: Id8ec4006d1060be2032caf8eda6bf80760f6db22 Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalplugin.cpp | 2 +- src/plugins/terminal/terminalsettingspage.cpp | 241 +++++++++--------- src/plugins/terminal/terminalsettingspage.h | 4 - 3 files changed, 123 insertions(+), 124 deletions(-) diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp index 9062e417f0f..831981e823a 100644 --- a/src/plugins/terminal/terminalplugin.cpp +++ b/src/plugins/terminal/terminalplugin.cpp @@ -44,7 +44,7 @@ bool TerminalPlugin::delayedInitialize() void TerminalPlugin::extensionsInitialized() { - TerminalSettingsPage::instance().init(); + (void) TerminalSettingsPage::instance(); TerminalSettings::instance().readSettings(Core::ICore::settings()); m_terminalPane = new TerminalPane(); diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index db7920bd61c..bac32c279da 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -28,18 +28,6 @@ using namespace Utils; namespace Terminal { -TerminalSettingsPage::TerminalSettingsPage() -{ - setId("Terminal.General"); - setDisplayName("Terminal"); - setCategory("ZY.Terminal"); - setDisplayCategory("Terminal"); - setSettings(&TerminalSettings::instance()); - setCategoryIconPath(":/terminal/images/settingscategory_terminal.png"); -} - -void TerminalSettingsPage::init() {} - static expected_str loadXdefaults(const FilePath &path) { const expected_str readResult = path.fileContents(); @@ -320,131 +308,146 @@ static expected_str loadColorScheme(const FilePath &path) return make_unexpected(Tr::tr("Unknown color scheme format")); } -QWidget *TerminalSettingsPage::widget() +class TerminalSettingsPageWidget : public Core::IOptionsPageWidget { - QWidget *widget = new QWidget; +public: + TerminalSettingsPageWidget() + { + using namespace Layouting; - using namespace Layouting; + QFontComboBox *fontComboBox = new QFontComboBox(this); + fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts); + fontComboBox->setCurrentFont(TerminalSettings::instance().font.value()); - QFontComboBox *fontComboBox = new QFontComboBox(widget); - fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts); - fontComboBox->setCurrentFont(TerminalSettings::instance().font.value()); + connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [](const QFont &f) { + TerminalSettings::instance().font.setValue(f.family()); + }); - connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [](const QFont &f) { - TerminalSettings::instance().font.setValue(f.family()); - }); - - TerminalSettings &settings = TerminalSettings::instance(); - - QPushButton *loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); - QPushButton *resetTheme = new QPushButton(Tr::tr("Reset Theme to default")); - - connect(loadThemeButton, &QPushButton::clicked, this, [widget] { - const FilePath path = FileUtils::getOpenFilePath( - widget, - "Open Theme", - {}, - "All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;" - "Xdefaults (.Xdefaults Xdefaults);;" - "iTerm Color Schemes(*.itermcolors);;" - "VS Code Color Schemes(*.json);;" - "Konsole Color Schemes(*.colorscheme);;" - "XFCE4 Terminal Color Schemes(*.theme *.theme.txt);;" - "All files (*)", - nullptr, - {}, - true, - false); - - if (path.isEmpty()) - return; - - const expected_str result = loadColorScheme(path); - if (!result) - QMessageBox::warning(widget, Tr::tr("Error"), result.error()); - }); - - connect(resetTheme, &QPushButton::clicked, this, [] { TerminalSettings &settings = TerminalSettings::instance(); - settings.foregroundColor.setVolatileValue(settings.foregroundColor.defaultValue()); - settings.backgroundColor.setVolatileValue(settings.backgroundColor.defaultValue()); - settings.selectionColor.setVolatileValue(settings.selectionColor.defaultValue()); - for (auto &color : settings.colors) - color.setVolatileValue(color.defaultValue()); - }); + QPushButton *loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); + QPushButton *resetTheme = new QPushButton(Tr::tr("Reset Theme to default")); - // clang-format off - Column { - Group { - title(Tr::tr("General")), - Column { - settings.enableTerminal, st, - settings.sendEscapeToTerminal, st, - settings.audibleBell, st, - }, - }, - Group { - title(Tr::tr("Font")), - Row { - settings.font.labelText(), fontComboBox, Space(20), - settings.fontSize, st, - }, - }, - Group { - title(Tr::tr("Cursor")), - Row { - settings.allowBlinkingCursor, st, - }, - }, - Group { - title(Tr::tr("Colors")), - Column { - Row { - Tr::tr("Foreground"), settings.foregroundColor, st, - Tr::tr("Background"), settings.backgroundColor, st, - Tr::tr("Selection"), settings.selectionColor, st, - Tr::tr("Find match"), settings.findMatchColor, st, - }, - Row { - settings.colors[0], settings.colors[1], - settings.colors[2], settings.colors[3], - settings.colors[4], settings.colors[5], - settings.colors[6], settings.colors[7] - }, - Row { - settings.colors[8], settings.colors[9], - settings.colors[10], settings.colors[11], - settings.colors[12], settings.colors[13], - settings.colors[14], settings.colors[15] - }, - Row { - loadThemeButton, resetTheme, st, - } - }, - }, + connect(loadThemeButton, &QPushButton::clicked, this, [this] { + const FilePath path = FileUtils::getOpenFilePath( + this, + "Open Theme", + {}, + "All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;" + "Xdefaults (.Xdefaults Xdefaults);;" + "iTerm Color Schemes(*.itermcolors);;" + "VS Code Color Schemes(*.json);;" + "Konsole Color Schemes(*.colorscheme);;" + "XFCE4 Terminal Color Schemes(*.theme *.theme.txt);;" + "All files (*)", + nullptr, + {}, + true, + false); + + if (path.isEmpty()) + return; + + const expected_str result = loadColorScheme(path); + if (!result) + QMessageBox::warning(this, Tr::tr("Error"), result.error()); + }); + + connect(resetTheme, &QPushButton::clicked, this, [] { + TerminalSettings &settings = TerminalSettings::instance(); + settings.foregroundColor.setVolatileValue(settings.foregroundColor.defaultValue()); + settings.backgroundColor.setVolatileValue(settings.backgroundColor.defaultValue()); + settings.selectionColor.setVolatileValue(settings.selectionColor.defaultValue()); + + for (auto &color : settings.colors) + color.setVolatileValue(color.defaultValue()); + }); + + // clang-format off Column { - settings.shell, - settings.shellArguments, - }, - st, - }.attachTo(widget); - // clang-format on + Group { + title(Tr::tr("General")), + Column { + settings.enableTerminal, st, + settings.sendEscapeToTerminal, st, + settings.audibleBell, st, + }, + }, + Group { + title(Tr::tr("Font")), + Row { + settings.font.labelText(), fontComboBox, Space(20), + settings.fontSize, st, + }, + }, + Group { + title(Tr::tr("Cursor")), + Row { + settings.allowBlinkingCursor, st, + }, + }, + Group { + title(Tr::tr("Colors")), + Column { + Row { + Tr::tr("Foreground"), settings.foregroundColor, st, + Tr::tr("Background"), settings.backgroundColor, st, + Tr::tr("Selection"), settings.selectionColor, st, + Tr::tr("Find match"), settings.findMatchColor, st, + }, + Row { + settings.colors[0], settings.colors[1], + settings.colors[2], settings.colors[3], + settings.colors[4], settings.colors[5], + settings.colors[6], settings.colors[7] + }, + Row { + settings.colors[8], settings.colors[9], + settings.colors[10], settings.colors[11], + settings.colors[12], settings.colors[13], + settings.colors[14], settings.colors[15] + }, + Row { + loadThemeButton, resetTheme, st, + } + }, + }, + Column { + settings.shell, + settings.shellArguments, + }, + st, + }.attachTo(this); + // clang-format on - DropSupport *dropSupport = new DropSupport(widget); - connect(dropSupport, + DropSupport *dropSupport = new DropSupport(this); + connect(dropSupport, &DropSupport::filesDropped, this, - [widget](const QList &files) { + [this](const QList &files) { if (files.size() != 1) return; const expected_str result = loadColorScheme(files.at(0).filePath); if (!result) - QMessageBox::warning(widget, Tr::tr("Error"), result.error()); + QMessageBox::warning(this, Tr::tr("Error"), result.error()); }); + } - return widget; + void apply() final {} +}; + +// TerminalSettingsPage + +TerminalSettingsPage::TerminalSettingsPage() +{ + setId("Terminal.General"); + setDisplayName("Terminal"); + setCategory("ZY.Terminal"); + setDisplayCategory("Terminal"); + setSettings(&TerminalSettings::instance()); + setCategoryIconPath(":/terminal/images/settingscategory_terminal.png"); + setWidgetCreator([] { return new TerminalSettingsPageWidget; }); } TerminalSettingsPage &TerminalSettingsPage::instance() diff --git a/src/plugins/terminal/terminalsettingspage.h b/src/plugins/terminal/terminalsettingspage.h index 4c12697b13f..12d3762844e 100644 --- a/src/plugins/terminal/terminalsettingspage.h +++ b/src/plugins/terminal/terminalsettingspage.h @@ -13,10 +13,6 @@ public: TerminalSettingsPage(); static TerminalSettingsPage &instance(); - - void init(); - - QWidget *widget() override; }; } // namespace Terminal From ec0462748b2388248dbc5d5c4ac81f3feebfb79f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 22:34:09 +0200 Subject: [PATCH 0720/1447] CommandLocator: Reimplement matchers() Change-Id: I57fd82dda9b74eff470c1708e12df1361294c575 Reviewed-by: Orgad Shaneh --- .../coreplugin/locator/commandlocator.cpp | 46 +++++++++++++++++++ .../coreplugin/locator/commandlocator.h | 2 + 2 files changed, 48 insertions(+) diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 9c644f4f998..681c9e1281d 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -48,6 +48,52 @@ void CommandLocator::appendCommand(Command *cmd) d->commands.push_back(cmd); } +LocatorMatcherTasks CommandLocator::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage, commands = d->commands] { + const QString input = storage->input(); + const Qt::CaseSensitivity inputCaseSensitivity = caseSensitivity(input); + LocatorFilterEntries goodEntries; + LocatorFilterEntries betterEntries; + for (Command *command : commands) { + if (!command->isActive()) + continue; + + QAction *action = command->action(); + if (!action || !action->isEnabled()) + continue; + + const QString text = Utils::stripAccelerator(action->text()); + const int index = text.indexOf(input, 0, inputCaseSensitivity); + if (index >= 0) { + LocatorFilterEntry entry; + entry.displayName = text; + entry.acceptor = [actionPointer = QPointer(action)] { + if (actionPointer) { + QMetaObject::invokeMethod(actionPointer, [actionPointer] { + if (actionPointer && actionPointer->isEnabled()) + actionPointer->trigger(); + }, Qt::QueuedConnection); + } + return AcceptResult(); + }; + entry.highlightInfo = {index, int(input.length())}; + if (index == 0) + betterEntries.append(entry); + else + goodEntries.append(entry); + } + } + storage->reportOutput(betterEntries + goodEntries); + return true; + }; + return {{Sync(onSetup), storage}}; +} + void CommandLocator::prepareSearch(const QString &entry) { Q_UNUSED(entry) diff --git a/src/plugins/coreplugin/locator/commandlocator.h b/src/plugins/coreplugin/locator/commandlocator.h index e47fbde5c41..a1cadbd4b77 100644 --- a/src/plugins/coreplugin/locator/commandlocator.h +++ b/src/plugins/coreplugin/locator/commandlocator.h @@ -27,6 +27,8 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + LocatorMatcherTasks matchers() final; + CommandLocatorPrivate *d = nullptr; }; From a5e5058c41582d88d2648c4a183960e266929a03 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 26 Apr 2023 12:14:12 +0200 Subject: [PATCH 0721/1447] FakeVim: Avoid using invalid regular expressions Print a warning in case of an invalid regular expression and do not apply it to the settings. This silently drops invalid regular expressions entered and restored from settings. Change-Id: I2f7686066541cf2307cf7cf96b3c6f89f6a677d8 Reviewed-by: hjk Reviewed-by: --- src/plugins/fakevim/fakevimplugin.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 789ceaa9d16..d71c0376457 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -605,12 +605,17 @@ FakeVimExCommandsMappings::FakeVimExCommandsMappings() m_commandBox = new QGroupBox(Tr::tr("Ex Command"), this); m_commandBox->setEnabled(false); - auto boxLayout = new QHBoxLayout(m_commandBox); + auto commandBoxLayout = new QVBoxLayout(m_commandBox); + auto boxLayout = new QHBoxLayout; + commandBoxLayout->addLayout(boxLayout); m_commandEdit = new FancyLineEdit(m_commandBox); m_commandEdit->setFiltering(true); m_commandEdit->setPlaceholderText(QString()); connect(m_commandEdit, &FancyLineEdit::textChanged, this, &FakeVimExCommandsMappings::commandChanged); + m_commandEdit->setValidationFunction([](FancyLineEdit *e, QString *){ + return QRegularExpression(e->text()).isValid(); + }); auto resetButton = new QPushButton(Tr::tr("Reset"), m_commandBox); resetButton->setToolTip(Tr::tr("Reset to default.")); connect(resetButton, &QPushButton::clicked, @@ -619,6 +624,12 @@ FakeVimExCommandsMappings::FakeVimExCommandsMappings() boxLayout->addWidget(m_commandEdit); boxLayout->addWidget(resetButton); + auto infoLabel = new InfoLabel(Tr::tr("Invalid regular expression."), InfoLabel::Error); + infoLabel->setVisible(false); + connect(m_commandEdit, &FancyLineEdit::validChanged, [infoLabel](bool valid){ + infoLabel->setVisible(!valid); + }); + commandBoxLayout->addWidget(infoLabel); layout()->addWidget(m_commandBox); QMap sections; @@ -675,7 +686,9 @@ ExCommandMap FakeVimExCommandsMappings::exCommandMapFromWidget() if ((regex.isEmpty() && pattern.isEmpty()) || (!regex.isEmpty() && pattern == regex)) continue; - map[name] = QRegularExpression(regex); + const QRegularExpression expression(regex); + if (expression.isValid()) + map[name] = expression; } } return map; @@ -1285,7 +1298,9 @@ void FakeVimPluginPrivate::readSettings() settings->setArrayIndex(i); const QString id = settings->value(idKey).toString(); const QString re = settings->value(reKey).toString(); - m_exCommandMap[id] = QRegularExpression(re); + const QRegularExpression regEx(re); + if (regEx.isValid()) + m_exCommandMap[id] = regEx; } settings->endArray(); From 36eab77c614ac337935553b78f623a897be58c90 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 26 Apr 2023 23:46:52 +0200 Subject: [PATCH 0722/1447] tst_taskTree: Add more tests for WaitFor/Condition/Activator Change-Id: I662d56c3b943a4df8b4c12da95eb57fbca9e3048 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- tests/auto/utils/tasktree/tst_tasktree.cpp | 70 ++++++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 37bbe498d7f..a360752fa36 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -1092,9 +1092,12 @@ void tst_TaskTree::processTree_data() }; }; - const Group root { - parallel, + // Test that Activator, triggered from inside the process described by + // setupProcessWithCondition, placed BEFORE the group containing the WaitFor element + // in the tree order, works OK in SEQUENTIAL mode. + const Group root1 { Storage(storage), + sequential, Process(setupProcessWithCondition(1)), Group { OnGroupSetup(groupSetup(2)), @@ -1103,15 +1106,72 @@ void tst_TaskTree::processTree_data() Process(setupProcess(3)) } }; - const Log log { + const Log log1 { + {1, Handler::Setup}, + {1, Handler::Activator}, + {2, Handler::GroupSetup}, + {2, Handler::Setup}, + {3, Handler::Setup} + }; + + // Test that Activator, triggered from inside the process described by + // setupProcessWithCondition, placed BEFORE the group containing the WaitFor element + // in the tree order, works OK in PARALLEL mode. + const Group root2 { + Storage(storage), + parallel, + Process(setupProcessWithCondition(1)), + Group { + OnGroupSetup(groupSetup(2)), + WaitFor(condition), + Process(setupProcess(2)), + Process(setupProcess(3)) + } + }; + const Log log2 { {1, Handler::Setup}, {2, Handler::GroupSetup}, {1, Handler::Activator}, {2, Handler::Setup}, {3, Handler::Setup} }; - QTest::newRow("WaitFor") - << TestData{storage, root, log, 3, OnStart::Running, OnDone::Success}; + + // Test that Activator, triggered from inside the process described by + // setupProcessWithCondition, placed AFTER the group containing the WaitFor element + // in the tree order, works OK in PARALLEL mode. + // + // Notice: This won't work in SEQUENTIAL mode, since the Activator placed after the + // group containing the WaitFor element, has no chance to be started in SEQUENTIAL mode, + // as in SEQUENTIAL mode the next task may only be started after the previous one finished. + // In this case, the previous task (Group element) awaits for the Activator's signal to + // come from the not yet started next task, causing a deadlock. + // The minimal requirement for this scenario to succeed is to set ParallelLimit(2) or more. + const Group root3 { + Storage(storage), + parallel, + Group { + OnGroupSetup(groupSetup(2)), + WaitFor(condition), + Process(setupProcess(2)), + Process(setupProcess(3)) + }, + Process(setupProcessWithCondition(1)) + }; + const Log log3 { + {2, Handler::GroupSetup}, + {1, Handler::Setup}, + {1, Handler::Activator}, + {2, Handler::Setup}, + {3, Handler::Setup} + }; + + // Notice the different log order for each scenario. + QTest::newRow("WaitForSequential") + << TestData{storage, root1, log1, 3, OnStart::Running, OnDone::Success}; + QTest::newRow("WaitForParallelActivatorFirst") + << TestData{storage, root2, log2, 3, OnStart::Running, OnDone::Success}; + QTest::newRow("WaitForParallelConditionFirst") + << TestData{storage, root3, log3, 3, OnStart::Running, OnDone::Success}; } } From 7db28e788f11e599e933eaccfa52b6743fe37347 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 21:32:30 +0200 Subject: [PATCH 0723/1447] CMakeTargetLocatorFilter: Reimplement matchers() Change-Id: I1d515da13ca2b9c84b4b21565926d6df8ca8db99 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- .../cmakelocatorfilter.cpp | 114 ++++++++++++++---- .../cmakeprojectmanager/cmakelocatorfilter.h | 11 +- 2 files changed, 100 insertions(+), 25 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 57cb7946de6..e89db528d70 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -25,6 +25,59 @@ namespace CMakeProjectManager::Internal { // CMakeTargetLocatorFilter: // -------------------------------------------------------------------- +static LocatorMatcherTasks cmakeMatchers(const CMakeTargetLocatorFilter::BuildAcceptor &acceptor) +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage, acceptor] { + const QString input = storage->input(); + const QList projects = ProjectManager::projects(); + LocatorFilterEntries entries; + for (Project *project : projects) { + const auto cmakeProject = qobject_cast(project); + if (!cmakeProject || !cmakeProject->activeTarget()) + continue; + const auto bs = qobject_cast( + cmakeProject->activeTarget()->buildSystem()); + if (!bs) + continue; + + const QList buildTargets = bs->buildTargets(); + for (const CMakeBuildTarget &target : buildTargets) { + if (CMakeBuildSystem::filteredOutTarget(target)) + continue; + const int index = target.title.indexOf(input, 0, Qt::CaseInsensitive); + if (index >= 0) { + const FilePath path = target.backtrace.isEmpty() + ? cmakeProject->projectFilePath() + : target.backtrace.last().path; + const int line = target.backtrace.isEmpty() ? 0 : target.backtrace.last().line; + const FilePath projectPath = cmakeProject->projectFilePath(); + const QString displayName = target.title; + LocatorFilterEntry entry; + entry.displayName = displayName; + if (acceptor) { + entry.acceptor = [projectPath, displayName, acceptor] { + acceptor(projectPath, displayName); + return AcceptResult(); + }; + } + entry.linkForEditor = {path, line}; + entry.extraInfo = path.shortNativePath(); + entry.highlightInfo = {index, int(input.length())}; + entry.filePath = cmakeProject->projectFilePath(); + entries.append(entry); + } + } + } + storage->reportOutput(entries); + return true; + }; + return {{Sync(onSetup), storage}}; +} + CMakeTargetLocatorFilter::CMakeTargetLocatorFilter() { connect(ProjectManager::instance(), &ProjectManager::projectAdded, @@ -97,6 +150,33 @@ void CMakeTargetLocatorFilter::projectListUpdated() // BuildCMakeTargetLocatorFilter: // -------------------------------------------------------------------- +static void buildAcceptor(const Utils::FilePath &projectPath, const QString &displayName) +{ + // Get the project containing the target selected + const auto cmakeProject = qobject_cast( + Utils::findOrDefault(ProjectManager::projects(), [projectPath](Project *p) { + return p->projectFilePath() == projectPath; + })); + if (!cmakeProject || !cmakeProject->activeTarget() + || !cmakeProject->activeTarget()->activeBuildConfiguration()) + return; + + // Find the make step + BuildStepList *buildStepList = + cmakeProject->activeTarget()->activeBuildConfiguration()->buildSteps(); + auto buildStep = buildStepList->firstOfType(); + if (!buildStep) + return; + + // Change the make step to build only the given target + QStringList oldTargets = buildStep->buildTargets(); + buildStep->setBuildTargets({displayName}); + + // Build + BuildManager::buildProjectWithDependencies(cmakeProject); + buildStep->setBuildTargets(oldTargets); +} + BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() { setId("Build CMake target"); @@ -104,31 +184,12 @@ BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() setDescription(Tr::tr("Builds a target of any open CMake project.")); setDefaultShortcutString("cm"); setPriority(High); - setBuildAcceptor([](const Utils::FilePath &projectPath, const QString &displayName) { - // Get the project containing the target selected - const auto cmakeProject = qobject_cast( - Utils::findOrDefault(ProjectManager::projects(), [projectPath](Project *p) { - return p->projectFilePath() == projectPath; - })); - if (!cmakeProject || !cmakeProject->activeTarget() - || !cmakeProject->activeTarget()->activeBuildConfiguration()) - return; + setBuildAcceptor(&buildAcceptor); +} - // Find the make step - BuildStepList *buildStepList = - cmakeProject->activeTarget()->activeBuildConfiguration()->buildSteps(); - auto buildStep = buildStepList->firstOfType(); - if (!buildStep) - return; - - // Change the make step to build only the given target - QStringList oldTargets = buildStep->buildTargets(); - buildStep->setBuildTargets({displayName}); - - // Build - BuildManager::buildProjectWithDependencies(cmakeProject); - buildStep->setBuildTargets(oldTargets); - }); +Core::LocatorMatcherTasks BuildCMakeTargetLocatorFilter::matchers() +{ + return cmakeMatchers(&buildAcceptor); } // -------------------------------------------------------------------- @@ -144,4 +205,9 @@ OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter() setPriority(Medium); } +Core::LocatorMatcherTasks OpenCMakeTargetLocatorFilter::matchers() +{ + return cmakeMatchers({}); +} + } // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h index 4e73b59e4ad..73b3212b3fd 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h @@ -7,6 +7,7 @@ namespace CMakeProjectManager::Internal { +// TODO: Remove the base class class CMakeTargetLocatorFilter : public Core::ILocatorFilter { public: @@ -15,8 +16,8 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) final; -protected: using BuildAcceptor = std::function; +protected: void setBuildAcceptor(const BuildAcceptor &acceptor) { m_acceptor = acceptor; } private: @@ -26,16 +27,24 @@ private: BuildAcceptor m_acceptor; }; +// TODO: Don't derive, flatten the hierarchy class BuildCMakeTargetLocatorFilter : CMakeTargetLocatorFilter { public: BuildCMakeTargetLocatorFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; +// TODO: Don't derive, flatten the hierarchy class OpenCMakeTargetLocatorFilter : CMakeTargetLocatorFilter { public: OpenCMakeTargetLocatorFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; } // CMakeProjectManager::Internal From 82e57b4e9f7e2348458bebfc29c5fa163d1b76d5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 18 Apr 2023 01:03:04 +0200 Subject: [PATCH 0724/1447] QmlJSToolsPlugin: Reimplement matchers() Change-Id: If6767b4dc62eddddce0285b7b766f44241f3367e Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns --- .../qmljstools/qmljsfunctionfilter.cpp | 65 ++++++++++++++++++- src/plugins/qmljstools/qmljsfunctionfilter.h | 3 +- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index e39ba3de132..d24b02156ba 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -5,12 +5,16 @@ #include "qmljslocatordata.h" #include "qmljstoolstr.h" +#include + #include +#include #include using namespace Core; using namespace QmlJSTools::Internal; +using namespace Utils; Q_DECLARE_METATYPE(LocatorData::Entry) @@ -25,7 +29,66 @@ FunctionFilter::FunctionFilter(LocatorData *data, QObject *parent) setDefaultIncludedByDefault(false); } -FunctionFilter::~FunctionFilter() = default; +static void matches(QPromise &promise, const LocatorStorage &storage, + const QHash> &locatorEntries) +{ + const QString input = storage.input(); + const Qt::CaseSensitivity caseSensitivityForPrefix = ILocatorFilter::caseSensitivity(input); + const QRegularExpression regexp = ILocatorFilter::createRegExp(input); + if (!regexp.isValid()) + return; + + LocatorFilterEntries entries[int(ILocatorFilter::MatchLevel::Count)]; + for (const QList &items : locatorEntries) { + for (const LocatorData::Entry &info : items) { + if (promise.isCanceled()) + return; + + if (info.type != LocatorData::Function) + continue; + + const QRegularExpressionMatch match = regexp.match(info.symbolName); + if (match.hasMatch()) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = info.displayName; + filterEntry.linkForEditor = {info.fileName, info.line, info.column}; + filterEntry.extraInfo = info.extraInfo; + filterEntry.highlightInfo = ILocatorFilter::highlightInfo(match); + + if (filterEntry.displayName.startsWith(input, caseSensitivityForPrefix)) + entries[int(ILocatorFilter::MatchLevel::Best)].append(filterEntry); + else if (filterEntry.displayName.contains(input, caseSensitivityForPrefix)) + entries[int(ILocatorFilter::MatchLevel::Better)].append(filterEntry); + else + entries[int(ILocatorFilter::MatchLevel::Good)].append(filterEntry); + } + } + } + + for (auto &entry : entries) { + if (promise.isCanceled()) + return; + + if (entry.size() < 1000) + Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); + } + storage.reportOutput(std::accumulate(std::begin(entries), std::end(entries), + LocatorFilterEntries())); +} + +LocatorMatcherTasks FunctionFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage, entries = m_data->entries()](AsyncTask &async) { + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + async.setConcurrentCallData(matches, *storage, entries); + }; + + return {{Async(onSetup), storage}}; +} QList FunctionFilter::matchesFor(QFutureInterface &future, const QString &entry) diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.h b/src/plugins/qmljstools/qmljsfunctionfilter.h index 4334d5d9fca..71b3d0b5dd6 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.h +++ b/src/plugins/qmljstools/qmljsfunctionfilter.h @@ -16,11 +16,12 @@ class FunctionFilter : public Core::ILocatorFilter public: explicit FunctionFilter(LocatorData *data, QObject *parent = nullptr); - ~FunctionFilter() override; QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final; + LocatorData *m_data = nullptr; }; From 76ba3ea6a5dd2afffffad0673cf4186fa818b734 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 18 Apr 2023 18:47:08 +0200 Subject: [PATCH 0725/1447] ActionsFilter: Reimplement matchers() Change-Id: I54421904ce17118984e5dd6f02e2adee75849dde Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/actionsfilter.cpp | 154 ++++++++++++++++++++++- src/plugins/coreplugin/actionsfilter.h | 1 + 2 files changed, 150 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index b3ef46ca543..6930e6af018 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -10,7 +10,10 @@ #include "icore.h" #include "locator/locatormanager.h" +#include + #include +#include #include #include #include @@ -23,6 +26,8 @@ #include #include +using namespace Utils; + static const char lastTriggeredC[] = "LastTriggeredActions"; QT_BEGIN_NAMESPACE @@ -34,6 +39,13 @@ QT_END_NAMESPACE namespace Core::Internal { +static const QList menuBarActions() +{ + QMenuBar *menuBar = Core::ActionManager::actionContainer(Constants::MENU_BAR)->menuBar(); + QTC_ASSERT(menuBar, return {}); + return menuBar->actions(); +} + ActionsFilter::ActionsFilter() { setId("Actions from the menu"); @@ -50,13 +62,145 @@ ActionsFilter::ActionsFilter() }); } -static const QList menuBarActions() +static void matches(QPromise &promise, const LocatorStorage &storage, + const LocatorFilterEntries &entries) { - QMenuBar *menuBar = Core::ActionManager::actionContainer(Constants::MENU_BAR)->menuBar(); - QTC_ASSERT(menuBar, return {}); - return menuBar->actions(); + using Highlight = LocatorFilterEntry::HighlightInfo; + using MatchLevel = ILocatorFilter::MatchLevel; + const QString input = storage.input(); + const QRegularExpression regExp = ILocatorFilter::createRegExp(input, Qt::CaseInsensitive, + true); + using FilterResult = std::pair; + const auto filter = [&](const LocatorFilterEntry &filterEntry) -> std::optional { + if (promise.isCanceled()) + return {}; + Highlight highlight; + + const auto withHighlight = [&highlight](LocatorFilterEntry result) { + result.highlightInfo = highlight; + return result; + }; + + Highlight::DataType first = Highlight::DisplayName; + QString allText = filterEntry.displayName + ' ' + filterEntry.extraInfo; + QRegularExpressionMatch allTextMatch = regExp.match(allText); + if (!allTextMatch.hasMatch()) { + first = Highlight::ExtraInfo; + allText = filterEntry.extraInfo + ' ' + filterEntry.displayName; + allTextMatch = regExp.match(allText); + } + if (allTextMatch.hasMatch()) { + if (first == Highlight::DisplayName) { + const QRegularExpressionMatch displayMatch = regExp.match(filterEntry.displayName); + if (displayMatch.hasMatch()) + highlight = ILocatorFilter::highlightInfo(displayMatch); + const QRegularExpressionMatch extraMatch = regExp.match(filterEntry.extraInfo); + if (extraMatch.hasMatch()) { + Highlight extraHighlight = ILocatorFilter::highlightInfo(extraMatch, + Highlight::ExtraInfo); + highlight.startsExtraInfo = extraHighlight.startsExtraInfo; + highlight.lengthsExtraInfo = extraHighlight.lengthsExtraInfo; + } + + if (filterEntry.displayName.startsWith(input, Qt::CaseInsensitive)) + return FilterResult{MatchLevel::Best, withHighlight(filterEntry)}; + if (filterEntry.displayName.contains(input, Qt::CaseInsensitive)) + return FilterResult{MatchLevel::Better, withHighlight(filterEntry)}; + if (displayMatch.hasMatch()) + return FilterResult{MatchLevel::Good, withHighlight(filterEntry)}; + if (extraMatch.hasMatch()) + return FilterResult{MatchLevel::Normal, withHighlight(filterEntry)}; + } + + const FuzzyMatcher::HighlightingPositions positions + = FuzzyMatcher::highlightingPositions(allTextMatch); + const int positionsCount = positions.starts.count(); + QTC_ASSERT(positionsCount == positions.lengths.count(), return {}); + const int border = first == Highlight::DisplayName ? filterEntry.displayName.length() + : filterEntry.extraInfo.length(); + for (int i = 0; i < positionsCount; ++i) { + int start = positions.starts.at(i); + const int length = positions.lengths.at(i); + Highlight::DataType type = first; + if (start > border) { + // this highlight is behind the border so switch type and reset start index + start -= border + 1; + type = first == Highlight::DisplayName ? Highlight::ExtraInfo + : Highlight::DisplayName; + } else if (start + length > border) { + const int firstStart = start; + const int firstLength = border - start; + const int secondStart = 0; + const int secondLength = length - firstLength - 1; + if (first == Highlight::DisplayName) { + highlight.startsDisplay.append(firstStart); + highlight.lengthsDisplay.append(firstLength); + highlight.startsExtraInfo.append(secondStart); + highlight.lengthsExtraInfo.append(secondLength); + } else { + highlight.startsExtraInfo.append(firstStart); + highlight.lengthsExtraInfo.append(firstLength); + highlight.startsDisplay.append(secondStart); + highlight.lengthsDisplay.append(secondLength); + } + continue; + } + if (type == Highlight::DisplayName) { + highlight.startsDisplay.append(start); + highlight.lengthsDisplay.append(length); + } else { + highlight.startsExtraInfo.append(start); + highlight.lengthsExtraInfo.append(length); + } + } + + return FilterResult{MatchLevel::Normal, withHighlight(filterEntry)}; + } + return {}; + }; + + QMap filtered; + const QList> filterResults + = QtConcurrent::blockingMapped(entries, filter); + if (promise.isCanceled()) + return; + for (const std::optional &filterResult : filterResults) { + if (promise.isCanceled()) + return; + if (filterResult) + filtered[filterResult->first] << filterResult->second; + } + storage.reportOutput(std::accumulate(std::begin(filtered), std::end(filtered), + LocatorFilterEntries())); } +LocatorMatcherTasks ActionsFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [this, storage](AsyncTask &async) { + m_entries.clear(); + m_indexes.clear(); + QList processedMenus; + collectEntriesForLastTriggered(); + for (QAction* action : menuBarActions()) + collectEntriesForAction(action, {}, processedMenus); + collectEntriesForCommands(); + if (storage->input().simplified().isEmpty()) { + storage->reportOutput(m_entries); + return TaskAction::StopWithDone; + } + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + async.setConcurrentCallData(matches, *storage, m_entries); + return TaskAction::Continue; + }; + + return {{Async(onSetup), storage}}; +} + + QList ActionsFilter::matchesFor(QFutureInterface &future, const QString &entry) { @@ -342,7 +486,7 @@ void ActionsFilter::restoreState(const QJsonObject &object) m_lastTriggered.clear(); for (const QJsonValue &command : object.value(lastTriggeredC).toArray()) { if (command.isString()) - m_lastTriggered.append({nullptr, Utils::Id::fromString(command.toString())}); + m_lastTriggered.append({nullptr, Id::fromString(command.toString())}); } } diff --git a/src/plugins/coreplugin/actionsfilter.h b/src/plugins/coreplugin/actionsfilter.h index 3a945c26f9c..3d5cf43814e 100644 --- a/src/plugins/coreplugin/actionsfilter.h +++ b/src/plugins/coreplugin/actionsfilter.h @@ -39,6 +39,7 @@ public: void prepareSearch(const QString &entry) override; private: + LocatorMatcherTasks matchers() final; void saveState(QJsonObject &object) const override; void restoreState(const QJsonObject &object) override; LocatorFilterEntry::Acceptor acceptor(const ActionFilterEntryData &data) const; From 86cdc6667d347c6f8af4a19f7d42dfac157a5545 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 12 Apr 2023 22:11:36 +0200 Subject: [PATCH 0726/1447] RunConfigurationLocatorFilter: Reimplement matchers() Change-Id: I36a0aca3eac0ecb7988e1c68056601054837b4ad Reviewed-by: Marcus Tillmanns Reviewed-by: Reviewed-by: Qt CI Bot --- .../projectexplorer/projectexplorer.cpp | 87 ++++++++++++++++--- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e58f00bd056..f0ec7269ae9 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -408,6 +408,7 @@ protected: void restoreState(const QJsonObject &object) override; }; +// TODO: Remove the base class class RunConfigurationLocatorFilter : public ILocatorFilter { public: @@ -416,8 +417,8 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; -protected: using RunAcceptor = std::function; +protected: void setRunAcceptor(const RunAcceptor &acceptor) { m_acceptor = acceptor; } private: @@ -426,16 +427,24 @@ private: RunAcceptor m_acceptor; }; +// TODO: Don't derive, flatten the hierarchy class RunRunConfigurationLocatorFilter final : public RunConfigurationLocatorFilter { public: RunRunConfigurationLocatorFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; +// TODO: Don't derive, flatten the hierarchy class SwitchToRunConfigurationLocatorFilter final : public RunConfigurationLocatorFilter { public: SwitchToRunConfigurationLocatorFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; }; class ProjectExplorerPluginPrivate : public QObject @@ -4401,6 +4410,40 @@ static RunConfiguration *runConfigurationForDisplayName(const QString &displayNa }); } +static LocatorMatcherTasks runConfigurationMatchers( + const RunConfigurationLocatorFilter::RunAcceptor &acceptor) +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage, acceptor] { + const QString input = storage->input(); + const Target *target = ProjectManager::startupTarget(); + if (!target) + return true; + + LocatorFilterEntries entries; + for (auto rc : target->runConfigurations()) { + if (rc->displayName().contains(input, Qt::CaseInsensitive)) { + LocatorFilterEntry entry; + entry.displayName = rc->displayName(); + entry.acceptor = [name = entry.displayName, acceptor = acceptor] { + RunConfiguration *config = runConfigurationForDisplayName(name); + if (!config) + return AcceptResult(); + acceptor(config); + return AcceptResult(); + }; + entries.append(entry); + } + } + storage->reportOutput(entries); + return true; + }; + return {{Sync(onSetup), storage}}; +} + void RunConfigurationLocatorFilter::prepareSearch(const QString &entry) { m_result.clear(); @@ -4436,6 +4479,12 @@ void RunConfigurationLocatorFilter::targetListUpdated() setEnabled(ProjectManager::startupProject()); // at least one project opened } +static void runAcceptor(RunConfiguration *config) +{ + if (!BuildManager::isBuilding(config->project())) + ProjectExplorerPlugin::runRunConfiguration(config, Constants::NORMAL_RUN_MODE, true); +} + RunRunConfigurationLocatorFilter::RunRunConfigurationLocatorFilter() { setId("Run run configuration"); @@ -4443,9 +4492,23 @@ RunRunConfigurationLocatorFilter::RunRunConfigurationLocatorFilter() setDescription(Tr::tr("Runs a run configuration of the active project.")); setDefaultShortcutString("rr"); setPriority(Medium); - setRunAcceptor([](RunConfiguration *config) { - if (!BuildManager::isBuilding(config->project())) - ProjectExplorerPlugin::runRunConfiguration(config, Constants::NORMAL_RUN_MODE, true); + setRunAcceptor(&runAcceptor); +} + +LocatorMatcherTasks RunRunConfigurationLocatorFilter::matchers() +{ + return runConfigurationMatchers(&runAcceptor); +} + +static void switchAcceptor(RunConfiguration *config) +{ + ProjectManager::startupTarget()->setActiveRunConfiguration(config); + QTimer::singleShot(200, ICore::mainWindow(), [name = config->displayName()] { + if (auto ks = ICore::mainWindow()->findChild("KitSelector.Button")) { + ToolTip::show(ks->mapToGlobal(QPoint{25, 25}), + Tr::tr("Switched run configuration to\n%1").arg(name), + ICore::dialogParent()); + } }); } @@ -4456,16 +4519,12 @@ SwitchToRunConfigurationLocatorFilter::SwitchToRunConfigurationLocatorFilter() setDescription(Tr::tr("Switches the active run configuration of the active project.")); setDefaultShortcutString("sr"); setPriority(Medium); - setRunAcceptor([](RunConfiguration *config) { - ProjectManager::startupTarget()->setActiveRunConfiguration(config); - QTimer::singleShot(200, ICore::mainWindow(), [displayName = config->displayName()] { - if (auto ks = ICore::mainWindow()->findChild("KitSelector.Button")) { - ToolTip::show(ks->mapToGlobal(QPoint{25, 25}), - Tr::tr("Switched run configuration to\n%1").arg(displayName), - ICore::dialogParent()); - } - }); - }); + setRunAcceptor(&switchAcceptor); +} + +LocatorMatcherTasks SwitchToRunConfigurationLocatorFilter::matchers() +{ + return runConfigurationMatchers(&switchAcceptor); } } // namespace ProjectExplorer From 1a658eff26f5b7954899475ee6a4df8d96691e10 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 27 Apr 2023 08:49:30 +0200 Subject: [PATCH 0727/1447] FakeVim: Clear suggestions on mode change Change-Id: I5d3a37ab61f83a70e055063de397654f5621401d Reviewed-by: David Schulz Reviewed-by: hjk --- src/plugins/fakevim/fakevimhandler.cpp | 8 ++++++++ src/plugins/fakevim/fakevimhandler.h | 1 + src/plugins/fakevim/fakevimplugin.cpp | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 68239650654..7403f9e454b 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -5197,6 +5197,7 @@ void FakeVimHandler::Private::handleReplaceMode(const Input &input) moveDown(); } else if (input.isKey(Key_Insert)) { g.mode = InsertMode; + q->modeChanged(); } else if (input.isControl('o')) { enterCommandMode(ReplaceMode); } else { @@ -5394,6 +5395,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) removeText(range); } else if (input.isKey(Key_Insert)) { g.mode = ReplaceMode; + q->modeChanged(); } else if (input.isKey(Key_Left)) { moveLeft(); } else if (input.isShift(Key_Left) || input.isControl(Key_Left)) { @@ -8575,6 +8577,8 @@ void FakeVimHandler::Private::enterInsertOrReplaceMode(Mode mode) g.returnToMode = mode; clearLastInsertion(); } + + q->modeChanged(); } void FakeVimHandler::Private::enterVisualInsertMode(QChar command) @@ -8650,6 +8654,8 @@ void FakeVimHandler::Private::enterCommandMode(Mode returnToMode) g.returnToMode = returnToMode; m_positionPastEnd = false; m_anchorPastEnd = false; + + q->modeChanged(); } void FakeVimHandler::Private::enterExMode(const QString &contents) @@ -8664,6 +8670,8 @@ void FakeVimHandler::Private::enterExMode(const QString &contents) g.submode = NoSubMode; g.subsubmode = NoSubSubMode; unfocus(); + + q->modeChanged(); } void FakeVimHandler::Private::recordJump(int position) diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index 57955cd2cbd..1d13fe301ad 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -157,6 +157,7 @@ public: Signal completionRequested; Signal tabPreviousRequested; Signal tabNextRequested; + Signal modeChanged; public: class Private; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index d71c0376457..4d3ec87ed6c 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1591,6 +1591,11 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) tew->setExtraSelections(TextEditorWidget::FakeVimSelection, selection); }); + handler->modeChanged.connect([tew]() { + if (tew) + tew->clearSuggestion(); + }); + handler->highlightMatches.connect([](const QString &needle) { for (IEditor *editor : EditorManager::visibleEditors()) { QWidget *w = editor->widget(); From df5e3c587a045fbd3d50233ecdde0e06dccf35a3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 26 Apr 2023 12:33:11 +0200 Subject: [PATCH 0728/1447] TaskTree: Enhance Sync's function Make it possible to pass a void returning function to the Sync constructor. In this case it's assumed that function returns true by default and finishes successfully. Add some helpful error messages when requirements for the passed function are not met. Change-Id: I8be75acd277d06e87db3c87a6eb96173aa9cd890 Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns --- src/libs/utils/tasktree.h | 25 ++++- tests/auto/utils/tasktree/tst_tasktree.cpp | 107 +++++++++++++++++---- 2 files changed, 109 insertions(+), 23 deletions(-) diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 8e9c0a6c17b..0c1b5e7a33d 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -306,11 +306,28 @@ public: // Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() class QTCREATOR_UTILS_EXPORT Sync : public Group { + public: - using SynchronousMethod = std::function; - Sync(const SynchronousMethod &sync) - : Group({OnGroupSetup([sync] { return sync() ? TaskAction::StopWithDone - : TaskAction::StopWithError; })}) {} + template + Sync(Function &&function) : Group(init(std::forward(function))) {} + +private: + template + static QList init(Function &&function) { + constexpr bool isInvocable = std::is_invocable_v>; + static_assert(isInvocable, + "Sync element: The synchronous function can't take any arguments."); + constexpr bool isBool = std::is_same_v>>; + constexpr bool isVoid = std::is_same_v>>; + static_assert(isBool || isVoid, + "Sync element: The synchronous function has to return void or bool."); + if constexpr (isBool) { + return {OnGroupSetup([function] { return function() ? TaskAction::StopWithDone + : TaskAction::StopWithError; })}; + } + return {OnGroupSetup([function] { function(); return TaskAction::StopWithDone; })}; + }; + }; QTCREATOR_UTILS_EXPORT extern ParallelLimit sequential; diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index a360752fa36..c0bb7839ec3 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -122,6 +122,32 @@ void tst_TaskTree::validConstructs() OnGroupDone([] {}), OnGroupError([] {}) }; + + // When turning each of below blocks on, you should see the specific compiler error message. + +#if 0 + { + // "Sync element: The synchronous function has to return void or bool." + const auto setupSync = [] { return 3; }; + const Sync sync(setupSync); + } +#endif + +#if 0 + { + // "Sync element: The synchronous function can't take any arguments." + const auto setupSync = [](int) { }; + const Sync sync(setupSync); + } +#endif + +#if 0 + { + // "Sync element: The synchronous function can't take any arguments." + const auto setupSync = [](int) { return true; }; + const Sync sync(setupSync); + } +#endif } void tst_TaskTree::processTree_data() @@ -174,7 +200,10 @@ void tst_TaskTree::processTree_data() const auto groupError = [storage](int groupId) { return [=] { storage->m_log.append({groupId, Handler::GroupError}); }; }; - const auto setupSync = [storage](int syncId, bool success) { + const auto setupSync = [storage](int syncId) { + return [=] { storage->m_log.append({syncId, Handler::Sync}); }; + }; + const auto setupSyncWithReturn = [storage](int syncId, bool success) { return [=] { storage->m_log.append({syncId, Handler::Sync}); return success; }; }; @@ -997,11 +1026,11 @@ void tst_TaskTree::processTree_data() { const Group root { Storage(storage), - Sync(setupSync(1, true)), - Sync(setupSync(2, true)), - Sync(setupSync(3, true)), - Sync(setupSync(4, true)), - Sync(setupSync(5, true)) + Sync(setupSync(1)), + Sync(setupSync(2)), + Sync(setupSync(3)), + Sync(setupSync(4)), + Sync(setupSync(5)) }; const Log log { {1, Handler::Sync}, @@ -1014,15 +1043,35 @@ void tst_TaskTree::processTree_data() << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; } + { + const Group root { + Storage(storage), + Sync(setupSyncWithReturn(1, true)), + Sync(setupSyncWithReturn(2, true)), + Sync(setupSyncWithReturn(3, true)), + Sync(setupSyncWithReturn(4, true)), + Sync(setupSyncWithReturn(5, true)) + }; + const Log log { + {1, Handler::Sync}, + {2, Handler::Sync}, + {3, Handler::Sync}, + {4, Handler::Sync}, + {5, Handler::Sync} + }; + QTest::newRow("SyncWithReturn") + << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; + } + { const Group root { Storage(storage), parallel, - Sync(setupSync(1, true)), - Sync(setupSync(2, true)), - Sync(setupSync(3, true)), - Sync(setupSync(4, true)), - Sync(setupSync(5, true)) + Sync(setupSync(1)), + Sync(setupSync(2)), + Sync(setupSync(3)), + Sync(setupSync(4)), + Sync(setupSync(5)) }; const Log log { {1, Handler::Sync}, @@ -1039,11 +1088,11 @@ void tst_TaskTree::processTree_data() const Group root { Storage(storage), parallel, - Sync(setupSync(1, true)), - Sync(setupSync(2, true)), - Sync(setupSync(3, false)), - Sync(setupSync(4, true)), - Sync(setupSync(5, true)) + Sync(setupSync(1)), + Sync(setupSync(2)), + Sync(setupSyncWithReturn(3, false)), + Sync(setupSync(4)), + Sync(setupSync(5)) }; const Log log { {1, Handler::Sync}, @@ -1057,11 +1106,11 @@ void tst_TaskTree::processTree_data() { const Group root { Storage(storage), - Sync(setupSync(1, true)), + Sync(setupSync(1)), Process(setupProcess(2)), - Sync(setupSync(3, true)), + Sync(setupSync(3)), Process(setupProcess(4)), - Sync(setupSync(5, true)), + Sync(setupSync(5)), OnGroupDone(groupDone(0)) }; const Log log { @@ -1076,6 +1125,26 @@ void tst_TaskTree::processTree_data() << TestData{storage, root, log, 2, OnStart::Running, OnDone::Success}; } + { + const Group root { + Storage(storage), + Sync(setupSync(1)), + Process(setupProcess(2)), + Sync(setupSyncWithReturn(3, false)), + Process(setupProcess(4)), + Sync(setupSync(5)), + OnGroupError(groupError(0)) + }; + const Log log { + {1, Handler::Sync}, + {2, Handler::Setup}, + {3, Handler::Sync}, + {0, Handler::GroupError} + }; + QTest::newRow("SyncAndAsyncError") + << TestData{storage, root, log, 2, OnStart::Running, OnDone::Failure}; + } + { Condition condition; From fad8ed8e2893f374a6211ff01c33a10acf320311 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 26 Apr 2023 21:57:30 +0200 Subject: [PATCH 0729/1447] ILocatorFilter: Simplify Sync's onSetup in matchers Remove no longer necessary bool return value from onSetup functions and from refresh recipe functions, see df5e3c587a045fbd3d50233ecdde0e06dccf35a3. By default, when no return bool is specified inside a function passed to Sync element, it's assumed that the return value is true. Eliminate passing "=" captures in 2 lambdas. Change-Id: I5005821444a386f70c0f05322812f98d3fd49926 Reviewed-by: Marcus Tillmanns --- src/plugins/bookmarks/bookmarkfilter.cpp | 5 +---- src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp | 1 - src/plugins/coreplugin/locator/commandlocator.cpp | 1 - src/plugins/coreplugin/locator/executefilter.cpp | 1 - src/plugins/coreplugin/locator/externaltoolsfilter.cpp | 1 - src/plugins/coreplugin/locator/locatorfiltersfilter.cpp | 7 +++---- src/plugins/coreplugin/locator/opendocumentsfilter.cpp | 2 +- src/plugins/coreplugin/locator/urllocatorfilter.cpp | 2 -- src/plugins/cppeditor/cppincludesfilter.cpp | 2 +- src/plugins/help/helpindexfilter.cpp | 2 +- src/plugins/macros/macrolocatorfilter.cpp | 2 -- src/plugins/projectexplorer/allprojectsfilter.cpp | 2 +- src/plugins/projectexplorer/currentprojectfilter.cpp | 2 +- src/plugins/projectexplorer/projectexplorer.cpp | 3 +-- src/plugins/texteditor/linenumberfilter.cpp | 5 ++--- 15 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index 220d5d308b0..e8322877c27 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -31,10 +31,7 @@ LocatorMatcherTasks BookmarkFilter::matchers() TreeStorage storage; - const auto onSetup = [=] { - storage->reportOutput(match(storage->input())); - return true; - }; + const auto onSetup = [=] { storage->reportOutput(match(storage->input())); }; return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index e89db528d70..589a30d1ae2 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -73,7 +73,6 @@ static LocatorMatcherTasks cmakeMatchers(const CMakeTargetLocatorFilter::BuildAc } } storage->reportOutput(entries); - return true; }; return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 681c9e1281d..9d076c13060 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -89,7 +89,6 @@ LocatorMatcherTasks CommandLocator::matchers() } } storage->reportOutput(betterEntries + goodEntries); - return true; }; return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 3d1bfb51ed4..3419c117adb 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -71,7 +71,6 @@ LocatorMatcherTasks ExecuteFilter::matchers() } } storage->reportOutput(entries + others); - return true; }; return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index d62a9903071..c3d2d1705c2 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -79,7 +79,6 @@ LocatorMatcherTasks ExternalToolsFilter::matchers() storage->reportOutput(bestEntries + betterEntries + goodEntries + LocatorFilterEntries{configEntry}); - return true; }; return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index 4ac12091ffc..a602be27848 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -33,9 +33,9 @@ LocatorMatcherTasks LocatorFiltersFilter::matchers() TreeStorage storage; - const auto onSetup = [=] { + const auto onSetup = [storage, icon = m_icon] { if (!storage->input().isEmpty()) - return true; + return; QMap uniqueFilters; const QList allFilters = Locator::filters(); @@ -53,7 +53,7 @@ LocatorMatcherTasks LocatorFiltersFilter::matchers() entry.acceptor = [shortcutString] { return AcceptResult{shortcutString + ' ', int(shortcutString.size() + 1)}; }; - entry.displayIcon = m_icon; + entry.displayIcon = icon; entry.extraInfo = filter->displayName(); entry.toolTip = filter->description(); QString keyboardShortcut; @@ -64,7 +64,6 @@ LocatorMatcherTasks LocatorFiltersFilter::matchers() } } storage->reportOutput(entries); - return true; }; return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 9cfccb8ca67..2fd479568ab 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -29,7 +29,7 @@ OpenDocumentsFilter::OpenDocumentsFilter() setPriority(High); setDefaultIncludedByDefault(true); // TODO: Remove the refresh recipe - setRefreshRecipe(Tasking::Sync([this] { refreshInternally(); return true; })); + setRefreshRecipe(Tasking::Sync([this] { refreshInternally(); })); connect(DocumentModel::model(), &QAbstractItemModel::dataChanged, this, &OpenDocumentsFilter::slotDataChanged); diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index 2ab1d6f62cc..f2d22ee9083 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -187,9 +187,7 @@ LocatorMatcherTasks UrlLocatorFilter::matchers() entries.append(entry); } storage->reportOutput(entries); - return true; }; - return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/cppeditor/cppincludesfilter.cpp b/src/plugins/cppeditor/cppincludesfilter.cpp index 1c9cb298d4b..c4588bf78c7 100644 --- a/src/plugins/cppeditor/cppincludesfilter.cpp +++ b/src/plugins/cppeditor/cppincludesfilter.cpp @@ -107,7 +107,7 @@ CppIncludesFilter::CppIncludesFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("ai"); setDefaultIncludedByDefault(true); - setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); + setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); })); setPriority(ILocatorFilter::Low); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 4c4b5be0251..a55cf0e6504 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -30,7 +30,7 @@ HelpIndexFilter::HelpIndexFilter() setDescription(Tr::tr("Locates help topics, for example in the Qt documentation.")); setDefaultIncludedByDefault(false); setDefaultShortcutString("?"); - setRefreshRecipe(Utils::Tasking::Sync([this] { invalidateCache(); return true; })); + setRefreshRecipe(Utils::Tasking::Sync([this] { invalidateCache(); })); m_icon = Utils::Icons::BOOKMARK.icon(); connect(Core::HelpManager::Signals::instance(), &Core::HelpManager::Signals::setupFinished, diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index dacb522f266..76201d09405 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -70,9 +70,7 @@ LocatorMatcherTasks MacroLocatorFilter::matchers() } } storage->reportOutput(betterEntries + goodEntries); - return true; }; - return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index d89e111150d..f4f9604b278 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -25,7 +25,7 @@ AllProjectsFilter::AllProjectsFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("a"); setDefaultIncludedByDefault(true); - setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); + setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); })); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, this, &AllProjectsFilter::invalidateCache); diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index c8d39d5403d..3d41eccee59 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -25,7 +25,7 @@ CurrentProjectFilter::CurrentProjectFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("p"); setDefaultIncludedByDefault(false); - setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); return true; })); + setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); })); connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &CurrentProjectFilter::currentProjectChanged); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index f0ec7269ae9..a48953623c0 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -4421,7 +4421,7 @@ static LocatorMatcherTasks runConfigurationMatchers( const QString input = storage->input(); const Target *target = ProjectManager::startupTarget(); if (!target) - return true; + return; LocatorFilterEntries entries; for (auto rc : target->runConfigurations()) { @@ -4439,7 +4439,6 @@ static LocatorMatcherTasks runConfigurationMatchers( } } storage->reportOutput(entries); - return true; }; return {{Sync(onSetup), storage}}; } diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index 1a7003877ee..cec55ecbffa 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -31,7 +31,7 @@ LocatorMatcherTasks LineNumberFilter::matchers() TreeStorage storage; - const auto onSetup = [=] { + const auto onSetup = [storage] { const QStringList lineAndColumn = storage->input().split(':'); int sectionCount = lineAndColumn.size(); int line = 0; @@ -42,7 +42,7 @@ LocatorMatcherTasks LineNumberFilter::matchers() if (ok && sectionCount > 1) column = lineAndColumn.at(1).toInt(&ok); if (!ok) - return true; + return; if (EditorManager::currentEditor() && (line > 0 || column > 0)) { QString text; if (line > 0 && column > 0) @@ -64,7 +64,6 @@ LocatorMatcherTasks LineNumberFilter::matchers() }; storage->reportOutput({entry}); } - return true; }; return {{Sync(onSetup), storage}}; } From 2b640f3dc341208f51ca29f5d1971782c3b8af4f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 26 Apr 2023 10:44:46 +0200 Subject: [PATCH 0730/1447] Support creating directories from file system locator It was already possible to create files, so add the option to create directories instead. Change-Id: I2e70dba0015ab30b1757f09c74eb2c2dd0db296b Reviewed-by: Reviewed-by: Christian Stenger --- .../coreplugin/locator/filesystemfilter.cpp | 116 +++++++++++++----- 1 file changed, 83 insertions(+), 33 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 8facb0304a8..4f3f349bcdc 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -8,6 +8,7 @@ #include "../editormanager/editormanager.h" #include "../icore.h" #include "../vcsmanager.h" +#include "locatormanager.h" #include @@ -56,33 +57,52 @@ static ILocatorFilter::MatchLevel matchLevelFor(const QRegularExpressionMatch &m return ILocatorFilter::MatchLevel::Normal; } -static void createAndOpen(const FilePath &filePath) +static bool askForCreating(const QString &title, const FilePath &filePath) +{ + if (CheckableMessageBox::shouldAskAgain(ICore::settings(), kAlwaysCreate)) { + CheckableMessageBox messageBox(ICore::dialogParent()); + messageBox.setWindowTitle(title); + messageBox.setIcon(QMessageBox::Question); + messageBox.setText(Tr::tr("Create \"%1\"?").arg(filePath.shortNativePath())); + messageBox.setCheckBoxVisible(true); + messageBox.setCheckBoxText(Tr::tr("Always create")); + messageBox.setChecked(false); + messageBox.setStandardButtons(QDialogButtonBox::Cancel); + QPushButton *createButton = messageBox.addButton(Tr::tr("Create"), + QDialogButtonBox::AcceptRole); + messageBox.setDefaultButton(QDialogButtonBox::Cancel); + messageBox.exec(); + if (messageBox.clickedButton() != createButton) + return false; + if (messageBox.isChecked()) + CheckableMessageBox::doNotAskAgain(ICore::settings(), kAlwaysCreate); + } + return true; +} + +static void createAndOpenFile(const FilePath &filePath) { if (!filePath.exists()) { - if (CheckableMessageBox::shouldAskAgain(ICore::settings(), kAlwaysCreate)) { - CheckableMessageBox messageBox(ICore::dialogParent()); - messageBox.setWindowTitle(Tr::tr("Create File")); - messageBox.setIcon(QMessageBox::Question); - messageBox.setText(Tr::tr("Create \"%1\"?").arg(filePath.shortNativePath())); - messageBox.setCheckBoxVisible(true); - messageBox.setCheckBoxText(Tr::tr("Always create")); - messageBox.setChecked(false); - messageBox.setStandardButtons(QDialogButtonBox::Cancel); - QPushButton *createButton = messageBox.addButton(Tr::tr("Create"), - QDialogButtonBox::AcceptRole); - messageBox.setDefaultButton(QDialogButtonBox::Cancel); - messageBox.exec(); - if (messageBox.clickedButton() != createButton) - return; - if (messageBox.isChecked()) - CheckableMessageBox::doNotAskAgain(ICore::settings(), kAlwaysCreate); + if (askForCreating(Tr::tr("Create File"), filePath)) { + QFile file(filePath.toFSPathString()); + file.open(QFile::WriteOnly); + file.close(); + VcsManager::promptToAdd(filePath.absolutePath(), {filePath}); } - QFile file(filePath.toFSPathString()); - file.open(QFile::WriteOnly); - file.close(); - VcsManager::promptToAdd(filePath.absolutePath(), {filePath}); } - EditorManager::openEditor(filePath); + if (filePath.exists()) + EditorManager::openEditor(filePath); +} + +static bool createDirectory(const FilePath &filePath) +{ + if (!filePath.exists()) { + if (askForCreating(Tr::tr("Create Directory"), filePath)) + filePath.createDir(); + } + if (filePath.exists()) + return true; + return false; } static FilePaths deviceRoots() @@ -241,16 +261,46 @@ static LocatorFilterEntries matchesImpl(Promise &promise, const FilePath fullFilePath = directory / entryFileName; const bool containsWildcard = expandedEntry.contains('?') || expandedEntry.contains('*'); if (!containsWildcard && !fullFilePath.exists() && directory.exists()) { - LocatorFilterEntry filterEntry; - filterEntry.displayName = Tr::tr("Create and Open \"%1\"").arg(expandedEntry); - filterEntry.acceptor = [fullFilePath] { - QMetaObject::invokeMethod(EditorManager::instance(), - [fullFilePath] { createAndOpen(fullFilePath); }, Qt::QueuedConnection); - return AcceptResult(); - }; - filterEntry.filePath = fullFilePath; - filterEntry.extraInfo = directory.absoluteFilePath().shortNativePath(); - entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); + // create and open file + { + LocatorFilterEntry filterEntry; + filterEntry.displayName = Tr::tr("Create and Open File \"%1\"").arg(expandedEntry); + filterEntry.acceptor = [fullFilePath] { + QMetaObject::invokeMethod( + EditorManager::instance(), + [fullFilePath] { createAndOpenFile(fullFilePath); }, + Qt::QueuedConnection); + return AcceptResult(); + }; + filterEntry.filePath = fullFilePath; + filterEntry.extraInfo = directory.absoluteFilePath().shortNativePath(); + entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); + } + + // create directory + { + LocatorFilterEntry filterEntry; + filterEntry.displayName = Tr::tr("Create Directory \"%1\"").arg(expandedEntry); + filterEntry.acceptor = [fullFilePath, shortcutString] { + QMetaObject::invokeMethod( + EditorManager::instance(), + [fullFilePath, shortcutString] { + if (createDirectory(fullFilePath)) { + const QString value = shortcutString + ' ' + + fullFilePath.absoluteFilePath() + .cleanPath() + .pathAppended("/") + .toUserOutput(); + LocatorManager::show(value, value.length()); + } + }, + Qt::QueuedConnection); + return AcceptResult(); + }; + filterEntry.filePath = fullFilePath; + filterEntry.extraInfo = directory.absoluteFilePath().shortNativePath(); + entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); + } } return std::accumulate(std::begin(entries), std::end(entries), LocatorFilterEntries()); } From 1339a4a9987ee8df143eb7276b394efe09be91c5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 27 Apr 2023 08:30:19 +0200 Subject: [PATCH 0731/1447] TextEditor: Add valid checks for text lines QTextLayout::lineForTextPosition can return invalid lines, which when accessed may crash. To workaround we add QTC_ASSERT to guard against this (see linked issue crash report) Fixes: QTCREATORBUG-28837 Change-Id: I66d8d8a46e766caa492ec2178b1fa88e35211333 Reviewed-by: David Schulz --- src/plugins/texteditor/texteditoroverlay.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/texteditor/texteditoroverlay.cpp b/src/plugins/texteditor/texteditoroverlay.cpp index 52ab8709de6..4257adbbdb0 100644 --- a/src/plugins/texteditor/texteditoroverlay.cpp +++ b/src/plugins/texteditor/texteditoroverlay.cpp @@ -129,6 +129,7 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co QTextLayout *blockLayout = block.layout(); int pos = begin.position() - begin.block().position(); QTextLine line = blockLayout->lineForTextPosition(pos); + QTC_ASSERT(line.isValid(), return {}); QRectF lineRect = line.naturalTextRect(); lineRect = lineRect.translated(blockGeometry.topLeft()); int x = line.cursorToX(pos); @@ -154,12 +155,12 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co QTextLayout *blockLayout = block.layout(); int firstLine = 0; - QTextLine line = blockLayout->lineAt(firstLine); int beginChar = 0; if (block == begin.block()) { beginChar = begin.positionInBlock(); - line = blockLayout->lineForTextPosition(beginChar); + QTextLine line = blockLayout->lineForTextPosition(beginChar); + QTC_ASSERT(line.isValid(), return {}); firstLine = line.lineNumber(); const int lineEnd = line.textStart() + line.textLength(); if (beginChar == lineEnd) @@ -170,7 +171,9 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co int endChar = -1; if (block == end.block()) { endChar = end.positionInBlock(); - lastLine = blockLayout->lineForTextPosition(endChar).lineNumber(); + QTextLine line = blockLayout->lineForTextPosition(endChar); + QTC_ASSERT(line.isValid(), return {}); + lastLine = line.lineNumber(); if (endChar == beginChar) break; // Do not expand overlay to empty selection at end } else { @@ -181,7 +184,8 @@ QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, co } for (int i = firstLine; i <= lastLine; ++i) { - line = blockLayout->lineAt(i); + QTextLine line = blockLayout->lineAt(i); + QTC_ASSERT(line.isValid(), return {}); QRectF lineRect = line.naturalTextRect(); if (i == firstLine && beginChar > 0) lineRect.setLeft(line.cursorToX(beginChar)); From e0aaa3960f3aa2b42893e1b5b01706ba8783a447 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 26 Apr 2023 12:24:26 +0200 Subject: [PATCH 0732/1447] Qnx: Ensure up-to-date contents of combobox in settingspage Change-Id: I2b157ac60d6ce79238c22fcdcb042798940ba647 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/qnx/qnxsettingspage.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index 26da82ab7d9..c6703cb3927 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -683,8 +683,10 @@ void QnxSettingsWidget::updateInformation() void QnxSettingsWidget::populateConfigsCombo() { m_configsCombo->clear(); - for (const QnxConfiguration &config : std::as_const(dd->m_configurations)) + for (const QnxConfiguration &config : std::as_const(dd->m_configurations)) { + config.ensureContents(); m_configsCombo->addItem(config.m_configName, QVariant::fromValue(config.m_envFile)); + } updateInformation(); } From 1eb765ecbb990f3c6fcb41fa133e9e386161b3a5 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 17:35:20 +0200 Subject: [PATCH 0733/1447] Qnx: Use more declarative syntax for settings page items Change-Id: Iced5efa88b059a55d7d0b3e33a24bbf3b9423fbc Reviewed-by: Christian Stenger --- src/plugins/qnx/qnxsettingspage.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index c6703cb3927..a06d05a8010 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -558,9 +558,6 @@ private: QnxSettingsWidget::QnxSettingsWidget() { - auto addButton = new QPushButton(Tr::tr("Add...")); - auto removeButton = new QPushButton(Tr::tr("Remove")); - using namespace Layouting; Row { @@ -581,18 +578,20 @@ QnxSettingsWidget::QnxSettingsWidget() st }, Column { - addButton, - removeButton, + PushButton { + text(Tr::tr("Add...")), + onClicked([this] { addConfiguration(); }, this) + }, + PushButton { + text(Tr::tr("Remove")), + onClicked([this] { removeConfiguration(); }, this) + }, st } }.attachTo(this); populateConfigsCombo(); - connect(addButton, &QAbstractButton::clicked, - this, &QnxSettingsWidget::addConfiguration); - connect(removeButton, &QAbstractButton::clicked, - this, &QnxSettingsWidget::removeConfiguration); connect(m_configsCombo, &QComboBox::currentIndexChanged, this, &QnxSettingsWidget::updateInformation); connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged, From b23dbc310c0dd04ae30d4dc2f86e8387814e1ec7 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 17:39:06 +0200 Subject: [PATCH 0734/1447] Qnx: Do not re-validate information on each Qt version manager chance That's rarely resulting in an actual change, but fairly expensive and triggered often, even when not actively using Qnx. Change-Id: I784bc7fa4919bf48711036d655e8246805aa578b Reviewed-by: Christian Stenger --- src/plugins/qnx/qnxsettingspage.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/qnx/qnxsettingspage.cpp b/src/plugins/qnx/qnxsettingspage.cpp index a06d05a8010..992ba9b87d3 100644 --- a/src/plugins/qnx/qnxsettingspage.cpp +++ b/src/plugins/qnx/qnxsettingspage.cpp @@ -484,7 +484,6 @@ static QnxSettingsPagePrivate *dd = nullptr; // QnxSettingsWidget - class ArchitecturesList final : public QWidget { public: @@ -594,8 +593,6 @@ QnxSettingsWidget::QnxSettingsWidget() connect(m_configsCombo, &QComboBox::currentIndexChanged, this, &QnxSettingsWidget::updateInformation); - connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged, - this, &QnxSettingsWidget::updateInformation); } void QnxSettingsWidget::addConfiguration() From 1a1b04064278a7888a2bf2125f0dc8b03f28e632 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:02:06 +0200 Subject: [PATCH 0735/1447] ProjectExplorer: Use IOptionPage::setWidgetCreator() for settings Change-Id: I4267e577ce91d97e633e8cdf513bde496d3f7c09 Reviewed-by: Christian Stenger --- .../projectexplorersettingspage.cpp | 53 +++++++------------ .../projectexplorersettingspage.h | 17 +----- 2 files changed, 21 insertions(+), 49 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.cpp b/src/plugins/projectexplorer/projectexplorersettingspage.cpp index 5a00e272b21..c8bc51b9675 100644 --- a/src/plugins/projectexplorer/projectexplorersettingspage.cpp +++ b/src/plugins/projectexplorer/projectexplorersettingspage.cpp @@ -25,15 +25,14 @@ using namespace Core; using namespace Utils; -namespace ProjectExplorer { -namespace Internal { +namespace ProjectExplorer::Internal { enum { UseCurrentDirectory, UseProjectDirectory }; -class ProjectExplorerSettingsWidget : public QWidget +class ProjectExplorerSettingsWidget : public IOptionsPageWidget { public: - explicit ProjectExplorerSettingsWidget(QWidget *parent = nullptr); + ProjectExplorerSettingsWidget(); ProjectExplorerSettings settings() const; void setSettings(const ProjectExplorerSettings &s); @@ -44,6 +43,13 @@ public: bool useProjectsDirectory(); void setUseProjectsDirectory(bool v); + void apply() final + { + ProjectExplorerPlugin::setProjectExplorerSettings(settings()); + DocumentManager::setProjectsDirectory(projectsDirectory()); + DocumentManager::setUseProjectsDirectory(useProjectsDirectory()); + } + private: void slotDirectoryButtonGroupChanged(); @@ -68,8 +74,7 @@ private: QButtonGroup *m_directoryButtonGroup; }; -ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget(QWidget *parent) : - QWidget(parent) +ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget() { m_currentDirectoryRadioButton = new QRadioButton(Tr::tr("Current directory")); m_directoryRadioButton = new QRadioButton(Tr::tr("Directory")); @@ -165,6 +170,10 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget(QWidget *parent) : connect(m_directoryButtonGroup, &QButtonGroup::buttonClicked, this, &ProjectExplorerSettingsWidget::slotDirectoryButtonGroupChanged); + + setSettings(ProjectExplorerPlugin::projectExplorerSettings()); + setProjectsDirectory(DocumentManager::projectsDirectory()); + setUseProjectsDirectory(DocumentManager::useProjectsDirectory()); } ProjectExplorerSettings ProjectExplorerSettingsWidget::settings() const @@ -236,7 +245,8 @@ void ProjectExplorerSettingsWidget::slotDirectoryButtonGroupChanged() m_projectsDirectoryPathChooser->setEnabled(enable); } -// ------------------ ProjectExplorerSettingsPage +// ProjectExplorerSettingsPage + ProjectExplorerSettingsPage::ProjectExplorerSettingsPage() { setId(Constants::BUILD_AND_RUN_SETTINGS_PAGE_ID); @@ -244,32 +254,7 @@ ProjectExplorerSettingsPage::ProjectExplorerSettingsPage() setCategory(Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr("Build & Run")); setCategoryIconPath(":/projectexplorer/images/settingscategory_buildrun.png"); + setWidgetCreator([] { return new ProjectExplorerSettingsWidget; }); } -QWidget *ProjectExplorerSettingsPage::widget() -{ - if (!m_widget) { - m_widget = new ProjectExplorerSettingsWidget; - m_widget->setSettings(ProjectExplorerPlugin::projectExplorerSettings()); - m_widget->setProjectsDirectory(DocumentManager::projectsDirectory()); - m_widget->setUseProjectsDirectory(DocumentManager::useProjectsDirectory()); - } - return m_widget; -} - -void ProjectExplorerSettingsPage::apply() -{ - if (m_widget) { - ProjectExplorerPlugin::setProjectExplorerSettings(m_widget->settings()); - DocumentManager::setProjectsDirectory(m_widget->projectsDirectory()); - DocumentManager::setUseProjectsDirectory(m_widget->useProjectsDirectory()); - } -} - -void ProjectExplorerSettingsPage::finish() -{ - delete m_widget; -} - -} // namespace Internal -} // namespace ProjectExplorer +} // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.h b/src/plugins/projectexplorer/projectexplorersettingspage.h index 82764c38506..a924681daed 100644 --- a/src/plugins/projectexplorer/projectexplorersettingspage.h +++ b/src/plugins/projectexplorer/projectexplorersettingspage.h @@ -5,25 +5,12 @@ #include -#include - -namespace ProjectExplorer { -namespace Internal { - -class ProjectExplorerSettingsWidget; +namespace ProjectExplorer::Internal { class ProjectExplorerSettingsPage : public Core::IOptionsPage { public: ProjectExplorerSettingsPage(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - QPointer m_widget; }; -} // namespace Internal -} // namespace ProjectExplorer +} // ProjectExplorer::Internal From 198d07e256c1446424bd607b3e4d5558fb56093c Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:02:35 +0200 Subject: [PATCH 0736/1447] ProjectExplorer: Use IOptionPage::setWidgetCreator() for main kits page Change-Id: I25545bfb00af3715adae35ba70e52e963dcdfc76 Reviewed-by: hjk Reviewed-by: Christian Stenger --- .../projectexplorer/kitoptionspage.cpp | 44 ++++++------------- src/plugins/projectexplorer/kitoptionspage.h | 7 --- 2 files changed, 14 insertions(+), 37 deletions(-) diff --git a/src/plugins/projectexplorer/kitoptionspage.cpp b/src/plugins/projectexplorer/kitoptionspage.cpp index d5c709194a1..a4fe93c1f8a 100644 --- a/src/plugins/projectexplorer/kitoptionspage.cpp +++ b/src/plugins/projectexplorer/kitoptionspage.cpp @@ -23,11 +23,11 @@ namespace ProjectExplorer { namespace Internal { -// -------------------------------------------------------------------------- -// KitOptionsPageWidget: -// -------------------------------------------------------------------------- +// KitOptionsPageWidget -class KitOptionsPageWidget : public QWidget +static KitOptionsPageWidget *kitOptionsPageWidget = nullptr; + +class KitOptionsPageWidget : public Core::IOptionsPageWidget { public: KitOptionsPageWidget(); @@ -42,6 +42,8 @@ public: void makeDefaultKit(); void updateState(); + void apply() final { m_model->apply(); } + public: QTreeView *m_kitsView = nullptr; QPushButton *m_addButton = nullptr; @@ -58,6 +60,7 @@ public: KitOptionsPageWidget::KitOptionsPageWidget() { + kitOptionsPageWidget = this; m_kitsView = new QTreeView(this); m_kitsView->setUniformRowHeights(true); m_kitsView->header()->setStretchLastSection(true); @@ -249,28 +252,7 @@ KitOptionsPage::KitOptionsPage() setCategory(Constants::KITS_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr("Kits")); setCategoryIconPath(":/projectexplorer/images/settingscategory_kits.png"); -} - -QWidget *KitOptionsPage::widget() -{ - if (!m_widget) - m_widget = new Internal::KitOptionsPageWidget; - - return m_widget; -} - -void KitOptionsPage::apply() -{ - if (m_widget) - m_widget->m_model->apply(); -} - -void KitOptionsPage::finish() -{ - if (m_widget) { - delete m_widget; - m_widget = nullptr; - } + setWidgetCreator([] { return new Internal::KitOptionsPageWidget; }); } void KitOptionsPage::showKit(Kit *k) @@ -278,13 +260,15 @@ void KitOptionsPage::showKit(Kit *k) if (!k) return; - (void) widget(); - QModelIndex index = m_widget->m_model->indexOf(k); - m_widget->m_selectionModel->select(index, + Internal::KitOptionsPageWidget *widget = Internal::kitOptionsPageWidget; + QTC_ASSERT(widget, return); + + QModelIndex index = widget->m_model->indexOf(k); + widget->m_selectionModel->select(index, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); - m_widget->m_kitsView->scrollTo(index); + widget->m_kitsView->scrollTo(index); } KitOptionsPage *KitOptionsPage::instance() diff --git a/src/plugins/projectexplorer/kitoptionspage.h b/src/plugins/projectexplorer/kitoptionspage.h index 5ce589cd6b2..b3378060bee 100644 --- a/src/plugins/projectexplorer/kitoptionspage.h +++ b/src/plugins/projectexplorer/kitoptionspage.h @@ -20,15 +20,8 @@ class PROJECTEXPLORER_EXPORT KitOptionsPage : public Core::IOptionsPage public: KitOptionsPage(); - QWidget *widget() override; - void apply() override; - void finish() override; - void showKit(Kit *k); static KitOptionsPage *instance(); - -private: - QPointer m_widget; }; } // namespace ProjectExplorer From b3df7c3cdb10f30a3255a716eec2c6e04f1d1d31 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:02:48 +0200 Subject: [PATCH 0737/1447] CppEditor: Use IOptionPage::setWidgetCreator() for settings Change-Id: I0d2f8ffae7ca4e7360de0f69566ab03036c10c53 Reviewed-by: Christian Stenger --- .../cppeditor/cppcodestylesettingspage.cpp | 51 ++++++++++--------- .../cppeditor/cppcodestylesettingspage.h | 8 --- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index aa7279aeb81..190c2f5fc4c 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -34,6 +34,7 @@ #include #include #include +#include using namespace TextEditor; using namespace Utils; @@ -548,18 +549,13 @@ void CppCodeStylePreferencesWidget::finish() emit finishEmitted(); } -// ------------------ CppCodeStyleSettingsPage +// CppCodeStyleSettingsPageWidget -CppCodeStyleSettingsPage::CppCodeStyleSettingsPage() +class CppCodeStyleSettingsPageWidget : public Core::IOptionsPageWidget { - setId(Constants::CPP_CODE_STYLE_SETTINGS_ID); - setDisplayName(Tr::tr("Code Style")); - setCategory(Constants::CPP_SETTINGS_CATEGORY); -} - -QWidget *CppCodeStyleSettingsPage::widget() -{ - if (!m_widget) { +public: + CppCodeStyleSettingsPageWidget() + { CppCodeStylePreferences *originalCodeStylePreferences = CppToolsSettings::instance() ->cppCodeStyle(); m_pageCppCodeStylePreferences = new CppCodeStylePreferences(); @@ -571,15 +567,16 @@ QWidget *CppCodeStyleSettingsPage::widget() originalCodeStylePreferences->currentDelegate()); // we set id so that it won't be possible to set delegate to the original prefs m_pageCppCodeStylePreferences->setId(originalCodeStylePreferences->id()); - m_widget = TextEditorSettings::codeStyleFactory(CppEditor::Constants::CPP_SETTINGS_ID) - ->createCodeStyleEditor(m_pageCppCodeStylePreferences); - } - return m_widget; -} -void CppCodeStyleSettingsPage::apply() -{ - if (m_widget) { + m_codeStyleEditor = TextEditorSettings::codeStyleFactory(CppEditor::Constants::CPP_SETTINGS_ID) + ->createCodeStyleEditor(m_pageCppCodeStylePreferences); + + auto hbox = new QVBoxLayout(this); + hbox->addWidget(m_codeStyleEditor); + } + + void apply() final + { QSettings *s = Core::ICore::settings(); CppCodeStylePreferences *originalCppCodeStylePreferences = CppToolsSettings::instance()->cppCodeStyle(); @@ -596,15 +593,21 @@ void CppCodeStyleSettingsPage::apply() originalCppCodeStylePreferences->toSettings(QLatin1String(CppEditor::Constants::CPP_SETTINGS_ID), s); } - m_widget->apply(); + m_codeStyleEditor->apply(); } -} -void CppCodeStyleSettingsPage::finish() + CppCodeStylePreferences *m_pageCppCodeStylePreferences = nullptr; + CodeStyleEditorWidget *m_codeStyleEditor; +}; + +// CppCodeStyleSettingsPage + +CppCodeStyleSettingsPage::CppCodeStyleSettingsPage() { - if (m_widget) - m_widget->finish(); - delete m_widget; + setId(Constants::CPP_CODE_STYLE_SETTINGS_ID); + setDisplayName(Tr::tr("Code Style")); + setCategory(Constants::CPP_SETTINGS_CATEGORY); + setWidgetCreator([] { return new CppCodeStyleSettingsPageWidget; }); } } // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.h b/src/plugins/cppeditor/cppcodestylesettingspage.h index da15c38948a..666b3ab4a29 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.h +++ b/src/plugins/cppeditor/cppcodestylesettingspage.h @@ -86,14 +86,6 @@ class CppCodeStyleSettingsPage : public Core::IOptionsPage { public: CppCodeStyleSettingsPage(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - CppCodeStylePreferences *m_pageCppCodeStylePreferences = nullptr; - QPointer m_widget; }; } // namespace Internal From d172e59d6e9e5ef13f47dd1964f86950d35975ea Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 15 Mar 2023 11:53:32 +0100 Subject: [PATCH 0738/1447] External tools: Fall back to active project's Qt for the Qt related external tools, if there is no open document with a project. Change-Id: I1d059d70e5163921a8d98b6a93224aef1fbf1743 Reviewed-by: Reviewed-by: Christian Stenger --- src/share/qtcreator/externaltools/lrelease.xml | 1 + src/share/qtcreator/externaltools/lupdate.xml | 1 + src/share/qtcreator/externaltools/qml.xml | 1 + src/share/qtcreator/externaltools/qmlscene.xml | 1 + 4 files changed, 4 insertions(+) diff --git a/src/share/qtcreator/externaltools/lrelease.xml b/src/share/qtcreator/externaltools/lrelease.xml index deb9aa0132c..05ab83e115f 100644 --- a/src/share/qtcreator/externaltools/lrelease.xml +++ b/src/share/qtcreator/externaltools/lrelease.xml @@ -11,6 +11,7 @@ 2 %{CurrentDocument:Project:QT_INSTALL_BINS}/lrelease + %{ActiveProject:QT_INSTALL_BINS}/lrelease lrelease %{CurrentDocument:Project:FilePath} %{CurrentDocument:Project:Path} diff --git a/src/share/qtcreator/externaltools/lupdate.xml b/src/share/qtcreator/externaltools/lupdate.xml index 2e885ef3ed4..f0edc35a833 100644 --- a/src/share/qtcreator/externaltools/lupdate.xml +++ b/src/share/qtcreator/externaltools/lupdate.xml @@ -11,6 +11,7 @@ 1 %{CurrentDocument:Project:QT_INSTALL_BINS}/lupdate + %{ActiveProject:QT_INSTALL_BINS}/lupdate lupdate %{CurrentDocument:Project:FilePath} %{CurrentDocument:Project:Path} diff --git a/src/share/qtcreator/externaltools/qml.xml b/src/share/qtcreator/externaltools/qml.xml index ec2cc5a9a7b..ee7d5479a74 100644 --- a/src/share/qtcreator/externaltools/qml.xml +++ b/src/share/qtcreator/externaltools/qml.xml @@ -11,6 +11,7 @@ 1 %{CurrentDocument:Project:QT_INSTALL_BINS}/qml + %{ActiveProject:QT_INSTALL_BINS}/qml qml %{CurrentDocument:FilePath} %{CurrentDocument:Path} diff --git a/src/share/qtcreator/externaltools/qmlscene.xml b/src/share/qtcreator/externaltools/qmlscene.xml index ff8751a7ed5..09b780e521f 100644 --- a/src/share/qtcreator/externaltools/qmlscene.xml +++ b/src/share/qtcreator/externaltools/qmlscene.xml @@ -11,6 +11,7 @@ 1 %{CurrentDocument:Project:QT_INSTALL_BINS}/qmlscene + %{ActiveProject:QT_INSTALL_BINS}/qmlscene qmlscene %{CurrentDocument:FilePath} %{CurrentDocument:Path} From 85d25390c9630bdc2dde1db3651e6b9469c70c59 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 27 Apr 2023 16:54:10 +0200 Subject: [PATCH 0739/1447] Doc: Describe the markdown editor Task-number: QTCREATORBUG-28996 Change-Id: I9222f51e5e6c1131198a0eef0361531190675db9 Reviewed-by: Eike Ziller --- .../images/qtcreator-markdown-editor.webp | Bin 0 -> 22486 bytes doc/qtcreator/src/editors/creator-coding.qdoc | 4 ++++ .../editors/creator-only/creator-fakevim.qdoc | 2 +- .../creator-only/creator-language-server.qdoc | 2 +- .../creator-only/creator-markdown-editor.qdoc | 22 ++++++++++++++++++ doc/qtcreator/src/qtcreator-toc.qdoc | 1 + 6 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-markdown-editor.webp create mode 100644 doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc diff --git a/doc/qtcreator/images/qtcreator-markdown-editor.webp b/doc/qtcreator/images/qtcreator-markdown-editor.webp new file mode 100644 index 0000000000000000000000000000000000000000..0943d90fb3b0f5a3e507738aec95eac774e38dc8 GIT binary patch literal 22486 zcmWIYbaOiw&cG1v>J$(bVBvExoPk0A_2GjI&k`?eo47>nPvrUS$Op^k9ou)M~ zFzT2-+&N3-fviBV>XZKwIf40EX|HwT6Zv*3zI)8MB>aPJ=3HYV8<|NWm-72U=3l3@FL?!SNkv(08}>)n&%*cVJSlW3iA`X%F?-%Hvj zRDaj1b#OSOHC5qqvCyU0Dj`)d*AHkNeOkEq(&`!S;v_l}wyg9??CSQjI@-#hzE?c) zE_Y}Q>-*AqjMLip?s&JO{MQEiH44FA);pso%dJw-Uh>@~=$BTmd98yHW0gM358wAE z8RVGWsUJ*TqQwy78MJ!o-4oMJzq3vG>tw#g>(7TR3tip^Z`1C`nx81I+BNNNfmXnU zC->?FroNvzo1s9~`=|C{Q6KiUhZXj&-AeU(b4n&IJ~;D0$K=buC5(l4GBi7K%()k) zP@t{1;Qzja+v|dFZ(Dojg`Bfb@+KQ+QO_T}zxn5V|9{5d`G#E@?x>YBZ@3M13LFMkd6Q53%iQqD>()lSC%_^%? z*mvm69NWZMQ;kw3wrve6eB`iq(&3YT4)H5Y)>FOhtL!=H$cpKQb_H8WEKZ+(#DjHl zPf}t0;)vBBEqYZvi(;}C{GZ<`@vwS9LGZ<8O}U4AWuG_bSWNzv&pk=Sv3Kc#zRedW zheh@tRMHI&2~YoTVt0e})zZ)g%NFh0cUt>@RD@Z3NZNY|+WLsy^q0ElEpx|L-naWEJxTRv7uBEb5)D@EYtQ}X zYMh?kpuYe1qcX`d`D~kAw)T;?RT#fN%?&)88+eBCdumF%q-)))*7{ei`?Fj3Ww-9j z+MR28=lOqw-uo+_^{`$(CDSGE@aEH2y^Q`m?w$~>mp%$hlKk$^W)k+vZ@yd+mohJ< z`SPUv3#IYTeBw%uH1XS_udSi?p%zLjNcTP%`2J<_yd)4z7XH;!j@4HF!{o&;2Odlq^yJmR&uiI{(-_k&0#{A0^VJX%gZTH$!lCjsf3h8^V z*`_(|8Yf#n$F6l>(!4Kh_uX0*nY8-Z^RDD~YPRq8*B|sds=7!ovpjUK{iohb8AUsm z`%e1U`+xR)nO8F&S1$IMeE6=-jR=-U?Vd}fwrV^KX|tD_`Mg%{;sY5K=L=HzDy{pr z&N1x9eQzgXLe{ zlp<{IZpqXXtXfjHD_5*g`HM%OeH1g-3tdjx>#Uoi?e2b5ky$PCn{NSYwVvYLLmJ8_ z<}&NPkr2r~(0J^kbhj8&a9qH(7pL`~UU!^1KS-{+t2ICT-?TlIk**P6zwEqn`1q&S zMonKbs~@VGhAGNCOlO{7VBnAuAd|Z6o87lXnt}7Gm#}YIk-+;trf9=4hOVbxw;8&1 zbq;Uv$k%j_U>1*a5}5MUtKIL5`_ZjSbidu-@31^*L2M!C^1i@#mIj;eJzZ2^^6c?} zsDo1ZTPA9&T&q~Dd)K(?^UmFKwCkrZTSf0$bh5c*!ct=xLggM;BPdroJ`1f8c5qQV&q3tx9UK3Du-AY{v@wDhI}&Ndu% zEB;%pGVQpwmq#JE?fA#Kr_;ae+~pt5FMqjP=paKFOI$#=|KHYo+f%2u9=?Cc+c zM~g$xf3!IBv~;dmldxdk6w^W!7amfz&GjYw=gaD>(tp$&SPpGkaiu%rJzoWVOM0N3GvllS} z1&pT0;eE%ULv9jdp!O$)56svwN-=pwDsNTyR8{aursie%jdt&O|^aqtOIpMSX?>uJD`Jhpy ztivJB9#!1d;qrTImlo2s0uGdcn;GT(c;sIBzRm7*W(^47I5bA5#bu!qw`+oXr;ev&@|oXrwfH_u&spegGizthm&-23(*v`0@21qQZ9lJJ zAEEHZ`O>mS#cZFy1gdU};`$uY&G}4a*OBDHT~WJ zzJKnyCAs3I$pdA%%UNC`jG+Y=MI*aqLeltL_}QA7okXWB{u#_0oOwoO(ucFNk7Zlc ztl2Ipbf3eJ&9{HKQ^Jyto)4Q;jxy``PD(0bu;FaDKHGm%-X=eV`N!o{)LRbJaU9Ct z?P>AO=atxrKTgxO9kSU|nN`L6+~2Tby%?|jy*b^SJIPyj%$Ic8xBg1ystRAu&844~T)Ves>g)yuL7TSn%7*F# zmwkoz3(ec|uyoC*X>C%cCg`6|wwktN$q5EWCaaAlxq57W(ltMX&AqN};}9}a+??s# zr1zJu?Nm{%-DQ2%V?Q^)Lv`dcDSpYQ3;aR8y`QS>4VTPUQ<^&0M&^QViQ7z2;AY*( zJASU<$Jthe7iXd;1?jUhluV0be{qV7{prEfX{oj@ybrI6@cDnJ5R?nHJ{g{G_Rl-3K| z^i;zSv9T;VARV%^5k(%Wr>{J)a>u}4l@&I2_Hx5OUq&t5CpJ1KC%)&(bK>@n-U6`LMl%VcW0LrM4u^MXk{ zqCJw52X@3L?5~UM?J-iFE`CI+(QnIjhVR>AZK#}UP>a8Ks5^W2b4z;_?-*7`R&5V=7)njQ3<0)r$kT%a} z?}VP)u95Z+yAo*Oy*O*xgd#?J(+$gI6_O5rdLLNCySPs*Bxd8(mr@7i!@SD2ufC-$ z`64SpB<1miB1f?fr>f?Y8;&2?D&*&Neu>QPkd)htSGTOVF+=+)tJ6gxr`84hXSh$z z;o9hOOXP^UW$JtlwJec!s}?D&U`cH~BFY&(TjD~|LCGZ1C7WZGG*-Rg5juO=&Sj&> zfhvtBHZHHl!h=QnoP@TtKCvz5Sx=ycgF>o8|B*3^$m(XWP*FxP2p&%P*5P>l?e=d~0GKwiljD-F?2a zT7T-7?JevkvT-H4+(qxXrRt*@_qA}WlYe}0^UwarVjX{v?x|eO|MJUs>5a3F%~5{* zJ0kNzo|d4pScYQ9iK6H4? z3%Q9aZrtiKcqw>OP{zOY*7D*Ra)$n0RXS+LWn#GpmS2t+i8^8)G2_*;L;BU`*K`BiQ~q*`D<50#6e2hG(G1>4 zUh`EtMHSlq2gkX}Cf`ety1$=u(T5rPGB+NrPYe4c5_9kEnsuqiew`hD$6L+yW}5+~nw6tF!dm%QJlu@uuITV$W?Xo4YY{ zTXc-~%9A?lpF8?(v^dd}8CHAz`Z{H1_p<^8cb4QvZ@Jbqf#r9$^y`NF45#Nl*rC35(OmlmwvBG>8yz{BZ*#VKbW4BAVhcWXE`#I1 z^_?qIZ*^6N?TgIGk&tzV?xL;Xy?~K(rN~+K&XcF6 zHL^%8XmL6+@gkezJdS5VXJ4=DO71wcgE^Z;zH^<+o%s4& zoZim7@bk={+LkF!JzO$tndQ&(j%^un+jmUs-uE}xn=^N>SiF_eHIDOoN2aTkD&-mq z2TUml%RX*%`REz7D5EU(b+cR7mWrwi$Q<~bqbn@Eo#~7E*@BvTI!V0?_PEH7J`#5kW|$biNH#dZD%)wDX;$}Y zpHvfnu~ei_5ydca_E2CJ#=D_O?G2WuW7k_R^{c}#?HFUk(BJlE4>8-O*7Vu0{?>4$p z6Pa^ea9ZlD9rHx5^W~qq?aTC)=VvA3*<@DD{h~7S&ACNvgfc^d&vUhA$W8nEHQ|2s z8o?<=5(X_y9};deEU8>0_~qHvFPk#XOxPB(-2T)o6@{$Rn@?Sz%D=ww*^e)pD*j?E z%mUpOdeX0|!VY}mQ+Ano>c#%=MpHd4^B?@&6DjbP`H@PaOyY#ZnCF zWybncD*ip!42cF0m4GFG!V2o|>Eu{#+Thw8vDi>XD=YPh_@|I=$xAw`Q|p%Mor?J%1;>VY3=X$1KKU z&#vu?G4Bp&v}*Lbbl|{g4~vy`lIuPt7tfHFs0`?qJ;gIu{YlD&xhtw>s=g9yjGF#B zP4KL=wfgx8WrGF#t}kzV{yf4*EuSTa?=$n>0B?>dxnbuTmwY%H>Fg7@oh_X4UFqfr z-P;`xZ+rR2YUAU8`0bni___(D%hpRyJTh~_dVQbQJJ;(uwXTn>to{3QgZ*pgteqAQ zo~A$eXYl0kPyUSx{|+qV?BhRD*z-SB!1kk!cKr256Wd=eI*+rTj{NycYWr=&@H_7h z|MS_+dQzCbs^iAT-=|(n>DbTf<~@CVxkL~5EdPw7iT1rWmZcWdO3q9FEbsoFbJFXI zr^jp}8}60viDFDDDyh5dr0p;EgVph)lPLG0`EP3G=^S`(6_**j%b?pPlHp*X)Y7NsD&huX`W;FFn%Hdfbv!@rh3uP%hDyg^l zc0|~}q}<}zjaO$b?(|*UxvTP)&E^09oBluNiOe=MW>Y(SOM1`Wedm52OgJ&Ga>}&h z@u9QXQ`WNHU@xoMx?1e3sm<29&acc(O*3qdY)D;tEq}`5bkh{CHA{Gmy%n-^-!fOG zOY%RfUODSz{LxTj>n|q%ryMj`&)>G8?p$xMk4#a3c=4V1Bl!Z?GcRPP{tCR79GDcc zrFNHeZH8lf`~Ls$elFP0)zuuf_IBnRQ-^w;4Sw8_=T36$Nm^KZe52F!H}wZY%zrw* z=d4mNeI)bScU^qBUyPj9>xHYcrZ<-!vcBJS-QuMataLv)z4iZPc(Cl^b*@jmR^>;2X>l`3 zi-%S0z4ztGwBV}fhOb+mJarcImQl1(KB%cHf3Q4nqq=pRv4j)rmQ9i&i|lTF__FQ6 zDvhNApRPNxZke#RY~OU*OShX=N5_;$$NgP1X|I{hUfm7rl33>Ly{5QV_sFsJcNbqh zpEhr=nZ{mSVQ%~FX8WF8aagP)ZZFT%_G5nDMsEXvS*Ieg4B3tF{AITfkE!b2K0WEg z@(D5$LX)JO1M>WOxBR;owD=#hX;P|Dw8h-)ncwbv`4@1`FV@J(U(q~A@@+-#k{fBw z=CV9hsp^|k=SoO^;PqNqcW&|Xq{wHxrJl{*zCU;8$()($Zf$?q-Yv*?sHr=e<-xm1c;`yGt|5mx0vLCxNEBqV}2h&c&j(D@zOeS>qqO&oab<6_29OPr+@mm)C!%}yUWP<>Ds0x67s>yHgk2e73yy4 z2uAbue(avxA!})T?f5n8s%_Ja&!$@2cJ6&p;*ow@>Vp34)TEOO8`+iTghuf7d`wn8 z_ow&o)*BOzl_x1)ef_g1@k^DVwCDUILXInKk`KtOZ(F`Ob)tmii|J>x{yNT`zoPb( zv9yAv!8ZTCy&wG79POJU`F^SIT-o_Ld**8u-nrtjKJ(D!n}=Ri>@B>lAkE91X)vYv zL&-J;YqRpII)i|Dh6(oRvX^ci`ejk$-u5I=zG0b!Wbd}+vm1n!n}4Pn*UHbSl6p4% ztO(!d(`iBbZ}~oHXacialoK2qmd$!0cl2&1_#_3rP?fHgDj&|Rataz zG0!|=k^K{k8ZFy@{7n5U^XA-9<)1}Qu3WbGmHIiGV_99~ z1F4x#bH&;$+Z*^+JXU&J_*nbigT8zE+=kl)f|j=?o>O#bU-MY$E@R!zl7nRppC<^E zp1gdE_ljk^fb6Di%_Zz#Pp2&ncrN2qqGEsK==)VG_Pwaz#WSP0qef?8Y1E2hK1bPr zn*_UT;z8`mR33}4T@Ddwd5@$v;vW{=S7 z)BMvqi)xH-8*TqF$y<3=`H5Zj-chs5+1Ob=K5i&Zi#F?;`0&~Ev&D~oXzu@hjQ`PG z{oBiThc?uQDV&iZk_P>t`k0d!+Dq-Kwf!dz~52g~gWb55T48zfz4Gg)jcu#Cf`g>7uTJ>vD!0>_lS&y=Mp|;1saWbM*pvd6<79jliXxo^I`ZB1Y2>AJ-QujL+o`gOZqVPo_5{kfmdPjvjd>E%X# z$1i_57Tvjgac2G3o#vK7o_##eru$B>8(UH`o<+ z=sSG6H1l`DzdJYX=UsVk$I{4lMt`>6Z-FB_In_K8-N8tY70xVJn`*U`^ zaTchxZ<64*s_px;wr1`-XMqL>xXq6|?!I#tC^+y3>=d5gf=4D=-ECJeFr3f*;q%9F3{kyZ%W>)2y!hu&_FwB;^HcP?^X_G# z%M}(2B`#ZgY?))2%pAj0hs<`U_AFo!5_xb((dl($)y7%>j-{r>GbXoNO}k^vNKGV5^;#qor^8Wj{;76f4dk9yL$IGK~^&*eLoGBzkj2Qz6jsEC-g8-_l21Fn}vrMZ$xG9`TM%3 z(U_l`qhYeb`?5uT>X!tz_M8a{-^iS`cS70R4;z+QURk%hCAjlq(>IN?`3+hB-rll2 zVz@u&(OK`{^na?~WgiACXK(W}JfX*7+ny}?CN@#v+pOl3zQC zNvU);emZm5iD|*2F85CFp0tFg4!Xj-O#e>*rn~F2&a}^|i%wts$-7A^B(21aIp}lt z5u^P%hYYuXA-S9Va(z&$+MA*=4KMed?m@n&y(6u0Fo#3>%%BKvHK zGS^0ti9$#GQ(iMCOylric*<~?bF<~9zW=+=O}=kL zgtMG8HyO9pDMg1e`AMth?7W`A^mJzXOy&aRu!CM-7#6ho8P1r#XRB7@m89g$|FQ*6 z{@K)7_432a`iTcV|81JeydymP?a8|I#XdG;QFFU^X{L;-=bKEWmBz1( z`8TsUZ2voz_n*=2)CsL#Ze{;f@10oczSH#b;wRA)W*u0ctIYgo)68q}>&;);pI75< zZ~HENwO_l>agx2f-?^U-|KjGc$yTG<=74F}cKtm5P1w$*PI#m1>Vy1;-f^}}U$s5x$({$tzP-!~t@^)V zLsE^-%P-6y`n8$X+IP&3Hw%}2uW(m5WMOj4^C_D?m`i{E>Jq))UVO^ezn>Q$Ic_u6 zX#RSa<=@*&Kc9YfXy)@bmn=*5E4a#abU&MDahAqvcRb!QqweARJs{pZW3*O{E-}mvx{k#YBuDEQt#~rHPBmDArMzYMf8VdfvZ!)TBhQwt zQLXQ*CYqOfFIn3pu=#u6(v@oKCb#y-o9+Mja7>=6^gPtQ`UCliKubm+Z`La zFDRN-?2Kx@(I(Sa6}^376LUarf7mOJ3B1PIHQD?{?Z194uK&n=UAzfmMD_vY@Tp}V zuiw4!`Od+`oyQ-5r?IpS}HGtNWe5 z+aBrWf=v+CkvtH#f7Om-QnIX1;`yb1q&6}p_3}m93a;4Z-kq&`!EMo}xf*t59=dY7 z6pk2`>G)1)DXlbDx7Y4)e#;QHIc(XiSoyRz)$42LcwCt9WU*-0(m6WY<$W8MZLhe~ zD9(98K(<_`cSm^YzQE}Ft7|$K_wT;5@8A@9pPfhJ=d6gHq?KWEv8=8v&oZY5u8`?0g>N2+mU@yqXTo8rxc&5xWH z_58!|C+6UvO*41xfAe)myqUhwC#iWaPp&<+|4L}fQw5#1ft}WS9j*R&ihpu_GGl6I z#zF?;N#SB$ORnw_Za$f@GEUW3_ew!p;RnT&6Hc$5=bJm>%4Ta@0f$egoF;BjvR^wd z`P+*~rOnHiu58u5d$8SSSLn|mYGmel zw#6(Jy5!R4p`k6Osm8YH%R`;S%2dWP{-=x2FgdNCw(MF?>lU(CG zOZ_zq^<w7g6-?zhVsD4%a6H)9>3{70`hA^y3chB)d4A`tP;LB7rLKK*j4!hXMm>s(xLwzK z`;GKTHm2h%|I}t{`6Q=UILHZ1yH?_{S1|0!|J?H_{5ty!{_Og1vr|d&_o)!qi_?qM ze(7u|<-KXYrRaFNbxv97sr%cPEi!RyV_&mu!sXbncCBCC1P=UOwneV1RWdGOZhWoq zT<0s%PyZwb$1c3TWxY?UoNN5KnJ=7m3QN=GXB0oQO*dkC95S;uTgxIj#o||Lai*`G z){2C^f-E0|#MZViy8QgR?e<@4DY0VuHtt_m|2{S41!Jv?{tITG!nI;s=dO8i@A#@S z`%Fa-8X9^1-@bn7RJZR^bG+V02VeBJVazD8cpDwep;&!%iuB#k%HP*Su06hE>Bh3` z>C14|wYR&=maA_MN?Mn-F6m#xgP%cvzMOs%wyVu-M?!%EgQ#tQVpreN$lR?~Y1@xn zoXwXJ6{X`hZEch8G~?Z-w)Q!tuXZ}@&pEb1+aqB03W1rcD$1fhJyBS|6%{lmhkwbU zL-(zAU;p*wgv0(EHv@&trOTL96T+f{j<1Q6)by|FZdxkllk$7lUNH@KwqL2n{|Qha(w&h|IwZ>eaBykGlv zznFeD?ETlOMJ8@+pHHWKTKC-P^XW8}eOW8x4jaF+UtG@o^QQFS-%F>?G2Z1{Cx1Om z!@cdr%Vo+_*X=xDyzcGgyGxj!9RvAU|62REmJ&r>V+Ai>r=Fh$CoL=2dV^fMjNd># zfA2r8HM<|3-5AGp<2O%LtytAxksI<{LhU>4xcBCZe*4R}==#jW_t~spwlA8PWcVp_ zf$+Z*kJ>Z-rDZdNjsMl~HTcEfjR(}F1N2!d{WG@Oaqq3;dc)7!c{pZ1Yo~YjqUd=PoH(kUlg9GwmnM5z?|*l>1F%@_N}+}bFy9YX0%NRc)fYU6@SI-y$OXg zUT;>&C~UjZ+-T)gefL6?^737=3{Ov8`m^=7mHKuyHl2fOeIl%VrP34}TR&(xedpyp z-_E_tfo0{!FqIQ`f3^s(b+i?KSj_+OjM$oqzce@e<6@1{Z{>Prdd1(cZll97!GQU# z?7u7)^rgAJw3*Llx*;ZV+J3R3M==Z7G))rMeqwRdP?=Ec+#DWc;=v>sk-T=z+-)WD)M&zI4ya?5wV7g6E6a@D3LDUtD0roe%72GJ9? zo|Bq*(y)1o3RWeE*$!pyAKf6_2KEKP$P!AZ6`lk*tUBe$HbOJ=?U% z)?|WyR$+6>n$y33PO#O#P-U`PPwYa#L?@}V0}I67O>;dL6d|Ld5tOWJQFhB=&X&4! zXIK1JG28d?$&HzhLuYn-to)z1Vb>(LUnvhCO!qB{t2wZD_hsGh@&7MLL>y=Rk-FK$ zYV&N-U(^51D7m`p$%zjiPOH7HU8eZ`=&D8SZ+Z<)zqcmlDZDEd6x?a*6L<8G#gomm ztmE$a%G~*qCNKDIx^LaPRnvYmt>=+DZ1iN`g=cI*hhkg|wzs_t)j6{@Fo0XV_shvg zwe=4=q;LKFz;Lt5-i_#4mJ9^LqS=ATk$_wmEeIEpIkSIxHA@$&b(p#3>voVMRv zt;_}Z1M(R*OPlmH86Tf~Y--SP*Bhc|JspeUH6m=1-<1jrZHvuAeWMWna&BYqim#FxM3A z9ju(WM!w0l``0{~)7$bgutj@u%S4X`pD7;ppO1aF$eG%e*ZA|n_V4?>7M|*nu@$c3 z7J8&9ytgxsIqgv5Yn6Wmf;L{WU#tCVIJq{g+iU?}R8GH6iD%f`nT-O5{?}f1zu0Jc zt-)hj)W$Pw`F8KVee2)X7dqGf*yYr2f4jWyM8k&c%;N1^b+dK^<4NK3T znkSL)ICZ96a567PkoJ^=Tbs0}hVAd(=lojPPlv&fsY!|Z!%gqc6*>IEeYTsN4>lNX zzZbkr@%s*SnFM_mZk=22PPVKRQ8ZF~`mXTCt6iKE+vgas{cDzfZDN#VgXA>99{b27 zUuTVZ1uwRJYm;u;uDnpG+`g;qQuF96|5}P}BUuW3@zFQ6()Y)2Za*HrYWjkzfl4L&d@3)-P56AeZ z`2Sh6!tFPH%KYr$cye9;TS1}Sa^X%-53;Si6y_Yea6^*ESuP19wSF1N7t?+F=jHvn z`&rvNz*h3zfoktgBS9;j^k_#W(43JI@tg5&Zt5n!_W-Utet(aej@SP-S@LYl;Met?V3O&U3jg`?jZe z$Fb{faS!|FY1TLIZwvFZRNWa9#z|VXvxgIxm*t#JGUzd0=fB97HOs>kQ z7@hX4st5b?LUP*(dcKV^;O?K^^$D`VJRaDIUTxZLfT$ehp zl=Yw%$TDw#bJG*=AMy0a2ivtS_?9vGO7X%)?>+||p69mx`eesP4trOyKXYj+mTvU- zeEs}VoQm+$IgjQ3{QlxKk4gSaQ;qEY+1cf#i&ucSN0wAAKfu1b!0x!LpV#&|$Kt9V zzTR(N=4`=gccbyU<-3BQT@OvZ-8!kw`$*(R0{gw^JJ{z=xu@XQ$e$H($nssH`cm_T z;0J&IevC2LpL1*#|MY^s-5-~fEMT0&#BXi(_rs>0H%|LLntryU^}FS}Pd;U*GvBcG zJ`|~F+`r#XY5FTY@cB=3(pd67R${FbcV{d<>E z*U!|;ll)66=W8zlYd-b+s?oKGV@HlAl=&%7Q2fGb(;kqu>iN5?1#z4B>8^DhLTp+~ zQiWTWnK(@B@Llt6-Q?Epcr(soy@m1)B3m!oPR!SQvEY!-q18K`L{k%+_ZJr0sozR{ z({FiyZQjl=zsqF*Y|=b+OJ~xm7S->om+oZwBwESDUcL2}(XX^MA1&5ut8M;lD5==G z>o&L81(u?eiXW-L6W(ec_MGdnc=kmhzmt=GU!62VK!Ww|*J)ogwoem2)uk-f6}xS& z&xX5)wmEkcO*Zj)H7z49ebv_7lz{y?%ihUIa^BaUz4+hb36ABvuYC>ec+$frJd?j` zt#|e7Q+sq49K4#Qd;X7ZpNh(Xq8}MEZGL9Xzp7i*dp$o}-R{T5QyYFxQ=7Yjz5DIn ziQU(yw`N~UGUW(z);{HQW%b!Z)|Ru**-VYK;J=Wo$ouN@#ZXRWVebpV+(*=Rr={le z9@IX3%Jtn(=F58yJbhm9p=w*k*{G|(HU*shpfJC1%4UcsLk?ggJ>^-Tho zEQP{JsSz$2zfTgf=}?frGU&Cz-Gts`ngGi*KZ1|>8;Go1#auaY+AVIGi{r| z_O+=k?tE)|yxHSNs%C}?d;G+v+nk+f;T8AViJ{yEG!u1lx4+mOP*bM#$Krp+S;Dmo zwU=M`&Y0Ex;>-03f)%{`8;@Hxtyve5@axR3(l@`D9>3zwi?C?Zbzf)CsJ7{!N%GIH zlIH3eHEE9a;h%4;4@`f_V<)pS=I5iXs)qVgo=4^@Rp{4GDE`rOko_jt{zm`EJ=+fb zIxkmLe~asc)XYWkX12dl5*>DKpVAar{$lTq-hTpKhpqq3wLSa5IB%ZaO0MM6wZD7+ zimu$9WFYRi-EhvNKZpG#+!nrIu;Y;FW^d=)-*~mr^W+AF=K)oriF0iq`a20&P5qW6 zXlh!}>vK_mwp{Hdj$;+~qdxwby@RE;v1E>O=r`T7X;fTs1(0U`TFOY%+A+uUUo*ET;wu2=lbn02TYAz z*W2#;a+2x#9FgnuOlo8uPwZ;Q$WDk_#J;PvRz=TO{vJEepJmHh^k?zcJ!Z=;$%Pv=&{6@QOysD3tkjqa*!i+JAnc={n$+TYv-o6mDe3I zuqt|Fn8SI${eHu2Z)fu#jz#hsEc>6d7wtTFu<_9Ubx*y2*vTyZAnlPG7vptz&(YUk z-Zy{ZeI~eY=@)@(=hjv&Dt_=MKu~-7Zh;R{H50ZL&#sZ@a#CHlIlVSGzBYKYrEEDvyhqI5`x1=vejeNE8frUnX~n+k4~h$38g|IY-|2Qk)<&)E)$#ZSFAEe4Teg7#}cy7WAvyV%U99ie|(Wt*9VROf_=k30) zv&8>ydU;8m+w$n&rCT3KNAUT)=52huZZb9I#ea!xwBny;?FwKm-E;qNQ?4uAGr>aYlOIPB}$dUe)(6Mi4|w5@+iza42c zcbQ(v5jS12;@pHMZ{vMBI^AXDKYLi4bZ4Y*xISm!n=6+mF!$R9oW?{ z!PH=D^7XaV$D^;hUz2sYxZI}r?L6a?97k#jq|F;MW!*w-+dgipy(wDE=4A7kH@iFQ zgNxV^SF_KvR~p_g)qbYVqio6k{q6ndg83VMEIoIycA>P}@vuEVwq&2w=lU>%Eh(`0 zr_${Dlj3t;$gDC~u$}$CK-cd6h5~_~O1s6xr?-Eot$jGx_20Ee|MqJ0Gi_G*KjY)S zkd?3BRDM~*Sb1*3vI3+25|7Ot9bao_pA%g-QS(RY<>mfjJDx4s@NEg-YmTPZOikGd zS;yB!$4?H9l|Pnx;k)X7qyB%szE_z|(qTGT3hMxN~E^nHc7fxPoh zH0?+*IQo_GsQcepJMUQCci-b!&#`*i<%z!?ZrXm}e){l4ZGz_B#fDSYGd|h&YtpCo z$4;-z9p))a-^s6|TCSuNpK|@t^gBx1Pez?t;3&j!v63)NRfMaAWcwqZ{6y_c(cvK)?GKx*7vW= zxhh@D8+&oRO#GvX_m#`?f=^jhXVqyt9{1#4e_FsQ-Q(3R@x3O(+w3H)X1d?HqNDV5 zL9F7Bt5u1Y`8$`}?S3cpbz0p{)`+NnE@8|4A0I5=uf?qV!KbzOW}ol%G`;rtOH)q@ zN1pTdS@UlG=2goQ4lcIe!G8Na&z>vAWw*5-oqrnGe&EdcWx}`Px32he@0Nq;wL4pW z?KJ*VFMq$KC|BVBevR!1A1dFPEF*bIfA-Y_XPX68*X_)FT9j^)B!B+dV$7Aeka-D5|Y?l3x_lqj(D>fYb8&jwy zk*ezx*~flK+jnO4p$XcD_PH(lHEa5*dpSn3Y_SsUG0m5Mot*1{YWhGfp}9ihq$U$IZ5Txl(^38?y_d%y$}l z=<(RHx7peGDqm;2qxa?Mw~Ts=O}9!L=Bcmyo-FWp`AUcL(wo;$)O?}7Q;sF;y;<(R zH3#M!yizV_lg}^a+Za{a(N2(H?PZm+uWA1d8}h^ypnkF z==)-EZ>{;(hZ#$2W_hpc?PnF+CDET19VO9VZM!q{>-FbsE}>@wmaA`nW#-;?p7C2= zaO)5M;G~nD3)fCu$#wdxLh9?iw^OVoJ2bR-EzrgDrMN=@&k3 zdw#%Smg_p+qTM1p4VMHJ2Y&Hn5AE&T+PD7t=eyIdoHe=5wl~(qHZ3$|Q)Kh>#i?bH z0jfb4qV_82nsR=ecK1X0qhn5nvk$NYJv&(U{+gw1XmRGFY|Fc+8IxkCRe0Ze$C|l{bDJL5N2d6b(%h~~_N(6D(drcxPhNKO zObegGxyV!7-Yng(R($o?(_04GIyZI7d}8<7^Rb;i6r!paH{spFism&!=3-qv6BkK_ z%<5~qTcvdBK;V;xjypGcn<~l_txxJRykY-yB*EYLbdaE_=+bWd6B)n;UV9w%3&C<}0^*&Sn z9qneGB7Sz`I~Dt`5Y?ayv-T?JniziUTC>Sa%&UXb$Dl6Nq+-SCC;K&-!xQd#*YnP_ zm@V~Q?E2lXi_=dOrCj-Z%*nIBq_4O2(vqT-BLe$#KBe^ZNIaVEJFjP=p!1(iCnp;k zUC^KH`6tV~?MLcl_2d*4tNl6Ga{GFgyqJEr>cqr}&;D+*++{Q0a+Zx_vGB&`U280- z@@B`by5jmUKHP23LaW&zJV+^(hY?OOT;Y4?a`7q;SG=yZw<{ zrQy!0Y3T+MG6Jg>$efkWe!lekg^;_sDLVV!^S3nFUEWgL+_1Cr$J_XzEA6H33M+(5 zqMsQ(3JZ6$X1KGNYu7!M2WqpnTrqzvoO5V$l=`Kxq?dmRFG`$kZZ=V0*>(Gb!cL>6 zN}tZR(k*9vkL3TKloTtpqu-Hb$vw`Xuzz%f_Ssj)*Q2Ecf9_m8k!|25HL4l<3zLRg6DS`-QqcOZS&-)^DFLz+;tI}py+6P z(|tkOcNxhayk0EtZ+K^0_5Gf1B6DT!xzr;8;cmYhS4KQ!Us+PC+#7ZMWMtIMg7Xs_ z>u&1wFWA{>@g_cK^YslMw%4zi{NmbkBcX_JHy@U_UtZlP3jZ)Q_d(ow*1G0T9J6M7 zaQ>by^4+jw*R`cC+pVSxw(l~!#rHy~XPHRWbzMF2=8rpUBC}%`?vhhCtx4$-$`z6l zwakCrB)82)s@AXm5a+TJtgR~L@r(S@D#d*LJbn zUqME>V~nh(lYa($xZUi!uzzA;@#+s%d(GO6zBw&FdUlZ?%W)IMC)cksERmhkE*CD+ z=QRJ#{(=>K*0JdgLd)DNtTQZy7P~QVwes;4wLN%zET3PME463Mtk*4{zU!~7oj)ba zJ-?bkPlRiW*dLF$*{*Nb8LyCQ%(@UWk@FE_fM*-mv7Qi#Yib*_LjF}U#7{CiE-%&iD;slyYUuAS&teWiKToii#qS5qJ#pb#PbK7PuN|-WfA=kA? zy(z^D0*{HVV)Hoj=-r+x3Qx>FWGQaUx>Bws%+>R1`BlNx?d?*m^2(c^o$ze4klZ0W zuXUy`lapYOW@5vq3y#4eJwcOp{=Ol1tyf+9mByTMW)~|c`d~t4ylhn$T z(5Wf2f7s2_=5kl`tiP1*p=>;%NK7bO<(0?6rVxbT3wkC7ZgvOFWTjbJ8lCyK%E4cK z!p_PobC2)leXRJ*Na&ey_m853i+|jG44V9#HdDFz&)(jz8-)|{n4QG`U?{I&)(e#7<*h z#N00SRkb6$AMzE+<);J9j4!T?P@>Np3mIZTj{*y_Zv?2P1gI;$j!9j{3kJ0|1F9xZB>#%YYsh9U}{j>;4WktH1S?DheR^RDK5_J zKmT8$CunQ(U)W-{pxP+IeCHEAoLd_uV;%xUfd!4!OPgC0Dp8tMV;X$rx{Zp1~Pxg06;W#EbsrPeX z>piY{&p$~-N?QK+Ih6nBP25L`C=IteTCAfT>hnq@-4 z)@BYP|CN^Ex;cBkf4TNEYx<8=<0GdA|DW z7M3d)BPK6%DwVvQ=?SiDW%u{kwC%~8lN5V}?ZFkF2ZobZ9^txoX!-jP^;g`>A3W}I zNts^$OmlO3lKq6qx0zmB7TUeb&F1~)cyZFR6CB@9FMG%|zh9coA(8dr&ArpRn?D%u zF87-wp;{DfcxwOQ6UP4*e}D2ZX^L&jm&lf9rYi$yMDB|gWRgiepYZ8l+By5{fA%e% zXIe62{@HqlE5)@F%JlL+B?az@JAYDtcKo0Gch7hC*Wca2+F&QzAv`0YUgv`TY(7h) zRc_~Qa&-z%(OPORHa+IqT;<0*R)7B%*LP>z(ZcT&f+s01p1*Z9H{%=TzaPG?VOaRY z_W#`TM&?Dow%7mO{ZCu??p*x}hI89jaW-1^Cd_GQ`Es1;@1~ctl%3}}8$aE4Wt%P^ z)0g)$jM}Hq$<2DP?aYbx56U&??Tw3;ms*ChU%xT&*ORL!&!1XfmcAGrMy^Xe~w)F3YVR8BeQOcrO&);ZSryZnr_9K4e}o) znu?Yja^-lOe%{5Pb{R8gzu6sej;6%pua9p0wfc@Y2UEsF=C<2Rjtqw1S(_$^G3Xs< zZDNSCe7;GHgK5^<_+`u{`&pYBzDh{O=uCWiqTti%XX5{(mE!6r6ztEr_R-QnK@{8( znW(JHy564SSL$U|ceh`AZ-EwX{&wB2?bZuQw35>HXCS^)elp!Kv!^G};O{2Mv#-Uj z7hT-GKUZ_%+V*4Yd)AyNkiElUES2TjX?m!6+ILmYxgODHSf&Kexq8d+{Fj=H5Vbv< zstjHTYLy8ejm}xS+G1+O1eRjq!m@}y0m%|!&R9XQ8oPvx_rJzZ`BVP?lUR_-t#X$R zo?V?>v4PV97^gqZVwaAQI21RN<*tjNc%q; zw)aUFDN(NuH3p^qE>HIyD7n^hXTgf8aUnHK)17_``!T#WXqHNq;QO*}rD|8^ja43B z)tqAMwVvypdDwsA8RxY%mtL3(um`G_#{96mpQERm`dBFZ^6m*2S*9!Ymg}%8oKs$L z;NqUf)mAH;%-Rn!@9E39s36{cO8;T-A%_%R&aSAJuE+e`c{(ki&?{~Gnu)xjq>zaU$XNeCZ z`M<3_F6F4%#^|iUz`u>xVb<{j>OZS|^}CPpWO|qWTD->7X>nNfLldrv&QA{*?U+-xdzSvPoF|Kwj~nrX7;@iM2-@5E;jmdxs3cp!tbI4! z*nXv6-ae0e&3&fV8w85EDtA>sig5|xzqtHrY2wPqOwVMR3K#k<`t5m6|L&{Zc}{f~ zL}M?c&-mOC=g)Rg@Fw#dpTpJR2c*zwi&16DduWSq`DZ~7WB;g`;abKG0kaXZV3 zr<_yF+AHDmeR9q1^u4D<^Z&8_Z~gVfvVXC49|~Wq-2CG5!HTON zH}|hDtIoM2{8;fZdzIkZZx0IH-i4I^E1l@S^}|y;*~lA<9M@cw;0qNo{={9rN|mF% z(9HNlb=91$LhC18nfhjS3E0LeA+EO(B`4J3wBTVru9BZxbxSS%7BcoDFS<&tae_`+{*v$>iy=Z zSH_JWUp-Ej3$Ls0h)|F-s#_3loABU=SF`2Eti}uXcf4>G()}U!+u#ptS=b5z(*lNd z%F=bS4A@;au5LQLzW$H2;HmhxLlVzJ@R>youeNMvRgr?TD-BI?g}&m#$5NmHvix-3(y&1(`E{efi>Rih=Cr_GuQ?c`+{^b1TFh z{;~4$tBxz#Zk@${E{I(B59Jr>c=ui>GvPsMil&?VHI-GT|MaiEYVc`+nDrFNIqaP$ z7gz^=HS)f~C}1jV;r(Idgg=7y9&HC%xTD2a-gjBR9TEJkWto59b5N!5BXvm~ciWuc z4%Q3HuYuB>)7)Z?7cO^sLgnquufIN-V0G^QxxYH!HXm5?O|jR`UmGn9O(=k5E>t%E8 zTaXiDyg*Kzd3@>-=J`nsUncGNa+~=P%k#9u;j=qy1EQ4<#C^%Qp;32ml1F&+>r2!A z>lZpt2tG4WG455*Pq+TlvfDwM#F-gNd)Vw6ibZFCx>$Yf)CNBLUh}s8te@{0G78S# zd=TT9ojRjI{H!TQnhDGG?X_RmG<}-i_?!8fb_e@wzNWgHK6f7MYF-d;cG+ylJB1h1 z&o1GOEEjkLqSsk>d^w%=s%?$6hm!q-|AK!v%{=0`KWEw3>mPbH`Kqk_m{55-_?gT1 zg6(A`a_e8tdDN&JCBXXZGgJ}dtN&ra&1e9 z-3o_TA(36*mUbVNiWaKR;p*_)CcY_9d`++BuftB?=d1m)75<&I@U_v8vrLbUFb4iz z=lSJTc2QPT_2v9MMLEm7OCDBmtvL6?qCb42+p=}x(^@~BiCmYtQY6jVAwKg^?c5*9 zm+KmKJ-IbwQM!u2zOrfEHLBITyKZc($hi`5>~UA`oSAVElY_hMs(v2(7b32CY_suh z&4pHvAKS#8l$tq>E%tJd@uN)Bz}*{;{n;pa;0;@>^ksnq?`JY(67k3C*Q`0K zvh%&RYm?%60v{=cgVoj(hZYk3sSAqdLbYzRa1a;M%#t_}TQc zM(YZEy{DS$JYCPcpzel9zsQDZOOJ%lvRc4>{g}v~#6-rw^D^DP&t^TwX?OL=M}r0H zPp;heZP^Fw0IPFz?Ob;L4NXqDbLqULdD#B+YyX%2c#~3EH}}(@$G29Szn1%XM9X!q z_w5CL=2_OgIg=K3exjk28sC%W#fpD6%{=!S)Rq19hWY%pm(oX0SLt2QpPjj99`~c^ zXI0|Pv;ImomXq7E!_sKc;&`*@+n=8;jW-jvT+IA4_43L3pNnLQQ||02ah3v)Rrx$F z<_D$xkKkTC%RJ@g*tg4acYNP)>E|71&?upeJm1IDX;JmO=U4pi`F8fzjQX?lt62YM z8o0B4Je{V|ZQ1Wozk6by>v>sZdbQQE@xUGD4n8As0bl;l zN7X9USTjC5;jllas-}YP`Lo7ien(jgae-L=k4M$caH?>AgDmGeA9_ym*)zvIuUEV~ zXwW>*uRieOnpCDUps}?Q$9FpoIIlAnGX{Q*@Th-&c5?m$#xtBP3*H|zh~@t{LsO}C zboEaa&+@VVN&@5U3E*{_zJx&Hd+Io2bu@Bau=+gHr!x&OyGRu#Vk3;-$J BaRUGV literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/editors/creator-coding.qdoc b/doc/qtcreator/src/editors/creator-coding.qdoc index 9a45600f791..6823bf1c8ff 100644 --- a/doc/qtcreator/src/editors/creator-coding.qdoc +++ b/doc/qtcreator/src/editors/creator-coding.qdoc @@ -68,6 +68,10 @@ \list + \li \l{Editing Markdown Files} + + Edit and preview markdown (.md) files. + \li \l{Using Language Servers} The language client offers code completion, highlighting of the diff --git a/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc b/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc index e6f910b22a1..dba4740fd69 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc @@ -4,7 +4,7 @@ /*! \previouspage creator-editor-options-text.html \page creator-editor-fakevim.html - \nextpage creator-language-servers.html + \nextpage creator-markdown-editor.html \title Using FakeVim Mode diff --git a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc index 248569aa78d..348845a7bd2 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! - \previouspage creator-editor-fakevim.html + \previouspage creator-markdown-editor.html \page creator-language-servers.html \nextpage creator-mime-types.html diff --git a/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc b/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc new file mode 100644 index 00000000000..9a3d2444e61 --- /dev/null +++ b/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc @@ -0,0 +1,22 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \previouspage creator-editor-fakevim.html + \page creator-markdown-editor.html + \nextpage creator-language-servers.html + + \title Editing Markdown Files + + Open \l{https://www.markdownguide.org/basic-syntax/}{markdown} (.md) files + or select \uicontrol File > \uicontrol {New File} > \uicontrol {General} > + \uicontrol {Markdown File} to create a new file. + + \image qtcreator-markdown-editor.webp {Markdown file in Preview and Editor views} + + When you edit the file in the editor, you can see the changes in the preview. + + To hide and show the views, select \uicontrol {Show Preview} and + \uicontrol {Show Editor}. To swap the places of the views, select + \uicontrol {Swap Views}. +*/ diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index dc4256e2622..e18f60632b6 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -128,6 +128,7 @@ \li \l{Specifying Text Editor Settings} \li \l{Using FakeVim Mode} \endlist + \li \l{Editing Markdown Files} \li \l{Using Language Servers} \li \l{Editing MIME Types} \li \l{Modeling} From e13c000196be60b5efa933a061a394c07f0b4413 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:03:22 +0200 Subject: [PATCH 0740/1447] CppEditor: Use IOptionPage::setWidgetCreator() for cppquickfix settings Change-Id: I33455f2ea98b1cafbb56ab8267b4d0afca106f33 Reviewed-by: Christian Stenger --- .../cppquickfixprojectsettingswidget.cpp | 2 +- .../cppeditor/cppquickfixsettingspage.cpp | 26 +------------------ .../cppeditor/cppquickfixsettingspage.h | 16 ++---------- .../cppeditor/cppquickfixsettingswidget.cpp | 14 +++++++--- .../cppeditor/cppquickfixsettingswidget.h | 7 +++-- 5 files changed, 20 insertions(+), 45 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp index c0fb8646651..c82985043f2 100644 --- a/src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp +++ b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.cpp @@ -28,7 +28,7 @@ CppQuickFixProjectSettingsWidget::CppQuickFixProjectSettingsWidget(ProjectExplor auto layout = new QVBoxLayout(); gridLayout->addLayout(layout, 2, 0, 1, 2); - m_settingsWidget = new CppQuickFixSettingsWidget(this); + m_settingsWidget = new CppQuickFixSettingsWidget; m_settingsWidget->loadSettings(m_projectSettings->getSettings()); if (QLayout *layout = m_settingsWidget->layout()) diff --git a/src/plugins/cppeditor/cppquickfixsettingspage.cpp b/src/plugins/cppeditor/cppquickfixsettingspage.cpp index 05aa4c586a8..735dbea3b4d 100644 --- a/src/plugins/cppeditor/cppquickfixsettingspage.cpp +++ b/src/plugins/cppeditor/cppquickfixsettingspage.cpp @@ -5,12 +5,8 @@ #include "cppeditorconstants.h" #include "cppeditortr.h" -#include "cppquickfixsettings.h" #include "cppquickfixsettingswidget.h" -#include -#include - namespace CppEditor::Internal { CppQuickFixSettingsPage::CppQuickFixSettingsPage() @@ -18,27 +14,7 @@ CppQuickFixSettingsPage::CppQuickFixSettingsPage() setId(Constants::QUICK_FIX_SETTINGS_ID); setDisplayName(Tr::tr(Constants::QUICK_FIX_SETTINGS_DISPLAY_NAME)); setCategory(Constants::CPP_SETTINGS_CATEGORY); -} - -QWidget *CppQuickFixSettingsPage::widget() -{ - if (!m_widget) { - m_widget = new CppQuickFixSettingsWidget; - m_widget->loadSettings(CppQuickFixSettings::instance()); - } - return m_widget; -} - -void CppQuickFixSettingsPage::apply() -{ - const auto s = CppQuickFixSettings::instance(); - m_widget->saveSettings(s); - s->saveAsGlobalSettings(); -} - -void CppQuickFixSettingsPage::finish() -{ - delete m_widget; + setWidgetCreator([] { return new CppQuickFixSettingsWidget; }); } } // CppEditor::Internal diff --git a/src/plugins/cppeditor/cppquickfixsettingspage.h b/src/plugins/cppeditor/cppquickfixsettingspage.h index 0fea07f91a1..1965aae9569 100644 --- a/src/plugins/cppeditor/cppquickfixsettingspage.h +++ b/src/plugins/cppeditor/cppquickfixsettingspage.h @@ -5,24 +5,12 @@ #include -#include - -namespace CppEditor { -namespace Internal { -class CppQuickFixSettingsWidget; +namespace CppEditor::Internal { class CppQuickFixSettingsPage : public Core::IOptionsPage { public: CppQuickFixSettingsPage(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - QPointer m_widget; }; -} // namespace Internal -} // namespace CppEditor +} // CppEditor::Internal diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.cpp b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp index 689a519ce37..c7aabdf6708 100644 --- a/src/plugins/cppeditor/cppquickfixsettingswidget.cpp +++ b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp @@ -88,9 +88,8 @@ void LineCountSpinBox::updateFields() m_unitLabel->setEnabled(enabled); } -CppQuickFixSettingsWidget::CppQuickFixSettingsWidget(QWidget *parent) - : QWidget(parent) - , m_typeSplitter("\\s*,\\s*") +CppQuickFixSettingsWidget::CppQuickFixSettingsWidget() + : m_typeSplitter("\\s*,\\s*") { m_lines_getterOutsideClass = new LineCountSpinBox; m_lines_getterInCppFile = new LineCountSpinBox; @@ -319,6 +318,8 @@ e.g. name = "m_test_foo_": connect(m_radioButton_addUsingnamespace, &QRadioButton::clicked, then); connect(m_radioButton_generateMissingNamespace, &QRadioButton::clicked, then); connect(m_radioButton_rewriteTypes, &QRadioButton::clicked, then); + + loadSettings(CppQuickFixSettings::instance()); } void CppQuickFixSettingsWidget::loadSettings(CppQuickFixSettings *settings) @@ -426,6 +427,13 @@ void CppQuickFixSettingsWidget::saveSettings(CppQuickFixSettings *settings) } } +void CppQuickFixSettingsWidget::apply() +{ + const auto s = CppQuickFixSettings::instance(); + saveSettings(s); + s->saveAsGlobalSettings(); +} + void CppQuickFixSettingsWidget::currentCustomItemChanged(QListWidgetItem *newItem, QListWidgetItem *oldItem) { diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.h b/src/plugins/cppeditor/cppquickfixsettingswidget.h index f921afbff03..e11d81a9f23 100644 --- a/src/plugins/cppeditor/cppquickfixsettingswidget.h +++ b/src/plugins/cppeditor/cppquickfixsettingswidget.h @@ -3,6 +3,8 @@ #pragma once +#include + #include #include #include @@ -23,7 +25,7 @@ namespace CppEditor::Internal { class LineCountSpinBox; -class CppQuickFixSettingsWidget : public QWidget +class CppQuickFixSettingsWidget : public Core::IOptionsPageWidget { Q_OBJECT @@ -36,7 +38,7 @@ class CppQuickFixSettingsWidget : public QWidget }; public: - explicit CppQuickFixSettingsWidget(QWidget *parent = nullptr); + CppQuickFixSettingsWidget(); void loadSettings(CppQuickFixSettings *settings); void saveSettings(CppQuickFixSettings *settings); @@ -45,6 +47,7 @@ signals: void settingsChanged(); private: + void apply() final; void currentCustomItemChanged(QListWidgetItem *newItem, QListWidgetItem *oldItem); bool m_isLoadingSettings = false; From 19918129bfe8839f1f54b26f546fc92cfeca729e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 21 Apr 2023 16:17:51 +0200 Subject: [PATCH 0741/1447] ILocatorFilter: Introduce LocatorFilterCache It's going to be used as a BaseFileFilter replacement. Add docs for it. Change-Id: I20a52d948373238b07db6cbe1bbadf8c648ae3bf Reviewed-by: Eike Ziller --- .../coreplugin/locator/ilocatorfilter.cpp | 406 +++++++++++++++++- .../coreplugin/locator/ilocatorfilter.h | 39 +- 2 files changed, 437 insertions(+), 8 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 7a6e761b2a5..4e427901385 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -7,13 +7,12 @@ #include +#include #include #include -#include #include #include -#include #include #include #include @@ -110,7 +109,7 @@ class ResultsDeduplicator LocatorFilterEntries entries() const { return m_data; } private: LocatorFilterEntries m_data; - std::unordered_set m_cache; + std::unordered_set m_cache; }; public: @@ -610,7 +609,7 @@ void ILocatorFilter::prepareSearch(const QString &entry) /*! Sets the refresh recipe for refreshing cached data. */ -void ILocatorFilter::setRefreshRecipe(const std::optional &recipe) +void ILocatorFilter::setRefreshRecipe(const std::optional &recipe) { m_refreshRecipe = recipe; } @@ -619,7 +618,7 @@ void ILocatorFilter::setRefreshRecipe(const std::optional ILocatorFilter::refreshRecipe() const +std::optional ILocatorFilter::refreshRecipe() const { return m_refreshRecipe; } @@ -1159,6 +1158,403 @@ bool ILocatorFilter::isOldSetting(const QByteArray &state) expression. */ +std::atomic_int s_executeId = 0; + + +class LocatorFileCachePrivate +{ +public: + bool isValid() const { return bool(m_generator); } + void invalidate(); + bool ensureValidated(); + void bumpExecutionId() { m_executionId = s_executeId.fetch_add(1) + 1; } + void update(const LocatorFileCachePrivate &newCache); + void setGeneratorProvider(const LocatorFileCache::GeneratorProvider &provider) + { m_provider = provider; } + void setGenerator(const LocatorFileCache::FilePathsGenerator &generator); + LocatorFilterEntries generate(const QFuture &future, const QString &input); + + // Is persistent, does not reset on invalidate + LocatorFileCache::GeneratorProvider m_provider; + LocatorFileCache::FilePathsGenerator m_generator; + int m_executionId = 0; + + std::optional m_filePaths; + + QString m_lastInput; + std::optional m_cache; +}; + +// Clears all but provider +void LocatorFileCachePrivate::invalidate() +{ + LocatorFileCachePrivate that; + that.m_provider = m_provider; + *this = that; +} + +/*! + \internal + + Returns true if the cache is valid. Otherwise, tries to validate the cache and returns whether + the validation succeeded. + + When the cache is valid, it does nothing and returns true. + Otherwise, when the GeneratorProvider is not set, it does nothing and returns false. + Otherwise, the GeneratorProvider is used for recreating the FilePathsGenerator. + If the recreated FilePathsGenerator is not empty, it return true. + Otherwise, it returns false; +*/ +bool LocatorFileCachePrivate::ensureValidated() +{ + if (isValid()) + return true; + + if (!m_provider) + return false; + + invalidate(); + m_generator = m_provider(); + return isValid(); +} + +void LocatorFileCachePrivate::update(const LocatorFileCachePrivate &newCache) +{ + if (m_executionId != newCache.m_executionId) + return; // The mismatching executionId was detected, ignoring the update... + auto provider = m_provider; + *this = newCache; + m_provider = provider; +} + +void LocatorFileCachePrivate::setGenerator(const LocatorFileCache::FilePathsGenerator &generator) +{ + invalidate(); + m_generator = generator; +} + +static bool containsPathSeparator(const QString &candidate) +{ + return candidate.contains('/') || candidate.contains('*'); +}; + +/*! + \internal + + Uses the generator to update the cache if needed and returns entries for the input. + Uses the cached data when no need for re-generation. Updates the cached accordingly. +*/ +LocatorFilterEntries LocatorFileCachePrivate::generate(const QFuture &future, + const QString &input) +{ + QTC_ASSERT(isValid(), return {}); + + // If search string contains spaces, treat them as wildcard '*' and search in full path + const QString wildcardInput = QDir::fromNativeSeparators(input).replace(' ', '*'); + const Link inputLink = Link::fromString(wildcardInput, true); + const QString newInput = inputLink.targetFilePath.toString(); + const QRegularExpression regExp = ILocatorFilter::createRegExp(newInput); + if (!regExp.isValid()) + return {}; // Don't clear the cache - still remember the cache for the last valid input. + + if (future.isCanceled()) + return {}; + + const bool hasPathSeparator = containsPathSeparator(newInput); + const bool containsLastInput = !m_lastInput.isEmpty() && newInput.contains(m_lastInput); + const bool pathSeparatorAdded = !containsPathSeparator(m_lastInput) && hasPathSeparator; + const bool searchInCache = m_filePaths && m_cache && containsLastInput && !pathSeparatorAdded; + + if (!searchInCache && !m_filePaths) { + const FilePaths newPaths = m_generator(future); + if (future.isCanceled()) // Ensure we got not canceled results from generator. + return {}; + m_filePaths = newPaths; + } + + const FilePaths &sourcePaths = searchInCache ? *m_cache : *m_filePaths; + LocatorFileCache::MatchedEntries entries = {}; + const FilePaths newCache = LocatorFileCache::processFilePaths( + future, sourcePaths, hasPathSeparator, regExp, inputLink, &entries); + for (auto &entry : entries) { + if (future.isCanceled()) + return {}; + + if (entry.size() < 1000) + Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); + } + + if (future.isCanceled()) + return {}; + + m_lastInput = newInput; + m_cache = newCache; + return std::accumulate(std::begin(entries), std::end(entries), LocatorFilterEntries()); +} + +/*! + \class Core::LocatorFileCache + + \brief The LocatorFileCache class encapsulates all the responsibilities needed for + implementing a cache for file filters. + + LocatorFileCache serves as a replacement for the old BaseFileFilter interface. +*/ + +/*! + \fn LocatorFileCache + + Constructs an invalid cache. + + The cache is considered to be in an invalid state after a call to invalidate(), + of after a call to setFilePathsGenerator() when passed functions was empty. + + It it possible to setup the automatic validator for the cache through the + setGeneratorProvider(). + + \sa invalidate, setGeneratorProvider, setFilePathsGenerator, setFilePaths +*/ + +LocatorFileCache::LocatorFileCache() + : d(new LocatorFileCachePrivate) {} + +/*! + Invalidates the cache. + + In order to validate it, use either setFilePathsGenerator() or setFilePaths(). + The cache may be automatically validated if the GeneratorProvider was set + through the setGeneratorProvider(). + + \note This function invalidates the cache permanently, clearing all the cached data, + and removing the stored generator. The stored generator provider is preserved. +*/ +void LocatorFileCache::invalidate() +{ + d->invalidate(); +} + +/*! + Sets the file path generator provider. + + The \a provider serves for an automatic validation of the invalid cache by recreating + the FilePathsGenerator. The automatic validation happens when the LocatorMatcherTask returned + by matcher() is being started, and the cache is not valid at that moment. In this case + the stored \a provider is being called. + + The passed \a provider function is always called from the main thread. If needed, it is + called prior to starting an asynchronous task that collects the locator filter results. + + When this function is called, the cache isn't invalidated. + Whenever cache's invalidation happens, e.g. when invalidate(), setFilePathsGenerator() or + setFilePaths() is called, the stored GeneratorProvider is being preserved. + In order to clear the stored GeneratorProvider, call this method with an empty + function {}. +*/ +void LocatorFileCache::setGeneratorProvider(const GeneratorProvider &provider) +{ + d->setGeneratorProvider(provider); +} + +/*! + Sets the file path generator. + + The \a generator serves for returning the full input list of file paths when the + associated LocatorMatherTask is being run in a separate thread. When the computation of the + full list of file paths takes a considerable amount of time, this computation may + be potentially moved to the separate thread, provided that all the dependent data may be safely + passed to the \a generator function when this function is being set in the main thread. + + The passed \a generator is always called exclusively from the non-main thread when running + LocatorMatcherTask returned by matcher(). It is called when the cached data is + empty or when it needs to be regenerated due to a new search which can't reuse + the cache from the previous search. + + Generating a new file path list may be a time consuming task. In order to finish the task early + when being canceled, the \e future argument of the FilePathsGenerator may be used. + The FilePathsGenerator returns the full list of file paths used for file filter's processing. + + Whenever it is possible to postpone the creation of a file path list so that it may be done + safely later from the non-main thread, based on some other reentrant/thread-safe data, + this method should be used. The other dependent data should be passed by lambda capture. + The body of the passed \a generator should take extra care for ensuring that the passed + other data via lambda captures are reentrant and the lambda body is thread safe. + See the example usage of the generator inside CppIncludesFilter implementation. + + Otherwise, when postponing the creation of file paths list isn't safe, use setFilePaths() + with ready made list, prepared in main thread. + + \note This function invalidates the cache, clearing all the cached data, + and if the passed generator is non-empty, the cache is set to a valid state. + The stored generator provider is preserved. + + \sa setGeneratorProvider, setFilePaths +*/ +void LocatorFileCache::setFilePathsGenerator(const FilePathsGenerator &generator) +{ + d->setGenerator(generator); +} + +/*! + Wraps the passed \a filePaths into a trivial FilePathsGenerator and sets it + as a cache's generator. + + \note This function invalidates the cache temporarily, clearing all the cached data, + and sets it to a valid state with the new generator for the passed \a filePaths. + + \sa setGenerator +*/ +void LocatorFileCache::setFilePaths(const FilePaths &filePaths) +{ + setFilePathsGenerator(filePathsGenerator(filePaths)); +} + +/*! + Adapts the \a filePaths list into a LocatorFileCacheGenerator. + Useful when implementing GeneratorProvider in case a creation of file paths + can't be invoked from the non-main thread. +*/ +LocatorFileCache::FilePathsGenerator LocatorFileCache::filePathsGenerator( + const FilePaths &filePaths) +{ + return [filePaths](const QFuture &) { return filePaths; }; +} + +static ILocatorFilter::MatchLevel matchLevelFor(const QRegularExpressionMatch &match, + const QString &matchText) +{ + const int consecutivePos = match.capturedStart(1); + if (consecutivePos == 0) + return ILocatorFilter::MatchLevel::Best; + if (consecutivePos > 0) { + const QChar prevChar = matchText.at(consecutivePos - 1); + if (prevChar == '_' || prevChar == '.') + return ILocatorFilter::MatchLevel::Better; + } + if (match.capturedStart() == 0) + return ILocatorFilter::MatchLevel::Good; + return ILocatorFilter::MatchLevel::Normal; +} + +/*! + Helper used internally and by SpotlightLocatorFilter. + + To be called from non-main thread. The cancellation is controlled by the passed \a future. + This function periodically checks for the cancellation state of the \a future and returns + early when cancellation was detected. + Creates lists of matching LocatorFilterEntries categorized by MatcherType. These lists + are returned through the \a entries argument. + + Returns a list of all matching files. + + This function checks for each file in \a filePaths if it matches the passed \a regExp. + If so, a new entry is created using \a hasPathSeparator and \a inputLink and + it's being added into the \a entries argument and the results list. +*/ +FilePaths LocatorFileCache::processFilePaths(const QFuture &future, + const FilePaths &filePaths, + bool hasPathSeparator, + const QRegularExpression ®Exp, + const Link &inputLink, + LocatorFileCache::MatchedEntries *entries) +{ + FilePaths cache; + for (const FilePath &path : filePaths) { + if (future.isCanceled()) + return {}; + + const QString matchText = hasPathSeparator ? path.toString() : path.fileName(); + const QRegularExpressionMatch match = regExp.match(matchText); + + if (match.hasMatch()) { + LocatorFilterEntry filterEntry; + filterEntry.displayName = path.fileName(); + filterEntry.filePath = path; + filterEntry.extraInfo = path.shortNativePath(); + filterEntry.linkForEditor = Link(path, inputLink.targetLine, inputLink.targetColumn); + filterEntry.highlightInfo = hasPathSeparator + ? ILocatorFilter::highlightInfo(regExp.match(filterEntry.extraInfo), + LocatorFilterEntry::HighlightInfo::ExtraInfo) + : ILocatorFilter::highlightInfo(match); + const ILocatorFilter::MatchLevel matchLevel = matchLevelFor(match, matchText); + (*entries)[int(matchLevel)].append(filterEntry); + cache << path; + } + } + return cache; +} + +static void filter(QPromise &promise, const LocatorStorage &storage, + const LocatorFileCachePrivate &cache) +{ + QTC_ASSERT(cache.isValid(), return); + auto newCache = cache; + const LocatorFilterEntries output = newCache.generate(QFuture(promise.future()), + storage.input()); + if (promise.isCanceled()) + return; + storage.reportOutput(output); + promise.addResult(newCache); +} + +/*! + Returns the locator matcher task for the cache. The task, when successfully finished, + updates this LocatorFileCache instance if needed. + + This method is to be used directly by the FilePaths filters. The FilePaths filter should + keep an instance of a LocatorFileCache internally. Ensure the LocatorFileCache instance + outlives the running matcher, otherwise the cache won't be updated after the task finished. + + When returned LocatorMatcherTask is being run it checks if this cache is valid. + When the cache is invalid, it uses GeneratorProvider to update the + cache's FilePathsGenerator and validates the cache. If that failed, the task + is not started. When the cache is valid, the running task will reuse cached data for + calculating the LocatorMatcherTask's results. + + After a successful run of the task, this cache is updated according to the last search. + When this cache started a new search in meantime, the cache was invalidated or even deleted, + the update of the cache after a successful run of the task is ignored. +*/ +LocatorMatcherTask LocatorFileCache::matcher() const +{ + using namespace Tasking; + + TreeStorage storage; + std::weak_ptr weak = d; + + const auto onSetup = [storage, weak](AsyncTask &async) { + auto that = weak.lock(); + if (!that) // LocatorMatcher is running after *this LocatorFileCache was destructed. + return TaskAction::StopWithDone; + + if (!that->ensureValidated()) + return TaskAction::StopWithDone; // The cache is invalid and + // no provider is set or it returned empty generator + that->bumpExecutionId(); + + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + async.setConcurrentCallData(&filter, *storage, *that); + return TaskAction::Continue; + }; + const auto onDone = [weak](const AsyncTask &async) { + auto that = weak.lock(); + if (!that) + return; // LocatorMatcherTask finished after *this LocatorFileCache was destructed. + + if (!that->isValid()) + return; // The cache has been invalidated in meantime. + + if (that->m_executionId == 0) + return; // The cache has been invalidated and not started. + + if (!async.isResultAvailable()) + return; // The async task didn't report updated cache. + + that->update(async.result()); + }; + + return {Async(onSetup, onDone), storage}; +} + } // Core #include "ilocatorfilter.moc" diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 7c89b69ee35..377dcd9eac1 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -12,13 +12,14 @@ #include #include -#include -#include #include #include -namespace Utils::Tasking { class TaskItem; } +QT_BEGIN_NAMESPACE +template +class QPromise; +QT_END_NAMESPACE namespace Core { @@ -29,6 +30,7 @@ class LocatorWidget; class ILocatorFilter; class LocatorStoragePrivate; +class LocatorFileCachePrivate; class AcceptResult { @@ -301,4 +303,35 @@ private: bool m_isConfigurable = true; }; +class CORE_EXPORT LocatorFileCache final +{ + Q_DISABLE_COPY_MOVE(LocatorFileCache) + +public: + // Always called from non-main thread. + using FilePathsGenerator = std::function &)>; + // Always called from main thread. + using GeneratorProvider = std::function; + + LocatorFileCache(); + + void invalidate(); + void setFilePathsGenerator(const FilePathsGenerator &generator); + void setFilePaths(const Utils::FilePaths &filePaths); + void setGeneratorProvider(const GeneratorProvider &provider); + + static FilePathsGenerator filePathsGenerator(const Utils::FilePaths &filePaths); + LocatorMatcherTask matcher() const; + + using MatchedEntries = std::array; + static Utils::FilePaths processFilePaths(const QFuture &future, + const Utils::FilePaths &filePaths, + bool hasPathSeparator, + const QRegularExpression ®Exp, + const Utils::Link &inputLink, + LocatorFileCache::MatchedEntries *entries); +private: + std::shared_ptr d; +}; + } // namespace Core From f44641bec7af750ae4ef2bd681b14a0dffa2233b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 17:36:02 +0200 Subject: [PATCH 0742/1447] Core: Add a test for LocatorFileCache This test corresponds to the old test for BaseFileFilter. Change-Id: If1e775f0f8490943ff41fb6a7ccc4069914fe1f2 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- .../coreplugin/locator/locator_test.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/locator/locator_test.cpp b/src/plugins/coreplugin/locator/locator_test.cpp index a261d15586b..806e5274446 100644 --- a/src/plugins/coreplugin/locator/locator_test.cpp +++ b/src/plugins/coreplugin/locator/locator_test.cpp @@ -16,6 +16,7 @@ #include using namespace Core::Tests; +using namespace Utils; namespace { @@ -24,7 +25,7 @@ QTC_DECLARE_MYTESTDATADIR("../../../tests/locators/") class MyBaseFileFilter : public Core::BaseFileFilter { public: - MyBaseFileFilter(const Utils::FilePaths &theFiles) + MyBaseFileFilter(const FilePaths &theFiles) { setFileIterator(new BaseFileFilter::ListIterator(theFiles)); } @@ -51,7 +52,8 @@ void Core::Internal::CorePlugin::test_basefilefilter() QFETCH(QStringList, testFiles); QFETCH(QList, referenceDataList); - MyBaseFileFilter filter(Utils::FileUtils::toFilePathList(testFiles)); + const FilePaths filePaths = FileUtils::toFilePathList(testFiles); + MyBaseFileFilter filter(filePaths); BasicLocatorFilterTest test(&filter); for (const ReferenceData &reference : std::as_const(referenceDataList)) { @@ -61,12 +63,22 @@ void Core::Internal::CorePlugin::test_basefilefilter() // ResultData::printFilterEntries(results); QCOMPARE(results, reference.results); } + + LocatorFileCache cache; + cache.setFilePaths(filePaths); + const LocatorMatcherTasks tasks = {cache.matcher()}; + for (const ReferenceData &reference : std::as_const(referenceDataList)) { + const LocatorFilterEntries filterEntries = LocatorMatcher::runBlocking( + tasks, reference.searchText); + const ResultDataList results = ResultData::fromFilterEntryList(filterEntries); + QCOMPARE(results, reference.results); + } } void Core::Internal::CorePlugin::test_basefilefilter_data() { auto shortNativePath = [](const QString &file) { - return Utils::FilePath::fromString(file).shortNativePath(); + return FilePath::fromString(file).shortNativePath(); }; QTest::addColumn("testFiles"); From 27f62806ca490081c77ab5a90d6a31ab707909d6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 19 Apr 2023 23:31:19 +0200 Subject: [PATCH 0743/1447] SpotlightLocatorFilter: Reimplement matchers() Change-Id: I6ce29929516dee3b23b67f0cc07dce16ae7ad49d Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../locator/spotlightlocatorfilter.cpp | 86 +++++++++++++++++++ .../locator/spotlightlocatorfilter.h | 2 + 2 files changed, 88 insertions(+) diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index e266e707680..f22cfd5c11e 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -6,7 +6,10 @@ #include "../coreplugintr.h" #include "../messagemanager.h" +#include + #include +#include #include #include #include @@ -233,6 +236,89 @@ SpotlightLocatorFilter::SpotlightLocatorFilter() reset(); } +static void matches(QPromise &promise, const LocatorStorage &storage, + const CommandLine &command) +{ + // If search string contains spaces, treat them as wildcard '*' and search in full path + const QString wildcardInput = QDir::fromNativeSeparators(storage.input()).replace(' ', '*'); + const Link inputLink = Link::fromString(wildcardInput, true); + const QString newInput = inputLink.targetFilePath.toString(); + const QRegularExpression regExp = ILocatorFilter::createRegExp(newInput); + if (!regExp.isValid()) + return; + + const bool hasPathSeparator = newInput.contains('/') || newInput.contains('*'); + LocatorFileCache::MatchedEntries entries = {}; + QEventLoop loop; + QtcProcess process; + process.setCommand(command); + process.setEnvironment(Environment::systemEnvironment()); // TODO: Is it needed? + + QObject::connect(&process, &QtcProcess::readyReadStandardOutput, &process, + [&, entriesPtr = &entries] { + QString output = process.readAllStandardOutput(); + output.replace("\r\n", "\n"); + const QStringList items = output.split('\n'); + const FilePaths filePaths = Utils::transform(items, &FilePath::fromUserInput); + LocatorFileCache::processFilePaths(promise.future(), filePaths, hasPathSeparator, regExp, + inputLink, entriesPtr); + if (promise.isCanceled()) + loop.exit(); + }); + QObject::connect(&process, &QtcProcess::done, &process, [&] { + if (process.result() != ProcessResult::FinishedWithSuccess) { + MessageManager::writeFlashing(Tr::tr("Locator: Error occurred when running \"%1\".") + .arg(command.executable().toUserOutput())); + } + loop.exit(); + }); + QFutureWatcher watcher; + watcher.setFuture(promise.future()); + QObject::connect(&watcher, &QFutureWatcherBase::canceled, &watcher, [&loop] { loop.exit(); }); + if (promise.isCanceled()) + return; + process.start(); + loop.exec(); + + for (auto &entry : entries) { + if (promise.isCanceled()) + return; + if (entry.size() < 1000) + Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); + } + if (promise.isCanceled()) + return; + storage.reportOutput(std::accumulate(std::begin(entries), std::end(entries), + LocatorFilterEntries())); +} + +LocatorMatcherTasks SpotlightLocatorFilter::matchers() +{ + using namespace Tasking; + + TreeStorage storage; + + const auto onSetup = [storage, command = m_command, insensArgs = m_arguments, + sensArgs = m_caseSensitiveArguments](AsyncTask &async) { + const Link link = Link::fromString(storage->input(), true); + const FilePath input = link.targetFilePath; + if (input.isEmpty()) + return TaskAction::StopWithDone; + + // only pass the file name part to allow searches like "somepath/*foo" + const std::unique_ptr expander(createMacroExpander(input.fileName())); + const QString args = caseSensitivity(input.toString()) == Qt::CaseInsensitive + ? insensArgs : sensArgs; + const CommandLine cmd(FilePath::fromString(command), expander->expand(args), + CommandLine::Raw); + async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + async.setConcurrentCallData(matches, *storage, cmd); + return TaskAction::Continue; + }; + + return {{Async(onSetup), storage}}; +} + void SpotlightLocatorFilter::prepareSearch(const QString &entry) { Link link = Utils::Link::fromString(entry, true); diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.h b/src/plugins/coreplugin/locator/spotlightlocatorfilter.h index 174319d4349..80d770dfa15 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.h +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.h @@ -10,6 +10,7 @@ namespace Core { namespace Internal { +// TODO: Don't derive from BaseFileFilter, flatten the hierarchy class SpotlightLocatorFilter : public BaseFileFilter { Q_OBJECT @@ -26,6 +27,7 @@ protected: void restoreState(const QJsonObject &obj) final; private: + LocatorMatcherTasks matchers() final; void reset(); QString m_command; From 9df91853823246bd77c35f15829d03770879a263 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 28 Apr 2023 12:49:51 +0200 Subject: [PATCH 0744/1447] LocatorFileCache: Update the cache in one go Don't leave the partially updated cache when the generate() method was canceled. Before, it was possible that only m_filePaths were updated, without updating m_lastInput and m_cache, what could leave the cache in inconsistent state. Remove unneeded namespace qualifier. Some doc fixes. Amends 19918129bfe8839f1f54b26f546fc92cfeca729e Change-Id: Icef6389f45f0699d851ce412f134c93353728338 Reviewed-by: Eike Ziller --- .../coreplugin/locator/ilocatorfilter.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 4e427901385..b8e393839d3 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -1179,10 +1179,10 @@ public: LocatorFileCache::FilePathsGenerator m_generator; int m_executionId = 0; - std::optional m_filePaths; + std::optional m_filePaths; QString m_lastInput; - std::optional m_cache; + std::optional m_cache; }; // Clears all but provider @@ -1242,7 +1242,7 @@ static bool containsPathSeparator(const QString &candidate) \internal Uses the generator to update the cache if needed and returns entries for the input. - Uses the cached data when no need for re-generation. Updates the cached accordingly. + Uses the cached data when no need for re-generation. Updates the cache accordingly. */ LocatorFilterEntries LocatorFileCachePrivate::generate(const QFuture &future, const QString &input) @@ -1265,14 +1265,14 @@ LocatorFilterEntries LocatorFileCachePrivate::generate(const QFuture &futu const bool pathSeparatorAdded = !containsPathSeparator(m_lastInput) && hasPathSeparator; const bool searchInCache = m_filePaths && m_cache && containsLastInput && !pathSeparatorAdded; - if (!searchInCache && !m_filePaths) { - const FilePaths newPaths = m_generator(future); + std::optional newPaths = m_filePaths; + if (!searchInCache && !newPaths) { + newPaths = m_generator(future); if (future.isCanceled()) // Ensure we got not canceled results from generator. return {}; - m_filePaths = newPaths; } - const FilePaths &sourcePaths = searchInCache ? *m_cache : *m_filePaths; + const FilePaths &sourcePaths = searchInCache ? *m_cache : *newPaths; LocatorFileCache::MatchedEntries entries = {}; const FilePaths newCache = LocatorFileCache::processFilePaths( future, sourcePaths, hasPathSeparator, regExp, inputLink, &entries); @@ -1287,8 +1287,11 @@ LocatorFilterEntries LocatorFileCachePrivate::generate(const QFuture &futu if (future.isCanceled()) return {}; + // Update all the cache data in one go + m_filePaths = newPaths; m_lastInput = newInput; m_cache = newCache; + return std::accumulate(std::begin(entries), std::end(entries), LocatorFilterEntries()); } @@ -1400,6 +1403,7 @@ void LocatorFileCache::setFilePathsGenerator(const FilePathsGenerator &generator \note This function invalidates the cache temporarily, clearing all the cached data, and sets it to a valid state with the new generator for the passed \a filePaths. + The stored generator provider is preserved. \sa setGenerator */ From 341ade96fb65e501623be32f6863749ba858de48 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 22 Apr 2023 12:00:59 +0200 Subject: [PATCH 0745/1447] CppIncludesFilter: Reimplement matchers() Change-Id: Ie449a9560203e50285bd0dab7bed7f8a5495628a Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppincludesfilter.cpp | 52 +++++++++++++++++++++ src/plugins/cppeditor/cppincludesfilter.h | 3 +- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppincludesfilter.cpp b/src/plugins/cppeditor/cppincludesfilter.cpp index c4588bf78c7..7f84b55932c 100644 --- a/src/plugins/cppeditor/cppincludesfilter.cpp +++ b/src/plugins/cppeditor/cppincludesfilter.cpp @@ -97,6 +97,36 @@ void CppIncludesIterator::fetchMore() } } +static FilePaths generateFilePaths(const QFuture &future, + const CPlusPlus::Snapshot &snapshot, + const std::unordered_set &inputFilePaths) +{ + FilePaths results; + std::unordered_set resultsCache; + std::unordered_set queuedPaths = inputFilePaths; + + while (!queuedPaths.empty()) { + if (future.isCanceled()) + return {}; + + const auto iterator = queuedPaths.cbegin(); + const FilePath filePath = *iterator; + queuedPaths.erase(iterator); + const CPlusPlus::Document::Ptr doc = snapshot.document(filePath); + if (!doc) + continue; + const FilePaths includedFiles = doc->includedFiles(); + for (const FilePath &includedFile : includedFiles) { + if (resultsCache.emplace(includedFile).second) { + queuedPaths.emplace(includedFile); + results.append(includedFile); + } + } + } + + return results; +} + CppIncludesFilter::CppIncludesFilter() { setId(Constants::INCLUDES_FILTER_ID); @@ -124,6 +154,27 @@ CppIncludesFilter::CppIncludesFilter() this, &CppIncludesFilter::invalidateCache); connect(DocumentModel::model(), &QAbstractItemModel::modelReset, this, &CppIncludesFilter::invalidateCache); + + const auto generatorProvider = [] { + // This body runs in main thread + std::unordered_set inputFilePaths; + for (Project *project : ProjectManager::projects()) { + const FilePaths allFiles = project->files(Project::SourceFiles); + for (const FilePath &filePath : allFiles) + inputFilePaths.insert(filePath); + } + const QList entries = DocumentModel::entries(); + for (DocumentModel::Entry *entry : entries) { + if (entry) + inputFilePaths.insert(entry->filePath()); + } + const CPlusPlus::Snapshot snapshot = CppModelManager::instance()->snapshot(); + return [snapshot, inputFilePaths](const QFuture &future) { + // This body runs in non-main thread + return generateFilePaths(future, snapshot, inputFilePaths); + }; + }; + m_cache.setGeneratorProvider(generatorProvider); } void CppIncludesFilter::prepareSearch(const QString &entry) @@ -150,6 +201,7 @@ void CppIncludesFilter::prepareSearch(const QString &entry) void CppIncludesFilter::invalidateCache() { + m_cache.invalidate(); m_needsUpdate = true; setFileIterator(nullptr); // clean up } diff --git a/src/plugins/cppeditor/cppincludesfilter.h b/src/plugins/cppeditor/cppincludesfilter.h index 303de152d60..d86b9991858 100644 --- a/src/plugins/cppeditor/cppincludesfilter.h +++ b/src/plugins/cppeditor/cppincludesfilter.h @@ -12,13 +12,14 @@ class CppIncludesFilter : public Core::BaseFileFilter public: CppIncludesFilter(); - // ILocatorFilter interface public: void prepareSearch(const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final { return {m_cache.matcher()}; } void invalidateCache(); + Core::LocatorFileCache m_cache; bool m_needsUpdate = true; }; From 0b3a0dce888678c4e3f5caf631cc4547677b5a69 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 28 Apr 2023 14:41:02 +0200 Subject: [PATCH 0746/1447] TaskTree: Rewrite tests to use AsyncTask Instead of using QtcProcess. In this way the tests may be executed much faster, since there is no need to start qtcreator_processlauncher. This should limit the CI failures caused by timeout when executing these tests. Remove testapp, unneeded now. Change-Id: I80775276c2aaec7c2d463b1ac25010efa942b258 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Marcus Tillmanns --- tests/auto/utils/tasktree/CMakeLists.txt | 9 +- .../utils/tasktree/testapp/CMakeLists.txt | 12 - tests/auto/utils/tasktree/testapp/main.cpp | 63 --- tests/auto/utils/tasktree/testapp/testapp.qbs | 20 - tests/auto/utils/tasktree/tst_tasktree.cpp | 425 +++++++++--------- 5 files changed, 220 insertions(+), 309 deletions(-) delete mode 100644 tests/auto/utils/tasktree/testapp/CMakeLists.txt delete mode 100644 tests/auto/utils/tasktree/testapp/main.cpp delete mode 100644 tests/auto/utils/tasktree/testapp/testapp.qbs diff --git a/tests/auto/utils/tasktree/CMakeLists.txt b/tests/auto/utils/tasktree/CMakeLists.txt index 87c31f18866..2a1ae73630b 100644 --- a/tests/auto/utils/tasktree/CMakeLists.txt +++ b/tests/auto/utils/tasktree/CMakeLists.txt @@ -1,11 +1,4 @@ -add_subdirectory(testapp) - -file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") -file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}") - add_qtc_test(tst_utils_tasktree - DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\"" - "TESTAPP_PATH=\"${CMAKE_CURRENT_BINARY_DIR}/testapp\"" - DEPENDS Utils app_version + DEPENDS Utils SOURCES tst_tasktree.cpp ) diff --git a/tests/auto/utils/tasktree/testapp/CMakeLists.txt b/tests/auto/utils/tasktree/testapp/CMakeLists.txt deleted file mode 100644 index 27a1289137c..00000000000 --- a/tests/auto/utils/tasktree/testapp/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_qtc_executable(testapp - DEPENDS Utils app_version - SOURCES main.cpp - SKIP_INSTALL - INTERNAL_ONLY -) - -set_target_properties(testapp PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" -) diff --git a/tests/auto/utils/tasktree/testapp/main.cpp b/tests/auto/utils/tasktree/testapp/main.cpp deleted file mode 100644 index 59e2d7baa07..00000000000 --- a/tests/auto/utils/tasktree/testapp/main.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include - -#include -#include - -#ifdef Q_OS_WIN -#include -#include -#endif - -const char CRASH_OPTION[] = "-crash"; -const char RETURN_OPTION[] = "-return"; -const char SLEEP_OPTION[] = "-sleep"; - -int main(int argc, char **argv) -{ -#ifdef Q_OS_WIN - // avoid crash reporter dialog - _set_error_mode(_OUT_TO_STDERR); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); -#endif - - if (argc > 1) { - const auto arg = QString::fromLocal8Bit(argv[1]); - if (arg == CRASH_OPTION) { - qFatal("The application has crashed purposefully!"); - return 1; - } - if (arg == RETURN_OPTION) { - if (argc > 2) { - const auto retString = QString::fromLocal8Bit(argv[2]); - bool ok = false; - const int retVal = retString.toInt(&ok); - if (ok) - return retVal; - // not an int return value - return 1; - } - // lacking return value - return 1; - } - if (arg == SLEEP_OPTION) { - if (argc > 2) { - const auto msecsString = QString::fromLocal8Bit(argv[2]); - bool ok = false; - const int msecsVal = msecsString.toInt(&ok); - if (ok) { - QThread::msleep(msecsVal); - return 0; - } - // not an int return value - return 1; - } - // lacking return value - return 1; - } - } - // not recognized option - return 1; -} diff --git a/tests/auto/utils/tasktree/testapp/testapp.qbs b/tests/auto/utils/tasktree/testapp/testapp.qbs deleted file mode 100644 index a106e851463..00000000000 --- a/tests/auto/utils/tasktree/testapp/testapp.qbs +++ /dev/null @@ -1,20 +0,0 @@ -import qbs.FileInfo - -QtApplication { - name: "testapp" - Depends { name: "qtc" } - Depends { name: "Utils" } - Depends { name: "app_version_header" } - - consoleApplication: true - cpp.cxxLanguageVersion: "c++17" - cpp.rpaths: project.buildDirectory + '/' + qtc.ide_library_path - - install: false - destinationDirectory: project.buildDirectory + '/' - + FileInfo.relativePath(project.ide_source_tree, sourceDirectory) - - files: [ - "main.cpp", - ] -} diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index c0bb7839ec3..c38df17f8de 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -1,18 +1,20 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include - -#include -#include -#include -#include +#include #include +#include + +using namespace std::literals::chrono_literals; + using namespace Utils; using namespace Utils::Tasking; +using TestTask = AsyncTask; +using Test = Async; + enum class Handler { Setup, Done, @@ -37,7 +39,9 @@ private: }; int CustomStorage::s_count = 0; -static const char s_processIdProperty[] = "__processId"; +static const char s_taskIdProperty[] = "__taskId"; + +static FutureSynchronizer *s_futureSynchronizer = nullptr; enum class OnStart { Running, NotRunning }; enum class OnDone { Success, Failure }; @@ -59,66 +63,58 @@ private slots: void initTestCase(); void validConstructs(); // compile test - void processTree_data(); - void processTree(); + void testTree_data(); + void testTree(); void storageOperators(); void storageDestructor(); void cleanupTestCase(); - -private: - FilePath m_testAppPath; }; void tst_TaskTree::initTestCase() { - TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" - + Core::Constants::IDE_CASED_ID + "-XXXXXX"); - const QString libExecPath(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - LauncherInterface::setPathToLauncher(libExecPath); - m_testAppPath = FilePath::fromString(QLatin1String(TESTAPP_PATH) - + QLatin1String("/testapp")).withExecutableSuffix(); + s_futureSynchronizer = new FutureSynchronizer; } void tst_TaskTree::cleanupTestCase() { - Singleton::deleteAll(); + delete s_futureSynchronizer; + s_futureSynchronizer = nullptr; } void tst_TaskTree::validConstructs() { - const Group process { + const Group task { parallel, - Process([](QtcProcess &) {}, [](const QtcProcess &) {}), - Process([](QtcProcess &) {}, [](const QtcProcess &) {}), - Process([](QtcProcess &) {}, [](const QtcProcess &) {}) + Test([](TestTask &) {}, [](const TestTask &) {}), + Test([](TestTask &) {}, [](const TestTask &) {}), + Test([](TestTask &) {}, [](const TestTask &) {}) }; const Group group1 { - process + task }; const Group group2 { parallel, Group { parallel, - Process([](QtcProcess &) {}, [](const QtcProcess &) {}), + Test([](TestTask &) {}, [](const TestTask &) {}), Group { parallel, - Process([](QtcProcess &) {}, [](const QtcProcess &) {}), + Test([](TestTask &) {}, [](const TestTask &) {}), Group { parallel, - Process([](QtcProcess &) {}, [](const QtcProcess &) {}) + Test([](TestTask &) {}, [](const TestTask &) {}) } }, Group { parallel, - Process([](QtcProcess &) {}, [](const QtcProcess &) {}), + Test([](TestTask &) {}, [](const TestTask &) {}), OnGroupDone([] {}) } }, - process, + task, OnGroupDone([] {}), OnGroupError([] {}) }; @@ -150,70 +146,75 @@ void tst_TaskTree::validConstructs() #endif } -void tst_TaskTree::processTree_data() +static void runTask(QPromise &promise, bool success, std::chrono::milliseconds sleep) +{ + QDeadlineTimer deadline(sleep); + while (!deadline.hasExpired()) { + QThread::msleep(1); + if (promise.isCanceled()) + return; + } + if (!success) + promise.future().cancel(); +} + +void tst_TaskTree::testTree_data() { QTest::addColumn("testData"); TreeStorage storage; - const auto setupProcessHelper = [storage, testAppPath = m_testAppPath] - (QtcProcess &process, const QStringList &args, int processId) { - process.setCommand(CommandLine(testAppPath, args)); - process.setProperty(s_processIdProperty, processId); - storage->m_log.append({processId, Handler::Setup}); + const auto setupTaskHelper = [storage](TestTask &task, int taskId, bool success = true, + std::chrono::milliseconds sleep = 0ms) { + task.setFutureSynchronizer(s_futureSynchronizer); + task.setConcurrentCallData(runTask, success, sleep); + task.setProperty(s_taskIdProperty, taskId); + storage->m_log.append({taskId, Handler::Setup}); }; - const auto setupProcess = [setupProcessHelper](int processId) { - return [=](QtcProcess &process) { - setupProcessHelper(process, {"-return", "0"}, processId); - }; + const auto setupTask = [setupTaskHelper](int taskId) { + return [=](TestTask &task) { setupTaskHelper(task, taskId); }; }; - const auto setupCrashProcess = [setupProcessHelper](int processId) { - return [=](QtcProcess &process) { - setupProcessHelper(process, {"-crash"}, processId); - }; + const auto setupFailingTask = [setupTaskHelper](int taskId) { + return [=](TestTask &task) { setupTaskHelper(task, taskId, false); }; }; - const auto setupSleepProcess = [setupProcessHelper](int processId, int msecs) { - return [=](QtcProcess &process) { - setupProcessHelper(process, {"-sleep", QString::number(msecs)}, processId); - }; + const auto setupSleepingTask = [setupTaskHelper](int taskId, std::chrono::milliseconds sleep) { + return [=](TestTask &task) { setupTaskHelper(task, taskId, true, sleep); }; }; - const auto setupDynamicProcess = [setupProcessHelper](int processId, TaskAction action) { - return [=](QtcProcess &process) { - setupProcessHelper(process, {"-return", "0"}, processId); + const auto setupDynamicTask = [setupTaskHelper](int taskId, TaskAction action) { + return [=](TestTask &task) { + setupTaskHelper(task, taskId); return action; }; }; - const auto readResult = [storage](const QtcProcess &process) { - const int processId = process.property(s_processIdProperty).toInt(); - storage->m_log.append({processId, Handler::Done}); + const auto logDone = [storage](const TestTask &task) { + storage->m_log.append({task.property(s_taskIdProperty).toInt(), Handler::Done}); }; - const auto readError = [storage](const QtcProcess &process) { - const int processId = process.property(s_processIdProperty).toInt(); - storage->m_log.append({processId, Handler::Error}); + const auto logError = [storage](const TestTask &task) { + storage->m_log.append({task.property(s_taskIdProperty).toInt(), Handler::Error}); }; - const auto groupSetup = [storage](int groupId) { - return [=] { storage->m_log.append({groupId, Handler::GroupSetup}); }; + const auto groupSetup = [storage](int taskId) { + return [=] { storage->m_log.append({taskId, Handler::GroupSetup}); }; }; - const auto groupDone = [storage](int groupId) { - return [=] { storage->m_log.append({groupId, Handler::GroupDone}); }; + const auto groupDone = [storage](int taskId) { + return [=] { storage->m_log.append({taskId, Handler::GroupDone}); }; }; - const auto groupError = [storage](int groupId) { - return [=] { storage->m_log.append({groupId, Handler::GroupError}); }; + const auto groupError = [storage](int taskId) { + return [=] { storage->m_log.append({taskId, Handler::GroupError}); }; }; - const auto setupSync = [storage](int syncId) { - return [=] { storage->m_log.append({syncId, Handler::Sync}); }; + const auto setupSync = [storage](int taskId) { + return [=] { storage->m_log.append({taskId, Handler::Sync}); }; }; - const auto setupSyncWithReturn = [storage](int syncId, bool success) { - return [=] { storage->m_log.append({syncId, Handler::Sync}); return success; }; + const auto setupSyncWithReturn = [storage](int taskId, bool success) { + return [=] { storage->m_log.append({taskId, Handler::Sync}); return success; }; }; const auto constructSimpleSequence = [=](const Workflow &policy) { return Group { Storage(storage), policy, - Process(setupProcess(1), readResult), - Process(setupCrashProcess(2), readResult, readError), - Process(setupProcess(3), readResult), + Test(setupTask(1), logDone), + Test(setupFailingTask(2), logDone, logError), + Test(setupTask(3), logDone), OnGroupDone(groupDone(0)), OnGroupError(groupError(0)) }; @@ -222,13 +223,13 @@ void tst_TaskTree::processTree_data() return Group { Storage(storage), Group { - Process(setupProcess(1), readResult) + Test(setupTask(1), logDone) }, Group { OnGroupSetup([=] { return taskAction; }), - Process(setupProcess(2), readResult), - Process(setupProcess(3), readResult), - Process(setupProcess(4), readResult) + Test(setupTask(2), logDone), + Test(setupTask(3), logDone), + Test(setupTask(4), logDone) }, OnGroupDone(groupDone(0)), OnGroupError(groupError(0)) @@ -274,8 +275,8 @@ void tst_TaskTree::processTree_data() { const Group root { Storage(storage), - Process(setupDynamicProcess(1, TaskAction::StopWithDone), readResult, readError), - Process(setupDynamicProcess(2, TaskAction::StopWithDone), readResult, readError) + Test(setupDynamicTask(1, TaskAction::StopWithDone), logDone, logError), + Test(setupDynamicTask(2, TaskAction::StopWithDone), logDone, logError) }; const Log log {{1, Handler::Setup}, {2, Handler::Setup}}; QTest::newRow("DynamicTaskDone") @@ -285,8 +286,8 @@ void tst_TaskTree::processTree_data() { const Group root { Storage(storage), - Process(setupDynamicProcess(1, TaskAction::StopWithError), readResult, readError), - Process(setupDynamicProcess(2, TaskAction::StopWithError), readResult, readError) + Test(setupDynamicTask(1, TaskAction::StopWithError), logDone, logError), + Test(setupDynamicTask(2, TaskAction::StopWithError), logDone, logError) }; const Log log {{1, Handler::Setup}}; QTest::newRow("DynamicTaskError") @@ -296,10 +297,10 @@ void tst_TaskTree::processTree_data() { const Group root { Storage(storage), - Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), - Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), - Process(setupDynamicProcess(3, TaskAction::StopWithError), readResult, readError), - Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) + Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), + Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), + Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError), + Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) }; const Log log { {1, Handler::Setup}, @@ -316,10 +317,10 @@ void tst_TaskTree::processTree_data() const Group root { parallel, Storage(storage), - Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), - Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), - Process(setupDynamicProcess(3, TaskAction::StopWithError), readResult, readError), - Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) + Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), + Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), + Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError), + Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) }; const Log log { {1, Handler::Setup}, @@ -336,12 +337,12 @@ void tst_TaskTree::processTree_data() const Group root { parallel, Storage(storage), - Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), - Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), + Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), + Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), Group { - Process(setupDynamicProcess(3, TaskAction::StopWithError), readResult, readError) + Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError) }, - Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) + Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) }; const Log log { {1, Handler::Setup}, @@ -358,16 +359,16 @@ void tst_TaskTree::processTree_data() const Group root { parallel, Storage(storage), - Process(setupDynamicProcess(1, TaskAction::Continue), readResult, readError), - Process(setupDynamicProcess(2, TaskAction::Continue), readResult, readError), + Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), + Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), Group { OnGroupSetup([storage] { storage->m_log.append({0, Handler::GroupSetup}); return TaskAction::StopWithError; }), - Process(setupDynamicProcess(3, TaskAction::Continue), readResult, readError) + Test(setupDynamicTask(3, TaskAction::Continue), logDone, logError) }, - Process(setupDynamicProcess(4, TaskAction::Continue), readResult, readError) + Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) }; const Log log { {1, Handler::Setup}, @@ -388,7 +389,7 @@ void tst_TaskTree::processTree_data() Group { Group { Group { - Process(setupProcess(5), readResult, readError), + Test(setupTask(5), logDone, logError), OnGroupSetup(groupSetup(5)), OnGroupDone(groupDone(5)) }, @@ -426,17 +427,17 @@ void tst_TaskTree::processTree_data() } { - const auto readResultAnonymous = [=](const QtcProcess &) { + const auto logDoneAnonymously = [=](const TestTask &) { storage->m_log.append({0, Handler::Done}); }; const Group root { Storage(storage), parallel, - Process(setupProcess(1), readResultAnonymous), - Process(setupProcess(2), readResultAnonymous), - Process(setupProcess(3), readResultAnonymous), - Process(setupProcess(4), readResultAnonymous), - Process(setupProcess(5), readResultAnonymous), + Test(setupTask(1), logDoneAnonymously), + Test(setupTask(2), logDoneAnonymously), + Test(setupTask(3), logDoneAnonymously), + Test(setupTask(4), logDoneAnonymously), + Test(setupTask(5), logDoneAnonymously), OnGroupDone(groupDone(0)) }; const Log log { @@ -460,9 +461,9 @@ void tst_TaskTree::processTree_data() auto setupSubTree = [=](TaskTree &taskTree) { const Group nestedRoot { Storage(storage), - Process(setupProcess(2), readResult), - Process(setupProcess(3), readResult), - Process(setupProcess(4), readResult) + Test(setupTask(2), logDone), + Test(setupTask(3), logDone), + Test(setupTask(4), logDone) }; taskTree.setupRoot(nestedRoot); CustomStorage *activeStorage = storage.activeStorage(); @@ -473,27 +474,27 @@ void tst_TaskTree::processTree_data() }; const Group root1 { Storage(storage), - Process(setupProcess(1), readResult), - Process(setupProcess(2), readResult), - Process(setupProcess(3), readResult), - Process(setupProcess(4), readResult), - Process(setupProcess(5), readResult), + Test(setupTask(1), logDone), + Test(setupTask(2), logDone), + Test(setupTask(3), logDone), + Test(setupTask(4), logDone), + Test(setupTask(5), logDone), OnGroupDone(groupDone(0)) }; const Group root2 { Storage(storage), - Group { Process(setupProcess(1), readResult) }, - Group { Process(setupProcess(2), readResult) }, - Group { Process(setupProcess(3), readResult) }, - Group { Process(setupProcess(4), readResult) }, - Group { Process(setupProcess(5), readResult) }, + Group { Test(setupTask(1), logDone) }, + Group { Test(setupTask(2), logDone) }, + Group { Test(setupTask(3), logDone) }, + Group { Test(setupTask(4), logDone) }, + Group { Test(setupTask(5), logDone) }, OnGroupDone(groupDone(0)) }; const Group root3 { Storage(storage), - Process(setupProcess(1), readResult), + Test(setupTask(1), logDone), Tree(setupSubTree), - Process(setupProcess(5), readResult), + Test(setupTask(5), logDone), OnGroupDone(groupDone(0)) }; const Log log { @@ -521,15 +522,15 @@ void tst_TaskTree::processTree_data() const Group root { Storage(storage), Group { - Process(setupProcess(1), readResult), + Test(setupTask(1), logDone), Group { - Process(setupProcess(2), readResult), + Test(setupTask(2), logDone), Group { - Process(setupProcess(3), readResult), + Test(setupTask(3), logDone), Group { - Process(setupProcess(4), readResult), + Test(setupTask(4), logDone), Group { - Process(setupProcess(5), readResult), + Test(setupTask(5), logDone), OnGroupDone(groupDone(5)) }, OnGroupDone(groupDone(4)) @@ -567,11 +568,11 @@ void tst_TaskTree::processTree_data() { const Group root { Storage(storage), - Process(setupProcess(1), readResult), - Process(setupProcess(2), readResult), - Process(setupCrashProcess(3), readResult, readError), - Process(setupProcess(4), readResult), - Process(setupProcess(5), readResult), + Test(setupTask(1), logDone), + Test(setupTask(2), logDone), + Test(setupFailingTask(3), logDone, logError), + Test(setupTask(4), logDone), + Test(setupTask(5), logDone), OnGroupDone(groupDone(0)), OnGroupError(groupError(0)) }; @@ -646,8 +647,8 @@ void tst_TaskTree::processTree_data() const Group root { Storage(storage), optional, - Process(setupCrashProcess(1), readResult, readError), - Process(setupCrashProcess(2), readResult, readError), + Test(setupFailingTask(1), logDone, logError), + Test(setupFailingTask(2), logDone, logError), OnGroupDone(groupDone(0)), OnGroupError(groupError(0)) }; @@ -707,19 +708,19 @@ void tst_TaskTree::processTree_data() Storage(storage), Group { OnGroupSetup(groupSetup(1)), - Process(setupProcess(1)) + Test(setupTask(1)) }, Group { OnGroupSetup(groupSetup(2)), - Process(setupProcess(2)) + Test(setupTask(2)) }, Group { OnGroupSetup(groupSetup(3)), - Process(setupProcess(3)) + Test(setupTask(3)) }, Group { OnGroupSetup(groupSetup(4)), - Process(setupProcess(4)) + Test(setupTask(4)) } }; const Log log { @@ -742,23 +743,23 @@ void tst_TaskTree::processTree_data() Storage(storage), Group { OnGroupSetup(groupSetup(1)), - Process(setupProcess(1)) + Test(setupTask(1)) }, Group { OnGroupSetup(groupSetup(2)), - Process(setupProcess(2)) + Test(setupTask(2)) }, Group { OnGroupSetup(groupSetup(3)), - Process(setupDynamicProcess(3, TaskAction::StopWithDone)) + Test(setupDynamicTask(3, TaskAction::StopWithDone)) }, Group { OnGroupSetup(groupSetup(4)), - Process(setupProcess(4)) + Test(setupTask(4)) }, Group { OnGroupSetup(groupSetup(5)), - Process(setupProcess(5)) + Test(setupTask(5)) } }; const Log log { @@ -783,63 +784,63 @@ void tst_TaskTree::processTree_data() Storage(storage), Group { OnGroupSetup(groupSetup(1)), - Process(setupProcess(1)) + Test(setupTask(1)) }, Group { OnGroupSetup(groupSetup(2)), - Process(setupProcess(2)) + Test(setupTask(2)) }, Group { OnGroupSetup(groupSetup(3)), - Process(setupDynamicProcess(3, TaskAction::StopWithError)) + Test(setupDynamicTask(3, TaskAction::StopWithError)) }, Group { OnGroupSetup(groupSetup(4)), - Process(setupProcess(4)) + Test(setupTask(4)) }, Group { OnGroupSetup(groupSetup(5)), - Process(setupProcess(5)) + Test(setupTask(5)) } }; - // Inside this test the process 2 should finish first, then synchonously: - // - process 3 should exit setup with error - // - process 1 should be stopped as a consequence of error inside the group - // - processes 4 and 5 should be skipped + // Inside this test the task 2 should finish first, then synchonously: + // - task 3 should exit setup with error + // - task 1 should be stopped as a consequence of error inside the group + // - tasks 4 and 5 should be skipped const Group root2 { ParallelLimit(2), Storage(storage), Group { OnGroupSetup(groupSetup(1)), - Process(setupSleepProcess(1, 100)) + Test(setupSleepingTask(1, 10ms)) }, Group { OnGroupSetup(groupSetup(2)), - Process(setupProcess(2)) + Test(setupTask(2)) }, Group { OnGroupSetup(groupSetup(3)), - Process(setupDynamicProcess(3, TaskAction::StopWithError)) + Test(setupDynamicTask(3, TaskAction::StopWithError)) }, Group { OnGroupSetup(groupSetup(4)), - Process(setupProcess(4)) + Test(setupTask(4)) }, Group { OnGroupSetup(groupSetup(5)), - Process(setupProcess(5)) + Test(setupTask(5)) } }; - // This test ensures process 1 doesn't invoke its done handler, - // being ready while sleeping in process 2 done handler. - // Inside this test the process 2 should finish first, then synchonously: - // - process 3 should exit setup with error - // - process 1 should be stopped as a consequence of error inside the group - // - process 4 should be skipped + // This test ensures that the task 1 doesn't invoke its done handler, + // being ready while sleeping in the task's 2 done handler. + // Inside this test the task 2 should finish first, then synchonously: + // - task 3 should exit setup with error + // - task 1 should be stopped as a consequence of error inside the group + // - task 4 should be skipped // - the first child group of root should finish with error - // - process 5 should be started (because of root's continueOnError policy) + // - task 5 should be started (because of root's continueOnError policy) const Group root3 { continueOnError, Storage(storage), @@ -847,24 +848,24 @@ void tst_TaskTree::processTree_data() ParallelLimit(2), Group { OnGroupSetup(groupSetup(1)), - Process(setupSleepProcess(1, 100)) + Test(setupSleepingTask(1, 20ms)) }, Group { OnGroupSetup(groupSetup(2)), - Process(setupProcess(2), [](const QtcProcess &) { QThread::msleep(200); }) + Test(setupTask(2), [](const TestTask &) { QThread::msleep(10); }) }, Group { OnGroupSetup(groupSetup(3)), - Process(setupDynamicProcess(3, TaskAction::StopWithError)) + Test(setupDynamicTask(3, TaskAction::StopWithError)) }, Group { OnGroupSetup(groupSetup(4)), - Process(setupProcess(4)) + Test(setupTask(4)) } }, Group { OnGroupSetup(groupSetup(5)), - Process(setupProcess(5)) + Test(setupTask(5)) } }; const Log shortLog { @@ -893,7 +894,7 @@ void tst_TaskTree::processTree_data() OnGroupSetup(groupSetup(1)), Group { parallel, - Process(setupProcess(1)) + Test(setupTask(1)) } }, Group { @@ -901,7 +902,7 @@ void tst_TaskTree::processTree_data() OnGroupSetup(groupSetup(2)), Group { parallel, - Process(setupProcess(2)) + Test(setupTask(2)) } }, Group { @@ -909,7 +910,7 @@ void tst_TaskTree::processTree_data() OnGroupSetup(groupSetup(3)), Group { parallel, - Process(setupProcess(3)) + Test(setupTask(3)) } }, Group { @@ -917,7 +918,7 @@ void tst_TaskTree::processTree_data() OnGroupSetup(groupSetup(4)), Group { parallel, - Process(setupProcess(4)) + Test(setupTask(4)) } } }; @@ -942,27 +943,27 @@ void tst_TaskTree::processTree_data() Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(1)), - Group { Process(setupProcess(1)) } + Group { Test(setupTask(1)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(2)), - Group { Process(setupProcess(2)) } + Group { Test(setupTask(2)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(3)), - Group { Process(setupDynamicProcess(3, TaskAction::StopWithDone)) } + Group { Test(setupDynamicTask(3, TaskAction::StopWithDone)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(4)), - Group { Process(setupProcess(4)) } + Group { Test(setupTask(4)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(5)), - Group { Process(setupProcess(5)) } + Group { Test(setupTask(5)) } } }; const Log log { @@ -988,27 +989,27 @@ void tst_TaskTree::processTree_data() Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(1)), - Group { Process(setupProcess(1)) } + Group { Test(setupTask(1)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(2)), - Group { Process(setupProcess(2)) } + Group { Test(setupTask(2)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(3)), - Group { Process(setupDynamicProcess(3, TaskAction::StopWithError)) } + Group { Test(setupDynamicTask(3, TaskAction::StopWithError)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(4)), - Group { Process(setupProcess(4)) } + Group { Test(setupTask(4)) } }, Group { Storage(TreeStorage()), OnGroupSetup(groupSetup(5)), - Group { Process(setupProcess(5)) } + Group { Test(setupTask(5)) } } }; const Log log { @@ -1107,9 +1108,9 @@ void tst_TaskTree::processTree_data() const Group root { Storage(storage), Sync(setupSync(1)), - Process(setupProcess(2)), + Test(setupTask(2)), Sync(setupSync(3)), - Process(setupProcess(4)), + Test(setupTask(4)), Sync(setupSync(5)), OnGroupDone(groupDone(0)) }; @@ -1129,9 +1130,9 @@ void tst_TaskTree::processTree_data() const Group root { Storage(storage), Sync(setupSync(1)), - Process(setupProcess(2)), + Test(setupTask(2)), Sync(setupSyncWithReturn(3, false)), - Process(setupProcess(4)), + Test(setupTask(4)), Sync(setupSync(5)), OnGroupError(groupError(0)) }; @@ -1148,31 +1149,41 @@ void tst_TaskTree::processTree_data() { Condition condition; - const auto setupProcessWithCondition - = [storage, condition, setupProcessHelper](int processId) { - return [storage, condition, setupProcessHelper, processId](QtcProcess &process) { - setupProcessHelper(process, {"-return", "0"}, processId); + const auto reportAndSleep = [](QPromise &promise) { + promise.addResult(false); + QThread::msleep(10); + }; + + const auto setupTaskWithCondition = [storage, condition, reportAndSleep](int taskId) { + return [storage, condition, reportAndSleep, taskId](AsyncTask &async) { + async.setFutureSynchronizer(s_futureSynchronizer); + async.setConcurrentCallData(reportAndSleep); + async.setProperty(s_taskIdProperty, taskId); + storage->m_log.append({taskId, Handler::Setup}); + CustomStorage *currentStorage = storage.activeStorage(); ConditionActivator *currentActivator = condition.activator(); - connect(&process, &QtcProcess::started, [currentStorage, currentActivator, processId] { - currentStorage->m_log.append({processId, Handler::Activator}); + connect(&async, &TestTask::resultReadyAt, + [currentStorage, currentActivator, taskId](int index) { + Q_UNUSED(index) + currentStorage->m_log.append({taskId, Handler::Activator}); currentActivator->activate(); }); }; }; - // Test that Activator, triggered from inside the process described by - // setupProcessWithCondition, placed BEFORE the group containing the WaitFor element + // Test that Activator, triggered from inside the task described by + // setupTaskWithCondition, placed BEFORE the group containing the WaitFor element // in the tree order, works OK in SEQUENTIAL mode. const Group root1 { Storage(storage), sequential, - Process(setupProcessWithCondition(1)), + Async(setupTaskWithCondition(1)), Group { OnGroupSetup(groupSetup(2)), WaitFor(condition), - Process(setupProcess(2)), - Process(setupProcess(3)) + Test(setupTask(2)), + Test(setupTask(3)) } }; const Log log1 { @@ -1183,18 +1194,18 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup} }; - // Test that Activator, triggered from inside the process described by - // setupProcessWithCondition, placed BEFORE the group containing the WaitFor element + // Test that Activator, triggered from inside the task described by + // setupTaskWithCondition, placed BEFORE the group containing the WaitFor element // in the tree order, works OK in PARALLEL mode. const Group root2 { Storage(storage), parallel, - Process(setupProcessWithCondition(1)), + Async(setupTaskWithCondition(1)), Group { OnGroupSetup(groupSetup(2)), WaitFor(condition), - Process(setupProcess(2)), - Process(setupProcess(3)) + Test(setupTask(2)), + Test(setupTask(3)) } }; const Log log2 { @@ -1205,8 +1216,8 @@ void tst_TaskTree::processTree_data() {3, Handler::Setup} }; - // Test that Activator, triggered from inside the process described by - // setupProcessWithCondition, placed AFTER the group containing the WaitFor element + // Test that Activator, triggered from inside the task described by + // setupTaskWithCondition, placed AFTER the group containing the WaitFor element // in the tree order, works OK in PARALLEL mode. // // Notice: This won't work in SEQUENTIAL mode, since the Activator placed after the @@ -1221,10 +1232,10 @@ void tst_TaskTree::processTree_data() Group { OnGroupSetup(groupSetup(2)), WaitFor(condition), - Process(setupProcess(2)), - Process(setupProcess(3)) + Test(setupTask(2)), + Test(setupTask(3)) }, - Process(setupProcessWithCondition(1)) + Async(setupTaskWithCondition(1)) }; const Log log3 { {2, Handler::GroupSetup}, @@ -1244,7 +1255,7 @@ void tst_TaskTree::processTree_data() } } -void tst_TaskTree::processTree() +void tst_TaskTree::testTree() { QFETCH(TestData, testData); @@ -1324,12 +1335,13 @@ void tst_TaskTree::storageDestructor() QCOMPARE(CustomStorage::instanceCount(), 0); { TreeStorage storage; - const auto setupProcess = [testAppPath = m_testAppPath](QtcProcess &process) { - process.setCommand(CommandLine(testAppPath, {"-sleep", "1000"})); + const auto setupSleepingTask = [](TestTask &task) { + task.setFutureSynchronizer(s_futureSynchronizer); + task.setConcurrentCallData(runTask, true, 1000ms); }; const Group root { Storage(storage), - Process(setupProcess) + Test(setupSleepingTask) }; TaskTree taskTree(root); @@ -1338,6 +1350,7 @@ void tst_TaskTree::storageDestructor() taskTree.onStorageDone(storage, doneHandler); taskTree.start(); QCOMPARE(CustomStorage::instanceCount(), 1); + QThread::msleep(5); // Give the sleeping task a change to start } QCOMPARE(CustomStorage::instanceCount(), 0); QVERIFY(setupCalled); From eeb1a4e1ec554278bb61df85ef83ad0f9f6678d9 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 1 May 2023 10:17:09 +0300 Subject: [PATCH 0747/1447] Terminal: Save settings on apply Amends 3d354290be78e9be5c91478e36c119f55697034a. Change-Id: I467806afc27f1aef474f9058426b4c3119b53e8d Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalsettingspage.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index bac32c279da..d0e7b4bab53 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -434,7 +434,14 @@ public: }); } - void apply() final {} + void apply() final + { + TerminalSettings &settings = TerminalSettings::instance(); + if (settings.isDirty()) { + settings.apply(); + settings.writeSettings(Core::ICore::settings()); + } + } }; // TerminalSettingsPage From 56b0d77c8276c8c3aa122409643deaaddb075bfb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 30 Apr 2023 12:18:00 +0200 Subject: [PATCH 0748/1447] TaskTree: Add an useful warning message It's a common mistake to forget to insert the Storage element into the tree, but reuse it from inside running handlers. This message should help in quick fixing the issue. Change-Id: I771e89b06943667b56188d0655ec3da1b48f8a34 Reviewed-by: Marcus Tillmanns --- src/libs/utils/tasktree.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 8ea51369322..97a4dbae66c 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -33,7 +33,12 @@ TreeStorageBase::StorageData::~StorageData() void *TreeStorageBase::activeStorageVoid() const { - QTC_ASSERT(m_storageData->m_activeStorage, return nullptr); + QTC_ASSERT(m_storageData->m_activeStorage, qWarning( + "The referenced storage is not reachable in the running tree. " + "A nullptr will be returned which might lead to a crash in the calling code. " + "It is possible that no storage was added to the tree, " + "or the storage is not reachable from where it is referenced."); + return nullptr); const auto it = m_storageData->m_storageHash.constFind(m_storageData->m_activeStorage); QTC_ASSERT(it != m_storageData->m_storageHash.constEnd(), return nullptr); return it.value(); From e46a4eba8dbe757903c10fd043bf03142836994a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 29 Apr 2023 19:53:40 +0200 Subject: [PATCH 0749/1447] Utils: Introduce Barrier primitive This primitive is going to replace the TaskTree's built-in mechanism consisting of Wait, Condition and ConditionActivator elements. When combining 2 barriers, one placed in a custom storage, and the other in a tree, it's possible to fully substitute the Wait, Condition and ConditionActivator with the comparable amount of code. However, the Barrier is much more versatile, since it makes it possible to: 1. distribute the decision about the ultimate barrier pass on the whole tree. In order to utilize it, increase the limit of the shared barrier with setLimit() to the expected number of places that participate in the decision about the ultimate barrier pass and use advance() from multiple places in the tree. When the number of calls to advance() reaches the limit(), the shared barrier passes automatically. Whenever some participant failed, so that the shared barrier can not be passed, it may call stopWithResult(false). Whenever some other participant decided that all the needed data are already collected, so that the barrier may pass early, it may call stopWithResult(true), making the remaining calls to advance no-op. 2. wait for the same barrier from multiple places. Before, only one WaitFor was possible for a single Condition. 3. insert multiple Barriers into one Group element. Before, only one WaitFor could be placed in a single Group. Provide ready-made SingleCondition and waitFor() helpers. With the new approach, the following equivalents are provided: - SingleBarrier (substitutes old Condition) - WaitForBarrier() (substitutes old WaitFor) - Barrier (substitutes old ConditionActivator) This change replaces the mechanism introduced in 29f634a8caf69a374edb00df7a19146352a14d6f. This change conforms to the naming scheme proposed in QTCREATORBUG-29102. Task-number: QTCREATORBUG-29102 Change-Id: I48b3e2ee723c3b9fe73a59a25eb7facc72940c3b Reviewed-by: Marcus Tillmanns --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/barrier.cpp | 47 +++++++++++++++++ src/libs/utils/barrier.h | 97 +++++++++++++++++++++++++++++++++++ src/libs/utils/utils.qbs | 2 + 4 files changed, 147 insertions(+) create mode 100644 src/libs/utils/barrier.cpp create mode 100644 src/libs/utils/barrier.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 69fa8769a9d..8660e65b84f 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -13,6 +13,7 @@ add_qtc_library(Utils archive.cpp archive.h aspects.cpp aspects.h asynctask.cpp asynctask.h + barrier.cpp barrier.h basetreeview.cpp basetreeview.h benchmarker.cpp benchmarker.h buildablehelperlibrary.cpp buildablehelperlibrary.h diff --git a/src/libs/utils/barrier.cpp b/src/libs/utils/barrier.cpp new file mode 100644 index 00000000000..76cc351088a --- /dev/null +++ b/src/libs/utils/barrier.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "barrier.h" + +#include "qtcassert.h" + +namespace Utils { + +void Barrier::setLimit(int value) +{ + QTC_ASSERT(!isRunning(), return); + QTC_ASSERT(value > 0, return); + + m_limit = value; +} + +void Barrier::start() +{ + QTC_ASSERT(!isRunning(), return); + m_current = 0; + m_result = {}; +} + +void Barrier::advance() +{ + // Calling advance on finished is OK + QTC_ASSERT(isRunning() || m_result, return); + if (!isRunning()) // no-op + return; + ++m_current; + if (m_current == m_limit) + stopWithResult(true); +} + +void Barrier::stopWithResult(bool success) +{ + // Calling stopWithResult on finished is OK when the same success is passed + QTC_ASSERT(isRunning() || (m_result && *m_result == success), return); + if (!isRunning()) // no-op + return; + m_current = -1; + m_result = success; + emit done(success); +} + +} // namespace Utils diff --git a/src/libs/utils/barrier.h b/src/libs/utils/barrier.h new file mode 100644 index 00000000000..f61b2ef2b85 --- /dev/null +++ b/src/libs/utils/barrier.h @@ -0,0 +1,97 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "utils_global.h" + +#include "tasktree.h" + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT Barrier final : public QObject +{ + Q_OBJECT + +public: + void setLimit(int value); + int limit() const { return m_limit; } + + void start(); + void advance(); // If limit reached, stops with true + void stopWithResult(bool success); // Ignores limit + + bool isRunning() const { return m_current >= 0; } + int current() const { return m_current; } + std::optional result() const { return m_result; } + +signals: + void done(bool success); + +private: + std::optional m_result = {}; + int m_limit = 1; + int m_current = -1; +}; + +class QTCREATOR_UTILS_EXPORT BarrierAdapter : public Tasking::TaskAdapter +{ +public: + BarrierAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); } + void start() final { task()->start(); } +}; + +} // namespace Utils + +QTC_DECLARE_CUSTOM_TASK(BarrierTask, Utils::BarrierAdapter); + +namespace Utils::Tasking { + +template +class SharedBarrier +{ +public: + static_assert(Limit > 0, "SharedBarrier's limit should be 1 or more."); + SharedBarrier() : m_barrier(new Barrier) { + m_barrier->setLimit(Limit); + m_barrier->start(); + } + Barrier *barrier() const { return m_barrier.get(); } + +private: + std::shared_ptr m_barrier; +}; + +template +using MultiBarrier = TreeStorage>; + +// Can't write: "MultiBarrier barrier;". Only "MultiBarrier<> barrier;" would work. +// Can't have one alias with default type in C++17, getting the following error: +// alias template deduction only available with C++20. +using SingleBarrier = MultiBarrier<1>; + +class WaitForBarrier : public BarrierTask +{ +public: + template + WaitForBarrier(const MultiBarrier &sharedBarrier) + : BarrierTask([sharedBarrier](Barrier &barrier) { + SharedBarrier *activeBarrier = sharedBarrier.activeStorage(); + if (!activeBarrier) { + qWarning("The barrier referenced from WaitForBarrier element " + "is not reachable in the running tree. " + "It is possible that no barrier was added to the tree, " + "or the storage is not reachable from where it is referenced. " + "The WaitForBarrier task will finish with error. "); + return TaskAction::StopWithError; + } + Barrier *activeSharedBarrier = activeBarrier->barrier(); + const std::optional result = activeSharedBarrier->result(); + if (result.has_value()) + return result.value() ? TaskAction::StopWithDone : TaskAction::StopWithError; + QObject::connect(activeSharedBarrier, &Barrier::done, &barrier, &Barrier::stopWithResult); + return TaskAction::Continue; + }) {} +}; + +} // namespace Utils::Tasking diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 210a6230318..eb8c2a9f563 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -51,6 +51,8 @@ Project { "aspects.h", "asynctask.cpp", "asynctask.h", + "barrier.cpp", + "barrier.h", "basetreeview.cpp", "basetreeview.h", "benchmarker.cpp", From 9f0919c4a3875d8baffc7b6f2b5f7d2e25e198c3 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 27 Apr 2023 11:03:12 +0200 Subject: [PATCH 0750/1447] FakeVim: Block Suggestions Block suggestions when FakeVim is enabled and the mode is not "Insert" or "Replace". Change-Id: I778eb25d9570b76e42652f9d938a8c580033c462 Reviewed-by: David Schulz --- src/plugins/copilot/copilotclient.cpp | 2 +- src/plugins/fakevim/fakevimhandler.cpp | 10 ++-- src/plugins/fakevim/fakevimhandler.h | 2 +- src/plugins/fakevim/fakevimplugin.cpp | 73 +++++++++++++++++++------- src/plugins/texteditor/texteditor.cpp | 18 +++++++ src/plugins/texteditor/texteditor.h | 5 ++ 6 files changed, 84 insertions(+), 26 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 5ea53b1d7c8..88ce40cd2a8 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -92,7 +92,7 @@ void CopilotClient::openDocument(TextDocument *document) const int cursorPosition = widget->textCursor().position(); if (cursorPosition < position || cursorPosition > position + charsAdded) return; - scheduleRequest(textEditor->editorWidget()); + scheduleRequest(widget); }); } diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 7403f9e454b..05ea400bbba 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -5197,7 +5197,7 @@ void FakeVimHandler::Private::handleReplaceMode(const Input &input) moveDown(); } else if (input.isKey(Key_Insert)) { g.mode = InsertMode; - q->modeChanged(); + q->modeChanged(isInsertMode()); } else if (input.isControl('o')) { enterCommandMode(ReplaceMode); } else { @@ -5395,7 +5395,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) removeText(range); } else if (input.isKey(Key_Insert)) { g.mode = ReplaceMode; - q->modeChanged(); + q->modeChanged(isInsertMode()); } else if (input.isKey(Key_Left)) { moveLeft(); } else if (input.isShift(Key_Left) || input.isControl(Key_Left)) { @@ -8578,7 +8578,7 @@ void FakeVimHandler::Private::enterInsertOrReplaceMode(Mode mode) clearLastInsertion(); } - q->modeChanged(); + q->modeChanged(isInsertMode()); } void FakeVimHandler::Private::enterVisualInsertMode(QChar command) @@ -8655,7 +8655,7 @@ void FakeVimHandler::Private::enterCommandMode(Mode returnToMode) m_positionPastEnd = false; m_anchorPastEnd = false; - q->modeChanged(); + q->modeChanged(isInsertMode()); } void FakeVimHandler::Private::enterExMode(const QString &contents) @@ -8671,7 +8671,7 @@ void FakeVimHandler::Private::enterExMode(const QString &contents) g.subsubmode = NoSubSubMode; unfocus(); - q->modeChanged(); + q->modeChanged(isInsertMode()); } void FakeVimHandler::Private::recordJump(int position) diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index 1d13fe301ad..30ee5599ef8 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -157,7 +157,7 @@ public: Signal completionRequested; Signal tabPreviousRequested; Signal tabNextRequested; - Signal modeChanged; + Signal modeChanged; public: class Private; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 4d3ec87ed6c..e41d83be2c0 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -539,7 +539,22 @@ signals: void delayedQuitAllRequested(bool forced); public: - QHash m_editorToHandler; + struct HandlerAndData + { +#ifdef Q_OS_WIN + // We need to declare a constructor here, otherwise the MSVC 17.5.x compiler fails to parse + // the "{nullptr}" initializer in the definition below. + // This seems to be a compiler bug, + // see: https://developercommunity.visualstudio.com/t/10351118 + HandlerAndData() + : handler(nullptr) + {} +#endif + FakeVimHandler *handler{nullptr}; + TextEditorWidget::SuggestionBlocker suggestionBlocker; + }; + + QHash m_editorToHandler; void setActionChecked(Id id, bool check); @@ -1253,7 +1268,7 @@ void FakeVimPluginPrivate::initialize() void FakeVimPluginPrivate::userActionTriggered(int key) { IEditor *editor = EditorManager::currentEditor(); - FakeVimHandler *handler = m_editorToHandler[editor]; + FakeVimHandler *handler = m_editorToHandler[editor].handler; if (handler) { // If disabled, enable FakeVim mode just for single user command. bool enableFakeVim = !fakeVimSettings()->useFakeVim.value(); @@ -1569,14 +1584,14 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) // the handler might have triggered the deletion of the editor: // make sure that it can return before being deleted itself new DeferredDeleter(widget, handler); - m_editorToHandler[editor] = handler; + m_editorToHandler[editor].handler = handler; handler->extraInformationChanged.connect([this](const QString &text) { EditorManager::splitSideBySide(); QString title = "stdout.txt"; IEditor *iedit = EditorManager::openEditorWithContents(Id(), &title, text.toUtf8()); EditorManager::activateEditor(iedit); - FakeVimHandler *handler = m_editorToHandler.value(iedit, nullptr); + FakeVimHandler *handler = m_editorToHandler.value(iedit, {}).handler; QTC_ASSERT(handler, return); handler->handleCommand("0"); }); @@ -1591,7 +1606,13 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) tew->setExtraSelections(TextEditorWidget::FakeVimSelection, selection); }); - handler->modeChanged.connect([tew]() { + handler->modeChanged.connect([tew, this, editor](bool insertMode) { + HandlerAndData &handlerAndData = m_editorToHandler[editor]; + + // We don't want to show suggestions unless we are in insert mode. + if (insertMode != (handlerAndData.suggestionBlocker == nullptr)) + handlerAndData.suggestionBlocker = insertMode ? nullptr : tew->blockSuggestions(); + if (tew) tew->clearSuggestion(); }); @@ -1840,7 +1861,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) handler->requestJumpToGlobalMark.connect( [this](QChar mark, bool backTickMode, const QString &fileName) { if (IEditor *iedit = EditorManager::openEditor(FilePath::fromString(fileName))) { - if (FakeVimHandler *handler = m_editorToHandler.value(iedit, nullptr)) + if (FakeVimHandler *handler = m_editorToHandler.value(iedit, {}).handler) handler->jumpToLocalMark(mark, backTickMode); } }); @@ -1887,7 +1908,7 @@ void FakeVimPluginPrivate::editorAboutToClose(IEditor *editor) void FakeVimPluginPrivate::currentEditorAboutToChange(IEditor *editor) { - if (FakeVimHandler *handler = m_editorToHandler.value(editor, 0)) + if (FakeVimHandler *handler = m_editorToHandler.value(editor, {}).handler) handler->enterCommandMode(); } @@ -1905,9 +1926,9 @@ void FakeVimPluginPrivate::documentRenamed( void FakeVimPluginPrivate::renameFileNameInEditors(const FilePath &oldPath, const FilePath &newPath) { - for (FakeVimHandler *handler : m_editorToHandler) { - if (handler->currentFileName() == oldPath.toString()) - handler->setCurrentFileName(newPath.toString()); + for (const HandlerAndData &handlerAndData : m_editorToHandler) { + if (handlerAndData.handler->currentFileName() == oldPath.toString()) + handlerAndData.handler->setCurrentFileName(newPath.toString()); } } @@ -1926,16 +1947,19 @@ void FakeVimPluginPrivate::setUseFakeVimInternal(bool on) //ICore *core = ICore::instance(); //core->updateAdditionalContexts(Context(FAKEVIM_CONTEXT), // Context()); - for (FakeVimHandler *handler : m_editorToHandler) - handler->setupWidget(); + for (const HandlerAndData &handlerAndData : m_editorToHandler) + handlerAndData.handler->setupWidget(); } else { //ICore *core = ICore::instance(); //core->updateAdditionalContexts(Context(), // Context(FAKEVIM_CONTEXT)); resetCommandBuffer(); - for (auto it = m_editorToHandler.constBegin(); it != m_editorToHandler.constEnd(); ++it) { - if (auto textDocument = qobject_cast(it.key()->document())) - it.value()->restoreWidget(textDocument->tabSettings().m_tabSize); + for (auto it = m_editorToHandler.begin(); it != m_editorToHandler.end(); ++it) { + if (auto textDocument = qobject_cast(it.key()->document())) { + HandlerAndData &handlerAndData = it.value(); + handlerAndData.handler->restoreWidget(textDocument->tabSettings().m_tabSize); + handlerAndData.suggestionBlocker.reset(); + } } } } @@ -1970,11 +1994,22 @@ void FakeVimPluginPrivate::handleExCommand(FakeVimHandler *handler, bool *handle if (editor) editor->setFocus(); + auto editorFromHandler = [this, handler]() -> Core::IEditor * { + auto itEditor = std::find_if(m_editorToHandler.cbegin(), + m_editorToHandler.cend(), + [handler](const HandlerAndData &handlerAndData) { + return handlerAndData.handler == handler; + }); + if (itEditor != m_editorToHandler.cend()) + return itEditor.key(); + return nullptr; + }; + *handled = true; if ((cmd.matches("w", "write") || cmd.cmd == "wq") && cmd.args.isEmpty()) { // :w[rite] bool saved = false; - IEditor *editor = m_editorToHandler.key(handler); + IEditor *editor = editorFromHandler(); const QString fileName = handler->currentFileName(); if (editor && editor->document()->filePath().toString() == fileName) { triggerAction(Core::Constants::SAVE); @@ -1986,7 +2021,7 @@ void FakeVimPluginPrivate::handleExCommand(FakeVimHandler *handler, bool *handle handler->showMessage(MessageInfo, Tr::tr("\"%1\" %2 %3L, %4C written") .arg(fileName).arg(' ').arg(ba.count('\n')).arg(ba.size())); if (cmd.cmd == "wq") - emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler)); + emit delayedQuitRequested(cmd.hasBang, editor); } } } @@ -2005,7 +2040,7 @@ void FakeVimPluginPrivate::handleExCommand(FakeVimHandler *handler, bool *handle emit delayedQuitAllRequested(cmd.hasBang); } else if (cmd.matches("q", "quit")) { // :q[uit] - emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler)); + emit delayedQuitRequested(cmd.hasBang, editorFromHandler()); } else if (cmd.matches("qa", "qall")) { // :qa[ll] emit delayedQuitAllRequested(cmd.hasBang); @@ -2167,7 +2202,7 @@ void FakeVimPlugin::setupTest(QString *title, FakeVimHandler **handler, QWidget IEditor *iedit = EditorManager::openEditorWithContents(Id(), title); EditorManager::activateEditor(iedit); *edit = iedit->widget(); - *handler = dd->m_editorToHandler.value(iedit, 0); + *handler = dd->m_editorToHandler.value(iedit, {}).handler; (*handler)->setupWidget(); (*handler)->handleCommand("set startofline"); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 4dea4ac2a41..eb4b3129f62 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -657,6 +657,7 @@ public: uint m_optionalActionMask = TextEditorActionHandler::None; bool m_contentsChanged = false; bool m_lastCursorChangeWasInteresting = false; + std::shared_ptr m_suggestionBlocker; QSharedPointer m_document; QList m_documentConnections; @@ -905,6 +906,7 @@ void TextEditorWidgetFind::cancelCurrentSelectAll() TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent) : q(parent) + , m_suggestionBlocker((void *) this, [](void *) {}) , m_overlay(new TextEditorOverlay(q)) , m_snippetOverlay(new SnippetOverlay(q)) , m_searchResultOverlay(new TextEditorOverlay(q)) @@ -1654,6 +1656,10 @@ void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperatio void TextEditorWidgetPrivate::insertSuggestion(std::unique_ptr &&suggestion) { clearCurrentSuggestion(); + + if (m_suggestionBlocker.use_count() > 1) + return; + auto cursor = q->textCursor(); cursor.setPosition(suggestion->position()); m_suggestionBlock = cursor.block(); @@ -6017,6 +6023,18 @@ bool TextEditorWidget::suggestionVisible() const return currentSuggestion(); } +bool TextEditorWidget::suggestionsBlocked() const +{ + return d->m_suggestionBlocker.use_count() > 1; +} + +TextEditorWidget::SuggestionBlocker TextEditorWidget::blockSuggestions() +{ + if (!suggestionsBlocked()) + clearSuggestion(); + return d->m_suggestionBlocker; +} + #ifdef WITH_TESTS void TextEditorWidget::processTooltipRequest(const QTextCursor &c) { diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 56308d796ed..2f2a9f81054 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -475,6 +475,11 @@ public: void clearSuggestion(); TextSuggestion *currentSuggestion() const; bool suggestionVisible() const; + bool suggestionsBlocked() const; + + using SuggestionBlocker = std::shared_ptr; + // Returns an object that blocks suggestions until it is destroyed. + SuggestionBlocker blockSuggestions(); #ifdef WITH_TESTS void processTooltipRequest(const QTextCursor &c); From 8f345bbc35e3d1d7e92fdee25d4f42b1194e9793 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Apr 2023 10:51:14 +0200 Subject: [PATCH 0751/1447] Layouting: Drop compile dependency on BoolAspect Change-Id: I4068048f470db126a2583d6b1b90245205cfd601 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/utils/aspects.cpp | 16 ++++++++++------ src/libs/utils/aspects.h | 10 ++-------- src/libs/utils/layoutbuilder.cpp | 10 ++-------- src/libs/utils/layoutbuilder.h | 6 +----- src/plugins/autotest/ctest/ctestsettings.cpp | 6 ++++-- src/plugins/clangformat/clangformatchecks.cpp | 2 -- .../cppeditor/cppquickfixsettingswidget.cpp | 2 -- src/plugins/macros/savedialog.cpp | 2 -- src/plugins/mercurial/revertdialog.cpp | 2 -- src/plugins/perforce/perforcesettings.cpp | 3 ++- src/plugins/subversion/subversionsettings.cpp | 3 ++- 11 files changed, 23 insertions(+), 39 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index ea4a2f1848a..baf80e3fe7f 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1423,6 +1423,16 @@ void BoolAspect::addToLayout(Layouting::LayoutBuilder &builder) this, &BoolAspect::volatileValueChanged); } +std::function BoolAspect::groupChecker() +{ + return [this](QObject *target) { + auto groupBox = qobject_cast(target); + QTC_ASSERT(groupBox, return); + registerSubWidget(groupBox); + d->m_groupBox = d->m_groupBox; + }; +} + QAction *BoolAspect::action() { if (hasAction()) @@ -1515,12 +1525,6 @@ void BoolAspect::setLabelPlacement(BoolAspect::LabelPlacement labelPlacement) d->m_labelPlacement = labelPlacement; } -void BoolAspect::setHandlesGroup(QGroupBox *box) -{ - registerSubWidget(box); - d->m_groupBox = box; -} - /*! \class Utils::SelectionAspect \inmodule QtCreator diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 81a67eb5d5d..9950fbef61a 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -9,22 +9,16 @@ #include "macroexpander.h" #include "pathchooser.h" -#include - #include #include #include QT_BEGIN_NAMESPACE class QAction; -class QGroupBox; class QSettings; QT_END_NAMESPACE -namespace Layouting { -class LayoutBuilder; -class LayoutItem; -} // Layouting +namespace Layouting { class LayoutBuilder; } namespace Utils { @@ -226,6 +220,7 @@ public: }; void addToLayout(Layouting::LayoutBuilder &builder) override; + std::function groupChecker(); QAction *action() override; @@ -242,7 +237,6 @@ public: void setLabel(const QString &labelText, LabelPlacement labelPlacement = LabelPlacement::InExtraLabel); void setLabelPlacement(LabelPlacement labelPlacement); - void setHandlesGroup(QGroupBox *box); signals: void valueChanged(bool newValue); diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 9308ba96ce4..c47be9778db 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -3,7 +3,6 @@ #include "layoutbuilder.h" -#include "aspects.h" #include "qtcassert.h" #include @@ -471,17 +470,12 @@ TabWidget::TabWidget(QTabWidget *tabWidget, std::initializer_list tabs) // "Properties" -LayoutItem::Setter title(const QString &title, Utils::BoolAspect *checker) +LayoutItem::Setter title(const QString &title) { - return [title, checker](QObject *target) { + return [title](QObject *target) { if (auto groupBox = qobject_cast(target)) { groupBox->setTitle(title); groupBox->setObjectName(title); - if (checker) { - groupBox->setCheckable(true); - groupBox->setChecked(checker->value()); - checker->setHandlesGroup(groupBox); - } } else { QTC_CHECK(false); } diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 06f0ae525d0..0e24d1d2ec4 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -24,8 +24,6 @@ class QTextEdit; class QWidget; QT_END_NAMESPACE -namespace Utils { class BoolAspect; } - namespace Layouting { enum AttachType { @@ -191,9 +189,7 @@ QTCREATOR_UTILS_EXPORT extern HorizontalRule hr; // "Properties" -QTCREATOR_UTILS_EXPORT LayoutItem::Setter title(const QString &title, - Utils::BoolAspect *checker = nullptr); - +QTCREATOR_UTILS_EXPORT LayoutItem::Setter title(const QString &title); QTCREATOR_UTILS_EXPORT LayoutItem::Setter text(const QString &text); QTCREATOR_UTILS_EXPORT LayoutItem::Setter tooltip(const QString &toolTip); QTCREATOR_UTILS_EXPORT LayoutItem::Setter onClicked(const std::function &func, diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index 69ad17d43f2..3fa9fadadee 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -133,11 +133,13 @@ CTestSettingsPage::CTestSettingsPage(CTestSettings *settings, Utils::Id settings Row {s.stopOnFailure}, br, Row {s.outputMode}, br, Group { - title(Tr::tr("Repeat tests"), &s.repeat), + title(Tr::tr("Repeat tests")), + s.repeat.groupChecker(), Row {s.repetitionMode, s.repetitionCount}, }, br, Group { - title(Tr::tr("Run in parallel"), &s.parallel), + title(Tr::tr("Run in parallel")), + s.parallel.groupChecker(), Column { Row {s.jobs}, br, Row {s.testLoad, s.threshold} diff --git a/src/plugins/clangformat/clangformatchecks.cpp b/src/plugins/clangformat/clangformatchecks.cpp index 1ec64e7a379..6027e600d70 100644 --- a/src/plugins/clangformat/clangformatchecks.cpp +++ b/src/plugins/clangformat/clangformatchecks.cpp @@ -15,8 +15,6 @@ #include #include -using namespace Utils; - using namespace ClangFormat; ClangFormatChecks::ClangFormatChecks(QWidget *parent) diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.cpp b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp index c7aabdf6708..ce7b4aba727 100644 --- a/src/plugins/cppeditor/cppquickfixsettingswidget.cpp +++ b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp @@ -20,8 +20,6 @@ #include #include -using namespace Utils; - namespace CppEditor::Internal { class LineCountSpinBox : public QWidget diff --git a/src/plugins/macros/savedialog.cpp b/src/plugins/macros/savedialog.cpp index 3d8f7d6ada4..cb45f96da03 100644 --- a/src/plugins/macros/savedialog.cpp +++ b/src/plugins/macros/savedialog.cpp @@ -12,8 +12,6 @@ #include #include -using namespace Utils; - namespace Macros::Internal { SaveDialog::SaveDialog(QWidget *parent) : diff --git a/src/plugins/mercurial/revertdialog.cpp b/src/plugins/mercurial/revertdialog.cpp index c36eb85fe74..cc140ee0b68 100644 --- a/src/plugins/mercurial/revertdialog.cpp +++ b/src/plugins/mercurial/revertdialog.cpp @@ -11,8 +11,6 @@ #include #include -using namespace Utils; - namespace Mercurial::Internal { RevertDialog::RevertDialog(QWidget *parent) diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp index ac9d0b26b05..2f1e930fb63 100644 --- a/src/plugins/perforce/perforcesettings.cpp +++ b/src/plugins/perforce/perforcesettings.cpp @@ -243,7 +243,8 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) }; Group environment { - title(Tr::tr("Environment Variables"), &s.customEnv), + title(Tr::tr("Environment Variables")), + s.customEnv.groupChecker(), Row { s.p4Port, s.p4Client, s.p4User } }; diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index 36a65eff0c3..d91f8f30c19 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -96,7 +96,8 @@ SubversionSettingsPage::SubversionSettingsPage(SubversionSettings *settings) }, Group { - title(Tr::tr("Authentication"), &s.useAuthentication), + title(Tr::tr("Authentication")), + s.useAuthentication.groupChecker(), Form { s.userName, s.password, From 015d12ccf317443576c286ef87c09ddb01e4d34c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 27 Apr 2023 12:18:07 +0200 Subject: [PATCH 0752/1447] FakeVim: Accept suggestion with Tab Key * Changed signals to callbacks as only one receiver was ever added * Added "tabPressedInInsertMode" callback to allow accepting a suggestion with the Tab Key Fixes: QTCREATORBUG-28830 Change-Id: Ie70ba595b8802b6100fff495164d8e0471b1354c Reviewed-by: hjk --- src/plugins/fakevim/fakevimhandler.cpp | 20 +++--- src/plugins/fakevim/fakevimhandler.h | 85 ++++++++++++++------------ src/plugins/fakevim/fakevimplugin.cpp | 72 +++++++++++----------- tests/manual/fakevim/main.cpp | 15 +++-- 4 files changed, 103 insertions(+), 89 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 05ea400bbba..bd1e035f48a 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -5459,16 +5459,18 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) } else if (input.isKey(Key_PageUp) || input.isControl('b')) { movePageUp(); } else if (input.isKey(Key_Tab)) { - m_buffer->insertState.insertingSpaces = true; - if (s.expandTab.value()) { - const int ts = s.tabStop.value(); - const int col = logicalCursorColumn(); - QString str = QString(ts - col % ts, ' '); - insertText(str); - } else { - insertInInsertMode(input.raw()); + if (q->tabPressedInInsertMode()) { + m_buffer->insertState.insertingSpaces = true; + if (s.expandTab.value()) { + const int ts = s.tabStop.value(); + const int col = logicalCursorColumn(); + QString str = QString(ts - col % ts, ' '); + insertText(str); + } else { + insertInInsertMode(input.raw()); + } + m_buffer->insertState.insertingSpaces = false; } - m_buffer->insertState.insertingSpaces = false; } else if (input.isControl('d')) { // remove one level of indentation from the current line const int shift = s.shiftWidth.value(); diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index 30ee5599ef8..b19e2579092 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -61,23 +61,30 @@ enum MessageLevel MessageShowCmd // partial command }; -template -class Signal +template +class Callback; + +template +class Callback { public: - using Callable = std::function; + static constexpr auto IsVoidReturnType = std::is_same_v; + using Function = std::function; + void set(const Function &callable) { m_callable = callable; } - void connect(const Callable &callable) { m_callables.push_back(callable); } - - template - void operator()(Args ...args) const + R operator()(Params... params) { - for (const Callable &callable : m_callables) - callable(args...); - } + if (!m_callable) + return R(); + + if constexpr (IsVoidReturnType) + m_callable(std::forward(params)...); + else + return m_callable(std::forward(params)...); + } private: - std::vector m_callables; + Function m_callable; }; class FakeVimHandler : public QObject @@ -131,33 +138,35 @@ public: bool eventFilter(QObject *ob, QEvent *ev) override; - Signal commandBufferChanged; - Signal statusDataChanged; - Signal extraInformationChanged; - Signal &selection)> selectionChanged; - Signal highlightMatches; - Signal moveToMatchingParenthesis; - Signal checkForElectricCharacter; - Signal indentRegion; - Signal simpleCompletionRequested; - Signal windowCommandRequested; - Signal findRequested; - Signal findNextRequested; - Signal handleExCommandRequested; - Signal requestDisableBlockSelection; - Signal requestSetBlockSelection; - Signal requestBlockSelection; - Signal requestHasBlockSelection; - Signal foldToggle; - Signal foldAll; - Signal fold; - Signal foldGoTo; - Signal requestJumpToLocalMark; - Signal requestJumpToGlobalMark; - Signal completionRequested; - Signal tabPreviousRequested; - Signal tabNextRequested; - Signal modeChanged; + Callback + commandBufferChanged; + Callback statusDataChanged; + Callback extraInformationChanged; + Callback &selection)> selectionChanged; + Callback highlightMatches; + Callback moveToMatchingParenthesis; + Callback checkForElectricCharacter; + Callback indentRegion; + Callback simpleCompletionRequested; + Callback windowCommandRequested; + Callback findRequested; + Callback findNextRequested; + Callback handleExCommandRequested; + Callback requestDisableBlockSelection; + Callback requestSetBlockSelection; + Callback requestBlockSelection; + Callback requestHasBlockSelection; + Callback foldToggle; + Callback foldAll; + Callback fold; + Callback foldGoTo; + Callback requestJumpToLocalMark; + Callback requestJumpToGlobalMark; + Callback completionRequested; + Callback tabPreviousRequested; + Callback tabNextRequested; + Callback modeChanged; + Callback tabPressedInInsertMode; public: class Private; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index e41d83be2c0..d0c399ac31b 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1586,7 +1586,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) new DeferredDeleter(widget, handler); m_editorToHandler[editor].handler = handler; - handler->extraInformationChanged.connect([this](const QString &text) { + handler->extraInformationChanged.set([this](const QString &text) { EditorManager::splitSideBySide(); QString title = "stdout.txt"; IEditor *iedit = EditorManager::openEditorWithContents(Id(), &title, text.toUtf8()); @@ -1596,17 +1596,27 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) handler->handleCommand("0"); }); - handler->commandBufferChanged - .connect([this, handler](const QString &contents, int cursorPos, int anchorPos, int messageLevel) { - showCommandBuffer(handler, contents, cursorPos, anchorPos, messageLevel); - }); + handler->commandBufferChanged.set( + [this, handler](const QString &contents, int cursorPos, int anchorPos, int messageLevel) { + showCommandBuffer(handler, contents, cursorPos, anchorPos, messageLevel); + }); - handler->selectionChanged.connect([tew](const QList &selection) { + handler->selectionChanged.set([tew](const QList &selection) { if (tew) tew->setExtraSelections(TextEditorWidget::FakeVimSelection, selection); }); - handler->modeChanged.connect([tew, this, editor](bool insertMode) { + handler->tabPressedInInsertMode.set([tew]() { + auto suggestion = tew->currentSuggestion(); + if (suggestion) { + suggestion->apply(); + return false; + } + + return true; + }); + + handler->modeChanged.set([tew, this, editor](bool insertMode) { HandlerAndData &handlerAndData = m_editorToHandler[editor]; // We don't want to show suggestions unless we are in insert mode. @@ -1617,7 +1627,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) tew->clearSuggestion(); }); - handler->highlightMatches.connect([](const QString &needle) { + handler->highlightMatches.set([](const QString &needle) { for (IEditor *editor : EditorManager::visibleEditors()) { QWidget *w = editor->widget(); if (auto find = Aggregation::query(w)) @@ -1625,7 +1635,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->moveToMatchingParenthesis.connect([](bool *moved, bool *forward, QTextCursor *cursor) { + handler->moveToMatchingParenthesis.set([](bool *moved, bool *forward, QTextCursor *cursor) { *moved = false; bool undoFakeEOL = false; @@ -1658,7 +1668,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->indentRegion.connect([tew](int beginBlock, int endBlock, QChar typedChar) { + handler->indentRegion.set([tew](int beginBlock, int endBlock, QChar typedChar) { if (!tew) return; @@ -1691,17 +1701,17 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->checkForElectricCharacter.connect([tew](bool *result, QChar c) { + handler->checkForElectricCharacter.set([tew](bool *result, QChar c) { if (tew) *result = tew->textDocument()->indenter()->isElectricCharacter(c); }); - handler->requestDisableBlockSelection.connect([tew] { + handler->requestDisableBlockSelection.set([tew] { if (tew) tew->setTextCursor(tew->textCursor()); }); - handler->requestSetBlockSelection.connect([tew](const QTextCursor &cursor) { + handler->requestSetBlockSelection.set([tew](const QTextCursor &cursor) { if (tew) { const TabSettings &tabs = tew->textDocument()->tabSettings(); MultiTextCursor mtc; @@ -1725,7 +1735,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->requestBlockSelection.connect([tew](QTextCursor *cursor) { + handler->requestBlockSelection.set([tew](QTextCursor *cursor) { if (tew && cursor) { MultiTextCursor mtc = tew->multiTextCursor(); *cursor = mtc.cursors().first(); @@ -1733,16 +1743,16 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->requestHasBlockSelection.connect([tew](bool *on) { + handler->requestHasBlockSelection.set([tew](bool *on) { if (tew && on) *on = tew->multiTextCursor().hasMultipleCursors(); }); - handler->simpleCompletionRequested.connect([this, handler](const QString &needle, bool forward) { + handler->simpleCompletionRequested.set([this, handler](const QString &needle, bool forward) { runData->wordProvider.setActive(needle, forward, handler); }); - handler->windowCommandRequested.connect([this, handler](const QString &map, int count) { + handler->windowCommandRequested.set([this, handler](const QString &map, int count) { // normalize mapping const QString key = map.toUpper(); @@ -1772,22 +1782,22 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) qDebug() << "UNKNOWN WINDOW COMMAND: " << map; }); - handler->findRequested.connect([](bool reverse) { + handler->findRequested.set([](bool reverse) { Find::setUseFakeVim(true); Find::openFindToolBar(reverse ? Find::FindBackwardDirection : Find::FindForwardDirection); }); - handler->findNextRequested.connect([](bool reverse) { + handler->findNextRequested.set([](bool reverse) { triggerAction(reverse ? Core::Constants::FIND_PREVIOUS : Core::Constants::FIND_NEXT); }); - handler->foldToggle.connect([this, handler](int depth) { + handler->foldToggle.set([this, handler](int depth) { QTextBlock block = handler->textCursor().block(); fold(handler, depth, !TextDocumentLayout::isFolded(block)); }); - handler->foldAll.connect([handler](bool fold) { + handler->foldAll.set([handler](bool fold) { QTextDocument *document = handler->textCursor().document(); auto documentLayout = qobject_cast(document->documentLayout()); QTC_ASSERT(documentLayout, return); @@ -1802,11 +1812,9 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) documentLayout->emitDocumentSizeChanged(); }); - handler->fold.connect([this, handler](int depth, bool dofold) { - fold(handler, depth, dofold); - }); + handler->fold.set([this, handler](int depth, bool dofold) { fold(handler, depth, dofold); }); - handler->foldGoTo.connect([handler](int count, bool current) { + handler->foldGoTo.set([handler](int count, bool current) { QTextCursor tc = handler->textCursor(); QTextBlock block = tc.block(); @@ -1858,7 +1866,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->requestJumpToGlobalMark.connect( + handler->requestJumpToGlobalMark.set( [this](QChar mark, bool backTickMode, const QString &fileName) { if (IEditor *iedit = EditorManager::openEditor(FilePath::fromString(fileName))) { if (FakeVimHandler *handler = m_editorToHandler.value(iedit, {}).handler) @@ -1866,19 +1874,15 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->handleExCommandRequested.connect([this, handler](bool *handled, const ExCommand &cmd) { + handler->handleExCommandRequested.set([this, handler](bool *handled, const ExCommand &cmd) { handleExCommand(handler, handled, cmd); }); - handler->tabNextRequested.connect([] { - triggerAction(Core::Constants::GOTONEXTINHISTORY); - }); + handler->tabNextRequested.set([] { triggerAction(Core::Constants::GOTONEXTINHISTORY); }); - handler->tabPreviousRequested.connect([] { - triggerAction(Core::Constants::GOTOPREVINHISTORY); - }); + handler->tabPreviousRequested.set([] { triggerAction(Core::Constants::GOTOPREVINHISTORY); }); - handler->completionRequested.connect([this, tew] { + handler->completionRequested.set([this, tew] { if (tew) tew->invokeAssist(Completion, &runData->wordProvider); }); diff --git a/tests/manual/fakevim/main.cpp b/tests/manual/fakevim/main.cpp index c733dd63198..288c244e43c 100644 --- a/tests/manual/fakevim/main.cpp +++ b/tests/manual/fakevim/main.cpp @@ -187,12 +187,12 @@ int main(int argc, char *argv[]) // Create FakeVimHandler instance which will emulate Vim behavior in editor widget. FakeVimHandler handler(editor, nullptr); - handler.commandBufferChanged.connect([&](const QString &msg, int cursorPos, int, int) { + handler.commandBufferChanged.set([&](const QString &msg, int cursorPos, int, int) { statusData.setStatusMessage(msg, cursorPos); mainWindow.statusBar()->showMessage(statusData.currentStatusLine()); }); - handler.selectionChanged.connect([&handler](const QList &s) { + handler.selectionChanged.set([&handler](const QList &s) { QWidget *widget = handler.widget(); if (auto ed = qobject_cast(widget)) ed->setExtraSelections(s); @@ -200,21 +200,20 @@ int main(int argc, char *argv[]) ed->setExtraSelections(s); }); - handler.extraInformationChanged.connect([&](const QString &info) { + handler.extraInformationChanged.set([&](const QString &info) { statusData.setStatusInfo(info); mainWindow.statusBar()->showMessage(statusData.currentStatusLine()); }); - handler.statusDataChanged.connect([&](const QString &info) { + handler.statusDataChanged.set([&](const QString &info) { statusData.setStatusInfo(info); mainWindow.statusBar()->showMessage(statusData.currentStatusLine()); }); - handler.highlightMatches.connect([&](const QString &needle) { - highlightMatches(handler.widget(), needle); - }); + handler.highlightMatches.set( + [&](const QString &needle) { highlightMatches(handler.widget(), needle); }); - handler.handleExCommandRequested.connect([](bool *handled, const ExCommand &cmd) { + handler.handleExCommandRequested.set([](bool *handled, const ExCommand &cmd) { if (cmd.matches("q", "quit") || cmd.matches("qa", "qall")) { QApplication::quit(); *handled = true; From 36dad70ab0f3e07043a4b09516ae2de85687f13c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 30 Apr 2023 10:08:12 +0200 Subject: [PATCH 0753/1447] TaskTree: Replace the usages of old WaitFor with new Barrier Adapt the TaskTree tests and the usage in FileStreamer. The FileStreamer may be tested by running the FileSystemAccessTest. Change-Id: I1d8086dd359c458b7bdd3d4d47cf249184b04c65 Reviewed-by: Marcus Tillmanns --- src/libs/utils/filestreamer.cpp | 9 +-- tests/auto/utils/tasktree/tst_tasktree.cpp | 68 ++++++++++++---------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 47cbffd3c27..c47eafaf7a8 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -4,6 +4,7 @@ #include "filestreamer.h" #include "asynctask.h" +#include "barrier.h" #include "qtcprocess.h" #include @@ -321,7 +322,7 @@ static Group sameRemoteDeviceTransferTask(const FilePath &source, const FilePath static Group interDeviceTransferTask(const FilePath &source, const FilePath &destination) { struct TransferStorage { QPointer writer; }; - Condition condition; + SingleBarrier writerReadyBarrier; TreeStorage storage; const auto setupReader = [=](FileStreamReader &reader) { @@ -336,19 +337,19 @@ static Group interDeviceTransferTask(const FilePath &source, const FilePath &des }; const auto setupWriter = [=](FileStreamWriter &writer) { writer.setFilePath(destination); - ConditionActivator *activator = condition.activator(); QObject::connect(&writer, &FileStreamWriter::started, - &writer, [activator] { activator->activate(); }); + writerReadyBarrier->barrier(), &Barrier::advance); QTC_CHECK(storage->writer == nullptr); storage->writer = &writer; }; const Group root { + Storage(writerReadyBarrier), parallel, Storage(storage), Writer(setupWriter), Group { - WaitFor(condition), + WaitForBarrier(writerReadyBarrier), Reader(setupReader, finalizeReader, finalizeReader) } }; diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index c38df17f8de..0533c6fd86f 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include +#include #include @@ -23,7 +24,7 @@ enum class Handler { GroupDone, GroupError, Sync, - Activator, + BarrierAdvance, }; using Log = QList>; @@ -1147,63 +1148,65 @@ void tst_TaskTree::testTree_data() } { - Condition condition; + SingleBarrier barrier; const auto reportAndSleep = [](QPromise &promise) { promise.addResult(false); QThread::msleep(10); }; - const auto setupTaskWithCondition = [storage, condition, reportAndSleep](int taskId) { - return [storage, condition, reportAndSleep, taskId](AsyncTask &async) { + const auto setupTaskWithBarrier = [storage, barrier, reportAndSleep](int taskId) { + return [storage, barrier, reportAndSleep, taskId](AsyncTask &async) { async.setFutureSynchronizer(s_futureSynchronizer); async.setConcurrentCallData(reportAndSleep); async.setProperty(s_taskIdProperty, taskId); storage->m_log.append({taskId, Handler::Setup}); CustomStorage *currentStorage = storage.activeStorage(); - ConditionActivator *currentActivator = condition.activator(); - connect(&async, &TestTask::resultReadyAt, - [currentStorage, currentActivator, taskId](int index) { + Barrier *sharedBarrier = barrier->barrier(); + connect(&async, &TestTask::resultReadyAt, sharedBarrier, + [currentStorage, sharedBarrier, taskId](int index) { Q_UNUSED(index) - currentStorage->m_log.append({taskId, Handler::Activator}); - currentActivator->activate(); + currentStorage->m_log.append({taskId, Handler::BarrierAdvance}); + sharedBarrier->advance(); }); }; }; - // Test that Activator, triggered from inside the task described by - // setupTaskWithCondition, placed BEFORE the group containing the WaitFor element + // Test that barrier advance, triggered from inside the task described by + // setupTaskWithCondition, placed BEFORE the group containing the waitFor() element // in the tree order, works OK in SEQUENTIAL mode. const Group root1 { Storage(storage), + Storage(barrier), sequential, - Async(setupTaskWithCondition(1)), + Async(setupTaskWithBarrier(1)), Group { OnGroupSetup(groupSetup(2)), - WaitFor(condition), + WaitForBarrier(barrier), Test(setupTask(2)), Test(setupTask(3)) } }; const Log log1 { {1, Handler::Setup}, - {1, Handler::Activator}, + {1, Handler::BarrierAdvance}, {2, Handler::GroupSetup}, {2, Handler::Setup}, {3, Handler::Setup} }; - // Test that Activator, triggered from inside the task described by - // setupTaskWithCondition, placed BEFORE the group containing the WaitFor element + // Test that barrier advance, triggered from inside the task described by + // setupTaskWithCondition, placed BEFORE the group containing the waitFor() element // in the tree order, works OK in PARALLEL mode. const Group root2 { Storage(storage), + Storage(barrier), parallel, - Async(setupTaskWithCondition(1)), + Async(setupTaskWithBarrier(1)), Group { OnGroupSetup(groupSetup(2)), - WaitFor(condition), + WaitForBarrier(barrier), Test(setupTask(2)), Test(setupTask(3)) } @@ -1211,47 +1214,48 @@ void tst_TaskTree::testTree_data() const Log log2 { {1, Handler::Setup}, {2, Handler::GroupSetup}, - {1, Handler::Activator}, + {1, Handler::BarrierAdvance}, {2, Handler::Setup}, {3, Handler::Setup} }; - // Test that Activator, triggered from inside the task described by - // setupTaskWithCondition, placed AFTER the group containing the WaitFor element + // Test that barrier advance, triggered from inside the task described by + // setupTaskWithCondition, placed AFTER the group containing the waitFor() element // in the tree order, works OK in PARALLEL mode. // - // Notice: This won't work in SEQUENTIAL mode, since the Activator placed after the + // Notice: This won't work in SEQUENTIAL mode, since the advancing barrier, placed after the // group containing the WaitFor element, has no chance to be started in SEQUENTIAL mode, // as in SEQUENTIAL mode the next task may only be started after the previous one finished. - // In this case, the previous task (Group element) awaits for the Activator's signal to + // In this case, the previous task (Group element) awaits for the barrier's advance to // come from the not yet started next task, causing a deadlock. // The minimal requirement for this scenario to succeed is to set ParallelLimit(2) or more. const Group root3 { Storage(storage), + Storage(barrier), parallel, Group { OnGroupSetup(groupSetup(2)), - WaitFor(condition), + WaitForBarrier(barrier), Test(setupTask(2)), Test(setupTask(3)) }, - Async(setupTaskWithCondition(1)) + Async(setupTaskWithBarrier(1)) }; const Log log3 { {2, Handler::GroupSetup}, {1, Handler::Setup}, - {1, Handler::Activator}, + {1, Handler::BarrierAdvance}, {2, Handler::Setup}, {3, Handler::Setup} }; // Notice the different log order for each scenario. - QTest::newRow("WaitForSequential") - << TestData{storage, root1, log1, 3, OnStart::Running, OnDone::Success}; - QTest::newRow("WaitForParallelActivatorFirst") - << TestData{storage, root2, log2, 3, OnStart::Running, OnDone::Success}; - QTest::newRow("WaitForParallelConditionFirst") - << TestData{storage, root3, log3, 3, OnStart::Running, OnDone::Success}; + QTest::newRow("BarrierSequential") + << TestData{storage, root1, log1, 4, OnStart::Running, OnDone::Success}; + QTest::newRow("BarrierParallelAdvanceFirst") + << TestData{storage, root2, log2, 4, OnStart::Running, OnDone::Success}; + QTest::newRow("BarrierParallelWaitForFirst") + << TestData{storage, root3, log3, 4, OnStart::Running, OnDone::Success}; } } From 68d05b05d9568c224ded23311754bc805455fd9c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 30 Apr 2023 11:25:22 +0200 Subject: [PATCH 0754/1447] TaskTree: Remove the old WaitFor, Condition, ConditionActivator Remove it from internals of TaskTree. It's replaced with the new mechanism consisting of Barrier, implemented outside of TaskTree. The change mostly reverts 29f634a8caf69a374edb00df7a19146352a14d6f. Change-Id: I1f2f4100e7c992389a19c3cc9132c3f2980b9bf8 Reviewed-by: Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/utils/tasktree.cpp | 179 +----------------------------------- src/libs/utils/tasktree.h | 56 ----------- 2 files changed, 1 insertion(+), 234 deletions(-) diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 97a4dbae66c..5e87466c665 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -79,54 +79,6 @@ void TreeStorageBase::activateStorage(int id) const m_storageData->m_activeStorage = id; } -Condition::Condition() - : m_conditionData(new ConditionData()) {} - -Condition::ConditionData::~ConditionData() -{ - QTC_CHECK(m_activatorHash.isEmpty()); - qDeleteAll(m_activatorHash); -} - -ConditionActivator *Condition::activator() const -{ - QTC_ASSERT(m_conditionData->m_activeActivator, return nullptr); - const auto it = m_conditionData->m_activatorHash.constFind(m_conditionData->m_activeActivator); - QTC_ASSERT(it != m_conditionData->m_activatorHash.constEnd(), return nullptr); - return it.value(); -} - -int Condition::createActivator(TaskNode *node) const -{ - QTC_ASSERT(m_conditionData->m_activeActivator == 0, return 0); // TODO: should be allowed? - const int newId = ++m_conditionData->m_activatorCounter; - m_conditionData->m_activatorHash.insert(newId, new ConditionActivator(node)); - return newId; -} - -void Condition::deleteActivator(int id) const -{ - QTC_ASSERT(m_conditionData->m_activeActivator == 0, return); // TODO: should be allowed? - const auto it = m_conditionData->m_activatorHash.constFind(id); - QTC_ASSERT(it != m_conditionData->m_activatorHash.constEnd(), return); - delete it.value(); - m_conditionData->m_activatorHash.erase(it); -} - -// passing 0 deactivates currently active condition -void Condition::activateActivator(int id) const -{ - if (id == 0) { - QTC_ASSERT(m_conditionData->m_activeActivator, return); - m_conditionData->m_activeActivator = 0; - return; - } - QTC_ASSERT(m_conditionData->m_activeActivator == 0, return); - const auto it = m_conditionData->m_activatorHash.find(id); - QTC_ASSERT(it != m_conditionData->m_activatorHash.end(), return); - m_conditionData->m_activeActivator = id; -} - ParallelLimit sequential(1); ParallelLimit parallel(0); Workflow stopOnError(WorkflowPolicy::StopOnError); @@ -180,12 +132,6 @@ void TaskItem::addChildren(const QList &children) if (child.m_groupHandler.m_errorHandler) m_groupHandler.m_errorHandler = child.m_groupHandler.m_errorHandler; break; - case Type::Condition: - QTC_ASSERT(m_type == Type::Group, qWarning("WaitFor may only be a child of a Group, " - "skipping..."); break); - QTC_ASSERT(!m_condition, qWarning("WaitFor redefinition, overriding...")); - m_condition = child.m_condition; - break; case Type::Storage: m_storageList.append(child.m_storageList); break; @@ -213,11 +159,6 @@ public: void emitProgress(); void emitDone(); void emitError(); - bool addCondition(const TaskItem &task, TaskContainer *container); - void createConditionActivators(); - void deleteConditionActivators(); - void activateConditions(); - void deactivateConditions(); QList addStorages(const QList &storages); void callSetupHandler(TreeStorageBase storage, int storageId) { callStorageHandler(storage, storageId, &StorageHandler::m_setupHandler); @@ -246,7 +187,6 @@ public: TaskTree *q = nullptr; Guard m_guard; int m_progressValue = 0; - QHash m_conditions; QSet m_storages; QHash m_storageHandlers; std::unique_ptr m_root = nullptr; // Keep me last in order to destruct first @@ -257,14 +197,11 @@ class TaskContainer public: TaskContainer(TaskTreePrivate *taskTreePrivate, const TaskItem &task, TaskNode *parentNode, TaskContainer *parentContainer) - : m_constData(taskTreePrivate, task, parentNode, parentContainer, this) - , m_conditionData(taskTreePrivate->addCondition(task, this) - ? ConditionData() : std::optional()) {} + : m_constData(taskTreePrivate, task, parentNode, parentContainer, this) {} TaskAction start(); TaskAction continueStart(TaskAction startAction, int nextChild); TaskAction startChildren(int nextChild); TaskAction childDone(bool success); - void activateCondition(); void stop(); void invokeEndHandler(); bool isRunning() const { return m_runtimeData.has_value(); } @@ -286,11 +223,6 @@ public: const int m_taskCount = 0; }; - struct ConditionData { - bool m_activated = false; - int m_conditionId = 0; - }; - struct RuntimeData { RuntimeData(const ConstData &constData); ~RuntimeData(); @@ -308,7 +240,6 @@ public: }; const ConstData m_constData; - std::optional m_conditionData; std::optional m_runtimeData; }; @@ -330,7 +261,6 @@ public: bool isTask() const { return m_taskHandler.m_createHandler && m_taskHandler.m_setupHandler; } int taskCount() const { return isTask() ? 1 : m_container.m_constData.m_taskCount; } TaskContainer *parentContainer() const { return m_container.m_constData.m_parentContainer; } - void activateCondition(); private: const TaskItem::TaskHandler m_taskHandler; @@ -348,7 +278,6 @@ void TaskTreePrivate::start() QTC_ASSERT(m_storages.contains(it.key()), qWarning("The registered storage doesn't " "exist in task tree. Its handlers will never be called.")); } - createConditionActivators(); m_root->start(); } @@ -391,7 +320,6 @@ void TaskTreePrivate::emitProgress() void TaskTreePrivate::emitDone() { - deleteConditionActivators(); QTC_CHECK(m_progressValue == m_root->taskCount()); GuardLocker locker(m_guard); emit q->done(); @@ -399,57 +327,11 @@ void TaskTreePrivate::emitDone() void TaskTreePrivate::emitError() { - deleteConditionActivators(); QTC_CHECK(m_progressValue == m_root->taskCount()); GuardLocker locker(m_guard); emit q->errorOccurred(); } -bool TaskTreePrivate::addCondition(const TaskItem &task, TaskContainer *container) -{ - if (!task.condition()) - return false; - QTC_ASSERT(!m_conditions.contains(*task.condition()), qWarning("Can't add the same condition " - "into one TaskTree twice, skipping..."); return false); - m_conditions.insert(*task.condition(), container); - return true; -} - -void TaskTreePrivate::createConditionActivators() -{ - for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) { - Condition condition = it.key(); - TaskContainer *container = it.value(); - container->m_conditionData->m_conditionId - = condition.createActivator(container->m_constData.m_parentNode); - } -} - -void TaskTreePrivate::deleteConditionActivators() -{ - for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) { - Condition condition = it.key(); - TaskContainer *container = it.value(); - condition.deleteActivator(container->m_conditionData->m_conditionId); - container->m_conditionData = TaskContainer::ConditionData(); - } -} - -void TaskTreePrivate::activateConditions() -{ - for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) { - Condition condition = it.key(); - TaskContainer *container = it.value(); - condition.activateActivator(container->m_conditionData->m_conditionId); - } -} - -void TaskTreePrivate::deactivateConditions() -{ - for (auto it = m_conditions.cbegin(); it != m_conditions.cend(); ++it) - it.key().activateActivator(0); -} - QList TaskTreePrivate::addStorages(const QList &storages) { QList addedStorages; @@ -462,7 +344,6 @@ QList TaskTreePrivate::addStorages(const QList return addedStorages; } -// TODO: Activate/deactivate Conditions class ExecutionContextActivator { public: @@ -477,8 +358,6 @@ private: const TaskContainer::ConstData &constData = container->m_constData; if (constData.m_parentContainer) activateContext(constData.m_parentContainer); - else - constData.m_taskTreePrivate->activateConditions(); for (int i = 0; i < constData.m_storageList.size(); ++i) constData.m_storageList[i].activateStorage(container->m_runtimeData->m_storageIdList.value(i)); } @@ -490,8 +369,6 @@ private: constData.m_storageList[i].activateStorage(0); if (constData.m_parentContainer) deactivateContext(constData.m_parentContainer); - else - constData.m_taskTreePrivate->deactivateConditions(); } TaskContainer *m_container = nullptr; }; @@ -597,8 +474,6 @@ TaskAction TaskContainer::start() m_constData.m_taskTreePrivate->advanceProgress(m_constData.m_taskCount); } if (startAction == TaskAction::Continue) { - if (m_conditionData && !m_conditionData->m_activated) // Group has condition and it wasn't activated yet - return TaskAction::Continue; if (m_constData.m_children.isEmpty()) startAction = TaskAction::StopWithDone; } @@ -673,35 +548,6 @@ TaskAction TaskContainer::childDone(bool success) return continueStart(startAction, limit); } -void ConditionActivator::activate() -{ - m_node->activateCondition(); -} - -void TaskContainer::activateCondition() -{ - QTC_ASSERT(m_conditionData, return); - if (!m_constData.m_taskTreePrivate->m_root->isRunning()) - return; - - if (!isRunning()) - return; // Condition not run yet or group already skipped or stopped - - if (!m_conditionData->m_activated) - return; // May it happen that scheduled call is coming from previous TaskTree's start? - - if (m_runtimeData->m_doneCount != 0) - return; // In meantime the group was started - - for (TaskNode *child : m_constData.m_children) { - if (child->isRunning()) - return; // In meantime the group was started - } - const TaskAction startAction = m_constData.m_children.isEmpty() ? TaskAction::StopWithDone - : TaskAction::Continue; - continueStart(startAction, 0); -} - void TaskContainer::stop() { if (!isRunning()) @@ -786,26 +632,6 @@ void TaskNode::invokeEndHandler(bool success) m_container.m_constData.m_taskTreePrivate->advanceProgress(1); } -void TaskNode::activateCondition() -{ - QTC_ASSERT(m_container.m_conditionData, return); - QTC_ASSERT(m_container.m_constData.m_taskTreePrivate->m_root->isRunning(), return); - - if (m_container.m_conditionData->m_activated) - return; // Was already activated - - m_container.m_conditionData->m_activated = true; - if (!isRunning()) - return; // Condition not run yet or group already skipped or stopped - - QTC_CHECK(m_container.m_runtimeData->m_doneCount == 0); - for (TaskNode *child : m_container.m_constData.m_children) - QTC_CHECK(!child->isRunning()); - - QMetaObject::invokeMethod(this, [this] { m_container.activateCondition(); }, - Qt::QueuedConnection); -} - /*! \class Utils::TaskTree \inheaderfile utils/tasktree.h @@ -1533,8 +1359,6 @@ TaskTree::~TaskTree() { QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting TaskTree instance directly from " "one of its handlers will lead to crash!")); - if (isRunning()) - d->deleteConditionActivators(); // TODO: delete storages explicitly here? delete d; } @@ -1544,7 +1368,6 @@ void TaskTree::setupRoot(const Tasking::Group &root) QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return); QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The setupRoot() is called from one of the" "TaskTree handlers, ingoring..."); return); - d->m_conditions.clear(); d->m_storages.clear(); d->m_root.reset(new TaskNode(d, root, nullptr)); } diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 0c1b5e7a33d..9fdb1717b02 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -88,50 +88,6 @@ private: } }; -class QTCREATOR_UTILS_EXPORT ConditionActivator -{ -public: - void activate(); - -private: - ConditionActivator(TaskNode *container) : m_node(container) {} - TaskNode *m_node = nullptr; - friend class Condition; -}; - -class QTCREATOR_UTILS_EXPORT Condition -{ -public: - Condition(); - ConditionActivator &operator*() const noexcept { return *activator(); } - ConditionActivator *operator->() const noexcept { return activator(); } - ConditionActivator *activator() const; - -private: - int createActivator(TaskNode *node) const; - void deleteActivator(int id) const; - void activateActivator(int id) const; - - friend bool operator==(const Condition &first, const Condition &second) - { return first.m_conditionData == second.m_conditionData; } - - friend bool operator!=(const Condition &first, const Condition &second) - { return first.m_conditionData != second.m_conditionData; } - - friend size_t qHash(const Condition &storage, uint seed = 0) - { return size_t(storage.m_conditionData.get()) ^ seed; } - - struct ConditionData { - ~ConditionData(); - QHash m_activatorHash = {}; - int m_activeActivator = 0; // 0 means no active activator - int m_activatorCounter = 0; - }; - QSharedPointer m_conditionData; - friend TaskTreePrivate; - friend ExecutionContextActivator; -}; - // WorkflowPolicy: // 1. When all children finished with done -> report done, otherwise: // a) Report error on first error and stop executing other children (including their subtree) @@ -188,13 +144,11 @@ public: TaskHandler taskHandler() const { return m_taskHandler; } GroupHandler groupHandler() const { return m_groupHandler; } QList children() const { return m_children; } - std::optional condition() const { return m_condition; } QList storageList() const { return m_storageList; } protected: enum class Type { Group, - Condition, Storage, Limit, Policy, @@ -215,9 +169,6 @@ protected: TaskItem(const GroupHandler &handler) : m_type(Type::GroupHandler) , m_groupHandler(handler) {} - TaskItem(const Condition &condition) - : m_type(Type::Condition) - , m_condition{condition} {} TaskItem(const TreeStorageBase &storage) : m_type(Type::Storage) , m_storageList{storage} {} @@ -229,7 +180,6 @@ private: WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError; TaskHandler m_taskHandler; GroupHandler m_groupHandler; - std::optional m_condition; QList m_storageList; QList m_children; }; @@ -247,12 +197,6 @@ public: Storage(const TreeStorageBase &storage) : TaskItem(storage) { } }; -class QTCREATOR_UTILS_EXPORT WaitFor : public TaskItem -{ -public: - WaitFor(const Condition &condition) : TaskItem(condition) { } -}; - class QTCREATOR_UTILS_EXPORT ParallelLimit : public TaskItem { public: From c4acd5ce4ce1d768c21e596466ab671a8f78ed1f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 2 May 2023 08:05:21 +0200 Subject: [PATCH 0755/1447] TaskTree: Refactor barrier tests A preparation step before adding new barrier tests. Change-Id: I83aa8a7788859f98c98885384b52dc3377e01916 Reviewed-by: Marcus Tillmanns --- tests/auto/utils/tasktree/tst_tasktree.cpp | 58 ++++++++++++---------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 0533c6fd86f..f5a7b26786f 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -159,6 +159,33 @@ static void runTask(QPromise &promise, bool success, std::chrono::millisec promise.future().cancel(); } +static void reportAndSleep(QPromise &promise) +{ + promise.addResult(false); + QThread::msleep(10); +}; + +template +auto setupBarrierAdvance(const TreeStorage &storage, + const SharedBarrierType &barrier, int taskId) +{ + return [storage, barrier, taskId](AsyncTask &async) { + async.setFutureSynchronizer(s_futureSynchronizer); + async.setConcurrentCallData(reportAndSleep); + async.setProperty(s_taskIdProperty, taskId); + storage->m_log.append({taskId, Handler::Setup}); + + CustomStorage *currentStorage = storage.activeStorage(); + Barrier *sharedBarrier = barrier->barrier(); + QObject::connect(&async, &TestTask::resultReadyAt, sharedBarrier, + [currentStorage, sharedBarrier, taskId](int index) { + Q_UNUSED(index) + currentStorage->m_log.append({taskId, Handler::BarrierAdvance}); + sharedBarrier->advance(); + }); + }; +} + void tst_TaskTree::testTree_data() { QTest::addColumn("testData"); @@ -1150,37 +1177,14 @@ void tst_TaskTree::testTree_data() { SingleBarrier barrier; - const auto reportAndSleep = [](QPromise &promise) { - promise.addResult(false); - QThread::msleep(10); - }; - - const auto setupTaskWithBarrier = [storage, barrier, reportAndSleep](int taskId) { - return [storage, barrier, reportAndSleep, taskId](AsyncTask &async) { - async.setFutureSynchronizer(s_futureSynchronizer); - async.setConcurrentCallData(reportAndSleep); - async.setProperty(s_taskIdProperty, taskId); - storage->m_log.append({taskId, Handler::Setup}); - - CustomStorage *currentStorage = storage.activeStorage(); - Barrier *sharedBarrier = barrier->barrier(); - connect(&async, &TestTask::resultReadyAt, sharedBarrier, - [currentStorage, sharedBarrier, taskId](int index) { - Q_UNUSED(index) - currentStorage->m_log.append({taskId, Handler::BarrierAdvance}); - sharedBarrier->advance(); - }); - }; - }; - // Test that barrier advance, triggered from inside the task described by - // setupTaskWithCondition, placed BEFORE the group containing the waitFor() element + // setupBarrierAdvance, placed BEFORE the group containing the waitFor() element // in the tree order, works OK in SEQUENTIAL mode. const Group root1 { Storage(storage), Storage(barrier), sequential, - Async(setupTaskWithBarrier(1)), + Async(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), @@ -1203,7 +1207,7 @@ void tst_TaskTree::testTree_data() Storage(storage), Storage(barrier), parallel, - Async(setupTaskWithBarrier(1)), + Async(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), @@ -1239,7 +1243,7 @@ void tst_TaskTree::testTree_data() Test(setupTask(2)), Test(setupTask(3)) }, - Async(setupTaskWithBarrier(1)) + Async(setupBarrierAdvance(storage, barrier, 1)) }; const Log log3 { {2, Handler::GroupSetup}, From ce1a9b5990492e44f0d19be88ad035f3aac348bb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 30 Apr 2023 13:31:33 +0200 Subject: [PATCH 0756/1447] TaskTree: Add tests for new functionality enabled by Barrier Test, that it's possible to distribute the barrier advance in multiple tasks. The barrier passes after the both advances are triggered. Change-Id: Ica58f9657ecdf1ba45e1059ea47be0453948e7b9 Reviewed-by: Marcus Tillmanns --- tests/auto/utils/tasktree/tst_tasktree.cpp | 194 ++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-) diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index f5a7b26786f..00ab33bb85e 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -162,7 +162,7 @@ static void runTask(QPromise &promise, bool success, std::chrono::millisec static void reportAndSleep(QPromise &promise) { promise.addResult(false); - QThread::msleep(10); + QThread::msleep(5); }; template @@ -1253,6 +1253,64 @@ void tst_TaskTree::testTree_data() {3, Handler::Setup} }; + // Test that barrier advance, triggered from inside the task described by + // setupBarrierAdvance, placed BEFORE the groups containing the waitFor() element + // in the tree order, wakes both waitFor tasks. + const Group root4 { + Storage(storage), + Storage(barrier), + parallel, + Async(setupBarrierAdvance(storage, barrier, 1)), + Group { + OnGroupSetup(groupSetup(2)), + WaitForBarrier(barrier), + Test(setupTask(4)) + }, + Group { + OnGroupSetup(groupSetup(3)), + WaitForBarrier(barrier), + Test(setupTask(5)) + } + }; + const Log log4 { + {1, Handler::Setup}, + {2, Handler::GroupSetup}, + {3, Handler::GroupSetup}, + {1, Handler::BarrierAdvance}, + {4, Handler::Setup}, + {5, Handler::Setup} + }; + + // Test two separate single barriers. + + SingleBarrier barrier2; + + const Group root5 { + Storage(storage), + Storage(barrier), + Storage(barrier2), + parallel, + Async(setupBarrierAdvance(storage, barrier, 0)), + Async(setupBarrierAdvance(storage, barrier2, 0)), + Group { + Group { + parallel, + OnGroupSetup(groupSetup(1)), + WaitForBarrier(barrier), + WaitForBarrier(barrier2) + }, + Test(setupTask(2)) + }, + }; + const Log log5 { + {0, Handler::Setup}, + {0, Handler::Setup}, + {1, Handler::GroupSetup}, + {0, Handler::BarrierAdvance}, + {0, Handler::BarrierAdvance}, + {2, Handler::Setup} + }; + // Notice the different log order for each scenario. QTest::newRow("BarrierSequential") << TestData{storage, root1, log1, 4, OnStart::Running, OnDone::Success}; @@ -1260,6 +1318,140 @@ void tst_TaskTree::testTree_data() << TestData{storage, root2, log2, 4, OnStart::Running, OnDone::Success}; QTest::newRow("BarrierParallelWaitForFirst") << TestData{storage, root3, log3, 4, OnStart::Running, OnDone::Success}; + QTest::newRow("BarrierParallelMultiWaitFor") + << TestData{storage, root4, log4, 5, OnStart::Running, OnDone::Success}; + QTest::newRow("BarrierParallelTwoSingleBarriers") + << TestData{storage, root5, log5, 5, OnStart::Running, OnDone::Success}; + } + + { + MultiBarrier<2> barrier; + + // Test that multi barrier advance, triggered from inside the tasks described by + // setupBarrierAdvance, placed BEFORE the group containing the waitFor() element + // in the tree order, works OK in SEQUENTIAL mode. + const Group root1 { + Storage(storage), + Storage(barrier), + sequential, + Async(setupBarrierAdvance(storage, barrier, 1)), + Async(setupBarrierAdvance(storage, barrier, 2)), + Group { + OnGroupSetup(groupSetup(2)), + WaitForBarrier(barrier), + Test(setupTask(2)), + Test(setupTask(3)) + } + }; + const Log log1 { + {1, Handler::Setup}, + {1, Handler::BarrierAdvance}, + {2, Handler::Setup}, + {2, Handler::BarrierAdvance}, + {2, Handler::GroupSetup}, + {2, Handler::Setup}, + {3, Handler::Setup} + }; + + // Test that multi barrier advance, triggered from inside the tasks described by + // setupBarrierAdvance, placed BEFORE the group containing the waitFor() element + // in the tree order, works OK in PARALLEL mode. + const Group root2 { + Storage(storage), + Storage(barrier), + parallel, + Async(setupBarrierAdvance(storage, barrier, 0)), + Async(setupBarrierAdvance(storage, barrier, 0)), + Group { + OnGroupSetup(groupSetup(2)), + WaitForBarrier(barrier), + Test(setupTask(2)), + Test(setupTask(3)) + } + }; + const Log log2 { + {0, Handler::Setup}, + {0, Handler::Setup}, + {2, Handler::GroupSetup}, + {0, Handler::BarrierAdvance}, // Barrier advances may come in different order in + {0, Handler::BarrierAdvance}, // parallel mode, that's why id = 0 (same for both). + {2, Handler::Setup}, + {3, Handler::Setup} + }; + + // Test that multi barrier advance, triggered from inside the tasks described by + // setupBarrierAdvance, placed AFTER the group containing the waitFor() element + // in the tree order, works OK in PARALLEL mode. + // + // Notice: This won't work in SEQUENTIAL mode, since the advancing barriers, placed after + // the group containing the WaitFor element, has no chance to be started in SEQUENTIAL mode, + // as in SEQUENTIAL mode the next task may only be started after the previous one finished. + // In this case, the previous task (Group element) awaits for the barrier's advance to + // come from the not yet started next task, causing a deadlock. + // The minimal requirement for this scenario to succeed is to set ParallelLimit(2) or more. + const Group root3 { + Storage(storage), + Storage(barrier), + parallel, + Group { + OnGroupSetup(groupSetup(2)), + WaitForBarrier(barrier), + Test(setupTask(2)), + Test(setupTask(3)) + }, + Async(setupBarrierAdvance(storage, barrier, 0)), + Async(setupBarrierAdvance(storage, barrier, 0)) + }; + const Log log3 { + {2, Handler::GroupSetup}, + {0, Handler::Setup}, + {0, Handler::Setup}, + {0, Handler::BarrierAdvance}, // Barrier advances may come in different order in + {0, Handler::BarrierAdvance}, // parallel mode, that's why id = 0 (same for both). + {2, Handler::Setup}, + {3, Handler::Setup} + }; + + // Test that multi barrier advance, triggered from inside the task described by + // setupBarrierAdvance, placed BEFORE the groups containing the waitFor() element + // in the tree order, wakes both waitFor tasks. + const Group root4 { + Storage(storage), + Storage(barrier), + parallel, + Async(setupBarrierAdvance(storage, barrier, 0)), + Async(setupBarrierAdvance(storage, barrier, 0)), + Group { + OnGroupSetup(groupSetup(2)), + WaitForBarrier(barrier), + Test(setupTask(4)) + }, + Group { + OnGroupSetup(groupSetup(3)), + WaitForBarrier(barrier), + Test(setupTask(5)) + } + }; + const Log log4 { + {0, Handler::Setup}, + {0, Handler::Setup}, + {2, Handler::GroupSetup}, + {3, Handler::GroupSetup}, + {0, Handler::BarrierAdvance}, + {0, Handler::BarrierAdvance}, + {4, Handler::Setup}, + {5, Handler::Setup} + }; + + // Notice the different log order for each scenario. + QTest::newRow("MultiBarrierSequential") + << TestData{storage, root1, log1, 5, OnStart::Running, OnDone::Success}; + QTest::newRow("MultiBarrierParallelAdvanceFirst") + << TestData{storage, root2, log2, 5, OnStart::Running, OnDone::Success}; + QTest::newRow("MultiBarrierParallelWaitForFirst") + << TestData{storage, root3, log3, 5, OnStart::Running, OnDone::Success}; + QTest::newRow("MultiBarrierParallelMultiWaitFor") + << TestData{storage, root4, log4, 6, OnStart::Running, OnDone::Success}; } } From 3aefbb37b9aeee0562ad9060f980fbf569adeca4 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 2 May 2023 08:12:01 +0200 Subject: [PATCH 0757/1447] Tests: Fix qbs build Amends 0b3a0dce888678c4e3f5caf631cc4547677b5a69. Change-Id: I89a301a8780f17c3197ffe99a6cfc9a61d5961b3 Reviewed-by: Jarek Kobus --- tests/auto/utils/tasktree/tasktree.qbs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/auto/utils/tasktree/tasktree.qbs b/tests/auto/utils/tasktree/tasktree.qbs index ed138d9f393..9b9789c4509 100644 --- a/tests/auto/utils/tasktree/tasktree.qbs +++ b/tests/auto/utils/tasktree/tasktree.qbs @@ -23,5 +23,4 @@ Project { return defines; } } - references: "testapp/testapp.qbs" } From fbe9366498a14bfb8daaa604037bb27e1d59db64 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Apr 2023 11:32:55 +0200 Subject: [PATCH 0758/1447] LayoutBuilder: Cut remaining dependency to utils layoutbuilder.{cpp,h} can now be re-used outside Creator Change-Id: I306d2d8168d8a09658ea008f4606ca37a0dbbc01 Reviewed-by: Eike Ziller --- src/libs/utils/layoutbuilder.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index c47be9778db..3633c083e3c 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -3,8 +3,7 @@ #include "layoutbuilder.h" -#include "qtcassert.h" - +#include #include #include #include @@ -18,6 +17,14 @@ namespace Layouting { +// That's cut down qtcassert.{c,h} to avoid the dependency. +#define QTC_STRINGIFY_HELPER(x) #x +#define QTC_STRINGIFY(x) QTC_STRINGIFY_HELPER(x) +#define QTC_STRING(cond) qDebug("SOFT ASSERT: \"%s\" in %s: %s", cond, __FILE__, QTC_STRINGIFY(__LINE__)) +#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_STRING(#cond); action; } do {} while (0) +#define QTC_CHECK(cond) if (cond) {} else { QTC_STRING(#cond); } do {} while (0) + + /*! \enum Utils::LayoutBuilder::LayoutType \inmodule QtCreator From 5299bca359b2b8086c7f295de6b636e9910598f4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 22 Apr 2023 10:12:01 +0200 Subject: [PATCH 0759/1447] CurrentProjectFilter: Reimplement matchers() Change-Id: Iec838504aa0fc1a08754779a55acb53f57b5bf6c Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/currentprojectfilter.cpp | 6 ++++++ src/plugins/projectexplorer/currentprojectfilter.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index 3d41eccee59..5b5c34fe44f 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -29,6 +29,11 @@ CurrentProjectFilter::CurrentProjectFilter() connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &CurrentProjectFilter::currentProjectChanged); + + m_cache.setGeneratorProvider([this] { + const FilePaths paths = m_project ? m_project->files(Project::SourceFiles) : FilePaths(); + return LocatorFileCache::filePathsGenerator(paths); + }); } void CurrentProjectFilter::prepareSearch(const QString &entry) @@ -60,5 +65,6 @@ void CurrentProjectFilter::currentProjectChanged() void CurrentProjectFilter::invalidateCache() { + m_cache.invalidate(); setFileIterator(nullptr); } diff --git a/src/plugins/projectexplorer/currentprojectfilter.h b/src/plugins/projectexplorer/currentprojectfilter.h index 9b74161fbd5..6aef3050584 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.h +++ b/src/plugins/projectexplorer/currentprojectfilter.h @@ -11,6 +11,7 @@ class Project; namespace Internal { +// TODO: Don't derive from BaseFileFilter, flatten the hierarchy class CurrentProjectFilter : public Core::BaseFileFilter { Q_OBJECT @@ -20,9 +21,12 @@ public: void prepareSearch(const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final { return {m_cache.matcher()}; } void currentProjectChanged(); + // TODO: Remove me, replace with direct "m_cache.invalidate()" call void invalidateCache(); + Core::LocatorFileCache m_cache; Project *m_project = nullptr; }; From a35fe27188de74d0b0436b4a6f2fab0948b3d0be Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 22 Apr 2023 11:27:59 +0200 Subject: [PATCH 0760/1447] DirectoryFilter: Reimplement matchers() Change-Id: I8891d253ba4f2409f3547b49293a35de12c3ee3c Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/locator/directoryfilter.cpp | 1 + src/plugins/coreplugin/locator/directoryfilter.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 59043051368..26a9455ca57 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -383,6 +383,7 @@ void DirectoryFilter::updateOptionButtons() void DirectoryFilter::updateFileIterator() { + m_cache.setFilePaths(m_files); setFileIterator(new BaseFileFilter::ListIterator(m_files)); } diff --git a/src/plugins/coreplugin/locator/directoryfilter.h b/src/plugins/coreplugin/locator/directoryfilter.h index 164c4ab164b..556c9937a30 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.h +++ b/src/plugins/coreplugin/locator/directoryfilter.h @@ -11,6 +11,7 @@ namespace Core { +// TODO: Don't derive from BaseFileFilter, flatten the hierarchy class CORE_EXPORT DirectoryFilter : public BaseFileFilter { Q_OBJECT @@ -31,11 +32,13 @@ protected: void restoreState(const QJsonObject &object) override; private: + LocatorMatcherTasks matchers() final { return {m_cache.matcher()}; } void setDirectories(const Utils::FilePaths &directories); void handleAddDirectory(); void handleEditDirectory(); void handleRemoveDirectory(); void updateOptionButtons(); + // TODO: Remove me, replace with direct "m_cache.setFilePaths()" call void updateFileIterator(); Utils::FilePaths m_directories; @@ -44,8 +47,10 @@ private: // Our config dialog, uses in addDirectory and editDirectory // to give their dialogs the right parent class DirectoryFilterOptions *m_dialog = nullptr; + // TODO: Remove me, use the cache instead. Utils::FilePaths m_files; bool m_isCustomFilter = true; + LocatorFileCache m_cache; }; } // namespace Core From c3a213cc657b1b9a6427990a57209e78581883c4 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 2 May 2023 09:30:37 +0200 Subject: [PATCH 0761/1447] FakeVim: Remove QtcProcess use from fakevimhandler.cpp fakevimhandler.{h,cpp} are meant to be re-usable outside of Qt Creator. Amends 91605c3. Change-Id: I569a393d13049ef92ed3ef0c4f69de5232b2fa32 Reviewed-by: Jarek Kobus --- src/plugins/fakevim/fakevimhandler.cpp | 28 ++------------------------ src/plugins/fakevim/fakevimhandler.h | 1 + src/plugins/fakevim/fakevimplugin.cpp | 14 ++++++++++++- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index bd1e035f48a..4fbab50d469 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -36,8 +36,6 @@ #include "fakevimactions.h" #include "fakevimtr.h" -#include - #include #include #include @@ -833,29 +831,6 @@ static void setClipboardData(const QString &content, RangeMode mode, clipboard->setMimeData(data, clipboardMode); } -static QByteArray toLocalEncoding(const QString &text) -{ -#if defined(Q_OS_WIN) - return QString(text).replace("\n", "\r\n").toLocal8Bit(); -#else - return text.toLocal8Bit(); -#endif -} - -static QString getProcessOutput(const QString &command, const QString &input) -{ - Utils::QtcProcess proc; - proc.setCommand(Utils::CommandLine::fromUserInput(command)); - proc.setWriteData(toLocalEncoding(input)); - proc.start(); - - // FIXME: Process should be interruptable by user. - // Solution is to create a QObject for each process and emit finished state. - proc.waitForFinished(); - - return proc.cleanedStdOut(); -} - static const QMap &vimKeyNames() { static const QMap k = { @@ -6432,7 +6407,8 @@ bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :! const QString command = QString(cmd.cmd.mid(1) + ' ' + cmd.args).trimmed(); const QString input = replaceText ? selectText(cmd.range) : QString(); - const QString result = getProcessOutput(command, input); + QString result; + q->processOutput(command, input, &result); if (replaceText) { setCurrentRange(cmd.range); diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index b19e2579092..7c0cecaf738 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -167,6 +167,7 @@ public: Callback tabNextRequested; Callback modeChanged; Callback tabPressedInInsertMode; + Callback processOutput; public: class Private; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index d0c399ac31b..8d71345b56f 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include #include @@ -1887,6 +1887,18 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) tew->invokeAssist(Completion, &runData->wordProvider); }); + handler->processOutput.set([](const QString &command, const QString &input, QString *output) { + QtcProcess proc; + proc.setCommand(Utils::CommandLine::fromUserInput(command)); + proc.setWriteData(input.toLocal8Bit()); + proc.start(); + + // FIXME: Process should be interruptable by user. + // Solution is to create a QObject for each process and emit finished state. + proc.waitForFinished(); + *output = proc.cleanedStdOut(); + }); + connect(ICore::instance(), &ICore::saveSettingsRequested, this, &FakeVimPluginPrivate::writeSettings); From a5db02c9a7215d7aec0f1473d619b1fda2f539f7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 22 Apr 2023 09:56:10 +0200 Subject: [PATCH 0762/1447] AllProjectsFilter: Reimplement matchers() Change-Id: I963929ce121e1dd22e0ea3ef4a72f1654b195066 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot Reviewed-by: --- .../projectexplorer/allprojectsfilter.cpp | 18 +++++++++++++++++- .../projectexplorer/allprojectsfilter.h | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index f4f9604b278..1fc9fe0b4b3 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -9,7 +9,8 @@ #include "projectmanager.h" #include -#include + +#include using namespace Core; using namespace Utils; @@ -29,6 +30,20 @@ AllProjectsFilter::AllProjectsFilter() connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, this, &AllProjectsFilter::invalidateCache); + m_cache.setGeneratorProvider([] { + // This body runs in main thread + FilePaths filePaths; + for (Project *project : ProjectManager::projects()) + filePaths.append(project->files(Project::SourceFiles)); + return [filePaths](const QFuture &future) { + // This body runs in non-main thread + FilePaths sortedPaths = filePaths; + if (future.isCanceled()) + return FilePaths(); + Utils::sort(sortedPaths); + return sortedPaths; + }; + }); } void AllProjectsFilter::prepareSearch(const QString &entry) @@ -46,6 +61,7 @@ void AllProjectsFilter::prepareSearch(const QString &entry) void AllProjectsFilter::invalidateCache() { + m_cache.invalidate(); setFileIterator(nullptr); } diff --git a/src/plugins/projectexplorer/allprojectsfilter.h b/src/plugins/projectexplorer/allprojectsfilter.h index 5d6e3b72fff..4cf5bf0b78e 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.h +++ b/src/plugins/projectexplorer/allprojectsfilter.h @@ -8,6 +8,7 @@ namespace ProjectExplorer { namespace Internal { +// TODO: Don't derive from BaseFileFilter, flatten the hierarchy class AllProjectsFilter : public Core::BaseFileFilter { Q_OBJECT @@ -17,7 +18,10 @@ public: void prepareSearch(const QString &entry) override; private: + Core::LocatorMatcherTasks matchers() final { return {m_cache.matcher()}; } + // TODO: Remove me, replace with direct "m_cache.invalidate()" call void invalidateCache(); + Core::LocatorFileCache m_cache; }; } // namespace Internal From 3e0a179d2442ec9b544e0701eadcdc85deae20ee Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 1 May 2023 14:56:44 +0200 Subject: [PATCH 0763/1447] ResultsCollector: Fix destructor It may happen that still running LocatorMatcher is destructed from the LocatorWidget destructor (i.e. from CorePlugin d'tor). In this case the global future synchronizer is already reset, so the d'tor of ResultsCollector can't put running deduplicator task into the global synchronizer. Check this case and place the deduplicator task into the global future synchronizer only when it still exists. Otherwise, blocking wait for the deduplicator to finish. Change-Id: Ie788db923808dd91bdfdc4f1f53d336baf7c672a Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index b8e393839d3..b4809d897c7 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -273,7 +273,11 @@ ResultsCollector::~ResultsCollector() return; m_deduplicator->cancel(); - ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(m_watcher->future()); + if (ExtensionSystem::PluginManager::futureSynchronizer()) { + ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(m_watcher->future()); + return; + } + m_watcher->future().waitForFinished(); } void ResultsCollector::setFilterCount(int count) From 3e953f4896849d375e81f37ad3ed718746e7527c Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 26 Apr 2023 12:37:43 +0200 Subject: [PATCH 0764/1447] Layouting: Add some example code as show case Change-Id: I92842c7859514397748e744949688090154772df Reviewed-by: Reviewed-by: Christian Stenger --- .../layoutbuilder/comparison/CMakeLists.txt | 6 +++ .../comparison/layoutbuilder/CMakeLists.txt | 46 +++++++++++++++++++ .../comparison/layoutbuilder/main.cpp | 11 +++++ .../comparison/layoutbuilder/mainwindow.cpp | 0 .../comparison/layoutbuilder/mainwindow.h | 29 ++++++++++++ .../comparison/quick/CMakeLists.txt | 37 +++++++++++++++ .../layoutbuilder/comparison/quick/Main.qml | 30 ++++++++++++ .../layoutbuilder/comparison/quick/main.cpp | 16 +++++++ .../comparison/widgets/CMakeLists.txt | 40 ++++++++++++++++ .../layoutbuilder/comparison/widgets/main.cpp | 12 +++++ .../comparison/widgets/mainwindow.cpp | 24 ++++++++++ .../comparison/widgets/mainwindow.h | 28 +++++++++++ 12 files changed, 279 insertions(+) create mode 100644 tests/manual/layoutbuilder/comparison/CMakeLists.txt create mode 100644 tests/manual/layoutbuilder/comparison/layoutbuilder/CMakeLists.txt create mode 100644 tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp create mode 100644 tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.cpp create mode 100644 tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h create mode 100644 tests/manual/layoutbuilder/comparison/quick/CMakeLists.txt create mode 100644 tests/manual/layoutbuilder/comparison/quick/Main.qml create mode 100644 tests/manual/layoutbuilder/comparison/quick/main.cpp create mode 100644 tests/manual/layoutbuilder/comparison/widgets/CMakeLists.txt create mode 100644 tests/manual/layoutbuilder/comparison/widgets/main.cpp create mode 100644 tests/manual/layoutbuilder/comparison/widgets/mainwindow.cpp create mode 100644 tests/manual/layoutbuilder/comparison/widgets/mainwindow.h diff --git a/tests/manual/layoutbuilder/comparison/CMakeLists.txt b/tests/manual/layoutbuilder/comparison/CMakeLists.txt new file mode 100644 index 00000000000..ac1c62fabdb --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/CMakeLists.txt @@ -0,0 +1,6 @@ + +project(Comparison) + +add_subdirectory(quick) +add_subdirectory(widgets) +add_subdirectory(layoutbuilder) diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/CMakeLists.txt b/tests/manual/layoutbuilder/comparison/layoutbuilder/CMakeLists.txt new file mode 100644 index 00000000000..326985aae03 --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.5) + +project(layoutbuilder VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Widgets) + +set(PROJECT_SOURCES + main.cpp + mainwindow.cpp + mainwindow.h + ../../../../../src/libs/utils/layoutbuilder.cpp + ../../../../../src/libs/utils/layoutbuilder.h +) + +add_executable(layoutbuilder + ${PROJECT_SOURCES} +) + +target_include_directories(layoutbuilder PRIVATE + ../../../../../src/libs/utils/ +) + +target_link_libraries(layoutbuilder PRIVATE + Qt6::Widgets +) + +set_target_properties(layoutbuilder PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +install(TARGETS layoutbuilder + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp b/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp new file mode 100644 index 00000000000..96911edee8c --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + ApplicationWindow w; + w.show(); + return a.exec(); +} diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.cpp b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h new file mode 100644 index 00000000000..8ff57827f9d --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h @@ -0,0 +1,29 @@ +#pragma once + +#include "layoutbuilder.h" + +#include +#include + +using namespace Layouting; + +class ApplicationWindow : public QWidget +{ +public: + ApplicationWindow() + { + resize(600, 400); + setWindowTitle("Hello World"); + + Column { + TextEdit { + text("Hallo") + }, + + PushButton { + text("Quit"), + onClicked([] { QCoreApplication::quit(); }) + } + }.attachTo(this); + } +}; diff --git a/tests/manual/layoutbuilder/comparison/quick/CMakeLists.txt b/tests/manual/layoutbuilder/comparison/quick/CMakeLists.txt new file mode 100644 index 00000000000..4166619afd4 --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/quick/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.16) + +project(quick VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 6.4 REQUIRED COMPONENTS Quick) + +qt_standard_project_setup() + +qt_add_executable(appquick + main.cpp +) + +qt_add_qml_module(appquick + URI quick + VERSION 1.0 + QML_FILES Main.qml +) + +set_target_properties(appquick PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +target_link_libraries(appquick + PRIVATE Qt6::Quick +) + +install(TARGETS appquick + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/tests/manual/layoutbuilder/comparison/quick/Main.qml b/tests/manual/layoutbuilder/comparison/quick/Main.qml new file mode 100644 index 00000000000..2200399429d --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/quick/Main.qml @@ -0,0 +1,30 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +ApplicationWindow { + + width: 640 + height: 480 + visible: true + title: "Hello World" + + ColumnLayout { + anchors.fill: parent + + Text { + Layout.fillHeight: true + Layout.fillWidth: true + + text: "Hallo" + } + + Button { + text: "Quit" + height: 20 + Layout.fillWidth: true + + onClicked: { Qt.quit() } + } + } +} diff --git a/tests/manual/layoutbuilder/comparison/quick/main.cpp b/tests/manual/layoutbuilder/comparison/quick/main.cpp new file mode 100644 index 00000000000..76df95e6ea3 --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/quick/main.cpp @@ -0,0 +1,16 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + const QUrl url(u"qrc:/quick/Main.qml"_qs); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, + &app, []() { QCoreApplication::exit(-1); }, + Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +} diff --git a/tests/manual/layoutbuilder/comparison/widgets/CMakeLists.txt b/tests/manual/layoutbuilder/comparison/widgets/CMakeLists.txt new file mode 100644 index 00000000000..8f895f41217 --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/widgets/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.5) + +project(widgets VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Widgets) + +set(PROJECT_SOURCES + main.cpp + mainwindow.cpp + mainwindow.h +) + +add_executable(widgets + ${PROJECT_SOURCES} +) + +target_link_libraries(widgets PRIVATE + Qt6::Widgets +) + +set_target_properties(widgets PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +install(TARGETS widgets + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/tests/manual/layoutbuilder/comparison/widgets/main.cpp b/tests/manual/layoutbuilder/comparison/widgets/main.cpp new file mode 100644 index 00000000000..5d394e06c38 --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/widgets/main.cpp @@ -0,0 +1,12 @@ + +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + ApplicationWindow w; + w.show(); + return a.exec(); +} diff --git a/tests/manual/layoutbuilder/comparison/widgets/mainwindow.cpp b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.cpp new file mode 100644 index 00000000000..346e6a1ca0d --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.cpp @@ -0,0 +1,24 @@ +//#include "mainwindow.h" + +//#include +//#include +//#include +//#include + +//ApplicationWindow::ApplicationWindow() +//{ +// resize(600, 400); +// setWindowTitle("Hello World"); + +// auto textEdit = new QTextEdit; +// textEdit->setText("Hallo"); + +// auto pushButton = new QPushButton("Quit"); + +// auto l = new QVBoxLayout(this); +// l->addWidget(textEdit); +// l->addWidget(pushButton); + +// connect(pushButton, &QPushButton::clicked, +// qApp, &QCoreApplication::quit); +//} diff --git a/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h new file mode 100644 index 00000000000..9acf84d4b55 --- /dev/null +++ b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +class ApplicationWindow : public QWidget +{ +public: + ApplicationWindow() + { + resize(600, 400); + setWindowTitle("Hello World"); + + auto textEdit = new QTextEdit; + textEdit->setText("Hallo"); + + auto pushButton = new QPushButton("Quit"); + + auto l = new QVBoxLayout(this); + l->addWidget(textEdit); + l->addWidget(pushButton); + + connect(pushButton, &QPushButton::clicked, + qApp, &QCoreApplication::quit); + } +}; From 66c0c36bc1cb2417295f5b5c7d7e556f5329f309 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 28 Apr 2023 11:29:08 +0200 Subject: [PATCH 0765/1447] Fix compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9b0b4a60d1152142f62bf3f76885cf8019714623 Reviewed-by: Qt CI Bot Reviewed-by: Sivert Krøvel Reviewed-by: Christian Stenger Reviewed-by: --- .../src/lib/syntaxhighlighter.cpp | 2 +- .../cmakeprojectmanager/cmakebuildstep.cpp | 2 +- src/plugins/cpaster/stickynotespasteprotocol.h | 1 - src/plugins/git/gitclient.cpp | 4 ++-- src/plugins/mcusupport/test/unittest.cpp | 10 +++------- .../designercore/include/qmlobjectnode.h | 1 + .../designercore/projectstorage/qmltypesparser.h | 2 +- .../qmldesigner/utils/multifiledownloader.cpp | 5 +++++ .../qmldesigner/utils/multifiledownloader.h | 3 ++- src/plugins/qmlpreview/qmlpreviewruncontrol.cpp | 15 +++++++++------ .../remotelinux/remotelinuxenvironmentaspect.cpp | 2 +- src/plugins/squish/squishnavigationwidget.cpp | 2 +- .../qml/qmldesigner/wizard/userpresets-test.cpp | 2 -- tests/unit/unittest/sqlitedatabasemock.h | 2 +- .../unit/unittest/sqlitereadwritestatementmock.h | 2 +- 15 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp index 41551e96da5..4754da22c61 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp @@ -179,7 +179,7 @@ void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion regio { Q_UNUSED(offset); Q_UNUSED(length); - Q_D(SyntaxHighlighter); + [[maybe_unused]] Q_D(SyntaxHighlighter); if (region.type() == FoldingRegion::Begin) { d->foldingRegions.push_back(region); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index bbf321cd70b..da5cf42e041 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -764,7 +764,7 @@ void CMakeBuildStep::updateDeploymentData() const auto appFileNames = transform>(buildSystem()->applicationTargets(), [](const BuildTargetInfo &appTarget) { return appTarget.targetFilePath.fileName(); }); - auto handleFile = [this, &appFileNames, startPos, &deploymentData](const FilePath &filePath) { + auto handleFile = [&appFileNames, startPos, &deploymentData](const FilePath &filePath) { const DeployableFile::Type type = appFileNames.contains(filePath.fileName()) ? DeployableFile::TypeExecutable : DeployableFile::TypeNormal; diff --git a/src/plugins/cpaster/stickynotespasteprotocol.h b/src/plugins/cpaster/stickynotespasteprotocol.h index e17508e084f..f212c883ef2 100644 --- a/src/plugins/cpaster/stickynotespasteprotocol.h +++ b/src/plugins/cpaster/stickynotespasteprotocol.h @@ -38,7 +38,6 @@ private: QNetworkReply *m_listReply = nullptr; QString m_fetchId; - int m_postId = -1; bool m_hostChecked = false; }; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 66f03aa974f..6ac72e8946d 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -60,7 +60,7 @@ const char GIT_DIRECTORY[] = ".git"; const char HEAD[] = "HEAD"; const char CHERRY_PICK_HEAD[] = "CHERRY_PICK_HEAD"; -const char BRANCHES_PREFIX[] = "Branches: "; +[[maybe_unused]] const char BRANCHES_PREFIX[] = "Branches: "; const char stashNamePrefix[] = "stash@{"; const char noColorOption[] = "--no-color"; const char colorOption[] = "--color=always"; @@ -92,7 +92,7 @@ static QString branchesDisplay(const QString &prefix, QStringList *branches, boo if (*first) *first = false; else - output += QString(sizeof(BRANCHES_PREFIX) - 1, ' '); // Align + output += QString(sizeof(BRANCHES_PREFIX) - 1 /* the \0 */, ' '); // Align output += prefix + ": "; // If there are more than 'limit' branches, list limit/2 (first limit/4 and last limit/4) if (count > limit) { diff --git a/src/plugins/mcusupport/test/unittest.cpp b/src/plugins/mcusupport/test/unittest.cpp index b9fc108ef76..a8a8f091399 100644 --- a/src/plugins/mcusupport/test/unittest.cpp +++ b/src/plugins/mcusupport/test/unittest.cpp @@ -152,11 +152,7 @@ const QString renesasProgrammerEnvVar{"RenesasFlashProgrammer_PATH"}; const char renesasProgrammerLabel[]{"Renesas Flash Programmer"}; const QString renesasProgrammerDetectionPath{HostOsInfo::withExecutableSuffix("rfp-cli")}; -const char renesasE2StudioCmakeVar[]{"EK_RA6M3G_E2_PROJECT_PATH"}; -const char renesasE2StudioDefaultPath[]{"%{Env:HOME}/e2_studio/workspace"}; const QString renesasE2StudioPath{(FileUtils::homePath() / "/e2_studio/workspace").toUserOutput()}; -const char renesasE2StudioLabel[]{"Path to project for Renesas e2 Studio"}; -const char renesasE2StudioSetting[]{"RenesasE2StudioPath"}; const char cypressProgrammerSetting[]{"CypressAutoFlashUtil"}; const char cypressProgrammerCmakeVar[]{"INFINEON_AUTO_FLASH_UTILITY_DIR"}; @@ -1760,9 +1756,9 @@ void McuSupportTest::test_nonemptyVersionDetector() // pkgDesc.versionDetection.xmlAttribute left empty pkgDesc.shouldAddToSystemPath = false; const auto package = targetFactory.createPackage(pkgDesc); - QVERIFY(package->getVersionDetector() != nullptr); - QCOMPARE(typeid(*package->getVersionDetector()).name(), - typeid(McuPackageExecutableVersionDetector).name()); + const McuPackageVersionDetector *detector = package->getVersionDetector(); + QVERIFY(detector != nullptr); + QCOMPARE(typeid(*detector).name(), typeid(McuPackageExecutableVersionDetector).name()); } void McuSupportTest::test_emptyVersionDetector() diff --git a/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h b/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h index c4e0c55a9e3..1eea5063c99 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlobjectnode.h @@ -29,6 +29,7 @@ public: QmlObjectNode(const ModelNode &modelNode) : QmlModelNodeFacade(modelNode) {} + virtual ~QmlObjectNode() = default; static bool isValidQmlObjectNode(const ModelNode &modelNode); bool isValid() const override; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h index 902d3c5a44f..09513bb74e3 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h @@ -42,7 +42,7 @@ public: private: // m_pathCache and m_storage are only used when compiled for QDS #ifdef QDS_HAS_QMLDOM - PathCache &m_pathCache; + [[maybe_unused]] PathCache &m_pathCache; ProjectStorage &m_storage; #endif }; diff --git a/src/plugins/qmldesigner/utils/multifiledownloader.cpp b/src/plugins/qmldesigner/utils/multifiledownloader.cpp index 346c1675f6e..c36476f05d6 100644 --- a/src/plugins/qmldesigner/utils/multifiledownloader.cpp +++ b/src/plugins/qmldesigner/utils/multifiledownloader.cpp @@ -41,6 +41,11 @@ void MultiFileDownloader::setDownloader(FileDownloader *downloader) }); } +FileDownloader *MultiFileDownloader::downloader() +{ + return m_downloader; +} + void MultiFileDownloader::start() { emit downloadStarting(); diff --git a/src/plugins/qmldesigner/utils/multifiledownloader.h b/src/plugins/qmldesigner/utils/multifiledownloader.h index 548896dbc8d..794f85538cb 100644 --- a/src/plugins/qmldesigner/utils/multifiledownloader.h +++ b/src/plugins/qmldesigner/utils/multifiledownloader.h @@ -13,7 +13,7 @@ class MultiFileDownloader : public QObject { Q_OBJECT - Q_PROPERTY(FileDownloader *downloader WRITE setDownloader) + Q_PROPERTY(FileDownloader *downloader READ downloader WRITE setDownloader) Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged) Q_PROPERTY(int progress READ progress NOTIFY progressChanged) Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged) @@ -34,6 +34,7 @@ public: void setTargetDirPath(const QString &path); QString targetDirPath() const; void setDownloader(FileDownloader *downloader); + FileDownloader *downloader(); bool finished() const; int progress() const; diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index 3aa935db74e..6b886389e6f 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -88,11 +88,14 @@ QmlPreviewRunner::QmlPreviewRunner(RunControl *runControl, const QmlPreviewRunne if (!runControl->isRunning()) return; - this->connect(runControl, &RunControl::stopped, [this, runControl] { - auto rc = new RunControl(ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE); - rc->copyDataFromRunControl(runControl); - ProjectExplorerPlugin::startRunControl(rc); - }); + this->connect(runControl, + &RunControl::stopped, + ProjectExplorerPlugin::instance(), + [runControl] { + auto rc = new RunControl(ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE); + rc->copyDataFromRunControl(runControl); + ProjectExplorerPlugin::startRunControl(rc); + }); runControl->initiateStop(); }); @@ -124,7 +127,7 @@ QUrl QmlPreviewRunner::serverUrl() const QmlPreviewRunWorkerFactory::QmlPreviewRunWorkerFactory(QmlPreviewPlugin *plugin, const QmlPreviewRunnerSetting *runnerSettings) { - setProducer([this, plugin, runnerSettings](RunControl *runControl) { + setProducer([plugin, runnerSettings](RunControl *runControl) { auto runner = new QmlPreviewRunner(runControl, *runnerSettings); QObject::connect(plugin, &QmlPreviewPlugin::updatePreviews, runner, &QmlPreviewRunner::loadFile); diff --git a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp index cc13e51273d..1be0624490f 100644 --- a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp +++ b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp @@ -40,7 +40,7 @@ public: connect(target, &Target::kitChanged, [aspect] { aspect->setRemoteEnvironment({}); }); - connect(fetchButton, &QPushButton::clicked, this, [this, aspect, target] { + connect(fetchButton, &QPushButton::clicked, this, [aspect, target] { if (IDevice::ConstPtr device = DeviceKitAspect::device(target->kit())) { DeviceFileAccess *access = device->fileAccess(); QTC_ASSERT(access, return); diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index ce965013987..829b2312cc7 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -185,7 +185,7 @@ void SquishNavigationWidget::contextMenuEvent(QContextMenuEvent *event) QAction *closeAllSuites = new QAction(Tr::tr("Close All Test Suites"), &menu); menu.addAction(closeAllSuites); - connect(closeAllSuites, &QAction::triggered, this, [this] { + connect(closeAllSuites, &QAction::triggered, this, [] { if (SquishMessages::simpleQuestion(Tr::tr("Close All Test Suites"), Tr::tr("Close all test suites?" /*"\nThis will close all related files as well."*/)) diff --git a/tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp b/tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp index 7dffbef4160..0605791315a 100644 --- a/tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp +++ b/tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp @@ -44,8 +44,6 @@ void PrintTo(const std::vector &presets, std::ostream *os) using namespace StudioWelcome; -constexpr char ARRAY_NAME[] = "UserPresets"; - class FakeStoreIo : public StoreIo { public: diff --git a/tests/unit/unittest/sqlitedatabasemock.h b/tests/unit/unittest/sqlitedatabasemock.h index 62a1d6585b7..658a0ec88b4 100644 --- a/tests/unit/unittest/sqlitedatabasemock.h +++ b/tests/unit/unittest/sqlitedatabasemock.h @@ -28,7 +28,7 @@ public: MOCK_METHOD(void, prepare, (Utils::SmallStringView sqlStatement), ()); - MOCK_METHOD(void, execute, (Utils::SmallStringView sqlStatement), ()); + MOCK_METHOD(void, execute, (Utils::SmallStringView sqlStatement), (override)); MOCK_METHOD(int64_t, lastInsertedRowId, (), (const)); diff --git a/tests/unit/unittest/sqlitereadwritestatementmock.h b/tests/unit/unittest/sqlitereadwritestatementmock.h index 3dab28d9946..aaf59530741 100644 --- a/tests/unit/unittest/sqlitereadwritestatementmock.h +++ b/tests/unit/unittest/sqlitereadwritestatementmock.h @@ -43,7 +43,7 @@ public: ()); template - auto optionalValue(const QueryTypes &...queryValues) + auto optionalValue([[maybe_unused]] const QueryTypes &...queryValues) { static_assert(!std::is_same_v, "SqliteReadStatementMock::value does not handle result type!"); From c192536b64df8fd3455e6f602be7fe858a5f3bb6 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 26 Apr 2023 09:35:52 +0200 Subject: [PATCH 0766/1447] Examples: Use theme colors for section separator + link Change-Id: Ia5706dd81c0494f0a7c1a1df346918462b52ba53 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/welcomepagehelper.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 1d13b1a8c6b..efcf74070ae 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -749,9 +749,21 @@ static QWidget *createSeparator(QWidget *parent) QSizePolicy linePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored); linePolicy.setHorizontalStretch(2); line->setSizePolicy(linePolicy); + QPalette pal = line->palette(); + pal.setColor(QPalette::Dark, Qt::transparent); + pal.setColor(QPalette::Light, themeColor(Theme::Welcome_ForegroundSecondaryColor)); + line->setPalette(pal); return line; } +static QLabel *createLinkLabel(const QString &text, QWidget *parent) +{ + const QString linkColor = themeColor(Theme::Welcome_LinkColor).name(); + auto link = new QLabel("" + + text + "", parent); + return link; +} + ListModel *SectionedGridView::addSection(const Section §ion, const QList &items) { auto model = new ListModel(this); @@ -772,8 +784,7 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList" + Tr::tr("Show All") + " >", this); + QLabel *seeAllLink = createLinkLabel(Tr::tr("Show All") + " >", this); if (gridView->maxRows().has_value()) { seeAllLink->setVisible(true); connect(gridView, &SectionGridView::itemsFitChanged, seeAllLink, [seeAllLink](bool fits) { @@ -783,6 +794,7 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetVisible(false); } connect(seeAllLink, &QLabel::linkActivated, this, [this, section] { zoomInSection(section); }); + using namespace Layouting; QWidget *sectionLabel = Row{section.name, createSeparator(this), seeAllLink, Space(HSpacing)} .emerge(Layouting::WithoutMargins); m_sectionLabels.append(sectionLabel); @@ -829,13 +841,13 @@ void SectionedGridView::zoomInSection(const Section §ion) layout->setContentsMargins(0, 0, 0, 0); zoomedInWidget->setLayout(layout); - using namespace Layouting; - auto backLink = new QLabel("< " + Tr::tr("Back") + "", zoomedInWidget); + QLabel *backLink = createLinkLabel("< " + Tr::tr("Back"), this); connect(backLink, &QLabel::linkActivated, this, [this, zoomedInWidget] { removeWidget(zoomedInWidget); delete zoomedInWidget; setCurrentIndex(0); }); + using namespace Layouting; QWidget *sectionLabel = Row{section.name, createSeparator(this), backLink, Space(HSpacing)} .emerge(Layouting::WithoutMargins); sectionLabel->setContentsMargins(0, ItemGap, 0, 0); From 1c2b29b31acc7f2cb27fc1a5c84fb9f0f176b38c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Apr 2023 17:21:39 +0200 Subject: [PATCH 0767/1447] Layouting: Introduce a 'bindTo' LayoutItem ... to 'export' the widget being operated on. The 'Tab' related changes are related, as they affect the order of execution. Change-Id: I7aa079f12e49a1dab7c6a49acfae9dc684cfb479 Reviewed-by: Qt CI Bot Reviewed-by: Alessandro Portale Reviewed-by: --- src/libs/utils/layoutbuilder.cpp | 81 +++++++++++-------- src/libs/utils/layoutbuilder.h | 16 ++-- .../cppeditor/cppcodemodelinspectordialog.cpp | 18 +++-- .../cppeditor/cppcodestylesettingspage.cpp | 10 +-- 4 files changed, 72 insertions(+), 53 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 3633c083e3c..e86e69a8302 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -418,16 +418,22 @@ Tab::Tab(const QString &tabName, const LayoutBuilder &item) text = tabName; widget = new QWidget; item.attachTo(widget); + specialType = LayoutItem::SpecialType::Tab; } // "Widgets" -static void applyItems(QWidget *widget, const QList &items) +static void applyItems(LayoutItem *owner, QWidget *widget, const QList &items) { + owner->widget = widget; bool hadLayout = false; for (const LayoutItem &item : items) { if (item.setter) { item.setter(widget); + } else if (item.specialType == LayoutItem::SpecialType::Tab) { + auto tabWidget = qobject_cast(widget); + QTC_ASSERT(tabWidget, continue); + tabWidget->addTab(item.widget, item.text); } else if (item.layout && !hadLayout) { hadLayout = true; widget->setLayout(item.layout); @@ -439,70 +445,65 @@ static void applyItems(QWidget *widget, const QList &items) Group::Group(std::initializer_list items) { - widget = new QGroupBox; - applyItems(widget, items); + applyItems(this, new QGroupBox, items); } PushButton::PushButton(std::initializer_list items) { - widget = new QPushButton; - applyItems(widget, items); + applyItems(this, new QPushButton, items); } TextEdit::TextEdit(std::initializer_list items) { - widget = new QTextEdit; - applyItems(widget, items); + applyItems(this, new QTextEdit, items); } Splitter::Splitter(std::initializer_list items) - : Splitter(new QSplitter(Qt::Vertical), items) {} - -Splitter::Splitter(QSplitter *splitter, std::initializer_list items) { - widget = splitter; - for (const LayoutItem &item : items) - splitter->addWidget(item.widget); -} + applyItems(this, new QSplitter(Qt::Vertical), items); + } -TabWidget::TabWidget(std::initializer_list tabs) - : TabWidget(new QTabWidget, tabs) {} -TabWidget::TabWidget(QTabWidget *tabWidget, std::initializer_list tabs) -{ - widget = tabWidget; - for (const Tab &tab : tabs) - tabWidget->addTab(tab.widget, tab.text); +TabWidget::TabWidget(std::initializer_list items) + { + applyItems(this, new QTabWidget, items); } // "Properties" -LayoutItem::Setter title(const QString &title) +static LayoutItem setter(const LayoutItem::Setter &setter) { - return [title](QObject *target) { + LayoutItem item; + item.setter = setter; + return item; +} + +LayoutItem title(const QString &title) +{ + return setter([title](QObject *target) { if (auto groupBox = qobject_cast(target)) { groupBox->setTitle(title); groupBox->setObjectName(title); } else { QTC_CHECK(false); } - }; + }); } -LayoutItem::Setter onClicked(const std::function &func, QObject *guard) +LayoutItem onClicked(const std::function &func, QObject *guard) { - return [func, guard](QObject *target) { + return setter([func, guard](QObject *target) { if (auto button = qobject_cast(target)) { QObject::connect(button, &QAbstractButton::clicked, guard ? guard : target, func); } else { QTC_CHECK(false); } - }; + }); } -LayoutItem::Setter text(const QString &text) +LayoutItem text(const QString &text) { - return [text](QObject *target) { + return setter([text](QObject *target) { if (auto button = qobject_cast(target)) { button->setText(text); } else if (auto textEdit = qobject_cast(target)) { @@ -510,18 +511,32 @@ LayoutItem::Setter text(const QString &text) } else { QTC_CHECK(false); } - }; + }); } -LayoutItem::Setter tooltip(const QString &toolTip) +LayoutItem tooltip(const QString &toolTip) { - return [toolTip](QObject *target) { + return setter([toolTip](QObject *target) { if (auto widget = qobject_cast(target)) { widget->setToolTip(toolTip); } else { QTC_CHECK(false); } - }; + }); +} + +LayoutItem bindTo(QSplitter **out) +{ + return setter([out](QObject *target) { + *out = qobject_cast(target); + }); +} + +LayoutItem bindTo(QTabWidget **out) +{ + return setter([out](QObject *target) { + *out = qobject_cast(target); + }); } QWidget *createHr(QWidget *parent) diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 0e24d1d2ec4..aea4db876c1 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -87,6 +87,7 @@ public: Stretch, Break, HorizontalRule, + Tab, }; using Setter = std::function; @@ -170,14 +171,12 @@ class QTCREATOR_UTILS_EXPORT Splitter : public LayoutItem { public: Splitter(std::initializer_list items); - Splitter(QSplitter *splitter, std::initializer_list items); }; class QTCREATOR_UTILS_EXPORT TabWidget : public LayoutItem { public: - TabWidget(std::initializer_list tabs); - TabWidget(QTabWidget *tabWidget, std::initializer_list tabs); + TabWidget(std::initializer_list items); }; // Singleton items. @@ -189,10 +188,13 @@ QTCREATOR_UTILS_EXPORT extern HorizontalRule hr; // "Properties" -QTCREATOR_UTILS_EXPORT LayoutItem::Setter title(const QString &title); -QTCREATOR_UTILS_EXPORT LayoutItem::Setter text(const QString &text); -QTCREATOR_UTILS_EXPORT LayoutItem::Setter tooltip(const QString &toolTip); -QTCREATOR_UTILS_EXPORT LayoutItem::Setter onClicked(const std::function &func, +QTCREATOR_UTILS_EXPORT LayoutItem bindTo(QTabWidget **); +QTCREATOR_UTILS_EXPORT LayoutItem bindTo(QSplitter **); + +QTCREATOR_UTILS_EXPORT LayoutItem title(const QString &title); +QTCREATOR_UTILS_EXPORT LayoutItem text(const QString &text); +QTCREATOR_UTILS_EXPORT LayoutItem tooltip(const QString &toolTip); +QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &func, QObject *guard = nullptr); diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp index 9d5137b9389..7c4d2c845dd 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp @@ -1429,7 +1429,9 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) m_workingCopyView->setModel(m_proxyWorkingCopyModel); using namespace Layouting; - m_projectPartTab = qobject_cast(TabWidget{ + + TabWidget projectPart { + bindTo(&m_projectPartTab), Tab("&General", Row { m_partGeneralView, @@ -1454,10 +1456,10 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) ), Tab("&Header Paths", Column{ projectHeaderPathsView }), Tab("Pre&compiled Headers", Column{ m_partPrecompiledHeadersEdit }), - }.widget); - QTC_CHECK(m_projectPartTab); + }; - m_docTab = qobject_cast(TabWidget{ + TabWidget docTab { + bindTo(&m_docTab), Tab("&General", Column { m_docGeneralView }), Tab("&Includes", Column { m_docIncludesView }), Tab("&Diagnostic Messages", Column { m_docDiagnosticMessagesView }), @@ -1465,8 +1467,7 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) Tab("P&reprocessed Source", Column { m_docPreprocessedSourceEdit }), Tab("&Symbols", Column { m_docSymbolsView }), Tab("&Tokens", Column { m_docTokensView }), - }.widget); - QTC_CHECK(m_docTab); + }; Column { TabWidget { @@ -1474,7 +1475,7 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) Column { Splitter { m_projectPartsView, - m_projectPartTab, + projectPart, }, } ), @@ -1485,7 +1486,7 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) Form { QString("Sn&apshot:"), m_snapshotSelector }, m_snapshotView, }.emerge(Layouting::WithoutMargins), - m_docTab, + docTab, }, } ), @@ -1506,6 +1507,7 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) } }.attachTo(this); + QTC_CHECK(m_projectPartTab); m_projectPartTab->setCurrentIndex(3); connect(m_snapshotView->selectionModel(), diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index 190c2f5fc4c..72308ed4caa 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -162,11 +162,8 @@ public: , m_bindStarToLeftSpecifier(createCheckBox(Tr::tr("Left const/volatile"))) , m_bindStarToRightSpecifier(createCheckBox(Tr::tr("Right const/volatile"), Tr::tr("This does not apply to references."))) - , m_categoryTab(new QTabWidget) , m_tabSettingsWidget(new TabSettingsWidget) { - m_categoryTab->setProperty("_q_custom_style_disabled", true); - QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); @@ -234,7 +231,8 @@ public: }; Row { - TabWidget { m_categoryTab, { + TabWidget { + bindTo(&m_categoryTab), Tab { Tr::tr("General"), Row { Column { m_tabSettingsWidget, st }, createPreview(0) } }, @@ -243,9 +241,11 @@ public: Tab { Tr::tr("\"switch\""), Row { switchGroup, createPreview(3) } }, Tab { Tr::tr("Alignment"), Row { alignmentGroup, createPreview(4) } }, Tab { Tr::tr("Pointers and References"), Row { typesGroup, createPreview(5) } } - } } + } }.attachTo(q); + m_categoryTab->setProperty("_q_custom_style_disabled", true); + m_controllers.append(m_tabSettingsWidget); m_controllers.append(contentGroup.widget); m_controllers.append(bracesGroup.widget); From bdabb6881066c9f40e5b8b3ba97b1847ab2d3db4 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 2 May 2023 12:21:43 +0200 Subject: [PATCH 0768/1447] Examples: Adapt line color between title and tags to category hr color "Welcome_ForegroundSecondaryColor" is less likely to burn a permanent, straight line into user's retina. Change-Id: Ie6c6f02d8b53c340b322945f0d735177f22ddd56 Reviewed-by: Christian Stenger --- src/plugins/coreplugin/welcomepagehelper.cpp | 5 +++-- src/plugins/coreplugin/welcomepagehelper.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index efcf74070ae..77ef96e9be0 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -446,6 +446,7 @@ ListItemDelegate::ListItemDelegate() : backgroundPrimaryColor(themeColor(Theme::Welcome_BackgroundPrimaryColor)) , backgroundSecondaryColor(themeColor(Theme::Welcome_BackgroundSecondaryColor)) , foregroundPrimaryColor(themeColor(Theme::Welcome_ForegroundPrimaryColor)) + , foregroundSecondaryColor(themeColor(Theme::Welcome_ForegroundSecondaryColor)) , hoverColor(themeColor(Theme::Welcome_HoverColor)) , textColor(themeColor(Theme::Welcome_TextColor)) { @@ -567,7 +568,7 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti // The separator line below the example title. const int ll = nameRect.height() + 3; const QLine line = QLine(0, ll, textArea.width(), ll).translated(shiftedTextRect.topLeft()); - painter->setPen(foregroundPrimaryColor); + painter->setPen(foregroundSecondaryColor); painter->setOpacity(animationProgress); // "fade in" separator line and description painter->drawLine(line); @@ -586,7 +587,7 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti } // Separator line between text and 'Tags:' section - painter->setPen(foregroundPrimaryColor); + painter->setPen(foregroundSecondaryColor); painter->drawLine(QLineF(textArea.topLeft(), textArea.topRight()) .translated(0, TagsSeparatorY)); diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 9baa341011d..641ce5983dd 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -165,6 +165,7 @@ protected: const QColor backgroundPrimaryColor; const QColor backgroundSecondaryColor; const QColor foregroundPrimaryColor; + const QColor foregroundSecondaryColor; const QColor hoverColor; const QColor textColor; From a548587a0bedac88ec3944ada0e5efcd2ac4a585 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 1 May 2023 10:21:29 +0300 Subject: [PATCH 0769/1447] QbsPM: Fix clang detection in toolchainList We should only care about the file name. If the file's directory contains "clang", the compiler is not necessarily clang. Reported by hjk. Change-Id: I079c59eca37a9dbaa2ef5d669aee8e185db528f9 Reviewed-by: hjk Reviewed-by: Christian Kandeler --- src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index d64ecc47e7e..e2d1ae9ee7b 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -107,7 +107,7 @@ static QStringList toolchainList(const ProjectExplorer::ToolChain *tc) const Utils::Id type = tc->typeId(); if (type == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID || (type == Android::Constants::ANDROID_TOOLCHAIN_TYPEID - && tc->compilerCommand().toString().contains("clang"))) { + && tc->compilerCommand().fileName().contains("clang"))) { return {"clang", "llvm", "gcc"}; } if (type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID From e2f83c74f4d25e7850f333723e6279a98cfd18c7 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 2 May 2023 15:38:45 +0200 Subject: [PATCH 0770/1447] Revert "CMakePM: Fix compile for gcc 7" This reverts commit ca04d9afcdea1f22580d2999ca4e6657d60979d8. GCC 9 or later is the minimum required version nowadays, so this piece of code can be more readable. Change-Id: I939ee6cd62572d23d5b1de8d113472136752a590 Reviewed-by: Orgad Shaneh Reviewed-by: Qt CI Bot --- .../cmakeprojectimporter.cpp | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index dc752f0a9f9..03cd3c6b0eb 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -284,36 +284,35 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config) if (!cmakeListTxt.open(QIODevice::WriteOnly)) { return FilePath(); } - // FIXME replace by raw string when gcc 8+ is minimum - cmakeListTxt.write(QByteArray( -"cmake_minimum_required(VERSION 3.15)\n" -"\n" -"project(qmake-probe LANGUAGES NONE)\n" -"\n" -"# Bypass Qt6's usage of find_dependency, which would require compiler\n" -"# and source code probing, which slows things unnecessarily\n" -"file(WRITE \"${CMAKE_SOURCE_DIR}/CMakeFindDependencyMacro.cmake\"\n" -"[=[" -" macro(find_dependency dep)\n" -" endmacro()\n" -"]=])\n" -"set(CMAKE_MODULE_PATH \"${CMAKE_SOURCE_DIR}\")\n" -"\n" -"find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)\n" -"find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)\n" -"\n" -"if (CMAKE_CROSSCOMPILING)\n" -" find_program(qmake_binary\n" -" NAMES qmake qmake.bat\n" -" PATHS \"${Qt${QT_VERSION_MAJOR}_DIR}/../../../bin\"\n" -" NO_DEFAULT_PATH)\n" -" file(WRITE \"${CMAKE_SOURCE_DIR}/qmake-location.txt\" \"${qmake_binary}\")\n" -"else()\n" -" file(GENERATE\n" -" OUTPUT \"${CMAKE_SOURCE_DIR}/qmake-location.txt\"\n" -" CONTENT \"$\")\n" -"endif()\n" -)); + cmakeListTxt.write(QByteArray(R"( + cmake_minimum_required(VERSION 3.15) + + project(qmake-probe LANGUAGES NONE) + + # Bypass Qt6's usage of find_dependency, which would require compiler + # and source code probing, which slows things unnecessarily + file(WRITE "${CMAKE_SOURCE_DIR}/CMakeFindDependencyMacro.cmake" + [=[ + macro(find_dependency dep) + endmacro() + ]=]) + set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}") + + find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) + + if (CMAKE_CROSSCOMPILING) + find_program(qmake_binary + NAMES qmake qmake.bat + PATHS "${Qt${QT_VERSION_MAJOR}_DIR}/../../../bin" + NO_DEFAULT_PATH) + file(WRITE "${CMAKE_SOURCE_DIR}/qmake-location.txt" "${qmake_binary}") + else() + file(GENERATE + OUTPUT "${CMAKE_SOURCE_DIR}/qmake-location.txt" + CONTENT "$") + endif() + )")); cmakeListTxt.close(); QtcProcess cmake; From 5c2b2966e78129dcbd220e35e15f6278a1b3d05d Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 27 Apr 2023 14:50:13 +0200 Subject: [PATCH 0771/1447] CMakePM: Enable "Add Existing Directory" This works via "addFiles" and it's supported. Change-Id: I18d193878c9549581a77d74fd8eb9761c4b08271 Reviewed-by: Reviewed-by: hjk --- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index c49dc50a770..d3bfcd720bc 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -202,7 +202,8 @@ bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const { if (dynamic_cast(context)) return action == ProjectAction::AddNewFile || action == ProjectAction::AddExistingFile - || action == ProjectAction::Rename || action == ProjectAction::RemoveFile; + || action == ProjectAction::AddExistingDirectory || action == ProjectAction::Rename + || action == ProjectAction::RemoveFile; return BuildSystem::supportsAction(context, action, node); } From 874b1133d9cfaef179851aa925b7d6b96e85019b Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 26 Apr 2023 19:29:37 +0200 Subject: [PATCH 0772/1447] CMakePM: Allow file rename / remove via variables Lookup any variables found in the target definition function in order to find the source files. This works for something like this: set(SOURCE_FILES myfile.cpp) add_executable(myexe ${SOURCE_FILES}) Change-Id: I8a47ea64b4efa467074f03ed5e1d1d05b2b1bf00 Reviewed-by: Reviewed-by: hjk --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index d3bfcd720bc..a493062621c 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -422,6 +422,7 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q if (!filePathArgument.Value.empty()) { return ProjectFileArgumentPosition{filePathArgument, targetCMakeFile, fileName}; } else { + // Check if the filename is part of globbing variable result const auto globFunctions = std::get<0>( Utils::partition(cmakeListFile.Functions, [](const auto &f) { return f.LowerCaseName() == "file" && f.Arguments().size() > 2 @@ -440,11 +441,43 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q != cmListFileArgument::Comment; }); - if (haveGlobbing) + if (haveGlobbing) { return ProjectFileArgumentPosition{filePathArgument, targetCMakeFile, fileName, true}; + } + + // Check if the filename is part of a variable set by the user + const auto setFunctions = std::get<0>( + Utils::partition(cmakeListFile.Functions, [](const auto &f) { + return f.LowerCaseName() == "set" && f.Arguments().size() > 1; + })); + + for (const auto &arg : func->Arguments()) { + if (arg.Delim == cmListFileArgument::Comment) + continue; + + auto matchedFunctions = Utils::filtered(setFunctions, [arg](const auto &f) { + return arg.Value == std::string("${") + f.Arguments()[0].Value + "}"; + }); + + for (const auto &f : matchedFunctions) { + filePathArgument + = Utils::findOrDefault(f.Arguments(), + [file_name = fileName.toStdString()]( + const auto &arg) { + return arg.Delim != cmListFileArgument::Comment + && arg.Value == file_name; + }); + + if (!filePathArgument.Value.empty()) { + return ProjectFileArgumentPosition{filePathArgument, + targetCMakeFile, + fileName}; + } + } + } } } From 7be8bd07b2d02c93ad9428abe32960c571f35e06 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 2 May 2023 17:02:26 +0200 Subject: [PATCH 0773/1447] Core: Don't change height of FancyToolButton for target chooser A freshly started Qt Creator showed a smaller target chooser button until a project was loaded. When loading a new project, the button changed its height which caused a noticeable jumping of the layout in the FancyActionBar. After closing the project the higher height remained. This change has the effect that the button has the final height right from the start of Qt Creator and that the jumping disappears. Change-Id: I6c9ac57c661398ba03d0b31269f62db28672ec91 Reviewed-by: Marcus Tillmanns Reviewed-by: Christian Stenger --- src/plugins/coreplugin/fancyactionbar.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/plugins/coreplugin/fancyactionbar.cpp b/src/plugins/coreplugin/fancyactionbar.cpp index 55904bf149b..a07dd718976 100644 --- a/src/plugins/coreplugin/fancyactionbar.cpp +++ b/src/plugins/coreplugin/fancyactionbar.cpp @@ -192,10 +192,7 @@ void FancyToolButton::paintEvent(QPaintEvent *event) const int textFlags = Qt::AlignVCenter | Qt::AlignHCenter; const QString projectName = defaultAction()->property("heading").toString(); - if (!projectName.isNull()) - centerRect.adjust(0, lineHeight + 4, 0, 0); - - centerRect.adjust(0, 0, 0, -lineHeight * 2 - 4); + centerRect.adjust(0, lineHeight + 4, 0, -lineHeight * 2 - 4); iconRect.moveCenter(centerRect.center()); StyleHelper::drawIconWithShadow(icon(), iconRect, &painter, iconMode); @@ -294,12 +291,12 @@ QSize FancyToolButton::sizeHint() const boldFont.setBold(true); const QFontMetrics fm(boldFont); const qreal lineHeight = fm.height(); - const QString projectName = defaultAction()->property("heading").toString(); - buttonSize += QSizeF(0, 10); - if (!projectName.isEmpty()) - buttonSize += QSizeF(0, lineHeight + 2); - - buttonSize += QSizeF(0, lineHeight * 2 + 2); + const int extraHeight = 10 // Spacing between top and projectName + + lineHeight // projectName height + + 2 // Spacing between projectName and icon + + lineHeight * 2 // configurationName height (2 lines) + + 2; // Spacing between configurationName and bottom + buttonSize.rheight() += extraHeight; } return buttonSize.toSize(); } From 5c414c1043e7a81fb79e75a898bf8da20a1c2836 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 18 Apr 2023 21:35:54 +0200 Subject: [PATCH 0774/1447] JavaScriptFilter: Reimplement matchers() Add JavaScriptRequest class that runs evaluation for a given input data and for a given JavaScriptEngine. The JavaScriptFilter holds the running JavaScriptEngine instance. Features: - It creates, destroys and runs evaluation of QJSEngine always in one, separate thread. - In case of a busy run of evaluator (e.g. because an input data contains a script with an endless loop) it's possible now to cancel the task before the timeout came. Useful when typing fast inside locator widget. Add also the JavaScriptRequestTask to be included in TaskTree. Change-Id: I866069c72bad17ab899f4aca9a3f6d928738f3a3 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../coreplugin/locator/javascriptfilter.cpp | 415 +++++++++++++++++- .../coreplugin/locator/javascriptfilter.h | 4 + 2 files changed, 418 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 5104ee81394..e05e4b0a968 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -5,9 +5,351 @@ #include "../coreplugintr.h" +#include + +#include +#include + #include #include #include +#include +#include +#include + +#include + +using namespace Core; +using namespace Core::Internal; +using namespace Utils; + +using namespace std::chrono_literals; + +static const char s_initData[] = R"( + function abs(x) { return Math.abs(x); } + function acos(x) { return Math.acos(x); } + function asin(x) { return Math.asin(x); } + function atan(x) { return Math.atan(x); } + function atan2(x, y) { return Math.atan2(x, y); } + function bin(x) { return '0b' + x.toString(2); } + function ceil(x) { return Math.ceil(x); } + function cos(x) { return Math.cos(x); } + function exp(x) { return Math.exp(x); } + function e() { return Math.E; } + function floor(x) { return Math.floor(x); } + function hex(x) { return '0x' + x.toString(16); } + function log(x) { return Math.log(x); } + function max() { return Math.max.apply(null, arguments); } + function min() { return Math.min.apply(null, arguments); } + function oct(x) { return '0' + x.toString(8); } + function pi() { return Math.PI; } + function pow(x, y) { return Math.pow(x, y); } + function random() { return Math.random(); } + function round(x) { return Math.round(x); } + function sin(x) { return Math.sin(x); } + function sqrt(x) { return Math.sqrt(x); } + function tan(x) { return Math.tan(x); } +)"; + +enum class JavaScriptResult { + FinishedWithSuccess, + FinishedWithError, + TimedOut, + Canceled +}; + +class JavaScriptOutput +{ +public: + QString m_output; + JavaScriptResult m_result = JavaScriptResult::Canceled; +}; + +using JavaScriptCallback = std::function; + +class JavaScriptInput +{ +public: + bool m_reset = false; // Recreates the QJSEngine, re-inits it and continues the request queue + QString m_input; + JavaScriptCallback m_callback = {}; +}; + +class JavaScriptThread : public QObject +{ + Q_OBJECT + +public: + // Called from the other thread, scheduled from the main thread through the queued + // invocation. + void run(); + + // Called from main thread exclusively + void cancel(); + // Called from main thread exclusively + int addRequest(const JavaScriptInput &input); + // Called from main thread exclusively + void removeRequest(int id); + + // Called from the main thread exclusively, scheduled from the other thread through the queued + // invocation when the new result is ready. + void flush(); + +signals: + void newOutput(); + +private: + struct QueueItem { + int m_id = 0; + JavaScriptInput m_input; + std::optional m_output = {}; + }; + + // Called from the main thread exclusively + QList takeOutputQueue() { + QMutexLocker locker(&m_mutex); + return std::exchange(m_outputQueue, {}); + } + + int m_maxId = 0; + std::unique_ptr m_engine; + + mutable QMutex m_mutex; + QWaitCondition m_waitCondition; + bool m_canceled = false; + QList m_inputQueue; + std::optional m_currentItem; + QList m_outputQueue; +}; + +void JavaScriptThread::run() +{ + const auto evaluate = [this](const QString &input) { + const QJSValue result = m_engine->evaluate(input); + if (m_engine->isInterrupted()) { + return JavaScriptOutput{Tr::tr("The evaluation was interrupted."), + JavaScriptResult::Canceled}; + } + return JavaScriptOutput{result.toString(), + result.isError() ? JavaScriptResult::FinishedWithError + : JavaScriptResult::FinishedWithSuccess}; + }; + const auto reset = [evaluate] { + JavaScriptOutput output = evaluate(s_initData); + output.m_output = output.m_result == JavaScriptResult::FinishedWithSuccess + ? Tr::tr("Engine reinitialized properly.") + : Tr::tr("Engine did not reinitialize properly."); + return output; + }; + + { + QMutexLocker locker(&m_mutex); + if (m_canceled) + return; + m_engine.reset(new QJSEngine); + } + + // TODO: consider placing a reset request as the first input instead + const JavaScriptOutput output = reset(); + QTC_ASSERT(output.m_result == JavaScriptResult::FinishedWithSuccess, + qWarning() << output.m_output); + + QueueItem currentItem; + while (true) { + { + QMutexLocker locker(&m_mutex); + if (m_canceled) + return; + if (m_currentItem) { + QTC_CHECK(m_currentItem->m_id == currentItem.m_id); + m_outputQueue.append(currentItem); + m_currentItem = {}; + emit newOutput(); + } + while (m_inputQueue.isEmpty()) { + m_waitCondition.wait(&m_mutex); + if (m_canceled) + return; + } + m_currentItem = currentItem = m_inputQueue.takeFirst(); + if (currentItem.m_input.m_reset) + m_engine.reset(new QJSEngine); + m_engine->setInterrupted(false); + } + const JavaScriptInput &input = currentItem.m_input; + if (input.m_reset) { + currentItem.m_output = reset(); + QTC_ASSERT(currentItem.m_output->m_result == JavaScriptResult::FinishedWithSuccess, + qWarning() << currentItem.m_output->m_output); + continue; + } + currentItem.m_output = evaluate(input.m_input); + } +} + +void JavaScriptThread::cancel() +{ + QMutexLocker locker(&m_mutex); + m_canceled = true; + if (m_engine) // we may be canceling before the run() started + m_engine->setInterrupted(true); + m_waitCondition.wakeOne(); +} + +int JavaScriptThread::addRequest(const JavaScriptInput &input) +{ + QMutexLocker locker(&m_mutex); + if (input.m_reset) { + if (m_currentItem) { + m_outputQueue += *m_currentItem; + m_engine->setInterrupted(true); + } + m_outputQueue += m_inputQueue; + m_currentItem = {}; + m_inputQueue.clear(); + for (int i = 0; i < m_outputQueue.size(); ++i) + m_outputQueue[i].m_output = {{}, JavaScriptResult::Canceled}; + QMetaObject::invokeMethod(this, &JavaScriptThread::newOutput, Qt::QueuedConnection); + } + m_inputQueue.append({++m_maxId, input}); + m_waitCondition.wakeOne(); + return m_maxId; +} + +void JavaScriptThread::removeRequest(int id) +{ + QMutexLocker locker(&m_mutex); + if (m_currentItem && m_currentItem->m_id == id) { + m_currentItem = {}; + m_engine->setInterrupted(true); + m_waitCondition.wakeOne(); + return; + } + const auto predicate = [id](const QueueItem &item) { return item.m_id == id; }; + if (Utils::eraseOne(m_inputQueue, predicate)) + return; + Utils::eraseOne(m_outputQueue, predicate); +} + +void JavaScriptThread::flush() +{ + const QList outputQueue = takeOutputQueue(); + for (const QueueItem &item : outputQueue) { + if (item.m_input.m_callback) + item.m_input.m_callback(*item.m_output); + } +} + +class JavaScriptEngine : public QObject +{ + Q_OBJECT + +public: + JavaScriptEngine() : m_javaScriptThread(new JavaScriptThread) { + connect(m_javaScriptThread, &JavaScriptThread::newOutput, this, [this] { + m_javaScriptThread->flush(); + }); + m_javaScriptThread->moveToThread(&m_thread); + QObject::connect(&m_thread, &QThread::finished, m_javaScriptThread, &QObject::deleteLater); + m_thread.start(); + QMetaObject::invokeMethod(m_javaScriptThread, &JavaScriptThread::run); + } + ~JavaScriptEngine() { + m_javaScriptThread->cancel(); + m_thread.quit(); + m_thread.wait(); + } + + int addRequest(const JavaScriptInput &input) { return m_javaScriptThread->addRequest(input); } + void removeRequest(int id) { m_javaScriptThread->removeRequest(id); } + +private: + QThread m_thread; + JavaScriptThread *m_javaScriptThread = nullptr; +}; + +class JavaScriptRequest : public QObject +{ + Q_OBJECT + +public: + virtual ~JavaScriptRequest() + { + if (m_engine && m_id) // In order to not to invoke a response callback anymore + m_engine->removeRequest(*m_id); + } + + void setEngine(JavaScriptEngine *engine) { + QTC_ASSERT(!isRunning(), return); + m_engine = engine; + } + void setReset(bool reset) { + QTC_ASSERT(!isRunning(), return); + m_input.m_reset = reset; // Reply: "Engine has been reset"? + } + void setEvaluateData(const QString &input) { + QTC_ASSERT(!isRunning(), return); + m_input.m_input = input; + } + void setTimeout(std::chrono::milliseconds timeout) { + QTC_ASSERT(!isRunning(), return); + m_timeout = timeout; + } + + void start() { + QTC_ASSERT(!isRunning(), return); + QTC_ASSERT(m_engine, return); + + JavaScriptInput input = m_input; + input.m_callback = [this](const JavaScriptOutput &output) { + m_timer.reset(); + m_output = output; + m_id = {}; + emit done(output.m_result == JavaScriptResult::FinishedWithSuccess); + }; + m_id = m_engine->addRequest(input); + if (m_timeout > 0ms) { + m_timer.reset(new QTimer); + m_timer->setSingleShot(true); + m_timer->setInterval(m_timeout); + connect(m_timer.get(), &QTimer::timeout, this, [this] { + if (m_engine && m_id) + m_engine->removeRequest(*m_id); + m_timer.release()->deleteLater(); + m_id = {}; + m_output = {Tr::tr("Engine aborted after timeout."), JavaScriptResult::Canceled}; + emit done(false); + }); + m_timer->start(); + } + } + + bool isRunning() const { return m_id.has_value(); } + JavaScriptOutput output() const { return m_output; } + +signals: + void done(bool success); + +private: + QPointer m_engine; + JavaScriptInput m_input; + std::chrono::milliseconds m_timeout = 1000ms; + + std::unique_ptr m_timer; + + std::optional m_id; + JavaScriptOutput m_output; +}; + +class JavaScriptRequestAdapter : public Tasking::TaskAdapter +{ +public: + JavaScriptRequestAdapter() { connect(task(), &JavaScriptRequest::done, + this, &TaskInterface::done); } + void start() final { task()->start(); } +}; + +QTC_DECLARE_CUSTOM_TASK(JavaScriptRequestTask, JavaScriptRequestAdapter); namespace Core { namespace Internal { @@ -28,10 +370,79 @@ JavaScriptFilter::JavaScriptFilter() }); } -JavaScriptFilter::~JavaScriptFilter() +LocatorMatcherTasks JavaScriptFilter::matchers() { + using namespace Tasking; + + TreeStorage storage; + if (!m_javaScriptEngine) + m_javaScriptEngine.reset(new JavaScriptEngine); + QPointer engine = m_javaScriptEngine.get(); + + const auto onGroupSetup = [storage, engine] { + if (!engine) + return TaskAction::StopWithError; + if (storage->input().trimmed().isEmpty()) { + LocatorFilterEntry entry; + entry.displayName = Tr::tr("Reset Engine"); + entry.acceptor = [engine] { + if (engine) { + JavaScriptInput request; + request.m_reset = true; + engine->addRequest(request); // TODO: timeout not handled + } + return AcceptResult(); + }; + storage->reportOutput({entry}); + return TaskAction::StopWithDone; + } + return TaskAction::Continue; + }; + + const auto onSetup = [storage, engine](JavaScriptRequest &request) { + request.setEngine(engine); + request.setEvaluateData(storage->input()); + }; + const auto onDone = [storage](const JavaScriptRequest &request) { + const auto acceptor = [](const QString &clipboardContents) { + return [clipboardContents] { + QGuiApplication::clipboard()->setText(clipboardContents); + return AcceptResult(); + }; + }; + const QString input = storage->input(); + const QString result = request.output().m_output; + const QString expression = input + " = " + result; + + LocatorFilterEntry entry; + entry.displayName = expression; + + LocatorFilterEntry copyResultEntry; + copyResultEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(result); + copyResultEntry.acceptor = acceptor(result); + + LocatorFilterEntry copyExpressionEntry; + copyExpressionEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(expression); + copyExpressionEntry.acceptor = acceptor(expression); + + storage->reportOutput({entry, copyResultEntry, copyExpressionEntry}); + }; + const auto onError = [storage](const JavaScriptRequest &request) { + LocatorFilterEntry entry; + entry.displayName = request.output().m_output; + storage->reportOutput({entry}); + }; + + const Group root { + OnGroupSetup(onGroupSetup), + JavaScriptRequestTask(onSetup, onDone, onError) + }; + + return {{root, storage}}; } +JavaScriptFilter::~JavaScriptFilter() = default; + void JavaScriptFilter::prepareSearch(const QString &entry) { Q_UNUSED(entry) @@ -126,3 +537,5 @@ void JavaScriptFilter::setupEngine() } // namespace Internal } // namespace Core + +#include "javascriptfilter.moc" diff --git a/src/plugins/coreplugin/locator/javascriptfilter.h b/src/plugins/coreplugin/locator/javascriptfilter.h index b65abf53439..e2508c70483 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.h +++ b/src/plugins/coreplugin/locator/javascriptfilter.h @@ -14,6 +14,8 @@ QT_BEGIN_NAMESPACE class QJSEngine; QT_END_NAMESPACE +class JavaScriptEngine; + namespace Core { namespace Internal { @@ -28,11 +30,13 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; private: + LocatorMatcherTasks matchers() final; void setupEngine(); mutable std::unique_ptr m_engine; QTimer m_abortTimer; std::atomic_bool m_aborted = false; + std::unique_ptr m_javaScriptEngine; }; } // namespace Internal From 4b129df44f7a3bf77befc04895c1e5de00e5030a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 2 May 2023 14:01:49 +0200 Subject: [PATCH 0775/1447] TaskTree: Enable the fluent interface for Tasks Make it possible to use the default Task c'tor and add selected handlers with onSetup/Done/Error() methods. Change-Id: I94f5806f347931faa07cff0ade620a3d30777cfe Reviewed-by: hjk --- src/libs/utils/tasktree.cpp | 42 +++++++++++++++++++--- src/libs/utils/tasktree.h | 25 +++++++++++-- tests/auto/utils/tasktree/tst_tasktree.cpp | 29 +++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 5e87466c665..ee0982072be 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -109,8 +109,6 @@ void TaskItem::addChildren(const QList &children) case Type::TaskHandler: QTC_ASSERT(child.m_taskHandler.m_createHandler, qWarning("Task Create Handler can't be null, skipping..."); return); - QTC_ASSERT(child.m_taskHandler.m_setupHandler, - qWarning("Task Setup Handler can't be null, skipping..."); return); m_children.append(child); break; case Type::GroupHandler: @@ -139,6 +137,39 @@ void TaskItem::addChildren(const QList &children) } } +void TaskItem::setTaskSetupHandler(const TaskSetupHandler &handler) +{ + if (!handler) { + qWarning("Setting empty Setup Handler is no-op, skipping..."); + return; + } + if (m_taskHandler.m_setupHandler) + qWarning("Setup Handler redefinition, overriding..."); + m_taskHandler.m_setupHandler = handler; +} + +void TaskItem::setTaskDoneHandler(const TaskEndHandler &handler) +{ + if (!handler) { + qWarning("Setting empty Done Handler is no-op, skipping..."); + return; + } + if (m_taskHandler.m_doneHandler) + qWarning("Done Handler redefinition, overriding..."); + m_taskHandler.m_doneHandler = handler; +} + +void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler) +{ + if (!handler) { + qWarning("Setting empty Error Handler is no-op, skipping..."); + return; + } + if (m_taskHandler.m_errorHandler) + qWarning("Error Handler redefinition, overriding..."); + m_taskHandler.m_errorHandler = handler; +} + } // namespace Tasking using namespace Tasking; @@ -258,7 +289,7 @@ public: void stop(); void invokeEndHandler(bool success); bool isRunning() const { return m_task || m_container.isRunning(); } - bool isTask() const { return m_taskHandler.m_createHandler && m_taskHandler.m_setupHandler; } + bool isTask() const { return bool(m_taskHandler.m_createHandler); } int taskCount() const { return isTask() ? 1 : m_container.m_constData.m_taskCount; } TaskContainer *parentContainer() const { return m_container.m_constData.m_parentContainer; } @@ -582,8 +613,9 @@ TaskAction TaskNode::start() return m_container.start(); m_task.reset(m_taskHandler.m_createHandler()); - const TaskAction startAction = invokeHandler(parentContainer(), m_taskHandler.m_setupHandler, - *m_task.get()); + const TaskAction startAction = m_taskHandler.m_setupHandler + ? invokeHandler(parentContainer(), m_taskHandler.m_setupHandler, *m_task.get()) + : TaskAction::Continue; if (startAction != TaskAction::Continue) { m_container.m_constData.m_taskTreePrivate->advanceProgress(1); m_task.reset(); diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 9fdb1717b02..418feb797ec 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -128,9 +128,9 @@ public: struct TaskHandler { TaskCreateHandler m_createHandler; - TaskSetupHandler m_setupHandler; - TaskEndHandler m_doneHandler; - TaskEndHandler m_errorHandler; + TaskSetupHandler m_setupHandler = {}; + TaskEndHandler m_doneHandler = {}; + TaskEndHandler m_errorHandler = {}; }; struct GroupHandler { @@ -174,6 +174,10 @@ protected: , m_storageList{storage} {} void addChildren(const QList &children); + void setTaskSetupHandler(const TaskSetupHandler &handler); + void setTaskDoneHandler(const TaskEndHandler &handler); + void setTaskErrorHandler(const TaskEndHandler &handler); + private: Type m_type = Type::Group; int m_parallelLimit = 1; // 0 means unlimited @@ -301,11 +305,26 @@ public: using Task = typename Adapter::Type; using EndHandler = std::function; static Adapter *createAdapter() { return new Adapter; } + CustomTask() : TaskItem({&createAdapter}) {} template CustomTask(SetupFunction &&function, const EndHandler &done = {}, const EndHandler &error = {}) : TaskItem({&createAdapter, wrapSetup(std::forward(function)), wrapEnd(done), wrapEnd(error)}) {} + template + CustomTask &onSetup(SetupFunction &&function) { + setTaskSetupHandler(wrapSetup(std::forward(function))); + return *this; + } + CustomTask &onDone(const EndHandler &handler) { + setTaskDoneHandler(wrapEnd(handler)); + return *this; + } + CustomTask &onError(const EndHandler &handler) { + setTaskErrorHandler(wrapEnd(handler)); + return *this; + } + private: template static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) { diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 00ab33bb85e..5bf8dcc006e 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -120,6 +120,35 @@ void tst_TaskTree::validConstructs() OnGroupError([] {}) }; + const auto setupHandler = [](TestTask &) {}; + const auto doneHandler = [](const TestTask &) {}; + const auto errorHandler = [](const TestTask &) {}; + + // Not fluent interface + + const Group task2 { + parallel, + Test(setupHandler), + Test(setupHandler, doneHandler), + Test(setupHandler, doneHandler, errorHandler), + // need to explicitly pass empty handler for done + Test(setupHandler, {}, errorHandler) + }; + + // Fluent interface + + const Group fluent { + parallel, + Test().onSetup(setupHandler), + Test().onSetup(setupHandler).onDone(doneHandler), + Test().onSetup(setupHandler).onDone(doneHandler).onError(errorHandler), + // possible to skip the empty done + Test().onSetup(setupHandler).onError(errorHandler), + // possible to set handlers in a different order + Test().onError(errorHandler).onDone(doneHandler).onSetup(setupHandler), + }; + + // When turning each of below blocks on, you should see the specific compiler error message. #if 0 From d4f022be6a1ec05bca44d23f19140eec0626c36c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 17:58:58 +0200 Subject: [PATCH 0776/1447] LocatorWidget: Turn the new LocatorMatcher implementation on by default Change-Id: Id9dab7ff68a710a8406879ecf4658cfb09e8f76e Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/coreplugin/locator/locatorwidget.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 01ea7f5b6ab..c253ff726c3 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -54,7 +54,11 @@ const int LocatorEntryRole = int(HighlightingItemRole::User); namespace Core { namespace Internal { -static bool isUsingLocatorMatcher() { return qtcEnvironmentVariableIsSet("QTC_USE_MATCHER"); } +static bool isUsingLocatorMatcher() +{ + const QString value = qtcEnvironmentVariable("QTC_USE_MATCHER", "").toLower(); + return !(value == "false" || value == "off"); +} bool LocatorWidget::m_shuttingDown = false; QFuture LocatorWidget::m_sharedFuture; @@ -975,11 +979,13 @@ static void printMatcherInfo() static bool printed = false; if (printed) return; - if (isUsingLocatorMatcher()) - qDebug() << "QTC_USE_MATCHER env var set, using new LocatorMatcher implementation."; - else - qDebug() << "QTC_USE_MATCHER env var not set, using old matchesFor implementation."; printed = true; + if (isUsingLocatorMatcher()) { + qDebug() << "Using the new LocatorMatcher implementation (default). In order to switch " + "back to the old implementation, set QTC_USE_MATCHER=FALSE env var."; + return; + } + qDebug() << "QTC_USE_MATCHER env var set to FALSE, using the old matchesFor implementation."; } void LocatorWidget::updateCompletionList(const QString &text) From b5492953e2ce9def4f4bb876cbeff025efd75c01 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 09:29:50 +0200 Subject: [PATCH 0777/1447] Barrier: Fix the missing export Amends e46a4eba8dbe757903c10fd043bf03142836994a Change-Id: I72d451151796b342fe97375abb30f9ef433c897e Reviewed-by: Alessandro Portale --- src/libs/utils/barrier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/barrier.h b/src/libs/utils/barrier.h index f61b2ef2b85..52b44fd7031 100644 --- a/src/libs/utils/barrier.h +++ b/src/libs/utils/barrier.h @@ -70,7 +70,7 @@ using MultiBarrier = TreeStorage>; // alias template deduction only available with C++20. using SingleBarrier = MultiBarrier<1>; -class WaitForBarrier : public BarrierTask +class QTCREATOR_UTILS_EXPORT WaitForBarrier : public BarrierTask { public: template From f8012b7ac9f8d559019f84efcf8117391275374f Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:58:35 +0200 Subject: [PATCH 0778/1447] TextEditor: Use IOptionPage::setWidgetCreator() for behavior settings Change-Id: I24629e64b48c08b1321f0ebf3fca21e17a1f69a1 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- .../texteditor/behaviorsettingspage.cpp | 132 ++++++++---------- src/plugins/texteditor/behaviorsettingspage.h | 18 +-- 2 files changed, 59 insertions(+), 91 deletions(-) diff --git a/src/plugins/texteditor/behaviorsettingspage.cpp b/src/plugins/texteditor/behaviorsettingspage.cpp index 5d397458071..73675e2cdb9 100644 --- a/src/plugins/texteditor/behaviorsettingspage.cpp +++ b/src/plugins/texteditor/behaviorsettingspage.cpp @@ -10,6 +10,7 @@ #include "simplecodestylepreferences.h" #include "storagesettings.h" #include "tabsettings.h" +#include "tabsettingswidget.h" #include "texteditorconstants.h" #include "texteditorsettings.h" #include "texteditortr.h" @@ -35,12 +36,12 @@ namespace TextEditor { -struct BehaviorSettingsPage::BehaviorSettingsPagePrivate : public QObject +class BehaviorSettingsPagePrivate : public QObject { +public: BehaviorSettingsPagePrivate(); const QString m_settingsPrefix{"text"}; - QPointer m_widget; TextEditor::BehaviorSettingsWidget *m_behaviorWidget = nullptr; CodeStylePool *m_defaultCodeStylePool = nullptr; @@ -52,7 +53,7 @@ struct BehaviorSettingsPage::BehaviorSettingsPagePrivate : public QObject ExtraEncodingSettings m_extraEncodingSettings; }; -BehaviorSettingsPage::BehaviorSettingsPagePrivate::BehaviorSettingsPagePrivate() +BehaviorSettingsPagePrivate::BehaviorSettingsPagePrivate() { // global tab preferences for all other languages m_codeStyle = new SimpleCodeStylePreferences(this); @@ -71,6 +72,54 @@ BehaviorSettingsPage::BehaviorSettingsPagePrivate::BehaviorSettingsPagePrivate() m_extraEncodingSettings.fromSettings(m_settingsPrefix, s); } +class BehaviorSettingsWidgetImpl : public Core::IOptionsPageWidget +{ +public: + BehaviorSettingsWidgetImpl(BehaviorSettingsPagePrivate *d) : d(d) + { + d->m_behaviorWidget = new BehaviorSettingsWidget(this); + + auto verticalSpacer = new QSpacerItem(20, 13, QSizePolicy::Minimum, QSizePolicy::Expanding); + + auto gridLayout = new QGridLayout(this); + if (Utils::HostOsInfo::isMacHost()) + gridLayout->setContentsMargins(-1, 0, -1, 0); // don't ask. + gridLayout->addWidget(d->m_behaviorWidget, 0, 0, 1, 1); + gridLayout->addItem(verticalSpacer, 1, 0, 1, 1); + + d->m_pageCodeStyle = new SimpleCodeStylePreferences(this); + d->m_pageCodeStyle->setDelegatingPool(d->m_codeStyle->delegatingPool()); + d->m_pageCodeStyle->setTabSettings(d->m_codeStyle->tabSettings()); + d->m_pageCodeStyle->setCurrentDelegate(d->m_codeStyle->currentDelegate()); + d->m_behaviorWidget->setCodeStyle(d->m_pageCodeStyle); + + TabSettingsWidget *tabSettingsWidget = d->m_behaviorWidget->tabSettingsWidget(); + tabSettingsWidget->setCodingStyleWarningVisible(true); + connect(tabSettingsWidget, &TabSettingsWidget::codingStyleLinkClicked, + this, [] (TabSettingsWidget::CodingStyleLink link) { + switch (link) { + case TabSettingsWidget::CppLink: + Core::ICore::showOptionsDialog(CppEditor::Constants::CPP_CODE_STYLE_SETTINGS_ID); + break; + case TabSettingsWidget::QtQuickLink: + Core::ICore::showOptionsDialog(QmlJSTools::Constants::QML_JS_CODE_STYLE_SETTINGS_ID); + break; + } + }); + + d->m_behaviorWidget->setAssignedTypingSettings(d->m_typingSettings); + d->m_behaviorWidget->setAssignedStorageSettings(d->m_storageSettings); + d->m_behaviorWidget->setAssignedBehaviorSettings(d->m_behaviorSettings); + d->m_behaviorWidget->setAssignedExtraEncodingSettings(d->m_extraEncodingSettings); + d->m_behaviorWidget->setAssignedCodec(Core::EditorManager::defaultTextCodec()); + d->m_behaviorWidget->setAssignedLineEnding(Core::EditorManager::defaultLineEnding()); + } + + void apply() final; + + BehaviorSettingsPagePrivate *d; +}; + BehaviorSettingsPage::BehaviorSettingsPage() : d(new BehaviorSettingsPagePrivate) { @@ -81,6 +130,7 @@ BehaviorSettingsPage::BehaviorSettingsPage() setCategory(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr("Text Editor")); setCategoryIconPath(TextEditor::Constants::TEXT_EDITOR_SETTINGS_CATEGORY_ICON_PATH); + setWidgetCreator([this] { return new BehaviorSettingsWidgetImpl(d); }); } BehaviorSettingsPage::~BehaviorSettingsPage() @@ -88,37 +138,7 @@ BehaviorSettingsPage::~BehaviorSettingsPage() delete d; } -QWidget *BehaviorSettingsPage::widget() -{ - if (!d->m_widget) { - d->m_widget = new QWidget; - d->m_behaviorWidget = new BehaviorSettingsWidget(d->m_widget); - - auto verticalSpacer = new QSpacerItem(20, 13, QSizePolicy::Minimum, QSizePolicy::Expanding); - - auto gridLayout = new QGridLayout(d->m_widget); - if (Utils::HostOsInfo::isMacHost()) - gridLayout->setContentsMargins(-1, 0, -1, 0); // don't ask. - gridLayout->addWidget(d->m_behaviorWidget, 0, 0, 1, 1); - gridLayout->addItem(verticalSpacer, 1, 0, 1, 1); - - d->m_pageCodeStyle = new SimpleCodeStylePreferences(d->m_widget); - d->m_pageCodeStyle->setDelegatingPool(d->m_codeStyle->delegatingPool()); - d->m_pageCodeStyle->setTabSettings(d->m_codeStyle->tabSettings()); - d->m_pageCodeStyle->setCurrentDelegate(d->m_codeStyle->currentDelegate()); - d->m_behaviorWidget->setCodeStyle(d->m_pageCodeStyle); - - TabSettingsWidget *tabSettingsWidget = d->m_behaviorWidget->tabSettingsWidget(); - tabSettingsWidget->setCodingStyleWarningVisible(true); - connect(tabSettingsWidget, &TabSettingsWidget::codingStyleLinkClicked, - this, &BehaviorSettingsPage::openCodingStylePreferences); - - settingsToUI(); - } - return d->m_widget; -} - -void BehaviorSettingsPage::apply() +void BehaviorSettingsWidgetImpl::apply() { if (!d->m_behaviorWidget) // page was never shown return; @@ -128,8 +148,10 @@ void BehaviorSettingsPage::apply() BehaviorSettings newBehaviorSettings; ExtraEncodingSettings newExtraEncodingSettings; - settingsFromUI(&newTypingSettings, &newStorageSettings, - &newBehaviorSettings, &newExtraEncodingSettings); + d->m_behaviorWidget->assignedTypingSettings(&newTypingSettings); + d->m_behaviorWidget->assignedStorageSettings(&newStorageSettings); + d->m_behaviorWidget->assignedBehaviorSettings(&newBehaviorSettings); + d->m_behaviorWidget->assignedExtraEncodingSettings(&newExtraEncodingSettings); QSettings *s = Core::ICore::settings(); QTC_ASSERT(s, return); @@ -178,32 +200,6 @@ void BehaviorSettingsPage::apply() d->m_behaviorWidget->assignedLineEnding()); } -void BehaviorSettingsPage::settingsFromUI(TypingSettings *typingSettings, - StorageSettings *storageSettings, - BehaviorSettings *behaviorSettings, - ExtraEncodingSettings *extraEncodingSettings) const -{ - d->m_behaviorWidget->assignedTypingSettings(typingSettings); - d->m_behaviorWidget->assignedStorageSettings(storageSettings); - d->m_behaviorWidget->assignedBehaviorSettings(behaviorSettings); - d->m_behaviorWidget->assignedExtraEncodingSettings(extraEncodingSettings); -} - -void BehaviorSettingsPage::settingsToUI() -{ - d->m_behaviorWidget->setAssignedTypingSettings(d->m_typingSettings); - d->m_behaviorWidget->setAssignedStorageSettings(d->m_storageSettings); - d->m_behaviorWidget->setAssignedBehaviorSettings(d->m_behaviorSettings); - d->m_behaviorWidget->setAssignedExtraEncodingSettings(d->m_extraEncodingSettings); - d->m_behaviorWidget->setAssignedCodec(Core::EditorManager::defaultTextCodec()); - d->m_behaviorWidget->setAssignedLineEnding(Core::EditorManager::defaultLineEnding()); -} - -void BehaviorSettingsPage::finish() -{ - delete d->m_widget; -} - ICodeStylePreferences *BehaviorSettingsPage::codeStyle() const { return d->m_codeStyle; @@ -235,16 +231,4 @@ const ExtraEncodingSettings &BehaviorSettingsPage::extraEncodingSettings() const } -void BehaviorSettingsPage::openCodingStylePreferences(TabSettingsWidget::CodingStyleLink link) -{ - switch (link) { - case TabSettingsWidget::CppLink: - Core::ICore::showOptionsDialog(CppEditor::Constants::CPP_CODE_STYLE_SETTINGS_ID); - break; - case TabSettingsWidget::QtQuickLink: - Core::ICore::showOptionsDialog(QmlJSTools::Constants::QML_JS_CODE_STYLE_SETTINGS_ID); - break; - } -} - } // namespace TextEditor diff --git a/src/plugins/texteditor/behaviorsettingspage.h b/src/plugins/texteditor/behaviorsettingspage.h index 495a800d86f..048a865d5ff 100644 --- a/src/plugins/texteditor/behaviorsettingspage.h +++ b/src/plugins/texteditor/behaviorsettingspage.h @@ -5,8 +5,6 @@ #include "texteditor_global.h" -#include "tabsettingswidget.h" - #include QT_BEGIN_NAMESPACE @@ -31,11 +29,6 @@ public: BehaviorSettingsPage(); ~BehaviorSettingsPage() override; - // IOptionsPage - QWidget *widget() override; - void apply() override; - void finish() override; - ICodeStylePreferences *codeStyle() const; CodeStylePool *codeStylePool() const; const TypingSettings &typingSettings() const; @@ -44,17 +37,8 @@ public: const ExtraEncodingSettings &extraEncodingSettings() const; private: - void openCodingStylePreferences(TextEditor::TabSettingsWidget::CodingStyleLink link); - - void settingsFromUI(TypingSettings *typingSettings, - StorageSettings *storageSettings, - BehaviorSettings *behaviorSettings, - ExtraEncodingSettings *extraEncodingSettings) const; - void settingsToUI(); - QList m_codecs; - struct BehaviorSettingsPagePrivate; - BehaviorSettingsPagePrivate *d; + class BehaviorSettingsPagePrivate *d; }; } // namespace TextEditor From 4704dab394d0c9e2f31545b6b46fa8de92fd4f10 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 14:15:58 +0200 Subject: [PATCH 0779/1447] Core: Allow functors for apply and finish in IOptionsPageWidget Change-Id: Ibe9f1c3853497885510b9b2493d976812fbe2f93 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/coreplugin/dialogs/ioptionspage.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 300ecda4a08..8aa2ed66413 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -22,9 +22,19 @@ namespace Core { class CORE_EXPORT IOptionsPageWidget : public QWidget { Q_OBJECT + public: - virtual void apply() = 0; - virtual void finish() {} + void setOnApply(const std::function &func) { m_onApply = func; } + void setOnFinish(const std::function &func) { m_onFinish = func; } + +protected: + friend class IOptionsPage; + virtual void apply() { if (m_onApply) m_onApply(); } + virtual void finish() { if (m_onFinish) m_onFinish(); } + +private: + std::function m_onApply; + std::function m_onFinish; }; class CORE_EXPORT IOptionsPage : public QObject From 89b589c0ea8f886a246da004ba01d57219fceee4 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 26 Apr 2023 15:25:24 +0200 Subject: [PATCH 0780/1447] CppEditor: Add quickfix adding a member declaration from assignment Fixes: QTCREATORBUG-1918 Change-Id: I92c409ba0831edb056d23ae3244f5155876c039b Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/cppeditor/cppquickfix_test.cpp | 121 ++++++++- src/plugins/cppeditor/cppquickfix_test.h | 4 +- src/plugins/cppeditor/cppquickfixes.cpp | 297 ++++++++++++++++----- src/plugins/cppeditor/cppquickfixes.h | 14 + 4 files changed, 369 insertions(+), 67 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index badf896a5c9..e78667c2fb5 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -3780,7 +3780,7 @@ void QuickfixTest::testInsertQtPropertyMembers() QuickFixOperationTest({CppTestDocument::create("file.cpp", original, expected)}, &factory); } -void QuickfixTest::testInsertMemberFromInitialization_data() +void QuickfixTest::testInsertMemberFromUse_data() { QTest::addColumn("original"); QTest::addColumn("expected"); @@ -3852,9 +3852,125 @@ void QuickfixTest::testInsertMemberFromInitialization_data() " int m_x;\n" "};\n"; QTest::addRow("initialization via function call") << original << expected; + + original = + "struct S {\n\n};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.@value = v; }\n" + "private:\n" + " S m_s;\n" + "};\n"; + expected = + "struct S {\n\n" + " int value;\n" + "};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.value = v; }\n" + "private:\n" + " S m_s;\n" + "};\n"; + QTest::addRow("add member to other struct") << original << expected; + + original = + "struct S {\n\n};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { S::@value = v; }\n" + "};\n"; + expected = + "struct S {\n\n" + " static int value;\n" + "};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { S::value = v; }\n" + "};\n"; + QTest::addRow("add static member to other struct (explicit)") << original << expected; + + original = + "struct S {\n\n};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.@value = v; }\n" + "private:\n" + " static S m_s;\n" + "};\n"; + expected = + "struct S {\n\n" + " static int value;\n" + "};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.value = v; }\n" + "private:\n" + " static S m_s;\n" + "};\n"; + QTest::addRow("add static member to other struct (implicit)") << original << expected; + + original = + "class C {\n" + "public:\n" + " void setValue(int v);\n" + "};\n" + "void C::setValue(int v) { this->@m_value = v; }\n"; + expected = + "class C {\n" + "public:\n" + " void setValue(int v);\n" + "private:\n" + " int m_value;\n" + "};\n" + "void C::setValue(int v) { this->@m_value = v; }\n"; + QTest::addRow("add member to this (explicit)") << original << expected; + + original = + "class C {\n" + "public:\n" + " void setValue(int v) { @m_value = v; }\n" + "};\n"; + expected = + "class C {\n" + "public:\n" + " void setValue(int v) { m_value = v; }\n" + "private:\n" + " int m_value;\n" + "};\n"; + QTest::addRow("add member to this (implicit)") << original << expected; + + original = + "class C {\n" + "public:\n" + " static void setValue(int v) { @m_value = v; }\n" + "};\n"; + expected = + "class C {\n" + "public:\n" + " static void setValue(int v) { m_value = v; }\n" + "private:\n" + " static int m_value;\n" + "};\n"; + QTest::addRow("add static member to this (inline)") << original << expected; + + original = + "class C {\n" + "public:\n" + " static void setValue(int v);\n" + "};\n" + "void C::setValue(int v) { @m_value = v; }\n"; + expected = + "class C {\n" + "public:\n" + " static void setValue(int v);\n" + "private:\n" + " static int m_value;\n" + "};\n" + "void C::setValue(int v) { @m_value = v; }\n"; + QTest::addRow("add static member to this (non-inline)") << original << expected; } -void QuickfixTest::testInsertMemberFromInitialization() +void QuickfixTest::testInsertMemberFromUse() { QFETCH(QByteArray, original); QFETCH(QByteArray, expected); @@ -3864,6 +3980,7 @@ void QuickfixTest::testInsertMemberFromInitialization() }); AddDeclarationForUndeclaredIdentifier factory; + factory.setMembersOnly(); QuickFixOperationTest(testDocuments, &factory); } diff --git a/src/plugins/cppeditor/cppquickfix_test.h b/src/plugins/cppeditor/cppquickfix_test.h index 56cacb367ca..2d0dd0ebc9d 100644 --- a/src/plugins/cppeditor/cppquickfix_test.h +++ b/src/plugins/cppeditor/cppquickfix_test.h @@ -101,8 +101,8 @@ private slots: void testInsertQtPropertyMembers_data(); void testInsertQtPropertyMembers(); - void testInsertMemberFromInitialization_data(); - void testInsertMemberFromInitialization(); + void testInsertMemberFromUse_data(); + void testInsertMemberFromUse(); void testConvertQt4ConnectConnectOutOfClass(); void testConvertQt4ConnectConnectWithinClass_data(); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index e0671d6412f..2d56cb7ba4c 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -302,6 +302,35 @@ ClassSpecifierAST *astForClassOperations(const CppQuickFixInterface &interface) return nullptr; } +// Just the type name if varName is null, full declaration otherwise. +QString typeOfRhsExpr(const BinaryExpressionAST *binExpr, const SimpleNameAST *varName, + const Snapshot &snapshot, const Document::Ptr &doc, + const LookupContext &context, const CppRefactoringFilePtr &file) +{ + TypeOfExpression typeOfExpression; + typeOfExpression.init(doc, snapshot, context.bindings()); + Scope *scope = file->scopeAt(binExpr->firstToken()); + const QList result = typeOfExpression( + file->textOf(binExpr->right_expression).toUtf8(), scope, TypeOfExpression::Preprocess); + if (result.isEmpty()) + return {}; + + SubstitutionEnvironment env; + env.setContext(context); + env.switchScope(result.first().scope()); + ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); + if (!con) + con = typeOfExpression.context().globalNamespace(); + UseMinimalNames q(con); + env.enter(&q); + + Control *control = context.bindings()->control().data(); + FullySpecifiedType tn = rewriteType(result.first().type(), &env, control); + + return CppCodeStyleSettings::currentProjectCodeStyleOverview() + .prettyType(tn, varName ? varName->name : nullptr); +} + } // anonymous namespace namespace { @@ -1611,33 +1640,8 @@ private: if (currentFile->cppDocument()->languageFeatures().cxx11Enabled && settings->useAuto) return "auto " + oo.prettyName(simpleNameAST->name); - - TypeOfExpression typeOfExpression; - typeOfExpression.init(semanticInfo().doc, snapshot(), context().bindings()); - Scope *scope = currentFile->scopeAt(binaryAST->firstToken()); - const QList result = - typeOfExpression(currentFile->textOf(binaryAST->right_expression).toUtf8(), - scope, - TypeOfExpression::Preprocess); - - if (!result.isEmpty()) { - SubstitutionEnvironment env; - env.setContext(context()); - env.switchScope(result.first().scope()); - ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); - if (!con) - con = typeOfExpression.context().globalNamespace(); - UseMinimalNames q(con); - env.enter(&q); - - Control *control = context().bindings()->control().data(); - FullySpecifiedType tn = rewriteType(result.first().type(), &env, control); - - QString declaration = oo.prettyType(tn, simpleNameAST->name); - return declaration; - } - - return {}; + return typeOfRhsExpr(binaryAST, simpleNameAST, snapshot(), semanticInfo().doc, context(), + currentFile); } const BinaryExpressionAST *binaryAST; @@ -2902,8 +2906,10 @@ public: const CppQuickFixInterface &interface, const Class *theClass, const QString &member, - const QString &type) - : CppQuickFixOperation(interface), m_class(theClass), m_member(member), m_type(type) + const QString &type, + InsertionPointLocator::AccessSpec accessSpec) + : CppQuickFixOperation(interface), + m_class(theClass), m_member(member), m_type(type), m_accessSpec(accessSpec) { setDescription(Tr::tr("Add Class Member \"%1\"").arg(m_member)); } @@ -2926,7 +2932,7 @@ private: const InsertionPointLocator locator(refactoring); const FilePath filePath = FilePath::fromUtf8(m_class->fileName()); const InsertionLocation loc = locator.methodDeclarationInClass( - filePath, m_class, InsertionPointLocator::Private); + filePath, m_class, m_accessSpec); QTC_ASSERT(loc.isValid(), return); CppRefactoringFilePtr targetFile = refactoring.file(filePath); @@ -2942,44 +2948,127 @@ private: const Class * const m_class; const QString m_member; const QString m_type; + const InsertionPointLocator::AccessSpec m_accessSpec; }; void AddDeclarationForUndeclaredIdentifier::match(const CppQuickFixInterface &interface, - QuickFixOperations &result) + QuickFixOperations &result) { + // Are we on a name? + const QList &path = interface.path(); + if (path.isEmpty()) + return; + if (!path.last()->asSimpleName()) + return; + + // Special case: Member initializer. if (!checkForMemberInitializer(interface, result)) return; - const CppRefactoringFilePtr &file = interface.currentFile(); - const QList path = interface.path(); - for (int index = path.size() - 1; index != -1; --index) { - if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) { - if (binary->left_expression && binary->right_expression - && file->tokenAt(binary->binary_op_token).is(T_EQUAL)) { - IdExpressionAST *idExpr = binary->left_expression->asIdExpression(); - if (interface.isCursorOn(binary->left_expression) && idExpr - && idExpr->name->asSimpleName() != nullptr) { - SimpleNameAST *nameAST = idExpr->name->asSimpleName(); - const QList results = interface.context().lookup( - nameAST->name, file->scopeAt(nameAST->firstToken())); - Declaration *decl = nullptr; - for (const LookupItem &r : results) { - if (!r.declaration()) - continue; - if (Declaration *d = r.declaration()->asDeclaration()) { - if (!d->type()->asFunctionType()) { - decl = d; - break; - } - } - } + // Are we inside a function? + const FunctionDefinitionAST *func = nullptr; + for (auto it = path.rbegin(); !func && it != path.rend(); ++it) + func = (*it)->asFunctionDefinition(); + if (!func) + return; - if (!decl) { - result << new AddLocalDeclarationOp(interface, index, binary, nameAST); - return; - } - } + // Is this name declared somewhere already? + const CursorInEditor cursorInEditor(interface.cursor(), interface.filePath(), + interface.editor(), interface.editor()->textDocument()); + const auto followSymbolFallback = [&](const Link &link) { + if (!link.hasValidTarget()) + collectOperations(interface, result); + }; + CppModelManager::followSymbol(cursorInEditor, followSymbolFallback, false, false, + CppModelManager::Backend::Builtin); +} + +void AddDeclarationForUndeclaredIdentifier::collectOperations( + const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) +{ + const QList &path = interface.path(); + const CppRefactoringFilePtr &file = interface.currentFile(); + for (int index = path.size() - 1; index != -1; --index) { + // We only trigger if the identifier appears on the left-hand side of an + // assignment expression. + const auto binExpr = path.at(index)->asBinaryExpression(); + if (!binExpr) + continue; + if (!binExpr->left_expression || !binExpr->right_expression + || file->tokenAt(binExpr->binary_op_token).kind() != T_EQUAL + || !interface.isCursorOn(binExpr->left_expression)) { + return; + } + + const QString typeString = typeOfRhsExpr( + binExpr, nullptr, interface.snapshot(), + interface.semanticInfo().doc, interface.context(), interface.currentFile()); + + // In the case of "a.|b = c", find out the type of a, locate the class declaration + // and add a member b there. + if (const auto memberAccess = binExpr->left_expression->asMemberAccess()) { + if (interface.isCursorOn(memberAccess->member_name) + && memberAccess->member_name == path.last()) { + maybeAddMember(interface, file->scopeAt(memberAccess->firstToken()), + file->textOf(memberAccess->base_expression).toUtf8(), typeString, + result); } + return; + } + + const auto idExpr = binExpr->left_expression->asIdExpression(); + if (!idExpr || !idExpr->name) + return; + + // In the case of "A::|b = c", add a static member b to A. + if (const auto qualName = idExpr->name->asQualifiedName()) { + if (!interface.isCursorOn(qualName->unqualified_name)) + return; + if (qualName->unqualified_name != path.last()) + return; + if (!qualName->nested_name_specifier_list) + return; + + const NameAST * const topLevelName + = qualName->nested_name_specifier_list->value->class_or_namespace_name; + if (!topLevelName) + return; + ClassOrNamespace * const classOrNamespace = interface.context().lookupType( + topLevelName->name, file->scopeAt(qualName->firstToken())); + if (!classOrNamespace) + return; + QList otherNames; + for (auto it = qualName->nested_name_specifier_list->next; it; it = it->next) { + if (!it->value || !it->value->class_or_namespace_name) + return; + otherNames << it->value->class_or_namespace_name->name; + } + + const Class *theClass = nullptr; + if (!otherNames.isEmpty()) { + const Symbol * const symbol = classOrNamespace->lookupInScope(otherNames); + if (!symbol) + return; + theClass = symbol->asClass(); + } else { + theClass = classOrNamespace->rootClass(); + } + if (theClass) { + result << new InsertMemberFromInitializationOp( + interface, theClass, getIdentifier(interface), "static " + typeString, + InsertionPointLocator::Public); + } + return; + } + + // For an unqualified access, offer a local declaration and, if we are + // in a member function, a member declaration. + if (const auto simpleName = idExpr->name->asSimpleName()) { + if (!m_membersOnly) + result << new AddLocalDeclarationOp(interface, index, binExpr, simpleName); + maybeAddMember(interface, file->scopeAt(idExpr->firstToken()), "this", typeString, + result); + return; } } } @@ -2991,9 +3080,6 @@ bool AddDeclarationForUndeclaredIdentifier::checkForMemberInitializer( const int size = path.size(); if (size < 4) return true; - const SimpleNameAST * const name = path.at(size - 1)->asSimpleName(); - if (!name) - return true; const MemInitializerAST * const memInitializer = path.at(size - 2)->asMemInitializer(); if (!memInitializer) return true; @@ -3023,6 +3109,9 @@ bool AddDeclarationForUndeclaredIdentifier::checkForMemberInitializer( if (!theClass) return false; + const SimpleNameAST * const name = path.at(size - 1)->asSimpleName(); + QTC_ASSERT(name, return false); + // Check whether the member exists already. if (theClass->find(interface.currentFile()->cppDocument()->translationUnit()->identifier( name->identifier_token))) { @@ -3034,10 +3123,84 @@ bool AddDeclarationForUndeclaredIdentifier::checkForMemberInitializer( ->translationUnit()->identifier(name->identifier_token); const QString member = QString::fromUtf8(memberId->chars(), memberId->size()); - result << new InsertMemberFromInitializationOp(interface, theClass, member, type); + result << new InsertMemberFromInitializationOp(interface, theClass, member, type, + InsertionPointLocator::Private); return false; } +void AddDeclarationForUndeclaredIdentifier::maybeAddMember( + const CppQuickFixInterface &interface, Scope *scope, const QByteArray &classTypeExpr, + const QString &typeString, TextEditor::QuickFixOperations &result) +{ + const QList &path = interface.path(); + + TypeOfExpression typeOfExpression; + typeOfExpression.init(interface.semanticInfo().doc, interface.snapshot(), + interface.context().bindings()); + const QList lhsTypes = typeOfExpression( + classTypeExpr, scope, + TypeOfExpression::Preprocess); + if (lhsTypes.isEmpty()) + return; + + const Type *type = lhsTypes.first().type().type(); + if (!type) + return; + if (type->asPointerType()) { + type = type->asPointerType()->elementType().type(); + if (!type) + return; + } + const auto namedType = type->asNamedType(); + if (!namedType) + return; + const ClassOrNamespace * const classOrNamespace + = interface.context().lookupType(namedType->name(), scope); + if (!classOrNamespace || !classOrNamespace->rootClass()) + return; + + const Class * const theClass = classOrNamespace->rootClass(); + bool needsStatic = lhsTypes.first().type().isStatic(); + + // If the base expression refers to the same class that the member function is in, + // then we want to insert a private member, otherwise a public one. + const FunctionDefinitionAST *func = nullptr; + for (auto it = path.rbegin(); !func && it != path.rend(); ++it) + func = (*it)->asFunctionDefinition(); + QTC_ASSERT(func, return); + InsertionPointLocator::AccessSpec accessSpec = InsertionPointLocator::Public; + for (int i = 0; i < theClass->memberCount(); ++i) { + if (theClass->memberAt(i) == func->symbol) { + accessSpec = InsertionPointLocator::Private; + needsStatic = func->symbol->isStatic(); + break; + } + } + if (accessSpec == InsertionPointLocator::Public) { + QList decls; + QList dummy; + SymbolFinder().findMatchingDeclaration(interface.context(), func->symbol, &decls, + &dummy, &dummy); + for (const Declaration * const decl : std::as_const(decls)) { + for (int i = 0; i < theClass->memberCount(); ++i) { + if (theClass->memberAt(i) == decl) { + accessSpec = InsertionPointLocator::Private; + needsStatic = decl->isStatic(); + break; + } + } + if (accessSpec == InsertionPointLocator::Private) + break; + } + } + + QString fullType = typeString; + if (needsStatic) + fullType.prepend("static "); + result << new InsertMemberFromInitializationOp(interface, theClass, getIdentifier(interface), + fullType, accessSpec); +} + QString AddDeclarationForUndeclaredIdentifier::getType( const CppQuickFixInterface &interface, const MemInitializerAST *memInitializer, @@ -3076,6 +3239,14 @@ QString AddDeclarationForUndeclaredIdentifier::getType( return tpp(type); } +QString AddDeclarationForUndeclaredIdentifier::getIdentifier( + const CppQuickFixInterface &interface) const +{ + const Identifier * const memberId = interface.currentFile()->cppDocument()->translationUnit() + ->identifier(interface.path().last()->asSimpleName()->identifier_token); + return QString::fromUtf8(memberId->chars(), memberId->size()); +} + class MemberFunctionImplSetting { public: diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h index c6d4c8eb136..252a3bcc9e3 100644 --- a/src/plugins/cppeditor/cppquickfixes.h +++ b/src/plugins/cppeditor/cppquickfixes.h @@ -363,15 +363,29 @@ public: void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override; +#ifdef WITH_TESTS + void setMembersOnly() { m_membersOnly = true; } +#endif + private: + void collectOperations(const CppQuickFixInterface &interface, + TextEditor::QuickFixOperations &result); + // Returns whether to still do other checks. bool checkForMemberInitializer(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result); + void maybeAddMember(const CppQuickFixInterface &interface, CPlusPlus::Scope *scope, + const QByteArray &classTypeExpr, const QString &typeString, + TextEditor::QuickFixOperations &result); + QString getType( const CppQuickFixInterface &interface, const CPlusPlus::MemInitializerAST *memInitializer, const CPlusPlus::FunctionDefinitionAST *ctor) const; + QString getIdentifier(const CppQuickFixInterface &interface) const; + + bool m_membersOnly = false; }; /*! From e15b38494433a6f3e608f561517966ea0d745ddf Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 25 Apr 2023 11:22:56 +0200 Subject: [PATCH 0781/1447] TextEditor: Use icons with better contrast in TextMark tooltip The "_TOOLBAR" variants do not have a good contrast in some themes. This also introduces the missing non-toolbar variation for the EYE_OPEN icon. Fixes: QTCREATORBUG-29087 Change-Id: I64c8c6b7f5696d640c7bea7a431982caacd70050 Reviewed-by: David Schulz Reviewed-by: --- src/libs/utils/utilsicons.cpp | 2 ++ src/libs/utils/utilsicons.h | 1 + src/plugins/texteditor/textmark.cpp | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/utilsicons.cpp b/src/libs/utils/utilsicons.cpp index cbc2ddf64fb..01b1f0c1dbc 100644 --- a/src/libs/utils/utilsicons.cpp +++ b/src/libs/utils/utilsicons.cpp @@ -227,6 +227,8 @@ const Icon INTERRUPT_SMALL_TOOLBAR({ {":/utils/images/interrupt_small.png", Theme::IconsInterruptToolBarColor}}); const Icon BOUNDING_RECT({ {":/utils/images/boundingrect.png", Theme::IconsBaseColor}}); +const Icon EYE_OPEN({ + {":/utils/images/eye_open.png", Theme::PanelTextColorMid}}, Icon::Tint); const Icon EYE_OPEN_TOOLBAR({ {":/utils/images/eye_open.png", Theme::IconsBaseColor}}); const Icon EYE_CLOSED_TOOLBAR({ diff --git a/src/libs/utils/utilsicons.h b/src/libs/utils/utilsicons.h index 3e5009c94c2..5a75267a363 100644 --- a/src/libs/utils/utilsicons.h +++ b/src/libs/utils/utilsicons.h @@ -121,6 +121,7 @@ QTCREATOR_UTILS_EXPORT extern const Icon STOP_SMALL_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon INTERRUPT_SMALL; QTCREATOR_UTILS_EXPORT extern const Icon INTERRUPT_SMALL_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon BOUNDING_RECT; +QTCREATOR_UTILS_EXPORT extern const Icon EYE_OPEN; QTCREATOR_UTILS_EXPORT extern const Icon EYE_OPEN_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon EYE_CLOSED_TOOLBAR; QTCREATOR_UTILS_EXPORT extern const Icon REPLACE; diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index 2988de1d11e..4f86bc5f942 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -286,7 +286,7 @@ void TextMark::addToToolTipLayout(QGridLayout *target) const if (m_category.id.isValid() && !m_lineAnnotation.isEmpty()) { auto visibilityAction = new QAction; const bool isHidden = TextDocument::marksAnnotationHidden(m_category.id); - visibilityAction->setIcon(Utils::Icons::EYE_OPEN_TOOLBAR.icon()); + visibilityAction->setIcon(Utils::Icons::EYE_OPEN.icon()); const QString tooltip = (isHidden ? Tr::tr("Show inline annotations for %1") : Tr::tr("Temporarily hide inline annotations for %1")) .arg(m_category.displayName); @@ -302,7 +302,7 @@ void TextMark::addToToolTipLayout(QGridLayout *target) const } if (m_settingsPage.isValid()) { auto settingsAction = new QAction; - settingsAction->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon()); + settingsAction->setIcon(Utils::Icons::SETTINGS.icon()); settingsAction->setToolTip(Tr::tr("Show Diagnostic Settings")); QObject::connect(settingsAction, &QAction::triggered, Core::ICore::instance(), [id = m_settingsPage] { Core::ICore::showOptionsDialog(id); }, From a03bea81c7bb994367855ab40b9d76e974bbff50 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 2 May 2023 17:55:44 +0200 Subject: [PATCH 0782/1447] CppEditor: Remove WorkingCopy::contains() Most uses involved a double look-up. Change-Id: Ifeb62ea2361222ed0faad749f44a59735c8d6930 Reviewed-by: Christian Stenger --- src/plugins/autotest/itestparser.cpp | 4 ++-- .../cppeditor/builtineditordocumentparser.cpp | 4 ++-- .../builtineditordocumentprocessor.cpp | 13 +++++++------ src/plugins/cppeditor/cppfindreferences.cpp | 4 ++-- src/plugins/cppeditor/cppmodelmanager_test.cpp | 10 +++++----- .../cppeditor/cpprefactoringchanges.cpp | 4 ++-- src/plugins/cppeditor/cppsourceprocessor.cpp | 18 +++++++++--------- src/plugins/cppeditor/cpptoolsjsextension.cpp | 6 +++--- src/plugins/cppeditor/cpptoolstestcase.cpp | 2 +- src/plugins/cppeditor/cppworkingcopy.cpp | 14 ++++++++++++++ src/plugins/cppeditor/cppworkingcopy.h | 11 ++++------- .../cppeditor/fileandtokenactions_test.cpp | 2 +- src/plugins/debugger/cdb/cdbengine.cpp | 4 ++-- src/plugins/designer/qtcreatorintegration.cpp | 4 ++-- 14 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/plugins/autotest/itestparser.cpp b/src/plugins/autotest/itestparser.cpp index 27408ee933e..79fde2a0bb1 100644 --- a/src/plugins/autotest/itestparser.cpp +++ b/src/plugins/autotest/itestparser.cpp @@ -43,8 +43,8 @@ bool CppParser::selectedForBuilding(const FilePath &fileName) QByteArray CppParser::getFileContent(const FilePath &filePath) const { QByteArray fileContent; - if (m_workingCopy.contains(filePath)) { - fileContent = m_workingCopy.source(filePath); + if (const auto source = m_workingCopy.source(filePath)) { + fileContent = *source; } else { QString error; const QTextCodec *codec = Core::EditorManager::defaultTextCodec(); diff --git a/src/plugins/cppeditor/builtineditordocumentparser.cpp b/src/plugins/cppeditor/builtineditordocumentparser.cpp index ca7b83960dd..f6d7d6faf22 100644 --- a/src/plugins/cppeditor/builtineditordocumentparser.cpp +++ b/src/plugins/cppeditor/builtineditordocumentparser.cpp @@ -144,8 +144,8 @@ void BuiltinEditorDocumentParser::updateImpl(const QPromise &promise, QSet toRemove; for (const Document::Ptr &doc : std::as_const(state.snapshot)) { const Utils::FilePath filePath = doc->filePath(); - if (workingCopy.contains(filePath)) { - if (workingCopy.get(filePath).second != doc->editorRevision()) + if (const auto entry = workingCopy.get(filePath)) { + if (entry->second != doc->editorRevision()) addFileAndDependencies(&state.snapshot, &toRemove, filePath); continue; } diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index 0ea0c9c2dd7..625bed9c1be 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -302,12 +302,13 @@ void BuiltinEditorDocumentProcessor::onCodeWarningsUpdated( SemanticInfo::Source BuiltinEditorDocumentProcessor::createSemanticInfoSource(bool force) const { - const WorkingCopy workingCopy = CppModelManager::instance()->workingCopy(); - return SemanticInfo::Source(filePath().toString(), - workingCopy.source(filePath()), - workingCopy.revision(filePath()), - m_documentSnapshot, - force); + QByteArray source; + int revision = 0; + if (const auto entry = CppModelManager::instance()->workingCopy().get(filePath())) { + source = entry->first; + revision = entry->second; + } + return SemanticInfo::Source(filePath().toString(), source, revision, m_documentSnapshot, force); } } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index 589ac2d1a67..a4a3aba5075 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -105,8 +105,8 @@ namespace Internal { static QByteArray getSource(const Utils::FilePath &fileName, const WorkingCopy &workingCopy) { - if (workingCopy.contains(fileName)) { - return workingCopy.source(fileName); + if (const auto source = workingCopy.source(fileName)) { + return *source; } else { QString fileContents; Utils::TextFileFormat format; diff --git a/src/plugins/cppeditor/cppmodelmanager_test.cpp b/src/plugins/cppeditor/cppmodelmanager_test.cpp index eaa2ef142d8..c3fb3416469 100644 --- a/src/plugins/cppeditor/cppmodelmanager_test.cpp +++ b/src/plugins/cppeditor/cppmodelmanager_test.cpp @@ -649,7 +649,7 @@ void ModelManagerTest::testGcIfLastCppeditorClosed() QVERIFY(editor); QCOMPARE(Core::DocumentModel::openedDocuments().size(), 1); QVERIFY(mm->isCppEditor(editor)); - QVERIFY(mm->workingCopy().contains(file)); + QVERIFY(mm->workingCopy().get(file)); // Wait until the file is refreshed helper.waitForRefreshedSourceFiles(); @@ -659,7 +659,7 @@ void ModelManagerTest::testGcIfLastCppeditorClosed() helper.waitForFinishedGc(); // Check: File is removed from the snapshpt - QVERIFY(!mm->workingCopy().contains(file)); + QVERIFY(!mm->workingCopy().get(file)); QVERIFY(!mm->snapshot().contains(file)); } @@ -684,13 +684,13 @@ void ModelManagerTest::testDontGcOpenedFiles() // Wait until the file is refreshed and check whether it is in the working copy helper.waitForRefreshedSourceFiles(); - QVERIFY(mm->workingCopy().contains(file)); + QVERIFY(mm->workingCopy().get(file)); // Run the garbage collector mm->GC(); // Check: File is still there - QVERIFY(mm->workingCopy().contains(file)); + QVERIFY(mm->workingCopy().get(file)); QVERIFY(mm->snapshot().contains(file)); // Close editor @@ -1090,7 +1090,7 @@ void ModelManagerTest::testRenameIncludesInEditor() }); QCOMPARE(Core::DocumentModel::openedDocuments().size(), 1); QVERIFY(modelManager->isCppEditor(editor)); - QVERIFY(modelManager->workingCopy().contains(mainFile)); + QVERIFY(modelManager->workingCopy().get(mainFile)); // Test the renaming of a header file where a pragma once guard is present QVERIFY(Core::FileUtils::renameFile(headerWithPragmaOnce, diff --git a/src/plugins/cppeditor/cpprefactoringchanges.cpp b/src/plugins/cppeditor/cpprefactoringchanges.cpp index 1cce747fc66..bb34174d06a 100644 --- a/src/plugins/cppeditor/cpprefactoringchanges.cpp +++ b/src/plugins/cppeditor/cpprefactoringchanges.cpp @@ -57,8 +57,8 @@ CppRefactoringFilePtr CppRefactoringChanges::file(const FilePath &filePath) cons CppRefactoringFileConstPtr CppRefactoringChanges::fileNoEditor(const FilePath &filePath) const { QTextDocument *document = nullptr; - if (data()->m_workingCopy.contains(filePath)) - document = new QTextDocument(QString::fromUtf8(data()->m_workingCopy.source(filePath))); + if (const auto source = data()->m_workingCopy.source(filePath)) + document = new QTextDocument(QString::fromUtf8(*source)); CppRefactoringFilePtr result(new CppRefactoringFile(document, filePath)); result->m_data = m_data; diff --git a/src/plugins/cppeditor/cppsourceprocessor.cpp b/src/plugins/cppeditor/cppsourceprocessor.cpp index 66cca58a0f7..55dc1f10e05 100644 --- a/src/plugins/cppeditor/cppsourceprocessor.cpp +++ b/src/plugins/cppeditor/cppsourceprocessor.cpp @@ -81,7 +81,8 @@ inline const CPlusPlus::Macro revision(const WorkingCopy &workingCopy, const CPlusPlus::Macro ¯o) { CPlusPlus::Macro newMacro(macro); - newMacro.setFileRevision(workingCopy.get(macro.filePath()).second); + if (const auto entry = workingCopy.get(macro.filePath())) + newMacro.setFileRevision(entry->second); return newMacro; } @@ -189,10 +190,9 @@ bool CppSourceProcessor::getFileContents(const FilePath &absoluteFilePath, return false; // Get from working copy - if (m_workingCopy.contains(absoluteFilePath)) { - const QPair entry = m_workingCopy.get(absoluteFilePath); - *contents = entry.first; - *revision = entry.second; + if (const auto entry = m_workingCopy.get(absoluteFilePath)) { + *contents = entry->first; + *revision = entry->second; return true; } @@ -216,7 +216,7 @@ bool CppSourceProcessor::checkFile(const FilePath &absoluteFilePath) const { if (absoluteFilePath.isEmpty() || m_included.contains(absoluteFilePath) - || m_workingCopy.contains(absoluteFilePath)) { + || m_workingCopy.get(absoluteFilePath)) { return true; } @@ -281,7 +281,7 @@ FilePath CppSourceProcessor::resolveFile_helper(const FilePath &filePath, } else { path = FilePath::fromString(headerPathsIt->path) / fileName; } - if (m_workingCopy.contains(path) || checkFile(path)) + if (m_workingCopy.get(path) || checkFile(path)) return path; } } @@ -468,8 +468,8 @@ void CppSourceProcessor::sourceNeeded(int line, const FilePath &filePath, Includ document->setUtf8Source(preprocessedCode); document->keepSourceAndAST(); document->tokenize(); - document->check(m_workingCopy.contains(document->filePath()) ? Document::FullCheck - : Document::FastCheck); + document->check(m_workingCopy.get(document->filePath()) ? Document::FullCheck + : Document::FastCheck); m_documentFinished(document); diff --git a/src/plugins/cppeditor/cpptoolsjsextension.cpp b/src/plugins/cppeditor/cpptoolsjsextension.cpp index b70328601ee..73a846593c1 100644 --- a/src/plugins/cppeditor/cpptoolsjsextension.cpp +++ b/src/plugins/cppeditor/cpptoolsjsextension.cpp @@ -135,13 +135,13 @@ bool CppToolsJsExtension::hasQObjectParent(const QString &klassName) const // Find class in AST. const CPlusPlus::Snapshot snapshot = CppModelManager::instance()->snapshot(); const WorkingCopy workingCopy = CppModelManager::instance()->workingCopy(); - QByteArray source = workingCopy.source(item->filePath()); - if (source.isEmpty()) { + std::optional source = workingCopy.source(item->filePath()); + if (!source) { const Utils::expected_str contents = item->filePath().fileContents(); QTC_ASSERT_EXPECTED(contents, return false); source = *contents; } - const auto doc = snapshot.preprocessedDocument(source, item->filePath()); + const auto doc = snapshot.preprocessedDocument(*source, item->filePath()); if (!doc) return false; doc->check(); diff --git a/src/plugins/cppeditor/cpptoolstestcase.cpp b/src/plugins/cppeditor/cpptoolstestcase.cpp index 2d149b3ff5d..706423c0515 100644 --- a/src/plugins/cppeditor/cpptoolstestcase.cpp +++ b/src/plugins/cppeditor/cpptoolstestcase.cpp @@ -158,7 +158,7 @@ bool VerifyCleanCppModelManager::isClean(bool testOnlyForCleanedProjects) if (!testOnlyForCleanedProjects) { RETURN_FALSE_IF_NOT(mm->snapshot().isEmpty()); RETURN_FALSE_IF_NOT(mm->workingCopy().size() == 1); - RETURN_FALSE_IF_NOT(mm->workingCopy().contains(mm->configurationFileName())); + RETURN_FALSE_IF_NOT(mm->workingCopy().get(mm->configurationFileName())); } return true; } diff --git a/src/plugins/cppeditor/cppworkingcopy.cpp b/src/plugins/cppeditor/cppworkingcopy.cpp index b8922b7076d..828388c96ce 100644 --- a/src/plugins/cppeditor/cppworkingcopy.cpp +++ b/src/plugins/cppeditor/cppworkingcopy.cpp @@ -20,4 +20,18 @@ namespace CppEditor { WorkingCopy::WorkingCopy() = default; +std::optional WorkingCopy::source(const Utils::FilePath &fileName) const +{ + if (const auto value = get(fileName)) + return value->first; + return {}; +} + +std::optional> WorkingCopy::get(const Utils::FilePath &fileName) const +{ + const auto it = _elements.constFind(fileName); + if (it == _elements.constEnd()) + return {}; + return it.value(); +} } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppworkingcopy.h b/src/plugins/cppeditor/cppworkingcopy.h index ccc8258745d..87a613bc7ac 100644 --- a/src/plugins/cppeditor/cppworkingcopy.h +++ b/src/plugins/cppeditor/cppworkingcopy.h @@ -11,6 +11,8 @@ #include #include +#include + namespace CppEditor { class CPPEDITOR_EXPORT WorkingCopy @@ -21,17 +23,12 @@ public: void insert(const Utils::FilePath &fileName, const QByteArray &source, unsigned revision = 0) { _elements.insert(fileName, {source, revision}); } - bool contains(const Utils::FilePath &fileName) const - { return _elements.contains(fileName); } - - QByteArray source(const Utils::FilePath &fileName) const - { return _elements.value(fileName).first; } + std::optional source(const Utils::FilePath &fileName) const; unsigned revision(const Utils::FilePath &fileName) const { return _elements.value(fileName).second; } - QPair get(const Utils::FilePath &fileName) const - { return _elements.value(fileName); } + std::optional> get(const Utils::FilePath &fileName) const; using Table = QHash >; const Table &elements() const diff --git a/src/plugins/cppeditor/fileandtokenactions_test.cpp b/src/plugins/cppeditor/fileandtokenactions_test.cpp index b4b60d6828c..2ad6b6b4ef2 100644 --- a/src/plugins/cppeditor/fileandtokenactions_test.cpp +++ b/src/plugins/cppeditor/fileandtokenactions_test.cpp @@ -163,7 +163,7 @@ TestActionsTestCase::TestActionsTestCase(const Actions &tokenActions, const Acti QCOMPARE(DocumentModel::openedDocuments().size(), 1); QVERIFY(m_modelManager->isCppEditor(editor)); - QVERIFY(m_modelManager->workingCopy().contains(filePath)); + QVERIFY(m_modelManager->workingCopy().get(filePath)); // Rehighlight waitForRehighlightedSemanticDocument(editorWidget); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 0f316faa764..5d5b828712b 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2466,8 +2466,8 @@ static CPlusPlus::Document::Ptr getParsedDocument(const FilePath &filePath, const CPlusPlus::Snapshot &snapshot) { QByteArray src; - if (workingCopy.contains(filePath)) - src = workingCopy.source(filePath); + if (const auto source = workingCopy.source(filePath)) + src = *source; else src = QString::fromLocal8Bit(filePath.fileContents().value_or(QByteArray())).toUtf8(); diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp index 02f01a5d091..60189282cec 100644 --- a/src/plugins/designer/qtcreatorintegration.cpp +++ b/src/plugins/designer/qtcreatorintegration.cpp @@ -456,8 +456,8 @@ static Document::Ptr getParsedDocument(const FilePath &filePath, Snapshot &snapshot) { QByteArray src; - if (workingCopy.contains(filePath)) { - src = workingCopy.source(filePath); + if (const auto source = workingCopy.source(filePath)) { + src = *source; } else { Utils::FileReader reader; if (reader.fetch(filePath)) // ### FIXME error reporting From 95e8280d121330490bacefe0340f8143fa9a98b9 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 May 2023 10:50:16 +0200 Subject: [PATCH 0783/1447] Designer: Remove FormEditorW class Just wrapped static functions. Change-Id: Ic60a2d7185aab5576e48894c74a9314a4b1c2324 Reviewed-by: Jarek Kobus --- src/plugins/designer/designercontext.cpp | 2 +- src/plugins/designer/editorwidget.cpp | 2 +- src/plugins/designer/formeditorfactory.cpp | 10 ++-- src/plugins/designer/formeditorplugin.cpp | 6 +- src/plugins/designer/formeditorstack.cpp | 2 + src/plugins/designer/formeditorw.cpp | 52 ++++++++-------- src/plugins/designer/formeditorw.h | 59 +++++++++---------- .../designer/formtemplatewizardpage.cpp | 2 +- src/plugins/designer/gotoslot_test.cpp | 2 +- src/plugins/designer/qtcreatorintegration.cpp | 15 +++-- src/plugins/designer/settingspage.cpp | 8 ++- 11 files changed, 79 insertions(+), 81 deletions(-) diff --git a/src/plugins/designer/designercontext.cpp b/src/plugins/designer/designercontext.cpp index de65df8a207..4c4587defe9 100644 --- a/src/plugins/designer/designercontext.cpp +++ b/src/plugins/designer/designercontext.cpp @@ -25,7 +25,7 @@ DesignerContext::DesignerContext(const Core::Context &context, void DesignerContext::contextHelp(const HelpCallback &callback) const { - const QDesignerFormEditorInterface *core = FormEditorW::designerEditor(); + const QDesignerFormEditorInterface *core = designerEditor(); callback(core->integration()->contextHelpId()); } diff --git a/src/plugins/designer/editorwidget.cpp b/src/plugins/designer/editorwidget.cpp index f1b1772fc2f..9869904287f 100644 --- a/src/plugins/designer/editorwidget.cpp +++ b/src/plugins/designer/editorwidget.cpp @@ -28,7 +28,7 @@ EditorWidget::EditorWidget(QWidget *parent) : setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); - QWidget * const*subs = FormEditorW::designerSubWindows(); + QWidget * const * subs = designerSubWindows(); for (int i = 0; i < DesignerSubWindowCount; i++) { QWidget *subWindow = subs[i]; subWindow->setWindowTitle(subs[i]->windowTitle()); diff --git a/src/plugins/designer/formeditorfactory.cpp b/src/plugins/designer/formeditorfactory.cpp index beace0702ed..5a650d85829 100644 --- a/src/plugins/designer/formeditorfactory.cpp +++ b/src/plugins/designer/formeditorfactory.cpp @@ -1,18 +1,16 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "designertr.h" #include "formeditorfactory.h" + +#include "designerconstants.h" +#include "designertr.h" #include "formeditorw.h" -#include "formwindoweditor.h" #include #include #include -#include -#include - using namespace Core; using namespace Designer::Constants; using namespace Utils; @@ -25,7 +23,7 @@ FormEditorFactory::FormEditorFactory() setId(K_DESIGNER_XML_EDITOR_ID); setDisplayName(Tr::tr(C_DESIGNER_XML_DISPLAY_NAME)); addMimeType(FORM_MIMETYPE); - setEditorCreator([] { return FormEditorW::createEditor(); }); + setEditorCreator([] { return Designer::Internal::createEditor(); }); FileIconProvider::registerIconOverlayForSuffix(ProjectExplorer::Constants::FILEOVERLAY_UI, "ui"); } diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp index 8d26f27f0fb..8db713457de 100644 --- a/src/plugins/designer/formeditorplugin.cpp +++ b/src/plugins/designer/formeditorplugin.cpp @@ -1,9 +1,11 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "formeditorplugin.h" + +#include "designerconstants.h" #include "designertr.h" #include "formeditorfactory.h" -#include "formeditorplugin.h" #include "formeditorw.h" #include "formtemplatewizardpage.h" @@ -54,7 +56,7 @@ public: FormEditorPlugin::~FormEditorPlugin() { - FormEditorW::deleteInstance(); + deleteInstance(); delete d; } diff --git a/src/plugins/designer/formeditorstack.cpp b/src/plugins/designer/formeditorstack.cpp index 9325827f878..585e607d83b 100644 --- a/src/plugins/designer/formeditorstack.cpp +++ b/src/plugins/designer/formeditorstack.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "formeditorstack.h" + +#include "designerconstants.h" #include "formwindoweditor.h" #include "formeditorw.h" #include "formwindowfile.h" diff --git a/src/plugins/designer/formeditorw.cpp b/src/plugins/designer/formeditorw.cpp index a55b93d71fe..242e77772f9 100644 --- a/src/plugins/designer/formeditorw.cpp +++ b/src/plugins/designer/formeditorw.cpp @@ -123,9 +123,9 @@ public: } }; -// --------- FormEditorW +// FormEditorData -class FormEditorData +class FormEditorData : public QObject { public: FormEditorData(); @@ -173,7 +173,7 @@ public: QDesignerFormEditorInterface *m_formeditor = nullptr; QtCreatorIntegration *m_integration = nullptr; QDesignerFormWindowManagerInterface *m_fwm = nullptr; - FormEditorW::InitializationStage m_initStage = FormEditorW::RegisterPlugins; + InitializationStage m_initStage = RegisterPlugins; QWidget *m_designerSubWindows[DesignerSubWindowCount]; @@ -202,7 +202,6 @@ public: }; static FormEditorData *d = nullptr; -static FormEditorW *m_instance = nullptr; FormEditorData::FormEditorData() : m_formeditor(QDesignerComponents::createFormEditor(nullptr)) @@ -238,7 +237,7 @@ FormEditorData::FormEditorData() : if (editor && editor->document()->id() == Constants::K_DESIGNER_XML_EDITOR_ID) { FormWindowEditor *xmlEditor = qobject_cast(editor); QTC_ASSERT(xmlEditor, return); - FormEditorW::ensureInitStage(FormEditorW::FullyInitialized); + ensureInitStage(FullyInitialized); SharedTools::WidgetHost *fw = m_editorWidget->formWindowEditorForXmlEditor(xmlEditor); QTC_ASSERT(fw, return); m_editorWidget->setVisibleEditor(xmlEditor); @@ -251,7 +250,7 @@ FormEditorData::FormEditorData() : FormEditorData::~FormEditorData() { - if (m_initStage == FormEditorW::FullyInitialized) { + if (m_initStage == FullyInitialized) { QSettings *s = ICore::settings(); s->beginGroup(settingsGroupC); m_editorWidget->saveSettings(s); @@ -324,18 +323,18 @@ void FormEditorData::setupViewActions() void FormEditorData::fullInit() { - QTC_ASSERT(m_initStage == FormEditorW::RegisterPlugins, return); + QTC_ASSERT(m_initStage == RegisterPlugins, return); QElapsedTimer *initTime = nullptr; if (Designer::Constants::Internal::debug) { initTime = new QElapsedTimer; initTime->start(); } - QDesignerComponents::createTaskMenu(m_formeditor, m_instance); + QDesignerComponents::createTaskMenu(m_formeditor, this); QDesignerComponents::initializePlugins(m_formeditor); QDesignerComponents::initializeResources(); initDesignerSubWindows(); - m_integration = new QtCreatorIntegration(m_formeditor, m_instance); + m_integration = new QtCreatorIntegration(m_formeditor, this); m_formeditor->setIntegration(m_integration); // Connect Qt Designer help request to HelpManager. QObject::connect(m_integration, &QtCreatorIntegration::creatorHelpRequested, @@ -397,13 +396,13 @@ void FormEditorData::fullInit() Context designerContexts = m_contexts; designerContexts.add(Core::Constants::C_EDITORMANAGER); - ICore::addContextObject(new DesignerContext(designerContexts, m_modeWidget, m_instance)); + ICore::addContextObject(new DesignerContext(designerContexts, m_modeWidget, this)); DesignMode::registerDesignWidget(m_modeWidget, QStringList(FORM_MIMETYPE), m_contexts); setupViewActions(); - m_initStage = FormEditorW::FullyInitialized; + m_initStage = FullyInitialized; } void FormEditorData::initDesignerSubWindows() @@ -438,22 +437,21 @@ void FormEditorData::initDesignerSubWindows() ae->setObjectName("ActionEditor"); m_formeditor->setActionEditor(ae); m_designerSubWindows[ActionEditorSubWindow] = ae; - m_initStage = FormEditorW::SubwindowsInitialized; + m_initStage = SubwindowsInitialized; } -QList FormEditorW::optionsPages() +QList optionsPages() { return d->m_settingsPages; } -void FormEditorW::ensureInitStage(InitializationStage s) +void ensureInitStage(InitializationStage s) { if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << s; - if (!d) { - m_instance = new FormEditorW; + if (!d) d = new FormEditorData; - } + if (d->m_initStage >= s) return; QApplication::setOverrideCursor(Qt::WaitCursor); @@ -461,15 +459,13 @@ void FormEditorW::ensureInitStage(InitializationStage s) QApplication::restoreOverrideCursor(); } -void FormEditorW::deleteInstance() +void deleteInstance() { delete d; d = nullptr; - delete m_instance; - m_instance = nullptr; } -IEditor *FormEditorW::createEditor() +IEditor *createEditor() { ensureInitStage(FullyInitialized); return d->createEditor(); @@ -489,7 +485,7 @@ void FormEditorData::setupActions() bindShortcut(ActionManager::registerAction(m_fwm->actionPaste(), Core::Constants::PASTE, m_contexts), m_fwm->actionPaste()); bindShortcut(ActionManager::registerAction(m_fwm->actionSelectAll(), Core::Constants::SELECTALL, m_contexts), m_fwm->actionSelectAll()); - m_actionPrint = new QAction(m_instance); + m_actionPrint = new QAction(this); bindShortcut(ActionManager::registerAction(m_actionPrint, Core::Constants::PRINT, m_contexts), m_actionPrint); QObject::connect(m_actionPrint, &QAction::triggered, [this]() { print(); }); @@ -502,7 +498,7 @@ void FormEditorData::setupActions() command->setAttribute(Command::CA_Hide); medit->addAction(command, Core::Constants::G_EDIT_COPYPASTE); - m_actionGroupEditMode = new QActionGroup(m_instance); + m_actionGroupEditMode = new QActionGroup(this); m_actionGroupEditMode->setExclusive(true); QObject::connect(m_actionGroupEditMode, &QActionGroup::triggered, [this](QAction *a) { activateEditMode(a->data().toInt()); }); @@ -601,7 +597,7 @@ void FormEditorData::setupActions() QString(), Core::Constants::G_DEFAULT_THREE); mformtools->addSeparator(m_contexts, Core::Constants::G_DEFAULT_THREE); - m_actionAboutPlugins = new QAction(Tr::tr("About Qt Designer Plugins..."), m_instance); + m_actionAboutPlugins = new QAction(Tr::tr("About Qt Designer Plugins..."), d); addToolAction(m_actionAboutPlugins, m_contexts, "FormEditor.AboutPlugins", mformtools, QString(), Core::Constants::G_DEFAULT_THREE); QObject::connect(m_actionAboutPlugins, &QAction::triggered, @@ -760,19 +756,19 @@ IEditor *FormEditorData::createEditor() return formWindowEditor; } -QDesignerFormEditorInterface *FormEditorW::designerEditor() +QDesignerFormEditorInterface *designerEditor() { ensureInitStage(FullyInitialized); return d->m_formeditor; } -QWidget * const *FormEditorW::designerSubWindows() +QWidget * const *designerSubWindows() { ensureInitStage(SubwindowsInitialized); return d->m_designerSubWindows; } -SharedTools::WidgetHost *FormEditorW::activeWidgetHost() +SharedTools::WidgetHost *activeWidgetHost() { ensureInitStage(FullyInitialized); if (d->m_editorWidget) @@ -780,7 +776,7 @@ SharedTools::WidgetHost *FormEditorW::activeWidgetHost() return nullptr; } -FormWindowEditor *FormEditorW::activeEditor() +FormWindowEditor *activeEditor() { ensureInitStage(FullyInitialized); if (d->m_editorWidget) diff --git a/src/plugins/designer/formeditorw.h b/src/plugins/designer/formeditorw.h index 50462c2aa18..0d069e2322c 100644 --- a/src/plugins/designer/formeditorw.h +++ b/src/plugins/designer/formeditorw.h @@ -3,12 +3,11 @@ #pragma once -#include "designerconstants.h" - -#include +#include QT_BEGIN_NAMESPACE class QDesignerFormEditorInterface; +class QWidget; QT_END_NAMESPACE namespace Core { @@ -24,11 +23,10 @@ class FormWindowEditor; namespace Internal { -/** FormEditorW is a singleton that stores the Designer CoreInterface and - * performs centralized operations. The instance() function will return an - * instance. However, it must be manually deleted when unloading the - * plugin. Since fully initializing Designer at startup is expensive, the - * class has an internal partial initialisation stage "RegisterPlugins" +/** This is an interface to the Designer CoreInterface to + * performs centralized operations. + * Since fully initializing Designer at startup is expensive, the + * setup has an internal partial initialization stage "RegisterPlugins" * which is there to register the Creator plugin objects * that must be present at startup (settings pages, actions). * The plugin uses this stage at first by calling ensureInitStage(). @@ -38,32 +36,29 @@ namespace Internal { * * The form editor shows a read-only XML editor in edit mode and Qt Designer * in Design mode. */ -class FormEditorW : public QObject -{ -public: - enum InitializationStage { - // Register Creator plugins (settings pages, actions) - RegisterPlugins, - // Subwindows of the designer are initialized - SubwindowsInitialized, - // Fully initialized for handling editor requests - FullyInitialized - }; - // Create an instance and initialize up to stage s - static void ensureInitStage(InitializationStage s); - // Deletes an existing instance if there is one. - static void deleteInstance(); - - static Core::IEditor *createEditor(); - - static QDesignerFormEditorInterface *designerEditor(); - static QWidget * const *designerSubWindows(); - - static SharedTools::WidgetHost *activeWidgetHost(); - static FormWindowEditor *activeEditor(); - static QList optionsPages(); +enum InitializationStage { + // Register Creator plugins (settings pages, actions) + RegisterPlugins, + // Subwindows of the designer are initialized + SubwindowsInitialized, + // Fully initialized for handling editor requests + FullyInitialized }; +// Create an instance and initialize up to stage s +void ensureInitStage(InitializationStage s); +// Deletes an existing instance if there is one. +void deleteInstance(); + +Core::IEditor *createEditor(); + +QDesignerFormEditorInterface *designerEditor(); +QWidget * const *designerSubWindows(); + +SharedTools::WidgetHost *activeWidgetHost(); +FormWindowEditor *activeEditor(); +QList optionsPages(); + } // namespace Internal } // namespace Designer diff --git a/src/plugins/designer/formtemplatewizardpage.cpp b/src/plugins/designer/formtemplatewizardpage.cpp index c6417522f44..fd13a6f1cca 100644 --- a/src/plugins/designer/formtemplatewizardpage.cpp +++ b/src/plugins/designer/formtemplatewizardpage.cpp @@ -58,7 +58,7 @@ bool FormPageFactory::validateData(Utils::Id typeId, const QVariant &data, QStri FormTemplateWizardPage::FormTemplateWizardPage(QWidget * parent) : Utils::WizardPage(parent), - m_newFormWidget(QDesignerNewFormWidgetInterface::createNewFormWidget(FormEditorW::designerEditor())), + m_newFormWidget(QDesignerNewFormWidgetInterface::createNewFormWidget(designerEditor())), m_templateSelected(m_newFormWidget->hasCurrentTemplate()) { setTitle(Tr::tr("Choose a Form Template")); diff --git a/src/plugins/designer/gotoslot_test.cpp b/src/plugins/designer/gotoslot_test.cpp index f4562a41e79..89740601e0d 100644 --- a/src/plugins/designer/gotoslot_test.cpp +++ b/src/plugins/designer/gotoslot_test.cpp @@ -147,7 +147,7 @@ public: waitForFilesInGlobalSnapshot({cppFile, hFile}); // Execute "Go To Slot" - QDesignerIntegrationInterface *integration = FormEditorW::designerEditor()->integration(); + QDesignerIntegrationInterface *integration = designerEditor()->integration(); QVERIFY(integration); integration->emitNavigateToSlot("pushButton", "clicked()", QStringList()); diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp index 60189282cec..2930f7787fa 100644 --- a/src/plugins/designer/qtcreatorintegration.cpp +++ b/src/plugins/designer/qtcreatorintegration.cpp @@ -1,10 +1,13 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "qtcreatorintegration.h" + +#include "designerconstants.h" #include "designertr.h" #include "formeditorw.h" #include "formwindoweditor.h" -#include "qtcreatorintegration.h" + #include #include @@ -156,14 +159,14 @@ void QtCreatorIntegration::slotDesignerHelpRequested(const QString &manual, cons void QtCreatorIntegration::updateSelection() { - if (SharedTools::WidgetHost *host = FormEditorW::activeWidgetHost()) + if (SharedTools::WidgetHost *host = activeWidgetHost()) host->updateFormWindowSelectionHandles(true); QDesignerIntegration::updateSelection(); } QWidget *QtCreatorIntegration::containerWindow(QWidget * /*widget*/) const { - if (SharedTools::WidgetHost *host = FormEditorW::activeWidgetHost()) + if (SharedTools::WidgetHost *host = activeWidgetHost()) return host->integrationContainer(); return nullptr; } @@ -435,7 +438,7 @@ void QtCreatorIntegration::slotNavigateToSlot(const QString &objectName, const Q { QString errorMessage; if (!navigateToSlot(objectName, signalSignature, parameterNames, &errorMessage) && !errorMessage.isEmpty()) - QMessageBox::warning(FormEditorW::designerEditor()->topLevel(), Tr::tr("Error finding/adding a slot."), errorMessage); + QMessageBox::warning(designerEditor()->topLevel(), Tr::tr("Error finding/adding a slot."), errorMessage); } // Build name of the class as generated by uic, insert Ui namespace @@ -480,7 +483,7 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName, { using DocumentMap = QMap; - const Utils::FilePath currentUiFile = FormEditorW::activeEditor()->document()->filePath(); + const Utils::FilePath currentUiFile = activeEditor()->document()->filePath(); #if 0 return Designer::Internal::navigateToSlot(currentUiFile.toString(), objectName, signalSignature, parameterNames, errorMessage); @@ -533,7 +536,7 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName, return false; } - QDesignerFormWindowInterface *fwi = FormEditorW::activeWidgetHost()->formWindow(); + QDesignerFormWindowInterface *fwi = activeWidgetHost()->formWindow(); QString uiClass; const Class *cl = nullptr; diff --git a/src/plugins/designer/settingspage.cpp b/src/plugins/designer/settingspage.cpp index 64b79940f56..d39ef9cc24d 100644 --- a/src/plugins/designer/settingspage.cpp +++ b/src/plugins/designer/settingspage.cpp @@ -1,9 +1,11 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "settingspage.h" + +#include "designerconstants.h" #include "designertr.h" #include "formeditorw.h" -#include "settingspage.h" #include @@ -54,9 +56,9 @@ QList SettingsPageProvider::pages() const if (!m_initialized) { // get options pages from designer m_initialized = true; - FormEditorW::ensureInitStage(FormEditorW::RegisterPlugins); + ensureInitStage(RegisterPlugins); } - return FormEditorW::optionsPages(); + return optionsPages(); } bool SettingsPageProvider::matches(const QRegularExpression ®ex) const From 30882d931dc3d3a282c43c9de9e4fbed2a9af06a Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 May 2023 11:52:07 +0200 Subject: [PATCH 0784/1447] Designer: Rename formeditorw.{cpp,h} -> formeditor.{cpp,h} Change-Id: I90412be98c4c506742c866f8900489a5e33b0e4d Reviewed-by: Jarek Kobus --- src/plugins/designer/CMakeLists.txt | 2 +- src/plugins/designer/designer.qbs | 2 +- src/plugins/designer/designercontext.cpp | 2 +- src/plugins/designer/editorwidget.cpp | 2 +- src/plugins/designer/{formeditorw.cpp => formeditor.cpp} | 2 +- src/plugins/designer/{formeditorw.h => formeditor.h} | 0 src/plugins/designer/formeditorfactory.cpp | 2 +- src/plugins/designer/formeditorplugin.cpp | 2 +- src/plugins/designer/formeditorstack.cpp | 2 +- src/plugins/designer/formtemplatewizardpage.cpp | 2 +- src/plugins/designer/gotoslot_test.cpp | 2 +- src/plugins/designer/qtcreatorintegration.cpp | 2 +- src/plugins/designer/settingspage.cpp | 2 +- 13 files changed, 12 insertions(+), 12 deletions(-) rename src/plugins/designer/{formeditorw.cpp => formeditor.cpp} (99%) rename src/plugins/designer/{formeditorw.h => formeditor.h} (100%) diff --git a/src/plugins/designer/CMakeLists.txt b/src/plugins/designer/CMakeLists.txt index f6304e4a67d..18b1cf97692 100644 --- a/src/plugins/designer/CMakeLists.txt +++ b/src/plugins/designer/CMakeLists.txt @@ -22,7 +22,7 @@ add_qtc_plugin(Designer formeditorfactory.cpp formeditorfactory.h formeditorplugin.cpp formeditorplugin.h formeditorstack.cpp formeditorstack.h - formeditorw.cpp formeditorw.h + formeditor.cpp formeditor.h formtemplatewizardpage.cpp formtemplatewizardpage.h formwindoweditor.cpp formwindoweditor.h formwindowfile.cpp formwindowfile.h diff --git a/src/plugins/designer/designer.qbs b/src/plugins/designer/designer.qbs index b730485329d..8b97a494a7c 100644 --- a/src/plugins/designer/designer.qbs +++ b/src/plugins/designer/designer.qbs @@ -41,7 +41,7 @@ QtcPlugin { "formeditorfactory.cpp", "formeditorfactory.h", "formeditorplugin.cpp", "formeditorplugin.h", "formeditorstack.cpp", "formeditorstack.h", - "formeditorw.cpp", "formeditorw.h", + "formeditor.cpp", "formeditor.h", "formtemplatewizardpage.cpp", "formtemplatewizardpage.h", "formwindoweditor.cpp", "formwindoweditor.h", "formwindowfile.cpp", "formwindowfile.h", diff --git a/src/plugins/designer/designercontext.cpp b/src/plugins/designer/designercontext.cpp index 4c4587defe9..266a347bbb2 100644 --- a/src/plugins/designer/designercontext.cpp +++ b/src/plugins/designer/designercontext.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "designercontext.h" -#include "formeditorw.h" +#include "formeditor.h" #include #include diff --git a/src/plugins/designer/editorwidget.cpp b/src/plugins/designer/editorwidget.cpp index 9869904287f..664e953b3bc 100644 --- a/src/plugins/designer/editorwidget.cpp +++ b/src/plugins/designer/editorwidget.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "editorwidget.h" -#include "formeditorw.h" +#include "formeditor.h" #include "formeditorstack.h" #include diff --git a/src/plugins/designer/formeditorw.cpp b/src/plugins/designer/formeditor.cpp similarity index 99% rename from src/plugins/designer/formeditorw.cpp rename to src/plugins/designer/formeditor.cpp index 242e77772f9..96e65796500 100644 --- a/src/plugins/designer/formeditorw.cpp +++ b/src/plugins/designer/formeditor.cpp @@ -5,7 +5,7 @@ #include "designertr.h" #include "editordata.h" #include "editorwidget.h" -#include "formeditorw.h" +#include "formeditor.h" #include "formwindoweditor.h" #include "formwindowfile.h" #include "qtcreatorintegration.h" diff --git a/src/plugins/designer/formeditorw.h b/src/plugins/designer/formeditor.h similarity index 100% rename from src/plugins/designer/formeditorw.h rename to src/plugins/designer/formeditor.h diff --git a/src/plugins/designer/formeditorfactory.cpp b/src/plugins/designer/formeditorfactory.cpp index 5a650d85829..278cb065f40 100644 --- a/src/plugins/designer/formeditorfactory.cpp +++ b/src/plugins/designer/formeditorfactory.cpp @@ -5,7 +5,7 @@ #include "designerconstants.h" #include "designertr.h" -#include "formeditorw.h" +#include "formeditor.h" #include #include diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp index 8db713457de..881e6a30eb5 100644 --- a/src/plugins/designer/formeditorplugin.cpp +++ b/src/plugins/designer/formeditorplugin.cpp @@ -6,7 +6,7 @@ #include "designerconstants.h" #include "designertr.h" #include "formeditorfactory.h" -#include "formeditorw.h" +#include "formeditor.h" #include "formtemplatewizardpage.h" #ifdef CPP_ENABLED diff --git a/src/plugins/designer/formeditorstack.cpp b/src/plugins/designer/formeditorstack.cpp index 585e607d83b..1bccd341784 100644 --- a/src/plugins/designer/formeditorstack.cpp +++ b/src/plugins/designer/formeditorstack.cpp @@ -5,7 +5,7 @@ #include "designerconstants.h" #include "formwindoweditor.h" -#include "formeditorw.h" +#include "formeditor.h" #include "formwindowfile.h" #include diff --git a/src/plugins/designer/formtemplatewizardpage.cpp b/src/plugins/designer/formtemplatewizardpage.cpp index fd13a6f1cca..68e3fb17111 100644 --- a/src/plugins/designer/formtemplatewizardpage.cpp +++ b/src/plugins/designer/formtemplatewizardpage.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "designertr.h" -#include "formeditorw.h" +#include "formeditor.h" #include "formtemplatewizardpage.h" #include diff --git a/src/plugins/designer/gotoslot_test.cpp b/src/plugins/designer/gotoslot_test.cpp index 89740601e0d..f804c2259e3 100644 --- a/src/plugins/designer/gotoslot_test.cpp +++ b/src/plugins/designer/gotoslot_test.cpp @@ -3,7 +3,7 @@ #include "formeditorplugin.h" -#include "formeditorw.h" +#include "formeditor.h" #include #include diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp index 2930f7787fa..010ab85a82b 100644 --- a/src/plugins/designer/qtcreatorintegration.cpp +++ b/src/plugins/designer/qtcreatorintegration.cpp @@ -5,7 +5,7 @@ #include "designerconstants.h" #include "designertr.h" -#include "formeditorw.h" +#include "formeditor.h" #include "formwindoweditor.h" #include diff --git a/src/plugins/designer/settingspage.cpp b/src/plugins/designer/settingspage.cpp index d39ef9cc24d..c393503d5ce 100644 --- a/src/plugins/designer/settingspage.cpp +++ b/src/plugins/designer/settingspage.cpp @@ -5,7 +5,7 @@ #include "designerconstants.h" #include "designertr.h" -#include "formeditorw.h" +#include "formeditor.h" #include From 3dd4b98c0cc47dcc89e5e59181647ff1409aebfb Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 2 May 2023 20:50:44 +0200 Subject: [PATCH 0785/1447] CMakePM: Better Qt import detection Qt6_DIR and Qt5_DIR CMake variables are additionally checked for existence. Qt6_ROOT and Qt5_ROOT are taken into consideration for both environment and CMake variables. CMAKE_PREFIX_PATH is also returned from the qmake probe. This fixes the case when qt.toolchain.cmake is used exclusively. Task-number: QTCREATORBUG-29075 Change-Id: I6e0c3adf7f5d9860a1cb776371e66dea1dfc26cc Reviewed-by: hjk Reviewed-by: Qt CI Bot --- .../cmakeprojectimporter.cpp | 104 ++++++++++++------ 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 03cd3c6b0eb..8210eb21924 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -247,44 +247,66 @@ static CMakeConfig configurationFromPresetProbe( return config; } -static FilePath qmakeFromCMakeCache(const CMakeConfig &config) +struct QMakeAndCMakePrefixPath +{ + FilePath qmakePath; + QString cmakePrefixPath; // can be a semicolon-separated list +}; + +static QMakeAndCMakePrefixPath qtInfoFromCMakeCache(const CMakeConfig &config, + const Environment &env) { // Qt4 way to define things (more convenient for us, so try this first;-) const FilePath qmake = config.filePathValueOf("QT_QMAKE_EXECUTABLE"); qCDebug(cmInputLog) << "QT_QMAKE_EXECUTABLE=" << qmake.toUserOutput(); - if (!qmake.isEmpty()) - return qmake; // Check Qt5 settings: oh, the horror! - const FilePath qtCMakeDir = [config] { - FilePath tmp = config.filePathValueOf("Qt5Core_DIR"); - if (tmp.isEmpty()) - tmp = config.filePathValueOf("Qt6Core_DIR"); + const FilePath qtCMakeDir = [config, env] { + FilePath tmp; + // Check the CMake "_DIR" variable + for (const auto &var : {"Qt6", "Qt6Core", "Qt5", "Qt5Core"}) { + tmp = config.filePathValueOf(QByteArray(var) + "_DIR"); + if (!tmp.isEmpty()) + break; + } return tmp; }(); qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput(); const FilePath canQtCMakeDir = FilePath::fromString(qtCMakeDir.toFileInfo().canonicalFilePath()); qCInfo(cmInputLog) << "QtXCore_DIR (canonical)=" << canQtCMakeDir.toUserOutput(); - QString prefixPath; - if (!qtCMakeDir.isEmpty()) { - prefixPath = canQtCMakeDir.parentDir().parentDir().parentDir().toString(); // Up 3 levels... - } else { - prefixPath = config.stringValueOf("CMAKE_PREFIX_PATH"); - } + + const QString prefixPath = [qtCMakeDir, canQtCMakeDir, config, env] { + QString result; + if (!qtCMakeDir.isEmpty()) { + result = canQtCMakeDir.parentDir().parentDir().parentDir().path(); // Up 3 levels... + } else { + // Check the CMAKE_PREFIX_PATH and "_ROOT" CMake or environment variables + // This can be a single value or a semicolon-separated list + for (const auto &var : {"CMAKE_PREFIX_PATH", "Qt6_ROOT", "Qt5_ROOT"}) { + result = config.stringValueOf(var); + if (result.isEmpty()) + result = env.value(QString::fromUtf8(var)); + if (!result.isEmpty()) + break; + } + } + return result; + }(); qCDebug(cmInputLog) << "PrefixPath:" << prefixPath; + if (!qmake.isEmpty() && !prefixPath.isEmpty()) + return {qmake, prefixPath}; + FilePath toolchainFile = config.filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE")); if (prefixPath.isEmpty() && toolchainFile.isEmpty()) - return FilePath(); + return {qmake, QString()}; // Run a CMake project that would do qmake probing TemporaryDirectory qtcQMakeProbeDir("qtc-cmake-qmake-probe-XXXXXXXX"); - QFile cmakeListTxt(qtcQMakeProbeDir.filePath("CMakeLists.txt").toString()); - if (!cmakeListTxt.open(QIODevice::WriteOnly)) { - return FilePath(); - } - cmakeListTxt.write(QByteArray(R"( + FilePath cmakeListTxt(qtcQMakeProbeDir.filePath("CMakeLists.txt")); + + cmakeListTxt.writeFileContents(QByteArray(R"( cmake_minimum_required(VERSION 3.15) project(qmake-probe LANGUAGES NONE) @@ -312,15 +334,20 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config) OUTPUT "${CMAKE_SOURCE_DIR}/qmake-location.txt" CONTENT "$") endif() + + # Remove a Qt CMake hack that adds lib/cmake at the end of every path in CMAKE_PREFIX_PATH + list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH) + list(TRANSFORM CMAKE_PREFIX_PATH REPLACE "/lib/cmake$" "") + file(WRITE "${CMAKE_SOURCE_DIR}/cmake-prefix-path.txt" "${CMAKE_PREFIX_PATH}") )")); - cmakeListTxt.close(); QtcProcess cmake; cmake.setTimeoutS(5); cmake.setDisableUnixTerminal(); - Environment env = Environment::systemEnvironment(); - env.setupEnglishOutput(); - cmake.setEnvironment(env); + + Environment cmakeEnv(env); + cmakeEnv.setupEnglishOutput(); + cmake.setEnvironment(cmakeEnv); cmake.setTimeOutMessageBoxEnabled(false); QString cmakeGenerator = config.stringValueOf(QByteArray("CMAKE_GENERATOR")); @@ -364,14 +391,17 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config) cmake.setCommand({cmakeExecutable, args}); cmake.runBlocking(); - QFile qmakeLocationTxt(qtcQMakeProbeDir.filePath("qmake-location.txt").path()); - if (!qmakeLocationTxt.open(QIODevice::ReadOnly)) { - return FilePath(); - } - FilePath qmakeLocation = FilePath::fromUtf8(qmakeLocationTxt.readLine().constData()); + const FilePath qmakeLocationTxt = qtcQMakeProbeDir.filePath("qmake-location.txt"); + const FilePath qmakeLocation = FilePath::fromUtf8( + qmakeLocationTxt.fileContents().value_or(QByteArray())); qCDebug(cmInputLog) << "qmake location: " << qmakeLocation.toUserOutput(); - return qmakeLocation; + const FilePath prefixPathTxt = qtcQMakeProbeDir.filePath("cmake-prefix-path.txt"); + const QString resultedPrefixPath = QString::fromUtf8( + prefixPathTxt.fileContents().value_or(QByteArray())); + qCDebug(cmInputLog) << "PrefixPath [after qmake probe]: " << resultedPrefixPath; + + return {qmakeLocation, resultedPrefixPath}; } static QVector extractToolChainsFromCache(const CMakeConfig &config) @@ -686,10 +716,15 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, configurePreset.generator.value().toUtf8()); } - const FilePath qmake = qmakeFromCMakeCache(config); + const auto [qmake, cmakePrefixPath] = qtInfoFromCMakeCache(config, env); if (!qmake.isEmpty()) data->qt = findOrCreateQtVersion(qmake); + if (!cmakePrefixPath.isEmpty() && config.valueOf("CMAKE_PREFIX_PATH").isEmpty()) + config << CMakeConfigItem("CMAKE_PREFIX_PATH", + CMakeConfigItem::PATH, + cmakePrefixPath.toUtf8()); + // ToolChains: data->toolChains = extractToolChainsFromCache(config); @@ -746,6 +781,8 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, buildConfigurationTypes = buildConfigurationTypesString.split(';'); } + const Environment env = projectDirectory().deviceEnvironment(); + for (auto const &buildType: std::as_const(buildConfigurationTypes)) { auto data = std::make_unique(); @@ -777,7 +814,7 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, data->sysroot = config.filePathValueOf("CMAKE_SYSROOT"); // Qt: - const FilePath qmake = qmakeFromCMakeCache(config); + const auto [qmake, cmakePrefixPath] = qtInfoFromCMakeCache(config, env); if (!qmake.isEmpty()) data->qt = findOrCreateQtVersion(qmake); @@ -1021,8 +1058,9 @@ void CMakeProjectPlugin::testCMakeProjectImporterQt() config.append(CMakeConfigItem(key.toUtf8(), value.toUtf8())); } - FilePath realQmake = qmakeFromCMakeCache(config); - QCOMPARE(realQmake.toString(), expectedQmake); + auto [realQmake, cmakePrefixPath] = qtInfoFromCMakeCache(config, + Environment::systemEnvironment()); + QCOMPARE(realQmake.path(), expectedQmake); } void CMakeProjectPlugin::testCMakeProjectImporterToolChain_data() { From 7b132faff82d822b2928894f61ba9b3b7fac6d23 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 21 Apr 2023 14:28:20 +0200 Subject: [PATCH 0786/1447] Vcpkg: Use IOptionsPageWidget in settings page Change-Id: I71a20b4120cf0fa93b304c8477d851a143fede04 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/vcpkg/vcpkgsettings.cpp | 25 ++++++++++++++----------- src/plugins/vcpkg/vcpkgsettings.h | 2 -- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp index 9900f54afdb..e600631e970 100644 --- a/src/plugins/vcpkg/vcpkgsettings.cpp +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -43,13 +43,11 @@ bool VcpkgSettings::vcpkgRootValid() const return (vcpkgRoot.filePath() / "vcpkg").withExecutableSuffix().isExecutableFile(); } -VcpkgSettingsPage::VcpkgSettingsPage() +class VcpkgSettingsPageWidget : public Core::IOptionsPageWidget { - setId(Constants::TOOLSSETTINGSPAGE_ID); - setDisplayName("Vcpkg"); - setCategory(CMakeProjectManager::Constants::Settings::CATEGORY); - - setLayouter([] (QWidget *widget) { +public: + VcpkgSettingsPageWidget() + { auto websiteButton = new QToolButton; websiteButton->setIcon(Utils::Icons::ONLINE.icon()); websiteButton->setToolTip(Constants::WEBSITE_URL); @@ -64,17 +62,22 @@ VcpkgSettingsPage::VcpkgSettingsPage() }, }, st, - }.attachTo(widget); + }.attachTo(this); connect(websiteButton, &QAbstractButton::clicked, [] { QDesktopServices::openUrl(QUrl::fromUserInput(Constants::WEBSITE_URL)); }); - }); -} -void VcpkgSettingsPage::apply() + setOnApply([] { VcpkgSettings::instance()->writeSettings(Core::ICore::settings()); }); + } +}; + +VcpkgSettingsPage::VcpkgSettingsPage() { - VcpkgSettings::instance()->writeSettings(Core::ICore::settings()); + setId(Constants::TOOLSSETTINGSPAGE_ID); + setDisplayName("Vcpkg"); + setCategory(CMakeProjectManager::Constants::Settings::CATEGORY); + setWidgetCreator([] { return new VcpkgSettingsPageWidget; }); } } // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgsettings.h b/src/plugins/vcpkg/vcpkgsettings.h index a0a7973cc01..b83cf7f9c1c 100644 --- a/src/plugins/vcpkg/vcpkgsettings.h +++ b/src/plugins/vcpkg/vcpkgsettings.h @@ -23,8 +23,6 @@ class VcpkgSettingsPage final : public Core::IOptionsPage { public: VcpkgSettingsPage(); - - void apply() override; }; } // namespace Vcpkg::Internal From 71b3c6950f93a7761d44079ea2065d487a8bd5c9 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 26 Apr 2023 18:09:24 +0200 Subject: [PATCH 0787/1447] CMakePM: Parse the CMake file before adding new / existing files This way the functionality would work even if autorun CMake is disabled. Change-Id: I54ab47d72664cb42486b260b895f58d37a885cce Reviewed-by: hjk Reviewed-by: --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index a493062621c..0ea477752ca 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -271,10 +271,19 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP const FilePath targetCMakeFile = target.backtrace.last().path; const int targetDefinitionLine = target.backtrace.last().line; - auto cmakeListFile - = Utils::findOrDefault(m_cmakeFiles, [targetCMakeFile](const CMakeFileInfo &info) { - return info.path == targetCMakeFile; - }).cmakeListFile; + // Have a fresh look at the CMake file, not relying on a cached value + expected_str fileContent = targetCMakeFile.fileContents(); + cmListFile cmakeListFile; + std::string errorString; + if (fileContent) { + fileContent = fileContent->replace("\r\n", "\n"); + if (!cmakeListFile.ParseString(fileContent->toStdString(), + targetCMakeFile.fileName().toStdString(), + errorString)) { + *notAdded = filePaths; + return false; + } + } auto function = std::find_if(cmakeListFile.Functions.begin(), cmakeListFile.Functions.end(), @@ -360,7 +369,8 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP editor->insert(snippet); editor->editorWidget()->autoIndent(); - Core::DocumentManager::saveDocument(editor->document()); + if (!Core::DocumentManager::saveDocument(editor->document())) + return false; return true; } From c2e657bbf6f6c39f88c21008f045f02e0a4e67db Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 26 Apr 2023 18:29:27 +0200 Subject: [PATCH 0788/1447] CMakePM: Allow file rename / remove for QtQuick projects qt_add_qml_module was not consided when looking for existing project files. This would fail when qt_add_executable and qt_add_qml_module were used with the same target name. Change-Id: Ib7374a3e1213c23aaf12d100a8817a46d57a4303 Reviewed-by: hjk Reviewed-by: --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 0ea477752ca..805f84f7c24 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -411,15 +411,25 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q }); const std::string target_name = targetName.toStdString(); - auto targetSourcesFunc - = std::find_if(cmakeListFile.Functions.begin(), - cmakeListFile.Functions.end(), - [target_name = targetName.toStdString()](const auto &func) { - return func.LowerCaseName() == "target_sources" - && func.Arguments().front().Value == target_name; - }); + auto targetSourcesFunc = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [target_name](const auto &func) { + return func.LowerCaseName() == "target_sources" + && func.Arguments().size() > 1 + && func.Arguments().front().Value + == target_name; + }); + auto addQmlModuleFunc = std::find_if(cmakeListFile.Functions.begin(), + cmakeListFile.Functions.end(), + [target_name](const auto &func) { + return (func.LowerCaseName() == "qt_add_qml_module" + || func.LowerCaseName() == "qt6_add_qml_module") + && func.Arguments().size() > 1 + && func.Arguments().front().Value + == target_name; + }); - for (const auto &func : {function, targetSourcesFunc}) { + for (const auto &func : {function, targetSourcesFunc, addQmlModuleFunc}) { if (func == cmakeListFile.Functions.end()) continue; auto filePathArgument From 6d805195f6d35df932d666f86af026c051c785f8 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 2 May 2023 16:48:41 +0200 Subject: [PATCH 0789/1447] CppEditor: Force document parser run on change in header dependency Fixes: QTCREATORBUG-24133 Change-Id: Ica89d4b0922dea5f2bea513ab8e4373bc52f7250 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/cppeditor/builtineditordocumentprocessor.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index 625bed9c1be..2c58182996d 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -264,6 +264,13 @@ void BuiltinEditorDocumentProcessor::onParserFinished(CPlusPlus::Document::Ptr d const auto source = createSemanticInfoSource(false); QTC_CHECK(source.snapshot.contains(document->filePath())); m_semanticInfoUpdater.updateDetached(source); + + const Utils::FilePaths deps + = CppModelManager::instance()->snapshot().filesDependingOn(document->filePath()); + for (const Utils::FilePath &dep : deps) { + if (const auto processor = CppModelManager::cppEditorDocumentProcessor(dep)) + processor->run(); + } } void BuiltinEditorDocumentProcessor::onSemanticInfoUpdated(const SemanticInfo semanticInfo) From 1d69f943aae6abbd0ea94c5130c82fe112abf618 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 14:06:15 +0200 Subject: [PATCH 0790/1447] Tasking::Process: Rename Process into ProcessTask Rename QtcProcessAdapter into ProcessTaskAdapter. Task-number: QTCREATORBUG-29102 Change-Id: I1902c7176da75db60d70125f505084a2ea5ba774 Reviewed-by: hjk --- src/libs/utils/filestreamer.cpp | 6 +++--- src/libs/utils/qtcprocess.cpp | 4 ++-- src/libs/utils/qtcprocess.h | 6 +++--- src/plugins/autotest/testrunner.cpp | 2 +- src/plugins/boot2qt/qdbmakedefaultappstep.cpp | 2 +- .../boot2qt/qdbstopapplicationstep.cpp | 2 +- src/plugins/clangtools/clangtoolrunner.cpp | 2 +- src/plugins/git/branchmodel.cpp | 4 ++-- src/plugins/git/branchview.cpp | 4 ++-- src/plugins/git/gitclient.cpp | 20 +++++++++---------- src/plugins/git/gitclient.h | 2 +- src/plugins/mercurial/mercurialclient.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 4 ++-- .../qnx/qnxdeployqtlibrariesdialog.cpp | 6 +++--- src/plugins/qnx/qnxdevicetester.cpp | 2 +- src/plugins/qnx/slog2inforunner.cpp | 6 +++--- .../remotelinux/customcommanddeploystep.cpp | 2 +- .../remotelinux/genericdirectuploadstep.cpp | 4 ++-- src/plugins/remotelinux/linuxdevicetester.cpp | 6 +++--- src/plugins/remotelinux/rsyncdeploystep.cpp | 2 +- .../remotelinux/tarpackagedeploystep.cpp | 2 +- src/plugins/subversion/subversionclient.cpp | 4 ++-- src/plugins/updateinfo/updateinfoplugin.cpp | 4 ++-- 23 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index c47eafaf7a8..a6a3e76ae62 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -93,7 +93,7 @@ private: emit readyRead(processPtr->readAllRawStandardOutput()); }); }; - return Process(setup); + return ProcessTask(setup); } TaskItem localTask() final { const auto setup = [this](AsyncTask &async) { @@ -264,7 +264,7 @@ private: delete m_writeBuffer; m_writeBuffer = nullptr; }; - return Process(setup, finalize, finalize); + return ProcessTask(setup, finalize, finalize); } TaskItem localTask() final { const auto setup = [this](AsyncTask &async) { @@ -316,7 +316,7 @@ static Group sameRemoteDeviceTransferTask(const FilePath &source, const FilePath const FilePath cp = source.withNewPath("cp"); process.setCommand({cp, args, OsType::OsTypeLinux}); }; - return {Process(setup)}; + return {ProcessTask(setup)}; } static Group interDeviceTransferTask(const FilePath &source, const FilePath &destination) diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 5220e8b5d56..593c4456480 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -2146,14 +2146,14 @@ void QtcProcessPrivate::storeEventLoopDebugInfo(const QVariant &value) setProperty(QTC_PROCESS_BLOCKING_TYPE, value); } -QtcProcessAdapter::QtcProcessAdapter() +ProcessTaskAdapter::ProcessTaskAdapter() { connect(task(), &QtcProcess::done, this, [this] { emit done(task()->result() == ProcessResult::FinishedWithSuccess); }); } -void QtcProcessAdapter::start() +void ProcessTaskAdapter::start() { task()->start(); } diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index e016b50d613..5e39453e38f 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -207,13 +207,13 @@ public: std::function systemEnvironmentForBinary; }; -class QTCREATOR_UTILS_EXPORT QtcProcessAdapter : public Tasking::TaskAdapter +class QTCREATOR_UTILS_EXPORT ProcessTaskAdapter : public Tasking::TaskAdapter { public: - QtcProcessAdapter(); + ProcessTaskAdapter(); void start() final; }; } // namespace Utils -QTC_DECLARE_CUSTOM_TASK(Process, Utils::QtcProcessAdapter); +QTC_DECLARE_CUSTOM_TASK(ProcessTask, Utils::ProcessTaskAdapter); diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 26ef727fd36..875549192f2 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -447,7 +447,7 @@ void TestRunner::runTestsHelper() optional, Storage(storage), OnGroupSetup(onGroupSetup), - Process(onSetup, onDone, onDone) + ProcessTask(onSetup, onDone, onDone) }; tasks.append(group); } diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp index ffc1c4c487f..8442fd03463 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp @@ -68,7 +68,7 @@ private: const auto errorHandler = [this](const QtcProcess &process) { addErrorMessage(Tr::tr("Remote process failed: %1").arg(process.errorString())); }; - return Group { Process(setupHandler, doneHandler, errorHandler) }; + return Group { ProcessTask(setupHandler, doneHandler, errorHandler) }; } bool m_makeDefault = true; diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index ac67385a7be..deeb535576b 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -71,7 +71,7 @@ Group QdbStopApplicationStep::deployRecipe() addErrorMessage(failureMessage); } }; - return Group { Process(setupHandler, doneHandler, errorHandler) }; + return Group { ProcessTask(setupHandler, doneHandler, errorHandler) }; } // QdbStopApplicationStepFactory diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 827cb9672b1..5866bcae944 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -187,7 +187,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, OnGroupSetup(onGroupSetup), Group { optional, - Process(onProcessSetup, onProcessDone, onProcessError) + ProcessTask(onProcessSetup, onProcessDone, onProcessError) } }; return group; diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 7b57df0739d..f10b6abd224 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -414,7 +414,7 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) } using namespace Tasking; - const Process topRevisionProc = + const ProcessTask topRevisionProc = d->client->topRevision(workingDirectory, [=](const QString &ref, const QDateTime &dateTime) { d->currentSha = ref; @@ -471,7 +471,7 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) const Group root { topRevisionProc, - Process(setupForEachRef, forEachRefDone, forEachRefError), + ProcessTask(setupForEachRef, forEachRefDone, forEachRefError), OnGroupDone(finalize), OnGroupError(finalize) }; diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index 2975f3c9eec..34f9b546cd3 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -549,7 +549,7 @@ TaskTree *BranchView::onFastForwardMerge(const std::function &callback) storage->mergeBase = process.cleanedStdOut().trimmed(); }; - const Process topRevisionProc = client->topRevision( + const ProcessTask topRevisionProc = client->topRevision( m_repository, [storage](const QString &revision, const QDateTime &) { storage->topRevision = revision; @@ -558,7 +558,7 @@ TaskTree *BranchView::onFastForwardMerge(const std::function &callback) const Group root { Storage(storage), parallel, - Process(setupMergeBase, onMergeBaseDone), + ProcessTask(setupMergeBase, onMergeBaseDone), topRevisionProc, OnGroupDone([storage, callback] { if (storage->mergeBase == storage->topRevision) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 6ac72e8946d..cc42faa9f87 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -176,7 +176,7 @@ GitDiffEditorController::GitDiffEditorController(IDocument *document, const Group root { Storage(diffInputStorage), - Process(setupDiff, onDiffDone), + ProcessTask(setupDiff, onDiffDone), postProcessTask() }; setReloadRecipe(root); @@ -267,8 +267,8 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin Group { parallel, continueOnDone, - Process(setupStaged, onStagedDone), - Process(setupUnstaged, onUnstagedDone), + ProcessTask(setupStaged, onStagedDone), + ProcessTask(setupUnstaged, onUnstagedDone), OnGroupDone(onStagingDone) }, postProcessTask() @@ -442,7 +442,7 @@ ShowController::ShowController(IDocument *document, const QString &id) using namespace std::placeholders; QList tasks {parallel, continueOnDone, OnGroupError(onFollowsError)}; for (int i = 0, total = parents.size(); i < total; ++i) { - tasks.append(Process(std::bind(setupFollow, _1, parents.at(i)), + tasks.append(ProcessTask(std::bind(setupFollow, _1, parents.at(i)), std::bind(onFollowDone, _1, i))); } taskTree.setupRoot(tasks); @@ -465,18 +465,18 @@ ShowController::ShowController(IDocument *document, const QString &id) OnGroupSetup([this] { setStartupFile(VcsBase::source(this->document()).toString()); }), Group { optional, - Process(setupDescription, onDescriptionDone), + ProcessTask(setupDescription, onDescriptionDone), Group { parallel, optional, OnGroupSetup(desciptionDetailsSetup), - Process(setupBranches, onBranchesDone, onBranchesError), - Process(setupPrecedes, onPrecedesDone, onPrecedesError), + ProcessTask(setupBranches, onBranchesDone, onBranchesError), + ProcessTask(setupPrecedes, onPrecedesDone, onPrecedesError), Tree(setupFollows) } }, Group { - Process(setupDiff, onDiffDone), + ProcessTask(setupDiff, onDiffDone), postProcessTask() } }; @@ -1730,7 +1730,7 @@ bool GitClient::synchronousRevParseCmd(const FilePath &workingDirectory, const Q } // Retrieve head revision -Utils::Tasking::Process GitClient::topRevision( +Utils::Tasking::ProcessTask GitClient::topRevision( const FilePath &workingDirectory, const std::function &callback) { @@ -1751,7 +1751,7 @@ Utils::Tasking::Process GitClient::topRevision( callback(output.first(), dateTime); }; - return Process(setupProcess, onProcessDone); + return ProcessTask(setupProcess, onProcessDone); } bool GitClient::isRemoteCommit(const FilePath &workingDirectory, const QString &commit) diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index a43c25a7426..0c4e4126255 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -242,7 +242,7 @@ public: QString synchronousTopic(const Utils::FilePath &workingDirectory) const; bool synchronousRevParseCmd(const Utils::FilePath &workingDirectory, const QString &ref, QString *output, QString *errorMessage = nullptr) const; - Utils::Tasking::Process topRevision( + Utils::Tasking::ProcessTask topRevision( const Utils::FilePath &workingDirectory, const std::function &callback); bool isRemoteCommit(const Utils::FilePath &workingDirectory, const QString &commit); diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index fd03bd2b2b6..0eb212f856a 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -65,7 +65,7 @@ MercurialDiffEditorController::MercurialDiffEditorController(IDocument *document const Group root { Storage(diffInputStorage), - Process(setupDiff, onDiffDone), + ProcessTask(setupDiff, onDiffDone), postProcessTask() }; setReloadRecipe(root); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 62c0f78dc99..3990fb8f9a0 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -330,9 +330,9 @@ void QMakeStep::doRun() emit buildConfiguration()->buildDirectoryInitialized(); }; - QList processList = {Process(setupQMake, onDone, onError)}; + QList processList = {ProcessTask(setupQMake, onDone, onError)}; if (m_runMakeQmake) - processList << Process(setupMakeQMake, onDone, onError); + processList << ProcessTask(setupMakeQMake, onDone, onError); processList << OnGroupDone(onGroupDone); runTaskTree(Group(processList)); diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 78d752efb07..65caee381ab 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -142,7 +142,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::checkDirTask() } m_checkResult = CheckResult::SkipRemoveDir; }; - return Process(setupHandler, doneHandler, errorHandler); + return ProcessTask(setupHandler, doneHandler, errorHandler); } TaskItem QnxDeployQtLibrariesDialogPrivate::removeDirTask() @@ -159,7 +159,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::removeDirTask() m_deployLogWindow->appendPlainText(Tr::tr("Connection failed: %1") .arg(process.errorString())); }; - return Process(setupHandler, {}, errorHandler); + return ProcessTask(setupHandler, {}, errorHandler); } TaskItem QnxDeployQtLibrariesDialogPrivate::uploadTask() @@ -212,7 +212,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::chmodTask(const DeployableFile &file .arg(file.remoteFilePath(), process.cleanedStdErr())); } }; - return Process(setupHandler, {}, errorHandler); + return ProcessTask(setupHandler, {}, errorHandler); } TaskItem QnxDeployQtLibrariesDialogPrivate::chmodTree() diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp index 1fd755138de..9e9e0524e2c 100644 --- a/src/plugins/qnx/qnxdevicetester.cpp +++ b/src/plugins/qnx/qnxdevicetester.cpp @@ -62,7 +62,7 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) : Tr::tr("Files cannot be created in %1.").arg(Constants::QNX_TMP_DIR); emit errorMessage(message + '\n'); }; - setExtraTests({Process(setupHandler, doneHandler, errorHandler)}); + setExtraTests({ProcessTask(setupHandler, doneHandler, errorHandler)}); RemoteLinux::GenericLinuxDeviceTester::testDevice(device); } diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index e350c75f6ec..0d17b872c96 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -69,9 +69,9 @@ void Slog2InfoRunner::start() }; const Tasking::Group root { - Process(testStartHandler, testDoneHandler, testErrorHandler), - Process(launchTimeStartHandler, launchTimeDoneHandler), - Process(logStartHandler, {}, logErrorHandler) + ProcessTask(testStartHandler, testDoneHandler, testErrorHandler), + ProcessTask(launchTimeStartHandler, launchTimeDoneHandler), + ProcessTask(logStartHandler, {}, logErrorHandler) }; m_taskTree.reset(new TaskTree(root)); diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index db8f9988b2b..80e8ded988a 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -81,7 +81,7 @@ Group CustomCommandDeployStep::deployRecipe() .arg(process.exitCode())); } }; - return Group { Process(setupHandler, doneHandler, errorHandler) }; + return Group { ProcessTask(setupHandler, doneHandler, errorHandler) }; } diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 3e3f40677f4..c1abc891b7a 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -170,7 +170,7 @@ TaskItem GenericDirectUploadStep::statTask(UploadStorage *storage, const QDateTime timestamp = timestampFromStat(file, proc); statEndHandler(storage, file, timestamp); }; - return Process(setupHandler, endHandler, endHandler); + return ProcessTask(setupHandler, endHandler, endHandler); } TaskItem GenericDirectUploadStep::statTree(const TreeStorage &storage, @@ -245,7 +245,7 @@ TaskItem GenericDirectUploadStep::chmodTask(const DeployableFile &file) .arg(file.remoteFilePath(), process.cleanedStdErr())); } }; - return Process(setupHandler, {}, errorHandler); + return ProcessTask(setupHandler, {}, errorHandler); } TaskItem GenericDirectUploadStep::chmodTree(const TreeStorage &storage) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 73a9c3f2b1f..f4df0b9bac5 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -111,7 +111,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::echoTask(const QString &contents) cons else emit q->errorMessage(Tr::tr("echo failed.") + '\n'); }; - return Process(setup, done, error); + return ProcessTask(setup, done, error); } TaskItem GenericLinuxDeviceTesterPrivate::unameTask() const @@ -132,7 +132,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::unameTask() const }; return Tasking::Group { optional, - Process(setup, done, error) + ProcessTask(setup, done, error) }; } @@ -249,7 +249,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::commandTask(const QString &commandName : Tr::tr("%1 not found.").arg(commandName); emit q->errorMessage(message); }; - return Process(setup, done, error); + return ProcessTask(setup, done, error); } TaskItem GenericLinuxDeviceTesterPrivate::commandTasks() const diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 0d81a181b02..193a112cb55 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -111,7 +111,7 @@ TaskItem RsyncDeployStep::mkdirTask() addErrorMessage(Tr::tr("Deploy via rsync: failed to create remote directories:") + '\n' + finalMessage); }; - return Process(setupHandler, {}, errorHandler); + return ProcessTask(setupHandler, {}, errorHandler); } TaskItem RsyncDeployStep::transferTask() diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index 9f6022e8160..795acabe0de 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -112,7 +112,7 @@ TaskItem TarPackageDeployStep::installTask() const auto errorHandler = [this](const QtcProcess &process) { addErrorMessage(Tr::tr("Installing package failed.") + process.errorString()); }; - return Process(setupHandler, doneHandler, errorHandler); + return ProcessTask(setupHandler, doneHandler, errorHandler); } Group TarPackageDeployStep::deployRecipe() diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 3602e1f4b83..ad657188f19 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -211,10 +211,10 @@ SubversionDiffEditorController::SubversionDiffEditorController(IDocument *docume parallel, Group { optional, - Process(setupDescription, onDescriptionDone, onDescriptionError) + ProcessTask(setupDescription, onDescriptionDone, onDescriptionError) }, Group { - Process(setupDiff, onDiffDone), + ProcessTask(setupDiff, onDiffDone), postProcessTask() } }; diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index decce3a47a9..435deb4812f 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -134,7 +134,7 @@ void UpdateInfoPlugin::startCheckForUpdates() d->m_updateOutput = process.cleanedStdOut(); }; - QList tasks { Process(setupUpdate, updateDone) }; + QList tasks { ProcessTask(setupUpdate, updateDone) }; if (d->m_settings.checkForQtVersions) { const auto setupPackages = [doSetup](QtcProcess &process) { doSetup(process, {"se", "qt[.]qt[0-9][.][0-9]+$", "-g", "*=false,ifw.package.*=true"}); @@ -142,7 +142,7 @@ void UpdateInfoPlugin::startCheckForUpdates() const auto packagesDone = [this](const QtcProcess &process) { d->m_packagesOutput = process.cleanedStdOut(); }; - tasks << Process(setupPackages, packagesDone); + tasks << ProcessTask(setupPackages, packagesDone); } d->m_taskTree.reset(new TaskTree(Group{tasks})); From 187a7640def4f137762547d82638c7f169f2cfe4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 14:33:12 +0200 Subject: [PATCH 0791/1447] Tasking::Async: Rename Async into AsyncTask Rename Utils::AsyncTask into Utils::Async. Rename AsyncTaskBase into AsyncTask. Task-number: QTCREATORBUG-29102 Change-Id: I3aa24d84138c19922d4f61b1c9cf15bc8989f60e Reviewed-by: hjk --- src/libs/utils/asynctask.h | 19 +++--- src/libs/utils/filestreamer.cpp | 18 +++--- src/plugins/autotest/testcodeparser.cpp | 6 +- .../clangcodemodel/clangdlocatorfilters.cpp | 4 +- src/plugins/coreplugin/actionsfilter.cpp | 4 +- .../coreplugin/locator/directoryfilter.cpp | 6 +- .../coreplugin/locator/filesystemfilter.cpp | 4 +- .../coreplugin/locator/ilocatorfilter.cpp | 6 +- .../locator/opendocumentsfilter.cpp | 4 +- .../locator/spotlightlocatorfilter.cpp | 4 +- src/plugins/cppeditor/cpplocatorfilter.cpp | 8 +-- src/plugins/cppeditor/cppprojectupdater.cpp | 6 +- src/plugins/debugger/loadcoredialog.cpp | 4 +- src/plugins/diffeditor/diffeditorplugin.cpp | 6 +- .../diffeditor/sidebysidediffeditorwidget.cpp | 4 +- .../diffeditor/sidebysidediffeditorwidget.h | 4 +- .../diffeditor/unifieddiffeditorwidget.cpp | 4 +- .../diffeditor/unifieddiffeditorwidget.h | 4 +- src/plugins/help/helpindexfilter.cpp | 6 +- src/plugins/languageclient/locatorfilter.cpp | 8 +-- src/plugins/projectexplorer/extracompiler.cpp | 6 +- .../qmljstools/qmljsfunctionfilter.cpp | 4 +- .../vcsbase/vcsbasediffeditorcontroller.cpp | 8 +-- tests/auto/utils/asynctask/tst_asynctask.cpp | 58 +++++++++---------- tests/auto/utils/tasktree/tst_tasktree.cpp | 34 +++++------ tests/manual/tasktree/main.cpp | 8 +-- 26 files changed, 123 insertions(+), 124 deletions(-) diff --git a/src/libs/utils/asynctask.h b/src/libs/utils/asynctask.h index d7c51a66fae..07b38487495 100644 --- a/src/libs/utils/asynctask.h +++ b/src/libs/utils/asynctask.h @@ -115,7 +115,7 @@ const QFuture &onFinished(const QFuture &future, QObject *guard, Function return future; } -class QTCREATOR_UTILS_EXPORT AsyncTaskBase : public QObject +class QTCREATOR_UTILS_EXPORT AsyncBase : public QObject { Q_OBJECT @@ -126,15 +126,14 @@ signals: }; template -class AsyncTask : public AsyncTaskBase +class Async : public AsyncBase { public: - AsyncTask() { - connect(&m_watcher, &QFutureWatcherBase::finished, this, &AsyncTaskBase::done); - connect(&m_watcher, &QFutureWatcherBase::resultReadyAt, - this, &AsyncTaskBase::resultReadyAt); + Async() { + connect(&m_watcher, &QFutureWatcherBase::finished, this, &AsyncBase::done); + connect(&m_watcher, &QFutureWatcherBase::resultReadyAt, this, &AsyncBase::resultReadyAt); } - ~AsyncTask() + ~Async() { if (isDone()) return; @@ -199,11 +198,11 @@ private: }; template -class AsyncTaskAdapter : public Tasking::TaskAdapter> +class AsyncTaskAdapter : public Tasking::TaskAdapter> { public: AsyncTaskAdapter() { - this->connect(this->task(), &AsyncTaskBase::done, this, [this] { + this->connect(this->task(), &AsyncBase::done, this, [this] { emit this->done(!this->task()->isCanceled()); }); } @@ -212,4 +211,4 @@ public: } // namespace Utils -QTC_DECLARE_CUSTOM_TEMPLATE_TASK(Async, AsyncTaskAdapter); +QTC_DECLARE_CUSTOM_TEMPLATE_TASK(AsyncTask, AsyncTaskAdapter); diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index a6a3e76ae62..cdc192422a9 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -96,14 +96,14 @@ private: return ProcessTask(setup); } TaskItem localTask() final { - const auto setup = [this](AsyncTask &async) { + const auto setup = [this](Async &async) { async.setConcurrentCallData(localRead, m_filePath); - AsyncTask *asyncPtr = &async; - connect(asyncPtr, &AsyncTaskBase::resultReadyAt, this, [=](int index) { + Async *asyncPtr = &async; + connect(asyncPtr, &AsyncBase::resultReadyAt, this, [=](int index) { emit readyRead(asyncPtr->resultAt(index)); }); }; - return Async(setup); + return AsyncTask(setup); } }; @@ -267,16 +267,16 @@ private: return ProcessTask(setup, finalize, finalize); } TaskItem localTask() final { - const auto setup = [this](AsyncTask &async) { + const auto setup = [this](Async &async) { m_writeBuffer = new WriteBuffer(isBuffered(), &async); async.setConcurrentCallData(localWrite, m_filePath, m_writeData, m_writeBuffer); emit started(); }; - const auto finalize = [this](const AsyncTask &) { + const auto finalize = [this](const Async &) { delete m_writeBuffer; m_writeBuffer = nullptr; }; - return Async(setup, finalize, finalize); + return AsyncTask(setup, finalize, finalize); } bool isBuffered() const { return m_writeData.isEmpty(); } @@ -437,10 +437,10 @@ private: return Writer(setup); } TaskItem transferTask() { - const auto setup = [this](AsyncTask &async) { + const auto setup = [this](Async &async) { async.setConcurrentCallData(transfer, m_source, m_destination); }; - return Async(setup); + return AsyncTask(setup); } }; diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index b6a87c20383..b6b6eaea01e 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -361,17 +361,17 @@ void TestCodeParser::scanForTests(const QSet &filePaths, QList tasks{ParallelLimit(std::max(QThread::idealThreadCount() / 4, 1))}; for (const FilePath &file : filteredFiles) { - const auto setup = [this, codeParsers, file](AsyncTask &async) { + const auto setup = [this, codeParsers, file](Async &async) { async.setConcurrentCallData(parseFileForTests, codeParsers, file); async.setPriority(QThread::LowestPriority); async.setFutureSynchronizer(&m_futureSynchronizer); }; - const auto onDone = [this](const AsyncTask &async) { + const auto onDone = [this](const Async &async) { const QList results = async.results(); for (const TestParseResultPtr &result : results) emit testParseResultReady(result); }; - tasks.append(Async(setup, onDone)); + tasks.append(AsyncTask(setup, onDone)); } m_taskTree.reset(new TaskTree{tasks}); const auto onDone = [this] { m_taskTree.release()->deleteLater(); onFinished(true); }; diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 1f4db567def..4dd0b3b9994 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -443,7 +443,7 @@ LocatorMatcherTask currentDocumentMatcher() *resultStorage = request.currentDocumentSymbolsData(); }; - const auto onFilterSetup = [=](AsyncTask &async) { + const auto onFilterSetup = [=](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage, TextDocument::currentTextDocument()->plainText()); @@ -452,7 +452,7 @@ LocatorMatcherTask currentDocumentMatcher() const Group root { Storage(resultStorage), CurrentDocumentSymbolsRequest(onQuerySetup, onQueryDone), - Async(onFilterSetup) + AsyncTask(onFilterSetup) }; return {root, storage}; } diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index 6930e6af018..3d04766c93b 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -180,7 +180,7 @@ LocatorMatcherTasks ActionsFilter::matchers() TreeStorage storage; - const auto onSetup = [this, storage](AsyncTask &async) { + const auto onSetup = [this, storage](Async &async) { m_entries.clear(); m_indexes.clear(); QList processedMenus; @@ -197,7 +197,7 @@ LocatorMatcherTasks ActionsFilter::matchers() return TaskAction::Continue; }; - return {{Async(onSetup), storage}}; + return {{AsyncTask(onSetup), storage}}; } diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 26a9455ca57..2b09b295425 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -87,17 +87,17 @@ DirectoryFilter::DirectoryFilter(Id id) updateFileIterator(); return TaskAction::StopWithDone; // Group stops, skips async task }; - const auto asyncSetup = [this](AsyncTask &async) { + const auto asyncSetup = [this](Async &async) { async.setConcurrentCallData(&refresh, m_directories, m_filters, m_exclusionFilters, displayName()); }; - const auto asyncDone = [this](const AsyncTask &async) { + const auto asyncDone = [this](const Async &async) { m_files = async.isResultAvailable() ? async.result() : FilePaths(); updateFileIterator(); }; const Group root { OnGroupSetup(groupSetup), - Async(asyncSetup, asyncDone) + AsyncTask(asyncSetup, asyncDone) }; setRefreshRecipe(root); } diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 4f3f349bcdc..5bd2d1a155a 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -323,7 +323,7 @@ LocatorMatcherTasks FileSystemFilter::matchers() TreeStorage storage; - const auto onSetup = [this, storage](AsyncTask &async) { + const auto onSetup = [this, storage](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matches, *storage, @@ -332,7 +332,7 @@ LocatorMatcherTasks FileSystemFilter::matchers() m_includeHidden); }; - return {{Async(onSetup), storage}}; + return {{AsyncTask(onSetup), storage}}; } void FileSystemFilter::prepareSearch(const QString &entry) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index b4809d897c7..70c70bbd963 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -1529,7 +1529,7 @@ LocatorMatcherTask LocatorFileCache::matcher() const TreeStorage storage; std::weak_ptr weak = d; - const auto onSetup = [storage, weak](AsyncTask &async) { + const auto onSetup = [storage, weak](Async &async) { auto that = weak.lock(); if (!that) // LocatorMatcher is running after *this LocatorFileCache was destructed. return TaskAction::StopWithDone; @@ -1543,7 +1543,7 @@ LocatorMatcherTask LocatorFileCache::matcher() const async.setConcurrentCallData(&filter, *storage, *that); return TaskAction::Continue; }; - const auto onDone = [weak](const AsyncTask &async) { + const auto onDone = [weak](const Async &async) { auto that = weak.lock(); if (!that) return; // LocatorMatcherTask finished after *this LocatorFileCache was destructed. @@ -1560,7 +1560,7 @@ LocatorMatcherTask LocatorFileCache::matcher() const that->update(async.result()); }; - return {Async(onSetup, onDone), storage}; + return {AsyncTask(onSetup, onDone), storage}; } } // Core diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 2fd479568ab..7cf3b986e8c 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -79,14 +79,14 @@ LocatorMatcherTasks OpenDocumentsFilter::matchers() TreeStorage storage; - const auto onSetup = [storage](AsyncTask &async) { + const auto onSetup = [storage](Async &async) { const QList editorsData = Utils::transform(DocumentModel::entries(), [](const DocumentModel::Entry *e) { return Entry{e->filePath(), e->displayName()}; }); async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matchEditors, *storage, editorsData); }; - return {{Async(onSetup), storage}}; + return {{AsyncTask(onSetup), storage}}; } void OpenDocumentsFilter::slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index f22cfd5c11e..1d57a0aed7c 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -299,7 +299,7 @@ LocatorMatcherTasks SpotlightLocatorFilter::matchers() TreeStorage storage; const auto onSetup = [storage, command = m_command, insensArgs = m_arguments, - sensArgs = m_caseSensitiveArguments](AsyncTask &async) { + sensArgs = m_caseSensitiveArguments](Async &async) { const Link link = Link::fromString(storage->input(), true); const FilePath input = link.targetFilePath; if (input.isEmpty()) @@ -316,7 +316,7 @@ LocatorMatcherTasks SpotlightLocatorFilter::matchers() return TaskAction::Continue; }; - return {{Async(onSetup), storage}}; + return {{AsyncTask(onSetup), storage}}; } void SpotlightLocatorFilter::prepareSearch(const QString &entry) diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index c13948bb3e9..c257444ce12 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -108,11 +108,11 @@ LocatorMatcherTask locatorMatcher(IndexItem::ItemType type, const EntryFromIndex TreeStorage storage; - const auto onSetup = [=](AsyncTask &async) { + const auto onSetup = [=](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matchesFor, *storage, type, converter); }; - return {Async(onSetup), storage}; + return {AsyncTask(onSetup), storage}; } LocatorMatcherTask allSymbolsMatcher() @@ -304,11 +304,11 @@ LocatorMatcherTask currentDocumentMatcher() TreeStorage storage; - const auto onSetup = [=](AsyncTask &async) { + const auto onSetup = [=](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matchesForCurrentDocument, *storage, currentFileName()); }; - return {Async(onSetup), storage}; + return {AsyncTask(onSetup), storage}; } using MatcherCreator = std::function; diff --git a/src/plugins/cppeditor/cppprojectupdater.cpp b/src/plugins/cppeditor/cppprojectupdater.cpp index 6bab2ec3c3c..dbea7361df9 100644 --- a/src/plugins/cppeditor/cppprojectupdater.cpp +++ b/src/plugins/cppeditor/cppprojectupdater.cpp @@ -58,16 +58,16 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo, ProjectInfo::ConstPtr projectInfo = nullptr; }; const TreeStorage storage; - const auto setupInfoGenerator = [=](AsyncTask &async) { + const auto setupInfoGenerator = [=](Async &async) { async.setConcurrentCallData(infoGenerator); async.setFutureSynchronizer(&m_futureSynchronizer); }; - const auto onInfoGeneratorDone = [=](const AsyncTask &async) { + const auto onInfoGeneratorDone = [=](const Async &async) { if (async.isResultAvailable()) storage->projectInfo = async.result(); }; QList tasks{parallel}; - tasks.append(Async(setupInfoGenerator, onInfoGeneratorDone)); + tasks.append(AsyncTask(setupInfoGenerator, onInfoGeneratorDone)); for (QPointer compiler : compilers) { if (compiler && compiler->isDirty()) tasks.append(compiler->compileFileItem()); diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index 85a81a9418d..e481aef4b78 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -249,11 +249,11 @@ void AttachCoreDialog::accepted() const Group root = { parallel, - Async{[=](auto &task) { + AsyncTask{[=](auto &task) { task.setConcurrentCallData(copyFileAsync, this->coreFile()); }, [=](const auto &task) { d->coreFileResult = task.result(); }}, - Async{[=](auto &task) { + AsyncTask{[=](auto &task) { task.setConcurrentCallData(copyFileAsync, this->symbolFile()); }, [=](const auto &task) { d->symbolFileResult = task.result(); }}, diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index eed5a6d0e4a..07410aee6f3 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -114,12 +114,12 @@ DiffFilesController::DiffFilesController(IDocument *document) const auto setupTree = [this, storage](TaskTree &taskTree) { QList> *outputList = storage.activeStorage(); - const auto setupDiff = [this](AsyncTask &async, const ReloadInput &reloadInput) { + const auto setupDiff = [this](Async &async, const ReloadInput &reloadInput) { async.setConcurrentCallData( DiffFile(ignoreWhitespace(), contextLineCount()), reloadInput); async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); }; - const auto onDiffDone = [outputList](const AsyncTask &async, int i) { + const auto onDiffDone = [outputList](const Async &async, int i) { if (async.isResultAvailable()) (*outputList)[i] = async.result(); }; @@ -130,7 +130,7 @@ DiffFilesController::DiffFilesController(IDocument *document) using namespace std::placeholders; QList tasks {parallel, optional}; for (int i = 0; i < inputList.size(); ++i) { - tasks.append(Async(std::bind(setupDiff, _1, inputList.at(i)), + tasks.append(AsyncTask(std::bind(setupDiff, _1, inputList.at(i)), std::bind(onDiffDone, _1, i))); } taskTree.setupRoot(tasks); diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index f1467f6ea27..8a69550232f 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -869,11 +869,11 @@ void SideBySideDiffEditorWidget::restoreState() void SideBySideDiffEditorWidget::showDiff() { - m_asyncTask.reset(new AsyncTask()); + m_asyncTask.reset(new Async()); m_asyncTask->setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); m_controller.setBusyShowing(true); - connect(m_asyncTask.get(), &AsyncTaskBase::done, this, [this] { + connect(m_asyncTask.get(), &AsyncBase::done, this, [this] { if (m_asyncTask->isCanceled() || !m_asyncTask->isResultAvailable()) { for (SideDiffEditorWidget *editor : m_editor) editor->clearAll(Tr::tr("Retrieving data failed.")); diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index c12025a6c00..f164d865798 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -18,7 +18,7 @@ class TextEditorWidget; namespace Utils { template -class AsyncTask; +class Async; } QT_BEGIN_NAMESPACE @@ -141,7 +141,7 @@ private: bool m_horizontalSync = false; - std::unique_ptr> m_asyncTask; + std::unique_ptr> m_asyncTask; }; } // namespace Internal diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index d914ef59cb5..43d9f4c749d 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -452,10 +452,10 @@ void UnifiedDiffEditorWidget::showDiff() return; } - m_asyncTask.reset(new AsyncTask()); + m_asyncTask.reset(new Async()); m_asyncTask->setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); m_controller.setBusyShowing(true); - connect(m_asyncTask.get(), &AsyncTaskBase::done, this, [this] { + connect(m_asyncTask.get(), &AsyncBase::done, this, [this] { if (m_asyncTask->isCanceled() || !m_asyncTask->isResultAvailable()) { setPlainText(Tr::tr("Retrieving data failed.")); } else { diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h index cbad273ab2f..ae7060b1446 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.h +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h @@ -12,7 +12,7 @@ namespace TextEditor { class FontSettings; } namespace Utils { template -class AsyncTask; +class Async; } QT_BEGIN_NAMESPACE @@ -112,7 +112,7 @@ private: DiffEditorWidgetController m_controller; QByteArray m_state; - std::unique_ptr> m_asyncTask; + std::unique_ptr> m_asyncTask; }; } // namespace Internal diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index a55cf0e6504..0556e970ac8 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -87,7 +87,7 @@ LocatorMatcherTasks HelpIndexFilter::matchers() TreeStorage storage; - const auto onSetup = [this, storage](AsyncTask &async) { + const auto onSetup = [this, storage](Async &async) { if (m_needsUpdate) { m_needsUpdate = false; LocalHelpManager::setupGuiHelpEngine(); @@ -100,14 +100,14 @@ LocatorMatcherTasks HelpIndexFilter::matchers() async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matches, *storage, cache, m_icon); }; - const auto onDone = [this, storage](const AsyncTask &async) { + const auto onDone = [this, storage](const Async &async) { if (async.isResultAvailable()) { m_lastIndicesCache = async.result(); m_lastEntry = storage->input(); } }; - return {{Async(onSetup, onDone), storage}}; + return {{AsyncTask(onSetup, onDone), storage}}; } void HelpIndexFilter::prepareSearch(const QString &entry) diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 16c0d52c72d..158d7476dbb 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -75,7 +75,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, *resultStorage = result->toList(); }; - const auto onFilterSetup = [=](AsyncTask &async) { + const auto onFilterSetup = [=](Async &async) { const QList results = *resultStorage; if (results.isEmpty()) return TaskAction::StopWithDone; @@ -87,7 +87,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, const Group root { Storage(resultStorage), SymbolRequest(onQuerySetup, onQueryDone), - Async(onFilterSetup) + AsyncTask(onFilterSetup) }; return {root, storage}; } @@ -138,7 +138,7 @@ LocatorMatcherTask currentDocumentMatcher() *resultStorage = request.currentDocumentSymbolsData(); }; - const auto onFilterSetup = [=](AsyncTask &async) { + const auto onFilterSetup = [=](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage); }; @@ -146,7 +146,7 @@ LocatorMatcherTask currentDocumentMatcher() const Group root { Storage(resultStorage), CurrentDocumentSymbolsRequest(onQuerySetup, onQueryDone), - Async(onFilterSetup) + AsyncTask(onFilterSetup) }; return {root, storage}; } diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index 0f0953cb3e7..291493bcbfc 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -327,14 +327,14 @@ ProcessExtraCompiler::ProcessExtraCompiler(const Project *project, const FilePat Tasking::TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &provider) { - const auto setupTask = [=](AsyncTask &async) { + const auto setupTask = [=](Async &async) { async.setThreadPool(extraCompilerThreadPool()); // The passed synchronizer has cancelOnWait set to true by default. async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(&ProcessExtraCompiler::runInThread, this, command(), workingDirectory(), arguments(), provider, buildEnvironment()); }; - const auto taskDone = [=](const AsyncTask &async) { + const auto taskDone = [=](const Async &async) { if (!async.isResultAvailable()) return; const FileNameToContentsHash data = async.result(); @@ -344,7 +344,7 @@ Tasking::TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &prov setContent(it.key(), it.value()); updateCompileTime(); }; - return Tasking::Async(setupTask, taskDone); + return Tasking::AsyncTask(setupTask, taskDone); } FilePath ProcessExtraCompiler::workingDirectory() const diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index d24b02156ba..ac173e515d1 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -82,12 +82,12 @@ LocatorMatcherTasks FunctionFilter::matchers() TreeStorage storage; - const auto onSetup = [storage, entries = m_data->entries()](AsyncTask &async) { + const auto onSetup = [storage, entries = m_data->entries()](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(matches, *storage, entries); }; - return {{Async(onSetup), storage}}; + return {{AsyncTask(onSetup), storage}}; } QList FunctionFilter::matchesFor(QFutureInterface &future, diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index 0735fee7296..e52fbb47c9f 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -48,7 +48,7 @@ Tasking::TaskItem VcsBaseDiffEditorController::postProcessTask() { using namespace Tasking; - const auto setupDiffProcessor = [this](AsyncTask> &async) { + const auto setupDiffProcessor = [this](Async> &async) { const QString *storage = inputStorage().activeStorage(); QTC_ASSERT(storage, qWarning("Using postProcessTask() requires putting inputStorage() " "into task tree's root group.")); @@ -56,14 +56,14 @@ Tasking::TaskItem VcsBaseDiffEditorController::postProcessTask() async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(&DiffUtils::readPatchWithPromise, inputData); }; - const auto onDiffProcessorDone = [this](const AsyncTask> &async) { + const auto onDiffProcessorDone = [this](const Async> &async) { setDiffFiles(async.isResultAvailable() ? async.result() : QList()); // TODO: We should set the right starting line here }; - const auto onDiffProcessorError = [this](const AsyncTask> &) { + const auto onDiffProcessorError = [this](const Async> &) { setDiffFiles({}); }; - return Async>(setupDiffProcessor, onDiffProcessorDone, onDiffProcessorError); + return AsyncTask>(setupDiffProcessor, onDiffProcessorDone, onDiffProcessorError); } void VcsBaseDiffEditorController::setupCommand(QtcProcess &process, const QStringList &args) const diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/asynctask/tst_asynctask.cpp index 37e33d5dcff..c438d1749b1 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/asynctask/tst_asynctask.cpp @@ -123,9 +123,9 @@ struct ConcurrentResultType template ::Type> -std::shared_ptr> createAsyncTask(Function &&function, Args &&...args) +std::shared_ptr> createAsyncTask(Function &&function, Args &&...args) { - auto asyncTask = std::make_shared>(); + auto asyncTask = std::make_shared>(); asyncTask->setConcurrentCallData(std::forward(function), std::forward(args)...); asyncTask->start(); return asyncTask; @@ -402,7 +402,7 @@ void tst_AsyncTask::futureSynchonizer() FutureSynchronizer synchronizer; synchronizer.setCancelOnWait(false); { - AsyncTask task; + Async task; task.setConcurrentCallData(lambda); task.setFutureSynchronizer(&synchronizer); task.start(); @@ -424,18 +424,18 @@ void tst_AsyncTask::taskTree() int value = 1; - const auto setupIntAsync = [&](AsyncTask &task) { + const auto setupIntAsync = [&](Async &task) { task.setConcurrentCallData(multiplyBy2, value); }; - const auto handleIntAsync = [&](const AsyncTask &task) { + const auto handleIntAsync = [&](const Async &task) { value = task.result(); }; const Group root { - Async(setupIntAsync, handleIntAsync), - Async(setupIntAsync, handleIntAsync), - Async(setupIntAsync, handleIntAsync), - Async(setupIntAsync, handleIntAsync), + AsyncTask(setupIntAsync, handleIntAsync), + AsyncTask(setupIntAsync, handleIntAsync), + AsyncTask(setupIntAsync, handleIntAsync), + AsyncTask(setupIntAsync, handleIntAsync), }; TaskTree tree(root); @@ -473,17 +473,17 @@ void tst_AsyncTask::mapReduce_data() s_sum = 0; s_results.append(s_sum); }; - const auto setupAsync = [](AsyncTask &task, int input) { + const auto setupAsync = [](Async &task, int input) { task.setConcurrentCallData(returnxx, input); }; - const auto setupAsyncWithFI = [](AsyncTask &task, int input) { + const auto setupAsyncWithFI = [](Async &task, int input) { task.setConcurrentCallData(returnxxWithPromise, input); }; - const auto setupAsyncWithTP = [this](AsyncTask &task, int input) { + const auto setupAsyncWithTP = [this](Async &task, int input) { task.setConcurrentCallData(returnxx, input); task.setThreadPool(&m_threadPool); }; - const auto handleAsync = [](const AsyncTask &task) { + const auto handleAsync = [](const Async &task) { s_sum += task.result(); s_results.append(task.result()); }; @@ -500,7 +500,7 @@ void tst_AsyncTask::mapReduce_data() using namespace Tasking; using namespace std::placeholders; - using SetupHandler = std::function &task, int input)>; + using SetupHandler = std::function &task, int input)>; using DoneHandler = std::function; const auto createTask = [=](const TaskItem &executeMode, @@ -509,11 +509,11 @@ void tst_AsyncTask::mapReduce_data() return Group { executeMode, OnGroupSetup(initTree), - Async(std::bind(setupHandler, _1, 1), handleAsync), - Async(std::bind(setupHandler, _1, 2), handleAsync), - Async(std::bind(setupHandler, _1, 3), handleAsync), - Async(std::bind(setupHandler, _1, 4), handleAsync), - Async(std::bind(setupHandler, _1, 5), handleAsync), + AsyncTask(std::bind(setupHandler, _1, 1), handleAsync), + AsyncTask(std::bind(setupHandler, _1, 2), handleAsync), + AsyncTask(std::bind(setupHandler, _1, 3), handleAsync), + AsyncTask(std::bind(setupHandler, _1, 4), handleAsync), + AsyncTask(std::bind(setupHandler, _1, 5), handleAsync), OnGroupDone(doneHandler) }; }; @@ -535,34 +535,34 @@ void tst_AsyncTask::mapReduce_data() QTest::newRow("SequentialWithFutureInterface") << sequentialRootWithFI << defaultSum << defaultResult; QTest::newRow("SequentialWithThreadPool") << sequentialRootWithTP << defaultSum << defaultResult; - const auto setupSimpleAsync = [](AsyncTask &task, int input) { + const auto setupSimpleAsync = [](Async &task, int input) { task.setConcurrentCallData([](int input) { return input * 2; }, input); }; - const auto handleSimpleAsync = [](const AsyncTask &task) { + const auto handleSimpleAsync = [](const Async &task) { s_sum += task.result() / 4.; s_results.append(s_sum); }; const Group simpleRoot = { sequential, OnGroupSetup([] { s_sum = 0; }), - Async(std::bind(setupSimpleAsync, _1, 1), handleSimpleAsync), - Async(std::bind(setupSimpleAsync, _1, 2), handleSimpleAsync), - Async(std::bind(setupSimpleAsync, _1, 3), handleSimpleAsync) + AsyncTask(std::bind(setupSimpleAsync, _1, 1), handleSimpleAsync), + AsyncTask(std::bind(setupSimpleAsync, _1, 2), handleSimpleAsync), + AsyncTask(std::bind(setupSimpleAsync, _1, 3), handleSimpleAsync) }; QTest::newRow("Simple") << simpleRoot << 3.0 << QList({.5, 1.5, 3.}); - const auto setupStringAsync = [](AsyncTask &task, const QString &input) { + const auto setupStringAsync = [](Async &task, const QString &input) { task.setConcurrentCallData([](const QString &input) -> int { return input.size(); }, input); }; - const auto handleStringAsync = [](const AsyncTask &task) { + const auto handleStringAsync = [](const Async &task) { s_sum /= task.result(); }; const Group stringRoot = { parallel, OnGroupSetup([] { s_sum = 90.0; }), - Async(std::bind(setupStringAsync, _1, "blubb"), handleStringAsync), - Async(std::bind(setupStringAsync, _1, "foo"), handleStringAsync), - Async(std::bind(setupStringAsync, _1, "blah"), handleStringAsync) + AsyncTask(std::bind(setupStringAsync, _1, "blubb"), handleStringAsync), + AsyncTask(std::bind(setupStringAsync, _1, "foo"), handleStringAsync), + AsyncTask(std::bind(setupStringAsync, _1, "blah"), handleStringAsync) }; QTest::newRow("String") << stringRoot << 1.5 << QList({}); } diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 5bf8dcc006e..465c7f6bbb0 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -13,8 +13,8 @@ using namespace std::literals::chrono_literals; using namespace Utils; using namespace Utils::Tasking; -using TestTask = AsyncTask; -using Test = Async; +using TestTask = Async; +using Test = AsyncTask; enum class Handler { Setup, @@ -198,7 +198,7 @@ template auto setupBarrierAdvance(const TreeStorage &storage, const SharedBarrierType &barrier, int taskId) { - return [storage, barrier, taskId](AsyncTask &async) { + return [storage, barrier, taskId](Async &async) { async.setFutureSynchronizer(s_futureSynchronizer); async.setConcurrentCallData(reportAndSleep); async.setProperty(s_taskIdProperty, taskId); @@ -1213,7 +1213,7 @@ void tst_TaskTree::testTree_data() Storage(storage), Storage(barrier), sequential, - Async(setupBarrierAdvance(storage, barrier, 1)), + AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), @@ -1236,7 +1236,7 @@ void tst_TaskTree::testTree_data() Storage(storage), Storage(barrier), parallel, - Async(setupBarrierAdvance(storage, barrier, 1)), + AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), @@ -1272,7 +1272,7 @@ void tst_TaskTree::testTree_data() Test(setupTask(2)), Test(setupTask(3)) }, - Async(setupBarrierAdvance(storage, barrier, 1)) + AsyncTask(setupBarrierAdvance(storage, barrier, 1)) }; const Log log3 { {2, Handler::GroupSetup}, @@ -1289,7 +1289,7 @@ void tst_TaskTree::testTree_data() Storage(storage), Storage(barrier), parallel, - Async(setupBarrierAdvance(storage, barrier, 1)), + AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), @@ -1319,8 +1319,8 @@ void tst_TaskTree::testTree_data() Storage(barrier), Storage(barrier2), parallel, - Async(setupBarrierAdvance(storage, barrier, 0)), - Async(setupBarrierAdvance(storage, barrier2, 0)), + AsyncTask(setupBarrierAdvance(storage, barrier, 0)), + AsyncTask(setupBarrierAdvance(storage, barrier2, 0)), Group { Group { parallel, @@ -1363,8 +1363,8 @@ void tst_TaskTree::testTree_data() Storage(storage), Storage(barrier), sequential, - Async(setupBarrierAdvance(storage, barrier, 1)), - Async(setupBarrierAdvance(storage, barrier, 2)), + AsyncTask(setupBarrierAdvance(storage, barrier, 1)), + AsyncTask(setupBarrierAdvance(storage, barrier, 2)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), @@ -1389,8 +1389,8 @@ void tst_TaskTree::testTree_data() Storage(storage), Storage(barrier), parallel, - Async(setupBarrierAdvance(storage, barrier, 0)), - Async(setupBarrierAdvance(storage, barrier, 0)), + AsyncTask(setupBarrierAdvance(storage, barrier, 0)), + AsyncTask(setupBarrierAdvance(storage, barrier, 0)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), @@ -1428,8 +1428,8 @@ void tst_TaskTree::testTree_data() Test(setupTask(2)), Test(setupTask(3)) }, - Async(setupBarrierAdvance(storage, barrier, 0)), - Async(setupBarrierAdvance(storage, barrier, 0)) + AsyncTask(setupBarrierAdvance(storage, barrier, 0)), + AsyncTask(setupBarrierAdvance(storage, barrier, 0)) }; const Log log3 { {2, Handler::GroupSetup}, @@ -1448,8 +1448,8 @@ void tst_TaskTree::testTree_data() Storage(storage), Storage(barrier), parallel, - Async(setupBarrierAdvance(storage, barrier, 0)), - Async(setupBarrierAdvance(storage, barrier, 0)), + AsyncTask(setupBarrierAdvance(storage, barrier, 0)), + AsyncTask(setupBarrierAdvance(storage, barrier, 0)), Group { OnGroupSetup(groupSetup(2)), WaitForBarrier(barrier), diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index 22514300592..33087fa18dd 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -153,19 +153,19 @@ int main(int argc, char *argv[]) using namespace Tasking; auto taskItem = [sync = &synchronizer, synchronizerCheckBox](TaskWidget *widget) { - const auto setupHandler = [=](AsyncTask &task) { + const auto setupHandler = [=](Async &task) { task.setConcurrentCallData(sleepInThread, widget->busyTime(), widget->isSuccess()); if (synchronizerCheckBox->isChecked()) task.setFutureSynchronizer(sync); widget->setState(State::Running); }; - const auto doneHandler = [widget](const AsyncTask &) { + const auto doneHandler = [widget](const Async &) { widget->setState(State::Done); }; - const auto errorHandler = [widget](const AsyncTask &) { + const auto errorHandler = [widget](const Async &) { widget->setState(State::Error); }; - return Async(setupHandler, doneHandler, errorHandler); + return AsyncTask(setupHandler, doneHandler, errorHandler); }; const Group root { From 5c254bb5bf8a55fe05db6901dbe4976028828e30 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 14:38:53 +0200 Subject: [PATCH 0792/1447] Tasking::Streamer: Rename Streamer into FileStreamerTask Rename FileStreamerAdapter into FileStreamerTaskAdapter. Task-number: QTCREATORBUG-29102 Change-Id: I8e8b773116a4c7203531341074b7c8efcef4f5f8 Reviewed-by: hjk --- src/libs/utils/filestreamer.h | 6 +++--- src/plugins/remotelinux/filesystemaccess_test.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libs/utils/filestreamer.h b/src/libs/utils/filestreamer.h index b572e910a20..7d274b94447 100644 --- a/src/libs/utils/filestreamer.h +++ b/src/libs/utils/filestreamer.h @@ -49,14 +49,14 @@ private: class FileStreamerPrivate *d = nullptr; }; -class FileStreamerAdapter : public Utils::Tasking::TaskAdapter +class FileStreamerTaskAdapter : public Utils::Tasking::TaskAdapter { public: - FileStreamerAdapter() { connect(task(), &FileStreamer::done, this, + FileStreamerTaskAdapter() { connect(task(), &FileStreamer::done, this, [this] { emit done(task()->result() == StreamResult::FinishedWithSuccess); }); } void start() override { task()->start(); } }; } // namespace Utils -QTC_DECLARE_CUSTOM_TASK(Streamer, Utils::FileStreamerAdapter); +QTC_DECLARE_CUSTOM_TASK(FileStreamerTask, Utils::FileStreamerTaskAdapter); diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index edcb8d4d01c..44dc4048109 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -432,7 +432,7 @@ void FileSystemAccessTest::testFileStreamer() streamer.setDestination(localSourcePath); streamer.setWriteData(data); }; - return Streamer(setup); + return FileStreamerTask(setup); }; const auto remoteWriter = [&] { const auto setup = [&](FileStreamer &streamer) { @@ -440,7 +440,7 @@ void FileSystemAccessTest::testFileStreamer() streamer.setDestination(remoteSourcePath); streamer.setWriteData(data); }; - return Streamer(setup); + return FileStreamerTask(setup); }; const auto localReader = [&] { const auto setup = [&](FileStreamer &streamer) { @@ -450,7 +450,7 @@ void FileSystemAccessTest::testFileStreamer() const auto onDone = [&](const FileStreamer &streamer) { localData = streamer.readData(); }; - return Streamer(setup, onDone); + return FileStreamerTask(setup, onDone); }; const auto remoteReader = [&] { const auto setup = [&](FileStreamer &streamer) { @@ -460,7 +460,7 @@ void FileSystemAccessTest::testFileStreamer() const auto onDone = [&](const FileStreamer &streamer) { remoteData = streamer.readData(); }; - return Streamer(setup, onDone); + return FileStreamerTask(setup, onDone); }; const auto transfer = [](const FilePath &source, const FilePath &dest, std::optional *result) { @@ -476,8 +476,8 @@ void FileSystemAccessTest::testFileStreamer() *result = streamer.readData(); }; const Group root { - Streamer(setupTransfer), - Streamer(setupReader, onReaderDone) + FileStreamerTask(setupTransfer), + FileStreamerTask(setupReader, onReaderDone) }; return root; }; From 161228d275fa657e99d529e78122ca08f610b7ff Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 28 Apr 2023 14:34:16 +0200 Subject: [PATCH 0793/1447] ProjectExplorer: Fix LLDB stdout lines DebuggerEngine::appendMessageRequested specifies if a newline should be added, but RunWorker::appendMessage did not use that information. Fixes: QTCREATORBUG-29098 Change-Id: I5ab1e489f691038fe1d9ea4a4d4b04429e403e0d Reviewed-by: hjk Reviewed-by: --- src/plugins/projectexplorer/runcontrol.cpp | 4 ++-- src/plugins/projectexplorer/runcontrol.h | 2 +- src/plugins/valgrind/valgrindengine.cpp | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index b43c7fe3e83..39f2af549a2 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1666,9 +1666,9 @@ void RunWorker::reportFailure(const QString &msg) * Appends a message in the specified \a format to * the owning RunControl's \uicontrol{Application Output} pane. */ -void RunWorker::appendMessage(const QString &msg, OutputFormat format) +void RunWorker::appendMessage(const QString &msg, OutputFormat format, bool appendNewLine) { - if (msg.endsWith('\n')) + if (!appendNewLine || msg.endsWith('\n')) emit d->runControl->appendMessage(msg, format); else emit d->runControl->appendMessage(msg + '\n', format); diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index d33d7071625..84a5b5c1667 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -67,7 +67,7 @@ public: QVariant recordedData(const QString &channel) const; // Part of read-only interface of RunControl for convenience. - void appendMessage(const QString &msg, Utils::OutputFormat format); + void appendMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true); void appendMessageChunk(const QString &msg, Utils::OutputFormat format); IDeviceConstPtr device() const; diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 58919333f17..977ca797758 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -39,8 +39,10 @@ ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) m_settings.fromMap(runControl->settingsData(ANALYZER_VALGRIND_SETTINGS)); - connect(&m_runner, &ValgrindRunner::appendMessage, - this, &ValgrindToolRunner::appendMessage); + connect(&m_runner, + &ValgrindRunner::appendMessage, + this, + [this](const QString &msg, Utils::OutputFormat format) { appendMessage(msg, format); }); connect(&m_runner, &ValgrindRunner::valgrindExecuted, this, [this](const QString &commandLine) { appendMessage(commandLine, NormalMessageFormat); From 82bc4870b37455d87e32826a55d1fe280723d07c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 14:45:54 +0200 Subject: [PATCH 0794/1447] Tasking::WaitForBarrier: Rename it into WaitForBarrierTask Rename BarrierAdapter into BarrierTaskAdapter. Task-number: QTCREATORBUG-29102 Change-Id: I003b09fd71af1bde870f761d365a8cea1858862a Reviewed-by: hjk --- src/libs/utils/barrier.h | 10 ++++----- src/libs/utils/filestreamer.cpp | 2 +- tests/auto/utils/tasktree/tst_tasktree.cpp | 24 +++++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libs/utils/barrier.h b/src/libs/utils/barrier.h index 52b44fd7031..2af08dfdd11 100644 --- a/src/libs/utils/barrier.h +++ b/src/libs/utils/barrier.h @@ -34,16 +34,16 @@ private: int m_current = -1; }; -class QTCREATOR_UTILS_EXPORT BarrierAdapter : public Tasking::TaskAdapter +class QTCREATOR_UTILS_EXPORT BarrierTaskAdapter : public Tasking::TaskAdapter { public: - BarrierAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); } + BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); } void start() final { task()->start(); } }; } // namespace Utils -QTC_DECLARE_CUSTOM_TASK(BarrierTask, Utils::BarrierAdapter); +QTC_DECLARE_CUSTOM_TASK(BarrierTask, Utils::BarrierTaskAdapter); namespace Utils::Tasking { @@ -70,11 +70,11 @@ using MultiBarrier = TreeStorage>; // alias template deduction only available with C++20. using SingleBarrier = MultiBarrier<1>; -class QTCREATOR_UTILS_EXPORT WaitForBarrier : public BarrierTask +class QTCREATOR_UTILS_EXPORT WaitForBarrierTask : public BarrierTask { public: template - WaitForBarrier(const MultiBarrier &sharedBarrier) + WaitForBarrierTask(const MultiBarrier &sharedBarrier) : BarrierTask([sharedBarrier](Barrier &barrier) { SharedBarrier *activeBarrier = sharedBarrier.activeStorage(); if (!activeBarrier) { diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index cdc192422a9..54e5d6e1b19 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -349,7 +349,7 @@ static Group interDeviceTransferTask(const FilePath &source, const FilePath &des Storage(storage), Writer(setupWriter), Group { - WaitForBarrier(writerReadyBarrier), + WaitForBarrierTask(writerReadyBarrier), Reader(setupReader, finalizeReader, finalizeReader) } }; diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 465c7f6bbb0..96e9f2fc535 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -1216,7 +1216,7 @@ void tst_TaskTree::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) } @@ -1239,7 +1239,7 @@ void tst_TaskTree::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) } @@ -1268,7 +1268,7 @@ void tst_TaskTree::testTree_data() parallel, Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) }, @@ -1292,12 +1292,12 @@ void tst_TaskTree::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(4)) }, Group { OnGroupSetup(groupSetup(3)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(5)) } }; @@ -1325,8 +1325,8 @@ void tst_TaskTree::testTree_data() Group { parallel, OnGroupSetup(groupSetup(1)), - WaitForBarrier(barrier), - WaitForBarrier(barrier2) + WaitForBarrierTask(barrier), + WaitForBarrierTask(barrier2) }, Test(setupTask(2)) }, @@ -1367,7 +1367,7 @@ void tst_TaskTree::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 2)), Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) } @@ -1393,7 +1393,7 @@ void tst_TaskTree::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 0)), Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) } @@ -1424,7 +1424,7 @@ void tst_TaskTree::testTree_data() parallel, Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) }, @@ -1452,12 +1452,12 @@ void tst_TaskTree::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 0)), Group { OnGroupSetup(groupSetup(2)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(4)) }, Group { OnGroupSetup(groupSetup(3)), - WaitForBarrier(barrier), + WaitForBarrierTask(barrier), Test(setupTask(5)) } }; From a3a5b8f806a4dc6515e2fe5cdf9be0f0dead7008 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 15:05:47 +0200 Subject: [PATCH 0795/1447] Utils: Rename asynctask.{cpp,h} -> async.{cpp,h} Follows AsyncTask -> Async rename. Change-Id: I37f18368ab826c9960a24087b52f6691bb33f225 Reviewed-by: hjk --- src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 2 +- src/libs/qmljs/qmljsplugindumper.cpp | 2 +- src/libs/tracing/timelinetracemanager.cpp | 2 +- src/libs/utils/CMakeLists.txt | 2 +- src/libs/utils/{asynctask.cpp => async.cpp} | 2 +- src/libs/utils/{asynctask.h => async.h} | 0 src/libs/utils/filestreamer.cpp | 2 +- src/libs/utils/stringtable.cpp | 2 +- src/libs/utils/utils.qbs | 4 ++-- src/plugins/android/androidavdmanager.cpp | 2 +- src/plugins/android/androiddeployqtstep.cpp | 2 +- src/plugins/android/androiddevice.cpp | 2 +- src/plugins/android/androidqmlpreviewworker.cpp | 2 +- src/plugins/android/androidrunnerworker.cpp | 2 +- src/plugins/android/androidsdkmanager.cpp | 2 +- src/plugins/android/androidsdkmanagerwidget.cpp | 2 +- src/plugins/autotest/testcodeparser.cpp | 2 +- src/plugins/clangcodemodel/clangcodemodelplugin.cpp | 2 +- src/plugins/clangcodemodel/clangdclient.cpp | 2 +- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 2 +- src/plugins/clangcodemodel/clangmodelmanagersupport.cpp | 2 +- src/plugins/clearcase/clearcaseplugin.cpp | 2 +- src/plugins/cmakeprojectmanager/fileapireader.cpp | 2 +- .../compilationdatabaseprojectmanager/compilationdbparser.cpp | 2 +- src/plugins/coreplugin/actionsfilter.cpp | 2 +- src/plugins/coreplugin/locator/directoryfilter.cpp | 2 +- src/plugins/coreplugin/locator/filesystemfilter.cpp | 2 +- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 2 +- src/plugins/coreplugin/locator/javascriptfilter.cpp | 2 +- src/plugins/coreplugin/locator/locator.cpp | 2 +- src/plugins/coreplugin/locator/locatorwidget.cpp | 2 +- src/plugins/coreplugin/locator/opendocumentsfilter.cpp | 2 +- src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp | 2 +- src/plugins/coreplugin/plugininstallwizard.cpp | 2 +- src/plugins/coreplugin/progressmanager/progressmanager.cpp | 2 +- src/plugins/cppeditor/builtincursorinfo.cpp | 2 +- src/plugins/cppeditor/builtineditordocumentprocessor.cpp | 2 +- src/plugins/cppeditor/cppelementevaluator.cpp | 2 +- src/plugins/cppeditor/cppfindreferences.cpp | 2 +- src/plugins/cppeditor/cppfunctiondecldeflink.cpp | 2 +- src/plugins/cppeditor/cppindexingsupport.cpp | 2 +- src/plugins/cppeditor/cpplocatorfilter.cpp | 2 +- src/plugins/cppeditor/cppprojectupdater.cpp | 2 +- src/plugins/cppeditor/cppsemanticinfoupdater.cpp | 2 +- src/plugins/cppeditor/symbolsearcher_test.cpp | 2 +- src/plugins/cppeditor/symbolsfindfilter.cpp | 2 +- src/plugins/debugger/loadcoredialog.cpp | 2 +- src/plugins/diffeditor/diffeditorplugin.cpp | 2 +- src/plugins/diffeditor/sidebysidediffeditorwidget.cpp | 2 +- src/plugins/diffeditor/unifieddiffeditorwidget.cpp | 2 +- src/plugins/docker/dockerapi.cpp | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/git/gitgrep.cpp | 2 +- src/plugins/git/gitplugin.cpp | 2 +- src/plugins/git/gitsubmiteditor.cpp | 2 +- src/plugins/help/helpindexfilter.cpp | 2 +- src/plugins/help/helpmanager.cpp | 2 +- src/plugins/ios/createsimulatordialog.cpp | 2 +- src/plugins/ios/iossettingswidget.cpp | 2 +- src/plugins/ios/iostoolhandler.cpp | 2 +- src/plugins/ios/simulatorcontrol.cpp | 2 +- src/plugins/ios/simulatorinfomodel.cpp | 2 +- src/plugins/languageclient/locatorfilter.cpp | 2 +- src/plugins/mesonprojectmanager/mesonprojectparser.cpp | 2 +- .../projectexplorer/devicesupport/devicesettingswidget.cpp | 2 +- src/plugins/projectexplorer/extracompiler.cpp | 2 +- src/plugins/projectexplorer/msvctoolchain.cpp | 2 +- src/plugins/projectexplorer/selectablefilesmodel.cpp | 2 +- src/plugins/projectexplorer/treescanner.cpp | 2 +- src/plugins/python/pipsupport.cpp | 2 +- src/plugins/python/pyside.cpp | 2 +- src/plugins/python/pythonlanguageclient.cpp | 2 +- src/plugins/qbsprojectmanager/qbsproject.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 2 +- src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp | 2 +- src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp | 2 +- .../components/itemlibrary/itemlibraryassetimporter.cpp | 2 +- src/plugins/qmljseditor/qmljsfindreferences.cpp | 2 +- src/plugins/qmljseditor/qmljssemantichighlighter.cpp | 2 +- src/plugins/qmljseditor/qmltaskmanager.cpp | 2 +- src/plugins/qmljstools/qmljsfunctionfilter.cpp | 2 +- src/plugins/remotelinux/tarpackagecreationstep.cpp | 2 +- src/plugins/silversearcher/findinfilessilversearcher.cpp | 2 +- src/plugins/texteditor/codeassist/asyncprocessor.cpp | 2 +- src/plugins/texteditor/formattexteditor.cpp | 2 +- src/plugins/vcsbase/cleandialog.cpp | 2 +- src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp | 2 +- tests/auto/utils/asynctask/tst_asynctask.cpp | 2 +- tests/auto/utils/tasktree/tst_tasktree.cpp | 2 +- tests/manual/tasktree/main.cpp | 2 +- 91 files changed, 91 insertions(+), 91 deletions(-) rename src/libs/utils/{asynctask.cpp => async.cpp} (99%) rename src/libs/utils/{asynctask.h => async.h} (100%) diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index f6c84fb88f4..6bcfe7ee25c 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index 9e2261014f0..3de270923b2 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -9,7 +9,7 @@ #include "qmljsutils.h" #include -#include +#include #include #include #include diff --git a/src/libs/tracing/timelinetracemanager.cpp b/src/libs/tracing/timelinetracemanager.cpp index b252a02cee9..98f333da91b 100644 --- a/src/libs/tracing/timelinetracemanager.cpp +++ b/src/libs/tracing/timelinetracemanager.cpp @@ -6,7 +6,7 @@ #include "timelinetracemanager.h" #include "tracingtr.h" -#include +#include #include #include diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 8660e65b84f..f26c08c7b56 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -12,7 +12,7 @@ add_qtc_library(Utils appmainwindow.cpp appmainwindow.h archive.cpp archive.h aspects.cpp aspects.h - asynctask.cpp asynctask.h + async.cpp async.h barrier.cpp barrier.h basetreeview.cpp basetreeview.h benchmarker.cpp benchmarker.h diff --git a/src/libs/utils/asynctask.cpp b/src/libs/utils/async.cpp similarity index 99% rename from src/libs/utils/asynctask.cpp rename to src/libs/utils/async.cpp index c2c42431d18..9295b50dc15 100644 --- a/src/libs/utils/asynctask.cpp +++ b/src/libs/utils/async.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "asynctask.h" +#include "async.h" #include diff --git a/src/libs/utils/asynctask.h b/src/libs/utils/async.h similarity index 100% rename from src/libs/utils/asynctask.h rename to src/libs/utils/async.h diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 54e5d6e1b19..744f682617c 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -3,7 +3,7 @@ #include "filestreamer.h" -#include "asynctask.h" +#include "async.h" #include "barrier.h" #include "qtcprocess.h" diff --git a/src/libs/utils/stringtable.cpp b/src/libs/utils/stringtable.cpp index e501203a10a..73cad02588a 100644 --- a/src/libs/utils/stringtable.cpp +++ b/src/libs/utils/stringtable.cpp @@ -3,7 +3,7 @@ #include "stringtable.h" -#include "asynctask.h" +#include "async.h" #include #include diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index eb8c2a9f563..ba2bc175f8a 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -49,8 +49,8 @@ Project { "archive.h", "aspects.cpp", "aspects.h", - "asynctask.cpp", - "asynctask.h", + "async.cpp", + "async.h", "barrier.cpp", "barrier.h", "basetreeview.cpp", diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index 6567c119a6e..8637fb6465d 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 1fef6615690..f108b1880f9 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index bd518a4e707..4d729c786e5 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index f18306f9f8a..85a3b917d37 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index b8462ac8c63..e2cae791030 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index af5fde48bea..7a16756f227 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -8,7 +8,7 @@ #include "sdkmanageroutputparser.h" #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index 81098b776aa..d071883a556 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -9,7 +9,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index b6b6eaea01e..b86f57e441d 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index c4f083592d1..9b5ec425231 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -34,7 +34,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 1c2892902e1..0082ff6cef9 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 4dd0b3b9994..a925f001fa4 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 5feca5c1a0b..57401da2660 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 4c810544b3f..c269a591389 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 42fca8b06ac..0ed163021cf 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index 7d6b399d91a..ccbead4c4ca 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index 3d04766c93b..7bb1d51d820 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 2b09b295425..a18c92b5736 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -7,7 +7,7 @@ #include "../coreplugintr.h" #include -#include +#include #include #include #include diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 5bd2d1a155a..a4f3d42a726 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 70c70bbd963..5d940487f0e 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index e05e4b0a968..7511bb9c6f5 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index dab6cf364cf..1072dc0eca0 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -27,7 +27,7 @@ #include "../statusbarmanager.h" #include -#include +#include #include #include diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index c253ff726c3..74b35abaf54 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -15,7 +15,7 @@ #include "../modemanager.h" #include -#include +#include #include #include #include diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 7cf3b986e8c..6b6b3139ad1 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index 1d57a0aed7c..ac1d698a258 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index 02f0e15eb28..224f692329e 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.cpp b/src/plugins/coreplugin/progressmanager/progressmanager.cpp index 969579aafd3..5504f8fe0ce 100644 --- a/src/plugins/coreplugin/progressmanager/progressmanager.cpp +++ b/src/plugins/coreplugin/progressmanager/progressmanager.cpp @@ -109,7 +109,7 @@ namespace Core { start a task concurrently in a different thread. QtConcurrent has several different functions to run e.g. a class function in a different thread. Qt Creator itself - adds a few more in \c{src/libs/utils/asynctask.h}. + adds a few more in \c{src/libs/utils/async.h}. The QtConcurrent functions to run a concurrent task return a \c QFuture object. This is what you want to give the ProgressManager in the addTask() function. diff --git a/src/plugins/cppeditor/builtincursorinfo.cpp b/src/plugins/cppeditor/builtincursorinfo.cpp index 6a0897c2433..ffc4d8b12a0 100644 --- a/src/plugins/cppeditor/builtincursorinfo.cpp +++ b/src/plugins/cppeditor/builtincursorinfo.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index 2c58182996d..c24cc73481e 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cppeditor/cppelementevaluator.cpp index 3ce1761ce59..221c75dd837 100644 --- a/src/plugins/cppeditor/cppelementevaluator.cpp +++ b/src/plugins/cppeditor/cppelementevaluator.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index a4a3aba5075..17f599dca8e 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index d196261db22..b43e87758e2 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/cppeditor/cppindexingsupport.cpp b/src/plugins/cppeditor/cppindexingsupport.cpp index 042caf227c1..455355470b9 100644 --- a/src/plugins/cppeditor/cppindexingsupport.cpp +++ b/src/plugins/cppeditor/cppindexingsupport.cpp @@ -15,7 +15,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index c257444ce12..7ddc7805731 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/cppprojectupdater.cpp b/src/plugins/cppeditor/cppprojectupdater.cpp index dbea7361df9..3f0c24bc288 100644 --- a/src/plugins/cppeditor/cppprojectupdater.cpp +++ b/src/plugins/cppeditor/cppprojectupdater.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/cppsemanticinfoupdater.cpp b/src/plugins/cppeditor/cppsemanticinfoupdater.cpp index 349c722fb36..4fc9dd7c66b 100644 --- a/src/plugins/cppeditor/cppsemanticinfoupdater.cpp +++ b/src/plugins/cppeditor/cppsemanticinfoupdater.cpp @@ -5,7 +5,7 @@ #include "cppmodelmanager.h" -#include +#include #include #include diff --git a/src/plugins/cppeditor/symbolsearcher_test.cpp b/src/plugins/cppeditor/symbolsearcher_test.cpp index 04b14b1002d..009afae5d50 100644 --- a/src/plugins/cppeditor/symbolsearcher_test.cpp +++ b/src/plugins/cppeditor/symbolsearcher_test.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include diff --git a/src/plugins/cppeditor/symbolsfindfilter.cpp b/src/plugins/cppeditor/symbolsfindfilter.cpp index acfbdaf298b..6fd8e78618f 100644 --- a/src/plugins/cppeditor/symbolsfindfilter.cpp +++ b/src/plugins/cppeditor/symbolsfindfilter.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index e481aef4b78..6095b4470d0 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 07410aee6f3..5f48dc13a97 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -17,7 +17,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index 8a69550232f..d2f58f83ac4 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index 43d9f4c749d..bb64e61d5b0 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/docker/dockerapi.cpp b/src/plugins/docker/dockerapi.cpp index eb77059a544..102256fd44a 100644 --- a/src/plugins/docker/dockerapi.cpp +++ b/src/plugins/docker/dockerapi.cpp @@ -6,7 +6,7 @@ #include "dockertr.h" #include -#include +#include #include #include diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index cc42faa9f87..14235cbe001 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 7d5dc7fa749..cd9c8bf5d6b 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 935fa5deb79..2f5716f8adc 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 8cc483cbf74..9ff83c8c124 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 0556e970ac8..1784867dc26 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/help/helpmanager.cpp b/src/plugins/help/helpmanager.cpp index f62aa65f352..3c053662d54 100644 --- a/src/plugins/help/helpmanager.cpp +++ b/src/plugins/help/helpmanager.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/ios/createsimulatordialog.cpp b/src/plugins/ios/createsimulatordialog.cpp index c2df6020f5c..aff8a673dfc 100644 --- a/src/plugins/ios/createsimulatordialog.cpp +++ b/src/plugins/ios/createsimulatordialog.cpp @@ -7,7 +7,7 @@ #include "simulatorcontrol.h" #include -#include +#include #include #include diff --git a/src/plugins/ios/iossettingswidget.cpp b/src/plugins/ios/iossettingswidget.cpp index 81a2cb5db62..ce1279cb0f1 100644 --- a/src/plugins/ios/iossettingswidget.cpp +++ b/src/plugins/ios/iossettingswidget.cpp @@ -12,7 +12,7 @@ #include "simulatoroperationdialog.h" #include -#include +#include #include #include diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 471d13f239a..fa5d0c3ac44 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index fe015b18815..d3af86365d8 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -5,7 +5,7 @@ #include "iosconfigurations.h" #include -#include +#include #include #include diff --git a/src/plugins/ios/simulatorinfomodel.cpp b/src/plugins/ios/simulatorinfomodel.cpp index a4627f56293..dce56467134 100644 --- a/src/plugins/ios/simulatorinfomodel.cpp +++ b/src/plugins/ios/simulatorinfomodel.cpp @@ -6,7 +6,7 @@ #include "iostr.h" #include -#include +#include #include diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 158d7476dbb..adf0952d6c5 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -18,7 +18,7 @@ #include -#include +#include #include #include diff --git a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp index 6f8ce162ed7..c84b5e4b3d6 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectparser.cpp +++ b/src/plugins/mesonprojectmanager/mesonprojectparser.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index 9094c992106..a35387a3c28 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index 291493bcbfc..a220f1906fa 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -13,7 +13,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 334777c24e2..d8cc0f7cff6 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/projectexplorer/selectablefilesmodel.cpp b/src/plugins/projectexplorer/selectablefilesmodel.cpp index 28d601f89b7..de5b0b79b40 100644 --- a/src/plugins/projectexplorer/selectablefilesmodel.cpp +++ b/src/plugins/projectexplorer/selectablefilesmodel.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp index 05d3db702f6..294ef4988e1 100644 --- a/src/plugins/projectexplorer/treescanner.cpp +++ b/src/plugins/projectexplorer/treescanner.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 7f420d245bf..0a155cb464f 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index 1309f777ed9..5e69c096a3a 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index cd95d4d329f..75ee2c8b686 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 7bf1cfd425c..c334bc84b97 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index cad20e189f1..4786d2f07a9 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 68494eca6bd..3846ce2eb82 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -48,7 +48,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp index 5cfb1414ed0..7b0604c19a8 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp b/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp index dd92973eba9..5020b095a34 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/filepathmodel.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index cca5ed47b31..635a248152d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index ff8ac54e931..72e4f7c35d2 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp index cb60b29941b..67e14dfbcd5 100644 --- a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp +++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/qmljseditor/qmltaskmanager.cpp b/src/plugins/qmljseditor/qmltaskmanager.cpp index 0d25bb3f13a..fb673066f3a 100644 --- a/src/plugins/qmljseditor/qmltaskmanager.cpp +++ b/src/plugins/qmljseditor/qmltaskmanager.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index ac173e515d1..b5f37e4c105 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include diff --git a/src/plugins/remotelinux/tarpackagecreationstep.cpp b/src/plugins/remotelinux/tarpackagecreationstep.cpp index 7d36c4d83be..7c577812da1 100644 --- a/src/plugins/remotelinux/tarpackagecreationstep.cpp +++ b/src/plugins/remotelinux/tarpackagecreationstep.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index 6e08a301d1a..9956a547774 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/texteditor/codeassist/asyncprocessor.cpp b/src/plugins/texteditor/codeassist/asyncprocessor.cpp index bd074f04c0d..3f440bfa709 100644 --- a/src/plugins/texteditor/codeassist/asyncprocessor.cpp +++ b/src/plugins/texteditor/codeassist/asyncprocessor.cpp @@ -6,7 +6,7 @@ #include "assistinterface.h" #include "iassistproposal.h" -#include +#include namespace TextEditor { diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp index ae25a574796..143b5848779 100644 --- a/src/plugins/texteditor/formattexteditor.cpp +++ b/src/plugins/texteditor/formattexteditor.cpp @@ -10,7 +10,7 @@ #include -#include +#include #include #include #include diff --git a/src/plugins/vcsbase/cleandialog.cpp b/src/plugins/vcsbase/cleandialog.cpp index 487c7c7e1eb..ae0b14a7ba8 100644 --- a/src/plugins/vcsbase/cleandialog.cpp +++ b/src/plugins/vcsbase/cleandialog.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index e52fbb47c9f..527a81be7e9 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -5,7 +5,7 @@ #include -#include +#include #include #include #include diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/asynctask/tst_asynctask.cpp index c438d1749b1..7218f7f5794 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/asynctask/tst_asynctask.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include -#include +#include #include diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index 96e9f2fc535..ae696e9fd7c 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include +#include #include #include diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index 33087fa18dd..1694ce2197a 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -3,7 +3,7 @@ #include "taskwidget.h" -#include +#include #include #include #include From 3face235d958b6601288f7d4675c39dbcf7559f7 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 10:51:29 +0200 Subject: [PATCH 0796/1447] Core: Use IOptionPage::setWidgetCreator for shortcut settings Less boilerplate for the implementation add user code access to IOptionPage::{apply,finish} is planned to be removed. Change-Id: Ie160e5bdc330dd6f257521c804a23a9ec453e780 Reviewed-by: David Schulz --- .../actionmanager/commandmappings.h | 2 - .../coreplugin/dialogs/shortcutsettings.cpp | 56 +++++++++---------- .../coreplugin/dialogs/shortcutsettings.h | 13 +---- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.h b/src/plugins/coreplugin/actionmanager/commandmappings.h index 67c864a0bf9..a6725265500 100644 --- a/src/plugins/coreplugin/actionmanager/commandmappings.h +++ b/src/plugins/coreplugin/actionmanager/commandmappings.h @@ -12,8 +12,6 @@ class QTreeWidget; class QTreeWidgetItem; QT_END_NAMESPACE -namespace Utils { class FancyLineEdit; } - namespace Core { namespace Internal { class CommandMappingsPrivate; } diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp index 598cf92d993..16c9c072038 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp @@ -268,10 +268,8 @@ ShortcutSettingsWidget::ShortcutSettingsWidget() this, &ShortcutSettingsWidget::initialize); connect(this, &ShortcutSettingsWidget::currentCommandChanged, this, &ShortcutSettingsWidget::handleCurrentCommandChanged); - connect(this, - &ShortcutSettingsWidget::resetRequested, - this, - &ShortcutSettingsWidget::resetToDefault); + connect(this, &ShortcutSettingsWidget::resetRequested, + this, &ShortcutSettingsWidget::resetToDefault); m_shortcutBox = new QGroupBox(Tr::tr("Shortcut"), this); m_shortcutBox->setEnabled(false); @@ -287,37 +285,12 @@ ShortcutSettingsWidget::~ShortcutSettingsWidget() qDeleteAll(m_scitems); } -ShortcutSettings::ShortcutSettings() -{ - setId(Constants::SETTINGS_ID_SHORTCUTS); - setDisplayName(Tr::tr("Keyboard")); - setCategory(Constants::SETTINGS_CATEGORY_CORE); -} - -QWidget *ShortcutSettings::widget() -{ - if (!m_widget) - m_widget = new ShortcutSettingsWidget(); - return m_widget; -} - void ShortcutSettingsWidget::apply() { for (const ShortcutItem *item : std::as_const(m_scitems)) item->m_cmd->setKeySequences(item->m_keys); } -void ShortcutSettings::apply() -{ - QTC_ASSERT(m_widget, return); - m_widget->apply(); -} - -void ShortcutSettings::finish() -{ - delete m_widget; -} - ShortcutItem *shortcutItem(QTreeWidgetItem *treeItem) { if (!treeItem) @@ -706,5 +679,30 @@ void ShortcutInput::setConflictChecker(const ShortcutInput::ConflictChecker &fun m_conflictChecker = fun; } +// ShortcutSettingsPageWidget + +class ShortcutSettingsPageWidget : public IOptionsPageWidget +{ +public: + ShortcutSettingsPageWidget() + { + auto inner = new ShortcutSettingsWidget; + auto vbox = new QVBoxLayout(this); + vbox->addWidget(inner); + + setOnApply([inner] { inner->apply(); }); + } +}; + +// ShortcutSettings + +ShortcutSettings::ShortcutSettings() +{ + setId(Constants::SETTINGS_ID_SHORTCUTS); + setDisplayName(Tr::tr("Keyboard")); + setCategory(Constants::SETTINGS_CATEGORY_CORE); + setWidgetCreator([] { return new ShortcutSettingsPageWidget; }); +} + } // namespace Internal } // namespace Core diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.h b/src/plugins/coreplugin/dialogs/shortcutsettings.h index d7edfcad29a..49297b3d501 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.h +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.h @@ -14,19 +14,17 @@ #include QT_BEGIN_NAMESPACE -class QGroupBox; class QLabel; QT_END_NAMESPACE +namespace Utils { class FancyLineEdit; } + namespace Core { class Command; namespace Internal { -class ActionManagerPrivate; -class ShortcutSettingsWidget; - struct ShortcutItem { Command *m_cmd; @@ -90,13 +88,6 @@ class ShortcutSettings final : public IOptionsPage { public: ShortcutSettings(); - - QWidget *widget() override; - void apply() override; - void finish() override; - -private: - QPointer m_widget; }; } // namespace Internal From 70b02d23e1a32a1c4911644cb73b7247430a4416 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 27 Apr 2023 08:24:43 +0200 Subject: [PATCH 0797/1447] LayoutBuilder: Rework Everying is a LayoutItem now, and everything is split into a proper setup and execution phase. Execution happens only via LayoutBuilder (directly or via convenience wrappers in LayoutItem). No direct access to the widget in creation, funnel out is via the new bindTo() facility. Change-Id: I7eb38fd736ae57a68f9a72a6add5c767da82b49f Reviewed-by: Qt CI Bot Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 32 +- src/libs/utils/aspects.h | 8 +- src/libs/utils/layoutbuilder.cpp | 719 +++++++++++------- src/libs/utils/layoutbuilder.h | 267 +++---- .../artisticstyleoptionspage.cpp | 2 +- .../clangformatglobalconfigwidget.cpp | 6 +- src/plugins/coreplugin/find/findtoolbar.cpp | 4 +- src/plugins/cpaster/pasteview.cpp | 3 +- .../cppeditor/cppcodestylesettingspage.cpp | 21 +- .../debuggersourcepathmappingwidget.cpp | 2 +- .../mesonbuildsettingswidget.cpp | 6 +- src/plugins/projectexplorer/buildaspects.cpp | 2 +- .../projectexplorer/buildconfiguration.cpp | 6 +- src/plugins/projectexplorer/buildstep.cpp | 6 +- src/plugins/projectexplorer/kitmanager.cpp | 3 +- .../miniprojecttargetselector.cpp | 14 +- .../projectexplorer/runconfiguration.cpp | 6 +- .../runconfigurationaspects.cpp | 4 +- .../qbsprojectmanager/qbsbuildstep.cpp | 33 +- .../qbsprojectmanager/qbsinstallstep.cpp | 15 +- .../qmljseditor/qmljseditingsettingspage.cpp | 12 +- .../scxmleditor/common/navigatorslider.cpp | 3 +- src/plugins/scxmleditor/common/search.cpp | 3 +- .../scxmleditor/common/shapestoolbox.cpp | 3 +- src/plugins/scxmleditor/common/stateview.cpp | 6 +- .../comparison/layoutbuilder/main.cpp | 7 +- .../comparison/layoutbuilder/mainwindow.h | 29 +- .../layoutbuilder/comparison/quick/Main.qml | 4 +- .../layoutbuilder/comparison/widgets/main.cpp | 3 - .../comparison/widgets/mainwindow.h | 2 +- tests/manual/tasktree/taskwidget.cpp | 7 +- tests/manual/tasktree/taskwidget.h | 2 +- 32 files changed, 680 insertions(+), 560 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index baf80e3fe7f..fd953d24934 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -216,9 +216,7 @@ void BaseAspect::addLabeledItem(Layouting::LayoutBuilder &builder, QWidget *widg if (QLabel *l = label()) { l->setBuddy(widget); builder.addItem(l); - LayoutItem item(widget); - item.span = std::max(d->m_spanX - 1, 1); - builder.addItem(item); + builder.addItem(Span(std::max(d->m_spanX - 1, 1), LayoutItem(widget))); } else { builder.addItem(LayoutItem(widget)); } @@ -425,13 +423,23 @@ void BaseAspect::addToLayout(LayoutBuilder &) { } -void doLayout(const BaseAspect &aspect, LayoutBuilder &builder) +void createItem(Layouting::LayoutItem *item, const BaseAspect &aspect) { - const_cast(aspect).addToLayout(builder); - if (builder.layoutType() == LayoutBuilder::FormLayout || builder.layoutType() == LayoutBuilder::VBoxLayout) - builder.finishRow(); + item->onAdd = [&aspect](LayoutBuilder &builder) { + const_cast(aspect).addToLayout(builder); + builder.addItem(br); + }; } +void createItem(Layouting::LayoutItem *item, const BaseAspect *aspect) +{ + item->onAdd = [aspect](LayoutBuilder &builder) { + const_cast(aspect)->addToLayout(builder); + builder.addItem(br); + }; +} + + /*! Updates this aspect's value from user-initiated changes in the widget. @@ -1063,7 +1071,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) { if (d->m_checker && d->m_checkBoxPlacement == CheckBoxPlacement::Top) { d->m_checker->addToLayout(builder); - builder.finishRow(); + builder.addItem(br); } const auto useMacroExpander = [this](QWidget *w) { @@ -1404,8 +1412,7 @@ void BoolAspect::addToLayout(Layouting::LayoutBuilder &builder) break; case LabelPlacement::AtCheckBox: { d->m_checkBox->setText(labelText()); - Layouting::LayoutBuilder::LayoutType type = builder.layoutType(); - if (type == LayoutBuilder::FormLayout) + if (builder.isForm()) builder.addItem(createSubWidget()); builder.addItem(d->m_checkBox.data()); break; @@ -1566,7 +1573,8 @@ void SelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) button->setChecked(i == value()); button->setEnabled(option.enabled); button->setToolTip(option.tooltip); - builder.addItems({Layouting::empty, button}); + builder.addItem(Layouting::empty); + builder.addItem(button); d->m_buttons.append(button); d->m_buttonGroup->addButton(button, i); if (isAutoApply()) { @@ -2284,7 +2292,7 @@ TextDisplay::~TextDisplay() = default; /*! \reimp */ -void TextDisplay::addToLayout(LayoutBuilder &builder) +void TextDisplay::addToLayout(Layouting::LayoutBuilder &builder) { if (!d->m_label) { d->m_label = createSubWidget(d->m_message, d->m_type); diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 9950fbef61a..3eae9ffaea1 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -18,7 +18,10 @@ class QAction; class QSettings; QT_END_NAMESPACE -namespace Layouting { class LayoutBuilder; } +namespace Layouting { +class LayoutItem; +class LayoutBuilder; +} namespace Utils { @@ -204,7 +207,8 @@ private: std::unique_ptr d; }; -QTCREATOR_UTILS_EXPORT void doLayout(const BaseAspect &aspect, Layouting::LayoutBuilder &builder); +QTCREATOR_UTILS_EXPORT void createItem(Layouting::LayoutItem *item, const BaseAspect &aspect); +QTCREATOR_UTILS_EXPORT void createItem(Layouting::LayoutItem *item, const BaseAspect *aspect); class QTCREATOR_UTILS_EXPORT BoolAspect : public BaseAspect { diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index e86e69a8302..c7ead009c74 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -10,10 +10,12 @@ #include #include #include +#include #include #include #include #include +#include namespace Layouting { @@ -26,20 +28,7 @@ namespace Layouting { /*! - \enum Utils::LayoutBuilder::LayoutType - \inmodule QtCreator - - The LayoutType enum describes the type of \c QLayout a layout builder - operates on. - - \value Form - \value Grid - \value HBox - \value VBox -*/ - -/*! - \class Utils::LayoutBuilder::LayoutItem + \class Layouting::LayoutItem \inmodule QtCreator \brief The LayoutItem class represents widgets, layouts, and aggregate @@ -53,8 +42,9 @@ namespace Layouting { /*! Constructs a layout item instance representing an empty cell. */ -LayoutItem::LayoutItem() -{} +LayoutItem::LayoutItem() = default; + +LayoutItem::~LayoutItem() = default; /*! @@ -70,47 +60,38 @@ LayoutItem::LayoutItem() \endlist */ - -/*! - Constructs a layout item representing something that knows how to add it - to a layout by itself. - */ -QLayout *LayoutBuilder::createLayout() const +struct ResultItem { + ResultItem() = default; + explicit ResultItem(QLayout *l) : layout(l) {} + explicit ResultItem(QWidget *w) : widget(w) {} + + QString text; QLayout *layout = nullptr; - switch (m_layoutType) { - case LayoutBuilder::FormLayout: { - auto formLayout = new QFormLayout; - formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); - layout = formLayout; - break; - } - case LayoutBuilder::GridLayout: { - auto gridLayout = new QGridLayout; - layout = gridLayout; - break; - } - case LayoutBuilder::HBoxLayout: { - auto hboxLayout = new QHBoxLayout; - layout = hboxLayout; - break; - } - case LayoutBuilder::VBoxLayout: { - auto vboxLayout = new QVBoxLayout; - layout = vboxLayout; - break; - } - case LayoutBuilder::StackLayout: { - auto stackLayout = new QStackedLayout; - layout = stackLayout; - break; - } - } - QTC_ASSERT(layout, return nullptr); - if (m_spacing) - layout->setSpacing(*m_spacing); - return layout; -} + QWidget *widget = nullptr; + int space = -1; + int stretch = -1; + int span = 1; +}; + +struct LayoutBuilder::Slice +{ + Slice() = default; + Slice(QLayout *l) : layout(l) {} + Slice(QWidget *w) : widget(w) {} + Slice(QWidget *w, AttachType a) : widget(w), attachType(a) {} + + QLayout *layout = nullptr; + QWidget *widget = nullptr; + + void flush(); + + int currentGridColumn = 0; + int currentGridRow = 0; + + AttachType attachType = WithMargins; + QList pendingItems; +}; static QWidget *widgetForItem(QLayoutItem *item) { @@ -135,18 +116,16 @@ static QLabel *createLabel(const QString &text) return label; } -static void addItemToBoxLayout(QBoxLayout *layout, const LayoutItem &item) +static void addItemToBoxLayout(QBoxLayout *layout, const ResultItem &item) { if (QWidget *w = item.widget) { layout->addWidget(w); } else if (QLayout *l = item.layout) { layout->addLayout(l); - } else if (item.specialType == LayoutItem::SpecialType::Stretch) { - layout->addStretch(item.specialValue.toInt()); - } else if (item.specialType == LayoutItem::SpecialType::Space) { - layout->addSpacing(item.specialValue.toInt()); - } else if (item.specialType == LayoutItem::SpecialType::HorizontalRule) { - layout->addWidget(Layouting::createHr()); + } else if (item.stretch != -1) { + layout->addStretch(item.stretch); + } else if (item.space != -1) { + layout->addSpacing(item.space); } else if (!item.text.isEmpty()) { layout->addWidget(createLabel(item.text)); } else { @@ -154,138 +133,168 @@ static void addItemToBoxLayout(QBoxLayout *layout, const LayoutItem &item) } } -static void flushPendingFormItems(QFormLayout *formLayout, - LayoutBuilder::LayoutItems &pendingFormItems) +void LayoutBuilder::Slice::flush() { - QTC_ASSERT(formLayout, return); - - if (pendingFormItems.empty()) + if (pendingItems.empty()) return; - // If there are more than two items, we cram the last ones in one hbox. - if (pendingFormItems.size() > 2) { - auto hbox = new QHBoxLayout; - hbox->setContentsMargins(0, 0, 0, 0); - for (int i = 1; i < pendingFormItems.size(); ++i) - addItemToBoxLayout(hbox, pendingFormItems.at(i)); - while (pendingFormItems.size() >= 2) - pendingFormItems.pop_back(); - pendingFormItems.append(LayoutItem(hbox)); - } + if (auto formLayout = qobject_cast(layout)) { - if (pendingFormItems.size() == 1) { // One one item given, so this spans both columns. - if (auto layout = pendingFormItems.at(0).layout) - formLayout->addRow(layout); - else if (auto widget = pendingFormItems.at(0).widget) - formLayout->addRow(widget); - } else if (pendingFormItems.size() == 2) { // Normal case, both columns used. - if (auto label = pendingFormItems.at(0).widget) { - if (auto layout = pendingFormItems.at(1).layout) - formLayout->addRow(label, layout); - else if (auto widget = pendingFormItems.at(1).widget) - formLayout->addRow(label, widget); - } else { - if (auto layout = pendingFormItems.at(1).layout) - formLayout->addRow(pendingFormItems.at(0).text, layout); - else if (auto widget = pendingFormItems.at(1).widget) - formLayout->addRow(pendingFormItems.at(0).text, widget); + // If there are more than two items, we cram the last ones in one hbox. + if (pendingItems.size() > 2) { + auto hbox = new QHBoxLayout; + hbox->setContentsMargins(0, 0, 0, 0); + for (int i = 1; i < pendingItems.size(); ++i) + addItemToBoxLayout(hbox, pendingItems.at(i)); + while (pendingItems.size() > 1) + pendingItems.pop_back(); + pendingItems.append(ResultItem(hbox)); } + + if (pendingItems.size() == 1) { // One one item given, so this spans both columns. + const ResultItem &f0 = pendingItems.at(0); + if (auto layout = f0.layout) + formLayout->addRow(layout); + else if (auto widget = f0.widget) + formLayout->addRow(widget); + } else if (pendingItems.size() == 2) { // Normal case, both columns used. + ResultItem &f1 = pendingItems[1]; + const ResultItem &f0 = pendingItems.at(0); + if (!f1.widget && !f1.layout && !f1.text.isEmpty()) + f1.widget = createLabel(f1.text); + + if (f0.widget) { + if (f1.layout) + formLayout->addRow(f0.widget, f1.layout); + else if (f1.widget) + formLayout->addRow(f0.widget, f1.widget); + } else { + if (f1.layout) + formLayout->addRow(f0.text, f1.layout); + else if (f1.widget) + formLayout->addRow(f0.text, f1.widget); + } + } else { + QTC_CHECK(false); + } + + // Set up label as buddy if possible. + const int lastRow = formLayout->rowCount() - 1; + QLayoutItem *l = formLayout->itemAt(lastRow, QFormLayout::LabelRole); + QLayoutItem *f = formLayout->itemAt(lastRow, QFormLayout::FieldRole); + if (l && f) { + if (QLabel *label = qobject_cast(l->widget())) { + if (QWidget *widget = widgetForItem(f)) + label->setBuddy(widget); + } + } + + } else if (auto gridLayout = qobject_cast(layout)) { + + for (const ResultItem &item : std::as_const(pendingItems)) { + Qt::Alignment align = {}; + // if (attachType == Layouting::WithFormAlignment && currentGridColumn == 0) + // align = Qt::Alignment(m_widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment)); + if (item.widget) + gridLayout->addWidget(item.widget, currentGridRow, currentGridColumn, 1, item.span, align); + else if (item.layout) + gridLayout->addLayout(item.layout, currentGridRow, currentGridColumn, 1, item.span, align); + else if (!item.text.isEmpty()) + gridLayout->addWidget(createLabel(item.text), currentGridRow, currentGridColumn, 1, 1, align); + currentGridColumn += item.span; + } + ++currentGridRow; + currentGridColumn = 0; + + } else if (auto boxLayout = qobject_cast(layout)) { + + for (const ResultItem &item : std::as_const(pendingItems)) + addItemToBoxLayout(boxLayout, item); + + } else if (auto stackLayout = qobject_cast(layout)) { + for (const ResultItem &item : std::as_const(pendingItems)) { + if (item.widget) + stackLayout->addWidget(item.widget); + else + QTC_CHECK(false); + } + } else { QTC_CHECK(false); } - // Set up label as buddy if possible. - const int lastRow = formLayout->rowCount() - 1; - QLayoutItem *l = formLayout->itemAt(lastRow, QFormLayout::LabelRole); - QLayoutItem *f = formLayout->itemAt(lastRow, QFormLayout::FieldRole); - if (l && f) { - if (QLabel *label = qobject_cast(l->widget())) { - if (QWidget *widget = widgetForItem(f)) - label->setBuddy(widget); - } + pendingItems.clear(); +} + +static void addItemHelper(LayoutBuilder &builder, const LayoutItem &item) +{ + if (item.onAdd) + item.onAdd(builder); + + if (item.setter) { + if (QWidget *widget = builder.stack.last().widget) + item.setter(widget); + else if (QLayout *layout = builder.stack.last().layout) + item.setter(layout); + else + QTC_CHECK(false); } - pendingFormItems.clear(); + for (const LayoutItem &subItem : item.subItems) + addItemHelper(builder, subItem); + + if (item.onExit) + item.onExit(builder); } -static void doLayoutHelper(QLayout *layout, - const LayoutBuilder::LayoutItems &items, - const Layouting::AttachType attachType, - int currentGridRow = 0) +void doAddText(LayoutBuilder &builder, const QString &text) { - int currentGridColumn = 0; - LayoutBuilder::LayoutItems pendingFormItems; + ResultItem fi; + fi.text = text; + builder.stack.last().pendingItems.append(fi); +} - auto formLayout = qobject_cast(layout); - auto gridLayout = qobject_cast(layout); - auto boxLayout = qobject_cast(layout); - auto stackLayout = qobject_cast(layout); +void doAddSpace(LayoutBuilder &builder, const Space &space) +{ + ResultItem fi; + fi.space = space.space; + builder.stack.last().pendingItems.append(fi); +} - for (const LayoutItem &item : items) { - if (item.specialType == LayoutItem::SpecialType::Break) { - if (formLayout) - flushPendingFormItems(formLayout, pendingFormItems); - else if (gridLayout) { - if (currentGridColumn != 0) { - ++currentGridRow; - currentGridColumn = 0; - } - } - continue; - } +void doAddStretch(LayoutBuilder &builder, const Stretch &stretch) +{ + ResultItem fi; + fi.stretch = stretch.stretch; + builder.stack.last().pendingItems.append(fi); +} - QWidget *widget = item.widget; +void doAddLayout(LayoutBuilder &builder, QLayout *layout) +{ + builder.stack.last().pendingItems.append(ResultItem(layout)); +} - if (gridLayout) { - Qt::Alignment align = {}; - if (attachType == Layouting::WithFormAlignment && currentGridColumn == 0) - align = Qt::Alignment(widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment)); - if (widget) - gridLayout->addWidget(widget, currentGridRow, currentGridColumn, 1, item.span, align); - else if (item.layout) - gridLayout->addLayout(item.layout, currentGridRow, currentGridColumn, 1, item.span, align); - else if (!item.text.isEmpty()) - gridLayout->addWidget(createLabel(item.text), currentGridRow, currentGridColumn, 1, 1, align); - currentGridColumn += item.span; - } else if (boxLayout) { - addItemToBoxLayout(boxLayout, item); - } else if (stackLayout) { - stackLayout->addWidget(item.widget); - } else { - pendingFormItems.append(item); - } - } - - if (formLayout) - flushPendingFormItems(formLayout, pendingFormItems); +void doAddWidget(LayoutBuilder &builder, QWidget *widget) +{ + builder.stack.last().pendingItems.append(ResultItem(widget)); } /*! - Constructs a layout item from the contents of another LayoutBuilder - */ -void LayoutItem::setBuilder(const LayoutBuilder &builder) -{ - layout = builder.createLayout(); - doLayoutHelper(layout, builder.m_items, Layouting::WithoutMargins); -} - -/*! - \class Utils::LayoutBuilder::Space + \class Layouting::Space \inmodule QtCreator - \brief The LayoutBuilder::Space class represents some empty space in a layout. + \brief The Layouting::Space class represents some empty space in a layout. */ /*! - \class Utils::LayoutBuilder::Stretch + \class Layouting::Stretch \inmodule QtCreator - \brief The LayoutBuilder::Stretch class represents some stretch in a layout. + \brief The Layouting::Stretch class represents some stretch in a layout. */ /*! - \class Utils::LayoutBuilder + \class LayoutBuilder \inmodule QtCreator \brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout @@ -298,20 +307,6 @@ void LayoutItem::setBuilder(const LayoutBuilder &builder) \sa addItem(), addItems(), addRow(), finishRow() */ -LayoutBuilder::LayoutBuilder(LayoutType layoutType, const LayoutItems &items) - : m_layoutType(layoutType) -{ - m_items.reserve(items.size() * 2); - for (const LayoutItem &item : items) - addItem(item); -} - -LayoutBuilder &LayoutBuilder::setSpacing(int spacing) -{ - m_spacing = spacing; - return *this; -} - LayoutBuilder::LayoutBuilder() = default; /*! @@ -319,14 +314,30 @@ LayoutBuilder::LayoutBuilder() = default; */ LayoutBuilder::~LayoutBuilder() = default; +void LayoutBuilder::addItem(const LayoutItem &item) +{ + addItemHelper(*this, item); +} + +void LayoutBuilder::addItems(const LayoutItems &items) +{ + for (const LayoutItem &item : items) + addItemHelper(*this, item); +} + +void LayoutBuilder::addRow(const LayoutItems &items) +{ + addItem(br); + addItems(items); +} + /*! Instructs a layout builder to finish the current row. This is implicitly called by LayoutBuilder's destructor. */ -LayoutBuilder &LayoutBuilder::finishRow() +void LayoutItem::finishRow() { - addItem(Break()); - return *this; + addItem(br); } /*! @@ -335,42 +346,26 @@ LayoutBuilder &LayoutBuilder::finishRow() \sa finishRow(), addItem(), addItems() */ -LayoutBuilder &LayoutBuilder::addRow(const LayoutItems &items) +void LayoutItem::addRow(const LayoutItems &items) { - return finishRow().addItems(items); + finishRow(); + addItems(items); } /*! - Adds the layout item \a item to the current row. + Adds the layout item \a item as sub items. */ -LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item) +void LayoutItem::addItem(const LayoutItem &item) { - if (item.onAdd) { - item.onAdd(*this); - } else { - m_items.push_back(item); - } - return *this; -} - -void LayoutBuilder::doLayout(QWidget *parent, Layouting::AttachType attachType) const -{ - QLayout *layout = createLayout(); - parent->setLayout(layout); - - doLayoutHelper(layout, m_items, attachType); - if (attachType == Layouting::WithoutMargins) - layout->setContentsMargins(0, 0, 0, 0); + subItems.append(item); } /*! - Adds the layout item \a items to the current row. + Adds the layout items \a items as sub items. */ -LayoutBuilder &LayoutBuilder::addItems(const LayoutItems &items) +void LayoutItem::addItems(const LayoutItems &items) { - for (const LayoutItem &item : items) - addItem(item); - return *this; + subItems.append(items); } /*! @@ -378,18 +373,106 @@ LayoutBuilder &LayoutBuilder::addItems(const LayoutItems &items) This operation can only be performed once per LayoutBuilder instance. */ -void LayoutBuilder::attachTo(QWidget *w, Layouting::AttachType attachType) const + +void LayoutItem::attachTo(QWidget *w, AttachType attachType) const { - doLayout(w, attachType); + LayoutBuilder builder; + + builder.stack.append({w, attachType}); + addItemHelper(builder, *this); } -QWidget *LayoutBuilder::emerge(Layouting::AttachType attachType) +QWidget *LayoutItem::emerge(Layouting::AttachType attachType) { auto w = new QWidget; - doLayout(w, attachType); + attachTo(w, attachType); return w; } +bool LayoutBuilder::isForm() const +{ + return qobject_cast(stack.last().layout); +} + +static void layoutExit(LayoutBuilder &builder) +{ + builder.stack.last().flush(); + QLayout *layout = builder.stack.last().layout; + if (builder.stack.back().attachType == WithoutMargins) + layout->setContentsMargins(0, 0, 0, 0); + builder.stack.pop_back(); + + if (QWidget *widget = builder.stack.last().widget) + widget->setLayout(layout); + else + builder.stack.last().pendingItems.append(ResultItem(layout)); +} + +static void widgetExit(LayoutBuilder &builder) +{ + QWidget *widget = builder.stack.last().widget; + if (builder.stack.back().attachType == WithoutMargins) + widget->setContentsMargins(0, 0, 0, 0); + builder.stack.pop_back(); + builder.stack.last().pendingItems.append(ResultItem(widget)); +} + +Column::Column(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QVBoxLayout); }; + onExit = layoutExit; +} + +Row::Row(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QHBoxLayout); }; + onExit = layoutExit; +} + +Grid::Grid(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QGridLayout); }; + onExit = layoutExit; +} + +static QFormLayout *newFormLayout() +{ + auto formLayout = new QFormLayout; + formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + return formLayout; +} + +Form::Form(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(newFormLayout()); }; + onExit = layoutExit; +} + +Stack::Stack(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QStackedLayout); }; + onExit = layoutExit; +} + +LayoutItem br() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { + builder.stack.last().flush(); + }; + return item; +} + +LayoutItem empty() +{ + return {}; +} + /*! Constructs a layout extender to extend an existing \a layout. @@ -399,111 +482,123 @@ QWidget *LayoutBuilder::emerge(Layouting::AttachType attachType) */ LayoutExtender::LayoutExtender(QLayout *layout, Layouting::AttachType attachType) - : m_layout(layout), m_attachType(attachType) -{} - -LayoutExtender::~LayoutExtender() { - QTC_ASSERT(m_layout, return); - int currentGridRow = 0; - if (auto gridLayout = qobject_cast(m_layout)) - currentGridRow = gridLayout->rowCount(); - doLayoutHelper(m_layout, m_items, m_attachType, currentGridRow); + Slice slice; + slice.layout = layout; + if (auto gridLayout = qobject_cast(layout)) + slice.currentGridRow = gridLayout->rowCount(); + slice.attachType = attachType; + stack.append(slice); } -// Special items - -Tab::Tab(const QString &tabName, const LayoutBuilder &item) -{ - text = tabName; - widget = new QWidget; - item.attachTo(widget); - specialType = LayoutItem::SpecialType::Tab; -} +LayoutExtender::~LayoutExtender() = default; // "Widgets" -static void applyItems(LayoutItem *owner, QWidget *widget, const QList &items) +template +void setupWidget(LayoutItem *item) { - owner->widget = widget; - bool hadLayout = false; - for (const LayoutItem &item : items) { - if (item.setter) { - item.setter(widget); - } else if (item.specialType == LayoutItem::SpecialType::Tab) { - auto tabWidget = qobject_cast(widget); - QTC_ASSERT(tabWidget, continue); - tabWidget->addTab(item.widget, item.text); - } else if (item.layout && !hadLayout) { - hadLayout = true; - widget->setLayout(item.layout); - } else { - QTC_CHECK(false); - } - } -} + item->onAdd = [](LayoutBuilder &builder) { builder.stack.append(new T); }; + item->onExit = widgetExit; +}; Group::Group(std::initializer_list items) { - applyItems(this, new QGroupBox, items); + this->subItems = items; + setupWidget(this); } PushButton::PushButton(std::initializer_list items) { - applyItems(this, new QPushButton, items); + this->subItems = items; + setupWidget(this); } TextEdit::TextEdit(std::initializer_list items) { - applyItems(this, new QTextEdit, items); + this->subItems = items; + setupWidget(this); } Splitter::Splitter(std::initializer_list items) { - applyItems(this, new QSplitter(Qt::Vertical), items); - } - + this->subItems = items; + setupWidget(this); // FIXME: Default was Qt::Vertical) +} TabWidget::TabWidget(std::initializer_list items) - { - applyItems(this, new QTabWidget, items); +{ + this->subItems = items; + setupWidget(this); +} + +// Special Tab + +Tab::Tab(const QString &tabName, const LayoutItem &item) +{ + onAdd = [item](LayoutBuilder &builder) { + auto tab = new QWidget; + builder.stack.append(tab); + item.attachTo(tab); + }; + onExit = [tabName](LayoutBuilder &builder) { + QWidget *inner = builder.stack.last().widget; + builder.stack.pop_back(); + auto tabWidget = qobject_cast(builder.stack.last().widget); + QTC_ASSERT(tabWidget, return); + tabWidget->addTab(inner, tabName); + }; +} + +// Special Application + +Application::Application(std::initializer_list items) +{ + subItems = items; + setupWidget(this); + onExit = {}; // Hack: Don't dropp the last slice, we need the resulting widget. +} + +int Application::exec(int &argc, char *argv[]) +{ + auto app = new QApplication(argc, argv); + LayoutBuilder builder; + addItemHelper(builder, *this); + if (QWidget *widget = builder.stack.last().widget) + widget->show(); + return app->exec(); } // "Properties" -static LayoutItem setter(const LayoutItem::Setter &setter) -{ - LayoutItem item; - item.setter = setter; - return item; -} - LayoutItem title(const QString &title) { - return setter([title](QObject *target) { + return [title](QObject *target) { if (auto groupBox = qobject_cast(target)) { groupBox->setTitle(title); groupBox->setObjectName(title); + } else if (auto widget = qobject_cast(target)) { + widget->setWindowTitle(title); } else { QTC_CHECK(false); } - }); + }; } LayoutItem onClicked(const std::function &func, QObject *guard) { - return setter([func, guard](QObject *target) { + return [func, guard](QObject *target) { if (auto button = qobject_cast(target)) { QObject::connect(button, &QAbstractButton::clicked, guard ? guard : target, func); } else { QTC_CHECK(false); } - }); + }; } LayoutItem text(const QString &text) { - return setter([text](QObject *target) { + return [text](QObject *target) { if (auto button = qobject_cast(target)) { button->setText(text); } else if (auto textEdit = qobject_cast(target)) { @@ -511,32 +606,40 @@ LayoutItem text(const QString &text) } else { QTC_CHECK(false); } - }); + }; } LayoutItem tooltip(const QString &toolTip) { - return setter([toolTip](QObject *target) { + return [toolTip](QObject *target) { if (auto widget = qobject_cast(target)) { widget->setToolTip(toolTip); } else { QTC_CHECK(false); } - }); + }; } -LayoutItem bindTo(QSplitter **out) +LayoutItem spacing(int spacing) { - return setter([out](QObject *target) { - *out = qobject_cast(target); - }); + return [spacing](QObject *target) { + if (auto layout = qobject_cast(target)) { + layout->setSpacing(spacing); + } else { + QTC_CHECK(false); + } + }; } -LayoutItem bindTo(QTabWidget **out) +LayoutItem resize(int w, int h) { - return setter([out](QObject *target) { - *out = qobject_cast(target); - }); + return [w, h](QObject *target) { + if (auto widget = qobject_cast(target)) { + widget->resize(w, h); + } else { + QTC_CHECK(false); + } + }; } QWidget *createHr(QWidget *parent) @@ -548,9 +651,67 @@ QWidget *createHr(QWidget *parent) } // Singletons. -Break br; -Stretch st; -Space empty(0); -HorizontalRule hr; + +LayoutItem::LayoutItem(const LayoutItem &t) +{ + operator=(t); +} + +void createItem(LayoutItem *item, LayoutItem(*t)()) +{ + *item = t(); +} + +void createItem(LayoutItem *item, const std::function &t) +{ + item->setter = t; +} + +void createItem(LayoutItem *item, QWidget *t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddWidget(builder, t); }; +} + +void createItem(LayoutItem *item, QLayout *t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddLayout(builder, t); }; +} + +void createItem(LayoutItem *item, const QString &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddText(builder, t); }; +} + +void createItem(LayoutItem *item, const Space &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddSpace(builder, t); }; +} + +void createItem(LayoutItem *item, const Stretch &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddStretch(builder, t); }; +} + +void createItem(LayoutItem *item, const Span &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { + addItemHelper(builder, t.item); + builder.stack.last().pendingItems.last().span = t.span; + }; +} + +LayoutItem hr() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { doAddWidget(builder, createHr()); }; + return item; +} + +LayoutItem st() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { doAddStretch(builder, Stretch(1)); }; + return item; +} } // Layouting diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index aea4db876c1..1e9e6b9ad3e 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -18,10 +17,9 @@ QT_BEGIN_NAMESPACE class QLayout; -class QSplitter; -class QTabWidget; -class QTextEdit; +class QObject; class QWidget; +template T qobject_cast(QObject *object); QT_END_NAMESPACE namespace Layouting { @@ -34,6 +32,7 @@ enum AttachType { class LayoutBuilder; class LayoutItem; +class Span; // Special items @@ -51,28 +50,20 @@ public: const int stretch; }; -class QTCREATOR_UTILS_EXPORT Break -{ -public: - Break() {} -}; - -class QTCREATOR_UTILS_EXPORT Span -{ -public: - Span(int span, const LayoutItem &item) : span(span), item(item) {} - const int span; - const LayoutItem &item; -}; - -class QTCREATOR_UTILS_EXPORT HorizontalRule -{ -public: - HorizontalRule() {} -}; // LayoutItem +using LayoutItems = QList; + +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const std::function &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QWidget *t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QLayout *t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, LayoutItem(*t)()); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const QString &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Span &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Space &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Stretch &t); + class QTCREATOR_UTILS_EXPORT LayoutItem { public: @@ -81,72 +72,81 @@ public: AlignAsFormLabel, }; - enum class SpecialType { - NotSpecial, - Space, - Stretch, - Break, - HorizontalRule, - Tab, - }; - using Setter = std::function; - using OnAdder = std::function; LayoutItem(); + ~LayoutItem(); + + LayoutItem(const LayoutItem &t); + LayoutItem &operator=(const LayoutItem &t) = default; template LayoutItem(const T &t) { - if constexpr (std::is_same_v) { - text = t; - } else if constexpr (std::is_same_v) { - specialType = LayoutItem::SpecialType::Space; - specialValue = t.space; - } else if constexpr (std::is_same_v) { - specialType = LayoutItem::SpecialType::Stretch; - specialValue = t.stretch; - } else if constexpr (std::is_same_v) { - specialType = LayoutItem::SpecialType::Break; - } else if constexpr (std::is_same_v) { - LayoutItem::operator=(t.item); - span = t.span; - } else if constexpr (std::is_same_v) { - specialType = SpecialType::HorizontalRule; - } else if constexpr (std::is_base_of_v) { - setBuilder(t); - } else if constexpr (std::is_base_of_v) { + if constexpr (std::is_base_of_v) LayoutItem::operator=(t); - } else if constexpr (std::is_base_of_v) { - setter = t; - } else if constexpr (std::is_base_of_v>) { - layout = t; - } else if constexpr (std::is_base_of_v>) { - widget = t; - } else if constexpr (std::is_pointer_v) { - onAdd = [t](LayoutBuilder &builder) { doLayout(*t, builder); }; - } else { - onAdd = [&t](LayoutBuilder &builder) { doLayout(t, builder); }; - } + else + createItem(this, t); } - void setBuilder(const LayoutBuilder &builder); + void attachTo(QWidget *w, AttachType attachType = WithMargins) const; + QWidget *emerge(AttachType attachType = WithMargins); - QLayout *layout = nullptr; - QWidget *widget = nullptr; - OnAdder onAdd; + void addItem(const LayoutItem &item); + void addItems(const LayoutItems &items); + void addRow(const LayoutItems &items); + void finishRow(); - QString text; // FIXME: Use specialValue for that - int span = 1; - AlignmentType align = AlignmentType::DefaultAlignment; - Setter setter; - SpecialType specialType = SpecialType::NotSpecial; - QVariant specialValue; + std::function onAdd; + std::function onExit; + std::function setter; + LayoutItems subItems; +}; + +class QTCREATOR_UTILS_EXPORT Span +{ +public: + Span(int span, const LayoutItem &item) : span(span), item(item) {} + const int span; + LayoutItem item; +}; + +class QTCREATOR_UTILS_EXPORT Column : public LayoutItem +{ +public: + Column(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Row : public LayoutItem +{ +public: + Row(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Grid : public LayoutItem +{ +public: + Grid() : Grid({}) {} + Grid(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Form : public LayoutItem +{ +public: + Form() : Form({}) {} + Form(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Stack : public LayoutItem +{ +public: + Stack() : Stack({}) {} + Stack(std::initializer_list items); }; class QTCREATOR_UTILS_EXPORT Tab : public LayoutItem { public: - Tab(const QString &tabName, const LayoutBuilder &item); + Tab(const QString &tabName, const LayoutItem &item); }; class QTCREATOR_UTILS_EXPORT Group : public LayoutItem @@ -179,124 +179,67 @@ public: TabWidget(std::initializer_list items); }; -// Singleton items. +class QTCREATOR_UTILS_EXPORT Application : public LayoutItem +{ +public: + Application(std::initializer_list items); -QTCREATOR_UTILS_EXPORT extern Break br; -QTCREATOR_UTILS_EXPORT extern Stretch st; -QTCREATOR_UTILS_EXPORT extern Space empty; -QTCREATOR_UTILS_EXPORT extern HorizontalRule hr; + int exec(int &argc, char *argv[]); +}; + +// "Singletons" + +QTCREATOR_UTILS_EXPORT LayoutItem br(); +QTCREATOR_UTILS_EXPORT LayoutItem st(); +QTCREATOR_UTILS_EXPORT LayoutItem empty(); +QTCREATOR_UTILS_EXPORT LayoutItem hr(); // "Properties" -QTCREATOR_UTILS_EXPORT LayoutItem bindTo(QTabWidget **); -QTCREATOR_UTILS_EXPORT LayoutItem bindTo(QSplitter **); - QTCREATOR_UTILS_EXPORT LayoutItem title(const QString &title); QTCREATOR_UTILS_EXPORT LayoutItem text(const QString &text); QTCREATOR_UTILS_EXPORT LayoutItem tooltip(const QString &toolTip); -QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &func, - QObject *guard = nullptr); - +QTCREATOR_UTILS_EXPORT LayoutItem resize(int, int); +QTCREATOR_UTILS_EXPORT LayoutItem spacing(int); +QTCREATOR_UTILS_EXPORT LayoutItem windowTitle(const QString &windowTitle); +QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &, + QObject *guard = nullptr); // Convenience QTCREATOR_UTILS_EXPORT QWidget *createHr(QWidget *parent = nullptr); +template +LayoutItem bindTo(T **out) +{ + return [out](QObject *target) { *out = qobject_cast(target); }; +} // LayoutBuilder class QTCREATOR_UTILS_EXPORT LayoutBuilder { - Q_DISABLE_COPY(LayoutBuilder) + Q_DISABLE_COPY_MOVE(LayoutBuilder) public: - enum LayoutType { - HBoxLayout, - VBoxLayout, - FormLayout, - GridLayout, - StackLayout, - }; - - using LayoutItems = QList; - - explicit LayoutBuilder(LayoutType layoutType, const LayoutItems &items = {}); - - LayoutBuilder(LayoutBuilder &&) = default; - LayoutBuilder &operator=(LayoutBuilder &&) = default; - + LayoutBuilder(); ~LayoutBuilder(); - LayoutBuilder &setSpacing(int spacing); + void addItem(const LayoutItem &item); + void addItems(const LayoutItems &items); + void addRow(const LayoutItems &items); - LayoutBuilder &addItem(const LayoutItem &item); - LayoutBuilder &addItems(const LayoutItems &items); + bool isForm() const; - LayoutBuilder &finishRow(); - LayoutBuilder &addRow(const LayoutItems &items); - - LayoutType layoutType() const { return m_layoutType; } - - void attachTo(QWidget *w, Layouting::AttachType attachType = Layouting::WithMargins) const; - QWidget *emerge(Layouting::AttachType attachType = Layouting::WithMargins); - -protected: - friend class LayoutItem; - - explicit LayoutBuilder(); // Adds to existing layout. - - QLayout *createLayout() const; - void doLayout(QWidget *parent, Layouting::AttachType attachType) const; - - LayoutItems m_items; - LayoutType m_layoutType; - std::optional m_spacing; + struct Slice; + QList stack; }; class QTCREATOR_UTILS_EXPORT LayoutExtender : public LayoutBuilder { public: - explicit LayoutExtender(QLayout *layout, Layouting::AttachType attachType); + explicit LayoutExtender(QLayout *layout, AttachType attachType); ~LayoutExtender(); - -private: - QLayout *m_layout = nullptr; - Layouting::AttachType m_attachType = {}; -}; - -class QTCREATOR_UTILS_EXPORT Column : public LayoutBuilder -{ -public: - Column() : LayoutBuilder(VBoxLayout) {} - Column(std::initializer_list items) : LayoutBuilder(VBoxLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Row : public LayoutBuilder -{ -public: - Row() : LayoutBuilder(HBoxLayout) {} - Row(std::initializer_list items) : LayoutBuilder(HBoxLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Grid : public LayoutBuilder -{ -public: - Grid() : LayoutBuilder(GridLayout) {} - Grid(std::initializer_list items) : LayoutBuilder(GridLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Form : public LayoutBuilder -{ -public: - Form() : LayoutBuilder(FormLayout) {} - Form(std::initializer_list items) : LayoutBuilder(FormLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Stack : public LayoutBuilder -{ -public: - Stack() : LayoutBuilder(StackLayout) {} - Stack(std::initializer_list items) : LayoutBuilder(StackLayout, items) {} }; } // Layouting diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp index 9d2741209ed..a968c2eb962 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp @@ -91,7 +91,7 @@ ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSett Row { m_useSpecificConfigFile, m_specificConfigFile }, m_useHomeFile, Row { m_useCustomStyle, m_configurations } - }.attachTo(options); + }.attachTo(options, WithoutMargins); Column { Group { diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index c70b5251a2c..44d32cc3a91 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -44,7 +44,10 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget( using namespace Layouting; + QWidget *globalSettingsGroupBoxWidget = nullptr; + Group globalSettingsGroupBox { + bindTo(&globalSettingsGroupBoxWidget), title(Tr::tr("ClangFormat settings:")), Column { m_useGlobalSettings, @@ -73,7 +76,8 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget( m_useGlobalSettings->show(); return; } - globalSettingsGroupBox.widget->show(); + + globalSettingsGroupBoxWidget->show(); } ClangFormatGlobalConfigWidget::~ClangFormatGlobalConfigWidget() = default; diff --git a/src/plugins/coreplugin/find/findtoolbar.cpp b/src/plugins/coreplugin/find/findtoolbar.cpp index 11c51fe26ea..4690502f50a 100644 --- a/src/plugins/coreplugin/find/findtoolbar.cpp +++ b/src/plugins/coreplugin/find/findtoolbar.cpp @@ -147,8 +147,8 @@ FindToolBar::FindToolBar(CurrentDocumentFind *currentDocumentFind) m_findEdit, findButtonsWidget, br, - Column { m_replaceLabel, st }.setSpacing(0), - Column { m_replaceEdit, st }.setSpacing(0), + Column { spacing(0), m_replaceLabel, st }, + Column { spacing(0), m_replaceEdit, st }, gridLayout, }.attachTo(this); diff --git a/src/plugins/cpaster/pasteview.cpp b/src/plugins/cpaster/pasteview.cpp index c575fa582b7..b1f4864b6e0 100644 --- a/src/plugins/cpaster/pasteview.cpp +++ b/src/plugins/cpaster/pasteview.cpp @@ -108,6 +108,7 @@ PasteView::PasteView(const QList &protocols, }.attachTo(groupBox); Column { + spacing(2), Form { Tr::tr("Protocol:"), m_protocolBox, br, Tr::tr("&Expires after:"), m_expirySpinBox, br, @@ -117,7 +118,7 @@ PasteView::PasteView(const QList &protocols, m_uiComment, m_stackedWidget, buttonBox - }.setSpacing(2).attachTo(this); + }.attachTo(this); connect(m_uiPatchList, &QListWidget::itemChanged, this, &PasteView::contentChanged); diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index 72308ed4caa..b9cdbc47f39 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -175,8 +175,15 @@ public: using namespace Layouting; + QWidget *contentGroupWidget = nullptr; + QWidget *bracesGroupWidget = nullptr; + QWidget *switchGroupWidget = nullptr; + QWidget *alignmentGroupWidget = nullptr; + QWidget *typesGroupWidget = nullptr; + const Group contentGroup { title(Tr::tr("Indent")), + bindTo(&contentGroupWidget), Column { m_indentAccessSpecifiers, m_indentDeclarationsRelativeToAccessSpecifiers, @@ -189,6 +196,7 @@ public: const Group bracesGroup { title(Tr::tr("Indent Braces")), + bindTo(&bracesGroupWidget), Column { m_indentClassBraces, m_indentNamespaceBraces, @@ -201,6 +209,7 @@ public: const Group switchGroup { title(Tr::tr("Indent within \"switch\"")), + bindTo(&switchGroupWidget), Column { m_indentSwitchLabels, m_indentCaseStatements, @@ -212,6 +221,7 @@ public: const Group alignmentGroup { title(Tr::tr("Align")), + bindTo(&alignmentGroupWidget), Column { m_alignAssignments, m_extraPaddingConditions, @@ -221,6 +231,7 @@ public: const Group typesGroup { title(Tr::tr("Bind '*' and '&&' in types/declarations to")), + bindTo(&typesGroupWidget), Column { m_bindStarToIdentifier, m_bindStarToTypeName, @@ -247,11 +258,11 @@ public: m_categoryTab->setProperty("_q_custom_style_disabled", true); m_controllers.append(m_tabSettingsWidget); - m_controllers.append(contentGroup.widget); - m_controllers.append(bracesGroup.widget); - m_controllers.append(switchGroup.widget); - m_controllers.append(alignmentGroup.widget); - m_controllers.append(typesGroup.widget); + m_controllers.append(contentGroupWidget); + m_controllers.append(bracesGroupWidget); + m_controllers.append(switchGroupWidget); + m_controllers.append(alignmentGroupWidget); + m_controllers.append(typesGroupWidget); } QCheckBox *createCheckBox(const QString &text, const QString &toolTip = {}) diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index 8aa30b3c630..d7abf7b12b5 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -496,7 +496,7 @@ void SourcePathMapAspect::addToLayout(Layouting::LayoutBuilder &builder) QTC_CHECK(!d->m_widget); d->m_widget = createSubWidget(); d->m_widget->setSourcePathMap(value()); - builder.addRow({d->m_widget.data()}); + builder.addItem(d->m_widget.data()); } QVariant SourcePathMapAspect::volatileValue() const diff --git a/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp b/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp index cedd9c5f3ef..8becece66b1 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp @@ -74,9 +74,9 @@ MesonBuildSettingsWidget::MesonBuildSettingsWidget(MesonBuildConfiguration *buil Row { configureButton, wipeButton, } }.attachTo(this, WithoutMargins); - Form buildDirWBuilder; - buildCfg->buildDirectoryAspect()->addToLayout(buildDirWBuilder); - buildDirWBuilder.attachTo(buildDirWidget, WithoutMargins); + Form { + buildCfg->buildDirectoryAspect(), + }.attachTo(buildDirWidget, WithoutMargins); parametersLineEdit->setText(buildCfg->parameters()); optionsFilterLineEdit->setFiltering(true); diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index adf37a33620..133cfb15b38 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -112,7 +112,7 @@ void BuildDirectoryAspect::addToLayout(Layouting::LayoutBuilder &builder) StringAspect::addToLayout(builder); d->problemLabel = new InfoLabel({}, InfoLabel::Warning); d->problemLabel->setElideMode(Qt::ElideNone); - builder.addRow({{}, d->problemLabel.data()}); + builder.addItems({{}, d->problemLabel.data()}); updateProblemLabel(); if (!d->sourceDir.isEmpty()) { connect(this, &StringAspect::checkedChanged, this, [this] { diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 124941b11a1..904530e9c77 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -322,12 +322,12 @@ NamedWidget *BuildConfiguration::createConfigWidget() widget = named; } - Layouting::Form builder; + Layouting::Form form; for (BaseAspect *aspect : aspects()) { if (aspect->isVisible()) - aspect->addToLayout(builder.finishRow()); + form.addItem(aspect); } - builder.attachTo(widget, Layouting::WithoutMargins); + form.attachTo(widget, Layouting::WithoutMargins); return named; } diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 69f05e41c4e..a7f74c3f03d 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -160,12 +160,12 @@ QWidget *BuildStep::doCreateConfigWidget() QWidget *BuildStep::createConfigWidget() { - Layouting::Form builder; + Layouting::Form form; for (BaseAspect *aspect : std::as_const(m_aspects)) { if (aspect->isVisible()) - aspect->addToLayout(builder.finishRow()); + form.addItem(aspect); } - auto widget = builder.emerge(Layouting::WithoutMargins); + auto widget = form.emerge(Layouting::WithoutMargins); if (m_addMacroExpander) VariableChooser::addSupportForChildWidgets(widget, macroExpander()); diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index cb67e11fac0..65c8475adba 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -757,8 +757,7 @@ void KitAspectWidget::addToLayoutWithLabel(QWidget *parent) }); Layouting::LayoutExtender builder(parent->layout(), Layouting::WithFormAlignment); - builder.finishRow(); - builder.addItem(label); + builder.addItems({label, Layouting::br}); addToLayout(builder); } diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 558e4fa7122..5ab5f109ff2 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -551,6 +551,11 @@ int SelectorView::padding() ///////// // KitAreaWidget ///////// +void doLayout(KitAspectWidget *widget, Layouting::LayoutBuilder &builder) +{ + widget->addToLayout(builder); +} + class KitAreaWidget : public QWidget { Q_OBJECT @@ -573,18 +578,15 @@ public: delete layout(); - Layouting::LayoutBuilder builder(Layouting::LayoutBuilder::GridLayout); + Layouting::Grid grid; for (KitAspect *aspect : KitManager::kitAspects()) { if (k && k->isMutable(aspect->id())) { KitAspectWidget *widget = aspect->createConfigWidget(k); m_widgets << widget; - QLabel *label = new QLabel(aspect->displayName()); - builder.addItem(label); - widget->addToLayout(builder); - builder.finishRow(); + grid.addItems({aspect->displayName(), widget, Layouting::br}); } } - builder.attachTo(this); + grid.attachTo(this); layout()->setContentsMargins(3, 3, 3, 3); m_kit = k; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 32740d6c33c..c6e47f7f838 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -216,13 +216,13 @@ bool RunConfiguration::isEnabled() const QWidget *RunConfiguration::createConfigurationWidget() { - Layouting::Form builder; + Layouting::Form form; for (BaseAspect *aspect : std::as_const(m_aspects)) { if (aspect->isVisible()) - aspect->addToLayout(builder.finishRow()); + form.addItem(aspect); } - auto widget = builder.emerge(Layouting::WithoutMargins); + auto widget = form.emerge(Layouting::WithoutMargins); VariableChooser::addSupportForChildWidgets(widget, &m_expander); diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index c1fceb613c1..face7d2ce4f 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -634,9 +634,9 @@ FilePath ExecutableAspect::executable() const */ void ExecutableAspect::addToLayout(LayoutBuilder &builder) { - m_executable.addToLayout(builder); + builder.addItem(m_executable); if (m_alternativeExecutable) - m_alternativeExecutable->addToLayout(builder.finishRow()); + builder.addItems({br, m_alternativeExecutable}); } /*! diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index acea24b0763..1f7fca3b856 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -658,25 +658,26 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) installDirChooser = new PathChooser(this); installDirChooser->setExpectedKind(PathChooser::Directory); - Layouting::Form builder; - builder.addRow({m_qbsStep->m_buildVariant}); - builder.addRow({m_qbsStep->m_selectedAbis}); - builder.addRow({m_qbsStep->m_maxJobCount}); - builder.addRow({QbsProjectManager::Tr::tr("Properties:"), propertyEdit}); + using namespace Layouting; + Form { + m_qbsStep->m_buildVariant, br, + m_qbsStep->m_selectedAbis, br, + m_qbsStep->m_maxJobCount, br, + QbsProjectManager::Tr::tr("Properties:"), propertyEdit, br, - builder.addRow({QbsProjectManager::Tr::tr("Flags:")}); - m_qbsStep->m_keepGoing->addToLayout(builder); - m_qbsStep->m_showCommandLines->addToLayout(builder); - m_qbsStep->m_forceProbes->addToLayout(builder); + QbsProjectManager::Tr::tr("Flags:"), + m_qbsStep->m_keepGoing, + m_qbsStep->m_showCommandLines, + m_qbsStep->m_forceProbes, br, - builder.addRow({QbsProjectManager::Tr::tr("Installation flags:")}); - m_qbsStep->m_install->addToLayout(builder); - m_qbsStep->m_cleanInstallDir->addToLayout(builder); - builder.addItem(defaultInstallDirCheckBox); + QbsProjectManager::Tr::tr("Installation flags:"), + m_qbsStep->m_install, + m_qbsStep->m_cleanInstallDir, + defaultInstallDirCheckBox, br, - builder.addRow({QbsProjectManager::Tr::tr("Installation directory:"), installDirChooser}); - builder.addRow({m_qbsStep->m_commandLine}); - builder.attachTo(this, Layouting::WithoutMargins); + QbsProjectManager::Tr::tr("Installation directory:"), installDirChooser, br, + m_qbsStep->m_commandLine, br, + }.attachTo(this, Layouting::WithoutMargins); propertyEdit->setToolTip(QbsProjectManager::Tr::tr("Properties to pass to the project.")); defaultInstallDirCheckBox->setText(QbsProjectManager::Tr::tr("Use default location")); diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index 179928c1795..939a03d9d9c 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -172,15 +172,12 @@ QWidget *QbsInstallStep::createConfigWidget() commandLineTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse); commandLineTextEdit->setMinimumHeight(QFontMetrics(widget->font()).height() * 8); - Layouting::Form builder; - builder.addRow({Tr::tr("Install root:"), installRootValueLabel}); - builder.addRow({Tr::tr("Flags:")}); - m_dryRun->addToLayout(builder); - m_keepGoing->addToLayout(builder); - m_cleanInstallRoot->addToLayout(builder); - - builder.addRow({commandLineKeyLabel, commandLineTextEdit}); - builder.attachTo(widget); + using namespace Layouting; + Form { + Tr::tr("Install root:"), installRootValueLabel, br, + Tr::tr("Flags:"), m_dryRun, m_keepGoing, m_cleanInstallRoot, br, + commandLineKeyLabel, commandLineTextEdit + }.attachTo(widget); const auto updateState = [this, commandLineTextEdit, installRootValueLabel] { installRootValueLabel->setText(installRoot().toUserOutput()); diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 8d168d440a4..7b6474449c4 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -246,10 +246,13 @@ public: QObject::connect(useQmlls, &QCheckBox::stateChanged, this, [this](int checked) { useLatestQmlls->setEnabled(checked != Qt::Unchecked); }); + using namespace Layouting; // clang-format off - const auto formattingGroup = + QWidget *formattingGroup = nullptr; + Column { Group { + bindTo(&formattingGroup), title(Tr::tr("Automatic Formatting on File Save")), Column { autoFormatOnSave, @@ -260,10 +263,7 @@ public: formatCommandOptionsLabel, formatCommandOptions } }, - }; - - Column { - formattingGroup, + }, Group { title(Tr::tr("Qt Quick Toolbars")), Column { pinContextPane, enableContextPane }, @@ -283,7 +283,7 @@ public: }.attachTo(this); // clang-format on - Utils::VariableChooser::addSupportForChildWidgets(formattingGroup.widget, + Utils::VariableChooser::addSupportForChildWidgets(formattingGroup, Utils::globalMacroExpander()); const auto updateFormatCommandState = [&, formatCommandLabel, formatCommandOptionsLabel] { diff --git a/src/plugins/scxmleditor/common/navigatorslider.cpp b/src/plugins/scxmleditor/common/navigatorslider.cpp index 68d74dd1bed..dd45a1c8af4 100644 --- a/src/plugins/scxmleditor/common/navigatorslider.cpp +++ b/src/plugins/scxmleditor/common/navigatorslider.cpp @@ -31,11 +31,12 @@ NavigatorSlider::NavigatorSlider(QWidget *parent) using namespace Layouting; Row { + spacing(0), zoomOut, m_slider, zoomIn, Space(20), - }.setSpacing(0).attachTo(this, WithoutMargins); + }.attachTo(this, WithoutMargins); connect(zoomOut, &QToolButton::clicked, this, &NavigatorSlider::zoomOut); connect(zoomIn, &QToolButton::clicked, this, &NavigatorSlider::zoomIn); diff --git a/src/plugins/scxmleditor/common/search.cpp b/src/plugins/scxmleditor/common/search.cpp index 34f26017333..b7b56295fd5 100644 --- a/src/plugins/scxmleditor/common/search.cpp +++ b/src/plugins/scxmleditor/common/search.cpp @@ -47,9 +47,10 @@ Search::Search(QWidget *parent) using namespace Layouting; Column { + spacing(0), m_searchEdit, m_searchView, - }.setSpacing(0).attachTo(this, WithoutMargins); + }.attachTo(this, WithoutMargins); connect(m_searchEdit, &Utils::FancyLineEdit::textChanged, this, &Search::setSearchText); connect(m_searchView, &TableView::pressed, this, &Search::rowActivated); diff --git a/src/plugins/scxmleditor/common/shapestoolbox.cpp b/src/plugins/scxmleditor/common/shapestoolbox.cpp index 1343859cc62..a0354d0bce4 100644 --- a/src/plugins/scxmleditor/common/shapestoolbox.cpp +++ b/src/plugins/scxmleditor/common/shapestoolbox.cpp @@ -31,8 +31,9 @@ ShapesToolbox::ShapesToolbox(QWidget *parent) using namespace Layouting; Column { + spacing(0), scrollArea, - }.setSpacing(0).attachTo(this, WithoutMargins); + }.attachTo(this, WithoutMargins); } void ShapesToolbox::setUIFactory(ScxmlEditor::PluginInterface::ScxmlUiFactory *factory) diff --git a/src/plugins/scxmleditor/common/stateview.cpp b/src/plugins/scxmleditor/common/stateview.cpp index 57759263fd4..e4c23046c7f 100644 --- a/src/plugins/scxmleditor/common/stateview.cpp +++ b/src/plugins/scxmleditor/common/stateview.cpp @@ -38,8 +38,10 @@ StateView::StateView(StateItem *state, QWidget *parent) }.attachTo(titleBar, WithoutMargins); Column { - titleBar, m_graphicsView - }.setSpacing(0).attachTo(this, WithoutMargins); + spacing(0), + titleBar, + m_graphicsView + }.attachTo(this, WithoutMargins); initScene(); } diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp b/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp index 96911edee8c..6620ba52e21 100644 --- a/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp @@ -1,11 +1,6 @@ #include "mainwindow.h" -#include - int main(int argc, char *argv[]) { - QApplication a(argc, argv); - ApplicationWindow w; - w.show(); - return a.exec(); + return app.exec(argc, argv); } diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h index 8ff57827f9d..5ccb647f846 100644 --- a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h @@ -2,28 +2,23 @@ #include "layoutbuilder.h" -#include -#include +#include using namespace Layouting; -class ApplicationWindow : public QWidget +Application app { -public: - ApplicationWindow() - { - resize(600, 400); - setWindowTitle("Hello World"); + resize(600, 400), + title("Hello World"), - Column { - TextEdit { - text("Hallo") - }, + Column { + TextEdit { + text("Hallo") + }, - PushButton { - text("Quit"), - onClicked([] { QCoreApplication::quit(); }) - } - }.attachTo(this); + PushButton { + text("Quit"), + onClicked([] { QApplication::quit(); }) + } } }; diff --git a/tests/manual/layoutbuilder/comparison/quick/Main.qml b/tests/manual/layoutbuilder/comparison/quick/Main.qml index 2200399429d..617b573caaa 100644 --- a/tests/manual/layoutbuilder/comparison/quick/Main.qml +++ b/tests/manual/layoutbuilder/comparison/quick/Main.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -ApplicationWindow { - +ApplicationWindow +{ width: 640 height: 480 visible: true diff --git a/tests/manual/layoutbuilder/comparison/widgets/main.cpp b/tests/manual/layoutbuilder/comparison/widgets/main.cpp index 5d394e06c38..c610fc6a497 100644 --- a/tests/manual/layoutbuilder/comparison/widgets/main.cpp +++ b/tests/manual/layoutbuilder/comparison/widgets/main.cpp @@ -1,8 +1,5 @@ - #include "mainwindow.h" -#include - int main(int argc, char *argv[]) { QApplication a(argc, argv); diff --git a/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h index 9acf84d4b55..1dc8ad6f838 100644 --- a/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h +++ b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h @@ -23,6 +23,6 @@ public: l->addWidget(pushButton); connect(pushButton, &QPushButton::clicked, - qApp, &QCoreApplication::quit); + qApp, &QApplication::quit); } }; diff --git a/tests/manual/tasktree/taskwidget.cpp b/tests/manual/tasktree/taskwidget.cpp index d5420defe59..e2770d916e3 100644 --- a/tests/manual/tasktree/taskwidget.cpp +++ b/tests/manual/tasktree/taskwidget.cpp @@ -184,11 +184,8 @@ Tasking::WorkflowPolicy GroupWidget::workflowPolicy() const return m_workflowPolicy; } - -void doLayout(const TaskGroup &taskGroup, LayoutBuilder &builder) +void createItem(Layouting::LayoutItem *item, const TaskGroup &taskGroup) { - builder.addItem(taskGroup.group); - builder.addItem(Group { taskGroup.items }); - builder.finishRow(); + item->addItems({taskGroup.group, Group { taskGroup.items }, br}); } diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasktree/taskwidget.h index 8caebf658b2..0e7828ac84b 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasktree/taskwidget.h @@ -83,4 +83,4 @@ public: Layouting::Column items; }; -void doLayout(const TaskGroup &taskGroup, Layouting::LayoutBuilder &builder); +void createItem(Layouting::LayoutItem *item, const TaskGroup &taskGroup); From 50084f6b0ed78bfee6f5e1d2e56ade9b52b3f2f6 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 2 May 2023 12:51:03 +0200 Subject: [PATCH 0798/1447] Layouting: Handle attach types via setter Change-Id: I862f5cd109db3582b4f029787ec0cded2da39ce6 Reviewed-by: Qt CI Bot Reviewed-by: Alessandro Portale --- .../extensionsystem/plugindetailsview.cpp | 5 +- src/libs/extensionsystem/pluginerrorview.cpp | 5 +- src/libs/utils/layoutbuilder.cpp | 92 +++++++++++++------ src/libs/utils/layoutbuilder.h | 15 ++- src/plugins/android/androidbuildapkstep.cpp | 5 +- src/plugins/android/androiddeployqtstep.cpp | 3 +- .../android/androidsdkmanagerwidget.cpp | 8 +- src/plugins/bazaar/bazaarcommitwidget.cpp | 5 +- .../artisticstyleoptionspage.cpp | 5 +- src/plugins/beautifier/configurationpanel.cpp | 5 +- .../clangformatglobalconfigwidget.cpp | 19 ++-- .../clangtoolsprojectsettingswidget.cpp | 5 +- .../clangtools/diagnosticconfigswidget.cpp | 18 ++-- src/plugins/clangtools/runsettingswidget.cpp | 5 +- src/plugins/clearcase/settingspage.cpp | 4 +- .../cmakebuildconfiguration.cpp | 8 +- .../cmakeprojectmanager/cmakebuildstep.cpp | 3 +- .../cmakeprojectmanager/cmakeinstallstep.cpp | 3 +- .../coreplugin/dialogs/addtovcsdialog.cpp | 2 +- .../coreplugin/dialogs/externaltoolconfig.cpp | 6 +- .../dialogs/readonlyfilesdialog.cpp | 8 +- .../coreplugin/find/findtoolwindow.cpp | 3 +- src/plugins/coreplugin/welcomepagehelper.cpp | 18 +++- .../cppeditor/cppcodemodelinspectordialog.cpp | 3 +- .../cppeditor/cppquickfixsettingswidget.cpp | 5 +- .../debuggerrunconfigurationaspect.cpp | 3 +- src/plugins/designer/cpp/newclasswidget.cpp | 3 +- src/plugins/docker/dockerdevicewidget.cpp | 3 +- src/plugins/fossil/fossilcommitwidget.cpp | 5 +- src/plugins/git/gitsubmiteditorwidget.cpp | 3 +- src/plugins/gitlab/gitlaboptionspage.cpp | 5 +- .../mercurial/mercurialcommitwidget.cpp | 5 +- src/plugins/mercurial/revertdialog.cpp | 4 +- .../mesonbuildsettingswidget.cpp | 10 +- .../mesonprojectmanager/toolitemsettings.cpp | 3 +- src/plugins/nim/project/nimbletaskstep.cpp | 5 +- .../nimcodestylepreferenceswidget.cpp | 3 +- .../projectexplorer/buildconfiguration.cpp | 3 +- src/plugins/projectexplorer/buildstep.cpp | 3 +- .../codestylesettingspropertiespage.cpp | 5 +- .../editorsettingspropertiespage.cpp | 3 +- src/plugins/projectexplorer/kitmanager.cpp | 2 +- .../kitmanagerconfigwidget.cpp | 6 +- src/plugins/projectexplorer/makestep.cpp | 3 +- .../projectexplorer/runconfiguration.cpp | 4 +- src/plugins/python/pythonsettings.cpp | 5 +- src/plugins/python/pythonwizardpage.cpp | 5 +- .../qbsprojectmanager/qbsbuildstep.cpp | 3 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 3 +- .../qmljstools/qmljscodestylesettingspage.cpp | 3 +- .../qmljscodestylesettingswidget.cpp | 5 +- src/plugins/qtsupport/qtoptionspage.cpp | 5 +- .../scxmleditor/common/colorpicker.cpp | 4 +- .../scxmleditor/common/colorsettings.cpp | 3 +- .../scxmleditor/common/navigatorslider.cpp | 3 +- src/plugins/scxmleditor/common/search.cpp | 3 +- .../scxmleditor/common/shapestoolbox.cpp | 3 +- src/plugins/scxmleditor/common/stateview.cpp | 8 +- src/plugins/scxmleditor/common/statistics.cpp | 5 +- .../texteditor/behaviorsettingswidget.cpp | 5 +- src/plugins/texteditor/codestyleeditor.cpp | 1 + .../texteditor/codestyleselectorwidget.cpp | 4 +- src/plugins/texteditor/colorschemeedit.cpp | 3 +- src/plugins/vcsbase/submiteditorwidget.cpp | 5 +- tests/manual/tasktree/taskwidget.cpp | 10 +- 65 files changed, 265 insertions(+), 160 deletions(-) diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp index 8fd9e7b5efc..49ba0815a35 100644 --- a/src/libs/extensionsystem/plugindetailsview.cpp +++ b/src/libs/extensionsystem/plugindetailsview.cpp @@ -68,8 +68,9 @@ public: Tr::tr("Description:"), description, br, Tr::tr("Copyright:"), copyright, br, Tr::tr("License:"), license, br, - Tr::tr("Dependencies:"), dependencies - }.attachTo(q, WithoutMargins); + Tr::tr("Dependencies:"), dependencies, + noMargin + }.attachTo(q); // clang-format on } diff --git a/src/libs/extensionsystem/pluginerrorview.cpp b/src/libs/extensionsystem/pluginerrorview.cpp index 42374b03768..31c4334b6af 100644 --- a/src/libs/extensionsystem/pluginerrorview.cpp +++ b/src/libs/extensionsystem/pluginerrorview.cpp @@ -45,8 +45,9 @@ public: Form { Tr::tr("State:"), state, br, - Tr::tr("Error message:"), errorString - }.attachTo(q, WithoutMargins); + Tr::tr("Error message:"), errorString, + noMargin, + }.attachTo(q); } PluginErrorView *q = nullptr; diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index c7ead009c74..48a75fc1623 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -79,17 +79,19 @@ struct LayoutBuilder::Slice Slice() = default; Slice(QLayout *l) : layout(l) {} Slice(QWidget *w) : widget(w) {} - Slice(QWidget *w, AttachType a) : widget(w), attachType(a) {} QLayout *layout = nullptr; QWidget *widget = nullptr; void flush(); + // Grid-specific int currentGridColumn = 0; int currentGridRow = 0; + bool isFormAlignment = false; + Qt::Alignment align = {}; // Can be changed to - AttachType attachType = WithMargins; + // Grid or Form QList pendingItems; }; @@ -192,9 +194,6 @@ void LayoutBuilder::Slice::flush() } else if (auto gridLayout = qobject_cast(layout)) { for (const ResultItem &item : std::as_const(pendingItems)) { - Qt::Alignment align = {}; - // if (attachType == Layouting::WithFormAlignment && currentGridColumn == 0) - // align = Qt::Alignment(m_widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment)); if (item.widget) gridLayout->addWidget(item.widget, currentGridRow, currentGridColumn, 1, item.span, align); else if (item.layout) @@ -374,18 +373,18 @@ void LayoutItem::addItems(const LayoutItems &items) This operation can only be performed once per LayoutBuilder instance. */ -void LayoutItem::attachTo(QWidget *w, AttachType attachType) const +void LayoutItem::attachTo(QWidget *w) const { LayoutBuilder builder; - builder.stack.append({w, attachType}); + builder.stack.append(w); addItemHelper(builder, *this); } -QWidget *LayoutItem::emerge(Layouting::AttachType attachType) +QWidget *LayoutItem::emerge() { auto w = new QWidget; - attachTo(w, attachType); + attachTo(w); return w; } @@ -398,8 +397,6 @@ static void layoutExit(LayoutBuilder &builder) { builder.stack.last().flush(); QLayout *layout = builder.stack.last().layout; - if (builder.stack.back().attachType == WithoutMargins) - layout->setContentsMargins(0, 0, 0, 0); builder.stack.pop_back(); if (QWidget *widget = builder.stack.last().widget) @@ -411,8 +408,6 @@ static void layoutExit(LayoutBuilder &builder) static void widgetExit(LayoutBuilder &builder) { QWidget *widget = builder.stack.last().widget; - if (builder.stack.back().attachType == WithoutMargins) - widget->setContentsMargins(0, 0, 0, 0); builder.stack.pop_back(); builder.stack.last().pendingItems.append(ResultItem(widget)); } @@ -464,7 +459,7 @@ LayoutItem br() LayoutItem item; item.onAdd = [](LayoutBuilder &builder) { builder.stack.last().flush(); - }; + }; return item; } @@ -473,6 +468,58 @@ LayoutItem empty() return {}; } +LayoutItem hr() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { doAddWidget(builder, createHr()); }; + return item; +} + +LayoutItem st() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { doAddStretch(builder, Stretch(1)); }; + return item; +} + +LayoutItem noMargin() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { + if (auto layout = builder.stack.last().layout) + layout->setContentsMargins(0, 0, 0, 0); + else if (auto widget = builder.stack.last().widget) + widget->setContentsMargins(0, 0, 0, 0); + }; + return item; +} + +LayoutItem normalMargin() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { + if (auto layout = builder.stack.last().layout) + layout->setContentsMargins(9, 9, 9, 9); + else if (auto widget = builder.stack.last().widget) + widget->setContentsMargins(9, 9, 9, 9); + }; + return item; +} + +LayoutItem withFormAlignment() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { + if (builder.stack.size() >= 2) { + if (auto widget = builder.stack.at(builder.stack.size() - 2).widget) { + const Qt::Alignment align(widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment)); + builder.stack.last().align = align; + } + } + }; + return item; +} + /*! Constructs a layout extender to extend an existing \a layout. @@ -481,13 +528,12 @@ LayoutItem empty() new items will be added below existing ones. */ -LayoutExtender::LayoutExtender(QLayout *layout, Layouting::AttachType attachType) +LayoutExtender::LayoutExtender(QLayout *layout) { Slice slice; slice.layout = layout; if (auto gridLayout = qobject_cast(layout)) slice.currentGridRow = gridLayout->rowCount(); - slice.attachType = attachType; stack.append(slice); } @@ -700,18 +746,4 @@ void createItem(LayoutItem *item, const Span &t) }; } -LayoutItem hr() -{ - LayoutItem item; - item.onAdd = [](LayoutBuilder &builder) { doAddWidget(builder, createHr()); }; - return item; -} - -LayoutItem st() -{ - LayoutItem item; - item.onAdd = [](LayoutBuilder &builder) { doAddStretch(builder, Stretch(1)); }; - return item; -} - } // Layouting diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 1e9e6b9ad3e..e63c359e7ed 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -24,12 +24,6 @@ QT_END_NAMESPACE namespace Layouting { -enum AttachType { - WithMargins, - WithoutMargins, - WithFormAlignment, // Handle Grid similar to QFormLayout, i.e. use special alignment for the first column on Mac -}; - class LayoutBuilder; class LayoutItem; class Span; @@ -88,8 +82,8 @@ public: createItem(this, t); } - void attachTo(QWidget *w, AttachType attachType = WithMargins) const; - QWidget *emerge(AttachType attachType = WithMargins); + void attachTo(QWidget *w) const; + QWidget *emerge(); void addItem(const LayoutItem &item); void addItems(const LayoutItems &items); @@ -193,6 +187,9 @@ QTCREATOR_UTILS_EXPORT LayoutItem br(); QTCREATOR_UTILS_EXPORT LayoutItem st(); QTCREATOR_UTILS_EXPORT LayoutItem empty(); QTCREATOR_UTILS_EXPORT LayoutItem hr(); +QTCREATOR_UTILS_EXPORT LayoutItem noMargin(); +QTCREATOR_UTILS_EXPORT LayoutItem normalMargin(); +QTCREATOR_UTILS_EXPORT LayoutItem withFormAlignment(); // "Properties" @@ -238,7 +235,7 @@ public: class QTCREATOR_UTILS_EXPORT LayoutExtender : public LayoutBuilder { public: - explicit LayoutExtender(QLayout *layout, AttachType attachType); + explicit LayoutExtender(QLayout *layout); ~LayoutExtender(); }; diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 6e7dba97252..25a7c4f6ec6 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -137,8 +137,9 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) createSignPackageGroup(), createApplicationGroup(), createAdvancedGroup(), - createAdditionalLibrariesGroup() - }.attachTo(this, WithoutMargins); + createAdditionalLibrariesGroup(), + noMargin + }.attachTo(this); connect(m_step->buildConfiguration(), &BuildConfiguration::buildTypeChanged, this, &AndroidBuildApkWidget::updateSigningWarning); diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index f108b1880f9..9d288fc5a0a 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -606,7 +606,8 @@ QWidget *AndroidDeployQtStep::createConfigWidget() Layouting::Form builder; builder.addRow({m_uninstallPreviousPackage}); builder.addRow({installCustomApkButton}); - builder.attachTo(widget, Layouting::WithoutMargins); + builder.addItem(Layouting::noMargin); + builder.attachTo(widget); return widget; } diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index d071883a556..8627e0c64ed 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -141,14 +141,16 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config, } }, optionsButton - } - }.attachTo(m_packagesStack, WithoutMargins); + }, + noMargin + }.attachTo(m_packagesStack); Column { m_outputEdit, Row { m_sdkLicenseLabel, m_sdkLicenseButtonBox }, m_operationProgress, - }.attachTo(m_outputStack, WithoutMargins); + noMargin + }.attachTo(m_outputStack); Column { m_viewStack, diff --git a/src/plugins/bazaar/bazaarcommitwidget.cpp b/src/plugins/bazaar/bazaarcommitwidget.cpp index 34cf2bb7ac4..379fca66610 100644 --- a/src/plugins/bazaar/bazaarcommitwidget.cpp +++ b/src/plugins/bazaar/bazaarcommitwidget.cpp @@ -65,8 +65,9 @@ public: Tr::tr("Email:"), emailLineEdit, br, Tr::tr("Fixed bugs:"), fixedBugsLineEdit } - } - }.attachTo(this, WithoutMargins); + }, + noMargin + }.attachTo(this); } QLineEdit *branchLineEdit; diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp index a968c2eb962..f13c764edde 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp @@ -90,8 +90,9 @@ ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSett m_useOtherFiles, Row { m_useSpecificConfigFile, m_specificConfigFile }, m_useHomeFile, - Row { m_useCustomStyle, m_configurations } - }.attachTo(options, WithoutMargins); + Row { m_useCustomStyle, m_configurations }, + noMargin, + }.attachTo(options); Column { Group { diff --git a/src/plugins/beautifier/configurationpanel.cpp b/src/plugins/beautifier/configurationpanel.cpp index 5e40c55f2b2..eae33d5ff99 100644 --- a/src/plugins/beautifier/configurationpanel.cpp +++ b/src/plugins/beautifier/configurationpanel.cpp @@ -32,8 +32,9 @@ ConfigurationPanel::ConfigurationPanel(QWidget *parent) m_configurations, m_edit, m_remove, - add - }.attachTo(this, WithoutMargins); + add, + noMargin, + }.attachTo(this); connect(add, &QPushButton::clicked, this, &ConfigurationPanel::add); connect(m_edit, &QPushButton::clicked, this, &ConfigurationPanel::edit); diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index 44d32cc3a91..95cac0d3bca 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -49,19 +49,20 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget( Group globalSettingsGroupBox { bindTo(&globalSettingsGroupBoxWidget), title(Tr::tr("ClangFormat settings:")), - Column { - m_useGlobalSettings, - Row { m_formattingModeLabel, m_indentingOrFormatting, st }, - m_formatWhileTyping, - m_formatOnSave, - m_projectHasClangFormat, - m_overrideDefault + Column { + m_useGlobalSettings, + Row { m_formattingModeLabel, m_indentingOrFormatting, st }, + m_formatWhileTyping, + m_formatOnSave, + m_projectHasClangFormat, + m_overrideDefault } }; Column { - globalSettingsGroupBox - }.attachTo(this, Layouting::WithoutMargins); + globalSettingsGroupBox, + noMargin + }.attachTo(this); initCheckBoxes(); initIndentationOrFormattingCombobox(); diff --git a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp index 4db61677223..8e1ac057f93 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettingswidget.cpp @@ -84,8 +84,9 @@ ClangToolsProjectSettingsWidget::ClangToolsProjectSettingsWidget(ProjectExplorer st } } - } - }.attachTo(this, WithoutMargins); + }, + noMargin + }.attachTo(this); setUseGlobalSettings(m_projectSettings->useGlobalSettings()); onGlobalCustomChanged(useGlobalSettings()); diff --git a/src/plugins/clangtools/diagnosticconfigswidget.cpp b/src/plugins/clangtools/diagnosticconfigswidget.cpp index 2b44fa6da85..57480bf8cd9 100644 --- a/src/plugins/clangtools/diagnosticconfigswidget.cpp +++ b/src/plugins/clangtools/diagnosticconfigswidget.cpp @@ -90,13 +90,15 @@ public: using namespace Layouting; Column { - checksPrefixesTree - }.attachTo(checksPage, WithoutMargins); + checksPrefixesTree, + noMargin + }.attachTo(checksPage); Column { invalidExecutableLabel, st, - }.attachTo(invalidExecutablePage, WithoutMargins); + noMargin + }.attachTo(invalidExecutablePage); Column { Row { plainTextEditButton, filterLineEdit }, @@ -169,13 +171,15 @@ public: Column { label, - Row { groupBox, checksGroupBox } - }.attachTo(checksPage, WithoutMargins); + Row { groupBox, checksGroupBox }, + noMargin + }.attachTo(checksPage); Column { invalidExecutableLabel, - st - }.attachTo(invalidExecutablePage, WithoutMargins); + st, + noMargin + }.attachTo(invalidExecutablePage); Column { enableLowerLevelsCheckBox, diff --git a/src/plugins/clangtools/runsettingswidget.cpp b/src/plugins/clangtools/runsettingswidget.cpp index 841661f0155..4581082c0fe 100644 --- a/src/plugins/clangtools/runsettingswidget.cpp +++ b/src/plugins/clangtools/runsettingswidget.cpp @@ -50,8 +50,9 @@ RunSettingsWidget::RunSettingsWidget(QWidget *parent) m_analyzeOpenFiles, Row { Tr::tr("Parallel jobs:"), m_parallelJobsSpinBox, st }, } - } - }.attachTo(this, WithoutMargins); + }, + noMargin + }.attachTo(this); } RunSettingsWidget::~RunSettingsWidget() = default; diff --git a/src/plugins/clearcase/settingspage.cpp b/src/plugins/clearcase/settingspage.cpp index bcbab9f16ae..0489340865e 100644 --- a/src/plugins/clearcase/settingspage.cpp +++ b/src/plugins/clearcase/settingspage.cpp @@ -109,8 +109,8 @@ SettingsPageWidget::SettingsPageWidget() using namespace Layouting; Form { - Tr::tr("Arg&uments:"), diffArgsEdit - }.attachTo(diffWidget, WithoutMargins); + Tr::tr("Arg&uments:"), diffArgsEdit, noMargin + }.attachTo(diffWidget); Column { Group { diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index a56564a8c0a..fb15eefdc08 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -354,12 +354,14 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildSystem *bs) : } }, configureEnvironmentAspectWidget - } - }.attachTo(details, WithoutMargins); + }, + noMargin + }.attachTo(details); Column { m_configureDetailsWidget, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); updateAdvancedCheckBox(); setError(m_buildSystem->error()); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index da5cf42e041..d4e50a0c27e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -577,7 +577,8 @@ QWidget *CMakeBuildStep::createConfigWidget() if (!isCleanStep() && !m_buildPreset.isEmpty()) createAndAddEnvironmentWidgets(builder); - auto widget = builder.emerge(Layouting::WithoutMargins); + builder.addItem(Layouting::noMargin); + auto widget = builder.emerge(); updateDetails(); diff --git a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp index 97c29631c47..91faa2ebaf8 100644 --- a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp @@ -108,8 +108,9 @@ QWidget *CMakeInstallStep::createConfigWidget() Layouting::Form builder; builder.addRow({m_cmakeArguments}); + builder.addItem(Layouting::noMargin); - auto widget = builder.emerge(Layouting::WithoutMargins); + auto widget = builder.emerge(); updateDetails(); diff --git a/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp b/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp index bb98305910e..09a4bf45921 100644 --- a/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/addtovcsdialog.cpp @@ -33,7 +33,7 @@ AddToVcsDialog::AddToVcsDialog(QWidget *parent, filesListWidget->setSelectionMode(QAbstractItemView::NoSelection); filesListWidget->setSelectionBehavior(QAbstractItemView::SelectRows); - QWidget *scrollAreaWidgetContents = Column{filesListWidget}.emerge(WithoutMargins); + QWidget *scrollAreaWidgetContents = Column{filesListWidget, noMargin}.emerge(); scrollAreaWidgetContents->setGeometry({0, 0, 341, 300}); auto scrollArea = new QScrollArea; diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp index 270ed9f681d..0d4404c7144 100644 --- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp +++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp @@ -564,11 +564,11 @@ ExternalToolConfig::ExternalToolConfig() Tr::tr("Environment:"), m_environmentLabel, environmentButton, br, empty, m_modifiesDocumentCheckbox, br, inputLabel, m_inputText - }.attachTo(m_infoWidget, WithMargins); + }.attachTo(m_infoWidget); Column { - m_infoWidget - }.attachTo(scrollAreaWidgetContents, WithoutMargins); + m_infoWidget, noMargin + }.attachTo(scrollAreaWidgetContents); Row { Column { diff --git a/src/plugins/coreplugin/dialogs/readonlyfilesdialog.cpp b/src/plugins/coreplugin/dialogs/readonlyfilesdialog.cpp index 97d35aca82c..88431454fef 100644 --- a/src/plugins/coreplugin/dialogs/readonlyfilesdialog.cpp +++ b/src/plugins/coreplugin/dialogs/readonlyfilesdialog.cpp @@ -422,8 +422,12 @@ void ReadOnlyFilesDialogPrivate::initDialog(const FilePaths &filePaths) using namespace Layouting; - QWidget *setAllWidget = Row{Tr::tr("Select all, if possible: "), m_setAll, st}.emerge( - WithoutMargins); + QWidget *setAllWidget = Row { + Tr::tr("Select all, if possible: "), + m_setAll, + st, + noMargin + }.emerge(); // clang-format off Column { diff --git a/src/plugins/coreplugin/find/findtoolwindow.cpp b/src/plugins/coreplugin/find/findtoolwindow.cpp index 1ab13cdc7c1..0125671d34e 100644 --- a/src/plugins/coreplugin/find/findtoolwindow.cpp +++ b/src/plugins/coreplugin/find/findtoolwindow.cpp @@ -109,7 +109,8 @@ FindToolWindow::FindToolWindow(QWidget *parent) m_wholeWords, m_regExp, st, - }.attachTo(m_optionsWidget, WithoutMargins); + noMargin + }.attachTo(m_optionsWidget); Grid { label, m_filterList, br, diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 77ef96e9be0..ad7c5867476 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -796,8 +796,13 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetContentsMargins(0, ItemGap, 0, 0); sectionLabel->setFont(Core::WelcomePageHelpers::brandFont()); @@ -849,8 +854,13 @@ void SectionedGridView::zoomInSection(const Section §ion) setCurrentIndex(0); }); using namespace Layouting; - QWidget *sectionLabel = Row{section.name, createSeparator(this), backLink, Space(HSpacing)} - .emerge(Layouting::WithoutMargins); + QWidget *sectionLabel = Row { + section.name, + createSeparator(this), + backLink, + Space(HSpacing), + noMargin + }.emerge(); sectionLabel->setContentsMargins(0, ItemGap, 0, 0); sectionLabel->setFont(Core::WelcomePageHelpers::brandFont()); diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp index 7c4d2c845dd..48ee4c80f1e 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp @@ -1485,7 +1485,8 @@ CppCodeModelInspectorDialog::CppCodeModelInspectorDialog(QWidget *parent) Column { Form { QString("Sn&apshot:"), m_snapshotSelector }, m_snapshotView, - }.emerge(Layouting::WithoutMargins), + noMargin, + }.emerge(), docTab, }, } diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.cpp b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp index ce7b4aba727..679d140967f 100644 --- a/src/plugins/cppeditor/cppquickfixsettingswidget.cpp +++ b/src/plugins/cppeditor/cppquickfixsettingswidget.cpp @@ -54,7 +54,7 @@ LineCountSpinBox::LineCountSpinBox(QWidget *parent) m_unitLabel = new QLabel(Tr::tr("lines")); using namespace Layouting; - Row { m_checkBox, m_opLabel, m_spinBox, m_unitLabel, }.attachTo(this, WithoutMargins); + Row { m_checkBox, m_opLabel, m_spinBox, m_unitLabel, noMargin }.attachTo(this); auto handleChange = [this] { updateFields(); @@ -220,7 +220,8 @@ e.g. name = "m_test_foo_": Tr::tr("Inside class:"), Tr::tr("Default"), Tr::tr("Default"), br, Tr::tr("Outside class:"), m_lines_setterOutsideClass, m_lines_getterOutsideClass, br, Tr::tr("In .cpp file:"), m_lines_setterInCppFile, m_lines_getterInCppFile, br, - }.attachTo(functionLocationsGrid, WithoutMargins); + noMargin, + }.attachTo(functionLocationsGrid); if (QGridLayout *gl = qobject_cast(functionLocationsGrid->layout())) gl->setHorizontalSpacing(48); diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 3c636c66924..7b64c0375f8 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -67,7 +67,8 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) details->setState(DetailsWidget::Expanded); auto innerPane = new QWidget; details->setWidget(innerPane); - builder.attachTo(innerPane, Layouting::WithoutMargins); + builder.addItem(Layouting::noMargin); + builder.attachTo(innerPane); const auto setSummaryText = [this, details] { QStringList items; diff --git a/src/plugins/designer/cpp/newclasswidget.cpp b/src/plugins/designer/cpp/newclasswidget.cpp index e6b24e55617..924700b59c0 100644 --- a/src/plugins/designer/cpp/newclasswidget.cpp +++ b/src/plugins/designer/cpp/newclasswidget.cpp @@ -73,7 +73,8 @@ NewClassWidget::NewClassWidget(QWidget *parent) : Tr::tr("&Source file:"), d->m_sourceFileLineEdit, br, Tr::tr("&Form file:"), d->m_formFileLineEdit, br, Tr::tr("&Path:"), d->m_pathChooser, br, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); connect(d->m_classLineEdit, &ClassNameValidatingLineEdit::updateFileName, this, &NewClassWidget::slotUpdateFileNames); diff --git a/src/plugins/docker/dockerdevicewidget.cpp b/src/plugins/docker/dockerdevicewidget.cpp index 8477256a356..cd32fead6fb 100644 --- a/src/plugins/docker/dockerdevicewidget.cpp +++ b/src/plugins/docker/dockerdevicewidget.cpp @@ -247,7 +247,8 @@ DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device) m_pathsListEdit, }, br, (dockerDevice->isAutoDetected() ? Column {} : std::move(detectionControls)), - }.attachTo(this, WithoutMargins); + noMargin, + }.attachTo(this); // clang-format on searchDirsLineEdit->setVisible(false); diff --git a/src/plugins/fossil/fossilcommitwidget.cpp b/src/plugins/fossil/fossilcommitwidget.cpp index 5658ed9f760..355a792bfda 100644 --- a/src/plugins/fossil/fossilcommitwidget.cpp +++ b/src/plugins/fossil/fossilcommitwidget.cpp @@ -120,8 +120,9 @@ FossilCommitWidget::FossilCommitWidget() : m_commitPanel(new QWidget) Tr::tr("Tags:"), m_tagsLineEdit, br, Tr::tr("Author:"), m_authorLineEdit, st, } - } - }.attachTo(m_commitPanel, WithoutMargins); + }, + noMargin + }.attachTo(m_commitPanel); insertTopWidget(m_commitPanel); new FossilSubmitHighlighter(descriptionEdit()); diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp index 65bc5beab41..946fc6f77c7 100644 --- a/src/plugins/git/gitsubmiteditorwidget.cpp +++ b/src/plugins/git/gitsubmiteditorwidget.cpp @@ -81,7 +81,8 @@ public: } }, editGroup, - }.attachTo(this, WithoutMargins); + noMargin, + }.attachTo(this); } QLabel *repositoryLabel; diff --git a/src/plugins/gitlab/gitlaboptionspage.cpp b/src/plugins/gitlab/gitlaboptionspage.cpp index 447b9111a83..c9e654af83a 100644 --- a/src/plugins/gitlab/gitlaboptionspage.cpp +++ b/src/plugins/gitlab/gitlaboptionspage.cpp @@ -101,9 +101,10 @@ GitLabServerWidget::GitLabServerWidget(Mode m, QWidget *parent) m_description, m_token, m_port, - m_secure + m_secure, + m == Edit ? normalMargin : noMargin }, - }.attachTo(this, m == Edit ? WithMargins : WithoutMargins); + }.attachTo(this); } GitLabServer GitLabServerWidget::gitLabServer() const diff --git a/src/plugins/mercurial/mercurialcommitwidget.cpp b/src/plugins/mercurial/mercurialcommitwidget.cpp index 0f57581aed0..c6b35a67d08 100644 --- a/src/plugins/mercurial/mercurialcommitwidget.cpp +++ b/src/plugins/mercurial/mercurialcommitwidget.cpp @@ -119,8 +119,9 @@ public: Tr::tr("Email:"), m_emailLineEdit, }, } - } - }.attachTo(this, Layouting::WithoutMargins); + }, + noMargin + }.attachTo(this); } QLabel *m_repositoryLabel; diff --git a/src/plugins/mercurial/revertdialog.cpp b/src/plugins/mercurial/revertdialog.cpp index cc140ee0b68..29ee250e55e 100644 --- a/src/plugins/mercurial/revertdialog.cpp +++ b/src/plugins/mercurial/revertdialog.cpp @@ -30,8 +30,8 @@ RevertDialog::RevertDialog(QWidget *parent) using namespace Layouting; Form { - Tr::tr("Revision:"), m_revisionLineEdit, - }.attachTo(groupBox, WithMargins); + Tr::tr("Revision:"), m_revisionLineEdit, normalMargin + }.attachTo(groupBox); Column { groupBox, diff --git a/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp b/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp index 8becece66b1..32719c08d61 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp @@ -67,16 +67,18 @@ MesonBuildSettingsWidget::MesonBuildSettingsWidget(MesonBuildConfiguration *buil buildDirWidget, optionsFilterLineEdit, optionsTreeView, - }.attachTo(details, WithoutMargins); + noMargin + }.attachTo(details); Column { container, - Row { configureButton, wipeButton, } - }.attachTo(this, WithoutMargins); + Row { configureButton, wipeButton, noMargin } + }.attachTo(this); Form { buildCfg->buildDirectoryAspect(), - }.attachTo(buildDirWidget, WithoutMargins); + noMargin + }.attachTo(buildDirWidget); parametersLineEdit->setText(buildCfg->parameters()); optionsFilterLineEdit->setFiltering(true); diff --git a/src/plugins/mesonprojectmanager/toolitemsettings.cpp b/src/plugins/mesonprojectmanager/toolitemsettings.cpp index 148e3e5faed..a0591b905c5 100644 --- a/src/plugins/mesonprojectmanager/toolitemsettings.cpp +++ b/src/plugins/mesonprojectmanager/toolitemsettings.cpp @@ -29,7 +29,8 @@ ToolItemSettings::ToolItemSettings(QWidget *parent) Form { Tr::tr("Name:"), m_mesonNameLineEdit, br, Tr::tr("Path:"), m_mesonPathChooser, br, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); connect(m_mesonPathChooser, &PathChooser::rawPathChanged, this, &ToolItemSettings::store); connect(m_mesonNameLineEdit, &QLineEdit::textChanged, this, &ToolItemSettings::store); diff --git a/src/plugins/nim/project/nimbletaskstep.cpp b/src/plugins/nim/project/nimbletaskstep.cpp index 06cf14a1077..e072b9422ee 100644 --- a/src/plugins/nim/project/nimbletaskstep.cpp +++ b/src/plugins/nim/project/nimbletaskstep.cpp @@ -88,8 +88,9 @@ QWidget *NimbleTaskStep::createConfigWidget() using namespace Layouting; auto widget = Form { m_taskArgs, - Tr::tr("Tasks:"), taskList - }.emerge(WithoutMargins); + Tr::tr("Tasks:"), taskList, + noMargin + }.emerge(); auto buildSystem = dynamic_cast(this->buildSystem()); QTC_ASSERT(buildSystem, return widget); diff --git a/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp b/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp index 7d13950b672..ec9cfa170e0 100644 --- a/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp +++ b/src/plugins/nim/settings/nimcodestylepreferenceswidget.cpp @@ -44,7 +44,8 @@ NimCodeStylePreferencesWidget::NimCodeStylePreferencesWidget(ICodeStylePreferenc st, }, m_previewTextEdit, - }.attachTo(this, WithoutMargins); + noMargin, + }.attachTo(this); decorateEditor(TextEditorSettings::fontSettings()); connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 904530e9c77..772bd64610e 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -327,7 +327,8 @@ NamedWidget *BuildConfiguration::createConfigWidget() if (aspect->isVisible()) form.addItem(aspect); } - form.attachTo(widget, Layouting::WithoutMargins); + form.addItem(Layouting::noMargin); + form.attachTo(widget); return named; } diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index a7f74c3f03d..46283b4c9fa 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -165,7 +165,8 @@ QWidget *BuildStep::createConfigWidget() if (aspect->isVisible()) form.addItem(aspect); } - auto widget = form.emerge(Layouting::WithoutMargins); + form.addItem(Layouting::noMargin); + auto widget = form.emerge(); if (m_addMacroExpander) VariableChooser::addSupportForChildWidgets(widget, macroExpander()); diff --git a/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp b/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp index 85cd9772625..f7ed131e575 100644 --- a/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/codestylesettingspropertiespage.cpp @@ -52,8 +52,9 @@ CodeStyleSettingsWidget::CodeStyleSettingsWidget(Project *project) Column { Row { new QLabel(Tr::tr("Language:")), languageComboBox, st }, - stackedWidget - }.attachTo(this, WithoutMargins); + stackedWidget, + noMargin + }.attachTo(this); } } // ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp index c32912f7444..e0c2b93bb26 100644 --- a/src/plugins/projectexplorer/editorsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/editorsettingspropertiespage.cpp @@ -63,7 +63,8 @@ EditorSettingsWidget::EditorSettingsWidget(Project *project) : m_project(project m_displaySettings, m_behaviorSettings, st, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); const EditorConfiguration *config = m_project->editorConfiguration(); settingsToUi(config); diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 65c8475adba..b2c773b55c3 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -756,7 +756,7 @@ void KitAspectWidget::addToLayoutWithLabel(QWidget *parent) emit labelLinkActivated(link); }); - Layouting::LayoutExtender builder(parent->layout(), Layouting::WithFormAlignment); + Layouting::LayoutExtender builder(parent->layout()); builder.addItems({label, Layouting::br}); addToLayout(builder); } diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index 1f7ea6f88ba..c1f8a3ed79a 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -67,9 +67,11 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k, bool &isDefaultKit, bool using namespace Layouting; Grid { + withFormAlignment, label, m_nameEdit, m_iconButton, br, - fsLabel, m_fileSystemFriendlyNameLineEdit - }.attachTo(this, WithFormAlignment); + fsLabel, m_fileSystemFriendlyNameLineEdit, + noMargin + }.attachTo(this); m_iconButton->setToolTip(Tr::tr("Kit icon.")); auto setIconAction = new QAction(Tr::tr("Select Icon..."), this); diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 3024eb65f75..9a3a939f34f 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -324,8 +324,9 @@ QWidget *MakeStep::createConfigWidget() if (m_disablingForSubDirsSupported) builder.addRow({m_disabledForSubdirsAspect}); builder.addRow({m_buildTargetsAspect}); + builder.addItem(Layouting::noMargin); - auto widget = builder.emerge(Layouting::WithoutMargins); + auto widget = builder.emerge(); VariableChooser::addSupportForChildWidgets(widget, macroExpander()); diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index c6e47f7f838..43e01576e2e 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -221,8 +221,8 @@ QWidget *RunConfiguration::createConfigurationWidget() if (aspect->isVisible()) form.addItem(aspect); } - - auto widget = form.emerge(Layouting::WithoutMargins); + form.addItem(Layouting::noMargin); + auto widget = form.emerge(); VariableChooser::addSupportForChildWidgets(widget, &m_expander); diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 714b8158189..d6eccc999ba 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -96,8 +96,9 @@ public: Form { Tr::tr("Name:"), m_name, br, - Tr::tr("Executable"), m_executable - }.attachTo(this, WithoutMargins); + Tr::tr("Executable"), m_executable, + noMargin + }.attachTo(this); } void updateInterpreter(const Interpreter &interpreter) diff --git a/src/plugins/python/pythonwizardpage.cpp b/src/plugins/python/pythonwizardpage.cpp index 0f0d907f621..d132f3550c7 100644 --- a/src/plugins/python/pythonwizardpage.cpp +++ b/src/plugins/python/pythonwizardpage.cpp @@ -118,8 +118,9 @@ PythonWizardPage::PythonWizardPage(const QList> &pySide m_interpreter, br, m_createVenv, br, m_venvPath, br, - m_stateLabel, br - }.attachTo(this, WithoutMargins); + m_stateLabel, br, + noMargin + }.attachTo(this); } void PythonWizardPage::initializePage() diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index 1f7fca3b856..da5c6e70f6d 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -677,7 +677,8 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) QbsProjectManager::Tr::tr("Installation directory:"), installDirChooser, br, m_qbsStep->m_commandLine, br, - }.attachTo(this, Layouting::WithoutMargins); + noMargin, + }.attachTo(this); propertyEdit->setToolTip(QbsProjectManager::Tr::tr("Properties to pass to the project.")); defaultInstallDirCheckBox->setText(QbsProjectManager::Tr::tr("Use default location")); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 3990fb8f9a0..7271e1f6e2f 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -485,7 +485,8 @@ QWidget *QMakeStep::createConfigWidget() builder.addRow({m_userArgs}); builder.addRow({m_effectiveCall}); builder.addRow({abisLabel, abisListWidget}); - auto widget = builder.emerge(Layouting::WithoutMargins); + builder.addItem(Layouting::noMargin); + auto widget = builder.emerge(); qmakeBuildConfigChanged(); diff --git a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp index 4a9f26b7105..fc97aa53c82 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingspage.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingspage.cpp @@ -54,7 +54,8 @@ QmlJSCodeStylePreferencesWidget::QmlJSCodeStylePreferencesWidget( st, }, m_previewTextEdit, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, this, &QmlJSCodeStylePreferencesWidget::decorateEditor); diff --git a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp index a732ddc0324..34919f6144f 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp @@ -26,8 +26,9 @@ QmlJSCodeStyleSettingsWidget::QmlJSCodeStyleSettingsWidget(QWidget *parent) Form { Tr::tr("&Line length:"), m_lineLengthSpinBox, br, } - } - }.attachTo(this, WithoutMargins); + }, + noMargin + }.attachTo(this); connect(m_lineLengthSpinBox, &QSpinBox::valueChanged, this, &QmlJSCodeStyleSettingsWidget::slotSettingsChanged); diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 618f322a6a7..5f33e269860 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -268,8 +268,9 @@ QtOptionsPageWidget::QtOptionsPageWidget() Form { Tr::tr("Name:"), m_nameEdit, br, Tr::tr("qmake path:"), Row { m_qmakePath, m_editPathPushButton }, br, - Span(2, m_errorLabel) - }.attachTo(versionInfoWidget, WithoutMargins); + Span(2, m_errorLabel), + noMargin + }.attachTo(versionInfoWidget); // clang-format on m_formLayout = qobject_cast(versionInfoWidget->layout()); diff --git a/src/plugins/scxmleditor/common/colorpicker.cpp b/src/plugins/scxmleditor/common/colorpicker.cpp index 32c3f6d6c46..88f4d6d22a7 100644 --- a/src/plugins/scxmleditor/common/colorpicker.cpp +++ b/src/plugins/scxmleditor/common/colorpicker.cpp @@ -35,7 +35,7 @@ ColorPicker::ColorPicker(const QString &key, QWidget *parent) m_lastUsedColorContainer->setContentsMargins(0, 0, 0, 0); using namespace Layouting; - Grid colorGrid; + Grid colorGrid{noMargin}; for (int i = 0; i < colors.count(); ++i) { QWidget *button = createButton(colors[i]); colorGrid.addItem(button); @@ -46,7 +46,7 @@ ColorPicker::ColorPicker(const QString &key, QWidget *parent) QSizePolicy::MinimumExpanding, QSizePolicy::Preferred)); } - colorGrid.attachTo(basicColorContentFrame, WithoutMargins); + colorGrid.attachTo(basicColorContentFrame); Column { Tr::tr("Basic Colors"), basicColorContentFrame, diff --git a/src/plugins/scxmleditor/common/colorsettings.cpp b/src/plugins/scxmleditor/common/colorsettings.cpp index 22761b7f02b..1419b481bc5 100644 --- a/src/plugins/scxmleditor/common/colorsettings.cpp +++ b/src/plugins/scxmleditor/common/colorsettings.cpp @@ -44,7 +44,8 @@ ColorSettings::ColorSettings(QWidget *parent) removeTheme, }, m_colorThemeView, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); connect(m_comboColorThemes, &QComboBox::currentIndexChanged, this, &ColorSettings::selectTheme); diff --git a/src/plugins/scxmleditor/common/navigatorslider.cpp b/src/plugins/scxmleditor/common/navigatorslider.cpp index dd45a1c8af4..ab3738bc06e 100644 --- a/src/plugins/scxmleditor/common/navigatorslider.cpp +++ b/src/plugins/scxmleditor/common/navigatorslider.cpp @@ -36,7 +36,8 @@ NavigatorSlider::NavigatorSlider(QWidget *parent) m_slider, zoomIn, Space(20), - }.attachTo(this, WithoutMargins); + noMargin, + }.attachTo(this); connect(zoomOut, &QToolButton::clicked, this, &NavigatorSlider::zoomOut); connect(zoomIn, &QToolButton::clicked, this, &NavigatorSlider::zoomIn); diff --git a/src/plugins/scxmleditor/common/search.cpp b/src/plugins/scxmleditor/common/search.cpp index b7b56295fd5..f4d7e4bbc3f 100644 --- a/src/plugins/scxmleditor/common/search.cpp +++ b/src/plugins/scxmleditor/common/search.cpp @@ -50,7 +50,8 @@ Search::Search(QWidget *parent) spacing(0), m_searchEdit, m_searchView, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); connect(m_searchEdit, &Utils::FancyLineEdit::textChanged, this, &Search::setSearchText); connect(m_searchView, &TableView::pressed, this, &Search::rowActivated); diff --git a/src/plugins/scxmleditor/common/shapestoolbox.cpp b/src/plugins/scxmleditor/common/shapestoolbox.cpp index a0354d0bce4..82def88379a 100644 --- a/src/plugins/scxmleditor/common/shapestoolbox.cpp +++ b/src/plugins/scxmleditor/common/shapestoolbox.cpp @@ -33,7 +33,8 @@ ShapesToolbox::ShapesToolbox(QWidget *parent) Column { spacing(0), scrollArea, - }.attachTo(this, WithoutMargins); + noMargin, + }.attachTo(this); } void ShapesToolbox::setUIFactory(ScxmlEditor::PluginInterface::ScxmlUiFactory *factory) diff --git a/src/plugins/scxmleditor/common/stateview.cpp b/src/plugins/scxmleditor/common/stateview.cpp index e4c23046c7f..517f53bd3ec 100644 --- a/src/plugins/scxmleditor/common/stateview.cpp +++ b/src/plugins/scxmleditor/common/stateview.cpp @@ -35,13 +35,15 @@ StateView::StateView(StateItem *state, QWidget *parent) Row { PushButton{ text("Back"), onClicked([this] { closeView(); }, this) }, stateNameLabel, - }.attachTo(titleBar, WithoutMargins); + noMargin + }.attachTo(titleBar); Column { spacing(0), titleBar, - m_graphicsView - }.attachTo(this, WithoutMargins); + m_graphicsView, + noMargin, + }.attachTo(this); initScene(); } diff --git a/src/plugins/scxmleditor/common/statistics.cpp b/src/plugins/scxmleditor/common/statistics.cpp index ff1811eadd4..cff7d337c37 100644 --- a/src/plugins/scxmleditor/common/statistics.cpp +++ b/src/plugins/scxmleditor/common/statistics.cpp @@ -140,8 +140,9 @@ Statistics::Statistics(QWidget *parent) Tr::tr("File"), m_fileNameLabel, br, Tr::tr("Time"), m_timeLabel, br, Tr::tr("Max. levels"), m_levels, br, - Span(2, m_statisticsView), br - }.attachTo(this, WithoutMargins); + Span(2, m_statisticsView), br, + noMargin + }.attachTo(this); } void Statistics::setDocument(ScxmlDocument *doc) diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index 3f7255219f2..99796877a5a 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -207,8 +207,9 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) Row { Column { d->tabPreferencesWidget, d->groupBoxTyping, st }, - Column { d->groupBoxStorageSettings, d->groupBoxEncodings, d->groupBoxMouse, st } - }.attachTo(this, WithoutMargins); + Column { d->groupBoxStorageSettings, d->groupBoxEncodings, d->groupBoxMouse, st }, + noMargin, + }.attachTo(this); connect(d->cleanWhitespace, &QCheckBox::toggled, d->inEntireDocument, &QCheckBox::setEnabled); diff --git a/src/plugins/texteditor/codestyleeditor.cpp b/src/plugins/texteditor/codestyleeditor.cpp index ac75f1ad6d3..070a230e384 100644 --- a/src/plugins/texteditor/codestyleeditor.cpp +++ b/src/plugins/texteditor/codestyleeditor.cpp @@ -29,6 +29,7 @@ CodeStyleEditor::CodeStyleEditor(ICodeStylePreferencesFactory *factory, , m_codeStyle(codeStyle) { m_layout = new QVBoxLayout(this); + m_layout->setContentsMargins(0, 0, 0, 0); auto selector = new CodeStyleSelectorWidget(factory, project, this); selector->setCodeStyle(codeStyle); m_additionalGlobalSettingsWidget = factory->createAdditionalGlobalSettings(codeStyle, diff --git a/src/plugins/texteditor/codestyleselectorwidget.cpp b/src/plugins/texteditor/codestyleselectorwidget.cpp index e1090078da5..791f9e488af 100644 --- a/src/plugins/texteditor/codestyleselectorwidget.cpp +++ b/src/plugins/texteditor/codestyleselectorwidget.cpp @@ -59,8 +59,8 @@ CodeStyleSelectorWidget::CodeStyleSelectorWidget(ICodeStylePreferencesFactory *f m_exportButton, m_importButton }, - - }.attachTo(this, WithoutMargins); + noMargin, + }.attachTo(this); connect(m_delegateComboBox, &QComboBox::activated, this, &CodeStyleSelectorWidget::slotComboBoxActivated); diff --git a/src/plugins/texteditor/colorschemeedit.cpp b/src/plugins/texteditor/colorschemeedit.cpp index 96e7c3a2ad5..d6f93888ddc 100644 --- a/src/plugins/texteditor/colorschemeedit.cpp +++ b/src/plugins/texteditor/colorschemeedit.cpp @@ -208,7 +208,8 @@ ColorSchemeEdit::ColorSchemeEdit(QWidget *parent) : m_itemList, m_builtinSchemeLabel, m_fontProperties, - }.attachTo(this, WithoutMargins); + noMargin + }.attachTo(this); Grid { m_foregroundLabel, m_foregroundToolButton, m_eraseForegroundToolButton, br, diff --git a/src/plugins/vcsbase/submiteditorwidget.cpp b/src/plugins/vcsbase/submiteditorwidget.cpp index eaac1d61d2d..376c7feceae 100644 --- a/src/plugins/vcsbase/submiteditorwidget.cpp +++ b/src/plugins/vcsbase/submiteditorwidget.cpp @@ -208,8 +208,9 @@ SubmitEditorWidget::SubmitEditorWidget() : using namespace Layouting; Column { - scrollArea - }.attachTo(this, WithoutMargins); + scrollArea, + noMargin + }.attachTo(this); connect(d->description, &QWidget::customContextMenuRequested, this, &SubmitEditorWidget::editorCustomContextMenuRequested); diff --git a/tests/manual/tasktree/taskwidget.cpp b/tests/manual/tasktree/taskwidget.cpp index e2770d916e3..0f721641813 100644 --- a/tests/manual/tasktree/taskwidget.cpp +++ b/tests/manual/tasktree/taskwidget.cpp @@ -91,8 +91,9 @@ TaskWidget::TaskWidget() m_infoLabel, m_spinBox, m_checkBox, - st - }.attachTo(this, WithoutMargins); + st, + noMargin, + }.attachTo(this); } void TaskWidget::setBusyTime(int seconds) @@ -145,9 +146,10 @@ GroupWidget::GroupWidget() m_executeCombo, new QLabel("Workflow:"), m_workflowCombo, - st + st, + noMargin } - }.attachTo(this, WithoutMargins); + }.attachTo(this); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); } From 99f767956417ed7dc91a5295a2af8326376d3b5e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 2 May 2023 17:20:57 +0200 Subject: [PATCH 0799/1447] Layouting: Make aspects operate on parent items, not LayoutBuilder LayoutBuilder is meant to be an implementation detail nowadays. Change-Id: I777ab934d3d405873e819eeddd27428d8c652f9a Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 82 +++++++++---------- src/libs/utils/aspects.h | 29 +++---- src/libs/utils/layoutbuilder.cpp | 69 +++++++++------- src/libs/utils/layoutbuilder.h | 28 +------ .../cmakebuildconfiguration.cpp | 18 ++-- .../cmakekitinformation.cpp | 14 ++-- src/plugins/debugger/debuggeractions.h | 2 +- .../debugger/debuggerkitinformation.cpp | 6 +- .../debuggersourcepathmappingwidget.cpp | 4 +- .../incredibuild/commandbuilderaspect.cpp | 8 +- .../incredibuild/commandbuilderaspect.h | 2 +- src/plugins/ios/iosrunconfiguration.cpp | 4 +- src/plugins/ios/iosrunconfiguration.h | 2 +- src/plugins/mcusupport/mcukitinformation.cpp | 2 +- .../mesonprojectmanager/toolkitaspectwidget.h | 6 +- src/plugins/projectexplorer/buildaspects.cpp | 6 +- src/plugins/projectexplorer/buildaspects.h | 2 +- .../projectexplorer/buildconfiguration.cpp | 4 +- .../buildpropertiessettings.cpp | 6 +- .../projectexplorer/kitinformation.cpp | 12 +-- src/plugins/projectexplorer/kitmanager.cpp | 8 +- src/plugins/projectexplorer/kitmanager.h | 2 +- .../kitmanagerconfigwidget.cpp | 16 ++-- .../projectexplorer/kitmanagerconfigwidget.h | 2 +- .../miniprojecttargetselector.cpp | 2 +- .../projectexplorer/runconfiguration.cpp | 4 +- .../runconfigurationaspects.cpp | 12 +-- .../projectexplorer/runconfigurationaspects.h | 10 +-- .../qbsprojectmanager/qbsbuildstep.cpp | 6 +- .../qbsprojectmanager/qbskitinformation.cpp | 6 +- .../qmakekitinformation.cpp | 4 +- .../qmlprojectmanager/qmlmainfileaspect.cpp | 4 +- .../qmlprojectmanager/qmlmainfileaspect.h | 2 +- src/plugins/qtsupport/qtbuildaspects.cpp | 12 +-- src/plugins/qtsupport/qtbuildaspects.h | 4 +- src/plugins/qtsupport/qtkitinformation.cpp | 6 +- src/plugins/valgrind/valgrindsettings.cpp | 6 +- src/plugins/valgrind/valgrindsettings.h | 2 +- .../webassemblyrunconfigurationaspects.cpp | 4 +- .../webassemblyrunconfigurationaspects.h | 2 +- 40 files changed, 204 insertions(+), 216 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index fd953d24934..94aee75214c 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -210,15 +210,15 @@ void BaseAspect::setupLabel() registerSubWidget(d->m_label); } -void BaseAspect::addLabeledItem(Layouting::LayoutBuilder &builder, QWidget *widget) +void BaseAspect::addLabeledItem(LayoutItem &parent, QWidget *widget) { setupLabel(); if (QLabel *l = label()) { l->setBuddy(widget); - builder.addItem(l); - builder.addItem(Span(std::max(d->m_spanX - 1, 1), LayoutItem(widget))); + parent.addItem(l); + parent.addItem(Span(std::max(d->m_spanX - 1, 1), LayoutItem(widget))); } else { - builder.addItem(LayoutItem(widget)); + parent.addItem(LayoutItem(widget)); } } @@ -419,24 +419,18 @@ QAction *BaseAspect::action() Adds the visual representation of this aspect to a layout using a layout builder. */ -void BaseAspect::addToLayout(LayoutBuilder &) +void BaseAspect::addToLayout(LayoutItem &) { } void createItem(Layouting::LayoutItem *item, const BaseAspect &aspect) { - item->onAdd = [&aspect](LayoutBuilder &builder) { - const_cast(aspect).addToLayout(builder); - builder.addItem(br); - }; + const_cast(aspect).addToLayout(*item); } void createItem(Layouting::LayoutItem *item, const BaseAspect *aspect) { - item->onAdd = [aspect](LayoutBuilder &builder) { - const_cast(aspect)->addToLayout(builder); - builder.addItem(br); - }; + const_cast(aspect)->addToLayout(*item); } @@ -1067,11 +1061,11 @@ void StringAspect::setUncheckedSemantics(StringAspect::UncheckedSemantics semant d->m_uncheckedSemantics = semantics; } -void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) +void StringAspect::addToLayout(LayoutItem &parent) { if (d->m_checker && d->m_checkBoxPlacement == CheckBoxPlacement::Top) { - d->m_checker->addToLayout(builder); - builder.addItem(br); + d->m_checker->addToLayout(parent); + parent.addItem(br); } const auto useMacroExpander = [this](QWidget *w) { @@ -1103,7 +1097,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) if (d->m_pathChooserDisplay->lineEdit()->placeholderText().isEmpty()) d->m_pathChooserDisplay->lineEdit()->setPlaceholderText(d->m_placeHolderText); d->updateWidgetFromCheckStatus(this, d->m_pathChooserDisplay.data()); - addLabeledItem(builder, d->m_pathChooserDisplay); + addLabeledItem(parent, d->m_pathChooserDisplay); useMacroExpander(d->m_pathChooserDisplay->lineEdit()); if (isAutoApply()) { if (d->m_autoApplyOnEditingFinished) { @@ -1134,7 +1128,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) d->m_lineEditDisplay->setTextKeepingActiveCursor(displayedString); d->m_lineEditDisplay->setReadOnly(isReadOnly()); d->updateWidgetFromCheckStatus(this, d->m_lineEditDisplay.data()); - addLabeledItem(builder, d->m_lineEditDisplay); + addLabeledItem(parent, d->m_lineEditDisplay); useMacroExpander(d->m_lineEditDisplay); if (isAutoApply()) { if (d->m_autoApplyOnEditingFinished) { @@ -1164,7 +1158,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) connect(d->m_lineEditDisplay, &QLineEdit::textChanged, this, [this, resetButton] { resetButton->setEnabled(d->m_lineEditDisplay->text() != defaultValue()); }); - builder.addItem(resetButton); + parent.addItem(resetButton); } break; case TextEditDisplay: @@ -1176,7 +1170,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) d->m_textEditDisplay->setText(displayedString); d->m_textEditDisplay->setReadOnly(isReadOnly()); d->updateWidgetFromCheckStatus(this, d->m_textEditDisplay.data()); - addLabeledItem(builder, d->m_textEditDisplay); + addLabeledItem(parent, d->m_textEditDisplay); useMacroExpander(d->m_textEditDisplay); if (isAutoApply()) { connect(d->m_textEditDisplay, &QTextEdit::textChanged, this, [this] { @@ -1190,14 +1184,14 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) d->m_labelDisplay->setTextInteractionFlags(Qt::TextSelectableByMouse); d->m_labelDisplay->setText(displayedString); d->m_labelDisplay->setToolTip(d->m_showToolTipOnLabel ? displayedString : toolTip()); - addLabeledItem(builder, d->m_labelDisplay); + addLabeledItem(parent, d->m_labelDisplay); break; } validateInput(); if (d->m_checker && d->m_checkBoxPlacement == CheckBoxPlacement::Right) - d->m_checker->addToLayout(builder); + d->m_checker->addToLayout(parent); } QVariant StringAspect::volatileValue() const @@ -1327,11 +1321,11 @@ ColorAspect::ColorAspect(const QString &settingsKey) ColorAspect::~ColorAspect() = default; -void ColorAspect::addToLayout(Layouting::LayoutBuilder &builder) +void ColorAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_CHECK(!d->m_colorButton); d->m_colorButton = createSubWidget(); - builder.addItem(d->m_colorButton.data()); + parent.addItem(d->m_colorButton.data()); d->m_colorButton->setColor(value()); if (isAutoApply()) { connect(d->m_colorButton.data(), @@ -1401,24 +1395,24 @@ BoolAspect::~BoolAspect() = default; /*! \reimp */ -void BoolAspect::addToLayout(Layouting::LayoutBuilder &builder) +void BoolAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_CHECK(!d->m_checkBox); d->m_checkBox = createSubWidget(); switch (d->m_labelPlacement) { case LabelPlacement::AtCheckBoxWithoutDummyLabel: d->m_checkBox->setText(labelText()); - builder.addItem(d->m_checkBox.data()); + parent.addItem(d->m_checkBox.data()); break; case LabelPlacement::AtCheckBox: { d->m_checkBox->setText(labelText()); - if (builder.isForm()) - builder.addItem(createSubWidget()); - builder.addItem(d->m_checkBox.data()); +// if (parent.isForm()) FIXME + parent.addItem(createSubWidget()); + parent.addItem(d->m_checkBox.data()); break; } case LabelPlacement::InExtraLabel: - addLabeledItem(builder, d->m_checkBox); + addLabeledItem(parent, d->m_checkBox); break; } d->m_checkBox->setChecked(value()); @@ -1557,7 +1551,7 @@ SelectionAspect::~SelectionAspect() = default; /*! \reimp */ -void SelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) +void SelectionAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_CHECK(d->m_buttonGroup == nullptr); QTC_CHECK(!d->m_comboBox); @@ -1573,8 +1567,8 @@ void SelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) button->setChecked(i == value()); button->setEnabled(option.enabled); button->setToolTip(option.tooltip); - builder.addItem(Layouting::empty); - builder.addItem(button); + parent.addItem(Layouting::empty); + parent.addItem(button); d->m_buttons.append(button); d->m_buttonGroup->addButton(button, i); if (isAutoApply()) { @@ -1596,7 +1590,7 @@ void SelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) connect(d->m_comboBox.data(), &QComboBox::currentIndexChanged, this, &SelectionAspect::volatileValueChanged); d->m_comboBox->setCurrentIndex(value()); - addLabeledItem(builder, d->m_comboBox); + addLabeledItem(parent, d->m_comboBox); break; } } @@ -1762,7 +1756,7 @@ MultiSelectionAspect::~MultiSelectionAspect() = default; /*! \reimp */ -void MultiSelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) +void MultiSelectionAspect::addToLayout(LayoutItem &builder) { QTC_CHECK(d->m_listView == nullptr); if (d->m_allValues.isEmpty()) @@ -1871,7 +1865,7 @@ IntegerAspect::~IntegerAspect() = default; /*! \reimp */ -void IntegerAspect::addToLayout(Layouting::LayoutBuilder &builder) +void IntegerAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_CHECK(!d->m_spinBox); d->m_spinBox = createSubWidget(); @@ -1884,7 +1878,7 @@ void IntegerAspect::addToLayout(Layouting::LayoutBuilder &builder) d->m_spinBox->setRange(int(d->m_minimumValue.value() / d->m_displayScaleFactor), int(d->m_maximumValue.value() / d->m_displayScaleFactor)); d->m_spinBox->setValue(int(value() / d->m_displayScaleFactor)); // Must happen after setRange() - addLabeledItem(builder, d->m_spinBox); + addLabeledItem(parent, d->m_spinBox); if (isAutoApply()) { connect(d->m_spinBox.data(), &QSpinBox::valueChanged, @@ -2005,7 +1999,7 @@ DoubleAspect::~DoubleAspect() = default; /*! \reimp */ -void DoubleAspect::addToLayout(Layouting::LayoutBuilder &builder) +void DoubleAspect::addToLayout(LayoutItem &builder) { QTC_CHECK(!d->m_spinBox); d->m_spinBox = createSubWidget(); @@ -2159,9 +2153,9 @@ StringListAspect::~StringListAspect() = default; /*! \reimp */ -void StringListAspect::addToLayout(Layouting::LayoutBuilder &builder) +void StringListAspect::addToLayout(LayoutItem &parent) { - Q_UNUSED(builder) + Q_UNUSED(parent) // TODO - when needed. } @@ -2229,9 +2223,9 @@ IntegersAspect::~IntegersAspect() = default; /*! \reimp */ -void IntegersAspect::addToLayout(Layouting::LayoutBuilder &builder) +void IntegersAspect::addToLayout(Layouting::LayoutItem &parent) { - Q_UNUSED(builder) + Q_UNUSED(parent) // TODO - when needed. } @@ -2292,7 +2286,7 @@ TextDisplay::~TextDisplay() = default; /*! \reimp */ -void TextDisplay::addToLayout(Layouting::LayoutBuilder &builder) +void TextDisplay::addToLayout(LayoutItem &parent) { if (!d->m_label) { d->m_label = createSubWidget(d->m_message, d->m_type); @@ -2304,7 +2298,7 @@ void TextDisplay::addToLayout(Layouting::LayoutBuilder &builder) if (!isVisible()) d->m_label->setVisible(false); } - builder.addItem(d->m_label.data()); + parent.addItem(d->m_label.data()); } /*! diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 3eae9ffaea1..8b75bf911db 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -18,10 +18,7 @@ class QAction; class QSettings; QT_END_NAMESPACE -namespace Layouting { -class LayoutItem; -class LayoutBuilder; -} +namespace Layouting { class LayoutItem; } namespace Utils { @@ -100,7 +97,7 @@ public: virtual void toMap(QVariantMap &map) const; virtual void toActiveMap(QVariantMap &map) const { toMap(map); } - virtual void addToLayout(Layouting::LayoutBuilder &builder); + virtual void addToLayout(Layouting::LayoutItem &parent); virtual QVariant volatileValue() const; virtual void setVolatileValue(const QVariant &val); @@ -171,7 +168,7 @@ signals: protected: QLabel *label() const; void setupLabel(); - void addLabeledItem(Layouting::LayoutBuilder &builder, QWidget *widget); + void addLabeledItem(Layouting::LayoutItem &parent, QWidget *widget); void setDataCreatorHelper(const DataCreator &creator) const; void setDataClonerHelper(const DataCloner &cloner) const; @@ -223,7 +220,7 @@ public: bool value; }; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; std::function groupChecker(); QAction *action() override; @@ -263,7 +260,7 @@ public: QColor value; }; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QColor value() const; void setValue(const QColor &val); @@ -283,7 +280,7 @@ public: SelectionAspect(); ~SelectionAspect() override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; void finish() override; @@ -337,7 +334,7 @@ public: MultiSelectionAspect(); ~MultiSelectionAspect() override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; enum class DisplayStyle { ListView }; void setDisplayStyle(DisplayStyle style); @@ -366,7 +363,7 @@ public: FilePath filePath; }; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; @@ -444,7 +441,7 @@ public: IntegerAspect(); ~IntegerAspect() override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; @@ -481,7 +478,7 @@ public: DoubleAspect(); ~DoubleAspect() override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; @@ -549,7 +546,7 @@ public: StringListAspect(); ~StringListAspect() override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QStringList value() const; void setValue(const QStringList &val); @@ -571,7 +568,7 @@ public: IntegersAspect(); ~IntegersAspect() override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; void emitChangedValue() override; QList value() const; @@ -593,7 +590,7 @@ public: InfoLabel::InfoType type = InfoLabel::None); ~TextDisplay() override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; void setIconType(InfoLabel::InfoType t); void setText(const QString &message); diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 48a75fc1623..3324e9c4f6f 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -74,7 +74,7 @@ struct ResultItem int span = 1; }; -struct LayoutBuilder::Slice +struct Slice { Slice() = default; Slice(QLayout *l) : layout(l) {} @@ -135,7 +135,7 @@ static void addItemToBoxLayout(QBoxLayout *layout, const ResultItem &item) } } -void LayoutBuilder::Slice::flush() +void Slice::flush() { if (pendingItems.empty()) return; @@ -194,13 +194,14 @@ void LayoutBuilder::Slice::flush() } else if (auto gridLayout = qobject_cast(layout)) { for (const ResultItem &item : std::as_const(pendingItems)) { - if (item.widget) - gridLayout->addWidget(item.widget, currentGridRow, currentGridColumn, 1, item.span, align); - else if (item.layout) - gridLayout->addLayout(item.layout, currentGridRow, currentGridColumn, 1, item.span, align); - else if (!item.text.isEmpty()) - gridLayout->addWidget(createLabel(item.text), currentGridRow, currentGridColumn, 1, 1, align); - currentGridColumn += item.span; + Qt::Alignment a = currentGridColumn == 0 ? align : Qt::Alignment(); + if (item.widget) + gridLayout->addWidget(item.widget, currentGridRow, currentGridColumn, 1, item.span, a); + else if (item.layout) + gridLayout->addLayout(item.layout, currentGridRow, currentGridColumn, 1, item.span, a); + else if (!item.text.isEmpty()) + gridLayout->addWidget(createLabel(item.text), currentGridRow, currentGridColumn, 1, 1, a); + currentGridColumn += item.span; } ++currentGridRow; currentGridColumn = 0; @@ -225,6 +226,25 @@ void LayoutBuilder::Slice::flush() pendingItems.clear(); } +// LayoutBuilder + +class LayoutBuilder +{ + Q_DISABLE_COPY_MOVE(LayoutBuilder) + +public: + LayoutBuilder(); + ~LayoutBuilder(); + + void addItem(const LayoutItem &item); + void addItems(const LayoutItems &items); + void addRow(const LayoutItems &items); + + bool isForm() const; + + QList stack; +}; + static void addItemHelper(LayoutBuilder &builder, const LayoutItem &item) { if (item.onAdd) @@ -306,6 +326,7 @@ void doAddWidget(LayoutBuilder &builder, QWidget *widget) \sa addItem(), addItems(), addRow(), finishRow() */ + LayoutBuilder::LayoutBuilder() = default; /*! @@ -520,25 +541,6 @@ LayoutItem withFormAlignment() return item; } -/*! - Constructs a layout extender to extend an existing \a layout. - - This constructor can be used to continue the work of previous layout building. - The type of the underlying layout and previous contents will be retained, - new items will be added below existing ones. - */ - -LayoutExtender::LayoutExtender(QLayout *layout) -{ - Slice slice; - slice.layout = layout; - if (auto gridLayout = qobject_cast(layout)) - slice.currentGridRow = gridLayout->rowCount(); - stack.append(slice); -} - -LayoutExtender::~LayoutExtender() = default; - // "Widgets" template @@ -688,6 +690,17 @@ LayoutItem resize(int w, int h) }; } +LayoutItem columnStretch(int column, int stretch) +{ + return [column, stretch](QObject *target) { + if (auto grid = qobject_cast(target)) { + grid->setColumnStretch(column, stretch); + } else { + QTC_CHECK(false); + } + }; +} + QWidget *createHr(QWidget *parent) { auto frame = new QFrame(parent); diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index e63c359e7ed..1a9c3439bcc 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -197,6 +197,7 @@ QTCREATOR_UTILS_EXPORT LayoutItem title(const QString &title); QTCREATOR_UTILS_EXPORT LayoutItem text(const QString &text); QTCREATOR_UTILS_EXPORT LayoutItem tooltip(const QString &toolTip); QTCREATOR_UTILS_EXPORT LayoutItem resize(int, int); +QTCREATOR_UTILS_EXPORT LayoutItem columnStretch(int column, int stretch); QTCREATOR_UTILS_EXPORT LayoutItem spacing(int); QTCREATOR_UTILS_EXPORT LayoutItem windowTitle(const QString &windowTitle); QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &, @@ -212,31 +213,4 @@ LayoutItem bindTo(T **out) return [out](QObject *target) { *out = qobject_cast(target); }; } -// LayoutBuilder - -class QTCREATOR_UTILS_EXPORT LayoutBuilder -{ - Q_DISABLE_COPY_MOVE(LayoutBuilder) - -public: - LayoutBuilder(); - ~LayoutBuilder(); - - void addItem(const LayoutItem &item); - void addItems(const LayoutItems &items); - void addRow(const LayoutItems &items); - - bool isForm() const; - - struct Slice; - QList stack; -}; - -class QTCREATOR_UTILS_EXPORT LayoutExtender : public LayoutBuilder -{ -public: - explicit LayoutExtender(QLayout *layout); - ~LayoutExtender(); -}; - } // Layouting diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index fb15eefdc08..d299b3eb77a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -335,8 +335,8 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildSystem *bs) : Column { Form { - buildDirAspect, - bc->aspect(), + buildDirAspect, br, + bc->aspect(), br, qmlDebugAspect }, m_warningMessageLabel, @@ -347,7 +347,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildSystem *bs) : Column { cmakeConfiguration, Row { - bc->aspect(), + bc->aspect(), br, bc->aspect() }, m_reconfigureButton, @@ -665,17 +665,19 @@ void CMakeBuildSettingsWidget::kitCMakeConfiguration() CMakeGeneratorKitAspect generatorAspect; CMakeConfigurationKitAspect configurationKitAspect; - auto layout = new QGridLayout(dialog); - + Layouting::Grid grid; KitAspectWidget *widget = kitAspect.createConfigWidget(m_buildSystem->kit()); widget->setParent(dialog); - widget->addToLayoutWithLabel(layout->parentWidget()); + widget->addToLayoutWithLabel(grid, dialog); widget = generatorAspect.createConfigWidget(m_buildSystem->kit()); widget->setParent(dialog); - widget->addToLayoutWithLabel(layout->parentWidget()); + widget->addToLayoutWithLabel(grid, dialog); widget = configurationKitAspect.createConfigWidget(m_buildSystem->kit()); widget->setParent(dialog); - widget->addToLayoutWithLabel(layout->parentWidget()); + widget->addToLayoutWithLabel(grid, dialog); + grid.attachTo(dialog); + + auto layout = qobject_cast(dialog->layout()); layout->setColumnStretch(1, 1); diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 46222ed76ae..064ed0d59ba 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -105,7 +105,7 @@ private: // KitAspectWidget interface void makeReadOnly() override { m_comboBox->setEnabled(false); } - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -350,11 +350,11 @@ private: // KitAspectWidget interface void makeReadOnly() override { m_changeButton->setEnabled(false); } - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &parent) override { addMutableAction(m_label); - builder.addItem(m_label); - builder.addItem(m_changeButton); + parent.addItem(m_label); + parent.addItem(m_changeButton); } void refresh() override @@ -892,11 +892,11 @@ public: private: // KitAspectWidget interface - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &parent) override { addMutableAction(m_summaryLabel); - builder.addItem(m_summaryLabel); - builder.addItem(m_manageButton); + parent.addItem(m_summaryLabel); + parent.addItem(m_manageButton); } void makeReadOnly() override diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index be11fd2be4a..40fabfef1eb 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -30,7 +30,7 @@ public: void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index 7002437fb2f..b1ba6bf1d59 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -60,11 +60,11 @@ public: } private: - void addToLayout(Layouting::LayoutBuilder &builder) override + void addToLayout(Layouting::LayoutItem &parent) override { addMutableAction(m_comboBox); - builder.addItem(m_comboBox); - builder.addItem(m_manageButton); + parent.addItem(m_comboBox); + parent.addItem(m_manageButton); } void makeReadOnly() override diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index d7abf7b12b5..276d0c685f1 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -491,12 +491,12 @@ void SourcePathMapAspect::toMap(QVariantMap &) const QTC_CHECK(false); } -void SourcePathMapAspect::addToLayout(Layouting::LayoutBuilder &builder) +void SourcePathMapAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_CHECK(!d->m_widget); d->m_widget = createSubWidget(); d->m_widget->setSourcePathMap(value()); - builder.addItem(d->m_widget.data()); + parent.addItem(d->m_widget.data()); } QVariant SourcePathMapAspect::volatileValue() const diff --git a/src/plugins/incredibuild/commandbuilderaspect.cpp b/src/plugins/incredibuild/commandbuilderaspect.cpp index 6a16cabc6d7..5cfbac953b1 100644 --- a/src/plugins/incredibuild/commandbuilderaspect.cpp +++ b/src/plugins/incredibuild/commandbuilderaspect.cpp @@ -110,7 +110,7 @@ void CommandBuilderAspectPrivate::tryToMigrate() } } -void CommandBuilderAspect::addToLayout(Layouting::LayoutBuilder &builder) +void CommandBuilderAspect::addToLayout(Layouting::LayoutItem &parent) { if (!d->commandBuilder) { d->commandBuilder = new QComboBox; @@ -151,9 +151,9 @@ void CommandBuilderAspect::addToLayout(Layouting::LayoutBuilder &builder) if (!d->m_loadedFromMap) d->tryToMigrate(); - builder.addRow({d->label.data(), d->commandBuilder.data()}); - builder.addRow({Tr::tr("Make command:"), d->makePathChooser.data()}); - builder.addRow({Tr::tr("Make arguments:"), d->makeArgumentsLineEdit.data()}); + parent.addRow({d->label.data(), d->commandBuilder.data()}); + parent.addRow({Tr::tr("Make command:"), d->makePathChooser.data()}); + parent.addRow({Tr::tr("Make arguments:"), d->makeArgumentsLineEdit.data()}); updateGui(); } diff --git a/src/plugins/incredibuild/commandbuilderaspect.h b/src/plugins/incredibuild/commandbuilderaspect.h index c880fa7d529..6033e9036e5 100644 --- a/src/plugins/incredibuild/commandbuilderaspect.h +++ b/src/plugins/incredibuild/commandbuilderaspect.h @@ -23,7 +23,7 @@ public: QString fullCommandFlag(bool keepJobNum) const; private: - void addToLayout(Layouting::LayoutBuilder &builder) final; + void addToLayout(Layouting::LayoutItem &parent) final; void fromMap(const QVariantMap &map) final; void toMap(QVariantMap &map) const final; diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index 9a9acedb29e..5c9170f2bae 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -324,14 +324,14 @@ IosDeviceTypeAspect::IosDeviceTypeAspect(IosRunConfiguration *runConfiguration) this, &IosDeviceTypeAspect::deviceChanges); } -void IosDeviceTypeAspect::addToLayout(Layouting::LayoutBuilder &builder) +void IosDeviceTypeAspect::addToLayout(Layouting::LayoutItem &parent) { m_deviceTypeComboBox = new QComboBox; m_deviceTypeComboBox->setModel(&m_deviceTypeModel); m_deviceTypeLabel = new QLabel(Tr::tr("Device type:")); - builder.addItems({m_deviceTypeLabel, m_deviceTypeComboBox}); + parent.addItems({m_deviceTypeLabel, m_deviceTypeComboBox}); updateValues(); diff --git a/src/plugins/ios/iosrunconfiguration.h b/src/plugins/ios/iosrunconfiguration.h index d348dd61cab..1ebe79efa56 100644 --- a/src/plugins/ios/iosrunconfiguration.h +++ b/src/plugins/ios/iosrunconfiguration.h @@ -27,7 +27,7 @@ public: void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; IosDeviceType deviceType() const; void setDeviceType(const IosDeviceType &deviceType); diff --git a/src/plugins/mcusupport/mcukitinformation.cpp b/src/plugins/mcusupport/mcukitinformation.cpp index 0b156e1ab47..2fd6f846e1e 100644 --- a/src/plugins/mcusupport/mcukitinformation.cpp +++ b/src/plugins/mcusupport/mcukitinformation.cpp @@ -22,7 +22,7 @@ public: void makeReadOnly() override {} void refresh() override {} - void addToLayout(Layouting::LayoutBuilder &) override {} + void addToLayout(Layouting::LayoutItem &) override {} }; } // anonymous namespace diff --git a/src/plugins/mesonprojectmanager/toolkitaspectwidget.h b/src/plugins/mesonprojectmanager/toolkitaspectwidget.h index beb9440add0..c327fb4e2b1 100644 --- a/src/plugins/mesonprojectmanager/toolkitaspectwidget.h +++ b/src/plugins/mesonprojectmanager/toolkitaspectwidget.h @@ -36,11 +36,11 @@ private: void makeReadOnly() override { m_toolsComboBox->setEnabled(false); } - void addToLayout(Layouting::LayoutBuilder &builder) override + void addToLayout(Layouting::LayoutItem &parent) override { addMutableAction(m_toolsComboBox); - builder.addItem(m_toolsComboBox); - builder.addItem(m_manageButton); + parent.addItem(m_toolsComboBox); + parent.addItem(m_manageButton); } void refresh() override diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index 133cfb15b38..e4cbf6903b7 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -107,12 +107,12 @@ void BuildDirectoryAspect::fromMap(const QVariantMap &map) } } -void BuildDirectoryAspect::addToLayout(Layouting::LayoutBuilder &builder) +void BuildDirectoryAspect::addToLayout(Layouting::LayoutItem &parent) { - StringAspect::addToLayout(builder); + StringAspect::addToLayout(parent); d->problemLabel = new InfoLabel({}, InfoLabel::Warning); d->problemLabel->setElideMode(Qt::ElideNone); - builder.addItems({{}, d->problemLabel.data()}); + parent.addItems({{}, d->problemLabel.data()}); updateProblemLabel(); if (!d->sourceDir.isEmpty()) { connect(this, &StringAspect::checkedChanged, this, [this] { diff --git a/src/plugins/projectexplorer/buildaspects.h b/src/plugins/projectexplorer/buildaspects.h index 968642f11f8..96c6db90716 100644 --- a/src/plugins/projectexplorer/buildaspects.h +++ b/src/plugins/projectexplorer/buildaspects.h @@ -23,7 +23,7 @@ public: bool isShadowBuild() const; void setProblem(const QString &description); - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; static Utils::FilePath fixupDir(const Utils::FilePath &dir); diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 772bd64610e..70d5a348c1c 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -324,8 +324,10 @@ NamedWidget *BuildConfiguration::createConfigWidget() Layouting::Form form; for (BaseAspect *aspect : aspects()) { - if (aspect->isVisible()) + if (aspect->isVisible()) { form.addItem(aspect); + form.addItem(Layouting::br); + } } form.addItem(Layouting::noMargin); form.attachTo(widget); diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp index a9126551e3e..36030fe60e9 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.cpp +++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp @@ -90,9 +90,9 @@ BuildPropertiesSettingsPage::BuildPropertiesSettingsPage(BuildPropertiesSettings Column { Form { - s.buildDirectoryTemplate, - s.separateDebugInfo, - s.qmlDebugging, + s.buildDirectoryTemplate, br, + s.separateDebugInfo, br, + s.qmlDebugging, br, s.qtQuickCompiler }, st diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index 52eae5f9b86..41cadfea1c4 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -65,7 +65,7 @@ public: private: void makeReadOnly() override { m_chooser->setReadOnly(true); } - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &builder) override { addMutableAction(m_chooser); builder.addItem(Layouting::Span(2, m_chooser)); @@ -231,7 +231,7 @@ public: } private: - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &builder) override { addMutableAction(m_mainWidget); builder.addItem(m_mainWidget); @@ -760,7 +760,7 @@ public: ~DeviceTypeKitAspectWidget() override { delete m_comboBox; } private: - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -896,7 +896,7 @@ public: } private: - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -1156,7 +1156,7 @@ public: } private: - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -1387,7 +1387,7 @@ public: } private: - void addToLayout(LayoutBuilder &builder) override + void addToLayout(LayoutItem &builder) override { addMutableAction(m_mainWidget); builder.addItem(m_mainWidget); diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index b2c773b55c3..86a3b533c15 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -747,7 +747,7 @@ KitAspectWidget::~KitAspectWidget() delete m_mutableAction; } -void KitAspectWidget::addToLayoutWithLabel(QWidget *parent) +void KitAspectWidget::addToLayoutWithLabel(Layouting::LayoutItem &parentItem, QWidget *parent) { QTC_ASSERT(parent, return); auto label = createSubWidget(m_kitInformation->displayName() + ':'); @@ -756,9 +756,9 @@ void KitAspectWidget::addToLayoutWithLabel(QWidget *parent) emit labelLinkActivated(link); }); - Layouting::LayoutExtender builder(parent->layout()); - builder.addItems({label, Layouting::br}); - addToLayout(builder); + parentItem.addItem(label); + addToLayout(parentItem); + parentItem.addItem(Layouting::br); } void KitAspectWidget::addMutableAction(QWidget *child) diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h index a494fde3237..f25f83ca7f4 100644 --- a/src/plugins/projectexplorer/kitmanager.h +++ b/src/plugins/projectexplorer/kitmanager.h @@ -117,7 +117,7 @@ public: virtual void makeReadOnly() = 0; virtual void refresh() = 0; - void addToLayoutWithLabel(QWidget *parent); + void addToLayoutWithLabel(Layouting::LayoutItem &parentItem, QWidget *parent); static QString msgManage(); diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp index c1f8a3ed79a..822844f57d0 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -66,12 +67,13 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k, bool &isDefaultKit, bool this, &KitManagerConfigWidget::setFileSystemFriendlyName); using namespace Layouting; - Grid { + Grid page { withFormAlignment, + columnStretch(1, 2), label, m_nameEdit, m_iconButton, br, - fsLabel, m_fileSystemFriendlyNameLineEdit, + fsLabel, m_fileSystemFriendlyNameLineEdit, br, noMargin - }.attachTo(this); + }; m_iconButton->setToolTip(Tr::tr("Kit icon.")); auto setIconAction = new QAction(Tr::tr("Select Icon..."), this); @@ -101,7 +103,9 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k, bool &isDefaultKit, bool chooser->addMacroExpanderProvider([this] { return m_modifiedKit->macroExpander(); }); for (KitAspect *aspect : KitManager::kitAspects()) - addAspectToWorkingCopy(aspect); + addAspectToWorkingCopy(page, aspect); + + page.attachTo(this); updateVisibility(); @@ -191,14 +195,14 @@ QString KitManagerConfigWidget::validityMessage() const return m_modifiedKit->toHtml(tmp); } -void KitManagerConfigWidget::addAspectToWorkingCopy(KitAspect *aspect) +void KitManagerConfigWidget::addAspectToWorkingCopy(Layouting::LayoutItem &parent, KitAspect *aspect) { QTC_ASSERT(aspect, return); KitAspectWidget *widget = aspect->createConfigWidget(workingCopy()); QTC_ASSERT(widget, return); QTC_ASSERT(!m_widgets.contains(widget), return); - widget->addToLayoutWithLabel(this); + widget->addToLayoutWithLabel(parent, this); m_widgets.append(widget); connect(widget->mutableAction(), &QAction::toggled, diff --git a/src/plugins/projectexplorer/kitmanagerconfigwidget.h b/src/plugins/projectexplorer/kitmanagerconfigwidget.h index bd4415ed480..94218c5de8a 100644 --- a/src/plugins/projectexplorer/kitmanagerconfigwidget.h +++ b/src/plugins/projectexplorer/kitmanagerconfigwidget.h @@ -35,7 +35,7 @@ public: void discard(); bool isDirty() const; QString validityMessage() const; - void addAspectToWorkingCopy(KitAspect *aspect); + void addAspectToWorkingCopy(Layouting::LayoutItem &parent, KitAspect *aspect); void makeStickySubWidgetsReadOnly(); Kit *workingCopy() const; diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 5ab5f109ff2..3da81e61542 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -551,7 +551,7 @@ int SelectorView::padding() ///////// // KitAreaWidget ///////// -void doLayout(KitAspectWidget *widget, Layouting::LayoutBuilder &builder) +void doLayout(KitAspectWidget *widget, Layouting::LayoutItem &builder) { widget->addToLayout(builder); } diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 43e01576e2e..d05c23eaf51 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -218,8 +218,10 @@ QWidget *RunConfiguration::createConfigurationWidget() { Layouting::Form form; for (BaseAspect *aspect : std::as_const(m_aspects)) { - if (aspect->isVisible()) + if (aspect->isVisible()) { form.addItem(aspect); + form.addItem(Layouting::br); + } } form.addItem(Layouting::noMargin); auto widget = form.emerge(); diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index face7d2ce4f..d90fbc7272a 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -62,12 +62,12 @@ TerminalAspect::TerminalAspect() /*! \reimp */ -void TerminalAspect::addToLayout(LayoutBuilder &builder) +void TerminalAspect::addToLayout(LayoutItem &parent) { QTC_CHECK(!m_checkBox); m_checkBox = new QCheckBox(Tr::tr("Run in terminal")); m_checkBox->setChecked(m_useTerminal); - builder.addItems({{}, m_checkBox.data()}); + parent.addItems({{}, m_checkBox.data()}); connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] { m_userSet = true; m_useTerminal = m_checkBox->isChecked(); @@ -163,7 +163,7 @@ WorkingDirectoryAspect::WorkingDirectoryAspect(const MacroExpander *expander, /*! \reimp */ -void WorkingDirectoryAspect::addToLayout(LayoutBuilder &builder) +void WorkingDirectoryAspect::addToLayout(LayoutItem &builder) { QTC_CHECK(!m_chooser); m_chooser = new PathChooser; @@ -435,7 +435,7 @@ QWidget *ArgumentsAspect::setupChooser() /*! \reimp */ -void ArgumentsAspect::addToLayout(LayoutBuilder &builder) +void ArgumentsAspect::addToLayout(LayoutItem &builder) { QTC_CHECK(!m_chooser && !m_multiLineChooser && !m_multiLineButton); @@ -632,7 +632,7 @@ FilePath ExecutableAspect::executable() const /*! \reimp */ -void ExecutableAspect::addToLayout(LayoutBuilder &builder) +void ExecutableAspect::addToLayout(LayoutItem &builder) { builder.addItem(m_executable); if (m_alternativeExecutable) @@ -830,7 +830,7 @@ void InterpreterAspect::toMap(QVariantMap &map) const saveToMap(map, m_currentId, QString(), settingsKey()); } -void InterpreterAspect::addToLayout(LayoutBuilder &builder) +void InterpreterAspect::addToLayout(LayoutItem &builder) { if (QTC_GUARD(m_comboBox.isNull())) m_comboBox = new QComboBox; diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index 0a7d4b54fbd..9fc7364772d 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -29,7 +29,7 @@ class PROJECTEXPLORER_EXPORT TerminalAspect : public Utils::BaseAspect public: TerminalAspect(); - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; bool useTerminal() const; void setUseTerminalHint(bool useTerminal); @@ -62,7 +62,7 @@ public: explicit WorkingDirectoryAspect(const Utils::MacroExpander *expander, EnvironmentAspect *envAspect); - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; Utils::FilePath workingDirectory() const; Utils::FilePath defaultWorkingDirectory() const; @@ -91,7 +91,7 @@ class PROJECTEXPLORER_EXPORT ArgumentsAspect : public Utils::BaseAspect public: explicit ArgumentsAspect(const Utils::MacroExpander *macroExpander); - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QString arguments() const; QString unexpandedArguments() const; @@ -163,7 +163,7 @@ public: void setSettingsKey(const QString &key); void makeOverridable(const QString &overridingKey, const QString &useOverridableKey); - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; void setLabelText(const QString &labelText); void setPlaceHolderText(const QString &placeHolderText); void setHistoryCompleter(const QString &historyCompleterKey); @@ -235,7 +235,7 @@ public: void fromMap(const QVariantMap &) override; void toMap(QVariantMap &) const override; - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; struct Data : Utils::BaseAspect::Data { Interpreter interpreter; }; diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index da5c6e70f6d..102cb7e3ae7 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -63,7 +63,7 @@ public: ArchitecturesAspect(); void setKit(const ProjectExplorer::Kit *kit) { m_kit = kit; } - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; QStringList selectedArchitectures() const; void setSelectedArchitectures(const QStringList& architectures); bool isManagedByTarget() const { return m_isManagedByTarget; } @@ -86,9 +86,9 @@ ArchitecturesAspect::ArchitecturesAspect() setAllValues(m_abisToArchMap.keys()); } -void ArchitecturesAspect::addToLayout(Layouting::LayoutBuilder &builder) +void ArchitecturesAspect::addToLayout(Layouting::LayoutItem &parent) { - MultiSelectionAspect::addToLayout(builder); + MultiSelectionAspect::addToLayout(parent); const auto changeHandler = [this] { const QtVersion *qtVersion = QtKitAspect::qtVersion(m_kit); if (!qtVersion) { diff --git a/src/plugins/qbsprojectmanager/qbskitinformation.cpp b/src/plugins/qbsprojectmanager/qbskitinformation.cpp index 800765bb368..b9cb79231d9 100644 --- a/src/plugins/qbsprojectmanager/qbskitinformation.cpp +++ b/src/plugins/qbsprojectmanager/qbskitinformation.cpp @@ -35,11 +35,11 @@ private: void makeReadOnly() override { m_changeButton->setEnabled(false); } void refresh() override { m_contentLabel->setText(QbsKitAspect::representation(kit())); } - void addToLayout(Layouting::LayoutBuilder &builder) override + void addToLayout(Layouting::LayoutItem &parent) override { addMutableAction(m_contentLabel); - builder.addItem(m_contentLabel); - builder.addItem(m_changeButton); + parent.addItem(m_contentLabel); + parent.addItem(m_changeButton); } void changeProperties() diff --git a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp index 06f2011244f..c413758048c 100644 --- a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp +++ b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp @@ -40,10 +40,10 @@ public: ~QmakeKitAspectWidget() override { delete m_lineEdit; } private: - void addToLayout(Layouting::LayoutBuilder &builder) override + void addToLayout(Layouting::LayoutItem &parent) override { addMutableAction(m_lineEdit); - builder.addItem(m_lineEdit); + parent.addItem(m_lineEdit); } void makeReadOnly() override { m_lineEdit->setEnabled(false); } diff --git a/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp b/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp index 279b48ccb1e..405e63965fe 100644 --- a/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp +++ b/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp @@ -55,7 +55,7 @@ QmlMainFileAspect::~QmlMainFileAspect() delete m_fileListCombo; } -void QmlMainFileAspect::addToLayout(Layouting::LayoutBuilder &builder) +void QmlMainFileAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_ASSERT(!m_fileListCombo, delete m_fileListCombo); m_fileListCombo = new QComboBox; @@ -67,7 +67,7 @@ void QmlMainFileAspect::addToLayout(Layouting::LayoutBuilder &builder) this, &QmlMainFileAspect::updateFileComboBox); connect(m_fileListCombo, &QComboBox::activated, this, &QmlMainFileAspect::setMainScript); - builder.addItems({Tr::tr("Main QML file:"), m_fileListCombo.data()}); + parent.addItems({Tr::tr("Main QML file:"), m_fileListCombo.data()}); } void QmlMainFileAspect::toMap(QVariantMap &map) const diff --git a/src/plugins/qmlprojectmanager/qmlmainfileaspect.h b/src/plugins/qmlprojectmanager/qmlmainfileaspect.h index 24ffcf94c6e..3c75e4744a2 100644 --- a/src/plugins/qmlprojectmanager/qmlmainfileaspect.h +++ b/src/plugins/qmlprojectmanager/qmlmainfileaspect.h @@ -42,7 +42,7 @@ public: Utils::FilePath currentFile; }; - void addToLayout(Layouting::LayoutBuilder &builder) final; + void addToLayout(Layouting::LayoutItem &parent) final; void toMap(QVariantMap &map) const final; void fromMap(const QVariantMap &map) final; diff --git a/src/plugins/qtsupport/qtbuildaspects.cpp b/src/plugins/qtsupport/qtbuildaspects.cpp index 95f2c8d4321..210ea58ee5a 100644 --- a/src/plugins/qtsupport/qtbuildaspects.cpp +++ b/src/plugins/qtsupport/qtbuildaspects.cpp @@ -30,13 +30,13 @@ QmlDebuggingAspect::QmlDebuggingAspect(BuildConfiguration *buildConfig) setValue(ProjectExplorerPlugin::buildPropertiesSettings().qmlDebugging.value()); } -void QmlDebuggingAspect::addToLayout(Layouting::LayoutBuilder &builder) +void QmlDebuggingAspect::addToLayout(Layouting::LayoutItem &parent) { - SelectionAspect::addToLayout(builder); + SelectionAspect::addToLayout(parent); const auto warningLabel = createSubWidget(QString(), InfoLabel::Warning); warningLabel->setElideMode(Qt::ElideNone); warningLabel->setVisible(false); - builder.addRow({{}, warningLabel}); + parent.addRow({{}, warningLabel}); const auto changeHandler = [this, warningLabel] { QString warningText; QTC_ASSERT(m_buildConfig, return); @@ -67,13 +67,13 @@ QtQuickCompilerAspect::QtQuickCompilerAspect(BuildConfiguration *buildConfig) setValue(ProjectExplorerPlugin::buildPropertiesSettings().qtQuickCompiler.value()); } -void QtQuickCompilerAspect::addToLayout(Layouting::LayoutBuilder &builder) +void QtQuickCompilerAspect::addToLayout(Layouting::LayoutItem &parent) { - SelectionAspect::addToLayout(builder); + SelectionAspect::addToLayout(parent); const auto warningLabel = createSubWidget(QString(), InfoLabel::Warning); warningLabel->setElideMode(Qt::ElideNone); warningLabel->setVisible(false); - builder.addRow({{}, warningLabel}); + parent.addRow({{}, warningLabel}); const auto changeHandler = [this, warningLabel] { QString warningText; QTC_ASSERT(m_buildConfig, return); diff --git a/src/plugins/qtsupport/qtbuildaspects.h b/src/plugins/qtsupport/qtbuildaspects.h index 8ba97afdbba..e5e0b3332e6 100644 --- a/src/plugins/qtsupport/qtbuildaspects.h +++ b/src/plugins/qtsupport/qtbuildaspects.h @@ -18,7 +18,7 @@ class QTSUPPORT_EXPORT QmlDebuggingAspect : public Utils::TriStateAspect public: explicit QmlDebuggingAspect(ProjectExplorer::BuildConfiguration *buildConfig); - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; private: const ProjectExplorer::BuildConfiguration *m_buildConfig = nullptr; @@ -32,7 +32,7 @@ public: QtQuickCompilerAspect(ProjectExplorer::BuildConfiguration *buildConfig); private: - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; const ProjectExplorer::BuildConfiguration *m_buildConfig = nullptr; }; diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp index 2489ce5839b..7fab3fbbcca 100644 --- a/src/plugins/qtsupport/qtkitinformation.cpp +++ b/src/plugins/qtsupport/qtkitinformation.cpp @@ -60,11 +60,11 @@ public: private: void makeReadOnly() final { m_combo->setEnabled(false); } - void addToLayout(Layouting::LayoutBuilder &builder) + void addToLayout(Layouting::LayoutItem &parent) { addMutableAction(m_combo); - builder.addItem(m_combo); - builder.addItem(m_manageButton); + parent.addItem(m_combo); + parent.addItem(m_manageButton); } void refresh() final diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index fe546ea0cc2..bdcf9971e6f 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -128,7 +128,7 @@ void SuppressionAspect::setValue(const FilePaths &val) BaseAspect::setValue(Utils::transform(val, &FilePath::toString)); } -void SuppressionAspect::addToLayout(Layouting::LayoutBuilder &builder) +void SuppressionAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_CHECK(!d->addEntry); QTC_CHECK(!d->removeEntry); @@ -150,12 +150,12 @@ void SuppressionAspect::addToLayout(Layouting::LayoutBuilder &builder) connect(d->entryList->selectionModel(), &QItemSelectionModel::selectionChanged, d, &SuppressionAspectPrivate::slotSuppressionSelectionChanged); - builder.addItem(Column { Tr::tr("Suppression files:"), st }); + parent.addItem(Column { Tr::tr("Suppression files:"), st }); Row group { d->entryList.data(), Column { d->addEntry.data(), d->removeEntry.data(), st } }; - builder.addItem(Span { 2, group }); + parent.addItem(Span { 2, group }); setVolatileValue(BaseAspect::value()); } diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h index d2a4bed606e..a8359804ddc 100644 --- a/src/plugins/valgrind/valgrindsettings.h +++ b/src/plugins/valgrind/valgrindsettings.h @@ -23,7 +23,7 @@ public: Utils::FilePaths value() const; void setValue(const Utils::FilePaths &val); - void addToLayout(Layouting::LayoutBuilder &builder) final; + void addToLayout(Layouting::LayoutItem &parent) final; void fromMap(const QVariantMap &map) final; void toMap(QVariantMap &map) const final; diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp index c1eb243e49a..abd6de8ed61 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp @@ -55,7 +55,7 @@ WebBrowserSelectionAspect::WebBrowserSelectionAspect(ProjectExplorer::Target *ta addDataExtractor(this, &WebBrowserSelectionAspect::currentBrowser, &Data::currentBrowser); } -void WebBrowserSelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) +void WebBrowserSelectionAspect::addToLayout(Layouting::LayoutItem &parent) { QTC_CHECK(!m_webBrowserComboBox); m_webBrowserComboBox = new QComboBox; @@ -66,7 +66,7 @@ void WebBrowserSelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) m_currentBrowser = m_webBrowserComboBox->currentData().toString(); emit changed(); }); - builder.addItems({Tr::tr("Web browser:"), m_webBrowserComboBox}); + parent.addItems({Tr::tr("Web browser:"), m_webBrowserComboBox}); } void WebBrowserSelectionAspect::fromMap(const QVariantMap &map) diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.h b/src/plugins/webassembly/webassemblyrunconfigurationaspects.h index 8b0d5128825..8a3cc24bdb2 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.h +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.h @@ -20,7 +20,7 @@ class WebBrowserSelectionAspect : public Utils::BaseAspect public: WebBrowserSelectionAspect(ProjectExplorer::Target *target); - void addToLayout(Layouting::LayoutBuilder &builder) override; + void addToLayout(Layouting::LayoutItem &parent) override; void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; From c99d848e53e53f8ed8102ad51e606fa9d41dcfb0 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 May 2023 16:09:01 +0200 Subject: [PATCH 0800/1447] CMake: Use LayoutBuilder in CMakeInstallStep Change-Id: Idfc836d04afa29a133d87506d5542716d5d9f542 Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp index 91faa2ebaf8..07d3c6fd478 100644 --- a/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeinstallstep.cpp @@ -106,11 +106,8 @@ QWidget *CMakeInstallStep::createConfigWidget() setDisplayName(Tr::tr("Install", "ConfigWidget display name.")); - Layouting::Form builder; - builder.addRow({m_cmakeArguments}); - builder.addItem(Layouting::noMargin); - - auto widget = builder.emerge(); + using namespace Layouting; + auto widget = Form { m_cmakeArguments, noMargin }.emerge(); updateDetails(); From 1c37aab5bd26c4dbaefd8828dfedb28afc064aaa Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 16:05:33 +0200 Subject: [PATCH 0801/1447] LauncherSocketHandler: Disambiguate Process name Rename Process -> ProcessWithToken. Change-Id: I75920488107f45198590e0b17fa5c9e7679c6192 Reviewed-by: hjk --- .../processlauncher/launchersockethandler.cpp | 28 +++++++++---------- .../processlauncher/launchersockethandler.h | 16 +++++------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/tools/processlauncher/launchersockethandler.cpp b/src/tools/processlauncher/launchersockethandler.cpp index a0a2733ded1..dae28aa4fbc 100644 --- a/src/tools/processlauncher/launchersockethandler.cpp +++ b/src/tools/processlauncher/launchersockethandler.cpp @@ -14,11 +14,11 @@ namespace Utils { namespace Internal { -class Process : public ProcessHelper +class ProcessWithToken : public ProcessHelper { Q_OBJECT public: - Process(quintptr token, QObject *parent = nullptr) : + ProcessWithToken(quintptr token, QObject *parent = nullptr) : ProcessHelper(parent), m_token(token) { } quintptr token() const { return m_token; } @@ -41,7 +41,7 @@ LauncherSocketHandler::LauncherSocketHandler(QString serverPath, QObject *parent LauncherSocketHandler::~LauncherSocketHandler() { for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it) { - Process *p = it.value(); + ProcessWithToken *p = it.value(); if (p->state() != QProcess::NotRunning) logWarn(QStringLiteral("Shutting down while process %1 is running").arg(p->program())); ProcessReaper::reap(p); @@ -114,7 +114,7 @@ void LauncherSocketHandler::handleSocketClosed() qApp->quit(); } -void LauncherSocketHandler::handleProcessError(Process *process) +void LauncherSocketHandler::handleProcessError(ProcessWithToken *process) { // In case of FailedToStart we won't receive finished signal, so we send the error // packet and remove the process here and now. For all other errors we should expect @@ -124,7 +124,7 @@ void LauncherSocketHandler::handleProcessError(Process *process) handleProcessFinished(process); } -void LauncherSocketHandler::handleProcessStarted(Process *process) +void LauncherSocketHandler::handleProcessStarted(ProcessWithToken *process) { ProcessStartedPacket packet(process->token()); packet.processId = process->processId(); @@ -132,21 +132,21 @@ void LauncherSocketHandler::handleProcessStarted(Process *process) sendPacket(packet); } -void LauncherSocketHandler::handleReadyReadStandardOutput(Process *process) +void LauncherSocketHandler::handleReadyReadStandardOutput(ProcessWithToken *process) { ReadyReadStandardOutputPacket packet(process->token()); packet.standardChannel = process->readAllStandardOutput(); sendPacket(packet); } -void LauncherSocketHandler::handleReadyReadStandardError(Process *process) +void LauncherSocketHandler::handleReadyReadStandardError(ProcessWithToken *process) { ReadyReadStandardErrorPacket packet(process->token()); packet.standardChannel = process->readAllStandardError(); sendPacket(packet); } -void LauncherSocketHandler::handleProcessFinished(Process *process) +void LauncherSocketHandler::handleProcessFinished(ProcessWithToken *process) { ProcessDonePacket packet(process->token()); packet.exitCode = process->exitCode(); @@ -162,7 +162,7 @@ void LauncherSocketHandler::handleProcessFinished(Process *process) void LauncherSocketHandler::handleStartPacket() { - Process *& process = m_processes[m_packetParser.token()]; + ProcessWithToken *& process = m_processes[m_packetParser.token()]; if (!process) process = setupProcess(m_packetParser.token()); if (process->state() != QProcess::NotRunning) { @@ -197,7 +197,7 @@ void LauncherSocketHandler::handleStartPacket() void LauncherSocketHandler::handleWritePacket() { - Process * const process = m_processes.value(m_packetParser.token()); + ProcessWithToken * const process = m_processes.value(m_packetParser.token()); if (!process) { logWarn("Got write request for unknown process"); return; @@ -214,7 +214,7 @@ void LauncherSocketHandler::handleWritePacket() void LauncherSocketHandler::handleControlPacket() { - Process * const process = m_processes.value(m_packetParser.token()); + ProcessWithToken * const process = m_processes.value(m_packetParser.token()); if (!process) { // This can happen when the process finishes on its own at about the same time the client // sends the request. In this case the process was already deleted. @@ -253,9 +253,9 @@ void LauncherSocketHandler::sendPacket(const LauncherPacket &packet) m_socket->write(packet.serialize()); } -Process *LauncherSocketHandler::setupProcess(quintptr token) +ProcessWithToken *LauncherSocketHandler::setupProcess(quintptr token) { - const auto p = new Process(token, this); + const auto p = new ProcessWithToken(token, this); connect(p, &QProcess::started, this, [this, p] { handleProcessStarted(p); }); connect(p, &QProcess::errorOccurred, this, [this, p] { handleProcessError(p); }); connect(p, &QProcess::finished, this, [this, p] { handleProcessFinished(p); }); @@ -272,7 +272,7 @@ void LauncherSocketHandler::removeProcess(quintptr token) if (it == m_processes.constEnd()) return; - Process *process = it.value(); + ProcessWithToken *process = it.value(); m_processes.erase(it); ProcessReaper::reap(process, process->reaperTimeout()); } diff --git a/src/tools/processlauncher/launchersockethandler.h b/src/tools/processlauncher/launchersockethandler.h index e3ec8a65b8f..d4146ad5f86 100644 --- a/src/tools/processlauncher/launchersockethandler.h +++ b/src/tools/processlauncher/launchersockethandler.h @@ -15,7 +15,7 @@ QT_END_NAMESPACE namespace Utils { namespace Internal { -class Process; +class ProcessWithToken; class LauncherSocketHandler : public QObject { @@ -31,11 +31,11 @@ private: void handleSocketError(); void handleSocketClosed(); - void handleProcessStarted(Process *process); - void handleProcessError(Process *process); - void handleProcessFinished(Process *process); - void handleReadyReadStandardOutput(Process *process); - void handleReadyReadStandardError(Process *process); + void handleProcessStarted(ProcessWithToken *process); + void handleProcessError(ProcessWithToken *process); + void handleProcessFinished(ProcessWithToken *process); + void handleReadyReadStandardOutput(ProcessWithToken *process); + void handleReadyReadStandardError(ProcessWithToken *process); void handleStartPacket(); void handleWritePacket(); @@ -44,13 +44,13 @@ private: void sendPacket(const LauncherPacket &packet); - Process *setupProcess(quintptr token); + ProcessWithToken *setupProcess(quintptr token); void removeProcess(quintptr token); const QString m_serverPath; QLocalSocket * const m_socket; PacketParser m_packetParser; - QHash m_processes; + QHash m_processes; }; } // namespace Internal From 43e3b41afda2682ed0725327d55bac5e683bcd06 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 19 Apr 2023 16:20:33 +0200 Subject: [PATCH 0802/1447] Core: Delay creation of settings page widgets ... until they are actually shown. Change-Id: Ibf47fe57c69557f9c514cc5a7c7c8aff369b1324 Reviewed-by: Eike Ziller --- .../coreplugin/dialogs/settingsdialog.cpp | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 017b8dc8846..f429994edd9 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -331,14 +331,26 @@ public: class SmartScrollArea : public QScrollArea { public: - explicit SmartScrollArea(QWidget *parent) - : QScrollArea(parent) + explicit SmartScrollArea(QWidget *parent, IOptionsPage *page) + : QScrollArea(parent), m_page(page) { setFrameStyle(QFrame::NoFrame | QFrame::Plain); viewport()->setAutoFillBackground(false); setWidgetResizable(true); } + private: + void showEvent(QShowEvent *event) final + { + if (!widget()) { + QWidget *inner = m_page->widget(); + setWidget(inner); + inner->setAutoFillBackground(false); + } + + QScrollArea::showEvent(event); + } + void resizeEvent(QResizeEvent *event) final { QWidget *inner = widget(); @@ -387,6 +399,8 @@ private: return 0; return list.first()->sizeHint().width(); } + + IOptionsPage *m_page = nullptr; }; // ----------- SettingsDialog @@ -604,14 +618,8 @@ void SettingsDialog::ensureCategoryWidget(Category *category) m_model.ensurePages(category); auto tabWidget = new QTabWidget; tabWidget->tabBar()->setObjectName("qc_settings_main_tabbar"); // easier lookup in Squish - for (IOptionsPage *page : std::as_const(category->pages)) { - QWidget *widget = page->widget(); - ICore::setupScreenShooter(page->displayName(), widget); - auto ssa = new SmartScrollArea(this); - ssa->setWidget(widget); - widget->setAutoFillBackground(false); - tabWidget->addTab(ssa, page->displayName()); - } + for (IOptionsPage *page : std::as_const(category->pages)) + tabWidget->addTab(new SmartScrollArea(this, page), page->displayName()); connect(tabWidget, &QTabWidget::currentChanged, this, &SettingsDialog::currentTabChanged); From 2a5f2961a75bd26acadc9ab514a8875d9eaade4c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 08:18:18 +0200 Subject: [PATCH 0803/1447] QDSNewDialog: Don't delete this QObject Use deleteLater() instead. Amends a850b1b866a5dfbaffdcf26fa7816c5a41305bbf Change-Id: Ib4e5f06b6a052a7bde1a9de45de4288b0ce44fe6 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/studiowelcome/qdsnewdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp index 455267e901e..964ae4db109 100644 --- a/src/plugins/studiowelcome/qdsnewdialog.cpp +++ b/src/plugins/studiowelcome/qdsnewdialog.cpp @@ -88,10 +88,10 @@ QdsNewDialog::QdsNewDialog(QWidget *parent) m_dialog->installEventFilter(this); - QObject::connect(&m_wizard, &WizardHandler::wizardCreationFailed, this, [this]() { + QObject::connect(&m_wizard, &WizardHandler::wizardCreationFailed, this, [this] { QMessageBox::critical(m_dialog, tr("New Project"), tr("Failed to initialize data.")); reject(); - delete this; + deleteLater(); }); QObject::connect(m_styleModel.data(), &StyleModel::modelAboutToBeReset, this, [this]() { From 765e8a65eaeb2ec01cd87970a44fd84bab08d59a Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 2 May 2023 18:28:12 +0200 Subject: [PATCH 0804/1447] Examples: Centralize constants in one place Having all constants in WelcomePageHelpers makes reading the welcome scren code a bit less interesting. Change-Id: Idc2e402f33042b49d041c43ecc78a6e8d2d3536a Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/coreplugin/welcomepagehelper.cpp | 13 ++++++------- src/plugins/coreplugin/welcomepagehelper.h | 13 ++++++------- src/plugins/marketplace/productlistmodel.cpp | 2 +- src/plugins/qtsupport/exampleslistmodel.cpp | 3 ++- src/plugins/qtsupport/gettingstartedwelcomepage.cpp | 4 ++-- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index ad7c5867476..cba0d6c033e 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -144,10 +144,10 @@ bool SectionGridView::hasHeightForWidth() const int SectionGridView::heightForWidth(int width) const { - const int columnCount = width / Core::ListItemDelegate::GridItemWidth; + const int columnCount = width / Core::WelcomePageHelpers::GridItemWidth; const int rowCount = (model()->rowCount() + columnCount - 1) / columnCount; const int maxRowCount = m_maxRows ? std::min(*m_maxRows, rowCount) : rowCount; - return maxRowCount * Core::ListItemDelegate::GridItemHeight; + return maxRowCount * Core::WelcomePageHelpers::GridItemHeight; } void SectionGridView::wheelEvent(QWheelEvent *e) @@ -162,8 +162,8 @@ bool SectionGridView::event(QEvent *e) { if (e->type() == QEvent::Resize) { const auto itemsFit = [this](const QSize &size) { - const int maxColumns = std::max(size.width() / ListItemDelegate::GridItemWidth, 1); - const int maxRows = std::max(size.height() / ListItemDelegate::GridItemHeight, 1); + const int maxColumns = std::max(size.width() / WelcomePageHelpers::GridItemWidth, 1); + const int maxRows = std::max(size.height() / WelcomePageHelpers::GridItemHeight, 1); const int maxItems = maxColumns * maxRows; const int items = model()->rowCount(); return maxItems >= items; @@ -178,8 +178,6 @@ bool SectionGridView::event(QEvent *e) return GridView::event(e); } -const QSize ListModel::defaultImageSize(214, 160); - ListModel::ListModel(QObject *parent) : QAbstractListModel(parent) { @@ -459,13 +457,14 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti const QRect rc = option.rect; const QRect tileRect(0, 0, rc.width() - GridItemGap, rc.height() - GridItemGap); - const QSize thumbnailBgSize = ListModel::defaultImageSize.grownBy(QMargins(1, 1, 1, 1)); + const QSize thumbnailBgSize = GridItemImageSize.grownBy(QMargins(1, 1, 1, 1)); const QRect thumbnailBgRect((tileRect.width() - thumbnailBgSize.width()) / 2, GridItemGap, thumbnailBgSize.width(), thumbnailBgSize.height()); const QRect textArea = tileRect.adjusted(GridItemGap, GridItemGap, -GridItemGap, -GridItemGap); const bool hovered = option.state & QStyle::State_MouseOver; + constexpr int TagsSeparatorY = GridItemHeight - GridItemGap - 52; constexpr int tagsBase = TagsSeparatorY + 17; constexpr int shiftY = TagsSeparatorY - 16; constexpr int nameY = TagsSeparatorY - 20; diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 641ce5983dd..f997b2539a9 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -24,6 +24,12 @@ namespace WelcomePageHelpers { constexpr int HSpacing = 20; constexpr int ItemGap = 4; + +constexpr int GridItemGap = 3 * ItemGap; +constexpr int GridItemWidth = 240 + GridItemGap; +constexpr int GridItemHeight = GridItemWidth; +constexpr QSize GridItemImageSize(214, 160); + CORE_EXPORT QFont brandFont(); CORE_EXPORT QWidget *panelBar(QWidget *parent = nullptr); @@ -99,8 +105,6 @@ public: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void setPixmapFunction(const PixmapFunction &fetchPixmapAndUpdatePixmapCache); - static const QSize defaultImageSize; - void setOwnsItems(bool owns); private: @@ -142,11 +146,6 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - static constexpr int GridItemGap = 3 * WelcomePageHelpers::ItemGap; - static constexpr int GridItemWidth = 240 + GridItemGap; - static constexpr int GridItemHeight = GridItemWidth; - static constexpr int TagsSeparatorY = GridItemHeight - GridItemGap - 52; - signals: void tagClicked(const QString &tag); diff --git a/src/plugins/marketplace/productlistmodel.cpp b/src/plugins/marketplace/productlistmodel.cpp index cdfb8d79e5f..36b047abc21 100644 --- a/src/plugins/marketplace/productlistmodel.cpp +++ b/src/plugins/marketplace/productlistmodel.cpp @@ -269,7 +269,7 @@ void SectionedProducts::onImageDownloadFinished(QNetworkReply *reply) if (pixmap.loadFromData(data, imageFormat.toLatin1())) { const QString url = imageUrl.toString(); const int dpr = qApp->devicePixelRatio(); - pixmap = pixmap.scaled(ListModel::defaultImageSize * dpr, + pixmap = pixmap.scaled(WelcomePageHelpers::GridItemImageSize * dpr, Qt::KeepAspectRatio, Qt::SmoothTransformation); pixmap.setDevicePixelRatio(dpr); diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 3478634815c..ebb90381c7b 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -255,7 +255,8 @@ static QPixmap fetchPixmapAndUpdatePixmapCache(const QString &url) img.convertTo(QImage::Format_RGB32); const int dpr = qApp->devicePixelRatio(); // boundedTo -> don't scale thumbnails up - const QSize scaledSize = Core::ListModel::defaultImageSize.boundedTo(img.size()) * dpr; + const QSize scaledSize = + WelcomePageHelpers::GridItemImageSize.boundedTo(img.size()) * dpr; pixmap = QPixmap::fromImage( img.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)); pixmap.setDevicePixelRatio(dpr); diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index bf19233c211..7bc7192185e 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -280,8 +280,8 @@ public: // for macOS dark mode pal.setColor(QPalette::Text, Utils::creatorTheme()->color(Theme::Welcome_TextColor)); exampleSetSelector->setPalette(pal); - exampleSetSelector->setMinimumWidth(Core::ListItemDelegate::GridItemWidth); - exampleSetSelector->setMaximumWidth(Core::ListItemDelegate::GridItemWidth); + exampleSetSelector->setMinimumWidth(Core::WelcomePageHelpers::GridItemWidth); + exampleSetSelector->setMaximumWidth(Core::WelcomePageHelpers::GridItemWidth); exampleSetSelector->setModel(s_exampleSetModel); exampleSetSelector->setCurrentIndex(s_exampleSetModel->selectedExampleSet()); connect(exampleSetSelector, From b3a595fcfe1c0beeb1ecca8b4cb4e96bcbc60ce4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 15:26:12 +0200 Subject: [PATCH 0805/1447] Tasking::CurrentDocumentSymbolsRequest: Rename CurrentDocumentSymbolsRequest -> CurrentDocumentSymbolsRequestTask CurrentDocumentSymbolsRequestTask -> CurrentDocumentSymbolsRequest currentdocumentsymbolsrequesttask.{cpp,h} -> currentdocumentsymbolsrequest.{cpp,h} Task-number: QTCREATORBUG-29102 Change-Id: I5a0b0edf67babf6880682a30a2fd973f849b1880 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 8 ++++---- src/plugins/languageclient/CMakeLists.txt | 2 +- ...questtask.cpp => currentdocumentsymbolsrequest.cpp} | 10 +++++----- ...lsrequesttask.h => currentdocumentsymbolsrequest.h} | 6 +++--- src/plugins/languageclient/languageclient.qbs | 4 ++-- src/plugins/languageclient/locatorfilter.cpp | 8 ++++---- 6 files changed, 19 insertions(+), 19 deletions(-) rename src/plugins/languageclient/{currentdocumentsymbolsrequesttask.cpp => currentdocumentsymbolsrequest.cpp} (88%) rename src/plugins/languageclient/{currentdocumentsymbolsrequesttask.h => currentdocumentsymbolsrequest.h} (89%) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index a925f001fa4..e81e3bfebf1 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -436,10 +436,10 @@ LocatorMatcherTask currentDocumentMatcher() TreeStorage storage; TreeStorage resultStorage; - const auto onQuerySetup = [=](CurrentDocumentSymbolsRequestTask &request) { + const auto onQuerySetup = [=](CurrentDocumentSymbolsRequest &request) { Q_UNUSED(request) }; - const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequestTask &request) { + const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequest &request) { *resultStorage = request.currentDocumentSymbolsData(); }; @@ -451,7 +451,7 @@ LocatorMatcherTask currentDocumentMatcher() const Group root { Storage(resultStorage), - CurrentDocumentSymbolsRequest(onQuerySetup, onQueryDone), + CurrentDocumentSymbolsRequestTask(onQuerySetup, onQueryDone), AsyncTask(onFilterSetup) }; return {root, storage}; diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt index ab195c3d764..5af221f7f86 100644 --- a/src/plugins/languageclient/CMakeLists.txt +++ b/src/plugins/languageclient/CMakeLists.txt @@ -11,7 +11,7 @@ add_qtc_plugin(LanguageClient callhierarchy.cpp callhierarchy.h client.cpp client.h clientrequesttask.cpp clientrequesttask.h - currentdocumentsymbolsrequesttask.cpp currentdocumentsymbolsrequesttask.h + currentdocumentsymbolsrequest.cpp currentdocumentsymbolsrequest.h diagnosticmanager.cpp diagnosticmanager.h documentsymbolcache.cpp documentsymbolcache.h dynamiccapabilities.cpp dynamiccapabilities.h diff --git a/src/plugins/languageclient/currentdocumentsymbolsrequesttask.cpp b/src/plugins/languageclient/currentdocumentsymbolsrequest.cpp similarity index 88% rename from src/plugins/languageclient/currentdocumentsymbolsrequesttask.cpp rename to src/plugins/languageclient/currentdocumentsymbolsrequest.cpp index 9221d65c17c..2d272a72161 100644 --- a/src/plugins/languageclient/currentdocumentsymbolsrequesttask.cpp +++ b/src/plugins/languageclient/currentdocumentsymbolsrequest.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "currentdocumentsymbolsrequesttask.h" +#include "currentdocumentsymbolsrequest.h" #include "documentsymbolcache.h" #include "languageclientmanager.h" @@ -15,7 +15,7 @@ using namespace Utils; namespace LanguageClient { -void CurrentDocumentSymbolsRequestTask::start() +void CurrentDocumentSymbolsRequest::start() { QTC_ASSERT(!isRunning(), return); @@ -58,12 +58,12 @@ void CurrentDocumentSymbolsRequestTask::start() symbolCache->requestSymbols(currentUri, Schedule::Now); } -bool CurrentDocumentSymbolsRequestTask::isRunning() const +bool CurrentDocumentSymbolsRequest::isRunning() const { return !m_connections.isEmpty(); } -void CurrentDocumentSymbolsRequestTask::clearConnections() +void CurrentDocumentSymbolsRequest::clearConnections() { for (const QMetaObject::Connection &connection : std::as_const(m_connections)) disconnect(connection); @@ -72,7 +72,7 @@ void CurrentDocumentSymbolsRequestTask::clearConnections() CurrentDocumentSymbolsRequestTaskAdapter::CurrentDocumentSymbolsRequestTaskAdapter() { - connect(task(), &CurrentDocumentSymbolsRequestTask::done, this, &TaskInterface::done); + connect(task(), &CurrentDocumentSymbolsRequest::done, this, &TaskInterface::done); } void CurrentDocumentSymbolsRequestTaskAdapter::start() diff --git a/src/plugins/languageclient/currentdocumentsymbolsrequesttask.h b/src/plugins/languageclient/currentdocumentsymbolsrequest.h similarity index 89% rename from src/plugins/languageclient/currentdocumentsymbolsrequesttask.h rename to src/plugins/languageclient/currentdocumentsymbolsrequest.h index 2c10b239689..f0e3fdccdac 100644 --- a/src/plugins/languageclient/currentdocumentsymbolsrequesttask.h +++ b/src/plugins/languageclient/currentdocumentsymbolsrequest.h @@ -19,7 +19,7 @@ public: LanguageServerProtocol::DocumentSymbolsResult m_symbols; }; -class LANGUAGECLIENT_EXPORT CurrentDocumentSymbolsRequestTask : public QObject +class LANGUAGECLIENT_EXPORT CurrentDocumentSymbolsRequest : public QObject { Q_OBJECT @@ -39,7 +39,7 @@ private: }; class LANGUAGECLIENT_EXPORT CurrentDocumentSymbolsRequestTaskAdapter - : public Utils::Tasking::TaskAdapter + : public Utils::Tasking::TaskAdapter { public: CurrentDocumentSymbolsRequestTaskAdapter(); @@ -48,5 +48,5 @@ public: } // namespace LanguageClient -QTC_DECLARE_CUSTOM_TASK(CurrentDocumentSymbolsRequest, +QTC_DECLARE_CUSTOM_TASK(CurrentDocumentSymbolsRequestTask, LanguageClient::CurrentDocumentSymbolsRequestTaskAdapter); diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index e0de5f6fb1b..286f319a3cc 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -26,8 +26,8 @@ QtcPlugin { "client.h", "clientrequesttask.cpp", "clientrequesttask.h", - "currentdocumentsymbolsrequesttask.cpp", - "currentdocumentsymbolsrequesttask.h", + "currentdocumentsymbolsrequest.cpp", + "currentdocumentsymbolsrequest.h", "diagnosticmanager.cpp", "diagnosticmanager.h", "documentsymbolcache.cpp", diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index adf0952d6c5..7ac85c165ba 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -4,7 +4,7 @@ #include "locatorfilter.h" #include "clientrequesttask.h" -#include "currentdocumentsymbolsrequesttask.h" +#include "currentdocumentsymbolsrequest.h" #include "documentsymbolcache.h" #include "languageclient_global.h" #include "languageclientmanager.h" @@ -131,10 +131,10 @@ LocatorMatcherTask currentDocumentMatcher() TreeStorage storage; TreeStorage resultStorage; - const auto onQuerySetup = [=](CurrentDocumentSymbolsRequestTask &request) { + const auto onQuerySetup = [=](CurrentDocumentSymbolsRequest &request) { Q_UNUSED(request) }; - const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequestTask &request) { + const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequest &request) { *resultStorage = request.currentDocumentSymbolsData(); }; @@ -145,7 +145,7 @@ LocatorMatcherTask currentDocumentMatcher() const Group root { Storage(resultStorage), - CurrentDocumentSymbolsRequest(onQuerySetup, onQueryDone), + CurrentDocumentSymbolsRequestTask(onQuerySetup, onQueryDone), AsyncTask(onFilterSetup) }; return {root, storage}; From 6531dc4569228c0ae120bf0eececb435f6e583d0 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 3 May 2023 20:50:32 +0200 Subject: [PATCH 0806/1447] Layouts: Add missing "br"s to terminate Form lines This restores the layout of various forms to the state prior to the LayoutHelper changes. Change-Id: I9b88229485b257ca7454d688aa0a9b1984206496 Reviewed-by: hjk --- src/plugins/bazaar/bazaarsettings.cpp | 2 +- src/plugins/cpaster/fileshareprotocolsettingspage.cpp | 2 +- src/plugins/cpaster/settings.cpp | 4 ++-- src/plugins/cvs/cvssettings.cpp | 4 ++-- src/plugins/gitlab/gitlaboptionspage.cpp | 8 ++++---- src/plugins/mercurial/mercurialsettings.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilersettings.cpp | 6 +++--- src/plugins/subversion/subversionsettings.cpp | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp index 7149f93251c..d76cb782fe1 100644 --- a/src/plugins/bazaar/bazaarsettings.cpp +++ b/src/plugins/bazaar/bazaarsettings.cpp @@ -90,7 +90,7 @@ BazaarSettingsPage::BazaarSettingsPage(BazaarSettings *settings) Group { title(Tr::tr("User")), Form { - s.userName, + s.userName, br, s.userEmail } }, diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp index 775c0438ab9..e2e382c94b0 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp @@ -52,7 +52,7 @@ FileShareProtocolSettingsPage::FileShareProtocolSettingsPage(FileShareProtocolSe Column { Form { label, br, - s.path, + s.path, br, s.displayCount }, st diff --git a/src/plugins/cpaster/settings.cpp b/src/plugins/cpaster/settings.cpp index 7459ae1098a..8f599dcd502 100644 --- a/src/plugins/cpaster/settings.cpp +++ b/src/plugins/cpaster/settings.cpp @@ -67,8 +67,8 @@ SettingsPage::SettingsPage(Settings *settings) Column { Form { - s.protocols, - s.username, + s.protocols, br, + s.username, br, s.expiryDays }, s.copyToClipboard, diff --git a/src/plugins/cvs/cvssettings.cpp b/src/plugins/cvs/cvssettings.cpp index 917db719211..1df80463692 100644 --- a/src/plugins/cvs/cvssettings.cpp +++ b/src/plugins/cvs/cvssettings.cpp @@ -85,7 +85,7 @@ CvsSettingsPage::CvsSettingsPage(CvsSettings *settings) Group { title(Tr::tr("Configuration")), Form { - s.binaryPath, + s.binaryPath, br, s.cvsRoot } }, @@ -93,7 +93,7 @@ CvsSettingsPage::CvsSettingsPage(CvsSettings *settings) title(Tr::tr("Miscellaneous")), Column { Form { - s.timeout, + s.timeout, br, s.diffOptions, }, s.describeByCommitId, diff --git a/src/plugins/gitlab/gitlaboptionspage.cpp b/src/plugins/gitlab/gitlaboptionspage.cpp index c9e654af83a..eb37c6de2bb 100644 --- a/src/plugins/gitlab/gitlaboptionspage.cpp +++ b/src/plugins/gitlab/gitlaboptionspage.cpp @@ -97,10 +97,10 @@ GitLabServerWidget::GitLabServerWidget(Mode m, QWidget *parent) Row { Form { - m_host, - m_description, - m_token, - m_port, + m_host, br, + m_description, br, + m_token, br, + m_port, br, m_secure, m == Edit ? normalMargin : noMargin }, diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp index 6d21550bc70..7286c54b90d 100644 --- a/src/plugins/mercurial/mercurialsettings.cpp +++ b/src/plugins/mercurial/mercurialsettings.cpp @@ -66,7 +66,7 @@ MercurialSettingsPage::MercurialSettingsPage(MercurialSettings *settings) Group { title(Tr::tr("User")), Form { - s.userName, + s.userName, br, s.userEmail } }, diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.cpp b/src/plugins/qmlprofiler/qmlprofilersettings.cpp index f7f955c87bf..1002479baae 100644 --- a/src/plugins/qmlprofiler/qmlprofilersettings.cpp +++ b/src/plugins/qmlprofiler/qmlprofilersettings.cpp @@ -28,9 +28,9 @@ public: using namespace Layouting; Form { - s.flushEnabled, - s.flushInterval, - s.aggregateTraces + s.flushEnabled, br, + s.flushInterval, br, + s.aggregateTraces, br, }.attachTo(this); } diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index d91f8f30c19..d26dceac7cf 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -99,7 +99,7 @@ SubversionSettingsPage::SubversionSettingsPage(SubversionSettings *settings) title(Tr::tr("Authentication")), s.useAuthentication.groupChecker(), Form { - s.userName, + s.userName, br, s.password, } }, From e5051bbfdef896ece974a949a392de7337284bf0 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 3 May 2023 20:47:53 +0200 Subject: [PATCH 0807/1447] Layouts: Add/remove contentMargins where needed Some cases were preexisting, some were introduced recently Change-Id: I0e7e7b74422c420fbf4563d7cbf384e53931c3a0 Reviewed-by: hjk --- src/plugins/coreplugin/dialogs/shortcutsettings.cpp | 1 + src/plugins/cppcheck/cppcheckoptions.cpp | 1 + src/plugins/fakevim/fakevimplugin.cpp | 1 + src/plugins/help/filtersettingspage.cpp | 1 + src/plugins/nim/settings/nimcodestylesettingspage.cpp | 1 - src/plugins/vcsbase/commonvcssettings.cpp | 8 ++++---- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp index 16c9c072038..c846fb9dae0 100644 --- a/src/plugins/coreplugin/dialogs/shortcutsettings.cpp +++ b/src/plugins/coreplugin/dialogs/shortcutsettings.cpp @@ -689,6 +689,7 @@ public: auto inner = new ShortcutSettingsWidget; auto vbox = new QVBoxLayout(this); vbox->addWidget(inner); + vbox->setContentsMargins(0, 0, 0, 0); setOnApply([inner] { inner->apply(); }); } diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp index 9a16319bb29..d91c9a6ebbe 100644 --- a/src/plugins/cppcheck/cppcheckoptions.cpp +++ b/src/plugins/cppcheck/cppcheckoptions.cpp @@ -130,6 +130,7 @@ public: auto vbox = new QVBoxLayout(this); vbox->addWidget(m_optionWidget); + vbox->setContentsMargins(0, 0, 0, 0); m_optionWidget->load(m_page->m_tool.options()); } diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 8d71345b56f..0ac0244ff6b 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -807,6 +807,7 @@ public: m_exCommands = new FakeVimExCommandsMappings; auto vbox = new QVBoxLayout(this); vbox->addWidget(m_exCommands); + vbox->setContentsMargins(0, 0, 0, 0); } private: diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp index 7f6ca802e9f..d484314f9d6 100644 --- a/src/plugins/help/filtersettingspage.cpp +++ b/src/plugins/help/filtersettingspage.cpp @@ -25,6 +25,7 @@ public: auto vbox = new QVBoxLayout(this); vbox->addWidget(m_widget); + vbox->setContentsMargins(0, 0, 0, 0); connect(Core::HelpManager::Signals::instance(), &Core::HelpManager::Signals::documentationChanged, diff --git a/src/plugins/nim/settings/nimcodestylesettingspage.cpp b/src/plugins/nim/settings/nimcodestylesettingspage.cpp index 79c3634cf25..ae26a14208a 100644 --- a/src/plugins/nim/settings/nimcodestylesettingspage.cpp +++ b/src/plugins/nim/settings/nimcodestylesettingspage.cpp @@ -36,7 +36,6 @@ public: auto layout = new QVBoxLayout(this); layout->addWidget(editor); - layout->setContentsMargins(0, 0, 0, 0); } private: diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 2f970ccbb83..416230e8d44 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -119,10 +119,10 @@ CommonSettingsWidget::CommonSettingsWidget(CommonOptionsPage *page) Column { Row { s.lineWrap, s.lineWrapWidth, st }, Form { - s.submitMessageCheckScript, - s.nickNameMailMap, - s.nickNameFieldListFile, - s.sshPasswordPrompt, + s.submitMessageCheckScript, br, + s.nickNameMailMap, br, + s.nickNameFieldListFile, br, + s.sshPasswordPrompt, br, {}, cacheResetButton } }.attachTo(this); From 0bffc2bc464a87b7f3a58ef8d249c91d9f5f73b5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 17:34:01 +0200 Subject: [PATCH 0808/1447] Adapt to upstream changes Follows 50084f6b0ed78bfee6f5e1d2e56ade9b52b3f2f6 Change-Id: I83a7a9bf491e1b587d26b9058952f23fc0c82f09 Reviewed-by: hjk --- plugins/axivion/axivionsettingspage.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index cb144371d9e..2c55192a995 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -71,11 +71,12 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) Form { m_dashboardUrl, m_description, - m_token + m_token, + mode == Edit ? normalMargin : noMargin } - }.attachTo(this, mode == Edit ? WithMargins : WithoutMargins); + }.attachTo(this); - auto checkValidity = [this](){ + auto checkValidity = [this] { bool old = m_valid; m_valid = isValid(); if (old != m_valid) From 470c95c94be58905bc3202d3b58175add5f576fa Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 16:00:22 +0200 Subject: [PATCH 0809/1447] Utils: Rename QtcProcess -> Process Task-number: QTCREATORBUG-29102 Change-Id: Ibc264f9db6a32206e4097766ee3f7d0b35225a5c Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- src/libs/extensionsystem/pluginmanager.cpp | 2 +- src/libs/qmljs/qmljsplugindumper.cpp | 8 +- src/libs/qmljs/qmljsplugindumper.h | 6 +- src/libs/utils/archive.cpp | 6 +- src/libs/utils/archive.h | 4 +- src/libs/utils/buildablehelperlibrary.cpp | 4 +- src/libs/utils/clangutils.cpp | 2 +- src/libs/utils/devicefileaccess.cpp | 8 +- src/libs/utils/deviceshell.cpp | 14 +- src/libs/utils/deviceshell.h | 6 +- src/libs/utils/filestreamer.cpp | 18 +- src/libs/utils/pathchooser.cpp | 2 +- src/libs/utils/processinfo.cpp | 6 +- src/libs/utils/processinterface.h | 2 +- src/libs/utils/qtcprocess.cpp | 204 +++++++++--------- src/libs/utils/qtcprocess.h | 10 +- src/libs/utils/terminalhooks.cpp | 4 +- src/plugins/android/androidavdmanager.cpp | 14 +- src/plugins/android/androidbuildapkstep.cpp | 2 +- src/plugins/android/androidconfigurations.cpp | 10 +- .../androidcreatekeystorecertificate.cpp | 2 +- src/plugins/android/androiddeployqtstep.cpp | 4 +- src/plugins/android/androiddevice.cpp | 6 +- src/plugins/android/androiddevice.h | 4 +- src/plugins/android/androidmanager.cpp | 8 +- .../android/androidqmlpreviewworker.cpp | 6 +- src/plugins/android/androidrunnerworker.cpp | 4 +- src/plugins/android/androidsdkmanager.cpp | 6 +- src/plugins/android/androidsettingswidget.cpp | 4 +- .../android/androidsignaloperation.cpp | 4 +- src/plugins/android/androidsignaloperation.h | 2 +- .../autotest/boost/boosttestconfiguration.cpp | 2 +- .../autotest/boost/boosttestconfiguration.h | 2 +- .../autotest/boost/boosttestoutputreader.cpp | 4 +- .../autotest/boost/boosttestoutputreader.h | 2 +- .../autotest/catch/catchconfiguration.cpp | 2 +- .../autotest/catch/catchconfiguration.h | 2 +- .../autotest/catch/catchoutputreader.cpp | 2 +- .../autotest/catch/catchoutputreader.h | 2 +- .../autotest/ctest/ctestconfiguration.cpp | 2 +- .../autotest/ctest/ctestconfiguration.h | 2 +- .../autotest/ctest/ctestoutputreader.cpp | 2 +- .../autotest/ctest/ctestoutputreader.h | 4 +- .../autotest/gtest/gtestconfiguration.cpp | 2 +- .../autotest/gtest/gtestconfiguration.h | 2 +- .../autotest/gtest/gtestoutputreader.cpp | 4 +- .../autotest/gtest/gtestoutputreader.h | 2 +- .../autotest/qtest/qttestconfiguration.cpp | 2 +- .../autotest/qtest/qttestconfiguration.h | 2 +- .../autotest/qtest/qttestoutputreader.cpp | 2 +- .../autotest/qtest/qttestoutputreader.h | 2 +- .../autotest/quick/quicktestconfiguration.cpp | 2 +- .../autotest/quick/quicktestconfiguration.h | 2 +- src/plugins/autotest/testconfiguration.h | 4 +- src/plugins/autotest/testoutputreader.cpp | 4 +- src/plugins/autotest/testoutputreader.h | 4 +- src/plugins/autotest/testrunner.cpp | 6 +- .../debugservers/uvsc/uvscserverprovider.cpp | 4 +- .../debugservers/uvsc/uvscserverprovider.h | 2 +- src/plugins/baremetal/iarewtoolchain.cpp | 4 +- src/plugins/baremetal/keiltoolchain.cpp | 6 +- src/plugins/baremetal/sdcctoolchain.cpp | 4 +- src/plugins/beautifier/abstractsettings.cpp | 4 +- .../artisticstyle/artisticstylesettings.cpp | 2 +- .../uncrustify/uncrustifysettings.cpp | 2 +- .../boot2qt/device-detection/qdbwatcher.cpp | 2 +- src/plugins/boot2qt/qdbdevice.cpp | 4 +- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 10 +- src/plugins/boot2qt/qdbmakedefaultappstep.cpp | 10 +- src/plugins/boot2qt/qdbplugin.cpp | 4 +- .../boot2qt/qdbstopapplicationstep.cpp | 10 +- src/plugins/clangtools/clangtoolrunner.cpp | 6 +- src/plugins/clangtools/clangtoolsutils.cpp | 2 +- src/plugins/clangtools/executableinfo.cpp | 2 +- src/plugins/clearcase/clearcaseplugin.cpp | 6 +- src/plugins/clearcase/clearcasesync.cpp | 2 +- .../cmakeprojectmanager/cmakebuildsystem.cpp | 12 +- .../cmakeprojectmanager/cmakebuildsystem.h | 4 +- .../cmakeprojectmanager/cmakeprocess.cpp | 4 +- .../cmakeprojectmanager/cmakeprocess.h | 4 +- .../cmakeprojectimporter.cpp | 4 +- src/plugins/cmakeprojectmanager/cmaketool.cpp | 6 +- src/plugins/cmakeprojectmanager/cmaketool.h | 4 +- src/plugins/coreplugin/externaltool.cpp | 8 +- src/plugins/coreplugin/externaltool.h | 4 +- src/plugins/coreplugin/fileutils.cpp | 4 +- .../coreplugin/locator/executefilter.cpp | 8 +- .../coreplugin/locator/executefilter.h | 4 +- .../locator/spotlightlocatorfilter.cpp | 14 +- src/plugins/coreplugin/patchtool.cpp | 2 +- .../coreplugin/plugininstallwizard.cpp | 2 +- .../progressmanager/processprogress.cpp | 20 +- .../progressmanager/processprogress.h | 4 +- src/plugins/cppcheck/cppcheckrunner.cpp | 6 +- src/plugins/cppcheck/cppcheckrunner.h | 2 +- .../cppeditor/cppcodemodelsettings.cpp | 2 +- src/plugins/cppeditor/cppmodelmanager.cpp | 4 +- src/plugins/debugger/cdb/cdbengine.cpp | 4 +- src/plugins/debugger/cdb/cdbengine.h | 2 +- src/plugins/debugger/dap/dapengine.cpp | 8 +- src/plugins/debugger/dap/dapengine.h | 2 +- src/plugins/debugger/debuggeritem.cpp | 4 +- src/plugins/debugger/debuggeritemmanager.cpp | 2 +- src/plugins/debugger/debuggerruncontrol.cpp | 6 +- .../debuggersourcepathmappingwidget.cpp | 2 +- src/plugins/debugger/gdb/gdbengine.cpp | 12 +- src/plugins/debugger/gdb/gdbengine.h | 2 +- src/plugins/debugger/lldb/lldbengine.cpp | 10 +- src/plugins/debugger/lldb/lldbengine.h | 2 +- src/plugins/debugger/moduleshandler.cpp | 2 +- src/plugins/debugger/pdb/pdbengine.cpp | 8 +- src/plugins/debugger/pdb/pdbengine.h | 2 +- src/plugins/debugger/qml/qmlengine.cpp | 10 +- src/plugins/debugger/terminal.cpp | 6 +- src/plugins/debugger/terminal.h | 4 +- src/plugins/docker/dockerapi.cpp | 4 +- src/plugins/docker/dockerdevice.cpp | 34 +-- src/plugins/fakevim/fakevimplugin.cpp | 2 +- src/plugins/git/branchmodel.cpp | 10 +- src/plugins/git/branchview.cpp | 4 +- src/plugins/git/changeselectiondialog.cpp | 8 +- src/plugins/git/changeselectiondialog.h | 4 +- src/plugins/git/gerrit/gerritmodel.cpp | 10 +- src/plugins/git/gerrit/gerritplugin.cpp | 8 +- src/plugins/git/gitclient.cpp | 56 ++--- src/plugins/git/gitgrep.cpp | 2 +- src/plugins/git/mergetool.cpp | 4 +- src/plugins/git/mergetool.h | 2 +- src/plugins/gitlab/queryrunner.cpp | 2 +- src/plugins/gitlab/queryrunner.h | 2 +- src/plugins/haskell/haskellmanager.cpp | 4 +- src/plugins/ios/iosconfigurations.cpp | 2 +- src/plugins/ios/iosprobe.cpp | 2 +- src/plugins/ios/iossimulator.cpp | 2 +- src/plugins/ios/simulatorcontrol.cpp | 4 +- .../languageclientinterface.cpp | 10 +- .../languageclient/languageclientinterface.h | 2 +- .../mcusupport/mcusupportversiondetection.cpp | 2 +- src/plugins/mercurial/mercurialclient.cpp | 4 +- .../mesonprojectmanager/mesonprocess.cpp | 8 +- .../mesonprojectmanager/mesonprocess.h | 4 +- .../mesonprojectmanager/mesonwrapper.h | 2 +- .../mesonprojectmanager/toolwrapper.cpp | 2 +- src/plugins/nim/project/nimblebuildsystem.cpp | 6 +- src/plugins/nim/project/nimtoolchain.cpp | 2 +- src/plugins/nim/suggest/server.cpp | 4 +- src/plugins/nim/suggest/server.h | 2 +- src/plugins/perforce/perforcechecker.cpp | 2 +- src/plugins/perforce/perforcechecker.h | 2 +- src/plugins/perforce/perforceplugin.cpp | 4 +- src/plugins/perfprofiler/perfconfigwidget.cpp | 4 +- src/plugins/perfprofiler/perfconfigwidget.h | 4 +- .../perfprofiler/perfprofilerruncontrol.cpp | 16 +- .../perfprofiler/perftracepointdialog.cpp | 4 +- .../perfprofiler/perftracepointdialog.h | 4 +- .../projectexplorer/abstractprocessstep.cpp | 14 +- .../projectexplorer/abstractprocessstep.h | 4 +- .../customwizardscriptgenerator.cpp | 2 +- .../devicesupport/desktopdevice.cpp | 4 +- .../devicesupport/devicemanager.cpp | 2 +- .../devicesupport/deviceusedportsgatherer.cpp | 6 +- .../projectexplorer/devicesupport/idevice.h | 2 +- .../devicesupport/sshparameters.cpp | 2 +- .../devicesupport/sshparameters.h | 4 +- src/plugins/projectexplorer/extracompiler.cpp | 2 +- src/plugins/projectexplorer/extracompiler.h | 4 +- src/plugins/projectexplorer/gcctoolchain.cpp | 4 +- src/plugins/projectexplorer/msvctoolchain.cpp | 10 +- src/plugins/projectexplorer/runcontrol.cpp | 10 +- src/plugins/python/pipsupport.cpp | 8 +- src/plugins/python/pipsupport.h | 2 +- src/plugins/python/pyside.cpp | 2 +- src/plugins/python/pysideuicextracompiler.cpp | 2 +- src/plugins/python/pysideuicextracompiler.h | 2 +- src/plugins/python/pythonlanguageclient.cpp | 4 +- src/plugins/python/pythonsettings.cpp | 2 +- src/plugins/python/pythonutils.cpp | 10 +- .../qbsprojectmanager/qbsprofilemanager.cpp | 2 +- src/plugins/qbsprojectmanager/qbssession.cpp | 10 +- src/plugins/qbsprojectmanager/qbssettings.cpp | 2 +- .../qmakeprojectmanager/qmakeproject.cpp | 8 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 8 +- .../assetslibrary/assetslibrarywidget.h | 2 +- .../componentcore/modelnodeoperations.cpp | 4 +- .../designercore/include/nodeinstanceview.h | 4 +- .../instances/nodeinstanceview.cpp | 6 +- src/plugins/qmldesigner/generateresource.cpp | 2 +- .../qmlprojectmanager/qmlprojectplugin.cpp | 4 +- .../qnx/qnxdeployqtlibrariesdialog.cpp | 14 +- src/plugins/qnx/qnxdevicetester.cpp | 6 +- src/plugins/qnx/qnxutils.cpp | 2 +- src/plugins/qnx/slog2inforunner.cpp | 18 +- src/plugins/qtsupport/baseqtversion.cpp | 2 +- src/plugins/qtsupport/externaleditors.cpp | 2 +- src/plugins/qtsupport/qscxmlcgenerator.cpp | 2 +- src/plugins/qtsupport/qscxmlcgenerator.h | 2 +- src/plugins/qtsupport/qtsupportplugin.cpp | 2 +- src/plugins/qtsupport/qtversionmanager.cpp | 2 +- src/plugins/qtsupport/uicgenerator.cpp | 2 +- src/plugins/qtsupport/uicgenerator.h | 2 +- .../remotelinux/customcommanddeploystep.cpp | 12 +- .../remotelinux/filesystemaccess_test.cpp | 2 +- .../remotelinux/genericdirectuploadstep.cpp | 14 +- src/plugins/remotelinux/linuxdevice.cpp | 38 ++-- src/plugins/remotelinux/linuxdevicetester.cpp | 18 +- .../remotelinux/publickeydeploymentdialog.cpp | 4 +- .../remotelinuxsignaloperation.cpp | 4 +- .../remotelinux/remotelinuxsignaloperation.h | 2 +- src/plugins/remotelinux/rsyncdeploystep.cpp | 6 +- .../remotelinux/sshkeycreationdialog.cpp | 2 +- .../remotelinux/tarpackagedeploystep.cpp | 12 +- .../findinfilessilversearcher.cpp | 4 +- src/plugins/squish/objectsmapdocument.cpp | 4 +- src/plugins/squish/squishprocessbase.cpp | 4 +- src/plugins/squish/squishprocessbase.h | 2 +- src/plugins/squish/squishserverprocess.cpp | 4 +- src/plugins/squish/squishtools.cpp | 4 +- src/plugins/subversion/subversionclient.cpp | 10 +- src/plugins/terminal/shellintegration.cpp | 2 +- src/plugins/terminal/shellintegration.h | 2 +- src/plugins/terminal/terminalwidget.cpp | 8 +- src/plugins/terminal/terminalwidget.h | 2 +- src/plugins/texteditor/formattexteditor.cpp | 4 +- src/plugins/updateinfo/updateinfoplugin.cpp | 12 +- src/plugins/valgrind/callgrindengine.cpp | 4 +- src/plugins/valgrind/callgrindengine.h | 2 +- src/plugins/valgrind/callgrindtool.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 6 +- src/plugins/valgrind/valgrindrunner.cpp | 10 +- src/plugins/vcsbase/vcsbaseclient.cpp | 2 +- src/plugins/vcsbase/vcsbaseclient.h | 4 +- .../vcsbase/vcsbasediffeditorcontroller.cpp | 2 +- .../vcsbase/vcsbasediffeditorcontroller.h | 4 +- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 2 +- src/plugins/vcsbase/vcscommand.cpp | 26 +-- src/plugins/vcsbase/vcscommand.h | 4 +- src/plugins/webassembly/webassemblyemsdk.cpp | 4 +- .../webassemblyrunconfigurationaspects.cpp | 2 +- .../utils/commandline/tst_commandline.cpp | 2 +- .../utils/deviceshell/tst_deviceshell.cpp | 4 +- .../processtestapp/processtestapp.cpp | 8 +- .../processtestapp/processtestapp.h | 4 +- .../auto/utils/qtcprocess/tst_qtcprocess.cpp | 58 ++--- tests/manual/deviceshell/tst_deviceshell.cpp | 2 +- 244 files changed, 769 insertions(+), 769 deletions(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 6ca6ef114c5..c22cdfdca0a 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -401,7 +401,7 @@ QString PluginManager::systemInformation() QString result; CommandLine qtDiag(FilePath::fromString(QLibraryInfo::location(QLibraryInfo::BinariesPath)) .pathAppended("qtdiag").withExecutableSuffix()); - QtcProcess qtDiagProc; + Process qtDiagProc; qtDiagProc.setCommand(qtDiag); qtDiagProc.runBlocking(); if (qtDiagProc.result() == ProcessResult::FinishedWithSuccess) diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index 3de270923b2..b5669057359 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -203,7 +203,7 @@ static void printParseWarnings(const FilePath &libraryPath, const QString &warni "%2").arg(libraryPath.toUserOutput(), warning)); } -static QString qmlPluginDumpErrorMessage(QtcProcess *process) +static QString qmlPluginDumpErrorMessage(Process *process) { QString errorMessage; const QString binary = process->commandLine().executable().toUserOutput(); @@ -237,7 +237,7 @@ static QString qmlPluginDumpErrorMessage(QtcProcess *process) return errorMessage; } -void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process) +void PluginDumper::qmlPluginTypeDumpDone(Process *process) { process->deleteLater(); @@ -597,11 +597,11 @@ void PluginDumper::loadQmltypesFile(const FilePaths &qmltypesFilePaths, void PluginDumper::runQmlDump(const ModelManagerInterface::ProjectInfo &info, const QStringList &arguments, const FilePath &importPath) { - auto process = new QtcProcess(this); + auto process = new Process(this); process->setEnvironment(info.qmlDumpEnvironment); process->setWorkingDirectory(importPath); process->setCommand({info.qmlDumpPath, arguments}); - connect(process, &QtcProcess::done, this, [this, process] { qmlPluginTypeDumpDone(process); }); + connect(process, &Process::done, this, [this, process] { qmlPluginTypeDumpDone(process); }); process->start(); m_runningQmldumps.insert(process, importPath); } diff --git a/src/libs/qmljs/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h index 1b672cefdc3..e27bfeba968 100644 --- a/src/libs/qmljs/qmljsplugindumper.h +++ b/src/libs/qmljs/qmljsplugindumper.h @@ -14,7 +14,7 @@ QT_END_NAMESPACE namespace Utils { class FileSystemWatcher; -class QtcProcess; +class Process; } namespace QmlJS { @@ -41,7 +41,7 @@ private: const QString &importUri, const QString &importVersion); Q_INVOKABLE void dumpAllPlugins(); - void qmlPluginTypeDumpDone(Utils::QtcProcess *process); + void qmlPluginTypeDumpDone(Utils::Process *process); void pluginChanged(const QString &pluginLibrary); private: @@ -102,7 +102,7 @@ private: ModelManagerInterface *m_modelManager; Utils::FileSystemWatcher *m_pluginWatcher; - QHash m_runningQmldumps; + QHash m_runningQmldumps; QList m_plugins; QHash m_libraryToPluginIndex; QHash m_qtToInfo; diff --git a/src/libs/utils/archive.cpp b/src/libs/utils/archive.cpp index 408c75d7c58..db541293e39 100644 --- a/src/libs/utils/archive.cpp +++ b/src/libs/utils/archive.cpp @@ -160,12 +160,12 @@ void Archive::unarchive() m_workingDirectory.ensureWritableDir(); - m_process.reset(new QtcProcess); + m_process.reset(new Process); m_process->setProcessChannelMode(QProcess::MergedChannels); - QObject::connect(m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this] { + QObject::connect(m_process.get(), &Process::readyReadStandardOutput, this, [this] { emit outputReceived(m_process->readAllStandardOutput()); }); - QObject::connect(m_process.get(), &QtcProcess::done, this, [this] { + QObject::connect(m_process.get(), &Process::done, this, [this] { const bool successfulFinish = m_process->result() == ProcessResult::FinishedWithSuccess; if (!successfulFinish) emit outputReceived(Tr::tr("Command failed.")); diff --git a/src/libs/utils/archive.h b/src/libs/utils/archive.h index 30f58585e3a..ccf62d3885c 100644 --- a/src/libs/utils/archive.h +++ b/src/libs/utils/archive.h @@ -12,7 +12,7 @@ namespace Utils { class FilePath; -class QtcProcess; +class Process; class QTCREATOR_UTILS_EXPORT Archive : public QObject { @@ -33,7 +33,7 @@ signals: private: CommandLine m_commandLine; FilePath m_workingDirectory; - std::unique_ptr m_process; + std::unique_ptr m_process; }; } // namespace Utils diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index eac24cfdba2..f4cb50b454f 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -21,7 +21,7 @@ bool BuildableHelperLibrary::isQtChooser(const FilePath &filePath) FilePath BuildableHelperLibrary::qtChooserToQmakePath(const FilePath &qtChooser) { const QString toolDir = QLatin1String("QTTOOLDIR=\""); - QtcProcess proc; + Process proc; proc.setTimeoutS(1); proc.setCommand({qtChooser, {"-print-env"}}); proc.runBlocking(); @@ -103,7 +103,7 @@ QString BuildableHelperLibrary::qtVersionForQMake(const FilePath &qmakePath) if (qmakePath.isEmpty()) return QString(); - QtcProcess qmake; + Process qmake; qmake.setTimeoutS(5); qmake.setCommand({qmakePath, {"--version"}}); qmake.runBlocking(); diff --git a/src/libs/utils/clangutils.cpp b/src/libs/utils/clangutils.cpp index ee4868f94b3..4c8c7d801db 100644 --- a/src/libs/utils/clangutils.cpp +++ b/src/libs/utils/clangutils.cpp @@ -13,7 +13,7 @@ namespace Utils { static QVersionNumber getClangdVersion(const FilePath &clangdFilePath) { - QtcProcess clangdProc; + Process clangdProc; clangdProc.setCommand({clangdFilePath, {"--version"}}); clangdProc.runBlocking(); if (clangdProc.result() != ProcessResult::FinishedWithSuccess) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 76f90efb69c..6b07fbdeb45 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -220,13 +220,13 @@ expected_str DeviceFileAccess::copyRecursively(const FilePath &src, if (isSrcOrTargetQrc || !targetTar.isExecutableFile() || !sourceTar.isExecutableFile()) return copyRecursively_fallback(src, target); - QtcProcess srcProcess; - QtcProcess targetProcess; + Process srcProcess; + Process targetProcess; targetProcess.setProcessMode(ProcessMode::Writer); QObject::connect(&srcProcess, - &QtcProcess::readyReadStandardOutput, + &Process::readyReadStandardOutput, &targetProcess, [&srcProcess, &targetProcess]() { targetProcess.writeRaw(srcProcess.readAllRawStandardOutput()); @@ -960,7 +960,7 @@ expected_str UnixDeviceFileAccess::fileContents(const FilePath &file #ifndef UTILS_STATIC_LIBRARY const FilePath dd = filePath.withNewPath("dd"); - QtcProcess p; + Process p; p.setCommand({dd, args, OsType::OsTypeLinux}); p.runBlocking(); if (p.exitCode() != 0) { diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp index 35b2a9ad82d..0641c10c381 100644 --- a/src/libs/utils/deviceshell.cpp +++ b/src/libs/utils/deviceshell.cpp @@ -81,7 +81,7 @@ RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData) useProcess |= stdInData.size() > (1024 * 100); if (useProcess) { - QtcProcess proc; + Process proc; const CommandLine fallbackCmd = createFallbackCommand(cmd); qCDebug(deviceShellLog) << "Running fallback:" << fallbackCmd; proc.setCommand(fallbackCmd); @@ -136,7 +136,7 @@ void DeviceShell::close() * Override this function to setup the shell process. * The default implementation just sets the command line to "bash" */ -void DeviceShell::setupShellProcess(QtcProcess *shellProcess) +void DeviceShell::setupShellProcess(Process *shellProcess) { shellProcess->setCommand(CommandLine{"bash"}); } @@ -171,8 +171,8 @@ void DeviceShell::startupFailed(const CommandLine &cmdLine) */ bool DeviceShell::start() { - m_shellProcess = std::make_unique(); - connect(m_shellProcess.get(), &QtcProcess::done, m_shellProcess.get(), + m_shellProcess = std::make_unique(); + connect(m_shellProcess.get(), &Process::done, m_shellProcess.get(), [this] { emit done(m_shellProcess->resultData()); }); connect(&m_thread, &QThread::finished, m_shellProcess.get(), [this] { closeShellProcess(); }, Qt::DirectConnection); @@ -199,11 +199,11 @@ bool DeviceShell::start() if (installShellScript()) { connect(m_shellProcess.get(), - &QtcProcess::readyReadStandardOutput, + &Process::readyReadStandardOutput, m_shellProcess.get(), [this] { onReadyRead(); }); connect(m_shellProcess.get(), - &QtcProcess::readyReadStandardError, + &Process::readyReadStandardError, m_shellProcess.get(), [this] { const QByteArray stdErr = m_shellProcess->readAllRawStandardError(); @@ -216,7 +216,7 @@ bool DeviceShell::start() return false; } - connect(m_shellProcess.get(), &QtcProcess::done, m_shellProcess.get(), [this] { + connect(m_shellProcess.get(), &Process::done, m_shellProcess.get(), [this] { if (m_shellProcess->resultData().m_exitCode != EXIT_SUCCESS || m_shellProcess->resultData().m_exitStatus != QProcess::NormalExit) { qCWarning(deviceShellLog) << "Shell exited with error code:" diff --git a/src/libs/utils/deviceshell.h b/src/libs/utils/deviceshell.h index 83af1db365e..052aac1838a 100644 --- a/src/libs/utils/deviceshell.h +++ b/src/libs/utils/deviceshell.h @@ -19,7 +19,7 @@ namespace Utils { class CommandLine; class ProcessResultData; -class QtcProcess; +class Process; class DeviceShellImpl; @@ -57,7 +57,7 @@ protected: void close(); private: - virtual void setupShellProcess(QtcProcess *shellProcess); + virtual void setupShellProcess(Process *shellProcess); virtual CommandLine createFallbackCommand(const CommandLine &cmdLine); bool installShellScript(); @@ -73,7 +73,7 @@ private: QWaitCondition *waiter; }; - std::unique_ptr m_shellProcess; + std::unique_ptr m_shellProcess; QThread m_thread; int m_currentId{0}; diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 744f682617c..e4dea9887da 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -84,12 +84,12 @@ signals: private: TaskItem remoteTask() final { - const auto setup = [this](QtcProcess &process) { + const auto setup = [this](Process &process) { const QStringList args = {"if=" + m_filePath.path()}; const FilePath dd = m_filePath.withNewPath("dd"); process.setCommand({dd, args, OsType::OsTypeLinux}); - QtcProcess *processPtr = &process; - connect(processPtr, &QtcProcess::readyReadStandardOutput, this, [this, processPtr] { + Process *processPtr = &process; + connect(processPtr, &Process::readyReadStandardOutput, this, [this, processPtr] { emit readyRead(processPtr->readAllRawStandardOutput()); }); }; @@ -246,11 +246,11 @@ signals: private: TaskItem remoteTask() final { - const auto setup = [this](QtcProcess &process) { + const auto setup = [this](Process &process) { m_writeBuffer = new WriteBuffer(false, &process); - connect(m_writeBuffer, &WriteBuffer::writeRequested, &process, &QtcProcess::writeRaw); + connect(m_writeBuffer, &WriteBuffer::writeRequested, &process, &Process::writeRaw); connect(m_writeBuffer, &WriteBuffer::closeWriteChannelRequested, - &process, &QtcProcess::closeWriteChannel); + &process, &Process::closeWriteChannel); const QStringList args = {"of=" + m_filePath.path()}; const FilePath dd = m_filePath.withNewPath("dd"); process.setCommand({dd, args, OsType::OsTypeLinux}); @@ -258,9 +258,9 @@ private: process.setProcessMode(ProcessMode::Writer); else process.setWriteData(m_writeData); - connect(&process, &QtcProcess::started, this, [this] { emit started(); }); + connect(&process, &Process::started, this, [this] { emit started(); }); }; - const auto finalize = [this](const QtcProcess &) { + const auto finalize = [this](const Process &) { delete m_writeBuffer; m_writeBuffer = nullptr; }; @@ -311,7 +311,7 @@ static Group sameRemoteDeviceTransferTask(const FilePath &source, const FilePath QTC_CHECK(destination.needsDevice()); QTC_CHECK(source.isSameDevice(destination)); - const auto setup = [source, destination](QtcProcess &process) { + const auto setup = [source, destination](Process &process) { const QStringList args = {source.path(), destination.path()}; const FilePath cp = source.withNewPath("cp"); process.setCommand({cp, args, OsType::OsTypeLinux}); diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 124fdc4cef4..0c43e8f5273 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -130,7 +130,7 @@ QString BinaryVersionToolTipEventFilter::toolVersion(const CommandLine &cmd) { if (cmd.executable().isEmpty()) return QString(); - QtcProcess proc; + Process proc; proc.setTimeoutS(1); proc.setCommand(cmd); proc.runBlocking(); diff --git a/src/libs/utils/processinfo.cpp b/src/libs/utils/processinfo.cpp index d6ecd4d2344..dc41a8f63ea 100644 --- a/src/libs/utils/processinfo.cpp +++ b/src/libs/utils/processinfo.cpp @@ -50,7 +50,7 @@ static QList getLocalProcessesUsingProc(const FilePath &procDir) cmd.addArgs(execs, CommandLine::Raw); - QtcProcess procProcess; + Process procProcess; procProcess.setCommand(cmd); procProcess.runBlocking(); @@ -83,7 +83,7 @@ static QList getLocalProcessesUsingProc(const FilePath &procDir) static QMap getLocalProcessDataUsingPs(const FilePath &deviceRoot, const QString &column) { - QtcProcess process; + Process process; process.setCommand({deviceRoot.withNewPath("ps"), {"-e", "-o", "pid," + column}}); process.runBlocking(); @@ -129,7 +129,7 @@ static QList getLocalProcessesUsingPs(const FilePath &deviceRoot) static QList getProcessesUsingPidin(const FilePath &pidin) { - QtcProcess process; + Process process; process.setCommand({pidin, {"-F", "%a %A {/%n}"}}); process.runBlocking(); diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index bd02428ef9b..e06076d60b8 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -142,7 +142,7 @@ private: virtual ProcessBlockingInterface *processBlockingInterface() const { return nullptr; } - friend class QtcProcess; + friend class Process; friend class Internal::QtcProcessPrivate; }; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 593c4456480..1fe97b3d2fd 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -717,7 +717,7 @@ private: class QtcProcessPrivate : public QObject { public: - explicit QtcProcessPrivate(QtcProcess *parent) + explicit QtcProcessPrivate(Process *parent) : QObject(parent) , q(parent) , m_killTimer(this) @@ -775,7 +775,7 @@ public: return rootCommand; } - QtcProcess *q; + Process *q; std::unique_ptr m_blockingInterface; std::unique_ptr m_process; ProcessSetupData m_setup; @@ -786,7 +786,7 @@ public: void handleDone(const ProcessResultData &data); void clearForRun(); - void emitGuardedSignal(void (QtcProcess::* signalName)()) { + void emitGuardedSignal(void (Process::* signalName)()) { GuardLocker locker(m_guard); emit (q->*signalName)(); } @@ -1092,7 +1092,7 @@ ProcessResult QtcProcessPrivate::interpretExitCode(int exitCode) \sa Utils::ProcessArgs */ -QtcProcess::QtcProcess(QObject *parent) +Process::Process(QObject *parent) : QObject(parent), d(new QtcProcessPrivate(this)) { @@ -1103,7 +1103,7 @@ QtcProcess::QtcProcess(QObject *parent) Q_UNUSED(qProcessProcessErrorMeta) } -QtcProcess::~QtcProcess() +Process::~Process() { QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting QtcProcess instance directly from " "one of its signal handlers will lead to crash!")); @@ -1112,62 +1112,62 @@ QtcProcess::~QtcProcess() delete d; } -void QtcProcess::setProcessImpl(ProcessImpl processImpl) +void Process::setProcessImpl(ProcessImpl processImpl) { d->m_setup.m_processImpl = processImpl; } -void QtcProcess::setPtyData(const std::optional &data) +void Process::setPtyData(const std::optional &data) { d->m_setup.m_ptyData = data; } -std::optional QtcProcess::ptyData() const +std::optional Process::ptyData() const { return d->m_setup.m_ptyData; } -ProcessMode QtcProcess::processMode() const +ProcessMode Process::processMode() const { return d->m_setup.m_processMode; } -void QtcProcess::setTerminalMode(TerminalMode mode) +void Process::setTerminalMode(TerminalMode mode) { d->m_setup.m_terminalMode = mode; } -TerminalMode QtcProcess::terminalMode() const +TerminalMode Process::terminalMode() const { return d->m_setup.m_terminalMode; } -void QtcProcess::setProcessMode(ProcessMode processMode) +void Process::setProcessMode(ProcessMode processMode) { d->m_setup.m_processMode = processMode; } -void QtcProcess::setEnvironment(const Environment &env) +void Process::setEnvironment(const Environment &env) { d->m_setup.m_environment = env; } -const Environment &QtcProcess::environment() const +const Environment &Process::environment() const { return d->m_setup.m_environment; } -void QtcProcess::setControlEnvironment(const Environment &environment) +void Process::setControlEnvironment(const Environment &environment) { d->m_setup.m_controlEnvironment = environment; } -const Environment &QtcProcess::controlEnvironment() const +const Environment &Process::controlEnvironment() const { return d->m_setup.m_controlEnvironment; } -void QtcProcess::setCommand(const CommandLine &cmdLine) +void Process::setCommand(const CommandLine &cmdLine) { if (d->m_setup.m_workingDirectory.needsDevice() && cmdLine.executable().needsDevice()) { QTC_CHECK(d->m_setup.m_workingDirectory.host() == cmdLine.executable().host()); @@ -1175,17 +1175,17 @@ void QtcProcess::setCommand(const CommandLine &cmdLine) d->m_setup.m_commandLine = cmdLine; } -const CommandLine &QtcProcess::commandLine() const +const CommandLine &Process::commandLine() const { return d->m_setup.m_commandLine; } -FilePath QtcProcess::workingDirectory() const +FilePath Process::workingDirectory() const { return d->m_setup.m_workingDirectory; } -void QtcProcess::setWorkingDirectory(const FilePath &dir) +void Process::setWorkingDirectory(const FilePath &dir) { if (dir.needsDevice() && d->m_setup.m_commandLine.executable().needsDevice()) { QTC_CHECK(dir.host() == d->m_setup.m_commandLine.executable().host()); @@ -1193,12 +1193,12 @@ void QtcProcess::setWorkingDirectory(const FilePath &dir) d->m_setup.m_workingDirectory = dir; } -void QtcProcess::setUseCtrlCStub(bool enabled) +void Process::setUseCtrlCStub(bool enabled) { d->m_setup.m_useCtrlCStub = enabled; } -void QtcProcess::start() +void Process::start() { QTC_ASSERT(state() == QProcess::NotRunning, return); QTC_ASSERT(!(d->m_process && d->m_guard.isLocked()), @@ -1217,36 +1217,36 @@ void QtcProcess::start() d->m_state = QProcess::Starting; d->m_process->m_setup = d->m_setup; d->m_process->m_setup.m_commandLine = d->fullCommandLine(); - d->emitGuardedSignal(&QtcProcess::starting); + d->emitGuardedSignal(&Process::starting); d->m_process->start(); } -void QtcProcess::terminate() +void Process::terminate() { d->sendControlSignal(ControlSignal::Terminate); } -void QtcProcess::kill() +void Process::kill() { d->sendControlSignal(ControlSignal::Kill); } -void QtcProcess::interrupt() +void Process::interrupt() { d->sendControlSignal(ControlSignal::Interrupt); } -void QtcProcess::kickoffProcess() +void Process::kickoffProcess() { d->sendControlSignal(ControlSignal::KickOff); } -void QtcProcess::closeWriteChannel() +void Process::closeWriteChannel() { d->sendControlSignal(ControlSignal::CloseWriteChannel); } -bool QtcProcess::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, qint64 *pid) +bool Process::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, qint64 *pid) { return QProcess::startDetached(cmd.executable().toUserOutput(), cmd.splitArguments(), @@ -1254,37 +1254,37 @@ bool QtcProcess::startDetached(const CommandLine &cmd, const FilePath &workingDi pid); } -void QtcProcess::setLowPriority() +void Process::setLowPriority() { d->m_setup.m_lowPriority = true; } -void QtcProcess::setDisableUnixTerminal() +void Process::setDisableUnixTerminal() { d->m_setup.m_unixTerminalDisabled = true; } -void QtcProcess::setAbortOnMetaChars(bool abort) +void Process::setAbortOnMetaChars(bool abort) { d->m_setup.m_abortOnMetaChars = abort; } -void QtcProcess::setRunAsRoot(bool on) +void Process::setRunAsRoot(bool on) { d->m_setup.m_runAsRoot = on; } -bool QtcProcess::isRunAsRoot() const +bool Process::isRunAsRoot() const { return d->m_setup.m_runAsRoot; } -void QtcProcess::setStandardInputFile(const QString &inputFile) +void Process::setStandardInputFile(const QString &inputFile) { d->m_setup.m_standardInputFile = inputFile; } -QString QtcProcess::toStandaloneCommandLine() const +QString Process::toStandaloneCommandLine() const { QStringList parts; parts.append("/usr/bin/env"); @@ -1303,47 +1303,47 @@ QString QtcProcess::toStandaloneCommandLine() const return parts.join(" "); } -void QtcProcess::setCreateConsoleOnWindows(bool create) +void Process::setCreateConsoleOnWindows(bool create) { d->m_setup.m_createConsoleOnWindows = create; } -bool QtcProcess::createConsoleOnWindows() const +bool Process::createConsoleOnWindows() const { return d->m_setup.m_createConsoleOnWindows; } -void QtcProcess::setExtraData(const QString &key, const QVariant &value) +void Process::setExtraData(const QString &key, const QVariant &value) { d->m_setup.m_extraData.insert(key, value); } -QVariant QtcProcess::extraData(const QString &key) const +QVariant Process::extraData(const QString &key) const { return d->m_setup.m_extraData.value(key); } -void QtcProcess::setExtraData(const QVariantHash &extraData) +void Process::setExtraData(const QVariantHash &extraData) { d->m_setup.m_extraData = extraData; } -QVariantHash QtcProcess::extraData() const +QVariantHash Process::extraData() const { return d->m_setup.m_extraData; } -void QtcProcess::setReaperTimeout(int msecs) +void Process::setReaperTimeout(int msecs) { d->m_setup.m_reaperTimeout = msecs; } -int QtcProcess::reaperTimeout() const +int Process::reaperTimeout() const { return d->m_setup.m_reaperTimeout; } -void QtcProcess::setRemoteProcessHooks(const DeviceProcessHooks &hooks) +void Process::setRemoteProcessHooks(const DeviceProcessHooks &hooks) { s_deviceHooks = hooks; } @@ -1378,7 +1378,7 @@ static bool askToKill(const CommandLine &command) // occurs on stderr/stdout as opposed to waitForFinished()). Returns false if a timeout // occurs. Checking of the process' exit state/code still has to be done. -bool QtcProcess::readDataFromProcess(QByteArray *stdOut, QByteArray *stdErr, int timeoutS) +bool Process::readDataFromProcess(QByteArray *stdOut, QByteArray *stdErr, int timeoutS) { enum { syncDebug = 0 }; if (syncDebug) @@ -1418,39 +1418,39 @@ bool QtcProcess::readDataFromProcess(QByteArray *stdOut, QByteArray *stdErr, int return finished; } -ProcessResult QtcProcess::result() const +ProcessResult Process::result() const { return d->m_result; } -ProcessResultData QtcProcess::resultData() const +ProcessResultData Process::resultData() const { return d->m_resultData; } -int QtcProcess::exitCode() const +int Process::exitCode() const { return resultData().m_exitCode; } -QProcess::ExitStatus QtcProcess::exitStatus() const +QProcess::ExitStatus Process::exitStatus() const { return resultData().m_exitStatus; } -QProcess::ProcessError QtcProcess::error() const +QProcess::ProcessError Process::error() const { return resultData().m_error; } -QString QtcProcess::errorString() const +QString Process::errorString() const { return resultData().m_errorString; } // Path utilities -Environment QtcProcess::systemEnvironmentForBinary(const FilePath &filePath) +Environment Process::systemEnvironmentForBinary(const FilePath &filePath) { if (filePath.needsDevice()) { QTC_ASSERT(s_deviceHooks.systemEnvironmentForBinary, return {}); @@ -1460,37 +1460,37 @@ Environment QtcProcess::systemEnvironmentForBinary(const FilePath &filePath) return Environment::systemEnvironment(); } -qint64 QtcProcess::applicationMainThreadId() const +qint64 Process::applicationMainThreadId() const { return d->m_applicationMainThreadId; } -QProcess::ProcessChannelMode QtcProcess::processChannelMode() const +QProcess::ProcessChannelMode Process::processChannelMode() const { return d->m_setup.m_processChannelMode; } -void QtcProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode) +void Process::setProcessChannelMode(QProcess::ProcessChannelMode mode) { d->m_setup.m_processChannelMode = mode; } -QProcess::ProcessState QtcProcess::state() const +QProcess::ProcessState Process::state() const { return d->m_state; } -bool QtcProcess::isRunning() const +bool Process::isRunning() const { return state() == QProcess::Running; } -qint64 QtcProcess::processId() const +qint64 Process::processId() const { return d->m_processId; } -bool QtcProcess::waitForStarted(int msecs) +bool Process::waitForStarted(int msecs) { QTC_ASSERT(d->m_process, return false); if (d->m_state == QProcess::Running) @@ -1501,7 +1501,7 @@ bool QtcProcess::waitForStarted(int msecs) ProcessSignalType::Started, msecs); } -bool QtcProcess::waitForReadyRead(int msecs) +bool Process::waitForReadyRead(int msecs) { QTC_ASSERT(d->m_process, return false); if (d->m_state == QProcess::NotRunning) @@ -1509,7 +1509,7 @@ bool QtcProcess::waitForReadyRead(int msecs) return d->waitForSignal(ProcessSignalType::ReadyRead, msecs); } -bool QtcProcess::waitForFinished(int msecs) +bool Process::waitForFinished(int msecs) { QTC_ASSERT(d->m_process, return false); if (d->m_state == QProcess::NotRunning) @@ -1517,17 +1517,17 @@ bool QtcProcess::waitForFinished(int msecs) return d->waitForSignal(ProcessSignalType::Done, msecs); } -QByteArray QtcProcess::readAllRawStandardOutput() +QByteArray Process::readAllRawStandardOutput() { return d->m_stdOut.readAllData(); } -QByteArray QtcProcess::readAllRawStandardError() +QByteArray Process::readAllRawStandardError() { return d->m_stdErr.readAllData(); } -qint64 QtcProcess::write(const QString &input) +qint64 Process::write(const QString &input) { // Non-windows is assumed to be UTF-8 if (commandLine().executable().osType() != OsTypeWindows) @@ -1542,7 +1542,7 @@ qint64 QtcProcess::write(const QString &input) return writeRaw(input.toUtf8()); } -qint64 QtcProcess::writeRaw(const QByteArray &input) +qint64 Process::writeRaw(const QByteArray &input) { QTC_ASSERT(processMode() == ProcessMode::Writer, return -1); QTC_ASSERT(d->m_process, return -1); @@ -1555,7 +1555,7 @@ qint64 QtcProcess::writeRaw(const QByteArray &input) return result; } -void QtcProcess::close() +void Process::close() { QTC_ASSERT(QThread::currentThread() == thread(), return); if (d->m_process) { @@ -1575,7 +1575,7 @@ void QtcProcess::close() Calls terminate() directly and after a delay of reaperTimeout() it calls kill() if the process is still running. */ -void QtcProcess::stop() +void Process::stop() { if (state() == QProcess::NotRunning) return; @@ -1584,12 +1584,12 @@ void QtcProcess::stop() d->m_killTimer.start(d->m_process->m_setup.m_reaperTimeout); } -QString QtcProcess::readAllStandardOutput() +QString Process::readAllStandardOutput() { return QString::fromUtf8(readAllRawStandardOutput()); } -QString QtcProcess::readAllStandardError() +QString Process::readAllStandardError() { return QString::fromUtf8(readAllRawStandardError()); } @@ -1624,7 +1624,7 @@ QString QtcProcess::readAllStandardError() as this will cause event loop problems. */ -QString QtcProcess::exitMessage() const +QString Process::exitMessage() const { const QString fullCmd = commandLine().toUserOutput(); switch (result()) { @@ -1644,7 +1644,7 @@ QString QtcProcess::exitMessage() const return {}; } -QByteArray QtcProcess::allRawOutput() const +QByteArray Process::allRawOutput() const { QTC_CHECK(d->m_stdOut.keepRawData); QTC_CHECK(d->m_stdErr.keepRawData); @@ -1658,7 +1658,7 @@ QByteArray QtcProcess::allRawOutput() const return !d->m_stdOut.rawData.isEmpty() ? d->m_stdOut.rawData : d->m_stdErr.rawData; } -QString QtcProcess::allOutput() const +QString Process::allOutput() const { QTC_CHECK(d->m_stdOut.keepRawData); QTC_CHECK(d->m_stdErr.keepRawData); @@ -1675,30 +1675,30 @@ QString QtcProcess::allOutput() const return !out.isEmpty() ? out : err; } -QByteArray QtcProcess::rawStdOut() const +QByteArray Process::rawStdOut() const { QTC_CHECK(d->m_stdOut.keepRawData); return d->m_stdOut.rawData; } -QString QtcProcess::stdOut() const +QString Process::stdOut() const { QTC_CHECK(d->m_stdOut.keepRawData); return d->m_codec->toUnicode(d->m_stdOut.rawData); } -QString QtcProcess::stdErr() const +QString Process::stdErr() const { QTC_CHECK(d->m_stdErr.keepRawData); return d->m_codec->toUnicode(d->m_stdErr.rawData); } -QString QtcProcess::cleanedStdOut() const +QString Process::cleanedStdOut() const { return Utils::normalizeNewlines(stdOut()); } -QString QtcProcess::cleanedStdErr() const +QString Process::cleanedStdErr() const { return Utils::normalizeNewlines(stdErr()); } @@ -1713,17 +1713,17 @@ static QStringList splitLines(const QString &text) return result; } -const QStringList QtcProcess::stdOutLines() const +const QStringList Process::stdOutLines() const { return splitLines(cleanedStdOut()); } -const QStringList QtcProcess::stdErrLines() const +const QStringList Process::stdErrLines() const { return splitLines(cleanedStdErr()); } -QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r) +QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const Process &r) { QDebug nsp = str.nospace(); nsp << "QtcProcess: result=" @@ -1802,7 +1802,7 @@ void ChannelBuffer::handleRest() } } -void QtcProcess::setTimeoutS(int timeoutS) +void Process::setTimeoutS(int timeoutS) { if (timeoutS > 0) d->m_maxHangTimerCount = qMax(2, timeoutS); @@ -1810,33 +1810,33 @@ void QtcProcess::setTimeoutS(int timeoutS) d->m_maxHangTimerCount = INT_MAX / 1000; } -int QtcProcess::timeoutS() const +int Process::timeoutS() const { return d->m_maxHangTimerCount; } -void QtcProcess::setCodec(QTextCodec *c) +void Process::setCodec(QTextCodec *c) { QTC_ASSERT(c, return); d->m_codec = c; } -void QtcProcess::setTimeOutMessageBoxEnabled(bool v) +void Process::setTimeOutMessageBoxEnabled(bool v) { d->m_timeOutMessageBoxEnabled = v; } -void QtcProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter) +void Process::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter) { d->m_exitCodeInterpreter = interpreter; } -void QtcProcess::setWriteData(const QByteArray &writeData) +void Process::setWriteData(const QByteArray &writeData) { d->m_setup.m_writeData = writeData; } -void QtcProcess::runBlocking(EventLoopMode eventLoopMode) +void Process::runBlocking(EventLoopMode eventLoopMode) { // Attach a dynamic property with info about blocking type d->storeEventLoopDebugInfo(int(eventLoopMode)); @@ -1845,7 +1845,7 @@ void QtcProcess::runBlocking(EventLoopMode eventLoopMode) static const int blockingThresholdMs = qtcEnvironmentVariableIntValue("QTC_PROCESS_THRESHOLD"); if (blockingThresholdMs > 0 && isMainThread()) startTime = QDateTime::currentDateTime(); - QtcProcess::start(); + Process::start(); // Remove the dynamic property so that it's not reused in subseqent start() d->storeEventLoopDebugInfo({}); @@ -1897,33 +1897,33 @@ void QtcProcess::runBlocking(EventLoopMode eventLoopMode) } } -void QtcProcess::setStdOutCallback(const TextChannelCallback &callback) +void Process::setStdOutCallback(const TextChannelCallback &callback) { d->m_stdOut.outputCallback = callback; d->m_stdOut.emitSingleLines = false; } -void QtcProcess::setStdOutLineCallback(const TextChannelCallback &callback) +void Process::setStdOutLineCallback(const TextChannelCallback &callback) { d->m_stdOut.outputCallback = callback; d->m_stdOut.emitSingleLines = true; d->m_stdOut.keepRawData = false; } -void QtcProcess::setStdErrCallback(const TextChannelCallback &callback) +void Process::setStdErrCallback(const TextChannelCallback &callback) { d->m_stdErr.outputCallback = callback; d->m_stdErr.emitSingleLines = false; } -void QtcProcess::setStdErrLineCallback(const TextChannelCallback &callback) +void Process::setStdErrLineCallback(const TextChannelCallback &callback) { d->m_stdErr.outputCallback = callback; d->m_stdErr.emitSingleLines = true; d->m_stdErr.keepRawData = false; } -void QtcProcess::setTextChannelMode(Channel channel, TextChannelMode mode) +void Process::setTextChannelMode(Channel channel, TextChannelMode mode) { const TextChannelCallback outputCb = [this](const QString &text) { GuardLocker locker(d->m_guard); @@ -1959,7 +1959,7 @@ void QtcProcess::setTextChannelMode(Channel channel, TextChannelMode mode) } } -TextChannelMode QtcProcess::textChannelMode(Channel channel) const +TextChannelMode Process::textChannelMode(Channel channel) const { ChannelBuffer *buffer = channel == Channel::Output ? &d->m_stdOut : &d->m_stdErr; return buffer->m_textChannelMode; @@ -1993,7 +1993,7 @@ void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainTh m_processId = processId; m_applicationMainThreadId = applicationMainThreadId; - emitGuardedSignal(&QtcProcess::started); + emitGuardedSignal(&Process::started); } void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByteArray &errorData) @@ -2011,7 +2011,7 @@ void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByt std::cout << outputData.constData() << std::flush; } else { m_stdOut.append(outputData); - emitGuardedSignal(&QtcProcess::readyReadStandardOutput); + emitGuardedSignal(&Process::readyReadStandardOutput); } } if (!errorData.isEmpty()) { @@ -2020,7 +2020,7 @@ void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByt std::cerr << errorData.constData() << std::flush; } else { m_stdErr.append(errorData); - emitGuardedSignal(&QtcProcess::readyReadStandardError); + emitGuardedSignal(&Process::readyReadStandardError); } } } @@ -2077,7 +2077,7 @@ void QtcProcessPrivate::handleDone(const ProcessResultData &data) m_stdOut.handleRest(); m_stdErr.handleRest(); - emitGuardedSignal(&QtcProcess::done); + emitGuardedSignal(&Process::done); m_processId = 0; m_applicationMainThreadId = 0; } @@ -2101,7 +2101,7 @@ void QtcProcessPrivate::setupDebugLog() return duration_cast(system_clock::now().time_since_epoch()).count(); }; - connect(q, &QtcProcess::starting, this, [=] { + connect(q, &Process::starting, this, [=] { const quint64 msNow = now(); setProperty(QTC_PROCESS_STARTTIME, msNow); @@ -2114,7 +2114,7 @@ void QtcProcessPrivate::setupDebugLog() setProperty(QTC_PROCESS_NUMBER, currentNumber); }); - connect(q, &QtcProcess::done, this, [=] { + connect(q, &Process::done, this, [=] { if (!m_process.get()) return; const QVariant n = property(QTC_PROCESS_NUMBER); @@ -2148,7 +2148,7 @@ void QtcProcessPrivate::storeEventLoopDebugInfo(const QVariant &value) ProcessTaskAdapter::ProcessTaskAdapter() { - connect(task(), &QtcProcess::done, this, [this] { + connect(task(), &Process::done, this, [this] { emit done(task()->result() == ProcessResult::FinishedWithSuccess); }); } diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 5e39453e38f..f89b6f9b22e 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -28,13 +28,13 @@ class DeviceProcessHooks; class ProcessInterface; class ProcessResultData; -class QTCREATOR_UTILS_EXPORT QtcProcess final : public QObject +class QTCREATOR_UTILS_EXPORT Process final : public QObject { Q_OBJECT public: - explicit QtcProcess(QObject *parent = nullptr); - ~QtcProcess(); + explicit Process(QObject *parent = nullptr); + ~Process(); // ProcessInterface related @@ -194,7 +194,7 @@ signals: void textOnStandardError(const QString &text); private: - friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r); + friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const Process &r); friend class Internal::QtcProcessPrivate; Internal::QtcProcessPrivate *d = nullptr; @@ -207,7 +207,7 @@ public: std::function systemEnvironmentForBinary; }; -class QTCREATOR_UTILS_EXPORT ProcessTaskAdapter : public Tasking::TaskAdapter +class QTCREATOR_UTILS_EXPORT ProcessTaskAdapter : public Tasking::TaskAdapter { public: ProcessTaskAdapter(); diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index d8e53010c30..c7cab040289 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -45,7 +45,7 @@ class ExternalTerminalProcessImpl final : public TerminalInterface if (HostOsInfo::isWindowsHost()) { m_terminalProcess.setCommand(cmd); - QObject::connect(&m_terminalProcess, &QtcProcess::done, this, [this] { + QObject::connect(&m_terminalProcess, &Process::done, this, [this] { m_interface->onStubExited(); }); m_terminalProcess.setCreateConsoleOnWindows(true); @@ -82,7 +82,7 @@ class ExternalTerminalProcessImpl final : public TerminalInterface } ExternalTerminalProcessImpl *m_interface; - QtcProcess m_terminalProcess; + Process m_terminalProcess; }; public: diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index 8637fb6465d..a5f71a95cdc 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -37,7 +37,7 @@ static Q_LOGGING_CATEGORY(avdManagerLog, "qtc.android.avdManager", QtWarningMsg) bool AndroidAvdManager::avdManagerCommand(const AndroidConfig &config, const QStringList &args, QString *output) { CommandLine cmd(config.avdManagerToolPath(), args); - QtcProcess proc; + Process proc; Environment env = AndroidConfigurations::toolsEnvironment(config); proc.setEnvironment(env); qCDebug(avdManagerLog).noquote() << "Running AVD Manager command:" << cmd.toUserOutput(); @@ -85,7 +85,7 @@ static CreateAvdInfo createAvdCommand(const AndroidConfig &config, const CreateA avdManager.addArg("-f"); qCDebug(avdManagerLog).noquote() << "Running AVD Manager command:" << avdManager.toUserOutput(); - QtcProcess proc; + Process proc; proc.setProcessMode(ProcessMode::Writer); proc.setEnvironment(AndroidConfigurations::toolsEnvironment(config)); proc.setCommand(avdManager); @@ -146,7 +146,7 @@ bool AndroidAvdManager::removeAvd(const QString &name) const { const CommandLine command(m_config.avdManagerToolPath(), {"delete", "avd", "-n", name}); qCDebug(avdManagerLog).noquote() << "Running command (removeAvd):" << command.toUserOutput(); - QtcProcess proc; + Process proc; proc.setTimeoutS(5); proc.setEnvironment(AndroidConfigurations::toolsEnvironment(m_config)); proc.setCommand(command); @@ -232,7 +232,7 @@ static bool is32BitUserSpace() // Do a similar check as android's emulator is doing: if (HostOsInfo::isLinuxHost()) { if (QSysInfo::WordSize == 32) { - QtcProcess proc; + Process proc; proc.setTimeoutS(3); proc.setCommand({"getconf", {"LONG_BIT"}}); proc.runBlocking(); @@ -262,9 +262,9 @@ bool AndroidAvdManager::startAvdAsync(const QString &avdName) const // after the avdProcess has started and before it has finished. Giving a parent object here // should solve the issue. However, AndroidAvdManager is not a QObject, so no clue what parent // would be the most appropriate. Preferably some object taken form android plugin... - QtcProcess *avdProcess = new QtcProcess; + Process *avdProcess = new Process; avdProcess->setProcessChannelMode(QProcess::MergedChannels); - QObject::connect(avdProcess, &QtcProcess::done, avdProcess, [avdProcess] { + QObject::connect(avdProcess, &Process::done, avdProcess, [avdProcess] { if (avdProcess->exitCode()) { const QString errorOutput = QString::fromLatin1(avdProcess->readAllRawStandardOutput()); QMetaObject::invokeMethod(Core::ICore::mainWindow(), [errorOutput] { @@ -324,7 +324,7 @@ bool AndroidAvdManager::isAvdBooted(const QString &device) const const CommandLine command({m_config.adbToolPath(), arguments}); qCDebug(avdManagerLog).noquote() << "Running command (isAvdBooted):" << command.toUserOutput(); - QtcProcess adbProc; + Process adbProc; adbProc.setTimeoutS(10); adbProc.setCommand(command); adbProc.runBlocking(); diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 25a7c4f6ec6..c79282e536b 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -1050,7 +1050,7 @@ QAbstractItemModel *AndroidBuildApkStep::keystoreCertificates() const QStringList params = {"-list", "-v", "-keystore", m_keystorePath.toUserOutput(), "-storepass", m_keystorePasswd, "-J-Duser.language=en"}; - QtcProcess keytoolProc; + Process keytoolProc; keytoolProc.setTimeoutS(30); keytoolProc.setCommand({AndroidConfigurations::currentConfig().keytoolPath(), params}); keytoolProc.runBlocking(EventLoopMode::On); diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 3c3b64062ec..eccfb2041e8 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -601,7 +601,7 @@ FilePath AndroidConfig::keytoolPath() const QVector AndroidConfig::connectedDevices(QString *error) const { QVector devices; - QtcProcess adbProc; + Process adbProc; adbProc.setTimeoutS(30); CommandLine cmd{adbToolPath(), {"devices"}}; adbProc.setCommand(cmd); @@ -670,7 +670,7 @@ QString AndroidConfig::getDeviceProperty(const QString &device, const QString &p AndroidDeviceInfo::adbSelector(device)); cmd.addArgs({"shell", "getprop", property}); - QtcProcess adbProc; + Process adbProc; adbProc.setTimeoutS(10); adbProc.setCommand(cmd); adbProc.runBlocking(); @@ -747,7 +747,7 @@ QStringList AndroidConfig::getAbis(const QString &device) // First try via ro.product.cpu.abilist QStringList arguments = AndroidDeviceInfo::adbSelector(device); arguments << "shell" << "getprop" << "ro.product.cpu.abilist"; - QtcProcess adbProc; + Process adbProc; adbProc.setTimeoutS(10); adbProc.setCommand({adbTool, arguments}); adbProc.runBlocking(); @@ -770,7 +770,7 @@ QStringList AndroidConfig::getAbis(const QString &device) else arguments << QString::fromLatin1("ro.product.cpu.abi%1").arg(i); - QtcProcess abiProc; + Process abiProc; abiProc.setTimeoutS(10); abiProc.setCommand({adbTool, arguments}); abiProc.runBlocking(); @@ -1530,7 +1530,7 @@ FilePath AndroidConfig::getJdkPath() args << "-c" << "readlink -f $(which java)"; - QtcProcess findJdkPathProc; + Process findJdkPathProc; findJdkPathProc.setCommand({"sh", args}); findJdkPathProc.start(); findJdkPathProc.waitForFinished(); diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp index e6537b8a27f..09858e36038 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/androidcreatekeystorecertificate.cpp @@ -272,7 +272,7 @@ void AndroidCreateKeystoreCertificate::buttonBoxAccepted() "-keypass", certificatePassword(), "-dname", distinguishedNames}); - QtcProcess genKeyCertProc; + Process genKeyCertProc; genKeyCertProc.setTimeoutS(15); genKeyCertProc.setCommand(command); genKeyCertProc.runBlocking(EventLoopMode::On); diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 9d288fc5a0a..2ba26ebc614 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -381,7 +381,7 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy() cmd.addArgs({"install", "-r", m_apkPath.toString()}); } - QtcProcess process; + Process process; process.setCommand(cmd); process.setWorkingDirectory(m_workingDirectory); process.setEnvironment(m_environment); @@ -576,7 +576,7 @@ void AndroidDeployQtStep::doCancel() void AndroidDeployQtStep::runCommand(const CommandLine &command) { - QtcProcess buildProc; + Process buildProc; buildProc.setTimeoutS(2 * 60); emit addOutput(Tr::tr("Package deploy: Running command \"%1\".").arg(command.toUserOutput()), OutputFormat::NormalMessage); diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 4d729c786e5..c1afae589bb 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -614,20 +614,20 @@ void AndroidDeviceManager::setupDevicesWatcher() } if (!m_adbDeviceWatcherProcess) - m_adbDeviceWatcherProcess.reset(new QtcProcess(this)); + m_adbDeviceWatcherProcess.reset(new Process(this)); if (m_adbDeviceWatcherProcess->isRunning()) { qCDebug(androidDeviceLog) << "ADB device watcher is already running."; return; } - connect(m_adbDeviceWatcherProcess.get(), &QtcProcess::done, this, [this] { + connect(m_adbDeviceWatcherProcess.get(), &Process::done, this, [this] { if (m_adbDeviceWatcherProcess->error() != QProcess::UnknownError) { qCDebug(androidDeviceLog) << "ADB device watcher encountered an error:" << m_adbDeviceWatcherProcess->errorString(); if (!m_adbDeviceWatcherProcess->isRunning()) { qCDebug(androidDeviceLog) << "Restarting the ADB device watcher now."; - QTimer::singleShot(0, m_adbDeviceWatcherProcess.get(), &QtcProcess::start); + QTimer::singleShot(0, m_adbDeviceWatcherProcess.get(), &Process::start); } } qCDebug(androidDeviceLog) << "ADB device watcher finished."; diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index 551d39b934d..cf8046cfa95 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -15,7 +15,7 @@ #include #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Android { namespace Internal { @@ -108,7 +108,7 @@ private: QFutureWatcher m_avdsFutureWatcher; QFutureWatcher> m_removeAvdFutureWatcher; QFileSystemWatcher m_avdFileSystemWatcher; - std::unique_ptr m_adbDeviceWatcherProcess; + std::unique_ptr m_adbDeviceWatcherProcess; AndroidConfig &m_androidConfig; AndroidAvdManager m_avdManager; diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 72a9e5c4799..495f031be45 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -612,7 +612,7 @@ bool AndroidManager::checkKeystorePassword(const FilePath &keystorePath, const CommandLine cmd(AndroidConfigurations::currentConfig().keytoolPath(), {"-list", "-keystore", keystorePath.toUserOutput(), "--storepass", keystorePasswd}); - QtcProcess proc; + Process proc; proc.setTimeoutS(10); proc.setCommand(cmd); proc.runBlocking(EventLoopMode::On); @@ -632,7 +632,7 @@ bool AndroidManager::checkCertificatePassword(const FilePath &keystorePath, else arguments << certificatePasswd; - QtcProcess proc; + Process proc; proc.setTimeoutS(10); proc.setCommand({AndroidConfigurations::currentConfig().keytoolPath(), arguments}); proc.runBlocking(EventLoopMode::On); @@ -646,7 +646,7 @@ bool AndroidManager::checkCertificateExists(const FilePath &keystorePath, QStringList arguments = { "-list", "-keystore", keystorePath.toUserOutput(), "--storepass", keystorePasswd, "-alias", alias }; - QtcProcess proc; + Process proc; proc.setTimeoutS(10); proc.setCommand({AndroidConfigurations::currentConfig().keytoolPath(), arguments}); proc.runBlocking(EventLoopMode::On); @@ -681,7 +681,7 @@ SdkToolResult AndroidManager::runCommand(const CommandLine &command, const QByteArray &writeData, int timeoutS) { Android::SdkToolResult cmdResult; - QtcProcess cmdProc; + Process cmdProc; cmdProc.setTimeoutS(timeoutS); cmdProc.setWriteData(writeData); qCDebug(androidManagerLog) << "Running command (sync):" << command.toUserOutput(); diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index 85a3b917d37..e489a1e1e7f 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -117,7 +117,7 @@ private: QStringList m_avdAbis; int m_viewerPid = -1; QFutureWatcher m_pidFutureWatcher; - Utils::QtcProcess m_logcatProcess; + Utils::Process m_logcatProcess; QString m_logcatStartTimeStamp; UploadInfo m_uploadInfo; }; @@ -226,7 +226,7 @@ AndroidQmlPreviewWorker::AndroidQmlPreviewWorker(RunControl *runControl) connect(this, &AndroidQmlPreviewWorker::previewPidChanged, this, &AndroidQmlPreviewWorker::startLogcat); - connect(this, &RunWorker::stopped, &m_logcatProcess, &QtcProcess::stop); + connect(this, &RunWorker::stopped, &m_logcatProcess, &Process::stop); m_logcatProcess.setStdOutCallback([this](const QString &stdOut) { filterLogcatAndAppendMessage(stdOut); }); @@ -376,7 +376,7 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder, { const QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(m_rc->kit()); const FilePath rccBinary = qtVersion->rccFilePath(); - QtcProcess rccProcess; + Process rccProcess; FilePath qrcPath = FilePath::fromString(basename + ".qrc4viewer"); const FilePath qmlrcPath = FilePath::fromString(QDir::tempPath()) / (basename + packageSuffix); diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index e2cae791030..0e5f6c6f807 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -98,7 +98,7 @@ static void findProcessPIDAndUser(QPromise &promise, chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now(); do { QThread::msleep(200); - QtcProcess proc; + Process proc; proc.setCommand({adbPath, args}); proc.runBlocking(); const QString out = proc.allOutput(); @@ -117,7 +117,7 @@ static void findProcessPIDAndUser(QPromise &promise, args = {selector}; args.append({"shell", "ps", "-o", "user", "-p"}); args.append(QString::number(processPID)); - QtcProcess proc; + Process proc; proc.setCommand({adbPath, args}); proc.runBlocking(); const QString out = proc.allOutput(); diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 7a16756f227..61354888fd5 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -93,7 +93,7 @@ static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &ar qCDebug(sdkManagerLog).noquote() << "Running SDK Manager command (sync):" << CommandLine(config.sdkManagerToolPath(), newArgs) .toUserOutput(); - QtcProcess proc; + Process proc; proc.setEnvironment(AndroidConfigurations::toolsEnvironment(config)); proc.setTimeoutS(timeout); proc.setTimeOutMessageBoxEnabled(true); @@ -121,7 +121,7 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar << CommandLine(config.sdkManagerToolPath(), newArgs) .toUserOutput(); int offset = promise.future().progressValue(); - QtcProcess proc; + Process proc; proc.setEnvironment(AndroidConfigurations::toolsEnvironment(config)); bool assertionFound = false; proc.setTimeoutS(timeout); @@ -521,7 +521,7 @@ void AndroidSdkManagerPrivate::getPendingLicense(SdkCmdPromise &fi) AndroidSdkManager::OperationOutput result; result.type = AndroidSdkManager::LicenseWorkflow; - QtcProcess licenseCommand; + Process licenseCommand; licenseCommand.setProcessMode(ProcessMode::Writer); licenseCommand.setEnvironment(AndroidConfigurations::toolsEnvironment(m_config)); bool reviewingLicenses = false; diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 21fe13ad8ba..62fed62a81d 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -659,7 +659,7 @@ void AndroidSettingsWidget::downloadOpenSslRepo(const bool silent) openSslProgressDialog->setFixedSize(openSslProgressDialog->sizeHint()); const QString openSslRepo("https://github.com/KDAB/android_openssl.git"); - QtcProcess *gitCloner = new QtcProcess(this); + Process *gitCloner = new Process(this); CommandLine gitCloneCommand("git", {"clone", "--depth=1", openSslRepo, openSslPath.toString()}); gitCloner->setCommand(gitCloneCommand); @@ -684,7 +684,7 @@ void AndroidSettingsWidget::downloadOpenSslRepo(const bool silent) openButton->deleteLater(); }; - connect(gitCloner, &QtcProcess::done, this, [=] { + connect(gitCloner, &Process::done, this, [=] { openSslProgressDialog->close(); if (gitCloner->error() != QProcess::UnknownError) { if (gitCloner->error() == QProcess::FailedToStart) { diff --git a/src/plugins/android/androidsignaloperation.cpp b/src/plugins/android/androidsignaloperation.cpp index 426b63c1441..a3fdfeeb835 100644 --- a/src/plugins/android/androidsignaloperation.cpp +++ b/src/plugins/android/androidsignaloperation.cpp @@ -90,8 +90,8 @@ void AndroidSignalOperation::startAdbProcess(State state, const Utils::CommandLi { m_state = state; m_timeout->start(); - m_adbProcess.reset(new QtcProcess); - connect(m_adbProcess.get(), &QtcProcess::done, this, handler); + m_adbProcess.reset(new Process); + connect(m_adbProcess.get(), &Process::done, this, handler); m_adbProcess->setCommand(commandLine); m_adbProcess->start(); } diff --git a/src/plugins/android/androidsignaloperation.h b/src/plugins/android/androidsignaloperation.h index 06a88b67057..1c3bb48454c 100644 --- a/src/plugins/android/androidsignaloperation.h +++ b/src/plugins/android/androidsignaloperation.h @@ -42,7 +42,7 @@ private: void startAdbProcess(State state, const Utils::CommandLine &commandLine, FinishHandler handler); Utils::FilePath m_adbPath; - std::unique_ptr m_adbProcess; + std::unique_ptr m_adbProcess; QTimer *m_timeout; State m_state = Idle; diff --git a/src/plugins/autotest/boost/boosttestconfiguration.cpp b/src/plugins/autotest/boost/boosttestconfiguration.cpp index d680699c36e..1df0bd6776b 100644 --- a/src/plugins/autotest/boost/boosttestconfiguration.cpp +++ b/src/plugins/autotest/boost/boosttestconfiguration.cpp @@ -17,7 +17,7 @@ using namespace Utils; namespace Autotest { namespace Internal { -TestOutputReader *BoostTestConfiguration::createOutputReader(QtcProcess *app) const +TestOutputReader *BoostTestConfiguration::createOutputReader(Process *app) const { auto settings = static_cast(framework()->testSettings()); return new BoostTestOutputReader(app, buildDirectory(), projectFile(), diff --git a/src/plugins/autotest/boost/boosttestconfiguration.h b/src/plugins/autotest/boost/boosttestconfiguration.h index 5a764dd8662..10e50004bc8 100644 --- a/src/plugins/autotest/boost/boosttestconfiguration.h +++ b/src/plugins/autotest/boost/boosttestconfiguration.h @@ -13,7 +13,7 @@ class BoostTestConfiguration : public DebuggableTestConfiguration public: explicit BoostTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::Process *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp index 3ac49d2aa46..f91dd25b215 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.cpp +++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp @@ -22,7 +22,7 @@ namespace Internal { static Q_LOGGING_CATEGORY(orLog, "qtc.autotest.boost.outputreader", QtWarningMsg) -BoostTestOutputReader::BoostTestOutputReader(QtcProcess *testApplication, +BoostTestOutputReader::BoostTestOutputReader(Process *testApplication, const FilePath &buildDirectory, const FilePath &projectFile, LogLevel log, ReportLevel report) @@ -34,7 +34,7 @@ BoostTestOutputReader::BoostTestOutputReader(QtcProcess *testApplication, if (!testApplication) return; - connect(testApplication, &QtcProcess::done, this, [this, testApplication] { + connect(testApplication, &Process::done, this, [this, testApplication] { onDone(testApplication->exitCode()); }); } diff --git a/src/plugins/autotest/boost/boosttestoutputreader.h b/src/plugins/autotest/boost/boosttestoutputreader.h index ff2066f7d45..648b55547f0 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.h +++ b/src/plugins/autotest/boost/boosttestoutputreader.h @@ -15,7 +15,7 @@ class BoostTestOutputReader : public TestOutputReader { Q_OBJECT public: - BoostTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + BoostTestOutputReader(Utils::Process *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, LogLevel log, ReportLevel report); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/catch/catchconfiguration.cpp b/src/plugins/autotest/catch/catchconfiguration.cpp index 593acc589e7..88f590d3521 100644 --- a/src/plugins/autotest/catch/catchconfiguration.cpp +++ b/src/plugins/autotest/catch/catchconfiguration.cpp @@ -15,7 +15,7 @@ using namespace Utils; namespace Autotest { namespace Internal { -TestOutputReader *CatchConfiguration::createOutputReader(QtcProcess *app) const +TestOutputReader *CatchConfiguration::createOutputReader(Process *app) const { return new CatchOutputReader(app, buildDirectory(), projectFile()); } diff --git a/src/plugins/autotest/catch/catchconfiguration.h b/src/plugins/autotest/catch/catchconfiguration.h index 90b9b09dceb..63ac84dba7b 100644 --- a/src/plugins/autotest/catch/catchconfiguration.h +++ b/src/plugins/autotest/catch/catchconfiguration.h @@ -12,7 +12,7 @@ class CatchConfiguration : public DebuggableTestConfiguration { public: CatchConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::Process *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/catch/catchoutputreader.cpp b/src/plugins/autotest/catch/catchoutputreader.cpp index 9bcb3778058..7a3aa277d4b 100644 --- a/src/plugins/autotest/catch/catchoutputreader.cpp +++ b/src/plugins/autotest/catch/catchoutputreader.cpp @@ -29,7 +29,7 @@ namespace CatchXml { const char TestCaseResultElement[] = "OverallResult"; } -CatchOutputReader::CatchOutputReader(QtcProcess *testApplication, +CatchOutputReader::CatchOutputReader(Process *testApplication, const FilePath &buildDirectory, const FilePath &projectFile) : TestOutputReader(testApplication, buildDirectory) diff --git a/src/plugins/autotest/catch/catchoutputreader.h b/src/plugins/autotest/catch/catchoutputreader.h index d65ebd7650f..b46db333f80 100644 --- a/src/plugins/autotest/catch/catchoutputreader.h +++ b/src/plugins/autotest/catch/catchoutputreader.h @@ -14,7 +14,7 @@ namespace Internal { class CatchOutputReader : public TestOutputReader { public: - CatchOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + CatchOutputReader(Utils::Process *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile); protected: diff --git a/src/plugins/autotest/ctest/ctestconfiguration.cpp b/src/plugins/autotest/ctest/ctestconfiguration.cpp index 183d7874e86..a2e2edfe0a7 100644 --- a/src/plugins/autotest/ctest/ctestconfiguration.cpp +++ b/src/plugins/autotest/ctest/ctestconfiguration.cpp @@ -13,7 +13,7 @@ CTestConfiguration::CTestConfiguration(ITestBase *testBase) setDisplayName("CTest"); } -TestOutputReader *CTestConfiguration::createOutputReader(Utils::QtcProcess *app) const +TestOutputReader *CTestConfiguration::createOutputReader(Utils::Process *app) const { return new CTestOutputReader(app, workingDirectory()); } diff --git a/src/plugins/autotest/ctest/ctestconfiguration.h b/src/plugins/autotest/ctest/ctestconfiguration.h index 4496fb4aaf5..a298fec86d7 100644 --- a/src/plugins/autotest/ctest/ctestconfiguration.h +++ b/src/plugins/autotest/ctest/ctestconfiguration.h @@ -13,7 +13,7 @@ class CTestConfiguration final : public Autotest::TestToolConfiguration public: explicit CTestConfiguration(ITestBase *testBase); - TestOutputReader *createOutputReader(Utils::QtcProcess *app) const final; + TestOutputReader *createOutputReader(Utils::Process *app) const final; }; } // namespace Internal diff --git a/src/plugins/autotest/ctest/ctestoutputreader.cpp b/src/plugins/autotest/ctest/ctestoutputreader.cpp index 9a6259d8c0d..10f48d9d46c 100644 --- a/src/plugins/autotest/ctest/ctestoutputreader.cpp +++ b/src/plugins/autotest/ctest/ctestoutputreader.cpp @@ -50,7 +50,7 @@ public: {} }; -CTestOutputReader::CTestOutputReader(QtcProcess *testApplication, +CTestOutputReader::CTestOutputReader(Process *testApplication, const FilePath &buildDirectory) : TestOutputReader(testApplication, buildDirectory) { diff --git a/src/plugins/autotest/ctest/ctestoutputreader.h b/src/plugins/autotest/ctest/ctestoutputreader.h index 896f17ba245..85785d44fca 100644 --- a/src/plugins/autotest/ctest/ctestoutputreader.h +++ b/src/plugins/autotest/ctest/ctestoutputreader.h @@ -5,7 +5,7 @@ #include "../testoutputreader.h" -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Autotest { namespace Internal { @@ -13,7 +13,7 @@ namespace Internal { class CTestOutputReader final : public Autotest::TestOutputReader { public: - CTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); + CTestOutputReader(Utils::Process *testApplication, const Utils::FilePath &buildDirectory); protected: void processOutputLine(const QByteArray &outputLineWithNewLine) final; diff --git a/src/plugins/autotest/gtest/gtestconfiguration.cpp b/src/plugins/autotest/gtest/gtestconfiguration.cpp index 1da1d212e4c..32e590ccb52 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.cpp +++ b/src/plugins/autotest/gtest/gtestconfiguration.cpp @@ -17,7 +17,7 @@ using namespace Utils; namespace Autotest { namespace Internal { -TestOutputReader *GTestConfiguration::createOutputReader(QtcProcess *app) const +TestOutputReader *GTestConfiguration::createOutputReader(Process *app) const { return new GTestOutputReader(app, buildDirectory(), projectFile()); } diff --git a/src/plugins/autotest/gtest/gtestconfiguration.h b/src/plugins/autotest/gtest/gtestconfiguration.h index a68a1f9674d..0cbfc8b0d82 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.h +++ b/src/plugins/autotest/gtest/gtestconfiguration.h @@ -14,7 +14,7 @@ public: explicit GTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::Process *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 6ee766b28a3..66a4935622e 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -17,14 +17,14 @@ using namespace Utils; namespace Autotest { namespace Internal { -GTestOutputReader::GTestOutputReader(QtcProcess *testApplication, +GTestOutputReader::GTestOutputReader(Process *testApplication, const FilePath &buildDirectory, const FilePath &projectFile) : TestOutputReader(testApplication, buildDirectory) , m_projectFile(projectFile) { if (testApplication) { - connect(testApplication, &QtcProcess::done, this, [this, testApplication] { + connect(testApplication, &Process::done, this, [this, testApplication] { const int exitCode = testApplication->exitCode(); if (exitCode == 1 && !m_description.isEmpty()) { createAndReportResult(Tr::tr("Running tests failed.\n %1\nExecutable: %2") diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h index a8ced858dd2..a63c5668295 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.h +++ b/src/plugins/autotest/gtest/gtestoutputreader.h @@ -11,7 +11,7 @@ namespace Internal { class GTestOutputReader : public TestOutputReader { public: - GTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + GTestOutputReader(Utils::Process *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp index 9210a9685f1..37da244cc97 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.cpp +++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp @@ -28,7 +28,7 @@ static QStringList quoteIfNeeded(const QStringList &testCases, bool debugMode) }); } -TestOutputReader *QtTestConfiguration::createOutputReader(QtcProcess *app) const +TestOutputReader *QtTestConfiguration::createOutputReader(Process *app) const { auto qtSettings = static_cast(framework()->testSettings()); const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() diff --git a/src/plugins/autotest/qtest/qttestconfiguration.h b/src/plugins/autotest/qtest/qttestconfiguration.h index f370f97c786..d41697090e6 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.h +++ b/src/plugins/autotest/qtest/qttestconfiguration.h @@ -13,7 +13,7 @@ class QtTestConfiguration : public DebuggableTestConfiguration public: explicit QtTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} - TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::Process *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index 8916b8d9818..70df35e6632 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -101,7 +101,7 @@ static QString constructBenchmarkInformation(const QString &metric, double value .arg(iterations); } -QtTestOutputReader::QtTestOutputReader(QtcProcess *testApplication, +QtTestOutputReader::QtTestOutputReader(Process *testApplication, const FilePath &buildDirectory, const FilePath &projectFile, OutputMode mode, TestType type) diff --git a/src/plugins/autotest/qtest/qttestoutputreader.h b/src/plugins/autotest/qtest/qttestoutputreader.h index a730d540dd5..0962c8d6845 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.h +++ b/src/plugins/autotest/qtest/qttestoutputreader.h @@ -23,7 +23,7 @@ public: PlainText }; - QtTestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, + QtTestOutputReader(Utils::Process *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, OutputMode mode, TestType type); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/quick/quicktestconfiguration.cpp b/src/plugins/autotest/quick/quicktestconfiguration.cpp index 1d00c48c201..cf316ca4896 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.cpp +++ b/src/plugins/autotest/quick/quicktestconfiguration.cpp @@ -21,7 +21,7 @@ QuickTestConfiguration::QuickTestConfiguration(ITestFramework *framework) setMixedDebugging(true); } -TestOutputReader *QuickTestConfiguration::createOutputReader(QtcProcess *app) const +TestOutputReader *QuickTestConfiguration::createOutputReader(Process *app) const { auto qtSettings = static_cast(framework()->testSettings()); const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() diff --git a/src/plugins/autotest/quick/quicktestconfiguration.h b/src/plugins/autotest/quick/quicktestconfiguration.h index 6739f848256..33a07b0294f 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.h +++ b/src/plugins/autotest/quick/quicktestconfiguration.h @@ -12,7 +12,7 @@ class QuickTestConfiguration : public DebuggableTestConfiguration { public: explicit QuickTestConfiguration(ITestFramework *framework); - TestOutputReader *createOutputReader(Utils::QtcProcess *app) const override; + TestOutputReader *createOutputReader(Utils::Process *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h index 492509605cf..6292ef8204c 100644 --- a/src/plugins/autotest/testconfiguration.h +++ b/src/plugins/autotest/testconfiguration.h @@ -12,7 +12,7 @@ #include #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Autotest { namespace Internal { @@ -39,7 +39,7 @@ public: Utils::FilePath executableFilePath() const; virtual Utils::FilePath testExecutable() const { return executableFilePath(); }; - virtual TestOutputReader *createOutputReader(Utils::QtcProcess *app) const = 0; + virtual TestOutputReader *createOutputReader(Utils::Process *app) const = 0; virtual Utils::Environment filteredEnvironment(const Utils::Environment &original) const; ITestBase *testBase() const { return m_testBase; } diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp index e05fe8fdddb..48bab930662 100644 --- a/src/plugins/autotest/testoutputreader.cpp +++ b/src/plugins/autotest/testoutputreader.cpp @@ -21,7 +21,7 @@ FilePath TestOutputReader::constructSourceFilePath(const FilePath &path, const Q return filePath.isReadableFile() ? filePath : FilePath(); } -TestOutputReader::TestOutputReader(QtcProcess *testApplication, const FilePath &buildDirectory) +TestOutputReader::TestOutputReader(Process *testApplication, const FilePath &buildDirectory) : m_buildDir(buildDirectory) { auto chopLineBreak = [](QByteArray line) { @@ -33,7 +33,7 @@ TestOutputReader::TestOutputReader(QtcProcess *testApplication, const FilePath & }; if (testApplication) { - connect(testApplication, &QtcProcess::started, this, [this, testApplication] { + connect(testApplication, &Process::started, this, [this, testApplication] { m_id = testApplication->commandLine().executable().toUserOutput(); }); testApplication->setStdOutLineCallback([this, &chopLineBreak](const QString &line) { diff --git a/src/plugins/autotest/testoutputreader.h b/src/plugins/autotest/testoutputreader.h index 7011070b44a..e87c463735a 100644 --- a/src/plugins/autotest/testoutputreader.h +++ b/src/plugins/autotest/testoutputreader.h @@ -7,7 +7,7 @@ #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Autotest { @@ -15,7 +15,7 @@ class TestOutputReader : public QObject { Q_OBJECT public: - TestOutputReader(Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); + TestOutputReader(Utils::Process *testApplication, const Utils::FilePath &buildDirectory); virtual ~TestOutputReader(); void processStdOutput(const QByteArray &outputLine); virtual void processStdError(const QByteArray &outputLine); diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 875549192f2..c0ca216533e 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -89,7 +89,7 @@ void TestRunner::runTest(TestRunMode mode, const ITestTreeItem *item) runTests(mode, {configuration}); } -static QString processInformation(const QtcProcess *proc) +static QString processInformation(const Process *proc) { QTC_ASSERT(proc, return {}); const CommandLine command = proc->commandLine(); @@ -365,7 +365,7 @@ void TestRunner::runTestsHelper() } return TaskAction::Continue; }; - const auto onSetup = [this, config, storage](QtcProcess &process) { + const auto onSetup = [this, config, storage](Process &process) { TestStorage *testStorage = storage.activeStorage(); QTC_ASSERT(testStorage, return); testStorage->m_outputReader.reset(config->createOutputReader(&process)); @@ -412,7 +412,7 @@ void TestRunner::runTestsHelper() qCInfo(runnerLog) << "Working directory:" << process.workingDirectory(); qCDebug(runnerLog) << "Environment:" << process.environment().toStringList(); }; - const auto onDone = [this, config, storage](const QtcProcess &process) { + const auto onDone = [this, config, storage](const Process &process) { TestStorage *testStorage = storage.activeStorage(); QTC_ASSERT(testStorage, return); if (process.result() == ProcessResult::StartFailed) { diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp index 590c1158866..a266ed7bfdc 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp @@ -358,12 +358,12 @@ UvscServerProviderRunner::UvscServerProviderRunner(ProjectExplorer::RunControl * m_process.setCommand(runnable.command); - connect(&m_process, &QtcProcess::started, this, [this] { + connect(&m_process, &Process::started, this, [this] { ProcessHandle pid(m_process.processId()); this->runControl()->setApplicationProcessHandle(pid); reportStarted(); }); - connect(&m_process, &QtcProcess::done, this, [this] { + connect(&m_process, &Process::done, this, [this] { appendMessage(m_process.exitMessage(), NormalMessageFormat); reportStopped(); }); diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h index d7b3bcafbad..6f4275769e1 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h @@ -127,7 +127,7 @@ private: void start() final; void stop() final; - Utils::QtcProcess m_process; + Utils::Process m_process; }; } // namespace Internal diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp index 80b5491ddff..392d4e8234f 100644 --- a/src/plugins/baremetal/iarewtoolchain.cpp +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -78,7 +78,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const QStringList & const QString outpath = fakeIn.fileName() + ".tmp"; - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); @@ -130,7 +130,7 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Id languageId cmd.addArg("--preinclude"); cmd.addArg("."); - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); cpp.setCommand(cmd); diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index 4c023ce3060..e9662ff0314 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -113,7 +113,7 @@ static Macros dumpMcsPredefinedMacros(const FilePath &compiler, const Environmen fakeIn.close(); - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); cpp.setCommand({compiler, {fakeIn.fileName()}}); @@ -190,7 +190,7 @@ static Macros dumpC166PredefinedMacros(const FilePath &compiler, const Environme fakeIn.close(); - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); @@ -255,7 +255,7 @@ static Macros dumpC166PredefinedMacros(const FilePath &compiler, const Environme static Macros dumpArmPredefinedMacros(const FilePath &compiler, const QStringList &extraArgs, const Environment &env) { - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp index a16372eff97..14b20657de8 100644 --- a/src/plugins/baremetal/sdcctoolchain.cpp +++ b/src/plugins/baremetal/sdcctoolchain.cpp @@ -65,7 +65,7 @@ static Macros dumpPredefinedMacros(const FilePath &compiler, const Environment & return {}; fakeIn.close(); - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); cpp.setCommand({compiler, {compilerTargetFlag(abi), "-dM", "-E", fakeIn.fileName()}}); @@ -86,7 +86,7 @@ static HeaderPaths dumpHeaderPaths(const FilePath &compiler, const Environment & if (!compiler.exists()) return {}; - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setTimeoutS(10); cpp.setCommand({compiler, {compilerTargetFlag(abi), "--print-search-dirs"}}); diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp index 0b96e1579ea..17e36d279cb 100644 --- a/src/plugins/beautifier/abstractsettings.cpp +++ b/src/plugins/beautifier/abstractsettings.cpp @@ -34,7 +34,7 @@ class VersionUpdater public: VersionUpdater() { - QObject::connect(&m_process, &QtcProcess::done, &m_process, [this] { + QObject::connect(&m_process, &Process::done, &m_process, [this] { if (m_process.result() != ProcessResult::FinishedWithSuccess) return; @@ -77,7 +77,7 @@ private: } QRegularExpression m_versionRegExp; - mutable QtcProcess m_process; + mutable Process m_process; QVersionNumber m_versionNumber; }; diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp index 1cff800ed1f..b7d54de96f2 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp @@ -112,7 +112,7 @@ QString ArtisticStyleSettings::documentationFilePath() const void ArtisticStyleSettings::createDocumentationFile() const { - QtcProcess process; + Process process; process.setTimeoutS(2); process.setCommand({command(), {"-h"}}); process.runBlocking(); diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp index e827a8f7915..243d63e049a 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp @@ -124,7 +124,7 @@ QString UncrustifySettings::documentationFilePath() const void UncrustifySettings::createDocumentationFile() const { - QtcProcess process; + Process process; process.setTimeoutS(2); process.setCommand({command(), {"--show-config"}}); process.runBlocking(); diff --git a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp index 3375e10e026..8a18a3b5ac9 100644 --- a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp +++ b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp @@ -118,7 +118,7 @@ void QdbWatcher::forkHostServer() showMessage(message, true); return; } - if (Utils::QtcProcess::startDetached({qdbFilePath, {"server"}})) + if (Utils::Process::startDetached({qdbFilePath, {"server"}})) showMessage(Tr::tr("QDB host server started."), false); else showMessage(Tr::tr("Could not start QDB host server in %1").arg(qdbFilePath.toString()), true); diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index c2c25b65372..dd767fbc7cc 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -50,7 +50,7 @@ class DeviceApplicationObserver : public QObject public: DeviceApplicationObserver(const IDevice::ConstPtr &device, const CommandLine &command) { - connect(&m_appRunner, &QtcProcess::done, this, &DeviceApplicationObserver::handleDone); + connect(&m_appRunner, &Process::done, this, &DeviceApplicationObserver::handleDone); QTC_ASSERT(device, return); m_deviceName = device->displayName(); @@ -94,7 +94,7 @@ private: deleteLater(); } - QtcProcess m_appRunner; + Process m_appRunner; QString m_deviceName; }; diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 97529dfa9fb..0aa4f74362a 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -34,13 +34,13 @@ public: { setId("QdbDebuggeeRunner"); - connect(&m_launcher, &QtcProcess::started, this, &RunWorker::reportStarted); - connect(&m_launcher, &QtcProcess::done, this, &RunWorker::reportStopped); + connect(&m_launcher, &Process::started, this, &RunWorker::reportStarted); + connect(&m_launcher, &Process::done, this, &RunWorker::reportStopped); - connect(&m_launcher, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&m_launcher, &Process::readyReadStandardOutput, this, [this] { appendMessage(m_launcher.readAllStandardOutput(), StdOutFormat); }); - connect(&m_launcher, &QtcProcess::readyReadStandardError, this, [this] { + connect(&m_launcher, &Process::readyReadStandardError, this, [this] { appendMessage(m_launcher.readAllStandardError(), StdErrFormat); }); @@ -112,7 +112,7 @@ private: bool m_useGdbServer; bool m_useQmlServer; QmlDebug::QmlDebugServicesPreset m_qmlServices; - QtcProcess m_launcher; + Process m_launcher; }; // QdbDeviceRunSupport diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp index 8442fd03463..b99d264066e 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp @@ -42,7 +42,7 @@ public: private: Group deployRecipe() final { - const auto setupHandler = [this](QtcProcess &process) { + const auto setupHandler = [this](Process &process) { QString remoteExe; if (RunConfiguration *rc = target()->activeRunConfiguration()) { if (auto exeAspect = rc->aspect()) @@ -54,18 +54,18 @@ private: else cmd.addArg("--remove-default"); process.setCommand(cmd); - QtcProcess *proc = &process; - connect(proc, &QtcProcess::readyReadStandardError, this, [this, proc] { + Process *proc = &process; + connect(proc, &Process::readyReadStandardError, this, [this, proc] { handleStdErrData(proc->readAllStandardError()); }); }; - const auto doneHandler = [this](const QtcProcess &) { + const auto doneHandler = [this](const Process &) { if (m_makeDefault) addProgressMessage(Tr::tr("Application set as the default one.")); else addProgressMessage(Tr::tr("Reset the default application.")); }; - const auto errorHandler = [this](const QtcProcess &process) { + const auto errorHandler = [this](const Process &process) { addErrorMessage(Tr::tr("Remote process failed: %1").arg(process.errorString())); }; return Group { ProcessTask(setupHandler, doneHandler, errorHandler) }; diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index 66196e246bb..6ce706e3c11 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -49,9 +49,9 @@ static void startFlashingWizard() { const FilePath filePath = flashWizardFilePath(); if (HostOsInfo::isWindowsHost()) { - if (QtcProcess::startDetached({"explorer.exe", {filePath.toUserOutput()}})) + if (Process::startDetached({"explorer.exe", {filePath.toUserOutput()}})) return; - } else if (QtcProcess::startDetached({filePath, {}})) { + } else if (Process::startDetached({filePath, {}})) { return; } const QString message = Tr::tr("Flash wizard \"%1\" failed to start."); diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index deeb535576b..a9fd0fb2200 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -39,7 +39,7 @@ public: Group QdbStopApplicationStep::deployRecipe() { - const auto setupHandler = [this](QtcProcess &process) { + const auto setupHandler = [this](Process &process) { const auto device = DeviceKitAspect::device(target()->kit()); if (!device) { addErrorMessage(Tr::tr("No device to stop the application on.")); @@ -48,16 +48,16 @@ Group QdbStopApplicationStep::deployRecipe() QTC_CHECK(device); process.setCommand({device->filePath(Constants::AppcontrollerFilepath), {"--stop"}}); process.setWorkingDirectory("/usr/bin"); - QtcProcess *proc = &process; - connect(proc, &QtcProcess::readyReadStandardOutput, this, [this, proc] { + Process *proc = &process; + connect(proc, &Process::readyReadStandardOutput, this, [this, proc] { handleStdOutData(proc->readAllStandardOutput()); }); return TaskAction::Continue; }; - const auto doneHandler = [this](const QtcProcess &) { + const auto doneHandler = [this](const Process &) { addProgressMessage(Tr::tr("Stopped the running application.")); }; - const auto errorHandler = [this](const QtcProcess &process) { + const auto errorHandler = [this](const Process &process) { const QString errorOutput = process.cleanedStdErr(); const QString failureMessage = Tr::tr("Could not check and possibly stop running application."); if (process.exitStatus() == QProcess::CrashExit) { diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 5866bcae944..7c71acceb92 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -141,7 +141,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, return TaskAction::Continue; }; - const auto onProcessSetup = [=](QtcProcess &process) { + const auto onProcessSetup = [=](Process &process) { process.setEnvironment(input.environment); process.setUseCtrlCStub(true); process.setLowPriority(); @@ -158,13 +158,13 @@ TaskItem clangToolTask(const AnalyzeInputData &input, qCDebug(LOG).noquote() << "Starting" << commandLine.toUserOutput(); process.setCommand(commandLine); }; - const auto onProcessDone = [=](const QtcProcess &process) { + const auto onProcessDone = [=](const Process &process) { qCDebug(LOG).noquote() << "Output:\n" << process.cleanedStdOut(); if (!outputHandler) return; outputHandler({true, input.unit.file, storage->outputFilePath, input.tool}); }; - const auto onProcessError = [=](const QtcProcess &process) { + const auto onProcessError = [=](const Process &process) { if (!outputHandler) return; const QString details = Tr::tr("Command line: %1\nProcess Error: %2\nOutput:\n%3") diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index 72f8086be1e..6b5e373daa5 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -211,7 +211,7 @@ bool isVFSOverlaySupported(const FilePath &executable) static QMap vfsCapabilities; auto it = vfsCapabilities.find(executable); if (it == vfsCapabilities.end()) { - QtcProcess p; + Process p; p.setCommand({executable, {"--help"}}); p.runBlocking(); it = vfsCapabilities.insert(executable, p.allOutput().contains("vfsoverlay")); diff --git a/src/plugins/clangtools/executableinfo.cpp b/src/plugins/clangtools/executableinfo.cpp index 1e280a68894..0b5d649cf50 100644 --- a/src/plugins/clangtools/executableinfo.cpp +++ b/src/plugins/clangtools/executableinfo.cpp @@ -26,7 +26,7 @@ static QString runExecutable(const Utils::CommandLine &commandLine, QueryFailMod if (commandLine.executable().isEmpty() || !commandLine.executable().toFileInfo().isExecutable()) return {}; - QtcProcess cpp; + Process cpp; Environment env = Environment::systemEnvironment(); env.setupEnglishOutput(); cpp.setEnvironment(env); diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index c269a591389..f32e502c1bf 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -1575,7 +1575,7 @@ CommandResult ClearCasePluginPrivate::runCleartoolProc(const FilePath &workingDi if (m_settings.ccBinaryPath.isEmpty()) return CommandResult(ProcessResult::StartFailed, Tr::tr("No ClearCase executable specified.")); - QtcProcess process; + Process process; Environment env = Environment::systemEnvironment(); VcsBase::setProcessEnvironment(&env); process.setEnvironment(env); @@ -2233,7 +2233,7 @@ void ClearCasePluginPrivate::diffGraphical(const QString &file1, const QString & args << file1; if (!pred) args << file2; - QtcProcess::startDetached({m_settings.ccBinaryPath, args}, m_topLevel); + Process::startDetached({m_settings.ccBinaryPath, args}, m_topLevel); } QString ClearCasePluginPrivate::runExtDiff(const FilePath &workingDir, const QStringList &arguments, @@ -2243,7 +2243,7 @@ QString ClearCasePluginPrivate::runExtDiff(const FilePath &workingDir, const QSt diff.addArgs(m_settings.diffArgs.split(' ', Qt::SkipEmptyParts)); diff.addArgs(arguments); - QtcProcess process; + Process process; process.setTimeoutS(timeOutS); process.setWorkingDirectory(workingDir); process.setCodec(outputCodec ? outputCodec : QTextCodec::codecForName("UTF-8")); diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp index 90dad2b988c..82e1b7571de 100644 --- a/src/plugins/clearcase/clearcasesync.cpp +++ b/src/plugins/clearcase/clearcasesync.cpp @@ -29,7 +29,7 @@ static void runProcess(QPromise &promise, const ClearCaseSettings &setting std::function processLine) { const QString viewRoot = ClearCasePlugin::viewData().root; - QtcProcess process; + Process process; process.setWorkingDirectory(FilePath::fromString(viewRoot)); process.setCommand({settings.ccBinaryPath, args}); process.start(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 805f84f7c24..146c2f853c4 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -1257,11 +1257,11 @@ void CMakeBuildSystem::runCTest() QTC_ASSERT(parameters.isValid(), return); ensureBuildDirectory(parameters); - m_ctestProcess.reset(new QtcProcess); + m_ctestProcess.reset(new Process); m_ctestProcess->setEnvironment(buildConfiguration()->environment()); m_ctestProcess->setWorkingDirectory(parameters.buildDirectory); m_ctestProcess->setCommand({m_ctestPath, { "-N", "--show-only=json-v1"}}); - connect(m_ctestProcess.get(), &QtcProcess::done, this, [this] { + connect(m_ctestProcess.get(), &Process::done, this, [this] { if (m_ctestProcess->result() == ProcessResult::FinishedWithSuccess) { const QJsonDocument json = QJsonDocument::fromJson(m_ctestProcess->readAllRawStandardOutput()); @@ -1735,12 +1735,12 @@ void CMakeBuildSystem::runGenerator(Id id) optionsAspect && !optionsAspect->value().isEmpty()) { cmdLine.addArgs(optionsAspect->value(), CommandLine::Raw); } - const auto proc = new QtcProcess(this); - connect(proc, &QtcProcess::done, proc, &QtcProcess::deleteLater); - connect(proc, &QtcProcess::readyReadStandardOutput, this, [proc] { + const auto proc = new Process(this); + connect(proc, &Process::done, proc, &Process::deleteLater); + connect(proc, &Process::readyReadStandardOutput, this, [proc] { Core::MessageManager::writeFlashing(QString::fromLocal8Bit(proc->readAllRawStandardOutput())); }); - connect(proc, &QtcProcess::readyReadStandardError, this, [proc] { + connect(proc, &Process::readyReadStandardError, this, [proc] { Core::MessageManager::writeDisrupting(QString::fromLocal8Bit(proc->readAllRawStandardError())); }); proc->setWorkingDirectory(outDir); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index b36b85d98f2..4770b4d84bc 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -18,7 +18,7 @@ namespace ProjectExplorer { class ExtraCompiler; class FolderNode; } -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace CMakeProjectManager { @@ -233,7 +233,7 @@ private: // CTest integration Utils::FilePath m_ctestPath; - std::unique_ptr m_ctestProcess; + std::unique_ptr m_ctestProcess; QList m_testNames; CMakeConfig m_configurationFromCMake; diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 2e2e221ba4c..6b8270db6c8 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -106,7 +106,7 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & // Always use the sourceDir: If we are triggered because the build directory is getting deleted // then we are racing against CMakeCache.txt also getting deleted. - m_process.reset(new QtcProcess); + m_process.reset(new Process); m_process->setWorkingDirectory(buildDirectory); m_process->setEnvironment(parameters.environment); @@ -120,7 +120,7 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & BuildSystem::appendBuildSystemOutput(stripTrailingNewline(s)); }); - connect(m_process.get(), &QtcProcess::done, this, [this] { + connect(m_process.get(), &Process::done, this, [this] { handleProcessDone(m_process->resultData()); }); diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.h b/src/plugins/cmakeprojectmanager/cmakeprocess.h index d13b0efabe2..bb365d337cc 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.h +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.h @@ -13,7 +13,7 @@ namespace Utils { class ProcessResultData; -class QtcProcess; +class Process; } namespace CMakeProjectManager::Internal { @@ -37,7 +37,7 @@ signals: private: void handleProcessDone(const Utils::ProcessResultData &resultData); - std::unique_ptr m_process; + std::unique_ptr m_process; Utils::OutputFormatter m_parser; QElapsedTimer m_elapsed; }; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 8210eb21924..52da1adc8ae 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -164,7 +164,7 @@ static CMakeConfig configurationFromPresetProbe( "project(preset-probe)\n" "\n")); - QtcProcess cmake; + Process cmake; cmake.setTimeoutS(30); cmake.setDisableUnixTerminal(); @@ -341,7 +341,7 @@ static QMakeAndCMakePrefixPath qtInfoFromCMakeCache(const CMakeConfig &config, file(WRITE "${CMAKE_SOURCE_DIR}/cmake-prefix-path.txt" "${CMAKE_PREFIX_PATH}") )")); - QtcProcess cmake; + Process cmake; cmake.setTimeoutS(5); cmake.setDisableUnixTerminal(); diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 184811884db..eae44c15638 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -162,7 +162,7 @@ bool CMakeTool::isValid() const return m_introspection->m_didRun && !m_introspection->m_fileApis.isEmpty(); } -void CMakeTool::runCMake(QtcProcess &cmake, const QStringList &args, int timeoutS) const +void CMakeTool::runCMake(Process &cmake, const QStringList &args, int timeoutS) const { const FilePath executable = cmakeExecutable(); cmake.setTimeoutS(timeoutS); @@ -248,7 +248,7 @@ TextEditor::Keywords CMakeTool::keywords() return {}; if (m_introspection->m_functions.isEmpty() && m_introspection->m_didRun) { - QtcProcess proc; + Process proc; runCMake(proc, {"--help-command-list"}, 5); if (proc.result() == ProcessResult::FinishedWithSuccess) m_introspection->m_functions = proc.cleanedStdOut().split('\n'); @@ -492,7 +492,7 @@ QStringList CMakeTool::parseVariableOutput(const QString &output) void CMakeTool::fetchFromCapabilities() const { - QtcProcess cmake; + Process cmake; runCMake(cmake, {"-E", "capabilities"}); if (cmake.result() == ProcessResult::FinishedWithSuccess) { diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h index 42fa7b8f62d..9d704b57248 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.h +++ b/src/plugins/cmakeprojectmanager/cmaketool.h @@ -12,7 +12,7 @@ #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace CMakeProjectManager { @@ -95,7 +95,7 @@ public: private: void readInformation() const; - void runCMake(Utils::QtcProcess &proc, const QStringList &args, int timeoutS = 1) const; + void runCMake(Utils::Process &proc, const QStringList &args, int timeoutS = 1) const; void parseFunctionDetailsOutput(const QString &output); QStringList parseVariableOutput(const QString &output); diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp index 0c0b1d89260..14e4d511203 100644 --- a/src/plugins/coreplugin/externaltool.cpp +++ b/src/plugins/coreplugin/externaltool.cpp @@ -623,11 +623,11 @@ void ExternalToolRunner::run() DocumentManager::expectFileChange(m_expectedFilePath); } } - m_process = new QtcProcess(this); - connect(m_process, &QtcProcess::done, this, &ExternalToolRunner::done); - connect(m_process, &QtcProcess::readyReadStandardOutput, + m_process = new Process(this); + connect(m_process, &Process::done, this, &ExternalToolRunner::done); + connect(m_process, &Process::readyReadStandardOutput, this, &ExternalToolRunner::readStandardOutput); - connect(m_process, &QtcProcess::readyReadStandardError, + connect(m_process, &Process::readyReadStandardError, this, &ExternalToolRunner::readStandardError); if (!m_resolvedWorkingDirectory.isEmpty()) m_process->setWorkingDirectory(m_resolvedWorkingDirectory); diff --git a/src/plugins/coreplugin/externaltool.h b/src/plugins/coreplugin/externaltool.h index 8a32d241653..d92d6099bc9 100644 --- a/src/plugins/coreplugin/externaltool.h +++ b/src/plugins/coreplugin/externaltool.h @@ -14,7 +14,7 @@ #include #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Core { @@ -127,7 +127,7 @@ private: QString m_resolvedInput; Utils::FilePath m_resolvedWorkingDirectory; Utils::Environment m_resolvedEnvironment; - Utils::QtcProcess *m_process; + Utils::Process *m_process; QTextCodec *m_outputCodec; QTextCodec::ConverterState m_outputCodecState; QTextCodec::ConverterState m_errorCodecState; diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index c98d5269f1c..32975986203 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -68,9 +68,9 @@ void FileUtils::showInGraphicalShell(QWidget *parent, const FilePath &pathIn) if (!pathIn.isDir()) param += QLatin1String("/select,"); param += QDir::toNativeSeparators(fileInfo.canonicalFilePath()); - QtcProcess::startDetached({explorer, param}); + Process::startDetached({explorer, param}); } else if (HostOsInfo::isMacHost()) { - QtcProcess::startDetached({"/usr/bin/open", {"-R", fileInfo.canonicalFilePath()}}); + Process::startDetached({"/usr/bin/open", {"-R", fileInfo.canonicalFilePath()}}); } else { // we cannot select a file here, because no file browser really supports it... const QString folder = fileInfo.isDir() ? fileInfo.absoluteFilePath() : fileInfo.filePath(); diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 3419c117adb..43b4d9a3784 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -196,11 +196,11 @@ void ExecuteFilter::createProcess() if (m_process) return; - m_process = new QtcProcess; + m_process = new Process; m_process->setEnvironment(Environment::systemEnvironment()); - connect(m_process, &QtcProcess::done, this, &ExecuteFilter::done); - connect(m_process, &QtcProcess::readyReadStandardOutput, this, &ExecuteFilter::readStandardOutput); - connect(m_process, &QtcProcess::readyReadStandardError, this, &ExecuteFilter::readStandardError); + connect(m_process, &Process::done, this, &ExecuteFilter::done); + connect(m_process, &Process::readyReadStandardOutput, this, &ExecuteFilter::readStandardOutput); + connect(m_process, &Process::readyReadStandardError, this, &ExecuteFilter::readStandardError); } void ExecuteFilter::removeProcess() diff --git a/src/plugins/coreplugin/locator/executefilter.h b/src/plugins/coreplugin/locator/executefilter.h index 525c7250283..348a09c7fe3 100644 --- a/src/plugins/coreplugin/locator/executefilter.h +++ b/src/plugins/coreplugin/locator/executefilter.h @@ -11,7 +11,7 @@ #include #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Core { namespace Internal { @@ -49,7 +49,7 @@ private: QQueue m_taskQueue; QStringList m_commandHistory; - Utils::QtcProcess *m_process = nullptr; + Utils::Process *m_process = nullptr; QTextCodec::ConverterState m_stdoutState; QTextCodec::ConverterState m_stderrState; }; diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index ac1d698a258..759b56fb267 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -53,7 +53,7 @@ public: private: void ensureNext(); - std::unique_ptr m_process; + std::unique_ptr m_process; QMutex m_mutex; QWaitCondition m_waitForItems; FilePaths m_queue; @@ -67,10 +67,10 @@ SpotlightIterator::SpotlightIterator(const CommandLine &command) , m_finished(false) { QTC_ASSERT(!command.isEmpty(), return ); - m_process.reset(new QtcProcess); + m_process.reset(new Process); m_process->setCommand(command); m_process->setEnvironment(Utils::Environment::systemEnvironment()); - QObject::connect(m_process.get(), &QtcProcess::done, + QObject::connect(m_process.get(), &Process::done, m_process.get(), [this, exe = command.executable().toUserOutput()] { if (m_process->result() != ProcessResult::FinishedWithSuccess) { MessageManager::writeFlashing(Tr::tr( @@ -78,7 +78,7 @@ SpotlightIterator::SpotlightIterator(const CommandLine &command) } scheduleKillProcess(); }); - QObject::connect(m_process.get(), &QtcProcess::readyReadStandardOutput, + QObject::connect(m_process.get(), &Process::readyReadStandardOutput, m_process.get(), [this] { QString output = m_process->readAllStandardOutput(); output.replace("\r\n", "\n"); @@ -250,11 +250,11 @@ static void matches(QPromise &promise, const LocatorStorage &storage, const bool hasPathSeparator = newInput.contains('/') || newInput.contains('*'); LocatorFileCache::MatchedEntries entries = {}; QEventLoop loop; - QtcProcess process; + Process process; process.setCommand(command); process.setEnvironment(Environment::systemEnvironment()); // TODO: Is it needed? - QObject::connect(&process, &QtcProcess::readyReadStandardOutput, &process, + QObject::connect(&process, &Process::readyReadStandardOutput, &process, [&, entriesPtr = &entries] { QString output = process.readAllStandardOutput(); output.replace("\r\n", "\n"); @@ -265,7 +265,7 @@ static void matches(QPromise &promise, const LocatorStorage &storage, if (promise.isCanceled()) loop.exit(); }); - QObject::connect(&process, &QtcProcess::done, &process, [&] { + QObject::connect(&process, &Process::done, &process, [&] { if (process.result() != ProcessResult::FinishedWithSuccess) { MessageManager::writeFlashing(Tr::tr("Locator: Error occurred when running \"%1\".") .arg(command.executable().toUserOutput())); diff --git a/src/plugins/coreplugin/patchtool.cpp b/src/plugins/coreplugin/patchtool.cpp index 9af08353807..06b20610f17 100644 --- a/src/plugins/coreplugin/patchtool.cpp +++ b/src/plugins/coreplugin/patchtool.cpp @@ -76,7 +76,7 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec return false; } - QtcProcess patchProcess; + Process patchProcess; if (!workingDirectory.isEmpty()) patchProcess.setWorkingDirectory(workingDirectory); Environment env = Environment::systemEnvironment(); diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index 224f692329e..503ab2d3790 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -403,7 +403,7 @@ static std::function postCopyOperation() return; // On macOS, downloaded files get a quarantine flag, remove it, otherwise it is a hassle // to get it loaded as a plugin in Qt Creator. - QtcProcess xattr; + Process xattr; xattr.setTimeoutS(1); xattr.setCommand({"/usr/bin/xattr", {"-d", "com.apple.quarantine", filePath.absoluteFilePath().toString()}}); xattr.runBlocking(); diff --git a/src/plugins/coreplugin/progressmanager/processprogress.cpp b/src/plugins/coreplugin/progressmanager/processprogress.cpp index 9a545561a78..2895b402a5c 100644 --- a/src/plugins/coreplugin/progressmanager/processprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/processprogress.cpp @@ -18,13 +18,13 @@ namespace Core { class ProcessProgressPrivate : public QObject { public: - explicit ProcessProgressPrivate(ProcessProgress *progress, QtcProcess *process); + explicit ProcessProgressPrivate(ProcessProgress *progress, Process *process); ~ProcessProgressPrivate(); QString displayName() const; void parseProgress(const QString &inputText); - QtcProcess *m_process = nullptr; + Process *m_process = nullptr; ProgressParser m_parser = {}; QFutureWatcher m_watcher; QFutureInterface m_futureInterface; @@ -33,7 +33,7 @@ public: FutureProgress::KeepOnFinishType m_keep = FutureProgress::HideOnFinish; }; -ProcessProgressPrivate::ProcessProgressPrivate(ProcessProgress *progress, QtcProcess *process) +ProcessProgressPrivate::ProcessProgressPrivate(ProcessProgress *progress, Process *process) : QObject(progress) , m_process(process) { @@ -77,14 +77,14 @@ void ProcessProgressPrivate::parseProgress(const QString &inputText) indicator on progress panel. In this case QtcProcess::stop() method is being called. */ -ProcessProgress::ProcessProgress(QtcProcess *process) +ProcessProgress::ProcessProgress(Process *process) : QObject(process) , d(new ProcessProgressPrivate(this, process)) { connect(&d->m_watcher, &QFutureWatcher::canceled, this, [this] { d->m_process->stop(); // TODO: See TaskProgress::setAutoStopOnCancel }); - connect(d->m_process, &QtcProcess::starting, this, [this] { + connect(d->m_process, &Process::starting, this, [this] { d->m_futureInterface = QFutureInterface(); d->m_futureInterface.setProgressRange(0, 1); d->m_watcher.setFuture(d->m_futureInterface.future()); @@ -100,7 +100,7 @@ ProcessProgress::ProcessProgress(QtcProcess *process) } d->m_futureProgress->setKeepOnFinish(d->m_keep); }); - connect(d->m_process, &QtcProcess::done, this, [this] { + connect(d->m_process, &Process::done, this, [this] { if (d->m_process->result() != ProcessResult::FinishedWithSuccess) d->m_futureInterface.reportCanceled(); d->m_futureInterface.reportFinished(); @@ -124,9 +124,9 @@ void ProcessProgress::setKeepOnFinish(FutureProgress::KeepOnFinishType keepType) void ProcessProgress::setProgressParser(const ProgressParser &parser) { if (d->m_parser) { - disconnect(d->m_process, &QtcProcess::textOnStandardOutput, + disconnect(d->m_process, &Process::textOnStandardOutput, d.get(), &ProcessProgressPrivate::parseProgress); - disconnect(d->m_process, &QtcProcess::textOnStandardError, + disconnect(d->m_process, &Process::textOnStandardError, d.get(), &ProcessProgressPrivate::parseProgress); } d->m_parser = parser; @@ -137,9 +137,9 @@ void ProcessProgress::setProgressParser(const ProgressParser &parser) qWarning() << "Setting progress parser on a process without changing process' " "text channel mode is no-op."); - connect(d->m_process, &QtcProcess::textOnStandardOutput, + connect(d->m_process, &Process::textOnStandardOutput, d.get(), &ProcessProgressPrivate::parseProgress); - connect(d->m_process, &QtcProcess::textOnStandardError, + connect(d->m_process, &Process::textOnStandardError, d.get(), &ProcessProgressPrivate::parseProgress); } diff --git a/src/plugins/coreplugin/progressmanager/processprogress.h b/src/plugins/coreplugin/progressmanager/processprogress.h index fd2f64caf03..e91c0b7b3c7 100644 --- a/src/plugins/coreplugin/progressmanager/processprogress.h +++ b/src/plugins/coreplugin/progressmanager/processprogress.h @@ -9,7 +9,7 @@ #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Core { @@ -20,7 +20,7 @@ class ProcessProgressPrivate; class CORE_EXPORT ProcessProgress : public QObject { public: - ProcessProgress(Utils::QtcProcess *process); // Makes ProcessProgress a child of process + ProcessProgress(Utils::Process *process); // Makes ProcessProgress a child of process ~ProcessProgress() override; void setDisplayName(const QString &name); diff --git a/src/plugins/cppcheck/cppcheckrunner.cpp b/src/plugins/cppcheck/cppcheckrunner.cpp index 8595eac28ba..436c8ab392c 100644 --- a/src/plugins/cppcheck/cppcheckrunner.cpp +++ b/src/plugins/cppcheck/cppcheckrunner.cpp @@ -16,7 +16,7 @@ namespace Cppcheck::Internal { CppcheckRunner::CppcheckRunner(CppcheckTool &tool) : m_tool(tool) { if (HostOsInfo::hostOs() == OsTypeLinux) { - QtcProcess getConf; + Process getConf; getConf.setCommand({"getconf", {"ARG_MAX"}}); getConf.start(); getConf.waitForFinished(2000); @@ -31,8 +31,8 @@ CppcheckRunner::CppcheckRunner(CppcheckTool &tool) : m_tool(tool) m_tool.parseErrorLine(line); }); - connect(&m_process, &QtcProcess::started, &m_tool, &CppcheckTool::startParsing); - connect(&m_process, &QtcProcess::done, this, &CppcheckRunner::handleDone); + connect(&m_process, &Process::started, &m_tool, &CppcheckTool::startParsing); + connect(&m_process, &Process::done, this, &CppcheckRunner::handleDone); m_queueTimer.setSingleShot(true); const int checkDelayInMs = 200; diff --git a/src/plugins/cppcheck/cppcheckrunner.h b/src/plugins/cppcheck/cppcheckrunner.h index 23689b2b05b..0ec49aceb54 100644 --- a/src/plugins/cppcheck/cppcheckrunner.h +++ b/src/plugins/cppcheck/cppcheckrunner.h @@ -35,7 +35,7 @@ private: void handleDone(); CppcheckTool &m_tool; - Utils::QtcProcess m_process; + Utils::Process m_process; Utils::FilePath m_binary; QString m_arguments; QHash m_queue; diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index d04d6c70eb6..679b3684944 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -340,7 +340,7 @@ static FilePath getClangHeadersPathFromClang(const FilePath &clangdFilePath) .withExecutableSuffix(); if (!clangFilePath.exists()) return {}; - QtcProcess clang; + Process clang; clang.setCommand({clangFilePath, {"-print-resource-dir"}}); clang.start(); if (!clang.waitForFinished()) diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index bc67f432f12..21c75b7cbc1 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -449,10 +449,10 @@ void CppModelManager::showPreprocessedFile(bool inNextSplit) compilerArgs.append("/E"); compilerArgs.append(filePath.toUserOutput()); const CommandLine compilerCommandLine(tc->compilerCommand(), compilerArgs); - const auto compiler = new QtcProcess(instance()); + const auto compiler = new Process(instance()); compiler->setCommand(compilerCommandLine); compiler->setEnvironment(project->activeTarget()->activeBuildConfiguration()->environment()); - connect(compiler, &QtcProcess::done, instance(), [compiler, outFilePath, inNextSplit, + connect(compiler, &Process::done, instance(), [compiler, outFilePath, inNextSplit, useBuiltinPreprocessor, isMsvc] { compiler->deleteLater(); if (compiler->result() != ProcessResult::FinishedWithSuccess) { diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 5d5b828712b..ade37ae8ec1 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -182,8 +182,8 @@ CdbEngine::CdbEngine() : DebuggerSettings *s = debuggerSettings(); connect(s->createFullBacktrace.action(), &QAction::triggered, this, &CdbEngine::createFullBacktrace); - connect(&m_process, &QtcProcess::started, this, &CdbEngine::processStarted); - connect(&m_process, &QtcProcess::done, this, &CdbEngine::processDone); + connect(&m_process, &Process::started, this, &CdbEngine::processStarted); + connect(&m_process, &Process::done, this, &CdbEngine::processDone); m_process.setStdOutLineCallback([this](const QString &line) { parseOutputLine(line); }); m_process.setStdErrLineCallback([this](const QString &line) { parseOutputLine(line); }); connect(&s->useDebuggingHelpers, &BaseAspect::changed, diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index f0c098e415a..0fba6708e9d 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -174,7 +174,7 @@ private: const QString m_tokenPrefix; void handleSetupFailure(const QString &errorMessage); - Utils::QtcProcess m_process; + Utils::Process m_process; DebuggerStartMode m_effectiveStartMode = NoStartMode; //! Debugger accessible (expecting commands) bool m_accessible = false; diff --git a/src/plugins/debugger/dap/dapengine.cpp b/src/plugins/debugger/dap/dapengine.cpp index 4b1a1198736..ed0933008e2 100644 --- a/src/plugins/debugger/dap/dapengine.cpp +++ b/src/plugins/debugger/dap/dapengine.cpp @@ -112,10 +112,10 @@ void DapEngine::setupEngine() { QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); - connect(&m_proc, &QtcProcess::started, this, &DapEngine::handleDabStarted); - connect(&m_proc, &QtcProcess::done, this, &DapEngine::handleDapDone); - connect(&m_proc, &QtcProcess::readyReadStandardOutput, this, &DapEngine::readDapStandardOutput); - connect(&m_proc, &QtcProcess::readyReadStandardError, this, &DapEngine::readDapStandardError); + connect(&m_proc, &Process::started, this, &DapEngine::handleDabStarted); + connect(&m_proc, &Process::done, this, &DapEngine::handleDapDone); + connect(&m_proc, &Process::readyReadStandardOutput, this, &DapEngine::readDapStandardOutput); + connect(&m_proc, &Process::readyReadStandardError, this, &DapEngine::readDapStandardError); const DebuggerRunParameters &rp = runParameters(); const CommandLine cmd{rp.debugger.command.executable(), {"-i", "dap"}}; diff --git a/src/plugins/debugger/dap/dapengine.h b/src/plugins/debugger/dap/dapengine.h index d4dca0d2f73..9b554d668ba 100644 --- a/src/plugins/debugger/dap/dapengine.h +++ b/src/plugins/debugger/dap/dapengine.h @@ -91,7 +91,7 @@ private: void updateLocals() override; QByteArray m_inbuffer; - Utils::QtcProcess m_proc; + Utils::Process m_proc; int m_nextBreakpointId = 1; }; diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index a6daacd16d3..76630f2e7dc 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -43,7 +43,7 @@ const char DEBUGGER_INFORMATION_WORKINGDIRECTORY[] = "WorkingDirectory"; static QString getGdbConfiguration(const FilePath &command, const Environment &sysEnv) { // run gdb with the --configuration opion - QtcProcess proc; + Process proc; proc.setEnvironment(sysEnv); proc.setCommand({command, {"--configuration"}}); proc.runBlocking(); @@ -162,7 +162,7 @@ void DebuggerItem::reinitializeFromFile(QString *error, Utils::Environment *cust // hack below tricks it into giving us the information we want. env.set("QNX_TARGET", QString()); - QtcProcess proc; + Process proc; proc.setEnvironment(env); proc.setCommand({m_command, {version}}); proc.runBlocking(); diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index ab1f53076d7..f418ace88e6 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -762,7 +762,7 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePaths &s FilePaths suspects; if (searchPaths.front().osType() == OsTypeMac) { - QtcProcess proc; + Process proc; proc.setTimeoutS(2); proc.setCommand({"xcrun", {"--find", "lldb"}}); proc.runBlocking(); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 85b48880fe0..5e5da91df6a 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -109,7 +109,7 @@ private: } m_coreUnpackProcess.setWorkingDirectory(TemporaryDirectory::masterDirectoryFilePath()); - connect(&m_coreUnpackProcess, &QtcProcess::done, this, [this] { + connect(&m_coreUnpackProcess, &Process::done, this, [this] { if (m_coreUnpackProcess.error() == QProcess::UnknownError) { reportStopped(); return; @@ -132,7 +132,7 @@ private: appendMessage(msg.arg(m_tempCoreFilePath.toUserOutput()), LogMessageFormat); m_tempCoreFile.setFileName(m_tempCoreFilePath.path()); m_tempCoreFile.open(QFile::WriteOnly); - connect(&m_coreUnpackProcess, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&m_coreUnpackProcess, &Process::readyReadStandardOutput, this, [this] { m_tempCoreFile.write(m_coreUnpackProcess.readAllRawStandardOutput()); }); m_coreUnpackProcess.setCommand({"gzip", {"-c", "-d", m_coreFilePath.path()}}); @@ -148,7 +148,7 @@ private: QFile m_tempCoreFile; FilePath m_coreFilePath; FilePath m_tempCoreFilePath; - QtcProcess m_coreUnpackProcess; + Process m_coreUnpackProcess; }; class DebuggerRunToolPrivate diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index 276d0c685f1..db5d8698ded 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -420,7 +420,7 @@ static QString findQtInstallPath(const FilePath &qmakePath) { if (qmakePath.isEmpty()) return QString(); - QtcProcess proc; + Process proc; proc.setCommand({qmakePath, {"-query", "QT_INSTALL_HEADERS"}}); proc.start(); if (!proc.waitForFinished()) { diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index d02b356a95b..6068294e40e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -146,13 +146,13 @@ GdbEngine::GdbEngine() connect(&s.useDynamicType, &BaseAspect::changed, this, &GdbEngine::reloadLocals); - connect(&m_gdbProc, &QtcProcess::started, + connect(&m_gdbProc, &Process::started, this, &GdbEngine::handleGdbStarted); - connect(&m_gdbProc, &QtcProcess::done, + connect(&m_gdbProc, &Process::done, this, &GdbEngine::handleGdbDone); - connect(&m_gdbProc, &QtcProcess::readyReadStandardOutput, + connect(&m_gdbProc, &Process::readyReadStandardOutput, this, &GdbEngine::readGdbStandardOutput); - connect(&m_gdbProc, &QtcProcess::readyReadStandardError, + connect(&m_gdbProc, &Process::readyReadStandardError, this, &GdbEngine::readGdbStandardError); // Output @@ -4305,7 +4305,7 @@ void GdbEngine::interruptLocalInferior(qint64 pid) if (runParameters().runAsRoot) { Environment env = Environment::systemEnvironment(); RunControl::provideAskPassEntry(env); - QtcProcess proc; + Process proc; proc.setCommand(CommandLine{"sudo", {"-A", "kill", "-s", "SIGINT", QString::number(pid)}}); proc.setEnvironment(env); proc.start(); @@ -5046,7 +5046,7 @@ CoreInfo CoreInfo::readExecutableNameFromCore(const Runnable &debugger, const Fi args += {"-ex", "set osabi GNU/Linux"}; args += {"-ex", "core " + coreFile.toUserOutput()}; - QtcProcess proc; + Process proc; Environment envLang(Environment::systemEnvironment()); envLang.setupEnglishOutput(); proc.setEnvironment(envLang); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 5e84366b649..6a6e68991b5 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -405,7 +405,7 @@ private: ////////// General Interface ////////// bool usesOutputCollector() const; - Utils::QtcProcess m_gdbProc; + Utils::Process m_gdbProc; OutputCollector m_outputCollector; QString m_errorString; }; diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index a930465b68b..91ef914c553 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -77,11 +77,11 @@ LldbEngine::LldbEngine() connect(&ds.useDynamicType, &BaseAspect::changed, this, &LldbEngine::updateLocals); connect(&ds.intelFlavor, &BaseAspect::changed, this, &LldbEngine::updateAll); - connect(&m_lldbProc, &QtcProcess::started, this, &LldbEngine::handleLldbStarted); - connect(&m_lldbProc, &QtcProcess::done, this, &LldbEngine::handleLldbDone); - connect(&m_lldbProc, &QtcProcess::readyReadStandardOutput, + connect(&m_lldbProc, &Process::started, this, &LldbEngine::handleLldbStarted); + connect(&m_lldbProc, &Process::done, this, &LldbEngine::handleLldbDone); + connect(&m_lldbProc, &Process::readyReadStandardOutput, this, &LldbEngine::readLldbStandardOutput); - connect(&m_lldbProc, &QtcProcess::readyReadStandardError, + connect(&m_lldbProc, &Process::readyReadStandardError, this, &LldbEngine::readLldbStandardError); connect(this, &LldbEngine::outputReady, @@ -187,7 +187,7 @@ void LldbEngine::setupEngine() // LLDB 14 installation on Ubuntu 22.04 is broken: // https://bugs.launchpad.net/ubuntu/+source/llvm-defaults/+bug/1972855 // Brush over it: - QtcProcess lldbPythonPathFinder; + Process lldbPythonPathFinder; lldbPythonPathFinder.setCommand({lldbCmd, {"-P"}}); lldbPythonPathFinder.start(); lldbPythonPathFinder.waitForFinished(); diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 8c0396ba509..2f5fe0d7688 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -113,7 +113,7 @@ private: QString m_inbuffer; QString m_scriptFileName; - Utils::QtcProcess m_lldbProc; + Utils::Process m_lldbProc; // FIXME: Make generic. int m_lastAgentId = 0; diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 6e7496bd37d..a904e1d7897 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -174,7 +174,7 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) moduleNameValid && !modulePath.needsDevice() && modulePath.exists() && dependsCanBeFound(), [modulePath] { - QtcProcess::startDetached({{"depends"}, {modulePath.toString()}}); + Process::startDetached({{"depends"}, {modulePath.toString()}}); }); addAction(this, menu, Tr::tr("Load Symbols for All Modules"), diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 4435409506b..54a347fb151 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -99,10 +99,10 @@ void PdbEngine::setupEngine() m_interpreter = runParameters().interpreter; QString bridge = ICore::resourcePath("debugger/pdbbridge.py").toString(); - connect(&m_proc, &QtcProcess::started, this, &PdbEngine::handlePdbStarted); - connect(&m_proc, &QtcProcess::done, this, &PdbEngine::handlePdbDone); - connect(&m_proc, &QtcProcess::readyReadStandardOutput, this, &PdbEngine::readPdbStandardOutput); - connect(&m_proc, &QtcProcess::readyReadStandardError, this, &PdbEngine::readPdbStandardError); + connect(&m_proc, &Process::started, this, &PdbEngine::handlePdbStarted); + connect(&m_proc, &Process::done, this, &PdbEngine::handlePdbDone); + connect(&m_proc, &Process::readyReadStandardOutput, this, &PdbEngine::readPdbStandardOutput); + connect(&m_proc, &Process::readyReadStandardError, this, &PdbEngine::readPdbStandardError); const FilePath scriptFile = runParameters().mainScript; if (!scriptFile.isReadableFile()) { diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index c4003884578..49dceb24417 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -87,7 +87,7 @@ private: void updateLocals() override; QString m_inbuffer; - Utils::QtcProcess m_proc; + Utils::Process m_proc; Utils::FilePath m_interpreter; }; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 0730caaf78f..096ddc13264 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -200,7 +200,7 @@ public: QHash sourceDocuments; InteractiveInterpreter interpreter; - QtcProcess process; + Process process; QmlInspectorAgent inspectorAgent; QList queryIds; @@ -249,17 +249,17 @@ QmlEngine::QmlEngine() connect(stackHandler(), &StackHandler::currentIndexChanged, this, &QmlEngine::updateCurrentContext); - connect(&d->process, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&d->process, &Process::readyReadStandardOutput, this, [this] { // FIXME: Redirect to RunControl showMessage(d->process.readAllStandardOutput(), AppOutput); }); - connect(&d->process, &QtcProcess::readyReadStandardError, this, [this] { + connect(&d->process, &Process::readyReadStandardError, this, [this] { // FIXME: Redirect to RunControl showMessage(d->process.readAllStandardError(), AppOutput); }); - connect(&d->process, &QtcProcess::done, this, &QmlEngine::disconnected); - connect(&d->process, &QtcProcess::started, this, &QmlEngine::handleLauncherStarted); + connect(&d->process, &Process::done, this, &QmlEngine::disconnected); + connect(&d->process, &Process::started, this, &QmlEngine::handleLauncherStarted); debuggerConsole()->populateFileFinder(); debuggerConsole()->setScriptEvaluator([this](const QString &expr) { diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index 49048ec1797..4b96d1a0a91 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -174,12 +174,12 @@ void TerminalRunner::start() QTC_ASSERT(!m_stubProc, reportFailure({}); return); Runnable stub = m_stubRunnable(); - m_stubProc = new QtcProcess(this); + m_stubProc = new Process(this); m_stubProc->setTerminalMode(TerminalMode::Debug); - connect(m_stubProc, &QtcProcess::started, + connect(m_stubProc, &Process::started, this, &TerminalRunner::stubStarted); - connect(m_stubProc, &QtcProcess::done, + connect(m_stubProc, &Process::done, this, &TerminalRunner::stubDone); m_stubProc->setEnvironment(stub.environment); diff --git a/src/plugins/debugger/terminal.h b/src/plugins/debugger/terminal.h index b4fa1317c59..cd57e9eea21 100644 --- a/src/plugins/debugger/terminal.h +++ b/src/plugins/debugger/terminal.h @@ -8,7 +8,7 @@ #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace Debugger { @@ -65,7 +65,7 @@ private: void stubStarted(); void stubDone(); - Utils::QtcProcess *m_stubProc = nullptr; + Utils::Process *m_stubProc = nullptr; std::function m_stubRunnable; qint64 m_applicationPid = 0; qint64 m_applicationMainThreadId = 0; diff --git a/src/plugins/docker/dockerapi.cpp b/src/plugins/docker/dockerapi.cpp index 102256fd44a..3ffa59b52b4 100644 --- a/src/plugins/docker/dockerapi.cpp +++ b/src/plugins/docker/dockerapi.cpp @@ -35,7 +35,7 @@ DockerApi *DockerApi::instance() bool DockerApi::canConnect() { - QtcProcess process; + Process process; FilePath dockerExe = dockerClient(); if (dockerExe.isEmpty() || !dockerExe.isExecutableFile()) return false; @@ -43,7 +43,7 @@ bool DockerApi::canConnect() bool result = false; process.setCommand(CommandLine(dockerExe, QStringList{"info"})); - connect(&process, &QtcProcess::done, [&process, &result] { + connect(&process, &Process::done, [&process, &result] { qCInfo(dockerApiLog) << "'docker info' result:\n" << qPrintable(process.allOutput()); if (process.result() == ProcessResult::FinishedWithSuccess) result = true; diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 474bc402e70..64d3dcd6da9 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -97,7 +97,7 @@ public: {} private: - void setupShellProcess(QtcProcess *shellProcess) final + void setupShellProcess(Process *shellProcess) final { shellProcess->setCommand({m_settings->dockerBinaryPath.filePath(), {"container", "start", "-i", "-a", m_containerId}}); @@ -226,7 +226,7 @@ private: // as this object is alive. IDevice::ConstPtr m_device; - QtcProcess m_process; + Process m_process; qint64 m_remotePID = 0; bool m_hasReceivedFirstOutput = false; }; @@ -236,7 +236,7 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva , m_device(std::move(device)) , m_process(this) { - connect(&m_process, &QtcProcess::started, this, [this] { + connect(&m_process, &Process::started, this, [this] { qCDebug(dockerDeviceLog) << "Process started:" << m_process.commandLine(); if (m_setup.m_ptyData.has_value()) { @@ -245,7 +245,7 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva } }); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&m_process, &Process::readyReadStandardOutput, this, [this] { if (m_hasReceivedFirstOutput) emit readyRead(m_process.readAllRawStandardOutput(), {}); @@ -273,12 +273,12 @@ DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePriva m_hasReceivedFirstOutput = true; }); - connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { + connect(&m_process, &Process::readyReadStandardError, this, [this] { if (m_remotePID) emit readyRead({}, m_process.readAllRawStandardError()); }); - connect(&m_process, &QtcProcess::done, this, [this] { + connect(&m_process, &Process::done, this, [this] { qCDebug(dockerDeviceLog) << "Process exited:" << m_process.commandLine() << "with code:" << m_process.resultData().m_exitCode; @@ -437,9 +437,9 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat return; } - QtcProcess *proc = new QtcProcess(d); + Process *proc = new Process(d); - QObject::connect(proc, &QtcProcess::done, [proc] { + QObject::connect(proc, &Process::done, [proc] { if (proc->error() != QProcess::UnknownError && MessageManager::instance()) { MessageManager::writeDisrupting( Tr::tr("Error starting remote shell: %1").arg(proc->errorString())); @@ -558,7 +558,7 @@ void DockerDevicePrivate::stopCurrentContainer() m_shell.reset(); } - QtcProcess proc; + Process proc; proc.setCommand({m_settings->dockerBinaryPath.filePath(), {"container", "stop", m_container}}); m_container.clear(); @@ -662,7 +662,7 @@ QStringList DockerDevicePrivate::createMountArgs() const bool DockerDevicePrivate::isImageAvailable() const { - QtcProcess proc; + Process proc; proc.setCommand( {m_settings->dockerBinaryPath.filePath(), {"image", "list", m_data.repoAndTag(), "--format", "{{.Repository}}:{{.Tag}}"}}); @@ -714,7 +714,7 @@ bool DockerDevicePrivate::createContainer() dockerCreate.addArg(m_data.repoAndTag()); qCDebug(dockerDeviceLog).noquote() << "RUNNING: " << dockerCreate.toUserOutput(); - QtcProcess createProcess; + Process createProcess; createProcess.setCommand(dockerCreate); createProcess.runBlocking(); @@ -930,7 +930,7 @@ void DockerDevicePrivate::fetchSystemEnviroment() return; } - QtcProcess proc; + Process proc; proc.setCommand(withDockerExecCmd({"env", {}})); proc.start(); proc.waitForFinished(); @@ -1061,10 +1061,10 @@ public: {"images", "--format", "{{.ID}}\\t{{.Repository}}\\t{{.Tag}}\\t{{.Size}}"}}; m_log->append(Tr::tr("Running \"%1\"\n").arg(cmd.toUserOutput())); - m_process = new QtcProcess(this); + m_process = new Process(this); m_process->setCommand(cmd); - connect(m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(m_process, &Process::readyReadStandardOutput, this, [this] { const QString out = m_process->readAllStandardOutput().trimmed(); m_log->append(out); for (const QString &line : out.split('\n')) { @@ -1083,12 +1083,12 @@ public: m_log->append(Tr::tr("Done.")); }); - connect(m_process, &Utils::QtcProcess::readyReadStandardError, this, [this] { + connect(m_process, &Utils::Process::readyReadStandardError, this, [this] { const QString out = Tr::tr("Error: %1").arg(m_process->cleanedStdErr()); m_log->append(Tr::tr("Error: %1").arg(out)); }); - connect(m_process, &QtcProcess::done, errorLabel, [errorLabel, this, statusLabel] { + connect(m_process, &Process::done, errorLabel, [errorLabel, this, statusLabel] { delete statusLabel; if (m_process->result() == ProcessResult::FinishedWithSuccess) m_view->setEnabled(true); @@ -1126,7 +1126,7 @@ public: QDialogButtonBox *m_buttons; DockerSettings *m_settings; - QtcProcess *m_process = nullptr; + Process *m_process = nullptr; QString m_selectedId; }; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 0ac0244ff6b..b13ff9dfcef 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1889,7 +1889,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) }); handler->processOutput.set([](const QString &command, const QString &input, QString *output) { - QtcProcess proc; + Process proc; proc.setCommand(Utils::CommandLine::fromUserInput(command)); proc.setWriteData(input.toLocal8Bit()); proc.start(); diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index f10b6abd224..275b00efbbe 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -421,7 +421,7 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) d->currentDateTime = dateTime; }); - const auto setupForEachRef = [=](QtcProcess &process) { + const auto setupForEachRef = [=](Process &process) { d->workingDirectory = workingDirectory; QStringList args = {"for-each-ref", "--format=%(objectname)\t%(refname)\t%(upstream:short)\t" @@ -433,7 +433,7 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) d->client->setupCommand(process, workingDirectory, args); }; - const auto forEachRefDone = [=](const QtcProcess &process) { + const auto forEachRefDone = [=](const Process &process) { const QString output = process.stdOut(); const QStringList lines = output.split('\n'); for (const QString &l : lines) @@ -454,7 +454,7 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) } }; - const auto forEachRefError = [=](const QtcProcess &process) { + const auto forEachRefError = [=](const Process &process) { if (showError == ShowError::No) return; const QString message = Tr::tr("Cannot run \"%1\" in \"%2\": %3") @@ -919,12 +919,12 @@ void BranchModel::updateUpstreamStatus(BranchNode *node) if (node->tracking.isEmpty()) return; - QtcProcess *process = new QtcProcess(node); + Process *process = new Process(node); process->setEnvironment(d->client->processEnvironment()); process->setCommand({d->client->vcsBinary(), {"rev-list", "--no-color", "--left-right", "--count", node->fullRef() + "..." + node->tracking}}); process->setWorkingDirectory(d->workingDirectory); - connect(process, &QtcProcess::done, this, [this, process, node] { + connect(process, &Process::done, this, [this, process, node] { process->deleteLater(); if (process->result() != ProcessResult::FinishedWithSuccess) return; diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index 34f9b546cd3..ce3bca34858 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -542,10 +542,10 @@ TaskTree *BranchView::onFastForwardMerge(const std::function &callback) const TreeStorage storage; GitClient *client = GitClient::instance(); - const auto setupMergeBase = [=](QtcProcess &process) { + const auto setupMergeBase = [=](Process &process) { client->setupCommand(process, m_repository, {"merge-base", "HEAD", branch}); }; - const auto onMergeBaseDone = [storage](const QtcProcess &process) { + const auto onMergeBaseDone = [storage](const Process &process) { storage->mergeBase = process.cleanedStdOut().trimmed(); }; diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp index aba7be1ad2c..2f93a2c7a16 100644 --- a/src/plugins/git/changeselectiondialog.cpp +++ b/src/plugins/git/changeselectiondialog.cpp @@ -209,12 +209,12 @@ void ChangeSelectionDialog::recalculateCompletion() return; GitClient *client = GitClient::instance(); - QtcProcess *process = new QtcProcess(this); + Process *process = new Process(this); process->setEnvironment(client->processEnvironment()); process->setCommand({client->vcsBinary(), {"for-each-ref", "--format=%(refname:short)"}}); process->setWorkingDirectory(workingDir); process->setUseCtrlCStub(true); - connect(process, &QtcProcess::done, this, [this, process] { + connect(process, &Process::done, this, [this, process] { if (process->result() == ProcessResult::FinishedWithSuccess) m_changeModel->setStringList(process->cleanedStdOut().split('\n')); process->deleteLater(); @@ -238,8 +238,8 @@ void ChangeSelectionDialog::recalculateDetails() return; } - m_process.reset(new QtcProcess); - connect(m_process.get(), &QtcProcess::done, this, &ChangeSelectionDialog::setDetails); + m_process.reset(new Process); + connect(m_process.get(), &Process::done, this, &ChangeSelectionDialog::setDetails); m_process->setWorkingDirectory(workingDir); m_process->setEnvironment(m_gitEnvironment); m_process->setCommand({m_gitExecutable, {"show", "--decorate", "--stat=80", ref}}); diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h index 69da3b20d43..24bc3155dc9 100644 --- a/src/plugins/git/changeselectiondialog.h +++ b/src/plugins/git/changeselectiondialog.h @@ -18,7 +18,7 @@ QT_END_NAMESPACE namespace Utils { class CompletingLineEdit; class PathChooser; -class QtcProcess; +class Process; } // Utils namespace Git::Internal { @@ -53,7 +53,7 @@ private: void enableButtons(bool b); - std::unique_ptr m_process; + std::unique_ptr m_process; Utils::FilePath m_gitExecutable; Utils::Environment m_gitEnvironment; ChangeCommand m_command = NoCommand; diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index 8273fe0f096..4791a41d4f5 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -227,7 +227,7 @@ private: void errorTermination(const QString &msg); - QtcProcess m_process; + Process m_process; QTimer m_timer; FilePath m_binary; QByteArray m_output; @@ -259,15 +259,15 @@ QueryContext::QueryContext(const QString &query, + "&o=CURRENT_REVISION&o=DETAILED_LABELS&o=DETAILED_ACCOUNTS"; m_arguments = server.curlArguments() << url; } - connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { + connect(&m_process, &Process::readyReadStandardError, this, [this] { const QString text = QString::fromLocal8Bit(m_process.readAllRawStandardError()); VcsOutputWindow::appendError(text); m_error.append(text); }); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&m_process, &Process::readyReadStandardOutput, this, [this] { m_output.append(m_process.readAllRawStandardOutput()); }); - connect(&m_process, &QtcProcess::done, this, &QueryContext::processDone); + connect(&m_process, &Process::done, this, &QueryContext::processDone); m_process.setEnvironment(Git::Internal::GitClient::instance()->processEnvironment()); m_timer.setInterval(timeOutMS); @@ -340,7 +340,7 @@ void QueryContext::timeout() arg(timeOutMS / 1000), QMessageBox::NoButton, parent); QPushButton *terminateButton = box.addButton(Git::Tr::tr("Terminate"), QMessageBox::YesRole); box.addButton(Git::Tr::tr("Keep Running"), QMessageBox::NoRole); - connect(&m_process, &QtcProcess::done, &box, &QDialog::reject); + connect(&m_process, &Process::done, &box, &QDialog::reject); box.exec(); if (m_process.state() != QProcess::Running) return; diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 41fa83731f9..0f5a393b1de 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -78,7 +78,7 @@ private: const FetchMode m_fetchMode; const Utils::FilePath m_git; const GerritServer m_server; - QtcProcess m_process; + Process m_process; }; FetchContext::FetchContext(const QSharedPointer &change, @@ -93,11 +93,11 @@ FetchContext::FetchContext(const QSharedPointer &change, , m_server(server) { m_process.setUseCtrlCStub(true); - connect(&m_process, &QtcProcess::done, this, &FetchContext::processDone); - connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { + connect(&m_process, &Process::done, this, &FetchContext::processDone); + connect(&m_process, &Process::readyReadStandardError, this, [this] { VcsBase::VcsOutputWindow::append(QString::fromLocal8Bit(m_process.readAllRawStandardError())); }); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&m_process, &Process::readyReadStandardOutput, this, [this] { VcsBase::VcsOutputWindow::append(QString::fromLocal8Bit(m_process.readAllRawStandardOutput())); }); m_process.setWorkingDirectory(repository); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 14235cbe001..ab5c8cc58a8 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -165,12 +165,12 @@ GitDiffEditorController::GitDiffEditorController(IDocument *document, const TreeStorage diffInputStorage = inputStorage(); - const auto setupDiff = [=](QtcProcess &process) { + const auto setupDiff = [=](Process &process) { process.setCodec(VcsBaseEditor::getCodec(workingDirectory(), {})); setupCommand(process, {addConfigurationArguments(diffArgs(leftCommit, rightCommit, extraArgs))}); VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); }; - const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { + const auto onDiffDone = [diffInputStorage](const Process &process) { *diffInputStorage = process.cleanedStdOut(); }; @@ -231,7 +231,7 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin const TreeStorage storage; const TreeStorage diffInputStorage = inputStorage(); - const auto setupStaged = [this, stagedFiles](QtcProcess &process) { + const auto setupStaged = [this, stagedFiles](Process &process) { if (stagedFiles.isEmpty()) return TaskAction::StopWithError; process.setCodec(VcsBaseEditor::getCodec(workingDirectory(), stagedFiles)); @@ -240,11 +240,11 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); return TaskAction::Continue; }; - const auto onStagedDone = [storage](const QtcProcess &process) { + const auto onStagedDone = [storage](const Process &process) { storage->m_stagedOutput = process.cleanedStdOut(); }; - const auto setupUnstaged = [this, unstagedFiles](QtcProcess &process) { + const auto setupUnstaged = [this, unstagedFiles](Process &process) { if (unstagedFiles.isEmpty()) return TaskAction::StopWithError; process.setCodec(VcsBaseEditor::getCodec(workingDirectory(), unstagedFiles)); @@ -253,7 +253,7 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); return TaskAction::Continue; }; - const auto onUnstagedDone = [storage](const QtcProcess &process) { + const auto onUnstagedDone = [storage](const Process &process) { storage->m_unstagedOutput = process.cleanedStdOut(); }; @@ -321,13 +321,13 @@ ShowController::ShowController(IDocument *document, const QString &id) setDescription(desc); }; - const auto setupDescription = [this, id](QtcProcess &process) { + const auto setupDescription = [this, id](Process &process) { process.setCodec(m_instance->encoding(GitClient::EncodingCommit, workingDirectory())); setupCommand(process, {"show", "-s", noColorOption, showFormatC, id}); VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); setDescription(Tr::tr("Waiting for data...")); }; - const auto onDescriptionDone = [this, storage, updateDescription](const QtcProcess &process) { + const auto onDescriptionDone = [this, storage, updateDescription](const Process &process) { ReloadStorage *data = storage.activeStorage(); const QString output = process.cleanedStdOut(); data->m_postProcessDescription = output.startsWith("commit "); @@ -348,12 +348,12 @@ ShowController::ShowController(IDocument *document, const QString &id) return TaskAction::Continue; }; - const auto setupBranches = [this, storage](QtcProcess &process) { + const auto setupBranches = [this, storage](Process &process) { storage->m_branches = busyMessage; setupCommand(process, {"branch", noColorOption, "-a", "--contains", storage->m_commit}); VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); }; - const auto onBranchesDone = [storage, updateDescription](const QtcProcess &process) { + const auto onBranchesDone = [storage, updateDescription](const Process &process) { ReloadStorage *data = storage.activeStorage(); data->m_branches.clear(); const QString remotePrefix = "remotes/"; @@ -391,17 +391,17 @@ ShowController::ShowController(IDocument *document, const QString &id) data->m_branches = data->m_branches.trimmed(); updateDescription(*data); }; - const auto onBranchesError = [storage, updateDescription](const QtcProcess &) { + const auto onBranchesError = [storage, updateDescription](const Process &) { ReloadStorage *data = storage.activeStorage(); data->m_branches.clear(); updateDescription(*data); }; - const auto setupPrecedes = [this, storage](QtcProcess &process) { + const auto setupPrecedes = [this, storage](Process &process) { storage->m_precedes = busyMessage; setupCommand(process, {"describe", "--contains", storage->m_commit}); }; - const auto onPrecedesDone = [storage, updateDescription](const QtcProcess &process) { + const auto onPrecedesDone = [storage, updateDescription](const Process &process) { ReloadStorage *data = storage.activeStorage(); data->m_precedes = process.cleanedStdOut().trimmed(); const int tilde = data->m_precedes.indexOf('~'); @@ -411,7 +411,7 @@ ShowController::ShowController(IDocument *document, const QString &id) data->m_precedes.chop(2); updateDescription(*data); }; - const auto onPrecedesError = [storage, updateDescription](const QtcProcess &) { + const auto onPrecedesError = [storage, updateDescription](const Process &) { ReloadStorage *data = storage.activeStorage(); data->m_precedes.clear(); updateDescription(*data); @@ -427,10 +427,10 @@ ShowController::ShowController(IDocument *document, const QString &id) data->m_follows = {busyMessage}; data->m_follows.resize(parents.size()); - const auto setupFollow = [this](QtcProcess &process, const QString &parent) { + const auto setupFollow = [this](Process &process, const QString &parent) { setupCommand(process, {"describe", "--tags", "--abbrev=0", parent}); }; - const auto onFollowDone = [data, updateDescription](const QtcProcess &process, int index) { + const auto onFollowDone = [data, updateDescription](const Process &process, int index) { data->m_follows[index] = process.cleanedStdOut().trimmed(); updateDescription(*data); }; @@ -448,13 +448,13 @@ ShowController::ShowController(IDocument *document, const QString &id) taskTree.setupRoot(tasks); }; - const auto setupDiff = [this, id](QtcProcess &process) { + const auto setupDiff = [this, id](Process &process) { setupCommand(process, addConfigurationArguments( {"show", "--format=format:", // omit header, already generated noColorOption, decorateOption, id})); VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); }; - const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { + const auto onDiffDone = [diffInputStorage](const Process &process) { *diffInputStorage = process.cleanedStdOut(); }; @@ -1736,10 +1736,10 @@ Utils::Tasking::ProcessTask GitClient::topRevision( { using namespace Tasking; - const auto setupProcess = [=](QtcProcess &process) { + const auto setupProcess = [=](Process &process) { setupCommand(process, workingDirectory, {"show", "-s", "--pretty=format:%H:%ct", HEAD}); }; - const auto onProcessDone = [=](const QtcProcess &process) { + const auto onProcessDone = [=](const Process &process) { const QStringList output = process.cleanedStdOut().trimmed().split(':'); QDateTime dateTime; if (output.size() > 1) { @@ -2424,7 +2424,7 @@ void GitClient::launchRepositoryBrowser(const FilePath &workingDirectory) const { const FilePath repBrowserBinary = settings().repositoryBrowserCmd.filePath(); if (!repBrowserBinary.isEmpty()) - QtcProcess::startDetached({repBrowserBinary, {workingDirectory.toString()}}, workingDirectory); + Process::startDetached({repBrowserBinary, {workingDirectory.toString()}}, workingDirectory); } static FilePath gitBinDir(const GitClient::GitKLaunchTrial trial, const FilePath &parentDir) @@ -2471,18 +2471,18 @@ void GitClient::tryLaunchingGitK(const Environment &env, // This should always use QtcProcess::startDetached (as not to kill // the child), but that does not have an environment parameter. if (!settings().path.value().isEmpty()) { - auto process = new QtcProcess(const_cast(this)); + auto process = new Process(const_cast(this)); process->setWorkingDirectory(workingDirectory); process->setEnvironment(env); process->setCommand({binary, arguments}); - connect(process, &QtcProcess::done, this, [=] { + connect(process, &Process::done, this, [=] { if (process->result() == ProcessResult::StartFailed) handleGitKFailedToStart(env, workingDirectory, fileName, trial, gitBinDirectory); process->deleteLater(); }); process->start(); } else { - if (!QtcProcess::startDetached({binary, arguments}, workingDirectory)) + if (!Process::startDetached({binary, arguments}, workingDirectory)) handleGitKFailedToStart(env, workingDirectory, fileName, trial, gitBinDirectory); } } @@ -2519,7 +2519,7 @@ bool GitClient::launchGitGui(const FilePath &workingDirectory) { if (gitBinary.isEmpty()) { success = false; } else { - success = QtcProcess::startDetached({gitBinary, {"gui"}}, workingDirectory); + success = Process::startDetached({gitBinary, {"gui"}}, workingDirectory); } if (!success) @@ -2564,7 +2564,7 @@ bool GitClient::launchGitBash(const FilePath &workingDirectory) success = false; } else { const FilePath gitBash = git.absolutePath().parentDir() / "git-bash.exe"; - success = QtcProcess::startDetached({gitBash, {}}, workingDirectory); + success = Process::startDetached({gitBash, {}}, workingDirectory); } if (!success) @@ -3466,8 +3466,8 @@ QFuture GitClient::gitVersion() const const FilePath newGitBinary = vcsBinary(); const bool needToRunGit = m_gitVersionForBinary != newGitBinary && !newGitBinary.isEmpty(); if (needToRunGit) { - auto proc = new QtcProcess(const_cast(this)); - connect(proc, &QtcProcess::done, this, [this, proc, fi, newGitBinary]() mutable { + auto proc = new Process(const_cast(this)); + connect(proc, &Process::done, this, [this, proc, fi, newGitBinary]() mutable { if (proc->result() == ProcessResult::FinishedWithSuccess) { m_cachedGitVersion = parseGitVersion(proc->cleanedStdOut()); m_gitVersionForBinary = newGitBinary; diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index cd9c8bf5d6b..2f70cddc822 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -161,7 +161,7 @@ public: }); arguments << "--" << filterArgs << exclusionArgs; - QtcProcess process; + Process process; process.setEnvironment(m_environment); process.setCommand({m_vcsBinary, arguments}); process.setWorkingDirectory(m_directory); diff --git a/src/plugins/git/mergetool.cpp b/src/plugins/git/mergetool.cpp index f696bef124c..6fbc9d5ea83 100644 --- a/src/plugins/git/mergetool.cpp +++ b/src/plugins/git/mergetool.cpp @@ -23,8 +23,8 @@ namespace Git::Internal { MergeTool::MergeTool(QObject *parent) : QObject(parent) { - connect(&m_process, &QtcProcess::done, this, &MergeTool::done); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, &MergeTool::readData); + connect(&m_process, &Process::done, this, &MergeTool::done); + connect(&m_process, &Process::readyReadStandardOutput, this, &MergeTool::readData); Environment env = Environment::systemEnvironment(); env.set("LANG", "C"); env.set("LANGUAGE", "C"); diff --git a/src/plugins/git/mergetool.h b/src/plugins/git/mergetool.h index 290b50f10c3..1fd32e3a4fe 100644 --- a/src/plugins/git/mergetool.h +++ b/src/plugins/git/mergetool.h @@ -49,7 +49,7 @@ private: void chooseAction(); void addButton(QMessageBox *msgBox, const QString &text, char key); - Utils::QtcProcess m_process; + Utils::Process m_process; MergeType m_mergeType = NormalMerge; QString m_fileName; FileState m_localState = UnknownState; diff --git a/src/plugins/gitlab/queryrunner.cpp b/src/plugins/gitlab/queryrunner.cpp index 2ddc86cd091..fd56c68c29d 100644 --- a/src/plugins/gitlab/queryrunner.cpp +++ b/src/plugins/gitlab/queryrunner.cpp @@ -96,7 +96,7 @@ QueryRunner::QueryRunner(const Query &query, const Id &id, QObject *parent) url += query.toString(); args << url; m_process.setCommand({p->curl, args}); - connect(&m_process, &QtcProcess::done, this, [this, id] { + connect(&m_process, &Process::done, this, [this, id] { if (m_process.result() != ProcessResult::FinishedWithSuccess) { const int exitCode = m_process.exitCode(); if (m_process.exitStatus() == QProcess::NormalExit diff --git a/src/plugins/gitlab/queryrunner.h b/src/plugins/gitlab/queryrunner.h index ee698e384f0..bdb5e06034a 100644 --- a/src/plugins/gitlab/queryrunner.h +++ b/src/plugins/gitlab/queryrunner.h @@ -47,7 +47,7 @@ signals: void resultRetrieved(const QByteArray &json); private: - Utils::QtcProcess m_process; + Utils::Process m_process; }; } // namespace GitLab diff --git a/src/plugins/haskell/haskellmanager.cpp b/src/plugins/haskell/haskellmanager.cpp index ac3564f23e0..250b795af79 100644 --- a/src/plugins/haskell/haskellmanager.cpp +++ b/src/plugins/haskell/haskellmanager.cpp @@ -87,11 +87,11 @@ void HaskellManager::openGhci(const FilePath &haskellFile) }); const auto args = QStringList{"ghci"} + (isHaskell ? QStringList{haskellFile.fileName()} : QStringList()); - auto p = new QtcProcess(m_instance); + auto p = new Process(m_instance); p->setTerminalMode(TerminalMode::On); p->setCommand({stackExecutable(), args}); p->setWorkingDirectory(haskellFile.absolutePath()); - connect(p, &QtcProcess::done, p, [p] { + connect(p, &Process::done, p, [p] { if (p->result() != ProcessResult::FinishedWithSuccess) { Core::MessageManager::writeDisrupting( Tr::tr("Failed to run GHCi: \"%1\".").arg(p->errorString())); diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 4ba74298a9b..0eab6b7947a 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -212,7 +212,7 @@ static QByteArray decodeProvisioningProfile(const QString &path) { QTC_ASSERT(!path.isEmpty(), return QByteArray()); - QtcProcess p; + Process p; p.setTimeoutS(3); // path is assumed to be valid file path to .mobileprovision p.setCommand({"openssl", {"smime", "-inform", "der", "-verify", "-in", path}}); diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp index c835e48390e..7b3e977e963 100644 --- a/src/plugins/ios/iosprobe.cpp +++ b/src/plugins/ios/iosprobe.cpp @@ -40,7 +40,7 @@ void XcodeProbe::addDeveloperPath(const QString &path) void XcodeProbe::detectDeveloperPaths() { - Utils::QtcProcess selectedXcode; + Utils::Process selectedXcode; selectedXcode.setTimeoutS(5); selectedXcode.setCommand({"/usr/bin/xcode-select", {"--print-path"}}); selectedXcode.runBlocking(); diff --git a/src/plugins/ios/iossimulator.cpp b/src/plugins/ios/iossimulator.cpp index ceb9fd77859..2caa691c927 100644 --- a/src/plugins/ios/iossimulator.cpp +++ b/src/plugins/ios/iossimulator.cpp @@ -52,7 +52,7 @@ Utils::Port IosSimulator::nextPort() const // use qrand instead? if (++m_lastPort >= Constants::IOS_SIMULATOR_PORT_END) m_lastPort = Constants::IOS_SIMULATOR_PORT_START; - Utils::QtcProcess portVerifier; + Utils::Process portVerifier; // this is a bit too broad (it does not check just listening sockets, but also connections // to that port from this computer) portVerifier.setCommand({"lsof", {"-n", "-P", "-i", QString(":%1").arg(m_lastPort)}}); diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index d3af86365d8..9d50088cd96 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -57,7 +57,7 @@ static bool checkForTimeout(const chrono::high_resolution_clock::time_point &sta static bool runCommand(const CommandLine &command, QString *stdOutput, QString *allOutput = nullptr) { - QtcProcess p; + Process p; p.setTimeoutS(-1); p.setCommand(command); p.runBlocking(); @@ -98,7 +98,7 @@ static bool launchSimulator(const QString &simUdid) { } } - return QtcProcess::startDetached({simulatorAppPath, {"--args", "-CurrentDeviceUDID", simUdid}}); + return Process::startDetached({simulatorAppPath, {"--args", "-CurrentDeviceUDID", simUdid}}); } static bool isAvailable(const QJsonObject &object) diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index 541d1c3ab05..84f4b5ed0a1 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -95,14 +95,14 @@ void StdIOClientInterface::startImpl() QTC_CHECK(!m_process->isRunning()); delete m_process; } - m_process = new QtcProcess; + m_process = new Process; m_process->setProcessMode(ProcessMode::Writer); - connect(m_process, &QtcProcess::readyReadStandardError, + connect(m_process, &Process::readyReadStandardError, this, &StdIOClientInterface::readError); - connect(m_process, &QtcProcess::readyReadStandardOutput, + connect(m_process, &Process::readyReadStandardOutput, this, &StdIOClientInterface::readOutput); - connect(m_process, &QtcProcess::started, this, &StdIOClientInterface::started); - connect(m_process, &QtcProcess::done, this, [this] { + connect(m_process, &Process::started, this, &StdIOClientInterface::started); + connect(m_process, &Process::done, this, [this] { m_logFile.flush(); if (m_process->result() != ProcessResult::FinishedWithSuccess) emit error(QString("%1 (see logs in \"%2\")") diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index e0d4789e1d8..ec1fc8206f9 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -71,7 +71,7 @@ protected: void sendData(const QByteArray &data) final; Utils::CommandLine m_cmd; Utils::FilePath m_workingDirectory; - Utils::QtcProcess *m_process = nullptr; + Utils::Process *m_process = nullptr; Utils::Environment m_env; private: diff --git a/src/plugins/mcusupport/mcusupportversiondetection.cpp b/src/plugins/mcusupport/mcusupportversiondetection.cpp index b31d01d8bc6..2ea28c38525 100644 --- a/src/plugins/mcusupport/mcusupportversiondetection.cpp +++ b/src/plugins/mcusupport/mcusupportversiondetection.cpp @@ -41,7 +41,7 @@ QString McuPackageExecutableVersionDetector::parseVersion(const FilePath &packag return {}; const int timeout = 3000; // usually runs below 1s, but we want to be on the safe side - QtcProcess process; + Process process; process.setCommand({binaryPath, m_detectionArgs}); process.start(); if (!process.waitForFinished(timeout) || process.result() != ProcessResult::FinishedWithSuccess) diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 0eb212f856a..62439896500 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -55,11 +55,11 @@ MercurialDiffEditorController::MercurialDiffEditorController(IDocument *document const TreeStorage diffInputStorage = inputStorage(); - const auto setupDiff = [=](QtcProcess &process) { + const auto setupDiff = [=](Process &process) { setupCommand(process, {addConfigurationArguments(args)}); VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine()); }; - const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { + const auto onDiffDone = [diffInputStorage](const Process &process) { *diffInputStorage = process.cleanedStdOut(); }; diff --git a/src/plugins/mesonprojectmanager/mesonprocess.cpp b/src/plugins/mesonprojectmanager/mesonprocess.cpp index 0c828588c20..5732f617e76 100644 --- a/src/plugins/mesonprojectmanager/mesonprocess.cpp +++ b/src/plugins/mesonprojectmanager/mesonprocess.cpp @@ -63,12 +63,12 @@ void MesonProcess::setupProcess(const Command &command, const Environment &env, { if (m_process) m_process.release()->deleteLater(); - m_process.reset(new QtcProcess); - connect(m_process.get(), &QtcProcess::done, this, &MesonProcess::handleProcessDone); + m_process.reset(new Process); + connect(m_process.get(), &Process::done, this, &MesonProcess::handleProcessDone); if (!captureStdo) { - connect(m_process.get(), &QtcProcess::readyReadStandardOutput, + connect(m_process.get(), &Process::readyReadStandardOutput, this, &MesonProcess::processStandardOutput); - connect(m_process.get(), &QtcProcess::readyReadStandardError, + connect(m_process.get(), &Process::readyReadStandardError, this, &MesonProcess::processStandardError); } diff --git a/src/plugins/mesonprojectmanager/mesonprocess.h b/src/plugins/mesonprojectmanager/mesonprocess.h index 949af3339f0..c01427c8fb9 100644 --- a/src/plugins/mesonprojectmanager/mesonprocess.h +++ b/src/plugins/mesonprojectmanager/mesonprocess.h @@ -12,7 +12,7 @@ namespace Utils { class Environment; -class QtcProcess; +class Process; } namespace MesonProjectManager { @@ -44,7 +44,7 @@ private: void processStandardOutput(); void processStandardError(); - std::unique_ptr m_process; + std::unique_ptr m_process; QElapsedTimer m_elapsed; QByteArray m_stdo; QByteArray m_stderr; diff --git a/src/plugins/mesonprojectmanager/mesonwrapper.h b/src/plugins/mesonprojectmanager/mesonwrapper.h index b229ab65550..668c78bc4cd 100644 --- a/src/plugins/mesonprojectmanager/mesonwrapper.h +++ b/src/plugins/mesonprojectmanager/mesonwrapper.h @@ -35,7 +35,7 @@ bool containsFiles(const QString &path, const File_t &file, const T &...files) inline bool run_meson(const Command &command, QIODevice *output = nullptr) { - Utils::QtcProcess process; + Utils::Process process; process.setWorkingDirectory(command.workDir()); process.setCommand(command.cmdLine()); process.start(); diff --git a/src/plugins/mesonprojectmanager/toolwrapper.cpp b/src/plugins/mesonprojectmanager/toolwrapper.cpp index 9864fd030b6..e3e54ef1b2d 100644 --- a/src/plugins/mesonprojectmanager/toolwrapper.cpp +++ b/src/plugins/mesonprojectmanager/toolwrapper.cpp @@ -40,7 +40,7 @@ void ToolWrapper::setExe(const Utils::FilePath &newExe) Version ToolWrapper::read_version(const Utils::FilePath &toolPath) { if (toolPath.toFileInfo().isExecutable()) { - Utils::QtcProcess process; + Utils::Process process; process.setCommand({ toolPath, { "--version" } }); process.start(); if (process.waitForFinished()) diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp index b1317153a81..f9be804571d 100644 --- a/src/plugins/nim/project/nimblebuildsystem.cpp +++ b/src/plugins/nim/project/nimblebuildsystem.cpp @@ -20,7 +20,7 @@ namespace Nim { const char C_NIMBLEPROJECT_TASKS[] = "Nim.NimbleProject.Tasks"; -static QList linesFromProcessOutput(QtcProcess *process) +static QList linesFromProcessOutput(Process *process) { QList lines = process->readAllRawStandardOutput().split('\n'); lines = Utils::transform(lines, [](const QByteArray &line){ return line.trimmed(); }); @@ -30,7 +30,7 @@ static QList linesFromProcessOutput(QtcProcess *process) static std::vector parseTasks(const FilePath &nimblePath, const FilePath &workingDirectory) { - QtcProcess process; + Process process; process.setCommand({nimblePath, {"tasks"}}); process.setWorkingDirectory(workingDirectory); process.start(); @@ -58,7 +58,7 @@ static std::vector parseTasks(const FilePath &nimblePath, const File static NimbleMetadata parseMetadata(const FilePath &nimblePath, const FilePath &workingDirectory) { - QtcProcess process; + Process process; process.setCommand({nimblePath, {"dump"}}); process.setWorkingDirectory(workingDirectory); process.start(); diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp index b373fc94182..159985f59d4 100644 --- a/src/plugins/nim/project/nimtoolchain.cpp +++ b/src/plugins/nim/project/nimtoolchain.cpp @@ -95,7 +95,7 @@ bool NimToolChain::fromMap(const QVariantMap &data) bool NimToolChain::parseVersion(const FilePath &path, std::tuple &result) { - QtcProcess process; + Process process; process.setCommand({path, {"--version"}}); process.start(); if (!process.waitForFinished()) diff --git a/src/plugins/nim/suggest/server.cpp b/src/plugins/nim/suggest/server.cpp index b891404fe8c..7573505f727 100644 --- a/src/plugins/nim/suggest/server.cpp +++ b/src/plugins/nim/suggest/server.cpp @@ -10,8 +10,8 @@ namespace Suggest { NimSuggestServer::NimSuggestServer(QObject *parent) : QObject(parent) { - connect(&m_process, &QtcProcess::done, this, &NimSuggestServer::onDone); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, + connect(&m_process, &Process::done, this, &NimSuggestServer::onDone); + connect(&m_process, &Process::readyReadStandardOutput, this, &NimSuggestServer::onStandardOutputAvailable); } diff --git a/src/plugins/nim/suggest/server.h b/src/plugins/nim/suggest/server.h index 9d8e880663b..a9f7d49b889 100644 --- a/src/plugins/nim/suggest/server.h +++ b/src/plugins/nim/suggest/server.h @@ -36,7 +36,7 @@ private: void clearState(); bool m_portAvailable = false; - Utils::QtcProcess m_process; + Utils::Process m_process; quint16 m_port = 0; QString m_projectFilePath; QString m_executablePath; diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp index fc2aeae3e1e..f9a5b5df38b 100644 --- a/src/plugins/perforce/perforcechecker.cpp +++ b/src/plugins/perforce/perforcechecker.cpp @@ -21,7 +21,7 @@ namespace Internal { PerforceChecker::PerforceChecker(QObject *parent) : QObject(parent) { - connect(&m_process, &QtcProcess::done, this, &PerforceChecker::slotDone); + connect(&m_process, &Process::done, this, &PerforceChecker::slotDone); } PerforceChecker::~PerforceChecker() diff --git a/src/plugins/perforce/perforcechecker.h b/src/plugins/perforce/perforcechecker.h index e9325b4cedd..5f7d2b16739 100644 --- a/src/plugins/perforce/perforcechecker.h +++ b/src/plugins/perforce/perforcechecker.h @@ -44,7 +44,7 @@ private: void parseOutput(const QString &); inline void resetOverrideCursor(); - Utils::QtcProcess m_process; + Utils::Process m_process; Utils::FilePath m_binary; int m_timeOutMS = -1; bool m_timedOut = false; diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index ccd4faec162..336ee8e7dc4 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -1225,7 +1225,7 @@ PerforceResponse PerforcePluginPrivate::synchronousProcess(const FilePath &worki QTC_ASSERT(stdInput.isEmpty(), return PerforceResponse()); // Not supported here // Run, connect stderr to the output window - QtcProcess process; + Process process; const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS.value(); process.setTimeoutS(timeOutS); if (outputCodec) @@ -1283,7 +1283,7 @@ PerforceResponse PerforcePluginPrivate::fullySynchronousProcess(const FilePath & const QByteArray &stdInput, QTextCodec *outputCodec) const { - QtcProcess process; + Process process; if (flags & OverrideDiffEnvironment) process.setEnvironment(overrideDiffEnvironmentVariable()); diff --git a/src/plugins/perfprofiler/perfconfigwidget.cpp b/src/plugins/perfprofiler/perfconfigwidget.cpp index 68c86ff720b..eed31e373a2 100644 --- a/src/plugins/perfprofiler/perfconfigwidget.cpp +++ b/src/plugins/perfprofiler/perfconfigwidget.cpp @@ -120,9 +120,9 @@ void PerfConfigWidget::setTarget(ProjectExplorer::Target *target) QTC_ASSERT(device, return); QTC_CHECK(!m_process || m_process->state() == QProcess::NotRunning); - m_process.reset(new QtcProcess); + m_process.reset(new Process); m_process->setCommand({device->filePath("perf"), {"probe", "-l"}}); - connect(m_process.get(), &QtcProcess::done, + connect(m_process.get(), &Process::done, this, &PerfConfigWidget::handleProcessDone); useTracePointsButton->setEnabled(true); diff --git a/src/plugins/perfprofiler/perfconfigwidget.h b/src/plugins/perfprofiler/perfconfigwidget.h index 3fc65c47534..5372647064e 100644 --- a/src/plugins/perfprofiler/perfconfigwidget.h +++ b/src/plugins/perfprofiler/perfconfigwidget.h @@ -14,7 +14,7 @@ class QPushButton; class QTableView; QT_END_NAMESPACE -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace PerfProfiler { namespace Internal { @@ -37,7 +37,7 @@ private: void handleProcessDone(); PerfSettings *m_settings; - std::unique_ptr m_process; + std::unique_ptr m_process; QTableView *eventsView; QPushButton *useTracePointsButton; diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index d14bfb87cde..68ba9e883f3 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -105,10 +105,10 @@ public: void start() override { - m_process = new QtcProcess(this); + m_process = new Process(this); - connect(m_process, &QtcProcess::started, this, &RunWorker::reportStarted); - connect(m_process, &QtcProcess::done, this, [this] { + connect(m_process, &Process::started, this, &RunWorker::reportStarted); + connect(m_process, &Process::done, this, [this] { // The terminate() below will frequently lead to QProcess::Crashed. We're not interested // in that. FailedToStart is the only actual failure. if (m_process->error() == QProcess::FailedToStart) { @@ -141,10 +141,10 @@ public: m_process->terminate(); } - QtcProcess *recorder() { return m_process; } + Process *recorder() { return m_process; } private: - QPointer m_process; + QPointer m_process; QStringList m_perfRecordArguments; }; @@ -193,12 +193,12 @@ void PerfProfilerRunner::start() PerfDataReader *reader = m_perfParserWorker->reader(); if (auto prw = qobject_cast(m_perfRecordWorker)) { // That's the local case. - QtcProcess *recorder = prw->recorder(); - connect(recorder, &QtcProcess::readyReadStandardError, this, [this, recorder] { + Process *recorder = prw->recorder(); + connect(recorder, &Process::readyReadStandardError, this, [this, recorder] { appendMessage(QString::fromLocal8Bit(recorder->readAllRawStandardError()), Utils::StdErrFormat); }); - connect(recorder, &QtcProcess::readyReadStandardOutput, this, [this, reader, recorder] { + connect(recorder, &Process::readyReadStandardOutput, this, [this, reader, recorder] { if (!reader->feedParser(recorder->readAllRawStandardOutput())) reportFailure(Tr::tr("Failed to transfer Perf data to perfparser.")); }); diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index 1a2e2c346ad..004f9aa0e15 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -93,7 +93,7 @@ void PerfTracePointDialog::runScript() m_privilegesChooser->setEnabled(false); m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - m_process.reset(new QtcProcess(this)); + m_process.reset(new Process(this)); m_process->setWriteData(m_textEdit->toPlainText().toUtf8()); m_textEdit->clear(); @@ -103,7 +103,7 @@ void PerfTracePointDialog::runScript() else m_process->setCommand({m_device->filePath("sh"), {}}); - connect(m_process.get(), &QtcProcess::done, this, &PerfTracePointDialog::handleProcessDone); + connect(m_process.get(), &Process::done, this, &PerfTracePointDialog::handleProcessDone); m_process->start(); } diff --git a/src/plugins/perfprofiler/perftracepointdialog.h b/src/plugins/perfprofiler/perftracepointdialog.h index 427220e64e5..d5affdcc7cb 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.h +++ b/src/plugins/perfprofiler/perftracepointdialog.h @@ -15,7 +15,7 @@ class QLabel; class QTextEdit; QT_END_NAMESPACE -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace PerfProfiler { namespace Internal { @@ -40,7 +40,7 @@ private: QComboBox *m_privilegesChooser; QDialogButtonBox *m_buttonBox; ProjectExplorer::IDeviceConstPtr m_device; - std::unique_ptr m_process; + std::unique_ptr m_process; void accept() final; void reject() final; diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index 30036fcdc5c..eca8b5c44f4 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -76,7 +76,7 @@ public: void cleanUp(int exitCode, QProcess::ExitStatus status); AbstractProcessStep *q; - std::unique_ptr m_process; + std::unique_ptr m_process; std::unique_ptr m_taskTree; ProcessParameters m_param; ProcessParameters *m_displayedParams = &m_param; @@ -182,9 +182,9 @@ void AbstractProcessStep::doRun() setupStreams(); - d->m_process.reset(new QtcProcess); + d->m_process.reset(new Process); setupProcess(d->m_process.get()); - connect(d->m_process.get(), &QtcProcess::done, this, &AbstractProcessStep::handleProcessDone); + connect(d->m_process.get(), &Process::done, this, &AbstractProcessStep::handleProcessDone); d->m_process->start(); } @@ -209,7 +209,7 @@ void AbstractProcessStep::setupStreams() d->stderrStream = std::make_unique(QTextCodec::codecForLocale()); } -void AbstractProcessStep::setupProcess(QtcProcess *process) +void AbstractProcessStep::setupProcess(Process *process) { process->setUseCtrlCStub(HostOsInfo::isWindowsHost()); process->setWorkingDirectory(d->m_param.effectiveWorkingDirectory()); @@ -224,15 +224,15 @@ void AbstractProcessStep::setupProcess(QtcProcess *process) if (d->m_lowPriority && ProjectExplorerPlugin::projectExplorerSettings().lowBuildPriority) process->setLowPriority(); - connect(process, &QtcProcess::readyReadStandardOutput, this, [this, process] { + connect(process, &Process::readyReadStandardOutput, this, [this, process] { emit addOutput(d->stdoutStream->toUnicode(process->readAllRawStandardOutput()), OutputFormat::Stdout, DontAppendNewline); }); - connect(process, &QtcProcess::readyReadStandardError, this, [this, process] { + connect(process, &Process::readyReadStandardError, this, [this, process] { emit addOutput(d->stderrStream->toUnicode(process->readAllRawStandardError()), OutputFormat::Stderr, DontAppendNewline); }); - connect(process, &QtcProcess::started, this, [this] { + connect(process, &Process::started, this, [this] { ProcessParameters *params = displayedParameters(); emit addOutput(Tr::tr("Starting: \"%1\" %2") .arg(params->effectiveCommand().toUserOutput(), params->prettyArguments()), diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h index 81125414471..d8050b66a89 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.h +++ b/src/plugins/projectexplorer/abstractprocessstep.h @@ -10,7 +10,7 @@ namespace Utils { class CommandLine; enum class ProcessResult; -class QtcProcess; +class Process; namespace Tasking { class Group; } } @@ -51,7 +51,7 @@ protected: virtual void finish(Utils::ProcessResult result); bool checkWorkingDirectory(); - void setupProcess(Utils::QtcProcess *process); + void setupProcess(Utils::Process *process); void runTaskTree(const Utils::Tasking::Group &recipe); ProcessParameters *displayedParameters() const; diff --git a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp index f2b33378b53..34ab30442d3 100644 --- a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp @@ -64,7 +64,7 @@ static bool const QMap &fieldMap, QString *stdOut /* = 0 */, QString *errorMessage) { - Utils::QtcProcess process; + Utils::Process process; const QString binary = script.front(); QStringList arguments; const int binarySize = script.size(); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 2ac44ad6220..82734cf6a9f 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -61,8 +61,8 @@ DesktopDevice::DesktopDevice() const FilePath shell = Terminal::defaultShellForDevice(path); - QtcProcess *process = new QtcProcess(d.get()); - QObject::connect(process, &QtcProcess::done, process, &QtcProcess::deleteLater); + Process *process = new Process(d.get()); + QObject::connect(process, &Process::done, process, &Process::deleteLater); process->setTerminalMode(TerminalMode::On); process->setEnvironment(realEnv); diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index ff3baf6148a..8973a7baf60 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -464,7 +464,7 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_uniquesystemEnvironment(); }; - QtcProcess::setRemoteProcessHooks(processHooks); + Process::setRemoteProcessHooks(processHooks); Terminal::Hooks::instance().getTerminalCommandsForDevicesHook().set( [this]() -> QList { diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp index 8081c9745df..b04397a66b9 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp @@ -22,7 +22,7 @@ namespace Internal { class DeviceUsedPortsGathererPrivate { public: - std::unique_ptr process; + std::unique_ptr process; QList usedPorts; IDevice::ConstPtr device; PortsGatheringMethod portsGatheringMethod; @@ -54,10 +54,10 @@ void DeviceUsedPortsGatherer::start() const QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::AnyIPProtocol; - d->process.reset(new QtcProcess); + d->process.reset(new Process); d->process->setCommand(d->portsGatheringMethod.commandLine(protocol)); - connect(d->process.get(), &QtcProcess::done, this, &DeviceUsedPortsGatherer::handleProcessDone); + connect(d->process.get(), &Process::done, this, &DeviceUsedPortsGatherer::handleProcessDone); d->process->start(); } diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 9c2dc2122f8..04c1facf41e 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -35,7 +35,7 @@ class Icon; class PortList; class Port; class ProcessInterface; -class QtcProcess; +class Process; } // Utils namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp index 2ab8aa006ea..8b67f300dbb 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp @@ -69,7 +69,7 @@ QStringList SshParameters::connectionOptions(const FilePath &binary) const return args; } -bool SshParameters::setupSshEnvironment(QtcProcess *process) +bool SshParameters::setupSshEnvironment(Process *process) { Environment env = process->controlEnvironment(); if (!env.hasChanges()) diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.h b/src/plugins/projectexplorer/devicesupport/sshparameters.h index 8bdd936d275..3ee483d5f3d 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.h +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.h @@ -7,7 +7,7 @@ #include -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace ProjectExplorer { @@ -45,7 +45,7 @@ public: AuthenticationType authenticationType = AuthenticationTypeAll; SshHostKeyCheckingMode hostKeyCheckingMode = SshHostKeyCheckingAllowNoMatch; - static bool setupSshEnvironment(Utils::QtcProcess *process); + static bool setupSshEnvironment(Utils::Process *process); friend PROJECTEXPLORER_EXPORT bool operator==(const SshParameters &p1, const SshParameters &p2); friend bool operator!=(const SshParameters &p1, const SshParameters &p2) { return !(p1 == p2); } diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index a220f1906fa..e60d6cb5d16 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -381,7 +381,7 @@ void ProcessExtraCompiler::runInThread(QPromise &promise if (sourceContents.isNull() || !prepareToRun(sourceContents)) return; - QtcProcess process; + Process process; process.setEnvironment(env); if (!workDir.isEmpty()) diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h index 889a79f858e..323fbb139d3 100644 --- a/src/plugins/projectexplorer/extracompiler.h +++ b/src/plugins/projectexplorer/extracompiler.h @@ -25,7 +25,7 @@ class QPromise; class QThreadPool; QT_END_NAMESPACE -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } namespace ProjectExplorer { @@ -96,7 +96,7 @@ protected: virtual bool prepareToRun(const QByteArray &sourceContents); - virtual FileNameToContentsHash handleProcessFinished(Utils::QtcProcess *process) = 0; + virtual FileNameToContentsHash handleProcessFinished(Utils::Process *process) = 0; virtual Tasks parseIssues(const QByteArray &stdErr); diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 7212e24dd5d..40a97737db3 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -119,7 +119,7 @@ static QString runGcc(const FilePath &gcc, const QStringList &arguments, const E if (!gcc.isExecutableFile()) return {}; - QtcProcess cpp; + Process cpp; Environment environment(env); environment.setupEnglishOutput(); @@ -1570,7 +1570,7 @@ bool ClangToolChain::matchesCompilerCommand(const FilePath &command) const m_resolvedCompilerCommand = FilePath(); if (HostOsInfo::isMacHost() && compilerCommand().parentDir() == FilePath::fromString("/usr/bin")) { - QtcProcess xcrun; + Process xcrun; xcrun.setCommand({"/usr/bin/xcrun", {"-f", compilerCommand().fileName()}}); xcrun.runBlocking(); const FilePath output = FilePath::fromString(xcrun.cleanedStdOut().trimmed()); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index d8cc0f7cff6..87547b2a79a 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -255,7 +255,7 @@ static std::optional detectCppBuildTools2017() static QVector detectVisualStudioFromVsWhere(const QString &vswhere) { QVector installations; - QtcProcess vsWhereProcess; + Process vsWhereProcess; vsWhereProcess.setCodec(QTextCodec::codecForName("UTF-8")); const int timeoutS = 5; vsWhereProcess.setTimeoutS(timeoutS); @@ -649,7 +649,7 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList &cxxflags, qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString())); return predefinedMacros; } - Utils::QtcProcess cpp; + Utils::Process cpp; cpp.setEnvironment(env); cpp.setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryFilePath()); QStringList arguments; @@ -1555,7 +1555,7 @@ static QVersionNumber clangClVersion(const FilePath &clangClPath) if (!dllversion.isEmpty()) return QVersionNumber::fromString(dllversion); - QtcProcess clangClProcess; + Process clangClProcess; clangClProcess.setCommand({clangClPath, {"--version"}}); clangClProcess.runBlocking(); if (clangClProcess.result() != ProcessResult::FinishedWithSuccess) @@ -1772,7 +1772,7 @@ Macros ClangClToolChain::msvcPredefinedMacros(const QStringList &cxxflags, if (!cxxflags.contains("--driver-mode=g++")) return MsvcToolChain::msvcPredefinedMacros(cxxflags, env); - QtcProcess cpp; + Process cpp; cpp.setEnvironment(env); cpp.setWorkingDirectory(Utils::TemporaryDirectory::masterDirectoryFilePath()); @@ -2122,7 +2122,7 @@ std::optional MsvcToolChain::generateEnvironmentSettings(const Utils::E return QString(); } - Utils::QtcProcess run; + Utils::Process run; // As of WinSDK 7.1, there is logic preventing the path from being set // correctly if "ORIGINALPATH" is already set. That can cause problems diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 39f2af549a2..3f0accdc314 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1179,7 +1179,7 @@ public: bool m_runAsRoot = false; - QtcProcess m_process; + Process m_process; QTextCodec *m_outputCodec = nullptr; QTextCodec::ConverterState m_outputCodecState; @@ -1216,11 +1216,11 @@ SimpleTargetRunnerPrivate::SimpleTargetRunnerPrivate(SimpleTargetRunner *parent) : q(parent) { m_process.setProcessChannelMode(defaultProcessChannelMode()); - connect(&m_process, &QtcProcess::started, this, &SimpleTargetRunnerPrivate::forwardStarted); - connect(&m_process, &QtcProcess::done, this, &SimpleTargetRunnerPrivate::handleDone); - connect(&m_process, &QtcProcess::readyReadStandardError, + connect(&m_process, &Process::started, this, &SimpleTargetRunnerPrivate::forwardStarted); + connect(&m_process, &Process::done, this, &SimpleTargetRunnerPrivate::handleDone); + connect(&m_process, &Process::readyReadStandardError, this, &SimpleTargetRunnerPrivate::handleStandardError); - connect(&m_process, &QtcProcess::readyReadStandardOutput, + connect(&m_process, &Process::readyReadStandardOutput, this, &SimpleTargetRunnerPrivate::handleStandardOutput); if (WinDebugInterface::instance()) { diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 0a155cb464f..db456479459 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -27,9 +27,9 @@ const char pipInstallTaskId[] = "Python::pipInstallTask"; PipInstallTask::PipInstallTask(const FilePath &python) : m_python(python) { - connect(&m_process, &QtcProcess::done, this, &PipInstallTask::handleDone); - connect(&m_process, &QtcProcess::readyReadStandardError, this, &PipInstallTask::handleError); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, &PipInstallTask::handleOutput); + connect(&m_process, &Process::done, this, &PipInstallTask::handleDone); + connect(&m_process, &Process::readyReadStandardError, this, &PipInstallTask::handleError); + connect(&m_process, &Process::readyReadStandardOutput, this, &PipInstallTask::handleOutput); connect(&m_killTimer, &QTimer::timeout, this, &PipInstallTask::cancel); connect(&m_watcher, &QFutureWatcher::canceled, this, &PipInstallTask::cancel); m_watcher.setFuture(m_future.future()); @@ -160,7 +160,7 @@ static PipPackageInfo infoImpl(const PipPackage &package, const FilePath &python { PipPackageInfo result; - QtcProcess pip; + Process pip; pip.setCommand(CommandLine(python, {"-m", "pip", "show", "-f", package.packageName})); pip.runBlocking(); QString fieldName; diff --git a/src/plugins/python/pipsupport.h b/src/plugins/python/pipsupport.h index ea59519c325..fefd3295755 100644 --- a/src/plugins/python/pipsupport.h +++ b/src/plugins/python/pipsupport.h @@ -80,7 +80,7 @@ private: const Utils::FilePath m_python; QList m_packages; - Utils::QtcProcess m_process; + Utils::Process m_process; QFutureInterface m_future; QFutureWatcher m_watcher; QTimer m_killTimer; diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index 5e69c096a3a..eb604f01e64 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -55,7 +55,7 @@ bool PySideInstaller::missingPySideInstallation(const FilePath &pythonPath, if (pythonWithPyside[pythonPath].contains(pySide)) return false; - QtcProcess pythonProcess; + Process pythonProcess; pythonProcess.setCommand({pythonPath, {"-c", "import " + pySide}}); pythonProcess.runBlocking(); const bool missing = pythonProcess.result() != ProcessResult::FinishedWithSuccess; diff --git a/src/plugins/python/pysideuicextracompiler.cpp b/src/plugins/python/pysideuicextracompiler.cpp index b1e7e31bb7f..c195aeaa1f7 100644 --- a/src/plugins/python/pysideuicextracompiler.cpp +++ b/src/plugins/python/pysideuicextracompiler.cpp @@ -30,7 +30,7 @@ FilePath PySideUicExtraCompiler::command() const return m_pySideUic; } -FileNameToContentsHash PySideUicExtraCompiler::handleProcessFinished(QtcProcess *process) +FileNameToContentsHash PySideUicExtraCompiler::handleProcessFinished(Process *process) { FileNameToContentsHash result; if (process->exitStatus() != QProcess::NormalExit && process->exitCode() != 0) diff --git a/src/plugins/python/pysideuicextracompiler.h b/src/plugins/python/pysideuicextracompiler.h index f2a09bed78a..058717621ed 100644 --- a/src/plugins/python/pysideuicextracompiler.h +++ b/src/plugins/python/pysideuicextracompiler.h @@ -21,7 +21,7 @@ public: private: Utils::FilePath command() const override; ProjectExplorer::FileNameToContentsHash handleProcessFinished( - Utils::QtcProcess *process) override; + Utils::Process *process) override; Utils::FilePath m_pySideUic; }; diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index 75ee2c8b686..6d3d7c8cfa7 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -80,7 +80,7 @@ FilePath getPylsModulePath(CommandLine pylsCommand) pylsCommand.addArg("-h"); - QtcProcess pythonProcess; + Process pythonProcess; Environment env = pythonProcess.environment(); env.set("PYTHONVERBOSE", "x"); pythonProcess.setEnvironment(env); @@ -114,7 +114,7 @@ static PythonLanguageServerState checkPythonLanguageServer(const FilePath &pytho const CommandLine pythonLShelpCommand(python, {"-m", "pylsp", "-h"}); const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand); - QtcProcess pythonProcess; + Process pythonProcess; pythonProcess.setCommand(pythonLShelpCommand); pythonProcess.runBlocking(); if (pythonProcess.allOutput().contains("Python Language Server")) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index d6eccc999ba..119bd9d2600 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -62,7 +62,7 @@ static Interpreter createInterpreter(const FilePath &python, result.id = QUuid::createUuid().toString(); result.command = python; - QtcProcess pythonProcess; + Process pythonProcess; pythonProcess.setProcessChannelMode(QProcess::MergedChannels); pythonProcess.setTimeoutS(1); pythonProcess.setCommand({python, {"--version"}}); diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 1f89eef5b5f..328ada95d95 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -116,13 +116,13 @@ void openPythonRepl(QObject *parent, const FilePath &file, ReplType type) }; const auto args = QStringList{"-i"} + replImportArgs(file, type); - auto process = new QtcProcess(parent); + auto process = new Process(parent); process->setTerminalMode(TerminalMode::On); const FilePath pythonCommand = detectPython(file); process->setCommand({pythonCommand, args}); process->setWorkingDirectory(workingDir(file)); const QString commandLine = process->commandLine().toUserOutput(); - QObject::connect(process, &QtcProcess::done, process, [process, commandLine] { + QObject::connect(process, &Process::done, process, [process, commandLine] { if (process->error() != QProcess::UnknownError) { Core::MessageManager::writeDisrupting(Tr::tr( (process->error() == QProcess::FailedToStart) @@ -142,7 +142,7 @@ QString pythonName(const FilePath &pythonPath) return {}; QString name = nameForPython.value(pythonPath); if (name.isEmpty()) { - QtcProcess pythonProcess; + Process pythonProcess; pythonProcess.setTimeoutS(2); pythonProcess.setCommand({pythonPath, {"--version"}}); pythonProcess.runBlocking(); @@ -174,10 +174,10 @@ void createVenv(const Utils::FilePath &python, const CommandLine command(python, QStringList{"-m", "venv", venvPath.toUserOutput()}); - auto process = new QtcProcess; + auto process = new Process; auto progress = new Core::ProcessProgress(process); progress->setDisplayName(Tr::tr("Create Python venv")); - QObject::connect(process, &QtcProcess::done, [process, callback](){ + QObject::connect(process, &Process::done, [process, callback](){ callback(process->result() == ProcessResult::FinishedWithSuccess); process->deleteLater(); }); diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp index c5e658ba54c..953768661d0 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp @@ -223,7 +223,7 @@ QString QbsProfileManager::runQbsConfig(QbsConfigOp op, const QString &key, cons const Utils::FilePath qbsConfigExe = QbsSettings::qbsConfigFilePath(); if (qbsConfigExe.isEmpty() || !qbsConfigExe.exists()) return {}; - Utils::QtcProcess qbsConfig; + Utils::Process qbsConfig; qbsConfig.setCommand({qbsConfigExe, args}); qbsConfig.start(); if (!qbsConfig.waitForFinished(5000)) { diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 06c605e842d..7248143313e 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -129,7 +129,7 @@ private: class QbsSession::Private { public: - QtcProcess *qbsProcess = nullptr; + Process *qbsProcess = nullptr; PacketReader *packetReader = nullptr; QJsonObject currentRequest; QJsonObject projectData; @@ -152,16 +152,16 @@ void QbsSession::initialize() d->packetReader = new PacketReader(this); - d->qbsProcess = new QtcProcess(this); + d->qbsProcess = new Process(this); d->qbsProcess->setProcessMode(ProcessMode::Writer); d->qbsProcess->setEnvironment(env); - connect(d->qbsProcess, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(d->qbsProcess, &Process::readyReadStandardOutput, this, [this] { d->packetReader->handleData(d->qbsProcess->readAllRawStandardOutput()); }); - connect(d->qbsProcess, &QtcProcess::readyReadStandardError, this, [this] { + connect(d->qbsProcess, &Process::readyReadStandardError, this, [this] { qCDebug(qbsPmLog) << "[qbs stderr]: " << d->qbsProcess->readAllRawStandardError(); }); - connect(d->qbsProcess, &QtcProcess::done, this, [this] { + connect(d->qbsProcess, &Process::done, this, [this] { if (d->qbsProcess->result() == ProcessResult::StartFailed) { d->eventLoop.exit(1); setError(Error::QbsFailedToStart); diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp index 2168d56d9e5..6317580f685 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.cpp +++ b/src/plugins/qbsprojectmanager/qbssettings.cpp @@ -31,7 +31,7 @@ static QString getQbsVersion(const FilePath &qbsExe) { if (qbsExe.isEmpty() || !qbsExe.exists()) return {}; - QtcProcess qbsProc; + Process qbsProc; qbsProc.setCommand({qbsExe, {"--version"}}); qbsProc.start(); if (!qbsProc.waitForFinished(5000) || qbsProc.exitCode() != 0) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 3846ce2eb82..a78c001283f 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1593,12 +1593,12 @@ void QmakeBuildSystem::runGenerator(Utils::Id id) showError(Tr::tr("Cannot create output directory \"%1\"").arg(outDir.toUserOutput())); return; } - const auto proc = new QtcProcess(this); - connect(proc, &QtcProcess::done, proc, &QtcProcess::deleteLater); - connect(proc, &QtcProcess::readyReadStandardOutput, this, [proc] { + const auto proc = new Process(this); + connect(proc, &Process::done, proc, &Process::deleteLater); + connect(proc, &Process::readyReadStandardOutput, this, [proc] { Core::MessageManager::writeFlashing(QString::fromLocal8Bit(proc->readAllRawStandardOutput())); }); - connect(proc, &QtcProcess::readyReadStandardError, this, [proc] { + connect(proc, &Process::readyReadStandardError, this, [proc] { Core::MessageManager::writeDisrupting(QString::fromLocal8Bit(proc->readAllRawStandardError())); }); proc->setWorkingDirectory(outDir); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 7271e1f6e2f..d8e99a39a54 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -284,14 +284,14 @@ void QMakeStep::doRun() using namespace Tasking; - const auto setupQMake = [this](QtcProcess &process) { + const auto setupQMake = [this](Process &process) { m_outputFormatter->setLineParsers({new QMakeParser}); ProcessParameters *pp = processParameters(); pp->setCommandLine(m_qmakeCommand); setupProcess(&process); }; - const auto setupMakeQMake = [this](QtcProcess &process) { + const auto setupMakeQMake = [this](Process &process) { auto *parser = new GnuMakeParser; parser->addSearchDir(processParameters()->workingDirectory()); m_outputFormatter->setLineParsers({parser}); @@ -300,13 +300,13 @@ void QMakeStep::doRun() setupProcess(&process); }; - const auto onDone = [this](const QtcProcess &) { + const auto onDone = [this](const Process &) { const QString command = displayedParameters()->effectiveCommand().toUserOutput(); emit addOutput(Tr::tr("The process \"%1\" exited normally.").arg(command), OutputFormat::NormalMessage); }; - const auto onError = [this](const QtcProcess &process) { + const auto onError = [this](const Process &process) { const QString command = displayedParameters()->effectiveCommand().toUserOutput(); if (process.result() == ProcessResult::FinishedWithError) { emit addOutput(Tr::tr("The process \"%1\" exited with code %2.") diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index 90ae46010a7..33ad100c0b1 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -23,7 +23,7 @@ QT_END_NAMESPACE class StudioQuickWidget; namespace Utils { - class QtcProcess; + class Process; } namespace QmlDesigner { diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index b8b1fa94e84..f6ea4a8455f 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1667,10 +1667,10 @@ void openEffectMaker(const QString &filePath) if (env.osType() == Utils::OsTypeMac) env.appendOrSet("QSG_RHI_BACKEND", "metal"); - Utils::QtcProcess *qqemProcess = new Utils::QtcProcess(); + Utils::Process *qqemProcess = new Utils::Process(); qqemProcess->setEnvironment(env); qqemProcess->setCommand({ effectMakerPath, arguments }); - QObject::connect(qqemProcess, &Utils::QtcProcess::done, [qqemProcess]() { + QObject::connect(qqemProcess, &Utils::Process::done, [qqemProcess]() { qqemProcess->deleteLater(); }); qqemProcess->start(); diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 467cef0ed3d..632dbfce077 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -34,7 +34,7 @@ class Target; } namespace Utils { -class QtcProcess; +class Process; } namespace QmlDesigner { @@ -228,7 +228,7 @@ private: // functions void updateWatcher(const QString &path); void handleShaderChanges(); - void handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader); + void handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader); void updateQsbPathToFilterMap(); void updateRotationBlocks(); void maybeResetOnPropertyChange(const PropertyName &name, const ModelNode &node, diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 406a7a295d1..67674ed5e92 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -2066,7 +2066,7 @@ void NodeInstanceView::updateWatcher(const QString &path) m_generateQsbFilesTimer.start(); } -void NodeInstanceView::handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader) +void NodeInstanceView::handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader) { --m_remainingQsbTargets; @@ -2167,8 +2167,8 @@ void NodeInstanceView::handleShaderChanges() QStringList args = baseArgs; args.append(outPath.toString()); args.append(shader); - auto qsbProcess = new Utils::QtcProcess(this); - connect(qsbProcess, &Utils::QtcProcess::done, this, [this, qsbProcess, shader] { + auto qsbProcess = new Utils::Process(this); + connect(qsbProcess, &Utils::Process::done, this, [this, qsbProcess, shader] { handleQsbProcessExit(qsbProcess, shader); }); qsbProcess->setWorkingDirectory(srcPath); diff --git a/src/plugins/qmldesigner/generateresource.cpp b/src/plugins/qmldesigner/generateresource.cpp index 8b00335ce33..673ba41de4f 100644 --- a/src/plugins/qmldesigner/generateresource.cpp +++ b/src/plugins/qmldesigner/generateresource.cpp @@ -177,7 +177,7 @@ QList getFilesFromQrc(QFile *file, bool inProjec static bool runRcc(const CommandLine &command, const FilePath &workingDir, const QString &resourceFile) { - Utils::QtcProcess rccProcess; + Utils::Process rccProcess; rccProcess.setWorkingDirectory(workingDir); rccProcess.setCommand(command); rccProcess.start(); diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index 443d5478fc9..2c1a294e7a3 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -116,10 +116,10 @@ void QmlProjectPlugin::openQDS(const Utils::FilePath &fileName) qputenv(Constants::enviromentLaunchedQDS, "true"); //-a and -client arguments help to append project to open design studio application if (Utils::HostOsInfo::isMacHost()) - qdsStarted = Utils::QtcProcess::startDetached( + qdsStarted = Utils::Process::startDetached( {"/usr/bin/open", {"-a", qdsPath.path(), fileName.toString()}}); else - qdsStarted = Utils::QtcProcess::startDetached({qdsPath, {"-client", fileName.toString()}}); + qdsStarted = Utils::Process::startDetached({qdsPath, {"-client", fileName.toString()}}); if (!qdsStarted) { QMessageBox::warning(Core::ICore::dialogParent(), diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 65caee381ab..6450223e431 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -119,12 +119,12 @@ QList collectFilesToUpload(const DeployableFile &deployable) TaskItem QnxDeployQtLibrariesDialogPrivate::checkDirTask() { - const auto setupHandler = [this](QtcProcess &process) { + const auto setupHandler = [this](Process &process) { m_deployLogWindow->appendPlainText(Tr::tr("Checking existence of \"%1\"") .arg(fullRemoteDirectory())); process.setCommand({m_device->filePath("test"), {"-d", fullRemoteDirectory()}}); }; - const auto doneHandler = [this](const QtcProcess &process) { + const auto doneHandler = [this](const Process &process) { Q_UNUSED(process) const int answer = QMessageBox::question(q, q->windowTitle(), Tr::tr("The remote directory \"%1\" already exists.\n" @@ -133,7 +133,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::checkDirTask() QMessageBox::Yes | QMessageBox::No); m_checkResult = answer == QMessageBox::Yes ? CheckResult::RemoveDir : CheckResult::Abort; }; - const auto errorHandler = [this](const QtcProcess &process) { + const auto errorHandler = [this](const Process &process) { if (process.result() != ProcessResult::FinishedWithError) { m_deployLogWindow->appendPlainText(Tr::tr("Connection failed: %1") .arg(process.errorString())); @@ -147,14 +147,14 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::checkDirTask() TaskItem QnxDeployQtLibrariesDialogPrivate::removeDirTask() { - const auto setupHandler = [this](QtcProcess &process) { + const auto setupHandler = [this](Process &process) { if (m_checkResult != CheckResult::RemoveDir) return TaskAction::StopWithDone; m_deployLogWindow->appendPlainText(Tr::tr("Removing \"%1\"").arg(fullRemoteDirectory())); process.setCommand({m_device->filePath("rm"), {"-rf", fullRemoteDirectory()}}); return TaskAction::Continue; }; - const auto errorHandler = [this](const QtcProcess &process) { + const auto errorHandler = [this](const Process &process) { QTC_ASSERT(process.exitCode() == 0, return); m_deployLogWindow->appendPlainText(Tr::tr("Connection failed: %1") .arg(process.errorString())); @@ -198,11 +198,11 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::uploadTask() TaskItem QnxDeployQtLibrariesDialogPrivate::chmodTask(const DeployableFile &file) { - const auto setupHandler = [=](QtcProcess &process) { + const auto setupHandler = [=](Process &process) { process.setCommand({m_device->filePath("chmod"), {"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); }; - const auto errorHandler = [=](const QtcProcess &process) { + const auto errorHandler = [=](const Process &process) { const QString error = process.errorString(); if (!error.isEmpty()) { emitWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp index 9e9e0524e2c..a96f5b6d7e7 100644 --- a/src/plugins/qnx/qnxdevicetester.cpp +++ b/src/plugins/qnx/qnxdevicetester.cpp @@ -44,7 +44,7 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) using namespace Tasking; - auto setupHandler = [device, this](QtcProcess &process) { + auto setupHandler = [device, this](Process &process) { emit progressMessage(Tr::tr("Checking that files can be created in %1...") .arg(Constants::QNX_TMP_DIR)); const QString pidFile = QString("%1/qtc_xxxx.pid").arg(Constants::QNX_TMP_DIR); @@ -52,10 +52,10 @@ void QnxDeviceTester::testDevice(const ProjectExplorer::IDevice::Ptr &device) {"-c", QLatin1String("rm %1 > /dev/null 2>&1; echo ABC > %1 && rm %1").arg(pidFile)}); process.setCommand(cmd); }; - auto doneHandler = [this](const QtcProcess &) { + auto doneHandler = [this](const Process &) { emit progressMessage(Tr::tr("Files can be created in /var/run.") + '\n'); }; - auto errorHandler = [this](const QtcProcess &process) { + auto errorHandler = [this](const Process &process) { const QString message = process.result() == ProcessResult::StartFailed ? Tr::tr("An error occurred while checking that files can be created in %1.") .arg(Constants::QNX_TMP_DIR) + '\n' + process.errorString() diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index 5c1107f5997..3cc73e6d54d 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -98,7 +98,7 @@ EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const FilePath &filePath) tmpFile->writeFileContents(content.toUtf8()); // running wrapper script - QtcProcess process; + Process process; if (isWindows) process.setCommand({filePath.withNewPath("cmd.exe"), {"/C", tmpFile->path()}}); else diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 0d17b872c96..21de26e5a24 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -34,36 +34,36 @@ void Slog2InfoRunner::start() using namespace Utils::Tasking; QTC_CHECK(!m_taskTree); - const auto testStartHandler = [this](QtcProcess &process) { + const auto testStartHandler = [this](Process &process) { process.setCommand({device()->filePath("slog2info"), {}}); }; - const auto testDoneHandler = [this](const QtcProcess &) { + const auto testDoneHandler = [this](const Process &) { m_found = true; }; - const auto testErrorHandler = [this](const QtcProcess &) { + const auto testErrorHandler = [this](const Process &) { appendMessage(Tr::tr("Warning: \"slog2info\" is not found on the device, " "debug output not available."), ErrorMessageFormat); }; - const auto launchTimeStartHandler = [this](QtcProcess &process) { + const auto launchTimeStartHandler = [this](Process &process) { process.setCommand({device()->filePath("date"), "+\"%d %H:%M:%S\"", CommandLine::Raw}); }; - const auto launchTimeDoneHandler = [this](const QtcProcess &process) { + const auto launchTimeDoneHandler = [this](const Process &process) { QTC_CHECK(!m_applicationId.isEmpty()); QTC_CHECK(m_found); m_launchDateTime = QDateTime::fromString(process.cleanedStdOut().trimmed(), "dd HH:mm:ss"); }; - const auto logStartHandler = [this](QtcProcess &process) { + const auto logStartHandler = [this](Process &process) { process.setCommand({device()->filePath("slog2info"), {"-w"}}); - connect(&process, &QtcProcess::readyReadStandardOutput, this, [&] { + connect(&process, &Process::readyReadStandardOutput, this, [&] { processLogInput(QString::fromLatin1(process.readAllRawStandardOutput())); }); - connect(&process, &QtcProcess::readyReadStandardError, this, [&] { + connect(&process, &Process::readyReadStandardError, this, [&] { appendMessage(QString::fromLatin1(process.readAllRawStandardError()), StdErrFormat); }); }; - const auto logErrorHandler = [this](const QtcProcess &process) { + const auto logErrorHandler = [this](const Process &process) { appendMessage(Tr::tr("Cannot show slog2info output. Error: %1").arg(process.errorString()), StdErrFormat); }; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index c96f310e0bc..c08f296a8c2 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1684,7 +1684,7 @@ static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env, // Prevent e.g. qmake 4.x on MinGW to show annoying errors about missing dll's. WindowsCrashDialogBlocker crashDialogBlocker; - QtcProcess process; + Process process; process.setEnvironment(env); process.setCommand({binary, {"-query"}}); process.start(); diff --git a/src/plugins/qtsupport/externaleditors.cpp b/src/plugins/qtsupport/externaleditors.cpp index ee3a3611031..9732693e6eb 100644 --- a/src/plugins/qtsupport/externaleditors.cpp +++ b/src/plugins/qtsupport/externaleditors.cpp @@ -224,7 +224,7 @@ static bool startEditorProcess(const LaunchData &data, QString *errorMessage) if (debug) qDebug() << Q_FUNC_INFO << '\n' << data.binary << data.arguments << data.workingDirectory; qint64 pid = 0; - if (!QtcProcess::startDetached({FilePath::fromString(data.binary), data.arguments}, data.workingDirectory, &pid)) { + if (!Process::startDetached({FilePath::fromString(data.binary), data.arguments}, data.workingDirectory, &pid)) { *errorMessage = msgStartFailed(data.binary, data.arguments); return false; } diff --git a/src/plugins/qtsupport/qscxmlcgenerator.cpp b/src/plugins/qtsupport/qscxmlcgenerator.cpp index 85c467281d3..7cb67f6171e 100644 --- a/src/plugins/qtsupport/qscxmlcgenerator.cpp +++ b/src/plugins/qtsupport/qscxmlcgenerator.cpp @@ -91,7 +91,7 @@ bool QScxmlcGenerator::prepareToRun(const QByteArray &sourceContents) return true; } -FileNameToContentsHash QScxmlcGenerator::handleProcessFinished(Utils::QtcProcess *process) +FileNameToContentsHash QScxmlcGenerator::handleProcessFinished(Utils::Process *process) { Q_UNUSED(process) const Utils::FilePath wd = workingDirectory(); diff --git a/src/plugins/qtsupport/qscxmlcgenerator.h b/src/plugins/qtsupport/qscxmlcgenerator.h index 633fb1231bf..342db3cb096 100644 --- a/src/plugins/qtsupport/qscxmlcgenerator.h +++ b/src/plugins/qtsupport/qscxmlcgenerator.h @@ -23,7 +23,7 @@ protected: private: Utils::FilePath tmpFile() const; - ProjectExplorer::FileNameToContentsHash handleProcessFinished(Utils::QtcProcess *process) override; + ProjectExplorer::FileNameToContentsHash handleProcessFinished(Utils::Process *process) override; bool prepareToRun(const QByteArray &sourceContents) override; ProjectExplorer::Tasks parseIssues(const QByteArray &processStderr) override; diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 8a1c94bddca..37d141e11c6 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -76,7 +76,7 @@ static void processRunnerCallback(ProcessData *data) { FilePath rootPath = FilePath::fromString(data->deviceRoot); - QtcProcess proc; + Process proc; proc.setProcessChannelMode(data->processChannelMode); proc.setCommand({rootPath.withNewPath("/bin/sh"), {QString("-c"), data->command}}); proc.setWorkingDirectory(FilePath::fromString(data->workingDirectory)); diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index e9a3691cdb9..bde9d2e3374 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -368,7 +368,7 @@ static void saveQtVersions() // Executes qtchooser with arguments in a process and returns its output static QList runQtChooser(const QString &qtchooser, const QStringList &arguments) { - QtcProcess p; + Process p; p.setCommand({FilePath::fromString(qtchooser), arguments}); p.start(); p.waitForFinished(); diff --git a/src/plugins/qtsupport/uicgenerator.cpp b/src/plugins/qtsupport/uicgenerator.cpp index 36c109e7b4f..f48a8d310ee 100644 --- a/src/plugins/qtsupport/uicgenerator.cpp +++ b/src/plugins/qtsupport/uicgenerator.cpp @@ -48,7 +48,7 @@ QStringList UicGenerator::arguments() const return {"-p"}; } -FileNameToContentsHash UicGenerator::handleProcessFinished(Utils::QtcProcess *process) +FileNameToContentsHash UicGenerator::handleProcessFinished(Utils::Process *process) { FileNameToContentsHash result; if (process->exitStatus() != QProcess::NormalExit && process->exitCode() != 0) diff --git a/src/plugins/qtsupport/uicgenerator.h b/src/plugins/qtsupport/uicgenerator.h index 1d9344634a3..d68b6814c22 100644 --- a/src/plugins/qtsupport/uicgenerator.h +++ b/src/plugins/qtsupport/uicgenerator.h @@ -18,7 +18,7 @@ public: protected: Utils::FilePath command() const override; QStringList arguments() const override; - ProjectExplorer::FileNameToContentsHash handleProcessFinished(Utils::QtcProcess *process) override; + ProjectExplorer::FileNameToContentsHash handleProcessFinished(Utils::Process *process) override; }; class UicGeneratorFactory : public ProjectExplorer::ExtraCompilerFactory diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index 80e8ded988a..7249d2c6b2b 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -57,22 +57,22 @@ CheckResult CustomCommandDeployStep::isDeploymentPossible() const Group CustomCommandDeployStep::deployRecipe() { - const auto setupHandler = [this](QtcProcess &process) { + const auto setupHandler = [this](Process &process) { addProgressMessage(Tr::tr("Starting remote command \"%1\"...").arg(m_commandLine)); process.setCommand({deviceConfiguration()->filePath("/bin/sh"), {"-c", m_commandLine}}); - QtcProcess *proc = &process; - connect(proc, &QtcProcess::readyReadStandardOutput, this, [this, proc] { + Process *proc = &process; + connect(proc, &Process::readyReadStandardOutput, this, [this, proc] { handleStdOutData(proc->readAllStandardOutput()); }); - connect(proc, &QtcProcess::readyReadStandardError, this, [this, proc] { + connect(proc, &Process::readyReadStandardError, this, [this, proc] { handleStdErrData(proc->readAllStandardError()); }); }; - const auto doneHandler = [this](const QtcProcess &) { + const auto doneHandler = [this](const Process &) { addProgressMessage(Tr::tr("Remote command finished successfully.")); }; - const auto errorHandler = [this](const QtcProcess &process) { + const auto errorHandler = [this](const Process &process) { if (process.error() != QProcess::UnknownError || process.exitStatus() != QProcess::NormalExit) { addErrorMessage(Tr::tr("Remote process failed: %1").arg(process.errorString())); diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index 44dc4048109..24267b16bd9 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -186,7 +186,7 @@ void FileSystemAccessTest::testWorkingDirectory() { const FilePath dir = baseFilePath() / "testdir with space and 'various' \"quotes\" here"; QVERIFY(dir.ensureWritableDir()); - QtcProcess proc; + Process proc; proc.setCommand({"pwd", {}}); proc.setWorkingDirectory(dir); proc.start(); diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index c1abc891b7a..4889dbb35d1 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -70,7 +70,7 @@ public: bool isDeploymentNecessary() const final; Utils::Tasking::Group deployRecipe() final; - QDateTime timestampFromStat(const DeployableFile &file, QtcProcess *statProc); + QDateTime timestampFromStat(const DeployableFile &file, Process *statProc); using FilesToStat = std::function(UploadStorage *)>; using StatEndHandler @@ -115,7 +115,7 @@ bool GenericDirectUploadStep::isDeploymentNecessary() const } QDateTime GenericDirectUploadStep::timestampFromStat(const DeployableFile &file, - QtcProcess *statProc) + Process *statProc) { bool succeeded = false; QString error; @@ -160,13 +160,13 @@ TaskItem GenericDirectUploadStep::statTask(UploadStorage *storage, const DeployableFile &file, StatEndHandler statEndHandler) { - const auto setupHandler = [=](QtcProcess &process) { + const auto setupHandler = [=](Process &process) { // We'd like to use --format=%Y, but it's not supported by busybox. process.setCommand({deviceConfiguration()->filePath("stat"), {"-t", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); }; - const auto endHandler = [=](const QtcProcess &process) { - QtcProcess *proc = const_cast(&process); + const auto endHandler = [=](const Process &process) { + Process *proc = const_cast(&process); const QDateTime timestamp = timestampFromStat(file, proc); statEndHandler(storage, file, timestamp); }; @@ -231,11 +231,11 @@ TaskItem GenericDirectUploadStep::uploadTask(const TreeStorage &s TaskItem GenericDirectUploadStep::chmodTask(const DeployableFile &file) { - const auto setupHandler = [=](QtcProcess &process) { + const auto setupHandler = [=](Process &process) { process.setCommand({deviceConfiguration()->filePath("chmod"), {"a+x", Utils::ProcessArgs::quoteArgUnix(file.remoteFilePath())}}); }; - const auto errorHandler = [=](const QtcProcess &process) { + const auto errorHandler = [=](const Process &process) { const QString error = process.errorString(); if (!error.isEmpty()) { addWarningMessage(Tr::tr("Remote chmod failed for file \"%1\": %2") diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 583a6bdeaf5..6aca035bb6c 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -92,7 +92,7 @@ private: QStringList connectionArgs(const FilePath &binary) const; const SshParameters m_sshParameters; - std::unique_ptr m_masterProcess; + std::unique_ptr m_masterProcess; std::unique_ptr m_masterSocketDir; QTimer m_timer; int m_ref = 0; @@ -158,11 +158,11 @@ void SshSharedConnection::connectToHost() return; } - m_masterProcess.reset(new QtcProcess); + m_masterProcess.reset(new Process); SshParameters::setupSshEnvironment(m_masterProcess.get()); m_timer.setSingleShot(true); connect(&m_timer, &QTimer::timeout, this, &SshSharedConnection::autoDestructRequested); - connect(m_masterProcess.get(), &QtcProcess::readyReadStandardOutput, this, [this] { + connect(m_masterProcess.get(), &Process::readyReadStandardOutput, this, [this] { const QByteArray reply = m_masterProcess->readAllRawStandardOutput(); if (reply == "\n") emitConnected(); @@ -170,7 +170,7 @@ void SshSharedConnection::connectToHost() }); // TODO: in case of refused connection we are getting the following on stdErr: // ssh: connect to host 127.0.0.1 port 22: Connection refused\r\n - connect(m_masterProcess.get(), &QtcProcess::done, this, [this] { + connect(m_masterProcess.get(), &Process::done, this, [this] { const ProcessResult result = m_masterProcess->result(); const ProcessResultData resultData = m_masterProcess->resultData(); if (result == ProcessResult::StartFailed) { @@ -316,7 +316,7 @@ public: QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; mutable QMutex m_shellMutex; - QList m_terminals; + QList m_terminals; LinuxDeviceFileAccess m_fileAccess{this}; QReadWriteLock m_environmentCacheLock; @@ -340,7 +340,7 @@ Environment LinuxDevicePrivate::getEnvironment() if (m_environmentCache.has_value()) return m_environmentCache.value(); - QtcProcess getEnvProc; + Process getEnvProc; getEnvProc.setCommand({q->filePath("env"), {}}); getEnvProc.runBlocking(); @@ -388,7 +388,7 @@ public: // as this object is alive. IDevice::ConstPtr m_device; std::unique_ptr m_connectionHandle; - QtcProcess m_process; + Process m_process; QString m_socketFilePath; SshParameters m_sshParameters; @@ -435,7 +435,7 @@ qint64 SshProcessInterface::processId() const bool SshProcessInterface::runInShell(const CommandLine &command, const QByteArray &data) { - QtcProcess process; + Process process; CommandLine cmd = {d->m_device->filePath("/bin/sh"), {"-c"}}; QString tmp; ProcessArgs::addArg(&tmp, command.executable().path()); @@ -584,11 +584,11 @@ SshProcessInterfacePrivate::SshProcessInterfacePrivate(SshProcessInterface *sshI , m_device(device) , m_process(this) { - connect(&m_process, &QtcProcess::started, this, &SshProcessInterfacePrivate::handleStarted); - connect(&m_process, &QtcProcess::done, this, &SshProcessInterfacePrivate::handleDone); - connect(&m_process, &QtcProcess::readyReadStandardOutput, + connect(&m_process, &Process::started, this, &SshProcessInterfacePrivate::handleStarted); + connect(&m_process, &Process::done, this, &SshProcessInterfacePrivate::handleDone); + connect(&m_process, &Process::readyReadStandardOutput, this, &SshProcessInterfacePrivate::handleReadyReadStandardOutput); - connect(&m_process, &QtcProcess::readyReadStandardError, + connect(&m_process, &Process::readyReadStandardError, this, &SshProcessInterfacePrivate::handleReadyReadStandardError); } @@ -796,7 +796,7 @@ class ShellThreadHandler : public QObject } private: - void setupShellProcess(QtcProcess *shellProcess) override + void setupShellProcess(Process *shellProcess) override { SshParameters::setupSshEnvironment(shellProcess); shellProcess->setCommand(m_cmdLine); @@ -961,9 +961,9 @@ LinuxDevice::LinuxDevice() }}); setOpenTerminal([this](const Environment &env, const FilePath &workingDir) { - QtcProcess * const proc = new QtcProcess; + Process * const proc = new Process; d->m_terminals.append(proc); - QObject::connect(proc, &QtcProcess::done, proc, [this, proc] { + QObject::connect(proc, &Process::done, proc, [this, proc] { if (proc->error() != QProcess::UnknownError) { const QString errorString = proc->errorString(); QString message; @@ -1172,10 +1172,10 @@ protected: , m_process(this) { SshParameters::setupSshEnvironment(&m_process); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&m_process, &Process::readyReadStandardOutput, this, [this] { emit progress(QString::fromLocal8Bit(m_process.readAllRawStandardOutput())); }); - connect(&m_process, &QtcProcess::done, this, &SshTransferInterface::doneImpl); + connect(&m_process, &Process::done, this, &SshTransferInterface::doneImpl); } IDevice::ConstPtr device() const { return m_device; } @@ -1215,7 +1215,7 @@ protected: QString host() const { return m_sshParameters.host(); } QString userAtHost() const { return m_sshParameters.userAtHost(); } - QtcProcess &process() { return m_process; } + Process &process() { return m_process; } private: virtual void startImpl() = 0; @@ -1274,7 +1274,7 @@ private: QString m_socketFilePath; bool m_connecting = false; - QtcProcess m_process; + Process m_process; }; class SftpTransferImpl : public SshTransferInterface diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index f4df0b9bac5..c28b2ecfc50 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -92,11 +92,11 @@ QStringList GenericLinuxDeviceTesterPrivate::commandsToTest() const TaskItem GenericLinuxDeviceTesterPrivate::echoTask(const QString &contents) const { - const auto setup = [this, contents](QtcProcess &process) { + const auto setup = [this, contents](Process &process) { emit q->progressMessage(Tr::tr("Sending echo to device...")); process.setCommand({m_device->filePath("echo"), {contents}}); }; - const auto done = [this, contents](const QtcProcess &process) { + const auto done = [this, contents](const Process &process) { const QString reply = Utils::chopIfEndsWith(process.cleanedStdOut(), '\n'); if (reply != contents) emit q->errorMessage(Tr::tr("Device replied to echo with unexpected contents: \"%1\"") @@ -104,7 +104,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::echoTask(const QString &contents) cons else emit q->progressMessage(Tr::tr("Device replied to echo with expected contents.") + '\n'); }; - const auto error = [this](const QtcProcess &process) { + const auto error = [this](const Process &process) { const QString stdErrOutput = process.cleanedStdErr(); if (!stdErrOutput.isEmpty()) emit q->errorMessage(Tr::tr("echo failed: %1").arg(stdErrOutput) + '\n'); @@ -116,14 +116,14 @@ TaskItem GenericLinuxDeviceTesterPrivate::echoTask(const QString &contents) cons TaskItem GenericLinuxDeviceTesterPrivate::unameTask() const { - const auto setup = [this](QtcProcess &process) { + const auto setup = [this](Process &process) { emit q->progressMessage(Tr::tr("Checking kernel version...")); process.setCommand({m_device->filePath("uname"), {"-rsm"}}); }; - const auto done = [this](const QtcProcess &process) { + const auto done = [this](const Process &process) { emit q->progressMessage(process.cleanedStdOut()); }; - const auto error = [this](const QtcProcess &process) { + const auto error = [this](const Process &process) { const QString stdErrOutput = process.cleanedStdErr(); if (!stdErrOutput.isEmpty()) emit q->errorMessage(Tr::tr("uname failed: %1").arg(stdErrOutput) + '\n'); @@ -233,16 +233,16 @@ TaskItem GenericLinuxDeviceTesterPrivate::transferTasks() const TaskItem GenericLinuxDeviceTesterPrivate::commandTask(const QString &commandName) const { - const auto setup = [this, commandName](QtcProcess &process) { + const auto setup = [this, commandName](Process &process) { emit q->progressMessage(Tr::tr("%1...").arg(commandName)); CommandLine command{m_device->filePath("/bin/sh"), {"-c"}}; command.addArgs(QLatin1String("\"command -v %1\"").arg(commandName), CommandLine::Raw); process.setCommand(command); }; - const auto done = [this, commandName](const QtcProcess &) { + const auto done = [this, commandName](const Process &) { emit q->progressMessage(Tr::tr("%1 found.").arg(commandName)); }; - const auto error = [this, commandName](const QtcProcess &process) { + const auto error = [this, commandName](const Process &process) { const QString message = process.result() == ProcessResult::StartFailed ? Tr::tr("An error occurred while checking for %1.").arg(commandName) + '\n' + process.errorString() diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp index fcff8efd44d..c5564d3c741 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp +++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp @@ -23,7 +23,7 @@ namespace Internal { class PublicKeyDeploymentDialogPrivate { public: - QtcProcess m_process; + Process m_process; bool m_done; }; } // namespace Internal; @@ -56,7 +56,7 @@ PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const IDevice::ConstPtr &de setValue(0); connect(this, &PublicKeyDeploymentDialog::canceled, this, [this] { d->m_done ? accept() : reject(); }); - connect(&d->m_process, &QtcProcess::done, this, [this] { + connect(&d->m_process, &Process::done, this, [this] { const bool succeeded = d->m_process.result() == ProcessResult::FinishedWithSuccess; QString finalMessage; if (!succeeded) { diff --git a/src/plugins/remotelinux/remotelinuxsignaloperation.cpp b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp index e073acde057..4ee28e77015 100644 --- a/src/plugins/remotelinux/remotelinuxsignaloperation.cpp +++ b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp @@ -30,8 +30,8 @@ static QString signalProcessGroupByPidCommandLine(qint64 pid, int signal) void RemoteLinuxSignalOperation::run(const QString &command) { QTC_ASSERT(!m_process, return); - m_process.reset(new QtcProcess); - connect(m_process.get(), &QtcProcess::done, this, &RemoteLinuxSignalOperation::runnerDone); + m_process.reset(new Process); + connect(m_process.get(), &Process::done, this, &RemoteLinuxSignalOperation::runnerDone); m_process->setCommand({m_device->filePath("/bin/sh"), {"-c", command}}); m_process->start(); diff --git a/src/plugins/remotelinux/remotelinuxsignaloperation.h b/src/plugins/remotelinux/remotelinuxsignaloperation.h index d3e840e0d3d..00967c9414c 100644 --- a/src/plugins/remotelinux/remotelinuxsignaloperation.h +++ b/src/plugins/remotelinux/remotelinuxsignaloperation.h @@ -32,7 +32,7 @@ private: void run(const QString &command); const ProjectExplorer::IDeviceConstPtr m_device; - std::unique_ptr m_process; + std::unique_ptr m_process; friend class LinuxDevice; }; diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 193a112cb55..7a161601b75 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -88,7 +88,7 @@ bool RsyncDeployStep::isDeploymentNecessary() const TaskItem RsyncDeployStep::mkdirTask() { - const auto setupHandler = [this](QtcProcess &process) { + const auto setupHandler = [this](Process &process) { QStringList remoteDirs; for (const FileToTransfer &file : std::as_const(m_files)) remoteDirs << file.m_target.parentDir().path(); @@ -96,11 +96,11 @@ TaskItem RsyncDeployStep::mkdirTask() remoteDirs.removeDuplicates(); process.setCommand({deviceConfiguration()->filePath("mkdir"), QStringList("-p") + remoteDirs}); - connect(&process, &QtcProcess::readyReadStandardError, this, [this, proc = &process] { + connect(&process, &Process::readyReadStandardError, this, [this, proc = &process] { handleStdErrData(QString::fromLocal8Bit(proc->readAllRawStandardError())); }); }; - const auto errorHandler = [this](const QtcProcess &process) { + const auto errorHandler = [this](const Process &process) { QString finalMessage = process.errorString(); const QString stdErr = process.cleanedStdErr(); if (!stdErr.isEmpty()) { diff --git a/src/plugins/remotelinux/sshkeycreationdialog.cpp b/src/plugins/remotelinux/sshkeycreationdialog.cpp index e0128d2a2ad..16dcf9220d7 100644 --- a/src/plugins/remotelinux/sshkeycreationdialog.cpp +++ b/src/plugins/remotelinux/sshkeycreationdialog.cpp @@ -109,7 +109,7 @@ void SshKeyCreationDialog::generateKeys() } const QString keyTypeString = QLatin1String(m_rsa->isChecked() ? "rsa": "ecdsa"); QApplication::setOverrideCursor(Qt::BusyCursor); - QtcProcess keygen; + Process keygen; const QStringList args{"-t", keyTypeString, "-b", m_comboBox->currentText(), "-N", QString(), "-f", privateKeyFilePath().path()}; QString errorMsg; diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index 795acabe0de..4f517ea91de 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -92,24 +92,24 @@ TaskItem TarPackageDeployStep::uploadTask() TaskItem TarPackageDeployStep::installTask() { - const auto setupHandler = [this](QtcProcess &process) { + const auto setupHandler = [this](Process &process) { const QString cmdLine = QLatin1String("cd / && tar xvf ") + remoteFilePath() + " && (rm " + remoteFilePath() + " || :)"; process.setCommand({deviceConfiguration()->filePath("/bin/sh"), {"-c", cmdLine}}); - QtcProcess *proc = &process; - connect(proc, &QtcProcess::readyReadStandardOutput, this, [this, proc] { + Process *proc = &process; + connect(proc, &Process::readyReadStandardOutput, this, [this, proc] { handleStdOutData(proc->readAllStandardOutput()); }); - connect(proc, &QtcProcess::readyReadStandardError, this, [this, proc] { + connect(proc, &Process::readyReadStandardError, this, [this, proc] { handleStdErrData(proc->readAllStandardError()); }); addProgressMessage(Tr::tr("Installing package to device...")); }; - const auto doneHandler = [this](const QtcProcess &) { + const auto doneHandler = [this](const Process &) { saveDeploymentTimeStamp(DeployableFile(m_packageFilePath, {}), {}); addProgressMessage(Tr::tr("Successfully installed package file.")); }; - const auto errorHandler = [this](const QtcProcess &process) { + const auto errorHandler = [this](const Process &process) { addErrorMessage(Tr::tr("Installing package failed.") + process.errorString()); }; return ProcessTask(setupHandler, doneHandler, errorHandler); diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index 9956a547774..e2a85ab53c5 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -62,7 +62,7 @@ QString convertWildcardToRegex(const QString &wildcard) bool isSilverSearcherAvailable() { - QtcProcess silverSearcherProcess; + Process silverSearcherProcess; silverSearcherProcess.setCommand({"ag", {"--version"}}); silverSearcherProcess.start(); if (silverSearcherProcess.waitForFinished(1000)) { @@ -106,7 +106,7 @@ void runSilverSeacher(QPromise &promise, FileFindParameter arguments << "--" << parameters.text << directory.normalizedPathName().toString(); - QtcProcess process; + Process process; process.setCommand({"ag", arguments}); process.start(); if (process.waitForFinished()) { diff --git a/src/plugins/squish/objectsmapdocument.cpp b/src/plugins/squish/objectsmapdocument.cpp index eb7266ddc43..0555bb3512c 100644 --- a/src/plugins/squish/objectsmapdocument.cpp +++ b/src/plugins/squish/objectsmapdocument.cpp @@ -209,7 +209,7 @@ Core::IDocument::OpenResult ObjectsMapDocument::openImpl(QString *error, return OpenResult::ReadError; } - Utils::QtcProcess objectMapReader; + Utils::Process objectMapReader; objectMapReader.setCommand({exe, {"--scriptMap", "--mode", "read", "--scriptedObjectMapPath", realFileName.toUserOutput()}}); objectMapReader.setCodec(QTextCodec::codecForName("UTF-8")); @@ -240,7 +240,7 @@ bool ObjectsMapDocument::writeFile(const Utils::FilePath &fileName) const if (!exe.isExecutableFile()) return false; - Utils::QtcProcess objectMapWriter; + Utils::Process objectMapWriter; objectMapWriter.setCommand({exe, {"--scriptMap", "--mode", "write", "--scriptedObjectMapPath", fileName.toUserOutput()}}); objectMapWriter.setWriteData(contents()); diff --git a/src/plugins/squish/squishprocessbase.cpp b/src/plugins/squish/squishprocessbase.cpp index 23d3a49aa70..744ea506c12 100644 --- a/src/plugins/squish/squishprocessbase.cpp +++ b/src/plugins/squish/squishprocessbase.cpp @@ -8,9 +8,9 @@ namespace Squish::Internal { SquishProcessBase::SquishProcessBase(QObject *parent) : QObject(parent) { - connect(&m_process, &Utils::QtcProcess::readyReadStandardError, + connect(&m_process, &Utils::Process::readyReadStandardError, this, &SquishProcessBase::onErrorOutput); - connect(&m_process, &Utils::QtcProcess::done, + connect(&m_process, &Utils::Process::done, this, &SquishProcessBase::onDone); } diff --git a/src/plugins/squish/squishprocessbase.h b/src/plugins/squish/squishprocessbase.h index 088eca8a73b..d8af2e9d4f2 100644 --- a/src/plugins/squish/squishprocessbase.h +++ b/src/plugins/squish/squishprocessbase.h @@ -36,7 +36,7 @@ protected: virtual void onDone() {} virtual void onErrorOutput() {} - Utils::QtcProcess m_process; + Utils::Process m_process; private: SquishProcessState m_state = Idle; diff --git a/src/plugins/squish/squishserverprocess.cpp b/src/plugins/squish/squishserverprocess.cpp index 4d7bb2ef97f..9e4b9741433 100644 --- a/src/plugins/squish/squishserverprocess.cpp +++ b/src/plugins/squish/squishserverprocess.cpp @@ -10,7 +10,7 @@ namespace Squish::Internal { SquishServerProcess::SquishServerProcess(QObject *parent) : SquishProcessBase(parent) { - connect(&m_process, &Utils::QtcProcess::readyReadStandardOutput, + connect(&m_process, &Utils::Process::readyReadStandardOutput, this, &SquishServerProcess::onStandardOutput); } @@ -25,7 +25,7 @@ void SquishServerProcess::start(const Utils::CommandLine &commandLine, void SquishServerProcess::stop() { if (m_process.state() != QProcess::NotRunning && m_serverPort > 0) { - Utils::QtcProcess serverKiller; + Utils::Process serverKiller; QStringList args; args << "--stop" << "--port" << QString::number(m_serverPort); serverKiller.setCommand({m_process.commandLine().executable(), args}); diff --git a/src/plugins/squish/squishtools.cpp b/src/plugins/squish/squishtools.cpp index bc09e2fa6cb..37b76136e7e 100644 --- a/src/plugins/squish/squishtools.cpp +++ b/src/plugins/squish/squishtools.cpp @@ -1040,7 +1040,7 @@ void SquishTools::interruptRunner() QTC_ASSERT(m_primaryRunner, return); qint64 processId = m_primaryRunner->processId(); const CommandLine cmd(toolsSettings.processComPath, {QString::number(processId), "break"}); - QtcProcess process; + Process process; process.setCommand(cmd); process.start(); process.waitForFinished(); @@ -1056,7 +1056,7 @@ void SquishTools::terminateRunner() QTC_ASSERT(m_primaryRunner, return); qint64 processId = m_primaryRunner->processId(); const CommandLine cmd(toolsSettings.processComPath, {QString::number(processId), "terminate"}); - QtcProcess process; + Process process; process.setCommand(cmd); process.start(); process.waitForFinished(); diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index ad657188f19..c9b28724eaa 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -171,7 +171,7 @@ SubversionDiffEditorController::SubversionDiffEditorController(IDocument *docume const TreeStorage diffInputStorage = inputStorage(); - const auto setupDescription = [this](QtcProcess &process) { + const auto setupDescription = [this](Process &process) { if (m_changeNumber == 0) return TaskAction::StopWithDone; setupCommand(process, {"log", "-r", QString::number(m_changeNumber)}); @@ -181,14 +181,14 @@ SubversionDiffEditorController::SubversionDiffEditorController(IDocument *docume setDescription(Tr::tr("Waiting for data...")); return TaskAction::Continue; }; - const auto onDescriptionDone = [this](const QtcProcess &process) { + const auto onDescriptionDone = [this](const Process &process) { setDescription(process.cleanedStdOut()); }; - const auto onDescriptionError = [this](const QtcProcess &) { + const auto onDescriptionError = [this](const Process &) { setDescription({}); }; - const auto setupDiff = [this](QtcProcess &process) { + const auto setupDiff = [this](Process &process) { QStringList args = QStringList{"diff"} << "--internal-diff"; if (ignoreWhitespace()) args << "-x" << "-uw"; @@ -202,7 +202,7 @@ SubversionDiffEditorController::SubversionDiffEditorController(IDocument *docume command << SubversionClient::AddAuthOptions(); process.setCommand(command); }; - const auto onDiffDone = [diffInputStorage](const QtcProcess &process) { + const auto onDiffDone = [diffInputStorage](const Process &process) { *diffInputStorage = process.cleanedStdOut(); }; diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp index 00f1b75cd69..230c6e3da83 100644 --- a/src/plugins/terminal/shellintegration.cpp +++ b/src/plugins/terminal/shellintegration.cpp @@ -102,7 +102,7 @@ void ShellIntegration::onOsc(int cmd, const VTermStringFragment &fragment) } } -void ShellIntegration::prepareProcess(Utils::QtcProcess &process) +void ShellIntegration::prepareProcess(Utils::Process &process) { Environment env = process.environment().hasChanges() ? process.environment() : Environment::systemEnvironment(); diff --git a/src/plugins/terminal/shellintegration.h b/src/plugins/terminal/shellintegration.h index 264b5a4d67a..8fce983b019 100644 --- a/src/plugins/terminal/shellintegration.h +++ b/src/plugins/terminal/shellintegration.h @@ -21,7 +21,7 @@ public: void onOsc(int cmd, const VTermStringFragment &fragment); - void prepareProcess(Utils::QtcProcess &process); + void prepareProcess(Utils::Process &process); signals: void commandChanged(const Utils::CommandLine &command); diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 6e13960bccf..11397d87b47 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -137,7 +137,7 @@ TerminalWidget::~TerminalWidget() void TerminalWidget::setupPty() { - m_process = std::make_unique(); + m_process = std::make_unique(); CommandLine shellCommand = m_openParameters.shellCommand.value_or( CommandLine{TerminalSettings::instance().shell.filePath(), @@ -163,11 +163,11 @@ void TerminalWidget::setupPty() m_surface->shellIntegration()->prepareProcess(*m_process.get()); } - connect(m_process.get(), &QtcProcess::readyReadStandardOutput, this, [this]() { + connect(m_process.get(), &Process::readyReadStandardOutput, this, [this]() { onReadyRead(false); }); - connect(m_process.get(), &QtcProcess::done, this, [this] { + connect(m_process.get(), &Process::done, this, [this] { if (m_process) { if (m_process->exitCode() != 0) { QByteArray msg = QString("\r\n\033[31mProcess exited with code: %1") @@ -206,7 +206,7 @@ void TerminalWidget::setupPty() } }); - connect(m_process.get(), &QtcProcess::started, this, [this] { + connect(m_process.get(), &Process::started, this, [this] { if (m_shellName.isEmpty()) m_shellName = m_process->commandLine().executable().fileName(); if (HostOsInfo::isWindowsHost() && m_shellName.endsWith(QTC_WIN_EXE_SUFFIX)) diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 4e1f2906b09..f6ea7d763b9 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -179,7 +179,7 @@ protected: void updateCopyState(); private: - std::unique_ptr m_process; + std::unique_ptr m_process; std::unique_ptr m_surface; std::unique_ptr m_shellIntegration; diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp index 143b5848779..5f02b7e9d02 100644 --- a/src/plugins/texteditor/formattexteditor.cpp +++ b/src/plugins/texteditor/formattexteditor.cpp @@ -64,7 +64,7 @@ static FormatTask format(FormatTask task) // Format temporary file QStringList options = task.command.options(); options.replaceInStrings(QLatin1String("%file"), sourceFile.filePath().toString()); - QtcProcess process; + Process process; process.setTimeoutS(5); process.setCommand({executable, options}); process.runBlocking(); @@ -89,7 +89,7 @@ static FormatTask format(FormatTask task) return task; case Command::PipeProcessing: { - QtcProcess process; + Process process; QStringList options = task.command.options(); options.replaceInStrings("%filename", task.filePath.fileName()); options.replaceInStrings("%file", task.filePath.toString()); diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index 435deb4812f..8ee3247010d 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -119,7 +119,7 @@ void UpdateInfoPlugin::startCheckForUpdates() using namespace Tasking; - const auto doSetup = [this](QtcProcess &process, const QStringList &args) { + const auto doSetup = [this](Process &process, const QStringList &args) { process.setCommand({d->m_maintenanceTool, args}); }; const auto doCleanup = [this] { @@ -127,19 +127,19 @@ void UpdateInfoPlugin::startCheckForUpdates() checkForUpdatesStopped(); }; - const auto setupUpdate = [doSetup](QtcProcess &process) { + const auto setupUpdate = [doSetup](Process &process) { doSetup(process, {"ch", "-g", "*=false,ifw.package.*=true"}); }; - const auto updateDone = [this](const QtcProcess &process) { + const auto updateDone = [this](const Process &process) { d->m_updateOutput = process.cleanedStdOut(); }; QList tasks { ProcessTask(setupUpdate, updateDone) }; if (d->m_settings.checkForQtVersions) { - const auto setupPackages = [doSetup](QtcProcess &process) { + const auto setupPackages = [doSetup](Process &process) { doSetup(process, {"se", "qt[.]qt[0-9][.][0-9]+$", "-g", "*=false,ifw.package.*=true"}); }; - const auto packagesDone = [this](const QtcProcess &process) { + const auto packagesDone = [this](const Process &process) { d->m_packagesOutput = process.cleanedStdOut(); }; tasks << ProcessTask(setupPackages, packagesDone); @@ -461,7 +461,7 @@ QDate UpdateInfoPlugin::nextCheckDate(CheckUpdateInterval interval) const void UpdateInfoPlugin::startMaintenanceTool(const QStringList &args) const { - QtcProcess::startDetached(CommandLine{d->m_maintenanceTool, args}); + Process::startDetached(CommandLine{d->m_maintenanceTool, args}); } void UpdateInfoPlugin::startUpdater() const diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index d238cb89e0c..2c2f73b10e5 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -175,7 +175,7 @@ void CallgrindToolRunner::run(Option option) // save back current running operation m_lastOption = option; - m_controllerProcess.reset(new QtcProcess); + m_controllerProcess.reset(new Process); switch (option) { case CallgrindToolRunner::Dump: @@ -197,7 +197,7 @@ void CallgrindToolRunner::run(Option option) #if CALLGRIND_CONTROL_DEBUG m_controllerProcess->setProcessChannelMode(QProcess::ForwardedChannels); #endif - connect(m_controllerProcess.get(), &QtcProcess::done, + connect(m_controllerProcess.get(), &Process::done, this, &CallgrindToolRunner::controllerProcessDone); const FilePath control = diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index 2f22280ffa8..13d04b63353 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -73,7 +73,7 @@ private: bool m_markAsPaused = false; - std::unique_ptr m_controllerProcess; + std::unique_ptr m_controllerProcess; ProjectExplorer::Runnable m_valgrindRunnable; qint64 m_pid = 0; diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 4daa04efcf6..9b35de452d4 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -361,7 +361,7 @@ CallgrindToolPrivate::CallgrindToolPrivate() action->setIcon(kCachegrindIcon.icon()); action->setToolTip(Tr::tr("Open results in KCachegrind.")); connect(action, &QAction::triggered, this, [this, settings] { - QtcProcess::startDetached({FilePath::fromString(settings->kcachegrindExecutable.value()), { m_lastFileName }}); + Process::startDetached({FilePath::fromString(settings->kcachegrindExecutable.value()), { m_lastFileName }}); }); // dump action diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 7042419a7b5..b07288b175d 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -129,9 +129,9 @@ public: void start() override { QTC_ASSERT(!m_process, return); - m_process.reset(new QtcProcess); + m_process.reset(new Process); m_process->setCommand({device()->filePath("echo"), "-n $SSH_CLIENT", CommandLine::Raw}); - connect(m_process.get(), &QtcProcess::done, this, [this] { + connect(m_process.get(), &Process::done, this, [this] { if (m_process->error() != QProcess::UnknownError) { reportFailure(); return; @@ -159,7 +159,7 @@ public: } private: - std::unique_ptr m_process = nullptr; + std::unique_ptr m_process = nullptr; QHostAddress *m_localServerAddress = nullptr; }; diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index ef84fba6759..3750217ad7c 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -25,18 +25,18 @@ class ValgrindRunner::Private : public QObject { public: Private(ValgrindRunner *owner) : q(owner) { - connect(&m_process, &QtcProcess::started, this, [this] { + connect(&m_process, &Process::started, this, [this] { emit q->valgrindStarted(m_process.processId()); }); - connect(&m_process, &QtcProcess::done, this, [this] { + connect(&m_process, &Process::done, this, [this] { if (m_process.result() != ProcessResult::FinishedWithSuccess) emit q->processErrorReceived(m_process.errorString(), m_process.error()); emit q->finished(); }); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + connect(&m_process, &Process::readyReadStandardOutput, this, [this] { emit q->appendMessage(m_process.readAllStandardOutput(), StdOutFormat); }); - connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { + connect(&m_process, &Process::readyReadStandardError, this, [this] { emit q->appendMessage(m_process.readAllStandardError(), StdErrFormat); }); @@ -53,7 +53,7 @@ public: Runnable m_debuggee; CommandLine m_command; - QtcProcess m_process; + Process m_process; QHostAddress m_localServerAddress; diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index 1bd13f312ab..b781b1772ae 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -90,7 +90,7 @@ VcsCommand *VcsBaseClientImpl::createCommand(const FilePath &workingDirectory, return cmd; } -void VcsBaseClientImpl::setupCommand(Utils::QtcProcess &process, +void VcsBaseClientImpl::setupCommand(Utils::Process &process, const FilePath &workingDirectory, const QStringList &args) const { diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index 4e5bf91d5ff..035e2f00424 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -24,7 +24,7 @@ class QToolBar; QT_END_NAMESPACE namespace Utils { -class QtcProcess; +class Process; } namespace VcsBase { @@ -60,7 +60,7 @@ public: VcsCommand *createCommand(const Utils::FilePath &workingDirectory, VcsBaseEditorWidget *editor = nullptr) const; - void setupCommand(Utils::QtcProcess &process, + void setupCommand(Utils::Process &process, const Utils::FilePath &workingDirectory, const QStringList &args) const; diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index 527a81be7e9..aaea619a2b1 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -66,7 +66,7 @@ Tasking::TaskItem VcsBaseDiffEditorController::postProcessTask() return AsyncTask>(setupDiffProcessor, onDiffProcessorDone, onDiffProcessorError); } -void VcsBaseDiffEditorController::setupCommand(QtcProcess &process, const QStringList &args) const +void VcsBaseDiffEditorController::setupCommand(Process &process, const QStringList &args) const { process.setEnvironment(d->m_processEnvironment); process.setWorkingDirectory(workingDirectory()); diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.h b/src/plugins/vcsbase/vcsbasediffeditorcontroller.h index 75672edb1ff..22d651fe720 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.h +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.h @@ -9,7 +9,7 @@ namespace Utils { class Environment; -class QtcProcess; +class Process; } // Utils namespace VcsBase { @@ -31,7 +31,7 @@ protected: Utils::Tasking::TreeStorage inputStorage() const; Utils::Tasking::TaskItem postProcessTask(); - void setupCommand(Utils::QtcProcess &process, const QStringList &args) const; + void setupCommand(Utils::Process &process, const QStringList &args) const; private: friend class VcsBaseDiffEditorControllerPrivate; diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 23a41f363ea..0d9f92a702e 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -561,7 +561,7 @@ bool VcsBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript // Run check process VcsOutputWindow::appendShellCommandLine(msgCheckScript(d->m_checkScriptWorkingDirectory, checkScript)); - QtcProcess checkProcess; + Process checkProcess; if (!d->m_checkScriptWorkingDirectory.isEmpty()) checkProcess.setWorkingDirectory(d->m_checkScriptWorkingDirectory); checkProcess.setCommand({FilePath::fromString(checkScript), {saver.filePath().toString()}}); diff --git a/src/plugins/vcsbase/vcscommand.cpp b/src/plugins/vcsbase/vcscommand.cpp index 5a4f43d28cb..a16545b70ba 100644 --- a/src/plugins/vcsbase/vcscommand.cpp +++ b/src/plugins/vcsbase/vcscommand.cpp @@ -55,10 +55,10 @@ public: void setup(); void cleanup(); - void setupProcess(QtcProcess *process, const Job &job); - void installStdCallbacks(QtcProcess *process); + void setupProcess(Process *process, const Job &job); + void installStdCallbacks(Process *process); EventLoopMode eventLoopMode() const; - void handleDone(QtcProcess *process); + void handleDone(Process *process); void startAll(); void startNextJob(); void processDone(); @@ -73,7 +73,7 @@ public: QList m_jobs; int m_currentJob = 0; - std::unique_ptr m_process; + std::unique_ptr m_process; QString m_stdOut; QString m_stdErr; ProcessResult m_result = ProcessResult::StartFailed; @@ -99,7 +99,7 @@ void VcsCommandPrivate::cleanup() GlobalFileChangeBlocker::instance()->forceBlocked(false); } -void VcsCommandPrivate::setupProcess(QtcProcess *process, const Job &job) +void VcsCommandPrivate::setupProcess(Process *process, const Job &job) { process->setExitCodeInterpreter(job.exitCodeInterpreter); process->setTimeoutS(job.timeoutS); @@ -127,12 +127,12 @@ void VcsCommandPrivate::setupProcess(QtcProcess *process, const Job &job) progress->setProgressParser(m_progressParser); } -void VcsCommandPrivate::installStdCallbacks(QtcProcess *process) +void VcsCommandPrivate::installStdCallbacks(Process *process) { if (!(m_flags & RunFlags::MergeOutputChannels) && (m_flags & RunFlags::ProgressiveOutput || m_progressParser || !(m_flags & RunFlags::SuppressStdErr))) { process->setTextChannelMode(Channel::Error, TextChannelMode::MultiLine); - connect(process, &QtcProcess::textOnStandardError, this, [this](const QString &text) { + connect(process, &Process::textOnStandardError, this, [this](const QString &text) { if (!(m_flags & RunFlags::SuppressStdErr)) VcsOutputWindow::appendError(text); if (m_flags & RunFlags::ProgressiveOutput) @@ -142,7 +142,7 @@ void VcsCommandPrivate::installStdCallbacks(QtcProcess *process) if (m_progressParser || m_flags & RunFlags::ProgressiveOutput || m_flags & RunFlags::ShowStdOut) { process->setTextChannelMode(Channel::Output, TextChannelMode::MultiLine); - connect(process, &QtcProcess::textOnStandardOutput, this, [this](const QString &text) { + connect(process, &Process::textOnStandardOutput, this, [this](const QString &text) { if (m_flags & RunFlags::ShowStdOut) VcsOutputWindow::append(text); if (m_flags & RunFlags::ProgressiveOutput) @@ -158,7 +158,7 @@ EventLoopMode VcsCommandPrivate::eventLoopMode() const return EventLoopMode::Off; } -void VcsCommandPrivate::handleDone(QtcProcess *process) +void VcsCommandPrivate::handleDone(Process *process) { // Success/Fail message in appropriate window? if (process->result() == ProcessResult::FinishedWithSuccess) { @@ -187,8 +187,8 @@ void VcsCommandPrivate::startAll() void VcsCommandPrivate::startNextJob() { QTC_ASSERT(m_currentJob < m_jobs.count(), return); - m_process.reset(new QtcProcess); - connect(m_process.get(), &QtcProcess::done, this, &VcsCommandPrivate::processDone); + m_process.reset(new Process); + connect(m_process.get(), &Process::done, this, &VcsCommandPrivate::processDone); setupProcess(m_process.get(), m_jobs.at(m_currentJob)); m_process->start(); } @@ -297,7 +297,7 @@ CommandResult VcsCommand::runBlocking(const Utils::FilePath &workingDirectory, CommandResult VcsCommand::runBlockingHelper(const CommandLine &command, int timeoutS) { - QtcProcess process; + Process process; if (command.executable().isEmpty()) return {}; @@ -321,7 +321,7 @@ void VcsCommand::setProgressParser(const ProgressParser &parser) d->m_progressParser = parser; } -CommandResult::CommandResult(const QtcProcess &process) +CommandResult::CommandResult(const Process &process) : m_result(process.result()) , m_exitCode(process.exitCode()) , m_exitMessage(process.exitMessage()) diff --git a/src/plugins/vcsbase/vcscommand.h b/src/plugins/vcsbase/vcscommand.h index 568d1095801..1cc4d5db54e 100644 --- a/src/plugins/vcsbase/vcscommand.h +++ b/src/plugins/vcsbase/vcscommand.h @@ -20,7 +20,7 @@ QT_END_NAMESPACE namespace Utils { class CommandLine; class Environment; -class QtcProcess; +class Process; } namespace VcsBase { @@ -33,7 +33,7 @@ class VCSBASE_EXPORT CommandResult { public: CommandResult() = default; - CommandResult(const Utils::QtcProcess &process); + CommandResult(const Utils::Process &process); CommandResult(const VcsCommand &command); CommandResult(Utils::ProcessResult result, const QString &exitMessage) : m_result(result), m_exitMessage(exitMessage) {} diff --git a/src/plugins/webassembly/webassemblyemsdk.cpp b/src/plugins/webassembly/webassemblyemsdk.cpp index 4acf6589c4d..e66df1272da 100644 --- a/src/plugins/webassembly/webassemblyemsdk.cpp +++ b/src/plugins/webassembly/webassemblyemsdk.cpp @@ -29,7 +29,7 @@ static QString emSdkEnvOutput(const FilePath &sdkRoot) if (!emSdkEnvCache()->contains(cacheKey)) { const FilePath scriptFile = sdkRoot.pathAppended(QLatin1String("emsdk_env") + (isWindows ? ".bat" : ".sh")); - QtcProcess emSdkEnv; + Process emSdkEnv; if (isWindows) { emSdkEnv.setCommand(CommandLine(scriptFile)); } else { @@ -88,7 +88,7 @@ QVersionNumber version(const FilePath &sdkRoot) QLatin1String scriptFile{sdkRoot.osType() == OsType::OsTypeWindows ? "emcc.bat" : "emcc"}; FilePath script = sdkRoot.withNewPath(scriptFile).searchInDirectories(env.path()); const CommandLine command(script, {"-dumpversion"}); - QtcProcess emcc; + Process emcc; emcc.setCommand(command); emcc.setEnvironment(env); emcc.runBlocking(); diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp index abd6de8ed61..70484168ebe 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp @@ -29,7 +29,7 @@ static WebBrowserEntries emrunBrowsers(ProjectExplorer::Target *target) const Utils::Environment environment = bc->environment(); const Utils::FilePath emrunPath = environment.searchInPath("emrun"); - QtcProcess browserLister; + Process browserLister; browserLister.setEnvironment(environment); browserLister.setCommand({emrunPath, {"--list_browsers"}}); browserLister.start(); diff --git a/tests/auto/utils/commandline/tst_commandline.cpp b/tests/auto/utils/commandline/tst_commandline.cpp index 6972ae6ba39..c20eb48db91 100644 --- a/tests/auto/utils/commandline/tst_commandline.cpp +++ b/tests/auto/utils/commandline/tst_commandline.cpp @@ -30,7 +30,7 @@ private: QString run(const CommandLine &cmd) { - QtcProcess p; + Process p; p.setCommand(cmd); p.setEnvironment(testEnv); p.runBlocking(); diff --git a/tests/auto/utils/deviceshell/tst_deviceshell.cpp b/tests/auto/utils/deviceshell/tst_deviceshell.cpp index 1d95bde4091..f94d0dc5b40 100644 --- a/tests/auto/utils/deviceshell/tst_deviceshell.cpp +++ b/tests/auto/utils/deviceshell/tst_deviceshell.cpp @@ -28,7 +28,7 @@ public: } private: - void setupShellProcess(QtcProcess *shellProcess) override + void setupShellProcess(Process *shellProcess) override { shellProcess->setCommand(m_cmdLine); } @@ -38,7 +38,7 @@ private: bool testDocker(const FilePath &executable) { - QtcProcess p; + Process p; p.setCommand({executable, {"info", "--format", "{{.OSType}}"}}); p.runBlocking(); const QString platform = p.cleanedStdOut().trimmed(); diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp index 0884ab44a78..1fa73a94759 100644 --- a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp +++ b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp @@ -77,7 +77,7 @@ SubProcessConfig::SubProcessConfig(const char *envVar, const QString &envVal) { } -void SubProcessConfig::setupSubProcess(QtcProcess *subProcess) const +void SubProcessConfig::setupSubProcess(Process *subProcess) const { subProcess->setEnvironment(m_environment); const FilePath filePath = FilePath::fromString(s_pathToProcessTestApp @@ -148,7 +148,7 @@ int ProcessTestApp::ChannelForwarding::main() qunsetenv(envVar()); SubProcessConfig subConfig(StandardOutputAndErrorWriter::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.setProcessChannelMode(channelMode); @@ -206,7 +206,7 @@ int ProcessTestApp::RecursiveCrashingProcess::main() return 1; } SubProcessConfig subConfig(envVar(), QString::number(currentDepth - 1)); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); process.waitForFinished(); @@ -249,7 +249,7 @@ int ProcessTestApp::RecursiveBlockingProcess::main() } } SubProcessConfig subConfig(envVar(), QString::number(currentDepth - 1)); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.setProcessChannelMode(QProcess::ForwardedChannels); process.start(); diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h index d529ac8265d..721ab83ae75 100644 --- a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h +++ b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h @@ -11,7 +11,7 @@ QT_BEGIN_NAMESPACE class QProcess; QT_END_NAMESPACE -namespace Utils { class QtcProcess; } +namespace Utils { class Process; } #define SUB_PROCESS(SubProcessClass)\ class SubProcessClass\ @@ -72,7 +72,7 @@ class SubProcessConfig { public: SubProcessConfig(const char *envVar, const QString &envVal); - void setupSubProcess(Utils::QtcProcess *subProcess) const; + void setupSubProcess(Utils::Process *subProcess) const; void setupSubProcess(QProcess *subProcess) const; static void setPathToProcessTestApp(const QString &path); diff --git a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp index bd8bb58af25..1bc1778237d 100644 --- a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp @@ -109,7 +109,7 @@ private slots: qDebug() << "QProcess output:" << qoutput; QCOMPARE(qproc.exitCode(), 0); - QtcProcess qtcproc; + Process qtcproc; qtcproc.setCommand({envPath, {}}); qtcproc.runBlocking(); QCOMPARE(qtcproc.exitCode(), 0); @@ -250,7 +250,7 @@ void tst_QtcProcess::multiRead() QSKIP("This test uses /bin/sh."); QByteArray buffer; - QtcProcess process; + Process process; process.setCommand({"/bin/sh", {}}); process.setProcessChannelMode(QProcess::SeparateChannels); @@ -902,7 +902,7 @@ void tst_QtcProcess::exitCode() SubProcessConfig subConfig(ProcessTestApp::ExitCode::envVar(), QString::number(exitCode)); { - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); const bool finished = process.waitForFinished(); @@ -912,7 +912,7 @@ void tst_QtcProcess::exitCode() QCOMPARE(process.exitCode() == 0, process.result() == ProcessResult::FinishedWithSuccess); } { - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.runBlocking(); @@ -949,7 +949,7 @@ void tst_QtcProcess::runBlockingStdOut() QFETCH(ProcessResult, expectedResult); SubProcessConfig subConfig(ProcessTestApp::RunBlockingStdOut::envVar(), withEndl ? "true" : "false"); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.setTimeoutS(timeOutS); @@ -980,13 +980,13 @@ void tst_QtcProcess::runBlockingSignal() QFETCH(ProcessResult, expectedResult); SubProcessConfig subConfig(ProcessTestApp::RunBlockingStdOut::envVar(), withEndl ? "true" : "false"); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.setTimeoutS(timeOutS); bool readLastLine = false; process.setTextChannelMode(Channel::Output, TextChannelMode::MultiLine); - connect(&process, &QtcProcess::textOnStandardOutput, + connect(&process, &Process::textOnStandardOutput, this, [&readLastLine, &process](const QString &out) { if (out.startsWith(s_runBlockingStdOutSubProcessMagicWord)) { readLastLine = true; @@ -1004,7 +1004,7 @@ void tst_QtcProcess::runBlockingSignal() void tst_QtcProcess::lineCallback() { SubProcessConfig subConfig(ProcessTestApp::LineCallback::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); const QStringList lines = QString(s_lineCallbackData).split('|'); @@ -1027,13 +1027,13 @@ void tst_QtcProcess::lineCallback() void tst_QtcProcess::lineSignal() { SubProcessConfig subConfig(ProcessTestApp::LineCallback::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); const QStringList lines = QString(s_lineCallbackData).split('|'); int lineNumber = 0; process.setTextChannelMode(Channel::Error, TextChannelMode::SingleLine); - connect(&process, &QtcProcess::textOnStandardError, + connect(&process, &Process::textOnStandardError, this, [lines, &lineNumber](const QString &actual) { QString expected = lines.at(lineNumber); expected.replace("\r\n", "\n"); @@ -1052,12 +1052,12 @@ void tst_QtcProcess::lineSignal() void tst_QtcProcess::waitForStartedAfterStarted() { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); bool started = false; bool waitForStartedResult = false; - connect(&process, &QtcProcess::started, this, [&] { + connect(&process, &Process::started, this, [&] { started = true; waitForStartedResult = process.waitForStarted(); }); @@ -1093,7 +1093,7 @@ void tst_QtcProcess::waitForStartedAfterStarted2() void tst_QtcProcess::waitForStartedAndFinished() { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); @@ -1119,12 +1119,12 @@ void tst_QtcProcess::notRunningAfterStartingNonExistingProgram() { QFETCH(ProcessSignalType, signalType); - QtcProcess process; + Process process; process.setCommand({ FilePath::fromString( "there_is_a_big_chance_that_executable_with_that_name_does_not_exists"), {} }); int doneCount = 0; - QObject::connect(&process, &QtcProcess::done, [&process, &doneCount]() { + QObject::connect(&process, &Process::done, [&process, &doneCount]() { ++doneCount; QCOMPARE(process.error(), QProcess::FailedToStart); }); @@ -1186,7 +1186,7 @@ void tst_QtcProcess::channelForwarding() SubProcessConfig subConfig(ProcessTestApp::ChannelForwarding::envVar(), QString::number(int(channelMode))); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); @@ -1229,7 +1229,7 @@ void tst_QtcProcess::mergedChannels() QFETCH(bool, errorOnError); SubProcessConfig subConfig(ProcessTestApp::StandardOutputAndErrorWriter::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.setProcessChannelMode(channelMode); @@ -1262,7 +1262,7 @@ void tst_QtcProcess::destroyBlockingProcess() SubProcessConfig subConfig(ProcessTestApp::BlockingProcess::envVar(), QString::number(int(blockType))); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); QVERIFY(process.waitForStarted()); @@ -1272,7 +1272,7 @@ void tst_QtcProcess::destroyBlockingProcess() void tst_QtcProcess::flushFinishedWhileWaitingForReadyRead() { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); @@ -1297,7 +1297,7 @@ void tst_QtcProcess::flushFinishedWhileWaitingForReadyRead() void tst_QtcProcess::crash() { SubProcessConfig subConfig(ProcessTestApp::Crash::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); @@ -1305,7 +1305,7 @@ void tst_QtcProcess::crash() QVERIFY(process.isRunning()); QEventLoop loop; - connect(&process, &QtcProcess::done, &loop, &QEventLoop::quit); + connect(&process, &Process::done, &loop, &QEventLoop::quit); loop.exec(); QCOMPARE(process.error(), QProcess::Crashed); @@ -1315,7 +1315,7 @@ void tst_QtcProcess::crash() void tst_QtcProcess::crashAfterOneSecond() { SubProcessConfig subConfig(ProcessTestApp::CrashAfterOneSecond::envVar(), {}); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); @@ -1335,7 +1335,7 @@ void tst_QtcProcess::recursiveCrashingProcess() const int recursionDepth = 5; // must be at least 2 SubProcessConfig subConfig(ProcessTestApp::RecursiveCrashingProcess::envVar(), QString::number(recursionDepth)); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); QVERIFY(process.waitForStarted(1000)); @@ -1367,7 +1367,7 @@ void tst_QtcProcess::recursiveBlockingProcess() SubProcessConfig subConfig(ProcessTestApp::RecursiveBlockingProcess::envVar(), QString::number(recursionDepth)); { - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); process.start(); QVERIFY(process.waitForStarted(1000)); @@ -1421,10 +1421,10 @@ void tst_QtcProcess::quitBlockingProcess() SubProcessConfig subConfig(ProcessTestApp::RecursiveBlockingProcess::envVar(), QString::number(recursionDepth)); - QtcProcess process; + Process process; subConfig.setupSubProcess(&process); bool done = false; - connect(&process, &QtcProcess::done, this, [&done] { done = true; }); + connect(&process, &Process::done, this, [&done] { done = true; }); process.start(); QVERIFY(process.waitForStarted()); @@ -1472,12 +1472,12 @@ void tst_QtcProcess::tarPipe() if (!FilePath::fromString("tar").searchInPath().isExecutableFile()) QSKIP("This test uses \"tar\" command."); - QtcProcess sourceProcess; - QtcProcess targetProcess; + Process sourceProcess; + Process targetProcess; targetProcess.setProcessMode(ProcessMode::Writer); - QObject::connect(&sourceProcess, &QtcProcess::readyReadStandardOutput, + QObject::connect(&sourceProcess, &Process::readyReadStandardOutput, &targetProcess, [&sourceProcess, &targetProcess]() { targetProcess.writeRaw(sourceProcess.readAllRawStandardOutput()); }); diff --git a/tests/manual/deviceshell/tst_deviceshell.cpp b/tests/manual/deviceshell/tst_deviceshell.cpp index 2703e6b82d6..96638763f8e 100644 --- a/tests/manual/deviceshell/tst_deviceshell.cpp +++ b/tests/manual/deviceshell/tst_deviceshell.cpp @@ -54,7 +54,7 @@ public: } private: - void setupShellProcess(QtcProcess *shellProcess) override + void setupShellProcess(Process *shellProcess) override { shellProcess->setCommand(cmdLine()); } From a0f6e8dc04291138ec2305fe7c02a0a460f57fac Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 17:05:35 +0200 Subject: [PATCH 0810/1447] Utils: Rename qtcprocess.{cpp,h} -> process.{cpp,h} Follows QtcProcess -> Process rename. Change-Id: I97235a9a40cb7fd52944515b7ab878d96528f919 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/extensionsystem/pluginmanager.cpp | 2 +- src/libs/qmljs/qmljsplugindumper.cpp | 2 +- src/libs/utils/CMakeLists.txt | 2 +- src/libs/utils/archive.cpp | 2 +- src/libs/utils/buildablehelperlibrary.cpp | 2 +- src/libs/utils/clangutils.cpp | 2 +- src/libs/utils/devicefileaccess.cpp | 2 +- src/libs/utils/deviceshell.cpp | 2 +- src/libs/utils/filestreamer.cpp | 2 +- src/libs/utils/pathchooser.cpp | 2 +- src/libs/utils/{qtcprocess.cpp => process.cpp} | 4 ++-- src/libs/utils/{qtcprocess.h => process.h} | 0 src/libs/utils/processinfo.cpp | 2 +- src/libs/utils/terminalhooks.cpp | 2 +- src/libs/utils/utils.qbs | 4 ++-- src/plugins/android/androidavdmanager.cpp | 2 +- src/plugins/android/androidbuildapkstep.cpp | 2 +- src/plugins/android/androidconfigurations.cpp | 2 +- .../android/androidcreatekeystorecertificate.cpp | 2 +- src/plugins/android/androiddebugsupport.cpp | 2 +- src/plugins/android/androiddeployqtstep.cpp | 2 +- src/plugins/android/androiddevice.cpp | 2 +- src/plugins/android/androidmanager.cpp | 2 +- .../android/androidpackageinstallationstep.cpp | 2 +- src/plugins/android/androidqmlpreviewworker.cpp | 2 +- src/plugins/android/androidrunconfiguration.cpp | 2 +- src/plugins/android/androidrunnerworker.cpp | 2 +- src/plugins/android/androidsdkmanager.cpp | 2 +- src/plugins/android/androidsettingswidget.cpp | 2 +- src/plugins/android/androidsignaloperation.cpp | 2 +- src/plugins/autotest/boost/boosttestoutputreader.cpp | 2 +- src/plugins/autotest/gtest/gtestoutputreader.cpp | 2 +- src/plugins/autotest/testoutputreader.cpp | 2 +- src/plugins/autotest/testrunner.cpp | 2 +- .../autotoolsprojectmanager/makefileparser.cpp | 2 +- src/plugins/baremetal/baremetaldebugsupport.cpp | 2 +- .../debugservers/gdb/jlinkgdbserverprovider.cpp | 2 +- .../debugservers/gdb/openocdgdbserverprovider.cpp | 2 +- .../baremetal/debugservers/uvsc/uvscserverprovider.h | 2 +- src/plugins/baremetal/iarewtoolchain.cpp | 2 +- src/plugins/baremetal/keiltoolchain.cpp | 2 +- src/plugins/baremetal/sdcctoolchain.cpp | 2 +- src/plugins/beautifier/abstractsettings.cpp | 2 +- .../artisticstyle/artisticstylesettings.cpp | 2 +- src/plugins/beautifier/beautifierplugin.cpp | 2 +- .../beautifier/uncrustify/uncrustifysettings.cpp | 2 +- src/plugins/boot2qt/device-detection/qdbwatcher.cpp | 2 +- src/plugins/boot2qt/qdbdevice.cpp | 2 +- src/plugins/boot2qt/qdbdevicedebugsupport.cpp | 2 +- src/plugins/boot2qt/qdbmakedefaultappstep.cpp | 2 +- src/plugins/boot2qt/qdbplugin.cpp | 4 ++-- src/plugins/boot2qt/qdbstopapplicationstep.cpp | 2 +- src/plugins/clangtools/clangtoolruncontrol.cpp | 2 +- src/plugins/clangtools/clangtoolrunner.cpp | 2 +- src/plugins/clangtools/clangtoolsutils.cpp | 2 +- src/plugins/clangtools/executableinfo.cpp | 2 +- src/plugins/clearcase/clearcaseplugin.cpp | 2 +- src/plugins/clearcase/clearcasesync.cpp | 2 +- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 2 +- .../cmakeprojectmanager/cmakeformattersettings.cpp | 2 +- src/plugins/cmakeprojectmanager/cmakeprocess.cpp | 2 +- .../cmakeprojectmanager/cmakeprojectimporter.cpp | 2 +- src/plugins/cmakeprojectmanager/cmaketool.cpp | 2 +- .../cmakeprojectmanager/fileapidataextractor.cpp | 2 +- src/plugins/coreplugin/dialogs/externaltoolconfig.cpp | 2 +- src/plugins/coreplugin/externaltool.cpp | 2 +- src/plugins/coreplugin/fileutils.cpp | 2 +- src/plugins/coreplugin/locator/executefilter.cpp | 2 +- .../coreplugin/locator/spotlightlocatorfilter.cpp | 2 +- src/plugins/coreplugin/patchtool.cpp | 2 +- src/plugins/coreplugin/plugininstallwizard.cpp | 2 +- .../coreplugin/progressmanager/processprogress.cpp | 2 +- src/plugins/cppcheck/cppcheckrunner.h | 2 +- src/plugins/cppeditor/cppcodemodelsettings.cpp | 2 +- src/plugins/cppeditor/cppmodelmanager.cpp | 2 +- src/plugins/debugger/cdb/cdbengine.cpp | 2 +- src/plugins/debugger/cdb/cdbengine.h | 2 +- src/plugins/debugger/dap/dapengine.cpp | 2 +- src/plugins/debugger/dap/dapengine.h | 2 +- src/plugins/debugger/debuggerengine.cpp | 2 +- src/plugins/debugger/debuggeritem.cpp | 2 +- src/plugins/debugger/debuggeritemmanager.cpp | 2 +- src/plugins/debugger/debuggerruncontrol.cpp | 2 +- .../debugger/debuggersourcepathmappingwidget.cpp | 2 +- src/plugins/debugger/gdb/gdbengine.cpp | 2 +- src/plugins/debugger/gdb/gdbengine.h | 2 +- src/plugins/debugger/lldb/lldbengine.cpp | 2 +- src/plugins/debugger/lldb/lldbengine.h | 2 +- src/plugins/debugger/moduleshandler.cpp | 2 +- src/plugins/debugger/pdb/pdbengine.cpp | 2 +- src/plugins/debugger/pdb/pdbengine.h | 2 +- src/plugins/debugger/qml/qmlengine.cpp | 2 +- src/plugins/debugger/terminal.cpp | 2 +- src/plugins/docker/dockerapi.cpp | 2 +- src/plugins/docker/dockerdevice.cpp | 2 +- src/plugins/fakevim/fakevimplugin.cpp | 2 +- src/plugins/fossil/fossilclient.cpp | 2 +- src/plugins/genericprojectmanager/genericproject.cpp | 2 +- src/plugins/git/branchmodel.cpp | 2 +- src/plugins/git/changeselectiondialog.cpp | 2 +- src/plugins/git/gerrit/gerritmodel.cpp | 2 +- src/plugins/git/gerrit/gerritplugin.cpp | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/git/gitclient.h | 2 +- src/plugins/git/gitgrep.cpp | 2 +- src/plugins/git/mergetool.h | 2 +- src/plugins/gitlab/gitlabclonedialog.cpp | 2 +- src/plugins/gitlab/queryrunner.h | 2 +- src/plugins/haskell/haskellmanager.cpp | 2 +- src/plugins/incredibuild/cmakecommandbuilder.cpp | 2 +- src/plugins/ios/iosbuildstep.cpp | 2 +- src/plugins/ios/iosconfigurations.cpp | 2 +- src/plugins/ios/iosdsymbuildstep.cpp | 11 ++++++----- src/plugins/ios/iosprobe.cpp | 2 +- src/plugins/ios/iosrunconfiguration.cpp | 4 ++-- src/plugins/ios/iosrunner.cpp | 2 +- src/plugins/ios/iossimulator.cpp | 2 +- src/plugins/ios/iostoolhandler.cpp | 2 +- src/plugins/ios/simulatorcontrol.cpp | 2 +- src/plugins/languageclient/client.cpp | 2 +- src/plugins/languageclient/languageclientinterface.h | 2 +- src/plugins/mcusupport/mcuqmlprojectnode.h | 2 +- src/plugins/mcusupport/mcusupportversiondetection.cpp | 2 +- src/plugins/mercurial/mercurialclient.cpp | 2 +- .../mesonprojectmanager/mesonbuildconfiguration.cpp | 2 +- src/plugins/mesonprojectmanager/mesonprocess.cpp | 2 +- src/plugins/mesonprojectmanager/mesonwrapper.h | 2 +- src/plugins/mesonprojectmanager/toolwrapper.cpp | 2 +- src/plugins/nim/project/nimblebuildsystem.cpp | 2 +- src/plugins/nim/project/nimcompilerbuildstep.cpp | 2 +- src/plugins/nim/project/nimtoolchain.cpp | 2 +- src/plugins/nim/suggest/server.h | 2 +- src/plugins/perforce/perforcechecker.h | 2 +- src/plugins/perforce/perforceplugin.cpp | 2 +- src/plugins/perfprofiler/perfconfigwidget.cpp | 2 +- src/plugins/perfprofiler/perfprofilerruncontrol.cpp | 2 +- src/plugins/perfprofiler/perfsettings.cpp | 2 +- src/plugins/perfprofiler/perftracepointdialog.cpp | 4 ++-- src/plugins/projectexplorer/abstractprocessstep.cpp | 2 +- .../customwizard/customwizardscriptgenerator.cpp | 2 +- .../projectexplorer/devicesupport/desktopdevice.cpp | 2 +- .../projectexplorer/devicesupport/devicemanager.cpp | 2 +- .../devicesupport/deviceusedportsgatherer.cpp | 2 +- .../projectexplorer/devicesupport/sshparameters.cpp | 2 +- src/plugins/projectexplorer/extracompiler.cpp | 2 +- src/plugins/projectexplorer/gcctoolchain.cpp | 2 +- src/plugins/projectexplorer/makestep.cpp | 2 +- src/plugins/projectexplorer/msvctoolchain.cpp | 2 +- src/plugins/projectexplorer/processparameters.cpp | 2 +- src/plugins/projectexplorer/projectmodels.cpp | 2 +- .../projectexplorer/runconfigurationaspects.cpp | 2 +- src/plugins/projectexplorer/runcontrol.cpp | 2 +- src/plugins/projectexplorer/targetsetuppage.cpp | 7 +++---- src/plugins/projectexplorer/taskfile.cpp | 2 +- src/plugins/projectexplorer/toolchainconfigwidget.cpp | 2 +- src/plugins/projectexplorer/userfileaccessor.cpp | 2 +- src/plugins/python/pipsupport.cpp | 2 +- src/plugins/python/pipsupport.h | 2 +- src/plugins/python/pyside.cpp | 3 +-- src/plugins/python/pysideuicextracompiler.cpp | 2 +- src/plugins/python/pythonlanguageclient.cpp | 2 +- src/plugins/python/pythonsettings.cpp | 2 +- src/plugins/python/pythonutils.cpp | 2 +- .../qbsprojectmanager/qbsbuildconfiguration.cpp | 2 +- src/plugins/qbsprojectmanager/qbsbuildstep.cpp | 2 +- src/plugins/qbsprojectmanager/qbsprofilemanager.cpp | 2 +- src/plugins/qbsprojectmanager/qbssession.cpp | 2 +- src/plugins/qbsprojectmanager/qbssettings.cpp | 2 +- .../qmakeprojectmanager/librarydetailscontroller.cpp | 2 +- src/plugins/qmakeprojectmanager/makefileparse.cpp | 2 +- .../qmakeprojectmanager/qmakebuildconfiguration.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakemakestep.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 2 +- .../qmakeprojectmanager/qmakeprojectimporter.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 2 +- .../components/componentcore/modelnodeoperations.cpp | 2 +- .../designercore/instances/nodeinstanceview.cpp | 2 +- src/plugins/qmldesigner/generateresource.cpp | 2 +- src/plugins/qmlpreview/qmlpreviewruncontrol.cpp | 2 +- src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp | 2 +- src/plugins/qmlprojectmanager/qmlproject.cpp | 2 +- src/plugins/qmlprojectmanager/qmlprojectplugin.cpp | 2 +- .../qmlprojectmanager/qmlprojectrunconfiguration.cpp | 2 +- src/plugins/qnx/qnxanalyzesupport.cpp | 3 +-- src/plugins/qnx/qnxdebugsupport.cpp | 2 +- src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp | 2 +- src/plugins/qnx/qnxdevice.cpp | 2 +- src/plugins/qnx/qnxdevicetester.cpp | 3 +-- src/plugins/qnx/qnxutils.cpp | 2 +- src/plugins/qnx/slog2inforunner.cpp | 2 +- src/plugins/qtsupport/baseqtversion.cpp | 2 +- src/plugins/qtsupport/externaleditors.cpp | 2 +- src/plugins/qtsupport/qtsupportplugin.cpp | 2 +- src/plugins/qtsupport/qtversionmanager.cpp | 2 +- src/plugins/qtsupport/uicgenerator.cpp | 11 ++++++----- src/plugins/remotelinux/customcommanddeploystep.cpp | 2 +- src/plugins/remotelinux/filesystemaccess_test.cpp | 2 +- src/plugins/remotelinux/genericdirectuploadstep.cpp | 2 +- src/plugins/remotelinux/linuxdevice.cpp | 2 +- src/plugins/remotelinux/linuxdevicetester.cpp | 2 +- src/plugins/remotelinux/makeinstallstep.cpp | 2 +- src/plugins/remotelinux/publickeydeploymentdialog.cpp | 2 +- .../remotelinux/remotelinuxsignaloperation.cpp | 2 +- src/plugins/remotelinux/rsyncdeploystep.cpp | 2 +- src/plugins/remotelinux/sshkeycreationdialog.cpp | 2 +- src/plugins/remotelinux/tarpackagedeploystep.cpp | 2 +- .../silversearcher/findinfilessilversearcher.cpp | 2 +- src/plugins/squish/objectsmapdocument.cpp | 2 +- src/plugins/squish/squishprocessbase.h | 2 +- src/plugins/squish/squishtools.h | 2 +- src/plugins/subversion/subversionclient.cpp | 3 +-- src/plugins/terminal/shellintegration.h | 2 +- src/plugins/terminal/terminalwidget.h | 2 +- src/plugins/texteditor/formattexteditor.cpp | 2 +- src/plugins/updateinfo/updateinfoplugin.cpp | 2 +- src/plugins/valgrind/callgrindengine.cpp | 2 +- src/plugins/valgrind/callgrindengine.h | 2 +- src/plugins/valgrind/callgrindtool.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 2 +- src/plugins/valgrind/valgrindrunner.cpp | 2 +- src/plugins/vcsbase/vcsbaseclient.cpp | 2 +- src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp | 2 +- src/plugins/vcsbase/vcsbaseplugin.cpp | 2 +- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 2 +- src/plugins/vcsbase/vcscommand.cpp | 2 +- src/plugins/vcsbase/vcsoutputwindow.cpp | 2 +- src/plugins/webassembly/webassemblyemsdk.cpp | 2 +- .../webassemblyrunconfigurationaspects.cpp | 2 +- tests/auto/utils/commandline/tst_commandline.cpp | 2 +- tests/auto/utils/deviceshell/tst_deviceshell.cpp | 2 +- tests/auto/utils/qtcprocess/processtestapp/main.cpp | 2 +- .../qtcprocess/processtestapp/processtestapp.cpp | 2 +- tests/auto/utils/qtcprocess/tst_qtcprocess.cpp | 2 +- tests/manual/deviceshell/tst_deviceshell.cpp | 2 +- 235 files changed, 251 insertions(+), 254 deletions(-) rename src/libs/utils/{qtcprocess.cpp => process.cpp} (99%) rename src/libs/utils/{qtcprocess.h => process.h} (100%) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index c22cdfdca0a..3ee99510552 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -35,8 +35,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index b5669057359..761df90ddcd 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index f26c08c7b56..defbbf27943 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -127,6 +127,7 @@ add_qtc_library(Utils port.cpp port.h portlist.cpp portlist.h predicates.h + process.cpp process.h processenums.h processhandle.cpp processhandle.h processinfo.cpp processinfo.h @@ -139,7 +140,6 @@ add_qtc_library(Utils qrcparser.cpp qrcparser.h qtcassert.cpp qtcassert.h qtcolorbutton.cpp qtcolorbutton.h - qtcprocess.cpp qtcprocess.h qtcsettings.cpp qtcsettings.h ranges.h reloadpromptutils.cpp reloadpromptutils.h diff --git a/src/libs/utils/archive.cpp b/src/libs/utils/archive.cpp index db541293e39..5e62835a20f 100644 --- a/src/libs/utils/archive.cpp +++ b/src/libs/utils/archive.cpp @@ -5,8 +5,8 @@ #include "algorithm.h" #include "mimeutils.h" +#include "process.h" #include "qtcassert.h" -#include "qtcprocess.h" #include "utilstr.h" #include diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index f4cb50b454f..cafd5b0452c 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -4,7 +4,7 @@ #include "buildablehelperlibrary.h" #include "environment.h" #include "hostosinfo.h" -#include "qtcprocess.h" +#include "process.h" #include #include diff --git a/src/libs/utils/clangutils.cpp b/src/libs/utils/clangutils.cpp index 4c8c7d801db..6cf265820e7 100644 --- a/src/libs/utils/clangutils.cpp +++ b/src/libs/utils/clangutils.cpp @@ -4,7 +4,7 @@ #include "clangutils.h" #include "filepath.h" -#include "qtcprocess.h" +#include "process.h" #include "utilstr.h" #include diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 6b07fbdeb45..bda098e0f69 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -13,7 +13,7 @@ #include "utilstr.h" #ifndef UTILS_STATIC_LIBRARY -#include "qtcprocess.h" +#include "process.h" #endif #include diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp index 0641c10c381..627fee3d675 100644 --- a/src/libs/utils/deviceshell.cpp +++ b/src/libs/utils/deviceshell.cpp @@ -3,9 +3,9 @@ #include "deviceshell.h" +#include "process.h" #include "processinterface.h" #include "qtcassert.h" -#include "qtcprocess.h" #include #include diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index e4dea9887da..a42e6320008 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -5,7 +5,7 @@ #include "async.h" #include "barrier.h" -#include "qtcprocess.h" +#include "process.h" #include #include diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 0c43e8f5273..1fe1e962560 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -10,8 +10,8 @@ #include "hostosinfo.h" #include "macroexpander.h" #include "optionpushbutton.h" +#include "process.h" #include "qtcassert.h" -#include "qtcprocess.h" #include "utilstr.h" #include diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/process.cpp similarity index 99% rename from src/libs/utils/qtcprocess.cpp rename to src/libs/utils/process.cpp index 1fe97b3d2fd..1b11bd8645c 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/process.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "qtcprocess.h" +#include "process.h" #include "algorithm.h" #include "environment.h" @@ -2160,4 +2160,4 @@ void ProcessTaskAdapter::start() } // namespace Utils -#include "qtcprocess.moc" +#include "process.moc" diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/process.h similarity index 100% rename from src/libs/utils/qtcprocess.h rename to src/libs/utils/process.h diff --git a/src/libs/utils/processinfo.cpp b/src/libs/utils/processinfo.cpp index dc41a8f63ea..0d71e380fbf 100644 --- a/src/libs/utils/processinfo.cpp +++ b/src/libs/utils/processinfo.cpp @@ -4,7 +4,7 @@ #include "processinfo.h" #include "algorithm.h" -#include "qtcprocess.h" +#include "process.h" #include #include diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index c7cab040289..b6faae765d5 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -4,7 +4,7 @@ #include "terminalhooks.h" #include "filepath.h" -#include "qtcprocess.h" +#include "process.h" #include "terminalcommand.h" #include "terminalinterface.h" diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index ba2bc175f8a..4f628616a10 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -239,6 +239,8 @@ Project { "port.h", "portlist.cpp", "portlist.h", + "process.cpp", + "process.h", "processenums.h", "processhandle.cpp", "processhandle.h", @@ -262,8 +264,6 @@ Project { "qtcassert.h", "qtcolorbutton.cpp", "qtcolorbutton.h", - "qtcprocess.cpp", - "qtcprocess.h", "qtcsettings.cpp", "qtcsettings.h", "reloadpromptutils.cpp", diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index a5f71a95cdc..2e7067ca271 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -11,8 +11,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index c79282e536b..b27730b45b0 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index eccfb2041e8..9c444f6e756 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -34,8 +34,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/android/androidcreatekeystorecertificate.cpp b/src/plugins/android/androidcreatekeystorecertificate.cpp index 09858e36038..67e6c8ff83d 100644 --- a/src/plugins/android/androidcreatekeystorecertificate.cpp +++ b/src/plugins/android/androidcreatekeystorecertificate.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index 138740e4a3a..bb4fc51b984 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 2ba26ebc614..979efcb1af4 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -38,8 +38,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index c1afae589bb..a8ae3f8746b 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 495f031be45..0ccca7c8f7b 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -36,8 +36,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp index e2f929f0813..e29bac3476b 100644 --- a/src/plugins/android/androidpackageinstallationstep.cpp +++ b/src/plugins/android/androidpackageinstallationstep.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index e489a1e1e7f..d296dfe677e 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index ef469da2b62..e62145566a1 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -18,8 +18,8 @@ #include #include +#include #include -#include #include using namespace ProjectExplorer; diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 0e5f6c6f807..65ef8695580 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 61354888fd5..1839f7c21c4 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 62fed62a81d..2ebc61802de 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/android/androidsignaloperation.cpp b/src/plugins/android/androidsignaloperation.cpp index a3fdfeeb835..b6a7699dd4f 100644 --- a/src/plugins/android/androidsignaloperation.cpp +++ b/src/plugins/android/androidsignaloperation.cpp @@ -4,8 +4,8 @@ #include "androidconfigurations.h" #include "androidsignaloperation.h" +#include #include -#include using namespace Utils; diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp index f91dd25b215..96b0dffd61b 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.cpp +++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp @@ -9,8 +9,8 @@ #include "../autotesttr.h" #include "../testtreeitem.h" +#include #include -#include #include #include diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 66a4935622e..12e04240162 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -8,7 +8,7 @@ #include "../autotesttr.h" #include -#include +#include #include diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp index 48bab930662..cef36c90e76 100644 --- a/src/plugins/autotest/testoutputreader.cpp +++ b/src/plugins/autotest/testoutputreader.cpp @@ -6,8 +6,8 @@ #include "autotesttr.h" #include "testtreeitem.h" +#include #include -#include #include diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index c0ca216533e..2d9be97b439 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/autotoolsprojectmanager/makefileparser.cpp b/src/plugins/autotoolsprojectmanager/makefileparser.cpp index 9bbccdb86ad..e1cac6b1866 100644 --- a/src/plugins/autotoolsprojectmanager/makefileparser.cpp +++ b/src/plugins/autotoolsprojectmanager/makefileparser.cpp @@ -5,8 +5,8 @@ #include "autotoolsprojectmanagertr.h" +#include #include -#include #include #include diff --git a/src/plugins/baremetal/baremetaldebugsupport.cpp b/src/plugins/baremetal/baremetaldebugsupport.cpp index c236ab32f24..4475be0b964 100644 --- a/src/plugins/baremetal/baremetaldebugsupport.cpp +++ b/src/plugins/baremetal/baremetaldebugsupport.cpp @@ -24,8 +24,8 @@ #include #include +#include #include -#include using namespace Debugger; using namespace ProjectExplorer; diff --git a/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp index d631923788e..c1ee31b7109 100644 --- a/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/gdb/jlinkgdbserverprovider.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp index 03933cff50e..ca7f25e56f3 100644 --- a/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/gdb/openocdgdbserverprovider.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h index 6f4275769e1..4c14ee7b7c1 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.h @@ -10,7 +10,7 @@ #include // for RunWorker -#include +#include namespace Utils { class PathChooser; } diff --git a/src/plugins/baremetal/iarewtoolchain.cpp b/src/plugins/baremetal/iarewtoolchain.cpp index 392d4e8234f..c6653fefbb4 100644 --- a/src/plugins/baremetal/iarewtoolchain.cpp +++ b/src/plugins/baremetal/iarewtoolchain.cpp @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/baremetal/keiltoolchain.cpp b/src/plugins/baremetal/keiltoolchain.cpp index e9662ff0314..3bb2423ab23 100644 --- a/src/plugins/baremetal/keiltoolchain.cpp +++ b/src/plugins/baremetal/keiltoolchain.cpp @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/baremetal/sdcctoolchain.cpp b/src/plugins/baremetal/sdcctoolchain.cpp index 14b20657de8..a35a468d202 100644 --- a/src/plugins/baremetal/sdcctoolchain.cpp +++ b/src/plugins/baremetal/sdcctoolchain.cpp @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp index 17e36d279cb..fa621fdebcb 100644 --- a/src/plugins/beautifier/abstractsettings.cpp +++ b/src/plugins/beautifier/abstractsettings.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp index b7d54de96f2..42b91a785fe 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp @@ -7,8 +7,8 @@ #include +#include #include -#include #include #include diff --git a/src/plugins/beautifier/beautifierplugin.cpp b/src/plugins/beautifier/beautifierplugin.cpp index 76db40daeab..3057f2034ac 100644 --- a/src/plugins/beautifier/beautifierplugin.cpp +++ b/src/plugins/beautifier/beautifierplugin.cpp @@ -31,8 +31,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp index 243d63e049a..a284d780b6c 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp @@ -6,7 +6,7 @@ #include "../beautifierconstants.h" #include -#include +#include #include #include diff --git a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp index 8a18a3b5ac9..869b2d84fcb 100644 --- a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp +++ b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp @@ -8,7 +8,7 @@ #include "../qdbutils.h" #include -#include +#include #include #include diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index dd767fbc7cc..43783279d69 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -15,8 +15,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 0aa4f74362a..d6e198538f9 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include using namespace Debugger; diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp index b99d264066e..4c18253fe17 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index 6ce706e3c11..8c806cb158f 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -29,9 +29,9 @@ #include -#include #include -#include +#include +#include #include diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index a9fd0fb2200..3707ef20bc1 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -13,7 +13,7 @@ #include -#include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index 39a27523a0a..2f455886253 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 7c71acceb92..9d27e9f49b5 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -11,8 +11,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index 6b5e373daa5..7a812d3750d 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include diff --git a/src/plugins/clangtools/executableinfo.cpp b/src/plugins/clangtools/executableinfo.cpp index 0b5d649cf50..22898b5734a 100644 --- a/src/plugins/clangtools/executableinfo.cpp +++ b/src/plugins/clangtools/executableinfo.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index f32e502c1bf..1b3b4d2ae90 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -35,8 +35,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp index 82e1b7571de..053c387ee92 100644 --- a/src/plugins/clearcase/clearcasesync.cpp +++ b/src/plugins/clearcase/clearcasesync.cpp @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 146c2f853c4..20c85133216 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -46,8 +46,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp b/src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp index 4bb2218340d..258954fa115 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace CMakeProjectManager { namespace Internal { diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 6b8270db6c8..5922f920452 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -14,8 +14,8 @@ #include #include +#include #include -#include #include using namespace Core; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 52da1adc8ae..69cdda4c526 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -20,8 +20,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index eae44c15638..9239ea54177 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index d6438e5d226..c6f8f1225c8 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -14,8 +14,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp index 0d4404c7144..59237aad79a 100644 --- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp +++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp index 14e4d511203..6cafa6ff887 100644 --- a/src/plugins/coreplugin/externaltool.cpp +++ b/src/plugins/coreplugin/externaltool.cpp @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 32975986203..0fe0ccd8875 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 43b4d9a3784..630bef03df7 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index 759b56fb267..587eadc6154 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/coreplugin/patchtool.cpp b/src/plugins/coreplugin/patchtool.cpp index 06b20610f17..af6c11825d4 100644 --- a/src/plugins/coreplugin/patchtool.cpp +++ b/src/plugins/coreplugin/patchtool.cpp @@ -7,7 +7,7 @@ #include "patchtool.h" #include -#include +#include #include diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index 503ab2d3790..c5694016d49 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/coreplugin/progressmanager/processprogress.cpp b/src/plugins/coreplugin/progressmanager/processprogress.cpp index 2895b402a5c..fce87e0d2b2 100644 --- a/src/plugins/coreplugin/progressmanager/processprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/processprogress.cpp @@ -6,8 +6,8 @@ #include "progressmanager.h" #include "../coreplugintr.h" +#include #include -#include #include diff --git a/src/plugins/cppcheck/cppcheckrunner.h b/src/plugins/cppcheck/cppcheckrunner.h index 0ec49aceb54..686a6c9eb97 100644 --- a/src/plugins/cppcheck/cppcheckrunner.h +++ b/src/plugins/cppcheck/cppcheckrunner.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include #include #include diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 679b3684944..5919a97b84c 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -15,8 +15,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 21c75b7cbc1..36c3832641d 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -63,8 +63,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index ade37ae8ec1..e3a2ba8ede8 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -45,9 +45,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 0fba6708e9d..84a0dded1a7 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -10,7 +10,7 @@ #include -#include +#include #include diff --git a/src/plugins/debugger/dap/dapengine.cpp b/src/plugins/debugger/dap/dapengine.cpp index ed0933008e2..9db7c0f7e5e 100644 --- a/src/plugins/debugger/dap/dapengine.cpp +++ b/src/plugins/debugger/dap/dapengine.cpp @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/debugger/dap/dapengine.h b/src/plugins/debugger/dap/dapengine.h index 9b554d668ba..2fa3019cad9 100644 --- a/src/plugins/debugger/dap/dapengine.h +++ b/src/plugins/debugger/dap/dapengine.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include #include diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index d387ce142c1..a59e48ecf99 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -54,10 +54,10 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index 76630f2e7dc..241ac32ecdd 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index f418ace88e6..42f9af0800c 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -22,8 +22,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 5e5da91df6a..663ad5bf6d4 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -35,8 +35,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index db5d8698ded..9d3af533bcc 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 6068294e40e..5ea6162a644 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -38,9 +38,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 6a6e68991b5..64a2eddd4eb 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 91ef914c553..3f182c828b9 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -29,9 +29,9 @@ #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 2f5fe0d7688..db11af9c104 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index a904e1d7897..4f063b57288 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -11,8 +11,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 54a347fb151..accf32d0e6e 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index 49dceb24417..1e365b36a7f 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include #include diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 096ddc13264..033069c1165 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -40,8 +40,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index 4b96d1a0a91..cc309541a81 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -11,8 +11,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/docker/dockerapi.cpp b/src/plugins/docker/dockerapi.cpp index 3ffa59b52b4..ffc14148597 100644 --- a/src/plugins/docker/dockerapi.cpp +++ b/src/plugins/docker/dockerapi.cpp @@ -7,8 +7,8 @@ #include #include +#include #include -#include #include diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 64d3dcd6da9..d1175a8b5f9 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -44,9 +44,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index b13ff9dfcef..347e3a2b7b3 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -50,8 +50,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index 16038150cb9..358a66caafb 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -16,9 +16,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index 5553e0a7404..906eeb5809a 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -38,8 +38,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 275b00efbbe..aeeea39fff2 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -11,8 +11,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp index 2f93a2c7a16..8e4a6bdc997 100644 --- a/src/plugins/git/changeselectiondialog.cpp +++ b/src/plugins/git/changeselectiondialog.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index 4791a41d4f5..6457117b322 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 0f5a393b1de..8ffc7a6d447 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index ab5c8cc58a8..a196d703ed3 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -27,8 +27,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 0c4e4126255..a52276f381b 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 2f70cddc822..edd042c9b9c 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/git/mergetool.h b/src/plugins/git/mergetool.h index 1fd32e3a4fe..727f9a85df0 100644 --- a/src/plugins/git/mergetool.h +++ b/src/plugins/git/mergetool.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include #include diff --git a/src/plugins/gitlab/gitlabclonedialog.cpp b/src/plugins/gitlab/gitlabclonedialog.cpp index 4d54105e447..3a061b9cc57 100644 --- a/src/plugins/gitlab/gitlabclonedialog.cpp +++ b/src/plugins/gitlab/gitlabclonedialog.cpp @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/gitlab/queryrunner.h b/src/plugins/gitlab/queryrunner.h index bdb5e06034a..08afc56e1b6 100644 --- a/src/plugins/gitlab/queryrunner.h +++ b/src/plugins/gitlab/queryrunner.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include #include diff --git a/src/plugins/haskell/haskellmanager.cpp b/src/plugins/haskell/haskellmanager.cpp index 250b795af79..fbd4ee8aa03 100644 --- a/src/plugins/haskell/haskellmanager.cpp +++ b/src/plugins/haskell/haskellmanager.cpp @@ -10,8 +10,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/incredibuild/cmakecommandbuilder.cpp b/src/plugins/incredibuild/cmakecommandbuilder.cpp index 8732601cbc4..2f0dd751ae9 100644 --- a/src/plugins/incredibuild/cmakecommandbuilder.cpp +++ b/src/plugins/incredibuild/cmakecommandbuilder.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include // Compile-time only diff --git a/src/plugins/ios/iosbuildstep.cpp b/src/plugins/ios/iosbuildstep.cpp index e4771d97e84..7831d84e239 100644 --- a/src/plugins/ios/iosbuildstep.cpp +++ b/src/plugins/ios/iosbuildstep.cpp @@ -20,8 +20,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 0eab6b7947a..04e4363a2a1 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -31,8 +31,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/ios/iosdsymbuildstep.cpp b/src/plugins/ios/iosdsymbuildstep.cpp index 33ff0e7e202..2d0e2b841f0 100644 --- a/src/plugins/ios/iosdsymbuildstep.cpp +++ b/src/plugins/ios/iosdsymbuildstep.cpp @@ -9,21 +9,22 @@ #include "iostr.h" #include -#include -#include + +#include #include #include #include +#include #include -#include #include +#include #include #include -#include +#include #include -#include +#include #include #include diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp index 7b3e977e963..e6fca977b25 100644 --- a/src/plugins/ios/iosprobe.cpp +++ b/src/plugins/ios/iosprobe.cpp @@ -4,7 +4,7 @@ #include "iosprobe.h" #include -#include +#include #include #include diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index 5c9170f2bae..8a0a3e62dcf 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -21,9 +21,9 @@ #include #include -#include -#include #include +#include +#include #include #include diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index c01c3c859dc..828bb65c007 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/ios/iossimulator.cpp b/src/plugins/ios/iossimulator.cpp index 2caa691c927..fa68c4031e3 100644 --- a/src/plugins/ios/iossimulator.cpp +++ b/src/plugins/ios/iossimulator.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index fa5d0c3ac44..0e4545bf1da 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index 9d50088cd96..0832a5faf37 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -6,8 +6,8 @@ #include #include +#include #include -#include #ifdef Q_OS_MAC #include diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 08d7429acd6..77b2cbfdee5 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -53,7 +53,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index ec1fc8206f9..7577f136913 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/mcusupport/mcuqmlprojectnode.h b/src/plugins/mcusupport/mcuqmlprojectnode.h index 2a06e5cde55..bf40a696f6b 100644 --- a/src/plugins/mcusupport/mcuqmlprojectnode.h +++ b/src/plugins/mcusupport/mcuqmlprojectnode.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/mcusupport/mcusupportversiondetection.cpp b/src/plugins/mcusupport/mcusupportversiondetection.cpp index 2ea28c38525..f92a443c4fc 100644 --- a/src/plugins/mcusupport/mcusupportversiondetection.cpp +++ b/src/plugins/mcusupport/mcusupportversiondetection.cpp @@ -3,7 +3,7 @@ #include "mcusupportversiondetection.h" -#include +#include #include #include diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 62439896500..1d8d542ed91 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp index bd90ee818c6..514c529212a 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildconfiguration.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include diff --git a/src/plugins/mesonprojectmanager/mesonprocess.cpp b/src/plugins/mesonprojectmanager/mesonprocess.cpp index 5732f617e76..2e4ba024559 100644 --- a/src/plugins/mesonprojectmanager/mesonprocess.cpp +++ b/src/plugins/mesonprojectmanager/mesonprocess.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/mesonprojectmanager/mesonwrapper.h b/src/plugins/mesonprojectmanager/mesonwrapper.h index 668c78bc4cd..6ec1e57a0f1 100644 --- a/src/plugins/mesonprojectmanager/mesonwrapper.h +++ b/src/plugins/mesonprojectmanager/mesonwrapper.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/mesonprojectmanager/toolwrapper.cpp b/src/plugins/mesonprojectmanager/toolwrapper.cpp index e3e54ef1b2d..83ed27f495d 100644 --- a/src/plugins/mesonprojectmanager/toolwrapper.cpp +++ b/src/plugins/mesonprojectmanager/toolwrapper.cpp @@ -3,7 +3,7 @@ #include "toolwrapper.h" -#include +#include namespace MesonProjectManager { namespace Internal { diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp index f9be804571d..3a8ccb08d62 100644 --- a/src/plugins/nim/project/nimblebuildsystem.cpp +++ b/src/plugins/nim/project/nimblebuildsystem.cpp @@ -10,8 +10,8 @@ #include #include +#include #include -#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp index 87f93e53e2a..588098619a2 100644 --- a/src/plugins/nim/project/nimcompilerbuildstep.cpp +++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp @@ -16,8 +16,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp index 159985f59d4..21b441fa6ce 100644 --- a/src/plugins/nim/project/nimtoolchain.cpp +++ b/src/plugins/nim/project/nimtoolchain.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include diff --git a/src/plugins/nim/suggest/server.h b/src/plugins/nim/suggest/server.h index a9f7d49b889..9eb2bac141d 100644 --- a/src/plugins/nim/suggest/server.h +++ b/src/plugins/nim/suggest/server.h @@ -7,7 +7,7 @@ #include #include -#include +#include namespace Nim { namespace Suggest { diff --git a/src/plugins/perforce/perforcechecker.h b/src/plugins/perforce/perforcechecker.h index 5f7d2b16739..d0f608de705 100644 --- a/src/plugins/perforce/perforcechecker.h +++ b/src/plugins/perforce/perforcechecker.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include namespace Perforce::Internal { diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 336ee8e7dc4..c6f4082767e 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -27,8 +27,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/perfprofiler/perfconfigwidget.cpp b/src/plugins/perfprofiler/perfconfigwidget.cpp index eed31e373a2..e5e3fd37256 100644 --- a/src/plugins/perfprofiler/perfconfigwidget.cpp +++ b/src/plugins/perfprofiler/perfconfigwidget.cpp @@ -14,8 +14,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index 68ba9e883f3..8579a9cf7cb 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index 9bea76b3e29..e5f307b85ae 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -10,7 +10,7 @@ #include -#include +#include using namespace Utils; diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index 004f9aa0e15..3920b526b89 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -11,9 +11,9 @@ #include #include -#include -#include #include +#include +#include #include #include diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index eca8b5c44f4..ddc2a8551a2 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -12,8 +12,8 @@ #include #include +#include #include -#include #include diff --git a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp index 34ab30442d3..7d1174839dd 100644 --- a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 82734cf6a9f..26d296b181b 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 8973a7baf60..aa017df46b0 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp index b04397a66b9..fbe300bf269 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp index 8b67f300dbb..744e350eaef 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index e60d6cb5d16..8830aadf856 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 40a97737db3..4012fbd6690 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 9a3a939f34f..b3b9c934868 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 87547b2a79a..d4d518de44d 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -19,8 +19,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/processparameters.cpp b/src/plugins/projectexplorer/processparameters.cpp index 49b50dccb3a..0b3d6d83c7a 100644 --- a/src/plugins/projectexplorer/processparameters.cpp +++ b/src/plugins/projectexplorer/processparameters.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index d318de8cc34..bc5a0ef4d65 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index d90fbc7272a..88dd720ee31 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -19,8 +19,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 3f0accdc314..3843e4c0e59 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -25,9 +25,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 3b11c8f1471..fd1e8a78c64 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -11,18 +11,17 @@ #include "project.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" -#include "session.h" #include "target.h" #include "targetsetupwidget.h" #include "task.h" #include -#include -#include -#include #include #include +#include +#include +#include #include #include diff --git a/src/plugins/projectexplorer/taskfile.cpp b/src/plugins/projectexplorer/taskfile.cpp index 6375d12ee7e..f137b0f812c 100644 --- a/src/plugins/projectexplorer/taskfile.cpp +++ b/src/plugins/projectexplorer/taskfile.cpp @@ -14,8 +14,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/toolchainconfigwidget.cpp b/src/plugins/projectexplorer/toolchainconfigwidget.cpp index ef97ad72cfd..84b80b4e047 100644 --- a/src/plugins/projectexplorer/toolchainconfigwidget.cpp +++ b/src/plugins/projectexplorer/toolchainconfigwidget.cpp @@ -7,8 +7,8 @@ #include "projectexplorertr.h" #include +#include #include -#include #include #include diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index 646e336643e..ae900ea818d 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index db456479459..8e3f55dd11b 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include using namespace Utils; diff --git a/src/plugins/python/pipsupport.h b/src/plugins/python/pipsupport.h index fefd3295755..4d08a3b1ea6 100644 --- a/src/plugins/python/pipsupport.h +++ b/src/plugins/python/pipsupport.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include #include #include diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index eb604f01e64..4b9df185a37 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -5,7 +5,6 @@ #include "pipsupport.h" #include "pythonplugin.h" -#include "pythonsettings.h" #include "pythontr.h" #include "pythonutils.h" @@ -19,8 +18,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/python/pysideuicextracompiler.cpp b/src/plugins/python/pysideuicextracompiler.cpp index c195aeaa1f7..45fb68066f9 100644 --- a/src/plugins/python/pysideuicextracompiler.cpp +++ b/src/plugins/python/pysideuicextracompiler.cpp @@ -3,7 +3,7 @@ #include "pysideuicextracompiler.h" -#include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index 6d3d7c8cfa7..9f347d8e486 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 119bd9d2600..e5251384d2c 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 328ada95d95..0fb4d03f194 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index c5d4b62a0d0..41ae75d8b9b 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -27,8 +27,8 @@ #include +#include #include -#include #include #include diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index 102cb7e3ae7..794e134d5a8 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -28,8 +28,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp index 953768661d0..2d952513ab8 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 7248143313e..ef0ef8e52ed 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp index 6317580f685..91e4763bf25 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.cpp +++ b/src/plugins/qbsprojectmanager/qbssettings.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp index 8c094c557a8..800d7350c19 100644 --- a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp +++ b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp @@ -13,8 +13,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp index 5fbab2084dd..990fd0ff417 100644 --- a/src/plugins/qmakeprojectmanager/makefileparse.cpp +++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp @@ -5,7 +5,7 @@ #include -#include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index 779d175b80f..ce64ecd2d91 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -37,8 +37,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp index 0fdaecc3db5..ae35a9dc767 100644 --- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 4786d2f07a9..31a55faab01 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -33,8 +33,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index a78c001283f..2b73c154f6d 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp index 8bcbe2027cf..1a929bf9a49 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp @@ -23,8 +23,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index d8e99a39a54..edcc0e40bb3 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index f6ea4a8455f..10386425fe7 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -55,8 +55,8 @@ #include #include +#include #include -#include "utils/qtcprocess.h" #include #include diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 67674ed5e92..8ebfaf52044 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -75,8 +75,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/qmldesigner/generateresource.cpp b/src/plugins/qmldesigner/generateresource.cpp index 673ba41de4f..439e124b705 100644 --- a/src/plugins/qmldesigner/generateresource.cpp +++ b/src/plugins/qmldesigner/generateresource.cpp @@ -22,9 +22,9 @@ #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp index 6b886389e6f..ca43b07a42f 100644 --- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp +++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include using namespace ProjectExplorer; diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index f5c45789d8f..41b67edda78 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -20,8 +20,8 @@ #include +#include #include -#include #include #include diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index aab0fcfe1c9..77e3cc82d40 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -38,8 +38,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index 2c1a294e7a3..2ead9de6da9 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index 584bf8773b7..1cce1650ce0 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index 29ea42b7cdb..4d5a73b2ab5 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -9,8 +9,7 @@ #include -#include -#include +#include #include diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index d6ee8618980..919e9ef1fcc 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -33,9 +33,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 6450223e431..aef2b0d0cd1 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -16,9 +16,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 49056d9ec40..306b87e861d 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -18,8 +18,8 @@ #include #include +#include #include -#include #include using namespace ProjectExplorer; diff --git a/src/plugins/qnx/qnxdevicetester.cpp b/src/plugins/qnx/qnxdevicetester.cpp index a96f5b6d7e7..cbead1aa3d6 100644 --- a/src/plugins/qnx/qnxdevicetester.cpp +++ b/src/plugins/qnx/qnxdevicetester.cpp @@ -6,8 +6,7 @@ #include "qnxconstants.h" #include "qnxtr.h" -#include -#include +#include using namespace Utils; diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index 3cc73e6d54d..ba2c41b3453 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 21de26e5a24..a6ceaab4ccb 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index c08f296a8c2..179649c53b8 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -33,8 +33,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/qtsupport/externaleditors.cpp b/src/plugins/qtsupport/externaleditors.cpp index 9732693e6eb..dffd730d285 100644 --- a/src/plugins/qtsupport/externaleditors.cpp +++ b/src/plugins/qtsupport/externaleditors.cpp @@ -19,8 +19,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 37d141e11c6..3fc9fe8fed8 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include using namespace Core; using namespace Utils; diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index bde9d2e3374..eedc79e6864 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/qtsupport/uicgenerator.cpp b/src/plugins/qtsupport/uicgenerator.cpp index f48a8d310ee..f1ff905b831 100644 --- a/src/plugins/qtsupport/uicgenerator.cpp +++ b/src/plugins/qtsupport/uicgenerator.cpp @@ -2,20 +2,21 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "uicgenerator.h" + #include "baseqtversion.h" #include "qtkitinformation.h" +#include #include #include -#include +#include #include -#include -#include -#include -#include #include +#include +#include +#include using namespace ProjectExplorer; diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index 7249d2c6b2b..670390eeb19 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index 24267b16bd9..00fdd82f367 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 4889dbb35d1..e4e3ed3801f 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -15,9 +15,9 @@ #include #include +#include #include #include -#include #include diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 6aca035bb6c..31980f6761e 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -29,9 +29,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index c28b2ecfc50..39df7d9403f 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -10,9 +10,9 @@ #include #include +#include #include #include -#include #include using namespace ProjectExplorer; diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index e5641abec01..d1be1051452 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -20,8 +20,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp index c5564d3c741..c7b4a548103 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp +++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/remotelinux/remotelinuxsignaloperation.cpp b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp index 4ee28e77015..816e0e38696 100644 --- a/src/plugins/remotelinux/remotelinuxsignaloperation.cpp +++ b/src/plugins/remotelinux/remotelinuxsignaloperation.cpp @@ -7,8 +7,8 @@ #include #include +#include #include -#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 7a161601b75..b0779c01e2c 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -16,8 +16,8 @@ #include #include +#include #include -#include #include using namespace ProjectExplorer; diff --git a/src/plugins/remotelinux/sshkeycreationdialog.cpp b/src/plugins/remotelinux/sshkeycreationdialog.cpp index 16dcf9220d7..441edab8898 100644 --- a/src/plugins/remotelinux/sshkeycreationdialog.cpp +++ b/src/plugins/remotelinux/sshkeycreationdialog.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index 4f517ea91de..a79209354aa 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -12,8 +12,8 @@ #include #include +#include #include -#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index e2a85ab53c5..9ac9702a6e4 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -9,8 +9,8 @@ #include #include #include +#include #include -#include #include "silversearcheroutputparser.h" #include "silversearchertr.h" diff --git a/src/plugins/squish/objectsmapdocument.cpp b/src/plugins/squish/objectsmapdocument.cpp index 0555bb3512c..3742ee3466d 100644 --- a/src/plugins/squish/objectsmapdocument.cpp +++ b/src/plugins/squish/objectsmapdocument.cpp @@ -10,7 +10,7 @@ #include "squishtr.h" #include -#include +#include #include diff --git a/src/plugins/squish/squishprocessbase.h b/src/plugins/squish/squishprocessbase.h index d8af2e9d4f2..6582c95062b 100644 --- a/src/plugins/squish/squishprocessbase.h +++ b/src/plugins/squish/squishprocessbase.h @@ -5,7 +5,7 @@ #include "squishconstants.h" -#include +#include #include diff --git a/src/plugins/squish/squishtools.h b/src/plugins/squish/squishtools.h index 19b57a7cb42..8d3cf61cfc5 100644 --- a/src/plugins/squish/squishtools.h +++ b/src/plugins/squish/squishtools.h @@ -9,7 +9,7 @@ #include "suiteconf.h" #include -#include +#include #include #include diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index c9b28724eaa..45cd652381c 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -12,8 +12,7 @@ #include #include #include -#include -#include +#include #include #include diff --git a/src/plugins/terminal/shellintegration.h b/src/plugins/terminal/shellintegration.h index 8fce983b019..a4a813c8a65 100644 --- a/src/plugins/terminal/shellintegration.h +++ b/src/plugins/terminal/shellintegration.h @@ -5,7 +5,7 @@ #pragma once #include -#include +#include #include diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index f6ea7d763b9..4f56f39efe4 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp index 5f02b7e9d02..3e31006d617 100644 --- a/src/plugins/texteditor/formattexteditor.cpp +++ b/src/plugins/texteditor/formattexteditor.cpp @@ -12,8 +12,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index 8ee3247010d..d6ec407f63b 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 2c2f73b10e5..99d948c2482 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -13,8 +13,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index 13d04b63353..4ec6a16d7fa 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -8,7 +8,7 @@ #include "callgrind/callgrindparsedata.h" #include "callgrind/callgrindparser.h" -#include +#include namespace Valgrind { namespace Internal { diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 9b35de452d4..ab5b0e55602 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -52,8 +52,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index b07288b175d..e0702ef9720 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -50,8 +50,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index 3750217ad7c..ef78c7f9ffc 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index b781b1772ae..d5ec691ec04 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -21,8 +21,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index aaea619a2b1..715b0855599 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include using namespace DiffEditor; using namespace Utils; diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index dfd89842c52..517ffbdf48f 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -17,8 +17,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 0d9f92a702e..d9717ece09e 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -28,8 +28,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/src/plugins/vcsbase/vcscommand.cpp b/src/plugins/vcsbase/vcscommand.cpp index a16545b70ba..885ff004dab 100644 --- a/src/plugins/vcsbase/vcscommand.cpp +++ b/src/plugins/vcsbase/vcscommand.cpp @@ -10,8 +10,8 @@ #include #include +#include #include -#include #include #include diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index 245de851346..2b5536809f8 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/webassembly/webassemblyemsdk.cpp b/src/plugins/webassembly/webassemblyemsdk.cpp index e66df1272da..42f8738a8e7 100644 --- a/src/plugins/webassembly/webassemblyemsdk.cpp +++ b/src/plugins/webassembly/webassemblyemsdk.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp index 70484168ebe..05b7e89e821 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include diff --git a/tests/auto/utils/commandline/tst_commandline.cpp b/tests/auto/utils/commandline/tst_commandline.cpp index c20eb48db91..2691b1e84ad 100644 --- a/tests/auto/utils/commandline/tst_commandline.cpp +++ b/tests/auto/utils/commandline/tst_commandline.cpp @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/tests/auto/utils/deviceshell/tst_deviceshell.cpp b/tests/auto/utils/deviceshell/tst_deviceshell.cpp index f94d0dc5b40..6e081495c36 100644 --- a/tests/auto/utils/deviceshell/tst_deviceshell.cpp +++ b/tests/auto/utils/deviceshell/tst_deviceshell.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/tests/auto/utils/qtcprocess/processtestapp/main.cpp b/tests/auto/utils/qtcprocess/processtestapp/main.cpp index 6851a3597cf..91952c2528e 100644 --- a/tests/auto/utils/qtcprocess/processtestapp/main.cpp +++ b/tests/auto/utils/qtcprocess/processtestapp/main.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp index 1fa73a94759..3905d0a22b5 100644 --- a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp +++ b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp @@ -3,7 +3,7 @@ #include "processtestapp.h" -#include +#include #include #include diff --git a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp index 1bc1778237d..657b3356068 100644 --- a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp @@ -8,10 +8,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/tests/manual/deviceshell/tst_deviceshell.cpp b/tests/manual/deviceshell/tst_deviceshell.cpp index 96638763f8e..99c506d1bda 100644 --- a/tests/manual/deviceshell/tst_deviceshell.cpp +++ b/tests/manual/deviceshell/tst_deviceshell.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include From 2dbdbaf202b0f0b7f3d7eea2cac48aea44e8e552 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 17:54:47 +0200 Subject: [PATCH 0811/1447] Adapt to upstream changes Change-Id: I99ded030d0382ea9c465e1e951d1457d87570389 Reviewed-by: hjk --- plugins/axivion/axivionquery.cpp | 2 +- plugins/axivion/axivionquery.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index fbf0ec61936..8fcb131c87f 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -66,7 +66,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren args << url; m_process.setCommand({settings->curl, args}); - connect(&m_process, &QtcProcess::done, this, [this]{ + connect(&m_process, &Process::done, this, [this]{ if (m_process.result() != ProcessResult::FinishedWithSuccess) { const int exitCode = m_process.exitCode(); if (m_process.exitStatus() == QProcess::NormalExit diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 63b64a52f9b..d9873a6db44 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include @@ -34,7 +34,7 @@ signals: void resultRetrieved(const QByteArray &json); private: - Utils::QtcProcess m_process; + Utils::Process m_process; }; } // Axivion::Internal From 867b10a06b74545f83f42ab805cf1ca24abd8b67 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 23:49:37 +0200 Subject: [PATCH 0812/1447] Remove unused includes of QFutureInterface Change-Id: I70f5e842801b628c7f9ad4d433334ce04d4e648e Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/cplusplus/CppDocument.cpp | 1 - src/plugins/autotest/testrunner.cpp | 2 -- src/plugins/clearcase/clearcaseplugin.cpp | 1 - src/plugins/clearcase/clearcasesync.cpp | 1 - src/plugins/clearcase/clearcasesync.h | 2 -- src/plugins/cppeditor/cppprojectupdater.cpp | 2 -- src/plugins/diffeditor/sidebysidediffeditorwidget.h | 1 - src/plugins/diffeditor/unifieddiffeditorwidget.h | 4 ---- src/plugins/help/helpmanager.h | 1 - src/plugins/projectexplorer/selectablefilesmodel.h | 1 - tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp | 1 - tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp | 1 - 12 files changed, 18 deletions(-) diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 42616498977..d28fdd50baa 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -26,7 +26,6 @@ #include #include -#include #include /*! diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 2d9be97b439..7f54d41ba8f 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -39,8 +39,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 1b3b4d2ae90..aa5c598c84c 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp index 053c387ee92..8476d1f04ac 100644 --- a/src/plugins/clearcase/clearcasesync.cpp +++ b/src/plugins/clearcase/clearcasesync.cpp @@ -6,7 +6,6 @@ #include "clearcasesettings.h" #include -#include #include #include diff --git a/src/plugins/clearcase/clearcasesync.h b/src/plugins/clearcase/clearcasesync.h index c2862d9d404..4b69985b0c7 100644 --- a/src/plugins/clearcase/clearcasesync.h +++ b/src/plugins/clearcase/clearcasesync.h @@ -8,8 +8,6 @@ QT_BEGIN_NAMESPACE class QDir; template -class QFutureInterface; -template class QPromise; QT_END_NAMESPACE diff --git a/src/plugins/cppeditor/cppprojectupdater.cpp b/src/plugins/cppeditor/cppprojectupdater.cpp index 3f0c24bc288..e848c6eba5a 100644 --- a/src/plugins/cppeditor/cppprojectupdater.cpp +++ b/src/plugins/cppeditor/cppprojectupdater.cpp @@ -16,8 +16,6 @@ #include #include -#include - using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index f164d865798..b56fea7da02 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -22,7 +22,6 @@ class Async; } QT_BEGIN_NAMESPACE -class QFutureInterfaceBase; class QMenu; class QSplitter; QT_END_NAMESPACE diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h index ae7060b1446..e303a757172 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.h +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h @@ -15,10 +15,6 @@ template class Async; } -QT_BEGIN_NAMESPACE -class QFutureInterfaceBase; -QT_END_NAMESPACE - namespace DiffEditor { class ChunkData; diff --git a/src/plugins/help/helpmanager.h b/src/plugins/help/helpmanager.h index 6ab3e72cd97..739d5a68767 100644 --- a/src/plugins/help/helpmanager.h +++ b/src/plugins/help/helpmanager.h @@ -5,7 +5,6 @@ #include -#include #include #include diff --git a/src/plugins/projectexplorer/selectablefilesmodel.h b/src/plugins/projectexplorer/selectablefilesmodel.h index 6f9d7b67bed..8c47fbd990b 100644 --- a/src/plugins/projectexplorer/selectablefilesmodel.h +++ b/src/plugins/projectexplorer/selectablefilesmodel.h @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp b/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp index 48f8d7ce6cf..e550383724f 100644 --- a/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp +++ b/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp b/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp index 4f86e3ba988..003630ab0bf 100644 --- a/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp +++ b/tests/auto/qml/codemodel/ecmascript7/tst_ecmascript7.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include From de247bff2b15a9eb1eaece9077abecd4369176ba Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 11:00:19 +0200 Subject: [PATCH 0813/1447] LanguageServer: Use IOptionPage::setWidgetCreator() for settings Change-Id: I6d05e739bc1348f09f3df7ab3ae8a701ce137b3c Reviewed-by: David Schulz --- .../languageclient/languageclientsettings.cpp | 117 ++++++++---------- 1 file changed, 50 insertions(+), 67 deletions(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 5b15c7c218d..b6545dae022 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -104,17 +104,39 @@ private: QList m_removed; }; -class LanguageClientSettingsPageWidget : public QWidget +class LanguageClientSettingsPageWidget : public Core::IOptionsPageWidget { public: - LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings); + LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings, + QSet &changedSettings); + void currentChanged(const QModelIndex &index); int currentRow() const; void resetCurrentSettings(int row); void applyCurrentSettings(); + void apply() final + { + applyCurrentSettings(); + LanguageClientManager::applySettings(); + + for (BaseSettings *setting : m_model.removed()) { + for (Client *client : LanguageClientManager::clientsForSetting(setting)) + LanguageClientManager::shutdownClient(client); + } + + int row = currentRow(); + m_model.reset(LanguageClientManager::currentSettings()); + resetCurrentSettings(row); + } + + void finish() + { + m_settings.reset(LanguageClientManager::currentSettings()); + m_changedSettings.clear(); + } + private: - LanguageClientSettingsModel &m_settings; QTreeView *m_view = nullptr; struct CurrentSettings { BaseSettings *setting = nullptr; @@ -123,30 +145,10 @@ private: void addItem(const Utils::Id &clientTypeId); void deleteItem(); -}; -class LanguageClientSettingsPage : public Core::IOptionsPage -{ -public: - LanguageClientSettingsPage(); - ~LanguageClientSettingsPage() override; - - void init(); - - // IOptionsPage interface - QWidget *widget() override; - void apply() override; - void finish() override; - - QList settings() const; - QList changedSettings() const; - void addSettings(BaseSettings *settings); - void enableSettings(const QString &id, bool enable = true); - -private: + LanguageClientSettingsModel &m_settings; + QSet &m_changedSettings; LanguageClientSettingsModel m_model; - QSet m_changedSettings; - QPointer m_widget; }; QMap &clientTypes() @@ -155,9 +157,11 @@ QMap &clientTypes() return types; } -LanguageClientSettingsPageWidget::LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings) - : m_settings(settings) - , m_view(new QTreeView()) +LanguageClientSettingsPageWidget::LanguageClientSettingsPageWidget(LanguageClientSettingsModel &settings, + QSet &changedSettings) + : m_view(new QTreeView()) + , m_settings(settings) + , m_changedSettings(changedSettings) { auto mainLayout = new QVBoxLayout(); auto layout = new QHBoxLayout(); @@ -264,6 +268,23 @@ void LanguageClientSettingsPageWidget::deleteItem() m_settings.removeRows(index.row()); } +class LanguageClientSettingsPage : public Core::IOptionsPage +{ +public: + LanguageClientSettingsPage(); + + void init(); + + QList settings() const; + QList changedSettings() const; + void addSettings(BaseSettings *settings); + void enableSettings(const QString &id, bool enable = true); + +private: + LanguageClientSettingsModel m_model; + QSet m_changedSettings; +}; + LanguageClientSettingsPage::LanguageClientSettingsPage() { setId(Constants::LANGUAGECLIENT_SETTINGS_PAGE); @@ -271,18 +292,13 @@ LanguageClientSettingsPage::LanguageClientSettingsPage() setCategory(Constants::LANGUAGECLIENT_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr(Constants::LANGUAGECLIENT_SETTINGS_TR)); setCategoryIconPath(":/languageclient/images/settingscategory_languageclient.png"); + setWidgetCreator([this] { return new LanguageClientSettingsPageWidget(m_model, m_changedSettings); }); connect(&m_model, &LanguageClientSettingsModel::dataChanged, [this](const QModelIndex &index) { if (BaseSettings *setting = m_model.settingForIndex(index)) m_changedSettings << setting->m_id; }); } -LanguageClientSettingsPage::~LanguageClientSettingsPage() -{ - if (m_widget) - delete m_widget; -} - void LanguageClientSettingsPage::init() { m_model.reset(LanguageClientSettings::fromSettings(Core::ICore::settings())); @@ -290,39 +306,6 @@ void LanguageClientSettingsPage::init() finish(); } -QWidget *LanguageClientSettingsPage::widget() -{ - if (!m_widget) - m_widget = new LanguageClientSettingsPageWidget(m_model); - return m_widget; -} - -void LanguageClientSettingsPage::apply() -{ - if (m_widget) - m_widget->applyCurrentSettings(); - LanguageClientManager::applySettings(); - - for (BaseSettings *setting : m_model.removed()) { - for (Client *client : LanguageClientManager::clientsForSetting(setting)) - LanguageClientManager::shutdownClient(client); - } - - if (m_widget) { - int row = m_widget->currentRow(); - m_model.reset(LanguageClientManager::currentSettings()); - m_widget->resetCurrentSettings(row); - } else { - m_model.reset(LanguageClientManager::currentSettings()); - } -} - -void LanguageClientSettingsPage::finish() -{ - m_model.reset(LanguageClientManager::currentSettings()); - m_changedSettings.clear(); -} - QList LanguageClientSettingsPage::settings() const { return m_model.settings(); From a059f87754c68aec9095b092f23a8cab325a5dfc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 2 May 2023 19:47:49 +0200 Subject: [PATCH 0814/1447] QtSingleApplication: Introduce QTC_FREEZE_DETECTOR env var This may help with tracking the freezes in main thread. By default, when QTC_FREEZE_DETECTOR is set, it detects freezes above the 100 ms and prints the receiver object and event type that triggered the freeze. Change the default 100 ms threshold by setting the QTC_FREEZE_DETECTOR to some different numeric value. Change-Id: Ifb68c7648c09a5329f1f2aa39cd7e29e69a76052 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/app/main.cpp | 32 ++++----- .../qtsingleapplication.cpp | 68 ++++++++++++++++++- .../qtsingleapplication/qtsingleapplication.h | 3 + 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index b0ca009b8c9..d6d0c8cc121 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -22,29 +22,20 @@ #include #include -#include #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include #include +#include #include #include +#include #include -#include +#include #include +#include +#include +#include #include #include @@ -589,11 +580,12 @@ int main(int argc, char **argv) SharedTools::QtSingleApplication::setAttribute(Qt::AA_ShareOpenGLContexts); - int numberofArguments = static_cast(options.appArguments.size()); + int numberOfArguments = static_cast(options.appArguments.size()); - SharedTools::QtSingleApplication app((QLatin1String(Core::Constants::IDE_DISPLAY_NAME)), - numberofArguments, - options.appArguments.data()); + std::unique_ptr + appPtr(SharedTools::createApplication(QLatin1String(Core::Constants::IDE_DISPLAY_NAME), + numberOfArguments, options.appArguments.data())); + SharedTools::QtSingleApplication &app = *appPtr; QCoreApplication::setApplicationName(Core::Constants::IDE_CASED_ID); QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG)); QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR)); diff --git a/src/shared/qtsingleapplication/qtsingleapplication.cpp b/src/shared/qtsingleapplication/qtsingleapplication.cpp index 4a79f4eee6b..0f8fa8b6d13 100644 --- a/src/shared/qtsingleapplication/qtsingleapplication.cpp +++ b/src/shared/qtsingleapplication/qtsingleapplication.cpp @@ -148,13 +148,11 @@ void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessag disconnect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); } - QWidget* QtSingleApplication::activationWindow() const { return actWin; } - void QtSingleApplication::activateWindow() { if (actWin) { @@ -164,4 +162,70 @@ void QtSingleApplication::activateWindow() } } +static const char s_freezeDetector[] = "QTC_FREEZE_DETECTOR"; + +static std::optional isUsingFreezeDetector() +{ + if (!qEnvironmentVariableIsSet(s_freezeDetector)) + return {}; + + bool ok = false; + const int threshold = qEnvironmentVariableIntValue(s_freezeDetector, &ok); + return ok ? threshold : 100; // default value 100ms +} + +class ApplicationWithFreezerDetector : public SharedTools::QtSingleApplication +{ +public: + ApplicationWithFreezerDetector(const QString &id, int &argc, char **argv) + : QtSingleApplication(id, argc, argv) + , m_align(21, QChar::Space) + {} + void setFreezeTreshold(std::chrono::milliseconds freezeAbove) { m_threshold = freezeAbove; } + + bool notify(QObject *receiver, QEvent *event) override { + using namespace std::chrono; + const auto start = system_clock::now(); + const QPointer p(receiver); + const QString className = QLatin1String(receiver->metaObject()->className()); + const QString name = receiver->objectName(); + + const bool ret = QtSingleApplication::notify(receiver, event); + + const auto end = system_clock::now(); + const auto freeze = duration_cast(end - start); + if (freeze > m_threshold) { + const QString time = QTime::currentTime().toString(Qt::ISODateWithMs); + qDebug().noquote() << QString("FREEZE [%1]").arg(time) + << "of" << freeze.count() << "ms, on:" << event; + const QString receiverMessage = name.isEmpty() + ? QString("receiver class: %1").arg(className) + : QString("receiver class: %1, object name: %2").arg(className, name); + qDebug().noquote() << m_align << receiverMessage; + if (!p) + qDebug().noquote() << m_align << "THE RECEIVER GOT DELETED inside the event filter!"; + } + return ret; + } + +private: + const QString m_align; + std::chrono::milliseconds m_threshold = std::chrono::milliseconds(100); +}; + +QtSingleApplication *createApplication(const QString &id, int &argc, char **argv) +{ + const std::optional freezeDetector = isUsingFreezeDetector(); + if (!freezeDetector) + return new SharedTools::QtSingleApplication(id, argc, argv); + + qDebug() << s_freezeDetector << "evn var is set. The freezes of main thread, above" + << *freezeDetector << "ms, will be reported."; + qDebug() << "Change the freeze detection threshold by setting the" << s_freezeDetector + << "env var to a different numeric value (in ms)."; + ApplicationWithFreezerDetector *app = new ApplicationWithFreezerDetector(id, argc, argv); + app->setFreezeTreshold(std::chrono::milliseconds(*freezeDetector)); + return app; +} + } // namespace SharedTools diff --git a/src/shared/qtsingleapplication/qtsingleapplication.h b/src/shared/qtsingleapplication/qtsingleapplication.h index 2adbe185426..fdc485bd98c 100644 --- a/src/shared/qtsingleapplication/qtsingleapplication.h +++ b/src/shared/qtsingleapplication/qtsingleapplication.h @@ -46,4 +46,7 @@ private: bool block; }; +// Instantiates Freeze Detector when QTC_FREEZE_DETECTOR env var is set. +QtSingleApplication *createApplication(const QString &id, int &argc, char **argv); + } // namespace SharedTools From e6081aaa0a845a3cb9af1e4ff9cc8278aca2c276 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 4 May 2023 08:09:40 +0200 Subject: [PATCH 0815/1447] Utils: Add TerminalMode::Detached Change-Id: Ic36845d3469719e17f24602ce80f3e6cfc984fbf Reviewed-by: Christian Stenger --- src/libs/utils/processenums.h | 6 +- src/libs/utils/terminalhooks.cpp | 74 ++++++++++++++----- src/libs/utils/terminalinterface.cpp | 21 ++++++ src/libs/utils/terminalinterface.h | 4 +- src/plugins/docker/dockerdevice.cpp | 30 ++++---- src/plugins/haskell/haskellmanager.cpp | 20 ++--- .../devicesupport/desktopdevice.cpp | 24 +++--- src/plugins/projectexplorer/runcontrol.cpp | 2 +- src/plugins/python/pythonutils.cpp | 32 ++++---- src/plugins/remotelinux/linuxdevice.cpp | 30 ++------ src/plugins/terminal/terminalprocessimpl.cpp | 5 +- src/plugins/valgrind/valgrindrunner.cpp | 2 +- 12 files changed, 140 insertions(+), 110 deletions(-) diff --git a/src/libs/utils/processenums.h b/src/libs/utils/processenums.h index 5ce782cd946..84019bae530 100644 --- a/src/libs/utils/processenums.h +++ b/src/libs/utils/processenums.h @@ -24,9 +24,9 @@ enum class ProcessImpl { enum class TerminalMode { Off, - Run, - Debug, - On = Run // Default mode for terminal set to on + Run, // Start with process stub enabled + Debug, // Start with process stub enabled and wait for debugger to attach + Detached, // Start in a terminal, without process stub. }; // Miscellaneous, not process core diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index b6faae765d5..355aefe2c22 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -7,6 +7,7 @@ #include "process.h" #include "terminalcommand.h" #include "terminalinterface.h" +#include "utilstr.h" #include #include @@ -39,24 +40,20 @@ class ExternalTerminalProcessImpl final : public TerminalInterface : m_interface(interface) {} - void startStubProcess(const CommandLine &cmd, const ProcessSetupData &) override + ~ProcessStubCreator() override = default; + + expected_str startStubProcess(const CommandLine &cmd, + const ProcessSetupData &setupData) override { const TerminalCommand terminal = TerminalCommand::terminalEmulator(); - if (HostOsInfo::isWindowsHost()) { - m_terminalProcess.setCommand(cmd); - QObject::connect(&m_terminalProcess, &Process::done, this, [this] { - m_interface->onStubExited(); - }); - m_terminalProcess.setCreateConsoleOnWindows(true); - m_terminalProcess.setProcessMode(ProcessMode::Writer); - m_terminalProcess.start(); - } else if (HostOsInfo::isMacHost() && terminal.command == "Terminal.app") { + if (HostOsInfo::isMacHost() && terminal.command == "Terminal.app") { QTemporaryFile f; f.setAutoRemove(false); f.open(); f.setPermissions(QFile::ExeUser | QFile::ReadUser | QFile::WriteUser); f.write("#!/bin/sh\n"); + f.write(QString("cd %1\n").arg(setupData.m_workingDirectory.nativePath()).toUtf8()); f.write("clear\n"); f.write(QString("exec '%1' %2\n") .arg(cmd.executable().nativePath()) @@ -69,20 +66,59 @@ class ExternalTerminalProcessImpl final : public TerminalInterface = QString("tell app \"Terminal\" to do script \"'%1'; rm -f '%1'; exit\"") .arg(path); - m_terminalProcess.setCommand( - {"osascript", {"-e", "tell app \"Terminal\" to activate", "-e", exe}}); - m_terminalProcess.runBlocking(); - } else { - CommandLine cmdLine = {terminal.command, {terminal.executeArgs}}; - cmdLine.addCommandLineAsArgs(cmd, CommandLine::Raw); + Process process; - m_terminalProcess.setCommand(cmdLine); - m_terminalProcess.start(); + process.setCommand( + {"osascript", {"-e", "tell app \"Terminal\" to activate", "-e", exe}}); + process.runBlocking(); + + if (process.exitCode() != 0) { + return make_unexpected(Tr::tr("Failed to start terminal process: \"%1\"") + .arg(process.errorString())); + } + + return 0; } + + bool detached = setupData.m_terminalMode == TerminalMode::Detached; + + Process *process = new Process(detached ? nullptr : this); + if (detached) + QObject::connect(process, &Process::done, process, &Process::deleteLater); + + QObject::connect(process, + &Process::done, + m_interface, + &ExternalTerminalProcessImpl::onStubExited); + + process->setWorkingDirectory(setupData.m_workingDirectory); + + if constexpr (HostOsInfo::isWindowsHost()) { + process->setCommand(cmd); + process->setCreateConsoleOnWindows(true); + process->setProcessMode(ProcessMode::Writer); + } else { + QString extraArgsFromOptions = detached ? terminal.openArgs : terminal.executeArgs; + CommandLine cmdLine = {terminal.command, {}}; + if (!extraArgsFromOptions.isEmpty()) + cmdLine.addArgs(extraArgsFromOptions, CommandLine::Raw); + cmdLine.addCommandLineAsArgs(cmd, CommandLine::Raw); + process->setCommand(cmdLine); + } + + process->start(); + process->waitForStarted(); + if (process->error() != QProcess::UnknownError) { + return make_unexpected( + Tr::tr("Failed to start terminal process: \"%1\"").arg(process->errorString())); + } + + qint64 pid = process->processId(); + + return pid; } ExternalTerminalProcessImpl *m_interface; - Process m_terminalProcess; }; public: diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index 74831723296..bb193b4d98d 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -300,6 +300,25 @@ void TerminalInterface::start() if (isRunning()) return; + if (m_setup.m_terminalMode == TerminalMode::Detached) { + expected_str result; + QMetaObject::invokeMethod( + d->stubCreator, + [this, &result] { + result = d->stubCreator->startStubProcess(m_setup.m_commandLine, m_setup); + }, + d->stubCreator->thread() == QThread::currentThread() ? Qt::DirectConnection + : Qt::BlockingQueuedConnection); + + if (result) { + emit started(*result, 0); + emitFinished(0, QProcess::NormalExit); + } else { + emitError(QProcess::FailedToStart, result.error()); + } + return; + } + const expected_str result = startStubServer(); if (!result) { emitError(QProcess::FailedToStart, msgCommChannelFailed(result.error())); @@ -391,6 +410,8 @@ qint64 TerminalInterface::write(const QByteArray &data) } void TerminalInterface::sendControlSignal(ControlSignal controlSignal) { + QTC_ASSERT(m_setup.m_terminalMode != TerminalMode::Detached, return); + switch (controlSignal) { case ControlSignal::Terminate: case ControlSignal::Kill: diff --git a/src/libs/utils/terminalinterface.h b/src/libs/utils/terminalinterface.h index feb19875ba2..15b3a8c69e8 100644 --- a/src/libs/utils/terminalinterface.h +++ b/src/libs/utils/terminalinterface.h @@ -14,7 +14,9 @@ class TerminalInterfacePrivate; class StubCreator : public QObject { public: - virtual void startStubProcess(const CommandLine &cmd, const ProcessSetupData &setup) = 0; + virtual expected_str startStubProcess(const CommandLine &cmd, + const ProcessSetupData &setup) + = 0; }; class QTCREATOR_UTILS_EXPORT TerminalInterface : public ProcessInterface diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index d1175a8b5f9..b87c198555a 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -437,21 +437,17 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat return; } - Process *proc = new Process(d); + Process proc; + proc.setTerminalMode(TerminalMode::Detached); + proc.setEnvironment(env); + proc.setWorkingDirectory(workingDir); + proc.setCommand({Terminal::defaultShellForDevice(rootPath()), {}}); + proc.start(); - QObject::connect(proc, &Process::done, [proc] { - if (proc->error() != QProcess::UnknownError && MessageManager::instance()) { - MessageManager::writeDisrupting( - Tr::tr("Error starting remote shell: %1").arg(proc->errorString())); - } - proc->deleteLater(); - }); - - proc->setTerminalMode(TerminalMode::On); - proc->setEnvironment(env); - proc->setWorkingDirectory(workingDir); - proc->setCommand({Terminal::defaultShellForDevice(rootPath()), {}}); - proc->start(); + if (proc.error() != QProcess::UnknownError && MessageManager::instance()) { + MessageManager::writeDisrupting( + Tr::tr("Error starting remote shell: %1").arg(proc.errorString())); + } }); addDeviceAction({Tr::tr("Open Shell in Container"), [](const IDevice::Ptr &device, QWidget *) { @@ -1042,6 +1038,7 @@ public: using namespace Layouting; + // clang-format off Column { Stack { statusLabel, @@ -1050,9 +1047,8 @@ public: m_log, errorLabel, Row{showUnnamedContainers, m_buttons}, - } - .attachTo(this); - + }.attachTo(this); + // clang-format on connect(m_buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(m_buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); m_buttons->button(QDialogButtonBox::Ok)->setEnabled(false); diff --git a/src/plugins/haskell/haskellmanager.cpp b/src/plugins/haskell/haskellmanager.cpp index fbd4ee8aa03..78134d4b159 100644 --- a/src/plugins/haskell/haskellmanager.cpp +++ b/src/plugins/haskell/haskellmanager.cpp @@ -87,25 +87,17 @@ void HaskellManager::openGhci(const FilePath &haskellFile) }); const auto args = QStringList{"ghci"} + (isHaskell ? QStringList{haskellFile.fileName()} : QStringList()); - auto p = new Process(m_instance); - p->setTerminalMode(TerminalMode::On); - p->setCommand({stackExecutable(), args}); - p->setWorkingDirectory(haskellFile.absolutePath()); - connect(p, &Process::done, p, [p] { - if (p->result() != ProcessResult::FinishedWithSuccess) { - Core::MessageManager::writeDisrupting( - Tr::tr("Failed to run GHCi: \"%1\".").arg(p->errorString())); - } - p->deleteLater(); - }); - p->start(); + Process p; + p.setTerminalMode(TerminalMode::Detached); + p.setCommand({stackExecutable(), args}); + p.setWorkingDirectory(haskellFile.absolutePath()); + p.start(); } void HaskellManager::readSettings(QSettings *settings) { m_d->stackExecutable = FilePath::fromString( - settings->value(kStackExecutableKey, - defaultStackExecutable().toString()).toString()); + settings->value(kStackExecutableKey, defaultStackExecutable().toString()).toString()); emit m_instance->stackExecutableChanged(m_d->stackExecutable); } diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 26d296b181b..099040d6b24 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -25,9 +25,9 @@ #include #ifdef Q_OS_WIN -#include -#include #include +#include +#include #endif using namespace ProjectExplorer::Constants; @@ -52,23 +52,21 @@ DesktopDevice::DesktopDevice() setMachineType(IDevice::Hardware); setOsType(HostOsInfo::hostOs()); - const QString portRange = - QString::fromLatin1("%1-%2").arg(DESKTOP_PORT_START).arg(DESKTOP_PORT_END); + const QString portRange + = QString::fromLatin1("%1-%2").arg(DESKTOP_PORT_START).arg(DESKTOP_PORT_END); setFreePorts(Utils::PortList::fromString(portRange)); - setOpenTerminal([this](const Environment &env, const FilePath &path) { + setOpenTerminal([](const Environment &env, const FilePath &path) { const Environment realEnv = env.hasChanges() ? env : Environment::systemEnvironment(); const FilePath shell = Terminal::defaultShellForDevice(path); - Process *process = new Process(d.get()); - QObject::connect(process, &Process::done, process, &Process::deleteLater); - - process->setTerminalMode(TerminalMode::On); - process->setEnvironment(realEnv); - process->setCommand({shell, {}}); - process->setWorkingDirectory(path); - process->start(); + Process process; + process.setTerminalMode(TerminalMode::Detached); + process.setEnvironment(realEnv); + process.setCommand({shell, {}}); + process.setWorkingDirectory(path); + process.start(); }); } diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 3843e4c0e59..a0329e8bb39 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1437,7 +1437,7 @@ void SimpleTargetRunner::start() d->m_stopForced = false; d->m_stopReported = false; d->disconnect(this); - d->m_process.setTerminalMode(useTerminal ? Utils::TerminalMode::On : Utils::TerminalMode::Off); + d->m_process.setTerminalMode(useTerminal ? Utils::TerminalMode::Run : Utils::TerminalMode::Off); d->m_runAsRoot = runAsRoot; const QString msg = Tr::tr("Starting %1...").arg(d->m_command.displayName()); diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 0fb4d03f194..bf3f683dd13 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -106,6 +106,8 @@ static QStringList replImportArgs(const FilePath &pythonFile, ReplType type) void openPythonRepl(QObject *parent, const FilePath &file, ReplType type) { + Q_UNUSED(parent) + static const auto workingDir = [](const FilePath &file) { if (file.isEmpty()) { if (Project *project = ProjectManager::startupProject()) @@ -116,23 +118,21 @@ void openPythonRepl(QObject *parent, const FilePath &file, ReplType type) }; const auto args = QStringList{"-i"} + replImportArgs(file, type); - auto process = new Process(parent); - process->setTerminalMode(TerminalMode::On); const FilePath pythonCommand = detectPython(file); - process->setCommand({pythonCommand, args}); - process->setWorkingDirectory(workingDir(file)); - const QString commandLine = process->commandLine().toUserOutput(); - QObject::connect(process, &Process::done, process, [process, commandLine] { - if (process->error() != QProcess::UnknownError) { - Core::MessageManager::writeDisrupting(Tr::tr( - (process->error() == QProcess::FailedToStart) - ? "Failed to run Python (%1): \"%2\"." - : "Error while running Python (%1): \"%2\".") - .arg(commandLine, process->errorString())); - } - process->deleteLater(); - }); - process->start(); + + Process process; + process.setCommand({pythonCommand, args}); + process.setWorkingDirectory(workingDir(file)); + process.setTerminalMode(TerminalMode::Detached); + process.start(); + + if (process.error() != QProcess::UnknownError) { + Core::MessageManager::writeDisrupting( + Tr::tr((process.error() == QProcess::FailedToStart) + ? "Failed to run Python (%1): \"%2\"." + : "Error while running Python (%1): \"%2\".") + .arg(process.commandLine().toUserOutput(), process.errorString())); + } } QString pythonName(const FilePath &pythonPath) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 31980f6761e..59af192eaa2 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -316,7 +316,6 @@ public: QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; mutable QMutex m_shellMutex; - QList m_terminals; LinuxDeviceFileAccess m_fileAccess{this}; QReadWriteLock m_environmentCacheLock; @@ -961,23 +960,7 @@ LinuxDevice::LinuxDevice() }}); setOpenTerminal([this](const Environment &env, const FilePath &workingDir) { - Process * const proc = new Process; - d->m_terminals.append(proc); - QObject::connect(proc, &Process::done, proc, [this, proc] { - if (proc->error() != QProcess::UnknownError) { - const QString errorString = proc->errorString(); - QString message; - if (proc->error() == QProcess::FailedToStart) - message = Tr::tr("Error starting remote shell."); - else if (errorString.isEmpty()) - message = Tr::tr("Error running remote shell."); - else - message = Tr::tr("Error running remote shell: %1").arg(errorString); - Core::MessageManager::writeDisrupting(message); - } - proc->deleteLater(); - d->m_terminals.removeOne(proc); - }); + Process proc; // If we will not set any environment variables, we can leave out the shell executable // as the "ssh ..." call will automatically launch the default shell if there are @@ -985,11 +968,11 @@ LinuxDevice::LinuxDevice() // specify the shell executable. const QString shell = env.hasChanges() ? env.value_or("SHELL", "/bin/sh") : QString(); - proc->setCommand({filePath(shell), {}}); - proc->setTerminalMode(TerminalMode::On); - proc->setEnvironment(env); - proc->setWorkingDirectory(workingDir); - proc->start(); + proc.setCommand({filePath(shell), {}}); + proc.setTerminalMode(TerminalMode::Detached); + proc.setEnvironment(env); + proc.setWorkingDirectory(workingDir); + proc.start(); }); addDeviceAction({Tr::tr("Open Remote Shell"), [](const IDevice::Ptr &device, QWidget *) { @@ -1069,7 +1052,6 @@ LinuxDevicePrivate::LinuxDevicePrivate(LinuxDevice *parent) LinuxDevicePrivate::~LinuxDevicePrivate() { - qDeleteAll(m_terminals); auto closeShell = [this] { m_shellThread.quit(); m_shellThread.wait(); diff --git a/src/plugins/terminal/terminalprocessimpl.cpp b/src/plugins/terminal/terminalprocessimpl.cpp index 2397af50d17..79e9b91708d 100644 --- a/src/plugins/terminal/terminalprocessimpl.cpp +++ b/src/plugins/terminal/terminalprocessimpl.cpp @@ -26,7 +26,8 @@ public: , m_process(interface) {} - void startStubProcess(const CommandLine &cmd, const ProcessSetupData &setup) override + expected_str startStubProcess(const CommandLine &cmd, + const ProcessSetupData &setup) override { const Id id = Id::fromString(setup.m_commandLine.executable().toUserOutput()); @@ -51,6 +52,8 @@ public: if (process->inferiorProcessId()) process->emitFinished(-1, QProcess::CrashExit); }); + + return 0; } TerminalPane *m_terminalPane; diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index ef78c7f9ffc..fd265444226 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -197,7 +197,7 @@ void ValgrindRunner::setLocalServerAddress(const QHostAddress &localServerAddres void ValgrindRunner::setUseTerminal(bool on) { - d->m_process.setTerminalMode(on ? TerminalMode::On : TerminalMode::Off); + d->m_process.setTerminalMode(on ? TerminalMode::Run : TerminalMode::Off); } void ValgrindRunner::waitForFinished() const From 427640063e2d95752e95b17af13b8ed3e0e4473a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 28 Apr 2023 14:15:27 +0200 Subject: [PATCH 0816/1447] QmlJS: Allow disabling static analyzer messages Provide settings to define a customized set of enabled static analyzer messages. Fixes: QTCREATORBUG-29095 Change-Id: Id629e383dd9e3beeef98026759ac66716dc43d23 Reviewed-by: Fabian Kosmale Reviewed-by: Leena Miettinen --- src/libs/qmljs/qmljscheck.cpp | 80 ++++++-- src/libs/qmljs/qmljscheck.h | 8 +- .../qmljseditor/qmljseditingsettingspage.cpp | 190 +++++++++++++++++- .../qmljseditor/qmljseditingsettingspage.h | 12 ++ .../qmljseditor/qmljssemanticinfoupdater.cpp | 2 +- src/plugins/qmljseditor/qmltaskmanager.cpp | 3 +- 6 files changed, 268 insertions(+), 27 deletions(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 8d5bcadad57..51be467387d 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -639,7 +640,46 @@ Q_GLOBAL_STATIC(UnsupportedRootObjectTypesByVisualDesigner, unsupportedRootObjec Q_GLOBAL_STATIC(UnsupportedRootObjectTypesByQmlUi, unsupportedRootObjectTypesByQmlUi) Q_GLOBAL_STATIC(UnsupportedTypesByQmlUi, unsupportedTypesByQmlUi) -Check::Check(Document::Ptr doc, const ContextPtr &context) +QList Check::defaultDisabledMessages() +{ + static const QList disabled = Utils::sorted(QList{ + HintAnonymousFunctionSpacing, + HintDeclareVarsInOneLine, + HintDeclarationsShouldBeAtStartOfFunction, + HintBinaryOperatorSpacing, + HintOneStatementPerLine, + HintExtraParentheses, + + // QmlDesigner related + WarnImperativeCodeNotEditableInVisualDesigner, + WarnUnsupportedTypeInVisualDesigner, + WarnReferenceToParentItemNotSupportedByVisualDesigner, + WarnUndefinedValueForVisualDesigner, + WarnStatesOnlyInRootItemForVisualDesigner, + ErrUnsupportedRootTypeInVisualDesigner, + ErrInvalidIdeInVisualDesigner, + + }); + return disabled; +} + +QList Check::defaultDisabledMessagesForNonQuickUi() +{ + static const QList disabled = Utils::sorted(QList{ + // QmlDesigner related + ErrUnsupportedRootTypeInQmlUi, + ErrUnsupportedTypeInQmlUi, + ErrFunctionsNotSupportedInQmlUi, + ErrBlocksNotSupportedInQmlUi, + ErrBehavioursNotSupportedInQmlUi, + ErrStatesOnlyInRootItemInQmlUi, + ErrReferenceToParentItemNotSupportedInQmlUi, + ErrDoNotMixTranslationFunctionsInQmlUi, + }); + return disabled; +} + +Check::Check(Document::Ptr doc, const ContextPtr &context, Utils::QtcSettings *qtcSettings) : _doc(doc) , _context(context) , _scopeChain(doc, _context) @@ -655,16 +695,25 @@ Check::Check(Document::Ptr doc, const ContextPtr &context) } _enabledMessages = Utils::toSet(Message::allMessageTypes()); - disableMessage(HintAnonymousFunctionSpacing); - disableMessage(HintDeclareVarsInOneLine); - disableMessage(HintDeclarationsShouldBeAtStartOfFunction); - disableMessage(HintBinaryOperatorSpacing); - disableMessage(HintOneStatementPerLine); - disableMessage(HintExtraParentheses); + if (qtcSettings && qtcSettings->value("J.QtQuick/QmlJSEditor.useCustomAnalyzer").toBool()) { + auto disabled = qtcSettings->value("J.QtQuick/QmlJSEditor.disabledMessages").toList(); + for (const QVariant &disabledNumber : disabled) + disableMessage(StaticAnalysis::Type(disabledNumber.toInt())); - disableQmlDesignerChecks(); - if (!isQtQuick2Ui()) - disableQmlDesignerUiFileChecks(); + if (!isQtQuick2Ui()) { + auto disabled = qtcSettings->value("J.QtQuick/QmlJSEditor.disabledMessagesNonQuickUI").toList(); + for (const QVariant &disabledNumber : disabled) + disableMessage(StaticAnalysis::Type(disabledNumber.toInt())); + } + } else { + for (auto type : defaultDisabledMessages()) + disableMessage(type); + + if (!isQtQuick2Ui()) { + for (auto type : defaultDisabledMessagesForNonQuickUi()) + disableMessage(type); + } + } } Check::~Check() @@ -702,17 +751,6 @@ void Check::enableQmlDesignerChecks() //## triggers too often ## check.enableMessage(StaticAnalysis::WarnUndefinedValueForVisualDesigner); } -void Check::disableQmlDesignerChecks() -{ - disableMessage(WarnImperativeCodeNotEditableInVisualDesigner); - disableMessage(WarnUnsupportedTypeInVisualDesigner); - disableMessage(WarnReferenceToParentItemNotSupportedByVisualDesigner); - disableMessage(WarnUndefinedValueForVisualDesigner); - disableMessage(WarnStatesOnlyInRootItemForVisualDesigner); - disableMessage(ErrUnsupportedRootTypeInVisualDesigner); - disableMessage(ErrInvalidIdeInVisualDesigner); -} - void Check::enableQmlDesignerUiFileChecks() { enableMessage(ErrUnsupportedRootTypeInQmlUi); diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h index a868bbe15e2..60484fc43f1 100644 --- a/src/libs/qmljs/qmljscheck.h +++ b/src/libs/qmljs/qmljscheck.h @@ -12,6 +12,8 @@ #include #include +namespace Utils { class QtcSettings; } + namespace QmlJS { class Imports; @@ -22,7 +24,7 @@ class QMLJS_EXPORT Check: protected AST::Visitor public: // prefer taking root scope chain? - Check(Document::Ptr doc, const ContextPtr &context); + Check(Document::Ptr doc, const ContextPtr &context, Utils::QtcSettings *qtcSettings = nullptr); ~Check(); QList operator()(); @@ -31,11 +33,13 @@ public: void disableMessage(StaticAnalysis::Type type); void enableQmlDesignerChecks(); - void disableQmlDesignerChecks(); void enableQmlDesignerUiFileChecks(); void disableQmlDesignerUiFileChecks(); + static QList defaultDisabledMessages(); + static QList defaultDisabledMessagesForNonQuickUi(); + protected: bool preVisit(AST::Node *ast) override; void postVisit(AST::Node *ast) override; diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 7b6474449c4..1a8ff90e552 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -7,11 +7,15 @@ #include #include +#include +#include +#include +#include #include #include #include +#include #include -#include #include #include @@ -19,6 +23,7 @@ #include #include #include +#include const char AUTO_FORMAT_ON_SAVE[] = "QmlJSEditor.AutoFormatOnSave"; const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "QmlJSEditor.AutoFormatOnlyCurrentProject"; @@ -31,6 +36,9 @@ const char UIQML_OPEN_MODE[] = "QmlJSEditor.openUiQmlMode"; const char FORMAT_COMMAND[] = "QmlJSEditor.formatCommand"; const char FORMAT_COMMAND_OPTIONS[] = "QmlJSEditor.formatCommandOptions"; const char CUSTOM_COMMAND[] = "QmlJSEditor.useCustomFormatCommand"; +const char CUSTOM_ANALYZER[] = "QmlJSEditor.useCustomAnalyzer"; +const char DISABLED_MESSAGES[] = "QmlJSEditor.disabledMessages"; +const char DISABLED_MESSAGES_NONQUICKUI[] = "QmlJSEditor.disabledMessagesNonQuickUI"; const char DEFAULT_CUSTOM_FORMAT_COMMAND[] = "%{CurrentDocument:Project:QT_HOST_BINS}/qmlformat"; using namespace QmlJSEditor; @@ -57,6 +65,23 @@ void QmlJsEditingSettings::fromSettings(QSettings *settings) m_formatCommand = settings->value(FORMAT_COMMAND, {}).toString(); m_formatCommandOptions = settings->value(FORMAT_COMMAND_OPTIONS, {}).toString(); m_useCustomFormatCommand = settings->value(CUSTOM_COMMAND, QVariant(false)).toBool(); + m_useCustomAnalyzer = settings->value(CUSTOM_ANALYZER, QVariant(false)).toBool(); + + const QList disabledByDefault = Utils::transform( + QmlJS::Check::defaultDisabledMessages(), + [](QmlJS::StaticAnalysis::Type t) { return int(t); }); + m_disabledMessages = Utils::transform( + settings->value(DISABLED_MESSAGES, + QVariant::fromValue(disabledByDefault)).toList(), + [](const QVariant &v){ return v.toInt(); }); + const QList disabledForNonQuickUi = Utils::transform( + QmlJS::Check::defaultDisabledMessagesForNonQuickUi(), + [](QmlJS::StaticAnalysis::Type t){ return int(t); }); + m_disabledMessagesForNonQuickUi = Utils::transform( + settings->value(DISABLED_MESSAGES_NONQUICKUI, + QVariant::fromValue(disabledForNonQuickUi)).toList(), + [](const QVariant &v) { return v.toInt(); }); + settings->endGroup(); } @@ -80,6 +105,24 @@ void QmlJsEditingSettings::toSettings(QSettings *settings) const CUSTOM_COMMAND, m_useCustomFormatCommand, false); + Utils::QtcSettings::setValueWithDefault(settings, + CUSTOM_ANALYZER, + m_useCustomAnalyzer, + false); + const QList disabledByDefault = Utils::transform( + QmlJS::Check::defaultDisabledMessages(), + [](QmlJS::StaticAnalysis::Type t){ return int(t); }); + Utils::QtcSettings::setValueWithDefault(settings, + DISABLED_MESSAGES, + Utils::sorted(Utils::toList(m_disabledMessages)), + disabledByDefault); + const QList disabledNonQuickUi = Utils::transform( + QmlJS::Check::defaultDisabledMessagesForNonQuickUi(), + [](QmlJS::StaticAnalysis::Type t){ return int(t); }); + Utils::QtcSettings::setValueWithDefault(settings, + DISABLED_MESSAGES_NONQUICKUI, + Utils::sorted(Utils::toList(m_disabledMessagesForNonQuickUi)), + disabledNonQuickUi); settings->endGroup(); QmllsSettingsManager::instance()->checkForChanges(); } @@ -93,7 +136,10 @@ bool QmlJsEditingSettings::equals(const QmlJsEditingSettings &other) const && m_foldAuxData == other.m_foldAuxData && m_qmllsSettings == other.m_qmllsSettings && m_uiQmlOpenMode == other.m_uiQmlOpenMode && m_formatCommand == other.m_formatCommand && m_formatCommandOptions == other.m_formatCommandOptions - && m_useCustomFormatCommand == other.m_useCustomFormatCommand; + && m_useCustomFormatCommand == other.m_useCustomFormatCommand + && m_useCustomAnalyzer == other.m_useCustomAnalyzer + && m_disabledMessages == other.m_disabledMessages + && m_disabledMessagesForNonQuickUi == other.m_disabledMessagesForNonQuickUi; } bool QmlJsEditingSettings::enableContextPane() const @@ -201,6 +247,92 @@ void QmlJsEditingSettings::setUiQmlOpenMode(const QString &mode) m_uiQmlOpenMode = mode; } +bool QmlJsEditingSettings::useCustomAnalyzer() const +{ + return m_useCustomAnalyzer; +} + +void QmlJsEditingSettings::setUseCustomAnalyzer(bool customAnalyzer) +{ + m_useCustomAnalyzer = customAnalyzer; +} + +QSet QmlJsEditingSettings::disabledMessages() const +{ + return m_disabledMessages; +} + +void QmlJsEditingSettings::setDisabledMessages(const QSet &disabled) +{ + m_disabledMessages = disabled; +} + +QSet QmlJsEditingSettings::disabledMessagesForNonQuickUi() const +{ + return m_disabledMessagesForNonQuickUi; +} + +void QmlJsEditingSettings::setDisabledMessagesForNonQuickUi(const QSet &disabled) +{ + m_disabledMessagesForNonQuickUi = disabled; +} + +class AnalyzerMessageItem final : public Utils::TreeItem +{ +public: + AnalyzerMessageItem() = default; + AnalyzerMessageItem(int number, const QString &message) + : m_messageNumber(number) + , m_message(message) + {} + + QVariant data(int column, int role) const final + { + if (role == Qt::DisplayRole) { + if (column == 0) + return QString("M%1").arg(m_messageNumber); + if (column == 2) + return m_message.split('\n').first(); + } else if (role == Qt::CheckStateRole) { + if (column == 0) + return m_checked ? Qt::Checked : Qt::Unchecked; + if (column == 1) + return m_disabledInNonQuickUi ? Qt::Checked : Qt::Unchecked; + } + return TreeItem::data(column, role); + } + + bool setData(int column, const QVariant &value, int role) final + { + if (role == Qt::CheckStateRole) { + if (column == 0) { + m_checked = value.toBool(); + return true; + } + if (column == 1) { + m_disabledInNonQuickUi = value.toBool(); + return true; + } + } + return false; + } + + Qt::ItemFlags flags(int column) const final + { + if (column == 0 || column == 1) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; + else + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + + int messageNumber() const { return m_messageNumber; } +private: + int m_messageNumber = -1; + QString m_message; + bool m_checked = true; + bool m_disabledInNonQuickUi = false; +}; + class QmlJsEditingSettingsPageWidget final : public Core::IOptionsPageWidget { public: @@ -247,6 +379,22 @@ public: useLatestQmlls->setEnabled(checked != Qt::Unchecked); }); + useCustomAnalyzer = new QCheckBox(Tr::tr("Use customized static analyzer")); + useCustomAnalyzer->setChecked(s.useCustomAnalyzer()); + analyzerMessageModel = new Utils::TreeModel(this); + analyzerMessageModel->setHeader({Tr::tr("Enabled"), + Tr::tr("Disabled for non Qt Quick UI"), + Tr::tr("Message")}); + analyzerMessagesView = new QTreeView; + analyzerMessagesView->setModel(analyzerMessageModel); + analyzerMessagesView->setEnabled(s.useCustomAnalyzer()); + QObject::connect(useCustomAnalyzer, &QCheckBox::stateChanged, this, [this](int checked){ + analyzerMessagesView->setEnabled(checked != Qt::Unchecked); + }); + analyzerMessagesView->setToolTip(Tr::tr("Enabled checks can be disabled for non Qt Quick UI" + " files,\nbut disabled checks cannot get explicitly" + " enabled for non Qt Quick UI files.")); + using namespace Layouting; // clang-format off QWidget *formattingGroup = nullptr; @@ -279,6 +427,10 @@ public: title(Tr::tr("Language Server")), Column{useQmlls, useLatestQmlls}, }, + Group { + title(Tr::tr("Static Analyzer")), + Column{ useCustomAnalyzer, analyzerMessagesView }, + }, st, }.attachTo(this); // clang-format on @@ -300,6 +452,8 @@ public: updateFormatCommandState(); }); connect(useCustomFormatCommand, &QCheckBox::toggled, this, updateFormatCommandState); + + populateAnalyzerMessages(s.disabledMessages(), s.disabledMessagesForNonQuickUi()); } void apply() final @@ -316,10 +470,39 @@ public: s.setUiQmlOpenMode(uiQmlOpenComboBox->currentData().toString()); s.qmllsSettings().useQmlls = useQmlls->isChecked(); s.qmllsSettings().useLatestQmlls = useLatestQmlls->isChecked(); + s.setUseCustomAnalyzer(useCustomAnalyzer->isChecked()); + QSet disabled; + QSet disabledForNonQuickUi; + analyzerMessageModel->forAllItems( + [&disabled, &disabledForNonQuickUi](AnalyzerMessageItem *item){ + if (item->data(0, Qt::CheckStateRole) == Qt::Unchecked) + disabled.insert(item->messageNumber()); + if (item->data(1, Qt::CheckStateRole) == Qt::Checked) + disabledForNonQuickUi.insert(item->messageNumber()); + }); + s.setDisabledMessages(disabled); + s.setDisabledMessagesForNonQuickUi(disabledForNonQuickUi); s.set(); } private: + void populateAnalyzerMessages(const QSet &disabled, const QSet &disabledForNonQuickUi) + { + using namespace QmlJS::StaticAnalysis; + auto knownMessages = Utils::sorted(Message::allMessageTypes()); + auto root = analyzerMessageModel->rootItem(); + for (auto msgType : knownMessages) { + const QString msg = Message::prototypeForMessageType(msgType).message; + auto item = new AnalyzerMessageItem(msgType, msg); + item->setData(0, !disabled.contains(msgType), Qt::CheckStateRole); + item->setData(1, disabledForNonQuickUi.contains(msgType), Qt::CheckStateRole); + root->appendChild(item); + } + + for (int column = 0; column < 3; ++column) + analyzerMessagesView->resizeColumnToContents(column); + } + QCheckBox *autoFormatOnSave; QCheckBox *autoFormatOnlyCurrentProject; QCheckBox *useCustomFormatCommand; @@ -331,6 +514,9 @@ private: QCheckBox *useQmlls; QCheckBox *useLatestQmlls; QComboBox *uiQmlOpenComboBox; + QCheckBox *useCustomAnalyzer; + QTreeView *analyzerMessagesView; + Utils::TreeModel *analyzerMessageModel; }; diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.h b/src/plugins/qmljseditor/qmljseditingsettingspage.h index dc6bf1e9fd9..d7f8f78bd30 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.h +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.h @@ -58,6 +58,15 @@ public: const QString uiQmlOpenMode() const; void setUiQmlOpenMode(const QString &mode); + bool useCustomAnalyzer() const; + void setUseCustomAnalyzer(bool customAnalyzer); + + QSet disabledMessages() const; + void setDisabledMessages(const QSet &disabled); + + QSet disabledMessagesForNonQuickUi() const; + void setDisabledMessagesForNonQuickUi(const QSet &disabled); + friend bool operator==(const QmlJsEditingSettings &s1, const QmlJsEditingSettings &s2) { return s1.equals(s2); } friend bool operator!=(const QmlJsEditingSettings &s1, const QmlJsEditingSettings &s2) @@ -70,10 +79,13 @@ private: bool m_autoFormatOnlyCurrentProject = false; bool m_foldAuxData = true; bool m_useCustomFormatCommand = false; + bool m_useCustomAnalyzer = false; QmllsSettings m_qmllsSettings; QString m_uiQmlOpenMode; QString m_formatCommand; QString m_formatCommandOptions; + QSet m_disabledMessages; + QSet m_disabledMessagesForNonQuickUi; }; namespace Internal { diff --git a/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp b/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp index e0a20c18451..764f125e543 100644 --- a/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp +++ b/src/plugins/qmljseditor/qmljssemanticinfoupdater.cpp @@ -104,7 +104,7 @@ QmlJSTools::SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::D semanticInfo.staticAnalysisMessages = jsonChecker(schema); } } else { - Check checker(doc, semanticInfo.context); + Check checker(doc, semanticInfo.context, Core::ICore::settings()); semanticInfo.staticAnalysisMessages = checker(); } diff --git a/src/plugins/qmljseditor/qmltaskmanager.cpp b/src/plugins/qmljseditor/qmltaskmanager.cpp index fb673066f3a..ca985f4022e 100644 --- a/src/plugins/qmljseditor/qmltaskmanager.cpp +++ b/src/plugins/qmljseditor/qmltaskmanager.cpp @@ -4,6 +4,7 @@ #include "qmltaskmanager.h" #include "qmljseditorconstants.h" +#include #include #include #include @@ -87,7 +88,7 @@ void QmlTaskManager::collectMessages(QPromise &promise, fileName, Constants::TASK_CATEGORY_QML_ANALYSIS); - Check checker(document, context); + Check checker(document, context, Core::ICore::settings()); result.tasks += convertToTasks(checker(), fileName, Constants::TASK_CATEGORY_QML_ANALYSIS); From 6e2e7a63e6f3f80d9bd1ead5ca85b16d9f22ed6b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 4 May 2023 09:05:27 +0200 Subject: [PATCH 0817/1447] QmlJS: Allow reset of the customized analyzer Provide a context menu to reset the enabled and disabled messages of the static analyzer to the internal default. Change-Id: I98bde71899ad4de50d0e170bf0d2892b87989ceb Reviewed-by: Fabian Kosmale Reviewed-by: Leena Miettinen --- .../qmljseditor/qmljseditingsettingspage.cpp | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 1a8ff90e552..bfb5a002cfa 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,22 @@ const char DEFAULT_CUSTOM_FORMAT_COMMAND[] = "%{CurrentDocument:Project:QT_HOST_ using namespace QmlJSEditor; using namespace QmlJSEditor::Internal; +static QList defaultDisabledMessages() +{ + static const QList disabledByDefault = Utils::transform( + QmlJS::Check::defaultDisabledMessages(), + [](QmlJS::StaticAnalysis::Type t) { return int(t); }); + return disabledByDefault; +} + +static QList defaultDisabledMessagesNonQuickUi() +{ + static const QList disabledForNonQuickUi = Utils::transform( + QmlJS::Check::defaultDisabledMessagesForNonQuickUi(), + [](QmlJS::StaticAnalysis::Type t){ return int(t); }); + return disabledForNonQuickUi; +} + void QmlJsEditingSettings::set() { if (get() != *this) @@ -67,19 +84,13 @@ void QmlJsEditingSettings::fromSettings(QSettings *settings) m_useCustomFormatCommand = settings->value(CUSTOM_COMMAND, QVariant(false)).toBool(); m_useCustomAnalyzer = settings->value(CUSTOM_ANALYZER, QVariant(false)).toBool(); - const QList disabledByDefault = Utils::transform( - QmlJS::Check::defaultDisabledMessages(), - [](QmlJS::StaticAnalysis::Type t) { return int(t); }); m_disabledMessages = Utils::transform( settings->value(DISABLED_MESSAGES, - QVariant::fromValue(disabledByDefault)).toList(), + QVariant::fromValue(defaultDisabledMessages())).toList(), [](const QVariant &v){ return v.toInt(); }); - const QList disabledForNonQuickUi = Utils::transform( - QmlJS::Check::defaultDisabledMessagesForNonQuickUi(), - [](QmlJS::StaticAnalysis::Type t){ return int(t); }); m_disabledMessagesForNonQuickUi = Utils::transform( settings->value(DISABLED_MESSAGES_NONQUICKUI, - QVariant::fromValue(disabledForNonQuickUi)).toList(), + QVariant::fromValue(defaultDisabledMessagesNonQuickUi())).toList(), [](const QVariant &v) { return v.toInt(); }); settings->endGroup(); @@ -109,20 +120,14 @@ void QmlJsEditingSettings::toSettings(QSettings *settings) const CUSTOM_ANALYZER, m_useCustomAnalyzer, false); - const QList disabledByDefault = Utils::transform( - QmlJS::Check::defaultDisabledMessages(), - [](QmlJS::StaticAnalysis::Type t){ return int(t); }); Utils::QtcSettings::setValueWithDefault(settings, DISABLED_MESSAGES, Utils::sorted(Utils::toList(m_disabledMessages)), - disabledByDefault); - const QList disabledNonQuickUi = Utils::transform( - QmlJS::Check::defaultDisabledMessagesForNonQuickUi(), - [](QmlJS::StaticAnalysis::Type t){ return int(t); }); + defaultDisabledMessages()); Utils::QtcSettings::setValueWithDefault(settings, DISABLED_MESSAGES_NONQUICKUI, Utils::sorted(Utils::toList(m_disabledMessagesForNonQuickUi)), - disabledNonQuickUi); + defaultDisabledMessagesNonQuickUi()); settings->endGroup(); QmllsSettingsManager::instance()->checkForChanges(); } @@ -394,7 +399,9 @@ public: analyzerMessagesView->setToolTip(Tr::tr("Enabled checks can be disabled for non Qt Quick UI" " files,\nbut disabled checks cannot get explicitly" " enabled for non Qt Quick UI files.")); - + analyzerMessagesView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(analyzerMessagesView, &QTreeView::customContextMenuRequested, + this, &QmlJsEditingSettingsPageWidget::showContextMenu); using namespace Layouting; // clang-format off QWidget *formattingGroup = nullptr; @@ -503,6 +510,20 @@ private: analyzerMessagesView->resizeColumnToContents(column); } + void showContextMenu(const QPoint &position) + { + QMenu menu; + QAction *reset = new QAction(Tr::tr("Reset to Default"), &menu); + menu.addAction(reset); + connect(reset, &QAction::triggered, this, [this](){ + analyzerMessageModel->clear(); + populateAnalyzerMessages(Utils::toSet(defaultDisabledMessages()), + Utils::toSet(defaultDisabledMessagesNonQuickUi())); + + }); + menu.exec(analyzerMessagesView->mapToGlobal(position)); + } + QCheckBox *autoFormatOnSave; QCheckBox *autoFormatOnlyCurrentProject; QCheckBox *useCustomFormatCommand; From d6e22f43753c941db2971ad1720e6c8f0aa7c452 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 3 May 2023 22:25:02 +0200 Subject: [PATCH 0818/1447] Examples: Make GridItemImageSize adapt to GridItemWidth/Height Reduces the magic values a bit, and adds comments. Change-Id: I9b288663ccfdaffdc2ffd25260d87c97c5dcbde1 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/welcomepagehelper.cpp | 2 +- src/plugins/coreplugin/welcomepagehelper.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index cba0d6c033e..d0b1c9f3f91 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -144,7 +144,7 @@ bool SectionGridView::hasHeightForWidth() const int SectionGridView::heightForWidth(int width) const { - const int columnCount = width / Core::WelcomePageHelpers::GridItemWidth; + const int columnCount = qMax(1, width / Core::WelcomePageHelpers::GridItemWidth); const int rowCount = (model()->rowCount() + columnCount - 1) / columnCount; const int maxRowCount = m_maxRows ? std::min(*m_maxRows, rowCount) : rowCount; return maxRowCount * Core::WelcomePageHelpers::GridItemHeight; diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index f997b2539a9..8599c227b90 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -26,9 +26,13 @@ constexpr int HSpacing = 20; constexpr int ItemGap = 4; constexpr int GridItemGap = 3 * ItemGap; -constexpr int GridItemWidth = 240 + GridItemGap; +constexpr int GridItemWidth = 240 + GridItemGap; // Extra GridItemGap as "spacing" constexpr int GridItemHeight = GridItemWidth; -constexpr QSize GridItemImageSize(214, 160); +constexpr QSize GridItemImageSize(GridItemWidth - GridItemGap + - 2 * (GridItemGap + 1), // Horizontal margins + 1 pixel + GridItemHeight - GridItemGap + - GridItemGap - 1 // Upper margin + 1 pixel + - 67); // Bottom margin (for title + tags) CORE_EXPORT QFont brandFont(); CORE_EXPORT QWidget *panelBar(QWidget *parent = nullptr); From ce7bd5792647a15bcabce6ef0794feb90e5723bf Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 4 May 2023 13:17:13 +0200 Subject: [PATCH 0819/1447] Core: Fix warning on macOS Previously the icon was taken from the new file/dir name which does not yet exists. This lead to a warning message. Settings a fixed icon fixes this. Change-Id: I4e7def0dfafd9d62b9a010ff850f3c7ea18c79a2 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/locator/filesystemfilter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index a4f3d42a726..674949f5a53 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -12,11 +12,12 @@ #include -#include #include +#include #include #include #include +#include #include #include @@ -265,6 +266,7 @@ static LocatorFilterEntries matchesImpl(Promise &promise, { LocatorFilterEntry filterEntry; filterEntry.displayName = Tr::tr("Create and Open File \"%1\"").arg(expandedEntry); + filterEntry.displayIcon = Utils::FileIconProvider::icon(QFileIconProvider::File); filterEntry.acceptor = [fullFilePath] { QMetaObject::invokeMethod( EditorManager::instance(), @@ -281,6 +283,7 @@ static LocatorFilterEntries matchesImpl(Promise &promise, { LocatorFilterEntry filterEntry; filterEntry.displayName = Tr::tr("Create Directory \"%1\"").arg(expandedEntry); + filterEntry.displayIcon = Utils::FileIconProvider::icon(QFileIconProvider::Folder); filterEntry.acceptor = [fullFilePath, shortcutString] { QMetaObject::invokeMethod( EditorManager::instance(), From 34ad405d762dd7cf836c88dd1266c69e1e0523c5 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 4 May 2023 10:47:09 +0200 Subject: [PATCH 0820/1447] QbsProjectManager: Consider cpp.warningLevel in compiler options setup Change-Id: I6f955691c1fedf319716e98645de50590fb05747 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger --- src/plugins/qbsprojectmanager/qbsproject.cpp | 9 +++++++++ src/plugins/qbsprojectmanager/qbssession.cpp | 1 + 2 files changed, 10 insertions(+) diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index c334bc84b97..3b59618310c 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -744,6 +744,7 @@ static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags, }; const QJsonValue &enableExceptions = getCppProp("enableExceptions"); const QJsonValue &enableRtti = getCppProp("enableRtti"); + const QString warningLevel = getCppProp("warningLevel").toString(); QStringList commonFlags = arrayToStringList(getCppProp("platformCommonCompilerFlags")); commonFlags << arrayToStringList(getCppProp("commonCompilerFlags")) << arrayToStringList(getCppProp("platformDriverFlags")) @@ -773,6 +774,10 @@ static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags, if (!machineType.isEmpty()) commonFlags << ("-march=" + machineType); } + if (warningLevel == "all") + commonFlags << "-Wall" << "-Wextra"; + else if (warningLevel == "none") + commonFlags << "-w"; const QStringList targetOS = arrayToStringList(properties.value("qbs.targetOS")); if (targetOS.contains("unix")) { const QVariant positionIndependentCode = getCppProp("positionIndependentCode"); @@ -837,6 +842,10 @@ static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags, else if (exceptionModel == "externc") commonFlags << "/EHs"; } + if (warningLevel == "all") + commonFlags << "/Wall"; + else if (warningLevel == "none") + commonFlags << "/w"; cFlags = cxxFlags = commonFlags; cFlags << "/TC"; cxxFlags << "/TP"; diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index ef0ef8e52ed..13121cfb66e 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -370,6 +370,7 @@ void QbsSession::insertRequestedModuleProperties(QJsonObject &request) "cpp.useCxxPrecompiledHeader", "cpp.useObjcPrecompiledHeader", "cpp.useObjcxxPrecompiledHeader", + "cpp.warningLevel", "qbs.architecture", "qbs.architectures", "qbs.sysroot", From 13dd6788349857452c8e8ace9d3ae2a55fed9468 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 4 May 2023 15:07:18 +0200 Subject: [PATCH 0821/1447] Utils: Fix MinGW build Amends a0f6e8dc04291138ec2305fe7c02a0a460f57fac The issue is that pthread.h is including , which ends up to utils/process.h since it's first in path. Change-Id: I525384083b6952aded4b77c29d00d85f084c60f9 Reviewed-by: Jarek Kobus --- src/libs/utils/process.h | 8 +++++++- src/plugins/clangformat/CMakeLists.txt | 1 + src/plugins/vcpkg/CMakeLists.txt | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/process.h b/src/libs/utils/process.h index f89b6f9b22e..f11f3c3c41c 100644 --- a/src/libs/utils/process.h +++ b/src/libs/utils/process.h @@ -1,7 +1,11 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#pragma once +#if defined(Q_CC_MINGW) && defined(WIN_PTHREADS_H) && !defined(_INC_PROCESS) + // Arrived here via which wants to include + #include_next +#elif !defined(UTILS_PROCESS_H) +#define UTILS_PROCESS_H #include "utils_global.h" @@ -217,3 +221,5 @@ public: } // namespace Utils QTC_DECLARE_CUSTOM_TASK(ProcessTask, Utils::ProcessTaskAdapter); + +#endif // UTILS_PROCESS_H diff --git a/src/plugins/clangformat/CMakeLists.txt b/src/plugins/clangformat/CMakeLists.txt index 79767a2ffed..7c49e9ad47e 100644 --- a/src/plugins/clangformat/CMakeLists.txt +++ b/src/plugins/clangformat/CMakeLists.txt @@ -39,4 +39,5 @@ extend_qtc_plugin(ClangFormat tests/clangformat-test.h DEFINES TESTDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/tests/data" + EXPLICIT_MOC tests/clangformat-test.h ) diff --git a/src/plugins/vcpkg/CMakeLists.txt b/src/plugins/vcpkg/CMakeLists.txt index f5d65cf3937..d3fb8d00ed8 100644 --- a/src/plugins/vcpkg/CMakeLists.txt +++ b/src/plugins/vcpkg/CMakeLists.txt @@ -13,4 +13,5 @@ extend_qtc_plugin(Vcpkg CONDITION WITH_TESTS SOURCES vcpkg_test.cpp vcpkg_test.h + EXPLICIT_MOC vcpkg_test.h ) From 8854f53a425111089ece016d57633f82bd8b41a2 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 3 May 2023 19:13:07 +0200 Subject: [PATCH 0822/1447] CMakePM: Fix duplicated CMake presets kits QTC_KIT_DEFAULT_CONFIG_HASH was introduced in order to match the previous CMake presets kits. This would hash the Qt and the C/C++ compiler paths. Unfortunately on Linux CMake would pick "cc" and "c++" by default, whilst Qt Creator uses "gcc" and "g++". The compilers would match from the Qt Creator point of view, but the hash values would be different. On mac there is a similar issue with compiler launchers. This patchset fixes this by removing the hash and fixes also the issue of allowing broken CMake presets kits (without any compilers), which were the reason for introducing the hash key in the first place. Fixes: QTCREATORBUG-29075 Change-Id: Id8dc081febba7bc7023c98055afc6ebfcdc55542 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- .../cmakebuildconfiguration.cpp | 6 --- .../cmakekitinformation.cpp | 47 ---------------- .../cmakeprojectmanager/cmakekitinformation.h | 5 -- .../cmakeprojectimporter.cpp | 53 +++++++++++-------- 4 files changed, 31 insertions(+), 80 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index d299b3eb77a..d7f85a7e44b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -1182,12 +1182,6 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume initialArguments.removeIf( [presetArgument](const QString &item) { return item == presetArgument; }); - // Remove the -DQTC_KIT_DEFAULT_CONFIG_HASH argument - const QString presetHashArgument - = CMakeConfigurationKitAspect::kitDefaultConfigHashItem(k).toArgument(); - initialArguments.removeIf( - [presetHashArgument](const QString &item) { return item == presetHashArgument; }); - PresetsDetails::ConfigurePreset configurePreset = Utils::findOrDefault(project->presetsData().configurePresets, [presetName](const PresetsDetails::ConfigurePreset &preset) { diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 064ed0d59ba..b02f68357d8 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -38,7 +38,6 @@ #include #include -#include #include #include #include @@ -874,7 +873,6 @@ const char CMAKE_CXX_TOOLCHAIN_KEY[] = "CMAKE_CXX_COMPILER"; const char CMAKE_QMAKE_KEY[] = "QT_QMAKE_EXECUTABLE"; const char CMAKE_PREFIX_PATH_KEY[] = "CMAKE_PREFIX_PATH"; const char QTC_CMAKE_PRESET_KEY[] = "QTC_CMAKE_PRESET"; -const char QTC_KIT_DEFAULT_CONFIG_HASH[] = "QTC_KIT_DEFAULT_CONFIG_HASH"; class CMakeConfigurationKitAspectWidget final : public KitAspectWidget { @@ -1135,51 +1133,6 @@ CMakeConfigItem CMakeConfigurationKitAspect::cmakePresetConfigItem(const Project }); } -void CMakeConfigurationKitAspect::setKitDefaultConfigHash(ProjectExplorer::Kit *k) -{ - const CMakeConfig defaultConfigExpanded - = Utils::transform(defaultConfiguration(k).toList(), [k](const CMakeConfigItem &item) { - CMakeConfigItem expanded(item); - expanded.value = item.expandedValue(k).toUtf8(); - return expanded; - }); - const CMakeTool *const tool = CMakeKitAspect::cmakeTool(k); - const QByteArray kitHash = computeDefaultConfigHash(defaultConfigExpanded, - tool ? tool->cmakeExecutable() - : FilePath()); - - CMakeConfig config = configuration(k); - config.append(CMakeConfigItem(QTC_KIT_DEFAULT_CONFIG_HASH, CMakeConfigItem::INTERNAL, kitHash)); - - setConfiguration(k, config); -} - -CMakeConfigItem CMakeConfigurationKitAspect::kitDefaultConfigHashItem(const ProjectExplorer::Kit *k) -{ - const CMakeConfig config = configuration(k); - return Utils::findOrDefault(config, [](const CMakeConfigItem &item) { - return item.key == QTC_KIT_DEFAULT_CONFIG_HASH; - }); -} - -QByteArray CMakeConfigurationKitAspect::computeDefaultConfigHash(const CMakeConfig &config, - const FilePath &cmakeBinary) -{ - const CMakeConfig defaultConfig = defaultConfiguration(nullptr); - const QByteArray configValues = std::accumulate(defaultConfig.begin(), - defaultConfig.end(), - QByteArray(), - [config](QByteArray &sum, - const CMakeConfigItem &item) { - return sum += config.valueOf(item.key); - }); - return QCryptographicHash::hash(cmakeBinary.caseSensitivity() == Qt::CaseInsensitive - ? configValues.toLower() - : configValues, - QCryptographicHash::Md5) - .toHex(); -} - QVariant CMakeConfigurationKitAspect::defaultValue(const Kit *k) const { // FIXME: Convert preload scripts diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.h b/src/plugins/cmakeprojectmanager/cmakekitinformation.h index bf056f99e23..3b85235d917 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.h +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.h @@ -91,11 +91,6 @@ public: static void setCMakePreset(ProjectExplorer::Kit *k, const QString &presetName); static CMakeConfigItem cmakePresetConfigItem(const ProjectExplorer::Kit *k); - static void setKitDefaultConfigHash(ProjectExplorer::Kit *k); - static CMakeConfigItem kitDefaultConfigHashItem(const ProjectExplorer::Kit *k); - static QByteArray computeDefaultConfigHash(const CMakeConfig &config, - const Utils::FilePath &cmakeBinary); - // KitAspect interface ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const final; void setup(ProjectExplorer::Kit *k) final; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 69cdda4c526..14c4a5b817f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -46,7 +46,6 @@ struct DirectoryData QString cmakePresetDisplayname; QString cmakePreset; - QByteArray cmakePresetDefaultConfigHash; // Kit Stuff FilePath cmakeBinary; @@ -731,9 +730,6 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, // Update QT_QMAKE_EXECUTABLE and CMAKE_C|XX_COMPILER config values updateConfigWithDirectoryData(config, data); - data->cmakePresetDefaultConfigHash - = CMakeConfigurationKitAspect::computeDefaultConfigHash(config, data->cmakeBinary); - QByteArrayList buildConfigurationTypes = {cache.valueOf("CMAKE_BUILD_TYPE")}; if (buildConfigurationTypes.front().isEmpty()) { buildConfigurationTypes.clear(); @@ -862,36 +858,50 @@ bool CMakeProjectImporter::matchKit(void *directoryData, const Kit *k) const if (data->qt.qt && QtSupport::QtKitAspect::qtVersionId(k) != data->qt.qt->uniqueId()) return false; + const bool compilersMatch = [k, data] { + const QList allLanguages = ToolChainManager::allLanguages(); + for (const ToolChainDescription &tcd : data->toolChains) { + if (!Utils::contains(allLanguages, + [&tcd](const Id &language) { return language == tcd.language; })) + continue; + ToolChain *tc = ToolChainKitAspect::toolChain(k, tcd.language); + if ((!tc || !tc->matchesCompilerCommand(tcd.compilerPath))) { + return false; + } + } + return true; + }(); + const bool noCompilers = [k, data] { + const QList allLanguages = ToolChainManager::allLanguages(); + for (const ToolChainDescription &tcd : data->toolChains) { + if (!Utils::contains(allLanguages, + [&tcd](const Id &language) { return language == tcd.language; })) + continue; + ToolChain *tc = ToolChainKitAspect::toolChain(k, tcd.language); + if (tc && tc->matchesCompilerCommand(tcd.compilerPath)) { + return false; + } + } + return true; + }(); + bool haveCMakePreset = false; if (!data->cmakePreset.isEmpty()) { const auto presetConfigItem = CMakeConfigurationKitAspect::cmakePresetConfigItem(k); - const auto kitConfigHashItem = CMakeConfigurationKitAspect::kitDefaultConfigHashItem(k); const QString presetName = presetConfigItem.expandedValue(k); - const bool haveSameKitConfigHash = kitConfigHashItem.isNull() - ? true - : data->cmakePresetDefaultConfigHash - == kitConfigHashItem.value; - - if (data->cmakePreset != presetName || !haveSameKitConfigHash) + if (data->cmakePreset != presetName) return false; ensureBuildDirectory(*data, k); haveCMakePreset = true; } - const QList allLanguages = ToolChainManager::allLanguages(); - for (const ToolChainDescription &tcd : data->toolChains) { - if (!Utils::contains(allLanguages, [&tcd](const Id& language) {return language == tcd.language;})) - continue; - ToolChain *tc = ToolChainKitAspect::toolChain(k, tcd.language); - if ((!tc || !tc->matchesCompilerCommand(tcd.compilerPath)) && !haveCMakePreset) { - return false; - } - } + if (!compilersMatch && !(haveCMakePreset && noCompilers)) + return false; qCDebug(cmInputLog) << k->displayName() - << "matches directoryData for" << data->buildDirectory.toUserOutput(); + << "matches directoryData for" << data->buildDirectory.toUserOutput(); return true; } @@ -930,7 +940,6 @@ Kit *CMakeProjectImporter::createKit(void *directoryData) const QString("%1 (CMake preset)").arg(data->cmakePresetDisplayname)); CMakeConfigurationKitAspect::setCMakePreset(k, data->cmakePreset); - CMakeConfigurationKitAspect::setKitDefaultConfigHash(k); } if (!data->cmakePreset.isEmpty()) ensureBuildDirectory(*data, k); From b083a4d55efbf9f6558034c0ce4efe31062e0e5b Mon Sep 17 00:00:00 2001 From: Karim Abdelrahman Date: Wed, 5 Apr 2023 10:50:33 +0300 Subject: [PATCH 0823/1447] McuSupport: fix toolchain naming difference between windows and linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Toolchain naming convention is different in windows "mingw" than in linux "gcc". That caused the logic to fail on windows and prompt the user to remove a kit of an existing target. Task-number: QTCREATORBUG-29003 Change-Id: Ib99a9b38fec30b9a6826874f1acd0bb2f8615e1e Reviewed-by: Reviewed-by: Sivert Krøvel Reviewed-by: Alessandro Portale --- src/plugins/mcusupport/mcukitmanager.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index 61f268f0215..f68eca6973d 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -289,8 +289,7 @@ public: cMakeToolchainFile.toString().toUtf8()); if (!cMakeToolchainFile.exists()) { printMessage( - Tr::tr( - "Warning for target %1: missing CMake toolchain file expected at %2.") + Tr::tr("Warning for target %1: missing CMake toolchain file expected at %2.") .arg(generateKitNameFromTarget(mcuTarget), cMakeToolchainFile.toUserOutput()), false); @@ -301,8 +300,7 @@ public: "/lib/cmake/Qul/QulGenerators.cmake"); configMap.insert("QUL_GENERATORS", generatorsPath.toString().toUtf8()); if (!generatorsPath.exists()) { - printMessage(Tr::tr( - "Warning for target %1: missing QulGenerators expected at %2.") + printMessage(Tr::tr("Warning for target %1: missing QulGenerators expected at %2.") .arg(generateKitNameFromTarget(mcuTarget), generatorsPath.toUserOutput()), false); @@ -510,8 +508,7 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler) } case McuAbstractPackage::Status::EmptyPath: { printMessage( - Tr::tr( - "Missing %1. Add the path in Edit > Preferences > Devices > MCU.") + Tr::tr("Missing %1. Add the path in Edit > Preferences > Devices > MCU.") .arg(qtForMCUsPackage->detectionPath().toUserOutput()), true); return; @@ -524,9 +521,8 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler) if (CMakeProjectManager::CMakeToolManager::cmakeTools().isEmpty()) { printMessage( - Tr::tr( - "No CMake tool was detected. Add a CMake tool in Edit > Preferences > " - "Kits > CMake."), + Tr::tr("No CMake tool was detected. Add a CMake tool in Edit > Preferences > " + "Kits > CMake."), true); return; } @@ -744,11 +740,17 @@ static bool anyKitDescriptionFileExists(const FilePaths &jsonFiles, const QRegularExpressionMatch match = re.match(jsonFile.fileName()); QStringList kitsPropertiesFromFileName; if (match.hasMatch()) { - const QString toolchain = match.captured(1).replace( - "gnu", "gcc"); // kitFileName contains gnu while profiles.xml contains gcc + QString toolchain = match.captured(1); const QString vendor = match.captured(2); const QString device = match.captured(3); + /* + * file name of kit starts with "gnu" while in profiles.xml name of + * toolchain is "gcc" on Linux and "mingw" on Windows + */ + toolchain = HostOsInfo::isLinuxHost() ? toolchain.replace("gnu", "gcc") + : toolchain.replace("gnu", "mingw"); + kitsPropertiesFromFileName << toolchain << vendor << device; } From 8b2f9b5d9ca230f3917b303aff46372ee3bcd781 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 14:16:11 +0200 Subject: [PATCH 0824/1447] Debugger: Option pages code cosmetics Change-Id: I299b944c95bd803ed143b0c06844ed92f76f856e Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/debugger/commonoptionspage.cpp | 48 ++++++++-------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index f04eeb74b91..97e9442266e 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -15,8 +15,7 @@ using namespace Core; using namespace Debugger::Constants; using namespace Utils; -namespace Debugger { -namespace Internal { +namespace Debugger::Internal { /////////////////////////////////////////////////////////////////////// // @@ -30,6 +29,19 @@ public: explicit CommonOptionsPageWidget() { DebuggerSettings &s = *debuggerSettings(); + + setOnApply([&s] { + const bool originalPostMortem = s.registerForPostMortem->value(); + const bool currentPostMortem = s.registerForPostMortem->volatileValue().toBool(); + // explicitly trigger setValue() to override the setValueSilently() and trigger the registration + if (originalPostMortem != currentPostMortem) + s.registerForPostMortem->setValue(currentPostMortem); + s.page1.apply(); + s.page1.writeSettings(ICore::settings()); + }); + + setOnFinish([&s] { s.page1.finish(); }); + using namespace Layouting; Column col1 { @@ -60,27 +72,8 @@ public: st }.attachTo(this); } - - void apply() final; - void finish() final { m_group.finish(); } - -private: - AspectContainer &m_group = debuggerSettings()->page1; }; -void CommonOptionsPageWidget::apply() -{ - const DebuggerSettings *s = debuggerSettings(); - const bool originalPostMortem = s->registerForPostMortem->value(); - const bool currentPostMortem = s->registerForPostMortem->volatileValue().toBool(); - // explicitly trigger setValue() to override the setValueSilently() and trigger the registration - if (originalPostMortem != currentPostMortem) - s->registerForPostMortem->setValue(currentPostMortem); - - m_group.apply(); - m_group.writeSettings(ICore::settings()); -} - CommonOptionsPage::CommonOptionsPage() { setId(DEBUGGER_COMMON_SETTINGS_ID); @@ -122,8 +115,9 @@ class LocalsAndExpressionsOptionsPageWidget : public IOptionsPageWidget public: LocalsAndExpressionsOptionsPageWidget() { - using namespace Layouting; DebuggerSettings &s = *debuggerSettings(); + setOnApply([&s] { s.page4.apply(); s.page4.writeSettings(ICore::settings()); }); + setOnFinish([&s] { s.page4.finish(); }); auto label = new QLabel; //(useHelperGroup); label->setTextFormat(Qt::AutoText); @@ -134,6 +128,7 @@ public: "std::map in the "Locals" and "Expressions" views.") + "

"); + using namespace Layouting; Column left { label, s.useCodeModel, @@ -169,12 +164,6 @@ public: st }.attachTo(this); } - - void apply() final { m_group.apply(); m_group.writeSettings(ICore::settings()); } - void finish() final { m_group.finish(); } - -private: - AspectContainer &m_group = debuggerSettings()->page4; }; LocalsAndExpressionsOptionsPage::LocalsAndExpressionsOptionsPage() @@ -186,5 +175,4 @@ LocalsAndExpressionsOptionsPage::LocalsAndExpressionsOptionsPage() setWidgetCreator([] { return new LocalsAndExpressionsOptionsPageWidget; }); } -} // namespace Internal -} // namespace Debugger +} // Debugger::Internal From 328d4c72954736242138d5092980e65873a2a590 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 May 2023 07:53:28 +0200 Subject: [PATCH 0825/1447] Layouting: Code cosmetics Change-Id: I0eea49bc5c39679ca66f73616a98e91546e493c2 Reviewed-by: Christian Stenger --- src/libs/utils/layoutbuilder.cpp | 15 ++------ src/libs/utils/layoutbuilder.h | 65 ++++++++++++++------------------ 2 files changed, 32 insertions(+), 48 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 3324e9c4f6f..33046a07f7d 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -323,7 +323,7 @@ void doAddWidget(LayoutBuilder &builder, QWidget *widget) A LayoutBuilder instance is typically used locally within a function and never stored. - \sa addItem(), addItems(), addRow(), finishRow() + \sa addItem(), addItems(), addRow() */ @@ -351,24 +351,15 @@ void LayoutBuilder::addRow(const LayoutItems &items) addItems(items); } -/*! - Instructs a layout builder to finish the current row. - This is implicitly called by LayoutBuilder's destructor. - */ -void LayoutItem::finishRow() -{ - addItem(br); -} - /*! This starts a new row containing \a items. The row can be further extended by other items using \c addItem() or \c addItems(). - \sa finishRow(), addItem(), addItems() + \sa addItem(), addItems() */ void LayoutItem::addRow(const LayoutItems &items) { - finishRow(); + addItem(br); addItems(items); } diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 1a9c3439bcc..f2efeaf2fe9 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -24,48 +24,15 @@ QT_END_NAMESPACE namespace Layouting { -class LayoutBuilder; -class LayoutItem; -class Span; - -// Special items - -class QTCREATOR_UTILS_EXPORT Space -{ -public: - explicit Space(int space) : space(space) {} - const int space; -}; - -class QTCREATOR_UTILS_EXPORT Stretch -{ -public: - explicit Stretch(int stretch = 1) : stretch(stretch) {} - const int stretch; -}; - - // LayoutItem +class LayoutBuilder; +class LayoutItem; using LayoutItems = QList; -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const std::function &t); -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QWidget *t); -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QLayout *t); -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, LayoutItem(*t)()); -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const QString &t); -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Span &t); -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Space &t); -void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Stretch &t); - class QTCREATOR_UTILS_EXPORT LayoutItem { public: - enum class AlignmentType { - DefaultAlignment, - AlignAsFormLabel, - }; - using Setter = std::function; LayoutItem(); @@ -88,7 +55,6 @@ public: void addItem(const LayoutItem &item); void addItems(const LayoutItems &items); void addRow(const LayoutItems &items); - void finishRow(); std::function onAdd; std::function onExit; @@ -96,6 +62,22 @@ public: LayoutItems subItems; }; +// Special items + +class QTCREATOR_UTILS_EXPORT Space +{ +public: + explicit Space(int space) : space(space) {} + const int space; +}; + +class QTCREATOR_UTILS_EXPORT Stretch +{ +public: + explicit Stretch(int stretch = 1) : stretch(stretch) {} + const int stretch; +}; + class QTCREATOR_UTILS_EXPORT Span { public: @@ -181,6 +163,17 @@ public: int exec(int &argc, char *argv[]); }; + +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const std::function &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QWidget *t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QLayout *t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, LayoutItem(*t)()); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const QString &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Span &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Space &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Stretch &t); + + // "Singletons" QTCREATOR_UTILS_EXPORT LayoutItem br(); From 15193d3250834f85d90b790c0c40632e6de65033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20K=C3=B6hne?= Date: Tue, 18 Apr 2023 12:55:51 +0200 Subject: [PATCH 0826/1447] Simplify generated CMakeLists.txt Fixes: QDS-9700 Change-Id: I2376e3938fb6f95d2cc53ad96b40c04ac7ce780e Reviewed-by: Reviewed-by: Alessandro Portale Reviewed-by: Cristian Adam --- .../projects/common/CMakeLists.main.txt.tpl | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl index a76765daee9..18aec1a93e2 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl @@ -1,46 +1,40 @@ cmake_minimum_required(VERSION 3.21.1) -set(BUILD_QDS_COMPONENTS ON CACHE BOOL "Build design studio components") +option(BUILD_QDS_COMPONENTS "Build design studio components" ON) project(%{ProjectName}App LANGUAGES CXX) -set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) -find_package(QT NAMES Qt6 COMPONENTS Gui Qml Quick) -find_package(Qt6 REQUIRED COMPONENTS Core Qml Quick) +find_package(Qt6 6.2 REQUIRED COMPONENTS Core Gui Qml Quick) -# To build this application you need Qt 6.2.0 or higher -if (Qt6_VERSION VERSION_LESS 6.2.0) -message(FATAL_ERROR "You need Qt 6.2.0 or newer to build the application.") +if (Qt6_VERSION VERSION_GREATER_EQUAL 6.3) + qt_standard_project_setup() endif() -qt_add_executable(${CMAKE_PROJECT_NAME} src/main.cpp) +qt_add_executable(%{ProjectName}App src/main.cpp) -# qt_standard_project_setup() requires Qt 6.3 or higher. See https://doc.qt.io/qt-6/qt-standard-project-setup.html for details. -if (${QT_VERSION_MINOR} GREATER_EQUAL 3) -qt6_standard_project_setup() -endif() - -qt_add_resources(${CMAKE_PROJECT_NAME} "configuration" +qt_add_resources(%{ProjectName}App "configuration" PREFIX "/" FILES qtquickcontrols2.conf ) -target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Gui - Qt${QT_VERSION_MAJOR}::Quick - Qt${QT_VERSION_MAJOR}::Qml +target_link_libraries(%{ProjectName}App PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Qml + Qt6::Quick ) -if (${BUILD_QDS_COMPONENTS}) +if (BUILD_QDS_COMPONENTS) include(${CMAKE_CURRENT_SOURCE_DIR}/qmlcomponents) -endif () +endif() include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules) -install(TARGETS ${CMAKE_PROJECT_NAME} +install(TARGETS %{ProjectName}App BUNDLE DESTINATION . - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) From 84b2862058e477736bc0b96b05e882ab00f5b407 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 4 May 2023 09:49:32 +0200 Subject: [PATCH 0827/1447] Utils: Improve CheckBox layouting This is not correct either, but the vast majority of Checkboxes is not added to Forms, so the !form case is a better fallback. Change-Id: I1375b3e23138fb6d881b2331ecf1d0f3a4f5431b Reviewed-by: hjk --- src/libs/utils/aspects.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 94aee75214c..dc1888279ab 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1406,8 +1406,9 @@ void BoolAspect::addToLayout(Layouting::LayoutItem &parent) break; case LabelPlacement::AtCheckBox: { d->m_checkBox->setText(labelText()); -// if (parent.isForm()) FIXME - parent.addItem(createSubWidget()); + // FIXME: + //if (parent.isForm()) + // parent.addItem(createSubWidget()); parent.addItem(d->m_checkBox.data()); break; } From f4abb1ec4a63411cfcaec1d299a8f5603d63395b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 5 May 2023 10:02:02 +0200 Subject: [PATCH 0828/1447] Terminal: Remove unnecessary destructor Calling Aggregate::remove is not necessary and led to a warning message. Change-Id: I51cdd7bfa9bdda7a3ebedf6a86e48fe54fd8f3ef Reviewed-by: Eike Ziller --- src/plugins/terminal/terminalwidget.cpp | 7 ------- src/plugins/terminal/terminalwidget.h | 1 - 2 files changed, 8 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 11397d87b47..b6e48165f39 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -128,13 +128,6 @@ TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &op m_aggregate->add(m_search.get()); } -TerminalWidget::~TerminalWidget() -{ - // The Aggregate stuff tries to do clever deletion of the children, but we - // we don't want that. - m_aggregate->remove(this); -} - void TerminalWidget::setupPty() { m_process = std::make_unique(); diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index 4f56f39efe4..f44a721bd31 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -29,7 +29,6 @@ class TerminalWidget : public QAbstractScrollArea public: TerminalWidget(QWidget *parent = nullptr, const Utils::Terminal::OpenTerminalParameters &openParameters = {}); - ~TerminalWidget() override; void setFont(const QFont &font); From 8d03220017bf7e5c7be51fc36acb56fbde9e3e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Wed, 3 May 2023 23:49:59 +0200 Subject: [PATCH 0829/1447] SquishTests: Improve log messages of exceptions ...and make them more similar to Squish's own "Error" messages. Change-Id: If5df701d4fa01fc1c1aea94cc9778a6a5dccc44e Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/shared/build_utils.py | 2 +- tests/system/shared/clang.py | 2 +- tests/system/shared/editor_utils.py | 4 ++-- tests/system/shared/fs_utils.py | 2 +- tests/system/shared/project.py | 4 ++-- tests/system/shared/utils.py | 4 ++-- tests/system/suite_HELP/tst_HELP02/test.py | 2 +- tests/system/suite_tools/tst_codepasting/test.py | 6 +++--- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index 74063c72f9f..9f9608a0c06 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -21,7 +21,7 @@ def toggleIssuesFilter(filterName, checked): except: t,v = sys.exc_info()[:2] test.log("Exception while toggling filter '%s'" % filterName, - "%s(%s)" % (str(t), str(v))) + "%s: %s" % (t.__name__, str(v))) def getBuildIssues(ignoreCodeModel=True): diff --git a/tests/system/shared/clang.py b/tests/system/shared/clang.py index 1753d8e724a..812ead3e6a5 100644 --- a/tests/system/shared/clang.py +++ b/tests/system/shared/clang.py @@ -16,7 +16,7 @@ def startCreatorVerifyingClang(useClang): if strv == "startApplication() failed": test.fatal("%s. Creator built without ClangCodeModel?" % strv) else: - test.fatal("Exception caught", "%s(%s)" % (str(t), strv)) + test.fatal("Exception caught", "%s: %s" % (t.__name__, strv)) return False if platform.system() not in ('Microsoft', 'Windows'): # only Win uses dialogs for this return startedWithoutPluginError() diff --git a/tests/system/shared/editor_utils.py b/tests/system/shared/editor_utils.py index c1df47ac3e6..de5619472e7 100644 --- a/tests/system/shared/editor_utils.py +++ b/tests/system/shared/editor_utils.py @@ -67,7 +67,7 @@ def menuVisibleAtEditor(editor, menuInList): return success except: t, v = sys.exc_info()[:2] - test.log("Exception: %s" % str(t), str(v)) + test.log("Exception: %s" % t.__name__, str(v)) return False # this function checks whether the given global point (QPoint) @@ -413,7 +413,7 @@ def openDocument(treeElement): return False except: t,v = sys.exc_info()[:2] - test.log("An exception occurred in openDocument(): %s(%s)" % (str(t), str(v))) + test.log("An exception occurred in openDocument(): %s: %s" % (t.__name__, str(v))) return False def earlyExit(details="No additional information"): diff --git a/tests/system/shared/fs_utils.py b/tests/system/shared/fs_utils.py index 1bcc3c81850..af76c7c8125 100644 --- a/tests/system/shared/fs_utils.py +++ b/tests/system/shared/fs_utils.py @@ -30,7 +30,7 @@ def changeFilePermissions(dirPath, readPerm, writePerm, excludeFileNames=None): os.chmod(filePath, permission) except: t,v = sys.exc_info()[:2] - test.log("Error: %s(%s)" % (str(t), str(v))) + test.log("%s: %s" % (t.__name__, str(v))) result = False return result diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index babbf0eb6ea..7b58b95c9f6 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -120,7 +120,7 @@ def __handleBuildSystem__(buildSystem): selectFromCombo(combo, buildSystem) except: t, v = sys.exc_info()[:2] - test.warning("Exception while handling build system", "%s(%s)" % (str(t), str(v))) + test.warning("Exception while handling build system", "%s: %s" % (t.__name__, str(v))) clickButton(waitForObject(":Next_QPushButton")) return buildSystem @@ -131,7 +131,7 @@ def __createProjectHandleQtQuickSelection__(minimumQtVersion): selectFromCombo(comboBox, minimumQtVersion) except: t,v = sys.exc_info()[:2] - test.fatal("Exception while trying to select Qt version", "%s (%s)" % (str(t), str(v))) + test.fatal("Exception while trying to select Qt version", "%s :%s" % (t.__name__, str(v))) clickButton(waitForObject(":Next_QPushButton")) return minimumQtVersion diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py index 96e63f29f05..aa70220407a 100644 --- a/tests/system/shared/utils.py +++ b/tests/system/shared/utils.py @@ -436,8 +436,8 @@ def iterateKits(clickOkWhenDone, alreadyOnOptionsDialog, t, v, _ = sys.exc_info() currResult = None test.fatal("Function to additionally execute on Options Dialog could not be " - "found or an exception occurred while executing it.", "%s(%s)" % - (str(t), str(v))) + "found or an exception occurred while executing it.", "%s: %s" % + (t.__name__, str(v))) additionalResult.append(currResult) if clickOkWhenDone: clickButton(waitForObject(":Options.OK_QPushButton")) diff --git a/tests/system/suite_HELP/tst_HELP02/test.py b/tests/system/suite_HELP/tst_HELP02/test.py index 0f8ff6767b0..3601c81a37b 100644 --- a/tests/system/suite_HELP/tst_HELP02/test.py +++ b/tests/system/suite_HELP/tst_HELP02/test.py @@ -41,7 +41,7 @@ def checkQtCreatorHelpVersion(expectedVersion): 'Verifying whether manual uses expected version.') except: t, v = sys.exc_info()[:2] - test.log("Exception caught", "%s(%s)" % (str(t), str(v))) + test.log("Exception caught", "%s: %s" % (t.__name__, str(v))) test.fail("Missing Qt Creator Manual.") diff --git a/tests/system/suite_tools/tst_codepasting/test.py b/tests/system/suite_tools/tst_codepasting/test.py index 5db5a28c901..3d4507095f0 100644 --- a/tests/system/suite_tools/tst_codepasting/test.py +++ b/tests/system/suite_tools/tst_codepasting/test.py @@ -34,8 +34,8 @@ def closeHTTPStatusAndPasterDialog(protocol, pasterDialog): test.log("Closed dialog without expected error.", text) except: t,v = sys.exc_info()[:2] - test.warning("An exception occurred in closeHTTPStatusAndPasterDialog(): %s(%s)" - % (str(t), str(v))) + test.warning("An exception occurred in closeHTTPStatusAndPasterDialog(): %s: %s" + % (t.__name__, str(v))) return False def pasteFile(sourceFile, protocol): @@ -167,7 +167,7 @@ def checkForMovedUrl(): # protocol may be redirected (HTTP status 30x) - check test.fail("URL has moved permanently.", match[0].group(0)) except: t,v,tb = sys.exc_info() - test.log(str(t), str(v)) + test.log("%s: %s" % (t.__name__, str(v))) def main(): startQC() From 200d3b455b086858dc0cc9e847a7b0636454e5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Thu, 4 May 2023 22:21:06 +0200 Subject: [PATCH 0830/1447] SquishTests: Don't test.verify state of checkbox in getBuildIssues - It generates a ridiculously large number of test results in comparison to what's actually tested - In tst_memberoperator, it is used in waitFor(). Thus, it depends on timing and the number of test results varies from one execution to another Change-Id: I7d4ad8f87590b4fc2dda51e9eda703961c7acd9e Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/shared/build_utils.py | 2 +- tests/system/shared/utils.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index 9f9608a0c06..dd7677d4730 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -25,7 +25,7 @@ def toggleIssuesFilter(filterName, checked): def getBuildIssues(ignoreCodeModel=True): - ensureChecked(":Qt Creator_Issues_Core::Internal::OutputPaneToggleButton") + ensureChecked(":Qt Creator_Issues_Core::Internal::OutputPaneToggleButton" , silent=True) model = waitForObject(":Qt Creator.Issues_QListView").model() if ignoreCodeModel: # filter out possible code model issues present inside the Issues pane diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py index aa70220407a..9b4f2dc95a3 100644 --- a/tests/system/shared/utils.py +++ b/tests/system/shared/utils.py @@ -25,7 +25,8 @@ def verifyChecked(objectName, checked=True): test.compare(object.checked, checked) return object -def ensureChecked(objectName, shouldBeChecked = True, timeout=20000): + +def ensureChecked(objectName, shouldBeChecked=True, timeout=20000, silent=False): if shouldBeChecked: targetState = Qt.Checked state = "checked" @@ -39,14 +40,13 @@ def ensureChecked(objectName, shouldBeChecked = True, timeout=20000): while not waitFor('widget.checkState() == targetState', 1500) and clicked < 2: clickButton(widget) clicked += 1 - test.verify(waitFor("widget.checkState() == targetState", 1000)) + silent or test.verify(waitFor("widget.checkState() == targetState", 1000)) except: # widgets not derived from QCheckbox don't have checkState() if not waitFor('widget.checked == shouldBeChecked', 1500): mouseClick(widget) - test.verify(waitFor("widget.checked == shouldBeChecked", 1000)) - test.log("New state for QCheckBox: %s" % state, - str(objectName)) + silent or test.verify(waitFor("widget.checked == shouldBeChecked", 1000)) + silent or test.log("New state for QCheckBox: %s" % state, str(objectName)) return widget # verify that an object is in an expected enable state. Returns the object. From 845192eb1433de9eb2953ef968dd8c4ba3e2ba7d Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 5 May 2023 09:55:38 +0200 Subject: [PATCH 0831/1447] Terminal: Fix strings Change-Id: I573d642084d3cc26e032c43d6fb7c1fdd2594d4d Reviewed-by: Leena Miettinen --- src/plugins/terminal/terminalsettings.cpp | 6 +++--- src/plugins/terminal/terminalsettingspage.cpp | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 1f548a65fae..e2d2150cd72 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -70,7 +70,7 @@ TerminalSettings::TerminalSettings() setSettingsGroup("Terminal"); enableTerminal.setSettingsKey("EnableTerminal"); - enableTerminal.setLabelText(Tr::tr("Use internal Terminal")); + enableTerminal.setLabelText(Tr::tr("Use internal terminal")); enableTerminal.setToolTip( Tr::tr("If enabled, use the internal terminal when \"Run In Terminal\" is " "enabled and for \"Open Terminal here\".")); @@ -98,14 +98,14 @@ TerminalSettings::TerminalSettings() shell.setExpectedKind(PathChooser::ExistingCommand); shell.setDisplayStyle(StringAspect::PathChooserDisplay); shell.setHistoryCompleter("Terminal.Shell.History"); - shell.setToolTip(Tr::tr("The shell executable to be started as terminal")); + shell.setToolTip(Tr::tr("The shell executable to be started.")); shell.setDefaultValue(defaultShell()); shellArguments.setSettingsKey("ShellArguments"); shellArguments.setLabelText(Tr::tr("Shell arguments:")); shellArguments.setDisplayStyle(StringAspect::LineEditDisplay); shellArguments.setHistoryCompleter("Terminal.Shell.History"); - shellArguments.setToolTip(Tr::tr("The arguments to be passed to the shell")); + shellArguments.setToolTip(Tr::tr("The arguments to be passed to the shell.")); if (!HostOsInfo::isWindowsHost()) shellArguments.setDefaultValue(QString("-l")); diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index d0e7b4bab53..d993a49f472 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -326,7 +326,7 @@ public: TerminalSettings &settings = TerminalSettings::instance(); QPushButton *loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); - QPushButton *resetTheme = new QPushButton(Tr::tr("Reset Theme to default")); + QPushButton *resetTheme = new QPushButton(Tr::tr("Reset Theme")); connect(loadThemeButton, &QPushButton::clicked, this, [this] { const FilePath path = FileUtils::getOpenFilePath( @@ -412,9 +412,12 @@ public: } }, }, - Column { - settings.shell, - settings.shellArguments, + Group { + title(Tr::tr("Default Shell")), + Column { + settings.shell, + settings.shellArguments, + }, }, st, }.attachTo(this); From 2d8fd4f0175061bfc0ae8c21211968bbfef33c9b Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 May 2023 17:08:51 +0200 Subject: [PATCH 0832/1447] Nim: Remove now-unnecessary function reimplementations Change-Id: Ie271499cb99766fd48b77ce66f2d42d898a8e115 Reviewed-by: Alessandro Portale --- src/plugins/nim/settings/nimcodestylesettingspage.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/nim/settings/nimcodestylesettingspage.cpp b/src/plugins/nim/settings/nimcodestylesettingspage.cpp index ae26a14208a..56919a6c156 100644 --- a/src/plugins/nim/settings/nimcodestylesettingspage.cpp +++ b/src/plugins/nim/settings/nimcodestylesettingspage.cpp @@ -39,9 +39,6 @@ public: } private: - void apply() final {} - void finish() final {} - TextEditor::SimpleCodeStylePreferences *m_nimCodeStylePreferences; }; From 2e9494bd714e91305d6d05ef2c5c4b476cd5eed3 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 21 Apr 2023 14:45:54 +0200 Subject: [PATCH 0833/1447] Core: Add "Toolbar Style" ComboBox to General settings Stores the style as int under General/ToolbarStyle. ManhattanStyle restores the setting on contruction, just in time before widgets get "QStyle::polished". Task-number: QTCREATORBUG-29054 Change-Id: Ifea953261eab0d42e35a128e2f3338fbbef06a88 Reviewed-by: Marcus Tillmanns Reviewed-by: hjk --- src/plugins/coreplugin/generalsettings.cpp | 43 ++++++++++++++++++++++ src/plugins/coreplugin/generalsettings.h | 2 + src/plugins/coreplugin/manhattanstyle.cpp | 3 ++ 3 files changed, 48 insertions(+) diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp index e12cb1ccc2c..e97797c9fc7 100644 --- a/src/plugins/coreplugin/generalsettings.cpp +++ b/src/plugins/coreplugin/generalsettings.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include #include @@ -17,6 +19,7 @@ #include #include +#include #include #include #include @@ -38,6 +41,7 @@ namespace Internal { const char settingsKeyDPI[] = "Core/EnableHighDpiScaling"; const char settingsKeyShortcutsInContextMenu[] = "General/ShowShortcutsInContextMenu"; const char settingsKeyCodecForLocale[] = "General/OverrideCodecForLocale"; +const char settingsKeyToolbarStyle[] = "General/ToolbarStyle"; class GeneralSettingsWidget final : public IOptionsPageWidget { @@ -57,6 +61,7 @@ public: void fillCodecBox() const; static QByteArray codecForLocale(); static void setCodecForLocale(const QByteArray&); + void fillToolbarSyleBox() const; GeneralSettings *q; QComboBox *m_languageBox; @@ -65,6 +70,7 @@ public: QtColorButton *m_colorButton; ThemeChooser *m_themeChooser; QPushButton *m_resetWarningsButton; + QComboBox *m_toolbarStyleBox; }; GeneralSettingsWidget::GeneralSettingsWidget(GeneralSettings *q) @@ -75,6 +81,7 @@ GeneralSettingsWidget::GeneralSettingsWidget(GeneralSettings *q) , m_colorButton(new QtColorButton) , m_themeChooser(new ThemeChooser) , m_resetWarningsButton(new QPushButton) + , m_toolbarStyleBox(new QComboBox) { m_languageBox->setObjectName("languageBox"); m_languageBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); @@ -92,6 +99,8 @@ GeneralSettingsWidget::GeneralSettingsWidget(GeneralSettings *q) "Show Again\" (for example, missing highlighter).", nullptr)); + m_toolbarStyleBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + auto resetColorButton = new QPushButton(Tr::tr("Reset")); resetColorButton->setToolTip(Tr::tr("Reset to default.", "Color")); @@ -116,10 +125,12 @@ GeneralSettingsWidget::GeneralSettingsWidget(GeneralSettings *q) form.addRow({empty, m_showShortcutsInContextMenus}); form.addRow({Row{m_resetWarningsButton, st}}); form.addRow({Tr::tr("Text codec for tools:"), m_codecBox, st}); + form.addRow({Tr::tr("Toolbar Style:"), m_toolbarStyleBox, st}); Column{Group{title(Tr::tr("User Interface")), form}}.attachTo(this); fillLanguageBox(); fillCodecBox(); + fillToolbarSyleBox(); m_colorButton->setColor(StyleHelper::requestedBaseColor()); m_resetWarningsButton->setEnabled(canResetWarnings()); @@ -188,6 +199,15 @@ void GeneralSettingsWidget::apply() // Apply the new base color if accepted StyleHelper::setBaseColor(m_colorButton->color()); m_themeChooser->apply(); + if (const auto newStyle = m_toolbarStyleBox->currentData().value(); + newStyle != StyleHelper::toolbarStyle()) { + ICore::settings()->setValueWithDefault(settingsKeyToolbarStyle, int(newStyle), + int(StyleHelper::defaultToolbarStyle)); + StyleHelper::setToolbarStyle(newStyle); + QStyle *applicationStyle = QApplication::style(); + for (QWidget *widget : QApplication::allWidgets()) + applicationStyle->polish(widget); + } } bool GeneralSettings::showShortcutsInContextMenu() @@ -268,6 +288,24 @@ void GeneralSettingsWidget::setCodecForLocale(const QByteArray &codec) QTextCodec::setCodecForLocale(QTextCodec::codecForName(codec)); } +StyleHelper::ToolbarStyle toolbarStylefromSettings() +{ + if (!ExtensionSystem::PluginManager::instance()) // May happen in tests + return StyleHelper::defaultToolbarStyle; + + return StyleHelper::ToolbarStyle( + ICore::settings()->value(settingsKeyToolbarStyle, + StyleHelper::defaultToolbarStyle).toInt()); +} + +void GeneralSettingsWidget::fillToolbarSyleBox() const +{ + m_toolbarStyleBox->addItem(Tr::tr("Compact"), StyleHelper::ToolbarStyleCompact); + m_toolbarStyleBox->addItem(Tr::tr("Relaxed"), StyleHelper::ToolbarStyleRelaxed); + const int curId = m_toolbarStyleBox->findData(toolbarStylefromSettings()); + m_toolbarStyleBox->setCurrentIndex(curId); +} + void GeneralSettings::setShowShortcutsInContextMenu(bool show) { ICore::settings()->setValueWithDefault(settingsKeyShortcutsInContextMenu, @@ -276,6 +314,11 @@ void GeneralSettings::setShowShortcutsInContextMenu(bool show) QCoreApplication::setAttribute(Qt::AA_DontShowShortcutsInContextMenus, !show); } +void GeneralSettings::applyToolbarStyleFromSettings() +{ + StyleHelper::setToolbarStyle(toolbarStylefromSettings()); +} + GeneralSettings::GeneralSettings() { setId(Constants::SETTINGS_ID_INTERFACE); diff --git a/src/plugins/coreplugin/generalsettings.h b/src/plugins/coreplugin/generalsettings.h index 78d1dab2702..4587443eaca 100644 --- a/src/plugins/coreplugin/generalsettings.h +++ b/src/plugins/coreplugin/generalsettings.h @@ -16,6 +16,8 @@ public: static bool showShortcutsInContextMenu(); void setShowShortcutsInContextMenu(bool show); + static void applyToolbarStyleFromSettings(); + private: friend class GeneralSettingsWidget; bool m_defaultShowShortcutsInContextMenu; diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 016185b1c3a..b8f24e6f709 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -3,6 +3,8 @@ #include "manhattanstyle.h" +#include "generalsettings.h" + #include #include #include @@ -390,6 +392,7 @@ ManhattanStyle::ManhattanStyle(const QString &baseStyleName) : QProxyStyle(QStyleFactory::create(baseStyleName)), d(new ManhattanStylePrivate()) { + Core::Internal::GeneralSettings::applyToolbarStyleFromSettings(); } ManhattanStyle::~ManhattanStyle() From 495f5f006f3fe14c7b472ee6a29925c0aa4c640c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 14 Apr 2023 15:43:31 +0200 Subject: [PATCH 0834/1447] Utils: Add toolbarStyle to StyleHelper Task-number: QTCREATORBUG-29054 Change-Id: I01572eb7bdd267ea6aadb9530afc52b3c7834382 Reviewed-by: hjk --- src/libs/utils/stylehelper.cpp | 16 ++++++++++++++++ src/libs/utils/stylehelper.h | 11 ++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index f27fb2f8fcb..690c04b9df0 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -58,6 +58,21 @@ QColor StyleHelper::alphaBlendedColors(const QColor &colorA, const QColor &color ); } +int StyleHelper::navigationWidgetHeight() +{ + return m_toolbarStyle == ToolbarStyleCompact ? 24 : 30; +} + +void StyleHelper::setToolbarStyle(ToolbarStyle style) +{ + m_toolbarStyle = style; +} + +StyleHelper::ToolbarStyle StyleHelper::toolbarStyle() +{ + return m_toolbarStyle; +} + qreal StyleHelper::sidebarFontSize() { return HostOsInfo::isMacHost() ? 10 : 7.5; @@ -89,6 +104,7 @@ QColor StyleHelper::panelTextColor(bool lightColored) return Qt::black; } +StyleHelper::ToolbarStyle StyleHelper::m_toolbarStyle = StyleHelper::defaultToolbarStyle; // Invalid by default, setBaseColor needs to be called at least once QColor StyleHelper::m_baseColor; QColor StyleHelper::m_requestedBaseColor; diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h index c7766b0ffeb..11fa8a03890 100644 --- a/src/libs/utils/stylehelper.h +++ b/src/libs/utils/stylehelper.h @@ -25,8 +25,16 @@ public: static const unsigned int DEFAULT_BASE_COLOR = 0x666666; static const int progressFadeAnimationDuration = 600; + enum ToolbarStyle { + ToolbarStyleCompact, + ToolbarStyleRelaxed, + }; + // Height of the project explorer navigation bar - static int navigationWidgetHeight() { return 24; } + static int navigationWidgetHeight(); + static void setToolbarStyle(ToolbarStyle style); + static ToolbarStyle toolbarStyle(); + static constexpr ToolbarStyle defaultToolbarStyle = ToolbarStyleCompact; static qreal sidebarFontSize(); static QPalette sidebarFontPalette(const QPalette &original); @@ -122,6 +130,7 @@ public: static QColor ensureReadableOn(const QColor &background, const QColor &desiredForeground); private: + static ToolbarStyle m_toolbarStyle; static QColor m_baseColor; static QColor m_requestedBaseColor; }; From 02637390fa48e69ba5e078cd053bb96484308bef Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 21 Apr 2023 14:49:26 +0200 Subject: [PATCH 0835/1447] ManhattanStyle: Draw round rectangles in "Relaxed toolbar style" Task-number: QTCREATORBUG-29054 Change-Id: Ic06ddfec87fd9b43c88b3a7dfb9946c3a8b22c60 Reviewed-by: Reviewed-by: hjk --- src/libs/utils/stylehelper.cpp | 17 ++++++++++++++ src/libs/utils/stylehelper.h | 2 ++ src/plugins/coreplugin/manhattanstyle.cpp | 24 ++++++++++++-------- src/plugins/coreplugin/outputpanemanager.cpp | 16 +++++++++---- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index 690c04b9df0..38a1b179319 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -455,6 +456,22 @@ void StyleHelper::drawMinimalArrow(QStyle::PrimitiveElement element, QPainter *p painter->drawPixmap(xOffset, yOffset, pixmap); } +void StyleHelper::drawPanelBgRect(QPainter *painter, const QRectF &rect, const QBrush &brush) +{ + if (toolbarStyle() == ToolbarStyleCompact) { + painter->fillRect(rect.toRect(), brush); + } else { + constexpr int margin = 2; + constexpr int radius = 5; + QPainterPath path; + path.addRoundedRect(rect.adjusted(margin, margin, -margin, -margin), radius, radius); + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->fillPath(path, brush); + painter->restore(); + } +} + void StyleHelper::menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect) { if (StyleHelper::usePixmapCache()) { diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h index 11fa8a03890..8ee91978b7e 100644 --- a/src/libs/utils/stylehelper.h +++ b/src/libs/utils/stylehelper.h @@ -65,6 +65,8 @@ public: static void drawArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option); static void drawMinimalArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option); + static void drawPanelBgRect(QPainter *painter, const QRectF &rect, const QBrush &brush); + // Gradients used for panels static void horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false); static void verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false); diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index b8f24e6f709..59d633ee0fc 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -655,9 +655,15 @@ void ManhattanStyle::polish(QWidget *widget) widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); // So that text isn't cutoff in line-edits, comboboxes... etc. const int height = qMax(StyleHelper::navigationWidgetHeight(), QApplication::fontMetrics().height()); - if (qobject_cast(widget) || qobject_cast(widget)) { + if (qobject_cast(widget)) { + widget->setMinimumWidth( + StyleHelper::toolbarStyle() == StyleHelper::ToolbarStyleCompact ? 24 : 28); widget->setAttribute(Qt::WA_Hover); widget->setMaximumHeight(height - 2); + } else if (qobject_cast(widget)) { + widget->setAttribute(Qt::WA_Hover); + widget->setFixedHeight(height - (StyleHelper::toolbarStyle() + == StyleHelper::ToolbarStyleCompact ? 1 : 3)); } else if (qobject_cast(widget) || qobject_cast(widget) || qobject_cast(widget)) { widget->setPalette(panelPalette(widget->palette(), lightColored(widget))); @@ -1046,22 +1052,22 @@ void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element, if (!animating && anim) { anim->paint(painter, option); } else { - bool pressed = option->state & State_Sunken || option->state & State_On; + const bool pressed = option->state & State_Sunken || option->state & State_On + || (widget && widget->property("highlightWidget").toBool()); painter->setPen(StyleHelper::sidebarShadow()); if (pressed) { - const QColor shade = creatorTheme()->color(Theme::FancyToolButtonSelectedColor); - painter->fillRect(rect, shade); - if (!creatorTheme()->flag(Theme::FlatToolBars)) { + StyleHelper::drawPanelBgRect( + painter, rect, creatorTheme()->color(Theme::FancyToolButtonSelectedColor)); + if (StyleHelper::toolbarStyle() == StyleHelper::ToolbarStyleCompact + && !creatorTheme()->flag(Theme::FlatToolBars)) { const QRectF borderRect = QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5); painter->drawLine(borderRect.topLeft() + QPointF(1, 0), borderRect.topRight() - QPointF(1, 0)); painter->drawLine(borderRect.topLeft(), borderRect.bottomLeft()); painter->drawLine(borderRect.topRight(), borderRect.bottomRight()); } } else if (option->state & State_Enabled && option->state & State_MouseOver) { - painter->fillRect(rect, creatorTheme()->color(Theme::FancyToolButtonHoverColor)); - } else if (widget && widget->property("highlightWidget").toBool()) { - QColor shade(0, 0, 0, 128); - painter->fillRect(rect, shade); + StyleHelper::drawPanelBgRect( + painter, rect, creatorTheme()->color(Theme::FancyToolButtonHoverColor)); } if (option->state & State_HasFocus && (option->state & State_KeyboardFocusChange)) { QColor highlight = option->palette.highlight().color(); diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index a249686f9e8..2e2da0d4bc0 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -803,6 +803,13 @@ QSize OutputPaneToggleButton::sizeHint() const return s; } +static QRect bgRect(const QRect &widgetRect) +{ + // Removes/compensates the left and right margins of StyleHelper::drawPanelBgRect + return StyleHelper::toolbarStyle() == StyleHelper::ToolbarStyleCompact + ? widgetRect : widgetRect.adjusted(-2, 0, 2, 0); +} + void OutputPaneToggleButton::paintEvent(QPaintEvent*) { const QFontMetrics fm = fontMetrics(); @@ -824,7 +831,7 @@ void OutputPaneToggleButton::paintEvent(QPaintEvent*) c = Theme::BackgroundColorSelected; if (c != Theme::BackgroundColorDark) - p.fillRect(rect(), creatorTheme()->color(c)); + StyleHelper::drawPanelBgRect(&p, bgRect(rect()), creatorTheme()->color(c)); } else { const QImage *image = nullptr; if (isDown()) { @@ -860,9 +867,10 @@ void OutputPaneToggleButton::paintEvent(QPaintEvent*) { QColor c = creatorTheme()->color(Theme::OutputPaneButtonFlashColor); c.setAlpha (m_flashTimer->currentFrame()); - QRect r = creatorTheme()->flag(Theme::FlatToolBars) - ? rect() : rect().adjusted(numberAreaWidth(), 1, -1, -1); - p.fillRect(r, c); + if (creatorTheme()->flag(Theme::FlatToolBars)) + StyleHelper::drawPanelBgRect(&p, bgRect(rect()), c); + else + p.fillRect(rect().adjusted(numberAreaWidth(), 1, -1, -1), c); } p.setFont(font()); From 0430aaeac8c68e3cec1d3abe31016ce97f847d87 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 21 Apr 2023 14:50:00 +0200 Subject: [PATCH 0836/1447] Core: Center the arrows on the OutputPaneManageButton Calculate the positions, instead of fixed coordinates. Task-number: QTCREATORBUG-29082 Change-Id: Iaf7ac9598bfd031a62222520be16d24652e2798c Reviewed-by: Reviewed-by: hjk --- src/plugins/coreplugin/outputpanemanager.cpp | 12 ++++-------- src/plugins/coreplugin/outputpanemanager.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 2e2da0d4bc0..906a940a40d 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -930,13 +930,7 @@ OutputPaneManageButton::OutputPaneManageButton() { setFocusPolicy(Qt::NoFocus); setCheckable(true); - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); -} - -QSize OutputPaneManageButton::sizeHint() const -{ - ensurePolished(); - return QSize(numberAreaWidth(), 16); + setFixedWidth(StyleHelper::toolbarStyle() == Utils::StyleHelper::ToolbarStyleCompact ? 17 : 21); } void OutputPaneManageButton::paintEvent(QPaintEvent*) @@ -949,7 +943,9 @@ void OutputPaneManageButton::paintEvent(QPaintEvent*) QStyle *s = style(); QStyleOption arrowOpt; arrowOpt.initFrom(this); - arrowOpt.rect = QRect(6, rect().center().y() - 3, 8, 8); + constexpr int arrowSize = 8; + arrowOpt.rect = QRect(0, 0, arrowSize, arrowSize); + arrowOpt.rect.moveCenter(rect().center()); arrowOpt.rect.translate(0, -3); s->drawPrimitive(QStyle::PE_IndicatorArrowUp, &arrowOpt, &p, this); arrowOpt.rect.translate(0, 6); diff --git a/src/plugins/coreplugin/outputpanemanager.h b/src/plugins/coreplugin/outputpanemanager.h index aa3a550a28e..7dc7085d534 100644 --- a/src/plugins/coreplugin/outputpanemanager.h +++ b/src/plugins/coreplugin/outputpanemanager.h @@ -134,7 +134,6 @@ class OutputPaneManageButton : public QToolButton Q_OBJECT public: OutputPaneManageButton(); - QSize sizeHint() const override; void paintEvent(QPaintEvent*) override; }; From 09a58ddd12b60455a4e3b28fd7e5091176b71892 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 24 Apr 2023 18:24:11 +0200 Subject: [PATCH 0837/1447] Tracing: Follow the active toolbar style This makes sure that the toolbar and toolbuttons in the trace resemble the look of the widget based UI in compact and relaxed toolbar style. This comes with the restriction that an already open tracing scene does only adapt to that change after an IDE restart. Task-number: QTCREATORBUG-29082 Change-Id: I6422227256d8e13658ff5565ae640e15c5e61229 Reviewed-by: hjk --- src/libs/tracing/qml/ImageToolButton.qml | 6 ++++-- src/libs/tracing/qml/MainView.qml | 2 +- src/libs/tracing/qml/RangeDetails.qml | 2 +- src/libs/tracing/qml/TimeDisplay.qml | 2 +- src/libs/tracing/timelinetheme.cpp | 13 ++++++++++++- src/libs/tracing/timelinetheme.h | 2 ++ 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/libs/tracing/qml/ImageToolButton.qml b/src/libs/tracing/qml/ImageToolButton.qml index 2d0231494bc..45ca12b8997 100644 --- a/src/libs/tracing/qml/ImageToolButton.qml +++ b/src/libs/tracing/qml/ImageToolButton.qml @@ -22,10 +22,12 @@ ToolButton { smooth: false } - background: Rectangle { + background: PaddedRectangle { + padding: Theme.compactToolbar() ? 0 : 3 + radius: Theme.compactToolbar() ? 0 : 5 color: (parent.checked || parent.pressed) ? Theme.color(Theme.FancyToolButtonSelectedColor) - : parent.hovered + : (parent.hovered && parent.enabled) ? Theme.color(Theme.FancyToolButtonHoverColor) : "#00000000" } diff --git a/src/libs/tracing/qml/MainView.qml b/src/libs/tracing/qml/MainView.qml index 5aa4e835a37..052ec4aa762 100644 --- a/src/libs/tracing/qml/MainView.qml +++ b/src/libs/tracing/qml/MainView.qml @@ -156,7 +156,7 @@ Rectangle { anchors.top: parent.top anchors.left: parent.left width: 150 - height: 24 + height: Theme.toolBarHeight() onZoomControlChanged: zoomSliderToolBar.visible = !zoomSliderToolBar.visible onJumpToNext: { var next = timelineModelAggregator.nextItem(root.selectedModel, root.selectedItem, diff --git a/src/libs/tracing/qml/RangeDetails.qml b/src/libs/tracing/qml/RangeDetails.qml index 8c0e64f25c2..9ce3e996d94 100644 --- a/src/libs/tracing/qml/RangeDetails.qml +++ b/src/libs/tracing/qml/RangeDetails.qml @@ -9,7 +9,7 @@ import QtCreator.Tracing Item { id: rangeDetails - property real titleBarHeight: 20 + property real titleBarHeight: Theme.toolBarHeight() / 1.2 property real borderWidth: 1 property real outerMargin: 10 property real innerMargin: 5 diff --git a/src/libs/tracing/qml/TimeDisplay.qml b/src/libs/tracing/qml/TimeDisplay.qml index ffcbea2e841..64cb0474cfd 100644 --- a/src/libs/tracing/qml/TimeDisplay.qml +++ b/src/libs/tracing/qml/TimeDisplay.qml @@ -11,7 +11,7 @@ Item { property double rangeDuration property int textMargin: 5 - property int labelsHeight: 24 + property int labelsHeight: Theme.toolBarHeight() property int fontSize: 8 property int initialBlockLength: 120 property double spacing: width / rangeDuration diff --git a/src/libs/tracing/timelinetheme.cpp b/src/libs/tracing/timelinetheme.cpp index df02cb63961..41c0c44b4ff 100644 --- a/src/libs/tracing/timelinetheme.cpp +++ b/src/libs/tracing/timelinetheme.cpp @@ -5,8 +5,9 @@ #include #include -#include +#include #include +#include #include #include @@ -92,4 +93,14 @@ void TimelineTheme::setupTheme(QQmlEngine *engine) engine->addImageProvider(QLatin1String("icons"), new TimelineImageIconProvider); } +bool TimelineTheme::compactToolbar() const +{ + return StyleHelper::toolbarStyle() == StyleHelper::ToolbarStyleCompact; +} + +int TimelineTheme::toolBarHeight() const +{ + return StyleHelper::navigationWidgetHeight(); +} + } // namespace Timeline diff --git a/src/libs/tracing/timelinetheme.h b/src/libs/tracing/timelinetheme.h index ebca62447dd..f15eccbdaf1 100644 --- a/src/libs/tracing/timelinetheme.h +++ b/src/libs/tracing/timelinetheme.h @@ -22,6 +22,8 @@ public: explicit TimelineTheme(QObject *parent = nullptr); static void setupTheme(QQmlEngine* engine); + Q_INVOKABLE bool compactToolbar() const; + Q_INVOKABLE int toolBarHeight() const; }; } // namespace Timeline From 4d2632c3fa92f0a6c227e75a81a34eba6ed96ea0 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 24 Apr 2023 09:41:09 +0200 Subject: [PATCH 0838/1447] Toolbars: various toolbar layout tweaks This makes sure that toolbutton sizes and spacings are correct in all toolbar layout modes. Task-number: QTCREATORBUG-29082 Change-Id: If2aad74b77c0b8dcda81478e3d345c783584cec4 Reviewed-by: hjk --- src/plugins/coreplugin/find/findtoolbar.cpp | 1 - src/plugins/coreplugin/manhattanstyle.cpp | 15 +++++++++++++-- src/plugins/coreplugin/statusbarmanager.cpp | 1 - src/plugins/cppeditor/cppincludehierarchy.cpp | 2 ++ src/plugins/debugger/debuggermainwindow.cpp | 2 +- src/plugins/perfprofiler/perfprofilertool.cpp | 5 +++++ .../scxmleditor/common/stateproperties.cpp | 1 - src/plugins/squish/squishoutputpane.cpp | 4 ++++ src/plugins/texteditor/outlinefactory.cpp | 3 +++ 9 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/plugins/coreplugin/find/findtoolbar.cpp b/src/plugins/coreplugin/find/findtoolbar.cpp index 4690502f50a..27283434636 100644 --- a/src/plugins/coreplugin/find/findtoolbar.cpp +++ b/src/plugins/coreplugin/find/findtoolbar.cpp @@ -133,7 +133,6 @@ FindToolBar::FindToolBar(CurrentDocumentFind *currentDocumentFind) auto verticalLayout_3 = new QVBoxLayout(); verticalLayout_3->setSpacing(0); verticalLayout_3->addWidget(m_advancedButton); - verticalLayout_3->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); auto gridLayout = new QGridLayout(); gridLayout->setHorizontalSpacing(3); diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 59d633ee0fc..9cd74e84cfb 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -77,6 +78,9 @@ bool panelWidget(const QWidget *widget) if (qobject_cast(widget)) return styleEnabled(widget); + if (qobject_cast(widget)) + return widget->property("panelwidget_singlerow").toBool(); // See DebuggerMainWindowPrivate + const QWidget *p = widget; while (p) { if (qobject_cast(p) || @@ -667,10 +671,14 @@ void ManhattanStyle::polish(QWidget *widget) } else if (qobject_cast(widget) || qobject_cast(widget) || qobject_cast(widget)) { widget->setPalette(panelPalette(widget->palette(), lightColored(widget))); - } else if (widget->property("panelwidget_singlerow").toBool()) { + } else if ((qobject_cast(widget) && !StyleHelper::isQDSTheme()) + || widget->property("panelwidget_singlerow").toBool()) { widget->setFixedHeight(height); } else if (qobject_cast(widget)) { - widget->setFixedHeight(height + 2); + const bool flatAndNotCompact = + StyleHelper::toolbarStyle() != StyleHelper::ToolbarStyleCompact + && creatorTheme()->flag(Theme::FlatToolBars); + widget->setFixedHeight(height + (flatAndNotCompact ? 3 : 2)); } else if (qobject_cast(widget)) { const bool isLightColored = lightColored(widget); QPalette palette = panelPalette(widget->palette(), isLightColored); @@ -680,6 +688,9 @@ void ManhattanStyle::polish(QWidget *widget) widget->setPalette(palette); widget->setMaximumHeight(height - 2); widget->setAttribute(Qt::WA_Hover); + } else if (qobject_cast(widget) + && widget->property("panelwidget_singlerow").toBool()) { + widget->setFixedHeight(height); } } } diff --git a/src/plugins/coreplugin/statusbarmanager.cpp b/src/plugins/coreplugin/statusbarmanager.cpp index 48413379756..83d910867bf 100644 --- a/src/plugins/coreplugin/statusbarmanager.cpp +++ b/src/plugins/coreplugin/statusbarmanager.cpp @@ -59,7 +59,6 @@ static void createStatusBarManager() m_statusBarWidgets.append(w); QWidget *w2 = createWidget(m_splitter); - w2->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); m_splitter->addWidget(w2); // second w = createWidget(w2); diff --git a/src/plugins/cppeditor/cppincludehierarchy.cpp b/src/plugins/cppeditor/cppincludehierarchy.cpp index c2a9ead6b78..caad2e0937b 100644 --- a/src/plugins/cppeditor/cppincludehierarchy.cpp +++ b/src/plugins/cppeditor/cppincludehierarchy.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -382,6 +383,7 @@ CppIncludeHierarchyWidget::CppIncludeHierarchyWidget() this, &CppIncludeHierarchyWidget::perform); m_toggleSync = new QToolButton(this); + StyleHelper::setPanelWidget(m_toggleSync); m_toggleSync->setIcon(Utils::Icons::LINK_TOOLBAR.icon()); m_toggleSync->setCheckable(true); m_toggleSync->setToolTip(Tr::tr("Synchronize with Editor")); diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 8dfe23d8b14..554ad397b0f 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -233,8 +233,8 @@ DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent) scrolledToolbar->setFrameStyle(QFrame::NoFrame); scrolledToolbar->setWidgetResizable(true); scrolledToolbar->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrolledToolbar->setFixedHeight(toolbar->height()); scrolledToolbar->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + StyleHelper::setPanelWidgetSingleRow(scrolledToolbar); auto dock = new QDockWidget(Tr::tr("Toolbar"), q); dock->setObjectName("Toolbar"); diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index b199f227481..57a829ed605 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -121,6 +121,7 @@ PerfProfilerTool::PerfProfilerTool() options->addAction(command); m_tracePointsButton = new QToolButton; + StyleHelper::setPanelWidget(m_tracePointsButton); m_tracePointsButton->setDefaultAction(tracePointsAction); m_objectsToDelete << m_tracePointsButton; @@ -147,10 +148,14 @@ PerfProfilerTool::PerfProfilerTool() this, &PerfProfilerTool::updateRunActions); m_recordButton = new QToolButton; + StyleHelper::setPanelWidget(m_recordButton); m_clearButton = new QToolButton; + StyleHelper::setPanelWidget(m_clearButton); m_filterButton = new QToolButton; + StyleHelper::setPanelWidget(m_filterButton); m_filterMenu = new QMenu(m_filterButton); m_aggregateButton = new QToolButton; + StyleHelper::setPanelWidget(m_aggregateButton); m_recordedLabel = new QLabel; StyleHelper::setPanelWidget(m_recordedLabel); m_delayLabel = new QLabel; diff --git a/src/plugins/scxmleditor/common/stateproperties.cpp b/src/plugins/scxmleditor/common/stateproperties.cpp index 32d6e43f642..f7a884837ea 100644 --- a/src/plugins/scxmleditor/common/stateproperties.cpp +++ b/src/plugins/scxmleditor/common/stateproperties.cpp @@ -106,7 +106,6 @@ void StateProperties::createUi() m_currentTagName = new QLabel; auto propertiesToolBar = new QToolBar; - propertiesToolBar->setMinimumHeight(24); propertiesToolBar->addWidget(titleLabel); propertiesToolBar->addWidget(m_currentTagName); diff --git a/src/plugins/squish/squishoutputpane.cpp b/src/plugins/squish/squishoutputpane.cpp index 2b2d90d1652..0b10967afa2 100644 --- a/src/plugins/squish/squishoutputpane.cpp +++ b/src/plugins/squish/squishoutputpane.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -305,14 +306,17 @@ void SquishOutputPane::clearOldResults() void SquishOutputPane::createToolButtons() { m_expandAll = new QToolButton(m_treeView); + Utils::StyleHelper::setPanelWidget(m_expandAll); m_expandAll->setIcon(Utils::Icons::EXPAND_TOOLBAR.icon()); m_expandAll->setToolTip(Tr::tr("Expand All")); m_collapseAll = new QToolButton(m_treeView); + Utils::StyleHelper::setPanelWidget(m_collapseAll); m_collapseAll->setIcon(Utils::Icons::COLLAPSE_TOOLBAR.icon()); m_collapseAll->setToolTip(Tr::tr("Collapse All")); m_filterButton = new QToolButton(m_treeView); + Utils::StyleHelper::setPanelWidget(m_filterButton); m_filterButton->setIcon(Utils::Icons::FILTER.icon()); m_filterButton->setToolTip(Tr::tr("Filter Test Results")); m_filterButton->setProperty("noArrow", true); diff --git a/src/plugins/texteditor/outlinefactory.cpp b/src/plugins/texteditor/outlinefactory.cpp index 76222642c15..2a39d7edfd0 100644 --- a/src/plugins/texteditor/outlinefactory.cpp +++ b/src/plugins/texteditor/outlinefactory.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -63,6 +64,7 @@ OutlineWidgetStack::OutlineWidgetStack(OutlineFactory *factory) : this, &OutlineWidgetStack::toggleCursorSynchronization); m_filterButton = new QToolButton(this); + Utils::StyleHelper::setPanelWidget(m_filterButton); // The ToolButton needs a parent because updateFilterMenu() sets // it visible. That would open a top-level window if the button // did not have a parent in that moment. @@ -75,6 +77,7 @@ OutlineWidgetStack::OutlineWidgetStack(OutlineFactory *factory) : m_filterButton->setMenu(m_filterMenu); m_toggleSort = new QToolButton(this); + Utils::StyleHelper::setPanelWidget(m_toggleSort); m_toggleSort->setIcon(Utils::Icons::SORT_ALPHABETICALLY_TOOLBAR.icon()); m_toggleSort->setCheckable(true); m_toggleSort->setChecked(false); From 5943152f65a964418321c62572c29a73036a7fa6 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 4 May 2023 13:00:00 +0200 Subject: [PATCH 0839/1447] Android: Remove CheckableMessageBox::shouldAskAgain check Most likely, that was checked in addition to InfoBar::canInfoBeAdded in order to be settings compatible with QtC versions prior to the migration from CheckableMessageBox to InfoBar. But that is at this point 4 Years ago, and should be removed because it causes confusion when reading the code. Change-Id: I76ae6a9ed0c8f9f7fa20b64090d89724588511ed Reviewed-by: Assam Boudjelthia Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/android/androidplugin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 04e9609b85e..c15cfef221d 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -153,8 +153,7 @@ void AndroidPlugin::kitsRestored() void AndroidPlugin::askUserAboutAndroidSetup() { - if (!Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(), kSetupAndroidSetting) - || !Core::ICore::infoBar()->canInfoBeAdded(kSetupAndroidSetting)) + if (!Core::ICore::infoBar()->canInfoBeAdded(kSetupAndroidSetting)) return; Utils::InfoBarEntry From 1c34fc7bca8fc27df28d0459f668a177d1c29c4a Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 5 May 2023 10:45:39 +0200 Subject: [PATCH 0840/1447] Layouting: Fix advancing by empty cells Change-Id: I404e80e98a8fa53e174a8a372b82e17e8187a52c Reviewed-by: Eike Ziller Reviewed-by: --- src/libs/utils/layoutbuilder.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 33046a07f7d..bda8bcab8e3 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -477,7 +477,13 @@ LayoutItem br() LayoutItem empty() { - return {}; + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { + ResultItem ri; + ri.span = 1; + builder.stack.last().pendingItems.append(ResultItem()); + }; + return item; } LayoutItem hr() From 302afcdfc7aeea1c1c072264605ecbf913cacb83 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 4 May 2023 15:34:40 +0200 Subject: [PATCH 0841/1447] Markdown: Fix focus handling When the markdown editor is opened or switched to, the focus is set on the editor widget. We don't want the focus on the splitter, but on either the text editor or the preview, depending on what had focus before. Change-Id: Ib54899c6251f2c5362f95d990e7150b6fee0f1e1 Reviewed-by: David Schulz --- src/plugins/texteditor/markdowneditor.cpp | 45 +++++++++++++++++------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index afdda1bfb4d..59a524226db 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -38,13 +38,15 @@ public: const bool textEditorRight = s->value(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, kTextEditorRightDefault).toBool(); - // Left side + m_splitter = new Core::MiniSplitter; + + // preview auto browser = new QTextBrowser(); browser->setOpenExternalLinks(true); browser->setFrameShape(QFrame::NoFrame); new Utils::MarkdownHighlighter(browser->document()); - // Right side (hidable) + // editor m_textEditorWidget = new TextEditorWidget; m_textEditorWidget->setTextDocument(m_document); m_textEditorWidget->setupGenericHighlighter(); @@ -55,15 +57,22 @@ public: Core::ICore::addContextObject(context); if (textEditorRight) { - m_widget.addWidget(browser); - m_widget.addWidget(m_textEditorWidget); + m_splitter->addWidget(browser); + m_splitter->addWidget(m_textEditorWidget); } else { - m_widget.addWidget(m_textEditorWidget); - m_widget.addWidget(browser); + m_splitter->addWidget(m_textEditorWidget); + m_splitter->addWidget(browser); } setContext(Core::Context(MARKDOWNVIEWER_ID)); - setWidget(&m_widget); + + auto widget = new QWidget; + auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + widget->setLayout(layout); + layout->addWidget(m_splitter); + setWidget(widget); + m_widget->installEventFilter(this); auto togglePreviewVisible = new QToolButton; togglePreviewVisible->setText(Tr::tr("Show Preview")); @@ -124,12 +133,12 @@ public: }); connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this, toolbarLayout] { - QTC_ASSERT(m_widget.count() > 1, return); + QTC_ASSERT(m_splitter->count() > 1, return); // switch views auto placeholder = std::make_unique(); - auto second = m_widget.replaceWidget(1, placeholder.get()); - auto first = m_widget.replaceWidget(0, second); - m_widget.replaceWidget(1, first); + auto second = m_splitter->replaceWidget(1, placeholder.get()); + auto first = m_splitter->replaceWidget(0, second); + m_splitter->replaceWidget(1, first); // switch buttons const int rightIndex = toolbarLayout->count() - 2; QLayoutItem *right = toolbarLayout->takeAt(rightIndex); @@ -164,8 +173,20 @@ public: Core::IDocument *document() const override { return m_document.data(); } TextEditorWidget *textEditorWidget() const { return m_textEditorWidget; } + bool eventFilter(QObject *obj, QEvent *ev) override + { + if (obj == m_widget && ev->type() == QEvent::FocusIn) { + if (m_splitter->focusWidget()) + m_splitter->focusWidget()->setFocus(); + else + m_splitter->widget(0)->setFocus(); + return true; + } + return Core::IEditor::eventFilter(obj, ev); + } + private: - Core::MiniSplitter m_widget; + Core::MiniSplitter *m_splitter; TextEditorWidget *m_textEditorWidget; TextDocumentPtr m_document; QWidget m_toolbar; From 34a3852efc1bf37e73527ebc2ffa931bac7e3857 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 20 Apr 2023 13:10:58 +0200 Subject: [PATCH 0842/1447] Haskell: Compactify option page implementation a bit Change-Id: I1aa765e47ae60a4b4e47888bf8f0d5dfd1ec23cc Reviewed-by: Alessandro Portale --- src/plugins/haskell/optionspage.cpp | 41 +++++++++++------------------ 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/plugins/haskell/optionspage.cpp b/src/plugins/haskell/optionspage.cpp index 540656ba4f4..48e5159da5a 100644 --- a/src/plugins/haskell/optionspage.cpp +++ b/src/plugins/haskell/optionspage.cpp @@ -8,11 +8,7 @@ #include "haskelltr.h" #include - -#include -#include -#include -#include +#include using namespace Utils; @@ -23,28 +19,23 @@ class HaskellOptionsPageWidget : public Core::IOptionsPageWidget public: HaskellOptionsPageWidget() { - auto topLayout = new QVBoxLayout; - setLayout(topLayout); - auto generalBox = new QGroupBox(Tr::tr("General")); - topLayout->addWidget(generalBox); - topLayout->addStretch(10); - auto boxLayout = new QHBoxLayout; - generalBox->setLayout(boxLayout); - boxLayout->addWidget(new QLabel(Tr::tr("Stack executable:"))); - m_stackPath = new PathChooser(); - m_stackPath->setExpectedKind(PathChooser::ExistingCommand); - m_stackPath->setPromptDialogTitle(Tr::tr("Choose Stack Executable")); - m_stackPath->setFilePath(HaskellManager::stackExecutable()); - m_stackPath->setCommandVersionArguments({"--version"}); - boxLayout->addWidget(m_stackPath); - } + auto stackPath = new PathChooser; + stackPath->setExpectedKind(PathChooser::ExistingCommand); + stackPath->setPromptDialogTitle(Tr::tr("Choose Stack Executable")); + stackPath->setFilePath(HaskellManager::stackExecutable()); + stackPath->setCommandVersionArguments({"--version"}); - void apply() final - { - HaskellManager::setStackExecutable(m_stackPath->rawFilePath()); - } + setOnApply([stackPath] { HaskellManager::setStackExecutable(stackPath->rawFilePath()); }); - QPointer m_stackPath; + using namespace Layouting; + Column { + Group { + title(Tr::tr("General")), + Row { Tr::tr("Stack executable:"), stackPath } + }, + st, + }.attachTo(this); + } }; OptionsPage::OptionsPage() From abce79939a5f314ea68b63aac48444f680cc414b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 4 May 2023 17:20:29 +0200 Subject: [PATCH 0843/1447] Tests: Rename tst_QtcProcess -> tst_Process Follows 470c95c94be58905bc3202d3b58175add5f576fa Change-Id: Ie26b5677d28e645ab27aeebf5976b5507385716a Reviewed-by: hjk --- src/libs/utils/process.h | 2 - tests/auto/utils/CMakeLists.txt | 2 +- .../{qtcprocess => process}/CMakeLists.txt | 4 +- .../qtcprocess.qbs => process/process.qbs} | 4 +- .../processtestapp/CMakeLists.txt | 0 .../processtestapp/main.cpp | 0 .../processtestapp/processtestapp.cpp | 0 .../processtestapp/processtestapp.h | 0 .../processtestapp/processtestapp.qbs | 0 .../tst_process.cpp} | 112 +++++++++--------- tests/auto/utils/utils.qbs | 2 +- 11 files changed, 61 insertions(+), 65 deletions(-) rename tests/auto/utils/{qtcprocess => process}/CMakeLists.txt (89%) rename tests/auto/utils/{qtcprocess/qtcprocess.qbs => process/process.qbs} (93%) rename tests/auto/utils/{qtcprocess => process}/processtestapp/CMakeLists.txt (100%) rename tests/auto/utils/{qtcprocess => process}/processtestapp/main.cpp (100%) rename tests/auto/utils/{qtcprocess => process}/processtestapp/processtestapp.cpp (100%) rename tests/auto/utils/{qtcprocess => process}/processtestapp/processtestapp.h (100%) rename tests/auto/utils/{qtcprocess => process}/processtestapp/processtestapp.qbs (100%) rename tests/auto/utils/{qtcprocess/tst_qtcprocess.cpp => process/tst_process.cpp} (95%) diff --git a/src/libs/utils/process.h b/src/libs/utils/process.h index f11f3c3c41c..b79cac2d393 100644 --- a/src/libs/utils/process.h +++ b/src/libs/utils/process.h @@ -20,8 +20,6 @@ class QDebug; class QTextCodec; QT_END_NAMESPACE -class tst_QtcProcess; - namespace Utils { namespace Internal { class QtcProcessPrivate; } diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index 74fed43c104..e58f15af6e9 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(indexedcontainerproxyconstiterator) add_subdirectory(mathutils) add_subdirectory(multicursor) add_subdirectory(persistentsettings) -add_subdirectory(qtcprocess) +add_subdirectory(process) add_subdirectory(settings) add_subdirectory(stringutils) add_subdirectory(tasktree) diff --git a/tests/auto/utils/qtcprocess/CMakeLists.txt b/tests/auto/utils/process/CMakeLists.txt similarity index 89% rename from tests/auto/utils/qtcprocess/CMakeLists.txt rename to tests/auto/utils/process/CMakeLists.txt index 51720bbeb5b..29bdf61451b 100644 --- a/tests/auto/utils/qtcprocess/CMakeLists.txt +++ b/tests/auto/utils/process/CMakeLists.txt @@ -3,11 +3,11 @@ add_subdirectory(processtestapp) file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}") -add_qtc_test(tst_qtcprocess +add_qtc_test(tst_process DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\"" "PROCESS_TESTAPP=\"${CMAKE_CURRENT_BINARY_DIR}/processtestapp\"" DEPENDS Utils app_version - SOURCES tst_qtcprocess.cpp + SOURCES tst_process.cpp processtestapp/processtestapp.h processtestapp/processtestapp.cpp ) diff --git a/tests/auto/utils/qtcprocess/qtcprocess.qbs b/tests/auto/utils/process/process.qbs similarity index 93% rename from tests/auto/utils/qtcprocess/qtcprocess.qbs rename to tests/auto/utils/process/process.qbs index cc37a0124fc..0ff6e929fcf 100644 --- a/tests/auto/utils/qtcprocess/qtcprocess.qbs +++ b/tests/auto/utils/process/process.qbs @@ -2,7 +2,7 @@ import qbs.FileInfo Project { QtcAutotest { - name: "QtcProcess autotest" + name: "Process autotest" Depends { name: "Utils" } Depends { name: "app_version_header" } @@ -10,7 +10,7 @@ Project { files: [ "processtestapp/processtestapp.cpp", "processtestapp/processtestapp.h", - "tst_qtcprocess.cpp", + "tst_process.cpp", ] cpp.defines: { var defines = base; diff --git a/tests/auto/utils/qtcprocess/processtestapp/CMakeLists.txt b/tests/auto/utils/process/processtestapp/CMakeLists.txt similarity index 100% rename from tests/auto/utils/qtcprocess/processtestapp/CMakeLists.txt rename to tests/auto/utils/process/processtestapp/CMakeLists.txt diff --git a/tests/auto/utils/qtcprocess/processtestapp/main.cpp b/tests/auto/utils/process/processtestapp/main.cpp similarity index 100% rename from tests/auto/utils/qtcprocess/processtestapp/main.cpp rename to tests/auto/utils/process/processtestapp/main.cpp diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp b/tests/auto/utils/process/processtestapp/processtestapp.cpp similarity index 100% rename from tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp rename to tests/auto/utils/process/processtestapp/processtestapp.cpp diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h b/tests/auto/utils/process/processtestapp/processtestapp.h similarity index 100% rename from tests/auto/utils/qtcprocess/processtestapp/processtestapp.h rename to tests/auto/utils/process/processtestapp/processtestapp.h diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.qbs b/tests/auto/utils/process/processtestapp/processtestapp.qbs similarity index 100% rename from tests/auto/utils/qtcprocess/processtestapp/processtestapp.qbs rename to tests/auto/utils/process/processtestapp/processtestapp.qbs diff --git a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/process/tst_process.cpp similarity index 95% rename from tests/auto/utils/qtcprocess/tst_qtcprocess.cpp rename to tests/auto/utils/process/tst_process.cpp index 657b3356068..fd11c5d4632 100644 --- a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/utils/process/tst_process.cpp @@ -87,7 +87,7 @@ private: static constexpr char s_skipTerminateOnWindows[] = "Windows implementation of this test is lacking handling of WM_CLOSE message."; -class tst_QtcProcess : public QObject +class tst_Process : public QObject { Q_OBJECT @@ -109,16 +109,14 @@ private slots: qDebug() << "QProcess output:" << qoutput; QCOMPARE(qproc.exitCode(), 0); - Process qtcproc; - qtcproc.setCommand({envPath, {}}); - qtcproc.runBlocking(); - QCOMPARE(qtcproc.exitCode(), 0); - QByteArray qtcoutput = qtcproc.readAllRawStandardOutput() - + qtcproc.readAllRawStandardError(); + Process proc; + proc.setCommand({envPath, {}}); + proc.runBlocking(); + QCOMPARE(proc.exitCode(), 0); + const QByteArray output = proc.readAllRawStandardOutput() + proc.readAllRawStandardError(); + qDebug() << "Process output:" << output; - qDebug() << "QtcProcess output:" << qtcoutput; - - QCOMPARE(qtcoutput.size() > 0, qoutput.size() > 0); + QCOMPARE(output.size() > 0, qoutput.size() > 0); } void multiRead(); @@ -179,7 +177,7 @@ private: MessageHandler *msgHandler = nullptr; }; -void tst_QtcProcess::initTestCase() +void tst_Process::initTestCase() { msgHandler = new MessageHandler; Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" @@ -230,7 +228,7 @@ void tst_QtcProcess::initTestCase() mxUnix.insert("z", ""); } -void tst_QtcProcess::cleanupTestCase() +void tst_Process::cleanupTestCase() { Utils::Singleton::deleteAll(); const int destroyCount = msgHandler->destroyCount(); @@ -244,7 +242,7 @@ Q_DECLARE_METATYPE(ProcessArgs::SplitError) Q_DECLARE_METATYPE(Utils::OsType) Q_DECLARE_METATYPE(Utils::ProcessResult) -void tst_QtcProcess::multiRead() +void tst_Process::multiRead() { if (HostOsInfo::isWindowsHost()) QSKIP("This test uses /bin/sh."); @@ -272,7 +270,7 @@ void tst_QtcProcess::multiRead() QCOMPARE(buffer, QByteArray("you\n")); } -void tst_QtcProcess::splitArgs_data() +void tst_Process::splitArgs_data() { QTest::addColumn("in"); QTest::addColumn("out"); @@ -329,7 +327,7 @@ void tst_QtcProcess::splitArgs_data() } } -void tst_QtcProcess::splitArgs() +void tst_Process::splitArgs() { QFETCH(QString, in); QFETCH(QString, out); @@ -343,7 +341,7 @@ void tst_QtcProcess::splitArgs() QCOMPARE(outstr, out); } -void tst_QtcProcess::prepareArgs_data() +void tst_Process::prepareArgs_data() { QTest::addColumn("in"); QTest::addColumn("out"); @@ -397,7 +395,7 @@ void tst_QtcProcess::prepareArgs_data() } } -void tst_QtcProcess::prepareArgs() +void tst_Process::prepareArgs() { QFETCH(QString, in); QFETCH(QString, out); @@ -413,7 +411,7 @@ void tst_QtcProcess::prepareArgs() QCOMPARE(outstr, out); } -void tst_QtcProcess::prepareArgsEnv_data() +void tst_Process::prepareArgsEnv_data() { QTest::addColumn("in"); QTest::addColumn("out"); @@ -487,7 +485,7 @@ void tst_QtcProcess::prepareArgsEnv_data() } } -void tst_QtcProcess::prepareArgsEnv() +void tst_Process::prepareArgsEnv() { QFETCH(QString, in); QFETCH(QString, out); @@ -503,7 +501,7 @@ void tst_QtcProcess::prepareArgsEnv() QCOMPARE(outstr, out); } -void tst_QtcProcess::expandMacros_data() +void tst_Process::expandMacros_data() { QTest::addColumn("in"); @@ -737,7 +735,7 @@ void tst_QtcProcess::expandMacros_data() } } -void tst_QtcProcess::expandMacros() +void tst_Process::expandMacros() { QFETCH(QString, in); QFETCH(QString, out); @@ -750,7 +748,7 @@ void tst_QtcProcess::expandMacros() QCOMPARE(in, out); } -void tst_QtcProcess::iterations_data() +void tst_Process::iterations_data() { QTest::addColumn("in"); QTest::addColumn("out"); @@ -805,7 +803,7 @@ void tst_QtcProcess::iterations_data() << vals[i].os; } -void tst_QtcProcess::iterations() +void tst_Process::iterations() { QFETCH(QString, in); QFETCH(QString, out); @@ -821,7 +819,7 @@ void tst_QtcProcess::iterations() QCOMPARE(outstr, out); } -void tst_QtcProcess::iteratorEditsHelper(OsType osType) +void tst_Process::iteratorEditsHelper(OsType osType) { QString in1 = "one two three", in2 = in1, in3 = in1, in4 = in1, in5 = in1; @@ -872,17 +870,17 @@ void tst_QtcProcess::iteratorEditsHelper(OsType osType) QCOMPARE(in5, QString::fromLatin1("one two")); } -void tst_QtcProcess::iteratorEditsWindows() +void tst_Process::iteratorEditsWindows() { iteratorEditsHelper(OsTypeWindows); } -void tst_QtcProcess::iteratorEditsLinux() +void tst_Process::iteratorEditsLinux() { iteratorEditsHelper(OsTypeLinux); } -void tst_QtcProcess::exitCode_data() +void tst_Process::exitCode_data() { QTest::addColumn("exitCode"); @@ -896,7 +894,7 @@ void tst_QtcProcess::exitCode_data() QTest::newRow(exitCode) << QString::fromLatin1(exitCode).toInt(); } -void tst_QtcProcess::exitCode() +void tst_Process::exitCode() { QFETCH(int, exitCode); @@ -921,7 +919,7 @@ void tst_QtcProcess::exitCode() } } -void tst_QtcProcess::runBlockingStdOut_data() +void tst_Process::runBlockingStdOut_data() { QTest::addColumn("withEndl"); QTest::addColumn("timeOutS"); @@ -942,7 +940,7 @@ void tst_QtcProcess::runBlockingStdOut_data() << false << 20 << ProcessResult::FinishedWithSuccess; } -void tst_QtcProcess::runBlockingStdOut() +void tst_Process::runBlockingStdOut() { QFETCH(bool, withEndl); QFETCH(int, timeOutS); @@ -962,18 +960,18 @@ void tst_QtcProcess::runBlockingStdOut() }); process.runBlocking(); - // See also QTCREATORBUG-25667 for why it is a bad idea to use QtcProcess::runBlocking + // See also QTCREATORBUG-25667 for why it is a bad idea to use Process::runBlocking // with interactive cli tools. QCOMPARE(process.result(), expectedResult); QVERIFY2(readLastLine, "Last line was read."); } -void tst_QtcProcess::runBlockingSignal_data() +void tst_Process::runBlockingSignal_data() { runBlockingStdOut_data(); } -void tst_QtcProcess::runBlockingSignal() +void tst_Process::runBlockingSignal() { QFETCH(bool, withEndl); QFETCH(int, timeOutS); @@ -995,13 +993,13 @@ void tst_QtcProcess::runBlockingSignal() }); process.runBlocking(); - // See also QTCREATORBUG-25667 for why it is a bad idea to use QtcProcess::runBlocking + // See also QTCREATORBUG-25667 for why it is a bad idea to use Process::runBlocking // with interactive cli tools. QCOMPARE(process.result(), expectedResult); QVERIFY2(readLastLine, "Last line was read."); } -void tst_QtcProcess::lineCallback() +void tst_Process::lineCallback() { SubProcessConfig subConfig(ProcessTestApp::LineCallback::envVar(), {}); Process process; @@ -1024,7 +1022,7 @@ void tst_QtcProcess::lineCallback() QCOMPARE(lineNumber, lines.size()); } -void tst_QtcProcess::lineSignal() +void tst_Process::lineSignal() { SubProcessConfig subConfig(ProcessTestApp::LineCallback::envVar(), {}); Process process; @@ -1049,7 +1047,7 @@ void tst_QtcProcess::lineSignal() QCOMPARE(lineNumber, lines.size()); } -void tst_QtcProcess::waitForStartedAfterStarted() +void tst_Process::waitForStartedAfterStarted() { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); Process process; @@ -1070,7 +1068,7 @@ void tst_QtcProcess::waitForStartedAfterStarted() } // This version is using QProcess -void tst_QtcProcess::waitForStartedAfterStarted2() +void tst_Process::waitForStartedAfterStarted2() { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); QProcess process; @@ -1090,7 +1088,7 @@ void tst_QtcProcess::waitForStartedAfterStarted2() QVERIFY(!process.waitForStarted()); } -void tst_QtcProcess::waitForStartedAndFinished() +void tst_Process::waitForStartedAndFinished() { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); Process process; @@ -1106,7 +1104,7 @@ void tst_QtcProcess::waitForStartedAndFinished() Q_DECLARE_METATYPE(ProcessSignalType) -void tst_QtcProcess::notRunningAfterStartingNonExistingProgram_data() +void tst_Process::notRunningAfterStartingNonExistingProgram_data() { QTest::addColumn("signalType"); @@ -1115,7 +1113,7 @@ void tst_QtcProcess::notRunningAfterStartingNonExistingProgram_data() QTest::newRow("Done") << ProcessSignalType::Done; } -void tst_QtcProcess::notRunningAfterStartingNonExistingProgram() +void tst_Process::notRunningAfterStartingNonExistingProgram() { QFETCH(ProcessSignalType, signalType); @@ -1165,7 +1163,7 @@ void tst_QtcProcess::notRunningAfterStartingNonExistingProgram() // and the error channels. Then ChannelForwarding::main() either forwards these channels // or not - we check it in the outer channelForwarding() test. -void tst_QtcProcess::channelForwarding_data() +void tst_Process::channelForwarding_data() { QTest::addColumn("channelMode"); QTest::addColumn("outputForwarded"); @@ -1178,7 +1176,7 @@ void tst_QtcProcess::channelForwarding_data() QTest::newRow("ForwardedErrorChannel") << QProcess::ForwardedErrorChannel << false << true; } -void tst_QtcProcess::channelForwarding() +void tst_Process::channelForwarding() { QFETCH(QProcess::ProcessChannelMode, channelMode); QFETCH(bool, outputForwarded); @@ -1199,7 +1197,7 @@ void tst_QtcProcess::channelForwarding() QCOMPARE(error.contains(QByteArray(s_errorData)), errorForwarded); } -void tst_QtcProcess::mergedChannels_data() +void tst_Process::mergedChannels_data() { QTest::addColumn("channelMode"); QTest::addColumn("outputOnOutput"); @@ -1220,7 +1218,7 @@ void tst_QtcProcess::mergedChannels_data() } -void tst_QtcProcess::mergedChannels() +void tst_Process::mergedChannels() { QFETCH(QProcess::ProcessChannelMode, channelMode); QFETCH(bool, outputOnOutput); @@ -1245,7 +1243,7 @@ void tst_QtcProcess::mergedChannels() QCOMPARE(error.contains(QByteArray(s_errorData)), errorOnError); } -void tst_QtcProcess::destroyBlockingProcess_data() +void tst_Process::destroyBlockingProcess_data() { QTest::addColumn("blockType"); @@ -1255,7 +1253,7 @@ void tst_QtcProcess::destroyBlockingProcess_data() QTest::newRow("EventLoop") << BlockType::EventLoop; } -void tst_QtcProcess::destroyBlockingProcess() +void tst_Process::destroyBlockingProcess() { QFETCH(BlockType, blockType); @@ -1269,7 +1267,7 @@ void tst_QtcProcess::destroyBlockingProcess() QVERIFY(!process.waitForFinished(1000)); } -void tst_QtcProcess::flushFinishedWhileWaitingForReadyRead() +void tst_Process::flushFinishedWhileWaitingForReadyRead() { SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {}); Process process; @@ -1294,7 +1292,7 @@ void tst_QtcProcess::flushFinishedWhileWaitingForReadyRead() QVERIFY(reply.contains(s_simpleTestData)); } -void tst_QtcProcess::crash() +void tst_Process::crash() { SubProcessConfig subConfig(ProcessTestApp::Crash::envVar(), {}); Process process; @@ -1312,7 +1310,7 @@ void tst_QtcProcess::crash() QCOMPARE(process.exitStatus(), QProcess::CrashExit); } -void tst_QtcProcess::crashAfterOneSecond() +void tst_Process::crashAfterOneSecond() { SubProcessConfig subConfig(ProcessTestApp::CrashAfterOneSecond::envVar(), {}); Process process; @@ -1330,7 +1328,7 @@ void tst_QtcProcess::crashAfterOneSecond() QCOMPARE(process.error(), QProcess::Crashed); } -void tst_QtcProcess::recursiveCrashingProcess() +void tst_Process::recursiveCrashingProcess() { const int recursionDepth = 5; // must be at least 2 SubProcessConfig subConfig(ProcessTestApp::RecursiveCrashingProcess::envVar(), @@ -1356,7 +1354,7 @@ static int runningTestProcessCount() return testProcessCounter; } -void tst_QtcProcess::recursiveBlockingProcess() +void tst_Process::recursiveBlockingProcess() { if (HostOsInfo::isWindowsHost()) QSKIP(s_skipTerminateOnWindows); @@ -1395,7 +1393,7 @@ enum class QuitType { Q_DECLARE_METATYPE(QuitType) -void tst_QtcProcess::quitBlockingProcess_data() +void tst_Process::quitBlockingProcess_data() { QTest::addColumn("quitType"); QTest::addColumn("doneExpected"); @@ -1407,7 +1405,7 @@ void tst_QtcProcess::quitBlockingProcess_data() QTest::newRow("Close") << QuitType::Close << false << true; } -void tst_QtcProcess::quitBlockingProcess() +void tst_Process::quitBlockingProcess() { QFETCH(QuitType, quitType); QFETCH(bool, doneExpected); @@ -1467,7 +1465,7 @@ void tst_QtcProcess::quitBlockingProcess() } } -void tst_QtcProcess::tarPipe() +void tst_Process::tarPipe() { if (!FilePath::fromString("tar").searchInPath().isExecutableFile()) QSKIP("This test uses \"tar\" command."); @@ -1521,6 +1519,6 @@ void tst_QtcProcess::tarPipe() QCOMPARE(sourceFile.fileSize(), destinationFile.fileSize()); } -QTEST_GUILESS_MAIN(tst_QtcProcess) +QTEST_GUILESS_MAIN(tst_Process) -#include "tst_qtcprocess.moc" +#include "tst_process.moc" diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index 5f4d0439201..ee38d935982 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -16,7 +16,7 @@ Project { "mathutils/mathutils.qbs", "multicursor/multicursor.qbs", "persistentsettings/persistentsettings.qbs", - "qtcprocess/qtcprocess.qbs", + "process/process.qbs", "settings/settings.qbs", "stringutils/stringutils.qbs", "tasktree/tasktree.qbs", From af32b0ce44884d0e8d45927deeb569c81e791625 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 4 May 2023 17:29:37 +0200 Subject: [PATCH 0844/1447] Tests: Rename tst_AsyncTask -> tst_Async Follows 187a7640def4f137762547d82638c7f169f2cfe4 Change-Id: I58e6afbc0cbdea37c405b11e133d794a91f09fc6 Reviewed-by: hjk --- tests/auto/utils/CMakeLists.txt | 2 +- tests/auto/utils/async/CMakeLists.txt | 4 ++++ tests/auto/utils/async/async.qbs | 7 +++++++ .../tst_asynctask.cpp => async/tst_async.cpp} | 20 +++++++++---------- tests/auto/utils/asynctask/CMakeLists.txt | 4 ---- tests/auto/utils/asynctask/asynctask.qbs | 7 ------- tests/auto/utils/utils.qbs | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 tests/auto/utils/async/CMakeLists.txt create mode 100644 tests/auto/utils/async/async.qbs rename tests/auto/utils/{asynctask/tst_asynctask.cpp => async/tst_async.cpp} (98%) delete mode 100644 tests/auto/utils/asynctask/CMakeLists.txt delete mode 100644 tests/auto/utils/asynctask/asynctask.qbs diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index e58f15af6e9..36f20fdac52 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -1,5 +1,5 @@ add_subdirectory(ansiescapecodehandler) -add_subdirectory(asynctask) +add_subdirectory(async) add_subdirectory(commandline) add_subdirectory(deviceshell) add_subdirectory(expected) diff --git a/tests/auto/utils/async/CMakeLists.txt b/tests/auto/utils/async/CMakeLists.txt new file mode 100644 index 00000000000..0e6de32f567 --- /dev/null +++ b/tests/auto/utils/async/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_utils_async + DEPENDS Utils + SOURCES tst_async.cpp +) diff --git a/tests/auto/utils/async/async.qbs b/tests/auto/utils/async/async.qbs new file mode 100644 index 00000000000..696b0959a5b --- /dev/null +++ b/tests/auto/utils/async/async.qbs @@ -0,0 +1,7 @@ +import qbs + +QtcAutotest { + name: "Async autotest" + Depends { name: "Utils" } + files: "tst_async.cpp" +} diff --git a/tests/auto/utils/asynctask/tst_asynctask.cpp b/tests/auto/utils/async/tst_async.cpp similarity index 98% rename from tests/auto/utils/asynctask/tst_asynctask.cpp rename to tests/auto/utils/async/tst_async.cpp index 7218f7f5794..bf7cae7eff1 100644 --- a/tests/auto/utils/asynctask/tst_asynctask.cpp +++ b/tests/auto/utils/async/tst_async.cpp @@ -8,7 +8,7 @@ using namespace Utils; -class tst_AsyncTask : public QObject +class tst_Async : public QObject { Q_OBJECT @@ -131,7 +131,7 @@ std::shared_ptr> createAsyncTask(Function &&function, Args &&. return asyncTask; } -void tst_AsyncTask::runAsync() +void tst_Async::runAsync() { // free function pointer QCOMPARE(createAsyncTask(&report3)->results(), @@ -282,7 +282,7 @@ void tst_AsyncTask::runAsync() QList({0, 2, 1})); } -void tst_AsyncTask::crefFunction() +void tst_Async::crefFunction() { // free function pointer with promise auto fun = &report3; @@ -341,7 +341,7 @@ public: QString value; }; -void tst_AsyncTask::onResultReady() +void tst_Async::onResultReady() { { // lambda QObject context; @@ -386,7 +386,7 @@ void tst_AsyncTask::onResultReady() } } -void tst_AsyncTask::futureSynchonizer() +void tst_Async::futureSynchonizer() { auto lambda = [](QPromise &promise) { while (true) { @@ -418,7 +418,7 @@ void tst_AsyncTask::futureSynchonizer() void multiplyBy2(QPromise &promise, int input) { promise.addResult(input * 2); } -void tst_AsyncTask::taskTree() +void tst_Async::taskTree() { using namespace Tasking; @@ -461,7 +461,7 @@ static void returnxxWithPromise(QPromise &promise, int x) static double s_sum = 0; static QList s_results; -void tst_AsyncTask::mapReduce_data() +void tst_Async::mapReduce_data() { using namespace Tasking; @@ -567,7 +567,7 @@ void tst_AsyncTask::mapReduce_data() QTest::newRow("String") << stringRoot << 1.5 << QList({}); } -void tst_AsyncTask::mapReduce() +void tst_Async::mapReduce() { QThreadPool pool; @@ -591,6 +591,6 @@ void tst_AsyncTask::mapReduce() QCOMPARE(s_sum, sum); } -QTEST_GUILESS_MAIN(tst_AsyncTask) +QTEST_GUILESS_MAIN(tst_Async) -#include "tst_asynctask.moc" +#include "tst_async.moc" diff --git a/tests/auto/utils/asynctask/CMakeLists.txt b/tests/auto/utils/asynctask/CMakeLists.txt deleted file mode 100644 index 8b234dbb024..00000000000 --- a/tests/auto/utils/asynctask/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_qtc_test(tst_utils_asynctask - DEPENDS Utils - SOURCES tst_asynctask.cpp -) diff --git a/tests/auto/utils/asynctask/asynctask.qbs b/tests/auto/utils/asynctask/asynctask.qbs deleted file mode 100644 index 8f478147e8d..00000000000 --- a/tests/auto/utils/asynctask/asynctask.qbs +++ /dev/null @@ -1,7 +0,0 @@ -import qbs - -QtcAutotest { - name: "AsyncTask autotest" - Depends { name: "Utils" } - files: "tst_asynctask.cpp" -} diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index ee38d935982..6ed3fd73486 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -4,7 +4,7 @@ Project { name: "Utils autotests" references: [ "ansiescapecodehandler/ansiescapecodehandler.qbs", - "asynctask/asynctask.qbs", + "async/async.qbs", "commandline/commandline.qbs", "deviceshell/deviceshell.qbs", "expected/expected.qbs", From 2fa375671a0070926d55bc5a7039db6e087ac06e Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 May 2023 16:02:55 +0200 Subject: [PATCH 0845/1447] Android: Use LayoutBuilder in AndroidDeployQtStep Change-Id: I855227bffa18aef5d547510a9c447071527ddcba Reviewed-by: Alessandro Portale --- src/plugins/android/androiddeployqtstep.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 979efcb1af4..84f0ffbbe59 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -603,11 +603,13 @@ QWidget *AndroidDeployQtStep::createConfigWidget() AndroidManager::installQASIPackage(target(), packagePath); }); - Layouting::Form builder; - builder.addRow({m_uninstallPreviousPackage}); - builder.addRow({installCustomApkButton}); - builder.addItem(Layouting::noMargin); - builder.attachTo(widget); + using namespace Layouting; + + Form { + m_uninstallPreviousPackage, br, + installCustomApkButton, + noMargin + }.attachTo(widget); return widget; } From 9106a6e6620500ec9015fa64299b51c9cf80e234 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 3 May 2023 17:18:49 +0200 Subject: [PATCH 0846/1447] Nim: Normalize somewhat unusal ctor/dtor split Change-Id: I65e6fac252c068b11c45d06bcbcbc08c9316a528 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/nim/settings/nimsettings.cpp | 37 +++++++++--------------- src/plugins/nim/settings/nimsettings.h | 4 --- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp index 5904b8b6e60..fb18177800d 100644 --- a/src/plugins/nim/settings/nimsettings.cpp +++ b/src/plugins/nim/settings/nimsettings.cpp @@ -29,29 +29,6 @@ NimSettings::NimSettings() setAutoApply(false); setSettingsGroups("Nim", "NimSuggest"); - InitializeCodeStyleSettings(); - - registerAspect(&nimSuggestPath); - nimSuggestPath.setSettingsKey("Command"); - nimSuggestPath.setDisplayStyle(StringAspect::PathChooserDisplay); - nimSuggestPath.setExpectedKind(PathChooser::ExistingCommand); - nimSuggestPath.setLabelText(Tr::tr("Path:")); - - readSettings(Core::ICore::settings()); -} - -NimSettings::~NimSettings() -{ - TerminateCodeStyleSettings(); -} - -SimpleCodeStylePreferences *NimSettings::globalCodeStyle() -{ - return m_globalCodeStyle; -} - -void NimSettings::InitializeCodeStyleSettings() -{ // code style factory auto factory = new NimCodeStylePreferencesFactory(); TextEditorSettings::registerCodeStyleFactory(factory); @@ -93,9 +70,17 @@ void NimSettings::InitializeCodeStyleSettings() Nim::Constants::C_NIMLANGUAGE_ID); TextEditorSettings::registerMimeTypeForLanguageId(Nim::Constants::C_NIM_SCRIPT_MIMETYPE, Nim::Constants::C_NIMLANGUAGE_ID); + + registerAspect(&nimSuggestPath); + nimSuggestPath.setSettingsKey("Command"); + nimSuggestPath.setDisplayStyle(StringAspect::PathChooserDisplay); + nimSuggestPath.setExpectedKind(PathChooser::ExistingCommand); + nimSuggestPath.setLabelText(Tr::tr("Path:")); + + readSettings(Core::ICore::settings()); } -void NimSettings::TerminateCodeStyleSettings() +NimSettings::~NimSettings() { TextEditorSettings::unregisterCodeStyle(Nim::Constants::C_NIMLANGUAGE_ID); TextEditorSettings::unregisterCodeStylePool(Nim::Constants::C_NIMLANGUAGE_ID); @@ -105,6 +90,10 @@ void NimSettings::TerminateCodeStyleSettings() m_globalCodeStyle = nullptr; } +SimpleCodeStylePreferences *NimSettings::globalCodeStyle() +{ + return m_globalCodeStyle; +} // NimToolSettingsPage diff --git a/src/plugins/nim/settings/nimsettings.h b/src/plugins/nim/settings/nimsettings.h index d144618f7d2..1e8546b3336 100644 --- a/src/plugins/nim/settings/nimsettings.h +++ b/src/plugins/nim/settings/nimsettings.h @@ -19,10 +19,6 @@ public: Utils::StringAspect nimSuggestPath; static TextEditor::SimpleCodeStylePreferences *globalCodeStyle(); - -private: - void InitializeCodeStyleSettings(); - void TerminateCodeStyleSettings(); }; class NimToolsSettingsPage final : public Core::IOptionsPage From 652e99830fe00e32b9ea774920a34fde7eb79698 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 4 May 2023 08:55:10 +0200 Subject: [PATCH 0847/1447] Layouting: Add some support for spin boxes Change-Id: I5eff963cf605f5239a96daee924e91b2c170f506 Reviewed-by: Alessandro Portale --- src/libs/utils/layoutbuilder.cpp | 55 +++++++++++++++++++++++++------- src/libs/utils/layoutbuilder.h | 13 ++++++++ 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index bda8bcab8e3..a4edf7dfabe 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -559,6 +560,12 @@ PushButton::PushButton(std::initializer_list items) setupWidget(this); } +SpinBox::SpinBox(std::initializer_list items) +{ + this->subItems = items; + setupWidget(this); +} + TextEdit::TextEdit(std::initializer_list items) { this->subItems = items; @@ -630,17 +637,6 @@ LayoutItem title(const QString &title) }; } -LayoutItem onClicked(const std::function &func, QObject *guard) -{ - return [func, guard](QObject *target) { - if (auto button = qobject_cast(target)) { - QObject::connect(button, &QAbstractButton::clicked, guard ? guard : target, func); - } else { - QTC_CHECK(false); - } - }; -} - LayoutItem text(const QString &text) { return [text](QObject *target) { @@ -698,6 +694,43 @@ LayoutItem columnStretch(int column, int stretch) }; } +// Signals + +LayoutItem onClicked(const std::function &func, QObject *guard) +{ + return [func, guard](QObject *target) { + if (auto button = qobject_cast(target)) { + QObject::connect(button, &QAbstractButton::clicked, guard ? guard : target, func); + } else { + QTC_CHECK(false); + } + }; +} + +LayoutItem onTextChanged(const std::function &func, QObject *guard) +{ + return [func, guard](QObject *target) { + if (auto button = qobject_cast(target)) { + QObject::connect(button, &QSpinBox::textChanged, guard ? guard : target, func); + } else { + QTC_CHECK(false); + } + }; +} + +LayoutItem onValueChanged(const std::function &func, QObject *guard) +{ + return [func, guard](QObject *target) { + if (auto button = qobject_cast(target)) { + QObject::connect(button, &QSpinBox::valueChanged, guard ? guard : target, func); + } else { + QTC_CHECK(false); + } + }; +} + +// Convenience + QWidget *createHr(QWidget *parent) { auto frame = new QFrame(parent); diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index f2efeaf2fe9..cac9fad372d 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -143,6 +143,12 @@ public: PushButton(std::initializer_list items); }; +class QTCREATOR_UTILS_EXPORT SpinBox : public LayoutItem +{ +public: + SpinBox(std::initializer_list items); +}; + class QTCREATOR_UTILS_EXPORT Splitter : public LayoutItem { public: @@ -193,8 +199,15 @@ QTCREATOR_UTILS_EXPORT LayoutItem resize(int, int); QTCREATOR_UTILS_EXPORT LayoutItem columnStretch(int column, int stretch); QTCREATOR_UTILS_EXPORT LayoutItem spacing(int); QTCREATOR_UTILS_EXPORT LayoutItem windowTitle(const QString &windowTitle); + +// "Signals" + QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &, QObject *guard = nullptr); +QTCREATOR_UTILS_EXPORT LayoutItem onTextChanged(const std::function &, + QObject *guard = nullptr); +QTCREATOR_UTILS_EXPORT LayoutItem onValueChanged(const std::function &, + QObject *guard = nullptr); // Convenience From d5329d56b641e690bfab9b492dee089071905a93 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 4 May 2023 08:26:31 +0200 Subject: [PATCH 0848/1447] Layouting: Add demo Currently almost the same as the comparison example, but planeed to grow. Change-Id: Id129266a1b5b12438e2fb643ee114e6d816581f6 Reviewed-by: Alessandro Portale --- .../manual/layoutbuilder/demo/CMakeLists.txt | 44 +++++++++++++++++++ tests/manual/layoutbuilder/demo/main.cpp | 33 ++++++++++++++ .../manual/layoutbuilder/demo/mainwindow.cpp | 0 tests/manual/layoutbuilder/demo/mainwindow.h | 0 4 files changed, 77 insertions(+) create mode 100644 tests/manual/layoutbuilder/demo/CMakeLists.txt create mode 100644 tests/manual/layoutbuilder/demo/main.cpp create mode 100644 tests/manual/layoutbuilder/demo/mainwindow.cpp create mode 100644 tests/manual/layoutbuilder/demo/mainwindow.h diff --git a/tests/manual/layoutbuilder/demo/CMakeLists.txt b/tests/manual/layoutbuilder/demo/CMakeLists.txt new file mode 100644 index 00000000000..3a93056bea8 --- /dev/null +++ b/tests/manual/layoutbuilder/demo/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.5) + +project(layoutbuilderdemo VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Widgets) + +set(PROJECT_SOURCES + main.cpp + ../../../../src/libs/utils/layoutbuilder.h + ../../../../src/libs/utils/layoutbuilder.cpp +) + +add_executable(layoutbuilderdemo + ${PROJECT_SOURCES} +) + +target_include_directories(layoutbuilderdemo PRIVATE + ../../../../src/libs/utils/ +) + +target_link_libraries(layoutbuilderdemo PRIVATE + Qt6::Widgets +) + +set_target_properties(layoutbuilderdemo PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +install(TARGETS layoutbuilderdemo + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/tests/manual/layoutbuilder/demo/main.cpp b/tests/manual/layoutbuilder/demo/main.cpp new file mode 100644 index 00000000000..249c159302b --- /dev/null +++ b/tests/manual/layoutbuilder/demo/main.cpp @@ -0,0 +1,33 @@ +#include "layoutbuilder.h" + +#include +#include + +using namespace Layouting; + +int main(int argc, char *argv[]) +{ + Application app + { + resize(600, 400), + title("Hello World"), + + Column { + TextEdit { + text("Hallo") + }, + + SpinBox { + text("Quit"), + onTextChanged([](const QString &text) { qDebug() << text; }) + }, + + PushButton { + text("Quit"), + onClicked([] { QApplication::quit(); }) + }, + } + }; + + return app.exec(argc, argv); +} diff --git a/tests/manual/layoutbuilder/demo/mainwindow.cpp b/tests/manual/layoutbuilder/demo/mainwindow.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/manual/layoutbuilder/demo/mainwindow.h b/tests/manual/layoutbuilder/demo/mainwindow.h new file mode 100644 index 00000000000..e69de29bb2d From fb50e35db94a0c130c538432c60f0bba6a7bf07a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 4 May 2023 21:12:22 +0200 Subject: [PATCH 0849/1447] FilePath: Fix hash function For better performance, include also the scheme and host in qHash calculation. Change-Id: I2a69a128597429b88a71943d248ce038b49285f2 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 0fce0a9e4c4..de70d4bf9bc 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -2072,9 +2072,10 @@ QTCREATOR_UTILS_EXPORT bool operator>=(const FilePath &first, const FilePath &se QTCREATOR_UTILS_EXPORT size_t qHash(const FilePath &filePath, uint seed) { - if (filePath.caseSensitivity() == Qt::CaseInsensitive) - return qHash(filePath.path().toCaseFolded(), seed); - return qHash(filePath.path(), seed); + if (filePath.caseSensitivity() == Qt::CaseSensitive) + return qHash(QStringView(filePath.m_data), seed); + const size_t schemeHostHash = qHash(QStringView(filePath.m_data).mid(filePath.m_pathLen), seed); + return qHash(filePath.path().toCaseFolded(), seed) ^ schemeHostHash; } QTCREATOR_UTILS_EXPORT size_t qHash(const FilePath &filePath) From 7581dcd3690b7b52bc7796e30a42fba178b1e4fe Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 5 May 2023 14:51:31 +0200 Subject: [PATCH 0850/1447] FakeVim: More compact settings page implementation Change-Id: Iaca48e8a22f26817442dbf5147f318868dbd1f34 Reviewed-by: Alessandro Portale --- src/plugins/fakevim/fakevimplugin.cpp | 170 +++++++++++--------------- 1 file changed, 69 insertions(+), 101 deletions(-) diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 347e3a2b7b3..a9778cbe71d 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -340,33 +340,8 @@ private: using ExCommandMap = QMap; using UserCommandMap = QMap; -class FakeVimOptionPage : public IOptionsPage +static void layoutPage(QWidget *widget) { -public: - FakeVimOptionPage() - { - setId(SETTINGS_ID); - setDisplayName(Tr::tr("General")); - setCategory(SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("FakeVim")); - setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png"); - setLayouter([this](QWidget *widget) { return layoutPage(widget); }); - setSettings(fakeVimSettings()); - } - -private: - void layoutPage(QWidget *); - void copyTextEditorSettings(); - void setQtStyle(); - void setPlainStyle(); -}; - -void FakeVimOptionPage::layoutPage(QWidget *widget) -{ - auto copyTextEditorSettings = new QPushButton(Tr::tr("Copy Text Editor Settings")); - auto setQtStyle = new QPushButton(Tr::tr("Set Qt Style")); - auto setPlainStyle = new QPushButton(Tr::tr("Set Plain Style")); - using namespace Layouting; FakeVimSettings &s = *fakeVimSettings(); @@ -426,63 +401,73 @@ void FakeVimOptionPage::layoutPage(QWidget *widget) } }, - Row { copyTextEditorSettings, setQtStyle, setPlainStyle, st }, + Row { + PushButton { + text(Tr::tr("Copy Text Editor Settings")), + onClicked([&s] { + TabSettings ts = TextEditorSettings::codeStyle()->tabSettings(); + TypingSettings tps = TextEditorSettings::typingSettings(); + s.expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy); + s.tabStop.setValue(ts.m_tabSize); + s.shiftWidth.setValue(ts.m_indentSize); + s.smartTab.setValue(tps.m_smartBackspaceBehavior + == TypingSettings::BackspaceFollowsPreviousIndents); + s.autoIndent.setValue(true); + s.smartIndent.setValue(tps.m_autoIndent); + s.incSearch.setValue(true); + }), + }, + PushButton { + text(Tr::tr("Set Qt Style")), + onClicked([&s] { + s.expandTab.setVolatileValue(true); + s.tabStop.setVolatileValue(4); + s.shiftWidth.setVolatileValue(4); + s.smartTab.setVolatileValue(true); + s.autoIndent.setVolatileValue(true); + s.smartIndent.setVolatileValue(true); + s.incSearch.setVolatileValue(true); + s.backspace.setVolatileValue(QString("indent,eol,start")); + s.passKeys.setVolatileValue(true); + }), + }, + PushButton { + text(Tr::tr("Set Plain Style")), + onClicked([&s] { + s.expandTab.setVolatileValue(false); + s.tabStop.setVolatileValue(8); + s.shiftWidth.setVolatileValue(8); + s.smartTab.setVolatileValue(false); + s.autoIndent.setVolatileValue(false); + s.smartIndent.setVolatileValue(false); + s.incSearch.setVolatileValue(false); + s.backspace.setVolatileValue(QString()); + s.passKeys.setVolatileValue(false); + }), + }, + st + }, st }.attachTo(widget); s.vimRcPath.setEnabler(&s.readVimRc); - - connect(copyTextEditorSettings, &QAbstractButton::clicked, - this, &FakeVimOptionPage::copyTextEditorSettings); - connect(setQtStyle, &QAbstractButton::clicked, - this, &FakeVimOptionPage::setQtStyle); - connect(setPlainStyle, &QAbstractButton::clicked, - this, &FakeVimOptionPage::setPlainStyle); } -void FakeVimOptionPage::copyTextEditorSettings() +class FakeVimOptionPage : public IOptionsPage { - FakeVimSettings &s = *fakeVimSettings(); - TabSettings ts = TextEditorSettings::codeStyle()->tabSettings(); - TypingSettings tps = TextEditorSettings::typingSettings(); - s.expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy); - s.tabStop.setValue(ts.m_tabSize); - s.shiftWidth.setValue(ts.m_indentSize); - s.smartTab.setValue(tps.m_smartBackspaceBehavior - == TypingSettings::BackspaceFollowsPreviousIndents); - s.autoIndent.setValue(true); - s.smartIndent.setValue(tps.m_autoIndent); - s.incSearch.setValue(true); -} - -void FakeVimOptionPage::setQtStyle() -{ - FakeVimSettings &s = *fakeVimSettings(); - s.expandTab.setVolatileValue(true); - s.tabStop.setVolatileValue(4); - s.shiftWidth.setVolatileValue(4); - s.smartTab.setVolatileValue(true); - s.autoIndent.setVolatileValue(true); - s.smartIndent.setVolatileValue(true); - s.incSearch.setVolatileValue(true); - s.backspace.setVolatileValue(QString("indent,eol,start")); - s.passKeys.setVolatileValue(true); -} - -void FakeVimOptionPage::setPlainStyle() -{ - FakeVimSettings &s = *fakeVimSettings(); - s.expandTab.setVolatileValue(false); - s.tabStop.setVolatileValue(8); - s.shiftWidth.setVolatileValue(8); - s.smartTab.setVolatileValue(false); - s.autoIndent.setVolatileValue(false); - s.smartIndent.setVolatileValue(false); - s.incSearch.setVolatileValue(false); - s.backspace.setVolatileValue(QString()); - s.passKeys.setVolatileValue(false); -} +public: + FakeVimOptionPage() + { + setId(SETTINGS_ID); + setDisplayName(Tr::tr("General")); + setCategory(SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("FakeVim")); + setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png"); + setLayouter(&layoutPage); + setSettings(fakeVimSettings()); + } +}; /////////////////////////////////////////////////////////////////////// // @@ -804,16 +789,10 @@ class FakeVimExCommandsPageWidget : public IOptionsPageWidget public: FakeVimExCommandsPageWidget() { - m_exCommands = new FakeVimExCommandsMappings; - auto vbox = new QVBoxLayout(this); - vbox->addWidget(m_exCommands); - vbox->setContentsMargins(0, 0, 0, 0); + auto exCommands = new FakeVimExCommandsMappings; + setOnApply([exCommands] { exCommands->apply(); }); + Layouting::Column { exCommands, Layouting::noMargin }.attachTo(this); } - -private: - void apply() final { m_exCommands->apply(); } - - FakeVimExCommandsMappings *m_exCommands; }; class FakeVimExCommandsPage : public IOptionsPage @@ -840,28 +819,17 @@ public: FakeVimUserCommandsModel() { m_commandMap = dd->m_userCommandMap; } UserCommandMap commandMap() const { return m_commandMap; } - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - bool setData(const QModelIndex &index, const QVariant &data, int role) override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; + int rowCount(const QModelIndex &parent) const final { return parent.isValid() ? 0 : 9; } + int columnCount(const QModelIndex &parent) const final { return parent.isValid() ? 0 : 2; } + QVariant data(const QModelIndex &index, int role) const final; + bool setData(const QModelIndex &index, const QVariant &data, int role) final; + QVariant headerData(int section, Qt::Orientation orientation, int role) const final; + Qt::ItemFlags flags(const QModelIndex &index) const final; private: UserCommandMap m_commandMap; }; -int FakeVimUserCommandsModel::rowCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : 9; -} - -int FakeVimUserCommandsModel::columnCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : 2; -} - - QVariant FakeVimUserCommandsModel::headerData(int section, Qt::Orientation orient, int role) const { From 62f3d29be4e57324d04fa7e0487f0330d684bd1c Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 5 May 2023 15:19:58 +0200 Subject: [PATCH 0851/1447] Layouting: Introduce Ids for Items Intenally just wrapping a 'bindTo' result, but less trigger potential for pointer related peladophobia Change-Id: I25171a2675fb0474ce97c04552ac1cf5ffd6ee56 Reviewed-by: Alessandro Portale Reviewed-by: hjk --- src/libs/utils/layoutbuilder.cpp | 13 ++++++++++ src/libs/utils/layoutbuilder.h | 18 ++++++++++++- .../cmakekitinformation.cpp | 7 +++-- .../locator/locatorsettingspage.cpp | 5 ++-- .../projectexplorer/kitinformation.cpp | 15 +++++------ tests/manual/layoutbuilder/demo/main.cpp | 26 ++++++++++++------- 6 files changed, 60 insertions(+), 24 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index a4edf7dfabe..51b94b582d8 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -694,6 +694,19 @@ LayoutItem columnStretch(int column, int stretch) }; } +// Id based setters + +LayoutItem id(Id &out) +{ + return [&out](QObject *target) { out.ob = target; }; +} + +void setText(Id id, const QString &text) +{ + if (auto textEdit = qobject_cast(id.ob)) + textEdit->setText(text); +} + // Signals LayoutItem onClicked(const std::function &func, QObject *guard) diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index cac9fad372d..3898dd59826 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -190,7 +190,7 @@ QTCREATOR_UTILS_EXPORT LayoutItem noMargin(); QTCREATOR_UTILS_EXPORT LayoutItem normalMargin(); QTCREATOR_UTILS_EXPORT LayoutItem withFormAlignment(); -// "Properties" +// "Setters" QTCREATOR_UTILS_EXPORT LayoutItem title(const QString &title); QTCREATOR_UTILS_EXPORT LayoutItem text(const QString &text); @@ -200,6 +200,19 @@ QTCREATOR_UTILS_EXPORT LayoutItem columnStretch(int column, int stretch); QTCREATOR_UTILS_EXPORT LayoutItem spacing(int); QTCREATOR_UTILS_EXPORT LayoutItem windowTitle(const QString &windowTitle); +// "Getters" + +class Id +{ +public: + QObject *ob = nullptr; +}; + +QTCREATOR_UTILS_EXPORT LayoutItem id(Id &out); + +QTCREATOR_UTILS_EXPORT void setText(Id id, const QString &text); + + // "Signals" QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &, @@ -209,6 +222,8 @@ QTCREATOR_UTILS_EXPORT LayoutItem onTextChanged(const std::function &, QObject *guard = nullptr); +QTCREATOR_UTILS_EXPORT LayoutItem onTextChanged(Id &id, QVariant(*sig)(QObject *)); + // Convenience QTCREATOR_UTILS_EXPORT QWidget *createHr(QWidget *parent = nullptr); @@ -219,4 +234,5 @@ LayoutItem bindTo(T **out) return [out](QObject *target) { *out = qobject_cast(target); }; } + } // Layouting diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index b02f68357d8..ee7cd5f1c1b 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -48,7 +48,6 @@ using namespace ProjectExplorer; using namespace Utils; -using namespace Layouting; namespace CMakeProjectManager { @@ -104,7 +103,7 @@ private: // KitAspectWidget interface void makeReadOnly() override { m_comboBox->setEnabled(false); } - void addToLayout(LayoutItem &builder) override + void addToLayout(Layouting::LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -349,7 +348,7 @@ private: // KitAspectWidget interface void makeReadOnly() override { m_changeButton->setEnabled(false); } - void addToLayout(LayoutItem &parent) override + void addToLayout(Layouting::LayoutItem &parent) override { addMutableAction(m_label); parent.addItem(m_label); @@ -890,7 +889,7 @@ public: private: // KitAspectWidget interface - void addToLayout(LayoutItem &parent) override + void addToLayout(Layouting::LayoutItem &parent) override { addMutableAction(m_summaryLabel); parent.addItem(m_summaryLabel); diff --git a/src/plugins/coreplugin/locator/locatorsettingspage.cpp b/src/plugins/coreplugin/locator/locatorsettingspage.cpp index 2ecc451a9ad..74c3b45692e 100644 --- a/src/plugins/coreplugin/locator/locatorsettingspage.cpp +++ b/src/plugins/coreplugin/locator/locatorsettingspage.cpp @@ -341,12 +341,13 @@ public: auto addMenu = new QMenu(addButton); addMenu->addAction(Tr::tr("Files in Directories"), this, [this] { - addCustomFilter(new DirectoryFilter(Id(Constants::CUSTOM_DIRECTORY_FILTER_BASEID) + addCustomFilter(new DirectoryFilter(Utils::Id(Constants::CUSTOM_DIRECTORY_FILTER_BASEID) .withSuffix(m_customFilters.size() + 1))); }); addMenu->addAction(Tr::tr("URL Template"), this, [this] { auto filter = new UrlLocatorFilter( - Id(Constants::CUSTOM_URL_FILTER_BASEID).withSuffix(m_customFilters.size() + 1)); + Utils::Id(Constants::CUSTOM_URL_FILTER_BASEID) + .withSuffix(m_customFilters.size() + 1)); filter->setIsCustomFilter(true); addCustomFilter(filter); }); diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index 41cadfea1c4..bd4a4c70525 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -34,7 +34,6 @@ #include using namespace Utils; -using namespace Layouting; namespace ProjectExplorer { @@ -65,7 +64,7 @@ public: private: void makeReadOnly() override { m_chooser->setReadOnly(true); } - void addToLayout(LayoutItem &builder) override + void addToLayout(Layouting::LayoutItem &builder) override { addMutableAction(m_chooser); builder.addItem(Layouting::Span(2, m_chooser)); @@ -142,7 +141,7 @@ void SysRootKitAspect::addToMacroExpander(Kit *kit, MacroExpander *expander) con }); } -Id SysRootKitAspect::id() +Utils::Id SysRootKitAspect::id() { return "PE.Profile.SysRoot"; } @@ -231,7 +230,7 @@ public: } private: - void addToLayout(LayoutItem &builder) override + void addToLayout(Layouting::LayoutItem &builder) override { addMutableAction(m_mainWidget); builder.addItem(m_mainWidget); @@ -760,7 +759,7 @@ public: ~DeviceTypeKitAspectWidget() override { delete m_comboBox; } private: - void addToLayout(LayoutItem &builder) override + void addToLayout(Layouting::LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -896,7 +895,7 @@ public: } private: - void addToLayout(LayoutItem &builder) override + void addToLayout(Layouting::LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -1156,7 +1155,7 @@ public: } private: - void addToLayout(LayoutItem &builder) override + void addToLayout(Layouting::LayoutItem &builder) override { addMutableAction(m_comboBox); builder.addItem(m_comboBox); @@ -1387,7 +1386,7 @@ public: } private: - void addToLayout(LayoutItem &builder) override + void addToLayout(Layouting::LayoutItem &builder) override { addMutableAction(m_mainWidget); builder.addItem(m_mainWidget); diff --git a/tests/manual/layoutbuilder/demo/main.cpp b/tests/manual/layoutbuilder/demo/main.cpp index 249c159302b..fe8d7541ba3 100644 --- a/tests/manual/layoutbuilder/demo/main.cpp +++ b/tests/manual/layoutbuilder/demo/main.cpp @@ -1,12 +1,16 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + #include "layoutbuilder.h" #include -#include using namespace Layouting; int main(int argc, char *argv[]) { + Id textId; + Application app { resize(600, 400), @@ -14,18 +18,22 @@ int main(int argc, char *argv[]) Column { TextEdit { + id(textId), text("Hallo") }, - SpinBox { - text("Quit"), - onTextChanged([](const QString &text) { qDebug() << text; }) - }, + Row { + SpinBox { + onTextChanged([&](const QString &text) { setText(textId, text); }) + }, - PushButton { - text("Quit"), - onClicked([] { QApplication::quit(); }) - }, + Stretch(), + + PushButton { + text("Quit"), + onClicked([] { QApplication::quit(); }) + }, + } } }; From fe45294357c91385a09bb3bc914e7047081218b1 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 21 Apr 2023 11:32:38 +0200 Subject: [PATCH 0852/1447] Wizards: Remove build system step from Qt Quick Application wizard Qbs is now covered by the "compat" wizard This reverts commit 13cf1ee948d7164ddaa51186d9929cfc3bd20609. Change-Id: Ic11a6bd4847d08b60f77421ecbc168bc46c50c6a Reviewed-by: Reviewed-by: hjk Reviewed-by: Eike Ziller --- .../projects/qtquickapplication/tmpl.qbs | 21 -------- .../projects/qtquickapplication/wizard.json | 50 ++----------------- 2 files changed, 5 insertions(+), 66 deletions(-) delete mode 100644 share/qtcreator/templates/wizards/projects/qtquickapplication/tmpl.qbs diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/tmpl.qbs b/share/qtcreator/templates/wizards/projects/qtquickapplication/tmpl.qbs deleted file mode 100644 index 050ace84150..00000000000 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/tmpl.qbs +++ /dev/null @@ -1,21 +0,0 @@ -import qbs -CppApplication { -@if "%{UseVirtualKeyboard}" == "true" - Depends { name: "Qt"; submodules: ["quick", "virtualkeyboard"] } -@else - Depends { name: "Qt.quick" } -@endif - install: true - // Additional import path used to resolve QML modules in Qt Creator's code model - property pathList qmlImportPaths: [] - - files: [ - "%{MainCppFileName}", - ] - - Group { - Qt.core.resourcePrefix: "%{ProjectName}/" - fileTags: ["qt.qml.qml", "qt.core.resource_data"] - files: ["Main.qml"] - } -} diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index 205f5ddafd0..aef71de2fe2 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -1,6 +1,6 @@ { "version": 1, - "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject", "QbsProjectManager.QbsProject" ], + "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ], "id": "U.QtQuickApplicationEmpty", "category": "D.ApplicationQt", "trDescription": "Creates a Qt Quick application that can have both QML and C++ code. You can build the application and deploy it to desktop, embedded, and mobile target platforms.\n\nYou can select an option to create a project that you can open in Qt Design Studio, which has a visual editor for Qt Quick UIs.", @@ -9,11 +9,11 @@ "icon": "icon.png", "iconKind": "Themed", "featuresRequired": [ "QtSupport.Wizards.FeatureQtQmlCMakeApi" ], - "enabled": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 }", + "enabled": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0 }", "options": [ - { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'cmake' ? '%{ProjectDirectory}/CMakeLists.txt' : '%{ProjectDirectory}/' + '%{ProjectName}'.toLowerCase() + '.qbs' }" }, + { "key": "ProjectFile", "value": "%{ProjectDirectory}/CMakeLists.txt" }, { "key": "MainCppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }" }, { "key": "UseVirtualKeyboardByDefault", "value": "%{JS: value('Plugins').indexOf('Boot2Qt') >= 0 || value('Plugins').indexOf('Boot2QtQdb') >= 0 }" }, { "key": "TargetName", "value": "%{JS: 'app' + value('ProjectName') }" }, @@ -22,7 +22,6 @@ { "key": "UsesAutoResourcePrefix", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.4' && value('BuildSystem') === 'cmake' }"}, { "key": "HasLoadFromModule", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.4' && value('UsesAutoResourcePrefix') }"}, { "key": "QdsWizardPath", "value": "%{IDE:ResourcePath}/qmldesigner/studio_templates/projects" }, - { "key": "QdsProjectStyle", "value": "%{JS: value('BuildSystem') === 'cmake' ? %{QdsProjectStyleInput} : false }" }, { "key": "NoQdsProjectStyle", "value": "%{JS: !%{QdsProjectStyle} }" }, { "key": "ImportModuleName", "value": "%{ProjectName}" }, @@ -47,38 +46,6 @@ "trShortTitle": "Location", "typeId": "Project" }, - { - "trDisplayName": "Define Build System", - "trShortTitle": "Build System", - "typeId": "Fields", - "enabled": "%{JS: ! %{IsSubproject}}", - "data": - [ - { - "name": "BuildSystem", - "trDisplayName": "Build system:", - "type": "ComboBox", - "persistenceKey": "BuildSystemType", - "data": - { - "index": 0, - "items": - [ - { - "trKey": "CMake", - "value": "cmake", - "condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}" - }, - { - "trKey": "Qbs", - "value": "qbs", - "condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}" - } - ] - } - } - ] - }, { "trDisplayName": "Define Project Details", "trShortTitle": "Details", @@ -86,12 +53,11 @@ "data": [ { - "name": "QdsProjectStyleInput", + "name": "QdsProjectStyle", "trDisplayName": "Create a project that you can open in Qt Design Studio", "trToolTip": "Create a project with a structure that is compatible both with Qt Design Studio (via .qmlproject) and with Qt Creator (via CMakeLists.txt). It contains a .ui.qml form that you can visually edit in Qt Design Studio.", "type": "CheckBox", "span": true, - "visible": "%{JS: value('BuildSystem') === 'cmake'}", "persistenceKey": "QtQuick.QdsProjectStyle", "data": { @@ -146,13 +112,7 @@ { "source": "CMakeLists.txt", "openAsProject": true, - "condition": "%{JS: %{NoQdsProjectStyle} && value('BuildSystem') === 'cmake' }" - }, - { - "source": "tmpl.qbs", - "target": "%{ProjectFile}", - "openAsProject": true, - "condition": "%{JS: value('BuildSystem') === 'qbs' }" + "condition": "%{NoQdsProjectStyle}" }, { "source": "main.cpp", From 1e1befd9eb608322bab41ee214c97d65af65066e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 6 Apr 2023 18:31:47 +0200 Subject: [PATCH 0853/1447] Proliferate pathListSeparator() Change-Id: I546107af6a88ad5901659a0a64485e4ebca3a164 Reviewed-by: Reviewed-by: hjk --- src/libs/utils/environment.cpp | 4 +--- src/libs/utils/namevalueitem.cpp | 12 ++---------- src/plugins/debugger/cdb/cdbengine.cpp | 5 +++-- tests/auto/environment/tst_environment.cpp | 2 +- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index cacd60fcd6f..977e63adb06 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -155,14 +155,13 @@ void Environment::prependOrSet(const QString &key, const QString &value, const Q void Environment::prependOrSetLibrarySearchPath(const FilePath &value) { QTC_CHECK(value.osType() == osType()); + const QChar sep = OsSpecificAspects::pathListSeparator(osType()); switch (osType()) { case OsTypeWindows: { - const QChar sep = ';'; prependOrSet("PATH", value.nativePath(), sep); break; } case OsTypeMac: { - const QChar sep = ':'; const QString nativeValue = value.nativePath(); prependOrSet("DYLD_LIBRARY_PATH", nativeValue, sep); prependOrSet("DYLD_FRAMEWORK_PATH", nativeValue, sep); @@ -170,7 +169,6 @@ void Environment::prependOrSetLibrarySearchPath(const FilePath &value) } case OsTypeLinux: case OsTypeOtherUnix: { - const QChar sep = ':'; prependOrSet("LD_LIBRARY_PATH", value.nativePath(), sep); break; } diff --git a/src/libs/utils/namevalueitem.cpp b/src/libs/utils/namevalueitem.cpp index 5fd3bc39eb9..adc7ff5afc9 100644 --- a/src/libs/utils/namevalueitem.cpp +++ b/src/libs/utils/namevalueitem.cpp @@ -118,14 +118,6 @@ static QString expand(const NameValueDictionary *dictionary, QString value) return value; } -enum : char { -#ifdef Q_OS_WIN - pathSepC = ';' -#else - pathSepC = ':' -#endif -}; - void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const { switch (op) { @@ -142,7 +134,7 @@ void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const const NameValueDictionary::const_iterator it = dictionary->constFind(name); if (it != dictionary->constEnd()) { QString v = dictionary->value(it); - const QChar pathSep{QLatin1Char(pathSepC)}; + const QChar pathSep = HostOsInfo::pathListSeparator(); int sepCount = 0; if (v.startsWith(pathSep)) ++sepCount; @@ -162,7 +154,7 @@ void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const const NameValueDictionary::const_iterator it = dictionary->constFind(name); if (it != dictionary->constEnd()) { QString v = dictionary->value(it); - const QChar pathSep{QLatin1Char(pathSepC)}; + const QChar pathSep = HostOsInfo::pathListSeparator(); int sepCount = 0; if (v.endsWith(pathSep)) ++sepCount; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index e3a2ba8ede8..5098ba6f24c 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -421,10 +421,11 @@ void CdbEngine::setupEngine() inferiorEnvironment.set(qtLoggingToConsoleKey, "0"); static const char cdbExtensionPathVariableC[] = "_NT_DEBUGGER_EXTENSION_PATH"; - inferiorEnvironment.prependOrSet(cdbExtensionPathVariableC, extensionFi.absolutePath(), {";"}); + const QString pSep = OsSpecificAspects::pathListSeparator(Utils::OsTypeWindows); + inferiorEnvironment.prependOrSet(cdbExtensionPathVariableC, extensionFi.absolutePath(), pSep); const QString oldCdbExtensionPath = qtcEnvironmentVariable(cdbExtensionPathVariableC); if (!oldCdbExtensionPath.isEmpty()) - inferiorEnvironment.appendOrSet(cdbExtensionPathVariableC, oldCdbExtensionPath, {";"}); + inferiorEnvironment.appendOrSet(cdbExtensionPathVariableC, oldCdbExtensionPath, pSep); m_process.setEnvironment(inferiorEnvironment); if (!sp.inferior.workingDirectory.isEmpty()) diff --git a/tests/auto/environment/tst_environment.cpp b/tests/auto/environment/tst_environment.cpp index 8aa0cbe063a..2fd11245f8a 100644 --- a/tests/auto/environment/tst_environment.cpp +++ b/tests/auto/environment/tst_environment.cpp @@ -363,7 +363,7 @@ void tst_Environment::pathChanges() QFETCH(QString, value); QFETCH(Environment, expected); - const QString sep = environment.osType() == OsTypeWindows ? ";" : ":"; + const QString sep = HostOsInfo::pathListSeparator(); if (prepend) environment.prependOrSet(variable, value, sep); From ca1e0dae56de06778fd4b91f331ec1c0bb87df39 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 4 May 2023 14:49:00 +0200 Subject: [PATCH 0854/1447] Utils: Introduce QTC_SCOPED_TIMER() QTC_SCOPED_TIMER() is a handly debug tool that measures the time spent in a block of code. It starts measuring the time when the line where it was placed is reached, and stops measuring the time when the current invocation exits the block in which it was placed (i.e. when QTC_SCOPED_TIMER() goes out of scope). The QTC_SCOPED_TIMER does two printouts: 1. When it starts - it prints the current time, filename and line number. 2. When it ends - it prints the current time, filename, line number and the timeout in ms. The QTC_SCOPED_TIMER() was added into qtcassert.h file on purpose, as this file is included already in most of the codebase. In this way, when it needs to be used, it's enough to add a QTC_SCOPED_TIMER() without adding extra #include. Example use case, after adding the "QTC_SCOPED_TIMER()" into ProjectExplorerPlugin::initialize() as a first line: SCOPED TIMER [14:46:57.959] in [_long_path_here_]/ projectexplorer.cpp:823 started SCOPED TIMER [14:46:58.087] in [_long_path_here_]/ projectexplorer.cpp:823 stopped with timeout: 127ms Change-Id: Iaed3f297c8aeb6e90dd9909e76fc9933599a39b6 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/utils/qtcassert.cpp | 28 ++++++++++++++++++++++++++++ src/libs/utils/qtcassert.h | 20 ++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/libs/utils/qtcassert.cpp b/src/libs/utils/qtcassert.cpp index 78baa41a4a8..019c223ef78 100644 --- a/src/libs/utils/qtcassert.cpp +++ b/src/libs/utils/qtcassert.cpp @@ -8,6 +8,8 @@ #include #include +#include + #if defined(Q_OS_UNIX) #include #include @@ -130,4 +132,30 @@ void writeAssertLocation(const char *msg) dumpBacktrace(maxdepth); } +using namespace std::chrono; + +class ScopedTimerPrivate +{ +public: + const char *m_fileName = nullptr; + const int m_line = 0; + const time_point m_start = system_clock::now(); +}; + +ScopedTimer::ScopedTimer(const char *fileName, int line) + : d(new ScopedTimerPrivate{fileName, line}) +{ + const QByteArray time = QTime::currentTime().toString(Qt::ISODateWithMs).toLatin1(); + qDebug("SCOPED TIMER [%s] in %s:%d started", time.data(), d->m_fileName, d->m_line); +} + +ScopedTimer::~ScopedTimer() +{ + const auto end = system_clock::now(); + const auto elapsed = duration_cast(end - d->m_start); + const QByteArray time = QTime::currentTime().toString(Qt::ISODateWithMs).toLatin1(); + qDebug("SCOPED TIMER [%s] in %s:%d stopped with timeout: %ldms", + time.data(), d->m_fileName, d->m_line, elapsed.count()); +} + } // namespace Utils diff --git a/src/libs/utils/qtcassert.h b/src/libs/utils/qtcassert.h index 8f6b2ec5b86..aab7ab93d09 100644 --- a/src/libs/utils/qtcassert.h +++ b/src/libs/utils/qtcassert.h @@ -5,9 +5,25 @@ #include "utils_global.h" +#include + namespace Utils { + QTCREATOR_UTILS_EXPORT void writeAssertLocation(const char *msg); QTCREATOR_UTILS_EXPORT void dumpBacktrace(int maxdepth); + +class ScopedTimerPrivate; + +class QTCREATOR_UTILS_EXPORT ScopedTimer +{ +public: + ScopedTimer(const char *fileName, int line); + ~ScopedTimer(); + +private: + std::unique_ptr d; +}; + } // Utils #define QTC_ASSERT_STRINGIFY_HELPER(x) #x @@ -21,3 +37,7 @@ QTCREATOR_UTILS_EXPORT void dumpBacktrace(int maxdepth); #define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0) #define QTC_CHECK(cond) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); } do {} while (0) #define QTC_GUARD(cond) ((Q_LIKELY(cond)) ? true : (QTC_ASSERT_STRING(#cond), false)) + +#define QTC_CONCAT_HELPER(x, y) x ## y +#define QTC_CONCAT(x, y) QTC_CONCAT_HELPER(x, y) +#define QTC_SCOPED_TIMER() ::Utils::ScopedTimer QTC_CONCAT(_qtc_scoped_timer_, __LINE__)(__FILE__, __LINE__) From 6aa02fe8043d23e57f1f1dc77fa971797a62d5ea Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 4 May 2023 09:54:24 +0200 Subject: [PATCH 0855/1447] Utils: Combine startStubProcess parameters Change-Id: Ic0515a3864687494bd1e280a82b91a5bafef46b1 Reviewed-by: Christian Stenger --- src/libs/utils/terminalhooks.cpp | 11 +++++------ src/libs/utils/terminalinterface.cpp | 9 +++++---- src/libs/utils/terminalinterface.h | 4 +--- src/plugins/terminal/terminalprocessimpl.cpp | 5 ++--- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index 355aefe2c22..07ebbd98d2f 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -42,8 +42,7 @@ class ExternalTerminalProcessImpl final : public TerminalInterface ~ProcessStubCreator() override = default; - expected_str startStubProcess(const CommandLine &cmd, - const ProcessSetupData &setupData) override + expected_str startStubProcess(const ProcessSetupData &setupData) override { const TerminalCommand terminal = TerminalCommand::terminalEmulator(); @@ -56,8 +55,8 @@ class ExternalTerminalProcessImpl final : public TerminalInterface f.write(QString("cd %1\n").arg(setupData.m_workingDirectory.nativePath()).toUtf8()); f.write("clear\n"); f.write(QString("exec '%1' %2\n") - .arg(cmd.executable().nativePath()) - .arg(cmd.arguments()) + .arg(setupData.m_commandLine.executable().nativePath()) + .arg(setupData.m_commandLine.arguments()) .toUtf8()); f.close(); @@ -94,7 +93,7 @@ class ExternalTerminalProcessImpl final : public TerminalInterface process->setWorkingDirectory(setupData.m_workingDirectory); if constexpr (HostOsInfo::isWindowsHost()) { - process->setCommand(cmd); + process->setCommand(setupData.m_commandLine); process->setCreateConsoleOnWindows(true); process->setProcessMode(ProcessMode::Writer); } else { @@ -102,7 +101,7 @@ class ExternalTerminalProcessImpl final : public TerminalInterface CommandLine cmdLine = {terminal.command, {}}; if (!extraArgsFromOptions.isEmpty()) cmdLine.addArgs(extraArgsFromOptions, CommandLine::Raw); - cmdLine.addCommandLineAsArgs(cmd, CommandLine::Raw); + cmdLine.addCommandLineAsArgs(setupData.m_commandLine, CommandLine::Raw); process->setCommand(cmdLine); } diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index bb193b4d98d..6972184e325 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -304,9 +304,7 @@ void TerminalInterface::start() expected_str result; QMetaObject::invokeMethod( d->stubCreator, - [this, &result] { - result = d->stubCreator->startStubProcess(m_setup.m_commandLine, m_setup); - }, + [this, &result] { result = d->stubCreator->startStubProcess(m_setup); }, d->stubCreator->thread() == QThread::currentThread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection); @@ -386,9 +384,12 @@ void TerminalInterface::start() QTC_ASSERT(d->stubCreator, return); + ProcessSetupData stubSetupData = m_setup; + stubSetupData.m_commandLine = cmd; + QMetaObject::invokeMethod( d->stubCreator, - [cmd, this] { d->stubCreator->startStubProcess(cmd, m_setup); }, + [stubSetupData, this] { d->stubCreator->startStubProcess(stubSetupData); }, d->stubCreator->thread() == QThread::currentThread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection); diff --git a/src/libs/utils/terminalinterface.h b/src/libs/utils/terminalinterface.h index 15b3a8c69e8..a1960e7b966 100644 --- a/src/libs/utils/terminalinterface.h +++ b/src/libs/utils/terminalinterface.h @@ -14,9 +14,7 @@ class TerminalInterfacePrivate; class StubCreator : public QObject { public: - virtual expected_str startStubProcess(const CommandLine &cmd, - const ProcessSetupData &setup) - = 0; + virtual expected_str startStubProcess(const ProcessSetupData &setup) = 0; }; class QTCREATOR_UTILS_EXPORT TerminalInterface : public ProcessInterface diff --git a/src/plugins/terminal/terminalprocessimpl.cpp b/src/plugins/terminal/terminalprocessimpl.cpp index 79e9b91708d..d371e1a654a 100644 --- a/src/plugins/terminal/terminalprocessimpl.cpp +++ b/src/plugins/terminal/terminalprocessimpl.cpp @@ -26,14 +26,13 @@ public: , m_process(interface) {} - expected_str startStubProcess(const CommandLine &cmd, - const ProcessSetupData &setup) override + expected_str startStubProcess(const ProcessSetupData &setup) override { const Id id = Id::fromString(setup.m_commandLine.executable().toUserOutput()); TerminalWidget *terminal = m_terminalPane->stoppedTerminalWithId(id); - const OpenTerminalParameters openParameters{cmd, + const OpenTerminalParameters openParameters{setup.m_commandLine, std::nullopt, std::nullopt, ExitBehavior::Keep, From 2c61eac1cbb8cc5c8c5e0295eb5ae68ddb921a2b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 8 May 2023 08:05:18 +0300 Subject: [PATCH 0856/1447] Git: Change default shortcuts for "Current Project" to Repository Current Project is misleading. Current Repository refers to the repository of the current file, which is much more expected for "everything around" actions (Diff, Log). Task-number: QTCREATORBUG-10170 Change-Id: I252f40cd3dfd9de184a889355b59f91bb64983dd Reviewed-by: Eike Ziller --- src/plugins/git/gitplugin.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 2f5716f8adc..1ef47ff6669 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -776,13 +776,11 @@ GitPluginPrivate::GitPluginPrivate() createProjectAction(currentProjectMenu, Tr::tr("Diff Current Project", "Avoid translating \"Diff\""), Tr::tr("Diff Project \"%1\"", "Avoid translating \"Diff\""), - "Git.DiffProject", context, true, &GitPluginPrivate::diffCurrentProject, - QKeySequence(useMacShortcuts ? Tr::tr("Meta+G,Meta+Shift+D") : Tr::tr("Alt+G,Alt+Shift+D"))); + "Git.DiffProject", context, true, &GitPluginPrivate::diffCurrentProject); createProjectAction(currentProjectMenu, Tr::tr("Log Project", "Avoid translating \"Log\""), Tr::tr("Log Project \"%1\"", "Avoid translating \"Log\""), - "Git.LogProject", context, true, &GitPluginPrivate::logProject, - QKeySequence(useMacShortcuts ? Tr::tr("Meta+G,Meta+K") : Tr::tr("Alt+G,Alt+K"))); + "Git.LogProject", context, true, &GitPluginPrivate::logProject); createProjectAction(currentProjectMenu, Tr::tr("Clean Project...", "Avoid translating \"Clean\""), Tr::tr("Clean Project \"%1\"...", "Avoid translating \"Clean\""), @@ -795,10 +793,12 @@ GitPluginPrivate::GitPluginPrivate() gitContainer->addMenu(localRepositoryMenu); createRepositoryAction(localRepositoryMenu, "Diff", "Git.DiffRepository", - context, true, &GitClient::diffRepository); + context, true, &GitClient::diffRepository, + QKeySequence(useMacShortcuts ? Tr::tr("Meta+G,Meta+Shift+D") : Tr::tr("Alt+G,Alt+Shift+D"))); createRepositoryAction(localRepositoryMenu, "Log", "Git.LogRepository", - context, true, std::bind(&GitPluginPrivate::logRepository, this)); + context, true, std::bind(&GitPluginPrivate::logRepository, this), + QKeySequence(useMacShortcuts ? Tr::tr("Meta+G,Meta+K") : Tr::tr("Alt+G,Alt+K"))); createRepositoryAction(localRepositoryMenu, "Reflog", "Git.ReflogRepository", context, true, std::bind(&GitPluginPrivate::reflogRepository, this)); From 8b3aa900da77b7dc8c5d42c86648ec45d5a28e7d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 5 May 2023 15:51:11 +0200 Subject: [PATCH 0857/1447] Utils: Move SearchResultItem/Color into Utils It's going to be reused inside FileSearch. Change-Id: I8993d7158ff31c311c2283d32bc43465a8946a52 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/searchresultitem.cpp | 59 ++++++++++++ .../find => libs/utils}/searchresultitem.h | 93 ++++++++----------- src/libs/utils/utils.qbs | 2 + src/plugins/clangcodemodel/clangdclient.h | 4 +- .../clangcodemodel/clangdfindreferences.h | 4 +- .../clangcodemodel/test/clangdtests.cpp | 34 +++---- src/plugins/clangcodemodel/test/clangdtests.h | 4 +- src/plugins/coreplugin/CMakeLists.txt | 2 - src/plugins/coreplugin/coreplugin.cpp | 3 +- src/plugins/coreplugin/coreplugin.qbs | 2 - .../editormanager/editormanager.cpp | 2 +- .../coreplugin/editormanager/editormanager.h | 10 +- .../coreplugin/find/searchresultcolor.h | 52 ----------- .../coreplugin/find/searchresulttreeitems.cpp | 11 ++- .../coreplugin/find/searchresulttreeitems.h | 13 ++- .../coreplugin/find/searchresulttreemodel.cpp | 3 + .../coreplugin/find/searchresulttreemodel.h | 6 +- .../coreplugin/find/searchresulttreeview.cpp | 5 +- .../coreplugin/find/searchresulttreeview.h | 8 +- .../coreplugin/find/searchresultwidget.h | 14 +-- .../coreplugin/find/searchresultwindow.cpp | 19 ++-- .../coreplugin/find/searchresultwindow.h | 22 ++--- src/plugins/cppeditor/cppfindreferences.cpp | 7 +- src/plugins/cppeditor/cppfindreferences.h | 19 ++-- src/plugins/cppeditor/cppindexingsupport.cpp | 14 +-- src/plugins/cppeditor/cppindexingsupport.h | 4 +- src/plugins/cppeditor/symbolsearcher_test.cpp | 6 +- src/plugins/cppeditor/symbolsfindfilter.h | 10 +- src/plugins/git/gitgrep.h | 11 ++- .../languageclientsymbolsupport.cpp | 30 +++--- .../languageclientsymbolsupport.h | 13 +-- .../qmljseditor/qmljsfindreferences.cpp | 7 +- src/plugins/qmljseditor/qmljsfindreferences.h | 9 +- .../findinfilessilversearcher.h | 2 +- src/plugins/texteditor/basefilefind.cpp | 4 +- src/plugins/texteditor/basefilefind.h | 18 ++-- tests/unit/unittest/compare-operators.h | 4 +- 38 files changed, 266 insertions(+), 265 deletions(-) create mode 100644 src/libs/utils/searchresultitem.cpp rename src/{plugins/coreplugin/find => libs/utils}/searchresultitem.h (58%) delete mode 100644 src/plugins/coreplugin/find/searchresultcolor.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index defbbf27943..e3bbfcf7a97 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -147,6 +147,7 @@ add_qtc_library(Utils runextensions.cpp runextensions.h savefile.cpp savefile.h scopedswap.h + searchresultitem.cpp searchresultitem.h set_algorithm.h settingsaccessor.cpp settingsaccessor.h settingsselector.cpp settingsselector.h diff --git a/src/libs/utils/searchresultitem.cpp b/src/libs/utils/searchresultitem.cpp new file mode 100644 index 00000000000..74881bd3962 --- /dev/null +++ b/src/libs/utils/searchresultitem.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "searchresultitem.h" + +namespace Utils { + +int Search::TextRange::length(const QString &text) const +{ + if (begin.line == end.line) + return end.column - begin.column; + + const int lineCount = end.line - begin.line; + int index = text.indexOf(QChar::LineFeed); + int currentLine = 1; + while (index > 0 && currentLine < lineCount) { + ++index; + index = text.indexOf(QChar::LineFeed, index); + ++currentLine; + } + + if (index < 0) + return 0; + + return index - begin.column + end.column; +} + +SearchResultColor::SearchResultColor(const QColor &textBg, const QColor &textFg, + const QColor &highlightBg, const QColor &highlightFg, + const QColor &functionBg, const QColor &functionFg) + : textBackground(textBg) + , textForeground(textFg) + , highlightBackground(highlightBg) + , highlightForeground(highlightFg) + , containingFunctionBackground(functionBg) + , containingFunctionForeground(functionFg) +{ + if (!highlightBackground.isValid()) + highlightBackground = textBackground; + if (!highlightForeground.isValid()) + highlightForeground = textForeground; + if (!containingFunctionBackground.isValid()) + containingFunctionBackground = textBackground; + if (!containingFunctionForeground.isValid()) + containingFunctionForeground = textForeground; +} + +QTCREATOR_UTILS_EXPORT size_t qHash(SearchResultColor::Style style, uint seed) +{ + int a = int(style); + return ::qHash(a, seed); +} + +void SearchResultItem::setMainRange(int line, int column, int length) +{ + m_mainRange = {{line, column}, {line, column + length}}; +} + +} // namespace Utils diff --git a/src/plugins/coreplugin/find/searchresultitem.h b/src/libs/utils/searchresultitem.h similarity index 58% rename from src/plugins/coreplugin/find/searchresultitem.h rename to src/libs/utils/searchresultitem.h index d33df65f0a0..558374704e8 100644 --- a/src/plugins/coreplugin/find/searchresultitem.h +++ b/src/libs/utils/searchresultitem.h @@ -1,82 +1,78 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "searchresultcolor.h" +#include "utils_global.h" #include #include +#include +#include #include #include #include #include -namespace Core { +namespace Utils { namespace Search { -class TextPosition +class QTCREATOR_UTILS_EXPORT TextPosition { public: - TextPosition() = default; - TextPosition(int line, int column) : line(line), column(column) {} - int line = -1; // (0 or -1 for no line number) int column = -1; // 0-based starting position for a mark (-1 for no mark) - bool operator<(const TextPosition &other) + bool operator<(const TextPosition &other) const { return line < other.line || (line == other.line && column < other.column); } }; -class TextRange +class QTCREATOR_UTILS_EXPORT TextRange { public: - TextRange() = default; - TextRange(TextPosition begin, TextPosition end) : begin(begin), end(end) {} - QString mid(const QString &text) const { return text.mid(begin.column, length(text)); } - - int length(const QString &text) const - { - if (begin.line == end.line) - return end.column - begin.column; - - const int lineCount = end.line - begin.line; - int index = text.indexOf(QChar::LineFeed); - int currentLine = 1; - while (index > 0 && currentLine < lineCount) { - ++index; - index = text.indexOf(QChar::LineFeed, index); - ++currentLine; - } - - if (index < 0) - return 0; - - return index - begin.column + end.column; - } + int length(const QString &text) const; TextPosition begin; TextPosition end; - bool operator<(const TextRange &other) - { return begin < other.begin; } + bool operator<(const TextRange &other) const { return begin < other.begin; } }; } // namespace Search -class CORE_EXPORT SearchResultItem +class QTCREATOR_UTILS_EXPORT SearchResultColor +{ +public: + enum class Style { Default, Alt1, Alt2 }; + + SearchResultColor() = default; + SearchResultColor(const QColor &textBg, const QColor &textFg, + const QColor &highlightBg, const QColor &highlightFg, + const QColor &functionBg, const QColor &functionFg); + + QColor textBackground; + QColor textForeground; + QColor highlightBackground; + QColor highlightForeground; + QColor containingFunctionBackground; + QColor containingFunctionForeground; + +private: + QTCREATOR_UTILS_EXPORT friend size_t qHash(Style style, uint seed); +}; + +using SearchResultColors = QHash; + +class QTCREATOR_UTILS_EXPORT SearchResultItem { public: QStringList path() const { return m_path; } void setPath(const QStringList &path) { m_path = path; } - void setFilePath(const Utils::FilePath &filePath) - { - m_path = QStringList{filePath.toUserOutput()}; - } + void setFilePath(const Utils::FilePath &filePath) { m_path = {filePath.toUserOutput()}; } QString lineText() const { return m_lineText; } void setLineText(const QString &text) { m_lineText = text; } @@ -89,14 +85,7 @@ public: Search::TextRange mainRange() const { return m_mainRange; } void setMainRange(const Search::TextRange &mainRange) { m_mainRange = mainRange; } - void setMainRange(int line, int column, int length) - { - m_mainRange = {}; - m_mainRange.begin.line = line; - m_mainRange.begin.column = column; - m_mainRange.end.line = m_mainRange.begin.line; - m_mainRange.end.column = m_mainRange.begin.column + length; - } + void setMainRange(int line, int column, int length); bool useTextEditorFont() const { return m_useTextEditorFont; } void setUseTextEditorFont(bool useTextEditorFont) { m_useTextEditorFont = useTextEditorFont; } @@ -109,9 +98,9 @@ public: std::optional containingFunctionName() const { return m_containingFunctionName; } - void setContainingFunctionName(std::optional containingFunctionName) + void setContainingFunctionName(const std::optional &containingFunctionName) { - m_containingFunctionName = std::move(containingFunctionName); + m_containingFunctionName = containingFunctionName; } private: @@ -126,7 +115,7 @@ private: std::optional m_containingFunctionName; }; -} // namespace Core +} // namespace Utils -Q_DECLARE_METATYPE(Core::SearchResultItem) -Q_DECLARE_METATYPE(Core::Search::TextPosition) +Q_DECLARE_METATYPE(Utils::SearchResultItem) +Q_DECLARE_METATYPE(Utils::Search::TextPosition) diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 4f628616a10..fa766b8bc4a 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -275,6 +275,8 @@ Project { "savefile.cpp", "savefile.h", "scopedswap.h", + "searchresultitem.cpp", + "searchresultitem.h", "set_algorithm.h", "settingsaccessor.cpp", "settingsaccessor.h", diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 6b495ddb73c..c8a71edf3ce 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -3,12 +3,12 @@ #pragma once -#include #include #include #include #include #include +#include #include @@ -119,7 +119,7 @@ public: signals: void indexingFinished(); - void foundReferences(const QList &items); + void foundReferences(const QList &items); void findUsagesDone(); void helpItemGathered(const Core::HelpItem &helpItem); void highlightingResultsReady(const TextEditor::HighlightingResults &results, diff --git a/src/plugins/clangcodemodel/clangdfindreferences.h b/src/plugins/clangcodemodel/clangdfindreferences.h index d904db31f41..c975fc164f3 100644 --- a/src/plugins/clangcodemodel/clangdfindreferences.h +++ b/src/plugins/clangcodemodel/clangdfindreferences.h @@ -3,9 +3,9 @@ #pragma once -#include #include #include +#include #include @@ -35,7 +35,7 @@ public: ~ClangdFindReferences(); signals: - void foundReferences(const QList &items); + void foundReferences(const QList &items); void done(); private: diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 1d9f4436648..5fdff3164d9 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -43,6 +43,7 @@ using namespace CppEditor::Tests; using namespace LanguageClient; using namespace ProjectExplorer; using namespace TextEditor; +using namespace Utils; namespace ClangCodeModel { namespace Internal { @@ -97,7 +98,7 @@ ClangdTest::~ClangdTest() delete m_projectDir; } -Utils::FilePath ClangdTest::filePath(const QString &fileName) const +FilePath ClangdTest::filePath(const QString &fileName) const { return m_projectDir->absolutePath(fileName); } @@ -139,7 +140,7 @@ void ClangdTest::initTestCase() { const QString clangdFromEnv = Utils::qtcEnvironmentVariable("QTC_CLANGD"); if (!clangdFromEnv.isEmpty()) - CppEditor::ClangdSettings::setClangdFilePath(Utils::FilePath::fromString(clangdFromEnv)); + CppEditor::ClangdSettings::setClangdFilePath(FilePath::fromString(clangdFromEnv)); const auto clangd = CppEditor::ClangdSettings::instance().clangdFilePath(); if (clangd.isEmpty() || !clangd.exists()) QSKIP("clangd binary not found"); @@ -408,13 +409,13 @@ void ClangdTestFollowSymbol::test() timer.setSingleShot(true); QEventLoop loop; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); - Utils::Link actualLink; - const auto handler = [&actualLink, &loop](const Utils::Link &l) { + Link actualLink; + const auto handler = [&actualLink, &loop](const Link &l) { actualLink = l; loop.quit(); }; QTextCursor cursor(doc->document()); - const int pos = Utils::Text::positionInText(doc->document(), sourceLine, sourceColumn); + const int pos = Text::positionInText(doc->document(), sourceLine, sourceColumn); cursor.setPosition(pos); client()->followSymbol(doc, cursor, nullptr, handler, true, goToType ? FollowTo::SymbolType : FollowTo::SymbolDef, false); @@ -520,15 +521,14 @@ void ClangdTestLocalReferences::test() QEventLoop loop; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); QList actualRanges; - const auto handler = [&actualRanges, &loop](const QString &symbol, - const Utils::Links &links, int) { - for (const Utils::Link &link : links) + const auto handler = [&actualRanges, &loop](const QString &symbol, const Links &links, int) { + for (const Link &link : links) actualRanges << Range(link.targetLine, link.targetColumn, symbol.length()); loop.quit(); }; QTextCursor cursor(doc->document()); - const int pos = Utils::Text::positionInText(doc->document(), sourceLine, sourceColumn); + const int pos = Text::positionInText(doc->document(), sourceLine, sourceColumn); cursor.setPosition(pos); client()->findLocalUsages(doc, cursor, std::move(handler)); timer.start(10000); @@ -659,7 +659,7 @@ void ClangdTestTooltips::test() connect(client(), &ClangdClient::helpItemGathered, &loop, handler); QTextCursor cursor(doc->document()); - const int pos = Utils::Text::positionInText(doc->document(), line, column); + const int pos = Text::positionInText(doc->document(), line, column); cursor.setPosition(pos); editor->editorWidget()->processTooltipRequest(cursor); @@ -1316,11 +1316,11 @@ void ClangdTestHighlighting::test() const TextEditor::TextDocument * const doc = document("highlighting.cpp"); QVERIFY(doc); - const int startPos = Utils::Text::positionInText(doc->document(), firstLine, startColumn); - const int endPos = Utils::Text::positionInText(doc->document(), lastLine, endColumn); + const int startPos = Text::positionInText(doc->document(), firstLine, startColumn); + const int endPos = Text::positionInText(doc->document(), lastLine, endColumn); const auto lessThan = [=](const TextEditor::HighlightingResult &r, int) { - return Utils::Text::positionInText(doc->document(), r.line, r.column) < startPos; + return Text::positionInText(doc->document(), r.line, r.column) < startPos; }; const auto findResults = [=] { TextEditor::HighlightingResults results; @@ -1328,7 +1328,7 @@ void ClangdTestHighlighting::test() if (it == m_results.cend()) return results; while (it != m_results.cend()) { - const int resultEndPos = Utils::Text::positionInText(doc->document(), it->line, + const int resultEndPos = Text::positionInText(doc->document(), it->line, it->column) + it->length; if (resultEndPos > endPos) break; @@ -1439,7 +1439,7 @@ public: { const int pos = currentPosition(); QPair lineAndColumn; - Utils::Text::convertPosition(m_doc, pos, &lineAndColumn.first, &lineAndColumn.second); + Text::convertPosition(m_doc, pos, &lineAndColumn.first, &lineAndColumn.second); return lineAndColumn; } @@ -1864,7 +1864,7 @@ void ClangdTestCompletion::startCollectingHighlightingInfo() { m_documentsWithHighlighting.clear(); connect(client(), &ClangdClient::highlightingResultsReady, this, - [this](const HighlightingResults &, const Utils::FilePath &file) { + [this](const HighlightingResults &, const FilePath &file) { m_documentsWithHighlighting.insert(file); }); } @@ -1881,7 +1881,7 @@ void ClangdTestCompletion::getProposal(const QString &fileName, if (cursorPos) *cursorPos = pos; int line, column; - Utils::Text::convertPosition(doc->document(), pos, &line, &column); + Text::convertPosition(doc->document(), pos, &line, &column); const auto editor = qobject_cast( EditorManager::openEditorAt({doc->filePath(), line, column - 1})); QVERIFY(editor); diff --git a/src/plugins/clangcodemodel/test/clangdtests.h b/src/plugins/clangcodemodel/test/clangdtests.h index 2a8f33579c2..f5740db5ec6 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.h +++ b/src/plugins/clangcodemodel/test/clangdtests.h @@ -4,11 +4,11 @@ #pragma once #include -#include #include #include #include #include +#include #include #include @@ -74,7 +74,7 @@ private slots: void test(); private: - QList m_actualResults; + QList m_actualResults; }; class ClangdTestFollowSymbol : public ClangdTest diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index 17d1af01e39..a7d1e6cf20f 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -72,8 +72,6 @@ add_qtc_plugin(Core find/ifindsupport.cpp find/ifindsupport.h find/itemviewfind.cpp find/itemviewfind.h find/optionspopup.cpp find/optionspopup.h - find/searchresultcolor.h - find/searchresultitem.h find/searchresulttreeitemdelegate.cpp find/searchresulttreeitemdelegate.h find/searchresulttreeitemroles.h find/searchresulttreeitems.cpp find/searchresulttreeitems.h diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 043bdba74d1..448d8e6a33d 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,7 @@ void CorePlugin::setupSystemEnvironment() CorePlugin::CorePlugin() { qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 459183224ca..3adf5b461c2 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -306,8 +306,6 @@ Project { "itemviewfind.h", "optionspopup.cpp", "optionspopup.h", - "searchresultcolor.h", - "searchresultitem.h", "searchresulttreeitemdelegate.cpp", "searchresulttreeitemdelegate.h", "searchresulttreeitemroles.h", diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index f84465303fb..6f1856f162f 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -24,7 +24,6 @@ #include "../editormanager/ieditorfactory_p.h" #include "../editormanager/iexternaleditor.h" #include "../fileutils.h" -#include "../find/searchresultitem.h" #include "../findplaceholder.h" #include "../icore.h" #include "../iversioncontrol.h" @@ -52,6 +51,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 6118d15c3dd..09218f42c3e 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -22,18 +22,14 @@ QT_BEGIN_NAMESPACE class QMenu; QT_END_NAMESPACE -namespace Utils { class MimeType; } +namespace Utils { class SearchResultItem; } namespace Core { class IDocument; class LocatorFilterEntry; -class SearchResultItem; -namespace Internal { -class EditorManagerPrivate; -class MainWindow; -} // namespace Internal +namespace Internal { class MainWindow; } class CORE_EXPORT EditorManagerPlaceHolder final : public QWidget { @@ -79,7 +75,7 @@ public: bool *newEditor = nullptr); static IEditor *openEditor(const LocatorFilterEntry &entry); - static void openEditorAtSearchResult(const SearchResultItem &item, + static void openEditorAtSearchResult(const Utils::SearchResultItem &item, Utils::Id editorId = {}, OpenEditorFlags flags = NoFlags, bool *newEditor = nullptr); diff --git a/src/plugins/coreplugin/find/searchresultcolor.h b/src/plugins/coreplugin/find/searchresultcolor.h deleted file mode 100644 index a6bc46b4e18..00000000000 --- a/src/plugins/coreplugin/find/searchresultcolor.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "../core_global.h" - -#include -#include - -namespace Core { - -class CORE_EXPORT SearchResultColor -{ -public: - enum class Style { Default, Alt1, Alt2 }; - - SearchResultColor() = default; - SearchResultColor(const QColor &textBg, const QColor &textFg, - const QColor &highlightBg, const QColor &highlightFg, - const QColor &functionBg, const QColor &functionFg - ) - : textBackground(textBg), textForeground(textFg), - highlightBackground(highlightBg), highlightForeground(highlightFg), - containingFunctionBackground(functionBg),containingFunctionForeground(functionFg) - { - if (!highlightBackground.isValid()) - highlightBackground = textBackground; - if (!highlightForeground.isValid()) - highlightForeground = textForeground; - if (!containingFunctionBackground.isValid()) - containingFunctionBackground = textBackground; - if (!containingFunctionForeground.isValid()) - containingFunctionForeground = textForeground; - } - - friend auto qHash(SearchResultColor::Style style) - { - return QT_PREPEND_NAMESPACE(qHash(int(style))); - } - - QColor textBackground; - QColor textForeground; - QColor highlightBackground; - QColor highlightForeground; - QColor containingFunctionBackground; - QColor containingFunctionForeground; -}; - -using SearchResultColors = QHash; - -} // namespace Core diff --git a/src/plugins/coreplugin/find/searchresulttreeitems.cpp b/src/plugins/coreplugin/find/searchresulttreeitems.cpp index 79ccc2429d0..9aa8a765db9 100644 --- a/src/plugins/coreplugin/find/searchresulttreeitems.cpp +++ b/src/plugins/coreplugin/find/searchresulttreeitems.cpp @@ -3,10 +3,12 @@ #include "searchresulttreeitems.h" +#include + namespace Core { namespace Internal { -SearchResultTreeItem::SearchResultTreeItem(const SearchResultItem &item, +SearchResultTreeItem::SearchResultTreeItem(const Utils::SearchResultItem &item, SearchResultTreeItem *parent) : item(item), m_parent(parent), @@ -79,7 +81,8 @@ int SearchResultTreeItem::insertionIndex(const QString &text, SearchResultTreeIt return insertionPosition - m_children.begin(); } -int SearchResultTreeItem::insertionIndex(const SearchResultItem &item, SearchResultTreeItem **existingItem) const +int SearchResultTreeItem::insertionIndex(const Utils::SearchResultItem &item, + SearchResultTreeItem **existingItem) const { return insertionIndex(item.lineText(), existingItem); } @@ -89,13 +92,13 @@ void SearchResultTreeItem::insertChild(int index, SearchResultTreeItem *child) m_children.insert(index, child); } -void SearchResultTreeItem::insertChild(int index, const SearchResultItem &item) +void SearchResultTreeItem::insertChild(int index, const Utils::SearchResultItem &item) { auto child = new SearchResultTreeItem(item, this); insertChild(index, child); } -void SearchResultTreeItem::appendChild(const SearchResultItem &item) +void SearchResultTreeItem::appendChild(const Utils::SearchResultItem &item) { insertChild(m_children.count(), item); } diff --git a/src/plugins/coreplugin/find/searchresulttreeitems.h b/src/plugins/coreplugin/find/searchresulttreeitems.h index 4d4b3530393..dbbc27d8861 100644 --- a/src/plugins/coreplugin/find/searchresulttreeitems.h +++ b/src/plugins/coreplugin/find/searchresulttreeitems.h @@ -5,8 +5,7 @@ #include "searchresultwindow.h" -#include -#include +#include namespace Core { namespace Internal { @@ -14,7 +13,7 @@ namespace Internal { class SearchResultTreeItem { public: - explicit SearchResultTreeItem(const SearchResultItem &item = SearchResultItem(), + explicit SearchResultTreeItem(const Utils::SearchResultItem &item = {}, SearchResultTreeItem *parent = nullptr); virtual ~SearchResultTreeItem(); @@ -22,10 +21,10 @@ public: SearchResultTreeItem *parent() const; SearchResultTreeItem *childAt(int index) const; int insertionIndex(const QString &text, SearchResultTreeItem **existingItem) const; - int insertionIndex(const SearchResultItem &item, SearchResultTreeItem **existingItem) const; + int insertionIndex(const Utils::SearchResultItem &item, SearchResultTreeItem **existingItem) const; void insertChild(int index, SearchResultTreeItem *child); - void insertChild(int index, const SearchResultItem &item); - void appendChild(const SearchResultItem &item); + void insertChild(int index, const Utils::SearchResultItem &item); + void appendChild(const Utils::SearchResultItem &item); int childrenCount() const; int rowOfItem() const; void clearChildren(); @@ -36,7 +35,7 @@ public: bool isGenerated() const { return m_isGenerated; } void setGenerated(bool value) { m_isGenerated = value; } - SearchResultItem item; + Utils::SearchResultItem item; private: SearchResultTreeItem *m_parent; diff --git a/src/plugins/coreplugin/find/searchresulttreemodel.cpp b/src/plugins/coreplugin/find/searchresulttreemodel.cpp index cf00cf755a2..6692848f9f8 100644 --- a/src/plugins/coreplugin/find/searchresulttreemodel.cpp +++ b/src/plugins/coreplugin/find/searchresulttreemodel.cpp @@ -6,12 +6,15 @@ #include "searchresulttreeitemroles.h" #include +#include #include #include #include #include +using namespace Utils; + namespace Core { namespace Internal { diff --git a/src/plugins/coreplugin/find/searchresulttreemodel.h b/src/plugins/coreplugin/find/searchresulttreemodel.h index 6727fc56b4c..37f163fe0ad 100644 --- a/src/plugins/coreplugin/find/searchresulttreemodel.h +++ b/src/plugins/coreplugin/find/searchresulttreemodel.h @@ -4,7 +4,6 @@ #pragma once #include "searchresultwindow.h" -#include "searchresultcolor.h" #include #include @@ -25,8 +24,9 @@ public: void setFilter(SearchResultFilter *filter); void setShowReplaceUI(bool show); - void setTextEditorFont(const QFont &font, const SearchResultColors &colors); - QList addResults(const QList &items, SearchResult::AddMode mode); + void setTextEditorFont(const QFont &font, const Utils::SearchResultColors &colors); + QList addResults(const QList &items, + SearchResult::AddMode mode); void clear(); QModelIndex next(const QModelIndex &idx, bool includeGenerated = false, bool *wrapped = nullptr) const; diff --git a/src/plugins/coreplugin/find/searchresulttreeview.cpp b/src/plugins/coreplugin/find/searchresulttreeview.cpp index e5ac5b4719c..dca9f0835d0 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.cpp +++ b/src/plugins/coreplugin/find/searchresulttreeview.cpp @@ -7,11 +7,14 @@ #include "searchresulttreeitemdelegate.h" #include +#include #include #include #include +using namespace Utils; + namespace Core { namespace Internal { @@ -31,7 +34,7 @@ public: }; SearchResultTreeView::SearchResultTreeView(QWidget *parent) - : Utils::TreeView(parent) + : TreeView(parent) , m_model(new SearchResultFilterModel(this)) , m_autoExpandResults(false) { diff --git a/src/plugins/coreplugin/find/searchresulttreeview.h b/src/plugins/coreplugin/find/searchresulttreeview.h index 9ddbb06cd15..4e81ed86920 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.h +++ b/src/plugins/coreplugin/find/searchresulttreeview.h @@ -6,9 +6,9 @@ #include "searchresultwindow.h" #include +#include namespace Core { -class SearchResultColor; namespace Internal { @@ -22,11 +22,11 @@ public: explicit SearchResultTreeView(QWidget *parent = nullptr); void setAutoExpandResults(bool expand); - void setTextEditorFont(const QFont &font, const SearchResultColors &colors); + void setTextEditorFont(const QFont &font, const Utils::SearchResultColors &colors); void setTabWidth(int tabWidth); SearchResultFilterModel *model() const; - void addResults(const QList &items, SearchResult::AddMode mode); + void addResults(const QList &items, SearchResult::AddMode mode); void setFilter(SearchResultFilter *filter); bool hasFilter() const; void showFilterWidget(QWidget *parent); @@ -35,7 +35,7 @@ public: bool event(QEvent *e) override; signals: - void jumpToSearchResult(const SearchResultItem &item); + void jumpToSearchResult(const Utils::SearchResultItem &item); void filterInvalidated(); void filterChanged(); diff --git a/src/plugins/coreplugin/find/searchresultwidget.h b/src/plugins/coreplugin/find/searchresultwidget.h index 8ec0096a601..3761606ccce 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.h +++ b/src/plugins/coreplugin/find/searchresultwidget.h @@ -6,6 +6,7 @@ #include "searchresultwindow.h" #include +#include #include @@ -33,7 +34,7 @@ public: QWidget *additionalReplaceWidget() const; void setAdditionalReplaceWidget(QWidget *widget); - void addResults(const QList &items, SearchResult::AddMode mode); + void addResults(const QList &items, SearchResult::AddMode mode); int count() const; bool isSearching() const { return m_searching; } @@ -52,7 +53,7 @@ public: void notifyVisibilityChanged(bool visible); - void setTextEditorFont(const QFont &font, const SearchResultColors &colors); + void setTextEditorFont(const QFont &font, const Utils::SearchResultColors &colors); void setTabWidth(int tabWidth); void setAutoExpandResults(bool expand); @@ -76,8 +77,9 @@ public slots: void sendRequestPopup(); signals: - void activated(const Core::SearchResultItem &item); - void replaceButtonClicked(const QString &replaceText, const QList &checkedItems, bool preserveCase); + void activated(const Utils::SearchResultItem &item); + void replaceButtonClicked(const QString &replaceText, + const QList &checkedItems, bool preserveCase); void replaceTextChanged(const QString &replaceText); void searchAgainRequested(); void canceled(); @@ -91,7 +93,7 @@ signals: void navigateStateChanged(); private: - void handleJumpToSearchResult(const SearchResultItem &item); + void handleJumpToSearchResult(const Utils::SearchResultItem &item); void handleReplaceButton(); void doReplace(); void cancel(); @@ -101,7 +103,7 @@ private: void continueAfterSizeWarning(); void cancelAfterSizeWarning(); - QList checkedItems() const; + QList checkedItems() const; void updateMatchesFoundLabel(); SearchResultTreeView *m_searchResultTreeView = nullptr; diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index bd3fcc97d07..524629289fc 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -52,12 +52,6 @@ namespace Core { \internal */ -/*! - \class Core::SearchResultItem - \inmodule QtCreator - \internal -*/ - namespace Internal { class InternalScrollArea : public QScrollArea @@ -110,7 +104,7 @@ namespace Internal { QList m_searchResults; int m_currentIndex; QFont m_font; - SearchResultColors m_colors; + Utils::SearchResultColors m_colors; int m_tabWidth; }; @@ -260,14 +254,14 @@ using namespace Core::Internal; */ /*! - \fn void Core::SearchResult::activated(const Core::SearchResultItem &item) + \fn void Core::SearchResult::activated(const Utils::SearchResultItem &item) Indicates that the user activated the search result \a item by double-clicking it, for example. */ /*! \fn void Core::SearchResult::replaceButtonClicked(const QString &replaceText, - const QList &checkedItems, + const QList &checkedItems, bool preserveCase) Indicates that the user initiated a text replace by selecting @@ -577,7 +571,8 @@ void SearchResultWindow::setFocus() /*! \internal */ -void SearchResultWindow::setTextEditorFont(const QFont &font, const SearchResultColors &colors) +void SearchResultWindow::setTextEditorFont(const QFont &font, + const Utils::SearchResultColors &colors) { d->m_font = font; d->m_colors = colors; @@ -837,7 +832,7 @@ void SearchResult::setAdditionalReplaceWidget(QWidget *widget) \sa addResults() */ -void SearchResult::addResult(const SearchResultItem &item) +void SearchResult::addResult(const Utils::SearchResultItem &item) { m_widget->addResults({item}, AddOrdered); } @@ -848,7 +843,7 @@ void SearchResult::addResult(const SearchResultItem &item) \sa addResult() */ -void SearchResult::addResults(const QList &items, AddMode mode) +void SearchResult::addResults(const QList &items, AddMode mode) { m_widget->addResults(items, mode); emit countChanged(m_widget->count()); diff --git a/src/plugins/coreplugin/find/searchresultwindow.h b/src/plugins/coreplugin/find/searchresultwindow.h index da1bcf67e41..d2a0dc8d31c 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.h +++ b/src/plugins/coreplugin/find/searchresultwindow.h @@ -3,11 +3,10 @@ #pragma once -#include "searchresultcolor.h" -#include "searchresultitem.h" - #include +#include + #include #include #include @@ -19,9 +18,10 @@ class QFont; QT_END_NAMESPACE namespace Core { + namespace Internal { - class SearchResultWindowPrivate; - class SearchResultWidget; +class SearchResultWindowPrivate; +class SearchResultWidget; } class SearchResultWindow; @@ -31,7 +31,7 @@ class CORE_EXPORT SearchResultFilter : public QObject public: virtual QWidget *createWidget() = 0; - virtual bool matches(const SearchResultItem &item) const = 0; + virtual bool matches(const Utils::SearchResultItem &item) const = 0; signals: void filterChanged(); @@ -59,8 +59,8 @@ public: bool isInteractive() const { return !m_finishedHandler; } public slots: - void addResult(const SearchResultItem &item); - void addResults(const QList &items, AddMode mode); + void addResult(const Utils::SearchResultItem &item); + void addResults(const QList &items, AddMode mode); void setFilter(SearchResultFilter *filter); // Takes ownership void finishSearch(bool canceled, const QString &reason = {}); void setTextToReplace(const QString &textToReplace); @@ -70,8 +70,8 @@ public slots: void popup(); signals: - void activated(const Core::SearchResultItem &item); - void replaceButtonClicked(const QString &replaceText, const QList &checkedItems, bool preserveCase); + void activated(const Utils::SearchResultItem &item); + void replaceButtonClicked(const QString &replaceText, const QList &checkedItems, bool preserveCase); void replaceTextChanged(const QString &replaceText); void canceled(); void paused(bool paused); @@ -125,7 +125,7 @@ public: void goToPrev() override; bool canNavigate() const override; - void setTextEditorFont(const QFont &font, const SearchResultColors &colors); + void setTextEditorFont(const QFont &font, const Utils::SearchResultColors &colors); void setTabWidth(int width); void openNewSearchPanel(); diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index 17f599dca8e..6194e649cb4 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -743,10 +743,9 @@ void CppFindReferences::findMacroUses(const CPlusPlus::Macro ¯o, const QStri setupSearch(search); SearchResultWindow::instance()->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); - connect(search, &SearchResult::activated, - [](const Core::SearchResultItem& item) { - Core::EditorManager::openEditorAtSearchResult(item); - }); + connect(search, &SearchResult::activated, search, [](const SearchResultItem &item) { + Core::EditorManager::openEditorAtSearchResult(item); + }); const CPlusPlus::Snapshot snapshot = m_modelManager->snapshot(); const WorkingCopy workingCopy = m_modelManager->workingCopy(); diff --git a/src/plugins/cppeditor/cppfindreferences.h b/src/plugins/cppeditor/cppfindreferences.h index 54f40bf4cfe..cbd1a9bf4ab 100644 --- a/src/plugins/cppeditor/cppfindreferences.h +++ b/src/plugins/cppeditor/cppfindreferences.h @@ -9,30 +9,29 @@ #include #include #include +#include -#include -#include #include +#include #include -QT_FORWARD_DECLARE_CLASS(QTimer) +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE -namespace Core { -class SearchResultItem; -class SearchResult; -} // namespace Core +namespace Core { class SearchResult; } namespace CppEditor { class CppModelManager; -Core::SearchResultColor::Style CPPEDITOR_EXPORT +Utils::SearchResultColor::Style CPPEDITOR_EXPORT colorStyleForUsageType(CPlusPlus::Usage::Tags tags); class CPPEDITOR_EXPORT CppSearchResultFilter : public Core::SearchResultFilter { QWidget *createWidget() override; - bool matches(const Core::SearchResultItem &item) const override; + bool matches(const Utils::SearchResultItem &item) const override; void setValue(bool &member, bool value); @@ -79,7 +78,7 @@ public: private: void setupSearch(Core::SearchResult *search); void onReplaceButtonClicked(Core::SearchResult *search, const QString &text, - const QList &items, bool preserveCase); + const QList &items, bool preserveCase); void searchAgain(Core::SearchResult *search); void findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context, diff --git a/src/plugins/cppeditor/cppindexingsupport.cpp b/src/plugins/cppeditor/cppindexingsupport.cpp index 455355470b9..be150b2d393 100644 --- a/src/plugins/cppeditor/cppindexingsupport.cpp +++ b/src/plugins/cppeditor/cppindexingsupport.cpp @@ -10,13 +10,13 @@ #include "cppsourceprocessor.h" #include "searchsymbols.h" -#include #include #include #include #include +#include #include #include @@ -54,7 +54,7 @@ class WriteTaskFileForDiagnostics public: WriteTaskFileForDiagnostics() { - const QString fileName = Utils::TemporaryDirectory::masterDirectoryPath() + const QString fileName = TemporaryDirectory::masterDirectoryPath() + "/qtc_findErrorsIndexing.diagnostics." + QDateTime::currentDateTime().toString("yyMMdd_HHmm") + ".tasks"; @@ -139,7 +139,7 @@ void indexFindErrors(QPromise &promise, const ParseParams params) BuiltinEditorDocumentParser parser(FilePath::fromString(file)); parser.setReleaseSourceAndAST(false); parser.update({CppModelManager::instance()->workingCopy(), nullptr, - Utils::Language::Cxx, false}); + Language::Cxx, false}); CPlusPlus::Document::Ptr document = parser.document(); QTC_ASSERT(document, return); @@ -241,7 +241,7 @@ void parse(QPromise &promise, const ParseParams params) } // anonymous namespace -void SymbolSearcher::runSearch(QPromise &promise) +void SymbolSearcher::runSearch(QPromise &promise) { promise.setProgressRange(0, m_snapshot.size()); promise.setProgressValue(0); @@ -264,7 +264,7 @@ void SymbolSearcher::runSearch(QPromise &promise) if (promise.isCanceled()) break; if (m_fileNames.isEmpty() || m_fileNames.contains(it.value()->filePath().path())) { - QVector resultItems; + QList resultItems; auto filter = [&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult { if (matcher.match(info->symbolName()).hasMatch()) { QString text = info->symbolName(); @@ -277,7 +277,7 @@ void SymbolSearcher::runSearch(QPromise &promise) text = info->representDeclaration(); } - Core::SearchResultItem item; + SearchResultItem item; item.setPath(scope.split(QLatin1String("::"), Qt::SkipEmptyParts)); item.setLineText(text); item.setIcon(info->icon()); @@ -288,7 +288,7 @@ void SymbolSearcher::runSearch(QPromise &promise) return IndexItem::Recurse; }; search(it.value())->visitAllChildren(filter); - for (const Core::SearchResultItem &item : std::as_const(resultItems)) + for (const SearchResultItem &item : std::as_const(resultItems)) promise.addResult(item); } ++it; diff --git a/src/plugins/cppeditor/cppindexingsupport.h b/src/plugins/cppeditor/cppindexingsupport.h index 0c2f631aae3..b5aa68585d6 100644 --- a/src/plugins/cppeditor/cppindexingsupport.h +++ b/src/plugins/cppeditor/cppindexingsupport.h @@ -11,7 +11,7 @@ #include -namespace Core { class SearchResultItem; } +namespace Utils { class SearchResultItem; } namespace CppEditor { @@ -44,7 +44,7 @@ public: }; SymbolSearcher(const SymbolSearcher::Parameters ¶meters, const QSet &fileNames); - void runSearch(QPromise &promise); + void runSearch(QPromise &promise); private: const CPlusPlus::Snapshot m_snapshot; diff --git a/src/plugins/cppeditor/symbolsearcher_test.cpp b/src/plugins/cppeditor/symbolsearcher_test.cpp index 009afae5d50..ade5b356207 100644 --- a/src/plugins/cppeditor/symbolsearcher_test.cpp +++ b/src/plugins/cppeditor/symbolsearcher_test.cpp @@ -35,10 +35,10 @@ public: return m_symbolName == other.m_symbolName && m_scope == other.m_scope; } - static ResultDataList fromSearchResultList(const QList &entries) + static ResultDataList fromSearchResultList(const QList &entries) { ResultDataList result; - for (const Core::SearchResultItem &entry : entries) + for (const Utils::SearchResultItem &entry : entries) result << ResultData(entry.lineText(), entry.path().join(QLatin1String("::"))); return result; } @@ -77,7 +77,7 @@ public: const QScopedPointer symbolSearcher( new SymbolSearcher(searchParameters, QSet{testFile})); - QFuture search + QFuture search = Utils::asyncRun(&SymbolSearcher::runSearch, symbolSearcher.data()); search.waitForFinished(); ResultDataList results = ResultData::fromSearchResultList(search.results()); diff --git a/src/plugins/cppeditor/symbolsfindfilter.h b/src/plugins/cppeditor/symbolsfindfilter.h index 61866aae4db..a77f5873606 100644 --- a/src/plugins/cppeditor/symbolsfindfilter.h +++ b/src/plugins/cppeditor/symbolsfindfilter.h @@ -6,7 +6,6 @@ #include "searchsymbols.h" #include -#include #include #include @@ -16,6 +15,7 @@ #include namespace Core { class SearchResult; } +namespace Utils { class SearchResultItem; } namespace CppEditor { class CppModelManager; @@ -52,10 +52,10 @@ signals: void symbolsToSearchChanged(); private: - void openEditor(const Core::SearchResultItem &item); + void openEditor(const Utils::SearchResultItem &item); - void addResults(QFutureWatcher *watcher, int begin, int end); - void finish(QFutureWatcher *watcher); + void addResults(QFutureWatcher *watcher, int begin, int end); + void finish(QFutureWatcher *watcher); void cancel(Core::SearchResult *search); void setPaused(Core::SearchResult *search, bool paused); void onTaskStarted(Utils::Id type); @@ -67,7 +67,7 @@ private: CppModelManager *m_manager; bool m_enabled; - QMap *, QPointer > m_watchers; + QMap *, QPointer > m_watchers; QPointer m_currentSearch; SearchSymbols::SymbolTypes m_symbolsToSearch; SearchScope m_scope; diff --git a/src/plugins/git/gitgrep.h b/src/plugins/git/gitgrep.h index 119751102c5..5df131baaba 100644 --- a/src/plugins/git/gitgrep.h +++ b/src/plugins/git/gitgrep.h @@ -5,9 +5,14 @@ #include -QT_FORWARD_DECLARE_CLASS(QCheckBox); +QT_BEGIN_NAMESPACE +class QCheckBox; +QT_END_NAMESPACE -namespace Utils { class FancyLineEdit; } +namespace Utils { +class FancyLineEdit; +class SearchResultItem; +} namespace Git::Internal { @@ -28,7 +33,7 @@ public: QFuture executeSearch( const TextEditor::FileFindParameters ¶meters, TextEditor::BaseFileFind *baseFileFind) override; - Core::IEditor *openEditor(const Core::SearchResultItem &item, + Core::IEditor *openEditor(const Utils::SearchResultItem &item, const TextEditor::FileFindParameters ¶meters) override; private: diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp index d67fc6580aa..73317fb6fe4 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.cpp +++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp @@ -193,7 +193,7 @@ bool SymbolSupport::supportsFindUsages(TextEditor::TextDocument *document) const struct ItemData { - Core::Search::TextRange range; + Utils::Search::TextRange range; QVariant userData; }; @@ -216,12 +216,12 @@ QStringList SymbolSupport::getFileContents(const Utils::FilePath &filePath) return fileContent.split("\n"); } -QList generateSearchResultItems( +QList generateSearchResultItems( const QMap> &rangesInDocument, Core::SearchResult *search = nullptr, bool limitToProjects = false) { - QList result; + QList result; const bool renaming = search && search->supportsReplace(); QString oldSymbolName; QVariantList userData; @@ -233,7 +233,7 @@ QList generateSearchResultItems( for (auto it = rangesInDocument.begin(); it != rangesInDocument.end(); ++it) { const Utils::FilePath &filePath = it.key(); - Core::SearchResultItem item; + Utils::SearchResultItem item; item.setFilePath(filePath); item.setUseTextEditorFont(true); if (renaming && limitToProjects) { @@ -264,7 +264,7 @@ QList generateSearchResultItems( return result; } -QList generateSearchResultItems( +QList generateSearchResultItems( const LanguageClientArray &locations, const DocumentUri::PathMapper &pathMapper) { if (locations.isNull()) @@ -291,7 +291,7 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re Tr::tr("Find References with %1 for:").arg(m_client->name()), "", wordUnderCursor); search->addResults(generateSearchResultItems(*result, m_client->hostPathMapper()), Core::SearchResult::AddOrdered); - connect(search, &Core::SearchResult::activated, [](const Core::SearchResultItem &item) { + connect(search, &Core::SearchResult::activated, [](const Utils::SearchResultItem &item) { Core::EditorManager::openEditorAtSearchResult(item); }); search->finishSearch(false); @@ -463,7 +463,7 @@ void SymbolSupport::requestRename(const TextDocumentPositionParams &positionPara search->popup(); } -QList generateReplaceItems(const WorkspaceEdit &edits, +QList generateReplaceItems(const WorkspaceEdit &edits, Core::SearchResult *search, bool limitToProjects, const DocumentUri::PathMapper &pathMapper) @@ -506,7 +506,7 @@ Core::SearchResult *SymbolSupport::createSearch(const TextDocumentPositionParams if (callback) search->makeNonInteractive(callback); - connect(search, &Core::SearchResult::activated, [](const Core::SearchResultItem &item) { + connect(search, &Core::SearchResult::activated, [](const Utils::SearchResultItem &item) { Core::EditorManager::openEditorAtSearchResult(item); }); connect(search, &Core::SearchResult::replaceTextChanged, this, [this, search, positionParams]() { @@ -524,7 +524,7 @@ Core::SearchResult *SymbolSupport::createSearch(const TextDocumentPositionParams connect(search, &Core::SearchResult::replaceButtonClicked, this, [this, search, resetConnection](const QString & /*replaceText*/, - const QList &checkedItems) { + const QList &checkedItems) { applyRename(checkedItems, search); disconnect(resetConnection); }); @@ -571,12 +571,12 @@ void SymbolSupport::handleRenameResponse(Core::SearchResult *search, } } -void SymbolSupport::applyRename(const QList &checkedItems, +void SymbolSupport::applyRename(const QList &checkedItems, Core::SearchResult *search) { QSet affectedNonOpenFilePaths; QMap> editsForDocuments; - for (const Core::SearchResultItem &item : checkedItems) { + for (const Utils::SearchResultItem &item : checkedItems) { const auto filePath = Utils::FilePath::fromString(item.path().value(0)); if (!m_client->documentForFilePath(filePath)) affectedNonOpenFilePaths << filePath; @@ -616,12 +616,12 @@ QString SymbolSupport::derivePlaceholder(const QString &oldSymbol, const QString return m_defaultSymbolMapper ? m_defaultSymbolMapper(oldSymbol) : oldSymbol; } -Core::Search::TextRange SymbolSupport::convertRange(const Range &range) +Utils::Search::TextRange SymbolSupport::convertRange(const Range &range) { - auto convertPosition = [](const Position &pos) { - return Core::Search::TextPosition(pos.line() + 1, pos.character()); + const auto convertPosition = [](const Position &pos) { + return Utils::Search::TextPosition{pos.line() + 1, pos.character()}; }; - return Core::Search::TextRange(convertPosition(range.start()), convertPosition(range.end())); + return {convertPosition(range.start()), convertPosition(range.end())}; } void SymbolSupport::setDefaultRenamingSymbolMapper(const SymbolMapper &mapper) diff --git a/src/plugins/languageclient/languageclientsymbolsupport.h b/src/plugins/languageclient/languageclientsymbolsupport.h index a4b910a9dbd..c9960c5c1c3 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.h +++ b/src/plugins/languageclient/languageclientsymbolsupport.h @@ -5,18 +5,15 @@ #include "languageclient_global.h" -#include #include #include +#include + #include -namespace Core { -class SearchResult; -class SearchResultItem; -} - +namespace Core { class SearchResult; } namespace LanguageServerProtocol { class MessageId; } namespace LanguageClient { @@ -46,7 +43,7 @@ public: const std::function &callback = {}, bool preferLowerCaseFileNames = true); - static Core::Search::TextRange convertRange(const LanguageServerProtocol::Range &range); + static Utils::Search::TextRange convertRange(const LanguageServerProtocol::Range &range); static QStringList getFileContents(const Utils::FilePath &filePath); using SymbolMapper = std::function; @@ -76,7 +73,7 @@ private: const std::function &callback, bool preferLowerCaseFileNames); void handleRenameResponse(Core::SearchResult *search, const LanguageServerProtocol::RenameRequest::Response &response); - void applyRename(const QList &checkedItems, Core::SearchResult *search); + void applyRename(const QList &checkedItems, Core::SearchResult *search); QString derivePlaceholder(const QString &oldSymbol, const QString &newSymbol); Client *m_client = nullptr; diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index 72e4f7c35d2..a660dbbb986 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -992,7 +992,7 @@ void FindReferences::displayResults(int first, int last) this, &FindReferences::onReplaceButtonClicked); } connect(m_currentSearch.data(), &SearchResult::activated, - [](const Core::SearchResultItem& item) { + [](const Utils::SearchResultItem& item) { Core::EditorManager::openEditorAtSearchResult(item); }); connect(m_currentSearch.data(), &SearchResult::canceled, this, &FindReferences::cancel); @@ -1013,7 +1013,7 @@ void FindReferences::displayResults(int first, int last) } for (int index = first; index != last; ++index) { Usage result = m_watcher.future().resultAt(index); - SearchResultItem item; + Utils::SearchResultItem item; item.setFilePath(result.path); item.setLineText(result.lineText); item.setMainRange(result.line, result.col, result.len); @@ -1041,7 +1041,8 @@ void FindReferences::setPaused(bool paused) m_watcher.setPaused(paused); } -void FindReferences::onReplaceButtonClicked(const QString &text, const QList &items, bool preserveCase) +void FindReferences::onReplaceButtonClicked(const QString &text, + const QList &items, bool preserveCase) { const Utils::FilePaths filePaths = TextEditor::BaseFileFind::replaceAll(text, items, diff --git a/src/plugins/qmljseditor/qmljsfindreferences.h b/src/plugins/qmljseditor/qmljsfindreferences.h index 22bdff0a954..b4040f080b3 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.h +++ b/src/plugins/qmljseditor/qmljsfindreferences.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -14,10 +15,7 @@ QT_FORWARD_DECLARE_CLASS(QTimer) -namespace Core { -class SearchResultItem; -class SearchResult; -} // namespace Core +namespace Core { class SearchResult; } namespace QmlJSEditor { @@ -64,7 +62,8 @@ private: void searchFinished(); void cancel(); void setPaused(bool paused); - void onReplaceButtonClicked(const QString &text, const QList &items, bool preserveCase); + void onReplaceButtonClicked(const QString &text, const QList &items, + bool preserveCase); QPointer m_currentSearch; QFutureWatcher m_watcher; diff --git a/src/plugins/silversearcher/findinfilessilversearcher.h b/src/plugins/silversearcher/findinfilessilversearcher.h index 3a5363d7137..af59e3d4b79 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.h +++ b/src/plugins/silversearcher/findinfilessilversearcher.h @@ -33,7 +33,7 @@ public: void writeSettings(QSettings *settings) const override; QFuture executeSearch( const TextEditor::FileFindParameters ¶meters, TextEditor::BaseFileFind *) override; - Core::IEditor *openEditor(const Core::SearchResultItem &item, + Core::IEditor *openEditor(const Utils::SearchResultItem &item, const TextEditor::FileFindParameters ¶meters) override; private: diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index f23d52ccb5e..5dabbda05b1 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -51,7 +51,7 @@ public: QVariant parameters() const override { return {}; } void readSettings(QSettings * /*settings*/) override {} void writeSettings(QSettings * /*settings*/) const override {} - QFuture executeSearch( + QFuture executeSearch( const TextEditor::FileFindParameters ¶meters, BaseFileFind *baseFileFind) override { @@ -65,7 +65,7 @@ public: TextDocument::openedTextDocumentContents()); } - Core::IEditor *openEditor(const Core::SearchResultItem &/*item*/, + Core::IEditor *openEditor(const SearchResultItem &/*item*/, const TextEditor::FileFindParameters &/*parameters*/) override { return nullptr; diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index 71811978146..53d085662a1 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -4,20 +4,24 @@ #pragma once #include "texteditor_global.h" -#include #include #include +#include +#include + #include -namespace Utils { class FileIterator; } namespace Core { class IEditor; class SearchResult; -class SearchResultItem; } // namespace Core +namespace Utils { +class FileIterator; +} + namespace TextEditor { namespace Internal { @@ -54,7 +58,7 @@ public: virtual void writeSettings(QSettings *settings) const = 0; virtual QFuture executeSearch( const FileFindParameters ¶meters, BaseFileFind *baseFileFind) = 0; - virtual Core::IEditor *openEditor(const Core::SearchResultItem &item, + virtual Core::IEditor *openEditor(const Utils::SearchResultItem &item, const FileFindParameters ¶meters) = 0; bool isEnabled() const; void setEnabled(bool enabled); @@ -82,7 +86,7 @@ public: /* returns the list of unique files that were passed in items */ static Utils::FilePaths replaceAll(const QString &txt, - const QList &items, + const QList &items, bool preserveCase = false); virtual Utils::FileIterator *files(const QStringList &nameFilters, const QStringList &exclusionFilters, @@ -111,9 +115,9 @@ signals: void currentSearchEngineChanged(); private: - void openEditor(Core::SearchResult *result, const Core::SearchResultItem &item); + void openEditor(Core::SearchResult *result, const Utils::SearchResultItem &item); void doReplace(const QString &txt, - const QList &items, + const QList &items, bool preserveCase); void hideHighlightAll(bool visible); void searchAgain(Core::SearchResult *search); diff --git a/tests/unit/unittest/compare-operators.h b/tests/unit/unittest/compare-operators.h index dc3b3357a2e..891fdfec034 100644 --- a/tests/unit/unittest/compare-operators.h +++ b/tests/unit/unittest/compare-operators.h @@ -3,9 +3,9 @@ #pragma once -#include +#include -namespace Core { +namespace Utils { namespace Search { inline From c879aeb56550494a27d12d004cff6fb6f42fc511 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 5 May 2023 19:12:47 +0200 Subject: [PATCH 0858/1447] SearchResultItem: Introduce SearchResultItems And reuse it. Change-Id: Ia052297340f2bf2478fbfdb2427b45e30bd9d067 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/utils/searchresultitem.h | 3 ++ src/plugins/clangcodemodel/clangdclient.h | 2 +- .../clangcodemodel/clangdfindreferences.cpp | 12 +++---- .../clangcodemodel/clangdfindreferences.h | 2 +- .../clangcodemodel/test/clangdtests.cpp | 33 +++++++++---------- src/plugins/clangcodemodel/test/clangdtests.h | 2 +- .../coreplugin/find/searchresulttreemodel.cpp | 15 +++++---- .../coreplugin/find/searchresulttreemodel.h | 2 +- .../coreplugin/find/searchresulttreeview.cpp | 2 +- .../coreplugin/find/searchresulttreeview.h | 2 +- .../coreplugin/find/searchresultwidget.cpp | 6 ++-- .../coreplugin/find/searchresultwidget.h | 6 ++-- .../coreplugin/find/searchresultwindow.cpp | 4 +-- .../coreplugin/find/searchresultwindow.h | 5 +-- src/plugins/cppeditor/cppfindreferences.cpp | 6 ++-- src/plugins/cppeditor/cppfindreferences.h | 2 +- src/plugins/cppeditor/cppindexingsupport.cpp | 2 +- src/plugins/cppeditor/symbolsearcher_test.cpp | 2 +- src/plugins/cppeditor/symbolsfindfilter.cpp | 2 +- .../languageclientsymbolsupport.cpp | 12 +++---- .../languageclientsymbolsupport.h | 2 +- .../qmljseditor/qmljsfindreferences.cpp | 4 +-- src/plugins/qmljseditor/qmljsfindreferences.h | 2 +- src/plugins/texteditor/basefilefind.cpp | 12 +++---- src/plugins/texteditor/basefilefind.h | 7 ++-- 25 files changed, 73 insertions(+), 76 deletions(-) diff --git a/src/libs/utils/searchresultitem.h b/src/libs/utils/searchresultitem.h index 558374704e8..ea0de8ceece 100644 --- a/src/libs/utils/searchresultitem.h +++ b/src/libs/utils/searchresultitem.h @@ -115,7 +115,10 @@ private: std::optional m_containingFunctionName; }; +using SearchResultItems = QList; + } // namespace Utils Q_DECLARE_METATYPE(Utils::SearchResultItem) +Q_DECLARE_METATYPE(Utils::SearchResultItems) Q_DECLARE_METATYPE(Utils::Search::TextPosition) diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index c8a71edf3ce..27ec66a3017 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -119,7 +119,7 @@ public: signals: void indexingFinished(); - void foundReferences(const QList &items); + void foundReferences(const Utils::SearchResultItems &items); void findUsagesDone(); void helpItemGathered(const Core::HelpItem &helpItem); void highlightingResultsReady(const TextEditor::HighlightingResults &results, diff --git a/src/plugins/clangcodemodel/clangdfindreferences.cpp b/src/plugins/clangcodemodel/clangdfindreferences.cpp index 12f860c87c1..b44fd41a828 100644 --- a/src/plugins/clangcodemodel/clangdfindreferences.cpp +++ b/src/plugins/clangcodemodel/clangdfindreferences.cpp @@ -72,7 +72,7 @@ public: const Position linkAsPosition; const QPointer search; const LinkHandler callback; - QList declDefItems; + SearchResultItems declDefItems; bool openedExtraFileForLink = false; bool declHasUsedTag = false; bool recursiveCallDetected = false; @@ -89,7 +89,7 @@ public: const SearchResult *search, const ReplacementData &replacementData, const QString &newSymbolName, - const QList &checkedItems, + const SearchResultItems &checkedItems, bool preserveCase); void handleFindUsagesResult(const QList &locations); void finishSearch(); @@ -143,7 +143,7 @@ ClangdFindReferences::ClangdFindReferences(ClangdClient *client, TextDocument *d d->search->setAdditionalReplaceWidget(renameFilesCheckBox); const auto renameHandler = [search = d->search](const QString &newSymbolName, - const QList &checkedItems, + const SearchResultItems &checkedItems, bool preserveCase) { const auto replacementData = search->userData().value(); Private::handleRenameRequest(search, replacementData, newSymbolName, checkedItems, @@ -151,7 +151,7 @@ ClangdFindReferences::ClangdFindReferences(ClangdClient *client, TextDocument *d }; connect(d->search, &SearchResult::replaceButtonClicked, renameHandler); } - connect(d->search, &SearchResult::activated, [](const SearchResultItem& item) { + connect(d->search, &SearchResult::activated, [](const SearchResultItem &item) { EditorManager::openEditorAtSearchResult(item); }); if (d->search->isInteractive()) @@ -243,7 +243,7 @@ void ClangdFindReferences::Private::handleRenameRequest( const SearchResult *search, const ReplacementData &replacementData, const QString &newSymbolName, - const QList &checkedItems, + const SearchResultItems &checkedItems, bool preserveCase) { const Utils::FilePaths filePaths = BaseFileFind::replaceAll(newSymbolName, checkedItems, @@ -391,7 +391,7 @@ static Usage::Tags getUsageType(const ClangdAstPath &path, const QString &search void ClangdFindReferences::Private::addSearchResultsForFile(const FilePath &file, const ReferencesFileData &fileData) { - QList items; + SearchResultItems items; qCDebug(clangdLog) << file << "has valid AST:" << fileData.ast.isValid(); const auto expectedDeclTypes = [this]() -> QStringList { if (checkUnusedData) diff --git a/src/plugins/clangcodemodel/clangdfindreferences.h b/src/plugins/clangcodemodel/clangdfindreferences.h index c975fc164f3..e110b355434 100644 --- a/src/plugins/clangcodemodel/clangdfindreferences.h +++ b/src/plugins/clangcodemodel/clangdfindreferences.h @@ -35,7 +35,7 @@ public: ~ClangdFindReferences(); signals: - void foundReferences(const QList &items); + void foundReferences(const Utils::SearchResultItems &items); void done(); private: diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 5fdff3164d9..e66515365b2 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -191,7 +191,7 @@ void ClangdTestFindReferences::initTestCase() ClangdTest::initTestCase(); CppEditor::codeModelSettings()->setCategorizeFindReferences(true); connect(client(), &ClangdClient::foundReferences, this, - [this](const QList &results) { + [this](const SearchResultItems &results) { if (results.isEmpty()) return; if (results.first().path().first().endsWith("defs.h")) @@ -205,8 +205,7 @@ void ClangdTestFindReferences::test_data() { QTest::addColumn("fileName"); QTest::addColumn("pos"); - using ItemList = QList; - QTest::addColumn("expectedResults"); + QTest::addColumn("expectedResults"); static const auto makeItem = [](int line, int column, Usage::Tags tags) { SearchResultItem item; @@ -215,7 +214,7 @@ void ClangdTestFindReferences::test_data() return item; }; - QTest::newRow("struct member") << "defs.h" << 55 << ItemList{ + QTest::newRow("struct member") << "defs.h" << 55 << SearchResultItems{ makeItem(2, 17, Usage::Tag::Read), makeItem(3, 15, Usage::Tag::Declaration), makeItem(6, 17, Usage::Tag::WritableRef), makeItem(8, 11, Usage::Tag::WritableRef), makeItem(9, 13, Usage::Tag::WritableRef), makeItem(10, 12, Usage::Tag::WritableRef), @@ -232,23 +231,23 @@ void ClangdTestFindReferences::test_data() makeItem(56, 7, Usage::Tag::Write), makeItem(56, 25, Usage::Tags()), makeItem(58, 13, Usage::Tag::Read), makeItem(58, 25, Usage::Tag::Read), makeItem(59, 7, Usage::Tag::Write), makeItem(59, 24, Usage::Tag::Read)}; - QTest::newRow("constructor member initialization") << "defs.h" << 68 << ItemList{ + QTest::newRow("constructor member initialization") << "defs.h" << 68 << SearchResultItems{ makeItem(2, 10, Usage::Tag::Write), makeItem(4, 8, Usage::Tag::Declaration)}; - QTest::newRow("direct member initialization") << "defs.h" << 101 << ItemList{ + QTest::newRow("direct member initialization") << "defs.h" << 101 << SearchResultItems{ makeItem(5, 21, Initialization), makeItem(45, 16, Usage::Tag::Read)}; - ItemList pureVirtualRefs{makeItem(17, 17, Usage::Tag::Declaration), + SearchResultItems pureVirtualRefs{makeItem(17, 17, Usage::Tag::Declaration), makeItem(21, 9, {Usage::Tag::Declaration, Usage::Tag::Override})}; QTest::newRow("pure virtual declaration") << "defs.h" << 420 << pureVirtualRefs; - QTest::newRow("pointer variable") << "main.cpp" << 52 << ItemList{ + QTest::newRow("pointer variable") << "main.cpp" << 52 << SearchResultItems{ makeItem(6, 10, Initialization), makeItem(8, 4, Usage::Tag::Write), makeItem(10, 4, Usage::Tag::Write), makeItem(24, 5, Usage::Tag::Write), makeItem(25, 11, Usage::Tag::WritableRef), makeItem(26, 11, Usage::Tag::Read), makeItem(27, 10, Usage::Tag::WritableRef), makeItem(28, 10, Usage::Tag::Read), makeItem(29, 11, Usage::Tag::Read), makeItem(30, 15, Usage::Tag::WritableRef), makeItem(31, 22, Usage::Tag::Read)}; - QTest::newRow("struct variable") << "main.cpp" << 39 << ItemList{ + QTest::newRow("struct variable") << "main.cpp" << 39 << SearchResultItems{ makeItem(5, 7, Usage::Tag::Declaration), makeItem(6, 15, Usage::Tag::WritableRef), makeItem(8, 9, Usage::Tag::WritableRef), makeItem(9, 11, Usage::Tag::WritableRef), makeItem(11, 4, Usage::Tag::Write), makeItem(11, 11, Usage::Tag::WritableRef), @@ -269,7 +268,7 @@ void ClangdTestFindReferences::test_data() // Some of these are conceptually questionable, as S is a type and thus we cannot "read from" // or "write to" it. But it probably matches the intuitive user expectation. - QTest::newRow("struct type") << "defs.h" << 7 << ItemList{ + QTest::newRow("struct type") << "defs.h" << 7 << SearchResultItems{ makeItem(1, 7, Usage::Tag::Declaration), makeItem(2, 4, (Usage::Tags{Usage::Tag::Declaration, Usage::Tag::ConstructorDestructor})), makeItem(20, 19, Usage::Tags()), makeItem(10, 9, Usage::Tag::WritableRef), @@ -281,24 +280,24 @@ void ClangdTestFindReferences::test_data() makeItem(58, 10, Usage::Tag::Read), makeItem(58, 22, Usage::Tag::Read), makeItem(59, 4, Usage::Tag::Write), makeItem(59, 21, Usage::Tag::Read)}; - QTest::newRow("struct type 2") << "defs.h" << 450 << ItemList{ + QTest::newRow("struct type 2") << "defs.h" << 450 << SearchResultItems{ makeItem(20, 7, Usage::Tag::Declaration), makeItem(5, 4, Usage::Tags()), makeItem(13, 21, Usage::Tags()), makeItem(32, 8, Usage::Tags())}; - QTest::newRow("constructor") << "defs.h" << 627 << ItemList{ + QTest::newRow("constructor") << "defs.h" << 627 << SearchResultItems{ makeItem(31, 4, (Usage::Tags{Usage::Tag::Declaration, Usage::Tag::ConstructorDestructor})), makeItem(36, 7, Usage::Tag::ConstructorDestructor)}; - QTest::newRow("subclass") << "defs.h" << 450 << ItemList{ + QTest::newRow("subclass") << "defs.h" << 450 << SearchResultItems{ makeItem(20, 7, Usage::Tag::Declaration), makeItem(5, 4, Usage::Tags()), makeItem(13, 21, Usage::Tags()), makeItem(32, 8, Usage::Tags())}; - QTest::newRow("array variable") << "main.cpp" << 1134 << ItemList{ + QTest::newRow("array variable") << "main.cpp" << 1134 << SearchResultItems{ makeItem(57, 8, Usage::Tag::Declaration), makeItem(58, 4, Usage::Tag::Write), makeItem(59, 15, Usage::Tag::Read)}; - QTest::newRow("free function") << "defs.h" << 510 << ItemList{ + QTest::newRow("free function") << "defs.h" << 510 << SearchResultItems{ makeItem(24, 5, Usage::Tag::Declaration), makeItem(19, 4, Usage::Tags()), makeItem(25, 4, Usage::Tags()), makeItem(60, 26, Usage::Tag::Read)}; - QTest::newRow("member function") << "defs.h" << 192 << ItemList{ + QTest::newRow("member function") << "defs.h" << 192 << SearchResultItems{ makeItem(9, 12, Usage::Tag::Declaration), makeItem(40, 8, Usage::Tags())}; } @@ -309,7 +308,7 @@ void ClangdTestFindReferences::test() { QFETCH(QString, fileName); QFETCH(int, pos); - QFETCH(QList, expectedResults); + QFETCH(SearchResultItems, expectedResults); TextEditor::TextDocument * const doc = document(fileName); QVERIFY(doc); diff --git a/src/plugins/clangcodemodel/test/clangdtests.h b/src/plugins/clangcodemodel/test/clangdtests.h index f5740db5ec6..90f4eca45af 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.h +++ b/src/plugins/clangcodemodel/test/clangdtests.h @@ -74,7 +74,7 @@ private slots: void test(); private: - QList m_actualResults; + Utils::SearchResultItems m_actualResults; }; class ClangdTestFollowSymbol : public ClangdTest diff --git a/src/plugins/coreplugin/find/searchresulttreemodel.cpp b/src/plugins/coreplugin/find/searchresulttreemodel.cpp index 6692848f9f8..769c63a6bca 100644 --- a/src/plugins/coreplugin/find/searchresulttreemodel.cpp +++ b/src/plugins/coreplugin/find/searchresulttreemodel.cpp @@ -41,7 +41,7 @@ public: QModelIndex next(const QModelIndex &idx, bool includeGenerated = false, bool *wrapped = nullptr) const; QModelIndex prev(const QModelIndex &idx, bool includeGenerated = false, bool *wrapped = nullptr) const; - QList addResults(const QList &items, SearchResult::AddMode mode); + QList addResults(const SearchResultItems &items, SearchResult::AddMode mode); static SearchResultTreeItem *treeItemAtIndex(const QModelIndex &idx); @@ -54,7 +54,7 @@ public slots: private: QModelIndex index(SearchResultTreeItem *item) const; - void addResultsToCurrentParent(const QList &items, SearchResult::AddMode mode); + void addResultsToCurrentParent(const SearchResultItems &items, SearchResult::AddMode mode); QSet addPath(const QStringList &path); QVariant data(const SearchResultTreeItem *row, int role) const; bool setCheckState(const QModelIndex &idx, Qt::CheckState checkState, bool firstCall = true); @@ -385,7 +385,8 @@ QSet SearchResultTreeModel::addPath(const QStringList &p return pathNodes; } -void SearchResultTreeModel::addResultsToCurrentParent(const QList &items, SearchResult::AddMode mode) +void SearchResultTreeModel::addResultsToCurrentParent(const SearchResultItems &items, + SearchResult::AddMode mode) { if (!m_currentParent) return; @@ -436,12 +437,12 @@ static bool lessThanByPath(const SearchResultItem &a, const SearchResultItem &b) * Adds the search result to the list of results, creating nodes for the path when * necessary. */ -QList SearchResultTreeModel::addResults(const QList &items, SearchResult::AddMode mode) +QList SearchResultTreeModel::addResults(const SearchResultItems &items, SearchResult::AddMode mode) { QSet pathNodes; - QList sortedItems = items; + SearchResultItems sortedItems = items; std::stable_sort(sortedItems.begin(), sortedItems.end(), lessThanByPath); - QList itemSet; + SearchResultItems itemSet; for (const SearchResultItem &item : sortedItems) { m_editorFontIsUsed |= item.useTextEditorFont(); if (!m_currentParent || (m_currentPath != item.path())) { @@ -580,7 +581,7 @@ void SearchResultFilterModel::setTextEditorFont(const QFont &font, const SearchR sourceModel()->setTextEditorFont(font, colors); } -QList SearchResultFilterModel::addResults(const QList &items, +QList SearchResultFilterModel::addResults(const SearchResultItems &items, SearchResult::AddMode mode) { QList sourceIndexes = sourceModel()->addResults(items, mode); diff --git a/src/plugins/coreplugin/find/searchresulttreemodel.h b/src/plugins/coreplugin/find/searchresulttreemodel.h index 37f163fe0ad..716bcccca32 100644 --- a/src/plugins/coreplugin/find/searchresulttreemodel.h +++ b/src/plugins/coreplugin/find/searchresulttreemodel.h @@ -25,7 +25,7 @@ public: void setFilter(SearchResultFilter *filter); void setShowReplaceUI(bool show); void setTextEditorFont(const QFont &font, const Utils::SearchResultColors &colors); - QList addResults(const QList &items, + QList addResults(const Utils::SearchResultItems &items, SearchResult::AddMode mode); void clear(); QModelIndex next(const QModelIndex &idx, bool includeGenerated = false, diff --git a/src/plugins/coreplugin/find/searchresulttreeview.cpp b/src/plugins/coreplugin/find/searchresulttreeview.cpp index dca9f0835d0..d8026ccd847 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.cpp +++ b/src/plugins/coreplugin/find/searchresulttreeview.cpp @@ -73,7 +73,7 @@ void SearchResultTreeView::clear() m_model->clear(); } -void SearchResultTreeView::addResults(const QList &items, SearchResult::AddMode mode) +void SearchResultTreeView::addResults(const SearchResultItems &items, SearchResult::AddMode mode) { const QList addedParents = m_model->addResults(items, mode); if (m_autoExpandResults && !addedParents.isEmpty()) { diff --git a/src/plugins/coreplugin/find/searchresulttreeview.h b/src/plugins/coreplugin/find/searchresulttreeview.h index 4e81ed86920..06996fefe09 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.h +++ b/src/plugins/coreplugin/find/searchresulttreeview.h @@ -26,7 +26,7 @@ public: void setTabWidth(int tabWidth); SearchResultFilterModel *model() const; - void addResults(const QList &items, SearchResult::AddMode mode); + void addResults(const Utils::SearchResultItems &items, SearchResult::AddMode mode); void setFilter(SearchResultFilter *filter); bool hasFilter() const; void showFilterWidget(QWidget *parent); diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp index 5959cd40fda..ec2ab2c0f64 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.cpp +++ b/src/plugins/coreplugin/find/searchresultwidget.cpp @@ -226,7 +226,7 @@ void SearchResultWidget::setAdditionalReplaceWidget(QWidget *widget) m_additionalReplaceWidget = widget; } -void SearchResultWidget::addResults(const QList &items, SearchResult::AddMode mode) +void SearchResultWidget::addResults(const SearchResultItems &items, SearchResult::AddMode mode) { bool firstItems = (m_count == 0); m_count += items.size(); @@ -496,9 +496,9 @@ void SearchResultWidget::searchAgain() emit searchAgainRequested(); } -QList SearchResultWidget::checkedItems() const +SearchResultItems SearchResultWidget::checkedItems() const { - QList result; + SearchResultItems result; SearchResultFilterModel *model = m_searchResultTreeView->model(); const int fileCount = model->rowCount(); for (int i = 0; i < fileCount; ++i) { diff --git a/src/plugins/coreplugin/find/searchresultwidget.h b/src/plugins/coreplugin/find/searchresultwidget.h index 3761606ccce..6722af579eb 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.h +++ b/src/plugins/coreplugin/find/searchresultwidget.h @@ -34,7 +34,7 @@ public: QWidget *additionalReplaceWidget() const; void setAdditionalReplaceWidget(QWidget *widget); - void addResults(const QList &items, SearchResult::AddMode mode); + void addResults(const Utils::SearchResultItems &items, SearchResult::AddMode mode); int count() const; bool isSearching() const { return m_searching; } @@ -79,7 +79,7 @@ public slots: signals: void activated(const Utils::SearchResultItem &item); void replaceButtonClicked(const QString &replaceText, - const QList &checkedItems, bool preserveCase); + const Utils::SearchResultItems &checkedItems, bool preserveCase); void replaceTextChanged(const QString &replaceText); void searchAgainRequested(); void canceled(); @@ -103,7 +103,7 @@ private: void continueAfterSizeWarning(); void cancelAfterSizeWarning(); - QList checkedItems() const; + Utils::SearchResultItems checkedItems() const; void updateMatchesFoundLabel(); SearchResultTreeView *m_searchResultTreeView = nullptr; diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 524629289fc..a9cc493681a 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -261,7 +261,7 @@ using namespace Core::Internal; /*! \fn void Core::SearchResult::replaceButtonClicked(const QString &replaceText, - const QList &checkedItems, + const Utils::SearchResultItems &checkedItems, bool preserveCase) Indicates that the user initiated a text replace by selecting @@ -843,7 +843,7 @@ void SearchResult::addResult(const Utils::SearchResultItem &item) \sa addResult() */ -void SearchResult::addResults(const QList &items, AddMode mode) +void SearchResult::addResults(const Utils::SearchResultItems &items, AddMode mode) { m_widget->addResults(items, mode); emit countChanged(m_widget->count()); diff --git a/src/plugins/coreplugin/find/searchresultwindow.h b/src/plugins/coreplugin/find/searchresultwindow.h index d2a0dc8d31c..ae611926818 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.h +++ b/src/plugins/coreplugin/find/searchresultwindow.h @@ -60,7 +60,7 @@ public: public slots: void addResult(const Utils::SearchResultItem &item); - void addResults(const QList &items, AddMode mode); + void addResults(const Utils::SearchResultItems &items, AddMode mode); void setFilter(SearchResultFilter *filter); // Takes ownership void finishSearch(bool canceled, const QString &reason = {}); void setTextToReplace(const QString &textToReplace); @@ -71,7 +71,8 @@ public slots: signals: void activated(const Utils::SearchResultItem &item); - void replaceButtonClicked(const QString &replaceText, const QList &checkedItems, bool preserveCase); + void replaceButtonClicked(const QString &replaceText, + const Utils::SearchResultItems &checkedItems, bool preserveCase); void replaceTextChanged(const QString &replaceText); void canceled(); void paused(bool paused); diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index 6194e649cb4..5da22854386 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -456,10 +456,8 @@ void CppFindReferences::setupSearch(Core::SearchResult *search) std::bind(&CppFindReferences::onReplaceButtonClicked, this, search, _1, _2, _3)); } -void CppFindReferences::onReplaceButtonClicked(Core::SearchResult *search, - const QString &text, - const QList &items, - bool preserveCase) +void CppFindReferences::onReplaceButtonClicked(Core::SearchResult *search, const QString &text, + const SearchResultItems &items, bool preserveCase) { const Utils::FilePaths filePaths = TextEditor::BaseFileFind::replaceAll(text, items, preserveCase); if (!filePaths.isEmpty()) { diff --git a/src/plugins/cppeditor/cppfindreferences.h b/src/plugins/cppeditor/cppfindreferences.h index cbd1a9bf4ab..b05ce723c4e 100644 --- a/src/plugins/cppeditor/cppfindreferences.h +++ b/src/plugins/cppeditor/cppfindreferences.h @@ -78,7 +78,7 @@ public: private: void setupSearch(Core::SearchResult *search); void onReplaceButtonClicked(Core::SearchResult *search, const QString &text, - const QList &items, bool preserveCase); + const Utils::SearchResultItems &items, bool preserveCase); void searchAgain(Core::SearchResult *search); void findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context, diff --git a/src/plugins/cppeditor/cppindexingsupport.cpp b/src/plugins/cppeditor/cppindexingsupport.cpp index be150b2d393..22ff93cdaa0 100644 --- a/src/plugins/cppeditor/cppindexingsupport.cpp +++ b/src/plugins/cppeditor/cppindexingsupport.cpp @@ -264,7 +264,7 @@ void SymbolSearcher::runSearch(QPromise &promise) if (promise.isCanceled()) break; if (m_fileNames.isEmpty() || m_fileNames.contains(it.value()->filePath().path())) { - QList resultItems; + SearchResultItems resultItems; auto filter = [&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult { if (matcher.match(info->symbolName()).hasMatch()) { QString text = info->symbolName(); diff --git a/src/plugins/cppeditor/symbolsearcher_test.cpp b/src/plugins/cppeditor/symbolsearcher_test.cpp index ade5b356207..688df3d924f 100644 --- a/src/plugins/cppeditor/symbolsearcher_test.cpp +++ b/src/plugins/cppeditor/symbolsearcher_test.cpp @@ -35,7 +35,7 @@ public: return m_symbolName == other.m_symbolName && m_scope == other.m_scope; } - static ResultDataList fromSearchResultList(const QList &entries) + static ResultDataList fromSearchResultList(const Utils::SearchResultItems &entries) { ResultDataList result; for (const Utils::SearchResultItem &entry : entries) diff --git a/src/plugins/cppeditor/symbolsfindfilter.cpp b/src/plugins/cppeditor/symbolsfindfilter.cpp index 6fd8e78618f..eb6a4c81dab 100644 --- a/src/plugins/cppeditor/symbolsfindfilter.cpp +++ b/src/plugins/cppeditor/symbolsfindfilter.cpp @@ -136,7 +136,7 @@ void SymbolsFindFilter::addResults(QFutureWatcher *watcher, in watcher->cancel(); return; } - QList items; + SearchResultItems items; for (int i = begin; i < end; ++i) items << watcher->resultAt(i); search->addResults(items, SearchResult::AddSorted); diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp index 73317fb6fe4..04267ebb074 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.cpp +++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp @@ -216,12 +216,12 @@ QStringList SymbolSupport::getFileContents(const Utils::FilePath &filePath) return fileContent.split("\n"); } -QList generateSearchResultItems( +Utils::SearchResultItems generateSearchResultItems( const QMap> &rangesInDocument, Core::SearchResult *search = nullptr, bool limitToProjects = false) { - QList result; + Utils::SearchResultItems result; const bool renaming = search && search->supportsReplace(); QString oldSymbolName; QVariantList userData; @@ -264,7 +264,7 @@ QList generateSearchResultItems( return result; } -QList generateSearchResultItems( +Utils::SearchResultItems generateSearchResultItems( const LanguageClientArray &locations, const DocumentUri::PathMapper &pathMapper) { if (locations.isNull()) @@ -463,7 +463,7 @@ void SymbolSupport::requestRename(const TextDocumentPositionParams &positionPara search->popup(); } -QList generateReplaceItems(const WorkspaceEdit &edits, +Utils::SearchResultItems generateReplaceItems(const WorkspaceEdit &edits, Core::SearchResult *search, bool limitToProjects, const DocumentUri::PathMapper &pathMapper) @@ -524,7 +524,7 @@ Core::SearchResult *SymbolSupport::createSearch(const TextDocumentPositionParams connect(search, &Core::SearchResult::replaceButtonClicked, this, [this, search, resetConnection](const QString & /*replaceText*/, - const QList &checkedItems) { + const Utils::SearchResultItems &checkedItems) { applyRename(checkedItems, search); disconnect(resetConnection); }); @@ -571,7 +571,7 @@ void SymbolSupport::handleRenameResponse(Core::SearchResult *search, } } -void SymbolSupport::applyRename(const QList &checkedItems, +void SymbolSupport::applyRename(const Utils::SearchResultItems &checkedItems, Core::SearchResult *search) { QSet affectedNonOpenFilePaths; diff --git a/src/plugins/languageclient/languageclientsymbolsupport.h b/src/plugins/languageclient/languageclientsymbolsupport.h index c9960c5c1c3..e52b80471ad 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.h +++ b/src/plugins/languageclient/languageclientsymbolsupport.h @@ -73,7 +73,7 @@ private: const std::function &callback, bool preferLowerCaseFileNames); void handleRenameResponse(Core::SearchResult *search, const LanguageServerProtocol::RenameRequest::Response &response); - void applyRename(const QList &checkedItems, Core::SearchResult *search); + void applyRename(const Utils::SearchResultItems &checkedItems, Core::SearchResult *search); QString derivePlaceholder(const QString &oldSymbol, const QString &newSymbol); Client *m_client = nullptr; diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index a660dbbb986..5e72cd642b9 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -992,7 +992,7 @@ void FindReferences::displayResults(int first, int last) this, &FindReferences::onReplaceButtonClicked); } connect(m_currentSearch.data(), &SearchResult::activated, - [](const Utils::SearchResultItem& item) { + [](const Utils::SearchResultItem &item) { Core::EditorManager::openEditorAtSearchResult(item); }); connect(m_currentSearch.data(), &SearchResult::canceled, this, &FindReferences::cancel); @@ -1042,7 +1042,7 @@ void FindReferences::setPaused(bool paused) } void FindReferences::onReplaceButtonClicked(const QString &text, - const QList &items, bool preserveCase) + const Utils::SearchResultItems &items, bool preserveCase) { const Utils::FilePaths filePaths = TextEditor::BaseFileFind::replaceAll(text, items, diff --git a/src/plugins/qmljseditor/qmljsfindreferences.h b/src/plugins/qmljseditor/qmljsfindreferences.h index b4040f080b3..c45d77ac180 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.h +++ b/src/plugins/qmljseditor/qmljsfindreferences.h @@ -62,7 +62,7 @@ private: void searchFinished(); void cancel(); void setPaused(bool paused); - void onReplaceButtonClicked(const QString &text, const QList &items, + void onReplaceButtonClicked(const QString &text, const Utils::SearchResultItems &items, bool preserveCase); QPointer m_currentSearch; diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 5dabbda05b1..9a57b083e69 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -223,7 +223,7 @@ static void displayResult(QFutureWatcher *watcher, SearchResult *search, int index) { const FileSearchResultList results = watcher->resultAt(index); - QList items; + SearchResultItems items; for (const FileSearchResult &result : results) { SearchResultItem item; item.setFilePath(result.fileName); @@ -330,8 +330,7 @@ void BaseFileFind::addSearchEngine(SearchEngine *searchEngine) setCurrentSearchEngine(0); } -void BaseFileFind::doReplace(const QString &text, - const QList &items, +void BaseFileFind::doReplace(const QString &text, const SearchResultItems &items, bool preserveCase) { const FilePaths files = replaceAll(text, items, preserveCase); @@ -472,8 +471,7 @@ void BaseFileFind::recheckEnabled(SearchResult *search) search->setSearchAgainEnabled(isEnabled()); } -FilePaths BaseFileFind::replaceAll(const QString &text, - const QList &items, +FilePaths BaseFileFind::replaceAll(const QString &text, const SearchResultItems &items, bool preserveCase) { if (items.isEmpty()) @@ -481,7 +479,7 @@ FilePaths BaseFileFind::replaceAll(const QString &text, RefactoringChanges refactoring; - QHash > changes; + QHash changes; for (const SearchResultItem &item : items) changes[FilePath::fromUserInput(item.path().constFirst())].append(item); @@ -502,7 +500,7 @@ FilePaths BaseFileFind::replaceAll(const QString &text, for (auto it = changes.cbegin(), end = changes.cend(); it != end; ++it) { const FilePath filePath = it.key(); - const QList changeItems = it.value(); + const SearchResultItems changeItems = it.value(); ChangeSet changeSet; RefactoringFilePtr file = refactoring.file(filePath); diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index 53d085662a1..5864eccf365 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -85,8 +85,7 @@ public: void addSearchEngine(SearchEngine *searchEngine); /* returns the list of unique files that were passed in items */ - static Utils::FilePaths replaceAll(const QString &txt, - const QList &items, + static Utils::FilePaths replaceAll(const QString &txt, const Utils::SearchResultItems &items, bool preserveCase = false); virtual Utils::FileIterator *files(const QStringList &nameFilters, const QStringList &exclusionFilters, @@ -116,9 +115,7 @@ signals: private: void openEditor(Core::SearchResult *result, const Utils::SearchResultItem &item); - void doReplace(const QString &txt, - const QList &items, - bool preserveCase); + void doReplace(const QString &txt, const Utils::SearchResultItems &items, bool preserveCase); void hideHighlightAll(bool visible); void searchAgain(Core::SearchResult *search); virtual void recheckEnabled(Core::SearchResult *search); From e4f4ad8aa690e159cc4ad4cbd6f85dfce4fd4fc4 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 8 May 2023 08:49:18 +0200 Subject: [PATCH 0859/1447] Bump version to 10.0.2 Change-Id: I8722d122d18e78054d844a4f4e75cf7d2ef746ef Reviewed-by: Eike Ziller --- cmake/QtCreatorIDEBranding.cmake | 4 ++-- qbs/modules/qtc/qtc.qbs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 0cafd6591fa..6f94c1fd90f 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "10.0.1") # The IDE version. +set(IDE_VERSION "10.0.2") # The IDE version. set(IDE_VERSION_COMPAT "10.0.0") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "10.0.1") # The IDE display version. +set(IDE_VERSION_DISPLAY "10.0.2") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2023") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index c37e05ce9dd..08d6eeffd73 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -6,10 +6,10 @@ import qbs.Utilities Module { Depends { name: "cpp"; required: false } - property string qtcreator_display_version: '10.0.1' + property string qtcreator_display_version: '10.0.2' property string ide_version_major: '10' property string ide_version_minor: '0' - property string ide_version_release: '1' + property string ide_version_release: '2' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release From cc45afdfb093ecab79ca927f1576c802aa6d3e95 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 5 May 2023 17:46:25 +0200 Subject: [PATCH 0860/1447] Layouting: Avoid a lambda in the demo Change-Id: Ic11936fd2a6da2153a52e39249d49d174ffb8466 Reviewed-by: Orgad Shaneh --- .../manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h | 2 +- tests/manual/layoutbuilder/demo/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h index 5ccb647f846..e238a5cfcdb 100644 --- a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h @@ -18,7 +18,7 @@ Application app PushButton { text("Quit"), - onClicked([] { QApplication::quit(); }) + onClicked(QApplication::quit) } } }; diff --git a/tests/manual/layoutbuilder/demo/main.cpp b/tests/manual/layoutbuilder/demo/main.cpp index fe8d7541ba3..60996ba96ef 100644 --- a/tests/manual/layoutbuilder/demo/main.cpp +++ b/tests/manual/layoutbuilder/demo/main.cpp @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) PushButton { text("Quit"), - onClicked([] { QApplication::quit(); }) + onClicked(QApplication::quit) }, } } From a11800ca1633015a7ead3397c3a0e8a81fcdb54e Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 8 May 2023 09:45:34 +0300 Subject: [PATCH 0861/1447] Doc: Update shortcut descriptions Follow-up commit 27966a17499a23f2d681f4318787eb49c938d6b1. Task-number: QTCREATORBUG-10170 Change-Id: Ifbb370ee6500e0cfdc63772c05bf33cae4b957c9 Reviewed-by: Leena Miettinen --- doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc b/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc index 94cced414bd..ef5d0cca4c6 100644 --- a/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc +++ b/doc/qtcreator/src/howto/creator-keyboard-shortcuts.qdoc @@ -729,7 +729,7 @@ \li \li Alt+S, Alt+D \row - \li Diff project + \li Diff project or repository \li \li \li Alt+G, Alt+Shift+D @@ -753,7 +753,7 @@ \li Alt+P, Alt+F \li \row - \li Log project + \li Log repository \li \li \li Alt+G, Alt+K From 82b5cc89cb1e1c5e539c7a7961079b213dbcffe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 5 May 2023 13:11:46 +0200 Subject: [PATCH 0862/1447] SquishTests: Log used Python version Change-Id: I60cb928382840f34800af6a8ee1ed7f084acfb93 Reviewed-by: Christian Stenger --- tests/system/shared/qtcreator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index 543c3c7ad4f..66407519066 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -382,6 +382,7 @@ def copySettingsToTmpDir(destination=None, omitFiles=[]): substituteUnchosenTargetABIs(tmpSettingsDir) SettingsPath = ['-settingspath', '"%s"' % tmpSettingsDir] +test.log("Test is running on Python %s" % sys.version) # current dir is directory holding qtcreator.py origSettingsDir = os.path.abspath(os.path.join(os.getcwd(), "..", "..", "settings")) From cd73f8c6b8dd6e62b3cdff972d7194f4ff34a105 Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Fri, 5 May 2023 19:44:56 +0200 Subject: [PATCH 0863/1447] qmljsreformatter: don't default foreach type to "in" Fixes: QTCREATORBUG-29123 Change-Id: I4d3a611c359946c4483388cbf18a0b6f16d0a8d6 Reviewed-by: Fabian Kosmale --- src/libs/qmljs/qmljsreformatter.cpp | 5 ++++- tests/auto/qml/reformatter/forEachType.qml | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/reformatter/forEachType.qml diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp index 03a95a668c9..232c0361a1a 100644 --- a/src/libs/qmljs/qmljsreformatter.cpp +++ b/src/libs/qmljs/qmljsreformatter.cpp @@ -1088,7 +1088,10 @@ protected: out(" "); out(ast->lparenToken); accept(ast->lhs); - out(" in "); + if (ast->type == ForEachType::In) + out(" in "); + else + out(" of "); accept(ast->expression); out(ast->rparenToken); acceptBlockOrIndented(ast->statement); diff --git a/tests/auto/qml/reformatter/forEachType.qml b/tests/auto/qml/reformatter/forEachType.qml new file mode 100644 index 00000000000..6fdabbde1bc --- /dev/null +++ b/tests/auto/qml/reformatter/forEachType.qml @@ -0,0 +1,9 @@ +import QtQml + +QtObject { + Component.onCompleted: { + for (var i of ["one", "two", "free"]) { + console.debug(i) + } + } +} From 78fe0c315ee18358f0aa2bc3452d3d19efac73b4 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 5 May 2023 12:26:48 +0200 Subject: [PATCH 0864/1447] Debugger: fix vanishing editor tooltip on expand fetchMore is called multiple times before expandNode and seems to invalidate the index that is passed to expandNode. Since we only need to fetch more when we want to expand the item we might as well just integrate the code of fetch more into expandNode. Fixes: QTCREATORBUG-29083 Change-Id: I0e60e9bb03b53de2e86eea232fb5bb98046bbb80 Reviewed-by: hjk --- .../debugger/debuggertooltipmanager.cpp | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index f5e9933fbef..70e52355867 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -266,9 +266,20 @@ public: void expandNode(const QModelIndex &idx) { + if (!m_engine) + return; + m_expandedINames.insert(idx.data(LocalsINameRole).toString()); - if (canFetchMore(idx)) - fetchMore(idx); + if (canFetchMore(idx)) { + if (!idx.isValid()) + return; + + if (auto item = dynamic_cast(itemForIndex(idx))) { + WatchItem *it = m_engine->watchHandler()->findItem(item->iname); + if (QTC_GUARD(it)) + it->model()->fetchMore(it->index()); + } + } } void collapseNode(const QModelIndex &idx) @@ -276,22 +287,6 @@ public: m_expandedINames.remove(idx.data(LocalsINameRole).toString()); } - void fetchMore(const QModelIndex &idx) override - { - if (!idx.isValid()) - return; - auto item = dynamic_cast(itemForIndex(idx)); - if (!item) - return; - QString iname = item->iname; - if (!m_engine) - return; - - WatchItem *it = m_engine->watchHandler()->findItem(iname); - QTC_ASSERT(it, return); - it->model()->fetchMore(it->index()); - } - void restoreTreeModel(QXmlStreamReader &r); QPointer m_engine; From e56e3b6f374e00179eb0537198437864dddc47f2 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 8 May 2023 09:48:36 +0200 Subject: [PATCH 0865/1447] FakeVim: Fix build with Qt 6.6 The connect doesn't work with incomplete type FakeVimHandler::Private anymore, so move the code. Change-Id: I686cd19a985f965cebf7d0a927cff4dc80ae746d Reviewed-by: hjk --- src/plugins/fakevim/fakevimhandler.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 4fbab50d469..5cf97784fe1 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1017,14 +1017,6 @@ inline QString msgMarkNotSet(const QString &text) return Tr::tr("Mark \"%1\" not set.").arg(text); } -static void initSingleShotTimer(QTimer *timer, int interval, FakeVimHandler::Private *receiver, - void (FakeVimHandler::Private::*slot)()) -{ - timer->setSingleShot(true); - timer->setInterval(interval); - QObject::connect(timer, &QTimer::timeout, receiver, slot); -} - class Input { public: @@ -2384,6 +2376,16 @@ public: FakeVimSettings &s = *fakeVimSettings(); }; +static void initSingleShotTimer(QTimer *timer, + int interval, + FakeVimHandler::Private *receiver, + void (FakeVimHandler::Private::*slot)()) +{ + timer->setSingleShot(true); + timer->setInterval(interval); + QObject::connect(timer, &QTimer::timeout, receiver, slot); +} + FakeVimHandler::Private::GlobalData FakeVimHandler::Private::g; FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget) From deec92b63128e23b4034f786090162e503fdde06 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 09:33:38 +0200 Subject: [PATCH 0866/1447] Debugger: Don't put option page into the central object pool Apparently not used anymore. Change-Id: Ie73e09aad04574460221ffaff0c4e6cfe50873e6 Reviewed-by: David Schulz --- src/plugins/debugger/debuggeritemmanager.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 42f9af0800c..aca5a976359 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -9,8 +9,6 @@ #include #include -#include - #include #include #include @@ -878,7 +876,6 @@ DebuggerItemManagerPrivate::DebuggerItemManagerPrivate() d = this; m_model = new DebuggerItemModel; m_optionsPage = new DebuggerOptionsPage; - ExtensionSystem::PluginManager::addObject(m_optionsPage); } void DebuggerItemManagerPrivate::extensionsInitialized() @@ -888,7 +885,6 @@ void DebuggerItemManagerPrivate::extensionsInitialized() DebuggerItemManagerPrivate::~DebuggerItemManagerPrivate() { - ExtensionSystem::PluginManager::removeObject(m_optionsPage); delete m_optionsPage; delete m_model; } From fb5efd01b57cc2b7d0dca24ee1dfec4627aaf0a2 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 10:16:23 +0200 Subject: [PATCH 0867/1447] LanguageClient: Explicitly qualify one QObject::connect Not needed currently but will be once an IOptionPage loses its QObject base dependency. Change-Id: Ide7de1a34ff62c32d63a77040e9ec59bb42e3c40 Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index b6545dae022..4dc70e31c96 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -293,7 +293,7 @@ LanguageClientSettingsPage::LanguageClientSettingsPage() setDisplayCategory(Tr::tr(Constants::LANGUAGECLIENT_SETTINGS_TR)); setCategoryIconPath(":/languageclient/images/settingscategory_languageclient.png"); setWidgetCreator([this] { return new LanguageClientSettingsPageWidget(m_model, m_changedSettings); }); - connect(&m_model, &LanguageClientSettingsModel::dataChanged, [this](const QModelIndex &index) { + QObject::connect(&m_model, &LanguageClientSettingsModel::dataChanged, [this](const QModelIndex &index) { if (BaseSettings *setting = m_model.settingForIndex(index)) m_changedSettings << setting->m_id; }); From 0faed9dda40c5145dd239a2bcdcc07f665d19170 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 21 Mar 2023 15:07:09 +0100 Subject: [PATCH 0868/1447] QmlDesigner: Remove unused PuppetBuildProgressDialog Change-Id: Id2e9da8c4fea128105cefe37d3c99ca5537d3acf Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/qmldesigner/CMakeLists.txt | 7 -- .../instances/puppetbuildprogressdialog.cpp | 65 ---------------- .../instances/puppetbuildprogressdialog.h | 38 --------- .../instances/puppetbuildprogressdialog.ui | 78 ------------------- 4 files changed, 188 deletions(-) delete mode 100644 src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.cpp delete mode 100644 src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.h delete mode 100644 src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.ui diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index d436d10e0ef..74fcd863302 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -91,11 +91,6 @@ extend_qtc_library(QmlDesignerCore PUBLIC_DEPENDS rt ) -set(UI_FILES - ${CMAKE_CURRENT_LIST_DIR}/designercore/instances/puppetbuildprogressdialog.ui -) -qt_wrap_ui(UI_SOURCES ${UI_FILES}) - extend_qtc_library(QmlDesignerCore INCLUDES ${CMAKE_CURRENT_BINARY_DIR} SOURCES @@ -290,8 +285,6 @@ extend_qtc_library(QmlDesignerCore nodeinstanceserverproxy.cpp nodeinstanceserverproxy.h nodeinstanceview.cpp - puppetbuildprogressdialog.cpp - puppetbuildprogressdialog.h puppetstartdata.h puppetstarter.cpp puppetstarter.h diff --git a/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.cpp b/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.cpp deleted file mode 100644 index 53489fa5b85..00000000000 --- a/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "puppetbuildprogressdialog.h" -#include "ui_puppetbuildprogressdialog.h" - -#include -#include -#include - -namespace QmlDesigner { - -PuppetBuildProgressDialog::PuppetBuildProgressDialog() : - QDialog(Core::ICore::dialogParent()), - ui(new Ui::PuppetBuildProgressDialog), - m_lineCount(0), - m_useFallbackPuppet(false) -{ - setWindowFlags(Qt::SplashScreen); - setWindowModality(Qt::ApplicationModal); - ui->setupUi(this); - ui->buildProgressBar->setMaximum(85); - connect(ui->useFallbackPuppetPushButton, &QAbstractButton::clicked, this, &PuppetBuildProgressDialog::setUseFallbackPuppet); -} - -PuppetBuildProgressDialog::~PuppetBuildProgressDialog() -{ - delete ui; -} - -void PuppetBuildProgressDialog::setProgress(int progress) -{ - ui->buildProgressBar->setValue(progress); -} - -bool PuppetBuildProgressDialog::useFallbackPuppet() const -{ - return m_useFallbackPuppet; -} - -void PuppetBuildProgressDialog::setErrorOutputFile(const QString &filePath) -{ - ui->openErrorOutputFileLabel->setText(QString::fromLatin1("%2").arg( - filePath, ui->openErrorOutputFileLabel->text())); -} - -void PuppetBuildProgressDialog::setErrorMessage(const QString &message) -{ - ui->label->setText(QString::fromLatin1("%1").arg(message)); - ui->useFallbackPuppetPushButton->setText(tr("OK")); - connect(ui->useFallbackPuppetPushButton, &QAbstractButton::clicked, this, &QDialog::accept); -} - -void PuppetBuildProgressDialog::setUseFallbackPuppet() -{ - m_useFallbackPuppet = true; -} - -void PuppetBuildProgressDialog::newBuildOutput(const QByteArray &standardOutput) -{ - m_lineCount += standardOutput.count('\n'); - setProgress(m_lineCount); -} - -} diff --git a/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.h b/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.h deleted file mode 100644 index c7db04eaeca..00000000000 --- a/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace QmlDesigner { - -namespace Ui { -class PuppetBuildProgressDialog; -} - - -class PuppetBuildProgressDialog : public QDialog -{ - Q_OBJECT - -public: - explicit PuppetBuildProgressDialog(); - ~PuppetBuildProgressDialog() override; - - void setProgress(int progress); - void newBuildOutput(const QByteArray &standardOutput); - bool useFallbackPuppet() const; - void setErrorOutputFile(const QString &filePath); - void setErrorMessage(const QString &message); - -private: - void setUseFallbackPuppet(); - -private: - Ui::PuppetBuildProgressDialog *ui; - int m_lineCount; - bool m_useFallbackPuppet; -}; - -} diff --git a/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.ui b/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.ui deleted file mode 100644 index 626eb6b5574..00000000000 --- a/src/plugins/qmldesigner/designercore/instances/puppetbuildprogressdialog.ui +++ /dev/null @@ -1,78 +0,0 @@ - - - QmlDesigner::PuppetBuildProgressDialog - - - - 0 - 0 - 695 - 99 - - - - Build Progress - - - true - - - - - - Building Adapter for the current Qt. Happens only once for every Qt installation. - - - - - - - 0 - - - - - - - - - Open error output file - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Use Fallback QML Emulation Layer - - - false - - - - - - - - - - From cd06a608db3e658dcb2cc2ad75f701ff833e64c9 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 09:46:30 +0200 Subject: [PATCH 0869/1447] Autotest: Move update connection from GTestSettingsPage ... to GTestSettings to prepare for removing the QObject base of IOptionsPage. Change-Id: I2d6f78e4f2a1d3690860c40b4ab55008034457a9 Reviewed-by: Christian Stenger --- src/plugins/autotest/gtest/gtestsettings.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp index babea83f78a..5a7a72ab46b 100644 --- a/src/plugins/autotest/gtest/gtestsettings.cpp +++ b/src/plugins/autotest/gtest/gtestsettings.cpp @@ -104,6 +104,11 @@ GTestSettings::GTestSettings() >estFilter, [this](int val) { gtestFilter.setEnabled(groupMode.itemValueForIndex(val) == GTest::Constants::GTestFilter); }); + + QObject::connect(this, &AspectContainer::applied, this, [] { + Id id = Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME); + TestTreeModel::instance()->rebuild({id}); + }); } GTestSettingsPage::GTestSettingsPage(GTestSettings *settings, Id settingsId) @@ -113,11 +118,6 @@ GTestSettingsPage::GTestSettingsPage(GTestSettings *settings, Id settingsId) setDisplayName(Tr::tr(GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); setSettings(settings); - QObject::connect(settings, &AspectContainer::applied, this, [] { - Id id = Id(Constants::FRAMEWORK_PREFIX).withSuffix(GTest::Constants::FRAMEWORK_NAME); - TestTreeModel::instance()->rebuild({id}); - }); - setLayouter([settings](QWidget *widget) { GTestSettings &s = *settings; using namespace Layouting; From ed4c936cfc0992be40e040c0c9504054591b8060 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 10:24:08 +0200 Subject: [PATCH 0870/1447] Core: Remove unused Q_OBJECT from LocatorSettings page Change-Id: I75698496ebaa13284cb0d134aa313f608d7b7edd Reviewed-by: Eike Ziller --- src/plugins/coreplugin/locator/locatorsettingspage.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorsettingspage.h b/src/plugins/coreplugin/locator/locatorsettingspage.h index 4818fc2e236..408fe7b91f8 100644 --- a/src/plugins/coreplugin/locator/locatorsettingspage.h +++ b/src/plugins/coreplugin/locator/locatorsettingspage.h @@ -5,16 +5,12 @@ #include -namespace Core { -namespace Internal { +namespace Core::Internal { class LocatorSettingsPage : public IOptionsPage { - Q_OBJECT - public: LocatorSettingsPage(); }; -} // namespace Internal -} // namespace Core +} // Core::Internal From 0f10c6df33667dadc086ca3ac1c93109e72e73c0 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 10:53:20 +0200 Subject: [PATCH 0871/1447] TextEditor: Remove now unused Q_OBJECT from BehaviorSettingsPage Change-Id: I0919200ddc8bb8b4547316c0af68f5aafa5d4892 Reviewed-by: David Schulz --- src/plugins/texteditor/behaviorsettingspage.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/texteditor/behaviorsettingspage.h b/src/plugins/texteditor/behaviorsettingspage.h index 048a865d5ff..2ecb48ea29c 100644 --- a/src/plugins/texteditor/behaviorsettingspage.h +++ b/src/plugins/texteditor/behaviorsettingspage.h @@ -3,8 +3,6 @@ #pragma once -#include "texteditor_global.h" - #include QT_BEGIN_NAMESPACE @@ -23,8 +21,6 @@ class CodeStylePool; class BehaviorSettingsPage : public Core::IOptionsPage { - Q_OBJECT - public: BehaviorSettingsPage(); ~BehaviorSettingsPage() override; From a7277bfb20cbfa4f73c739a150ba772043a355f8 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 10:54:03 +0200 Subject: [PATCH 0872/1447] UpdateInfo: Remove now unused Q_OBJECT from SettingsPage Change-Id: If5ff4d37816089114d952af934d0dd6fe4acb70a Reviewed-by: Eike Ziller --- src/plugins/updateinfo/settingspage.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/updateinfo/settingspage.h b/src/plugins/updateinfo/settingspage.h index 3ed45a71c65..6da738a9a0c 100644 --- a/src/plugins/updateinfo/settingspage.h +++ b/src/plugins/updateinfo/settingspage.h @@ -5,18 +5,14 @@ #include -namespace UpdateInfo { -namespace Internal { +namespace UpdateInfo::Internal { class UpdateInfoPlugin; class SettingsPage : public Core::IOptionsPage { - Q_OBJECT - public: explicit SettingsPage(UpdateInfoPlugin *plugin); }; -} // namespace Internal -} // namespace UpdateInfo +} // UpdateInfo::Internal From 0e4a7d5207c522c1d25d03212777b00b79b0e360 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 3 May 2023 09:11:28 +0200 Subject: [PATCH 0873/1447] Utils: Avoid watching directories of watched files Do not watch directories unconditionally, but only if they contain removed files to check whether those files are readded. This should reduce the number of needlesly watched directories to a minimum and fix performance regressions introduced by 61598eca15e14af64c20d314db382973dfccb2d2. Fixes: QTCREATORBUG-28957 Change-Id: I8fe387e7de32b0fb585074330c7f6ca7eae44730 Reviewed-by: Reviewed-by: Ulf Hermann Reviewed-by: hjk --- src/libs/utils/filesystemwatcher.cpp | 59 ++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/libs/utils/filesystemwatcher.cpp b/src/libs/utils/filesystemwatcher.cpp index 3f427cce2ea..ad7f77c10e7 100644 --- a/src/libs/utils/filesystemwatcher.cpp +++ b/src/libs/utils/filesystemwatcher.cpp @@ -275,15 +275,19 @@ void FileSystemWatcher::addFiles(const QStringList &files, WatchMode wm) const int count = ++d->m_staticData->m_fileCount[file]; Q_ASSERT(count > 0); - if (count == 1) + if (count == 1) { toAdd << file; - const QString directory = QFileInfo(file).path(); - const int dirCount = ++d->m_staticData->m_directoryCount[directory]; - Q_ASSERT(dirCount > 0); + QFileInfo fi(file); + if (!fi.exists()) { + const QString directory = fi.path(); + const int dirCount = ++d->m_staticData->m_directoryCount[directory]; + Q_ASSERT(dirCount > 0); - if (dirCount == 1) - toAdd << directory; + if (dirCount == 1) + toAdd << directory; + } + } } if (!toAdd.isEmpty()) @@ -311,15 +315,19 @@ void FileSystemWatcher::removeFiles(const QStringList &files) const int count = --(d->m_staticData->m_fileCount[file]); Q_ASSERT(count >= 0); - if (!count) + if (!count) { toRemove << file; - const QString directory = QFileInfo(file).path(); - const int dirCount = --d->m_staticData->m_directoryCount[directory]; - Q_ASSERT(dirCount >= 0); + QFileInfo fi(file); + if (!fi.exists()) { + const QString directory = fi.path(); + const int dirCount = --d->m_staticData->m_directoryCount[directory]; + Q_ASSERT(dirCount >= 0); - if (!dirCount) - toRemove << directory; + if (!dirCount) + toRemove << directory; + } + } } if (!toRemove.isEmpty()) @@ -418,13 +426,27 @@ QStringList FileSystemWatcher::directories() const void FileSystemWatcher::slotFileChanged(const QString &path) { const auto it = d->m_files.find(path); + QStringList toAdd; if (it != d->m_files.end() && it.value().trigger(path)) { if (debug) qDebug() << this << "triggers on file " << path << it.value().watchMode << it.value().modifiedTime.toString(Qt::ISODate); d->fileChanged(path); + + QFileInfo fi(path); + if (!fi.exists()) { + const QString directory = fi.path(); + const int dirCount = ++d->m_staticData->m_directoryCount[directory]; + Q_ASSERT(dirCount > 0); + + if (dirCount == 1) + toAdd << directory; + } } + + if (!toAdd.isEmpty()) + d->m_staticData->m_watcher->addPaths(toAdd); } void FileSystemWatcher::slotDirectoryChanged(const QString &path) @@ -450,9 +472,20 @@ void FileSystemWatcher::slotDirectoryChanged(const QString &path) for (const QString &rejected : d->m_staticData->m_watcher->addPaths(toReadd)) toReadd.removeOne(rejected); + QStringList toRemove; // If we've successfully added the file, that means it was deleted and replaced. - for (const QString &reAdded : std::as_const(toReadd)) + for (const QString &reAdded : std::as_const(toReadd)) { d->fileChanged(reAdded); + const QString directory = QFileInfo(reAdded).path(); + const int dirCount = --d->m_staticData->m_directoryCount[directory]; + Q_ASSERT(dirCount >= 0); + + if (!dirCount) + toRemove << directory; + } + + if (!toRemove.isEmpty()) + d->m_staticData->m_watcher->removePaths(toRemove); } } From ce00785efbcab3aa1cc4f3ae210ecc558f5652cd Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 10:45:15 +0200 Subject: [PATCH 0874/1447] Core: De-QObject-ify bits of mime settings Change-Id: Ib4ffabe6392b5923cb6cce596e3e3563c9d6b7a3 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/mimetypesettings.cpp | 6 ------ src/plugins/coreplugin/mimetypesettings.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/plugins/coreplugin/mimetypesettings.cpp b/src/plugins/coreplugin/mimetypesettings.cpp index d01abeffd21..116fcf4a06e 100644 --- a/src/plugins/coreplugin/mimetypesettings.cpp +++ b/src/plugins/coreplugin/mimetypesettings.cpp @@ -82,8 +82,6 @@ public: // MimeTypeSettingsModel class MimeTypeSettingsModel : public QAbstractTableModel { - Q_OBJECT - public: enum class Role { DefaultHandler = Qt::UserRole @@ -227,8 +225,6 @@ void MimeTypeSettingsModel::resetUserDefaults() // MimeTypeSettingsPrivate class MimeTypeSettingsPrivate : public QObject { - Q_OBJECT - public: MimeTypeSettingsPrivate(); ~MimeTypeSettingsPrivate() override; @@ -787,5 +783,3 @@ void MimeEditorDelegate::setModelData(QWidget *editor, } } // Core::Internal - -#include "mimetypesettings.moc" diff --git a/src/plugins/coreplugin/mimetypesettings.h b/src/plugins/coreplugin/mimetypesettings.h index 57dee3a732b..0127e227685 100644 --- a/src/plugins/coreplugin/mimetypesettings.h +++ b/src/plugins/coreplugin/mimetypesettings.h @@ -11,8 +11,6 @@ class MimeTypeSettingsPrivate; class MimeTypeSettings : public IOptionsPage { - Q_OBJECT - public: MimeTypeSettings(); ~MimeTypeSettings() override; From 5cb0a5629682731e42bd076de74c581065de1eb3 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 5 May 2023 16:30:19 +0200 Subject: [PATCH 0875/1447] Markdown: Delay update of preview Delay the update: The implementation in Qt is currently very slow, and while we don't have a fix, editing with immediate update is very sluggish. Also do not update the preview, if it isn't visible. Change-Id: I35e10af232064b02a36a8be3758ea0bbc5b66f40 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/texteditor/markdowneditor.cpp | 53 ++++++++++++++++------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 59a524226db..3cd1dfb789f 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include namespace TextEditor::Internal { @@ -100,8 +101,25 @@ public: } toolbarLayout->addWidget(swapViews); - connect(m_document.data(), &TextDocument::mimeTypeChanged, - m_document.data(), &TextDocument::changed); + connect(m_document.data(), + &TextDocument::mimeTypeChanged, + m_document.data(), + &TextDocument::changed); + + const auto updatePreview = [this, browser] { + QHash positions; + const auto scrollBars = browser->findChildren(); + + // save scroll positions + for (QScrollBar *scrollBar : scrollBars) + positions.insert(scrollBar, scrollBar->value()); + + browser->setMarkdown(m_document->plainText()); + + // restore scroll positions + for (QScrollBar *scrollBar : scrollBars) + scrollBar->setValue(positions.value(scrollBar)); + }; const auto viewToggled = [swapViews](QWidget *view, bool visible, QWidget *otherView, QToolButton *otherButton) { @@ -128,8 +146,12 @@ public: connect(togglePreviewVisible, &QToolButton::toggled, this, - [this, browser, toggleEditorVisible, viewToggled](bool visible) { + [this, browser, toggleEditorVisible, viewToggled, updatePreview](bool visible) { viewToggled(browser, visible, m_textEditorWidget, toggleEditorVisible); + if (visible && m_performDelayedUpdate) { + m_performDelayedUpdate = false; + updatePreview(); + } }); connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this, toolbarLayout] { @@ -152,19 +174,18 @@ public: kTextEditorRightDefault); }); - connect(m_document->document(), &QTextDocument::contentsChanged, this, [this, browser] { - QHash positions; - const auto scrollBars = browser->findChildren(); + // TODO directly update when we build with Qt 6.5.2 + m_previewTimer.setInterval(500); + m_previewTimer.setSingleShot(true); + connect(&m_previewTimer, &QTimer::timeout, this, [this, togglePreviewVisible, updatePreview] { + if (togglePreviewVisible->isChecked()) + updatePreview(); + else + m_performDelayedUpdate = true; + }); - // save scroll positions - for (QScrollBar *scrollBar : scrollBars) - positions.insert(scrollBar, scrollBar->value()); - - browser->setMarkdown(m_document->plainText()); - - // restore scroll positions - for (QScrollBar *scrollBar : scrollBars) - scrollBar->setValue(positions.value(scrollBar)); + connect(m_document->document(), &QTextDocument::contentsChanged, &m_previewTimer, [this] { + m_previewTimer.start(); }); } @@ -186,6 +207,8 @@ public: } private: + QTimer m_previewTimer; + bool m_performDelayedUpdate = false; Core::MiniSplitter *m_splitter; TextEditorWidget *m_textEditorWidget; TextDocumentPtr m_document; From 06b0d105dce49653118fe0b1880c2c0e9fb8f0a2 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 8 May 2023 12:03:20 +0200 Subject: [PATCH 0876/1447] Editor: simplify font to display options page connection Operating on saved settings is less error prone and easier to maintain. Change-Id: I92e3a6b52296cddc302ba2e4410edfd243b8ad32 Reviewed-by: hjk --- .../texteditor/displaysettingspage.cpp | 53 +++++-------------- src/plugins/texteditor/fontsettingspage.cpp | 1 - 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index 49927710bba..b94c931ab80 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -4,6 +4,7 @@ #include "displaysettingspage.h" #include "displaysettings.h" +#include "fontsettings.h" #include "marginsettings.h" #include "texteditorconstants.h" #include "texteditorsettings.h" @@ -50,23 +51,18 @@ public: enableTextWrappingHintLabel = new QLabel(Tr::tr("Set font line spacing " "to 100% to enable text wrapping option.")); - fontSettingsPageLineSpacing = fontSettingsPageLineSpacingLink(); - - if (fontSettingsPageLineSpacing) { - connect(fontSettingsPageLineSpacing, &QSpinBox::valueChanged, - this, [this](const int &value) { - if (value != 100) - enableTextWrapping->setChecked(false); - enableTextWrapping->setEnabled(value == 100); - enableTextWrappingHintLabel->setVisible(value != 100); - }); - - if (fontSettingsPageLineSpacing->value() != 100) + auto updateWrapping = [this] { + const bool normalLineSpacing = TextEditorSettings::fontSettings().relativeLineSpacing() == 100; + if (!normalLineSpacing) enableTextWrapping->setChecked(false); + enableTextWrapping->setEnabled(normalLineSpacing); + enableTextWrappingHintLabel->setVisible(!normalLineSpacing); + }; - enableTextWrapping->setEnabled(fontSettingsPageLineSpacing->value() == 100); - enableTextWrappingHintLabel->setVisible(fontSettingsPageLineSpacing->value() != 100); - } + updateWrapping(); + + connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, + this, updateWrapping); connect(enableTextWrappingHintLabel, &QLabel::linkActivated, [] { Core::ICore::showOptionsDialog(Constants::TEXT_EDITOR_FONT_SETTINGS); } ); @@ -177,8 +173,6 @@ public: void settingsToUI(); void setDisplaySettings(const DisplaySettings &, const MarginSettings &newMarginSettings); - QSpinBox *fontSettingsPageLineSpacingLink(); - DisplaySettingsPagePrivate *m_data = nullptr; QCheckBox *enableTextWrapping; @@ -208,8 +202,6 @@ public: QRadioButton *atMargin; QRadioButton *rightAligned; QRadioButton *betweenLines; - - QSpinBox *fontSettingsPageLineSpacing = nullptr; }; void DisplaySettingsWidget::apply() @@ -226,10 +218,8 @@ void DisplaySettingsWidget::settingsFromUI(DisplaySettings &displaySettings, { displaySettings.m_displayLineNumbers = displayLineNumbers->isChecked(); displaySettings.m_textWrapping = enableTextWrapping->isChecked(); - if (fontSettingsPageLineSpacing) { - if (fontSettingsPageLineSpacing->value() != 100) - displaySettings.m_textWrapping = false; - } + if (TextEditorSettings::fontSettings().relativeLineSpacing() != 100) + displaySettings.m_textWrapping = false; marginSettings.m_showMargin = showWrapColumn->isChecked(); marginSettings.m_tintMarginArea = tintMarginArea->isChecked(); marginSettings.m_useIndenter = useIndenter->isChecked(); @@ -322,23 +312,6 @@ void DisplaySettingsWidget::setDisplaySettings(const DisplaySettings &newDisplay } } - QSpinBox *DisplaySettingsWidget::fontSettingsPageLineSpacingLink() - { - for (const auto &page : Core::IOptionsPage::allOptionsPages()) { - QWidget *widget = page->widget(); - - if (!widget) - continue; - - for (QSpinBox *spinBox : widget->findChildren()) { - if (spinBox->objectName() == QLatin1String("FontSettingsPage.LineSpacingSpinBox")) - return spinBox; - } - } - - return nullptr; - } - DisplaySettingsPage::DisplaySettingsPage() : d(new DisplaySettingsPagePrivate) { diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp index 1e9ec7fafba..9802ba19a55 100644 --- a/src/plugins/texteditor/fontsettingspage.cpp +++ b/src/plugins/texteditor/fontsettingspage.cpp @@ -119,7 +119,6 @@ public: m_zoomSpinBox->setValue(m_value.fontZoom()); m_lineSpacingSpinBox = new QSpinBox; - m_lineSpacingSpinBox->setObjectName(QLatin1String("FontSettingsPage.LineSpacingSpinBox")); m_lineSpacingSpinBox->setSuffix(Tr::tr("%")); m_lineSpacingSpinBox->setRange(50, 3000); m_lineSpacingSpinBox->setValue(m_value.relativeLineSpacing()); From b03808031a9a5376c964826e137972c6bb1f76d4 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 13:06:14 +0200 Subject: [PATCH 0877/1447] VcsBase: Use functor for apply in CommonSettingsWidget More compact. Change-Id: Ib5985b9aa6fb9fcbe9ff1fffdc17c6c0888f786e Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/commonvcssettings.cpp | 83 ++++++++++------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 416230e8d44..3284f7df31b 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -94,61 +94,48 @@ CommonVcsSettings::CommonVcsSettings() class CommonSettingsWidget final : public Core::IOptionsPageWidget { public: - CommonSettingsWidget(CommonOptionsPage *page); + CommonSettingsWidget(CommonOptionsPage *page) + { + CommonVcsSettings &s = page->settings(); - void apply() final; + auto cacheResetButton = new QPushButton(Tr::tr("Reset VCS Cache")); + cacheResetButton->setToolTip(Tr::tr("Reset information about which " + "version control system handles which directory.")); -private: - void updatePath(); - CommonOptionsPage *m_page; -}; + auto updatePath = [&s] { + Environment env; + env.appendToPath(Core::VcsManager::additionalToolsPath()); + s.sshPasswordPrompt.setEnvironment(env); + }; + using namespace Layouting; + Column { + Row { s.lineWrap, s.lineWrapWidth, st }, + Form { + s.submitMessageCheckScript, br, + s.nickNameMailMap, br, + s.nickNameFieldListFile, br, + s.sshPasswordPrompt, br, + {}, cacheResetButton + } + }.attachTo(this); -CommonSettingsWidget::CommonSettingsWidget(CommonOptionsPage *page) - : m_page(page) -{ - CommonVcsSettings &s = m_page->settings(); + updatePath(); - auto cacheResetButton = new QPushButton(Tr::tr("Reset VCS Cache")); - cacheResetButton->setToolTip(Tr::tr("Reset information about which " - "version control system handles which directory.")); + connect(Core::VcsManager::instance(), &Core::VcsManager::configurationChanged, + this, updatePath); + connect(cacheResetButton, &QPushButton::clicked, + Core::VcsManager::instance(), &Core::VcsManager::clearVersionControlCache); - updatePath(); - - using namespace Layouting; - Column { - Row { s.lineWrap, s.lineWrapWidth, st }, - Form { - s.submitMessageCheckScript, br, - s.nickNameMailMap, br, - s.nickNameFieldListFile, br, - s.sshPasswordPrompt, br, - {}, cacheResetButton - } - }.attachTo(this); - - connect(Core::VcsManager::instance(), &Core::VcsManager::configurationChanged, - this, &CommonSettingsWidget::updatePath); - connect(cacheResetButton, &QPushButton::clicked, - Core::VcsManager::instance(), &Core::VcsManager::clearVersionControlCache); -} - -void CommonSettingsWidget::updatePath() -{ - Environment env; - env.appendToPath(Core::VcsManager::additionalToolsPath()); - m_page->settings().sshPasswordPrompt.setEnvironment(env); -} - -void CommonSettingsWidget::apply() -{ - CommonVcsSettings &s = m_page->settings(); - if (s.isDirty()) { - s.apply(); - s.writeSettings(Core::ICore::settings()); - emit m_page->settingsChanged(); + setOnApply([&s, page] { + if (s.isDirty()) { + s.apply(); + s.writeSettings(Core::ICore::settings()); + emit page->settingsChanged(); + } + }); } -} +}; // CommonOptionsPage From 63522999ee454466449f138a5ddee9ff22abb6fe Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 8 May 2023 12:42:40 +0200 Subject: [PATCH 0878/1447] Avoid crash on close Private may not have been initialized in case QC gets stopped before it could be. Change-Id: I4b6cf6755dd6803834f956e2e125bc1c5f1d929f Reviewed-by: hjk Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 253ca34ad2f..923c0cabb09 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -102,7 +102,7 @@ AxivionPlugin::AxivionPlugin() AxivionPlugin::~AxivionPlugin() { - if (!dd->m_axivionProjectSettings.isEmpty()) { + if (dd && !dd->m_axivionProjectSettings.isEmpty()) { qDeleteAll(dd->m_axivionProjectSettings); dd->m_axivionProjectSettings.clear(); } From de859dfd43bc5105dbdfc23a86aece7b8bebc4fc Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 8 May 2023 12:35:58 +0200 Subject: [PATCH 0879/1447] CppEditor: Do not call Snapshot::filesDependingOn() ... in document processor callback. The dependency table seems to get rebuilt more often than expected, making this operation expensive. Amends 6d805195f6d35df932d666f86af026c051c785f8. Change-Id: I1eace180b2428756b648fa1c58eb0fb66cce3c0c Reviewed-by: Christian Stenger Reviewed-by: hjk Reviewed-by: Jarek Kobus --- .../builtineditordocumentprocessor.cpp | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index c24cc73481e..4baa2bff341 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -6,11 +6,14 @@ #include "builtincursorinfo.h" #include "cppchecksymbols.h" #include "cppcodemodelsettings.h" +#include "cppeditordocument.h" #include "cppeditorplugin.h" #include "cppmodelmanager.h" #include "cpptoolsreuse.h" #include "cppworkingcopy.h" +#include + #include #include #include @@ -265,11 +268,20 @@ void BuiltinEditorDocumentProcessor::onParserFinished(CPlusPlus::Document::Ptr d QTC_CHECK(source.snapshot.contains(document->filePath())); m_semanticInfoUpdater.updateDetached(source); - const Utils::FilePaths deps - = CppModelManager::instance()->snapshot().filesDependingOn(document->filePath()); - for (const Utils::FilePath &dep : deps) { - if (const auto processor = CppModelManager::cppEditorDocumentProcessor(dep)) - processor->run(); + const QList openDocuments = Core::DocumentModel::openedDocuments(); + for (Core::IDocument * const openDocument : openDocuments) { + const auto cppEditorDoc = qobject_cast(openDocument); + if (!cppEditorDoc) + continue; + if (cppEditorDoc->filePath() == document->filePath()) + continue; + CPlusPlus::Document::Ptr cppDoc = CppModelManager::instance()->document( + cppEditorDoc->filePath()); + if (!cppDoc) + continue; + if (!cppDoc->includedFiles().contains(document->filePath())) + continue; + cppEditorDoc->scheduleProcessDocument(); } } From aa8a76c357359d1d78772edc415256e79defa0cd Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 11:29:27 +0200 Subject: [PATCH 0880/1447] GitLab: Use apply functor in GitLabOptionsWidget Babystep towards removing QObject inheritance of IOptionsPage Change-Id: Ib36b8ce4dd1f6878abdfe20c0c4e3ddb95e927dd Reviewed-by: Christian Stenger --- src/plugins/gitlab/gitlaboptionspage.cpp | 41 +++++++++--------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/plugins/gitlab/gitlaboptionspage.cpp b/src/plugins/gitlab/gitlaboptionspage.cpp index eb37c6de2bb..96e83300307 100644 --- a/src/plugins/gitlab/gitlaboptionspage.cpp +++ b/src/plugins/gitlab/gitlaboptionspage.cpp @@ -134,18 +134,6 @@ class GitLabOptionsWidget : public Core::IOptionsPageWidget public: explicit GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParameters *parameters); - GitLabParameters parameters() const; - - void apply() final - { - GitLabParameters newParameters = parameters(); - if (newParameters != *m_parameters) { - *m_parameters = newParameters; - m_parameters->toSettings(Core::ICore::settings()); - emit m_page->settingsChanged(); - } - } - private: void showEditServerDialog(); void showAddServerDialog(); @@ -154,7 +142,6 @@ private: void modifyCurrentServer(const GitLabServer &newServer); void updateButtonsState(); - GitLabOptionsPage *m_page = nullptr; GitLabParameters *m_parameters = nullptr; GitLabServerWidget *m_gitLabServerWidget = nullptr; QPushButton *m_edit = nullptr; @@ -165,7 +152,7 @@ private: }; GitLabOptionsWidget::GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParameters *params) - : m_page(page), m_parameters(params) + : m_parameters(params) { auto defaultLabel = new QLabel(Tr::tr("Default:"), this); m_defaultGitLabServer = new QComboBox(this); @@ -213,18 +200,22 @@ GitLabOptionsWidget::GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParamete m_gitLabServerWidget->setGitLabServer( m_defaultGitLabServer->currentData().value()); }); -} -GitLabParameters GitLabOptionsWidget::parameters() const -{ - GitLabParameters result; - // get all configured gitlabservers - for (int i = 0, end = m_defaultGitLabServer->count(); i < end; ++i) - result.gitLabServers.append(m_defaultGitLabServer->itemData(i).value()); - if (m_defaultGitLabServer->count()) - result.defaultGitLabServer = m_defaultGitLabServer->currentData().value().id; - result.curl = m_curl.filePath(); - return result; + setOnApply([page, this] { + GitLabParameters result; + // get all configured gitlabservers + for (int i = 0, end = m_defaultGitLabServer->count(); i < end; ++i) + result.gitLabServers.append(m_defaultGitLabServer->itemData(i).value()); + if (m_defaultGitLabServer->count()) + result.defaultGitLabServer = m_defaultGitLabServer->currentData().value().id; + result.curl = m_curl.filePath(); + + if (result != *m_parameters) { + *m_parameters = result; + m_parameters->toSettings(Core::ICore::settings()); + emit page->settingsChanged(); + } + }); } void GitLabOptionsWidget::showEditServerDialog() From 4a2a1c2978bf5fc84830cbfaffc4a2ab5c7127ec Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 8 May 2023 09:48:36 +0200 Subject: [PATCH 0881/1447] FakeVim: Fix build with Qt 6.6 The connect doesn't work with incomplete type FakeVimHandler::Private anymore, so move the code. Change-Id: I686cd19a985f965cebf7d0a927cff4dc80ae746d Reviewed-by: hjk (cherry picked from commit e56e3b6f374e00179eb0537198437864dddc47f2) --- src/plugins/fakevim/fakevimhandler.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 68239650654..23a52793e88 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1042,14 +1042,6 @@ inline QString msgMarkNotSet(const QString &text) return Tr::tr("Mark \"%1\" not set.").arg(text); } -static void initSingleShotTimer(QTimer *timer, int interval, FakeVimHandler::Private *receiver, - void (FakeVimHandler::Private::*slot)()) -{ - timer->setSingleShot(true); - timer->setInterval(interval); - QObject::connect(timer, &QTimer::timeout, receiver, slot); -} - class Input { public: @@ -2409,6 +2401,16 @@ public: FakeVimSettings &s = *fakeVimSettings(); }; +static void initSingleShotTimer(QTimer *timer, + int interval, + FakeVimHandler::Private *receiver, + void (FakeVimHandler::Private::*slot)()) +{ + timer->setSingleShot(true); + timer->setInterval(interval); + QObject::connect(timer, &QTimer::timeout, receiver, slot); +} + FakeVimHandler::Private::GlobalData FakeVimHandler::Private::g; FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget) From 6f253b06947c3f00f90950d5bbb9f0b4ac24dd00 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 13:38:30 +0200 Subject: [PATCH 0882/1447] VcsBase: Move some private pieces off vcsplugin.h By themselves not worth a pimpl, but since we have one already... Change-Id: I867e68c5e82f71ebbe16a55eb190d87f981a550b Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/vcsplugin.cpp | 68 ++++++++++++++++++------------- src/plugins/vcsbase/vcsplugin.h | 5 --- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/src/plugins/vcsbase/vcsplugin.cpp b/src/plugins/vcsbase/vcsplugin.cpp index 77da3af71c1..5d14b3a4722 100644 --- a/src/plugins/vcsbase/vcsplugin.cpp +++ b/src/plugins/vcsbase/vcsplugin.cpp @@ -32,12 +32,45 @@ using namespace Core; using namespace ProjectExplorer; using namespace Utils; -namespace VcsBase { -namespace Internal { +namespace VcsBase::Internal { class VcsPluginPrivate { public: + explicit VcsPluginPrivate(VcsPlugin *plugin) + : q(plugin) + { + QObject::connect(&m_settingsPage, &CommonOptionsPage::settingsChanged, + [this] { slotSettingsChanged(); }); + slotSettingsChanged(); + } + + QStandardItemModel *nickNameModel() + { + if (!m_nickNameModel) { + m_nickNameModel = NickNameDialog::createModel(q); + populateNickNameModel(); + } + return m_nickNameModel; + } + + void populateNickNameModel() + { + QString errorMessage; + if (!NickNameDialog::populateModelFromMailCapFile(m_settingsPage.settings().nickNameMailMap.filePath(), + m_nickNameModel, + &errorMessage)) { + qWarning("%s", qPrintable(errorMessage)); + } + } + + void slotSettingsChanged() + { + if (m_nickNameModel) + populateNickNameModel(); + } + + VcsPlugin *q; CommonOptionsPage m_settingsPage; QStandardItemModel *m_nickNameModel = nullptr; }; @@ -59,7 +92,7 @@ VcsPlugin::~VcsPlugin() void VcsPlugin::initialize() { - d = new VcsPluginPrivate; + d = new VcsPluginPrivate(this); EditorManager::addCloseEditorListener([this](IEditor *editor) -> bool { bool result = true; @@ -70,9 +103,6 @@ void VcsPlugin::initialize() connect(&d->m_settingsPage, &CommonOptionsPage::settingsChanged, this, &VcsPlugin::settingsChanged); - connect(&d->m_settingsPage, &CommonOptionsPage::settingsChanged, - this, &VcsPlugin::slotSettingsChanged); - slotSettingsChanged(); JsonWizardFactory::registerPageFactory(new Internal::VcsConfigurationPageFactory); JsonWizardFactory::registerPageFactory(new Internal::VcsCommandPageFactory); @@ -124,28 +154,8 @@ CommonVcsSettings &VcsPlugin::settings() const /* Delayed creation/update of the nick name model. */ QStandardItemModel *VcsPlugin::nickNameModel() { - if (!d->m_nickNameModel) { - d->m_nickNameModel = NickNameDialog::createModel(this); - populateNickNameModel(); - } - return d->m_nickNameModel; + QTC_ASSERT(d, return nullptr); + return d->nickNameModel(); } -void VcsPlugin::populateNickNameModel() -{ - QString errorMessage; - if (!NickNameDialog::populateModelFromMailCapFile(settings().nickNameMailMap.filePath(), - d->m_nickNameModel, - &errorMessage)) { - qWarning("%s", qPrintable(errorMessage)); - } -} - -void VcsPlugin::slotSettingsChanged() -{ - if (d->m_nickNameModel) - populateNickNameModel(); -} - -} // namespace Internal -} // namespace VcsBase +} // VcsBase::Internal diff --git a/src/plugins/vcsbase/vcsplugin.h b/src/plugins/vcsbase/vcsplugin.h index 99c3d74bbe8..6d4b35c11fd 100644 --- a/src/plugins/vcsbase/vcsplugin.h +++ b/src/plugins/vcsbase/vcsplugin.h @@ -5,8 +5,6 @@ #include -#include - QT_BEGIN_NAMESPACE class QStandardItemModel; QT_END_NAMESPACE @@ -44,9 +42,6 @@ signals: void submitEditorAboutToClose(VcsBase::VcsBaseSubmitEditor *e, bool *result); private: - void slotSettingsChanged(); - void populateNickNameModel(); - class VcsPluginPrivate *d = nullptr; }; From 41b6ecf502c275713eb97bb59420e5d8c4f7fda5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 13:56:51 +0200 Subject: [PATCH 0883/1447] Fix environment auto test Amends 1e1befd9eb6. Change-Id: Iecd06ee06081057208a2b3387d618142dc74d0bd Reviewed-by: Jarek Kobus --- tests/auto/environment/tst_environment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/environment/tst_environment.cpp b/tests/auto/environment/tst_environment.cpp index 2fd11245f8a..1b870ddd6da 100644 --- a/tests/auto/environment/tst_environment.cpp +++ b/tests/auto/environment/tst_environment.cpp @@ -363,7 +363,7 @@ void tst_Environment::pathChanges() QFETCH(QString, value); QFETCH(Environment, expected); - const QString sep = HostOsInfo::pathListSeparator(); + const QString sep = OsSpecificAspects::pathListSeparator(environment.osType()); if (prepend) environment.prependOrSet(variable, value, sep); From bd660aaf27e131c069fb779db556a962c067fdf4 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 8 May 2023 13:37:07 +0200 Subject: [PATCH 0884/1447] CMake: Fix setting additional project files for file watching Amends d8be2491a5f5cfdc512f63c766a550dd43694063 The change above introduced FileApiReader::takeCMakeFileInfos and uses it to move the information about additional CMake files out of the FileApiReader. But that now emptied variable was later used to inform the project about these additional files. So, that broke the automatic running of CMake when project files (except the toplevel one) changes. Instead use the list of additional files that now lives in the CMakeBuildSystem for that purpose. Change-Id: I1062593029880af9d4c70e72e1bd101d40ad0c00 Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp | 11 ++++++++++- src/plugins/cmakeprojectmanager/fileapireader.cpp | 8 -------- src/plugins/cmakeprojectmanager/fileapireader.h | 1 - 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 20c85133216..aaad00ed4bd 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -872,13 +872,22 @@ void CMakeBuildSystem::checkAndReportError(QString &errorMessage) } } +static QSet projectFilesToWatch(const QSet &cmakeFiles) +{ + return Utils::transform(Utils::filtered(cmakeFiles, + [](const CMakeFileInfo &info) { + return !info.isGenerated; + }), + [](const CMakeFileInfo &info) { return info.path; }); +} + void CMakeBuildSystem::updateProjectData() { qCDebug(cmakeBuildSystemLog) << "Updating CMake project data"; QTC_ASSERT(m_treeScanner.isFinished() && !m_reader.isParsing(), return ); - buildConfiguration()->project()->setExtraProjectFiles(m_reader.projectFilesToWatch()); + buildConfiguration()->project()->setExtraProjectFiles(projectFilesToWatch(m_cmakeFiles)); CMakeConfig patchedConfig = configurationFromCMake(); { diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 0ed163021cf..fd507f7bf71 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -165,14 +165,6 @@ bool FileApiReader::isParsing() const return m_isParsing; } -QSet FileApiReader::projectFilesToWatch() const -{ - return Utils::transform( - Utils::filtered(m_cmakeFiles, - [](const CMakeFileInfo &info) { return !info.isGenerated; }), - [](const CMakeFileInfo &info) { return info.path;}); -} - QList FileApiReader::takeBuildTargets(QString &errorMessage){ Q_UNUSED(errorMessage) diff --git a/src/plugins/cmakeprojectmanager/fileapireader.h b/src/plugins/cmakeprojectmanager/fileapireader.h index cb90af8477d..115d22ea71a 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.h +++ b/src/plugins/cmakeprojectmanager/fileapireader.h @@ -44,7 +44,6 @@ public: bool isParsing() const; - QSet projectFilesToWatch() const; QList takeBuildTargets(QString &errorMessage); QSet takeCMakeFileInfos(QString &errorMessage); CMakeConfig takeParsedConfiguration(QString &errorMessage); From 851f317199ec15a6cf0483580c09efa2ab9bde58 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 14:09:09 +0200 Subject: [PATCH 0885/1447] Core: Remove parent pointer from IOptionPage constructor Not used anymore. Change-Id: Ic44ce021b1f952337a3193454b5b6649d5847446 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/dialogs/ioptionspage.cpp | 3 +-- src/plugins/coreplugin/dialogs/ioptionspage.h | 2 +- src/plugins/designer/settingspage.cpp | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index 451859c5274..f7657498ca4 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -240,8 +240,7 @@ static QList g_optionsPages; Constructs an options page with the given \a parent and registers it at the global options page pool if \a registerGlobally is \c true. */ -IOptionsPage::IOptionsPage(QObject *parent, bool registerGlobally) - : QObject(parent) +IOptionsPage::IOptionsPage(bool registerGlobally) { if (registerGlobally) g_optionsPages.append(this); diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 8aa2ed66413..21b5a6ec445 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -42,7 +42,7 @@ class CORE_EXPORT IOptionsPage : public QObject Q_OBJECT public: - IOptionsPage(QObject *parent = nullptr, bool registerGlobally = true); + explicit IOptionsPage(bool registerGlobally = true); ~IOptionsPage() override; static const QList allOptionsPages(); diff --git a/src/plugins/designer/settingspage.cpp b/src/plugins/designer/settingspage.cpp index c393503d5ce..e1998ffd5e3 100644 --- a/src/plugins/designer/settingspage.cpp +++ b/src/plugins/designer/settingspage.cpp @@ -34,8 +34,8 @@ public: }; -SettingsPage::SettingsPage(QDesignerOptionsPageInterface *designerPage) : - Core::IOptionsPage(nullptr, false) +SettingsPage::SettingsPage(QDesignerOptionsPageInterface *designerPage) + : Core::IOptionsPage(false) { setId(Utils::Id::fromString(designerPage->name())); setDisplayName(designerPage->name()); From e3e17c4586bd341b140d0054c68b9e438f056e8a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 8 May 2023 13:47:14 +0200 Subject: [PATCH 0886/1447] Editor: Fix initial enabled state of margin settings Change-Id: I0adff884743dd8301a9c7f8b7a44f94658af4b5f Reviewed-by: hjk --- src/plugins/texteditor/displaysettingspage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index b94c931ab80..7101004bca8 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -258,8 +258,10 @@ void DisplaySettingsWidget::settingsToUI() enableTextWrapping->setChecked(displaySettings.m_textWrapping); showWrapColumn->setChecked(marginSettings.m_showMargin); tintMarginArea->setChecked(marginSettings.m_tintMarginArea); + tintMarginArea->setEnabled(marginSettings.m_showMargin); useIndenter->setChecked(marginSettings.m_useIndenter); wrapColumn->setValue(marginSettings.m_marginColumn); + wrapColumn->setEnabled(marginSettings.m_showMargin); visualizeWhitespace->setChecked(displaySettings.m_visualizeWhitespace); visualizeIndent->setChecked(displaySettings.m_visualizeIndent); displayFoldingMarkers->setChecked(displaySettings.m_displayFoldingMarkers); From 80a425acbae5334b70b468921173240e502ceeb3 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 14:25:50 +0200 Subject: [PATCH 0887/1447] Core: Remove QObject inheritance of IOptionsPageProvider This was not really used. Change-Id: I86049697d211d88827a9633b367d2121fa8d1f1c Reviewed-by: Eike Ziller --- src/plugins/coreplugin/dialogs/ioptionspage.cpp | 3 +-- src/plugins/coreplugin/dialogs/ioptionspage.h | 8 ++++---- src/plugins/designer/settingspage.h | 2 -- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index f7657498ca4..a19458c5fbb 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -277,8 +277,7 @@ bool IOptionsPage::matches(const QRegularExpression ®exp) const static QList g_optionsPagesProviders; -IOptionsPageProvider::IOptionsPageProvider(QObject *parent) - : QObject(parent) +IOptionsPageProvider::IOptionsPageProvider() { g_optionsPagesProviders.append(this); } diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 21b5a6ec445..7849ce0bb13 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -99,13 +99,13 @@ private: before the options pages get available.) */ -class CORE_EXPORT IOptionsPageProvider : public QObject +class CORE_EXPORT IOptionsPageProvider { - Q_OBJECT + Q_DISABLE_COPY_MOVE(IOptionsPageProvider); public: - IOptionsPageProvider(QObject *parent = nullptr); - ~IOptionsPageProvider() override; + IOptionsPageProvider(); + virtual ~IOptionsPageProvider(); static const QList allOptionsPagesProviders(); diff --git a/src/plugins/designer/settingspage.h b/src/plugins/designer/settingspage.h index 5efc062fcba..03206109dba 100644 --- a/src/plugins/designer/settingspage.h +++ b/src/plugins/designer/settingspage.h @@ -19,8 +19,6 @@ public: class SettingsPageProvider : public Core::IOptionsPageProvider { - Q_OBJECT - public: SettingsPageProvider(); From 7808195f74519ae83c23255256106d2d28c41dda Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 4 May 2023 13:21:17 +0200 Subject: [PATCH 0888/1447] CppEditor: Refactor "insert member from use" quickfixes The interfaces make much more sense now, and the coding style is taken into account (except for the fallback case where the user enters the type). Change-Id: If08dfc41ebd63287fb5b0b187944e7fdf08b0823 Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfixes.cpp | 163 +++++++++--------------- src/plugins/cppeditor/cppquickfixes.h | 8 +- 2 files changed, 60 insertions(+), 111 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 2d56cb7ba4c..4c37e75934a 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -302,18 +303,31 @@ ClassSpecifierAST *astForClassOperations(const CppQuickFixInterface &interface) return nullptr; } -// Just the type name if varName is null, full declaration otherwise. -QString typeOfRhsExpr(const BinaryExpressionAST *binExpr, const SimpleNameAST *varName, - const Snapshot &snapshot, const Document::Ptr &doc, - const LookupContext &context, const CppRefactoringFilePtr &file) +QString nameString(const NameAST *name) { - TypeOfExpression typeOfExpression; - typeOfExpression.init(doc, snapshot, context.bindings()); - Scope *scope = file->scopeAt(binExpr->firstToken()); - const QList result = typeOfExpression( - file->textOf(binExpr->right_expression).toUtf8(), scope, TypeOfExpression::Preprocess); - if (result.isEmpty()) + return CppCodeStyleSettings::currentProjectCodeStyleOverview().prettyName(name->name); +} + +QString declFromExpr(const ExpressionAST *expr, const NameAST *varName, + const Snapshot &snapshot, const LookupContext &context, + const CppRefactoringFilePtr &file) +{ + const auto getTypeFromUser = [varName]() -> QString { + const QString typeFromUser = QInputDialog::getText(Core::ICore::dialogParent(), + Tr::tr("Provide the type"), + Tr::tr("Data type:"), QLineEdit::Normal); + if (!typeFromUser.isEmpty()) + return typeFromUser + ' ' + nameString(varName); return {}; + }; + + TypeOfExpression typeOfExpression; + typeOfExpression.init(file->cppDocument(), snapshot, context.bindings()); + Scope *scope = file->scopeAt(expr->firstToken()); + const QList result = typeOfExpression( + file->textOf(expr).toUtf8(), scope, TypeOfExpression::Preprocess); + if (result.isEmpty()) + return getTypeFromUser(); SubstitutionEnvironment env; env.setContext(context); @@ -326,9 +340,9 @@ QString typeOfRhsExpr(const BinaryExpressionAST *binExpr, const SimpleNameAST *v Control *control = context.bindings()->control().data(); FullySpecifiedType tn = rewriteType(result.first().type(), &env, control); - - return CppCodeStyleSettings::currentProjectCodeStyleOverview() - .prettyType(tn, varName ? varName->name : nullptr); + if (!tn.isValid()) + return getTypeFromUser(); + return CppCodeStyleSettings::currentProjectCodeStyleOverview().prettyType(tn, varName->name); } } // anonymous namespace @@ -1640,8 +1654,8 @@ private: if (currentFile->cppDocument()->languageFeatures().cxx11Enabled && settings->useAuto) return "auto " + oo.prettyName(simpleNameAST->name); - return typeOfRhsExpr(binaryAST, simpleNameAST, snapshot(), semanticInfo().doc, context(), - currentFile); + return declFromExpr(binaryAST->right_expression, simpleNameAST, snapshot(), + context(), currentFile); } const BinaryExpressionAST *binaryAST; @@ -2903,30 +2917,28 @@ class InsertMemberFromInitializationOp : public CppQuickFixOperation { public: InsertMemberFromInitializationOp( - const CppQuickFixInterface &interface, - const Class *theClass, - const QString &member, - const QString &type, - InsertionPointLocator::AccessSpec accessSpec) + const CppQuickFixInterface &interface, + const Class *theClass, + const NameAST *memberName, + const ExpressionAST *initExpr, + InsertionPointLocator::AccessSpec accessSpec, + bool makeStatic) : CppQuickFixOperation(interface), - m_class(theClass), m_member(member), m_type(type), m_accessSpec(accessSpec) + m_class(theClass), m_memberName(memberName), m_initExpr(initExpr), + m_accessSpec(accessSpec), m_makeStatic(makeStatic) { - setDescription(Tr::tr("Add Class Member \"%1\"").arg(m_member)); + setDescription(Tr::tr("Add Class Member \"%1\"").arg(nameString(memberName))); } private: void perform() override { - QString type = m_type; - if (type.isEmpty()) { - type = QInputDialog::getText( - Core::ICore::dialogParent(), - Tr::tr("Provide the type"), - Tr::tr("Data type:"), - QLineEdit::Normal); - } - if (type.isEmpty()) + QString decl = declFromExpr(m_initExpr, m_memberName, snapshot(), context(), + currentFile()); + if (decl.isEmpty()) return; + if (m_makeStatic) + decl.prepend("static "); const CppRefactoringChanges refactoring(snapshot()); const InsertionPointLocator locator(refactoring); @@ -2939,16 +2951,17 @@ private: const int targetPosition1 = targetFile->position(loc.line(), loc.column()); const int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1); ChangeSet target; - target.insert(targetPosition1, loc.prefix() + type + ' ' + m_member + ";\n"); + target.insert(targetPosition1, loc.prefix() + decl + ";\n"); targetFile->setChangeSet(target); targetFile->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1)); targetFile->apply(); } const Class * const m_class; - const QString m_member; - const QString m_type; + const NameAST * const m_memberName; + const ExpressionAST * const m_initExpr; const InsertionPointLocator::AccessSpec m_accessSpec; + const bool m_makeStatic; }; void AddDeclarationForUndeclaredIdentifier::match(const CppQuickFixInterface &interface, @@ -3000,18 +3013,14 @@ void AddDeclarationForUndeclaredIdentifier::collectOperations( return; } - const QString typeString = typeOfRhsExpr( - binExpr, nullptr, interface.snapshot(), - interface.semanticInfo().doc, interface.context(), interface.currentFile()); - // In the case of "a.|b = c", find out the type of a, locate the class declaration // and add a member b there. if (const auto memberAccess = binExpr->left_expression->asMemberAccess()) { if (interface.isCursorOn(memberAccess->member_name) && memberAccess->member_name == path.last()) { maybeAddMember(interface, file->scopeAt(memberAccess->firstToken()), - file->textOf(memberAccess->base_expression).toUtf8(), typeString, - result); + file->textOf(memberAccess->base_expression).toUtf8(), + binExpr->right_expression, result); } return; } @@ -3055,8 +3064,8 @@ void AddDeclarationForUndeclaredIdentifier::collectOperations( } if (theClass) { result << new InsertMemberFromInitializationOp( - interface, theClass, getIdentifier(interface), "static " + typeString, - InsertionPointLocator::Public); + interface, theClass, path.last()->asName(), binExpr->right_expression, + InsertionPointLocator::Public, true); } return; } @@ -3066,8 +3075,8 @@ void AddDeclarationForUndeclaredIdentifier::collectOperations( if (const auto simpleName = idExpr->name->asSimpleName()) { if (!m_membersOnly) result << new AddLocalDeclarationOp(interface, index, binExpr, simpleName); - maybeAddMember(interface, file->scopeAt(idExpr->firstToken()), "this", typeString, - result); + maybeAddMember(interface, file->scopeAt(idExpr->firstToken()), "this", + binExpr->right_expression, result); return; } } @@ -3118,19 +3127,15 @@ bool AddDeclarationForUndeclaredIdentifier::checkForMemberInitializer( return false; } - const QString type = getType(interface, memInitializer, ctor); - const Identifier * const memberId = interface.currentFile()->cppDocument() - ->translationUnit()->identifier(name->identifier_token); - const QString member = QString::fromUtf8(memberId->chars(), memberId->size()); - - result << new InsertMemberFromInitializationOp(interface, theClass, member, type, - InsertionPointLocator::Private); + result << new InsertMemberFromInitializationOp( + interface, theClass, memInitializer->name->asSimpleName(), memInitializer->expression, + InsertionPointLocator::Private, false); return false; } void AddDeclarationForUndeclaredIdentifier::maybeAddMember( const CppQuickFixInterface &interface, Scope *scope, const QByteArray &classTypeExpr, - const QString &typeString, TextEditor::QuickFixOperations &result) + const ExpressionAST *initExpr, TextEditor::QuickFixOperations &result) { const QList &path = interface.path(); @@ -3193,58 +3198,8 @@ void AddDeclarationForUndeclaredIdentifier::maybeAddMember( break; } } - - QString fullType = typeString; - if (needsStatic) - fullType.prepend("static "); - result << new InsertMemberFromInitializationOp(interface, theClass, getIdentifier(interface), - fullType, accessSpec); -} - -QString AddDeclarationForUndeclaredIdentifier::getType( - const CppQuickFixInterface &interface, - const MemInitializerAST *memInitializer, - const FunctionDefinitionAST *ctor) const -{ - // Try to deduce the type: If the initialization expression is just a name - // (e.g. a constructor argument) or a function call, we don't bother the user. - if (!memInitializer->expression) - return {}; - const ExpressionListParenAST * const lParenAst - = memInitializer->expression->asExpressionListParen(); - if (!lParenAst || !lParenAst->expression_list || !lParenAst->expression_list->value) - return {}; - const IdExpressionAST *idExpr = lParenAst->expression_list->value->asIdExpression(); - if (!idExpr) { // Not a variable, so check for function call. - const CallAST * const call = lParenAst->expression_list->value->asCall(); - if (!call || !call->base_expression) - return {}; - idExpr = call->base_expression->asIdExpression(); - } - if (!idExpr || !idExpr->name) - return {}; - - LookupContext context(interface.currentFile()->cppDocument(), interface.snapshot()); - const QList matches = context.lookup(idExpr->name->name, ctor->symbol); - if (matches.isEmpty()) - return {}; - Overview o = CppCodeStyleSettings::currentProjectCodeStyleOverview(); - TypePrettyPrinter tpp(&o); - FullySpecifiedType type = matches.first().type(); - if (!type.type()) - return {}; - const Function * const funcType = type.type()->asFunctionType(); - if (funcType) - type = funcType->returnType(); - return tpp(type); -} - -QString AddDeclarationForUndeclaredIdentifier::getIdentifier( - const CppQuickFixInterface &interface) const -{ - const Identifier * const memberId = interface.currentFile()->cppDocument()->translationUnit() - ->identifier(interface.path().last()->asSimpleName()->identifier_token); - return QString::fromUtf8(memberId->chars(), memberId->size()); + result << new InsertMemberFromInitializationOp(interface, theClass, path.last()->asName(), + initExpr, accessSpec, needsStatic); } class MemberFunctionImplSetting diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h index 252a3bcc9e3..04c54793e97 100644 --- a/src/plugins/cppeditor/cppquickfixes.h +++ b/src/plugins/cppeditor/cppquickfixes.h @@ -376,15 +376,9 @@ private: TextEditor::QuickFixOperations &result); void maybeAddMember(const CppQuickFixInterface &interface, CPlusPlus::Scope *scope, - const QByteArray &classTypeExpr, const QString &typeString, + const QByteArray &classTypeExpr, const CPlusPlus::ExpressionAST *initExpr, TextEditor::QuickFixOperations &result); - QString getType( - const CppQuickFixInterface &interface, - const CPlusPlus::MemInitializerAST *memInitializer, - const CPlusPlus::FunctionDefinitionAST *ctor) const; - QString getIdentifier(const CppQuickFixInterface &interface) const; - bool m_membersOnly = false; }; From 3f1a75eacce37a17b671701393ab0dc4ee0491a5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 15:00:34 +0200 Subject: [PATCH 0889/1447] Git: Small simplification to Gerrit "plugin" setup The indirection is not needed. It's not really stand-alone, and not touched before GitPlugin::initialize(). Change-Id: If8552dc69ff9efa18a3f1d6d998a8f28ab65e501 Reviewed-by: Orgad Shaneh --- src/plugins/git/gerrit/gerritplugin.cpp | 7 +++---- src/plugins/git/gerrit/gerritplugin.h | 5 +++-- src/plugins/git/gitplugin.cpp | 15 +++++++-------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 8ffc7a6d447..3b46022e771 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -152,16 +152,15 @@ void FetchContext::checkout() GitClient::instance()->checkout(m_repository, "FETCH_HEAD"); } -GerritPlugin::GerritPlugin(QObject *parent) - : QObject(parent) - , m_parameters(new GerritParameters) +GerritPlugin::GerritPlugin() + : m_parameters(new GerritParameters) , m_server(new GerritServer) { } GerritPlugin::~GerritPlugin() = default; -void GerritPlugin::initialize(ActionContainer *ac) +void GerritPlugin::addToMenu(ActionContainer *ac) { m_parameters->fromSettings(ICore::settings()); diff --git a/src/plugins/git/gerrit/gerritplugin.h b/src/plugins/git/gerrit/gerritplugin.h index 77d96d9f74a..8de02570827 100644 --- a/src/plugins/git/gerrit/gerritplugin.h +++ b/src/plugins/git/gerrit/gerritplugin.h @@ -29,11 +29,12 @@ class GerritServer; class GerritPlugin : public QObject { Q_OBJECT + public: - explicit GerritPlugin(QObject *parent = nullptr); + GerritPlugin(); ~GerritPlugin() override; - void initialize(Core::ActionContainer *ac); + void addToMenu(Core::ActionContainer *ac); static Utils::FilePath gitBinDirectory(); static QString branch(const Utils::FilePath &repository); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 1ef47ff6669..a9d1cb0c6f2 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -418,7 +418,7 @@ public: QVector m_projectActions; QVector m_repositoryActions; ParameterAction *m_applyCurrentFilePatchAction = nullptr; - Gerrit::Internal::GerritPlugin *m_gerritPlugin = nullptr; + Gerrit::Internal::GerritPlugin m_gerritPlugin; GitSettings m_settings; GitClient m_gitClient{&m_settings}; @@ -1065,10 +1065,9 @@ GitPluginPrivate::GitPluginPrivate() this, &GitPluginPrivate::updateBranches, Qt::QueuedConnection); /* "Gerrit" */ - m_gerritPlugin = new Gerrit::Internal::GerritPlugin(this); - m_gerritPlugin->initialize(remoteRepositoryMenu); - m_gerritPlugin->updateActions(currentState()); - m_gerritPlugin->addToLocator(m_commandLocator); + m_gerritPlugin.addToMenu(remoteRepositoryMenu); + m_gerritPlugin.updateActions(currentState()); + m_gerritPlugin.addToLocator(m_commandLocator); connect(&m_settings, &AspectContainer::applied, this, &GitPluginPrivate::onApplySettings); @@ -1927,7 +1926,7 @@ void GitPluginPrivate::updateActions(VcsBasePluginPrivate::ActionState as) updateContinueAndAbortCommands(); updateRepositoryBrowserAction(); - m_gerritPlugin->updateActions(state); + m_gerritPlugin.updateActions(state); } void GitPluginPrivate::updateContinueAndAbortCommands() @@ -1965,7 +1964,7 @@ void GitPluginPrivate::updateContinueAndAbortCommands() void GitPluginPrivate::delayedPushToGerrit() { - m_gerritPlugin->push(m_submitRepository); + m_gerritPlugin.push(m_submitRepository); } void GitPluginPrivate::updateBranches(const FilePath &repository) @@ -2172,7 +2171,7 @@ void GitPlugin::updateBranches(const FilePath &repository) void GitPlugin::gerritPush(const FilePath &topLevel) { - dd->m_gerritPlugin->push(topLevel); + dd->m_gerritPlugin.push(topLevel); } bool GitPlugin::isCommitEditorOpen() From 1b4aa44e89d47222ca686e17fd8892513176ca6f Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 14:51:42 +0200 Subject: [PATCH 0890/1447] QmlDesignerBase: Remove the dependency on IOptionPage's QObject base The base will be cut soonish, and the only use here was tr() with a (wrong) context. Use StudioSettingsPage for that now. Change-Id: I41e4b737713591e002c126bbf97226de7c3f784f Reviewed-by: Mahmoud Badri --- src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp | 2 +- src/plugins/qmldesignerbase/qmldesignerbaseplugin.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp index 0dc9734e8fb..0a9ef8483a1 100644 --- a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp +++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp @@ -264,7 +264,7 @@ void StudioSettingsPage::apply() StudioConfigSettingsPage::StudioConfigSettingsPage() { setId("Z.StudioConfig.Settings"); - setDisplayName(tr("Qt Design Studio Configuration")); + setDisplayName(StudioSettingsPage::tr("Qt Design Studio Configuration")); setCategory(Core::Constants::SETTINGS_CATEGORY_CORE); setWidgetCreator([] { return new StudioSettingsPage; }); } diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h index de9c9cabe37..3676a04e8c1 100644 --- a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h +++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h @@ -35,8 +35,6 @@ private: class QMLDESIGNERBASE_EXPORT StudioConfigSettingsPage : public Core::IOptionsPage { - Q_OBJECT - public: StudioConfigSettingsPage(); }; From 5a318df0eeed48bfff83001a728fe10b6d0cc58b Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 11:40:44 +0200 Subject: [PATCH 0891/1447] Perforce: Don't use Option page as guard object There's a plan to remove the QObject base from IOptionPage Change-Id: I142d2323f86e46d7758f8bd9a65c988988a18ed1 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/perforce/perforcesettings.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp index 2f1e930fb63..ee18c4ee5fc 100644 --- a/src/plugins/perforce/perforcesettings.cpp +++ b/src/plugins/perforce/perforcesettings.cpp @@ -206,24 +206,24 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); setSettings(settings); - setLayouter([settings, this](QWidget *widget) { + setLayouter([settings](QWidget *widget) { PerforceSettings &s = *settings; using namespace Layouting; auto errorLabel = new QLabel; auto testButton = new QPushButton(Tr::tr("Test")); - connect(testButton, &QPushButton::clicked, this, [settings, errorLabel, testButton] { + QObject::connect(testButton, &QPushButton::clicked, widget, [settings, errorLabel, testButton] { testButton->setEnabled(false); auto checker = new PerforceChecker(errorLabel); checker->setUseOverideCursor(true); - connect(checker, &PerforceChecker::failed, errorLabel, + QObject::connect(checker, &PerforceChecker::failed, errorLabel, [errorLabel, testButton, checker](const QString &t) { errorLabel->setStyleSheet("background-color: red"); errorLabel->setText(t); testButton->setEnabled(true); checker->deleteLater(); }); - connect(checker, &PerforceChecker::succeeded, errorLabel, + QObject::connect(checker, &PerforceChecker::succeeded, errorLabel, [errorLabel, testButton, checker](const FilePath &repo) { errorLabel->setStyleSheet({}); errorLabel->setText(Tr::tr("Test succeeded (%1).") From a8f288fc9e752f34e8e3b732ced758074060c52d Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 8 May 2023 14:28:20 +0200 Subject: [PATCH 0892/1447] CMakePM: Store CMake Autorun state for all tools Amends 2f39b51bdc1f73e2d87cc641a8501fd04ee76b4f The default tool's value is taken as default global value, then will be saved for all tools. This fixes the case when the false Autorun value for the default CMake tool would always be set as global autorun with no option to actually set global Autorun value due to the "upgrade" path mechanism. Change-Id: I17076bc0c77b087c5d4048fdfe74ddf91d837fd4 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/cmakeprojectmanager/cmaketool.h | 2 ++ src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp | 1 + .../cmakeprojectmanager/cmaketoolsettingsaccessor.cpp | 8 +++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h index 42fa7b8f62d..54628910cc1 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.h +++ b/src/plugins/cmakeprojectmanager/cmaketool.h @@ -61,6 +61,8 @@ public: Utils::Id id() const { return m_id; } QVariantMap toMap () const; + void setAutorun(bool autoRun) { m_isAutoRun = autoRun; } + void setFilePath(const Utils::FilePath &executable); Utils::FilePath filePath() const; Utils::FilePath cmakeExecutable() const; diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp index 8bc396ced1a..7e4c777317d 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp @@ -141,6 +141,7 @@ void CMakeToolManager::restoreCMakeTools() emit m_instance->cmakeToolsLoaded(); // Store the default CMake tool "Autorun CMake" value globally + // TODO: Remove in Qt Creator 13 auto settings = Internal::CMakeSpecificSettings::instance(); if (settings->autorunCMake.value() == settings->autorunCMake.defaultValue()) { CMakeTool *cmake = defaultCMakeTool(); diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp index 43f1915709f..cfce81f005f 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp @@ -4,6 +4,7 @@ #include "cmaketoolsettingsaccessor.h" #include "cmakeprojectmanagertr.h" +#include "cmakespecificsettings.h" #include "cmaketool.h" #include @@ -185,9 +186,14 @@ void CMakeToolSettingsAccessor::saveCMakeTools(const QList &cmakeTo data.insert(QLatin1String(CMAKE_TOOL_DEFAULT_KEY), defaultId.toSetting()); int count = 0; - for (const CMakeTool *item : cmakeTools) { + for (CMakeTool *item : cmakeTools) { Utils::FilePath fi = item->cmakeExecutable(); + // Gobal Autorun value will be set for all tools + // TODO: Remove in Qt Creator 13 + const auto settings = CMakeSpecificSettings::instance(); + item->setAutorun(settings->autorunCMake.value()); + if (fi.needsDevice() || fi.isExecutableFile()) { // be graceful for device related stuff QVariantMap tmp = item->toMap(); if (tmp.isEmpty()) From 72093746ac6134551c7f7de8cc9570e1940b1e20 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 15:25:08 +0200 Subject: [PATCH 0893/1447] Git: Use LayoutBuilder in Gerrit options page Move towards using aspects and away from IOptionPage's QObject base. Change-Id: I07850a6b8e9fa7d2591efc6f76a23f249dfc164f Reviewed-by: Orgad Shaneh --- src/plugins/git/gerrit/gerritoptionspage.cpp | 128 +++++++++---------- src/plugins/git/gerrit/gerritoptionspage.h | 8 +- src/plugins/git/gerrit/gerritplugin.cpp | 20 +-- src/plugins/git/gerrit/gerritplugin.h | 4 +- 4 files changed, 77 insertions(+), 83 deletions(-) diff --git a/src/plugins/git/gerrit/gerritoptionspage.cpp b/src/plugins/git/gerrit/gerritoptionspage.cpp index 3b96d160bd0..3f225d82eb1 100644 --- a/src/plugins/git/gerrit/gerritoptionspage.cpp +++ b/src/plugins/git/gerrit/gerritoptionspage.cpp @@ -7,6 +7,8 @@ #include "../gittr.h" #include + +#include #include #include @@ -21,90 +23,82 @@ namespace Gerrit::Internal { class GerritOptionsWidget : public Core::IOptionsPageWidget { public: - GerritOptionsWidget(GerritOptionsPage *page, const QSharedPointer &p) - : m_page(page) - , m_hostLineEdit(new QLineEdit(this)) - , m_userLineEdit(new QLineEdit(this)) - , m_sshChooser(new Utils::PathChooser) - , m_curlChooser(new Utils::PathChooser) - , m_portSpinBox(new QSpinBox(this)) - , m_httpsCheckBox(new QCheckBox(Git::Tr::tr("HTTPS"))) - , m_parameters(p) + GerritOptionsWidget(const QSharedPointer &p, + const std::function &onChanged) + : m_parameters(p) { - m_hostLineEdit->setText(p->server.host); - m_userLineEdit->setText(p->server.user.userName); - m_sshChooser->setFilePath(p->ssh); - m_curlChooser->setFilePath(p->curl); - m_portSpinBox->setValue(p->server.port); - m_httpsCheckBox->setChecked(p->https); + auto hostLineEdit = new QLineEdit(p->server.host); - auto formLayout = new QFormLayout(this); - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - formLayout->addRow(Git::Tr::tr("&Host:"), m_hostLineEdit); - formLayout->addRow(Git::Tr::tr("&User:"), m_userLineEdit); - m_sshChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_sshChooser->setCommandVersionArguments({"-V"}); - m_sshChooser->setHistoryCompleter("Git.SshCommand.History"); - formLayout->addRow(Git::Tr::tr("&ssh:"), m_sshChooser); - m_curlChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_curlChooser->setCommandVersionArguments({"-V"}); - formLayout->addRow(Git::Tr::tr("cur&l:"), m_curlChooser); - m_portSpinBox->setMinimum(1); - m_portSpinBox->setMaximum(65535); - formLayout->addRow(Git::Tr::tr("SSH &Port:"), m_portSpinBox); - formLayout->addRow(Git::Tr::tr("P&rotocol:"), m_httpsCheckBox); - m_httpsCheckBox->setToolTip(Git::Tr::tr( + auto userLineEdit = new QLineEdit(p->server.user.userName); + + auto sshChooser = new Utils::PathChooser; + sshChooser->setFilePath(p->ssh); + sshChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); + sshChooser->setCommandVersionArguments({"-V"}); + sshChooser->setHistoryCompleter("Git.SshCommand.History"); + + auto curlChooser = new Utils::PathChooser; + curlChooser->setFilePath(p->curl); + curlChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); + curlChooser->setCommandVersionArguments({"-V"}); + + auto portSpinBox = new QSpinBox(this); + portSpinBox->setValue(p->server.port); + portSpinBox->setRange(1, 65535); + + auto httpsCheckBox = new QCheckBox(Git::Tr::tr("HTTPS")); + httpsCheckBox->setChecked(p->https); + httpsCheckBox->setToolTip(Git::Tr::tr( "Determines the protocol used to form a URL in case\n" "\"canonicalWebUrl\" is not configured in the file\n" "\"gerrit.config\".")); - setTabOrder(m_sshChooser, m_curlChooser); - setTabOrder(m_curlChooser, m_portSpinBox); + + using namespace Layouting; + Form { + Git::Tr::tr("&Host:"), hostLineEdit, br, + Git::Tr::tr("&User:"), userLineEdit, br, + Git::Tr::tr("&ssh:"), sshChooser, br, + Git::Tr::tr("cur&l:"), curlChooser, br, + Git::Tr::tr("SSH &Port:"), portSpinBox, br, + Git::Tr::tr("P&rotocol:"), httpsCheckBox + }.attachTo(this); + + setOnApply([this, hostLineEdit, userLineEdit, sshChooser, + curlChooser, portSpinBox, httpsCheckBox, onChanged] { + GerritParameters newParameters; + newParameters.server = GerritServer(hostLineEdit->text().trimmed(), + static_cast(portSpinBox->value()), + userLineEdit->text().trimmed(), + GerritServer::Ssh); + newParameters.ssh = sshChooser->filePath(); + newParameters.curl = curlChooser->filePath(); + newParameters.https = httpsCheckBox->isChecked(); + + if (newParameters != *m_parameters) { + if (m_parameters->ssh == newParameters.ssh) + newParameters.portFlag = m_parameters->portFlag; + else + newParameters.setPortFlagBySshType(); + *m_parameters = newParameters; + m_parameters->toSettings(Core::ICore::settings()); + emit onChanged(); + } + }); } private: - void apply() final; - - GerritOptionsPage *m_page; - QLineEdit *m_hostLineEdit; - QLineEdit *m_userLineEdit; - Utils::PathChooser *m_sshChooser; - Utils::PathChooser *m_curlChooser; - QSpinBox *m_portSpinBox; - QCheckBox *m_httpsCheckBox; const QSharedPointer &m_parameters; }; -void GerritOptionsWidget::apply() -{ - GerritParameters newParameters; - newParameters.server = GerritServer(m_hostLineEdit->text().trimmed(), - static_cast(m_portSpinBox->value()), - m_userLineEdit->text().trimmed(), - GerritServer::Ssh); - newParameters.ssh = m_sshChooser->filePath(); - newParameters.curl = m_curlChooser->filePath(); - newParameters.https = m_httpsCheckBox->isChecked(); - - if (newParameters != *m_parameters) { - if (m_parameters->ssh == newParameters.ssh) - newParameters.portFlag = m_parameters->portFlag; - else - newParameters.setPortFlagBySshType(); - *m_parameters = newParameters; - m_parameters->toSettings(Core::ICore::settings()); - emit m_page->settingsChanged(); - } -} - // GerritOptionsPage -GerritOptionsPage::GerritOptionsPage(const QSharedPointer &p, QObject *parent) - : Core::IOptionsPage(parent) +GerritOptionsPage::GerritOptionsPage(const QSharedPointer &p, + const std::function &onChanged) { setId("Gerrit"); setDisplayName(Git::Tr::tr("Gerrit")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setWidgetCreator([this, p] { return new GerritOptionsWidget(this, p); }); + setWidgetCreator([p, onChanged] { return new GerritOptionsWidget(p, onChanged); }); } } // Gerrit::Internal diff --git a/src/plugins/git/gerrit/gerritoptionspage.h b/src/plugins/git/gerrit/gerritoptionspage.h index 6e6695ae367..96caab06092 100644 --- a/src/plugins/git/gerrit/gerritoptionspage.h +++ b/src/plugins/git/gerrit/gerritoptionspage.h @@ -13,13 +13,9 @@ class GerritParameters; class GerritOptionsPage : public Core::IOptionsPage { - Q_OBJECT - public: - GerritOptionsPage(const QSharedPointer &p, QObject *parent = nullptr); - -signals: - void settingsChanged(); + GerritOptionsPage(const QSharedPointer &p, + const std::function &onChanged); }; } // Gerrit::Internal diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 3b46022e771..87ce5bfdaca 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -156,13 +156,22 @@ GerritPlugin::GerritPlugin() : m_parameters(new GerritParameters) , m_server(new GerritServer) { + m_parameters->fromSettings(ICore::settings()); + + m_gerritOptionsPage = new GerritOptionsPage(m_parameters, + [this] { + if (m_dialog) + m_dialog->scheduleUpdateRemotes(); + }); } -GerritPlugin::~GerritPlugin() = default; +GerritPlugin::~GerritPlugin() +{ + delete m_gerritOptionsPage; +} void GerritPlugin::addToMenu(ActionContainer *ac) { - m_parameters->fromSettings(ICore::settings()); QAction *openViewAction = new QAction(Git::Tr::tr("Gerrit..."), this); @@ -177,13 +186,6 @@ void GerritPlugin::addToMenu(ActionContainer *ac) ActionManager::registerAction(pushAction, Constants::GERRIT_PUSH); connect(pushAction, &QAction::triggered, this, [this] { push(); }); ac->addAction(m_pushToGerritCommand); - - auto options = new GerritOptionsPage(m_parameters, this); - connect(options, &GerritOptionsPage::settingsChanged, - this, [this] { - if (m_dialog) - m_dialog->scheduleUpdateRemotes(); - }); } void GerritPlugin::updateActions(const VcsBase::VcsBasePluginState &state) diff --git a/src/plugins/git/gerrit/gerritplugin.h b/src/plugins/git/gerrit/gerritplugin.h index 8de02570827..b7e0de29d81 100644 --- a/src/plugins/git/gerrit/gerritplugin.h +++ b/src/plugins/git/gerrit/gerritplugin.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include #include @@ -25,6 +25,7 @@ class GerritChange; class GerritDialog; class GerritParameters; class GerritServer; +class GerritOptionsPage; class GerritPlugin : public QObject { @@ -60,6 +61,7 @@ private: Core::Command *m_gerritCommand = nullptr; Core::Command *m_pushToGerritCommand = nullptr; QString m_reviewers; + GerritOptionsPage *m_gerritOptionsPage = nullptr; }; } // namespace Internal From 65281429d45673b189557ebd0cb0ba52f8653d12 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 14:42:50 +0200 Subject: [PATCH 0894/1447] VcsPlugin: shift signalling of settings changes To allow removing the QObject ineritance of IOptionPage Change-Id: Id230ee9230dd1bee094b19b5a22d61d37e650d27 Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/commonvcssettings.cpp | 4 ++-- src/plugins/vcsbase/commonvcssettings.h | 12 ++++++------ src/plugins/vcsbase/vcsplugin.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 3284f7df31b..46c412011e5 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -127,11 +127,11 @@ public: connect(cacheResetButton, &QPushButton::clicked, Core::VcsManager::instance(), &Core::VcsManager::clearVersionControlCache); - setOnApply([&s, page] { + setOnApply([&s] { if (s.isDirty()) { s.apply(); s.writeSettings(Core::ICore::settings()); - emit page->settingsChanged(); + emit s.settingsChanged(); } }); } diff --git a/src/plugins/vcsbase/commonvcssettings.h b/src/plugins/vcsbase/commonvcssettings.h index 8d781a45d72..376ad0bae90 100644 --- a/src/plugins/vcsbase/commonvcssettings.h +++ b/src/plugins/vcsbase/commonvcssettings.h @@ -12,6 +12,8 @@ namespace Internal { class CommonVcsSettings : public Utils::AspectContainer { + Q_OBJECT + public: CommonVcsSettings(); @@ -27,20 +29,18 @@ public: Utils::BoolAspect lineWrap; Utils::IntegerAspect lineWrapWidth; + +signals: + void settingsChanged(); }; class CommonOptionsPage final : public Core::IOptionsPage { - Q_OBJECT - public: - explicit CommonOptionsPage(); + CommonOptionsPage(); CommonVcsSettings &settings() { return m_settings; } -signals: - void settingsChanged(); - private: CommonVcsSettings m_settings; }; diff --git a/src/plugins/vcsbase/vcsplugin.cpp b/src/plugins/vcsbase/vcsplugin.cpp index 5d14b3a4722..0596f406b8b 100644 --- a/src/plugins/vcsbase/vcsplugin.cpp +++ b/src/plugins/vcsbase/vcsplugin.cpp @@ -40,7 +40,7 @@ public: explicit VcsPluginPrivate(VcsPlugin *plugin) : q(plugin) { - QObject::connect(&m_settingsPage, &CommonOptionsPage::settingsChanged, + QObject::connect(&m_settingsPage.settings(), &CommonVcsSettings::settingsChanged, [this] { slotSettingsChanged(); }); slotSettingsChanged(); } @@ -101,7 +101,7 @@ void VcsPlugin::initialize() return result; }); - connect(&d->m_settingsPage, &CommonOptionsPage::settingsChanged, + connect(&d->m_settingsPage.settings(), &CommonVcsSettings::settingsChanged, this, &VcsPlugin::settingsChanged); JsonWizardFactory::registerPageFactory(new Internal::VcsConfigurationPageFactory); From 3f7e92e052469646c85b1eb65918ea84db67088c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 7 May 2023 20:58:46 +0200 Subject: [PATCH 0895/1447] Utils: Introduce QTC_STATIC_SCOPED_TIMER() This macro, similar to QTC_SCOPED_TIMER(), measures the time spent in a block of code. In addition, the time spent in a block is saved in a static variable. This macro enables measuring a cumulative time spent inside a certain block of code for all invocations. When a long freeze is being tracked, and QTC_SCOPED_TIMER() indicates that the most of the freeze is spent inside a loop with a big amount of iterations, placing QTC_STATIC_SCOPED_TIMER() inside the loop may detect the part of the loop that composes in total for the longest freeze. In contrary to the QTC_SCOPED_TIMER(), this macro it doesn't print the message when it's entered. It prints the output at first hit, and later, as not to clog the debug output, only at 10ms resolution. Change-Id: I3360a3ab9147d544f90ce914fb78359f7179c767 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/utils/CMakeLists.txt | 1 + src/libs/utils/qtcassert.cpp | 28 --------------- src/libs/utils/qtcassert.h | 20 ----------- src/libs/utils/scopedtimer.cpp | 64 ++++++++++++++++++++++++++++++++++ src/libs/utils/scopedtimer.h | 38 ++++++++++++++++++++ src/libs/utils/utils.qbs | 2 ++ 6 files changed, 105 insertions(+), 48 deletions(-) create mode 100644 src/libs/utils/scopedtimer.cpp create mode 100644 src/libs/utils/scopedtimer.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index e3bbfcf7a97..f05398094a4 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -147,6 +147,7 @@ add_qtc_library(Utils runextensions.cpp runextensions.h savefile.cpp savefile.h scopedswap.h + scopedtimer.cpp scopedtimer.h searchresultitem.cpp searchresultitem.h set_algorithm.h settingsaccessor.cpp settingsaccessor.h diff --git a/src/libs/utils/qtcassert.cpp b/src/libs/utils/qtcassert.cpp index 019c223ef78..78baa41a4a8 100644 --- a/src/libs/utils/qtcassert.cpp +++ b/src/libs/utils/qtcassert.cpp @@ -8,8 +8,6 @@ #include #include -#include - #if defined(Q_OS_UNIX) #include #include @@ -132,30 +130,4 @@ void writeAssertLocation(const char *msg) dumpBacktrace(maxdepth); } -using namespace std::chrono; - -class ScopedTimerPrivate -{ -public: - const char *m_fileName = nullptr; - const int m_line = 0; - const time_point m_start = system_clock::now(); -}; - -ScopedTimer::ScopedTimer(const char *fileName, int line) - : d(new ScopedTimerPrivate{fileName, line}) -{ - const QByteArray time = QTime::currentTime().toString(Qt::ISODateWithMs).toLatin1(); - qDebug("SCOPED TIMER [%s] in %s:%d started", time.data(), d->m_fileName, d->m_line); -} - -ScopedTimer::~ScopedTimer() -{ - const auto end = system_clock::now(); - const auto elapsed = duration_cast(end - d->m_start); - const QByteArray time = QTime::currentTime().toString(Qt::ISODateWithMs).toLatin1(); - qDebug("SCOPED TIMER [%s] in %s:%d stopped with timeout: %ldms", - time.data(), d->m_fileName, d->m_line, elapsed.count()); -} - } // namespace Utils diff --git a/src/libs/utils/qtcassert.h b/src/libs/utils/qtcassert.h index aab7ab93d09..8f6b2ec5b86 100644 --- a/src/libs/utils/qtcassert.h +++ b/src/libs/utils/qtcassert.h @@ -5,25 +5,9 @@ #include "utils_global.h" -#include - namespace Utils { - QTCREATOR_UTILS_EXPORT void writeAssertLocation(const char *msg); QTCREATOR_UTILS_EXPORT void dumpBacktrace(int maxdepth); - -class ScopedTimerPrivate; - -class QTCREATOR_UTILS_EXPORT ScopedTimer -{ -public: - ScopedTimer(const char *fileName, int line); - ~ScopedTimer(); - -private: - std::unique_ptr d; -}; - } // Utils #define QTC_ASSERT_STRINGIFY_HELPER(x) #x @@ -37,7 +21,3 @@ private: #define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0) #define QTC_CHECK(cond) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); } do {} while (0) #define QTC_GUARD(cond) ((Q_LIKELY(cond)) ? true : (QTC_ASSERT_STRING(#cond), false)) - -#define QTC_CONCAT_HELPER(x, y) x ## y -#define QTC_CONCAT(x, y) QTC_CONCAT_HELPER(x, y) -#define QTC_SCOPED_TIMER() ::Utils::ScopedTimer QTC_CONCAT(_qtc_scoped_timer_, __LINE__)(__FILE__, __LINE__) diff --git a/src/libs/utils/scopedtimer.cpp b/src/libs/utils/scopedtimer.cpp new file mode 100644 index 00000000000..97b8beffdaa --- /dev/null +++ b/src/libs/utils/scopedtimer.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "scopedtimer.h" + +#include +#include +#include + +#include + +namespace Utils { + +static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateWithMs); } + +using namespace std::chrono; + +class ScopedTimerPrivate +{ +public: + const char *m_fileName = nullptr; + const int m_line = 0; + std::atomic *m_cumulative = nullptr; + const time_point m_start = system_clock::now(); +}; + +static const char s_scoped[] = "SCOPED TIMER"; +static const char s_scopedCumulative[] = "STATIC SCOPED TIMER"; + +ScopedTimer::ScopedTimer(const char *fileName, int line, std::atomic *cumulative) + : d(new ScopedTimerPrivate{fileName, line, cumulative}) +{ + if (d->m_cumulative) + return; + qDebug().noquote().nospace() << s_scoped << " [" << currentTime() << "] in " << d->m_fileName + << ':' << d->m_line << " started"; +} + +static int64_t toMs(int64_t ns) { return ns / 1000000; } + +ScopedTimer::~ScopedTimer() +{ + const auto elapsed = duration_cast(system_clock::now() - d->m_start); + QString suffix; + if (d->m_cumulative) { + const int64_t nsOld = d->m_cumulative->fetch_add(elapsed.count()); + const int64_t msOld = toMs(nsOld); + const int64_t nsNew = nsOld + elapsed.count(); + const int64_t msNew = toMs(nsNew); + // Always report the first hit, and later, as not to clog the debug output, + // only at 10ms resolution. + if (nsOld != 0 && msOld / 10 == msNew / 10) + return; + + suffix = " cumulative timeout: " + QString::number(msNew) + "ms"; + } else { + suffix = " stopped with timeout: " + QString::number(toMs(elapsed.count())) + "ms"; + } + const char *header = d->m_cumulative ? s_scopedCumulative : s_scoped; + qDebug().noquote().nospace() << header << " [" << currentTime() << "] in " << d->m_fileName + << ':' << d->m_line << suffix; +} + +} // namespace Utils diff --git a/src/libs/utils/scopedtimer.h b/src/libs/utils/scopedtimer.h new file mode 100644 index 00000000000..e6ec42e6f44 --- /dev/null +++ b/src/libs/utils/scopedtimer.h @@ -0,0 +1,38 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "utils_global.h" + +#include +#include + +namespace Utils { + +class ScopedTimerPrivate; + +class QTCREATOR_UTILS_EXPORT ScopedTimer +{ +public: + ScopedTimer(const char *fileName, int line, std::atomic *cumulative = nullptr); + ~ScopedTimer(); + +private: + std::unique_ptr d; +}; + +} // Utils + +#define QTC_CONCAT_HELPER(x, y) x ## y +#define QTC_CONCAT(x, y) QTC_CONCAT_HELPER(x, y) +#define QTC_SCOPED_TIMER() ::Utils::ScopedTimer QTC_CONCAT(_qtc_scoped_timer_, __LINE__)\ +(__FILE__, __LINE__) + +// The macro below expands as follows (in one line): +// static std::atomic _qtc_static_scoped_timer___LINE__ = 0; +// ScopedTimer _qtc_scoped_timer___LINE__(__FILE__, __LINE__, &_qtc_static_scoped_timer___LINE__) +#define QTC_STATIC_SCOPED_TIMER() static std::atomic \ +QTC_CONCAT(_qtc_static_scoped_timer_, __LINE__) = 0; \ +::Utils::ScopedTimer QTC_CONCAT(_qtc_scoped_timer_, __LINE__)\ +(__FILE__, __LINE__, &QTC_CONCAT(_qtc_static_scoped_timer_, __LINE__)) diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index fa766b8bc4a..f1940a053da 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -275,6 +275,8 @@ Project { "savefile.cpp", "savefile.h", "scopedswap.h", + "scopedtimer.cpp", + "scopedtimer.h", "searchresultitem.cpp", "searchresultitem.h", "set_algorithm.h", From b2226c99d4f970de07648ac325d2c8e525283da0 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 08:15:22 +0200 Subject: [PATCH 0896/1447] VCS: fix compile of CommonVcsSettings Remove undeclared operator definition Amends 65281429d45673b189557ebd0cb0ba52f8653d12 Change-Id: I30ffd5d7b4a50acd9db7acef1668a26c942cc50c Reviewed-by: hjk --- src/plugins/vcsbase/commonvcssettings.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/vcsbase/commonvcssettings.h b/src/plugins/vcsbase/commonvcssettings.h index 376ad0bae90..b1cf09ac14a 100644 --- a/src/plugins/vcsbase/commonvcssettings.h +++ b/src/plugins/vcsbase/commonvcssettings.h @@ -17,8 +17,6 @@ class CommonVcsSettings : public Utils::AspectContainer public: CommonVcsSettings(); - friend QDebug operator<<(QDebug, const CommonVcsSettings &); - Utils::StringAspect nickNameMailMap; Utils::StringAspect nickNameFieldListFile; From dfaebde5207dc2ede076333658f80e0e88f265c8 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 3 Mar 2023 14:30:47 +0100 Subject: [PATCH 0897/1447] ProjectExplorer: Simplify a complex translatable string Change-Id: I51a3f18b2c05eb7371d77c18f3f390f5809e2920 Reviewed-by: Eike Ziller --- share/qtcreator/translations/qtcreator_cs.ts | 8 ++------ share/qtcreator/translations/qtcreator_da.ts | 4 ++-- share/qtcreator/translations/qtcreator_de.ts | 4 ++-- share/qtcreator/translations/qtcreator_fr.ts | 8 ++------ share/qtcreator/translations/qtcreator_hr.ts | 4 ++-- share/qtcreator/translations/qtcreator_ja.ts | 4 ++-- share/qtcreator/translations/qtcreator_pl.ts | 4 ++-- share/qtcreator/translations/qtcreator_ru.ts | 4 ++-- share/qtcreator/translations/qtcreator_sl.ts | 4 ++-- share/qtcreator/translations/qtcreator_zh_CN.ts | 4 ++-- share/qtcreator/translations/qtcreator_zh_TW.ts | 4 ++-- src/plugins/projectexplorer/sessiondialog.cpp | 6 ++---- 12 files changed, 24 insertions(+), 34 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_cs.ts b/share/qtcreator/translations/qtcreator_cs.ts index 7f62f6a363e..c96e36d85bb 100644 --- a/share/qtcreator/translations/qtcreator_cs.ts +++ b/share/qtcreator/translations/qtcreator_cs.ts @@ -9719,10 +9719,6 @@ se projektu '%2' nepodařilo přidat. Clone Session Zdvojit sezení - - <a href="qthelp://org.qt-project.qtcreator/doc/creator-quick-tour.html#session-management-in-qt-creator">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-quick-tour.html#session-management-in-qt-creator">Co je to sezení?</a> - Switch to session Přepnout na sezení @@ -9748,8 +9744,8 @@ se projektu '%2' nepodařilo přidat. &Otevřít - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Co je sezení?</a> + What is a Session? + Co je sezení? New session name diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 67e43c395b6..210c99ebbb6 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -22723,8 +22723,8 @@ til projektet "%2". Genskab sidste session ved opstart - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Hvad er en session?</a> + What is a Session? + Hvad er en session? Session diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index a49b915b5a2..f362fd8f21f 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -35115,8 +35115,8 @@ Title of a the cloned RunConfiguration window, text of the window Bei Start letzte Sitzung laden - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Was ist eine Sitzung?</a> + What is a Session? + Was ist eine Sitzung? &Open diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 5ee57efddef..48fa7edbe0d 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -9879,10 +9879,6 @@ francis : voila une nouvelle suggestion :) Rename session Renommer la session - - <a href="qthelp://com.nokia.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://com.nokia.qtcreator/doc/creator-project-managing-sessions.html">Qu'est-ce qu'une session?</a> - Automatically restore the last session when Qt Creator is started. Restaurer automatiquement la dernière session quand Qt Creator est démarré. @@ -9892,8 +9888,8 @@ francis : voila une nouvelle suggestion :) Restaurer la dernière session au démarrage - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Qu'est-ce qu'une session ?</a> + What is a Session? + Qu'est-ce qu'une session ? Custom Process Step diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 86fd5ff6388..179850cef10 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -5588,8 +5588,8 @@ Greška: %5 Vrati izvorno stanje posljednje sesije prilikom pokretanja programa - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Što je sesija?</a> + What is a Session? + Što je sesija? diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index efdd53f0586..6014b49996a 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -4403,8 +4403,8 @@ Add, modify, and remove document filters, which determine the documentation set 起動時に最後のセッションを復元する - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">セッションとは?</a> + What is a Session? + セッションとは? Automatically restores the last session when Qt Creator is started. diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 56cdaa31b63..be632f066de 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -903,8 +903,8 @@ &Otwórz - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Co to jest sesja?</a> + What is a Session? + Co to jest sesja? Restore last session on startup diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index e9fd7a81937..f6c71e9dcfd 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -29153,8 +29153,8 @@ to project "%2". &Удалить - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Что такое сессия?</a> + What is a Session? + Что такое сессия? Restore last session on startup diff --git a/share/qtcreator/translations/qtcreator_sl.ts b/share/qtcreator/translations/qtcreator_sl.ts index 6d74be5bd7e..462ed14e8af 100644 --- a/share/qtcreator/translations/qtcreator_sl.ts +++ b/share/qtcreator/translations/qtcreator_sl.ts @@ -6772,8 +6772,8 @@ enojen »Vstopi« za oddajo signala pa vas bo privedel neposredno do ustrezne pr &Odpri - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">Kaj je seja?</a> + What is a Session? + Kaj je seja? New session name diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index ba78031390d..b1e219464c2 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -28222,8 +28222,8 @@ to project "%2". 打开(&S) - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-quick-tour.html#session-management-in-qt-creator">什么是会话?</a> + What is a Session? + 什么是会话? Restore last session on startup diff --git a/share/qtcreator/translations/qtcreator_zh_TW.ts b/share/qtcreator/translations/qtcreator_zh_TW.ts index c1f35c81802..7f39bb619d1 100644 --- a/share/qtcreator/translations/qtcreator_zh_TW.ts +++ b/share/qtcreator/translations/qtcreator_zh_TW.ts @@ -6500,8 +6500,8 @@ Add, modify, and remove document filters, which determine the documentation set 重新命名工作階段 - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">What is a Session?</a> - <a href="qthelp://org.qt-project.qtcreator/doc/creator-project-managing-sessions.html">什麼是工作階段?</a> + What is a Session? + 什麼是工作階段? Automatically restore the last session when Qt Creator is started. diff --git a/src/plugins/projectexplorer/sessiondialog.cpp b/src/plugins/projectexplorer/sessiondialog.cpp index 336da285a45..fe9758dc1b7 100644 --- a/src/plugins/projectexplorer/sessiondialog.cpp +++ b/src/plugins/projectexplorer/sessiondialog.cpp @@ -144,10 +144,8 @@ SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent) m_openButton->setDefault(true); - // FIXME: Simplify translator's work. - auto whatsASessionLabel = new QLabel( - Tr::tr("" - "What is a Session?")); + auto whatsASessionLabel = new QLabel(QString("%1").arg(Tr::tr("What is a Session?"))); whatsASessionLabel->setOpenExternalLinks(true); using namespace Layouting; From be25db429e7f23d5ec862d8c455ccd381d9255d4 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 9 May 2023 08:38:54 +0200 Subject: [PATCH 0898/1447] Debugger: Fix compatibility for debugger engine states ..when switching back to an older version of QC. Amends e0219fad4d9b540145739832a5d91045a3f3fd0e. Change-Id: I3662eb95cf1ae72f92688f12cc15b7a42fb1452c Reviewed-by: hjk Reviewed-by: Eike Ziller --- src/plugins/debugger/debuggerrunconfigurationaspect.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 7b64c0375f8..4b67e82fd86 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -216,6 +216,10 @@ void DebuggerRunConfigurationAspect::toMap(QVariantMap &map) const m_qmlAspect->toMap(map); m_multiProcessAspect->toMap(map); m_overrideStartupAspect->toMap(map); + + // compatibility to old settings + map.insert("RunConfiguration.UseCppDebuggerAuto", m_cppAspect->value() == TriState::Default); + map.insert("RunConfiguration.UseQmlDebuggerAuto", m_qmlAspect->value() == TriState::Default); } void DebuggerRunConfigurationAspect::fromMap(const QVariantMap &map) From c8608e5d9f1800099b0c8fc006cf653e87c95511 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 11:11:28 +0200 Subject: [PATCH 0899/1447] Help: Use functors and layouting in FilterSettingsPageWidget Change-Id: Ib163a41feeafebf4a80b587b6cebbf83cc8e97cb Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/help/filtersettingspage.cpp | 62 +++++++++++-------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp index d484314f9d6..de082526c53 100644 --- a/src/plugins/help/filtersettingspage.cpp +++ b/src/plugins/help/filtersettingspage.cpp @@ -7,9 +7,10 @@ #include "helptr.h" #include "localhelpmanager.h" +#include + #include #include -#include #include namespace Help::Internal { @@ -17,48 +18,37 @@ namespace Help::Internal { class FilterSettingsPageWidget : public Core::IOptionsPageWidget { public: - FilterSettingsPageWidget(FilterSettingsPage *page) : m_page(page) + FilterSettingsPageWidget(FilterSettingsPage *page) { LocalHelpManager::setupGuiHelpEngine(); - m_widget = new QHelpFilterSettingsWidget; - m_widget->readSettings(LocalHelpManager::filterEngine()); - auto vbox = new QVBoxLayout(this); - vbox->addWidget(m_widget); - vbox->setContentsMargins(0, 0, 0, 0); + auto widget = new QHelpFilterSettingsWidget; + widget->readSettings(LocalHelpManager::filterEngine()); - connect(Core::HelpManager::Signals::instance(), - &Core::HelpManager::Signals::documentationChanged, - this, - &FilterSettingsPageWidget::updateFilterPage); + Layouting::Column { + Layouting::noMargin, + widget + }.attachTo(this); + auto updateFilterPage = [widget] { + widget->setAvailableComponents(LocalHelpManager::filterEngine()->availableComponents()); + widget->setAvailableVersions(LocalHelpManager::filterEngine()->availableVersions()); + }; + + auto connection = connect(Core::HelpManager::Signals::instance(), + &Core::HelpManager::Signals::documentationChanged, + this, + updateFilterPage); updateFilterPage(); + + setOnApply([widget, page] { + if (widget->applySettings(LocalHelpManager::filterEngine())) + emit page->filtersChanged(); + widget->readSettings(LocalHelpManager::filterEngine()); + }); + + setOnFinish([connection] { disconnect(connection); }); } - - void apply() final - { - if (m_widget->applySettings(LocalHelpManager::filterEngine())) - emit m_page->filtersChanged(); - - m_widget->readSettings(LocalHelpManager::filterEngine()); - } - - void finish() final - { - disconnect(Core::HelpManager::Signals::instance(), - &Core::HelpManager::Signals::documentationChanged, - this, - &FilterSettingsPageWidget::updateFilterPage); - } - - void updateFilterPage() - { - m_widget->setAvailableComponents(LocalHelpManager::filterEngine()->availableComponents()); - m_widget->setAvailableVersions(LocalHelpManager::filterEngine()->availableVersions()); - } - - FilterSettingsPage *m_page; - QHelpFilterSettingsWidget *m_widget; }; FilterSettingsPage::FilterSettingsPage() From 372ce469fad9d97c92fe36e281417f03a764eefe Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 8 May 2023 12:48:20 +0200 Subject: [PATCH 0900/1447] CppEditor: Remove SendDocumentTracker This was forgotten in the clangbackend removal. Change-Id: I73a3016504ee4af5d921e387f1502d8906161c1a Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/cppeditor/CMakeLists.txt | 1 - src/plugins/cppeditor/cppeditor.qbs | 5 +- src/plugins/cppeditor/cppeditorplugin.cpp | 2 - .../cppeditor/editordocumenthandle.cpp | 5 - src/plugins/cppeditor/editordocumenthandle.h | 4 - src/plugins/cppeditor/senddocumenttracker.cpp | 236 ------------------ src/plugins/cppeditor/senddocumenttracker.h | 67 ----- 7 files changed, 2 insertions(+), 318 deletions(-) delete mode 100644 src/plugins/cppeditor/senddocumenttracker.cpp delete mode 100644 src/plugins/cppeditor/senddocumenttracker.h diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt index b3db8c4d1dc..184dc9f50fa 100644 --- a/src/plugins/cppeditor/CMakeLists.txt +++ b/src/plugins/cppeditor/CMakeLists.txt @@ -107,7 +107,6 @@ add_qtc_plugin(CppEditor resourcepreviewhoverhandler.cpp resourcepreviewhoverhandler.h searchsymbols.cpp searchsymbols.h semantichighlighter.cpp semantichighlighter.h - senddocumenttracker.cpp senddocumenttracker.h symbolfinder.cpp symbolfinder.h symbolsfindfilter.cpp symbolsfindfilter.h typehierarchybuilder.cpp typehierarchybuilder.h diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 1824af07090..dd07f44901c 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -91,7 +91,8 @@ QtcPlugin { "cppeditorwidget.cpp", "cppeditorwidget.h", "cppeditor.qrc", - "cppeditor_global.h", "cppeditortr.h", + "cppeditor_global.h", + "cppeditortr.h", "cppeditorconstants.h", "cppeditordocument.cpp", "cppeditordocument.h", @@ -224,8 +225,6 @@ QtcPlugin { "searchsymbols.h", "semantichighlighter.cpp", "semantichighlighter.h", - "senddocumenttracker.cpp", - "senddocumenttracker.h", "symbolfinder.cpp", "symbolfinder.h", "symbolsfindfilter.cpp", diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 2d4cabe726e..5791a5cb62a 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -49,7 +49,6 @@ #include "functionutils.h" #include "includeutils.h" #include "projectinfo_test.h" -#include "senddocumenttracker.h" #include "symbolsearcher_test.h" #include "typehierarchybuilder_test.h" #endif @@ -486,7 +485,6 @@ void CppEditorPlugin::initialize() addTest(); addTest(); addTest(); - addTest(); addTest(); addTest(); addTest(); diff --git a/src/plugins/cppeditor/editordocumenthandle.cpp b/src/plugins/cppeditor/editordocumenthandle.cpp index 89b20f2ef3f..fe1638f85a2 100644 --- a/src/plugins/cppeditor/editordocumenthandle.cpp +++ b/src/plugins/cppeditor/editordocumenthandle.cpp @@ -14,11 +14,6 @@ namespace CppEditor { CppEditorDocumentHandle::~CppEditorDocumentHandle() = default; -SendDocumentTracker &CppEditorDocumentHandle::sendTracker() -{ - return m_sendTracker; -} - CppEditorDocumentHandle::RefreshReason CppEditorDocumentHandle::refreshReason() const { return m_refreshReason; diff --git a/src/plugins/cppeditor/editordocumenthandle.h b/src/plugins/cppeditor/editordocumenthandle.h index 28c60ddae9f..ef9b8403b58 100644 --- a/src/plugins/cppeditor/editordocumenthandle.h +++ b/src/plugins/cppeditor/editordocumenthandle.h @@ -4,7 +4,6 @@ #pragma once #include "cppeditor_global.h" -#include "senddocumenttracker.h" namespace Utils { class FilePath; } @@ -35,10 +34,7 @@ public: virtual void resetProcessor() = 0; - SendDocumentTracker &sendTracker(); - private: - SendDocumentTracker m_sendTracker; RefreshReason m_refreshReason = None; }; diff --git a/src/plugins/cppeditor/senddocumenttracker.cpp b/src/plugins/cppeditor/senddocumenttracker.cpp deleted file mode 100644 index f7044a65a2b..00000000000 --- a/src/plugins/cppeditor/senddocumenttracker.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "senddocumenttracker.h" - -#include - -#ifdef WITH_TESTS -#include -#endif - -namespace CppEditor { - -void SendDocumentTracker::setLastSentRevision(int revision) -{ - m_lastSentRevision = revision; - m_contentChangeStartPosition = std::numeric_limits::max(); -} - -int SendDocumentTracker::lastSentRevision() const -{ - return m_lastSentRevision; -} - -void SendDocumentTracker::setLastCompletionPosition(int lastCompletionPosition) -{ - m_lastCompletionPosition = lastCompletionPosition; -} - -int SendDocumentTracker::lastCompletionPosition() const -{ - return m_lastCompletionPosition; -} - -void SendDocumentTracker::applyContentChange(int startPosition) -{ - if (startPosition < m_lastCompletionPosition) - m_lastCompletionPosition = -1; - - m_contentChangeStartPosition = std::min(startPosition, m_contentChangeStartPosition); -} - -bool SendDocumentTracker::shouldSendCompletion(int newCompletionPosition) const -{ - return m_lastCompletionPosition != newCompletionPosition; -} - -bool SendDocumentTracker::shouldSendRevision(uint newRevision) const -{ - return m_lastSentRevision != int(newRevision); -} - -bool SendDocumentTracker::shouldSendRevisionWithCompletionPosition(int newRevision, int newCompletionPosition) const -{ - if (shouldSendRevision(newRevision)) - return changedBeforeCompletionPosition(newCompletionPosition); - - return false; -} - -bool SendDocumentTracker::changedBeforeCompletionPosition(int newCompletionPosition) const -{ - return m_contentChangeStartPosition < newCompletionPosition; -} - -#ifdef WITH_TESTS -namespace Internal { - -void DocumentTrackerTest::testDefaultLastSentRevision() -{ - SendDocumentTracker tracker; - - QCOMPARE(tracker.lastSentRevision(), -1); - QCOMPARE(tracker.lastCompletionPosition(), -1); -} - -void DocumentTrackerTest::testSetRevision() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - - QCOMPARE(tracker.lastSentRevision(), 46); - QCOMPARE(tracker.lastCompletionPosition(), -1); -} - -void DocumentTrackerTest::testSetLastCompletionPosition() -{ - SendDocumentTracker tracker; - tracker.setLastCompletionPosition(33); - - QCOMPARE(tracker.lastSentRevision(), -1); - QCOMPARE(tracker.lastCompletionPosition(), 33); -} - -void DocumentTrackerTest::testApplyContentChange() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - tracker.applyContentChange(10); - - QCOMPARE(tracker.lastSentRevision(), 46); - QCOMPARE(tracker.lastCompletionPosition(), -1); -} - -void DocumentTrackerTest::testDontSendCompletionIfPositionIsEqual() -{ - SendDocumentTracker tracker; - tracker.setLastCompletionPosition(33); - - QVERIFY(!tracker.shouldSendCompletion(33)); -} - -void DocumentTrackerTest::testSendCompletionIfPositionIsDifferent() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - - QVERIFY(tracker.shouldSendCompletion(22)); -} - -void DocumentTrackerTest::testSendCompletionIfChangeIsBeforeCompletionPositionAndPositionIsEqual() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - tracker.applyContentChange(10); - - QVERIFY(tracker.shouldSendCompletion(33)); -} - -void DocumentTrackerTest::testDontSendCompletionIfChangeIsAfterCompletionPositionAndPositionIsEqual() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - tracker.applyContentChange(40); - - QVERIFY(!tracker.shouldSendCompletion(33)); -} - -void DocumentTrackerTest::testDontSendRevisionIfRevisionIsEqual() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - - QVERIFY(!tracker.shouldSendRevision(46)); -} - -void DocumentTrackerTest::testSendRevisionIfRevisionIsDifferent() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - - QVERIFY(tracker.shouldSendRevision(21)); -} - -void DocumentTrackerTest::testDontSendRevisionWithDefaults() -{ - SendDocumentTracker tracker; - QVERIFY(!tracker.shouldSendRevisionWithCompletionPosition(21, 33)); -} - -void DocumentTrackerTest::testDontSendIfRevisionIsDifferentAndCompletionPositionIsEqualAndNoContentChange() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - - QVERIFY(!tracker.shouldSendRevisionWithCompletionPosition(21, 33)); -} - -void DocumentTrackerTest::testDontSendIfRevisionIsDifferentAndCompletionPositionIsDifferentAndNoContentChange() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - - QVERIFY(!tracker.shouldSendRevisionWithCompletionPosition(21, 44)); -} - -void DocumentTrackerTest::testDontSendIfRevisionIsEqualAndCompletionPositionIsDifferentAndNoContentChange() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - - QVERIFY(!tracker.shouldSendRevisionWithCompletionPosition(46,44)); -} - -void DocumentTrackerTest::testSendIfChangeIsBeforeCompletionAndPositionIsEqualAndRevisionIsDifferent() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(33); - tracker.applyContentChange(10); - - QVERIFY(tracker.shouldSendRevisionWithCompletionPosition(45, 33)); -} - -void DocumentTrackerTest::testDontSendIfChangeIsAfterCompletionPositionAndRevisionIsDifferent() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(50); - tracker.applyContentChange(40); - - QVERIFY(!tracker.shouldSendRevisionWithCompletionPosition(45, 36)); -} - -void DocumentTrackerTest::testSendIfChangeIsBeforeCompletionPositionAndRevisionIsDifferent() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(50); - tracker.applyContentChange(30); - - QVERIFY(tracker.shouldSendRevisionWithCompletionPosition(45, 36)); -} - -void DocumentTrackerTest::testResetChangedContentStartPositionIfLastRevisionIsSet() -{ - SendDocumentTracker tracker; - tracker.setLastSentRevision(46); - tracker.setLastCompletionPosition(50); - tracker.applyContentChange(30); - tracker.setLastSentRevision(47); - - QVERIFY(!tracker.shouldSendRevisionWithCompletionPosition(45, 36)); -} - -} // namespace Internal -#endif - -} // namespace CppEditor diff --git a/src/plugins/cppeditor/senddocumenttracker.h b/src/plugins/cppeditor/senddocumenttracker.h deleted file mode 100644 index f2736efdd99..00000000000 --- a/src/plugins/cppeditor/senddocumenttracker.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "cppeditor_global.h" - -#include - -#include - -namespace CppEditor { - -class CPPEDITOR_EXPORT SendDocumentTracker -{ -public: - void setLastSentRevision(int lastSentRevision); - int lastSentRevision() const; - - void setLastCompletionPosition(int lastCompletionPosition); - int lastCompletionPosition() const; - - void applyContentChange(int startPosition); - - bool shouldSendCompletion(int newCompletionPosition) const; - bool shouldSendRevision(uint newRevision) const; - bool shouldSendRevisionWithCompletionPosition(int newRevision, int newCompletionPosition) const; - -private: - bool changedBeforeCompletionPosition(int newCompletionPosition) const; - -private: - int m_lastSentRevision = -1; - int m_lastCompletionPosition = -1; - int m_contentChangeStartPosition = std::numeric_limits::max(); -}; - -#ifdef WITH_TESTS -namespace Internal { -class DocumentTrackerTest : public QObject -{ - Q_OBJECT - -private slots: - void testDefaultLastSentRevision(); - void testSetRevision(); - void testSetLastCompletionPosition(); - void testApplyContentChange(); - void testDontSendCompletionIfPositionIsEqual(); - void testSendCompletionIfPositionIsDifferent(); - void testSendCompletionIfChangeIsBeforeCompletionPositionAndPositionIsEqual(); - void testDontSendCompletionIfChangeIsAfterCompletionPositionAndPositionIsEqual(); - void testDontSendRevisionIfRevisionIsEqual(); - void testSendRevisionIfRevisionIsDifferent(); - void testDontSendRevisionWithDefaults(); - void testDontSendIfRevisionIsDifferentAndCompletionPositionIsEqualAndNoContentChange(); - void testDontSendIfRevisionIsDifferentAndCompletionPositionIsDifferentAndNoContentChange(); - void testDontSendIfRevisionIsEqualAndCompletionPositionIsDifferentAndNoContentChange(); - void testSendIfChangeIsBeforeCompletionAndPositionIsEqualAndRevisionIsDifferent(); - void testDontSendIfChangeIsAfterCompletionPositionAndRevisionIsDifferent(); - void testSendIfChangeIsBeforeCompletionPositionAndRevisionIsDifferent(); - void testResetChangedContentStartPositionIfLastRevisionIsSet(); -}; -} // namespace Internal -#endif // WITH_TESTS - -} // namespace CppEditor From a32e72069244046702745ebab572e02b0f8f9cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 5 May 2023 13:13:51 +0200 Subject: [PATCH 0901/1447] SquishTests: Some more Python3 adaption Change-Id: Iee0fd4107c3423d72a1dc51b0087837e4de46537 Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/suite_HELP/tst_HELP02/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/suite_HELP/tst_HELP02/test.py b/tests/system/suite_HELP/tst_HELP02/test.py index 3601c81a37b..7cacdf6e515 100644 --- a/tests/system/suite_HELP/tst_HELP02/test.py +++ b/tests/system/suite_HELP/tst_HELP02/test.py @@ -36,7 +36,7 @@ def checkQtCreatorHelpVersion(expectedVersion): helpContentWidget = waitForObject(':Qt Creator_QHelpContentWidget', 5000) waitFor("any(map(rightStart, dumpItems(helpContentWidget.model())))", 10000) items = dumpItems(helpContentWidget.model()) - test.compare(filter(rightStart, items)[0], + test.compare(list(filter(rightStart, items))[0], 'Qt Creator Manual %s' % expectedVersion, 'Verifying whether manual uses expected version.') except: From 13e0011dba24adff2454f89b4c8603d4ccf494f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 5 May 2023 16:45:35 +0200 Subject: [PATCH 0902/1447] SquishTests: Fix formatting of exception message Amends 8d03220017bf7e5c7be51fc36acb56fbde9e3e13 Change-Id: I05266fe6152a8ac2601890e8dcf32fc68d0989d3 Reviewed-by: Christian Stenger --- tests/system/shared/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 7b58b95c9f6..d05a3b37a8e 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -131,7 +131,7 @@ def __createProjectHandleQtQuickSelection__(minimumQtVersion): selectFromCombo(comboBox, minimumQtVersion) except: t,v = sys.exc_info()[:2] - test.fatal("Exception while trying to select Qt version", "%s :%s" % (t.__name__, str(v))) + test.fatal("Exception while trying to select Qt version", "%s: %s" % (t.__name__, str(v))) clickButton(waitForObject(":Next_QPushButton")) return minimumQtVersion From 8764bab6278aeefd8ecce71b0a700ce7e89b4a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 5 May 2023 13:28:32 +0200 Subject: [PATCH 0903/1447] SquishTests: Improve version detection for imports Change-Id: If38aa92c22c3390859f738ad5bfa5bacf47302ec Reviewed-by: Christian Stenger Reviewed-by: --- tests/system/shared/qtcreator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index 66407519066..d49b23350d7 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -12,10 +12,10 @@ import subprocess; import sys import errno; from datetime import datetime,timedelta; -try: - import __builtin__ # Python 2 -except ImportError: - import builtins as __builtin__ # Python 3 +if sys.version_info.major > 2: + import builtins as __builtin__ +else: + import __builtin__ srcPath = '' From 3003b6cb2b7debb9e0dc0651af8d3aca6e5f595f Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 16:22:27 +0200 Subject: [PATCH 0904/1447] GitLab: Shift responsibility to signal changes ... from the option pasge (factory) to the settings (storage). This will help with removing the QObject base from IOptionPage Change-Id: I04a6b499bdca6065bf8f742b4624beabe7d8f8cc Reviewed-by: Christian Stenger --- src/plugins/gitlab/gitlaboptionspage.cpp | 12 +++++----- src/plugins/gitlab/gitlaboptionspage.h | 5 ---- src/plugins/gitlab/gitlabparameters.cpp | 7 ++++++ src/plugins/gitlab/gitlabparameters.h | 9 ++++++- src/plugins/gitlab/gitlabplugin.cpp | 25 ++++++++++---------- src/plugins/gitlab/gitlabprojectsettings.cpp | 2 +- 6 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/plugins/gitlab/gitlaboptionspage.cpp b/src/plugins/gitlab/gitlaboptionspage.cpp index 96e83300307..c2e56d5730b 100644 --- a/src/plugins/gitlab/gitlaboptionspage.cpp +++ b/src/plugins/gitlab/gitlaboptionspage.cpp @@ -132,7 +132,7 @@ void GitLabServerWidget::setGitLabServer(const GitLabServer &server) class GitLabOptionsWidget : public Core::IOptionsPageWidget { public: - explicit GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParameters *parameters); + explicit GitLabOptionsWidget(GitLabParameters *parameters); private: void showEditServerDialog(); @@ -151,7 +151,7 @@ private: Utils::StringAspect m_curl; }; -GitLabOptionsWidget::GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParameters *params) +GitLabOptionsWidget::GitLabOptionsWidget(GitLabParameters *params) : m_parameters(params) { auto defaultLabel = new QLabel(Tr::tr("Default:"), this); @@ -201,7 +201,7 @@ GitLabOptionsWidget::GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParamete m_defaultGitLabServer->currentData().value()); }); - setOnApply([page, this] { + setOnApply([this] { GitLabParameters result; // get all configured gitlabservers for (int i = 0, end = m_defaultGitLabServer->count(); i < end; ++i) @@ -211,9 +211,9 @@ GitLabOptionsWidget::GitLabOptionsWidget(GitLabOptionsPage *page, GitLabParamete result.curl = m_curl.filePath(); if (result != *m_parameters) { - *m_parameters = result; + m_parameters->assign(result); m_parameters->toSettings(Core::ICore::settings()); - emit page->settingsChanged(); + emit m_parameters->changed(); } }); } @@ -304,7 +304,7 @@ GitLabOptionsPage::GitLabOptionsPage(GitLabParameters *p) setId(Constants::GITLAB_SETTINGS); setDisplayName(Tr::tr("GitLab")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setWidgetCreator([this, p] { return new GitLabOptionsWidget(this, p); }); + setWidgetCreator([p] { return new GitLabOptionsWidget(p); }); } } // namespace GitLab diff --git a/src/plugins/gitlab/gitlaboptionspage.h b/src/plugins/gitlab/gitlaboptionspage.h index 04aecf21998..664f4a26fc1 100644 --- a/src/plugins/gitlab/gitlaboptionspage.h +++ b/src/plugins/gitlab/gitlaboptionspage.h @@ -13,13 +13,8 @@ namespace Constants { const char GITLAB_SETTINGS[] = "GitLab"; } class GitLabOptionsPage : public Core::IOptionsPage { - Q_OBJECT - public: explicit GitLabOptionsPage(GitLabParameters *p); - -signals: - void settingsChanged(); }; } // GitLab diff --git a/src/plugins/gitlab/gitlabparameters.cpp b/src/plugins/gitlab/gitlabparameters.cpp index 1a3f970edb0..79a6ce7da67 100644 --- a/src/plugins/gitlab/gitlabparameters.cpp +++ b/src/plugins/gitlab/gitlabparameters.cpp @@ -102,6 +102,13 @@ GitLabParameters::GitLabParameters() { } +void GitLabParameters::assign(const GitLabParameters &other) +{ + curl = other.curl; + defaultGitLabServer = other.defaultGitLabServer; + gitLabServers = other.gitLabServers; +} + bool GitLabParameters::equals(const GitLabParameters &other) const { return curl == other.curl && defaultGitLabServer == other.defaultGitLabServer diff --git a/src/plugins/gitlab/gitlabparameters.h b/src/plugins/gitlab/gitlabparameters.h index 57dda3667d9..7a21976dc24 100644 --- a/src/plugins/gitlab/gitlabparameters.h +++ b/src/plugins/gitlab/gitlabparameters.h @@ -38,11 +38,14 @@ public: bool validateCert = true; }; -class GitLabParameters +class GitLabParameters : public QObject { + Q_OBJECT + public: GitLabParameters(); + void assign(const GitLabParameters &other); bool equals(const GitLabParameters &other) const; bool isValid() const; @@ -52,6 +55,10 @@ public: GitLabServer currentDefaultServer() const; GitLabServer serverForId(const Utils::Id &id) const; +signals: + void changed(); + +public: friend bool operator==(const GitLabParameters &p1, const GitLabParameters &p2) { return p1.equals(p2); diff --git a/src/plugins/gitlab/gitlabplugin.cpp b/src/plugins/gitlab/gitlabplugin.cpp index 9427aa1d44b..5ae4df682b6 100644 --- a/src/plugins/gitlab/gitlabplugin.cpp +++ b/src/plugins/gitlab/gitlabplugin.cpp @@ -38,6 +38,18 @@ const char GITLAB_OPEN_VIEW[] = "GitLab.OpenView"; class GitLabPluginPrivate : public QObject { public: + void setupNotificationTimer(); + void fetchEvents(); + void fetchUser(); + void createAndSendEventsRequest(const QDateTime timeStamp, int page = -1); + void handleUser(const User &user); + void handleEvents(const Events &events, const QDateTime &timeStamp); + + void onSettingsChanged() { + if (dialog) + dialog->updateRemotes(); + } + GitLabParameters parameters; GitLabOptionsPage optionsPage{¶meters}; QHash projectSettings; @@ -47,13 +59,6 @@ public: QString projectName; Utils::Id serverId; bool runningQuery = false; - - void setupNotificationTimer(); - void fetchEvents(); - void fetchUser(); - void createAndSendEventsRequest(const QDateTime timeStamp, int page = -1); - void handleUser(const User &user); - void handleEvents(const Events &events, const QDateTime &timeStamp); }; static GitLabPluginPrivate *dd = nullptr; @@ -89,10 +94,6 @@ void GitLabPlugin::initialize() connect(openViewAction, &QAction::triggered, this, &GitLabPlugin::openView); Core::ActionContainer *ac = Core::ActionManager::actionContainer(Core::Constants::M_TOOLS); ac->addAction(gitlabCommand); - connect(&dd->optionsPage, &GitLabOptionsPage::settingsChanged, this, [] { - if (dd->dialog) - dd->dialog->updateRemotes(); - }); connect(ProjectExplorer::ProjectManager::instance(), &ProjectExplorer::ProjectManager::startupProjectChanged, this, &GitLabPlugin::onStartupProjectChanged); @@ -305,7 +306,7 @@ bool GitLabPlugin::handleCertificateIssue(const Utils::Id &serverId) int index = dd->parameters.gitLabServers.indexOf(server); server.validateCert = false; dd->parameters.gitLabServers.replace(index, server); - emit dd->optionsPage.settingsChanged(); + dd->onSettingsChanged(); return true; } return false; diff --git a/src/plugins/gitlab/gitlabprojectsettings.cpp b/src/plugins/gitlab/gitlabprojectsettings.cpp index 73532e492f8..240f5292e4f 100644 --- a/src/plugins/gitlab/gitlabprojectsettings.cpp +++ b/src/plugins/gitlab/gitlabprojectsettings.cpp @@ -157,7 +157,7 @@ GitLabProjectSettingsWidget::GitLabProjectSettingsWidget(ProjectExplorer::Projec connect(m_hostCB, &QComboBox::currentIndexChanged, this, [this] { m_infoLabel->setVisible(false); }); - connect(GitLabPlugin::optionsPage(), &GitLabOptionsPage::settingsChanged, + connect(GitLabPlugin::globalParameters(), &GitLabParameters::changed, this, &GitLabProjectSettingsWidget::updateUi); updateUi(); } From d3ef8aa9adee8d83a38836568c9ffd919c48fbf4 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 08:25:58 +0200 Subject: [PATCH 0905/1447] Copilot: Use functor to apply settings Change-Id: Ie17273a4fd55c2144b2751166fb69bd523033321 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotoptionspage.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index 8092e68bb17..d0f2bf654a3 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -72,12 +72,11 @@ file from the Copilot neovim plugin. authWidget, updateAuthWidget); updateAuthWidget(); - } - void apply() final - { - CopilotSettings::instance().apply(); - CopilotSettings::instance().writeSettings(Core::ICore::settings()); + setOnApply([] { + CopilotSettings::instance().apply(); + CopilotSettings::instance().writeSettings(Core::ICore::settings()); + }); } }; From 1d4228dfda8137920523c242c17e59451bcb937b Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 8 May 2023 19:01:49 +0200 Subject: [PATCH 0906/1447] ProjectExplorer: Prevent context menu on ProjectSelector The context menu on the ProjectSelector (outside the "SelectorTree") does not make much sense and pops up with an offset. Change-Id: I79aa3157e04b9d343077fdbc87b8f7cd891426b4 Reviewed-by: hjk Reviewed-by: --- src/plugins/projectexplorer/projectwindow.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index 7baedc4df2e..f44c5354fee 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -572,9 +572,6 @@ public: selectorView->setObjectName("ProjectSelector"); // Needed for dock widget state saving selectorView->setWindowTitle(Tr::tr("Project Selector")); selectorView->setAutoFillBackground(true); - selectorView->setContextMenuPolicy(Qt::CustomContextMenu); - connect(selectorView, &QWidget::customContextMenuRequested, - this, &ProjectWindowPrivate::openContextMenu); auto activeLabel = new QLabel(Tr::tr("Active Project")); QFont font = activeLabel->font(); From 936086745ab826932f6559cc51f49ba20718f56a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 5 May 2023 14:05:10 +0200 Subject: [PATCH 0907/1447] FileSearch: Get rid of FileSearchResult Use SearchResultItem instead. This change should reduce the remaining freeze described in a9eb732ce6763e22badd92fc8523cebe84b09a84 even more. Change-Id: I102b82ed5677360ccd9e425dd0bdd941d87116f0 Reviewed-by: Eike Ziller --- src/libs/utils/filesearch.cpp | 64 +++++------ src/libs/utils/filesearch.h | 56 ++-------- src/libs/utils/searchresultitem.cpp | 41 ++++++- src/libs/utils/searchresultitem.h | 8 ++ src/plugins/git/gitgrep.cpp | 25 +++-- src/plugins/git/gitgrep.h | 2 +- .../findinfilessilversearcher.cpp | 6 +- .../findinfilessilversearcher.h | 2 +- .../silversearcher/outputparser_test.cpp | 64 ++++++----- .../silversearcheroutputparser.cpp | 42 ++++---- .../silversearcheroutputparser.h | 14 +-- src/plugins/texteditor/basefilefind.cpp | 41 ++----- src/plugins/texteditor/basefilefind.h | 4 +- src/plugins/texteditor/texteditor.cpp | 85 ++++++++------- tests/auto/filesearch/tst_filesearch.cpp | 101 +++++++++++------- tests/unit/unittest/CMakeLists.txt | 1 - tests/unit/unittest/compare-operators.h | 25 ----- tests/unit/unittest/googletest.h | 2 - 18 files changed, 289 insertions(+), 294 deletions(-) delete mode 100644 tests/unit/unittest/compare-operators.h diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index 02f6409de08..fe657562769 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -7,6 +7,7 @@ #include "filepath.h" #include "mapreduce.h" #include "qtcassert.h" +#include "searchresultitem.h" #include "stringutils.h" #include "utilstr.h" #include "utiltypes.h" @@ -69,7 +70,7 @@ public: FileSearch(const QString &searchTerm, QTextDocument::FindFlags flags, const QMap &fileToContentsMap); - void operator()(QFutureInterface &futureInterface, + void operator()(QFutureInterface &futureInterface, const FileIterator::Item &item) const; private: @@ -91,7 +92,7 @@ public: QTextDocument::FindFlags flags, const QMap &fileToContentsMap); FileSearchRegExp(const FileSearchRegExp &other); - void operator()(QFutureInterface &futureInterface, + void operator()(QFutureInterface &futureInterface, const FileIterator::Item &item) const; private: @@ -117,7 +118,7 @@ FileSearch::FileSearch(const QString &searchTerm, termDataUpper = searchTermUpper.constData(); } -void FileSearch::operator()(QFutureInterface &futureInterface, +void FileSearch::operator()(QFutureInterface &futureInterface, const FileIterator::Item &item) const { if (futureInterface.isCanceled()) @@ -125,7 +126,7 @@ void FileSearch::operator()(QFutureInterface &futureInterf qCDebug(searchLog) << "Searching in" << item.filePath; futureInterface.setProgressRange(0, 1); futureInterface.setProgressValue(0); - FileSearchResultList results; + SearchResultItems results; QString tempString; if (!getFileContent(item.filePath, item.encoding, &tempString, fileToContentsMap)) { qCDebug(searchLog) << "- failed to get content for" << item.filePath; @@ -190,13 +191,13 @@ void FileSearch::operator()(QFutureInterface &futureInterf } } if (equal) { - const QString resultItemText = clippedText(chunk, MAX_LINE_SIZE); - results << FileSearchResult(item.filePath, - lineNr, - resultItemText, - regionPtr - chunkPtr, - termMaxIndex + 1, - QStringList()); + SearchResultItem result; + result.setFilePath(item.filePath); + result.setMainRange(lineNr, regionPtr - chunkPtr, termMaxIndex + 1); + result.setDisplayText(clippedText(chunk, MAX_LINE_SIZE)); + result.setUserData(QStringList()); + result.setUseTextEditorFont(true); + results << result; regionPtr += termMaxIndex; // another +1 done by for-loop } } @@ -238,7 +239,7 @@ QRegularExpressionMatch FileSearchRegExp::doGuardedMatch(const QString &line, in return expression.match(line, offset); } -void FileSearchRegExp::operator()(QFutureInterface &futureInterface, +void FileSearchRegExp::operator()(QFutureInterface &futureInterface, const FileIterator::Item &item) const { if (!expression.isValid()) { @@ -250,7 +251,7 @@ void FileSearchRegExp::operator()(QFutureInterface &future qCDebug(searchLog) << "Searching in" << item.filePath; futureInterface.setProgressRange(0, 1); futureInterface.setProgressValue(0); - FileSearchResultList results; + SearchResultItems results; QString tempString; if (!getFileContent(item.filePath, item.encoding, &tempString, fileToContentsMap)) { qCDebug(searchLog) << "- failed to get content for" << item.filePath; @@ -270,12 +271,13 @@ void FileSearchRegExp::operator()(QFutureInterface &future int pos = 0; while ((match = doGuardedMatch(line, pos)).hasMatch()) { pos = match.capturedStart(); - results << FileSearchResult(item.filePath, - lineNr, - resultItemText, - pos, - match.capturedLength(), - match.capturedTexts()); + SearchResultItem result; + result.setFilePath(item.filePath); + result.setMainRange(lineNr, pos, match.capturedLength()); + result.setDisplayText(resultItemText); + result.setUserData(match.capturedTexts()); + result.setUseTextEditorFont(true); + results << result; if (match.capturedLength() == 0) break; pos += match.capturedLength(); @@ -299,12 +301,12 @@ struct SearchState SearchState(const QString &term, FileIterator *iterator) : searchTerm(term), files(iterator) {} QString searchTerm; FileIterator *files = nullptr; - FileSearchResultList cachedResults; + SearchResultItems cachedResults; int numFilesSearched = 0; int numMatches = 0; }; -SearchState initFileSearch(QFutureInterface &futureInterface, +SearchState initFileSearch(QFutureInterface &futureInterface, const QString &searchTerm, FileIterator *files) { futureInterface.setProgressRange(0, files->maxProgress()); @@ -312,9 +314,9 @@ SearchState initFileSearch(QFutureInterface &futureInterfa return SearchState(searchTerm, files); } -void collectSearchResults(QFutureInterface &futureInterface, +void collectSearchResults(QFutureInterface &futureInterface, SearchState &state, - const FileSearchResultList &results) + const SearchResultItems &results) { state.numMatches += results.size(); state.cachedResults << results; @@ -333,7 +335,7 @@ void collectSearchResults(QFutureInterface &futureInterfac } } -void cleanUpFileSearch(QFutureInterface &futureInterface, +void cleanUpFileSearch(QFutureInterface &futureInterface, SearchState &state) { if (!state.cachedResults.isEmpty()) { @@ -356,13 +358,13 @@ void cleanUpFileSearch(QFutureInterface &futureInterface, } // namespace -QFuture Utils::findInFiles(const QString &searchTerm, - FileIterator *files, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap) +QFuture Utils::findInFiles(const QString &searchTerm, + FileIterator *files, + QTextDocument::FindFlags flags, + const QMap &fileToContentsMap) { return mapReduce(files->begin(), files->end(), - [searchTerm, files](QFutureInterface &futureInterface) { + [searchTerm, files](QFutureInterface &futureInterface) { return initFileSearch(futureInterface, searchTerm, files); }, FileSearch(searchTerm, flags, fileToContentsMap), @@ -370,14 +372,14 @@ QFuture Utils::findInFiles(const QString &searchTerm, &cleanUpFileSearch); } -QFuture Utils::findInFilesRegExp( +QFuture Utils::findInFilesRegExp( const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, const QMap &fileToContentsMap) { return mapReduce(files->begin(), files->end(), - [searchTerm, files](QFutureInterface &futureInterface) { + [searchTerm, files](QFutureInterface &futureInterface) { return initFileSearch(futureInterface, searchTerm, files); }, FileSearchRegExp(searchTerm, flags, fileToContentsMap), diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index ecb6c574af0..7bb7af5d33f 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -6,8 +6,8 @@ #include "utils_global.h" #include "filepath.h" +#include "searchresultitem.h" -#include #include #include #include @@ -152,54 +152,20 @@ private: QList m_items; }; -class QTCREATOR_UTILS_EXPORT FileSearchResult -{ -public: - FileSearchResult() = default; - FileSearchResult(const FilePath &fileName, int lineNumber, const QString &matchingLine, - int matchStart, int matchLength, - const QStringList ®expCapturedTexts) - : fileName(fileName), - lineNumber(lineNumber), - matchingLine(matchingLine), - matchStart(matchStart), - matchLength(matchLength), - regexpCapturedTexts(regexpCapturedTexts) - {} +QTCREATOR_UTILS_EXPORT QFuture findInFiles(const QString &searchTerm, + FileIterator *files, + QTextDocument::FindFlags flags, + const QMap &fileToContentsMap = {}); - bool operator==(const FileSearchResult &o) const - { - return fileName == o.fileName && lineNumber == o.lineNumber - && matchingLine == o.matchingLine && matchStart == o.matchStart - && matchLength == o.matchLength && regexpCapturedTexts == o.regexpCapturedTexts; - } - bool operator!=(const FileSearchResult &o) const { return !(*this == o); } - - FilePath fileName; - int lineNumber; - QString matchingLine; - int matchStart; - int matchLength; - QStringList regexpCapturedTexts; -}; - -using FileSearchResultList = QList; - -QTCREATOR_UTILS_EXPORT QFuture findInFiles( +QTCREATOR_UTILS_EXPORT QFuture findInFilesRegExp( const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, - const QMap &fileToContentsMap = QMap()); + const QMap &fileToContentsMap = {}); -QTCREATOR_UTILS_EXPORT QFuture findInFilesRegExp( - const QString &searchTerm, - FileIterator *files, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap = QMap()); - -QTCREATOR_UTILS_EXPORT QString expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts); -QTCREATOR_UTILS_EXPORT QString matchCaseReplacement(const QString &originalText, const QString &replaceText); +QTCREATOR_UTILS_EXPORT QString expandRegExpReplacement(const QString &replaceText, + const QStringList &capturedTexts); +QTCREATOR_UTILS_EXPORT QString matchCaseReplacement(const QString &originalText, + const QString &replaceText); } // namespace Utils - -Q_DECLARE_METATYPE(Utils::FileSearchResultList) diff --git a/src/libs/utils/searchresultitem.cpp b/src/libs/utils/searchresultitem.cpp index 74881bd3962..1fe0d953f6b 100644 --- a/src/libs/utils/searchresultitem.cpp +++ b/src/libs/utils/searchresultitem.cpp @@ -45,10 +45,20 @@ SearchResultColor::SearchResultColor(const QColor &textBg, const QColor &textFg, containingFunctionForeground = textForeground; } -QTCREATOR_UTILS_EXPORT size_t qHash(SearchResultColor::Style style, uint seed) +static QString displayText(const QString &line) { - int a = int(style); - return ::qHash(a, seed); + QString result = line; + auto end = result.end(); + for (auto it = result.begin(); it != end; ++it) { + if (!it->isSpace() && !it->isPrint()) + *it = QChar('?'); + } + return result; +} + +void SearchResultItem::setDisplayText(const QString &text) +{ + setLineText(displayText(text)); } void SearchResultItem::setMainRange(int line, int column, int length) @@ -56,4 +66,29 @@ void SearchResultItem::setMainRange(int line, int column, int length) m_mainRange = {{line, column}, {line, column + length}}; } +QTCREATOR_UTILS_EXPORT size_t qHash(SearchResultColor::Style style, uint seed) +{ + int a = int(style); + return ::qHash(a, seed); +} + +bool Search::TextPosition::operator==(const Search::TextPosition &other) const +{ + return line == other.line && column == other.column; +} + +bool Search::TextRange::operator==(const Search::TextRange &other) const +{ + return begin == other.begin && end == other.end; +} + +bool SearchResultItem::operator==(const SearchResultItem &other) const +{ + return m_path == other.m_path && m_lineText == other.m_lineText + && m_userData == other.m_userData && m_mainRange == other.m_mainRange + && m_useTextEditorFont == other.m_useTextEditorFont + && m_selectForReplacement == other.m_selectForReplacement && m_style == other.m_style + && m_containingFunctionName == other.m_containingFunctionName; +} + } // namespace Utils diff --git a/src/libs/utils/searchresultitem.h b/src/libs/utils/searchresultitem.h index ea0de8ceece..080a44f24e8 100644 --- a/src/libs/utils/searchresultitem.h +++ b/src/libs/utils/searchresultitem.h @@ -28,6 +28,8 @@ public: bool operator<(const TextPosition &other) const { return line < other.line || (line == other.line && column < other.column); } + bool operator==(const TextPosition &other) const; + bool operator!=(const TextPosition &other) const { return !(operator==(other)); } }; class QTCREATOR_UTILS_EXPORT TextRange @@ -40,6 +42,8 @@ public: TextPosition end; bool operator<(const TextRange &other) const { return begin < other.begin; } + bool operator==(const TextRange &other) const; + bool operator!=(const TextRange &other) const { return !(operator==(other)); } }; } // namespace Search @@ -76,6 +80,7 @@ public: QString lineText() const { return m_lineText; } void setLineText(const QString &text) { m_lineText = text; } + void setDisplayText(const QString &text); QIcon icon() const { return m_icon; } void setIcon(const QIcon &icon) { m_icon = icon; } @@ -103,6 +108,9 @@ public: m_containingFunctionName = containingFunctionName; } + bool operator==(const SearchResultItem &other) const; + bool operator!=(const SearchResultItem &other) const { return !(operator==(other)); } + private: QStringList m_path; // hierarchy to the parent item of this item QString m_lineText; // text to show for the item itself diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index edd042c9b9c..2161cbbf68e 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -45,7 +45,7 @@ public: class GitGrepRunner { - using PromiseType = QPromise; + using PromiseType = QPromise; public: GitGrepRunner(const TextEditor::FileFindParameters ¶meters) @@ -67,23 +67,23 @@ public: QStringList regexpCapturedTexts; }; - void processLine(const QString &line, FileSearchResultList *resultList) const + void processLine(const QString &line, SearchResultItems *resultList) const { if (line.isEmpty()) return; static const QLatin1String boldRed("\x1b[1;31m"); static const QLatin1String resetColor("\x1b[m"); - FileSearchResult single; + SearchResultItem result; const int lineSeparator = line.indexOf(QChar::Null); QString filePath = line.left(lineSeparator); if (!m_ref.isEmpty() && filePath.startsWith(m_ref)) filePath.remove(0, m_ref.length()); - single.fileName = m_directory.pathAppended(filePath); + result.setFilePath(m_directory.pathAppended(filePath)); const int textSeparator = line.indexOf(QChar::Null, lineSeparator + 1); - single.lineNumber = line.mid(lineSeparator + 1, textSeparator - lineSeparator - 1).toInt(); + const int lineNumber = line.mid(lineSeparator + 1, textSeparator - lineSeparator - 1).toInt(); QString text = line.mid(textSeparator + 1); QRegularExpression regexp; - QVector matches; + QList matches; if (m_parameters.flags & FindRegularExpression) { const QRegularExpression::PatternOptions patternOptions = (m_parameters.flags & FindCaseSensitively) @@ -106,19 +106,18 @@ public: matches.append(match); text = text.left(matchStart) + matchText + text.mid(matchEnd + resetColor.size()); } - single.matchingLine = text; + result.setDisplayText(text); for (const auto &match : std::as_const(matches)) { - single.matchStart = match.matchStart; - single.matchLength = match.matchLength; - single.regexpCapturedTexts = match.regexpCapturedTexts; - resultList->append(single); + result.setMainRange(lineNumber, match.matchStart, match.matchLength); + result.setUserData(match.regexpCapturedTexts); + resultList->append(result); } } void read(PromiseType &fi, const QString &text) { - FileSearchResultList resultList; + SearchResultItems resultList; QString t = text; QTextStream stream(&t); while (!stream.atEnd() && !fi.isCanceled()) @@ -272,7 +271,7 @@ void GitGrep::writeSettings(QSettings *settings) const settings->setValue(GitGrepRef, m_treeLineEdit->text()); } -QFuture GitGrep::executeSearch(const TextEditor::FileFindParameters ¶meters, +QFuture GitGrep::executeSearch(const TextEditor::FileFindParameters ¶meters, TextEditor::BaseFileFind * /*baseFileFind*/) { return Utils::asyncRun(GitGrepRunner(parameters)); diff --git a/src/plugins/git/gitgrep.h b/src/plugins/git/gitgrep.h index 5df131baaba..2fd114e36ec 100644 --- a/src/plugins/git/gitgrep.h +++ b/src/plugins/git/gitgrep.h @@ -30,7 +30,7 @@ public: QVariant parameters() const override; void readSettings(QSettings *settings) override; void writeSettings(QSettings *settings) const override; - QFuture executeSearch( + QFuture executeSearch( const TextEditor::FileFindParameters ¶meters, TextEditor::BaseFileFind *baseFileFind) override; Core::IEditor *openEditor(const Utils::SearchResultItem &item, diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index 9ac9702a6e4..b6759aeaeff 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -73,7 +73,7 @@ bool isSilverSearcherAvailable() return false; } -void runSilverSeacher(QPromise &promise, FileFindParameters parameters) +void runSilverSeacher(QPromise &promise, FileFindParameters parameters) { const FilePath directory = FilePath::fromUserInput(parameters.additionalParameters.toString()); QStringList arguments = {"--parallel", "--ackmate"}; @@ -120,7 +120,7 @@ void runSilverSeacher(QPromise &promise, FileFindParameter regexp.setPatternOptions(patternOptions); } SilverSearcher::SilverSearcherOutputParser parser(process.cleanedStdOut(), regexp); - FileSearchResultList items = parser.parse(); + const SearchResultItems items = parser.parse(); if (!items.isEmpty()) promise.addResult(items); } else { @@ -189,7 +189,7 @@ void FindInFilesSilverSearcher::writeSettings(QSettings *settings) const settings->setValue(SearchOptionsString, m_searchOptionsLineEdit->text()); } -QFuture FindInFilesSilverSearcher::executeSearch( +QFuture FindInFilesSilverSearcher::executeSearch( const FileFindParameters ¶meters, BaseFileFind * /*baseFileFind*/) { return Utils::asyncRun(runSilverSeacher, parameters); diff --git a/src/plugins/silversearcher/findinfilessilversearcher.h b/src/plugins/silversearcher/findinfilessilversearcher.h index af59e3d4b79..85b35192b8e 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.h +++ b/src/plugins/silversearcher/findinfilessilversearcher.h @@ -31,7 +31,7 @@ public: QVariant parameters() const override; void readSettings(QSettings *settings) override; void writeSettings(QSettings *settings) const override; - QFuture executeSearch( + QFuture executeSearch( const TextEditor::FileFindParameters ¶meters, TextEditor::BaseFileFind *) override; Core::IEditor *openEditor(const Utils::SearchResultItem &item, const TextEditor::FileFindParameters ¶meters) override; diff --git a/src/plugins/silversearcher/outputparser_test.cpp b/src/plugins/silversearcher/outputparser_test.cpp index a9185b31568..cdc587ce702 100644 --- a/src/plugins/silversearcher/outputparser_test.cpp +++ b/src/plugins/silversearcher/outputparser_test.cpp @@ -11,47 +11,57 @@ using namespace Utils; namespace SilverSearcher { namespace Internal { +SearchResultItem searchResult(const FilePath &fileName, const QString &matchingLine, + int lineNumber, int matchStart, int matchLength) +{ + SearchResultItem result; + result.setFilePath(fileName); + result.setLineText(matchingLine); + result.setMainRange(lineNumber, matchStart, matchLength); + return result; +} + void OutputParserTest::test_data() { QTest::addColumn("parserOutput"); - QTest::addColumn("results"); + QTest::addColumn("results"); - QTest::addRow("nothing") << QString("\n") << FileSearchResultList(); + QTest::addRow("nothing") << QString("\n") << SearchResultItems(); QTest::addRow("oneFileOneMatch") - << QString(":/file/path/to/filename.h\n" - "1;1 5:match\n") - << FileSearchResultList({{"/file/path/to/filename.h", 1, "match", 1, 5, {}}}); + << QString(":/file/path/to/filename.h\n" + "1;1 5:match\n") + << SearchResultItems{searchResult("/file/path/to/filename.h", "match", 1, 1, 5)}; QTest::addRow("multipleFilesWithOneMatch") - << QString(":/file/path/to/filename1.h\n" - "1;1 5:match\n" - "\n" - ":/file/path/to/filename2.h\n" - "2;2 5: match\n") - << FileSearchResultList({{"/file/path/to/filename1.h", 1, "match", 1, 5, {}}, - {"/file/path/to/filename2.h", 2, " match", 2, 5, {}}}); + << QString(":/file/path/to/filename1.h\n" + "1;1 5:match\n" + "\n" + ":/file/path/to/filename2.h\n" + "2;2 5: match\n") + << SearchResultItems{searchResult("/file/path/to/filename1.h", "match", 1, 1, 5), + searchResult("/file/path/to/filename2.h", " match", 2, 2, 5)}; QTest::addRow("oneFileMultipleMatches") - << QString(":/file/path/to/filename.h\n" - "1;1 5,7 5:match match\n") - << FileSearchResultList({{"/file/path/to/filename.h", 1, "match match", 1, 5, {}}, - {"/file/path/to/filename.h", 1, "match match", 7, 5, {}}}); + << QString(":/file/path/to/filename.h\n" + "1;1 5,7 5:match match\n") + << SearchResultItems{searchResult("/file/path/to/filename.h", "match match", 1, 1, 5), + searchResult("/file/path/to/filename.h", "match match", 1, 7, 5)}; QTest::addRow("multipleFilesWithMultipleMatches") - << QString(":/file/path/to/filename1.h\n" - "1;1 5,7 5:match match\n" - "\n" - ":/file/path/to/filename2.h\n" - "2;2 5,8 5: match match\n") - << FileSearchResultList({{"/file/path/to/filename1.h", 1, "match match", 1, 5, {}}, - {"/file/path/to/filename1.h", 1, "match match", 7, 5, {}}, - {"/file/path/to/filename2.h", 2, " match match", 2, 5, {}}, - {"/file/path/to/filename2.h", 2, " match match", 8, 5, {}}}); + << QString(":/file/path/to/filename1.h\n" + "1;1 5,7 5:match match\n" + "\n" + ":/file/path/to/filename2.h\n" + "2;2 5,8 5: match match\n") + << SearchResultItems{searchResult("/file/path/to/filename1.h", "match match", 1, 1, 5), + searchResult("/file/path/to/filename1.h", "match match", 1, 7, 5), + searchResult("/file/path/to/filename2.h", " match match", 2, 2, 5), + searchResult("/file/path/to/filename2.h", " match match", 2, 8, 5)}; } void OutputParserTest::test() { QFETCH(QString, parserOutput); - QFETCH(FileSearchResultList, results); + QFETCH(SearchResultItems, results); SilverSearcher::SilverSearcherOutputParser ssop(parserOutput); - const FileSearchResultList items = ssop.parse(); + const SearchResultItems items = ssop.parse(); QCOMPARE(items, results); } diff --git a/src/plugins/silversearcher/silversearcheroutputparser.cpp b/src/plugins/silversearcher/silversearcheroutputparser.cpp index 9088310c3fc..20ce2473425 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.cpp +++ b/src/plugins/silversearcher/silversearcheroutputparser.cpp @@ -16,7 +16,7 @@ SilverSearcherOutputParser::SilverSearcherOutputParser( hasRegexp = !regexp.pattern().isEmpty(); } -Utils::FileSearchResultList SilverSearcherOutputParser::parse() +Utils::SearchResultItems SilverSearcherOutputParser::parse() { while (index < outputSize - 1) { if (output[index] == '\n') { @@ -25,15 +25,15 @@ Utils::FileSearchResultList SilverSearcherOutputParser::parse() } parseFilePath(); while (index < outputSize && output[index] != '\n') { - parseLineNumber(); + const int lineNumber = parseLineNumber(); if (index >= outputSize - 1) break; - int matches = parseMatches(); + int matches = parseMatches(lineNumber); if (index >= outputSize - 1) break; parseText(); for (int i = 0; i < matches; ++i) - items[items.size() - i - 1].matchingLine = item.matchingLine; + items[items.size() - i - 1].setDisplayText(item.lineText()); } } @@ -45,41 +45,41 @@ bool SilverSearcherOutputParser::parseFilePath() int startIndex = ++index; while (index < outputSize && output[index] != '\n') ++index; - item.fileName = Utils::FilePath::fromString(QString(output.data() + startIndex, index - startIndex)); + item.setFilePath(Utils::FilePath::fromString(QString(output.data() + startIndex, + index - startIndex))); ++index; return true; } -bool SilverSearcherOutputParser::parseLineNumber() +int SilverSearcherOutputParser::parseLineNumber() { int startIndex = index; while (index < outputSize && output[++index] != ';') { } - item.lineNumber = QString(output.data() + startIndex, index - startIndex).toInt(); + const int lineNumber = QString(output.data() + startIndex, index - startIndex).toInt(); ++index; - return true; + return lineNumber; } -bool SilverSearcherOutputParser::parseMatchIndex() +int SilverSearcherOutputParser::parseMatchIndex() { int startIndex = index; while (index < outputSize && output[++index] != ' ') { } - item.matchStart = QString(output.data() + startIndex, index - startIndex).toInt(); + const int lineStart = QString(output.data() + startIndex, index - startIndex).toInt(); ++index; - return true; + return lineStart; } -bool SilverSearcherOutputParser::parseMatchLength() +int SilverSearcherOutputParser::parseMatchLength() { int startIndex = index; while (index < outputSize && output[++index] != ':' && output[index] != ',') { } - item.matchLength = QString(output.data() + startIndex, index - startIndex).toInt(); - return true; + return QString(output.data() + startIndex, index - startIndex).toInt(); } -int SilverSearcherOutputParser::parseMatches() +int SilverSearcherOutputParser::parseMatches(int lineNumber) { int matches = 1; const int colon = output.indexOf(':', index); @@ -94,11 +94,12 @@ int SilverSearcherOutputParser::parseMatches() ++matches; ++index; } - parseMatchIndex(); - parseMatchLength(); + const int lineStart = parseMatchIndex(); + const int lineLength = parseMatchLength(); + item.setMainRange(lineNumber, lineStart, lineLength); if (hasRegexp) { - const QString part = QString(text.mid(item.matchStart, item.matchLength)); - item.regexpCapturedTexts = regexp.match(part).capturedTexts(); + const QString part = QString(text.mid(lineStart, lineLength)); + item.setUserData(regexp.match(part).capturedTexts()); } items << item; } @@ -111,7 +112,8 @@ bool SilverSearcherOutputParser::parseText() { int startIndex = index; while (index < outputSize && output[++index] != '\n') { } - item.matchingLine = QString(output.data() + startIndex, index - startIndex); + + item.setLineText(QString(output.data() + startIndex, index - startIndex)); ++index; return true; } diff --git a/src/plugins/silversearcher/silversearcheroutputparser.h b/src/plugins/silversearcher/silversearcheroutputparser.h index 187e463938c..a4b34a6051f 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.h +++ b/src/plugins/silversearcher/silversearcheroutputparser.h @@ -16,13 +16,13 @@ class SilverSearcherOutputParser public: SilverSearcherOutputParser(const QString &output, const QRegularExpression ®exp = {}); - Utils::FileSearchResultList parse(); + Utils::SearchResultItems parse(); private: - int parseMatches(); - bool parseMatchLength(); - bool parseMatchIndex(); - bool parseLineNumber(); + int parseMatches(int lineNumber); + int parseMatchLength(); + int parseMatchIndex(); + int parseLineNumber(); bool parseFilePath(); bool parseText(); @@ -31,8 +31,8 @@ private: bool hasRegexp = false; int outputSize = 0; int index = 0; - Utils::FileSearchResult item; - Utils::FileSearchResultList items; + Utils::SearchResultItem item; + Utils::SearchResultItems items; }; } // namespace SilverSearcher diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 9a57b083e69..197a2fa6968 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -51,9 +51,8 @@ public: QVariant parameters() const override { return {}; } void readSettings(QSettings * /*settings*/) override {} void writeSettings(QSettings * /*settings*/) const override {} - QFuture executeSearch( - const TextEditor::FileFindParameters ¶meters, - BaseFileFind *baseFileFind) override + QFuture executeSearch(const TextEditor::FileFindParameters ¶meters, + BaseFileFind *baseFileFind) override { const auto func = parameters.flags & FindRegularExpression ? Utils::findInFilesRegExp : Utils::findInFiles; @@ -208,34 +207,6 @@ void BaseFileFind::setCurrentSearchEngine(int index) emit currentSearchEngineChanged(); } -static QString displayText(const QString &line) -{ - QString result = line; - auto end = result.end(); - for (auto it = result.begin(); it != end; ++it) { - if (!it->isSpace() && !it->isPrint()) - *it = QChar('?'); - } - return result; -} - -static void displayResult(QFutureWatcher *watcher, - SearchResult *search, int index) -{ - const FileSearchResultList results = watcher->resultAt(index); - SearchResultItems items; - for (const FileSearchResult &result : results) { - SearchResultItem item; - item.setFilePath(result.fileName); - item.setMainRange(result.lineNumber, result.matchStart, result.matchLength); - item.setLineText(displayText(result.matchingLine)); - item.setUseTextEditorFont(true); - item.setUserData(result.regexpCapturedTexts); - items << item; - } - search->addResults(items, SearchResult::AddOrdered); -} - void BaseFileFind::runNewSearch(const QString &txt, FindFlags findFlags, SearchResultWindow::SearchMode searchMode) { @@ -283,7 +254,7 @@ void BaseFileFind::runSearch(SearchResult *search) { const FileFindParameters parameters = search->userData().value(); SearchResultWindow::instance()->popup(IOutputPane::Flags(IOutputPane::ModeSwitch|IOutputPane::WithFocus)); - auto watcher = new QFutureWatcher(); + auto watcher = new QFutureWatcher; watcher->setPendingResultsLimit(1); // search is deleted if it is removed from search panel connect(search, &QObject::destroyed, watcher, &QFutureWatcherBase::cancel); @@ -293,14 +264,14 @@ void BaseFileFind::runSearch(SearchResult *search) watcher->setPaused(paused); }); connect(watcher, &QFutureWatcherBase::resultReadyAt, search, [watcher, search](int index) { - displayResult(watcher, search, index); + search->addResults(watcher->resultAt(index), SearchResult::AddOrdered); }); // auto-delete: connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); connect(watcher, &QFutureWatcherBase::finished, search, [watcher, search]() { search->finishSearch(watcher->isCanceled()); }); - QFuture future = executeSearch(parameters); + QFuture future = executeSearch(parameters); watcher->setFuture(future); d->m_futureSynchronizer.addFuture(future); FutureProgress *progress = ProgressManager::addTask(future, @@ -541,7 +512,7 @@ QVariant BaseFileFind::getAdditionalParameters(SearchResult *search) return search->userData().value().additionalParameters; } -QFuture BaseFileFind::executeSearch(const FileFindParameters ¶meters) +QFuture BaseFileFind::executeSearch(const FileFindParameters ¶meters) { return d->m_searchEngines[parameters.searchEngineIndex]->executeSearch(parameters, this); } diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index 5864eccf365..b564b35c0c1 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -56,7 +56,7 @@ public: virtual QVariant parameters() const = 0; virtual void readSettings(QSettings *settings) = 0; virtual void writeSettings(QSettings *settings) const = 0; - virtual QFuture executeSearch( + virtual QFuture executeSearch( const FileFindParameters ¶meters, BaseFileFind *baseFileFind) = 0; virtual Core::IEditor *openEditor(const Utils::SearchResultItem &item, const FileFindParameters ¶meters) = 0; @@ -97,7 +97,7 @@ protected: virtual QString label() const = 0; // see Core::SearchResultWindow::startNewSearch virtual QString toolTip() const = 0; // see Core::SearchResultWindow::startNewSearch, // add %1 placeholder where the find flags should be put - QFuture executeSearch(const FileFindParameters ¶meters); + QFuture executeSearch(const FileFindParameters ¶meters); void writeCommonSettings(QSettings *settings); void readCommonSettings(QSettings *settings, const QString &defaultFilter, const QString &defaultExclusionFilter); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index eb4b3129f62..e9e7367d8e0 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -790,7 +791,7 @@ public: QScopedPointer m_autoCompleter; CommentDefinition m_commentDefinition; - QFutureWatcher *m_searchWatcher = nullptr; + QFutureWatcher *m_searchWatcher = nullptr; QVector m_searchResults; QTimer m_scrollBarUpdateTimer; HighlightScrollBarController *m_highlightScrollBarController = nullptr; @@ -846,10 +847,27 @@ public: private: TextEditorWidget * const m_editor; - static QFutureWatcher *m_selectWatcher; + static QFutureWatcher *m_selectWatcher; }; -QFutureWatcher *TextEditorWidgetFind::m_selectWatcher = nullptr; +static QTextCursor selectRange(QTextDocument *textDocument, const Search::TextRange &range, + TextEditorWidgetPrivate::SearchResult *searchResult = nullptr) +{ + const int startLine = qMax(range.begin.line - 1, 0); + const int startColumn = qMax(range.begin.column, 0); + const int endLine = qMax(range.end.line - 1, 0); + const int endColumn = qMax(range.end.column, 0); + const int startPosition = textDocument->findBlockByNumber(startLine).position() + startColumn; + const int endPosition = textDocument->findBlockByNumber(endLine).position() + endColumn; + QTextCursor textCursor(textDocument); + textCursor.setPosition(startPosition); + textCursor.setPosition(endPosition, QTextCursor::KeepAnchor); + if (searchResult) + *searchResult = {startPosition + 1, endPosition + 1}; + return textCursor; +} + +QFutureWatcher *TextEditorWidgetFind::m_selectWatcher = nullptr; void TextEditorWidgetFind::selectAll(const QString &txt, FindFlags findFlags) { @@ -858,26 +876,24 @@ void TextEditorWidgetFind::selectAll(const QString &txt, FindFlags findFlags) cancelCurrentSelectAll(); - m_selectWatcher = new QFutureWatcher(); - connect(m_selectWatcher, &QFutureWatcher::finished, - this, [this] { - const QFuture future = m_selectWatcher->future(); - m_selectWatcher->deleteLater(); - m_selectWatcher = nullptr; - if (future.resultCount() <= 0) - return; - const FileSearchResultList &results = future.result(); - const QTextCursor c(m_editor->document()); - auto cursorForResult = [c](const FileSearchResult &r) { - return Utils::Text::selectAt(c, r.lineNumber, r.matchStart + 1, r.matchLength); - }; - QList cursors = Utils::transform(results, cursorForResult); - cursors = Utils::filtered(cursors, [this](const QTextCursor &c) { - return m_editor->inFindScope(c); - }); - m_editor->setMultiTextCursor(MultiTextCursor(cursors)); - m_editor->setFocus(); - }); + m_selectWatcher = new QFutureWatcher(); + connect(m_selectWatcher, &QFutureWatcher::finished, this, [this] { + const QFuture future = m_selectWatcher->future(); + m_selectWatcher->deleteLater(); + m_selectWatcher = nullptr; + if (future.resultCount() <= 0) + return; + const SearchResultItems &results = future.result(); + const auto cursorForResult = [this](const SearchResultItem &item) { + return selectRange(m_editor->document(), item.mainRange()); + }; + QList cursors = Utils::transform(results, cursorForResult); + cursors = Utils::filtered(cursors, [this](const QTextCursor &c) { + return m_editor->inFindScope(c); + }); + m_editor->setMultiTextCursor(MultiTextCursor(cursors)); + m_editor->setFocus(); + }); const FilePath &fileName = m_editor->textDocument()->filePath(); QMap fileToContentsMap; @@ -6671,16 +6687,11 @@ void TextEditorWidgetPrivate::searchResultsReady(int beginIndex, int endIndex) { QVector results; for (int index = beginIndex; index < endIndex; ++index) { - const FileSearchResultList resultList = m_searchWatcher->resultAt(index); - for (FileSearchResult result : resultList) { - const QTextBlock &block = q->document()->findBlockByNumber(result.lineNumber - 1); - const int matchStart = block.position() + result.matchStart; - QTextCursor cursor(block); - cursor.setPosition(matchStart); - cursor.setPosition(matchStart + result.matchLength, QTextCursor::KeepAnchor); - if (!q->inFindScope(cursor)) - continue; - results << SearchResult{matchStart, result.matchLength}; + const SearchResultItems resultList = m_searchWatcher->resultAt(index); + for (const SearchResultItem &result : resultList) { + SearchResult searchResult; + if (q->inFindScope(selectRange(q->document(), result.mainRange(), &searchResult))) + results << searchResult; } } m_searchResults << results; @@ -6726,10 +6737,10 @@ void TextEditorWidgetPrivate::highlightSearchResultsInScrollBar() adjustScrollBarRanges(); - m_searchWatcher = new QFutureWatcher(); - connect(m_searchWatcher, &QFutureWatcher::resultsReadyAt, + m_searchWatcher = new QFutureWatcher; + connect(m_searchWatcher, &QFutureWatcher::resultsReadyAt, this, &TextEditorWidgetPrivate::searchResultsReady); - connect(m_searchWatcher, &QFutureWatcher::finished, + connect(m_searchWatcher, &QFutureWatcher::finished, this, &TextEditorWidgetPrivate::searchFinished); m_searchWatcher->setPendingResultsLimit(10); @@ -6775,7 +6786,7 @@ void TextEditorWidgetPrivate::addSearchResultsToScrollBar(const QVectordocument()->findBlock(result.start); if (block.isValid() && block.isVisible()) { const int firstLine = block.layout()->lineForTextPosition(result.start - block.position()).lineNumber(); diff --git a/tests/auto/filesearch/tst_filesearch.cpp b/tests/auto/filesearch/tst_filesearch.cpp index 2532f7a313a..95bec53e099 100644 --- a/tests/auto/filesearch/tst_filesearch.cpp +++ b/tests/auto/filesearch/tst_filesearch.cpp @@ -22,66 +22,85 @@ private slots: void caseSensitive(); void caseInSensitive(); void matchCaseReplacement(); + +private: + const FilePath m_filePath = FilePath::fromString(":/tst_filesearch/testfile.txt"); }; -namespace { - const char * const FILENAME = ":/tst_filesearch/testfile.txt"; +SearchResultItem searchResult(const FilePath &fileName, const QString &matchingLine, + int lineNumber, int matchStart, int matchLength, + const QStringList ®expCapturedTexts = {}) +{ + SearchResultItem result; + result.setFilePath(fileName); + result.setLineText(matchingLine); + result.setMainRange(lineNumber, matchStart, matchLength); + result.setUserData(regexpCapturedTexts); + result.setUseTextEditorFont(true); + return result; +} - void test_helper(const Utils::FileSearchResultList &expectedResults, - const QString &term, - QTextDocument::FindFlags flags, tst_FileSearch::RegExpFlag regexp = tst_FileSearch::NoRegExp) - { - Utils::FileIterator *it = new Utils::FileListIterator({FilePath::fromString(FILENAME)}, - {QTextCodec::codecForLocale()}); - QFutureWatcher watcher; - QSignalSpy ready(&watcher, &QFutureWatcherBase::resultsReadyAt); - if (regexp == tst_FileSearch::NoRegExp) - watcher.setFuture(Utils::findInFiles(term, it, flags)); - else - watcher.setFuture(Utils::findInFilesRegExp(term, it, flags)); - watcher.future().waitForFinished(); - QTest::qWait(100); // process events - QCOMPARE(ready.count(), 1); - Utils::FileSearchResultList results = watcher.resultAt(0); - QCOMPARE(results.count(), expectedResults.count()); - for (int i = 0; i < expectedResults.size(); ++i) { - QCOMPARE(results.at(i), expectedResults.at(i)); - } - } +void test_helper(const FilePath &filePath, const SearchResultItems &expectedResults, + const QString &term, QTextDocument::FindFlags flags = {}, + tst_FileSearch::RegExpFlag regexp = tst_FileSearch::NoRegExp) +{ + FileIterator *it = new FileListIterator({filePath}, {QTextCodec::codecForLocale()}); + QFutureWatcher watcher; + QSignalSpy ready(&watcher, &QFutureWatcherBase::resultsReadyAt); + if (regexp == tst_FileSearch::NoRegExp) + watcher.setFuture(Utils::findInFiles(term, it, flags)); + else + watcher.setFuture(Utils::findInFilesRegExp(term, it, flags)); + watcher.future().waitForFinished(); + QTest::qWait(100); // process events + QCOMPARE(ready.count(), 1); + SearchResultItems results = watcher.resultAt(0); + QCOMPARE(results.count(), expectedResults.count()); + for (int i = 0; i < expectedResults.size(); ++i) + QCOMPARE(results.at(i), expectedResults.at(i)); } void tst_FileSearch::multipleResults() { - Utils::FileSearchResultList expectedResults; - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 2, QLatin1String("search to find multiple find results"), 10, 4, QStringList()); - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 2, QLatin1String("search to find multiple find results"), 24, 4, QStringList()); - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 4, QLatin1String("here you find another result"), 9, 4, QStringList()); - test_helper(expectedResults, QLatin1String("find"), QTextDocument::FindFlags()); + SearchResultItems expectedResults; + expectedResults << searchResult(m_filePath, "search to find multiple find results", 2, 10, 4); + expectedResults << searchResult(m_filePath, "search to find multiple find results", 2, 24, 4); + expectedResults << searchResult(m_filePath, "here you find another result", 4, 9, 4); + test_helper(m_filePath, expectedResults, "find"); expectedResults.clear(); - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 5, QLatin1String("aaaaaaaa this line has 2 results for four a in a row"), 0, 4, QStringList()); - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 5, QLatin1String("aaaaaaaa this line has 2 results for four a in a row"), 4, 4, QStringList()); - test_helper(expectedResults, QLatin1String("aaaa"), QTextDocument::FindFlags()); + expectedResults << searchResult(m_filePath, + "aaaaaaaa this line has 2 results for four a in a row", + 5, 0, 4); + expectedResults << searchResult(m_filePath, + "aaaaaaaa this line has 2 results for four a in a row", + 5, 4, 4); + test_helper(m_filePath, expectedResults, "aaaa"); expectedResults.clear(); - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 5, QLatin1String("aaaaaaaa this line has 2 results for four a in a row"), 0, 4, QStringList() << QLatin1String("aaaa")); - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 5, QLatin1String("aaaaaaaa this line has 2 results for four a in a row"), 4, 4, QStringList() << QLatin1String("aaaa")); - test_helper(expectedResults, QLatin1String("aaaa"), QTextDocument::FindFlags(), RegExp); + expectedResults << searchResult(m_filePath, + "aaaaaaaa this line has 2 results for four a in a row", + 5, 0, 4, {"aaaa"}); + expectedResults << searchResult(m_filePath, + "aaaaaaaa this line has 2 results for four a in a row", + 5, 4, 4, {"aaaa"}); + test_helper(m_filePath, expectedResults, "aaaa", {}, RegExp); } void tst_FileSearch::caseSensitive() { - Utils::FileSearchResultList expectedResults; - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 3, QLatin1String("search CaseSensitively for casesensitive"), 7, 13, QStringList()); - test_helper(expectedResults, QLatin1String("CaseSensitive"), QTextDocument::FindCaseSensitively); + SearchResultItems expectedResults; + expectedResults << searchResult(m_filePath, "search CaseSensitively for casesensitive", + 3, 7, 13); + test_helper(m_filePath, expectedResults, "CaseSensitive", QTextDocument::FindCaseSensitively); } void tst_FileSearch::caseInSensitive() { - Utils::FileSearchResultList expectedResults; - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 3, QLatin1String("search CaseSensitively for casesensitive"), 7, 13, QStringList()); - expectedResults << FileSearchResult(FilePath::fromString(FILENAME), 3, QLatin1String("search CaseSensitively for casesensitive"), 27, 13, QStringList()); - test_helper(expectedResults, QLatin1String("CaseSensitive"), QTextDocument::FindFlags()); + SearchResultItems expectedResults; + expectedResults << searchResult(m_filePath, "search CaseSensitively for casesensitive", 3, 7, 13); + expectedResults << searchResult(m_filePath, "search CaseSensitively for casesensitive", 3, 27, 13); + test_helper(m_filePath, expectedResults, "CaseSensitive"); } void tst_FileSearch::matchCaseReplacement() diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index f220087daf9..7522a8e180e 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -38,7 +38,6 @@ add_qtc_test(unittest GTEST TEST_RELATIVE_LIBEXEC_PATH="${TEST_RELATIVE_LIBEXEC_PATH}" SOURCES abstractviewmock.h - compare-operators.h conditionally-disabled-tests.h dynamicastmatcherdiagnosticcontainer-matcher.h eventspy.cpp eventspy.h diff --git a/tests/unit/unittest/compare-operators.h b/tests/unit/unittest/compare-operators.h deleted file mode 100644 index 891fdfec034..00000000000 --- a/tests/unit/unittest/compare-operators.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Utils { -namespace Search { - -inline -bool operator==(const TextPosition first, class TextPosition second) -{ - return first.line == second.line - && first.column == second.column; -} - -inline -bool operator==(const TextRange first, class TextRange second) -{ - return first.begin == second.begin - && first.end == second.end; -} -} -} diff --git a/tests/unit/unittest/googletest.h b/tests/unit/unittest/googletest.h index 72ece6a6022..a3d3012a09a 100644 --- a/tests/unit/unittest/googletest.h +++ b/tests/unit/unittest/googletest.h @@ -13,8 +13,6 @@ #include #include -#include "compare-operators.h" - #include "conditionally-disabled-tests.h" #include "gtest-creator-printing.h" #include "gtest-llvm-printing.h" From 12504b6802326f4540277182e020b25df0ff7fec Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 9 May 2023 10:07:36 +0200 Subject: [PATCH 0908/1447] Terminal: Combine settings Change-Id: Ic9e3ac9bdba73eb99e8177083e08c8b4b1765972 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalsettingspage.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp index d993a49f472..25a7250a1eb 100644 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ b/src/plugins/terminal/terminalsettingspage.cpp @@ -371,6 +371,7 @@ public: settings.enableTerminal, st, settings.sendEscapeToTerminal, st, settings.audibleBell, st, + settings.allowBlinkingCursor, st, }, }, Group { @@ -380,12 +381,6 @@ public: settings.fontSize, st, }, }, - Group { - title(Tr::tr("Cursor")), - Row { - settings.allowBlinkingCursor, st, - }, - }, Group { title(Tr::tr("Colors")), Column { From 5ea6c34a2346732f340c2367e8c1b59ffa39554f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 9 May 2023 10:07:05 +0200 Subject: [PATCH 0909/1447] Terminal: Fix shell integration for login shells Change-Id: I78cc4b60b4e2164752b7b65e2e61659e5d5bbe22 Reviewed-by: Cristian Adam --- src/plugins/terminal/shellintegration.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp index 230c6e3da83..cd67318604c 100644 --- a/src/plugins/terminal/shellintegration.cpp +++ b/src/plugins/terminal/shellintegration.cpp @@ -54,15 +54,15 @@ bool ShellIntegration::canIntegrate(const Utils::CommandLine &cmdLine) if (cmdLine.executable().needsDevice()) return false; // TODO: Allow integration for remote shells - if (!cmdLine.arguments().isEmpty()) + if (cmdLine.executable().baseName() == "zsh") + return true; + + if (!cmdLine.arguments().isEmpty() && cmdLine.arguments() != "-l") return false; if (cmdLine.executable().baseName() == "bash") return true; - if (cmdLine.executable().baseName() == "zsh") - return true; - if (cmdLine.executable().baseName() == "pwsh" || cmdLine.executable().baseName() == "powershell") { return true; From 734f559b76b3fdaea621851e57a543e364c4a1a9 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 9 May 2023 08:35:24 +0200 Subject: [PATCH 0910/1447] Terminal: Fix cursor/viewport updates Under some font sizes the cursor size and cell size were not correctly aligned on the pixel grid, leaving behind artifacts of prior draws. Change-Id: I25e6efdc44102f24672912e1e56c31be0c686b89 Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index b6e48165f39..19ad1b82023 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -920,9 +920,13 @@ void TerminalWidget::paintCursor(QPainter &p) const QRectF cursorRect = QRectF(gridToGlobal(cursor.position), gridToGlobal({cursor.position.x() + cursorCellWidth, cursor.position.y()}, - true)); + true)) + .toAlignedRect(); - cursorRect.adjust(0, 0, 0, -1); + cursorRect.adjust(1, 1, -1, -1); + + QPen pen(Qt::white, 0, Qt::SolidLine); + p.setPen(pen); if (hasFocus()) { QPainter::CompositionMode oldMode = p.compositionMode(); @@ -1162,14 +1166,14 @@ QRect TerminalWidget::gridToViewport(QRect rect) const int numRows = rect.height(); int numCols = rect.width(); - QRect r{qFloor(rect.x() * m_cellSize.width()), - qFloor(startRow * m_cellSize.height()), - qCeil(numCols * m_cellSize.width()), - qCeil(numRows * m_cellSize.height())}; + QRectF r{rect.x() * m_cellSize.width(), + startRow * m_cellSize.height(), + numCols * m_cellSize.width(), + numRows * m_cellSize.height()}; r.translate(0, topMargin()); - return r; + return r.toAlignedRect(); } void TerminalWidget::updateViewport() From c0f0ccdc78c6892f17209efa67b70943deca0e25 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 9 May 2023 10:29:55 +0200 Subject: [PATCH 0911/1447] Terminal: Ensure terminal is visible When restarting an app, make sure the terminal is visible and focused. Change-Id: I305eb59ddf2f5e0f2844d47e51500953c3145c38 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalpane.cpp | 8 ++++++++ src/plugins/terminal/terminalpane.h | 2 ++ src/plugins/terminal/terminalprocessimpl.cpp | 1 + 3 files changed, 11 insertions(+) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 35a099d410a..f5c4046f922 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -206,6 +206,14 @@ void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) emit navigateStateUpdate(); } +void TerminalPane::ensureVisible(TerminalWidget *terminal) +{ + if (!m_isVisible) + emit showPage(0); + m_tabWidget->setCurrentWidget(terminal); + terminal->setFocus(); +} + TerminalWidget *TerminalPane::stoppedTerminalWithId(const Id &identifier) const { QTC_ASSERT(m_tabWidget, return nullptr); diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 079d45a6712..28c59b523d7 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -42,6 +42,8 @@ public: TerminalWidget *stoppedTerminalWithId(const Utils::Id &identifier) const; + void ensureVisible(TerminalWidget *terminal); + private: TerminalWidget *currentTerminal() const; diff --git a/src/plugins/terminal/terminalprocessimpl.cpp b/src/plugins/terminal/terminalprocessimpl.cpp index d371e1a654a..ef3c4acf646 100644 --- a/src/plugins/terminal/terminalprocessimpl.cpp +++ b/src/plugins/terminal/terminalprocessimpl.cpp @@ -44,6 +44,7 @@ public: terminal->setShellName(setup.m_commandLine.executable().fileName()); m_terminalPane->addTerminal(terminal, "App"); } else { + m_terminalPane->ensureVisible(terminal); terminal->restart(openParameters); } From b509e5aef99a76d213bfee2150c32cd06ac42ebf Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 9 May 2023 07:37:30 +0200 Subject: [PATCH 0912/1447] Terminal: Fix endless loop An error in the QPoint constructor version of CellIterator meant that m_pos could be bigger than m_maxpos. CellIterator(,State) was also simplified to be more correct. Change-Id: Ib67b26695fae1e1857d106319037ca8f63bcb250 Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/terminal/celliterator.cpp | 30 +++++++----------------- src/plugins/terminal/celliterator.h | 2 +- src/plugins/terminal/terminalsurface.cpp | 2 +- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/plugins/terminal/celliterator.cpp b/src/plugins/terminal/celliterator.cpp index 6ad487ae276..597c3a632fd 100644 --- a/src/plugins/terminal/celliterator.cpp +++ b/src/plugins/terminal/celliterator.cpp @@ -10,18 +10,8 @@ namespace Terminal::Internal { CellIterator::CellIterator(const TerminalSurface *surface, QPoint pos) - : m_state(State::INSIDE) - , m_surface(surface) -{ - m_pos = (pos.x()) + (pos.y() * surface->liveSize().width()); - if (m_pos < 0) - m_pos = 0; - if (m_pos == 0) - m_state = State::BEGIN; - - m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; - updateChar(); -} + : CellIterator(surface, pos.x() + (pos.y() * surface->liveSize().width())) +{} CellIterator::CellIterator(const TerminalSurface *surface, int pos) : m_state(State::INSIDE) @@ -29,23 +19,21 @@ CellIterator::CellIterator(const TerminalSurface *surface, int pos) { m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; m_pos = qMax(0, qMin(m_maxpos + 1, pos)); - if (m_pos == 0) { + + if (m_pos == 0) m_state = State::BEGIN; - } else if (m_pos == m_maxpos + 1) { + else if (m_pos == m_maxpos + 1) m_state = State::END; - } + updateChar(); } -CellIterator::CellIterator(const TerminalSurface *surface, State state) - : m_state(state) +CellIterator::CellIterator(const TerminalSurface *surface) + : m_state(State::END) , m_surface(surface) - , m_pos() { m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; - if (state == State::END) { - m_pos = m_maxpos + 1; - } + m_pos = m_maxpos + 1; } QPoint CellIterator::gridPos() const diff --git a/src/plugins/terminal/celliterator.h b/src/plugins/terminal/celliterator.h index e5e7847edc2..c246aaa3114 100644 --- a/src/plugins/terminal/celliterator.h +++ b/src/plugins/terminal/celliterator.h @@ -26,7 +26,7 @@ public: public: CellIterator(const TerminalSurface *surface, QPoint pos); CellIterator(const TerminalSurface *surface, int pos); - CellIterator(const TerminalSurface *surface, State state); + CellIterator(const TerminalSurface *surface); public: QPoint gridPos() const; diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index 01b1f2c2aae..ee8e571adb3 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -496,7 +496,7 @@ CellIterator TerminalSurface::begin() const CellIterator TerminalSurface::end() const { - return CellIterator(this, CellIterator::State::END); + return CellIterator(this); } std::reverse_iterator TerminalSurface::rbegin() const From c68b01c4788957becdf480cee6d81b525fccf255 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 9 May 2023 09:13:32 +0200 Subject: [PATCH 0913/1447] Markdown: Support bookmarks and jumping to search results Redirect the currentLine/Column and gotoLine functions to the text editor and ensure that it is visible for gotoLine. Change-Id: I546e2cb1761363e3a75f9adeebcba195e312f00b Reviewed-by: David Schulz --- src/plugins/bookmarks/bookmarksplugin.cpp | 10 +++--- src/plugins/texteditor/markdowneditor.cpp | 39 +++++++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/plugins/bookmarks/bookmarksplugin.cpp b/src/plugins/bookmarks/bookmarksplugin.cpp index 2f25571b538..7473876ec63 100644 --- a/src/plugins/bookmarks/bookmarksplugin.cpp +++ b/src/plugins/bookmarks/bookmarksplugin.cpp @@ -128,14 +128,16 @@ BookmarksPluginPrivate::BookmarksPluginPrivate() mbm->addAction(cmd); connect(&m_toggleAction, &QAction::triggered, this, [this] { - BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); - if (editor && !editor->document()->isTemporary()) + IEditor *editor = EditorManager::currentEditor(); + auto widget = TextEditorWidget::fromEditor(editor); + if (widget && editor && !editor->document()->isTemporary()) m_bookmarkManager.toggleBookmark(editor->document()->filePath(), editor->currentLine()); }); connect(&m_editAction, &QAction::triggered, this, [this] { - BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); - if (editor && !editor->document()->isTemporary()) { + IEditor *editor = EditorManager::currentEditor(); + auto widget = TextEditorWidget::fromEditor(editor); + if (widget && editor && !editor->document()->isTemporary()) { const FilePath filePath = editor->document()->filePath(); const int line = editor->currentLine(); if (!m_bookmarkManager.hasBookmarkInPosition(filePath, line)) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 3cd1dfb789f..0e76c893315 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -7,6 +7,7 @@ #include "texteditor.h" #include "texteditortr.h" +#include #include #include #include @@ -74,16 +75,23 @@ public: layout->addWidget(m_splitter); setWidget(widget); m_widget->installEventFilter(this); + using namespace Aggregation; + Aggregate *agg = Aggregate::parentAggregate(m_textEditorWidget); + if (!agg) { + agg = new Aggregate; + agg->add(m_textEditorWidget); + } + agg->add(m_widget.get()); auto togglePreviewVisible = new QToolButton; togglePreviewVisible->setText(Tr::tr("Show Preview")); togglePreviewVisible->setCheckable(true); togglePreviewVisible->setChecked(true); - auto toggleEditorVisible = new QToolButton; - toggleEditorVisible->setText(Tr::tr("Show Editor")); - toggleEditorVisible->setCheckable(true); - toggleEditorVisible->setChecked(true); + m_toggleEditorVisible = new QToolButton; + m_toggleEditorVisible->setText(Tr::tr("Show Editor")); + m_toggleEditorVisible->setCheckable(true); + m_toggleEditorVisible->setChecked(true); auto swapViews = new QToolButton; swapViews->setText(Tr::tr("Swap Views")); @@ -94,9 +102,9 @@ public: toolbarLayout->addStretch(); if (textEditorRight) { toolbarLayout->addWidget(togglePreviewVisible); - toolbarLayout->addWidget(toggleEditorVisible); + toolbarLayout->addWidget(m_toggleEditorVisible); } else { - toolbarLayout->addWidget(toggleEditorVisible); + toolbarLayout->addWidget(m_toggleEditorVisible); toolbarLayout->addWidget(togglePreviewVisible); } toolbarLayout->addWidget(swapViews); @@ -137,7 +145,7 @@ public: swapViews->setEnabled(view->isVisible() && otherView->isVisible()); }; - connect(toggleEditorVisible, + connect(m_toggleEditorVisible, &QToolButton::toggled, this, [this, browser, togglePreviewVisible, viewToggled](bool visible) { @@ -146,8 +154,8 @@ public: connect(togglePreviewVisible, &QToolButton::toggled, this, - [this, browser, toggleEditorVisible, viewToggled, updatePreview](bool visible) { - viewToggled(browser, visible, m_textEditorWidget, toggleEditorVisible); + [this, browser, viewToggled, updatePreview](bool visible) { + viewToggled(browser, visible, m_textEditorWidget, m_toggleEditorVisible); if (visible && m_performDelayedUpdate) { m_performDelayedUpdate = false; updatePreview(); @@ -193,6 +201,18 @@ public: Core::IDocument *document() const override { return m_document.data(); } TextEditorWidget *textEditorWidget() const { return m_textEditorWidget; } + int currentLine() const override { return textEditorWidget()->textCursor().blockNumber() + 1; }; + int currentColumn() const override + { + QTextCursor cursor = textEditorWidget()->textCursor(); + return cursor.position() - cursor.block().position() + 1; + } + void gotoLine(int line, int column, bool centerLine) override + { + if (!m_toggleEditorVisible->isChecked()) + m_toggleEditorVisible->toggle(); + textEditorWidget()->gotoLine(line, column, centerLine); + } bool eventFilter(QObject *obj, QEvent *ev) override { @@ -213,6 +233,7 @@ private: TextEditorWidget *m_textEditorWidget; TextDocumentPtr m_document; QWidget m_toolbar; + QToolButton *m_toggleEditorVisible; }; MarkdownEditorFactory::MarkdownEditorFactory() From 7d35a11fd4955f9191211e3f19b4737bbb0347ac Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 19 Apr 2023 10:17:48 +0200 Subject: [PATCH 0914/1447] QtVersionManager: Fix a warning about missing initializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It fixes the following warning: warning: missing initializer for member ‘QtSupport::Internal::ExampleSetModel::ExtraExampleSet::qtVersion’ Amends bdfa412b14174e7e81b899ae8323fc78ddd7916e Change-Id: Ieb984664953f53d458297970e09678c499a26197 Reviewed-by: Eike Ziller (cherry picked from commit a5ad7221841e9fd2c358f1b2a43cfb0fc0c819b9) Reviewed-by: Jarek Kobus Reviewed-by: Qt CI Bot Reviewed-by: Marco Bubke --- src/plugins/qtsupport/exampleslistmodel.h | 2 +- src/plugins/qtsupport/qtversionmanager.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h index c444f9bc1e7..f0465655b79 100644 --- a/src/plugins/qtsupport/exampleslistmodel.h +++ b/src/plugins/qtsupport/exampleslistmodel.h @@ -31,7 +31,7 @@ public: // qtVersion is set by recreateModel for extra sets that correspond to actual Qt versions. // This is needed for the decision to show categories or not based on the Qt version // (which is not ideal). - QVersionNumber qtVersion; + QVersionNumber qtVersion = {}; }; static QVector pluginRegisteredExampleSets(); diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index bdf00c87d5a..c46a45c7636 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -5,7 +5,6 @@ #include "baseqtversion.h" #include "exampleslistmodel.h" -#include "qtkitinformation.h" #include "qtsupportconstants.h" #include "qtversionfactory.h" From 3dc775a6dfbc106e3eb28b5b0198e1e8c31a743a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 5 May 2023 09:50:16 +0200 Subject: [PATCH 0915/1447] MultiTextCursor: iterate over map entries This will ensure that the cursors are iterated over in the order they appear in the document. This fixes an issue on copy and paste a multitext cursors, since the text was copied in the order inside the document, but inserted in the order how the different cursors were added to the multi text cursor. Fixes: QTCREATORBUG-29117 Change-Id: I8475cde7129c378ec7862482226db25e40f61e1b Reviewed-by: Reviewed-by: Christian Stenger --- src/libs/utils/multitextcursor.h | 38 +++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/multitextcursor.h b/src/libs/utils/multitextcursor.h index b2565f931ff..dc554dd2276 100644 --- a/src/libs/utils/multitextcursor.h +++ b/src/libs/utils/multitextcursor.h @@ -76,15 +76,37 @@ public: bool operator==(const MultiTextCursor &other) const; bool operator!=(const MultiTextCursor &other) const; - using iterator = std::list::iterator; - using const_iterator = std::list::const_iterator; + template + class BaseIterator { + public: + using iterator_category = std::input_iterator_tag; + using difference_type = int; + using value_type = T; + using pointer = T *; + using reference = T &; + BaseIterator(const mapit &it) : internalit(it) {} + BaseIterator &operator++() { ++internalit; return *this; } + BaseIterator operator++(int) { auto result = *this; ++(*this); return result; } + bool operator==(BaseIterator other) const { return internalit == other.internalit; } + bool operator!=(BaseIterator other) const { return !(*this == other); } + reference operator*() const { return *(internalit->second); } - iterator begin() { return m_cursorList.begin(); } - iterator end() { return m_cursorList.end(); } - const_iterator begin() const { return m_cursorList.begin(); } - const_iterator end() const { return m_cursorList.end(); } - const_iterator constBegin() const { return m_cursorList.cbegin(); } - const_iterator constEnd() const { return m_cursorList.cend(); } + private: + mapit internalit; + }; + + using iterator + = BaseIterator::iterator>::iterator>; + using const_iterator + = BaseIterator::iterator>::const_iterator>; + + iterator begin() { return m_cursorMap.begin(); } + iterator end() { return m_cursorMap.end(); } + const_iterator begin() const { return m_cursorMap.begin(); } + const_iterator end() const { return m_cursorMap.end(); } + const_iterator constBegin() const { return m_cursorMap.cbegin(); } + const_iterator constEnd() const { return m_cursorMap.cend(); } static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey); From 03e14c264ca206c33ef161262ed51e74607f520a Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 9 May 2023 11:35:20 +0200 Subject: [PATCH 0916/1447] Terminal: Remove clazy warning Don't call QList::constEnd() on temporary [clazy-temporary-iterator] Change-Id: I92108a5c7706173097ae643774af1dd7d7acb5dd Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalsearch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalsearch.h b/src/plugins/terminal/terminalsearch.h index 29af50fa0da..3daa05c04d2 100644 --- a/src/plugins/terminal/terminalsearch.h +++ b/src/plugins/terminal/terminalsearch.h @@ -40,7 +40,7 @@ public: void nextHit(); void previousHit(); - QList hits() const { return m_hits; } + const QList &hits() const { return m_hits; } SearchHit currentHit() const { return m_currentHit >= 0 ? m_hits.at(m_currentHit) : SearchHit{}; From 266202b6b43668203f6aa39f972ea8690297d4e2 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 15:54:09 +0200 Subject: [PATCH 0917/1447] CppEditor: reduce complexity of getting previous line for a given text cursor. Change-Id: I43591b529e9d04b3ef013db3b9b30cf37773c115 Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cpptoolsreuse.cpp | 5 +---- src/plugins/cppeditor/doxygengenerator.cpp | 12 +----------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp index 912902c0c9c..8f68ed3ec9d 100644 --- a/src/plugins/cppeditor/cpptoolsreuse.cpp +++ b/src/plugins/cppeditor/cpptoolsreuse.cpp @@ -266,10 +266,7 @@ const Macro *findCanonicalMacro(const QTextCursor &cursor, Document::Ptr documen { QTC_ASSERT(document, return nullptr); - int line, column; - Utils::Text::convertPosition(cursor.document(), cursor.position(), &line, &column); - - if (const Macro *macro = document->findMacroDefinitionAt(line)) { + if (const Macro *macro = document->findMacroDefinitionAt(cursor.blockNumber() + 1)) { QTextCursor macroCursor = cursor; const QByteArray name = identifierUnderCursor(¯oCursor).toUtf8(); if (macro->name() == name) diff --git a/src/plugins/cppeditor/doxygengenerator.cpp b/src/plugins/cppeditor/doxygengenerator.cpp index 24cfba4abfa..3d88ddd0f55 100644 --- a/src/plugins/cppeditor/doxygengenerator.cpp +++ b/src/plugins/cppeditor/doxygengenerator.cpp @@ -44,16 +44,6 @@ void DoxygenGenerator::setAddLeadingAsterisks(bool add) m_addLeadingAsterisks = add; } -static int lineBeforeCursor(const QTextCursor &cursor) -{ - int line, column; - const bool converted = Utils::Text::convertPosition(cursor.document(), cursor.position(), &line, - &column); - QTC_ASSERT(converted, return std::numeric_limits::max()); - - return line - 1; -} - QString DoxygenGenerator::generate(QTextCursor cursor, const CPlusPlus::Snapshot &snapshot, const Utils::FilePath &documentFilePath) @@ -104,7 +94,7 @@ QString DoxygenGenerator::generate(QTextCursor cursor, Document::Ptr doc = snapshot.preprocessedDocument(declCandidate.toUtf8(), documentFilePath, - lineBeforeCursor(initialCursor)); + cursor.blockNumber()); doc->parse(Document::ParseDeclaration); doc->check(Document::FastCheck); From e7397ec57609914a496019f9926bfae43da88a5b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 14:44:17 +0200 Subject: [PATCH 0918/1447] LayoutBuilder: Fix Splitter construction QSplitter is different insofar as that it doesn't have a Layout, but a list of child widgets. Change-Id: I4e1076e39d20df409c4bab93d79770b6d0e5aa8d Reviewed-by: Alessandro Portale --- src/libs/utils/layoutbuilder.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 51b94b582d8..40862c04346 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -574,8 +574,22 @@ TextEdit::TextEdit(std::initializer_list items) Splitter::Splitter(std::initializer_list items) { - this->subItems = items; - setupWidget(this); // FIXME: Default was Qt::Vertical) + subItems = items; + onAdd = [](LayoutBuilder &builder) { + auto splitter = new QSplitter; + splitter->setOrientation(Qt::Vertical); + builder.stack.append(splitter); + }; + onExit = [](LayoutBuilder &builder) { + const Slice slice = builder.stack.last(); + QSplitter *splitter = qobject_cast(slice.widget); + for (const ResultItem &ri : slice.pendingItems) { + if (ri.widget) + splitter->addWidget(ri.widget); + } + builder.stack.pop_back(); + builder.stack.last().pendingItems.append(ResultItem(splitter)); + }; } TabWidget::TabWidget(std::initializer_list items) From c2f9f4265344737fa485b5800543c484e9f54b1e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 17:38:15 +0200 Subject: [PATCH 0919/1447] BareMetal: Use a functor to apply settings Change-Id: I5e770e6c51a3c709b38879b75c172d4c25e27085 Reviewed-by: Alessandro Portale --- src/plugins/baremetal/debugserverproviderssettingspage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/baremetal/debugserverproviderssettingspage.cpp b/src/plugins/baremetal/debugserverproviderssettingspage.cpp index 097d08033a2..58af3578a96 100644 --- a/src/plugins/baremetal/debugserverproviderssettingspage.cpp +++ b/src/plugins/baremetal/debugserverproviderssettingspage.cpp @@ -257,8 +257,6 @@ class DebugServerProvidersSettingsWidget final : public Core::IOptionsPageWidget public: DebugServerProvidersSettingsWidget(); - void apply() final { m_model.apply(); } - void providerSelectionChanged(); void removeProvider(); void updateState(); @@ -363,6 +361,8 @@ DebugServerProvidersSettingsWidget::DebugServerProvidersSettingsWidget() this, &DebugServerProvidersSettingsWidget::removeProvider); updateState(); + + setOnApply([this] { m_model.apply(); }); } void DebugServerProvidersSettingsWidget::providerSelectionChanged() From 2e7930b56e1e32343587e0c7c74cdb641050ea30 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 18:22:42 +0200 Subject: [PATCH 0920/1447] LayoutBuilder: Rename Id to ID The Id was only used in the demo. "ID" is Not exactly canonical naming, but this clashes often with Utils::Id, so mis-spell until we settle on a proper name. Change-Id: I6fdf806c41abf224f7422ec6c9263db3eb357190 Reviewed-by: Alessandro Portale --- src/libs/utils/layoutbuilder.cpp | 4 ++-- src/libs/utils/layoutbuilder.h | 8 ++++---- tests/manual/layoutbuilder/demo/main.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 40862c04346..f23b5e025f5 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -710,12 +710,12 @@ LayoutItem columnStretch(int column, int stretch) // Id based setters -LayoutItem id(Id &out) +LayoutItem id(ID &out) { return [&out](QObject *target) { out.ob = target; }; } -void setText(Id id, const QString &text) +void setText(ID id, const QString &text) { if (auto textEdit = qobject_cast(id.ob)) textEdit->setText(text); diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 3898dd59826..33fba0270d0 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -202,15 +202,15 @@ QTCREATOR_UTILS_EXPORT LayoutItem windowTitle(const QString &windowTitle); // "Getters" -class Id +class ID { public: QObject *ob = nullptr; }; -QTCREATOR_UTILS_EXPORT LayoutItem id(Id &out); +QTCREATOR_UTILS_EXPORT LayoutItem id(ID &out); -QTCREATOR_UTILS_EXPORT void setText(Id id, const QString &text); +QTCREATOR_UTILS_EXPORT void setText(ID id, const QString &text); // "Signals" @@ -222,7 +222,7 @@ QTCREATOR_UTILS_EXPORT LayoutItem onTextChanged(const std::function &, QObject *guard = nullptr); -QTCREATOR_UTILS_EXPORT LayoutItem onTextChanged(Id &id, QVariant(*sig)(QObject *)); +QTCREATOR_UTILS_EXPORT LayoutItem onTextChanged(ID &id, QVariant(*sig)(QObject *)); // Convenience diff --git a/tests/manual/layoutbuilder/demo/main.cpp b/tests/manual/layoutbuilder/demo/main.cpp index 60996ba96ef..2dd95dfddbf 100644 --- a/tests/manual/layoutbuilder/demo/main.cpp +++ b/tests/manual/layoutbuilder/demo/main.cpp @@ -9,7 +9,7 @@ using namespace Layouting; int main(int argc, char *argv[]) { - Id textId; + ID textId; Application app { From f9fd83df9ad4be3eb99dbd7569813a02887ca3fe Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 17:47:15 +0200 Subject: [PATCH 0921/1447] Core: Introduce PagedSettings An AspectContainer with an IOptionsPage. Change-Id: I03d460f788cfcb2c631b2789bc8f7c74a0b62a37 Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/dialogs/ioptionspage.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 7849ce0bb13..31d8e399600 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -5,6 +5,7 @@ #include +#include #include #include @@ -126,4 +127,10 @@ protected: Utils::Icon m_categoryIcon; }; +class CORE_EXPORT PagedSettings : public Utils::AspectContainer, public IOptionsPage +{ +public: + PagedSettings() = default; +}; + } // namespace Core From e206ed5236c6ca1846c7a9add8976fb8cac07672 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 18:08:46 +0200 Subject: [PATCH 0922/1447] Core: Introduce a IOptionsPage::setLayout(const LayoutItem) Helps to move the lambda setup off the user code. Change-Id: I0de43f53fc9018913340e81b5c1e8e69df067bd6 Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/dialogs/ioptionspage.cpp | 9 +++++++++ src/plugins/coreplugin/dialogs/ioptionspage.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index a19458c5fbb..a0e8fd99225 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -204,6 +205,14 @@ void IOptionsPage::setLayouter(const std::function &layouter) m_layouter = layouter; } +void IOptionsPage::setLayout(const Layouting::LayoutItem &layout) +{ + using namespace Layouting; + m_layouter = [layout](QWidget *widget) { + Column { Row { Column { layout, st }, st } }.attachTo(widget); + }; +} + /*! \fn void Core::IOptionsPage::setId(Utils::Id id) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 31d8e399600..a6263de97df 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -16,6 +16,8 @@ #include +namespace Layouting { class LayoutItem; }; + namespace Utils { class AspectContainer; }; namespace Core { @@ -73,6 +75,7 @@ protected: void setCategoryIconPath(const Utils::FilePath &categoryIconPath); void setSettings(Utils::AspectContainer *settings); void setLayouter(const std::function &layouter); + void setLayout(const Layouting::LayoutItem &layout); // Used in FontSettingsPage. FIXME? QPointer m_widget; // Used in conjunction with m_widgetCreator From c75b59f9b448b9d4ed3f618df705601dcd4eb9db Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 9 May 2023 22:49:14 +0200 Subject: [PATCH 0923/1447] Process: Rename QtcProcessPrivate -> ProcessPrivate Rename the logging category for Process. Fix inline comments accordingly. Adapt warning/debug messages accordingly. Change-Id: I2b1f0f558701def3afa3c1b04adf629833dba9e7 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/commandline.cpp | 2 +- src/libs/utils/deviceshell.cpp | 4 +- src/libs/utils/filepath.cpp | 2 +- src/libs/utils/launchersocket.cpp | 4 +- src/libs/utils/launchersocket.h | 2 +- src/libs/utils/macroexpander.cpp | 2 +- src/libs/utils/process.cpp | 66 +++++++++---------- src/libs/utils/process.h | 8 +-- src/libs/utils/processinterface.h | 6 +- src/libs/utils/processreaper.cpp | 2 +- src/plugins/android/androidavdmanager.cpp | 2 +- .../cmakeprojectmanager/cmakeprocess.cpp | 2 +- .../progressmanager/processprogress.cpp | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/projectexplorer/runcontrol.cpp | 2 +- src/plugins/squish/squishtools.cpp | 2 +- src/plugins/vcsbase/vcsenums.h | 2 +- .../process/processtestapp/processtestapp.h | 2 +- 18 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 9f6fdec35d1..103049ae246 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -893,7 +893,7 @@ bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType o break; case CrtClosed: // Two consecutive quotes make a literal quote - and - // still close quoting. See QtcProcess::quoteArg(). + // still close quoting. See Process::quoteArg(). crtState = CrtInWord; break; case CrtHadQuote: diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp index 627fee3d675..f6474721ace 100644 --- a/src/libs/utils/deviceshell.cpp +++ b/src/libs/utils/deviceshell.cpp @@ -73,11 +73,11 @@ QStringList DeviceShell::missingFeatures() const { return m_missingFeatures; } RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData) { - // If the script failed to install, use QtcProcess directly instead. + // If the script failed to install, use Process directly instead. bool useProcess = m_shellScriptState == State::Failed; // Transferring large amounts of stdInData is slow via the shell script. - // Use QtcProcess directly if the size exceeds 100kb. + // Use Process directly if the size exceeds 100kb. useProcess |= stdInData.size() > (1024 * 100); if (useProcess) { diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index de70d4bf9bc..313da1cd7c9 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -91,7 +91,7 @@ inline bool isWindowsDriveLetter(QChar ch); executed on the associated OS. \note The FilePath passed as executable to a CommandLine is typically - not touched by user code. QtcProcess will use it to determine + not touched by user code. The Process will use it to determine the remote system and apply the necessary conversions internally. \li FilePath::toFSPathString() diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index ccf2ee7b2f4..b1ffb77055f 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -228,7 +228,7 @@ void CallerHandle::start(const QString &program, const QStringList &arguments) auto startWhenRunning = [&program, &oldProgram = m_command] { qWarning() << "Trying to start" << program << "while" << oldProgram - << "is still running for the same QtcProcess instance." + << "is still running for the same Process instance." << "The current call will be ignored."; }; QTC_ASSERT(m_processState == QProcess::NotRunning, startWhenRunning(); return); @@ -622,7 +622,7 @@ void LauncherSocket::handleSocketDataAvailable() } } else { // qDebug() << "No handler for token" << m_packetParser.token() << m_handles; - // in this case the QtcProcess was canceled and deleted + // in this case the Process was canceled and deleted } handleSocketDataAvailable(); } diff --git a/src/libs/utils/launchersocket.h b/src/libs/utils/launchersocket.h index 3a9be73e65e..be1b7f7f9ba 100644 --- a/src/libs/utils/launchersocket.h +++ b/src/libs/utils/launchersocket.h @@ -124,7 +124,7 @@ private: // Moved to the launcher thread, returned to caller's thread. // It's assumed that this object will be alive at least -// as long as the corresponding QtcProcess is alive. +// as long as the corresponding Process is alive. class LauncherHandle : public QObject { diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index b1ce40d25aa..644268d7cf4 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -196,7 +196,7 @@ using namespace Internal; you would use the one provided by the variable manager). Mostly the same as MacroExpander::expandedString(), but also has a variant that does the replacement inline instead of returning a new string. - \li Using Utils::QtcProcess::expandMacros(). This expands the string while conforming to the + \li Using Utils::CommandLine::expandMacros(). This expands the string while conforming to the quoting rules of the platform it is run on. Use this function with the variable manager's macro expander if your string will be passed as a command line parameter string to an external command. diff --git a/src/libs/utils/process.cpp b/src/libs/utils/process.cpp index 1b11bd8645c..f25bc3d3fde 100644 --- a/src/libs/utils/process.cpp +++ b/src/libs/utils/process.cpp @@ -171,9 +171,9 @@ enum { syncDebug = 0 }; enum { defaultMaxHangTimerCount = 10 }; -static Q_LOGGING_CATEGORY(processLog, "qtc.utils.qtcprocess", QtWarningMsg) -static Q_LOGGING_CATEGORY(processStdoutLog, "qtc.utils.qtcprocess.stdout", QtWarningMsg) -static Q_LOGGING_CATEGORY(processStderrLog, "qtc.utils.qtcprocess.stderr", QtWarningMsg) +static Q_LOGGING_CATEGORY(processLog, "qtc.utils.process", QtWarningMsg) +static Q_LOGGING_CATEGORY(processStdoutLog, "qtc.utils.process.stdout", QtWarningMsg) +static Q_LOGGING_CATEGORY(processStderrLog, "qtc.utils.process.stderr", QtWarningMsg) static DeviceProcessHooks s_deviceHooks; @@ -454,7 +454,7 @@ private: void doDefaultStart(const QString &program, const QStringList &arguments) final { QTC_ASSERT(QThread::currentThread()->eventDispatcher(), - qWarning("QtcProcess::start(): Starting a process in a non QThread thread " + qWarning("Process::start(): Starting a process in a non QThread thread " "may cause infinite hang when destroying the running process.")); ProcessStartHandler *handler = m_process->processStartHandler(); handler->setProcessMode(m_setup.m_processMode); @@ -684,7 +684,7 @@ private: class GeneralProcessBlockingImpl : public ProcessBlockingInterface { public: - GeneralProcessBlockingImpl(QtcProcessPrivate *parent); + GeneralProcessBlockingImpl(ProcessPrivate *parent); void flush() { flushSignals(takeAllSignals()); } bool flushFor(ProcessSignalType signalType) { @@ -708,16 +708,16 @@ private: void handleReadyReadSignal(const ReadyReadSignal *launcherSignal); void handleDoneSignal(const DoneSignal *launcherSignal); - QtcProcessPrivate *m_caller = nullptr; + ProcessPrivate *m_caller = nullptr; std::unique_ptr m_processHandler; mutable QMutex m_mutex; QList m_signals; }; -class QtcProcessPrivate : public QObject +class ProcessPrivate : public QObject { public: - explicit QtcProcessPrivate(Process *parent) + explicit ProcessPrivate(Process *parent) : QObject(parent) , q(parent) , m_killTimer(this) @@ -754,11 +754,11 @@ public: m_process.reset(process); m_process->setParent(this); connect(m_process.get(), &ProcessInterface::started, - this, &QtcProcessPrivate::handleStarted); + this, &ProcessPrivate::handleStarted); connect(m_process.get(), &ProcessInterface::readyRead, - this, &QtcProcessPrivate::handleReadyRead); + this, &ProcessPrivate::handleReadyRead); connect(m_process.get(), &ProcessInterface::done, - this, &QtcProcessPrivate::handleDone); + this, &ProcessPrivate::handleDone); m_blockingInterface.reset(process->processBlockingInterface()); if (!m_blockingInterface) @@ -899,7 +899,7 @@ void ProcessInterfaceHandler::appendSignal(ProcessInterfaceSignal *newSignal) QMetaObject::invokeMethod(m_caller, &GeneralProcessBlockingImpl::flush); } -GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(QtcProcessPrivate *parent) +GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(ProcessPrivate *parent) : m_caller(parent) , m_processHandler(new ProcessInterfaceHandler(this, parent->m_process.get())) { @@ -907,7 +907,7 @@ GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(QtcProcessPrivate *parent parent->m_process.get()->setParent(m_processHandler.get()); m_processHandler->setParent(this); // So the hierarchy looks like: - // QtcProcessPrivate + // ProcessPrivate // | // +- GeneralProcessBlockingImpl // | @@ -1021,7 +1021,7 @@ void GeneralProcessBlockingImpl::appendSignal(ProcessInterfaceSignal *newSignal) m_signals.append(newSignal); } -bool QtcProcessPrivate::waitForSignal(ProcessSignalType newSignal, int msecs) +bool ProcessPrivate::waitForSignal(ProcessSignalType newSignal, int msecs) { const QDeadlineTimer timeout(msecs); const QDeadlineTimer currentKillTimeout(m_killTimer.remainingTime()); @@ -1037,13 +1037,13 @@ bool QtcProcessPrivate::waitForSignal(ProcessSignalType newSignal, int msecs) return result; } -Qt::ConnectionType QtcProcessPrivate::connectionType() const +Qt::ConnectionType ProcessPrivate::connectionType() const { return (m_process->thread() == thread()) ? Qt::DirectConnection : Qt::BlockingQueuedConnection; } -void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal) +void ProcessPrivate::sendControlSignal(ControlSignal controlSignal) { QTC_ASSERT(QThread::currentThread() == thread(), return); if (!m_process || (m_state == QProcess::NotRunning)) @@ -1057,7 +1057,7 @@ void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal) }, connectionType()); } -void QtcProcessPrivate::clearForRun() +void ProcessPrivate::clearForRun() { m_hangTimerCount = 0; m_stdOut.clearForRun(); @@ -1073,7 +1073,7 @@ void QtcProcessPrivate::clearForRun() m_resultData = {}; } -ProcessResult QtcProcessPrivate::interpretExitCode(int exitCode) +ProcessResult ProcessPrivate::interpretExitCode(int exitCode) { if (m_exitCodeInterpreter) return m_exitCodeInterpreter(exitCode); @@ -1085,16 +1085,16 @@ ProcessResult QtcProcessPrivate::interpretExitCode(int exitCode) } // Internal /*! - \class Utils::QtcProcess + \class Utils::Process - \brief The QtcProcess class provides functionality for with processes. + \brief The Process class provides functionality for with processes. \sa Utils::ProcessArgs */ Process::Process(QObject *parent) : QObject(parent), - d(new QtcProcessPrivate(this)) + d(new ProcessPrivate(this)) { qRegisterMetaType("ProcessResultData"); static int qProcessExitStatusMeta = qRegisterMetaType(); @@ -1105,7 +1105,7 @@ Process::Process(QObject *parent) Process::~Process() { - QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting QtcProcess instance directly from " + QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting Process instance directly from " "one of its signal handlers will lead to crash!")); if (d->m_process) d->m_process->disconnect(); @@ -1202,7 +1202,7 @@ void Process::start() { QTC_ASSERT(state() == QProcess::NotRunning, return); QTC_ASSERT(!(d->m_process && d->m_guard.isLocked()), - qWarning("Restarting the QtcProcess directly from one of its signal handlers will " + qWarning("Restarting the Process directly from one of its signal handlers will " "lead to crash! Consider calling close() prior to direct restart.")); d->clearForRun(); ProcessInterface *processImpl = nullptr; @@ -1497,7 +1497,7 @@ bool Process::waitForStarted(int msecs) return true; if (d->m_state == QProcess::NotRunning) return false; - return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d, + return s_waitForStarted.measureAndRun(&ProcessPrivate::waitForSignal, d, ProcessSignalType::Started, msecs); } @@ -1726,7 +1726,7 @@ const QStringList Process::stdErrLines() const QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const Process &r) { QDebug nsp = str.nospace(); - nsp << "QtcProcess: result=" + nsp << "Process: result=" << int(r.d->m_result) << " ex=" << r.exitCode() << '\n' << r.d->m_stdOut.rawData.size() << " bytes stdout, stderr=" << r.d->m_stdErr.rawData << '\n'; return str; @@ -1856,7 +1856,7 @@ void Process::runBlocking(EventLoopMode eventLoopMode) // Do not start the event loop in that case. if (state() == QProcess::Starting) { QTimer timer(this); - connect(&timer, &QTimer::timeout, d, &QtcProcessPrivate::slotTimeout); + connect(&timer, &QTimer::timeout, d, &ProcessPrivate::slotTimeout); timer.setInterval(1000); timer.start(); #ifdef QT_GUI_LIB @@ -1936,7 +1936,7 @@ void Process::setTextChannelMode(Channel channel, TextChannelMode mode) const TextChannelCallback callback = (channel == Channel::Output) ? outputCb : errorCb; ChannelBuffer *buffer = channel == Channel::Output ? &d->m_stdOut : &d->m_stdErr; QTC_ASSERT(buffer->m_textChannelMode == TextChannelMode::Off, qWarning() - << "QtcProcess::setTextChannelMode(): Changing text channel mode for" + << "Process::setTextChannelMode(): Changing text channel mode for" << (channel == Channel::Output ? "Output": "Error") << "channel while it was previously set for this channel."); buffer->m_textChannelMode = mode; @@ -1965,7 +1965,7 @@ TextChannelMode Process::textChannelMode(Channel channel) const return buffer->m_textChannelMode; } -void QtcProcessPrivate::slotTimeout() +void ProcessPrivate::slotTimeout() { if (!m_waitingForUser && (++m_hangTimerCount > m_maxHangTimerCount)) { if (debug) @@ -1986,7 +1986,7 @@ void QtcProcessPrivate::slotTimeout() } } -void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId) +void ProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId) { QTC_CHECK(m_state == QProcess::Starting); m_state = QProcess::Running; @@ -1996,7 +1996,7 @@ void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainTh emitGuardedSignal(&Process::started); } -void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByteArray &errorData) +void ProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByteArray &errorData) { QTC_CHECK(m_state == QProcess::Running); @@ -2025,7 +2025,7 @@ void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByt } } -void QtcProcessPrivate::handleDone(const ProcessResultData &data) +void ProcessPrivate::handleDone(const ProcessResultData &data) { m_killTimer.stop(); const bool wasCanceled = m_resultData.m_canceledByUser; @@ -2091,7 +2091,7 @@ static QString blockingMessage(const QVariant &variant) return "blocking without event loop"; } -void QtcProcessPrivate::setupDebugLog() +void ProcessPrivate::setupDebugLog() { if (!processLog().isDebugEnabled()) return; @@ -2140,7 +2140,7 @@ void QtcProcessPrivate::setupDebugLog() }); } -void QtcProcessPrivate::storeEventLoopDebugInfo(const QVariant &value) +void ProcessPrivate::storeEventLoopDebugInfo(const QVariant &value) { if (processLog().isDebugEnabled()) setProperty(QTC_PROCESS_BLOCKING_TYPE, value); diff --git a/src/libs/utils/process.h b/src/libs/utils/process.h index b79cac2d393..6de4f4418b1 100644 --- a/src/libs/utils/process.h +++ b/src/libs/utils/process.h @@ -22,7 +22,7 @@ QT_END_NAMESPACE namespace Utils { -namespace Internal { class QtcProcessPrivate; } +namespace Internal { class ProcessPrivate; } namespace Pty { class Data; } class Environment; @@ -131,7 +131,7 @@ public: // Other enhancements. // These (or some of them) may be potentially moved outside of the class. - // For some we may aggregate in another public utils class (or subclass of QtcProcess)? + // Some of them could be aggregated in another public utils class. // TODO: Unused currently? Should it serve as a compartment for contrary of remoteEnvironment? static Environment systemEnvironmentForBinary(const FilePath &filePath); @@ -198,8 +198,8 @@ signals: private: friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const Process &r); - friend class Internal::QtcProcessPrivate; - Internal::QtcProcessPrivate *d = nullptr; + friend class Internal::ProcessPrivate; + Internal::ProcessPrivate *d = nullptr; }; class DeviceProcessHooks diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index e06076d60b8..a0460c5af3a 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -14,7 +14,7 @@ namespace Utils { -namespace Internal { class QtcProcessPrivate; } +namespace Internal { class ProcessPrivate; } namespace Pty { @@ -104,7 +104,7 @@ private: // - Done is being called in Starting or Running state. virtual bool waitForSignal(ProcessSignalType signalType, int msecs) = 0; - friend class Internal::QtcProcessPrivate; + friend class Internal::ProcessPrivate; }; class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject @@ -143,7 +143,7 @@ private: virtual ProcessBlockingInterface *processBlockingInterface() const { return nullptr; } friend class Process; - friend class Internal::QtcProcessPrivate; + friend class Internal::ProcessPrivate; }; } // namespace Utils diff --git a/src/libs/utils/processreaper.cpp b/src/libs/utils/processreaper.cpp index 117d5fcb33a..f7235d55290 100644 --- a/src/libs/utils/processreaper.cpp +++ b/src/libs/utils/processreaper.cpp @@ -33,7 +33,7 @@ never ending running process: It looks like when you call terminate() for the adb.exe, it won't stop, never, even after default 30 seconds timeout. The same happens for blocking processes tested in - tst_QtcProcess::killBlockingProcess(). It's hard to say whether any process on Windows can + tst_Process::killBlockingProcess(). It's hard to say whether any process on Windows can be finished by a call to terminate(). Until now, no such a process has been found. Further call to kill() (after a call to terminate()) finishes the process quickly. diff --git a/src/plugins/android/androidavdmanager.cpp b/src/plugins/android/androidavdmanager.cpp index 2e7067ca271..67403703025 100644 --- a/src/plugins/android/androidavdmanager.cpp +++ b/src/plugins/android/androidavdmanager.cpp @@ -258,7 +258,7 @@ bool AndroidAvdManager::startAvdAsync(const QString &avdName) const return false; } - // TODO: Here we are potentially leaking QtcProcess instance in case when shutdown happens + // TODO: Here we are potentially leaking Process instance in case when shutdown happens // after the avdProcess has started and before it has finished. Giving a parent object here // should solve the issue. However, AndroidAvdManager is not a QObject, so no clue what parent // would be the most appropriate. Preferably some object taken form android plugin... diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 5922f920452..1455cbf88b9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -38,7 +38,7 @@ CMakeProcess::~CMakeProcess() m_parser.flush(); } -static const int failedToStartExitCode = 0xFF; // See QtcProcessPrivate::handleDone() impl +static const int failedToStartExitCode = 0xFF; // See ProcessPrivate::handleDone() impl void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList &arguments) { diff --git a/src/plugins/coreplugin/progressmanager/processprogress.cpp b/src/plugins/coreplugin/progressmanager/processprogress.cpp index fce87e0d2b2..57b9dcbbfb2 100644 --- a/src/plugins/coreplugin/progressmanager/processprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/processprogress.cpp @@ -74,7 +74,7 @@ void ProcessProgressPrivate::parseProgress(const QString &inputText) \brief The ProcessProgress class is responsible for showing progress of the running process. It's possible to cancel the running process automatically after pressing a small 'x' - indicator on progress panel. In this case QtcProcess::stop() method is being called. + indicator on progress panel. In this case Process::stop() method is being called. */ ProcessProgress::ProcessProgress(Process *process) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index a196d703ed3..df6249f3dbf 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2468,7 +2468,7 @@ void GitClient::tryLaunchingGitK(const Environment &env, arguments << "--" << fileName; VcsOutputWindow::appendCommand(workingDirectory, {binary, arguments}); - // This should always use QtcProcess::startDetached (as not to kill + // This should always use Process::startDetached (as not to kill // the child), but that does not have an environment parameter. if (!settings().path.value().isEmpty()) { auto process = new Process(const_cast(this)); diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index a0329e8bb39..05693d68320 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1375,7 +1375,7 @@ void SimpleTargetRunnerPrivate::start() Encapsulates processes running in a console or as GUI processes, captures debug output of GUI processes on Windows (outputDebugString()). - \sa Utils::QtcProcess + \sa Utils::Process */ SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl) diff --git a/src/plugins/squish/squishtools.cpp b/src/plugins/squish/squishtools.cpp index 37b76136e7e..c31109fab3b 100644 --- a/src/plugins/squish/squishtools.cpp +++ b/src/plugins/squish/squishtools.cpp @@ -1198,7 +1198,7 @@ bool SquishTools::setupRunnerPath() void SquishTools::setupAndStartSquishRunnerProcess(const Utils::CommandLine &cmdLine) { QTC_ASSERT(m_primaryRunner, return); - // avoid crashes on fast re-usage of QtcProcess + // avoid crashes on fast re-usage of Process m_primaryRunner->closeProcess(); if (m_request == RunTestRequested) { diff --git a/src/plugins/vcsbase/vcsenums.h b/src/plugins/vcsbase/vcsenums.h index 69f85f2e5d1..5a5b2c42a74 100644 --- a/src/plugins/vcsbase/vcsenums.h +++ b/src/plugins/vcsbase/vcsenums.h @@ -9,7 +9,7 @@ namespace VcsBase { enum class RunFlags { None = 0, // Empty. - // QtcProcess related + // Process related MergeOutputChannels = (1 << 0), // See QProcess::ProcessChannelMode::MergedChannels. ForceCLocale = (1 << 1), // Force C-locale, sets LANG and LANGUAGE env vars to "C". UseEventLoop = (1 << 2), // Use event loop when executed in UI thread with diff --git a/tests/auto/utils/process/processtestapp/processtestapp.h b/tests/auto/utils/process/processtestapp/processtestapp.h index 721ab83ae75..adc0ebb9c88 100644 --- a/tests/auto/utils/process/processtestapp/processtestapp.h +++ b/tests/auto/utils/process/processtestapp/processtestapp.h @@ -35,7 +35,7 @@ public: static void invokeSubProcess(); - // Many tests inside tst_qtcprocess need to start a new subprocess with custom code. + // Many tests inside tst_Process need to start a new subprocess with custom code. // In order to simplify things we produce just one separate executable - processtestapp. // We embed all our custom subprocesses in processtestapp and enclose them in separate // classes. We select desired process to run by setting the relevant environment variable. From 2bec94ea5850b2fdb29f4dc4845cc6edc2155b76 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 9 May 2023 23:06:18 +0200 Subject: [PATCH 0924/1447] Tasking::Transfer: Rename Transfer into FileTransferTask Rename TransferTest into FileTransferTestTask. Rename adapters accordingly. Task-number: QTCREATORBUG-29102 Change-Id: I50c8b8d64abd7d3063044eaf2e0daceb01e8d388 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- .../projectexplorer/devicesupport/filetransfer.cpp | 2 +- .../projectexplorer/devicesupport/filetransfer.h | 10 +++++----- src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp | 2 +- src/plugins/remotelinux/genericdirectuploadstep.cpp | 2 +- src/plugins/remotelinux/linuxdevicetester.cpp | 2 +- src/plugins/remotelinux/rsyncdeploystep.cpp | 2 +- src/plugins/remotelinux/tarpackagedeploystep.cpp | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/filetransfer.cpp b/src/plugins/projectexplorer/devicesupport/filetransfer.cpp index 523db6b32c2..05815797672 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransfer.cpp +++ b/src/plugins/projectexplorer/devicesupport/filetransfer.cpp @@ -193,7 +193,7 @@ QString FileTransfer::transferMethodName(FileTransferMethod method) return {}; } -FileTransferAdapter::FileTransferAdapter() +FileTransferTaskAdapter::FileTransferTaskAdapter() { connect(task(), &FileTransfer::done, this, [this](const ProcessResultData &result) { emit done(result.m_exitStatus == QProcess::NormalExit diff --git a/src/plugins/projectexplorer/devicesupport/filetransfer.h b/src/plugins/projectexplorer/devicesupport/filetransfer.h index dcc04f05c0b..bc02dbc7829 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransfer.h +++ b/src/plugins/projectexplorer/devicesupport/filetransfer.h @@ -46,14 +46,14 @@ private: FileTransferPrivate *d; }; -class PROJECTEXPLORER_EXPORT FileTransferAdapter : public Utils::Tasking::TaskAdapter +class PROJECTEXPLORER_EXPORT FileTransferTaskAdapter : public Utils::Tasking::TaskAdapter { public: - FileTransferAdapter(); + FileTransferTaskAdapter(); void start() override { task()->start(); } }; -class PROJECTEXPLORER_EXPORT FileTransferTestAdapter : public FileTransferAdapter +class PROJECTEXPLORER_EXPORT FileTransferTestTaskAdapter : public FileTransferTaskAdapter { public: void start() final { task()->test(); } @@ -61,5 +61,5 @@ public: } // namespace ProjectExplorer -QTC_DECLARE_CUSTOM_TASK(Transfer, ProjectExplorer::FileTransferAdapter); -QTC_DECLARE_CUSTOM_TASK(TransferTest, ProjectExplorer::FileTransferTestAdapter); +QTC_DECLARE_CUSTOM_TASK(FileTransferTask, ProjectExplorer::FileTransferTaskAdapter); +QTC_DECLARE_CUSTOM_TASK(FileTransferTestTask, ProjectExplorer::FileTransferTestTaskAdapter); diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index aef2b0d0cd1..f87d9a85712 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -193,7 +193,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::uploadTask() const auto errorHandler = [this](const FileTransfer &transfer) { emitErrorMessage(transfer.resultData().m_errorString); }; - return Transfer(setupHandler, {}, errorHandler); + return FileTransferTask(setupHandler, {}, errorHandler); } TaskItem QnxDeployQtLibrariesDialogPrivate::chmodTask(const DeployableFile &file) diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index e4e3ed3801f..7388ceee039 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -226,7 +226,7 @@ TaskItem GenericDirectUploadStep::uploadTask(const TreeStorage &s addErrorMessage(transfer.resultData().m_errorString); }; - return Transfer(setupHandler, {}, errorHandler); + return FileTransferTask(setupHandler, {}, errorHandler); } TaskItem GenericDirectUploadStep::chmodTask(const DeployableFile &file) diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 39df7d9403f..e9338554fda 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -213,7 +213,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod method .arg(generic, sftp, rsync)); } }; - return TransferTest(setup, done, error); + return FileTransferTestTask(setup, done, error); } TaskItem GenericLinuxDeviceTesterPrivate::transferTasks() const diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index b0779c01e2c..38dcc4dea11 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -134,7 +134,7 @@ TaskItem RsyncDeployStep::transferTask() + "\n" + result.m_errorString); } }; - return Transfer(setupHandler, {}, errorHandler); + return FileTransferTask(setupHandler, {}, errorHandler); } Group RsyncDeployStep::deployRecipe() diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index a79209354aa..cdd4cd71671 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -87,7 +87,7 @@ TaskItem TarPackageDeployStep::uploadTask() const ProcessResultData result = transfer.resultData(); addErrorMessage(result.m_errorString); }; - return Transfer(setupHandler, doneHandler, errorHandler); + return FileTransferTask(setupHandler, doneHandler, errorHandler); } TaskItem TarPackageDeployStep::installTask() From b05666d5c53046076415fd4d06abdd82a0674f95 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 9 May 2023 23:36:18 +0200 Subject: [PATCH 0925/1447] TaskTree: Adapt docs naming to the recent renaming Task-number: QTCREATORBUG-29102 Change-Id: I1edf4d4e38c8853560bca3d3a6da55322a6764d6 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/utils/tasktree.cpp | 128 ++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index ee0982072be..dccb023ff31 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -673,15 +673,15 @@ void TaskNode::invokeEndHandler(bool success) declarative way. Use the Tasking namespace to build extensible, declarative task tree - structures that contain possibly asynchronous tasks, such as QtcProcess, - FileTransfer, or AsyncTask. TaskTree structures enable you + structures that contain possibly asynchronous tasks, such as Process, + FileTransfer, or Async. TaskTree structures enable you to create a sophisticated mixture of a parallel or sequential flow of tasks in the form of a tree and to run it any time later. \section1 Root Element and Tasks The TaskTree has a mandatory Group root element, which may contain - any number of tasks of various types, such as Process, FileTransfer, + any number of tasks of various types, such as ProcessTask, FileTransferTask, or AsyncTask: \code @@ -689,9 +689,9 @@ void TaskNode::invokeEndHandler(bool success) using namespace Tasking; const Group root { - Process(...), - Async(...), - Transfer(...) + ProcessTask(...), + AsyncTask(...), + FileTransferTask(...) }; TaskTree *taskTree = new TaskTree(root); @@ -701,11 +701,11 @@ void TaskNode::invokeEndHandler(bool success) \endcode The task tree above has a top level element of the Group type that contains - tasks of the type QtcProcess, FileTransfer, and AsyncTask. + tasks of the type ProcessTask, FileTransferTask, and AsyncTask. After taskTree->start() is called, the tasks are run in a chain, starting - with Process. When Process finishes successfully, the Async task is + with ProcessTask. When the ProcessTask finishes successfully, the AsyncTask task is started. Finally, when the asynchronous task finishes successfully, the - FileTransfer task is started. + FileTransferTask task is started. When the last running task finishes with success, the task tree is considered to have run successfully and the TaskTree::done() signal is emitted. @@ -723,27 +723,27 @@ void TaskNode::invokeEndHandler(bool success) const Group root { Group { parallel, - Process(...), - Async(...) + ProcessTask(...), + AsyncTask(...) }, - Transfer(...) + FileTransferTask(...) }; \endcode The example above differs from the first example in that the root element has - a subgroup that contains the Process and Async tasks. The subgroup is a - sibling element of the Transfer task in the root. The subgroup contains an + a subgroup that contains the ProcessTask and AsyncTask. The subgroup is a + sibling element of the FileTransferTask in the root. The subgroup contains an additional \e parallel element that instructs its Group to execute its tasks in parallel. - So, when the tree above is started, the Process and Async tasks start + So, when the tree above is started, the ProcessTask and AsyncTask start immediately and run in parallel. Since the root group doesn't contain a \e parallel element, its direct child tasks are run in sequence. Thus, the - Transfer task starts when the whole subgroup finishes. The group is + FileTransferTask starts when the whole subgroup finishes. The group is considered as finished when all its tasks have finished. The order in which the tasks finish is not relevant. - So, depending on which task lasts longer (Process or Async), the + So, depending on which task lasts longer (ProcessTask or AsyncTask), the following scenarios can take place: \table @@ -757,35 +757,35 @@ void TaskNode::invokeEndHandler(bool success) \li Sub Group starts \li Sub Group starts \row - \li Process starts - \li Process starts + \li ProcessTask starts + \li ProcessTask starts \row - \li Async starts - \li Async starts + \li AsyncTask starts + \li AsyncTask starts \row \li ... \li ... \row - \li \b {Process finishes} - \li \b {Async finishes} + \li \b {ProcessTask finishes} + \li \b {AsyncTask finishes} \row \li ... \li ... \row - \li \b {Async finishes} - \li \b {Process finishes} + \li \b {AsyncTask finishes} + \li \b {ProcessTask finishes} \row \li Sub Group finishes \li Sub Group finishes \row - \li Transfer starts - \li Transfer starts + \li FileTransferTask starts + \li FileTransferTask starts \row \li ... \li ... \row - \li Transfer finishes - \li Transfer finishes + \li FileTransferTask finishes + \li FileTransferTask finishes \row \li Root Group finishes \li Root Group finishes @@ -798,24 +798,24 @@ void TaskNode::invokeEndHandler(bool success) The presented scenarios assume that all tasks run successfully. If a task fails during execution, the task tree finishes with an error. In particular, - when Process finishes with an error while Async is still being executed, - Async is automatically stopped, the subgroup finishes with an error, - Transfer is skipped, and the tree finishes with an error. + when ProcessTask finishes with an error while AsyncTask is still being executed, + the AsyncTask is automatically stopped, the subgroup finishes with an error, + the FileTransferTask is skipped, and the tree finishes with an error. \section1 Task Types Each task type is associated with its corresponding task class that executes - the task. For example, a Process task inside a task tree is associated with - the QtcProcess class that executes the process. The associated objects are + the task. For example, a ProcessTask inside a task tree is associated with + the Process class that executes the process. The associated objects are automatically created, started, and destructed exclusively by the task tree at the appropriate time. - If a root group consists of five sequential Process tasks, and the task tree - executes the group, it creates an instance of QtcProcess for the first - Process task and starts it. If the QtcProcess instance finishes successfully, - the task tree destructs it and creates a new QtcProcess instance for the - second Process, and so on. If the first task finishes with an error, the task - tree stops creating QtcProcess instances, and the root group finishes with an + If a root group consists of five sequential ProcessTask tasks, and the task tree + executes the group, it creates an instance of Process for the first + ProcessTask and starts it. If the Process instance finishes successfully, + the task tree destructs it and creates a new Process instance for the + second ProcessTask, and so on. If the first task finishes with an error, the task + tree stops creating Process instances, and the root group finishes with an error. The following table shows examples of task types and their corresponding task @@ -827,19 +827,19 @@ void TaskNode::invokeEndHandler(bool success) \li Associated Task Class \li Brief Description \row - \li Process - \li Utils::QtcProcess + \li ProcessTask + \li Utils::Process \li Starts processes. \row - \li Async - \li Utils::AsyncTask + \li AsyncTask + \li Utils::Async \li Starts asynchronous tasks; run in separate thread. \row - \li Tree + \li TaskTreeTask \li Utils::TaskTree \li Starts a nested task tree. \row - \li Transfer + \li FileTransferTask \li ProjectExplorer::FileTransfer \li Starts file transfer between different devices. \endtable @@ -856,15 +856,15 @@ void TaskNode::invokeEndHandler(bool success) handler should always take a \e reference to the associated task class object: \code - const auto onSetup = [](QtcProcess &process) { + const auto onSetup = [](Process &process) { process.setCommand({"sleep", {"3"}}); }; const Group root { - Process(onSetup) + ProcessTask(onSetup) }; \endcode - You can modify the passed QtcProcess in the setup handler, so that the task + You can modify the passed Process in the setup handler, so that the task tree can start the process according to your configuration. You do not need to call \e {process.start();} in the setup handler, as the task tree calls it when needed. The setup handler is mandatory @@ -904,21 +904,21 @@ void TaskNode::invokeEndHandler(bool success) to the associated task class object: \code - const auto onSetup = [](QtcProcess &process) { + const auto onSetup = [](Process &process) { process.setCommand({"sleep", {"3"}}); }; - const auto onDone = [](const QtcProcess &process) { + const auto onDone = [](const Process &process) { qDebug() << "Success" << process.cleanedStdOut(); }; - const auto onError = [](const QtcProcess &process) { + const auto onError = [](const Process &process) { qDebug() << "Failure" << process.cleanedStdErr(); }; const Group root { - Process(onSetup, onDone, onError) + ProcessTask(onSetup, onDone, onError) }; \endcode - The done and error handlers may collect output data from QtcProcess, and store it + The done and error handlers may collect output data from Process, and store it for further processing or perform additional actions. The done handler is optional. When used, it must be the second argument of the task constructor. The error handler must always be the third argument. @@ -944,7 +944,7 @@ void TaskNode::invokeEndHandler(bool success) }; const Group root { OnGroupSetup(onGroupSetup), - Process(...) + ProcessTask(...) }; \endcode @@ -967,17 +967,17 @@ void TaskNode::invokeEndHandler(bool success) OnGroupSetup([] { qDebug() << "Root setup"; }), Group { OnGroupSetup([] { qDebug() << "Group 1 setup"; return TaskAction::Continue; }), - Process(...) // Process 1 + ProcessTask(...) // Process 1 }, Group { OnGroupSetup([] { qDebug() << "Group 2 setup"; return TaskAction::StopWithDone; }), - Process(...) // Process 2 + ProcessTask(...) // Process 2 }, Group { OnGroupSetup([] { qDebug() << "Group 3 setup"; return TaskAction::StopWithError; }), - Process(...) // Process 3 + ProcessTask(...) // Process 3 }, - Process(...) // Process 4 + ProcessTask(...) // Process 4 }; \endcode @@ -1039,7 +1039,7 @@ void TaskNode::invokeEndHandler(bool success) \code const Group root { OnGroupSetup([] { qDebug() << "Root setup"; }), - Process(...), + ProcessTask(...), OnGroupDone([] { qDebug() << "Root finished with success"; }), OnGroupError([] { qDebug() << "Root finished with error"; }) }; @@ -1191,7 +1191,7 @@ void TaskNode::invokeEndHandler(bool success) const TreeStorage storage; const auto onLoaderSetup = [source](Async &async) { - async.setAsyncCallData(&load, source); + async.setConcurrentCallData(&load, source); }; // [4] runtime: task tree activates the instance from [5] before invoking handler const auto onLoaderDone = [storage](const Async &async) { @@ -1200,7 +1200,7 @@ void TaskNode::invokeEndHandler(bool success) // [4] runtime: task tree activates the instance from [5] before invoking handler const auto onSaverSetup = [storage, destination](Async &async) { - async.setAsyncCallData(&save, destination, storage->content); + async.setConcurrentCallData(&save, destination, storage->content); }; const auto onSaverDone = [](const Async &async) { qDebug() << "Save done successfully"; @@ -1209,8 +1209,8 @@ void TaskNode::invokeEndHandler(bool success) const Group root { // [5] runtime: task tree creates an instance of CopyStorage when root is entered Storage(storage), - Async(onLoaderSetup, onLoaderDone), - Async(onSaverSetup, onSaverDone) + AsyncTask(onLoaderSetup, onLoaderDone), + AsyncTask(onSaverSetup, onSaverDone) }; return root; } From c68a013a3e02cf2dde6a7683eb15e87b655fd523 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 9 May 2023 23:43:18 +0200 Subject: [PATCH 0926/1447] Tasking::Tree: Rename Tree into TaskTreeTask Task-number: QTCREATORBUG-29102 Change-Id: I70073bcb44a712c427c8c5aea42c48dbc30eebe0 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/tasktree.cpp | 6 +++--- src/libs/utils/tasktree.h | 6 +++--- src/plugins/diffeditor/diffeditorplugin.cpp | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp | 2 +- src/plugins/remotelinux/genericdirectuploadstep.cpp | 4 ++-- tests/auto/utils/tasktree/tst_tasktree.cpp | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index dccb023ff31..e27cd8f8bbd 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -1264,7 +1264,7 @@ void TaskNode::invokeEndHandler(bool success) recipe described by the Group root element. As TaskTree is also an asynchronous task, it can be a part of another TaskTree. - To place a nested TaskTree inside another TaskTree, insert the Tasking::Tree + To place a nested TaskTree inside another TaskTree, insert the Tasking::TaskTreeTask element into other tree's Group element. TaskTree reports progress of completed tasks when running. The progress value @@ -1455,13 +1455,13 @@ void TaskTree::setupStorageHandler(const Tasking::TreeStorageBase &storage, } } -TaskTreeAdapter::TaskTreeAdapter() +TaskTreeTaskAdapter::TaskTreeTaskAdapter() { connect(task(), &TaskTree::done, this, [this] { emit done(true); }); connect(task(), &TaskTree::errorOccurred, this, [this] { emit done(false); }); } -void TaskTreeAdapter::start() +void TaskTreeTaskAdapter::start() { task()->start(); } diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 418feb797ec..46333c3dc86 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -413,10 +413,10 @@ private: TaskTreePrivate *d; }; -class QTCREATOR_UTILS_EXPORT TaskTreeAdapter : public Tasking::TaskAdapter +class QTCREATOR_UTILS_EXPORT TaskTreeTaskAdapter : public Tasking::TaskAdapter { public: - TaskTreeAdapter(); + TaskTreeTaskAdapter(); void start() final; }; @@ -431,4 +431,4 @@ template \ using CustomTaskName = CustomTask>;\ } // namespace Utils::Tasking -QTC_DECLARE_CUSTOM_TASK(Tree, Utils::TaskTreeAdapter); +QTC_DECLARE_CUSTOM_TASK(TaskTreeTask, Utils::TaskTreeTaskAdapter); diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 5f48dc13a97..e5bed027a34 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -150,7 +150,7 @@ DiffFilesController::DiffFilesController(IDocument *document) const Group root = { Storage(storage), - Tree(setupTree), + TaskTreeTask(setupTree), OnGroupDone(onTreeDone), OnGroupError(onTreeError) }; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index df6249f3dbf..fad0d19afb6 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -472,7 +472,7 @@ ShowController::ShowController(IDocument *document, const QString &id) OnGroupSetup(desciptionDetailsSetup), ProcessTask(setupBranches, onBranchesDone, onBranchesError), ProcessTask(setupPrecedes, onPrecedesDone, onPrecedesError), - Tree(setupFollows) + TaskTreeTask(setupFollows) } }, Group { diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index f87d9a85712..e06303cffaa 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -230,7 +230,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::chmodTree() } tree.setupRoot(chmodList); }; - return Tree{setupChmodHandler}; + return TaskTreeTask{setupChmodHandler}; } Group QnxDeployQtLibrariesDialogPrivate::deployRecipe() diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 7388ceee039..a8f2200cf80 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -186,7 +186,7 @@ TaskItem GenericDirectUploadStep::statTree(const TreeStorage &sto } tree.setupRoot({statList}); }; - return Tree(setupHandler); + return TaskTreeTask(setupHandler); } TaskItem GenericDirectUploadStep::uploadTask(const TreeStorage &storage) @@ -263,7 +263,7 @@ TaskItem GenericDirectUploadStep::chmodTree(const TreeStorage &st } tree.setupRoot({chmodList}); }; - return Tree(setupChmodHandler); + return TaskTreeTask(setupChmodHandler); } Group GenericDirectUploadStep::deployRecipe() diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index ae696e9fd7c..ea60db9745d 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -550,7 +550,7 @@ void tst_TaskTree::testTree_data() const Group root3 { Storage(storage), Test(setupTask(1), logDone), - Tree(setupSubTree), + TaskTreeTask(setupSubTree), Test(setupTask(5), logDone), OnGroupDone(groupDone(0)) }; From 905d76961d9827c4ae55304db9f74f2201a0ed98 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 9 May 2023 15:11:18 +0200 Subject: [PATCH 0927/1447] CPlusPlus: Don't double uniquify CppDocument::includedFiles removes duplicates. Snapshot::allIncludesForDocument also removes duplicates. Once is enough. This doubles test scan performance on my machine. Change-Id: I892908cf0820cfa11854ac3d82e9175d1fc38043 Reviewed-by: Christian Kandeler --- src/libs/cplusplus/CppDocument.cpp | 7 ++++--- src/libs/cplusplus/CppDocument.h | 7 ++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index d28fdd50baa..07714c0fe2f 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -296,12 +296,13 @@ void Document::setLastModified(const QDateTime &lastModified) _lastModified = lastModified; } -FilePaths Document::includedFiles() const +FilePaths Document::includedFiles(Duplicates duplicates) const { FilePaths files; for (const Include &i : std::as_const(_resolvedIncludes)) files.append(i.resolvedFileName()); - FilePath::removeDuplicates(files); + if (duplicates == Duplicates::Remove) + FilePath::removeDuplicates(files); return files; } @@ -771,7 +772,7 @@ QSet Snapshot::allIncludesForDocument(const FilePath &filePath) const while (!files.isEmpty()) { FilePath file = files.pop(); if (Document::Ptr doc = document(file)) { - const FilePaths includedFiles = doc->includedFiles(); + const FilePaths includedFiles = doc->includedFiles(Document::Duplicates::Keep); for (const FilePath &inc : includedFiles) { if (!result.contains(inc)) { result.insert(inc); diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index 679663f2d99..00bebf277d9 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -297,7 +297,12 @@ public: } }; - Utils::FilePaths includedFiles() const; + enum class Duplicates { + Remove, + Keep, + }; + + Utils::FilePaths includedFiles(Duplicates duplicates = Duplicates::Remove) const; void addIncludeFile(const Include &include); const QList &resolvedIncludes() const From b6acb9743ae05d1704a4bbc19538c726f5bb27d4 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 14:48:39 +0200 Subject: [PATCH 0928/1447] Help: Remove dependency of IOptionPage's QObject base Change-Id: Ide7b16406947cc4865653661d0020d657671bc16 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger --- src/plugins/help/filtersettingspage.cpp | 10 +++++----- src/plugins/help/filtersettingspage.h | 7 +------ src/plugins/help/helpplugin.cpp | 4 +--- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/plugins/help/filtersettingspage.cpp b/src/plugins/help/filtersettingspage.cpp index de082526c53..e227b025ef0 100644 --- a/src/plugins/help/filtersettingspage.cpp +++ b/src/plugins/help/filtersettingspage.cpp @@ -18,7 +18,7 @@ namespace Help::Internal { class FilterSettingsPageWidget : public Core::IOptionsPageWidget { public: - FilterSettingsPageWidget(FilterSettingsPage *page) + FilterSettingsPageWidget(const std::function &onChanged) { LocalHelpManager::setupGuiHelpEngine(); @@ -41,9 +41,9 @@ public: updateFilterPage); updateFilterPage(); - setOnApply([widget, page] { + setOnApply([widget, onChanged] { if (widget->applySettings(LocalHelpManager::filterEngine())) - emit page->filtersChanged(); + onChanged(); widget->readSettings(LocalHelpManager::filterEngine()); }); @@ -51,12 +51,12 @@ public: } }; -FilterSettingsPage::FilterSettingsPage() +FilterSettingsPage::FilterSettingsPage(const std::function &onChanged) { setId("D.Filters"); setDisplayName(Tr::tr("Filters")); setCategory(Help::Constants::HELP_CATEGORY); - setWidgetCreator([this] { return new FilterSettingsPageWidget(this); }); + setWidgetCreator([onChanged] { return new FilterSettingsPageWidget(onChanged); }); } } // Help::Internal diff --git a/src/plugins/help/filtersettingspage.h b/src/plugins/help/filtersettingspage.h index 112726c1af9..54256b1d7f0 100644 --- a/src/plugins/help/filtersettingspage.h +++ b/src/plugins/help/filtersettingspage.h @@ -9,13 +9,8 @@ namespace Help::Internal { class FilterSettingsPage : public Core::IOptionsPage { - Q_OBJECT - public: - FilterSettingsPage(); - -signals: - void filtersChanged(); + explicit FilterSettingsPage(const std::function &onChanged); }; } // Help::Internal diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index e46effd10b7..7329b3dad67 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -134,7 +134,7 @@ public: QRect m_externalWindowState; DocSettingsPage m_docSettingsPage; - FilterSettingsPage m_filterSettingsPage; + FilterSettingsPage m_filterSettingsPage{[this] {setupHelpEngineIfNeeded(); }}; SearchTaskHandler m_searchTaskHandler; GeneralSettingsPage m_generalSettingsPage; @@ -197,8 +197,6 @@ HelpPluginPrivate::HelpPluginPrivate() connect(&m_searchTaskHandler, &SearchTaskHandler::search, this, &QDesktopServices::openUrl); - connect(&m_filterSettingsPage, &FilterSettingsPage::filtersChanged, - this, &HelpPluginPrivate::setupHelpEngineIfNeeded); connect(Core::HelpManager::Signals::instance(), &Core::HelpManager::Signals::documentationChanged, this, From d7781c16f7dbfa1b850fd129b0b108c2d2a91070 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 08:02:08 +0200 Subject: [PATCH 0929/1447] Layouting: Remove some now unused functions Change-Id: I9e91bdbf68c38da22bd2378cb7d9596306bbb413 Reviewed-by: Eike Ziller --- src/libs/utils/layoutbuilder.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index f23b5e025f5..251569fdd23 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -239,9 +239,6 @@ public: void addItem(const LayoutItem &item); void addItems(const LayoutItems &items); - void addRow(const LayoutItems &items); - - bool isForm() const; QList stack; }; @@ -324,7 +321,7 @@ void doAddWidget(LayoutBuilder &builder, QWidget *widget) A LayoutBuilder instance is typically used locally within a function and never stored. - \sa addItem(), addItems(), addRow() + \sa addItem(), addItems() */ @@ -346,12 +343,6 @@ void LayoutBuilder::addItems(const LayoutItems &items) addItemHelper(*this, item); } -void LayoutBuilder::addRow(const LayoutItems &items) -{ - addItem(br); - addItems(items); -} - /*! This starts a new row containing \a items. The row can be further extended by other items using \c addItem() or \c addItems(). @@ -401,11 +392,6 @@ QWidget *LayoutItem::emerge() return w; } -bool LayoutBuilder::isForm() const -{ - return qobject_cast(stack.last().layout); -} - static void layoutExit(LayoutBuilder &builder) { builder.stack.last().flush(); From 2c433f7fe1b47b3fd497f87e51e248c70323a3f5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 14:36:11 +0200 Subject: [PATCH 0930/1447] Core: Remove QObject base of IOptionsPage Change-Id: I714fd0cdd542da947deb2a8395dec87bb40fca75 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/dialogs/ioptionspage.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index a6263de97df..a51b459f5f0 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -40,13 +40,13 @@ private: std::function m_onFinish; }; -class CORE_EXPORT IOptionsPage : public QObject +class CORE_EXPORT IOptionsPage { - Q_OBJECT + Q_DISABLE_COPY_MOVE(IOptionsPage) public: explicit IOptionsPage(bool registerGlobally = true); - ~IOptionsPage() override; + virtual ~IOptionsPage(); static const QList allOptionsPages(); From fc95d7a73730f67584891471d912dfd7f65a9cc2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 10 May 2023 08:53:35 +0200 Subject: [PATCH 0931/1447] Utils: Improve FilePath::sort Remove the conversion to/from QString for sorting. Change-Id: I89921328b6d9e952c802d41998495bd2ffbb9f99 Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 16 ++++--- tests/auto/utils/filepath/tst_filepath.cpp | 52 ++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 313da1cd7c9..9bf47805964 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1531,11 +1531,17 @@ void FilePath::removeDuplicates(FilePaths &files) void FilePath::sort(FilePaths &files) { - // FIXME: Improve. - // FIXME: This drops the osType information, which is not correct. - QStringList list = transform(files, &FilePath::toString); - list.sort(); - files = FileUtils::toFilePathList(list); + std::sort(files.begin(), files.end(), [](const FilePath &a, const FilePath &b) { + const int scheme = a.scheme().compare(b.scheme()); + if (scheme != 0) + return scheme < 0; + + const int host = a.host().compare(b.host()); + if (host != 0) + return host < 0; + + return a.pathView() < b.pathView(); + }); } void join(QString &left, const QString &right) diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index 64888937dec..6e11ddb71cd 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -109,6 +110,9 @@ private slots: void searchInWithFilter(); + void sort(); + void sort_data(); + private: QTemporaryDir tempDir; QString rootPath; @@ -1657,6 +1661,54 @@ void tst_filepath::tmp() } } +void tst_filepath::sort() +{ + QFETCH(QStringList, input); + + FilePaths filePaths = Utils::transform(input, &FilePath::fromString); + QStringList sorted = input; + sorted.sort(); + + FilePath::sort(filePaths); + QStringList sortedPaths = Utils::transform(filePaths, &FilePath::toString); + + QCOMPARE(sortedPaths, sorted); +} + +void tst_filepath::sort_data() +{ + QTest::addColumn("input"); + + QTest::addRow("empty") << QStringList{}; + + QTest::addRow("one") << QStringList{"foo"}; + QTest::addRow("two") << QStringList{"foo", "bar"}; + QTest::addRow("three") << QStringList{"foo", "bar", "baz"}; + + QTest::addRow("one-absolute") << QStringList{"/foo"}; + QTest::addRow("two-absolute") << QStringList{"/foo", "/bar"}; + + QTest::addRow("one-relative") << QStringList{"foo"}; + + QTest::addRow("one-absolute-one-relative") << QStringList{"/foo", "bar"}; + + QTest::addRow("host") << QStringList{"ssh://test/blah", "ssh://gulp/blah", "ssh://zzz/blah"}; + + QTest::addRow("scheme") << QStringList{"ssh://test/blah", + "ssh://gulp/blah", + "ssh://zzz/blah", + "aaa://gulp/blah", + "xyz://test/blah"}; + + QTest::addRow("others") << QStringList{"a://a//a", + "a://b//a", + "a://a//b", + "a://b//b", + "b://b//b"}; + QTest::addRow("others-reversed") + << QStringList{"b://b//b", "a://b//b", "a://a//b", "a://b//a", "a://a//a"}; +} + QTEST_GUILESS_MAIN(tst_filepath) #include "tst_filepath.moc" From 3f2832289de7a1069937275d22b02c03aabe8776 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 13:49:57 +0200 Subject: [PATCH 0932/1447] Utils: move TextPosition/Range to textutils Change-Id: Id94a7a96f3b0f978e94850d67eb4b8fba6c18fe2 Reviewed-by: Jarek Kobus --- src/libs/utils/searchresultitem.cpp | 30 --------------- src/libs/utils/searchresultitem.h | 38 ++----------------- src/libs/utils/textutils.cpp | 36 ++++++++++++++++-- src/libs/utils/textutils.h | 30 +++++++++++++++ src/plugins/coreplugin/coreplugin.cpp | 4 +- .../editormanager/editormanager.cpp | 2 +- .../coreplugin/find/searchresultwindow.cpp | 12 ------ .../languageclientsymbolsupport.cpp | 6 +-- .../languageclientsymbolsupport.h | 2 +- .../languageclient/languageclientutils.cpp | 5 +-- src/plugins/texteditor/texteditor.cpp | 2 +- 11 files changed, 76 insertions(+), 91 deletions(-) diff --git a/src/libs/utils/searchresultitem.cpp b/src/libs/utils/searchresultitem.cpp index 1fe0d953f6b..2574473c933 100644 --- a/src/libs/utils/searchresultitem.cpp +++ b/src/libs/utils/searchresultitem.cpp @@ -5,26 +5,6 @@ namespace Utils { -int Search::TextRange::length(const QString &text) const -{ - if (begin.line == end.line) - return end.column - begin.column; - - const int lineCount = end.line - begin.line; - int index = text.indexOf(QChar::LineFeed); - int currentLine = 1; - while (index > 0 && currentLine < lineCount) { - ++index; - index = text.indexOf(QChar::LineFeed, index); - ++currentLine; - } - - if (index < 0) - return 0; - - return index - begin.column + end.column; -} - SearchResultColor::SearchResultColor(const QColor &textBg, const QColor &textFg, const QColor &highlightBg, const QColor &highlightFg, const QColor &functionBg, const QColor &functionFg) @@ -72,16 +52,6 @@ QTCREATOR_UTILS_EXPORT size_t qHash(SearchResultColor::Style style, uint seed) return ::qHash(a, seed); } -bool Search::TextPosition::operator==(const Search::TextPosition &other) const -{ - return line == other.line && column == other.column; -} - -bool Search::TextRange::operator==(const Search::TextRange &other) const -{ - return begin == other.begin && end == other.end; -} - bool SearchResultItem::operator==(const SearchResultItem &other) const { return m_path == other.m_path && m_lineText == other.m_lineText diff --git a/src/libs/utils/searchresultitem.h b/src/libs/utils/searchresultitem.h index 080a44f24e8..ea9d0332d5a 100644 --- a/src/libs/utils/searchresultitem.h +++ b/src/libs/utils/searchresultitem.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -18,36 +19,6 @@ namespace Utils { -namespace Search { - -class QTCREATOR_UTILS_EXPORT TextPosition -{ -public: - int line = -1; // (0 or -1 for no line number) - int column = -1; // 0-based starting position for a mark (-1 for no mark) - - bool operator<(const TextPosition &other) const - { return line < other.line || (line == other.line && column < other.column); } - bool operator==(const TextPosition &other) const; - bool operator!=(const TextPosition &other) const { return !(operator==(other)); } -}; - -class QTCREATOR_UTILS_EXPORT TextRange -{ -public: - QString mid(const QString &text) const { return text.mid(begin.column, length(text)); } - int length(const QString &text) const; - - TextPosition begin; - TextPosition end; - - bool operator<(const TextRange &other) const { return begin < other.begin; } - bool operator==(const TextRange &other) const; - bool operator!=(const TextRange &other) const { return !(operator==(other)); } -}; - -} // namespace Search - class QTCREATOR_UTILS_EXPORT SearchResultColor { public: @@ -88,8 +59,8 @@ public: QVariant userData() const { return m_userData; } void setUserData(const QVariant &userData) { m_userData = userData; } - Search::TextRange mainRange() const { return m_mainRange; } - void setMainRange(const Search::TextRange &mainRange) { m_mainRange = mainRange; } + Text::Range mainRange() const { return m_mainRange; } + void setMainRange(const Text::Range &mainRange) { m_mainRange = mainRange; } void setMainRange(int line, int column, int length); bool useTextEditorFont() const { return m_useTextEditorFont; } @@ -116,7 +87,7 @@ private: QString m_lineText; // text to show for the item itself QIcon m_icon; // icon to show in front of the item (by be null icon to hide) QVariant m_userData; // user data for identification of the item - Search::TextRange m_mainRange; + Text::Range m_mainRange; bool m_useTextEditorFont = false; bool m_selectForReplacement = true; SearchResultColor::Style m_style = SearchResultColor::Style::Default; @@ -129,4 +100,3 @@ using SearchResultItems = QList; Q_DECLARE_METATYPE(Utils::SearchResultItem) Q_DECLARE_METATYPE(Utils::SearchResultItems) -Q_DECLARE_METATYPE(Utils::Search::TextPosition) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 1222038039f..ec440a8902a 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -6,8 +6,37 @@ #include #include -namespace Utils { -namespace Text { +namespace Utils::Text { + +bool Position::operator==(const Position &other) const +{ + return line == other.line && column == other.column; +} + +int Range::length(const QString &text) const +{ + if (begin.line == end.line) + return end.column - begin.column; + + const int lineCount = end.line - begin.line; + int index = text.indexOf(QChar::LineFeed); + int currentLine = 1; + while (index > 0 && currentLine < lineCount) { + ++index; + index = text.indexOf(QChar::LineFeed, index); + ++currentLine; + } + + if (index < 0) + return 0; + + return index - begin.column + end.column; +} + +bool Range::operator==(const Range &other) const +{ + return begin == other.begin && end == other.end; +} bool convertPosition(const QTextDocument *document, int pos, int *line, int *column) { @@ -211,5 +240,4 @@ void applyReplacements(QTextDocument *doc, const Replacements &replacements) editCursor.endEditBlock(); } -} // Text -} // Utils +} // namespace Utils::Text diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index e214f746598..ce8a450302a 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -17,6 +17,34 @@ QT_END_NAMESPACE namespace Utils { namespace Text { +class QTCREATOR_UTILS_EXPORT Position +{ +public: + int line = 0; // 1-based + int column = -1; // 0-based + + bool operator<(const Position &other) const + { return line < other.line || (line == other.line && column < other.column); } + bool operator==(const Position &other) const; + + bool operator!=(const Position &other) const { return !(operator==(other)); } +}; + +class QTCREATOR_UTILS_EXPORT Range +{ +public: + QString mid(const QString &text) const { return text.mid(begin.column, length(text)); } + int length(const QString &text) const; + + Position begin; + Position end; + + bool operator<(const Range &other) const { return begin < other.begin; } + bool operator==(const Range &other) const; + + bool operator!=(const Range &other) const { return !(operator==(other)); } +}; + struct Replacement { Replacement() = default; @@ -66,3 +94,5 @@ QTCREATOR_UTILS_EXPORT QString utf16LineTextInUtf8Buffer(const QByteArray &utf8B } // Text } // Utils + +Q_DECLARE_METATYPE(Utils::Text::Position) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 448d8e6a33d..5d7524d8080 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -35,8 +35,8 @@ #include #include #include -#include #include +#include #include #include @@ -72,7 +72,7 @@ void CorePlugin::setupSystemEnvironment() CorePlugin::CorePlugin() { qRegisterMetaType(); - qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 6f1856f162f..19c6b309f1b 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -3192,7 +3192,7 @@ void EditorManager::openEditorAtSearchResult(const SearchResultItem &item, openEditor(FilePath::fromUserInput(item.lineText()), editorId, flags, newEditor); return; } - const Search::TextPosition position = item.mainRange().begin; + const Text::Position position = item.mainRange().begin; openEditorAt({FilePath::fromUserInput(path.first()), position.line, position.column}, editorId, flags, newEditor); } diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index a9cc493681a..60a514f51d3 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -40,18 +40,6 @@ namespace Core { \internal */ -/*! - \class Core::Search::TextPosition - \inmodule QtCreator - \internal -*/ - -/*! - \class Core::Search::TextRange - \inmodule QtCreator - \internal -*/ - namespace Internal { class InternalScrollArea : public QScrollArea diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp index 04267ebb074..7069360b021 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.cpp +++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp @@ -193,7 +193,7 @@ bool SymbolSupport::supportsFindUsages(TextEditor::TextDocument *document) const struct ItemData { - Utils::Search::TextRange range; + Utils::Text::Range range; QVariant userData; }; @@ -616,10 +616,10 @@ QString SymbolSupport::derivePlaceholder(const QString &oldSymbol, const QString return m_defaultSymbolMapper ? m_defaultSymbolMapper(oldSymbol) : oldSymbol; } -Utils::Search::TextRange SymbolSupport::convertRange(const Range &range) +Utils::Text::Range SymbolSupport::convertRange(const Range &range) { const auto convertPosition = [](const Position &pos) { - return Utils::Search::TextPosition{pos.line() + 1, pos.character()}; + return Utils::Text::Position{pos.line() + 1, pos.character()}; }; return {convertPosition(range.start()), convertPosition(range.end())}; } diff --git a/src/plugins/languageclient/languageclientsymbolsupport.h b/src/plugins/languageclient/languageclientsymbolsupport.h index e52b80471ad..3dcc7b0ddc3 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.h +++ b/src/plugins/languageclient/languageclientsymbolsupport.h @@ -43,7 +43,7 @@ public: const std::function &callback = {}, bool preferLowerCaseFileNames = true); - static Utils::Search::TextRange convertRange(const LanguageServerProtocol::Range &range); + static Utils::Text::Range convertRange(const LanguageServerProtocol::Range &range); static QStringList getFileContents(const Utils::FilePath &filePath); using SymbolMapper = std::function; diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index 44168d1dd25..c421b2a9376 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -97,11 +97,10 @@ void applyTextEdit(TextDocumentManipulatorInterface &manipulator, const TextEdit &edit, bool newTextIsSnippet) { - using namespace Utils::Text; const Range range = edit.range(); const QTextDocument *doc = manipulator.textCursorAt(manipulator.currentPosition()).document(); - const int start = positionInText(doc, range.start().line() + 1, range.start().character() + 1); - const int end = positionInText(doc, range.end().line() + 1, range.end().character() + 1); + const int start = Text::positionInText(doc, range.start().line() + 1, range.start().character() + 1); + const int end = Text::positionInText(doc, range.end().line() + 1, range.end().character() + 1); if (newTextIsSnippet) { manipulator.replace(start, end - start, {}); manipulator.insertCodeSnippet(start, edit.newText(), &parseSnippet); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index e9e7367d8e0..bd50833304e 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -850,7 +850,7 @@ private: static QFutureWatcher *m_selectWatcher; }; -static QTextCursor selectRange(QTextDocument *textDocument, const Search::TextRange &range, +static QTextCursor selectRange(QTextDocument *textDocument, const Text::Range &range, TextEditorWidgetPrivate::SearchResult *searchResult = nullptr) { const int startLine = qMax(range.begin.line - 1, 0); From 2196e082958c97e4a39be93b3b12c237bf792cb2 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 9 May 2023 20:38:51 +0200 Subject: [PATCH 0933/1447] LayoutBuilder: Avoid leak warnings in Application::exec() Change-Id: I9c05f3015b120220408076d58d29983d2194d9e1 Reviewed-by: hjk --- src/libs/utils/layoutbuilder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 251569fdd23..226120b823d 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -613,12 +613,12 @@ Application::Application(std::initializer_list items) int Application::exec(int &argc, char *argv[]) { - auto app = new QApplication(argc, argv); + QApplication app(argc, argv); LayoutBuilder builder; addItemHelper(builder, *this); if (QWidget *widget = builder.stack.last().widget) widget->show(); - return app->exec(); + return app.exec(); } // "Properties" From 9c31267e58625ba804379e32a167985f1ed00763 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 5 May 2023 12:33:31 +0200 Subject: [PATCH 0934/1447] Remove ineffective resize() calls This removes apparently unnecessary resize() calls on QWidgets based forms which get anyways added to layouts and resized. Most of these size values looked "accidental", i.e. neither divisible by 2 nor by 5, in most cases a remnant from the ui inlining. Change-Id: I95da3b93f2915ef955b5235e5c2ecc94b51f813a Reviewed-by: Reviewed-by: hjk --- src/libs/utils/filewizardpage.cpp | 1 - src/libs/utils/projectintropage.cpp | 1 - src/plugins/autotest/testsettingspage.cpp | 2 -- .../beautifier/artisticstyle/artisticstyleoptionspage.cpp | 2 -- src/plugins/beautifier/configurationpanel.cpp | 2 -- src/plugins/beautifier/generaloptionspage.cpp | 2 -- src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp | 2 -- src/plugins/clangformat/clangformatconfigwidget.cpp | 1 - src/plugins/clangformat/clangformatglobalconfigwidget.cpp | 2 -- src/plugins/clangtools/runsettingswidget.cpp | 2 -- src/plugins/clangtools/settingswidget.cpp | 2 -- src/plugins/clearcase/settingspage.cpp | 2 -- src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp | 2 -- src/plugins/git/gitsubmiteditorwidget.cpp | 2 -- src/plugins/ios/iossettingswidget.cpp | 1 - src/plugins/perforce/perforcesubmiteditorwidget.cpp | 1 - src/plugins/qmakeprojectmanager/addlibrarywizard.cpp | 1 - src/plugins/qtsupport/codegensettingspage.cpp | 2 -- src/plugins/qtsupport/qtoptionspage.cpp | 2 -- .../remotelinux/genericlinuxdeviceconfigurationwidget.cpp | 2 -- src/plugins/squish/squishwizardpages.cpp | 3 --- src/plugins/texteditor/behaviorsettingswidget.cpp | 2 -- src/plugins/texteditor/codestyleselectorwidget.cpp | 2 -- src/plugins/texteditor/colorschemeedit.cpp | 1 - src/plugins/texteditor/completionsettingspage.cpp | 2 -- src/plugins/texteditor/displaysettingspage.cpp | 2 -- src/plugins/texteditor/fontsettingspage.cpp | 2 -- src/plugins/texteditor/highlightersettingspage.cpp | 1 - src/plugins/texteditor/tabsettingswidget.cpp | 1 - src/plugins/vcsbase/submiteditorwidget.cpp | 2 -- src/plugins/vcsbase/wizard/vcscommandpage.cpp | 1 - 31 files changed, 53 deletions(-) diff --git a/src/libs/utils/filewizardpage.cpp b/src/libs/utils/filewizardpage.cpp index aae79b1a497..cc1f83b6969 100644 --- a/src/libs/utils/filewizardpage.cpp +++ b/src/libs/utils/filewizardpage.cpp @@ -45,7 +45,6 @@ FileWizardPage::FileWizardPage(QWidget *parent) : d(new FileWizardPagePrivate) { setTitle(Tr::tr("Choose the Location")); - resize(368, 102); d->m_defaultSuffixLabel = new QLabel; d->m_nameLabel = new QLabel; diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp index 8df64b97f06..cb7018943d1 100644 --- a/src/libs/utils/projectintropage.cpp +++ b/src/libs/utils/projectintropage.cpp @@ -66,7 +66,6 @@ ProjectIntroPage::ProjectIntroPage(QWidget *parent) : WizardPage(parent), d(new ProjectIntroPagePrivate) { - resize(355, 289); setTitle(Tr::tr("Introduction and Project Location")); d->m_descriptionLabel = new QLabel(this); diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp index 6ba73675f7a..e07fdc51f79 100644 --- a/src/plugins/autotest/testsettingspage.cpp +++ b/src/plugins/autotest/testsettingspage.cpp @@ -69,8 +69,6 @@ private: TestSettingsWidget::TestSettingsWidget(TestSettings *settings) : m_settings(settings) { - resize(586, 469); - m_omitInternalMsgCB = new QCheckBox(Tr::tr("Omit internal messages")); m_omitInternalMsgCB->setChecked(true); m_omitInternalMsgCB->setToolTip(Tr::tr("Hides internal messages by default. " diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp index f13c764edde..e34fe18349d 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp @@ -45,8 +45,6 @@ private: ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSettings *settings) : m_settings(settings) { - resize(817, 631); - m_command = new Utils::PathChooser; m_mime = new QLineEdit(m_settings->supportedMimeTypesAsString()); diff --git a/src/plugins/beautifier/configurationpanel.cpp b/src/plugins/beautifier/configurationpanel.cpp index eae33d5ff99..fa0fca71393 100644 --- a/src/plugins/beautifier/configurationpanel.cpp +++ b/src/plugins/beautifier/configurationpanel.cpp @@ -17,8 +17,6 @@ namespace Beautifier::Internal { ConfigurationPanel::ConfigurationPanel(QWidget *parent) : QWidget(parent) { - resize(595, 23); - m_configurations = new QComboBox; m_configurations->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); diff --git a/src/plugins/beautifier/generaloptionspage.cpp b/src/plugins/beautifier/generaloptionspage.cpp index be10d126fbb..5e03499a99e 100644 --- a/src/plugins/beautifier/generaloptionspage.cpp +++ b/src/plugins/beautifier/generaloptionspage.cpp @@ -33,8 +33,6 @@ private: GeneralOptionsPageWidget::GeneralOptionsPageWidget(const QStringList &toolIds) { - resize(817, 631); - auto settings = GeneralSettings::instance(); m_autoFormat = new QCheckBox(Tr::tr("Enable auto format on file save")); diff --git a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp index 433f52506b5..8da74a71973 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp @@ -45,8 +45,6 @@ private: UncrustifyOptionsPageWidget::UncrustifyOptionsPageWidget(UncrustifySettings *settings) : m_settings(settings) { - resize(817, 631); - m_command = new Utils::PathChooser; m_mime = new QLineEdit(m_settings->supportedMimeTypesAsString()); diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index 12e02b4fa74..ae914a39430 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -82,7 +82,6 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(TextEditor::ICodeStylePreferenc d->project = project; d->config = std::make_unique(filePathToCurrentSettings(codeStyle->currentPreferences())); - resize(489, 305); d->fallbackConfig = new QLabel(Tr::tr("Clang-Format Style")); d->checksScrollArea = new QScrollArea(); d->checksWidget = new ClangFormatChecks(); diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index 95cac0d3bca..2b4b0028471 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -31,8 +31,6 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget( , m_project(project) , m_codeStyle(codeStyle) { - resize(489, 305); - m_projectHasClangFormat = new QLabel(this); m_formattingModeLabel = new QLabel(Tr::tr("Formatting mode:")); m_indentingOrFormatting = new QComboBox(this); diff --git a/src/plugins/clangtools/runsettingswidget.cpp b/src/plugins/clangtools/runsettingswidget.cpp index 4581082c0fe..cd0dc6a1ee3 100644 --- a/src/plugins/clangtools/runsettingswidget.cpp +++ b/src/plugins/clangtools/runsettingswidget.cpp @@ -28,8 +28,6 @@ namespace ClangTools::Internal { RunSettingsWidget::RunSettingsWidget(QWidget *parent) : QWidget(parent) { - resize(383, 125); - m_diagnosticWidget = new ClangDiagnosticConfigsSelectionWidget; m_preferConfigFile = new QCheckBox(Tr::tr("Prefer .clang-tidy file, if present")); m_buildBeforeAnalysis = new QCheckBox(Tr::tr("Build the project before analysis")); diff --git a/src/plugins/clangtools/settingswidget.cpp b/src/plugins/clangtools/settingswidget.cpp index 41b4807570a..80aad561b07 100644 --- a/src/plugins/clangtools/settingswidget.cpp +++ b/src/plugins/clangtools/settingswidget.cpp @@ -34,8 +34,6 @@ SettingsWidget::SettingsWidget() { m_instance = this; - resize(400, 300); - auto createPathChooser = [this](ClangToolType tool) { const QString placeHolderText = toolShippedExecutable(tool).toUserOutput(); diff --git a/src/plugins/clearcase/settingspage.cpp b/src/plugins/clearcase/settingspage.cpp index 0489340865e..1ff8e48264d 100644 --- a/src/plugins/clearcase/settingspage.cpp +++ b/src/plugins/clearcase/settingspage.cpp @@ -50,8 +50,6 @@ private: SettingsPageWidget::SettingsPageWidget() { - resize(512, 589); - commandPathChooser = new PathChooser; commandPathChooser->setPromptDialogTitle(Tr::tr("ClearCase Command")); commandPathChooser->setExpectedKind(PathChooser::ExistingCommand); diff --git a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp b/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp index 8fe970404e9..2e089469910 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp @@ -35,8 +35,6 @@ private: CMakeFormatterOptionsPageWidget::CMakeFormatterOptionsPageWidget() { - resize(817, 631); - auto settings = CMakeFormatterSettings::instance(); m_autoFormat = new QCheckBox(Tr::tr("Enable auto format on file save")); diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp index 946fc6f77c7..ec09437e266 100644 --- a/src/plugins/git/gitsubmiteditorwidget.cpp +++ b/src/plugins/git/gitsubmiteditorwidget.cpp @@ -36,8 +36,6 @@ class GitSubmitPanel : public QWidget public: GitSubmitPanel() { - resize(364, 269); - repositoryLabel = new QLabel(Tr::tr("repository")); branchLabel = new QLabel(Tr::tr("branch")); // FIXME: Isn't this overwritten soon? showHeadLabel = new QLabel("" + Tr::tr("Show HEAD") + ""); diff --git a/src/plugins/ios/iossettingswidget.cpp b/src/plugins/ios/iossettingswidget.cpp index ce1279cb0f1..bb0bc36d61a 100644 --- a/src/plugins/ios/iossettingswidget.cpp +++ b/src/plugins/ios/iossettingswidget.cpp @@ -51,7 +51,6 @@ static void onSimOperation(const SimulatorInfo &simInfo, SimulatorOperationDialo IosSettingsWidget::IosSettingsWidget() { - resize(622, 456); setWindowTitle(Tr::tr("iOS Configuration")); m_deviceAskCheckBox = new QCheckBox(Tr::tr("Ask about devices not in developer mode")); diff --git a/src/plugins/perforce/perforcesubmiteditorwidget.cpp b/src/plugins/perforce/perforcesubmiteditorwidget.cpp index ddf4f1feb14..6887472822e 100644 --- a/src/plugins/perforce/perforcesubmiteditorwidget.cpp +++ b/src/plugins/perforce/perforcesubmiteditorwidget.cpp @@ -22,7 +22,6 @@ public: , m_clientName(createLabel()) , m_userName(createLabel()) { - resize(402, 134); setFlat(true); setTitle(Tr::tr("Submit")); diff --git a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp index ebf266d701b..ff74701cf71 100644 --- a/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp +++ b/src/plugins/qmakeprojectmanager/addlibrarywizard.cpp @@ -178,7 +178,6 @@ DetailsPage::DetailsPage(AddLibraryWizard *parent) : QWizardPage(parent), m_libraryWizard(parent) { m_libraryDetailsWidget = new LibraryDetailsWidget(this); - resize(456, 438); PathChooser * const libPathChooser = m_libraryDetailsWidget->libraryPathChooser; libPathChooser->setHistoryCompleter("Qmake.LibDir.History"); diff --git a/src/plugins/qtsupport/codegensettingspage.cpp b/src/plugins/qtsupport/codegensettingspage.cpp index 99d6a6976ca..4a30e5f969f 100644 --- a/src/plugins/qtsupport/codegensettingspage.cpp +++ b/src/plugins/qtsupport/codegensettingspage.cpp @@ -39,8 +39,6 @@ private: CodeGenSettingsPageWidget::CodeGenSettingsPageWidget() { - resize(340, 232); - CodeGenSettings parameters; parameters.fromSettings(Core::ICore::settings()); diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 5f33e269860..92b439ea1a2 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -232,8 +232,6 @@ QtOptionsPageWidget::QtOptionsPageWidget() , m_warningVersionIcon(Utils::Icons::WARNING.icon()) , m_configurationWidget(nullptr) { - resize(446, 450); - m_qtdirList = new QTreeView(this); m_qtdirList->setObjectName("qtDirList"); m_qtdirList->setUniformRowHeights(true); diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index d0c7cc1edc4..ae85284ccb1 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -35,8 +35,6 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( const IDevice::Ptr &device) : IDeviceWidget(device) { - resize(556, 309); - m_defaultAuthButton = new QRadioButton(Tr::tr("Default"), this); m_keyButton = new QRadioButton(Tr::tr("Specific &key")); diff --git a/src/plugins/squish/squishwizardpages.cpp b/src/plugins/squish/squishwizardpages.cpp index 118c3217f2d..e55a6ee8b2a 100644 --- a/src/plugins/squish/squishwizardpages.cpp +++ b/src/plugins/squish/squishwizardpages.cpp @@ -48,7 +48,6 @@ bool SquishToolkitsPageFactory::validateData(Utils::Id typeId, const QVariant &, SquishToolkitsPage::SquishToolkitsPage() { - resize(400, 300); setTitle(Tr::tr("Create New Squish Test Suite")); auto layout = new QVBoxLayout(this); @@ -173,7 +172,6 @@ bool SquishScriptLanguagePageFactory::validateData(Utils::Id typeId, const QVari SquishScriptLanguagePage::SquishScriptLanguagePage() { - resize(400, 300); setTitle(Tr::tr("Create New Squish Test Suite")); auto layout = new QHBoxLayout(this); @@ -229,7 +227,6 @@ bool SquishAUTPageFactory::validateData(Utils::Id typeId, const QVariant &, QStr SquishAUTPage::SquishAUTPage() { - resize(400, 300); auto layout = new QVBoxLayout(this); m_autCombo = new QComboBox(this); layout->addWidget(m_autCombo); diff --git a/src/plugins/texteditor/behaviorsettingswidget.cpp b/src/plugins/texteditor/behaviorsettingswidget.cpp index 99796877a5a..144afa6eb23 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.cpp +++ b/src/plugins/texteditor/behaviorsettingswidget.cpp @@ -65,8 +65,6 @@ BehaviorSettingsWidget::BehaviorSettingsWidget(QWidget *parent) : QWidget(parent) , d(new BehaviorSettingsWidgetPrivate) { - resize(801, 693); - d->tabPreferencesWidget = new SimpleCodeStylePreferencesWidget(this); d->tabPreferencesWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // FIXME: Desirable? diff --git a/src/plugins/texteditor/codestyleselectorwidget.cpp b/src/plugins/texteditor/codestyleselectorwidget.cpp index 791f9e488af..2b21fd12c31 100644 --- a/src/plugins/texteditor/codestyleselectorwidget.cpp +++ b/src/plugins/texteditor/codestyleselectorwidget.cpp @@ -33,8 +33,6 @@ CodeStyleSelectorWidget::CodeStyleSelectorWidget(ICodeStylePreferencesFactory *f , m_factory(factory) , m_project(project) { - resize(536, 59); - m_delegateComboBox = new QComboBox(this); m_delegateComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); diff --git a/src/plugins/texteditor/colorschemeedit.cpp b/src/plugins/texteditor/colorschemeedit.cpp index d6f93888ddc..c6f661df429 100644 --- a/src/plugins/texteditor/colorschemeedit.cpp +++ b/src/plugins/texteditor/colorschemeedit.cpp @@ -121,7 +121,6 @@ ColorSchemeEdit::ColorSchemeEdit(QWidget *parent) : m_formatsModel(new FormatsModel(this)) { setContentsMargins(0, layoutSpacing, 0, 0); - resize(513, 416); auto colorButton = [] () { auto tb = new Utils::QtColorButton; diff --git a/src/plugins/texteditor/completionsettingspage.cpp b/src/plugins/texteditor/completionsettingspage.cpp index 6187688e4e9..167cde25a75 100644 --- a/src/plugins/texteditor/completionsettingspage.cpp +++ b/src/plugins/texteditor/completionsettingspage.cpp @@ -66,8 +66,6 @@ private: CompletionSettingsPageWidget::CompletionSettingsPageWidget(CompletionSettingsPage *owner) : m_owner(owner) { - resize(823, 756); - m_caseSensitivity = new QComboBox; m_caseSensitivity->addItem(Tr::tr("Full")); m_caseSensitivity->addItem(Tr::tr("None")); diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index 7101004bca8..2449618bf05 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -44,8 +44,6 @@ public: DisplaySettingsWidget(DisplaySettingsPagePrivate *data) : m_data(data) { - resize(452, 458); - enableTextWrapping = new QCheckBox(Tr::tr("Enable text &wrapping")); enableTextWrappingHintLabel = new QLabel(Tr::tr("Set font line spacing " diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp index 9802ba19a55..b57e23f35b8 100644 --- a/src/plugins/texteditor/fontsettingspage.cpp +++ b/src/plugins/texteditor/fontsettingspage.cpp @@ -107,8 +107,6 @@ public: { m_lastValue = m_value; - resize(639, 306); - m_antialias = new QCheckBox(Tr::tr("Antialias")); m_antialias->setChecked(m_value.antialias()); diff --git a/src/plugins/texteditor/highlightersettingspage.cpp b/src/plugins/texteditor/highlightersettingspage.cpp index ac10982de3d..4cc16a488a6 100644 --- a/src/plugins/texteditor/highlightersettingspage.cpp +++ b/src/plugins/texteditor/highlightersettingspage.cpp @@ -65,7 +65,6 @@ public: HighlighterSettingsPageWidget(HighlighterSettingsPagePrivate *d) : d(d) { d->ensureInitialized(); - resize(521, 332); auto definitionsInfolabel = new QLabel(this); definitionsInfolabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); diff --git a/src/plugins/texteditor/tabsettingswidget.cpp b/src/plugins/texteditor/tabsettingswidget.cpp index d8096102488..f3476ec5f42 100644 --- a/src/plugins/texteditor/tabsettingswidget.cpp +++ b/src/plugins/texteditor/tabsettingswidget.cpp @@ -50,7 +50,6 @@ QString continuationTooltip() TabSettingsWidget::TabSettingsWidget(QWidget *parent) : QGroupBox(parent) { - resize(254, 189); setTitle(Tr::tr("Tabs And Indentation")); m_codingStyleWarning = new QLabel( diff --git a/src/plugins/vcsbase/submiteditorwidget.cpp b/src/plugins/vcsbase/submiteditorwidget.cpp index 376c7feceae..63a75e7ac06 100644 --- a/src/plugins/vcsbase/submiteditorwidget.cpp +++ b/src/plugins/vcsbase/submiteditorwidget.cpp @@ -127,8 +127,6 @@ struct SubmitEditorWidgetPrivate SubmitEditorWidget::SubmitEditorWidget() : d(new SubmitEditorWidgetPrivate) { - resize(507, 419); - setMinimumSize(QSize(0, 0)); setWindowTitle(Tr::tr("Subversion Submit")); auto scrollAreaWidgetContents = new QWidget(); diff --git a/src/plugins/vcsbase/wizard/vcscommandpage.cpp b/src/plugins/vcsbase/wizard/vcscommandpage.cpp index 1fef5540f40..0877e3ffbea 100644 --- a/src/plugins/vcsbase/wizard/vcscommandpage.cpp +++ b/src/plugins/vcsbase/wizard/vcscommandpage.cpp @@ -212,7 +212,6 @@ bool VcsCommandPageFactory::validateData(Id typeId, const QVariant &data, QStrin VcsCommandPage::VcsCommandPage() : m_startedStatus(Tr::tr("Command started...")) { - resize(264, 200); auto verticalLayout = new QVBoxLayout(this); m_logPlainTextEdit = new QPlainTextEdit; m_formatter = new OutputFormatter; From e9c3fcf342eabfcc4680809bd463577595060ff4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 18:40:46 +0200 Subject: [PATCH 0935/1447] Locator tests: Remove tests for old matchesFor implementation Change-Id: I0d0293cc248dc4208cf5d50de468ccf94b4bb960 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../coreplugin/locator/locator_test.cpp | 26 +--- .../coreplugin/locator/locatorfiltertest.cpp | 41 ----- .../coreplugin/locator/locatorfiltertest.h | 16 -- .../cppeditor/cpplocatorfilter_test.cpp | 145 ++++-------------- 4 files changed, 31 insertions(+), 197 deletions(-) diff --git a/src/plugins/coreplugin/locator/locator_test.cpp b/src/plugins/coreplugin/locator/locator_test.cpp index 806e5274446..c83a2d8779c 100644 --- a/src/plugins/coreplugin/locator/locator_test.cpp +++ b/src/plugins/coreplugin/locator/locator_test.cpp @@ -3,16 +3,13 @@ #include "../coreplugin.h" -#include "basefilefilter.h" #include "locatorfiltertest.h" #include #include -#include #include #include -#include #include using namespace Core::Tests; @@ -22,15 +19,6 @@ namespace { QTC_DECLARE_MYTESTDATADIR("../../../tests/locators/") -class MyBaseFileFilter : public Core::BaseFileFilter -{ -public: - MyBaseFileFilter(const FilePaths &theFiles) - { - setFileIterator(new BaseFileFilter::ListIterator(theFiles)); - } -}; - class ReferenceData { public: @@ -52,20 +40,8 @@ void Core::Internal::CorePlugin::test_basefilefilter() QFETCH(QStringList, testFiles); QFETCH(QList, referenceDataList); - const FilePaths filePaths = FileUtils::toFilePathList(testFiles); - MyBaseFileFilter filter(filePaths); - BasicLocatorFilterTest test(&filter); - - for (const ReferenceData &reference : std::as_const(referenceDataList)) { - const QList filterEntries = test.matchesFor(reference.searchText); - const ResultDataList results = ResultData::fromFilterEntryList(filterEntries); -// QTextStream(stdout) << "----" << endl; -// ResultData::printFilterEntries(results); - QCOMPARE(results, reference.results); - } - LocatorFileCache cache; - cache.setFilePaths(filePaths); + cache.setFilePaths(FileUtils::toFilePathList(testFiles)); const LocatorMatcherTasks tasks = {cache.matcher()}; for (const ReferenceData &reference : std::as_const(referenceDataList)) { const LocatorFilterEntries filterEntries = LocatorMatcher::runBlocking( diff --git a/src/plugins/coreplugin/locator/locatorfiltertest.cpp b/src/plugins/coreplugin/locator/locatorfiltertest.cpp index c134db16696..2a901f8669e 100644 --- a/src/plugins/coreplugin/locator/locatorfiltertest.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltertest.cpp @@ -3,52 +3,11 @@ #include "locatorfiltertest.h" -#include "locatorsearchutils.h" - -#include - -#include -#include -#include #include using namespace Core; using namespace Core::Tests; -/*! - \class Core::Tests::BasicLocatorFilterTest - \inmodule QtCreator - \internal -*/ - -/*! - \class Core::Tests::TestDataDir - \inmodule QtCreator - \internal -*/ - -/*! - \namespace Core::Tests - \inmodule QtCreator - \internal -*/ -BasicLocatorFilterTest::BasicLocatorFilterTest(ILocatorFilter *filter) : m_filter(filter) -{ -} - -BasicLocatorFilterTest::~BasicLocatorFilterTest() = default; - -QList BasicLocatorFilterTest::matchesFor(const QString &searchText) -{ - doBeforeLocatorRun(); - m_filter->prepareSearch(searchText); - QFuture locatorSearch = Utils::runAsync( - &Internal::runSearch, QList({m_filter}), searchText); - locatorSearch.waitForFinished(); - doAfterLocatorRun(); - return locatorSearch.results(); -} - /*! \class Core::Tests::ResultData \inmodule QtCreator diff --git a/src/plugins/coreplugin/locator/locatorfiltertest.h b/src/plugins/coreplugin/locator/locatorfiltertest.h index f6d5d595011..5003f1e9ff0 100644 --- a/src/plugins/coreplugin/locator/locatorfiltertest.h +++ b/src/plugins/coreplugin/locator/locatorfiltertest.h @@ -10,22 +10,6 @@ namespace Core { namespace Tests { -/// Runs a locator filter for a search text and returns the results. -class CORE_EXPORT BasicLocatorFilterTest -{ -public: - BasicLocatorFilterTest(ILocatorFilter *filter); - virtual ~BasicLocatorFilterTest(); - - QList matchesFor(const QString &searchText = QString()); - -private: - virtual void doBeforeLocatorRun() {} - virtual void doAfterLocatorRun() {} - - ILocatorFilter *m_filter = nullptr; -}; - class CORE_EXPORT ResultData { public: diff --git a/src/plugins/cppeditor/cpplocatorfilter_test.cpp b/src/plugins/cppeditor/cpplocatorfilter_test.cpp index 7edb0c9d50e..18e9b933cbe 100644 --- a/src/plugins/cppeditor/cpplocatorfilter_test.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter_test.cpp @@ -3,15 +3,12 @@ #include "cpplocatorfilter_test.h" -#include "cppmodelmanager.h" #include "cpptoolstestcase.h" #include #include #include -#include #include -#include #include #include @@ -19,7 +16,6 @@ using namespace Core; using namespace Core::Tests; -using namespace ExtensionSystem; using namespace Utils; namespace CppEditor::Internal { @@ -29,31 +25,21 @@ const bool debug = qtcEnvironmentVariable("QTC_DEBUG_CPPLOCATORFILTERTESTCASE") QTC_DECLARE_MYTESTDATADIR("../../../tests/cpplocators/") -class CppLocatorFilterTestCase - : public BasicLocatorFilterTest - , public CppEditor::Tests::TestCase +class CppLocatorFilterTestCase : public CppEditor::Tests::TestCase { public: - CppLocatorFilterTestCase(ILocatorFilter *filter, - const QList &matchers, + CppLocatorFilterTestCase(const QList &matchers, const QString &fileName, const QString &searchText, const ResultDataList &expectedResults) - : BasicLocatorFilterTest(filter) - , m_fileName(fileName) { QVERIFY(succeededSoFar()); - QVERIFY(!m_fileName.isEmpty()); + QVERIFY(!fileName.isEmpty()); QVERIFY(garbageCollectGlobalSnapshot()); - const auto runMatcher = [this, matchers, searchText] { - CppLocatorFilterTestCase::doBeforeLocatorRun(); - const auto result = LocatorMatcher::runBlocking(matchers, searchText); - CppLocatorFilterTestCase::doAfterLocatorRun(); - return result; - }; - - const LocatorFilterEntries entries = filter ? matchesFor(searchText) : runMatcher(); + QVERIFY(parseFiles(fileName)); + const LocatorFilterEntries entries = LocatorMatcher::runBlocking(matchers, searchText); + QVERIFY(garbageCollectGlobalSnapshot()); const ResultDataList results = ResultData::fromFilterEntryList(entries); if (debug) { ResultData::printFilterEntries(expectedResults, "Expected:"); @@ -62,40 +48,32 @@ public: QVERIFY(!results.isEmpty()); QCOMPARE(results, expectedResults); } - -private: - void doBeforeLocatorRun() override { QVERIFY(parseFiles(m_fileName)); } - void doAfterLocatorRun() override { QVERIFY(garbageCollectGlobalSnapshot()); } - -private: - const QString m_fileName; }; -class CppCurrentDocumentFilterTestCase - : public BasicLocatorFilterTest - , public CppEditor::Tests::TestCase +class CppCurrentDocumentFilterTestCase : public CppEditor::Tests::TestCase { public: CppCurrentDocumentFilterTestCase(const FilePath &filePath, const QList &matchers, const ResultDataList &expectedResults, const QString &searchText = QString()) - : BasicLocatorFilterTest(CppModelManager::instance()->currentDocumentFilter()) - , m_filePath(filePath) { QVERIFY(succeededSoFar()); - QVERIFY(!m_filePath.isEmpty()); + QVERIFY(!filePath.isEmpty()); - const auto runMatcher = [this, matchers, searchText] { - CppCurrentDocumentFilterTestCase::doBeforeLocatorRun(); - const auto result = LocatorMatcher::runBlocking(matchers, searchText); - CppCurrentDocumentFilterTestCase::doAfterLocatorRun(); - return result; - }; + QVERIFY(DocumentModel::openedDocuments().isEmpty()); + QVERIFY(garbageCollectGlobalSnapshot()); - const LocatorFilterEntries entries = matchers.isEmpty() ? matchesFor(searchText) - : runMatcher(); - ResultDataList results = ResultData::fromFilterEntryList(entries); + const auto editor = EditorManager::openEditor(filePath); + QVERIFY(editor); + + QVERIFY(waitForFileInGlobalSnapshot(filePath)); + const LocatorFilterEntries entries = LocatorMatcher::runBlocking(matchers, searchText); + QVERIFY(closeEditorWithoutGarbageCollectorInvocation(editor)); + QCoreApplication::processEvents(); + QVERIFY(DocumentModel::openedDocuments().isEmpty()); + QVERIFY(garbageCollectGlobalSnapshot()); + const ResultDataList results = ResultData::fromFilterEntryList(entries); if (debug) { ResultData::printFilterEntries(expectedResults, "Expected:"); ResultData::printFilterEntries(results, "Results:"); @@ -103,69 +81,29 @@ public: QVERIFY(!results.isEmpty()); QCOMPARE(results, expectedResults); } - -private: - void doBeforeLocatorRun() override - { - QVERIFY(DocumentModel::openedDocuments().isEmpty()); - QVERIFY(garbageCollectGlobalSnapshot()); - - m_editor = EditorManager::openEditor(m_filePath); - QVERIFY(m_editor); - - QVERIFY(waitForFileInGlobalSnapshot(m_filePath)); - } - - void doAfterLocatorRun() override - { - QVERIFY(closeEditorWithoutGarbageCollectorInvocation(m_editor)); - QCoreApplication::processEvents(); - QVERIFY(DocumentModel::openedDocuments().isEmpty()); - QVERIFY(garbageCollectGlobalSnapshot()); - } - -private: - IEditor *m_editor = nullptr; - const FilePath m_filePath; }; } // anonymous namespace -using MatcherCreator = std::function()>; - void LocatorFilterTest::testLocatorFilter() { QFETCH(QString, testFile); - QFETCH(ILocatorFilter *, filter); QFETCH(MatcherType, matcherType); QFETCH(QString, searchText); QFETCH(ResultDataList, expectedResults); - { - Tests::VerifyCleanCppModelManager verify; - CppLocatorFilterTestCase(filter, {}, testFile, searchText, expectedResults); - } - - { - Tests::VerifyCleanCppModelManager verify; - CppLocatorFilterTestCase(nullptr, LocatorMatcher::matchers(matcherType), testFile, - searchText, expectedResults); - } + Tests::VerifyCleanCppModelManager verify; + CppLocatorFilterTestCase(LocatorMatcher::matchers(matcherType), testFile, searchText, + expectedResults); } void LocatorFilterTest::testLocatorFilter_data() { QTest::addColumn("testFile"); - QTest::addColumn("filter"); QTest::addColumn("matcherType"); QTest::addColumn("searchText"); QTest::addColumn("expectedResults"); - CppModelManager *cppModelManager = CppModelManager::instance(); - ILocatorFilter *cppFunctionsFilter = cppModelManager->functionsFilter(); - ILocatorFilter *cppClassesFilter = cppModelManager->classesFilter(); - ILocatorFilter *cppLocatorFilter = cppModelManager->locatorFilter(); - MyTestDataDir testDirectory("testdata_basic"); QString testFile = testDirectory.file("file1.cpp"); testFile[0] = testFile[0].toLower(); // Ensure Windows path sorts after scope names. @@ -175,7 +113,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter") << testFile - << cppFunctionsFilter << MatcherType::Functions << "function" << ResultDataList{ @@ -198,7 +135,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-Sorting") << testFile - << cppFunctionsFilter << MatcherType::Functions << "pos" << ResultDataList{ @@ -210,7 +146,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-arguments") << testFile - << cppFunctionsFilter << MatcherType::Functions << "function*bool" << ResultDataList{ @@ -227,7 +162,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-WithNamespacePrefix") << testFile - << cppFunctionsFilter << MatcherType::Functions << "mynamespace::" << ResultDataList{ @@ -243,7 +177,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-WithClassPrefix") << testFile - << cppFunctionsFilter << MatcherType::Functions << "MyClass::func" << ResultDataList{ @@ -265,7 +198,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter") << testFile - << cppClassesFilter << MatcherType::Classes << "myclass" << ResultDataList{ @@ -276,7 +208,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter-WithNamespacePrefix") << testFile - << cppClassesFilter << MatcherType::Classes << "mynamespace::" << ResultDataList{ @@ -286,7 +217,6 @@ void LocatorFilterTest::testLocatorFilter_data() // all symbols in the left column are expected to be fully qualified. QTest::newRow("CppLocatorFilter-filtered") << testFile - << cppLocatorFilter << MatcherType::AllSymbols << "my" << ResultDataList{ @@ -313,7 +243,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppClassesFilter-ObjC") << objTestFile - << cppClassesFilter << MatcherType::Classes << "M" << ResultDataList{ @@ -325,7 +254,6 @@ void LocatorFilterTest::testLocatorFilter_data() QTest::newRow("CppFunctionsFilter-ObjC") << objTestFile - << cppFunctionsFilter << MatcherType::Functions << "M" << ResultDataList{ @@ -381,10 +309,9 @@ void LocatorFilterTest::testCurrentDocumentFilter() ResultData("main()", ""), }; - CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults); - CppCurrentDocumentFilterTestCase(testFile, - LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols), - expectedResults); + Tests::VerifyCleanCppModelManager verify; + CppCurrentDocumentFilterTestCase( + testFile, LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols), expectedResults); } void LocatorFilterTest::testCurrentDocumentHighlighting() @@ -407,11 +334,8 @@ void LocatorFilterTest::testCurrentDocumentHighlighting() }; Tests::VerifyCleanCppModelManager verify; - - CppCurrentDocumentFilterTestCase(testFile, {}, expectedResults, searchText); CppCurrentDocumentFilterTestCase(testFile, - LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols), - expectedResults, searchText); + LocatorMatcher::matchers(MatcherType::CurrentDocumentSymbols), expectedResults, searchText); } void LocatorFilterTest::testFunctionsFilterHighlighting() @@ -432,18 +356,9 @@ void LocatorFilterTest::testFunctionsFilterHighlighting() " ~~~ ") }; - { - Tests::VerifyCleanCppModelManager verify; - CppModelManager *cppModelManager = CppModelManager::instance(); - ILocatorFilter *filter = cppModelManager->functionsFilter(); - CppLocatorFilterTestCase(filter, {}, testFile, searchText, expectedResults); - } - - { - Tests::VerifyCleanCppModelManager verify; - CppLocatorFilterTestCase(nullptr, LocatorMatcher::matchers(MatcherType::Functions), - testFile, searchText, expectedResults); - } + Tests::VerifyCleanCppModelManager verify; + CppLocatorFilterTestCase(LocatorMatcher::matchers(MatcherType::Functions), testFile, + searchText, expectedResults); } } // namespace CppEditor::Internal From 76d1973514561d8e0d93e98cfcbc19b266fa4eab Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 12:52:09 +0200 Subject: [PATCH 0936/1447] Adapt to upstream removal of IOptionPage's QObject base Change-Id: Id001ec22478ecb42c0506b4223c497d258c51e18 Reviewed-by: Christian Stenger --- plugins/axivion/axivionsettingspage.h | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h index 5d1fc9c8b8d..5dd52564800 100644 --- a/plugins/axivion/axivionsettingspage.h +++ b/plugins/axivion/axivionsettingspage.h @@ -42,7 +42,6 @@ private: class AxivionSettingsPage : public Core::IOptionsPage { - Q_OBJECT public: explicit AxivionSettingsPage(AxivionSettings *settings); From 5fa073543abaa67aa778c4c13d6eb4202e109a52 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 4 May 2023 14:14:43 +0200 Subject: [PATCH 0937/1447] Utils: Fix hasSuppressedQuestions QSettings::childKeys() only returns direct child values, not child groups. Therefore we also need to check QSettings::childGroups() here. We don't need to iterate all the keys. Keys are only created with "true" value. Change-Id: Ie4653dca1dfbad85ab895440a756c8e03aa78118 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/libs/utils/checkablemessagebox.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index 4420fc66cbc..5d3011ff597 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -443,15 +443,9 @@ void CheckableMessageBox::resetAllDoNotAskAgainQuestions(QSettings *settings) bool CheckableMessageBox::hasSuppressedQuestions(QSettings *settings) { QTC_ASSERT(settings, return false); - bool hasSuppressed = false; settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); - const QStringList childKeys = settings->childKeys(); - for (const QString &subKey : childKeys) { - if (settings->value(subKey, false).toBool()) { - hasSuppressed = true; - break; - } - } + const bool hasSuppressed = !settings->childKeys().isEmpty() + || !settings->childGroups().isEmpty(); settings->endGroup(); return hasSuppressed; } From 2628e0f82f892439a52a71f8e418f846eda09507 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 9 May 2023 09:28:57 +0200 Subject: [PATCH 0938/1447] SilverSearcher: Refactor the Silver Searcher parser This speeds up the parsing by ~20%. Change-Id: Ibddfa4e1162e1fcbeeda9e441bdb7e92db903f88 Reviewed-by: Qt CI Bot Reviewed-by: Przemyslaw Gorszkowski Reviewed-by: Orgad Shaneh --- .../findinfilessilversearcher.cpp | 10 +- .../silversearcher/outputparser_test.cpp | 3 +- .../silversearcheroutputparser.cpp | 221 ++++++++++-------- .../silversearcheroutputparser.h | 29 +-- 4 files changed, 130 insertions(+), 133 deletions(-) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index b6759aeaeff..52e9f08a956 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -110,17 +110,17 @@ void runSilverSeacher(QPromise &promise, FileFindParameters p process.setCommand({"ag", arguments}); process.start(); if (process.waitForFinished()) { - QRegularExpression regexp; + std::optional regExp; if (parameters.flags & FindRegularExpression) { + regExp = QRegularExpression(); const QRegularExpression::PatternOptions patternOptions = (parameters.flags & FindCaseSensitively) ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption; - regexp.setPattern(parameters.text); - regexp.setPatternOptions(patternOptions); + regExp->setPattern(parameters.text); + regExp->setPatternOptions(patternOptions); } - SilverSearcher::SilverSearcherOutputParser parser(process.cleanedStdOut(), regexp); - const SearchResultItems items = parser.parse(); + const SearchResultItems items = SilverSearcher::parse(process.cleanedStdOut(), regExp); if (!items.isEmpty()) promise.addResult(items); } else { diff --git a/src/plugins/silversearcher/outputparser_test.cpp b/src/plugins/silversearcher/outputparser_test.cpp index cdc587ce702..4aaacf37e68 100644 --- a/src/plugins/silversearcher/outputparser_test.cpp +++ b/src/plugins/silversearcher/outputparser_test.cpp @@ -60,8 +60,7 @@ void OutputParserTest::test() { QFETCH(QString, parserOutput); QFETCH(SearchResultItems, results); - SilverSearcher::SilverSearcherOutputParser ssop(parserOutput); - const SearchResultItems items = ssop.parse(); + const SearchResultItems items = SilverSearcher::parse(parserOutput); QCOMPARE(items, results); } diff --git a/src/plugins/silversearcher/silversearcheroutputparser.cpp b/src/plugins/silversearcher/silversearcheroutputparser.cpp index 20ce2473425..65d773d0c68 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.cpp +++ b/src/plugins/silversearcher/silversearcheroutputparser.cpp @@ -3,119 +3,140 @@ #include "silversearcheroutputparser.h" -#include +using namespace Utils; namespace SilverSearcher { -SilverSearcherOutputParser::SilverSearcherOutputParser( - const QString &output, const QRegularExpression ®exp) - : output(output) - , regexp(regexp) - , outputSize(output.size()) +/* +// Example output (searching for "ab"): + +:/home/jarek/dev/creator-master/src/libs/qmlpuppetcommunication/container/imagecontainer.cpp +149;60 2: static const bool dontUseSharedMemory = qEnvironmentVariableIsSet("DESIGNER_DONT_USE_SHARED_MEMORY"); +198;65 2: qCInfo(imageContainerDebug()) << Q_FUNC_INFO << "Not able to create image:" << imageWidth << imageHeight << imageFormat; + +:/home/jarek/dev/creator-master/src/libs/qmlpuppetcommunication/container/propertyabstractcontainer.cpp +4;18 2:#include "propertyabstractcontainer.h" +10;8 2,35 2:PropertyAbstractContainer::PropertyAbstractContainer() +*/ + +static QStringView nextLine(QStringView *remainingOutput) { - hasRegexp = !regexp.pattern().isEmpty(); + const int newLinePos = remainingOutput->indexOf('\n'); + if (newLinePos < 0) { + QStringView ret = *remainingOutput; + *remainingOutput = QStringView(); + return ret; + } + QStringView ret = remainingOutput->left(newLinePos); + *remainingOutput = remainingOutput->mid(newLinePos + 1); + return ret; } -Utils::SearchResultItems SilverSearcherOutputParser::parse() +static bool parseNumber(QStringView numberString, int *number) { - while (index < outputSize - 1) { - if (output[index] == '\n') { - ++index; + for (const auto &c : numberString) { + if (!c.isDigit()) + return false; + } + bool ok = false; + int parsedNumber = numberString.toInt(&ok); + if (ok) + *number = parsedNumber; + return ok; +} + +static bool parseLineNumber(QStringView *remainingOutput, int *lineNumber) +{ + const int lineNumberDelimiterPos = remainingOutput->indexOf(';'); + if (lineNumberDelimiterPos < 0) + return false; + + if (!parseNumber(remainingOutput->left(lineNumberDelimiterPos), lineNumber)) + return false; + + *remainingOutput = remainingOutput->mid(lineNumberDelimiterPos + 1); + return true; +} + +static bool parseLineHit(QStringView hitString, QPair *hit) +{ + const int hitSpaceDelimiterPos = hitString.indexOf(' '); + if (hitSpaceDelimiterPos < 0) + return false; + + int hitStart = -1; + if (!parseNumber(hitString.left(hitSpaceDelimiterPos), &hitStart)) + return false; + + int hitLength = -1; + if (!parseNumber(hitString.mid(hitSpaceDelimiterPos + 1), &hitLength)) + return false; + + *hit = {hitStart, hitLength}; + return true; +} + +static bool parseLineHits(QStringView *remainingOutput, QList> *hits) +{ + const int hitsDelimiterPos = remainingOutput->indexOf(':'); + if (hitsDelimiterPos < 0) + return false; + + const QStringView hitsString = remainingOutput->left(hitsDelimiterPos); + const QList hitStrings = hitsString.split(',', Qt::SkipEmptyParts); + for (const auto hitString : hitStrings) { + QPair hit; + if (!parseLineHit(hitString, &hit)) + return false; + hits->append(hit); + } + *remainingOutput = remainingOutput->mid(hitsDelimiterPos + 1); + return true; +} + +SearchResultItems parse(const QString &output, const std::optional ®Exp) +{ + SearchResultItems items; + + QStringView remainingOutput(output); + while (true) { + if (remainingOutput.isEmpty()) + break; + + const QStringView filePathLine = nextLine(&remainingOutput); + if (filePathLine.isEmpty()) continue; - } - parseFilePath(); - while (index < outputSize && output[index] != '\n') { - const int lineNumber = parseLineNumber(); - if (index >= outputSize - 1) + + if (!filePathLine.startsWith(':')) + continue; + + const FilePath filePath = FilePath::fromPathPart(filePathLine.mid(1)); + + QStringView hitLine = nextLine(&remainingOutput); + while (!hitLine.isEmpty()) { + int lineNumber = -1; + if (!parseLineNumber(&hitLine, &lineNumber)) break; - int matches = parseMatches(lineNumber); - if (index >= outputSize - 1) + + // List of pairs + QList> hits; + if (!parseLineHits(&hitLine, &hits)) break; - parseText(); - for (int i = 0; i < matches; ++i) - items[items.size() - i - 1].setDisplayText(item.lineText()); + + SearchResultItem item; + item.setFilePath(filePath); + item.setDisplayText(hitLine.toString()); + for (const QPair &hit : hits) { + item.setMainRange(lineNumber, hit.first, hit.second); + item.setUserData( + regExp ? regExp->match(hitLine.mid(hit.first, hit.second)).capturedTexts() + : QVariant()); + items.append(item); + } + hitLine = nextLine(&remainingOutput); } } - return items; } -bool SilverSearcherOutputParser::parseFilePath() -{ - int startIndex = ++index; - while (index < outputSize && output[index] != '\n') - ++index; - item.setFilePath(Utils::FilePath::fromString(QString(output.data() + startIndex, - index - startIndex))); - ++index; - return true; -} - -int SilverSearcherOutputParser::parseLineNumber() -{ - int startIndex = index; - while (index < outputSize && output[++index] != ';') { } - - const int lineNumber = QString(output.data() + startIndex, index - startIndex).toInt(); - ++index; - return lineNumber; -} - -int SilverSearcherOutputParser::parseMatchIndex() -{ - int startIndex = index; - while (index < outputSize && output[++index] != ' ') { } - - const int lineStart = QString(output.data() + startIndex, index - startIndex).toInt(); - ++index; - return lineStart; -} - -int SilverSearcherOutputParser::parseMatchLength() -{ - int startIndex = index; - while (index < outputSize && output[++index] != ':' && output[index] != ',') { } - - return QString(output.data() + startIndex, index - startIndex).toInt(); -} - -int SilverSearcherOutputParser::parseMatches(int lineNumber) -{ - int matches = 1; - const int colon = output.indexOf(':', index); - QString text; - if (colon != -1) { - const int textStart = colon + 1; - const int newline = output.indexOf('\n', textStart); - text = output.mid(textStart, newline >= 0 ? newline - textStart : -1); - } - while (index < outputSize && output[index] != ':') { - if (output[index] == ',') { - ++matches; - ++index; - } - const int lineStart = parseMatchIndex(); - const int lineLength = parseMatchLength(); - item.setMainRange(lineNumber, lineStart, lineLength); - if (hasRegexp) { - const QString part = QString(text.mid(lineStart, lineLength)); - item.setUserData(regexp.match(part).capturedTexts()); - } - items << item; - } - - ++index; - return matches; -} - -bool SilverSearcherOutputParser::parseText() -{ - int startIndex = index; - while (index < outputSize && output[++index] != '\n') { } - - item.setLineText(QString(output.data() + startIndex, index - startIndex)); - ++index; - return true; -} - } // namespace SilverSearcher diff --git a/src/plugins/silversearcher/silversearcheroutputparser.h b/src/plugins/silversearcher/silversearcheroutputparser.h index a4b34a6051f..f9d8502759a 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.h +++ b/src/plugins/silversearcher/silversearcheroutputparser.h @@ -3,36 +3,13 @@ #pragma once -#include -#include +#include -#include #include namespace SilverSearcher { -class SilverSearcherOutputParser -{ -public: - SilverSearcherOutputParser(const QString &output, const QRegularExpression ®exp = {}); - - Utils::SearchResultItems parse(); - -private: - int parseMatches(int lineNumber); - int parseMatchLength(); - int parseMatchIndex(); - int parseLineNumber(); - bool parseFilePath(); - bool parseText(); - - QString output; - QRegularExpression regexp; - bool hasRegexp = false; - int outputSize = 0; - int index = 0; - Utils::SearchResultItem item; - Utils::SearchResultItems items; -}; +Utils::SearchResultItems parse(const QString &output, + const std::optional ®Exp = {}); } // namespace SilverSearcher From 24664515f1edd7a6f8b89e5591e8e111dabb54b3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 18:21:14 +0200 Subject: [PATCH 0939/1447] LocatorWidget: Dismantle the old matchesFor implementation Stop using it internally. Make ILocatorFilter::matchesFor() temporarily implemented by default so that the reimplementations in subclasses may be removed without leaving them abstract. Change-Id: I0c5d4ff70145a37d29385ee58a051c9c5ddfab8e Reviewed-by: Eike Ziller --- src/plugins/coreplugin/CMakeLists.txt | 1 - src/plugins/coreplugin/coreplugin.cpp | 6 +- src/plugins/coreplugin/coreplugin.qbs | 2 - .../coreplugin/locator/ilocatorfilter.h | 3 +- src/plugins/coreplugin/locator/locator.cpp | 4 +- src/plugins/coreplugin/locator/locator.h | 3 +- .../coreplugin/locator/locatorsearchutils.cpp | 35 ---- .../coreplugin/locator/locatorsearchutils.h | 16 -- .../coreplugin/locator/locatorwidget.cpp | 151 +----------------- .../coreplugin/locator/locatorwidget.h | 14 -- 10 files changed, 9 insertions(+), 226 deletions(-) delete mode 100644 src/plugins/coreplugin/locator/locatorsearchutils.cpp delete mode 100644 src/plugins/coreplugin/locator/locatorsearchutils.h diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index a7d1e6cf20f..0869553d8c4 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -111,7 +111,6 @@ add_qtc_plugin(Core locator/locatorconstants.h locator/locatorfiltersfilter.cpp locator/locatorfiltersfilter.h locator/locatormanager.cpp locator/locatormanager.h - locator/locatorsearchutils.cpp locator/locatorsearchutils.h locator/locatorsettingspage.cpp locator/locatorsettingspage.h locator/locatorwidget.cpp locator/locatorwidget.h locator/opendocumentsfilter.cpp locator/opendocumentsfilter.h diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 5d7524d8080..bf8e09b67b5 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -6,7 +6,6 @@ #include "designmode.h" #include "editmode.h" #include "foldernavigationwidget.h" -#include "helpmanager.h" #include "icore.h" #include "idocument.h" #include "iwizardfactory.h" @@ -472,8 +471,7 @@ QString CorePlugin::msgCrashpadInformation() ExtensionSystem::IPlugin::ShutdownFlag CorePlugin::aboutToShutdown() { Find::aboutToShutdown(); - ExtensionSystem::IPlugin::ShutdownFlag shutdownFlag = m_locator->aboutToShutdown( - [this] { emit asynchronousShutdownFinished(); }); + m_locator->aboutToShutdown(); m_mainWindow->aboutToShutdown(); - return shutdownFlag; + return SynchronousShutdown; } diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 3adf5b461c2..654f2e6bcb6 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -350,8 +350,6 @@ Project { "locatormanager.h", "locator.cpp", "locator.h", - "locatorsearchutils.cpp", - "locatorsearchutils.h", "locatorsettingspage.cpp", "locatorsettingspage.h", "locatorwidget.cpp", diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 377dcd9eac1..9ded00c1d0a 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -229,7 +229,8 @@ public: virtual void prepareSearch(const QString &entry); - virtual QList matchesFor(QFutureInterface &future, const QString &entry) = 0; + virtual QList matchesFor(QFutureInterface &, + const QString &) { return {}; }; virtual QByteArray saveState() const; virtual void restoreState(const QByteArray &state); diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index 1072dc0eca0..30d996a08e8 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -145,13 +145,11 @@ bool Locator::delayedInitialize() return true; } -ExtensionSystem::IPlugin::ShutdownFlag Locator::aboutToShutdown( - const std::function &emitAsynchronousShutdownFinished) +void Locator::aboutToShutdown() { m_shuttingDown = true; m_refreshTimer.stop(); m_taskTree.reset(); - return LocatorWidget::aboutToShutdown(emitAsynchronousShutdownFinished); } void Locator::loadSettings() diff --git a/src/plugins/coreplugin/locator/locator.h b/src/plugins/coreplugin/locator/locator.h index 59da8767d8a..edf978e6973 100644 --- a/src/plugins/coreplugin/locator/locator.h +++ b/src/plugins/coreplugin/locator/locator.h @@ -30,8 +30,7 @@ public: ~Locator() override; static Locator *instance(); - ExtensionSystem::IPlugin::ShutdownFlag aboutToShutdown( - const std::function &emitAsynchronousShutdownFinished); + void aboutToShutdown(); void initialize(); void extensionsInitialized(); diff --git a/src/plugins/coreplugin/locator/locatorsearchutils.cpp b/src/plugins/coreplugin/locator/locatorsearchutils.cpp deleted file mode 100644 index a6a90107fe3..00000000000 --- a/src/plugins/coreplugin/locator/locatorsearchutils.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "locatorsearchutils.h" - -#include - -#include - -void Core::Internal::runSearch(QFutureInterface &future, - const QList &filters, const QString &searchText) -{ - std::unordered_set addedCache; - const bool checkDuplicates = (filters.size() > 1); - const auto duplicatesRemoved = [&](const QList &entries) { - if (!checkDuplicates) - return entries; - QList results; - results.reserve(entries.size()); - for (const LocatorFilterEntry &entry : entries) { - const auto &link = entry.linkForEditor; - if (!link || addedCache.emplace(*link).second) - results.append(entry); - } - return results; - }; - - for (ILocatorFilter *filter : filters) { - if (future.isCanceled()) - break; - const auto results = duplicatesRemoved(filter->matchesFor(future, searchText)); - if (!results.isEmpty()) - future.reportResults(results); - } -} diff --git a/src/plugins/coreplugin/locator/locatorsearchutils.h b/src/plugins/coreplugin/locator/locatorsearchutils.h deleted file mode 100644 index d863b580a67..00000000000 --- a/src/plugins/coreplugin/locator/locatorsearchutils.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "ilocatorfilter.h" - -namespace Core { -namespace Internal { - -void CORE_EXPORT runSearch(QFutureInterface &future, - const QList &filters, - const QString &searchText); - -} // namespace Internal -} // namespace Core diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 74b35abaf54..1384f7b5de0 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -7,7 +7,6 @@ #include "locator.h" #include "locatorconstants.h" #include "locatormanager.h" -#include "locatorsearchutils.h" #include "../actionmanager/actionmanager.h" #include "../coreplugintr.h" #include "../editormanager/editormanager.h" @@ -25,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -54,16 +52,6 @@ const int LocatorEntryRole = int(HighlightingItemRole::User); namespace Core { namespace Internal { -static bool isUsingLocatorMatcher() -{ - const QString value = qtcEnvironmentVariable("QTC_USE_MATCHER", "").toLower(); - return !(value == "false" || value == "off"); -} - -bool LocatorWidget::m_shuttingDown = false; -QFuture LocatorWidget::m_sharedFuture; -LocatorWidget *LocatorWidget::m_sharedFutureOrigin = nullptr; - /* A model to represent the Locator results. */ class LocatorModel : public QAbstractListModel { @@ -631,12 +619,6 @@ LocatorWidget::LocatorWidget(Locator *locator) connect(m_fileLineEdit, &QLineEdit::textChanged, this, &LocatorWidget::showPopupDelayed); - m_entriesWatcher = new QFutureWatcher(this); - connect(m_entriesWatcher, &QFutureWatcher::resultsReadyAt, - this, &LocatorWidget::addSearchResults); - connect(m_entriesWatcher, &QFutureWatcher::finished, - this, &LocatorWidget::handleSearchFinished); - m_showPopupTimer.setInterval(100); m_showPopupTimer.setSingleShot(true); connect(&m_showPopupTimer, &QTimer::timeout, this, &LocatorWidget::showPopupNow); @@ -664,12 +646,7 @@ LocatorWidget::LocatorWidget(Locator *locator) updateFilterList(); } -LocatorWidget::~LocatorWidget() -{ - // no need to completely finish a running search, cancel it - if (m_entriesWatcher->future().isRunning()) - m_entriesWatcher->future().cancel(); -} +LocatorWidget::~LocatorWidget() = default; void LocatorWidget::updatePlaceholderText(Command *command) { @@ -878,7 +855,7 @@ void LocatorWidget::showPopupDelayed() void LocatorWidget::showPopupNow() { m_showPopupTimer.stop(); - updateCompletionList(m_fileLineEdit->text()); + runMatcher(m_fileLineEdit->text()); emit showPopup(); } @@ -973,91 +950,6 @@ void LocatorWidget::runMatcher(const QString &text) m_locatorMatcher->start(); } -// TODO: Remove when switched the default into new implementation. -static void printMatcherInfo() -{ - static bool printed = false; - if (printed) - return; - printed = true; - if (isUsingLocatorMatcher()) { - qDebug() << "Using the new LocatorMatcher implementation (default). In order to switch " - "back to the old implementation, set QTC_USE_MATCHER=FALSE env var."; - return; - } - qDebug() << "QTC_USE_MATCHER env var set to FALSE, using the old matchesFor implementation."; -} - -void LocatorWidget::updateCompletionList(const QString &text) -{ - if (m_shuttingDown) - return; - - printMatcherInfo(); - - if (isUsingLocatorMatcher()) { - runMatcher(text); - return; - } - - m_updateRequested = true; - if (m_sharedFuture.isRunning()) { - // Cancel the old future. We may not just block the UI thread to wait for the search to - // actually cancel. - m_requestedCompletionText = text; - if (m_sharedFutureOrigin == this) { - // This locator widget is currently running. Make handleSearchFinished trigger another - // update. - m_rerunAfterFinished = true; - } else { - // Another locator widget is running. Trigger another update when that is finished. - Utils::onFinished(m_sharedFuture, this, [this](const QFuture &) { - const QString text = m_requestedCompletionText; - m_requestedCompletionText.clear(); - updateCompletionList(text); - }); - } - m_sharedFuture.cancel(); - return; - } - - m_showProgressTimer.start(); - m_needsClearResult = true; - QString searchText; - const QList filters = filtersFor(text, searchText); - - for (ILocatorFilter *filter : filters) - filter->prepareSearch(searchText); - QFuture future = Utils::runAsync(&runSearch, filters, searchText); - m_sharedFuture = QFuture(future); - m_sharedFutureOrigin = this; - m_entriesWatcher->setFuture(future); -} - -void LocatorWidget::handleSearchFinished() -{ - m_showProgressTimer.stop(); - setProgressIndicatorVisible(false); - m_updateRequested = false; - if (m_rowRequestedForAccept) { - acceptEntry(m_rowRequestedForAccept.value()); - m_rowRequestedForAccept.reset(); - return; - } - if (m_rerunAfterFinished) { - m_rerunAfterFinished = false; - const QString text = m_requestedCompletionText; - m_requestedCompletionText.clear(); - updateCompletionList(text); - return; - } - - if (m_needsClearResult) { - m_locatorModel->clear(); - m_needsClearResult = false; - } -} - void LocatorWidget::scheduleAcceptEntry(const QModelIndex &index) { if (m_updateRequested) { @@ -1065,31 +957,12 @@ void LocatorWidget::scheduleAcceptEntry(const QModelIndex &index) // accept will be called after the update finished m_rowRequestedForAccept = index.row(); // do not wait for the rest of the search to finish - if (isUsingLocatorMatcher()) - m_locatorMatcher.reset(); - else - m_entriesWatcher->future().cancel(); + m_locatorMatcher.reset(); } else { acceptEntry(index.row()); } } -ExtensionSystem::IPlugin::ShutdownFlag LocatorWidget::aboutToShutdown( - const std::function &emitAsynchronousShutdownFinished) -{ - m_shuttingDown = true; - if (m_sharedFuture.isRunning()) { - Utils::onFinished(m_sharedFuture, - Locator::instance(), - [emitAsynchronousShutdownFinished](const QFuture &) { - emitAsynchronousShutdownFinished(); - }); - m_sharedFuture.cancel(); - return ExtensionSystem::IPlugin::AsynchronousShutdown; - } - return ExtensionSystem::IPlugin::SynchronousShutdown; -} - void LocatorWidget::acceptEntry(int row) { if (row < 0 || row >= m_locatorModel->rowCount()) @@ -1150,24 +1023,6 @@ void LocatorWidget::showConfigureDialog() ICore::showOptionsDialog(Constants::FILTER_OPTIONS_PAGE); } -void LocatorWidget::addSearchResults(int firstIndex, int endIndex) -{ - if (m_needsClearResult) { - m_locatorModel->clear(); - m_needsClearResult = false; - } - const bool selectFirst = m_locatorModel->rowCount() == 0; - QList entries; - for (int i = firstIndex; i < endIndex; ++i) - entries.append(m_entriesWatcher->resultAt(i)); - m_locatorModel->addEntries(entries); - if (selectFirst) { - emit selectRow(0); - if (m_rowRequestedForAccept) - m_rowRequestedForAccept = 0; - } -} - LocatorWidget *createStaticLocatorWidget(Locator *locator) { auto widget = new LocatorWidget(locator); diff --git a/src/plugins/coreplugin/locator/locatorwidget.h b/src/plugins/coreplugin/locator/locatorwidget.h index 4f6c1560ce5..ec3eca56f89 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.h +++ b/src/plugins/coreplugin/locator/locatorwidget.h @@ -44,9 +44,6 @@ public: void scheduleAcceptEntry(const QModelIndex &index); - static ExtensionSystem::IPlugin::ShutdownFlag aboutToShutdown( - const std::function &emitAsynchronousShutdownFinished); - signals: void showCurrentItemToolTip(); void lostFocus(); @@ -61,8 +58,6 @@ private: void showPopupNow(); void acceptEntry(int row); static void showConfigureDialog(); - void addSearchResults(int firstIndex, int endIndex); - void handleSearchFinished(); void updateFilterList(); bool isInMainWindow() const; @@ -70,27 +65,18 @@ private: bool eventFilter(QObject *obj, QEvent *event) override; void runMatcher(const QString &text); - void updateCompletionList(const QString &text); static QList filtersFor(const QString &text, QString &searchText); void setProgressIndicatorVisible(bool visible); LocatorModel *m_locatorModel = nullptr; - - static bool m_shuttingDown; - static QFuture m_sharedFuture; - static LocatorWidget *m_sharedFutureOrigin; - QMenu *m_filterMenu = nullptr; QAction *m_centeredPopupAction = nullptr; QAction *m_refreshAction = nullptr; QAction *m_configureAction = nullptr; Utils::FancyLineEdit *m_fileLineEdit = nullptr; QTimer m_showPopupTimer; - QFutureWatcher *m_entriesWatcher = nullptr; - QString m_requestedCompletionText; bool m_needsClearResult = true; bool m_updateRequested = false; - bool m_rerunAfterFinished = false; bool m_possibleToolTipRequest = false; QWidget *m_progressIndicator = nullptr; QTimer m_showProgressTimer; From 2d58d1b280959236968211f7811b040ae0d14daa Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 10 May 2023 08:54:25 +0200 Subject: [PATCH 0940/1447] Utils: Fix groupChecker functionality for aspects Change-Id: I1a44384cfebe8e23d8778ccb97f5846bfcbf0b9f Reviewed-by: hjk --- src/libs/utils/aspects.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index dc1888279ab..675f6b116f1 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1431,7 +1431,9 @@ std::function BoolAspect::groupChecker() auto groupBox = qobject_cast(target); QTC_ASSERT(groupBox, return); registerSubWidget(groupBox); - d->m_groupBox = d->m_groupBox; + groupBox->setCheckable(true); + groupBox->setChecked(value()); + d->m_groupBox = groupBox; }; } From dab004b3c201f332ea38184bfec924cdfe800800 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 20:45:25 +0200 Subject: [PATCH 0941/1447] ActionsFilter: Remove the old matchesFor() implementation Change-Id: I9f2d4c3d070869a720b63089b689c22c06dd4f4e Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/coreplugin/actionsfilter.cpp | 129 +---------------------- src/plugins/coreplugin/actionsfilter.h | 13 +-- 2 files changed, 6 insertions(+), 136 deletions(-) diff --git a/src/plugins/coreplugin/actionsfilter.cpp b/src/plugins/coreplugin/actionsfilter.cpp index 7bb1d51d820..01772ac2520 100644 --- a/src/plugins/coreplugin/actionsfilter.cpp +++ b/src/plugins/coreplugin/actionsfilter.cpp @@ -200,118 +200,6 @@ LocatorMatcherTasks ActionsFilter::matchers() return {{AsyncTask(onSetup), storage}}; } - -QList ActionsFilter::matchesFor(QFutureInterface &future, - const QString &entry) -{ - using Highlight = LocatorFilterEntry::HighlightInfo; - if (entry.simplified().isEmpty()) - return m_entries; - - const QRegularExpression regExp = createRegExp(entry, Qt::CaseInsensitive, true); - - using FilterResult = std::pair; - const auto filter = [&](const LocatorFilterEntry &filterEntry) -> std::optional { - if (future.isCanceled()) - return {}; - Highlight highlight; - - const auto withHighlight = [&](LocatorFilterEntry result) { - result.highlightInfo = highlight; - return result; - }; - - Highlight::DataType first = Highlight::DisplayName; - QString allText = filterEntry.displayName + ' ' + filterEntry.extraInfo; - QRegularExpressionMatch allTextMatch = regExp.match(allText); - if (!allTextMatch.hasMatch()) { - first = Highlight::ExtraInfo; - allText = filterEntry.extraInfo + ' ' + filterEntry.displayName; - allTextMatch = regExp.match(allText); - } - if (allTextMatch.hasMatch()) { - if (first == Highlight::DisplayName) { - const QRegularExpressionMatch displayMatch = regExp.match(filterEntry.displayName); - if (displayMatch.hasMatch()) - highlight = highlightInfo(displayMatch); - const QRegularExpressionMatch extraMatch = regExp.match(filterEntry.extraInfo); - if (extraMatch.hasMatch()) { - Highlight extraHighlight = highlightInfo(extraMatch, Highlight::ExtraInfo); - highlight.startsExtraInfo = extraHighlight.startsExtraInfo; - highlight.lengthsExtraInfo = extraHighlight.lengthsExtraInfo; - } - - if (filterEntry.displayName.startsWith(entry, Qt::CaseInsensitive)) - return FilterResult{MatchLevel::Best, withHighlight(filterEntry)}; - if (filterEntry.displayName.contains(entry, Qt::CaseInsensitive)) - return FilterResult{MatchLevel::Better, withHighlight(filterEntry)}; - if (displayMatch.hasMatch()) - return FilterResult{MatchLevel::Good, withHighlight(filterEntry)}; - if (extraMatch.hasMatch()) - return FilterResult{MatchLevel::Normal, withHighlight(filterEntry)}; - } - - const FuzzyMatcher::HighlightingPositions positions - = FuzzyMatcher::highlightingPositions(allTextMatch); - const int positionsCount = positions.starts.count(); - QTC_ASSERT(positionsCount == positions.lengths.count(), return {}); - const int border = first == Highlight::DisplayName ? filterEntry.displayName.length() - : filterEntry.extraInfo.length(); - for (int i = 0; i < positionsCount; ++i) { - int start = positions.starts.at(i); - const int length = positions.lengths.at(i); - Highlight::DataType type = first; - if (start > border) { - // this highlight is behind the border so switch type and reset start index - start -= border + 1; - type = first == Highlight::DisplayName ? Highlight::ExtraInfo - : Highlight::DisplayName; - } else if (start + length > border) { - const int firstStart = start; - const int firstLength = border - start; - const int secondStart = 0; - const int secondLength = length - firstLength - 1; - if (first == Highlight::DisplayName) { - highlight.startsDisplay.append(firstStart); - highlight.lengthsDisplay.append(firstLength); - highlight.startsExtraInfo.append(secondStart); - highlight.lengthsExtraInfo.append(secondLength); - } else { - highlight.startsExtraInfo.append(firstStart); - highlight.lengthsExtraInfo.append(firstLength); - highlight.startsDisplay.append(secondStart); - highlight.lengthsDisplay.append(secondLength); - } - continue; - } - if (type == Highlight::DisplayName) { - highlight.startsDisplay.append(start); - highlight.lengthsDisplay.append(length); - } else { - highlight.startsExtraInfo.append(start); - highlight.lengthsExtraInfo.append(length); - } - } - - return FilterResult{MatchLevel::Normal, withHighlight(filterEntry)}; - } - return {}; - }; - - QMap> filtered; - const QList> filterResults - = QtConcurrent::blockingMapped(m_entries, filter); - for (const std::optional &filterResult : filterResults) { - if (filterResult) - filtered[filterResult->first] << filterResult->second; - } - - QList result; - for (const QList &sublist : std::as_const(filtered)) - result << sublist; - return result; -} - LocatorFilterEntry::Acceptor ActionsFilter::acceptor(const ActionFilterEntryData &data) const { static const int maxHistorySize = 30; @@ -415,7 +303,7 @@ void ActionsFilter::collectEntriesForLastTriggered() void ActionsFilter::updateEntry(const QPointer action, const LocatorFilterEntry &entry) { - auto index = m_indexes.value(action, -1); + const int index = m_indexes.value(action, -1); if (index < 0) { m_indexes[action] = m_entries.size(); m_entries << entry; @@ -459,18 +347,6 @@ void ActionsFilter::updateEnabledActionCache() } } -void Core::Internal::ActionsFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - m_entries.clear(); - m_indexes.clear(); - QList processedMenus; - collectEntriesForLastTriggered(); - for (QAction* action : menuBarActions()) - collectEntriesForAction(action, QStringList(), processedMenus); - collectEntriesForCommands(); -} - void ActionsFilter::saveState(QJsonObject &object) const { QJsonArray commands; @@ -484,7 +360,8 @@ void ActionsFilter::saveState(QJsonObject &object) const void ActionsFilter::restoreState(const QJsonObject &object) { m_lastTriggered.clear(); - for (const QJsonValue &command : object.value(lastTriggeredC).toArray()) { + const QJsonArray commands = object.value(lastTriggeredC).toArray(); + for (const QJsonValue &command : commands) { if (command.isString()) m_lastTriggered.append({nullptr, Id::fromString(command.toString())}); } diff --git a/src/plugins/coreplugin/actionsfilter.h b/src/plugins/coreplugin/actionsfilter.h index 3d5cf43814e..692dea95d26 100644 --- a/src/plugins/coreplugin/actionsfilter.h +++ b/src/plugins/coreplugin/actionsfilter.h @@ -14,8 +14,7 @@ class QAction; class QMenu; QT_END_NAMESPACE -namespace Core { -namespace Internal { +namespace Core::Internal { class ActionFilterEntryData { @@ -30,14 +29,9 @@ public: class ActionsFilter : public ILocatorFilter { - Q_OBJECT public: ActionsFilter(); - QList matchesFor(QFutureInterface &future, - const QString &entry) override; - void prepareSearch(const QString &entry) override; - private: LocatorMatcherTasks matchers() final; void saveState(QJsonObject &object) const override; @@ -51,11 +45,10 @@ private: void updateEntry(const QPointer action, const LocatorFilterEntry &entry); void updateEnabledActionCache(); - QList m_entries; + LocatorFilterEntries m_entries; QMap, int> m_indexes; QSet> m_enabledActions; mutable QList m_lastTriggered; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From 7ce40a76912b26589d2fa06869e51301b9051085 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:03:18 +0200 Subject: [PATCH 0942/1447] CMakeLocatorFilter: Remove the old matchesFor() implementation Since the base class vanished, rename the filters so that they have the common prefix now. Change-Id: I164c7c17229f5c5b05649afe9e7aa79069a82f82 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- .../cmakelocatorfilter.cpp | 101 ++++-------------- .../cmakeprojectmanager/cmakelocatorfilter.h | 32 +----- .../cmakeprojectplugin.cpp | 4 +- 3 files changed, 29 insertions(+), 108 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 589a30d1ae2..2a6dba5b8e6 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -21,11 +21,9 @@ using namespace Utils; namespace CMakeProjectManager::Internal { -// -------------------------------------------------------------------- -// CMakeTargetLocatorFilter: -// -------------------------------------------------------------------- +using BuildAcceptor = std::function; -static LocatorMatcherTasks cmakeMatchers(const CMakeTargetLocatorFilter::BuildAcceptor &acceptor) +static LocatorMatcherTasks cmakeMatchers(const BuildAcceptor &acceptor) { using namespace Tasking; @@ -77,79 +75,23 @@ static LocatorMatcherTasks cmakeMatchers(const CMakeTargetLocatorFilter::BuildAc return {{Sync(onSetup), storage}}; } -CMakeTargetLocatorFilter::CMakeTargetLocatorFilter() +void setupFilter(ILocatorFilter *filter) { - connect(ProjectManager::instance(), &ProjectManager::projectAdded, - this, &CMakeTargetLocatorFilter::projectListUpdated); - connect(ProjectManager::instance(), &ProjectManager::projectRemoved, - this, &CMakeTargetLocatorFilter::projectListUpdated); - - // Initialize the filter - projectListUpdated(); -} - -void CMakeTargetLocatorFilter::prepareSearch(const QString &entry) -{ - m_result.clear(); - const QList projects = ProjectManager::projects(); - for (Project *p : projects) { - auto cmakeProject = qobject_cast(p); - if (!cmakeProject || !cmakeProject->activeTarget()) - continue; - auto bs = qobject_cast(cmakeProject->activeTarget()->buildSystem()); - if (!bs) - continue; - - const QList buildTargets = bs->buildTargets(); - for (const CMakeBuildTarget &target : buildTargets) { - if (CMakeBuildSystem::filteredOutTarget(target)) - continue; - const int index = target.title.indexOf(entry, 0, Qt::CaseInsensitive); - if (index >= 0) { - const FilePath path = target.backtrace.isEmpty() ? cmakeProject->projectFilePath() - : target.backtrace.last().path; - const int line = target.backtrace.isEmpty() ? 0 : target.backtrace.last().line; - const FilePath projectPath = cmakeProject->projectFilePath(); - const QString displayName = target.title; - LocatorFilterEntry filterEntry; - filterEntry.displayName = displayName; - if (m_acceptor) { - filterEntry.acceptor = [projectPath, displayName, acceptor = m_acceptor] { - acceptor(projectPath, displayName); - return AcceptResult(); - }; - } - filterEntry.linkForEditor = {path, line}; - filterEntry.extraInfo = path.shortNativePath(); - filterEntry.highlightInfo = {index, int(entry.length())}; - filterEntry.filePath = cmakeProject->projectFilePath(); - - m_result.append(filterEntry); - } - } - } -} - -QList CMakeTargetLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - Q_UNUSED(future) - Q_UNUSED(entry) - return m_result; -} - -void CMakeTargetLocatorFilter::projectListUpdated() -{ - // Enable the filter if there's at least one CMake project - setEnabled(Utils::contains(ProjectManager::projects(), - [](Project *p) { return qobject_cast(p); })); + const auto projectListUpdated = [filter] { + filter->setEnabled(Utils::contains(ProjectManager::projects(), + [](Project *p) { return qobject_cast(p); })); + }; + QObject::connect(ProjectManager::instance(), &ProjectManager::projectAdded, + filter, projectListUpdated); + QObject::connect(ProjectManager::instance(), &ProjectManager::projectRemoved, + filter, projectListUpdated); } // -------------------------------------------------------------------- // BuildCMakeTargetLocatorFilter: // -------------------------------------------------------------------- -static void buildAcceptor(const Utils::FilePath &projectPath, const QString &displayName) +static void buildAcceptor(const FilePath &projectPath, const QString &displayName) { // Get the project containing the target selected const auto cmakeProject = qobject_cast( @@ -161,14 +103,14 @@ static void buildAcceptor(const Utils::FilePath &projectPath, const QString &dis return; // Find the make step - BuildStepList *buildStepList = + const BuildStepList *buildStepList = cmakeProject->activeTarget()->activeBuildConfiguration()->buildSteps(); - auto buildStep = buildStepList->firstOfType(); + const auto buildStep = buildStepList->firstOfType(); if (!buildStep) return; // Change the make step to build only the given target - QStringList oldTargets = buildStep->buildTargets(); + const QStringList oldTargets = buildStep->buildTargets(); buildStep->setBuildTargets({displayName}); // Build @@ -176,17 +118,17 @@ static void buildAcceptor(const Utils::FilePath &projectPath, const QString &dis buildStep->setBuildTargets(oldTargets); } -BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() +CMakeBuildTargetFilter::CMakeBuildTargetFilter() { setId("Build CMake target"); setDisplayName(Tr::tr("Build CMake Target")); setDescription(Tr::tr("Builds a target of any open CMake project.")); setDefaultShortcutString("cm"); setPriority(High); - setBuildAcceptor(&buildAcceptor); + setupFilter(this); } -Core::LocatorMatcherTasks BuildCMakeTargetLocatorFilter::matchers() +Core::LocatorMatcherTasks CMakeBuildTargetFilter::matchers() { return cmakeMatchers(&buildAcceptor); } @@ -195,18 +137,19 @@ Core::LocatorMatcherTasks BuildCMakeTargetLocatorFilter::matchers() // OpenCMakeTargetLocatorFilter: // -------------------------------------------------------------------- -OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter() +CMakeOpenTargetFilter::CMakeOpenTargetFilter() { setId("Open CMake target definition"); setDisplayName(Tr::tr("Open CMake Target")); setDescription(Tr::tr("Locates the definition of a target of any open CMake project.")); setDefaultShortcutString("cmo"); setPriority(Medium); + setupFilter(this); } -Core::LocatorMatcherTasks OpenCMakeTargetLocatorFilter::matchers() +Core::LocatorMatcherTasks CMakeOpenTargetFilter::matchers() { return cmakeMatchers({}); } -} // CMakeProjectManager::Internal +} // namespace CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h index 73b3212b3fd..73e0a9fe4ab 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h @@ -7,44 +7,22 @@ namespace CMakeProjectManager::Internal { -// TODO: Remove the base class -class CMakeTargetLocatorFilter : public Core::ILocatorFilter +class CMakeBuildTargetFilter : Core::ILocatorFilter { public: - CMakeTargetLocatorFilter(); - - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) final; - using BuildAcceptor = std::function; -protected: - void setBuildAcceptor(const BuildAcceptor &acceptor) { m_acceptor = acceptor; } - -private: - void projectListUpdated(); - - QList m_result; - BuildAcceptor m_acceptor; -}; - -// TODO: Don't derive, flatten the hierarchy -class BuildCMakeTargetLocatorFilter : CMakeTargetLocatorFilter -{ -public: - BuildCMakeTargetLocatorFilter(); + CMakeBuildTargetFilter(); private: Core::LocatorMatcherTasks matchers() final; }; -// TODO: Don't derive, flatten the hierarchy -class OpenCMakeTargetLocatorFilter : CMakeTargetLocatorFilter +class CMakeOpenTargetFilter : Core::ILocatorFilter { public: - OpenCMakeTargetLocatorFilter(); + CMakeOpenTargetFilter(); private: Core::LocatorMatcherTasks matchers() final; }; -} // CMakeProjectManager::Internal +} // namespace CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp index bb0270d16ef..fd41c284455 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp @@ -81,8 +81,8 @@ public: CMakeBuildConfigurationFactory buildConfigFactory; CMakeEditorFactory editorFactor; CMakeInstallStepFactory installStepFactory; - BuildCMakeTargetLocatorFilter buildCMakeTargetLocatorFilter; - OpenCMakeTargetLocatorFilter openCMakeTargetLocationFilter; + CMakeBuildTargetFilter cMakeBuildTargetFilter; + CMakeOpenTargetFilter cMakeOpenTargetFilter; CMakeKitAspect cmakeKitAspect; CMakeGeneratorKitAspect cmakeGeneratorKitAspect; From c8ae479a23de64b41bb85af30442555637ff1c0e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:19:49 +0200 Subject: [PATCH 0943/1447] ExternalToolsFilter: Remove the old matchesFor() implementation Change-Id: I79e81103b0200ea9da56ecb84980e1814a01f2f1 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- .../locator/externaltoolsfilter.cpp | 54 ------------------- .../coreplugin/locator/externaltoolsfilter.h | 12 +---- 2 files changed, 2 insertions(+), 64 deletions(-) diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index c3d2d1705c2..308a378995f 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -83,58 +83,4 @@ LocatorMatcherTasks ExternalToolsFilter::matchers() return {{Sync(onSetup), storage}}; } -QList ExternalToolsFilter::matchesFor(QFutureInterface &, - const QString &) -{ - return m_results; -} - -void ExternalToolsFilter::prepareSearch(const QString &entry) -{ - QList bestEntries; - QList betterEntries; - QList goodEntries; - const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); - const QMap externalToolsById = ExternalToolManager::toolsById(); - for (ExternalTool *tool : externalToolsById) { - int index = tool->displayName().indexOf(entry, 0, entryCaseSensitivity); - LocatorFilterEntry::HighlightInfo::DataType hDataType = LocatorFilterEntry::HighlightInfo::DisplayName; - if (index < 0) { - index = tool->description().indexOf(entry, 0, entryCaseSensitivity); - hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo; - } - - if (index >= 0) { - LocatorFilterEntry filterEntry; - filterEntry.displayName = tool->displayName(); - filterEntry.acceptor = [tool] { - auto runner = new ExternalToolRunner(tool); - if (runner->hasError()) - MessageManager::writeFlashing(runner->errorString()); - return AcceptResult(); - }; - filterEntry.extraInfo = tool->description(); - filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); - - if (filterEntry.displayName.startsWith(entry, entryCaseSensitivity)) - bestEntries.append(filterEntry); - else if (filterEntry.displayName.contains(entry, entryCaseSensitivity)) - betterEntries.append(filterEntry); - else - goodEntries.append(filterEntry); - } - } - LocatorFilterEntry configEntry; - configEntry.displayName = "Configure External Tool..."; - configEntry.extraInfo = "Opens External Tool settings"; - configEntry.acceptor = [] { - QMetaObject::invokeMethod(CorePlugin::instance(), [] { - ICore::showOptionsDialog(Constants::SETTINGS_ID_TOOLS); - }, Qt::QueuedConnection); - return AcceptResult(); - }; - m_results = {}; - m_results << bestEntries << betterEntries << goodEntries << configEntry; -} - } // Core::Internal diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.h b/src/plugins/coreplugin/locator/externaltoolsfilter.h index 74c83112b50..bc8fca6e705 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.h +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.h @@ -5,23 +5,15 @@ #include "ilocatorfilter.h" -namespace Core { -namespace Internal { +namespace Core::Internal { class ExternalToolsFilter : public ILocatorFilter { - Q_OBJECT public: ExternalToolsFilter(); - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: LocatorMatcherTasks matchers() final; - - QList m_results; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From 86995160ba5ff917d027e30a409277ce946f058d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:30:44 +0200 Subject: [PATCH 0944/1447] QmlJSFunctionsFilter: Remove the old matchesFor() implementation Rename the filter to QmlJSFunctionsFilter, to conform to the other naming (CppFunctionsFilter, LanguageFunctionsFilter, ClangdFunctionsFilter). Change-Id: I6859c5c8f6d133d1f4dd49d4ee2742b5744c1463 Reviewed-by: Marcus Tillmanns Reviewed-by: Reviewed-by: Qt CI Bot --- .../qmljstools/qmljsfunctionfilter.cpp | 51 ++----------------- src/plugins/qmljstools/qmljsfunctionfilter.h | 14 ++--- src/plugins/qmljstools/qmljstoolsplugin.cpp | 2 +- 3 files changed, 8 insertions(+), 59 deletions(-) diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index b5f37e4c105..293e8962f48 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -18,9 +18,8 @@ using namespace Utils; Q_DECLARE_METATYPE(LocatorData::Entry) -FunctionFilter::FunctionFilter(LocatorData *data, QObject *parent) - : ILocatorFilter(parent) - , m_data(data) +QmlJSFunctionsFilter::QmlJSFunctionsFilter(LocatorData *data) + : m_data(data) { setId("Functions"); setDisplayName(Tr::tr("QML Functions")); @@ -76,7 +75,7 @@ static void matches(QPromise &promise, const LocatorStorage &storage, LocatorFilterEntries())); } -LocatorMatcherTasks FunctionFilter::matchers() +LocatorMatcherTasks QmlJSFunctionsFilter::matchers() { using namespace Tasking; @@ -89,47 +88,3 @@ LocatorMatcherTasks FunctionFilter::matchers() return {{AsyncTask(onSetup), storage}}; } - -QList FunctionFilter::matchesFor(QFutureInterface &future, - const QString &entry) -{ - QList entries[int(MatchLevel::Count)]; - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); - - const QRegularExpression regexp = createRegExp(entry); - if (!regexp.isValid()) - return {}; - - const QHash> locatorEntries = m_data->entries(); - for (const QList &items : locatorEntries) { - if (future.isCanceled()) - break; - - for (const LocatorData::Entry &info : items) { - if (info.type != LocatorData::Function) - continue; - - const QRegularExpressionMatch match = regexp.match(info.symbolName); - if (match.hasMatch()) { - LocatorFilterEntry filterEntry; - filterEntry.displayName = info.displayName; - filterEntry.linkForEditor = {info.fileName, info.line, info.column}; - filterEntry.extraInfo = info.extraInfo; - filterEntry.highlightInfo = highlightInfo(match); - - if (filterEntry.displayName.startsWith(entry, caseSensitivityForPrefix)) - entries[int(MatchLevel::Best)].append(filterEntry); - else if (filterEntry.displayName.contains(entry, caseSensitivityForPrefix)) - entries[int(MatchLevel::Better)].append(filterEntry); - else - entries[int(MatchLevel::Good)].append(filterEntry); - } - } - } - - for (auto &entry : entries) { - if (entry.size() < 1000) - Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); - } - return std::accumulate(std::begin(entries), std::end(entries), QList()); -} diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.h b/src/plugins/qmljstools/qmljsfunctionfilter.h index 71b3d0b5dd6..3775259fb27 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.h +++ b/src/plugins/qmljstools/qmljsfunctionfilter.h @@ -5,25 +5,19 @@ #include -namespace QmlJSTools { -namespace Internal { +namespace QmlJSTools::Internal { class LocatorData; -class FunctionFilter : public Core::ILocatorFilter +class QmlJSFunctionsFilter : public Core::ILocatorFilter { - Q_OBJECT - public: - explicit FunctionFilter(LocatorData *data, QObject *parent = nullptr); + QmlJSFunctionsFilter(LocatorData *data); - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: Core::LocatorMatcherTasks matchers() final; LocatorData *m_data = nullptr; }; -} // namespace Internal -} // namespace QmlJSTools +} // namespace QmlJSTools::Internal diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp index 574c73190b5..88c72b29e64 100644 --- a/src/plugins/qmljstools/qmljstoolsplugin.cpp +++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp @@ -38,7 +38,7 @@ public: QAction resetCodeModelAction{Tr::tr("Reset Code Model"), nullptr}; LocatorData locatorData; - FunctionFilter functionFilter{&locatorData}; + QmlJSFunctionsFilter functionsFilter{&locatorData}; QmlJSCodeStyleSettingsPage codeStyleSettingsPage; BasicBundleProvider basicBundleProvider; }; From 19834f598630c93c39730e7e1a7589cbe66c12cf Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:34:21 +0200 Subject: [PATCH 0945/1447] HelpIndexFilter: Remove the old matchesFor() implementation Change-Id: I867520fc790832c93381f390bcd74e4908086461 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/help/helpindexfilter.cpp | 51 ---------------------------- src/plugins/help/helpindexfilter.h | 11 ++---- 2 files changed, 2 insertions(+), 60 deletions(-) diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 1784867dc26..1a8fcd42d72 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -110,57 +110,6 @@ LocatorMatcherTasks HelpIndexFilter::matchers() return {{AsyncTask(onSetup, onDone), storage}}; } -void HelpIndexFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - if (!m_needsUpdate) - return; - - m_needsUpdate = false; - LocalHelpManager::setupGuiHelpEngine(); - m_allIndicesCache = LocalHelpManager::filterEngine()->indices({}); - m_lastIndicesCache.clear(); - m_lastEntry.clear(); -} - -QList HelpIndexFilter::matchesFor(QFutureInterface &future, - const QString &entry) -{ - const QStringList cache = m_lastEntry.isEmpty() || !entry.contains(m_lastEntry) - ? m_allIndicesCache : m_lastIndicesCache; - - const Qt::CaseSensitivity cs = caseSensitivity(entry); - QStringList bestKeywords; - QStringList worseKeywords; - bestKeywords.reserve(cache.size()); - worseKeywords.reserve(cache.size()); - for (const QString &keyword : cache) { - if (future.isCanceled()) - return {}; - if (keyword.startsWith(entry, cs)) - bestKeywords.append(keyword); - else if (keyword.contains(entry, cs)) - worseKeywords.append(keyword); - } - m_lastIndicesCache = bestKeywords + worseKeywords; - m_lastEntry = entry; - - QList entries; - for (const QString &key : std::as_const(m_lastIndicesCache)) { - const int index = key.indexOf(entry, 0, cs); - LocatorFilterEntry filterEntry; - filterEntry.displayName = key; - filterEntry.acceptor = [key] { - HelpPlugin::showLinksInCurrentViewer(LocalHelpManager::linksForKeyword(key), key); - return AcceptResult(); - }; - filterEntry.displayIcon = m_icon; - filterEntry.highlightInfo = {index, int(entry.length())}; - entries.append(filterEntry); - } - return entries; -} - void HelpIndexFilter::invalidateCache() { m_needsUpdate = true; diff --git a/src/plugins/help/helpindexfilter.h b/src/plugins/help/helpindexfilter.h index 489f7078c18..e980f49ab0c 100644 --- a/src/plugins/help/helpindexfilter.h +++ b/src/plugins/help/helpindexfilter.h @@ -5,19 +5,13 @@ #include -namespace Help { -namespace Internal { +namespace Help::Internal { class HelpIndexFilter final : public Core::ILocatorFilter { - Q_OBJECT - public: HelpIndexFilter(); - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: Core::LocatorMatcherTasks matchers() final; void invalidateCache(); @@ -29,5 +23,4 @@ private: QIcon m_icon; }; -} // namespace Internal -} // namespace Help +} // namespace Help::Internal From 2950762cb1aad63cf8a5ad29bbd756db68713165 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:41:04 +0200 Subject: [PATCH 0946/1447] JavaScriptFilter: Remove the old matchesFor() implementation Change-Id: I5a799238d3aae3ae342580e58af4d6993618f101 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../coreplugin/locator/javascriptfilter.cpp | 109 +----------------- .../coreplugin/locator/javascriptfilter.h | 26 +---- 2 files changed, 7 insertions(+), 128 deletions(-) diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 7511bb9c6f5..094d13f1f2c 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -351,8 +351,7 @@ public: QTC_DECLARE_CUSTOM_TASK(JavaScriptRequestTask, JavaScriptRequestAdapter); -namespace Core { -namespace Internal { +namespace Core::Internal { JavaScriptFilter::JavaScriptFilter() { @@ -361,15 +360,10 @@ JavaScriptFilter::JavaScriptFilter() setDescription(Tr::tr("Evaluates arbitrary JavaScript expressions and copies the result.")); setDefaultIncludedByDefault(false); setDefaultShortcutString("="); - m_abortTimer.setSingleShot(true); - m_abortTimer.setInterval(1000); - connect(&m_abortTimer, &QTimer::timeout, this, [this] { - m_aborted = true; - if (m_engine) - m_engine->setInterrupted(true); - }); } +JavaScriptFilter::~JavaScriptFilter() = default; + LocatorMatcherTasks JavaScriptFilter::matchers() { using namespace Tasking; @@ -441,101 +435,6 @@ LocatorMatcherTasks JavaScriptFilter::matchers() return {{root, storage}}; } -JavaScriptFilter::~JavaScriptFilter() = default; - -void JavaScriptFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - - if (!m_engine) - setupEngine(); - m_engine->setInterrupted(false); - m_aborted = false; - m_abortTimer.start(); -} - -QList JavaScriptFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - Q_UNUSED(future) - - QList entries; - if (entry.trimmed().isEmpty()) { - LocatorFilterEntry entry; - entry.displayName = Tr::tr("Reset Engine"); - entry.acceptor = [this] { - m_engine.reset(); - return AcceptResult(); - }; - entries.append(entry); - } else { - // Note, that evaluate may be interrupted from caller thread. - // In this case m_aborted is set to true. - const QString result = m_engine->evaluate(entry).toString(); - if (m_aborted) { - const QString message = entry + " = " + Tr::tr("Engine aborted after timeout."); - LocatorFilterEntry entry; - entry.displayName = message; - entry.acceptor = [] { return AcceptResult(); }; - entries.append(entry); - } else { - const auto acceptor = [](const QString &clipboardContents) { - return [clipboardContents] { - QGuiApplication::clipboard()->setText(clipboardContents); - return AcceptResult(); - }; - }; - const QString expression = entry + " = " + result; - - LocatorFilterEntry entry; - entry.displayName = expression; - entry.acceptor = [] { return AcceptResult(); }; - entries.append(entry); - - LocatorFilterEntry resultEntry; - resultEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(result); - resultEntry.acceptor = acceptor(result); - entries.append(resultEntry); - - LocatorFilterEntry expressionEntry; - expressionEntry.displayName = Tr::tr("Copy to clipboard: %1").arg(expression); - expressionEntry.acceptor = acceptor(expression); - entries.append(expressionEntry); - } - } - return entries; -} - -void JavaScriptFilter::setupEngine() -{ - m_engine.reset(new QJSEngine); - m_engine->evaluate( - "function abs(x) { return Math.abs(x); }\n" - "function acos(x) { return Math.acos(x); }\n" - "function asin(x) { return Math.asin(x); }\n" - "function atan(x) { return Math.atan(x); }\n" - "function atan2(x, y) { return Math.atan2(x, y); }\n" - "function bin(x) { return '0b' + x.toString(2); }\n" - "function ceil(x) { return Math.ceil(x); }\n" - "function cos(x) { return Math.cos(x); }\n" - "function exp(x) { return Math.exp(x); }\n" - "function e() { return Math.E; }\n" - "function floor(x) { return Math.floor(x); }\n" - "function hex(x) { return '0x' + x.toString(16); }\n" - "function log(x) { return Math.log(x); }\n" - "function max() { return Math.max.apply(null, arguments); }\n" - "function min() { return Math.min.apply(null, arguments); }\n" - "function oct(x) { return '0' + x.toString(8); }\n" - "function pi() { return Math.PI; }\n" - "function pow(x, y) { return Math.pow(x, y); }\n" - "function random() { return Math.random(); }\n" - "function round(x) { return Math.round(x); }\n" - "function sin(x) { return Math.sin(x); }\n" - "function sqrt(x) { return Math.sqrt(x); }\n" - "function tan(x) { return Math.tan(x); }\n"); -} - -} // namespace Internal -} // namespace Core +} // namespace Core::Internal #include "javascriptfilter.moc" diff --git a/src/plugins/coreplugin/locator/javascriptfilter.h b/src/plugins/coreplugin/locator/javascriptfilter.h index e2508c70483..8b7112fd27d 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.h +++ b/src/plugins/coreplugin/locator/javascriptfilter.h @@ -5,39 +5,19 @@ #include -#include - -#include -#include - -QT_BEGIN_NAMESPACE -class QJSEngine; -QT_END_NAMESPACE - class JavaScriptEngine; -namespace Core { -namespace Internal { +namespace Core::Internal { class JavaScriptFilter : public Core::ILocatorFilter { - Q_OBJECT public: JavaScriptFilter(); - ~JavaScriptFilter() override; + ~JavaScriptFilter(); - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: LocatorMatcherTasks matchers() final; - void setupEngine(); - - mutable std::unique_ptr m_engine; - QTimer m_abortTimer; - std::atomic_bool m_aborted = false; std::unique_ptr m_javaScriptEngine; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From 475e85946285cd1fd0daa0579214ef456f0a4ac7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:51:26 +0200 Subject: [PATCH 0947/1447] LineNumberFilter: Remove the old matchesFor() implementation Change-Id: Ia45de8cd265300776c9cb0660b491f9584620a14 Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/plugins/texteditor/linenumberfilter.cpp | 50 +-------------------- src/plugins/texteditor/linenumberfilter.h | 16 ++----- 2 files changed, 5 insertions(+), 61 deletions(-) diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index cec55ecbffa..b718e5b4331 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -6,15 +6,13 @@ #include "texteditortr.h" #include -#include using namespace Core; using namespace Utils; namespace TextEditor::Internal { -LineNumberFilter::LineNumberFilter(QObject *parent) - : ILocatorFilter(parent) +LineNumberFilter::LineNumberFilter() { setId("Line in current document"); setDisplayName(Tr::tr("Line in Current Document")); @@ -68,48 +66,4 @@ LocatorMatcherTasks LineNumberFilter::matchers() return {{Sync(onSetup), storage}}; } -void LineNumberFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - m_hasCurrentEditor = EditorManager::currentEditor() != nullptr; -} - -QList LineNumberFilter::matchesFor(QFutureInterface &, const QString &entry) -{ - QList value; - const QStringList lineAndColumn = entry.split(':'); - int sectionCount = lineAndColumn.size(); - int line = 0; - int column = 0; - bool ok = false; - if (sectionCount > 0) - line = lineAndColumn.at(0).toInt(&ok); - if (ok && sectionCount > 1) - column = lineAndColumn.at(1).toInt(&ok); - if (!ok) - return value; - if (m_hasCurrentEditor && (line > 0 || column > 0)) { - QString text; - if (line > 0 && column > 0) - text = Tr::tr("Line %1, Column %2").arg(line).arg(column); - else if (line > 0) - text = Tr::tr("Line %1").arg(line); - else - text = Tr::tr("Column %1").arg(column); - LocatorFilterEntry entry; - entry.displayName = text; - entry.acceptor = [line, targetColumn = column - 1] { - IEditor *editor = EditorManager::currentEditor(); - if (!editor) - return AcceptResult(); - EditorManager::addCurrentPositionToNavigationHistory(); - editor->gotoLine(line < 1 ? editor->currentLine() : line, targetColumn); - EditorManager::activateEditor(editor); - return AcceptResult(); - }; - value.append(entry); - } - return value; -} - -} // TextEditor::Internal +} // namespace TextEditor::Internal diff --git a/src/plugins/texteditor/linenumberfilter.h b/src/plugins/texteditor/linenumberfilter.h index 5717da176dd..ec72c1bb029 100644 --- a/src/plugins/texteditor/linenumberfilter.h +++ b/src/plugins/texteditor/linenumberfilter.h @@ -5,25 +5,15 @@ #include -namespace Core { class IEditor; } - -namespace TextEditor { -namespace Internal { +namespace TextEditor::Internal { class LineNumberFilter : public Core::ILocatorFilter { - Q_OBJECT - public: - explicit LineNumberFilter(QObject *parent = nullptr); + LineNumberFilter(); - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: Core::LocatorMatcherTasks matchers() final; - bool m_hasCurrentEditor = false; }; -} // namespace Internal -} // namespace TextEditor +} // namespace TextEditor::Internal From 062db6b3a527c59f3c0ee6ee329e9175f550c2b7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 22:30:11 +0200 Subject: [PATCH 0948/1447] LocatorFiltersFilter: Remove the old matchesFor() implementation Change-Id: I28bef914103b3650badf1ec44fdcd4a1081384dc Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../locator/locatorfiltersfilter.cpp | 53 ------------------- .../coreplugin/locator/locatorfiltersfilter.h | 16 +----- 2 files changed, 2 insertions(+), 67 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index a602be27848..782cb3f5576 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -7,11 +7,8 @@ #include "../actionmanager/actionmanager.h" #include "../coreplugintr.h" -#include #include -Q_DECLARE_METATYPE(Core::ILocatorFilter*) - using namespace Utils; namespace Core::Internal { @@ -68,54 +65,4 @@ LocatorMatcherTasks LocatorFiltersFilter::matchers() return {{Sync(onSetup), storage}}; } -void LocatorFiltersFilter::prepareSearch(const QString &entry) -{ - m_filterShortcutStrings.clear(); - m_filterDisplayNames.clear(); - m_filterDescriptions.clear(); - if (!entry.isEmpty()) - return; - - QMap uniqueFilters; - const QList allFilters = Locator::filters(); - for (ILocatorFilter *filter : allFilters) { - const QString filterId = filter->shortcutString() + ',' + filter->displayName(); - uniqueFilters.insert(filterId, filter); - } - - for (ILocatorFilter *filter : std::as_const(uniqueFilters)) { - if (!filter->shortcutString().isEmpty() && !filter->isHidden() && filter->isEnabled()) { - m_filterShortcutStrings.append(filter->shortcutString()); - m_filterDisplayNames.append(filter->displayName()); - m_filterDescriptions.append(filter->description()); - QString keyboardShortcut; - if (auto command = ActionManager::command(filter->actionId())) - keyboardShortcut = command->keySequence().toString(QKeySequence::NativeText); - m_filterKeyboardShortcuts.append(keyboardShortcut); - } - } -} - -QList LocatorFiltersFilter::matchesFor(QFutureInterface &future, const QString &entry) -{ - Q_UNUSED(entry) // search is already done in the GUI thread in prepareSearch - QList entries; - for (int i = 0; i < m_filterShortcutStrings.size(); ++i) { - if (future.isCanceled()) - break; - const QString shortcutString = m_filterShortcutStrings.at(i); - LocatorFilterEntry filterEntry; - filterEntry.displayName = shortcutString; - filterEntry.acceptor = [shortcutString] { - return AcceptResult{shortcutString + ' ', int(shortcutString.size() + 1)}; - }; - filterEntry.displayIcon = m_icon; - filterEntry.extraInfo = m_filterDisplayNames.at(i); - filterEntry.toolTip = m_filterDescriptions.at(i); - filterEntry.displayExtra = m_filterKeyboardShortcuts.at(i); - entries.append(filterEntry); - } - return entries; -} - } // Core::Internal diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.h b/src/plugins/coreplugin/locator/locatorfiltersfilter.h index e1cf75a75bf..f6dea092eb6 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.h +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.h @@ -5,12 +5,7 @@ #include "ilocatorfilter.h" -#include - -namespace Core { -namespace Internal { - -class Locator; +namespace Core::Internal { /*! This filter provides the user with the list of available Locator filters. @@ -18,15 +13,9 @@ class Locator; */ class LocatorFiltersFilter : public ILocatorFilter { - Q_OBJECT - public: LocatorFiltersFilter(); - // ILocatorFilter - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: LocatorMatcherTasks matchers() final; @@ -37,5 +26,4 @@ private: QIcon m_icon; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From 349a3a5872b8287329ae48466a19aaf43cd43dd6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 9 May 2023 09:38:51 +0200 Subject: [PATCH 0949/1447] Markdown: Save visible views as default Remember if editor and/or preview are visible and use it as default for when a markdown editor is opened. Change-Id: I19414adfd118003628783fadeae472b7bb7915f5 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/texteditor/markdowneditor.cpp | 29 +++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 0e76c893315..6310bd32689 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -26,7 +26,11 @@ const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; const char MARKDOWNVIEWER_TEXT_CONTEXT[] = "Editors.MarkdownViewer.Text"; const char MARKDOWNVIEWER_MIME_TYPE[] = "text/markdown"; const char MARKDOWNVIEWER_TEXTEDITOR_RIGHT[] = "Markdown.TextEditorRight"; +const char MARKDOWNVIEWER_SHOW_EDITOR[] = "Markdown.ShowEditor"; +const char MARKDOWNVIEWER_SHOW_PREVIEW[] = "Markdown.ShowPreview"; const bool kTextEditorRightDefault = true; +const bool kShowEditorDefault = true; +const bool kShowPreviewDefault = true; class MarkdownEditor : public Core::IEditor { @@ -39,6 +43,9 @@ public: QSettings *s = Core::ICore::settings(); const bool textEditorRight = s->value(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, kTextEditorRightDefault).toBool(); + const bool showPreview = s->value(MARKDOWNVIEWER_SHOW_PREVIEW, kShowPreviewDefault).toBool(); + const bool showEditor = s->value(MARKDOWNVIEWER_SHOW_EDITOR, kShowEditorDefault).toBool() + || !showPreview; // ensure at least one is visible m_splitter = new Core::MiniSplitter; @@ -86,15 +93,18 @@ public: auto togglePreviewVisible = new QToolButton; togglePreviewVisible->setText(Tr::tr("Show Preview")); togglePreviewVisible->setCheckable(true); - togglePreviewVisible->setChecked(true); + togglePreviewVisible->setChecked(showPreview); + browser->setVisible(showPreview); m_toggleEditorVisible = new QToolButton; m_toggleEditorVisible->setText(Tr::tr("Show Editor")); m_toggleEditorVisible->setCheckable(true); - m_toggleEditorVisible->setChecked(true); + m_toggleEditorVisible->setChecked(showEditor); + m_textEditorWidget->setVisible(showEditor); auto swapViews = new QToolButton; swapViews->setText(Tr::tr("Swap Views")); + swapViews->setEnabled(showEditor && showPreview); auto toolbarLayout = new QHBoxLayout(&m_toolbar); toolbarLayout->setSpacing(0); @@ -144,22 +154,33 @@ public: } swapViews->setEnabled(view->isVisible() && otherView->isVisible()); }; + const auto saveViewSettings = [this, togglePreviewVisible] { + Utils::QtcSettings *s = Core::ICore::settings(); + s->setValueWithDefault(MARKDOWNVIEWER_SHOW_PREVIEW, + togglePreviewVisible->isChecked(), + kShowPreviewDefault); + s->setValueWithDefault(MARKDOWNVIEWER_SHOW_EDITOR, + m_toggleEditorVisible->isChecked(), + kShowEditorDefault); + }; connect(m_toggleEditorVisible, &QToolButton::toggled, this, - [this, browser, togglePreviewVisible, viewToggled](bool visible) { + [this, browser, togglePreviewVisible, viewToggled, saveViewSettings](bool visible) { viewToggled(m_textEditorWidget, visible, browser, togglePreviewVisible); + saveViewSettings(); }); connect(togglePreviewVisible, &QToolButton::toggled, this, - [this, browser, viewToggled, updatePreview](bool visible) { + [this, browser, viewToggled, updatePreview, saveViewSettings](bool visible) { viewToggled(browser, visible, m_textEditorWidget, m_toggleEditorVisible); if (visible && m_performDelayedUpdate) { m_performDelayedUpdate = false; updatePreview(); } + saveViewSettings(); }); connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this, toolbarLayout] { From 68656354427141b8521270a559cffe8230f5d6fd Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 9 May 2023 14:55:44 +0200 Subject: [PATCH 0950/1447] Markdown: Save and restore state This restores the state of the markdown editor, including text editor state, preview scroll position and button states, when closing and re- opening a file. Change-Id: Ibf1cadd5e0e80149123c6c5f599157e931330343 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: David Schulz --- src/plugins/texteditor/markdowneditor.cpp | 176 ++++++++++++++-------- 1 file changed, 115 insertions(+), 61 deletions(-) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 6310bd32689..12e60f027af 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -20,6 +20,8 @@ #include #include +#include + namespace TextEditor::Internal { const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer"; @@ -50,10 +52,10 @@ public: m_splitter = new Core::MiniSplitter; // preview - auto browser = new QTextBrowser(); - browser->setOpenExternalLinks(true); - browser->setFrameShape(QFrame::NoFrame); - new Utils::MarkdownHighlighter(browser->document()); + m_previewWidget = new QTextBrowser(); + m_previewWidget->setOpenExternalLinks(true); + m_previewWidget->setFrameShape(QFrame::NoFrame); + new Utils::MarkdownHighlighter(m_previewWidget->document()); // editor m_textEditorWidget = new TextEditorWidget; @@ -65,13 +67,8 @@ public: context->setContext(Core::Context(MARKDOWNVIEWER_TEXT_CONTEXT)); Core::ICore::addContextObject(context); - if (textEditorRight) { - m_splitter->addWidget(browser); - m_splitter->addWidget(m_textEditorWidget); - } else { - m_splitter->addWidget(m_textEditorWidget); - m_splitter->addWidget(browser); - } + m_splitter->addWidget(m_previewWidget); + m_splitter->addWidget(m_textEditorWidget); setContext(Core::Context(MARKDOWNVIEWER_ID)); @@ -90,11 +87,11 @@ public: } agg->add(m_widget.get()); - auto togglePreviewVisible = new QToolButton; - togglePreviewVisible->setText(Tr::tr("Show Preview")); - togglePreviewVisible->setCheckable(true); - togglePreviewVisible->setChecked(showPreview); - browser->setVisible(showPreview); + m_togglePreviewVisible = new QToolButton; + m_togglePreviewVisible->setText(Tr::tr("Show Preview")); + m_togglePreviewVisible->setCheckable(true); + m_togglePreviewVisible->setChecked(showPreview); + m_previewWidget->setVisible(showPreview); m_toggleEditorVisible = new QToolButton; m_toggleEditorVisible->setText(Tr::tr("Show Editor")); @@ -106,37 +103,33 @@ public: swapViews->setText(Tr::tr("Swap Views")); swapViews->setEnabled(showEditor && showPreview); - auto toolbarLayout = new QHBoxLayout(&m_toolbar); - toolbarLayout->setSpacing(0); - toolbarLayout->setContentsMargins(0, 0, 0, 0); - toolbarLayout->addStretch(); - if (textEditorRight) { - toolbarLayout->addWidget(togglePreviewVisible); - toolbarLayout->addWidget(m_toggleEditorVisible); - } else { - toolbarLayout->addWidget(m_toggleEditorVisible); - toolbarLayout->addWidget(togglePreviewVisible); - } - toolbarLayout->addWidget(swapViews); + m_toolbarLayout = new QHBoxLayout(&m_toolbar); + m_toolbarLayout->setSpacing(0); + m_toolbarLayout->setContentsMargins(0, 0, 0, 0); + m_toolbarLayout->addStretch(); + m_toolbarLayout->addWidget(m_togglePreviewVisible); + m_toolbarLayout->addWidget(m_toggleEditorVisible); + m_toolbarLayout->addWidget(swapViews); + + setWidgetOrder(textEditorRight); connect(m_document.data(), &TextDocument::mimeTypeChanged, m_document.data(), &TextDocument::changed); - const auto updatePreview = [this, browser] { - QHash positions; - const auto scrollBars = browser->findChildren(); - + const auto updatePreview = [this] { // save scroll positions - for (QScrollBar *scrollBar : scrollBars) - positions.insert(scrollBar, scrollBar->value()); + const QPoint positions = m_previewRestoreScrollPosition + ? *m_previewRestoreScrollPosition + : QPoint(m_previewWidget->horizontalScrollBar()->value(), + m_previewWidget->verticalScrollBar()->value()); + m_previewRestoreScrollPosition.reset(); - browser->setMarkdown(m_document->plainText()); + m_previewWidget->setMarkdown(m_document->plainText()); - // restore scroll positions - for (QScrollBar *scrollBar : scrollBars) - scrollBar->setValue(positions.value(scrollBar)); + m_previewWidget->horizontalScrollBar()->setValue(positions.x()); + m_previewWidget->verticalScrollBar()->setValue(positions.y()); }; const auto viewToggled = @@ -154,10 +147,10 @@ public: } swapViews->setEnabled(view->isVisible() && otherView->isVisible()); }; - const auto saveViewSettings = [this, togglePreviewVisible] { + const auto saveViewSettings = [this] { Utils::QtcSettings *s = Core::ICore::settings(); s->setValueWithDefault(MARKDOWNVIEWER_SHOW_PREVIEW, - togglePreviewVisible->isChecked(), + m_togglePreviewVisible->isChecked(), kShowPreviewDefault); s->setValueWithDefault(MARKDOWNVIEWER_SHOW_EDITOR, m_toggleEditorVisible->isChecked(), @@ -167,15 +160,18 @@ public: connect(m_toggleEditorVisible, &QToolButton::toggled, this, - [this, browser, togglePreviewVisible, viewToggled, saveViewSettings](bool visible) { - viewToggled(m_textEditorWidget, visible, browser, togglePreviewVisible); + [this, viewToggled, saveViewSettings](bool visible) { + viewToggled(m_textEditorWidget, + visible, + m_previewWidget, + m_togglePreviewVisible); saveViewSettings(); }); - connect(togglePreviewVisible, + connect(m_togglePreviewVisible, &QToolButton::toggled, this, - [this, browser, viewToggled, updatePreview, saveViewSettings](bool visible) { - viewToggled(browser, visible, m_textEditorWidget, m_toggleEditorVisible); + [this, viewToggled, updatePreview, saveViewSettings](bool visible) { + viewToggled(m_previewWidget, visible, m_textEditorWidget, m_toggleEditorVisible); if (visible && m_performDelayedUpdate) { m_performDelayedUpdate = false; updatePreview(); @@ -183,31 +179,21 @@ public: saveViewSettings(); }); - connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this, toolbarLayout] { - QTC_ASSERT(m_splitter->count() > 1, return); - // switch views - auto placeholder = std::make_unique(); - auto second = m_splitter->replaceWidget(1, placeholder.get()); - auto first = m_splitter->replaceWidget(0, second); - m_splitter->replaceWidget(1, first); - // switch buttons - const int rightIndex = toolbarLayout->count() - 2; - QLayoutItem *right = toolbarLayout->takeAt(rightIndex); - toolbarLayout->insertItem(rightIndex - 1, right); + connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this] { + const bool textEditorRight = isTextEditorRight(); + setWidgetOrder(!textEditorRight); // save settings Utils::QtcSettings *s = Core::ICore::settings(); s->setValueWithDefault(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, - !s->value(MARKDOWNVIEWER_TEXTEDITOR_RIGHT, - kTextEditorRightDefault) - .toBool(), + !textEditorRight, kTextEditorRightDefault); }); // TODO directly update when we build with Qt 6.5.2 m_previewTimer.setInterval(500); m_previewTimer.setSingleShot(true); - connect(&m_previewTimer, &QTimer::timeout, this, [this, togglePreviewVisible, updatePreview] { - if (togglePreviewVisible->isChecked()) + connect(&m_previewTimer, &QTimer::timeout, this, [this, updatePreview] { + if (m_togglePreviewVisible->isChecked()) updatePreview(); else m_performDelayedUpdate = true; @@ -218,6 +204,25 @@ public: }); } + bool isTextEditorRight() const { return m_splitter->widget(0) == m_previewWidget; } + + void setWidgetOrder(bool textEditorRight) + { + QTC_ASSERT(m_splitter->count() > 1, return); + QWidget *left = textEditorRight ? static_cast(m_previewWidget) + : m_textEditorWidget; + QWidget *right = textEditorRight ? static_cast(m_textEditorWidget) + : m_previewWidget; + m_splitter->insertWidget(0, left); + m_splitter->insertWidget(1, right); + // buttons + QWidget *leftButton = textEditorRight ? m_togglePreviewVisible : m_toggleEditorVisible; + QWidget *rightButton = textEditorRight ? m_toggleEditorVisible : m_togglePreviewVisible; + const int rightIndex = m_toolbarLayout->count() - 2; + m_toolbarLayout->insertWidget(rightIndex, leftButton); + m_toolbarLayout->insertWidget(rightIndex, rightButton); + } + QWidget *toolBar() override { return &m_toolbar; } Core::IDocument *document() const override { return m_document.data(); } @@ -247,14 +252,63 @@ public: return Core::IEditor::eventFilter(obj, ev); } + QByteArray saveState() const override + { + QByteArray state; + QDataStream stream(&state, QIODevice::WriteOnly); + stream << 1; // version number + stream << m_textEditorWidget->saveState(); + stream << m_previewWidget->horizontalScrollBar()->value(); + stream << m_previewWidget->verticalScrollBar()->value(); + stream << isTextEditorRight(); + stream << m_togglePreviewVisible->isChecked(); + stream << m_toggleEditorVisible->isChecked(); + stream << m_splitter->saveState(); + return state; + } + + void restoreState(const QByteArray &state) override + { + if (state.isEmpty()) + return; + int version; + QByteArray editorState; + int previewHV; + int previewVV; + bool textEditorRight; + bool previewShown; + bool textEditorShown; + QByteArray splitterState; + QDataStream stream(state); + stream >> version; + stream >> editorState; + stream >> previewHV; + stream >> previewVV; + stream >> textEditorRight; + stream >> previewShown; + stream >> textEditorShown; + stream >> splitterState; + m_textEditorWidget->restoreState(editorState); + m_previewRestoreScrollPosition.emplace(previewHV, previewVV); + setWidgetOrder(textEditorRight); + m_splitter->restoreState(splitterState); + m_togglePreviewVisible->setChecked(previewShown); + // ensure at least one is shown + m_toggleEditorVisible->setChecked(textEditorShown || !previewShown); + } + private: QTimer m_previewTimer; bool m_performDelayedUpdate = false; Core::MiniSplitter *m_splitter; + QTextBrowser *m_previewWidget; TextEditorWidget *m_textEditorWidget; TextDocumentPtr m_document; QWidget m_toolbar; + QHBoxLayout *m_toolbarLayout; QToolButton *m_toggleEditorVisible; + QToolButton *m_togglePreviewVisible; + std::optional m_previewRestoreScrollPosition; }; MarkdownEditorFactory::MarkdownEditorFactory() From 5975657e7747052211310a9bfedaac1fa937fc19 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 9 May 2023 13:20:04 +0200 Subject: [PATCH 0951/1447] Utils: Centralize style-related property names as constants This introduces string constants in Utils::StyleHelper. They are used by code all over in Qt Creator to tell ManhattanStyle how to paint certain widgets. Change-Id: Iecca36103f80084cd5fe93fcb6b18b8fbb3a32bb Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- .../advanceddockingsystem/docksplitter.cpp | 4 +- src/libs/utils/styledbar.cpp | 8 +-- src/libs/utils/stylehelper.cpp | 4 +- src/libs/utils/stylehelper.h | 15 ++++++ src/plugins/autotest/testnavigationwidget.cpp | 3 +- src/plugins/autotest/testresultspane.cpp | 2 +- src/plugins/clangtools/clangtoolsplugin.cpp | 3 +- src/plugins/coreplugin/editortoolbar.cpp | 13 ++--- src/plugins/coreplugin/find/findtoolbar.cpp | 2 +- .../coreplugin/find/searchresultwindow.cpp | 3 +- .../coreplugin/foldernavigationwidget.cpp | 3 +- src/plugins/coreplugin/manhattanstyle.cpp | 54 +++++++++++-------- src/plugins/coreplugin/minisplitter.cpp | 4 +- .../coreplugin/navigationsubwidget.cpp | 3 +- src/plugins/cppeditor/cppeditorwidget.cpp | 5 +- .../ctfvisualizer/ctfvisualizertool.cpp | 4 +- src/plugins/debugger/debuggermainwindow.cpp | 2 +- src/plugins/git/branchview.cpp | 7 +-- src/plugins/help/helpwidget.cpp | 5 +- src/plugins/imageviewer/imageviewer.cpp | 5 +- src/plugins/perfprofiler/perfprofilertool.cpp | 2 +- .../projectexplorer/projecttreewidget.cpp | 3 +- src/plugins/projectexplorer/taskwindow.cpp | 2 +- src/plugins/python/pythoneditor.cpp | 6 ++- .../components/componentcore/zoomaction.cpp | 4 +- .../formeditor/backgroundaction.cpp | 4 +- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- src/plugins/squish/squishoutputpane.cpp | 2 +- src/plugins/texteditor/outlinefactory.cpp | 2 +- src/plugins/valgrind/memchecktool.cpp | 3 +- 30 files changed, 112 insertions(+), 67 deletions(-) diff --git a/src/libs/advanceddockingsystem/docksplitter.cpp b/src/libs/advanceddockingsystem/docksplitter.cpp index 22efb632040..a10161da596 100644 --- a/src/libs/advanceddockingsystem/docksplitter.cpp +++ b/src/libs/advanceddockingsystem/docksplitter.cpp @@ -6,6 +6,8 @@ #include "ads_globals_p.h" #include "dockareawidget.h" +#include + #include #include #include @@ -30,7 +32,7 @@ namespace ADS , d(new DockSplitterPrivate(this)) { //setProperty("ads-splitter", true); // TODO - setProperty("minisplitter", true); + setProperty(Utils::StyleHelper::C_MINI_SPLITTER, true); setChildrenCollapsible(false); } diff --git a/src/libs/utils/styledbar.cpp b/src/libs/utils/styledbar.cpp index 7b00c4b4953..4e7ec489fbd 100644 --- a/src/libs/utils/styledbar.cpp +++ b/src/libs/utils/styledbar.cpp @@ -15,7 +15,7 @@ StyledBar::StyledBar(QWidget *parent) { StyleHelper::setPanelWidget(this); StyleHelper::setPanelWidgetSingleRow(this); - setProperty("lightColored", false); + setProperty(StyleHelper::C_LIGHT_COLORED, false); } void StyledBar::setSingleRow(bool singleRow) @@ -25,14 +25,14 @@ void StyledBar::setSingleRow(bool singleRow) bool StyledBar::isSingleRow() const { - return property("panelwidget_singlerow").toBool(); + return property(StyleHelper::C_PANEL_WIDGET_SINGLE_ROW).toBool(); } void StyledBar::setLightColored(bool lightColored) { if (isLightColored() == lightColored) return; - setProperty("lightColored", lightColored); + setProperty(StyleHelper::C_LIGHT_COLORED, lightColored); const QList children = findChildren(); for (QWidget *childWidget : children) childWidget->style()->polish(childWidget); @@ -40,7 +40,7 @@ void StyledBar::setLightColored(bool lightColored) bool StyledBar::isLightColored() const { - return property("lightColored").toBool(); + return property(StyleHelper::C_LIGHT_COLORED).toBool(); } void StyledBar::paintEvent(QPaintEvent *event) diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index 38a1b179319..315d9efb23e 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -669,12 +669,12 @@ QLinearGradient StyleHelper::statusBarGradient(const QRect &statusBarRect) void StyleHelper::setPanelWidget(QWidget *widget, bool value) { - widget->setProperty("panelwidget", value); + widget->setProperty(C_PANEL_WIDGET, value); } void StyleHelper::setPanelWidgetSingleRow(QWidget *widget, bool value) { - widget->setProperty("panelwidget_singlerow", value); + widget->setProperty(C_PANEL_WIDGET_SINGLE_ROW, value); } bool StyleHelper::isQDSTheme() diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h index 8ee91978b7e..9e7c3c19110 100644 --- a/src/libs/utils/stylehelper.h +++ b/src/libs/utils/stylehelper.h @@ -25,6 +25,21 @@ public: static const unsigned int DEFAULT_BASE_COLOR = 0x666666; static const int progressFadeAnimationDuration = 600; + constexpr static char C_ALIGN_ARROW[] = "alignarrow"; + constexpr static char C_DRAW_LEFT_BORDER[] = "drawleftborder"; + constexpr static char C_ELIDE_MODE[] = "elidemode"; + constexpr static char C_HIDE_BORDER[] = "hideborder"; + constexpr static char C_HIDE_ICON[] = "hideicon"; + constexpr static char C_HIGHLIGHT_WIDGET[] = "highlightWidget"; + constexpr static char C_LIGHT_COLORED[] = "lightColored"; + constexpr static char C_MINI_SPLITTER[] = "minisplitter"; + constexpr static char C_NOT_ELIDE_ASTERISK[] = "notelideasterisk"; + constexpr static char C_NO_ARROW[] = "noArrow"; + constexpr static char C_PANEL_WIDGET[] = "panelwidget"; + constexpr static char C_PANEL_WIDGET_SINGLE_ROW[] = "panelwidget_singlerow"; + constexpr static char C_SHOW_BORDER[] = "showborder"; + constexpr static char C_TOP_BORDER[] = "topBorder"; + enum ToolbarStyle { ToolbarStyleCompact, ToolbarStyleRelaxed, diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp index 95defb21ec4..431f5a3af89 100644 --- a/src/plugins/autotest/testnavigationwidget.cpp +++ b/src/plugins/autotest/testnavigationwidget.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -192,7 +193,7 @@ QList TestNavigationWidget::createToolButtons() m_filterButton = new QToolButton(m_view); m_filterButton->setIcon(Utils::Icons::FILTER.icon()); m_filterButton->setToolTip(Tr::tr("Filter Test Tree")); - m_filterButton->setProperty("noArrow", true); + m_filterButton->setProperty(StyleHelper::C_NO_ARROW, true); m_filterButton->setPopupMode(QToolButton::InstantPopup); m_filterMenu = new QMenu(m_filterButton); initializeFilterMenu(); diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp index 87d44b0f2f9..8997f43d1d3 100644 --- a/src/plugins/autotest/testresultspane.cpp +++ b/src/plugins/autotest/testresultspane.cpp @@ -197,7 +197,7 @@ void TestResultsPane::createToolButtons() m_filterButton = new QToolButton(m_treeView); m_filterButton->setIcon(Utils::Icons::FILTER.icon()); m_filterButton->setToolTip(Tr::tr("Filter Test Results")); - m_filterButton->setProperty("noArrow", true); + m_filterButton->setProperty(StyleHelper::C_NO_ARROW, true); m_filterButton->setPopupMode(QToolButton::InstantPopup); m_filterMenu = new QMenu(m_filterButton); initializeFilterMenu(); diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp index 6bd68d8710a..35086be7aaf 100644 --- a/src/plugins/clangtools/clangtoolsplugin.cpp +++ b/src/plugins/clangtools/clangtoolsplugin.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -171,7 +172,7 @@ void ClangToolsPlugin::registerAnalyzeActions() button->setPopupMode(QToolButton::InstantPopup); button->setIcon(icon); button->setToolTip(Tr::tr("Analyze File...")); - button->setProperty("noArrow", true); + button->setProperty(Utils::StyleHelper::C_NO_ARROW, true); widget->toolBar()->addWidget(button); const auto toolsMenu = new QMenu(widget); button->setMenu(toolsMenu); diff --git a/src/plugins/coreplugin/editortoolbar.cpp b/src/plugins/coreplugin/editortoolbar.cpp index fadfe4cae67..ee4d912d85c 100644 --- a/src/plugins/coreplugin/editortoolbar.cpp +++ b/src/plugins/coreplugin/editortoolbar.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -109,7 +110,7 @@ EditorToolBar::EditorToolBar(QWidget *parent) : d->m_lockButton->setEnabled(false); - d->m_dragHandle->setProperty("noArrow", true); + d->m_dragHandle->setProperty(Utils::StyleHelper::C_NO_ARROW, true); d->m_dragHandle->setToolTip(Tr::tr("Drag to drag documents between splits")); d->m_dragHandle->installEventFilter(this); d->m_dragHandleMenu = new QMenu(d->m_dragHandle); @@ -118,9 +119,9 @@ EditorToolBar::EditorToolBar(QWidget *parent) : connect(d->m_goBackAction, &QAction::triggered, this, &EditorToolBar::goBackClicked); connect(d->m_goForwardAction, &QAction::triggered, this, &EditorToolBar::goForwardClicked); - d->m_editorList->setProperty("hideicon", true); - d->m_editorList->setProperty("notelideasterisk", true); - d->m_editorList->setProperty("elidemode", Qt::ElideMiddle); + d->m_editorList->setProperty(Utils::StyleHelper::C_HIDE_ICON, true); + d->m_editorList->setProperty(Utils::StyleHelper::C_NOT_ELIDE_ASTERISK, true); + d->m_editorList->setProperty(Utils::StyleHelper::C_ELIDE_MODE, Qt::ElideMiddle); d->m_editorList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); d->m_editorList->setMinimumContentsLength(20); d->m_editorList->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); @@ -130,7 +131,7 @@ EditorToolBar::EditorToolBar(QWidget *parent) : d->m_closeEditorButton->setIcon(Utils::Icons::CLOSE_TOOLBAR.icon()); d->m_closeEditorButton->setEnabled(false); - d->m_closeEditorButton->setProperty("showborder", true); + d->m_closeEditorButton->setProperty(Utils::StyleHelper::C_SHOW_BORDER, true); d->m_toolBarPlaceholder->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); @@ -141,7 +142,7 @@ EditorToolBar::EditorToolBar(QWidget *parent) : d->m_splitButton->setIcon(Utils::Icons::SPLIT_HORIZONTAL_TOOLBAR.icon()); d->m_splitButton->setToolTip(Tr::tr("Split")); d->m_splitButton->setPopupMode(QToolButton::InstantPopup); - d->m_splitButton->setProperty("noArrow", true); + d->m_splitButton->setProperty(Utils::StyleHelper::C_NO_ARROW, true); auto splitMenu = new QMenu(d->m_splitButton); splitMenu->addAction(d->m_horizontalSplitAction); splitMenu->addAction(d->m_verticalSplitAction); diff --git a/src/plugins/coreplugin/find/findtoolbar.cpp b/src/plugins/coreplugin/find/findtoolbar.cpp index 27283434636..96a99f6eba7 100644 --- a/src/plugins/coreplugin/find/findtoolbar.cpp +++ b/src/plugins/coreplugin/find/findtoolbar.cpp @@ -158,7 +158,7 @@ FindToolBar::FindToolBar(CurrentDocumentFind *currentDocumentFind) mainLayout->setColumnStretch(1, 10); setFocusProxy(m_findEdit); - setProperty("topBorder", true); + setProperty(StyleHelper::C_TOP_BORDER, true); setSingleRow(false); QWidget::setTabOrder(m_findEdit, m_replaceEdit); diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 60a514f51d3..534c9e13bb2 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -621,7 +622,7 @@ QList SearchResultWindowPrivate::toolBarWidgets() m_historyLabel = new QLabel(Tr::tr("History:")); if (!m_recentSearchesBox) { m_recentSearchesBox = new QComboBox; - m_recentSearchesBox->setProperty("drawleftborder", true); + m_recentSearchesBox->setProperty(Utils::StyleHelper::C_DRAW_LEFT_BORDER, true); m_recentSearchesBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_recentSearchesBox->addItem(Tr::tr("New Search")); connect(m_recentSearchesBox, &QComboBox::activated, diff --git a/src/plugins/coreplugin/foldernavigationwidget.cpp b/src/plugins/coreplugin/foldernavigationwidget.cpp index fc7b86ab177..7460f427b5c 100644 --- a/src/plugins/coreplugin/foldernavigationwidget.cpp +++ b/src/plugins/coreplugin/foldernavigationwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -818,7 +819,7 @@ Core::NavigationView FolderNavigationWidgetFactory::createWidget() filter->setIcon(Utils::Icons::FILTER.icon()); filter->setToolTip(Tr::tr("Options")); filter->setPopupMode(QToolButton::InstantPopup); - filter->setProperty("noArrow", true); + filter->setProperty(StyleHelper::C_NO_ARROW, true); auto filterMenu = new QMenu(filter); filterMenu->addAction(fnw->m_filterHiddenFilesAction); filterMenu->addAction(fnw->m_showBreadCrumbsAction); diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 9cd74e84cfb..11687c49f87 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -57,7 +58,7 @@ static bool isInUnstyledDialogOrPopup(const QWidget *widget) { // Do not style contents of dialogs or popups without "panelwidget" property const QWidget *window = widget->window(); - if (window->property("panelwidget").toBool()) + if (window->property(StyleHelper::C_PANEL_WIDGET).toBool()) return false; const Qt::WindowType windowType = window->windowType(); return (windowType == Qt::Dialog || windowType == Qt::Popup); @@ -78,15 +79,15 @@ bool panelWidget(const QWidget *widget) if (qobject_cast(widget)) return styleEnabled(widget); - if (qobject_cast(widget)) - return widget->property("panelwidget_singlerow").toBool(); // See DebuggerMainWindowPrivate + if (qobject_cast(widget)) // See DebuggerMainWindowPrivate + return widget->property(StyleHelper::C_PANEL_WIDGET_SINGLE_ROW).toBool(); const QWidget *p = widget; while (p) { if (qobject_cast(p) || qobject_cast(p) || qobject_cast(p) || - p->property("panelwidget").toBool()) + p->property(StyleHelper::C_PANEL_WIDGET).toBool()) return styleEnabled(widget); p = p->parentWidget(); } @@ -121,7 +122,7 @@ bool lightColored(const QWidget *widget) const QWidget *p = widget; while (p) { - if (p->property("lightColored").toBool()) + if (p->property(StyleHelper::C_LIGHT_COLORED).toBool()) return true; p = p->parentWidget(); } @@ -417,7 +418,7 @@ QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *op switch (type) { case CT_Splitter: - if (widget && widget->property("minisplitter").toBool()) + if (widget && widget->property(StyleHelper::C_MINI_SPLITTER).toBool()) newSize = QSize(1, 1); break; case CT_ComboBox: @@ -538,7 +539,7 @@ int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, break; #endif case PM_SplitterWidth: - if (widget && widget->property("minisplitter").toBool()) + if (widget && widget->property(StyleHelper::C_MINI_SPLITTER).toBool()) retval = 1; break; case PM_ToolBarIconSize: @@ -672,7 +673,7 @@ void ManhattanStyle::polish(QWidget *widget) || qobject_cast(widget)) { widget->setPalette(panelPalette(widget->palette(), lightColored(widget))); } else if ((qobject_cast(widget) && !StyleHelper::isQDSTheme()) - || widget->property("panelwidget_singlerow").toBool()) { + || widget->property(StyleHelper::C_PANEL_WIDGET_SINGLE_ROW).toBool()) { widget->setFixedHeight(height); } else if (qobject_cast(widget)) { const bool flatAndNotCompact = @@ -689,7 +690,7 @@ void ManhattanStyle::polish(QWidget *widget) widget->setMaximumHeight(height - 2); widget->setAttribute(Qt::WA_Hover); } else if (qobject_cast(widget) - && widget->property("panelwidget_singlerow").toBool()) { + && widget->property(StyleHelper::C_PANEL_WIDGET_SINGLE_ROW).toBool()) { widget->setFixedHeight(height); } } @@ -767,7 +768,7 @@ int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const case QStyle::SH_ItemView_ActivateItemOnSingleClick: // default depends on the style if (widget) { - QVariant activationMode = widget->property("ActivationMode"); + QVariant activationMode = widget->property(activationModeC); if (activationMode.isValid()) ret = activationMode.toBool(); } @@ -1064,7 +1065,8 @@ void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element, anim->paint(painter, option); } else { const bool pressed = option->state & State_Sunken || option->state & State_On - || (widget && widget->property("highlightWidget").toBool()); + || (widget && widget->property(StyleHelper::C_HIGHLIGHT_WIDGET) + .toBool()); painter->setPen(StyleHelper::sidebarShadow()); if (pressed) { StyleHelper::drawPanelBgRect( @@ -1479,7 +1481,8 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt painter->save(); QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); QPalette customPal = cb->palette; - bool drawIcon = !(widget && widget->property("hideicon").toBool()); + const bool drawIcon = + !(widget && widget->property(StyleHelper::C_HIDE_ICON).toBool()); if (!cb->currentIcon.isNull() && drawIcon) { QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal @@ -1504,14 +1507,15 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt } Qt::TextElideMode elideMode = Qt::ElideRight; - if (widget && widget->dynamicPropertyNames().contains("elidemode")) - elideMode = widget->property("elidemode").value(); + if (widget && widget->dynamicPropertyNames().contains(StyleHelper::C_ELIDE_MODE)) + elideMode = widget->property(StyleHelper::C_ELIDE_MODE) + .value(); QLatin1Char asterisk('*'); int elideWidth = editRect.width(); bool notElideAsterisk = elideMode == Qt::ElideRight && widget - && widget->property("notelideasterisk").toBool() + && widget->property(StyleHelper::C_NOT_ELIDE_ASTERISK).toBool() && cb->currentText.endsWith(asterisk) && option->fontMetrics.horizontalAdvance(cb->currentText) > elideWidth; @@ -1633,7 +1637,7 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt : StyleHelper::sidebarHighlight(); const QColor borderColor = drawLightColored ? QColor(255, 255, 255, 180) : hightLight; - if (widget && widget->property("topBorder").toBool()) { + if (widget && widget->property(StyleHelper::C_TOP_BORDER).toBool()) { painter->drawLine(borderRect.topLeft(), borderRect.topRight()); painter->setPen(borderColor); painter->drawLine(borderRect.topLeft() + QPointF(0, 1), borderRect.topRight() + QPointF(0, 1)); @@ -1649,7 +1653,7 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt } if (creatorTheme()->flag(Theme::DrawToolBarBorders)) { painter->setPen(StyleHelper::toolBarBorderColor()); - if (widget && widget->property("topBorder").toBool()) + if (widget && widget->property(StyleHelper::C_TOP_BORDER).toBool()) painter->drawLine(borderRect.topLeft(), borderRect.topRight()); else painter->drawLine(borderRect.bottomLeft(), borderRect.bottomRight()); @@ -1678,7 +1682,8 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti case CC_ToolButton: if (const auto toolbutton = qstyleoption_cast(option)) { bool reverse = option->direction == Qt::RightToLeft; - bool drawborder = (widget && widget->property("showborder").toBool()); + const bool drawborder = + (widget && widget->property(StyleHelper::C_SHOW_BORDER).toBool()); if (drawborder) drawButtonSeparator(painter, rect, reverse); @@ -1712,7 +1717,7 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti QStyleOptionToolButton label = *toolbutton; label.palette = panelPalette(option->palette, lightColored(widget)); - if (widget && widget->property("highlightWidget").toBool()) { + if (widget && widget->property(StyleHelper::C_HIGHLIGHT_WIDGET).toBool()) { label.palette.setColor(QPalette::ButtonText, creatorTheme()->color(Theme::IconsWarningToolBarColor)); } @@ -1739,7 +1744,7 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti tool.rect = tool.rect.adjusted(2, 2, -2, -2); drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget); } else if (toolbutton->features & QStyleOptionToolButton::HasMenu - && widget && !widget->property("noArrow").toBool()) { + && widget && !widget->property(StyleHelper::C_NO_ARROW).toBool()) { int arrowSize = 6; QRect ir = toolbutton->rect.adjusted(1, 1, -1, -1); QStyleOptionToolButton newBtn = *toolbutton; @@ -1756,9 +1761,12 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti painter->save(); bool isEmpty = cb->currentText.isEmpty() && cb->currentIcon.isNull(); bool reverse = option->direction == Qt::RightToLeft; - bool drawborder = !(widget && widget->property("hideborder").toBool()); - bool drawleftborder = (widget && widget->property("drawleftborder").toBool()); - bool alignarrow = !(widget && widget->property("alignarrow").toBool()); + const bool drawborder = + !(widget && widget->property(StyleHelper::C_HIDE_BORDER).toBool()); + const bool drawleftborder = + (widget && widget->property(StyleHelper::C_DRAW_LEFT_BORDER).toBool()); + const bool alignarrow = + !(widget && widget->property(StyleHelper::C_ALIGN_ARROW).toBool()); if (drawborder) { drawButtonSeparator(painter, rect, reverse); diff --git a/src/plugins/coreplugin/minisplitter.cpp b/src/plugins/coreplugin/minisplitter.cpp index d589a7dfc62..e4e9db129bb 100644 --- a/src/plugins/coreplugin/minisplitter.cpp +++ b/src/plugins/coreplugin/minisplitter.cpp @@ -84,7 +84,7 @@ MiniSplitter::MiniSplitter(QWidget *parent, SplitterStyle style) { setHandleWidth(1); setChildrenCollapsible(false); - setProperty("minisplitter", true); + setProperty(Utils::StyleHelper::C_MINI_SPLITTER, true); } MiniSplitter::MiniSplitter(Qt::Orientation orientation, QWidget *parent, SplitterStyle style) @@ -93,7 +93,7 @@ MiniSplitter::MiniSplitter(Qt::Orientation orientation, QWidget *parent, Splitte { setHandleWidth(1); setChildrenCollapsible(false); - setProperty("minisplitter", true); + setProperty(Utils::StyleHelper::C_MINI_SPLITTER, true); } /*! diff --git a/src/plugins/coreplugin/navigationsubwidget.cpp b/src/plugins/coreplugin/navigationsubwidget.cpp index 1d5b0e4bb68..838635c7b2f 100644 --- a/src/plugins/coreplugin/navigationsubwidget.cpp +++ b/src/plugins/coreplugin/navigationsubwidget.cpp @@ -11,6 +11,7 @@ #include "navigationwidget.h" #include +#include #include #include @@ -53,7 +54,7 @@ NavigationSubWidget::NavigationSubWidget(NavigationWidget *parentWidget, int pos splitAction->setIcon(Utils::Icons::SPLIT_HORIZONTAL_TOOLBAR.icon()); splitAction->setToolTip(Tr::tr("Split")); splitAction->setPopupMode(QToolButton::InstantPopup); - splitAction->setProperty("noArrow", true); + splitAction->setProperty(StyleHelper::C_NO_ARROW, true); m_splitMenu = new QMenu(splitAction); splitAction->setMenu(m_splitMenu); connect(m_splitMenu, &QMenu::aboutToShow, this, &NavigationSubWidget::populateSplitMenu); diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 9aa98c7189a..96f97feea3b 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -684,13 +685,13 @@ void CppEditorWidget::updateWidgetHighlighting(QWidget *widget, bool highlight) if (!widget) return; - widget->setProperty("highlightWidget", highlight); + widget->setProperty(StyleHelper::C_HIGHLIGHT_WIDGET, highlight); widget->update(); } bool CppEditorWidget::isWidgetHighlighted(QWidget *widget) { - return widget ? widget->property("highlightWidget").toBool() : false; + return widget ? widget->property(StyleHelper::C_HIGHLIGHT_WIDGET).toBool() : false; } namespace { diff --git a/src/plugins/ctfvisualizer/ctfvisualizertool.cpp b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp index 0fbc5cac650..05cf55d729f 100644 --- a/src/plugins/ctfvisualizer/ctfvisualizertool.cpp +++ b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp @@ -15,6 +15,8 @@ #include #include #include + +#include #include #include @@ -64,7 +66,7 @@ CtfVisualizerTool::CtfVisualizerTool() m_restrictToThreadsButton->setIcon(Utils::Icons::FILTER.icon()); m_restrictToThreadsButton->setToolTip(Tr::tr("Restrict to Threads")); m_restrictToThreadsButton->setPopupMode(QToolButton::InstantPopup); - m_restrictToThreadsButton->setProperty("noArrow", true); + m_restrictToThreadsButton->setProperty(Utils::StyleHelper::C_NO_ARROW, true); m_restrictToThreadsButton->setMenu(m_restrictToThreadsMenu); connect(m_restrictToThreadsMenu, &QMenu::triggered, this, &CtfVisualizerTool::toggleThreadRestriction); diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 554ad397b0f..2a5ec866edb 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -201,7 +201,7 @@ DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent) closeButton->setToolTip(Tr::tr("Leave Debug Mode")); auto toolbar = new Utils::StyledBar; - toolbar->setProperty("topBorder", true); + toolbar->setProperty(StyleHelper::C_TOP_BORDER, true); // "Engine switcher" style comboboxes auto subPerspectiveSwitcher = new QWidget; diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index ce3bca34858..5d437968c92 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -179,7 +180,7 @@ QList BranchView::createToolButtons() filter->setIcon(Utils::Icons::FILTER.icon()); filter->setToolTip(Tr::tr("Filter")); filter->setPopupMode(QToolButton::InstantPopup); - filter->setProperty("noArrow", true); + filter->setProperty(StyleHelper::C_NO_ARROW, true); auto filterMenu = new QMenu(filter); filterMenu->addAction(m_includeOldEntriesAction); @@ -188,11 +189,11 @@ QList BranchView::createToolButtons() auto addButton = new QToolButton; addButton->setDefaultAction(m_addAction); - addButton->setProperty("noArrow", true); + addButton->setProperty(StyleHelper::C_NO_ARROW, true); auto refreshButton = new QToolButton; refreshButton->setDefaultAction(m_refreshAction); - refreshButton->setProperty("noArrow", true); + refreshButton->setProperty(StyleHelper::C_NO_ARROW, true); return {filter, addButton, refreshButton}; } diff --git a/src/plugins/help/helpwidget.cpp b/src/plugins/help/helpwidget.cpp index 571964d0b3e..67b42232c90 100644 --- a/src/plugins/help/helpwidget.cpp +++ b/src/plugins/help/helpwidget.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -319,7 +320,7 @@ HelpWidget::HelpWidget(const Core::Context &context, WidgetStyle style, QWidget cmd = Core::ActionManager::registerAction(helpTargetAction, "Help.OpenContextHelpHere", context); QToolButton *helpTargetButton = Core::Command::toolButtonWithAppendedShortcut(helpTargetAction, cmd); - helpTargetButton->setProperty("noArrow", true); + helpTargetButton->setProperty(Utils::StyleHelper::C_NO_ARROW, true); helpTargetButton->setPopupMode(QToolButton::DelayedPopup); helpTargetButton->setMenu(createHelpTargetMenu(helpTargetButton)); connect(LocalHelpManager::instance(), @@ -416,7 +417,7 @@ HelpWidget::HelpWidget(const Core::Context &context, WidgetStyle style, QWidget auto openButton = new QToolButton; openButton->setIcon(Utils::Icons::SPLIT_HORIZONTAL_TOOLBAR.icon()); openButton->setPopupMode(QToolButton::InstantPopup); - openButton->setProperty("noArrow", true); + openButton->setProperty(Utils::StyleHelper::C_NO_ARROW, true); layout->addWidget(openButton); auto openMenu = new QMenu(openButton); openButton->setMenu(openMenu); diff --git a/src/plugins/imageviewer/imageviewer.cpp b/src/plugins/imageviewer/imageviewer.cpp index 9c19b0ffbf8..5d4a068e717 100644 --- a/src/plugins/imageviewer/imageviewer.cpp +++ b/src/plugins/imageviewer/imageviewer.cpp @@ -17,8 +17,9 @@ #include #include -#include #include +#include +#include #include #include @@ -112,7 +113,7 @@ void ImageViewer::ctor() d->shareButton->setToolTip(Tr::tr("Export")); d->shareButton->setPopupMode(QToolButton::InstantPopup); d->shareButton->setIcon(Icons::EXPORTFILE_TOOLBAR.icon()); - d->shareButton->setProperty("noArrow", true); + d->shareButton->setProperty(StyleHelper::C_NO_ARROW, true); auto shareMenu = new QMenu(d->shareButton); shareMenu->addAction(d->actionExportImage); shareMenu->addAction(d->actionMultiExportImages); diff --git a/src/plugins/perfprofiler/perfprofilertool.cpp b/src/plugins/perfprofiler/perfprofilertool.cpp index 57a829ed605..60bbcc3ae31 100644 --- a/src/plugins/perfprofiler/perfprofilertool.cpp +++ b/src/plugins/perfprofiler/perfprofilertool.cpp @@ -256,7 +256,7 @@ void PerfProfilerTool::createViews() m_filterButton->setIcon(Utils::Icons::FILTER.icon()); m_filterButton->setPopupMode(QToolButton::InstantPopup); - m_filterButton->setProperty("noArrow", true); + m_filterButton->setProperty(StyleHelper::C_NO_ARROW, true); m_filterButton->setMenu(m_filterMenu); m_aggregateButton->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon()); diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index 28c06e9254d..a3d608ebd80 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -420,7 +421,7 @@ QList ProjectTreeWidget::createToolButtons() filter->setIcon(Icons::FILTER.icon()); filter->setToolTip(Tr::tr("Filter Tree")); filter->setPopupMode(QToolButton::InstantPopup); - filter->setProperty("noArrow", true); + filter->setProperty(StyleHelper::C_NO_ARROW, true); auto filterMenu = new QMenu(filter); filterMenu->addAction(m_filterProjectsAction); diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 5f1c6aa9e00..60ad28ec7ef 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -217,7 +217,7 @@ TaskWindow::TaskWindow() : d(std::make_unique()) d->m_categoriesButton = new QToolButton; d->m_categoriesButton->setIcon(Utils::Icons::FILTER.icon()); d->m_categoriesButton->setToolTip(Tr::tr("Filter by categories")); - d->m_categoriesButton->setProperty("noArrow", true); + d->m_categoriesButton->setProperty(StyleHelper::C_NO_ARROW, true); d->m_categoriesButton->setPopupMode(QToolButton::InstantPopup); d->m_categoriesMenu = new QMenu(d->m_categoriesButton); diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index ca6b606616a..d23685bc3b7 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -120,7 +122,7 @@ private: PythonEditorWidget::PythonEditorWidget(QWidget *parent) : TextEditorWidget(parent) { auto replButton = new QToolButton(this); - replButton->setProperty("noArrow", true); + replButton->setProperty(StyleHelper::C_NO_ARROW, true); replButton->setText(Tr::tr("REPL")); replButton->setPopupMode(QToolButton::InstantPopup); replButton->setToolTip(Tr::tr("Open interactive Python. Either importing nothing, " @@ -175,7 +177,7 @@ void PythonEditorWidget::updateInterpretersSelector() m_interpreters->setMenu(new QMenu(m_interpreters)); m_interpreters->setPopupMode(QToolButton::InstantPopup); m_interpreters->setToolButtonStyle(Qt::ToolButtonTextOnly); - m_interpreters->setProperty("noArrow", true); + m_interpreters->setProperty(StyleHelper::C_NO_ARROW, true); } QMenu *menu = m_interpreters->menu(); diff --git a/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp b/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp index 3d0464778d3..e967be04ec8 100644 --- a/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp +++ b/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include #include @@ -123,7 +125,7 @@ QWidget *ZoomAction::createWidget(QWidget *parent) { if (!m_combo && parentIsToolBar(parent)) { m_combo = createZoomComboBox(parent); - m_combo->setProperty("hideborder", true); + m_combo->setProperty(Utils::StyleHelper::C_HIDE_BORDER, true); m_combo->setCurrentIndex(m_index); m_combo->setToolTip(m_combo->currentText()); diff --git a/src/plugins/qmldesigner/components/formeditor/backgroundaction.cpp b/src/plugins/qmldesigner/components/formeditor/backgroundaction.cpp index 7403c239b35..a9d72be8ddb 100644 --- a/src/plugins/qmldesigner/components/formeditor/backgroundaction.cpp +++ b/src/plugins/qmldesigner/components/formeditor/backgroundaction.cpp @@ -3,6 +3,8 @@ #include "backgroundaction.h" +#include + #include #include @@ -52,7 +54,7 @@ QWidget *BackgroundAction::createWidget(QWidget *parent) connect(comboBox, &QComboBox::currentIndexChanged, this, &BackgroundAction::emitBackgroundChanged); - comboBox->setProperty("hideborder", true); + comboBox->setProperty(Utils::StyleHelper::C_HIDE_BORDER, true); comboBox->setToolTip(tr("Set the color of the canvas.")); m_comboBox = comboBox; return comboBox; diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index a82b6d74e0e..f003d5f0e40 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -191,7 +191,7 @@ QmlProfilerTool::QmlProfilerTool() d->m_displayFeaturesButton->setIcon(Utils::Icons::FILTER.icon()); d->m_displayFeaturesButton->setToolTip(Tr::tr("Hide or show event categories.")); d->m_displayFeaturesButton->setPopupMode(QToolButton::InstantPopup); - d->m_displayFeaturesButton->setProperty("noArrow", true); + d->m_displayFeaturesButton->setProperty(StyleHelper::C_NO_ARROW, true); d->m_displayFeaturesMenu = new QMenu(d->m_displayFeaturesButton); d->m_displayFeaturesButton->setMenu(d->m_displayFeaturesMenu); connect(d->m_displayFeaturesMenu, &QMenu::triggered, diff --git a/src/plugins/squish/squishoutputpane.cpp b/src/plugins/squish/squishoutputpane.cpp index 0b10967afa2..8c8047f47f4 100644 --- a/src/plugins/squish/squishoutputpane.cpp +++ b/src/plugins/squish/squishoutputpane.cpp @@ -319,7 +319,7 @@ void SquishOutputPane::createToolButtons() Utils::StyleHelper::setPanelWidget(m_filterButton); m_filterButton->setIcon(Utils::Icons::FILTER.icon()); m_filterButton->setToolTip(Tr::tr("Filter Test Results")); - m_filterButton->setProperty("noArrow", true); + m_filterButton->setProperty(Utils::StyleHelper::C_NO_ARROW, true); m_filterButton->setAutoRaise(true); m_filterButton->setPopupMode(QToolButton::InstantPopup); m_filterMenu = new QMenu(m_filterButton); diff --git a/src/plugins/texteditor/outlinefactory.cpp b/src/plugins/texteditor/outlinefactory.cpp index 2a39d7edfd0..bc9aa03c8ba 100644 --- a/src/plugins/texteditor/outlinefactory.cpp +++ b/src/plugins/texteditor/outlinefactory.cpp @@ -72,7 +72,7 @@ OutlineWidgetStack::OutlineWidgetStack(OutlineFactory *factory) : m_filterButton->setIcon(Utils::Icons::FILTER.icon()); m_filterButton->setToolTip(Tr::tr("Filter tree")); m_filterButton->setPopupMode(QToolButton::InstantPopup); - m_filterButton->setProperty("noArrow", true); + m_filterButton->setProperty(Utils::StyleHelper::C_NO_ARROW, true); m_filterMenu = new QMenu(m_filterButton); m_filterButton->setMenu(m_filterMenu); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index e0702ef9720..529bac9d6b3 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -609,7 +610,7 @@ MemcheckToolPrivate::MemcheckToolPrivate() filterButton->setIcon(Icons::FILTER.icon()); filterButton->setText(Tr::tr("Error Filter")); filterButton->setPopupMode(QToolButton::InstantPopup); - filterButton->setProperty("noArrow", true); + filterButton->setProperty(StyleHelper::C_NO_ARROW, true); m_filterMenu = new QMenu(filterButton); for (QAction *filterAction : std::as_const(m_errorFilterActions)) From e44d0c57dc849c3d18d6b1babfbd8197490d4de2 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 9 May 2023 17:38:23 +0200 Subject: [PATCH 0952/1447] Utils: Fix the applying of new base color at run-time If the base color was changed via the color picker that opens with shift-click on the upper left toolbar area, some widgets were not instantly updated with the new color. This change ensures that all (visible) widgets instead of just all top level windows get updated after changing the color. While this method is potentially more expensive, it does not effect the start-up negatively, because on start-up StyleHelper::setBaseColor() gets called before the mainwindow is shown. Fixes: QTCREATORBUG-29135 Change-Id: I227c2f243ffcd9f8210b9d2d1a47ad0494663d50 Reviewed-by: Christian Stenger --- src/libs/utils/stylehelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index 315d9efb23e..43f14222ac1 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -190,7 +190,7 @@ void StyleHelper::setBaseColor(const QColor &newcolor) if (color.isValid() && color != m_baseColor) { m_baseColor = color; - const QList widgets = QApplication::topLevelWidgets(); + const QWidgetList widgets = QApplication::allWidgets(); for (QWidget *w : widgets) w->update(); } From c2265077f661ffe0cc48736d756fdf631aea51bd Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 17:36:03 +0200 Subject: [PATCH 0953/1447] TestSettings: Use functor to apply changed settings Baby-steps towards use of aspects. Change-Id: I08a0db083c29e754cf58a631dc3a5c36f400ee96 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger --- src/plugins/autotest/testsettingspage.cpp | 87 ++++++++++------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp index e07fdc51f79..be6c4244575 100644 --- a/src/plugins/autotest/testsettingspage.cpp +++ b/src/plugins/autotest/testsettingspage.cpp @@ -37,10 +37,6 @@ class TestSettingsWidget : public Core::IOptionsPageWidget public: explicit TestSettingsWidget(TestSettings *settings); - void apply() final; - - TestSettings settings() const; - private: void populateFrameworksListWidget(const QHash &frameworks, const QHash &testTools); @@ -218,27 +214,46 @@ TestSettingsWidget::TestSettingsWidget(TestSettings *settings) m_openResultsOnFailCB->setChecked(settings->popupOnFail); m_runAfterBuildCB->setCurrentIndex(int(settings->runAfterBuild)); populateFrameworksListWidget(settings->frameworks, settings->tools); -} -TestSettings TestSettingsWidget::settings() const -{ - TestSettings result; - result.timeout = m_timeoutSpin->value() * 1000; // we display seconds - result.omitInternalMssg = m_omitInternalMsgCB->isChecked(); - result.omitRunConfigWarn = m_omitRunConfigWarnCB->isChecked(); - result.limitResultOutput = m_limitResultOutputCB->isChecked(); - result.limitResultDescription = m_limitResultDescriptionCb->isChecked(); - result.resultDescriptionMaxSize = m_limitResultDescriptionSpinBox->value(); - result.autoScroll = m_autoScrollCB->isChecked(); - result.processArgs = m_processArgsCB->isChecked(); - result.displayApplication = m_displayAppCB->isChecked(); - result.popupOnStart = m_openResultsOnStartCB->isChecked(); - result.popupOnFinish = m_openResultsOnFinishCB->isChecked(); - result.popupOnFail = m_openResultsOnFailCB->isChecked(); - result.runAfterBuild = RunAfterBuildMode(m_runAfterBuildCB->currentIndex()); - testSettings(result); - testToolsSettings(result); - return result; + setOnApply([this] { + TestSettings result; + result.timeout = m_timeoutSpin->value() * 1000; // we display seconds + result.omitInternalMssg = m_omitInternalMsgCB->isChecked(); + result.omitRunConfigWarn = m_omitRunConfigWarnCB->isChecked(); + result.limitResultOutput = m_limitResultOutputCB->isChecked(); + result.limitResultDescription = m_limitResultDescriptionCb->isChecked(); + result.resultDescriptionMaxSize = m_limitResultDescriptionSpinBox->value(); + result.autoScroll = m_autoScrollCB->isChecked(); + result.processArgs = m_processArgsCB->isChecked(); + result.displayApplication = m_displayAppCB->isChecked(); + result.popupOnStart = m_openResultsOnStartCB->isChecked(); + result.popupOnFinish = m_openResultsOnFinishCB->isChecked(); + result.popupOnFail = m_openResultsOnFailCB->isChecked(); + result.runAfterBuild = RunAfterBuildMode(m_runAfterBuildCB->currentIndex()); + testSettings(result); + testToolsSettings(result); + + const QList changedIds = Utils::filtered(result.frameworksGrouping.keys(), + [result, this](Utils::Id id) { + return result.frameworksGrouping[id] != m_settings->frameworksGrouping[id]; + }); + + *m_settings = result; + m_settings->toSettings(Core::ICore::settings()); + + for (ITestFramework *framework : TestFrameworkManager::registeredFrameworks()) { + framework->setActive(m_settings->frameworks.value(framework->id(), false)); + framework->setGrouping(m_settings->frameworksGrouping.value(framework->id(), false)); + } + + for (ITestTool *testTool : TestFrameworkManager::registeredTestTools()) + testTool->setActive(m_settings->tools.value(testTool->id(), false)); + + TestTreeModel::instance()->synchronizeTestFrameworks(); + TestTreeModel::instance()->synchronizeTestTools(); + if (!changedIds.isEmpty()) + TestTreeModel::instance()->rebuild(changedIds); + }); } enum TestBaseInfo @@ -339,30 +354,6 @@ void TestSettingsWidget::onFrameworkItemChanged() || (mixed == (ITestBase::Framework | ITestBase::Tool))); } -void TestSettingsWidget::apply() -{ - const TestSettings newSettings = settings(); - const QList changedIds = Utils::filtered(newSettings.frameworksGrouping.keys(), - [newSettings, this](const Id &id) { - return newSettings.frameworksGrouping[id] != m_settings->frameworksGrouping[id]; - }); - *m_settings = newSettings; - m_settings->toSettings(Core::ICore::settings()); - - for (ITestFramework *framework : TestFrameworkManager::registeredFrameworks()) { - framework->setActive(m_settings->frameworks.value(framework->id(), false)); - framework->setGrouping(m_settings->frameworksGrouping.value(framework->id(), false)); - } - - for (ITestTool *testTool : TestFrameworkManager::registeredTestTools()) - testTool->setActive(m_settings->tools.value(testTool->id(), false)); - - TestTreeModel::instance()->synchronizeTestFrameworks(); - TestTreeModel::instance()->synchronizeTestTools(); - if (!changedIds.isEmpty()) - TestTreeModel::instance()->rebuild(changedIds); -} - // TestSettingsPage TestSettingsPage::TestSettingsPage(TestSettings *settings) From 6891f0f157e9b3f8ef60918a322671b8390a27b7 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 15:32:17 +0200 Subject: [PATCH 0954/1447] AutoTest: Remove layout hack from CatchTestSettings page Does not look needed anymore. Change-Id: Ie00b60521b7e41039161978b195d00d2162ce95b Reviewed-by: Christian Stenger --- src/plugins/autotest/catch/catchtestsettings.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp index 6fd0cde16d5..e3e2c000db4 100644 --- a/src/plugins/autotest/catch/catchtestsettings.cpp +++ b/src/plugins/autotest/catch/catchtestsettings.cpp @@ -106,12 +106,6 @@ CatchTestSettings::CatchTestSettings() warnOnEmpty.setSettingsKey("WarnEmpty"); warnOnEmpty.setLabelText(Tr::tr("Warn on empty tests")); warnOnEmpty.setToolTip(Tr::tr("Warns if a test section does not check any assertion.")); - - forEachAspect([](BaseAspect *aspect) { - // FIXME: Make the positioning part of the LayoutBuilder later - if (auto boolAspect = dynamic_cast(aspect)) - boolAspect->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); - }); } CatchTestSettingsPage::CatchTestSettingsPage(CatchTestSettings *settings, Id settingsId) From 529ade9f08b69726ad0e5a4a3e2b49fabee7e7a8 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 8 May 2023 17:33:22 +0200 Subject: [PATCH 0955/1447] Android: Use functor to apply changed settings Change-Id: I12a62dd4aa34ba3c23b0569e3b2724c2d7415ded Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Alessandro Portale --- src/plugins/android/androidsettingswidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 2ebc61802de..dfb14c49cfc 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -145,8 +145,6 @@ public: ~AndroidSettingsWidget() final; private: - void apply() final { AndroidConfigurations::setConfig(m_androidConfig); } - void showEvent(QShowEvent *event) override; void validateJdk(); @@ -450,6 +448,8 @@ AndroidSettingsWidget::AndroidSettingsWidget() delete openSslOneShot; }); }); + + setOnApply([this] { AndroidConfigurations::setConfig(m_androidConfig); }); } AndroidSettingsWidget::~AndroidSettingsWidget() From fb3b9d2268902d4a6f29f6ec9f0465dd3a928bba Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:10:50 +0200 Subject: [PATCH 0956/1447] CommandLocator: Remove the old matchesFor() implementation Change-Id: Ide5f9141bc756059aadc561800b34e7c4fffa5cf Reviewed-by: Orgad Shaneh Reviewed-by: Reviewed-by: Qt CI Bot --- .../coreplugin/locator/commandlocator.cpp | 86 +------------------ .../coreplugin/locator/commandlocator.h | 16 +--- 2 files changed, 8 insertions(+), 94 deletions(-) diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 9d076c13060..e960b4df85d 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -5,7 +5,6 @@ #include -#include #include #include @@ -14,47 +13,22 @@ using namespace Utils; namespace Core { -struct CommandLocatorPrivate -{ - QList commands; - QList> commandsData; -}; - -/*! - \class Core::CommandLocator - \inmodule QtCreator - \internal -*/ - -CommandLocator::CommandLocator(Id id, - const QString &displayName, - const QString &shortCutString, - QObject *parent) : - ILocatorFilter(parent), - d(new CommandLocatorPrivate) +CommandLocator::CommandLocator(Id id, const QString &displayName, const QString &shortCutString, + QObject *parent) + : ILocatorFilter(parent) { setId(id); setDisplayName(displayName); setDefaultShortcutString(shortCutString); } -CommandLocator::~CommandLocator() -{ - delete d; -} - -void CommandLocator::appendCommand(Command *cmd) -{ - d->commands.push_back(cmd); -} - LocatorMatcherTasks CommandLocator::matchers() { using namespace Tasking; TreeStorage storage; - const auto onSetup = [storage, commands = d->commands] { + const auto onSetup = [storage, commands = m_commands] { const QString input = storage->input(); const Qt::CaseSensitivity inputCaseSensitivity = caseSensitivity(input); LocatorFilterEntries goodEntries; @@ -93,56 +67,4 @@ LocatorMatcherTasks CommandLocator::matchers() return {{Sync(onSetup), storage}}; } -void CommandLocator::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - d->commandsData = {}; - const int count = d->commands.size(); - // Get active, enabled actions matching text, store in list. - // Reference via index in extraInfo. - for (int i = 0; i < count; ++i) { - Command *command = d->commands.at(i); - if (!command->isActive()) - continue; - QAction *action = command->action(); - if (action && action->isEnabled()) - d->commandsData.append({action, action->text()}); - } -} - -QList CommandLocator::matchesFor(QFutureInterface &future, const QString &entry) -{ - QList goodEntries; - QList betterEntries; - const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); - for (const auto &pair : std::as_const(d->commandsData)) { - if (future.isCanceled()) - break; - - const QString text = Utils::stripAccelerator(pair.second); - const int index = text.indexOf(entry, 0, entryCaseSensitivity); - if (index >= 0) { - QAction *action = pair.first; - LocatorFilterEntry filterEntry; - filterEntry.displayName = text; - filterEntry.acceptor = [action] { - // avoid nested stack trace and blocking locator by delayed triggering - QMetaObject::invokeMethod(action, [action] { - if (action->isEnabled()) - action->trigger(); - }, Qt::QueuedConnection); - return AcceptResult(); - }; - filterEntry.highlightInfo = {index, int(entry.length())}; - - if (index == 0) - betterEntries.append(filterEntry); - else - goodEntries.append(filterEntry); - } - } - betterEntries.append(goodEntries); - return betterEntries; -} - } // namespace Core diff --git a/src/plugins/coreplugin/locator/commandlocator.h b/src/plugins/coreplugin/locator/commandlocator.h index a1cadbd4b77..8e7d1ead035 100644 --- a/src/plugins/coreplugin/locator/commandlocator.h +++ b/src/plugins/coreplugin/locator/commandlocator.h @@ -10,26 +10,18 @@ namespace Core { /* Command locators: Provides completion for a set of * Core::Command's by sub-string of their action's text. */ class Command; -struct CommandLocatorPrivate; class CORE_EXPORT CommandLocator : public ILocatorFilter { - Q_OBJECT - public: - CommandLocator(Utils::Id id, const QString &displayName, - const QString &shortCutString, QObject *parent = nullptr); - ~CommandLocator() override; + CommandLocator(Utils::Id id, const QString &displayName, const QString &shortCutString, + QObject *parent = nullptr); + void appendCommand(Command *cmd) { m_commands.push_back(cmd); } - void appendCommand(Command *cmd); - - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: LocatorMatcherTasks matchers() final; - CommandLocatorPrivate *d = nullptr; + QList m_commands; }; } // namespace Core From 699b804181e3554a13e5b16f59122e90b672b96e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 16:27:47 +0200 Subject: [PATCH 0957/1447] ProjectExplorer: Rename 'Device' into 'Run device' in Kit settings Similar for 'Run device type'. Less ambiguity. Change-Id: Iab88009b92ae760f14140ac8bbdadea51d6dfad4 Reviewed-by: Christian Kandeler Reviewed-by: Eike Ziller Reviewed-by: Leena Miettinen --- doc/qtcreator/src/linux-mobile/linuxdev.qdoc | 2 +- .../src/projects/creator-only/creator-projects-targets.qdoc | 6 +++--- doc/qtcreator/src/webassembly/creator-webassembly.qdoc | 2 +- src/plugins/projectexplorer/kitinformation.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/qtcreator/src/linux-mobile/linuxdev.qdoc b/doc/qtcreator/src/linux-mobile/linuxdev.qdoc index b874866f60c..028619c7fad 100644 --- a/doc/qtcreator/src/linux-mobile/linuxdev.qdoc +++ b/doc/qtcreator/src/linux-mobile/linuxdev.qdoc @@ -111,7 +111,7 @@ \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Kits > \uicontrol Add to add a kit for building for the device. Select the Qt version, compiler, and device that you added above, and select - \uicontrol {Remote Linux Device} in \uicontrol {Device type}. + \uicontrol {Remote Linux Device} in \uicontrol {Run device type}. To build on the remote device, select \uicontrol {Remote Linux Device} also in \uicontrol {Build device}. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc index 04b639f1dd3..08a6d988207 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc @@ -97,8 +97,8 @@ used for the \c CurrentKit:FileSystemName variable, which determines the name of the shadow build directory, for example. \row - \li \uicontrol{Device type} - \li Type of the device. + \li \uicontrol{Run device type} + \li Type of the run device. Double-click the icon next to the field to select the image that is displayed in the kit selector for this kit. You can use any @@ -107,7 +107,7 @@ logo as an icon allows you to easily see, which compiler is used to build the project for the selected kit. \row - \li \uicontrol Device + \li \uicontrol {Run device} \li The device to run applications on. \row \li \uicontrol {Build device} diff --git a/doc/qtcreator/src/webassembly/creator-webassembly.qdoc b/doc/qtcreator/src/webassembly/creator-webassembly.qdoc index d01c038ce5b..c05f84832e5 100644 --- a/doc/qtcreator/src/webassembly/creator-webassembly.qdoc +++ b/doc/qtcreator/src/webassembly/creator-webassembly.qdoc @@ -95,7 +95,7 @@ \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Kits > \uicontrol Add. \li In the \uicontrol Name field, specify a name for the kit. - \li In the \uicontrol {Device type} field, select + \li In the \uicontrol {Run device type} field, select \uicontrol {WebAssembly Runtime}. The value of the \uicontrol Device field is automatically set to \uicontrol {Web Browser}. diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index bd4a4c70525..fc8039b402d 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -794,7 +794,7 @@ DeviceTypeKitAspect::DeviceTypeKitAspect() { setObjectName(QLatin1String("DeviceTypeInformation")); setId(DeviceTypeKitAspect::id()); - setDisplayName(Tr::tr("Device type")); + setDisplayName(Tr::tr("Run device type")); setDescription(Tr::tr("The type of device to run applications on.")); setPriority(33000); makeEssential(); @@ -941,7 +941,7 @@ DeviceKitAspect::DeviceKitAspect() { setObjectName(QLatin1String("DeviceInformation")); setId(DeviceKitAspect::id()); - setDisplayName(Tr::tr("Device")); + setDisplayName(Tr::tr("Run device")); setDescription(Tr::tr("The device to run the applications on.")); setPriority(32000); From 3f5d33fe5c2c8e5dfde6e8478102acde6b1b2e57 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 15:17:03 +0200 Subject: [PATCH 0958/1447] CppEditor: Fix an error raised by Clang 16 error: integer value -1 is outside the valid range of values [0, 255] for this enumeration type [-Wenum-constexpr-conversion] Change-Id: I1b029099634dcc8f11071aad6a974ec0c41077ce Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppquickfixes.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 3dae225cea3..4410ab60a8b 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -3697,6 +3697,7 @@ public: GenerateProperty = 1 << 5, GenerateConstantProperty = 1 << 6, HaveExistingQProperty = 1 << 7, + Invalid = -1, }; GenerateGetterSetterOp(const CppQuickFixInterface &interface, @@ -4394,7 +4395,7 @@ public: }; using Flag = GenerateGetterSetterOp::GenerateFlag; constexpr static Flag ColumnFlag[] = { - static_cast(-1), + Flag::Invalid, Flag::GenerateGetter, Flag::GenerateSetter, Flag::GenerateSignal, From 72e30b69c5984f8a5aa16bf5b923c7d9a68249bc Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 13:51:34 +0200 Subject: [PATCH 0959/1447] CMake: Use new PagedSettings More compact. Change-Id: Ie800e52b98d23e1acd1deba9d6b6e5f778c016bb Reviewed-by: Alessandro Portale --- .../cmakeprojectplugin.cpp | 4 +- .../cmakespecificsettings.cpp | 60 +++++++++---------- .../cmakespecificsettings.h | 10 +--- 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp index fd41c284455..109a44bf9c0 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -74,7 +73,7 @@ public: }; CMakeSettingsPage settingsPage; - CMakeSpecificSettingsPage specificSettings; + CMakeSpecificSettings specificSettings; CMakeManager manager; CMakeBuildStepFactory buildStepFactory; @@ -146,7 +145,6 @@ CMakeProjectPlugin::~CMakeProjectPlugin() void CMakeProjectPlugin::initialize() { d = new CMakeProjectPluginPrivate; - CMakeSpecificSettings::instance()->readSettings(ICore::settings()); const Context projectContext{CMakeProjectManager::Constants::CMAKE_PROJECT_ID}; diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index d7c8775bd18..377916490db 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -15,8 +15,36 @@ using namespace Utils; namespace CMakeProjectManager::Internal { +static CMakeSpecificSettings *theSettings; + +CMakeSpecificSettings *CMakeSpecificSettings::instance() +{ + return theSettings; +} + CMakeSpecificSettings::CMakeSpecificSettings() { + theSettings = this; + + setId(Constants::Settings::GENERAL_ID); + setDisplayName(::CMakeProjectManager::Tr::tr("General")); + setDisplayCategory("CMake"); + setCategory(Constants::Settings::CATEGORY); + setCategoryIconPath(Constants::Icons::SETTINGS_CATEGORY); + setSettings(this); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + Column { + autorunCMake, + packageManagerAutoSetup, + askBeforeReConfigureInitialParams, + showSourceSubFolders, + showAdvancedOptionsByDefault, + st + }.attachTo(widget); + }); + // TODO: fixup of QTCREATORBUG-26289 , remove in Qt Creator 7 or so Core::ICore::settings()->remove("CMakeSpecificSettings/NinjaPath"); @@ -61,38 +89,8 @@ CMakeSpecificSettings::CMakeSpecificSettings() showAdvancedOptionsByDefault.setDefaultValue(false); showAdvancedOptionsByDefault.setLabelText( ::CMakeProjectManager::Tr::tr("Show advanced options by default")); -} -CMakeSpecificSettings *CMakeSpecificSettings::instance() -{ - static CMakeSpecificSettings theSettings; - return &theSettings; -} - -// CMakeSpecificSettingsPage - -CMakeSpecificSettingsPage::CMakeSpecificSettingsPage() -{ - CMakeSpecificSettings *settings = CMakeSpecificSettings::instance(); - setId(Constants::Settings::GENERAL_ID); - setDisplayName(::CMakeProjectManager::Tr::tr("General")); - setDisplayCategory("CMake"); - setCategory(Constants::Settings::CATEGORY); - setCategoryIconPath(Constants::Icons::SETTINGS_CATEGORY); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - CMakeSpecificSettings &s = *settings; - using namespace Layouting; - Column { - s.autorunCMake, - s.packageManagerAutoSetup, - s.askBeforeReConfigureInitialParams, - s.showSourceSubFolders, - s.showAdvancedOptionsByDefault, - st - }.attachTo(widget); - }); + readSettings(Core::ICore::settings()); } } // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h index 830f1050c24..7050452c791 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h @@ -5,11 +5,9 @@ #include -#include - namespace CMakeProjectManager::Internal { -class CMakeSpecificSettings final : public Utils::AspectContainer +class CMakeSpecificSettings final : public Core::PagedSettings { public: CMakeSpecificSettings(); @@ -24,10 +22,4 @@ public: Utils::BoolAspect showAdvancedOptionsByDefault; }; -class CMakeSpecificSettingsPage final : public Core::IOptionsPage -{ -public: - CMakeSpecificSettingsPage(); -}; - } // CMakeProjectManager::Internal From 47e0e9be29ebebccf3ad08f7b1553ab5bd009513 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 12:59:35 +0200 Subject: [PATCH 0960/1447] Core: PagedSettings, next attempt We cannnot pass the LayoutItem directly but need the lambda to postpone creation of aspect subwidgets until the settings page gets into view. Change-Id: I420e82f66fd5c4781451d6851cc38368e7501abc Reviewed-by: Alessandro Portale --- .../coreplugin/dialogs/ioptionspage.cpp | 27 +++++++++---------- src/plugins/coreplugin/dialogs/ioptionspage.h | 4 +-- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index a0e8fd99225..0a8eb257469 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -136,9 +136,6 @@ QWidget *IOptionsPage::widget() if (!m_widget) { if (m_widgetCreator) { m_widget = m_widgetCreator(); - } else if (m_layouter) { - m_widget = new QWidget; - m_layouter(m_widget); } else { QTC_CHECK(false); } @@ -157,9 +154,10 @@ QWidget *IOptionsPage::widget() void IOptionsPage::apply() { - if (auto widget = qobject_cast(m_widget)) { + if (auto widget = qobject_cast(m_widget)) widget->apply(); - } else if (m_settings) { + + if (m_settings) { if (m_settings->isDirty()) { m_settings->apply(); m_settings->writeSettings(ICore::settings()); @@ -180,7 +178,8 @@ void IOptionsPage::finish() { if (auto widget = qobject_cast(m_widget)) widget->finish(); - else if (m_settings) + + if (m_settings) m_settings->finish(); delete m_widget; @@ -202,14 +201,10 @@ void IOptionsPage::setSettings(AspectContainer *settings) void IOptionsPage::setLayouter(const std::function &layouter) { - m_layouter = layouter; -} - -void IOptionsPage::setLayout(const Layouting::LayoutItem &layout) -{ - using namespace Layouting; - m_layouter = [layout](QWidget *widget) { - Column { Row { Column { layout, st }, st } }.attachTo(widget); + m_widgetCreator = [layouter] { + auto widget = new IOptionsPageWidget; + layouter(widget); + return widget; }; } @@ -306,4 +301,8 @@ QIcon IOptionsPageProvider::categoryIcon() const return m_categoryIcon.icon(); } +// PagedSettings + +PagedSettings::PagedSettings() = default; + } // Core diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index a51b459f5f0..256f729a9e4 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -75,7 +75,6 @@ protected: void setCategoryIconPath(const Utils::FilePath &categoryIconPath); void setSettings(Utils::AspectContainer *settings); void setLayouter(const std::function &layouter); - void setLayout(const Layouting::LayoutItem &layout); // Used in FontSettingsPage. FIXME? QPointer m_widget; // Used in conjunction with m_widgetCreator @@ -92,7 +91,6 @@ private: mutable QStringList m_keywords; Utils::AspectContainer *m_settings = nullptr; - std::function m_layouter; }; /* @@ -133,7 +131,7 @@ protected: class CORE_EXPORT PagedSettings : public Utils::AspectContainer, public IOptionsPage { public: - PagedSettings() = default; + PagedSettings(); }; } // namespace Core From 20f237baf2ec287210062f742cf766816aee6c81 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 14:10:14 +0200 Subject: [PATCH 0961/1447] Nim: Use PagedSettings for Tools settings page Change-Id: Iee5f4a89380499d781a42c3e0b6bc82b7386c28e Reviewed-by: Alessandro Portale --- src/plugins/nim/nimplugin.cpp | 1 - src/plugins/nim/settings/nimsettings.cpp | 41 +++++++++++------------- src/plugins/nim/settings/nimsettings.h | 9 +----- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/plugins/nim/nimplugin.cpp b/src/plugins/nim/nimplugin.cpp index fcca3ef8d38..b3ef6fc49f0 100644 --- a/src/plugins/nim/nimplugin.cpp +++ b/src/plugins/nim/nimplugin.cpp @@ -62,7 +62,6 @@ public: NimCompilerBuildStepFactory buildStepFactory; NimCompilerCleanStepFactory cleanStepFactory; NimCodeStyleSettingsPage codeStyleSettingsPage; - NimToolsSettingsPage toolsSettingsPage{&settings}; NimCodeStylePreferencesFactory codeStylePreferencesPage; NimToolChainFactory toolChainFactory; diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp index fb18177800d..036045fada4 100644 --- a/src/plugins/nim/settings/nimsettings.cpp +++ b/src/plugins/nim/settings/nimsettings.cpp @@ -29,6 +29,24 @@ NimSettings::NimSettings() setAutoApply(false); setSettingsGroups("Nim", "NimSuggest"); + setId(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_ID); + setDisplayName(Tr::tr("Tools")); + setCategory(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_CATEGORY); + setDisplayCategory(Tr::tr("Nim")); + setCategoryIconPath(":/nim/images/settingscategory_nim.png"); + setSettings(this); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + Column { + Group { + title("Nimsuggest"), + Column { nimSuggestPath } + }, + st + }.attachTo(widget); + }); + // code style factory auto factory = new NimCodeStylePreferencesFactory(); TextEditorSettings::registerCodeStyleFactory(factory); @@ -95,27 +113,4 @@ SimpleCodeStylePreferences *NimSettings::globalCodeStyle() return m_globalCodeStyle; } -// NimToolSettingsPage - -NimToolsSettingsPage::NimToolsSettingsPage(NimSettings *settings) -{ - setId(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_ID); - setDisplayName(Tr::tr("Tools")); - setCategory(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_CATEGORY); - setDisplayCategory(Tr::tr("Nim")); - setCategoryIconPath(":/nim/images/settingscategory_nim.png"); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - using namespace Layouting; - Column { - Group { - title("Nimsuggest"), - Column { settings->nimSuggestPath } - }, - st - }.attachTo(widget); - }); -} - } // namespace Nim diff --git a/src/plugins/nim/settings/nimsettings.h b/src/plugins/nim/settings/nimsettings.h index 1e8546b3336..57beb64f45d 100644 --- a/src/plugins/nim/settings/nimsettings.h +++ b/src/plugins/nim/settings/nimsettings.h @@ -4,13 +4,12 @@ #pragma once #include -#include namespace TextEditor { class SimpleCodeStylePreferences; } namespace Nim { -class NimSettings : public Utils::AspectContainer +class NimSettings : public Core::PagedSettings { public: NimSettings(); @@ -21,11 +20,5 @@ public: static TextEditor::SimpleCodeStylePreferences *globalCodeStyle(); }; -class NimToolsSettingsPage final : public Core::IOptionsPage -{ -public: - explicit NimToolsSettingsPage(NimSettings *settings); -}; - } // Nim From 98d9ad8b3cfd70556c3935463d079e57c5e43e55 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 14:04:03 +0200 Subject: [PATCH 0962/1447] Docker: Use PagedSettings More compact. Change-Id: Ic21c6ea9e7faf67e5f507f336f18e1134b371a97 Reviewed-by: Alessandro Portale --- src/plugins/docker/dockerplugin.cpp | 1 - src/plugins/docker/dockersettings.cpp | 44 ++++++++++++--------------- src/plugins/docker/dockersettings.h | 10 +----- 3 files changed, 20 insertions(+), 35 deletions(-) diff --git a/src/plugins/docker/dockerplugin.cpp b/src/plugins/docker/dockerplugin.cpp index d7addc894df..cd2dd623bc8 100644 --- a/src/plugins/docker/dockerplugin.cpp +++ b/src/plugins/docker/dockerplugin.cpp @@ -28,7 +28,6 @@ public: DockerSettings m_settings; DockerDeviceFactory m_deviceFactory{&m_settings}; - DockerSettingsPage m_settingPage{&m_settings}; DockerApi m_dockerApi{&m_settings}; }; diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp index 60e9ec4ff2a..2a60dacb7da 100644 --- a/src/plugins/docker/dockersettings.cpp +++ b/src/plugins/docker/dockersettings.cpp @@ -23,6 +23,25 @@ DockerSettings::DockerSettings() setSettingsGroup(Constants::DOCKER); setAutoApply(false); + setId(Docker::Constants::DOCKER_SETTINGS_ID); + setDisplayName(Tr::tr("Docker")); + setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); + setSettings(this); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + + // clang-format off + Column { + Group { + title(Tr::tr("Configuration")), + Row { dockerBinaryPath } + }, + st + }.attachTo(widget); + // clang-format on + }); + FilePaths additionalPaths; if (HostOsInfo::isWindowsHost()) additionalPaths.append("C:/Program Files/Docker/Docker/resources/bin"); @@ -42,29 +61,4 @@ DockerSettings::DockerSettings() readSettings(Core::ICore::settings()); } -// DockerSettingsPage - -DockerSettingsPage::DockerSettingsPage(DockerSettings *settings) -{ - setId(Docker::Constants::DOCKER_SETTINGS_ID); - setDisplayName(Tr::tr("Docker")); - setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - DockerSettings &s = *settings; - using namespace Layouting; - - // clang-format off - Column { - Group { - title(Tr::tr("Configuration")), - Row { s.dockerBinaryPath } - }, - st - }.attachTo(widget); - // clang-format on - }); -} - } // Docker::Internal diff --git a/src/plugins/docker/dockersettings.h b/src/plugins/docker/dockersettings.h index 4980a0a6b04..e6f8f1ec1fb 100644 --- a/src/plugins/docker/dockersettings.h +++ b/src/plugins/docker/dockersettings.h @@ -5,11 +5,9 @@ #include -#include - namespace Docker::Internal { -class DockerSettings final : public Utils::AspectContainer +class DockerSettings final : public Core::PagedSettings { public: DockerSettings(); @@ -17,10 +15,4 @@ public: Utils::StringAspect dockerBinaryPath; }; -class DockerSettingsPage final : public Core::IOptionsPage -{ -public: - explicit DockerSettingsPage(DockerSettings *settings); -}; - } // Docker::Internal From 17ca266b5fe9d4714084c497624e9d67c707435a Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 10 May 2023 17:52:49 +0200 Subject: [PATCH 0963/1447] Vcpkg: Use new PagedSettings Change-Id: I75d1b61a05efa630db080a2750d214636c02b5d9 Reviewed-by: hjk --- src/plugins/vcpkg/vcpkgplugin.cpp | 2 +- src/plugins/vcpkg/vcpkgsettings.cpp | 81 ++++++++++++++--------------- src/plugins/vcpkg/vcpkgsettings.h | 9 +--- 3 files changed, 40 insertions(+), 52 deletions(-) diff --git a/src/plugins/vcpkg/vcpkgplugin.cpp b/src/plugins/vcpkg/vcpkgplugin.cpp index 883b6896a72..4ef89499a76 100644 --- a/src/plugins/vcpkg/vcpkgplugin.cpp +++ b/src/plugins/vcpkg/vcpkgplugin.cpp @@ -17,7 +17,7 @@ class VcpkgPluginPrivate { public: VcpkgManifestEditorFactory manifestEditorFactory; - VcpkgSettingsPage settingsPage; + VcpkgSettings settings; }; VcpkgPlugin::~VcpkgPlugin() diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp index e600631e970..16622fe8b37 100644 --- a/src/plugins/vcpkg/vcpkgsettings.cpp +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -19,10 +19,48 @@ namespace Vcpkg::Internal { +static VcpkgSettings *theSettings = nullptr; + +VcpkgSettings *VcpkgSettings::instance() +{ + return theSettings; +} + VcpkgSettings::VcpkgSettings() { + theSettings = this; + setSettingsGroup("Vcpkg"); + setId(Constants::TOOLSSETTINGSPAGE_ID); + setDisplayName("Vcpkg"); + setCategory(CMakeProjectManager::Constants::Settings::CATEGORY); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + auto websiteButton = new QToolButton; + websiteButton->setIcon(Utils::Icons::ONLINE.icon()); + websiteButton->setToolTip(Constants::WEBSITE_URL); + + // clang-format off + using namespace Layouting; + Column { + Group { + title(tr("Vcpkg installation")), + Form { + Utils::PathChooser::label(), + Span{ 2, Row{ vcpkgRoot, websiteButton} }, + }, + }, + st, + }.attachTo(widget); + // clang-format on + + connect(websiteButton, &QAbstractButton::clicked, [] { + QDesktopServices::openUrl(QUrl::fromUserInput(Constants::WEBSITE_URL)); + }); + }); + registerAspect(&vcpkgRoot); vcpkgRoot.setSettingsKey("VcpkgRoot"); vcpkgRoot.setDisplayStyle(Utils::StringAspect::PathChooserDisplay); @@ -32,52 +70,9 @@ VcpkgSettings::VcpkgSettings() readSettings(Core::ICore::settings()); } -VcpkgSettings *VcpkgSettings::instance() -{ - static VcpkgSettings s; - return &s; -} - bool VcpkgSettings::vcpkgRootValid() const { return (vcpkgRoot.filePath() / "vcpkg").withExecutableSuffix().isExecutableFile(); } -class VcpkgSettingsPageWidget : public Core::IOptionsPageWidget -{ -public: - VcpkgSettingsPageWidget() - { - auto websiteButton = new QToolButton; - websiteButton->setIcon(Utils::Icons::ONLINE.icon()); - websiteButton->setToolTip(Constants::WEBSITE_URL); - - using namespace Layouting; - Column { - Group { - title(tr("Vcpkg installation")), - Form { - Utils::PathChooser::label(), - Span{ 2, Row{ VcpkgSettings::instance()->vcpkgRoot, websiteButton} }, - }, - }, - st, - }.attachTo(this); - - connect(websiteButton, &QAbstractButton::clicked, [] { - QDesktopServices::openUrl(QUrl::fromUserInput(Constants::WEBSITE_URL)); - }); - - setOnApply([] { VcpkgSettings::instance()->writeSettings(Core::ICore::settings()); }); - } -}; - -VcpkgSettingsPage::VcpkgSettingsPage() -{ - setId(Constants::TOOLSSETTINGSPAGE_ID); - setDisplayName("Vcpkg"); - setCategory(CMakeProjectManager::Constants::Settings::CATEGORY); - setWidgetCreator([] { return new VcpkgSettingsPageWidget; }); -} - } // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgsettings.h b/src/plugins/vcpkg/vcpkgsettings.h index b83cf7f9c1c..fb1c478fc4f 100644 --- a/src/plugins/vcpkg/vcpkgsettings.h +++ b/src/plugins/vcpkg/vcpkgsettings.h @@ -4,11 +4,10 @@ #pragma once #include -#include namespace Vcpkg::Internal { -class VcpkgSettings : public Utils::AspectContainer +class VcpkgSettings : public Core::PagedSettings { public: VcpkgSettings(); @@ -19,10 +18,4 @@ public: Utils::StringAspect vcpkgRoot; }; -class VcpkgSettingsPage final : public Core::IOptionsPage -{ -public: - VcpkgSettingsPage(); -}; - } // namespace Vcpkg::Internal From 0b8a0f8f598e3dc75c7101b6d7f553f75c398d72 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 10 May 2023 14:33:20 +0200 Subject: [PATCH 0964/1447] Copilot: remove unused function and member Change-Id: I77bc6533f658dbd6c3b58f603f384e6c516974df Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotclient.cpp | 6 ------ src/plugins/copilot/copilotclient.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 88ce40cd2a8..946e5c1e3e1 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -164,7 +164,6 @@ void CopilotClient::handleCompletions(const GetCompletionRequest::Response &resp return; editor->insertSuggestion( std::make_unique(completions, editor->document())); - m_lastCompletions[editor] = *result; editor->addHoverHandler(&m_hoverHandler); } } @@ -215,9 +214,4 @@ void CopilotClient::requestSignInConfirm( sendMessage(request); } -GetCompletionResponse CopilotClient::lastCompletion(TextEditor::TextEditorWidget *editor) const -{ - return m_lastCompletions.value(editor); -} - } // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index 13f43149f71..bd48710a185 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -46,8 +46,6 @@ public: const QString &userCode, std::function callback); - GetCompletionResponse lastCompletion(TextEditor::TextEditorWidget *editor) const; - private: QMap m_runningRequests; struct ScheduleData @@ -57,7 +55,6 @@ private: }; QMap m_scheduledRequests; CopilotHoverHandler m_hoverHandler; - QHash m_lastCompletions; }; } // namespace Copilot::Internal From edeea10e6a4aa2eeec50f6974495099520a66a47 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 10 May 2023 15:23:24 +0200 Subject: [PATCH 0965/1447] CodeAssistant: block suggestions while proposal is visible Change-Id: I78068306252c5c32304ea97e3abb2d87fdee7832 Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/codeassist/codeassistant.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index bbcbb130be0..fce8d083856 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -81,6 +81,7 @@ private: IAssistProcessor *m_processor = nullptr; AssistKind m_assistKind = TextEditor::Completion; IAssistProposalWidget *m_proposalWidget = nullptr; + TextEditorWidget::SuggestionBlocker m_suggestionBlocker; bool m_receivedContentWhileWaiting = false; QTimer m_automaticProposalTimer; CompletionSettings m_settings; @@ -295,6 +296,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR m_proposalWidget->setDisplayRect(m_editorWidget->cursorRect(basePosition)); m_proposalWidget->setIsSynchronized(!m_receivedContentWhileWaiting); m_proposalWidget->showProposal(prefix); + m_suggestionBlocker = m_editorWidget->blockSuggestions(); } void CodeAssistantPrivate::processProposalItem(AssistProposalItemInterface *proposalItem) @@ -337,6 +339,7 @@ void CodeAssistantPrivate::handlePrefixExpansion(const QString &newPrefix) void CodeAssistantPrivate::finalizeProposal() { stopAutomaticProposalTimer(); + m_suggestionBlocker.reset(); m_proposalWidget = nullptr; if (m_receivedContentWhileWaiting) m_receivedContentWhileWaiting = false; From 5b0c3258bb56fb4de71c28340857761641fe9aa7 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 14:08:41 +0200 Subject: [PATCH 0966/1447] Utils: Make column of LineColumn consistently 0-based Change-Id: I4ab153d1c55653936efbcdc13ac04463185930e0 Reviewed-by: Jarek Kobus Reviewed-by: Qt CI Bot --- src/libs/utils/linecolumn.h | 4 ++-- src/libs/utils/textutils.cpp | 5 ++--- src/plugins/cppeditor/cppeditoroutline.cpp | 2 +- src/plugins/cppeditor/cppoutline.cpp | 5 ++--- src/plugins/cppeditor/cppoutlinemodel.cpp | 2 +- src/plugins/cppeditor/cppoutlinemodel.h | 1 + tests/auto/utils/filepath/tst_filepath.cpp | 4 ++-- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/libs/utils/linecolumn.h b/src/libs/utils/linecolumn.h index 78a881d7f46..457ebd6a515 100644 --- a/src/libs/utils/linecolumn.h +++ b/src/libs/utils/linecolumn.h @@ -19,7 +19,7 @@ public: bool isValid() const { - return line >= 0 && column >= 0; + return line > 0 && column >= 0; } friend bool operator==(LineColumn first, LineColumn second) @@ -35,7 +35,7 @@ public: static LineColumn extractFromFileName(QStringView fileName, int &postfixPos); public: - int line = -1; + int line = 0; int column = -1; }; diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index ec440a8902a..8b52d51d2c2 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -60,7 +60,7 @@ OptionalLineColumn convertPosition(const QTextDocument *document, int pos) QTextBlock block = document->findBlock(pos); if (block.isValid()) - optional.emplace(block.blockNumber() + 1, pos - block.position() + 1); + optional.emplace(block.blockNumber() + 1, pos - block.position()); return optional; } @@ -180,8 +180,7 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) : 0; lineColumn.column = QString::fromUtf8( utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset)) - .length() - + 1; + .length(); return lineColumn; } diff --git a/src/plugins/cppeditor/cppeditoroutline.cpp b/src/plugins/cppeditor/cppeditoroutline.cpp index b0d14ca1192..a3c9c363f99 100644 --- a/src/plugins/cppeditor/cppeditoroutline.cpp +++ b/src/plugins/cppeditor/cppeditoroutline.cpp @@ -152,7 +152,7 @@ void CppEditorOutline::updateIndexNow() int line = 0, column = 0; m_editorWidget->convertPosition(m_editorWidget->position(), &line, &column); - QModelIndex comboIndex = m_model->indexForPosition(line, column); + QModelIndex comboIndex = m_model->indexForPosition(line, column - 1); if (comboIndex.isValid()) { QSignalBlocker blocker(m_combo); diff --git a/src/plugins/cppeditor/cppoutline.cpp b/src/plugins/cppeditor/cppoutline.cpp index 8c28c7e30a6..2efa3709269 100644 --- a/src/plugins/cppeditor/cppoutline.cpp +++ b/src/plugins/cppeditor/cppoutline.cpp @@ -169,7 +169,7 @@ void CppOutlineWidget::updateIndexNow() int line = 0, column = 0; m_editor->convertPosition(m_editor->position(), &line, &column); - QModelIndex index = m_model->indexForPosition(line, column); + QModelIndex index = m_model->indexForPosition(line, column - 1); if (index.isValid()) { m_blockCursorSync = true; @@ -194,8 +194,7 @@ void CppOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex) Core::EditorManager::cutForwardNavigationHistory(); Core::EditorManager::addCurrentPositionToNavigationHistory(); - // line has to be 1 based, column 0 based! - m_editor->gotoLine(lineColumn.line, lineColumn.column - 1, true, true); + m_editor->gotoLine(lineColumn.line, lineColumn.column, true, true); m_blockCursorSync = false; } diff --git a/src/plugins/cppeditor/cppoutlinemodel.cpp b/src/plugins/cppeditor/cppoutlinemodel.cpp index 2ce6f7dad0e..660492b81cd 100644 --- a/src/plugins/cppeditor/cppoutlinemodel.cpp +++ b/src/plugins/cppeditor/cppoutlinemodel.cpp @@ -246,7 +246,7 @@ Utils::LineColumn OutlineModel::lineColumnFromIndex(const QModelIndex &sourceInd if (!symbol) return lineColumn; lineColumn.line = symbol->line(); - lineColumn.column = symbol->column(); + lineColumn.column = symbol->column() - 1; return lineColumn; } diff --git a/src/plugins/cppeditor/cppoutlinemodel.h b/src/plugins/cppeditor/cppoutlinemodel.h index 08b7adb4424..3afed56486b 100644 --- a/src/plugins/cppeditor/cppoutlinemodel.h +++ b/src/plugins/cppeditor/cppoutlinemodel.h @@ -48,6 +48,7 @@ public: using Range = std::pair; Range rangeFromIndex(const QModelIndex &sourceIndex) const; + // line is 1-based and column is 0-based QModelIndex indexForPosition(int line, int column, const QModelIndex &rootIndex = {}) const; private: diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index 6e11ddb71cd..f2ecac2bb6d 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -1095,7 +1095,7 @@ void tst_filepath::linkFromString_data() QTest::addColumn("column"); QTest::newRow("no-line-no-column") - << QString("someFile.txt") << FilePath("someFile.txt") << -1 << -1; + << QString("someFile.txt") << FilePath("someFile.txt") << 0 << -1; QTest::newRow(": at end") << QString::fromLatin1("someFile.txt:") << FilePath("someFile.txt") << 0 << -1; QTest::newRow("+ at end") << QString::fromLatin1("someFile.txt+") << FilePath("someFile.txt") @@ -1121,7 +1121,7 @@ void tst_filepath::linkFromString_data() QTest::newRow("+line-+column") << QString::fromLatin1("/some/path/file.txt+142+33") << FilePath("/some/path/file.txt") << 142 << 32; QTest::newRow("( at end") << QString::fromLatin1("/some/path/file.txt(") - << FilePath("/some/path/file.txt") << -1 << -1; + << FilePath("/some/path/file.txt") << 0 << -1; QTest::newRow("(42 at end") << QString::fromLatin1("/some/path/file.txt(42") << FilePath("/some/path/file.txt") << 42 << -1; QTest::newRow("(42) at end") << QString::fromLatin1("/some/path/file.txt(42)") From 24aea361b7b26bef467292d4f41ced1178b718bf Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 14:15:38 +0200 Subject: [PATCH 0967/1447] Utils: remove OptionalLineColumn LineColumn already has a isValid() that is sufficient for the use case. Change-Id: I7f6e1d64b66a9af05d74ce0ef45717265dc28ed3 Reviewed-by: Jarek Kobus --- src/libs/utils/linecolumn.h | 2 -- src/libs/utils/textutils.cpp | 11 ++++------- src/libs/utils/textutils.h | 2 +- src/plugins/languageclient/languageclientsettings.cpp | 6 +++--- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/libs/utils/linecolumn.h b/src/libs/utils/linecolumn.h index 457ebd6a515..922c981d79e 100644 --- a/src/libs/utils/linecolumn.h +++ b/src/libs/utils/linecolumn.h @@ -39,8 +39,6 @@ public: int column = -1; }; -using OptionalLineColumn = std::optional; - } // namespace Utils Q_DECLARE_METATYPE(Utils::LineColumn) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 8b52d51d2c2..55e8a736d05 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -53,16 +53,13 @@ bool convertPosition(const QTextDocument *document, int pos, int *line, int *col } } -OptionalLineColumn convertPosition(const QTextDocument *document, int pos) +LineColumn convertPosition(const QTextDocument *document, int pos) { - OptionalLineColumn optional; - - QTextBlock block = document->findBlock(pos); - + const QTextBlock block = document->findBlock(pos); if (block.isValid()) - optional.emplace(block.blockNumber() + 1, pos - block.position()); + return {block.blockNumber() + 1, pos - block.position()}; - return optional; + return {}; } int positionInText(const QTextDocument *textDocument, int line, int column) diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index ce8a450302a..573dc7aa1d7 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -69,7 +69,7 @@ QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document, int pos, int *line, int *column); QTCREATOR_UTILS_EXPORT -OptionalLineColumn convertPosition(const QTextDocument *document, int pos); +LineColumn convertPosition(const QTextDocument *document, int pos); // line and column are 1-based QTCREATOR_UTILS_EXPORT int positionInText(const QTextDocument *textDocument, int line, int column); diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 4dc70e31c96..92d314beabc 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -1052,12 +1052,12 @@ TextEditor::BaseTextEditor *jsonEditor() QJsonDocument::fromJson(content.toUtf8(), &error); if (error.error == QJsonParseError::NoError) return; - const Utils::OptionalLineColumn lineColumn + const Utils::LineColumn lineColumn = Utils::Text::convertPosition(document->document(), error.offset); - if (!lineColumn.has_value()) + if (!lineColumn.isValid()) return; auto mark = new TextMark(Utils::FilePath(), - lineColumn->line, + lineColumn.line, {::LanguageClient::Tr::tr("JSON Error"), jsonMarkId}); mark->setLineAnnotation(error.errorString()); mark->setColor(Utils::Theme::CodeModel_Error_TextMarkColor); From 4b851bbb011ad386b165203bc381e818f50c24cd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:27:39 +0200 Subject: [PATCH 0968/1447] FileSystemFilter: Remove the old matchesFor() implementation Change-Id: I21e714a7cd89e82eb408f89bfe1271c91758f13a Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller Reviewed-by: --- .../coreplugin/locator/filesystemfilter.cpp | 67 +++++-------------- .../coreplugin/locator/filesystemfilter.h | 28 ++------ 2 files changed, 24 insertions(+), 71 deletions(-) diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 674949f5a53..e1d45afeb3f 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -35,8 +35,7 @@ using namespace Utils; -namespace Core { -namespace Internal { +namespace Core::Internal { Q_GLOBAL_STATIC(QIcon, sDeviceRootIcon); @@ -132,13 +131,11 @@ FileSystemFilter::FileSystemFilter() *sDeviceRootIcon = qApp->style()->standardIcon(QStyle::SP_DriveHDIcon); } -template -static LocatorFilterEntries matchesImpl(Promise &promise, - const QString &input, - const QString &shortcutString, - const FilePath ¤tDocumentDir, - bool includeHidden) +static void matches(QPromise &promise, const LocatorStorage &storage, + const QString &shortcutString, const FilePath ¤tDocumentDir, + bool includeHidden) { + const QString input = storage.input(); LocatorFilterEntries entries[int(ILocatorFilter::MatchLevel::Count)]; const Environment env = Environment::systemEnvironment(); @@ -185,7 +182,7 @@ static LocatorFilterEntries matchesImpl(Promise &promise, if (regExp.isValid()) { for (const FilePath &dir : dirs) { if (promise.isCanceled()) - return {}; + return; const QString dirString = dir.relativeChildPath(directory).nativePath(); const QRegularExpressionMatch match = regExp.match(dirString); @@ -212,7 +209,7 @@ static LocatorFilterEntries matchesImpl(Promise &promise, if (regExp.isValid()) { for (const FilePath &file : files) { if (promise.isCanceled()) - return {}; + return; const QString fileString = file.relativeChildPath(directory).nativePath(); const QRegularExpressionMatch match = regExp.match(fileString); @@ -236,7 +233,7 @@ static LocatorFilterEntries matchesImpl(Promise &promise, const FilePaths roots = deviceRoots(); for (const FilePath &root : roots) { if (promise.isCanceled()) - return {}; + return; const QString displayString = root.toUserOutput(); const QRegularExpressionMatch match = regExp.match(displayString); @@ -305,19 +302,9 @@ static LocatorFilterEntries matchesImpl(Promise &promise, entries[int(ILocatorFilter::MatchLevel::Normal)].append(filterEntry); } } - return std::accumulate(std::begin(entries), std::end(entries), LocatorFilterEntries()); -} -static void matches(QPromise &promise, - const LocatorStorage &storage, - const QString &shortcutString, - const FilePath ¤tDocumentDir, - bool includeHidden) -{ - const LocatorFilterEntries result - = matchesImpl(promise, storage.input(), shortcutString, currentDocumentDir, includeHidden); - if (!result.isEmpty()) - storage.reportOutput(result); + storage.reportOutput(std::accumulate(std::begin(entries), std::end(entries), + LocatorFilterEntries())); } LocatorMatcherTasks FileSystemFilter::matchers() @@ -326,35 +313,16 @@ LocatorMatcherTasks FileSystemFilter::matchers() TreeStorage storage; - const auto onSetup = [this, storage](Async &async) { + const auto onSetup = [storage, includeHidden = m_includeHidden, shortcut = shortcutString()] + (Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); - async.setConcurrentCallData(matches, - *storage, - shortcutString(), - DocumentManager::fileDialogInitialDirectory(), - m_includeHidden); + async.setConcurrentCallData(matches, *storage, shortcut, + DocumentManager::fileDialogInitialDirectory(), includeHidden); }; return {{AsyncTask(onSetup), storage}}; } -void FileSystemFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - m_currentDocumentDirectory = DocumentManager::fileDialogInitialDirectory(); - m_currentIncludeHidden = m_includeHidden; -} - -QList FileSystemFilter::matchesFor(QFutureInterface &future, - const QString &entry) -{ - return matchesImpl(future, - entry, - shortcutString(), - m_currentDocumentDirectory, - m_currentIncludeHidden); -} - class FileSystemFilterOptions : public QDialog { public: @@ -418,13 +386,13 @@ const char kIncludeHiddenKey[] = "includeHidden"; void FileSystemFilter::saveState(QJsonObject &object) const { - if (m_includeHidden != kIncludeHiddenDefault) + if (m_includeHidden != s_includeHiddenDefault) object.insert(kIncludeHiddenKey, m_includeHidden); } void FileSystemFilter::restoreState(const QJsonObject &object) { - m_currentIncludeHidden = object.value(kIncludeHiddenKey).toBool(kIncludeHiddenDefault); + m_includeHidden = object.value(kIncludeHiddenKey).toBool(s_includeHiddenDefault); } void FileSystemFilter::restoreState(const QByteArray &state) @@ -448,5 +416,4 @@ void FileSystemFilter::restoreState(const QByteArray &state) } } -} // Internal -} // Core +} // namespace Core::Internal diff --git a/src/plugins/coreplugin/locator/filesystemfilter.h b/src/plugins/coreplugin/locator/filesystemfilter.h index 20f6ecd1486..3dfac11b3a5 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.h +++ b/src/plugins/coreplugin/locator/filesystemfilter.h @@ -5,25 +5,14 @@ #include "ilocatorfilter.h" -#include -#include -#include -#include - -namespace Core { -namespace Internal { +namespace Core::Internal { class FileSystemFilter : public ILocatorFilter { - Q_OBJECT - public: - explicit FileSystemFilter(); - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; - void restoreState(const QByteArray &state) override; - bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; + FileSystemFilter(); + void restoreState(const QByteArray &state) final; + bool openConfigDialog(QWidget *parent, bool &needsRefresh) final; protected: void saveState(QJsonObject &object) const final; @@ -32,11 +21,8 @@ protected: private: LocatorMatcherTasks matchers() final; - static const bool kIncludeHiddenDefault = true; - bool m_includeHidden = kIncludeHiddenDefault; - bool m_currentIncludeHidden = kIncludeHiddenDefault; - Utils::FilePath m_currentDocumentDirectory; + static const bool s_includeHiddenDefault = true; + bool m_includeHidden = s_includeHiddenDefault; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From 37cf70aebac444d99e3c7270ebc5c5a19dc6cdb4 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 10 May 2023 15:18:45 +0200 Subject: [PATCH 0969/1447] Squish: Redo layout of settingspage Change-Id: I0622423a25942d803f38e85cb4aecd57024666a9 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/squish/squishsettings.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/squish/squishsettings.cpp b/src/plugins/squish/squishsettings.cpp index 144e3046083..68de6c62977 100644 --- a/src/plugins/squish/squishsettings.cpp +++ b/src/plugins/squish/squishsettings.cpp @@ -127,14 +127,13 @@ SquishSettingsPage::SquishSettingsPage(SquishSettings *settings) SquishSettings &s = *settings; using namespace Layouting; - Grid grid { + Form { s.squishPath, br, s.licensePath, br, - Span {2, Row { s.local, s.serverHost, s.serverPort } }, br, + s.local, s.serverHost, s.serverPort, br, s.verbose, br, s.minimizeIDE, br, - }; - Column { Row { grid }, st }.attachTo(widget); + }.attachTo(widget); }); } From 670d36a931cb094aedd6cf97ca4c9b09176e33f7 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 26 Apr 2023 15:05:16 +0200 Subject: [PATCH 0970/1447] Doc: Don't mention qmake in Qt Quick debugging instructions The same field is available for both qmake and CMake projects. Use a screenshot from a CMake project. Also point to "Preferences > Build & Run > Default Build Properties" for globally enabling QML debugging and explain what "Use Project Default" and "Leave at Default" mean. Fixes: QTCREATORBUG-29089 Change-Id: I3d007d10ca3247dc387eaf21d4d4623d7e90167d Reviewed-by: Eike Ziller --- ...reator-build-settings-cmake-configure.webp | Bin 5270 -> 18528 bytes .../src/debugger/qtquick-debugging.qdoc | 63 +++++++++++++++--- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/doc/qtcreator/images/qtcreator-build-settings-cmake-configure.webp b/doc/qtcreator/images/qtcreator-build-settings-cmake-configure.webp index 4b38b162f4cf840f41d73a2c6a9fe01fa0d4639a..0038dc4763198872c218fb790a32867118002328 100644 GIT binary patch literal 18528 zcmWIYbaRXFU|#g&?vw<&iKD8E{KIq~Sw|z<9xoxVADlYdJH)%y{%Vbvj&0Z_8qJ`nT|~jS8%vi{UG|&&-(rM z@4uJ%B(q6nm*k0prFY(hE(} z*yQBQo9hl6c-Cz5_gxZSb}2Gb(y4p*?(Cxa{SUXj>vlf*ZN<~78y-_~qjP6hudY-J zR5CU;e*C@tOrqLpMag4LO*XH-$P20LES%l=K8D*ygPqA?|I<_3w)$|rd-pESaN}<0 zcXB&jU0i-~?P;`a75>Q7GG({-f8G1n|6eyPdN0{oFn!&``RjfaoR~AQub}(b&yOpV zQ&f~@{pWmPud=OI#&gp5qBS?~UVm!*%28w0?Xu?oTmCG6YOni0^QZsm`lx@!wXyajasn|hO{?d}@sw7;v|lQ?8A*cn)gEPKN4c02ckidkNeY)|^2eLPxJ?smog-Pp$f3v=1wfm!9k+iU( z$d-3oz3bCefA3qi&7;TDIP1_~fn(dZ%rLoYn%cB@;)`D&GyP}8S|08z6IFKQR@@Nzv?IB<8{8U0HvQ=B#Z`kE?~Wo=rjrjY@BKi<=(4JH93)_}AYYrfsv-RXPQqXdbBg-O@7Qd4JZa zANITl-W-~s@I;nx$E|Bt>PPzLIG=JiieN83XSCzR?7JJ)+nOdGsu#}NxGi*IO4Me) z1sgKs>!&>Yaa`NvTW0dVsKg-m+hU>}eDQ*FEWgG*ytRH(p8XVK-gQ5o-DOVIcyoR8 ztBmujU3u18Dn@)fYnN-Jxo5VBSiDHfgN1z22WW6dqqW#LV zg$D{QRyW`3=WAZ$YxmVvIwSMhW>-xO_wRMx|Ckj{x!zWssooUGvXK3o^QEhr&1YP1 zb^H-^l;AThTln;R+>)%RpZB%-yKR~GBv@NY({tnZt(#r--seXe%KTk#w|v&e8g|Vs zA3qD|yxM!J-zwoqXd54Q2)pJQ=hWXPxL@t}T4Rleu`;#?L`Bg{oF2 zTq>0i@Jicunr%btZM6=glMlK={+S6D9dG;n=7sI4=I_!b^)6dGkI(A7*gL=d#O7zx z&)?l;l^1ky{E+(n-CfzW+DEx1L<{tlVs3aca8P zqJ=Hor%;z`E9zCoh8ev z4B79UOy1vBJ2_8JyfUr(oN@1cUvB-6iLTR#OZ>k>rPBLyo;?q{ zlHl4O)BLaHz?M@h(?Tv*eGybRBp?uV``&gZ3)#iT4$hA0zj8upv-p+G@g-~CXCM9R zEt&T5ROAI2?Ke{%%<2oTh*y`>mU#E0T4Ajq2WxW1SD)A1v$h&c4dxD$KBv#4hG z^6Y?+qjDX;N*=AX%DTxjqyFDimup%Q4?k@bUw8Ynw{yOE8^nmgc=qJ%pEpTp zRl3aXJ+Y45T6W1Zr^`3me7TVJn0tTBrB%$Vl_v#vI$n9Ce01@O2`%9d_o|qvF}%j)AVrBda*uPaoS?dTT!lk1>u7c#T-&oMQN@Wgbs=ks``G%nwu|LD5ejQAc=Kjs7O9P^Ac z%d&4Dsd7=5xG5pA^-brEPmh$RnJ8X~yw~}uC1-z|eC=5eL0<<$H>rhZb$B?PW?t0l zXn&zxV1DFFRAt5E6lMnrCcB#5ODt44L`|pdPE+4Gce=vEi|bF#``B8+bn1`DA0d{R zKR*^*s4hLaWLBJ@CWq?$;>6;WO)er$J+Vt(aHvE+oiqOmmt@f7<$b+7v=<8A)w}gg z*G9;MBVo>((g(tiMNYM+q#Zln!gJ2!;xo(trt@Xb96MdIxTfml?C;$7e(jqwf1<@A zr=w4u_1R=Yn_TS;izobIDpHs?V}H3@7jtn___VVZvLp?D#vWPAetRjG%X80F`?=4} zwU)V?($l=PCHjxq3|^U%YibtduPxr?E(kuNJDXLtX~Km@o`mG2=qKWtI)8qIyxurV z!HfO(tb`}8GS#^LuMhWqX`3jgZ?w{E;;ZP?J_#pX=Q!pZ^LZwV*Bh+-d#HcKS>y6& z{;Q4z*W6d;RkCMnu=@2`yzF_xC#MPeH7S*<>*hSS_ITHF$aY_{e?#@;6N@(0uD_a| zJUQ^f@;L$Pb?>cOthlMmG-0;M4#j>g-i31~JzX@@TZu#Qy|uU0S(fkx2cNsk?wOfA ziG60Fz=L<5*6(iVsr?C5xsrKger4FjW3IP;{P`LjwUx~`{$!U&)Y5IQ+D^~=*lqHy zPd}mGzjXGx_5D|}frvDQE6#sDea8J9l zn{j0^OX0Z{7oX2(KkuhJ&5ZlJAdA&vw*ULj$Nl~OY5E7bKPq)n(*K_3eYo}UjvDKd zbAm@K7q`u;=Slx>`_C$U{-c~(8*Fxn?9sM!zwo?As%qW5zpj5o>V)cf>ly3ir2jp2 ze{)y-f3xpID|Z2q{JD91rQ?4c(!SiJ`mL3ZP4%4M6U)VH^Q)h#Kh?Hxzufe6s;H3g zrZ~apJyLb^>UP=tM(B9=qy|3kk=uPz{o%^_M>7uziL0yW^;xA~X=?X>F#kV~pYXKJ z=||_-de1ekdZRXT0r753o8XnO! z_Y$2S@pvNh#R~VNd9`0$jy&C*8lLg?=Ow|YpIw&UtPZ96AGu!qV6hUDi_WvY_I-C7 zazm5rii5n5Sj;L@R8HS3(79MirLJO2#Y>lW6JGO&dHFA7?S8yr#&+({vyHBYFWo-# zL+h$dAAS9-<>lti`*>;M${Wgyo0473x5s7FREXri`>ND>`RHqngk5KBE6S`NZJK*^ zw)FQfW33(KcjY?yr~Tct(?>T{X_a8iyUF!T$BLr7tg5d)le3wdA|>JPITdE(cctR^jLXw>KU<9yZblsSiN0w_D2d|jmchzmT1?< z-=f5OAGUvuOwLgc{bzV5?)QV3c0pG_O5 zs+8#6>oLsxv)AiVXHRnE@>iE%85cc}wXwMVK(Z`S-RYcl^FqIKNvX5<$j<)KA@f4M zZuhaDA8wyAf3w!tApB=ah16DA>HVEeR*9@W0h5ZI)lZ6uxt*R^&9lGcKp|_NM&vu^ z@c%(hL28*BbP7aTxPtBVR5rbtq$I5Pq0vd*+U}0zVyB|MP7TM<7ll5bn{K#Ho~)kl z9+Q_|nxJX+ZfoYWY3$3b>>|oO6mO8}XuBOO%o|+1wQ&7LR;{+}*Uz21=U1ilXU>l1 z>e?f+p26=VTFf0z*M2xYY1;1tmx@0vIeT()q@>DYH@5RTC8qVVYd)UxIz5!bR-*XH zrJ!wgLULUmJ!QO#>k2}gFD%k8i{$Q-(|NATlT~t^%gV?t$noD3>lxj9xGJWt`u*bV zlGGFKx6Bu0JXKoTzDn_+wD@Da$D9Hs)w`JdRpU%mmPckSwY6l9@U1zUVVUzT)@*Zp z$fgxZt1K#wp4*#oM&F#{ZTWS#-W%Z+nkzSiaBX3AD{r~|>35ucJa1>s$0<{`>o0%w zU;UGnq2Cc!7M4f-ziuoq<@^@%XZnK8lS}L#F){M9obYa|{Gn=_R64VJBd=pQuf>8# zmxNkwcCoIJQdv1~@w2EMRw)x+>2)oUx&2}BftV+{4LvjeYSp>*7AO2E-}YeIvq@Xz zEfn;0TN&nct(3`7e|M0AGTyzX$_i?`UYu>Ile1C1T09=6O4wRX^p zVLbMtS5r`?^xU+V+)X@I!mFQNuywp+dFz?-^w=n^yj>qpg`Rnn=~2aC_soEG8tb!% ztt+Hd9xUvea9v$vzsUrq-F8nJyKXSwSfjfAaGcSZ!};lM96!yzaY>|2pJrgxzWw^F z7?DY@EWOsXW^>)Edlt}8b79`nDaYp4m3}%LemH%~1b*4)Cs@UkXMfWA&LZ$p=Gc+| z)lX#~o|?u4w#}W@BJUcpkI^+(WMfkKr8g&Uw5i><$nrSHt-V<-?R28L$J$kU%JUv) zTwE0ND{9V!X(3aR-e+*>aDO@Hr`ssXzN31hLZimX<3}W-H!-em-MytU?%ko8w*{u( zj<7$~m({i9jZBj3n~nd>_VmW4o?d!8$nnU|1j;q{ZCr z^!vy1-H&bCXY4LGmX@YwoSd?{Sme!z+sYy)Z`~jMP_Uf&TjOIuNzxU!I3~gBWeyjA z-I}O*eR6qIz1cqBSq|NwG4jL#Tr*F_*|{UQNhW& z(EeO*&Fx8VVzZXp@_tTvv>{q=-6}Em=NyfpQE6$Px@`nhxy4+${1_t=94c=qFKnK& zDExv)tZa8Yke=+uA-$U`TgLm=zKim!Mg^d4IYj9jYUyeJU5O0XTQD}lKrDi%72Tj+2%*=cUEj^ zT&nt<`Nl3|!)U$~0e#lHzF(OFAFQ5IW%ebeq) zz1C|hb7z+|KiqcBh56pWKi3M}IP)J&vwphk?60bAyV4i)O)k5WEPE>Rc>C#pTUA=p znz|GoI9$m;eP(%o3%^3dW4~-3`?DKnyV$H}OI=+!H+I*@qYGZ%HTP&tT5f9kRQaya z=jcMu-)&O<8r<5d*333XdcE?DRIb;&*?Fxp!(;Q)DLq$RF7HWNS+#L`{F0V64wjk> z+%X;8(aD91w&ClRwQkuNC~ox7Z_ggy!kfpe8dcs%I?t(my|((#woT9P=B~`|eEM+b zy&sE$w)fsm*s<17kg=ShYU&5Jyq&`Ow`2CrnVG}K*fn9t@;CRYveV@s^Q^K^cIHUd z+;1mz&O*5PV|>5$+KXNHE}yHmS(p4_bp_kP>FmZ&9^LvfF++04(ua$_@p{Y*JSCUz zzW2A`j!x;RVSy9oY`#%#W3uexgtXI~-&y8gb?MttV|o9@-qyJ@xIDg2=sx=1aOV9j z>yjcD=zNJ&w{F~`a79AG(ClC_H0w1^vH@!CNKNSB&iAw z%Z`?5DMmew`)_+SSS);T($;PIv}x;g^J@ZItXA0xUl06V)$9D0V_)It(zuU%8lK2B z`iiCNoSA0a@LJUN(Tcr(A{X>$UUIQIv%#j7J@K$aXKQNXwU~LE@>keQ?F)|m*fI}P zF|E3Nd)1Hszqj}`tUFce+?mCFpZD*wny+C;o`zlP*LiyE?$<9ho9?{5T-5VD+*e>j zI)`AZjm_2SQ)V&x$7Vj6_U^rM)-C~Usk~ekLGEHl4NopB=^an6hUdoBntET2|D_;j ztPi-(ZvQ{5xK93%Vvx{mURIlVp8ylR>*+{hP`X z*;cDx#Sas&cIvEr^2JB@*NZ1cTYL&m8=f{-pPoKt)8z{d%jG+LLz-r9dBWYfTj!+s zqm2vRm0k&(yz%&I+im9!L8<75?IFe+SN!dT_*GM63i>#Ddu|zDH*cA_w_8YV$Issz z|BB3WJzDOlarcds-Na{&&)c5~*XwW}xpdY4Pa^NifIQE6kBXnJy6mU8%tcc6xp2LZ zx6Xr3`^=6l2eLSSvWh1>{+F_|$GP>&%9f}9ykZXeFWzJO^pB(R`ID(!VjRsgCu}fi zd8d9%QZ(4}jR^CEJj=4jO~QMX_V{IOWr|?W5-YlNXwIizPV?8BneBs&O5_f9U$~gl zlV$wvLO_(j>ZdvL>ZMczS@!VR%H(m1sXeNEdu+RZsgBr3&o7(!cNAT%TeUZpQRmSP zVZ&q1GyjHYElEv`IGVovM?{Kb?8lJm*OGrF>o@-EZt7aU&yY*7^Y-K^{e2&~>WVB+ z{0?$H&+0QT$$8eU-;xuT_&ewAxV`+3vQtePldZ?cg^%hI{eE5c=sP}dedrEN|7oYp z#dbW(?YZaOJZVn9{uQ4aem5q#ot7+64h|2xs?U2;>Db}y|M~ZR`c`}tTQl>i*fsf( zl0B53%Pn|L$n-*}nKm>}t;by%;j9}q}%kI3k z|0T}-(>Pb3IBUb1@8|5Y-H#mfmpA?L=k3ka_FVFRZ2oZlkuv#n`om8Ce^x)!J$5TS zN?6`6_3P>U$0o~uFst+T{aUf{|M~R&rnV2F&;MJitpsv+Wi@nI_wuLt)6hnGu?ro) zrx^Epq3rhcvugzP%?mW+cv*i=I(cz*)Ws=2>RqXa^y_EVu>P7gBeL7>O7`=cd(K3e zBy!g5%$(WxhTrbjj2r5QEOzhMb8*g@Kg+%z;!)%m?Qs@AI9))jsDQ zYdv4e)a3%7H!@tlxPJ47ipV+ZV{&h`UaEh=tH$-SU3KH*Yrdu2Nt`Cf>weD^miwR- zqqf5T!UndFJPVgyxBoEbwgKOjxzm=j*hpO#eX#Lq;ia1H8x`|8dfp|(`~Ao~=q`U) zW7koan9a$3XH1U9iOj64D^{}D>NfjL)6cUC${trQJ-{Ss#{Uq1V`f>lx%I^PB6nk^y_MdV3H-4MXjX$BOzb7W} zbN;%Owp?1@>R!9|E!K&0Sbf4#VasC;_c#CMKF*(8pLJzs)T%DO?_t4wlI{`T)bIcI zbrhQ@&+M4KUSP$Jh^23y|Fw~snzJd9CU z8LG~m+8Dz3`nu5JogZ`hDjufh?Yy;2Hkr+GDbJ-}ktZe3?L5-MtLgnZA^rC3Zx%`J zD}2^ut@-(<>8_2ykDy~3#oIR57(Xh~wU(RnddDPx1OB9EXA}-zlRUOBbc1Z>%bPdN z>~+@0$Lo3}o#*iuJdnnZ?uAXYWRXt&@`+@S@Y~?%)cV5diZ)Qbq{y#apOgHIPM7mzYyNA^~_stT#xxLIf zhkIhCa`|MQ=L(;B%G2ZT7Uh`M^7v2wyI}j#;I9q26M0Sxe)+a1v8e9gjR>RP?Pd&e zYxrjT)ZZhyczN-T^4_V;)2FSjN-ScOPtw`-Xz8gNOVZcK&%Vld>NEE_zawimE<2IH zvqvG2_u%S}C+6#B3-9kO<(=5(zO}_PY>`m@eQ(cBb!AIctBg5c3dE{i->fvdIon9R zu*9P6o}6cGtF=kyy7T^zKUZ&EC3MH~NcPraOTspFtz4=6^g;OF!+mGCF+g63G zQ{snik%=MuG1)ww^Z&!P&3e7jG41!QcQ^i8hfnqU#O84)E;yPcY(w9ccEQ3H5wVcxaP1S8sZQP|B4rK*;*D>! z4bnC`T3EH0Ci-#zlV7MYg=u9&_~VB%EzE0FUr6Tt5L(Q1)cJHTi<`HF%{4aHEcdj6 z9{E?ld)_3hzayjHanAKnuWIj!T}tOawK=%V<+(HQM08u&J+`IR7kaf8?OI;g(kJ!( z=?;&3XoR`_65J*#H;qgGO3Jq1w-eZ!CawFgbiFw1{l80A z>kdrwKl7!o?x29<;-AmO?;LK|d>Sx=V|rxIF{6-4Q)7?wtlMzszNHQG*}wT+?Vb~Y zZFX!wx`T5y$KQu~+03_Z+6gAd9L)W{AtuU=^UD03W7%EC8|<(C|M_8|;Qa@!(`5x2 zyU+ZszV2d_Gv$Q&pEtP?{f*lUS~tz-(UiKv|K^*e+pD^S-08br+&EIDYk%}U{=qfz zx+RaS#AEB?GRZ6c#b%bwl)?ODF5x7a>U zy)$3t+xqT#C!QYGQ{%0fa9?=-+Y{NX9IBVf>KM&A6f`dsES&KA=DL2RNq=XnD1B8eI2m+J57xv0PG@CD{}#|qc8ajF}b z7dzza{^WN4-hSb&Y!_A9Xc zS%JtT-yMw`W(7z-Z)I%l*8gO4@5Ri(>&F7_@2?X#n-vv%LTo|Cg&$7rbF}6}E^<~m zzFV3{2S{J?1@_}zG0wnNeF=hK#ceP7!h#t{}-YWCP` zN8FE(-1*0{KOLGWDlx57TWog0U19cb&D`6cmv$CqxNfuhA+UVP^@$U!F4#Zw4OV5p z_EzM}m1fSG8`{^I&+MuSnQgvqs#3DYBKFw!j{;L;+}t%fdE}}U6$1BV+uSZHwtxD; z__Ucq`iaM^nsXPY8{B=F*ztPx8`%aSSvGr~ycx?bYx&QVPrby&Vstf4QfYV4r8Z6D z9dlEd-Mnwec~6$c#qW`al6NH)M}gbnl-MRUTZ>?E(;`v zKI?1RJkLusC{Xf$+FtiVQ}q7Vf8hy=xy@nMaa@1#?G=hjmkyUs+$FI{-%8HTz-`ST zTMxlsx2}Cuvi-I^V)+Vp`N)Fmz|V@$#arwd7puz13717UKis=hm za;q{l7Hm6cxUS-bd;UZ>*V#4+?7Ke;Hg=RVC%*RB;b`b|Y;)Q+#pRzu-%d2};VXLG z*4lrhVYk=MM~btSowxp@n!&p!ZbDzrw1SGBmy)t($Jw&qB`OuF8osYHjJC7lO<5q# zkp5)nouuUGO~OduWD$?%w4D)w6E$(R>|W#Y-th!4;ZTc9?nyDJHW&5&APr) znKLSNhkWlV#RU$DEk`6?MswcnG4T8AcTRsp%61v~rOX^$OAquIFZGIao4ri==7!Wa zvlAw>I$kKh%8)+kwSBe9rA0S=wpc8PdlJ><-~X{wy>oGv(W*=#?+Y7*Jj*urZBpd; zHsRpscYhwTuHMjX#!z=`>guYFFaGb!o3(aq)Nl_Gf4cF?i)jI69U33GRgPOvIJ`^s zXtC)*wKtP{XFmS*s5xXp;+=!x!Ul}&cY~9+ZJm;^YkrmAgWi6`!u+jUEX;h;cHdZisNa**Psnh=qa(s%7Wd>H>t*kq z-=tCRm^}CR+1_$bH}OMRDUI7CUf$xlXcF)(_)A-{mG&&f7ZquYYl|i2W@Ptlz9reR z@!Nrd7kq3l1;x02ZTqTJx@%#yS6KO91y$x7ygb&|UK$#S3Ti5FKe@+nTlsrb=Q8*;&%yi zY*e-hh^zEH&|jK-Y~9ysk7kB{(Rsr2{Lk_J{tM3+_69ZlW-%#QalS$<_vg_+w?5dc z2#U{YF)lo6Im<8kMO=;j7LAAO@@#U;_J;77bluqX{@kNDr+r>gM;5n~xmc>6(pb!- ztGreJ&HG4(iMFzfUS<^cJ0H+`*p;09mT|A6{jt(({vDc+E3TF13U9KF(7v)|v3QyO z+gmIK{M9k+vn%UfG`M}4bmCcNr*hoiiz08WZzmUpOMaVU6ZPuo#=;wYZ7vgcv);P5 zAm-hc;>RD|&fnqMu=&%0D_$%0J+^tUbY^&T7cfg7TNR}Ay_wl6cM=;9kG74EsNb>9 z#an)t$}F6JsQtgzH2*bx>K0*JS|^u@`1xtKH&3(8XxevwbxEBf?~_DUw;S(zcFLtT z-;J`Ibm|7z%vbRilU3?uHWeCd4cTE>uU4fH`mFs!^D$=qtM#k)R;_SnpMAoycMFT; zr?x3P+zZ=xDSU1``ZaWiqWGh4|NbX>iS4*`+Cj@*>Eb1hw-G%N3H(9e56)ne13!$FCMD;L=t+_jgJ zy#4V*;+q@2wG-Za?0i~ixXE*pm$Ou>RBLjT<&|ff+|4HcuuxeRazRR4F7o5%H@}bR zM{V3~6D7NfukTR7`Uazt+JR-W^^?_d7#k&JDaO3&Ykhb^CO`pm7Vus$FvY5Gz}yK0TT6C#UMbNcuG zH!@}3R;{^bqT}SwGQlDRnUr|zIl|8_eT!ddX1T8ZX758@C-=D%E(p)kSz8pIm&ur? zv^||+YYG3?4`M-4|I+3%$r*lQD1NP;Xt?Rn;ef>LTk~?NpDHUKHS=1em!WF7RAP-m z?V}$F*8@~6mGUjrne>D$Rihs^?Ajc%A;0zXhO0OE5ARG^dbse(1uf@gUC(cRj#l|C zwR+c*SC=ybY+fYLnnE9ocys&>AZd_ixDjZql0$deZL zT8W+awp|pMt8`RKIWHlF*Kz0K)$iXr{Fcc5U}C`jXTkQlCIUNux0dKUu$Wr9rz@se zd3%2T1im7z9Wz6granM` zq%vut^kL~9!BX$nBFZ_+S**tcq$lO^Gv`beH*)MR-jcc3$9KNFL8_F@>d;-hxf3`* z;qlPn(PhKxu+Kk1}#0zxXN?$#LI5}mXcGhhX*gb<7*c* z`_CuAUCNmYoU>lnHw{K*q#Pp*1PuGF9MSia{@`EmO- z&g);Xy7`pLPEW!9idXz>`CEk{zcb5BR!m>Pu5>x%$v?%49pUi?#_7HR+@Ah6MY=X? zu7tmSqJH+0;M&s8ZBo1awmWKk4_G?g=9^vW;*i7NOh0+pFrTli4V><|-+HUsw6WO7ot$pAyrB3s+XeGbbx_u1=}w z&RZL=cT75Jm z>VD<&vW~rXF05NIb8UCY5l?ZQYisT>8288SRXJwlyercD^Pgpzx2`P?p0dEc(Yjj7 zy$n2f@xsl~%l|}LoVQ;~mf=L*WhVQDjT>&MyDDEdel$gzTT<`O)BL&hr%tvm{c6=d zmt)sbk10hmOSb7*Tz|By z*SL2(OKrjyb+z9tw+`3o1XnhRlzHFKQD2$ksh-KS{pS(`S-0OyvYuEq%~`IIDK=9l zZ3SO@ugcsfEg!z+)ID$ai&@j$v1Ug^^M^b3%Y8myD(#P2(WrR6Y|CTajt_GqR+;^L zDDm;Hd30t8fAr&8rD-;YCSCgTuCx6{iu)=zy$GM1`+IC&TF&eAf0jR~evRy{UZp){ z{xLUKfAd(r@}J_Fif3)-W-XCEGjZ9^8TU(~Hl;qVF>E-*tjT6@^J1sOjf0P0r0Y)G zCcC2g_}YUtU%GSmtz0}?_NCO$yp7pBuDnyr`nVIj%Ntm0oI_?N``!vL-OUo)ddubE z*U-pA@e8H0CUq}e6I!}u>etP(?`!>6v2FPqaOvcsWyx#ro}9&%y`gd529e#bS`_ye zO}*w^;VgCG!m}1(k$v87EU)GqUv@D>fN$o4SH)+SOxnB5&+h9aH>Mlgx7_bN{^Fvk ztliN~&0D9vZTWO@kxZH1&Djr{T>ab=B4=i`{e7I)5m>=;#vw!HsoK2W%=|W+z58|N z&uBZ^so2Ceqc`m3k)vUHr7@icK^+e4-cuLU2 znaT#`-m5ZujkX6gt_r@?7jZkIRj1zM@YYbjgoPTLm%I}8_6p4N3*4Bt>aW!;sZ&|8 zM?M@*KL7ZyY1HCO)<0)(=jP>?as7I z2g~i<;@2!Z_{MaK?l&$kxr(}uu(A{F)86(J6lKmib@Kr4-POLQA`kfT*ZHvRm|*wj zg_$xZgY1!wtpT4WB~J5~P`3U2puIoOD0ecKZqU-I`+gC7yCp0QIo*o9X9Z+`R_joV z&`3EyJ??Yp{RhdthpwqDcH5?O*om!p-9>fd8PC-UCpC(E=6bSI!o08RXP8mkV$LfQ zpY^+iIDX#x+CW0NmSnP&Jgk^>!Z&1L#j7V8*}1kMH6aJS z80-}L{`CL1z3aSXx=nM_cU@V(kX?QGls4h~$IWtO_CFVYx!if`km(hMo!R%#*B^10 z_qH!wy-;(Re^5_w$9nxMnCza?7BZasZHfidyyF1BAq*VpXID|{@` zyu>8oU}RHRO7fG%M@*w^{!H6_bl09tUm=5^(yObIytY1@#DH*qQ2G*PYICQlUG;_7_MaBIO1~KHCrCu3Tssk# zBJm~rW-@0E=#4JoxCpUcV>X5%>LYI zx%Yo;d!@01Z|;W6A<6qyjF#NdcvvC(C?wpr;i~rAa(lkjD?Hebv|L_x=Ggf;0=E2X z)>n1cU9`COPNS)`rk=cBz=Jx7uz?p9Fmb7y$K)T1`}5{D$S!0IUW z&wFmy@US0y%hP>E>Sh-Yv+SA5v^T~#eM%-9%yd}SvGeytHFM8-T?&Bv?5VEqy6^I> z!vs&w@0nQc;bwk}BVuyzB9`#fds~`cyT*zATx+ECN$9EL#9wzO@G{8>FFjjiSJD)y zIsfzZBSpNb$%nSY#!MCWs5n$Qjs1&@5=SQg)yR@orKf8=R&L|w61ichad4XdrP|x4 zk7!1=TwK&|%5J3LBUV~G_0$8FfJIVb*38>~K2X#bPTb4tUNUpr#I+|38U(bwe()uP zO*6S<|AoI|uWhizx;$8HM z$AxPFmJgYZ+t2B^dCF1!UjXmgd8azo8peKD)BVMHg^Zx)!S+e>B}=@2-FTT-^US5{ zMvP;onhNjiSqgt2E|vDKJ}jfV%(4A}2zTYdPn}b}POewE>VEwrtMr|Zu5V=xVvfAJ z@cbZiW<%|6DXR%88wF#EE+3Blu;=!lk`A*CC)P|{dxC*SaOd%sqdzs4Z$HugTuNQq z!_w68QwWRXlRf2?AL5kKcg%zI&?0R`uiiNw>G{$I_qOhYRk_1JGlDaMHJX8 zNSs@`w`=Fa_<8Xff6{Z-x&EIjs?^`P);44gTh#vR7F%cWYr6be^e1}m&NL(2M;6ar zl@~8LutoNQC%b7wmCKh*Rdc4LmFjno1U}o*zVoe=-JkG{HA&xgFMU^?)1sQO<>rTT zc6xp{=BvHGFKFZD{*xgtn(Bv6o^CELUnjUc@#I{y{If4OGlZ6{IrS^06eG(T{wB|D3COqbc=BKTHt#hYkz6Df@kqBma^`iI>)lkaw}#==Bt-5N*U z32TqM-8<`*caQL^9)YiKp8MTc7#0*J5WcKX{^#v?8k*53nm-ve-1)%k^XYe;P{_Ib zWxtbd^eroB=lZUimp@;??&3~QRd3<1-98>OGM>05-xjs&k=w@I_ z%l~d+sJ_jRyMVcBjarYe&pfjyy`Ms)JfuqaH*wdLo;hW<;CRXG_bxM>av474Yn}$h z=YoQTW|I%jN#1jNe^1rCMMpTpg3bx{#{W`yG(}7^&HuQ2$fG3}e-xZC@|o3dY{GAR zDzkTzTDzO6q;Zbi3h_sTKZelEW@?avYUh2D#- zraK1Oe{@d~{E5P2AL- zX-3=^ZUkAEe+-f0xh?oP;0#~at%J#v>N~%So_KCwXf?ez%i400-LwXG7in3Y&Pd^A z(PjQJ@_|(hZ#T;G1^loOwLa!k@!>w>(w89|_c!_9{4HF>@FZpb&y_a{we3%L3A~*g zsBEp2To>H3p6^)`^V}IF0z&g9sxF?@s1RQtcP@5n&?{Dv6LZ^V{ZskOtd@T2x$XVn zx3?#}__^|1+o^4>b-Hp9uF}8Q%%LM76%;i`Ty25vD&@o-~{fE%zca8f4*pv4)}A7 z@x&&xDLiYxtT2j;nNkx_*0jW9Q5){%*IB7uSkt|RiP>^Opz`NAmfaH*ZFk186&rr~_4&MUlGS<>goJhf?sS&a`*G#p6mLHphR*d``!{v- zKi6r9-+GldbKl15@~kH_H{|^{x+Y%1y#K;UrI+9~y6zd@W4}1+) z^!nWW(#)j?UQOD2PU>FCYVVSo;L@fw~n1O|BP3_z5^*|Dz*3XjsuXzj9`}>!%VCKdj%;ru9Me7&b+;~T-y}Rr1RgLXz0 zU;kFI?V#eZO)DF1u74@b-0SE#?SgYtpQ^4D%IpxRx4Z#woO$ z)^2@uY4V)diqD@+GXqI z(srt692cCIcdAcF^{Al7j(t)77hP2+w(4zqwIECJ^@6I7IWpJ2Tn*Rt(JEd1*k+o4 zO48S>uRe)~3NG^N5niJ^E0jHyJC^;b^J9>4W?vE<@5Ic^IbUq~=1g#2oxzIhC*%(q z6~*p6rMlbjLTP}lNuA_vYv-v;PiNkaJO1)m=NcEmhD8gi9ZIe;%r=mivN2vZLT%26YrJeu zPMi53-!y5l=ictlQQh-*L8*ACh34ve^BOetmz`ZaiEriP-Lv*pF|^jR^|OAtclq_| z0I#i8e4?j?Kkwhpw<_RG=sK%K(@HY_Xj!g#xjInGwD8xj?&BP%7%ESly?$Q$(>2Gf zr$v)uuapK%oyz_82umdURp%$>Q|`~&*Y#`9s?D-DE&899{@it5|H@hQe-^J7tkOEU zE91K3)Z=&ePY(GUd)@Kt1&f_)U#?zteznxhi_bUO+;+UaZg%{i(tx)Qw#JqQ99^}w zZTIBTfLt$yCbeIjiVFn)XkVU{w&41SMUD%my;^Wfgqe503CEQn*^t=@56pSp7CZ1> zb=+#%CiJb*jO$8(Y{=}i7yMFeSXf^YAdJ0MKVDmlC_mnGhb-A{5W;_ z{`|6p$nTDamd~%#Q5ULZWaXS+wTe|B{k&L1OZ~s+{ZCyMEnKbe@bh_p<_Q{AnjRHj zv)*m|-+8lA-=#nB!tSge`lsseX2<;iZ40p5FR3GXR&37)qkV?6TDd0XhQ2kty>YtX z)!FBq7P)+z|3$4xUhzlU!LS1@n~${W{r%8)-DIqs?71{)jbPX&ilrcZvCct z#&}u!_xEe^fB(|*6_BX4Jgj9B)?@!-r}%<z?aRGW!?v4Dd#)6-Vi(W5OQmzJ ztv^(*QkO92!usZ*75T?EH0-l$`a1Vx#X{bFdBvq1#!1#MJNdUSpJyp_Zhz<`k;$pk zOML>ieEi;H#U8%dr8MtT*q3zQMD@L8OBR_VeQ(gbbDle7_w~D{V)$-w{1kt1^4gN; z4c?jCt&`7bh^}GH+P!bp+RbHGCK)^s|NQ!h+m8=(udTmk!ulm@ylvuZj9I3= zPEVb$zu?-;9ai4z-=D9G<*1rGnMvflU_gYNjfIj8J?qyBSE$KO5>(B==kn;Y_-``);jN{lw|fn* zOvehDjKgnZxkLDp-RIm|nlJAua&V^D?n04^&mUw>yKy^U=Hxq~|JD>vyVhxt;Agex z#mUo$3^ga{tnF61{Z&V3s?(%Et%&9u>KCV#u5+xlkyoqq)0()n-PFV7#Hj}>UxjuG zZCZNZLsMznfk)eol|BD0)aHnO|7jw_{DrG4`tC4Yv)nODGB439ZNJz2%AZWtq8k@n z^b6=Xal4{x_bK7oWj5Mw6+8h#h;QAlr2L~3OI-h@>DSBu zkC1u4({J~csJ~_}7+L)^wtC$vO1iXx%QK7NxxrcnmR&D6Q`<_f1y5!0d3}d5qRhgU zMeB&5c}l#Lj=lqXl&YTX(s!w84Sti;Uub=kdARDAOw3te{gK=-YfCH_ zhpEARJ(YJ;UjOomS(-Y#Y^v`2ywgXlJ^c1x{kc}+dqlhX(^VGE;mr-@_dP;Fp3B5s z-L{-3r1Slb6E<`7*UwWdI&rXIb^g1r zIC}o(&-}k=!Q3-?rq{!L=WL$oDI+Nv_1^l*Z|~D7pJTi?l}+50>7F`w@wu0LY)dyd zD`zk0yW3tn^~{9b8LK(Uco)Vy1l+x!d$CijyUF-?@ediRL;ipIM4bMFY4@(3KFQ{k zUZlx&mT6lq82`wOag{%jE;HqYTapy}wo! zs;&EU^M7ah-{;lMPeOF}-d_Gx;YCVneU(gJre$07uS@JFD;c}e`BxP3txMZt@nKFF z?~R(tGfqX>RJ#XT%z69&A3D9}ke28g z@yxkDw#_Q>$cb6nZu*>4$Ts0}m^HJJ^E|~3e~!!#dB9OQ=`ZgOk?6TQ8_vWil$P9@ zeyX@&tJaO^f|i39lOHOTdrg~ExkFua%5V3iE7d-y3_r4qDrQFeuS>6e=;CDV#rpc# zrgJ}b?7Ow?;}p4T^VB^Aeg_=mStz&CJmd3pEeF{{ug@DRFqhtad-+oj$QSJfJ$+wi zCx6~>f@MwnY2zQiYghdUXTCbkTsB;@;WKNHXKUGkrBQ;ZLj04{XgyUm%Q1}W6kw|C-&;LlwYayes0mt{PJ`w z!?_EgmT%U({zy$yHLX1N`1o?!J@tPIrXDw)3w`)_QQ0n{R3zW~wZ2Nia(zYcRr(b8X za1P)4dga%vv)T_PX-&-9xATc^EY#k&Ratk|FO!g2WRQD#S$B2)AI9U7yJk7Z_(x4I z=X84(V4T-r^7~U1$McoJZN9Ji4!U(+tlNLn?uivY*MqW8kcD5TiZa>FtK0R$dyV8@&9BSVrWF<% z{u54pA5q@D%`ESizt`zXmsIbdV@7kt6% zjBo4=t=BJ1$#%M=Q^>b_%}$B+jO-z68V-1S`?j>?e%rD|vicAk!%c0CiW`OrjSmmI z=SXi`lM$eP(~iCNh~*C38OPaY{olczzGKQl>&dB49bErBFzbm)3R}Eqp@B0qN9aYv zMCKFU+5Q)>x&}r@Ej>^y`jL5ElJ-5u>szL#9@SXZ!jSmloMMwm5mSaa*FCFmj|EO_ zzwId*dHKS#Bl3TR%@{mQ85&n|+-2nGy~tV~e2Zh-!k_)tPj{_ye64kDqG;Axt=E^d zPM_oIPCvwUAX3`FGq$&SjdHHWgy+=^A?L$Z%-XgsStc*rRnqHLR?PC(dzbYlNUtzk zcHsEa)0?I&jBhvpYf;0~*F((ee02>W(;ZSS!bUV#+-GoC+}KYp!X z(ovD`z?$9r@!u-Jr`fi$JG<6q2u4&toOt7@sALX6BJzf~Dx}wbCB;Ry7 zt<%ZhJxc6Z52v&OYt=ip8J?5&1Z*s<-xPCgPK=tNaZKn%m#dkZJf`f}+9`PIuIDDP z=m%lBk*=zRYdNJAbgyic;r5(o-QIiAv++m73}wmpydrmws-&6zocMlLL|n)Gm9u88 zxuSfihrB=RkGt*c0<$pUdn| L)R`1?@bdxyP$kj{ literal 5270 zcmWIYbaU$yVPFV%bqWXzu<&UVVPMc-#$>=C7k_@+-n_^E?pL2IGw{;CeQVycN%wXy z)vSKm$^GE$mwlnjHS--B9QHR)`8w^{&h@|R=55_^;$xI1mrQ{`J3iSYLyQ@HaD+s6}yW4lM`w)ja(y% z%DzG8HyiW)iNE~0x82>rTRd^c)GST@2T4}kT>tudC+@hC_BXvuo$vWpb_wg8KN}67 z)jDj=m?1HFmE4mEAB(>W*=uE$3l;w^0)#T)VCe4>PcI5TQ|NHR! z@VhOIffwZcoU7S3s!Vm-e$?&I)&4q%?q@$1yGfl{u<$n1U&XWUl&@CgFPT!3-D)i8 z{a52g!j-uRGL8I6OQe}E34X49;(9E}%{}`1Q%kuG=_UNep7G0E&P!(+UaOwKXXak@ zqglL5lzHF$=H)BJ*x5pZ1m4G1mQJ4MG$q4Bpi-Ali?t#{Y?p3L$5)?O3pgvLx2^am zm-%$+`B%}}AMcyzWU6dP&1ao|X>Z>~#Uzsp)s`xHTO#qGDbl6Fg?{9cvp=cIS6M_g!^1L!BmE6k`TgyMlYFp-py_R%1 zy!mk4){j;18kx>3tu*4iI{$n@@VaLiSGHI`VbpRAZ#wL2&tH65Yr(V9HrvHqDQwIf zUs_#vt8^sInacb|L67%>gvCya)|e1QkD^CYXS=^M@jHBDd$X|TiKewdp)z?3-wy0UEYUW<$ z3w&L+s`v7aDGZE{*{z??GLdoU7Pz42XJB&F^Repm57R$?v(|aPs?3A)Q}GqPeV*r< zSat+U#7zr(bVsh?)F#4hz#4zUre_PhVUTp&oiteu@Ii%$KGOQ=+EN zD}S}EuX2HU(EF6945#N^Q`lg0s>7Rk$ENG4?kap4yFxy2$USg;yY_kas$%cp(iP_> z${oIcT5dt?$IpxBf67k{zg4sM%0j__c4JN+DQ4cLZ5E{xGQhAA@0y z;eE^L3Cj(3&1ksw?Z?5}Z|5y=<;Y_?b7OUBKmVw}$Qfw8ucdEKe`cLLSeW-bopc>Z>Jy#3$j=NGzpK9Bv_&~lfvy0(4Yg9)?d zocLsQ=G!XS%5SL$4<|0L%Ac{ZL6VV$i|N&@h%Gi34x27A*txN6X_$zk>Ww!GWNU@z zviiO~(vWBBXFm7K;?-aIf}5FCUirS+(^PfQki*;h;lB+Qo{R}qtviZO+U$Gq^=MHT zpTXxVOv1ePEKM4W-IoM^_P=WRpkcL*gROyb?N6?Aeczv^E zw$%mEl+qI)=hc3_J8^o~k7I{69Z^;lJ78{YZ|`2Py=a!ji{l2j6W8zeRTdV!vOD1` zJ9ENevB_H235_RDF}nH7CIpsdF~~3fXvrq@@%wt?Y18Z`Sk)B--#V^6?Nt5lCr8eo zKbV@s5@9G*XLqsHUPOyl4C?(M8H{NBPWUHb3VmAqNgqt&=rA2@E;ytMp=d8_B@ zkL;8F3QMd#{n{;v{f?m*!#dfT%@=ZmxEHqPTridW!fh)$J6fQj>!js3sWXpK3VGPf zKD&2p7hw2y>+Iuq4Am!2F{aJCv|`=)+x&N=4*cB2JZskH%42r~L#l(h%G1nu9r|Bt zl=z1`B2T4mh1t#ElnNCErtBsTTS!ak<}WuibSQ z9bfcJYOv~Lo2l~fcZ_Xwrpm`N@{0GICd`aeeD`E&tDfcjxy(KDn$F!eusQl*(ds?D6vWbN7W$^K7oWy)0_&rD)dxp(Ee# zGF^~gu-lR2%fmmm{tcU7@n=4?O*6e6`8LGT+oJxw@B-=-p zPSf0L^>+J@q@21}@=0;ljebf0*>OA5O8#*=8!K))?LRl_NYRy}*rdsFN zqo0Z9A!6x;#bybz3uLukAC2%)`}_RY+JKvf^Ah?hzpr`c&}#Rs>m z8Mp15?DHNqwVd4iV$r|sqn1o{Nt#|09-sU(!)({lRch-h-17LegnOo#88nHWPpD2v z3Hj&Xx8TA?!~cie6{q)XnLjzBTl??ByAeqloY4tBN8VV*T~0dx@zmVex6b~~|CE*g z;me$=&;Lqpil(nvo$jwCZ<=GUAWUw?%B)#0r(KzKS-!?q?10+lnvI(TB&N0+Ffnp* z*l!e3J@GN6=8N;;FLx|1YUQpqc>7m1*hSNi>jk^`E%PVcDz_ea{rkW^-|SACZjR$d zeXsAkc)Q=0cF*;^+3@-0rbg?pw?AC7UA=qCS-GMc&Uu+0g+G6ti#}y~GU$l3r(E6n zk_iD-XRqt?PrrVcd)kIwdnR#Y4&hXB|451uL~ZjT)x>n=r5Z(ZbcqhKUo- z<$e)knXG)c|Iw_ZR=Hw(_U6X<5m71}A5;FMX6mS=vHWTMqse#S?4>pnjYOXX0g^YT zo^pD+Tia>ReOY^TPg}%d zy<^6znsS}8(^ygvcmz_AfexH5e=k(`4KFs{y*ne64^tqRtq^DoYoxD5C-Rt1lqWtEx z^~P@!)y{obBt6w>;$DwwEI;n#Oj#f$qTpb(aJNM3)TTowx05yt>ZtgZKl;~TA(YhE z$@c!n7Z1?{W6zurjvzKCl?kUG=pN~rVWyFEJXy}z{^P+m0jIzw*^;>@^F57HR)f+S(uzwv@E>H|0d_mC+b>gApHx$~s_n1V&KXJ@t^Jl|mF*X4y=&<08NH{X&TjsGj-UTOpZlgS-m>Q1!2?En ztb@*)7N6ZPf7!9S%icZNQdiQb&+2|#CggR~6My+-&h7`Snd8jOp2crd^pHGpS;6B; zt!X}A+x^=G4Y~^Ow>4+P`T6`PVmW zWczqHyX;)q)a35BTIt-sUG{8SJ!cuqx79P=ZCS4)cehk>{o1>wo!;@DoV)!~G*!!7 zGrd;SPG7V^yX*S3d-9QcU6TIXP~InJuzL4rM)u+((fobi8;ji(}63>4VHk~?eo|t*_Yhl2m@U+{E9)%4uZCBe( z?EAZ#6u8c8II%oNe&ZIe3Hv=8^yMF%JR*_5Q8QZ6h->;(GnIuLZfBoy$%xFfxxV41 zREzA7XaD`Cb+FsEdViQ-H(lv>o!9lc^65eS6IR`~{q*3xoMUOl6aHwss_$#wt!QYr zd}MgOdTX!$%;)zPWR$OZ=w|*PdQwi_snuGh7dmR&C&wu+O!s8+T6LRwN@UPCk)I4L z6Dm&1f8NJ^WLk(l7iW6F{x4Jh1(a5QZt`>XtItsDv}IiyAfnPHA^AnDhPg3XTlsE+ z+~WBa+TSB?sV3O4nk}Cx)6Lme!kW0{P};t{wGYm9252-~eSLbJ!kPd7I63A9-+03I z&{y&EtGSn@y(b>c(@C`t{+bZ4zG(OREd}pq8n4&x{H*fujJ@AI?&tU8X0584aj!yf zqQqYAnG;*x({sMPntOS||1YcOrkwHL@8w!(uKg};x};R&zI_=UF5z5}#m>r8=jV6r zsrvn-ElEP_b*uQd|7&-%|4__bc1eC!*Y5lYQ&t0{+=);@OP2akwm90CQ+kRr& zzT2H^D^5MR6s$gdzWA27eT5&odJkW?ajkQ?kM7x{;q?`Nzn|ME5SgAA_SdK3=3lqK zTXl2p)~^v*`gZo_m%=4#2XvZ)i*|8%Uzo}8@zR>c33K!gIX5eCE2%E;KEyJgbHlZz zxA+xL-v99_dd=}^qN=<0%&TOXGDpv79-oD`dNPQSRYf?XW>)( zyU$&-op!gf?ndvqX-|K?-oAMAUsG@8DfQxW*G^w52$KJ{LHbbNtL!*-*(nbXPMKR2 z`SagrvHM4V{}hY6{#0B)-cgNL`9AwP)BCl>&!3fb-_?Aj^lnAnu~|h^^Pcm^PxH&V ztHQ9qFE-Ki{>fuY3|uc>T(=|P=GITSvX@)_uAG0$!Eb7<;?(-*0q=r>So`o3%tJGmz{96a_;g& z?;{SD3!aVJv*-83<;VU1{JC|j>PvQA*SyVdR@_^%IwPhk;85!SFFKO5r&xIC-CKWn zd)WNPr5AUcbo?3dI^KNalJepS`pQ>ort6$rJ8$lO{&w$8Gn}@nFBG>a$`aYo^nTH8 z_S#>I^e*k#lIJx;xZsw3?bf*lGgMY;S#`@TSoiASjuVNWj^6qwk@sn7bA963@(S5G z_u~Us$>j(x3Hi4A$em8n8u6QNTu)oS-?i^&{6aJP`^!(;%kP^PA1f9A?T*Dg;UYFR zj=b0Rx)khrZJLg5d01LScD4P%pg717=Ct>bX&H`%M#Gta&*xsZG7yGOqD zgaoIKU6*gUOwzyh?Ri_tgLD5jc{#r6di38qa*@&dGh6xfCN#b1+OfE5PHg&*4ehnT zp|ijJy?pzd2mhoWb1kOnG;N5k61RNx>|JDTy^+~mrSE%TiChOgK!d<%6HT`!{$AP6R>+^p#&g-6M@=(d%s?a20_WXci*oSayTEK52VJ zJCE1K>$YOzg1?UBZ4|8MtxwuM11#2Ed18S`HUDw91i8J>e@%D4^+V*;?7z39cd$0L zzYDc(`n5Ci^eM&vp8x+pTT@qaP~NR7=cvmWgZ_IVvhoro@CskK44u>U_|3-m3wxp+4kHf{R5xgOw=e--~2gpS(A3_lA4%lzS(yF*WX}QESFT# znf?F1X=3n-Dbe|7CGNl0@ysnNthhz>Q6Zp72hjdcCe)g~{HBN<0P| zqt7_+DxQ9~vQI>A-F;rBGc!bQ7uG)1Ddi94zx?`qv;2|Nlz^_iF=w2gEx8f>D^LBN dqu)mHUq|u`FUrUL-zyA?_Dren$g~wq3;@#QR`~z` diff --git a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc index 833cbe69c47..c0246fc7b6f 100644 --- a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc +++ b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc @@ -38,22 +38,26 @@ The process of setting up debugging for Qt Quick projects depends on the \l{Creating Qt Quick Projects}{type of the project}: Qt Quick UI or Qt Quick Application, and the Qt version used. + + \section2 Debugging Qt Quick UI Projects \endif - To debug Qt Quick UI projects, select the \uicontrol {Enable QML} check box in the - \uicontrol {Debugger Settings} in \uicontrol Projects mode \uicontrol {Run Settings}. + To debug Qt Quick UI projects (.qmlproject), select the + \uicontrol {Enable QML} check box in \uicontrol {Debugger settings} + in \uicontrol Projects mode \uicontrol {Run Settings}. \if defined(qtcreator) + \section2 Debugging Qt Quick Applications + To debug Qt Quick Applications: \list 1 - \li If you use qmake as the build system, make sure that - debugging is enabled in the \uicontrol {Build Settings}, - \uicontrol {QML debugging and profiling} field, either - explicitly for the project or globally by default. + \li To create a build configuration that supports QML debugging, + select \uicontrol {Projects} > \uicontrol {Build} > + \uicontrol {QML debugging and profiling} > \uicontrol Enable. - \image qtcreator-projectpane.png "qmake general build settings pane" + \image qtcreator-build-settings-cmake-configure.webp {Build settings for a CMake project} \note Debugging requires opening a socket at a TCP port, which presents a security risk. Anyone on the Internet could connect @@ -61,9 +65,9 @@ functions. Therefore, you must make sure that the port is properly protected by a firewall. - \li In the \uicontrol {Run Settings}, \uicontrol {Debugger Settings} section, select - the \uicontrol {Enable QML} check box to enable - QML debugging. + \li In \uicontrol {Run Settings} > \uicontrol {Debugger settings}, select + the \uicontrol {Enable QML} check box to enable QML debugging for + running applications. \li Select \uicontrol Build > \uicontrol {Rebuild Project} to clean and rebuild the project. @@ -79,6 +83,43 @@ automatically installed during \QC and Qt installation. Do not delete them if you plan to debug QML applications. + \section2 Using Default Values + + You can enable or disable QML debugging globally in \uicontrol Edit > + \uicontrol Preferences > \uicontrol {Build & Run} > + \uicontrol {Default Build Properties}. + + \image qtcreator-build-settings-default.png "Default Build Properties tab in Build & Run Preferences" + + The value of the \uicontrol {QML debugging} field determines what happens + when creating new build configurations. The values \uicontrol Enable + and \uicontrol Disable explicitly set QML debugging for the new build + configuration to that value, regardless of what type of build + configuration you create. + + \uicontrol {Use Project Default} makes the values depend on the type of + build configuration: \uicontrol Debug, \uicontrol Profile, or + \uicontrol Release. When you use \l {CMake Build Configuration}{CMake} or + \l {qmake Build Configuration}{qmake} as a build system, debug and profile + build configurations have QML debugging enabled. However, release build + configurations do not include QML debugging because the debugging feature + makes applications vulnerable. + + The \uicontrol {Leave at Default} option in \uicontrol {Projects} > + \uicontrol {Build} > \uicontrol {QML debugging and profiling} is needed to keep existing, + already configured CMake build directories intact. Also, it + enables you to import an existing build into \QC without enforced changes, + so that you don't have to worry about a complete rebuild of the project, for + example. Even if you later change the configuration of the build outside of + \QC, it will be kept as you want it. + + There are some known issues in the interaction between the global setting + in \uicontrol Edit > \uicontrol Preferences > \uicontrol {Build & Run} > + \uicontrol {Default Build Properties} and the build configuration. + For example, for qmake the global setting only affects build configurations + that are automatically created when enabling a kit. Also, CMake ignores the + global setting. + \section1 Mixed C++/QML Debugging To debug both the C++ and QML parts of your application at the same time, @@ -87,7 +128,7 @@ \uicontrol{Run Settings}. \endif - \image qtquick-debugging-settings.png + \image qtquick-debugging-settings.png {Debugger settings section in Run Settings} \section1 Starting QML Debugging From 2455ff28cd8b96d9fee329b47f8fc515e540198d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Wed, 10 May 2023 21:40:53 +0200 Subject: [PATCH 0971/1447] Debugger: Fix defined but not used warning Move the currentError function where it is used. Change-Id: Iba669d677b35abc0c9291572c2ccb1df3cd2ed56 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/debugger/terminal.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index 6707137e853..5de7740380f 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -38,12 +38,6 @@ using namespace Utils; namespace Debugger::Internal { -static QString currentError() -{ - int err = errno; - return QString::fromLatin1(strerror(err)); -} - Terminal::Terminal(QObject *parent) : QObject(parent) { @@ -52,6 +46,10 @@ Terminal::Terminal(QObject *parent) void Terminal::setup() { #ifdef DEBUGGER_USE_TERMINAL + const auto currentError = [] { + int err = errno; + return QString::fromLatin1(strerror(err)); + }; if (!qtcEnvironmentVariableIsSet("QTC_USE_PTY")) return; From 7960c1f3f6481227986a09dbb20bbdead84bdc00 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Mon, 8 May 2023 11:00:04 +0200 Subject: [PATCH 0972/1447] ClangFormat: Fix code style preferences are grayed out Code style preferences are grayed out even when formatting mode is set to disable. Fixes: QTCREATORBUG-29129 Change-Id: Icf82fa0751f9291122c2af55111b6bd5fac85c7b Reviewed-by: Christian Kandeler --- .../clangformat/clangformatconfigwidget.cpp | 8 ++--- .../clangformatglobalconfigwidget.cpp | 30 ++++++++++++------- .../clangformatglobalconfigwidget.h | 3 ++ src/plugins/clangformat/clangformatutils.cpp | 12 +++++--- .../cppeditor/cppcodestylesettingspage.cpp | 3 +- .../texteditor/icodestylepreferences.cpp | 11 +++++++ .../texteditor/icodestylepreferences.h | 3 ++ 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index 12e02b4fa74..dc5d1b3dc05 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -89,8 +89,8 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(TextEditor::ICodeStylePreferenc d->checksScrollArea->setWidget(d->checksWidget); d->checksScrollArea->setWidgetResizable(true); - d->checksWidget->setEnabled(!codeStyle->isReadOnly() - && !codeStyle->isTemporarilyReadOnly()); + d->checksWidget->setEnabled(!codeStyle->isReadOnly() && !codeStyle->isTemporarilyReadOnly() + && !codeStyle->isAdditionalTabDisabled()); FilePath fileName; if (d->project) @@ -141,8 +141,8 @@ void ClangFormatConfigWidget::slotCodeStyleChanged( d->config->setIsReadOnly(codeStyle->isReadOnly()); d->style = d->config->style(); - d->checksWidget->setEnabled(!codeStyle->isReadOnly() - && !codeStyle->isTemporarilyReadOnly()); + d->checksWidget->setEnabled(!codeStyle->isReadOnly() && !codeStyle->isTemporarilyReadOnly() + && !codeStyle->isAdditionalTabDisabled()); fillTable(); updatePreview(); diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index a0344e14eda..1f810c968cd 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -153,9 +153,20 @@ void ClangFormatGlobalConfigWidget::initOverrideCheckBox() "can be overridden by the settings below.")); } - auto setEnableOverrideCheckBox = [this](int index) { + auto setTemporarilyReadOnly = [this]() { + if (m_ignoreChanges.isLocked()) + return; + Utils::GuardLocker locker(m_ignoreChanges); + m_codeStyle->currentPreferences()->setTemporarilyReadOnly(!m_overrideDefault->isChecked()); + m_codeStyle->currentPreferences()->setIsAdditionalTabDisabled(!m_overrideDefault->isEnabled()); + ClangFormatSettings::instance().write(); + emit m_codeStyle->currentPreferencesChanged(m_codeStyle->currentPreferences()); + }; + + auto setEnableOverrideCheckBox = [this, setTemporarilyReadOnly](int index) { bool isDisable = index == static_cast(ClangFormatSettings::Mode::Disable); m_overrideDefault->setDisabled(isDisable); + setTemporarilyReadOnly(); }; setEnableOverrideCheckBox(m_indentingOrFormatting->currentIndex()); @@ -166,20 +177,19 @@ void ClangFormatGlobalConfigWidget::initOverrideCheckBox() Tr::tr("Override Clang Format configuration file with the chosen configuration.")); m_overrideDefault->setChecked(getProjectOverriddenSettings(m_project)); - m_codeStyle->currentPreferences()->setTemporarilyReadOnly(!m_overrideDefault->isChecked()); + setTemporarilyReadOnly(); - connect(m_overrideDefault, &QCheckBox::toggled, this, [this](bool checked) { + connect(m_overrideDefault, &QCheckBox::toggled, this, [this, setTemporarilyReadOnly](bool checked) { if (m_project) m_project->setNamedSettings(Constants::OVERRIDE_FILE_ID, checked); - else { - m_codeStyle->currentPreferences()->setTemporarilyReadOnly(!checked); - emit m_codeStyle->currentPreferencesChanged(m_codeStyle->currentPreferences()); - } + else + setTemporarilyReadOnly(); }); - connect(m_codeStyle, &TextEditor::ICodeStylePreferences::currentPreferencesChanged, this, [this] { - m_codeStyle->currentPreferences()->setTemporarilyReadOnly(!m_overrideDefault->isChecked()); - }); + connect(m_codeStyle, + &TextEditor::ICodeStylePreferences::currentPreferencesChanged, + this, + setTemporarilyReadOnly); } diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.h b/src/plugins/clangformat/clangformatglobalconfigwidget.h index 063c82852a3..962a7daaf17 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.h +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.h @@ -5,6 +5,8 @@ #include +#include + #include QT_BEGIN_NAMESPACE @@ -40,6 +42,7 @@ private: ProjectExplorer::Project *m_project; TextEditor::ICodeStylePreferences *m_codeStyle; + Utils::Guard m_ignoreChanges; QLabel *m_projectHasClangFormat; QLabel *m_formattingModeLabel; diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 120e27fde7b..a9f1a0d29b2 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -213,10 +213,14 @@ bool getCurrentOverriddenSettings(const Utils::FilePath &filePath) const ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( filePath); - return getProjectUseGlobalSettings(project) ? !TextEditor::TextEditorSettings::codeStyle("Cpp") - ->currentPreferences() - ->isTemporarilyReadOnly() - : getProjectOverriddenSettings(project); + return getProjectUseGlobalSettings(project) + ? !TextEditor::TextEditorSettings::codeStyle("Cpp") + ->currentPreferences() + ->isTemporarilyReadOnly() + && !TextEditor::TextEditorSettings::codeStyle("Cpp") + ->currentPreferences() + ->isAdditionalTabDisabled() + : getProjectOverriddenSettings(project); } ClangFormatSettings::Mode getProjectIndentationOrFormattingSettings( diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index ebb4a37485d..02adc539693 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -414,7 +414,8 @@ void CppCodeStylePreferencesWidget::setCodeStyleSettings(const CppCodeStyleSetti void CppCodeStylePreferencesWidget::slotCurrentPreferencesChanged(ICodeStylePreferences *preferences, bool preview) { - const bool enable = !preferences->isReadOnly() && !preferences->isTemporarilyReadOnly(); + const bool enable = !preferences->isReadOnly() && (!preferences->isTemporarilyReadOnly() + || preferences->isAdditionalTabDisabled()); for (QWidget *widget : d->m_controllers) widget->setEnabled(enable); diff --git a/src/plugins/texteditor/icodestylepreferences.cpp b/src/plugins/texteditor/icodestylepreferences.cpp index 931714b71c5..29a524ebf68 100644 --- a/src/plugins/texteditor/icodestylepreferences.cpp +++ b/src/plugins/texteditor/icodestylepreferences.cpp @@ -25,6 +25,7 @@ public: QString m_displayName; bool m_readOnly = false; bool m_temporarilyReadOnly = false; + bool m_isAdditionalTabDisabled = false; QString m_settingsSuffix; }; @@ -82,6 +83,16 @@ bool ICodeStylePreferences::isTemporarilyReadOnly() const return d->m_temporarilyReadOnly; } +bool ICodeStylePreferences::isAdditionalTabDisabled() const +{ + return d->m_isAdditionalTabDisabled; +} + +void ICodeStylePreferences::setIsAdditionalTabDisabled(bool on) +{ + d->m_isAdditionalTabDisabled = on; +} + void ICodeStylePreferences::setTabSettings(const TabSettings &settings) { if (d->m_tabSettings == settings) diff --git a/src/plugins/texteditor/icodestylepreferences.h b/src/plugins/texteditor/icodestylepreferences.h index 1c363903445..7fd616d5604 100644 --- a/src/plugins/texteditor/icodestylepreferences.h +++ b/src/plugins/texteditor/icodestylepreferences.h @@ -40,6 +40,9 @@ public: bool isTemporarilyReadOnly() const; void setTemporarilyReadOnly(bool on); + bool isAdditionalTabDisabled() const; + void setIsAdditionalTabDisabled(bool on); + void setTabSettings(const TabSettings &settings); TabSettings tabSettings() const; TabSettings currentTabSettings() const; From 74f6b9631561022b1dc1980e81a098707d87897c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 23:28:37 +0200 Subject: [PATCH 0973/1447] CppIncludesFilter: Remove the old matchesFor() implementation Change-Id: I8c65041e22195ecb44e32a8102800c2020298f71 Reviewed-by: Christian Kandeler Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/cppeditor/cppincludesfilter.cpp | 125 ++------------------ src/plugins/cppeditor/cppincludesfilter.h | 10 +- 2 files changed, 11 insertions(+), 124 deletions(-) diff --git a/src/plugins/cppeditor/cppincludesfilter.cpp b/src/plugins/cppeditor/cppincludesfilter.cpp index 7f84b55932c..9711b6f52de 100644 --- a/src/plugins/cppeditor/cppincludesfilter.cpp +++ b/src/plugins/cppeditor/cppincludesfilter.cpp @@ -9,14 +9,9 @@ #include -#include - #include #include #include -#include - -#include using namespace Core; using namespace ProjectExplorer; @@ -24,79 +19,6 @@ using namespace Utils; namespace CppEditor::Internal { -class CppIncludesIterator final : public BaseFileFilter::Iterator -{ -public: - CppIncludesIterator(CPlusPlus::Snapshot snapshot, const QSet &seedPaths) - : m_snapshot(snapshot), - m_paths(seedPaths) - { - toFront(); - } - - void toFront() override; - bool hasNext() const override; - Utils::FilePath next() override; - Utils::FilePath filePath() const override; - -private: - void fetchMore(); - - CPlusPlus::Snapshot m_snapshot; - QSet m_paths; - QSet m_queuedPaths; - QSet m_allResultPaths; - FilePaths m_resultQueue; - FilePath m_currentPath; -}; - -void CppIncludesIterator::toFront() -{ - m_queuedPaths = m_paths; - m_allResultPaths.clear(); - m_resultQueue.clear(); - fetchMore(); -} - -bool CppIncludesIterator::hasNext() const -{ - return !m_resultQueue.isEmpty(); -} - -FilePath CppIncludesIterator::next() -{ - if (m_resultQueue.isEmpty()) - return {}; - m_currentPath = m_resultQueue.takeFirst(); - if (m_resultQueue.isEmpty()) - fetchMore(); - return m_currentPath; -} - -FilePath CppIncludesIterator::filePath() const -{ - return m_currentPath; -} - -void CppIncludesIterator::fetchMore() -{ - while (!m_queuedPaths.isEmpty() && m_resultQueue.isEmpty()) { - const FilePath filePath = *m_queuedPaths.begin(); - m_queuedPaths.remove(filePath); - CPlusPlus::Document::Ptr doc = m_snapshot.document(filePath); - if (!doc) - continue; - const FilePaths includedFiles = doc->includedFiles(); - for (const FilePath &includedPath : includedFiles ) { - if (!m_allResultPaths.contains(includedPath)) { - m_allResultPaths.insert(includedPath); - m_queuedPaths.insert(includedPath); - m_resultQueue.append(includedPath); - } - } - } -} - static FilePaths generateFilePaths(const QFuture &future, const CPlusPlus::Snapshot &snapshot, const std::unordered_set &inputFilePaths) @@ -123,7 +45,6 @@ static FilePaths generateFilePaths(const QFuture &future, } } } - return results; } @@ -137,23 +58,24 @@ CppIncludesFilter::CppIncludesFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("ai"); setDefaultIncludedByDefault(true); - setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); })); + const auto invalidate = [this] { m_cache.invalidate(); }; + setRefreshRecipe(Tasking::Sync([invalidate] { invalidate(); return true; })); setPriority(ILocatorFilter::Low); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, - this, &CppIncludesFilter::invalidateCache); + this, invalidate); connect(CppModelManager::instance(), &CppModelManager::documentUpdated, - this, &CppIncludesFilter::invalidateCache); + this, invalidate); connect(CppModelManager::instance(), &CppModelManager::aboutToRemoveFiles, - this, &CppIncludesFilter::invalidateCache); + this, invalidate); connect(DocumentModel::model(), &QAbstractItemModel::rowsInserted, - this, &CppIncludesFilter::invalidateCache); + this, invalidate); connect(DocumentModel::model(), &QAbstractItemModel::rowsRemoved, - this, &CppIncludesFilter::invalidateCache); + this, invalidate); connect(DocumentModel::model(), &QAbstractItemModel::dataChanged, - this, &CppIncludesFilter::invalidateCache); + this, invalidate); connect(DocumentModel::model(), &QAbstractItemModel::modelReset, - this, &CppIncludesFilter::invalidateCache); + this, invalidate); const auto generatorProvider = [] { // This body runs in main thread @@ -177,33 +99,4 @@ CppIncludesFilter::CppIncludesFilter() m_cache.setGeneratorProvider(generatorProvider); } -void CppIncludesFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - if (m_needsUpdate) { - m_needsUpdate = false; - QSet seedPaths; - for (Project *project : ProjectManager::projects()) { - const FilePaths allFiles = project->files(Project::SourceFiles); - for (const FilePath &filePath : allFiles ) - seedPaths.insert(filePath); - } - const QList entries = DocumentModel::entries(); - for (DocumentModel::Entry *entry : entries) { - if (entry) - seedPaths.insert(entry->filePath()); - } - CPlusPlus::Snapshot snapshot = CppModelManager::instance()->snapshot(); - setFileIterator(new CppIncludesIterator(snapshot, seedPaths)); - } - BaseFileFilter::prepareSearch(entry); -} - -void CppIncludesFilter::invalidateCache() -{ - m_cache.invalidate(); - m_needsUpdate = true; - setFileIterator(nullptr); // clean up -} - } // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cppincludesfilter.h b/src/plugins/cppeditor/cppincludesfilter.h index d86b9991858..4ab5ffba97f 100644 --- a/src/plugins/cppeditor/cppincludesfilter.h +++ b/src/plugins/cppeditor/cppincludesfilter.h @@ -3,24 +3,18 @@ #pragma once -#include +#include namespace CppEditor::Internal { -class CppIncludesFilter : public Core::BaseFileFilter +class CppIncludesFilter : public Core::ILocatorFilter { public: CppIncludesFilter(); -public: - void prepareSearch(const QString &entry) override; - private: Core::LocatorMatcherTasks matchers() final { return {m_cache.matcher()}; } - void invalidateCache(); - Core::LocatorFileCache m_cache; - bool m_needsUpdate = true; }; } // namespace CppEditor::Internal From 7d87233c9c70eed9bf10d36ff1d4da115c071db7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 00:17:52 +0200 Subject: [PATCH 0974/1447] ClangCodeModel: Remove the old matchesFor() implementation Rename some filter classes to conform to the names for cpp filters. Remove some unneeded intermediate classes now. Change-Id: Ib4fa295fa60da61c42c792556751d954ddb936e7 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../clangcodemodel/clangdlocatorfilters.cpp | 299 +----------------- .../clangcodemodel/clangdlocatorfilters.h | 50 +-- .../clangmodelmanagersupport.cpp | 6 +- src/plugins/cppeditor/cppmodelmanager.cpp | 7 - src/plugins/cppeditor/cppmodelmanager.h | 2 - 5 files changed, 30 insertions(+), 334 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index e81e3bfebf1..6d3ab92e144 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -6,21 +6,17 @@ #include "clangdclient.h" #include "clangmodelmanagersupport.h" -#include #include #include #include -#include -#include + #include + #include -#include -#include #include -#include + #include #include -#include #include @@ -31,124 +27,11 @@ using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; -namespace ClangCodeModel { -namespace Internal { +namespace ClangCodeModel::Internal { const int MaxResultCount = 10000; -// TODO: Remove this class, it's used only internally by ClangGlobalSymbolFilter -class CppLocatorFilter : public CppEditor::CppLocatorFilter -{ -public: - CppLocatorFilter() - { - setId({}); - setDisplayName({}); - setDescription({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); - } -}; - -// TODO: Remove this class, it's used only internally by ClangGlobalSymbolFilter -class LspWorkspaceFilter : public WorkspaceLocatorFilter -{ -public: - LspWorkspaceFilter() - { - setId({}); - setDisplayName({}); - setDescription({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); - setMaxResultCount(MaxResultCount); - } - void prepareSearch(const QString &entry) override - { - prepareSearchForClients(entry, ClangModelManagerSupport::clientsForOpenProjects()); - } -}; - -// TODO: Remove this class, it's used only internally by ClangClassesFilter -class CppClassesFilter : public CppEditor::CppClassesFilter -{ -public: - CppClassesFilter() - { - setId({}); - setDisplayName({}); - setDescription({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); - } -}; - -// TODO: Remove this class, it's used only internally by ClangClassesFilter -class LspClassesFilter : public WorkspaceClassLocatorFilter -{ -public: - LspClassesFilter() { - setId({}); - setDisplayName({}); - setDescription({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); - setMaxResultCount(MaxResultCount); - } - void prepareSearch(const QString &entry) override - { - prepareSearchForClients(entry, ClangModelManagerSupport::clientsForOpenProjects()); - } -}; - -// TODO: Remove this class, it's used only internally by ClangFunctionsFilter -class CppFunctionsFilter : public CppEditor::CppFunctionsFilter -{ -public: - CppFunctionsFilter() - { - setId({}); - setDisplayName({}); - setDescription({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); - } -}; - -// TODO: Remove this class, it's used only internally by ClangFunctionsFilter -class LspFunctionsFilter : public WorkspaceMethodLocatorFilter -{ -public: - LspFunctionsFilter() - { - setId({}); - setDisplayName({}); - setDescription({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); - setMaxResultCount(MaxResultCount); - } - void prepareSearch(const QString &entry) override - { - prepareSearchForClients(entry, ClangModelManagerSupport::clientsForOpenProjects()); - } -}; - - -ClangGlobalSymbolFilter::ClangGlobalSymbolFilter() - : ClangGlobalSymbolFilter(new CppLocatorFilter, new LspWorkspaceFilter) -{ -} - -ClangGlobalSymbolFilter::ClangGlobalSymbolFilter(ILocatorFilter *cppFilter, - ILocatorFilter *lspFilter) - : m_cppFilter(cppFilter), m_lspFilter(lspFilter) +ClangdAllSymbolsFilter::ClangdAllSymbolsFilter() { setId(CppEditor::Constants::LOCATOR_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::LOCATOR_FILTER_DISPLAY_NAME)); @@ -157,33 +40,14 @@ ClangGlobalSymbolFilter::ClangGlobalSymbolFilter(ILocatorFilter *cppFilter, setDefaultIncludedByDefault(false); } -ClangGlobalSymbolFilter::~ClangGlobalSymbolFilter() -{ - delete m_cppFilter; - delete m_lspFilter; -} - -LocatorMatcherTasks ClangGlobalSymbolFilter::matchers() +LocatorMatcherTasks ClangdAllSymbolsFilter::matchers() { return CppEditor::cppMatchers(MatcherType::AllSymbols) + LanguageClient::languageClientMatchers(MatcherType::AllSymbols, ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); } -void ClangGlobalSymbolFilter::prepareSearch(const QString &entry) -{ - m_cppFilter->prepareSearch(entry); - m_lspFilter->prepareSearch(entry); -} - -QList ClangGlobalSymbolFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - return m_cppFilter->matchesFor(future, entry) + m_lspFilter->matchesFor(future, entry); -} - -ClangClassesFilter::ClangClassesFilter() - : ClangGlobalSymbolFilter(new CppClassesFilter, new LspClassesFilter) +ClangdClassesFilter::ClangdClassesFilter() { setId(CppEditor::Constants::CLASSES_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::CLASSES_FILTER_DISPLAY_NAME)); @@ -192,15 +56,14 @@ ClangClassesFilter::ClangClassesFilter() setDefaultIncludedByDefault(false); } -LocatorMatcherTasks ClangClassesFilter::matchers() +LocatorMatcherTasks ClangdClassesFilter::matchers() { return CppEditor::cppMatchers(MatcherType::Classes) + LanguageClient::languageClientMatchers(MatcherType::Classes, ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); } -ClangFunctionsFilter::ClangFunctionsFilter() - : ClangGlobalSymbolFilter(new CppFunctionsFilter, new LspFunctionsFilter) +ClangdFunctionsFilter::ClangdFunctionsFilter() { setId(CppEditor::Constants::FUNCTIONS_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::FUNCTIONS_FILTER_DISPLAY_NAME)); @@ -209,129 +72,14 @@ ClangFunctionsFilter::ClangFunctionsFilter() setDefaultIncludedByDefault(false); } -LocatorMatcherTasks ClangFunctionsFilter::matchers() +LocatorMatcherTasks ClangdFunctionsFilter::matchers() { return CppEditor::cppMatchers(MatcherType::Functions) + LanguageClient::languageClientMatchers(MatcherType::Functions, ClangModelManagerSupport::clientsForOpenProjects(), MaxResultCount); } -// TODO: Remove this class, it's used only internally by ClangdCurrentDocumentFilter -class LspCurrentDocumentFilter : public DocumentLocatorFilter -{ -public: - LspCurrentDocumentFilter() - { - setId({}); - setDisplayName({}); - setDescription({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); - forceUse(); - } - -private: - void prepareSearch(const QString &entry) override - { - DocumentLocatorFilter::prepareSearch(entry); - m_content = TextEditor::TextDocument::currentTextDocument()->plainText(); - } - - // Filter out declarations for which a definition is also present. - QList matchesFor(QFutureInterface &future, - const QString &entry) override - { - struct Entry - { - LocatorFilterEntry entry; - DocumentSymbol symbol; - }; - QList docEntries; - - const auto docSymbolModifier = [&docEntries](LocatorFilterEntry &entry, - const DocumentSymbol &info, - const LocatorFilterEntry &parent) { - entry.displayName = ClangdClient::displayNameFromDocumentSymbol( - static_cast(info.kind()), info.name(), - info.detail().value_or(QString())); - entry.extraInfo = parent.extraInfo; - if (!entry.extraInfo.isEmpty()) - entry.extraInfo.append("::"); - entry.extraInfo.append(parent.displayName); - - // TODO: Can we extend clangd to send visibility information? - docEntries.append({entry, info}); - }; - - const QList allMatches = matchesForImpl(future, entry, - docSymbolModifier); - if (docEntries.isEmpty()) - return allMatches; // SymbolInformation case - - QTC_CHECK(docEntries.size() == allMatches.size()); - QHash> possibleDuplicates; - for (const Entry &e : std::as_const(docEntries)) - possibleDuplicates[e.entry.displayName + e.entry.extraInfo] << e; - const QTextDocument doc(m_content); - for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { - const QList &duplicates = it.value(); - if (duplicates.size() == 1) - continue; - QList declarations; - QList definitions; - for (const Entry &candidate : duplicates) { - const DocumentSymbol symbol = candidate.symbol; - const SymbolKind kind = static_cast(symbol.kind()); - if (kind != SymbolKind::Class && kind != SymbolKind::Function) - break; - const Range range = symbol.range(); - const Range selectionRange = symbol.selectionRange(); - if (kind == SymbolKind::Class) { - if (range.end() == selectionRange.end()) - declarations << candidate; - else - definitions << candidate; - continue; - } - const int startPos = selectionRange.end().toPositionInDocument(&doc); - const int endPos = range.end().toPositionInDocument(&doc); - const QString functionBody = m_content.mid(startPos, endPos - startPos); - - // Hacky, but I don't see anything better. - if (functionBody.contains('{') && functionBody.contains('}')) - definitions << candidate; - else - declarations << candidate; - } - if (definitions.size() == 1 - && declarations.size() + definitions.size() == duplicates.size()) { - for (const Entry &decl : std::as_const(declarations)) { - Utils::erase(docEntries, [&decl](const Entry &e) { - return e.symbol == decl.symbol; - }); - } - } - } - return Utils::transform(docEntries, [](const Entry &entry) { return entry.entry; }); - } - - QString m_content; -}; - -class ClangdCurrentDocumentFilter::Private -{ -public: - ~Private() { delete cppFilter; } - - ILocatorFilter * const cppFilter - = CppEditor::CppModelManager::createAuxiliaryCurrentDocumentFilter(); - LspCurrentDocumentFilter lspFilter; - ILocatorFilter *activeFilter = nullptr; -}; - - -ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private) +ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() { setId(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_ID); setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME)); @@ -344,8 +92,6 @@ ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private) this, [this](const IEditor *editor) { setEnabled(editor); }); } -ClangdCurrentDocumentFilter::~ClangdCurrentDocumentFilter() { delete d; } - static void filterCurrentResults(QPromise &promise, const LocatorStorage &storage, const CurrentDocumentSymbolsData ¤tSymbolsData, const QString &contents) @@ -468,25 +214,4 @@ LocatorMatcherTasks ClangdCurrentDocumentFilter::matchers() return CppEditor::cppMatchers(MatcherType::CurrentDocumentSymbols); } -void ClangdCurrentDocumentFilter::prepareSearch(const QString &entry) -{ - const auto doc = TextEditor::TextDocument::currentTextDocument(); - QTC_ASSERT(doc, return); - if (const ClangdClient * const client = ClangModelManagerSupport::clientForFile - (doc->filePath()); client && client->reachable()) { - d->activeFilter = &d->lspFilter; - } else { - d->activeFilter = d->cppFilter; - } - d->activeFilter->prepareSearch(entry); -} - -QList ClangdCurrentDocumentFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - QTC_ASSERT(d->activeFilter, return {}); - return d->activeFilter->matchesFor(future, entry); -} - -} // namespace Internal -} // namespace ClangCodeModel +} // namespace ClangCodeModel::Internal diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index 8074c95c9ac..1aba669417e 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -5,43 +5,30 @@ #include -namespace LanguageClient { class WorkspaceLocatorFilter; } +namespace ClangCodeModel::Internal { -namespace ClangCodeModel { -namespace Internal { - -class ClangGlobalSymbolFilter : public Core::ILocatorFilter +class ClangdAllSymbolsFilter : public Core::ILocatorFilter { public: - ClangGlobalSymbolFilter(); - ClangGlobalSymbolFilter(Core::ILocatorFilter *cppFilter, - Core::ILocatorFilter *lspFilter); - ~ClangGlobalSymbolFilter() override; - -private: - Core::LocatorMatcherTasks matchers() override; - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; - Core::ILocatorFilter * const m_cppFilter; - Core::ILocatorFilter * const m_lspFilter; -}; - -// TODO: Don't derive, flatten the hierarchy -class ClangClassesFilter : public ClangGlobalSymbolFilter -{ -public: - ClangClassesFilter(); + ClangdAllSymbolsFilter(); private: Core::LocatorMatcherTasks matchers() final; }; -// TODO: Don't derive, flatten the hierarchy -class ClangFunctionsFilter : public ClangGlobalSymbolFilter +class ClangdClassesFilter : public Core::ILocatorFilter { public: - ClangFunctionsFilter(); + ClangdClassesFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; +}; + +class ClangdFunctionsFilter : public Core::ILocatorFilter +{ +public: + ClangdFunctionsFilter(); private: Core::LocatorMatcherTasks matchers() final; @@ -51,16 +38,9 @@ class ClangdCurrentDocumentFilter : public Core::ILocatorFilter { public: ClangdCurrentDocumentFilter(); - ~ClangdCurrentDocumentFilter() override; private: Core::LocatorMatcherTasks matchers() final; - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; - class Private; - Private * const d; }; -} // namespace Internal -} // namespace ClangCodeModel +} // namespace ClangCodeModel::Internal diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 57401da2660..1dd66db3cda 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -202,9 +202,9 @@ ClangModelManagerSupport::ClangModelManagerSupport() setupClangdConfigFile(); checkSystemForClangdSuitability(); cppModelManager()->setCurrentDocumentFilter(std::make_unique()); - cppModelManager()->setLocatorFilter(std::make_unique()); - cppModelManager()->setClassesFilter(std::make_unique()); - cppModelManager()->setFunctionsFilter(std::make_unique()); + cppModelManager()->setLocatorFilter(std::make_unique()); + cppModelManager()->setClassesFilter(std::make_unique()); + cppModelManager()->setFunctionsFilter(std::make_unique()); // Setup matchers LocatorMatcher::addMatcherCreator(MatcherType::AllSymbols, [] { return LanguageClient::languageClientMatchers( diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 36c3832641d..c249dd29392 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -2020,13 +2020,6 @@ void CppModelManager::switchDeclDef(const CursorInEditor &data, instance()->modelManagerSupport(backend)->switchDeclDef(data, processLinkCallback); } -ILocatorFilter *CppModelManager::createAuxiliaryCurrentDocumentFilter() -{ - const auto filter = new Internal::CppCurrentDocumentFilter; - filter->makeAuxiliary(); - return filter; -} - BaseEditorDocumentProcessor *CppModelManager::createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) const { diff --git a/src/plugins/cppeditor/cppmodelmanager.h b/src/plugins/cppeditor/cppmodelmanager.h index 2929d615e62..3ab9ee26898 100644 --- a/src/plugins/cppeditor/cppmodelmanager.h +++ b/src/plugins/cppeditor/cppmodelmanager.h @@ -196,8 +196,6 @@ public: const CPlusPlus::LookupContext &context, const Utils::LinkHandler &callback); - static Core::ILocatorFilter *createAuxiliaryCurrentDocumentFilter(); - CppIndexingSupport *indexingSupport(); Utils::FilePaths projectFiles(); From 5a0f2e6d15123559d0d489b8b466888af28136ef Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 14:24:24 +0200 Subject: [PATCH 0975/1447] Utils: move extractFromFileName from LineColumn to Text::Position Change-Id: Ibb2465e66c280d4201377921f69741a050d94bc1 Reviewed-by: Jarek Kobus Reviewed-by: Qt CI Bot --- src/libs/utils/CMakeLists.txt | 2 +- src/libs/utils/linecolumn.cpp | 43 ----------------------------------- src/libs/utils/linecolumn.h | 5 ---- src/libs/utils/link.cpp | 8 +++---- src/libs/utils/textutils.cpp | 36 ++++++++++++++++++++++++++++- src/libs/utils/textutils.h | 2 ++ src/libs/utils/utils.qbs | 1 - 7 files changed, 42 insertions(+), 55 deletions(-) delete mode 100644 src/libs/utils/linecolumn.cpp diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index f05398094a4..5fa076027fd 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -89,7 +89,7 @@ add_qtc_library(Utils launcherpackets.cpp launcherpackets.h launchersocket.cpp launchersocket.h layoutbuilder.cpp layoutbuilder.h - linecolumn.cpp linecolumn.h + linecolumn.h link.cpp link.h listmodel.h listutils.h diff --git a/src/libs/utils/linecolumn.cpp b/src/libs/utils/linecolumn.cpp deleted file mode 100644 index 50a24ada62c..00000000000 --- a/src/libs/utils/linecolumn.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "linecolumn.h" - -#include - -namespace Utils { - -/*! - Returns the line and column of a \a fileName and sets the \a postfixPos if - it can find a positional postfix. - - The following patterns are supported: \c {filepath.txt:19}, - \c{filepath.txt:19:12}, \c {filepath.txt+19}, - \c {filepath.txt+19+12}, and \c {filepath.txt(19)}. -*/ - -LineColumn LineColumn::extractFromFileName(QStringView fileName, int &postfixPos) -{ - static const auto regexp = QRegularExpression("[:+](\\d+)?([:+](\\d+)?)?$"); - // (10) MSVC-style - static const auto vsRegexp = QRegularExpression("[(]((\\d+)[)]?)?$"); - const QRegularExpressionMatch match = regexp.match(fileName); - LineColumn lineColumn; - if (match.hasMatch()) { - postfixPos = match.capturedStart(0); - lineColumn.line = 0; // for the case that there's only a : at the end - if (match.lastCapturedIndex() > 0) { - lineColumn.line = match.captured(1).toInt(); - if (match.lastCapturedIndex() > 2) // index 2 includes the + or : for the column number - lineColumn.column = match.captured(3).toInt() - 1; //column is 0 based, despite line being 1 based - } - } else { - const QRegularExpressionMatch vsMatch = vsRegexp.match(fileName); - postfixPos = vsMatch.capturedStart(0); - if (vsMatch.lastCapturedIndex() > 1) // index 1 includes closing ) - lineColumn.line = vsMatch.captured(2).toInt(); - } - return lineColumn; -} - -} // namespace Utils diff --git a/src/libs/utils/linecolumn.h b/src/libs/utils/linecolumn.h index 922c981d79e..4cd982b8e7e 100644 --- a/src/libs/utils/linecolumn.h +++ b/src/libs/utils/linecolumn.h @@ -14,9 +14,6 @@ namespace Utils { class QTCREATOR_UTILS_EXPORT LineColumn { public: - constexpr LineColumn() = default; - constexpr LineColumn(int line, int column) : line(line), column(column) {} - bool isValid() const { return line > 0 && column >= 0; @@ -32,8 +29,6 @@ public: return !(first == second); } - static LineColumn extractFromFileName(QStringView fileName, int &postfixPos); - public: int line = 0; int column = -1; diff --git a/src/libs/utils/link.cpp b/src/libs/utils/link.cpp index e4c7032eeb7..1a4b4f9f9af 100644 --- a/src/libs/utils/link.cpp +++ b/src/libs/utils/link.cpp @@ -3,7 +3,7 @@ #include "link.h" -#include "linecolumn.h" +#include "textutils.h" namespace Utils { @@ -24,10 +24,10 @@ Link Link::fromString(const QString &filePathWithNumbers, bool canContainLineNum link.targetFilePath = FilePath::fromUserInput(filePathWithNumbers); } else { int postfixPos = -1; - const LineColumn lineColumn = LineColumn::extractFromFileName(filePathWithNumbers, postfixPos); + const Text::Position pos = Text::Position::fromFileName(filePathWithNumbers, postfixPos); link.targetFilePath = FilePath::fromUserInput(filePathWithNumbers.left(postfixPos)); - link.targetLine = lineColumn.line; - link.targetColumn = lineColumn.column; + link.targetLine = pos.line; + link.targetColumn = pos.column; } return link; } diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 55e8a736d05..5c9846a24d6 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -3,8 +3,9 @@ #include "textutils.h" -#include +#include #include +#include namespace Utils::Text { @@ -13,6 +14,39 @@ bool Position::operator==(const Position &other) const return line == other.line && column == other.column; } +/*! + Returns the text position of a \a fileName and sets the \a postfixPos if + it can find a positional postfix. + + The following patterns are supported: \c {filepath.txt:19}, + \c{filepath.txt:19:12}, \c {filepath.txt+19}, + \c {filepath.txt+19+12}, and \c {filepath.txt(19)}. +*/ + +Position Position::fromFileName(QStringView fileName, int &postfixPos) +{ + static const auto regexp = QRegularExpression("[:+](\\d+)?([:+](\\d+)?)?$"); + // (10) MSVC-style + static const auto vsRegexp = QRegularExpression("[(]((\\d+)[)]?)?$"); + const QRegularExpressionMatch match = regexp.match(fileName); + Position pos; + if (match.hasMatch()) { + postfixPos = match.capturedStart(0); + pos.line = 0; // for the case that there's only a : at the end + if (match.lastCapturedIndex() > 0) { + pos.line = match.captured(1).toInt(); + if (match.lastCapturedIndex() > 2) // index 2 includes the + or : for the column number + pos.column = match.captured(3).toInt() - 1; //column is 0 based, despite line being 1 based + } + } else { + const QRegularExpressionMatch vsMatch = vsRegexp.match(fileName); + postfixPos = vsMatch.capturedStart(0); + if (vsMatch.lastCapturedIndex() > 1) // index 1 includes closing ) + pos.line = vsMatch.captured(2).toInt(); + } + return pos; +} + int Range::length(const QString &text) const { if (begin.line == end.line) diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index 573dc7aa1d7..e278cf919f5 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -28,6 +28,8 @@ public: bool operator==(const Position &other) const; bool operator!=(const Position &other) const { return !(operator==(other)); } + + static Position fromFileName(QStringView fileName, int &postfixPos); }; class QTCREATOR_UTILS_EXPORT Range diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index f1940a053da..d3c826ef26f 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -185,7 +185,6 @@ Project { "launchersocket.h", "layoutbuilder.cpp", "layoutbuilder.h", - "linecolumn.cpp", "linecolumn.h", "link.cpp", "link.h", From e9cd4dd4392a7f82f41d9ca1af7e030b532d756d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 14:44:48 +0200 Subject: [PATCH 0976/1447] Utils: use Text::Position instead of LineColumn in textutils Change-Id: I606b0b4f8106bdb2f97383d6c81ac065e7e61858 Reviewed-by: Jarek Kobus --- src/libs/utils/textutils.cpp | 32 ++++++------------- src/libs/utils/textutils.h | 8 ++--- .../languageclient/languageclientsettings.cpp | 8 ++--- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 5c9846a24d6..34dbb5e1fa5 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -47,6 +47,15 @@ Position Position::fromFileName(QStringView fileName, int &postfixPos) return pos; } +Position Position::fromPositionInDocument(const QTextDocument *document, int pos) +{ + const QTextBlock block = document->findBlock(pos); + if (block.isValid()) + return {block.blockNumber() + 1, pos - block.position()}; + + return {}; +} + int Range::length(const QString &text) const { if (begin.line == end.line) @@ -87,15 +96,6 @@ bool convertPosition(const QTextDocument *document, int pos, int *line, int *col } } -LineColumn convertPosition(const QTextDocument *document, int pos) -{ - const QTextBlock block = document->findBlock(pos); - if (block.isValid()) - return {block.blockNumber() + 1, pos - block.position()}; - - return {}; -} - int positionInText(const QTextDocument *textDocument, int line, int column) { // Deduct 1 from line and column since they are 1-based. @@ -201,20 +201,6 @@ int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffe return utf8Offset; } -LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) -{ - LineColumn lineColumn; - lineColumn.line = static_cast( - std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n')) - + 1; - const int startOfLineOffset = utf8Offset ? (utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1) - : 0; - lineColumn.column = QString::fromUtf8( - utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset)) - .length(); - return lineColumn; -} - QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset) { const int lineStartUtf8Offset = currentUtf8Offset diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index e278cf919f5..14e83322a30 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -5,8 +5,6 @@ #include "utils_global.h" -#include "linecolumn.h" - #include QT_BEGIN_NAMESPACE @@ -29,7 +27,10 @@ public: bool operator!=(const Position &other) const { return !(operator==(other)); } + bool isValid() const { return line > 0 && column >= 0; } + static Position fromFileName(QStringView fileName, int &postfixPos); + static Position fromPositionInDocument(const QTextDocument *document, int pos); }; class QTCREATOR_UTILS_EXPORT Range @@ -70,8 +71,6 @@ QTCREATOR_UTILS_EXPORT void applyReplacements(QTextDocument *doc, const Replacem QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document, int pos, int *line, int *column); -QTCREATOR_UTILS_EXPORT -LineColumn convertPosition(const QTextDocument *document, int pos); // line and column are 1-based QTCREATOR_UTILS_EXPORT int positionInText(const QTextDocument *textDocument, int line, int column); @@ -90,7 +89,6 @@ QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffer, int line); -QTCREATOR_UTILS_EXPORT LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset); QTCREATOR_UTILS_EXPORT QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset); diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 92d314beabc..650b450a5d3 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -1030,6 +1030,7 @@ bool LanguageFilter::operator!=(const LanguageFilter &other) const TextEditor::BaseTextEditor *jsonEditor() { using namespace TextEditor; + using namespace Utils::Text; BaseTextEditor *editor = PlainTextEditorFactory::createPlainTextEditor(); TextDocument *document = editor->textDocument(); TextEditorWidget *widget = editor->editorWidget(); @@ -1052,12 +1053,11 @@ TextEditor::BaseTextEditor *jsonEditor() QJsonDocument::fromJson(content.toUtf8(), &error); if (error.error == QJsonParseError::NoError) return; - const Utils::LineColumn lineColumn - = Utils::Text::convertPosition(document->document(), error.offset); - if (!lineColumn.isValid()) + const Position pos = Position::fromPositionInDocument(document->document(), error.offset); + if (!pos.isValid()) return; auto mark = new TextMark(Utils::FilePath(), - lineColumn.line, + pos.line, {::LanguageClient::Tr::tr("JSON Error"), jsonMarkId}); mark->setLineAnnotation(error.errorString()); mark->setColor(Utils::Theme::CodeModel_Error_TextMarkColor); From 80f46c28a5608a07d2adb820dfc18f61b811df62 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 11 May 2023 12:59:34 +0200 Subject: [PATCH 0977/1447] Utils: fix build Change-Id: Ibc9050c8b3dd4a1fcba9e87f70b46908dbbd1dce Reviewed-by: hjk --- src/libs/utils/textutils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index 14e83322a30..4ba3b0e1a82 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -5,6 +5,7 @@ #include "utils_global.h" +#include #include QT_BEGIN_NAMESPACE From a69f58180c601aaabd25bd438215cf6c13572f03 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 11 May 2023 13:22:31 +0200 Subject: [PATCH 0978/1447] ClangFormat: Compile fix related to LineColumns Change-Id: I645d448bea8ee22db54b110cf83e58b7b2e20660 Reviewed-by: David Schulz --- src/plugins/clangformat/clangformatbaseindenter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 9ab44472304..062dfe5550a 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include From b8390d35442220af8509f8fea4a17c92ace55c9b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 20:06:53 +0200 Subject: [PATCH 0979/1447] LocatorWidget: Further simplifications Change-Id: Ia3a5eade7f49d45d08539b6bb3d2cbaf9fa12242 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../coreplugin/locator/locatorwidget.cpp | 95 ++++++------------- .../coreplugin/locator/locatorwidget.h | 10 +- 2 files changed, 32 insertions(+), 73 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 1384f7b5de0..6de120b4dc6 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -4,7 +4,6 @@ #include "locatorwidget.h" #include "ilocatorfilter.h" -#include "locator.h" #include "locatorconstants.h" #include "locatormanager.h" #include "../actionmanager/actionmanager.h" @@ -14,9 +13,6 @@ #include "../modemanager.h" #include -#include -#include -#include #include #include #include @@ -24,7 +20,6 @@ #include #include #include -#include #include #include @@ -32,16 +27,13 @@ #include #include #include -#include #include #include #include +#include #include -#include #include -#include #include -#include Q_DECLARE_METATYPE(Core::LocatorFilterEntry) @@ -442,9 +434,10 @@ LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent) }, Qt::DirectConnection); // must be handled directly before event is deleted connect(m_tree, &QAbstractItemView::activated, locatorWidget, [this, locatorWidget](const QModelIndex &index) { - if (isVisible()) - locatorWidget->scheduleAcceptEntry(index); - }); + if (!index.isValid() || !isVisible()) + return; + locatorWidget->acceptEntry(index.row()); + }); } CompletionList *LocatorPopup::completionList() const @@ -457,29 +450,28 @@ LocatorWidget *LocatorPopup::inputWidget() const return m_inputWidget; } -void LocatorPopup::focusOutEvent(QFocusEvent *event) { +void LocatorPopup::focusOutEvent(QFocusEvent *event) +{ if (event->reason() == Qt::ActiveWindowFocusReason) hide(); QWidget::focusOutEvent(event); } -void CompletionList::next() { +void CompletionList::next() +{ int index = currentIndex().row(); ++index; - if (index >= model()->rowCount(QModelIndex())) { - // wrap - index = 0; - } + if (index >= model()->rowCount(QModelIndex())) + index = 0; // wrap setCurrentIndex(model()->index(index, 0)); } -void CompletionList::previous() { +void CompletionList::previous() +{ int index = currentIndex().row(); --index; - if (index < 0) { - // wrap - index = model()->rowCount(QModelIndex()) - 1; - } + if (index < 0) + index = model()->rowCount(QModelIndex()) - 1; // wrap setCurrentIndex(model()->index(index, 0)); } @@ -616,12 +608,7 @@ LocatorWidget::LocatorWidget(Locator *locator) locator->refresh(Locator::filters()); }); connect(m_configureAction, &QAction::triggered, this, &LocatorWidget::showConfigureDialog); - connect(m_fileLineEdit, &QLineEdit::textChanged, - this, &LocatorWidget::showPopupDelayed); - - m_showPopupTimer.setInterval(100); - m_showPopupTimer.setSingleShot(true); - connect(&m_showPopupTimer, &QTimer::timeout, this, &LocatorWidget::showPopupNow); + connect(m_fileLineEdit, &QLineEdit::textChanged, this, &LocatorWidget::showPopupNow); m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Small, m_fileLineEdit); @@ -634,7 +621,7 @@ LocatorWidget::LocatorWidget(Locator *locator) Command *locateCmd = ActionManager::command(Constants::LOCATE); if (QTC_GUARD(locateCmd)) { - connect(locateCmd, &Command::keySequenceChanged, this, [this,locateCmd] { + connect(locateCmd, &Command::keySequenceChanged, this, [this, locateCmd] { updatePlaceholderText(locateCmd); }); updatePlaceholderText(locateCmd); @@ -846,15 +833,8 @@ bool LocatorWidget::eventFilter(QObject *obj, QEvent *event) return QWidget::eventFilter(obj, event); } -void LocatorWidget::showPopupDelayed() -{ - m_updateRequested = true; - m_showPopupTimer.start(); -} - void LocatorWidget::showPopupNow() { - m_showPopupTimer.stop(); runMatcher(m_fileLineEdit->text()); emit showPopup(); } @@ -913,28 +893,25 @@ void LocatorWidget::runMatcher(const QString &text) m_locatorMatcher.reset(new LocatorMatcher); m_locatorMatcher->setTasks(tasks); m_locatorMatcher->setInputData(searchText); + m_rowRequestedForAccept.reset(); - connect(m_locatorMatcher.get(), &LocatorMatcher::done, this, [this] { + std::shared_ptr needsClearResult = std::make_shared(true); + connect(m_locatorMatcher.get(), &LocatorMatcher::done, this, [this, needsClearResult] { m_showProgressTimer.stop(); setProgressIndicatorVisible(false); - m_updateRequested = false; m_locatorMatcher.release()->deleteLater(); if (m_rowRequestedForAccept) { acceptEntry(m_rowRequestedForAccept.value()); m_rowRequestedForAccept.reset(); return; } - if (m_needsClearResult) { + if (needsClearResult->exchange(false)) m_locatorModel->clear(); - m_needsClearResult = false; - } }); connect(m_locatorMatcher.get(), &LocatorMatcher::serialOutputDataReady, - this, [this](const LocatorFilterEntries &serialOutputData) { - if (m_needsClearResult) { + this, [this, needsClearResult](const LocatorFilterEntries &serialOutputData) { + if (needsClearResult->exchange(false)) m_locatorModel->clear(); - m_needsClearResult = false; - } const bool selectFirst = m_locatorModel->rowCount() == 0; m_locatorModel->addEntries(serialOutputData); if (selectFirst) { @@ -945,26 +922,15 @@ void LocatorWidget::runMatcher(const QString &text) }); m_showProgressTimer.start(); - m_needsClearResult = true; - m_updateRequested = true; m_locatorMatcher->start(); } -void LocatorWidget::scheduleAcceptEntry(const QModelIndex &index) -{ - if (m_updateRequested) { - // don't just accept the selected entry, since the list is not up to date - // accept will be called after the update finished - m_rowRequestedForAccept = index.row(); - // do not wait for the rest of the search to finish - m_locatorMatcher.reset(); - } else { - acceptEntry(index.row()); - } -} - void LocatorWidget::acceptEntry(int row) { + if (m_locatorMatcher) { + m_rowRequestedForAccept = row; + return; + } if (row < 0 || row >= m_locatorModel->rowCount()) return; const QModelIndex index = m_locatorModel->index(row, 0); @@ -972,13 +938,12 @@ void LocatorWidget::acceptEntry(int row) return; const LocatorFilterEntry entry = m_locatorModel->data(index, LocatorEntryRole).value(); + if (!entry.acceptor) { // Opening editors can open dialogs (e.g. the ssh prompt, or showing erros), so delay until // we have hidden the popup with emit hidePopup below and Qt actually processed that - QMetaObject::invokeMethod( - EditorManager::instance(), - [entry] { EditorManager::openEditor(entry); }, - Qt::QueuedConnection); + QMetaObject::invokeMethod(EditorManager::instance(), + [entry] { EditorManager::openEditor(entry); }, Qt::QueuedConnection); } QWidget *focusBeforeAccept = QApplication::focusWidget(); const AcceptResult result = entry.acceptor ? entry.acceptor() : AcceptResult(); diff --git a/src/plugins/coreplugin/locator/locatorwidget.h b/src/plugins/coreplugin/locator/locatorwidget.h index ec3eca56f89..c766637c3dc 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.h +++ b/src/plugins/coreplugin/locator/locatorwidget.h @@ -7,8 +7,8 @@ #include -#include #include +#include #include #include @@ -41,8 +41,7 @@ public: QAbstractItemModel *model() const; void updatePlaceholderText(Command *command); - - void scheduleAcceptEntry(const QModelIndex &index); + void acceptEntry(int row); signals: void showCurrentItemToolTip(); @@ -54,9 +53,7 @@ signals: void showPopup(); private: - void showPopupDelayed(); void showPopupNow(); - void acceptEntry(int row); static void showConfigureDialog(); void updateFilterList(); bool isInMainWindow() const; @@ -74,9 +71,6 @@ private: QAction *m_refreshAction = nullptr; QAction *m_configureAction = nullptr; Utils::FancyLineEdit *m_fileLineEdit = nullptr; - QTimer m_showPopupTimer; - bool m_needsClearResult = true; - bool m_updateRequested = false; bool m_possibleToolTipRequest = false; QWidget *m_progressIndicator = nullptr; QTimer m_showProgressTimer; From a631a0441e011d0c28f7a5dbf7810c826252f5cf Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 11 May 2023 13:53:04 +0200 Subject: [PATCH 0980/1447] ClangFormatBaseIndenter: Fix build Bring back the utf16LineColumn function locally. Amends e9cd4dd4392a7f82f41d9ca1af7e030b532d756d Change-Id: Ic10ea0355b75498217e7bc057a3666a276a18a11 Reviewed-by: hjk --- .../clangformat/clangformatbaseindenter.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 062dfe5550a..d65053a9669 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -350,6 +350,17 @@ bool isInsideDummyTextInLine(const QString &originalLine, const QString &modifie || !modifiedLine.startsWith(originalLine)); } +static Utils::Text::Position utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) +{ + Utils::Text::Position position; + position.line = static_cast(std::count(utf8Buffer.begin(), + utf8Buffer.begin() + utf8Offset, '\n')) + 1; + const int startOfLineOffset = utf8Offset ? (utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1) + : 0; + position.column = QString::fromUtf8(utf8Buffer.mid(startOfLineOffset, + utf8Offset - startOfLineOffset)).length(); + return position; +} Utils::Text::Replacements utf16Replacements(const QTextDocument *doc, const QByteArray &utf8Buffer, const clang::tooling::Replacements &replacements) @@ -358,9 +369,8 @@ Utils::Text::Replacements utf16Replacements(const QTextDocument *doc, convertedReplacements.reserve(replacements.size()); for (const clang::tooling::Replacement &replacement : replacements) { - Utils::LineColumn lineColUtf16 = Utils::Text::utf16LineColumn(utf8Buffer, - static_cast( - replacement.getOffset())); + Utils::Text::Position lineColUtf16 = utf16LineColumn( + utf8Buffer, static_cast(replacement.getOffset())); if (!lineColUtf16.isValid()) continue; From 7bd3ee8123be30854ed5ef4dbb056c510a300106 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 11 May 2023 14:00:31 +0200 Subject: [PATCH 0981/1447] Utils: Add more FilePathChooser config options to StringAspect Will be used in the Beautifier plugin. Change-Id: I6e70f757a25afcdf1d3e3742357d71503f210b2a Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 27 +++++++++++++++++++++++++++ src/libs/utils/aspects.h | 3 +++ 2 files changed, 30 insertions(+) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 675f6b116f1..b73f1481a59 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -639,6 +639,9 @@ public: Qt::TextElideMode m_elideMode = Qt::ElideNone; QString m_placeHolderText; + QString m_prompDialogFilter; + QString m_prompDialogTitle; + QStringList m_commandVersionArguments; QString m_historyCompleterKey; PathChooser::Kind m_expectedKind = PathChooser::File; Environment m_environment; @@ -947,6 +950,27 @@ void StringAspect::setPlaceHolderText(const QString &placeHolderText) d->m_textEditDisplay->setPlaceholderText(placeHolderText); } +void StringAspect::setPromptDialogFilter(const QString &filter) +{ + d->m_prompDialogFilter = filter; + if (d->m_pathChooserDisplay) + d->m_pathChooserDisplay->setPromptDialogFilter(filter); +} + +void StringAspect::setPromptDialogTitle(const QString &title) +{ + d->m_prompDialogTitle = title; + if (d->m_pathChooserDisplay) + d->m_pathChooserDisplay->setPromptDialogTitle(title); +} + +void StringAspect::setCommandVersionArguments(const QStringList &arguments) +{ + d->m_commandVersionArguments = arguments; + if (d->m_pathChooserDisplay) + d->m_pathChooserDisplay->setCommandVersionArguments(arguments); +} + /*! Sets \a elideMode as label elide mode. */ @@ -1089,6 +1113,9 @@ void StringAspect::addToLayout(LayoutItem &parent) d->m_pathChooserDisplay->setEnvironment(d->m_environment); d->m_pathChooserDisplay->setBaseDirectory(d->m_baseFileName); d->m_pathChooserDisplay->setOpenTerminalHandler(d->m_openTerminal); + d->m_pathChooserDisplay->setPromptDialogFilter(d->m_prompDialogFilter); + d->m_pathChooserDisplay->setPromptDialogTitle(d->m_prompDialogTitle); + d->m_pathChooserDisplay->setCommandVersionArguments(d->m_commandVersionArguments); if (defaultValue() == value()) d->m_pathChooserDisplay->setDefaultValue(defaultValue()); else diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 8b75bf911db..c511595e1ba 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -382,6 +382,9 @@ public: void setDisplayFilter(const std::function &displayFilter); void setPlaceHolderText(const QString &placeHolderText); + void setPromptDialogFilter(const QString &filter); + void setPromptDialogTitle(const QString &title); + void setCommandVersionArguments(const QStringList &arguments); void setHistoryCompleter(const QString &historyCompleterKey); void setExpectedKind(const PathChooser::Kind expectedKind); void setEnvironment(const Environment &env); From 74c311d68ff2596f2b07e51465741cf6d076a860 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 11 May 2023 14:16:57 +0200 Subject: [PATCH 0982/1447] ClangFormat: column of Position is 0-based Amends 5b0c3258bb56fb4de71c28340857761641fe9aa7 Amends e9cd4dd4392a7f82f41d9ca1af7e030b532d756d Amends a631a0441e011d0c28f7a5dbf7810c826252f5cf Change-Id: I9dd542dfdf7936bdaf1fb05152228aff3895bccf Reviewed-by: Christian Kandeler --- src/plugins/clangformat/clangformatbaseindenter.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index d65053a9669..64d7d4a4905 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -378,14 +378,13 @@ Utils::Text::Replacements utf16Replacements(const QTextDocument *doc, const QString bufferLineText = Utils::Text::utf16LineTextInUtf8Buffer(utf8Buffer, static_cast(replacement.getOffset())); - if (isInsideDummyTextInLine(lineText, bufferLineText, lineColUtf16.column)) + if (isInsideDummyTextInLine(lineText, bufferLineText, lineColUtf16.column + 1)) continue; - lineColUtf16.column = std::min(lineColUtf16.column, int(lineText.length()) + 1); - + lineColUtf16.column = std::min(lineColUtf16.column, int(lineText.length())); const int utf16Offset = Utils::Text::positionInText(doc, lineColUtf16.line, - lineColUtf16.column); + lineColUtf16.column + 1); const int utf16Length = QString::fromUtf8( utf8Buffer.mid(static_cast(replacement.getOffset()), static_cast(replacement.getLength()))) From 9b00ab8d7950ad8abd6759d572a4d9b90f66a316 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 11 May 2023 15:21:21 +0200 Subject: [PATCH 0983/1447] Qt Quick Application Wizard: Fix a property assignment The option "BuildSystem" does not exist, anymore. Amends: fe45294357c91385a09bb3bc914e7047081218b1 Change-Id: I76aa3fe05cf1a4a4f74944d67d3fa7c6c273af6a Reviewed-by: Alessandro Portale --- .../templates/wizards/projects/qtquickapplication/wizard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index aef71de2fe2..8b4165fa35c 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -19,7 +19,7 @@ { "key": "TargetName", "value": "%{JS: 'app' + value('ProjectName') }" }, { "key": "HasQSPSetup", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.2' }"}, { "key": "HasFailureSignal", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.3' }"}, - { "key": "UsesAutoResourcePrefix", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.4' && value('BuildSystem') === 'cmake' }"}, + { "key": "UsesAutoResourcePrefix", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.4' }"}, { "key": "HasLoadFromModule", "value": "%{JS: value('MinimumSupportedQtVersion') > '6.4' && value('UsesAutoResourcePrefix') }"}, { "key": "QdsWizardPath", "value": "%{IDE:ResourcePath}/qmldesigner/studio_templates/projects" }, { "key": "NoQdsProjectStyle", "value": "%{JS: !%{QdsProjectStyle} }" }, From 0449a3fdab2400174d1e19fb9b5e87e822a16487 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 9 May 2023 17:46:02 +0200 Subject: [PATCH 0984/1447] Autotest: Use new PagedSettings Change-Id: If93494ef9e3f10e1b7bbc95a3930d3b36e83f8fc Reviewed-by: Christian Stenger --- .../autotest/boost/boosttestframework.h | 9 +-- .../autotest/boost/boosttestsettings.cpp | 49 +++++------- .../autotest/boost/boosttestsettings.h | 19 +---- src/plugins/autotest/catch/catchframework.h | 9 +-- .../autotest/catch/catchtestsettings.cpp | 57 ++++++------- .../autotest/catch/catchtestsettings.h | 18 +---- src/plugins/autotest/ctest/ctestsettings.cpp | 79 +++++++++---------- src/plugins/autotest/ctest/ctestsettings.h | 18 +---- src/plugins/autotest/ctest/ctesttool.h | 9 +-- src/plugins/autotest/gtest/gtestframework.h | 9 +-- src/plugins/autotest/gtest/gtestsettings.cpp | 56 ++++++------- src/plugins/autotest/gtest/gtestsettings.h | 18 +---- src/plugins/autotest/qtest/qttestframework.h | 9 +-- src/plugins/autotest/qtest/qttestsettings.cpp | 62 ++++++--------- src/plugins/autotest/qtest/qttestsettings.h | 18 +---- 15 files changed, 165 insertions(+), 274 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestframework.h b/src/plugins/autotest/boost/boosttestframework.h index e8f4c98ed82..da015fbd6f3 100644 --- a/src/plugins/autotest/boost/boosttestframework.h +++ b/src/plugins/autotest/boost/boosttestframework.h @@ -7,8 +7,7 @@ #include "boosttestsettings.h" -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { class BoostTestFramework : public ITestFramework { @@ -23,9 +22,7 @@ private: ITestParser *createTestParser() override; ITestTreeItem *createRootNode() override; - BoostTestSettings m_settings; - BoostTestSettingsPage m_settingsPage{&m_settings, settingsId()}; + BoostTestSettings m_settings{settingsId()}; }; -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp index c995cab9b6c..182c0dac0e3 100644 --- a/src/plugins/autotest/boost/boosttestsettings.cpp +++ b/src/plugins/autotest/boost/boosttestsettings.cpp @@ -10,13 +10,29 @@ #include +using namespace Layouting; using namespace Utils; -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { -BoostTestSettings::BoostTestSettings() +BoostTestSettings::BoostTestSettings(Id settingsId) { + setId(settingsId); + setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); + setDisplayName(Tr::tr(BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); + setSettings(this); + + setLayouter([this](QWidget *widget) { + Row { Form { + logLevel, br, + reportLevel, br, + randomize, Row { seed }, br, + systemErrors, br, + fpExceptions, br, + memLeaks, + }, st}.attachTo(widget); + }); + setSettingsGroups("Autotest", "BoostTest"); setAutoApply(false); @@ -81,30 +97,6 @@ BoostTestSettings::BoostTestSettings() memLeaks.setToolTip(Tr::tr("Enable memory leak detection.")); } -BoostTestSettingsPage::BoostTestSettingsPage(BoostTestSettings *settings, Id settingsId) -{ - setId(settingsId); - setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); - setDisplayName(Tr::tr(BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - BoostTestSettings &s = *settings; - using namespace Layouting; - - Grid grid { - s.logLevel, br, - s.reportLevel, br, - s.randomize, Row { s.seed }, br, - s.systemErrors, br, - s.fpExceptions, br, - s.memLeaks, - }; - - Column { Row { Column { grid, st }, st } }.attachTo(widget); - }); -} - QString BoostTestSettings::logLevelToOption(const LogLevel logLevel) { switch (logLevel) { @@ -134,5 +126,4 @@ QString BoostTestSettings::reportLevelToOption(const ReportLevel reportLevel) return {}; } -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/boost/boosttestsettings.h b/src/plugins/autotest/boost/boosttestsettings.h index 60a3df5042f..f2a906cd79e 100644 --- a/src/plugins/autotest/boost/boosttestsettings.h +++ b/src/plugins/autotest/boost/boosttestsettings.h @@ -5,10 +5,7 @@ #include -#include - -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { enum class LogLevel { @@ -33,10 +30,10 @@ enum class ReportLevel No }; -class BoostTestSettings : public Utils::AspectContainer +class BoostTestSettings : public Core::PagedSettings { public: - BoostTestSettings(); + explicit BoostTestSettings(Utils::Id settingsId); static QString logLevelToOption(const LogLevel logLevel); static QString reportLevelToOption(const ReportLevel reportLevel); @@ -50,15 +47,7 @@ public: Utils::BoolAspect memLeaks; }; - -class BoostTestSettingsPage final : public Core::IOptionsPage -{ -public: - BoostTestSettingsPage(BoostTestSettings *settings, Utils::Id settingsId); -}; - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal Q_DECLARE_METATYPE(Autotest::Internal::LogLevel) Q_DECLARE_METATYPE(Autotest::Internal::ReportLevel) diff --git a/src/plugins/autotest/catch/catchframework.h b/src/plugins/autotest/catch/catchframework.h index 0fe7138ce90..6bd20b44f6a 100644 --- a/src/plugins/autotest/catch/catchframework.h +++ b/src/plugins/autotest/catch/catchframework.h @@ -7,8 +7,7 @@ #include "catchtestsettings.h" -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { class CatchFramework : public ITestFramework { @@ -25,9 +24,7 @@ protected: private: ITestSettings * testSettings() override { return &m_settings; } - CatchTestSettings m_settings; - CatchTestSettingsPage m_settingsPage{&m_settings, settingsId()}; + CatchTestSettings m_settings{settingsId()}; }; -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp index e3e2c000db4..583fc95dc60 100644 --- a/src/plugins/autotest/catch/catchtestsettings.cpp +++ b/src/plugins/autotest/catch/catchtestsettings.cpp @@ -10,13 +10,33 @@ #include +using namespace Layouting; using namespace Utils; -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { -CatchTestSettings::CatchTestSettings() +CatchTestSettings::CatchTestSettings(Id settingsId) { + setId(settingsId); + setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); + setDisplayName(Tr::tr("Catch Test")); + setSettings(this); + + setLayouter([this](QWidget *widget) { + Column { Row { Grid { + showSuccess, br, + breakOnFailure, br, + noThrow, br, + visibleWhitespace, br, + abortAfterChecked, abortAfter, br, + samplesChecked, benchmarkSamples, br, + resamplesChecked, benchmarkResamples, br, + confidenceIntervalChecked, confidenceInterval, br, + warmupChecked, benchmarkWarmupTime, br, + noAnalysis + }, st }, st }.attachTo(widget); + }); + setSettingsGroups("Autotest", "Catch2"); setAutoApply(false); @@ -108,33 +128,4 @@ CatchTestSettings::CatchTestSettings() warnOnEmpty.setToolTip(Tr::tr("Warns if a test section does not check any assertion.")); } -CatchTestSettingsPage::CatchTestSettingsPage(CatchTestSettings *settings, Id settingsId) -{ - setId(settingsId); - setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); - setDisplayName(Tr::tr("Catch Test")); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - CatchTestSettings &s = *settings; - using namespace Layouting; - - Grid col { - s.showSuccess, br, - s.breakOnFailure, br, - s.noThrow, br, - s.visibleWhitespace, br, - s.abortAfterChecked, s.abortAfter, br, - s.samplesChecked, s.benchmarkSamples, br, - s.resamplesChecked, s.benchmarkResamples, br, - s.confidenceIntervalChecked, s.confidenceInterval, br, - s.warmupChecked, s.benchmarkWarmupTime, br, - s.noAnalysis - }; - - Column { Row { col, st }, st }.attachTo(widget); - }); -} - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/catch/catchtestsettings.h b/src/plugins/autotest/catch/catchtestsettings.h index 9e1b639fd31..07ac5580814 100644 --- a/src/plugins/autotest/catch/catchtestsettings.h +++ b/src/plugins/autotest/catch/catchtestsettings.h @@ -5,15 +5,12 @@ #include -#include +namespace Autotest::Internal { -namespace Autotest { -namespace Internal { - -class CatchTestSettings : public Utils::AspectContainer +class CatchTestSettings : public Core::PagedSettings { public: - CatchTestSettings(); + explicit CatchTestSettings(Utils::Id settingsId); Utils::IntegerAspect abortAfter; Utils::IntegerAspect benchmarkSamples; @@ -33,11 +30,4 @@ public: Utils::BoolAspect warnOnEmpty; }; -class CatchTestSettingsPage : public Core::IOptionsPage -{ -public: - CatchTestSettingsPage(CatchTestSettings *settings, Utils::Id settingsId); -}; - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index 3fa9fadadee..07e6a3bf22b 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -8,14 +8,44 @@ #include -namespace Autotest { -namespace Internal { +using namespace Layouting; +using namespace Utils; -CTestSettings::CTestSettings() +namespace Autotest::Internal { + +CTestSettings::CTestSettings(Id settingsId) { setSettingsGroups("Autotest", "CTest"); setAutoApply(false); + setId(settingsId); + setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); + setDisplayName(Tr::tr("CTest")); + + setSettings(this); + + setLayouter([this](QWidget *w) { + Column { Row { Form { + outputOnFail, br, + scheduleRandom, br, + stopOnFailure, br, + outputMode, br, + Group { + title(Tr::tr("Repeat tests")), + repeat.groupChecker(), + Row { repetitionMode, repetitionCount}, + }, br, + Group { + title(Tr::tr("Run in parallel")), + parallel.groupChecker(), + Column { + Row { jobs }, br, + Row { testLoad, threshold} + } + } + }, st }, st }.attachTo(w); + }); + registerAspect(&outputOnFail); outputOnFail.setSettingsKey("OutputOnFail"); outputOnFail.setLabelText(Tr::tr("Output on failure")); @@ -24,7 +54,7 @@ CTestSettings::CTestSettings() registerAspect(&outputMode); outputMode.setSettingsKey("OutputMode"); outputMode.setLabelText(Tr::tr("Output mode")); - outputMode.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); + outputMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); outputMode.addOption({Tr::tr("Default"), {}, 0}); outputMode.addOption({Tr::tr("Verbose"), {}, 1}); outputMode.addOption({Tr::tr("Very Verbose"), {}, 2}); @@ -32,7 +62,7 @@ CTestSettings::CTestSettings() registerAspect(&repetitionMode); repetitionMode.setSettingsKey("RepetitionMode"); repetitionMode.setLabelText(Tr::tr("Repetition mode")); - repetitionMode.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); + repetitionMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); repetitionMode.addOption({Tr::tr("Until Fail"), {}, 0}); repetitionMode.addOption({Tr::tr("Until Pass"), {}, 1}); repetitionMode.addOption({Tr::tr("After Timeout"), {}, 2}); @@ -115,41 +145,4 @@ QStringList CTestSettings::activeSettingsAsOptions() const return options; } -CTestSettingsPage::CTestSettingsPage(CTestSettings *settings, Utils::Id settingsId) -{ - setId(settingsId); - setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); - setDisplayName(Tr::tr("CTest")); - - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - CTestSettings &s = *settings; - using namespace Layouting; - - Form form { - Row {s.outputOnFail}, br, - Row {s.scheduleRandom}, br, - Row {s.stopOnFailure}, br, - Row {s.outputMode}, br, - Group { - title(Tr::tr("Repeat tests")), - s.repeat.groupChecker(), - Row {s.repetitionMode, s.repetitionCount}, - }, br, - Group { - title(Tr::tr("Run in parallel")), - s.parallel.groupChecker(), - Column { - Row {s.jobs}, br, - Row {s.testLoad, s.threshold} - } - } - }; - - Column { Row { Column { form , st }, st } }.attachTo(widget); - }); -} - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/ctest/ctestsettings.h b/src/plugins/autotest/ctest/ctestsettings.h index f9e87f5a8e8..a4e9b19605a 100644 --- a/src/plugins/autotest/ctest/ctestsettings.h +++ b/src/plugins/autotest/ctest/ctestsettings.h @@ -5,15 +5,12 @@ #include -#include +namespace Autotest::Internal { -namespace Autotest { -namespace Internal { - -class CTestSettings : public Utils::AspectContainer +class CTestSettings : public Core::PagedSettings { public: - CTestSettings(); + explicit CTestSettings(Utils::Id settingsId); QStringList activeSettingsAsOptions() const; @@ -31,12 +28,5 @@ public: Utils::IntegerAspect threshold; }; -class CTestSettingsPage final : public Core::IOptionsPage -{ -public: - CTestSettingsPage(CTestSettings *settings, Utils::Id settingsId); -}; - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/ctest/ctesttool.h b/src/plugins/autotest/ctest/ctesttool.h index ad510ac9471..e7a7f74218a 100644 --- a/src/plugins/autotest/ctest/ctesttool.h +++ b/src/plugins/autotest/ctest/ctesttool.h @@ -6,8 +6,7 @@ #include "../itestframework.h" #include "ctestsettings.h" -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { class CTestTool final : public Autotest::ITestTool { @@ -26,9 +25,7 @@ protected: private: ITestSettings *testSettings() override { return &m_settings; } - CTestSettings m_settings; - CTestSettingsPage m_settingsPage{&m_settings, settingsId()}; + CTestSettings m_settings{settingsId()}; }; -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/gtest/gtestframework.h b/src/plugins/autotest/gtest/gtestframework.h index c9e8cbddc07..03c8a4fc0d9 100644 --- a/src/plugins/autotest/gtest/gtestframework.h +++ b/src/plugins/autotest/gtest/gtestframework.h @@ -7,8 +7,7 @@ #include "gtestconstants.h" #include "gtestsettings.h" -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { class GTestFramework : public ITestFramework { @@ -28,9 +27,7 @@ private: ITestParser *createTestParser() override; ITestTreeItem *createRootNode() override; - GTestSettings m_settings; - GTestSettingsPage m_settingsPage{&m_settings, settingsId()}; + GTestSettings m_settings{settingsId()}; }; -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp index 5a7a72ab46b..9af32fb8d4d 100644 --- a/src/plugins/autotest/gtest/gtestsettings.cpp +++ b/src/plugins/autotest/gtest/gtestsettings.cpp @@ -11,16 +11,36 @@ #include +using namespace Layouting; using namespace Utils; -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { -GTestSettings::GTestSettings() +GTestSettings::GTestSettings(Utils::Id settingsId) { setSettingsGroups("Autotest", "GTest"); setAutoApply(false); + setId(settingsId); + setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); + setDisplayName(Tr::tr(GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); + setSettings(this); + + setLayouter([this](QWidget *widget) { + Column { Row { Column { + Grid { + runDisabled, br, + breakOnFailure, br, + repeat, iterations, br, + shuffle, seed + }, + Form { + groupMode, + gtestFilter + } + }, st }, st }.attachTo(widget); + }); + registerAspect(&iterations); iterations.setSettingsKey("Iterations"); iterations.setDefaultValue(1); @@ -111,32 +131,4 @@ GTestSettings::GTestSettings() }); } -GTestSettingsPage::GTestSettingsPage(GTestSettings *settings, Id settingsId) -{ - setId(settingsId); - setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); - setDisplayName(Tr::tr(GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - GTestSettings &s = *settings; - using namespace Layouting; - - Grid grid { - s.runDisabled, br, - s.breakOnFailure, br, - s.repeat, s.iterations, br, - s.shuffle, s.seed - }; - - Form form { - s.groupMode, - s.gtestFilter - }; - - Column { Row { Column { grid, form, st }, st } }.attachTo(widget); - }); -} - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/gtest/gtestsettings.h b/src/plugins/autotest/gtest/gtestsettings.h index 11fb144e227..fe928376075 100644 --- a/src/plugins/autotest/gtest/gtestsettings.h +++ b/src/plugins/autotest/gtest/gtestsettings.h @@ -5,15 +5,12 @@ #include -#include +namespace Autotest::Internal { -namespace Autotest { -namespace Internal { - -class GTestSettings : public Utils::AspectContainer +class GTestSettings : public Core::PagedSettings { public: - GTestSettings(); + explicit GTestSettings(Utils::Id settingsId); Utils::IntegerAspect iterations; Utils::IntegerAspect seed; @@ -26,11 +23,4 @@ public: Utils::StringAspect gtestFilter; }; -class GTestSettingsPage final : public Core::IOptionsPage -{ -public: - GTestSettingsPage(GTestSettings *settings, Utils::Id settingsId); -}; - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/qtest/qttestframework.h b/src/plugins/autotest/qtest/qttestframework.h index 4fa765ab192..c90bd3c9d8c 100644 --- a/src/plugins/autotest/qtest/qttestframework.h +++ b/src/plugins/autotest/qtest/qttestframework.h @@ -7,8 +7,7 @@ #include "qttestsettings.h" -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { class QtTestFramework : public ITestFramework { @@ -24,9 +23,7 @@ private: ITestTreeItem *createRootNode() override; ITestSettings *testSettings() override { return &m_settings; } - QtTestSettings m_settings; - QtTestSettingsPage m_settingsPage{&m_settings, settingsId()}; + QtTestSettings m_settings{settingsId()}; }; -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/qtest/qttestsettings.cpp b/src/plugins/autotest/qtest/qttestsettings.cpp index 4be93d99379..06f368de379 100644 --- a/src/plugins/autotest/qtest/qttestsettings.cpp +++ b/src/plugins/autotest/qtest/qttestsettings.cpp @@ -10,15 +10,37 @@ #include #include +using namespace Layouting; using namespace Utils; -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { -QtTestSettings::QtTestSettings() +QtTestSettings::QtTestSettings(Id settingsId) { setSettingsGroups("Autotest", "QtTest"); setAutoApply(false); + setId(settingsId); + setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); + setDisplayName(Tr::tr(QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); + setSettings(this); + + setLayouter([this](QWidget *widget) { + Column { Row { Column { + noCrashHandler, + useXMLOutput, + verboseBench, + logSignalsSlots, + Row { + limitWarnings, maxWarnings + }, + Group { + title(Tr::tr("Benchmark Metrics")), + Column { metrics } + }, + br, + quickCheckForDerivedTests, + }, st }, st }.attachTo(widget); + }); registerAspect(&metrics); metrics.setSettingsKey("Metrics"); @@ -99,36 +121,4 @@ QString QtTestSettings::metricsTypeToOption(const MetricsType type) return {}; } -QtTestSettingsPage::QtTestSettingsPage(QtTestSettings *settings, Id settingsId) -{ - setId(settingsId); - setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); - setDisplayName(Tr::tr(QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - QtTestSettings &s = *settings; - using namespace Layouting; - - Column col { - s.noCrashHandler, - s.useXMLOutput, - s.verboseBench, - s.logSignalsSlots, - Row { - s.limitWarnings, s.maxWarnings - }, - Group { - title(Tr::tr("Benchmark Metrics")), - Column { s.metrics } - }, - br, - s.quickCheckForDerivedTests, - }; - - Column { Row { col, st }, st }.attachTo(widget); - }); -} - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal diff --git a/src/plugins/autotest/qtest/qttestsettings.h b/src/plugins/autotest/qtest/qttestsettings.h index 4bbec4332df..eafd464d7ba 100644 --- a/src/plugins/autotest/qtest/qttestsettings.h +++ b/src/plugins/autotest/qtest/qttestsettings.h @@ -5,10 +5,7 @@ #include -#include - -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { enum MetricsType { @@ -19,10 +16,10 @@ enum MetricsType Perf }; -class QtTestSettings : public Utils::AspectContainer +class QtTestSettings : public Core::PagedSettings { public: - QtTestSettings(); + explicit QtTestSettings(Utils::Id settingsId); static QString metricsTypeToOption(const MetricsType type); @@ -36,11 +33,4 @@ public: Utils::BoolAspect quickCheckForDerivedTests; }; -class QtTestSettingsPage final : public Core::IOptionsPage -{ -public: - QtTestSettingsPage(QtTestSettings *settings, Utils::Id settingsId); -}; - -} // namespace Internal -} // namespace Autotest +} // Autotest::Internal From 56146960029ee843812a5386908d0ea3aaf8ad93 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 17:04:22 +0200 Subject: [PATCH 0985/1447] Core: Make PagedSettings autoapply by default in the base Instead of relying (and forgetting...) it in all derived clases. Change-Id: I5d1dea0ace420d464c39c192278ae6e5db01de90 Reviewed-by: Alessandro Portale --- src/plugins/autotest/boost/boosttestsettings.cpp | 5 +---- src/plugins/autotest/catch/catchtestsettings.cpp | 5 +---- src/plugins/autotest/ctest/ctestsettings.cpp | 4 ---- src/plugins/autotest/gtest/gtestsettings.cpp | 5 +---- src/plugins/autotest/qtest/qttestsettings.cpp | 2 -- src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp | 1 - src/plugins/coreplugin/dialogs/ioptionspage.cpp | 6 +++++- src/plugins/docker/dockersettings.cpp | 3 --- src/plugins/nim/settings/nimsettings.cpp | 3 --- 9 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp index 182c0dac0e3..fc2ce851e62 100644 --- a/src/plugins/autotest/boost/boosttestsettings.cpp +++ b/src/plugins/autotest/boost/boosttestsettings.cpp @@ -20,7 +20,7 @@ BoostTestSettings::BoostTestSettings(Id settingsId) setId(settingsId); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr(BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setSettings(this); + setSettingsGroups("Autotest", "BoostTest"); setLayouter([this](QWidget *widget) { Row { Form { @@ -33,9 +33,6 @@ BoostTestSettings::BoostTestSettings(Id settingsId) }, st}.attachTo(widget); }); - setSettingsGroups("Autotest", "BoostTest"); - setAutoApply(false); - registerAspect(&logLevel); logLevel.setSettingsKey("LogLevel"); logLevel.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp index 583fc95dc60..12b5c1094ff 100644 --- a/src/plugins/autotest/catch/catchtestsettings.cpp +++ b/src/plugins/autotest/catch/catchtestsettings.cpp @@ -20,7 +20,7 @@ CatchTestSettings::CatchTestSettings(Id settingsId) setId(settingsId); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr("Catch Test")); - setSettings(this); + setSettingsGroups("Autotest", "Catch2"); setLayouter([this](QWidget *widget) { Column { Row { Grid { @@ -37,9 +37,6 @@ CatchTestSettings::CatchTestSettings(Id settingsId) }, st }, st }.attachTo(widget); }); - setSettingsGroups("Autotest", "Catch2"); - setAutoApply(false); - registerAspect(&abortAfter); abortAfter.setSettingsKey("AbortAfter"); abortAfter.setRange(1, 9999); diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index 07e6a3bf22b..b8485530e15 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -16,14 +16,10 @@ namespace Autotest::Internal { CTestSettings::CTestSettings(Id settingsId) { setSettingsGroups("Autotest", "CTest"); - setAutoApply(false); - setId(settingsId); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr("CTest")); - setSettings(this); - setLayouter([this](QWidget *w) { Column { Row { Form { outputOnFail, br, diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp index 9af32fb8d4d..3979f28c754 100644 --- a/src/plugins/autotest/gtest/gtestsettings.cpp +++ b/src/plugins/autotest/gtest/gtestsettings.cpp @@ -16,15 +16,12 @@ using namespace Utils; namespace Autotest::Internal { -GTestSettings::GTestSettings(Utils::Id settingsId) +GTestSettings::GTestSettings(Id settingsId) { setSettingsGroups("Autotest", "GTest"); - setAutoApply(false); - setId(settingsId); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr(GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setSettings(this); setLayouter([this](QWidget *widget) { Column { Row { Column { diff --git a/src/plugins/autotest/qtest/qttestsettings.cpp b/src/plugins/autotest/qtest/qttestsettings.cpp index 06f368de379..9832a0ed4a0 100644 --- a/src/plugins/autotest/qtest/qttestsettings.cpp +++ b/src/plugins/autotest/qtest/qttestsettings.cpp @@ -18,11 +18,9 @@ namespace Autotest::Internal { QtTestSettings::QtTestSettings(Id settingsId) { setSettingsGroups("Autotest", "QtTest"); - setAutoApply(false); setId(settingsId); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr(QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setSettings(this); setLayouter([this](QWidget *widget) { Column { Row { Column { diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index 377916490db..a4f08c60b15 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -31,7 +31,6 @@ CMakeSpecificSettings::CMakeSpecificSettings() setDisplayCategory("CMake"); setCategory(Constants::Settings::CATEGORY); setCategoryIconPath(Constants::Icons::SETTINGS_CATEGORY); - setSettings(this); setLayouter([this](QWidget *widget) { using namespace Layouting; diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index 0a8eb257469..070cc6159b4 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -303,6 +303,10 @@ QIcon IOptionsPageProvider::categoryIcon() const // PagedSettings -PagedSettings::PagedSettings() = default; +PagedSettings::PagedSettings() +{ + setSettings(this); + setAutoApply(false); +} } // Core diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp index 2a60dacb7da..4adb98af9cc 100644 --- a/src/plugins/docker/dockersettings.cpp +++ b/src/plugins/docker/dockersettings.cpp @@ -21,12 +21,9 @@ namespace Docker::Internal { DockerSettings::DockerSettings() { setSettingsGroup(Constants::DOCKER); - setAutoApply(false); - setId(Docker::Constants::DOCKER_SETTINGS_ID); setDisplayName(Tr::tr("Docker")); setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); - setSettings(this); setLayouter([this](QWidget *widget) { using namespace Layouting; diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp index 036045fada4..d99ae2974b8 100644 --- a/src/plugins/nim/settings/nimsettings.cpp +++ b/src/plugins/nim/settings/nimsettings.cpp @@ -26,15 +26,12 @@ static SimpleCodeStylePreferences *m_globalCodeStyle = nullptr; NimSettings::NimSettings() { - setAutoApply(false); setSettingsGroups("Nim", "NimSuggest"); - setId(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_ID); setDisplayName(Tr::tr("Tools")); setCategory(Nim::Constants::C_NIMTOOLSSETTINGSPAGE_CATEGORY); setDisplayCategory(Tr::tr("Nim")); setCategoryIconPath(":/nim/images/settingscategory_nim.png"); - setSettings(this); setLayouter([this](QWidget *widget) { using namespace Layouting; From 2d1b8dbc2987e6db76c78d8cb449b47e39dd1597 Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Tue, 18 Apr 2023 16:46:04 +0200 Subject: [PATCH 0986/1447] Scxmleditor: Add showing onEntry and on Exit events This commit enhances the SCXML Editor by adding a new feature that enables the display of onEntry and onExit events in the state item. This feature provides developers with a more comprehensive view of the state machine's behavior, allowing them to better understand the transitions that occur when entering or exiting a particular state. Fixes: QTCREATORBUG-17378 Change-Id: Iaf84af209d9acf13bd4183f7da9acbcd6c1c8214 Reviewed-by: Alessandro Portale --- src/plugins/scxmleditor/CMakeLists.txt | 1 + .../scxmleditor/plugin_interface/baseitem.cpp | 3 +- .../scxmleditor/plugin_interface/baseitem.h | 1 + .../plugin_interface/eventitem.cpp | 108 ++++++++++++++++++ .../scxmleditor/plugin_interface/eventitem.h | 41 +++++++ .../plugin_interface/graphicsscene.cpp | 15 ++- .../plugin_interface/stateitem.cpp | 66 +++++++++-- .../scxmleditor/plugin_interface/stateitem.h | 8 ++ 8 files changed, 228 insertions(+), 15 deletions(-) create mode 100644 src/plugins/scxmleditor/plugin_interface/eventitem.cpp create mode 100644 src/plugins/scxmleditor/plugin_interface/eventitem.h diff --git a/src/plugins/scxmleditor/CMakeLists.txt b/src/plugins/scxmleditor/CMakeLists.txt index fef49a90827..358c407233c 100644 --- a/src/plugins/scxmleditor/CMakeLists.txt +++ b/src/plugins/scxmleditor/CMakeLists.txt @@ -42,6 +42,7 @@ add_qtc_plugin(ScxmlEditor plugin_interface/baseitem.cpp plugin_interface/baseitem.h plugin_interface/connectableitem.cpp plugin_interface/connectableitem.h plugin_interface/cornergrabberitem.cpp plugin_interface/cornergrabberitem.h + plugin_interface/eventitem.cpp plugin_interface/eventitem.h plugin_interface/finalstateitem.cpp plugin_interface/finalstateitem.h plugin_interface/genericscxmlplugin.cpp plugin_interface/genericscxmlplugin.h plugin_interface/graphicsitemprovider.h diff --git a/src/plugins/scxmleditor/plugin_interface/baseitem.cpp b/src/plugins/scxmleditor/plugin_interface/baseitem.cpp index 861094321aa..7d87a68f91c 100644 --- a/src/plugins/scxmleditor/plugin_interface/baseitem.cpp +++ b/src/plugins/scxmleditor/plugin_interface/baseitem.cpp @@ -41,7 +41,8 @@ BaseItem::~BaseItem() void BaseItem::checkParentBoundingRect() { BaseItem *parentBaseItem = this->parentBaseItem(); - if (parentBaseItem && type() >= InitialStateType && !parentBaseItem->blockUpdates()) { + if ((parentBaseItem && type() >= InitialStateType && !parentBaseItem->blockUpdates()) + || (parentBaseItem && type() == StateWarningType)) { auto parentStateItem = qgraphicsitem_cast(parentBaseItem); if (parentStateItem && (parentStateItem->type() >= StateType)) parentStateItem->updateBoundingRect(); diff --git a/src/plugins/scxmleditor/plugin_interface/baseitem.h b/src/plugins/scxmleditor/plugin_interface/baseitem.h index 5c992c632b6..42f09ca3893 100644 --- a/src/plugins/scxmleditor/plugin_interface/baseitem.h +++ b/src/plugins/scxmleditor/plugin_interface/baseitem.h @@ -93,6 +93,7 @@ public: ScxmlUiFactory *uiFactory() const; virtual void updateUIProperties(); + virtual void addChild(ScxmlTag */*tag*/) {}; protected: virtual void updatePolygon(); diff --git a/src/plugins/scxmleditor/plugin_interface/eventitem.cpp b/src/plugins/scxmleditor/plugin_interface/eventitem.cpp new file mode 100644 index 00000000000..f61517f7cf6 --- /dev/null +++ b/src/plugins/scxmleditor/plugin_interface/eventitem.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "eventitem.h" + +#include +#include +#include +#include +#include + +namespace ScxmlEditor { + +namespace PluginInterface { + +EventItem::EventItem(const QPointF &pos, BaseItem *parent) + : BaseItem(parent) +{ + m_eventNameItem = new TextItem(this); + m_eventNameItem->setParentItem(this); + QFont serifFont("Times", 13, QFont::Normal); + m_eventNameItem->setFont(serifFont); + + QString color = editorInfo("fontColor"); + m_eventNameItem->setDefaultTextColor(color.isEmpty() ? QColor(Qt::black) : QColor(color)); + + setPos(pos); + m_eventNameItem->setTextInteractionFlags(Qt::NoTextInteraction); + setItemBoundingRect(m_eventNameItem->boundingRect()); +} + +void EventItem::updateAttributes() +{ + QString text = " " + tag()->tagName(); + if (tag()->attributeNames().size() > 0) { + for (int i = 0; i < tag()->attributeNames().size(); ++i) + if (tag()->attributeNames().at(i) == "event") { + if (tag()->attributeValues().size() > i) + text += " / " + tag()->attributeValues().at(i); + break; + } + } + m_eventNameItem->setText(text); + setItemBoundingRect(m_eventNameItem->boundingRect()); +} + +OnEntryExitItem::OnEntryExitItem(BaseItem *parent) + : BaseItem(parent) +{ + m_eventNameItem = new TextItem(this); + m_eventNameItem->setParentItem(this); + QFont serifFont("Times", 13, QFont::Normal); + m_eventNameItem->setFont(serifFont); + m_eventNameItem->setDefaultTextColor(Qt::black); + m_eventNameItem->setTextInteractionFlags(Qt::NoTextInteraction); +} + +void OnEntryExitItem::updateAttributes() +{ + QString text = tag()->tagName(); + + m_eventNameItem->setText(text); + setItemBoundingRect(childBoundingRect()); + checkParentBoundingRect(); +} + +void OnEntryExitItem::finalizeCreation() +{ + auto children = tag()->allChildren(); + auto pos = m_eventNameItem->boundingRect().bottomLeft(); + for (auto child : children) { + EventItem *item = new EventItem(pos, this); + item->setTag(child); + item->updateAttributes(); + pos = item->pos() + item->boundingRect().bottomLeft(); + } + + setItemBoundingRect(childBoundingRect()); +} + +void OnEntryExitItem::addChild(ScxmlTag *tag) +{ + auto pos = childBoundingRect().bottomLeft(); + EventItem *item = new EventItem(pos, this); + item->setTag(tag); + item->updateAttributes(); + + setItemBoundingRect(childBoundingRect()); + checkParentBoundingRect(); +} + +QRectF OnEntryExitItem::childBoundingRect() const +{ + QRectF r = m_eventNameItem->boundingRect(); + + const QList children = childItems(); + + for (const QGraphicsItem *child : children) { + QRectF br = child->boundingRect(); + QPointF p = child->pos() + br.topLeft(); + br.moveTopLeft(p); + r = r.united(br); + } + return r; +} + +} // namespace PluginInterface +} // namespace ScxmlEditor diff --git a/src/plugins/scxmleditor/plugin_interface/eventitem.h b/src/plugins/scxmleditor/plugin_interface/eventitem.h new file mode 100644 index 00000000000..cf8ff3a9e34 --- /dev/null +++ b/src/plugins/scxmleditor/plugin_interface/eventitem.h @@ -0,0 +1,41 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "baseitem.h" +#include "textitem.h" + +namespace ScxmlEditor::PluginInterface { + +class EventItem : public BaseItem +{ +public: + explicit EventItem(const QPointF &pos = QPointF(), BaseItem *parent = nullptr); + + void updateAttributes() override; + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {} + +private: + TextItem *m_eventNameItem; +}; + +class OnEntryExitItem : public BaseItem +{ +public: + explicit OnEntryExitItem(BaseItem *parent = nullptr); + + int type() const override { return StateWarningType; } + + void updateAttributes() override; + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {} + void finalizeCreation() override; + void addChild(ScxmlTag *tag) override; + + QRectF childBoundingRect() const; + +private: + TextItem *m_eventNameItem; +}; + +} // namespace ScxmlEditor::PluginInterface diff --git a/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp b/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp index fb0e8252db9..94bd8b41edb 100644 --- a/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp +++ b/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp @@ -467,8 +467,7 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag, break; } case ScxmlDocument::TagChangeParent: { - auto childItem = qobject_cast(findItem(tag)); - + auto childItem = findItem(tag); if (childItem) { QTC_ASSERT(tag, break); BaseItem *newParentItem = findItem(tag->parentTag()); @@ -485,8 +484,11 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag, childItem->setParentItem(newParentItem); childItem->updateUIProperties(); - childItem->updateTransitions(true); - childItem->updateTransitionAttributes(true); + if (auto childConItem = qobject_cast(findItem(tag))) { + childConItem->updateTransitions(true); + childConItem->updateTransitionAttributes(true); + } + childItem->checkWarnings(); childItem->checkInitial(); if (newParentItem) { @@ -495,6 +497,8 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag, newParentItem->checkWarnings(); newParentItem->checkOverlapping(); newParentItem->updateUIProperties(); + if (auto newConItem = qobject_cast(newParentItem)) + newConItem->updateBoundingRect(); } if (oldParentItem) @@ -549,6 +553,9 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag, } if (parentItem) { + if (childItem == nullptr) + parentItem->addChild(childTag); + parentItem->updateAttributes(); parentItem->updateUIProperties(); parentItem->checkInitial(); diff --git a/src/plugins/scxmleditor/plugin_interface/stateitem.cpp b/src/plugins/scxmleditor/plugin_interface/stateitem.cpp index dd1015f9d40..e53bd8c894e 100644 --- a/src/plugins/scxmleditor/plugin_interface/stateitem.cpp +++ b/src/plugins/scxmleditor/plugin_interface/stateitem.cpp @@ -1,19 +1,18 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "finalstateitem.h" +#include "stateitem.h" + +#include "eventitem.h" #include "graphicsitemprovider.h" #include "graphicsscene.h" #include "idwarningitem.h" #include "imageprovider.h" -#include "initialstateitem.h" -#include "parallelitem.h" #include "sceneutils.h" #include "scxmleditorconstants.h" #include "scxmleditortr.h" #include "scxmltagutils.h" #include "scxmluifactory.h" -#include "stateitem.h" #include "statewarningitem.h" #include "textitem.h" #include "transitionitem.h" @@ -28,6 +27,7 @@ #include #include #include +#include using namespace ScxmlEditor::PluginInterface; @@ -171,6 +171,7 @@ void StateItem::updateBoundingRect() // Check if we need to increase parent boundingrect if (!r2.isNull()) { + positionOnExitItems(); QRectF r = boundingRect(); QRectF r3 = r.united(r2); @@ -244,7 +245,6 @@ void StateItem::transitionCountChanged() QRectF StateItem::childItemsBoundingRect() const { QRectF r; - QRectF rr = boundingRect(); QList children = childItems(); for (int i = 0; i < children.count(); ++i) { @@ -256,15 +256,26 @@ QRectF StateItem::childItemsBoundingRect() const } } + if (m_onEntryItem) { + QRectF br = m_onEntryItem->childBoundingRect(); + QPointF p = m_onEntryItem->pos() + br.topLeft(); + br.moveTopLeft(p); + r = r.united(br); + } + + if (m_onExitItem) { + QRectF br = m_onExitItem->childBoundingRect(); + QPointF p = m_onExitItem->pos() + br.topLeft(); + br.moveTopLeft(p); + r = r.united(br); + } + if (m_transitionRect.isValid()) { r.setLeft(r.left() - m_transitionRect.width()); r.setHeight(qMax(r.height(), m_transitionRect.height())); r.moveBottom(qMax(r.bottom(), m_transitionRect.bottom())); } - if (!r.isNull()) - r.adjust(-20, -(rr.height() * 0.06 + 40), 20, 20); - return r; } @@ -418,11 +429,18 @@ void StateItem::updatePolygon() << m_drawingRect.bottomLeft() << m_drawingRect.topLeft(); - m_titleRect = QRectF(m_drawingRect.left(), m_drawingRect.top(), m_drawingRect.width(), TEXT_ITEM_HEIGHT + m_drawingRect.height() * 0.06); + m_titleRect = QRectF(m_drawingRect.left(), + m_drawingRect.top(), + m_drawingRect.width(), + TEXT_ITEM_HEIGHT + m_drawingRect.height() * 0.06); QFont f = m_stateNameItem->font(); f.setPixelSize(m_titleRect.height() * 0.65); m_stateNameItem->setFont(f); + if (m_onEntryItem) + m_onEntryItem->setPos(m_titleRect.x(), m_titleRect.bottom()); + positionOnExitItems(); + updateTextPositions(); } @@ -517,13 +535,41 @@ void StateItem::init(ScxmlTag *tag, BaseItem *parentItem, bool initChildren, boo if (newItem) { newItem->init(child, this, initChildren, blockUpdates); newItem->finalizeCreation(); - } + } else + addChild(child); } } if (blockUpdates) setBlockUpdates(false); } + +void StateItem::addChild(ScxmlTag *child) +{ + if (child->tagName() == "onentry") { + OnEntryExitItem *item = new OnEntryExitItem(this); + m_onEntryItem = item; + item->setTag(child); + item->finalizeCreation(); + item->updateAttributes(); + m_onEntryItem->setPos(m_titleRect.x(), m_titleRect.bottom()); + } else if (child->tagName() == "onexit") { + OnEntryExitItem *item = new OnEntryExitItem(this); + m_onExitItem = item; + item->setTag(child); + item->finalizeCreation(); + item->updateAttributes(); + positionOnExitItems(); + } +} + +void StateItem::positionOnExitItems() +{ + int offset = m_onEntryItem ? m_onEntryItem->boundingRect().height() : 0; + if (m_onExitItem) + m_onExitItem->setPos(m_titleRect.x(), m_titleRect.bottom() + offset); +} + QString StateItem::itemId() const { return m_stateNameItem ? m_stateNameItem->toPlainText() : QString(); diff --git a/src/plugins/scxmleditor/plugin_interface/stateitem.h b/src/plugins/scxmleditor/plugin_interface/stateitem.h index 585992f040e..beaebe9ebd7 100644 --- a/src/plugins/scxmleditor/plugin_interface/stateitem.h +++ b/src/plugins/scxmleditor/plugin_interface/stateitem.h @@ -4,7 +4,9 @@ #pragma once #include "connectableitem.h" +#include "textitem.h" #include +#include QT_FORWARD_DECLARE_CLASS(QGraphicsSceneMouseEvent) @@ -16,6 +18,7 @@ class TransitionItem; class TextItem; class IdWarningItem; class StateWarningItem; +class OnEntryExitItem; /** * @brief The StateItem class represents the SCXML-State. @@ -49,6 +52,8 @@ public: QRectF childItemsBoundingRect() const; void connectToParent(BaseItem *parentItem) override; + void addChild(ScxmlTag *child) override; + protected: void updatePolygon() override; void transitionsChanged() override; @@ -69,6 +74,7 @@ private: void updateTextPositions(); void checkParentBoundingRect(); void checkWarningItems(); + void positionOnExitItems(); TextItem *m_stateNameItem; StateWarningItem *m_stateWarningItem = nullptr; @@ -76,6 +82,8 @@ private: QPen m_pen; bool m_initial = false; bool m_parallelState = false; + QPointer m_onEntryItem; + QPointer m_onExitItem; QImage m_backgroundImage; }; From 67acfd7076a52605d6b3b87ca362d0ff60a11277 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 14:13:38 +0200 Subject: [PATCH 0987/1447] ProjectExplorer: Use PagedSettings for BuildPropertiesSettingsPage More compact. Change-Id: Id35c3e8eeb54039a6769730fecc6b862fefc10e1 Reviewed-by: Alessandro Portale --- .../buildpropertiessettings.cpp | 45 ++++++++----------- .../projectexplorer/buildpropertiessettings.h | 13 +----- .../projectexplorer/projectexplorer.cpp | 1 - 3 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp index 36030fe60e9..be0a699707f 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.cpp +++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp @@ -24,6 +24,25 @@ BuildPropertiesSettings::BuildPropertiesSettings() { setAutoApply(false); + setId("AB.ProjectExplorer.BuildPropertiesSettingsPage"); + setDisplayName(Tr::tr("Default Build Properties")); + setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); + setSettings(this); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + + Column { + Form { + buildDirectoryTemplate, br, + separateDebugInfo, br, + qmlDebugging, br, + qtQuickCompiler + }, + st + }.attachTo(widget); + }); + registerAspect(&buildDirectoryTemplate); buildDirectoryTemplate.setDisplayStyle(StringAspect::LineEditDisplay); buildDirectoryTemplate.setSettingsKey("Directories/BuildDirectory.TemplateV2"); @@ -75,30 +94,4 @@ QString BuildPropertiesSettings::defaultBuildDirectoryTemplate() return QString(DEFAULT_BUILD_DIRECTORY_TEMPLATE); } -namespace Internal { - -BuildPropertiesSettingsPage::BuildPropertiesSettingsPage(BuildPropertiesSettings *settings) -{ - setId("AB.ProjectExplorer.BuildPropertiesSettingsPage"); - setDisplayName(Tr::tr("Default Build Properties")); - setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - BuildPropertiesSettings &s = *settings; - using namespace Layouting; - - Column { - Form { - s.buildDirectoryTemplate, br, - s.separateDebugInfo, br, - s.qmlDebugging, br, - s.qtQuickCompiler - }, - st - }.attachTo(widget); - }); -} - -} // Internal } // ProjectExplorer diff --git a/src/plugins/projectexplorer/buildpropertiessettings.h b/src/plugins/projectexplorer/buildpropertiessettings.h index 75ec957a4ea..5edf60d666b 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.h +++ b/src/plugins/projectexplorer/buildpropertiessettings.h @@ -7,11 +7,9 @@ #include -#include - namespace ProjectExplorer { -class PROJECTEXPLORER_EXPORT BuildPropertiesSettings : public Utils::AspectContainer +class PROJECTEXPLORER_EXPORT BuildPropertiesSettings : public Core::PagedSettings { public: BuildPropertiesSettings(); @@ -34,13 +32,4 @@ public: QString defaultBuildDirectoryTemplate(); }; -namespace Internal { - -class BuildPropertiesSettingsPage final : public Core::IOptionsPage -{ -public: - explicit BuildPropertiesSettingsPage(BuildPropertiesSettings *settings); -}; - -} // namespace Internal } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index a48953623c0..b382d6fec08 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -700,7 +700,6 @@ public: // Settings pages ProjectExplorerSettingsPage m_projectExplorerSettingsPage; - BuildPropertiesSettingsPage m_buildPropertiesSettingsPage{&m_buildPropertiesSettings}; AppOutputSettingsPage m_appOutputSettingsPage; CompileOutputSettingsPage m_compileOutputSettingsPage; DeviceSettingsPage m_deviceSettingsPage; From 268da290b2f178eeceff50e41c9fba3f927ad4a4 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 11 May 2023 14:14:00 +0200 Subject: [PATCH 0988/1447] Utils: Guard SelectionAspect value access against out-of-bounds access Change-Id: I6ca414015cb55f06b7264949487fafc7eb57efd3 Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index b73f1481a59..21c221dc5f3 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1712,12 +1712,14 @@ void SelectionAspect::setDefaultValue(const QString &val) QString SelectionAspect::stringValue() const { - return d->m_options.at(value()).displayName; + const int idx = value(); + return idx >= 0 && idx < d->m_options.size() ? d->m_options.at(idx).displayName : QString(); } QVariant SelectionAspect::itemValue() const { - return d->m_options.at(value()).itemData; + const int idx = value(); + return idx >= 0 && idx < d->m_options.size() ? d->m_options.at(idx).itemData : QVariant(); } void SelectionAspect::addOption(const QString &displayName, const QString &toolTip) From 1acd2499e29b6119fe1db0520867e97ecb89f88b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 9 May 2023 15:18:42 +0200 Subject: [PATCH 0989/1447] Utils: replace LineColumn with Text::Position Change-Id: Ia69547374efec7412717cbed1eb4162162a89d39 Reviewed-by: Jarek Kobus Reviewed-by: Qt CI Bot Reviewed-by: Cristian Adam --- src/libs/utils/CMakeLists.txt | 1 - src/libs/utils/linecolumn.h | 39 ------------------- src/libs/utils/utils.qbs | 1 - .../clangformat/clangformatbaseindenter.cpp | 1 - src/plugins/cppeditor/cppeditoroutline.cpp | 1 - src/plugins/cppeditor/cppoutline.cpp | 5 +-- src/plugins/cppeditor/cppoutlinemodel.cpp | 7 ++-- src/plugins/cppeditor/cppoutlinemodel.h | 5 ++- .../unit/unittest/gtest-creator-printing.cpp | 6 --- tests/unit/unittest/gtest-creator-printing.h | 1 - 10 files changed, 8 insertions(+), 59 deletions(-) delete mode 100644 src/libs/utils/linecolumn.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 5fa076027fd..5762fc3902e 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -89,7 +89,6 @@ add_qtc_library(Utils launcherpackets.cpp launcherpackets.h launchersocket.cpp launchersocket.h layoutbuilder.cpp layoutbuilder.h - linecolumn.h link.cpp link.h listmodel.h listutils.h diff --git a/src/libs/utils/linecolumn.h b/src/libs/utils/linecolumn.h deleted file mode 100644 index 4cd982b8e7e..00000000000 --- a/src/libs/utils/linecolumn.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "utils_global.h" - -#include - -#include - -namespace Utils { - -class QTCREATOR_UTILS_EXPORT LineColumn -{ -public: - bool isValid() const - { - return line > 0 && column >= 0; - } - - friend bool operator==(LineColumn first, LineColumn second) - { - return first.isValid() && first.line == second.line && first.column == second.column; - } - - friend bool operator!=(LineColumn first, LineColumn second) - { - return !(first == second); - } - -public: - int line = 0; - int column = -1; -}; - -} // namespace Utils - -Q_DECLARE_METATYPE(Utils::LineColumn) diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d3c826ef26f..f316a8b75b5 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -185,7 +185,6 @@ Project { "launchersocket.h", "layoutbuilder.cpp", "layoutbuilder.h", - "linecolumn.h", "link.cpp", "link.h", "listmodel.h", diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 64d7d4a4905..65a1fe3c9db 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include diff --git a/src/plugins/cppeditor/cppeditoroutline.cpp b/src/plugins/cppeditor/cppeditoroutline.cpp index a3c9c363f99..701eea0a76d 100644 --- a/src/plugins/cppeditor/cppeditoroutline.cpp +++ b/src/plugins/cppeditor/cppeditoroutline.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/src/plugins/cppeditor/cppoutline.cpp b/src/plugins/cppeditor/cppoutline.cpp index 2efa3709269..d492ad4fa7e 100644 --- a/src/plugins/cppeditor/cppoutline.cpp +++ b/src/plugins/cppeditor/cppoutline.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -184,8 +183,8 @@ void CppOutlineWidget::updateIndexNow() void CppOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex) { QModelIndex index = m_proxyModel->mapToSource(proxyIndex); - Utils::LineColumn lineColumn - = m_editor->cppEditorDocument()->outlineModel().lineColumnFromIndex(index); + Utils::Text::Position lineColumn + = m_editor->cppEditorDocument()->outlineModel().positionFromIndex(index); if (!lineColumn.isValid()) return; diff --git a/src/plugins/cppeditor/cppoutlinemodel.cpp b/src/plugins/cppeditor/cppoutlinemodel.cpp index 660492b81cd..068dc310b1e 100644 --- a/src/plugins/cppeditor/cppoutlinemodel.cpp +++ b/src/plugins/cppeditor/cppoutlinemodel.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -239,9 +238,9 @@ Utils::Link OutlineModel::linkFromIndex(const QModelIndex &sourceIndex) const return symbol->toLink(); } -Utils::LineColumn OutlineModel::lineColumnFromIndex(const QModelIndex &sourceIndex) const +Utils::Text::Position OutlineModel::positionFromIndex(const QModelIndex &sourceIndex) const { - Utils::LineColumn lineColumn; + Utils::Text::Position lineColumn; CPlusPlus::Symbol *symbol = symbolFromIndex(sourceIndex); if (!symbol) return lineColumn; @@ -252,7 +251,7 @@ Utils::LineColumn OutlineModel::lineColumnFromIndex(const QModelIndex &sourceInd OutlineModel::Range OutlineModel::rangeFromIndex(const QModelIndex &sourceIndex) const { - Utils::LineColumn lineColumn = lineColumnFromIndex(sourceIndex); + Utils::Text::Position lineColumn = positionFromIndex(sourceIndex); return {lineColumn, lineColumn}; } diff --git a/src/plugins/cppeditor/cppoutlinemodel.h b/src/plugins/cppeditor/cppoutlinemodel.h index 3afed56486b..ce499c91a0a 100644 --- a/src/plugins/cppeditor/cppoutlinemodel.h +++ b/src/plugins/cppeditor/cppoutlinemodel.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include @@ -44,8 +45,8 @@ public: bool isGenerated(const QModelIndex &sourceIndex) const; Utils::Link linkFromIndex(const QModelIndex &sourceIndex) const; - Utils::LineColumn lineColumnFromIndex(const QModelIndex &sourceIndex) const; - using Range = std::pair; + Utils::Text::Position positionFromIndex(const QModelIndex &sourceIndex) const; + using Range = std::pair; Range rangeFromIndex(const QModelIndex &sourceIndex) const; // line is 1-based and column is 0-based diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 4da2cee485b..602e973af1b 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -42,11 +41,6 @@ std::ostream &operator<<(std::ostream &out, const monostate &) } // namespace std namespace Utils { - -std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn) -{ - return out << "(" << lineColumn.line << ", " << lineColumn.column << ")"; -} namespace { const char * toText(Utils::Language language) { diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index d9d3cba5592..4fb8b7d316b 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -72,7 +72,6 @@ class LineColumn; class SmallStringView; class FilePath; -std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn); std::ostream &operator<<(std::ostream &out, const Utils::Language &language); std::ostream &operator<<(std::ostream &out, const Utils::LanguageVersion &languageVersion); std::ostream &operator<<(std::ostream &out, const Utils::LanguageExtension &languageExtension); From fb406a26f49e6b195c9e6e4e9d17e572092add63 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 11 May 2023 13:15:55 +0200 Subject: [PATCH 0990/1447] Utils: Turn StyleHelper into a namespace It was in fact just a bag of static functions. Most importantly, it fixes a previouls introduced build error. Amends 5975657e7747052211310a9bfedaac1fa937fc19 Change-Id: Ia7de8bdcf91e1763f9d3b435316a5df9993717de Reviewed-by: Cristian Adam Reviewed-by: Qt CI Bot --- src/libs/utils/stylehelper.cpp | 40 +++- src/libs/utils/stylehelper.h | 265 +++++++++++----------- src/plugins/coreplugin/manhattanstyle.cpp | 2 +- 3 files changed, 172 insertions(+), 135 deletions(-) diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index 43f14222ac1..cc860e715a9 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -37,6 +37,11 @@ static int range(float x, int min, int max) namespace Utils { +static StyleHelper::ToolbarStyle m_toolbarStyle = StyleHelper::defaultToolbarStyle; +// Invalid by default, setBaseColor needs to be called at least once +static QColor m_baseColor; +static QColor m_requestedBaseColor; + QColor StyleHelper::mergedColors(const QColor &colorA, const QColor &colorB, int factor) { const int maxFactor = 100; @@ -59,6 +64,21 @@ QColor StyleHelper::alphaBlendedColors(const QColor &colorA, const QColor &color ); } +QColor StyleHelper::sidebarHighlight() +{ + return QColor(255, 255, 255, 40); +} + +QColor StyleHelper::sidebarShadow() +{ + return QColor(0, 0, 0, 40); +} + +QColor StyleHelper::toolBarDropShadowColor() +{ + return QColor(0, 0, 0, 70); +} + int StyleHelper::navigationWidgetHeight() { return m_toolbarStyle == ToolbarStyleCompact ? 24 : 30; @@ -105,11 +125,6 @@ QColor StyleHelper::panelTextColor(bool lightColored) return Qt::black; } -StyleHelper::ToolbarStyle StyleHelper::m_toolbarStyle = StyleHelper::defaultToolbarStyle; -// Invalid by default, setBaseColor needs to be called at least once -QColor StyleHelper::m_baseColor; -QColor StyleHelper::m_requestedBaseColor; - QColor StyleHelper::baseColor(bool lightColored) { static const QColor windowColor = QApplication::palette().color(QPalette::Window); @@ -118,6 +133,11 @@ QColor StyleHelper::baseColor(bool lightColored) return (lightColored || windowColorAsBase) ? windowColor : m_baseColor; } +QColor StyleHelper::requestedBaseColor() +{ + return m_requestedBaseColor; +} + QColor StyleHelper::toolbarBaseColor(bool lightColored) { if (creatorTheme()->flag(Theme::QDSTheme)) @@ -166,6 +186,11 @@ QColor StyleHelper::toolBarBorderColor() clamp(base.value() * 0.80f)); } +QColor StyleHelper::buttonTextColor() +{ + return QColor(0x4c4c4c); +} + // We try to ensure that the actual color used are within // reasonalbe bounds while generating the actual baseColor // from the users request. @@ -495,6 +520,11 @@ void StyleHelper::menuGradient(QPainter *painter, const QRect &spanRect, const Q } } +bool StyleHelper::usePixmapCache() +{ + return true; +} + QPixmap StyleHelper::disabledSideBarIcon(const QPixmap &enabledicon) { QImage im = enabledicon.toImage().convertToFormat(QImage::Format_ARGB32); diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h index 9e7c3c19110..2b898cb1049 100644 --- a/src/libs/utils/stylehelper.h +++ b/src/libs/utils/stylehelper.h @@ -13,143 +13,150 @@ class QPainter; class QRect; // Note, this is exported but in a private header as qtopengl depends on it. // We should consider adding this as a public helper function. -void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); +void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, + int transposed = 0); QT_END_NAMESPACE // Helper class holding all custom color values +namespace Utils::StyleHelper { -namespace Utils { -class QTCREATOR_UTILS_EXPORT StyleHelper +const unsigned int DEFAULT_BASE_COLOR = 0x666666; +const int progressFadeAnimationDuration = 600; + +constexpr char C_ALIGN_ARROW[] = "alignarrow"; +constexpr char C_DRAW_LEFT_BORDER[] = "drawleftborder"; +constexpr char C_ELIDE_MODE[] = "elidemode"; +constexpr char C_HIDE_BORDER[] = "hideborder"; +constexpr char C_HIDE_ICON[] = "hideicon"; +constexpr char C_HIGHLIGHT_WIDGET[] = "highlightWidget"; +constexpr char C_LIGHT_COLORED[] = "lightColored"; +constexpr char C_MINI_SPLITTER[] = "minisplitter"; +constexpr char C_NOT_ELIDE_ASTERISK[] = "notelideasterisk"; +constexpr char C_NO_ARROW[] = "noArrow"; +constexpr char C_PANEL_WIDGET[] = "panelwidget"; +constexpr char C_PANEL_WIDGET_SINGLE_ROW[] = "panelwidget_singlerow"; +constexpr char C_SHOW_BORDER[] = "showborder"; +constexpr char C_TOP_BORDER[] = "topBorder"; + +enum ToolbarStyle { + ToolbarStyleCompact, + ToolbarStyleRelaxed, +}; +constexpr ToolbarStyle defaultToolbarStyle = ToolbarStyleCompact; + +// Height of the project explorer navigation bar +QTCREATOR_UTILS_EXPORT int navigationWidgetHeight(); +QTCREATOR_UTILS_EXPORT void setToolbarStyle(ToolbarStyle style); +QTCREATOR_UTILS_EXPORT ToolbarStyle toolbarStyle(); +QTCREATOR_UTILS_EXPORT qreal sidebarFontSize(); +QTCREATOR_UTILS_EXPORT QPalette sidebarFontPalette(const QPalette &original); + +// This is our color table, all colors derive from baseColor +QTCREATOR_UTILS_EXPORT QColor requestedBaseColor(); +QTCREATOR_UTILS_EXPORT QColor baseColor(bool lightColored = false); +QTCREATOR_UTILS_EXPORT QColor toolbarBaseColor(bool lightColored = false); +QTCREATOR_UTILS_EXPORT QColor panelTextColor(bool lightColored = false); +QTCREATOR_UTILS_EXPORT QColor highlightColor(bool lightColored = false); +QTCREATOR_UTILS_EXPORT QColor shadowColor(bool lightColored = false); +QTCREATOR_UTILS_EXPORT QColor borderColor(bool lightColored = false); +QTCREATOR_UTILS_EXPORT QColor toolBarBorderColor(); +QTCREATOR_UTILS_EXPORT QColor buttonTextColor(); +QTCREATOR_UTILS_EXPORT QColor mergedColors(const QColor &colorA, const QColor &colorB, + int factor = 50); +QTCREATOR_UTILS_EXPORT QColor alphaBlendedColors(const QColor &colorA, const QColor &colorB); + +QTCREATOR_UTILS_EXPORT QColor sidebarHighlight(); +QTCREATOR_UTILS_EXPORT QColor sidebarShadow(); +QTCREATOR_UTILS_EXPORT QColor toolBarDropShadowColor(); +QTCREATOR_UTILS_EXPORT QColor notTooBrightHighlightColor(); + +// Sets the base color and makes sure all top level widgets are updated +QTCREATOR_UTILS_EXPORT void setBaseColor(const QColor &color); + +// Draws a shaded anti-aliased arrow +QTCREATOR_UTILS_EXPORT void drawArrow(QStyle::PrimitiveElement element, QPainter *painter, + const QStyleOption *option); +QTCREATOR_UTILS_EXPORT void drawMinimalArrow(QStyle::PrimitiveElement element, QPainter *painter, + const QStyleOption *option); + +QTCREATOR_UTILS_EXPORT void drawPanelBgRect(QPainter *painter, const QRectF &rect, + const QBrush &brush); + +// Gradients used for panels +QTCREATOR_UTILS_EXPORT void horizontalGradient(QPainter *painter, const QRect &spanRect, + const QRect &clipRect, bool lightColored = false); +QTCREATOR_UTILS_EXPORT void verticalGradient(QPainter *painter, const QRect &spanRect, + const QRect &clipRect, bool lightColored = false); +QTCREATOR_UTILS_EXPORT void menuGradient(QPainter *painter, const QRect &spanRect, + const QRect &clipRect); +QTCREATOR_UTILS_EXPORT bool usePixmapCache(); + +QTCREATOR_UTILS_EXPORT QPixmap disabledSideBarIcon(const QPixmap &enabledicon); +QTCREATOR_UTILS_EXPORT void drawIconWithShadow(const QIcon &icon, const QRect &rect, QPainter *p, + QIcon::Mode iconMode, int dipRadius = 3, + const QColor &color = QColor(0, 0, 0, 130), + const QPoint &dipOffset = QPoint(1, -2)); +QTCREATOR_UTILS_EXPORT void drawCornerImage(const QImage &img, QPainter *painter, const QRect &rect, + int left = 0, int top = 0, int right = 0, + int bottom = 0); + +QTCREATOR_UTILS_EXPORT void tintImage(QImage &img, const QColor &tintColor); +QTCREATOR_UTILS_EXPORT QLinearGradient statusBarGradient(const QRect &statusBarRect); +QTCREATOR_UTILS_EXPORT void setPanelWidget(QWidget *widget, bool value = true); +QTCREATOR_UTILS_EXPORT void setPanelWidgetSingleRow(QWidget *widget, bool value = true); + +QTCREATOR_UTILS_EXPORT bool isQDSTheme(); + +class IconFontHelper { public: - static const unsigned int DEFAULT_BASE_COLOR = 0x666666; - static const int progressFadeAnimationDuration = 600; + IconFontHelper(const QString &iconSymbol, + const QColor &color, + const QSize &size, + QIcon::Mode mode = QIcon::Normal, + QIcon::State state = QIcon::Off) + : m_iconSymbol(iconSymbol) + , m_color(color) + , m_size(size) + , m_mode(mode) + , m_state(state) + {} - constexpr static char C_ALIGN_ARROW[] = "alignarrow"; - constexpr static char C_DRAW_LEFT_BORDER[] = "drawleftborder"; - constexpr static char C_ELIDE_MODE[] = "elidemode"; - constexpr static char C_HIDE_BORDER[] = "hideborder"; - constexpr static char C_HIDE_ICON[] = "hideicon"; - constexpr static char C_HIGHLIGHT_WIDGET[] = "highlightWidget"; - constexpr static char C_LIGHT_COLORED[] = "lightColored"; - constexpr static char C_MINI_SPLITTER[] = "minisplitter"; - constexpr static char C_NOT_ELIDE_ASTERISK[] = "notelideasterisk"; - constexpr static char C_NO_ARROW[] = "noArrow"; - constexpr static char C_PANEL_WIDGET[] = "panelwidget"; - constexpr static char C_PANEL_WIDGET_SINGLE_ROW[] = "panelwidget_singlerow"; - constexpr static char C_SHOW_BORDER[] = "showborder"; - constexpr static char C_TOP_BORDER[] = "topBorder"; - - enum ToolbarStyle { - ToolbarStyleCompact, - ToolbarStyleRelaxed, - }; - - // Height of the project explorer navigation bar - static int navigationWidgetHeight(); - static void setToolbarStyle(ToolbarStyle style); - static ToolbarStyle toolbarStyle(); - static constexpr ToolbarStyle defaultToolbarStyle = ToolbarStyleCompact; - static qreal sidebarFontSize(); - static QPalette sidebarFontPalette(const QPalette &original); - - // This is our color table, all colors derive from baseColor - static QColor requestedBaseColor() { return m_requestedBaseColor; } - static QColor baseColor(bool lightColored = false); - static QColor toolbarBaseColor(bool lightColored = false); - static QColor panelTextColor(bool lightColored = false); - static QColor highlightColor(bool lightColored = false); - static QColor shadowColor(bool lightColored = false); - static QColor borderColor(bool lightColored = false); - static QColor toolBarBorderColor(); - static QColor buttonTextColor() { return QColor(0x4c4c4c); } - static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50); - static QColor alphaBlendedColors(const QColor &colorA, const QColor &colorB); - - static QColor sidebarHighlight() { return QColor(255, 255, 255, 40); } - static QColor sidebarShadow() { return QColor(0, 0, 0, 40); } - - static QColor toolBarDropShadowColor() { return QColor(0, 0, 0, 70); } - - static QColor notTooBrightHighlightColor(); - - // Sets the base color and makes sure all top level widgets are updated - static void setBaseColor(const QColor &color); - - // Draws a shaded anti-aliased arrow - static void drawArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option); - static void drawMinimalArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option); - - static void drawPanelBgRect(QPainter *painter, const QRectF &rect, const QBrush &brush); - - // Gradients used for panels - static void horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false); - static void verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false); - static void menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect); - static bool usePixmapCache() { return true; } - - static QPixmap disabledSideBarIcon(const QPixmap &enabledicon); - static void drawIconWithShadow(const QIcon &icon, const QRect &rect, QPainter *p, QIcon::Mode iconMode, - int dipRadius = 3, const QColor &color = QColor(0, 0, 0, 130), - const QPoint &dipOffset = QPoint(1, -2)); - static void drawCornerImage(const QImage &img, QPainter *painter, const QRect &rect, - int left = 0, int top = 0, int right = 0, int bottom = 0); - - static void tintImage(QImage &img, const QColor &tintColor); - static QLinearGradient statusBarGradient(const QRect &statusBarRect); - static void setPanelWidget(QWidget *widget, bool value = true); - static void setPanelWidgetSingleRow(QWidget *widget, bool value = true); - - static bool isQDSTheme(); - - class IconFontHelper - { - public: - IconFontHelper(const QString &iconSymbol, - const QColor &color, - const QSize &size, - QIcon::Mode mode = QIcon::Normal, - QIcon::State state = QIcon::Off) - : m_iconSymbol(iconSymbol) - , m_color(color) - , m_size(size) - , m_mode(mode) - , m_state(state) - {} - - QString iconSymbol() const { return m_iconSymbol; } - QColor color() const { return m_color; } - QSize size() const { return m_size; } - QIcon::Mode mode() const { return m_mode; } - QIcon::State state() const { return m_state; } - - private: - QString m_iconSymbol; - QColor m_color; - QSize m_size; - QIcon::Mode m_mode; - QIcon::State m_state; - }; - - static QIcon getIconFromIconFont(const QString &fontName, const QList ¶meters); - static QIcon getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize, QColor color); - static QIcon getIconFromIconFont(const QString &fontName, const QString &iconSymbol, int fontSize, int iconSize); - static QIcon getCursorFromIconFont(const QString &fontname, const QString &cursorFill, const QString &cursorOutline, - int fontSize, int iconSize); - - static QString dpiSpecificImageFile(const QString &fileName); - static QString imageFileWithResolution(const QString &fileName, int dpr); - static QList availableImageResolutions(const QString &fileName); - - static double luminance(const QColor &color); - static bool isReadableOn(const QColor &background, const QColor &foreground); - // returns a foreground color readable on background (desiredForeground if already readable or adaption fails) - static QColor ensureReadableOn(const QColor &background, const QColor &desiredForeground); + QString iconSymbol() const { return m_iconSymbol; } + QColor color() const { return m_color; } + QSize size() const { return m_size; } + QIcon::Mode mode() const { return m_mode; } + QIcon::State state() const { return m_state; } private: - static ToolbarStyle m_toolbarStyle; - static QColor m_baseColor; - static QColor m_requestedBaseColor; + QString m_iconSymbol; + QColor m_color; + QSize m_size; + QIcon::Mode m_mode; + QIcon::State m_state; }; -} // namespace Utils +QTCREATOR_UTILS_EXPORT QIcon getIconFromIconFont(const QString &fontName, + const QList ¶meters); +QTCREATOR_UTILS_EXPORT QIcon getIconFromIconFont(const QString &fontName, + const QString &iconSymbol, int fontSize, + int iconSize, QColor color); +QTCREATOR_UTILS_EXPORT QIcon getIconFromIconFont(const QString &fontName, + const QString &iconSymbol, int fontSize, + int iconSize); +QTCREATOR_UTILS_EXPORT QIcon getCursorFromIconFont(const QString &fontname, + const QString &cursorFill, + const QString &cursorOutline, + int fontSize, int iconSize); + +QTCREATOR_UTILS_EXPORT QString dpiSpecificImageFile(const QString &fileName); +QTCREATOR_UTILS_EXPORT QString imageFileWithResolution(const QString &fileName, int dpr); +QTCREATOR_UTILS_EXPORT QList availableImageResolutions(const QString &fileName); + +QTCREATOR_UTILS_EXPORT double luminance(const QColor &color); +QTCREATOR_UTILS_EXPORT bool isReadableOn(const QColor &background, const QColor &foreground); +// returns a foreground color readable on background (desiredForeground if already readable or adaption fails) +QTCREATOR_UTILS_EXPORT QColor ensureReadableOn(const QColor &background, + const QColor &desiredForeground); + +} // namespace Utils::StyleHelper diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 11687c49f87..b729ab0c191 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -154,7 +154,7 @@ QPixmap getDeletePixmap(bool enabled, { using Utils::Theme; using Utils::creatorTheme; - using Utils::StyleHelper; + using namespace Utils::StyleHelper; const double xRatio = 19; const double yRatio = 9; From b8a82d824b2749d9d73d34ed1fe727b45efc34f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Wed, 10 May 2023 13:33:27 +0200 Subject: [PATCH 0991/1447] Utils: Fix unused parameter warning Change-Id: Ibe4c866b4f3bf39999cfe43bd32287e069e51d2c Reviewed-by: Qt CI Bot Reviewed-by: Jarek Kobus --- src/libs/utils/devicefileaccess.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index bda098e0f69..a29c5bb9be6 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -493,6 +493,8 @@ bool DesktopDeviceFileAccess::hasHardLinks(const FilePath &filePath) const if (s.st_nlink > 1) return true; } +#else + Q_UNUSED(filePath) #endif return false; } From 1dfaecfb1e1cc163841e0e7ba05048ab9503d45d Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 11 May 2023 21:18:56 +0200 Subject: [PATCH 0992/1447] ScxmlEditor: Fix Qbs build Amends 2d1b8dbc2987e6db76c78d8cb449b47e39dd1597. Change-Id: I994b98b3f5b5bd0ae8026f04ddd6c42beb9545e0 Reviewed-by: Alessandro Portale Reviewed-by: hjk --- src/plugins/scxmleditor/scxmleditor.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/scxmleditor/scxmleditor.qbs b/src/plugins/scxmleditor/scxmleditor.qbs index c110b92f28d..39340d8764c 100644 --- a/src/plugins/scxmleditor/scxmleditor.qbs +++ b/src/plugins/scxmleditor/scxmleditor.qbs @@ -93,6 +93,7 @@ QtcPlugin { "baseitem.cpp", "baseitem.h", "connectableitem.cpp", "connectableitem.h", "cornergrabberitem.cpp", "cornergrabberitem.h", + "eventitem.cpp", "eventitem.h", "finalstateitem.cpp", "finalstateitem.h", "genericscxmlplugin.cpp", "genericscxmlplugin.h", "graphicsitemprovider.h", From d14f1af52331755f7f7dda0eefada26b4d671a90 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 12 May 2023 06:55:36 +0200 Subject: [PATCH 0993/1447] AutoTest: Some layout polishing Layouts are simpler nowadays. Some drive-by formatting changes. Change-Id: If5fd0ff8cf8e39487bfb29d792bdf2d8ddb0342c Reviewed-by: hjk --- .../autotest/boost/boosttestsettings.cpp | 2 +- .../autotest/catch/catchtestsettings.cpp | 4 +-- src/plugins/autotest/ctest/ctestsettings.cpp | 6 ++--- src/plugins/autotest/gtest/gtestsettings.cpp | 21 +++++++--------- src/plugins/autotest/qtest/qttestsettings.cpp | 25 ++++++++----------- 5 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp index fc2ce851e62..840647572a4 100644 --- a/src/plugins/autotest/boost/boosttestsettings.cpp +++ b/src/plugins/autotest/boost/boosttestsettings.cpp @@ -65,7 +65,7 @@ BoostTestSettings::BoostTestSettings(Id settingsId) seed.setEnabled(false); seed.setLabelText(Tr::tr("Seed:")); seed.setToolTip(Tr::tr("A seed of 0 means no randomization. A value of 1 uses the current " - "time, any other value is used as random seed generator.")); + "time, any other value is used as random seed generator.")); seed.setEnabler(&randomize); registerAspect(&randomize); diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp index 12b5c1094ff..07dac310ebe 100644 --- a/src/plugins/autotest/catch/catchtestsettings.cpp +++ b/src/plugins/autotest/catch/catchtestsettings.cpp @@ -23,7 +23,7 @@ CatchTestSettings::CatchTestSettings(Id settingsId) setSettingsGroups("Autotest", "Catch2"); setLayouter([this](QWidget *widget) { - Column { Row { Grid { + Row { Form { showSuccess, br, breakOnFailure, br, noThrow, br, @@ -34,7 +34,7 @@ CatchTestSettings::CatchTestSettings(Id settingsId) confidenceIntervalChecked, confidenceInterval, br, warmupChecked, benchmarkWarmupTime, br, noAnalysis - }, st }, st }.attachTo(widget); + }, st }.attachTo(widget); }); registerAspect(&abortAfter); diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index b8485530e15..e200de98e88 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -21,7 +21,7 @@ CTestSettings::CTestSettings(Id settingsId) setDisplayName(Tr::tr("CTest")); setLayouter([this](QWidget *w) { - Column { Row { Form { + Row { Form { outputOnFail, br, scheduleRandom, br, stopOnFailure, br, @@ -39,7 +39,7 @@ CTestSettings::CTestSettings(Id settingsId) Row { testLoad, threshold} } } - }, st }, st }.attachTo(w); + }, st }.attachTo(w); }); registerAspect(&outputOnFail); @@ -95,7 +95,7 @@ CTestSettings::CTestSettings(Id settingsId) testLoad.setSettingsKey("TestLoad"); testLoad.setLabelText(Tr::tr("Test load")); testLoad.setToolTip(Tr::tr("Try not to start tests when they may cause CPU load to pass a " - "threshold.")); + "threshold.")); registerAspect(&threshold); threshold.setSettingsKey("Threshold"); diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp index 3979f28c754..d7302d6bd57 100644 --- a/src/plugins/autotest/gtest/gtestsettings.cpp +++ b/src/plugins/autotest/gtest/gtestsettings.cpp @@ -24,18 +24,14 @@ GTestSettings::GTestSettings(Id settingsId) setDisplayName(Tr::tr(GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); setLayouter([this](QWidget *widget) { - Column { Row { Column { - Grid { + Row { Form { runDisabled, br, breakOnFailure, br, repeat, iterations, br, - shuffle, seed - }, - Form { - groupMode, - gtestFilter - } - }, st }, st }.attachTo(widget); + shuffle, seed, br, + groupMode, br, + gtestFilter, br + }, st }.attachTo(widget); }); registerAspect(&iterations); @@ -66,7 +62,8 @@ GTestSettings::GTestSettings(Id settingsId) registerAspect(&repeat); repeat.setSettingsKey("Repeat"); repeat.setLabelText(Tr::tr("Repeat tests")); - repeat.setToolTip(Tr::tr("Repeats a test run (you might be required to increase the timeout to avoid canceling the tests).")); + repeat.setToolTip(Tr::tr("Repeats a test run (you might be required to increase the timeout to " + "avoid canceling the tests).")); registerAspect(&throwOnFailure); throwOnFailure.setSettingsKey("ThrowOnFailure"); @@ -110,8 +107,8 @@ GTestSettings::GTestSettings(Id settingsId) }); gtestFilter.setEnabled(false); gtestFilter.setLabelText(Tr::tr("Active filter:")); - gtestFilter.setToolTip(Tr::tr("Set the GTest filter to be used for grouping.\n" - "See Google Test documentation for further information on GTest filters.")); + gtestFilter.setToolTip(Tr::tr("Set the GTest filter to be used for grouping.\nSee Google Test " + "documentation for further information on GTest filters.")); gtestFilter.setValidationFunction([](FancyLineEdit *edit, QString * /*error*/) { return edit && GTestUtils::isValidGTestFilter(edit->text()); diff --git a/src/plugins/autotest/qtest/qttestsettings.cpp b/src/plugins/autotest/qtest/qttestsettings.cpp index 9832a0ed4a0..07fac99d986 100644 --- a/src/plugins/autotest/qtest/qttestsettings.cpp +++ b/src/plugins/autotest/qtest/qttestsettings.cpp @@ -23,21 +23,18 @@ QtTestSettings::QtTestSettings(Id settingsId) setDisplayName(Tr::tr(QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); setLayouter([this](QWidget *widget) { - Column { Row { Column { - noCrashHandler, - useXMLOutput, - verboseBench, - logSignalsSlots, - Row { - limitWarnings, maxWarnings - }, + Row { Form { + noCrashHandler, br, + useXMLOutput, br, + verboseBench, br, + logSignalsSlots, br, + limitWarnings, maxWarnings, br, Group { title(Tr::tr("Benchmark Metrics")), Column { metrics } - }, - br, - quickCheckForDerivedTests, - }, st }, st }.attachTo(widget); + }, br, + quickCheckForDerivedTests, br + }, st }.attachTo(widget); }); registerAspect(&metrics); @@ -68,8 +65,8 @@ QtTestSettings::QtTestSettings(Id settingsId) useXMLOutput.setDefaultValue(true); useXMLOutput.setLabelText(Tr::tr("Use XML output")); useXMLOutput.setToolTip(Tr::tr("XML output is recommended, because it avoids parsing issues, " - "while plain text is more human readable.\n\n" - "Warning: Plain text misses some information, such as duration.")); + "while plain text is more human readable.\n\nWarning: " + "Plain text misses some information, such as duration.")); registerAspect(&verboseBench); verboseBench.setSettingsKey("VerboseBench"); From 1a86c7bed4c100e227173ed288a9285b44ecbb57 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 11 May 2023 15:46:34 +0200 Subject: [PATCH 0994/1447] Utils: Remove empty item after option Triggers a soft assert. Change-Id: I9ad863ceb7e1f377e4f9fbae62cca1d0932a76d6 Reviewed-by: hjk --- src/libs/utils/aspects.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 21c221dc5f3..0f75cfcbded 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1597,7 +1597,6 @@ void SelectionAspect::addToLayout(Layouting::LayoutItem &parent) button->setChecked(i == value()); button->setEnabled(option.enabled); button->setToolTip(option.tooltip); - parent.addItem(Layouting::empty); parent.addItem(button); d->m_buttons.append(button); d->m_buttonGroup->addButton(button, i); From 979f938aa5003d52b4e0ff275180219c1c82b9e3 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 12 May 2023 08:16:11 +0200 Subject: [PATCH 0995/1447] AutoTest: Fix handling of multiple fails of tests Broke with d05c5b7d07194b7c0fe938e88e63cfaab9ee5f4d. Fixes: QTCREATORBUG-29146 Change-Id: If7cc7f943c16113785a21b661a545e00331f1dcd Reviewed-by: Jarek Kobus Reviewed-by: David Schulz --- src/plugins/autotest/gtest/gtestoutputreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index a24377bef7a..7c6365d2f0a 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -210,7 +210,7 @@ void GTestOutputReader::handleDescriptionAndReportResult(const TestResult &testR } } result.setDescription(resultDescription.join('\n')); - reportResult(testResult); + reportResult(result); resultDescription.clear(); result = createDefaultResult(); From f2213db913dcf379a05b375fe01e3df0fec7fe8e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 9 May 2023 16:50:22 +0200 Subject: [PATCH 0996/1447] Terminal: Fix warning warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] Change-Id: Ib66cbde9ff48f31d1a5ca97c8bafb0efd419dc2e Reviewed-by: Reviewed-by: hjk --- src/plugins/terminal/terminalwidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index 19ad1b82023..b3c7421a6a7 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -658,9 +658,9 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) const qreal radiusBase = qMax(qreal(1), maxRadius); const qreal pWidth = pen.widthF(); - QString key = QLatin1String("WaveUnderline-") % pen.color().name() - % QString::number(*(size_t *) &radiusBase, 16) - % QString::number(*(size_t *) &pWidth); + const QString key = QLatin1String("WaveUnderline-") % pen.color().name() + % QString::number(int(radiusBase), 16) + % QString::number(int(pWidth), 16); QPixmap pixmap; if (QPixmapCache::find(key, &pixmap)) From c559bcc4b1c356d62f9717232c2cc21996185afe Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 22:40:53 +0200 Subject: [PATCH 0997/1447] BookmarkFilter: Remove the old matchesFor() implementation Change-Id: I85b02fcaf73686146fe4da9d8582dd0c677ba101 Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns Reviewed-by: Eike Ziller --- src/plugins/bookmarks/bookmarkfilter.cpp | 13 ------------- src/plugins/bookmarks/bookmarkfilter.h | 7 ++----- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index e8322877c27..1cedbade481 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -112,17 +112,4 @@ LocatorFilterEntries BookmarkFilter::match(const QString &input) const return entries; } -void BookmarkFilter::prepareSearch(const QString &entry) -{ - m_results = match(entry); -} - -QList BookmarkFilter::matchesFor(QFutureInterface &future, - const QString &entry) -{ - Q_UNUSED(future) - Q_UNUSED(entry) - return m_results; -} - } // Bookmarks::Internal diff --git a/src/plugins/bookmarks/bookmarkfilter.h b/src/plugins/bookmarks/bookmarkfilter.h index 9c3b6d1d9aa..f85eff9b7d7 100644 --- a/src/plugins/bookmarks/bookmarkfilter.h +++ b/src/plugins/bookmarks/bookmarkfilter.h @@ -12,16 +12,13 @@ class BookmarkManager; class BookmarkFilter : public Core::ILocatorFilter { public: - explicit BookmarkFilter(BookmarkManager *manager); - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; + BookmarkFilter(BookmarkManager *manager); + private: Core::LocatorMatcherTasks matchers() final; Core::LocatorFilterEntries match(const QString &input) const; BookmarkManager *m_manager = nullptr; // not owned - QList m_results; }; } // Bookmarks::Internal From 946da55f6eaa881f0d0a5771681828168121d68a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 22:32:30 +0200 Subject: [PATCH 0998/1447] MacroLocatorFilter: Remove the old matchesFor() implementation Change-Id: I44869742c590125805eab277464ffde3df3a2bc2 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/macros/macrolocatorfilter.cpp | 47 ----------------------- src/plugins/macros/macrolocatorfilter.h | 10 +---- 2 files changed, 2 insertions(+), 55 deletions(-) diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 76201d09405..f43758bd034 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -73,50 +73,3 @@ LocatorMatcherTasks MacroLocatorFilter::matchers() }; return {{Sync(onSetup), storage}}; } - -QList MacroLocatorFilter::matchesFor(QFutureInterface &future, const QString &entry) -{ - Q_UNUSED(future) - QList goodEntries; - QList betterEntries; - - const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); - - const QMap ¯os = MacroManager::macros(); - - for (auto it = macros.cbegin(), end = macros.cend(); it != end; ++it) { - const QString displayName = it.key(); - const QString description = it.value()->description(); - - int index = displayName.indexOf(entry, 0, entryCaseSensitivity); - LocatorFilterEntry::HighlightInfo::DataType hDataType - = LocatorFilterEntry::HighlightInfo::DisplayName; - if (index < 0) { - index = description.indexOf(entry, 0, entryCaseSensitivity); - hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo; - } - - if (index >= 0) { - LocatorFilterEntry filterEntry; - filterEntry.displayName = displayName; - filterEntry.acceptor = [displayName] { - IEditor *editor = EditorManager::currentEditor(); - if (editor) - editor->widget()->setFocus(Qt::OtherFocusReason); - - MacroManager::instance()->executeMacro(displayName); - return AcceptResult(); - }; - filterEntry.displayIcon = m_icon; - filterEntry.extraInfo = description; - filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); - - if (index == 0) - betterEntries.append(filterEntry); - else - goodEntries.append(filterEntry); - } - } - betterEntries.append(goodEntries); - return betterEntries; -} diff --git a/src/plugins/macros/macrolocatorfilter.h b/src/plugins/macros/macrolocatorfilter.h index 189cfcc6973..b6acc6d2c7f 100644 --- a/src/plugins/macros/macrolocatorfilter.h +++ b/src/plugins/macros/macrolocatorfilter.h @@ -5,23 +5,17 @@ #include -namespace Macros { -namespace Internal { +namespace Macros::Internal { class MacroLocatorFilter : public Core::ILocatorFilter { - Q_OBJECT - public: MacroLocatorFilter(); - QList matchesFor(QFutureInterface &future, - const QString &entry) override; private: Core::LocatorMatcherTasks matchers() final; const QIcon m_icon; }; -} // namespace Internal -} // namespace Macros +} // namespace Macros::Internal From 0c8ae843c6cd2516e4394cd102eeec254d9d4ac2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 11 May 2023 15:47:25 +0200 Subject: [PATCH 0999/1447] Terminal: Switch Mode to ensure visible Change-Id: I6d92ac07b7f6e7d5ed3fa4d27531d1cb8ec1a36f Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalpane.cpp | 6 +++--- src/plugins/terminal/terminalprocessimpl.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index f5c4046f922..92ad5951914 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -175,7 +175,7 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) { OpenTerminalParameters parametersCopy{parameters}; if (!m_isVisible) - emit showPage(0); + emit showPage(IOutputPane::ModeSwitch); if (!parametersCopy.workingDirectory) { const std::optional projectDir = startupProjectDirectory(); @@ -199,7 +199,7 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) { if (!m_isVisible) - emit showPage(0); + emit showPage(IOutputPane::ModeSwitch); m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminal, title)); setupTerminalWidget(terminal); @@ -209,7 +209,7 @@ void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) void TerminalPane::ensureVisible(TerminalWidget *terminal) { if (!m_isVisible) - emit showPage(0); + emit showPage(IOutputPane::ModeSwitch); m_tabWidget->setCurrentWidget(terminal); terminal->setFocus(); } diff --git a/src/plugins/terminal/terminalprocessimpl.cpp b/src/plugins/terminal/terminalprocessimpl.cpp index ef3c4acf646..d2b76e51a68 100644 --- a/src/plugins/terminal/terminalprocessimpl.cpp +++ b/src/plugins/terminal/terminalprocessimpl.cpp @@ -44,10 +44,11 @@ public: terminal->setShellName(setup.m_commandLine.executable().fileName()); m_terminalPane->addTerminal(terminal, "App"); } else { - m_terminalPane->ensureVisible(terminal); terminal->restart(openParameters); } + m_terminalPane->ensureVisible(terminal); + connect(terminal, &TerminalWidget::destroyed, m_process, [process = m_process] { if (process->inferiorProcessId()) process->emitFinished(-1, QProcess::CrashExit); From b1d520c6b1a145fa1e7713c355b237b705fc2aaf Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 01:03:44 +0200 Subject: [PATCH 1000/1447] CppLocatorFilters: Remove the old matchesFor() implementation Move the implementation of CppCurrentDocumentFilter into cpplocatorfilter.h/cpp. Rename CppLocatorFilter into CppAllSymbolsFilter to conform to the other names. Remove some unneeded intermediate classes now. Change-Id: Ia911dc826b83ba11894757fc353ff72211910ff7 Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/CMakeLists.txt | 1 - .../cppeditor/cppcurrentdocumentfilter.cpp | 200 ------------------ .../cppeditor/cppcurrentdocumentfilter.h | 48 ----- src/plugins/cppeditor/cppeditor.qbs | 2 - src/plugins/cppeditor/cpplocatorfilter.cpp | 132 ++---------- src/plugins/cppeditor/cpplocatorfilter.h | 56 ++--- src/plugins/cppeditor/cppmodelmanager.cpp | 5 +- 7 files changed, 36 insertions(+), 408 deletions(-) delete mode 100644 src/plugins/cppeditor/cppcurrentdocumentfilter.cpp delete mode 100644 src/plugins/cppeditor/cppcurrentdocumentfilter.h diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt index 184dc9f50fa..021bf0b7630 100644 --- a/src/plugins/cppeditor/CMakeLists.txt +++ b/src/plugins/cppeditor/CMakeLists.txt @@ -32,7 +32,6 @@ add_qtc_plugin(CppEditor cppcompletionassist.cpp cppcompletionassist.h cppcompletionassistprocessor.cpp cppcompletionassistprocessor.h cppcompletionassistprovider.cpp cppcompletionassistprovider.h - cppcurrentdocumentfilter.cpp cppcurrentdocumentfilter.h cppcursorinfo.h cppdoxygen.cpp cppdoxygen.h cppeditor.qrc diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp deleted file mode 100644 index ba7cdfda713..00000000000 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "cppcurrentdocumentfilter.h" - -#include "cppeditorconstants.h" -#include "cppeditortr.h" -#include "cpplocatorfilter.h" -#include "cppmodelmanager.h" - -#include -#include -#include - -#include -#include - -using namespace Core; -using namespace CPlusPlus; - -namespace CppEditor::Internal { - -CppCurrentDocumentFilter::CppCurrentDocumentFilter() - : m_modelManager(CppModelManager::instance()) -{ - setId(Constants::CURRENT_DOCUMENT_FILTER_ID); - setDisplayName(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME)); - setDescription(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DESCRIPTION)); - setDefaultShortcutString("."); - setPriority(High); - setDefaultIncludedByDefault(false); - - search.setSymbolsToSearchFor(SymbolSearcher::Declarations | - SymbolSearcher::Enums | - SymbolSearcher::Functions | - SymbolSearcher::Classes); - - connect(m_modelManager, &CppModelManager::documentUpdated, - this, &CppCurrentDocumentFilter::onDocumentUpdated); - connect(EditorManager::instance(), &EditorManager::currentEditorChanged, - this, &CppCurrentDocumentFilter::onCurrentEditorChanged); - connect(EditorManager::instance(), &EditorManager::editorAboutToClose, - this, &CppCurrentDocumentFilter::onEditorAboutToClose); -} - -LocatorMatcherTasks CppCurrentDocumentFilter::matchers() -{ - return CppEditor::cppMatchers(MatcherType::CurrentDocumentSymbols); -} - -void CppCurrentDocumentFilter::makeAuxiliary() -{ - setId({}); - setDisplayName({}); - setDefaultShortcutString({}); - setEnabled(false); - setHidden(true); -} - -QList CppCurrentDocumentFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - const QRegularExpression regexp = createRegExp(entry); - if (!regexp.isValid()) - return {}; - - struct Entry - { - LocatorFilterEntry entry; - IndexItem::Ptr info; - }; - QList goodEntries; - QList betterEntries; - const QList items = itemsOfCurrentDocument(); - for (const IndexItem::Ptr &info : items) { - if (future.isCanceled()) - break; - - QString matchString = info->symbolName(); - if (info->type() == IndexItem::Declaration) - matchString = info->representDeclaration(); - else if (info->type() == IndexItem::Function) - matchString += info->symbolType(); - - QRegularExpressionMatch match = regexp.match(matchString); - if (match.hasMatch()) { - const bool betterMatch = match.capturedStart() == 0; - QString name = matchString; - QString extraInfo = info->symbolScope(); - if (info->type() == IndexItem::Function) { - if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) { - name += info->symbolType(); - match = regexp.match(name); - } - } - - LocatorFilterEntry filterEntry; - filterEntry.displayName = name; - filterEntry.displayIcon = info->icon(); - filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; - filterEntry.extraInfo = extraInfo; - if (match.hasMatch()) { - filterEntry.highlightInfo = highlightInfo(match); - } else { - match = regexp.match(extraInfo); - filterEntry.highlightInfo = - highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo); - } - - if (betterMatch) - betterEntries.append({filterEntry, info}); - else - goodEntries.append({filterEntry, info}); - } - } - - // entries are unsorted by design! - betterEntries += goodEntries; - - QHash> possibleDuplicates; - for (const Entry &e : std::as_const(betterEntries)) - possibleDuplicates[e.info->scopedSymbolName() + e.info->symbolType()] << e; - for (auto it = possibleDuplicates.cbegin(); it != possibleDuplicates.cend(); ++it) { - const QList &duplicates = it.value(); - if (duplicates.size() == 1) - continue; - QList declarations; - QList definitions; - for (const Entry &candidate : duplicates) { - const IndexItem::Ptr info = candidate.info; - if (info->type() != IndexItem::Function) - break; - if (info->isFunctionDefinition()) - definitions << candidate; - else - declarations << candidate; - } - if (definitions.size() == 1 - && declarations.size() + definitions.size() == duplicates.size()) { - for (const Entry &decl : std::as_const(declarations)) { - Utils::erase(betterEntries, [&decl](const Entry &e) { - return e.info == decl.info; - }); - } - } - } - return Utils::transform(betterEntries, [](const Entry &entry) { return entry.entry; }); -} - -void CppCurrentDocumentFilter::onDocumentUpdated(Document::Ptr doc) -{ - QMutexLocker locker(&m_mutex); - if (m_currentFileName == doc->filePath()) - m_itemsOfCurrentDoc.clear(); -} - -void CppCurrentDocumentFilter::onCurrentEditorChanged(IEditor *currentEditor) -{ - QMutexLocker locker(&m_mutex); - if (currentEditor) - m_currentFileName = currentEditor->document()->filePath(); - else - m_currentFileName.clear(); - m_itemsOfCurrentDoc.clear(); -} - -void CppCurrentDocumentFilter::onEditorAboutToClose(IEditor *editorAboutToClose) -{ - if (!editorAboutToClose) - return; - - QMutexLocker locker(&m_mutex); - if (m_currentFileName == editorAboutToClose->document()->filePath()) { - m_currentFileName.clear(); - m_itemsOfCurrentDoc.clear(); - } -} - -QList CppCurrentDocumentFilter::itemsOfCurrentDocument() -{ - QMutexLocker locker(&m_mutex); - - if (m_currentFileName.isEmpty()) - return QList(); - - if (m_itemsOfCurrentDoc.isEmpty()) { - const Snapshot snapshot = m_modelManager->snapshot(); - if (const Document::Ptr thisDocument = snapshot.document(m_currentFileName)) { - IndexItem::Ptr rootNode = search(thisDocument); - rootNode->visitAllChildren([&](const IndexItem::Ptr &info) { - m_itemsOfCurrentDoc.append(info); - return IndexItem::Recurse; - }); - } - } - - return m_itemsOfCurrentDoc; -} - -} // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.h b/src/plugins/cppeditor/cppcurrentdocumentfilter.h deleted file mode 100644 index 5327851e6ff..00000000000 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "searchsymbols.h" - -#include - -namespace Core { class IEditor; } - -namespace CppEditor { - -class CppModelManager; - -namespace Internal { - -// TODO: Move the class into cpplocatorfilter.h -class CppCurrentDocumentFilter : public Core::ILocatorFilter -{ - Q_OBJECT - -public: - explicit CppCurrentDocumentFilter(); - ~CppCurrentDocumentFilter() override = default; - - void makeAuxiliary(); - - QList matchesFor(QFutureInterface &future, - const QString &entry) override; -private: - Core::LocatorMatcherTasks matchers() final; - void onDocumentUpdated(CPlusPlus::Document::Ptr doc); - void onCurrentEditorChanged(Core::IEditor *currentEditor); - void onEditorAboutToClose(Core::IEditor *currentEditor); - - QList itemsOfCurrentDocument(); - - CppModelManager * m_modelManager; - SearchSymbols search; - - mutable QMutex m_mutex; - Utils::FilePath m_currentFileName; - QList m_itemsOfCurrentDoc; -}; - -} // namespace Internal -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index dd07f44901c..b7d2aea0314 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -82,8 +82,6 @@ QtcPlugin { "cppcompletionassistprocessor.h", "cppcompletionassistprovider.cpp", "cppcompletionassistprovider.h", - "cppcurrentdocumentfilter.cpp", - "cppcurrentdocumentfilter.h", "cppcursorinfo.h", "cppdoxygen.cpp", "cppdoxygen.h", diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 7ddc7805731..4e78d8130f7 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -332,7 +332,7 @@ LocatorMatcherTasks cppMatchers(MatcherType type) return {creator()}; } -CppLocatorFilter::CppLocatorFilter() +CppAllSymbolsFilter::CppAllSymbolsFilter() { setId(Constants::LOCATOR_FILTER_ID); setDisplayName(Tr::tr(Constants::LOCATOR_FILTER_DISPLAY_NAME)); @@ -341,99 +341,11 @@ CppLocatorFilter::CppLocatorFilter() setDefaultIncludedByDefault(false); } -LocatorMatcherTasks CppLocatorFilter::matchers() +LocatorMatcherTasks CppAllSymbolsFilter::matchers() { return {allSymbolsMatcher()}; } -LocatorFilterEntry CppLocatorFilter::filterEntryFromIndexItem(IndexItem::Ptr info) -{ - LocatorFilterEntry filterEntry; - filterEntry.displayName = info->scopedSymbolName(); - filterEntry.displayIcon = info->icon(); - filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; - if (info->type() == IndexItem::Class || info->type() == IndexItem::Enum) - filterEntry.extraInfo = info->shortNativeFilePath(); - else - filterEntry.extraInfo = info->symbolType(); - - return filterEntry; -} - -QList CppLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - QList entries[int(MatchLevel::Count)]; - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); - const IndexItem::ItemType wanted = matchTypes(); - - const QRegularExpression regexp = createRegExp(entry); - if (!regexp.isValid()) - return {}; - const bool hasColonColon = entry.contains("::"); - const QRegularExpression shortRegexp = - hasColonColon ? createRegExp(entry.mid(entry.lastIndexOf("::") + 2)) : regexp; - - CppLocatorData *locatorData = CppModelManager::instance()->locatorData(); - locatorData->filterAllFiles([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult { - if (future.isCanceled()) - return IndexItem::Break; - const IndexItem::ItemType type = info->type(); - if (type & wanted) { - const QString symbolName = info->symbolName(); - QString matchString = hasColonColon ? info->scopedSymbolName() : symbolName; - int matchOffset = hasColonColon ? matchString.size() - symbolName.size() : 0; - QRegularExpressionMatch match = regexp.match(matchString); - bool matchInParameterList = false; - if (!match.hasMatch() && (type == IndexItem::Function)) { - matchString += info->symbolType(); - match = regexp.match(matchString); - matchInParameterList = true; - } - - if (match.hasMatch()) { - LocatorFilterEntry filterEntry = filterEntryFromIndexItem(info); - - // Highlight the matched characters, therefore it may be necessary - // to update the match if the displayName is different from matchString - if (QStringView(matchString).mid(matchOffset) != filterEntry.displayName) { - match = shortRegexp.match(filterEntry.displayName); - matchOffset = 0; - } - filterEntry.highlightInfo = highlightInfo(match); - if (matchInParameterList && filterEntry.highlightInfo.startsDisplay.isEmpty()) { - match = regexp.match(filterEntry.extraInfo); - filterEntry.highlightInfo - = highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo); - } else if (matchOffset > 0) { - for (int &start : filterEntry.highlightInfo.startsDisplay) - start -= matchOffset; - } - - if (matchInParameterList) - entries[int(MatchLevel::Normal)].append(filterEntry); - else if (filterEntry.displayName.startsWith(entry, caseSensitivityForPrefix)) - entries[int(MatchLevel::Best)].append(filterEntry); - else if (filterEntry.displayName.contains(entry, caseSensitivityForPrefix)) - entries[int(MatchLevel::Better)].append(filterEntry); - else - entries[int(MatchLevel::Good)].append(filterEntry); - } - } - - if (info->type() & IndexItem::Enum) - return IndexItem::Continue; - else - return IndexItem::Recurse; - }); - - for (auto &entry : entries) { - if (entry.size() < 1000) - Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); - } - - return std::accumulate(std::begin(entries), std::end(entries), QList()); -} CppClassesFilter::CppClassesFilter() { @@ -449,19 +361,6 @@ LocatorMatcherTasks CppClassesFilter::matchers() return {classMatcher()}; } -LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info) -{ - LocatorFilterEntry filterEntry; - filterEntry.displayName = info->symbolName(); - filterEntry.displayIcon = info->icon(); - filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; - filterEntry.extraInfo = info->symbolScope().isEmpty() - ? info->shortNativeFilePath() - : info->symbolScope(); - filterEntry.filePath = info->filePath(); - return filterEntry; -} - CppFunctionsFilter::CppFunctionsFilter() { setId(Constants::FUNCTIONS_FILTER_ID); @@ -476,24 +375,19 @@ LocatorMatcherTasks CppFunctionsFilter::matchers() return {functionMatcher()}; } -LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr info) +CppCurrentDocumentFilter::CppCurrentDocumentFilter() { - QString name = info->symbolName(); - QString extraInfo = info->symbolScope(); - info->unqualifiedNameAndScope(name, &name, &extraInfo); - if (extraInfo.isEmpty()) { - extraInfo = info->shortNativeFilePath(); - } else { - extraInfo.append(" (" + info->filePath().fileName() + ')'); - } + setId(Constants::CURRENT_DOCUMENT_FILTER_ID); + setDisplayName(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME)); + setDescription(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DESCRIPTION)); + setDefaultShortcutString("."); + setPriority(High); + setDefaultIncludedByDefault(false); +} - LocatorFilterEntry filterEntry; - filterEntry.displayName = name + info->symbolType(); - filterEntry.displayIcon = info->icon(); - filterEntry.linkForEditor = {info->filePath(), info->line(), info->column()}; - filterEntry.extraInfo = extraInfo; - - return filterEntry; +LocatorMatcherTasks CppCurrentDocumentFilter::matchers() +{ + return {currentDocumentMatcher()}; } } // namespace CppEditor diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index 65bc5fa2d13..0b012fac6b4 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -4,7 +4,6 @@ #pragma once #include "cppeditor_global.h" -#include "indexitem.h" #include @@ -12,50 +11,37 @@ namespace CppEditor { Core::LocatorMatcherTasks CPPEDITOR_EXPORT cppMatchers(Core::MatcherType type); -class CPPEDITOR_EXPORT CppLocatorFilter : public Core::ILocatorFilter +class CppAllSymbolsFilter : public Core::ILocatorFilter { - Q_OBJECT - public: - explicit CppLocatorFilter(); - - QList matchesFor(QFutureInterface &future, - const QString &entry) override; -protected: - virtual IndexItem::ItemType matchTypes() const { return IndexItem::All; } - virtual Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info); - -private: - Core::LocatorMatcherTasks matchers() override; -}; - -// TODO: Don't derive, flatten the hierarchy -class CPPEDITOR_EXPORT CppClassesFilter : public CppLocatorFilter -{ - Q_OBJECT - -public: - explicit CppClassesFilter(); - -protected: - IndexItem::ItemType matchTypes() const override { return IndexItem::Class; } - Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info) override; + CppAllSymbolsFilter(); private: Core::LocatorMatcherTasks matchers() final; }; -// TODO: Don't derive, flatten the hierarchy -class CPPEDITOR_EXPORT CppFunctionsFilter : public CppLocatorFilter +class CppClassesFilter : public Core::ILocatorFilter { - Q_OBJECT - public: - explicit CppFunctionsFilter(); + CppClassesFilter(); -protected: - IndexItem::ItemType matchTypes() const override { return IndexItem::Function; } - Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info) override; +private: + Core::LocatorMatcherTasks matchers() final; +}; + +class CppFunctionsFilter : public Core::ILocatorFilter +{ +public: + CppFunctionsFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; +}; + +class CppCurrentDocumentFilter : public Core::ILocatorFilter +{ +public: + CppCurrentDocumentFilter(); private: Core::LocatorMatcherTasks matchers() final; diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index c249dd29392..0de793bfc4e 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -6,10 +6,10 @@ #include "abstracteditorsupport.h" #include "baseeditordocumentprocessor.h" #include "compileroptionsbuilder.h" +#include "cppbuiltinmodelmanagersupport.h" #include "cppcanonicalsymbol.h" #include "cppcodemodelinspectordumper.h" #include "cppcodemodelsettings.h" -#include "cppcurrentdocumentfilter.h" #include "cppeditorconstants.h" #include "cppeditortr.h" #include "cppfindreferences.h" @@ -17,7 +17,6 @@ #include "cppindexingsupport.h" #include "cpplocatordata.h" #include "cpplocatorfilter.h" -#include "cppbuiltinmodelmanagersupport.h" #include "cppprojectfile.h" #include "cppsourceprocessor.h" #include "cpptoolsjsextension.h" @@ -890,7 +889,7 @@ void CppModelManager::initCppTools() &d->m_locatorData, &CppLocatorData::onAboutToRemoveFiles); // Set up builtin filters - setLocatorFilter(std::make_unique()); + setLocatorFilter(std::make_unique()); setClassesFilter(std::make_unique()); setIncludesFilter(std::make_unique()); setFunctionsFilter(std::make_unique()); From ef06d8925578a43c9c45832b38839755d5e59a7d Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Mon, 8 May 2023 11:39:33 +0200 Subject: [PATCH 1001/1447] ClangFormat: Improve conversion from and to ClangFormat style Improved conversion from ClangFormat style settings to CppCode style settings and the other way around. Task-number: QTCREATORBUG-29069 Change-Id: If4f75259f7fe77397fc144a83370749a49d25297 Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/clangformat/clangformatfile.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangformat/clangformatfile.cpp b/src/plugins/clangformat/clangformatfile.cpp index 7023645cc80..f0c48099131 100644 --- a/src/plugins/clangformat/clangformatfile.cpp +++ b/src/plugins/clangformat/clangformatfile.cpp @@ -169,6 +169,12 @@ CppEditor::CppCodeStyleSettings ClangFormatFile::toCppCodeStyleSettings( settings.bindStarToRightSpecifier = style.PointerAlignment == FormatStyle::PAS_Right; } + settings.extraPaddingForConditionsIfConfusingAlign = style.BreakBeforeBinaryOperators + == FormatStyle::BOS_All; + settings.alignAssignments = style.BreakBeforeBinaryOperators == FormatStyle::BOS_All + || style.BreakBeforeBinaryOperators + == FormatStyle::BOS_NonAssignment; + return settings; } @@ -188,6 +194,9 @@ void ClangFormatFile::fromCppCodeStyleSettings(const CppEditor::CppCodeStyleSett if (settings.indentClassBraces || settings.indentEnumBraces || settings.indentBlockBraces || settings.indentFunctionBraces) m_style.BreakBeforeBraces = FormatStyle::BS_Whitesmiths; + else + m_style.BreakBeforeBraces = FormatStyle::BS_Custom; + m_style.IndentCaseLabels = settings.indentSwitchLabels; #if LLVM_VERSION_MAJOR >= 11 @@ -196,11 +205,12 @@ void ClangFormatFile::fromCppCodeStyleSettings(const CppEditor::CppCodeStyleSett || settings.indentControlFlowRelativeToSwitchLabels; #endif - if (settings.alignAssignments) - m_style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment; - if (settings.extraPaddingForConditionsIfConfusingAlign) m_style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; + else if (settings.alignAssignments) + m_style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment; + else + m_style.BreakBeforeBinaryOperators = FormatStyle::BOS_None; m_style.DerivePointerAlignment = settings.bindStarToIdentifier || settings.bindStarToTypeName || settings.bindStarToLeftSpecifier From b28df28660eb301024af2a029b880707e9753f9e Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Thu, 11 May 2023 10:30:19 +0200 Subject: [PATCH 1002/1447] ClangFormat: Remove redundant KeepLineBreaks property Change-Id: I74250bde4a224d89b078f127da4e7b63454b03a6 Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/clangformat/clangformatbaseindenter.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index affabfec671..45e55495a56 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -56,9 +56,6 @@ void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, return; style.ColumnLimit = 0; -#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED - style.KeepLineBreaksForNonEmptyLines = true; -#endif } llvm::StringRef clearExtraNewline(llvm::StringRef text) From 430f07cf383954312c4ee2908b0c344b207cab9e Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 11 May 2023 16:30:19 +0200 Subject: [PATCH 1003/1447] GitHub Actions: Use universal for macOS only for releases For the regular checks we should be as fast as possible. Change-Id: If5b14f6ac48aebdefced137f74fc8ecdd72f741b Reviewed-by: Eike Ziller --- .github/workflows/build_cmake.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 8a623779f16..14f4a74751a 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -577,7 +577,11 @@ jobs: endif() if ("${{ runner.os }}" STREQUAL "macOS") - set(ENV{CMAKE_OSX_ARCHITECTURES} "x86_64;arm64") + if (${{github.ref}} MATCHES "tags/v(.*)") + set(ENV{CMAKE_OSX_ARCHITECTURES} "x86_64;arm64") + else() + set(ENV{CMAKE_OSX_ARCHITECTURES} "x86_64") + endif() endif() execute_process( From 5a73d07c72db6be79046ecd619871eeaa73d2973 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 10 May 2023 18:39:25 +0200 Subject: [PATCH 1004/1447] TaskTree: Prepare for de-utils-ization - part 1 Add internal implementation for Guard/GuardLocker. Change-Id: I9bcedee937221c0796143be2f943650a1bb56f38 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/tasktree.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index e27cd8f8bbd..3e88b0e8a1f 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -3,11 +3,32 @@ #include "tasktree.h" -#include "guard.h" #include "qtcassert.h" #include +class Guard +{ + Q_DISABLE_COPY(Guard) +public: + Guard() = default; + ~Guard() { QTC_CHECK(m_lockCount == 0); } + bool isLocked() const { return m_lockCount; } +private: + int m_lockCount = 0; + friend class GuardLocker; +}; + +class GuardLocker +{ + Q_DISABLE_COPY(GuardLocker) +public: + GuardLocker(Guard &guard) : m_guard(guard) { ++m_guard.m_lockCount; } + ~GuardLocker() { --m_guard.m_lockCount; } +private: + Guard &m_guard; +}; + namespace Utils { namespace Tasking { From 97a66067bb8c85cede9c51c64a271a16f3abd7e8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 10 May 2023 19:54:52 +0200 Subject: [PATCH 1005/1447] TaskTree: Prepare for de-utils-ization - part 2 Move TaskTree into Tasking namespace. Move Tasking namespace out of Utils namespace. Change-Id: Ib4c1d7f54f1808517e54768dfa27209c33517b61 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/async.cpp | 2 -- src/libs/utils/async.h | 2 +- src/libs/utils/barrier.cpp | 4 +-- src/libs/utils/barrier.h | 10 +++---- src/libs/utils/filestreamer.cpp | 4 +-- src/libs/utils/filestreamer.h | 2 +- src/libs/utils/tasktree.cpp | 26 +++++++--------- src/libs/utils/tasktree.h | 30 ++++++++----------- src/plugins/autotest/testcodeparser.h | 4 +-- src/plugins/autotest/testrunner.cpp | 2 +- src/plugins/autotest/testrunner.h | 4 +-- src/plugins/boot2qt/qdbmakedefaultappstep.cpp | 2 +- .../boot2qt/qdbstopapplicationstep.cpp | 2 +- .../clangtools/clangtoolruncontrol.cpp | 2 +- src/plugins/clangtools/clangtoolruncontrol.h | 4 +-- src/plugins/clangtools/clangtoolrunner.h | 8 ++--- .../clangtools/documentclangtoolrunner.cpp | 2 +- .../clangtools/documentclangtoolrunner.h | 4 +-- .../locator/externaltoolsfilter.cpp | 2 +- .../coreplugin/locator/ilocatorfilter.cpp | 13 ++++---- .../coreplugin/locator/ilocatorfilter.h | 10 +++---- .../coreplugin/locator/javascriptfilter.cpp | 5 ++-- src/plugins/coreplugin/locator/locator.h | 4 +-- .../locator/opendocumentsfilter.cpp | 5 ++-- .../progressmanager/taskprogress.cpp | 1 + .../coreplugin/progressmanager/taskprogress.h | 4 +-- src/plugins/cppeditor/cppprojectupdater.h | 4 +-- src/plugins/debugger/loadcoredialog.cpp | 3 +- .../diffeditor/diffeditorcontroller.cpp | 1 + src/plugins/diffeditor/diffeditorcontroller.h | 6 ++-- src/plugins/git/branchmodel.cpp | 2 +- src/plugins/git/branchview.cpp | 3 +- src/plugins/git/branchview.h | 5 ++-- src/plugins/git/gitclient.cpp | 6 ++-- src/plugins/git/gitclient.h | 3 +- src/plugins/help/helpindexfilter.cpp | 5 ++-- .../languageclient/clientrequesttask.h | 2 +- .../currentdocumentsymbolsrequest.h | 2 +- .../projectexplorer/abstractprocessstep.cpp | 3 +- .../projectexplorer/abstractprocessstep.h | 5 ++-- .../devicesupport/deviceusedportsgatherer.h | 2 +- .../devicesupport/filetransfer.h | 2 +- .../projectexplorer/devicesupport/idevice.h | 2 +- src/plugins/projectexplorer/extracompiler.cpp | 7 +++-- src/plugins/projectexplorer/extracompiler.h | 6 ++-- .../qnx/qnxdeployqtlibrariesdialog.cpp | 2 +- src/plugins/qnx/slog2inforunner.cpp | 4 +-- src/plugins/qnx/slog2inforunner.h | 4 +-- .../abstractremotelinuxdeploystep.cpp | 3 +- .../abstractremotelinuxdeploystep.h | 5 ++-- .../remotelinux/customcommanddeploystep.cpp | 2 +- .../remotelinux/genericdirectuploadstep.cpp | 4 +-- src/plugins/remotelinux/killappstep.cpp | 2 +- src/plugins/remotelinux/linuxdevicetester.cpp | 8 ++--- src/plugins/remotelinux/linuxdevicetester.h | 4 +-- src/plugins/remotelinux/rsyncdeploystep.cpp | 8 ++--- .../remotelinux/tarpackagedeploystep.cpp | 2 +- src/plugins/updateinfo/updateinfoplugin.cpp | 1 + .../vcsbase/vcsbasediffeditorcontroller.cpp | 9 +++--- .../vcsbase/vcsbasediffeditorcontroller.h | 4 +-- tests/auto/utils/tasktree/tst_tasktree.cpp | 2 +- tests/manual/tasktree/main.cpp | 3 +- tests/manual/tasktree/taskwidget.h | 8 ++--- 63 files changed, 142 insertions(+), 160 deletions(-) diff --git a/src/libs/utils/async.cpp b/src/libs/utils/async.cpp index 9295b50dc15..33487db73be 100644 --- a/src/libs/utils/async.cpp +++ b/src/libs/utils/async.cpp @@ -3,8 +3,6 @@ #include "async.h" -#include - namespace Utils { static int s_maxThreadCount = INT_MAX; diff --git a/src/libs/utils/async.h b/src/libs/utils/async.h index 07b38487495..59d91ba0ad5 100644 --- a/src/libs/utils/async.h +++ b/src/libs/utils/async.h @@ -211,4 +211,4 @@ public: } // namespace Utils -QTC_DECLARE_CUSTOM_TEMPLATE_TASK(AsyncTask, AsyncTaskAdapter); +QTC_DECLARE_CUSTOM_TEMPLATE_TASK(AsyncTask, Utils::AsyncTaskAdapter); diff --git a/src/libs/utils/barrier.cpp b/src/libs/utils/barrier.cpp index 76cc351088a..690391cb0f2 100644 --- a/src/libs/utils/barrier.cpp +++ b/src/libs/utils/barrier.cpp @@ -5,7 +5,7 @@ #include "qtcassert.h" -namespace Utils { +namespace Tasking { void Barrier::setLimit(int value) { @@ -44,4 +44,4 @@ void Barrier::stopWithResult(bool success) emit done(success); } -} // namespace Utils +} // namespace Tasking diff --git a/src/libs/utils/barrier.h b/src/libs/utils/barrier.h index 2af08dfdd11..9e5f8d50371 100644 --- a/src/libs/utils/barrier.h +++ b/src/libs/utils/barrier.h @@ -7,7 +7,7 @@ #include "tasktree.h" -namespace Utils { +namespace Tasking { class QTCREATOR_UTILS_EXPORT Barrier final : public QObject { @@ -41,11 +41,11 @@ public: void start() final { task()->start(); } }; -} // namespace Utils +} // namespace Tasking -QTC_DECLARE_CUSTOM_TASK(BarrierTask, Utils::BarrierTaskAdapter); +QTC_DECLARE_CUSTOM_TASK(BarrierTask, Tasking::BarrierTaskAdapter); -namespace Utils::Tasking { +namespace Tasking { template class SharedBarrier @@ -94,4 +94,4 @@ public: }) {} }; -} // namespace Utils::Tasking +} // namespace Tasking diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index a42e6320008..67a8a6cd92c 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -284,14 +284,14 @@ private: WriteBuffer *m_writeBuffer = nullptr; }; -class FileStreamReaderAdapter : public Utils::Tasking::TaskAdapter +class FileStreamReaderAdapter : public TaskAdapter { public: FileStreamReaderAdapter() { connect(task(), &FileStreamBase::done, this, &TaskInterface::done); } void start() override { task()->start(); } }; -class FileStreamWriterAdapter : public Utils::Tasking::TaskAdapter +class FileStreamWriterAdapter : public TaskAdapter { public: FileStreamWriterAdapter() { connect(task(), &FileStreamBase::done, this, &TaskInterface::done); } diff --git a/src/libs/utils/filestreamer.h b/src/libs/utils/filestreamer.h index 7d274b94447..3bbca65b8fe 100644 --- a/src/libs/utils/filestreamer.h +++ b/src/libs/utils/filestreamer.h @@ -49,7 +49,7 @@ private: class FileStreamerPrivate *d = nullptr; }; -class FileStreamerTaskAdapter : public Utils::Tasking::TaskAdapter +class FileStreamerTaskAdapter : public Tasking::TaskAdapter { public: FileStreamerTaskAdapter() { connect(task(), &FileStreamer::done, this, diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 3e88b0e8a1f..2c88546e6c4 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -7,6 +7,8 @@ #include +namespace Tasking { + class Guard { Q_DISABLE_COPY(Guard) @@ -29,9 +31,6 @@ private: Guard &m_guard; }; -namespace Utils { -namespace Tasking { - static TaskAction toTaskAction(bool success) { return success ? TaskAction::StopWithDone : TaskAction::StopWithError; @@ -191,10 +190,6 @@ void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler) m_taskHandler.m_errorHandler = handler; } -} // namespace Tasking - -using namespace Tasking; - class TaskTreePrivate; class TaskNode; @@ -686,8 +681,8 @@ void TaskNode::invokeEndHandler(bool success) } /*! - \class Utils::TaskTree - \inheaderfile utils/tasktree.h + \class TaskTree + \inheaderfile solutions/tasking/tasktree.h \inmodule QtCreator \ingroup mainclasses \brief The TaskTree class runs an async task tree structure defined in a @@ -706,7 +701,6 @@ void TaskNode::invokeEndHandler(bool success) or AsyncTask: \code - using namespace Utils; using namespace Tasking; const Group root { @@ -1285,7 +1279,7 @@ void TaskNode::invokeEndHandler(bool success) recipe described by the Group root element. As TaskTree is also an asynchronous task, it can be a part of another TaskTree. - To place a nested TaskTree inside another TaskTree, insert the Tasking::TaskTreeTask + To place a nested TaskTree inside another TaskTree, insert the TaskTreeTask element into other tree's Group element. TaskTree reports progress of completed tasks when running. The progress value @@ -1344,7 +1338,7 @@ void TaskNode::invokeEndHandler(bool success) asynchronous task: \code - class TimeoutAdapter : public Utils::Tasking::TaskAdapter + class TimeoutAdapter : public Tasking::TaskAdapter { public: TimeoutAdapter() { @@ -1372,7 +1366,7 @@ void TaskNode::invokeEndHandler(bool success) To make QTimer accessible inside TaskTree under the \e Timeout name, register it with QTC_DECLARE_CUSTOM_TASK(Timeout, TimeoutAdapter). Timeout - becomes a new task type inside Utils::Tasking namespace, using TimeoutAdapter. + becomes a new task type inside Tasking namespace, using TimeoutAdapter. The new task type is now registered, and you can use it in TaskTree: @@ -1416,7 +1410,7 @@ TaskTree::~TaskTree() delete d; } -void TaskTree::setupRoot(const Tasking::Group &root) +void TaskTree::setupRoot(const Group &root) { QTC_ASSERT(!isRunning(), qWarning("The TaskTree is already running, ignoring..."); return); QTC_ASSERT(!d->m_guard.isLocked(), qWarning("The setupRoot() is called from one of the" @@ -1455,7 +1449,7 @@ int TaskTree::progressValue() const return d->m_progressValue; } -void TaskTree::setupStorageHandler(const Tasking::TreeStorageBase &storage, +void TaskTree::setupStorageHandler(const TreeStorageBase &storage, StorageVoidHandler setupHandler, StorageVoidHandler doneHandler) { @@ -1487,4 +1481,4 @@ void TaskTreeTaskAdapter::start() task()->start(); } -} // namespace Utils +} // namespace Tasking diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index 46333c3dc86..b37749f9a42 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -9,15 +9,13 @@ #include #include -namespace Utils { +namespace Tasking { class ExecutionContextActivator; class TaskContainer; class TaskNode; class TaskTreePrivate; -namespace Tasking { - class QTCREATOR_UTILS_EXPORT TaskInterface : public QObject { Q_OBJECT @@ -354,8 +352,6 @@ private: }; }; -} // namespace Tasking - class TaskTreePrivate; class QTCREATOR_UTILS_EXPORT TaskTree final : public QObject @@ -364,10 +360,10 @@ class QTCREATOR_UTILS_EXPORT TaskTree final : public QObject public: TaskTree(); - TaskTree(const Tasking::Group &root); + TaskTree(const Group &root); ~TaskTree(); - void setupRoot(const Tasking::Group &root); + void setupRoot(const Group &root); void start(); void stop(); @@ -378,14 +374,12 @@ public: int progressValue() const; // all finished / skipped / stopped tasks, groups itself excluded template - void onStorageSetup(const Tasking::TreeStorage &storage, - StorageHandler &&handler) { + void onStorageSetup(const TreeStorage &storage, StorageHandler &&handler) { setupStorageHandler(storage, wrapHandler(std::forward(handler)), {}); } template - void onStorageDone(const Tasking::TreeStorage &storage, - StorageHandler &&handler) { + void onStorageDone(const TreeStorage &storage, StorageHandler &&handler) { setupStorageHandler(storage, {}, wrapHandler(std::forward(handler))); } @@ -398,7 +392,7 @@ signals: private: using StorageVoidHandler = std::function; - void setupStorageHandler(const Tasking::TreeStorageBase &storage, + void setupStorageHandler(const TreeStorageBase &storage, StorageVoidHandler setupHandler, StorageVoidHandler doneHandler); template @@ -413,22 +407,22 @@ private: TaskTreePrivate *d; }; -class QTCREATOR_UTILS_EXPORT TaskTreeTaskAdapter : public Tasking::TaskAdapter +class QTCREATOR_UTILS_EXPORT TaskTreeTaskAdapter : public TaskAdapter { public: TaskTreeTaskAdapter(); void start() final; }; -} // namespace Utils +} // namespace Tasking #define QTC_DECLARE_CUSTOM_TASK(CustomTaskName, TaskAdapterClass)\ -namespace Utils::Tasking { using CustomTaskName = CustomTask; } +namespace Tasking { using CustomTaskName = CustomTask; } #define QTC_DECLARE_CUSTOM_TEMPLATE_TASK(CustomTaskName, TaskAdapterClass)\ -namespace Utils::Tasking {\ +namespace Tasking {\ template \ using CustomTaskName = CustomTask>;\ -} // namespace Utils::Tasking +} // namespace Tasking -QTC_DECLARE_CUSTOM_TASK(TaskTreeTask, Utils::TaskTreeTaskAdapter); +QTC_DECLARE_CUSTOM_TASK(TaskTreeTask, TaskTreeTaskAdapter); diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index c86de52b943..d99c11ea570 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -18,7 +18,7 @@ class QThreadPool; QT_END_NAMESPACE namespace ProjectExplorer { class Project; } -namespace Utils { class TaskTree; } +namespace Tasking { class TaskTree; } namespace Autotest { namespace Internal { @@ -95,7 +95,7 @@ private: QTimer m_reparseTimer; QSet m_updateParsers; Utils::FutureSynchronizer m_futureSynchronizer; - std::unique_ptr m_taskTree; + std::unique_ptr m_taskTree; QHash m_qmlEditorRev; }; diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 7f54d41ba8f..631b76aca11 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -46,6 +46,7 @@ using namespace Core; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace Autotest { @@ -346,7 +347,6 @@ void TestRunner::runTestsHelper() std::unique_ptr m_outputReader; }; - using namespace Tasking; QList tasks{optional}; for (ITestConfiguration *config : m_selectedTests) { diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h index f361d7297a8..25c65f89851 100644 --- a/src/plugins/autotest/testrunner.h +++ b/src/plugins/autotest/testrunner.h @@ -19,7 +19,7 @@ class QLabel; QT_END_NAMESPACE namespace ProjectExplorer { class Project; } -namespace Utils { class TaskTree; } +namespace Tasking { class TaskTree; } namespace Autotest { @@ -70,7 +70,7 @@ private: bool postponeTestRunWithEmptyExecutable(ProjectExplorer::Project *project); void onBuildSystemUpdated(); - std::unique_ptr m_taskTree; + std::unique_ptr m_taskTree; QList m_selectedTests; TestRunMode m_runMode = TestRunMode::None; diff --git a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp index 4c18253fe17..ae5806deb95 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappstep.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappstep.cpp @@ -17,8 +17,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace Qdb::Internal { diff --git a/src/plugins/boot2qt/qdbstopapplicationstep.cpp b/src/plugins/boot2qt/qdbstopapplicationstep.cpp index 3707ef20bc1..5fef60268f9 100644 --- a/src/plugins/boot2qt/qdbstopapplicationstep.cpp +++ b/src/plugins/boot2qt/qdbstopapplicationstep.cpp @@ -16,8 +16,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace Qdb::Internal { diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index 2f455886253..4f1b39a27ec 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -29,6 +29,7 @@ using namespace CppEditor; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runcontrol", QtWarningMsg) @@ -183,7 +184,6 @@ void ClangToolRunWorker::start() m_filesAnalyzed.clear(); m_filesNotAnalyzed.clear(); - using namespace Tasking; QList tasks{ParallelLimit(qMax(1, m_runSettings.parallelJobs()))}; for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) { if (!m_diagnosticConfig.isEnabled(tool) diff --git a/src/plugins/clangtools/clangtoolruncontrol.h b/src/plugins/clangtools/clangtoolruncontrol.h index 19ad9189af4..e6204da4ff2 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.h +++ b/src/plugins/clangtools/clangtoolruncontrol.h @@ -15,7 +15,7 @@ #include #include -namespace Utils { class TaskTree; } +namespace Tasking { class TaskTree; } namespace ClangTools { namespace Internal { @@ -67,7 +67,7 @@ private: QString m_targetTriple; Utils::Id m_toolChainType; - std::unique_ptr m_taskTree; + std::unique_ptr m_taskTree; QSet m_projectFiles; QSet m_filesAnalyzed; QSet m_filesNotAnalyzed; diff --git a/src/plugins/clangtools/clangtoolrunner.h b/src/plugins/clangtools/clangtoolrunner.h index f581f7169aa..3a0f59f3417 100644 --- a/src/plugins/clangtools/clangtoolrunner.h +++ b/src/plugins/clangtools/clangtoolrunner.h @@ -10,7 +10,7 @@ #include -namespace Utils::Tasking { class TaskItem; } +namespace Tasking { class TaskItem; } namespace ClangTools { namespace Internal { @@ -50,9 +50,9 @@ struct AnalyzeOutputData using AnalyzeSetupHandler = std::function; using AnalyzeOutputHandler = std::function; -Utils::Tasking::TaskItem clangToolTask(const AnalyzeInputData &input, - const AnalyzeSetupHandler &setupHandler, - const AnalyzeOutputHandler &outputHandler); +Tasking::TaskItem clangToolTask(const AnalyzeInputData &input, + const AnalyzeSetupHandler &setupHandler, + const AnalyzeOutputHandler &outputHandler); } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index cc1016fb420..7077786d32f 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -35,6 +35,7 @@ static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.cftr", QtWarningMsg) using namespace Core; using namespace CppEditor; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace ClangTools { @@ -188,7 +189,6 @@ void DocumentClangToolRunner::run() vfso().update(); const ClangDiagnosticConfig config = diagnosticConfig(runSettings.diagnosticConfigId()); const Environment env = projectBuildEnvironment(project); - using namespace Tasking; QList tasks{parallel}; const auto addClangTool = [this, &runSettings, &config, &env, &tasks](ClangToolType tool) { if (!toolEnabled(tool, config, runSettings)) diff --git a/src/plugins/clangtools/documentclangtoolrunner.h b/src/plugins/clangtools/documentclangtoolrunner.h index 94111abb37a..e80a9632dce 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.h +++ b/src/plugins/clangtools/documentclangtoolrunner.h @@ -14,8 +14,8 @@ #include namespace Core { class IDocument; } +namespace Tasking { class TaskTree; } namespace TextEditor { class TextEditorWidget; } -namespace Utils { class TaskTree; } namespace ClangTools { namespace Internal { @@ -51,7 +51,7 @@ private: QList> m_editorsWithMarkers; SuppressedDiagnosticsList m_suppressed; Utils::FilePath m_lastProjectDirectory; - std::unique_ptr m_taskTree; + std::unique_ptr m_taskTree; }; } // namespace Internal diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index 308a378995f..36fc78cba9b 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -27,7 +27,7 @@ ExternalToolsFilter::ExternalToolsFilter() LocatorMatcherTasks ExternalToolsFilter::matchers() { - using namespace Utils::Tasking; + using namespace Tasking; TreeStorage storage; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 5d940487f0e..b9350e5baa2 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -25,6 +25,7 @@ #include +using namespace Tasking; using namespace Utils; /*! @@ -243,7 +244,7 @@ private: // When all the results are reported (the expected number of reports is set with setFilterCount()), // the ResultsCollector finishes. The intermediate results are reported with // serialOutputDataReady() signal. -// The object of ResultsCollector is registered in Tasking namespace with Tasking::Collector name. +// The object of ResultsCollector is registered in Tasking namespace under the Collector name. class ResultsCollector : public QObject { Q_OBJECT @@ -316,7 +317,7 @@ void ResultsCollector::start() m_watcher->setFuture(Utils::asyncRun(deduplicate, m_deduplicator)); } -class ResultsCollectorAdapter : public Tasking::TaskAdapter +class ResultsCollectorAdapter : public TaskAdapter { public: ResultsCollectorAdapter() { @@ -427,8 +428,6 @@ void LocatorMatcher::start() d->m_output = {}; d->m_taskTree.reset(new TaskTree); - using namespace Tasking; - struct CollectorStorage { ResultsCollector *m_collector = nullptr; @@ -613,7 +612,7 @@ void ILocatorFilter::prepareSearch(const QString &entry) /*! Sets the refresh recipe for refreshing cached data. */ -void ILocatorFilter::setRefreshRecipe(const std::optional &recipe) +void ILocatorFilter::setRefreshRecipe(const std::optional &recipe) { m_refreshRecipe = recipe; } @@ -622,7 +621,7 @@ void ILocatorFilter::setRefreshRecipe(const std::optional &re Returns the refresh recipe for refreshing cached data. By default, the locator filter has no recipe set, so that it won't be refreshed. */ -std::optional ILocatorFilter::refreshRecipe() const +std::optional ILocatorFilter::refreshRecipe() const { return m_refreshRecipe; } @@ -1524,8 +1523,6 @@ static void filter(QPromise &promise, const LocatorStor */ LocatorMatcherTask LocatorFileCache::matcher() const { - using namespace Tasking; - TreeStorage storage; std::weak_ptr weak = d; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 9ded00c1d0a..b7b8618ea96 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -139,10 +139,10 @@ class CORE_EXPORT LocatorMatcherTask final public: // The main task. Initial data (searchTerm) should be taken from storage.input(). // Results reporting is done via the storage.reportOutput(). - Utils::Tasking::TaskItem task = Utils::Tasking::Group{}; + Tasking::TaskItem task = Tasking::Group{}; // When constructing the task, don't place the storage inside the task above. - Utils::Tasking::TreeStorage storage; + Tasking::TreeStorage storage; }; using LocatorMatcherTasks = QList; @@ -275,8 +275,8 @@ protected: virtual void saveState(QJsonObject &object) const; virtual void restoreState(const QJsonObject &object); - void setRefreshRecipe(const std::optional &recipe); - std::optional refreshRecipe() const; + void setRefreshRecipe(const std::optional &recipe); + std::optional refreshRecipe() const; static bool isOldSetting(const QByteArray &state); @@ -295,7 +295,7 @@ private: QString m_description; QString m_defaultShortcut; std::optional m_defaultSearchText; - std::optional m_refreshRecipe; + std::optional m_refreshRecipe; QKeySequence m_defaultKeySequence; bool m_defaultIncludedByDefault = false; bool m_includedByDefault = m_defaultIncludedByDefault; diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 094d13f1f2c..9fd66fa0ddb 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -21,6 +21,7 @@ using namespace Core; using namespace Core::Internal; +using namespace Tasking; using namespace Utils; using namespace std::chrono_literals; @@ -341,7 +342,7 @@ private: JavaScriptOutput m_output; }; -class JavaScriptRequestAdapter : public Tasking::TaskAdapter +class JavaScriptRequestAdapter : public TaskAdapter { public: JavaScriptRequestAdapter() { connect(task(), &JavaScriptRequest::done, @@ -366,8 +367,6 @@ JavaScriptFilter::~JavaScriptFilter() = default; LocatorMatcherTasks JavaScriptFilter::matchers() { - using namespace Tasking; - TreeStorage storage; if (!m_javaScriptEngine) m_javaScriptEngine.reset(new JavaScriptEngine); diff --git a/src/plugins/coreplugin/locator/locator.h b/src/plugins/coreplugin/locator/locator.h index edf978e6973..3e73054153c 100644 --- a/src/plugins/coreplugin/locator/locator.h +++ b/src/plugins/coreplugin/locator/locator.h @@ -13,7 +13,7 @@ #include -namespace Utils { class TaskTree; } +namespace Tasking { class TaskTree; } namespace Core { namespace Internal { @@ -74,7 +74,7 @@ private: QList m_customFilters; QMap m_filterActionMap; QTimer m_refreshTimer; - std::unique_ptr m_taskTree; + std::unique_ptr m_taskTree; QList m_refreshingFilters; }; diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 6b6b3139ad1..64c68efa28c 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -16,6 +16,7 @@ #include #include +using namespace Tasking; using namespace Utils; namespace Core::Internal { @@ -29,7 +30,7 @@ OpenDocumentsFilter::OpenDocumentsFilter() setPriority(High); setDefaultIncludedByDefault(true); // TODO: Remove the refresh recipe - setRefreshRecipe(Tasking::Sync([this] { refreshInternally(); })); + setRefreshRecipe(Sync([this] { refreshInternally(); })); connect(DocumentModel::model(), &QAbstractItemModel::dataChanged, this, &OpenDocumentsFilter::slotDataChanged); @@ -75,8 +76,6 @@ static void matchEditors(QPromise &promise, const LocatorStorage &storage, LocatorMatcherTasks OpenDocumentsFilter::matchers() { - using namespace Tasking; - TreeStorage storage; const auto onSetup = [storage](Async &async) { diff --git a/src/plugins/coreplugin/progressmanager/taskprogress.cpp b/src/plugins/coreplugin/progressmanager/taskprogress.cpp index 6c7ee0bbb79..7e59a9b146a 100644 --- a/src/plugins/coreplugin/progressmanager/taskprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/taskprogress.cpp @@ -14,6 +14,7 @@ #include using namespace Utils; +using namespace Tasking; namespace Core { diff --git a/src/plugins/coreplugin/progressmanager/taskprogress.h b/src/plugins/coreplugin/progressmanager/taskprogress.h index e15967fa2b8..d82fc433d5e 100644 --- a/src/plugins/coreplugin/progressmanager/taskprogress.h +++ b/src/plugins/coreplugin/progressmanager/taskprogress.h @@ -9,7 +9,7 @@ #include -namespace Utils { class TaskTree; } +namespace Tasking { class TaskTree; } namespace Core { @@ -20,7 +20,7 @@ class CORE_EXPORT TaskProgress : public QObject Q_OBJECT public: - TaskProgress(Utils::TaskTree *taskTree); // Makes TaskProgress a child of task tree + TaskProgress(Tasking::TaskTree *taskTree); // Makes TaskProgress a child of task tree ~TaskProgress() override; void setId(Utils::Id id); diff --git a/src/plugins/cppeditor/cppprojectupdater.h b/src/plugins/cppeditor/cppprojectupdater.h index 50910e83207..a8cebc5b1e0 100644 --- a/src/plugins/cppeditor/cppprojectupdater.h +++ b/src/plugins/cppeditor/cppprojectupdater.h @@ -10,7 +10,7 @@ #include namespace ProjectExplorer { class ExtraCompiler; } -namespace Utils { class TaskTree; } +namespace Tasking { class TaskTree; } namespace CppEditor { @@ -44,7 +44,7 @@ public: private: Utils::FutureSynchronizer m_futureSynchronizer; - std::unique_ptr m_taskTree; + std::unique_ptr m_taskTree; }; } // namespace CppEditor diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index 6095b4470d0..a196fb43d14 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -34,6 +34,7 @@ using namespace Core; using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace Debugger::Internal { @@ -217,8 +218,6 @@ void AttachCoreDialog::accepted() const DebuggerItem *debuggerItem = Debugger::DebuggerKitAspect::debugger(kit()); const FilePath debuggerCommand = debuggerItem->command(); - using namespace Tasking; - const auto copyFile = [debuggerCommand](const FilePath &srcPath) -> expected_str { if (!srcPath.isSameDevice(debuggerCommand)) { const expected_str tmpPath = debuggerCommand.tmpDir(); diff --git a/src/plugins/diffeditor/diffeditorcontroller.cpp b/src/plugins/diffeditor/diffeditorcontroller.cpp index dcce09f0b2b..1ab7bfccb2d 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorcontroller.cpp @@ -12,6 +12,7 @@ #include using namespace Core; +using namespace Tasking; using namespace Utils; namespace DiffEditor { diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index f52f2af1a0a..7f990ecb2fd 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -61,7 +61,7 @@ signals: protected: // Core functions: - void setReloadRecipe(const Utils::Tasking::Group &recipe) { m_reloadRecipe = recipe; } + void setReloadRecipe(const Tasking::Group &recipe) { m_reloadRecipe = recipe; } void setDiffFiles(const QList &diffFileList); // Optional: void setDisplayName(const QString &name) { m_displayName = name; } @@ -74,8 +74,8 @@ private: Internal::DiffEditorDocument *const m_document; QString m_displayName; - std::unique_ptr m_taskTree; - Utils::Tasking::Group m_reloadRecipe; + std::unique_ptr m_taskTree; + Tasking::Group m_reloadRecipe; }; Q_DECLARE_OPERATORS_FOR_FLAGS(DiffEditorController::PatchOptions) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index aeeea39fff2..859f177845c 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -20,6 +20,7 @@ #include +using namespace Tasking; using namespace Utils; using namespace VcsBase; @@ -413,7 +414,6 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) return; } - using namespace Tasking; const ProcessTask topRevisionProc = d->client->topRevision(workingDirectory, [=](const QString &ref, const QDateTime &dateTime) { diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index 5d437968c92..3915d20ab80 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -37,6 +37,7 @@ #include using namespace Core; +using namespace Tasking; using namespace Utils; using namespace VcsBase; @@ -527,8 +528,6 @@ bool BranchView::reset(const QByteArray &resetType) TaskTree *BranchView::onFastForwardMerge(const std::function &callback) { - using namespace Tasking; - const QModelIndex selected = selectedIndex(); QTC_CHECK(selected != m_model->currentBranch()); diff --git a/src/plugins/git/branchview.h b/src/plugins/git/branchview.h index c1ac77c82be..d272a5e2194 100644 --- a/src/plugins/git/branchview.h +++ b/src/plugins/git/branchview.h @@ -17,10 +17,11 @@ class QToolButton; class QTreeView; QT_END_NAMESPACE; +namespace Tasking { class TaskTree; } + namespace Utils { class ElidingLabel; class NavigationTreeView; -class TaskTree; } // Utils namespace Git::Internal { @@ -55,7 +56,7 @@ private: bool remove(); bool rename(); bool reset(const QByteArray &resetType); - Utils::TaskTree *onFastForwardMerge(const std::function &callback); + Tasking::TaskTree *onFastForwardMerge(const std::function &callback); bool merge(bool allowFastForward); void rebase(); bool cherryPick(); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index fad0d19afb6..3bd505f25b5 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -76,6 +76,7 @@ const char showFormatC[] = using namespace Core; using namespace DiffEditor; +using namespace Tasking; using namespace Utils; using namespace VcsBase; @@ -1730,12 +1731,9 @@ bool GitClient::synchronousRevParseCmd(const FilePath &workingDirectory, const Q } // Retrieve head revision -Utils::Tasking::ProcessTask GitClient::topRevision( - const FilePath &workingDirectory, +ProcessTask GitClient::topRevision(const FilePath &workingDirectory, const std::function &callback) { - using namespace Tasking; - const auto setupProcess = [=](Process &process) { setupCommand(process, workingDirectory, {"show", "-s", "--pretty=format:%H:%ct", HEAD}); }; diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index a52276f381b..fb3a06b3556 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -242,8 +242,7 @@ public: QString synchronousTopic(const Utils::FilePath &workingDirectory) const; bool synchronousRevParseCmd(const Utils::FilePath &workingDirectory, const QString &ref, QString *output, QString *errorMessage = nullptr) const; - Utils::Tasking::ProcessTask topRevision( - const Utils::FilePath &workingDirectory, + Tasking::ProcessTask topRevision(const Utils::FilePath &workingDirectory, const std::function &callback); bool isRemoteCommit(const Utils::FilePath &workingDirectory, const QString &commit); diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 1a8fcd42d72..c32f02c6c16 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -21,6 +21,7 @@ using namespace Core; using namespace Help; using namespace Help::Internal; +using namespace Tasking; using namespace Utils; HelpIndexFilter::HelpIndexFilter() @@ -30,7 +31,7 @@ HelpIndexFilter::HelpIndexFilter() setDescription(Tr::tr("Locates help topics, for example in the Qt documentation.")); setDefaultIncludedByDefault(false); setDefaultShortcutString("?"); - setRefreshRecipe(Utils::Tasking::Sync([this] { invalidateCache(); })); + setRefreshRecipe(Sync([this] { invalidateCache(); })); m_icon = Utils::Icons::BOOKMARK.icon(); connect(Core::HelpManager::Signals::instance(), &Core::HelpManager::Signals::setupFinished, @@ -83,8 +84,6 @@ static void matches(QPromise &promise, const LocatorStorage &storag LocatorMatcherTasks HelpIndexFilter::matchers() { - using namespace Tasking; - TreeStorage storage; const auto onSetup = [this, storage](Async &async) { diff --git a/src/plugins/languageclient/clientrequesttask.h b/src/plugins/languageclient/clientrequesttask.h index 9f92bc9047b..6700902ff11 100644 --- a/src/plugins/languageclient/clientrequesttask.h +++ b/src/plugins/languageclient/clientrequesttask.h @@ -67,7 +67,7 @@ public: }; class LANGUAGECLIENT_EXPORT WorkspaceSymbolRequestTaskAdapter - : public Utils::Tasking::TaskAdapter + : public Tasking::TaskAdapter { public: WorkspaceSymbolRequestTaskAdapter(); diff --git a/src/plugins/languageclient/currentdocumentsymbolsrequest.h b/src/plugins/languageclient/currentdocumentsymbolsrequest.h index f0e3fdccdac..6dd8e35a9b4 100644 --- a/src/plugins/languageclient/currentdocumentsymbolsrequest.h +++ b/src/plugins/languageclient/currentdocumentsymbolsrequest.h @@ -39,7 +39,7 @@ private: }; class LANGUAGECLIENT_EXPORT CurrentDocumentSymbolsRequestTaskAdapter - : public Utils::Tasking::TaskAdapter + : public Tasking::TaskAdapter { public: CurrentDocumentSymbolsRequestTaskAdapter(); diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index ddc2a8551a2..806d9159f95 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -20,6 +20,7 @@ #include #include +using namespace Tasking; using namespace Utils; namespace ProjectExplorer { @@ -240,7 +241,7 @@ void AbstractProcessStep::setupProcess(Process *process) }); } -void AbstractProcessStep::runTaskTree(const Tasking::Group &recipe) +void AbstractProcessStep::runTaskTree(const Group &recipe) { setupStreams(); diff --git a/src/plugins/projectexplorer/abstractprocessstep.h b/src/plugins/projectexplorer/abstractprocessstep.h index d8050b66a89..fc1ed131357 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.h +++ b/src/plugins/projectexplorer/abstractprocessstep.h @@ -11,9 +11,10 @@ namespace Utils { class CommandLine; enum class ProcessResult; class Process; -namespace Tasking { class Group; } } +namespace Tasking { class Group; } + namespace ProjectExplorer { class ProcessParameters; @@ -52,7 +53,7 @@ protected: bool checkWorkingDirectory(); void setupProcess(Utils::Process *process); - void runTaskTree(const Utils::Tasking::Group &recipe); + void runTaskTree(const Tasking::Group &recipe); ProcessParameters *displayedParameters() const; private: diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h index 3519c7d22fe..56408e9aef1 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h @@ -44,7 +44,7 @@ private: }; class PROJECTEXPLORER_EXPORT DeviceUsedPortsGathererAdapter - : public Utils::Tasking::TaskAdapter + : public Tasking::TaskAdapter { public: DeviceUsedPortsGathererAdapter(); diff --git a/src/plugins/projectexplorer/devicesupport/filetransfer.h b/src/plugins/projectexplorer/devicesupport/filetransfer.h index bc02dbc7829..10c1a87c030 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransfer.h +++ b/src/plugins/projectexplorer/devicesupport/filetransfer.h @@ -46,7 +46,7 @@ private: FileTransferPrivate *d; }; -class PROJECTEXPLORER_EXPORT FileTransferTaskAdapter : public Utils::Tasking::TaskAdapter +class PROJECTEXPLORER_EXPORT FileTransferTaskAdapter : public Tasking::TaskAdapter { public: FileTransferTaskAdapter(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 04c1facf41e..719aa916543 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -276,7 +276,7 @@ private: QString m_errorString; }; -class PROJECTEXPLORER_EXPORT KillerAdapter : public Utils::Tasking::TaskAdapter +class PROJECTEXPLORER_EXPORT KillerAdapter : public Tasking::TaskAdapter { public: KillerAdapter(); diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index 8830aadf856..67bb4a63fc3 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -24,6 +24,7 @@ #include using namespace Core; +using namespace Tasking; using namespace Utils; namespace ProjectExplorer { @@ -136,7 +137,7 @@ QThreadPool *ExtraCompiler::extraCompilerThreadPool() return s_extraCompilerThreadPool(); } -Tasking::TaskItem ExtraCompiler::compileFileItem() +TaskItem ExtraCompiler::compileFileItem() { return taskItemImpl(fromFileProvider()); } @@ -325,7 +326,7 @@ ProcessExtraCompiler::ProcessExtraCompiler(const Project *project, const FilePat ExtraCompiler(project, source, targets, parent) { } -Tasking::TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &provider) +TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &provider) { const auto setupTask = [=](Async &async) { async.setThreadPool(extraCompilerThreadPool()); @@ -344,7 +345,7 @@ Tasking::TaskItem ProcessExtraCompiler::taskItemImpl(const ContentProvider &prov setContent(it.key(), it.value()); updateCompileTime(); }; - return Tasking::AsyncTask(setupTask, taskDone); + return AsyncTask(setupTask, taskDone); } FilePath ProcessExtraCompiler::workingDirectory() const diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h index 323fbb139d3..bcc0ebee905 100644 --- a/src/plugins/projectexplorer/extracompiler.h +++ b/src/plugins/projectexplorer/extracompiler.h @@ -49,7 +49,7 @@ public: Utils::FilePaths targets() const; void forEachTarget(std::function func) const; - Utils::Tasking::TaskItem compileFileItem(); + Tasking::TaskItem compileFileItem(); void compileFile(); bool isDirty() const; void block(); @@ -75,7 +75,7 @@ private: void compileContent(const QByteArray &content); void compileImpl(const ContentProvider &provider); void compileIfDirty(); - virtual Utils::Tasking::TaskItem taskItemImpl(const ContentProvider &provider) = 0; + virtual Tasking::TaskItem taskItemImpl(const ContentProvider &provider) = 0; const std::unique_ptr d; }; @@ -101,7 +101,7 @@ protected: virtual Tasks parseIssues(const QByteArray &stdErr); private: - Utils::Tasking::TaskItem taskItemImpl(const ContentProvider &provider) final; + Tasking::TaskItem taskItemImpl(const ContentProvider &provider) final; void runInThread(QPromise &promise, const Utils::FilePath &cmd, const Utils::FilePath &workDir, const QStringList &args, const ContentProvider &provider, diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index e06303cffaa..2a7f56d2f34 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -31,8 +31,8 @@ using namespace ProjectExplorer; using namespace QtSupport; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace Qnx::Internal { diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index a6ceaab4ccb..77700804b21 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -31,7 +31,7 @@ Slog2InfoRunner::Slog2InfoRunner(RunControl *runControl) void Slog2InfoRunner::start() { - using namespace Utils::Tasking; + using namespace Tasking; QTC_CHECK(!m_taskTree); const auto testStartHandler = [this](Process &process) { @@ -68,7 +68,7 @@ void Slog2InfoRunner::start() StdErrFormat); }; - const Tasking::Group root { + const Group root { ProcessTask(testStartHandler, testDoneHandler, testErrorHandler), ProcessTask(launchTimeStartHandler, launchTimeDoneHandler), ProcessTask(logStartHandler, {}, logErrorHandler) diff --git a/src/plugins/qnx/slog2inforunner.h b/src/plugins/qnx/slog2inforunner.h index e89b80b6975..83d8d293336 100644 --- a/src/plugins/qnx/slog2inforunner.h +++ b/src/plugins/qnx/slog2inforunner.h @@ -7,7 +7,7 @@ #include -namespace Utils { class TaskTree; } +namespace Tasking { class TaskTree; } namespace Qnx::Internal { @@ -33,7 +33,7 @@ private: bool m_currentLogs = false; QString m_remainingData; - std::unique_ptr m_taskTree; + std::unique_ptr m_taskTree; }; } // Qnx::Internal diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp index 60982c32872..ae94e6574a7 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp @@ -19,6 +19,7 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace RemoteLinux { @@ -204,7 +205,7 @@ bool AbstractRemoteLinuxDeployStep::isDeploymentNecessary() const return true; } -Tasking::Group AbstractRemoteLinuxDeployStep::deployRecipe() +Group AbstractRemoteLinuxDeployStep::deployRecipe() { return {}; } diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h index 5b4eb8bbe92..b0af97f5d2b 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.h +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.h @@ -11,8 +11,7 @@ #include namespace ProjectExplorer { class DeployableFile; } - -namespace Utils::Tasking { class Group; } +namespace Tasking { class Group; } namespace RemoteLinux { @@ -71,7 +70,7 @@ protected: private: virtual bool isDeploymentNecessary() const; - virtual Utils::Tasking::Group deployRecipe(); + virtual Tasking::Group deployRecipe(); Internal::AbstractRemoteLinuxDeployStepPrivate *d; }; diff --git a/src/plugins/remotelinux/customcommanddeploystep.cpp b/src/plugins/remotelinux/customcommanddeploystep.cpp index 670390eeb19..32076d34f27 100644 --- a/src/plugins/remotelinux/customcommanddeploystep.cpp +++ b/src/plugins/remotelinux/customcommanddeploystep.cpp @@ -14,8 +14,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace RemoteLinux::Internal { diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index a8f2200cf80..8a7c1e4c029 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -22,8 +22,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace RemoteLinux::Internal { @@ -68,7 +68,7 @@ public: } bool isDeploymentNecessary() const final; - Utils::Tasking::Group deployRecipe() final; + Group deployRecipe() final; QDateTime timestampFromStat(const DeployableFile &file, Process *statProc); diff --git a/src/plugins/remotelinux/killappstep.cpp b/src/plugins/remotelinux/killappstep.cpp index d82844fa157..df8d701dcfc 100644 --- a/src/plugins/remotelinux/killappstep.cpp +++ b/src/plugins/remotelinux/killappstep.cpp @@ -15,8 +15,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace RemoteLinux::Internal { diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index e9338554fda..c32cabfee10 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -16,8 +16,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace RemoteLinux { namespace Internal { @@ -130,7 +130,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::unameTask() const else emit q->errorMessage(Tr::tr("uname failed.") + '\n'); }; - return Tasking::Group { + return Group { optional, ProcessTask(setup, done, error) }; @@ -219,7 +219,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod method TaskItem GenericLinuxDeviceTesterPrivate::transferTasks() const { TreeStorage storage; - return Tasking::Group { + return Group { continueOnDone, Storage(storage), transferTask(FileTransferMethod::GenericCopy, storage), @@ -260,7 +260,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::commandTasks() const })); for (const QString &commandName : commandsToTest()) tasks.append(commandTask(commandName)); - return Tasking::Group {tasks}; + return Group {tasks}; } } // namespace Internal diff --git a/src/plugins/remotelinux/linuxdevicetester.h b/src/plugins/remotelinux/linuxdevicetester.h index 5c1210f9a14..3fda1ecb3a2 100644 --- a/src/plugins/remotelinux/linuxdevicetester.h +++ b/src/plugins/remotelinux/linuxdevicetester.h @@ -7,7 +7,7 @@ #include -namespace Utils::Tasking { class TaskItem; } +namespace Tasking { class TaskItem; } namespace RemoteLinux { @@ -22,7 +22,7 @@ public: ~GenericLinuxDeviceTester() override; void setExtraCommandsToTest(const QStringList &extraCommands); - void setExtraTests(const QList &extraTests); + void setExtraTests(const QList &extraTests); void testDevice(const ProjectExplorer::IDevice::Ptr &deviceConfiguration) override; void stopTest() override; diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index 38dcc4dea11..a5436c2bbc6 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -21,8 +21,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace RemoteLinux { @@ -35,9 +35,9 @@ public: private: bool isDeploymentNecessary() const final; - Tasking::Group deployRecipe() final; - Tasking::TaskItem mkdirTask(); - Tasking::TaskItem transferTask(); + Group deployRecipe() final; + TaskItem mkdirTask(); + TaskItem transferTask(); mutable FilesToTransfer m_files; bool m_ignoreMissingFiles = false; diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index cdd4cd71671..6b50ca4dced 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -16,8 +16,8 @@ #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; -using namespace Utils::Tasking; namespace RemoteLinux::Internal { diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index d6ec407f63b..749cbbbec64 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -43,6 +43,7 @@ const char InstallQtUpdates[] = "UpdateInfo.InstallQtUpdates"; const char M_MAINTENANCE_TOOL[] = "QtCreator.Menu.Tools.MaintenanceTool"; using namespace Core; +using namespace Tasking; using namespace Utils; namespace UpdateInfo { diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp index 715b0855599..696e96b2916 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.cpp @@ -12,6 +12,7 @@ #include using namespace DiffEditor; +using namespace Tasking; using namespace Utils; namespace VcsBase { @@ -24,7 +25,7 @@ public: VcsBaseDiffEditorController *q; Environment m_processEnvironment; FilePath m_vcsBinary; - const Tasking::TreeStorage m_inputStorage; + const TreeStorage m_inputStorage; }; ///////////////////// @@ -39,15 +40,13 @@ VcsBaseDiffEditorController::~VcsBaseDiffEditorController() delete d; } -Tasking::TreeStorage VcsBaseDiffEditorController::inputStorage() const +TreeStorage VcsBaseDiffEditorController::inputStorage() const { return d->m_inputStorage; } -Tasking::TaskItem VcsBaseDiffEditorController::postProcessTask() +TaskItem VcsBaseDiffEditorController::postProcessTask() { - using namespace Tasking; - const auto setupDiffProcessor = [this](Async> &async) { const QString *storage = inputStorage().activeStorage(); QTC_ASSERT(storage, qWarning("Using postProcessTask() requires putting inputStorage() " diff --git a/src/plugins/vcsbase/vcsbasediffeditorcontroller.h b/src/plugins/vcsbase/vcsbasediffeditorcontroller.h index 22d651fe720..63976bc26cb 100644 --- a/src/plugins/vcsbase/vcsbasediffeditorcontroller.h +++ b/src/plugins/vcsbase/vcsbasediffeditorcontroller.h @@ -28,8 +28,8 @@ public: void setVcsBinary(const Utils::FilePath &path); protected: - Utils::Tasking::TreeStorage inputStorage() const; - Utils::Tasking::TaskItem postProcessTask(); + Tasking::TreeStorage inputStorage() const; + Tasking::TaskItem postProcessTask(); void setupCommand(Utils::Process &process, const QStringList &args) const; diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/utils/tasktree/tst_tasktree.cpp index ea60db9745d..e897cd36fc4 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/utils/tasktree/tst_tasktree.cpp @@ -11,7 +11,7 @@ using namespace std::literals::chrono_literals; using namespace Utils; -using namespace Utils::Tasking; +using namespace Tasking; using TestTask = Async; using Test = AsyncTask; diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index 1694ce2197a..6b6db61adeb 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -146,11 +146,12 @@ int main(int argc, char *argv[]) // Task tree creator (takes configuation from GUI) + using namespace Tasking; + std::unique_ptr taskTree; FutureSynchronizer synchronizer; auto treeRoot = [&] { - using namespace Tasking; auto taskItem = [sync = &synchronizer, synchronizerCheckBox](TaskWidget *widget) { const auto setupHandler = [=](Async &task) { diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasktree/taskwidget.h index 0e7828ac84b..ae8e7b6788c 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasktree/taskwidget.h @@ -60,10 +60,10 @@ public: GroupWidget(); void setExecuteMode(ExecuteMode mode); - Utils::Tasking::ParallelLimit executeMode() const; + Tasking::ParallelLimit executeMode() const; - void setWorkflowPolicy(Utils::Tasking::WorkflowPolicy policy); - Utils::Tasking::WorkflowPolicy workflowPolicy() const; + void setWorkflowPolicy(Tasking::WorkflowPolicy policy); + Tasking::WorkflowPolicy workflowPolicy() const; private: void updateExecuteMode(); @@ -73,7 +73,7 @@ private: QComboBox *m_workflowCombo = nullptr; ExecuteMode m_executeMode = ExecuteMode::Sequential; - Utils::Tasking::WorkflowPolicy m_workflowPolicy = Utils::Tasking::WorkflowPolicy::StopOnError; + Tasking::WorkflowPolicy m_workflowPolicy = Tasking::WorkflowPolicy::StopOnError; }; class TaskGroup From fe470d60a2c9a4ccae07a4acd87d8d1a9fb696bb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 10 May 2023 20:20:21 +0200 Subject: [PATCH 1006/1447] TaskTree: Prepare for de-utils-ization - part 3 Rename QTC_* macros into TASKING_*. Change-Id: I809ebf678f20df612a3211c38ebbfe6d4bf6492d Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/utils/async.h | 2 +- src/libs/utils/barrier.h | 2 +- src/libs/utils/filestreamer.cpp | 4 ++-- src/libs/utils/filestreamer.h | 2 +- src/libs/utils/process.h | 2 +- src/libs/utils/tasktree.h | 6 +++--- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 2 +- src/plugins/coreplugin/locator/javascriptfilter.cpp | 2 +- src/plugins/languageclient/clientrequesttask.h | 2 +- src/plugins/languageclient/currentdocumentsymbolsrequest.h | 2 +- .../projectexplorer/devicesupport/deviceusedportsgatherer.h | 2 +- src/plugins/projectexplorer/devicesupport/filetransfer.h | 4 ++-- src/plugins/projectexplorer/devicesupport/idevice.h | 2 +- 13 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libs/utils/async.h b/src/libs/utils/async.h index 59d91ba0ad5..b08ceaf3dc2 100644 --- a/src/libs/utils/async.h +++ b/src/libs/utils/async.h @@ -211,4 +211,4 @@ public: } // namespace Utils -QTC_DECLARE_CUSTOM_TEMPLATE_TASK(AsyncTask, Utils::AsyncTaskAdapter); +TASKING_DECLARE_TEMPLATE_TASK(AsyncTask, Utils::AsyncTaskAdapter); diff --git a/src/libs/utils/barrier.h b/src/libs/utils/barrier.h index 9e5f8d50371..fe2d7bbe62c 100644 --- a/src/libs/utils/barrier.h +++ b/src/libs/utils/barrier.h @@ -43,7 +43,7 @@ public: } // namespace Tasking -QTC_DECLARE_CUSTOM_TASK(BarrierTask, Tasking::BarrierTaskAdapter); +TASKING_DECLARE_TASK(BarrierTask, Tasking::BarrierTaskAdapter); namespace Tasking { diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 67a8a6cd92c..2d4d4909401 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -300,8 +300,8 @@ public: } // namespace Utils -QTC_DECLARE_CUSTOM_TASK(Reader, Utils::FileStreamReaderAdapter); -QTC_DECLARE_CUSTOM_TASK(Writer, Utils::FileStreamWriterAdapter); +TASKING_DECLARE_TASK(Reader, Utils::FileStreamReaderAdapter); +TASKING_DECLARE_TASK(Writer, Utils::FileStreamWriterAdapter); namespace Utils { diff --git a/src/libs/utils/filestreamer.h b/src/libs/utils/filestreamer.h index 3bbca65b8fe..8e46d7d1646 100644 --- a/src/libs/utils/filestreamer.h +++ b/src/libs/utils/filestreamer.h @@ -59,4 +59,4 @@ public: } // namespace Utils -QTC_DECLARE_CUSTOM_TASK(FileStreamerTask, Utils::FileStreamerTaskAdapter); +TASKING_DECLARE_TASK(FileStreamerTask, Utils::FileStreamerTaskAdapter); diff --git a/src/libs/utils/process.h b/src/libs/utils/process.h index 6de4f4418b1..272e25f3774 100644 --- a/src/libs/utils/process.h +++ b/src/libs/utils/process.h @@ -218,6 +218,6 @@ public: } // namespace Utils -QTC_DECLARE_CUSTOM_TASK(ProcessTask, Utils::ProcessTaskAdapter); +TASKING_DECLARE_TASK(ProcessTask, Utils::ProcessTaskAdapter); #endif // UTILS_PROCESS_H diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h index b37749f9a42..d8545564b9c 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/utils/tasktree.h @@ -416,13 +416,13 @@ public: } // namespace Tasking -#define QTC_DECLARE_CUSTOM_TASK(CustomTaskName, TaskAdapterClass)\ +#define TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass)\ namespace Tasking { using CustomTaskName = CustomTask; } -#define QTC_DECLARE_CUSTOM_TEMPLATE_TASK(CustomTaskName, TaskAdapterClass)\ +#define TASKING_DECLARE_TEMPLATE_TASK(CustomTaskName, TaskAdapterClass)\ namespace Tasking {\ template \ using CustomTaskName = CustomTask>;\ } // namespace Tasking -QTC_DECLARE_CUSTOM_TASK(TaskTreeTask, TaskTreeTaskAdapter); +TASKING_DECLARE_TASK(TaskTreeTask, TaskTreeTaskAdapter); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index b9350e5baa2..4fadef96d8e 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -328,7 +328,7 @@ public: } // namespace Core -QTC_DECLARE_CUSTOM_TASK(Collector, Core::ResultsCollectorAdapter); +TASKING_DECLARE_TASK(Collector, Core::ResultsCollectorAdapter); namespace Core { diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 9fd66fa0ddb..0a155e85500 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -350,7 +350,7 @@ public: void start() final { task()->start(); } }; -QTC_DECLARE_CUSTOM_TASK(JavaScriptRequestTask, JavaScriptRequestAdapter); +TASKING_DECLARE_TASK(JavaScriptRequestTask, JavaScriptRequestAdapter); namespace Core::Internal { diff --git a/src/plugins/languageclient/clientrequesttask.h b/src/plugins/languageclient/clientrequesttask.h index 6700902ff11..98c4888d05b 100644 --- a/src/plugins/languageclient/clientrequesttask.h +++ b/src/plugins/languageclient/clientrequesttask.h @@ -76,4 +76,4 @@ public: } // namespace LanguageClient -QTC_DECLARE_CUSTOM_TASK(SymbolRequest, LanguageClient::WorkspaceSymbolRequestTaskAdapter); +TASKING_DECLARE_TASK(SymbolRequest, LanguageClient::WorkspaceSymbolRequestTaskAdapter); diff --git a/src/plugins/languageclient/currentdocumentsymbolsrequest.h b/src/plugins/languageclient/currentdocumentsymbolsrequest.h index 6dd8e35a9b4..399a3fe7f07 100644 --- a/src/plugins/languageclient/currentdocumentsymbolsrequest.h +++ b/src/plugins/languageclient/currentdocumentsymbolsrequest.h @@ -48,5 +48,5 @@ public: } // namespace LanguageClient -QTC_DECLARE_CUSTOM_TASK(CurrentDocumentSymbolsRequestTask, +TASKING_DECLARE_TASK(CurrentDocumentSymbolsRequestTask, LanguageClient::CurrentDocumentSymbolsRequestTaskAdapter); diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h index 56408e9aef1..194ca6f4a62 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h @@ -85,4 +85,4 @@ private: } // namespace ProjectExplorer -QTC_DECLARE_CUSTOM_TASK(PortGatherer, ProjectExplorer::DeviceUsedPortsGathererAdapter); +TASKING_DECLARE_TASK(PortGatherer, ProjectExplorer::DeviceUsedPortsGathererAdapter); diff --git a/src/plugins/projectexplorer/devicesupport/filetransfer.h b/src/plugins/projectexplorer/devicesupport/filetransfer.h index 10c1a87c030..cb8fcedf9e0 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransfer.h +++ b/src/plugins/projectexplorer/devicesupport/filetransfer.h @@ -61,5 +61,5 @@ public: } // namespace ProjectExplorer -QTC_DECLARE_CUSTOM_TASK(FileTransferTask, ProjectExplorer::FileTransferTaskAdapter); -QTC_DECLARE_CUSTOM_TASK(FileTransferTestTask, ProjectExplorer::FileTransferTestTaskAdapter); +TASKING_DECLARE_TASK(FileTransferTask, ProjectExplorer::FileTransferTaskAdapter); +TASKING_DECLARE_TASK(FileTransferTestTask, ProjectExplorer::FileTransferTestTaskAdapter); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 719aa916543..55c5e2dea5b 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -285,4 +285,4 @@ public: } // namespace ProjectExplorer -QTC_DECLARE_CUSTOM_TASK(Killer, ProjectExplorer::KillerAdapter); +TASKING_DECLARE_TASK(Killer, ProjectExplorer::KillerAdapter); From a1792c653ebeaa251523bddc0e66dbda70551bf7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 10 May 2023 20:25:05 +0200 Subject: [PATCH 1007/1447] TaskTree: Prepare for de-utils-ization - part 4 Add internal implementation for qtcassert.{c,h}. Change-Id: I646b302be2f86e32e91c8c6fafa7b799e48773c2 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/barrier.cpp | 9 +++++++-- src/libs/utils/tasktree.cpp | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/barrier.cpp b/src/libs/utils/barrier.cpp index 690391cb0f2..c4daa033b41 100644 --- a/src/libs/utils/barrier.cpp +++ b/src/libs/utils/barrier.cpp @@ -3,10 +3,15 @@ #include "barrier.h" -#include "qtcassert.h" - namespace Tasking { +// That's cut down qtcassert.{c,h} to avoid the dependency. +#define QTC_STRINGIFY_HELPER(x) #x +#define QTC_STRINGIFY(x) QTC_STRINGIFY_HELPER(x) +#define QTC_STRING(cond) qDebug("SOFT ASSERT: \"%s\" in %s: %s", cond, __FILE__, QTC_STRINGIFY(__LINE__)) +#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_STRING(#cond); action; } do {} while (0) +#define QTC_CHECK(cond) if (cond) {} else { QTC_STRING(#cond); } do {} while (0) + void Barrier::setLimit(int value) { QTC_ASSERT(!isRunning(), return); diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 2c88546e6c4..75de54c374a 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -3,12 +3,17 @@ #include "tasktree.h" -#include "qtcassert.h" - #include namespace Tasking { +// That's cut down qtcassert.{c,h} to avoid the dependency. +#define QTC_STRINGIFY_HELPER(x) #x +#define QTC_STRINGIFY(x) QTC_STRINGIFY_HELPER(x) +#define QTC_STRING(cond) qDebug("SOFT ASSERT: \"%s\" in %s: %s", cond, __FILE__, QTC_STRINGIFY(__LINE__)) +#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_STRING(#cond); action; } do {} while (0) +#define QTC_CHECK(cond) if (cond) {} else { QTC_STRING(#cond); } do {} while (0) + class Guard { Q_DISABLE_COPY(Guard) From 62c309eeda1002799caa1afd1163ff79cbcad51f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 23:14:52 +0200 Subject: [PATCH 1008/1447] AllProjectsFilter: Remove the old matchesFor() implementation Change-Id: I9b5a0a1483e1dcd55d845ca2a5645ad9a4d05b52 Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- .../projectexplorer/allprojectsfilter.cpp | 25 +++---------------- .../projectexplorer/allprojectsfilter.h | 16 +++--------- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/plugins/projectexplorer/allprojectsfilter.cpp b/src/plugins/projectexplorer/allprojectsfilter.cpp index 1fc9fe0b4b3..42e110d3504 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.cpp +++ b/src/plugins/projectexplorer/allprojectsfilter.cpp @@ -26,10 +26,10 @@ AllProjectsFilter::AllProjectsFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("a"); setDefaultIncludedByDefault(true); - setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); })); + setRefreshRecipe(Tasking::Sync([this] { m_cache.invalidate(); })); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, - this, &AllProjectsFilter::invalidateCache); + this, [this] { m_cache.invalidate(); }); m_cache.setGeneratorProvider([] { // This body runs in main thread FilePaths filePaths; @@ -46,23 +46,4 @@ AllProjectsFilter::AllProjectsFilter() }); } -void AllProjectsFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - if (!fileIterator()) { - FilePaths paths; - for (Project *project : ProjectManager::projects()) - paths.append(project->files(Project::SourceFiles)); - Utils::sort(paths); - setFileIterator(new BaseFileFilter::ListIterator(paths)); - } - BaseFileFilter::prepareSearch(entry); -} - -void AllProjectsFilter::invalidateCache() -{ - m_cache.invalidate(); - setFileIterator(nullptr); -} - -} // ProjectExplorer::Internal +} // namespace ProjectExplorer::Internal diff --git a/src/plugins/projectexplorer/allprojectsfilter.h b/src/plugins/projectexplorer/allprojectsfilter.h index 4cf5bf0b78e..6782ef46115 100644 --- a/src/plugins/projectexplorer/allprojectsfilter.h +++ b/src/plugins/projectexplorer/allprojectsfilter.h @@ -3,26 +3,18 @@ #pragma once -#include +#include -namespace ProjectExplorer { -namespace Internal { +namespace ProjectExplorer::Internal { -// TODO: Don't derive from BaseFileFilter, flatten the hierarchy -class AllProjectsFilter : public Core::BaseFileFilter +class AllProjectsFilter : public Core::ILocatorFilter { - Q_OBJECT - public: AllProjectsFilter(); - void prepareSearch(const QString &entry) override; private: Core::LocatorMatcherTasks matchers() final { return {m_cache.matcher()}; } - // TODO: Remove me, replace with direct "m_cache.invalidate()" call - void invalidateCache(); Core::LocatorFileCache m_cache; }; -} // namespace Internal -} // namespace ProjectExplorer +} // namespace ProjectExplorer::Internal From af5e50edf73b98fc7b995906b8ddd492756bff52 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 8 May 2023 17:59:26 +0200 Subject: [PATCH 1009/1447] CMakePM: Cancel current build before locator "cm " In case the current project is building and the user starts a "cm " in Locator, now the build is canceled before starting a a "cmake --build --target ". Fixes: QTCREATORBUG-26699 Change-Id: I27ed9ba5b8d917dce94835a5462e4e64e7515bd9 Reviewed-by: hjk --- src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index ab646d1fa69..0eab6012006 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -122,6 +122,9 @@ void BuildCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &selec || !cmakeProject->activeTarget()->activeBuildConfiguration()) return; + if (BuildManager::isBuilding(cmakeProject)) + BuildManager::cancel(); + // Find the make step BuildStepList *buildStepList = cmakeProject->activeTarget()->activeBuildConfiguration()->buildSteps(); From 3e3a202e75604d756b728c71630b4c2df9f28656 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 22:38:38 +0200 Subject: [PATCH 1010/1447] OpenDocumentsFilter: Remove the old matchesFor() implementation Change-Id: I1166dbd17125aa3c6bab4dae4c416063c4b6f7ba Reviewed-by: Eike Ziller --- .../locator/opendocumentsfilter.cpp | 122 ++---------------- .../coreplugin/locator/opendocumentsfilter.h | 32 +---- 2 files changed, 14 insertions(+), 140 deletions(-) diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 64c68efa28c..95e076ec2bd 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -5,15 +5,14 @@ #include "../coreplugintr.h" +#include + #include #include #include -#include #include -#include -#include #include using namespace Tasking; @@ -21,6 +20,13 @@ using namespace Utils; namespace Core::Internal { +class Entry +{ +public: + Utils::FilePath fileName; + QString displayName; +}; + OpenDocumentsFilter::OpenDocumentsFilter() { setId("Open documents"); @@ -29,19 +35,10 @@ OpenDocumentsFilter::OpenDocumentsFilter() setDefaultShortcutString("o"); setPriority(High); setDefaultIncludedByDefault(true); - // TODO: Remove the refresh recipe - setRefreshRecipe(Sync([this] { refreshInternally(); })); - - connect(DocumentModel::model(), &QAbstractItemModel::dataChanged, - this, &OpenDocumentsFilter::slotDataChanged); - connect(DocumentModel::model(), &QAbstractItemModel::rowsInserted, - this, &OpenDocumentsFilter::slotRowsInserted); - connect(DocumentModel::model(), &QAbstractItemModel::rowsRemoved, - this, &OpenDocumentsFilter::slotRowsRemoved); } static void matchEditors(QPromise &promise, const LocatorStorage &storage, - const QList &editorsData) + const QList &editorsData) { const Link link = Link::fromString(storage.input(), true); const QRegularExpression regexp = ILocatorFilter::createRegExp(link.targetFilePath.toString()); @@ -51,7 +48,7 @@ static void matchEditors(QPromise &promise, const LocatorStorage &storage, LocatorFilterEntries goodEntries; LocatorFilterEntries betterEntries; - for (const OpenDocumentsFilter::Entry &editorData : editorsData) { + for (const Entry &editorData : editorsData) { if (promise.isCanceled()) return; if (editorData.fileName.isEmpty()) @@ -88,99 +85,4 @@ LocatorMatcherTasks OpenDocumentsFilter::matchers() return {{AsyncTask(onSetup), storage}}; } -void OpenDocumentsFilter::slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector &roles) -{ - Q_UNUSED(roles) - - const int topIndex = std::max(0, topLeft.row() - 1 /**/); - const int bottomIndex = bottomRight.row() - 1 /**/; - - QMutexLocker lock(&m_mutex); - - const QList documentEntries = DocumentModel::entries(); - for (int i = topIndex; i <= bottomIndex; ++i) { - QTC_ASSERT(i < m_editors.size(), break); - DocumentModel::Entry *e = documentEntries.at(i); - m_editors[i] = {e->filePath(), e->displayName()}; - } -} - -void OpenDocumentsFilter::slotRowsInserted(const QModelIndex &, int first, int last) -{ - const int firstIndex = std::max(0, first - 1 /**/); - - QMutexLocker lock(&m_mutex); - - const QList documentEntries = DocumentModel::entries(); - for (int i = firstIndex; i < last; ++i) { - DocumentModel::Entry *e = documentEntries.at(i); - m_editors.insert(i, {e->filePath(), e->displayName()}); - } -} - -void OpenDocumentsFilter::slotRowsRemoved(const QModelIndex &, int first, int last) -{ - QMutexLocker lock(&m_mutex); - - const int firstIndex = std::max(0, first - 1 /**/); - for (int i = firstIndex; i < last; ++i) - m_editors.removeAt(i); -} - -QList OpenDocumentsFilter::matchesFor(QFutureInterface &future, - const QString &entry) -{ - QList goodEntries; - QList betterEntries; - const Link link = Link::fromString(entry, true); - - const QRegularExpression regexp = createRegExp(link.targetFilePath.toString()); - if (!regexp.isValid()) - return goodEntries; - - const QList editorEntries = editors(); - for (const Entry &editorEntry : editorEntries) { - if (future.isCanceled()) - break; - QString fileName = editorEntry.fileName.toString(); - if (fileName.isEmpty()) - continue; - QString displayName = editorEntry.displayName; - const QRegularExpressionMatch match = regexp.match(displayName); - if (match.hasMatch()) { - LocatorFilterEntry filterEntry; - filterEntry.displayName = displayName; - filterEntry.filePath = FilePath::fromString(fileName); - filterEntry.extraInfo = filterEntry.filePath.shortNativePath(); - filterEntry.highlightInfo = highlightInfo(match); - filterEntry.linkForEditor = Link(filterEntry.filePath, link.targetLine, - link.targetColumn); - if (match.capturedStart() == 0) - betterEntries.append(filterEntry); - else - goodEntries.append(filterEntry); - } - } - betterEntries.append(goodEntries); - return betterEntries; -} - -QList OpenDocumentsFilter::editors() const -{ - QMutexLocker lock(&m_mutex); - return m_editors; -} - -void OpenDocumentsFilter::refreshInternally() -{ - QMutexLocker lock(&m_mutex); - m_editors.clear(); - const QList documentEntries = DocumentModel::entries(); - // create copy with only the information relevant to use - // to avoid model deleting entries behind our back - for (DocumentModel::Entry *e : documentEntries) - m_editors.append({e->filePath(), e->displayName()}); -} - -} // Core::Internal +} // namespace Core::Internal diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index c75c4da1db7..94306d0515c 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -5,43 +5,15 @@ #include "ilocatorfilter.h" -#include - -#include - -namespace Core { -namespace Internal { +namespace Core::Internal { class OpenDocumentsFilter : public ILocatorFilter { - Q_OBJECT - public: OpenDocumentsFilter(); - QList matchesFor(QFutureInterface &future, - const QString &entry) override; - // TODO: Move to cpp when matchesFor() is removed - class Entry - { - public: - Utils::FilePath fileName; - QString displayName; - }; - -public slots: - void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector &roles); - void slotRowsInserted(const QModelIndex &, int first, int last); - void slotRowsRemoved(const QModelIndex &, int first, int last); private: LocatorMatcherTasks matchers() final; - QList editors() const; - void refreshInternally(); - - mutable QMutex m_mutex; - QList m_editors; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From 161cac0a85a61678da4e8722639bf952fe4aa32b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 11 May 2023 15:46:59 +0200 Subject: [PATCH 1011/1447] Terminal: Fix Shellintegration for bash bash needs long options to be before short options. Change-Id: I277a9283253f11bcb76e0366a0b6c5a0346fdfd8 Reviewed-by: hjk --- src/plugins/terminal/shellintegration.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp index cd67318604c..d8e26f94ce5 100644 --- a/src/plugins/terminal/shellintegration.cpp +++ b/src/plugins/terminal/shellintegration.cpp @@ -120,7 +120,12 @@ void ShellIntegration::prepareProcess(Utils::Process &process) m_tempDir.filePath(filesToCopy.bash.rcFile.fileName())); rcPath.copyFile(tmpRc); - cmd.addArgs({"--init-file", tmpRc.nativePath()}); + CommandLine newCmd = {cmd.executable(), {"--init-file", tmpRc.nativePath()}}; + + if (cmd.arguments() == "-l") + newCmd.addArg("-l"); + + cmd = newCmd; } else if (cmd.executable().baseName() == "zsh") { for (const FileToCopy &file : filesToCopy.zsh.files) { const auto copyResult = file.source.copyFile( From aca8e5906b83373d54025bae5c4ddb998ceff86c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 12 May 2023 11:13:03 +0200 Subject: [PATCH 1012/1447] AutoTest: Output time taken when parsing tests Makes debugging easier as you don't have to calculate end - start yourself. Change-Id: Ib75a36bbf52633e188a6c4bbd488eb439cb52984 Reviewed-by: Christian Stenger --- src/plugins/autotest/testcodeparser.cpp | 2 ++ src/plugins/autotest/testcodeparser.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index b86f57e441d..6f3d5137e45 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -334,6 +334,7 @@ void TestCodeParser::scanForTests(const QSet &filePaths, // use only a single parser or all current active? const QList codeParsers = parsers.isEmpty() ? m_testCodeParsers : parsers; qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing"; + m_parsingTimer.restart(); QSet extensions; const auto cppSnapshot = CppEditor::CppModelManager::instance()->snapshot(); @@ -438,6 +439,7 @@ void TestCodeParser::onFinished(bool success) m_updateParsers.clear(); emit parsingFinished(); qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFin"; + qCDebug(LOG) << "Parsing took:" << m_parsingTimer.elapsed() << "ms"; } m_dirty = false; break; diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index d99c11ea570..2dd81d93d60 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -97,6 +97,8 @@ private: Utils::FutureSynchronizer m_futureSynchronizer; std::unique_ptr m_taskTree; QHash m_qmlEditorRev; + + QElapsedTimer m_parsingTimer; }; } // namespace Internal From dc18d4b9ee88178241df9b51fbba2c4a3216cd12 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 9 May 2023 13:49:50 +0200 Subject: [PATCH 1013/1447] CMakePM: Display presets as part of the project outline Fixes: QTCREATORBUG-28966 Change-Id: Iae0f77956bf6f4682ea8a25e08d05de3331c7420 Reviewed-by: Alessandro Portale Reviewed-by: Reviewed-by: hjk --- .../cmakeprojectmanager/cmakeproject.cpp | 8 +++++ .../cmakeprojectmanager/cmakeprojectnodes.cpp | 9 ++++++ .../cmakeprojectmanager/cmakeprojectnodes.h | 6 ++++ .../fileapidataextractor.cpp | 3 ++ .../cmakeprojectmanager/projecttreehelper.cpp | 30 +++++++++++++++++++ .../cmakeprojectmanager/projecttreehelper.h | 2 ++ 6 files changed, 58 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 71b96610db5..8bd96f239ef 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -93,6 +93,14 @@ Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakeP result.version = cmakePresetsData.version; result.cmakeMinimimRequired = cmakePresetsData.cmakeMinimimRequired; + result.include = cmakePresetsData.include; + if (result.include) { + if (cmakeUserPresetsData.include) + result.include->append(cmakeUserPresetsData.include.value()); + } else { + result.include = cmakeUserPresetsData.include; + } + auto combinePresetsInternal = [](auto &presetsHash, auto &presets, auto &userPresets, diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 10f18fbf675..b26f9a70b5b 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -30,6 +30,15 @@ CMakeInputsNode::CMakeInputsNode(const FilePath &cmakeLists) : setListInProject(false); } +CMakePresetsNode::CMakePresetsNode(const FilePath &projectPath) : + ProjectExplorer::ProjectNode(projectPath) +{ + setPriority(Node::DefaultPriority - 9); + setDisplayName(Tr::tr("CMake Presets")); + setIcon(DirectoryIcon(ProjectExplorer::Constants::FILEOVERLAY_PRODUCT)); + setListInProject(false); +} + CMakeListsNode::CMakeListsNode(const FilePath &cmakeListPath) : ProjectExplorer::ProjectNode(cmakeListPath) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h index 5d248020abe..94cde6dfef1 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h @@ -15,6 +15,12 @@ public: CMakeInputsNode(const Utils::FilePath &cmakeLists); }; +class CMakePresetsNode : public ProjectExplorer::ProjectNode +{ +public: + CMakePresetsNode(const Utils::FilePath &projectPath); +}; + class CMakeListsNode : public ProjectExplorer::ProjectNode { public: diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index c6f8f1225c8..1ef71721686 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -711,6 +711,9 @@ std::unique_ptr generateRootProjectNode( std::move(data.cmakeNodesBuild), std::move(data.cmakeNodesOther)); + + addCMakePresets(result.get(), sourceDirectory); + data.cmakeNodesSource.clear(); // Remove all the nullptr in the vector... data.cmakeNodesBuild.clear(); // Remove all the nullptr in the vector... data.cmakeNodesOther.clear(); // Remove all the nullptr in the vector... diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp index 4069ca6aa1f..7b9efb07b94 100644 --- a/src/plugins/cmakeprojectmanager/projecttreehelper.cpp +++ b/src/plugins/cmakeprojectmanager/projecttreehelper.cpp @@ -3,9 +3,11 @@ #include "projecttreehelper.h" +#include "cmakeproject.h" #include "cmakeprojectmanagertr.h" #include +#include #include #include @@ -88,6 +90,34 @@ void addCMakeInputs(FolderNode *root, root->addNode(std::move(cmakeVFolder)); } +void addCMakePresets(FolderNode *root, const Utils::FilePath &sourceDir) +{ + QStringList presetFileNames; + presetFileNames << "CMakePresets.json"; + presetFileNames << "CMakeUserPresets.json"; + + const CMakeProject *cp = static_cast( + ProjectManager::projectForFile(sourceDir.pathAppended("CMakeLists.txt"))); + + if (cp && cp->presetsData().include) + presetFileNames.append(cp->presetsData().include.value()); + + std::vector> presets; + for (const auto &fileName : presetFileNames) { + Utils::FilePath file = sourceDir.pathAppended(fileName); + if (file.exists()) + presets.push_back(std::make_unique(file, Node::fileTypeForFileName(file))); + } + + if (presets.empty()) + return; + + std::unique_ptr cmakeVFolder = std::make_unique(root->filePath()); + addCMakeVFolder(cmakeVFolder.get(), sourceDir, 1000, QString(), std::move(presets)); + + root->addNode(std::move(cmakeVFolder)); +} + QHash addCMakeLists( CMakeProjectNode *root, std::vector> &&cmakeLists) { diff --git a/src/plugins/cmakeprojectmanager/projecttreehelper.h b/src/plugins/cmakeprojectmanager/projecttreehelper.h index 66cde4aea9b..34a8723759f 100644 --- a/src/plugins/cmakeprojectmanager/projecttreehelper.h +++ b/src/plugins/cmakeprojectmanager/projecttreehelper.h @@ -30,6 +30,8 @@ void addCMakeInputs(ProjectExplorer::FolderNode *root, std::vector> &&buildInputs, std::vector> &&rootInputs); +void addCMakePresets(ProjectExplorer::FolderNode *root, const Utils::FilePath &sourceDir); + QHash addCMakeLists( CMakeProjectNode *root, std::vector> &&cmakeLists); From 1a98dda5c417e892cadbedb656829cf2ba4d1d0a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 11 May 2023 09:34:53 +0200 Subject: [PATCH 1014/1447] Utils: fix Text::Range length and remove mid Those functions are based on the assumption that the passed text starts at the begin position, which was good enough for search results, but if used in other parts of the codebase it might give unwanted results. Calculate the length of the range now as expected and subtract the beginning lines. In order to still got the correct results for the text result texts modify the result range to always start at the first line before calculating the length of the range. Also add tests for the modified functionality Change-Id: I7ccd75b642dda6dd4f738877cbe3543d46c03652 Reviewed-by: Qt CI Bot Reviewed-by: Jarek Kobus --- src/libs/utils/textutils.cpp | 26 ++++++--- src/libs/utils/textutils.h | 2 +- .../coreplugin/find/searchresulttreemodel.cpp | 8 ++- src/plugins/texteditor/basefilefind.cpp | 10 +++- tests/auto/utils/CMakeLists.txt | 1 + tests/auto/utils/text/CMakeLists.txt | 4 ++ tests/auto/utils/text/text.qbs | 7 +++ tests/auto/utils/text/tst_text.cpp | 58 +++++++++++++++++++ 8 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 tests/auto/utils/text/CMakeLists.txt create mode 100644 tests/auto/utils/text/text.qbs create mode 100644 tests/auto/utils/text/tst_text.cpp diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 34dbb5e1fa5..8cf7a41ed60 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -58,22 +58,30 @@ Position Position::fromPositionInDocument(const QTextDocument *document, int pos int Range::length(const QString &text) const { + if (end.line < begin.line) + return -1; + if (begin.line == end.line) return end.column - begin.column; - const int lineCount = end.line - begin.line; - int index = text.indexOf(QChar::LineFeed); + int index = 0; int currentLine = 1; - while (index > 0 && currentLine < lineCount) { - ++index; + while (currentLine < begin.line) { index = text.indexOf(QChar::LineFeed, index); + if (index < 0) + return -1; + ++index; ++currentLine; } - - if (index < 0) - return 0; - - return index - begin.column + end.column; + const int beginIndex = index + begin.column; + while (currentLine < end.line) { + index = text.indexOf(QChar::LineFeed, index); + if (index < 0) + return -1; + ++index; + ++currentLine; + } + return index + end.column - beginIndex; } bool Range::operator==(const Range &other) const diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index 4ba3b0e1a82..6ee82274dc8 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -37,7 +37,6 @@ public: class QTCREATOR_UTILS_EXPORT Range { public: - QString mid(const QString &text) const { return text.mid(begin.column, length(text)); } int length(const QString &text) const; Position begin; @@ -97,3 +96,4 @@ QTCREATOR_UTILS_EXPORT QString utf16LineTextInUtf8Buffer(const QByteArray &utf8B } // Utils Q_DECLARE_METATYPE(Utils::Text::Position) +Q_DECLARE_METATYPE(Utils::Text::Range) diff --git a/src/plugins/coreplugin/find/searchresulttreemodel.cpp b/src/plugins/coreplugin/find/searchresulttreemodel.cpp index 769c63a6bca..b6d620b80b5 100644 --- a/src/plugins/coreplugin/find/searchresulttreemodel.cpp +++ b/src/plugins/coreplugin/find/searchresulttreemodel.cpp @@ -322,9 +322,13 @@ QVariant SearchResultTreeModel::data(const SearchResultTreeItem *row, int role) case ItemDataRoles::ResultBeginColumnNumberRole: result = row->item.mainRange().begin.column; break; - case ItemDataRoles::SearchTermLengthRole: - result = row->item.mainRange().length(row->item.lineText()); + case ItemDataRoles::SearchTermLengthRole:{ + Text::Range range = row->item.mainRange(); + range.end.line -= range.begin.line - 1; + range.begin.line = 1; + result = range.length(row->item.lineText()); break; + } case ItemDataRoles::ContainingFunctionNameRole: result = row->item.containingFunctionName().value_or(QString{}); break; diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 197a2fa6968..974f1472912 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -486,9 +486,13 @@ FilePaths BaseFileFind::replaceAll(const QString &text, const SearchResultItems if (item.userData().canConvert() && !item.userData().toStringList().isEmpty()) { replacement = Utils::expandRegExpReplacement(text, item.userData().toStringList()); } else if (preserveCase) { - const QString originalText = (item.mainRange().length(item.lineText()) == 0) - ? item.lineText() - : item.mainRange().mid(item.lineText()); + Text::Range range = item.mainRange(); + range.end.line -= range.begin.line - 1; + range.begin.line = 1; + QString originalText = item.lineText(); + const int rangeLength = range.length(item.lineText()); + if (rangeLength > 0) + originalText = originalText.mid(range.begin.column, rangeLength); replacement = Utils::matchCaseReplacement(originalText, text); } else { replacement = text; diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index 36f20fdac52..1bb4bb641ae 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -17,4 +17,5 @@ add_subdirectory(stringutils) add_subdirectory(tasktree) add_subdirectory(templateengine) add_subdirectory(treemodel) +add_subdirectory(text) add_subdirectory(unixdevicefileaccess) diff --git a/tests/auto/utils/text/CMakeLists.txt b/tests/auto/utils/text/CMakeLists.txt new file mode 100644 index 00000000000..78fd3838f42 --- /dev/null +++ b/tests/auto/utils/text/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_utils_text + DEPENDS Utils + SOURCES tst_text.cpp +) diff --git a/tests/auto/utils/text/text.qbs b/tests/auto/utils/text/text.qbs new file mode 100644 index 00000000000..828dec8d117 --- /dev/null +++ b/tests/auto/utils/text/text.qbs @@ -0,0 +1,7 @@ +import qbs + +QtcAutotest { + name: "Utils::Text autotest" + Depends { name: "Utils" } + files: "tst_text.cpp" +} diff --git a/tests/auto/utils/text/tst_text.cpp b/tests/auto/utils/text/tst_text.cpp new file mode 100644 index 00000000000..a2e9dc5037b --- /dev/null +++ b/tests/auto/utils/text/tst_text.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include + +#include + +using namespace Utils::Text; + +class tst_Text : public QObject +{ + Q_OBJECT + +private slots: + void testRangeLength_data(); + void testRangeLength(); +}; + +void tst_Text::testRangeLength_data() +{ + QTest::addColumn("text"); + QTest::addColumn("range"); + QTest::addColumn("length"); + + QTest::newRow("empty range") << QString() << Range{{1, 0}, {1, 0}} << 0; + + QTest::newRow("range on same line") << QString() << Range{{1, 0}, {1, 1}} << 1; + + QTest::newRow("range spanning lines") << QString("foo\nbar") << Range{{1, 0}, {2, 0}} << 4; + + QTest::newRow("range spanning lines and column offset") + << QString("foo\nbar") << Range{{1, 1}, {2, 1}} << 4; + + QTest::newRow("range spanning lines and begin column offset") + << QString("foo\nbar") << Range{{1, 1}, {2, 0}} << 3; + + QTest::newRow("range spanning lines and end column offset") + << QString("foo\nbar") << Range{{1, 0}, {2, 1}} << 5; + + QTest::newRow("hyper range") << QString("foo\nbar\nfoobar") << Range{{2, 1}, {3, 1}} << 4; + + QTest::newRow("flipped range") << QString() << Range{{2, 0}, {1, 0}} << -1; + + QTest::newRow("out of range") << QString() << Range{{1, 0}, {2, 0}} << -1; +} + +void tst_Text::testRangeLength() +{ + QFETCH(QString, text); + QFETCH(Range, range); + QFETCH(int, length); + + QCOMPARE(range.length(text), length); +} + +QTEST_GUILESS_MAIN(tst_Text) + +#include "tst_text.moc" From ed6f5e348687b6f22e803448a3c54965d573c45d Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 11 May 2023 16:55:01 +0200 Subject: [PATCH 1015/1447] Layouting: Add a plain 'Widget' item Change-Id: Id419b1efd56f51fb282b11c4b241b96eb7d7d0ae Reviewed-by: Alessandro Portale --- src/libs/utils/layoutbuilder.cpp | 6 ++++++ src/libs/utils/layoutbuilder.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 226120b823d..e3582f6adec 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -534,6 +534,12 @@ void setupWidget(LayoutItem *item) item->onExit = widgetExit; }; +Widget::Widget(std::initializer_list items) +{ + this->subItems = items; + setupWidget(this); +} + Group::Group(std::initializer_list items) { this->subItems = items; diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 33fba0270d0..5f69e0ef6a5 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -112,6 +112,12 @@ public: Form(std::initializer_list items); }; +class QTCREATOR_UTILS_EXPORT Widget : public LayoutItem +{ +public: + Widget(std::initializer_list items); +}; + class QTCREATOR_UTILS_EXPORT Stack : public LayoutItem { public: From 6149fd8bfa742d45b258bd8d4f08e7ce867841e8 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 12 May 2023 11:12:20 +0200 Subject: [PATCH 1016/1447] Utils: Cache FilePath::qHash Calling toCaseFolded is expensive if the same filepath is hashed often, so we calculate the hash value once and cache the result. One such case was found to happen when parsing tests, as the cpp parser is queried a lot and it uses hash maps / sets with filepaths. Change-Id: Ic3ca7f09e8f108f5a89b3fdb17743ae7c3258001 Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 15 +++++++++++---- src/libs/utils/filepath.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 9bf47805964..ab6ec4da1f3 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -441,6 +441,7 @@ void FilePath::setParts(const QStringView scheme, const QStringView host, QStrin if (path.length() >= 3 && path[0] == '/' && path[1] == '.' && path[2] == '/') path = path.mid(3); + m_hash = 0; m_data = path.toString() + scheme.toString() + host.toString(); m_schemeLen = scheme.size(); m_hostLen = host.size(); @@ -2078,10 +2079,16 @@ QTCREATOR_UTILS_EXPORT bool operator>=(const FilePath &first, const FilePath &se QTCREATOR_UTILS_EXPORT size_t qHash(const FilePath &filePath, uint seed) { - if (filePath.caseSensitivity() == Qt::CaseSensitive) - return qHash(QStringView(filePath.m_data), seed); - const size_t schemeHostHash = qHash(QStringView(filePath.m_data).mid(filePath.m_pathLen), seed); - return qHash(filePath.path().toCaseFolded(), seed) ^ schemeHostHash; + Q_UNUSED(seed); + + if (filePath.m_hash == 0) { + if (filePath.caseSensitivity() == Qt::CaseSensitive) + filePath.m_hash = qHash(QStringView(filePath.m_data), 0); + else + filePath.m_hash = qHash(filePath.m_data.toCaseFolded(), 0); + } + + return filePath.m_hash; } QTCREATOR_UTILS_EXPORT size_t qHash(const FilePath &filePath) diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 64651691545..142542b7343 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -277,6 +277,7 @@ private: unsigned int m_pathLen = 0; unsigned short m_schemeLen = 0; unsigned short m_hostLen = 0; + mutable size_t m_hash = 0; }; class QTCREATOR_UTILS_EXPORT DeviceFileHooks From 69fbe727525c01d7d84ec5f860b99f04086da294 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 12 May 2023 13:33:45 +0200 Subject: [PATCH 1017/1447] Utils: Use FilePath hash in operator== Change-Id: Ibbea420a5a5353da221d285b70272cdf9b09d0d0 Reviewed-by: Jarek Kobus --- src/libs/utils/filepath.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index ab6ec4da1f3..5681837582a 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -2042,6 +2042,9 @@ DeviceFileHooks &DeviceFileHooks::instance() QTCREATOR_UTILS_EXPORT bool operator==(const FilePath &first, const FilePath &second) { + if (first.m_hash != 0 && second.m_hash != 0 && first.m_hash != second.m_hash) + return false; + return first.pathView().compare(second.pathView(), first.caseSensitivity()) == 0 && first.host() == second.host() && first.scheme() == second.scheme(); From fc8ae0e2dc011e59792cc6d68841e24643138b16 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 13:46:00 +0200 Subject: [PATCH 1018/1447] VcsBase: Remove unused settings member Change-Id: I3247a639d9607a4acbf5477302e1f2860325a0e6 Reviewed-by: Orgad Shaneh --- src/plugins/vcsbase/vcsbaseclientsettings.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.h b/src/plugins/vcsbase/vcsbaseclientsettings.h index 87835755ca0..102405c4bfc 100644 --- a/src/plugins/vcsbase/vcsbaseclientsettings.h +++ b/src/plugins/vcsbase/vcsbaseclientsettings.h @@ -23,9 +23,6 @@ public: Utils::StringAspect path; Utils::FilePaths searchPathList() const; - -private: - QString m_settingsGroup; }; } // namespace VcsBase From 62e9a0bec1a9811833c1194f287f30eaa7afec14 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 8 May 2023 17:18:44 +0200 Subject: [PATCH 1019/1447] CMakePM: Stretch the CMake parameters column on resize Makes sure that the CMake parameters columns are properly stretched when Qt Creator window is being resized or maximized / restored from maximized state. Fixes: QTCREATORBUG-27257 Change-Id: Ifb4d439fb758dcc5b2593be917ba35e9c79f2840 Reviewed-by: Alessandro Portale --- src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 494d7ee67d7..1ae95c18073 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -68,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -250,7 +250,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildSystem *bs) : m_configView->setUniformRowHeights(true); m_configView->setSortingEnabled(true); m_configView->sortByColumn(0, Qt::AscendingOrder); - (void) new HeaderViewStretcher(m_configView->header(), 0); + m_configView->header()->setSectionResizeMode(QHeaderView::Stretch); m_configView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_configView->setSelectionBehavior(QAbstractItemView::SelectItems); m_configView->setAlternatingRowColors(true); From 8cd00ad279e5cb9e0c392b27c52631f9935e8e95 Mon Sep 17 00:00:00 2001 From: Patrik Teivonen Date: Tue, 2 May 2023 10:07:01 +0300 Subject: [PATCH 1020/1447] Coin: Switch to the new packaging tools scripts location Script location is changed from qtsdk.git to tqtc-qtsdk.git. Adjust the coin instructions to use the new location. This change should be picked to all the branches in use. Task-number: QTQAINFRA-5506 Change-Id: I78abb36781cfaaff72870c297ba152066ac5f385 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- coin/instructions/build.yaml | 6 +++--- coin/instructions/provision.yaml | 9 +-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/coin/instructions/build.yaml b/coin/instructions/build.yaml index 23461dbcf4e..401db50562a 100644 --- a/coin/instructions/build.yaml +++ b/coin/instructions/build.yaml @@ -31,7 +31,7 @@ instructions: maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run build.py, check logs." - type: ChangeDirectory - directory: "{{.AgentWorkingDir}}/build/qtsdk/packaging-tools" + directory: "{{.AgentWorkingDir}}/build/tqtc-qtsdk/packaging_tools" - type: ExecuteCommand command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command make" maxTimeInSeconds: 36000 @@ -65,7 +65,7 @@ instructions: maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run build.py, check logs." - type: ChangeDirectory - directory: "{{.AgentWorkingDir}}/build/qtsdk/packaging-tools" + directory: "{{.AgentWorkingDir}}/build/tqtc-qtsdk/packaging_tools" - type: ExecuteCommand command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command make" maxTimeInSeconds: 36000 @@ -114,7 +114,7 @@ instructions: maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run build.py, check logs." - type: ChangeDirectory - directory: "{{.AgentWorkingDir}}\\build\\qtsdk\\packaging-tools" + directory: "{{.AgentWorkingDir}}\\build\\tqtc-qtsdk\\packaging_tools" - type: ExecuteCommand command: "python -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}\\build\\sdktool\\qt --src {{.AgentWorkingDir}}\\qt-creator\\qt-creator\\src\\tools\\sdktool --build {{.AgentWorkingDir}}\\build\\sdktool\\build --install {{.AgentWorkingDir}}\\build\\sdktool\\install --make-command nmake" maxTimeInSeconds: 36000 diff --git a/coin/instructions/provision.yaml b/coin/instructions/provision.yaml index c11325d1375..75fab041366 100644 --- a/coin/instructions/provision.yaml +++ b/coin/instructions/provision.yaml @@ -16,13 +16,6 @@ instructions: directory: "{{.BuildDir}}" - type: ChangeDirectory directory: "{{.BuildDir}}" - - type: InstallSourceArchive - maxTimeInSeconds: 600 - maxTimeBetweenOutput: 600 - project: qtsdk/qtsdk - ref: master - directory: "build/qtsdk" - userMessageOnFailure: "Failed to install qtsdk, check logs" - type: InstallSourceArchive maxTimeInSeconds: 600 maxTimeBetweenOutput: 600 @@ -57,7 +50,7 @@ instructions: property: host.os not_equals_value: Windows - type: ChangeDirectory - directory: "{{.BuildDir}}/qtsdk/packaging-tools" + directory: "{{.BuildDir}}/tqtc-qtsdk/packaging_tools" - type: ExecuteCommand command: "python3 -m pipenv run python -u install_qt.py --qt-path {{.BuildDir}}/qt_install_dir --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} --icu7z http://master.qt.io/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z {{.Env.QTC_QT_MODULES}}" executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution From 0dbc208a070812de867cec27c960ed7de31e8bf7 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 12 May 2023 13:18:35 +0200 Subject: [PATCH 1021/1447] CMake: Add -fPIC also for OBJECT libraries add_qtc_library would have set the POSITION_INDEPENDENT_CODE property for STATIC libraries on UNIX based systems. The OBJECT libraries need the same treatment. Change-Id: Ia333a36ea0f35d7db3ed876cdde5b895b47644c7 Reviewed-by: Eike Ziller --- cmake/QtCreatorAPI.cmake | 2 +- src/libs/3rdparty/cplusplus/CMakeLists.txt | 1 - src/libs/sqlite/CMakeLists.txt | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index a50e9be59f1..effbb454047 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -188,7 +188,7 @@ function(add_qtc_library name) set(TEST_DEFINES WITH_TESTS SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}") endif() - if(_arg_STATIC AND UNIX) + if((_arg_STATIC OR _arg_OBJECT) AND UNIX) # not added by Qt if reduce_relocations is turned off for it set_target_properties(${name} PROPERTIES POSITION_INDEPENDENT_CODE ON) endif() diff --git a/src/libs/3rdparty/cplusplus/CMakeLists.txt b/src/libs/3rdparty/cplusplus/CMakeLists.txt index 2758ffe6eeb..d9f130b470a 100644 --- a/src/libs/3rdparty/cplusplus/CMakeLists.txt +++ b/src/libs/3rdparty/cplusplus/CMakeLists.txt @@ -41,7 +41,6 @@ add_qtc_library(3rd_cplusplus OBJECT TypeVisitor.cpp TypeVisitor.h cppassert.h SKIP_PCH - PROPERTIES POSITION_INDEPENDENT_CODE ON ) set(export_symbol_declaration DEFINES CPLUSPLUS_BUILD_LIB) diff --git a/src/libs/sqlite/CMakeLists.txt b/src/libs/sqlite/CMakeLists.txt index 7f33b189215..4c7cd774c60 100644 --- a/src/libs/sqlite/CMakeLists.txt +++ b/src/libs/sqlite/CMakeLists.txt @@ -1,5 +1,5 @@ add_qtc_library(SqliteC OBJECT - PROPERTIES AUTOMOC OFF AUTOUIC OFF QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON POSITION_INDEPENDENT_CODE ON + PROPERTIES AUTOMOC OFF AUTOUIC OFF QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON DEFINES SQLITE_CORE SQLITE_CUSTOM_INCLUDE=config.h $<$:SQLITE_DEBUG> PROPERTIES COMPILE_OPTIONS $,/FIconfig.h,-includeconfig.h> PUBLIC_INCLUDES From 06723148447ea244267be1ec3eb3e3a22e931bf1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 23:55:20 +0200 Subject: [PATCH 1022/1447] DirectoryFilter: Remove the old matchesFor() implementation Change-Id: Iae8a2e3adda7fdaec69873bf4b171da98eee4874 Reviewed-by: Eike Ziller --- .../coreplugin/locator/directoryfilter.cpp | 30 ++++++++----------- .../coreplugin/locator/directoryfilter.h | 13 ++------ .../coreplugin/locator/ilocatorfilter.cpp | 6 ++++ .../coreplugin/locator/ilocatorfilter.h | 2 ++ 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index a18c92b5736..6100181ff43 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -83,8 +83,7 @@ DirectoryFilter::DirectoryFilter(Id id) const auto groupSetup = [this] { if (!m_directories.isEmpty()) return TaskAction::Continue; // Async task will run - m_files.clear(); - updateFileIterator(); + m_cache.setFilePaths({}); return TaskAction::StopWithDone; // Group stops, skips async task }; const auto asyncSetup = [this](Async &async) { @@ -92,8 +91,8 @@ DirectoryFilter::DirectoryFilter(Id id) displayName()); }; const auto asyncDone = [this](const Async &async) { - m_files = async.isResultAvailable() ? async.result() : FilePaths(); - updateFileIterator(); + if (async.isResultAvailable()) + m_cache.setFilePaths(async.result()); }; const Group root { OnGroupSetup(groupSetup), @@ -113,10 +112,11 @@ void DirectoryFilter::saveState(QJsonObject &object) const } if (m_filters != kFiltersDefault) object.insert(kFiltersKey, QJsonArray::fromStringList(m_filters)); - if (!m_files.isEmpty()) - object.insert(kFilesKey, - QJsonArray::fromStringList( - Utils::transform(m_files, &Utils::FilePath::toString))); + const std::optional files = m_cache.filePaths(); + if (files) { + object.insert(kFilesKey, QJsonArray::fromStringList( + Utils::transform(*files, &FilePath::toString))); + } if (m_exclusionFilters != kExclusionFiltersDefault) object.insert(kExclusionFiltersKey, QJsonArray::fromStringList(m_exclusionFilters)); } @@ -138,7 +138,10 @@ void DirectoryFilter::restoreState(const QJsonObject &object) m_directories = toFilePaths(object.value(kDirectoriesKey).toArray()); m_filters = toStringList( object.value(kFiltersKey).toArray(QJsonArray::fromStringList(kFiltersDefault))); - m_files = FileUtils::toFilePathList(toStringList(object.value(kFilesKey).toArray())); + if (object.contains(kFilesKey)) { + m_cache.setFilePaths(FileUtils::toFilePathList( + toStringList(object.value(kFilesKey).toArray()))); + } m_exclusionFilters = toStringList( object.value(kExclusionFiltersKey) .toArray(QJsonArray::fromStringList(kExclusionFiltersDefault))); @@ -161,7 +164,7 @@ void DirectoryFilter::restoreState(const QByteArray &state) in >> shortcut; in >> defaultFilter; in >> files; - m_files = FileUtils::toFilePathList(files); + m_cache.setFilePaths(FileUtils::toFilePathList(files)); if (!in.atEnd()) // Qt Creator 4.3 and later in >> m_exclusionFilters; else @@ -178,7 +181,6 @@ void DirectoryFilter::restoreState(const QByteArray &state) } else { ILocatorFilter::restoreState(state); } - updateFileIterator(); } class DirectoryFilterOptions : public QDialog @@ -381,12 +383,6 @@ void DirectoryFilter::updateOptionButtons() m_dialog->removeButton->setEnabled(haveSelectedItem); } -void DirectoryFilter::updateFileIterator() -{ - m_cache.setFilePaths(m_files); - setFileIterator(new BaseFileFilter::ListIterator(m_files)); -} - void DirectoryFilter::setIsCustomFilter(bool value) { m_isCustomFilter = value; diff --git a/src/plugins/coreplugin/locator/directoryfilter.h b/src/plugins/coreplugin/locator/directoryfilter.h index 556c9937a30..485377d2a15 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.h +++ b/src/plugins/coreplugin/locator/directoryfilter.h @@ -3,19 +3,14 @@ #pragma once -#include "basefilefilter.h" +#include "ilocatorfilter.h" #include -#include - namespace Core { -// TODO: Don't derive from BaseFileFilter, flatten the hierarchy -class CORE_EXPORT DirectoryFilter : public BaseFileFilter +class CORE_EXPORT DirectoryFilter : public ILocatorFilter { - Q_OBJECT - public: DirectoryFilter(Utils::Id id); void restoreState(const QByteArray &state) override; @@ -38,8 +33,6 @@ private: void handleEditDirectory(); void handleRemoveDirectory(); void updateOptionButtons(); - // TODO: Remove me, replace with direct "m_cache.setFilePaths()" call - void updateFileIterator(); Utils::FilePaths m_directories; QStringList m_filters; @@ -47,8 +40,6 @@ private: // Our config dialog, uses in addDirectory and editDirectory // to give their dialogs the right parent class DirectoryFilterOptions *m_dialog = nullptr; - // TODO: Remove me, use the cache instead. - Utils::FilePaths m_files; bool m_isCustomFilter = true; LocatorFileCache m_cache; }; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 4fadef96d8e..45ae41c8fdd 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -1361,6 +1361,11 @@ void LocatorFileCache::setGeneratorProvider(const GeneratorProvider &provider) d->setGeneratorProvider(provider); } +std::optional LocatorFileCache::filePaths() const +{ + return d->m_filePaths; +} + /*! Sets the file path generator. @@ -1413,6 +1418,7 @@ void LocatorFileCache::setFilePathsGenerator(const FilePathsGenerator &generator void LocatorFileCache::setFilePaths(const FilePaths &filePaths) { setFilePathsGenerator(filePathsGenerator(filePaths)); + d->m_filePaths = filePaths; } /*! diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index b7b8618ea96..fb70648967e 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -321,6 +321,8 @@ public: void setFilePaths(const Utils::FilePaths &filePaths); void setGeneratorProvider(const GeneratorProvider &provider); + std::optional filePaths() const; + static FilePathsGenerator filePathsGenerator(const Utils::FilePaths &filePaths); LocatorMatcherTask matcher() const; From 7dd27301ab2ea3b5d049d167d51dca8b9b5461d5 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 16:30:11 +0200 Subject: [PATCH 1023/1447] Beautifier: Base Beautifier::GeneralSettings on Core::PagedSettings This also uses the "Enable auto format on file save" bool directly for the now-checked group box. Change-Id: I7f3f392828f6ccfda99fa1d757f49cb9e3b6bc1b Reviewed-by: Alessandro Portale --- src/plugins/beautifier/CMakeLists.txt | 1 - src/plugins/beautifier/beautifier.qbs | 2 - src/plugins/beautifier/beautifierplugin.cpp | 18 +-- src/plugins/beautifier/generaloptionspage.cpp | 103 ------------- src/plugins/beautifier/generaloptionspage.h | 16 -- src/plugins/beautifier/generalsettings.cpp | 144 +++++++----------- src/plugins/beautifier/generalsettings.h | 33 ++-- 7 files changed, 75 insertions(+), 242 deletions(-) delete mode 100644 src/plugins/beautifier/generaloptionspage.cpp delete mode 100644 src/plugins/beautifier/generaloptionspage.h diff --git a/src/plugins/beautifier/CMakeLists.txt b/src/plugins/beautifier/CMakeLists.txt index d721f1ef201..cdfacccce1a 100644 --- a/src/plugins/beautifier/CMakeLists.txt +++ b/src/plugins/beautifier/CMakeLists.txt @@ -19,7 +19,6 @@ add_qtc_plugin(Beautifier configurationdialog.cpp configurationdialog.h configurationeditor.cpp configurationeditor.h configurationpanel.cpp configurationpanel.h - generaloptionspage.cpp generaloptionspage.h generalsettings.cpp generalsettings.h uncrustify/uncrustify.cpp uncrustify/uncrustify.h uncrustify/uncrustifyconstants.h diff --git a/src/plugins/beautifier/beautifier.qbs b/src/plugins/beautifier/beautifier.qbs index d1160ae5f59..0f85ca29b57 100644 --- a/src/plugins/beautifier/beautifier.qbs +++ b/src/plugins/beautifier/beautifier.qbs @@ -25,8 +25,6 @@ QtcPlugin { "configurationeditor.h", "configurationpanel.cpp", "configurationpanel.h", - "generaloptionspage.cpp", - "generaloptionspage.h", "generalsettings.cpp", "generalsettings.h", ] diff --git a/src/plugins/beautifier/beautifierplugin.cpp b/src/plugins/beautifier/beautifierplugin.cpp index 3057f2034ac..b849976a05b 100644 --- a/src/plugins/beautifier/beautifierplugin.cpp +++ b/src/plugins/beautifier/beautifierplugin.cpp @@ -5,7 +5,6 @@ #include "beautifierconstants.h" #include "beautifiertr.h" -#include "generaloptionspage.h" #include "generalsettings.h" #include "artisticstyle/artisticstyle.h" @@ -80,12 +79,6 @@ public: &uncrustifyBeautifier, &clangFormatBeautifier }; - - GeneralOptionsPage optionsPage {{ - artisticStyleBeautifier.id(), - uncrustifyBeautifier.id(), - clangFormatBeautifier.id() - }}; }; static BeautifierPluginPrivate *dd = nullptr; @@ -112,6 +105,9 @@ ExtensionSystem::IPlugin::ShutdownFlag BeautifierPlugin::aboutToShutdown() BeautifierPluginPrivate::BeautifierPluginPrivate() { + for (BeautifierAbstractTool *tool : m_tools) + generalSettings.autoFormatTools.addOption(tool->id()); + updateActions(); const Core::EditorManager *editorManager = Core::EditorManager::instance(); @@ -129,14 +125,14 @@ void BeautifierPluginPrivate::updateActions(Core::IEditor *editor) void BeautifierPluginPrivate::autoFormatOnSave(Core::IDocument *document) { - if (!generalSettings.autoFormatOnSave()) + if (!generalSettings.autoFormatOnSave.value()) return; - if (!isAutoFormatApplicable(document, generalSettings.autoFormatMime())) + if (!isAutoFormatApplicable(document, generalSettings.allowedMimeTypes())) return; // Check if file is contained in the current project (if wished) - if (generalSettings.autoFormatOnlyCurrentProject()) { + if (generalSettings.autoFormatOnlyCurrentProject.value()) { const ProjectExplorer::Project *pro = ProjectExplorer::ProjectTree::currentProject(); if (!pro || pro->files([document](const ProjectExplorer::Node *n) { @@ -149,7 +145,7 @@ void BeautifierPluginPrivate::autoFormatOnSave(Core::IDocument *document) } // Find tool to use by id and format file! - const QString id = generalSettings.autoFormatTool(); + const QString id = generalSettings.autoFormatTools.stringValue(); auto tool = std::find_if(std::begin(m_tools), std::end(m_tools), [&id](const BeautifierAbstractTool *t){return t->id() == id;}); if (tool != std::end(m_tools)) { diff --git a/src/plugins/beautifier/generaloptionspage.cpp b/src/plugins/beautifier/generaloptionspage.cpp deleted file mode 100644 index 5e03499a99e..00000000000 --- a/src/plugins/beautifier/generaloptionspage.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "generaloptionspage.h" - -#include "beautifierconstants.h" -#include "beautifiertr.h" -#include "generalsettings.h" - -#include - -#include -#include -#include -#include -#include - -namespace Beautifier::Internal { - -class GeneralOptionsPageWidget : public Core::IOptionsPageWidget -{ -public: - explicit GeneralOptionsPageWidget(const QStringList &toolIds); - -private: - void apply() final; - - QCheckBox *m_autoFormat; - QComboBox *m_autoFormatTool; - QLineEdit *m_autoFormatMime; - QCheckBox *m_autoFormatOnlyCurrentProject; -}; - -GeneralOptionsPageWidget::GeneralOptionsPageWidget(const QStringList &toolIds) -{ - auto settings = GeneralSettings::instance(); - - m_autoFormat = new QCheckBox(Tr::tr("Enable auto format on file save")); - m_autoFormat->setChecked(settings->autoFormatOnSave()); - - auto toolLabel = new QLabel(Tr::tr("Tool:")); - toolLabel->setEnabled(false); - - auto mimeLabel = new QLabel(Tr::tr("Restrict to MIME types:")); - mimeLabel->setEnabled(false); - - m_autoFormatMime = new QLineEdit(settings->autoFormatMimeAsString()); - m_autoFormatMime->setEnabled(false); - - m_autoFormatOnlyCurrentProject = - new QCheckBox(Tr::tr("Restrict to files contained in the current project")); - m_autoFormatOnlyCurrentProject->setEnabled(false); - m_autoFormatOnlyCurrentProject->setChecked(settings->autoFormatOnlyCurrentProject()); - - m_autoFormatTool = new QComboBox; - m_autoFormatTool->setEnabled(false); - m_autoFormatTool->addItems(toolIds); - const int index = m_autoFormatTool->findText(settings->autoFormatTool()); - m_autoFormatTool->setCurrentIndex(qMax(index, 0)); - - using namespace Layouting; - - Column { - Group { - title(Tr::tr("Automatic Formatting on File Save")), - Form { - Span(2, m_autoFormat), br, - toolLabel, m_autoFormatTool, br, - mimeLabel, m_autoFormatMime, br, - Span(2, m_autoFormatOnlyCurrentProject) - } - }, - st - }.attachTo(this); - - connect(m_autoFormat, &QCheckBox::toggled, m_autoFormatTool, &QComboBox::setEnabled); - connect(m_autoFormat, &QCheckBox::toggled, m_autoFormatMime, &QLineEdit::setEnabled); - connect(m_autoFormat, &QCheckBox::toggled, toolLabel, &QLabel::setEnabled); - connect(m_autoFormat, &QCheckBox::toggled, mimeLabel, &QLabel::setEnabled); - connect(m_autoFormat, &QCheckBox::toggled, m_autoFormatOnlyCurrentProject, &QCheckBox::setEnabled); -} - -void GeneralOptionsPageWidget::apply() -{ - auto settings = GeneralSettings::instance(); - settings->setAutoFormatOnSave(m_autoFormat->isChecked()); - settings->setAutoFormatTool(m_autoFormatTool->currentText()); - settings->setAutoFormatMime(m_autoFormatMime->text()); - settings->setAutoFormatOnlyCurrentProject(m_autoFormatOnlyCurrentProject->isChecked()); - settings->save(); -} - -GeneralOptionsPage::GeneralOptionsPage(const QStringList &toolIds) -{ - setId(Constants::OPTION_GENERAL_ID); - setDisplayName(Tr::tr("General")); - setCategory(Constants::OPTION_CATEGORY); - setDisplayCategory(Tr::tr("Beautifier")); - setWidgetCreator([toolIds] { return new GeneralOptionsPageWidget(toolIds); }); - setCategoryIconPath(":/beautifier/images/settingscategory_beautifier.png"); -} - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/generaloptionspage.h b/src/plugins/beautifier/generaloptionspage.h deleted file mode 100644 index 885a27cb199..00000000000 --- a/src/plugins/beautifier/generaloptionspage.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Beautifier::Internal { - -class GeneralOptionsPage final : public Core::IOptionsPage -{ -public: - explicit GeneralOptionsPage(const QStringList &toolIds); -}; - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/generalsettings.cpp b/src/plugins/beautifier/generalsettings.cpp index 218f6963f37..d9ae27b3fc3 100644 --- a/src/plugins/beautifier/generalsettings.cpp +++ b/src/plugins/beautifier/generalsettings.cpp @@ -3,114 +3,88 @@ #include "generalsettings.h" -#include +#include "beautifierconstants.h" +#include "beautifiertr.h" #include #include -#include +#include + +using namespace Utils; namespace Beautifier::Internal { -const char AUTO_FORMAT_TOOL[] = "autoFormatTool"; -const char AUTO_FORMAT_MIME[] = "autoFormatMime"; -const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "autoFormatOnlyCurrentProject"; - static GeneralSettings *m_instance; -GeneralSettings::GeneralSettings() -{ - m_instance = this; - read(); -} - GeneralSettings *GeneralSettings::instance() { return m_instance; } -void GeneralSettings::read() +GeneralSettings::GeneralSettings() { - QSettings *s = Core::ICore::settings(); - s->beginGroup(Utils::Constants::BEAUTIFIER_SETTINGS_GROUP); - s->beginGroup(Utils::Constants::BEAUTIFIER_GENERAL_GROUP); - m_autoFormatOnSave = s->value(Utils::Constants::BEAUTIFIER_AUTO_FORMAT_ON_SAVE, false).toBool(); - m_autoFormatTool = s->value(AUTO_FORMAT_TOOL, QString()).toString(); - setAutoFormatMime(s->value(AUTO_FORMAT_MIME, "text/x-c++src;text/x-c++hdr").toString()); - m_autoFormatOnlyCurrentProject = s->value(AUTO_FORMAT_ONLY_CURRENT_PROJECT, true).toBool(); - s->endGroup(); - s->endGroup(); + m_instance = this; + + setId(Constants::OPTION_GENERAL_ID); + setDisplayName(Tr::tr("General")); + setCategory(Constants::OPTION_CATEGORY); + setDisplayCategory(Tr::tr("Beautifier")); + setCategoryIconPath(":/beautifier/images/settingscategory_beautifier.png"); + setSettingsGroups("Beautifier", "General"); + setSettings(this); + setAutoApply(false); + + registerAspect(&autoFormatOnSave); + autoFormatOnSave.setSettingsKey(Utils::Constants::BEAUTIFIER_AUTO_FORMAT_ON_SAVE); + autoFormatOnSave.setDefaultValue(false); + autoFormatOnSave.setLabelText(Tr::tr("Enable auto format on file save")); + + registerAspect(&autoFormatOnlyCurrentProject); + autoFormatOnlyCurrentProject.setSettingsKey("autoFormatOnlyCurrentProject"); + autoFormatOnlyCurrentProject.setDefaultValue(true); + autoFormatOnlyCurrentProject.setLabelText(Tr::tr("Restrict to files contained in the current project")); + + registerAspect(&autoFormatTools); + autoFormatTools.setSettingsKey("autoFormatTool"); + autoFormatTools.setLabelText(Tr::tr("Tool:")); + autoFormatTools.setDefaultValue(0); + autoFormatTools.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); + + registerAspect(&autoFormatMime); + autoFormatMime.setSettingsKey("autoFormatMime"); + autoFormatMime.setDefaultValue("text/x-c++src;text/x-c++hdr"); + autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:")); + autoFormatMime.setDisplayStyle(StringAspect::LineEditDisplay); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + Column { + Group { + title(Tr::tr("Automatic Formatting on File Save")), + autoFormatOnSave.groupChecker(), + Form { + autoFormatTools, br, + autoFormatMime, br, + Span(2, autoFormatOnlyCurrentProject) + } + }, + st + }.attachTo(widget); + }); } -void GeneralSettings::save() +QList GeneralSettings::allowedMimeTypes() const { - QSettings *s = Core::ICore::settings(); - s->beginGroup(Utils::Constants::BEAUTIFIER_SETTINGS_GROUP); - s->beginGroup(Utils::Constants::BEAUTIFIER_GENERAL_GROUP); - s->setValue(Utils::Constants::BEAUTIFIER_AUTO_FORMAT_ON_SAVE, m_autoFormatOnSave); - s->setValue(AUTO_FORMAT_TOOL, m_autoFormatTool); - s->setValue(AUTO_FORMAT_MIME, autoFormatMimeAsString()); - s->setValue(AUTO_FORMAT_ONLY_CURRENT_PROJECT, m_autoFormatOnlyCurrentProject); - s->endGroup(); - s->endGroup(); -} + const QStringList stringTypes = autoFormatMime.value().split(';'); -bool GeneralSettings::autoFormatOnSave() const -{ - return m_autoFormatOnSave; -} - -void GeneralSettings::setAutoFormatOnSave(bool autoFormatOnSave) -{ - m_autoFormatOnSave = autoFormatOnSave; -} - -QString GeneralSettings::autoFormatTool() const -{ - return m_autoFormatTool; -} - -void GeneralSettings::setAutoFormatTool(const QString &autoFormatTool) -{ - m_autoFormatTool = autoFormatTool; -} - -QList GeneralSettings::autoFormatMime() const -{ - return m_autoFormatMime; -} - -QString GeneralSettings::autoFormatMimeAsString() const -{ - return Utils::transform(m_autoFormatMime, &Utils::MimeType::name).join("; "); -} - -void GeneralSettings::setAutoFormatMime(const QList &autoFormatMime) -{ - m_autoFormatMime = autoFormatMime; -} - -void GeneralSettings::setAutoFormatMime(const QString &mimeList) -{ - const QStringList stringTypes = mimeList.split(';'); - QList types; - types.reserve(stringTypes.count()); + QList types; for (QString t : stringTypes) { t = t.trimmed(); - const Utils::MimeType mime = Utils::mimeTypeForName(t); + const MimeType mime = Utils::mimeTypeForName(t); if (mime.isValid()) types << mime; } - setAutoFormatMime(types); -} - -bool GeneralSettings::autoFormatOnlyCurrentProject() const -{ - return m_autoFormatOnlyCurrentProject; -} - -void GeneralSettings::setAutoFormatOnlyCurrentProject(bool autoFormatOnlyCurrentProject) -{ - m_autoFormatOnlyCurrentProject = autoFormatOnlyCurrentProject; + return types; } } // Beautifier::Internal diff --git a/src/plugins/beautifier/generalsettings.h b/src/plugins/beautifier/generalsettings.h index b381dacb26a..2c6743301ba 100644 --- a/src/plugins/beautifier/generalsettings.h +++ b/src/plugins/beautifier/generalsettings.h @@ -5,38 +5,23 @@ #include -#include +#include namespace Beautifier::Internal { -class GeneralSettings +class GeneralSettings : public Core::PagedSettings { public: - explicit GeneralSettings(); + GeneralSettings(); + static GeneralSettings *instance(); - void read(); - void save(); + QList allowedMimeTypes() const; - bool autoFormatOnSave() const; - void setAutoFormatOnSave(bool autoFormatOnSave); - - QString autoFormatTool() const; - void setAutoFormatTool(const QString &autoFormatTool); - - QList autoFormatMime() const; - QString autoFormatMimeAsString() const; - void setAutoFormatMime(const QList &autoFormatMime); - void setAutoFormatMime(const QString &mimeList); - - bool autoFormatOnlyCurrentProject() const; - void setAutoFormatOnlyCurrentProject(bool autoFormatOnlyCurrentProject); - -private: - bool m_autoFormatOnSave = false; - bool m_autoFormatOnlyCurrentProject = true; - QString m_autoFormatTool; - QList m_autoFormatMime; + Utils::BoolAspect autoFormatOnSave; + Utils::BoolAspect autoFormatOnlyCurrentProject; + Utils::SelectionAspect autoFormatTools; + Utils::StringAspect autoFormatMime; }; } // Beautifier::Internal From cfbdee3a3bff25cb83736bf674f5036cd7d5c165 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 17:15:48 +0200 Subject: [PATCH 1024/1447] Beautifier: Base AbstractSettings on Utils::AspectContainer Plan is to eliminate AbstractSettings as much as possible and use Aspect functionality instead. Change-Id: Idb71fb4df0893ffa4713b0182c21725f0c71089e Reviewed-by: Alessandro Portale --- src/plugins/beautifier/abstractsettings.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/beautifier/abstractsettings.h b/src/plugins/beautifier/abstractsettings.h index d386313e1b5..25baa838858 100644 --- a/src/plugins/beautifier/abstractsettings.h +++ b/src/plugins/beautifier/abstractsettings.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include @@ -28,7 +29,7 @@ namespace Beautifier::Internal { class VersionUpdater; -class AbstractSettings : public QObject +class AbstractSettings : public Utils::AspectContainer { Q_OBJECT From ddee1c92a48dde69d236eb14570f5a03d07dbe42 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 13:18:07 +0200 Subject: [PATCH 1025/1447] Utils: Add operator() as a way to access .value() for some aspects This can make the user code look a bit nicer. Change-Id: I98867114810ede2f04342144f600682ff3c261b4 Reviewed-by: Alessandro Portale Reviewed-by: Christian Stenger --- src/libs/utils/aspects.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index c511595e1ba..3e4bd9ca967 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -229,6 +229,7 @@ public: void setVolatileValue(const QVariant &val) override; void emitChangedValue() override; + bool operator()() const { return value(); } bool value() const; void setValue(bool val); bool defaultValue() const; @@ -372,6 +373,8 @@ public: // Hook between UI and StringAspect: using ValueAcceptor = std::function(const QString &, const QString &)>; void setValueAcceptor(ValueAcceptor &&acceptor); + + QString operator()() const { return value(); } QString value() const; void setValue(const QString &val); @@ -449,6 +452,7 @@ public: QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; + qint64 operator()() const { return value(); } qint64 value() const; void setValue(qint64 val); @@ -486,6 +490,7 @@ public: QVariant volatileValue() const override; void setVolatileValue(const QVariant &val) override; + double operator()() const { return value(); } double value() const; void setValue(double val); From 5cf5b1ae3f94edcffab95044b9d361d5d6a28b17 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 14:13:28 +0200 Subject: [PATCH 1026/1447] Utils: Add an AspectContainer::changed() signal In contrast to applied() only emitted if anything was dirty before. Ideally, applied() would not be needed, but I am not sure about downstream uses. Change-Id: Ie0c293b8730c503fc4409884a33207ee9ca5f129 Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 5 +++++ src/libs/utils/aspects.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 0f75cfcbded..1eecb1de17d 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2475,10 +2475,15 @@ void AspectContainer::setSettingsGroups(const QString &groupKey, const QString & void AspectContainer::apply() { + const bool willChange = isDirty(); + for (BaseAspect *aspect : std::as_const(d->m_items)) aspect->apply(); emit applied(); + + if (willChange) + emit changed(); } void AspectContainer::cancel() diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 3e4bd9ca967..266a41f8ee1 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -695,6 +695,7 @@ public: signals: void applied(); + void changed(); void fromMapFinished(); private: From 2b54ef80d18f84e628ae0c38c8f67dee1c059f18 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 12 May 2023 16:22:04 +0200 Subject: [PATCH 1027/1447] LocatorFilters: Use ILocatorFilter::createRegExp() consistently Use it consistently inside ILocatorFilter subclasses, instead of FuzzyMatcher. Drop repeated default arguments from the caller. Change-Id: I53762f27216a30ed0281f3d0ddc5e50c7452559a Reviewed-by: Eike Ziller --- src/plugins/cppeditor/cpplocatorfilter.cpp | 2 +- src/plugins/languageclient/locatorfilter.cpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 4e78d8130f7..5f0904dd035 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -203,7 +203,7 @@ void matchesForCurrentDocument(QPromise &promise, const LocatorStorage &st const FilePath ¤tFileName) { const QString input = storage.input(); - const QRegularExpression regexp = FuzzyMatcher::createRegExp(input, Qt::CaseInsensitive, false); + const QRegularExpression regexp = ILocatorFilter::createRegExp(input); if (!regexp.isValid()) return; diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 7ac85c165ba..5d52f28f232 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -293,11 +293,8 @@ Core::LocatorFilterEntries currentDocumentSymbols(const QString &input, const CurrentDocumentSymbolsData ¤tSymbolsData, const DocSymbolModifier &docSymbolModifier) { - const FuzzyMatcher::CaseSensitivity caseSensitivity - = ILocatorFilter::caseSensitivity(input) == Qt::CaseSensitive - ? FuzzyMatcher::CaseSensitivity::CaseSensitive - : FuzzyMatcher::CaseSensitivity::CaseInsensitive; - const QRegularExpression regExp = FuzzyMatcher::createRegExp(input, caseSensitivity); + const Qt::CaseSensitivity caseSensitivity = ILocatorFilter::caseSensitivity(input); + const QRegularExpression regExp = ILocatorFilter::createRegExp(input, caseSensitivity); if (!regExp.isValid()) return {}; From 4c1a161abd946b4bf51c6cc573728cf25f47876e Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 16:27:01 +0200 Subject: [PATCH 1028/1447] Utils: Fix some IntegerAspect value display issue ... when a display scale factor was set. Change-Id: I764db99e444f9cc70871c3dbec101d0b65542c4a Reviewed-by: Christian Stenger --- src/libs/utils/aspects.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 1eecb1de17d..8aa1f77beea 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1913,7 +1913,7 @@ void IntegerAspect::addToLayout(Layouting::LayoutItem &parent) if (isAutoApply()) { connect(d->m_spinBox.data(), &QSpinBox::valueChanged, - this, [this] { setValue(d->m_spinBox->value()); }); + this, [this] { setValue(d->m_spinBox->value() * d->m_displayScaleFactor); }); } } @@ -1940,7 +1940,7 @@ void IntegerAspect::setValue(qint64 value) { if (BaseAspect::setValueQuietly(value)) { if (d->m_spinBox) - d->m_spinBox->setValue(value); + d->m_spinBox->setValue(value / d->m_displayScaleFactor); //qDebug() << "SetValue: Changing" << labelText() << " to " << value; emit changed(); //QTC_CHECK(!labelText().isEmpty()); From 30af7a9503c3848ac9cb35e1aebfc28d51f41d07 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 11:00:00 +0200 Subject: [PATCH 1029/1447] AutoTests: Aspectify parts of main settings Change-Id: I407b5102e1f2a6647f6fdca01a61dfa422c5d3ee Reviewed-by: Christian Stenger --- src/plugins/autotest/autotestplugin.cpp | 7 +- src/plugins/autotest/autotestplugin.h | 2 - .../autotest/boost/boosttestconfiguration.cpp | 3 +- .../autotest/catch/catchconfiguration.cpp | 3 +- src/plugins/autotest/ctest/ctesttreeitem.cpp | 2 +- .../autotest/gtest/gtestconfiguration.cpp | 3 +- src/plugins/autotest/qtest/qttest_utils.cpp | 5 +- .../autotest/qtest/qttestconfiguration.cpp | 3 +- .../autotest/quick/quicktestconfiguration.cpp | 3 +- src/plugins/autotest/testframeworkmanager.cpp | 3 +- src/plugins/autotest/testresultdelegate.cpp | 7 +- src/plugins/autotest/testresultmodel.cpp | 3 +- src/plugins/autotest/testresultspane.cpp | 8 +- src/plugins/autotest/testrunner.cpp | 12 +- src/plugins/autotest/testsettings.cpp | 159 +++++++++++----- src/plugins/autotest/testsettings.h | 63 ++++--- src/plugins/autotest/testsettingspage.cpp | 177 ++++-------------- src/plugins/autotest/testsettingspage.h | 4 +- 18 files changed, 205 insertions(+), 262 deletions(-) diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp index 28475f3870b..d6bfc6f9a88 100644 --- a/src/plugins/autotest/autotestplugin.cpp +++ b/src/plugins/autotest/autotestplugin.cpp @@ -96,7 +96,7 @@ public: void onRunUnderCursorTriggered(TestRunMode mode); TestSettings m_settings; - TestSettingsPage m_testSettingPage{&m_settings}; + TestSettingsPage m_testSettingPage; TestCodeParser m_testCodeParser; TestTreeModel m_testTreeModel{&m_testCodeParser}; @@ -178,11 +178,6 @@ AutotestPluginPrivate::~AutotestPluginPrivate() delete m_resultsPane; } -TestSettings *AutotestPlugin::settings() -{ - return &dd->m_settings; -} - TestProjectSettings *AutotestPlugin::projectSettings(ProjectExplorer::Project *project) { auto &settings = s_projectSettings[project]; diff --git a/src/plugins/autotest/autotestplugin.h b/src/plugins/autotest/autotestplugin.h index 8705a8a538d..e6daa0c7390 100644 --- a/src/plugins/autotest/autotestplugin.h +++ b/src/plugins/autotest/autotestplugin.h @@ -18,7 +18,6 @@ namespace Autotest { namespace Internal { class TestProjectSettings; -struct TestSettings; struct ChoicePair { @@ -43,7 +42,6 @@ public: void extensionsInitialized() override; ShutdownFlag aboutToShutdown() override; - static TestSettings *settings(); static TestProjectSettings *projectSettings(ProjectExplorer::Project *project); static TestFrameworks activeTestFrameworks(); static void updateMenuItemsEnabledState(); diff --git a/src/plugins/autotest/boost/boosttestconfiguration.cpp b/src/plugins/autotest/boost/boosttestconfiguration.cpp index 1df0bd6776b..e581cff50ee 100644 --- a/src/plugins/autotest/boost/boosttestconfiguration.cpp +++ b/src/plugins/autotest/boost/boosttestconfiguration.cpp @@ -6,7 +6,6 @@ #include "boosttestoutputreader.h" #include "boosttestsettings.h" -#include "../autotestplugin.h" #include "../itestframework.h" #include "../testsettings.h" @@ -106,7 +105,7 @@ QStringList BoostTestConfiguration::argumentsForTestRunner(QStringList *omitted) for (const QString &test : testCases()) arguments << "-t" << test; - if (AutotestPlugin::settings()->processArgs) { + if (TestSettings::instance()->processArgs()) { arguments << filterInterfering(runnable().command.arguments().split( ' ', Qt::SkipEmptyParts), omitted); } diff --git a/src/plugins/autotest/catch/catchconfiguration.cpp b/src/plugins/autotest/catch/catchconfiguration.cpp index 88f590d3521..a5036398688 100644 --- a/src/plugins/autotest/catch/catchconfiguration.cpp +++ b/src/plugins/autotest/catch/catchconfiguration.cpp @@ -6,7 +6,6 @@ #include "catchoutputreader.h" #include "catchtestsettings.h" -#include "../autotestplugin.h" #include "../itestframework.h" #include "../testsettings.h" @@ -80,7 +79,7 @@ QStringList CatchConfiguration::argumentsForTestRunner(QStringList *omitted) con arguments << "\"" + testCases().join("\", \"") + "\""; arguments << "--reporter" << "xml"; - if (AutotestPlugin::settings()->processArgs) { + if (TestSettings::instance()->processArgs()) { arguments << filterInterfering(runnable().command.arguments().split( ' ', Qt::SkipEmptyParts), omitted); } diff --git a/src/plugins/autotest/ctest/ctesttreeitem.cpp b/src/plugins/autotest/ctest/ctesttreeitem.cpp index dac1b6da008..9ffc06b028e 100644 --- a/src/plugins/autotest/ctest/ctesttreeitem.cpp +++ b/src/plugins/autotest/ctest/ctesttreeitem.cpp @@ -88,7 +88,7 @@ QList CTestTreeItem::testConfigurationsFor(const QStringLi return {}; const ProjectExplorer::BuildSystem *buildSystem = target->buildSystem(); - QStringList options{"--timeout", QString::number(AutotestPlugin::settings()->timeout / 1000)}; + QStringList options{"--timeout", QString::number(TestSettings::instance()->timeout() / 1000)}; auto ctestSettings = static_cast(testBase()->testSettings()); options << ctestSettings->activeSettingsAsOptions(); CommandLine command = buildSystem->commandLineForTests(selected, options); diff --git a/src/plugins/autotest/gtest/gtestconfiguration.cpp b/src/plugins/autotest/gtest/gtestconfiguration.cpp index 32e590ccb52..8680da1fcaf 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.cpp +++ b/src/plugins/autotest/gtest/gtestconfiguration.cpp @@ -6,7 +6,6 @@ #include "gtestoutputreader.h" #include "gtestsettings.h" -#include "../autotestplugin.h" #include "../itestframework.h" #include "../testsettings.h" @@ -55,7 +54,7 @@ QStringList filterInterfering(const QStringList &provided, QStringList *omitted) QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) const { QStringList arguments; - if (AutotestPlugin::settings()->processArgs) { + if (TestSettings::instance()->processArgs()) { arguments << filterInterfering(runnable().command.arguments().split( ' ', Qt::SkipEmptyParts), omitted); } diff --git a/src/plugins/autotest/qtest/qttest_utils.cpp b/src/plugins/autotest/qtest/qttest_utils.cpp index ab6048da084..9bedaa64c37 100644 --- a/src/plugins/autotest/qtest/qttest_utils.cpp +++ b/src/plugins/autotest/qtest/qttest_utils.cpp @@ -2,8 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qttest_utils.h" + #include "qttesttreeitem.h" -#include "../autotestplugin.h" +#include "../itestframework.h" #include "../testsettings.h" #include @@ -136,7 +137,7 @@ Environment prepareBasicEnvironment(const Environment &env) result.set("QT_FORCE_STDERR_LOGGING", "1"); result.set("QT_LOGGING_TO_CONSOLE", "1"); } - const int timeout = AutotestPlugin::settings()->timeout; + const int timeout = TestSettings::instance()->timeout(); if (timeout > 5 * 60 * 1000) // Qt5.5 introduced hard limit, Qt5.6.1 added env var to raise this result.set("QTEST_FUNCTION_TIMEOUT", QString::number(timeout)); return result; diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp index 37da244cc97..5dcf59a48e1 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.cpp +++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp @@ -7,7 +7,6 @@ #include "qttestsettings.h" #include "qttest_utils.h" -#include "../autotestplugin.h" #include "../itestframework.h" #include "../testsettings.h" @@ -40,7 +39,7 @@ TestOutputReader *QtTestConfiguration::createOutputReader(Process *app) const QStringList QtTestConfiguration::argumentsForTestRunner(QStringList *omitted) const { QStringList arguments; - if (AutotestPlugin::settings()->processArgs) { + if (TestSettings::instance()->processArgs()) { arguments.append(QTestUtils::filterInterfering( runnable().command.arguments().split(' ', Qt::SkipEmptyParts), omitted, false)); diff --git a/src/plugins/autotest/quick/quicktestconfiguration.cpp b/src/plugins/autotest/quick/quicktestconfiguration.cpp index cf316ca4896..e37b208ac44 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.cpp +++ b/src/plugins/autotest/quick/quicktestconfiguration.cpp @@ -3,7 +3,6 @@ #include "quicktestconfiguration.h" -#include "../autotestplugin.h" #include "../itestframework.h" #include "../qtest/qttestoutputreader.h" #include "../qtest/qttestsettings.h" @@ -33,7 +32,7 @@ TestOutputReader *QuickTestConfiguration::createOutputReader(Process *app) const QStringList QuickTestConfiguration::argumentsForTestRunner(QStringList *omitted) const { QStringList arguments; - if (AutotestPlugin::settings()->processArgs) { + if (TestSettings::instance()->processArgs()) { arguments.append(QTestUtils::filterInterfering (runnable().command.arguments().split(' ', Qt::SkipEmptyParts), omitted, true)); diff --git a/src/plugins/autotest/testframeworkmanager.cpp b/src/plugins/autotest/testframeworkmanager.cpp index 91fa3135930..3c6aff581db 100644 --- a/src/plugins/autotest/testframeworkmanager.cpp +++ b/src/plugins/autotest/testframeworkmanager.cpp @@ -3,7 +3,6 @@ #include "testframeworkmanager.h" -#include "autotestplugin.h" #include "testsettings.h" #include @@ -98,7 +97,7 @@ ITestTool *TestFrameworkManager::testToolForBuildSystemId(Id buildSystemId) void TestFrameworkManager::synchronizeSettings(QSettings *s) { - Internal::AutotestPlugin::settings()->fromSettings(s); + Internal::TestSettings::instance()->fromSettings(s); for (ITestFramework *framework : std::as_const(m_registeredFrameworks)) { if (ITestSettings *fSettings = framework->testSettings()) fSettings->readSettings(s); diff --git a/src/plugins/autotest/testresultdelegate.cpp b/src/plugins/autotest/testresultdelegate.cpp index 9b55623d572..c14b6c17032 100644 --- a/src/plugins/autotest/testresultdelegate.cpp +++ b/src/plugins/autotest/testresultdelegate.cpp @@ -3,7 +3,6 @@ #include "testresultdelegate.h" -#include "autotestplugin.h" #include "testresultmodel.h" #include "testsettings.h" @@ -162,10 +161,10 @@ void TestResultDelegate::clearCache() void TestResultDelegate::limitTextOutput(QString &output) const { - int maxLineCount = Internal::AutotestPlugin::settings()->resultDescriptionMaxSize; + int maxLineCount = Internal::TestSettings::instance()->resultDescriptionMaxSize(); bool limited = false; - if (Internal::AutotestPlugin::settings()->limitResultDescription && maxLineCount > 0) { + if (Internal::TestSettings::instance()->limitResultDescription() && maxLineCount > 0) { int index = -1; int lastChar = output.size() - 1; @@ -183,7 +182,7 @@ void TestResultDelegate::limitTextOutput(QString &output) const } } - if (AutotestPlugin::settings()->limitResultOutput && output.length() > outputLimit) { + if (TestSettings::instance()->limitResultOutput() && output.length() > outputLimit) { output = output.left(outputLimit); limited = true; } diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp index 434d6474103..f686692faad 100644 --- a/src/plugins/autotest/testresultmodel.cpp +++ b/src/plugins/autotest/testresultmodel.cpp @@ -4,7 +4,6 @@ #include "testresultmodel.h" #include "autotesticons.h" -#include "autotestplugin.h" #include "testrunner.h" #include "testsettings.h" #include "testtreeitem.h" @@ -274,7 +273,7 @@ void TestResultModel::addTestResult(const TestResult &testResult, bool autoExpan TestResultItem *newItem = new TestResultItem(testResult); TestResultItem *root = nullptr; - if (AutotestPlugin::settings()->displayApplication) { + if (TestSettings::instance()->displayApplication()) { const QString application = testResult.id(); if (!application.isEmpty()) { root = rootItem()->findFirstLevelChild([&application](TestResultItem *child) { diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp index 8997f43d1d3..3dbad31ea99 100644 --- a/src/plugins/autotest/testresultspane.cpp +++ b/src/plugins/autotest/testresultspane.cpp @@ -291,7 +291,7 @@ void TestResultsPane::clearContents() setIconBadgeNumber(0); navigateStateChanged(); m_summaryWidget->setVisible(false); - m_autoScroll = AutotestPlugin::settings()->autoScroll; + m_autoScroll = TestSettings::instance()->autoScroll(); connect(m_treeView->verticalScrollBar(), &QScrollBar::rangeChanged, this, &TestResultsPane::onScrollBarRangeChanged, Qt::UniqueConnection); m_textOutput->clear(); @@ -437,7 +437,7 @@ void TestResultsPane::onRunSelectedTriggered() void TestResultsPane::initializeFilterMenu() { - const bool omitIntern = AutotestPlugin::settings()->omitInternalMssg; + const bool omitIntern = TestSettings::instance()->omitInternalMsg(); // FilterModel has all messages enabled by default if (omitIntern) m_filterModel->toggleTestResultType(ResultType::MessageInternal); @@ -553,8 +553,8 @@ void TestResultsPane::onTestRunFinished() m_model->removeCurrentTestMessage(); disconnect(m_treeView->verticalScrollBar(), &QScrollBar::rangeChanged, this, &TestResultsPane::onScrollBarRangeChanged); - if (AutotestPlugin::settings()->popupOnFinish - && (!AutotestPlugin::settings()->popupOnFail || hasFailedTests(m_model))) { + if (TestSettings::instance()->popupOnFinish() + && (!TestSettings::instance()->popupOnFail() || hasFailedTests(m_model))) { popup(IOutputPane::NoModeSwitch); } createMarks(); diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 631b76aca11..68dddaf9511 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -258,7 +258,7 @@ static RunConfiguration *getRunConfiguration(const QString &buildTargetKey) int TestRunner::precheckTestConfigurations() { - const bool omitWarnings = AutotestPlugin::settings()->omitRunConfigWarn; + const bool omitWarnings = TestSettings::instance()->omitRunConfigWarn(); int testCaseCount = 0; for (ITestConfiguration *itc : std::as_const(m_selectedTests)) { if (itc->testBase()->type() == ITestBase::Tool) { @@ -402,7 +402,7 @@ void TestRunner::runTestsHelper() } process.setEnvironment(environment); - m_cancelTimer.setInterval(AutotestPlugin::settings()->timeout); + m_cancelTimer.setInterval(TestSettings::instance()->timeout()); m_cancelTimer.start(); qCInfo(runnerLog) << "Command:" << process.commandLine().executable(); @@ -465,7 +465,7 @@ void TestRunner::runTestsHelper() cancelCurrent(UserCanceled); }); - if (AutotestPlugin::settings()->popupOnStart) + if (TestSettings::instance()->popupOnStart()) AutotestPlugin::popupResultsPane(); m_taskTree->start(); @@ -588,7 +588,7 @@ void TestRunner::debugTests() connect(runControl, &RunControl::stopped, this, &TestRunner::onFinished); m_finishDebugConnect = connect(runControl, &RunControl::finished, this, &TestRunner::onFinished); ProjectExplorerPlugin::startRunControl(runControl); - if (useOutputProcessor && AutotestPlugin::settings()->popupOnStart) + if (useOutputProcessor && TestSettings::instance()->popupOnStart()) AutotestPlugin::popupResultsPane(); } @@ -669,10 +669,10 @@ static RunAfterBuildMode runAfterBuild() return RunAfterBuildMode::None; if (!project->namedSettings(Constants::SK_USE_GLOBAL).isValid()) - return AutotestPlugin::settings()->runAfterBuild; + return TestSettings::instance()->runAfterBuildMode(); TestProjectSettings *projectSettings = AutotestPlugin::projectSettings(project); - return projectSettings->useGlobalSettings() ? AutotestPlugin::settings()->runAfterBuild + return projectSettings->useGlobalSettings() ? TestSettings::instance()->runAfterBuildMode() : projectSettings->runAfterBuild(); } diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp index 6de76d815fc..001bf7fe07c 100644 --- a/src/plugins/autotest/testsettings.cpp +++ b/src/plugins/autotest/testsettings.cpp @@ -4,53 +4,123 @@ #include "testsettings.h" #include "autotestconstants.h" +#include "autotesttr.h" #include "testframeworkmanager.h" -#include - #include -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { -static const char timeoutKey[] = "Timeout"; -static const char omitInternalKey[] = "OmitInternal"; -static const char omitRunConfigWarnKey[] = "OmitRCWarnings"; -static const char limitResultOutputKey[] = "LimitResultOutput"; -static const char limitResultDescriptionKey[] = "LimitResultDescription"; -static const char resultDescriptionMaxSizeKey[] = "ResultDescriptionMaxSize"; -static const char autoScrollKey[] = "AutoScrollResults"; -static const char processArgsKey[] = "ProcessArgs"; -static const char displayApplicationKey[] = "DisplayApp"; -static const char popupOnStartKey[] = "PopupOnStart"; -static const char popupOnFinishKey[] = "PopupOnFinish"; -static const char popupOnFailKey[] = "PopupOnFail"; -static const char runAfterBuildKey[] = "RunAfterBuild"; static const char groupSuffix[] = ".group"; constexpr int defaultTimeout = 60000; -TestSettings::TestSettings() - : timeout(defaultTimeout) +static TestSettings *s_instance; + +TestSettings *TestSettings::instance() { + return s_instance; +} + +TestSettings::TestSettings() +{ + s_instance = this; + + setSettingsGroup(Constants::SETTINGSGROUP); + + registerAspect(&timeout); + timeout.setSettingsKey("Timeout"); + timeout.setDefaultValue(defaultTimeout); + timeout.setRange(5000, 36'000'000); // 36 Mio ms = 36'000 s = 10 h + timeout.setSuffix(Tr::tr(" s")); // we show seconds, but store milliseconds + timeout.setDisplayScaleFactor(1000); + timeout.setToolTip(Tr::tr("Timeout used when executing test cases. This will apply " + "for each test case on its own, not the whole project.")); + + registerAspect(&omitInternalMsg); + omitInternalMsg.setSettingsKey("OmitInternal"); + omitInternalMsg.setDefaultValue(true); + omitInternalMsg.setLabelText(Tr::tr("Omit internal messages")); + omitInternalMsg.setToolTip(Tr::tr("Hides internal messages by default. " + "You can still enable them by using the test results filter.")); + + registerAspect(&omitRunConfigWarn); + omitRunConfigWarn.setSettingsKey("OmitRCWarnings"); + omitRunConfigWarn.setLabelText(Tr::tr("Omit run configuration warnings")); + omitRunConfigWarn.setToolTip(Tr::tr("Hides warnings related to a deduced run configuration.")); + + registerAspect(&limitResultOutput); + limitResultOutput.setSettingsKey("LimitResultOutput"); + limitResultOutput.setDefaultValue(true); + limitResultOutput.setLabelText(Tr::tr("Limit result output")); + limitResultOutput.setToolTip(Tr::tr("Limits result output to 100000 characters.")); + + registerAspect(&limitResultDescription); + limitResultDescription.setSettingsKey("LimitResultDescription"); + limitResultDescription.setLabelText(Tr::tr("Limit result description:")); + limitResultDescription.setToolTip( + Tr::tr("Limit number of lines shown in test result tooltip and description.")); + + registerAspect(&resultDescriptionMaxSize); + resultDescriptionMaxSize.setSettingsKey("ResultDescriptionMaxSize"); + resultDescriptionMaxSize.setDefaultValue(10); + resultDescriptionMaxSize.setRange(1, 100000); + resultDescriptionMaxSize.setEnabler(&limitResultDescription); + + registerAspect(&autoScroll); + autoScroll.setSettingsKey("AutoScrollResults"); + autoScroll.setDefaultValue(true); + autoScroll.setLabelText(Tr::tr("Automatically scroll results")); + autoScroll.setToolTip(Tr::tr("Automatically scrolls down when new items are added " + "and scrollbar is at bottom.")); + + registerAspect(&processArgs); + processArgs.setSettingsKey("ProcessArgs"); + processArgs.setLabelText(Tr::tr("Process arguments")); + processArgs.setToolTip( + Tr::tr("Allow passing arguments specified on the respective run configuration.\n" + "Warning: this is an experimental feature and might lead to failing to " + "execute the test executable.")); + + registerAspect(&displayApplication); + displayApplication.setSettingsKey("DisplayApp"); + displayApplication.setLabelText(Tr::tr("Group results by application")); + + registerAspect(&popupOnStart); + popupOnStart.setSettingsKey("PopupOnStart"); + popupOnStart.setLabelText(Tr::tr("Open results when tests start")); + popupOnStart.setToolTip( + Tr::tr("Displays test results automatically when tests are started.")); + + registerAspect(&popupOnFinish); + popupOnFinish.setSettingsKey("PopupOnFinish"); + popupOnFinish.setDefaultValue(true); + popupOnFinish.setLabelText(Tr::tr("Open results when tests finish")); + popupOnFinish.setToolTip( + Tr::tr("Displays test results automatically when tests are finished.")); + + registerAspect(&popupOnFail); + popupOnFail.setSettingsKey("PopupOnFail"); + popupOnFail.setLabelText(Tr::tr("Only for unsuccessful test runs")); + popupOnFail.setEnabler(&popupOnFinish); + popupOnFail.setToolTip(Tr::tr("Displays test results only if the test run contains " + "failed, fatal or unexpectedly passed tests.")); + + registerAspect(&runAfterBuild); + runAfterBuild.setSettingsKey("RunAfterBuild"); + runAfterBuild.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); + runAfterBuild.setToolTip(Tr::tr("Runs chosen tests automatically if a build succeeded.")); + runAfterBuild.addOption(Tr::tr("None")); + runAfterBuild.addOption(Tr::tr("All")); + runAfterBuild.addOption(Tr::tr("Selected")); } void TestSettings::toSettings(QSettings *s) const { + AspectContainer::writeSettings(s); + s->beginGroup(Constants::SETTINGSGROUP); - s->setValue(timeoutKey, timeout); - s->setValue(omitInternalKey, omitInternalMssg); - s->setValue(omitRunConfigWarnKey, omitRunConfigWarn); - s->setValue(limitResultOutputKey, limitResultOutput); - s->setValue(limitResultDescriptionKey, limitResultDescription); - s->setValue(resultDescriptionMaxSizeKey, resultDescriptionMaxSize); - s->setValue(autoScrollKey, autoScroll); - s->setValue(processArgsKey, processArgs); - s->setValue(displayApplicationKey, displayApplication); - s->setValue(popupOnStartKey, popupOnStart); - s->setValue(popupOnFinishKey, popupOnFinish); - s->setValue(popupOnFailKey, popupOnFail); - s->setValue(runAfterBuildKey, int(runAfterBuild)); + // store frameworks and their current active and grouping state for (auto it = frameworks.cbegin(); it != frameworks.cend(); ++it) { const Utils::Id &id = it.key(); @@ -65,21 +135,10 @@ void TestSettings::toSettings(QSettings *s) const void TestSettings::fromSettings(QSettings *s) { + AspectContainer::readSettings(s); + s->beginGroup(Constants::SETTINGSGROUP); - timeout = s->value(timeoutKey, defaultTimeout).toInt(); - omitInternalMssg = s->value(omitInternalKey, true).toBool(); - omitRunConfigWarn = s->value(omitRunConfigWarnKey, false).toBool(); - limitResultOutput = s->value(limitResultOutputKey, true).toBool(); - limitResultDescription = s->value(limitResultDescriptionKey, false).toBool(); - resultDescriptionMaxSize = s->value(resultDescriptionMaxSizeKey, 10).toInt(); - autoScroll = s->value(autoScrollKey, true).toBool(); - processArgs = s->value(processArgsKey, false).toBool(); - displayApplication = s->value(displayApplicationKey, false).toBool(); - popupOnStart = s->value(popupOnStartKey, true).toBool(); - popupOnFinish = s->value(popupOnFinishKey, true).toBool(); - popupOnFail = s->value(popupOnFailKey, false).toBool(); - runAfterBuild = RunAfterBuildMode(s->value(runAfterBuildKey, - int(RunAfterBuildMode::None)).toInt()); + // try to get settings for registered frameworks const TestFrameworks ®istered = TestFrameworkManager::registeredFrameworks(); frameworks.clear(); @@ -102,5 +161,9 @@ void TestSettings::fromSettings(QSettings *s) s->endGroup(); } -} // namespace Internal -} // namespace Autotest +RunAfterBuildMode TestSettings::runAfterBuildMode() const +{ + return static_cast(runAfterBuild.value()); +} + +} // namespace Autotest::Internal diff --git a/src/plugins/autotest/testsettings.h b/src/plugins/autotest/testsettings.h index ecf04fabaac..b4aec87f49d 100644 --- a/src/plugins/autotest/testsettings.h +++ b/src/plugins/autotest/testsettings.h @@ -3,18 +3,9 @@ #pragma once -#include +#include -namespace Utils { -class Id; -} - -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE - -namespace Autotest { -namespace Internal { +namespace Autotest::Internal { enum class RunAfterBuildMode { @@ -23,29 +14,39 @@ enum class RunAfterBuildMode Selected }; -struct TestSettings +class NonAspectSettings { - TestSettings(); - void toSettings(QSettings *s) const; - void fromSettings(QSettings *s); - - int timeout; - bool omitInternalMssg = true; - bool omitRunConfigWarn = false; - bool limitResultOutput = true; - bool limitResultDescription = false; - int resultDescriptionMaxSize = 10; - bool autoScroll = true; - bool processArgs = false; - bool displayApplication = false; - bool popupOnStart = true; - bool popupOnFinish = true; - bool popupOnFail = false; - RunAfterBuildMode runAfterBuild = RunAfterBuildMode::None; +public: QHash frameworks; QHash frameworksGrouping; QHash tools; }; -} // namespace Internal -} // namespace Autotest +class TestSettings : public Utils::AspectContainer, public NonAspectSettings +{ +public: + TestSettings(); + + static TestSettings *instance(); + + void toSettings(QSettings *s) const; + void fromSettings(QSettings *s); + + Utils::IntegerAspect timeout; + Utils::BoolAspect omitInternalMsg; + Utils::BoolAspect omitRunConfigWarn; + Utils::BoolAspect limitResultOutput; + Utils::BoolAspect limitResultDescription; + Utils::IntegerAspect resultDescriptionMaxSize; + Utils::BoolAspect autoScroll; + Utils::BoolAspect processArgs; + Utils::BoolAspect displayApplication; + Utils::BoolAspect popupOnStart; + Utils::BoolAspect popupOnFinish; + Utils::BoolAspect popupOnFail; + Utils::SelectionAspect runAfterBuild; + + RunAfterBuildMode runAfterBuildMode() const; +}; + +} // Autotest::Internal diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp index be6c4244575..6c9850bc2ac 100644 --- a/src/plugins/autotest/testsettingspage.cpp +++ b/src/plugins/autotest/testsettingspage.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include using namespace Utils; @@ -35,100 +34,24 @@ namespace Autotest::Internal { class TestSettingsWidget : public Core::IOptionsPageWidget { public: - explicit TestSettingsWidget(TestSettings *settings); + TestSettingsWidget(); private: void populateFrameworksListWidget(const QHash &frameworks, const QHash &testTools); - void testSettings(TestSettings &settings) const; - void testToolsSettings(TestSettings &settings) const; + void testSettings(NonAspectSettings &settings) const; + void testToolsSettings(NonAspectSettings &settings) const; void onFrameworkItemChanged(); - TestSettings *m_settings; - QCheckBox *m_omitInternalMsgCB; - QCheckBox *m_omitRunConfigWarnCB; - QCheckBox *m_limitResultOutputCB; - QCheckBox *m_limitResultDescriptionCb; - QSpinBox *m_limitResultDescriptionSpinBox; - QCheckBox *m_openResultsOnStartCB; - QCheckBox *m_openResultsOnFinishCB; - QCheckBox *m_openResultsOnFailCB; - QCheckBox *m_autoScrollCB; - QCheckBox *m_displayAppCB; - QCheckBox *m_processArgsCB; - QComboBox *m_runAfterBuildCB; - QSpinBox *m_timeoutSpin; QTreeWidget *m_frameworkTreeWidget; InfoLabel *m_frameworksWarn; }; -TestSettingsWidget::TestSettingsWidget(TestSettings *settings) - : m_settings(settings) +TestSettingsWidget::TestSettingsWidget() { - m_omitInternalMsgCB = new QCheckBox(Tr::tr("Omit internal messages")); - m_omitInternalMsgCB->setChecked(true); - m_omitInternalMsgCB->setToolTip(Tr::tr("Hides internal messages by default. " - "You can still enable them by using the test results filter.")); - - m_omitRunConfigWarnCB = new QCheckBox(Tr::tr("Omit run configuration warnings")); - m_omitRunConfigWarnCB->setToolTip(Tr::tr("Hides warnings related to a deduced run configuration.")); - - m_limitResultOutputCB = new QCheckBox(Tr::tr("Limit result output")); - m_limitResultOutputCB->setChecked(true); - m_limitResultOutputCB->setToolTip(Tr::tr("Limits result output to 100000 characters.")); - - m_limitResultDescriptionCb = new QCheckBox(Tr::tr("Limit result description:")); - m_limitResultDescriptionCb->setToolTip( - Tr::tr("Limit number of lines shown in test result tooltip and description.")); - - m_limitResultDescriptionSpinBox = new QSpinBox; - m_limitResultDescriptionSpinBox->setEnabled(false); - m_limitResultDescriptionSpinBox->setMinimum(1); - m_limitResultDescriptionSpinBox->setMaximum(1000000); - m_limitResultDescriptionSpinBox->setValue(10); - - m_openResultsOnStartCB = new QCheckBox(Tr::tr("Open results when tests start")); - m_openResultsOnStartCB->setToolTip( - Tr::tr("Displays test results automatically when tests are started.")); - - m_openResultsOnFinishCB = new QCheckBox(Tr::tr("Open results when tests finish")); - m_openResultsOnFinishCB->setChecked(true); - m_openResultsOnFinishCB->setToolTip( - Tr::tr("Displays test results automatically when tests are finished.")); - - m_openResultsOnFailCB = new QCheckBox(Tr::tr("Only for unsuccessful test runs")); - m_openResultsOnFailCB->setToolTip( - Tr::tr("Displays test results only if the test run contains failed, fatal or unexpectedly passed tests.")); - - m_autoScrollCB = new QCheckBox(Tr::tr("Automatically scroll results")); - m_autoScrollCB->setChecked(true); - m_autoScrollCB->setToolTip(Tr::tr("Automatically scrolls down when new items are added and scrollbar is at bottom.")); - - m_displayAppCB = new QCheckBox(Tr::tr("Group results by application")); - - m_processArgsCB = new QCheckBox(Tr::tr("Process arguments")); - m_processArgsCB->setToolTip( - Tr::tr("Allow passing arguments specified on the respective run configuration.\n" - "Warning: this is an experimental feature and might lead to failing to execute the test executable.")); - - m_runAfterBuildCB = new QComboBox; - m_runAfterBuildCB->setToolTip(Tr::tr("Runs chosen tests automatically if a build succeeded.")); - m_runAfterBuildCB->addItem(Tr::tr("None")); - m_runAfterBuildCB->addItem(Tr::tr("All")); - m_runAfterBuildCB->addItem(Tr::tr("Selected")); - auto timeoutLabel = new QLabel(Tr::tr("Timeout:")); timeoutLabel->setToolTip(Tr::tr("Timeout used when executing each test case.")); - m_timeoutSpin = new QSpinBox; - m_timeoutSpin->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_timeoutSpin->setRange(5, 36000); - m_timeoutSpin->setValue(60); - m_timeoutSpin->setSuffix(Tr::tr(" s")); - m_timeoutSpin->setToolTip( - Tr::tr("Timeout used when executing test cases. This will apply " - "for each test case on its own, not the whole project.")); - m_frameworkTreeWidget = new QTreeWidget; m_frameworkTreeWidget->setRootIsDecorated(false); m_frameworkTreeWidget->setHeaderHidden(false); @@ -156,21 +79,22 @@ TestSettingsWidget::TestSettingsWidget(TestSettings *settings) onClicked([] { AutotestPlugin::clearChoiceCache(); }, this) }; + TestSettings &s = *TestSettings::instance(); Group generalGroup { title(Tr::tr("General")), Column { - m_omitInternalMsgCB, - m_omitRunConfigWarnCB, - m_limitResultOutputCB, - Row { m_limitResultDescriptionCb, m_limitResultDescriptionSpinBox, st }, - m_openResultsOnStartCB, - m_openResultsOnFinishCB, - Row { Space(20), m_openResultsOnFailCB }, - m_autoScrollCB, - m_displayAppCB, - m_processArgsCB, - Row { Tr::tr("Automatically run"), m_runAfterBuildCB, st }, - Row { timeoutLabel, m_timeoutSpin, st }, + s.omitInternalMsg, + s.omitRunConfigWarn, + s.limitResultOutput, + Row { s.limitResultDescription, s.resultDescriptionMaxSize, st }, + s.popupOnStart, + s.popupOnFinish, + Row { Space(20), s.popupOnFail }, + s.autoScroll, + s.displayApplication, + s.processArgs, + Row { Tr::tr("Automatically run"), s.runAfterBuild, st }, + Row { timeoutLabel, s.timeout, st }, Row { resetChoicesButton, st } } }; @@ -193,61 +117,32 @@ TestSettingsWidget::TestSettingsWidget(TestSettings *settings) connect(m_frameworkTreeWidget, &QTreeWidget::itemChanged, this, &TestSettingsWidget::onFrameworkItemChanged); - connect(m_openResultsOnFinishCB, &QCheckBox::toggled, - m_openResultsOnFailCB, &QCheckBox::setEnabled); - connect(m_limitResultDescriptionCb, &QCheckBox::toggled, - m_limitResultDescriptionSpinBox, &QSpinBox::setEnabled); - - m_timeoutSpin->setValue(settings->timeout / 1000); // we store milliseconds - m_omitInternalMsgCB->setChecked(settings->omitInternalMssg); - m_omitRunConfigWarnCB->setChecked(settings->omitRunConfigWarn); - m_limitResultOutputCB->setChecked(settings->limitResultOutput); - m_limitResultDescriptionCb->setChecked(settings->limitResultDescription); - m_limitResultDescriptionSpinBox->setEnabled(settings->limitResultDescription); - m_limitResultDescriptionSpinBox->setValue(settings->resultDescriptionMaxSize); - m_autoScrollCB->setChecked(settings->autoScroll); - m_processArgsCB->setChecked(settings->processArgs); - m_displayAppCB->setChecked(settings->displayApplication); - m_openResultsOnStartCB->setChecked(settings->popupOnStart); - m_openResultsOnFinishCB->setChecked(settings->popupOnFinish); - m_openResultsOnFailCB->setChecked(settings->popupOnFail); - m_runAfterBuildCB->setCurrentIndex(int(settings->runAfterBuild)); - populateFrameworksListWidget(settings->frameworks, settings->tools); + populateFrameworksListWidget(s.frameworks, s.tools); setOnApply([this] { - TestSettings result; - result.timeout = m_timeoutSpin->value() * 1000; // we display seconds - result.omitInternalMssg = m_omitInternalMsgCB->isChecked(); - result.omitRunConfigWarn = m_omitRunConfigWarnCB->isChecked(); - result.limitResultOutput = m_limitResultOutputCB->isChecked(); - result.limitResultDescription = m_limitResultDescriptionCb->isChecked(); - result.resultDescriptionMaxSize = m_limitResultDescriptionSpinBox->value(); - result.autoScroll = m_autoScrollCB->isChecked(); - result.processArgs = m_processArgsCB->isChecked(); - result.displayApplication = m_displayAppCB->isChecked(); - result.popupOnStart = m_openResultsOnStartCB->isChecked(); - result.popupOnFinish = m_openResultsOnFinishCB->isChecked(); - result.popupOnFail = m_openResultsOnFailCB->isChecked(); - result.runAfterBuild = RunAfterBuildMode(m_runAfterBuildCB->currentIndex()); - testSettings(result); - testToolsSettings(result); + TestSettings &s = *TestSettings::instance(); - const QList changedIds = Utils::filtered(result.frameworksGrouping.keys(), - [result, this](Utils::Id id) { - return result.frameworksGrouping[id] != m_settings->frameworksGrouping[id]; + NonAspectSettings tmp; + testSettings(tmp); + testToolsSettings(tmp); + + const QList changedIds = Utils::filtered(tmp.frameworksGrouping.keys(), + [&tmp, &s](Utils::Id id) { + return tmp.frameworksGrouping[id] != s.frameworksGrouping[id]; }); - *m_settings = result; - m_settings->toSettings(Core::ICore::settings()); + testSettings(s); + testToolsSettings(s); + s.toSettings(Core::ICore::settings()); for (ITestFramework *framework : TestFrameworkManager::registeredFrameworks()) { - framework->setActive(m_settings->frameworks.value(framework->id(), false)); - framework->setGrouping(m_settings->frameworksGrouping.value(framework->id(), false)); + framework->setActive(s.frameworks.value(framework->id(), false)); + framework->setGrouping(s.frameworksGrouping.value(framework->id(), false)); } for (ITestTool *testTool : TestFrameworkManager::registeredTestTools()) - testTool->setActive(m_settings->tools.value(testTool->id(), false)); + testTool->setActive(s.tools.value(testTool->id(), false)); TestTreeModel::instance()->synchronizeTestFrameworks(); TestTreeModel::instance()->synchronizeTestTools(); @@ -294,7 +189,7 @@ void TestSettingsWidget::populateFrameworksListWidget(const QHash &fra } } -void TestSettingsWidget::testSettings(TestSettings &settings) const +void TestSettingsWidget::testSettings(NonAspectSettings &settings) const { const QAbstractItemModel *model = m_frameworkTreeWidget->model(); QTC_ASSERT(model, return); @@ -309,7 +204,7 @@ void TestSettingsWidget::testSettings(TestSettings &settings) const } } -void TestSettingsWidget::testToolsSettings(TestSettings &settings) const +void TestSettingsWidget::testToolsSettings(NonAspectSettings &settings) const { const QAbstractItemModel *model = m_frameworkTreeWidget->model(); QTC_ASSERT(model, return); @@ -356,14 +251,14 @@ void TestSettingsWidget::onFrameworkItemChanged() // TestSettingsPage -TestSettingsPage::TestSettingsPage(TestSettings *settings) +TestSettingsPage::TestSettingsPage() { setId(Constants::AUTOTEST_SETTINGS_ID); setDisplayName(Tr::tr("General")); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayCategory(Tr::tr("Testing")); setCategoryIconPath(":/autotest/images/settingscategory_autotest.png"); - setWidgetCreator([settings] { return new TestSettingsWidget(settings); }); + setWidgetCreator([] { return new TestSettingsWidget; }); } } // Autotest::Internal diff --git a/src/plugins/autotest/testsettingspage.h b/src/plugins/autotest/testsettingspage.h index 46338e7f890..03eb214097d 100644 --- a/src/plugins/autotest/testsettingspage.h +++ b/src/plugins/autotest/testsettingspage.h @@ -7,12 +7,10 @@ namespace Autotest::Internal { -struct TestSettings; - class TestSettingsPage : public Core::IOptionsPage { public: - explicit TestSettingsPage(TestSettings *settings); + TestSettingsPage(); }; } // Autotest::Internal From c85b72000f2861247ba832b5a22cb3746bd709ca Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 16:51:12 +0200 Subject: [PATCH 1030/1447] All: Use the shorter access to aspect values in a few places Change-Id: Ie0ff0e4e1cf4c2750897ea733dfccb743f44fa93 Reviewed-by: Alessandro Portale --- src/plugins/bazaar/bazaarplugin.cpp | 2 +- src/plugins/cpaster/cpasterplugin.cpp | 4 ++-- src/plugins/cpaster/fileshareprotocol.cpp | 2 +- src/plugins/cvs/cvsplugin.cpp | 2 +- src/plugins/debugger/cdb/cdbengine.cpp | 8 +++---- src/plugins/debugger/gdb/gdbengine.cpp | 16 +++++++------- src/plugins/debugger/lldb/lldbengine.cpp | 4 ++-- src/plugins/debugger/stackhandler.cpp | 2 +- src/plugins/debugger/watchhandler.cpp | 2 +- src/plugins/fakevim/fakevimactions.h | 3 +++ src/plugins/fakevim/fakevimhandler.cpp | 24 ++++++++++----------- src/plugins/fakevim/fakevimplugin.cpp | 6 +++--- src/plugins/fossil/fossilplugin.cpp | 8 +++---- src/plugins/git/gitclient.cpp | 6 +++--- src/plugins/git/logchangedialog.cpp | 2 +- src/plugins/perforce/perforceplugin.cpp | 12 +++++------ src/plugins/perforce/perforcesettings.h | 4 ++-- src/plugins/subversion/subversionclient.cpp | 2 +- src/plugins/subversion/subversionplugin.cpp | 4 ++-- src/plugins/vcsbase/vcsbaseclient.cpp | 2 +- src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 4 ++-- 21 files changed, 61 insertions(+), 58 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 964f5241b39..097fca18207 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -523,7 +523,7 @@ void BazaarPluginPrivate::logRepository() const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); QStringList extraOptions; - extraOptions += "--limit=" + QString::number(m_settings.logCount.value()); + extraOptions += "--limit=" + QString::number(m_settings.logCount()); m_client.log(state.topLevel(), QStringList(), extraOptions); } diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp index 65b3d251798..dd576f228f6 100644 --- a/src/plugins/cpaster/cpasterplugin.cpp +++ b/src/plugins/cpaster/cpasterplugin.cpp @@ -247,8 +247,8 @@ void CodePasterPluginPrivate::post(QString data, const QString &mimeType) const FileDataList diffChunks = splitDiffToFiles(data); const int dialogResult = diffChunks.isEmpty() ? - view.show(username, {}, {}, m_settings.expiryDays.value(), data) : - view.show(username, {}, {}, m_settings.expiryDays.value(), diffChunks); + view.show(username, {}, {}, m_settings.expiryDays(), data) : + view.show(username, {}, {}, m_settings.expiryDays(), diffChunks); // Save new protocol in case user changed it. if (dialogResult == QDialog::Accepted && m_settings.protocols.value() != view.protocol()) { diff --git a/src/plugins/cpaster/fileshareprotocol.cpp b/src/plugins/cpaster/fileshareprotocol.cpp index 2ca4bfa6771..6ceb8a4e13b 100644 --- a/src/plugins/cpaster/fileshareprotocol.cpp +++ b/src/plugins/cpaster/fileshareprotocol.cpp @@ -141,7 +141,7 @@ void FileShareProtocol::list() QString errorMessage; const QChar blank = QLatin1Char(' '); const QFileInfoList entryInfoList = dir.entryInfoList(); - const int count = qMin(int(m_settings.displayCount.value()), entryInfoList.size()); + const int count = qMin(int(m_settings.displayCount()), entryInfoList.size()); for (int i = 0; i < count; i++) { const QFileInfo& entryFi = entryInfoList.at(i); if (parse(entryFi.absoluteFilePath(), &errorMessage, &user, &description)) { diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 85e98c1e4ce..884afc37273 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -1333,7 +1333,7 @@ CommandResult CvsPluginPrivate::runCvs(const FilePath &workingDirectory, if (executable.isEmpty()) return CommandResult(ProcessResult::StartFailed, Tr::tr("No CVS executable specified.")); - const int timeoutS = m_settings.timeout.value() * timeoutMultiplier; + const int timeoutS = m_settings.timeout() * timeoutMultiplier; return m_client->vcsSynchronousExec(workingDirectory, {executable, m_settings.addOptions(arguments)}, flags, timeoutS, outputCodec); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 5098ba6f24c..9117728f8e2 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -488,10 +488,10 @@ void CdbEngine::handleInitialSessionIdle() runCommand({"sxn ibp", NoFlags}); // Do not break on initial breakpoints. runCommand({".asm source_line", NoFlags}); // Source line in assembly runCommand({m_extensionCommandPrefix - + "setparameter maxStringLength=" + QString::number(s.maximalStringLength.value()) - + " maxStackDepth=" + QString::number(s.maximalStackDepth.value()) - + " firstChance=" + (s.firstChanceExceptionTaskEntry.value() ? "1" : "0") - + " secondChance=" + (s.secondChanceExceptionTaskEntry.value() ? "1" : "0") + + "setparameter maxStringLength=" + QString::number(s.maximalStringLength()) + + " maxStackDepth=" + QString::number(s.maximalStackDepth()) + + " firstChance=" + (s.firstChanceExceptionTaskEntry() ? "1" : "0") + + " secondChance=" + (s.secondChanceExceptionTaskEntry() ? "1" : "0") , NoFlags}); if (s.cdbUsePythonDumper.value()) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 5ea6162a644..aa84c6d2d78 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -801,7 +801,7 @@ void GdbEngine::runCommand(const DebuggerCommand &command) int GdbEngine::commandTimeoutTime() const { - const int time = debuggerSettings()->gdbWatchdogTimeout.value(); + const int time = debuggerSettings()->gdbWatchdogTimeout(); return 1000 * qMax(20, time); } @@ -1016,7 +1016,7 @@ void GdbEngine::updateAll() { //PENDING_DEBUG("UPDATING ALL\n"); QTC_CHECK(state() == InferiorUnrunnable || state() == InferiorStopOk); - DebuggerCommand cmd(stackCommand(debuggerSettings()->maximalStackDepth.value())); + DebuggerCommand cmd(stackCommand(debuggerSettings()->maximalStackDepth())); cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, false); }; runCommand(cmd); stackHandler()->setCurrentIndex(0); @@ -2616,13 +2616,13 @@ void GdbEngine::insertBreakpoint(const Breakpoint &bp) "QTC_DEBUGGER_PYTHON_VERBOSE"); const DebuggerSettings &s = *debuggerSettings(); cmd.arg("passexceptions", alwaysVerbose); - cmd.arg("fancy", s.useDebuggingHelpers.value()); - cmd.arg("autoderef", s.autoDerefPointers.value()); - cmd.arg("dyntype", s.useDynamicType.value()); - cmd.arg("qobjectnames", s.showQObjectNames.value()); + cmd.arg("fancy", s.useDebuggingHelpers()); + cmd.arg("autoderef", s.autoDerefPointers()); + cmd.arg("dyntype", s.useDynamicType()); + cmd.arg("qobjectnames", s.showQObjectNames()); cmd.arg("nativemixed", isNativeMixedActive()); - cmd.arg("stringcutoff", s.maximalStringLength.value()); - cmd.arg("displaystringlimit", s.displayStringLimit.value()); + cmd.arg("stringcutoff", s.maximalStringLength()); + cmd.arg("displaystringlimit", s.displayStringLimit()); cmd.arg("spec", breakpointLocation2(requested)); cmd.callback = [this, bp](const DebuggerResponse &r) { handleTracepointInsert(r, bp); }; diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 3f182c828b9..ef4d7a4354d 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -469,7 +469,7 @@ void LldbEngine::selectThread(const Thread &thread) DebuggerCommand cmd("selectThread"); cmd.arg("id", thread->id()); cmd.callback = [this](const DebuggerResponse &) { - fetchStack(debuggerSettings()->maximalStackDepth.value()); + fetchStack(debuggerSettings()->maximalStackDepth()); }; runCommand(cmd); } @@ -701,7 +701,7 @@ void LldbEngine::updateAll() DebuggerCommand cmd("fetchThreads"); cmd.callback = [this](const DebuggerResponse &response) { threadsHandler()->setThreads(response.data); - fetchStack(debuggerSettings()->maximalStackDepth.value()); + fetchStack(debuggerSettings()->maximalStackDepth()); reloadRegisters(); }; runCommand(cmd); diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index 6a2390fcadd..1fc6f04582f 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -234,7 +234,7 @@ void StackHandler::setFramesAndCurrentIndex(const GdbMi &frames, bool isFull) targetFrame = i; } - bool canExpand = !isFull && (n >= debuggerSettings()->maximalStackDepth.value()); + bool canExpand = !isFull && (n >= debuggerSettings()->maximalStackDepth()); debuggerSettings()->expandStack.setEnabled(canExpand); setFrames(stackFrames, canExpand); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 0923348d94f..739c0ee4ce7 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -2848,7 +2848,7 @@ QSet WatchHandler::expandedINames() const int WatchHandler::maxArrayCount(const QString &iname) const { - return m_model->m_maxArrayCount.value(iname, debuggerSettings()->defaultArraySize.value()); + return m_model->m_maxArrayCount.value(iname, debuggerSettings()->defaultArraySize()); } void WatchHandler::recordTypeInfo(const GdbMi &typeInfo) diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h index 6f7e303f0f4..582630e83d1 100644 --- a/src/plugins/fakevim/fakevimactions.h +++ b/src/plugins/fakevim/fakevimactions.h @@ -44,18 +44,21 @@ class FvBoolAspect : public FvBaseAspect { public: bool value() const { return FvBaseAspect::value().toBool(); } + bool operator()() const { return value(); } }; class FvIntegerAspect : public FvBaseAspect { public: qint64 value() const { return FvBaseAspect::value().toLongLong(); } + qint64 operator()() const { return value(); } }; class FvStringAspect : public FvBaseAspect { public: QString value() const { return FvBaseAspect::value().toString(); } + QString operator()() const { return value(); } }; class FvAspectContainer : public FvBaseAspect diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 5cf97784fe1..f41c8cc63a6 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -2786,7 +2786,7 @@ void FakeVimHandler::Private::ensureCursorVisible() void FakeVimHandler::Private::updateEditor() { - setTabSize(s.tabStop.value()); + setTabSize(s.tabStop()); setupCharClass(); } @@ -5412,7 +5412,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) const Column ind = indentation(data); if (col.logical <= ind.logical && col.logical && startsWithWhitespace(data, col.physical)) { - const int ts = s.tabStop.value(); + const int ts = s.tabStop(); const int newl = col.logical - 1 - (col.logical - 1) % ts; const QString prefix = tabExpand(newl); setLineContents(line, prefix + data.mid(col.physical)); @@ -5439,7 +5439,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) if (q->tabPressedInInsertMode()) { m_buffer->insertState.insertingSpaces = true; if (s.expandTab.value()) { - const int ts = s.tabStop.value(); + const int ts = s.tabStop(); const int col = logicalCursorColumn(); QString str = QString(ts - col % ts, ' '); insertText(str); @@ -5450,8 +5450,8 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) } } else if (input.isControl('d')) { // remove one level of indentation from the current line - const int shift = s.shiftWidth.value(); - const int tab = s.tabStop.value(); + const int shift = s.shiftWidth(); + const int tab = s.tabStop(); int line = cursorLine() + 1; int pos = firstPositionInLine(line); QString text = lineContents(line); @@ -6957,7 +6957,7 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat) if (s.startOfLine.value()) targetPos = firstPositionInLine(beginLine); - const int sw = s.shiftWidth.value(); + const int sw = s.shiftWidth(); g.movetype = MoveLineWise; beginEditBlock(); QTextBlock block = document()->findBlockByLineNumber(beginLine - 1); @@ -7295,7 +7295,7 @@ int FakeVimHandler::Private::physicalCursorColumn() const int FakeVimHandler::Private::physicalToLogicalColumn (const int physical, const QString &line) const { - const int ts = s.tabStop.value(); + const int ts = s.tabStop(); int p = 0; int logical = 0; while (p < physical) { @@ -7316,7 +7316,7 @@ int FakeVimHandler::Private::physicalToLogicalColumn int FakeVimHandler::Private::logicalToPhysicalColumn (const int logical, const QString &line) const { - const int ts = s.tabStop.value(); + const int ts = s.tabStop(); int physical = 0; for (int l = 0; l < logical && physical < line.size(); ++physical) { QChar c = line.at(physical); @@ -7330,7 +7330,7 @@ int FakeVimHandler::Private::logicalToPhysicalColumn int FakeVimHandler::Private::windowScrollOffset() const { - return qMin(static_cast(s.scrollOff.value()), linesOnScreen() / 2); + return qMin(static_cast(s.scrollOff()), linesOnScreen() / 2); } int FakeVimHandler::Private::logicalCursorColumn() const @@ -8684,7 +8684,7 @@ void FakeVimHandler::Private::jump(int distance) Column FakeVimHandler::Private::indentation(const QString &line) const { - int ts = s.tabStop.value(); + int ts = s.tabStop(); int physical = 0; int logical = 0; int n = line.size(); @@ -8703,8 +8703,8 @@ Column FakeVimHandler::Private::indentation(const QString &line) const QString FakeVimHandler::Private::tabExpand(int n) const { - int ts = s.tabStop.value(); - if (s.expandTab.value() || ts < 1) + int ts = s.tabStop(); + if (s.expandTab() || ts < 1) return QString(n, ' '); return QString(n / ts, '\t') + QString(n % ts, ' '); diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index a9778cbe71d..2f86a7d87a7 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1642,9 +1642,9 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) return; TabSettings tabSettings; - tabSettings.m_indentSize = fakeVimSettings()->shiftWidth.value(); - tabSettings.m_tabSize = fakeVimSettings()->tabStop.value(); - tabSettings.m_tabPolicy = fakeVimSettings()->expandTab.value() + tabSettings.m_indentSize = fakeVimSettings()->shiftWidth(); + tabSettings.m_tabSize = fakeVimSettings()->tabStop(); + tabSettings.m_tabPolicy = fakeVimSettings()->expandTab() ? TabSettings::SpacesOnlyTabPolicy : TabSettings::TabsOnlyTabPolicy; tabSettings.m_continuationAlignBehavior = tew->textDocument()->tabSettings().m_continuationAlignBehavior; diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 8d771eeee19..4386c4a6a47 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -418,10 +418,10 @@ void FossilPluginPrivate::logCurrentFile() QTC_ASSERT(state.hasFile(), return); FossilClient::SupportedFeatures features = m_client.supportedFeatures(); QStringList extraOptions; - extraOptions << "-n" << QString::number(m_client.settings().logCount.value()); + extraOptions << "-n" << QString::number(m_client.settings().logCount()); if (features.testFlag(FossilClient::TimelineWidthFeature)) - extraOptions << "-W" << QString::number(m_client.settings().timelineWidth.value()); + extraOptions << "-W" << QString::number(m_client.settings().timelineWidth()); // disable annotate context menu for older client versions, used to be supported for current revision only bool enableAnnotationContextMenu = features.testFlag(FossilClient::AnnotateRevisionFeature); @@ -503,10 +503,10 @@ void FossilPluginPrivate::logRepository() QTC_ASSERT(state.hasTopLevel(), return); FossilClient::SupportedFeatures features = m_client.supportedFeatures(); QStringList extraOptions; - extraOptions << "-n" << QString::number(m_client.settings().logCount.value()); + extraOptions << "-n" << QString::number(m_client.settings().logCount()); if (features.testFlag(FossilClient::TimelineWidthFeature)) - extraOptions << "-W" << QString::number(m_client.settings().timelineWidth.value()); + extraOptions << "-W" << QString::number(m_client.settings().timelineWidth()); m_client.log(state.topLevel(), {}, extraOptions); } diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 3bd505f25b5..fa42a2565e5 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -1085,7 +1085,7 @@ void GitClient::log(const FilePath &workingDirectory, const QString &fileName, editor->setWorkingDirectory(workingDir); QStringList arguments = {"log", decorateOption}; - int logCount = settings().logCount.value(); + int logCount = settings().logCount(); if (logCount > 0) arguments << "-n" << QString::number(logCount); @@ -1142,7 +1142,7 @@ void GitClient::reflog(const FilePath &workingDirectory, const QString &ref) QStringList arguments = {"reflog", noColorOption, decorateOption}; arguments << argWidget->arguments(); - int logCount = settings().logCount.value(); + int logCount = settings().logCount(); if (logCount > 0) arguments << "-n" << QString::number(logCount); @@ -3120,7 +3120,7 @@ void GitClient::synchronousSubversionFetch(const FilePath &workingDirectory) con void GitClient::subversionLog(const FilePath &workingDirectory) const { QStringList arguments = {"svn", "log"}; - int logCount = settings().logCount.value(); + int logCount = settings().logCount(); if (logCount > 0) arguments << ("--limit=" + QString::number(logCount)); diff --git a/src/plugins/git/logchangedialog.cpp b/src/plugins/git/logchangedialog.cpp index 55055cbf768..7e61b133de8 100644 --- a/src/plugins/git/logchangedialog.cpp +++ b/src/plugins/git/logchangedialog.cpp @@ -224,7 +224,7 @@ LogChangeDialog::LogChangeDialog(bool isReset, QWidget *parent) : m_resetTypeComboBox->addItem(Tr::tr("Hard"), "--hard"); m_resetTypeComboBox->addItem(Tr::tr("Mixed"), "--mixed"); m_resetTypeComboBox->addItem(Tr::tr("Soft"), "--soft"); - m_resetTypeComboBox->setCurrentIndex(GitClient::settings().lastResetIndex.value()); + m_resetTypeComboBox->setCurrentIndex(GitClient::settings().lastResetIndex()); popUpLayout->addWidget(m_resetTypeComboBox); popUpLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); } diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index c6f4082767e..5a7e74450dd 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -889,8 +889,8 @@ void PerforcePluginPrivate::filelog(const FilePath &workingDir, const QString &f QTextCodec *codec = VcsBaseEditor::getCodec(workingDir, QStringList(fileName)); QStringList args; args << QLatin1String("filelog") << QLatin1String("-li"); - if (m_settings.logCount.value() > 0) - args << "-m" << QString::number(m_settings.logCount.value()); + if (m_settings.logCount() > 0) + args << "-m" << QString::number(m_settings.logCount()); if (!fileName.isEmpty()) args.append(fileName); const PerforceResponse result = runP4Cmd(workingDir, args, @@ -911,8 +911,8 @@ void PerforcePluginPrivate::changelists(const FilePath &workingDir, const QStrin QTextCodec *codec = VcsBaseEditor::getCodec(workingDir, QStringList(fileName)); QStringList args; args << QLatin1String("changelists") << QLatin1String("-lit"); - if (m_settings.logCount.value() > 0) - args << "-m" << QString::number(m_settings.logCount.value()); + if (m_settings.logCount() > 0) + args << "-m" << QString::number(m_settings.logCount()); if (!fileName.isEmpty()) args.append(fileName); const PerforceResponse result = runP4Cmd(workingDir, args, @@ -1226,7 +1226,7 @@ PerforceResponse PerforcePluginPrivate::synchronousProcess(const FilePath &worki // Run, connect stderr to the output window Process process; - const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS.value(); + const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS(); process.setTimeoutS(timeOutS); if (outputCodec) process.setCodec(outputCodec); @@ -1303,7 +1303,7 @@ PerforceResponse PerforcePluginPrivate::fullySynchronousProcess(const FilePath & QByteArray stdOut; QByteArray stdErr; - const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS.value(); + const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS(); if (!process.readDataFromProcess(&stdOut, &stdErr, timeOutS)) { process.stop(); process.waitForFinished(); diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h index f6c52957e6f..f0754e982ee 100644 --- a/src/plugins/perforce/perforcesettings.h +++ b/src/plugins/perforce/perforcesettings.h @@ -41,8 +41,8 @@ public: QString *repositoryRoot /* = 0 */, QString *errorMessage); - int longTimeOutS() const { return timeOutS.value() * 10; } - int timeOutMS() const { return timeOutS.value() * 1000; } + int longTimeOutS() const { return timeOutS() * 10; } + int timeOutMS() const { return timeOutS() * 1000; } Utils::FilePath topLevel() const; Utils::FilePath topLevelSymLinkTarget() const; diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 45cd652381c..d728fb79f45 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -277,7 +277,7 @@ void SubversionClient::log(const FilePath &workingDir, const std::function &addAuthOptions) { auto &settings = static_cast(this->settings()); - const int logCount = settings.logCount.value(); + const int logCount = settings.logCount(); QStringList svnExtraOptions = extraOptions; if (logCount > 0) svnExtraOptions << QLatin1String("-l") << QString::number(logCount); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 1eedd616065..8d2be99c0c4 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -949,10 +949,10 @@ CommandResult SubversionPluginPrivate::runSvn(const FilePath &workingDir, const CommandLine &command, RunFlags flags, QTextCodec *outputCodec, int timeoutMutiplier) const { - if (m_settings.binaryPath.value().isEmpty()) + if (m_settings.binaryPath().isEmpty()) return CommandResult(ProcessResult::StartFailed, Tr::tr("No subversion executable specified.")); - const int timeoutS = m_settings.timeout.value() * timeoutMutiplier; + const int timeoutS = m_settings.timeout() * timeoutMutiplier; return m_client->vcsSynchronousExec(workingDir, command, flags, timeoutS, outputCodec); } diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index d5ec691ec04..527db5387c0 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -204,7 +204,7 @@ void VcsBaseClientImpl::vcsExecWithEditor(const Utils::FilePath &workingDirector int VcsBaseClientImpl::vcsTimeoutS() const { - return m_baseSettings->timeout.value(); + return m_baseSettings->timeout(); } VcsCommand *VcsBaseClientImpl::createVcsCommand(const FilePath &defaultWorkingDir, diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index d9717ece09e..1895a64f4d1 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -230,8 +230,8 @@ VcsBaseSubmitEditor::~VcsBaseSubmitEditor() void VcsBaseSubmitEditor::slotUpdateEditorSettings() { const CommonVcsSettings &s = VcsPlugin::instance()->settings(); - setLineWrapWidth(s.lineWrapWidth.value()); - setLineWrap(s.lineWrap.value()); + setLineWrapWidth(s.lineWrapWidth()); + setLineWrap(s.lineWrap()); } // Return a trimmed list of non-empty field texts From ab8f3d78ae6bfeaa0253cca9de35b206fa8e02de Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 08:38:01 +0200 Subject: [PATCH 1031/1447] Utils: Use QAbstractButton instead of QCheckBox in BoolAspect Opens the path to use e.g. QRadioButton. Change-Id: Idb1591c0a1486181b8aeb51edb93bc4bfecef834 Reviewed-by: Alessandro Portale Reviewed-by: --- src/libs/utils/aspects.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 8aa1f77beea..ae3841c647a 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -585,7 +585,7 @@ class BoolAspectPrivate { public: BoolAspect::LabelPlacement m_labelPlacement = BoolAspect::LabelPlacement::AtCheckBox; - QPointer m_checkBox; // Owned by configuration widget + QPointer m_button; // Owned by configuration widget QPointer m_groupBox; // For BoolAspects handling GroupBox check boxes }; @@ -1424,31 +1424,31 @@ BoolAspect::~BoolAspect() = default; */ void BoolAspect::addToLayout(Layouting::LayoutItem &parent) { - QTC_CHECK(!d->m_checkBox); - d->m_checkBox = createSubWidget(); + QTC_CHECK(!d->m_button); + d->m_button = createSubWidget(); switch (d->m_labelPlacement) { case LabelPlacement::AtCheckBoxWithoutDummyLabel: - d->m_checkBox->setText(labelText()); - parent.addItem(d->m_checkBox.data()); + d->m_button->setText(labelText()); + parent.addItem(d->m_button.data()); break; case LabelPlacement::AtCheckBox: { - d->m_checkBox->setText(labelText()); + d->m_button->setText(labelText()); // FIXME: //if (parent.isForm()) // parent.addItem(createSubWidget()); - parent.addItem(d->m_checkBox.data()); + parent.addItem(d->m_button.data()); break; } case LabelPlacement::InExtraLabel: - addLabeledItem(parent, d->m_checkBox); + addLabeledItem(parent, d->m_button); break; } - d->m_checkBox->setChecked(value()); + d->m_button->setChecked(value()); if (isAutoApply()) { - connect(d->m_checkBox.data(), &QAbstractButton::clicked, + connect(d->m_button.data(), &QAbstractButton::clicked, this, [this](bool val) { setValue(val); }); } - connect(d->m_checkBox.data(), &QAbstractButton::clicked, + connect(d->m_button.data(), &QAbstractButton::clicked, this, &BoolAspect::volatileValueChanged); } @@ -1486,8 +1486,8 @@ QAction *BoolAspect::action() QVariant BoolAspect::volatileValue() const { QTC_CHECK(!isAutoApply()); - if (d->m_checkBox) - return d->m_checkBox->isChecked(); + if (d->m_button) + return d->m_button->isChecked(); if (d->m_groupBox) return d->m_groupBox->isChecked(); QTC_CHECK(false); @@ -1497,8 +1497,8 @@ QVariant BoolAspect::volatileValue() const void BoolAspect::setVolatileValue(const QVariant &val) { QTC_CHECK(!isAutoApply()); - if (d->m_checkBox) - d->m_checkBox->setChecked(val.toBool()); + if (d->m_button) + d->m_button->setChecked(val.toBool()); else if (d->m_groupBox) d->m_groupBox->setChecked(val.toBool()); } @@ -1521,8 +1521,8 @@ bool BoolAspect::value() const void BoolAspect::setValue(bool value) { if (BaseAspect::setValueQuietly(value)) { - if (d->m_checkBox) - d->m_checkBox->setChecked(value); + if (d->m_button) + d->m_button->setChecked(value); //qDebug() << "SetValue: Changing" << labelText() << " to " << value; emit changed(); //QTC_CHECK(!labelText().isEmpty()); From 7327a3bbc27566a4431c9b2d54df6f9158b6c593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Wed, 10 May 2023 21:42:59 +0200 Subject: [PATCH 1032/1447] Registryaccess: Fix defined but not used warning In file included from .../src/plugins/debugger/registerpostmortemaction.cpp:6: .../src/shared/registryaccess/registryaccess.h:26:21: warning: 'RegistryAccess::autoRegistryValueNameC' defined but not used [-Wunused-variable] 26 | static const WCHAR *autoRegistryValueNameC = L"Auto"; I don't think using static in a header is a nice thing, inline would work, but we have constexpr which implies inline. Change-Id: I7b872e65a554a9a9feb39845717c5dba7ba6777c Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/shared/registryaccess/registryaccess.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shared/registryaccess/registryaccess.h b/src/shared/registryaccess/registryaccess.h index 21862ae4a19..b4e0c089583 100644 --- a/src/shared/registryaccess/registryaccess.h +++ b/src/shared/registryaccess/registryaccess.h @@ -20,10 +20,11 @@ enum AccessMode { Registry64Mode = 0x4 // Corresponds to QSettings::Registry64Format (5.7) }; -static const char *debuggerApplicationFileC = "qtcdebugger"; -static const WCHAR *debuggerRegistryKeyC = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"; -static const WCHAR *debuggerRegistryValueNameC = L"Debugger"; -static const WCHAR *autoRegistryValueNameC = L"Auto"; +constexpr const char debuggerApplicationFileC[] = "qtcdebugger"; +constexpr const WCHAR debuggerRegistryKeyC[] + = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"; +constexpr const WCHAR debuggerRegistryValueNameC[] = L"Debugger"; +constexpr const WCHAR autoRegistryValueNameC[] = L"Auto"; static inline QString wCharToQString(const WCHAR *w) { From 64d1f49078b6b88b670149e33c5637070524359f Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 14 May 2023 12:58:52 +0300 Subject: [PATCH 1033/1447] Autotest: Fix struct/class misalignment Amends 30af7a9503c. Change-Id: Ie8ca92c427fc3446727d78a76aee492eb789b7ed Reviewed-by: Christian Stenger --- src/plugins/autotest/testframeworkmanager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/autotest/testframeworkmanager.h b/src/plugins/autotest/testframeworkmanager.h index 3eab62adbc8..73dfd96ff96 100644 --- a/src/plugins/autotest/testframeworkmanager.h +++ b/src/plugins/autotest/testframeworkmanager.h @@ -11,7 +11,7 @@ QT_END_NAMESPACE namespace Autotest { namespace Internal { -struct TestSettings; +class TestSettings; } class TestFrameworkManager final From 985c1ee3e9dc0298405e9400f7016d869ec4676e Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 10 May 2023 12:32:05 +0200 Subject: [PATCH 1034/1447] Perforce: Do not wait for process if not set up The process could be not set up correctly or at all if we exit the start function early. Avoids a soft assert. Change-Id: I9f0d71acc4a440b85dbb26fa656e0b551ae685f4 Reviewed-by: hjk --- src/plugins/perforce/perforcechecker.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp index f9a5b5df38b..cf63d9e6913 100644 --- a/src/plugins/perforce/perforcechecker.cpp +++ b/src/plugins/perforce/perforcechecker.cpp @@ -26,8 +26,10 @@ PerforceChecker::PerforceChecker(QObject *parent) : QObject(parent) PerforceChecker::~PerforceChecker() { - m_process.kill(); - m_process.waitForFinished(); + if (m_process.isRunning()) { + m_process.kill(); + m_process.waitForFinished(); + } resetOverrideCursor(); } From 9c2fa5c975d3a416d858d2635b718d6e5afaaecc Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 10 May 2023 13:03:33 +0200 Subject: [PATCH 1035/1447] Perforce: Fix testing settings Changed settings had been taken into account only after an explicit Apply and this may be rather confusing. Change-Id: I344ddf18a3cb15b0bc2d2b41a38587395b592e46 Reviewed-by: hjk --- src/plugins/perforce/perforcesettings.cpp | 22 +++++++++++++++++++++- src/plugins/perforce/perforcesettings.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp index ee18c4ee5fc..e62fdade894 100644 --- a/src/plugins/perforce/perforcesettings.cpp +++ b/src/plugins/perforce/perforcesettings.cpp @@ -106,6 +106,23 @@ QStringList PerforceSettings::commonP4Arguments() const return lst; } +QStringList PerforceSettings::commonP4Arguments_volatile() const +{ + QStringList lst; + if (customEnv.volatileValue().toBool()) { + auto p4C = p4Client.volatileValue().toString(); + if (!p4C.isEmpty()) + lst << "-c" << p4C; + auto p4P = p4Port.volatileValue().toString(); + if (!p4P.isEmpty()) + lst << "-p" << p4P; + auto p4U = p4User.volatileValue().toString(); + if (!p4U.isEmpty()) + lst << "-u" << p4U; + } + return lst; +} + bool PerforceSettings::isValid() const { return !m_topLevel.isEmpty() && !p4BinaryPath.value().isEmpty(); @@ -234,7 +251,10 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) errorLabel->setStyleSheet(QString()); errorLabel->setText(Tr::tr("Testing...")); - checker->start(settings->p4BinaryPath.filePath(), {}, settings->commonP4Arguments(), 10000); + + const FilePath p4Bin = FilePath::fromUserInput( + settings->p4BinaryPath.volatileValue().toString()); + checker->start(p4Bin, {}, settings->commonP4Arguments_volatile(), 10000); }); Group config { diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h index f0754e982ee..b632d153256 100644 --- a/src/plugins/perforce/perforcesettings.h +++ b/src/plugins/perforce/perforcesettings.h @@ -64,6 +64,7 @@ public: // Return basic arguments, including -d and server connection parameters. QStringList commonP4Arguments() const; QStringList commonP4Arguments(const QString &workingDir) const; + QStringList commonP4Arguments_volatile() const; // remove when auto apply is done void clearTopLevel(); From 681627cac38c577a577fdc337dac0c81515b18f2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 23:39:51 +0200 Subject: [PATCH 1036/1447] CurrentProjectFilter: Remove the old matchesFor() implementation Change-Id: I2bd960c14056907e6735002120900b6252ea3989 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- .../projectexplorer/currentprojectfilter.cpp | 34 ++++--------------- .../projectexplorer/currentprojectfilter.h | 20 ++++------- 2 files changed, 12 insertions(+), 42 deletions(-) diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index 5b5c34fe44f..d42ab82e968 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -7,16 +7,12 @@ #include "projectexplorertr.h" #include "projecttree.h" -#include -#include - using namespace Core; using namespace ProjectExplorer; using namespace ProjectExplorer::Internal; using namespace Utils; CurrentProjectFilter::CurrentProjectFilter() - : BaseFileFilter() { setId("Files in current project"); setDisplayName(Tr::tr("Files in Current Project")); @@ -25,7 +21,7 @@ CurrentProjectFilter::CurrentProjectFilter() "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("p"); setDefaultIncludedByDefault(false); - setRefreshRecipe(Tasking::Sync([this] { invalidateCache(); })); + setRefreshRecipe(Tasking::Sync([this] { invalidate(); })); connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &CurrentProjectFilter::currentProjectChanged); @@ -36,35 +32,17 @@ CurrentProjectFilter::CurrentProjectFilter() }); } -void CurrentProjectFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - if (!fileIterator()) { - const FilePaths paths = m_project ? m_project->files(Project::SourceFiles) : FilePaths(); - setFileIterator(new BaseFileFilter::ListIterator(paths)); - } - BaseFileFilter::prepareSearch(entry); -} - void CurrentProjectFilter::currentProjectChanged() { Project *project = ProjectTree::currentProject(); if (project == m_project) return; + if (m_project) - disconnect(m_project, &Project::fileListChanged, - this, &CurrentProjectFilter::invalidateCache); - - if (project) - connect(project, &Project::fileListChanged, - this, &CurrentProjectFilter::invalidateCache); - + disconnect(m_project, &Project::fileListChanged, this, &CurrentProjectFilter::invalidate); m_project = project; - invalidateCache(); -} + if (m_project) + connect(m_project, &Project::fileListChanged, this, &CurrentProjectFilter::invalidate); -void CurrentProjectFilter::invalidateCache() -{ - m_cache.invalidate(); - setFileIterator(nullptr); + invalidate(); } diff --git a/src/plugins/projectexplorer/currentprojectfilter.h b/src/plugins/projectexplorer/currentprojectfilter.h index 6aef3050584..6c500707907 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.h +++ b/src/plugins/projectexplorer/currentprojectfilter.h @@ -3,32 +3,24 @@ #pragma once -#include +#include -namespace ProjectExplorer { +namespace ProjectExplorer { class Project; } -class Project; +namespace ProjectExplorer::Internal { -namespace Internal { - -// TODO: Don't derive from BaseFileFilter, flatten the hierarchy -class CurrentProjectFilter : public Core::BaseFileFilter +class CurrentProjectFilter : public Core::ILocatorFilter { - Q_OBJECT - public: CurrentProjectFilter(); - void prepareSearch(const QString &entry) override; private: Core::LocatorMatcherTasks matchers() final { return {m_cache.matcher()}; } void currentProjectChanged(); - // TODO: Remove me, replace with direct "m_cache.invalidate()" call - void invalidateCache(); + void invalidate() { m_cache.invalidate(); } Core::LocatorFileCache m_cache; Project *m_project = nullptr; }; -} // namespace Internal -} // namespace ProjectExplorer +} // namespace ProjectExplorer::Internal From 091f3f71f8e09f68679dea56ab55a57c5d1542d2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 23:08:31 +0200 Subject: [PATCH 1037/1447] SpotlightLocatorFilter: Remove the old matchesFor() implementation Change-Id: If1ecc94b4246a279c3688c7c8320ccbd18b3533c Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../locator/spotlightlocatorfilter.cpp | 161 +----------------- .../locator/spotlightlocatorfilter.h | 18 +- 2 files changed, 10 insertions(+), 169 deletions(-) diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index 587eadc6154..167a24be8ad 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -22,136 +22,12 @@ #include #include -#include #include -#include -#include #include -#include using namespace Utils; -namespace Core { -namespace Internal { - -// #pragma mark -- SpotlightIterator - -class SpotlightIterator : public BaseFileFilter::Iterator -{ -public: - SpotlightIterator(const CommandLine &command); - ~SpotlightIterator() override; - - void toFront() override; - bool hasNext() const override; - Utils::FilePath next() override; - Utils::FilePath filePath() const override; - - void scheduleKillProcess(); - void killProcess(); - -private: - void ensureNext(); - - std::unique_ptr m_process; - QMutex m_mutex; - QWaitCondition m_waitForItems; - FilePaths m_queue; - FilePaths m_filePaths; - int m_index; - bool m_finished; -}; - -SpotlightIterator::SpotlightIterator(const CommandLine &command) - : m_index(-1) - , m_finished(false) -{ - QTC_ASSERT(!command.isEmpty(), return ); - m_process.reset(new Process); - m_process->setCommand(command); - m_process->setEnvironment(Utils::Environment::systemEnvironment()); - QObject::connect(m_process.get(), &Process::done, - m_process.get(), [this, exe = command.executable().toUserOutput()] { - if (m_process->result() != ProcessResult::FinishedWithSuccess) { - MessageManager::writeFlashing(Tr::tr( - "Locator: Error occurred when running \"%1\".").arg(exe)); - } - scheduleKillProcess(); - }); - QObject::connect(m_process.get(), &Process::readyReadStandardOutput, - m_process.get(), [this] { - QString output = m_process->readAllStandardOutput(); - output.replace("\r\n", "\n"); - const QStringList items = output.split('\n'); - QMutexLocker lock(&m_mutex); - m_queue.append(Utils::transform(items, &FilePath::fromUserInput)); - if (m_filePaths.size() + m_queue.size() > 10000) // limit the amount of data - scheduleKillProcess(); - m_waitForItems.wakeAll(); - }); - m_process->start(); -} - -SpotlightIterator::~SpotlightIterator() -{ - killProcess(); -} - -void SpotlightIterator::toFront() -{ - m_index = -1; -} - -bool SpotlightIterator::hasNext() const -{ - auto that = const_cast(this); - that->ensureNext(); - return (m_index + 1 < m_filePaths.size()); -} - -Utils::FilePath SpotlightIterator::next() -{ - ensureNext(); - ++m_index; - QTC_ASSERT(m_index < m_filePaths.size(), return FilePath()); - return m_filePaths.at(m_index); -} - -Utils::FilePath SpotlightIterator::filePath() const -{ - QTC_ASSERT(m_index < m_filePaths.size(), return FilePath()); - return m_filePaths.at(m_index); -} - -void SpotlightIterator::scheduleKillProcess() -{ - QMetaObject::invokeMethod(m_process.get(), [this] { killProcess(); }, Qt::QueuedConnection); -} - -void SpotlightIterator::killProcess() -{ - if (!m_process) - return; - m_process->disconnect(); - QMutexLocker lock(&m_mutex); - m_finished = true; - m_waitForItems.wakeAll(); - m_process.reset(); -} - -void SpotlightIterator::ensureNext() -{ - if (m_index + 1 < m_filePaths.size()) // nothing to do - return; - // check if there are items in the queue, otherwise wait for some - QMutexLocker lock(&m_mutex); - if (m_queue.isEmpty() && !m_finished) - m_waitForItems.wait(&m_mutex); - m_filePaths.append(m_queue); - m_queue.clear(); -} - -// #pragma mark -- SpotlightLocatorFilter +namespace Core::Internal { static QString defaultCommand() { @@ -233,7 +109,9 @@ SpotlightLocatorFilter::SpotlightLocatorFilter() "\"+\" or \":\" to jump to the given line number. Append another " "\"+\" or \":\" to jump to the column number as well.")); setConfigurable(true); - reset(); + m_command = defaultCommand(); + m_arguments = defaultArguments(); + m_caseSensitiveArguments = defaultArguments(Qt::CaseSensitive); } static void matches(QPromise &promise, const LocatorStorage &storage, @@ -319,25 +197,6 @@ LocatorMatcherTasks SpotlightLocatorFilter::matchers() return {{AsyncTask(onSetup), storage}}; } -void SpotlightLocatorFilter::prepareSearch(const QString &entry) -{ - Link link = Utils::Link::fromString(entry, true); - if (link.targetFilePath.isEmpty()) { - setFileIterator(new BaseFileFilter::ListIterator(Utils::FilePaths())); - } else { - // only pass the file name part to allow searches like "somepath/*foo" - - std::unique_ptr expander(createMacroExpander(link.targetFilePath.fileName())); - const QString argumentString = expander->expand( - caseSensitivity(link.targetFilePath.toString()) == Qt::CaseInsensitive - ? m_arguments - : m_caseSensitiveArguments); - const CommandLine cmd(FilePath::fromString(m_command), argumentString, CommandLine::Raw); - setFileIterator(new SpotlightIterator(cmd)); - } - BaseFileFilter::prepareSearch(entry); -} - bool SpotlightLocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) { Q_UNUSED(needsRefresh) @@ -361,7 +220,7 @@ bool SpotlightLocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefres chooser->addMacroExpanderProvider([expander = expander.get()] { return expander; }); chooser->addSupportedWidget(argumentsEdit); chooser->addSupportedWidget(caseSensitiveArgumentsEdit); - const bool accepted = openConfigDialog(parent, &configWidget); + const bool accepted = ILocatorFilter::openConfigDialog(parent, &configWidget); if (accepted) { m_command = commandEdit->rawFilePath().toString(); m_arguments = argumentsEdit->text(); @@ -387,12 +246,4 @@ void SpotlightLocatorFilter::restoreState(const QJsonObject &obj) m_caseSensitiveArguments = obj.value(kCaseSensitiveKey).toString(defaultArguments(Qt::CaseSensitive)); } -void SpotlightLocatorFilter::reset() -{ - m_command = defaultCommand(); - m_arguments = defaultArguments(); - m_caseSensitiveArguments = defaultArguments(Qt::CaseSensitive); -} - -} // Internal -} // Core +} // namespace Core::Internal diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.h b/src/plugins/coreplugin/locator/spotlightlocatorfilter.h index 80d770dfa15..06114d4e264 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.h +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.h @@ -3,23 +3,15 @@ #pragma once -#include "basefilefilter.h" +#include "ilocatorfilter.h" -#include +namespace Core::Internal { -namespace Core { -namespace Internal { - -// TODO: Don't derive from BaseFileFilter, flatten the hierarchy -class SpotlightLocatorFilter : public BaseFileFilter +class SpotlightLocatorFilter : public ILocatorFilter { - Q_OBJECT public: SpotlightLocatorFilter(); - void prepareSearch(const QString &entry) override; - - using ILocatorFilter::openConfigDialog; bool openConfigDialog(QWidget *parent, bool &needsRefresh) final; protected: @@ -28,12 +20,10 @@ protected: private: LocatorMatcherTasks matchers() final; - void reset(); QString m_command; QString m_arguments; QString m_caseSensitiveArguments; }; -} // Internal -} // Core +} // namespace Core::Internal From 4d2710bae248247aaf9c4fe0441466e4a97c825d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 22:56:29 +0200 Subject: [PATCH 1038/1447] UrlLocatorFilter: Remove the old matchesFor() implementation Change-Id: I2d04f4bf66ec12c8c641cbfb39a4c2b0049ecdc4 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Eike Ziller --- .../coreplugin/locator/urllocatorfilter.cpp | 42 ------------------- .../coreplugin/locator/urllocatorfilter.h | 18 +++----- 2 files changed, 5 insertions(+), 55 deletions(-) diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index f2d22ee9083..d00eb7a21fe 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include using namespace Utils; @@ -163,8 +162,6 @@ UrlLocatorFilter::UrlLocatorFilter(const QString &displayName, Id id) setDefaultIncludedByDefault(false); } -UrlLocatorFilter::~UrlLocatorFilter() = default; - LocatorMatcherTasks UrlLocatorFilter::matchers() { using namespace Tasking; @@ -191,28 +188,6 @@ LocatorMatcherTasks UrlLocatorFilter::matchers() return {{Sync(onSetup), storage}}; } -QList UrlLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - QList entries; - const QStringList urls = remoteUrls(); - for (const QString &url : urls) { - if (future.isCanceled()) - break; - const QString name = url.arg(entry); - Core::LocatorFilterEntry filterEntry; - filterEntry.displayName = name; - filterEntry.acceptor = [name] { - if (!name.isEmpty()) - QDesktopServices::openUrl(name); - return AcceptResult(); - }; - filterEntry.highlightInfo = {int(name.lastIndexOf(entry)), int(entry.length())}; - entries.append(filterEntry); - } - return entries; -} - const char kDisplayNameKey[] = "displayName"; const char kRemoteUrlsKey[] = "remoteUrls"; @@ -266,7 +241,6 @@ bool UrlLocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) Q_UNUSED(needsRefresh) Internal::UrlFilterOptions optionsDialog(this, parent); if (optionsDialog.exec() == QDialog::Accepted) { - QMutexLocker lock(&m_mutex); m_remoteUrls.clear(); setIncludedByDefault(optionsDialog.includeByDefault->isChecked()); setShortcutString(optionsDialog.shortcutEdit->text().trimmed()); @@ -285,20 +259,4 @@ void UrlLocatorFilter::addDefaultUrl(const QString &urlTemplate) m_defaultUrls.append(urlTemplate); } -QStringList UrlLocatorFilter::remoteUrls() const -{ - QMutexLocker lock(&m_mutex); - return m_remoteUrls; -} - -void UrlLocatorFilter::setIsCustomFilter(bool value) -{ - m_isCustomFilter = value; -} - -bool UrlLocatorFilter::isCustomFilter() const -{ - return m_isCustomFilter; -} - } // namespace Core diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.h b/src/plugins/coreplugin/locator/urllocatorfilter.h index dbd4bef45b7..57f652aeca1 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.h +++ b/src/plugins/coreplugin/locator/urllocatorfilter.h @@ -8,7 +8,6 @@ #include #include -#include QT_BEGIN_NAMESPACE class QCheckBox; @@ -21,23 +20,18 @@ namespace Core { class CORE_EXPORT UrlLocatorFilter final : public Core::ILocatorFilter { - Q_OBJECT public: UrlLocatorFilter(Utils::Id id); UrlLocatorFilter(const QString &displayName, Utils::Id id); - ~UrlLocatorFilter() final; - // ILocatorFilter - QList matchesFor(QFutureInterface &future, - const QString &entry) override; - void restoreState(const QByteArray &state) override; - bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; + void restoreState(const QByteArray &state) final; + bool openConfigDialog(QWidget *parent, bool &needsRefresh) final; void addDefaultUrl(const QString &urlTemplate); - QStringList remoteUrls() const; + QStringList remoteUrls() const { return m_remoteUrls; } - void setIsCustomFilter(bool value); - bool isCustomFilter() const; + void setIsCustomFilter(bool value) { m_isCustomFilter = value; } + bool isCustomFilter() const { return m_isCustomFilter; } protected: void saveState(QJsonObject &object) const final; @@ -50,7 +44,6 @@ private: QStringList m_defaultUrls; QStringList m_remoteUrls; bool m_isCustomFilter = false; - mutable QMutex m_mutex; }; namespace Internal { @@ -81,5 +74,4 @@ private: }; } // namespace Internal - } // namespace Core From 6b600798a4cf009c4df7649df0ba7b2992e1fdd0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 09:21:22 +0200 Subject: [PATCH 1039/1447] LanguageClient: Remove the old matchesFor() implementation Rename some workspace filter classes to conform to the names for cpp filters. Remove some unneeded intermediate classes now. Change-Id: I1ec0dbb7ed91944e9dd8b1b0f4878b826191a020 Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- .../languageclient/languageclientmanager.cpp | 9 +- src/plugins/languageclient/locatorfilter.cpp | 241 ++---------------- src/plugins/languageclient/locatorfilter.h | 118 ++------- 3 files changed, 43 insertions(+), 325 deletions(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 275e9ed9e49..4de4a0de46e 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -30,7 +30,6 @@ #include #include -#include #include using namespace LanguageServerProtocol; @@ -44,10 +43,10 @@ static bool g_shuttingDown = false; class LanguageClientManagerPrivate { - DocumentLocatorFilter m_currentDocumentLocatorFilter; - WorkspaceLocatorFilter m_workspaceLocatorFilter; - WorkspaceClassLocatorFilter m_workspaceClassLocatorFilter; - WorkspaceMethodLocatorFilter m_workspaceMethodLocatorFilter; + LanguageCurrentDocumentFilter m_currentDocumentFilter; + LanguageAllSymbolsFilter m_allSymbolsFilter; + LanguageClassesFilter m_classFilter; + LanguageFunctionsFilter m_functionFilter; }; LanguageClientManager::LanguageClientManager(QObject *parent) diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 5d52f28f232..04caf2d1723 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -5,23 +5,14 @@ #include "clientrequesttask.h" #include "currentdocumentsymbolsrequest.h" -#include "documentsymbolcache.h" -#include "languageclient_global.h" #include "languageclientmanager.h" #include "languageclienttr.h" -#include - #include -#include - -#include - #include #include -#include #include using namespace Core; @@ -60,7 +51,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, TreeStorage storage; TreeStorage> resultStorage; - const auto onQuerySetup = [=](WorkspaceSymbolRequestTask &request) { + const auto onQuerySetup = [storage, client, maxResultCount](WorkspaceSymbolRequestTask &request) { request.setClient(client); WorkspaceSymbolParams params; params.setQuery(storage->input()); @@ -75,7 +66,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, *resultStorage = result->toList(); }; - const auto onFilterSetup = [=](Async &async) { + const auto onFilterSetup = [storage, resultStorage, client, filter](Async &async) { const QList results = *resultStorage; if (results.isEmpty()) return TaskAction::StopWithDone; @@ -131,14 +122,14 @@ LocatorMatcherTask currentDocumentMatcher() TreeStorage storage; TreeStorage resultStorage; - const auto onQuerySetup = [=](CurrentDocumentSymbolsRequest &request) { + const auto onQuerySetup = [](CurrentDocumentSymbolsRequest &request) { Q_UNUSED(request) }; const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequest &request) { *resultStorage = request.currentDocumentSymbolsData(); }; - const auto onFilterSetup = [=](Async &async) { + const auto onFilterSetup = [storage, resultStorage](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage); }; @@ -178,7 +169,7 @@ LocatorMatcherTasks languageClientMatchers(MatcherType type, const QListlocatorsEnabled() || m_forced)) { - - setEnabled(!m_forced); - if (m_symbolCache != client->documentSymbolCache()) { - disconnect(m_updateSymbolsConnection); - m_symbolCache = client->documentSymbolCache(); - m_updateSymbolsConnection = connect(m_symbolCache, &DocumentSymbolCache::gotSymbols, - this, &DocumentLocatorFilter::updateSymbols); - } - m_resetSymbolsConnection = connect(document, &IDocument::contentsChanged, - this, &DocumentLocatorFilter::resetSymbols); - m_currentUri = client->hostPathToServerUri(document->filePath()); - m_pathMapper = client->hostPathMapper(); - } else { - disconnect(m_updateSymbolsConnection); - m_symbolCache.clear(); - m_currentUri.clear(); - setEnabled(false); - m_pathMapper = DocumentUri::PathMapper(); - } -} - -void DocumentLocatorFilter::updateSymbols(const DocumentUri &uri, - const DocumentSymbolsResult &symbols) -{ - if (uri != m_currentUri) - return; - QMutexLocker locker(&m_mutex); - m_currentSymbols = symbols; - emit symbolsUpToDate(QPrivateSignal()); -} - -void DocumentLocatorFilter::resetSymbols() -{ - QMutexLocker locker(&m_mutex); - m_currentSymbols.reset(); -} - static LocatorFilterEntry entryForSymbolInfo(const SymbolInformation &info, - DocumentUri::PathMapper pathMapper) + const DocumentUri::PathMapper &pathMapper) { LocatorFilterEntry entry; entry.displayName = info.name(); @@ -305,78 +247,7 @@ Core::LocatorFilterEntries currentDocumentSymbols(const QString &input, return {}; } -void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) -{ - QMutexLocker locker(&m_mutex); - m_currentFilePath = m_pathMapper ? m_currentUri.toFilePath(m_pathMapper) : FilePath(); - if (m_symbolCache && !m_currentSymbols.has_value()) { - locker.unlock(); - m_symbolCache->requestSymbols(m_currentUri, Schedule::Now); - } -} - -QList DocumentLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - const auto docSymbolModifier = [](LocatorFilterEntry &entry, const DocumentSymbol &info, - const LocatorFilterEntry &parent) { - Q_UNUSED(parent) - entry.displayName = info.name(); - if (std::optional detail = info.detail()) - entry.extraInfo = *detail; - }; - return matchesForImpl(future, entry, docSymbolModifier); -} - -QList DocumentLocatorFilter::matchesForImpl( - QFutureInterface &future, const QString &entry, - const DocSymbolModifier &docSymbolModifier) -{ - const FuzzyMatcher::CaseSensitivity caseSensitivity - = ILocatorFilter::caseSensitivity(entry) == Qt::CaseSensitive - ? FuzzyMatcher::CaseSensitivity::CaseSensitive - : FuzzyMatcher::CaseSensitivity::CaseInsensitive; - const QRegularExpression regExp = FuzzyMatcher::createRegExp(entry, caseSensitivity); - if (!regExp.isValid()) - return {}; - - QMutexLocker locker(&m_mutex); - if (!m_symbolCache) - return {}; - if (!m_currentSymbols.has_value()) { - QEventLoop loop; - connect(this, &DocumentLocatorFilter::symbolsUpToDate, &loop, [&] { loop.exit(1); }); - QFutureWatcher watcher; - connect(&watcher, &QFutureWatcher::canceled, &loop, &QEventLoop::quit); - watcher.setFuture(future.future()); - locker.unlock(); - if (!loop.exec()) - return {}; - locker.relock(); - } - - QTC_ASSERT(m_currentSymbols.has_value(), return {}); - - if (auto list = std::get_if>(&*m_currentSymbols)) - return entriesForDocSymbols(*list, regExp, m_currentFilePath, docSymbolModifier); - else if (auto list = std::get_if>(&*m_currentSymbols)) - return entriesForSymbolsInfo(*list, regExp, m_pathMapper); - - return {}; -} - -WorkspaceLocatorFilter::WorkspaceLocatorFilter() - : WorkspaceLocatorFilter(QVector()) -{} - -LocatorMatcherTasks WorkspaceLocatorFilter::matchers() -{ - return languageClientMatchers(MatcherType::AllSymbols, - Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); -} - -WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter) - : m_filterKinds(filter) +LanguageAllSymbolsFilter::LanguageAllSymbolsFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_DISPLAY_NAME)); @@ -386,94 +257,13 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter setPriority(ILocatorFilter::Low); } -void WorkspaceLocatorFilter::prepareSearch(const QString &entry) +LocatorMatcherTasks LanguageAllSymbolsFilter::matchers() { - prepareSearchForClients(entry, Utils::filtered(LanguageClientManager::clients(), - &Client::locatorsEnabled)); + return languageClientMatchers(MatcherType::AllSymbols, + Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); } -void WorkspaceLocatorFilter::prepareSearchForClients(const QString &entry, - const QList &clients) -{ - m_pendingRequests.clear(); - m_results.clear(); - - if (clients.isEmpty()) - return; - - WorkspaceSymbolParams params; - params.setQuery(entry); - if (m_maxResultCount > 0) - params.setLimit(m_maxResultCount); - - QMutexLocker locker(&m_mutex); - for (auto client : std::as_const(clients)) { - if (!client->reachable()) - continue; - std::optional> capability - = client->capabilities().workspaceSymbolProvider(); - if (!capability.has_value()) - continue; - if (std::holds_alternative(*capability) && !std::get(*capability)) - continue; - WorkspaceSymbolRequest request(params); - request.setResponseCallback( - [this, client](const WorkspaceSymbolRequest::Response &response) { - handleResponse(client, response); - }); - m_pendingRequests[client] = request.id(); - client->sendMessage(request); - } -} - -QList WorkspaceLocatorFilter::matchesFor( - QFutureInterface &future, const QString & /*entry*/) -{ - QMutexLocker locker(&m_mutex); - if (!m_pendingRequests.isEmpty()) { - QEventLoop loop; - connect(this, &WorkspaceLocatorFilter::allRequestsFinished, &loop, [&] { loop.exit(1); }); - QFutureWatcher watcher; - connect(&watcher, - &QFutureWatcher::canceled, - &loop, - &QEventLoop::quit); - watcher.setFuture(future.future()); - locker.unlock(); - if (!loop.exec()) - return {}; - - locker.relock(); - } - - if (!m_filterKinds.isEmpty()) { - m_results = Utils::filtered(m_results, [&](const SymbolInfoWithPathMapper &info) { - return m_filterKinds.contains(SymbolKind(info.symbol.kind())); - }); - } - auto generateEntry = [](const SymbolInfoWithPathMapper &info) { - return entryForSymbolInfo(info.symbol, info.mapper); - }; - return Utils::transform(m_results, generateEntry).toList(); -} - -void WorkspaceLocatorFilter::handleResponse(Client *client, - const WorkspaceSymbolRequest::Response &response) -{ - QMutexLocker locker(&m_mutex); - m_pendingRequests.remove(client); - auto result = response.result().value_or(LanguageClientArray()); - if (!result.isNull()) - m_results.append( - Utils::transform(result.toList(), [client](const SymbolInformation &info) { - return SymbolInfoWithPathMapper{info, client->hostPathMapper()}; - })); - if (m_pendingRequests.isEmpty()) - emit allRequestsFinished(QPrivateSignal()); -} - -WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter() - : WorkspaceLocatorFilter({SymbolKind::Class, SymbolKind::Struct}) +LanguageClassesFilter::LanguageClassesFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME)); @@ -481,14 +271,13 @@ WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter() setDefaultShortcutString("c"); } -LocatorMatcherTasks WorkspaceClassLocatorFilter::matchers() +LocatorMatcherTasks LanguageClassesFilter::matchers() { return languageClientMatchers(MatcherType::Classes, Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); } -WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() - : WorkspaceLocatorFilter({SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}) +LanguageFunctionsFilter::LanguageFunctionsFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME)); @@ -496,7 +285,7 @@ WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() setDefaultShortcutString("m"); } -LocatorMatcherTasks WorkspaceMethodLocatorFilter::matchers() +LocatorMatcherTasks LanguageFunctionsFilter::matchers() { return languageClientMatchers(MatcherType::Functions, Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 286e064c509..39d135723ce 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -3,22 +3,15 @@ #pragma once -#include "client.h" #include "languageclient_global.h" #include -#include -#include -#include - -#include -#include - -namespace Core { class IEditor; } +namespace LanguageServerProtocol { class DocumentSymbol; }; namespace LanguageClient { +class Client; class CurrentDocumentSymbolsData; using DocSymbolModifier = std::function &clients = {}, int maxResultCount = 0); -class LanguageClientManager; - -class LANGUAGECLIENT_EXPORT DocumentLocatorFilter : public Core::ILocatorFilter -{ - Q_OBJECT -public: - DocumentLocatorFilter(); - - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; -signals: - void symbolsUpToDate(QPrivateSignal); - -protected: - void forceUse() { m_forced = true; } - - Utils::FilePath m_currentFilePath; - - QList matchesForImpl( - QFutureInterface &future, const QString &entry, - const DocSymbolModifier &docSymbolModifier); - -private: - Core::LocatorMatcherTasks matchers() final; - void updateCurrentClient(); - void updateSymbols(const LanguageServerProtocol::DocumentUri &uri, - const LanguageServerProtocol::DocumentSymbolsResult &symbols); - void resetSymbols(); - - QMutex m_mutex; - QMetaObject::Connection m_updateSymbolsConnection; - QMetaObject::Connection m_resetSymbolsConnection; - std::optional m_currentSymbols; - LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper; - bool m_forced = false; - QPointer m_symbolCache; - LanguageServerProtocol::DocumentUri m_currentUri; -}; - -class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter -{ - Q_OBJECT -public: - WorkspaceLocatorFilter(); - - /// request workspace symbols for all clients with enabled locator - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; -signals: - void allRequestsFinished(QPrivateSignal); - -protected: - explicit WorkspaceLocatorFilter(const QVector &filter); - - /// force request workspace symbols for all given clients - void prepareSearchForClients(const QString &entry, const QList &clients); - void setMaxResultCount(qint64 limit) { m_maxResultCount = limit; } - -private: - Core::LocatorMatcherTasks matchers() override; - void handleResponse(Client *client, - const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); - - QMutex m_mutex; - - struct SymbolInfoWithPathMapper - { - LanguageServerProtocol::SymbolInformation symbol; - LanguageServerProtocol::DocumentUri::PathMapper mapper; - }; - - QMap m_pendingRequests; - QVector m_results; - QVector m_filterKinds; - qint64 m_maxResultCount = 0; -}; - -// TODO: Don't derive, flatten the hierarchy -class LANGUAGECLIENT_EXPORT WorkspaceClassLocatorFilter : public WorkspaceLocatorFilter +class LanguageAllSymbolsFilter : public Core::ILocatorFilter { public: - WorkspaceClassLocatorFilter(); + LanguageAllSymbolsFilter(); private: Core::LocatorMatcherTasks matchers() final; }; -// TODO: Don't derive, flatten the hierarchy -class LANGUAGECLIENT_EXPORT WorkspaceMethodLocatorFilter : public WorkspaceLocatorFilter +class LanguageClassesFilter : public Core::ILocatorFilter { public: - WorkspaceMethodLocatorFilter(); + LanguageClassesFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; +}; + +class LanguageFunctionsFilter : public Core::ILocatorFilter +{ +public: + LanguageFunctionsFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; +}; + +class LanguageCurrentDocumentFilter : public Core::ILocatorFilter +{ +public: + LanguageCurrentDocumentFilter(); private: Core::LocatorMatcherTasks matchers() final; From e71f9b9c87076302617e55f800b717a2912b0f65 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 18:29:24 +0200 Subject: [PATCH 1040/1447] Uitls: Make BaseAspect::isDirty() virtual It's sometimes not so easy to trigger the volatileValue() != value() branch, so create a way to be explicit when needed. Change-Id: I322508a33c935077038d730fd09c819419901353 Reviewed-by: Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 266a41f8ee1..b610c1ffbe1 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -115,7 +115,7 @@ public: virtual void apply(); virtual void cancel(); virtual void finish(); - bool isDirty() const; + virtual bool isDirty() const; bool hasAction() const; class QTCREATOR_UTILS_EXPORT Data From c6a69023c9bfd39c023e63e8394f433105479456 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 20 Apr 2023 15:09:00 +0200 Subject: [PATCH 1041/1447] German translation: VcsBase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7b9dc7a2e6868481ab900b56acce2a084b203bd9 Reviewed-by: Robert Löhning --- share/qtcreator/translations/qtcreator_de.ts | 72 ++++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index a49b915b5a2..5b78592b199 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -29091,7 +29091,7 @@ Nicht markiert - Die Änderung ist kein Entwurf. Filter log entries by text in the commit message. - Log-Einträge nach Nachrichtentext filtern. + Log-Einträge nach Beschreibung filtern. Filter by content @@ -53075,7 +53075,7 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Clean Repository - Repository bereinigen + Repository bereinigen Delete... @@ -53190,25 +53190,25 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Warning: The commit subject is very short. - + Warnung: Der Titel des Commits ist sehr kurz. Warning: The commit subject is too long. - + Warnung: Der Titel des Commits ist zu lang. Hint: Aim for a shorter commit subject. - + Hinweis: Versuchen Sie, einen kürzeren Titel zu vergeben. Hint: The second line of a commit message should be empty. - + Hinweis: Die zweite Zeile der Beschreibung sollte leer sein. <p>Writing good commit messages</p><ul><li>Avoid very short commit messages.</li><li>Consider the first line as subject (like in email) and keep it shorter than %n characters.</li><li>After an empty second line, a longer description can be added.</li><li>Describe why the change was done, not how it was done.</li></ul> - - - + + <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als ein Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul> + <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als %n Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul> @@ -53263,11 +53263,11 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Running: %1 - Führe aus: %1 + Führe aus: %1 Running in %1: %2 - Führe in %1 aus: %2 {1:?} + Führe in %1 aus: %2 Failed to retrieve data. @@ -53307,7 +53307,7 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Command started... - Kommando gestartet... + Kommando gestartet... Checkout @@ -53315,15 +53315,15 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch No job running, please abort. - Kein laufender Job, bitte brechen Sie ab. + Kein laufender Job, bitte brechen Sie ab. Succeeded. - Erfolgreich beendet. + Erfolgreich beendet. Failed. - Fehlgeschlagen. + Fehlgeschlagen. "%1" (%2) not found. @@ -53404,91 +53404,91 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch User/&alias configuration file: - Nutzer/&Alias-Konfigurationsdatei: + Nutzer/&Alias-Konfigurationsdatei: A file listing nicknames in a 4-column mailmap format: 'name <email> alias <email>'. - Eine Datei, die Nutzernamen in einem vierspaltigen Format (mailmap) enthält: + Eine Datei, die Nutzernamen in einem vierspaltigen Format (mailmap) enthält: 'Name <E-Mail> Alias <E-Mail>'. User &fields configuration file: - Nutzer&feld-Konfigurationsdatei: + Nutzer&feld-Konfigurationsdatei: A simple file containing lines with field names like "Reviewed-By:" which will be added below the submit editor. - Eine Datei, die Zeilen mit Feldnamen (zum Beispiel "Reviewed-By:") enthält, die im Abgabefenster unter der Beschreibung erscheinen. + Eine Datei, die Zeilen mit Feldnamen (zum Beispiel "Reviewed-By:") enthält, die im Abgabefenster unter der Beschreibung erscheinen. Submit message &check script: - Skript zur &Überprüfung der Beschreibung: + Skript zur &Überprüfung der Beschreibung: An executable which is called with the submit message in a temporary file as first argument. It should return with an exit != 0 and a message on standard error to indicate failure. - Eine ausführbare Datei, die mit der Beschreibung in einer temporären Datei als erstem Kommandozeilenparameter aufgerufen wird. Bei Fehlschlag sollte sie einen Rückgabewert ungleich Null mit einer entsprechende Nachricht auf der Fehlerausgabe zurückgeben. + Eine ausführbare Datei, die mit der Beschreibung in einer temporären Datei als erstem Kommandozeilenparameter aufgerufen wird. Bei Fehlschlag sollte sie einen Rückgabewert ungleich Null mit einer entsprechenden Nachricht auf der Fehlerausgabe zurückgeben. &SSH prompt command: - Graphische &SSH-Passwortabfrage: + Graphische &SSH-Passwortabfrage: Specifies a command that is executed to graphically prompt for a password, should a repository require SSH-authentication (see documentation on SSH and the environment variable SSH_ASKPASS). - Kommando zur graphischen Passwortabfrage bei SSH-Authorisierung eines Repositorys + Kommando zur graphischen Passwortabfrage bei SSH-Authorisierung eines Repositorys (siehe SSH-Dokumentation zur Umgebungsvariable SSH-ASKPASS). Wrap submit message at: - Beschreibung umbrechen bei: + Beschreibung umbrechen bei: characters - Zeichen + Zeichen Reset VCS Cache - VCS-Cache zurücksetzen + VCS-Cache zurücksetzen Reset information about which version control system handles which directory. - Die Zuordnung, welches Versionsverwaltungssystem welches Verzeichnis behandelt, zurücksetzen. + Die Zuordnung zurücksetzen, welches Versionsverwaltungssystem welches Verzeichnis behandelt. Log count: - Log-Anzeige beschränken auf: + Log-Anzeige beschränken auf: Timeout: - Zeitlimit: + Zeitlimit: s - s + s &Open "%1" - + "%1" ö&ffnen &Copy to clipboard: "%1" - + In die Zwischenablage &kopieren: "%1" Fossil File Log Editor - + Fossil Datei-Log-Editor Fossil Annotation Editor - + Fossil Annotations-Editor Fossil Diff Editor - + Fossil Diff-Editor Fossil Commit Log Editor - + Fossil Commit-Log-Editor From 63b2934a62c145d8916307a7833de2ef139901a0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 12 May 2023 08:40:03 +0200 Subject: [PATCH 1042/1447] ProjectExplorer: Do not override application cursor in TaskView Change-Id: Ia8c332ee4d736c74fd773ecc5aecf8ee1c8345df Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/projectexplorer/taskwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 60ad28ec7ef..e1e346887f7 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -688,9 +688,9 @@ void TaskView::mouseMoveEvent(QMouseEvent *e) if (m_hoverAnchor != anchor) { m_hoverAnchor = anchor; if (!m_hoverAnchor.isEmpty()) - QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); + setCursor(Qt::PointingHandCursor); else - QApplication::restoreOverrideCursor(); + unsetCursor(); } } From fe74e6d43bba607d0543164ff380fceaa54d0bb7 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 15 May 2023 09:05:51 +0200 Subject: [PATCH 1043/1447] FakeVim: only block suggestion when fakevim is in use This fixes the issue that no copilot suggestion were shown after switching documents. Change-Id: Ic81bfbe266877964eeaf688d9915a7937607118b Reviewed-by: Marcus Tillmanns --- src/plugins/fakevim/fakevimhandler.cpp | 5 +++++ src/plugins/fakevim/fakevimhandler.h | 2 ++ src/plugins/fakevim/fakevimplugin.cpp | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index f41c8cc63a6..2eb052432cf 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -9546,6 +9546,11 @@ bool FakeVimHandler::jumpToLocalMark(QChar mark, bool backTickMode) return d->jumpToMark(mark, backTickMode); } +bool FakeVimHandler::inFakeVimMode() +{ + return d->m_inFakeVim; +} + } // namespace Internal } // namespace FakeVim diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index 7c0cecaf738..0b615e1657e 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -136,6 +136,8 @@ public: bool jumpToLocalMark(QChar mark, bool backTickMode); + bool inFakeVimMode(); + bool eventFilter(QObject *ob, QEvent *ev) override; Callback diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 2f86a7d87a7..be06ece7f45 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1587,6 +1587,8 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) handler->modeChanged.set([tew, this, editor](bool insertMode) { HandlerAndData &handlerAndData = m_editorToHandler[editor]; + if (!handlerAndData.handler->inFakeVimMode()) + return; // We don't want to show suggestions unless we are in insert mode. if (insertMode != (handlerAndData.suggestionBlocker == nullptr)) From e6d574ee775f724aac0e4ea0e1175649281d6f22 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 10:24:35 +0200 Subject: [PATCH 1044/1447] Fossil: Consolidate optionpage/apply further Change-Id: I345c6f38421864630d99a45fd2176ba0836536e9 Reviewed-by: Orgad Shaneh --- src/plugins/fossil/fossilplugin.cpp | 5 +- src/plugins/fossil/fossilsettings.cpp | 110 +++++++++++--------------- src/plugins/fossil/fossilsettings.h | 12 ++- 3 files changed, 55 insertions(+), 72 deletions(-) diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 4386c4a6a47..825a81bbcab 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -190,7 +190,7 @@ public: FossilSettings m_fossilSettings; FossilClient m_client{&m_fossilSettings}; - OptionsPage optionPage{[this] { configurationChanged(); }, &m_fossilSettings}; + OptionsPage optionPage{&m_fossilSettings}; VcsSubmitEditorFactory submitEditorFactory { submitEditorParameters, @@ -300,6 +300,9 @@ FossilPluginPrivate::FossilPluginPrivate() return new FossilJsExtension(&m_fossilSettings); }); + connect(&m_fossilSettings, &AspectContainer::changed, + this, &IVersionControl::configurationChanged); + createMenu(context); } diff --git a/src/plugins/fossil/fossilsettings.cpp b/src/plugins/fossil/fossilsettings.cpp index 130ff5c2c56..7fdea5f075d 100644 --- a/src/plugins/fossil/fossilsettings.cpp +++ b/src/plugins/fossil/fossilsettings.cpp @@ -15,8 +15,7 @@ using namespace Utils; -namespace Fossil { -namespace Internal { +namespace Fossil::Internal { FossilSettings::FossilSettings() { @@ -95,80 +94,63 @@ FossilSettings::FossilSettings() logCount.setLabelText(Tr::tr("Log count:")); logCount.setToolTip(Tr::tr("The number of recent commit log entries to show. " "Choose 0 to see all entries.")); -}; +} // OptionsPage class OptionsPageWidget final : public Core::IOptionsPageWidget { public: - OptionsPageWidget(const std::function &onApply, FossilSettings *settings); - void apply() final; + OptionsPageWidget(FossilSettings *settings) + { + FossilSettings &s = *settings; -private: - const std::function m_onApply; - FossilSettings *m_settings; + using namespace Layouting; + + Column { + Group { + title(Tr::tr("Configuration")), + Row { s.binaryPath } + }, + + Group { + title(Tr::tr("Local Repositories")), + Row { s.defaultRepoPath } + }, + Group { + title(Tr::tr("User")), + Form { + s.userName, br, + s.sslIdentityFile + } + }, + + Group { + title(Tr::tr("Miscellaneous")), + Column { + Row { + s.logCount, + s.timelineWidth, + s.timeout, + st + }, + s.disableAutosync + }, + }, + st + + }.attachTo(this); + + setOnApply([settings] { settings->apply(); }); + } }; -void OptionsPageWidget::apply() -{ - if (!m_settings->isDirty()) - return; - - m_settings->apply(); - m_onApply(); -} - -OptionsPageWidget::OptionsPageWidget(const std::function &onApply, FossilSettings *settings) : - m_onApply(onApply), - m_settings(settings) -{ - FossilSettings &s = *m_settings; - - using namespace Layouting; - - Column { - Group { - title(Tr::tr("Configuration")), - Row { s.binaryPath } - }, - - Group { - title(Tr::tr("Local Repositories")), - Row { s.defaultRepoPath } - }, - Group { - title(Tr::tr("User")), - Form { - s.userName, br, - s.sslIdentityFile - } - }, - - Group { - title(Tr::tr("Miscellaneous")), - Column { - Row { - s.logCount, - s.timelineWidth, - s.timeout, - st - }, - s.disableAutosync - }, - }, - st - - }.attachTo(this); -} - -OptionsPage::OptionsPage(const std::function &onApply, FossilSettings *settings) +OptionsPage::OptionsPage(FossilSettings *settings) { setId(Constants::VCS_ID_FOSSIL); setDisplayName(Tr::tr("Fossil")); - setWidgetCreator([onApply, settings]() { return new OptionsPageWidget(onApply, settings); }); + setWidgetCreator([settings] { return new OptionsPageWidget(settings); }); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); } -} // Internal -} // Fossil +} // Fossil::Internal diff --git a/src/plugins/fossil/fossilsettings.h b/src/plugins/fossil/fossilsettings.h index e4133393f66..f1a872ee0d1 100644 --- a/src/plugins/fossil/fossilsettings.h +++ b/src/plugins/fossil/fossilsettings.h @@ -6,12 +6,13 @@ #include #include -namespace Fossil { -namespace Internal { +namespace Fossil::Internal { class FossilSettings : public VcsBase::VcsBaseSettings { public: + FossilSettings(); + Utils::StringAspect defaultRepoPath; Utils::StringAspect sslIdentityFile; Utils::BoolAspect diffIgnoreAllWhiteSpace; @@ -23,8 +24,6 @@ public: Utils::BoolAspect timelineVerbose; Utils::StringAspect timelineItemType; Utils::BoolAspect disableAutosync; - - FossilSettings(); }; struct RepositorySettings @@ -46,8 +45,7 @@ inline bool operator==(const RepositorySettings &lh, const RepositorySettings &r class OptionsPage : public Core::IOptionsPage { public: - OptionsPage(const std::function &onApply, FossilSettings *settings); + explicit OptionsPage(FossilSettings *settings); }; -} // namespace Internal -} // namespace Fossil +} // Fossil::Internal From ef4fa870fc2f688ddc2f137954d1988cac2ef1b5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 11:32:51 +0200 Subject: [PATCH 1045/1447] Fossil: Make operator== fro RepositorySettings a hidden friend Change-Id: I82091ddec03ea10ef0fbd5ec2767a8219a2a3a76 Reviewed-by: Orgad Shaneh --- src/plugins/fossil/fossilsettings.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/fossil/fossilsettings.h b/src/plugins/fossil/fossilsettings.h index f1a872ee0d1..8cdbb9c3f6c 100644 --- a/src/plugins/fossil/fossilsettings.h +++ b/src/plugins/fossil/fossilsettings.h @@ -33,14 +33,14 @@ struct RepositorySettings QString user; QString sslIdentityFile; AutosyncMode autosync = AutosyncOn; -}; -inline bool operator==(const RepositorySettings &lh, const RepositorySettings &rh) -{ - return (lh.user == rh.user && - lh.sslIdentityFile == rh.sslIdentityFile && - lh.autosync == rh.autosync); -} + friend bool operator==(const RepositorySettings &lh, const RepositorySettings &rh) + { + return lh.user == rh.user + && lh.sslIdentityFile == rh.sslIdentityFile + && lh.autosync == rh.autosync; + } +}; class OptionsPage : public Core::IOptionsPage { From 12f788179ef1548b8969c158b37220d81b20fda7 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 10:55:16 +0200 Subject: [PATCH 1046/1447] Fossil: Make settings more directly accessible I am still not sure how the final pattern may ideally look like but it looks like some kind of singleton access to a plugin's settings helps with clarity. Change-Id: I6a6a5f5b7cfdfb062f5b5231a79086f34e09487f Reviewed-by: Orgad Shaneh --- src/plugins/fossil/fossilclient.cpp | 37 ++++++++----------- src/plugins/fossil/fossilclient.h | 3 +- src/plugins/fossil/fossilplugin.cpp | 16 ++------ src/plugins/fossil/fossilplugin.h | 3 -- src/plugins/fossil/fossilsettings.cpp | 16 +++++--- src/plugins/fossil/fossilsettings.h | 4 +- .../fossil/wizard/fossiljsextension.cpp | 34 ++++------------- src/plugins/fossil/wizard/fossiljsextension.h | 8 +--- 8 files changed, 43 insertions(+), 78 deletions(-) diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index 358a66caafb..83a2938f91e 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -55,9 +55,9 @@ public: addReloadButton(); if (features.testFlag(FossilClient::DiffIgnoreWhiteSpaceFeature)) { mapSetting(addToggleButton("-w", Tr::tr("Ignore All Whitespace")), - &client->settings().diffIgnoreAllWhiteSpace); + &settings().diffIgnoreAllWhiteSpace); mapSetting(addToggleButton("--strip-trailing-cr", Tr::tr("Strip Trailing CR")), - &client->settings().diffStripTrailingCR); + &settings().diffStripTrailingCR); } } }; @@ -73,20 +73,19 @@ public: { QTC_ASSERT(client, return); - FossilSettings &settings = client->settings(); FossilClient::SupportedFeatures features = client->supportedFeatures(); if (features.testFlag(FossilClient::AnnotateBlameFeature)) { mapSetting(addToggleButton("|BLAME|", Tr::tr("Show Committers")), - &settings.annotateShowCommitters); + &settings().annotateShowCommitters); } // Force listVersions setting to false by default. // This way the annotated line number would not get offset by the version list. - settings.annotateListVersions.setValue(false); + settings().annotateListVersions.setValue(false); mapSetting(addToggleButton("--log", Tr::tr("List Versions")), - &settings.annotateListVersions); + &settings().annotateListVersions); } }; @@ -122,8 +121,6 @@ public: void addLineageComboBox() { - FossilSettings &settings = m_client->settings(); - // ancestors/descendants filter // This is a positional argument not an option. // Normally it takes the checkin/branch/tag as an additional parameter @@ -137,23 +134,19 @@ public: ChoiceItem(Tr::tr("Unfiltered"), "") }; mapSetting(addChoices(Tr::tr("Lineage"), QStringList("|LINEAGE|%1|current"), lineageFilterChoices), - &settings.timelineLineageFilter); + &settings().timelineLineageFilter); } void addVerboseToggleButton() { - FossilSettings &settings = m_client->settings(); - // show files mapSetting(addToggleButton("-showfiles", Tr::tr("Verbose"), Tr::tr("Show files changed in each revision")), - &settings.timelineVerbose); + &settings().timelineVerbose); } void addItemTypeComboBox() { - FossilSettings &settings = m_client->settings(); - // option: -t const QList itemTypeChoices = { ChoiceItem(Tr::tr("All Items"), "all"), @@ -169,7 +162,7 @@ public: // Fossil expects separate arguments for option and value ( i.e. "-t" "all") // so we need to handle the splitting explicitly in arguments(). mapSetting(addChoices(Tr::tr("Item Types"), QStringList("-t %1"), itemTypeChoices), - &settings.timelineItemType); + &settings().timelineItemType); } QStringList arguments() const final @@ -224,19 +217,19 @@ QString FossilClient::makeVersionString(unsigned version) .arg(versionPart(version)); } -FossilClient::FossilClient(FossilSettings *settings) - : VcsBaseClient(settings), m_settings(settings) +FossilSettings &FossilClient::settings() const +{ + return Internal::settings(); +} + +FossilClient::FossilClient() + : VcsBaseClient(&Internal::settings()) { setDiffConfigCreator([this](QToolBar *toolBar) { return new FossilDiffConfig(this, toolBar); }); } -FossilSettings &FossilClient::settings() const -{ - return *m_settings; -} - unsigned int FossilClient::synchronousBinaryVersion() const { if (settings().binaryPath.value().isEmpty()) diff --git a/src/plugins/fossil/fossilclient.h b/src/plugins/fossil/fossilclient.h index 21dfeaae046..b3016378461 100644 --- a/src/plugins/fossil/fossilclient.h +++ b/src/plugins/fossil/fossilclient.h @@ -41,7 +41,7 @@ public: static unsigned makeVersionNumber(int major, int minor, int patch); static QString makeVersionString(unsigned version); - explicit FossilClient(FossilSettings *settings); + FossilClient(); FossilSettings &settings() const; unsigned int synchronousBinaryVersion() const; @@ -107,7 +107,6 @@ private: VcsBase::VcsBaseEditorConfig *createLogEditor(VcsBase::VcsBaseEditorWidget *editor); friend class FossilPluginPrivate; - FossilSettings *m_settings = nullptr; }; Q_DECLARE_OPERATORS_FOR_FLAGS(FossilClient::SupportedFeatures) diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 825a81bbcab..71833aabc1f 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -187,10 +187,9 @@ public: bool pullOrPush(SyncMode mode); // Variables - FossilSettings m_fossilSettings; - FossilClient m_client{&m_fossilSettings}; + FossilClient m_client; - OptionsPage optionPage{&m_fossilSettings}; + OptionsPage optionPage; VcsSubmitEditorFactory submitEditorFactory { submitEditorParameters, @@ -274,11 +273,6 @@ void FossilPlugin::extensionsInitialized() dd->extensionsInitialized(); } -const FossilSettings &FossilPlugin::settings() -{ - return dd->m_fossilSettings; -} - FossilClient *FossilPlugin::client() { return &dd->m_client; @@ -296,11 +290,9 @@ FossilPluginPrivate::FossilPluginPrivate() m_commandLocator->setDescription(Tr::tr("Triggers a Fossil version control operation.")); ProjectExplorer::JsonWizardFactory::addWizardPath(Utils::FilePath::fromString(Constants::WIZARD_PATH)); - Core::JsExpander::registerGlobalObject("Fossil", [this] { - return new FossilJsExtension(&m_fossilSettings); - }); + Core::JsExpander::registerGlobalObject("Fossil", [] { return new FossilJsExtension; }); - connect(&m_fossilSettings, &AspectContainer::changed, + connect(&settings(), &AspectContainer::changed, this, &IVersionControl::configurationChanged); createMenu(context); diff --git a/src/plugins/fossil/fossilplugin.h b/src/plugins/fossil/fossilplugin.h index b3a45f62dbb..7297cd05ae9 100644 --- a/src/plugins/fossil/fossilplugin.h +++ b/src/plugins/fossil/fossilplugin.h @@ -3,8 +3,6 @@ #pragma once -#include "fossilsettings.h" - #include #include #include @@ -25,7 +23,6 @@ class FossilPlugin final : public ExtensionSystem::IPlugin void extensionsInitialized() final; public: - static const FossilSettings &settings(); static FossilClient *client(); #ifdef WITH_TESTS diff --git a/src/plugins/fossil/fossilsettings.cpp b/src/plugins/fossil/fossilsettings.cpp index 7fdea5f075d..4ee13bd698a 100644 --- a/src/plugins/fossil/fossilsettings.cpp +++ b/src/plugins/fossil/fossilsettings.cpp @@ -101,9 +101,9 @@ FossilSettings::FossilSettings() class OptionsPageWidget final : public Core::IOptionsPageWidget { public: - OptionsPageWidget(FossilSettings *settings) + OptionsPageWidget() { - FossilSettings &s = *settings; + FossilSettings &s = settings(); using namespace Layouting; @@ -141,16 +141,22 @@ public: }.attachTo(this); - setOnApply([settings] { settings->apply(); }); + setOnApply([] { settings().apply(); }); } }; -OptionsPage::OptionsPage(FossilSettings *settings) +OptionsPage::OptionsPage() { setId(Constants::VCS_ID_FOSSIL); setDisplayName(Tr::tr("Fossil")); - setWidgetCreator([settings] { return new OptionsPageWidget(settings); }); + setWidgetCreator([] { return new OptionsPageWidget; }); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); } +FossilSettings &settings() +{ + static FossilSettings theSettings; + return theSettings; +} + } // Fossil::Internal diff --git a/src/plugins/fossil/fossilsettings.h b/src/plugins/fossil/fossilsettings.h index 8cdbb9c3f6c..e373a30cee7 100644 --- a/src/plugins/fossil/fossilsettings.h +++ b/src/plugins/fossil/fossilsettings.h @@ -26,6 +26,8 @@ public: Utils::BoolAspect disableAutosync; }; +FossilSettings &settings(); + struct RepositorySettings { enum AutosyncMode {AutosyncOff, AutosyncOn, AutosyncPullOnly}; @@ -45,7 +47,7 @@ struct RepositorySettings class OptionsPage : public Core::IOptionsPage { public: - explicit OptionsPage(FossilSettings *settings); + OptionsPage(); }; } // Fossil::Internal diff --git a/src/plugins/fossil/wizard/fossiljsextension.cpp b/src/plugins/fossil/wizard/fossiljsextension.cpp index 66747db5674..4c013b503a8 100644 --- a/src/plugins/fossil/wizard/fossiljsextension.cpp +++ b/src/plugins/fossil/wizard/fossiljsextension.cpp @@ -17,19 +17,6 @@ using namespace Core; namespace Fossil { namespace Internal { -class FossilJsExtensionPrivate { -public: - FossilJsExtensionPrivate(FossilSettings *settings) : - m_vscId(Constants::VCS_ID_FOSSIL), - m_settings(settings) - { - } - - Utils::Id m_vscId; - FossilSettings *m_settings; -}; - - QMap FossilJsExtension::parseArgOptions(const QStringList &args) { QMap options; @@ -42,24 +29,19 @@ QMap FossilJsExtension::parseArgOptions(const QStringList &arg return options; } -FossilJsExtension::FossilJsExtension(FossilSettings *settings) : - d(new FossilJsExtensionPrivate(settings)) -{ } +FossilJsExtension::FossilJsExtension() = default; -FossilJsExtension::~FossilJsExtension() -{ - delete d; -} +FossilJsExtension::~FossilJsExtension() = default; bool FossilJsExtension::isConfigured() const { - IVersionControl *vc = VcsManager::versionControl(d->m_vscId); + IVersionControl *vc = VcsManager::versionControl(Constants::VCS_ID_FOSSIL); return vc && vc->isConfigured(); } QString FossilJsExtension::displayName() const { - IVersionControl *vc = VcsManager::versionControl(d->m_vscId); + IVersionControl *vc = VcsManager::versionControl(Constants::VCS_ID_FOSSIL); return vc ? vc->displayName() : QString(); } @@ -68,7 +50,7 @@ QString FossilJsExtension::defaultAdminUser() const if (!isConfigured()) return QString(); - return d->m_settings->userName.value(); + return settings().userName.value(); } QString FossilJsExtension::defaultSslIdentityFile() const @@ -76,7 +58,7 @@ QString FossilJsExtension::defaultSslIdentityFile() const if (!isConfigured()) return QString(); - return d->m_settings->sslIdentityFile.value(); + return settings().sslIdentityFile.value(); } QString FossilJsExtension::defaultLocalRepoPath() const @@ -84,7 +66,7 @@ QString FossilJsExtension::defaultLocalRepoPath() const if (!isConfigured()) return QString(); - return d->m_settings->defaultRepoPath.value(); + return settings().defaultRepoPath.value(); } bool FossilJsExtension::defaultDisableAutosync() const @@ -92,7 +74,7 @@ bool FossilJsExtension::defaultDisableAutosync() const if (!isConfigured()) return false; - return d->m_settings->disableAutosync.value(); + return settings().disableAutosync.value(); } } // namespace Internal diff --git a/src/plugins/fossil/wizard/fossiljsextension.h b/src/plugins/fossil/wizard/fossiljsextension.h index 3a37fc5280a..0947693d581 100644 --- a/src/plugins/fossil/wizard/fossiljsextension.h +++ b/src/plugins/fossil/wizard/fossiljsextension.h @@ -12,9 +12,6 @@ namespace Fossil { namespace Internal { -class FossilJsExtensionPrivate; -class FossilSettings; - class FossilJsExtension : public QObject { Q_OBJECT @@ -22,7 +19,7 @@ class FossilJsExtension : public QObject public: static QMap parseArgOptions(const QStringList &args); - FossilJsExtension(FossilSettings *settings); + FossilJsExtension(); ~FossilJsExtension(); Q_INVOKABLE bool isConfigured() const; @@ -31,9 +28,6 @@ public: Q_INVOKABLE QString defaultSslIdentityFile() const; Q_INVOKABLE QString defaultLocalRepoPath() const; Q_INVOKABLE bool defaultDisableAutosync() const; - -private: - FossilJsExtensionPrivate *d = nullptr; }; } // namespace Internal From c158921af32e44e9e2850d853f83450651758dd7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 4 May 2023 09:06:46 +0200 Subject: [PATCH 1047/1447] ProjectExplorer: Don't allow remote run in terminal Currently the process stub does not support starting / debugging processes on remote devices. To reflect this the "Run In Terminal" aspect is disabled for remote targets. Fixes: QTCREATORBUG-29058 Change-Id: I9b3bcd65d4db468c683f2743a49227bfbecaf3d3 Reviewed-by: hjk --- src/libs/utils/terminalinterface.cpp | 2 -- .../desktoprunconfiguration.cpp | 3 +- .../runconfigurationaspects.cpp | 5 +-- src/tools/process_stub/main.cpp | 31 +------------------ 4 files changed, 6 insertions(+), 35 deletions(-) diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index 6972184e325..6767c16c61f 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -183,8 +183,6 @@ void TerminalInterface::onStubReadyRead() emitFinished(out.mid(5).toInt(), QProcess::NormalExit); } else if (out.startsWith("crash ")) { emitFinished(out.mid(6).toInt(), QProcess::CrashExit); - } else if (out.startsWith("qtc: ")) { - emit readyRead(out.mid(5) + "\n", {}); } else { emitError(QProcess::UnknownError, msgUnexpectedOutput(out)); break; diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp index 82d0123b117..286f5c4b6e0 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp +++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp @@ -87,7 +87,8 @@ void DesktopRunConfiguration::updateTargetInformation() BuildTargetInfo bti = buildTargetInfo(); auto terminalAspect = aspect(); - terminalAspect->setUseTerminalHint(bti.usesTerminal); + terminalAspect->setUseTerminalHint(bti.targetFilePath.needsDevice() ? false : bti.usesTerminal); + terminalAspect->setEnabled(!bti.targetFilePath.needsDevice()); if (m_kind == Qmake) { diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 88dd720ee31..8098606afb0 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -65,8 +65,9 @@ TerminalAspect::TerminalAspect() void TerminalAspect::addToLayout(LayoutItem &parent) { QTC_CHECK(!m_checkBox); - m_checkBox = new QCheckBox(Tr::tr("Run in terminal")); + m_checkBox = createSubWidget(Tr::tr("Run in terminal")); m_checkBox->setChecked(m_useTerminal); + m_checkBox->setEnabled(isEnabled()); parent.addItems({{}, m_checkBox.data()}); connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] { m_userSet = true; @@ -123,7 +124,7 @@ void TerminalAspect::calculateUseTerminal() */ bool TerminalAspect::useTerminal() const { - return m_useTerminal; + return m_useTerminal && isEnabled(); } /*! diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index ff3437659b9..f606b063694 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -137,11 +137,6 @@ void sendMsg(const QByteArray &msg) } } -void sendQtcMarker(const QByteArray &marker) -{ - sendMsg(QByteArray("qtc: ") + marker + "\n"); -} - void sendPid(int inferiorPid) { sendMsg(QString("pid %1\n").arg(inferiorPid).toUtf8()); @@ -317,31 +312,7 @@ void startProcess(const QString &executable, const QStringList &arguments, const QCoreApplication::instance(), &onInferiorStarted); - inferiorProcess.setProcessChannelMode(QProcess::SeparateChannels); - - QObject::connect(&inferiorProcess, - &QProcess::readyReadStandardOutput, - QCoreApplication::instance(), - [] { - const QByteArray data = inferiorProcess.readAllStandardOutput(); - static bool isFirst = true; - if (isFirst) { - isFirst = false; - if (data.startsWith("__qtc")) { - int lineBreak = data.indexOf("\r\n"); - sendQtcMarker(data.mid(0, lineBreak)); - if (lineBreak != -1) - writeToOut(data.mid(lineBreak + 2), Out::StdOut); - return; - } - } - writeToOut(data, Out::StdOut); - }); - - QObject::connect(&inferiorProcess, - &QProcess::readyReadStandardError, - QCoreApplication::instance(), - [] { writeToOut(inferiorProcess.readAllStandardError(), Out::StdErr); }); + inferiorProcess.setProcessChannelMode(QProcess::ForwardedChannels); if (!(testMode && debugMode)) inferiorProcess.setInputChannelMode(QProcess::ForwardedInputChannel); From 948dc6b37edaea86c067fe2c4750977d7272314e Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Thu, 11 May 2023 14:52:51 +0200 Subject: [PATCH 1048/1447] ClangFormat: Fix clangformat ignores configuration file Fixes: QTCREATORBUG-29145 Change-Id: I6950151aaab9df51cfdd0af0ad9cf3c7b35c0636 Reviewed-by: Christian Kandeler --- .../clangformat/clangformatglobalconfigwidget.cpp | 9 +++++++-- src/plugins/clangformat/clangformatglobalconfigwidget.h | 1 + src/plugins/clangformat/clangformatutils.cpp | 7 +------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index 1f810c968cd..5579e594e1c 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -41,6 +41,7 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget( m_overrideDefault = new QCheckBox(Tr::tr("Override Clang Format configuration file")); m_useGlobalSettings = new QCheckBox(Tr::tr("Use global settings")); m_useGlobalSettings->hide(); + m_overrideDefaultFile = ClangFormatSettings::instance().overrideDefaultFile(); using namespace Layouting; @@ -180,10 +181,12 @@ void ClangFormatGlobalConfigWidget::initOverrideCheckBox() setTemporarilyReadOnly(); connect(m_overrideDefault, &QCheckBox::toggled, this, [this, setTemporarilyReadOnly](bool checked) { - if (m_project) + if (m_project) { m_project->setNamedSettings(Constants::OVERRIDE_FILE_ID, checked); - else + } else { + ClangFormatSettings::instance().setOverrideDefaultFile(checked); setTemporarilyReadOnly(); + } }); connect(m_codeStyle, @@ -202,12 +205,14 @@ void ClangFormatGlobalConfigWidget::apply() settings.setMode( static_cast(m_indentingOrFormatting->currentIndex())); settings.setOverrideDefaultFile(m_overrideDefault->isChecked()); + m_overrideDefaultFile = m_overrideDefault->isChecked(); } settings.write(); } void ClangFormatGlobalConfigWidget::finish() { + ClangFormatSettings::instance().setOverrideDefaultFile(m_overrideDefaultFile); m_codeStyle->currentPreferences()->setTemporarilyReadOnly( !ClangFormatSettings::instance().overrideDefaultFile()); } diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.h b/src/plugins/clangformat/clangformatglobalconfigwidget.h index 962a7daaf17..7b2d6fe7c9c 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.h +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.h @@ -43,6 +43,7 @@ private: ProjectExplorer::Project *m_project; TextEditor::ICodeStylePreferences *m_codeStyle; Utils::Guard m_ignoreChanges; + bool m_overrideDefaultFile; QLabel *m_projectHasClangFormat; QLabel *m_formattingModeLabel; diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index a9f1a0d29b2..95632db7a09 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -214,12 +214,7 @@ bool getCurrentOverriddenSettings(const Utils::FilePath &filePath) filePath); return getProjectUseGlobalSettings(project) - ? !TextEditor::TextEditorSettings::codeStyle("Cpp") - ->currentPreferences() - ->isTemporarilyReadOnly() - && !TextEditor::TextEditorSettings::codeStyle("Cpp") - ->currentPreferences() - ->isAdditionalTabDisabled() + ? ClangFormatSettings::instance().overrideDefaultFile() : getProjectOverriddenSettings(project); } From 72d9decb877c158e79f6b21c7aab5a006985c024 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 15 May 2023 12:24:48 +0200 Subject: [PATCH 1049/1447] QEventLoop: Remove unused includes Change-Id: Ic278aa9b204a3caa17e38125d07a0176a8281422 Reviewed-by: Christian Kandeler --- src/plugins/android/androiddevice.cpp | 1 - src/plugins/clangtools/clangtoolsunittests.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index a8ae3f8746b..ce2f4c11ee7 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include diff --git a/src/plugins/clangtools/clangtoolsunittests.cpp b/src/plugins/clangtools/clangtoolsunittests.cpp index c8650c0b771..0672d430548 100644 --- a/src/plugins/clangtools/clangtoolsunittests.cpp +++ b/src/plugins/clangtools/clangtoolsunittests.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include From 9dad4ab9d4f3b638ab3df6cd45eca1fbaa51fa96 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 11 May 2023 08:49:06 +0200 Subject: [PATCH 1050/1447] CMakeProjectManager: Rework CMakeFormatter Use PagedSettings, make setup more local, remove Q_OBJECT Change-Id: I9e91f9e63ed8ad15749323bd039d118562dba1a6 Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/CMakeLists.txt | 2 - .../cmakeprojectmanager/cmakeformatter.cpp | 201 +++++++++++++++--- .../cmakeprojectmanager/cmakeformatter.h | 31 +-- .../cmakeformatteroptionspage.cpp | 99 --------- .../cmakeformatteroptionspage.h | 17 -- .../cmakeformattersettings.cpp | 135 ------------ .../cmakeformattersettings.h | 58 ----- .../cmakeprojectmanager.qbs | 4 - .../cmakeprojectplugin.cpp | 74 ------- 9 files changed, 176 insertions(+), 445 deletions(-) delete mode 100644 src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp delete mode 100644 src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.h delete mode 100644 src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp delete mode 100644 src/plugins/cmakeprojectmanager/cmakeformattersettings.h diff --git a/src/plugins/cmakeprojectmanager/CMakeLists.txt b/src/plugins/cmakeprojectmanager/CMakeLists.txt index e12c9656a83..3d9dc4849e0 100644 --- a/src/plugins/cmakeprojectmanager/CMakeLists.txt +++ b/src/plugins/cmakeprojectmanager/CMakeLists.txt @@ -16,8 +16,6 @@ add_qtc_plugin(CMakeProjectManager cmakeeditor.cpp cmakeeditor.h cmakefilecompletionassist.cpp cmakefilecompletionassist.h cmakeformatter.cpp cmakeformatter.h - cmakeformatteroptionspage.cpp cmakeformatteroptionspage.h - cmakeformattersettings.cpp cmakeformattersettings.h cmakeindenter.cpp cmakeindenter.h cmakeinstallstep.cpp cmakeinstallstep.h cmakekitinformation.cpp cmakekitinformation.h diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp index d9aa8b2c84a..3996946e470 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp @@ -4,7 +4,6 @@ #include "cmakeformatter.h" -#include "cmakeformattersettings.h" #include "cmakeprojectconstants.h" #include "cmakeprojectmanagertr.h" @@ -12,62 +11,198 @@ #include #include #include +#include #include #include +#include #include #include #include #include +#include #include #include -#include -#include +#include +#include +#include +#include +#include + +using namespace Core; using namespace TextEditor; +using namespace Utils; -namespace CMakeProjectManager { -namespace Internal { +namespace CMakeProjectManager::Internal { -void CMakeFormatter::updateActions(Core::IEditor *editor) +class CMakeFormatterPrivate : public PagedSettings { - const bool enabled = editor && CMakeFormatterSettings::instance()->isApplicable(editor->document()); - m_formatFile->setEnabled(enabled); +public: + CMakeFormatterPrivate() + { + setSettingsGroups(Constants::CMAKEFORMATTER_SETTINGS_GROUP, + Constants::CMAKEFORMATTER_GENERAL_GROUP); + + setId(Constants::Settings::FORMATTER_ID); + setDisplayName(Tr::tr("Formatter")); + setDisplayCategory("CMake"); + setCategory(Constants::Settings::CATEGORY); + + registerAspect(&command); + command.setSettingsKey("autoFormatCommand"); + command.setDisplayStyle(StringAspect::PathChooserDisplay); + command.setDefaultValue("cmake-format"); + command.setExpectedKind(PathChooser::ExistingCommand); + + registerAspect(&autoFormatOnSave); + autoFormatOnSave.setSettingsKey("autoFormatOnSave"); + autoFormatOnSave.setLabelText(Tr::tr("Enable auto format on file save")); + + registerAspect(&autoFormatOnlyCurrentProject); + autoFormatOnlyCurrentProject.setSettingsKey("autoFormatOnlyCurrentProject"); + autoFormatOnlyCurrentProject.setDefaultValue(true); + autoFormatOnlyCurrentProject.setLabelText(Tr::tr("Restrict to files contained in the current project")); + + registerAspect(&autoFormatMime); + autoFormatMime.setSettingsKey("autoFormatMime"); + autoFormatMime.setDefaultValue("text/x-cmake"); + autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:")); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + Column { + Row { Tr::tr("CMakeFormat command:"), command }, + Space(10), + Group { + title(Tr::tr("Automatic Formatting on File Save")), + autoFormatOnSave.groupChecker(), + Form { + autoFormatMime, br, + Span(2, autoFormatOnlyCurrentProject) + } + }, + st + }.attachTo(widget); + }); + + ActionContainer *menu = ActionManager::createMenu(Constants::CMAKEFORMATTER_MENU_ID); + menu->menu()->setTitle(Tr::tr("CMakeFormatter")); + menu->setOnAllDisabledBehavior(ActionContainer::Show); + ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu); + + Core::Command *cmd = ActionManager::registerAction(&formatFile, Constants::CMAKEFORMATTER_ACTION_ID); + connect(&formatFile, &QAction::triggered, this, [this] { + TextEditor::formatCurrentFile(formatCommand()); + }); + + ActionManager::actionContainer(Constants::CMAKEFORMATTER_MENU_ID)->addAction(cmd); + + auto updateActions = [this] { + auto editor = EditorManager::currentEditor(); + formatFile.setEnabled(editor && isApplicable(editor->document())); + }; + + connect(&autoFormatMime, &Utils::StringAspect::changed, + this, updateActions); + connect(EditorManager::instance(), &EditorManager::currentEditorChanged, + this, updateActions); + connect(EditorManager::instance(), &EditorManager::aboutToSave, + this, &CMakeFormatterPrivate::applyIfNecessary); + + readSettings(ICore::settings()); + } + + bool isApplicable(const IDocument *document) const; + + void applyIfNecessary(IDocument *document) const; + + TextEditor::Command formatCommand() const + { + TextEditor::Command cmd; + cmd.setExecutable(command.filePath()); + cmd.setProcessing(TextEditor::Command::FileProcessing); + cmd.addOption("--in-place"); + cmd.addOption("%file"); + return cmd; + } + + StringAspect command; + BoolAspect autoFormatOnSave; + BoolAspect autoFormatOnlyCurrentProject; + StringAspect autoFormatMime; + + QAction formatFile{Tr::tr("Format &Current File")}; +}; + +bool CMakeFormatterPrivate::isApplicable(const IDocument *document) const +{ + if (!document) + return false; + + if (autoFormatMime.value().isEmpty()) + return true; + + const QStringList allowedMimeTypes = autoFormatMime.value().split(';'); + const MimeType documentMimeType = Utils::mimeTypeForName(document->mimeType()); + + return anyOf(allowedMimeTypes, [&documentMimeType](const QString &mime) { + return documentMimeType.inherits(mime); + }); } -void CMakeFormatter::formatFile() +void CMakeFormatterPrivate::applyIfNecessary(IDocument *document) const { - formatCurrentFile(command()); + if (!autoFormatOnSave.value()) + return; + + if (!document) + return; + + if (!isApplicable(document)) + return; + + // Check if file is contained in the current project (if wished) + if (autoFormatOnlyCurrentProject.value()) { + const ProjectExplorer::Project *pro = ProjectExplorer::ProjectTree::currentProject(); + if (!pro || pro->files([document](const ProjectExplorer::Node *n) { + return ProjectExplorer::Project::SourceFiles(n) + && n->filePath() == document->filePath(); + }).isEmpty()) { + return; + } + } + + TextEditor::Command command = formatCommand(); + if (!command.isValid()) + return; + + const QList editors = DocumentModel::editorsForDocument(document); + if (editors.isEmpty()) + return; + + IEditor *currentEditor = EditorManager::currentEditor(); + IEditor *editor = editors.contains(currentEditor) ? currentEditor : editors.first(); + if (auto widget = TextEditorWidget::fromEditor(editor)) + TextEditor::formatEditor(widget, command); } -Command CMakeFormatter::command() const +// CMakeFormatter + +CMakeFormatter::CMakeFormatter() + : d(new CMakeFormatterPrivate) +{} + +CMakeFormatter::~CMakeFormatter() { - Command command; - command.setExecutable(CMakeFormatterSettings::instance()->command()); - command.setProcessing(Command::FileProcessing); - command.addOption("--in-place"); - command.addOption("%file"); - return command; + delete d; } -bool CMakeFormatter::isApplicable(const Core::IDocument *document) const +void CMakeFormatter::applyIfNecessary(IDocument *document) const { - return CMakeFormatterSettings::instance()->isApplicable(document); + d->applyIfNecessary(document); } -void CMakeFormatter::initialize() -{ - m_formatFile = new QAction(Tr::tr("Format &Current File"), this); - Core::Command *cmd = Core::ActionManager::registerAction(m_formatFile, Constants::CMAKEFORMATTER_ACTION_ID); - connect(m_formatFile, &QAction::triggered, this, &CMakeFormatter::formatFile); - - Core::ActionManager::actionContainer(Constants::CMAKEFORMATTER_MENU_ID)->addAction(cmd); - - connect(CMakeFormatterSettings::instance(), &CMakeFormatterSettings::supportedMimeTypesChanged, - [this] { updateActions(Core::EditorManager::currentEditor()); }); -} - -} // namespace Internal -} // namespace CMakeProjectManager +} // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.h b/src/plugins/cmakeprojectmanager/cmakeformatter.h index f3fc3a28c53..9727c245a50 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatter.h +++ b/src/plugins/cmakeprojectmanager/cmakeformatter.h @@ -4,35 +4,20 @@ #pragma once -#include +namespace Core { class IDocument; } -#include "cmakeformatteroptionspage.h" +namespace CMakeProjectManager::Internal { -namespace Core { -class IDocument; -class IEditor; -} - -namespace CMakeProjectManager { -namespace Internal { - -class CMakeFormatter : public QObject +class CMakeFormatter { - Q_OBJECT - public: - void updateActions(Core::IEditor *editor); - TextEditor::Command command() const; - bool isApplicable(const Core::IDocument *document) const; + CMakeFormatter(); + ~CMakeFormatter(); - void initialize(); + void applyIfNecessary(Core::IDocument *document) const; private: - void formatFile(); - - QAction *m_formatFile = nullptr; - CMakeFormatterOptionsPage m_page; + class CMakeFormatterPrivate *d = nullptr; }; -} // namespace Internal -} // namespace CMakeProjectManager +} // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp b/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp deleted file mode 100644 index 2e089469910..00000000000 --- a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// Copyright (C) 2022 Xavier BESSON -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "cmakeformatteroptionspage.h" - -#include "cmakeprojectconstants.h" -#include "cmakeprojectmanagertr.h" -#include "cmakeformattersettings.h" - -#include -#include - -#include -#include -#include -#include -#include - -namespace CMakeProjectManager::Internal { - -class CMakeFormatterOptionsPageWidget : public Core::IOptionsPageWidget -{ -public: - explicit CMakeFormatterOptionsPageWidget(); - -private: - void apply() final; - - Utils::PathChooser *m_command; - QCheckBox *m_autoFormat; - QLineEdit *m_autoFormatMime; - QCheckBox *m_autoFormatOnlyCurrentProject; -}; - -CMakeFormatterOptionsPageWidget::CMakeFormatterOptionsPageWidget() -{ - auto settings = CMakeFormatterSettings::instance(); - - m_autoFormat = new QCheckBox(Tr::tr("Enable auto format on file save")); - m_autoFormat->setChecked(settings->autoFormatOnSave()); - - auto mimeLabel = new QLabel(Tr::tr("Restrict to MIME types:")); - mimeLabel->setEnabled(false); - - m_autoFormatMime = new QLineEdit(settings->autoFormatMimeAsString()); - m_autoFormatMime->setEnabled(m_autoFormat->isChecked()); - - m_autoFormatOnlyCurrentProject = - new QCheckBox(Tr::tr("Restrict to files contained in the current project")); - m_autoFormatOnlyCurrentProject->setEnabled(m_autoFormat->isChecked()); - m_autoFormatOnlyCurrentProject->setChecked(settings->autoFormatOnlyCurrentProject()); - - m_command = new Utils::PathChooser; - m_command->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_command->setCommandVersionArguments({"--version"}); - m_command->setPromptDialogTitle(Tr::tr("%1 Command").arg(Tr::tr("Formatter"))); - m_command->setFilePath(settings->command()); - - using namespace Layouting; - - Column { - Group { - title(Tr::tr("Automatic Formatting on File Save")), - Form { - Tr::tr("CMakeFormat command:"), m_command, br, - Span(2, m_autoFormat), br, - mimeLabel, m_autoFormatMime, br, - Span(2, m_autoFormatOnlyCurrentProject) - } - }, - st - }.attachTo(this); - - connect(m_autoFormat, &QCheckBox::toggled, m_autoFormatMime, &QLineEdit::setEnabled); - connect(m_autoFormat, &QCheckBox::toggled, mimeLabel, &QLabel::setEnabled); - connect(m_autoFormat, &QCheckBox::toggled, m_autoFormatOnlyCurrentProject, &QCheckBox::setEnabled); -} - -void CMakeFormatterOptionsPageWidget::apply() -{ - auto settings = CMakeFormatterSettings::instance(); - settings->setCommand(m_command->filePath().toString()); - settings->setAutoFormatOnSave(m_autoFormat->isChecked()); - settings->setAutoFormatMime(m_autoFormatMime->text()); - settings->setAutoFormatOnlyCurrentProject(m_autoFormatOnlyCurrentProject->isChecked()); - settings->save(); -} - -CMakeFormatterOptionsPage::CMakeFormatterOptionsPage() -{ - setId(Constants::Settings::FORMATTER_ID); - setDisplayName(Tr::tr("Formatter")); - setDisplayCategory("CMake"); - setCategory(Constants::Settings::CATEGORY); - setWidgetCreator([] { return new CMakeFormatterOptionsPageWidget; }); -} - -} // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.h b/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.h deleted file mode 100644 index 08cfac3590c..00000000000 --- a/src/plugins/cmakeprojectmanager/cmakeformatteroptionspage.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// Copyright (C) 2022 Xavier BESSON -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace CMakeProjectManager::Internal { - -class CMakeFormatterOptionsPage final : public Core::IOptionsPage -{ -public: - explicit CMakeFormatterOptionsPage(); -}; - -} // CMakeProjectManager::Internal diff --git a/src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp b/src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp deleted file mode 100644 index 258954fa115..00000000000 --- a/src/plugins/cmakeprojectmanager/cmakeformattersettings.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// Copyright (C) 2022 Xavier BESSON -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "cmakeformattersettings.h" -#include "cmakeprojectconstants.h" - -#include -#include -#include -#include -#include -#include - -namespace CMakeProjectManager { -namespace Internal { - -namespace { -const char AUTO_FORMAT_COMMAND[] = "autoFormatCommand"; -const char AUTO_FORMAT_MIME[] = "autoFormatMime"; -const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "autoFormatOnlyCurrentProject"; -const char AUTO_FORMAT_ON_SAVE[] = "autoFormatOnSave"; -} - -CMakeFormatterSettings::CMakeFormatterSettings(QObject* parent) - : QObject(parent) -{ - read(); -} - -CMakeFormatterSettings *CMakeFormatterSettings::instance() -{ - static CMakeFormatterSettings m_instance; - return &m_instance; -} - -void CMakeFormatterSettings::read() -{ - QSettings *s = Core::ICore::settings(); - s->beginGroup(Constants::CMAKEFORMATTER_SETTINGS_GROUP); - s->beginGroup(Constants::CMAKEFORMATTER_GENERAL_GROUP); - setCommand(s->value(AUTO_FORMAT_COMMAND, QString("cmake-format")).toString()); - m_autoFormatOnSave = s->value(AUTO_FORMAT_ON_SAVE, false).toBool(); - setAutoFormatMime(s->value(AUTO_FORMAT_MIME, QString("text/x-cmake")).toString()); - m_autoFormatOnlyCurrentProject = s->value(AUTO_FORMAT_ONLY_CURRENT_PROJECT, true).toBool(); - s->endGroup(); - s->endGroup(); -} - -void CMakeFormatterSettings::save() -{ - QSettings *s = Core::ICore::settings(); - s->beginGroup(Constants::CMAKEFORMATTER_SETTINGS_GROUP); - s->beginGroup(Constants::CMAKEFORMATTER_GENERAL_GROUP); - Utils::QtcSettings::setValueWithDefault(s, AUTO_FORMAT_COMMAND, m_command, QString("cmake-format")); - Utils::QtcSettings::setValueWithDefault(s, AUTO_FORMAT_ON_SAVE, m_autoFormatOnSave, false); - Utils::QtcSettings::setValueWithDefault(s, AUTO_FORMAT_MIME, autoFormatMimeAsString(), QString("text/x-cmake")); - Utils::QtcSettings::setValueWithDefault(s, AUTO_FORMAT_ONLY_CURRENT_PROJECT, m_autoFormatOnlyCurrentProject, true); - s->endGroup(); - s->endGroup(); -} - -Utils::FilePath CMakeFormatterSettings::command() const -{ - return Utils::FilePath::fromString(m_command); -} - -void CMakeFormatterSettings::setCommand(const QString &cmd) -{ - if (cmd == m_command) - return; - - m_command = cmd; -} - -bool CMakeFormatterSettings::autoFormatOnSave() const -{ - return m_autoFormatOnSave; -} - -void CMakeFormatterSettings::setAutoFormatOnSave(bool autoFormatOnSave) -{ - m_autoFormatOnSave = autoFormatOnSave; -} - -QStringList CMakeFormatterSettings::autoFormatMime() const -{ - return m_autoFormatMime; -} - -QString CMakeFormatterSettings::autoFormatMimeAsString() const -{ - return m_autoFormatMime.join("; "); -} - -void CMakeFormatterSettings::setAutoFormatMime(const QStringList &autoFormatMime) -{ - if (m_autoFormatMime == autoFormatMime) - return; - - m_autoFormatMime = autoFormatMime; - emit supportedMimeTypesChanged(); -} - -void CMakeFormatterSettings::setAutoFormatMime(const QString &mimeList) -{ - setAutoFormatMime(mimeList.split(';')); -} - -bool CMakeFormatterSettings::autoFormatOnlyCurrentProject() const -{ - return m_autoFormatOnlyCurrentProject; -} - -void CMakeFormatterSettings::setAutoFormatOnlyCurrentProject(bool autoFormatOnlyCurrentProject) -{ - m_autoFormatOnlyCurrentProject = autoFormatOnlyCurrentProject; -} - -bool CMakeFormatterSettings::isApplicable(const Core::IDocument *document) const -{ - if (!document) - return false; - - if (m_autoFormatMime.isEmpty()) - return true; - - const Utils::MimeType documentMimeType = Utils::mimeTypeForName(document->mimeType()); - return Utils::anyOf(m_autoFormatMime, [&documentMimeType](const QString &mime) { - return documentMimeType.inherits(mime); - }); -} - -} // namespace Internal -} // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeformattersettings.h b/src/plugins/cmakeprojectmanager/cmakeformattersettings.h deleted file mode 100644 index ea8a3ba1628..00000000000 --- a/src/plugins/cmakeprojectmanager/cmakeformattersettings.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// Copyright (C) 2022 Xavier BESSON -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include -#include - -namespace Core { class IDocument; } -namespace Utils { class FilePath; } - -namespace CMakeProjectManager { -namespace Internal { - -class VersionUpdater; - -class CMakeFormatterSettings : public QObject -{ - Q_OBJECT -public: - explicit CMakeFormatterSettings(QObject* parent = nullptr); - static CMakeFormatterSettings *instance(); - - void read(); - void save(); - - Utils::FilePath command() const; - void setCommand(const QString &cmd); - - bool autoFormatOnSave() const; - void setAutoFormatOnSave(bool autoFormatOnSave); - - QStringList autoFormatMime() const; - QString autoFormatMimeAsString() const; - void setAutoFormatMime(const QStringList &autoFormatMime); - void setAutoFormatMime(const QString &mimeList); - - bool autoFormatOnlyCurrentProject() const; - void setAutoFormatOnlyCurrentProject(bool autoFormatOnlyCurrentProject); - - bool isApplicable(const Core::IDocument *document) const; - -signals: - void supportedMimeTypesChanged(); - -private: - QString m_command; - - bool m_autoFormatOnSave = false; - bool m_autoFormatOnlyCurrentProject = true; - QString m_autoFormatTool; - QStringList m_autoFormatMime; -}; - -} // namespace Internal -} // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs index f3eca551292..79d8c219f27 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs @@ -35,10 +35,6 @@ QtcPlugin { "cmakefilecompletionassist.h", "cmakeformatter.cpp", "cmakeformatter.h", - "cmakeformatteroptionspage.cpp", - "cmakeformatteroptionspage.h", - "cmakeformattersettings.cpp", - "cmakeformattersettings.h", "cmakeinstallstep.cpp", "cmakeinstallstep.h", "cmakekitinformation.h", diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp index 109a44bf9c0..39e3ec29269 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp @@ -8,7 +8,6 @@ #include "cmakebuildsystem.h" #include "cmakeeditor.h" #include "cmakeformatter.h" -#include "cmakeformattersettings.h" #include "cmakeinstallstep.h" #include "cmakekitinformation.h" #include "cmakelocatorfilter.h" @@ -43,27 +42,9 @@ using namespace Utils; namespace CMakeProjectManager::Internal { -bool isAutoFormatApplicable(const Core::IDocument *document, const QStringList &allowedMimeTypes) -{ - if (!document) - return false; - - if (allowedMimeTypes.isEmpty()) - return true; - - const Utils::MimeType documentMimeType = Utils::mimeTypeForName(document->mimeType()); - return Utils::anyOf(allowedMimeTypes, [&documentMimeType](const QString &mime) { - return documentMimeType.inherits(mime); - }); -} - class CMakeProjectPluginPrivate : public QObject { public: - CMakeProjectPluginPrivate(); - void updateActions(Core::IEditor *editor = nullptr); - void autoFormatOnSave(Core::IDocument *document); - CMakeToolManager cmakeToolManager; // have that before the first CMakeKitAspect ParameterAction buildTargetContextAction{ @@ -90,53 +71,6 @@ public: CMakeFormatter cmakeFormatter; }; -CMakeProjectPluginPrivate::CMakeProjectPluginPrivate() -{ - const Core::EditorManager *editorManager = Core::EditorManager::instance(); - QObject::connect(editorManager, &Core::EditorManager::currentEditorChanged, - this, &CMakeProjectPluginPrivate::updateActions); - QObject::connect(editorManager, &Core::EditorManager::aboutToSave, - this, &CMakeProjectPluginPrivate::autoFormatOnSave); -} - -void CMakeProjectPluginPrivate::updateActions(Core::IEditor *editor) -{ - cmakeFormatter.updateActions(editor); -} - -void CMakeProjectPluginPrivate::autoFormatOnSave(Core::IDocument *document) -{ - if (!CMakeFormatterSettings::instance()->autoFormatOnSave()) - return; - - if (!isAutoFormatApplicable(document, CMakeFormatterSettings::instance()->autoFormatMime())) - return; - - // Check if file is contained in the current project (if wished) - if (CMakeFormatterSettings::instance()->autoFormatOnlyCurrentProject()) { - const ProjectExplorer::Project *pro = ProjectExplorer::ProjectTree::currentProject(); - if (!pro || pro->files([document](const ProjectExplorer::Node *n) { - return ProjectExplorer::Project::SourceFiles(n) - && n->filePath() == document->filePath(); - }).isEmpty()) { - return; - } - } - - if (!cmakeFormatter.isApplicable(document)) - return; - const TextEditor::Command command = cmakeFormatter.command(); - if (!command.isValid()) - return; - const QList editors = Core::DocumentModel::editorsForDocument(document); - if (editors.isEmpty()) - return; - IEditor *currentEditor = EditorManager::currentEditor(); - IEditor *editor = editors.contains(currentEditor) ? currentEditor : editors.first(); - if (auto widget = TextEditor::TextEditorWidget::fromEditor(editor)) - TextEditor::formatEditor(widget, command); -} - CMakeProjectPlugin::~CMakeProjectPlugin() { delete d; @@ -177,14 +111,6 @@ void CMakeProjectPlugin::initialize() bs->buildCMakeTarget(targetNode ? targetNode->displayName() : QString()); } }); - - Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::CMAKEFORMATTER_MENU_ID); - menu->menu()->setTitle(Tr::tr("CMakeFormatter")); - menu->setOnAllDisabledBehavior(Core::ActionContainer::Show); - Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu); - - d->cmakeFormatter.initialize(); - d->updateActions(); } void CMakeProjectPlugin::extensionsInitialized() From c82d7ccdcde982b40ecb6690af2dd182fd8dba75 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 15 May 2023 11:03:16 +0200 Subject: [PATCH 1051/1447] Utils: Delay close signal in pty process The close signal of the conpty process needs to be delayed as it otherwise might arrive before the last output of the process. This should be fixed in the future by using overlapped io for the pipes. Change-Id: I49fe4863672a0b14f5766bbe5ee7b1d8894594ca Reviewed-by: Orgad Shaneh --- src/libs/3rdparty/libptyqt/conptyprocess.cpp | 2 +- src/libs/3rdparty/libptyqt/conptyprocess.h | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.cpp b/src/libs/3rdparty/libptyqt/conptyprocess.cpp index 687d3116f5a..b9a4afd1262 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/conptyprocess.cpp @@ -184,7 +184,7 @@ bool ConPtyProcess::startProcess(const QString &executable, if (!m_aboutToDestruct) emit notifier()->aboutToClose(); m_shellCloseWaitNotifier->setEnabled(false); - }); + }, Qt::QueuedConnection); //this code runned in separate thread m_readThread = QThread::create([this]() { diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.h b/src/libs/3rdparty/libptyqt/conptyprocess.h index ac940489816..d4ffd62b7ee 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.h +++ b/src/libs/3rdparty/libptyqt/conptyprocess.h @@ -115,11 +115,7 @@ public: void emitReadyRead() { - //for emit signal from PtyBuffer own thread - QTimer::singleShot(1, this, [this]() - { - emit readyRead(); - }); + emit readyRead(); } private: From 545a105634057a6c0f7af11425ac26383ed5c7f5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 14:23:01 +0200 Subject: [PATCH 1052/1447] Git: Also use the latest settings setup approach Change-Id: I34a210575d02d18927c1e0f6d8ea6cb9924c563d Reviewed-by: Orgad Shaneh --- src/plugins/git/branchmodel.cpp | 4 +-- src/plugins/git/branchview.cpp | 4 +-- src/plugins/git/gitclient.cpp | 56 ++++++++++++++--------------- src/plugins/git/gitclient.h | 5 +-- src/plugins/git/giteditor.cpp | 2 +- src/plugins/git/gitplugin.cpp | 30 +++++++--------- src/plugins/git/gitplugin.h | 3 -- src/plugins/git/gitsettings.cpp | 14 +++++--- src/plugins/git/gitsettings.h | 4 ++- src/plugins/git/logchangedialog.cpp | 4 +-- 10 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 859f177845c..8a495a8d8f3 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -428,7 +428,7 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) "%(*objectname)\t%(committerdate:raw)\t%(*committerdate:raw)", "refs/heads/**", "refs/remotes/**"}; - if (d->client->settings().showTags.value()) + if (settings().showTags()) args << "refs/tags/**"; d->client->setupCommand(process, workingDirectory, args); }; @@ -805,7 +805,7 @@ void BranchModel::Private::parseOutputLine(const QString &line, bool force) const qint64 age = dateTime.daysTo(QDateTime::currentDateTime()); isOld = age > Constants::OBSOLETE_COMMIT_AGE_IN_DAYS; } - const bool showTags = client->settings().showTags.value(); + const bool showTags = settings().showTags(); // insert node into tree: QStringList nameParts = fullName.split('/'); diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index 3915d20ab80..ff428b1b90e 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -115,7 +115,7 @@ BranchView::BranchView() connect(m_includeOldEntriesAction, &QAction::toggled, this, &BranchView::setIncludeOldEntries); m_includeTagsAction->setCheckable(true); - m_includeTagsAction->setChecked(GitClient::settings().showTags.value()); + m_includeTagsAction->setChecked(settings().showTags.value()); connect(m_includeTagsAction, &QAction::toggled, this, &BranchView::setIncludeTags); @@ -319,7 +319,7 @@ void BranchView::setIncludeOldEntries(bool filter) void BranchView::setIncludeTags(bool includeTags) { - GitClient::settings().showTags.setValue(includeTags); + settings().showTags.setValue(includeTags); refreshCurrentRepository(); } diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index fa42a2565e5..53268c97423 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -491,16 +491,16 @@ class BaseGitDiffArgumentsWidget : public VcsBaseEditorConfig Q_OBJECT public: - BaseGitDiffArgumentsWidget(GitSettings &settings, QToolBar *toolBar) : - VcsBaseEditorConfig(toolBar) + explicit BaseGitDiffArgumentsWidget(QToolBar *toolBar) + : VcsBaseEditorConfig(toolBar) { m_patienceButton = addToggleButton("--patience", Tr::tr("Patience"), Tr::tr("Use the patience algorithm for calculating the differences.")); - mapSetting(m_patienceButton, &settings.diffPatience); + mapSetting(m_patienceButton, &settings().diffPatience); m_ignoreWSButton = addToggleButton("--ignore-space-change", Tr::tr("Ignore Whitespace"), Tr::tr("Ignore whitespace only changes.")); - mapSetting(m_ignoreWSButton, &settings.ignoreSpaceChangesInDiff); + mapSetting(m_ignoreWSButton, &settings().ignoreSpaceChangesInDiff); } protected: @@ -513,15 +513,15 @@ class GitBlameArgumentsWidget : public VcsBaseEditorConfig Q_OBJECT public: - GitBlameArgumentsWidget(GitSettings &settings, QToolBar *toolBar) : - VcsBaseEditorConfig(toolBar) + explicit GitBlameArgumentsWidget(QToolBar *toolBar) + : VcsBaseEditorConfig(toolBar) { mapSetting(addToggleButton(QString(), Tr::tr("Omit Date"), Tr::tr("Hide the date of a change from the output.")), - &settings.omitAnnotationDate); + &settings().omitAnnotationDate); mapSetting(addToggleButton("-w", Tr::tr("Ignore Whitespace"), Tr::tr("Ignore whitespace only changes.")), - &settings.ignoreSpaceChangesInBlame); + &settings().ignoreSpaceChangesInBlame); const QList logChoices = { ChoiceItem(Tr::tr("No Move Detection"), ""), @@ -530,7 +530,7 @@ public: ChoiceItem(Tr::tr("Detect Moves and Copies Between Files"), "-M -C -C") }; mapSetting(addChoices(Tr::tr("Move detection"), {}, logChoices), - &settings.blameMoveDetection); + &settings().blameMoveDetection); addReloadButton(); } @@ -541,13 +541,13 @@ class BaseGitLogArgumentsWidget : public BaseGitDiffArgumentsWidget Q_OBJECT public: - BaseGitLogArgumentsWidget(GitSettings &settings, GitEditorWidget *editor) : - BaseGitDiffArgumentsWidget(settings, editor->toolBar()) + BaseGitLogArgumentsWidget(GitEditorWidget *editor) + : BaseGitDiffArgumentsWidget(editor->toolBar()) { QToolBar *toolBar = editor->toolBar(); QAction *diffButton = addToggleButton(patchOption, Tr::tr("Diff"), Tr::tr("Show difference.")); - mapSetting(diffButton, &settings.logDiff); + mapSetting(diffButton, &settings().logDiff); connect(diffButton, &QAction::toggled, m_patienceButton, &QAction::setVisible); connect(diffButton, &QAction::toggled, m_ignoreWSButton, &QAction::setVisible); m_patienceButton->setVisible(diffButton->isChecked()); @@ -582,27 +582,27 @@ class GitLogArgumentsWidget : public BaseGitLogArgumentsWidget Q_OBJECT public: - GitLogArgumentsWidget(GitSettings &settings, bool fileRelated, GitEditorWidget *editor) : - BaseGitLogArgumentsWidget(settings, editor) + GitLogArgumentsWidget(bool fileRelated, GitEditorWidget *editor) + : BaseGitLogArgumentsWidget(editor) { QAction *firstParentButton = addToggleButton({"-m", "--first-parent"}, Tr::tr("First Parent"), Tr::tr("Follow only the first parent on merge commits.")); - mapSetting(firstParentButton, &settings.firstParent); + mapSetting(firstParentButton, &settings().firstParent); QAction *graphButton = addToggleButton(graphArguments(), Tr::tr("Graph"), Tr::tr("Show textual graph log.")); - mapSetting(graphButton, &settings.graphLog); + mapSetting(graphButton, &settings().graphLog); QAction *colorButton = addToggleButton(QStringList{colorOption}, Tr::tr("Color"), Tr::tr("Use colors in log.")); - mapSetting(colorButton, &settings.colorLog); + mapSetting(colorButton, &settings().colorLog); if (fileRelated) { QAction *followButton = addToggleButton( "--follow", Tr::tr("Follow"), Tr::tr("Show log also for previous names of the file.")); - mapSetting(followButton, &settings.followRenames); + mapSetting(followButton, &settings().followRenames); } addReloadButton(); @@ -641,14 +641,14 @@ class GitRefLogArgumentsWidget : public BaseGitLogArgumentsWidget Q_OBJECT public: - GitRefLogArgumentsWidget(GitSettings &settings, GitEditorWidget *editor) : - BaseGitLogArgumentsWidget(settings, editor) + explicit GitRefLogArgumentsWidget(GitEditorWidget *editor) + : BaseGitLogArgumentsWidget(editor) { QAction *showDateButton = addToggleButton("--date=iso", Tr::tr("Show Date"), Tr::tr("Show date instead of sequence.")); - mapSetting(showDateButton, &settings.refLogShowDate); + mapSetting(showDateButton, &settings().refLogShowDate); addReloadButton(); } @@ -736,8 +736,8 @@ static inline void msgCannotRun(const QStringList &args, const FilePath &working // ---------------- GitClient -GitClient::GitClient(GitSettings *settings) - : VcsBase::VcsBaseClientImpl(settings) +GitClient::GitClient() + : VcsBase::VcsBaseClientImpl(&Internal::settings()) { m_instance = this; m_gitQtcEditor = QString::fromLatin1("\"%1\" -client -block -pid %2") @@ -752,7 +752,7 @@ GitClient *GitClient::instance() GitSettings &GitClient::settings() { - return static_cast(m_instance->VcsBaseClientImpl::settings()); + return Internal::settings(); } FilePath GitClient::findRepositoryForDirectory(const FilePath &directory) const @@ -1075,7 +1075,7 @@ void GitClient::log(const FilePath &workingDirectory, const QString &fileName, encoding(EncodingLogOutput), "logTitle", msgArg)); VcsBaseEditorConfig *argWidget = editor->editorConfig(); if (!argWidget) { - argWidget = new GitLogArgumentsWidget(settings(), !fileName.isEmpty(), editor); + argWidget = new GitLogArgumentsWidget(!fileName.isEmpty(), editor); argWidget->setBaseArguments(args); connect(argWidget, &VcsBaseEditorConfig::commandExecutionRequested, this, [=] { this->log(workingDir, fileName, enableAnnotationContextMenu, args); }); @@ -1131,7 +1131,7 @@ void GitClient::reflog(const FilePath &workingDirectory, const QString &ref) "reflogRepository", workingDir.toString())); VcsBaseEditorConfig *argWidget = editor->editorConfig(); if (!argWidget) { - argWidget = new GitRefLogArgumentsWidget(settings(), editor); + argWidget = new GitRefLogArgumentsWidget(editor); if (!ref.isEmpty()) argWidget->setBaseArguments({ref}); connect(argWidget, &VcsBaseEditorConfig::commandExecutionRequested, this, @@ -1243,7 +1243,7 @@ void GitClient::annotate(const Utils::FilePath &workingDir, const QString &file, encoding(EncodingSource, sourceFile), "blameFileName", id); VcsBaseEditorConfig *argWidget = editor->editorConfig(); if (!argWidget) { - argWidget = new GitBlameArgumentsWidget(settings(), editor->toolBar()); + argWidget = new GitBlameArgumentsWidget(editor->toolBar()); argWidget->setBaseArguments(extraOptions); connect(argWidget, &VcsBaseEditorConfig::commandExecutionRequested, this, [=] { const int line = VcsBaseEditor::lineNumberOfCurrentEditor(); @@ -2574,7 +2574,7 @@ bool GitClient::launchGitBash(const FilePath &workingDirectory) FilePath GitClient::vcsBinary() const { bool ok; - Utils::FilePath binary = static_cast(settings()).gitExecutable(&ok); + Utils::FilePath binary = settings().gitExecutable(&ok); if (!ok) return Utils::FilePath(); return binary; diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index fb3a06b3556..88c2f3870f8 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -115,9 +115,8 @@ public: PushAction m_pushAction = NoPush; }; - explicit GitClient(GitSettings *settings); + GitClient(); static GitClient *instance(); - static GitSettings &settings(); Utils::FilePath vcsBinary() const override; QFuture gitVersion() const; @@ -350,6 +349,8 @@ public: QTextCodec *encoding(EncodingType encodingType, const Utils::FilePath &source = {}) const; private: + static GitSettings &settings(); + void finishSubmoduleUpdate(); void chunkActionsRequested(DiffEditor::DiffEditorController *controller, QMenu *menu, int fileIndex, int chunkIndex, diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp index 7f73842cb02..c7078dc2ba1 100644 --- a/src/plugins/git/giteditor.cpp +++ b/src/plugins/git/giteditor.cpp @@ -132,7 +132,7 @@ static QString sanitizeBlameOutput(const QString &b) if (b.isEmpty()) return b; - const bool omitDate = GitClient::instance()->settings().omitAnnotationDate.value(); + const bool omitDate = settings().omitAnnotationDate.value(); const QChar space(' '); const int parenPos = b.indexOf(')'); if (parenPos == -1) diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index a9d1cb0c6f2..0401eb835ed 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -420,8 +420,7 @@ public: ParameterAction *m_applyCurrentFilePatchAction = nullptr; Gerrit::Internal::GerritPlugin m_gerritPlugin; - GitSettings m_settings; - GitClient m_gitClient{&m_settings}; + GitClient m_gitClient; QPointer m_stashDialog; BranchViewFactory m_branchViewFactory; QPointer m_remoteDialog; @@ -434,7 +433,7 @@ public: std::unique_ptr m_blameMark; QMetaObject::Connection m_blameCursorPosConn; - GitSettingsPage settingPage{&m_settings}; + GitSettingsPage settingPage; GitGrep gitGrep{&m_gitClient}; @@ -524,7 +523,7 @@ void GitPluginPrivate::onApplySettings() updateRepositoryBrowserAction(); bool gitFoundOk; QString errorMessage; - m_settings.gitExecutable(&gitFoundOk, &errorMessage); + settings().gitExecutable(&gitFoundOk, &errorMessage); if (!gitFoundOk) { QTimer::singleShot(0, this, [errorMessage] { AsynchronousMessageBox::warning(Tr::tr("Git Settings"), errorMessage); @@ -555,11 +554,6 @@ IVersionControl *GitPlugin::versionControl() return dd; } -const GitSettings &GitPlugin::settings() -{ - return dd->m_settings; -} - const VcsBasePluginState &GitPlugin::currentState() { return dd->currentState(); @@ -1069,7 +1063,7 @@ GitPluginPrivate::GitPluginPrivate() m_gerritPlugin.updateActions(currentState()); m_gerritPlugin.addToLocator(m_commandLocator); - connect(&m_settings, &AspectContainer::applied, this, &GitPluginPrivate::onApplySettings); + connect(&settings(), &AspectContainer::applied, this, &GitPluginPrivate::onApplySettings); setupInstantBlame(); } @@ -1439,7 +1433,7 @@ void GitPluginPrivate::setupInstantBlame() return; } - if (!GitClient::instance()->settings().instantBlame.value()) { + if (!settings().instantBlame.value()) { m_lastVisitedEditorLine = -1; stopInstantBlame(); return; @@ -1459,7 +1453,7 @@ void GitPluginPrivate::setupInstantBlame() m_blameCursorPosConn = connect(widget, &QPlainTextEdit::cursorPositionChanged, this, [this] { - if (!GitClient::instance()->settings().instantBlame.value()) { + if (!settings().instantBlame.value()) { disconnect(m_blameCursorPosConn); return; } @@ -1470,8 +1464,8 @@ void GitPluginPrivate::setupInstantBlame() instantBlame(); }; - connect(&GitClient::instance()->settings().instantBlame, - &BoolAspect::valueChanged, this, [this, setupBlameForEditor](bool enabled) { + connect(&settings().instantBlame, &BoolAspect::valueChanged, this, + [this, setupBlameForEditor](bool enabled) { if (enabled) setupBlameForEditor(EditorManager::currentEditor()); else @@ -1520,7 +1514,7 @@ CommitInfo parseBlameOutput(const QStringList &blame, const Utils::FilePath &fil void GitPluginPrivate::instantBlameOnce() { - if (!GitClient::instance()->settings().instantBlame.value()) { + if (!settings().instantBlame.value()) { const TextEditorWidget *widget = TextEditorWidget::currentTextEditorWidget(); if (!widget) return; @@ -1682,7 +1676,7 @@ void GitPluginPrivate::pull() const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); FilePath topLevel = state.topLevel(); - bool rebase = m_settings.pullRebase.value(); + bool rebase = settings().pullRebase.value(); if (!rebase) { QString currentBranch = m_gitClient.synchronousCurrentLocalBranch(topLevel); @@ -1993,7 +1987,7 @@ QObject *GitPlugin::remoteCommand(const QStringList &options, const QString &wor void GitPluginPrivate::updateRepositoryBrowserAction() { const bool repositoryEnabled = currentState().hasTopLevel(); - const bool hasRepositoryBrowserCmd = !m_settings.repositoryBrowserCmd.value().isEmpty(); + const bool hasRepositoryBrowserCmd = !settings().repositoryBrowserCmd.value().isEmpty(); m_repositoryBrowserAction->setEnabled(repositoryEnabled && hasRepositoryBrowserCmd); } @@ -2099,7 +2093,7 @@ GitPluginPrivate::RepoUrl GitPluginPrivate::getRepoUrl(const QString &location) FilePaths GitPluginPrivate::additionalToolsPath() const { - FilePaths res = m_gitClient.settings().searchPathList(); + FilePaths res = settings().searchPathList(); const FilePath binaryPath = m_gitClient.gitBinDirectory(); if (!binaryPath.isEmpty() && !res.contains(binaryPath)) res << binaryPath; diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index 0b0e7518012..59d9a87fdec 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -3,7 +3,6 @@ #pragma once -#include "gitsettings.h" #include "git_global.h" #include @@ -36,7 +35,6 @@ public: static GitClient *client(); static Core::IVersionControl *versionControl(); - static const GitSettings &settings(); static const VcsBase::VcsBasePluginState ¤tState(); static QString msgRepositoryLabel(const Utils::FilePath &repository); @@ -63,7 +61,6 @@ private slots: void testGitRemote_data(); void testGitRemote(); #endif - }; } // Git::Internal diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 25a8f77988e..965a62c728c 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -148,15 +148,15 @@ FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const // GitSettingsPage -GitSettingsPage::GitSettingsPage(GitSettings *settings) +GitSettingsPage::GitSettingsPage() { setId(VcsBase::Constants::VCS_ID_GIT); setDisplayName(Tr::tr("Git")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(settings); + setSettings(&settings()); - setLayouter([settings](QWidget *widget) { - GitSettings &s = *settings; + setLayouter([](QWidget *widget) { + GitSettings &s = settings(); using namespace Layouting; Column { @@ -196,4 +196,10 @@ GitSettingsPage::GitSettingsPage(GitSettings *settings) }); } +GitSettings &settings() +{ + static GitSettings theSettings; + return theSettings; +} + } // Git::Internal diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index c03deadeb9b..d9976de838c 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -46,10 +46,12 @@ public: Utils::FilePath gitExecutable(bool *ok = nullptr, QString *errorMessage = nullptr) const; }; +GitSettings &settings(); + class GitSettingsPage final : public Core::IOptionsPage { public: - explicit GitSettingsPage(GitSettings *settings); + GitSettingsPage(); }; } // Git::Internal diff --git a/src/plugins/git/logchangedialog.cpp b/src/plugins/git/logchangedialog.cpp index 7e61b133de8..75660c11897 100644 --- a/src/plugins/git/logchangedialog.cpp +++ b/src/plugins/git/logchangedialog.cpp @@ -224,7 +224,7 @@ LogChangeDialog::LogChangeDialog(bool isReset, QWidget *parent) : m_resetTypeComboBox->addItem(Tr::tr("Hard"), "--hard"); m_resetTypeComboBox->addItem(Tr::tr("Mixed"), "--mixed"); m_resetTypeComboBox->addItem(Tr::tr("Soft"), "--soft"); - m_resetTypeComboBox->setCurrentIndex(GitClient::settings().lastResetIndex()); + m_resetTypeComboBox->setCurrentIndex(settings().lastResetIndex()); popUpLayout->addWidget(m_resetTypeComboBox); popUpLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); } @@ -250,7 +250,7 @@ bool LogChangeDialog::runDialog(const FilePath &repository, if (QDialog::exec() == QDialog::Accepted) { if (m_resetTypeComboBox) - GitClient::settings().lastResetIndex.setValue(m_resetTypeComboBox->currentIndex()); + settings().lastResetIndex.setValue(m_resetTypeComboBox->currentIndex()); return true; } return false; From f6c995cdd0a84a7b9f3494597dd1383bee520b68 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 14:02:10 +0200 Subject: [PATCH 1053/1447] Bazaar: Follow the Fossil settings setup Change-Id: If711f8a43a6579c72cad1bc98ef24c3fdd83993b Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarclient.cpp | 30 ++++++++++++--------------- src/plugins/bazaar/bazaarclient.h | 4 +--- src/plugins/bazaar/bazaarplugin.cpp | 15 +++++++------- src/plugins/bazaar/bazaarsettings.cpp | 14 +++++++++---- src/plugins/bazaar/bazaarsettings.h | 4 +++- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp index 0b07bcd9ec0..303b7e21c28 100644 --- a/src/plugins/bazaar/bazaarclient.cpp +++ b/src/plugins/bazaar/bazaarclient.cpp @@ -29,13 +29,13 @@ namespace Bazaar::Internal { class BazaarDiffConfig : public VcsBaseEditorConfig { public: - BazaarDiffConfig(BazaarSettings &settings, QToolBar *toolBar) : - VcsBaseEditorConfig(toolBar) + explicit BazaarDiffConfig(QToolBar *toolBar) + : VcsBaseEditorConfig(toolBar) { mapSetting(addToggleButton("-w", Tr::tr("Ignore Whitespace")), - &settings.diffIgnoreWhiteSpace); + &settings().diffIgnoreWhiteSpace); mapSetting(addToggleButton("-B", Tr::tr("Ignore Blank Lines")), - &settings.diffIgnoreBlankLines); + &settings().diffIgnoreBlankLines); } QStringList arguments() const override @@ -54,18 +54,18 @@ public: class BazaarLogConfig : public VcsBaseEditorConfig { public: - BazaarLogConfig(BazaarSettings &settings, QToolBar *toolBar) : - VcsBaseEditorConfig(toolBar) + BazaarLogConfig(QToolBar *toolBar) + : VcsBaseEditorConfig(toolBar) { mapSetting(addToggleButton("--verbose", Tr::tr("Verbose"), Tr::tr("Show files changed in each revision.")), - &settings.logVerbose); + &settings().logVerbose); mapSetting(addToggleButton("--forward", Tr::tr("Forward"), Tr::tr("Show from oldest to newest.")), - &settings.logForward); + &settings().logForward); mapSetting(addToggleButton("--include-merges", Tr::tr("Include Merges"), Tr::tr("Show merged revisions.")), - &settings.logIncludeMerges); + &settings().logIncludeMerges); const QList logChoices = { {Tr::tr("Detailed"), "long"}, @@ -74,18 +74,14 @@ public: {Tr::tr("GNU Change Log"), "gnu-changelog"} }; mapSetting(addChoices(Tr::tr("Format"), { "--log-format=%1" }, logChoices), - &settings.logFormat); + &settings().logFormat); } }; -BazaarClient::BazaarClient(BazaarSettings *settings) : VcsBaseClient(settings) +BazaarClient::BazaarClient() : VcsBaseClient(&Internal::settings()) { - setDiffConfigCreator([settings](QToolBar *toolBar) { - return new BazaarDiffConfig(*settings, toolBar); - }); - setLogConfigCreator([settings](QToolBar *toolBar) { - return new BazaarLogConfig(*settings, toolBar); - }); + setDiffConfigCreator([](QToolBar *toolBar) { return new BazaarDiffConfig(toolBar); }); + setLogConfigCreator([](QToolBar *toolBar) { return new BazaarLogConfig(toolBar); }); } BranchInfo BazaarClient::synchronousBranchQuery(const FilePath &repositoryRoot) const diff --git a/src/plugins/bazaar/bazaarclient.h b/src/plugins/bazaar/bazaarclient.h index b84484b6875..5b6ce1e6d48 100644 --- a/src/plugins/bazaar/bazaarclient.h +++ b/src/plugins/bazaar/bazaarclient.h @@ -9,12 +9,10 @@ namespace Bazaar::Internal { -class BazaarSettings; - class BazaarClient : public VcsBase::VcsBaseClient { public: - explicit BazaarClient(BazaarSettings *settings); + BazaarClient(); BranchInfo synchronousBranchQuery(const Utils::FilePath &repositoryRoot) const; bool synchronousUncommit(const Utils::FilePath &workingDir, diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 097fca18207..0c2d11b9f31 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -215,9 +215,8 @@ public: void createRepositoryActions(const Core::Context &context); // Variables - BazaarSettings m_settings; - BazaarClient m_client{&m_settings}; - BazaarSettingsPage m_settingPage{&m_settings}; + BazaarClient m_client; + BazaarSettingsPage m_settingPage; VcsSubmitEditorFactory m_submitEditorFactory { submitEditorParameters, @@ -372,7 +371,7 @@ BazaarPluginPrivate::BazaarPluginPrivate() toolsMenu->addMenu(m_bazaarContainer); m_menuAction = m_bazaarContainer->menu()->menuAction(); - connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged); + connect(&settings(), &AspectContainer::applied, this, &IVersionControl::configurationChanged); } void BazaarPluginPrivate::createFileActions(const Context &context) @@ -523,7 +522,7 @@ void BazaarPluginPrivate::logRepository() const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); QStringList extraOptions; - extraOptions += "--limit=" + QString::number(m_settings.logCount()); + extraOptions += "--limit=" + QString::number(settings().logCount()); m_client.log(state.topLevel(), QStringList(), extraOptions); } @@ -705,8 +704,8 @@ void BazaarPluginPrivate::showCommitWidget(const QListsetFields(m_submitRepository, branch, - m_settings.userName.value(), - m_settings.userEmail.value(), status); + settings().userName(), + settings().userEmail(), status); } void BazaarPluginPrivate::diffFromEditorSelected(const QStringList &files) @@ -872,7 +871,7 @@ bool BazaarPluginPrivate::managesFile(const FilePath &workingDirectory, const QS bool BazaarPluginPrivate::isConfigured() const { - const FilePath binary = m_settings.binaryPath.filePath(); + const FilePath binary = settings().binaryPath.filePath(); return !binary.isEmpty() && binary.isExecutableFile(); } diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp index d76cb782fe1..394864ea541 100644 --- a/src/plugins/bazaar/bazaarsettings.cpp +++ b/src/plugins/bazaar/bazaarsettings.cpp @@ -70,15 +70,15 @@ BazaarSettings::BazaarSettings() // BazaarSettingsPage -BazaarSettingsPage::BazaarSettingsPage(BazaarSettings *settings) +BazaarSettingsPage::BazaarSettingsPage() { setId(VcsBase::Constants::VCS_ID_BAZAAR); setDisplayName(Tr::tr("Bazaar")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(settings); + setSettings(&settings()); - setLayouter([settings](QWidget *widget) { - BazaarSettings &s = *settings; + setLayouter([](QWidget *widget) { + BazaarSettings &s = settings(); using namespace Layouting; Column { @@ -108,4 +108,10 @@ BazaarSettingsPage::BazaarSettingsPage(BazaarSettings *settings) }); } +BazaarSettings &settings() +{ + static BazaarSettings theSettings; + return theSettings; +} + } // Bazaar::Internal diff --git a/src/plugins/bazaar/bazaarsettings.h b/src/plugins/bazaar/bazaarsettings.h index a10828b42df..971147175ae 100644 --- a/src/plugins/bazaar/bazaarsettings.h +++ b/src/plugins/bazaar/bazaarsettings.h @@ -22,10 +22,12 @@ public: Utils::StringAspect logFormat; }; +BazaarSettings &settings(); + class BazaarSettingsPage final : public Core::IOptionsPage { public: - explicit BazaarSettingsPage(BazaarSettings *settings); + BazaarSettingsPage(); }; } // Bazaar::Internal From d301ddabc7e10463a82d9decd67ad430e6285964 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 13:52:03 +0200 Subject: [PATCH 1054/1447] Subversion: Follow the Fossil settings setup Change-Id: I967396073abbcbc3058a016d5d37fa3fc5645f8a Reviewed-by: Orgad Shaneh --- src/plugins/subversion/subversionclient.cpp | 23 ++++------- src/plugins/subversion/subversionclient.h | 2 +- src/plugins/subversion/subversionplugin.cpp | 41 +++++++++---------- src/plugins/subversion/subversionsettings.cpp | 14 +++++-- src/plugins/subversion/subversionsettings.h | 4 +- 5 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index d728fb79f45..b81656f1452 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -34,27 +34,22 @@ using namespace VcsBase; namespace Subversion { namespace Internal { -static SubversionSettings *s_settings = nullptr; - class SubversionLogConfig : public VcsBaseEditorConfig { Q_OBJECT public: - SubversionLogConfig(SubversionSettings &settings, QToolBar *toolBar) : - VcsBaseEditorConfig(toolBar) + explicit SubversionLogConfig(QToolBar *toolBar) + : VcsBaseEditorConfig(toolBar) { mapSetting(addToggleButton("--verbose", Tr::tr("Verbose"), Tr::tr("Show files changed in each revision")), - &settings.logVerbose); + &settings().logVerbose); } }; -SubversionClient::SubversionClient(SubversionSettings *settings) : VcsBaseClient(settings) +SubversionClient::SubversionClient() : VcsBaseClient(&Internal::settings()) { - s_settings = settings; - setLogConfigCreator([settings](QToolBar *toolBar) { - return new SubversionLogConfig(*settings, toolBar); - }); + setLogConfigCreator([](QToolBar *toolBar) { return new SubversionLogConfig(toolBar); }); } bool SubversionClient::doCommit(const FilePath &repositoryRoot, @@ -101,11 +96,11 @@ Id SubversionClient::vcsEditorKind(VcsCommandTag cmd) const // Add authorization options to the command line arguments. CommandLine &operator<<(Utils::CommandLine &command, SubversionClient::AddAuthOptions) { - if (!s_settings->hasAuthentication()) + if (!settings().hasAuthentication()) return command; - const QString userName = s_settings->userName.value(); - const QString password = s_settings->password.value(); + const QString userName = settings().userName(); + const QString password = settings().password(); if (userName.isEmpty()) return command; @@ -239,7 +234,7 @@ void SubversionDiffEditorController::setChangeNumber(int changeNumber) SubversionDiffEditorController *SubversionClient::findOrCreateDiffEditor(const QString &documentId, const FilePath &source, const QString &title, const FilePath &workingDirectory) { - auto &settings = static_cast(this->settings()); + SubversionSettings &settings = Internal::settings(); IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title); auto controller = qobject_cast( DiffEditorController::controller(document)); diff --git a/src/plugins/subversion/subversionclient.h b/src/plugins/subversion/subversionclient.h index d3beec2b4c9..b2ce0f90616 100644 --- a/src/plugins/subversion/subversionclient.h +++ b/src/plugins/subversion/subversionclient.h @@ -18,7 +18,7 @@ class SubversionClient : public VcsBase::VcsBaseClient Q_OBJECT public: - SubversionClient(SubversionSettings *settings); + SubversionClient(); bool doCommit(const Utils::FilePath &repositoryRoot, const QStringList &files, diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 8d2be99c0c4..cdcfbb96d63 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -261,7 +261,6 @@ private: const QStringList m_svnDirectories; - SubversionSettings m_settings; SubversionClient *m_client = nullptr; QString m_commitMessageFileName; FilePath m_commitRepository; @@ -289,7 +288,7 @@ private: QAction *m_menuAction = nullptr; - SubversionSettingsPage m_settingsPage{&m_settings}; + SubversionSettingsPage m_settingsPage; public: VcsSubmitEditorFactory submitEditorFactory { @@ -358,7 +357,7 @@ SubversionPluginPrivate::SubversionPluginPrivate() { dd = this; - m_client = new SubversionClient(&m_settings); + m_client = new SubversionClient(); setTopicCache(new SubversionTopicCache(this)); @@ -524,7 +523,7 @@ SubversionPluginPrivate::SubversionPluginPrivate() subversionMenu->addAction(command); m_commandLocator->appendCommand(command); - connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged); + connect(&settings(), &AspectContainer::applied, this, &IVersionControl::configurationChanged); } bool SubversionPluginPrivate::isVcsDirectory(const FilePath &fileName) const @@ -640,7 +639,7 @@ void SubversionPluginPrivate::revertAll() QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) return; // NoteL: Svn "revert ." doesn not work. - CommandLine args{m_settings.binaryPath.filePath(), {"revert"}}; + CommandLine args{settings().binaryPath.filePath(), {"revert"}}; args << SubversionClient::AddAuthOptions(); args << QLatin1String("--recursive") << state.topLevel().toString(); const auto revertResponse = runSvn(state.topLevel(), args, RunFlags::ShowStdOut); @@ -657,7 +656,7 @@ void SubversionPluginPrivate::revertCurrentFile() const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasFile(), return); - CommandLine diffArgs{m_settings.binaryPath.filePath(), {"diff"}}; + CommandLine diffArgs{settings().binaryPath.filePath(), {"diff"}}; diffArgs << SubversionClient::AddAuthOptions(); diffArgs << SubversionClient::escapeFile(state.relativeCurrentFile()); @@ -675,7 +674,7 @@ void SubversionPluginPrivate::revertCurrentFile() FileChangeBlocker fcb(state.currentFile()); // revert - CommandLine args{m_settings.binaryPath.filePath(), {"revert"}}; + CommandLine args{settings().binaryPath.filePath(), {"revert"}}; args << SubversionClient::AddAuthOptions(); args << SubversionClient::escapeFile(state.relativeCurrentFile()); @@ -736,7 +735,7 @@ void SubversionPluginPrivate::startCommit(const FilePath &workingDir, const QStr return; } - CommandLine args{m_settings.binaryPath.filePath(), {"status"}}; + CommandLine args{settings().binaryPath.filePath(), {"status"}}; args << SubversionClient::AddAuthOptions(); args << SubversionClient::escapeFiles(files); @@ -815,7 +814,7 @@ void SubversionPluginPrivate::svnStatus(const FilePath &workingDir, const QStrin { const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); - CommandLine args{m_settings.binaryPath.filePath(), {"status"}}; + CommandLine args{settings().binaryPath.filePath(), {"status"}}; args << SubversionClient::AddAuthOptions(); if (!relativePath.isEmpty()) args << SubversionClient::escapeFile(relativePath); @@ -841,7 +840,7 @@ void SubversionPluginPrivate::updateProject() void SubversionPluginPrivate::svnUpdate(const FilePath &workingDir, const QString &relativePath) { - CommandLine args{m_settings.binaryPath.filePath(), {"update"}}; + CommandLine args{settings().binaryPath.filePath(), {"update"}}; args << SubversionClient::AddAuthOptions(); args << Constants::NON_INTERACTIVE_OPTION; if (!relativePath.isEmpty()) @@ -865,9 +864,9 @@ void SubversionPluginPrivate::vcsAnnotateHelper(const FilePath &workingDir, cons const FilePath source = VcsBaseEditor::getSource(workingDir, file); QTextCodec *codec = VcsBaseEditor::getCodec(source); - CommandLine args{m_settings.binaryPath.filePath(), {"annotate"}}; + CommandLine args{settings().binaryPath.filePath(), {"annotate"}}; args << SubversionClient::AddAuthOptions(); - if (m_settings.spaceIgnorantAnnotation.value()) + if (settings().spaceIgnorantAnnotation.value()) args << "-x" << "-uw"; if (!revision.isEmpty()) args << "-r" << revision; @@ -949,10 +948,10 @@ CommandResult SubversionPluginPrivate::runSvn(const FilePath &workingDir, const CommandLine &command, RunFlags flags, QTextCodec *outputCodec, int timeoutMutiplier) const { - if (m_settings.binaryPath().isEmpty()) + if (settings().binaryPath().isEmpty()) return CommandResult(ProcessResult::StartFailed, Tr::tr("No subversion executable specified.")); - const int timeoutS = m_settings.timeout() * timeoutMutiplier; + const int timeoutS = settings().timeout() * timeoutMutiplier; return m_client->vcsSynchronousExec(workingDir, command, flags, timeoutS, outputCodec); } @@ -1008,7 +1007,7 @@ QString SubversionPluginPrivate::synchronousTopic(const FilePath &repository) co bool SubversionPluginPrivate::vcsAdd(const FilePath &workingDir, const QString &rawFileName) { const QString file = QDir::toNativeSeparators(SubversionClient::escapeFile(rawFileName)); - CommandLine args{m_settings.binaryPath.filePath()}; + CommandLine args{settings().binaryPath.filePath()}; args << "add" << SubversionClient::AddAuthOptions() << "--parents" << file; return runSvn(workingDir, args, RunFlags::ShowStdOut).result() == ProcessResult::FinishedWithSuccess; @@ -1018,7 +1017,7 @@ bool SubversionPluginPrivate::vcsDelete(const FilePath &workingDir, const QStrin { const QString file = QDir::toNativeSeparators(SubversionClient::escapeFile(rawFileName)); - CommandLine args{m_settings.binaryPath.filePath()}; + CommandLine args{settings().binaryPath.filePath()}; args << "delete" << SubversionClient::AddAuthOptions() << "--force" << file; return runSvn(workingDir, args, RunFlags::ShowStdOut).result() @@ -1027,7 +1026,7 @@ bool SubversionPluginPrivate::vcsDelete(const FilePath &workingDir, const QStrin bool SubversionPluginPrivate::vcsMove(const FilePath &workingDir, const QString &from, const QString &to) { - CommandLine args{m_settings.binaryPath.filePath(), {"move"}}; + CommandLine args{settings().binaryPath.filePath(), {"move"}}; args << SubversionClient::AddAuthOptions() << QDir::toNativeSeparators(SubversionClient::escapeFile(from)) << QDir::toNativeSeparators(SubversionClient::escapeFile(to)); @@ -1040,7 +1039,7 @@ bool SubversionPluginPrivate::vcsCheckout(const FilePath &directory, const QByte QUrl tempUrl = QUrl::fromEncoded(url); const QString username = tempUrl.userName(); const QString password = tempUrl.password(); - CommandLine args{m_settings.binaryPath.filePath(), {"checkout"}}; + CommandLine args{settings().binaryPath.filePath(), {"checkout"}}; args << Constants::NON_INTERACTIVE_OPTION; if (!username.isEmpty()) { @@ -1087,7 +1086,7 @@ bool SubversionPluginPrivate::managesDirectory(const FilePath &directory, FilePa bool SubversionPluginPrivate::managesFile(const FilePath &workingDirectory, const QString &fileName) const { - CommandLine args{m_settings.binaryPath.filePath()}; + CommandLine args{settings().binaryPath.filePath()}; args << "status" << SubversionClient::AddAuthOptions() << QDir::toNativeSeparators(SubversionClient::escapeFile(fileName)); const QString output = runSvn(workingDirectory, args).cleanedStdOut(); @@ -1126,7 +1125,7 @@ bool SubversionPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) con bool SubversionPluginPrivate::isConfigured() const { - const FilePath binary = m_settings.binaryPath.filePath(); + const FilePath binary = settings().binaryPath.filePath(); if (binary.isEmpty()) return false; QFileInfo fi = binary.toFileInfo(); @@ -1189,7 +1188,7 @@ VcsCommand *SubversionPluginPrivate::createInitialCheckoutCommand(const QString const QString &localName, const QStringList &extraArgs) { - CommandLine args{m_settings.binaryPath.filePath()}; + CommandLine args{settings().binaryPath.filePath()}; args << "checkout"; args << SubversionClient::AddAuthOptions(); args << Subversion::Constants::NON_INTERACTIVE_OPTION << extraArgs << url << localName; diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index d26dceac7cf..1e56e27ccb4 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -78,15 +78,15 @@ bool SubversionSettings::hasAuthentication() const return useAuthentication.value() && !userName.value().isEmpty(); } -SubversionSettingsPage::SubversionSettingsPage(SubversionSettings *settings) +SubversionSettingsPage::SubversionSettingsPage() { setId(VcsBase::Constants::VCS_ID_SUBVERSION); setDisplayName(Tr::tr("Subversion")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(settings); + setSettings(&settings()); - setLayouter([settings](QWidget *widget) { - SubversionSettings &s = *settings; + setLayouter([](QWidget *widget) { + SubversionSettings &s = settings(); using namespace Layouting; Column { @@ -117,4 +117,10 @@ SubversionSettingsPage::SubversionSettingsPage(SubversionSettings *settings) }); } +SubversionSettings &settings() +{ + static SubversionSettings theSettings; + return theSettings; +} + } // Subversion::Internal diff --git a/src/plugins/subversion/subversionsettings.h b/src/plugins/subversion/subversionsettings.h index 206a19d59ff..080dbd6c0ce 100644 --- a/src/plugins/subversion/subversionsettings.h +++ b/src/plugins/subversion/subversionsettings.h @@ -23,10 +23,12 @@ public: Utils::BoolAspect logVerbose; }; +SubversionSettings &settings(); + class SubversionSettingsPage final : public Core::IOptionsPage { public: - explicit SubversionSettingsPage(SubversionSettings *settings); + SubversionSettingsPage(); }; } // Subversion::Internal From 8bdb528f86d2731fff15193bea0bdb6e1b310aaf Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 13:20:41 +0200 Subject: [PATCH 1055/1447] Cvs: Follow the Fossil settings setup Change-Id: I3cd949fa8dad71531c54392de0402783fb314c19 Reviewed-by: Orgad Shaneh --- src/plugins/cvs/cvsplugin.cpp | 41 ++++++++++++++------------------- src/plugins/cvs/cvssettings.cpp | 14 +++++++---- src/plugins/cvs/cvssettings.h | 8 ++++--- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 884afc37273..adfab49ef84 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -137,34 +137,28 @@ static inline bool messageBoxQuestion(const QString &title, const QString &quest class CvsDiffConfig : public VcsBaseEditorConfig { public: - CvsDiffConfig(CvsSettings &settings, QToolBar *toolBar) : - VcsBaseEditorConfig(toolBar), - m_settings(settings) + CvsDiffConfig(QToolBar *toolBar) + : VcsBaseEditorConfig(toolBar) { mapSetting(addToggleButton("-w", Tr::tr("Ignore Whitespace")), - &settings.diffIgnoreWhiteSpace); + &settings().diffIgnoreWhiteSpace); mapSetting(addToggleButton("-B", Tr::tr("Ignore Blank Lines")), - &settings.diffIgnoreBlankLines); + &settings().diffIgnoreBlankLines); } QStringList arguments() const override { - return m_settings.diffOptions.value().split(' ', Qt::SkipEmptyParts) + return settings().diffOptions.value().split(' ', Qt::SkipEmptyParts) + VcsBaseEditorConfig::arguments(); } - -private: - CvsSettings &m_settings; }; class CvsClient : public VcsBaseClient { public: - explicit CvsClient(CvsSettings *settings) : VcsBaseClient(settings) + explicit CvsClient() : VcsBaseClient(&Internal::settings()) { - setDiffConfigCreator([settings](QToolBar *toolBar) { - return new CvsDiffConfig(*settings, toolBar); - }); + setDiffConfigCreator([](QToolBar *toolBar) { return new CvsDiffConfig(toolBar); }); } ExitCodeInterpreter exitCodeInterpreter(VcsCommandTag cmd) const override @@ -294,7 +288,6 @@ private: bool commit(const QString &messageFile, const QStringList &subVersionFileList); void cleanCommitMessageFile(); - CvsSettings m_settings; CvsClient *m_client = nullptr; QString m_commitMessageFileName; @@ -327,7 +320,7 @@ private: QAction *m_menuAction = nullptr; - CvsSettingsPage m_settingsPage{&m_settings}; + CvsSettingsPage m_settingsPage; public: VcsSubmitEditorFactory submitEditorFactory { @@ -374,7 +367,7 @@ bool CvsPluginPrivate::isVcsFileOrDirectory(const Utils::FilePath &filePath) con bool CvsPluginPrivate::isConfigured() const { - const Utils::FilePath binary = m_settings.binaryPath.filePath(); + const FilePath binary = settings().binaryPath.filePath(); if (binary.isEmpty()) return false; QFileInfo fi = binary.toFileInfo(); @@ -447,7 +440,7 @@ VcsCommand *CvsPluginPrivate::createInitialCheckoutCommand(const QString &url, auto command = VcsBaseClient::createVcsCommand(baseDirectory, Environment::systemEnvironment()); command->setDisplayName(Tr::tr("CVS Checkout")); - command->addJob({m_settings.binaryPath.filePath(), m_settings.addOptions(args)}, -1); + command->addJob({settings().binaryPath.filePath(), settings().addOptions(args)}, -1); return command; } @@ -497,7 +490,7 @@ CvsPluginPrivate::CvsPluginPrivate() dd = this; Context context(CVS_CONTEXT); - m_client = new CvsClient(&m_settings); + m_client = new CvsClient; const QString prefix = QLatin1String("cvs"); m_commandLocator = new CommandLocator("CVS", prefix, prefix, this); @@ -692,7 +685,7 @@ CvsPluginPrivate::CvsPluginPrivate() cvsMenu->addAction(command); m_commandLocator->appendCommand(command); - connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged); + connect(&settings(), &AspectContainer::applied, this, &IVersionControl::configurationChanged); } void CvsPluginPrivate::vcsDescribe(const FilePath &source, const QString &changeNr) @@ -1230,7 +1223,7 @@ bool CvsPluginPrivate::describe(const FilePath &toplevel, const QString &file, *errorMessage = Tr::tr("Parsing of the log output failed."); return false; } - if (m_settings.describeByCommitId.value()) { + if (settings().describeByCommitId()) { // Run a log command over the repo, filtering by the commit date // and commit id, collecting all files touched by the commit. const QString commitId = fileLog.front().revisions.front().commitId; @@ -1286,7 +1279,7 @@ bool CvsPluginPrivate::describe(const FilePath &repositoryPath, for (QList::iterator it = entries.begin(); it != lend; ++it) { const QString &revision = it->revisions.front().revision; if (!isFirstRevision(revision)) { - const QStringList args{"diff", m_settings.diffOptions.value(), + const QStringList args{"diff", settings().diffOptions(), "-r", previousRevision(revision), "-r", it->revisions.front().revision, it->file}; const auto diffResponse = runCvs(repositoryPath, args, RunFlags::None, codec); @@ -1329,13 +1322,13 @@ CommandResult CvsPluginPrivate::runCvs(const FilePath &workingDirectory, const QStringList &arguments, RunFlags flags, QTextCodec *outputCodec, int timeoutMultiplier) const { - const FilePath executable = m_settings.binaryPath.filePath(); + const FilePath executable = settings().binaryPath.filePath(); if (executable.isEmpty()) return CommandResult(ProcessResult::StartFailed, Tr::tr("No CVS executable specified.")); - const int timeoutS = m_settings.timeout() * timeoutMultiplier; + const int timeoutS = settings().timeout() * timeoutMultiplier; return m_client->vcsSynchronousExec(workingDirectory, - {executable, m_settings.addOptions(arguments)}, + {executable, settings().addOptions(arguments)}, flags, timeoutS, outputCodec); } diff --git a/src/plugins/cvs/cvssettings.cpp b/src/plugins/cvs/cvssettings.cpp index 1df80463692..693fb36016a 100644 --- a/src/plugins/cvs/cvssettings.cpp +++ b/src/plugins/cvs/cvssettings.cpp @@ -70,15 +70,15 @@ QStringList CvsSettings::addOptions(const QStringList &args) const return rc; } -CvsSettingsPage::CvsSettingsPage(CvsSettings *settings) +CvsSettingsPage::CvsSettingsPage() { setId(VcsBase::Constants::VCS_ID_CVS); setDisplayName(Tr::tr("CVS")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(settings); + setSettings(&settings()); - setLayouter([settings](QWidget *widget) { - CvsSettings &s = *settings; + setLayouter([](QWidget *widget) { + CvsSettings &s = settings(); using namespace Layouting; Column { @@ -104,4 +104,10 @@ CvsSettingsPage::CvsSettingsPage(CvsSettings *settings) }); } +CvsSettings &settings() +{ + static CvsSettings theSettings; + return theSettings; +} + } // Cvs::Internal diff --git a/src/plugins/cvs/cvssettings.h b/src/plugins/cvs/cvssettings.h index ac52ce9402f..b500ee8b838 100644 --- a/src/plugins/cvs/cvssettings.h +++ b/src/plugins/cvs/cvssettings.h @@ -12,21 +12,23 @@ namespace Cvs::Internal { class CvsSettings : public VcsBase::VcsBaseSettings { public: + CvsSettings(); + Utils::StringAspect cvsRoot; Utils::StringAspect diffOptions; Utils::BoolAspect diffIgnoreWhiteSpace; Utils::BoolAspect diffIgnoreBlankLines; Utils::BoolAspect describeByCommitId; - CvsSettings(); - QStringList addOptions(const QStringList &args) const; }; +CvsSettings &settings(); + class CvsSettingsPage final : public Core::IOptionsPage { public: - explicit CvsSettingsPage(CvsSettings *settings); + CvsSettingsPage(); }; } // Cvs::Internal From 1697ff874874def127daa83610f6d5ba190702d2 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 14:05:39 +0200 Subject: [PATCH 1056/1447] Mercurial: Follow the Fossil settings setup Change-Id: I3261669991d55c6da5c80c116c2a66c8b7b0d577 Reviewed-by: Orgad Shaneh --- src/plugins/mercurial/mercurialclient.cpp | 3 ++- src/plugins/mercurial/mercurialclient.h | 3 ++- src/plugins/mercurial/mercurialplugin.cpp | 15 +++++++-------- src/plugins/mercurial/mercurialsettings.cpp | 14 ++++++++++---- src/plugins/mercurial/mercurialsettings.h | 4 +++- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 1d8d542ed91..20e4d3745dd 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -81,7 +81,8 @@ QStringList MercurialDiffEditorController::addConfigurationArguments(const QStri ///////////////////////////////////////////////////////////// -MercurialClient::MercurialClient(MercurialSettings *settings) : VcsBaseClient(settings) +MercurialClient::MercurialClient() + : VcsBaseClient(&Internal::settings()) { } diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h index 15c31845db5..27badd45d00 100644 --- a/src/plugins/mercurial/mercurialclient.h +++ b/src/plugins/mercurial/mercurialclient.h @@ -16,8 +16,9 @@ class MercurialDiffEditorController; class MercurialClient : public VcsBase::VcsBaseClient { Q_OBJECT + public: - explicit MercurialClient(MercurialSettings *settings); + MercurialClient(); bool synchronousClone(const Utils::FilePath &workingDir, const QString &srcLocation, diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index e84c26a6caa..374484a6a3b 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -169,9 +169,8 @@ private: void createRepositoryActions(const Core::Context &context); // Variables - MercurialSettings m_settings; - MercurialClient m_client{&m_settings}; - MercurialSettingsPage m_settingsPage{&m_settings}; + MercurialClient m_client; + MercurialSettingsPage m_settingsPage; Core::CommandLocator *m_commandLocator = nullptr; Core::ActionContainer *m_mercurialContainer = nullptr; @@ -254,7 +253,7 @@ MercurialPluginPrivate::MercurialPluginPrivate() createMenu(context); - connect(&m_settings, &AspectContainer::applied, this, &IVersionControl::configurationChanged); + connect(&settings(), &AspectContainer::applied, this, &IVersionControl::configurationChanged); } void MercurialPluginPrivate::createMenu(const Core::Context &context) @@ -633,8 +632,8 @@ void MercurialPluginPrivate::showCommitWidget(const QListsetFields(m_submitRepository, branch, - m_settings.userName.value(), - m_settings.userEmail.value(), status); + settings().userName(), + settings().userEmail(), status); } void MercurialPluginPrivate::diffFromEditorSelected(const QStringList &files) @@ -716,7 +715,7 @@ bool MercurialPluginPrivate::managesFile(const FilePath &workingDirectory, const bool MercurialPluginPrivate::isConfigured() const { - const FilePath binary = m_settings.binaryPath.filePath(); + const FilePath binary = settings().binaryPath.filePath(); if (binary.isEmpty()) return false; QFileInfo fi = binary.toFileInfo(); @@ -784,7 +783,7 @@ VcsCommand *MercurialPluginPrivate::createInitialCheckoutCommand(const QString & QStringList args; args << QLatin1String("clone") << extraArgs << url << localName; auto command = VcsBaseClient::createVcsCommand(baseDirectory, m_client.processEnvironment()); - command->addJob({m_settings.binaryPath.filePath(), args}, -1); + command->addJob({settings().binaryPath.filePath(), args}, -1); return command; } diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp index 7286c54b90d..f19ea172833 100644 --- a/src/plugins/mercurial/mercurialsettings.cpp +++ b/src/plugins/mercurial/mercurialsettings.cpp @@ -46,15 +46,15 @@ MercurialSettings::MercurialSettings() // MercurialSettingsPage -MercurialSettingsPage::MercurialSettingsPage(MercurialSettings *settings) +MercurialSettingsPage::MercurialSettingsPage() { setId(VcsBase::Constants::VCS_ID_MERCURIAL); setDisplayName(Tr::tr("Mercurial")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(settings); + setSettings(&settings()); - setLayouter([settings](QWidget *widget) { - MercurialSettings &s = *settings; + setLayouter([](QWidget *widget) { + MercurialSettings &s = settings(); using namespace Layouting; Column { @@ -85,4 +85,10 @@ MercurialSettingsPage::MercurialSettingsPage(MercurialSettings *settings) }); } +MercurialSettings &settings() +{ + static MercurialSettings theSettings; + return theSettings; +} + } // Mercurial::Internal diff --git a/src/plugins/mercurial/mercurialsettings.h b/src/plugins/mercurial/mercurialsettings.h index 881bcd04476..34c6693c93e 100644 --- a/src/plugins/mercurial/mercurialsettings.h +++ b/src/plugins/mercurial/mercurialsettings.h @@ -18,10 +18,12 @@ public: Utils::StringAspect diffIgnoreBlankLines; }; +MercurialSettings &settings(); + class MercurialSettingsPage final : public Core::IOptionsPage { public: - explicit MercurialSettingsPage(MercurialSettings *settings); + MercurialSettingsPage(); }; } // Mercurial::Internal From ce7ee677d84850c087e0cef8f9d65470efac8f9e Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 14:52:40 +0200 Subject: [PATCH 1057/1447] Vcs: Use PagedSettings for all plugin settings Hopefully the last structural change for a while. Settings lifetime is again tied to the plugin private. Change-Id: I221e8b8baa69422306191b48a9f034ef5b1a0dc2 Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarplugin.cpp | 2 +- src/plugins/bazaar/bazaarsettings.cpp | 44 +++---- src/plugins/bazaar/bazaarsettings.h | 8 -- src/plugins/cvs/cvsplugin.cpp | 3 +- src/plugins/cvs/cvssettings.cpp | 76 ++++++------- src/plugins/cvs/cvssettings.h | 8 -- src/plugins/fossil/fossilplugin.cpp | 3 +- src/plugins/fossil/fossilsettings.cpp | 68 ++++------- src/plugins/fossil/fossilsettings.h | 7 -- src/plugins/git/gitplugin.cpp | 3 +- src/plugins/git/gitsettings.cpp | 107 +++++++++--------- src/plugins/git/gitsettings.h | 7 -- src/plugins/mercurial/mercurialplugin.cpp | 2 +- src/plugins/mercurial/mercurialsettings.cpp | 45 ++++---- src/plugins/mercurial/mercurialsettings.h | 8 -- src/plugins/subversion/subversionplugin.cpp | 3 +- src/plugins/subversion/subversionsettings.cpp | 53 ++++----- src/plugins/subversion/subversionsettings.h | 8 -- src/plugins/vcsbase/vcsbaseclientsettings.h | 4 +- 19 files changed, 176 insertions(+), 283 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 0c2d11b9f31..110e990447d 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -215,8 +215,8 @@ public: void createRepositoryActions(const Core::Context &context); // Variables + BazaarSettings m_setting; BazaarClient m_client; - BazaarSettingsPage m_settingPage; VcsSubmitEditorFactory m_submitEditorFactory { submitEditorParameters, diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp index 394864ea541..231562edc1b 100644 --- a/src/plugins/bazaar/bazaarsettings.cpp +++ b/src/plugins/bazaar/bazaarsettings.cpp @@ -16,10 +16,21 @@ using namespace Utils; namespace Bazaar::Internal { +static BazaarSettings *theSettings; + +BazaarSettings &settings() +{ + return *theSettings; +} + BazaarSettings::BazaarSettings() { + theSettings = this; + setSettingsGroup(Constants::BAZAAR); - setAutoApply(false); + setId(VcsBase::Constants::VCS_ID_BAZAAR); + setDisplayName(Tr::tr("Bazaar")); + setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); registerAspect(&binaryPath); binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); @@ -66,52 +77,31 @@ BazaarSettings::BazaarSettings() registerAspect(&logCount); timeout.setLabelText(Tr::tr("Timeout:")); timeout.setSuffix(Tr::tr("s")); -} -// BazaarSettingsPage - -BazaarSettingsPage::BazaarSettingsPage() -{ - setId(VcsBase::Constants::VCS_ID_BAZAAR); - setDisplayName(Tr::tr("Bazaar")); - setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(&settings()); - - setLayouter([](QWidget *widget) { - BazaarSettings &s = settings(); + setLayouter([this](QWidget *widget) { using namespace Layouting; Column { Group { title(Tr::tr("Configuration")), - Row { s.binaryPath } + Row { binaryPath } }, Group { title(Tr::tr("User")), Form { - s.userName, br, - s.userEmail + userName, br, + userEmail } }, Group { title(Tr::tr("Miscellaneous")), - Row { - s.logCount, - s.timeout, - st - } + Row { logCount, timeout, st } }, st }.attachTo(widget); }); } -BazaarSettings &settings() -{ - static BazaarSettings theSettings; - return theSettings; -} - } // Bazaar::Internal diff --git a/src/plugins/bazaar/bazaarsettings.h b/src/plugins/bazaar/bazaarsettings.h index 971147175ae..24643a2d4cd 100644 --- a/src/plugins/bazaar/bazaarsettings.h +++ b/src/plugins/bazaar/bazaarsettings.h @@ -3,8 +3,6 @@ #pragma once -#include - #include namespace Bazaar::Internal { @@ -24,10 +22,4 @@ public: BazaarSettings &settings(); -class BazaarSettingsPage final : public Core::IOptionsPage -{ -public: - BazaarSettingsPage(); -}; - } // Bazaar::Internal diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index adfab49ef84..076f2ad8b28 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -288,6 +288,7 @@ private: bool commit(const QString &messageFile, const QStringList &subVersionFileList); void cleanCommitMessageFile(); + CvsSettings m_setting; CvsClient *m_client = nullptr; QString m_commitMessageFileName; @@ -320,8 +321,6 @@ private: QAction *m_menuAction = nullptr; - CvsSettingsPage m_settingsPage; - public: VcsSubmitEditorFactory submitEditorFactory { submitParameters, diff --git a/src/plugins/cvs/cvssettings.cpp b/src/plugins/cvs/cvssettings.cpp index 693fb36016a..f18feeed661 100644 --- a/src/plugins/cvs/cvssettings.cpp +++ b/src/plugins/cvs/cvssettings.cpp @@ -17,12 +17,22 @@ using namespace Utils; namespace Cvs::Internal { -// CvsSettings +static CvsSettings *theSettings; + +CvsSettings &settings() +{ + return *theSettings; +} CvsSettings::CvsSettings() { + theSettings = this; setSettingsGroup("CVS"); + setId(VcsBase::Constants::VCS_ID_CVS); + setDisplayName(Tr::tr("CVS")); + setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); + registerAspect(&binaryPath); binaryPath.setDefaultValue("cvs" QTC_HOST_EXE_SUFFIX); binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); @@ -55,6 +65,30 @@ CvsSettings::CvsSettings() registerAspect(&diffIgnoreBlankLines); diffIgnoreBlankLines.setSettingsKey("DiffIgnoreBlankLines"); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + Column { + Group { + title(Tr::tr("Configuration")), + Form { + binaryPath, br, + cvsRoot + } + }, + Group { + title(Tr::tr("Miscellaneous")), + Column { + Form { + timeout, br, + diffOptions, + }, + describeByCommitId, + } + }, + st + }.attachTo(widget); + }); } QStringList CvsSettings::addOptions(const QStringList &args) const @@ -70,44 +104,4 @@ QStringList CvsSettings::addOptions(const QStringList &args) const return rc; } -CvsSettingsPage::CvsSettingsPage() -{ - setId(VcsBase::Constants::VCS_ID_CVS); - setDisplayName(Tr::tr("CVS")); - setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(&settings()); - - setLayouter([](QWidget *widget) { - CvsSettings &s = settings(); - using namespace Layouting; - - Column { - Group { - title(Tr::tr("Configuration")), - Form { - s.binaryPath, br, - s.cvsRoot - } - }, - Group { - title(Tr::tr("Miscellaneous")), - Column { - Form { - s.timeout, br, - s.diffOptions, - }, - s.describeByCommitId, - } - }, - st - }.attachTo(widget); - }); -} - -CvsSettings &settings() -{ - static CvsSettings theSettings; - return theSettings; -} - } // Cvs::Internal diff --git a/src/plugins/cvs/cvssettings.h b/src/plugins/cvs/cvssettings.h index b500ee8b838..0c2e5442a62 100644 --- a/src/plugins/cvs/cvssettings.h +++ b/src/plugins/cvs/cvssettings.h @@ -3,8 +3,6 @@ #pragma once -#include - #include namespace Cvs::Internal { @@ -25,10 +23,4 @@ public: CvsSettings &settings(); -class CvsSettingsPage final : public Core::IOptionsPage -{ -public: - CvsSettingsPage(); -}; - } // Cvs::Internal diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 71833aabc1f..4979b1d1203 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -187,10 +187,9 @@ public: bool pullOrPush(SyncMode mode); // Variables + FossilSettings m_settings; FossilClient m_client; - OptionsPage optionPage; - VcsSubmitEditorFactory submitEditorFactory { submitEditorParameters, [] { return new CommitEditor; }, diff --git a/src/plugins/fossil/fossilsettings.cpp b/src/plugins/fossil/fossilsettings.cpp index 4ee13bd698a..ca248021143 100644 --- a/src/plugins/fossil/fossilsettings.cpp +++ b/src/plugins/fossil/fossilsettings.cpp @@ -17,10 +17,21 @@ using namespace Utils; namespace Fossil::Internal { +static FossilSettings *theSettings; + +FossilSettings &settings() +{ + return *theSettings; +} + FossilSettings::FossilSettings() { + theSettings = this; + setSettingsGroup(Constants::FOSSIL); - setAutoApply(false); + setId(Constants::VCS_ID_FOSSIL); + setDisplayName(Tr::tr("Fossil")); + setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); registerAspect(&binaryPath); binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); @@ -94,69 +105,38 @@ FossilSettings::FossilSettings() logCount.setLabelText(Tr::tr("Log count:")); logCount.setToolTip(Tr::tr("The number of recent commit log entries to show. " "Choose 0 to see all entries.")); -} - -// OptionsPage - -class OptionsPageWidget final : public Core::IOptionsPageWidget -{ -public: - OptionsPageWidget() - { - FossilSettings &s = settings(); + setLayouter([this](QWidget *widget) { using namespace Layouting; - Column { Group { title(Tr::tr("Configuration")), - Row { s.binaryPath } + Row { binaryPath } }, Group { title(Tr::tr("Local Repositories")), - Row { s.defaultRepoPath } + Row { defaultRepoPath } }, + Group { title(Tr::tr("User")), - Form { - s.userName, br, - s.sslIdentityFile + Form { + userName, br, + sslIdentityFile } }, Group { title(Tr::tr("Miscellaneous")), - Column { - Row { - s.logCount, - s.timelineWidth, - s.timeout, - st - }, - s.disableAutosync + Column { + Row { logCount, timelineWidth, timeout, st }, + disableAutosync }, }, st - - }.attachTo(this); - - setOnApply([] { settings().apply(); }); - } -}; - -OptionsPage::OptionsPage() -{ - setId(Constants::VCS_ID_FOSSIL); - setDisplayName(Tr::tr("Fossil")); - setWidgetCreator([] { return new OptionsPageWidget; }); - setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); -} - -FossilSettings &settings() -{ - static FossilSettings theSettings; - return theSettings; + }.attachTo(widget); + }); } } // Fossil::Internal diff --git a/src/plugins/fossil/fossilsettings.h b/src/plugins/fossil/fossilsettings.h index e373a30cee7..eeea6041bdc 100644 --- a/src/plugins/fossil/fossilsettings.h +++ b/src/plugins/fossil/fossilsettings.h @@ -3,7 +3,6 @@ #pragma once -#include #include namespace Fossil::Internal { @@ -44,10 +43,4 @@ struct RepositorySettings } }; -class OptionsPage : public Core::IOptionsPage -{ -public: - OptionsPage(); -}; - } // Fossil::Internal diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 0401eb835ed..7443f0baa39 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -397,6 +397,7 @@ public: void onApplySettings(); + GitSettings setting; CommandLocator *m_commandLocator = nullptr; QAction *m_menuAction = nullptr; @@ -433,8 +434,6 @@ public: std::unique_ptr m_blameMark; QMetaObject::Connection m_blameCursorPosConn; - GitSettingsPage settingPage; - GitGrep gitGrep{&m_gitClient}; VcsEditorFactory svnLogEditorFactory { diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 965a62c728c..f092dd74e92 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -17,8 +17,21 @@ using namespace VcsBase; namespace Git::Internal { +static GitSettings *theSettings; + +GitSettings &settings() +{ + return *theSettings; +} + GitSettings::GitSettings() { + theSettings = this; + + setId(VcsBase::Constants::VCS_ID_GIT); + setDisplayName(Tr::tr("Git")); + setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); + setSettingsGroup("Git"); path.setDisplayStyle(StringAspect::LineEditDisplay); @@ -117,6 +130,44 @@ GitSettings::GitSettings() timeout.setDefaultValue(Utils::HostOsInfo::isWindowsHost() ? 60 : 30); + setLayouter([this](QWidget *widget) { + using namespace Layouting; + + Column { + Group { + title(Tr::tr("Configuration")), + Column { + Row { path }, + winSetHomeEnvironment, + } + }, + + Group { + title(Tr::tr("Miscellaneous")), + Column { + Row { logCount, timeout, st }, + pullRebase + } + }, + + Group { + title(Tr::tr("Gitk")), + Row { gitkOptions } + }, + + Group { + title(Tr::tr("Repository Browser")), + Row { repositoryBrowserCmd } + }, + + Group { + title(Tr::tr("Instant Blame")), + Row { instantBlame } + }, + + st + }.attachTo(widget); + }); connect(&binaryPath, &StringAspect::valueChanged, this, [this] { tryResolve = true; }); connect(&path, &StringAspect::valueChanged, this, [this] { tryResolve = true; }); } @@ -146,60 +197,4 @@ FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const return resolvedBinPath; } -// GitSettingsPage - -GitSettingsPage::GitSettingsPage() -{ - setId(VcsBase::Constants::VCS_ID_GIT); - setDisplayName(Tr::tr("Git")); - setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(&settings()); - - setLayouter([](QWidget *widget) { - GitSettings &s = settings(); - using namespace Layouting; - - Column { - Group { - title(Tr::tr("Configuration")), - Column { - Row { s.path }, - s.winSetHomeEnvironment, - } - }, - - Group { - title(Tr::tr("Miscellaneous")), - Column { - Row { s.logCount, s.timeout, st }, - s.pullRebase - } - }, - - Group { - title(Tr::tr("Gitk")), - Row { s.gitkOptions } - }, - - Group { - title(Tr::tr("Repository Browser")), - Row { s.repositoryBrowserCmd } - }, - - Group { - title(Tr::tr("Instant Blame")), - Row { s.instantBlame } - }, - - st - }.attachTo(widget); - }); -} - -GitSettings &settings() -{ - static GitSettings theSettings; - return theSettings; -} - } // Git::Internal diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index d9976de838c..3899fdada58 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -3,7 +3,6 @@ #pragma once -#include #include namespace Git::Internal { @@ -48,10 +47,4 @@ public: GitSettings &settings(); -class GitSettingsPage final : public Core::IOptionsPage -{ -public: - GitSettingsPage(); -}; - } // Git::Internal diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 374484a6a3b..a6bd955c3a7 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -169,8 +169,8 @@ private: void createRepositoryActions(const Core::Context &context); // Variables + MercurialSettings m_settings; MercurialClient m_client; - MercurialSettingsPage m_settingsPage; Core::CommandLocator *m_commandLocator = nullptr; Core::ActionContainer *m_mercurialContainer = nullptr; diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp index f19ea172833..dd63faddc05 100644 --- a/src/plugins/mercurial/mercurialsettings.cpp +++ b/src/plugins/mercurial/mercurialsettings.cpp @@ -14,8 +14,22 @@ using namespace Utils; namespace Mercurial::Internal { +static MercurialSettings *theSettings; + +MercurialSettings &settings() +{ + return *theSettings; +} + MercurialSettings::MercurialSettings() { + theSettings = this; + + setId(VcsBase::Constants::VCS_ID_MERCURIAL); + setDisplayName(Tr::tr("Mercurial")); + setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); + setSettings(&settings()); + setSettingsGroup("Mercurial"); setAutoApply(false); @@ -42,42 +56,27 @@ MercurialSettings::MercurialSettings() registerAspect(&diffIgnoreBlankLines); diffIgnoreBlankLines.setSettingsKey("diffIgnoreBlankLines"); -} -// MercurialSettingsPage - -MercurialSettingsPage::MercurialSettingsPage() -{ - setId(VcsBase::Constants::VCS_ID_MERCURIAL); - setDisplayName(Tr::tr("Mercurial")); - setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(&settings()); - - setLayouter([](QWidget *widget) { - MercurialSettings &s = settings(); + setLayouter([this](QWidget *widget) { using namespace Layouting; Column { Group { title(Tr::tr("Configuration")), - Row { s.binaryPath } + Row { binaryPath } }, Group { title(Tr::tr("User")), Form { - s.userName, br, - s.userEmail + userName, br, + userEmail } }, Group { title(Tr::tr("Miscellaneous")), - Row { - s.logCount, - s.timeout, - st - } + Row { logCount, timeout, st } }, st @@ -85,10 +84,4 @@ MercurialSettingsPage::MercurialSettingsPage() }); } -MercurialSettings &settings() -{ - static MercurialSettings theSettings; - return theSettings; -} - } // Mercurial::Internal diff --git a/src/plugins/mercurial/mercurialsettings.h b/src/plugins/mercurial/mercurialsettings.h index 34c6693c93e..08c8fa41544 100644 --- a/src/plugins/mercurial/mercurialsettings.h +++ b/src/plugins/mercurial/mercurialsettings.h @@ -3,8 +3,6 @@ #pragma once -#include - #include namespace Mercurial::Internal { @@ -20,10 +18,4 @@ public: MercurialSettings &settings(); -class MercurialSettingsPage final : public Core::IOptionsPage -{ -public: - MercurialSettingsPage(); -}; - } // Mercurial::Internal diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index cdcfbb96d63..957947a89a6 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -261,6 +261,7 @@ private: const QStringList m_svnDirectories; + SubversionSettings m_settings; SubversionClient *m_client = nullptr; QString m_commitMessageFileName; FilePath m_commitRepository; @@ -288,8 +289,6 @@ private: QAction *m_menuAction = nullptr; - SubversionSettingsPage m_settingsPage; - public: VcsSubmitEditorFactory submitEditorFactory { submitParameters, diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index 1e56e27ccb4..98945ab82ef 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -5,25 +5,31 @@ #include "subversiontr.h" -#include #include #include #include #include -#include - using namespace Utils; using namespace VcsBase; namespace Subversion::Internal { -// SubversionSettings +static SubversionSettings *theSettings; + +SubversionSettings &settings() +{ + return *theSettings; +} SubversionSettings::SubversionSettings() { - setAutoApply(false); + theSettings = this; + + setId(VcsBase::Constants::VCS_ID_SUBVERSION); + setDisplayName(Tr::tr("Subversion")); + setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); setSettingsGroup("Subversion"); registerAspect(&binaryPath); @@ -68,47 +74,33 @@ SubversionSettings::SubversionSettings() timeout.setSuffix(Tr::tr("s")); QObject::connect(&useAuthentication, &BaseAspect::changed, this, [this] { - userName.setEnabled(useAuthentication.value()); - password.setEnabled(useAuthentication.value()); + userName.setEnabled(useAuthentication()); + password.setEnabled(useAuthentication()); }); -} -bool SubversionSettings::hasAuthentication() const -{ - return useAuthentication.value() && !userName.value().isEmpty(); -} - -SubversionSettingsPage::SubversionSettingsPage() -{ - setId(VcsBase::Constants::VCS_ID_SUBVERSION); - setDisplayName(Tr::tr("Subversion")); - setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(&settings()); - - setLayouter([](QWidget *widget) { - SubversionSettings &s = settings(); + setLayouter([this](QWidget *widget) { using namespace Layouting; Column { Group { title(Tr::tr("Configuration")), - Column { s.binaryPath } + Column { binaryPath } }, Group { title(Tr::tr("Authentication")), - s.useAuthentication.groupChecker(), + useAuthentication.groupChecker(), Form { - s.userName, br, - s.password, + userName, br, + password, } }, Group { title(Tr::tr("Miscellaneous")), Column { - Row { s.logCount, s.timeout, st }, - s.spaceIgnorantAnnotation, + Row { logCount, timeout, st }, + spaceIgnorantAnnotation, } }, @@ -117,10 +109,9 @@ SubversionSettingsPage::SubversionSettingsPage() }); } -SubversionSettings &settings() +bool SubversionSettings::hasAuthentication() const { - static SubversionSettings theSettings; - return theSettings; + return useAuthentication() && !userName().isEmpty(); } } // Subversion::Internal diff --git a/src/plugins/subversion/subversionsettings.h b/src/plugins/subversion/subversionsettings.h index 080dbd6c0ce..49aaec171b1 100644 --- a/src/plugins/subversion/subversionsettings.h +++ b/src/plugins/subversion/subversionsettings.h @@ -3,8 +3,6 @@ #pragma once -#include - #include namespace Subversion::Internal { @@ -25,10 +23,4 @@ public: SubversionSettings &settings(); -class SubversionSettingsPage final : public Core::IOptionsPage -{ -public: - SubversionSettingsPage(); -}; - } // Subversion::Internal diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.h b/src/plugins/vcsbase/vcsbaseclientsettings.h index 102405c4bfc..9a034e5f924 100644 --- a/src/plugins/vcsbase/vcsbaseclientsettings.h +++ b/src/plugins/vcsbase/vcsbaseclientsettings.h @@ -5,11 +5,11 @@ #include "vcsbase_global.h" -#include +#include namespace VcsBase { -class VCSBASE_EXPORT VcsBaseSettings : public Utils::AspectContainer +class VCSBASE_EXPORT VcsBaseSettings : public Core::PagedSettings { public: VcsBaseSettings(); From a820b5490c4eb09b4b957e96d56b13ebf479f0e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Wed, 10 May 2023 17:28:35 +0200 Subject: [PATCH 1058/1447] SquishTests: Fix using invalid paste IDs Change-Id: Ibc48506ff1632cbfe8d662cd00ed057af7d16a6a Reviewed-by: Christian Stenger --- tests/system/suite_tools/tst_codepasting/test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/suite_tools/tst_codepasting/test.py b/tests/system/suite_tools/tst_codepasting/test.py index 3d4507095f0..148052a8042 100644 --- a/tests/system/suite_tools/tst_codepasting/test.py +++ b/tests/system/suite_tools/tst_codepasting/test.py @@ -107,7 +107,7 @@ def fetchSnippet(protocol, description, pasteId, skippedPasting): pasteModel = waitForObject(":PasteSelectDialog.listWidget_QListWidget").model() except: closeHTTPStatusAndPasterDialog(protocol, ':PasteSelectDialog_CodePaster::PasteSelectDialog') - return -1 + return invalidPasteId(protocol) condition = "pasteModel.rowCount() > 1" if protocol == NAME_DPCOM: # no list support @@ -125,7 +125,7 @@ def fetchSnippet(protocol, description, pasteId, skippedPasting): "window=':PasteSelectDialog_CodePaster::PasteSelectDialog'}") waitFor("pasteModel.rowCount() == 1", 1000) waitFor("pasteModel.rowCount() > 1", 20000) - if pasteId == -1: + if pasteId == invalidPasteId(protocol): try: pasteLine = filter(lambda str:description in str, dumpItems(pasteModel))[0] pasteId = pasteLine.split(" ", 1)[0] @@ -207,7 +207,7 @@ def main(): test.fatal(message) continue pasteId = fetchSnippet(protocol, description, pasteId, skippedPasting) - if pasteId == -1: + if pasteId == invalidPasteId(protocol): continue filenameCombo = waitForObject(":Qt Creator_FilenameQComboBox") waitFor("not filenameCombo.currentText.isEmpty()", 20000) From 0b241f42f186e13b70550c070d3d271c1eb9e989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Mon, 8 May 2023 18:12:33 +0200 Subject: [PATCH 1059/1447] SquishTests: Make suite_tools Python3 compatible Except for tst_designer_edit which needs a bigger update. Change-Id: I8300a9491ec34b4d8deeed39f02fc59281cc20c9 Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/suite_tools/tst_codepasting/test.py | 14 ++++++++------ tests/system/suite_tools/tst_git_local/test.py | 5 +++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/system/suite_tools/tst_codepasting/test.py b/tests/system/suite_tools/tst_codepasting/test.py index 148052a8042..ec0d9ee226e 100644 --- a/tests/system/suite_tools/tst_codepasting/test.py +++ b/tests/system/suite_tools/tst_codepasting/test.py @@ -72,7 +72,7 @@ def pasteFile(sourceFile, protocol): try: outputWindow = waitForObject(":Qt Creator_Core::OutputWindow") waitFor("re.search('^https://', str(outputWindow.plainText)) is not None", 20000) - output = filter(lambda x: len(x), str(outputWindow.plainText).splitlines())[-1] + output = list(filter(lambda x: len(x), str(outputWindow.plainText).splitlines()))[-1] except: output = "" if closeHTTPStatusAndPasterDialog(protocol, ':Send to Codepaster_CodePaster::PasteView'): @@ -126,10 +126,11 @@ def fetchSnippet(protocol, description, pasteId, skippedPasting): waitFor("pasteModel.rowCount() == 1", 1000) waitFor("pasteModel.rowCount() > 1", 20000) if pasteId == invalidPasteId(protocol): - try: - pasteLine = filter(lambda str:description in str, dumpItems(pasteModel))[0] - pasteId = pasteLine.split(" ", 1)[0] - except: + for currentItem in dumpItems(pasteModel): + if description in currentItem: + pasteId = currentItem.split(" ", 1)[0] + break + if pasteId == invalidPasteId(protocol): test.fail("Could not find description line in list of pastes from %s" % protocol) clickButton(waitForObject(":PasteSelectDialog.Cancel_QPushButton")) return pasteId @@ -242,7 +243,8 @@ def main(): # QString QTextCursor::selectedText () const: # "Note: If the selection obtained from an editor spans a line break, the text will contain a # Unicode U+2029 paragraph separator character instead of a newline \n character." - selectedText = str(editor.textCursor().selectedText()).replace(unichr(0x2029), "\n") + newParagraph = chr(0x2029) if sys.version_info.major > 2 else unichr(0x2029) + selectedText = str(editor.textCursor().selectedText()).replace(newParagraph, "\n") invokeMenuItem("Tools", "Code Pasting", "Paste Snippet...") test.compare(waitForObject(":stackedWidget.plainTextEdit_QPlainTextEdit").plainText, selectedText, "Verify that dialog shows selected text from the editor") diff --git a/tests/system/suite_tools/tst_git_local/test.py b/tests/system/suite_tools/tst_git_local/test.py index 07208367fdb..ab36b86b251 100644 --- a/tests/system/suite_tools/tst_git_local/test.py +++ b/tests/system/suite_tools/tst_git_local/test.py @@ -65,7 +65,8 @@ def __clickCommit__(count): # find commit try: # Commits are listed in reverse chronologic order, so we have to invert count - line = filter(lambda line: line.startswith("commit"), content.splitlines())[-count].strip() + line = list(filter(lambda line: line.startswith("commit"), + content.splitlines()))[-count].strip() commit = line.split(" ", 1)[1] except: test.fail("Could not find the %d. commit - leaving test" % count) @@ -90,7 +91,7 @@ def __clickCommit__(count): {"Committer: %s, %s" % (id, time): True}] for line, exp in zip(show.splitlines(), expected): expLine = list(exp.keys())[0] - isRegex = exp.values()[0] + isRegex = list(exp.values())[0] if isRegex: test.verify(re.match(expLine, line), "Verifying commit header line '%s'" % line) else: From e719a2b47a11cdb6c4c9ac8fe889cf8347380580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 5 May 2023 16:45:08 +0200 Subject: [PATCH 1060/1447] SquishTests: Update tst_create_proj_wizard Change-Id: Id17f5d1a68da7fe7c9f45dc5b62ab3fe1039f753 Reviewed-by: Christian Stenger Reviewed-by: --- tests/system/shared/project.py | 6 +++--- .../suite_general/tst_create_proj_wizard/test.py | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index d05a3b37a8e..2e541ddf920 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -125,8 +125,8 @@ def __handleBuildSystem__(buildSystem): return buildSystem def __createProjectHandleQtQuickSelection__(minimumQtVersion): - comboBox = waitForObject("{name='MinimumSupportedQtVersion' type='QComboBox' " - "visible='1' window=':New_ProjectExplorer::JsonWizard'}") + comboBox = waitForObject("{name?='*QtVersion' type='QComboBox' visible='1'" + " window=':New_ProjectExplorer::JsonWizard'}") try: selectFromCombo(comboBox, minimumQtVersion) except: @@ -505,7 +505,7 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False, ignoreVali version = res.group("version") else: version = None - if "Qt Quick" in templateName: + if templateName == "Qt Quick Application": result = set([Targets.DESKTOP_6_2_4]) elif 'Supported Platforms' in text: supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split("\n") 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 5cf9365275d..643e8054fa1 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -53,11 +53,18 @@ def main(): template = list(current.values())[0] with TestSection("Testing project template %s -> %s" % (category, template)): displayedPlatforms = __createProject__(category, template) - if template == "Qt Quick Application": - qtVersionsForQuick = ["6.2"] + if template.startswith("Qt Quick Application"): + if "(compat)" in template: # QTCREATORBUG-29126 + qtVersionsForQuick = ["Qt 5.14", "Qt 6.2"] + else: + qtVersionsForQuick = ["6.2"] for counter, qtVersion in enumerate(qtVersionsForQuick): def additionalFunc(displayedPlatforms, qtVersion): requiredQtVersion = __createProjectHandleQtQuickSelection__(qtVersion) + if sys.version_info.major > 2: + requiredQtVersion = requiredQtVersion.removeprefix("Qt ") + else: + requiredQtVersion = requiredQtVersion.lstrip("Qt ") __modifyAvailableTargets__(displayedPlatforms, requiredQtVersion, True) handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms, additionalFunc, qtVersion) @@ -120,7 +127,7 @@ def handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms, clickButton(waitForObject(":Next_QPushButton")) if specialHandlingFunc: specialHandlingFunc(displayedPlatforms, *args) - if not ('Plain C' in template or 'Qt Quick' in template): + if not ('Plain C' in template or template == 'Qt Quick Application'): __createProjectHandleTranslationSelection__() verifyKitCheckboxes(kits, displayedPlatforms) safeClickButton("Cancel") From 9ff0cf7306eed74f36bd1826fe6ec5b26d5f25e9 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 9 May 2023 18:22:47 +0200 Subject: [PATCH 1061/1447] CMakePM: Add action to reload CMake Presets The CMake presets will be reloaded. The preset kits will get the CMake configuration cleared (no more CMakeCache.txt) All the kits will be removed from the project, so that the Kit configuration wizard will be displayed at the end. If a normal Qt Kit was configured, the user will get the chance to import the existing configuration (the initial configuration will be lost though). Change-Id: Ieda83098d7716913d7870b67ab522705da4ed93b Reviewed-by: Leena Miettinen Reviewed-by: Alessandro Portale Reviewed-by: hjk --- .../cmakeprojectmanager/cmakeproject.cpp | 13 ++- .../cmakeprojectmanager/cmakeproject.h | 4 + .../cmakeprojectconstants.h | 1 + .../cmakeprojectimporter.cpp | 25 +++++- .../cmakeprojectimporter.h | 7 +- .../cmakeprojectmanager.cpp | 89 +++++++++++++++++++ .../cmakeprojectmanager/cmakeprojectmanager.h | 2 + .../cmakespecificsettings.cpp | 6 ++ .../cmakespecificsettings.h | 1 + 9 files changed, 141 insertions(+), 7 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 8bd96f239ef..610fd86ec29 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -67,7 +67,7 @@ Tasks CMakeProject::projectIssues(const Kit *k) const ProjectImporter *CMakeProject::projectImporter() const { if (!m_projectImporter) - m_projectImporter = new CMakeProjectImporter(projectFilePath(), m_presetsData); + m_projectImporter = new CMakeProjectImporter(projectFilePath(), this); return m_projectImporter; } @@ -306,4 +306,15 @@ void CMakeProject::configureAsExampleProject(ProjectExplorer::Kit *kit) setup(infoList); } +void CMakeProjectManager::CMakeProject::setOldPresetKits( + const QList &presetKits) const +{ + m_oldPresetKits = presetKits; +} + +QList CMakeProject::oldPresetKits() const +{ + return m_oldPresetKits; +} + } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 09154615013..6540dd4964d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -31,6 +31,9 @@ public: Internal::PresetsData presetsData() const; void readPresets(); + void setOldPresetKits(const QList &presetKits) const; + QList oldPresetKits() const; + protected: bool setupTarget(ProjectExplorer::Target *t) final; @@ -43,6 +46,7 @@ private: void setupBuildPresets(Internal::PresetsData &presetsData); mutable Internal::CMakeProjectImporter *m_projectImporter = nullptr; + mutable QList m_oldPresetKits; ProjectExplorer::Tasks m_issues; Internal::PresetsData m_presetsData; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h index cbaa6487266..183e9501360 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h @@ -17,6 +17,7 @@ const char BUILD_FILE_CONTEXT_MENU[] = "CMakeProject.BuildFileContextMenu"; const char BUILD_FILE[] = "CMakeProject.BuildFile"; const char CMAKE_HOME_DIR[] = "CMakeProject.HomeDirectory"; const char QML_DEBUG_SETTING[] = "CMakeProject.EnableQmlDebugging"; +const char RELOAD_CMAKE_PRESETS[] = "CMakeProject.ReloadCMakePresets"; const char CMAKEFORMATTER_SETTINGS_GROUP[] = "CMakeFormatter"; const char CMAKEFORMATTER_GENERAL_GROUP[] = "General"; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 14c4a5b817f..029182a053d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -5,6 +5,7 @@ #include "cmakebuildconfiguration.h" #include "cmakekitinformation.h" +#include "cmakeproject.h" #include "cmakeprojectconstants.h" #include "cmakeprojectmanagertr.h" #include "cmaketoolmanager.h" @@ -15,6 +16,7 @@ #include #include #include +#include #include #include @@ -92,9 +94,9 @@ static QString uniqueCMakeToolDisplayName(CMakeTool &tool) // CMakeProjectImporter -CMakeProjectImporter::CMakeProjectImporter(const FilePath &path, const PresetsData &presetsData) +CMakeProjectImporter::CMakeProjectImporter(const FilePath &path, const CMakeProject *project) : QtProjectImporter(path) - , m_presetsData(presetsData) + , m_project(project) , m_presetsTempDir("qtc-cmake-presets-XXXXXXXX") { useTemporaryKitAspect(CMakeKitAspect::id(), @@ -119,7 +121,7 @@ FilePaths CMakeProjectImporter::importCandidates() candidates << scanDirectory(shadowBuildDirectory.absolutePath(), QString()); } - for (const auto &configPreset : m_presetsData.configurePresets) { + for (const auto &configPreset : m_project->presetsData().configurePresets) { if (configPreset.hidden.value()) continue; @@ -152,6 +154,21 @@ FilePaths CMakeProjectImporter::importCandidates() return finalists; } +Target *CMakeProjectImporter::preferredTarget(const QList &possibleTargets) +{ + for (Kit *kit : m_project->oldPresetKits()) { + const bool haveKit = Utils::contains(possibleTargets, [kit](const auto &target) { + return target->kit() == kit; + }); + + if (!haveKit) + KitManager::deregisterKit(kit); + } + m_project->setOldPresetKits({}); + + return ProjectImporter::preferredTarget(possibleTargets); +} + static CMakeConfig configurationFromPresetProbe( const FilePath &importPath, const FilePath &sourceDirectory, @@ -618,7 +635,7 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, const QString presetName = importPath.fileName(); PresetsDetails::ConfigurePreset configurePreset - = Utils::findOrDefault(m_presetsData.configurePresets, + = Utils::findOrDefault(m_project->presetsData().configurePresets, [presetName](const PresetsDetails::ConfigurePreset &preset) { return preset.name == presetName; }); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h index 229ccfa36d5..350b0b77d6c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h @@ -11,6 +11,7 @@ namespace CMakeProjectManager { +class CMakeProject; class CMakeTool; namespace Internal { @@ -20,9 +21,11 @@ struct DirectoryData; class CMakeProjectImporter : public QtSupport::QtProjectImporter { public: - CMakeProjectImporter(const Utils::FilePath &path, const Internal::PresetsData &presetsData); + CMakeProjectImporter(const Utils::FilePath &path, + const CMakeProjectManager::CMakeProject *project); Utils::FilePaths importCandidates() final; + ProjectExplorer::Target *preferredTarget(const QList &possibleTargets) final; private: QList examineDirectory(const Utils::FilePath &importPath, @@ -44,7 +47,7 @@ private: void ensureBuildDirectory(DirectoryData &data, const ProjectExplorer::Kit *k) const; - Internal::PresetsData m_presetsData; + const CMakeProject *m_project; Utils::TemporaryDirectory m_presetsTempDir; }; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index 95baccee1e9..ab7bfb4990e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -9,6 +9,7 @@ #include "cmakeprojectconstants.h" #include "cmakeprojectmanagertr.h" #include "cmakeprojectnodes.h" +#include "cmakespecificsettings.h" #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include @@ -26,6 +28,8 @@ #include #include +#include +#include #include #include @@ -42,6 +46,8 @@ CMakeManager::CMakeManager() , m_clearCMakeCacheAction(new QAction(QIcon(), Tr::tr("Clear CMake Configuration"), this)) , m_runCMakeActionContextMenu(new QAction(QIcon(), Tr::tr("Run CMake"), this)) , m_rescanProjectAction(new QAction(QIcon(), Tr::tr("Rescan Project"), this)) + , m_reloadCMakePresetsAction( + new QAction(Utils::Icons::RELOAD_TOOLBAR.icon(), Tr::tr("Reload CMake Presets"), this)) { Core::ActionContainer *mbuild = Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT); @@ -101,6 +107,15 @@ CMakeManager::CMakeManager() rescanProject(ProjectTree::currentBuildSystem()); }); + command = Core::ActionManager::registerAction(m_reloadCMakePresetsAction, + Constants::RELOAD_CMAKE_PRESETS, + globalContext); + command->setAttribute(Core::Command::CA_Hide); + mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD); + connect(m_reloadCMakePresetsAction, &QAction::triggered, this, [this] { + reloadCMakePresets(); + }); + m_buildFileAction = new Utils::ParameterAction(Tr::tr("Build File"), Tr::tr("Build File \"%1\""), Utils::ParameterAction::AlwaysEnabled, @@ -135,6 +150,16 @@ void CMakeManager::updateCmakeActions(Node *node) m_runCMakeActionContextMenu->setEnabled(visible); m_clearCMakeCacheAction->setVisible(visible); m_rescanProjectAction->setVisible(visible); + + const bool reloadPresetsVisible = [project] { + if (!project) + return false; + const FilePath presetsPath = project->projectFilePath().parentDir().pathAppended( + "CMakePresets.json"); + return presetsPath.exists(); + }(); + m_reloadCMakePresetsAction->setVisible(reloadPresetsVisible); + enableBuildFileMenus(node); } @@ -204,6 +229,70 @@ void CMakeManager::enableBuildFileMenus(Node *node) } } +void CMakeManager::reloadCMakePresets() +{ + auto settings = CMakeSpecificSettings::instance(); + bool doNotAsk = !settings->askBeforePresetsReload.value(); + if (!doNotAsk) { + CheckableMessageBox question(Core::ICore::dialogParent()); + + question.setIcon(QMessageBox::Question); + question.setWindowTitle(Tr::tr("Reload CMake Presets")); + question.setText(Tr::tr("Re-generates the CMake presets kits. The manual CMake project modifications will be lost.")); + question.setCheckBoxText(Tr::tr("Do not ask again")); + question.setCheckBoxVisible(true); + question.setChecked(doNotAsk); + question.setStandardButtons(QDialogButtonBox::Cancel); + + question.addButton(Tr::tr("Reload"), QDialogButtonBox::YesRole); + question.setDefaultButton(QDialogButtonBox::Yes); + question.exec(); + + doNotAsk = question.isChecked(); + + settings->askBeforePresetsReload.setValue(!doNotAsk); + settings->writeSettings(Core::ICore::settings()); + + if (question.clickedStandardButton() == QDialogButtonBox::Cancel) + return; + } + + CMakeProject *project = static_cast(ProjectTree::currentProject()); + if (!project) + return; + + const QSet oldPresets = Utils::transform(project->presetsData().configurePresets, + [](const auto &preset) { + return preset.name; + }); + project->readPresets(); + + QList oldKits; + for (const auto &target : project->targets()) { + const CMakeConfigItem presetItem = CMakeConfigurationKitAspect::cmakePresetConfigItem( + target->kit()); + + if (BuildManager::isBuilding(target)) + BuildManager::cancel(); + + // Only clear the CMake configuration for preset kits. Any manual kit configuration + // will get the chance to get imported afterwards in the Kit selection wizard + CMakeBuildSystem *bs = static_cast(target->buildSystem()); + if (!presetItem.isNull() && bs) + bs->clearCMakeCache(); + + if (!presetItem.isNull() && oldPresets.contains(QString::fromUtf8(presetItem.value))) + oldKits << target->kit(); + + project->removeTarget(target); + } + + project->setOldPresetKits(oldKits); + + Core::ModeManager::activateMode(ProjectExplorer::Constants::MODE_SESSION); + Core::ModeManager::setFocusToCurrentMode(); +} + void CMakeManager::buildFile(Node *node) { if (!node) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h index 3a527092917..c47d724c9b6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h @@ -30,12 +30,14 @@ private: void buildFile(ProjectExplorer::Node *node = nullptr); void updateBuildFileAction(); void enableBuildFileMenus(ProjectExplorer::Node *node); + void reloadCMakePresets(); QAction *m_runCMakeAction; QAction *m_clearCMakeCacheAction; QAction *m_runCMakeActionContextMenu; QAction *m_rescanProjectAction; QAction *m_buildFileContextMenu; + QAction *m_reloadCMakePresetsAction; Utils::ParameterAction *m_buildFileAction; }; diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index a4f08c60b15..5c22423a40d 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -38,6 +38,7 @@ CMakeSpecificSettings::CMakeSpecificSettings() autorunCMake, packageManagerAutoSetup, askBeforeReConfigureInitialParams, + askBeforePresetsReload, showSourceSubFolders, showAdvancedOptionsByDefault, st @@ -77,6 +78,11 @@ CMakeSpecificSettings::CMakeSpecificSettings() askBeforeReConfigureInitialParams.setLabelText(::CMakeProjectManager::Tr::tr("Ask before re-configuring with " "initial parameters")); + registerAspect(&askBeforePresetsReload); + askBeforePresetsReload.setSettingsKey("AskBeforePresetsReload"); + askBeforePresetsReload.setDefaultValue(true); + askBeforePresetsReload.setLabelText(::CMakeProjectManager::Tr::tr("Ask before reloading CMake Presets")); + registerAspect(&showSourceSubFolders); showSourceSubFolders.setSettingsKey("ShowSourceSubFolders"); showSourceSubFolders.setDefaultValue(true); diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h index 7050452c791..472945e1a5f 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h @@ -18,6 +18,7 @@ public: Utils::StringAspect ninjaPath; Utils::BoolAspect packageManagerAutoSetup; Utils::BoolAspect askBeforeReConfigureInitialParams; + Utils::BoolAspect askBeforePresetsReload; Utils::BoolAspect showSourceSubFolders; Utils::BoolAspect showAdvancedOptionsByDefault; }; From a3e9fc37ba3fc01ad441ca574b1f9d66520d5ff6 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 15 May 2023 16:24:13 +0200 Subject: [PATCH 1062/1447] Terminal: Fix assert Trying to fetch a cell outside the valid range did trigger an assert. Change-Id: I5ac3d78aa2249d1559e7603c9e4a9bcea4d0b563 Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/terminal/celliterator.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/terminal/celliterator.cpp b/src/plugins/terminal/celliterator.cpp index 597c3a632fd..d81c4b71879 100644 --- a/src/plugins/terminal/celliterator.cpp +++ b/src/plugins/terminal/celliterator.cpp @@ -20,12 +20,12 @@ CellIterator::CellIterator(const TerminalSurface *surface, int pos) m_maxpos = surface->fullSize().width() * (surface->fullSize().height()) - 1; m_pos = qMax(0, qMin(m_maxpos + 1, pos)); - if (m_pos == 0) + if (m_pos == 0) { m_state = State::BEGIN; - else if (m_pos == m_maxpos + 1) + updateChar(); + } else if (m_pos == m_maxpos + 1) { m_state = State::END; - - updateChar(); + } } CellIterator::CellIterator(const TerminalSurface *surface) From 8bd5c67ea8c15151e6435f6ccddd85347144864a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 4 May 2023 11:41:51 +0200 Subject: [PATCH 1063/1447] German translation: CVS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Iac295e700edf365b06b01bbb3a20c2f2f190a5ab Reviewed-by: Christian Stenger Reviewed-by: Robert Löhning --- share/qtcreator/translations/qtcreator_de.ts | 160 +++++++++---------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 5b78592b199..65fec424e4a 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -13850,315 +13850,315 @@ Stellen Sie sicher, dass der Wert der CMAKE_BUILD_TYPE-Variable derselbe wie der QtC::CVS Annotate revision "%1" - Annotation für Revision "%1" + Annotation für Revision "%1" Ignore Whitespace - Leerzeichen ignorieren + Leerzeichen ignorieren Ignore Blank Lines - Leerzeilen ignorieren + Leerzeilen ignorieren &Edit - + B&earbeiten CVS Checkout - CVS-Checkout + CVS-Checkout Triggers a CVS version control operation. - + Führt eine Aktion des CVS-Versionskontrollsystems aus. &CVS - &CVS + &CVS Diff Current File - + Diff für aktuelle Datei Diff "%1" - Diff für "%1" + Diff für "%1" Meta+C,Meta+D - Meta+C,Meta+D + Meta+C,Meta+D Alt+C,Alt+D - Alt+C,Alt+D + Alt+C,Alt+D Filelog Current File - Filelog für Datei + Filelog für aktuelle Datei Filelog "%1" - Filelog für "%1" + Filelog für "%1" Annotate Current File - Annotation für Datei + Annotation für aktuelle Datei Annotate "%1" - Annotation für "%1" + Annotation für "%1" Add - Hinzufügen + Hinzufügen Add "%1" - "%1" hinzufügen + "%1" hinzufügen Meta+C,Meta+A - Meta+C,Meta+A + Meta+C,Meta+A Alt+C,Alt+A - Alt+C,Alt+A + Alt+C,Alt+A Commit Current File - Commit der aktuellen Datei + Commit der aktuellen Datei Commit "%1" - Commit von "%1" + Commit von "%1" Meta+C,Meta+C - Meta+C,Meta+C + Meta+C,Meta+C Alt+C,Alt+C - Alt+C,Alt+C + Alt+C,Alt+C Delete... - Löschen... + Löschen... Delete "%1"... - Lösche "%1"... + Lösche "%1"... Revert... - Rückgängig machen... + Rückgängig machen... Revert "%1"... - Änderungen in "%1" rückgängig machen... + Änderungen in "%1" rückgängig machen... Edit - + Anfordern (edit) Edit "%1" - "%1" anfordern + "%1" anfordern (edit) Unedit - Anforderung zurücknehmen + Anforderung zurücknehmen (unedit) Unedit "%1" - Anforderung der Datei '%1" zurücknehmen + Anforderung der Datei '%1" zurücknehmen (unedit) Unedit Repository - Anforderung im gesamten Repository zurücknehmen + Anforderung im gesamten Repository zurücknehmen (unedit) Diff Project - Diff für Projekt + Diff für Projekt Diff Project "%1" - Diff für Projekt "%1" + Diff für Projekt "%1" Project Status - Status des Projekts (status) + Status des Projekts Status of Project "%1" - Status des Projekts "%1" + Status des Projekts "%1" Log Project - Log für Projekt + Log für Projekt Log Project "%1" - Log für Projekt "%1" + Log für Projekt "%1" Update Project - Projekt auf aktuellen Stand bringen + Projekt auf aktuellen Stand bringen Update Project "%1" - Projekt "%1"auf aktuellen Stand bringen + Projekt "%1" auf aktuellen Stand bringen Commit Project - Commit des Projekts + Commit des Projekts Commit Project "%1" - Commit des Projekts "%1" + Commit des Projekts "%1" Update Directory - Verzeichnis aktualisieren + Verzeichnis aktualisieren Update Directory "%1" - Verzeichnis "%1" aktualisieren + Verzeichnis "%1" aktualisieren Commit Directory - Commit des Verzeichnisses + Commit des Verzeichnisses Commit Directory "%1" - Commit des Verzeichnisses "%1" + Commit des Verzeichnisses "%1" Diff Repository - Diff des Repositorys + Diff des Repositorys Repository Status - Status des Repositorys + Status des Repositorys Repository Log - Log des Repositorys + Log des Repositorys Update Repository - Repository auf den aktuellen Stand bringen + Repository auf den aktuellen Stand bringen Commit All Files - Commit aller Dateien + Commit aller Dateien Revert Repository... - Änderungen im gesamten Repository rückgängig machen... + Änderungen im gesamten Repository rückgängig machen... Revert Repository - Alle Änderungen rückgängig machen + Änderungen im gesamten Repository rückgängig machen Revert all pending changes to the repository? - Möchten Sie alle ausstehenden Änderungen des Repositorys verwerfen? + Möchten Sie alle ausstehenden Änderungen des Repositorys verwerfen? Revert failed: %1 - Fehler beim Rücksetzen der Änderungen: %1 + Fehler beim Rückgängigmachen der Änderungen: %1 The file has been changed. Do you want to revert it? - + Die Datei wurde geändert. Möchten Sie die Änderungen rückgängig machen? Another commit is currently being executed. - Es läuft bereits ein Commit-Vorgang. + Es läuft bereits ein Commit-Vorgang. There are no modified files. - Es gibt keine geänderten Dateien. + Es gibt keine geänderten Dateien. Would you like to discard your changes to the repository "%1"? - Möchten Sie alle ausstehenden Änderungen des Repositorys "%1" verwerfen? + Möchten Sie alle ausstehenden Änderungen des Repositorys "%1" verwerfen? Would you like to discard your changes to the file "%1"? - Möchten Sie alle ausstehenden Änderungen in der Datei "%1" verwerfen? + Möchten Sie alle ausstehenden Änderungen in der Datei "%1" verwerfen? Project status - Status des Projekts + Status des Projekts Repository status - Status des Repositorys + Status des Repositorys Cannot find repository for "%1". - Kann das Repository für "%1" nicht finden. + Kann das Repository für "%1" nicht finden. The initial revision %1 cannot be described. - Die erste Version (%1) kann nicht weiter beschrieben werden. + Die erste Version (%1) kann nicht beschrieben werden. Parsing of the log output failed. - Die Log-Ausgabe konnte nicht ausgewertet werden. + Die Log-Ausgabe konnte nicht ausgewertet werden. Could not find commits of id "%1" on %2. - Es konnten keine Commits des Datums %2 mit der ID "%1" gefunden werden. + Es konnten keine Commits des Datums %2 mit der ID "%1" gefunden werden. No CVS executable specified. - Es wurde keine ausführbare Datei für CVS angegeben. + Es wurde keine ausführbare Datei für CVS angegeben. CVS Command - CVS-Kommando + CVS-Kommando CVS command: - CVS-Kommando: + CVS-Kommando: CVS root: - CVS-Quelle (CVSROOT): + CVS-Quelle (CVSROOT): Describe all files matching commit id - Alle zur Commit-ID gehörenden Dateien beschreiben + Alle zur Commit-ID gehörenden Dateien beschreiben When checked, all files touched by a commit will be displayed when clicking on a revision number in the annotation view (retrieved via commit ID). Otherwise, only the respective file will be displayed. - Wenn die Option aktiviert ist, werden beim Klick auf die Revisionsnummer in der Annotationsansicht alle Dateien angezeigt, die zu einem Commit gehören (mittels Commit-ID bestimmt). Ansonsten wird nur die betreffende Datei angezeigt. + Wenn die Option aktiviert ist, werden beim Klick auf die Revisionsnummer in der Annotationsansicht alle Dateien angezeigt, die zu einem Commit gehören (mittels Commit-ID bestimmt). Ansonsten wird nur die betreffende Datei angezeigt. CVS - CVS + CVS Configuration - Konfiguration + Konfiguration Miscellaneous - Sonstige Einstellungen + Sonstige Einstellungen Added - Hinzugefügt + Hinzugefügt Removed - Gelöscht + Gelöscht Modified - Geändert + Geändert @@ -34170,7 +34170,7 @@ You might find further explanations in the Application Output view. Update Project "%1" - Projekt "%1"auf aktuellen Stand bringen + Projekt "%1" auf aktuellen Stand bringen Describe... @@ -47616,7 +47616,7 @@ Failed to open file "%1" Update Project "%1" - Projekt "%1"auf aktuellen Stand bringen + Projekt "%1" auf aktuellen Stand bringen Revert Repository... From ef0cc8a1d91e0e9b898b23b6ccc0cab00b72713e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 21:16:32 +0200 Subject: [PATCH 1064/1447] ExecuteFilter: Remove the old matchesFor() implementation Change-Id: Ib1f001f366ef78f359d7c04cf8861ae59b9d22a9 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- .../coreplugin/locator/executefilter.cpp | 58 +++++-------------- .../coreplugin/locator/executefilter.h | 18 ++---- 2 files changed, 19 insertions(+), 57 deletions(-) diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 630bef03df7..2225508ae4b 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -104,47 +104,15 @@ void ExecuteFilter::acceptCommand(const QString &cmd) if (result == QMessageBox::Cancel) return; if (result == QMessageBox::No) { - m_taskQueue.enqueue(data); + m_taskQueue.append(data); return; } removeProcess(); } - m_taskQueue.enqueue(data); + m_taskQueue.append(data); runHeadCommand(); } -QList ExecuteFilter::matchesFor(QFutureInterface &future, - const QString &entry) -{ - QList results; - if (!entry.isEmpty()) { // avoid empty entry - LocatorFilterEntry filterEntry; - filterEntry.displayName = entry; - filterEntry.acceptor = [this, entry] { acceptCommand(entry); return AcceptResult(); }; - results.append(filterEntry); - } - QList others; - const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); - for (const QString &cmd : std::as_const(m_commandHistory)) { - if (future.isCanceled()) - break; - if (cmd == entry) // avoid repeated entry - continue; - LocatorFilterEntry filterEntry; - filterEntry.displayName = cmd; - filterEntry.acceptor = [this, cmd] { acceptCommand(cmd); return AcceptResult(); }; - const int index = cmd.indexOf(entry, 0, entryCaseSensitivity); - if (index >= 0) { - filterEntry.highlightInfo = {index, int(entry.length())}; - results.append(filterEntry); - } else { - others.append(filterEntry); - } - } - results.append(others); - return results; -} - void ExecuteFilter::done() { QTC_ASSERT(m_process, return); @@ -155,7 +123,7 @@ void ExecuteFilter::done() runHeadCommand(); } -void ExecuteFilter::readStandardOutput() +void ExecuteFilter::readStdOutput() { QTC_ASSERT(m_process, return); const QByteArray data = m_process->readAllRawStandardOutput(); @@ -163,7 +131,7 @@ void ExecuteFilter::readStandardOutput() QTextCodec::codecForLocale()->toUnicode(data.constData(), data.size(), &m_stdoutState)); } -void ExecuteFilter::readStandardError() +void ExecuteFilter::readStdError() { QTC_ASSERT(m_process, return); const QByteArray data = m_process->readAllRawStandardError(); @@ -174,11 +142,11 @@ void ExecuteFilter::readStandardError() void ExecuteFilter::runHeadCommand() { if (!m_taskQueue.isEmpty()) { - const ExecuteData &d = m_taskQueue.head(); + const ExecuteData &d = m_taskQueue.first(); if (d.command.executable().isEmpty()) { - MessageManager::writeDisrupting( - Tr::tr("Could not find executable for \"%1\".").arg(d.command.executable().toUserOutput())); - m_taskQueue.dequeue(); + MessageManager::writeDisrupting(Tr::tr("Could not find executable for \"%1\".") + .arg(d.command.executable().toUserOutput())); + m_taskQueue.removeFirst(); runHeadCommand(); return; } @@ -199,8 +167,8 @@ void ExecuteFilter::createProcess() m_process = new Process; m_process->setEnvironment(Environment::systemEnvironment()); connect(m_process, &Process::done, this, &ExecuteFilter::done); - connect(m_process, &Process::readyReadStandardOutput, this, &ExecuteFilter::readStandardOutput); - connect(m_process, &Process::readyReadStandardError, this, &ExecuteFilter::readStandardError); + connect(m_process, &Process::readyReadStandardOutput, this, &ExecuteFilter::readStdOutput); + connect(m_process, &Process::readyReadStandardError, this, &ExecuteFilter::readStdError); } void ExecuteFilter::removeProcess() @@ -208,7 +176,7 @@ void ExecuteFilter::removeProcess() if (!m_process) return; - m_taskQueue.dequeue(); + m_taskQueue.removeFirst(); m_process->deleteLater(); m_process = nullptr; } @@ -231,8 +199,8 @@ QString ExecuteFilter::headCommand() const { if (m_taskQueue.isEmpty()) return QString(); - const ExecuteData &data = m_taskQueue.head(); + const ExecuteData &data = m_taskQueue.first(); return data.command.toUserOutput(); } -} // Core::Internal +} // namespace Core::Internal diff --git a/src/plugins/coreplugin/locator/executefilter.h b/src/plugins/coreplugin/locator/executefilter.h index 348a09c7fe3..2e51d320d3c 100644 --- a/src/plugins/coreplugin/locator/executefilter.h +++ b/src/plugins/coreplugin/locator/executefilter.h @@ -7,19 +7,15 @@ #include -#include #include #include namespace Utils { class Process; } -namespace Core { -namespace Internal { +namespace Core::Internal { class ExecuteFilter : public Core::ILocatorFilter { - Q_OBJECT - struct ExecuteData { Utils::CommandLine command; @@ -29,14 +25,13 @@ class ExecuteFilter : public Core::ILocatorFilter public: ExecuteFilter(); ~ExecuteFilter() override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; + private: LocatorMatcherTasks matchers() final; void acceptCommand(const QString &cmd); void done(); - void readStandardOutput(); - void readStandardError(); + void readStdOutput(); + void readStdError(); void runHeadCommand(); void createProcess(); @@ -47,12 +42,11 @@ private: QString headCommand() const; - QQueue m_taskQueue; + QList m_taskQueue; QStringList m_commandHistory; Utils::Process *m_process = nullptr; QTextCodec::ConverterState m_stdoutState; QTextCodec::ConverterState m_stderrState; }; -} // namespace Internal -} // namespace Core +} // namespace Core::Internal From bc1144025631bd609cf3a16281e22962cb165cc7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 24 Apr 2023 22:45:42 +0200 Subject: [PATCH 1065/1447] RunConfigurationFilter: Remove the old matchesFor() implementation Since the base class vanished, rename the filters so that they have the common prefix now. Change-Id: I21c8d1f3ea3c3ad22063d7db8be72e66d449e701 Reviewed-by: Marcus Tillmanns --- .../projectexplorer/projectexplorer.cpp | 94 ++++--------------- 1 file changed, 19 insertions(+), 75 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index b382d6fec08..df77b48f8b8 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -408,40 +408,19 @@ protected: void restoreState(const QJsonObject &object) override; }; -// TODO: Remove the base class -class RunConfigurationLocatorFilter : public ILocatorFilter +class RunConfigurationStartFilter final : public ILocatorFilter { public: - RunConfigurationLocatorFilter(); - - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; - using RunAcceptor = std::function; -protected: - void setRunAcceptor(const RunAcceptor &acceptor) { m_acceptor = acceptor; } - -private: - void targetListUpdated(); - QList m_result; - RunAcceptor m_acceptor; -}; - -// TODO: Don't derive, flatten the hierarchy -class RunRunConfigurationLocatorFilter final : public RunConfigurationLocatorFilter -{ -public: - RunRunConfigurationLocatorFilter(); + RunConfigurationStartFilter(); private: Core::LocatorMatcherTasks matchers() final; }; -// TODO: Don't derive, flatten the hierarchy -class SwitchToRunConfigurationLocatorFilter final : public RunConfigurationLocatorFilter +class RunConfigurationSwitchFilter final : public ILocatorFilter { public: - SwitchToRunConfigurationLocatorFilter(); + RunConfigurationSwitchFilter(); private: Core::LocatorMatcherTasks matchers() final; @@ -682,8 +661,8 @@ public: AllProjectsFilter m_allProjectsFilter; CurrentProjectFilter m_currentProjectFilter; AllProjectFilesFilter m_allProjectDirectoriesFilter; - RunRunConfigurationLocatorFilter m_runConfigurationLocatorFilter; - SwitchToRunConfigurationLocatorFilter m_switchRunConfigurationLocatorFilter; + RunConfigurationStartFilter m_runConfigurationStartFilter; + RunConfigurationSwitchFilter m_runConfigurationSwitchFilter; CopyFileStepFactory m_copyFileStepFactory; CopyDirectoryStepFactory m_copyDirectoryFactory; @@ -4390,14 +4369,15 @@ void AllProjectFilesFilter::restoreState(const QJsonObject &object) DirectoryFilter::restoreState(withoutDirectories); } -RunConfigurationLocatorFilter::RunConfigurationLocatorFilter() +static void setupFilter(ILocatorFilter *filter) { - connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, - this, &RunConfigurationLocatorFilter::targetListUpdated); - - targetListUpdated(); + QObject::connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, + filter, [filter] { filter->setEnabled(ProjectManager::startupProject()); }); + filter->setEnabled(ProjectManager::startupProject()); } +using RunAcceptor = std::function; + static RunConfiguration *runConfigurationForDisplayName(const QString &displayName) { const Target *target = ProjectManager::startupTarget(); @@ -4409,8 +4389,7 @@ static RunConfiguration *runConfigurationForDisplayName(const QString &displayNa }); } -static LocatorMatcherTasks runConfigurationMatchers( - const RunConfigurationLocatorFilter::RunAcceptor &acceptor) +static LocatorMatcherTasks runConfigurationMatchers(const RunAcceptor &acceptor) { using namespace Tasking; @@ -4442,58 +4421,23 @@ static LocatorMatcherTasks runConfigurationMatchers( return {{Sync(onSetup), storage}}; } -void RunConfigurationLocatorFilter::prepareSearch(const QString &entry) -{ - m_result.clear(); - const Target *target = ProjectManager::startupTarget(); - if (!target) - return; - for (auto rc : target->runConfigurations()) { - if (rc->displayName().contains(entry, Qt::CaseInsensitive)) { - LocatorFilterEntry entry; - entry.displayName = rc->displayName(); - entry.acceptor = [name = entry.displayName, acceptor = m_acceptor] { - RunConfiguration *config = runConfigurationForDisplayName(name); - if (!config) - return AcceptResult(); - acceptor(config); - return AcceptResult(); - }; - m_result.append(entry); - } - } -} - -QList RunConfigurationLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - Q_UNUSED(future) - Q_UNUSED(entry) - return m_result; -} - -void RunConfigurationLocatorFilter::targetListUpdated() -{ - setEnabled(ProjectManager::startupProject()); // at least one project opened -} - static void runAcceptor(RunConfiguration *config) { if (!BuildManager::isBuilding(config->project())) ProjectExplorerPlugin::runRunConfiguration(config, Constants::NORMAL_RUN_MODE, true); } -RunRunConfigurationLocatorFilter::RunRunConfigurationLocatorFilter() +RunConfigurationStartFilter::RunConfigurationStartFilter() { setId("Run run configuration"); setDisplayName(Tr::tr("Run Run Configuration")); setDescription(Tr::tr("Runs a run configuration of the active project.")); setDefaultShortcutString("rr"); setPriority(Medium); - setRunAcceptor(&runAcceptor); + setupFilter(this); } -LocatorMatcherTasks RunRunConfigurationLocatorFilter::matchers() +LocatorMatcherTasks RunConfigurationStartFilter::matchers() { return runConfigurationMatchers(&runAcceptor); } @@ -4510,17 +4454,17 @@ static void switchAcceptor(RunConfiguration *config) }); } -SwitchToRunConfigurationLocatorFilter::SwitchToRunConfigurationLocatorFilter() +RunConfigurationSwitchFilter::RunConfigurationSwitchFilter() { setId("Switch run configuration"); setDisplayName(Tr::tr("Switch Run Configuration")); setDescription(Tr::tr("Switches the active run configuration of the active project.")); setDefaultShortcutString("sr"); setPriority(Medium); - setRunAcceptor(&switchAcceptor); + setupFilter(this); } -LocatorMatcherTasks SwitchToRunConfigurationLocatorFilter::matchers() +LocatorMatcherTasks RunConfigurationSwitchFilter::matchers() { return runConfigurationMatchers(&switchAcceptor); } From 318ac763392edf37bd2e18b15efebc7274f222b5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 12:42:08 +0200 Subject: [PATCH 1066/1447] QMakeProject: Use PagedSettings page for options Also adapt to a few recent usage changes. Change-Id: I33f45fe7c2b8738280a7c81ddb9110cb8714c45a Reviewed-by: Christian Stenger --- .../qmakebuildconfiguration.cpp | 8 +- .../qmakeprojectmanager/qmakemakestep.cpp | 2 +- .../qmakeprojectmanagerplugin.cpp | 2 +- .../qmakeprojectmanager/qmakesettings.cpp | 121 ++++++------------ .../qmakeprojectmanager/qmakesettings.h | 36 ++---- src/plugins/qmakeprojectmanager/qmakestep.cpp | 2 +- 6 files changed, 57 insertions(+), 114 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index ce64ecd2d91..173443958db 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -160,7 +160,7 @@ QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target, Id id) this, &QmakeBuildConfiguration::updateProblemLabel); connect(this, &QmakeBuildConfiguration::qmakeBuildConfigurationChanged, this, &QmakeBuildConfiguration::updateProblemLabel); - connect(&QmakeSettings::instance(), &QmakeSettings::settingsChanged, + connect(&settings(), &AspectContainer::changed, this, &QmakeBuildConfiguration::updateProblemLabel); connect(target, &Target::parsingFinished, this, &QmakeBuildConfiguration::updateProblemLabel); connect(target, &Target::kitChanged, this, &QmakeBuildConfiguration::updateProblemLabel); @@ -267,7 +267,7 @@ void QmakeBuildConfiguration::updateProblemLabel() } } - const bool unalignedBuildDir = QmakeSettings::warnAgainstUnalignedBuildDir() + const bool unalignedBuildDir = settings().warnAgainstUnalignedBuildDir() && !isBuildDirAtSafeLocation(); if (unalignedBuildDir) allGood = false; @@ -426,7 +426,7 @@ bool QmakeBuildConfiguration::runSystemFunction() const return true; if (runSystem == TriState::Disabled) return false; - return QmakeSettings::runSystemFunction(); + return settings().runSystemFunction(); } QStringList QmakeBuildConfiguration::configCommandLineArguments() const @@ -753,7 +753,7 @@ QmakeBuildConfigurationFactory::QmakeBuildConfigurationFactory() Tasks issues; if (version) issues << version->reportIssues(projectPath, buildDir); - if (QmakeSettings::warnAgainstUnalignedBuildDir() + if (settings().warnAgainstUnalignedBuildDir() && !QmakeBuildConfiguration::isBuildDirAtSafeLocation( projectPath.absolutePath(), buildDir.absoluteFilePath())) { issues.append(BuildSystemTask(Task::Warning, diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp index ae35a9dc767..e72d3467582 100644 --- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp @@ -222,7 +222,7 @@ void QmakeMakeStep::doRun() void QmakeMakeStep::finish(ProcessResult result) { if (!isSuccess(result) && !isCanceled() && m_unalignedBuildDir - && QmakeSettings::warnAgainstUnalignedBuildDir()) { + && settings().warnAgainstUnalignedBuildDir()) { const QString msg = Tr::tr("The build directory is not at the same level as the source " "directory, which could be the reason for the build failure."); emit addTask(BuildSystemTask(Task::Warning, msg)); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index 67d450b56f4..d89393909ba 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -80,7 +80,7 @@ public: ProFileEditorFactory profileEditorFactory; - QmakeSettingsPage settingsPage; + QmakeSettings settings; QmakeProject *m_previousStartupProject = nullptr; Target *m_previousTarget = nullptr; diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.cpp b/src/plugins/qmakeprojectmanager/qmakesettings.cpp index a9e1de07c3b..5a05e5904d9 100644 --- a/src/plugins/qmakeprojectmanager/qmakesettings.cpp +++ b/src/plugins/qmakeprojectmanager/qmakesettings.cpp @@ -11,98 +11,59 @@ #include #include -#include - using namespace Utils; -namespace QmakeProjectManager { -namespace Internal { +namespace QmakeProjectManager::Internal { + +static QmakeSettings *theSettings; + +QmakeSettings &settings() { return *theSettings; } QmakeSettings::QmakeSettings() { - setAutoApply(false); + theSettings = this; - registerAspect(&m_warnAgainstUnalignedBuildDir); - m_warnAgainstUnalignedBuildDir.setSettingsKey("QmakeProjectManager/WarnAgainstUnalignedBuildDir"); - m_warnAgainstUnalignedBuildDir.setDefaultValue(HostOsInfo::isWindowsHost()); - m_warnAgainstUnalignedBuildDir.setLabelText(Tr::tr("Warn if a project's source and " - "build directories are not at the same level")); - m_warnAgainstUnalignedBuildDir.setToolTip(Tr::tr("Qmake has subtle bugs that " - "can be triggered if source and build directory are not at the same level.")); + setId("K.QmakeProjectManager.QmakeSettings"); + setDisplayName(Tr::tr("Qmake")); + setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); + setSettingsGroup("QmakeProjectManager"); - registerAspect(&m_alwaysRunQmake); - m_alwaysRunQmake.setSettingsKey("QmakeProjectManager/AlwaysRunQmake"); - m_alwaysRunQmake.setLabelText(Tr::tr("Run qmake on every build")); - m_alwaysRunQmake.setToolTip(Tr::tr("This option can help to prevent failures on " - "incremental builds, but might slow them down unnecessarily in the general case.")); + registerAspect(&warnAgainstUnalignedBuildDir); + warnAgainstUnalignedBuildDir.setSettingsKey("WarnAgainstUnalignedBuildDir"); + warnAgainstUnalignedBuildDir.setDefaultValue(HostOsInfo::isWindowsHost()); + warnAgainstUnalignedBuildDir.setLabelText(Tr::tr("Warn if a project's source and " + "build directories are not at the same level")); + warnAgainstUnalignedBuildDir.setToolTip(Tr::tr("Qmake has subtle bugs that " + "can be triggered if source and build directory are not at the same level.")); - registerAspect(&m_ignoreSystemFunction); - m_ignoreSystemFunction.setSettingsKey("QmakeProjectManager/RunSystemFunction"); - m_ignoreSystemFunction.setLabelText(Tr::tr("Ignore qmake's system() function when parsing a project")); - m_ignoreSystemFunction.setToolTip(Tr::tr("Checking this option avoids unwanted side effects, " - "but may result in inexact parsing results.")); + registerAspect(&alwaysRunQmake); + alwaysRunQmake.setSettingsKey("AlwaysRunQmake"); + alwaysRunQmake.setLabelText(Tr::tr("Run qmake on every build")); + alwaysRunQmake.setToolTip(Tr::tr("This option can help to prevent failures on " + "incremental builds, but might slow them down unnecessarily in the general case.")); + + registerAspect(&ignoreSystemFunction); + ignoreSystemFunction.setSettingsKey("RunSystemFunction"); + ignoreSystemFunction.setLabelText(Tr::tr("Ignore qmake's system() function when parsing a project")); + ignoreSystemFunction.setToolTip(Tr::tr("Checking this option avoids unwanted side effects, " + "but may result in inexact parsing results.")); // The settings value has been stored with the opposite meaning for a while. // Avoid changing the stored value, but flip it on read/write: const auto invertBoolVariant = [](const QVariant &v) { return QVariant(!v.toBool()); }; - m_ignoreSystemFunction.setFromSettingsTransformation(invertBoolVariant); - m_ignoreSystemFunction.setToSettingsTransformation(invertBoolVariant); + ignoreSystemFunction.setFromSettingsTransformation(invertBoolVariant); + ignoreSystemFunction.setToSettingsTransformation(invertBoolVariant); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + Column { + warnAgainstUnalignedBuildDir, + alwaysRunQmake, + ignoreSystemFunction, + st + }.attachTo(widget); + }); readSettings(Core::ICore::settings()); } -bool QmakeSettings::warnAgainstUnalignedBuildDir() -{ - return instance().m_warnAgainstUnalignedBuildDir.value(); -} - -bool QmakeSettings::alwaysRunQmake() -{ - return instance().m_alwaysRunQmake.value(); -} - -bool QmakeSettings::runSystemFunction() -{ - return !instance().m_ignoreSystemFunction.value(); // Note: negated. -} - -QmakeSettings &QmakeSettings::instance() -{ - static QmakeSettings theSettings; - return theSettings; -} - -class SettingsWidget final : public Core::IOptionsPageWidget -{ -public: - SettingsWidget() - { - auto &s = QmakeSettings::instance(); - using namespace Layouting; - Column { - s.m_warnAgainstUnalignedBuildDir, - s.m_alwaysRunQmake, - s.m_ignoreSystemFunction, - st - }.attachTo(this); - } - - void apply() final - { - auto &s = QmakeSettings::instance(); - if (s.isDirty()) { - s.apply(); - s.writeSettings(Core::ICore::settings()); - } - } -}; - -QmakeSettingsPage::QmakeSettingsPage() -{ - setId("K.QmakeProjectManager.QmakeSettings"); - setDisplayName(Tr::tr("Qmake")); - setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); - setWidgetCreator([] { return new SettingsWidget; }); -} - -} // namespace Internal -} // namespace QmakeProjectManager +} // QmakeProjectManager::Internal diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.h b/src/plugins/qmakeprojectmanager/qmakesettings.h index 242f6601e2d..de9a9ec0d37 100644 --- a/src/plugins/qmakeprojectmanager/qmakesettings.h +++ b/src/plugins/qmakeprojectmanager/qmakesettings.h @@ -5,38 +5,20 @@ #include -#include +namespace QmakeProjectManager::Internal { -namespace QmakeProjectManager { -namespace Internal { - -class QmakeSettings : public Utils::AspectContainer +class QmakeSettings : public Core::PagedSettings { - Q_OBJECT - public: - static QmakeSettings &instance(); - static bool warnAgainstUnalignedBuildDir(); - static bool alwaysRunQmake(); - static bool runSystemFunction(); - -signals: - void settingsChanged(); - -private: QmakeSettings(); - friend class SettingsWidget; - Utils::BoolAspect m_warnAgainstUnalignedBuildDir; - Utils::BoolAspect m_alwaysRunQmake; - Utils::BoolAspect m_ignoreSystemFunction; + bool runSystemFunction() { return !ignoreSystemFunction(); } + + Utils::BoolAspect warnAgainstUnalignedBuildDir; + Utils::BoolAspect alwaysRunQmake; + Utils::BoolAspect ignoreSystemFunction; }; -class QmakeSettingsPage final : public Core::IOptionsPage -{ -public: - QmakeSettingsPage(); -}; +QmakeSettings &settings(); -} // namespace Internal -} // namespace QmakeProjectManager +} // QmakeProjectManager::Internal diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index edcc0e40bb3..010d160823b 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -225,7 +225,7 @@ bool QMakeStep::init() } // Check whether we need to run qmake - if (m_forced || QmakeSettings::alwaysRunQmake() + if (m_forced || settings().alwaysRunQmake() || qmakeBc->compareToImportFrom(makeFile) != QmakeBuildConfiguration::MakefileMatches) { m_needToRunQMake = true; } From e2df60abc2acf465c2941719ab6e56573d07a762 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 00:05:01 +0200 Subject: [PATCH 1067/1447] BaseFileFilter: Remove me - I'm not needed anymore Change-Id: I19effcb846f57838b47352c19aec0d521e1c3ecd Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns --- src/plugins/coreplugin/CMakeLists.txt | 1 - src/plugins/coreplugin/coreplugin.qbs | 2 - .../coreplugin/locator/basefilefilter.cpp | 254 ------------------ .../coreplugin/locator/basefilefilter.h | 61 ----- 4 files changed, 318 deletions(-) delete mode 100644 src/plugins/coreplugin/locator/basefilefilter.cpp delete mode 100644 src/plugins/coreplugin/locator/basefilefilter.h diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index 0869553d8c4..1507b345c9a 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -99,7 +99,6 @@ add_qtc_plugin(Core iwelcomepage.cpp iwelcomepage.h iwizardfactory.cpp iwizardfactory.h jsexpander.cpp jsexpander.h - locator/basefilefilter.cpp locator/basefilefilter.h locator/commandlocator.cpp locator/commandlocator.h locator/directoryfilter.cpp locator/directoryfilter.h locator/executefilter.cpp locator/executefilter.h diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 654f2e6bcb6..2467567f01f 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -327,8 +327,6 @@ Project { name: "Locator" prefix: "locator/" files: [ - "basefilefilter.cpp", - "basefilefilter.h", "commandlocator.cpp", "commandlocator.h", "directoryfilter.cpp", diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp deleted file mode 100644 index d7f96b8ec16..00000000000 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "basefilefilter.h" - -#include -#include -#include -#include - -#include -#include - -using namespace Utils; - -namespace Core { -namespace Internal { - -class Data -{ -public: - void clear() - { - iterator.clear(); - previousResultPaths.clear(); - previousEntry.clear(); - } - - QSharedPointer iterator; - FilePaths previousResultPaths; - bool forceNewSearchList; - QString previousEntry; -}; - -class BaseFileFilterPrivate -{ -public: - Data m_data; - Data m_current; -}; - -} // Internal - -/*! - \class Core::BaseFileFilter - \inheaderfile coreplugin/locator/basefilefilter.h - \inmodule QtCreator - - \brief The BaseFileFilter class is a base class for locator filter classes. -*/ - -/*! - \class Core::BaseFileFilter::Iterator - \inmodule QtCreator - \internal -*/ - -/*! - \class Core::BaseFileFilter::ListIterator - \inmodule QtCreator - \internal -*/ - -BaseFileFilter::Iterator::~Iterator() = default; - -/*! - \internal -*/ -BaseFileFilter::BaseFileFilter() - : d(new Internal::BaseFileFilterPrivate) -{ - d->m_data.forceNewSearchList = true; - setFileIterator(new ListIterator({})); -} - -/*! - \internal -*/ -BaseFileFilter::~BaseFileFilter() -{ - delete d; -} - -/*! - \reimp -*/ -void BaseFileFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) - d->m_current = d->m_data; - d->m_data.forceNewSearchList = false; -} - -ILocatorFilter::MatchLevel BaseFileFilter::matchLevelFor(const QRegularExpressionMatch &match, - const QString &matchText) -{ - const int consecutivePos = match.capturedStart(1); - if (consecutivePos == 0) - return MatchLevel::Best; - if (consecutivePos > 0) { - const QChar prevChar = matchText.at(consecutivePos - 1); - if (prevChar == '_' || prevChar == '.') - return MatchLevel::Better; - } - if (match.capturedStart() == 0) - return MatchLevel::Good; - return MatchLevel::Normal; -} - -/*! - \reimp -*/ -QList BaseFileFilter::matchesFor(QFutureInterface &future, const QString &origEntry) -{ - QList entries[int(MatchLevel::Count)]; - // If search string contains spaces, treat them as wildcard '*' and search in full path - const QString entry = QDir::fromNativeSeparators(origEntry).replace(' ', '*'); - const Link link = Link::fromString(entry, true); - - const QRegularExpression regexp = createRegExp(link.targetFilePath.toString()); - if (!regexp.isValid()) { - d->m_current.clear(); // free memory - return {}; - } - auto containsPathSeparator = [](const QString &candidate) { - return candidate.contains('/') || candidate.contains('*'); - }; - - const bool hasPathSeparator = containsPathSeparator(link.targetFilePath.toString()); - const bool containsPreviousEntry = !d->m_current.previousEntry.isEmpty() - && link.targetFilePath.toString().contains(d->m_current.previousEntry); - const bool pathSeparatorAdded = !containsPathSeparator(d->m_current.previousEntry) - && hasPathSeparator; - const bool searchInPreviousResults = !d->m_current.forceNewSearchList && containsPreviousEntry - && !pathSeparatorAdded; - if (searchInPreviousResults) - d->m_current.iterator.reset(new ListIterator(d->m_current.previousResultPaths)); - - QTC_ASSERT(d->m_current.iterator.data(), return QList()); - d->m_current.previousResultPaths.clear(); - d->m_current.previousEntry = link.targetFilePath.toString(); - d->m_current.iterator->toFront(); - bool canceled = false; - while (d->m_current.iterator->hasNext()) { - if (future.isCanceled()) { - canceled = true; - break; - } - - d->m_current.iterator->next(); - FilePath path = d->m_current.iterator->filePath(); - QString matchText = hasPathSeparator ? path.toString() : path.fileName(); - QRegularExpressionMatch match = regexp.match(matchText); - - if (match.hasMatch()) { - LocatorFilterEntry filterEntry; - filterEntry.displayName = path.fileName(); - filterEntry.filePath = path; - filterEntry.extraInfo = path.shortNativePath(); - filterEntry.linkForEditor = Link(path, link.targetLine, link.targetColumn); - const MatchLevel matchLevel = matchLevelFor(match, matchText); - if (hasPathSeparator) { - match = regexp.match(filterEntry.extraInfo); - filterEntry.highlightInfo = - highlightInfo(match, LocatorFilterEntry::HighlightInfo::ExtraInfo); - } else { - filterEntry.highlightInfo = highlightInfo(match); - } - - entries[int(matchLevel)].append(filterEntry); - d->m_current.previousResultPaths.append(path); - } - } - - if (canceled) { - // we keep the old list of previous search results if this search was canceled - // so a later search without forceNewSearchList will use that previous list instead of an - // incomplete list of a canceled search - d->m_current.clear(); // free memory - } else { - d->m_current.iterator.clear(); - QMetaObject::invokeMethod(this, &BaseFileFilter::updatePreviousResultData, - Qt::QueuedConnection); - } - - for (auto &entry : entries) { - if (entry.size() < 1000) - Utils::sort(entry, LocatorFilterEntry::compareLexigraphically); - } - - return std::accumulate(std::begin(entries), std::end(entries), QList()); -} - -/*! - Takes ownership of the \a iterator. The previously set iterator might not be deleted until - a currently running search is finished. -*/ - -void BaseFileFilter::setFileIterator(BaseFileFilter::Iterator *iterator) -{ - d->m_data.clear(); - d->m_data.forceNewSearchList = true; - d->m_data.iterator.reset(iterator); -} - -/*! - Returns the file iterator. -*/ -QSharedPointer BaseFileFilter::fileIterator() -{ - return d->m_data.iterator; -} - -void BaseFileFilter::updatePreviousResultData() -{ - if (d->m_data.forceNewSearchList) // in the meantime the iterator was reset / cache invalidated - return; // do not update with the new result list etc - d->m_data.previousEntry = d->m_current.previousEntry; - d->m_data.previousResultPaths = d->m_current.previousResultPaths; - // forceNewSearchList was already reset in prepareSearch -} - -BaseFileFilter::ListIterator::ListIterator(const FilePaths &filePaths) -{ - m_filePaths = filePaths; - toFront(); -} - -void BaseFileFilter::ListIterator::toFront() -{ - m_pathPosition = m_filePaths.constBegin() - 1; -} - -bool BaseFileFilter::ListIterator::hasNext() const -{ - QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return false); - return m_pathPosition + 1 != m_filePaths.constEnd(); -} - -FilePath BaseFileFilter::ListIterator::next() -{ - QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return {}); - ++m_pathPosition; - QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return {}); - return *m_pathPosition; -} - -FilePath BaseFileFilter::ListIterator::filePath() const -{ - QTC_ASSERT(m_pathPosition != m_filePaths.constEnd(), return {}); - return *m_pathPosition; -} - -} // Core diff --git a/src/plugins/coreplugin/locator/basefilefilter.h b/src/plugins/coreplugin/locator/basefilefilter.h deleted file mode 100644 index 55289e57b0a..00000000000 --- a/src/plugins/coreplugin/locator/basefilefilter.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "ilocatorfilter.h" - -#include - -#include - -namespace Core { - -namespace Internal { class BaseFileFilterPrivate; } - -class CORE_EXPORT BaseFileFilter : public ILocatorFilter -{ - Q_OBJECT - -public: - class CORE_EXPORT Iterator { - public: - virtual ~Iterator(); - virtual void toFront() = 0; - virtual bool hasNext() const = 0; - virtual Utils::FilePath next() = 0; - virtual Utils::FilePath filePath() const = 0; - }; - - class CORE_EXPORT ListIterator final : public Iterator { - public: - ListIterator(const Utils::FilePaths &filePaths); - - void toFront() override; - bool hasNext() const override; - Utils::FilePath next() override; - Utils::FilePath filePath() const override; - - private: - Utils::FilePaths m_filePaths; - Utils::FilePaths::const_iterator m_pathPosition; - }; - - BaseFileFilter(); - ~BaseFileFilter() override; - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; -protected: - void setFileIterator(Iterator *iterator); - QSharedPointer fileIterator(); - -private: - static MatchLevel matchLevelFor(const QRegularExpressionMatch &match, - const QString &matchText); - void updatePreviousResultData(); - - Internal::BaseFileFilterPrivate *d = nullptr; -}; - -} // namespace Core From b4734ff7279284eec4f0ced0e4de07cb348c481e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 12 May 2023 10:59:04 +0200 Subject: [PATCH 1068/1447] Utils: add tests for Position::fromFileName Change-Id: I321b91567e47e08883c7b991cd24d02bb8a9b9c6 Reviewed-by: Jarek Kobus --- src/libs/utils/textutils.cpp | 9 +- src/libs/utils/textutils.h | 2 + tests/auto/utils/filepath/tst_filepath.cpp | 28 +------ tests/auto/utils/text/tst_text.cpp | 95 ++++++++++++++++++++++ 4 files changed, 106 insertions(+), 28 deletions(-) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 8cf7a41ed60..9cb7c1e011f 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -32,7 +32,6 @@ Position Position::fromFileName(QStringView fileName, int &postfixPos) Position pos; if (match.hasMatch()) { postfixPos = match.capturedStart(0); - pos.line = 0; // for the case that there's only a : at the end if (match.lastCapturedIndex() > 0) { pos.line = match.captured(1).toInt(); if (match.lastCapturedIndex() > 2) // index 2 includes the + or : for the column number @@ -44,6 +43,8 @@ Position Position::fromFileName(QStringView fileName, int &postfixPos) if (vsMatch.lastCapturedIndex() > 1) // index 1 includes closing ) pos.line = vsMatch.captured(2).toInt(); } + if (pos.line > 0 && pos.column < 0) + pos.column = 0; // if we got a valid line make sure to return a valid TextPosition return pos; } @@ -264,4 +265,10 @@ void applyReplacements(QTextDocument *doc, const Replacements &replacements) editCursor.endEditBlock(); } +QDebug &operator<<(QDebug &stream, const Position &pos) +{ + stream << "line: " << pos.line << ", column: " << pos.column; + return stream; +} + } // namespace Utils::Text diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index 6ee82274dc8..df1eb73d8eb 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -92,6 +92,8 @@ QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument, QTCREATOR_UTILS_EXPORT QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset); +QTCREATOR_UTILS_EXPORT QDebug &operator<<(QDebug &stream, const Position &pos); + } // Text } // Utils diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index f2ecac2bb6d..3699ec6b2e8 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -1096,36 +1096,10 @@ void tst_filepath::linkFromString_data() QTest::newRow("no-line-no-column") << QString("someFile.txt") << FilePath("someFile.txt") << 0 << -1; - QTest::newRow(": at end") << QString::fromLatin1("someFile.txt:") << FilePath("someFile.txt") - << 0 << -1; - QTest::newRow("+ at end") << QString::fromLatin1("someFile.txt+") << FilePath("someFile.txt") - << 0 << -1; - QTest::newRow(": for column") << QString::fromLatin1("someFile.txt:10:") - << FilePath("someFile.txt") << 10 << -1; - QTest::newRow("+ for column") << QString::fromLatin1("someFile.txt:10+") - << FilePath("someFile.txt") << 10 << -1; - QTest::newRow(": and + at end") - << QString::fromLatin1("someFile.txt:+") << FilePath("someFile.txt") << 0 << -1; - QTest::newRow("empty line") << QString::fromLatin1("someFile.txt:+10") - << FilePath("someFile.txt") << 0 << 9; - QTest::newRow(":line-no-column") << QString::fromLatin1("/some/path/file.txt:42") - << FilePath("/some/path/file.txt") << 42 << -1; - QTest::newRow("+line-no-column") << QString::fromLatin1("/some/path/file.txt+42") - << FilePath("/some/path/file.txt") << 42 << -1; QTest::newRow(":line-:column") << QString::fromLatin1("/some/path/file.txt:42:3") << FilePath("/some/path/file.txt") << 42 << 2; - QTest::newRow(":line-+column") << QString::fromLatin1("/some/path/file.txt:42+33") - << FilePath("/some/path/file.txt") << 42 << 32; - QTest::newRow("+line-:column") << QString::fromLatin1("/some/path/file.txt+142:30") - << FilePath("/some/path/file.txt") << 142 << 29; - QTest::newRow("+line-+column") << QString::fromLatin1("/some/path/file.txt+142+33") - << FilePath("/some/path/file.txt") << 142 << 32; - QTest::newRow("( at end") << QString::fromLatin1("/some/path/file.txt(") - << FilePath("/some/path/file.txt") << 0 << -1; - QTest::newRow("(42 at end") << QString::fromLatin1("/some/path/file.txt(42") - << FilePath("/some/path/file.txt") << 42 << -1; QTest::newRow("(42) at end") << QString::fromLatin1("/some/path/file.txt(42)") - << FilePath("/some/path/file.txt") << 42 << -1; + << FilePath("/some/path/file.txt") << 42 << 0; } void tst_filepath::pathAppended() diff --git a/tests/auto/utils/text/tst_text.cpp b/tests/auto/utils/text/tst_text.cpp index a2e9dc5037b..d683ab3542c 100644 --- a/tests/auto/utils/text/tst_text.cpp +++ b/tests/auto/utils/text/tst_text.cpp @@ -12,10 +12,105 @@ class tst_Text : public QObject Q_OBJECT private slots: + void testPositionFromFileName_data(); + void testPositionFromFileName(); + void testRangeLength_data(); void testRangeLength(); }; +void tst_Text::testPositionFromFileName_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("pos"); + QTest::addColumn("expectedPostfixPos"); + + const QString file("/foo/bar"); + const QString fileWin("C:\\foo\\bar"); + + QTest::newRow("no pos") << file << Position() << -1; + QTest::newRow("no pos win") << fileWin << Position() << -1; + + QTest::newRow("empty:") << file + ":" << Position() << 8; + QTest::newRow("empty: win") << fileWin + ":" << Position() << 10; + + QTest::newRow("empty+") << file + "+" << Position() << 8; + QTest::newRow("empty+ win") << fileWin + "+" << Position() << 10; + + QTest::newRow("empty::") << file + "::" << Position() << 8; + QTest::newRow("empty:: win") << fileWin + "::" << Position() << 10; + + QTest::newRow("empty++") << file + "++" << Position() << 8; + QTest::newRow("empty++ win") << fileWin + "++" << Position() << 10; + + QTest::newRow("line:") << file + ":1" << Position{1, 0} << 8; + QTest::newRow("line: win") << fileWin + ":1" << Position{1, 0} << 10; + + QTest::newRow("line+") << file + "+8" << Position{8, 0} << 8; + QTest::newRow("line+ win") << fileWin + "+8" << Position{8, 0} << 10; + + QTest::newRow("multi digit line:") << file + ":42" << Position{42, 0} << 8; + QTest::newRow("multi digit line: win") << fileWin + ":42" << Position{42, 0} << 10; + + QTest::newRow("multi digit line+") << file + "+1234567890" << Position{1234567890, 0} << 8; + QTest::newRow("multi digit line+ win") + << fileWin + "+1234567890" << Position{1234567890, 0} << 10; + + QTest::newRow("multi digit line+") << file + "+1234567890" << Position{1234567890, 0} << 8; + QTest::newRow("multi digit line+ win") + << fileWin + "+1234567890" << Position{1234567890, 0} << 10; + + QTest::newRow("line: empty column:") << file + ":1:" << Position{1, 0} << 8; + QTest::newRow("line: empty column: win") << fileWin + ":1:" << Position{1, 0} << 10; + + QTest::newRow("line+ empty column+") << file + "+8+" << Position{8, 0} << 8; + QTest::newRow("line+ empty column+ win") << fileWin + "+8+" << Position{8, 0} << 10; + + QTest::newRow("line: column:") << file + ":1:2" << Position{1, 1} << 8; + QTest::newRow("line: column: win") << fileWin + ":1:2" << Position{1, 1} << 10; + + QTest::newRow("line+ column+") << file + "+8+3" << Position{8, 2} << 8; + QTest::newRow("line+ column+ win") << fileWin + "+8+3" << Position{8, 2} << 10; + + QTest::newRow("mixed:+") << file + ":1+2" << Position{1, 1} << 8; + QTest::newRow("mixed:+ win") << fileWin + ":1+2" << Position{1, 1} << 10; + + QTest::newRow("mixed+:") << file + "+8:3" << Position{8, 2} << 8; + QTest::newRow("mixed+: win") << fileWin + "+8:3" << Position{8, 2} << 10; + + QTest::newRow("garbage:") << file + ":foo" << Position() << -1; + QTest::newRow("garbage: win") << fileWin + ":bar" << Position() << -1; + + QTest::newRow("garbage+") << file + "+snu" << Position() << -1; + QTest::newRow("garbage+ win") << fileWin + "+snu" << Position() << -1; + + QTest::newRow("msvc(") << file + "(" << Position() << 8; + QTest::newRow("msvc( win") << fileWin + "(" << Position() << 10; + + QTest::newRow("msvc(empty)") << file + "()" << Position() << -1; + QTest::newRow("msvc(empty) win") << fileWin + "()" << Position() << -1; + + QTest::newRow("msvc(line") << file + "(1" << Position{1, 0} << 8; + QTest::newRow("msvc(line win") << fileWin + "(4569871" << Position{4569871, 0} << 10; + + QTest::newRow("msvc(line)") << file + "(1)" << Position{1, 0} << 8; + QTest::newRow("msvc(line) win") << fileWin + "(4569871)" << Position{4569871, 0} << 10; + + QTest::newRow("msvc(garbage)") << file + "(foo)" << Position() << -1; + QTest::newRow("msvc(garbage) win") << fileWin + "(bar)" << Position() << -1; +} + +void tst_Text::testPositionFromFileName() +{ + QFETCH(QString, fileName); + QFETCH(Position, pos); + QFETCH(int, expectedPostfixPos); + + int postfixPos = -1; + QCOMPARE(Position::fromFileName(fileName, postfixPos), pos); + QCOMPARE(postfixPos, expectedPostfixPos); +} + void tst_Text::testRangeLength_data() { QTest::addColumn("text"); From 23f7352834c1e0c6fb6440766dbb16341ce01ae8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 09:48:03 +0200 Subject: [PATCH 1069/1447] ILocatorFilter: Remove prepareSearch() and matchesFor() Implement matchers() instead. Make matchers() a pure virtual method. Change-Id: I931cb9a5787bc796968cd2123e14d33002169588 Reviewed-by: Eike Ziller --- .../coreplugin/locator/ilocatorfilter.cpp | 33 ------------------- .../coreplugin/locator/ilocatorfilter.h | 11 ++----- src/plugins/modeleditor/elementtasks.cpp | 1 - 3 files changed, 2 insertions(+), 43 deletions(-) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 45ae41c8fdd..1a08792382b 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -592,23 +592,6 @@ QString ILocatorFilter::shortcutString() const return m_shortcut; } -/*! - Performs actions that need to be done in the main thread before actually - running the search for \a entry. - - Called on the main thread before matchesFor() is called in a separate - thread. - - The default implementation does nothing. - - \sa matchesFor() -*/ -void ILocatorFilter::prepareSearch(const QString &entry) -{ - Q_UNUSED(entry) -} - - /*! Sets the refresh recipe for refreshing cached data. */ @@ -1112,22 +1095,6 @@ bool ILocatorFilter::isOldSetting(const QByteArray &state) return !doc.isObject(); } -/*! - \fn QList Core::ILocatorFilter::matchesFor(QFutureInterface &future, const QString &entry) - - Returns the list of results of this filter for the search term \a entry. - This is run in a separate thread, but is guaranteed to only run in a single - thread at any given time. Quickly running preparations can be done in the - GUI thread in prepareSearch(). - - Implementations should do a case sensitive or case insensitive search - depending on caseSensitivity(). If \a future is \c canceled, the search - should be aborted. - - \sa prepareSearch() - \sa caseSensitivity() -*/ - /*! \enum Core::ILocatorFilter::Priority diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index fb70648967e..8a8114743ce 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -18,7 +17,7 @@ QT_BEGIN_NAMESPACE template -class QPromise; +class QFuture; QT_END_NAMESPACE namespace Core { @@ -227,11 +226,6 @@ public: std::optional defaultSearchText() const; void setDefaultSearchText(const QString &defaultSearchText); - virtual void prepareSearch(const QString &entry); - - virtual QList matchesFor(QFutureInterface &, - const QString &) { return {}; }; - virtual QByteArray saveState() const; virtual void restoreState(const QByteArray &state); @@ -281,8 +275,7 @@ protected: static bool isOldSetting(const QByteArray &state); private: - // TODO: Make pure virtual when all subclasses implement it. - virtual LocatorMatcherTasks matchers() { return {}; } + virtual LocatorMatcherTasks matchers() = 0; friend class Internal::Locator; friend class Internal::LocatorWidget; diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp index d54cc2e6c84..6413686f61d 100644 --- a/src/plugins/modeleditor/elementtasks.cpp +++ b/src/plugins/modeleditor/elementtasks.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include From c8c48d899f91e7c9a44389860d7afb8af35eadd0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 25 Apr 2023 10:00:07 +0200 Subject: [PATCH 1070/1447] Locator: Fix style and reuse LocatorFilterEntries Fix names of private members of LocatorModel to have one common style. Reuse LocatorFilterEntries where possible. Change-Id: Icca1e396b9fafd165adf35939dd7859032f90c0c Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- .../coreplugin/locator/locatorfiltertest.cpp | 2 +- .../coreplugin/locator/locatorfiltertest.h | 2 +- .../coreplugin/locator/locatorwidget.cpp | 50 +++++++++---------- src/plugins/cppeditor/cppmodelmanager.cpp | 2 +- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorfiltertest.cpp b/src/plugins/coreplugin/locator/locatorfiltertest.cpp index 2a901f8669e..152ac117336 100644 --- a/src/plugins/coreplugin/locator/locatorfiltertest.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltertest.cpp @@ -30,7 +30,7 @@ bool ResultData::operator==(const ResultData &other) const return textColumn1 == other.textColumn1 && textColumn2 == other.textColumn2 && highlightEqual; } -ResultData::ResultDataList ResultData::fromFilterEntryList(const QList &entries) +ResultData::ResultDataList ResultData::fromFilterEntryList(const LocatorFilterEntries &entries) { ResultDataList result; for (const LocatorFilterEntry &entry : entries) { diff --git a/src/plugins/coreplugin/locator/locatorfiltertest.h b/src/plugins/coreplugin/locator/locatorfiltertest.h index 5003f1e9ff0..2ad18ac2363 100644 --- a/src/plugins/coreplugin/locator/locatorfiltertest.h +++ b/src/plugins/coreplugin/locator/locatorfiltertest.h @@ -21,7 +21,7 @@ public: bool operator==(const ResultData &other) const; - static ResultDataList fromFilterEntryList(const QList &entries); + static ResultDataList fromFilterEntryList(const LocatorFilterEntries &entries); /// For debugging and creating reference data static void printFilterEntries(const ResultDataList &entries, const QString &msg = QString()); diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 6de120b4dc6..28114297dc5 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -57,8 +57,8 @@ public: LocatorModel(QObject *parent = nullptr) : QAbstractListModel(parent) - , mBackgroundColor(Utils::creatorTheme()->color(Utils::Theme::TextColorHighlightBackground)) - , mForegroundColor(Utils::creatorTheme()->color(Utils::Theme::TextColorNormal)) + , m_backgroundColor(Utils::creatorTheme()->color(Utils::Theme::TextColorHighlightBackground)) + , m_foregroundColor(Utils::creatorTheme()->color(Utils::Theme::TextColorNormal)) {} void clear(); @@ -66,13 +66,13 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - void addEntries(const QList &entries); + void addEntries(const LocatorFilterEntries &entries); private: - mutable QList mEntries; - bool hasExtraInfo = false; - QColor mBackgroundColor; - QColor mForegroundColor; + mutable LocatorFilterEntries m_entries; + bool m_hasExtraInfo = false; + QColor m_backgroundColor; + QColor m_foregroundColor; }; class CompletionDelegate : public HighlightingItemDelegate @@ -134,8 +134,8 @@ protected: void LocatorModel::clear() { beginResetModel(); - mEntries.clear(); - hasExtraInfo = false; + m_entries.clear(); + m_hasExtraInfo = false; endResetModel(); } @@ -143,30 +143,30 @@ int LocatorModel::rowCount(const QModelIndex & parent) const { if (parent.isValid()) return 0; - return mEntries.size(); + return m_entries.size(); } int LocatorModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; - return hasExtraInfo ? ColumnCount : 1; + return m_hasExtraInfo ? ColumnCount : 1; } QVariant LocatorModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.row() >= mEntries.size()) + if (!index.isValid() || index.row() >= m_entries.size()) return QVariant(); switch (role) { case Qt::DisplayRole: if (index.column() == DisplayNameColumn) - return mEntries.at(index.row()).displayName; + return m_entries.at(index.row()).displayName; else if (index.column() == ExtraInfoColumn) - return mEntries.at(index.row()).extraInfo; + return m_entries.at(index.row()).extraInfo; break; case Qt::ToolTipRole: { - const LocatorFilterEntry &entry = mEntries.at(index.row()); + const LocatorFilterEntry &entry = m_entries.at(index.row()); QString toolTip = entry.displayName; if (!entry.extraInfo.isEmpty()) toolTip += "\n\n" + entry.extraInfo; @@ -176,7 +176,7 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const } case Qt::DecorationRole: if (index.column() == DisplayNameColumn) { - LocatorFilterEntry &entry = mEntries[index.row()]; + LocatorFilterEntry &entry = m_entries[index.row()]; if (!entry.displayIcon && !entry.filePath.isEmpty()) entry.displayIcon = FileIconProvider::icon(entry.filePath); return entry.displayIcon ? entry.displayIcon.value() : QIcon(); @@ -187,10 +187,10 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const return QColor(Qt::darkGray); break; case LocatorEntryRole: - return QVariant::fromValue(mEntries.at(index.row())); + return QVariant::fromValue(m_entries.at(index.row())); case int(HighlightingItemRole::StartColumn): case int(HighlightingItemRole::Length): { - const LocatorFilterEntry &entry = mEntries[index.row()]; + const LocatorFilterEntry &entry = m_entries[index.row()]; auto highlights = [&](LocatorFilterEntry::HighlightInfo::DataType type){ const bool startIndexRole = role == int(HighlightingItemRole::StartColumn); return startIndexRole ? QVariant::fromValue(entry.highlightInfo.starts(type)) @@ -204,7 +204,7 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const } case int(HighlightingItemRole::DisplayExtra): { if (index.column() == LocatorFilterEntry::HighlightInfo::DisplayName) { - LocatorFilterEntry &entry = mEntries[index.row()]; + LocatorFilterEntry &entry = m_entries[index.row()]; if (!entry.displayExtra.isEmpty()) return QString(" (" + entry.displayExtra + ')'); } @@ -213,9 +213,9 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const case int(HighlightingItemRole::DisplayExtraForeground): return QColor(Qt::darkGray); case int(HighlightingItemRole::Background): - return mBackgroundColor; + return m_backgroundColor; case int(HighlightingItemRole::Foreground): - return mForegroundColor; + return m_foregroundColor; } return QVariant(); @@ -223,14 +223,14 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const void LocatorModel::addEntries(const QList &entries) { - beginInsertRows(QModelIndex(), mEntries.size(), mEntries.size() + entries.size() - 1); - mEntries.append(entries); + beginInsertRows(QModelIndex(), m_entries.size(), m_entries.size() + entries.size() - 1); + m_entries.append(entries); endInsertRows(); - if (hasExtraInfo) + if (m_hasExtraInfo) return; if (Utils::anyOf(entries, [](const LocatorFilterEntry &e) { return !e.extraInfo.isEmpty();})) { beginInsertColumns(QModelIndex(), 1, 1); - hasExtraInfo = true; + m_hasExtraInfo = true; endInsertColumns(); } } diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 0de793bfc4e..07b4e67d270 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -556,7 +556,7 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder) return; } Links links; - const auto entries = matcher->outputData(); + const LocatorFilterEntries entries = matcher->outputData(); for (const LocatorFilterEntry &entry : entries) { static const QStringList prefixBlacklist{"main(", "~", "qHash(", "begin()", "end()", "cbegin()", "cend()", "constBegin()", "constEnd()"}; From 4195b4e7e2b0da842f043233074c5a479450691d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 19:05:23 +0200 Subject: [PATCH 1071/1447] ILocatorFilter: Remove calls to setDefaultIncludedByDefault(false) By default, setDefaultIncludedByDefault() is set to false, so no need to repeat it now in direct subclasses. Leave it only inside the AllProjectFilesFilter, as the DirectoryFilter superclass sets it to true. Change-Id: Ib66d112a3bfeed52315663f6898148cf5c5d88b1 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/clangcodemodel/clangdlocatorfilters.cpp | 4 ---- src/plugins/coreplugin/locator/executefilter.cpp | 1 - src/plugins/coreplugin/locator/filesystemfilter.cpp | 1 - src/plugins/coreplugin/locator/javascriptfilter.cpp | 1 - src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp | 1 - src/plugins/coreplugin/locator/urllocatorfilter.cpp | 1 - src/plugins/cppeditor/cpplocatorfilter.cpp | 4 ---- src/plugins/help/helpindexfilter.cpp | 1 - src/plugins/languageclient/locatorfilter.cpp | 2 -- src/plugins/projectexplorer/currentprojectfilter.cpp | 1 - src/plugins/qmljstools/qmljsfunctionfilter.cpp | 1 - 11 files changed, 18 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index 6d3ab92e144..f783a98499a 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -37,7 +37,6 @@ ClangdAllSymbolsFilter::ClangdAllSymbolsFilter() setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::LOCATOR_FILTER_DISPLAY_NAME)); setDescription(::CppEditor::Tr::tr(CppEditor::Constants::LOCATOR_FILTER_DESCRIPTION)); setDefaultShortcutString(":"); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks ClangdAllSymbolsFilter::matchers() @@ -53,7 +52,6 @@ ClangdClassesFilter::ClangdClassesFilter() setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::CLASSES_FILTER_DISPLAY_NAME)); setDescription(::CppEditor::Tr::tr(CppEditor::Constants::CLASSES_FILTER_DESCRIPTION)); setDefaultShortcutString("c"); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks ClangdClassesFilter::matchers() @@ -69,7 +67,6 @@ ClangdFunctionsFilter::ClangdFunctionsFilter() setDisplayName(::CppEditor::Tr::tr(CppEditor::Constants::FUNCTIONS_FILTER_DISPLAY_NAME)); setDescription(::CppEditor::Tr::tr(CppEditor::Constants::FUNCTIONS_FILTER_DESCRIPTION)); setDefaultShortcutString("m"); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks ClangdFunctionsFilter::matchers() @@ -86,7 +83,6 @@ ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() setDescription(::CppEditor::Tr::tr(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_DESCRIPTION)); setDefaultShortcutString("."); setPriority(High); - setDefaultIncludedByDefault(false); setEnabled(false); connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, [this](const IEditor *editor) { setEnabled(editor); }); diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 2225508ae4b..2a405c369ea 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -31,7 +31,6 @@ ExecuteFilter::ExecuteFilter() "environment variable if needed. Note that the command is run directly, not in a shell.")); setDefaultShortcutString("!"); setPriority(High); - setDefaultIncludedByDefault(false); } ExecuteFilter::~ExecuteFilter() diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index e1d45afeb3f..066be68330c 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -127,7 +127,6 @@ FileSystemFilter::FileSystemFilter() "path. \"~\" refers to your home directory. You have the option to create a " "file if it does not exist yet.")); setDefaultShortcutString("f"); - setDefaultIncludedByDefault(false); *sDeviceRootIcon = qApp->style()->standardIcon(QStyle::SP_DriveHDIcon); } diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 0a155e85500..ea5a832c984 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -359,7 +359,6 @@ JavaScriptFilter::JavaScriptFilter() setId("JavaScriptFilter"); setDisplayName(Tr::tr("Evaluate JavaScript")); setDescription(Tr::tr("Evaluates arbitrary JavaScript expressions and copies the result.")); - setDefaultIncludedByDefault(false); setDefaultShortcutString("="); } diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index 167a24be8ad..e2f077a5659 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -102,7 +102,6 @@ SpotlightLocatorFilter::SpotlightLocatorFilter() { setId("SpotlightFileNamesLocatorFilter"); setDefaultShortcutString("md"); - setDefaultIncludedByDefault(false); setDisplayName(Tr::tr("File Name Index")); setDescription(Tr::tr( "Locates files from a global file system index (Spotlight, Locate, Everything). Append " diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index d00eb7a21fe..c9025b2237a 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -159,7 +159,6 @@ UrlLocatorFilter::UrlLocatorFilter(const QString &displayName, Id id) setId(id); m_defaultDisplayName = displayName; setDisplayName(displayName); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks UrlLocatorFilter::matchers() diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 5f0904dd035..cd1add7786e 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -338,7 +338,6 @@ CppAllSymbolsFilter::CppAllSymbolsFilter() setDisplayName(Tr::tr(Constants::LOCATOR_FILTER_DISPLAY_NAME)); setDescription(Tr::tr(Constants::LOCATOR_FILTER_DESCRIPTION)); setDefaultShortcutString(":"); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks CppAllSymbolsFilter::matchers() @@ -353,7 +352,6 @@ CppClassesFilter::CppClassesFilter() setDisplayName(Tr::tr(Constants::CLASSES_FILTER_DISPLAY_NAME)); setDescription(Tr::tr(Constants::CLASSES_FILTER_DESCRIPTION)); setDefaultShortcutString("c"); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks CppClassesFilter::matchers() @@ -367,7 +365,6 @@ CppFunctionsFilter::CppFunctionsFilter() setDisplayName(Tr::tr(Constants::FUNCTIONS_FILTER_DISPLAY_NAME)); setDescription(Tr::tr(Constants::FUNCTIONS_FILTER_DESCRIPTION)); setDefaultShortcutString("m"); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks CppFunctionsFilter::matchers() @@ -382,7 +379,6 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter() setDescription(Tr::tr(Constants::CURRENT_DOCUMENT_FILTER_DESCRIPTION)); setDefaultShortcutString("."); setPriority(High); - setDefaultIncludedByDefault(false); } LocatorMatcherTasks CppCurrentDocumentFilter::matchers() diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index c32f02c6c16..9da19214801 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -29,7 +29,6 @@ HelpIndexFilter::HelpIndexFilter() setId("HelpIndexFilter"); setDisplayName(Tr::tr("Help Index")); setDescription(Tr::tr("Locates help topics, for example in the Qt documentation.")); - setDefaultIncludedByDefault(false); setDefaultShortcutString("?"); setRefreshRecipe(Sync([this] { invalidateCache(); })); diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 04caf2d1723..da03b2e7c50 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -175,7 +175,6 @@ LanguageCurrentDocumentFilter::LanguageCurrentDocumentFilter() setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DISPLAY_NAME)); setDescription(Tr::tr(Constants::LANGUAGECLIENT_DOCUMENT_FILTER_DESCRIPTION)); setDefaultShortcutString("."); - setDefaultIncludedByDefault(false); setPriority(ILocatorFilter::Low); } @@ -253,7 +252,6 @@ LanguageAllSymbolsFilter::LanguageAllSymbolsFilter() setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_DISPLAY_NAME)); setDescription(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_DESCRIPTION)); setDefaultShortcutString(":"); - setDefaultIncludedByDefault(false); setPriority(ILocatorFilter::Low); } diff --git a/src/plugins/projectexplorer/currentprojectfilter.cpp b/src/plugins/projectexplorer/currentprojectfilter.cpp index d42ab82e968..d0f9ed99b0a 100644 --- a/src/plugins/projectexplorer/currentprojectfilter.cpp +++ b/src/plugins/projectexplorer/currentprojectfilter.cpp @@ -20,7 +20,6 @@ CurrentProjectFilter::CurrentProjectFilter() "or \":\" to jump to the given line number. Append another " "\"+\" or \":\" to jump to the column number as well.")); setDefaultShortcutString("p"); - setDefaultIncludedByDefault(false); setRefreshRecipe(Tasking::Sync([this] { invalidate(); })); connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 293e8962f48..34a60040f3c 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -25,7 +25,6 @@ QmlJSFunctionsFilter::QmlJSFunctionsFilter(LocatorData *data) setDisplayName(Tr::tr("QML Functions")); setDescription(Tr::tr("Locates QML functions in any open project.")); setDefaultShortcutString("m"); - setDefaultIncludedByDefault(false); } static void matches(QPromise &promise, const LocatorStorage &storage, From 8b2d7977ca74c09e12d235d16a5c6473e60e9961 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 15 May 2023 14:04:34 +0200 Subject: [PATCH 1072/1447] Utils: Make CTAD work with std::unexpected Aliases are not working with CTAD before C++ 20. Instead of aliasing some types we simply importing the namespace tl into the namespace Utils. This enables some not aliased things too. Change-Id: Ic61a50bedbbf7253ecb5bb1f6dc0624dcc704aa0 Reviewed-by: Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/utils/expected.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/libs/utils/expected.h b/src/libs/utils/expected.h index 943cfe5591f..33231c1246e 100644 --- a/src/libs/utils/expected.h +++ b/src/libs/utils/expected.h @@ -9,24 +9,11 @@ namespace Utils { -template -using expected = tl::expected; +using namespace tl; template using expected_str = tl::expected; -template -using unexpected = tl::unexpected; -using unexpect_t = tl::unexpect_t; - -static constexpr unexpect_t unexpect{}; - -template -constexpr unexpected> make_unexpected(E &&e) -{ - return tl::make_unexpected(e); -} - } // namespace Utils //! If 'expected' has an error the error will be printed and the 'action' will be executed. From 479d7e3732526e60e52d74dcf95f55c3c5aa7b48 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 16 May 2023 10:41:44 +0200 Subject: [PATCH 1073/1447] Utils: remove duplicated test Change-Id: I0391feb848af09295afd9d3e84e25337023c24b6 Reviewed-by: Jarek Kobus --- tests/auto/utils/text/tst_text.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/auto/utils/text/tst_text.cpp b/tests/auto/utils/text/tst_text.cpp index d683ab3542c..013c1d46c7c 100644 --- a/tests/auto/utils/text/tst_text.cpp +++ b/tests/auto/utils/text/tst_text.cpp @@ -52,10 +52,6 @@ void tst_Text::testPositionFromFileName_data() QTest::newRow("multi digit line:") << file + ":42" << Position{42, 0} << 8; QTest::newRow("multi digit line: win") << fileWin + ":42" << Position{42, 0} << 10; - QTest::newRow("multi digit line+") << file + "+1234567890" << Position{1234567890, 0} << 8; - QTest::newRow("multi digit line+ win") - << fileWin + "+1234567890" << Position{1234567890, 0} << 10; - QTest::newRow("multi digit line+") << file + "+1234567890" << Position{1234567890, 0} << 8; QTest::newRow("multi digit line+ win") << fileWin + "+1234567890" << Position{1234567890, 0} << 10; From 2bf5cc81b5188be01a38d699b9a34cea2e2dd3d9 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 16 May 2023 10:37:01 +0200 Subject: [PATCH 1074/1447] Haskell: Build with Qbs as well Change-Id: Ia8f9fd3c22acc50c149594859a0471b0e58fc027 Reviewed-by: Christian Kandeler Reviewed-by: Eike Ziller --- src/plugins/plugins.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 48b0825430c..b199706481e 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -44,6 +44,7 @@ Project { "git/git.qbs", "gitlab/gitlab.qbs", "glsleditor/glsleditor.qbs", + "haskell/haskell.qbs", "helloworld/helloworld.qbs", "help/help.qbs", "imageviewer/imageviewer.qbs", From 1512aaa0cd3e7ed4953d465988372886483a4e40 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 1 May 2023 10:18:19 +0300 Subject: [PATCH 1075/1447] Build: Avoid passing unsupported flag to MSVC linker Change-Id: Ia73aeccb824bca10ce928cb82d5ad77033521527 Reviewed-by: Cristian Adam --- cmake/QtCreatorAPIInternal.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index bbb4db462e7..ecb6d17f360 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -182,7 +182,7 @@ endfunction() function(qtc_add_link_flags_no_undefined target) # needs CheckLinkerFlags - if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18) + if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18 AND NOT MSVC) set(no_undefined_flag "-Wl,--no-undefined") check_linker_flag(CXX ${no_undefined_flag} QTC_LINKER_SUPPORTS_NO_UNDEFINED) if (NOT QTC_LINKER_SUPPORTS_NO_UNDEFINED) From b8a56abb22eb4895b9ef50cfc0bbf70fdff58a24 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 10 May 2023 17:35:59 +0200 Subject: [PATCH 1076/1447] LocatorWidget: Drop Utils namespace qualifier Change-Id: Ife0fb3a5908326136531801c6d8e372ed10827a4 Reviewed-by: Eike Ziller --- .../coreplugin/locator/locatorwidget.cpp | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 28114297dc5..8af3f4b753d 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -57,8 +57,8 @@ public: LocatorModel(QObject *parent = nullptr) : QAbstractListModel(parent) - , m_backgroundColor(Utils::creatorTheme()->color(Utils::Theme::TextColorHighlightBackground)) - , m_foregroundColor(Utils::creatorTheme()->color(Utils::Theme::TextColorNormal)) + , m_backgroundColor(Utils::creatorTheme()->color(Theme::TextColorHighlightBackground)) + , m_foregroundColor(Utils::creatorTheme()->color(Theme::TextColorNormal)) {} void clear(); @@ -83,7 +83,7 @@ public: QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; -class CompletionList : public Utils::TreeView +class CompletionList : public TreeView { public: CompletionList(QWidget *parent = nullptr); @@ -238,7 +238,7 @@ void LocatorModel::addEntries(const QList &entries) // =========== CompletionList =========== CompletionList::CompletionList(QWidget *parent) - : Utils::TreeView(parent) + : TreeView(parent) { // on macOS and Windows the popup doesn't really get focus, so fake the selection color // which would then just be a very light gray, but should look as if it had focus @@ -255,7 +255,7 @@ CompletionList::CompletionList(QWidget *parent) header()->setStretchLastSection(true); // This is too slow when done on all results //header()->setSectionResizeMode(QHeaderView::ResizeToContents); - if (Utils::HostOsInfo::isMacHost()) { + if (HostOsInfo::isMacHost()) { if (horizontalScrollBar()) horizontalScrollBar()->setAttribute(Qt::WA_MacMiniSize); if (verticalScrollBar()) @@ -406,7 +406,7 @@ LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent) m_tree(new CompletionList(this)), m_inputWidget(locatorWidget) { - if (Utils::HostOsInfo::isMacHost()) + if (HostOsInfo::isMacHost()) m_tree->setFrameStyle(QFrame::NoFrame); // tool tip already includes a frame m_tree->setModel(locatorWidget->model()); m_tree->setTextElideMode(Qt::ElideMiddle); @@ -500,7 +500,7 @@ void CompletionList::keyPressEvent(QKeyEvent *event) return; case Qt::Key_P: case Qt::Key_N: - if (event->modifiers() == Qt::KeyboardModifiers(Utils::HostOsInfo::controlModifier())) { + if (event->modifiers() == Qt::KeyboardModifiers(HostOsInfo::controlModifier())) { if (event->key() == Qt::Key_P) previous(); else @@ -519,7 +519,7 @@ void CompletionList::keyPressEvent(QKeyEvent *event) } break; } - Utils::TreeView::keyPressEvent(event); + TreeView::keyPressEvent(event); } bool CompletionList::eventFilter(QObject *watched, QEvent *event) @@ -535,14 +535,14 @@ bool CompletionList::eventFilter(QObject *watched, QEvent *event) break; case Qt::Key_P: case Qt::Key_N: - if (ke->modifiers() == Qt::KeyboardModifiers(Utils::HostOsInfo::controlModifier())) { + if (ke->modifiers() == Qt::KeyboardModifiers(HostOsInfo::controlModifier())) { event->accept(); return true; } break; } } - return Utils::TreeView::eventFilter(watched, event); + return TreeView::eventFilter(watched, event); } // =========== LocatorWidget =========== @@ -553,7 +553,7 @@ LocatorWidget::LocatorWidget(Locator *locator) , m_centeredPopupAction(new QAction(Tr::tr("Open as Centered Popup"), this)) , m_refreshAction(new QAction(Tr::tr("Refresh"), this)) , m_configureAction(new QAction(ICore::msgShowOptionsDialog(), this)) - , m_fileLineEdit(new Utils::FancyLineEdit) + , m_fileLineEdit(new FancyLineEdit) { setAttribute(Qt::WA_Hover); setFocusProxy(m_fileLineEdit); @@ -571,12 +571,12 @@ LocatorWidget::LocatorWidget(Locator *locator) const QIcon icon = Utils::Icons::MAGNIFIER.icon(); m_fileLineEdit->setFiltering(true); - m_fileLineEdit->setButtonIcon(Utils::FancyLineEdit::Left, icon); - m_fileLineEdit->setButtonToolTip(Utils::FancyLineEdit::Left, Tr::tr("Options")); + m_fileLineEdit->setButtonIcon(FancyLineEdit::Left, icon); + m_fileLineEdit->setButtonToolTip(FancyLineEdit::Left, Tr::tr("Options")); m_fileLineEdit->setFocusPolicy(Qt::ClickFocus); - m_fileLineEdit->setButtonVisible(Utils::FancyLineEdit::Left, true); + m_fileLineEdit->setButtonVisible(FancyLineEdit::Left, true); // We set click focus since otherwise you will always get two popups - m_fileLineEdit->setButtonFocusPolicy(Utils::FancyLineEdit::Left, Qt::ClickFocus); + m_fileLineEdit->setButtonFocusPolicy(FancyLineEdit::Left, Qt::ClickFocus); m_fileLineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); m_fileLineEdit->installEventFilter(this); @@ -602,7 +602,7 @@ LocatorWidget::LocatorWidget(Locator *locator) m_filterMenu->addAction(m_refreshAction); m_filterMenu->addAction(m_configureAction); - m_fileLineEdit->setButtonMenu(Utils::FancyLineEdit::Left, m_filterMenu); + m_fileLineEdit->setButtonMenu(FancyLineEdit::Left, m_filterMenu); connect(m_refreshAction, &QAction::triggered, locator, [locator] { locator->refresh(Locator::filters()); @@ -610,8 +610,7 @@ LocatorWidget::LocatorWidget(Locator *locator) connect(m_configureAction, &QAction::triggered, this, &LocatorWidget::showConfigureDialog); connect(m_fileLineEdit, &QLineEdit::textChanged, this, &LocatorWidget::showPopupNow); - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Small, - m_fileLineEdit); + m_progressIndicator = new ProgressIndicator(ProgressIndicatorSize::Small, m_fileLineEdit); m_progressIndicator->raise(); m_progressIndicator->hide(); m_showProgressTimer.setSingleShot(true); @@ -648,11 +647,10 @@ void LocatorWidget::updatePlaceholderText(Command *command) void LocatorWidget::updateFilterList() { m_filterMenu->clear(); - const QList filters = Utils::sorted(Locator::filters(), - [](ILocatorFilter *a, ILocatorFilter *b) { - return a->displayName() - < b->displayName(); - }); + const QList filters = Utils::sorted( + Locator::filters(), [](ILocatorFilter *a, ILocatorFilter *b) { + return a->displayName() < b->displayName(); + }); for (ILocatorFilter *filter : filters) { if (filter->shortcutString().isEmpty() || filter->isHidden()) continue; @@ -701,7 +699,7 @@ bool LocatorWidget::eventFilter(QObject *obj, QEvent *event) switch (keyEvent->key()) { case Qt::Key_P: case Qt::Key_N: - if (keyEvent->modifiers() == Qt::KeyboardModifiers(Utils::HostOsInfo::controlModifier())) { + if (keyEvent->modifiers() == Qt::KeyboardModifiers(HostOsInfo::controlModifier())) { event->accept(); return true; } @@ -758,7 +756,7 @@ bool LocatorWidget::eventFilter(QObject *obj, QEvent *event) return true; case Qt::Key_Home: case Qt::Key_End: - if (Utils::HostOsInfo::isMacHost() + if (HostOsInfo::isMacHost() != (keyEvent->modifiers() == Qt::KeyboardModifiers(Qt::ControlModifier))) { emit showPopup(); emit handleKey(keyEvent); @@ -780,7 +778,7 @@ bool LocatorWidget::eventFilter(QObject *obj, QEvent *event) break; case Qt::Key_P: case Qt::Key_N: - if (keyEvent->modifiers() == Qt::KeyboardModifiers(Utils::HostOsInfo::controlModifier())) { + if (keyEvent->modifiers() == Qt::KeyboardModifiers(HostOsInfo::controlModifier())) { emit showPopup(); emit handleKey(keyEvent); return true; @@ -873,7 +871,7 @@ void LocatorWidget::setProgressIndicatorVisible(bool visible) return; } const QSize iconSize = m_progressIndicator->sizeHint(); - m_progressIndicator->setGeometry(m_fileLineEdit->button(Utils::FancyLineEdit::Right)->geometry().x() + m_progressIndicator->setGeometry(m_fileLineEdit->button(FancyLineEdit::Right)->geometry().x() - iconSize.width(), (m_fileLineEdit->height() - iconSize.height()) / 2 /*center*/, iconSize.width(), From 00d8e9d7179fa5feecdd058dd9a705832bfa3cb5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 19:18:14 +0200 Subject: [PATCH 1077/1447] SpotlightLocatorFilter: Remove no-op call to setConfigurable(true) Change-Id: Iafc9b1f3f7e0e5e214b44ab29bbd2537a0bbb569 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp index e2f077a5659..64ea71998b7 100644 --- a/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/spotlightlocatorfilter.cpp @@ -107,7 +107,6 @@ SpotlightLocatorFilter::SpotlightLocatorFilter() "Locates files from a global file system index (Spotlight, Locate, Everything). Append " "\"+\" or \":\" to jump to the given line number. Append another " "\"+\" or \":\" to jump to the column number as well.")); - setConfigurable(true); m_command = defaultCommand(); m_arguments = defaultArguments(); m_caseSensitiveArguments = defaultArguments(Qt::CaseSensitive); From 9758e7145828e1303a33af3b1ae04c4210b55a28 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 12 May 2023 10:59:29 +0200 Subject: [PATCH 1078/1447] Utils: add tests for Position::fromPositionInDocument Change-Id: I2b530cf62a4defe0292c51834b1e5093a7d5e55f Reviewed-by: Reviewed-by: Jarek Kobus Reviewed-by: Qt CI Bot --- src/libs/utils/textutils.cpp | 2 ++ tests/auto/utils/text/tst_text.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 9cb7c1e011f..a57e5310593 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "textutils.h" +#include "qtcassert.h" #include #include @@ -50,6 +51,7 @@ Position Position::fromFileName(QStringView fileName, int &postfixPos) Position Position::fromPositionInDocument(const QTextDocument *document, int pos) { + QTC_ASSERT(document, return {}); const QTextBlock block = document->findBlock(pos); if (block.isValid()) return {block.blockNumber() + 1, pos - block.position()}; diff --git a/tests/auto/utils/text/tst_text.cpp b/tests/auto/utils/text/tst_text.cpp index 013c1d46c7c..3428b0b7576 100644 --- a/tests/auto/utils/text/tst_text.cpp +++ b/tests/auto/utils/text/tst_text.cpp @@ -3,6 +3,7 @@ #include +#include #include using namespace Utils::Text; @@ -15,6 +16,9 @@ private slots: void testPositionFromFileName_data(); void testPositionFromFileName(); + void testPositionFromPositionInDocument_data(); + void testPositionFromPositionInDocument(); + void testRangeLength_data(); void testRangeLength(); }; @@ -107,6 +111,30 @@ void tst_Text::testPositionFromFileName() QCOMPARE(postfixPos, expectedPostfixPos); } +void tst_Text::testPositionFromPositionInDocument_data() +{ + QTest::addColumn("text"); + QTest::addColumn("documentPosition"); + QTest::addColumn("position"); + + QTest::newRow("0") << QString() << 0 << Position{1, 0}; + QTest::newRow("-1") << QString() << -1 << Position(); + QTest::newRow("mid line") << QString("foo\n") << 1 << Position{1, 1}; + QTest::newRow("second line") << QString("foo\n") << 4 << Position{2, 0}; + QTest::newRow("second mid line") << QString("foo\nbar") << 5 << Position{2, 1}; + QTest::newRow("behind content") << QString("foo\nbar") << 8 << Position(); +} + +void tst_Text::testPositionFromPositionInDocument() +{ + QFETCH(QString, text); + QFETCH(int, documentPosition); + QFETCH(Position, position); + + const QTextDocument doc(text); + QCOMPARE(Position::fromPositionInDocument(&doc, documentPosition), position); +} + void tst_Text::testRangeLength_data() { QTest::addColumn("text"); From 7869c4e8103d1ba6e71b683e94ed7ae8dd04b8c0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 11 May 2023 13:16:27 +0200 Subject: [PATCH 1079/1447] CppEditor: Add quickfix for creating a member function from use Fixes: QTCREATORBUG-10356 Change-Id: If7376e766f2817949259591560c74bd6fb0e0cd6 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfix_test.cpp | 116 ++++++++++ src/plugins/cppeditor/cppquickfixes.cpp | 253 +++++++++++++++------ src/plugins/cppeditor/cppquickfixes.h | 15 +- 3 files changed, 311 insertions(+), 73 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index e78667c2fb5..f57670c1611 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -3968,6 +3968,122 @@ void QuickfixTest::testInsertMemberFromUse_data() "};\n" "void C::setValue(int v) { @m_value = v; }\n"; QTest::addRow("add static member to this (non-inline)") << original << expected; + + original = + "struct S {\n\n};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.@setValue(v); }\n" + "private:\n" + " S m_s;\n" + "};\n"; + expected = + "struct S {\n\n" + " void setValue(int);\n" + "};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.setValue(v); }\n" + "private:\n" + " S m_s;\n" + "};\n"; + QTest::addRow("add member function to other struct") << original << expected; + + original = + "struct S {\n\n};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { S::@setValue(v); }\n" + "};\n"; + expected = + "struct S {\n\n" + " static void setValue(int);\n" + "};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { S::setValue(v); }\n" + "};\n"; + QTest::addRow("add static member function to other struct (explicit)") << original << expected; + + original = + "struct S {\n\n};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.@setValue(v); }\n" + "private:\n" + " static S m_s;\n" + "};\n"; + expected = + "struct S {\n\n" + " static void setValue(int);\n" + "};\n" + "class C {\n" + "public:\n" + " void setValue(int v) { m_s.setValue(v); }\n" + "private:\n" + " static S m_s;\n" + "};\n"; + QTest::addRow("add static member function to other struct (implicit)") << original << expected; + + original = + "class C {\n" + "public:\n" + " void setValue(int v);\n" + "};\n" + "void C::setValue(int v) { this->@setValueInternal(v); }\n"; + expected = + "class C {\n" + "public:\n" + " void setValue(int v);\n" + "private:\n" + " void setValueInternal(int);\n" + "};\n" + "void C::setValue(int v) { this->setValueInternal(v); }\n"; + QTest::addRow("add member function to this (explicit)") << original << expected; + + original = + "class C {\n" + "public:\n" + " void setValue(int v) { @setValueInternal(v); }\n" + "};\n"; + expected = + "class C {\n" + "public:\n" + " void setValue(int v) { setValueInternal(v); }\n" + "private:\n" + " void setValueInternal(int);\n" + "};\n"; + QTest::addRow("add member function to this (implicit)") << original << expected; + + original = + "class C {\n" + "public:\n" + " static int value() { int i = @valueInternal(); return i; }\n" + "};\n"; + expected = + "class C {\n" + "public:\n" + " static int value() { int i = @valueInternal(); return i; }\n" + "private:\n" + " static int valueInternal();\n" + "};\n"; + QTest::addRow("add static member function to this (inline)") << original << expected; + + original = + "class C {\n" + "public:\n" + " static int value();\n" + "};\n" + "int C::value() { return @valueInternal(); }\n"; + expected = + "class C {\n" + "public:\n" + " static int value();\n" + "private:\n" + " static int valueInternal();\n" + "};\n" + "int C::value() { return valueInternal(); }\n"; + QTest::addRow("add static member function to this (non-inline)") << original << expected; } void QuickfixTest::testInsertMemberFromUse() diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 60d799cb5f4..85489b877e7 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -308,11 +308,14 @@ QString nameString(const NameAST *name) return CppCodeStyleSettings::currentProjectCodeStyleOverview().prettyName(name->name); } -QString declFromExpr(const ExpressionAST *expr, const NameAST *varName, +// FIXME: Needs to consider the scope at the insertion site. +QString declFromExpr(const TypeOrExpr &typeOrExpr, const CallAST *call, const NameAST *varName, const Snapshot &snapshot, const LookupContext &context, const CppRefactoringFilePtr &file) { - const auto getTypeFromUser = [varName]() -> QString { + const auto getTypeFromUser = [varName, call]() -> QString { + if (call) + return {}; const QString typeFromUser = QInputDialog::getText(Core::ICore::dialogParent(), Tr::tr("Provide the type"), Tr::tr("Data type:"), QLineEdit::Normal); @@ -320,29 +323,42 @@ QString declFromExpr(const ExpressionAST *expr, const NameAST *varName, return typeFromUser + ' ' + nameString(varName); return {}; }; + const auto getTypeOfExpr = [&](const ExpressionAST *expr) -> FullySpecifiedType { + TypeOfExpression typeOfExpression; + typeOfExpression.init(file->cppDocument(), snapshot, context.bindings()); + Scope *scope = file->scopeAt(expr->firstToken()); + const QList result = typeOfExpression( + file->textOf(expr).toUtf8(), scope, TypeOfExpression::Preprocess); + if (result.isEmpty()) + return {}; - TypeOfExpression typeOfExpression; - typeOfExpression.init(file->cppDocument(), snapshot, context.bindings()); - Scope *scope = file->scopeAt(expr->firstToken()); - const QList result = typeOfExpression( - file->textOf(expr).toUtf8(), scope, TypeOfExpression::Preprocess); - if (result.isEmpty()) - return getTypeFromUser(); + SubstitutionEnvironment env; + env.setContext(context); + env.switchScope(result.first().scope()); + ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); + if (!con) + con = typeOfExpression.context().globalNamespace(); + UseMinimalNames q(con); + env.enter(&q); - SubstitutionEnvironment env; - env.setContext(context); - env.switchScope(result.first().scope()); - ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); - if (!con) - con = typeOfExpression.context().globalNamespace(); - UseMinimalNames q(con); - env.enter(&q); + Control *control = context.bindings()->control().data(); + return rewriteType(result.first().type(), &env, control); + }; - Control *control = context.bindings()->control().data(); - FullySpecifiedType tn = rewriteType(result.first().type(), &env, control); - if (!tn.isValid()) - return getTypeFromUser(); - return CppCodeStyleSettings::currentProjectCodeStyleOverview().prettyType(tn, varName->name); + const Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); + const FullySpecifiedType type = std::holds_alternative(typeOrExpr) + ? std::get(typeOrExpr) + : getTypeOfExpr(std::get(typeOrExpr)); + if (!call) + return type.isValid() ? oo.prettyType(type, varName->name) : getTypeFromUser(); + + Function func(file->cppDocument()->translationUnit(), 0, varName->name); + for (ExpressionListAST *it = call->expression_list; it; it = it->next) { + Argument * const arg = new Argument(nullptr, 0, nullptr); + arg->setType(getTypeOfExpr(it->value)); + func.addMember(arg); + } + return oo.prettyType(type) + ' ' + oo.prettyType(func.type(), varName->name); } } // anonymous namespace @@ -1654,7 +1670,7 @@ private: if (currentFile->cppDocument()->languageFeatures().cxx11Enabled && settings->useAuto) return "auto " + oo.prettyName(simpleNameAST->name); - return declFromExpr(binaryAST->right_expression, simpleNameAST, snapshot(), + return declFromExpr(binaryAST->right_expression, nullptr, simpleNameAST, snapshot(), context(), currentFile); } @@ -2920,20 +2936,24 @@ public: const CppQuickFixInterface &interface, const Class *theClass, const NameAST *memberName, - const ExpressionAST *initExpr, + const TypeOrExpr &typeOrExpr, + const CallAST *call, InsertionPointLocator::AccessSpec accessSpec, bool makeStatic) : CppQuickFixOperation(interface), - m_class(theClass), m_memberName(memberName), m_initExpr(initExpr), + m_class(theClass), m_memberName(memberName), m_typeOrExpr(typeOrExpr), m_call(call), m_accessSpec(accessSpec), m_makeStatic(makeStatic) { - setDescription(Tr::tr("Add Class Member \"%1\"").arg(nameString(memberName))); + if (call) + setDescription(Tr::tr("Add Member Function \"%1\"").arg(nameString(memberName))); + else + setDescription(Tr::tr("Add Class Member \"%1\"").arg(nameString(memberName))); } private: void perform() override { - QString decl = declFromExpr(m_initExpr, m_memberName, snapshot(), context(), + QString decl = declFromExpr(m_typeOrExpr, m_call, m_memberName, snapshot(), context(), currentFile()); if (decl.isEmpty()) return; @@ -2959,7 +2979,8 @@ private: const Class * const m_class; const NameAST * const m_memberName; - const ExpressionAST * const m_initExpr; + const TypeOrExpr m_typeOrExpr; + const CallAST * m_call; const InsertionPointLocator::AccessSpec m_accessSpec; const bool m_makeStatic; }; @@ -3002,6 +3023,9 @@ void AddDeclarationForUndeclaredIdentifier::collectOperations( const QList &path = interface.path(); const CppRefactoringFilePtr &file = interface.currentFile(); for (int index = path.size() - 1; index != -1; --index) { + if (const auto call = path.at(index)->asCall()) + return handleCall(call, interface, result); + // We only trigger if the identifier appears on the left-hand side of an // assignment expression. const auto binExpr = path.at(index)->asBinaryExpression(); @@ -3020,7 +3044,7 @@ void AddDeclarationForUndeclaredIdentifier::collectOperations( && memberAccess->member_name == path.last()) { maybeAddMember(interface, file->scopeAt(memberAccess->firstToken()), file->textOf(memberAccess->base_expression).toUtf8(), - binExpr->right_expression, result); + binExpr->right_expression, nullptr, result); } return; } @@ -3031,43 +3055,8 @@ void AddDeclarationForUndeclaredIdentifier::collectOperations( // In the case of "A::|b = c", add a static member b to A. if (const auto qualName = idExpr->name->asQualifiedName()) { - if (!interface.isCursorOn(qualName->unqualified_name)) - return; - if (qualName->unqualified_name != path.last()) - return; - if (!qualName->nested_name_specifier_list) - return; - - const NameAST * const topLevelName - = qualName->nested_name_specifier_list->value->class_or_namespace_name; - if (!topLevelName) - return; - ClassOrNamespace * const classOrNamespace = interface.context().lookupType( - topLevelName->name, file->scopeAt(qualName->firstToken())); - if (!classOrNamespace) - return; - QList otherNames; - for (auto it = qualName->nested_name_specifier_list->next; it; it = it->next) { - if (!it->value || !it->value->class_or_namespace_name) - return; - otherNames << it->value->class_or_namespace_name->name; - } - - const Class *theClass = nullptr; - if (!otherNames.isEmpty()) { - const Symbol * const symbol = classOrNamespace->lookupInScope(otherNames); - if (!symbol) - return; - theClass = symbol->asClass(); - } else { - theClass = classOrNamespace->rootClass(); - } - if (theClass) { - result << new InsertMemberFromInitializationOp( - interface, theClass, path.last()->asName(), binExpr->right_expression, - InsertionPointLocator::Public, true); - } - return; + return maybeAddStaticMember(interface, qualName, binExpr->right_expression, nullptr, + result); } // For an unqualified access, offer a local declaration and, if we are @@ -3076,12 +3065,92 @@ void AddDeclarationForUndeclaredIdentifier::collectOperations( if (!m_membersOnly) result << new AddLocalDeclarationOp(interface, index, binExpr, simpleName); maybeAddMember(interface, file->scopeAt(idExpr->firstToken()), "this", - binExpr->right_expression, result); + binExpr->right_expression, nullptr, result); return; } } } +void AddDeclarationForUndeclaredIdentifier::handleCall( + const CallAST *call, const CppQuickFixInterface &interface, + TextEditor::QuickFixOperations &result) +{ + if (!call->base_expression) + return; + + // In order to find out the return type, we need to check the context of the call. + // If it is a statement expression, the type is void, if it's a binary expression, + // we assume the type of the other side of the expression, if it's a return statement, + // we use the return type of the surrounding function, and if it's a declaration, + // we use the type of the variable. Other cases are not supported. + const QList &path = interface.path(); + const CppRefactoringFilePtr &file = interface.currentFile(); + TypeOrExpr returnTypeOrExpr; + for (auto it = path.rbegin(); it != path.rend(); ++it) { + if ((*it)->asCompoundStatement()) + return; + if ((*it)->asExpressionStatement()) { + returnTypeOrExpr = FullySpecifiedType(new VoidType); + break; + } + if (const auto binExpr = (*it)->asBinaryExpression()) { + returnTypeOrExpr = interface.isCursorOn(binExpr->left_expression) + ? binExpr->right_expression : binExpr->left_expression; + break; + } + if (const auto returnExpr = (*it)->asReturnStatement()) { + for (auto it2 = std::next(it); it2 != path.rend(); ++it2) { + if (const auto func = (*it2)->asFunctionDefinition()) { + if (!func->symbol) + return; + returnTypeOrExpr = func->symbol->returnType(); + break; + } + } + break; + } + if (const auto declarator = (*it)->asDeclarator()) { + if (!interface.isCursorOn(declarator->initializer)) + return; + const auto decl = (*std::next(it))->asSimpleDeclaration(); + if (!decl || !decl->symbols) + return; + if (!decl->symbols->value->type().isValid()) + return; + returnTypeOrExpr = decl->symbols->value->type(); + break; + } + } + + if (std::holds_alternative(returnTypeOrExpr) + && !std::get(returnTypeOrExpr)) { + return; + } + + // a.f() + if (const auto memberAccess = call->base_expression->asMemberAccess()) { + if (!interface.isCursorOn(memberAccess->member_name)) + return; + maybeAddMember( + interface, file->scopeAt(call->firstToken()), + file->textOf(memberAccess->base_expression).toUtf8(), returnTypeOrExpr, call, result); + } + + const auto idExpr = call->base_expression->asIdExpression(); + if (!idExpr || !idExpr->name) + return; + + // A::f() + if (const auto qualName = idExpr->name->asQualifiedName()) + return maybeAddStaticMember(interface, qualName, returnTypeOrExpr, call, result); + + // f() + if (const auto simpleName = idExpr->name->asSimpleName()) { + maybeAddMember(interface, file->scopeAt(idExpr->firstToken()), "this", + returnTypeOrExpr, call, result); + } +} + bool AddDeclarationForUndeclaredIdentifier::checkForMemberInitializer( const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) { @@ -3129,13 +3198,13 @@ bool AddDeclarationForUndeclaredIdentifier::checkForMemberInitializer( result << new InsertMemberFromInitializationOp( interface, theClass, memInitializer->name->asSimpleName(), memInitializer->expression, - InsertionPointLocator::Private, false); + nullptr, InsertionPointLocator::Private, false); return false; } void AddDeclarationForUndeclaredIdentifier::maybeAddMember( const CppQuickFixInterface &interface, Scope *scope, const QByteArray &classTypeExpr, - const ExpressionAST *initExpr, TextEditor::QuickFixOperations &result) + const TypeOrExpr &typeOrExpr, const CallAST *call, TextEditor::QuickFixOperations &result) { const QList &path = interface.path(); @@ -3199,7 +3268,51 @@ void AddDeclarationForUndeclaredIdentifier::maybeAddMember( } } result << new InsertMemberFromInitializationOp(interface, theClass, path.last()->asName(), - initExpr, accessSpec, needsStatic); + typeOrExpr, call, accessSpec, needsStatic); +} + +void AddDeclarationForUndeclaredIdentifier::maybeAddStaticMember( + const CppQuickFixInterface &interface, const QualifiedNameAST *qualName, + const TypeOrExpr &typeOrExpr, const CallAST *call, TextEditor::QuickFixOperations &result) +{ + const QList &path = interface.path(); + + if (!interface.isCursorOn(qualName->unqualified_name)) + return; + if (qualName->unqualified_name != path.last()) + return; + if (!qualName->nested_name_specifier_list) + return; + + const NameAST * const topLevelName + = qualName->nested_name_specifier_list->value->class_or_namespace_name; + if (!topLevelName) + return; + ClassOrNamespace * const classOrNamespace = interface.context().lookupType( + topLevelName->name, interface.currentFile()->scopeAt(qualName->firstToken())); + if (!classOrNamespace) + return; + QList otherNames; + for (auto it = qualName->nested_name_specifier_list->next; it; it = it->next) { + if (!it->value || !it->value->class_or_namespace_name) + return; + otherNames << it->value->class_or_namespace_name->name; + } + + const Class *theClass = nullptr; + if (!otherNames.isEmpty()) { + const Symbol * const symbol = classOrNamespace->lookupInScope(otherNames); + if (!symbol) + return; + theClass = symbol->asClass(); + } else { + theClass = classOrNamespace->rootClass(); + } + if (theClass) { + result << new InsertMemberFromInitializationOp( + interface, theClass, path.last()->asName(), typeOrExpr, call, + InsertionPointLocator::Public, true); + } } class MemberFunctionImplSetting diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h index 04c54793e97..61db3ebf53d 100644 --- a/src/plugins/cppeditor/cppquickfixes.h +++ b/src/plugins/cppeditor/cppquickfixes.h @@ -3,9 +3,10 @@ #pragma once -#include "cppeditor_global.h" #include "cppquickfix.h" +#include + /// /// Adding New Quick Fixes /// @@ -16,6 +17,7 @@ namespace CppEditor { namespace Internal { +using TypeOrExpr = std::variant; void createCppQuickFixes(); void destroyCppQuickFixes(); @@ -370,14 +372,21 @@ public: private: void collectOperations(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result); + void handleCall(const CPlusPlus::CallAST *call, const CppQuickFixInterface &interface, + TextEditor::QuickFixOperations &result); // Returns whether to still do other checks. bool checkForMemberInitializer(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result); void maybeAddMember(const CppQuickFixInterface &interface, CPlusPlus::Scope *scope, - const QByteArray &classTypeExpr, const CPlusPlus::ExpressionAST *initExpr, - TextEditor::QuickFixOperations &result); + const QByteArray &classTypeExpr, const TypeOrExpr &typeOrExpr, + const CPlusPlus::CallAST *call, TextEditor::QuickFixOperations &result); + + void maybeAddStaticMember( + const CppQuickFixInterface &interface, const CPlusPlus::QualifiedNameAST *qualName, + const TypeOrExpr &typeOrExpr, const CPlusPlus::CallAST *call, + TextEditor::QuickFixOperations &result); bool m_membersOnly = false; }; From b91f234c7daf03b116ac5bd882cac286d520ee7f Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 2 Mar 2023 15:29:50 +0100 Subject: [PATCH 1080/1447] ExtensionSystem: Start reworking initialization order system Allow specifying object creation without immediate creation (but create them nevetheless very soon). Change-Id: I01b91f7cf753ced61705d3f26352548b268be6b5 Reviewed-by: Eike Ziller --- src/libs/extensionsystem/iplugin.cpp | 53 +++++++++++++++++++++++++ src/libs/extensionsystem/iplugin.h | 25 ++++++++++++ src/libs/extensionsystem/pluginspec.cpp | 6 ++- 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/libs/extensionsystem/iplugin.cpp b/src/libs/extensionsystem/iplugin.cpp index 9f7ca221e51..6661a46f610 100644 --- a/src/libs/extensionsystem/iplugin.cpp +++ b/src/libs/extensionsystem/iplugin.cpp @@ -161,12 +161,47 @@ namespace ExtensionSystem { namespace Internal { +class ObjectInitializer +{ +public: + ObjectCreator creator; + ObjectDestructor destructor; + ObjectCreationPolicy policy; +}; + class IPluginPrivate { public: + void tryCreateObjects(); + QList testCreators; + + QList objectInitializers; + QList> objectDestructors; + + // For debugging purposes: + QList createdObjects; // Not owned. }; +void IPluginPrivate::tryCreateObjects() +{ + QList unhandledObjectInitializers; + + for (const ObjectInitializer &initializer : std::as_const(objectInitializers)) { + if (!initializer.policy.dependsOn.isEmpty()) { + qWarning("Initialization dependencies are not supported yet"); + unhandledObjectInitializers.append(initializer); + continue; + } + + void *object = initializer.creator(); + createdObjects.append(object); + objectDestructors.append([initializer, object] { initializer.destructor(object); }); + } + + objectInitializers = unhandledObjectInitializers; +} + } // Internal /*! @@ -182,10 +217,20 @@ IPlugin::IPlugin() */ IPlugin::~IPlugin() { + for (const std::function &dtor : std::as_const(d->objectDestructors)) + dtor(); + delete d; d = nullptr; } +void IPlugin::addManagedHelper(const ObjectCreator &creator, + const ObjectDestructor &destructor, + const ObjectCreationPolicy &policy) +{ + d->objectInitializers.append({creator, destructor, policy}); +} + bool IPlugin::initialize(const QStringList &arguments, QString *errorString) { Q_UNUSED(arguments) @@ -194,6 +239,14 @@ bool IPlugin::initialize(const QStringList &arguments, QString *errorString) return true; } +/*! + \internal +*/ +void IPlugin::tryCreateObjects() +{ + d->tryCreateObjects(); +} + /*! Registers a function object that creates a test object. diff --git a/src/libs/extensionsystem/iplugin.h b/src/libs/extensionsystem/iplugin.h index 5a8fceb3d6e..3e477e42e81 100644 --- a/src/libs/extensionsystem/iplugin.h +++ b/src/libs/extensionsystem/iplugin.h @@ -5,6 +5,8 @@ #include "extensionsystem_global.h" +#include + #include #include @@ -15,6 +17,17 @@ namespace Internal { class IPluginPrivate; } using TestCreator = std::function; +using ObjectCreator = std::function; +using ObjectDestructor = std::function; + +struct EXTENSIONSYSTEM_EXPORT ObjectCreationPolicy +{ + // Can be empty if nothing depends on it. + Utils::Id id; + // Objects with empty dependencies are created as soon as possible. + QList dependsOn; +}; + class EXTENSIONSYSTEM_EXPORT IPlugin : public QObject { Q_OBJECT @@ -39,6 +52,7 @@ public: // Deprecated in 10.0, use addTest() virtual QVector createTestObjects() const; + virtual void tryCreateObjects(); protected: virtual void initialize() {} @@ -47,6 +61,17 @@ protected: void addTest(Args && ...args) { addTestCreator([args...] { return new Test(args...); }); } void addTestCreator(const TestCreator &creator); + template + void addManaged(const ObjectCreationPolicy &policy = {}) { + addManagedHelper([]() -> void * { return new Type(); }, + [](void *p) { delete static_cast(p); }, + policy); + } + + void addManagedHelper(const ObjectCreator &creator, + const ObjectDestructor &destructor, + const ObjectCreationPolicy &policy); + signals: void asynchronousShutdownFinished(); diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index d18f410e818..62b3c0096f6 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -1119,6 +1119,7 @@ bool PluginSpecPrivate::initializePlugin() hasError = true; return false; } + plugin->tryCreateObjects(); state = PluginSpec::Initialized; return true; } @@ -1145,6 +1146,7 @@ bool PluginSpecPrivate::initializeExtensions() return false; } plugin->extensionsInitialized(); + plugin->tryCreateObjects(); state = PluginSpec::Running; return true; } @@ -1164,7 +1166,9 @@ bool PluginSpecPrivate::delayedInitialize() hasError = true; return false; } - return plugin->delayedInitialize(); + const bool res = plugin->delayedInitialize(); + plugin->tryCreateObjects(); + return res; } /*! From 39f27a8eb82c66af17d30b7946988ca9275bb705 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 11 May 2023 10:34:08 +0200 Subject: [PATCH 1081/1447] Squish: Fix layout of server settings dialog Broke with the overhaul of the layout builder. Change-Id: I94da9c8f6b2a67b43b8bfe08e838dbd38400c2f4 Reviewed-by: David Schulz --- src/plugins/squish/squishsettings.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/squish/squishsettings.cpp b/src/plugins/squish/squishsettings.cpp index 68de6c62977..e95ed33f48f 100644 --- a/src/plugins/squish/squishsettings.cpp +++ b/src/plugins/squish/squishsettings.cpp @@ -385,10 +385,10 @@ SquishServerSettingsWidget::SquishServerSettingsWidget(QWidget *parent) using namespace Layouting; Form grid { &m_applicationsView, br, - &m_serverSettings.autTimeout, - &m_serverSettings.responseTimeout, - &m_serverSettings.postMortemWaitTime, - &m_serverSettings.animatedCursor, + &m_serverSettings.autTimeout, br, + &m_serverSettings.responseTimeout, br, + &m_serverSettings.postMortemWaitTime, br, + &m_serverSettings.animatedCursor, br, }; Column buttonCol { add, From 21cb45e665c2247cdc7abe6c9e002c0900842098 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 16 May 2023 13:00:18 +0200 Subject: [PATCH 1082/1447] App: Remove workaround for crash in regexp jitting in Rosetta The relevant Qt bug was fixed upstream. This effectively reverts ab16f2984b6661ea172d345 Task-number: QTBUG-97085 Change-Id: I2ccf50f83b42111bbeaa26dfd95b1eb69a62c3bf Reviewed-by: Eike Ziller --- src/app/main.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index d6d0c8cc121..3a2cb5bfaae 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -518,11 +518,6 @@ int main(int argc, char **argv) QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar); } - if (Utils::HostOsInfo::isRunningUnderRosetta()) { - // work around QTBUG-97085: QRegularExpression jitting is not reentrant under Rosetta - qputenv("QT_ENABLE_REGEXP_JIT", "0"); - } - if (Utils::HostOsInfo::isLinuxHost() && !qEnvironmentVariableIsSet("GTK_THEME")) // Work around QTCREATORBUG-28497: // Prevent Qt's GTK3 platform theme plugin from enforcing a dark palette From 22fa5f2d3a600f9932a3abc3c71a72cd45c7f3ee Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 15:15:17 +0200 Subject: [PATCH 1083/1447] Haskell: More compact settings/manager setup Use PagedSettings, move related parts Manager interface there, too. Change-Id: I079dad8bbbea39d2424a25867b08c34ab0234ad5 Reviewed-by: Christian Stenger Reviewed-by: Eike Ziller --- src/plugins/haskell/CMakeLists.txt | 2 +- src/plugins/haskell/haskell.qbs | 2 +- src/plugins/haskell/haskelleditorfactory.cpp | 14 ++-- src/plugins/haskell/haskelleditorfactory.h | 6 +- src/plugins/haskell/haskellmanager.cpp | 67 ++----------------- src/plugins/haskell/haskellmanager.h | 21 +----- src/plugins/haskell/haskellplugin.cpp | 18 ++--- .../haskell/haskellrunconfiguration.cpp | 4 +- src/plugins/haskell/haskellsettings.cpp | 63 +++++++++++++++++ .../{optionspage.h => haskellsettings.h} | 8 ++- src/plugins/haskell/optionspage.cpp | 51 -------------- src/plugins/haskell/stackbuildstep.cpp | 4 +- 12 files changed, 95 insertions(+), 165 deletions(-) create mode 100644 src/plugins/haskell/haskellsettings.cpp rename src/plugins/haskell/{optionspage.h => haskellsettings.h} (65%) delete mode 100644 src/plugins/haskell/optionspage.cpp diff --git a/src/plugins/haskell/CMakeLists.txt b/src/plugins/haskell/CMakeLists.txt index 0f43b456999..d45326695cb 100644 --- a/src/plugins/haskell/CMakeLists.txt +++ b/src/plugins/haskell/CMakeLists.txt @@ -12,9 +12,9 @@ add_qtc_plugin(Haskell haskellplugin.cpp haskellplugin.h haskellproject.cpp haskellproject.h haskellrunconfiguration.cpp haskellrunconfiguration.h + haskellsettings.cpp haskellsettings.h haskelltokenizer.cpp haskelltokenizer.h haskelltr.h - optionspage.cpp optionspage.h stackbuildstep.cpp stackbuildstep.h ) diff --git a/src/plugins/haskell/haskell.qbs b/src/plugins/haskell/haskell.qbs index 30eb8328f1a..5c1be115387 100644 --- a/src/plugins/haskell/haskell.qbs +++ b/src/plugins/haskell/haskell.qbs @@ -21,8 +21,8 @@ QtcPlugin { "haskellplugin.cpp", "haskellplugin.h", "haskellproject.cpp", "haskellproject.h", "haskellrunconfiguration.cpp", "haskellrunconfiguration.h", + "haskellsettings.cpp", "haskellsettings.h", "haskelltokenizer.cpp", "haskelltokenizer.h", - "optionspage.cpp", "optionspage.h", "stackbuildstep.cpp", "stackbuildstep.h" ] } diff --git a/src/plugins/haskell/haskelleditorfactory.cpp b/src/plugins/haskell/haskelleditorfactory.cpp index 4053efeba2d..ba87f88ef70 100644 --- a/src/plugins/haskell/haskelleditorfactory.cpp +++ b/src/plugins/haskell/haskelleditorfactory.cpp @@ -14,17 +14,14 @@ #include #include -#include +namespace Haskell::Internal { -namespace Haskell { -namespace Internal { - -static QWidget *createEditorWidget() +static QWidget *createEditorWidget(QObject *guard) { auto widget = new TextEditor::TextEditorWidget; auto ghciButton = new Core::CommandButton(Constants::A_RUN_GHCI, widget); ghciButton->setText(Tr::tr("GHCi")); - QObject::connect(ghciButton, &QToolButton::clicked, HaskellManager::instance(), [widget] { + QObject::connect(ghciButton, &QToolButton::clicked, guard, [widget] { HaskellManager::openGhci(widget->textDocument()->filePath()); }); widget->insertExtraToolBarWidget(TextEditor::TextEditorWidget::Left, ghciButton); @@ -40,12 +37,11 @@ HaskellEditorFactory::HaskellEditorFactory() | TextEditor::TextEditorActionHandler::FollowSymbolUnderCursor); setDocumentCreator([] { return new TextEditor::TextDocument(Constants::C_HASKELLEDITOR_ID); }); setIndenterCreator([](QTextDocument *doc) { return new TextEditor::TextIndenter(doc); }); - setEditorWidgetCreator(createEditorWidget); + setEditorWidgetCreator([this] { return createEditorWidget(this); }); setCommentDefinition(Utils::CommentDefinition("--", "{-", "-}")); setParenthesesMatchingEnabled(true); setMarksVisible(true); setSyntaxHighlighterCreator([] { return new HaskellHighlighter(); }); } -} // Internal -} // Haskell +} // Haskell::Internal diff --git a/src/plugins/haskell/haskelleditorfactory.h b/src/plugins/haskell/haskelleditorfactory.h index c91f875df29..090a5b12782 100644 --- a/src/plugins/haskell/haskelleditorfactory.h +++ b/src/plugins/haskell/haskelleditorfactory.h @@ -5,8 +5,7 @@ #include -namespace Haskell { -namespace Internal { +namespace Haskell::Internal { class HaskellEditorFactory : public TextEditor::TextEditorFactory { @@ -14,5 +13,4 @@ public: HaskellEditorFactory(); }; -} // Internal -} // Haskell +} // Haskell::Internal diff --git a/src/plugins/haskell/haskellmanager.cpp b/src/plugins/haskell/haskellmanager.cpp index 78134d4b159..94a03ec659e 100644 --- a/src/plugins/haskell/haskellmanager.cpp +++ b/src/plugins/haskell/haskellmanager.cpp @@ -3,9 +3,9 @@ #include "haskellmanager.h" +#include "haskellsettings.h" #include "haskelltr.h" -#include #include #include #include @@ -13,33 +13,12 @@ #include #include -#include #include #include -#include - -#include - -static const char kStackExecutableKey[] = "Haskell/StackExecutable"; using namespace Utils; -namespace Haskell { -namespace Internal { - -class HaskellManagerPrivate -{ -public: - FilePath stackExecutable; -}; - -Q_GLOBAL_STATIC(HaskellManagerPrivate, m_d) -Q_GLOBAL_STATIC(HaskellManager, m_instance) - -HaskellManager *HaskellManager::instance() -{ - return m_instance; -} +namespace Haskell::Internal { FilePath HaskellManager::findProjectDirectory(const FilePath &filePath) { @@ -57,28 +36,6 @@ FilePath HaskellManager::findProjectDirectory(const FilePath &filePath) return {}; } -FilePath defaultStackExecutable() -{ - // stack from brew or the installer script from https://docs.haskellstack.org - // install to /usr/local/bin. - if (HostOsInfo::isAnyUnixHost()) - return FilePath::fromString("/usr/local/bin/stack"); - return FilePath::fromString("stack"); -} - -FilePath HaskellManager::stackExecutable() -{ - return m_d->stackExecutable; -} - -void HaskellManager::setStackExecutable(const FilePath &filePath) -{ - if (filePath == m_d->stackExecutable) - return; - m_d->stackExecutable = filePath; - emit m_instance->stackExecutableChanged(m_d->stackExecutable); -} - void HaskellManager::openGhci(const FilePath &haskellFile) { const QList mimeTypes = mimeTypesForFileName(haskellFile.toString()); @@ -89,25 +46,9 @@ void HaskellManager::openGhci(const FilePath &haskellFile) + (isHaskell ? QStringList{haskellFile.fileName()} : QStringList()); Process p; p.setTerminalMode(TerminalMode::Detached); - p.setCommand({stackExecutable(), args}); + p.setCommand({settings().stackPath.filePath(), args}); p.setWorkingDirectory(haskellFile.absolutePath()); p.start(); } -void HaskellManager::readSettings(QSettings *settings) -{ - m_d->stackExecutable = FilePath::fromString( - settings->value(kStackExecutableKey, defaultStackExecutable().toString()).toString()); - emit m_instance->stackExecutableChanged(m_d->stackExecutable); -} - -void HaskellManager::writeSettings(QSettings *settings) -{ - if (m_d->stackExecutable == defaultStackExecutable()) - settings->remove(kStackExecutableKey); - else - settings->setValue(kStackExecutableKey, m_d->stackExecutable.toString()); -} - -} // namespace Internal -} // namespace Haskell +} // Haskell::Internal diff --git a/src/plugins/haskell/haskellmanager.h b/src/plugins/haskell/haskellmanager.h index da4018930d1..862f46460f1 100644 --- a/src/plugins/haskell/haskellmanager.h +++ b/src/plugins/haskell/haskellmanager.h @@ -7,30 +7,15 @@ #include -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE +namespace Haskell::Internal { -namespace Haskell { -namespace Internal { - -class HaskellManager : public QObject +class HaskellManager { - Q_OBJECT - public: static HaskellManager *instance(); static Utils::FilePath findProjectDirectory(const Utils::FilePath &filePath); - static Utils::FilePath stackExecutable(); - static void setStackExecutable(const Utils::FilePath &filePath); static void openGhci(const Utils::FilePath &haskellFile); - static void readSettings(QSettings *settings); - static void writeSettings(QSettings *settings); - -signals: - void stackExecutableChanged(const Utils::FilePath &filePath); }; -} // namespace Internal -} // namespace Haskell +} // Haskell::Internal diff --git a/src/plugins/haskell/haskellplugin.cpp b/src/plugins/haskell/haskellplugin.cpp index 334c1049112..84a86f7db48 100644 --- a/src/plugins/haskell/haskellplugin.cpp +++ b/src/plugins/haskell/haskellplugin.cpp @@ -9,8 +9,8 @@ #include "haskellmanager.h" #include "haskellproject.h" #include "haskellrunconfiguration.h" +#include "haskellsettings.h" #include "haskelltr.h" -#include "optionspage.h" #include "stackbuildstep.h" #include @@ -28,8 +28,8 @@ namespace Internal { class HaskellPluginPrivate { public: + HaskellSettings settings; HaskellEditorFactory editorFactory; - OptionsPage optionsPage; HaskellBuildConfigurationFactory buildConfigFactory; StackBuildStepFactory stackBuildStepFactory; HaskellRunConfigurationFactory runConfigFactory; @@ -41,11 +41,11 @@ HaskellPlugin::~HaskellPlugin() delete d; } -static void registerGhciAction() +static void registerGhciAction(QObject *guard) { - QAction *action = new QAction(Tr::tr("Run GHCi"), HaskellManager::instance()); + QAction *action = new QAction(Tr::tr("Run GHCi"), guard); Core::ActionManager::registerAction(action, Constants::A_RUN_GHCI); - QObject::connect(action, &QAction::triggered, HaskellManager::instance(), [] { + QObject::connect(action, &QAction::triggered, guard, [] { if (Core::IDocument *doc = Core::EditorManager::currentDocument()) HaskellManager::openGhci(doc->filePath()); }); @@ -63,13 +63,7 @@ bool HaskellPlugin::initialize(const QStringList &arguments, QString *errorStrin TextEditor::SnippetProvider::registerGroup(Constants::C_HASKELLSNIPPETSGROUP_ID, Tr::tr("Haskell", "SnippetProvider")); - connect(Core::ICore::instance(), &Core::ICore::saveSettingsRequested, this, [] { - HaskellManager::writeSettings(Core::ICore::settings()); - }); - - registerGhciAction(); - - HaskellManager::readSettings(Core::ICore::settings()); + registerGhciAction(this); ProjectExplorer::JsonWizardFactory::addWizardPath(":/haskell/share/wizards/"); return true; diff --git a/src/plugins/haskell/haskellrunconfiguration.cpp b/src/plugins/haskell/haskellrunconfiguration.cpp index 45b6e684bc4..9c236c65b5e 100644 --- a/src/plugins/haskell/haskellrunconfiguration.cpp +++ b/src/plugins/haskell/haskellrunconfiguration.cpp @@ -4,9 +4,9 @@ #include "haskellrunconfiguration.h" #include "haskellconstants.h" -#include "haskellmanager.h" #include "haskellproject.h" #include "haskelltr.h" +#include "haskellsettings.h" #include #include @@ -68,7 +68,7 @@ Runnable HaskellRunConfiguration::runnable() const r.workingDirectory = projectDirectory; r.environment = aspect()->environment(); - r.command = {r.environment.searchInPath(HaskellManager::stackExecutable().toString()), args}; + r.command = {r.environment.searchInPath(settings().stackPath()), args}; return r; } diff --git a/src/plugins/haskell/haskellsettings.cpp b/src/plugins/haskell/haskellsettings.cpp new file mode 100644 index 00000000000..6b0ee170368 --- /dev/null +++ b/src/plugins/haskell/haskellsettings.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "haskellsettings.h" + +#include "haskellconstants.h" +#include "haskelltr.h" + +#include + +#include +#include +#include + +using namespace Utils; + +namespace Haskell::Internal { + +static HaskellSettings *theSettings; + +HaskellSettings &settings() +{ + return *theSettings; +} + +HaskellSettings::HaskellSettings() +{ + theSettings = this; + + setId(Constants::OPTIONS_GENERAL); + setDisplayName(Tr::tr("General")); + setCategory("J.Z.Haskell"); + setDisplayCategory(Tr::tr("Haskell")); + setCategoryIconPath(":/haskell/images/settingscategory_haskell.png"); + + registerAspect(&stackPath); + stackPath.setSettingsKey("Haskell/StackExecutable"); + stackPath.setDisplayStyle(StringAspect::PathChooserDisplay); + stackPath.setExpectedKind(PathChooser::ExistingCommand); + stackPath.setPromptDialogTitle(Tr::tr("Choose Stack Executable")); + stackPath.setCommandVersionArguments({"--version"}); + + // stack from brew or the installer script from https://docs.haskellstack.org + // install to /usr/local/bin. + stackPath.setDefaultFilePath(HostOsInfo::isAnyUnixHost() + ? FilePath::fromString("/usr/local/bin/stack") + : FilePath::fromString("stack")); + + setLayouter([this](QWidget *widget) { + using namespace Layouting; + Column { + Group { + title(Tr::tr("General")), + Row { Tr::tr("Stack executable:"), stackPath } + }, + st, + }.attachTo(widget); + }); + + readSettings(Core::ICore::settings()); +} + +} // Haskell::Internal diff --git a/src/plugins/haskell/optionspage.h b/src/plugins/haskell/haskellsettings.h similarity index 65% rename from src/plugins/haskell/optionspage.h rename to src/plugins/haskell/haskellsettings.h index 4328be44e7b..c697a154ee4 100644 --- a/src/plugins/haskell/optionspage.h +++ b/src/plugins/haskell/haskellsettings.h @@ -7,10 +7,14 @@ namespace Haskell::Internal { -class OptionsPage : public Core::IOptionsPage +class HaskellSettings : public Core::PagedSettings { public: - OptionsPage(); + HaskellSettings(); + + Utils::StringAspect stackPath; }; +HaskellSettings &settings(); + } // Haskell::Internal diff --git a/src/plugins/haskell/optionspage.cpp b/src/plugins/haskell/optionspage.cpp deleted file mode 100644 index 48e5159da5a..00000000000 --- a/src/plugins/haskell/optionspage.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "optionspage.h" - -#include "haskellconstants.h" -#include "haskellmanager.h" -#include "haskelltr.h" - -#include -#include - -using namespace Utils; - -namespace Haskell::Internal { - -class HaskellOptionsPageWidget : public Core::IOptionsPageWidget -{ -public: - HaskellOptionsPageWidget() - { - auto stackPath = new PathChooser; - stackPath->setExpectedKind(PathChooser::ExistingCommand); - stackPath->setPromptDialogTitle(Tr::tr("Choose Stack Executable")); - stackPath->setFilePath(HaskellManager::stackExecutable()); - stackPath->setCommandVersionArguments({"--version"}); - - setOnApply([stackPath] { HaskellManager::setStackExecutable(stackPath->rawFilePath()); }); - - using namespace Layouting; - Column { - Group { - title(Tr::tr("General")), - Row { Tr::tr("Stack executable:"), stackPath } - }, - st, - }.attachTo(this); - } -}; - -OptionsPage::OptionsPage() -{ - setId(Constants::OPTIONS_GENERAL); - setDisplayName(Tr::tr("General")); - setCategory("J.Z.Haskell"); - setDisplayCategory(Tr::tr("Haskell")); - setCategoryIconPath(":/haskell/images/settingscategory_haskell.png"); - setWidgetCreator([] { return new HaskellOptionsPageWidget; }); -} - -} // Haskell::Internal diff --git a/src/plugins/haskell/stackbuildstep.cpp b/src/plugins/haskell/stackbuildstep.cpp index 084ba8af4a7..860ef458c5f 100644 --- a/src/plugins/haskell/stackbuildstep.cpp +++ b/src/plugins/haskell/stackbuildstep.cpp @@ -4,7 +4,7 @@ #include "stackbuildstep.h" #include "haskellconstants.h" -#include "haskellmanager.h" +#include "haskellsettings.h" #include "haskelltr.h" #include @@ -38,7 +38,7 @@ bool StackBuildStep::init() if (AbstractProcessStep::init()) { const auto projectDir = QDir(project()->projectDirectory().toString()); processParameters()->setCommandLine( - {HaskellManager::stackExecutable(), + {settings().stackPath.filePath(), {"build", "--work-dir", projectDir.relativeFilePath(buildDirectory().toString())}}); processParameters()->setEnvironment(buildEnvironment()); } From 3416ccd7ec9c441ddcd3aaafd9ad0cb603f05c6e Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 15 May 2023 15:55:50 +0200 Subject: [PATCH 1084/1447] Terminal: Fix selection When moving the mouse left or right out of the viewport the selection would grow into the previous/next line without the bounding. Change-Id: Ica38eac3b306338ef24aa4abace66f110edb2aef Reviewed-by: Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalwidget.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index b3c7421a6a7..b63e66b78dd 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -1313,8 +1313,11 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event) m_scrollTimer.setInterval(scrollInterval); } + QPoint posBoundedToViewport = event->pos(); + posBoundedToViewport.setX(qBound(0, posBoundedToViewport.x(), viewport()->width())); + int start = m_surface->gridToPos(globalToGrid(m_activeMouseSelect.start)); - int newEnd = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos()))); + int newEnd = m_surface->gridToPos(globalToGrid(viewportToGlobal(posBoundedToViewport))); if (start > newEnd) { std::swap(start, newEnd); From d6111f2e1d7a04e3c0c2ddf052745dd956c11712 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 16 May 2023 14:33:51 +0200 Subject: [PATCH 1085/1447] ProjectExplorer: Remove some pointerage around KitOptionsPage Change-Id: Ib1736a80739c6052372896bac03aa324fd807151 Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/kitoptionspage.cpp | 15 +++++---------- src/plugins/projectexplorer/kitoptionspage.h | 7 +------ src/plugins/projectexplorer/projectwindow.cpp | 3 +-- src/plugins/projectexplorer/targetsetupwidget.cpp | 6 ++---- 4 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/plugins/projectexplorer/kitoptionspage.cpp b/src/plugins/projectexplorer/kitoptionspage.cpp index a4fe93c1f8a..db578a403e6 100644 --- a/src/plugins/projectexplorer/kitoptionspage.cpp +++ b/src/plugins/projectexplorer/kitoptionspage.cpp @@ -25,7 +25,9 @@ namespace Internal { // KitOptionsPageWidget -static KitOptionsPageWidget *kitOptionsPageWidget = nullptr; +class KitOptionsPageWidget; + +static QPointer kitOptionsPageWidget; class KitOptionsPageWidget : public Core::IOptionsPageWidget { @@ -242,11 +244,8 @@ QModelIndex KitOptionsPageWidget::currentIndex() const // KitOptionsPage: // -------------------------------------------------------------------------- -static KitOptionsPage *theKitOptionsPage = nullptr; - KitOptionsPage::KitOptionsPage() { - theKitOptionsPage = this; setId(Constants::KITS_SETTINGS_PAGE_ID); setDisplayName(Tr::tr("Kits")); setCategory(Constants::KITS_SETTINGS_CATEGORY); @@ -261,7 +260,8 @@ void KitOptionsPage::showKit(Kit *k) return; Internal::KitOptionsPageWidget *widget = Internal::kitOptionsPageWidget; - QTC_ASSERT(widget, return); + if (!widget) + return; QModelIndex index = widget->m_model->indexOf(k); widget->m_selectionModel->select(index, @@ -271,9 +271,4 @@ void KitOptionsPage::showKit(Kit *k) widget->m_kitsView->scrollTo(index); } -KitOptionsPage *KitOptionsPage::instance() -{ - return theKitOptionsPage; -} - } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/kitoptionspage.h b/src/plugins/projectexplorer/kitoptionspage.h index b3378060bee..a7a4ba29dbc 100644 --- a/src/plugins/projectexplorer/kitoptionspage.h +++ b/src/plugins/projectexplorer/kitoptionspage.h @@ -7,12 +7,8 @@ #include -#include - namespace ProjectExplorer { -namespace Internal { class KitOptionsPageWidget; } - class Kit; class PROJECTEXPLORER_EXPORT KitOptionsPage : public Core::IOptionsPage @@ -20,8 +16,7 @@ class PROJECTEXPLORER_EXPORT KitOptionsPage : public Core::IOptionsPage public: KitOptionsPage(); - void showKit(Kit *k); - static KitOptionsPage *instance(); + static void showKit(Kit *k); }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index f44c5354fee..6d51ada4106 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -743,8 +743,7 @@ public: void handleManageKits() { if (ProjectItem *projectItem = m_projectsModel.rootItem()->childAt(0)) { - if (auto kitPage = KitOptionsPage::instance()) - kitPage->showKit(KitManager::kit(Id::fromSetting(projectItem->data(0, KitIdRole)))); + KitOptionsPage::showKit(KitManager::kit(Id::fromSetting(projectItem->data(0, KitIdRole)))); } ICore::showOptionsDialog(Constants::KITS_SETTINGS_PAGE_ID); } diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp index cae28fc3e1f..63b61401d5f 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.cpp +++ b/src/plugins/projectexplorer/targetsetupwidget.cpp @@ -180,10 +180,8 @@ void TargetSetupWidget::manageKit() if (!m_kit) return; - if (auto kitPage = KitOptionsPage::instance()) { - kitPage->showKit(m_kit); - Core::ICore::showOptionsDialog(Constants::KITS_SETTINGS_PAGE_ID, parentWidget()); - } + KitOptionsPage::showKit(m_kit); + Core::ICore::showOptionsDialog(Constants::KITS_SETTINGS_PAGE_ID, parentWidget()); } void TargetSetupWidget::setProjectPath(const FilePath &projectPath) From 1e595c6afe6032c04d42a41c4d030b3c7980008c Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 16 May 2023 12:42:04 +0200 Subject: [PATCH 1086/1447] Terminal: Fix exiting of conpty terminals QMetaObject would complain about not knowing about the HANDLE type. Change-Id: Iae240bed37c892561eaacdc1d22cf4ae0173df29 Reviewed-by: Marcus Tillmanns --- src/libs/3rdparty/libptyqt/conptyprocess.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/3rdparty/libptyqt/conptyprocess.cpp b/src/libs/3rdparty/libptyqt/conptyprocess.cpp index b9a4afd1262..cb18b332066 100644 --- a/src/libs/3rdparty/libptyqt/conptyprocess.cpp +++ b/src/libs/3rdparty/libptyqt/conptyprocess.cpp @@ -83,6 +83,8 @@ HRESULT ConPtyProcess::initializeStartupInfoAttachedToPseudoConsole(STARTUPINFOE return hr; } +Q_DECLARE_METATYPE(HANDLE) + ConPtyProcess::ConPtyProcess() : IPtyProcess() , m_ptyHandler { INVALID_HANDLE_VALUE } @@ -90,7 +92,7 @@ ConPtyProcess::ConPtyProcess() , m_hPipeOut { INVALID_HANDLE_VALUE } , m_readThread(nullptr) { - + qRegisterMetaType("HANDLE"); } ConPtyProcess::~ConPtyProcess() From 671621d79bc9fa8542562503a12d381f054b27e8 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 18:24:20 +0200 Subject: [PATCH 1087/1447] Utils: Introduce a FilePathAspect A shallow wrapper around a StringAspect with a suitable operator(). Change-Id: I0a5e121565d03573faa5c3f4085d72db2b9c3774 Reviewed-by: Christian Stenger --- src/libs/utils/aspects.cpp | 22 ++++++++++++++++++++++ src/libs/utils/aspects.h | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index ae3841c647a..541b258c0bb 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1325,6 +1325,28 @@ void StringAspect::makeCheckable(CheckBoxPlacement checkBoxPlacement, update(); } + +/*! + \class Utils::FilePathAspect + \inmodule QtCreator + + \brief A file path aspect is shallow wrapper around a Utils::StringAspect that + represents a file in the file system. + + It is displayed by default using Utils::PathChooser. + + The visual representation often contains a label in front of the display + of the actual value. + + \sa Utils::StringAspect +*/ + + +FilePathAspect::FilePathAspect() +{ + setDisplayStyle(PathChooserDisplay); +} + /*! \class Utils::ColorAspect \inmodule QtCreator diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index b610c1ffbe1..1a2570ea837 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -439,6 +439,14 @@ protected: std::unique_ptr d; }; +class QTCREATOR_UTILS_EXPORT FilePathAspect : public StringAspect +{ +public: + FilePathAspect(); + + FilePath operator()() const { return filePath(); } +}; + class QTCREATOR_UTILS_EXPORT IntegerAspect : public BaseAspect { Q_OBJECT From 7e5ba6c99324760269392f5ca3937aa7e5fb5976 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 16 May 2023 13:27:29 +0200 Subject: [PATCH 1088/1447] Terminal: Fix CellIterator again The updateChar() was only called when m_pos == 0. It needs to be called unless m_state == End though. Change-Id: I2c9a7c151420395d18f2846705d57129d7afc5f3 Reviewed-by: Cristian Adam --- src/plugins/terminal/celliterator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/terminal/celliterator.cpp b/src/plugins/terminal/celliterator.cpp index d81c4b71879..91a70f76ea3 100644 --- a/src/plugins/terminal/celliterator.cpp +++ b/src/plugins/terminal/celliterator.cpp @@ -22,10 +22,12 @@ CellIterator::CellIterator(const TerminalSurface *surface, int pos) if (m_pos == 0) { m_state = State::BEGIN; - updateChar(); } else if (m_pos == m_maxpos + 1) { m_state = State::END; } + + if (m_state != State::END) + updateChar(); } CellIterator::CellIterator(const TerminalSurface *surface) From 77c19ae213a3e4cbc9717db2a14124ac7ca59e28 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 16 May 2023 12:51:21 +0200 Subject: [PATCH 1089/1447] Utils: Add minimal Flow layout support to layout builder It will be used in the CppCheck option page. The de-facto copy of utils/flowlayout.{cpp,h} is intentional to keep the layout builder usable stand-alone. Change-Id: Ibda3ece2aeb3cbb1badaf6083b52ebb63b6524ac Reviewed-by: Alessandro Portale --- src/libs/utils/layoutbuilder.cpp | 178 +++++++++++++++++++++++++++++++ src/libs/utils/layoutbuilder.h | 6 ++ 2 files changed, 184 insertions(+) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index e3582f6adec..43dd68c7905 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -27,6 +27,153 @@ namespace Layouting { #define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_STRING(#cond); action; } do {} while (0) #define QTC_CHECK(cond) if (cond) {} else { QTC_STRING(#cond); } do {} while (0) +class FlowLayout final : public QLayout +{ + Q_OBJECT + +public: + explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1) + : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) + { + setContentsMargins(margin, margin, margin, margin); + } + + FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1) + : m_hSpace(hSpacing), m_vSpace(vSpacing) + { + setContentsMargins(margin, margin, margin, margin); + } + + ~FlowLayout() override + { + QLayoutItem *item; + while ((item = takeAt(0))) + delete item; + } + + void addItem(QLayoutItem *item) override { itemList.append(item); } + + int horizontalSpacing() const + { + if (m_hSpace >= 0) + return m_hSpace; + else + return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } + + int verticalSpacing() const + { + if (m_vSpace >= 0) + return m_vSpace; + else + return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } + + Qt::Orientations expandingDirections() const override + { + return {}; + } + + bool hasHeightForWidth() const override { return true; } + + int heightForWidth(int width) const override + { + int height = doLayout(QRect(0, 0, width, 0), true); + return height; + } + + int count() const override { return itemList.size(); } + + QLayoutItem *itemAt(int index) const override + { + return itemList.value(index); + } + + QSize minimumSize() const override + { + QSize size; + for (QLayoutItem *item : itemList) + size = size.expandedTo(item->minimumSize()); + + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + size += QSize(left + right, top + bottom); + return size; + } + + void setGeometry(const QRect &rect) override + { + QLayout::setGeometry(rect); + doLayout(rect, false); + } + + QSize sizeHint() const override + { + return minimumSize(); + } + + QLayoutItem *takeAt(int index) override + { + if (index >= 0 && index < itemList.size()) + return itemList.takeAt(index); + else + return nullptr; + } + +private: + int doLayout(const QRect &rect, bool testOnly) const + { + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + int x = effectiveRect.x(); + int y = effectiveRect.y(); + int lineHeight = 0; + + for (QLayoutItem *item : itemList) { + QWidget *wid = item->widget(); + int spaceX = horizontalSpacing(); + if (spaceX == -1) + spaceX = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); + int spaceY = verticalSpacing(); + if (spaceY == -1) + spaceY = wid->style()->layoutSpacing( + QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); + int nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { + x = effectiveRect.x(); + y = y + lineHeight + spaceY; + nextX = x + item->sizeHint().width() + spaceX; + lineHeight = 0; + } + + if (!testOnly) + item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + + x = nextX; + lineHeight = qMax(lineHeight, item->sizeHint().height()); + } + return y + lineHeight - rect.y() + bottom; + } + + int smartSpacing(QStyle::PixelMetric pm) const + { + QObject *parent = this->parent(); + if (!parent) { + return -1; + } else if (parent->isWidgetType()) { + auto pw = static_cast(parent); + return pw->style()->pixelMetric(pm, nullptr, pw); + } else { + return static_cast(parent)->spacing(); + } + } + + QList itemList; + int m_hSpace; + int m_vSpace; +}; /*! \class Layouting::LayoutItem @@ -136,6 +283,23 @@ static void addItemToBoxLayout(QBoxLayout *layout, const ResultItem &item) } } +static void addItemToFlowLayout(FlowLayout *layout, const ResultItem &item) +{ + if (QWidget *w = item.widget) { + layout->addWidget(w); + } else if (QLayout *l = item.layout) { + layout->addItem(l); +// } else if (item.stretch != -1) { +// layout->addStretch(item.stretch); +// } else if (item.space != -1) { +// layout->addSpacing(item.space); + } else if (!item.text.isEmpty()) { + layout->addWidget(createLabel(item.text)); + } else { + QTC_CHECK(false); + } +} + void Slice::flush() { if (pendingItems.empty()) @@ -212,6 +376,11 @@ void Slice::flush() for (const ResultItem &item : std::as_const(pendingItems)) addItemToBoxLayout(boxLayout, item); + } else if (auto flowLayout = qobject_cast(layout)) { + + for (const ResultItem &item : std::as_const(pendingItems)) + addItemToFlowLayout(flowLayout, item); + } else if (auto stackLayout = qobject_cast(layout)) { for (const ResultItem &item : std::as_const(pendingItems)) { if (item.widget) @@ -425,6 +594,13 @@ Row::Row(std::initializer_list items) onExit = layoutExit; } +Flow::Flow(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new FlowLayout); }; + onExit = layoutExit; +} + Grid::Grid(std::initializer_list items) { subItems = items; @@ -809,3 +985,5 @@ void createItem(LayoutItem *item, const Span &t) } } // Layouting + +#include "layoutbuilder.moc" diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 5f69e0ef6a5..d716ad034c5 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -98,6 +98,12 @@ public: Row(std::initializer_list items); }; +class QTCREATOR_UTILS_EXPORT Flow : public LayoutItem +{ +public: + Flow(std::initializer_list items); +}; + class QTCREATOR_UTILS_EXPORT Grid : public LayoutItem { public: From 824de3046c439908372f164b397b324ca09da1fb Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 18:00:42 +0200 Subject: [PATCH 1090/1447] CppCheck: Rework settings handling Change-Id: Id9c9b316c5e0d39bc5fcba14951664e72d947a71 Reviewed-by: Alessandro Portale --- src/plugins/cppcheck/cppcheckconstants.h | 17 - .../cppcheck/cppcheckmanualrundialog.cpp | 19 +- .../cppcheck/cppcheckmanualrundialog.h | 8 +- src/plugins/cppcheck/cppcheckoptions.cpp | 300 +++++++----------- src/plugins/cppcheck/cppcheckoptions.h | 81 ++--- src/plugins/cppcheck/cppcheckplugin.cpp | 23 +- src/plugins/cppcheck/cppchecktool.cpp | 51 ++- src/plugins/cppcheck/cppchecktool.h | 8 +- 8 files changed, 174 insertions(+), 333 deletions(-) diff --git a/src/plugins/cppcheck/cppcheckconstants.h b/src/plugins/cppcheck/cppcheckconstants.h index 6efbb2f6158..427bdfc10fb 100644 --- a/src/plugins/cppcheck/cppcheckconstants.h +++ b/src/plugins/cppcheck/cppcheckconstants.h @@ -9,23 +9,6 @@ const char TEXTMARK_CATEGORY_ID[] = "Cppcheck"; const char OPTIONS_PAGE_ID[] = "Analyzer.Cppcheck.Settings"; -const char SETTINGS_ID[] = "Cppcheck"; -const char SETTINGS_BINARY[] = "binary"; -const char SETTINGS_WARNING[] = "warning"; -const char SETTINGS_STYLE[] = "style"; -const char SETTINGS_PERFORMANCE[] = "performance"; -const char SETTINGS_PORTABILITY[] = "portability"; -const char SETTINGS_INFORMATION[] = "information"; -const char SETTINGS_UNUSED_FUNCTION[] = "unusedFunction"; -const char SETTINGS_MISSING_INCLUDE[] = "missingInclude"; -const char SETTINGS_INCONCLUSIVE[] = "inconclusive"; -const char SETTINGS_FORCE_DEFINES[] = "forceDefines"; -const char SETTINGS_CUSTOM_ARGUMENTS[] = "customArguments"; -const char SETTINGS_IGNORE_PATTERNS[] = "ignorePatterns"; -const char SETTINGS_SHOW_OUTPUT[] = "showOutput"; -const char SETTINGS_ADD_INCLUDE_PATHS[] = "addIncludePaths"; -const char SETTINGS_GUESS_ARGUMENTS[] = "guessArguments"; - const char CHECK_PROGRESS_ID[] = "Cppcheck.CheckingTask"; const char MANUAL_CHECK_PROGRESS_ID[] = "Cppcheck.ManualCheckingTask"; diff --git a/src/plugins/cppcheck/cppcheckmanualrundialog.cpp b/src/plugins/cppcheck/cppcheckmanualrundialog.cpp index 1f53e6835bd..060f888cc25 100644 --- a/src/plugins/cppcheck/cppcheckmanualrundialog.cpp +++ b/src/plugins/cppcheck/cppcheckmanualrundialog.cpp @@ -18,11 +18,9 @@ namespace Cppcheck::Internal { -ManualRunDialog::ManualRunDialog(const CppcheckOptions &options, +ManualRunDialog::ManualRunDialog(QWidget *optionsWidget, const ProjectExplorer::Project *project) - : QDialog(), - m_options(new OptionsWidget(this)), - m_model(new ProjectExplorer::SelectableFilesFromDirModel(this)) + : m_model(new ProjectExplorer::SelectableFilesFromDirModel(this)) { QTC_ASSERT(project, return ); @@ -55,21 +53,12 @@ ManualRunDialog::ManualRunDialog(const CppcheckOptions &options, }); auto layout = new QVBoxLayout(this); - layout->addWidget(m_options); + layout->addWidget(optionsWidget); layout->addWidget(view); layout->addWidget(buttons); - if (auto layout = m_options->layout()) + if (auto layout = optionsWidget->layout()) layout->setContentsMargins(0, 0, 0, 0); - - m_options->load(options); -} - -CppcheckOptions ManualRunDialog::options() const -{ - CppcheckOptions result; - m_options->save(result); - return result; } Utils::FilePaths ManualRunDialog::filePaths() const diff --git a/src/plugins/cppcheck/cppcheckmanualrundialog.h b/src/plugins/cppcheck/cppcheckmanualrundialog.h index 8ffadcc48a2..460a85e75c4 100644 --- a/src/plugins/cppcheck/cppcheckmanualrundialog.h +++ b/src/plugins/cppcheck/cppcheckmanualrundialog.h @@ -17,21 +17,15 @@ class SelectableFilesFromDirModel; namespace Cppcheck::Internal { -class OptionsWidget; -class CppcheckOptions; - class ManualRunDialog : public QDialog { public: - ManualRunDialog(const CppcheckOptions &options, - const ProjectExplorer::Project *project); + ManualRunDialog(QWidget *optionsWidget, const ProjectExplorer::Project *project); - CppcheckOptions options() const; Utils::FilePaths filePaths() const; QSize sizeHint() const override; private: - OptionsWidget *m_options; ProjectExplorer::SelectableFilesFromDirModel *m_model; }; diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp index d91c9a6ebbe..46ab82cfeea 100644 --- a/src/plugins/cppcheck/cppcheckoptions.cpp +++ b/src/plugins/cppcheck/cppcheckoptions.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -20,220 +21,135 @@ #include #include -#include -#include - using namespace Utils; namespace Cppcheck::Internal { -OptionsWidget::OptionsWidget(QWidget *parent) - : QWidget(parent), - m_binary(new Utils::PathChooser(this)), - m_customArguments(new QLineEdit(this)), - m_ignorePatterns(new QLineEdit(this)), - m_warning(new QCheckBox(Tr::tr("Warnings"), this)), - m_style(new QCheckBox(Tr::tr("Style"), this)), - m_performance(new QCheckBox(Tr::tr("Performance"), this)), - m_portability(new QCheckBox(Tr::tr("Portability"), this)), - m_information(new QCheckBox(Tr::tr("Information"), this)), - m_unusedFunction(new QCheckBox(Tr::tr("Unused functions"), this)), - m_missingInclude(new QCheckBox(Tr::tr("Missing includes"), this)), - m_inconclusive(new QCheckBox(Tr::tr("Inconclusive errors"), this)), - m_forceDefines(new QCheckBox(Tr::tr("Check all define combinations"), this)), - m_showOutput(new QCheckBox(Tr::tr("Show raw output"), this)), - m_addIncludePaths(new QCheckBox(Tr::tr("Add include paths"), this)), - m_guessArguments(new QCheckBox(Tr::tr("Calculate additional arguments"), this)) -{ - m_binary->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_binary->setCommandVersionArguments({"--version"}); - - auto variableChooser = new Utils::VariableChooser(this); - variableChooser->addSupportedWidget (m_customArguments); - - m_unusedFunction->setToolTip(Tr::tr("Disables multithreaded check.")); - m_ignorePatterns->setToolTip(Tr::tr("Comma-separated wildcards of full file paths. " - "Files still can be checked if others include them.")); - m_addIncludePaths->setToolTip(Tr::tr("Can find missing includes but makes " - "checking slower. Use only when needed.")); - m_guessArguments->setToolTip(Tr::tr("Like C++ standard and language.")); - - auto layout = new QFormLayout(this); - layout->addRow(Tr::tr("Binary:"), m_binary); - - auto checks = new Utils::FlowLayout; - layout->addRow(Tr::tr("Checks:"), checks); - checks->addWidget(m_warning); - checks->addWidget(m_style); - checks->addWidget(m_performance); - checks->addWidget(m_portability); - checks->addWidget(m_information); - checks->addWidget(m_unusedFunction); - checks->addWidget(m_missingInclude); - - layout->addRow(Tr::tr("Custom arguments:"), m_customArguments); - layout->addRow(Tr::tr("Ignored file patterns:"), m_ignorePatterns); - auto flags = new Utils::FlowLayout; - layout->addRow(flags); - flags->addWidget(m_inconclusive); - flags->addWidget(m_forceDefines); - flags->addWidget(m_showOutput); - flags->addWidget(m_addIncludePaths); - flags->addWidget(m_guessArguments); -} - -void OptionsWidget::load(const CppcheckOptions &options) -{ - m_binary->setFilePath(options.binary); - m_customArguments->setText(options.customArguments); - m_ignorePatterns->setText(options.ignoredPatterns); - m_warning->setChecked(options.warning); - m_style->setChecked(options.style); - m_performance->setChecked(options.performance); - m_portability->setChecked(options.portability); - m_information->setChecked(options.information); - m_unusedFunction->setChecked(options.unusedFunction); - m_missingInclude->setChecked(options.missingInclude); - m_inconclusive->setChecked(options.inconclusive); - m_forceDefines->setChecked(options.forceDefines); - m_showOutput->setChecked(options.showOutput); - m_addIncludePaths->setChecked(options.addIncludePaths); - m_guessArguments->setChecked(options.guessArguments); -} - -void OptionsWidget::save(CppcheckOptions &options) const -{ - options.binary = m_binary->filePath(); - options.customArguments = m_customArguments->text(); - options.ignoredPatterns = m_ignorePatterns->text(); - options.warning = m_warning->isChecked(); - options.style = m_style->isChecked(); - options.performance = m_performance->isChecked(); - options.portability = m_portability->isChecked(); - options.information = m_information->isChecked(); - options.unusedFunction = m_unusedFunction->isChecked(); - options.missingInclude = m_missingInclude->isChecked(); - options.inconclusive = m_inconclusive->isChecked(); - options.forceDefines = m_forceDefines->isChecked(); - options.showOutput = m_showOutput->isChecked(); - options.addIncludePaths = m_addIncludePaths->isChecked(); - options.guessArguments = m_guessArguments->isChecked(); -} - -class CppcheckOptionsPageWidget : public Core::IOptionsPageWidget -{ -public: - CppcheckOptionsPageWidget(CppcheckOptionsPage *page) - : m_page(page) - { - m_optionWidget = new OptionsWidget; - - auto vbox = new QVBoxLayout(this); - vbox->addWidget(m_optionWidget); - vbox->setContentsMargins(0, 0, 0, 0); - - m_optionWidget->load(m_page->m_tool.options()); - } - - void apply() final - { - CppcheckOptions options; - m_optionWidget->save(options); - m_page->save(options); - m_page->m_tool.updateOptions(options); - m_page->m_trigger.recheck(); - } - - OptionsWidget *m_optionWidget; - CppcheckOptionsPage *m_page; -}; - -CppcheckOptionsPage::CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &trigger): - m_tool(tool), - m_trigger(trigger) +CppcheckOptions::CppcheckOptions() { setId(Constants::OPTIONS_PAGE_ID); setDisplayName(Tr::tr("Cppcheck")); setCategory("T.Analyzer"); setDisplayCategory(::Debugger::Tr::tr("Analyzer")); setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); + setSettingsGroup("Cppcheck"); - setWidgetCreator([this] { return new CppcheckOptionsPageWidget(this); }); - - CppcheckOptions options; + registerAspect(&binary); + binary.setSettingsKey("binary"); + binary.setDisplayStyle(StringAspect::PathChooserDisplay); + binary.setExpectedKind(PathChooser::ExistingCommand); + binary.setCommandVersionArguments({"--version"}); + binary.setLabelText(Tr::tr("Binary:")); if (HostOsInfo::isAnyUnixHost()) { - options.binary = "cppcheck"; + binary.setDefaultValue("cppcheck"); } else { FilePath programFiles = FilePath::fromUserInput(qtcEnvironmentVariable("PROGRAMFILES")); if (programFiles.isEmpty()) programFiles = "C:/Program Files"; - options.binary = programFiles / "Cppcheck/cppcheck.exe"; + binary.setDefaultValue(programFiles.pathAppended("Cppcheck/cppcheck.exe").toString()); } - load(options); + registerAspect(&warning); + warning.setSettingsKey("warning"); + warning.setDefaultValue(true); + warning.setLabelText(Tr::tr("Warnings")); - m_tool.updateOptions(options); + registerAspect(&style); + style.setSettingsKey("style"); + style.setDefaultValue(true); + style.setLabelText(Tr::tr("Style")); + + registerAspect(&performance); + performance.setSettingsKey("performance"); + performance.setDefaultValue(true); + performance.setLabelText(Tr::tr("Performance")); + + registerAspect(&portability); + portability.setSettingsKey("portability"); + portability.setDefaultValue(true); + portability.setLabelText(Tr::tr("Portability")); + + registerAspect(&information); + information.setSettingsKey("information"); + information.setDefaultValue(true); + information.setLabelText(Tr::tr("Information")); + + registerAspect(&unusedFunction); + unusedFunction.setSettingsKey("unusedFunction"); + unusedFunction.setLabelText(Tr::tr("Unused functions")); + unusedFunction.setToolTip(Tr::tr("Disables multithreaded check.")); + + registerAspect(&missingInclude); + missingInclude.setSettingsKey("missingInclude"); + missingInclude.setLabelText(Tr::tr("Missing includes")); + + registerAspect(&inconclusive); + inconclusive.setSettingsKey("inconclusive"); + inconclusive.setLabelText(Tr::tr("Inconclusive errors")); + + registerAspect(&forceDefines); + forceDefines.setSettingsKey("forceDefines"); + forceDefines.setLabelText(Tr::tr("Check all define combinations")); + + registerAspect(&customArguments); + customArguments.setSettingsKey("customArguments"); + customArguments.setDisplayStyle(StringAspect::LineEditDisplay); + customArguments.setLabelText(Tr::tr("Custom arguments:")); + + registerAspect(&ignoredPatterns); + ignoredPatterns.setSettingsKey("ignoredPatterns"); + ignoredPatterns.setDisplayStyle(StringAspect::LineEditDisplay); + ignoredPatterns.setLabelText(Tr::tr("Ignored file patterns:")); + ignoredPatterns.setToolTip(Tr::tr("Comma-separated wildcards of full file paths. " + "Files still can be checked if others include them.")); + + registerAspect(&showOutput); + showOutput.setSettingsKey("showOutput"); + showOutput.setLabelText(Tr::tr("Show raw output")); + + registerAspect(&addIncludePaths); + addIncludePaths.setSettingsKey("addIncludePaths"); + addIncludePaths.setLabelText(Tr::tr("Add include paths")); + addIncludePaths.setToolTip(Tr::tr("Can find missing includes but makes " + "checking slower. Use only when needed.")); + + registerAspect(&guessArguments); + guessArguments.setSettingsKey("guessArguments"); + guessArguments.setDefaultValue(true); + guessArguments.setLabelText(Tr::tr("Calculate additional arguments")); + guessArguments.setToolTip(Tr::tr("Like C++ standard and language.")); + + setLayouter(layouter()); + + readSettings(Core::ICore::settings()); } -void CppcheckOptionsPage::save(const CppcheckOptions &options) const +std::function CppcheckOptions::layouter() { - QSettings *s = Core::ICore::settings(); - QTC_ASSERT(s, return); - s->beginGroup(Constants::SETTINGS_ID); - s->setValue(Constants::SETTINGS_BINARY, options.binary.toString()); - s->setValue(Constants::SETTINGS_CUSTOM_ARGUMENTS, options.customArguments); - s->setValue(Constants::SETTINGS_IGNORE_PATTERNS, options.ignoredPatterns); - s->setValue(Constants::SETTINGS_WARNING, options.warning); - s->setValue(Constants::SETTINGS_STYLE, options.style); - s->setValue(Constants::SETTINGS_PERFORMANCE, options.performance); - s->setValue(Constants::SETTINGS_PORTABILITY, options.portability); - s->setValue(Constants::SETTINGS_INFORMATION, options.information); - s->setValue(Constants::SETTINGS_UNUSED_FUNCTION, options.unusedFunction); - s->setValue(Constants::SETTINGS_MISSING_INCLUDE, options.missingInclude); - s->setValue(Constants::SETTINGS_INCONCLUSIVE, options.inconclusive); - s->setValue(Constants::SETTINGS_FORCE_DEFINES, options.forceDefines); - s->setValue(Constants::SETTINGS_SHOW_OUTPUT, options.showOutput); - s->setValue(Constants::SETTINGS_ADD_INCLUDE_PATHS, options.addIncludePaths); - s->setValue(Constants::SETTINGS_GUESS_ARGUMENTS, options.guessArguments); - s->endGroup(); -} - -void CppcheckOptionsPage::load(CppcheckOptions &options) const -{ - QSettings *s = Core::ICore::settings(); - QTC_ASSERT(s, return); - s->beginGroup(Constants::SETTINGS_ID); - options.binary = FilePath::fromString(s->value(Constants::SETTINGS_BINARY, - options.binary.toString()).toString()); - options.customArguments = s->value(Constants::SETTINGS_CUSTOM_ARGUMENTS, - options.customArguments).toString(); - options.ignoredPatterns = s->value(Constants::SETTINGS_IGNORE_PATTERNS, - options.ignoredPatterns).toString(); - options.warning = s->value(Constants::SETTINGS_WARNING, - options.warning).toBool(); - options.style = s->value(Constants::SETTINGS_STYLE, - options.style).toBool(); - options.performance = s->value(Constants::SETTINGS_PERFORMANCE, - options.performance).toBool(); - options.portability = s->value(Constants::SETTINGS_PORTABILITY, - options.portability).toBool(); - options.information = s->value(Constants::SETTINGS_INFORMATION, - options.information).toBool(); - options.unusedFunction = s->value(Constants::SETTINGS_UNUSED_FUNCTION, - options.unusedFunction).toBool(); - options.missingInclude = s->value(Constants::SETTINGS_MISSING_INCLUDE, - options.missingInclude).toBool(); - options.inconclusive = s->value(Constants::SETTINGS_INCONCLUSIVE, - options.inconclusive).toBool(); - options.forceDefines = s->value(Constants::SETTINGS_FORCE_DEFINES, - options.forceDefines).toBool(); - options.showOutput = s->value(Constants::SETTINGS_SHOW_OUTPUT, - options.showOutput).toBool(); - options.addIncludePaths = s->value(Constants::SETTINGS_ADD_INCLUDE_PATHS, - options.addIncludePaths).toBool(); - options.guessArguments = s->value(Constants::SETTINGS_GUESS_ARGUMENTS, - options.guessArguments).toBool(); - s->endGroup(); + return [this](QWidget *widget) { + using namespace Layouting; + Form { + binary, br, + Tr::tr("Checks:"), Flow { + warning, + style, + performance, + portability, + information, + unusedFunction, + missingInclude + }, br, + customArguments, br, + ignoredPatterns, br, + Flow { + inconclusive, + forceDefines, + showOutput, + addIncludePaths, + guessArguments + } + }.attachTo(widget); + }; } } // Cppcheck::Internal diff --git a/src/plugins/cppcheck/cppcheckoptions.h b/src/plugins/cppcheck/cppcheckoptions.h index 48526cd540f..84fbf483bbb 100644 --- a/src/plugins/cppcheck/cppcheckoptions.h +++ b/src/plugins/cppcheck/cppcheckoptions.h @@ -4,80 +4,35 @@ #pragma once #include -#include - -QT_BEGIN_NAMESPACE -class QLineEdit; -class QCheckBox; -QT_END_NAMESPACE - -namespace Utils { class PathChooser; } namespace Cppcheck::Internal { class CppcheckTool; class CppcheckTrigger; -class OptionsWidget; -class CppcheckOptions final +class CppcheckOptions final : public Core::PagedSettings { public: - Utils::FilePath binary; + CppcheckOptions(); - bool warning = true; - bool style = true; - bool performance = true; - bool portability = true; - bool information = true; - bool unusedFunction = false; - bool missingInclude = false; - bool inconclusive = false; - bool forceDefines = false; + std::function layouter(); - QString customArguments; - QString ignoredPatterns; - bool showOutput = false; - bool addIncludePaths = false; - bool guessArguments = true; -}; + Utils::StringAspect binary; + Utils::BoolAspect warning; + Utils::BoolAspect style; + Utils::BoolAspect performance; + Utils::BoolAspect portability; + Utils::BoolAspect information; + Utils::BoolAspect unusedFunction; + Utils::BoolAspect missingInclude; + Utils::BoolAspect inconclusive; + Utils::BoolAspect forceDefines; -class OptionsWidget final : public QWidget -{ -public: - explicit OptionsWidget(QWidget *parent = nullptr); - void load(const CppcheckOptions &options); - void save(CppcheckOptions &options) const; - -private: - Utils::PathChooser *m_binary = nullptr; - QLineEdit *m_customArguments = nullptr; - QLineEdit *m_ignorePatterns = nullptr; - QCheckBox *m_warning = nullptr; - QCheckBox *m_style = nullptr; - QCheckBox *m_performance = nullptr; - QCheckBox *m_portability = nullptr; - QCheckBox *m_information = nullptr; - QCheckBox *m_unusedFunction = nullptr; - QCheckBox *m_missingInclude = nullptr; - QCheckBox *m_inconclusive = nullptr; - QCheckBox *m_forceDefines = nullptr; - QCheckBox *m_showOutput = nullptr; - QCheckBox *m_addIncludePaths = nullptr; - QCheckBox *m_guessArguments = nullptr; -}; - -class CppcheckOptionsPage final : public Core::IOptionsPage -{ -public: - explicit CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &trigger); - -private: - friend class CppcheckOptionsPageWidget; - void save(const CppcheckOptions &options) const; - void load(CppcheckOptions &options) const; - - CppcheckTool &m_tool; - CppcheckTrigger &m_trigger; + Utils::StringAspect customArguments; + Utils::StringAspect ignoredPatterns; + Utils::BoolAspect showOutput; + Utils::BoolAspect addIncludePaths; + Utils::BoolAspect guessArguments; }; } // Cppcheck::Internal diff --git a/src/plugins/cppcheck/cppcheckplugin.cpp b/src/plugins/cppcheck/cppcheckplugin.cpp index 8d44f0dda56..890e2e3c0ad 100644 --- a/src/plugins/cppcheck/cppcheckplugin.cpp +++ b/src/plugins/cppcheck/cppcheckplugin.cpp @@ -28,6 +28,8 @@ #include #include +using namespace Utils; + namespace Cppcheck::Internal { class CppcheckPluginPrivate final : public QObject @@ -36,11 +38,11 @@ public: explicit CppcheckPluginPrivate(); CppcheckTextMarkManager marks; - CppcheckTool tool{marks, Constants::CHECK_PROGRESS_ID}; + CppcheckOptions options; + CppcheckTool tool{options, marks, Constants::CHECK_PROGRESS_ID}; CppcheckTrigger trigger{marks, tool}; - CppcheckOptionsPage options{tool, trigger}; DiagnosticsModel manualRunModel; - CppcheckTool manualRunTool{manualRunModel, Constants::MANUAL_CHECK_PROGRESS_ID}; + CppcheckTool manualRunTool{options, manualRunModel, Constants::MANUAL_CHECK_PROGRESS_ID}; Utils::Perspective perspective{Constants::PERSPECTIVE_ID, ::Cppcheck::Tr::tr("Cppcheck")}; QAction *manualRunAction; @@ -51,7 +53,11 @@ public: CppcheckPluginPrivate::CppcheckPluginPrivate() { - manualRunTool.updateOptions(tool.options()); + tool.updateOptions(); + connect(&options, &AspectContainer::changed, [this] { + tool.updateOptions(); + trigger.recheck(); + }); auto manualRunView = new DiagnosticView; manualRunView->setModel(&manualRunModel); @@ -103,7 +109,12 @@ void CppcheckPluginPrivate::startManualRun() if (!project) return; - ManualRunDialog dialog(manualRunTool.options(), project); + manualRunTool.updateOptions(); + + auto optionsWidget = new QWidget; + options.layouter()(optionsWidget); + + ManualRunDialog dialog(optionsWidget, project); if (dialog.exec() == ManualRunDialog::Rejected) return; @@ -114,7 +125,7 @@ void CppcheckPluginPrivate::startManualRun() return; manualRunTool.setProject(project); - manualRunTool.updateOptions(dialog.options()); + manualRunTool.updateOptions(); manualRunTool.check(files); perspective.select(); } diff --git a/src/plugins/cppcheck/cppchecktool.cpp b/src/plugins/cppcheck/cppchecktool.cpp index a5c3bc6afb5..bd44957c379 100644 --- a/src/plugins/cppcheck/cppchecktool.cpp +++ b/src/plugins/cppcheck/cppchecktool.cpp @@ -26,7 +26,8 @@ using namespace Utils; namespace Cppcheck::Internal { -CppcheckTool::CppcheckTool(CppcheckDiagnosticManager &manager, const Id &progressId) : +CppcheckTool::CppcheckTool(CppcheckOptions &options, CppcheckDiagnosticManager &manager, const Id &progressId) : + m_options(options), m_manager(manager), m_progressRegexp("^.* checked (\\d+)% done$"), m_messageRegexp("^(.+),(\\d+),(\\w+),(\\w+),(.*)$"), @@ -39,11 +40,10 @@ CppcheckTool::CppcheckTool(CppcheckDiagnosticManager &manager, const Id &progres CppcheckTool::~CppcheckTool() = default; -void CppcheckTool::updateOptions(const CppcheckOptions &options) +void CppcheckTool::updateOptions() { - m_options = options; m_filters.clear(); - for (const QString &pattern : m_options.ignoredPatterns.split(',')) { + for (const QString &pattern : m_options.ignoredPatterns().split(',')) { const QString trimmedPattern = pattern.trimmed(); if (trimmedPattern.isEmpty()) continue; @@ -70,44 +70,44 @@ void CppcheckTool::updateArguments() m_cachedAdditionalArguments.clear(); QStringList arguments; - if (!m_options.customArguments.isEmpty()) { + if (!m_options.customArguments().isEmpty()) { Utils::MacroExpander *expander = Utils::globalMacroExpander(); - const QString expanded = expander->expand(m_options.customArguments); + const QString expanded = expander->expand(m_options.customArguments()); arguments.push_back(expanded); } - if (m_options.warning) + if (m_options.warning()) arguments.push_back("--enable=warning"); - if (m_options.style) + if (m_options.style()) arguments.push_back("--enable=style"); - if (m_options.performance) + if (m_options.performance()) arguments.push_back("--enable=performance"); - if (m_options.portability) + if (m_options.portability()) arguments.push_back("--enable=portability"); - if (m_options.information) + if (m_options.information()) arguments.push_back("--enable=information"); - if (m_options.unusedFunction) + if (m_options.unusedFunction()) arguments.push_back("--enable=unusedFunction"); - if (m_options.missingInclude) + if (m_options.missingInclude()) arguments.push_back("--enable=missingInclude"); - if (m_options.inconclusive) + if (m_options.inconclusive()) arguments.push_back("--inconclusive"); - if (m_options.forceDefines) + if (m_options.forceDefines()) arguments.push_back("--force"); - if (!m_options.unusedFunction && !m_options.customArguments.contains("-j ")) + if (!m_options.unusedFunction() && !m_options.customArguments().contains("-j ")) arguments.push_back("-j " + QString::number(QThread::idealThreadCount())); arguments.push_back("--template=\"{file},{line},{severity},{id},{message}\""); - m_runner->reconfigure(m_options.binary, arguments.join(' ')); + m_runner->reconfigure(m_options.binary.filePath(), arguments.join(' ')); } QStringList CppcheckTool::additionalArguments(const CppEditor::ProjectPart &part) const { QStringList result; - if (m_options.addIncludePaths) { + if (m_options.addIncludePaths()) { for (const ProjectExplorer::HeaderPath &path : part.headerPaths) { const QString projectDir = m_project->projectDirectory().toString(); if (path.type == ProjectExplorer::HeaderPathType::User @@ -116,7 +116,7 @@ QStringList CppcheckTool::additionalArguments(const CppEditor::ProjectPart &part } } - if (!m_options.guessArguments) + if (!m_options.guessArguments()) return result; using Version = Utils::LanguageVersion; @@ -158,11 +158,6 @@ QStringList CppcheckTool::additionalArguments(const CppEditor::ProjectPart &part return result; } -const CppcheckOptions &CppcheckTool::options() const -{ - return m_options; -} - void CppcheckTool::check(const Utils::FilePaths &files) { QTC_ASSERT(m_project, return); @@ -226,7 +221,7 @@ void CppcheckTool::stop(const Utils::FilePaths &files) void CppcheckTool::startParsing() { - if (m_options.showOutput) { + if (m_options.showOutput()) { const QString message = Tr::tr("Cppcheck started: \"%1\".").arg(m_runner->currentCommand()); Core::MessageManager::writeSilently(message); } @@ -245,7 +240,7 @@ void CppcheckTool::parseOutputLine(const QString &line) if (line.isEmpty()) return; - if (m_options.showOutput) + if (m_options.showOutput()) Core::MessageManager::writeSilently(line); enum Matches { Percentage = 1 }; @@ -276,7 +271,7 @@ void CppcheckTool::parseErrorLine(const QString &line) if (line.isEmpty()) return; - if (m_options.showOutput) + if (m_options.showOutput()) Core::MessageManager::writeSilently(line); enum Matches { File = 1, Line, Severity, Id, Message }; @@ -301,7 +296,7 @@ void CppcheckTool::parseErrorLine(const QString &line) void CppcheckTool::finishParsing() { - if (m_options.showOutput) + if (m_options.showOutput()) Core::MessageManager::writeSilently(Tr::tr("Cppcheck finished.")); QTC_ASSERT(m_progress, return); diff --git a/src/plugins/cppcheck/cppchecktool.h b/src/plugins/cppcheck/cppchecktool.h index ccb8e19d0fe..4dc6699e336 100644 --- a/src/plugins/cppcheck/cppchecktool.h +++ b/src/plugins/cppcheck/cppchecktool.h @@ -31,10 +31,10 @@ class CppcheckTool final : public QObject Q_OBJECT public: - CppcheckTool(CppcheckDiagnosticManager &manager, const Utils::Id &progressId); + CppcheckTool(CppcheckOptions &options, CppcheckDiagnosticManager &manager, const Utils::Id &progressId); ~CppcheckTool() override; - void updateOptions(const CppcheckOptions &options); + void updateOptions(); void setProject(ProjectExplorer::Project *project); void check(const Utils::FilePaths &files); void stop(const Utils::FilePaths &files); @@ -44,15 +44,13 @@ public: void parseErrorLine(const QString &line); void finishParsing(); - const CppcheckOptions &options() const; - private: void updateArguments(); void addToQueue(const Utils::FilePaths &files, const CppEditor::ProjectPart &part); QStringList additionalArguments(const CppEditor::ProjectPart &part) const; + CppcheckOptions &m_options; CppcheckDiagnosticManager &m_manager; - CppcheckOptions m_options; QPointer m_project; std::unique_ptr m_runner; std::unique_ptr> m_progress; From 6c5fb656d63efddcdc7e98e58aae04f2ae718c50 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 16 May 2023 13:06:18 +0200 Subject: [PATCH 1091/1447] Utils: Make PagedSettings::readSettings() calls shorter Ideally, this would not be needed on the user code side at all, but there's no way to ensure the settings are read timing before sibling constructors might need it. So keep the 'poor man's two-phase initialization', but make it less intrusive. Change-Id: Ica7f6510cd05072d7286f4e85cd72c494e8f10f8 Reviewed-by: Alessandro Portale --- src/plugins/cmakeprojectmanager/cmakeformatter.cpp | 3 +-- src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp | 2 +- src/plugins/coreplugin/dialogs/ioptionspage.cpp | 5 +++++ src/plugins/coreplugin/dialogs/ioptionspage.h | 3 +++ src/plugins/cppcheck/cppcheckoptions.cpp | 2 +- src/plugins/docker/dockersettings.cpp | 4 +--- src/plugins/nim/settings/nimsettings.cpp | 2 +- src/plugins/qmakeprojectmanager/qmakesettings.cpp | 4 +--- src/plugins/vcpkg/vcpkgsettings.cpp | 4 +--- src/plugins/vcsbase/vcsbaseclient.cpp | 2 +- 10 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp index 3996946e470..778e04563da 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -112,7 +111,7 @@ public: connect(EditorManager::instance(), &EditorManager::aboutToSave, this, &CMakeFormatterPrivate::applyIfNecessary); - readSettings(ICore::settings()); + readSettings(); } bool isApplicable(const IDocument *document) const; diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index 5c22423a40d..7875f97ada2 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -95,7 +95,7 @@ CMakeSpecificSettings::CMakeSpecificSettings() showAdvancedOptionsByDefault.setLabelText( ::CMakeProjectManager::Tr::tr("Show advanced options by default")); - readSettings(Core::ICore::settings()); + readSettings(); } } // CMakeProjectManager::Internal diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index 070cc6159b4..bb9b80a9133 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -309,4 +309,9 @@ PagedSettings::PagedSettings() setAutoApply(false); } +void PagedSettings::readSettings() +{ + return AspectContainer::readSettings(Core::ICore::settings()); +} + } // Core diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 256f729a9e4..96d9b6824af 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -132,6 +132,9 @@ class CORE_EXPORT PagedSettings : public Utils::AspectContainer, public IOptions { public: PagedSettings(); + + using AspectContainer::readSettings; // FIXME: Remove. + void readSettings(); // Intentionally hides AspectContainer::readSettings() }; } // namespace Core diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp index 46ab82cfeea..37f537f2fee 100644 --- a/src/plugins/cppcheck/cppcheckoptions.cpp +++ b/src/plugins/cppcheck/cppcheckoptions.cpp @@ -121,7 +121,7 @@ CppcheckOptions::CppcheckOptions() setLayouter(layouter()); - readSettings(Core::ICore::settings()); + readSettings(); } std::function CppcheckOptions::layouter() diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp index 4adb98af9cc..a43e7a20d3b 100644 --- a/src/plugins/docker/dockersettings.cpp +++ b/src/plugins/docker/dockersettings.cpp @@ -6,8 +6,6 @@ #include "dockerconstants.h" #include "dockertr.h" -#include - #include #include @@ -55,7 +53,7 @@ DockerSettings::DockerSettings() dockerBinaryPath.setLabelText(Tr::tr("Command:")); dockerBinaryPath.setSettingsKey("cli"); - readSettings(Core::ICore::settings()); + readSettings(); } } // Docker::Internal diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp index d99ae2974b8..5e98b0fd536 100644 --- a/src/plugins/nim/settings/nimsettings.cpp +++ b/src/plugins/nim/settings/nimsettings.cpp @@ -92,7 +92,7 @@ NimSettings::NimSettings() nimSuggestPath.setExpectedKind(PathChooser::ExistingCommand); nimSuggestPath.setLabelText(Tr::tr("Path:")); - readSettings(Core::ICore::settings()); + readSettings(); } NimSettings::~NimSettings() diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.cpp b/src/plugins/qmakeprojectmanager/qmakesettings.cpp index 5a05e5904d9..292851e444b 100644 --- a/src/plugins/qmakeprojectmanager/qmakesettings.cpp +++ b/src/plugins/qmakeprojectmanager/qmakesettings.cpp @@ -4,8 +4,6 @@ #include "qmakesettings.h" #include "qmakeprojectmanagertr.h" -#include - #include #include @@ -63,7 +61,7 @@ QmakeSettings::QmakeSettings() }.attachTo(widget); }); - readSettings(Core::ICore::settings()); + readSettings(); } } // QmakeProjectManager::Internal diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp index 16622fe8b37..85b4b6f4faa 100644 --- a/src/plugins/vcpkg/vcpkgsettings.cpp +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -5,8 +5,6 @@ #include "vcpkgconstants.h" -#include - #include #include @@ -67,7 +65,7 @@ VcpkgSettings::VcpkgSettings() vcpkgRoot.setExpectedKind(Utils::PathChooser::ExistingDirectory); vcpkgRoot.setDefaultValue(Utils::qtcEnvironmentVariable(Constants::ENVVAR_VCPKG_ROOT)); - readSettings(Core::ICore::settings()); + readSettings(); } bool VcpkgSettings::vcpkgRootValid() const diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index 527db5387c0..9bd83df3c37 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -57,7 +57,7 @@ namespace VcsBase { VcsBaseClientImpl::VcsBaseClientImpl(VcsBaseSettings *baseSettings) : m_baseSettings(baseSettings) { - m_baseSettings->readSettings(ICore::settings()); + m_baseSettings->readSettings(); connect(ICore::instance(), &ICore::saveSettingsRequested, this, &VcsBaseClientImpl::saveSettings); } From 330a30aa5b7562cf8d68f3bd870d3c9b5d15b2fc Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 16 May 2023 14:30:51 +0200 Subject: [PATCH 1092/1447] Doc: Hide text and links that only apply to Qt Creator Manual ...from the QDS manual. Change-Id: I24be3b656922b1c10643f6ef274f1fa91c8330df Reviewed-by: Mats Honkamaa --- doc/qtcreator/src/user-interface/creator-views.qdoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/qtcreator/src/user-interface/creator-views.qdoc b/doc/qtcreator/src/user-interface/creator-views.qdoc index 856dfd15eef..e676ed18907 100644 --- a/doc/qtcreator/src/user-interface/creator-views.qdoc +++ b/doc/qtcreator/src/user-interface/creator-views.qdoc @@ -88,6 +88,7 @@ (\uicontrol {Synchronize with Editor}). \endlist + \if defined(qtcreator) \section1 Viewing the Class Hierarchy The \uicontrol {Class View} shows the class hierarchy of the currently @@ -144,4 +145,5 @@ To keep the view synchronized with the file currently open in the editor, select \inlineimage icons/linkicon.png (\uicontrol {Synchronize with Editor}). + \endif */ From 337497d990bbfb52f27b5ba7019cdd0fb9c6d5fe Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 18:32:01 +0200 Subject: [PATCH 1093/1447] Vcs: Use new FilePathAspect in a few places Change-Id: Idc23616dd3b7bc21301471cb48e2893116b83f0d Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarplugin.cpp | 2 +- src/plugins/bazaar/bazaarsettings.cpp | 1 - src/plugins/cvs/cvsplugin.cpp | 6 +++--- src/plugins/cvs/cvssettings.cpp | 1 - src/plugins/fossil/fossilsettings.cpp | 1 - src/plugins/mercurial/mercurialclient.cpp | 2 +- src/plugins/mercurial/mercurialplugin.cpp | 2 +- src/plugins/mercurial/mercurialsettings.cpp | 1 - src/plugins/subversion/subversionclient.cpp | 2 +- src/plugins/subversion/subversionplugin.cpp | 12 ++++++------ src/plugins/vcsbase/vcsbaseclient.cpp | 2 +- src/plugins/vcsbase/vcsbaseclientsettings.h | 2 +- 12 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index 110e990447d..d992d70eba1 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -871,7 +871,7 @@ bool BazaarPluginPrivate::managesFile(const FilePath &workingDirectory, const QS bool BazaarPluginPrivate::isConfigured() const { - const FilePath binary = settings().binaryPath.filePath(); + const FilePath binary = settings().binaryPath(); return !binary.isEmpty() && binary.isExecutableFile(); } diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp index 231562edc1b..1b2840084cb 100644 --- a/src/plugins/bazaar/bazaarsettings.cpp +++ b/src/plugins/bazaar/bazaarsettings.cpp @@ -33,7 +33,6 @@ BazaarSettings::BazaarSettings() setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); registerAspect(&binaryPath); - binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setDefaultValue(Constants::BAZAARDEFAULT); binaryPath.setDisplayName(Tr::tr("Bazaar Command")); diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 076f2ad8b28..d9980328fc9 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -366,7 +366,7 @@ bool CvsPluginPrivate::isVcsFileOrDirectory(const Utils::FilePath &filePath) con bool CvsPluginPrivate::isConfigured() const { - const FilePath binary = settings().binaryPath.filePath(); + const FilePath binary = settings().binaryPath(); if (binary.isEmpty()) return false; QFileInfo fi = binary.toFileInfo(); @@ -439,7 +439,7 @@ VcsCommand *CvsPluginPrivate::createInitialCheckoutCommand(const QString &url, auto command = VcsBaseClient::createVcsCommand(baseDirectory, Environment::systemEnvironment()); command->setDisplayName(Tr::tr("CVS Checkout")); - command->addJob({settings().binaryPath.filePath(), settings().addOptions(args)}, -1); + command->addJob({settings().binaryPath(), settings().addOptions(args)}, -1); return command; } @@ -1321,7 +1321,7 @@ CommandResult CvsPluginPrivate::runCvs(const FilePath &workingDirectory, const QStringList &arguments, RunFlags flags, QTextCodec *outputCodec, int timeoutMultiplier) const { - const FilePath executable = settings().binaryPath.filePath(); + const FilePath executable = settings().binaryPath(); if (executable.isEmpty()) return CommandResult(ProcessResult::StartFailed, Tr::tr("No CVS executable specified.")); diff --git a/src/plugins/cvs/cvssettings.cpp b/src/plugins/cvs/cvssettings.cpp index f18feeed661..dbfd41e500c 100644 --- a/src/plugins/cvs/cvssettings.cpp +++ b/src/plugins/cvs/cvssettings.cpp @@ -35,7 +35,6 @@ CvsSettings::CvsSettings() registerAspect(&binaryPath); binaryPath.setDefaultValue("cvs" QTC_HOST_EXE_SUFFIX); - binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setHistoryCompleter(QLatin1String("Cvs.Command.History")); binaryPath.setDisplayName(Tr::tr("CVS Command")); diff --git a/src/plugins/fossil/fossilsettings.cpp b/src/plugins/fossil/fossilsettings.cpp index ca248021143..b72f6b76234 100644 --- a/src/plugins/fossil/fossilsettings.cpp +++ b/src/plugins/fossil/fossilsettings.cpp @@ -34,7 +34,6 @@ FossilSettings::FossilSettings() setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); registerAspect(&binaryPath); - binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setDefaultValue(Constants::FOSSILDEFAULT); binaryPath.setDisplayName(Tr::tr("Fossil Command")); diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 20e4d3745dd..6a0c2574d43 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -428,7 +428,7 @@ void MercurialClient::requestReload(const QString &documentId, const FilePath &s IDocument *document = DiffEditorController::findOrCreateDocument(documentId, title); QTC_ASSERT(document, return); auto controller = new MercurialDiffEditorController(document, args); - controller->setVcsBinary(settings().binaryPath.filePath()); + controller->setVcsBinary(settings().binaryPath()); controller->setProcessEnvironment(processEnvironment()); controller->setWorkingDirectory(workingDirectory); diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index a6bd955c3a7..05b3524b4de 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -715,7 +715,7 @@ bool MercurialPluginPrivate::managesFile(const FilePath &workingDirectory, const bool MercurialPluginPrivate::isConfigured() const { - const FilePath binary = settings().binaryPath.filePath(); + const FilePath binary = settings().binaryPath(); if (binary.isEmpty()) return false; QFileInfo fi = binary.toFileInfo(); diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp index dd63faddc05..0b84187b1b4 100644 --- a/src/plugins/mercurial/mercurialsettings.cpp +++ b/src/plugins/mercurial/mercurialsettings.cpp @@ -34,7 +34,6 @@ MercurialSettings::MercurialSettings() setAutoApply(false); registerAspect(&binaryPath); - binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setDefaultValue(Constants::MERCURIALDEFAULT); binaryPath.setDisplayName(Tr::tr("Mercurial Command")); diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index b81656f1452..3146f066d6e 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -240,7 +240,7 @@ SubversionDiffEditorController *SubversionClient::findOrCreateDiffEditor(const Q DiffEditorController::controller(document)); if (!controller) { controller = new SubversionDiffEditorController(document); - controller->setVcsBinary(settings.binaryPath.filePath()); + controller->setVcsBinary(settings.binaryPath()); controller->setProcessEnvironment(processEnvironment()); controller->setWorkingDirectory(workingDirectory); } diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 957947a89a6..5cb7475edb0 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -638,7 +638,7 @@ void SubversionPluginPrivate::revertAll() QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) return; // NoteL: Svn "revert ." doesn not work. - CommandLine args{settings().binaryPath.filePath(), {"revert"}}; + CommandLine args{settings().binaryPath(), {"revert"}}; args << SubversionClient::AddAuthOptions(); args << QLatin1String("--recursive") << state.topLevel().toString(); const auto revertResponse = runSvn(state.topLevel(), args, RunFlags::ShowStdOut); @@ -655,7 +655,7 @@ void SubversionPluginPrivate::revertCurrentFile() const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasFile(), return); - CommandLine diffArgs{settings().binaryPath.filePath(), {"diff"}}; + CommandLine diffArgs{settings().binaryPath(), {"diff"}}; diffArgs << SubversionClient::AddAuthOptions(); diffArgs << SubversionClient::escapeFile(state.relativeCurrentFile()); @@ -673,7 +673,7 @@ void SubversionPluginPrivate::revertCurrentFile() FileChangeBlocker fcb(state.currentFile()); // revert - CommandLine args{settings().binaryPath.filePath(), {"revert"}}; + CommandLine args{settings().binaryPath(), {"revert"}}; args << SubversionClient::AddAuthOptions(); args << SubversionClient::escapeFile(state.relativeCurrentFile()); @@ -734,7 +734,7 @@ void SubversionPluginPrivate::startCommit(const FilePath &workingDir, const QStr return; } - CommandLine args{settings().binaryPath.filePath(), {"status"}}; + CommandLine args{settings().binaryPath(), {"status"}}; args << SubversionClient::AddAuthOptions(); args << SubversionClient::escapeFiles(files); @@ -813,7 +813,7 @@ void SubversionPluginPrivate::svnStatus(const FilePath &workingDir, const QStrin { const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasTopLevel(), return); - CommandLine args{settings().binaryPath.filePath(), {"status"}}; + CommandLine args{settings().binaryPath(), {"status"}}; args << SubversionClient::AddAuthOptions(); if (!relativePath.isEmpty()) args << SubversionClient::escapeFile(relativePath); @@ -839,7 +839,7 @@ void SubversionPluginPrivate::updateProject() void SubversionPluginPrivate::svnUpdate(const FilePath &workingDir, const QString &relativePath) { - CommandLine args{settings().binaryPath.filePath(), {"update"}}; + CommandLine args{settings().binaryPath(), {"update"}}; args << SubversionClient::AddAuthOptions(); args << Constants::NON_INTERACTIVE_OPTION; if (!relativePath.isEmpty()) diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index 9bd83df3c37..ffa19b24f78 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -69,7 +69,7 @@ VcsBaseSettings &VcsBaseClientImpl::settings() const FilePath VcsBaseClientImpl::vcsBinary() const { - return m_baseSettings->binaryPath.filePath(); + return m_baseSettings->binaryPath(); } VcsCommand *VcsBaseClientImpl::createCommand(const FilePath &workingDirectory, diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.h b/src/plugins/vcsbase/vcsbaseclientsettings.h index 9a034e5f924..ec5ad3aab09 100644 --- a/src/plugins/vcsbase/vcsbaseclientsettings.h +++ b/src/plugins/vcsbase/vcsbaseclientsettings.h @@ -15,7 +15,7 @@ public: VcsBaseSettings(); ~VcsBaseSettings(); - Utils::StringAspect binaryPath; + Utils::FilePathAspect binaryPath; Utils::StringAspect userName; Utils::StringAspect userEmail; Utils::IntegerAspect logCount; From a21b96f4b6bc252c20824c0d807583df4b905f49 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 12 May 2023 10:09:52 +0200 Subject: [PATCH 1094/1447] Utils: Allow a BoolAspect to adopt an external button This will be used by the apply machinery and allows more complex setups than the automatically generated internal CheckBox button. Change-Id: I237a9283253f11bcb76e0366a0b6c5a0346fdfd8 Reviewed-by: Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 16 ++++++++++++++-- src/libs/utils/aspects.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 541b258c0bb..549a3942730 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -587,6 +587,7 @@ public: BoolAspect::LabelPlacement m_labelPlacement = BoolAspect::LabelPlacement::AtCheckBox; QPointer m_button; // Owned by configuration widget QPointer m_groupBox; // For BoolAspects handling GroupBox check boxes + bool m_buttonIsAdopted = false; }; class ColorAspectPrivate @@ -1446,8 +1447,10 @@ BoolAspect::~BoolAspect() = default; */ void BoolAspect::addToLayout(Layouting::LayoutItem &parent) { - QTC_CHECK(!d->m_button); - d->m_button = createSubWidget(); + if (!d->m_buttonIsAdopted) { + QTC_CHECK(!d->m_button); + d->m_button = createSubWidget(); + } switch (d->m_labelPlacement) { case LabelPlacement::AtCheckBoxWithoutDummyLabel: d->m_button->setText(labelText()); @@ -1474,6 +1477,15 @@ void BoolAspect::addToLayout(Layouting::LayoutItem &parent) this, &BoolAspect::volatileValueChanged); } +void BoolAspect::adoptButton(QAbstractButton *button) +{ + QTC_ASSERT(button, return); + QTC_CHECK(!d->m_button); + d->m_button = button; + d->m_buttonIsAdopted = true; + registerSubWidget(button); +} + std::function BoolAspect::groupChecker() { return [this](QObject *target) { diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 1a2570ea837..f6a35fa4ef8 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -240,6 +240,8 @@ public: LabelPlacement labelPlacement = LabelPlacement::InExtraLabel); void setLabelPlacement(LabelPlacement labelPlacement); + void adoptButton(QAbstractButton *button); + signals: void valueChanged(bool newValue); void volatileValueChanged(bool newValue); From 0672199de83042fa160f0abbb5c6077642b0d261 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 29 Mar 2023 21:15:47 +0200 Subject: [PATCH 1095/1447] Squish: Provide object picker Provide the object picker. Currently only partial functionality and limited for a debug run of a squish test. Change-Id: Ic6f765d3c76b29c732684879c2459f1e0f732978 Reviewed-by: David Schulz --- src/plugins/squish/squishperspective.cpp | 161 ++++++++++++++++++++- src/plugins/squish/squishperspective.h | 36 ++++- src/plugins/squish/squishrunnerprocess.cpp | 93 +++++++++++- src/plugins/squish/squishrunnerprocess.h | 16 +- src/plugins/squish/squishtools.cpp | 78 +++++++++- src/plugins/squish/squishtools.h | 8 + 6 files changed, 378 insertions(+), 14 deletions(-) diff --git a/src/plugins/squish/squishperspective.cpp b/src/plugins/squish/squishperspective.cpp index b229541842a..5120ec6ea95 100644 --- a/src/plugins/squish/squishperspective.cpp +++ b/src/plugins/squish/squishperspective.cpp @@ -96,6 +96,79 @@ QVariant LocalsItem::data(int column, int role) const return TreeItem::data(column, role); } +QVariant InspectedObjectItem::data(int column, int role) const +{ + if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { + switch (column) { + case 0: return value; + case 1: return type; + } + } + return TreeItem::data(column, role); +} + +QVariant InspectedPropertyItem::data(int column, int role) const +{ + if (role ==Qt::DisplayRole || role == Qt::ToolTipRole) { + switch (column) { + case 0: return name; + case 1: return value; + } + } + return TreeItem::data(column, role); +} + +void InspectedPropertyItem::parseAndUpdateChildren() +{ + const char open = '{'; + const char close = '}'; + const char delimiter =','; + const char eq = '='; + + if (!value.startsWith(open) || !value.endsWith(close)) // only parse multi-property content + return; + + int start = 1; + int end = value.size() - 1; + do { + int endOfName = value.indexOf(eq, start); + QTC_ASSERT(endOfName != -1, return); + int innerStart = endOfName + 2; + QTC_ASSERT(innerStart < end, return); + const QString name = value.mid(start, endOfName - start).trimmed(); + if (value.at(innerStart) != open) { + int endOfItemValue = value.indexOf(delimiter, innerStart); + if (endOfItemValue == -1) + endOfItemValue = end; + const QString content = value.mid(innerStart, endOfItemValue - innerStart).trimmed(); + appendChild(new InspectedPropertyItem(name, content)); + start = endOfItemValue + 1; + } else { + int openedBraces = 1; + // advance until item's content is complete + int pos = innerStart; + do { + if (++pos > end) + break; + if (value.at(pos) == open) { + ++openedBraces; + continue; + } + if (value.at(pos) == close) { + --openedBraces; + if (openedBraces == 0) + break; + } + } while (pos < end); + ++pos; + QTC_ASSERT(pos < end, return); + const QString content = value.mid(innerStart, pos - innerStart).trimmed(); + appendChild(new InspectedPropertyItem(name, content)); + start = pos + 1; + } + } while (start < end); +} + class SquishControlBar : public QDialog { public: @@ -240,12 +313,12 @@ void SquishPerspective::initPerspective() objectsMainLayout->setSpacing(1); m_objectsModel.setHeader({Tr::tr("Object"), Tr::tr("Type")}); - auto objectsView = new Utils::TreeView; - objectsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - objectsView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - objectsView->setModel(&m_objectsModel); - objectsView->setRootIsDecorated(true); - objectsMainLayout->addWidget(objectsView); + m_objectsView = new Utils::TreeView; + m_objectsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_objectsView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_objectsView->setModel(&m_objectsModel); + m_objectsView->setRootIsDecorated(true); + objectsMainLayout->addWidget(m_objectsView); QWidget *objectWidget = new QWidget; objectWidget->setObjectName("SquishObjectsView"); @@ -313,6 +386,33 @@ void SquishPerspective::initPerspective() SquishTools::instance()->requestExpansion(item->name); } }); + + connect(SquishTools::instance(), &SquishTools::objectPicked, + this, &SquishPerspective::onObjectPicked); + connect(SquishTools::instance(), &SquishTools::propertiesFetched, + this, &SquishPerspective::onPropertiesFetched); + connect(SquishTools::instance(), &SquishTools::autIdRetrieved, + this, [this]{ + m_autIdKnown = true; + m_inspectAction->setEnabled(true); + }); + connect(m_objectsView, &QTreeView::expanded, this, [this](const QModelIndex &idx) { + InspectedObjectItem *item = m_objectsModel.itemForIndex(idx); + if (QTC_GUARD(item)) { + if (item->expanded) + return; + item->expanded = true; + SquishTools::instance()->requestExpansionForObject(item->value); + } + }); + connect(m_objectsView->selectionModel(), &QItemSelectionModel::currentChanged, + this, [this](const QModelIndex ¤t){ + m_propertiesModel.clear(); + InspectedObjectItem *item = m_objectsModel.itemForIndex(current); + if (!item) + return; + SquishTools::instance()->requestPropertiesForObject(item->value); + }); } void SquishPerspective::onStopTriggered() @@ -321,6 +421,7 @@ void SquishPerspective::onStopTriggered() m_pausePlayAction->setEnabled(false); m_stopAction->setEnabled(false); m_inspectAction->setEnabled(false); + m_autIdKnown = false; emit stopRequested(); } @@ -330,6 +431,7 @@ void SquishPerspective::onStopRecordTriggered() m_pausePlayAction->setEnabled(false); m_stopAction->setEnabled(false); m_inspectAction->setEnabled(false); + m_autIdKnown = false; emit stopRecordRequested(); } @@ -379,6 +481,44 @@ void SquishPerspective::onLocalsUpdated(const QString &output) } } +void SquishPerspective::onObjectPicked(const QString &output) +{ + // "+{container=':o_QQuickView' text='2' type='Text' unnamed='1' visible='true'}\tQQuickText_QML_1" + static const QRegularExpression regex("^(?[-+])(?\\{.*\\})\t(?.+)$"); + const QRegularExpressionMatch match = regex.match(output); + if (!match.hasMatch()) + return; + InspectedObjectItem *parent = nullptr; + const QString content = match.captured("content"); + parent = m_objectsModel.findNonRootItem([content](InspectedObjectItem *it) { + return it->value == content; + }); + if (!parent) { + m_objectsModel.clear(); + parent = m_objectsModel.rootItem(); + } + InspectedObjectItem *obj = new InspectedObjectItem(content, match.captured("type")); + if (match.captured("exp") == "+") + obj->appendChild(new InspectedObjectItem); // add pseudo child + parent->appendChild(obj); + m_inspectAction->setEnabled(true); + const QModelIndex idx = m_objectsModel.indexForItem(obj); + if (idx.isValid()) + m_objectsView->setCurrentIndex(idx); +} + +void SquishPerspective::onPropertiesFetched(const QStringList &properties) +{ + static const QRegularExpression regex("(?.+)=(?[-+])(?.*)"); + + for (const QString &line : properties) { + const QRegularExpressionMatch match = regex.match(line); + QTC_ASSERT(match.hasMatch(), continue); + auto item = new InspectedPropertyItem(match.captured("name"), match.captured("content")); + m_propertiesModel.rootItem()->appendChild(item); + } +} + void SquishPerspective::updateStatus(const QString &status) { m_status->setText(status); @@ -413,6 +553,12 @@ void SquishPerspective::destroyControlBar() m_controlBar = nullptr; } +void SquishPerspective::resetAutId() +{ + m_autIdKnown = false; + m_inspectAction->setEnabled(false); +} + void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) { if (m_mode == mode) // ignore @@ -450,7 +596,7 @@ void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) m_stepOverAction->setEnabled(true); m_stepOutAction->setEnabled(true); m_stopAction->setEnabled(true); - m_inspectAction->setEnabled(true); + m_inspectAction->setEnabled(m_autIdKnown); break; case Configuring: case Querying: @@ -465,6 +611,7 @@ void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) m_stopAction->setEnabled(false); m_inspectAction->setEnabled(false); m_localsModel.clear(); + m_objectsModel.clear(); break; default: break; diff --git a/src/plugins/squish/squishperspective.h b/src/plugins/squish/squishperspective.h index 3a69247c33a..1ab6b59be2e 100644 --- a/src/plugins/squish/squishperspective.h +++ b/src/plugins/squish/squishperspective.h @@ -9,6 +9,8 @@ #include +namespace Utils { class TreeView; } + namespace Squish { namespace Internal { @@ -26,6 +28,31 @@ public: bool expanded = false; }; +class InspectedObjectItem : public Utils::TreeItem +{ +public: + InspectedObjectItem() = default; + InspectedObjectItem(const QString &v, const QString &t) : value(v), type(t) {} + QVariant data(int column, int role) const override; + QString value; + QString type; + bool expanded = false; +}; + +class InspectedPropertyItem : public Utils::TreeItem +{ +public: + InspectedPropertyItem() = default; + InspectedPropertyItem(const QString &n, const QString &v) + : name(n), value(v) { parseAndUpdateChildren(); } + QVariant data(int column, int role) const override; + QString name; + QString value; + bool expanded = false; +private: + void parseAndUpdateChildren(); +}; + class SquishPerspective : public Utils::Perspective { Q_OBJECT @@ -41,6 +68,7 @@ public: void showControlBar(SquishXmlOutputHandler *xmlOutputHandler); void destroyControlBar(); + void resetAutId(); signals: void stopRequested(); @@ -54,6 +82,8 @@ private: void onStopRecordTriggered(); void onPausePlayTriggered(); void onLocalsUpdated(const QString &output); + void onObjectPicked(const QString &output); + void onPropertiesFetched(const QStringList &properties); QAction *m_stopRecordAction = nullptr; QAction *m_pausePlayAction = nullptr; @@ -65,9 +95,11 @@ private: QLabel *m_status = nullptr; class SquishControlBar *m_controlBar = nullptr; Utils::TreeModel m_localsModel; - Utils::TreeModel<> m_objectsModel; - Utils::TreeModel<> m_propertiesModel; + Utils::TreeModel m_objectsModel; + Utils::TreeModel m_propertiesModel; + Utils::TreeView *m_objectsView = nullptr; PerspectiveMode m_mode = NoMode; + bool m_autIdKnown = false; friend class SquishControlBar; }; diff --git a/src/plugins/squish/squishrunnerprocess.cpp b/src/plugins/squish/squishrunnerprocess.cpp index 3fa6474e269..4c6991a2070 100644 --- a/src/plugins/squish/squishrunnerprocess.cpp +++ b/src/plugins/squish/squishrunnerprocess.cpp @@ -6,6 +6,7 @@ #include "squishtr.h" #include +#include #include @@ -13,6 +14,14 @@ Q_LOGGING_CATEGORY(runnerLOG, "qtc.squish.squishrunner", QtWarningMsg) namespace Squish::Internal { +static QString maskedArgument(const QString &originalArg) +{ + QString masked = originalArg; + masked.replace('\\', "\\\\"); + masked.replace(' ', "\\x20"); + return masked; +} + SquishRunnerProcess::SquishRunnerProcess(QObject *parent) : SquishProcessBase{parent} { @@ -36,6 +45,10 @@ void SquishRunnerProcess::setupProcess(RunnerMode mode) case Record: m_process.setProcessMode(Utils::ProcessMode::Writer); break; + case Inspect: + m_process.setProcessMode(Utils::ProcessMode::Writer); + m_process.setStdOutLineCallback([this](const QString &line) { onInspectorOutput(line); }); + break; } } @@ -44,6 +57,8 @@ void SquishRunnerProcess::start(const Utils::CommandLine &cmdline, const Utils:: QTC_ASSERT(m_process.state() == QProcess::NotRunning, return); m_licenseIssues = false; m_autId = 0; + m_outputMode = SingleLine; + m_multiLineContent.clear(); SquishProcessBase::start(cmdline, env); } @@ -130,11 +145,75 @@ void SquishRunnerProcess::onStdOutput(const QString &lineIn) isPrompt = true; m_autId = line.mid(7).toInt(); qCInfo(runnerLOG) << "AUT ID set" << m_autId << "(" << line << ")"; + emit autIdRetrieved(); } if (isPrompt) emit interrupted(fileName, fileLine, fileColumn); } +void SquishRunnerProcess::handleMultiLineOutput(OutputMode mode) +{ + Utils::ExecuteOnDestruction atExit([this]{ + m_multiLineContent.clear(); + m_context.clear(); + }); + + if (mode == MultiLineProperties) { + emit propertiesFetched(m_multiLineContent); + } else if (mode == MultiLineChildren) { + // TODO + } +} + +void SquishRunnerProcess::onInspectorOutput(const QString &lineIn) +{ + QString line = lineIn; + line.chop(1); // line has a newline + if (line.startsWith("SSPY:")) + line = line.mid(5); + if (line.isEmpty()) // we have a prompt, that's fine + return; + + if (m_outputMode != SingleLine) { + const OutputMode originalMode = m_outputMode; + if (line.startsWith("@end")) { + m_outputMode = SingleLine; + if (!QTC_GUARD(line.mid(6).chopped(1) == m_context)) { // messed up output + m_multiLineContent.clear(); + m_context.clear(); + return; + } + } else { + m_multiLineContent.append(line); + } + if (m_outputMode == SingleLine) // we reached the @end + handleMultiLineOutput(originalMode); + return; + } + if (line == "@ready") + return; + if (line.startsWith("@picked: ")) { + const QString value = line.mid(9); + emit objectPicked(value); + return; + } + if (line.startsWith("@startprop")) { + m_outputMode = MultiLineProperties; + m_context = line.mid(12).chopped(1); + return; + } + if (line.startsWith("@startobj")) { + m_outputMode = MultiLineChildren; + m_context = line.mid(11).chopped(1); + return; + } + if (line.contains("license acquisition")) { + emit logOutputReceived("Inspect: " + line); + return; + } +// qDebug() << "unhandled" << line; +} + static QString cmdToString(SquishRunnerProcess::RunnerCommand cmd) { switch (cmd) { @@ -142,6 +221,7 @@ static QString cmdToString(SquishRunnerProcess::RunnerCommand cmd) case SquishRunnerProcess::EndRecord: return "endrecord\n"; case SquishRunnerProcess::Exit: return "exit\n"; case SquishRunnerProcess::Next: return "next\n"; + case SquishRunnerProcess::Pick: return "pick\n"; case SquishRunnerProcess::PrintVariables: return "print variables\n"; case SquishRunnerProcess::Return: return "return\n"; case SquishRunnerProcess::Step: return "step\n"; @@ -161,6 +241,16 @@ void SquishRunnerProcess::requestExpanded(const QString &variableName) m_process.write("print variables +" + variableName + "\n"); } +void SquishRunnerProcess::requestListObject(const QString &value) +{ + m_process.write("list objects " + maskedArgument(value) + "\n"); +} + +void SquishRunnerProcess::requestListProperties(const QString &value) +{ + m_process.write("list properties " + maskedArgument(value) + "\n"); +} + // FIXME: add/removal of breakpoints while debugging not handled yet // FIXME: enabled state of breakpoints Utils::Links SquishRunnerProcess::setBreakpoints(const QString &scriptExtension) @@ -180,8 +270,7 @@ Utils::Links SquishRunnerProcess::setBreakpoints(const QString &scriptExtension) continue; // mask backslashes and spaces - fileName.replace('\\', "\\\\"); - fileName.replace(' ', "\\x20"); + fileName = maskedArgument(fileName); auto line = gb->data(BreakpointLineColumn, Qt::DisplayRole).toInt(); QString cmd = "break "; cmd.append(fileName); diff --git a/src/plugins/squish/squishrunnerprocess.h b/src/plugins/squish/squishrunnerprocess.h index b1c98220c17..624b986c6d6 100644 --- a/src/plugins/squish/squishrunnerprocess.h +++ b/src/plugins/squish/squishrunnerprocess.h @@ -15,8 +15,8 @@ class SquishRunnerProcess : public SquishProcessBase { Q_OBJECT public: - enum RunnerCommand { Continue, EndRecord, Exit, Next, PrintVariables, Return, Step }; - enum RunnerMode { Run, StartAut, QueryServer, Record }; + enum RunnerCommand { Continue, EndRecord, Exit, Next, Pick, PrintVariables, Return, Step }; + enum RunnerMode { Run, StartAut, QueryServer, Record, Inspect }; enum RunnerError { InvalidSocket, MappedAutMissing }; explicit SquishRunnerProcess(QObject *parent = nullptr); @@ -33,6 +33,8 @@ public: void writeCommand(RunnerCommand cmd); void requestExpanded(const QString &variableName); + void requestListObject(const QString &value); + void requestListProperties(const QString &value); Utils::Links setBreakpoints(const QString &scriptExtension); bool lastRunHadLicenseIssues() const { return m_licenseIssues; } @@ -43,16 +45,26 @@ signals: void runnerFinished(); void interrupted(const QString &fileName, int line, int column); void localsUpdated(const QString &output); + void propertiesFetched(const QStringList &properties); + void objectPicked(const QString &output); void runnerError(RunnerError error); + void autIdRetrieved(); protected: void onDone() override; void onErrorOutput() override; private: + enum OutputMode { SingleLine, MultiLineChildren, MultiLineProperties }; + void onStdOutput(const QString &line); + void handleMultiLineOutput(OutputMode mode); + void onInspectorOutput(const QString &line); Utils::FilePath m_currentTestCasePath; + QStringList m_multiLineContent; + QString m_context; + OutputMode m_outputMode = SingleLine; int m_autId = 0; bool m_licenseIssues = false; std::optional m_mode; diff --git a/src/plugins/squish/squishtools.cpp b/src/plugins/squish/squishtools.cpp index c31109fab3b..64cc98f780d 100644 --- a/src/plugins/squish/squishtools.cpp +++ b/src/plugins/squish/squishtools.cpp @@ -133,6 +133,8 @@ SquishTools::SquishTools(QObject *parent) this, &SquishTools::stopRecorder); connect(&m_perspective, &SquishPerspective::runRequested, this, &SquishTools::onRunnerRunRequested); + connect(&m_perspective, &SquishPerspective::inspectTriggered, + this, &SquishTools::onInspectTriggered); } SquishTools::~SquishTools() @@ -440,6 +442,7 @@ void SquishTools::onRunnerStopped() m_request = ServerStopRequested; qCInfo(LOG) << "Stopping server from RunnerStopped (query)"; stopSquishServer(); + return; } else if (m_request == RecordTestRequested) { if (m_secondaryRunner && m_secondaryRunner->isRunning()) { stopRecorder(); @@ -448,7 +451,12 @@ void SquishTools::onRunnerStopped() qCInfo(LOG) << "Stopping server from RunnerStopped (startaut)"; stopSquishServer(); } - } else if (m_testCases.isEmpty() || (m_squishRunnerState == RunnerState::Canceled)) { + return; + } + // below only normal run of test case(s) + exitAndResetSecondaryRunner(); + + if (m_testCases.isEmpty() || (m_squishRunnerState == RunnerState::Canceled)) { m_request = ServerStopRequested; qCInfo(LOG) << "Stopping server from RunnerStopped"; stopSquishServer(); @@ -613,6 +621,50 @@ void SquishTools::setupAndStartRecorder() m_secondaryRunner->start(cmd, squishEnvironment()); } +void SquishTools::setupAndStartInspector() +{ + QTC_ASSERT(m_primaryRunner && m_primaryRunner->autId() != 0, return); + QTC_ASSERT(!m_secondaryRunner, return); + + QStringList args; + if (!toolsSettings.isLocalServer) + args << "--host" << toolsSettings.serverHost; + args << "--port" << QString::number(m_serverProcess.port()); + args << "--debugLog" << "alpw"; // TODO make this configurable? + args << "--inspect"; + args << "--suitedir" << m_suitePath.toUserOutput(); + args << "--autid" << QString::number(m_primaryRunner->autId()); + + m_secondaryRunner = new SquishRunnerProcess(this); + m_secondaryRunner->setupProcess(SquishRunnerProcess::Inspect); + const CommandLine cmd = {toolsSettings.runnerPath, args}; + connect(m_secondaryRunner, &SquishRunnerProcess::logOutputReceived, + this, &SquishTools::logOutputReceived); + connect(m_secondaryRunner, &SquishRunnerProcess::objectPicked, + this, &SquishTools::objectPicked); + connect(m_secondaryRunner, &SquishRunnerProcess::propertiesFetched, + this, &SquishTools::propertiesFetched); + qCDebug(LOG) << "Inspector starting:" << cmd.toUserOutput(); + m_secondaryRunner->start(cmd, squishEnvironment()); +} + +void SquishTools::exitAndResetSecondaryRunner() +{ + m_perspective.resetAutId(); + if (m_secondaryRunner) { + m_secondaryRunner->writeCommand(SquishRunnerProcess::Exit); + m_secondaryRunner->deleteLater(); + m_secondaryRunner = nullptr; + } +} + +void SquishTools::onInspectTriggered() +{ + QTC_ASSERT(m_primaryRunner, return); + QTC_ASSERT(m_secondaryRunner, return); + m_secondaryRunner->writeCommand(SquishRunnerProcess::Pick); +} + void SquishTools::stopRecorder() { QTC_ASSERT(m_secondaryRunner && m_secondaryRunner->isRunning(), return); @@ -865,6 +917,7 @@ void SquishTools::handlePrompt(const QString &fileName, int line, int column) case RunnerState::CancelRequested: case RunnerState::CancelRequestedWhileInterrupted: logAndChangeRunnerState(RunnerState::Canceled); + exitAndResetSecondaryRunner(); m_primaryRunner->writeCommand(SquishRunnerProcess::Exit); clearLocationMarker(); break; @@ -885,6 +938,9 @@ void SquishTools::handlePrompt(const QString &fileName, int line, int column) const FilePath filePath = FilePath::fromUserInput(fileName); Core::EditorManager::openEditorAt({filePath, line, column}); updateLocationMarker(filePath, line); + // looks like we need to start inspector while being interrupted? + if (!m_secondaryRunner && m_primaryRunner->autId() !=0) + setupAndStartInspector(); } } else { // it's just some output coming from the server if (m_squishRunnerState == RunnerState::Interrupted && !m_requestVarsTimer) { @@ -909,6 +965,24 @@ void SquishTools::requestExpansion(const QString &name) m_primaryRunner->requestExpanded(name); } +void SquishTools::requestExpansionForObject(const QString &value) +{ + QTC_ASSERT(m_primaryRunner, return); + if (m_squishRunnerState != RunnerState::Interrupted) + return; + QTC_ASSERT(m_secondaryRunner, return); + m_secondaryRunner->requestListObject(value); +} + +void SquishTools::requestPropertiesForObject(const QString &value) +{ + QTC_ASSERT(m_primaryRunner, return); + if (m_squishRunnerState != RunnerState::Interrupted) + return; + QTC_ASSERT(m_secondaryRunner, return); + m_secondaryRunner->requestListProperties(value); +} + bool SquishTools::shutdown() { QTC_ASSERT(!m_shutdownInitiated, return true); @@ -1202,6 +1276,8 @@ void SquishTools::setupAndStartSquishRunnerProcess(const Utils::CommandLine &cmd m_primaryRunner->closeProcess(); if (m_request == RunTestRequested) { + connect(m_primaryRunner, &SquishRunnerProcess::autIdRetrieved, + this, &SquishTools::autIdRetrieved); // set up the file system watcher for being able to read the results.xml file m_resultsFileWatcher = new QFileSystemWatcher; // on 2nd run this directory exists and won't emit changes, so use the current subdirectory diff --git a/src/plugins/squish/squishtools.h b/src/plugins/squish/squishtools.h index 8d3cf61cfc5..11bb9d3096c 100644 --- a/src/plugins/squish/squishtools.h +++ b/src/plugins/squish/squishtools.h @@ -60,10 +60,13 @@ public: void requestSetSharedFolders(const Utils::FilePaths &sharedFolders); void writeServerSettingsChanges(const QList &changes); void requestExpansion(const QString &name); + void requestExpansionForObject(const QString &value); + void requestPropertiesForObject(const QString &value); bool shutdown(); signals: + void autIdRetrieved(); void logOutputReceived(const QString &output); void squishTestRunStarted(); void squishTestRunFinished(); @@ -71,6 +74,8 @@ signals: void configChangesFailed(QProcess::ProcessError error); void configChangesWritten(); void localsUpdated(const QString &output); + void objectPicked(const QString &output); + void propertiesFetched(const QStringList &properties); void shutdownFinished(); private: @@ -103,6 +108,9 @@ private: void stopSquishServer(); void startSquishRunner(); void setupAndStartRecorder(); + void setupAndStartInspector(); + void exitAndResetSecondaryRunner(); + void onInspectTriggered(); void stopRecorder(); void queryServer(RunnerQuery query); void executeRunnerQuery(); From 520412d147b12ed8fda1a13aef96d79b953590c5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 16:29:22 +0200 Subject: [PATCH 1096/1447] CPaster: Use PagedSettings Change-Id: I826030f9a691c9e9c929deb1624d9705d3222e23 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/cpaster/fileshareprotocol.cpp | 18 +++++---------- src/plugins/cpaster/fileshareprotocol.h | 5 +---- .../cpaster/fileshareprotocolsettingspage.cpp | 22 +++++++------------ .../cpaster/fileshareprotocolsettingspage.h | 10 +-------- src/plugins/cpaster/protocol.cpp | 2 +- src/plugins/cpaster/protocol.h | 2 +- 6 files changed, 17 insertions(+), 42 deletions(-) diff --git a/src/plugins/cpaster/fileshareprotocol.cpp b/src/plugins/cpaster/fileshareprotocol.cpp index 6ceb8a4e13b..e9b85ee1af1 100644 --- a/src/plugins/cpaster/fileshareprotocol.cpp +++ b/src/plugins/cpaster/fileshareprotocol.cpp @@ -6,7 +6,6 @@ #include "cpastertr.h" #include "fileshareprotocolsettingspage.h" -#include #include #include @@ -29,20 +28,13 @@ const char textElementC[] = "text"; namespace CodePaster { -FileShareProtocol::FileShareProtocol() : - m_settingsPage(new FileShareProtocolSettingsPage(&m_settings)) -{ - m_settings.readSettings(Core::ICore::settings()); -} +FileShareProtocol::FileShareProtocol() = default; -FileShareProtocol::~FileShareProtocol() -{ - delete m_settingsPage; -} +FileShareProtocol::~FileShareProtocol() = default; QString FileShareProtocol::name() const { - return m_settingsPage->displayName(); + return m_settings.displayName(); } unsigned FileShareProtocol::capabilities() const @@ -55,9 +47,9 @@ bool FileShareProtocol::hasSettings() const return true; } -Core::IOptionsPage *FileShareProtocol::settingsPage() const +const Core::IOptionsPage *FileShareProtocol::settingsPage() const { - return m_settingsPage; + return &m_settings; } static bool parse(const QString &fileName, diff --git a/src/plugins/cpaster/fileshareprotocol.h b/src/plugins/cpaster/fileshareprotocol.h index 100c0aece03..db03bb11bf6 100644 --- a/src/plugins/cpaster/fileshareprotocol.h +++ b/src/plugins/cpaster/fileshareprotocol.h @@ -8,8 +8,6 @@ namespace CodePaster { -class FileShareProtocolSettingsPage; - /* FileShareProtocol: Allows for pasting via a shared network * drive by writing XML files. */ @@ -22,7 +20,7 @@ public: QString name() const override; unsigned capabilities() const override; bool hasSettings() const override; - Core::IOptionsPage *settingsPage() const override; + const Core::IOptionsPage *settingsPage() const override; bool checkConfiguration(QString *errorMessage = nullptr) override; void fetch(const QString &id) override; @@ -35,7 +33,6 @@ public: private: FileShareProtocolSettings m_settings; - FileShareProtocolSettingsPage *m_settingsPage; }; } // CodePaster diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp index e2e382c94b0..f3c6daad53e 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp @@ -15,8 +15,10 @@ namespace CodePaster { FileShareProtocolSettings::FileShareProtocolSettings() { + setId("X.CodePaster.FileSharePaster"); + setDisplayName(Tr::tr("Fileshare")); + setCategory(Constants::CPASTER_SETTINGS_CATEGORY); setSettingsGroup("FileSharePasterSettings"); - setAutoApply(false); registerAspect(&path); path.setSettingsKey("Path"); @@ -30,18 +32,8 @@ FileShareProtocolSettings::FileShareProtocolSettings() displayCount.setDefaultValue(10); displayCount.setSuffix(' ' + Tr::tr("entries")); displayCount.setLabelText(Tr::tr("&Display:")); -} -// Settings page - -FileShareProtocolSettingsPage::FileShareProtocolSettingsPage(FileShareProtocolSettings *settings) -{ - setId("X.CodePaster.FileSharePaster"); - setDisplayName(Tr::tr("Fileshare")); - setCategory(Constants::CPASTER_SETTINGS_CATEGORY); - setSettings(settings); - - setLayouter([&s = *settings](QWidget *widget) { + setLayouter([this](QWidget *widget) { using namespace Layouting; auto label = new QLabel(Tr::tr( @@ -52,12 +44,14 @@ FileShareProtocolSettingsPage::FileShareProtocolSettingsPage(FileShareProtocolSe Column { Form { label, br, - s.path, br, - s.displayCount + path, br, + displayCount }, st }.attachTo(widget); }); + + readSettings(); } } // namespace CodePaster diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.h b/src/plugins/cpaster/fileshareprotocolsettingspage.h index 3b92c3596d4..36a06c2106b 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.h +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.h @@ -5,11 +5,9 @@ #include -#include - namespace CodePaster { -class FileShareProtocolSettings : public Utils::AspectContainer +class FileShareProtocolSettings : public Core::PagedSettings { public: FileShareProtocolSettings(); @@ -18,10 +16,4 @@ public: Utils::IntegerAspect displayCount; }; -class FileShareProtocolSettingsPage final : public Core::IOptionsPage -{ -public: - explicit FileShareProtocolSettingsPage(FileShareProtocolSettings *settings); -}; - } // CodePaster diff --git a/src/plugins/cpaster/protocol.cpp b/src/plugins/cpaster/protocol.cpp index d26396205a8..c2630d09c13 100644 --- a/src/plugins/cpaster/protocol.cpp +++ b/src/plugins/cpaster/protocol.cpp @@ -47,7 +47,7 @@ bool Protocol::checkConfiguration(QString *) return true; } -Core::IOptionsPage *Protocol::settingsPage() const +const Core::IOptionsPage *Protocol::settingsPage() const { return nullptr; } diff --git a/src/plugins/cpaster/protocol.h b/src/plugins/cpaster/protocol.h index a8d233619b4..90464768c2a 100644 --- a/src/plugins/cpaster/protocol.h +++ b/src/plugins/cpaster/protocol.h @@ -38,7 +38,7 @@ public: virtual unsigned capabilities() const = 0; virtual bool hasSettings() const; - virtual Core::IOptionsPage *settingsPage() const; + virtual const Core::IOptionsPage *settingsPage() const; virtual bool checkConfiguration(QString *errorMessage = nullptr); virtual void fetch(const QString &id) = 0; From f84199f8b70bb03b66a0dbac3ff4dcdb56094d20 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 10 May 2023 21:38:41 +0200 Subject: [PATCH 1097/1447] Solutions: Long live Solutions! Short live Tasking in Solutions! Add src/libs/solutions/README.md with the motivation and hints. Move TaskTree and Barrier from Utils into Tasking object lib, the first solution in Solutions project. Tasking: Some more work is still required for adapting auto and manual tests. Currently they use Async task, which stayed in Utils. For Qt purposed we most probably need to have a clone of Async task inside the Tasking namespace that is more Qt-like (no Utils::FutureSynchronizer, no priority field, global QThreadPool instead of a custom one for Creator). Change-Id: I5d10a2d68170ffa467d8c299be5995b9aa4f8f77 Reviewed-by: Cristian Adam Reviewed-by: hjk Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/CMakeLists.txt | 22 ++++----- src/libs/libs.qbs | 1 + src/libs/solutions/CMakeLists.txt | 1 + src/libs/solutions/README.md | 48 +++++++++++++++++++ src/libs/solutions/solutions.qbs | 7 +++ src/libs/solutions/tasking/CMakeLists.txt | 9 ++++ .../{utils => solutions/tasking}/barrier.cpp | 0 .../{utils => solutions/tasking}/barrier.h | 8 ++-- src/libs/solutions/tasking/tasking.qbs | 14 ++++++ src/libs/solutions/tasking/tasking_global.h | 14 ++++++ .../{utils => solutions/tasking}/tasktree.cpp | 2 +- .../{utils => solutions/tasking}/tasktree.h | 44 ++++++++--------- src/libs/utils/CMakeLists.txt | 4 +- src/libs/utils/async.h | 3 +- src/libs/utils/filestreamer.cpp | 3 +- src/libs/utils/filestreamer.h | 3 +- src/libs/utils/process.h | 3 +- src/libs/utils/utils.qbs | 5 +- .../clangtools/clangtoolruncontrol.cpp | 1 - .../clangtools/documentclangtoolrunner.cpp | 3 +- .../coreplugin/locator/ilocatorfilter.h | 3 +- .../progressmanager/taskprogress.cpp | 3 +- src/plugins/debugger/loadcoredialog.cpp | 1 - src/plugins/diffeditor/diffeditorcontroller.h | 2 +- .../languageclient/clientrequesttask.h | 3 +- .../currentdocumentsymbolsrequest.h | 3 +- .../devicesupport/deviceusedportsgatherer.h | 3 +- .../devicesupport/filetransfer.h | 2 +- .../projectexplorer/devicesupport/idevice.h | 3 +- src/plugins/projectexplorer/extracompiler.h | 2 +- .../abstractremotelinuxdeploystep.cpp | 3 +- src/plugins/remotelinux/rsyncdeploystep.cpp | 1 - src/tools/processlauncher/CMakeLists.txt | 3 +- .../processlauncher/launchersockethandler.cpp | 8 ++-- .../processlauncher/launchersockethandler.h | 2 +- .../processlauncher/processlauncher-main.cpp | 3 +- src/tools/processlauncher/processlauncher.qbs | 3 +- tests/auto/CMakeLists.txt | 1 + tests/auto/auto.qbs | 1 + tests/auto/solutions/CMakeLists.txt | 1 + tests/auto/solutions/solutions.qbs | 8 ++++ tests/auto/solutions/tasking/CMakeLists.txt | 4 ++ tests/auto/solutions/tasking/tasking.qbs | 7 +++ .../tasking/tst_tasking.cpp} | 23 ++++----- tests/auto/utils/CMakeLists.txt | 1 - tests/auto/utils/tasktree/CMakeLists.txt | 4 -- tests/auto/utils/tasktree/tasktree.qbs | 26 ---------- tests/auto/utils/utils.qbs | 1 - tests/manual/tasktree/taskwidget.h | 3 +- 49 files changed, 208 insertions(+), 115 deletions(-) create mode 100644 src/libs/solutions/CMakeLists.txt create mode 100644 src/libs/solutions/README.md create mode 100644 src/libs/solutions/solutions.qbs create mode 100644 src/libs/solutions/tasking/CMakeLists.txt rename src/libs/{utils => solutions/tasking}/barrier.cpp (100%) rename src/libs/{utils => solutions/tasking}/barrier.h (92%) create mode 100644 src/libs/solutions/tasking/tasking.qbs create mode 100644 src/libs/solutions/tasking/tasking_global.h rename src/libs/{utils => solutions/tasking}/tasktree.cpp (99%) rename src/libs/{utils => solutions/tasking}/tasktree.h (92%) create mode 100644 tests/auto/solutions/CMakeLists.txt create mode 100644 tests/auto/solutions/solutions.qbs create mode 100644 tests/auto/solutions/tasking/CMakeLists.txt create mode 100644 tests/auto/solutions/tasking/tasking.qbs rename tests/auto/{utils/tasktree/tst_tasktree.cpp => solutions/tasking/tst_tasking.cpp} (99%) delete mode 100644 tests/auto/utils/tasktree/CMakeLists.txt delete mode 100644 tests/auto/utils/tasktree/tasktree.qbs diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt index fc6b53d81c4..2ee109d5cd0 100644 --- a/src/libs/CMakeLists.txt +++ b/src/libs/CMakeLists.txt @@ -2,22 +2,22 @@ add_subdirectory(3rdparty) add_subdirectory(advanceddockingsystem) add_subdirectory(aggregation) -add_subdirectory(extensionsystem) -add_subdirectory(utils) -add_subdirectory(languageutils) add_subdirectory(cplusplus) -add_subdirectory(modelinglib) -add_subdirectory(nanotrace) -add_subdirectory(qmljs) -add_subdirectory(qmldebug) -add_subdirectory(qmleditorwidgets) +add_subdirectory(extensionsystem) add_subdirectory(glsl) add_subdirectory(languageserverprotocol) +add_subdirectory(languageutils) +add_subdirectory(modelinglib) +add_subdirectory(nanotrace) +add_subdirectory(qmldebug) +add_subdirectory(qmleditorwidgets) +add_subdirectory(qmljs) +add_subdirectory(qmlpuppetcommunication) +add_subdirectory(qtcreatorcdbext) +add_subdirectory(solutions) add_subdirectory(sqlite) add_subdirectory(tracing) -add_subdirectory(qmlpuppetcommunication) - -add_subdirectory(qtcreatorcdbext) +add_subdirectory(utils) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt) option(BUILD_LIBRARY_QLITEHTML "Build library qlitehtml." ${BUILD_LIBRARIES_BY_DEFAULT}) diff --git a/src/libs/libs.qbs b/src/libs/libs.qbs index 141e2a65475..ffc3017cba0 100644 --- a/src/libs/libs.qbs +++ b/src/libs/libs.qbs @@ -19,6 +19,7 @@ Project { "qmljs/qmljs.qbs", "qmldebug/qmldebug.qbs", "qtcreatorcdbext/qtcreatorcdbext.qbs", + "solutions/solutions.qbs", "sqlite/sqlite.qbs", "tracing/tracing.qbs", "utils/process_ctrlc_stub.qbs", diff --git a/src/libs/solutions/CMakeLists.txt b/src/libs/solutions/CMakeLists.txt new file mode 100644 index 00000000000..694d940195d --- /dev/null +++ b/src/libs/solutions/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(tasking) diff --git a/src/libs/solutions/README.md b/src/libs/solutions/README.md new file mode 100644 index 00000000000..ab4cc9727d3 --- /dev/null +++ b/src/libs/solutions/README.md @@ -0,0 +1,48 @@ +# Solutions project + +The Solutions project is designed to contain a collection of +object libraries, independent on any Creator's specific code, +ready to be a part of Qt. Kind of a staging area for possible +inclusions into Qt. + +## Motivation and benefits + +- Such a separation will ensure no future back dependencies to the Creator + specific code are introduced by mistake during maintenance. +- Easy to compile outside of Creator code. +- General hub of ideas to be considered by foundation team to be integrated + into Qt. +- The more stuff of a general purpose goes into Qt, the less maintenance work + for Creator. + +## Conformity of solutions + +Each solution: +- Is a separate object lib. +- Is placed in a separate subdirectory. +- Is enclosed within a namespace (namespace name = solution name). +- Should compile independently, i.e. there are no cross-includes + between solutions. + +## Dependencies of solution libraries + +**Do not add dependencies to non-Qt libraries.** +The only allowed dependencies are to Qt libraries. +Especially, don't add dependencies to any Creator's library +nor to any 3rd party library. + +If you can't avoid a dependency to the other Creator's library +in your solution, place it somewhere else (e.g. inside Utils library). + +The Utils lib depends on the solution libraries. + +## Predictions on possible integration into Qt + +The solutions in this project may have a bigger / faster chance to be +integrated into Qt when they: +- Conform to Qt API style. +- Integrate easily with existing classes / types in Qt + (instead of providing own structures / data types). +- Have full docs. +- Have auto tests. +- Have at least one example (however, autotests often play this role, too). diff --git a/src/libs/solutions/solutions.qbs b/src/libs/solutions/solutions.qbs new file mode 100644 index 00000000000..6184dce2af7 --- /dev/null +++ b/src/libs/solutions/solutions.qbs @@ -0,0 +1,7 @@ +Project { + name: "Solutions" + + references: [ + "tasking/tasking.qbs", + ].concat(project.additionalLibs) +} diff --git a/src/libs/solutions/tasking/CMakeLists.txt b/src/libs/solutions/tasking/CMakeLists.txt new file mode 100644 index 00000000000..5beed2fe5b4 --- /dev/null +++ b/src/libs/solutions/tasking/CMakeLists.txt @@ -0,0 +1,9 @@ +add_qtc_library(Tasking OBJECT +# Never add dependencies to non-Qt libraries for this library + DEPENDS Qt::Core + PUBLIC_DEFINES TASKING_LIBRARY + SOURCES + barrier.cpp barrier.h + tasking_global.h + tasktree.cpp tasktree.h +) diff --git a/src/libs/utils/barrier.cpp b/src/libs/solutions/tasking/barrier.cpp similarity index 100% rename from src/libs/utils/barrier.cpp rename to src/libs/solutions/tasking/barrier.cpp diff --git a/src/libs/utils/barrier.h b/src/libs/solutions/tasking/barrier.h similarity index 92% rename from src/libs/utils/barrier.h rename to src/libs/solutions/tasking/barrier.h index fe2d7bbe62c..6939da5b365 100644 --- a/src/libs/utils/barrier.h +++ b/src/libs/solutions/tasking/barrier.h @@ -3,13 +3,13 @@ #pragma once -#include "utils_global.h" +#include "tasking_global.h" #include "tasktree.h" namespace Tasking { -class QTCREATOR_UTILS_EXPORT Barrier final : public QObject +class TASKING_EXPORT Barrier final : public QObject { Q_OBJECT @@ -34,7 +34,7 @@ private: int m_current = -1; }; -class QTCREATOR_UTILS_EXPORT BarrierTaskAdapter : public Tasking::TaskAdapter +class TASKING_EXPORT BarrierTaskAdapter : public Tasking::TaskAdapter { public: BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); } @@ -70,7 +70,7 @@ using MultiBarrier = TreeStorage>; // alias template deduction only available with C++20. using SingleBarrier = MultiBarrier<1>; -class QTCREATOR_UTILS_EXPORT WaitForBarrierTask : public BarrierTask +class TASKING_EXPORT WaitForBarrierTask : public BarrierTask { public: template diff --git a/src/libs/solutions/tasking/tasking.qbs b/src/libs/solutions/tasking/tasking.qbs new file mode 100644 index 00000000000..8697b9c009b --- /dev/null +++ b/src/libs/solutions/tasking/tasking.qbs @@ -0,0 +1,14 @@ +QtcLibrary { + name: "Tasking" + Depends { name: "Qt"; submodules: ["core"] } + cpp.defines: base.concat("TASKING_LIBRARY") + + files: [ + "barrier.cpp", + "barrier.h", + "tasking_global.h", + "tasktree.cpp", + "tasktree.h", + ] +} + diff --git a/src/libs/solutions/tasking/tasking_global.h b/src/libs/solutions/tasking/tasking_global.h new file mode 100644 index 00000000000..d7e76fa9e6f --- /dev/null +++ b/src/libs/solutions/tasking/tasking_global.h @@ -0,0 +1,14 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#if defined(TASKING_LIBRARY) +# define TASKING_EXPORT Q_DECL_EXPORT +#elif defined(TASKING_STATIC_LIBRARY) +# define TASKING_EXPORT +#else +# define TASKING_EXPORT Q_DECL_IMPORT +#endif diff --git a/src/libs/utils/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp similarity index 99% rename from src/libs/utils/tasktree.cpp rename to src/libs/solutions/tasking/tasktree.cpp index 75de54c374a..4a66d7f674b 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "tasktree.h" diff --git a/src/libs/utils/tasktree.h b/src/libs/solutions/tasking/tasktree.h similarity index 92% rename from src/libs/utils/tasktree.h rename to src/libs/solutions/tasking/tasktree.h index d8545564b9c..bbee1a3fe8c 100644 --- a/src/libs/utils/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -1,9 +1,9 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "utils_global.h" +#include "tasking_global.h" #include #include @@ -16,7 +16,7 @@ class TaskContainer; class TaskNode; class TaskTreePrivate; -class QTCREATOR_UTILS_EXPORT TaskInterface : public QObject +class TASKING_EXPORT TaskInterface : public QObject { Q_OBJECT @@ -28,7 +28,7 @@ signals: void done(bool success); }; -class QTCREATOR_UTILS_EXPORT TreeStorageBase +class TASKING_EXPORT TreeStorageBase { public: bool isValid() const; @@ -110,7 +110,7 @@ enum class TaskAction StopWithError }; -class QTCREATOR_UTILS_EXPORT TaskItem +class TASKING_EXPORT TaskItem { public: // Internal, provided by QTC_DECLARE_CUSTOM_TASK @@ -186,32 +186,32 @@ private: QList m_children; }; -class QTCREATOR_UTILS_EXPORT Group : public TaskItem +class TASKING_EXPORT Group : public TaskItem { public: Group(const QList &children) { addChildren(children); } Group(std::initializer_list children) { addChildren(children); } }; -class QTCREATOR_UTILS_EXPORT Storage : public TaskItem +class TASKING_EXPORT Storage : public TaskItem { public: Storage(const TreeStorageBase &storage) : TaskItem(storage) { } }; -class QTCREATOR_UTILS_EXPORT ParallelLimit : public TaskItem +class TASKING_EXPORT ParallelLimit : public TaskItem { public: ParallelLimit(int parallelLimit) : TaskItem(qMax(parallelLimit, 0)) {} }; -class QTCREATOR_UTILS_EXPORT Workflow : public TaskItem +class TASKING_EXPORT Workflow : public TaskItem { public: Workflow(WorkflowPolicy policy) : TaskItem(policy) {} }; -class QTCREATOR_UTILS_EXPORT OnGroupSetup : public TaskItem +class TASKING_EXPORT OnGroupSetup : public TaskItem { public: template @@ -237,20 +237,20 @@ private: }; }; -class QTCREATOR_UTILS_EXPORT OnGroupDone : public TaskItem +class TASKING_EXPORT OnGroupDone : public TaskItem { public: OnGroupDone(const GroupEndHandler &handler) : TaskItem({{}, handler}) {} }; -class QTCREATOR_UTILS_EXPORT OnGroupError : public TaskItem +class TASKING_EXPORT OnGroupError : public TaskItem { public: OnGroupError(const GroupEndHandler &handler) : TaskItem({{}, {}, handler}) {} }; // Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() -class QTCREATOR_UTILS_EXPORT Sync : public Group +class TASKING_EXPORT Sync : public Group { public: @@ -276,13 +276,13 @@ private: }; -QTCREATOR_UTILS_EXPORT extern ParallelLimit sequential; -QTCREATOR_UTILS_EXPORT extern ParallelLimit parallel; -QTCREATOR_UTILS_EXPORT extern Workflow stopOnError; -QTCREATOR_UTILS_EXPORT extern Workflow continueOnError; -QTCREATOR_UTILS_EXPORT extern Workflow stopOnDone; -QTCREATOR_UTILS_EXPORT extern Workflow continueOnDone; -QTCREATOR_UTILS_EXPORT extern Workflow optional; +TASKING_EXPORT extern ParallelLimit sequential; +TASKING_EXPORT extern ParallelLimit parallel; +TASKING_EXPORT extern Workflow stopOnError; +TASKING_EXPORT extern Workflow continueOnError; +TASKING_EXPORT extern Workflow stopOnDone; +TASKING_EXPORT extern Workflow continueOnDone; +TASKING_EXPORT extern Workflow optional; template class TaskAdapter : public TaskInterface @@ -354,7 +354,7 @@ private: class TaskTreePrivate; -class QTCREATOR_UTILS_EXPORT TaskTree final : public QObject +class TASKING_EXPORT TaskTree final : public QObject { Q_OBJECT @@ -407,7 +407,7 @@ private: TaskTreePrivate *d; }; -class QTCREATOR_UTILS_EXPORT TaskTreeTaskAdapter : public TaskAdapter +class TASKING_EXPORT TaskTreeTaskAdapter : public TaskAdapter { public: TaskTreeTaskAdapter(); diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 5762fc3902e..51511b117db 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -1,5 +1,5 @@ add_qtc_library(Utils - DEPENDS Qt::Qml Qt::Xml + DEPENDS Tasking Qt::Qml Qt::Xml PUBLIC_DEPENDS Qt::Concurrent Qt::Core Qt::Network Qt::Gui Qt::Widgets Qt::Core5Compat @@ -13,7 +13,6 @@ add_qtc_library(Utils archive.cpp archive.h aspects.cpp aspects.h async.cpp async.h - barrier.cpp barrier.h basetreeview.cpp basetreeview.h benchmarker.cpp benchmarker.h buildablehelperlibrary.cpp buildablehelperlibrary.h @@ -171,7 +170,6 @@ add_qtc_library(Utils styleanimator.cpp styleanimator.h styledbar.cpp styledbar.h stylehelper.cpp stylehelper.h - tasktree.cpp tasktree.h templateengine.cpp templateengine.h temporarydirectory.cpp temporarydirectory.h temporaryfile.cpp temporaryfile.h diff --git a/src/libs/utils/async.h b/src/libs/utils/async.h index b08ceaf3dc2..f8dc6813a7b 100644 --- a/src/libs/utils/async.h +++ b/src/libs/utils/async.h @@ -7,7 +7,8 @@ #include "futuresynchronizer.h" #include "qtcassert.h" -#include "tasktree.h" + +#include #include #include diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 2d4d4909401..6d4a7683369 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -4,9 +4,10 @@ #include "filestreamer.h" #include "async.h" -#include "barrier.h" #include "process.h" +#include + #include #include #include diff --git a/src/libs/utils/filestreamer.h b/src/libs/utils/filestreamer.h index 8e46d7d1646..a5b6ff4f256 100644 --- a/src/libs/utils/filestreamer.h +++ b/src/libs/utils/filestreamer.h @@ -6,7 +6,8 @@ #include "utils_global.h" #include "filepath.h" -#include "tasktree.h" + +#include #include diff --git a/src/libs/utils/process.h b/src/libs/utils/process.h index 272e25f3774..83f1bb990b4 100644 --- a/src/libs/utils/process.h +++ b/src/libs/utils/process.h @@ -11,7 +11,8 @@ #include "commandline.h" #include "processenums.h" -#include "tasktree.h" + +#include #include diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index f316a8b75b5..d1c8d0e95e4 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -35,6 +35,7 @@ Project { Depends { name: "Qt"; submodules: ["concurrent", "core-private", "network", "qml", "widgets", "xml"] } Depends { name: "Qt.macextras"; condition: Qt.core.versionMajor < 6 && qbs.targetOS.contains("macos") } + Depends { name: "Tasking" } Depends { name: "app_version_header" } Depends { name: "ptyqt" } @@ -51,8 +52,6 @@ Project { "aspects.h", "async.cpp", "async.h", - "barrier.cpp", - "barrier.h", "basetreeview.cpp", "basetreeview.h", "benchmarker.cpp", @@ -308,8 +307,6 @@ Project { "styledbar.h", "stylehelper.cpp", "stylehelper.h", - "tasktree.cpp", - "tasktree.h", "templateengine.cpp", "templateengine.h", "temporarydirectory.cpp", diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index 4f1b39a27ec..be6f416d2e0 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index 7077786d32f..178022a91a6 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -21,11 +21,12 @@ #include #include +#include + #include #include #include -#include #include #include diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 8a8114743ce..b008c12bb5c 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -5,10 +5,11 @@ #include +#include + #include #include #include -#include #include #include diff --git a/src/plugins/coreplugin/progressmanager/taskprogress.cpp b/src/plugins/coreplugin/progressmanager/taskprogress.cpp index 7e59a9b146a..c82ec339c51 100644 --- a/src/plugins/coreplugin/progressmanager/taskprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/taskprogress.cpp @@ -6,9 +6,10 @@ #include "futureprogress.h" #include "progressmanager.h" +#include + #include #include -#include #include #include diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index a196fb43d14..4a0fea3f165 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index 7f990ecb2fd..1f791b2dcb3 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -6,7 +6,7 @@ #include "diffeditor_global.h" #include "diffutils.h" -#include +#include #include diff --git a/src/plugins/languageclient/clientrequesttask.h b/src/plugins/languageclient/clientrequesttask.h index 98c4888d05b..3e08e1a287f 100644 --- a/src/plugins/languageclient/clientrequesttask.h +++ b/src/plugins/languageclient/clientrequesttask.h @@ -10,7 +10,8 @@ #include #include #include -#include + +#include namespace LanguageClient { diff --git a/src/plugins/languageclient/currentdocumentsymbolsrequest.h b/src/plugins/languageclient/currentdocumentsymbolsrequest.h index 399a3fe7f07..0b9c11a2215 100644 --- a/src/plugins/languageclient/currentdocumentsymbolsrequest.h +++ b/src/plugins/languageclient/currentdocumentsymbolsrequest.h @@ -7,7 +7,8 @@ #include #include -#include + +#include namespace LanguageClient { diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h index 194ca6f4a62..7be6f9c4855 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h @@ -7,8 +7,9 @@ #include +#include + #include -#include namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/devicesupport/filetransfer.h b/src/plugins/projectexplorer/devicesupport/filetransfer.h index cb8fcedf9e0..f73a3741682 100644 --- a/src/plugins/projectexplorer/devicesupport/filetransfer.h +++ b/src/plugins/projectexplorer/devicesupport/filetransfer.h @@ -7,7 +7,7 @@ #include "filetransferinterface.h" #include "idevicefwd.h" -#include +#include namespace Utils { class ProcessResultData; } diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 55c5e2dea5b..f0a902227ad 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -6,11 +6,12 @@ #include "../projectexplorer_export.h" #include "idevicefwd.h" +#include + #include #include #include #include -#include #include #include diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h index bcc0ebee905..1dbda0e4242 100644 --- a/src/plugins/projectexplorer/extracompiler.h +++ b/src/plugins/projectexplorer/extracompiler.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -25,6 +24,7 @@ class QPromise; class QThreadPool; QT_END_NAMESPACE +namespace Tasking { class TaskItem; } namespace Utils { class Process; } namespace ProjectExplorer { diff --git a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp index ae94e6574a7..afd4e0e96a2 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeploystep.cpp @@ -12,8 +12,9 @@ #include #include +#include + #include -#include #include #include diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index a5436c2bbc6..84eb47b8cc1 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -18,7 +18,6 @@ #include #include #include -#include using namespace ProjectExplorer; using namespace Tasking; diff --git a/src/tools/processlauncher/CMakeLists.txt b/src/tools/processlauncher/CMakeLists.txt index 9360d1e9f65..11149814ab8 100644 --- a/src/tools/processlauncher/CMakeLists.txt +++ b/src/tools/processlauncher/CMakeLists.txt @@ -1,7 +1,8 @@ +set(LIBSDIR "${PROJECT_SOURCE_DIR}/src/libs") set(UTILSDIR "${PROJECT_SOURCE_DIR}/src/libs/utils") add_qtc_executable(qtcreator_processlauncher - INCLUDES "${UTILSDIR}" + INCLUDES "${LIBSDIR}" DEPENDS Qt::Core Qt::Network DEFINES UTILS_STATIC_LIBRARY SOURCES diff --git a/src/tools/processlauncher/launchersockethandler.cpp b/src/tools/processlauncher/launchersockethandler.cpp index dae28aa4fbc..c7879dc7cc6 100644 --- a/src/tools/processlauncher/launchersockethandler.cpp +++ b/src/tools/processlauncher/launchersockethandler.cpp @@ -2,10 +2,10 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "launchersockethandler.h" - #include "launcherlogging.h" -#include "processreaper.h" -#include "processutils.h" + +#include +#include #include #include @@ -280,4 +280,4 @@ void LauncherSocketHandler::removeProcess(quintptr token) } // namespace Internal } // namespace Utils -#include +#include "launchersockethandler.moc" diff --git a/src/tools/processlauncher/launchersockethandler.h b/src/tools/processlauncher/launchersockethandler.h index d4146ad5f86..05eefb09b82 100644 --- a/src/tools/processlauncher/launchersockethandler.h +++ b/src/tools/processlauncher/launchersockethandler.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include #include diff --git a/src/tools/processlauncher/processlauncher-main.cpp b/src/tools/processlauncher/processlauncher-main.cpp index f23ea88c92e..0629ec3c6d2 100644 --- a/src/tools/processlauncher/processlauncher-main.cpp +++ b/src/tools/processlauncher/processlauncher-main.cpp @@ -3,7 +3,8 @@ #include "launcherlogging.h" #include "launchersockethandler.h" -#include "singleton.h" + +#include #include #include diff --git a/src/tools/processlauncher/processlauncher.qbs b/src/tools/processlauncher/processlauncher.qbs index 757d50f9bb6..2f03f7fba57 100644 --- a/src/tools/processlauncher/processlauncher.qbs +++ b/src/tools/processlauncher/processlauncher.qbs @@ -7,7 +7,7 @@ QtcTool { Depends { name: "Qt.network" } cpp.defines: base.concat("UTILS_STATIC_LIBRARY") - cpp.includePaths: base.concat(pathToUtils) + cpp.includePaths: base.concat(pathToLibs) Properties { condition: qbs.targetOS.contains("windows") @@ -24,6 +24,7 @@ QtcTool { "processlauncher-main.cpp", ] + property string pathToLibs: sourceDirectory + "/../../libs" property string pathToUtils: sourceDirectory + "/../../libs/utils" Group { name: "protocol sources" diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index 98ee3458965..9849f8776ec 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -19,6 +19,7 @@ add_subdirectory(profilewriter) add_subdirectory(qml) add_subdirectory(runextensions) add_subdirectory(sdktool) +add_subdirectory(solutions) add_subdirectory(toolchaincache) add_subdirectory(tracing) add_subdirectory(treeviewfind) diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs index 2ff98d14097..063977537ba 100644 --- a/tests/auto/auto.qbs +++ b/tests/auto/auto.qbs @@ -22,6 +22,7 @@ Project { "qml/qml.qbs", "runextensions/runextensions.qbs", "sdktool/sdktool.qbs", + "solutions/solutions.qbs", "toolchaincache/toolchaincache.qbs", "tracing/tracing.qbs", "treeviewfind/treeviewfind.qbs", diff --git a/tests/auto/solutions/CMakeLists.txt b/tests/auto/solutions/CMakeLists.txt new file mode 100644 index 00000000000..694d940195d --- /dev/null +++ b/tests/auto/solutions/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(tasking) diff --git a/tests/auto/solutions/solutions.qbs b/tests/auto/solutions/solutions.qbs new file mode 100644 index 00000000000..cc445753cc2 --- /dev/null +++ b/tests/auto/solutions/solutions.qbs @@ -0,0 +1,8 @@ +import qbs + +Project { + name: "Solutions autotests" + references: [ + "tasking/tasking.qbs", + ] +} diff --git a/tests/auto/solutions/tasking/CMakeLists.txt b/tests/auto/solutions/tasking/CMakeLists.txt new file mode 100644 index 00000000000..534d215ccb1 --- /dev/null +++ b/tests/auto/solutions/tasking/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_solutions_tasking + DEPENDS Utils + SOURCES tst_tasking.cpp +) diff --git a/tests/auto/solutions/tasking/tasking.qbs b/tests/auto/solutions/tasking/tasking.qbs new file mode 100644 index 00000000000..173c1fc5752 --- /dev/null +++ b/tests/auto/solutions/tasking/tasking.qbs @@ -0,0 +1,7 @@ +QtcAutotest { + name: "Tasking autotest" + + Depends { name: "Utils" } + + files: "tst_tasking.cpp" +} diff --git a/tests/auto/utils/tasktree/tst_tasktree.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp similarity index 99% rename from tests/auto/utils/tasktree/tst_tasktree.cpp rename to tests/auto/solutions/tasking/tst_tasking.cpp index e897cd36fc4..9efba89bb2e 100644 --- a/tests/auto/utils/tasktree/tst_tasktree.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -1,8 +1,9 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include + #include -#include #include @@ -56,7 +57,7 @@ struct TestData { OnDone onDone = OnDone::Success; }; -class tst_TaskTree : public QObject +class tst_Tasking : public QObject { Q_OBJECT @@ -72,18 +73,18 @@ private slots: void cleanupTestCase(); }; -void tst_TaskTree::initTestCase() +void tst_Tasking::initTestCase() { s_futureSynchronizer = new FutureSynchronizer; } -void tst_TaskTree::cleanupTestCase() +void tst_Tasking::cleanupTestCase() { delete s_futureSynchronizer; s_futureSynchronizer = nullptr; } -void tst_TaskTree::validConstructs() +void tst_Tasking::validConstructs() { const Group task { parallel, @@ -215,7 +216,7 @@ auto setupBarrierAdvance(const TreeStorage &storage, }; } -void tst_TaskTree::testTree_data() +void tst_Tasking::testTree_data() { QTest::addColumn("testData"); @@ -1484,7 +1485,7 @@ void tst_TaskTree::testTree_data() } } -void tst_TaskTree::testTree() +void tst_Tasking::testTree() { QFETCH(TestData, testData); @@ -1536,7 +1537,7 @@ void tst_TaskTree::testTree() QCOMPARE(errorCount, expectedErrorCount); } -void tst_TaskTree::storageOperators() +void tst_Tasking::storageOperators() { TreeStorageBase storage1 = TreeStorage(); TreeStorageBase storage2 = TreeStorage(); @@ -1551,7 +1552,7 @@ void tst_TaskTree::storageOperators() // It also checks whether the destructor of a task tree deletes properly the storage created // while starting the task tree. When running task tree is destructed, the storage done // handler shouldn't be invoked. -void tst_TaskTree::storageDestructor() +void tst_Tasking::storageDestructor() { bool setupCalled = false; const auto setupHandler = [&setupCalled](CustomStorage *) { @@ -1586,6 +1587,6 @@ void tst_TaskTree::storageDestructor() QVERIFY(!doneCalled); } -QTEST_GUILESS_MAIN(tst_TaskTree) +QTEST_GUILESS_MAIN(tst_Tasking) -#include "tst_tasktree.moc" +#include "tst_tasking.moc" diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt index 1bb4bb641ae..e78cb3380cc 100644 --- a/tests/auto/utils/CMakeLists.txt +++ b/tests/auto/utils/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(persistentsettings) add_subdirectory(process) add_subdirectory(settings) add_subdirectory(stringutils) -add_subdirectory(tasktree) add_subdirectory(templateengine) add_subdirectory(treemodel) add_subdirectory(text) diff --git a/tests/auto/utils/tasktree/CMakeLists.txt b/tests/auto/utils/tasktree/CMakeLists.txt deleted file mode 100644 index 2a1ae73630b..00000000000 --- a/tests/auto/utils/tasktree/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_qtc_test(tst_utils_tasktree - DEPENDS Utils - SOURCES tst_tasktree.cpp -) diff --git a/tests/auto/utils/tasktree/tasktree.qbs b/tests/auto/utils/tasktree/tasktree.qbs deleted file mode 100644 index 9b9789c4509..00000000000 --- a/tests/auto/utils/tasktree/tasktree.qbs +++ /dev/null @@ -1,26 +0,0 @@ -import qbs.FileInfo - -Project { - QtcAutotest { - name: "TaskTree autotest" - - Depends { name: "Utils" } - Depends { name: "app_version_header" } - - files: [ - "tst_tasktree.cpp", - ] - cpp.defines: { - var defines = base; - if (qbs.targetOS === "windows") - defines.push("_CRT_SECURE_NO_WARNINGS"); - var absLibExecPath = FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, - qtc.ide_libexec_path); - var relLibExecPath = FileInfo.relativePath(destinationDirectory, absLibExecPath); - defines.push('TEST_RELATIVE_LIBEXEC_PATH="' + relLibExecPath + '"'); - defines.push('TESTAPP_PATH="' - + FileInfo.joinPaths(destinationDirectory, "testapp") + '"'); - return defines; - } - } -} diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index 6ed3fd73486..e267f009f7e 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -19,7 +19,6 @@ Project { "process/process.qbs", "settings/settings.qbs", "stringutils/stringutils.qbs", - "tasktree/tasktree.qbs", "templateengine/templateengine.qbs", "treemodel/treemodel.qbs", "unixdevicefileaccess/unixdevicefileaccess.qbs", diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasktree/taskwidget.h index ae8e7b6788c..dc8821af5e1 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasktree/taskwidget.h @@ -1,8 +1,9 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include + #include -#include #include From ac0f273081c6294d43c39f1ba4af848bd36da683 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Tue, 16 May 2023 15:18:36 +0200 Subject: [PATCH 1098/1447] Git: Fix missing instant blame with line folding When lines are folded (e.g. the license header), the editors lineCount() is smaller than its blockCount(). That resulted in missing blame marks for the last document lines. E.g. if 10 lines were folded, the last 10 lines did not have blame marks. Change-Id: I502afb09697fd3d6a062d3ae2321357a3e565a0e Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/git/gitplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 7443f0baa39..34baa29d9d3 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -1548,7 +1548,7 @@ void GitPluginPrivate::instantBlame() const QTextCursor cursor = widget->textCursor(); const QTextBlock block = cursor.block(); const int line = block.blockNumber() + 1; - const int lines = widget->document()->lineCount(); + const int lines = widget->document()->blockCount(); if (line >= lines) { m_blameMark.reset(); From 29371dc2f3d736b04ee706e2bd2498e8d8ea755a Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Mon, 15 May 2023 12:47:56 +0200 Subject: [PATCH 1099/1447] Git: Cache author and encoding for instant blame Querying both may be expensive and is only necessary when the repository is changed. Fixes: QTCREATORBUG-29151 Change-Id: I1d37f8b8708c02a8c3dc2d89fe7e331f0f416818 Reviewed-by: Reviewed-by: Orgad Shaneh --- src/plugins/git/gitplugin.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 34baa29d9d3..2b9f908ff86 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -394,6 +394,7 @@ public: void instantBlameOnce(); void instantBlame(); void stopInstantBlame(); + bool refreshWorkingDirectory(const FilePath &workingDirectory); void onApplySettings(); @@ -428,6 +429,8 @@ public: FilePath m_submitRepository; QString m_commitMessageFileName; + FilePath m_workingDirectory; + QTextCodec *m_codec = nullptr; Author m_author; int m_lastVisitedEditorLine = -1; QTimer *m_cursorPositionChangedTimer = nullptr; @@ -1439,9 +1442,8 @@ void GitPluginPrivate::setupInstantBlame() } const Utils::FilePath workingDirectory = GitPlugin::currentState().currentFileTopLevel(); - if (workingDirectory.isEmpty()) + if (!refreshWorkingDirectory(workingDirectory)) return; - m_author = GitClient::instance()->getAuthor(workingDirectory); const TextEditorWidget *widget = TextEditorWidget::fromEditor(editor); if (!widget) @@ -1524,9 +1526,8 @@ void GitPluginPrivate::instantBlameOnce() this, [this] { m_blameMark.reset(); }, Qt::SingleShotConnection); const Utils::FilePath workingDirectory = GitPlugin::currentState().topLevel(); - if (workingDirectory.isEmpty()) + if (!refreshWorkingDirectory(workingDirectory)) return; - m_author = GitClient::instance()->getAuthor(workingDirectory); } m_lastVisitedEditorLine = -1; @@ -1574,10 +1575,9 @@ void GitPluginPrivate::instantBlame() const CommitInfo info = parseBlameOutput(output.split('\n'), filePath, m_author); m_blameMark.reset(new BlameMark(filePath, line, info)); }; - QTextCodec *codec = GitClient::instance()->encoding(GitClient::EncodingCommit, workingDirectory); GitClient::instance()->vcsExecWithHandler(workingDirectory, {"blame", "-p", "-L", lineString, "--", filePath.toString()}, - this, commandHandler, RunFlags::NoOutput, codec); + this, commandHandler, RunFlags::NoOutput, m_codec); } void GitPluginPrivate::stopInstantBlame() @@ -1587,6 +1587,21 @@ void GitPluginPrivate::stopInstantBlame() disconnect(m_blameCursorPosConn); } +bool GitPluginPrivate::refreshWorkingDirectory(const FilePath &workingDirectory) +{ + if (workingDirectory.isEmpty()) + return false; + + if (m_workingDirectory == workingDirectory) + return true; + + m_workingDirectory = workingDirectory; + m_author = GitClient::instance()->getAuthor(workingDirectory); + m_codec = GitClient::instance()->encoding(GitClient::EncodingCommit, workingDirectory); + + return true; +} + IEditor *GitPluginPrivate::openSubmitEditor(const QString &fileName, const CommitData &cd) { IEditor *editor = EditorManager::openEditor(FilePath::fromString(fileName), From 1fc2459b6219a0163f2a52bb636f6ec473791615 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 28 Apr 2023 08:39:20 +0200 Subject: [PATCH 1100/1447] Utils: Unify CheckableMessageBox and make it look more native Change-Id: I5690c16f38cfd2058e01441283bec28d44cadf75 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/utils/checkablemessagebox.cpp | 494 +++++------------- src/libs/utils/checkablemessagebox.h | 251 ++++++--- src/plugins/android/androidplugin.cpp | 1 - src/plugins/bookmarks/bookmarkmanager.cpp | 12 +- src/plugins/clangtools/clangtool.cpp | 12 +- src/plugins/clangtools/clangtoolsutils.cpp | 11 +- .../cmakebuildconfiguration.cpp | 25 +- .../cmakeprojectmanager.cpp | 36 +- .../editormanager/editormanager.cpp | 18 +- .../coreplugin/locator/filesystemfilter.cpp | 31 +- src/plugins/debugger/breakhandler.cpp | 17 +- src/plugins/debugger/cdb/cdbengine.cpp | 13 +- src/plugins/debugger/debuggerengine.cpp | 18 +- src/plugins/debugger/debuggerplugin.cpp | 11 +- src/plugins/debugger/debuggerruncontrol.cpp | 14 +- .../shared/cdbsymbolpathlisteditor.cpp | 2 +- src/plugins/debugger/watchhandler.cpp | 15 +- src/plugins/git/gitclient.cpp | 18 +- src/plugins/projectexplorer/runcontrol.cpp | 33 +- .../propertyeditor/aligndistribute.cpp | 10 +- src/plugins/squish/squishnavigationwidget.cpp | 17 +- src/plugins/valgrind/memchecktool.cpp | 10 +- src/plugins/welcome/introductionwidget.cpp | 3 +- 23 files changed, 462 insertions(+), 610 deletions(-) diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index 5d3011ff597..92b111ed7c7 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -3,6 +3,7 @@ #include "checkablemessagebox.h" +#include "hostosinfo.h" #include "qtcassert.h" #include "utilstr.h" @@ -30,398 +31,159 @@ static const char kDoNotAskAgainKey[] = "DoNotAskAgain"; namespace Utils { -class CheckableMessageBoxPrivate +static QMessageBox::StandardButton exec( + QWidget *parent, + QMessageBox::Icon icon, + const QString &title, + const QString &text, + std::optional decider, + QMessageBox::StandardButtons buttons, + QMessageBox::StandardButton defaultButton, + QMessageBox::StandardButton acceptButton, + QMap buttonTextOverrides) { -public: - CheckableMessageBoxPrivate(QDialog *q) - { - QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + QMessageBox msgBox(parent); + msgBox.setWindowTitle(title); + msgBox.setIcon(icon); + msgBox.setText(text); + msgBox.setTextFormat(Qt::RichText); + msgBox.setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse); - pixmapLabel = new QLabel(q); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth()); - pixmapLabel->setSizePolicy(sizePolicy); - pixmapLabel->setVisible(false); - pixmapLabel->setFocusPolicy(Qt::NoFocus); - - auto pixmapSpacer = - new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); - - messageLabel = new QLabel(q); - messageLabel->setMinimumSize(QSize(300, 0)); - messageLabel->setWordWrap(true); - messageLabel->setOpenExternalLinks(true); - messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse); - messageLabel->setFocusPolicy(Qt::NoFocus); - messageLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); - - checkBox = new QCheckBox(q); - checkBox->setText(Tr::tr("Do not ask again")); - - const QString showText = Tr::tr("Show Details..."); - detailsButton = new QPushButton(showText, q); - detailsButton->setAutoDefault(false); - detailsButton->hide(); - detailsText = new QTextEdit(q); - detailsText->hide(); - QObject::connect(detailsButton, &QPushButton::clicked, detailsText, [this, showText] { - detailsText->setVisible(!detailsText->isVisible()); - detailsButton->setText( - detailsText->isVisible() ? Tr::tr("Hide Details...") : showText); - }); - - buttonBox = new QDialogButtonBox(q); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - - auto verticalLayout = new QVBoxLayout(); - verticalLayout->addWidget(pixmapLabel); - verticalLayout->addItem(pixmapSpacer); - - auto horizontalLayout_2 = new QHBoxLayout(); - horizontalLayout_2->addLayout(verticalLayout); - horizontalLayout_2->addWidget(messageLabel, 10); - - auto horizontalLayout = new QHBoxLayout(); - horizontalLayout->addWidget(checkBox); - horizontalLayout->addStretch(10); - - auto detailsButtonLayout = new QHBoxLayout; - detailsButtonLayout->addWidget(detailsButton); - detailsButtonLayout->addStretch(10); - - auto verticalLayout_2 = new QVBoxLayout(q); - verticalLayout_2->addLayout(horizontalLayout_2); - verticalLayout_2->addLayout(horizontalLayout); - verticalLayout_2->addLayout(detailsButtonLayout); - verticalLayout_2->addWidget(detailsText, 10); - verticalLayout_2->addStretch(1); - verticalLayout_2->addWidget(buttonBox); - } - - QLabel *pixmapLabel = nullptr; - QLabel *messageLabel = nullptr; - QCheckBox *checkBox = nullptr; - QDialogButtonBox *buttonBox = nullptr; - QAbstractButton *clickedButton = nullptr; - QPushButton *detailsButton = nullptr; - QTextEdit *detailsText = nullptr; - QMessageBox::Icon icon = QMessageBox::NoIcon; -}; - -CheckableMessageBox::CheckableMessageBox(QWidget *parent) : - QDialog(parent), - d(new CheckableMessageBoxPrivate(this)) -{ - setModal(true); - connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(d->buttonBox, &QDialogButtonBox::clicked, - this, [this](QAbstractButton *b) { d->clickedButton = b; }); -} - -CheckableMessageBox::~CheckableMessageBox() -{ - delete d; -} - -QAbstractButton *CheckableMessageBox::clickedButton() const -{ - return d->clickedButton; -} - -QDialogButtonBox::StandardButton CheckableMessageBox::clickedStandardButton() const -{ - if (d->clickedButton) - return d->buttonBox->standardButton(d->clickedButton); - return QDialogButtonBox::NoButton; -} - -QString CheckableMessageBox::text() const -{ - return d->messageLabel->text(); -} - -void CheckableMessageBox::setText(const QString &t) -{ - d->messageLabel->setText(t); -} - -QMessageBox::Icon CheckableMessageBox::icon() const -{ - return d->icon; -} - -// See QMessageBoxPrivate::standardIcon -static QPixmap pixmapForIcon(QMessageBox::Icon icon, QWidget *w) -{ - const QStyle *style = w ? w->style() : QApplication::style(); - const int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, w); - QIcon tmpIcon; - switch (icon) { - case QMessageBox::Information: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, w); - break; - case QMessageBox::Warning: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, w); - break; - case QMessageBox::Critical: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, nullptr, w); - break; - case QMessageBox::Question: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, w); - break; - default: - break; - } - if (!tmpIcon.isNull()) { - QWindow *window = nullptr; - if (w) { - window = w->windowHandle(); - if (!window) { - if (const QWidget *nativeParent = w->nativeParentWidget()) - window = nativeParent->windowHandle(); - } + if (HostOsInfo::isMacHost()) { + // Message boxes on macOS cannot display links. + // If the message contains a link, we need to disable native dialogs. + if (text.contains("= QT_VERSION_CHECK(6, 6, 0) + msgBox.setOptions(QMessageBox::Option::DontUseNativeDialog); +#endif } - return tmpIcon.pixmap(window, QSize(iconSize, iconSize)); } - return QPixmap(); -} -void CheckableMessageBox::setIcon(QMessageBox::Icon icon) -{ - d->icon = icon; - const QPixmap pixmap = pixmapForIcon(icon, this); - d->pixmapLabel->setPixmap(pixmap); - d->pixmapLabel->setVisible(!pixmap.isNull()); -} + if (decider) { + if (!CheckableMessageBox::shouldAskAgain(*decider)) + return acceptButton; -bool CheckableMessageBox::isChecked() const -{ - return d->checkBox->isChecked(); -} + msgBox.setCheckBox(new QCheckBox); -void CheckableMessageBox::setChecked(bool s) -{ - d->checkBox->setChecked(s); -} - -QString CheckableMessageBox::checkBoxText() const -{ - return d->checkBox->text(); -} - -void CheckableMessageBox::setCheckBoxText(const QString &t) -{ - d->checkBox->setText(t); -} - -bool CheckableMessageBox::isCheckBoxVisible() const -{ - return d->checkBox->isVisible(); -} - -void CheckableMessageBox::setCheckBoxVisible(bool v) -{ - d->checkBox->setVisible(v); -} - -QString CheckableMessageBox::detailedText() const -{ - return d->detailsText->toPlainText(); -} - -void CheckableMessageBox::setDetailedText(const QString &text) -{ - d->detailsText->setText(text); - if (!text.isEmpty()) - d->detailsButton->setVisible(true); -} - -QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const -{ - return d->buttonBox->standardButtons(); -} - -void CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s) -{ - d->buttonBox->setStandardButtons(s); -} - -QPushButton *CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const -{ - return d->buttonBox->button(b); -} - -QPushButton *CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role) -{ - return d->buttonBox->addButton(text, role); -} - -QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const -{ - const QList buttons = d->buttonBox->buttons(); - for (QAbstractButton *b : buttons) - if (auto *pb = qobject_cast(b)) - if (pb->isDefault()) - return d->buttonBox->standardButton(pb); - return QDialogButtonBox::NoButton; -} - -void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s) -{ - if (QPushButton *b = d->buttonBox->button(s)) { - b->setDefault(true); - b->setFocus(); + std::visit( + [&msgBox](auto &&decider) { + using T = std::decay_t; + msgBox.checkBox()->setText(decider.text); + if constexpr (std::is_same_v) { + msgBox.checkBox()->setChecked(decider.value); + } else if constexpr (std::is_same_v) { + msgBox.checkBox()->setChecked( + decider.settings->value(decider.settingsSubKey, false).toBool()); + } else if constexpr (std::is_same_v) { + msgBox.checkBox()->setChecked(decider.aspect.value()); + } + }, + *decider); } + + msgBox.setStandardButtons(buttons); + msgBox.setDefaultButton(defaultButton); + for (auto it = buttonTextOverrides.constBegin(); it != buttonTextOverrides.constEnd(); ++it) + msgBox.button(it.key())->setText(it.value()); + msgBox.exec(); + + QMessageBox::StandardButton clickedBtn = msgBox.standardButton(msgBox.clickedButton()); + + if (decider && msgBox.checkBox()->isChecked() + && (acceptButton == QMessageBox::NoButton || clickedBtn == acceptButton)) + CheckableMessageBox::doNotAskAgain(*decider); + return clickedBtn; } -QDialogButtonBox::StandardButton -CheckableMessageBox::question(QWidget *parent, - const QString &title, - const QString &question, - const QString &checkBoxText, - bool *checkBoxSetting, - QDialogButtonBox::StandardButtons buttons, - QDialogButtonBox::StandardButton defaultButton) +QMessageBox::StandardButton CheckableMessageBox::question( + QWidget *parent, + const QString &title, + const QString &question, + std::optional decider, + QMessageBox::StandardButtons buttons, + QMessageBox::StandardButton defaultButton, + QMessageBox::StandardButton acceptButton, + QMap buttonTextOverrides) { - CheckableMessageBox mb(parent); - mb.setWindowTitle(title); - mb.setIcon(QMessageBox::Question); - mb.setText(question); - mb.setCheckBoxText(checkBoxText); - mb.setChecked(*checkBoxSetting); - mb.setStandardButtons(buttons); - mb.setDefaultButton(defaultButton); - mb.exec(); - *checkBoxSetting = mb.isChecked(); - return mb.clickedStandardButton(); + return exec(parent, + QMessageBox::Question, + title, + question, + decider, + buttons, + defaultButton, + acceptButton, + buttonTextOverrides); } -QDialogButtonBox::StandardButton -CheckableMessageBox::information(QWidget *parent, - const QString &title, - const QString &text, - const QString &checkBoxText, - bool *checkBoxSetting, - QDialogButtonBox::StandardButtons buttons, - QDialogButtonBox::StandardButton defaultButton) +QMessageBox::StandardButton CheckableMessageBox::information( + QWidget *parent, + const QString &title, + const QString &text, + std::optional decider, + QMessageBox::StandardButtons buttons, + QMessageBox::StandardButton defaultButton, + QMap buttonTextOverrides) { - CheckableMessageBox mb(parent); - mb.setWindowTitle(title); - mb.setIcon(QMessageBox::Information); - mb.setText(text); - mb.setCheckBoxText(checkBoxText); - mb.setChecked(*checkBoxSetting); - mb.setStandardButtons(buttons); - mb.setDefaultButton(defaultButton); - mb.exec(); - *checkBoxSetting = mb.isChecked(); - return mb.clickedStandardButton(); + return exec(parent, + QMessageBox::Information, + title, + text, + decider, + buttons, + defaultButton, + QMessageBox::NoButton, + buttonTextOverrides); } -QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db) +void CheckableMessageBox::doNotAskAgain(Decider &decider) { - return static_cast(int(db)); + std::visit( + [](auto &&decider) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + decider.value = true; + } else if constexpr (std::is_same_v) { + decider.settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); + decider.settings->setValue(decider.settingsSubKey, true); + decider.settings->endGroup(); + } else if constexpr (std::is_same_v) { + decider.aspect.setValue(true); + } + }, + decider); } -bool CheckableMessageBox::shouldAskAgain(QSettings *settings, const QString &settingsSubKey) +bool CheckableMessageBox::shouldAskAgain(const Decider &decider) { - if (QTC_GUARD(settings)) { - settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); - bool shouldNotAsk = settings->value(settingsSubKey, false).toBool(); - settings->endGroup(); - if (shouldNotAsk) - return false; - } - return true; + bool result = std::visit( + [](auto &&decider) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return !decider.value; + } else if constexpr (std::is_same_v) { + decider.settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); + bool shouldNotAsk = decider.settings->value(decider.settingsSubKey, false).toBool(); + decider.settings->endGroup(); + return !shouldNotAsk; + } else if constexpr (std::is_same_v) { + return !decider.aspect.value(); + } + }, + decider); + + return result; } -enum DoNotAskAgainType{Question, Information}; - -void initDoNotAskAgainMessageBox(CheckableMessageBox &messageBox, const QString &title, - const QString &text, QDialogButtonBox::StandardButtons buttons, - QDialogButtonBox::StandardButton defaultButton, - DoNotAskAgainType type) +bool CheckableMessageBox::shouldAskAgain(QSettings *settings, const QString &key) { - messageBox.setWindowTitle(title); - messageBox.setIcon(type == Information ? QMessageBox::Information : QMessageBox::Question); - messageBox.setText(text); - messageBox.setCheckBoxVisible(true); - messageBox.setCheckBoxText(type == Information ? CheckableMessageBox::msgDoNotShowAgain() - : CheckableMessageBox::msgDoNotAskAgain()); - messageBox.setChecked(false); - messageBox.setStandardButtons(buttons); - messageBox.setDefaultButton(defaultButton); + return shouldAskAgain(make_decider(settings, key)); } -void CheckableMessageBox::doNotAskAgain(QSettings *settings, const QString &settingsSubKey) +void CheckableMessageBox::doNotAskAgain(QSettings *settings, const QString &key) { - if (!settings) - return; - - settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); - settings->setValue(settingsSubKey, true); - settings->endGroup(); -} - -/*! - Shows a message box with given \a title and \a text, and a \gui {Do not ask again} check box. - If the user checks the check box and accepts the dialog with the \a acceptButton, - further invocations of this function with the same \a settings and \a settingsSubKey will not - show the dialog, but instantly return \a acceptButton. - - Returns the clicked button, or QDialogButtonBox::NoButton if the user rejects the dialog - with the escape key, or \a acceptButton if the dialog is suppressed. -*/ -QDialogButtonBox::StandardButton -CheckableMessageBox::doNotAskAgainQuestion(QWidget *parent, const QString &title, - const QString &text, QSettings *settings, - const QString &settingsSubKey, - QDialogButtonBox::StandardButtons buttons, - QDialogButtonBox::StandardButton defaultButton, - QDialogButtonBox::StandardButton acceptButton) - -{ - if (!shouldAskAgain(settings, settingsSubKey)) - return acceptButton; - - CheckableMessageBox messageBox(parent); - initDoNotAskAgainMessageBox(messageBox, title, text, buttons, defaultButton, Question); - messageBox.exec(); - if (messageBox.isChecked() && (messageBox.clickedStandardButton() == acceptButton)) - doNotAskAgain(settings, settingsSubKey); - - return messageBox.clickedStandardButton(); -} - -/*! - Shows a message box with given \a title and \a text, and a \gui {Do not show again} check box. - If the user checks the check box and quits the dialog, further invocations of this - function with the same \a settings and \a settingsSubKey will not show the dialog, but instantly return. - - Returns the clicked button, or QDialogButtonBox::NoButton if the user rejects the dialog - with the escape key, or \a defaultButton if the dialog is suppressed. -*/ -QDialogButtonBox::StandardButton -CheckableMessageBox::doNotShowAgainInformation(QWidget *parent, const QString &title, - const QString &text, QSettings *settings, - const QString &settingsSubKey, - QDialogButtonBox::StandardButtons buttons, - QDialogButtonBox::StandardButton defaultButton) - -{ - if (!shouldAskAgain(settings, settingsSubKey)) - return defaultButton; - - CheckableMessageBox messageBox(parent); - initDoNotAskAgainMessageBox(messageBox, title, text, buttons, defaultButton, Information); - messageBox.exec(); - if (messageBox.isChecked()) - doNotAskAgain(settings, settingsSubKey); - - return messageBox.clickedStandardButton(); + Decider decider = make_decider(settings, key); + return doNotAskAgain(decider); } /*! diff --git a/src/libs/utils/checkablemessagebox.h b/src/libs/utils/checkablemessagebox.h index eb80e15eac5..e6988fc8e9c 100644 --- a/src/libs/utils/checkablemessagebox.h +++ b/src/libs/utils/checkablemessagebox.h @@ -5,7 +5,8 @@ #include "utils_global.h" -#include +#include "aspects.h" + #include QT_BEGIN_NAMESPACE @@ -16,100 +17,206 @@ namespace Utils { class CheckableMessageBoxPrivate; -class QTCREATOR_UTILS_EXPORT CheckableMessageBox : public QDialog +class QTCREATOR_UTILS_EXPORT CheckableMessageBox { - Q_OBJECT - Q_PROPERTY(QString text READ text WRITE setText) - Q_PROPERTY(QMessageBox::Icon icon READ icon WRITE setIcon) - Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked) - Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText) - Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons) - Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton) - public: - explicit CheckableMessageBox(QWidget *parent); - ~CheckableMessageBox() override; + struct BoolDecision + { + QString text; + bool &value; + }; - static QDialogButtonBox::StandardButton - question(QWidget *parent, - const QString &title, - const QString &question, - const QString &checkBoxText, - bool *checkBoxSetting, - QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, - QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No); + struct SettingsDecision + { + QString text; + QSettings *settings; + QString settingsSubKey; + }; - static QDialogButtonBox::StandardButton - information(QWidget *parent, - const QString &title, - const QString &text, - const QString &checkBoxText, - bool *checkBoxSetting, - QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Ok, - QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::NoButton); + struct AspectDecision + { + QString text; + BoolAspect &aspect; + }; - static QDialogButtonBox::StandardButton - doNotAskAgainQuestion(QWidget *parent, - const QString &title, - const QString &text, - QSettings *settings, - const QString &settingsSubKey, - QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, - QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No, - QDialogButtonBox::StandardButton acceptButton = QDialogButtonBox::Yes); + using Decider = std::variant; - static QDialogButtonBox::StandardButton - doNotShowAgainInformation(QWidget *parent, - const QString &title, - const QString &text, - QSettings *settings, - const QString &settingsSubKey, - QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Ok, - QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::NoButton); + static Decider make_decider(QSettings *settings, + const QString &settingsSubKey, + const QString &text = msgDoNotAskAgain()) + { + return Decider{SettingsDecision{text, settings, settingsSubKey}}; + } - QString text() const; - void setText(const QString &); + static Decider make_decider(bool &value, const QString &text = msgDoNotAskAgain()) + { + return Decider{BoolDecision{text, value}}; + } - bool isChecked() const; - void setChecked(bool s); + static Decider make_decider(BoolAspect &aspect, const QString &text = msgDoNotAskAgain()) + { + return Decider{AspectDecision{text, aspect}}; + } - QString checkBoxText() const; - void setCheckBoxText(const QString &); + static QMessageBox::StandardButton question( + QWidget *parent, + const QString &title, + const QString &question, + std::optional decider = std::nullopt, + QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, + QMessageBox::StandardButton defaultButton = QMessageBox::No, + QMessageBox::StandardButton acceptButton = QMessageBox::Yes, + QMap buttonTextOverrides = {}); - bool isCheckBoxVisible() const; - void setCheckBoxVisible(bool); + static QMessageBox::StandardButton question( + QWidget *parent, + const QString &title, + const QString &question, + bool &value, + QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, + QMessageBox::StandardButton defaultButton = QMessageBox::No, + QMessageBox::StandardButton acceptButton = QMessageBox::Yes, + QMap buttonTextOverrides = {}, + const QString &text = msgDoNotAskAgain()) + { + Decider decider = make_decider(value, text); + return CheckableMessageBox::question(parent, + title, + question, + decider, + buttons, + defaultButton, + acceptButton, + buttonTextOverrides); + } - QString detailedText() const; - void setDetailedText(const QString &text); + static QMessageBox::StandardButton question( + QWidget *parent, + const QString &title, + const QString &question, + QSettings *settings, + const QString &settingsSubKey, + QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, + QMessageBox::StandardButton defaultButton = QMessageBox::No, + QMessageBox::StandardButton acceptButton = QMessageBox::Yes, + QMap buttonTextOverrides = {}, + const QString &text = msgDoNotAskAgain()) + { + Decider decider = make_decider(settings, settingsSubKey, text); + return CheckableMessageBox::question(parent, + title, + question, + decider, + buttons, + defaultButton, + acceptButton, + buttonTextOverrides); + } - QDialogButtonBox::StandardButtons standardButtons() const; - void setStandardButtons(QDialogButtonBox::StandardButtons s); - QPushButton *button(QDialogButtonBox::StandardButton b) const; - QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role); + static QMessageBox::StandardButton question( + QWidget *parent, + const QString &title, + const QString &question, + BoolAspect &aspect, + QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, + QMessageBox::StandardButton defaultButton = QMessageBox::No, + QMessageBox::StandardButton acceptButton = QMessageBox::Yes, + QMap buttonTextOverrides = {}, + const QString &text = msgDoNotAskAgain()) + { + Decider decider = make_decider(aspect, text); + return CheckableMessageBox::question(parent, + title, + question, + decider, + buttons, + defaultButton, + acceptButton, + buttonTextOverrides); + } - QDialogButtonBox::StandardButton defaultButton() const; - void setDefaultButton(QDialogButtonBox::StandardButton s); + static QMessageBox::StandardButton information( + QWidget *parent, + const QString &title, + const QString &text, + std::optional decider = std::nullopt, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, + QMap buttonTextOverrides = {}); - QMessageBox::Icon icon() const; - void setIcon(QMessageBox::Icon icon); + static QMessageBox::StandardButton information( + QWidget *parent, + const QString &title, + const QString &information, + bool &value, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, + QMap buttonTextOverrides = {}, + const QString &text = msgDoNotAskAgain()) + { + Decider decider = make_decider(value, text); + return CheckableMessageBox::information(parent, + title, + information, + decider, + buttons, + defaultButton, + buttonTextOverrides); + } - // Query the result - QAbstractButton *clickedButton() const; - QDialogButtonBox::StandardButton clickedStandardButton() const; + static QMessageBox::StandardButton information( + QWidget *parent, + const QString &title, + const QString &information, + QSettings *settings, + const QString &settingsSubKey, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, + QMap buttonTextOverrides = {}, + const QString &text = msgDoNotAskAgain()) + { + Decider decider = make_decider(settings, settingsSubKey, text); + return CheckableMessageBox::information(parent, + title, + information, + decider, + buttons, + defaultButton, + buttonTextOverrides); + } + + static QMessageBox::StandardButton information( + QWidget *parent, + const QString &title, + const QString &information, + BoolAspect &aspect, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, + QMap buttonTextOverrides = {}, + const QString &text = msgDoNotAskAgain()) + { + Decider decider = make_decider(aspect, text); + return CheckableMessageBox::information(parent, + title, + information, + decider, + buttons, + defaultButton, + buttonTextOverrides); + } // check and set "ask again" status - static bool shouldAskAgain(QSettings *settings, const QString &settingsSubKey); - static void doNotAskAgain(QSettings *settings, const QString &settingsSubKey); + static bool shouldAskAgain(const Decider &decider); + static void doNotAskAgain(Decider &decider); + + static bool shouldAskAgain(QSettings *settings, const QString &key); + static void doNotAskAgain(QSettings *settings, const QString &key); // Conversion convenience - static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton); static void resetAllDoNotAskAgainQuestions(QSettings *settings); static bool hasSuppressedQuestions(QSettings *settings); static QString msgDoNotAskAgain(); static QString msgDoNotShowAgain(); - -private: - CheckableMessageBoxPrivate *d; }; } // namespace Utils diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index c15cfef221d..459edad2bbd 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -34,7 +34,6 @@ #endif #include -#include #include #include diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp index 4e98648147a..77bb0f41518 100644 --- a/src/plugins/bookmarks/bookmarkmanager.cpp +++ b/src/plugins/bookmarks/bookmarkmanager.cpp @@ -257,11 +257,13 @@ void BookmarkView::keyPressEvent(QKeyEvent *event) void BookmarkView::removeAll() { - if (CheckableMessageBox::doNotAskAgainQuestion(this, - Tr::tr("Remove All Bookmarks"), - Tr::tr("Are you sure you want to remove all bookmarks from all files in the current session?"), - ICore::settings(), - QLatin1String("RemoveAllBookmarks")) != QDialogButtonBox::Yes) + if (CheckableMessageBox::question(this, + Tr::tr("Remove All Bookmarks"), + Tr::tr("Are you sure you want to remove all bookmarks from " + "all files in the current session?"), + ICore::settings(), + QLatin1String("RemoveAllBookmarks")) + != QMessageBox::Yes) return; // The performance of this function could be greatly improved. diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index a4d26750651..343849458aa 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -599,12 +599,12 @@ static bool continueDespiteReleaseBuild(const QString &toolName) "

%2

" "") .arg(problem, question); - return CheckableMessageBox::doNotAskAgainQuestion(ICore::dialogParent(), - title, - message, - ICore::settings(), - "ClangToolsCorrectModeWarning") - == QDialogButtonBox::Yes; + return CheckableMessageBox::question(ICore::dialogParent(), + title, + message, + ICore::settings(), + "ClangToolsCorrectModeWarning") + == QMessageBox::Yes; } void ClangTool::startTool(ClangTool::FileSelection fileSelection, diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index 7a812d3750d..a2cdd5fc7ba 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -138,12 +138,11 @@ QString hintAboutBuildBeforeAnalysis() void showHintAboutBuildBeforeAnalysis() { - Utils::CheckableMessageBox::doNotShowAgainInformation( - Core::ICore::dialogParent(), - Tr::tr("Info About Build the Project Before Analysis"), - hintAboutBuildBeforeAnalysis(), - Core::ICore::settings(), - "ClangToolsDisablingBuildBeforeAnalysisHint"); + Utils::CheckableMessageBox::information(Core::ICore::dialogParent(), + Tr::tr("Info About Build the Project Before Analysis"), + hintAboutBuildBeforeAnalysis(), + Core::ICore::settings(), + "ClangToolsDisablingBuildBeforeAnalysisHint"); } FilePath fullPath(const FilePath &executable) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index d7f85a7e44b..f425af569cf 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -590,23 +590,18 @@ void CMakeBuildSettingsWidget::batchEditConfiguration() void CMakeBuildSettingsWidget::reconfigureWithInitialParameters() { auto settings = CMakeSpecificSettings::instance(); - bool doNotAsk = !settings->askBeforeReConfigureInitialParams.value(); - if (!doNotAsk) { - QDialogButtonBox::StandardButton reply = CheckableMessageBox::question( - Core::ICore::dialogParent(), - Tr::tr("Re-configure with Initial Parameters"), - Tr::tr("Clear CMake configuration and configure with initial parameters?"), - Tr::tr("Do not ask again"), - &doNotAsk, - QDialogButtonBox::Yes | QDialogButtonBox::No, - QDialogButtonBox::Yes); + QMessageBox::StandardButton reply = CheckableMessageBox::question( + Core::ICore::dialogParent(), + Tr::tr("Re-configure with Initial Parameters"), + Tr::tr("Clear CMake configuration and configure with initial parameters?"), + settings->askBeforeReConfigureInitialParams, + QMessageBox::Yes | QMessageBox::No, + QMessageBox::Yes); - settings->askBeforeReConfigureInitialParams.setValue(!doNotAsk); - settings->writeSettings(Core::ICore::settings()); + settings->writeSettings(Core::ICore::settings()); - if (reply != QDialogButtonBox::Yes) { - return; - } + if (reply != QMessageBox::Yes) { + return; } m_buildSystem->clearCMakeCache(); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index ab7bfb4990e..a1950b6bccd 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -232,30 +232,22 @@ void CMakeManager::enableBuildFileMenus(Node *node) void CMakeManager::reloadCMakePresets() { auto settings = CMakeSpecificSettings::instance(); - bool doNotAsk = !settings->askBeforePresetsReload.value(); - if (!doNotAsk) { - CheckableMessageBox question(Core::ICore::dialogParent()); - question.setIcon(QMessageBox::Question); - question.setWindowTitle(Tr::tr("Reload CMake Presets")); - question.setText(Tr::tr("Re-generates the CMake presets kits. The manual CMake project modifications will be lost.")); - question.setCheckBoxText(Tr::tr("Do not ask again")); - question.setCheckBoxVisible(true); - question.setChecked(doNotAsk); - question.setStandardButtons(QDialogButtonBox::Cancel); + QMessageBox::StandardButton clickedButton + = CheckableMessageBox::question(Core::ICore::dialogParent(), + Tr::tr("Reload CMake Presets"), + Tr::tr("Re-generates the CMake presets kits. The manual " + "CMake project modifications will be lost."), + settings->askBeforePresetsReload, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Yes, + QMessageBox::Yes, + { + {QMessageBox::Yes, Tr::tr("Reload")}, + }); - question.addButton(Tr::tr("Reload"), QDialogButtonBox::YesRole); - question.setDefaultButton(QDialogButtonBox::Yes); - question.exec(); - - doNotAsk = question.isChecked(); - - settings->askBeforePresetsReload.setValue(!doNotAsk); - settings->writeSettings(Core::ICore::settings()); - - if (question.clickedStandardButton() == QDialogButtonBox::Cancel) - return; - } + if (clickedButton == QMessageBox::Cancel) + return; CMakeProject *project = static_cast(ProjectTree::currentProject()); if (!project) diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 19c6b309f1b..107ce249e1e 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -752,17 +752,13 @@ bool EditorManagerPrivate::skipOpeningBigTextFile(const FilePath &filePath) .arg(filePath.fileName()) .arg(fileSizeInMB, 0, 'f', 2); - CheckableMessageBox messageBox(ICore::dialogParent()); - messageBox.setWindowTitle(title); - messageBox.setText(text); - messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::No); - messageBox.setDefaultButton(QDialogButtonBox::No); - messageBox.setIcon(QMessageBox::Question); - messageBox.setCheckBoxVisible(true); - messageBox.setCheckBoxText(CheckableMessageBox::msgDoNotAskAgain()); - messageBox.exec(); - setWarnBeforeOpeningBigFilesEnabled(!messageBox.isChecked()); - return messageBox.clickedStandardButton() != QDialogButtonBox::Yes; + bool askAgain = true; + auto decider = CheckableMessageBox::make_decider(askAgain); + + QMessageBox::StandardButton clickedButton + = CheckableMessageBox::question(ICore::dialogParent(), title, text, decider); + setWarnBeforeOpeningBigFilesEnabled(askAgain); + return clickedButton != QMessageBox::Yes; } return false; diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 066be68330c..32ad0a2a2bf 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -59,25 +59,18 @@ static ILocatorFilter::MatchLevel matchLevelFor(const QRegularExpressionMatch &m static bool askForCreating(const QString &title, const FilePath &filePath) { - if (CheckableMessageBox::shouldAskAgain(ICore::settings(), kAlwaysCreate)) { - CheckableMessageBox messageBox(ICore::dialogParent()); - messageBox.setWindowTitle(title); - messageBox.setIcon(QMessageBox::Question); - messageBox.setText(Tr::tr("Create \"%1\"?").arg(filePath.shortNativePath())); - messageBox.setCheckBoxVisible(true); - messageBox.setCheckBoxText(Tr::tr("Always create")); - messageBox.setChecked(false); - messageBox.setStandardButtons(QDialogButtonBox::Cancel); - QPushButton *createButton = messageBox.addButton(Tr::tr("Create"), - QDialogButtonBox::AcceptRole); - messageBox.setDefaultButton(QDialogButtonBox::Cancel); - messageBox.exec(); - if (messageBox.clickedButton() != createButton) - return false; - if (messageBox.isChecked()) - CheckableMessageBox::doNotAskAgain(ICore::settings(), kAlwaysCreate); - } - return true; + QMessageBox::StandardButton selected + = CheckableMessageBox::question(ICore::dialogParent(), + title, + Tr::tr("Create \"%1\"?").arg(filePath.shortNativePath()), + ICore::settings(), + kAlwaysCreate, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel, + QMessageBox::Yes, + {{QMessageBox::Yes, Tr::tr("Create")}}, + Tr::tr("Always create")); + return selected == QMessageBox::Yes; } static void createAndOpenFile(const FilePath &filePath) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index f13ac94d89b..2b21db5be53 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -2691,14 +2692,14 @@ void BreakpointManager::gotoLocation(const GlobalBreakpoint &gbp) const void BreakpointManager::executeDeleteAllBreakpointsDialog() { - QDialogButtonBox::StandardButton pressed = - CheckableMessageBox::doNotAskAgainQuestion(ICore::dialogParent(), - Tr::tr("Remove All Breakpoints"), - Tr::tr("Are you sure you want to remove all breakpoints " - "from all files in the current session?"), - ICore::settings(), - "RemoveAllBreakpoints"); - if (pressed != QDialogButtonBox::Yes) + QMessageBox::StandardButton pressed + = CheckableMessageBox::question(ICore::dialogParent(), + Tr::tr("Remove All Breakpoints"), + Tr::tr("Are you sure you want to remove all breakpoints " + "from all files in the current session?"), + ICore::settings(), + "RemoveAllBreakpoints"); + if (pressed != QMessageBox::Yes) return; for (GlobalBreakpoint gbp : globalBreakpoints()) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 9117728f8e2..52e6d71fe6a 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2262,12 +2262,11 @@ void CdbEngine::checkQtSdkPdbFiles(const QString &module) "symbols for the debugger.") .arg(qtName); - CheckableMessageBox::doNotShowAgainInformation( - Core::ICore::dialogParent(), - Tr::tr("Missing Qt Debug Information"), - message, - Core::ICore::settings(), - "CdbQtSdkPdbHint"); + CheckableMessageBox::information(Core::ICore::dialogParent(), + Tr::tr("Missing Qt Debug Information"), + message, + Core::ICore::settings(), + "CdbQtSdkPdbHint"); showMessage("Missing Qt Debug Information Files package for " + qtName, LogMisc); }; @@ -2288,7 +2287,7 @@ void CdbEngine::parseOutputLine(QString line) // An extension notification (potentially consisting of several chunks) if (!m_initialSessionIdleHandled && line.startsWith("SECURE: File not allowed to be loaded") && line.endsWith("qtcreatorcdbext.dll")) { - CheckableMessageBox::doNotShowAgainInformation( + CheckableMessageBox::information( Core::ICore::dialogParent(), Tr::tr("Debugger Start Failed"), Tr::tr("The system prevents loading of %1, which is required for debugging. " diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index a59e48ecf99..28d218929a6 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2722,9 +2722,11 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor; bool warnOnInappropriateDebugger = false; QString detailedWarning; + auto shouldAskAgain = CheckableMessageBox::make_decider(coreSettings, + warnOnInappropriateDebuggerKey); switch (rp.toolChainAbi.binaryFormat()) { case Abi::PEFormat: { - if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) { + if (CheckableMessageBox::shouldAskAgain(shouldAskAgain)) { QString preferredDebugger; if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) { if (rp.cppEngineType == CdbEngineType) @@ -2764,7 +2766,7 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) break; } case Abi::ElfFormat: { - if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) { + if (CheckableMessageBox::shouldAskAgain(shouldAskAgain)) { if (rp.cppEngineType == CdbEngineType) { warnOnInappropriateDebugger = true; detailedWarning = Tr::tr( @@ -2870,16 +2872,14 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) return; } if (warnOnInappropriateDebugger) { - CheckableMessageBox::doNotShowAgainInformation( + CheckableMessageBox::information( Core::ICore::dialogParent(), Tr::tr("Warning"), - Tr::tr( - "The selected debugger may be inappropriate for the inferior.\n" - "Examining symbols and setting breakpoints by file name and line number " - "may fail.\n") + Tr::tr("The selected debugger may be inappropriate for the inferior.\n" + "Examining symbols and setting breakpoints by file name and line number " + "may fail.\n") + '\n' + detailedWarning, - Core::ICore::settings(), - warnOnInappropriateDebuggerKey); + shouldAskAgain); } else if (warnOnRelease) { AsynchronousMessageBox::information(Tr::tr("Warning"), Tr::tr("This does not seem to be a \"Debug\" build.\n" diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index e8c14d4dccf..8b14ff0e236 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -2240,10 +2240,13 @@ bool wantRunTool(ToolMode toolMode, const QString &toolName) "or otherwise insufficient output.

" "Do you want to continue and run the tool in %2 mode?

") .arg(toolName).arg(currentMode).arg(toolModeString); - if (Utils::CheckableMessageBox::doNotAskAgainQuestion(ICore::dialogParent(), - title, message, ICore::settings(), "AnalyzerCorrectModeWarning") - != QDialogButtonBox::Yes) - return false; + if (Utils::CheckableMessageBox::question(ICore::dialogParent(), + title, + message, + ICore::settings(), + "AnalyzerCorrectModeWarning") + != QMessageBox::Yes) + return false; } return true; diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 663ad5bf6d4..17da601429d 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -616,14 +616,12 @@ void DebuggerRunTool::start() showMessage(warningMessage, LogWarning); - static bool checked = true; - if (checked) - CheckableMessageBox::information(Core::ICore::dialogParent(), - Tr::tr("Debugger"), - warningMessage, - Tr::tr("&Show this message again."), - &checked, - QDialogButtonBox::Ok); + static bool doNotShowAgain = false; + CheckableMessageBox::information(Core::ICore::dialogParent(), + Tr::tr("Debugger"), + warningMessage, + doNotShowAgain, + QMessageBox::Ok); } } diff --git a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp index eb17cba3dec..9f3824ffce5 100644 --- a/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp +++ b/src/plugins/debugger/shared/cdbsymbolpathlisteditor.cpp @@ -9,13 +9,13 @@ #include #include -#include #include #include #include #include #include +#include #include #include #include diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 739c0ee4ce7..d533a0d4f63 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -52,8 +53,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -2571,11 +2572,13 @@ void WatchModel::clearWatches() if (theWatcherNames.isEmpty()) return; - const QDialogButtonBox::StandardButton ret = CheckableMessageBox::doNotAskAgainQuestion( - ICore::dialogParent(), Tr::tr("Remove All Expression Evaluators"), - Tr::tr("Are you sure you want to remove all expression evaluators?"), - ICore::settings(), "RemoveAllWatchers"); - if (ret != QDialogButtonBox::Yes) + const QMessageBox::StandardButton ret = CheckableMessageBox::question( + ICore::dialogParent(), + Tr::tr("Remove All Expression Evaluators"), + Tr::tr("Are you sure you want to remove all expression evaluators?"), + ICore::settings(), + "RemoveAllWatchers"); + if (ret != QMessageBox::Yes) return; m_watchRoot->removeChildren(); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 53268c97423..bda248be63c 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -1293,14 +1293,16 @@ QStringList GitClient::setupCheckoutArguments(const FilePath &workingDirectory, if (localBranches.contains(ref)) return arguments; - if (Utils::CheckableMessageBox::doNotAskAgainQuestion( - ICore::dialogParent() /*parent*/, - Tr::tr("Create Local Branch") /*title*/, - Tr::tr("Would you like to create a local branch?") /*message*/, - ICore::settings(), "Git.CreateLocalBranchOnCheckout" /*setting*/, - QDialogButtonBox::Yes | QDialogButtonBox::No /*buttons*/, - QDialogButtonBox::No /*default button*/, - QDialogButtonBox::No /*button to save*/) != QDialogButtonBox::Yes) { + if (Utils::CheckableMessageBox::question( + ICore::dialogParent() /*parent*/, + Tr::tr("Create Local Branch") /*title*/, + Tr::tr("Would you like to create a local branch?") /*message*/, + ICore::settings(), + "Git.CreateLocalBranchOnCheckout" /*setting*/, + QMessageBox::Yes | QMessageBox::No /*buttons*/, + QMessageBox::No /*default button*/, + QMessageBox::No /*button to save*/) + != QMessageBox::Yes) { return arguments; } diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 05693d68320..82aeeba4ff8 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1051,26 +1051,23 @@ bool RunControl::showPromptToStopDialog(const QString &title, { // Show a question message box where user can uncheck this // question for this class. - Utils::CheckableMessageBox messageBox(Core::ICore::dialogParent()); - messageBox.setWindowTitle(title); - messageBox.setText(text); - messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::Cancel); + QMap buttonTexts; if (!stopButtonText.isEmpty()) - messageBox.button(QDialogButtonBox::Yes)->setText(stopButtonText); + buttonTexts[QMessageBox::Yes] = stopButtonText; if (!cancelButtonText.isEmpty()) - messageBox.button(QDialogButtonBox::Cancel)->setText(cancelButtonText); - messageBox.setDefaultButton(QDialogButtonBox::Yes); - if (prompt) { - messageBox.setCheckBoxText(Utils::CheckableMessageBox::msgDoNotAskAgain()); - messageBox.setChecked(false); - } else { - messageBox.setCheckBoxVisible(false); - } - messageBox.exec(); - const bool close = messageBox.clickedStandardButton() == QDialogButtonBox::Yes; - if (close && prompt && messageBox.isChecked()) - *prompt = false; - return close; + buttonTexts[QMessageBox::Cancel] = cancelButtonText; + + std::optional decider + = prompt ? std::nullopt : make_optional(CheckableMessageBox::make_decider(*prompt)); + + auto selected = CheckableMessageBox::question(Core::ICore::dialogParent(), + title, + text, + decider, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Yes); + + return selected == QMessageBox::Yes; } void RunControl::provideAskPassEntry(Environment &env) diff --git a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp index 5d1900c4947..f71f04fd398 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp @@ -663,14 +663,16 @@ AlignDistribute::Dimension AlignDistribute::getDimension(Target target) const bool AlignDistribute::executePixelPerfectDialog() const { - QDialogButtonBox::StandardButton pressed = Utils::CheckableMessageBox::doNotAskAgainQuestion( + auto decider = Utils::CheckableMessageBox::make_decider(Core::ICore::settings(), + "WarnAboutPixelPerfectDistribution"); + + QMessageBox::StandardButton pressed = Utils::CheckableMessageBox::question( Core::ICore::dialogParent(), tr("Cannot Distribute Perfectly"), tr("These objects cannot be distributed to equal pixel values. " "Do you want to distribute to the nearest possible values?"), - Core::ICore::settings(), - "WarnAboutPixelPerfectDistribution"); - return (pressed == QDialogButtonBox::Yes) ? true : false; + decider); + return (pressed == QMessageBox::Yes) ? true : false; } } // namespace QmlDesigner diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index 829b2312cc7..1b99c338f16 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -296,14 +296,15 @@ void SquishNavigationWidget::onRemoveAllSharedFolderTriggered() void SquishNavigationWidget::onRecordTestCase(const QString &suiteName, const QString &testCase) { - QDialogButtonBox::StandardButton pressed = Utils::CheckableMessageBox::doNotAskAgainQuestion( - Core::ICore::dialogParent(), - Tr::tr("Record Test Case"), - Tr::tr("Do you want to record over the test case \"%1\"? The existing content will " - "be overwritten by the recorded script.").arg(testCase), - Core::ICore::settings(), - "RecordWithoutApproval"); - if (pressed != QDialogButtonBox::Yes) + QMessageBox::StandardButton pressed = Utils::CheckableMessageBox::question( + Core::ICore::dialogParent(), + Tr::tr("Record Test Case"), + Tr::tr("Do you want to record over the test case \"%1\"? The existing content will " + "be overwritten by the recorded script.") + .arg(testCase), + Core::ICore::settings(), + "RecordWithoutApproval"); + if (pressed != QMessageBox::Yes) return; SquishFileHandler::instance()->recordTestCase(suiteName, testCase); diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 529bac9d6b3..8b842ec0800 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -801,19 +801,19 @@ void MemcheckToolPrivate::heobAction() const QString dwarfstack = QString("dwarfstack%1.dll").arg(abi.wordWidth()); const QString dwarfstackPath = dialog.path() + '/' + dwarfstack; if (!QFile::exists(dwarfstackPath) - && CheckableMessageBox::doNotShowAgainInformation( + && CheckableMessageBox::information( Core::ICore::dialogParent(), Tr::tr("Heob"), Tr::tr("Heob used with MinGW projects needs the %1 DLLs for proper " - "stacktrace resolution.") + "stacktrace resolution.") .arg( "
Dwarfstack"), ICore::settings(), "HeobDwarfstackInfo", - QDialogButtonBox::Ok | QDialogButtonBox::Cancel, - QDialogButtonBox::Ok) - != QDialogButtonBox::Ok) + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok) + != QMessageBox::Ok) return; } diff --git a/src/plugins/welcome/introductionwidget.cpp b/src/plugins/welcome/introductionwidget.cpp index a18287b0f60..4ee3e7868b3 100644 --- a/src/plugins/welcome/introductionwidget.cpp +++ b/src/plugins/welcome/introductionwidget.cpp @@ -28,8 +28,9 @@ namespace Internal { void IntroductionWidget::askUserAboutIntroduction(QWidget *parent, QSettings *settings) { + auto decider = CheckableMessageBox::make_decider(settings, kTakeTourSetting); // CheckableMessageBox for compatibility with Qt Creator < 4.11 - if (!CheckableMessageBox::shouldAskAgain(settings, kTakeTourSetting) + if (!CheckableMessageBox::shouldAskAgain(decider) || !Core::ICore::infoBar()->canInfoBeAdded(kTakeTourSetting)) return; From 796cfceb3a27337e2f613624a8c223761fdd44b8 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 17 May 2023 09:04:13 +0200 Subject: [PATCH 1101/1447] Tests: Fix Qbs build Amends f84199f8b70bb03b66a0dbac3ff4dcdb56094d20. Change-Id: I6a233aca13f9908451748c20c1804fa2851043aa Reviewed-by: hjk --- tests/auto/solutions/tasking/tasking.qbs | 1 + tests/auto/utils/async/async.qbs | 1 + tests/manual/tasktree/tasktree.qbs | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/auto/solutions/tasking/tasking.qbs b/tests/auto/solutions/tasking/tasking.qbs index 173c1fc5752..aa5ab766ef9 100644 --- a/tests/auto/solutions/tasking/tasking.qbs +++ b/tests/auto/solutions/tasking/tasking.qbs @@ -1,6 +1,7 @@ QtcAutotest { name: "Tasking autotest" + Depends { name: "Tasking" } Depends { name: "Utils" } files: "tst_tasking.cpp" diff --git a/tests/auto/utils/async/async.qbs b/tests/auto/utils/async/async.qbs index 696b0959a5b..31fd6268dec 100644 --- a/tests/auto/utils/async/async.qbs +++ b/tests/auto/utils/async/async.qbs @@ -2,6 +2,7 @@ import qbs QtcAutotest { name: "Async autotest" + Depends { name: "Tasking" } Depends { name: "Utils" } files: "tst_async.cpp" } diff --git a/tests/manual/tasktree/tasktree.qbs b/tests/manual/tasktree/tasktree.qbs index dad8e14763c..6a548d4d831 100644 --- a/tests/manual/tasktree/tasktree.qbs +++ b/tests/manual/tasktree/tasktree.qbs @@ -4,6 +4,7 @@ QtcManualtest { name: "Manual TaskTree test" type: ["application"] + Depends { name: "Tasking" } Depends { name: "Utils" } files: [ From db2b09f4ebc20d8a8f624cdc32de130e8030b780 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 16 May 2023 11:19:31 +0200 Subject: [PATCH 1102/1447] Valgrind: Do not start valgrind if it does not exist ...and print a warning with some user hint inside the application output instead. Drive-by fix: silence a soft assert in case of a failed start of callgrind. Fixes: QTCREATORBUG-28988 Change-Id: I4fd0253e1f18489031e2f6cfa276c4df5ea4483a Reviewed-by: hjk --- src/plugins/valgrind/callgrindengine.cpp | 3 ++- src/plugins/valgrind/memchecktool.cpp | 1 - src/plugins/valgrind/valgrindengine.cpp | 23 ++++++++++------------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 99d948c2482..e8ddb08fac7 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -258,7 +258,8 @@ void CallgrindToolRunner::triggerParse() } const auto afterCopy = [this](expected_str res) { - QTC_ASSERT_EXPECTED(res, return); + if (!res) // failed to run callgrind + return; showStatusMessage(Tr::tr("Parsing Profile Data...")); m_parser.parse(m_hostOutputFile); }; diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 8b842ec0800..552d5a28233 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -7,7 +7,6 @@ #include "valgrindengine.h" #include "valgrindrunner.h" #include "valgrindsettings.h" -#include "valgrindsettings.h" #include "valgrindtr.h" #include "xmlprotocol/error.h" diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 977ca797758..462d1b1a735 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -22,8 +22,6 @@ #include -#define VALGRIND_DEBUG_OUTPUT 0 - using namespace Debugger; using namespace Core; using namespace Utils; @@ -55,6 +53,16 @@ ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) void ValgrindToolRunner::start() { + FilePath valgrindExecutable = m_settings.valgrindExecutable.filePath(); + if (IDevice::ConstPtr dev = DeviceKitAspect::device(runControl()->kit())) + valgrindExecutable = dev->filePath(valgrindExecutable.path()); + if (!valgrindExecutable.isExecutableFile()) { + reportFailure(Tr::tr("Valgrind executable \"%1\" not found or not executable.\n" + "Check settings or ensure valgrind is installed and available in PATH.") + .arg(valgrindExecutable.toUserOutput())); + return; + } + FutureProgress *fp = ProgressManager::addTimedTask(m_progress, progressTitle(), "valgrind", 100); connect(fp, &FutureProgress::canceled, this, &ValgrindToolRunner::handleProgressCanceled); @@ -62,17 +70,6 @@ void ValgrindToolRunner::start() this, &ValgrindToolRunner::handleProgressFinished); m_progress.reportStarted(); -#if VALGRIND_DEBUG_OUTPUT - emit outputReceived(Tr::tr("Valgrind options: %1").arg(toolArguments().join(' ')), LogMessageFormat); - emit outputReceived(Tr::tr("Working directory: %1").arg(runnable().workingDirectory), LogMessageFormat); - emit outputReceived(Tr::tr("Command line arguments: %1").arg(runnable().debuggeeArgs), LogMessageFormat); -#endif - - - FilePath valgrindExecutable = m_settings.valgrindExecutable.filePath(); - if (IDevice::ConstPtr dev = DeviceKitAspect::device(runControl()->kit())) - valgrindExecutable = dev->filePath(valgrindExecutable.path()); - CommandLine valgrind{valgrindExecutable}; valgrind.addArgs(m_settings.valgrindArguments.value(), CommandLine::Raw); valgrind.addArgs(genericToolArguments()); From 8f5703a7b9c5b4a272b44c85aa428dd3992bb13d Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 14 Apr 2023 10:00:08 +0200 Subject: [PATCH 1103/1447] Tests: Add a test to feed shells via stdin Change-Id: I7e19537d0a3015aeb329849758cc92da17a67606 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- tests/auto/utils/process/tst_process.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/auto/utils/process/tst_process.cpp b/tests/auto/utils/process/tst_process.cpp index fd11c5d4632..589adbb6fa8 100644 --- a/tests/auto/utils/process/tst_process.cpp +++ b/tests/auto/utils/process/tst_process.cpp @@ -160,6 +160,7 @@ private slots: void quitBlockingProcess_data(); void quitBlockingProcess(); void tarPipe(); + void stdinToShell(); void cleanupTestCase(); @@ -1519,6 +1520,21 @@ void tst_Process::tarPipe() QCOMPARE(sourceFile.fileSize(), destinationFile.fileSize()); } +void tst_Process::stdinToShell() +{ + // proc.setCommand({"cmd.exe", {}}); - Piping into cmd.exe does not appear to work. + if (HostOsInfo::isWindowsHost()) + QSKIP("Skipping env test on Windows"); + + Process proc; + proc.setCommand({"sh", {}}); + proc.setWriteData("echo hallo"); + proc.runBlocking(); + + QString result = proc.readAllStandardOutput().trimmed(); + QCOMPARE(result, "hallo"); +} + QTEST_GUILESS_MAIN(tst_Process) #include "tst_process.moc" From c59f3102a1a772da33022ca490a32d390ae827a3 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 17 May 2023 10:30:20 +0200 Subject: [PATCH 1104/1447] CrashHandler: Fix missing update The change to CheckableMessageBox was missed. Change-Id: I8b7fe1230bcf483f9e5371b878d862aff422d925 Reviewed-by: hjk --- .../crashhandlerdialog.cpp | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp index acbc3fa28f7..61d1fd4230d 100644 --- a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp @@ -205,12 +205,10 @@ CrashHandlerDialog::~CrashHandlerDialog() bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished() { // Check settings. - QSettings settings(QSettings::IniFormat, QSettings::UserScope, + QSettings settings(QSettings::IniFormat, + QSettings::UserScope, QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR), QLatin1String(SettingsApplication)); - if (settings.value(QLatin1String(SettingsKeySkipWarningAbortingBacktrace), false).toBool()) - return true; - // Ask user. const QString title = tr("Run Debugger And Abort Collecting Backtrace?"); const QString message = tr( @@ -219,15 +217,18 @@ bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished() "

You have requested to run the debugger while collecting the backtrace was not " "finished.

" ""); - const QString checkBoxText = tr("Do not &ask again."); - bool checkBoxSetting = false; - const QDialogButtonBox::StandardButton button = Utils::CheckableMessageBox::question(this, - title, message, checkBoxText, &checkBoxSetting, - QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::No); - if (checkBoxSetting) - settings.setValue(QLatin1String(SettingsKeySkipWarningAbortingBacktrace), checkBoxSetting); - return button == QDialogButtonBox::Yes; + const QMessageBox::StandardButton button + = Utils::CheckableMessageBox::question(this, + title, + message, + &settings, + QLatin1String( + SettingsKeySkipWarningAbortingBacktrace), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No); + + return button == QMessageBox::Yes; } void CrashHandlerDialog::setToFinalState() From c3334cd1afd6af6c0705c5079766d737b6b224bc Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 12 May 2023 15:25:28 +0200 Subject: [PATCH 1105/1447] Session: Move some settings saving to session itself Change-Id: I306bb86f1fda03f9b34efd7101d405ed64076711 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- src/plugins/projectexplorer/projectexplorer.cpp | 6 ------ .../projectexplorer/projectexplorerconstants.h | 2 -- src/plugins/projectexplorer/session.cpp | 16 ++++++++++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index df77b48f8b8..9b9a0252552 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2256,12 +2256,6 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() } QtcSettings *s = ICore::settings(); - if (SessionManager::isDefaultVirgin()) { - s->remove(Constants::STARTUPSESSION_KEY); - } else { - s->setValue(Constants::STARTUPSESSION_KEY, SessionManager::activeSession()); - s->setValue(Constants::LASTSESSION_KEY, SessionManager::activeSession()); - } s->remove(QLatin1String("ProjectExplorer/RecentProjects/Files")); QStringList fileNames; diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 005981e697d..75054120a83 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -206,8 +206,6 @@ const char FILEOVERLAY_UNKNOWN[]=":/projectexplorer/images/fileoverlay_unknown.p // Settings const char ADD_FILES_DIALOG_FILTER_HISTORY_KEY[] = "ProjectExplorer.AddFilesFilterKey"; const char PROJECT_ROOT_PATH_KEY[] = "ProjectExplorer.Project.RootPath"; -const char STARTUPSESSION_KEY[] = "ProjectExplorer/SessionToRestore"; -const char LASTSESSION_KEY[] = "ProjectExplorer/StartupSession"; const char SETTINGS_MENU_HIDE_BUILD[] = "Menu/HideBuild"; const char SETTINGS_MENU_HIDE_DEBUG[] = "Menu/HideDebug"; const char SETTINGS_MENU_HIDE_ANALYZE[] = "Menu/HideAnalyze"; diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 427cb8e4ca0..8de2a10ba2c 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -5,7 +5,6 @@ #include "session_p.h" -#include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "projectmanager.h" @@ -37,6 +36,8 @@ namespace ProjectExplorer { const char DEFAULT_SESSION[] = "default"; const char LAST_ACTIVE_TIMES_KEY[] = "LastActiveTimes"; +const char STARTUPSESSION_KEY[] = "ProjectExplorer/SessionToRestore"; +const char LASTSESSION_KEY[] = "ProjectExplorer/StartupSession"; /*! \class ProjectExplorer::SessionManager @@ -61,10 +62,17 @@ SessionManager::SessionManager() this, &SessionManager::saveActiveMode); connect(ICore::instance(), &ICore::saveSettingsRequested, this, [] { + QtcSettings *s = ICore::settings(); QVariantMap times; for (auto it = sb_d->m_lastActiveTimes.cbegin(); it != sb_d->m_lastActiveTimes.cend(); ++it) times.insert(it.key(), it.value()); - ICore::settings()->setValue(LAST_ACTIVE_TIMES_KEY, times); + s->setValue(LAST_ACTIVE_TIMES_KEY, times); + if (SessionManager::isDefaultVirgin()) { + s->remove(STARTUPSESSION_KEY); + } else { + s->setValue(STARTUPSESSION_KEY, SessionManager::activeSession()); + s->setValue(LASTSESSION_KEY, SessionManager::activeSession()); + } }); connect(EditorManager::instance(), &EditorManager::editorOpened, @@ -266,7 +274,7 @@ void SessionManagerPrivate::restoreEditors(const PersistentSettingsReader &reade */ QString SessionManager::lastSession() { - return ICore::settings()->value(Constants::LASTSESSION_KEY).toString(); + return ICore::settings()->value(LASTSESSION_KEY).toString(); } /*! @@ -274,7 +282,7 @@ QString SessionManager::lastSession() */ QString SessionManager::startupSession() { - return ICore::settings()->value(Constants::STARTUPSESSION_KEY).toString(); + return ICore::settings()->value(STARTUPSESSION_KEY).toString(); } void SessionManager::markSessionFileDirty() From 667d5a8f91e7b501a7eb210b3e16f2c66fd18c76 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 12 May 2023 15:28:09 +0200 Subject: [PATCH 1106/1447] Remove include of projectmanager.h from session.h Users need to include that themselves if needed. Change-Id: I90f8fe2784ee395cc6a4fc43e62eedebf9f05b76 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/session.h | 3 --- src/plugins/projectexplorer/session_p.h | 3 +-- src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index d42868f129b..37f60626719 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -5,9 +5,6 @@ #include "projectexplorer_export.h" -// FIXME: Remove once dowstream is adjusted. -#include "projectmanager.h" - #include #include diff --git a/src/plugins/projectexplorer/session_p.h b/src/plugins/projectexplorer/session_p.h index 078fad5c364..a44833feaee 100644 --- a/src/plugins/projectexplorer/session_p.h +++ b/src/plugins/projectexplorer/session_p.h @@ -1,11 +1,10 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "session.h" +#include #include -using namespace Core; using namespace Utils; namespace ProjectExplorer { diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index d20c765fd68..ce7d783a4ed 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include From cbeac777a61322fbc2d365c7b83ead8aaaaf4bbf Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 15 May 2023 10:31:33 +0200 Subject: [PATCH 1107/1447] Move restoring startup session to SessionManager It needs to be done after the delayed restoring of kits, so this now implicitly depends on ICore::coreOpened coming after restoring kits has triggered on the event loop before, which is ugly, but works (and is at least guarded by a warning). Change-Id: Ie8676b1c7f4d099fb83f0f2a0f2e5677c4a0b999 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- .../projectexplorer/projectexplorer.cpp | 129 +++--------------- .../projectexplorer/projectexplorersettings.h | 2 - src/plugins/projectexplorer/session.cpp | 122 +++++++++++++++++ src/plugins/projectexplorer/session.h | 1 + src/plugins/projectexplorer/session_p.h | 10 ++ 5 files changed, 154 insertions(+), 110 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 9b9a0252552..6334dfee582 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -35,8 +35,8 @@ #include "dependenciespanel.h" #include "devicesupport/desktopdevice.h" #include "devicesupport/desktopdevicefactory.h" -#include "devicesupport/devicemanager.h" #include "devicesupport/devicecheckbuildstep.h" +#include "devicesupport/devicemanager.h" #include "devicesupport/devicesettingspage.h" #include "devicesupport/sshsettings.h" #include "devicesupport/sshsettingspage.h" @@ -69,6 +69,7 @@ #include "sanitizerparser.h" #include "selectablefilesmodel.h" #include "session.h" +#include "session_p.h" #include "sessiondialog.h" #include "showineditortaskhandler.h" #include "simpleprojectwizard.h" @@ -257,7 +258,6 @@ const char BUILD_BEFORE_DEPLOY_SETTINGS_KEY[] = "ProjectExplorer/Settings/BuildB const char DEPLOY_BEFORE_RUN_SETTINGS_KEY[] = "ProjectExplorer/Settings/DeployBeforeRun"; const char SAVE_BEFORE_BUILD_SETTINGS_KEY[] = "ProjectExplorer/Settings/SaveBeforeBuild"; const char USE_JOM_SETTINGS_KEY[] = "ProjectExplorer/Settings/UseJom"; -const char AUTO_RESTORE_SESSION_SETTINGS_KEY[] = "ProjectExplorer/Settings/AutoRestoreLastSession"; const char ADD_LIBRARY_PATHS_TO_RUN_ENV_SETTINGS_KEY[] = "ProjectExplorer/Settings/AddLibraryPathsToRunEnv"; const char PROMPT_TO_STOP_RUN_CONTROL_SETTINGS_KEY[] = @@ -457,8 +457,6 @@ public: void updateSessionMenu(); void setSession(QAction *action); - void determineSessionToRestoreAtStartup(); - void restoreSession(); void runProjectContextMenu(RunConfiguration *rc); void savePersistentSettings(); @@ -584,7 +582,6 @@ public: QAction *m_runSubProject; ProjectWindow *m_proWindow = nullptr; - QString m_sessionToRestoreAtStartup; QStringList m_profileMimeTypes; int m_activeRunControlCount = 0; @@ -607,7 +604,6 @@ public: Id m_runMode = Constants::NO_RUN_MODE; ToolChainManager *m_toolChainManager = nullptr; - QStringList m_arguments; #ifdef WITH_JOURNALD JournaldWatcher m_journalWatcher; @@ -1675,10 +1671,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er .toBool(); dd->m_projectExplorerSettings.useJom = s->value(Constants::USE_JOM_SETTINGS_KEY, defaultSettings.useJom).toBool(); - dd->m_projectExplorerSettings.autorestoreLastSession - = s->value(Constants::AUTO_RESTORE_SESSION_SETTINGS_KEY, - defaultSettings.autorestoreLastSession) - .toBool(); dd->m_projectExplorerSettings.addLibraryPathsToRunEnv = s->value(Constants::ADD_LIBRARY_PATHS_TO_RUN_ENV_SETTINGS_KEY, defaultSettings.addLibraryPathsToRunEnv) @@ -1720,6 +1712,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er .toBool(); dd->m_buildPropertiesSettings.readSettings(s); + sb_d->restoreSettings(); const int customParserCount = s->value(Constants::CUSTOM_PARSER_COUNT_KEY).toInt(); for (int i = 0; i < customParserCount; ++i) { @@ -1913,6 +1906,18 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd->updateContextMenuActions(ProjectTree::currentNode()); }); + connect(ModeManager::instance(), + &ModeManager::currentModeChanged, + dd, + &ProjectExplorerPluginPrivate::currentModeChanged); + connect(&dd->m_welcomePage, + &ProjectWelcomePage::requestProject, + m_instance, + &ProjectExplorerPlugin::openProjectWelcomePage); + connect(SessionManager::instance(), + &SessionManager::startupSessionRestored, + m_instance, + &ProjectExplorerPlugin::finishedInitialization); dd->updateWelcomePage(); MacroExpander *expander = Utils::globalMacroExpander(); @@ -2155,11 +2160,12 @@ void ProjectExplorerPlugin::extensionsInitialized() void ProjectExplorerPlugin::restoreKits() { - dd->determineSessionToRestoreAtStartup(); ExtraAbi::load(); // Load this before Toolchains! ToolChainManager::restoreToolChains(); KitManager::restoreKits(); - QTimer::singleShot(0, dd, &ProjectExplorerPluginPrivate::restoreSession); // delay a bit... + // restoring startup session is supposed to be done as a result of ICore::coreOpened, + // and that is supposed to happen after restoring kits: + QTC_CHECK(!sb_d->isStartupSessionRestored()); } void ProjectExplorerPluginPrivate::updateRunWithoutDeployMenu() @@ -2208,9 +2214,9 @@ void ProjectExplorerPluginPrivate::showSessionManager() { ProjectManager::save(); SessionDialog sessionDialog(ICore::dialogParent()); - sessionDialog.setAutoLoadSession(dd->m_projectExplorerSettings.autorestoreLastSession); + sessionDialog.setAutoLoadSession(sb_d->isAutoRestoreLastSession()); sessionDialog.exec(); - dd->m_projectExplorerSettings.autorestoreLastSession = sessionDialog.autoLoadSession(); + sb_d->setAutoRestoreLastSession(sessionDialog.autoLoadSession()); updateActions(); @@ -2284,9 +2290,6 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() s->setValueWithDefault(Constants::USE_JOM_SETTINGS_KEY, dd->m_projectExplorerSettings.useJom, defaultSettings.useJom); - s->setValueWithDefault(Constants::AUTO_RESTORE_SESSION_SETTINGS_KEY, - dd->m_projectExplorerSettings.autorestoreLastSession, - defaultSettings.autorestoreLastSession); s->setValueWithDefault(Constants::ADD_LIBRARY_PATHS_TO_RUN_ENV_SETTINGS_KEY, dd->m_projectExplorerSettings.addLibraryPathsToRunEnv, defaultSettings.addLibraryPathsToRunEnv); @@ -2318,6 +2321,7 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() int(defaultSettings.stopBeforeBuild)); dd->m_buildPropertiesSettings.writeSettings(s); + sb_d->saveSettings(); s->setValueWithDefault(Constants::CUSTOM_PARSER_COUNT_KEY, int(dd->m_customParsers.count()), 0); for (int i = 0; i < dd->m_customParsers.count(); ++i) { @@ -2468,33 +2472,6 @@ void ProjectExplorerPluginPrivate::currentModeChanged(Id mode, Id oldMode) updateWelcomePage(); } -void ProjectExplorerPluginPrivate::determineSessionToRestoreAtStartup() -{ - // Process command line arguments first: - const bool lastSessionArg = - ExtensionSystem::PluginManager::specForPlugin(m_instance)->arguments().contains("-lastsession"); - m_sessionToRestoreAtStartup = lastSessionArg ? SessionManager::startupSession() : QString(); - const QStringList arguments = ExtensionSystem::PluginManager::arguments(); - if (!lastSessionArg) { - QStringList sessions = SessionManager::sessions(); - // We have command line arguments, try to find a session in them - // Default to no session loading - for (const QString &arg : arguments) { - if (sessions.contains(arg)) { - // Session argument - m_sessionToRestoreAtStartup = arg; - break; - } - } - } - // Handle settings only after command line arguments: - if (m_sessionToRestoreAtStartup.isEmpty() && m_projectExplorerSettings.autorestoreLastSession) - m_sessionToRestoreAtStartup = SessionManager::startupSession(); - - if (!m_sessionToRestoreAtStartup.isEmpty()) - ModeManager::activateMode(Core::Constants::MODE_EDIT); -} - // Return a list of glob patterns for project files ("*.pro", etc), use first, main pattern only. QStringList ProjectExplorerPlugin::projectFileGlobs() { @@ -2520,70 +2497,6 @@ MiniProjectTargetSelector *ProjectExplorerPlugin::targetSelector() return dd->m_targetSelector; } -/*! - This function is connected to the ICore::coreOpened signal. If - there was no session explicitly loaded, it creates an empty new - default session and puts the list of recent projects and sessions - onto the welcome page. -*/ -void ProjectExplorerPluginPrivate::restoreSession() -{ - // We have command line arguments, try to find a session in them - QStringList arguments = ExtensionSystem::PluginManager::arguments(); - if (!dd->m_sessionToRestoreAtStartup.isEmpty() && !arguments.isEmpty()) - arguments.removeOne(dd->m_sessionToRestoreAtStartup); - - // Massage the argument list. - // Be smart about directories: If there is a session of that name, load it. - // Other than that, look for project files in it. The idea is to achieve - // 'Do what I mean' functionality when starting Creator in a directory with - // the single command line argument '.' and avoid editor warnings about not - // being able to open directories. - // In addition, convert "filename" "+45" or "filename" ":23" into - // "filename+45" and "filename:23". - if (!arguments.isEmpty()) { - const QStringList sessions = SessionManager::sessions(); - for (int a = 0; a < arguments.size(); ) { - const QString &arg = arguments.at(a); - const QFileInfo fi(arg); - if (fi.isDir()) { - const QDir dir(fi.absoluteFilePath()); - // Does the directory name match a session? - if (dd->m_sessionToRestoreAtStartup.isEmpty() - && sessions.contains(dir.dirName())) { - dd->m_sessionToRestoreAtStartup = dir.dirName(); - arguments.removeAt(a); - continue; - } - } // Done directories. - // Converts "filename" "+45" or "filename" ":23" into "filename+45" and "filename:23" - if (a && (arg.startsWith(QLatin1Char('+')) || arg.startsWith(QLatin1Char(':')))) { - arguments[a - 1].append(arguments.takeAt(a)); - continue; - } - ++a; - } // for arguments - } // !arguments.isEmpty() - // Restore latest session or what was passed on the command line - - ProjectManager::loadSession(!dd->m_sessionToRestoreAtStartup.isEmpty() - ? dd->m_sessionToRestoreAtStartup : QString(), true); - - // update welcome page - connect(ModeManager::instance(), &ModeManager::currentModeChanged, - dd, &ProjectExplorerPluginPrivate::currentModeChanged); - connect(&dd->m_welcomePage, &ProjectWelcomePage::requestProject, - m_instance, &ProjectExplorerPlugin::openProjectWelcomePage); - dd->m_arguments = arguments; - // delay opening projects from the command line even more - QTimer::singleShot(0, m_instance, [] { - ICore::openFiles(Utils::transform(dd->m_arguments, &FilePath::fromUserInput), - ICore::OpenFilesFlags(ICore::CanContainLineAndColumnNumbers | ICore::SwitchMode)); - emit m_instance->finishedInitialization(); - }); - updateActions(); -} - void ProjectExplorerPluginPrivate::executeRunConfiguration(RunConfiguration *runConfiguration, Id runMode) { const Tasks runConfigIssues = runConfiguration->checkForIssues(); diff --git a/src/plugins/projectexplorer/projectexplorersettings.h b/src/plugins/projectexplorer/projectexplorersettings.h index b4b80124cd8..bda218aef22 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.h +++ b/src/plugins/projectexplorer/projectexplorersettings.h @@ -23,7 +23,6 @@ public: && p1.deployBeforeRun == p2.deployBeforeRun && p1.saveBeforeBuild == p2.saveBeforeBuild && p1.useJom == p2.useJom - && p1.autorestoreLastSession == p2.autorestoreLastSession && p1.prompToStopRunControl == p2.prompToStopRunControl && p1.automaticallyCreateRunConfigurations == p2.automaticallyCreateRunConfigurations && p1.addLibraryPathsToRunEnv == p2.addLibraryPathsToRunEnv @@ -40,7 +39,6 @@ public: bool deployBeforeRun = true; bool saveBeforeBuild = false; bool useJom = true; - bool autorestoreLastSession = false; // This option is set in the Session Manager! bool prompToStopRunControl = false; bool automaticallyCreateRunConfigurations = true; bool addLibraryPathsToRunEnv = true; diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 8de2a10ba2c..f1588147765 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -5,9 +5,13 @@ #include "session_p.h" +#include "projectexplorer.h" #include "projectexplorertr.h" #include "projectmanager.h" +#include +#include + #include #include #include @@ -28,6 +32,7 @@ #include #include #include +#include using namespace Core; using namespace Utils; @@ -38,6 +43,8 @@ const char DEFAULT_SESSION[] = "default"; const char LAST_ACTIVE_TIMES_KEY[] = "LastActiveTimes"; const char STARTUPSESSION_KEY[] = "ProjectExplorer/SessionToRestore"; const char LASTSESSION_KEY[] = "ProjectExplorer/StartupSession"; +const char AUTO_RESTORE_SESSION_SETTINGS_KEY[] = "ProjectExplorer/Settings/AutoRestoreLastSession"; +static bool kIsAutoRestoreLastSessionDefault = false; /*! \class ProjectExplorer::SessionManager @@ -58,6 +65,8 @@ SessionManager::SessionManager() m_instance = this; sb_d = new SessionManagerPrivate; + connect(ICore::instance(), &ICore::coreOpened, this, [] { sb_d->restoreStartupSession(); }); + connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, &SessionManager::saveActiveMode); @@ -251,6 +260,119 @@ bool SessionManager::cloneSession(const QString &original, const QString &clone) return false; } +static QString determineSessionToRestoreAtStartup() +{ + // TODO (session) move argument to core + // Process command line arguments first: + const bool lastSessionArg = ExtensionSystem::PluginManager::specForPlugin( + ProjectExplorerPlugin::instance()) + ->arguments() + .contains("-lastsession"); + if (lastSessionArg && !SessionManager::startupSession().isEmpty()) + return SessionManager::startupSession(); + const QStringList arguments = ExtensionSystem::PluginManager::arguments(); + QStringList sessions = SessionManager::sessions(); + // We have command line arguments, try to find a session in them + // Default to no session loading + for (const QString &arg : arguments) { + if (sessions.contains(arg)) { + // Session argument + return arg; + } + } + // Handle settings only after command line arguments: + if (sb_d->m_isAutoRestoreLastSession) + return SessionManager::startupSession(); + return {}; +} + +void SessionManagerPrivate::restoreStartupSession() +{ + m_isStartupSessionRestored = true; + QString sessionToRestoreAtStartup = determineSessionToRestoreAtStartup(); + if (!sessionToRestoreAtStartup.isEmpty()) + ModeManager::activateMode(Core::Constants::MODE_EDIT); + + // We have command line arguments, try to find a session in them + QStringList arguments = ExtensionSystem::PluginManager::arguments(); + if (!sessionToRestoreAtStartup.isEmpty() && !arguments.isEmpty()) + arguments.removeOne(sessionToRestoreAtStartup); + + // Massage the argument list. + // Be smart about directories: If there is a session of that name, load it. + // Other than that, look for project files in it. The idea is to achieve + // 'Do what I mean' functionality when starting Creator in a directory with + // the single command line argument '.' and avoid editor warnings about not + // being able to open directories. + // In addition, convert "filename" "+45" or "filename" ":23" into + // "filename+45" and "filename:23". + if (!arguments.isEmpty()) { + const QStringList sessions = SessionManager::sessions(); + for (int a = 0; a < arguments.size();) { + const QString &arg = arguments.at(a); + const QFileInfo fi(arg); + if (fi.isDir()) { + const QDir dir(fi.absoluteFilePath()); + // Does the directory name match a session? + if (sessionToRestoreAtStartup.isEmpty() && sessions.contains(dir.dirName())) { + sessionToRestoreAtStartup = dir.dirName(); + arguments.removeAt(a); + continue; + } + } // Done directories. + // Converts "filename" "+45" or "filename" ":23" into "filename+45" and "filename:23" + if (a && (arg.startsWith(QLatin1Char('+')) || arg.startsWith(QLatin1Char(':')))) { + arguments[a - 1].append(arguments.takeAt(a)); + continue; + } + ++a; + } // for arguments + } // !arguments.isEmpty() + + // Restore latest session or what was passed on the command line + ProjectManager::loadSession(!sessionToRestoreAtStartup.isEmpty() ? sessionToRestoreAtStartup + : QString(), + true); + + // delay opening projects from the command line even more + QTimer::singleShot(0, m_instance, [arguments] { + ICore::openFiles(Utils::transform(arguments, &FilePath::fromUserInput), + ICore::OpenFilesFlags(ICore::CanContainLineAndColumnNumbers + | ICore::SwitchMode)); + emit m_instance->startupSessionRestored(); + }); +} + +bool SessionManagerPrivate::isStartupSessionRestored() +{ + return sb_d->m_isStartupSessionRestored; +} + +void SessionManagerPrivate::saveSettings() +{ + ICore::settings()->setValueWithDefault(AUTO_RESTORE_SESSION_SETTINGS_KEY, + sb_d->m_isAutoRestoreLastSession, + kIsAutoRestoreLastSessionDefault); +} + +void SessionManagerPrivate::restoreSettings() +{ + sb_d->m_isAutoRestoreLastSession = ICore::settings() + ->value(AUTO_RESTORE_SESSION_SETTINGS_KEY, + kIsAutoRestoreLastSessionDefault) + .toBool(); +} + +bool SessionManagerPrivate::isAutoRestoreLastSession() +{ + return sb_d->m_isAutoRestoreLastSession; +} + +void SessionManagerPrivate::setAutoRestoreLastSession(bool restore) +{ + sb_d->m_isAutoRestoreLastSession = restore; +} + void SessionManagerPrivate::restoreValues(const PersistentSettingsReader &reader) { const QStringList keys = reader.restoreValue(QLatin1String("valueKeys")).toStringList(); diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 37f60626719..21f571b1f3f 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -54,6 +54,7 @@ public: static void markSessionFileDirty(); signals: + void startupSessionRestored(); void aboutToUnloadSession(QString sessionName); void aboutToLoadSession(QString sessionName); void sessionLoaded(QString sessionName); diff --git a/src/plugins/projectexplorer/session_p.h b/src/plugins/projectexplorer/session_p.h index a44833feaee..471c78c06eb 100644 --- a/src/plugins/projectexplorer/session_p.h +++ b/src/plugins/projectexplorer/session_p.h @@ -12,14 +12,24 @@ namespace ProjectExplorer { class SessionManagerPrivate { public: + void restoreStartupSession(); + void restoreValues(const PersistentSettingsReader &reader); void restoreEditors(const PersistentSettingsReader &reader); void sessionLoadingProgress(); + bool isStartupSessionRestored(); + void saveSettings(); + void restoreSettings(); + bool isAutoRestoreLastSession(); + void setAutoRestoreLastSession(bool restore); + static QString windowTitleAddition(const FilePath &filePath); static QString sessionTitle(const FilePath &filePath); QString m_sessionName = "default"; + bool m_isStartupSessionRestored = false; + bool m_isAutoRestoreLastSession = false; bool m_virginSession = true; bool m_loadingSession = false; From 3fc461e7129d24184e5850f412892a2426c43293 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 16 May 2023 18:17:58 +0200 Subject: [PATCH 1108/1447] CppEditor/QmlJSTools: Remove settings migration from Qt Creator 2.3 This removes settings migration from Cpp Code Style Settings migration from Qt Creator <= 2.3 to 2.3+ Let's assume that most active Qt Creator users launched a Qt Creator 2.4 or later in the last decade if they still work with their decade-old installation. Change-Id: I9c49dd9c1c0bd85e2b8c58a0d4eb6c393abf94a1 Reviewed-by: Reviewed-by: Christian Kandeler Reviewed-by: Orgad Shaneh --- src/plugins/cppeditor/cpptoolssettings.cpp | 48 ------------------- src/plugins/qmljstools/qmljstoolssettings.cpp | 39 --------------- 2 files changed, 87 deletions(-) diff --git a/src/plugins/cppeditor/cpptoolssettings.cpp b/src/plugins/cppeditor/cpptoolssettings.cpp index 3d5b4658b84..0b5536fdd72 100644 --- a/src/plugins/cppeditor/cpptoolssettings.cpp +++ b/src/plugins/cppeditor/cpptoolssettings.cpp @@ -134,54 +134,6 @@ CppToolsSettings::CppToolsSettings() // load global settings (after built-in settings are added to the pool) d->m_globalCodeStyle->fromSettings(QLatin1String(Constants::CPP_SETTINGS_ID), s); - // legacy handling start (Qt Creator Version < 2.4) - const bool legacyTransformed = - s->value(QLatin1String("CppCodeStyleSettings/LegacyTransformed"), false).toBool(); - - if (!legacyTransformed) { - // creator 2.4 didn't mark yet the transformation (first run of creator 2.4) - - // we need to transform the settings only if at least one from - // below settings was already written - otherwise we use - // defaults like it would be the first run of creator 2.4 without stored settings - const QStringList groups = s->childGroups(); - const bool needTransform = groups.contains(QLatin1String("textTabPreferences")) || - groups.contains(QLatin1String("CppTabPreferences")) || - groups.contains(QLatin1String("CppCodeStyleSettings")); - if (needTransform) { - CppCodeStyleSettings legacyCodeStyleSettings; - if (groups.contains(QLatin1String("CppCodeStyleSettings"))) { - Utils::fromSettings(QLatin1String("CppCodeStyleSettings"), - QString(), s, &legacyCodeStyleSettings); - } - - const QString currentFallback = s->value(QLatin1String("CppTabPreferences/CurrentFallback")).toString(); - TabSettings legacyTabSettings; - if (currentFallback == QLatin1String("CppGlobal")) { - // no delegate, global overwritten - Utils::fromSettings(QLatin1String("CppTabPreferences"), - QString(), s, &legacyTabSettings); - } else { - // delegating to global - legacyTabSettings = TextEditorSettings::codeStyle()->currentTabSettings(); - } - - // create custom code style out of old settings - QVariant v; - v.setValue(legacyCodeStyleSettings); - ICodeStylePreferences *oldCreator = pool->createCodeStyle( - "legacy", legacyTabSettings, v, Tr::tr("Old Creator")); - - // change the current delegate and save - d->m_globalCodeStyle->setCurrentDelegate(oldCreator); - d->m_globalCodeStyle->toSettings(QLatin1String(Constants::CPP_SETTINGS_ID), s); - } - // mark old settings as transformed - s->setValue(QLatin1String("CppCodeStyleSettings/LegacyTransformed"), true); - // legacy handling stop - } - - // mimetypes to be handled TextEditorSettings::registerMimeTypeForLanguageId(Constants::C_SOURCE_MIMETYPE, Constants::CPP_SETTINGS_ID); TextEditorSettings::registerMimeTypeForLanguageId(Constants::C_HEADER_MIMETYPE, Constants::CPP_SETTINGS_ID); diff --git a/src/plugins/qmljstools/qmljstoolssettings.cpp b/src/plugins/qmljstools/qmljstoolssettings.cpp index 093fb676c25..caeb6dfa26f 100644 --- a/src/plugins/qmljstools/qmljstoolssettings.cpp +++ b/src/plugins/qmljstools/qmljstoolssettings.cpp @@ -71,45 +71,6 @@ QmlJSToolsSettings::QmlJSToolsSettings() QSettings *s = Core::ICore::settings(); m_globalCodeStyle->fromSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); - // legacy handling start (Qt Creator Version < 2.4) - const bool legacyTransformed = - s->value(QLatin1String("QmlJSTabPreferences/LegacyTransformed"), false).toBool(); - - if (!legacyTransformed) { - // creator 2.4 didn't mark yet the transformation (first run of creator 2.4) - - // we need to transform the settings only if at least one from - // below settings was already written - otherwise we use - // defaults like it would be the first run of creator 2.4 without stored settings - const QStringList groups = s->childGroups(); - const bool needTransform = groups.contains(QLatin1String("textTabPreferences")) || - groups.contains(QLatin1String("QmlJSTabPreferences")); - - if (needTransform) { - const QString currentFallback = s->value(QLatin1String("QmlJSTabPreferences/CurrentFallback")).toString(); - TabSettings legacyTabSettings; - if (currentFallback == QLatin1String("QmlJSGlobal")) { - // no delegate, global overwritten - Utils::fromSettings(QLatin1String("QmlJSTabPreferences"), - QString(), s, &legacyTabSettings); - } else { - // delegating to global - legacyTabSettings = TextEditorSettings::codeStyle()->currentTabSettings(); - } - - // create custom code style out of old settings - ICodeStylePreferences *oldCreator = pool->createCodeStyle( - "legacy", legacyTabSettings, QVariant(), Tr::tr("Old Creator")); - - // change the current delegate and save - m_globalCodeStyle->setCurrentDelegate(oldCreator); - m_globalCodeStyle->toSettings(QLatin1String(QmlJSTools::Constants::QML_JS_SETTINGS_ID), s); - } - // mark old settings as transformed - s->setValue(QLatin1String("QmlJSTabPreferences/LegacyTransformed"), true); - // legacy handling stop - } - // mimetypes to be handled TextEditorSettings::registerMimeTypeForLanguageId(Constants::QML_MIMETYPE, Constants::QML_JS_SETTINGS_ID); TextEditorSettings::registerMimeTypeForLanguageId(Constants::QMLUI_MIMETYPE, Constants::QML_JS_SETTINGS_ID); From a468bc2f029e50c0516eb712d09562c80ee1bdb1 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 17 May 2023 11:31:49 +0200 Subject: [PATCH 1109/1447] Fix Qbs build Amends f84199f8b70bb03b66a0dbac3ff4dcdb56094d20 and reverts 796cfceb3a27337e2f613624a8c223761fdd44b8. Change-Id: I7eb686c012bd99cddf36aa16219e3f33de2b15b2 Reviewed-by: Christian Kandeler Reviewed-by: Eike Ziller --- src/libs/utils/utils.qbs | 1 + tests/auto/solutions/tasking/tasking.qbs | 1 - tests/auto/utils/async/async.qbs | 1 - tests/manual/tasktree/tasktree.qbs | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d1c8d0e95e4..18dcf1675cb 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -471,6 +471,7 @@ Project { Export { Depends { name: "Qt"; submodules: ["concurrent", "widgets" ] } + Depends { name: "Tasking" } cpp.includePaths: base.concat("mimetypes2") } } diff --git a/tests/auto/solutions/tasking/tasking.qbs b/tests/auto/solutions/tasking/tasking.qbs index aa5ab766ef9..173c1fc5752 100644 --- a/tests/auto/solutions/tasking/tasking.qbs +++ b/tests/auto/solutions/tasking/tasking.qbs @@ -1,7 +1,6 @@ QtcAutotest { name: "Tasking autotest" - Depends { name: "Tasking" } Depends { name: "Utils" } files: "tst_tasking.cpp" diff --git a/tests/auto/utils/async/async.qbs b/tests/auto/utils/async/async.qbs index 31fd6268dec..696b0959a5b 100644 --- a/tests/auto/utils/async/async.qbs +++ b/tests/auto/utils/async/async.qbs @@ -2,7 +2,6 @@ import qbs QtcAutotest { name: "Async autotest" - Depends { name: "Tasking" } Depends { name: "Utils" } files: "tst_async.cpp" } diff --git a/tests/manual/tasktree/tasktree.qbs b/tests/manual/tasktree/tasktree.qbs index 6a548d4d831..dad8e14763c 100644 --- a/tests/manual/tasktree/tasktree.qbs +++ b/tests/manual/tasktree/tasktree.qbs @@ -4,7 +4,6 @@ QtcManualtest { name: "Manual TaskTree test" type: ["application"] - Depends { name: "Tasking" } Depends { name: "Utils" } files: [ From c7bf77ae72d27f6bada34eea184ca283a4a113f9 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 17 May 2023 12:04:09 +0200 Subject: [PATCH 1110/1447] CheckableMessageBox: Make semantics of bool value clearer Change-Id: I06a43ab986e6f028cf07ea5e9700c831a591cbf2 Reviewed-by: Marcus Tillmanns --- src/libs/utils/checkablemessagebox.cpp | 6 +++--- src/libs/utils/checkablemessagebox.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index 92b111ed7c7..29951fd9c44 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -70,7 +70,7 @@ static QMessageBox::StandardButton exec( using T = std::decay_t; msgBox.checkBox()->setText(decider.text); if constexpr (std::is_same_v) { - msgBox.checkBox()->setChecked(decider.value); + msgBox.checkBox()->setChecked(decider.doNotAskAgain); } else if constexpr (std::is_same_v) { msgBox.checkBox()->setChecked( decider.settings->value(decider.settingsSubKey, false).toBool()); @@ -142,7 +142,7 @@ void CheckableMessageBox::doNotAskAgain(Decider &decider) [](auto &&decider) { using T = std::decay_t; if constexpr (std::is_same_v) { - decider.value = true; + decider.doNotAskAgain = true; } else if constexpr (std::is_same_v) { decider.settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); decider.settings->setValue(decider.settingsSubKey, true); @@ -160,7 +160,7 @@ bool CheckableMessageBox::shouldAskAgain(const Decider &decider) [](auto &&decider) { using T = std::decay_t; if constexpr (std::is_same_v) { - return !decider.value; + return !decider.doNotAskAgain; } else if constexpr (std::is_same_v) { decider.settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); bool shouldNotAsk = decider.settings->value(decider.settingsSubKey, false).toBool(); diff --git a/src/libs/utils/checkablemessagebox.h b/src/libs/utils/checkablemessagebox.h index e6988fc8e9c..1f4c84e1a79 100644 --- a/src/libs/utils/checkablemessagebox.h +++ b/src/libs/utils/checkablemessagebox.h @@ -23,7 +23,7 @@ public: struct BoolDecision { QString text; - bool &value; + bool &doNotAskAgain; }; struct SettingsDecision @@ -48,9 +48,9 @@ public: return Decider{SettingsDecision{text, settings, settingsSubKey}}; } - static Decider make_decider(bool &value, const QString &text = msgDoNotAskAgain()) + static Decider make_decider(bool &doNotAskAgain, const QString &text = msgDoNotAskAgain()) { - return Decider{BoolDecision{text, value}}; + return Decider{BoolDecision{text, doNotAskAgain}}; } static Decider make_decider(BoolAspect &aspect, const QString &text = msgDoNotAskAgain()) From b512f414bda2d6914c6209522e94f98ce1d4a570 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 15 May 2023 15:19:01 +0200 Subject: [PATCH 1111/1447] Session: Minimize direct use of reader when loading sessions Instead of directly reading things like the project list from the reader, add a map of "session values" in the session and read these from the reader once, then use the session to access these values while loading the details of the session. This is in preparation of separating the session loading from projectexplorer. This is similar to Session::(set)Value. We cannot use the same (set)Value methods directly though, because of differences in the handling of these values during implict and explicit default session loading. Change-Id: I9a4f38a9f958734d20d6e6eb7253f9e44ba1285e Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../projectexplorer/projectexplorer.cpp | 4 +- .../projectexplorer/projectmanager.cpp | 86 ++++++++++--------- src/plugins/projectexplorer/projectmanager.h | 2 - src/plugins/projectexplorer/session.cpp | 38 ++++++-- src/plugins/projectexplorer/session.h | 11 +++ src/plugins/projectexplorer/session_p.h | 5 +- 6 files changed, 93 insertions(+), 53 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 6334dfee582..ca7c40a0731 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2400,7 +2400,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con Utils::equal(&Project::projectFilePath, filePath)); if (found) { alreadyOpen.append(found); - ProjectManager::reportProjectLoadingProgress(); + SessionManager::sessionLoadingProgress(); continue; } @@ -2429,7 +2429,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con .arg(mt.name())); } if (filePaths.size() > 1) - ProjectManager::reportProjectLoadingProgress(); + SessionManager::sessionLoadingProgress(); } dd->updateActions(); diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index 09f6ad2cf41..81824c7c7af 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -54,8 +54,8 @@ const char DEFAULT_SESSION[] = "default"; class ProjectManagerPrivate { public: - void restoreDependencies(const PersistentSettingsReader &reader); - void restoreStartupProject(const PersistentSettingsReader &reader); + void restoreDependencies(); + void restoreStartupProject(); void restoreProjects(const FilePaths &fileList); void askUserAboutFailedProjects(); @@ -619,11 +619,11 @@ void ProjectManager::removeProjects(const QList &remove) qDeleteAll(remove); } -void ProjectManagerPrivate::restoreDependencies(const PersistentSettingsReader &reader) +void ProjectManagerPrivate::restoreDependencies() { - QMap depMap = reader.restoreValue(QLatin1String("ProjectDependencies")).toMap(); - auto i = depMap.constBegin(); - while (i != depMap.constEnd()) { + QMap depMap = SessionManager::sessionValue("ProjectDependencies").toMap(); + auto i = depMap.constBegin(); + while (i != depMap.constEnd()) { const QString &key = i.key(); FilePaths values; const QStringList valueList = i.value().toStringList(); @@ -631,7 +631,7 @@ void ProjectManagerPrivate::restoreDependencies(const PersistentSettingsReader & values << FilePath::fromString(value); m_depMap.insert(FilePath::fromString(key), values); ++i; - } + } } void ProjectManagerPrivate::askUserAboutFailedProjects() @@ -655,9 +655,10 @@ void ProjectManagerPrivate::askUserAboutFailedProjects() } } -void ProjectManagerPrivate::restoreStartupProject(const PersistentSettingsReader &reader) +void ProjectManagerPrivate::restoreStartupProject() { - const FilePath startupProject = FilePath::fromSettings(reader.restoreValue("StartupProject")); + const FilePath startupProject = FilePath::fromSettings( + SessionManager::sessionValue("StartupProject")); if (!startupProject.isEmpty()) { for (Project *pro : std::as_const(m_projects)) { if (pro->projectFilePath() == startupProject) { @@ -732,7 +733,6 @@ bool ProjectManager::loadSession(const QString &session, bool initial) if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) return false; - FilePaths fileList; // Try loading the file FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION : session); PersistentSettingsReader reader; @@ -749,8 +749,6 @@ bool ProjectManager::loadSession(const QString &session, bool initial) emit SessionManager::instance()->sessionLoaded(DEFAULT_SESSION); return true; } - - fileList = FileUtils::toFilePathList(reader.restoreValue("ProjectList").toStringList()); } else if (loadImplicitDefault) { return true; } @@ -771,20 +769,11 @@ bool ProjectManager::loadSession(const QString &session, bool initial) return false; } - // find a list of projects to close later - const QList projectsToRemove = Utils::filtered(projects(), [&fileList](Project *p) { - return !fileList.contains(p->projectFilePath()); - }); - const QList openProjects = projects(); - const FilePaths projectPathsToLoad = Utils::filtered(fileList, [&openProjects](const FilePath &path) { - return !Utils::contains(openProjects, [&path](Project *p) { - return p->projectFilePath() == path; - }); - }); d->m_failedProjects.clear(); d->m_depMap.clear(); if (!switchFromImplicitToExplicitDefault) sb_d->m_values.clear(); + sb_d->m_sessionValues.clear(); d->m_casadeSetActive = false; sb_d->m_sessionName = session; @@ -798,38 +787,53 @@ bool ProjectManager::loadSession(const QString &session, bool initial) ProgressManager::addTask(sb_d->m_future.future(), Tr::tr("Loading Session"), "ProjectExplorer.SessionFile.Load"); - sb_d->m_future.setProgressRange(0, 1); + sb_d->m_future.setProgressRange(0, 1 /*initialization*/ + 1 /*editors*/); sb_d->m_future.setProgressValue(0); if (!switchFromImplicitToExplicitDefault) sb_d->restoreValues(reader); - emit SessionManager::instance()->aboutToLoadSession(session); + sb_d->restoreSessionValues(reader); // retrieve all values before the following code could change them again Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); if (!modeId.isValid()) modeId = Id(Core::Constants::MODE_EDIT); - QColor c = QColor(reader.restoreValue(QLatin1String("Color")).toString()); + QColor c = QColor(SessionManager::sessionValue("Color").toString()); if (c.isValid()) StyleHelper::setBaseColor(c); - sb_d->m_future.setProgressRange(0, projectPathsToLoad.count() + 1/*initialization above*/ + 1/*editors*/); - sb_d->m_future.setProgressValue(1); - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + SessionManager::sessionLoadingProgress(); + + sb_d->restoreEditors(); + + // let other code restore the session + emit SessionManager::instance()->aboutToLoadSession(session); + + // find a list of projects to close later + const FilePaths fileList = FileUtils::toFilePathList( + SessionManager::sessionValue("ProjectList").toStringList()); + const QList projectsToRemove + = Utils::filtered(projects(), [&fileList](Project *p) { + return !fileList.contains(p->projectFilePath()); + }); + const QList openProjects = projects(); + const FilePaths projectPathsToLoad + = Utils::filtered(fileList, [&openProjects](const FilePath &path) { + return !Utils::contains(openProjects, [&path](Project *p) { + return p->projectFilePath() == path; + }); + }); + + SessionManager::addSessionLoadingSteps(projectPathsToLoad.count()); d->restoreProjects(projectPathsToLoad); - sb_d->sessionLoadingProgress(); - d->restoreDependencies(reader); - d->restoreStartupProject(reader); + SessionManager::sessionLoadingProgress(); + d->restoreDependencies(); + d->restoreStartupProject(); removeProjects(projectsToRemove); // only remove old projects now that the startup project is set! - sb_d->restoreEditors(reader); - - sb_d->m_future.reportFinished(); - sb_d->m_future = QFutureInterface(); - // Fall back to Project mode if the startup project is unconfigured and // use the mode saved in the session otherwise if (d->m_startupProject && d->m_startupProject->needsConfiguration()) @@ -843,9 +847,12 @@ bool ProjectManager::loadSession(const QString &session, bool initial) ModeManager::setFocusToCurrentMode(); } - d->m_casadeSetActive = reader.restoreValue(QLatin1String("CascadeSetActive"), false).toBool(); + d->m_casadeSetActive = SessionManager::sessionValue("CascadeSetActive", false).toBool(); sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); + sb_d->m_future.reportFinished(); + sb_d->m_future = QFutureInterface(); + emit SessionManager::instance()->sessionLoaded(session); // Starts a event loop, better do that at the very end @@ -854,11 +861,6 @@ bool ProjectManager::loadSession(const QString &session, bool initial) return true; } -void ProjectManager::reportProjectLoadingProgress() -{ - sb_d->sessionLoadingProgress(); -} - FilePaths ProjectManager::projectsForSessionName(const QString &session) { const FilePath fileName = SessionManager::sessionNameToFileName(session); diff --git a/src/plugins/projectexplorer/projectmanager.h b/src/plugins/projectexplorer/projectmanager.h index ad3e402992a..1aa58d6aa57 100644 --- a/src/plugins/projectexplorer/projectmanager.h +++ b/src/plugins/projectexplorer/projectmanager.h @@ -82,8 +82,6 @@ public: static Utils::FilePaths projectsForSessionName(const QString &session); - static void reportProjectLoadingProgress(); - static bool loadSession(const QString &session, bool initial = false); signals: diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index f1588147765..a259e5336ee 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -141,6 +141,17 @@ QVariant SessionManager::value(const QString &name) return (it == sb_d->m_values.constEnd()) ? QVariant() : *it; } +void SessionManager::setSessionValue(const QString &name, const QVariant &value) +{ + sb_d->m_sessionValues.insert(name, value); +} + +QVariant SessionManager::sessionValue(const QString &name, const QVariant &defaultValue) +{ + auto it = sb_d->m_sessionValues.constFind(name); + return (it == sb_d->m_sessionValues.constEnd()) ? defaultValue : *it; +} + QString SessionManager::activeSession() { return sb_d->m_sessionName; @@ -382,12 +393,24 @@ void SessionManagerPrivate::restoreValues(const PersistentSettingsReader &reader } } -void SessionManagerPrivate::restoreEditors(const PersistentSettingsReader &reader) +void SessionManagerPrivate::restoreSessionValues(const PersistentSettingsReader &reader) { - const QVariant editorsettings = reader.restoreValue(QLatin1String("EditorSettings")); + const QVariantMap values = reader.restoreValues(); + // restore toplevel items that are not restored by restoreValues + const auto end = values.constEnd(); + for (auto it = values.constBegin(); it != end; ++it) { + if (it.key() == "valueKeys" || it.key().startsWith("value-")) + continue; + m_sessionValues.insert(it.key(), it.value()); + } +} + +void SessionManagerPrivate::restoreEditors() +{ + const QVariant editorsettings = m_sessionValues.value("EditorSettings"); if (editorsettings.isValid()) { EditorManager::restoreState(QByteArray::fromBase64(editorsettings.toByteArray())); - sessionLoadingProgress(); + SessionManager::sessionLoadingProgress(); } } @@ -412,10 +435,15 @@ void SessionManager::markSessionFileDirty() sb_d->m_virginSession = false; } -void SessionManagerPrivate::sessionLoadingProgress() +void SessionManager::sessionLoadingProgress() { - m_future.setProgressValue(m_future.progressValue() + 1); + sb_d->m_future.setProgressValue(sb_d->m_future.progressValue() + 1); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } +void SessionManager::addSessionLoadingSteps(int steps) +{ + sb_d->m_future.setProgressRange(0, sb_d->m_future.progressMaximum() + steps); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 21f571b1f3f..9af82d066cd 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -47,15 +47,26 @@ public: static bool isDefaultSession(const QString &session); // Let other plugins store persistent values within the session file + // These are settings that are also saved and loaded at startup, and are taken over + // to the default session when switching from implicit to explicit default session static void setValue(const QString &name, const QVariant &value); static QVariant value(const QString &name); + // These are settings that are specific to a session and are not loaded + // at startup and also not taken over to the default session when switching from implicit + static void setSessionValue(const QString &name, const QVariant &value); + static QVariant sessionValue(const QString &name, const QVariant &defaultValue = {}); + static bool loadingSession(); static void markSessionFileDirty(); + static void sessionLoadingProgress(); + static void addSessionLoadingSteps(int steps); signals: void startupSessionRestored(); void aboutToUnloadSession(QString sessionName); + // Sent during session loading, after the values of the session are available via value() and + // sessionValue. Use to restore values from the new session void aboutToLoadSession(QString sessionName); void sessionLoaded(QString sessionName); void aboutToSaveSession(); diff --git a/src/plugins/projectexplorer/session_p.h b/src/plugins/projectexplorer/session_p.h index 471c78c06eb..40f691ab2d1 100644 --- a/src/plugins/projectexplorer/session_p.h +++ b/src/plugins/projectexplorer/session_p.h @@ -15,8 +15,8 @@ public: void restoreStartupSession(); void restoreValues(const PersistentSettingsReader &reader); - void restoreEditors(const PersistentSettingsReader &reader); - void sessionLoadingProgress(); + void restoreSessionValues(const PersistentSettingsReader &reader); + void restoreEditors(); bool isStartupSessionRestored(); void saveSettings(); @@ -38,6 +38,7 @@ public: QHash m_lastActiveTimes; QMap m_values; + QMap m_sessionValues; QFutureInterface m_future; PersistentSettingsWriter *m_writer = nullptr; }; From a928fee10890f964e02d290ae428af0810dcb0ad Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 15 May 2023 16:09:56 +0200 Subject: [PATCH 1112/1447] Separate session loading from project manager Move the generic parts to session manager and let the project manager load its parts separately. Change-Id: I14ee3311ab0c0f40444674b82cee1e4bb0fb9daf Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- .../clangtoolspreconfiguredsessiontests.cpp | 2 +- .../projectexplorer/projectexplorer.cpp | 2 +- .../projectexplorer/projectmanager.cpp | 199 ++++-------------- src/plugins/projectexplorer/projectmanager.h | 2 - src/plugins/projectexplorer/session.cpp | 129 +++++++++++- src/plugins/projectexplorer/session.h | 3 + src/plugins/projectexplorer/sessionmodel.cpp | 2 +- 7 files changed, 174 insertions(+), 165 deletions(-) diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index 4d4b34c1ef8..1a87580efc1 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -91,7 +91,7 @@ void PreconfiguredSessionTests::initTestCase() // Load session const FilePaths projects = ProjectManager::projectsForSessionName(preconfiguredSessionName); WaitForParsedProjects waitForParsedProjects(projects); - QVERIFY(ProjectManager::loadSession(preconfiguredSessionName)); + QVERIFY(SessionManager::loadSession(preconfiguredSessionName)); QVERIFY(waitForParsedProjects.wait()); } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index ca7c40a0731..1244dbd1ba2 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -4013,7 +4013,7 @@ void ProjectExplorerPluginPrivate::updateSessionMenu() void ProjectExplorerPluginPrivate::setSession(QAction *action) { - ProjectManager::loadSession(action->data().toString()); + SessionManager::loadSession(action->data().toString()); } void ProjectExplorerPlugin::setProjectExplorerSettings(const ProjectExplorerSettings &pes) diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index 81824c7c7af..ccfa95a289a 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -49,11 +49,10 @@ using namespace ProjectExplorer::Internal; namespace ProjectExplorer { -const char DEFAULT_SESSION[] = "default"; - class ProjectManagerPrivate { public: + void loadSession(); void restoreDependencies(); void restoreStartupProject(); void restoreProjects(const FilePaths &fileList); @@ -106,6 +105,10 @@ ProjectManager::ProjectManager() EditorManager::setWindowTitleAdditionHandler(&ProjectManagerPrivate::windowTitleAddition); EditorManager::setSessionTitleHandler(&ProjectManagerPrivate::sessionTitle); + + connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, this, [] { + d->loadSession(); + }); } ProjectManager::~ProjectManager() @@ -693,172 +696,52 @@ void ProjectManagerPrivate::restoreProjects(const FilePaths &fileList) } } -/* - * ========== Notes on storing and loading the default session ========== - * The default session comes in two flavors: implicit and explicit. The implicit one, - * also referred to as "default virgin" in the code base, is the one that is active - * at start-up, if no session has been explicitly loaded due to command-line arguments - * or the "restore last session" setting in the session manager. - * The implicit default session silently turns into the explicit default session - * by loading a project or a file or changing settings in the Dependencies panel. The explicit - * default session can also be loaded by the user via the Welcome Screen. - * This mechanism somewhat complicates the handling of session-specific settings such as - * the ones in the task pane: Users expect that changes they make there become persistent, even - * when they are in the implicit default session. However, we can't just blindly store - * the implicit default session, because then we'd overwrite the project list of the explicit - * default session. Therefore, we use the following logic: - * - Upon start-up, if no session is to be explicitly loaded, we restore the parts of the - * explicit default session that are not related to projects, editors etc; the - * "general settings" of the session, so to speak. - * - When storing the implicit default session, we overwrite only these "general settings" - * of the explicit default session and keep the others as they are. - * - When switching from the implicit to the explicit default session, we keep the - * "general settings" and load everything else from the session file. - * This guarantees that user changes are properly transferred and nothing gets lost from - * either the implicit or the explicit default session. - * - */ -bool ProjectManager::loadSession(const QString &session, bool initial) +void ProjectManagerPrivate::loadSession() { - const bool loadImplicitDefault = session.isEmpty(); - const bool switchFromImplicitToExplicitDefault = session == DEFAULT_SESSION - && sb_d->m_sessionName == DEFAULT_SESSION && !initial; - - // Do nothing if we have that session already loaded, - // exception if the session is the default virgin session - // we still want to be able to load the default session - if (session == sb_d->m_sessionName && !SessionManager::isDefaultVirgin()) - return true; - - if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) - return false; - - // Try loading the file - FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION : session); - PersistentSettingsReader reader; - if (fileName.exists()) { - if (!reader.load(fileName)) { - QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while restoring session"), - Tr::tr("Could not restore session %1").arg(fileName.toUserOutput())); - - return false; - } - - if (loadImplicitDefault) { - sb_d->restoreValues(reader); - emit SessionManager::instance()->sessionLoaded(DEFAULT_SESSION); - return true; - } - } else if (loadImplicitDefault) { - return true; - } - - sb_d->m_loadingSession = true; - - // Allow everyone to set something in the session and before saving - emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName); - - if (!save()) { - sb_d->m_loadingSession = false; - return false; - } - - // Clean up - if (!EditorManager::closeAllEditors()) { - sb_d->m_loadingSession = false; - return false; - } - d->m_failedProjects.clear(); d->m_depMap.clear(); - if (!switchFromImplicitToExplicitDefault) - sb_d->m_values.clear(); - sb_d->m_sessionValues.clear(); d->m_casadeSetActive = false; - sb_d->m_sessionName = session; - delete sb_d->m_writer; - sb_d->m_writer = nullptr; - EditorManager::updateWindowTitles(); + // not ideal that this is in ProjectManager + Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); + if (!modeId.isValid()) + modeId = Id(Core::Constants::MODE_EDIT); - if (fileName.exists()) { - sb_d->m_virginSession = false; + // find a list of projects to close later + const FilePaths fileList = FileUtils::toFilePathList( + SessionManager::sessionValue("ProjectList").toStringList()); + const QList projectsToRemove + = Utils::filtered(ProjectManager::projects(), [&fileList](Project *p) { + return !fileList.contains(p->projectFilePath()); + }); + const QList openProjects = ProjectManager::projects(); + const FilePaths projectPathsToLoad + = Utils::filtered(fileList, [&openProjects](const FilePath &path) { + return !Utils::contains(openProjects, + [&path](Project *p) { return p->projectFilePath() == path; }); + }); - ProgressManager::addTask(sb_d->m_future.future(), Tr::tr("Loading Session"), - "ProjectExplorer.SessionFile.Load"); + SessionManager::addSessionLoadingSteps(projectPathsToLoad.count()); - sb_d->m_future.setProgressRange(0, 1 /*initialization*/ + 1 /*editors*/); - sb_d->m_future.setProgressValue(0); + d->restoreProjects(projectPathsToLoad); + d->restoreDependencies(); + d->restoreStartupProject(); - if (!switchFromImplicitToExplicitDefault) - sb_d->restoreValues(reader); - sb_d->restoreSessionValues(reader); + // only remove old projects now that the startup project is set! + ProjectManager::removeProjects(projectsToRemove); - // retrieve all values before the following code could change them again - Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); - if (!modeId.isValid()) - modeId = Id(Core::Constants::MODE_EDIT); + // Fall back to Project mode if the startup project is unconfigured and + // use the mode saved in the session otherwise + if (d->m_startupProject && d->m_startupProject->needsConfiguration()) + modeId = Id(Constants::MODE_SESSION); - QColor c = QColor(SessionManager::sessionValue("Color").toString()); - if (c.isValid()) - StyleHelper::setBaseColor(c); - - SessionManager::sessionLoadingProgress(); - - sb_d->restoreEditors(); - - // let other code restore the session - emit SessionManager::instance()->aboutToLoadSession(session); - - // find a list of projects to close later - const FilePaths fileList = FileUtils::toFilePathList( - SessionManager::sessionValue("ProjectList").toStringList()); - const QList projectsToRemove - = Utils::filtered(projects(), [&fileList](Project *p) { - return !fileList.contains(p->projectFilePath()); - }); - const QList openProjects = projects(); - const FilePaths projectPathsToLoad - = Utils::filtered(fileList, [&openProjects](const FilePath &path) { - return !Utils::contains(openProjects, [&path](Project *p) { - return p->projectFilePath() == path; - }); - }); - - SessionManager::addSessionLoadingSteps(projectPathsToLoad.count()); - - d->restoreProjects(projectPathsToLoad); - SessionManager::sessionLoadingProgress(); - d->restoreDependencies(); - d->restoreStartupProject(); - - removeProjects(projectsToRemove); // only remove old projects now that the startup project is set! - - // Fall back to Project mode if the startup project is unconfigured and - // use the mode saved in the session otherwise - if (d->m_startupProject && d->m_startupProject->needsConfiguration()) - modeId = Id(Constants::MODE_SESSION); - - ModeManager::activateMode(modeId); - ModeManager::setFocusToCurrentMode(); - } else { - removeProjects(projects()); - ModeManager::activateMode(Id(Core::Constants::MODE_EDIT)); - ModeManager::setFocusToCurrentMode(); - } + ModeManager::activateMode(modeId); + ModeManager::setFocusToCurrentMode(); d->m_casadeSetActive = SessionManager::sessionValue("CascadeSetActive", false).toBool(); - sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); - - sb_d->m_future.reportFinished(); - sb_d->m_future = QFutureInterface(); - - emit SessionManager::instance()->sessionLoaded(session); // Starts a event loop, better do that at the very end - d->askUserAboutFailedProjects(); - sb_d->m_loadingSession = false; - return true; + QMetaObject::invokeMethod(m_instance, [this] { askUserAboutFailedProjects(); }); } FilePaths ProjectManager::projectsForSessionName(const QString &session) @@ -901,7 +784,7 @@ void ProjectExplorerPlugin::testSessionSwitch() QVERIFY(sessionSpec.projectFile.open()); sessionSpec.projectFile.write(proFileContents); sessionSpec.projectFile.close(); - QVERIFY(ProjectManager::loadSession(sessionSpec.name)); + QVERIFY(SessionManager::loadSession(sessionSpec.name)); const OpenProjectResult openResult = ProjectExplorerPlugin::openProject( FilePath::fromString(sessionSpec.projectFile.fileName())); @@ -913,16 +796,16 @@ void ProjectExplorerPlugin::testSessionSwitch() QCOMPARE(ProjectManager::projects().count(), 1); } for (int i = 0; i < 30; ++i) { - QVERIFY(ProjectManager::loadSession("session1")); + QVERIFY(SessionManager::loadSession("session1")); QCOMPARE(SessionManager::activeSession(), "session1"); QCOMPARE(ProjectManager::projects().count(), 1); - QVERIFY(ProjectManager::loadSession("session2")); + QVERIFY(SessionManager::loadSession("session2")); QCOMPARE(SessionManager::activeSession(), "session2"); QCOMPARE(ProjectManager::projects().count(), 1); } - QVERIFY(ProjectManager::loadSession("session1")); + QVERIFY(SessionManager::loadSession("session1")); ProjectManager::closeAllProjects(); - QVERIFY(ProjectManager::loadSession("session2")); + QVERIFY(SessionManager::loadSession("session2")); ProjectManager::closeAllProjects(); QVERIFY(SessionManager::deleteSession("session1")); QVERIFY(SessionManager::deleteSession("session2")); diff --git a/src/plugins/projectexplorer/projectmanager.h b/src/plugins/projectexplorer/projectmanager.h index 1aa58d6aa57..7f515869013 100644 --- a/src/plugins/projectexplorer/projectmanager.h +++ b/src/plugins/projectexplorer/projectmanager.h @@ -82,8 +82,6 @@ public: static Utils::FilePaths projectsForSessionName(const QString &session); - static bool loadSession(const QString &session, bool initial = false); - signals: void targetAdded(ProjectExplorer::Target *target); void targetRemoved(ProjectExplorer::Target *target); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index a259e5336ee..5edd7b4f9d6 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -213,7 +213,7 @@ bool SessionManager::renameSession(const QString &original, const QString &newNa if (!cloneSession(original, newName)) return false; if (original == activeSession()) - ProjectManager::loadSession(newName); + loadSession(newName); emit instance()->sessionRenamed(original, newName); return deleteSession(original); } @@ -341,7 +341,7 @@ void SessionManagerPrivate::restoreStartupSession() } // !arguments.isEmpty() // Restore latest session or what was passed on the command line - ProjectManager::loadSession(!sessionToRestoreAtStartup.isEmpty() ? sessionToRestoreAtStartup + SessionManager::loadSession(!sessionToRestoreAtStartup.isEmpty() ? sessionToRestoreAtStartup : QString(), true); @@ -446,4 +446,129 @@ void SessionManager::addSessionLoadingSteps(int steps) sb_d->m_future.setProgressRange(0, sb_d->m_future.progressMaximum() + steps); } +/* + * ========== Notes on storing and loading the default session ========== + * The default session comes in two flavors: implicit and explicit. The implicit one, + * also referred to as "default virgin" in the code base, is the one that is active + * at start-up, if no session has been explicitly loaded due to command-line arguments + * or the "restore last session" setting in the session manager. + * The implicit default session silently turns into the explicit default session + * by loading a project or a file or changing settings in the Dependencies panel. The explicit + * default session can also be loaded by the user via the Welcome Screen. + * This mechanism somewhat complicates the handling of session-specific settings such as + * the ones in the task pane: Users expect that changes they make there become persistent, even + * when they are in the implicit default session. However, we can't just blindly store + * the implicit default session, because then we'd overwrite the project list of the explicit + * default session. Therefore, we use the following logic: + * - Upon start-up, if no session is to be explicitly loaded, we restore the parts of the + * explicit default session that are not related to projects, editors etc; the + * "general settings" of the session, so to speak. + * - When storing the implicit default session, we overwrite only these "general settings" + * of the explicit default session and keep the others as they are. + * - When switching from the implicit to the explicit default session, we keep the + * "general settings" and load everything else from the session file. + * This guarantees that user changes are properly transferred and nothing gets lost from + * either the implicit or the explicit default session. + * + */ +bool SessionManager::loadSession(const QString &session, bool initial) +{ + const bool loadImplicitDefault = session.isEmpty(); + const bool switchFromImplicitToExplicitDefault = session == DEFAULT_SESSION + && sb_d->m_sessionName == DEFAULT_SESSION + && !initial; + + // Do nothing if we have that session already loaded, + // exception if the session is the default virgin session + // we still want to be able to load the default session + if (session == sb_d->m_sessionName && !SessionManager::isDefaultVirgin()) + return true; + + if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) + return false; + + // Try loading the file + FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION + : session); + PersistentSettingsReader reader; + if (fileName.exists()) { + if (!reader.load(fileName)) { + QMessageBox::warning(ICore::dialogParent(), + Tr::tr("Error while restoring session"), + Tr::tr("Could not restore session %1").arg(fileName.toUserOutput())); + + return false; + } + + if (loadImplicitDefault) { + sb_d->restoreValues(reader); + emit SessionManager::instance()->sessionLoaded(DEFAULT_SESSION); + return true; + } + } else if (loadImplicitDefault) { + return true; + } + + sb_d->m_loadingSession = true; + + // Allow everyone to set something in the session and before saving + emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName); + + if (!ProjectManager::save()) { + sb_d->m_loadingSession = false; + return false; + } + + // Clean up + if (!EditorManager::closeAllEditors()) { + sb_d->m_loadingSession = false; + return false; + } + + if (!switchFromImplicitToExplicitDefault) + sb_d->m_values.clear(); + sb_d->m_sessionValues.clear(); + + sb_d->m_sessionName = session; + delete sb_d->m_writer; + sb_d->m_writer = nullptr; + EditorManager::updateWindowTitles(); + + sb_d->m_virginSession = false; + + ProgressManager::addTask(sb_d->m_future.future(), + Tr::tr("Loading Session"), + "ProjectExplorer.SessionFile.Load"); + + sb_d->m_future.setProgressRange(0, 1 /*initialization*/ + 1 /*editors*/); + sb_d->m_future.setProgressValue(0); + + if (fileName.exists()) { + if (!switchFromImplicitToExplicitDefault) + sb_d->restoreValues(reader); + sb_d->restoreSessionValues(reader); + } + + QColor c = QColor(SessionManager::sessionValue("Color").toString()); + if (c.isValid()) + StyleHelper::setBaseColor(c); + + SessionManager::sessionLoadingProgress(); + + sb_d->restoreEditors(); + + // let other code restore the session + emit SessionManager::instance()->aboutToLoadSession(session); + + sb_d->m_future.reportFinished(); + sb_d->m_future = QFutureInterface(); + + sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); + + emit SessionManager::instance()->sessionLoaded(session); + + sb_d->m_loadingSession = false; + return true; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 9af82d066cd..b40e687d648 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -62,6 +62,9 @@ public: static void sessionLoadingProgress(); static void addSessionLoadingSteps(int steps); + + static bool loadSession(const QString &session, bool initial = false); + signals: void startupSessionRestored(); void aboutToUnloadSession(QString sessionName); diff --git a/src/plugins/projectexplorer/sessionmodel.cpp b/src/plugins/projectexplorer/sessionmodel.cpp index 6e22c3b091d..960a9dbdee3 100644 --- a/src/plugins/projectexplorer/sessionmodel.cpp +++ b/src/plugins/projectexplorer/sessionmodel.cpp @@ -241,7 +241,7 @@ void SessionModel::renameSession(QWidget *parent, const QString &session) void SessionModel::switchToSession(const QString &session) { - ProjectManager::loadSession(session); + SessionManager::loadSession(session); emit sessionSwitched(); } From 95d21f396675df1efc1eb16a825c39981b6ea22b Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 18:32:22 +0200 Subject: [PATCH 1113/1447] Use new FilePathAspect in a few more places Change-Id: I910a802255c8d54a31313dcccb0d1a48ec577b7a Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/conan/conaninstallstep.cpp | 2 +- src/plugins/conan/conansettings.cpp | 1 - src/plugins/conan/conansettings.h | 2 +- src/plugins/copilot/copilotplugin.cpp | 4 ++-- src/plugins/copilot/copilotsettings.cpp | 13 +++++-------- src/plugins/copilot/copilotsettings.h | 4 ++-- src/plugins/subversion/subversionsettings.cpp | 1 - 7 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/plugins/conan/conaninstallstep.cpp b/src/plugins/conan/conaninstallstep.cpp index d0c2ef5bacd..c1957cc976a 100644 --- a/src/plugins/conan/conaninstallstep.cpp +++ b/src/plugins/conan/conaninstallstep.cpp @@ -68,7 +68,7 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id) const QString buildType = bt == BuildConfiguration::Release ? QString("Release") : QString("Debug"); - CommandLine cmd(ConanPlugin::conanSettings()->conanFilePath.filePath()); + CommandLine cmd(ConanPlugin::conanSettings()->conanFilePath()); cmd.addArgs({"install", "-s", "build_type=" + buildType}); if (buildMissing->value()) cmd.addArg("--build=missing"); diff --git a/src/plugins/conan/conansettings.cpp b/src/plugins/conan/conansettings.cpp index 6a608b99f89..83e8f38d533 100644 --- a/src/plugins/conan/conansettings.cpp +++ b/src/plugins/conan/conansettings.cpp @@ -16,7 +16,6 @@ ConanSettings::ConanSettings() registerAspect(&conanFilePath); conanFilePath.setSettingsKey("ConanFilePath"); - conanFilePath.setDisplayStyle(StringAspect::PathChooserDisplay); conanFilePath.setExpectedKind(PathChooser::ExistingCommand); conanFilePath.setDefaultValue(HostOsInfo::withExecutableSuffix("conan")); } diff --git a/src/plugins/conan/conansettings.h b/src/plugins/conan/conansettings.h index 93e61908399..69a836dcfe1 100644 --- a/src/plugins/conan/conansettings.h +++ b/src/plugins/conan/conansettings.h @@ -12,7 +12,7 @@ class ConanSettings : public Utils::AspectContainer public: ConanSettings(); - Utils::StringAspect conanFilePath; + Utils::FilePathAspect conanFilePath; }; } // Conan::Internal diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 3acbc705854..61753b29c30 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -56,8 +56,8 @@ void CopilotPlugin::extensionsInitialized() void CopilotPlugin::restartClient() { LanguageClient::LanguageClientManager::shutdownClient(m_client); - m_client = new CopilotClient(CopilotSettings::instance().nodeJsPath.filePath(), - CopilotSettings::instance().distPath.filePath()); + m_client = new CopilotClient(CopilotSettings::instance().nodeJsPath(), + CopilotSettings::instance().distPath()); } } // namespace Internal diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index a566180ac78..202da82488f 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -36,10 +36,10 @@ CopilotSettings::CopilotSettings() return fp.exists(); }); + registerAspect(&nodeJsPath); nodeJsPath.setExpectedKind(PathChooser::ExistingCommand); nodeJsPath.setDefaultFilePath(nodeFromPath); nodeJsPath.setSettingsKey("Copilot.NodeJsPath"); - nodeJsPath.setDisplayStyle(StringAspect::PathChooserDisplay); nodeJsPath.setLabelText(Tr::tr("Node.js path:")); nodeJsPath.setHistoryCompleter("Copilot.NodePath.History"); nodeJsPath.setDisplayName(Tr::tr("Node.js Path")); @@ -47,26 +47,23 @@ CopilotSettings::CopilotSettings() Tr::tr("Select path to node.js executable. See https://nodejs.org/de/download/" "for installation instructions.")); + registerAspect(&distPath); distPath.setExpectedKind(PathChooser::File); distPath.setDefaultFilePath(distFromVim); distPath.setSettingsKey("Copilot.DistPath"); - distPath.setDisplayStyle(StringAspect::PathChooserDisplay); distPath.setLabelText(Tr::tr("Path to agent.js:")); + distPath.setHistoryCompleter("Copilot.DistPath.History"); + distPath.setDisplayName(Tr::tr("Agent.js path")); distPath.setToolTip(Tr::tr( "Select path to agent.js in copilot neovim plugin. See " "https://github.com/github/copilot.vim#getting-started for installation instructions.")); - distPath.setHistoryCompleter("Copilot.DistPath.History"); - distPath.setDisplayName(Tr::tr("Agent.js path")); + registerAspect(&autoComplete); autoComplete.setDisplayName(Tr::tr("Auto Complete")); autoComplete.setLabelText(Tr::tr("Request completions automatically")); autoComplete.setDefaultValue(true); autoComplete.setToolTip(Tr::tr("Automatically request suggestions for the current text cursor " "position after changes to the document")); - - registerAspect(&nodeJsPath); - registerAspect(&distPath); - registerAspect(&autoComplete); } } // namespace Copilot diff --git a/src/plugins/copilot/copilotsettings.h b/src/plugins/copilot/copilotsettings.h index 44ce178ea5c..23370948765 100644 --- a/src/plugins/copilot/copilotsettings.h +++ b/src/plugins/copilot/copilotsettings.h @@ -14,8 +14,8 @@ public: static CopilotSettings &instance(); - Utils::StringAspect nodeJsPath; - Utils::StringAspect distPath; + Utils::FilePathAspect nodeJsPath; + Utils::FilePathAspect distPath; Utils::BoolAspect autoComplete; }; diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index 98945ab82ef..9bdd07fbf8b 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -33,7 +33,6 @@ SubversionSettings::SubversionSettings() setSettingsGroup("Subversion"); registerAspect(&binaryPath); - binaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setHistoryCompleter("Subversion.Command.History"); binaryPath.setDefaultValue("svn" QTC_HOST_EXE_SUFFIX); From 8121575067f4f0c48de7ca8e9444e3562e4655af Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 12 May 2023 11:50:51 +0200 Subject: [PATCH 1114/1447] Core: Fix item view find ...when there is only one matching item and we are starting search from there. Change-Id: Icfffd37d9330c83058fb81356762e72b183f24e8 Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/find/itemviewfind.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/find/itemviewfind.cpp b/src/plugins/coreplugin/find/itemviewfind.cpp index c1c6e84f936..8bba18ae692 100644 --- a/src/plugins/coreplugin/find/itemviewfind.cpp +++ b/src/plugins/coreplugin/find/itemviewfind.cpp @@ -203,11 +203,18 @@ IFindSupport::Result ItemViewFind::find(const QString &searchTxt, index, d->m_role).toString(); if (d->m_view->model()->flags(index) & Qt::ItemIsSelectable && (index.row() != currentRow || index.parent() != currentIndex.parent()) - && text.indexOf(searchExpr) != -1) + && text.indexOf(searchExpr) != -1) { resultIndex = index; + break; + } } index = followingIndex(index, backward, &stepWrapped); - } while (!resultIndex.isValid() && index.isValid() && index != currentIndex); + if (index == currentIndex) { // we're back where we started + if (d->m_view->model()->data(index, d->m_role).toString().indexOf(searchExpr) != -1) + resultIndex = index; + break; + } + } while (index.isValid()); if (resultIndex.isValid()) { d->m_view->setCurrentIndex(resultIndex); From 2cd2324963b7f0ea23e0e6aad5cd04ad42cda049 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 17 May 2023 13:00:47 +0200 Subject: [PATCH 1115/1447] CheckableMessageBox: Simplify checkbox setup If the dialog is shown, the checkbox must be unchecked, because otherwise the dialog would not have been shown. Change-Id: I34e8034975baef710997e0cdb3c7d2f8b0c94cd2 Reviewed-by: Marcus Tillmanns --- src/libs/utils/checkablemessagebox.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index 29951fd9c44..bf566e53a8a 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -64,19 +64,11 @@ static QMessageBox::StandardButton exec( return acceptButton; msgBox.setCheckBox(new QCheckBox); + msgBox.checkBox()->setChecked(false); std::visit( [&msgBox](auto &&decider) { - using T = std::decay_t; msgBox.checkBox()->setText(decider.text); - if constexpr (std::is_same_v) { - msgBox.checkBox()->setChecked(decider.doNotAskAgain); - } else if constexpr (std::is_same_v) { - msgBox.checkBox()->setChecked( - decider.settings->value(decider.settingsSubKey, false).toBool()); - } else if constexpr (std::is_same_v) { - msgBox.checkBox()->setChecked(decider.aspect.value()); - } }, *decider); } From b2e30e7ef86595c537062cb8261a0735b389949c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 16 May 2023 11:17:27 +0200 Subject: [PATCH 1116/1447] Utils: add Position::fromCursor with tests Change-Id: I1cd989eaf7e75bc04f171989f9f9fe932402abef Reviewed-by: Qt CI Bot Reviewed-by: Jarek Kobus --- src/libs/utils/textutils.cpp | 5 +++++ src/libs/utils/textutils.h | 1 + tests/auto/utils/text/tst_text.cpp | 34 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index a57e5310593..8b17cc7e013 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -59,6 +59,11 @@ Position Position::fromPositionInDocument(const QTextDocument *document, int pos return {}; } +Position Position::fromCursor(const QTextCursor &c) +{ + return c.isNull() ? Position{} : Position{c.blockNumber() + 1, c.positionInBlock()}; +} + int Range::length(const QString &text) const { if (end.line < begin.line) diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index df1eb73d8eb..96b7afbeb86 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -32,6 +32,7 @@ public: static Position fromFileName(QStringView fileName, int &postfixPos); static Position fromPositionInDocument(const QTextDocument *document, int pos); + static Position fromCursor(const QTextCursor &cursor); }; class QTCREATOR_UTILS_EXPORT Range diff --git a/tests/auto/utils/text/tst_text.cpp b/tests/auto/utils/text/tst_text.cpp index 3428b0b7576..3672eb2ce2a 100644 --- a/tests/auto/utils/text/tst_text.cpp +++ b/tests/auto/utils/text/tst_text.cpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -19,6 +20,9 @@ private slots: void testPositionFromPositionInDocument_data(); void testPositionFromPositionInDocument(); + void testPositionFromCursor_data(); + void testPositionFromCursor(); + void testRangeLength_data(); void testRangeLength(); }; @@ -135,6 +139,36 @@ void tst_Text::testPositionFromPositionInDocument() QCOMPARE(Position::fromPositionInDocument(&doc, documentPosition), position); } +void tst_Text::testPositionFromCursor_data() +{ + QTest::addColumn("text"); + QTest::addColumn("documentPosition"); + QTest::addColumn("position"); + + QTest::newRow("0") << QString() << 0 << Position{1, 0}; + QTest::newRow("-1") << QString() << -1 << Position{}; + QTest::newRow("mid line") << QString("foo\n") << 1 << Position{1, 1}; + QTest::newRow("second line") << QString("foo\n") << 4 << Position{2, 0}; + QTest::newRow("second mid line") << QString("foo\nbar") << 5 << Position{2, 1}; + QTest::newRow("behind content") << QString("foo\nbar") << 8 << Position{1, 0}; +} + +void tst_Text::testPositionFromCursor() +{ + QFETCH(QString, text); + QFETCH(int, documentPosition); + QFETCH(Position, position); + + if (documentPosition < 0) {// test invalid Cursor { + QCOMPARE(Position::fromCursor(QTextCursor()), position); + } else { + QTextDocument doc(text); + QTextCursor cursor(&doc); + cursor.setPosition(documentPosition); + QCOMPARE(Position::fromCursor(cursor), position); + } +} + void tst_Text::testRangeLength_data() { QTest::addColumn("text"); From 5ad790d5c8f70b46c8603724e919fc3e30d10c60 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 16 May 2023 11:09:50 +0200 Subject: [PATCH 1117/1447] FakeVim: Maintain highlighting on split Fixes: QTCREATORBUG-28914 Change-Id: I4e0b82e49bd97f19eb513f21e1dc405ea9f0700c Reviewed-by: David Schulz Reviewed-by: --- src/plugins/fakevim/fakevimplugin.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index be06ece7f45..49354921325 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -514,6 +514,8 @@ public: void handleDelayedQuit(bool forced, Core::IEditor *editor); void userActionTriggered(int key); + void updateAllHightLights(); + void switchToFile(int n); int currentFile() const; @@ -557,6 +559,8 @@ public: MiniBuffer *m_miniBuffer = nullptr; FakeVimPluginRunData *runData = nullptr; + QString m_lastHighlight; + int m_savedCursorFlashTime = 0; }; @@ -1252,6 +1256,16 @@ void FakeVimPluginPrivate::userActionTriggered(int key) } } +void FakeVimPluginPrivate::updateAllHightLights() +{ + const QList editors = EditorManager::visibleEditors(); + for (IEditor *editor : editors) { + QWidget *w = editor->widget(); + if (auto find = Aggregation::query(w)) + find->highlightAll(m_lastHighlight, FindRegularExpression | FindCaseSensitively); + } +} + void FakeVimPluginPrivate::createRelativeNumberWidget(IEditor *editor) { if (auto textEditor = TextEditorWidget::fromEditor(editor)) { @@ -1598,7 +1612,8 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) tew->clearSuggestion(); }); - handler->highlightMatches.set([](const QString &needle) { + handler->highlightMatches.set([this](const QString &needle) { + m_lastHighlight = needle; for (IEditor *editor : EditorManager::visibleEditors()) { QWidget *w = editor->widget(); if (auto find = Aggregation::query(w)) @@ -2034,9 +2049,11 @@ void FakeVimPluginPrivate::handleExCommand(FakeVimHandler *handler, bool *handle } else if (cmd.matches("sp", "split")) { // :sp[lit] triggerAction(Core::Constants::SPLIT); + updateAllHightLights(); } else if (cmd.matches("vs", "vsplit")) { // :vs[plit] triggerAction(Core::Constants::SPLIT_SIDE_BY_SIDE); + updateAllHightLights(); } else if (cmd.matches("mak", "make")) { // :mak[e][!] [arguments] triggerAction(ProjectExplorer::Constants::BUILD); From 23b0082b20272847f9d764f05c7495b15e5e941e Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 17 May 2023 15:21:18 +0200 Subject: [PATCH 1118/1447] Tests: Build text tests with Qbs as well Amends 1a98dda5c417e892cadbedb656829cf2ba4d1d0a. Change-Id: If563437141ac75bb2b72a9d550d1fb507a89e63c Reviewed-by: Christian Kandeler --- tests/auto/utils/text/text.qbs | 2 +- tests/auto/utils/utils.qbs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/utils/text/text.qbs b/tests/auto/utils/text/text.qbs index 828dec8d117..91b2cdb6950 100644 --- a/tests/auto/utils/text/text.qbs +++ b/tests/auto/utils/text/text.qbs @@ -1,7 +1,7 @@ import qbs QtcAutotest { - name: "Utils::Text autotest" + name: "Text autotest" Depends { name: "Utils" } files: "tst_text.cpp" } diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs index e267f009f7e..9f5a580435a 100644 --- a/tests/auto/utils/utils.qbs +++ b/tests/auto/utils/utils.qbs @@ -20,6 +20,7 @@ Project { "settings/settings.qbs", "stringutils/stringutils.qbs", "templateengine/templateengine.qbs", + "text/text.qbs", "treemodel/treemodel.qbs", "unixdevicefileaccess/unixdevicefileaccess.qbs", ] From 5abb1959c5883ddd74c0ddbba477a4e22881b2a8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 14 May 2023 16:50:15 +0200 Subject: [PATCH 1119/1447] ScopedTimer: Make it possible to provide optional message string When optional message argument is provided, both macros print the message instead of __FILE__ and __LINE__ info. It helps to ease the identification of the exact place in code when many macros are added - custom message may be more informative that the file and line location. Change-Id: I7a3ccbdaca2858b44dcbd51a8f9330160dab73e9 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/scopedtimer.cpp | 47 ++++++++++++++++++---------------- src/libs/utils/scopedtimer.h | 24 +++++++++++++---- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/libs/utils/scopedtimer.cpp b/src/libs/utils/scopedtimer.cpp index 97b8beffdaa..6a4522e28d0 100644 --- a/src/libs/utils/scopedtimer.cpp +++ b/src/libs/utils/scopedtimer.cpp @@ -3,7 +3,6 @@ #include "scopedtimer.h" -#include #include #include @@ -15,25 +14,31 @@ static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateW using namespace std::chrono; -class ScopedTimerPrivate -{ -public: - const char *m_fileName = nullptr; - const int m_line = 0; - std::atomic *m_cumulative = nullptr; - const time_point m_start = system_clock::now(); -}; - static const char s_scoped[] = "SCOPED TIMER"; static const char s_scopedCumulative[] = "STATIC SCOPED TIMER"; -ScopedTimer::ScopedTimer(const char *fileName, int line, std::atomic *cumulative) - : d(new ScopedTimerPrivate{fileName, line, cumulative}) +class ScopedTimerPrivate { - if (d->m_cumulative) +public: + QString header() const { + const char *scopedTimerType = m_data.m_cumulative ? s_scopedCumulative : s_scoped; + const QString prefix = QLatin1String(scopedTimerType) + " [" + currentTime() + "] "; + const QString infix = m_data.m_message.isEmpty() + ? QLatin1String(m_data.m_fileName) + ':' + QString::number(m_data.m_line) + : m_data.m_message; + return prefix + infix + ' '; + } + + const ScopedTimerData m_data; + const time_point m_start = system_clock::now(); +}; + +ScopedTimer::ScopedTimer(const ScopedTimerData &data) + : d(new ScopedTimerPrivate{data}) +{ + if (d->m_data.m_cumulative) return; - qDebug().noquote().nospace() << s_scoped << " [" << currentTime() << "] in " << d->m_fileName - << ':' << d->m_line << " started"; + qDebug().noquote().nospace() << d->header() << "started"; } static int64_t toMs(int64_t ns) { return ns / 1000000; } @@ -42,8 +47,8 @@ ScopedTimer::~ScopedTimer() { const auto elapsed = duration_cast(system_clock::now() - d->m_start); QString suffix; - if (d->m_cumulative) { - const int64_t nsOld = d->m_cumulative->fetch_add(elapsed.count()); + if (d->m_data.m_cumulative) { + const int64_t nsOld = d->m_data.m_cumulative->fetch_add(elapsed.count()); const int64_t msOld = toMs(nsOld); const int64_t nsNew = nsOld + elapsed.count(); const int64_t msNew = toMs(nsNew); @@ -52,13 +57,11 @@ ScopedTimer::~ScopedTimer() if (nsOld != 0 && msOld / 10 == msNew / 10) return; - suffix = " cumulative timeout: " + QString::number(msNew) + "ms"; + suffix = "cumulative timeout: " + QString::number(msNew) + "ms"; } else { - suffix = " stopped with timeout: " + QString::number(toMs(elapsed.count())) + "ms"; + suffix = "stopped with timeout: " + QString::number(toMs(elapsed.count())) + "ms"; } - const char *header = d->m_cumulative ? s_scopedCumulative : s_scoped; - qDebug().noquote().nospace() << header << " [" << currentTime() << "] in " << d->m_fileName - << ':' << d->m_line << suffix; + qDebug().noquote().nospace() << d->header() << suffix; } } // namespace Utils diff --git a/src/libs/utils/scopedtimer.h b/src/libs/utils/scopedtimer.h index e6ec42e6f44..d66ef158419 100644 --- a/src/libs/utils/scopedtimer.h +++ b/src/libs/utils/scopedtimer.h @@ -5,6 +5,8 @@ #include "utils_global.h" +#include + #include #include @@ -12,10 +14,19 @@ namespace Utils { class ScopedTimerPrivate; +class QTCREATOR_UTILS_EXPORT ScopedTimerData +{ +public: + QString m_message; + const char *m_fileName = nullptr; + int m_line = 0; + std::atomic *m_cumulative = nullptr; +}; + class QTCREATOR_UTILS_EXPORT ScopedTimer { public: - ScopedTimer(const char *fileName, int line, std::atomic *cumulative = nullptr); + ScopedTimer(const ScopedTimerData &data); ~ScopedTimer(); private: @@ -24,15 +35,18 @@ private: } // Utils +// The "message" argument of QTC_SCOPED_TIMER() and QTC_STATIC_SCOPED_TIMER() macros is optional. +// When provided, it should evaluate to QString. + #define QTC_CONCAT_HELPER(x, y) x ## y #define QTC_CONCAT(x, y) QTC_CONCAT_HELPER(x, y) -#define QTC_SCOPED_TIMER() ::Utils::ScopedTimer QTC_CONCAT(_qtc_scoped_timer_, __LINE__)\ -(__FILE__, __LINE__) +#define QTC_SCOPED_TIMER(message) ::Utils::ScopedTimer QTC_CONCAT(_qtc_scoped_timer_, __LINE__)\ +({{message}, __FILE__, __LINE__}) // The macro below expands as follows (in one line): // static std::atomic _qtc_static_scoped_timer___LINE__ = 0; // ScopedTimer _qtc_scoped_timer___LINE__(__FILE__, __LINE__, &_qtc_static_scoped_timer___LINE__) -#define QTC_STATIC_SCOPED_TIMER() static std::atomic \ +#define QTC_STATIC_SCOPED_TIMER(message) static std::atomic \ QTC_CONCAT(_qtc_static_scoped_timer_, __LINE__) = 0; \ ::Utils::ScopedTimer QTC_CONCAT(_qtc_scoped_timer_, __LINE__)\ -(__FILE__, __LINE__, &QTC_CONCAT(_qtc_static_scoped_timer_, __LINE__)) +({{message}, __FILE__, __LINE__, &QTC_CONCAT(_qtc_static_scoped_timer_, __LINE__)}) From aa5ddaf4122cc95b7d475fd1ab3d899ef3c0c062 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 17 May 2023 13:45:56 +0200 Subject: [PATCH 1120/1447] ClangCodeModel: Let user decide how to do the header/source switch While clangd's AST matching can find source files at any location, it also has a number of annoying bugs that break the functionality for some users. This patch brings back the previous "try built-in first" logic, but also lets users choose their preferred backend. Task-number: QTCREATORBUG-29175 Change-Id: I6b854ed05652e6468509e5748a83a8f9bf76fc20 Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- .../clangmodelmanagersupport.cpp | 22 ++++++++++++--- .../cppeditor/cppcodemodelsettings.cpp | 16 +++++++++++ src/plugins/cppeditor/cppcodemodelsettings.h | 5 ++++ .../cppeditor/cppcodemodelsettingspage.cpp | 27 +++++++++++++++++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 1dd66db3cda..8aea72ce0e1 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -352,10 +352,24 @@ void ClangModelManagerSupport::findUsages(const CursorInEditor &cursor) const void ClangModelManagerSupport::switchHeaderSource(const FilePath &filePath, bool inNextSplit) { - if (ClangdClient * const client = clientForFile(filePath)) - client->switchHeaderSource(filePath, inNextSplit); - else - CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin); + if (ClangdClient * const client = clientForFile(filePath)) { + switch (ClangdProjectSettings(client->project()).settings().headerSourceSwitchMode) { + case ClangdSettings::HeaderSourceSwitchMode::BuiltinOnly: + CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin); + return; + case ClangdSettings::HeaderSourceSwitchMode::ClangdOnly: + client->switchHeaderSource(filePath, inNextSplit); + return; + case ClangdSettings::HeaderSourceSwitchMode::Both: + const FilePath otherFile = correspondingHeaderOrSource(filePath); + if (!otherFile.isEmpty()) + openEditor(otherFile, inNextSplit); + else + client->switchHeaderSource(filePath, inNextSplit); + return; + } + } + CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin); } void ClangModelManagerSupport::checkUnused(const Link &link, SearchResult *search, diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 5919a97b84c..2f4fdffab2d 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -64,6 +64,9 @@ static QString useClangdKey() { return QLatin1String("UseClangdV7"); } static QString clangdPathKey() { return QLatin1String("ClangdPath"); } static QString clangdIndexingKey() { return QLatin1String("ClangdIndexing"); } static QString clangdIndexingPriorityKey() { return QLatin1String("ClangdIndexingPriority"); } +static QString clangdHeaderSourceSwitchModeKey() { + return QLatin1String("ClangdHeaderSourceSwitchMode"); +} static QString clangdHeaderInsertionKey() { return QLatin1String("ClangdHeaderInsertion"); } static QString clangdThreadLimitKey() { return QLatin1String("ClangdThreadLimit"); } static QString clangdDocumentThresholdKey() { return QLatin1String("ClangdDocumentThreshold"); } @@ -229,6 +232,16 @@ QString ClangdSettings::priorityToDisplayString(const IndexingPriority &priority return {}; } +QString ClangdSettings::headerSourceSwitchModeToDisplayString(HeaderSourceSwitchMode mode) +{ + switch (mode) { + case HeaderSourceSwitchMode::BuiltinOnly: return Tr::tr("Use Built-in Only"); + case HeaderSourceSwitchMode::ClangdOnly: return Tr::tr("Use Clangd Only"); + case HeaderSourceSwitchMode::Both: return Tr::tr("Try Both"); + } + return {}; +} + ClangdSettings &ClangdSettings::instance() { static ClangdSettings settings; @@ -528,6 +541,7 @@ QVariantMap ClangdSettings::Data::toMap() const : QString()); map.insert(clangdIndexingKey(), indexingPriority != IndexingPriority::Off); map.insert(clangdIndexingPriorityKey(), int(indexingPriority)); + map.insert(clangdHeaderSourceSwitchModeKey(), int(headerSourceSwitchMode)); map.insert(clangdHeaderInsertionKey(), autoIncludeHeaders); map.insert(clangdThreadLimitKey(), workerThreadLimit); map.insert(clangdDocumentThresholdKey(), documentUpdateThreshold); @@ -549,6 +563,8 @@ void ClangdSettings::Data::fromMap(const QVariantMap &map) const auto it = map.find(clangdIndexingKey()); if (it != map.end() && !it->toBool()) indexingPriority = IndexingPriority::Off; + headerSourceSwitchMode = HeaderSourceSwitchMode(map.value(clangdHeaderSourceSwitchModeKey(), + int(headerSourceSwitchMode)).toInt()); autoIncludeHeaders = map.value(clangdHeaderInsertionKey(), false).toBool(); workerThreadLimit = map.value(clangdThreadLimitKey(), 0).toInt(); documentUpdateThreshold = map.value(clangdDocumentThresholdKey(), 500).toInt(); diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h index 7bfdc2e85e8..c22fb88faa5 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.h +++ b/src/plugins/cppeditor/cppcodemodelsettings.h @@ -84,9 +84,11 @@ class CPPEDITOR_EXPORT ClangdSettings : public QObject Q_OBJECT public: enum class IndexingPriority { Off, Background, Normal, Low, }; + enum class HeaderSourceSwitchMode { BuiltinOnly, ClangdOnly, Both }; static QString priorityToString(const IndexingPriority &priority); static QString priorityToDisplayString(const IndexingPriority &priority); + static QString headerSourceSwitchModeToDisplayString(HeaderSourceSwitchMode mode); class CPPEDITOR_EXPORT Data { @@ -103,6 +105,7 @@ public: && s1.diagnosticConfigId == s2.diagnosticConfigId && s1.workerThreadLimit == s2.workerThreadLimit && s1.indexingPriority == s2.indexingPriority + && s1.headerSourceSwitchMode == s2.headerSourceSwitchMode && s1.autoIncludeHeaders == s2.autoIncludeHeaders && s1.documentUpdateThreshold == s2.documentUpdateThreshold && s1.sizeThresholdEnabled == s2.sizeThresholdEnabled @@ -123,6 +126,7 @@ public: qint64 sizeThresholdInKb = 1024; bool useClangd = true; IndexingPriority indexingPriority = IndexingPriority::Low; + HeaderSourceSwitchMode headerSourceSwitchMode = HeaderSourceSwitchMode::Both; bool autoIncludeHeaders = false; bool sizeThresholdEnabled = false; bool haveCheckedHardwareReqirements = false; @@ -143,6 +147,7 @@ public: static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs); Utils::FilePath clangdFilePath() const; IndexingPriority indexingPriority() const { return m_data.indexingPriority; } + HeaderSourceSwitchMode headerSourceSwitchMode() const { return m_data.headerSourceSwitchMode; } bool autoIncludeHeaders() const { return m_data.autoIncludeHeaders; } int workerThreadLimit() const { return m_data.workerThreadLimit; } int documentUpdateThreshold() const { return m_data.documentUpdateThreshold; } diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 00224f5d90b..88f5bf0de8b 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -192,6 +192,7 @@ class ClangdSettingsWidget::Private public: QCheckBox useClangdCheckBox; QComboBox indexingComboBox; + QComboBox headerSourceSwitchComboBox; QCheckBox autoIncludeHeadersCheckBox; QCheckBox sizeThresholdCheckBox; QSpinBox threadLimitSpinBox; @@ -220,6 +221,12 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD "cores unused.

" "

Normal Priority: Reduced priority compared to interactive work.

" "Low Priority: Same priority as other clangd work."); + const QString headerSourceSwitchToolTip = Tr::tr( + "

Which C/C++ backend to use when switching between header and source file." + "

The clangd implementation has more capabilities, but also has some bugs not present " + "in the built-in variant." + "

When \"Try Both\" is selected, clangd will be employed only if the built-in variant " + "does not find anything."); const QString workerThreadsToolTip = Tr::tr( "Number of worker threads used by clangd. Background indexing also uses this many " "worker threads."); @@ -249,6 +256,15 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD d->indexingComboBox.setCurrentIndex(d->indexingComboBox.count() - 1); } d->indexingComboBox.setToolTip(indexingToolTip); + using SwitchMode = ClangdSettings::HeaderSourceSwitchMode; + for (SwitchMode mode : {SwitchMode::BuiltinOnly, SwitchMode::ClangdOnly, SwitchMode::Both}) { + d->headerSourceSwitchComboBox.addItem( + ClangdSettings::headerSourceSwitchModeToDisplayString(mode), int(mode)); + if (mode == settings.headerSourceSwitchMode()) + d->headerSourceSwitchComboBox.setCurrentIndex( + d->headerSourceSwitchComboBox.count() - 1); + } + d->headerSourceSwitchComboBox.setToolTip(headerSourceSwitchToolTip); d->autoIncludeHeadersCheckBox.setText(Tr::tr("Insert header files on completion")); d->autoIncludeHeadersCheckBox.setChecked(settings.autoIncludeHeaders()); d->autoIncludeHeadersCheckBox.setToolTip(autoIncludeToolTip); @@ -294,6 +310,13 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD indexingPriorityLabel->setToolTip(indexingToolTip); formLayout->addRow(indexingPriorityLabel, indexingPriorityLayout); + const auto headerSourceSwitchLayout = new QHBoxLayout; + headerSourceSwitchLayout->addWidget(&d->headerSourceSwitchComboBox); + headerSourceSwitchLayout->addStretch(1); + const auto headerSourceSwitchLabel = new QLabel(Tr::tr("Header/source switch mode:")); + headerSourceSwitchLabel->setToolTip(headerSourceSwitchToolTip); + formLayout->addRow(headerSourceSwitchLabel, headerSourceSwitchLayout); + const auto threadLimitLayout = new QHBoxLayout; threadLimitLayout->addWidget(&d->threadLimitSpinBox); threadLimitLayout->addStretch(1); @@ -449,6 +472,8 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD this, &ClangdSettingsWidget::settingsDataChanged); connect(&d->indexingComboBox, &QComboBox::currentIndexChanged, this, &ClangdSettingsWidget::settingsDataChanged); + connect(&d->headerSourceSwitchComboBox, &QComboBox::currentIndexChanged, + this, &ClangdSettingsWidget::settingsDataChanged); connect(&d->autoIncludeHeadersCheckBox, &QCheckBox::toggled, this, &ClangdSettingsWidget::settingsDataChanged); connect(&d->threadLimitSpinBox, &QSpinBox::valueChanged, @@ -479,6 +504,8 @@ ClangdSettings::Data ClangdSettingsWidget::settingsData() const data.executableFilePath = d->clangdChooser.filePath(); data.indexingPriority = ClangdSettings::IndexingPriority( d->indexingComboBox.currentData().toInt()); + data.headerSourceSwitchMode = ClangdSettings::HeaderSourceSwitchMode( + d->headerSourceSwitchComboBox.currentData().toInt()); data.autoIncludeHeaders = d->autoIncludeHeadersCheckBox.isChecked(); data.workerThreadLimit = d->threadLimitSpinBox.value(); data.documentUpdateThreshold = d->documentUpdateThreshold.value(); From 07b2a30dfe9a4410e658fb816a9105050a52c429 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 10 May 2023 13:01:34 +0200 Subject: [PATCH 1121/1447] Qt Quick Application Wizard: Unify Qt version combobox entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "compat" variant, which was around for a long time, had a Qt version combobox with entries following the "Qt x.yz" scheme. This change adds the Qt prefix also to the combobox of the new wizard. Fixes: QTCREATORBUG-29126 Change-Id: I4cd59f09248ba487077c2dcdd0828222311dd9a7 Reviewed-by: Robert Löhning --- .../wizards/projects/qtquickapplication/wizard.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index 8b4165fa35c..dbfe93bbca1 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -81,7 +81,11 @@ "type": "ComboBox", "data": { - "items": [ "6.2", "6.4", "6.5" ], + "items": [ + { "trKey": "Qt 6.2", "value": "6.2" }, + { "trKey": "Qt 6.4", "value": "6.4" }, + { "trKey": "Qt 6.5", "value": "6.5" } + ], "index": 1 } } From caad8074de37db4eccfa9daf392cf1d7f70ff70d Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 17 May 2023 17:24:28 +0200 Subject: [PATCH 1122/1447] WebAssembly: Prevent null pointer access The detector.device can be nullptr Amends: cacc4aeede245ddc92a196e99fb1e66458d4403c Change-Id: I5b9b6aa722c8e6e8a96d05cdf2f1b214735db858 Reviewed-by: hjk --- src/plugins/webassembly/webassemblytoolchain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/webassembly/webassemblytoolchain.cpp b/src/plugins/webassembly/webassemblytoolchain.cpp index 4ee3eff5916..c413f27566c 100644 --- a/src/plugins/webassembly/webassemblytoolchain.cpp +++ b/src/plugins/webassembly/webassemblytoolchain.cpp @@ -96,7 +96,8 @@ static Toolchains doAutoDetect(const ToolchainDetector &detector) if (!WebAssemblyEmSdk::isValid(sdk)) return {}; - if (detector.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { + if (detector.device + && detector.device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { // Only detect toolchains from the emsdk installation device const FilePath deviceRoot = detector.device->rootPath(); if (deviceRoot.host() != sdk.host()) From 9c78ef983a1203515a7552784a119f1ba3df4a71 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 15 May 2023 10:52:45 +0200 Subject: [PATCH 1123/1447] TaskTree: Add runBlocking() helpers To be used in non-main threads and in autotests. Change-Id: If37be854f65c9cfe94eb781a28dc8db4365809e1 Reviewed-by: Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.cpp | 51 +++++++++++++++++++++++++ src/libs/solutions/tasking/tasktree.h | 11 ++++++ 2 files changed, 62 insertions(+) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 4a66d7f674b..58235cd814f 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -3,7 +3,10 @@ #include "tasktree.h" +#include +#include #include +#include namespace Tasking { @@ -1444,6 +1447,54 @@ bool TaskTree::isRunning() const return d->m_root && d->m_root->isRunning(); } +bool TaskTree::runBlocking(const QFuture &future, int timeoutMs) +{ + if (isRunning() || future.isCanceled()) + return false; + + bool ok = false; + QEventLoop loop; + + const auto finalize = [&loop, &ok](bool success) { + ok = success; + // Otherwise, the tasks from inside the running tree that were deleteLater() + // will be leaked. Refer to the QObject::deleteLater() docs. + QMetaObject::invokeMethod(&loop, [&loop] { loop.quit(); }, Qt::QueuedConnection); + }; + + QFutureWatcher watcher; + connect(&watcher, &QFutureWatcherBase::canceled, this, &TaskTree::stop); + watcher.setFuture(future); + + connect(this, &TaskTree::done, &loop, [finalize] { finalize(true); }); + connect(this, &TaskTree::errorOccurred, &loop, [finalize] { finalize(false); }); + start(); + if (!isRunning()) + return ok; + + QTimer timer; + if (timeoutMs) { + timer.setSingleShot(true); + timer.setInterval(timeoutMs); + connect(&timer, &QTimer::timeout, this, &TaskTree::stop); + timer.start(); + } + + loop.exec(QEventLoop::ExcludeUserInputEvents); + if (!ok) { + auto nonConstFuture = future; + nonConstFuture.cancel(); + } + return ok; +} + +bool TaskTree::runBlocking(int timeoutMs) +{ + QPromise dummy; + dummy.start(); + return runBlocking(dummy.future(), timeoutMs); +} + int TaskTree::taskCount() const { return d->m_root ? d->m_root->taskCount() : 0; diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index bbee1a3fe8c..462eb5bd2eb 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -9,6 +9,11 @@ #include #include +QT_BEGIN_NAMESPACE +template +class QFuture; +QT_END_NAMESPACE + namespace Tasking { class ExecutionContextActivator; @@ -369,6 +374,12 @@ public: void stop(); bool isRunning() const; + // Helper methods. They execute a local event loop with ExcludeUserInputEvents. + // The passed future is used for listening to the cancel event. + // Don't use it in main thread. To be used in non-main threads or in auto tests. + bool runBlocking(const QFuture &future, int timeoutMs = 0); + bool runBlocking(int timeoutMs = 0); + int taskCount() const; int progressMaximum() const { return taskCount(); } int progressValue() const; // all finished / skipped / stopped tasks, groups itself excluded From 686a40d199864c1b2e29defc1ba67fd73f5aaaf0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 12 May 2023 21:38:33 +0200 Subject: [PATCH 1124/1447] SubDirFileIterator: Add manual performance test Compare the total time spent on iterating a big file tree with 3 different time iterators: - Utils::SubDirFileIterator - manually written iterator using QDir::entryInfoList() - QDirIterator The iterator run through about one million files (including about ~100K directories). The more files above this number to be iterated over, the bigger the relative time difference of SubDirFileIterator compared to other iterators. The number of generated files depends on the running machine's core number. In my case: Number of cores: 24 Number of generated files: 898753 Number of generated directories: 112345 Time spent on generating file tree: ~2 seconds Time spent on iterating using SubDirIterator: ~80 seconds Time spent on iterating using manual iterator: ~8 seconds Time spent on iterating using QDirIterator: ~4 seconds Time spent on removing generated file tree: ~2 seconds Task-number: QTCREATORBUG-28892 Change-Id: I94d7cf0169a470820dc27f39c9cdb4150eea51c1 Reviewed-by: hjk Reviewed-by: Qt CI Bot Reviewed-by: --- tests/manual/CMakeLists.txt | 1 + tests/manual/manual.qbs | 1 + .../manual/subdirfileiterator/CMakeLists.txt | 10 + .../subdirfileiterator/subdirfileiterator.qbs | 22 ++ .../tst_subdirfileiterator.cpp | 257 ++++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 tests/manual/subdirfileiterator/CMakeLists.txt create mode 100644 tests/manual/subdirfileiterator/subdirfileiterator.qbs create mode 100644 tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt index c171a70deb6..fb0b611f4f7 100644 --- a/tests/manual/CMakeLists.txt +++ b/tests/manual/CMakeLists.txt @@ -16,5 +16,6 @@ add_subdirectory(proparser) # add_subdirectory(qt4projectmanager) # add_subdirectory(search) add_subdirectory(shootout) +add_subdirectory(subdirfileiterator) add_subdirectory(tasktree) add_subdirectory(widgets) diff --git a/tests/manual/manual.qbs b/tests/manual/manual.qbs index e3ebf0707a3..8e157a9216b 100644 --- a/tests/manual/manual.qbs +++ b/tests/manual/manual.qbs @@ -13,6 +13,7 @@ Project { "pluginview/pluginview.qbs", "proparser/testreader.qbs", "shootout/shootout.qbs", + "subdirfileiterator/subdirfileiterator.qbs", "tasktree/tasktree.qbs", "widgets/widgets.qbs", ] diff --git a/tests/manual/subdirfileiterator/CMakeLists.txt b/tests/manual/subdirfileiterator/CMakeLists.txt new file mode 100644 index 00000000000..9613e197b77 --- /dev/null +++ b/tests/manual/subdirfileiterator/CMakeLists.txt @@ -0,0 +1,10 @@ +file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") +file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}") + +add_qtc_test(tst_manual_subdirfileiterator + MANUALTEST + DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\"" + DEPENDS Utils app_version + SOURCES + tst_subdirfileiterator.cpp +) diff --git a/tests/manual/subdirfileiterator/subdirfileiterator.qbs b/tests/manual/subdirfileiterator/subdirfileiterator.qbs new file mode 100644 index 00000000000..852fb9b545b --- /dev/null +++ b/tests/manual/subdirfileiterator/subdirfileiterator.qbs @@ -0,0 +1,22 @@ +import qbs.FileInfo + +QtcManualtest { + name: "Manual SubDirFileIterator test" + type: ["application"] + + Depends { name: "Utils" } + Depends { name: "app_version_header" } + + files: [ + "tst_subdirfileiterator.cpp", + ] + + cpp.defines: { + var defines = base; + var absLibExecPath = FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, + qtc.ide_libexec_path); + var relLibExecPath = FileInfo.relativePath(destinationDirectory, absLibExecPath); + defines.push('TEST_RELATIVE_LIBEXEC_PATH="' + relLibExecPath + '"'); + return defines; + } +} diff --git a/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp b/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp new file mode 100644 index 00000000000..4093030a719 --- /dev/null +++ b/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp @@ -0,0 +1,257 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace Tasking; +using namespace Utils; + +static const int s_subDirsCount = 8; +static const int s_subFilesCount = 8; +static const int s_treeDepth = 4; + +static const QDir::Filters s_filters = QDir::Dirs | QDir::Files | QDir::Hidden + | QDir::NoDotAndDotDot; + +static const char s_dirPrefix[] = "dir_"; +static const char s_filePrefix[] = "file_"; + +static int expectedDirsCountHelper(int depth) +{ + if (depth == 1) + return s_subDirsCount + 1; // +1 -> dir itself + return expectedDirsCountHelper(depth - 1) * s_subDirsCount + 1; // +1 -> dir itself +} + +static int expectedDirsCount(int tasksCount) +{ + return expectedDirsCountHelper(s_treeDepth) * tasksCount + 1; // +1 -> root temp dir +} + +static int expectedFilesCountHelper(int depth) +{ + if (depth == 0) + return s_subFilesCount; + return expectedFilesCountHelper(depth - 1) * s_subDirsCount + s_subFilesCount; +} + +static int expectedFilesCount(int tasksCount) +{ + return expectedFilesCountHelper(s_treeDepth) * tasksCount + 1; // +1 -> fileTemplate.txt +} + +static void generate(QPromise &promise, const QString &parentPath, + const QString &templateFile, int depth) +{ + const QDir parentDir(parentPath); + for (int i = 0; i < s_subFilesCount; ++i) + QFile::copy(templateFile, parentDir.filePath(QString("%1%2").arg(s_filePrefix).arg(i))); + + if (depth == 0) + return; + + if (promise.isCanceled()) + return; + + const QString templateDir("dirTemplate"); + if (!parentDir.mkdir(templateDir)) { + promise.future().cancel(); + return; + } + + const QString templateDirPath = parentDir.filePath(templateDir); + generate(promise, templateDirPath, templateFile, depth - 1); + + if (promise.isCanceled()) + return; + + for (int i = 0; i < s_subDirsCount - 1; ++i) { + const QString dirName = QString("%1%2").arg(s_dirPrefix).arg(i); + const FilePath source = FilePath::fromString(templateDirPath); + const FilePath destination = FilePath::fromString(parentDir.filePath(dirName)); + if (!source.copyRecursively(destination)) { + promise.future().cancel(); + return; + } + } +} + +class tst_SubDirFileIterator : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase() + { + TemporaryDirectory::setMasterTemporaryDirectory( + QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); + + const QString libExecPath(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); + LauncherInterface::setPathToLauncher(libExecPath); + + qDebug() << "This manual test compares the performance of the SubDirFileIterator with " + "a manually written iterator using QDir::entryInfoList()."; + QTC_SCOPED_TIMER("GENERATING TEMPORARY FILES TREE"); + const int tasksCount = QThread::idealThreadCount(); + m_filesCount = expectedFilesCount(tasksCount); + m_dirsCount = expectedDirsCount(tasksCount); + m_tempDir.reset(new QTemporaryDir); + qDebug() << "Generating on" << tasksCount << "cores..."; + qDebug() << "Generating" << m_filesCount << "files..."; + qDebug() << "Generating" << m_dirsCount << "dirs..."; + qDebug() << "Generating inside" << m_tempDir->path() << "dir..."; + const QString templateFile = m_tempDir->filePath("fileTemplate.txt"); + { + QFile file(templateFile); + QVERIFY(file.open(QIODevice::ReadWrite)); + file.write("X"); + } + + // Parallelize tree generation + const QDir parentDir(m_tempDir->path()); + const auto onSetup = [](const QString &parentPath, const QString &templateFile) { + return [parentPath, templateFile](Async &async) { + async.setConcurrentCallData(generate, parentPath, templateFile, s_treeDepth); + }; + }; + QList tasks {parallel}; + for (int i = 0; i < tasksCount; ++i) { + const QString dirName = QString("%1%2").arg(s_dirPrefix).arg(i); + QVERIFY(parentDir.mkdir(dirName)); + tasks.append(AsyncTask(onSetup(parentDir.filePath(dirName), templateFile))); + } + + TaskTree taskTree(tasks); + QVERIFY(taskTree.runBlocking()); + } + + void cleanupTestCase() + { + QTC_SCOPED_TIMER("CLEANING UP"); + + // Parallelize tree removal + const auto removeTree = [](const QString &parentPath) { + FilePath::fromString(parentPath).removeRecursively(); + }; + + const QDir parentDir(m_tempDir->path()); + const auto onSetup = [removeTree](const QString &parentPath) { + return [parentPath, removeTree](Async &async) { + async.setConcurrentCallData(removeTree, parentPath); + }; + }; + QList tasks {parallel}; + const int tasksCount = QThread::idealThreadCount(); + for (int i = 0; i < tasksCount; ++i) { + const QString dirName = QString("%1%2").arg(s_dirPrefix).arg(i); + tasks.append(AsyncTask(onSetup(parentDir.filePath(dirName)))); + } + + TaskTree taskTree(tasks); + QVERIFY(taskTree.runBlocking()); + + m_tempDir.reset(); + Singleton::deleteAll(); + } + + void testSubDirFileIterator() + { + QTC_SCOPED_TIMER("ITERATING with SubDirFileIterator"); + int filesCount = 0; + { + const FilePath root(FilePath::fromString(m_tempDir->path())); + SubDirFileIterator it({root}, {}, {}); + auto i = it.begin(); + const auto e = it.end(); + while (i != e) { + ++filesCount; + ++i; + if (filesCount % 100000 == 0) + qDebug() << filesCount << '/' << m_filesCount << "files visited so far..."; + } + } + qDebug() << "Visited" << filesCount << "files."; + } + + void testManualIterator() + { + QTC_SCOPED_TIMER("ITERATING with manual iterator"); + int filesCount = 0; + int dirsCount = 0; + { + const QDir root(m_tempDir->path()); + std::unordered_set visitedFiles; + std::unordered_set visitedDirs; + visitedDirs.emplace(root.absolutePath()); + QFileInfoList workingList = root.entryInfoList(s_filters); + ++dirsCount; // for root itself + while (!workingList.isEmpty()) { + const QFileInfo fi = workingList.takeLast(); + const QString absoluteFilePath = fi.absoluteFilePath(); + if (fi.isDir()) { + if (!visitedDirs.emplace(absoluteFilePath).second) + continue; + if (fi.isSymbolicLink() && !visitedDirs.emplace(fi.symLinkTarget()).second) + continue; + ++dirsCount; + workingList.append(QDir(absoluteFilePath).entryInfoList(s_filters)); + } else { + if (!visitedFiles.emplace(absoluteFilePath).second) + continue; + if (fi.isSymbolicLink() && !visitedFiles.emplace(fi.symLinkTarget()).second) + continue; + ++filesCount; + if (filesCount % 100000 == 0) + qDebug() << filesCount << '/' << m_filesCount << "files visited so far..."; + } + } + } + qDebug() << "Visited" << filesCount << "files and" << dirsCount << "directories."; + } + + void testQDirIterator() + { + QTC_SCOPED_TIMER("ITERATING with QDirIterator"); + int filesCount = 0; + int dirsCount = 0; + { + ++dirsCount; // for root itself + QDirIterator it(m_tempDir->path(), s_filters, QDirIterator::Subdirectories + | QDirIterator::FollowSymlinks); + while (it.hasNext()) { + const QFileInfo fi = it.nextFileInfo(); + if (fi.isDir()) { + ++dirsCount; + } else { + ++filesCount; + if (filesCount % 100000 == 0) + qDebug() << filesCount << '/' << m_filesCount << "files visited so far..."; + } + } + } + qDebug() << "Visited" << filesCount << "files and" << dirsCount << "directories."; + } + +private: + int m_dirsCount = 0; + int m_filesCount = 0; + std::unique_ptr m_tempDir; +}; + +QTEST_GUILESS_MAIN(tst_SubDirFileIterator) + +#include "tst_subdirfileiterator.moc" From 2b174a763faf458a347504896a75db5f5440e7a7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 15 May 2023 17:54:23 +0200 Subject: [PATCH 1125/1447] FileStreamer: Reuse TaskTree::runBlocking() Reuse it also in FileSystemAccessTest. Change-Id: I6ce1c926bd5d3a617b8badb0905e7b2fd58b4745 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot Reviewed-by: --- src/libs/utils/filestreamer.cpp | 33 ++------------- .../remotelinux/filesystemaccess_test.cpp | 40 ++----------------- 2 files changed, 8 insertions(+), 65 deletions(-) diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 6d4a7683369..55e984c2fbf 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -333,8 +333,8 @@ static Group interDeviceTransferTask(const FilePath &source, const FilePath &des storage->writer, &FileStreamWriter::write); }; const auto finalizeReader = [=](const FileStreamReader &) { - QTC_CHECK(storage->writer != nullptr); - storage->writer->closeWriteChannel(); + if (storage->writer) // writer may be deleted before the reader on TaskTree::stop(). + storage->writer->closeWriteChannel(); }; const auto setupWriter = [=](FileStreamWriter &writer) { writer.setFilePath(destination); @@ -370,33 +370,8 @@ static void transfer(QPromise &promise, const FilePath &source, const File if (promise.isCanceled()) return; - std::unique_ptr taskTree(new TaskTree(transferTask(source, destination))); - - QEventLoop eventLoop; - bool finalized = false; - const auto finalize = [loop = &eventLoop, &taskTree, &finalized](int exitCode) { - if (finalized) // finalize only once - return; - finalized = true; - // Give the tree a chance to delete later all tasks that have finished and caused - // emission of tree's done or errorOccurred signal. - // TODO: maybe these signals should be sent queued already? - QMetaObject::invokeMethod(loop, [loop, &taskTree, exitCode] { - taskTree.reset(); - loop->exit(exitCode); - }, Qt::QueuedConnection); - }; - QTimer timer; - timer.setInterval(50); - QObject::connect(&timer, &QTimer::timeout, [&promise, finalize] { - if (promise.isCanceled()) - finalize(2); - }); - QObject::connect(taskTree.get(), &TaskTree::done, &eventLoop, [=] { finalize(0); }); - QObject::connect(taskTree.get(), &TaskTree::errorOccurred, &eventLoop, [=] { finalize(1); }); - taskTree->start(); - timer.start(); - if (eventLoop.exec()) + TaskTree taskTree(transferTask(source, destination)); + if (!taskTree.runBlocking(promise.future())) promise.future().cancel(); } diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index 00fdd82f367..dda6e417615 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -390,8 +391,7 @@ void FileSystemAccessTest::testFileStreamer_data() void FileSystemAccessTest::testFileStreamer() { - QElapsedTimer timer; - timer.start(); + QTC_SCOPED_TIMER("testFileStreamer"); QFETCH(QString, fileName); QFETCH(QByteArray, data); @@ -503,35 +503,8 @@ void FileSystemAccessTest::testFileStreamer() } }; - QEventLoop eventLoop; TaskTree taskTree(root); - int doneCount = 0; - int errorCount = 0; - connect(&taskTree, &TaskTree::done, this, [&doneCount, &eventLoop] { - ++doneCount; - eventLoop.quit(); - }); - connect(&taskTree, &TaskTree::errorOccurred, this, [&errorCount, &eventLoop] { - ++errorCount; - eventLoop.quit(); - }); - taskTree.start(); - QVERIFY(taskTree.isRunning()); - - QTimer timeoutTimer; - bool timedOut = false; - connect(&timeoutTimer, &QTimer::timeout, &eventLoop, [&eventLoop, &timedOut] { - timedOut = true; - eventLoop.quit(); - }); - timeoutTimer.setInterval(10000); - timeoutTimer.setSingleShot(true); - timeoutTimer.start(); - eventLoop.exec(); - QCOMPARE(timedOut, false); - QCOMPARE(taskTree.isRunning(), false); - QCOMPARE(doneCount, 1); - QCOMPARE(errorCount, 0); + QVERIFY(taskTree.runBlocking(10000)); QVERIFY(localData); QCOMPARE(*localData, data); @@ -546,8 +519,6 @@ void FileSystemAccessTest::testFileStreamer() QCOMPARE(*remoteLocalData, data); QVERIFY(remoteRemoteData); QCOMPARE(*remoteRemoteData, data); - - qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; } void FileSystemAccessTest::testFileStreamerManager_data() @@ -557,8 +528,7 @@ void FileSystemAccessTest::testFileStreamerManager_data() void FileSystemAccessTest::testFileStreamerManager() { - QElapsedTimer timer; - timer.start(); + QTC_SCOPED_TIMER("testFileStreamerManager"); QFETCH(QString, fileName); QFETCH(QByteArray, data); @@ -660,8 +630,6 @@ void FileSystemAccessTest::testFileStreamerManager() QCOMPARE(*remoteLocalData, data); QVERIFY(remoteRemoteData); QCOMPARE(*remoteRemoteData, data); - - qDebug() << "Elapsed time:" << timer.elapsed() << "ms."; } } // Internal From 6a8e8f5fbd5f1f466d4ae72ae368aeb81fcd2e69 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 16 May 2023 23:21:55 +0200 Subject: [PATCH 1126/1447] tst_Tasking: Reuse TaskTree:runBlocking() Get rid of the OnStart enum - that's checked indirectly through the runBlocking() call. Change-Id: I190de0f911c68195c31e722bcb1823b678cb0bd4 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Jarek Kobus --- tests/auto/solutions/tasking/tst_tasking.cpp | 172 ++++++------------- 1 file changed, 53 insertions(+), 119 deletions(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 9efba89bb2e..06bebf99f51 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -45,7 +45,6 @@ static const char s_taskIdProperty[] = "__taskId"; static FutureSynchronizer *s_futureSynchronizer = nullptr; -enum class OnStart { Running, NotRunning }; enum class OnDone { Success, Failure }; struct TestData { @@ -53,7 +52,6 @@ struct TestData { Group root; Log expectedLog; int taskCount = 0; - OnStart onStart = OnStart::Running; OnDone onDone = OnDone::Success; }; @@ -320,14 +318,10 @@ void tst_Tasking::testTree_data() }; const Log logDone {{0, Handler::GroupDone}}; const Log logError {{0, Handler::GroupError}}; - QTest::newRow("Empty") - << TestData{storage, root1, logDone, 0, OnStart::NotRunning, OnDone::Success}; - QTest::newRow("EmptyContinue") - << TestData{storage, root2, logDone, 0, OnStart::NotRunning, OnDone::Success}; - QTest::newRow("EmptyDone") - << TestData{storage, root3, logDone, 0, OnStart::NotRunning, OnDone::Success}; - QTest::newRow("EmptyError") - << TestData{storage, root4, logError, 0, OnStart::NotRunning, OnDone::Failure}; + QTest::newRow("Empty") << TestData{storage, root1, logDone, 0, OnDone::Success}; + QTest::newRow("EmptyContinue") << TestData{storage, root2, logDone, 0, OnDone::Success}; + QTest::newRow("EmptyDone") << TestData{storage, root3, logDone, 0, OnDone::Success}; + QTest::newRow("EmptyError") << TestData{storage, root4, logError, 0, OnDone::Failure}; } { @@ -337,8 +331,7 @@ void tst_Tasking::testTree_data() Test(setupDynamicTask(2, TaskAction::StopWithDone), logDone, logError) }; const Log log {{1, Handler::Setup}, {2, Handler::Setup}}; - QTest::newRow("DynamicTaskDone") - << TestData{storage, root, log, 2, OnStart::NotRunning, OnDone::Success}; + QTest::newRow("DynamicTaskDone") << TestData{storage, root, log, 2, OnDone::Success}; } { @@ -348,8 +341,7 @@ void tst_Tasking::testTree_data() Test(setupDynamicTask(2, TaskAction::StopWithError), logDone, logError) }; const Log log {{1, Handler::Setup}}; - QTest::newRow("DynamicTaskError") - << TestData{storage, root, log, 2, OnStart::NotRunning, OnDone::Failure}; + QTest::newRow("DynamicTaskError") << TestData{storage, root, log, 2, OnDone::Failure}; } { @@ -367,8 +359,7 @@ void tst_Tasking::testTree_data() {2, Handler::Done}, {3, Handler::Setup} }; - QTest::newRow("DynamicMixed") - << TestData{storage, root, log, 4, OnStart::Running, OnDone::Failure}; + QTest::newRow("DynamicMixed") << TestData{storage, root, log, 4, OnDone::Failure}; } { @@ -387,8 +378,7 @@ void tst_Tasking::testTree_data() {1, Handler::Error}, {2, Handler::Error} }; - QTest::newRow("DynamicParallel") - << TestData{storage, root, log, 4, OnStart::NotRunning, OnDone::Failure}; + QTest::newRow("DynamicParallel") << TestData{storage, root, log, 4, OnDone::Failure}; } { @@ -409,8 +399,7 @@ void tst_Tasking::testTree_data() {1, Handler::Error}, {2, Handler::Error} }; - QTest::newRow("DynamicParallelGroup") - << TestData{storage, root, log, 4, OnStart::NotRunning, OnDone::Failure}; + QTest::newRow("DynamicParallelGroup") << TestData{storage, root, log, 4, OnDone::Failure}; } { @@ -436,7 +425,7 @@ void tst_Tasking::testTree_data() {2, Handler::Error} }; QTest::newRow("DynamicParallelGroupSetup") - << TestData{storage, root, log, 4, OnStart::NotRunning, OnDone::Failure}; + << TestData{storage, root, log, 4, OnDone::Failure}; } { @@ -480,8 +469,7 @@ void tst_Tasking::testTree_data() {1, Handler::GroupDone}, {0, Handler::GroupDone} }; - QTest::newRow("Nested") - << TestData{storage, root, log, 1, OnStart::Running, OnDone::Success}; + QTest::newRow("Nested") << TestData{storage, root, log, 1, OnDone::Success}; } { @@ -511,8 +499,7 @@ void tst_Tasking::testTree_data() {0, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("Parallel") - << TestData{storage, root, log, 5, OnStart::Running, OnDone::Success}; + QTest::newRow("Parallel") << TestData{storage, root, log, 5, OnDone::Success}; } { @@ -568,12 +555,10 @@ void tst_Tasking::testTree_data() {5, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("Sequential") - << TestData{storage, root1, log, 5, OnStart::Running, OnDone::Success}; - QTest::newRow("SequentialEncapsulated") - << TestData{storage, root2, log, 5, OnStart::Running, OnDone::Success}; - QTest::newRow("SequentialSubTree") // We don't inspect subtrees, so taskCount is 3, not 5. - << TestData{storage, root3, log, 3, OnStart::Running, OnDone::Success}; + QTest::newRow("Sequential") << TestData{storage, root1, log, 5, OnDone::Success}; + QTest::newRow("SequentialEncapsulated") << TestData{storage, root2, log, 5, OnDone::Success}; + // We don't inspect subtrees, so taskCount is 3, not 5. + QTest::newRow("SequentialSubTree") << TestData{storage, root3, log, 3, OnDone::Success}; } { @@ -619,8 +604,7 @@ void tst_Tasking::testTree_data() {1, Handler::GroupDone}, {0, Handler::GroupDone} }; - QTest::newRow("SequentialNested") - << TestData{storage, root, log, 5, OnStart::Running, OnDone::Success}; + QTest::newRow("SequentialNested") << TestData{storage, root, log, 5, OnDone::Success}; } { @@ -643,8 +627,7 @@ void tst_Tasking::testTree_data() {3, Handler::Error}, {0, Handler::GroupError} }; - QTest::newRow("SequentialError") - << TestData{storage, root, log, 5, OnStart::Running, OnDone::Failure}; + QTest::newRow("SequentialError") << TestData{storage, root, log, 5, OnDone::Failure}; } { @@ -656,8 +639,7 @@ void tst_Tasking::testTree_data() {2, Handler::Error}, {0, Handler::GroupError} }; - QTest::newRow("StopOnError") - << TestData{storage, root, log, 3, OnStart::Running, OnDone::Failure}; + QTest::newRow("StopOnError") << TestData{storage, root, log, 3, OnDone::Failure}; } { @@ -671,8 +653,7 @@ void tst_Tasking::testTree_data() {3, Handler::Done}, {0, Handler::GroupError} }; - QTest::newRow("ContinueOnError") - << TestData{storage, root, log, 3, OnStart::Running, OnDone::Failure}; + QTest::newRow("ContinueOnError") << TestData{storage, root, log, 3, OnDone::Failure}; } { @@ -682,8 +663,7 @@ void tst_Tasking::testTree_data() {1, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("StopOnDone") - << TestData{storage, root, log, 3, OnStart::Running, OnDone::Success}; + QTest::newRow("StopOnDone") << TestData{storage, root, log, 3, OnDone::Success}; } { @@ -697,8 +677,7 @@ void tst_Tasking::testTree_data() {3, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("ContinueOnDone") - << TestData{storage, root, log, 3, OnStart::Running, OnDone::Success}; + QTest::newRow("ContinueOnDone") << TestData{storage, root, log, 3, OnDone::Success}; } { @@ -717,8 +696,7 @@ void tst_Tasking::testTree_data() {2, Handler::Error}, {0, Handler::GroupDone} }; - QTest::newRow("Optional") - << TestData{storage, root, log, 2, OnStart::Running, OnDone::Success}; + QTest::newRow("Optional") << TestData{storage, root, log, 2, OnDone::Success}; } { @@ -728,8 +706,7 @@ void tst_Tasking::testTree_data() {1, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("DynamicSetupDone") - << TestData{storage, root, log, 4, OnStart::Running, OnDone::Success}; + QTest::newRow("DynamicSetupDone") << TestData{storage, root, log, 4, OnDone::Success}; } { @@ -739,8 +716,7 @@ void tst_Tasking::testTree_data() {1, Handler::Done}, {0, Handler::GroupError} }; - QTest::newRow("DynamicSetupError") - << TestData{storage, root, log, 4, OnStart::Running, OnDone::Failure}; + QTest::newRow("DynamicSetupError") << TestData{storage, root, log, 4, OnDone::Failure}; } { @@ -756,8 +732,7 @@ void tst_Tasking::testTree_data() {4, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("DynamicSetupContinue") - << TestData{storage, root, log, 4, OnStart::Running, OnDone::Success}; + QTest::newRow("DynamicSetupContinue") << TestData{storage, root, log, 4, OnDone::Success}; } { @@ -791,8 +766,7 @@ void tst_Tasking::testTree_data() {4, Handler::GroupSetup}, {4, Handler::Setup} }; - QTest::newRow("NestedParallel") - << TestData{storage, root, log, 4, OnStart::Running, OnDone::Success}; + QTest::newRow("NestedParallel") << TestData{storage, root, log, 4, OnDone::Success}; } { @@ -832,8 +806,7 @@ void tst_Tasking::testTree_data() {5, Handler::GroupSetup}, {5, Handler::Setup} }; - QTest::newRow("NestedParallelDone") - << TestData{storage, root, log, 5, OnStart::Running, OnDone::Success}; + QTest::newRow("NestedParallelDone") << TestData{storage, root, log, 5, OnDone::Success}; } { @@ -936,11 +909,11 @@ void tst_Tasking::testTree_data() }; const Log longLog = shortLog + Log {{5, Handler::GroupSetup}, {5, Handler::Setup}}; QTest::newRow("NestedParallelError1") - << TestData{storage, root1, shortLog, 5, OnStart::Running, OnDone::Failure}; + << TestData{storage, root1, shortLog, 5, OnDone::Failure}; QTest::newRow("NestedParallelError2") - << TestData{storage, root2, shortLog, 5, OnStart::Running, OnDone::Failure}; + << TestData{storage, root2, shortLog, 5, OnDone::Failure}; QTest::newRow("NestedParallelError3") - << TestData{storage, root3, longLog, 5, OnStart::Running, OnDone::Failure}; + << TestData{storage, root3, longLog, 5, OnDone::Failure}; } { @@ -990,8 +963,7 @@ void tst_Tasking::testTree_data() {4, Handler::GroupSetup}, {4, Handler::Setup} }; - QTest::newRow("DeeplyNestedParallel") - << TestData{storage, root, log, 4, OnStart::Running, OnDone::Success}; + QTest::newRow("DeeplyNestedParallel") << TestData{storage, root, log, 4, OnDone::Success}; } { @@ -1037,7 +1009,7 @@ void tst_Tasking::testTree_data() {5, Handler::Setup} }; QTest::newRow("DeeplyNestedParallelDone") - << TestData{storage, root, log, 5, OnStart::Running, OnDone::Success}; + << TestData{storage, root, log, 5, OnDone::Success}; } { @@ -1079,7 +1051,7 @@ void tst_Tasking::testTree_data() {3, Handler::Setup} }; QTest::newRow("DeeplyNestedParallelError") - << TestData{storage, root, log, 5, OnStart::Running, OnDone::Failure}; + << TestData{storage, root, log, 5, OnDone::Failure}; } { @@ -1098,8 +1070,7 @@ void tst_Tasking::testTree_data() {4, Handler::Sync}, {5, Handler::Sync} }; - QTest::newRow("SyncSequential") - << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; + QTest::newRow("SyncSequential") << TestData{storage, root, log, 0, OnDone::Success}; } { @@ -1118,8 +1089,7 @@ void tst_Tasking::testTree_data() {4, Handler::Sync}, {5, Handler::Sync} }; - QTest::newRow("SyncWithReturn") - << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; + QTest::newRow("SyncWithReturn") << TestData{storage, root, log, 0, OnDone::Success}; } { @@ -1139,8 +1109,7 @@ void tst_Tasking::testTree_data() {4, Handler::Sync}, {5, Handler::Sync} }; - QTest::newRow("SyncParallel") - << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; + QTest::newRow("SyncParallel") << TestData{storage, root, log, 0, OnDone::Success}; } { @@ -1158,8 +1127,7 @@ void tst_Tasking::testTree_data() {2, Handler::Sync}, {3, Handler::Sync} }; - QTest::newRow("SyncError") - << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Failure}; + QTest::newRow("SyncError") << TestData{storage, root, log, 0, OnDone::Failure}; } { @@ -1180,8 +1148,7 @@ void tst_Tasking::testTree_data() {5, Handler::Sync}, {0, Handler::GroupDone} }; - QTest::newRow("SyncAndAsync") - << TestData{storage, root, log, 2, OnStart::Running, OnDone::Success}; + QTest::newRow("SyncAndAsync") << TestData{storage, root, log, 2, OnDone::Success}; } { @@ -1200,8 +1167,7 @@ void tst_Tasking::testTree_data() {3, Handler::Sync}, {0, Handler::GroupError} }; - QTest::newRow("SyncAndAsyncError") - << TestData{storage, root, log, 2, OnStart::Running, OnDone::Failure}; + QTest::newRow("SyncAndAsyncError") << TestData{storage, root, log, 2, OnDone::Failure}; } { @@ -1343,15 +1309,15 @@ void tst_Tasking::testTree_data() // Notice the different log order for each scenario. QTest::newRow("BarrierSequential") - << TestData{storage, root1, log1, 4, OnStart::Running, OnDone::Success}; + << TestData{storage, root1, log1, 4, OnDone::Success}; QTest::newRow("BarrierParallelAdvanceFirst") - << TestData{storage, root2, log2, 4, OnStart::Running, OnDone::Success}; + << TestData{storage, root2, log2, 4, OnDone::Success}; QTest::newRow("BarrierParallelWaitForFirst") - << TestData{storage, root3, log3, 4, OnStart::Running, OnDone::Success}; + << TestData{storage, root3, log3, 4, OnDone::Success}; QTest::newRow("BarrierParallelMultiWaitFor") - << TestData{storage, root4, log4, 5, OnStart::Running, OnDone::Success}; + << TestData{storage, root4, log4, 5, OnDone::Success}; QTest::newRow("BarrierParallelTwoSingleBarriers") - << TestData{storage, root5, log5, 5, OnStart::Running, OnDone::Success}; + << TestData{storage, root5, log5, 5, OnDone::Success}; } { @@ -1475,13 +1441,13 @@ void tst_Tasking::testTree_data() // Notice the different log order for each scenario. QTest::newRow("MultiBarrierSequential") - << TestData{storage, root1, log1, 5, OnStart::Running, OnDone::Success}; + << TestData{storage, root1, log1, 5, OnDone::Success}; QTest::newRow("MultiBarrierParallelAdvanceFirst") - << TestData{storage, root2, log2, 5, OnStart::Running, OnDone::Success}; + << TestData{storage, root2, log2, 5, OnDone::Success}; QTest::newRow("MultiBarrierParallelWaitForFirst") - << TestData{storage, root3, log3, 5, OnStart::Running, OnDone::Success}; + << TestData{storage, root3, log3, 5, OnDone::Success}; QTest::newRow("MultiBarrierParallelMultiWaitFor") - << TestData{storage, root4, log4, 6, OnStart::Running, OnDone::Success}; + << TestData{storage, root4, log4, 6, OnDone::Success}; } } @@ -1489,52 +1455,20 @@ void tst_Tasking::testTree() { QFETCH(TestData, testData); - QEventLoop eventLoop; TaskTree taskTree(testData.root); QCOMPARE(taskTree.taskCount(), testData.taskCount); - int doneCount = 0; - int errorCount = 0; - connect(&taskTree, &TaskTree::done, this, [&doneCount, &eventLoop] { - ++doneCount; - eventLoop.quit(); - }); - connect(&taskTree, &TaskTree::errorOccurred, this, [&errorCount, &eventLoop] { - ++errorCount; - eventLoop.quit(); - }); Log actualLog; - auto collectLog = [&actualLog](CustomStorage *storage){ - actualLog = storage->m_log; - }; + const auto collectLog = [&actualLog](CustomStorage *storage) { actualLog = storage->m_log; }; taskTree.onStorageDone(testData.storage, collectLog); - taskTree.start(); - const bool expectRunning = testData.onStart == OnStart::Running; - QCOMPARE(taskTree.isRunning(), expectRunning); - - if (expectRunning) { - QTimer timer; - bool timedOut = false; - connect(&timer, &QTimer::timeout, &eventLoop, [&eventLoop, &timedOut] { - timedOut = true; - eventLoop.quit(); - }); - timer.setInterval(2000); - timer.setSingleShot(true); - timer.start(); - eventLoop.exec(); - QCOMPARE(timedOut, false); - QCOMPARE(taskTree.isRunning(), false); - } + const int result = taskTree.runBlocking(2000); + QCOMPARE(taskTree.isRunning(), false); QCOMPARE(taskTree.progressValue(), testData.taskCount); QCOMPARE(actualLog, testData.expectedLog); QCOMPARE(CustomStorage::instanceCount(), 0); const bool expectSuccess = testData.onDone == OnDone::Success; - const int expectedDoneCount = expectSuccess ? 1 : 0; - const int expectedErrorCount = expectSuccess ? 0 : 1; - QCOMPARE(doneCount, expectedDoneCount); - QCOMPARE(errorCount, expectedErrorCount); + QCOMPARE(result, expectSuccess); } void tst_Tasking::storageOperators() From f0acaecc6340e6c594296e890fefce5ed865c5ed Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 16 May 2023 23:26:40 +0200 Subject: [PATCH 1127/1447] tst_Async: Reuse TaskTree:runBlocking() Change-Id: Ia5dd76bed15014d920e44f51de1774323be0b9a6 Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns Reviewed-by: --- tests/auto/utils/async/tst_async.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/auto/utils/async/tst_async.cpp b/tests/auto/utils/async/tst_async.cpp index bf7cae7eff1..4a496f93a00 100644 --- a/tests/auto/utils/async/tst_async.cpp +++ b/tests/auto/utils/async/tst_async.cpp @@ -439,12 +439,7 @@ void tst_Async::taskTree() }; TaskTree tree(root); - - QEventLoop eventLoop; - connect(&tree, &TaskTree::done, &eventLoop, &QEventLoop::quit); - tree.start(); - eventLoop.exec(); - + QVERIFY(tree.runBlocking(1000)); QCOMPARE(value, 16); } @@ -581,12 +576,7 @@ void tst_Async::mapReduce() QFETCH(QList, results); TaskTree tree(root); - - QEventLoop eventLoop; - connect(&tree, &TaskTree::done, &eventLoop, &QEventLoop::quit); - tree.start(); - eventLoop.exec(); - + QVERIFY(tree.runBlocking(1000)); QCOMPARE(s_results, results); QCOMPARE(s_sum, sum); } From 376c1cf2466a583ecc9187f8f95b613d9ed96f9c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 15 May 2023 17:54:23 +0200 Subject: [PATCH 1128/1447] FileStreamWriter: Add some comments into d'tor When d'tor of the parent Async runs, it busy waits for the WriteBuffer's thread to finish, and afterwards QObject's d'tor deletes the child WriteBuffer object. Change-Id: Ifc696b3e56735e697d8c54c2471f89e323d3c0d1 Reviewed-by: Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/utils/filestreamer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index 55e984c2fbf..ababb94cf68 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -223,6 +223,11 @@ public: ~FileStreamWriter() { // TODO: should d'tor remove unfinished file write leftovers? if (m_writeBuffer && isBuffered()) m_writeBuffer->cancel(); + // m_writeBuffer is a child of either Process or Async. So, if m_writeBuffer + // is still alive now (in case when TaskTree::stop() was called), the FileStreamBase + // d'tor is going to delete m_writeBuffer later. In case of Async, coming from + // localTask(), the d'tor of Async, run by FileStreamBase, busy waits for the + // already canceled here WriteBuffer to finish before deleting WriteBuffer child. } void setWriteData(const QByteArray &writeData) { From 5ae82a88cf8e8572aa4e948fc1cbc3732aa1f440 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 18 May 2023 19:14:39 +0200 Subject: [PATCH 1129/1447] TaskTree tasks: Make task naming consistent Task-number: QTCREATORBUG-29102 Change-Id: I96dfde58b684a3b48704778b92cdf2f869bbb7b1 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/utils/filestreamer.cpp | 12 ++++++------ src/plugins/coreplugin/locator/ilocatorfilter.cpp | 11 ++++++----- .../devicesupport/deviceusedportsgatherer.cpp | 6 ------ .../devicesupport/deviceusedportsgatherer.h | 10 +++++++--- .../projectexplorer/devicesupport/idevice.cpp | 6 +++--- src/plugins/projectexplorer/devicesupport/idevice.h | 7 ++++--- src/plugins/remotelinux/killappstep.cpp | 2 +- src/plugins/remotelinux/linuxdevicetester.cpp | 2 +- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index ababb94cf68..d24b61dbde3 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -306,8 +306,8 @@ public: } // namespace Utils -TASKING_DECLARE_TASK(Reader, Utils::FileStreamReaderAdapter); -TASKING_DECLARE_TASK(Writer, Utils::FileStreamWriterAdapter); +TASKING_DECLARE_TASK(FileStreamReaderTask, Utils::FileStreamReaderAdapter); +TASKING_DECLARE_TASK(FileStreamWriterTask, Utils::FileStreamWriterAdapter); namespace Utils { @@ -353,10 +353,10 @@ static Group interDeviceTransferTask(const FilePath &source, const FilePath &des Storage(writerReadyBarrier), parallel, Storage(storage), - Writer(setupWriter), + FileStreamWriterTask(setupWriter), Group { WaitForBarrierTask(writerReadyBarrier), - Reader(setupReader, finalizeReader, finalizeReader) + FileStreamReaderTask(setupReader, finalizeReader, finalizeReader) } }; @@ -408,14 +408,14 @@ private: m_readBuffer += data; }); }; - return Reader(setup); + return FileStreamReaderTask(setup); } TaskItem writerTask() { const auto setup = [this](FileStreamWriter &writer) { writer.setFilePath(m_destination); writer.setWriteData(m_writeBuffer); }; - return Writer(setup); + return FileStreamWriterTask(setup); } TaskItem transferTask() { const auto setup = [this](Async &async) { diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 1a08792382b..18f9dfd29d7 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -244,7 +244,8 @@ private: // When all the results are reported (the expected number of reports is set with setFilterCount()), // the ResultsCollector finishes. The intermediate results are reported with // serialOutputDataReady() signal. -// The object of ResultsCollector is registered in Tasking namespace under the Collector name. +// The object of ResultsCollector is registered in Tasking namespace under the +// ResultsCollectorTask name. class ResultsCollector : public QObject { Q_OBJECT @@ -317,10 +318,10 @@ void ResultsCollector::start() m_watcher->setFuture(Utils::asyncRun(deduplicate, m_deduplicator)); } -class ResultsCollectorAdapter : public TaskAdapter +class ResultsCollectorTaskAdapter : public TaskAdapter { public: - ResultsCollectorAdapter() { + ResultsCollectorTaskAdapter() { connect(task(), &ResultsCollector::done, this, [this] { emit done(true); }); } void start() final { task()->start(); } @@ -328,7 +329,7 @@ public: } // namespace Core -TASKING_DECLARE_TASK(Collector, Core::ResultsCollectorAdapter); +TASKING_DECLARE_TASK(ResultsCollectorTask, Core::ResultsCollectorTaskAdapter); namespace Core { @@ -483,7 +484,7 @@ void LocatorMatcher::start() const Group root { parallel, Storage(collectorStorage), - Collector(onCollectorSetup, onCollectorDone, onCollectorDone), + ResultsCollectorTask(onCollectorSetup, onCollectorDone, onCollectorDone), Group { parallelTasks } diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp index fbe300bf269..c3f3f195ca1 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp @@ -116,12 +116,6 @@ void DeviceUsedPortsGatherer::handleProcessDone() stop(); } -DeviceUsedPortsGathererAdapter::DeviceUsedPortsGathererAdapter() -{ - connect(task(), &DeviceUsedPortsGatherer::portListReady, this, [this] { emit done(true); }); - connect(task(), &DeviceUsedPortsGatherer::error, this, [this] { emit done(false); }); -} - // PortGatherer PortsGatherer::PortsGatherer(RunControl *runControl) diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h index 7be6f9c4855..20b0c9c9e8f 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h @@ -44,11 +44,14 @@ private: Internal::DeviceUsedPortsGathererPrivate * const d; }; -class PROJECTEXPLORER_EXPORT DeviceUsedPortsGathererAdapter +class PROJECTEXPLORER_EXPORT DeviceUsedPortsGathererTaskAdapter : public Tasking::TaskAdapter { public: - DeviceUsedPortsGathererAdapter(); + DeviceUsedPortsGathererTaskAdapter() { + connect(task(), &DeviceUsedPortsGatherer::portListReady, this, [this] { emit done(true); }); + connect(task(), &DeviceUsedPortsGatherer::error, this, [this] { emit done(false); }); + } void start() final { task()->start(); } }; @@ -86,4 +89,5 @@ private: } // namespace ProjectExplorer -TASKING_DECLARE_TASK(PortGatherer, ProjectExplorer::DeviceUsedPortsGathererAdapter); +TASKING_DECLARE_TASK(DeviceUsedPortsGathererTask, + ProjectExplorer::DeviceUsedPortsGathererTaskAdapter); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 775f60e396d..50f552444b3 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -695,12 +695,12 @@ void DeviceProcessKiller::start() m_signalOperation->killProcess(m_processPath.path()); } -KillerAdapter::KillerAdapter() +DeviceProcessKillerTaskAdapter::DeviceProcessKillerTaskAdapter() { - connect(task(), &DeviceProcessKiller::done, this, &KillerAdapter::done); + connect(task(), &DeviceProcessKiller::done, this, &TaskInterface::done); } -void KillerAdapter::start() +void DeviceProcessKillerTaskAdapter::start() { task()->start(); } diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index f0a902227ad..e28f88aaf46 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -277,13 +277,14 @@ private: QString m_errorString; }; -class PROJECTEXPLORER_EXPORT KillerAdapter : public Tasking::TaskAdapter +class PROJECTEXPLORER_EXPORT DeviceProcessKillerTaskAdapter + : public Tasking::TaskAdapter { public: - KillerAdapter(); + DeviceProcessKillerTaskAdapter(); void start() final; }; } // namespace ProjectExplorer -TASKING_DECLARE_TASK(Killer, ProjectExplorer::KillerAdapter); +TASKING_DECLARE_TASK(DeviceProcessKillerTask, ProjectExplorer::DeviceProcessKillerTaskAdapter); diff --git a/src/plugins/remotelinux/killappstep.cpp b/src/plugins/remotelinux/killappstep.cpp index df8d701dcfc..d3ec72e8895 100644 --- a/src/plugins/remotelinux/killappstep.cpp +++ b/src/plugins/remotelinux/killappstep.cpp @@ -57,7 +57,7 @@ Group KillAppStep::deployRecipe() addProgressMessage(Tr::tr("Failed to kill remote application. " "Assuming it was not running.")); }; - return Group { Killer(setupHandler, doneHandler, errorHandler) }; + return Group { DeviceProcessKillerTask(setupHandler, doneHandler, errorHandler) }; } KillAppStepFactory::KillAppStepFactory() diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index c32cabfee10..e1a209664fe 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -160,7 +160,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::gathererTask() const return Group { optional, - PortGatherer(setup, done, error) + DeviceUsedPortsGathererTask(setup, done, error) }; } From c603e01535dd50849ae17498922f27a142db7b01 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 17 May 2023 17:38:10 +0200 Subject: [PATCH 1130/1447] TaskTree: Don't derive TaskNode from QObject It reduces the time spent inside TaskTree::setupRoot() by ~30% for big trees (~7000 tasks). Change-Id: Ic65ed0fdf511977d9cc2fe22bdac814516e9883d Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 58235cd814f..e3605aaf027 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -298,7 +298,7 @@ public: std::optional m_runtimeData; }; -class TaskNode : public QObject +class TaskNode { public: TaskNode(TaskTreePrivate *taskTreePrivate, const TaskItem &task, @@ -316,6 +316,7 @@ public: bool isTask() const { return bool(m_taskHandler.m_createHandler); } int taskCount() const { return isTask() ? 1 : m_container.m_constData.m_taskCount; } TaskContainer *parentContainer() const { return m_container.m_constData.m_parentContainer; } + TaskTree *taskTree() const { return m_container.m_constData.m_taskTreePrivate->q; } private: const TaskItem::TaskHandler m_taskHandler; @@ -647,9 +648,9 @@ TaskAction TaskNode::start() } const std::shared_ptr unwindAction = std::make_shared(TaskAction::Continue); - connect(m_task.get(), &TaskInterface::done, this, [=](bool success) { + QObject::connect(m_task.get(), &TaskInterface::done, taskTree(), [=](bool success) { invokeEndHandler(success); - disconnect(m_task.get(), &TaskInterface::done, this, nullptr); + QObject::disconnect(m_task.get(), &TaskInterface::done, taskTree(), nullptr); m_task.release()->deleteLater(); QTC_ASSERT(parentContainer() && parentContainer()->isRunning(), return); if (parentContainer()->isStarting()) From 3763370ab9e93f97d8acc63aed710c32e6034229 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 19 May 2023 09:35:09 +0200 Subject: [PATCH 1131/1447] TaskTree: Add Q_DISABLE_COPY_MOVE() into internal classes Change-Id: I1b599902dfeebed93378a4d38bd3deb786f572b9 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index e3605aaf027..6930e117277 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -203,6 +203,8 @@ class TaskNode; class TaskTreePrivate { + Q_DISABLE_COPY_MOVE(TaskTreePrivate) + public: TaskTreePrivate(TaskTree *taskTree) : q(taskTree) {} @@ -249,6 +251,8 @@ public: class TaskContainer { + Q_DISABLE_COPY_MOVE(TaskContainer) + public: TaskContainer(TaskTreePrivate *taskTreePrivate, const TaskItem &task, TaskNode *parentNode, TaskContainer *parentContainer) @@ -300,6 +304,8 @@ public: class TaskNode { + Q_DISABLE_COPY_MOVE(TaskNode) + public: TaskNode(TaskTreePrivate *taskTreePrivate, const TaskItem &task, TaskContainer *parentContainer) From 7bfc3197aa9518a2a08cf8bbdc6ea1425feb003d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 19 May 2023 10:31:02 +0200 Subject: [PATCH 1132/1447] TaskTree: Add missing include Amends 9c78ef983a1203515a7552784a119f1ba3df4a71 Change-Id: Id912771b2d23c6856233705a054c0e8e1e9b5a41 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 6930e117277..9544e356ac0 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include From 7501d7587fc931a1454c0fea8412c2cee9a1c065 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 17 May 2023 19:28:57 +0200 Subject: [PATCH 1133/1447] TaskTree: Introduce WorkflowPolicy::StopOnFinished The policy is useful mainly in parallel mode. It stops executing the Group when any task finishes. It reports the task's result. Change-Id: I7aa98365cdc4c1eb869ab419d42d0cc5438d43bf Reviewed-by: Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 76 ++++++++++++-------- src/libs/solutions/tasking/tasktree.h | 24 ++++--- tests/auto/solutions/tasking/tst_tasking.cpp | 62 ++++++++++++++-- 3 files changed, 115 insertions(+), 47 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 9544e356ac0..32e7f3eadd5 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -114,6 +114,7 @@ Workflow stopOnError(WorkflowPolicy::StopOnError); Workflow continueOnError(WorkflowPolicy::ContinueOnError); Workflow stopOnDone(WorkflowPolicy::StopOnDone); Workflow continueOnDone(WorkflowPolicy::ContinueOnDone); +Workflow stopOnFinished(WorkflowPolicy::StopOnFinished); Workflow optional(WorkflowPolicy::Optional); void TaskItem::addChildren(const QList &children) @@ -511,6 +512,10 @@ bool TaskContainer::RuntimeData::updateSuccessBit(bool success) { if (m_constData.m_workflowPolicy == WorkflowPolicy::Optional) return m_successBit; + if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) { + m_successBit = success; + return m_successBit; + } const bool donePolicy = m_constData.m_workflowPolicy == WorkflowPolicy::StopOnDone || m_constData.m_workflowPolicy == WorkflowPolicy::ContinueOnDone; @@ -595,8 +600,9 @@ TaskAction TaskContainer::childDone(bool success) { QTC_CHECK(isRunning()); const int limit = m_runtimeData->currentLimit(); // Read before bumping m_doneCount and stop() - const bool shouldStop = (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnDone && success) - || (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnError && !success); + const bool shouldStop = m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished + || (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnDone && success) + || (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnError && !success); if (shouldStop) stop(); @@ -1146,15 +1152,15 @@ void TaskNode::invokeEndHandler(bool success) \row \li stopOnError \li Default. If a task finishes with an error, the group: - \list 1 - \li Stops the running tasks (if any - for example, in parallel - mode). - \li Skips executing tasks it has not started (for example, in the - sequential mode). - \li Immediately finishes with an error. - \endlist - If all child tasks finish successfully or the group is empty, the group - finishes with success. + \list 1 + \li Stops the running tasks (if any - for example, in parallel + mode). + \li Skips executing tasks it has not started (for example, in the + sequential mode). + \li Immediately finishes with an error. + \endlist + If all child tasks finish successfully or the group is empty, the group + finishes with success. \row \li continueOnError \li Similar to stopOnError, but in case any child finishes with @@ -1162,22 +1168,22 @@ void TaskNode::invokeEndHandler(bool success) and the group reports an error afterwards, even when some other tasks in group finished with success. If a task finishes with an error, the group: - \list 1 - \li Continues executing the tasks that are running or have not - started yet. - \li Finishes with an error when all tasks finish. - \endlist - If all tasks finish successfully or the group is empty, the group - finishes with success. + \list 1 + \li Continues executing the tasks that are running or have not + started yet. + \li Finishes with an error when all tasks finish. + \endlist + If all tasks finish successfully or the group is empty, the group + finishes with success. \row \li stopOnDone \li If a task finishes with success, the group: - \list 1 - \li Stops running tasks and skips those that it has not started. - \li Immediately finishes with success. - \endlist - If all tasks finish with an error or the group is empty, the group - finishes with an error. + \list 1 + \li Stops running tasks and skips those that it has not started. + \li Immediately finishes with success. + \endlist + If all tasks finish with an error or the group is empty, the group + finishes with an error. \row \li continueOnDone \li Similar to stopOnDone, but in case any child finishes @@ -1185,13 +1191,21 @@ void TaskNode::invokeEndHandler(bool success) and the group reports success afterwards, even when some other tasks in group finished with an error. If a task finishes with success, the group: - \list 1 - \li Continues executing the tasks that are running or have not - started yet. - \li Finishes with success when all tasks finish. - \endlist - If all tasks finish with an error or the group is empty, the group - finishes with an error. + \list 1 + \li Continues executing the tasks that are running or have not + started yet. + \li Finishes with success when all tasks finish. + \endlist + If all tasks finish with an error or the group is empty, the group + finishes with an error. + \row + \li stopOnFinished + \li The group starts as many tasks as it can. When a task finishes + the group stops and reports the task's result. + When the group is empty, it finishes immediately with success. + Useful only in parallel mode. + In sequential mode, only the first task is started, and when finished, + the group finishes too, so the other tasks are ignored. \row \li optional \li The group executes all tasks and ignores their return state. If all diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 462eb5bd2eb..407db58b0ae 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -93,19 +93,22 @@ private: // WorkflowPolicy: // 1. When all children finished with done -> report done, otherwise: -// a) Report error on first error and stop executing other children (including their subtree) -// b) On first error - continue executing all children and report error afterwards +// a) Report error on first error and stop executing other children (including their subtree). +// b) On first error - continue executing all children and report error afterwards. // 2. When all children finished with error -> report error, otherwise: -// a) Report done on first done and stop executing other children (including their subtree) -// b) On first done - continue executing all children and report done afterwards -// 3. Always run all children, ignore their result and report done afterwards +// a) Report done on first done and stop executing other children (including their subtree). +// b) On first done - continue executing all children and report done afterwards. +// 3. Stops on first finished child. In sequential mode it will never run other children then the first one. +// Useful only in parallel mode. +// 4. Always run all children, ignore their result and report done afterwards. enum class WorkflowPolicy { - StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done) - ContinueOnError, // 1b - The same, but children execution continues. When no children it reports done. - StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error) - ContinueOnDone, // 2b - The same, but children execution continues. When no children it reports done. (?) - Optional // 3 - Always reports done after all children finished + StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done). + ContinueOnError, // 1b - The same, but children execution continues. Reports done when no children. + StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error). + ContinueOnDone, // 2b - The same, but children execution continues. Reports error when no children. + StopOnFinished, // 3 - Stops on first finished child and report its result. + Optional // 4 - Reports done after all children finished. }; enum class TaskAction @@ -287,6 +290,7 @@ TASKING_EXPORT extern Workflow stopOnError; TASKING_EXPORT extern Workflow continueOnError; TASKING_EXPORT extern Workflow stopOnDone; TASKING_EXPORT extern Workflow continueOnDone; +TASKING_EXPORT extern Workflow stopOnFinished; TASKING_EXPORT extern Workflow optional; template diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 06bebf99f51..1efcf7096a3 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -233,8 +233,9 @@ void tst_Tasking::testTree_data() const auto setupFailingTask = [setupTaskHelper](int taskId) { return [=](TestTask &task) { setupTaskHelper(task, taskId, false); }; }; - const auto setupSleepingTask = [setupTaskHelper](int taskId, std::chrono::milliseconds sleep) { - return [=](TestTask &task) { setupTaskHelper(task, taskId, true, sleep); }; + const auto setupSleepingTask = [setupTaskHelper](int taskId, bool success, + std::chrono::milliseconds sleep) { + return [=](TestTask &task) { setupTaskHelper(task, taskId, success, sleep); }; }; const auto setupDynamicTask = [setupTaskHelper](int taskId, TaskAction action) { return [=](TestTask &task) { @@ -680,6 +681,55 @@ void tst_Tasking::testTree_data() QTest::newRow("ContinueOnDone") << TestData{storage, root, log, 3, OnDone::Success}; } + { + const Group root = constructSimpleSequence(stopOnFinished); + const Log log { + {1, Handler::Setup}, + {1, Handler::Done}, + {0, Handler::GroupDone} + }; + QTest::newRow("StopOnFinished") << TestData{storage, root, log, 3, OnDone::Success}; + } + + { + const auto setupRoot = [=](bool firstSuccess, bool secondSuccess) { + return Group { + parallel, + stopOnFinished, + Storage(storage), + Test(setupSleepingTask(1, firstSuccess, 1000ms), logDone, logError), + Test(setupSleepingTask(2, secondSuccess, 5ms), logDone, logError), + OnGroupDone(groupDone(0)), + OnGroupError(groupError(0)) + }; + }; + + const Group root1 = setupRoot(true, true); + const Group root2 = setupRoot(true, false); + const Group root3 = setupRoot(false, true); + const Group root4 = setupRoot(false, false); + + const Log success { + {1, Handler::Setup}, + {2, Handler::Setup}, + {2, Handler::Done}, + {1, Handler::Error}, + {0, Handler::GroupDone} + }; + const Log failure { + {1, Handler::Setup}, + {2, Handler::Setup}, + {2, Handler::Error}, + {1, Handler::Error}, + {0, Handler::GroupError} + }; + + QTest::newRow("StopOnFinished1") << TestData{storage, root1, success, 2, OnDone::Success}; + QTest::newRow("StopOnFinished2") << TestData{storage, root2, failure, 2, OnDone::Failure}; + QTest::newRow("StopOnFinished3") << TestData{storage, root3, success, 2, OnDone::Success}; + QTest::newRow("StopOnFinished4") << TestData{storage, root4, failure, 2, OnDone::Failure}; + } + { const Group root { Storage(storage), @@ -837,14 +887,14 @@ void tst_Tasking::testTree_data() // Inside this test the task 2 should finish first, then synchonously: // - task 3 should exit setup with error - // - task 1 should be stopped as a consequence of error inside the group + // - task 1 should be stopped as a consequence of the error inside the group // - tasks 4 and 5 should be skipped const Group root2 { ParallelLimit(2), Storage(storage), Group { OnGroupSetup(groupSetup(1)), - Test(setupSleepingTask(1, 10ms)) + Test(setupSleepingTask(1, true, 10ms)) }, Group { OnGroupSetup(groupSetup(2)), @@ -879,11 +929,11 @@ void tst_Tasking::testTree_data() ParallelLimit(2), Group { OnGroupSetup(groupSetup(1)), - Test(setupSleepingTask(1, 20ms)) + Test(setupSleepingTask(1, true, 20ms)) }, Group { OnGroupSetup(groupSetup(2)), - Test(setupTask(2), [](const TestTask &) { QThread::msleep(10); }) + Test(setupSleepingTask(2, true, 10ms)) }, Group { OnGroupSetup(groupSetup(3)), From 5acecd4ef9c3e38df5cc01756aae756549623901 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 17 May 2023 16:10:10 +0200 Subject: [PATCH 1134/1447] WebAssembly: Base Settings handling on Core::PagedSettings Change-Id: If28afd8046367eb1b8b12e54d2dae4235dbc821f Reviewed-by: hjk --- src/plugins/webassembly/CMakeLists.txt | 6 +- src/plugins/webassembly/webassembly.qbs | 11 +- .../webassembly/webassemblyconstants.h | 3 - src/plugins/webassembly/webassemblyemsdk.cpp | 16 -- src/plugins/webassembly/webassemblyemsdk.h | 2 - .../webassembly/webassemblyoptionspage.cpp | 175 ------------------ .../webassembly/webassemblyoptionspage.h | 18 -- src/plugins/webassembly/webassemblyplugin.cpp | 4 +- .../webassembly/webassemblysettings.cpp | 164 ++++++++++++++++ src/plugins/webassembly/webassemblysettings.h | 35 ++++ .../webassembly/webassemblytoolchain.cpp | 9 +- 11 files changed, 216 insertions(+), 227 deletions(-) delete mode 100644 src/plugins/webassembly/webassemblyoptionspage.cpp delete mode 100644 src/plugins/webassembly/webassemblyoptionspage.h create mode 100644 src/plugins/webassembly/webassemblysettings.cpp create mode 100644 src/plugins/webassembly/webassemblysettings.h diff --git a/src/plugins/webassembly/CMakeLists.txt b/src/plugins/webassembly/CMakeLists.txt index 3ee300b09ff..6609357f015 100644 --- a/src/plugins/webassembly/CMakeLists.txt +++ b/src/plugins/webassembly/CMakeLists.txt @@ -4,16 +4,16 @@ add_qtc_plugin(WebAssembly SOURCES webassembly.qrc webassembly_global.h - webassemblytr.h webassemblyconstants.h webassemblydevice.cpp webassemblydevice.h webassemblyemsdk.cpp webassemblyemsdk.h - webassemblyoptionspage.cpp webassemblyoptionspage.h webassemblyplugin.cpp webassemblyplugin.h webassemblyqtversion.cpp webassemblyqtversion.h - webassemblyrunconfigurationaspects.cpp webassemblyrunconfigurationaspects.h webassemblyrunconfiguration.cpp webassemblyrunconfiguration.h + webassemblyrunconfigurationaspects.cpp webassemblyrunconfigurationaspects.h + webassemblysettings.cpp webassemblysettings.h webassemblytoolchain.cpp webassemblytoolchain.h + webassemblytr.h ) extend_qtc_plugin(WebAssembly diff --git a/src/plugins/webassembly/webassembly.qbs b/src/plugins/webassembly/webassembly.qbs index b859ea538a2..12b639238cb 100644 --- a/src/plugins/webassembly/webassembly.qbs +++ b/src/plugins/webassembly/webassembly.qbs @@ -13,24 +13,25 @@ QtcPlugin { files: [ "webassembly.qrc", - "webassembly_global.h", "webassemblytr.h", + "webassembly_global.h", "webassemblyconstants.h", "webassemblydevice.cpp", "webassemblydevice.h", "webassemblyemsdk.cpp", "webassemblyemsdk.h", - "webassemblyoptionspage.cpp", - "webassemblyoptionspage.h", "webassemblyplugin.cpp", "webassemblyplugin.h", "webassemblyqtversion.cpp", "webassemblyqtversion.h", - "webassemblyrunconfigurationaspects.cpp", - "webassemblyrunconfigurationaspects.h", "webassemblyrunconfiguration.cpp", "webassemblyrunconfiguration.h", + "webassemblyrunconfigurationaspects.cpp", + "webassemblyrunconfigurationaspects.h", + "webassemblysettings.cpp", + "webassemblysettings.h", "webassemblytoolchain.cpp", "webassemblytoolchain.h", + "webassemblytr.h", ] QtcTestFiles { diff --git a/src/plugins/webassembly/webassemblyconstants.h b/src/plugins/webassembly/webassemblyconstants.h index 40f49f73a4f..56315b0b404 100644 --- a/src/plugins/webassembly/webassemblyconstants.h +++ b/src/plugins/webassembly/webassemblyconstants.h @@ -14,8 +14,5 @@ const char WEBASSEMBLY_DEVICE_DEVICE_ID[] = "WebAssembly Device"; const char WEBASSEMBLY_QT_VERSION[] = "Qt4ProjectManager.QtVersion.WebAssembly"; const char WEBASSEMBLY_RUNCONFIGURATION_EMRUN[] = "WebAssembly.RunConfiguration.Emrun"; -const char SETTINGS_GROUP[] = "WebAssembly"; -const char SETTINGS_KEY_EMSDK[] = "EmSdk"; - } // namespace WebAssembly } // namespace Constants diff --git a/src/plugins/webassembly/webassemblyemsdk.cpp b/src/plugins/webassembly/webassemblyemsdk.cpp index 42f8738a8e7..507c2949654 100644 --- a/src/plugins/webassembly/webassemblyemsdk.cpp +++ b/src/plugins/webassembly/webassemblyemsdk.cpp @@ -11,7 +11,6 @@ #include #include -#include using namespace Utils; @@ -99,21 +98,6 @@ QVersionNumber version(const FilePath &sdkRoot) return *emSdkVersionCache()->object(cacheKey); } -void registerEmSdk(const FilePath &sdkRoot) -{ - QSettings *s = Core::ICore::settings(); - s->setValue(QLatin1String(Constants::SETTINGS_GROUP) + '/' - + QLatin1String(Constants::SETTINGS_KEY_EMSDK), sdkRoot.toString()); -} - -FilePath registeredEmSdk() -{ - QSettings *s = Core::ICore::settings(); - const QString path = s->value(QLatin1String(Constants::SETTINGS_GROUP) + '/' - + QLatin1String(Constants::SETTINGS_KEY_EMSDK)).toString(); - return FilePath::fromUserInput(path); -} - void clearCaches() { emSdkEnvCache()->clear(); diff --git a/src/plugins/webassembly/webassemblyemsdk.h b/src/plugins/webassembly/webassemblyemsdk.h index 8310e0320f2..55d83abcd22 100644 --- a/src/plugins/webassembly/webassemblyemsdk.h +++ b/src/plugins/webassembly/webassemblyemsdk.h @@ -16,8 +16,6 @@ bool isValid(const Utils::FilePath &sdkRoot); void parseEmSdkEnvOutputAndAddToEnv(const QString &output, Utils::Environment &env); void addToEnvironment(const Utils::FilePath &sdkRoot, Utils::Environment &env); QVersionNumber version(const Utils::FilePath &sdkRoot); -void registerEmSdk(const Utils::FilePath &sdkRoot); -Utils::FilePath registeredEmSdk(); void clearCaches(); } // WebAssembly::Internal::WebAssemblyEmSdk diff --git a/src/plugins/webassembly/webassemblyoptionspage.cpp b/src/plugins/webassembly/webassemblyoptionspage.cpp deleted file mode 100644 index 1a4524b945a..00000000000 --- a/src/plugins/webassembly/webassemblyoptionspage.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "webassemblyconstants.h" -#include "webassemblyemsdk.h" -#include "webassemblyoptionspage.h" -#include "webassemblyqtversion.h" -#include "webassemblytoolchain.h" -#include "webassemblytr.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace Utils; - -namespace WebAssembly { -namespace Internal { - -class WebAssemblyOptionsWidget : public Core::IOptionsPageWidget -{ -public: - WebAssemblyOptionsWidget(); - - void updateStatus(); - -private: - void apply() final; - void showEvent(QShowEvent *event) final; - - PathChooser *m_emSdkPathChooser; - InfoLabel *m_emSdkVersionDisplay; - QGroupBox *m_emSdkEnvGroupBox; - QTextBrowser *m_emSdkEnvDisplay; - InfoLabel *m_qtVersionDisplay; -}; - -WebAssemblyOptionsWidget::WebAssemblyOptionsWidget() -{ - auto mainLayout = new QVBoxLayout(this); - - { - auto pathChooserBox = new QGroupBox(Tr::tr("Emscripten SDK path:")); - pathChooserBox->setFlat(true); - auto layout = new QVBoxLayout(pathChooserBox); - auto instruction = new QLabel( - Tr::tr("Select the root directory of an installed %1. " - "Ensure that the activated SDK version is compatible with the %2 " - "or %3 version that you plan to develop against.") - .arg(R"(Emscripten SDK)") - .arg(R"(Qt 5)") - .arg(R"(Qt 6)")); - - instruction->setOpenExternalLinks(true); - instruction->setWordWrap(true); - layout->addWidget(instruction); - m_emSdkPathChooser = new PathChooser(this); - m_emSdkPathChooser->setExpectedKind(PathChooser::Directory); - m_emSdkPathChooser->setInitialBrowsePathBackup(FileUtils::homePath()); - m_emSdkPathChooser->setFilePath(WebAssemblyEmSdk::registeredEmSdk()); - connect(m_emSdkPathChooser, &PathChooser::textChanged, - this, &WebAssemblyOptionsWidget::updateStatus); - layout->addWidget(m_emSdkPathChooser); - m_emSdkVersionDisplay = new InfoLabel(this); - m_emSdkVersionDisplay->setElideMode(Qt::ElideNone); - m_emSdkVersionDisplay->setWordWrap(true); - layout->addWidget(m_emSdkVersionDisplay); - mainLayout->addWidget(pathChooserBox); - } - - { - m_emSdkEnvGroupBox = new QGroupBox(Tr::tr("Emscripten SDK environment:")); - m_emSdkEnvGroupBox->setFlat(true); - m_emSdkEnvGroupBox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::MinimumExpanding); - auto layout = new QVBoxLayout(m_emSdkEnvGroupBox); - m_emSdkEnvDisplay = new QTextBrowser; - m_emSdkEnvDisplay->setLineWrapMode(QTextBrowser::NoWrap); - m_emSdkEnvDisplay->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); - layout->addWidget(m_emSdkEnvDisplay); - mainLayout->addWidget(m_emSdkEnvGroupBox, 1); - } - - mainLayout->addStretch(); - - { - const QString minimumSupportedQtVersion = - WebAssemblyQtVersion::minimumSupportedQtVersion().toString(); - m_qtVersionDisplay = new InfoLabel( - Tr::tr("Note: %1 supports Qt %2 for WebAssembly and higher. " - "Your installed lower Qt version(s) are not supported.") - .arg(Core::ICore::versionString(), minimumSupportedQtVersion), - InfoLabel::Warning); - m_qtVersionDisplay->setElideMode(Qt::ElideNone); - m_qtVersionDisplay->setWordWrap(true); - mainLayout->addWidget(m_qtVersionDisplay); - } -} - -static QString environmentDisplay(const FilePath &sdkRoot) -{ - Environment env; - WebAssemblyEmSdk::addToEnvironment(sdkRoot, env); - QString result; - auto h4 = [](const QString &text) { return QString("

" + text + "

"); }; - result.append(h4(Tr::tr("Adding directories to PATH:"))); - result.append(env.value("PATH").replace(OsSpecificAspects::pathListSeparator(sdkRoot.osType()), "
")); - result.append(h4(Tr::tr("Setting environment variables:"))); - for (const QString &envVar : env.toStringList()) { - if (!envVar.startsWith("PATH")) // Path was already printed out above - result.append(envVar + "
"); - } - return result; -} - -void WebAssemblyOptionsWidget::updateStatus() -{ - WebAssemblyEmSdk::clearCaches(); - - const FilePath sdkPath = m_emSdkPathChooser->filePath(); - const bool sdkValid = sdkPath.exists() && WebAssemblyEmSdk::isValid(sdkPath); - - m_emSdkVersionDisplay->setVisible(sdkValid); - m_emSdkEnvGroupBox->setVisible(sdkValid); - - if (sdkValid) { - const QVersionNumber sdkVersion = WebAssemblyEmSdk::version(sdkPath); - const QVersionNumber minVersion = WebAssemblyToolChain::minimumSupportedEmSdkVersion(); - const bool versionTooLow = sdkVersion < minVersion; - m_emSdkVersionDisplay->setType(versionTooLow ? InfoLabel::NotOk : InfoLabel::Ok); - auto bold = [](const QString &text) { return QString("" + text + ""); }; - m_emSdkVersionDisplay->setText( - versionTooLow ? Tr::tr("The activated version %1 is not supported by %2. " - "Activate version %3 or higher.") - .arg(bold(sdkVersion.toString())) - .arg(bold(Core::ICore::versionString())) - .arg(bold(minVersion.toString())) - : Tr::tr("Activated version: %1") - .arg(bold(sdkVersion.toString()))); - m_emSdkEnvDisplay->setText(environmentDisplay(sdkPath)); - } - - m_qtVersionDisplay->setVisible(WebAssemblyQtVersion::isUnsupportedQtVersionInstalled()); -} - -void WebAssemblyOptionsWidget::showEvent(QShowEvent *event) -{ - Q_UNUSED(event) - updateStatus(); -} - -void WebAssemblyOptionsWidget::apply() -{ - const FilePath sdkPath = m_emSdkPathChooser->filePath(); - if (!WebAssemblyEmSdk::isValid(sdkPath)) - return; - WebAssemblyEmSdk::registerEmSdk(sdkPath); - WebAssemblyToolChain::registerToolChains(); -} - -WebAssemblyOptionsPage::WebAssemblyOptionsPage() -{ - setId(Id(Constants::SETTINGS_ID)); - setDisplayName(Tr::tr("WebAssembly")); - setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); - setWidgetCreator([] { return new WebAssemblyOptionsWidget; }); -} - -} // Internal -} // WebAssembly diff --git a/src/plugins/webassembly/webassemblyoptionspage.h b/src/plugins/webassembly/webassemblyoptionspage.h deleted file mode 100644 index 62a17a9b153..00000000000 --- a/src/plugins/webassembly/webassemblyoptionspage.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace WebAssembly { -namespace Internal { - -class WebAssemblyOptionsPage final : public Core::IOptionsPage -{ -public: - WebAssemblyOptionsPage(); -}; - -} // namespace Internal -} // namespace WebAssmbly diff --git a/src/plugins/webassembly/webassemblyplugin.cpp b/src/plugins/webassembly/webassemblyplugin.cpp index 0857e43f2f9..28227884da7 100644 --- a/src/plugins/webassembly/webassemblyplugin.cpp +++ b/src/plugins/webassembly/webassemblyplugin.cpp @@ -8,9 +8,9 @@ #endif // WITH_TESTS #include "webassemblyconstants.h" #include "webassemblydevice.h" -#include "webassemblyoptionspage.h" #include "webassemblyqtversion.h" #include "webassemblyrunconfiguration.h" +#include "webassemblysettings.h" #include "webassemblytoolchain.h" #include "webassemblytr.h" @@ -39,7 +39,7 @@ public: WebAssemblyQtVersionFactory qtVersionFactory; EmrunRunConfigurationFactory emrunRunConfigurationFactory; EmrunRunWorkerFactory emrunRunWorkerFactory; - WebAssemblyOptionsPage optionsPage; + WebAssemblySettings settings; }; static WebAssemblyPluginPrivate *dd = nullptr; diff --git a/src/plugins/webassembly/webassemblysettings.cpp b/src/plugins/webassembly/webassemblysettings.cpp new file mode 100644 index 00000000000..3d85e2127fd --- /dev/null +++ b/src/plugins/webassembly/webassemblysettings.cpp @@ -0,0 +1,164 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "webassemblysettings.h" + +#include "webassemblyconstants.h" +#include "webassemblyemsdk.h" +#include "webassemblyqtversion.h" +#include "webassemblytoolchain.h" +#include "webassemblytr.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace Utils; + +namespace WebAssembly { +namespace Internal { + +static WebAssemblySettings *theSettings = nullptr; + +WebAssemblySettings *WebAssemblySettings::instance() +{ + return theSettings; +} + +static QString environmentDisplay(const FilePath &sdkRoot) +{ + Environment env; + WebAssemblyEmSdk::addToEnvironment(sdkRoot, env); + QString result; + auto h4 = [](const QString &text) { return QString("

" + text + "

"); }; + result.append(h4(Tr::tr("Adding directories to PATH:"))); + result.append(env.value("PATH").replace(OsSpecificAspects::pathListSeparator(sdkRoot.osType()), "
")); + result.append(h4(Tr::tr("Setting environment variables:"))); + for (const QString &envVar : env.toStringList()) { + if (!envVar.startsWith("PATH")) // Path was already printed out above + result.append(envVar + "
"); + } + return result; +} + +WebAssemblySettings::WebAssemblySettings() +{ + theSettings = this; + + setSettingsGroup("WebAssembly"); + + setId(Id(Constants::SETTINGS_ID)); + setDisplayName(Tr::tr("WebAssembly")); + setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); + + registerAspect(&emSdk); + emSdk.setSettingsKey("EmSdk"); + emSdk.setExpectedKind(Utils::PathChooser::ExistingDirectory); + emSdk.setDefaultFilePath(FileUtils::homePath()); + + setLayouter([this](QWidget *widget) { + auto instruction = new QLabel( + Tr::tr("Select the root directory of an installed %1. " + "Ensure that the activated SDK version is compatible with the %2 " + "or %3 version that you plan to develop against.") + .arg(R"(Emscripten SDK)") + .arg(R"(Qt 5)") + .arg(R"(Qt 6)")); + instruction->setOpenExternalLinks(true); + instruction->setWordWrap(true); + + m_emSdkVersionDisplay = new InfoLabel; + m_emSdkVersionDisplay->setElideMode(Qt::ElideNone); + m_emSdkVersionDisplay->setWordWrap(true); + + m_emSdkEnvDisplay = new QTextBrowser; + m_emSdkEnvDisplay->setLineWrapMode(QTextBrowser::NoWrap); + + const QString minimumSupportedQtVersion = + WebAssemblyQtVersion::minimumSupportedQtVersion().toString(); + m_qtVersionDisplay = new InfoLabel( + Tr::tr("Note: %1 supports Qt %2 for WebAssembly and higher. " + "Your installed lower Qt version(s) are not supported.") + .arg(Core::ICore::versionString(), minimumSupportedQtVersion), + InfoLabel::Warning); + m_qtVersionDisplay->setElideMode(Qt::ElideNone); + m_qtVersionDisplay->setWordWrap(true); + + // _clang-format off + using namespace Layouting; + Column { + Group { + title(Tr::tr("Emscripten SDK path:")), + Column { + instruction, + emSdk, + m_emSdkVersionDisplay, + }, + }, + Group { + title(Tr::tr("Emscripten SDK environment:")), + bindTo(&m_emSdkEnvGroupBox), + Column { + m_emSdkEnvDisplay, + }, + }, + m_qtVersionDisplay, + }.attachTo(widget); + // _clang-format on + + updateStatus(); + connect(emSdk.pathChooser(), &Utils::PathChooser::textChanged, + this, &WebAssemblySettings::updateStatus); + }); + + readSettings(); +} + +void WebAssemblySettings::apply() +{ + WebAssemblyToolChain::registerToolChains(); + Core::IOptionsPage::apply(); +} + +void WebAssemblySettings::updateStatus() +{ + WebAssemblyEmSdk::clearCaches(); + + const Utils::FilePath newEmSdk = emSdk.pathChooser()->filePath(); + const bool sdkValid = newEmSdk.exists() && WebAssemblyEmSdk::isValid(newEmSdk); + + m_emSdkVersionDisplay->setVisible(sdkValid); + m_emSdkEnvGroupBox->setEnabled(sdkValid); + + if (sdkValid) { + const QVersionNumber sdkVersion = WebAssemblyEmSdk::version(newEmSdk); + const QVersionNumber minVersion = WebAssemblyToolChain::minimumSupportedEmSdkVersion(); + const bool versionTooLow = sdkVersion < minVersion; + m_emSdkVersionDisplay->setType(versionTooLow ? InfoLabel::NotOk : InfoLabel::Ok); + auto bold = [](const QString &text) { return QString("" + text + ""); }; + m_emSdkVersionDisplay->setText( + versionTooLow ? Tr::tr("The activated version %1 is not supported by %2. " + "Activate version %3 or higher.") + .arg(bold(sdkVersion.toString())) + .arg(bold(Core::ICore::versionString())) + .arg(bold(minVersion.toString())) + : Tr::tr("Activated version: %1") + .arg(bold(sdkVersion.toString()))); + m_emSdkEnvDisplay->setText(environmentDisplay(newEmSdk)); + } else { + m_emSdkEnvDisplay->clear(); + } + + m_qtVersionDisplay->setVisible(WebAssemblyQtVersion::isUnsupportedQtVersionInstalled()); +} + +} // Internal +} // WebAssembly diff --git a/src/plugins/webassembly/webassemblysettings.h b/src/plugins/webassembly/webassemblysettings.h new file mode 100644 index 00000000000..1d92a5176d1 --- /dev/null +++ b/src/plugins/webassembly/webassemblysettings.h @@ -0,0 +1,35 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +QT_BEGIN_NAMESPACE +class QTextBrowser; +QT_END_NAMESPACE + +namespace WebAssembly { +namespace Internal { + +class WebAssemblySettings final : public Core::PagedSettings +{ +public: + WebAssemblySettings(); + + static WebAssemblySettings *instance(); + void apply() final; + + Utils::FilePathAspect emSdk; + +private: + QWidget *m_emSdkEnvGroupBox = nullptr; + Utils::InfoLabel *m_emSdkVersionDisplay = nullptr; + QTextBrowser *m_emSdkEnvDisplay = nullptr; + Utils::InfoLabel *m_qtVersionDisplay = nullptr; + + void updateStatus(); +}; + +} // namespace Internal +} // namespace WebAssmbly diff --git a/src/plugins/webassembly/webassemblytoolchain.cpp b/src/plugins/webassembly/webassemblytoolchain.cpp index c413f27566c..c554ee65cd5 100644 --- a/src/plugins/webassembly/webassemblytoolchain.cpp +++ b/src/plugins/webassembly/webassemblytoolchain.cpp @@ -1,9 +1,11 @@ // Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "webassemblytoolchain.h" + #include "webassemblyconstants.h" #include "webassemblyemsdk.h" -#include "webassemblytoolchain.h" +#include "webassemblysettings.h" #include "webassemblytr.h" #include @@ -49,7 +51,8 @@ static void addRegisteredMinGWToEnvironment(Environment &env) void WebAssemblyToolChain::addToEnvironment(Environment &env) const { - WebAssemblyEmSdk::addToEnvironment(WebAssemblyEmSdk::registeredEmSdk(), env); + const FilePath emSdk = WebAssemblySettings::instance()->emSdk(); + WebAssemblyEmSdk::addToEnvironment(emSdk, env); if (env.osType() == OsTypeWindows) addRegisteredMinGWToEnvironment(env); } @@ -92,7 +95,7 @@ const QVersionNumber &WebAssemblyToolChain::minimumSupportedEmSdkVersion() static Toolchains doAutoDetect(const ToolchainDetector &detector) { - const FilePath sdk = WebAssemblyEmSdk::registeredEmSdk(); + const FilePath sdk = WebAssemblySettings::instance()->emSdk(); if (!WebAssemblyEmSdk::isValid(sdk)) return {}; From b0f68a916fa4086b0b304a6b374a22e0a0e80015 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 19 May 2023 11:30:57 +0200 Subject: [PATCH 1135/1447] Vcpkg: Use Utils::FilePathAspect Change-Id: I7532536186d500748e3ad30794801436c0a997e2 Reviewed-by: hjk --- src/plugins/vcpkg/vcpkgsearch.cpp | 2 +- src/plugins/vcpkg/vcpkgsettings.cpp | 3 +-- src/plugins/vcpkg/vcpkgsettings.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/vcpkg/vcpkgsearch.cpp b/src/plugins/vcpkg/vcpkgsearch.cpp index a2ec2c66c28..1e2d28f74ab 100644 --- a/src/plugins/vcpkg/vcpkgsearch.cpp +++ b/src/plugins/vcpkg/vcpkgsearch.cpp @@ -94,7 +94,7 @@ VcpkgPackageSearchDialog::VcpkgPackageSearchDialog(QWidget *parent) m_buttonBox, }.attachTo(this); - m_allPackages = vcpkgManifests(VcpkgSettings::instance()->vcpkgRoot.filePath()); + m_allPackages = vcpkgManifests(VcpkgSettings::instance()->vcpkgRoot()); listPackages({}); diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp index 85b4b6f4faa..eb3c71c0b4d 100644 --- a/src/plugins/vcpkg/vcpkgsettings.cpp +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -61,7 +61,6 @@ VcpkgSettings::VcpkgSettings() registerAspect(&vcpkgRoot); vcpkgRoot.setSettingsKey("VcpkgRoot"); - vcpkgRoot.setDisplayStyle(Utils::StringAspect::PathChooserDisplay); vcpkgRoot.setExpectedKind(Utils::PathChooser::ExistingDirectory); vcpkgRoot.setDefaultValue(Utils::qtcEnvironmentVariable(Constants::ENVVAR_VCPKG_ROOT)); @@ -70,7 +69,7 @@ VcpkgSettings::VcpkgSettings() bool VcpkgSettings::vcpkgRootValid() const { - return (vcpkgRoot.filePath() / "vcpkg").withExecutableSuffix().isExecutableFile(); + return (vcpkgRoot() / "vcpkg").withExecutableSuffix().isExecutableFile(); } } // namespace Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgsettings.h b/src/plugins/vcpkg/vcpkgsettings.h index fb1c478fc4f..bbff08035ab 100644 --- a/src/plugins/vcpkg/vcpkgsettings.h +++ b/src/plugins/vcpkg/vcpkgsettings.h @@ -15,7 +15,7 @@ public: static VcpkgSettings *instance(); bool vcpkgRootValid() const; - Utils::StringAspect vcpkgRoot; + Utils::FilePathAspect vcpkgRoot; }; } // namespace Vcpkg::Internal From d4cf9b667b3a24bd5c01428917f1a912d39fc7cb Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 15 May 2023 18:52:11 +0200 Subject: [PATCH 1136/1447] Conan: Simplify plugin setup Change-Id: Ic60d2626384c2d15b81614f51db447a197640156 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/conan/CMakeLists.txt | 2 +- src/plugins/conan/conan.qbs | 1 - src/plugins/conan/conaninstallstep.cpp | 39 +++++++++++- src/plugins/conan/conanplugin.cpp | 84 ++++---------------------- src/plugins/conan/conanplugin.h | 34 ----------- src/plugins/conan/conansettings.cpp | 10 +++ src/plugins/conan/conansettings.h | 2 + 7 files changed, 61 insertions(+), 111 deletions(-) delete mode 100644 src/plugins/conan/conanplugin.h diff --git a/src/plugins/conan/CMakeLists.txt b/src/plugins/conan/CMakeLists.txt index c9ad746a84d..80da66de4d2 100644 --- a/src/plugins/conan/CMakeLists.txt +++ b/src/plugins/conan/CMakeLists.txt @@ -3,7 +3,7 @@ add_qtc_plugin(Conan SOURCES conanconstants.h conaninstallstep.cpp conaninstallstep.h - conanplugin.cpp conanplugin.h + conanplugin.cpp conansettings.cpp conansettings.h conantr.h ) diff --git a/src/plugins/conan/conan.qbs b/src/plugins/conan/conan.qbs index 486df35f49f..b5beeb7d359 100644 --- a/src/plugins/conan/conan.qbs +++ b/src/plugins/conan/conan.qbs @@ -13,7 +13,6 @@ QtcPlugin { "conanconstants.h", "conaninstallstep.h", "conaninstallstep.cpp", - "conanplugin.h", "conanplugin.cpp", "conansettings.h", "conansettings.cpp", diff --git a/src/plugins/conan/conaninstallstep.cpp b/src/plugins/conan/conaninstallstep.cpp index c1957cc976a..fbc5999192d 100644 --- a/src/plugins/conan/conaninstallstep.cpp +++ b/src/plugins/conan/conaninstallstep.cpp @@ -4,7 +4,6 @@ #include "conaninstallstep.h" #include "conanconstants.h" -#include "conanplugin.h" #include "conansettings.h" #include "conantr.h" @@ -19,12 +18,40 @@ #include #include #include +#include using namespace ProjectExplorer; using namespace Utils; namespace Conan::Internal { +static FilePath conanFilePath(Project *project, const FilePath &defaultFilePath = {}) +{ + const FilePath projectDirectory = project->projectDirectory(); + // conanfile.py takes precedence over conanfile.txt when "conan install dir" is invoked + const FilePath conanPy = projectDirectory / "conanfile.py"; + if (conanPy.exists()) + return conanPy; + const FilePath conanTxt = projectDirectory / "conanfile.txt"; + if (conanTxt.exists()) + return conanTxt; + return defaultFilePath; +} + +static void connectTarget(Project *project, Target *target) +{ + if (!conanFilePath(project).isEmpty()) { + const QList buildConfigurations = target->buildConfigurations(); + for (BuildConfiguration *buildConfiguration : buildConfigurations) + buildConfiguration->buildSteps()->insertStep(0, Constants::INSTALL_STEP); + } + QObject::connect(target, &Target::addedBuildConfiguration, + target, [project] (BuildConfiguration *buildConfiguration) { + if (!conanFilePath(project).isEmpty()) + buildConfiguration->buildSteps()->insertStep(0, Constants::INSTALL_STEP); + }); +} + // ConanInstallStep class ConanInstallStep final : public AbstractProcessStep @@ -45,7 +72,7 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id) auto conanFile = addAspect(); conanFile->setSettingsKey("ConanPackageManager.InstallStep.ConanFile"); - conanFile->setFilePath(ConanPlugin::conanFilePath(project(), + conanFile->setFilePath(conanFilePath(project(), project()->projectDirectory() / "conanfile.txt")); conanFile->setLabelText(Tr::tr("Conan file:")); conanFile->setToolTip(Tr::tr("Enter location of conanfile.txt or conanfile.py.")); @@ -68,7 +95,7 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id) const QString buildType = bt == BuildConfiguration::Release ? QString("Release") : QString("Debug"); - CommandLine cmd(ConanPlugin::conanSettings()->conanFilePath()); + CommandLine cmd(settings().conanFilePath()); cmd.addArgs({"install", "-s", "build_type=" + buildType}); if (buildMissing->value()) cmd.addArg("--build=missing"); @@ -85,6 +112,12 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id) setupProcessParameters(¶m); return param.summary(displayName()); }); + + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this](Project * project) { + connect(project, &Project::addedTarget, project, [project] (Target *target) { + connectTarget(project, target); + }); + }); } bool ConanInstallStep::init() diff --git a/src/plugins/conan/conanplugin.cpp b/src/plugins/conan/conanplugin.cpp index 3844b2983bd..13655b93b63 100644 --- a/src/plugins/conan/conanplugin.cpp +++ b/src/plugins/conan/conanplugin.cpp @@ -1,86 +1,26 @@ // Copyright (C) 2018 Jochen Seemann // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "conanplugin.h" - -#include "conanconstants.h" #include "conaninstallstep.h" #include "conansettings.h" -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace Core; -using namespace ProjectExplorer; -using namespace Utils; +#include namespace Conan::Internal { -class ConanPluginPrivate +class ConanPlugin final : public ExtensionSystem::IPlugin { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Conan.json") + public: - ConanInstallStepFactory installStepFactory; + ConanPlugin() + { + addManaged(); + addManaged(); + } }; -ConanPlugin::~ConanPlugin() -{ - delete d; -} - -void ConanPlugin::initialize() -{ - d = new ConanPluginPrivate; - conanSettings()->readSettings(ICore::settings()); - - connect(ProjectManager::instance(), &ProjectManager::projectAdded, - this, &ConanPlugin::projectAdded); -} - -static void connectTarget(Project *project, Target *target) -{ - if (!ConanPlugin::conanFilePath(project).isEmpty()) { - const QList buildConfigurations = target->buildConfigurations(); - for (BuildConfiguration *buildConfiguration : buildConfigurations) - buildConfiguration->buildSteps()->insertStep(0, Constants::INSTALL_STEP); - } - QObject::connect(target, &Target::addedBuildConfiguration, - target, [project] (BuildConfiguration *buildConfiguration) { - if (!ConanPlugin::conanFilePath(project).isEmpty()) - buildConfiguration->buildSteps()->insertStep(0, Constants::INSTALL_STEP); - }); -} - -void ConanPlugin::projectAdded(Project *project) -{ - connect(project, &Project::addedTarget, project, [project] (Target *target) { - connectTarget(project, target); - }); -} - -ConanSettings *ConanPlugin::conanSettings() -{ - static ConanSettings theSettings; - return &theSettings; -} - -FilePath ConanPlugin::conanFilePath(Project *project, const FilePath &defaultFilePath) -{ - const FilePath projectDirectory = project->projectDirectory(); - // conanfile.py takes precedence over conanfile.txt when "conan install dir" is invoked - const FilePath conanPy = projectDirectory / "conanfile.py"; - if (conanPy.exists()) - return conanPy; - const FilePath conanTxt = projectDirectory / "conanfile.txt"; - if (conanTxt.exists()) - return conanTxt; - return defaultFilePath; -} - } // Conan::Internal + +#include "conanplugin.moc" diff --git a/src/plugins/conan/conanplugin.h b/src/plugins/conan/conanplugin.h deleted file mode 100644 index 59fbe976d2e..00000000000 --- a/src/plugins/conan/conanplugin.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2018 Jochen Seemann -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include -#include - -namespace ProjectExplorer { class Project; } - -namespace Conan::Internal { - -class ConanSettings; - -class ConanPlugin final : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Conan.json") - -public: - static ConanSettings *conanSettings(); - static Utils::FilePath conanFilePath(ProjectExplorer::Project *project, - const Utils::FilePath &defaultFilePath = {}); - -private: - ~ConanPlugin() final; - void projectAdded(ProjectExplorer::Project *project); - - void initialize() final; - - class ConanPluginPrivate *d = nullptr; -}; - -} // Conan::Internal diff --git a/src/plugins/conan/conansettings.cpp b/src/plugins/conan/conansettings.cpp index 83e8f38d533..4aca2ddffbe 100644 --- a/src/plugins/conan/conansettings.cpp +++ b/src/plugins/conan/conansettings.cpp @@ -3,14 +3,22 @@ #include "conansettings.h" +#include + #include using namespace Utils; namespace Conan::Internal { +static ConanSettings *theSettings; + +ConanSettings &settings() { return *theSettings; } + ConanSettings::ConanSettings() { + theSettings = this; + setSettingsGroup("ConanSettings"); setAutoApply(false); @@ -18,6 +26,8 @@ ConanSettings::ConanSettings() conanFilePath.setSettingsKey("ConanFilePath"); conanFilePath.setExpectedKind(PathChooser::ExistingCommand); conanFilePath.setDefaultValue(HostOsInfo::withExecutableSuffix("conan")); + + readSettings(Core::ICore::settings()); } } // Conan::Internal diff --git a/src/plugins/conan/conansettings.h b/src/plugins/conan/conansettings.h index 69a836dcfe1..41b7a133188 100644 --- a/src/plugins/conan/conansettings.h +++ b/src/plugins/conan/conansettings.h @@ -15,4 +15,6 @@ public: Utils::FilePathAspect conanFilePath; }; +ConanSettings &settings(); + } // Conan::Internal From 22af1a02550fe6c0c9c807c50227ba71ab9587aa Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 17 May 2023 09:43:14 +0200 Subject: [PATCH 1137/1447] Core: Even terser layout setup for option pages Change-Id: Id39c841da70c87d47c125903b390a75c4414cc2f Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/autotest/boost/boosttestsettings.cpp | 6 +++--- src/plugins/autotest/catch/catchtestsettings.cpp | 8 +++----- src/plugins/autotest/gtest/gtestsettings.cpp | 6 +++--- src/plugins/autotest/qtest/qttestsettings.cpp | 6 +++--- src/plugins/coreplugin/dialogs/ioptionspage.cpp | 9 +++++++++ src/plugins/coreplugin/dialogs/ioptionspage.h | 1 + src/plugins/cpaster/fileshareprotocolsettingspage.cpp | 6 +++--- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp index 840647572a4..958f756bfe0 100644 --- a/src/plugins/autotest/boost/boosttestsettings.cpp +++ b/src/plugins/autotest/boost/boosttestsettings.cpp @@ -22,15 +22,15 @@ BoostTestSettings::BoostTestSettings(Id settingsId) setDisplayName(Tr::tr(BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); setSettingsGroups("Autotest", "BoostTest"); - setLayouter([this](QWidget *widget) { - Row { Form { + setLayouter([this] { + return Row { Form { logLevel, br, reportLevel, br, randomize, Row { seed }, br, systemErrors, br, fpExceptions, br, memLeaks, - }, st}.attachTo(widget); + }, st}; }); registerAspect(&logLevel); diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp index 07dac310ebe..4859efdeaae 100644 --- a/src/plugins/autotest/catch/catchtestsettings.cpp +++ b/src/plugins/autotest/catch/catchtestsettings.cpp @@ -6,8 +6,6 @@ #include "../autotestconstants.h" #include "../autotesttr.h" -#include - #include using namespace Layouting; @@ -22,8 +20,8 @@ CatchTestSettings::CatchTestSettings(Id settingsId) setDisplayName(Tr::tr("Catch Test")); setSettingsGroups("Autotest", "Catch2"); - setLayouter([this](QWidget *widget) { - Row { Form { + setLayouter([this] { + return Row { Form { showSuccess, br, breakOnFailure, br, noThrow, br, @@ -34,7 +32,7 @@ CatchTestSettings::CatchTestSettings(Id settingsId) confidenceIntervalChecked, confidenceInterval, br, warmupChecked, benchmarkWarmupTime, br, noAnalysis - }, st }.attachTo(widget); + }, st }; }); registerAspect(&abortAfter); diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp index d7302d6bd57..f6fe44135ac 100644 --- a/src/plugins/autotest/gtest/gtestsettings.cpp +++ b/src/plugins/autotest/gtest/gtestsettings.cpp @@ -23,15 +23,15 @@ GTestSettings::GTestSettings(Id settingsId) setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr(GTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setLayouter([this](QWidget *widget) { - Row { Form { + setLayouter([this] { + return Row { Form { runDisabled, br, breakOnFailure, br, repeat, iterations, br, shuffle, seed, br, groupMode, br, gtestFilter, br - }, st }.attachTo(widget); + }, st }; }); registerAspect(&iterations); diff --git a/src/plugins/autotest/qtest/qttestsettings.cpp b/src/plugins/autotest/qtest/qttestsettings.cpp index 07fac99d986..4db11ebdb17 100644 --- a/src/plugins/autotest/qtest/qttestsettings.cpp +++ b/src/plugins/autotest/qtest/qttestsettings.cpp @@ -22,8 +22,8 @@ QtTestSettings::QtTestSettings(Id settingsId) setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr(QtTest::Constants::FRAMEWORK_SETTINGS_CATEGORY)); - setLayouter([this](QWidget *widget) { - Row { Form { + setLayouter([this] { + return Row { Form { noCrashHandler, br, useXMLOutput, br, verboseBench, br, @@ -34,7 +34,7 @@ QtTestSettings::QtTestSettings(Id settingsId) Column { metrics } }, br, quickCheckForDerivedTests, br - }, st }.attachTo(widget); + }, st }; }); registerAspect(&metrics); diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index bb9b80a9133..d7646749c68 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -208,6 +208,15 @@ void IOptionsPage::setLayouter(const std::function &layouter) }; } +void IOptionsPage::setLayouter(const std::function &layouter) +{ + m_widgetCreator = [layouter] { + auto widget = new IOptionsPageWidget; + layouter().attachTo(widget); + return widget; + }; +} + /*! \fn void Core::IOptionsPage::setId(Utils::Id id) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index 96d9b6824af..a38bf863c36 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -75,6 +75,7 @@ protected: void setCategoryIconPath(const Utils::FilePath &categoryIconPath); void setSettings(Utils::AspectContainer *settings); void setLayouter(const std::function &layouter); + void setLayouter(const std::function &layouter); // Used in FontSettingsPage. FIXME? QPointer m_widget; // Used in conjunction with m_widgetCreator diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp index f3c6daad53e..dd12a68e73d 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp @@ -33,7 +33,7 @@ FileShareProtocolSettings::FileShareProtocolSettings() displayCount.setSuffix(' ' + Tr::tr("entries")); displayCount.setLabelText(Tr::tr("&Display:")); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; auto label = new QLabel(Tr::tr( @@ -41,14 +41,14 @@ FileShareProtocolSettings::FileShareProtocolSettings() "simple files on a shared network drive. Files are never deleted.")); label->setWordWrap(true); - Column { + return Column { Form { label, br, path, br, displayCount }, st - }.attachTo(widget); + }; }); readSettings(); From b1b9f54de734d7621c3c62b44aa55d713577583c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 17 May 2023 20:09:43 +0200 Subject: [PATCH 1138/1447] WebAssembly: Make caching code less cryptic Change-Id: Ib768e6f41fe8c5218875287dd0e60c76cbe0053e Reviewed-by: hjk --- src/plugins/webassembly/webassemblyemsdk.cpp | 31 ++++++++++++-------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/plugins/webassembly/webassemblyemsdk.cpp b/src/plugins/webassembly/webassemblyemsdk.cpp index 507c2949654..ad12f12e62d 100644 --- a/src/plugins/webassembly/webassemblyemsdk.cpp +++ b/src/plugins/webassembly/webassemblyemsdk.cpp @@ -16,16 +16,24 @@ using namespace Utils; namespace WebAssembly::Internal::WebAssemblyEmSdk { -using EmSdkEnvCache = QCache; -Q_GLOBAL_STATIC_WITH_ARGS(EmSdkEnvCache, emSdkEnvCache, (10)) -using EmSdkVersionCache = QCache; -Q_GLOBAL_STATIC_WITH_ARGS(EmSdkVersionCache, emSdkVersionCache, (10)) +using EmSdkEnvCache = QCache; +static EmSdkEnvCache *emSdkEnvCache() +{ + static EmSdkEnvCache cache(10); + return &cache; +} + +using EmSdkVersionCache = QCache; +static EmSdkVersionCache *emSdkVersionCache() +{ + static EmSdkVersionCache cache(10); + return &cache; +} static QString emSdkEnvOutput(const FilePath &sdkRoot) { - const QString cacheKey = sdkRoot.toString(); const bool isWindows = sdkRoot.osType() == OsTypeWindows; - if (!emSdkEnvCache()->contains(cacheKey)) { + if (!emSdkEnvCache()->contains(sdkRoot)) { const FilePath scriptFile = sdkRoot.pathAppended(QLatin1String("emsdk_env") + (isWindows ? ".bat" : ".sh")); Process emSdkEnv; @@ -37,9 +45,9 @@ static QString emSdkEnvOutput(const FilePath &sdkRoot) } emSdkEnv.runBlocking(); const QString output = emSdkEnv.allOutput(); - emSdkEnvCache()->insert(cacheKey, new QString(output)); + emSdkEnvCache()->insert(sdkRoot, new QString(output)); } - return *emSdkEnvCache()->object(cacheKey); + return *emSdkEnvCache()->object(sdkRoot); } void parseEmSdkEnvOutputAndAddToEnv(const QString &output, Environment &env) @@ -80,8 +88,7 @@ QVersionNumber version(const FilePath &sdkRoot) { if (!sdkRoot.exists()) return {}; - const QString cacheKey = sdkRoot.toString(); - if (!emSdkVersionCache()->contains(cacheKey)) { + if (!emSdkVersionCache()->contains(sdkRoot)) { Environment env = sdkRoot.deviceEnvironment(); addToEnvironment(sdkRoot, env); QLatin1String scriptFile{sdkRoot.osType() == OsType::OsTypeWindows ? "emcc.bat" : "emcc"}; @@ -92,10 +99,10 @@ QVersionNumber version(const FilePath &sdkRoot) emcc.setEnvironment(env); emcc.runBlocking(); const QString version = emcc.cleanedStdOut(); - emSdkVersionCache()->insert(cacheKey, + emSdkVersionCache()->insert(sdkRoot, new QVersionNumber(QVersionNumber::fromString(version))); } - return *emSdkVersionCache()->object(cacheKey); + return *emSdkVersionCache()->object(sdkRoot); } void clearCaches() From 40d7fcc1d402d94f9e1fd5dd12da8e4f7ad97b44 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 17 May 2023 16:34:54 +0200 Subject: [PATCH 1139/1447] Utils: Remove check against 'autoapply' for some volatile aspect value This was based on the wrong assumption that on !autoapply aspects (i.e. aspects in settings pages the non-applied value would never be needed by user code. This is, however, not the case when e.g. temporary checkbox states or values in comboboxes are used to enable/disable parts of the ui while interacting with the page. Change-Id: I4fe6a0df8137083a0a0faecc3ba20792caa5a747 Reviewed-by: Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 549a3942730..082f4f8244a 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1224,7 +1224,6 @@ void StringAspect::addToLayout(LayoutItem &parent) QVariant StringAspect::volatileValue() const { - QTC_CHECK(!isAutoApply()); switch (d->m_displayStyle) { case PathChooserDisplay: QTC_ASSERT(d->m_pathChooserDisplay, return {}); @@ -1519,7 +1518,6 @@ QAction *BoolAspect::action() QVariant BoolAspect::volatileValue() const { - QTC_CHECK(!isAutoApply()); if (d->m_button) return d->m_button->isChecked(); if (d->m_groupBox) @@ -1530,7 +1528,6 @@ QVariant BoolAspect::volatileValue() const void BoolAspect::setVolatileValue(const QVariant &val) { - QTC_CHECK(!isAutoApply()); if (d->m_button) d->m_button->setChecked(val.toBool()); else if (d->m_groupBox) @@ -1660,7 +1657,6 @@ void SelectionAspect::addToLayout(Layouting::LayoutItem &parent) QVariant SelectionAspect::volatileValue() const { - QTC_CHECK(!isAutoApply()); switch (d->m_displayStyle) { case DisplayStyle::RadioButtons: QTC_ASSERT(d->m_buttonGroup, return {}); @@ -1674,7 +1670,6 @@ QVariant SelectionAspect::volatileValue() const void SelectionAspect::setVolatileValue(const QVariant &val) { - QTC_CHECK(!isAutoApply()); switch (d->m_displayStyle) { case DisplayStyle::RadioButtons: { if (d->m_buttonGroup) { From c597961d7d53341ab216ea36ed8c41f267c7bbe2 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 17 May 2023 17:04:14 +0200 Subject: [PATCH 1140/1447] Beautifier: Simplify GeneralSettings implementation Change-Id: Ib8b8f0b1cab3d9bbacf24009c0bd546660c19906 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/beautifier/generalsettings.cpp | 9 --------- src/plugins/beautifier/generalsettings.h | 2 -- 2 files changed, 11 deletions(-) diff --git a/src/plugins/beautifier/generalsettings.cpp b/src/plugins/beautifier/generalsettings.cpp index d9ae27b3fc3..1568ae5f1bb 100644 --- a/src/plugins/beautifier/generalsettings.cpp +++ b/src/plugins/beautifier/generalsettings.cpp @@ -14,17 +14,8 @@ using namespace Utils; namespace Beautifier::Internal { -static GeneralSettings *m_instance; - -GeneralSettings *GeneralSettings::instance() -{ - return m_instance; -} - GeneralSettings::GeneralSettings() { - m_instance = this; - setId(Constants::OPTION_GENERAL_ID); setDisplayName(Tr::tr("General")); setCategory(Constants::OPTION_CATEGORY); diff --git a/src/plugins/beautifier/generalsettings.h b/src/plugins/beautifier/generalsettings.h index 2c6743301ba..5403c66410c 100644 --- a/src/plugins/beautifier/generalsettings.h +++ b/src/plugins/beautifier/generalsettings.h @@ -14,8 +14,6 @@ class GeneralSettings : public Core::PagedSettings public: GeneralSettings(); - static GeneralSettings *instance(); - QList allowedMimeTypes() const; Utils::BoolAspect autoFormatOnSave; From 0c425540deb79d42651aa308c5213ae706c1860c Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 19 May 2023 16:44:53 +0200 Subject: [PATCH 1141/1447] Fossil: Replace one qAsConst Change-Id: Ia03f9aa81d41e03b9611da823c6999082d243864 Reviewed-by: Jarek Kobus --- src/plugins/fossil/fossilplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 4979b1d1203..6792c6e42b8 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -834,7 +834,7 @@ void FossilPluginPrivate::updateActions(VcsBase::VcsBasePluginPrivate::ActionSta m_revertFile->setParameter(filename); m_statusFile->setParameter(filename); - for (QAction *repoAction : qAsConst(m_repositoryActionList)) + for (QAction *repoAction : std::as_const(m_repositoryActionList)) repoAction->setEnabled(repoEnabled); } From 2274847bfe517ec4889b01fd5eaef11b9161bfe0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 19 May 2023 16:35:29 +0200 Subject: [PATCH 1142/1447] tst_SubDirFileIterator: Fix build with Qt < 6.3 QDirIterator::nextFileInfo() was introduced in Qt 6.3. Change-Id: I3ed6293d4262b0ff2bb4423eb37c35c7b3650e97 Reviewed-by: hjk --- tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp b/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp index 4093030a719..66dd7737816 100644 --- a/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp +++ b/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp @@ -233,7 +233,12 @@ private slots: QDirIterator it(m_tempDir->path(), s_filters, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); while (it.hasNext()) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) const QFileInfo fi = it.nextFileInfo(); +#else + it.next(); + const QFileInfo fi = it.fileInfo(); +#endif if (fi.isDir()) { ++dirsCount; } else { From 6f31d874441050738e83af8dad920b178fc6998b Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 17 May 2023 17:18:11 +0200 Subject: [PATCH 1143/1447] Use more FilePathAspect Change-Id: Ib348df1460f8610607251498b07010df58d51ddf Reviewed-by: Alessandro Portale --- src/plugins/beautifier/generalsettings.cpp | 8 +++----- .../cmakebuildconfiguration.cpp | 4 ++-- .../cmakeprojectmanager/cmakeformatter.cpp | 5 ++--- .../cmakeprojectmanager/cmakekitinformation.cpp | 2 +- .../cmakespecificsettings.cpp | 6 +++--- .../cmakeprojectmanager/cmakespecificsettings.h | 2 +- src/plugins/cppcheck/cppcheckoptions.cpp | 1 - src/plugins/cppcheck/cppcheckoptions.h | 2 +- src/plugins/cppcheck/cppchecktool.cpp | 2 +- src/plugins/docker/dockerapi.cpp | 2 +- src/plugins/docker/dockerdevice.cpp | 12 ++++++------ src/plugins/docker/dockersettings.cpp | 9 +++------ src/plugins/docker/dockersettings.h | 2 +- src/plugins/fossil/fossilclient.cpp | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/git/gitplugin.cpp | 2 +- src/plugins/git/gitsettings.cpp | 10 ++++------ src/plugins/git/gitsettings.h | 2 +- src/plugins/gitlab/gitlaboptionspage.cpp | 7 +++---- src/plugins/haskell/haskellmanager.cpp | 2 +- src/plugins/haskell/haskellrunconfiguration.cpp | 2 +- src/plugins/haskell/haskellsettings.cpp | 11 ++++------- src/plugins/haskell/haskellsettings.h | 2 +- src/plugins/haskell/stackbuildstep.cpp | 2 +- src/plugins/mercurial/mercurialplugin.cpp | 2 +- src/plugins/subversion/subversionplugin.cpp | 16 ++++++++-------- 26 files changed, 53 insertions(+), 66 deletions(-) diff --git a/src/plugins/beautifier/generalsettings.cpp b/src/plugins/beautifier/generalsettings.cpp index 1568ae5f1bb..1f6d515d8e7 100644 --- a/src/plugins/beautifier/generalsettings.cpp +++ b/src/plugins/beautifier/generalsettings.cpp @@ -22,8 +22,6 @@ GeneralSettings::GeneralSettings() setDisplayCategory(Tr::tr("Beautifier")); setCategoryIconPath(":/beautifier/images/settingscategory_beautifier.png"); setSettingsGroups("Beautifier", "General"); - setSettings(this); - setAutoApply(false); registerAspect(&autoFormatOnSave); autoFormatOnSave.setSettingsKey(Utils::Constants::BEAUTIFIER_AUTO_FORMAT_ON_SAVE); @@ -47,9 +45,9 @@ GeneralSettings::GeneralSettings() autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:")); autoFormatMime.setDisplayStyle(StringAspect::LineEditDisplay); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title(Tr::tr("Automatic Formatting on File Save")), autoFormatOnSave.groupChecker(), @@ -60,7 +58,7 @@ GeneralSettings::GeneralSettings() } }, st - }.attachTo(widget); + }; }); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index c13cf8709c1..7a6a192e80f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -2079,8 +2079,8 @@ void CMakeBuildConfiguration::addToEnvironment(Utils::Environment &env) const return; auto settings = CMakeSpecificSettings::instance(); - if (!settings->ninjaPath.filePath().isEmpty()) { - const Utils::FilePath ninja = settings->ninjaPath.filePath(); + if (!settings->ninjaPath().isEmpty()) { + const Utils::FilePath ninja = settings->ninjaPath(); env.appendOrSetPath(ninja.isFile() ? ninja.parentDir() : ninja); } } diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp index 778e04563da..e12ab4b278d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp @@ -52,7 +52,6 @@ public: registerAspect(&command); command.setSettingsKey("autoFormatCommand"); - command.setDisplayStyle(StringAspect::PathChooserDisplay); command.setDefaultValue("cmake-format"); command.setExpectedKind(PathChooser::ExistingCommand); @@ -121,14 +120,14 @@ public: TextEditor::Command formatCommand() const { TextEditor::Command cmd; - cmd.setExecutable(command.filePath()); + cmd.setExecutable(command()); cmd.setProcessing(TextEditor::Command::FileProcessing); cmd.addOption("--in-place"); cmd.addOption("%file"); return cmd; } - StringAspect command; + FilePathAspect command; BoolAspect autoFormatOnSave; BoolAspect autoFormatOnlyCurrentProject; StringAspect autoFormatMime; diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index ee7cd5f1c1b..def549f5800 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -678,7 +678,7 @@ QVariant CMakeGeneratorKitAspect::defaultValue(const Kit *k) const if (it != known.constEnd()) { const bool hasNinja = [k, tool] { auto settings = Internal::CMakeSpecificSettings::instance(); - if (settings->ninjaPath.filePath().isEmpty()) { + if (settings->ninjaPath().isEmpty()) { auto findNinja = [](const Environment &env) -> bool { return !env.searchInPath("ninja").isEmpty(); }; diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index 7875f97ada2..e343158f569 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -32,9 +32,9 @@ CMakeSpecificSettings::CMakeSpecificSettings() setCategory(Constants::Settings::CATEGORY); setCategoryIconPath(Constants::Icons::SETTINGS_CATEGORY); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { autorunCMake, packageManagerAutoSetup, askBeforeReConfigureInitialParams, @@ -42,7 +42,7 @@ CMakeSpecificSettings::CMakeSpecificSettings() showSourceSubFolders, showAdvancedOptionsByDefault, st - }.attachTo(widget); + }; }); // TODO: fixup of QTCREATORBUG-26289 , remove in Qt Creator 7 or so diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h index 472945e1a5f..9ed848e4749 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h @@ -15,7 +15,7 @@ public: static CMakeSpecificSettings *instance(); Utils::BoolAspect autorunCMake; - Utils::StringAspect ninjaPath; + Utils::FilePathAspect ninjaPath; Utils::BoolAspect packageManagerAutoSetup; Utils::BoolAspect askBeforeReConfigureInitialParams; Utils::BoolAspect askBeforePresetsReload; diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp index 37f537f2fee..22f728f8f11 100644 --- a/src/plugins/cppcheck/cppcheckoptions.cpp +++ b/src/plugins/cppcheck/cppcheckoptions.cpp @@ -36,7 +36,6 @@ CppcheckOptions::CppcheckOptions() registerAspect(&binary); binary.setSettingsKey("binary"); - binary.setDisplayStyle(StringAspect::PathChooserDisplay); binary.setExpectedKind(PathChooser::ExistingCommand); binary.setCommandVersionArguments({"--version"}); binary.setLabelText(Tr::tr("Binary:")); diff --git a/src/plugins/cppcheck/cppcheckoptions.h b/src/plugins/cppcheck/cppcheckoptions.h index 84fbf483bbb..5a617b1241c 100644 --- a/src/plugins/cppcheck/cppcheckoptions.h +++ b/src/plugins/cppcheck/cppcheckoptions.h @@ -17,7 +17,7 @@ public: std::function layouter(); - Utils::StringAspect binary; + Utils::FilePathAspect binary; Utils::BoolAspect warning; Utils::BoolAspect style; Utils::BoolAspect performance; diff --git a/src/plugins/cppcheck/cppchecktool.cpp b/src/plugins/cppcheck/cppchecktool.cpp index bd44957c379..cd824b3db47 100644 --- a/src/plugins/cppcheck/cppchecktool.cpp +++ b/src/plugins/cppcheck/cppchecktool.cpp @@ -100,7 +100,7 @@ void CppcheckTool::updateArguments() arguments.push_back("--template=\"{file},{line},{severity},{id},{message}\""); - m_runner->reconfigure(m_options.binary.filePath(), arguments.join(' ')); + m_runner->reconfigure(m_options.binary(), arguments.join(' ')); } QStringList CppcheckTool::additionalArguments(const CppEditor::ProjectPart &part) const diff --git a/src/plugins/docker/dockerapi.cpp b/src/plugins/docker/dockerapi.cpp index ffc14148597..baa9ed6be9f 100644 --- a/src/plugins/docker/dockerapi.cpp +++ b/src/plugins/docker/dockerapi.cpp @@ -103,7 +103,7 @@ std::optional DockerApi::isDockerDaemonAvailable(bool async) FilePath DockerApi::dockerClient() { - return FilePath::fromString(m_settings->dockerBinaryPath.value()); + return m_settings->dockerBinaryPath(); } } // Docker::Internal diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index b87c198555a..2dd2a589f72 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -99,7 +99,7 @@ public: private: void setupShellProcess(Process *shellProcess) final { - shellProcess->setCommand({m_settings->dockerBinaryPath.filePath(), + shellProcess->setCommand({m_settings->dockerBinaryPath(), {"container", "start", "-i", "-a", m_containerId}}); } @@ -498,7 +498,7 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, if (!updateContainerAccess()) return {}; - CommandLine dockerCmd{m_settings->dockerBinaryPath.filePath(), {"exec"}}; + CommandLine dockerCmd{m_settings->dockerBinaryPath(), {"exec"}}; if (interactive) dockerCmd.addArg("-i"); @@ -555,7 +555,7 @@ void DockerDevicePrivate::stopCurrentContainer() } Process proc; - proc.setCommand({m_settings->dockerBinaryPath.filePath(), {"container", "stop", m_container}}); + proc.setCommand({m_settings->dockerBinaryPath(), {"container", "stop", m_container}}); m_container.clear(); @@ -660,7 +660,7 @@ bool DockerDevicePrivate::isImageAvailable() const { Process proc; proc.setCommand( - {m_settings->dockerBinaryPath.filePath(), + {m_settings->dockerBinaryPath(), {"image", "list", m_data.repoAndTag(), "--format", "{{.Repository}}:{{.Tag}}"}}); proc.runBlocking(); if (proc.result() != ProcessResult::FinishedWithSuccess) @@ -682,7 +682,7 @@ bool DockerDevicePrivate::createContainer() const QString display = HostOsInfo::isLinuxHost() ? QString(":0") : QString("host.docker.internal:0"); - CommandLine dockerCreate{m_settings->dockerBinaryPath.filePath(), + CommandLine dockerCreate{m_settings->dockerBinaryPath(), {"create", "-i", "--rm", @@ -1053,7 +1053,7 @@ public: connect(m_buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); m_buttons->button(QDialogButtonBox::Ok)->setEnabled(false); - CommandLine cmd{m_settings->dockerBinaryPath.filePath(), + CommandLine cmd{m_settings->dockerBinaryPath(), {"images", "--format", "{{.ID}}\\t{{.Repository}}\\t{{.Tag}}\\t{{.Size}}"}}; m_log->append(Tr::tr("Running \"%1\"\n").arg(cmd.toUserOutput())); diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp index a43e7a20d3b..a5dfc8581fc 100644 --- a/src/plugins/docker/dockersettings.cpp +++ b/src/plugins/docker/dockersettings.cpp @@ -8,7 +8,6 @@ #include -#include #include #include @@ -23,17 +22,16 @@ DockerSettings::DockerSettings() setDisplayName(Tr::tr("Docker")); setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - // clang-format off - Column { + return Column { Group { title(Tr::tr("Configuration")), Row { dockerBinaryPath } }, st - }.attachTo(widget); + }; // clang-format on }); @@ -44,7 +42,6 @@ DockerSettings::DockerSettings() additionalPaths.append("/usr/local/bin"); registerAspect(&dockerBinaryPath); - dockerBinaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); dockerBinaryPath.setExpectedKind(PathChooser::ExistingCommand); dockerBinaryPath.setDefaultFilePath( FilePath::fromString("docker").searchInPath(additionalPaths)); diff --git a/src/plugins/docker/dockersettings.h b/src/plugins/docker/dockersettings.h index e6f8f1ec1fb..92b2f374ccf 100644 --- a/src/plugins/docker/dockersettings.h +++ b/src/plugins/docker/dockersettings.h @@ -12,7 +12,7 @@ class DockerSettings final : public Core::PagedSettings public: DockerSettings(); - Utils::StringAspect dockerBinaryPath; + Utils::FilePathAspect dockerBinaryPath; }; } // Docker::Internal diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index 83a2938f91e..49ded9c7740 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -232,7 +232,7 @@ FossilClient::FossilClient() unsigned int FossilClient::synchronousBinaryVersion() const { - if (settings().binaryPath.value().isEmpty()) + if (settings().binaryPath().isEmpty()) return 0; const CommandResult result = vcsSynchronousExec({}, QStringList{"version"}); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index bda248be63c..3b4a748c0c1 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2422,7 +2422,7 @@ void GitClient::launchGitK(const FilePath &workingDirectory, const QString &file void GitClient::launchRepositoryBrowser(const FilePath &workingDirectory) const { - const FilePath repBrowserBinary = settings().repositoryBrowserCmd.filePath(); + const FilePath repBrowserBinary = settings().repositoryBrowserCmd(); if (!repBrowserBinary.isEmpty()) Process::startDetached({repBrowserBinary, {workingDirectory.toString()}}, workingDirectory); } diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 2b9f908ff86..e4fc95be8cb 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -2001,7 +2001,7 @@ QObject *GitPlugin::remoteCommand(const QStringList &options, const QString &wor void GitPluginPrivate::updateRepositoryBrowserAction() { const bool repositoryEnabled = currentState().hasTopLevel(); - const bool hasRepositoryBrowserCmd = !settings().repositoryBrowserCmd.value().isEmpty(); + const bool hasRepositoryBrowserCmd = !settings().repositoryBrowserCmd().isEmpty(); m_repositoryBrowserAction->setEnabled(repositoryEnabled && hasRepositoryBrowserCmd); } diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index f092dd74e92..5f65fa2f1b8 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -94,7 +94,6 @@ GitSettings::GitSettings() logDiff.setToolTip(Tr::tr("Note that huge amount of commits might take some time.")); registerAspect(&repositoryBrowserCmd); - repositoryBrowserCmd.setDisplayStyle(StringAspect::PathChooserDisplay); repositoryBrowserCmd.setSettingsKey("RepositoryBrowserCmd"); repositoryBrowserCmd.setExpectedKind(PathChooser::ExistingCommand); repositoryBrowserCmd.setHistoryCompleter("Git.RepoCommand.History"); @@ -130,10 +129,9 @@ GitSettings::GitSettings() timeout.setDefaultValue(Utils::HostOsInfo::isWindowsHost() ? 60 : 30); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - - Column { + return Column { Group { title(Tr::tr("Configuration")), Column { @@ -166,7 +164,7 @@ GitSettings::GitSettings() }, st - }.attachTo(widget); + }; }); connect(&binaryPath, &StringAspect::valueChanged, this, [this] { tryResolve = true; }); connect(&path, &StringAspect::valueChanged, this, [this] { tryResolve = true; }); @@ -181,7 +179,7 @@ FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const errorMessage->clear(); if (tryResolve) { - resolvedBinPath = binaryPath.filePath(); + resolvedBinPath = binaryPath(); if (!resolvedBinPath.isAbsolutePath()) resolvedBinPath = resolvedBinPath.searchInPath({path.filePath()}, FilePath::PrependToPath); tryResolve = false; diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index 3899fdada58..0b82146b042 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -30,7 +30,7 @@ public: Utils::BoolAspect winSetHomeEnvironment; Utils::StringAspect gitkOptions; Utils::BoolAspect logDiff; - Utils::StringAspect repositoryBrowserCmd; + Utils::FilePathAspect repositoryBrowserCmd; Utils::BoolAspect graphLog; Utils::BoolAspect colorLog; Utils::BoolAspect firstParent; diff --git a/src/plugins/gitlab/gitlaboptionspage.cpp b/src/plugins/gitlab/gitlaboptionspage.cpp index c2e56d5730b..4660cc92bb5 100644 --- a/src/plugins/gitlab/gitlaboptionspage.cpp +++ b/src/plugins/gitlab/gitlaboptionspage.cpp @@ -148,7 +148,7 @@ private: QPushButton *m_remove = nullptr; QPushButton *m_add = nullptr; QComboBox *m_defaultGitLabServer = nullptr; - Utils::StringAspect m_curl; + FilePathAspect m_curl; }; GitLabOptionsWidget::GitLabOptionsWidget(GitLabParameters *params) @@ -156,9 +156,8 @@ GitLabOptionsWidget::GitLabOptionsWidget(GitLabParameters *params) { auto defaultLabel = new QLabel(Tr::tr("Default:"), this); m_defaultGitLabServer = new QComboBox(this); - m_curl.setDisplayStyle(Utils::StringAspect::DisplayStyle::PathChooserDisplay); m_curl.setLabelText(Tr::tr("curl:")); - m_curl.setExpectedKind(Utils::PathChooser::ExistingCommand); + m_curl.setExpectedKind(PathChooser::ExistingCommand); m_gitLabServerWidget = new GitLabServerWidget(GitLabServerWidget::Display, this); @@ -208,7 +207,7 @@ GitLabOptionsWidget::GitLabOptionsWidget(GitLabParameters *params) result.gitLabServers.append(m_defaultGitLabServer->itemData(i).value()); if (m_defaultGitLabServer->count()) result.defaultGitLabServer = m_defaultGitLabServer->currentData().value().id; - result.curl = m_curl.filePath(); + result.curl = m_curl(); if (result != *m_parameters) { m_parameters->assign(result); diff --git a/src/plugins/haskell/haskellmanager.cpp b/src/plugins/haskell/haskellmanager.cpp index 94a03ec659e..cc91ae7f816 100644 --- a/src/plugins/haskell/haskellmanager.cpp +++ b/src/plugins/haskell/haskellmanager.cpp @@ -46,7 +46,7 @@ void HaskellManager::openGhci(const FilePath &haskellFile) + (isHaskell ? QStringList{haskellFile.fileName()} : QStringList()); Process p; p.setTerminalMode(TerminalMode::Detached); - p.setCommand({settings().stackPath.filePath(), args}); + p.setCommand({settings().stackPath(), args}); p.setWorkingDirectory(haskellFile.absolutePath()); p.start(); } diff --git a/src/plugins/haskell/haskellrunconfiguration.cpp b/src/plugins/haskell/haskellrunconfiguration.cpp index 9c236c65b5e..c4caf175058 100644 --- a/src/plugins/haskell/haskellrunconfiguration.cpp +++ b/src/plugins/haskell/haskellrunconfiguration.cpp @@ -68,7 +68,7 @@ Runnable HaskellRunConfiguration::runnable() const r.workingDirectory = projectDirectory; r.environment = aspect()->environment(); - r.command = {r.environment.searchInPath(settings().stackPath()), args}; + r.command = {r.environment.searchInPath(settings().stackPath().path()), args}; return r; } diff --git a/src/plugins/haskell/haskellsettings.cpp b/src/plugins/haskell/haskellsettings.cpp index 6b0ee170368..e4993020b7f 100644 --- a/src/plugins/haskell/haskellsettings.cpp +++ b/src/plugins/haskell/haskellsettings.cpp @@ -6,10 +6,7 @@ #include "haskellconstants.h" #include "haskelltr.h" -#include - #include -#include #include using namespace Utils; @@ -46,18 +43,18 @@ HaskellSettings::HaskellSettings() ? FilePath::fromString("/usr/local/bin/stack") : FilePath::fromString("stack")); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title(Tr::tr("General")), Row { Tr::tr("Stack executable:"), stackPath } }, st, - }.attachTo(widget); + }; }); - readSettings(Core::ICore::settings()); + readSettings(); } } // Haskell::Internal diff --git a/src/plugins/haskell/haskellsettings.h b/src/plugins/haskell/haskellsettings.h index c697a154ee4..3b0d374c792 100644 --- a/src/plugins/haskell/haskellsettings.h +++ b/src/plugins/haskell/haskellsettings.h @@ -12,7 +12,7 @@ class HaskellSettings : public Core::PagedSettings public: HaskellSettings(); - Utils::StringAspect stackPath; + Utils::FilePathAspect stackPath; }; HaskellSettings &settings(); diff --git a/src/plugins/haskell/stackbuildstep.cpp b/src/plugins/haskell/stackbuildstep.cpp index 860ef458c5f..4006ae9daad 100644 --- a/src/plugins/haskell/stackbuildstep.cpp +++ b/src/plugins/haskell/stackbuildstep.cpp @@ -38,7 +38,7 @@ bool StackBuildStep::init() if (AbstractProcessStep::init()) { const auto projectDir = QDir(project()->projectDirectory().toString()); processParameters()->setCommandLine( - {settings().stackPath.filePath(), + {settings().stackPath(), {"build", "--work-dir", projectDir.relativeFilePath(buildDirectory().toString())}}); processParameters()->setEnvironment(buildEnvironment()); } diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 05b3524b4de..cc294cad57a 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -783,7 +783,7 @@ VcsCommand *MercurialPluginPrivate::createInitialCheckoutCommand(const QString & QStringList args; args << QLatin1String("clone") << extraArgs << url << localName; auto command = VcsBaseClient::createVcsCommand(baseDirectory, m_client.processEnvironment()); - command->addJob({settings().binaryPath.filePath(), args}, -1); + command->addJob({settings().binaryPath(), args}, -1); return command; } diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 5cb7475edb0..e584d981818 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -863,7 +863,7 @@ void SubversionPluginPrivate::vcsAnnotateHelper(const FilePath &workingDir, cons const FilePath source = VcsBaseEditor::getSource(workingDir, file); QTextCodec *codec = VcsBaseEditor::getCodec(source); - CommandLine args{settings().binaryPath.filePath(), {"annotate"}}; + CommandLine args{settings().binaryPath(), {"annotate"}}; args << SubversionClient::AddAuthOptions(); if (settings().spaceIgnorantAnnotation.value()) args << "-x" << "-uw"; @@ -1006,7 +1006,7 @@ QString SubversionPluginPrivate::synchronousTopic(const FilePath &repository) co bool SubversionPluginPrivate::vcsAdd(const FilePath &workingDir, const QString &rawFileName) { const QString file = QDir::toNativeSeparators(SubversionClient::escapeFile(rawFileName)); - CommandLine args{settings().binaryPath.filePath()}; + CommandLine args{settings().binaryPath()}; args << "add" << SubversionClient::AddAuthOptions() << "--parents" << file; return runSvn(workingDir, args, RunFlags::ShowStdOut).result() == ProcessResult::FinishedWithSuccess; @@ -1016,7 +1016,7 @@ bool SubversionPluginPrivate::vcsDelete(const FilePath &workingDir, const QStrin { const QString file = QDir::toNativeSeparators(SubversionClient::escapeFile(rawFileName)); - CommandLine args{settings().binaryPath.filePath()}; + CommandLine args{settings().binaryPath()}; args << "delete" << SubversionClient::AddAuthOptions() << "--force" << file; return runSvn(workingDir, args, RunFlags::ShowStdOut).result() @@ -1025,7 +1025,7 @@ bool SubversionPluginPrivate::vcsDelete(const FilePath &workingDir, const QStrin bool SubversionPluginPrivate::vcsMove(const FilePath &workingDir, const QString &from, const QString &to) { - CommandLine args{settings().binaryPath.filePath(), {"move"}}; + CommandLine args{settings().binaryPath(), {"move"}}; args << SubversionClient::AddAuthOptions() << QDir::toNativeSeparators(SubversionClient::escapeFile(from)) << QDir::toNativeSeparators(SubversionClient::escapeFile(to)); @@ -1038,7 +1038,7 @@ bool SubversionPluginPrivate::vcsCheckout(const FilePath &directory, const QByte QUrl tempUrl = QUrl::fromEncoded(url); const QString username = tempUrl.userName(); const QString password = tempUrl.password(); - CommandLine args{settings().binaryPath.filePath(), {"checkout"}}; + CommandLine args{settings().binaryPath(), {"checkout"}}; args << Constants::NON_INTERACTIVE_OPTION; if (!username.isEmpty()) { @@ -1085,7 +1085,7 @@ bool SubversionPluginPrivate::managesDirectory(const FilePath &directory, FilePa bool SubversionPluginPrivate::managesFile(const FilePath &workingDirectory, const QString &fileName) const { - CommandLine args{settings().binaryPath.filePath()}; + CommandLine args{settings().binaryPath()}; args << "status" << SubversionClient::AddAuthOptions() << QDir::toNativeSeparators(SubversionClient::escapeFile(fileName)); const QString output = runSvn(workingDirectory, args).cleanedStdOut(); @@ -1124,7 +1124,7 @@ bool SubversionPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) con bool SubversionPluginPrivate::isConfigured() const { - const FilePath binary = settings().binaryPath.filePath(); + const FilePath binary = settings().binaryPath(); if (binary.isEmpty()) return false; QFileInfo fi = binary.toFileInfo(); @@ -1187,7 +1187,7 @@ VcsCommand *SubversionPluginPrivate::createInitialCheckoutCommand(const QString const QString &localName, const QStringList &extraArgs) { - CommandLine args{settings().binaryPath.filePath()}; + CommandLine args{settings().binaryPath()}; args << "checkout"; args << SubversionClient::AddAuthOptions(); args << Subversion::Constants::NON_INTERACTIVE_OPTION << extraArgs << url << localName; From ceff14303a39df571b062de0b0289e21fda07856 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 2 May 2023 09:28:52 +0200 Subject: [PATCH 1144/1447] TaskTree: Prepare for OnGroup... -> onGroup... renaming Change-Id: I52b695999b53b80fb8dbb77895080f6c1b86a58f Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 4 ++-- src/plugins/autotest/testrunner.cpp | 10 +++++----- src/plugins/clangtools/clangtoolrunner.cpp | 4 ++-- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 10 +++++----- src/plugins/coreplugin/locator/javascriptfilter.cpp | 12 ++++++------ src/plugins/qmakeprojectmanager/qmakestep.cpp | 12 ++++++------ 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 32e7f3eadd5..8e79485a8f3 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -976,11 +976,11 @@ void TaskNode::invokeEndHandler(bool success) tasks. The group handler doesn't take any arguments: \code - const auto onGroupSetup = [] { + const auto onSetup = [] { qDebug() << "Entering the group"; }; const Group root { - OnGroupSetup(onGroupSetup), + OnGroupSetup(onSetup), ProcessTask(...) }; \endcode diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 68dddaf9511..58192741855 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -353,7 +353,7 @@ void TestRunner::runTestsHelper() QTC_ASSERT(config, continue); const TreeStorage storage; - const auto onGroupSetup = [this, config] { + const auto onSetup = [this, config] { if (!config->project()) return TaskAction::StopWithDone; if (config->testExecutable().isEmpty()) { @@ -363,7 +363,7 @@ void TestRunner::runTestsHelper() } return TaskAction::Continue; }; - const auto onSetup = [this, config, storage](Process &process) { + const auto onProcessSetup = [this, config, storage](Process &process) { TestStorage *testStorage = storage.activeStorage(); QTC_ASSERT(testStorage, return); testStorage->m_outputReader.reset(config->createOutputReader(&process)); @@ -410,7 +410,7 @@ void TestRunner::runTestsHelper() qCInfo(runnerLog) << "Working directory:" << process.workingDirectory(); qCDebug(runnerLog) << "Environment:" << process.environment().toStringList(); }; - const auto onDone = [this, config, storage](const Process &process) { + const auto onProcessDone = [this, config, storage](const Process &process) { TestStorage *testStorage = storage.activeStorage(); QTC_ASSERT(testStorage, return); if (process.result() == ProcessResult::StartFailed) { @@ -444,8 +444,8 @@ void TestRunner::runTestsHelper() const Group group { optional, Storage(storage), - OnGroupSetup(onGroupSetup), - ProcessTask(onSetup, onDone, onDone) + OnGroupSetup(onSetup), + ProcessTask(onProcessSetup, onProcessDone, onProcessDone) }; tasks.append(group); } diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 9d27e9f49b5..8afdd60f186 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -121,7 +121,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, return result; }; - const auto onGroupSetup = [=] { + const auto onSetup = [=] { if (setupHandler && !setupHandler()) return TaskAction::StopWithError; @@ -184,7 +184,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, const Group group { Storage(storage), - OnGroupSetup(onGroupSetup), + OnGroupSetup(onSetup), Group { optional, ProcessTask(onProcessSetup, onProcessDone, onProcessError) diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 18f9dfd29d7..31f23cafd24 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -452,7 +452,7 @@ void LocatorMatcher::start() QList parallelTasks { ParallelLimit(d->m_parallelLimit) }; - const auto onGroupSetup = [this, collectorStorage](const TreeStorage &storage, + const auto onSetup = [this, collectorStorage](const TreeStorage &storage, int index) { return [this, collectorStorage, storage, index] { ResultsCollector *collector = collectorStorage->m_collector; @@ -462,7 +462,7 @@ void LocatorMatcher::start() }; }; - const auto onGroupDone = [](const TreeStorage &storage) { + const auto onDone = [](const TreeStorage &storage) { return [storage] { storage->finalize(); }; }; @@ -472,9 +472,9 @@ void LocatorMatcher::start() const Group group { optional, Storage(storage), - OnGroupSetup(onGroupSetup(storage, index)), - OnGroupDone(onGroupDone(storage)), - OnGroupError(onGroupDone(storage)), + OnGroupSetup(onSetup(storage, index)), + OnGroupDone(onDone(storage)), + OnGroupError(onDone(storage)), task.task }; parallelTasks << group; diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index ea5a832c984..e5cad19baa9 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -371,7 +371,7 @@ LocatorMatcherTasks JavaScriptFilter::matchers() m_javaScriptEngine.reset(new JavaScriptEngine); QPointer engine = m_javaScriptEngine.get(); - const auto onGroupSetup = [storage, engine] { + const auto onSetup = [storage, engine] { if (!engine) return TaskAction::StopWithError; if (storage->input().trimmed().isEmpty()) { @@ -391,11 +391,11 @@ LocatorMatcherTasks JavaScriptFilter::matchers() return TaskAction::Continue; }; - const auto onSetup = [storage, engine](JavaScriptRequest &request) { + const auto onJavaScriptSetup = [storage, engine](JavaScriptRequest &request) { request.setEngine(engine); request.setEvaluateData(storage->input()); }; - const auto onDone = [storage](const JavaScriptRequest &request) { + const auto onJavaScriptDone = [storage](const JavaScriptRequest &request) { const auto acceptor = [](const QString &clipboardContents) { return [clipboardContents] { QGuiApplication::clipboard()->setText(clipboardContents); @@ -419,15 +419,15 @@ LocatorMatcherTasks JavaScriptFilter::matchers() storage->reportOutput({entry, copyResultEntry, copyExpressionEntry}); }; - const auto onError = [storage](const JavaScriptRequest &request) { + const auto onJavaScriptError = [storage](const JavaScriptRequest &request) { LocatorFilterEntry entry; entry.displayName = request.output().m_output; storage->reportOutput({entry}); }; const Group root { - OnGroupSetup(onGroupSetup), - JavaScriptRequestTask(onSetup, onDone, onError) + OnGroupSetup(onSetup), + JavaScriptRequestTask(onJavaScriptSetup, onJavaScriptDone, onJavaScriptError) }; return {{root, storage}}; diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 010d160823b..2f257977a81 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -300,13 +300,13 @@ void QMakeStep::doRun() setupProcess(&process); }; - const auto onDone = [this](const Process &) { + const auto onProcessDone = [this](const Process &) { const QString command = displayedParameters()->effectiveCommand().toUserOutput(); emit addOutput(Tr::tr("The process \"%1\" exited normally.").arg(command), OutputFormat::NormalMessage); }; - const auto onError = [this](const Process &process) { + const auto onProcessError = [this](const Process &process) { const QString command = displayedParameters()->effectiveCommand().toUserOutput(); if (process.result() == ProcessResult::FinishedWithError) { emit addOutput(Tr::tr("The process \"%1\" exited with code %2.") @@ -326,14 +326,14 @@ void QMakeStep::doRun() m_needToRunQMake = true; }; - const auto onGroupDone = [this] { + const auto onDone = [this] { emit buildConfiguration()->buildDirectoryInitialized(); }; - QList processList = {ProcessTask(setupQMake, onDone, onError)}; + QList processList = {ProcessTask(setupQMake, onProcessDone, onProcessError)}; if (m_runMakeQmake) - processList << ProcessTask(setupMakeQMake, onDone, onError); - processList << OnGroupDone(onGroupDone); + processList << ProcessTask(setupMakeQMake, onProcessDone, onProcessError); + processList << OnGroupDone(onDone); runTaskTree(Group(processList)); } From 04382d39a07b31f28ac1a75b66dd729c200a782c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 17 May 2023 19:57:23 +0200 Subject: [PATCH 1145/1447] TaskTree: Introduce onGroup...() functions The OnGroup... elements are going to be replaced with these functions. Change-Id: Ia271a89062cc9c6b18384607b20b1f68d273bcde Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 10 ++++++ src/libs/solutions/tasking/tasktree.h | 44 +++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 8e79485a8f3..06a3804f9dd 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -40,6 +40,16 @@ private: Guard &m_guard; }; +TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler) +{ + return Group::onGroupDone(handler); +} + +TaskItem onGroupError(const TaskItem::GroupEndHandler &handler) +{ + return Group::onGroupError(handler); +} + static TaskAction toTaskAction(bool success) { return success ? TaskAction::StopWithDone : TaskAction::StopWithError; diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 407db58b0ae..08391d9d633 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -183,6 +183,7 @@ protected: void setTaskSetupHandler(const TaskSetupHandler &handler); void setTaskDoneHandler(const TaskEndHandler &handler); void setTaskErrorHandler(const TaskEndHandler &handler); + static TaskItem createGroupHandler(const GroupHandler &handler) { return TaskItem(handler); } private: Type m_type = Type::Group; @@ -199,8 +200,47 @@ class TASKING_EXPORT Group : public TaskItem public: Group(const QList &children) { addChildren(children); } Group(std::initializer_list children) { addChildren(children); } + + template + static TaskItem onGroupSetup(SetupHandler &&handler) { + return createGroupHandler({wrapGroupSetup(std::forward(handler))}); + } + static TaskItem onGroupDone(const GroupEndHandler &handler) { + return createGroupHandler({{}, handler}); + } + static TaskItem onGroupError(const GroupEndHandler &handler) { + return createGroupHandler({{}, {}, handler}); + } + +private: + template + static GroupSetupHandler wrapGroupSetup(SetupHandler &&handler) + { + static constexpr bool isDynamic + = std::is_same_v>>; + constexpr bool isVoid + = std::is_same_v>>; + static_assert(isDynamic || isVoid, + "Group setup handler needs to take no arguments and has to return " + "void or TaskAction. The passed handler doesn't fulfill these requirements."); + return [=] { + if constexpr (isDynamic) + return std::invoke(handler); + std::invoke(handler); + return TaskAction::Continue; + }; + }; }; +template +static TaskItem onGroupSetup(SetupHandler &&handler) +{ + return Group::onGroupSetup(std::forward(handler)); +} + +TASKING_EXPORT TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler); +TASKING_EXPORT TaskItem onGroupError(const TaskItem::GroupEndHandler &handler); + class TASKING_EXPORT Storage : public TaskItem { public: @@ -276,10 +316,10 @@ private: static_assert(isBool || isVoid, "Sync element: The synchronous function has to return void or bool."); if constexpr (isBool) { - return {OnGroupSetup([function] { return function() ? TaskAction::StopWithDone + return {onGroupSetup([function] { return function() ? TaskAction::StopWithDone : TaskAction::StopWithError; })}; } - return {OnGroupSetup([function] { function(); return TaskAction::StopWithDone; })}; + return {onGroupSetup([function] { function(); return TaskAction::StopWithDone; })}; }; }; From 0793b945f3b88bb652bf4e23a67a8d4a568e7873 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 2 May 2023 12:31:16 +0200 Subject: [PATCH 1146/1447] TaskTree: Replace usages of OnGroup... with onGroup... functions Change-Id: I06ce6c917ac28b6362ad2cdef42355e5aa28f4eb Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/plugins/autotest/testrunner.cpp | 2 +- src/plugins/clangtools/clangtoolrunner.cpp | 2 +- .../coreplugin/locator/directoryfilter.cpp | 2 +- .../coreplugin/locator/ilocatorfilter.cpp | 6 +- .../coreplugin/locator/javascriptfilter.cpp | 2 +- src/plugins/coreplugin/locator/locator.cpp | 2 +- src/plugins/cppeditor/cppprojectupdater.cpp | 4 +- src/plugins/diffeditor/diffeditorplugin.cpp | 4 +- src/plugins/git/branchmodel.cpp | 4 +- src/plugins/git/branchview.cpp | 2 +- src/plugins/git/gitclient.cpp | 8 +- src/plugins/qmakeprojectmanager/qmakestep.cpp | 2 +- .../qnx/qnxdeployqtlibrariesdialog.cpp | 6 +- .../remotelinux/genericdirectuploadstep.cpp | 2 +- src/plugins/remotelinux/linuxdevicetester.cpp | 8 +- tests/auto/solutions/tasking/tst_tasking.cpp | 196 +++++++++--------- tests/auto/utils/async/tst_async.cpp | 8 +- tests/manual/tasktree/main.cpp | 24 +-- 18 files changed, 142 insertions(+), 142 deletions(-) diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 58192741855..206dca8da41 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -444,7 +444,7 @@ void TestRunner::runTestsHelper() const Group group { optional, Storage(storage), - OnGroupSetup(onSetup), + onGroupSetup(onSetup), ProcessTask(onProcessSetup, onProcessDone, onProcessDone) }; tasks.append(group); diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 8afdd60f186..40cbf75d47e 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -184,7 +184,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, const Group group { Storage(storage), - OnGroupSetup(onSetup), + onGroupSetup(onSetup), Group { optional, ProcessTask(onProcessSetup, onProcessDone, onProcessError) diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 6100181ff43..0c1dd72bb77 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -95,7 +95,7 @@ DirectoryFilter::DirectoryFilter(Id id) m_cache.setFilePaths(async.result()); }; const Group root { - OnGroupSetup(groupSetup), + onGroupSetup(groupSetup), AsyncTask(asyncSetup, asyncDone) }; setRefreshRecipe(root); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 31f23cafd24..3c0ab0a5659 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -472,9 +472,9 @@ void LocatorMatcher::start() const Group group { optional, Storage(storage), - OnGroupSetup(onSetup(storage, index)), - OnGroupDone(onDone(storage)), - OnGroupError(onDone(storage)), + onGroupSetup(onSetup(storage, index)), + onGroupDone(onDone(storage)), + onGroupError(onDone(storage)), task.task }; parallelTasks << group; diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index e5cad19baa9..3656d673205 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -426,7 +426,7 @@ LocatorMatcherTasks JavaScriptFilter::matchers() }; const Group root { - OnGroupSetup(onSetup), + onGroupSetup(onSetup), JavaScriptRequestTask(onJavaScriptSetup, onJavaScriptDone, onJavaScriptError) }; diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index 30d996a08e8..fb9f50c3b1f 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -389,7 +389,7 @@ void Locator::refresh(const QList &filters) const Group group { optional, *task, - OnGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); }) + onGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); }) }; tasks.append(group); } diff --git a/src/plugins/cppeditor/cppprojectupdater.cpp b/src/plugins/cppeditor/cppprojectupdater.cpp index e848c6eba5a..c92d091396e 100644 --- a/src/plugins/cppeditor/cppprojectupdater.cpp +++ b/src/plugins/cppeditor/cppprojectupdater.cpp @@ -93,8 +93,8 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo, const Group root { Storage(storage), Group(tasks), - OnGroupDone(onDone), - OnGroupError(onError) + onGroupDone(onDone), + onGroupError(onError) }; m_taskTree.reset(new TaskTree(root)); auto progress = new Core::TaskProgress(m_taskTree.get()); diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index e5bed027a34..fe4c4f9a6a5 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -151,8 +151,8 @@ DiffFilesController::DiffFilesController(IDocument *document) const Group root = { Storage(storage), TaskTreeTask(setupTree), - OnGroupDone(onTreeDone), - OnGroupError(onTreeError) + onGroupDone(onTreeDone), + onGroupError(onTreeError) }; setReloadRecipe(root); } diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 8a495a8d8f3..3bf65cf5b38 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -472,8 +472,8 @@ void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError) const Group root { topRevisionProc, ProcessTask(setupForEachRef, forEachRefDone, forEachRefError), - OnGroupDone(finalize), - OnGroupError(finalize) + onGroupDone(finalize), + onGroupError(finalize) }; d->refreshTask.reset(new TaskTree(root)); d->refreshTask->start(); diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index ff428b1b90e..c3daf9d5a88 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -560,7 +560,7 @@ TaskTree *BranchView::onFastForwardMerge(const std::function &callback) parallel, ProcessTask(setupMergeBase, onMergeBaseDone), topRevisionProc, - OnGroupDone([storage, callback] { + onGroupDone([storage, callback] { if (storage->mergeBase == storage->topRevision) callback(); }) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 3b4a748c0c1..5c1d82d359f 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -270,7 +270,7 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin continueOnDone, ProcessTask(setupStaged, onStagedDone), ProcessTask(setupUnstaged, onUnstagedDone), - OnGroupDone(onStagingDone) + onGroupDone(onStagingDone) }, postProcessTask() }; @@ -441,7 +441,7 @@ ShowController::ShowController(IDocument *document, const QString &id) }; using namespace std::placeholders; - QList tasks {parallel, continueOnDone, OnGroupError(onFollowsError)}; + QList tasks {parallel, continueOnDone, onGroupError(onFollowsError)}; for (int i = 0, total = parents.size(); i < total; ++i) { tasks.append(ProcessTask(std::bind(setupFollow, _1, parents.at(i)), std::bind(onFollowDone, _1, i))); @@ -463,14 +463,14 @@ ShowController::ShowController(IDocument *document, const QString &id) Storage(storage), Storage(diffInputStorage), parallel, - OnGroupSetup([this] { setStartupFile(VcsBase::source(this->document()).toString()); }), + onGroupSetup([this] { setStartupFile(VcsBase::source(this->document()).toString()); }), Group { optional, ProcessTask(setupDescription, onDescriptionDone), Group { parallel, optional, - OnGroupSetup(desciptionDetailsSetup), + onGroupSetup(desciptionDetailsSetup), ProcessTask(setupBranches, onBranchesDone, onBranchesError), ProcessTask(setupPrecedes, onPrecedesDone, onPrecedesError), TaskTreeTask(setupFollows) diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 2f257977a81..c747f756581 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -333,7 +333,7 @@ void QMakeStep::doRun() QList processList = {ProcessTask(setupQMake, onProcessDone, onProcessError)}; if (m_runMakeQmake) processList << ProcessTask(setupMakeQMake, onProcessDone, onProcessError); - processList << OnGroupDone(onDone); + processList << onGroupDone(onDone); runTaskTree(Group(processList)); } diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 2a7f56d2f34..768553ff7a7 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -261,18 +261,18 @@ Group QnxDeployQtLibrariesDialogPrivate::deployRecipe() return TaskAction::Continue; }; const Group root { - OnGroupSetup(setupHandler), + onGroupSetup(setupHandler), Group { optional, checkDirTask() }, Group { - OnGroupSetup(subGroupSetupHandler), + onGroupSetup(subGroupSetupHandler), removeDirTask(), uploadTask(), chmodTree() }, - OnGroupDone(doneHandler) + onGroupDone(doneHandler) }; return root; } diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 8a7c1e4c029..586fc8bafd4 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -310,7 +310,7 @@ Group GenericDirectUploadStep::deployRecipe() chmodTree(storage), statTree(storage, postFilesToStat, postStatEndHandler) }, - OnGroupDone(doneHandler) + onGroupDone(doneHandler) }; return root; } diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index e1a209664fe..ecb4296262d 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -225,7 +225,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::transferTasks() const transferTask(FileTransferMethod::GenericCopy, storage), transferTask(FileTransferMethod::Sftp, storage), transferTask(FileTransferMethod::Rsync, storage), - OnGroupError([this] { emit q->errorMessage(Tr::tr("Deployment to this device will not " + onGroupError([this] { emit q->errorMessage(Tr::tr("Deployment to this device will not " "work out of the box.\n")); }) }; @@ -255,7 +255,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::commandTask(const QString &commandName TaskItem GenericLinuxDeviceTesterPrivate::commandTasks() const { QList tasks {continueOnError}; - tasks.append(OnGroupSetup([this] { + tasks.append(onGroupSetup([this] { emit q->progressMessage(Tr::tr("Checking if required commands are available...")); })); for (const QString &commandName : commandsToTest()) @@ -305,8 +305,8 @@ void GenericLinuxDeviceTester::testDevice(const IDevice::Ptr &deviceConfiguratio if (!d->m_extraTests.isEmpty()) taskItems << Group { d->m_extraTests }; taskItems << d->commandTasks() - << OnGroupDone(std::bind(allFinished, TestSuccess)) - << OnGroupError(std::bind(allFinished, TestFailure)); + << onGroupDone(std::bind(allFinished, TestSuccess)) + << onGroupError(std::bind(allFinished, TestFailure)); d->m_taskTree.reset(new TaskTree(taskItems)); d->m_taskTree->start(); diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 1efcf7096a3..a94c449dfc6 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -111,12 +111,12 @@ void tst_Tasking::validConstructs() Group { parallel, Test([](TestTask &) {}, [](const TestTask &) {}), - OnGroupDone([] {}) + onGroupDone([] {}) } }, task, - OnGroupDone([] {}), - OnGroupError([] {}) + onGroupDone([] {}), + onGroupError([] {}) }; const auto setupHandler = [](TestTask &) {}; @@ -272,8 +272,8 @@ void tst_Tasking::testTree_data() Test(setupTask(1), logDone), Test(setupFailingTask(2), logDone, logError), Test(setupTask(3), logDone), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; }; const auto constructDynamicHierarchy = [=](TaskAction taskAction) { @@ -283,39 +283,39 @@ void tst_Tasking::testTree_data() Test(setupTask(1), logDone) }, Group { - OnGroupSetup([=] { return taskAction; }), + onGroupSetup([=] { return taskAction; }), Test(setupTask(2), logDone), Test(setupTask(3), logDone), Test(setupTask(4), logDone) }, - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; }; { const Group root1 { Storage(storage), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; const Group root2 { Storage(storage), - OnGroupSetup([] { return TaskAction::Continue; }), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupSetup([] { return TaskAction::Continue; }), + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; const Group root3 { Storage(storage), - OnGroupSetup([] { return TaskAction::StopWithDone; }), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupSetup([] { return TaskAction::StopWithDone; }), + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; const Group root4 { Storage(storage), - OnGroupSetup([] { return TaskAction::StopWithError; }), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupSetup([] { return TaskAction::StopWithError; }), + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; const Log logDone {{0, Handler::GroupDone}}; const Log logError {{0, Handler::GroupError}}; @@ -410,7 +410,7 @@ void tst_Tasking::testTree_data() Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), Group { - OnGroupSetup([storage] { + onGroupSetup([storage] { storage->m_log.append({0, Handler::GroupSetup}); return TaskAction::StopWithError; }), @@ -438,22 +438,22 @@ void tst_Tasking::testTree_data() Group { Group { Test(setupTask(5), logDone, logError), - OnGroupSetup(groupSetup(5)), - OnGroupDone(groupDone(5)) + onGroupSetup(groupSetup(5)), + onGroupDone(groupDone(5)) }, - OnGroupSetup(groupSetup(4)), - OnGroupDone(groupDone(4)) + onGroupSetup(groupSetup(4)), + onGroupDone(groupDone(4)) }, - OnGroupSetup(groupSetup(3)), - OnGroupDone(groupDone(3)) + onGroupSetup(groupSetup(3)), + onGroupDone(groupDone(3)) }, - OnGroupSetup(groupSetup(2)), - OnGroupDone(groupDone(2)) + onGroupSetup(groupSetup(2)), + onGroupDone(groupDone(2)) }, - OnGroupSetup(groupSetup(1)), - OnGroupDone(groupDone(1)) + onGroupSetup(groupSetup(1)), + onGroupDone(groupDone(1)) }, - OnGroupDone(groupDone(0)) + onGroupDone(groupDone(0)) }; const Log log { {1, Handler::GroupSetup}, @@ -485,7 +485,7 @@ void tst_Tasking::testTree_data() Test(setupTask(3), logDoneAnonymously), Test(setupTask(4), logDoneAnonymously), Test(setupTask(5), logDoneAnonymously), - OnGroupDone(groupDone(0)) + onGroupDone(groupDone(0)) }; const Log log { {1, Handler::Setup}, // Setup order is determined in parallel mode @@ -525,7 +525,7 @@ void tst_Tasking::testTree_data() Test(setupTask(3), logDone), Test(setupTask(4), logDone), Test(setupTask(5), logDone), - OnGroupDone(groupDone(0)) + onGroupDone(groupDone(0)) }; const Group root2 { Storage(storage), @@ -534,14 +534,14 @@ void tst_Tasking::testTree_data() Group { Test(setupTask(3), logDone) }, Group { Test(setupTask(4), logDone) }, Group { Test(setupTask(5), logDone) }, - OnGroupDone(groupDone(0)) + onGroupDone(groupDone(0)) }; const Group root3 { Storage(storage), Test(setupTask(1), logDone), TaskTreeTask(setupSubTree), Test(setupTask(5), logDone), - OnGroupDone(groupDone(0)) + onGroupDone(groupDone(0)) }; const Log log { {1, Handler::Setup}, @@ -575,17 +575,17 @@ void tst_Tasking::testTree_data() Test(setupTask(4), logDone), Group { Test(setupTask(5), logDone), - OnGroupDone(groupDone(5)) + onGroupDone(groupDone(5)) }, - OnGroupDone(groupDone(4)) + onGroupDone(groupDone(4)) }, - OnGroupDone(groupDone(3)) + onGroupDone(groupDone(3)) }, - OnGroupDone(groupDone(2)) + onGroupDone(groupDone(2)) }, - OnGroupDone(groupDone(1)) + onGroupDone(groupDone(1)) }, - OnGroupDone(groupDone(0)) + onGroupDone(groupDone(0)) }; const Log log { {1, Handler::Setup}, @@ -616,8 +616,8 @@ void tst_Tasking::testTree_data() Test(setupFailingTask(3), logDone, logError), Test(setupTask(4), logDone), Test(setupTask(5), logDone), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; const Log log { {1, Handler::Setup}, @@ -699,8 +699,8 @@ void tst_Tasking::testTree_data() Storage(storage), Test(setupSleepingTask(1, firstSuccess, 1000ms), logDone, logError), Test(setupSleepingTask(2, secondSuccess, 5ms), logDone, logError), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; }; @@ -736,8 +736,8 @@ void tst_Tasking::testTree_data() optional, Test(setupFailingTask(1), logDone, logError), Test(setupFailingTask(2), logDone, logError), - OnGroupDone(groupDone(0)), - OnGroupError(groupError(0)) + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) }; const Log log { {1, Handler::Setup}, @@ -790,19 +790,19 @@ void tst_Tasking::testTree_data() ParallelLimit(2), Storage(storage), Group { - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Test(setupTask(1)) }, Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Test(setupTask(2)) }, Group { - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Test(setupTask(3)) }, Group { - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Test(setupTask(4)) } }; @@ -824,23 +824,23 @@ void tst_Tasking::testTree_data() ParallelLimit(2), Storage(storage), Group { - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Test(setupTask(1)) }, Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Test(setupTask(2)) }, Group { - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Test(setupDynamicTask(3, TaskAction::StopWithDone)) }, Group { - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Test(setupTask(4)) }, Group { - OnGroupSetup(groupSetup(5)), + onGroupSetup(groupSetup(5)), Test(setupTask(5)) } }; @@ -864,23 +864,23 @@ void tst_Tasking::testTree_data() ParallelLimit(2), Storage(storage), Group { - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Test(setupTask(1)) }, Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Test(setupTask(2)) }, Group { - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Test(setupDynamicTask(3, TaskAction::StopWithError)) }, Group { - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Test(setupTask(4)) }, Group { - OnGroupSetup(groupSetup(5)), + onGroupSetup(groupSetup(5)), Test(setupTask(5)) } }; @@ -893,23 +893,23 @@ void tst_Tasking::testTree_data() ParallelLimit(2), Storage(storage), Group { - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Test(setupSleepingTask(1, true, 10ms)) }, Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Test(setupTask(2)) }, Group { - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Test(setupDynamicTask(3, TaskAction::StopWithError)) }, Group { - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Test(setupTask(4)) }, Group { - OnGroupSetup(groupSetup(5)), + onGroupSetup(groupSetup(5)), Test(setupTask(5)) } }; @@ -928,24 +928,24 @@ void tst_Tasking::testTree_data() Group { ParallelLimit(2), Group { - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Test(setupSleepingTask(1, true, 20ms)) }, Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Test(setupSleepingTask(2, true, 10ms)) }, Group { - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Test(setupDynamicTask(3, TaskAction::StopWithError)) }, Group { - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Test(setupTask(4)) } }, Group { - OnGroupSetup(groupSetup(5)), + onGroupSetup(groupSetup(5)), Test(setupTask(5)) } }; @@ -972,7 +972,7 @@ void tst_Tasking::testTree_data() Storage(storage), Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Group { parallel, Test(setupTask(1)) @@ -980,7 +980,7 @@ void tst_Tasking::testTree_data() }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Group { parallel, Test(setupTask(2)) @@ -988,7 +988,7 @@ void tst_Tasking::testTree_data() }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Group { parallel, Test(setupTask(3)) @@ -996,7 +996,7 @@ void tst_Tasking::testTree_data() }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Group { parallel, Test(setupTask(4)) @@ -1022,27 +1022,27 @@ void tst_Tasking::testTree_data() Storage(storage), Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Group { Test(setupTask(1)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Group { Test(setupTask(2)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Group { Test(setupDynamicTask(3, TaskAction::StopWithDone)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Group { Test(setupTask(4)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(5)), + onGroupSetup(groupSetup(5)), Group { Test(setupTask(5)) } } }; @@ -1068,27 +1068,27 @@ void tst_Tasking::testTree_data() Storage(storage), Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), Group { Test(setupTask(1)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), Group { Test(setupTask(2)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), Group { Test(setupDynamicTask(3, TaskAction::StopWithError)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(4)), + onGroupSetup(groupSetup(4)), Group { Test(setupTask(4)) } }, Group { Storage(TreeStorage()), - OnGroupSetup(groupSetup(5)), + onGroupSetup(groupSetup(5)), Group { Test(setupTask(5)) } } }; @@ -1188,7 +1188,7 @@ void tst_Tasking::testTree_data() Sync(setupSync(3)), Test(setupTask(4)), Sync(setupSync(5)), - OnGroupDone(groupDone(0)) + onGroupDone(groupDone(0)) }; const Log log { {1, Handler::Sync}, @@ -1209,7 +1209,7 @@ void tst_Tasking::testTree_data() Sync(setupSyncWithReturn(3, false)), Test(setupTask(4)), Sync(setupSync(5)), - OnGroupError(groupError(0)) + onGroupError(groupError(0)) }; const Log log { {1, Handler::Sync}, @@ -1232,7 +1232,7 @@ void tst_Tasking::testTree_data() sequential, AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) @@ -1255,7 +1255,7 @@ void tst_Tasking::testTree_data() parallel, AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) @@ -1284,7 +1284,7 @@ void tst_Tasking::testTree_data() Storage(barrier), parallel, Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) @@ -1308,12 +1308,12 @@ void tst_Tasking::testTree_data() parallel, AsyncTask(setupBarrierAdvance(storage, barrier, 1)), Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(4)) }, Group { - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), WaitForBarrierTask(barrier), Test(setupTask(5)) } @@ -1341,7 +1341,7 @@ void tst_Tasking::testTree_data() Group { Group { parallel, - OnGroupSetup(groupSetup(1)), + onGroupSetup(groupSetup(1)), WaitForBarrierTask(barrier), WaitForBarrierTask(barrier2) }, @@ -1383,7 +1383,7 @@ void tst_Tasking::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 1)), AsyncTask(setupBarrierAdvance(storage, barrier, 2)), Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) @@ -1409,7 +1409,7 @@ void tst_Tasking::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 0)), AsyncTask(setupBarrierAdvance(storage, barrier, 0)), Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) @@ -1440,7 +1440,7 @@ void tst_Tasking::testTree_data() Storage(barrier), parallel, Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(2)), Test(setupTask(3)) @@ -1468,12 +1468,12 @@ void tst_Tasking::testTree_data() AsyncTask(setupBarrierAdvance(storage, barrier, 0)), AsyncTask(setupBarrierAdvance(storage, barrier, 0)), Group { - OnGroupSetup(groupSetup(2)), + onGroupSetup(groupSetup(2)), WaitForBarrierTask(barrier), Test(setupTask(4)) }, Group { - OnGroupSetup(groupSetup(3)), + onGroupSetup(groupSetup(3)), WaitForBarrierTask(barrier), Test(setupTask(5)) } diff --git a/tests/auto/utils/async/tst_async.cpp b/tests/auto/utils/async/tst_async.cpp index 4a496f93a00..01c3306a3bf 100644 --- a/tests/auto/utils/async/tst_async.cpp +++ b/tests/auto/utils/async/tst_async.cpp @@ -503,13 +503,13 @@ void tst_Async::mapReduce_data() const DoneHandler &doneHandler) { return Group { executeMode, - OnGroupSetup(initTree), + onGroupSetup(initTree), AsyncTask(std::bind(setupHandler, _1, 1), handleAsync), AsyncTask(std::bind(setupHandler, _1, 2), handleAsync), AsyncTask(std::bind(setupHandler, _1, 3), handleAsync), AsyncTask(std::bind(setupHandler, _1, 4), handleAsync), AsyncTask(std::bind(setupHandler, _1, 5), handleAsync), - OnGroupDone(doneHandler) + onGroupDone(doneHandler) }; }; @@ -539,7 +539,7 @@ void tst_Async::mapReduce_data() }; const Group simpleRoot = { sequential, - OnGroupSetup([] { s_sum = 0; }), + onGroupSetup([] { s_sum = 0; }), AsyncTask(std::bind(setupSimpleAsync, _1, 1), handleSimpleAsync), AsyncTask(std::bind(setupSimpleAsync, _1, 2), handleSimpleAsync), AsyncTask(std::bind(setupSimpleAsync, _1, 3), handleSimpleAsync) @@ -554,7 +554,7 @@ void tst_Async::mapReduce_data() }; const Group stringRoot = { parallel, - OnGroupSetup([] { s_sum = 90.0; }), + onGroupSetup([] { s_sum = 90.0; }), AsyncTask(std::bind(setupStringAsync, _1, "blubb"), handleStringAsync), AsyncTask(std::bind(setupStringAsync, _1, "foo"), handleStringAsync), AsyncTask(std::bind(setupStringAsync, _1, "blah"), handleStringAsync) diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index 6b6db61adeb..de575346bf8 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -172,16 +172,16 @@ int main(int argc, char *argv[]) const Group root { rootGroup->executeMode(), Workflow(rootGroup->workflowPolicy()), - OnGroupSetup([rootGroup] { rootGroup->setState(State::Running); }), - OnGroupDone([rootGroup] { rootGroup->setState(State::Done); }), - OnGroupError([rootGroup] { rootGroup->setState(State::Error); }), + onGroupSetup([rootGroup] { rootGroup->setState(State::Running); }), + onGroupDone([rootGroup] { rootGroup->setState(State::Done); }), + onGroupError([rootGroup] { rootGroup->setState(State::Error); }), Group { groupTask_1->executeMode(), Workflow(groupTask_1->workflowPolicy()), - OnGroupSetup([groupTask_1] { groupTask_1->setState(State::Running); }), - OnGroupDone([groupTask_1] { groupTask_1->setState(State::Done); }), - OnGroupError([groupTask_1] { groupTask_1->setState(State::Error); }), + onGroupSetup([groupTask_1] { groupTask_1->setState(State::Running); }), + onGroupDone([groupTask_1] { groupTask_1->setState(State::Done); }), + onGroupError([groupTask_1] { groupTask_1->setState(State::Error); }), taskItem(task_1_1), taskItem(task_1_2), @@ -192,18 +192,18 @@ int main(int argc, char *argv[]) Group { groupTask_4->executeMode(), Workflow(groupTask_4->workflowPolicy()), - OnGroupSetup([groupTask_4] { groupTask_4->setState(State::Running); }), - OnGroupDone([groupTask_4] { groupTask_4->setState(State::Done); }), - OnGroupError([groupTask_4] { groupTask_4->setState(State::Error); }), + onGroupSetup([groupTask_4] { groupTask_4->setState(State::Running); }), + onGroupDone([groupTask_4] { groupTask_4->setState(State::Done); }), + onGroupError([groupTask_4] { groupTask_4->setState(State::Error); }), taskItem(task_4_1), taskItem(task_4_2), Group { groupTask_4_3->executeMode(), Workflow(groupTask_4_3->workflowPolicy()), - OnGroupSetup([groupTask_4_3] { groupTask_4_3->setState(State::Running); }), - OnGroupDone([groupTask_4_3] { groupTask_4_3->setState(State::Done); }), - OnGroupError([groupTask_4_3] { groupTask_4_3->setState(State::Error); }), + onGroupSetup([groupTask_4_3] { groupTask_4_3->setState(State::Running); }), + onGroupDone([groupTask_4_3] { groupTask_4_3->setState(State::Done); }), + onGroupError([groupTask_4_3] { groupTask_4_3->setState(State::Error); }), taskItem(task_4_3_1), taskItem(task_4_3_2), From 56fda87389fbc277ca3c3636660209dfc5da82ed Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 17 May 2023 20:03:57 +0200 Subject: [PATCH 1147/1447] TaskTree: Get rid of OnGroup... elements Change-Id: Id1b600999d2051eff8d2207db8235ad08eb6e663 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 24 ++++++++-------- src/libs/solutions/tasking/tasktree.h | 38 ------------------------- 2 files changed, 12 insertions(+), 50 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 06a3804f9dd..57429b90516 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -990,14 +990,14 @@ void TaskNode::invokeEndHandler(bool success) qDebug() << "Entering the group"; }; const Group root { - OnGroupSetup(onSetup), + onGroupSetup(onSetup), ProcessTask(...) }; \endcode The group setup handler is optional. To define a group setup handler, add an - OnGroupSetup element to a group. The argument of OnGroupSetup is a user - handler. If you add more than one OnGroupSetup element to a group, an assert + onGroupSetup element to a group. The argument of onGroupSetup is a user + handler. If you add more than one onGroupSetup element to a group, an assert is triggered at runtime that includes an error message. Like the task start handler, the group start handler may return TaskAction. @@ -1011,17 +1011,17 @@ void TaskNode::invokeEndHandler(bool success) \code const Group root { - OnGroupSetup([] { qDebug() << "Root setup"; }), + onGroupSetup([] { qDebug() << "Root setup"; }), Group { - OnGroupSetup([] { qDebug() << "Group 1 setup"; return TaskAction::Continue; }), + onGroupSetup([] { qDebug() << "Group 1 setup"; return TaskAction::Continue; }), ProcessTask(...) // Process 1 }, Group { - OnGroupSetup([] { qDebug() << "Group 2 setup"; return TaskAction::StopWithDone; }), + onGroupSetup([] { qDebug() << "Group 2 setup"; return TaskAction::StopWithDone; }), ProcessTask(...) // Process 2 }, Group { - OnGroupSetup([] { qDebug() << "Group 3 setup"; return TaskAction::StopWithError; }), + onGroupSetup([] { qDebug() << "Group 3 setup"; return TaskAction::StopWithError; }), ProcessTask(...) // Process 3 }, ProcessTask(...) // Process 4 @@ -1080,20 +1080,20 @@ void TaskNode::invokeEndHandler(bool success) execution of its tasks, respectively. The final value reported by the group depends on its \l {Workflow Policy}. The handlers can apply other necessary actions. The done and error handlers are defined inside the - OnGroupDone and OnGroupError elements of a group, respectively. They do not + onGroupDone and onGroupError elements of a group, respectively. They do not take arguments: \code const Group root { - OnGroupSetup([] { qDebug() << "Root setup"; }), + onGroupSetup([] { qDebug() << "Root setup"; }), ProcessTask(...), - OnGroupDone([] { qDebug() << "Root finished with success"; }), - OnGroupError([] { qDebug() << "Root finished with error"; }) + onGroupDone([] { qDebug() << "Root finished with success"; }), + onGroupError([] { qDebug() << "Root finished with error"; }) }; \endcode The group done and error handlers are optional. If you add more than one - OnGroupDone or OnGroupError each to a group, an assert is triggered at + onGroupDone or onGroupError each to a group, an assert is triggered at runtime that includes an error message. \note Even if the group setup handler returns StopWithDone or StopWithError, diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 08391d9d633..7b37c36eb90 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -259,44 +259,6 @@ public: Workflow(WorkflowPolicy policy) : TaskItem(policy) {} }; -class TASKING_EXPORT OnGroupSetup : public TaskItem -{ -public: - template - OnGroupSetup(SetupFunction &&function) - : TaskItem({wrapSetup(std::forward(function))}) {} - -private: - template - static TaskItem::GroupSetupHandler wrapSetup(SetupFunction &&function) { - static constexpr bool isDynamic = std::is_same_v>>; - constexpr bool isVoid = std::is_same_v>>; - static_assert(isDynamic || isVoid, - "Group setup handler needs to take no arguments and has to return " - "void or TaskAction. The passed handler doesn't fulfill these requirements."); - return [=] { - if constexpr (isDynamic) - return std::invoke(function); - std::invoke(function); - return TaskAction::Continue; - }; - }; -}; - -class TASKING_EXPORT OnGroupDone : public TaskItem -{ -public: - OnGroupDone(const GroupEndHandler &handler) : TaskItem({{}, handler}) {} -}; - -class TASKING_EXPORT OnGroupError : public TaskItem -{ -public: - OnGroupError(const GroupEndHandler &handler) : TaskItem({{}, {}, handler}) {} -}; - // Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() class TASKING_EXPORT Sync : public Group { From c098b261dc54fa8edbdd2bde17841cfe8b7e64a0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 18 May 2023 13:16:40 +0200 Subject: [PATCH 1148/1447] TaskTree: Refactor Group internal data Introduce the GroupData structure. In this way it's easily possible to add extra properties of already used types, e.g. int. It's also possible to easily create elements with multiple properties. Simplify internal TaskItem::Type enum. Get rid of special ParallelLimit and Workflow elements. Provide global parallelLimit() and workflowPolicy() functions. Make global items (e.g. parallel, stopOnDone, etc...) const. Change-Id: Ic5628255b542fd6c5a5565b055ff11804c8d7b68 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 93 +++++++++++-------- src/libs/solutions/tasking/tasktree.h | 93 ++++++++----------- src/plugins/autotest/testcodeparser.cpp | 2 +- .../clangtools/clangtoolruncontrol.cpp | 2 +- .../coreplugin/locator/ilocatorfilter.cpp | 2 +- .../qnx/qnxdeployqtlibrariesdialog.cpp | 2 +- .../remotelinux/genericdirectuploadstep.cpp | 4 +- tests/auto/solutions/tasking/tst_tasking.cpp | 34 +++---- tests/manual/tasktree/main.cpp | 8 +- tests/manual/tasktree/taskwidget.cpp | 2 +- tests/manual/tasktree/taskwidget.h | 2 +- 11 files changed, 121 insertions(+), 123 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 57429b90516..4e9cab7bb90 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -50,6 +50,25 @@ TaskItem onGroupError(const TaskItem::GroupEndHandler &handler) return Group::onGroupError(handler); } +TaskItem parallelLimit(int limit) +{ + return Group::parallelLimit(qMax(limit, 0)); +} + +TaskItem workflowPolicy(WorkflowPolicy policy) +{ + return Group::workflowPolicy(policy); +} + +const TaskItem sequential = parallelLimit(1); +const TaskItem parallel = parallelLimit(0); +const TaskItem stopOnError = workflowPolicy(WorkflowPolicy::StopOnError); +const TaskItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError); +const TaskItem stopOnDone = workflowPolicy(WorkflowPolicy::StopOnDone); +const TaskItem continueOnDone = workflowPolicy(WorkflowPolicy::ContinueOnDone); +const TaskItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished); +const TaskItem optional = workflowPolicy(WorkflowPolicy::Optional); + static TaskAction toTaskAction(bool success) { return success ? TaskAction::StopWithDone : TaskAction::StopWithError; @@ -118,15 +137,6 @@ void TreeStorageBase::activateStorage(int id) const m_storageData->m_activeStorage = id; } -ParallelLimit sequential(1); -ParallelLimit parallel(0); -Workflow stopOnError(WorkflowPolicy::StopOnError); -Workflow continueOnError(WorkflowPolicy::ContinueOnError); -Workflow stopOnDone(WorkflowPolicy::StopOnDone); -Workflow continueOnDone(WorkflowPolicy::ContinueOnDone); -Workflow stopOnFinished(WorkflowPolicy::StopOnFinished); -Workflow optional(WorkflowPolicy::Optional); - void TaskItem::addChildren(const QList &children) { QTC_ASSERT(m_type == Type::Group, qWarning("Only Group may have children, skipping..."); @@ -136,40 +146,41 @@ void TaskItem::addChildren(const QList &children) case Type::Group: m_children.append(child); break; - case Type::Limit: - QTC_ASSERT(m_type == Type::Group, qWarning("Execution Mode may only be a child of a " - "Group, skipping..."); return); - m_parallelLimit = child.m_parallelLimit; // TODO: Assert on redefinition? - break; - case Type::Policy: - QTC_ASSERT(m_type == Type::Group, qWarning("Workflow Policy may only be a child of a " - "Group, skipping..."); return); - m_workflowPolicy = child.m_workflowPolicy; // TODO: Assert on redefinition? + case Type::GroupData: + if (child.m_groupData.m_groupHandler.m_setupHandler) { + QTC_ASSERT(!m_groupData.m_groupHandler.m_setupHandler, + qWarning("Group Setup Handler redefinition, overriding...")); + m_groupData.m_groupHandler.m_setupHandler + = child.m_groupData.m_groupHandler.m_setupHandler; + } + if (child.m_groupData.m_groupHandler.m_doneHandler) { + QTC_ASSERT(!m_groupData.m_groupHandler.m_doneHandler, + qWarning("Group Done Handler redefinition, overriding...")); + m_groupData.m_groupHandler.m_doneHandler + = child.m_groupData.m_groupHandler.m_doneHandler; + } + if (child.m_groupData.m_groupHandler.m_errorHandler) { + QTC_ASSERT(!m_groupData.m_groupHandler.m_errorHandler, + qWarning("Group Error Handler redefinition, overriding...")); + m_groupData.m_groupHandler.m_errorHandler + = child.m_groupData.m_groupHandler.m_errorHandler; + } + if (child.m_groupData.m_parallelLimit) { + QTC_ASSERT(!m_groupData.m_parallelLimit, + qWarning("Group Execution Mode redefinition, overriding...")); + m_groupData.m_parallelLimit = child.m_groupData.m_parallelLimit; + } + if (child.m_groupData.m_workflowPolicy) { + QTC_ASSERT(!m_groupData.m_workflowPolicy, + qWarning("Group Workflow Policy redefinition, overriding...")); + m_groupData.m_workflowPolicy = child.m_groupData.m_workflowPolicy; + } break; case Type::TaskHandler: QTC_ASSERT(child.m_taskHandler.m_createHandler, qWarning("Task Create Handler can't be null, skipping..."); return); m_children.append(child); break; - case Type::GroupHandler: - QTC_ASSERT(m_type == Type::Group, qWarning("Group Handler may only be a " - "child of a Group, skipping..."); break); - QTC_ASSERT(!child.m_groupHandler.m_setupHandler - || !m_groupHandler.m_setupHandler, - qWarning("Group Setup Handler redefinition, overriding...")); - QTC_ASSERT(!child.m_groupHandler.m_doneHandler - || !m_groupHandler.m_doneHandler, - qWarning("Group Done Handler redefinition, overriding...")); - QTC_ASSERT(!child.m_groupHandler.m_errorHandler - || !m_groupHandler.m_errorHandler, - qWarning("Group Error Handler redefinition, overriding...")); - if (child.m_groupHandler.m_setupHandler) - m_groupHandler.m_setupHandler = child.m_groupHandler.m_setupHandler; - if (child.m_groupHandler.m_doneHandler) - m_groupHandler.m_doneHandler = child.m_groupHandler.m_doneHandler; - if (child.m_groupHandler.m_errorHandler) - m_groupHandler.m_errorHandler = child.m_groupHandler.m_errorHandler; - break; case Type::Storage: m_storageList.append(child.m_storageList); break; @@ -472,9 +483,9 @@ TaskContainer::ConstData::ConstData(TaskTreePrivate *taskTreePrivate, const Task : m_taskTreePrivate(taskTreePrivate) , m_parentNode(parentNode) , m_parentContainer(parentContainer) - , m_parallelLimit(task.parallelLimit()) - , m_workflowPolicy(task.workflowPolicy()) - , m_groupHandler(task.groupHandler()) + , m_parallelLimit(task.groupData().m_parallelLimit.value_or(1)) + , m_workflowPolicy(task.groupData().m_workflowPolicy.value_or(WorkflowPolicy::StopOnError)) + , m_groupHandler(task.groupData().m_groupHandler) , m_storageList(taskTreePrivate->addStorages(task.storageList())) , m_children(createChildren(taskTreePrivate, thisContainer, task)) , m_taskCount(std::accumulate(m_children.cbegin(), m_children.cend(), 0, @@ -1130,7 +1141,7 @@ void TaskNode::invokeEndHandler(bool success) started, without waiting for the previous tasks to finish. In this mode, all tasks run simultaneously. \row - \li ParallelLimit(int limit) + \li parallelLimit(int limit) \li In this mode, a limited number of direct child tasks run simultaneously. The \e limit defines the maximum number of tasks running in parallel in a group. When the group is started, the first batch tasks is diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 7b37c36eb90..1754e092631 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -18,7 +18,6 @@ namespace Tasking { class ExecutionContextActivator; class TaskContainer; -class TaskNode; class TaskTreePrivate; class TASKING_EXPORT TaskInterface : public QObject @@ -68,9 +67,9 @@ private: int m_storageCounter = 0; }; QSharedPointer m_storageData; + friend ExecutionContextActivator; friend TaskContainer; friend TaskTreePrivate; - friend ExecutionContextActivator; }; template @@ -145,54 +144,50 @@ public: GroupEndHandler m_errorHandler = {}; }; - int parallelLimit() const { return m_parallelLimit; } - WorkflowPolicy workflowPolicy() const { return m_workflowPolicy; } - TaskHandler taskHandler() const { return m_taskHandler; } - GroupHandler groupHandler() const { return m_groupHandler; } + struct GroupData { + GroupHandler m_groupHandler = {}; + std::optional m_parallelLimit = {}; + std::optional m_workflowPolicy = {}; + }; + QList children() const { return m_children; } + GroupData groupData() const { return m_groupData; } QList storageList() const { return m_storageList; } + TaskHandler taskHandler() const { return m_taskHandler; } protected: enum class Type { Group, + GroupData, Storage, - Limit, - Policy, - TaskHandler, - GroupHandler + TaskHandler }; TaskItem() = default; - TaskItem(int parallelLimit) - : m_type(Type::Limit) - , m_parallelLimit(parallelLimit) {} - TaskItem(WorkflowPolicy policy) - : m_type(Type::Policy) - , m_workflowPolicy(policy) {} - TaskItem(const TaskHandler &handler) - : m_type(Type::TaskHandler) - , m_taskHandler(handler) {} - TaskItem(const GroupHandler &handler) - : m_type(Type::GroupHandler) - , m_groupHandler(handler) {} + TaskItem(const GroupData &data) + : m_type(Type::GroupData) + , m_groupData(data) {} TaskItem(const TreeStorageBase &storage) : m_type(Type::Storage) , m_storageList{storage} {} + TaskItem(const TaskHandler &handler) + : m_type(Type::TaskHandler) + , m_taskHandler(handler) {} void addChildren(const QList &children); void setTaskSetupHandler(const TaskSetupHandler &handler); void setTaskDoneHandler(const TaskEndHandler &handler); void setTaskErrorHandler(const TaskEndHandler &handler); - static TaskItem createGroupHandler(const GroupHandler &handler) { return TaskItem(handler); } + static TaskItem groupHandler(const GroupHandler &handler) { return TaskItem({handler}); } + static TaskItem parallelLimit(int limit) { return TaskItem({{}, limit}); } + static TaskItem workflowPolicy(WorkflowPolicy policy) { return TaskItem({{}, {}, policy}); } private: Type m_type = Type::Group; - int m_parallelLimit = 1; // 0 means unlimited - WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError; - TaskHandler m_taskHandler; - GroupHandler m_groupHandler; - QList m_storageList; QList m_children; + GroupData m_groupData; + QList m_storageList; + TaskHandler m_taskHandler; }; class TASKING_EXPORT Group : public TaskItem @@ -201,16 +196,19 @@ public: Group(const QList &children) { addChildren(children); } Group(std::initializer_list children) { addChildren(children); } + // GroupData related: template static TaskItem onGroupSetup(SetupHandler &&handler) { - return createGroupHandler({wrapGroupSetup(std::forward(handler))}); + return groupHandler({wrapGroupSetup(std::forward(handler))}); } static TaskItem onGroupDone(const GroupEndHandler &handler) { - return createGroupHandler({{}, handler}); + return groupHandler({{}, handler}); } static TaskItem onGroupError(const GroupEndHandler &handler) { - return createGroupHandler({{}, {}, handler}); + return groupHandler({{}, {}, handler}); } + using TaskItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel). + using TaskItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError. private: template @@ -240,6 +238,17 @@ static TaskItem onGroupSetup(SetupHandler &&handler) TASKING_EXPORT TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler); TASKING_EXPORT TaskItem onGroupError(const TaskItem::GroupEndHandler &handler); +TASKING_EXPORT TaskItem parallelLimit(int limit); +TASKING_EXPORT TaskItem workflowPolicy(WorkflowPolicy policy); + +TASKING_EXPORT extern const TaskItem sequential; +TASKING_EXPORT extern const TaskItem parallel; +TASKING_EXPORT extern const TaskItem stopOnError; +TASKING_EXPORT extern const TaskItem continueOnError; +TASKING_EXPORT extern const TaskItem stopOnDone; +TASKING_EXPORT extern const TaskItem continueOnDone; +TASKING_EXPORT extern const TaskItem stopOnFinished; +TASKING_EXPORT extern const TaskItem optional; class TASKING_EXPORT Storage : public TaskItem { @@ -247,18 +256,6 @@ public: Storage(const TreeStorageBase &storage) : TaskItem(storage) { } }; -class TASKING_EXPORT ParallelLimit : public TaskItem -{ -public: - ParallelLimit(int parallelLimit) : TaskItem(qMax(parallelLimit, 0)) {} -}; - -class TASKING_EXPORT Workflow : public TaskItem -{ -public: - Workflow(WorkflowPolicy policy) : TaskItem(policy) {} -}; - // Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() class TASKING_EXPORT Sync : public Group { @@ -283,18 +280,8 @@ private: } return {onGroupSetup([function] { function(); return TaskAction::StopWithDone; })}; }; - }; -TASKING_EXPORT extern ParallelLimit sequential; -TASKING_EXPORT extern ParallelLimit parallel; -TASKING_EXPORT extern Workflow stopOnError; -TASKING_EXPORT extern Workflow continueOnError; -TASKING_EXPORT extern Workflow stopOnDone; -TASKING_EXPORT extern Workflow continueOnDone; -TASKING_EXPORT extern Workflow stopOnFinished; -TASKING_EXPORT extern Workflow optional; - template class TaskAdapter : public TaskInterface { diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 6f3d5137e45..8553702432f 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -360,7 +360,7 @@ void TestCodeParser::scanForTests(const QSet &filePaths, using namespace Tasking; - QList tasks{ParallelLimit(std::max(QThread::idealThreadCount() / 4, 1))}; + QList tasks{parallelLimit(std::max(QThread::idealThreadCount() / 4, 1))}; for (const FilePath &file : filteredFiles) { const auto setup = [this, codeParsers, file](Async &async) { async.setConcurrentCallData(parseFileForTests, codeParsers, file); diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index be6f416d2e0..11353b04ae4 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -183,7 +183,7 @@ void ClangToolRunWorker::start() m_filesAnalyzed.clear(); m_filesNotAnalyzed.clear(); - QList tasks{ParallelLimit(qMax(1, m_runSettings.parallelJobs()))}; + QList tasks{parallelLimit(qMax(1, m_runSettings.parallelJobs()))}; for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) { if (!m_diagnosticConfig.isEnabled(tool) && !m_runSettings.hasConfigFileForSourceFile(unit.file)) { diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 3c0ab0a5659..930b2c918d9 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -450,7 +450,7 @@ void LocatorMatcher::start() collectorStorage->m_collector = nullptr; }; - QList parallelTasks { ParallelLimit(d->m_parallelLimit) }; + QList parallelTasks {parallelLimit(d->m_parallelLimit)}; const auto onSetup = [this, collectorStorage](const TreeStorage &storage, int index) { diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 768553ff7a7..0b6e74dca8b 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -223,7 +223,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::chmodTree() if (file.isExecutable()) filesToChmod << file; } - QList chmodList{optional, ParallelLimit(MaxConcurrentStatCalls)}; + QList chmodList{optional, parallelLimit(MaxConcurrentStatCalls)}; for (const DeployableFile &file : std::as_const(filesToChmod)) { QTC_ASSERT(file.isValid(), continue); chmodList.append(chmodTask(file)); diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 586fc8bafd4..9179ac87519 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -179,7 +179,7 @@ TaskItem GenericDirectUploadStep::statTree(const TreeStorage &sto const auto setupHandler = [=](TaskTree &tree) { UploadStorage *storagePtr = storage.activeStorage(); const QList files = filesToStat(storagePtr); - QList statList{optional, ParallelLimit(MaxConcurrentStatCalls)}; + QList statList{optional, parallelLimit(MaxConcurrentStatCalls)}; for (const DeployableFile &file : std::as_const(files)) { QTC_ASSERT(file.isValid(), continue); statList.append(statTask(storagePtr, file, statEndHandler)); @@ -256,7 +256,7 @@ TaskItem GenericDirectUploadStep::chmodTree(const TreeStorage &st if (file.isExecutable()) filesToChmod << file; } - QList chmodList{optional, ParallelLimit(MaxConcurrentStatCalls)}; + QList chmodList{optional, parallelLimit(MaxConcurrentStatCalls)}; for (const DeployableFile &file : std::as_const(filesToChmod)) { QTC_ASSERT(file.isValid(), continue); chmodList.append(chmodTask(file)); diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index a94c449dfc6..fb8e575322f 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -265,10 +265,10 @@ void tst_Tasking::testTree_data() return [=] { storage->m_log.append({taskId, Handler::Sync}); return success; }; }; - const auto constructSimpleSequence = [=](const Workflow &policy) { + const auto constructSimpleSequence = [=](WorkflowPolicy policy) { return Group { Storage(storage), - policy, + workflowPolicy(policy), Test(setupTask(1), logDone), Test(setupFailingTask(2), logDone, logError), Test(setupTask(3), logDone), @@ -632,7 +632,7 @@ void tst_Tasking::testTree_data() } { - const Group root = constructSimpleSequence(stopOnError); + const Group root = constructSimpleSequence(WorkflowPolicy::StopOnError); const Log log { {1, Handler::Setup}, {1, Handler::Done}, @@ -644,7 +644,7 @@ void tst_Tasking::testTree_data() } { - const Group root = constructSimpleSequence(continueOnError); + const Group root = constructSimpleSequence(WorkflowPolicy::ContinueOnError); const Log log { {1, Handler::Setup}, {1, Handler::Done}, @@ -658,7 +658,7 @@ void tst_Tasking::testTree_data() } { - const Group root = constructSimpleSequence(stopOnDone); + const Group root = constructSimpleSequence(WorkflowPolicy::StopOnDone); const Log log { {1, Handler::Setup}, {1, Handler::Done}, @@ -668,7 +668,7 @@ void tst_Tasking::testTree_data() } { - const Group root = constructSimpleSequence(continueOnDone); + const Group root = constructSimpleSequence(WorkflowPolicy::ContinueOnDone); const Log log { {1, Handler::Setup}, {1, Handler::Done}, @@ -682,7 +682,7 @@ void tst_Tasking::testTree_data() } { - const Group root = constructSimpleSequence(stopOnFinished); + const Group root = constructSimpleSequence(WorkflowPolicy::StopOnFinished); const Log log { {1, Handler::Setup}, {1, Handler::Done}, @@ -787,7 +787,7 @@ void tst_Tasking::testTree_data() { const Group root { - ParallelLimit(2), + parallelLimit(2), Storage(storage), Group { onGroupSetup(groupSetup(1)), @@ -821,7 +821,7 @@ void tst_Tasking::testTree_data() { const Group root { - ParallelLimit(2), + parallelLimit(2), Storage(storage), Group { onGroupSetup(groupSetup(1)), @@ -861,7 +861,7 @@ void tst_Tasking::testTree_data() { const Group root1 { - ParallelLimit(2), + parallelLimit(2), Storage(storage), Group { onGroupSetup(groupSetup(1)), @@ -890,7 +890,7 @@ void tst_Tasking::testTree_data() // - task 1 should be stopped as a consequence of the error inside the group // - tasks 4 and 5 should be skipped const Group root2 { - ParallelLimit(2), + parallelLimit(2), Storage(storage), Group { onGroupSetup(groupSetup(1)), @@ -926,7 +926,7 @@ void tst_Tasking::testTree_data() continueOnError, Storage(storage), Group { - ParallelLimit(2), + parallelLimit(2), Group { onGroupSetup(groupSetup(1)), Test(setupSleepingTask(1, true, 20ms)) @@ -968,7 +968,7 @@ void tst_Tasking::testTree_data() { const Group root { - ParallelLimit(2), + parallelLimit(2), Storage(storage), Group { Storage(TreeStorage()), @@ -1018,7 +1018,7 @@ void tst_Tasking::testTree_data() { const Group root { - ParallelLimit(2), + parallelLimit(2), Storage(storage), Group { Storage(TreeStorage()), @@ -1064,7 +1064,7 @@ void tst_Tasking::testTree_data() { const Group root { - ParallelLimit(2), + parallelLimit(2), Storage(storage), Group { Storage(TreeStorage()), @@ -1278,7 +1278,7 @@ void tst_Tasking::testTree_data() // as in SEQUENTIAL mode the next task may only be started after the previous one finished. // In this case, the previous task (Group element) awaits for the barrier's advance to // come from the not yet started next task, causing a deadlock. - // The minimal requirement for this scenario to succeed is to set ParallelLimit(2) or more. + // The minimal requirement for this scenario to succeed is to set parallelLimit(2) or more. const Group root3 { Storage(storage), Storage(barrier), @@ -1434,7 +1434,7 @@ void tst_Tasking::testTree_data() // as in SEQUENTIAL mode the next task may only be started after the previous one finished. // In this case, the previous task (Group element) awaits for the barrier's advance to // come from the not yet started next task, causing a deadlock. - // The minimal requirement for this scenario to succeed is to set ParallelLimit(2) or more. + // The minimal requirement for this scenario to succeed is to set parallelLimit(2) or more. const Group root3 { Storage(storage), Storage(barrier), diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index de575346bf8..ac5df4b0f6c 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -171,14 +171,14 @@ int main(int argc, char *argv[]) const Group root { rootGroup->executeMode(), - Workflow(rootGroup->workflowPolicy()), + workflowPolicy(rootGroup->workflowPolicy()), onGroupSetup([rootGroup] { rootGroup->setState(State::Running); }), onGroupDone([rootGroup] { rootGroup->setState(State::Done); }), onGroupError([rootGroup] { rootGroup->setState(State::Error); }), Group { groupTask_1->executeMode(), - Workflow(groupTask_1->workflowPolicy()), + workflowPolicy(groupTask_1->workflowPolicy()), onGroupSetup([groupTask_1] { groupTask_1->setState(State::Running); }), onGroupDone([groupTask_1] { groupTask_1->setState(State::Done); }), onGroupError([groupTask_1] { groupTask_1->setState(State::Error); }), @@ -191,7 +191,7 @@ int main(int argc, char *argv[]) taskItem(task_3), Group { groupTask_4->executeMode(), - Workflow(groupTask_4->workflowPolicy()), + workflowPolicy(groupTask_4->workflowPolicy()), onGroupSetup([groupTask_4] { groupTask_4->setState(State::Running); }), onGroupDone([groupTask_4] { groupTask_4->setState(State::Done); }), onGroupError([groupTask_4] { groupTask_4->setState(State::Error); }), @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) taskItem(task_4_2), Group { groupTask_4_3->executeMode(), - Workflow(groupTask_4_3->workflowPolicy()), + workflowPolicy(groupTask_4_3->workflowPolicy()), onGroupSetup([groupTask_4_3] { groupTask_4_3->setState(State::Running); }), onGroupDone([groupTask_4_3] { groupTask_4_3->setState(State::Done); }), onGroupError([groupTask_4_3] { groupTask_4_3->setState(State::Error); }), diff --git a/tests/manual/tasktree/taskwidget.cpp b/tests/manual/tasktree/taskwidget.cpp index 0f721641813..e969dbf2d73 100644 --- a/tests/manual/tasktree/taskwidget.cpp +++ b/tests/manual/tasktree/taskwidget.cpp @@ -165,7 +165,7 @@ void GroupWidget::updateExecuteMode() m_executeCombo->setCurrentIndex(m_executeCombo->findData((int)m_executeMode)); } -Tasking::ParallelLimit GroupWidget::executeMode() const +Tasking::TaskItem GroupWidget::executeMode() const { return m_executeMode == ExecuteMode::Sequential ? Tasking::sequential : Tasking::parallel; } diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasktree/taskwidget.h index dc8821af5e1..c425f23965f 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasktree/taskwidget.h @@ -61,7 +61,7 @@ public: GroupWidget(); void setExecuteMode(ExecuteMode mode); - Tasking::ParallelLimit executeMode() const; + Tasking::TaskItem executeMode() const; void setWorkflowPolicy(Tasking::WorkflowPolicy policy); Tasking::WorkflowPolicy workflowPolicy() const; From e6875aa01e755856192651424260675ae4d1211a Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Thu, 18 May 2023 12:01:11 +0300 Subject: [PATCH 1149/1447] Android: don't stop deployment if kit's abis list is empty If the kit's detected abis list is empty for some reason, avoid blocking the deployment process. Fixes: QTCREATORBUG-27103 Change-Id: I9e7b01c123666f087c6d48e56af6e6637e147442 Reviewed-by: Reviewed-by: hjk --- src/plugins/android/androiddeployqtstep.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 84f0ffbbe59..f33ae5aa6b3 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -235,8 +235,7 @@ bool AndroidDeployQtStep::init() return false; } - const bool abiListNotEmpty = !selectedAbis.isEmpty() && !dev->supportedAbis().isEmpty(); - if (abiListNotEmpty && !dev->canSupportAbis(selectedAbis)) { + if (!dev->canSupportAbis(selectedAbis)) { const QString error = Tr::tr("The deployment device \"%1\" does not support the " "architectures used by the kit.\n" "The kit supports \"%2\", but the device uses \"%3\".") From c0ebf227a73d3047b495e72e4c64453273ce21de Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Mon, 22 May 2023 07:59:56 +0200 Subject: [PATCH 1150/1447] ProjectExplorer: Fix inverted if statement Change-Id: I94c9d8d5ff335ee53002fdb1ea75ca882e858d71 Reviewed-by: hjk --- src/plugins/projectexplorer/runcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 82aeeba4ff8..fde831943bb 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1058,7 +1058,7 @@ bool RunControl::showPromptToStopDialog(const QString &title, buttonTexts[QMessageBox::Cancel] = cancelButtonText; std::optional decider - = prompt ? std::nullopt : make_optional(CheckableMessageBox::make_decider(*prompt)); + = prompt ? make_optional(CheckableMessageBox::make_decider(*prompt)) : std::nullopt; auto selected = CheckableMessageBox::question(Core::ICore::dialogParent(), title, From d740a355bb1954714234edd13194ce158540bcc0 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 19 May 2023 10:09:59 +0200 Subject: [PATCH 1151/1447] Utils: Rework CheckableMessageBox Remove function overloads, thes are hard to read, to use and to extend. I'd even argue this should be a plain default ctor and a few setters + exec(), pretty much like Process::start() nowadays. Move "decider" magic into a structure that can be filled ad-hoc outside checkablemessagebox.cpp paving the ground for: ...removing aspect dependency from CheckableMessageBox, Instead, add a convenience function to BoolAspect. Arguably, the latter is not needed and could be done on the user side. Use pointers instead of mutable references for in-out parameter. Makes the "specialness" visible on the user side. Pass ICore::settings() centrally as done elsewhere to reduce line noise on the user side. Change-Id: Ibb366353d1ea35401723fd05ce05672617a0a8fd Reviewed-by: Marcus Tillmanns --- src/libs/utils/aspects.cpp | 12 +- src/libs/utils/aspects.h | 4 +- src/libs/utils/checkablemessagebox.cpp | 141 ++++++------ src/libs/utils/checkablemessagebox.h | 201 ++---------------- src/plugins/bookmarks/bookmarkmanager.cpp | 3 +- src/plugins/clangtools/clangtool.cpp | 3 +- src/plugins/clangtools/clangtoolsutils.cpp | 3 +- .../cmakebuildconfiguration.cpp | 2 +- .../cmakeprojectmanager.cpp | 2 +- src/plugins/coreplugin/coreplugin.cpp | 1 + .../editormanager/editormanager.cpp | 2 +- src/plugins/coreplugin/generalsettings.cpp | 5 +- .../coreplugin/locator/filesystemfilter.cpp | 3 +- src/plugins/debugger/breakhandler.cpp | 3 +- src/plugins/debugger/cdb/cdbengine.cpp | 6 +- src/plugins/debugger/debuggerengine.cpp | 9 +- src/plugins/debugger/debuggerplugin.cpp | 3 +- src/plugins/debugger/debuggerruncontrol.cpp | 2 +- src/plugins/debugger/watchhandler.cpp | 3 +- src/plugins/git/gitclient.cpp | 3 +- src/plugins/projectexplorer/runcontrol.cpp | 5 +- .../propertyeditor/aligndistribute.cpp | 3 +- src/plugins/squish/squishnavigationwidget.cpp | 3 +- .../studiowelcome/studiowelcomeplugin.cpp | 6 +- src/plugins/valgrind/memchecktool.cpp | 3 +- src/plugins/welcome/introductionwidget.cpp | 5 +- src/plugins/welcome/introductionwidget.h | 3 +- src/plugins/welcome/welcomeplugin.cpp | 3 +- .../crashhandlerdialog.cpp | 6 +- 29 files changed, 129 insertions(+), 319 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 082f4f8244a..e96014eba14 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -4,6 +4,7 @@ #include "aspects.h" #include "algorithm.h" +#include "checkablemessagebox.h" #include "environment.h" #include "fancylineedit.h" #include "layoutbuilder.h" @@ -1358,11 +1359,10 @@ FilePathAspect::FilePathAspect() The color aspect is displayed using a QtColorButton. */ -ColorAspect::ColorAspect(const QString &settingsKey) +ColorAspect::ColorAspect() : d(new Internal::ColorAspectPrivate) { setDefaultValue(QColor::fromRgb(0, 0, 0)); - setSettingsKey(settingsKey); setSpan(1, 1); addDataExtractor(this, &ColorAspect::value, &Data::value); @@ -1587,6 +1587,14 @@ void BoolAspect::setLabelPlacement(BoolAspect::LabelPlacement labelPlacement) d->m_labelPlacement = labelPlacement; } +CheckableDecider BoolAspect::checkableDecider() +{ + return CheckableDecider( + [this] { return !value(); }, + [this] { setValue(true); } + ); +} + /*! \class Utils::SelectionAspect \inmodule QtCreator diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index f6a35fa4ef8..1086c7445b6 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -24,6 +24,7 @@ namespace Utils { class AspectContainer; class BoolAspect; +class CheckableDecider; namespace Internal { class AspectContainerPrivate; @@ -222,6 +223,7 @@ public: void addToLayout(Layouting::LayoutItem &parent) override; std::function groupChecker(); + Utils::CheckableDecider checkableDecider(); QAction *action() override; @@ -255,7 +257,7 @@ class QTCREATOR_UTILS_EXPORT ColorAspect : public BaseAspect Q_OBJECT public: - explicit ColorAspect(const QString &settingsKey = QString()); + ColorAspect(); ~ColorAspect() override; struct Data : BaseAspect::Data diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index bf566e53a8a..d09c2941752 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -31,16 +31,19 @@ static const char kDoNotAskAgainKey[] = "DoNotAskAgain"; namespace Utils { +static QSettings *theSettings; + static QMessageBox::StandardButton exec( QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, - std::optional decider, + const CheckableDecider &decider, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton, QMessageBox::StandardButton acceptButton, - QMap buttonTextOverrides) + QMap buttonTextOverrides, + const QString &msg) { QMessageBox msgBox(parent); msgBox.setWindowTitle(title); @@ -59,18 +62,13 @@ static QMessageBox::StandardButton exec( } } - if (decider) { - if (!CheckableMessageBox::shouldAskAgain(*decider)) + if (decider.shouldAskAgain) { + if (!decider.shouldAskAgain()) return acceptButton; msgBox.setCheckBox(new QCheckBox); msgBox.checkBox()->setChecked(false); - - std::visit( - [&msgBox](auto &&decider) { - msgBox.checkBox()->setText(decider.text); - }, - *decider); + msgBox.checkBox()->setText(msg); } msgBox.setStandardButtons(buttons); @@ -81,21 +79,44 @@ static QMessageBox::StandardButton exec( QMessageBox::StandardButton clickedBtn = msgBox.standardButton(msgBox.clickedButton()); - if (decider && msgBox.checkBox()->isChecked() + if (decider.doNotAskAgain && msgBox.checkBox()->isChecked() && (acceptButton == QMessageBox::NoButton || clickedBtn == acceptButton)) - CheckableMessageBox::doNotAskAgain(*decider); + decider.doNotAskAgain(); return clickedBtn; } +CheckableDecider::CheckableDecider(const QString &settingsSubKey) +{ + QTC_ASSERT(theSettings, return); + shouldAskAgain = [settingsSubKey] { + theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey)); + bool shouldNotAsk = theSettings->value(settingsSubKey, false).toBool(); + theSettings->endGroup(); + return !shouldNotAsk; + }; + doNotAskAgain = [settingsSubKey] { + theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey)); + theSettings->setValue(settingsSubKey, true); + theSettings->endGroup(); + }; +} + +CheckableDecider::CheckableDecider(bool *storage) +{ + shouldAskAgain = [storage] { return !*storage; }; + doNotAskAgain = [storage] { *storage = true; }; +} + QMessageBox::StandardButton CheckableMessageBox::question( QWidget *parent, const QString &title, const QString &question, - std::optional decider, + const CheckableDecider &decider, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton, QMessageBox::StandardButton acceptButton, - QMap buttonTextOverrides) + QMap buttonTextOverrides, + const QString &msg) { return exec(parent, QMessageBox::Question, @@ -105,17 +126,19 @@ QMessageBox::StandardButton CheckableMessageBox::question( buttons, defaultButton, acceptButton, - buttonTextOverrides); + buttonTextOverrides, + msg.isEmpty() ? msgDoNotAskAgain() : msg); } QMessageBox::StandardButton CheckableMessageBox::information( QWidget *parent, const QString &title, const QString &text, - std::optional decider, + const CheckableDecider &decider, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton, - QMap buttonTextOverrides) + QMap buttonTextOverrides, + const QString &msg) { return exec(parent, QMessageBox::Information, @@ -125,82 +148,33 @@ QMessageBox::StandardButton CheckableMessageBox::information( buttons, defaultButton, QMessageBox::NoButton, - buttonTextOverrides); -} - -void CheckableMessageBox::doNotAskAgain(Decider &decider) -{ - std::visit( - [](auto &&decider) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - decider.doNotAskAgain = true; - } else if constexpr (std::is_same_v) { - decider.settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); - decider.settings->setValue(decider.settingsSubKey, true); - decider.settings->endGroup(); - } else if constexpr (std::is_same_v) { - decider.aspect.setValue(true); - } - }, - decider); -} - -bool CheckableMessageBox::shouldAskAgain(const Decider &decider) -{ - bool result = std::visit( - [](auto &&decider) { - using T = std::decay_t; - if constexpr (std::is_same_v) { - return !decider.doNotAskAgain; - } else if constexpr (std::is_same_v) { - decider.settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); - bool shouldNotAsk = decider.settings->value(decider.settingsSubKey, false).toBool(); - decider.settings->endGroup(); - return !shouldNotAsk; - } else if constexpr (std::is_same_v) { - return !decider.aspect.value(); - } - }, - decider); - - return result; -} - -bool CheckableMessageBox::shouldAskAgain(QSettings *settings, const QString &key) -{ - return shouldAskAgain(make_decider(settings, key)); -} - -void CheckableMessageBox::doNotAskAgain(QSettings *settings, const QString &key) -{ - Decider decider = make_decider(settings, key); - return doNotAskAgain(decider); + buttonTextOverrides, + msg.isEmpty() ? msgDoNotShowAgain() : msg); } /*! - Resets all suppression settings for doNotAskAgainQuestion() found in \a settings, + Resets all suppression settings for doNotAskAgainQuestion() so all these message boxes are shown again. */ -void CheckableMessageBox::resetAllDoNotAskAgainQuestions(QSettings *settings) +void CheckableMessageBox::resetAllDoNotAskAgainQuestions() { - QTC_ASSERT(settings, return); - settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); - settings->remove(QString()); - settings->endGroup(); + QTC_ASSERT(theSettings, return); + theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey)); + theSettings->remove(QString()); + theSettings->endGroup(); } /*! Returns whether any message boxes from doNotAskAgainQuestion() are suppressed - in the \a settings. + in the settings. */ -bool CheckableMessageBox::hasSuppressedQuestions(QSettings *settings) +bool CheckableMessageBox::hasSuppressedQuestions() { - QTC_ASSERT(settings, return false); - settings->beginGroup(QLatin1String(kDoNotAskAgainKey)); - const bool hasSuppressed = !settings->childKeys().isEmpty() - || !settings->childGroups().isEmpty(); - settings->endGroup(); + QTC_ASSERT(theSettings, return false); + theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey)); + const bool hasSuppressed = !theSettings->childKeys().isEmpty() + || !theSettings->childGroups().isEmpty(); + theSettings->endGroup(); return hasSuppressed; } @@ -222,4 +196,9 @@ QString CheckableMessageBox::msgDoNotShowAgain() return Tr::tr("Do not &show again"); } +void CheckableMessageBox::initialize(QSettings *settings) +{ + theSettings = settings; +} + } // namespace Utils diff --git a/src/libs/utils/checkablemessagebox.h b/src/libs/utils/checkablemessagebox.h index 1f4c84e1a79..3f156b2de1a 100644 --- a/src/libs/utils/checkablemessagebox.h +++ b/src/libs/utils/checkablemessagebox.h @@ -5,8 +5,6 @@ #include "utils_global.h" -#include "aspects.h" - #include QT_BEGIN_NAMESPACE @@ -15,208 +13,51 @@ QT_END_NAMESPACE namespace Utils { -class CheckableMessageBoxPrivate; +class QTCREATOR_UTILS_EXPORT CheckableDecider +{ +public: + CheckableDecider() = default; + CheckableDecider(const QString &settingsSubKey); + CheckableDecider(bool *doNotAskAgain); + CheckableDecider(const std::function &should, const std::function &doNot) + : shouldAskAgain(should), doNotAskAgain(doNot) + {} + + std::function shouldAskAgain; + std::function doNotAskAgain; +}; class QTCREATOR_UTILS_EXPORT CheckableMessageBox { public: - struct BoolDecision - { - QString text; - bool &doNotAskAgain; - }; - - struct SettingsDecision - { - QString text; - QSettings *settings; - QString settingsSubKey; - }; - - struct AspectDecision - { - QString text; - BoolAspect &aspect; - }; - - using Decider = std::variant; - - static Decider make_decider(QSettings *settings, - const QString &settingsSubKey, - const QString &text = msgDoNotAskAgain()) - { - return Decider{SettingsDecision{text, settings, settingsSubKey}}; - } - - static Decider make_decider(bool &doNotAskAgain, const QString &text = msgDoNotAskAgain()) - { - return Decider{BoolDecision{text, doNotAskAgain}}; - } - - static Decider make_decider(BoolAspect &aspect, const QString &text = msgDoNotAskAgain()) - { - return Decider{AspectDecision{text, aspect}}; - } - static QMessageBox::StandardButton question( QWidget *parent, const QString &title, const QString &question, - std::optional decider = std::nullopt, - QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, - QMessageBox::StandardButton defaultButton = QMessageBox::No, - QMessageBox::StandardButton acceptButton = QMessageBox::Yes, - QMap buttonTextOverrides = {}); - - static QMessageBox::StandardButton question( - QWidget *parent, - const QString &title, - const QString &question, - bool &value, + const CheckableDecider &decider, QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, QMessageBox::StandardButton defaultButton = QMessageBox::No, QMessageBox::StandardButton acceptButton = QMessageBox::Yes, QMap buttonTextOverrides = {}, - const QString &text = msgDoNotAskAgain()) - { - Decider decider = make_decider(value, text); - return CheckableMessageBox::question(parent, - title, - question, - decider, - buttons, - defaultButton, - acceptButton, - buttonTextOverrides); - } - - static QMessageBox::StandardButton question( - QWidget *parent, - const QString &title, - const QString &question, - QSettings *settings, - const QString &settingsSubKey, - QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, - QMessageBox::StandardButton defaultButton = QMessageBox::No, - QMessageBox::StandardButton acceptButton = QMessageBox::Yes, - QMap buttonTextOverrides = {}, - const QString &text = msgDoNotAskAgain()) - { - Decider decider = make_decider(settings, settingsSubKey, text); - return CheckableMessageBox::question(parent, - title, - question, - decider, - buttons, - defaultButton, - acceptButton, - buttonTextOverrides); - } - - static QMessageBox::StandardButton question( - QWidget *parent, - const QString &title, - const QString &question, - BoolAspect &aspect, - QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, - QMessageBox::StandardButton defaultButton = QMessageBox::No, - QMessageBox::StandardButton acceptButton = QMessageBox::Yes, - QMap buttonTextOverrides = {}, - const QString &text = msgDoNotAskAgain()) - { - Decider decider = make_decider(aspect, text); - return CheckableMessageBox::question(parent, - title, - question, - decider, - buttons, - defaultButton, - acceptButton, - buttonTextOverrides); - } + const QString &msg = {}); static QMessageBox::StandardButton information( QWidget *parent, const QString &title, const QString &text, - std::optional decider = std::nullopt, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, - QMap buttonTextOverrides = {}); - - static QMessageBox::StandardButton information( - QWidget *parent, - const QString &title, - const QString &information, - bool &value, + const CheckableDecider &decider, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, QMap buttonTextOverrides = {}, - const QString &text = msgDoNotAskAgain()) - { - Decider decider = make_decider(value, text); - return CheckableMessageBox::information(parent, - title, - information, - decider, - buttons, - defaultButton, - buttonTextOverrides); - } - - static QMessageBox::StandardButton information( - QWidget *parent, - const QString &title, - const QString &information, - QSettings *settings, - const QString &settingsSubKey, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, - QMap buttonTextOverrides = {}, - const QString &text = msgDoNotAskAgain()) - { - Decider decider = make_decider(settings, settingsSubKey, text); - return CheckableMessageBox::information(parent, - title, - information, - decider, - buttons, - defaultButton, - buttonTextOverrides); - } - - static QMessageBox::StandardButton information( - QWidget *parent, - const QString &title, - const QString &information, - BoolAspect &aspect, - QMessageBox::StandardButtons buttons = QMessageBox::Ok, - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton, - QMap buttonTextOverrides = {}, - const QString &text = msgDoNotAskAgain()) - { - Decider decider = make_decider(aspect, text); - return CheckableMessageBox::information(parent, - title, - information, - decider, - buttons, - defaultButton, - buttonTextOverrides); - } - - // check and set "ask again" status - static bool shouldAskAgain(const Decider &decider); - static void doNotAskAgain(Decider &decider); - - static bool shouldAskAgain(QSettings *settings, const QString &key); - static void doNotAskAgain(QSettings *settings, const QString &key); + const QString &msg = {}); // Conversion convenience - static void resetAllDoNotAskAgainQuestions(QSettings *settings); - static bool hasSuppressedQuestions(QSettings *settings); + static void resetAllDoNotAskAgainQuestions(); + static bool hasSuppressedQuestions(); static QString msgDoNotAskAgain(); static QString msgDoNotShowAgain(); + + static void initialize(QSettings *settings); }; } // namespace Utils diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp index 77bb0f41518..791455d619a 100644 --- a/src/plugins/bookmarks/bookmarkmanager.cpp +++ b/src/plugins/bookmarks/bookmarkmanager.cpp @@ -261,8 +261,7 @@ void BookmarkView::removeAll() Tr::tr("Remove All Bookmarks"), Tr::tr("Are you sure you want to remove all bookmarks from " "all files in the current session?"), - ICore::settings(), - QLatin1String("RemoveAllBookmarks")) + QString("RemoveAllBookmarks")) != QMessageBox::Yes) return; diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 343849458aa..00da4bb880e 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -602,8 +602,7 @@ static bool continueDespiteReleaseBuild(const QString &toolName) return CheckableMessageBox::question(ICore::dialogParent(), title, message, - ICore::settings(), - "ClangToolsCorrectModeWarning") + QString("ClangToolsCorrectModeWarning")) == QMessageBox::Yes; } diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index a2cdd5fc7ba..de3ac2b9cba 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -141,8 +141,7 @@ void showHintAboutBuildBeforeAnalysis() Utils::CheckableMessageBox::information(Core::ICore::dialogParent(), Tr::tr("Info About Build the Project Before Analysis"), hintAboutBuildBeforeAnalysis(), - Core::ICore::settings(), - "ClangToolsDisablingBuildBeforeAnalysisHint"); + QString("ClangToolsDisablingBuildBeforeAnalysisHint")); } FilePath fullPath(const FilePath &executable) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 7a6a192e80f..5ddc68c1c23 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -594,7 +594,7 @@ void CMakeBuildSettingsWidget::reconfigureWithInitialParameters() Core::ICore::dialogParent(), Tr::tr("Re-configure with Initial Parameters"), Tr::tr("Clear CMake configuration and configure with initial parameters?"), - settings->askBeforeReConfigureInitialParams, + settings->askBeforeReConfigureInitialParams.checkableDecider(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index a1950b6bccd..c43c7978a61 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -238,7 +238,7 @@ void CMakeManager::reloadCMakePresets() Tr::tr("Reload CMake Presets"), Tr::tr("Re-generates the CMake presets kits. The manual " "CMake project modifications will be lost."), - settings->askBeforePresetsReload, + settings->askBeforePresetsReload.checkableDecider(), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes, QMessageBox::Yes, diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index bf8e09b67b5..1a4ec33ef87 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -148,6 +148,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) Theme::setInitialPalette(theme); // Initialize palette before setting it setCreatorTheme(theme); InfoBar::initialize(ICore::settings()); + CheckableMessageBox::initialize(ICore::settings()); new ActionManager(this); ActionManager::setPresentationModeEnabled(args.presentationMode); m_mainWindow = new MainWindow; diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 107ce249e1e..227ffba28c8 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -753,7 +753,7 @@ bool EditorManagerPrivate::skipOpeningBigTextFile(const FilePath &filePath) .arg(fileSizeInMB, 0, 'f', 2); bool askAgain = true; - auto decider = CheckableMessageBox::make_decider(askAgain); + CheckableDecider decider(&askAgain); QMessageBox::StandardButton clickedButton = CheckableMessageBox::question(ICore::dialogParent(), title, text, decider); diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp index e97797c9fc7..19b66e64497 100644 --- a/src/plugins/coreplugin/generalsettings.cpp +++ b/src/plugins/coreplugin/generalsettings.cpp @@ -226,14 +226,13 @@ void GeneralSettingsWidget::resetInterfaceColor() void GeneralSettingsWidget::resetWarnings() { InfoBar::clearGloballySuppressed(); - CheckableMessageBox::resetAllDoNotAskAgainQuestions(ICore::settings()); + CheckableMessageBox::resetAllDoNotAskAgainQuestions(); m_resetWarningsButton->setEnabled(false); } bool GeneralSettingsWidget::canResetWarnings() { - return InfoBar::anyGloballySuppressed() - || CheckableMessageBox::hasSuppressedQuestions(ICore::settings()); + return InfoBar::anyGloballySuppressed() || CheckableMessageBox::hasSuppressedQuestions(); } void GeneralSettingsWidget::resetLanguage() diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 32ad0a2a2bf..7c6ac13abda 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -63,8 +63,7 @@ static bool askForCreating(const QString &title, const FilePath &filePath) = CheckableMessageBox::question(ICore::dialogParent(), title, Tr::tr("Create \"%1\"?").arg(filePath.shortNativePath()), - ICore::settings(), - kAlwaysCreate, + QString(kAlwaysCreate), QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel, QMessageBox::Yes, diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 2b21db5be53..e08b155d8e7 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -2697,8 +2697,7 @@ void BreakpointManager::executeDeleteAllBreakpointsDialog() Tr::tr("Remove All Breakpoints"), Tr::tr("Are you sure you want to remove all breakpoints " "from all files in the current session?"), - ICore::settings(), - "RemoveAllBreakpoints"); + QString("RemoveAllBreakpoints")); if (pressed != QMessageBox::Yes) return; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 52e6d71fe6a..e6d54ad2e5c 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2265,8 +2265,7 @@ void CdbEngine::checkQtSdkPdbFiles(const QString &module) CheckableMessageBox::information(Core::ICore::dialogParent(), Tr::tr("Missing Qt Debug Information"), message, - Core::ICore::settings(), - "CdbQtSdkPdbHint"); + QString("CdbQtSdkPdbHint")); showMessage("Missing Qt Debug Information Files package for " + qtName, LogMisc); }; @@ -2294,8 +2293,7 @@ void CdbEngine::parseOutputLine(QString line) "Make sure that your antivirus solution is up to date and if that does not work " "consider adding an exception for %1.") .arg(m_extensionFileName), - Core::ICore::settings(), - "SecureInfoCdbextCannotBeLoaded"); + QString("SecureInfoCdbextCannotBeLoaded")); notifyEngineSetupFailed(); } static const QString creatorExtPrefix = "|"; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 28d218929a6..27c1373c99e 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2716,17 +2716,14 @@ Context CppDebuggerEngine::languageContext() const void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) { static const QString warnOnInappropriateDebuggerKey = "DebuggerWarnOnInappropriateDebugger"; - QtcSettings *coreSettings = Core::ICore::settings(); const bool warnOnRelease = debuggerSettings()->warnOnReleaseBuilds.value() && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor; bool warnOnInappropriateDebugger = false; QString detailedWarning; - auto shouldAskAgain = CheckableMessageBox::make_decider(coreSettings, - warnOnInappropriateDebuggerKey); switch (rp.toolChainAbi.binaryFormat()) { case Abi::PEFormat: { - if (CheckableMessageBox::shouldAskAgain(shouldAskAgain)) { + if (CheckableDecider(warnOnInappropriateDebuggerKey).shouldAskAgain()) { QString preferredDebugger; if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) { if (rp.cppEngineType == CdbEngineType) @@ -2766,7 +2763,7 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) break; } case Abi::ElfFormat: { - if (CheckableMessageBox::shouldAskAgain(shouldAskAgain)) { + if (CheckableDecider(warnOnInappropriateDebuggerKey).shouldAskAgain()) { if (rp.cppEngineType == CdbEngineType) { warnOnInappropriateDebugger = true; detailedWarning = Tr::tr( @@ -2879,7 +2876,7 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) "Examining symbols and setting breakpoints by file name and line number " "may fail.\n") + '\n' + detailedWarning, - shouldAskAgain); + warnOnInappropriateDebuggerKey); } else if (warnOnRelease) { AsynchronousMessageBox::information(Tr::tr("Warning"), Tr::tr("This does not seem to be a \"Debug\" build.\n" diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 8b14ff0e236..87ae84dd8d6 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -2243,8 +2243,7 @@ bool wantRunTool(ToolMode toolMode, const QString &toolName) if (Utils::CheckableMessageBox::question(ICore::dialogParent(), title, message, - ICore::settings(), - "AnalyzerCorrectModeWarning") + QString("AnalyzerCorrectModeWarning")) != QMessageBox::Yes) return false; } diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 17da601429d..e3feb04e393 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -620,7 +620,7 @@ void DebuggerRunTool::start() CheckableMessageBox::information(Core::ICore::dialogParent(), Tr::tr("Debugger"), warningMessage, - doNotShowAgain, + &doNotShowAgain, QMessageBox::Ok); } } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index d533a0d4f63..734bab3b3ca 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -2576,8 +2576,7 @@ void WatchModel::clearWatches() ICore::dialogParent(), Tr::tr("Remove All Expression Evaluators"), Tr::tr("Are you sure you want to remove all expression evaluators?"), - ICore::settings(), - "RemoveAllWatchers"); + QString("RemoveAllWatchers")); if (ret != QMessageBox::Yes) return; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 5c1d82d359f..4a7a43a689f 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -1297,8 +1297,7 @@ QStringList GitClient::setupCheckoutArguments(const FilePath &workingDirectory, ICore::dialogParent() /*parent*/, Tr::tr("Create Local Branch") /*title*/, Tr::tr("Would you like to create a local branch?") /*message*/, - ICore::settings(), - "Git.CreateLocalBranchOnCheckout" /*setting*/, + QString("Git.CreateLocalBranchOnCheckout"), /* decider */ QMessageBox::Yes | QMessageBox::No /*buttons*/, QMessageBox::No /*default button*/, QMessageBox::No /*button to save*/) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index fde831943bb..f9bafd234ad 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1057,8 +1057,9 @@ bool RunControl::showPromptToStopDialog(const QString &title, if (!cancelButtonText.isEmpty()) buttonTexts[QMessageBox::Cancel] = cancelButtonText; - std::optional decider - = prompt ? make_optional(CheckableMessageBox::make_decider(*prompt)) : std::nullopt; + CheckableDecider decider; + if (prompt) + decider = CheckableDecider(prompt); auto selected = CheckableMessageBox::question(Core::ICore::dialogParent(), title, diff --git a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp index f71f04fd398..5d8400b47e2 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp @@ -663,8 +663,7 @@ AlignDistribute::Dimension AlignDistribute::getDimension(Target target) const bool AlignDistribute::executePixelPerfectDialog() const { - auto decider = Utils::CheckableMessageBox::make_decider(Core::ICore::settings(), - "WarnAboutPixelPerfectDistribution"); + Utils::CheckableDecider decider(QString("WarnAboutPixelPerfectDistribution")); QMessageBox::StandardButton pressed = Utils::CheckableMessageBox::question( Core::ICore::dialogParent(), diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index 1b99c338f16..5e51e5980e9 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -302,8 +302,7 @@ void SquishNavigationWidget::onRecordTestCase(const QString &suiteName, const QS Tr::tr("Do you want to record over the test case \"%1\"? The existing content will " "be overwritten by the recorded script.") .arg(testCase), - Core::ICore::settings(), - "RecordWithoutApproval"); + QString("RecordWithoutApproval")); if (pressed != QMessageBox::Yes) return; diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index ba58c0bd742..9604c0f1ec6 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -489,8 +489,7 @@ private: void StudioWelcomePlugin::closeSplashScreen() { - Utils::CheckableMessageBox::doNotAskAgain(Core::ICore::settings(), - DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY); + Utils::CheckableDecider(DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY).doNotAskAgain(); if (!s_viewWindow.isNull()) s_viewWindow->deleteLater(); @@ -538,8 +537,7 @@ static bool showSplashScreen() return true; } - return Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(), - DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY); + return Utils::CheckableDecider(DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY).shouldAskAgain(); } void StudioWelcomePlugin::extensionsInitialized() diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 552d5a28233..21a0c2290c1 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -808,8 +808,7 @@ void MemcheckToolPrivate::heobAction() .arg( "Dwarfstack"), - ICore::settings(), - "HeobDwarfstackInfo", + QString("HeobDwarfstackInfo"), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok) diff --git a/src/plugins/welcome/introductionwidget.cpp b/src/plugins/welcome/introductionwidget.cpp index 4ee3e7868b3..ef56d9ab3ed 100644 --- a/src/plugins/welcome/introductionwidget.cpp +++ b/src/plugins/welcome/introductionwidget.cpp @@ -26,11 +26,10 @@ const char kTakeTourSetting[] = "TakeUITour"; namespace Welcome { namespace Internal { -void IntroductionWidget::askUserAboutIntroduction(QWidget *parent, QSettings *settings) +void IntroductionWidget::askUserAboutIntroduction(QWidget *parent) { - auto decider = CheckableMessageBox::make_decider(settings, kTakeTourSetting); // CheckableMessageBox for compatibility with Qt Creator < 4.11 - if (!CheckableMessageBox::shouldAskAgain(decider) + if (!CheckableDecider(QString(kTakeTourSetting)).shouldAskAgain() || !Core::ICore::infoBar()->canInfoBeAdded(kTakeTourSetting)) return; diff --git a/src/plugins/welcome/introductionwidget.h b/src/plugins/welcome/introductionwidget.h index a11069003a0..4b1f99c5ae3 100644 --- a/src/plugins/welcome/introductionwidget.h +++ b/src/plugins/welcome/introductionwidget.h @@ -11,7 +11,6 @@ QT_BEGIN_NAMESPACE class QLabel; -class QSettings; QT_END_NAMESPACE namespace Welcome { @@ -31,7 +30,7 @@ class IntroductionWidget : public QWidget public: explicit IntroductionWidget(QWidget *parent = nullptr); - static void askUserAboutIntroduction(QWidget *parent, QSettings *settings); + static void askUserAboutIntroduction(QWidget *parent); protected: bool event(QEvent *e) override; diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index 1a1a1aa647f..915695dafa2 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -132,8 +132,7 @@ public: if (!arguments.contains("-notour")) { connect(ICore::instance(), &ICore::coreOpened, this, []() { - IntroductionWidget::askUserAboutIntroduction(ICore::dialogParent(), - ICore::settings()); + IntroductionWidget::askUserAboutIntroduction(ICore::dialogParent()); }, Qt::QueuedConnection); } diff --git a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp index 61d1fd4230d..c8853f53459 100644 --- a/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp +++ b/src/tools/qtcreatorcrashhandler/crashhandlerdialog.cpp @@ -209,6 +209,8 @@ bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished() QSettings::UserScope, QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR), QLatin1String(SettingsApplication)); + Utils::CheckableMessageBox::initialize(&settings); + // Ask user. const QString title = tr("Run Debugger And Abort Collecting Backtrace?"); const QString message = tr( @@ -222,9 +224,7 @@ bool CrashHandlerDialog::runDebuggerWhileBacktraceNotFinished() = Utils::CheckableMessageBox::question(this, title, message, - &settings, - QLatin1String( - SettingsKeySkipWarningAbortingBacktrace), + QString(SettingsKeySkipWarningAbortingBacktrace), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); From d0881f55420062f6898a091090935307c80b617b Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 08:15:05 +0200 Subject: [PATCH 1152/1447] Utils: Remove a unused aspect ctor parameters Change-Id: I6e3c6ce7b04a7817f35da10f1975ae2fec62b9e4 Reviewed-by: Christian Stenger --- src/libs/utils/aspects.cpp | 3 +-- src/libs/utils/aspects.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index e96014eba14..613a5561ea9 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1426,11 +1426,10 @@ void ColorAspect::setVolatileValue(const QVariant &val) */ -BoolAspect::BoolAspect(const QString &settingsKey) +BoolAspect::BoolAspect() : d(new Internal::BoolAspectPrivate) { setDefaultValue(false); - setSettingsKey(settingsKey); setSpan(2, 1); addDataExtractor(this, &BoolAspect::value, &Data::value); diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 1086c7445b6..ecfc9ee86bf 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -213,7 +213,7 @@ class QTCREATOR_UTILS_EXPORT BoolAspect : public BaseAspect Q_OBJECT public: - explicit BoolAspect(const QString &settingsKey = QString()); + BoolAspect(); ~BoolAspect() override; struct Data : BaseAspect::Data From 07934fadcfbddaf804298f5efa3f573c46231f00 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 8 May 2023 10:58:05 +0200 Subject: [PATCH 1153/1447] Examples: Use Qt logging instead of environment variable Use logging category qtc.examples instead of a custom QTC_DEBUG_EXAMPLESMODEL environment variable. Change-Id: Idbd6d4b29dbd7b9e8c5976eca6efeb232bf7fa5f Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/qtsupport/exampleslistmodel.cpp | 55 ++++++++++----------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index ebb90381c7b..84e1b57ab1c 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -38,6 +39,8 @@ using namespace Utils; namespace QtSupport { namespace Internal { +static QLoggingCategory log = QLoggingCategory("qtc.examples", QtWarningMsg); + static bool debugExamples() { return qtcEnvironmentVariableIsSet("QTC_DEBUG_EXAMPLESMODEL"); @@ -64,16 +67,16 @@ int ExampleSetModel::readCurrentIndexFromSettings() const ExampleSetModel::ExampleSetModel() { + if (debugExamples() && !log().isDebugEnabled()) + log().setEnabled(QtDebugMsg, true); // read extra example sets settings QSettings *settings = Core::ICore::settings(); const QStringList list = settings->value("Help/InstalledExamples", QStringList()).toStringList(); - if (debugExamples()) - qWarning() << "Reading Help/InstalledExamples from settings:" << list; + qCDebug(log) << "Reading Help/InstalledExamples from settings:" << list; for (const QString &item : list) { const QStringList &parts = item.split(QLatin1Char('|')); if (parts.size() < 3) { - if (debugExamples()) - qWarning() << "Item" << item << "has less than 3 parts (separated by '|'):" << parts; + qCDebug(log) << "Item" << item << "has less than 3 parts (separated by '|'):" << parts; continue; } ExtraExampleSet set; @@ -82,15 +85,13 @@ ExampleSetModel::ExampleSetModel() set.examplesPath = parts.at(2); QFileInfo fi(set.manifestPath); if (!fi.isDir() || !fi.isReadable()) { - if (debugExamples()) - qWarning() << "Manifest path " << set.manifestPath << "is not a readable directory, ignoring"; + qCDebug(log) << "Manifest path " << set.manifestPath + << "is not a readable directory, ignoring"; continue; } - if (debugExamples()) { - qWarning() << "Adding examples set displayName=" << set.displayName - << ", manifestPath=" << set.manifestPath - << ", examplesPath=" << set.examplesPath; - } + qCDebug(log) << "Adding examples set displayName=" << set.displayName + << ", manifestPath=" << set.manifestPath + << ", examplesPath=" << set.examplesPath; if (!Utils::anyOf(m_extraExampleSets, [&set](const ExtraExampleSet &s) { return FilePath::fromString(s.examplesPath).cleanPath() == FilePath::fromString(set.examplesPath).cleanPath() @@ -98,8 +99,8 @@ ExampleSetModel::ExampleSetModel() == FilePath::fromString(set.manifestPath).cleanPath(); })) { m_extraExampleSets.append(set); - } else if (debugExamples()) { - qWarning() << "Not adding, because example set with same directories exists"; + } else { + qCDebug(log) << "Not adding, because example set with same directories exists"; } } m_extraExampleSets += pluginRegisteredExampleSets(); @@ -138,11 +139,9 @@ void ExampleSetModel::recreateModel(const QtVersions &qtVersions) if (extraManifestDirs.contains(version->docsPath())) { m_extraExampleSets[extraManifestDirs.value(version->docsPath())].qtVersion = version->qtVersion(); - if (debugExamples()) { - qWarning() << "Not showing Qt version because manifest path is already added " - "through InstalledExamples settings:" - << version->displayName(); - } + qCDebug(log) << "Not showing Qt version because manifest path is already added " + "through InstalledExamples settings:" + << version->displayName(); continue; } auto newItem = new QStandardItem(); @@ -319,11 +318,11 @@ static bool isValidExampleOrDemo(ExampleItem *item) } if (!ok) { item->tags.append(QLatin1String("broken")); - if (debugExamples()) - qWarning() << QString::fromLatin1("ERROR: Item \"%1\" broken: %2").arg(item->name, reason); + qCDebug(log) << QString::fromLatin1("ERROR: Item \"%1\" broken: %2").arg(item->name, reason); } - if (debugExamples() && item->description.isEmpty()) - qWarning() << QString::fromLatin1("WARNING: Item \"%1\" has no description").arg(item->name); + if (item->description.isEmpty()) + qCDebug(log) << QString::fromLatin1("WARNING: Item \"%1\" has no description") + .arg(item->name); return ok || debugExamples(); } @@ -396,10 +395,8 @@ void ExamplesViewController::updateExamples() QList items; for (const QString &exampleSource : sources) { const auto manifest = FilePath::fromUserInput(exampleSource); - if (debugExamples()) { - qWarning() << QString::fromLatin1("Reading file \"%1\"...") - .arg(manifest.absoluteFilePath().toUserOutput()); - } + qCDebug(log) << QString::fromLatin1("Reading file \"%1\"...") + .arg(manifest.absoluteFilePath().toUserOutput()); const expected_str> result = parseExamples(manifest, @@ -407,10 +404,8 @@ void ExamplesViewController::updateExamples() FilePath::fromUserInput(demosInstallPath), m_isExamples); if (!result) { - if (debugExamples()) { - qWarning() << "ERROR: Could not read examples from" << exampleSource << ":" - << result.error(); - } + qCDebug(log) << "ERROR: Could not read examples from" << exampleSource << ":" + << result.error(); continue; } items += filtered(*result, isValidExampleOrDemo); From dfcfea478eac8fe8a29c34f0345627157f05be01 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 16 May 2023 19:01:54 +0200 Subject: [PATCH 1154/1447] PerfProfiler: Re-organize general command line construction ... to avoid unnecessary argument splitting. Also, make a potentially missing access to the settings more noticeable to the user. Task-number: QTCREATORBUG-28701 Change-Id: I7b7f7f5f6a68357dbec064516370bacbf00746dc Reviewed-by: Ulf Hermann Reviewed-by: Reviewed-by: Eike Ziller --- .../perfprofiler/perfprofilerruncontrol.cpp | 14 ++++++-------- src/plugins/perfprofiler/perfsettings.cpp | 12 ++++++------ src/plugins/perfprofiler/perfsettings.h | 3 +-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp index 8579a9cf7cb..3d633160133 100644 --- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp +++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp @@ -95,16 +95,15 @@ public: : RunWorker(runControl) { setId("LocalPerfRecordWorker"); - - auto perfAspect = runControl->aspect(); - QTC_ASSERT(perfAspect, return); - PerfSettings *settings = static_cast(perfAspect->currentSettings); - QTC_ASSERT(settings, return); - m_perfRecordArguments = settings->perfRecordArguments(); } void start() override { + auto perfAspect = runControl()->aspect(); + QTC_ASSERT(perfAspect, reportFailure(); return); + PerfSettings *settings = static_cast(perfAspect->currentSettings); + QTC_ASSERT(settings, reportFailure(); return); + m_process = new Process(this); connect(m_process, &Process::started, this, &RunWorker::reportStarted); @@ -125,7 +124,7 @@ public: }); CommandLine cmd({device()->filePath("perf"), {"record"}}); - cmd.addArgs(m_perfRecordArguments); + settings->addPerfRecordArguments(&cmd); cmd.addArgs({"-o", "-", "--"}); cmd.addCommandLineAsArgs(runControl()->commandLine(), CommandLine::Raw); @@ -145,7 +144,6 @@ public: private: QPointer m_process; - QStringList m_perfRecordArguments; }; diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index e5f307b85ae..9cfdf3d92c7 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -103,7 +103,7 @@ void PerfSettings::writeGlobalSettings() const settings->endGroup(); } -QStringList PerfSettings::perfRecordArguments() const +void PerfSettings::addPerfRecordArguments(CommandLine *cmd) const { QString callgraphArg = callgraphMode.itemValue().toString(); if (callgraphArg == Constants::PerfCallgraphDwarf) @@ -118,11 +118,11 @@ QStringList PerfSettings::perfRecordArguments() const } } - return QStringList({"-e", events, - "--call-graph", callgraphArg, - sampleMode.itemValue().toString(), - QString::number(period.value())}) - + ProcessArgs::splitArgs(extraArguments.value(), HostOsInfo::hostOs()); + cmd->addArgs({"-e", events, + "--call-graph", callgraphArg, + sampleMode.itemValue().toString(), + QString::number(period.value())}); + cmd->addArgs(extraArguments(), CommandLine::Raw); } void PerfSettings::resetToDefault() diff --git a/src/plugins/perfprofiler/perfsettings.h b/src/plugins/perfprofiler/perfsettings.h index fc808c1e118..4e8ae5700f8 100644 --- a/src/plugins/perfprofiler/perfsettings.h +++ b/src/plugins/perfprofiler/perfsettings.h @@ -14,7 +14,6 @@ namespace PerfProfiler { class PERFPROFILER_EXPORT PerfSettings final : public ProjectExplorer::ISettingsAspect { Q_OBJECT - Q_PROPERTY(QStringList perfRecordArguments READ perfRecordArguments NOTIFY changed) public: explicit PerfSettings(ProjectExplorer::Target *target = nullptr); @@ -23,7 +22,7 @@ public: void readGlobalSettings(); void writeGlobalSettings() const; - QStringList perfRecordArguments() const; + void addPerfRecordArguments(Utils::CommandLine *cmd) const; void resetToDefault(); From 355589f4c218ac1d9810b51145dac30348e5a685 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 19 May 2023 09:49:53 +0200 Subject: [PATCH 1155/1447] Fossil: Remove unused variable Change-Id: I4a55ccacc6daccab653666c943f6aeb931e11c89 Reviewed-by: Orgad Shaneh --- src/plugins/fossil/fossilclient.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index 49ded9c7740..11d2bf868d1 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -107,12 +107,9 @@ class FossilLogConfig : public VcsBaseEditorConfig Q_OBJECT public: - FossilLogConfig(FossilClient *client, QToolBar *toolBar) : - VcsBaseEditorConfig(toolBar), - m_client(client) + FossilLogConfig(QToolBar *toolBar) + : VcsBaseEditorConfig(toolBar) { - QTC_ASSERT(client, return); - addReloadButton(); addLineageComboBox(); addVerboseToggleButton(); @@ -192,9 +189,6 @@ public: } return args; } - -private: - FossilClient *m_client; }; unsigned FossilClient::makeVersionNumber(int major, int minor, int patch) @@ -1170,7 +1164,7 @@ VcsBaseEditorConfig *FossilClient::createLogCurrentFileEditor(VcsBaseEditorWidge VcsBaseEditorConfig *FossilClient::createLogEditor(VcsBaseEditorWidget *editor) { - return new FossilLogConfig(this, editor->toolBar()); + return new FossilLogConfig(editor->toolBar()); } } // namespace Internal From c9638ff64291351b846d28c28f077bbe70f6c1f0 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 19 May 2023 19:31:22 +0200 Subject: [PATCH 1156/1447] TaskTree: Fix docs about empty Group and different workflows Add tests for empty Group with different workflow policies. Add tests for successful / failing task in a Group with different workflow policies. Change-Id: I50129713f836d2146b119ceb73b5ae43abf01639 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 17 ++- tests/auto/solutions/tasking/tst_tasking.cpp | 109 +++++++++++++++++++ 2 files changed, 116 insertions(+), 10 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 4e9cab7bb90..3ee5f89f9f7 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1180,8 +1180,7 @@ void TaskNode::invokeEndHandler(bool success) sequential mode). \li Immediately finishes with an error. \endlist - If all child tasks finish successfully or the group is empty, the group - finishes with success. + If all child tasks finish successfully, the group finishes with success. \row \li continueOnError \li Similar to stopOnError, but in case any child finishes with @@ -1194,8 +1193,7 @@ void TaskNode::invokeEndHandler(bool success) started yet. \li Finishes with an error when all tasks finish. \endlist - If all tasks finish successfully or the group is empty, the group - finishes with success. + If all tasks finish successfully, the group finishes with success. \row \li stopOnDone \li If a task finishes with success, the group: @@ -1203,8 +1201,7 @@ void TaskNode::invokeEndHandler(bool success) \li Stops running tasks and skips those that it has not started. \li Immediately finishes with success. \endlist - If all tasks finish with an error or the group is empty, the group - finishes with an error. + If all tasks finish with an error, the group finishes with an error. \row \li continueOnDone \li Similar to stopOnDone, but in case any child finishes @@ -1217,22 +1214,22 @@ void TaskNode::invokeEndHandler(bool success) started yet. \li Finishes with success when all tasks finish. \endlist - If all tasks finish with an error or the group is empty, the group - finishes with an error. + If all tasks finish with an error, the group finishes with an error. \row \li stopOnFinished \li The group starts as many tasks as it can. When a task finishes the group stops and reports the task's result. - When the group is empty, it finishes immediately with success. Useful only in parallel mode. In sequential mode, only the first task is started, and when finished, the group finishes too, so the other tasks are ignored. \row \li optional \li The group executes all tasks and ignores their return state. If all - tasks finish or the group is empty, the group finishes with success. + tasks finish, the group finishes with success. \endtable + When the group is empty, it finishes immediately with success, + regardless of its workflow policy. If a child of a group is also a group (in a nested tree), the child group runs its tasks according to its own workflow policy. diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index fb8e575322f..7da3177b8a8 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -631,6 +631,115 @@ void tst_Tasking::testTree_data() QTest::newRow("SequentialError") << TestData{storage, root, log, 5, OnDone::Failure}; } + { + const auto constructEmptyWorkflow = [=](WorkflowPolicy policy) { + return Group { + Storage(storage), + workflowPolicy(policy), + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) + }; + }; + + const Log log = {{0, Handler::GroupDone}}; + + const Group root1 = constructEmptyWorkflow(WorkflowPolicy::StopOnError); + QTest::newRow("EmptyStopOnError") << TestData{storage, root1, log, 0, OnDone::Success}; + + const Group root2 = constructEmptyWorkflow(WorkflowPolicy::ContinueOnError); + QTest::newRow("EmptyContinueOnError") << TestData{storage, root2, log, 0, OnDone::Success}; + + const Group root3 = constructEmptyWorkflow(WorkflowPolicy::StopOnDone); + QTest::newRow("EmptyStopOnDone") << TestData{storage, root3, log, 0, OnDone::Success}; + + const Group root4 = constructEmptyWorkflow(WorkflowPolicy::ContinueOnDone); + QTest::newRow("EmptyContinueOnDone") << TestData{storage, root4, log, 0, OnDone::Success}; + + const Group root5 = constructEmptyWorkflow(WorkflowPolicy::StopOnFinished); + QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, log, 0, OnDone::Success}; + + const Group root6 = constructEmptyWorkflow(WorkflowPolicy::Optional); + QTest::newRow("EmptyOptional") << TestData{storage, root6, log, 0, OnDone::Success}; + } + + { + const auto constructDoneWorkflow = [=](WorkflowPolicy policy) { + return Group { + Storage(storage), + workflowPolicy(policy), + Test(setupTask(1), logDone, logError), + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) + }; + }; + + const Log log = { + {1, Handler::Setup}, + {1, Handler::Done}, + {0, Handler::GroupDone} + }; + + const Group root1 = constructDoneWorkflow(WorkflowPolicy::StopOnError); + QTest::newRow("DoneStopOnError") << TestData{storage, root1, log, 1, OnDone::Success}; + + const Group root2 = constructDoneWorkflow(WorkflowPolicy::ContinueOnError); + QTest::newRow("DoneContinueOnError") << TestData{storage, root2, log, 1, OnDone::Success}; + + const Group root3 = constructDoneWorkflow(WorkflowPolicy::StopOnDone); + QTest::newRow("DoneStopOnDone") << TestData{storage, root3, log, 1, OnDone::Success}; + + const Group root4 = constructDoneWorkflow(WorkflowPolicy::ContinueOnDone); + QTest::newRow("DoneContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Success}; + + const Group root5 = constructDoneWorkflow(WorkflowPolicy::StopOnFinished); + QTest::newRow("DoneStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Success}; + + const Group root6 = constructDoneWorkflow(WorkflowPolicy::Optional); + QTest::newRow("DoneOptional") << TestData{storage, root6, log, 1, OnDone::Success}; + } + + { + const auto constructErrorWorkflow = [=](WorkflowPolicy policy) { + return Group { + Storage(storage), + workflowPolicy(policy), + Test(setupFailingTask(1), logDone, logError), + onGroupDone(groupDone(0)), + onGroupError(groupError(0)) + }; + }; + + const Log log = { + {1, Handler::Setup}, + {1, Handler::Error}, + {0, Handler::GroupError} + }; + + const Log optionalLog = { + {1, Handler::Setup}, + {1, Handler::Error}, + {0, Handler::GroupDone} + }; + + const Group root1 = constructErrorWorkflow(WorkflowPolicy::StopOnError); + QTest::newRow("ErrorStopOnError") << TestData{storage, root1, log, 1, OnDone::Failure}; + + const Group root2 = constructErrorWorkflow(WorkflowPolicy::ContinueOnError); + QTest::newRow("ErrorContinueOnError") << TestData{storage, root2, log, 1, OnDone::Failure}; + + const Group root3 = constructErrorWorkflow(WorkflowPolicy::StopOnDone); + QTest::newRow("ErrorStopOnDone") << TestData{storage, root3, log, 1, OnDone::Failure}; + + const Group root4 = constructErrorWorkflow(WorkflowPolicy::ContinueOnDone); + QTest::newRow("ErrorContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Failure}; + + const Group root5 = constructErrorWorkflow(WorkflowPolicy::StopOnFinished); + QTest::newRow("ErrorStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Failure}; + + const Group root6 = constructErrorWorkflow(WorkflowPolicy::Optional); + QTest::newRow("ErrorOptional") << TestData{storage, root6, optionalLog, 1, OnDone::Success}; + } + { const Group root = constructSimpleSequence(WorkflowPolicy::StopOnError); const Log log { From d8ed764611cc43bc00534ec5116e8389ab5b1387 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 18 May 2023 20:52:20 +0200 Subject: [PATCH 1157/1447] TaskTree: Bring the documentation back It vanished after recent move into Tasking lib. Amends f84199f8b70bb03b66a0dbac3ff4dcdb56094d20 Change-Id: I561784c82285de41c2e29c257940678eeeccb5eb Reviewed-by: Eike Ziller --- doc/qtcreatordev/config/qtcreator-developer.qdocconf | 2 ++ doc/qtcreatordev/src/qtcreator-module.qdoc | 5 +++++ src/libs/solutions/tasking/tasktree.cpp | 8 +++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/qtcreatordev/config/qtcreator-developer.qdocconf b/doc/qtcreatordev/config/qtcreator-developer.qdocconf index 417b1ffd426..99b00d54fa8 100644 --- a/doc/qtcreatordev/config/qtcreator-developer.qdocconf +++ b/doc/qtcreatordev/config/qtcreator-developer.qdocconf @@ -16,6 +16,7 @@ headerdirs = . \ ../src \ ../../../src/libs/aggregation \ ../../../src/libs/extensionsystem \ + ../../../src/libs/solutions/tasking \ ../../../src/libs/utils \ ../../../src/plugins/coreplugin @@ -23,6 +24,7 @@ sourcedirs = . \ ../src \ ../../../src/libs/aggregation \ ../../../src/libs/extensionsystem \ + ../../../src/libs/solutions/tasking \ ../../../src/libs/utils \ ../../../src/plugins/coreplugin diff --git a/doc/qtcreatordev/src/qtcreator-module.qdoc b/doc/qtcreatordev/src/qtcreator-module.qdoc index 6a6b1a62f10..18a56103353 100644 --- a/doc/qtcreatordev/src/qtcreator-module.qdoc +++ b/doc/qtcreatordev/src/qtcreator-module.qdoc @@ -34,6 +34,11 @@ for plugins and basic mechanisms for plugin interaction like an object pool. + \row + \li \l{Tasking} + \li A solution containing a TaskTree and other classes for writing + declarative trees of asynchronous task flows. + \row \li \l{Utils} \li Useful classes that are reused in a lot of places in Qt Creator code. diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 3ee5f89f9f7..5b5ca0890f1 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -724,7 +724,13 @@ void TaskNode::invokeEndHandler(bool success) } /*! - \class TaskTree + \namespace Tasking + The Tasking namespace contains a general purpose TaskTree solution. + It depends on Qt only, and doesn't depend on any \QC specific code. +*/ + +/*! + \class Tasking::TaskTree \inheaderfile solutions/tasking/tasktree.h \inmodule QtCreator \ingroup mainclasses From c5818cfe6d272b8f485acbfac7c93120003f1dee Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 22 May 2023 11:42:32 +0200 Subject: [PATCH 1158/1447] Utils: Fix pathchooser handling for aspects ..especially when entering a path manually. Fixes some soft asserts regarding the call guard and re-allows to type a backslash directly to separate path from sub-path instead of using wild workarounds like adding a dummy character and adding the backslash before this. Change-Id: I8cc8aaccf414d0fd9acc03d7c69e10ddd88dbfd9 Reviewed-by: hjk --- src/libs/utils/aspects.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 613a5561ea9..e2dda5e31cb 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1134,7 +1134,7 @@ void StringAspect::addToLayout(LayoutItem &parent) if (d->m_blockAutoApply) return; d->m_blockAutoApply = true; - setValue(d->m_pathChooserDisplay->filePath().toString()); + setValueQuietly(d->m_pathChooserDisplay->filePath().toString()); d->m_blockAutoApply = false; }; connect(d->m_pathChooserDisplay, &PathChooser::editingFinished, this, setPathChooserValue); @@ -1142,7 +1142,7 @@ void StringAspect::addToLayout(LayoutItem &parent) } else { connect(d->m_pathChooserDisplay, &PathChooser::textChanged, this, [this](const QString &path) { - setValue(path); + setValueQuietly(path); }); } } From cae4dd01a8a5445d1b2815a22ff318eb2976ca48 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Fri, 12 May 2023 01:22:07 +0300 Subject: [PATCH 1159/1447] Android: Skip "Build APK" for non-app builds For projects using Qt 5.15 and Qt 6, the deployment settings file is generated by CMake/qmake and not Qt Creator, so if such file doesn't exist or it's been generated by Qt Creator, we can assume the project is not an android app. This is mainly a workaround for now to avoid a more involved fix which would need to potentially remove the method AndroidManager::deploymentSettings() (and it's use cases) which is used to generate a minimal version of deployment settings file, which was added some time ago where the build system CMake and Qt wasn't handling that generation, but now with Qt 5.15 and Qt 6, that shouldn't be a concern of Qt Creator. Fixes: QTCREATORBUG-27167 Fixes: QTBUG-111334 Task-number: QTCREATORBUG-26888 Change-Id: I15657f3b67acc52c28c92e6af24668f778432a19 Reviewed-by: Alessandro Portale --- src/plugins/android/androidmanager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 0ccca7c8f7b..78b6202a65c 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -361,6 +361,14 @@ Abi AndroidManager::androidAbi2Abi(const QString &androidAbi) bool AndroidManager::skipInstallationAndPackageSteps(const Target *target) { + // For projects using Qt 5.15 and Qt 6, the deployment settings file + // is generated by CMake/qmake and not Qt Creator, so if such file doesn't exist + // or it's been generated by Qt Creator, we can assume the project is not + // an android app. + const FilePath inputFile = AndroidQtVersion::androidDeploymentSettings(target); + if (!inputFile.exists() || AndroidManager::isQtCreatorGenerated(inputFile)) + return true; + const Project *p = target->project(); const Core::Context cmakeCtx = Core::Context(CMakeProjectManager::Constants::CMAKE_PROJECT_ID); From cb053048583771ff9c60c548a6335c18e08f2050 Mon Sep 17 00:00:00 2001 From: Alexander Pershin Date: Fri, 19 May 2023 23:16:54 +0300 Subject: [PATCH 1160/1447] MiniProjectTargetSelector: Ensure selected item is visible on show event Is useful when project contains large amount of targets and you have to switch between them more or less often. Change also applies to other tree views in selector but they are less likely to contain large row counts. Change-Id: Ic2cd920335adeef618d85202b3347a4cd042871c Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/miniprojecttargetselector.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 3da81e61542..96f85e94bea 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -389,6 +389,12 @@ private: TreeView::mouseReleaseEvent(event); } + void showEvent(QShowEvent* event) override + { + scrollTo(currentIndex()); + TreeView::showEvent(event); + } + QObject *objectAt(const QModelIndex &index) const { return theModel()->itemForIndex(index)->object(); From 5e059db065b1680c4f08b901b64f102300eda6e6 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 12:01:30 +0200 Subject: [PATCH 1161/1447] CMakeProjectManager: Robustify buildAndRunOnSameDevice helper Change-Id: Ib3559f81f2ff71ad5fc04d982ad6286df0d4390e Reviewed-by: David Schulz Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/cmakebuildstep.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index d4e50a0c27e..885cdea9f8f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -174,6 +174,8 @@ static bool buildAndRunOnSameDevice(Kit *kit) { IDeviceConstPtr runDevice = DeviceKitAspect::device(kit); IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit); + QTC_ASSERT(runDevice, return false); + QTC_ASSERT(buildDevice, return false); return runDevice->id() == buildDevice->id(); } From 8c288bf05fa8b0df10778421f71f7406fc175bd3 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 22 May 2023 14:38:47 +0200 Subject: [PATCH 1162/1447] Doc: Add "\inmodule QtCreator" to \class and \namespace docs To get rid of QDoc warnings. Change-Id: Idd39b7ae4327798c376f424c94d6617bcaee2258 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 1 + src/libs/utils/ansiescapecodehandler.cpp | 1 + src/libs/utils/aspects.cpp | 1 + src/libs/utils/checkablemessagebox.cpp | 1 + src/libs/utils/classnamevalidatinglineedit.cpp | 1 + src/libs/utils/commandline.cpp | 2 ++ src/libs/utils/completingtextedit.cpp | 4 +++- src/libs/utils/detailswidget.cpp | 1 + src/libs/utils/elidinglabel.cpp | 1 + src/libs/utils/faketooltip.cpp | 1 + src/libs/utils/fancylineedit.cpp | 1 + src/libs/utils/fancymainwindow.cpp | 4 +++- src/libs/utils/fileinprojectfinder.cpp | 1 + src/libs/utils/filenamevalidatinglineedit.cpp | 1 + src/libs/utils/filepath.cpp | 4 +++- src/libs/utils/filesystemwatcher.cpp | 1 + src/libs/utils/fileutils.cpp | 4 +++- src/libs/utils/filewizardpage.cpp | 1 + src/libs/utils/futuresynchronizer.cpp | 4 +++- src/libs/utils/guard.cpp | 4 +++- src/libs/utils/headerviewstretcher.cpp | 1 + src/libs/utils/itemviews.cpp | 4 ++++ src/libs/utils/macroexpander.cpp | 1 + src/libs/utils/navigationtreeview.cpp | 1 + src/libs/utils/optionpushbutton.cpp | 1 + src/libs/utils/parameteraction.cpp | 1 + src/libs/utils/pathlisteditor.cpp | 1 + src/libs/utils/persistentsettings.cpp | 2 ++ src/libs/utils/port.cpp | 4 +++- src/libs/utils/process.cpp | 2 ++ src/libs/utils/processhandle.cpp | 1 + src/libs/utils/projectintropage.cpp | 1 + src/libs/utils/statuslabel.cpp | 1 + src/libs/utils/textfieldcheckbox.cpp | 1 + src/libs/utils/textfieldcombobox.cpp | 1 + src/libs/utils/textfileformat.cpp | 1 + src/libs/utils/treemodel.cpp | 1 + src/libs/utils/utils.qdoc | 1 + src/libs/utils/wizard.cpp | 4 +++- src/libs/utils/wizardpage.cpp | 4 +++- src/plugins/coreplugin/locator/ilocatorfilter.cpp | 1 + src/plugins/coreplugin/progressmanager/processprogress.cpp | 1 + src/plugins/coreplugin/progressmanager/taskprogress.cpp | 1 + 43 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 5b5ca0890f1..dd7f2fea98b 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -725,6 +725,7 @@ void TaskNode::invokeEndHandler(bool success) /*! \namespace Tasking + \inmodule QtCreator The Tasking namespace contains a general purpose TaskTree solution. It depends on Qt only, and doesn't depend on any \QC specific code. */ diff --git a/src/libs/utils/ansiescapecodehandler.cpp b/src/libs/utils/ansiescapecodehandler.cpp index 0909a3d2c6f..91f13d9a25e 100644 --- a/src/libs/utils/ansiescapecodehandler.cpp +++ b/src/libs/utils/ansiescapecodehandler.cpp @@ -9,6 +9,7 @@ namespace Utils { /*! \class Utils::AnsiEscapeCodeHandler + \inmodule QtCreator \brief The AnsiEscapeCodeHandler class parses text and extracts ANSI escape codes from it. diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 613a5561ea9..71a61051fc8 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2326,6 +2326,7 @@ void IntegersAspect::setDefaultValue(const QList &value) /*! \class Utils::TextDisplay + \inmodule QtCreator \brief A text display is a phony aspect with the sole purpose of providing some text display using an Utils::InfoLabel in places where otherwise diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index d09c2941752..3c57a736670 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -18,6 +18,7 @@ /*! \class Utils::CheckableMessageBox + \inmodule QtCreator \brief The CheckableMessageBox class implements a message box suitable for questions with a diff --git a/src/libs/utils/classnamevalidatinglineedit.cpp b/src/libs/utils/classnamevalidatinglineedit.cpp index 01235d57e32..3515abef023 100644 --- a/src/libs/utils/classnamevalidatinglineedit.cpp +++ b/src/libs/utils/classnamevalidatinglineedit.cpp @@ -10,6 +10,7 @@ /*! \class Utils::ClassNameValidatingLineEdit + \inmodule QtCreator \brief The ClassNameValidatingLineEdit class implements a line edit that validates a C++ class name and emits a signal diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 103049ae246..858e6e861f0 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -41,6 +41,7 @@ namespace Utils { /*! \class Utils::ProcessArgs + \inmodule QtCreator \brief The ProcessArgs class provides functionality for dealing with shell-quoted process arguments. @@ -1398,6 +1399,7 @@ QString ProcessArgs::toString() const /*! \class Utils::CommandLine + \inmodule QtCreator \brief The CommandLine class represents a command line of a QProcess or similar utility. diff --git a/src/libs/utils/completingtextedit.cpp b/src/libs/utils/completingtextedit.cpp index 66d1e7e49f5..0fbdd2068bc 100644 --- a/src/libs/utils/completingtextedit.cpp +++ b/src/libs/utils/completingtextedit.cpp @@ -13,7 +13,9 @@ static bool isEndOfWordChar(const QChar &c) return !c.isLetterOrNumber() && c.category() != QChar::Punctuation_Connector; } -/*! \class Utils::CompletingTextEdit +/*! + \class Utils::CompletingTextEdit + \inmodule QtCreator \brief The CompletingTextEdit class is a QTextEdit with auto-completion support. diff --git a/src/libs/utils/detailswidget.cpp b/src/libs/utils/detailswidget.cpp index 420ed11b40f..ec7a3d22ebb 100644 --- a/src/libs/utils/detailswidget.cpp +++ b/src/libs/utils/detailswidget.cpp @@ -20,6 +20,7 @@ /*! \class Utils::DetailsWidget + \inmodule QtCreator \brief The DetailsWidget class implements a button to expand a \e Details area. diff --git a/src/libs/utils/elidinglabel.cpp b/src/libs/utils/elidinglabel.cpp index cf74d5f3d92..0b328a82b16 100644 --- a/src/libs/utils/elidinglabel.cpp +++ b/src/libs/utils/elidinglabel.cpp @@ -9,6 +9,7 @@ /*! \class Utils::ElidingLabel + \inmodule QtCreator \brief The ElidingLabel class is a label suitable for displaying elided text. diff --git a/src/libs/utils/faketooltip.cpp b/src/libs/utils/faketooltip.cpp index 571d2027639..c94ce528e02 100644 --- a/src/libs/utils/faketooltip.cpp +++ b/src/libs/utils/faketooltip.cpp @@ -8,6 +8,7 @@ /*! \class Utils::FakeToolTip + \inmodule QtCreator \brief The FakeToolTip class is a widget that pretends to be a tooltip. diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp index 03e33c67b67..5a85928b1d6 100644 --- a/src/libs/utils/fancylineedit.cpp +++ b/src/libs/utils/fancylineedit.cpp @@ -26,6 +26,7 @@ /*! \class Utils::FancyLineEdit + \inmodule QtCreator \brief The FancyLineEdit class is an enhanced line edit with several opt-in features. diff --git a/src/libs/utils/fancymainwindow.cpp b/src/libs/utils/fancymainwindow.cpp index a19fc6c3c76..323e2508eba 100644 --- a/src/libs/utils/fancymainwindow.cpp +++ b/src/libs/utils/fancymainwindow.cpp @@ -311,7 +311,9 @@ void DockWidget::handleToplevelChanged(bool floating) -/*! \class Utils::FancyMainWindow +/*! + \class Utils::FancyMainWindow + \inmodule QtCreator \brief The FancyMainWindow class is a MainWindow with dock widgets and additional "lock" functionality diff --git a/src/libs/utils/fileinprojectfinder.cpp b/src/libs/utils/fileinprojectfinder.cpp index 6ee3c34becd..6ec36212eb0 100644 --- a/src/libs/utils/fileinprojectfinder.cpp +++ b/src/libs/utils/fileinprojectfinder.cpp @@ -40,6 +40,7 @@ static bool checkPath(const FilePath &candidate, int matchLength, /*! \class Utils::FileInProjectFinder + \inmodule QtCreator \brief The FileInProjectFinder class is a helper class to find the \e original file in the project directory for a given file URL. diff --git a/src/libs/utils/filenamevalidatinglineedit.cpp b/src/libs/utils/filenamevalidatinglineedit.cpp index 58112ceb6c0..5602e72d1a1 100644 --- a/src/libs/utils/filenamevalidatinglineedit.cpp +++ b/src/libs/utils/filenamevalidatinglineedit.cpp @@ -10,6 +10,7 @@ /*! \class Utils::FileNameValidatingLineEdit + \inmodule QtCreator \brief The FileNameValidatingLineEdit class is a control that lets the user choose a (base) file name, based on a QLineEdit. diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 5681837582a..049debe9ee0 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -37,7 +37,9 @@ static DeviceFileHooks s_deviceHooks; inline bool isWindowsDriveLetter(QChar ch); -/*! \class Utils::FilePath +/*! + \class Utils::FilePath + \inmodule QtCreator \brief The FilePath class is an abstraction for handles to objects in a (possibly remote) file system, similar to a URL or, in the local diff --git a/src/libs/utils/filesystemwatcher.cpp b/src/libs/utils/filesystemwatcher.cpp index d1c2e003116..9a4d7b56930 100644 --- a/src/libs/utils/filesystemwatcher.cpp +++ b/src/libs/utils/filesystemwatcher.cpp @@ -28,6 +28,7 @@ static inline quint64 getFileLimit() /*! \class Utils::FileSystemWatcher + \inmodule QtCreator \brief The FileSystemWatcher class is a file watcher that internally uses a centralized QFileSystemWatcher and enforces limits on Mac OS. diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 98d190e2966..a6cbebf3681 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -259,7 +259,9 @@ TempFileSaver::~TempFileSaver() QFile::remove(m_filePath.toString()); } -/*! \class Utils::FileUtils +/*! + \class Utils::FileUtils + \inmodule QtCreator \brief The FileUtils class contains file and directory related convenience functions. diff --git a/src/libs/utils/filewizardpage.cpp b/src/libs/utils/filewizardpage.cpp index cc1f83b6969..a883f960566 100644 --- a/src/libs/utils/filewizardpage.cpp +++ b/src/libs/utils/filewizardpage.cpp @@ -8,6 +8,7 @@ /*! \class Utils::FileWizardPage + \inmodule QtCreator \brief The FileWizardPage class is a standard wizard page for a single file letting the user choose name diff --git a/src/libs/utils/futuresynchronizer.cpp b/src/libs/utils/futuresynchronizer.cpp index baef71f4ef3..da3347f35e3 100644 --- a/src/libs/utils/futuresynchronizer.cpp +++ b/src/libs/utils/futuresynchronizer.cpp @@ -3,7 +3,9 @@ #include "futuresynchronizer.h" -/*! \class Utils::FutureSynchronizer +/*! + \class Utils::FutureSynchronizer + \inmodule QtCreator \brief The FutureSynchronizer is an enhanced version of QFutureSynchronizer. */ diff --git a/src/libs/utils/guard.cpp b/src/libs/utils/guard.cpp index a70faf2c405..0273e7c9b8d 100644 --- a/src/libs/utils/guard.cpp +++ b/src/libs/utils/guard.cpp @@ -4,7 +4,9 @@ #include "guard.h" #include "qtcassert.h" -/*! \class Utils::Guard +/*! + \class Utils::Guard + \inmodule QtCreator \brief The Guard class implements a recursive guard with locking mechanism. diff --git a/src/libs/utils/headerviewstretcher.cpp b/src/libs/utils/headerviewstretcher.cpp index 3bc5c1d515c..2c0dd00ca02 100644 --- a/src/libs/utils/headerviewstretcher.cpp +++ b/src/libs/utils/headerviewstretcher.cpp @@ -10,6 +10,7 @@ using namespace Utils; /*! \class Utils::HeaderViewStretcher + \inmodule QtCreator \brief The HeaderViewStretcher class fixes QHeaderView to resize all columns to contents, except one diff --git a/src/libs/utils/itemviews.cpp b/src/libs/utils/itemviews.cpp index 8af7eba5a18..27f7cbb4281 100644 --- a/src/libs/utils/itemviews.cpp +++ b/src/libs/utils/itemviews.cpp @@ -5,6 +5,7 @@ /*! \class Utils::TreeView + \inmodule QtCreator \brief The TreeView adds setActivationMode to QTreeView to allow for single click/double click behavior on @@ -15,6 +16,7 @@ /*! \class Utils::TreeWidget + \inmodule QtCreator \brief The TreeWidget adds setActivationMode to QTreeWidget to allow for single click/double click behavior on @@ -25,6 +27,7 @@ /*! \class Utils::ListView + \inmodule QtCreator \brief The ListView adds setActivationMode to QListView to allow for single click/double click behavior on @@ -35,6 +38,7 @@ /*! \class Utils::ListWidget + \inmodule QtCreator \brief The ListWidget adds setActivationMode to QListWidget to allow for single click/double click behavior on diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 644268d7cf4..43d23d2d190 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -104,6 +104,7 @@ using namespace Internal; /*! \class Utils::MacroExpander + \inmodule QtCreator \brief The MacroExpander class manages \QC wide variables, that a user can enter into many string settings. The variables are replaced by an actual value when the string is used, similar to how environment variables are expanded by a shell. diff --git a/src/libs/utils/navigationtreeview.cpp b/src/libs/utils/navigationtreeview.cpp index 8394388f17d..7a6bd4be234 100644 --- a/src/libs/utils/navigationtreeview.cpp +++ b/src/libs/utils/navigationtreeview.cpp @@ -9,6 +9,7 @@ /*! \class Utils::NavigationTreeView + \inmodule QtCreator \brief The NavigationTreeView class implements a general TreeView for any sidebar widget. diff --git a/src/libs/utils/optionpushbutton.cpp b/src/libs/utils/optionpushbutton.cpp index f98f9ee5a33..c3993fef4b0 100644 --- a/src/libs/utils/optionpushbutton.cpp +++ b/src/libs/utils/optionpushbutton.cpp @@ -11,6 +11,7 @@ namespace Utils { /*! \class Utils::OptionPushButton + \inmodule QtCreator \brief The OptionPushButton class implements a QPushButton for which the menu is only opened if the user presses the menu indicator. diff --git a/src/libs/utils/parameteraction.cpp b/src/libs/utils/parameteraction.cpp index 13efd9fa013..a77154b41f2 100644 --- a/src/libs/utils/parameteraction.cpp +++ b/src/libs/utils/parameteraction.cpp @@ -5,6 +5,7 @@ /*! \class Utils::ParameterAction + \inmodule QtCreator \brief The ParameterAction class is intended for actions that act on a 'current', string-type parameter (typically a file name), for example 'Save file %1'. diff --git a/src/libs/utils/pathlisteditor.cpp b/src/libs/utils/pathlisteditor.cpp index fc7beb75977..f2349b275fd 100644 --- a/src/libs/utils/pathlisteditor.cpp +++ b/src/libs/utils/pathlisteditor.cpp @@ -16,6 +16,7 @@ /*! \class Utils::PathListEditor + \inmodule QtCreator \brief The PathListEditor class is a control that lets the user edit a list of (directory) paths diff --git a/src/libs/utils/persistentsettings.cpp b/src/libs/utils/persistentsettings.cpp index 1db834bff7f..2daf2934c51 100644 --- a/src/libs/utils/persistentsettings.cpp +++ b/src/libs/utils/persistentsettings.cpp @@ -50,6 +50,7 @@ static QRect stringToRectangle(const QString &v) /*! \class Utils::PersistentSettingsReader + \inmodule QtCreator \brief The PersistentSettingsReader class reads a QVariantMap of arbitrary, nested data structures from an XML file. @@ -349,6 +350,7 @@ FilePath PersistentSettingsReader::filePath() /*! \class Utils::PersistentSettingsWriter + \inmodule QtCreator \brief The PersistentSettingsWriter class serializes a QVariantMap of arbitrary, nested data structures to an XML file. diff --git a/src/libs/utils/port.cpp b/src/libs/utils/port.cpp index c41a65335db..7ddd3ea0da4 100644 --- a/src/libs/utils/port.cpp +++ b/src/libs/utils/port.cpp @@ -10,7 +10,9 @@ #include -/*! \class Utils::Port +/*! + \class Utils::Port + \inmodule QtCreator \brief The Port class implements a wrapper around a 16 bit port number to be used in conjunction with IP addresses. diff --git a/src/libs/utils/process.cpp b/src/libs/utils/process.cpp index f25bc3d3fde..9a798ec11cf 100644 --- a/src/libs/utils/process.cpp +++ b/src/libs/utils/process.cpp @@ -1086,6 +1086,7 @@ ProcessResult ProcessPrivate::interpretExitCode(int exitCode) /*! \class Utils::Process + \inmodule QtCreator \brief The Process class provides functionality for with processes. @@ -1596,6 +1597,7 @@ QString Process::readAllStandardError() /*! \class Utils::SynchronousProcess + \inmodule QtCreator \brief The SynchronousProcess class runs a synchronous process in its own event loop that blocks only user input events. Thus, it allows for the GUI to diff --git a/src/libs/utils/processhandle.cpp b/src/libs/utils/processhandle.cpp index 686b1157adf..06850457d37 100644 --- a/src/libs/utils/processhandle.cpp +++ b/src/libs/utils/processhandle.cpp @@ -7,6 +7,7 @@ namespace Utils { /*! \class Utils::ProcessHandle + \inmodule QtCreator \brief The ProcessHandle class is a helper class to describe a process. Encapsulates parameters of a running process, local (PID) or remote (to be diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp index cb7018943d1..dba9a801e4b 100644 --- a/src/libs/utils/projectintropage.cpp +++ b/src/libs/utils/projectintropage.cpp @@ -22,6 +22,7 @@ /*! \class Utils::ProjectIntroPage + \inmodule QtCreator \brief The ProjectIntroPage class is the standard wizard page for a project, letting the user choose its name diff --git a/src/libs/utils/statuslabel.cpp b/src/libs/utils/statuslabel.cpp index 32db235b66c..26d5a5b3614 100644 --- a/src/libs/utils/statuslabel.cpp +++ b/src/libs/utils/statuslabel.cpp @@ -7,6 +7,7 @@ /*! \class Utils::StatusLabel + \inmodule QtCreator \brief The StatusLabel class displays messages for a while with a timeout. */ diff --git a/src/libs/utils/textfieldcheckbox.cpp b/src/libs/utils/textfieldcheckbox.cpp index 5dae8538ae6..a00f840422a 100644 --- a/src/libs/utils/textfieldcheckbox.cpp +++ b/src/libs/utils/textfieldcheckbox.cpp @@ -7,6 +7,7 @@ namespace Utils { /*! \class Utils::TextFieldCheckBox + \inmodule QtCreator \brief The TextFieldCheckBox class is a aheckbox that plays with \c QWizard::registerField. diff --git a/src/libs/utils/textfieldcombobox.cpp b/src/libs/utils/textfieldcombobox.cpp index 5d72f523a57..790358a1df9 100644 --- a/src/libs/utils/textfieldcombobox.cpp +++ b/src/libs/utils/textfieldcombobox.cpp @@ -9,6 +9,7 @@ namespace Utils { /*! \class Utils::TextFieldComboBox + \inmodule QtCreator \brief The TextFieldComboBox class is a non-editable combo box for text editing purposes that plays with \c QWizard::registerField (providing a settable 'text' property). diff --git a/src/libs/utils/textfileformat.cpp b/src/libs/utils/textfileformat.cpp index 28fb243abf7..094c6d0d72f 100644 --- a/src/libs/utils/textfileformat.cpp +++ b/src/libs/utils/textfileformat.cpp @@ -33,6 +33,7 @@ QDebug operator<<(QDebug d, const TextFileFormat &format) /*! \class Utils::TextFileFormat + \inmodule QtCreator \brief The TextFileFormat class describes the format of a text file and provides autodetection. diff --git a/src/libs/utils/treemodel.cpp b/src/libs/utils/treemodel.cpp index 344a77d837c..53477b53c97 100644 --- a/src/libs/utils/treemodel.cpp +++ b/src/libs/utils/treemodel.cpp @@ -895,6 +895,7 @@ void TreeItem::propagateModel(BaseTreeModel *m) /*! \class Utils::TreeModel + \inmodule QtCreator \brief The TreeModel class is a convienience base class for models to use in a QTreeView. diff --git a/src/libs/utils/utils.qdoc b/src/libs/utils/utils.qdoc index c0717043314..ae6d39b589d 100644 --- a/src/libs/utils/utils.qdoc +++ b/src/libs/utils/utils.qdoc @@ -3,6 +3,7 @@ /*! \namespace Utils + \inmodule QtCreator The Utils namespace contains a collection of utility classes and functions for use by all plugins. diff --git a/src/libs/utils/wizard.cpp b/src/libs/utils/wizard.cpp index 9fca25eaead..ce37d80705e 100644 --- a/src/libs/utils/wizard.cpp +++ b/src/libs/utils/wizard.cpp @@ -23,7 +23,9 @@ #include -/*! \class Utils::Wizard +/*! + \class Utils::Wizard + \inmodule QtCreator \brief The Wizard class implements a wizard with a progress bar on the left. diff --git a/src/libs/utils/wizardpage.cpp b/src/libs/utils/wizardpage.cpp index 740f46e8fc9..c4730b70115 100644 --- a/src/libs/utils/wizardpage.cpp +++ b/src/libs/utils/wizardpage.cpp @@ -5,7 +5,9 @@ #include "wizard.h" -/*! \class Utils::WizardPage +/*! + \class Utils::WizardPage + \inmodule QtCreator \brief QWizardPage with a couple of improvements. diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 930b2c918d9..f277884cce3 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -1268,6 +1268,7 @@ LocatorFilterEntries LocatorFileCachePrivate::generate(const QFuture &futu /*! \class Core::LocatorFileCache + \inmodule QtCreator \brief The LocatorFileCache class encapsulates all the responsibilities needed for implementing a cache for file filters. diff --git a/src/plugins/coreplugin/progressmanager/processprogress.cpp b/src/plugins/coreplugin/progressmanager/processprogress.cpp index 57b9dcbbfb2..9aeebf4ecf0 100644 --- a/src/plugins/coreplugin/progressmanager/processprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/processprogress.cpp @@ -70,6 +70,7 @@ void ProcessProgressPrivate::parseProgress(const QString &inputText) /*! \class Core::ProcessProgress + \inmodule QtCreator \brief The ProcessProgress class is responsible for showing progress of the running process. diff --git a/src/plugins/coreplugin/progressmanager/taskprogress.cpp b/src/plugins/coreplugin/progressmanager/taskprogress.cpp index c82ec339c51..5ee5feb24a8 100644 --- a/src/plugins/coreplugin/progressmanager/taskprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/taskprogress.cpp @@ -91,6 +91,7 @@ void TaskProgressPrivate::updateProgress() /*! \class Core::TaskProgress + \inmodule QtCreator \brief The TaskProgress class is responsible for showing progress of the running task tree. From 4de56e2683010c8b22848191405150b4d0e69c82 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 16 May 2023 15:00:32 +0200 Subject: [PATCH 1163/1447] Beautifier: Use Aspects for part of settings Change-Id: Icff60f5f1292ae6b2de2ce757d645d5fec47bcc6 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/beautifier/CMakeLists.txt | 3 - src/plugins/beautifier/abstractsettings.cpp | 118 ++++------ src/plugins/beautifier/abstractsettings.h | 17 +- .../artisticstyle/artisticstyle.cpp | 2 +- .../beautifier/artisticstyle/artisticstyle.h | 1 - .../artisticstyleoptionspage.cpp | 134 ----------- .../artisticstyle/artisticstyleoptionspage.h | 18 -- .../artisticstyle/artisticstylesettings.cpp | 189 ++++++++------- .../artisticstyle/artisticstylesettings.h | 32 +-- src/plugins/beautifier/beautifier.qbs | 6 - .../beautifier/clangformat/clangformat.cpp | 6 +- .../beautifier/clangformat/clangformat.h | 1 - .../clangformat/clangformatoptionspage.cpp | 144 ------------ .../clangformat/clangformatoptionspage.h | 18 -- .../clangformat/clangformatsettings.cpp | 219 ++++++++++++------ .../clangformat/clangformatsettings.h | 26 +-- .../beautifier/uncrustify/uncrustify.cpp | 2 +- .../beautifier/uncrustify/uncrustify.h | 1 - .../uncrustify/uncrustifyoptionspage.cpp | 137 ----------- .../uncrustify/uncrustifyoptionspage.h | 18 -- .../uncrustify/uncrustifysettings.cpp | 214 +++++++++-------- .../uncrustify/uncrustifysettings.h | 43 ++-- 22 files changed, 453 insertions(+), 896 deletions(-) delete mode 100644 src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp delete mode 100644 src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.h delete mode 100644 src/plugins/beautifier/clangformat/clangformatoptionspage.cpp delete mode 100644 src/plugins/beautifier/clangformat/clangformatoptionspage.h delete mode 100644 src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp delete mode 100644 src/plugins/beautifier/uncrustify/uncrustifyoptionspage.h diff --git a/src/plugins/beautifier/CMakeLists.txt b/src/plugins/beautifier/CMakeLists.txt index cdfacccce1a..4e921342b7a 100644 --- a/src/plugins/beautifier/CMakeLists.txt +++ b/src/plugins/beautifier/CMakeLists.txt @@ -5,7 +5,6 @@ add_qtc_plugin(Beautifier abstractsettings.cpp abstractsettings.h artisticstyle/artisticstyle.cpp artisticstyle/artisticstyle.h artisticstyle/artisticstyleconstants.h - artisticstyle/artisticstyleoptionspage.cpp artisticstyle/artisticstyleoptionspage.h artisticstyle/artisticstylesettings.cpp artisticstyle/artisticstylesettings.h beautifier.qrc beautifierabstracttool.h @@ -14,7 +13,6 @@ add_qtc_plugin(Beautifier beautifiertr.h clangformat/clangformat.cpp clangformat/clangformat.h clangformat/clangformatconstants.h - clangformat/clangformatoptionspage.cpp clangformat/clangformatoptionspage.h clangformat/clangformatsettings.cpp clangformat/clangformatsettings.h configurationdialog.cpp configurationdialog.h configurationeditor.cpp configurationeditor.h @@ -22,6 +20,5 @@ add_qtc_plugin(Beautifier generalsettings.cpp generalsettings.h uncrustify/uncrustify.cpp uncrustify/uncrustify.h uncrustify/uncrustifyconstants.h - uncrustify/uncrustifyoptionspage.cpp uncrustify/uncrustifyoptionspage.h uncrustify/uncrustifysettings.cpp uncrustify/uncrustifysettings.h ) diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp index fa621fdebcb..c80d4f6ac7b 100644 --- a/src/plugins/beautifier/abstractsettings.cpp +++ b/src/plugins/beautifier/abstractsettings.cpp @@ -26,9 +26,6 @@ using namespace Utils; namespace Beautifier::Internal { -const char COMMAND[] = "command"; -const char SUPPORTED_MIME[] = "supportedMime"; - class VersionUpdater { public: @@ -86,9 +83,40 @@ AbstractSettings::AbstractSettings(const QString &name, const QString &ending) , m_styleDir(Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME) .pathAppended(name) .toString()) - , m_name(name) , m_versionUpdater(new VersionUpdater) { + setSettingsGroups(Utils::Constants::BEAUTIFIER_SETTINGS_GROUP, name); + + registerAspect(&command); + command.setSettingsKey("command"); + command.setExpectedKind(Utils::PathChooser::ExistingCommand); + command.setCommandVersionArguments({"--version"}); + command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle("Clang Format")); + + registerAspect(&supportedMimeTypes); + supportedMimeTypes.setDisplayStyle(StringAspect::LineEditDisplay); + supportedMimeTypes.setSettingsKey("supportedMime"); + supportedMimeTypes.setLabelText(Tr::tr("Restrict to MIME types:")); + supportedMimeTypes.setDefaultValue("text/x-c++src; text/x-c++hdr; text/x-csrc;text/x-chdr; " + "text/x-objcsrc; text/x-objc++src"); + + supportedMimeTypes.setValueAcceptor([](const QString &, const QString &value) -> std::optional { + const QStringList stringTypes = value.split(';'); + QStringList types; + for (const QString &type : stringTypes) { + const MimeType mime = mimeTypeForName(type.trimmed()); + if (!mime.isValid()) + continue; + const QString canonicalName = mime.name(); + if (!types.contains(canonicalName)) + types << canonicalName; + } + return types.join("; "); + }); + + connect(&command, &BaseAspect::changed, this, [this] { + m_versionUpdater->update(command()); + }); } AbstractSettings::~AbstractSettings() = default; @@ -157,20 +185,6 @@ QString AbstractSettings::styleFileName(const QString &key) const return m_styleDir.absoluteFilePath(key + m_ending); } -FilePath AbstractSettings::command() const -{ - return m_command; -} - -void AbstractSettings::setCommand(const FilePath &cmd) -{ - if (cmd == m_command) - return; - - m_command = cmd; - m_versionUpdater->update(command()); -} - QVersionNumber AbstractSettings::version() const { return m_versionUpdater->version(); @@ -181,30 +195,6 @@ void AbstractSettings::setVersionRegExp(const QRegularExpression &versionRegExp) m_versionUpdater->setVersionRegExp(versionRegExp); } -QString AbstractSettings::supportedMimeTypesAsString() const -{ - return m_supportedMimeTypes.join("; "); -} - -void AbstractSettings::setSupportedMimeTypes(const QString &mimes) -{ - const QStringList stringTypes = mimes.split(';'); - QStringList types; - for (const QString &type : stringTypes) { - const MimeType mime = mimeTypeForName(type.trimmed()); - if (!mime.isValid()) - continue; - const QString canonicalName = mime.name(); - if (!types.contains(canonicalName)) - types << canonicalName; - } - - if (m_supportedMimeTypes != types) { - m_supportedMimeTypes = types; - emit supportedMimeTypesChanged(); - } -} - bool AbstractSettings::isApplicable(const Core::IDocument *document) const { if (!document) @@ -240,17 +230,8 @@ void AbstractSettings::save() { // Save settings, except styles QSettings *s = Core::ICore::settings(); - s->beginGroup(Utils::Constants::BEAUTIFIER_SETTINGS_GROUP); - s->beginGroup(m_name); - QMap::const_iterator iSettings = m_settings.constBegin(); - while (iSettings != m_settings.constEnd()) { - s->setValue(iSettings.key(), iSettings.value()); - ++iSettings; - } - s->setValue(COMMAND, m_command.toSettings()); - s->setValue(SUPPORTED_MIME, supportedMimeTypesAsString()); - s->endGroup(); - s->endGroup(); + + AspectContainer::writeSettings(s); // Save styles if (m_stylesToRemove.isEmpty() && m_styles.isEmpty()) @@ -306,27 +287,9 @@ void AbstractSettings::createDocumentationFile() const void AbstractSettings::read() { - // Set default values - setSupportedMimeTypes("text/x-c++src;text/x-c++hdr;text/x-csrc;text/x-chdr;text/x-objcsrc;" - "text/x-objc++src"); - // Read settings, except styles QSettings *s = Core::ICore::settings(); - s->beginGroup(Utils::Constants::BEAUTIFIER_SETTINGS_GROUP); - s->beginGroup(m_name); - const QStringList keys = s->allKeys(); - for (const QString &key : keys) { - if (key == COMMAND) - setCommand(FilePath::fromSettings(s->value(key))); - else if (key == SUPPORTED_MIME) - setSupportedMimeTypes(s->value(key).toString()); - else if (m_settings.contains(key)) - m_settings[key] = s->value(key); - else - s->remove(key); - } - s->endGroup(); - s->endGroup(); + AspectContainer::readSettings(s); m_styles.clear(); m_changedStyles.clear(); @@ -336,18 +299,19 @@ void AbstractSettings::read() void AbstractSettings::readDocumentation() { - const QString filename = documentationFilePath(); + const FilePath filename = documentationFilePath(); if (filename.isEmpty()) { BeautifierPlugin::showError(Tr::tr("No documentation file specified.")); return; } - QFile file(filename); + QFile file(filename.toFSPathString()); if (!file.exists()) createDocumentationFile(); if (!file.open(QIODevice::ReadOnly)) { - BeautifierPlugin::showError(Tr::tr("Cannot open documentation file \"%1\".").arg(filename)); + BeautifierPlugin::showError(Tr::tr("Cannot open documentation file \"%1\".") + .arg(filename.toUserOutput())); return; } @@ -356,7 +320,7 @@ void AbstractSettings::readDocumentation() return; if (xml.name() != QLatin1String(Constants::DOCUMENTATION_XMLROOT)) { BeautifierPlugin::showError(Tr::tr("The file \"%1\" is not a valid documentation file.") - .arg(filename)); + .arg(filename.toUserOutput())); return; } @@ -387,7 +351,7 @@ void AbstractSettings::readDocumentation() if (xml.hasError()) { BeautifierPlugin::showError(Tr::tr("Cannot read documentation file \"%1\": %2.") - .arg(filename).arg(xml.errorString())); + .arg(filename.toUserOutput()).arg(xml.errorString())); } } diff --git a/src/plugins/beautifier/abstractsettings.h b/src/plugins/beautifier/abstractsettings.h index 25baa838858..5eb930396ee 100644 --- a/src/plugins/beautifier/abstractsettings.h +++ b/src/plugins/beautifier/abstractsettings.h @@ -3,6 +3,8 @@ #pragma once +#include + #include #include @@ -40,7 +42,6 @@ public: void read(); void save(); - virtual QString documentationFilePath() const = 0; virtual void createDocumentationFile() const; virtual QStringList completerWords(); @@ -53,25 +54,21 @@ public: void replaceStyle(const QString &oldKey, const QString &newKey, const QString &value); virtual QString styleFileName(const QString &key) const; - Utils::FilePath command() const; - void setCommand(const Utils::FilePath &cmd); + Utils::FilePathAspect command; + Utils::StringAspect supportedMimeTypes; + Utils::FilePathAspect documentationFilePath; + QVersionNumber version() const; - QString supportedMimeTypesAsString() const; - void setSupportedMimeTypes(const QString &mimes); bool isApplicable(const Core::IDocument *document) const; QStringList options(); QString documentation(const QString &option) const; -signals: - void supportedMimeTypesChanged(); - protected: void setVersionRegExp(const QRegularExpression &versionRegExp); QMap m_styles; - QMap m_settings; QString m_ending; QDir m_styleDir; @@ -79,11 +76,9 @@ protected: virtual void readStyles(); private: - QString m_name; std::unique_ptr m_versionUpdater; QStringList m_stylesToRemove; QSet m_changedStyles; - Utils::FilePath m_command; QHash m_options; QStringList m_docu; QStringList m_supportedMimeTypes; diff --git a/src/plugins/beautifier/artisticstyle/artisticstyle.cpp b/src/plugins/beautifier/artisticstyle/artisticstyle.cpp index 610f636d743..1f063829944 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyle.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyle.cpp @@ -48,7 +48,7 @@ ArtisticStyle::ArtisticStyle() Core::ActionManager::actionContainer(Constants::MENU_ID)->addMenu(menu); - connect(&m_settings, &ArtisticStyleSettings::supportedMimeTypesChanged, + connect(&m_settings.supportedMimeTypes, &Utils::BaseAspect::changed, this, [this] { updateActions(Core::EditorManager::currentEditor()); }); } diff --git a/src/plugins/beautifier/artisticstyle/artisticstyle.h b/src/plugins/beautifier/artisticstyle/artisticstyle.h index ef394d068aa..3f3f15946af 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyle.h +++ b/src/plugins/beautifier/artisticstyle/artisticstyle.h @@ -5,7 +5,6 @@ #include "../beautifierabstracttool.h" -#include "artisticstyleoptionspage.h" #include "artisticstylesettings.h" namespace Beautifier::Internal { diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp deleted file mode 100644 index e34fe18349d..00000000000 --- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "artisticstyleoptionspage.h" - -#include "artisticstyleconstants.h" -#include "artisticstylesettings.h" - -#include "../beautifierconstants.h" -#include "../beautifierplugin.h" -#include "../beautifiertr.h" -#include "../configurationpanel.h" - -#include -#include - -#include -#include -#include -#include -#include - -namespace Beautifier::Internal { - -class ArtisticStyleOptionsPageWidget : public Core::IOptionsPageWidget -{ -public: - explicit ArtisticStyleOptionsPageWidget(ArtisticStyleSettings *settings); - - void apply() final; - -private: - ArtisticStyleSettings *m_settings; - - Utils::PathChooser *m_command; - QLineEdit *m_mime; - QCheckBox *m_useOtherFiles; - QCheckBox *m_useSpecificConfigFile; - Utils::PathChooser *m_specificConfigFile; - QCheckBox *m_useHomeFile; - QCheckBox *m_useCustomStyle; - Beautifier::Internal::ConfigurationPanel *m_configurations; -}; - -ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSettings *settings) - : m_settings(settings) -{ - m_command = new Utils::PathChooser; - - m_mime = new QLineEdit(m_settings->supportedMimeTypesAsString()); - - auto options = new QGroupBox(Tr::tr("Options")); - - m_useOtherFiles = new QCheckBox(Tr::tr("Use file *.astylerc defined in project files")); - m_useOtherFiles->setChecked(m_settings->useOtherFiles()); - - m_useSpecificConfigFile = new QCheckBox(Tr::tr("Use specific config file:")); - m_useSpecificConfigFile->setChecked(m_settings->useSpecificConfigFile()); - - m_specificConfigFile = new Utils::PathChooser; - m_specificConfigFile->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - m_specificConfigFile->setExpectedKind(Utils::PathChooser::File); - m_specificConfigFile->setPromptDialogFilter(Tr::tr("AStyle (*.astylerc)")); - m_specificConfigFile->setFilePath(m_settings->specificConfigFile()); - - m_useHomeFile = new QCheckBox( - Tr::tr("Use file .astylerc or astylerc in HOME"). - replace("HOME", QDir::toNativeSeparators(QDir::home().absolutePath()))); - m_useHomeFile->setChecked(m_settings->useHomeFile()); - - m_useCustomStyle = new QCheckBox(Tr::tr("Use customized style:")); - m_useCustomStyle->setChecked(m_settings->useCustomStyle()); - - m_configurations = new ConfigurationPanel(options); - m_configurations->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - m_configurations->setSettings(m_settings); - m_configurations->setCurrentConfiguration(m_settings->customStyle()); - - m_command->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_command->setCommandVersionArguments({"--version"}); - m_command->setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle( - Tr::tr(Constants::ARTISTICSTYLE_DISPLAY_NAME))); - m_command->setFilePath(m_settings->command()); - - using namespace Layouting; - - Column { - m_useOtherFiles, - Row { m_useSpecificConfigFile, m_specificConfigFile }, - m_useHomeFile, - Row { m_useCustomStyle, m_configurations }, - noMargin, - }.attachTo(options); - - Column { - Group { - title(Tr::tr("Configuration")), - Form { - Tr::tr("Artistic Style command:"), m_command, br, - Tr::tr("Restrict to MIME types:"), m_mime - } - }, - options, - st - }.attachTo(this); - - connect(m_command, &Utils::PathChooser::validChanged, options, &QWidget::setEnabled); -} - -void ArtisticStyleOptionsPageWidget::apply() -{ - m_settings->setCommand(m_command->filePath()); - m_settings->setSupportedMimeTypes(m_mime->text()); - m_settings->setUseOtherFiles(m_useOtherFiles->isChecked()); - m_settings->setUseSpecificConfigFile(m_useSpecificConfigFile->isChecked()); - m_settings->setSpecificConfigFile(m_specificConfigFile->filePath()); - m_settings->setUseHomeFile(m_useHomeFile->isChecked()); - m_settings->setUseCustomStyle(m_useCustomStyle->isChecked()); - m_settings->setCustomStyle(m_configurations->currentConfiguration()); - m_settings->save(); - - // update since not all MIME types are accepted (invalids or duplicates) - m_mime->setText(m_settings->supportedMimeTypesAsString()); -} - -ArtisticStyleOptionsPage::ArtisticStyleOptionsPage(ArtisticStyleSettings *settings) -{ - setId("ArtisticStyle"); - setDisplayName(Tr::tr("Artistic Style")); - setCategory(Constants::OPTION_CATEGORY); - setWidgetCreator([settings] { return new ArtisticStyleOptionsPageWidget(settings); }); -} - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.h b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.h deleted file mode 100644 index 161e20f7067..00000000000 --- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Beautifier::Internal { - -class ArtisticStyleSettings; - -class ArtisticStyleOptionsPage final : public Core::IOptionsPage -{ -public: - explicit ArtisticStyleOptionsPage(ArtisticStyleSettings *settings); -}; - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp index 42b91a785fe..78537df1970 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp @@ -3,16 +3,24 @@ #include "artisticstylesettings.h" +#include "artisticstyleconstants.h" #include "../beautifierconstants.h" +#include "../beautifierplugin.h" +#include "../beautifiertr.h" +#include "../configurationpanel.h" #include +#include +#include #include #include +#include #include #include #include +#include #include #include @@ -20,96 +28,52 @@ using namespace Utils; namespace Beautifier::Internal { -const char USE_OTHER_FILES[] = "useOtherFiles"; -const char USE_SPECIFIC_CONFIG_FILE[] = "useSpecificConfigFile"; -const char SPECIFIC_CONFIG_FILE[] = "specificConfigFile"; -const char USE_HOME_FILE[] = "useHomeFile"; -const char USE_CUSTOM_STYLE[] = "useCustomStyle"; -const char CUSTOM_STYLE[] = "customStyle"; const char SETTINGS_NAME[] = "artisticstyle"; -ArtisticStyleSettings::ArtisticStyleSettings() : - AbstractSettings(SETTINGS_NAME, ".astyle") +ArtisticStyleSettings::ArtisticStyleSettings() + : AbstractSettings(SETTINGS_NAME, ".astyle") { setVersionRegExp(QRegularExpression("([2-9]{1})\\.([0-9]{1,2})(\\.[1-9]{1})?$")); - setCommand("astyle"); - m_settings.insert(USE_OTHER_FILES, QVariant(true)); - m_settings.insert(USE_SPECIFIC_CONFIG_FILE, QVariant(false)); - m_settings.insert(SPECIFIC_CONFIG_FILE, QVariant()); - m_settings.insert(USE_HOME_FILE, QVariant(false)); - m_settings.insert(USE_CUSTOM_STYLE, QVariant(false)); - m_settings.insert(CUSTOM_STYLE, QVariant()); + command.setLabelText(Tr::tr("Artistic Style command:")); + command.setDefaultValue("astyle"); + command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle( + Tr::tr(Constants::ARTISTICSTYLE_DISPLAY_NAME))); + + registerAspect(&useOtherFiles); + useOtherFiles.setSettingsKey("useOtherFiles"); + useOtherFiles.setLabelText(Tr::tr("Use file *.astylerc defined in project files")); + useOtherFiles.setDefaultValue(true); + + registerAspect(&useSpecificConfigFile); + useSpecificConfigFile.setSettingsKey("useSpecificConfigFile"); + useSpecificConfigFile.setLabelText(Tr::tr("Use specific config file:")); + + registerAspect(&specificConfigFile); + specificConfigFile.setSettingsKey("specificConfigFile"); + specificConfigFile.setExpectedKind(PathChooser::File); + specificConfigFile.setPromptDialogFilter(Tr::tr("AStyle (*.astylerc)")); + + registerAspect(&useHomeFile); + useHomeFile.setSettingsKey("useHomeFile"); + useHomeFile.setLabelText(Tr::tr("Use file .astylerc or astylerc in HOME"). + replace("HOME", QDir::toNativeSeparators(QDir::home().absolutePath()))); + + registerAspect(&useCustomStyle); + useCustomStyle.setSettingsKey("useCustomStyle"); + useCustomStyle.setLabelText(Tr::tr("Use customized style:")); + + registerAspect(&customStyle); + customStyle.setSettingsKey("customStyle"); + + documentationFilePath.setFilePath( + Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME) + .pathAppended(Beautifier::Constants::DOCUMENTATION_DIRNAME) + .pathAppended(SETTINGS_NAME) + .stringAppended(".xml")); + read(); } -bool ArtisticStyleSettings::useOtherFiles() const -{ - return m_settings.value(USE_OTHER_FILES).toBool(); -} - -void ArtisticStyleSettings::setUseOtherFiles(bool useOtherFiles) -{ - m_settings.insert(USE_OTHER_FILES, QVariant(useOtherFiles)); -} - -bool ArtisticStyleSettings::useSpecificConfigFile() const -{ - return m_settings.value(USE_SPECIFIC_CONFIG_FILE).toBool(); -} - -void ArtisticStyleSettings::setUseSpecificConfigFile(bool useSpecificConfigFile) -{ - m_settings.insert(USE_SPECIFIC_CONFIG_FILE, QVariant(useSpecificConfigFile)); -} - -FilePath ArtisticStyleSettings::specificConfigFile() const -{ - return FilePath::fromString(m_settings.value(SPECIFIC_CONFIG_FILE).toString()); -} - -void ArtisticStyleSettings::setSpecificConfigFile(const FilePath &specificConfigFile) -{ - m_settings.insert(SPECIFIC_CONFIG_FILE, QVariant(specificConfigFile.toString())); -} - -bool ArtisticStyleSettings::useHomeFile() const -{ - return m_settings.value(USE_HOME_FILE).toBool(); -} - -void ArtisticStyleSettings::setUseHomeFile(bool useHomeFile) -{ - m_settings.insert(USE_HOME_FILE, QVariant(useHomeFile)); -} - -bool ArtisticStyleSettings::useCustomStyle() const -{ - return m_settings.value(USE_CUSTOM_STYLE).toBool(); -} - -void ArtisticStyleSettings::setUseCustomStyle(bool useCustomStyle) -{ - m_settings.insert(USE_CUSTOM_STYLE, QVariant(useCustomStyle)); -} - -QString ArtisticStyleSettings::customStyle() const -{ - return m_settings.value(CUSTOM_STYLE).toString(); -} - -void ArtisticStyleSettings::setCustomStyle(const QString &customStyle) -{ - m_settings.insert(CUSTOM_STYLE, QVariant(customStyle)); -} - -QString ArtisticStyleSettings::documentationFilePath() const -{ - return (Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME) - / Beautifier::Constants::DOCUMENTATION_DIRNAME / SETTINGS_NAME) - .stringAppended(".xml") - .toString(); -} - void ArtisticStyleSettings::createDocumentationFile() const { Process process; @@ -119,7 +83,7 @@ void ArtisticStyleSettings::createDocumentationFile() const if (process.result() != ProcessResult::FinishedWithSuccess) return; - QFile file(documentationFilePath()); + QFile file(documentationFilePath().toFSPathString()); const QFileInfo fi(file); if (!fi.exists()) fi.dir().mkpath(fi.absolutePath()); @@ -183,4 +147,61 @@ void ArtisticStyleSettings::createDocumentationFile() const } } +class ArtisticStyleOptionsPageWidget : public Core::IOptionsPageWidget +{ +public: + explicit ArtisticStyleOptionsPageWidget(ArtisticStyleSettings *settings) + { + QGroupBox *options = nullptr; + + auto configurations = new ConfigurationPanel(this); + configurations->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + configurations->setSettings(settings); + configurations->setCurrentConfiguration(settings->customStyle()); + + using namespace Layouting; + + ArtisticStyleSettings &s = *settings; + + Column { + Group { + title(Tr::tr("Configuration")), + Form { + s.command, br, + s.supportedMimeTypes + } + }, + Group { + title(Tr::tr("Options")), + bindTo(&options), + Column { + s.useOtherFiles, + Row { s.useSpecificConfigFile, s.specificConfigFile }, + s.useHomeFile, + Row { s.useCustomStyle, configurations }, + } + }, + st + }.attachTo(this); + + setOnApply([&s, configurations] { + s.customStyle.setValue(configurations->currentConfiguration()); + s.save(); + }); + + s.read(); + + connect(s.command.pathChooser(), &PathChooser::validChanged, options, &QWidget::setEnabled); + options->setEnabled(s.command.pathChooser()->isValid()); + } +}; + +ArtisticStyleOptionsPage::ArtisticStyleOptionsPage(ArtisticStyleSettings *settings) +{ + setId("ArtisticStyle"); + setDisplayName(Tr::tr("Artistic Style")); + setCategory(Constants::OPTION_CATEGORY); + setWidgetCreator([settings] { return new ArtisticStyleOptionsPageWidget(settings); }); +} + } // Beautifier::Internal diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.h b/src/plugins/beautifier/artisticstyle/artisticstylesettings.h index de5402a8ee5..5b74f8d1a03 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.h +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.h @@ -5,8 +5,6 @@ #include "../abstractsettings.h" -#include - namespace Beautifier::Internal { class ArtisticStyleSettings : public AbstractSettings @@ -14,26 +12,20 @@ class ArtisticStyleSettings : public AbstractSettings public: ArtisticStyleSettings(); - bool useOtherFiles() const; - void setUseOtherFiles(bool useOtherFiles); + Utils::BoolAspect useOtherFiles; + Utils::BoolAspect useSpecificConfigFile; + Utils::FilePathAspect specificConfigFile; + Utils::BoolAspect useHomeFile; + Utils::BoolAspect useCustomStyle; + Utils::StringAspect customStyle; - bool useSpecificConfigFile() const; - void setUseSpecificConfigFile(bool useSpecificConfigFile); - - Utils::FilePath specificConfigFile() const; - void setSpecificConfigFile(const Utils::FilePath &specificConfigFile); - - bool useHomeFile() const; - void setUseHomeFile(bool useHomeFile); - - bool useCustomStyle() const; - void setUseCustomStyle(bool useCustomStyle); - - QString customStyle() const; - void setCustomStyle(const QString &customStyle); - - QString documentationFilePath() const override; void createDocumentationFile() const override; }; +class ArtisticStyleOptionsPage final : public Core::IOptionsPage +{ +public: + explicit ArtisticStyleOptionsPage(ArtisticStyleSettings *settings); +}; + } // Beautifier::Internal diff --git a/src/plugins/beautifier/beautifier.qbs b/src/plugins/beautifier/beautifier.qbs index 0f85ca29b57..24fecd671f1 100644 --- a/src/plugins/beautifier/beautifier.qbs +++ b/src/plugins/beautifier/beautifier.qbs @@ -36,8 +36,6 @@ QtcPlugin { "artisticstyle.cpp", "artisticstyle.h", "artisticstyleconstants.h", - "artisticstyleoptionspage.cpp", - "artisticstyleoptionspage.h", "artisticstylesettings.cpp", "artisticstylesettings.h" ] @@ -50,8 +48,6 @@ QtcPlugin { "clangformat.cpp", "clangformat.h", "clangformatconstants.h", - "clangformatoptionspage.cpp", - "clangformatoptionspage.h", "clangformatsettings.cpp", "clangformatsettings.h" ] @@ -64,8 +60,6 @@ QtcPlugin { "uncrustify.cpp", "uncrustify.h", "uncrustifyconstants.h", - "uncrustifyoptionspage.cpp", - "uncrustifyoptionspage.h", "uncrustifysettings.cpp", "uncrustifysettings.h" ] diff --git a/src/plugins/beautifier/clangformat/clangformat.cpp b/src/plugins/beautifier/clangformat/clangformat.cpp index c1833a77f11..92c8c7f454d 100644 --- a/src/plugins/beautifier/clangformat/clangformat.cpp +++ b/src/plugins/beautifier/clangformat/clangformat.cpp @@ -64,7 +64,7 @@ ClangFormat::ClangFormat() Core::ActionManager::actionContainer(Constants::MENU_ID)->addMenu(menu); - connect(&m_settings, &ClangFormatSettings::supportedMimeTypesChanged, + connect(&m_settings.supportedMimeTypes, &Utils::BaseAspect::changed, this, [this] { updateActions(Core::EditorManager::currentEditor()); }); } @@ -191,10 +191,10 @@ Command ClangFormat::command() const command.setProcessing(Command::PipeProcessing); if (m_settings.usePredefinedStyle()) { - const QString predefinedStyle = m_settings.predefinedStyle(); + const QString predefinedStyle = m_settings.predefinedStyle.stringValue(); command.addOption("-style=" + predefinedStyle); if (predefinedStyle == "File") { - const QString fallbackStyle = m_settings.fallbackStyle(); + const QString fallbackStyle = m_settings.fallbackStyle.stringValue(); if (fallbackStyle != "Default") command.addOption("-fallback-style=" + fallbackStyle); } diff --git a/src/plugins/beautifier/clangformat/clangformat.h b/src/plugins/beautifier/clangformat/clangformat.h index 8563a782efc..65fd23a43f1 100644 --- a/src/plugins/beautifier/clangformat/clangformat.h +++ b/src/plugins/beautifier/clangformat/clangformat.h @@ -5,7 +5,6 @@ #include "../beautifierabstracttool.h" -#include "clangformatoptionspage.h" #include "clangformatsettings.h" namespace Beautifier::Internal { diff --git a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp b/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp deleted file mode 100644 index fd79826846a..00000000000 --- a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "clangformatoptionspage.h" - -#include "clangformatsettings.h" - -#include "../beautifierconstants.h" -#include "../beautifierplugin.h" -#include "../beautifiertr.h" -#include "../configurationpanel.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace Beautifier::Internal { - -class ClangFormatOptionsPageWidget : public Core::IOptionsPageWidget -{ -public: - explicit ClangFormatOptionsPageWidget(ClangFormatSettings *settings); - - void apply() final; - -private: - ClangFormatSettings *m_settings; - ConfigurationPanel *m_configurations; - QRadioButton *m_usePredefinedStyle; - QComboBox *m_predefinedStyle; - QComboBox *m_fallbackStyle; - Utils::PathChooser *m_command; - QLineEdit *m_mime; -}; - -ClangFormatOptionsPageWidget::ClangFormatOptionsPageWidget(ClangFormatSettings *settings) - : m_settings(settings) -{ - auto options = new QGroupBox(Tr::tr("Options")); - options->setEnabled(false); - - auto styleButtonGroup = new QButtonGroup(this); - - auto useCustomizedStyle = new QRadioButton(Tr::tr("Use customized style:")); - styleButtonGroup->addButton(useCustomizedStyle); - - m_configurations = new ConfigurationPanel; - m_configurations->setSettings(m_settings); - m_configurations->setCurrentConfiguration(m_settings->customStyle()); - - m_usePredefinedStyle = new QRadioButton(Tr::tr("Use predefined style:")); - - m_usePredefinedStyle->setChecked(true); - styleButtonGroup->addButton(m_usePredefinedStyle); - - m_predefinedStyle = new QComboBox; - m_predefinedStyle->addItems(m_settings->predefinedStyles()); - const int predefinedStyleIndex = m_predefinedStyle->findText(m_settings->predefinedStyle()); - if (predefinedStyleIndex != -1) - m_predefinedStyle->setCurrentIndex(predefinedStyleIndex); - - m_fallbackStyle = new QComboBox; - m_fallbackStyle->addItems(m_settings->fallbackStyles()); - m_fallbackStyle->setEnabled(false); - const int fallbackStyleIndex = m_fallbackStyle->findText(m_settings->fallbackStyle()); - if (fallbackStyleIndex != -1) - m_fallbackStyle->setCurrentIndex(fallbackStyleIndex); - - m_mime = new QLineEdit(m_settings->supportedMimeTypesAsString()); - - m_command = new Utils::PathChooser; - m_command->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_command->setCommandVersionArguments({"--version"}); - m_command->setPromptDialogTitle( - BeautifierPlugin::msgCommandPromptDialogTitle("Clang Format")); - - if (m_settings->usePredefinedStyle()) - m_usePredefinedStyle->setChecked(true); - else - useCustomizedStyle->setChecked(true); - - using namespace Layouting; - - Form { - m_usePredefinedStyle, m_predefinedStyle, br, - empty, Row { Tr::tr("Fallback style:"), m_fallbackStyle }, br, - useCustomizedStyle, m_configurations, br, - }.attachTo(options); - - Column { - Group { - title(Tr::tr("Configuration")), - Form { - Tr::tr("Clang Format command:"), m_command, br, - Tr::tr("Restrict to MIME types:"), m_mime - } - }, - options, - st - }.attachTo(this); - - connect(m_command, &Utils::PathChooser::validChanged, options, &QWidget::setEnabled); - connect(m_predefinedStyle, &QComboBox::currentTextChanged, this, [this](const QString &item) { - m_fallbackStyle->setEnabled(item == "File"); - }); - connect(m_usePredefinedStyle, &QRadioButton::toggled, this, [this](bool checked) { - m_fallbackStyle->setEnabled(checked && m_predefinedStyle->currentText() == "File"); - m_predefinedStyle->setEnabled(checked); - }); - - // might trigger PathChooser::validChanged, so so after the connect above - m_command->setFilePath(m_settings->command()); -} - -void ClangFormatOptionsPageWidget::apply() -{ - m_settings->setCommand(m_command->filePath()); - m_settings->setSupportedMimeTypes(m_mime->text()); - m_settings->setUsePredefinedStyle(m_usePredefinedStyle->isChecked()); - m_settings->setPredefinedStyle(m_predefinedStyle->currentText()); - m_settings->setFallbackStyle(m_fallbackStyle->currentText()); - m_settings->setCustomStyle(m_configurations->currentConfiguration()); - m_settings->save(); - - // update since not all MIME types are accepted (invalids or duplicates) - m_mime->setText(m_settings->supportedMimeTypesAsString()); -} - -ClangFormatOptionsPage::ClangFormatOptionsPage(ClangFormatSettings *settings) -{ - setId("ClangFormat"); - setDisplayName(Tr::tr("Clang Format")); - setCategory(Constants::OPTION_CATEGORY); - setWidgetCreator([settings] { return new ClangFormatOptionsPageWidget(settings); }); -} - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/clangformat/clangformatoptionspage.h b/src/plugins/beautifier/clangformat/clangformatoptionspage.h deleted file mode 100644 index e9a845af267..00000000000 --- a/src/plugins/beautifier/clangformat/clangformatoptionspage.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Beautifier::Internal { - -class ClangFormatSettings; - -class ClangFormatOptionsPage final : public Core::IOptionsPage -{ -public: - explicit ClangFormatOptionsPage(ClangFormatSettings *settings); -}; - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.cpp b/src/plugins/beautifier/clangformat/clangformatsettings.cpp index 16a2225cd97..dc061ed9658 100644 --- a/src/plugins/beautifier/clangformat/clangformatsettings.cpp +++ b/src/plugins/beautifier/clangformat/clangformatsettings.cpp @@ -4,43 +4,80 @@ #include "clangformatsettings.h" #include "../beautifierconstants.h" +#include "../beautifierplugin.h" #include "../beautifiertr.h" - -#include -#include +#include "../configurationpanel.h" #include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace Utils; + namespace Beautifier::Internal { -const char USE_PREDEFINED_STYLE[] = "usePredefinedStyle"; -const char PREDEFINED_STYLE[] = "predefinedStyle"; -const char FALLBACK_STYLE[] = "fallbackStyle"; -const char CUSTOM_STYLE[] = "customStyle"; const char SETTINGS_NAME[] = "clangformat"; -ClangFormatSettings::ClangFormatSettings() : - AbstractSettings(SETTINGS_NAME, ".clang-format") +ClangFormatSettings::ClangFormatSettings() + : AbstractSettings(SETTINGS_NAME, ".clang-format") { - setCommand("clang-format"); - m_settings.insert(USE_PREDEFINED_STYLE, QVariant(true)); - m_settings.insert(PREDEFINED_STYLE, "LLVM"); - m_settings.insert(FALLBACK_STYLE, "Default"); - m_settings.insert(CUSTOM_STYLE, QVariant()); - read(); -} + command.setDefaultValue("clang-format"); + command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle("Clang Format")); + command.setLabelText(Tr::tr("Clang Format command:")); -QString ClangFormatSettings::documentationFilePath() const -{ - return (Core::ICore::userResourcePath() / Beautifier::Constants::SETTINGS_DIRNAME - / Beautifier::Constants::DOCUMENTATION_DIRNAME / SETTINGS_NAME) - .stringAppended(".xml") - .toString(); + registerAspect(&usePredefinedStyle); + usePredefinedStyle.setSettingsKey("usePredefinedStyle"); + usePredefinedStyle.setLabelText(Tr::tr("Use predefined style:")); + usePredefinedStyle.setDefaultValue(true); + + registerAspect(&predefinedStyle); + predefinedStyle.setSettingsKey("predefinedStyle"); + predefinedStyle.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); + predefinedStyle.addOption("LLVM"); + predefinedStyle.addOption("Google"); + predefinedStyle.addOption("Chromium"); + predefinedStyle.addOption("Mozilla"); + predefinedStyle.addOption("WebKit"); + predefinedStyle.addOption("File"); + predefinedStyle.setDefaultValue("LLVM"); + + registerAspect(&fallbackStyle); + fallbackStyle.setSettingsKey("fallbackStyle"); + fallbackStyle.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); + fallbackStyle.addOption("Default"); + fallbackStyle.addOption("None"); + fallbackStyle.addOption("LLVM"); + fallbackStyle.addOption("Google"); + fallbackStyle.addOption("Chromium"); + fallbackStyle.addOption("Mozilla"); + fallbackStyle.addOption("WebKit"); + fallbackStyle.setDefaultValue("Default"); + + registerAspect(&predefinedStyle); + predefinedStyle.setSettingsKey("predefinedStyle"); + predefinedStyle.setDefaultValue("LLVM"); + + registerAspect(&customStyle); + customStyle.setSettingsKey("customStyle"); + + documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME) + .pathAppended(Constants::DOCUMENTATION_DIRNAME) + .pathAppended(SETTINGS_NAME).stringAppended(".xml")); + + read(); } void ClangFormatSettings::createDocumentationFile() const { - QFile file(documentationFilePath()); + QFile file(documentationFilePath().toFSPathString()); const QFileInfo fi(file); if (!fi.exists()) fi.dir().mkpath(fi.absolutePath()); @@ -144,60 +181,6 @@ QStringList ClangFormatSettings::completerWords() }; } -bool ClangFormatSettings::usePredefinedStyle() const -{ - return m_settings.value(USE_PREDEFINED_STYLE).toBool(); -} - -void ClangFormatSettings::setUsePredefinedStyle(bool usePredefinedStyle) -{ - m_settings.insert(USE_PREDEFINED_STYLE, QVariant(usePredefinedStyle)); -} - -QString ClangFormatSettings::predefinedStyle() const -{ - return m_settings.value(PREDEFINED_STYLE).toString(); -} - -void ClangFormatSettings::setPredefinedStyle(const QString &predefinedStyle) -{ - const QStringList test = predefinedStyles(); - if (test.contains(predefinedStyle)) - m_settings.insert(PREDEFINED_STYLE, QVariant(predefinedStyle)); -} - -QString ClangFormatSettings::fallbackStyle() const -{ - return m_settings.value(FALLBACK_STYLE).toString(); -} - -void ClangFormatSettings::setFallbackStyle(const QString &fallbackStyle) -{ - const QStringList test = fallbackStyles(); - if (test.contains(fallbackStyle)) - m_settings.insert(FALLBACK_STYLE, QVariant(fallbackStyle)); -} - -QString ClangFormatSettings::customStyle() const -{ - return m_settings.value(CUSTOM_STYLE).toString(); -} - -void ClangFormatSettings::setCustomStyle(const QString &customStyle) -{ - m_settings.insert(CUSTOM_STYLE, QVariant(customStyle)); -} - -QStringList ClangFormatSettings::predefinedStyles() const -{ - return {"LLVM", "Google", "Chromium", "Mozilla", "WebKit", "File"}; -} - -QStringList ClangFormatSettings::fallbackStyles() const -{ - return {"Default", "None", "LLVM", "Google", "Chromium", "Mozilla", "WebKit"}; -} - QString ClangFormatSettings::styleFileName(const QString &key) const { return m_styleDir.absolutePath() + '/' + key + '/' + m_ending; @@ -213,4 +196,86 @@ void ClangFormatSettings::readStyles() } } +class ClangFormatOptionsPageWidget : public Core::IOptionsPageWidget +{ +public: + explicit ClangFormatOptionsPageWidget(ClangFormatSettings *settings) + { + ClangFormatSettings &s = *settings; + QGroupBox *options = nullptr; + + auto predefinedStyleButton = new QRadioButton; + s.usePredefinedStyle.adoptButton(predefinedStyleButton); + + auto customizedStyleButton = new QRadioButton(Tr::tr("Use customized style:")); + + auto styleButtonGroup = new QButtonGroup; + styleButtonGroup->addButton(predefinedStyleButton); + styleButtonGroup->addButton(customizedStyleButton); + + auto configurations = new ConfigurationPanel(this); + configurations->setSettings(&s); + configurations->setCurrentConfiguration(s.customStyle()); + + using namespace Layouting; + + auto fallbackBlob = Row { noMargin, Tr::tr("Fallback style:"), s.fallbackStyle }.emerge(); + + auto predefinedBlob = Column { noMargin, s.predefinedStyle, fallbackBlob }.emerge(); + + Column { + Group { + title(Tr::tr("Configuration")), + Form { + s.command, br, + s.supportedMimeTypes + } + }, + Group { + title(Tr::tr("Options")), + bindTo(&options), + Form { + s.usePredefinedStyle, predefinedBlob, br, + customizedStyleButton, configurations, + }, + }, + st + }.attachTo(this); + + if (s.usePredefinedStyle.value()) + predefinedStyleButton->click(); + else + customizedStyleButton->click(); + + const auto updateEnabled = [&s, styleButtonGroup, predefinedBlob, fallbackBlob, + configurations, predefinedStyleButton] { + const bool predefSelected = styleButtonGroup->checkedButton() == predefinedStyleButton; + predefinedBlob->setEnabled(predefSelected); + fallbackBlob->setEnabled(predefSelected && s.predefinedStyle.volatileValue().toInt() == 5); // File + configurations->setEnabled(!predefSelected); + }; + updateEnabled(); + connect(styleButtonGroup, &QButtonGroup::buttonClicked, this, updateEnabled); + connect(&s.predefinedStyle, &SelectionAspect::volatileValueChanged, this, updateEnabled); + + setOnApply([settings, configurations] { + settings->customStyle.setValue(configurations->currentConfiguration()); + settings->save(); + }); + + s.read(); + + connect(s.command.pathChooser(), &PathChooser::validChanged, options, &QWidget::setEnabled); + options->setEnabled(s.command.pathChooser()->isValid()); + } +}; + +ClangFormatOptionsPage::ClangFormatOptionsPage(ClangFormatSettings *settings) +{ + setId("ClangFormat"); + setDisplayName(Tr::tr("Clang Format")); + setCategory(Constants::OPTION_CATEGORY); + setWidgetCreator([settings] { return new ClangFormatOptionsPageWidget(settings); }); +} + } // Beautifier::Internal diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.h b/src/plugins/beautifier/clangformat/clangformatsettings.h index 310eeaf8926..22c16eafc3d 100644 --- a/src/plugins/beautifier/clangformat/clangformatsettings.h +++ b/src/plugins/beautifier/clangformat/clangformatsettings.h @@ -12,24 +12,14 @@ class ClangFormatSettings : public AbstractSettings public: explicit ClangFormatSettings(); - QString documentationFilePath() const override; void createDocumentationFile() const override; + QStringList completerWords() override; - bool usePredefinedStyle() const; - void setUsePredefinedStyle(bool usePredefinedStyle); - - QString predefinedStyle() const; - void setPredefinedStyle(const QString &predefinedStyle); - - QString fallbackStyle() const; - void setFallbackStyle(const QString &fallbackStyle); - - QString customStyle() const; - void setCustomStyle(const QString &customStyle); - - QStringList predefinedStyles() const; - QStringList fallbackStyles() const; + Utils::BoolAspect usePredefinedStyle; + Utils::SelectionAspect predefinedStyle; + Utils::SelectionAspect fallbackStyle; + Utils::StringAspect customStyle; QString styleFileName(const QString &key) const override; @@ -37,4 +27,10 @@ private: void readStyles() override; }; +class ClangFormatOptionsPage final : public Core::IOptionsPage +{ +public: + explicit ClangFormatOptionsPage(ClangFormatSettings *settings); +}; + } // Beautifier::Internal diff --git a/src/plugins/beautifier/uncrustify/uncrustify.cpp b/src/plugins/beautifier/uncrustify/uncrustify.cpp index 2e6f6d67d59..1439dc315f2 100644 --- a/src/plugins/beautifier/uncrustify/uncrustify.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustify.cpp @@ -54,7 +54,7 @@ Uncrustify::Uncrustify() Core::ActionManager::actionContainer(Constants::MENU_ID)->addMenu(menu); - connect(&m_settings, &UncrustifySettings::supportedMimeTypesChanged, + connect(&m_settings.supportedMimeTypes, &Utils::BaseAspect::changed, this, [this] { updateActions(Core::EditorManager::currentEditor()); }); } diff --git a/src/plugins/beautifier/uncrustify/uncrustify.h b/src/plugins/beautifier/uncrustify/uncrustify.h index 1261576274c..685a29c25a1 100644 --- a/src/plugins/beautifier/uncrustify/uncrustify.h +++ b/src/plugins/beautifier/uncrustify/uncrustify.h @@ -5,7 +5,6 @@ #include "../beautifierabstracttool.h" -#include "uncrustifyoptionspage.h" #include "uncrustifysettings.h" namespace Beautifier::Internal { diff --git a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp deleted file mode 100644 index 8da74a71973..00000000000 --- a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "uncrustifyoptionspage.h" - -#include "uncrustifyconstants.h" -#include "uncrustifysettings.h" - -#include "../beautifierconstants.h" -#include "../beautifierplugin.h" -#include "../beautifiertr.h" -#include "../configurationpanel.h" - -#include -#include - -#include -#include -#include -#include - -namespace Beautifier::Internal { - -class UncrustifyOptionsPageWidget : public Core::IOptionsPageWidget -{ -public: - explicit UncrustifyOptionsPageWidget(UncrustifySettings *settings); - - void apply() final; - -private: - UncrustifySettings *m_settings; - - Utils::PathChooser *m_command; - QLineEdit *m_mime; - QCheckBox *m_useOtherFiles; - QCheckBox *m_useSpecificFile; - Utils::PathChooser *m_uncrusifyFilePath; - QCheckBox *m_useHomeFile; - QCheckBox *m_useCustomStyle; - ConfigurationPanel *m_configurations; - QCheckBox *m_formatEntireFileFallback; -}; - -UncrustifyOptionsPageWidget::UncrustifyOptionsPageWidget(UncrustifySettings *settings) - : m_settings(settings) -{ - m_command = new Utils::PathChooser; - - m_mime = new QLineEdit(m_settings->supportedMimeTypesAsString()); - - m_useOtherFiles = new QCheckBox(Tr::tr("Use file uncrustify.cfg defined in project files")); - m_useOtherFiles->setChecked(m_settings->useOtherFiles()); - - m_useSpecificFile = new QCheckBox(Tr::tr("Use file specific uncrustify.cfg")); - m_useSpecificFile->setChecked(m_settings->useSpecificConfigFile()); - - m_uncrusifyFilePath = new Utils::PathChooser; - m_uncrusifyFilePath->setExpectedKind(Utils::PathChooser::File); - m_uncrusifyFilePath->setPromptDialogFilter(Tr::tr("Uncrustify file (*.cfg)")); - m_uncrusifyFilePath->setFilePath(m_settings->specificConfigFile()); - - m_useHomeFile = new QCheckBox(Tr::tr("Use file uncrustify.cfg in HOME") - .replace( "HOME", QDir::toNativeSeparators(QDir::home().absolutePath()))); - m_useHomeFile->setChecked(m_settings->useHomeFile()); - - m_useCustomStyle = new QCheckBox(Tr::tr("Use customized style:")); - m_useCustomStyle->setChecked(m_settings->useCustomStyle()); - - m_configurations = new ConfigurationPanel; - m_configurations->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - m_configurations->setSettings(m_settings); - m_configurations->setCurrentConfiguration(m_settings->customStyle()); - - m_formatEntireFileFallback = new QCheckBox(Tr::tr("Format entire file if no text was selected")); - m_formatEntireFileFallback->setToolTip(Tr::tr("For action Format Selected Text")); - m_formatEntireFileFallback->setChecked(m_settings->formatEntireFileFallback()); - - m_command->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_command->setCommandVersionArguments({"--version"}); - m_command->setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle( - Tr::tr(Constants::UNCRUSTIFY_DISPLAY_NAME))); - m_command->setFilePath(m_settings->command()); - - auto options = new QGroupBox(Tr::tr("Options")); - - using namespace Layouting; - - Column { - m_useOtherFiles, - Row { m_useSpecificFile, m_uncrusifyFilePath }, - m_useHomeFile, - Row { m_useCustomStyle, m_configurations }, - m_formatEntireFileFallback - }.attachTo(options); - - Column { - Group { - title(Tr::tr("Configuration")), - Form { - Tr::tr("Uncrustify command:"), m_command, br, - Tr::tr("Restrict to MIME types:"), m_mime - } - }, - options, - st - }.attachTo(this); - - connect(m_command, &Utils::PathChooser::validChanged, options, &QWidget::setEnabled); -} - -void UncrustifyOptionsPageWidget::apply() -{ - m_settings->setCommand(m_command->filePath()); - m_settings->setSupportedMimeTypes(m_mime->text()); - m_settings->setUseOtherFiles(m_useOtherFiles->isChecked()); - m_settings->setUseHomeFile(m_useHomeFile->isChecked()); - m_settings->setUseSpecificConfigFile(m_useSpecificFile->isChecked()); - m_settings->setSpecificConfigFile(m_uncrusifyFilePath->filePath()); - m_settings->setUseCustomStyle(m_useCustomStyle->isChecked()); - m_settings->setCustomStyle(m_configurations->currentConfiguration()); - m_settings->setFormatEntireFileFallback(m_formatEntireFileFallback->isChecked()); - m_settings->save(); - - // update since not all MIME types are accepted (invalids or duplicates) - m_mime->setText(m_settings->supportedMimeTypesAsString()); -} - -UncrustifyOptionsPage::UncrustifyOptionsPage(UncrustifySettings *settings) -{ - setId("Uncrustify"); - setDisplayName(Tr::tr("Uncrustify")); - setCategory(Constants::OPTION_CATEGORY); - setWidgetCreator([settings] { return new UncrustifyOptionsPageWidget(settings); }); -} - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.h b/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.h deleted file mode 100644 index a8512d0da62..00000000000 --- a/src/plugins/beautifier/uncrustify/uncrustifyoptionspage.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2016 Lorenz Haas -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Beautifier::Internal { - -class UncrustifySettings; - -class UncrustifyOptionsPage final : public Core::IOptionsPage -{ -public: - explicit UncrustifyOptionsPage(UncrustifySettings *settings); -}; - -} // Beautifier::Internal diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp index a284d780b6c..8fefa851d0c 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp @@ -3,14 +3,25 @@ #include "uncrustifysettings.h" +#include "uncrustifyconstants.h" #include "../beautifierconstants.h" +#include "../beautifierplugin.h" +#include "../beautifiertr.h" +#include "../configurationpanel.h" #include + +#include +#include #include +#include #include #include #include +#include +#include +#include #include #include @@ -18,110 +29,57 @@ using namespace Utils; namespace Beautifier::Internal { -const char USE_OTHER_FILES[] = "useOtherFiles"; -const char USE_HOME_FILE[] = "useHomeFile"; -const char USE_SPECIFIC_CONFIG_FILE_PATH[] = "useSpecificConfigFile"; -const char SPECIFIC_CONFIG_FILE_PATH[] = "specificConfigFile"; -const char USE_CUSTOM_STYLE[] = "useCustomStyle"; -const char CUSTOM_STYLE[] = "customStyle"; -const char FORMAT_ENTIRE_FILE_FALLBACK[] = "formatEntireFileFallback"; -const char SETTINGS_NAME[] = "uncrustify"; +const char SETTINGS_NAME[] = "uncrustify"; -UncrustifySettings::UncrustifySettings() : - AbstractSettings(SETTINGS_NAME, ".cfg") +UncrustifySettings::UncrustifySettings() + : AbstractSettings(SETTINGS_NAME, ".cfg") { setVersionRegExp(QRegularExpression("([0-9]{1})\\.([0-9]{2})")); - setCommand("uncrustify"); - m_settings.insert(USE_OTHER_FILES, QVariant(true)); - m_settings.insert(USE_HOME_FILE, QVariant(false)); - m_settings.insert(USE_CUSTOM_STYLE, QVariant(false)); - m_settings.insert(USE_SPECIFIC_CONFIG_FILE_PATH, QVariant(false)); - m_settings.insert(CUSTOM_STYLE, QVariant()); - m_settings.insert(FORMAT_ENTIRE_FILE_FALLBACK, QVariant(true)); - m_settings.insert(SPECIFIC_CONFIG_FILE_PATH, QVariant()); + + command.setDefaultValue("uncrustify"); + command.setLabelText(Tr::tr("Uncrustify command:")); + command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle( + Tr::tr(Constants::UNCRUSTIFY_DISPLAY_NAME))); + + registerAspect(&useOtherFiles); + useOtherFiles.setSettingsKey("useOtherFiles"); + useOtherFiles.setDefaultValue(true); + useOtherFiles.setLabelText(Tr::tr("Use file uncrustify.cfg defined in project files")); + + registerAspect(&useHomeFile); + useHomeFile.setSettingsKey("useHomeFile"); + useHomeFile.setLabelText(Tr::tr("Use file uncrustify.cfg in HOME") + .replace( "HOME", QDir::toNativeSeparators(QDir::home().absolutePath()))); + + registerAspect(&useCustomStyle); + useCustomStyle.setSettingsKey("useCustomStyle"); + useCustomStyle.setLabelText(Tr::tr("Use customized style:")); + + registerAspect(&useSpecificConfigFile); + useSpecificConfigFile.setSettingsKey("useSpecificConfigFile"); + useSpecificConfigFile.setLabelText(Tr::tr("Use file specific uncrustify.cfg")); + + registerAspect(&customStyle); + customStyle.setSettingsKey("customStyle"); + + registerAspect(&formatEntireFileFallback); + formatEntireFileFallback.setSettingsKey("formatEntireFileFallback"); + formatEntireFileFallback.setDefaultValue(true); + formatEntireFileFallback.setLabelText(Tr::tr("Format entire file if no text was selected")); + formatEntireFileFallback.setToolTip(Tr::tr("For action Format Selected Text")); + + registerAspect(&specificConfigFile); + specificConfigFile.setSettingsKey("specificConfigFile"); + specificConfigFile.setExpectedKind(Utils::PathChooser::File); + specificConfigFile.setPromptDialogFilter(Tr::tr("Uncrustify file (*.cfg)")); + + documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME) + .pathAppended(Constants::DOCUMENTATION_DIRNAME) + .pathAppended(SETTINGS_NAME).stringAppended(".xml")); + read(); } -UncrustifySettings::~UncrustifySettings() = default; - -bool UncrustifySettings::useOtherFiles() const -{ - return m_settings.value(USE_OTHER_FILES).toBool(); -} - -void UncrustifySettings::setUseOtherFiles(bool useOtherFiles) -{ - m_settings.insert(USE_OTHER_FILES, QVariant(useOtherFiles)); -} - -bool UncrustifySettings::useHomeFile() const -{ - return m_settings.value(USE_HOME_FILE).toBool(); -} - -void UncrustifySettings::setUseHomeFile(bool useHomeFile) -{ - m_settings.insert(USE_HOME_FILE, QVariant(useHomeFile)); -} - -FilePath UncrustifySettings::specificConfigFile() const -{ - return FilePath::fromString(m_settings.value(SPECIFIC_CONFIG_FILE_PATH).toString()); -} - -void UncrustifySettings::setSpecificConfigFile(const FilePath &filePath) -{ - m_settings.insert(SPECIFIC_CONFIG_FILE_PATH, QVariant(filePath.toString())); -} - -bool UncrustifySettings::useSpecificConfigFile() const -{ - return m_settings.value(USE_SPECIFIC_CONFIG_FILE_PATH).toBool(); -} - -void UncrustifySettings::setUseSpecificConfigFile(bool useConfigFile) -{ - m_settings.insert(USE_SPECIFIC_CONFIG_FILE_PATH, QVariant(useConfigFile)); -} - -bool UncrustifySettings::useCustomStyle() const -{ - return m_settings.value(USE_CUSTOM_STYLE).toBool(); -} - -void UncrustifySettings::setUseCustomStyle(bool useCustomStyle) -{ - m_settings.insert(USE_CUSTOM_STYLE, QVariant(useCustomStyle)); -} - -QString UncrustifySettings::customStyle() const -{ - return m_settings.value(CUSTOM_STYLE).toString(); -} - -void UncrustifySettings::setCustomStyle(const QString &customStyle) -{ - m_settings.insert(CUSTOM_STYLE, QVariant(customStyle)); -} - -bool UncrustifySettings::formatEntireFileFallback() const -{ - return m_settings.value(FORMAT_ENTIRE_FILE_FALLBACK).toBool(); -} - -void UncrustifySettings::setFormatEntireFileFallback(bool formatEntireFileFallback) -{ - m_settings.insert(FORMAT_ENTIRE_FILE_FALLBACK, QVariant(formatEntireFileFallback)); -} - -QString UncrustifySettings::documentationFilePath() const -{ - return (Core::ICore::userResourcePath() / Beautifier::Constants::SETTINGS_DIRNAME - / Beautifier::Constants::DOCUMENTATION_DIRNAME / SETTINGS_NAME) - .stringAppended(".xml") - .toString(); -} - void UncrustifySettings::createDocumentationFile() const { Process process; @@ -131,7 +89,7 @@ void UncrustifySettings::createDocumentationFile() const if (process.result() != ProcessResult::FinishedWithSuccess) return; - QFile file(documentationFilePath()); + QFile file(documentationFilePath().toFSPathString()); const QFileInfo fi(file); if (!fi.exists()) fi.dir().mkpath(fi.absolutePath()); @@ -185,4 +143,62 @@ void UncrustifySettings::createDocumentationFile() const } } +class UncrustifyOptionsPageWidget : public Core::IOptionsPageWidget +{ +public: + explicit UncrustifyOptionsPageWidget(UncrustifySettings *settings) + { + UncrustifySettings &s = *settings; + + auto configurations = new ConfigurationPanel(this); + configurations->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + configurations->setSettings(settings); + configurations->setCurrentConfiguration(settings->customStyle()); + + QGroupBox *options = nullptr; + + using namespace Layouting; + + Column { + Group { + title(Tr::tr("Configuration")), + Form { + s.command, br, + s.supportedMimeTypes, + } + }, + Group { + title(Tr::tr("Options")), + bindTo(&options), + Column { + s.useOtherFiles, + Row { s.useSpecificConfigFile, s.specificConfigFile }, + s.useHomeFile, + Row { s.useCustomStyle, configurations }, + s.formatEntireFileFallback + }, + }, + st + }.attachTo(this); + + s.read(); + + connect(s.command.pathChooser(), &PathChooser::validChanged, options, &QWidget::setEnabled); + options->setEnabled(s.command.pathChooser()->isValid()); + + setOnApply([&s, configurations] { + s.customStyle.setValue(configurations->currentConfiguration()); + s.save(); + }); + } +}; + +UncrustifyOptionsPage::UncrustifyOptionsPage(UncrustifySettings *settings) +{ + setId("Uncrustify"); + setDisplayName(Tr::tr("Uncrustify")); + setCategory(Constants::OPTION_CATEGORY); + setWidgetCreator([settings] { return new UncrustifyOptionsPageWidget(settings); }); +} + } // Beautifier::Internal diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.h b/src/plugins/beautifier/uncrustify/uncrustifysettings.h index d57bfe6d39e..c0de1b891b2 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.h +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.h @@ -5,41 +5,30 @@ #include "../abstractsettings.h" -namespace Beautifier { -namespace Internal { +namespace Beautifier::Internal { class UncrustifySettings : public AbstractSettings { - Q_OBJECT - public: UncrustifySettings(); - ~UncrustifySettings() override; - bool useOtherFiles() const; - void setUseOtherFiles(bool useOtherFiles); - - bool useHomeFile() const; - void setUseHomeFile(bool useHomeFile); - - bool useCustomStyle() const; - void setUseCustomStyle(bool useCustomStyle); - - QString customStyle() const; - void setCustomStyle(const QString &customStyle); - - bool formatEntireFileFallback() const; - void setFormatEntireFileFallback(bool formatEntireFileFallback); - - QString documentationFilePath() const override; void createDocumentationFile() const override; - Utils::FilePath specificConfigFile() const; - void setSpecificConfigFile(const Utils::FilePath &filePath); + Utils::BoolAspect useOtherFiles; + Utils::BoolAspect useHomeFile; + Utils::BoolAspect useCustomStyle; - bool useSpecificConfigFile() const; - void setUseSpecificConfigFile(bool useConfigFile); + Utils::StringAspect customStyle; + Utils::BoolAspect formatEntireFileFallback; + + Utils::FilePathAspect specificConfigFile; + Utils::BoolAspect useSpecificConfigFile; }; -} // namespace Internal -} // namespace Beautifier +class UncrustifyOptionsPage final : public Core::IOptionsPage +{ +public: + explicit UncrustifyOptionsPage(UncrustifySettings *settings); +}; + +} // Beautifier::Internal From 1467aedb8dfcb1ee716352164d729f2a0ea28ad5 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 22 May 2023 15:03:08 +0200 Subject: [PATCH 1164/1447] Doc: Turn docs for DeviceShell::DeviceShell() into a comment The notation was causing QDoc errors, and according to the developer this is more like a comment to other developers than documentation. Change-Id: Ibbf3f64252f164c361315f8ecf16e3422703bb1c Reviewed-by: Marcus Tillmanns --- src/libs/utils/deviceshell.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp index f6474721ace..ae983b6f482 100644 --- a/src/libs/utils/deviceshell.cpp +++ b/src/libs/utils/deviceshell.cpp @@ -14,10 +14,10 @@ Q_LOGGING_CATEGORY(deviceShellLog, "qtc.utils.deviceshell", QtWarningMsg) namespace Utils { -/*! +/* * The multiplex script waits for input via stdin. * - * To start a command, a message is send with + * To start a command, a message is sent with * the format " "" \n" * To stop the script, simply send "exit\n" via stdin * From 0ddbf9f6b80a86301999ec97627d95858f959b5d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 22 May 2023 13:29:44 +0200 Subject: [PATCH 1165/1447] Update qbs submodule to HEAD of 2.0 branch Change-Id: I5e8f30c4eefbddd2660e5b68b8a13837c70cdfe4 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 03e717b06ed..dc4da2ef8aa 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 03e717b06ed5c0864618e763f08f91d9fc94b733 +Subproject commit dc4da2ef8aaf63ab837da0aa7689a5b18e34ace8 From 231397efe2e63741688b7dfc1e5a582ae4903df7 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 22 May 2023 15:30:48 +0200 Subject: [PATCH 1166/1447] Doc: Fix qdoc command to "\a env" To fix a qdoc warning. However, qdoc cannot find the function to bind these docs to in any header file. Change-Id: I86b88bbd9e6f0731f8f79587981c46b720b4a91f Reviewed-by: Eike Ziller --- src/libs/utils/commandline.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 858e6e861f0..b259aaf7e64 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -218,7 +218,7 @@ static QStringList doSplitArgsWin(const QString &args, ProcessArgs::SplitError * If \a err is not NULL, stores a status code at the pointer target. For more information, see \l SplitError. - If \env is not NULL, performs variable substitution with the + If \a env is not NULL, performs variable substitution with the given environment. Returns a list of unquoted words or an empty list if an error occurred. @@ -254,7 +254,6 @@ static QStringList doSplitArgsWin(const QString &args, ProcessArgs::SplitError * \c{foo " bar}. */ - static QStringList splitArgsWin(const QString &_args, bool abortOnMeta, ProcessArgs::SplitError *err, const Environment *env, const QString *pwd) From 3dcdbe9069c452e2f0eacb925aa7412e63dc4762 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 10:32:24 +0200 Subject: [PATCH 1167/1447] FancyLineEdit: Mark placeholder text that doesn't pass validation ... also for place holder text. While this omission was apparently intentional, the opposite behavior was used in the Beautifier settings, arguably being a better standard as this makes clear to the user that the pre-selected placeholder value won't be ok to use. Change-Id: Iaf15b1351de929dee57329efdf18d7e831b4f8bc Reviewed-by: Reviewed-by: Eike Ziller --- src/libs/utils/fancylineedit.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp index 03e33c67b67..443845e7801 100644 --- a/src/libs/utils/fancylineedit.cpp +++ b/src/libs/utils/fancylineedit.cpp @@ -115,6 +115,7 @@ public: const QColor m_okTextColor; const QColor m_errorTextColor; + const QColor m_placeholderTextColor; QString m_errorMessage; }; @@ -123,7 +124,9 @@ FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) : m_lineEdit(parent), m_completionShortcut(completionShortcut()->key(), parent), m_okTextColor(creatorTheme()->color(Theme::TextColorNormal)), - m_errorTextColor(creatorTheme()->color(Theme::TextColorError)) + m_errorTextColor(creatorTheme()->color(Theme::TextColorError)), + m_placeholderTextColor(creatorTheme()->color(Theme::PalettePlaceholderText)) + { m_completionShortcut.setContext(Qt::WidgetShortcut); connect(completionShortcut(), &CompletionShortcut::keyChanged, @@ -485,15 +488,18 @@ void FancyLineEdit::validate() setToolTip(d->m_errorMessage); d->m_toolTipSet = true; } - // Changed..figure out if valid changed. DisplayingPlaceholderText is not valid, - // but should not show error color. Also trigger on the first change. + // Changed..figure out if valid changed. Also trigger on the first change. + // Invalid DisplayingPlaceholderText shows also error color. if (newState != d->m_state || d->m_firstChange) { const bool validHasChanged = (d->m_state == Valid) != (newState == Valid); d->m_state = newState; d->m_firstChange = false; QPalette p = palette(); - p.setColor(QPalette::Active, QPalette::Text, newState == Invalid ? d->m_errorTextColor : d->m_okTextColor); + p.setColor(QPalette::Active, QPalette::Text, + newState == Invalid ? d->m_errorTextColor : d->m_okTextColor); + p.setColor(QPalette::Active, QPalette::PlaceholderText, + validates ? d->m_placeholderTextColor : d->m_errorTextColor); setPalette(p); if (validHasChanged) From db1d12f69abd77219a17ffe93e4ddc6ab4d65874 Mon Sep 17 00:00:00 2001 From: Alexander Pershin Date: Sat, 20 May 2023 01:25:41 +0300 Subject: [PATCH 1168/1447] MiniProjectTargetSelector: Natural sorting of entries Change-Id: Ibad929d1423d964204b4b236e1cc4df7e0614889 Reviewed-by: Christian Kandeler Reviewed-by: --- .../projectexplorer/miniprojecttargetselector.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 96f85e94bea..3a1b01b724b 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -141,8 +142,15 @@ private: static bool compareItems(const TreeItem *ti1, const TreeItem *ti2) { - const int result = caseFriendlyCompare(static_cast(ti1)->rawDisplayName(), - static_cast(ti2)->rawDisplayName()); + static const QCollator collator = [] { + QCollator collator; + collator.setNumericMode(true); + collator.setCaseSensitivity(Qt::CaseInsensitive); + return collator; + }(); + + const int result = collator.compare(static_cast(ti1)->rawDisplayName(), + static_cast(ti2)->rawDisplayName()); if (result != 0) return result < 0; return ti1 < ti2; From a4c962aa33ac74e0a357f30f9b2f90111f8d865a Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 11:35:52 +0200 Subject: [PATCH 1169/1447] Utils: Introduce aspect ctors referring to an "wrapping" AspectContainer This removes the need to manual 'registerAspect' calls in most cases. Whether the containers owns the registered aspects or just references them is still determined by AspectContainer::setOwnsSubAspects() Change-Id: Iadd17c919287f625bf5eb4964de4149d4da5a0f9 Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 36 +++++++++++++++++++----------------- src/libs/utils/aspects.h | 18 +++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index e2dda5e31cb..7baa9ba38ce 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -92,9 +92,11 @@ public: /*! Constructs a BaseAspect. */ -BaseAspect::BaseAspect() +BaseAspect::BaseAspect(AspectContainer *container) : d(new Internal::BaseAspectPrivate) { + if (container) + container->registerAspect(this); addDataExtractor(this, &BaseAspect::value, &Data::value); } @@ -766,8 +768,8 @@ public: Constructs a StringAspect. */ -StringAspect::StringAspect() - : d(new Internal::StringAspectPrivate) +StringAspect::StringAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::StringAspectPrivate) { setDefaultValue(QString()); setSpan(2, 1); // Default: Label + something @@ -1359,8 +1361,8 @@ FilePathAspect::FilePathAspect() The color aspect is displayed using a QtColorButton. */ -ColorAspect::ColorAspect() - : d(new Internal::ColorAspectPrivate) +ColorAspect::ColorAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::ColorAspectPrivate) { setDefaultValue(QColor::fromRgb(0, 0, 0)); setSpan(1, 1); @@ -1426,8 +1428,8 @@ void ColorAspect::setVolatileValue(const QVariant &val) */ -BoolAspect::BoolAspect() - : d(new Internal::BoolAspectPrivate) +BoolAspect::BoolAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::BoolAspectPrivate) { setDefaultValue(false); setSpan(2, 1); @@ -1605,8 +1607,8 @@ CheckableDecider BoolAspect::checkableDecider() QRadioButtons in a QButtonGroup. */ -SelectionAspect::SelectionAspect() - : d(new Internal::SelectionAspectPrivate) +SelectionAspect::SelectionAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::SelectionAspectPrivate) { setSpan(2, 1); } @@ -1808,8 +1810,8 @@ QVariant SelectionAspect::itemValueForIndex(int index) const checkable items. */ -MultiSelectionAspect::MultiSelectionAspect() - : d(new Internal::MultiSelectionAspectPrivate(this)) +MultiSelectionAspect::MultiSelectionAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::MultiSelectionAspectPrivate(this)) { setDefaultValue(QStringList()); setSpan(2, 1); @@ -1915,8 +1917,8 @@ void MultiSelectionAspect::setValue(const QStringList &value) // IntegerAspect -IntegerAspect::IntegerAspect() - : d(new Internal::IntegerAspectPrivate) +IntegerAspect::IntegerAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::IntegerAspectPrivate) { setDefaultValue(qint64(0)); setSpan(2, 1); @@ -2051,8 +2053,8 @@ void IntegerAspect::setSingleStep(qint64 step) the display of the spin box. */ -DoubleAspect::DoubleAspect() - : d(new Internal::DoubleAspectPrivate) +DoubleAspect::DoubleAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::DoubleAspectPrivate) { setDefaultValue(double(0)); setSpan(2, 1); @@ -2206,8 +2208,8 @@ TriState TriState::fromVariant(const QVariant &variant) that is a list of strings. */ -StringListAspect::StringListAspect() - : d(new Internal::StringListAspectPrivate) +StringListAspect::StringListAspect(AspectContainer *container) + : BaseAspect(container), d(new Internal::StringListAspectPrivate) { setDefaultValue(QStringList()); } diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index ecfc9ee86bf..5fb16356ce3 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -45,7 +45,7 @@ class QTCREATOR_UTILS_EXPORT BaseAspect : public QObject Q_OBJECT public: - BaseAspect(); + BaseAspect(AspectContainer *container = nullptr); ~BaseAspect() override; Id id() const; @@ -213,7 +213,7 @@ class QTCREATOR_UTILS_EXPORT BoolAspect : public BaseAspect Q_OBJECT public: - BoolAspect(); + BoolAspect(AspectContainer *container = nullptr); ~BoolAspect() override; struct Data : BaseAspect::Data @@ -257,7 +257,7 @@ class QTCREATOR_UTILS_EXPORT ColorAspect : public BaseAspect Q_OBJECT public: - ColorAspect(); + ColorAspect(AspectContainer *container = nullptr); ~ColorAspect() override; struct Data : BaseAspect::Data @@ -282,7 +282,7 @@ class QTCREATOR_UTILS_EXPORT SelectionAspect : public BaseAspect Q_OBJECT public: - SelectionAspect(); + SelectionAspect(AspectContainer *container = nullptr); ~SelectionAspect() override; void addToLayout(Layouting::LayoutItem &parent) override; @@ -336,7 +336,7 @@ class QTCREATOR_UTILS_EXPORT MultiSelectionAspect : public BaseAspect Q_OBJECT public: - MultiSelectionAspect(); + MultiSelectionAspect(AspectContainer *container = nullptr); ~MultiSelectionAspect() override; void addToLayout(Layouting::LayoutItem &parent) override; @@ -359,7 +359,7 @@ class QTCREATOR_UTILS_EXPORT StringAspect : public BaseAspect Q_OBJECT public: - StringAspect(); + StringAspect(AspectContainer *container = nullptr); ~StringAspect() override; struct Data : BaseAspect::Data @@ -456,7 +456,7 @@ class QTCREATOR_UTILS_EXPORT IntegerAspect : public BaseAspect Q_OBJECT public: - IntegerAspect(); + IntegerAspect(AspectContainer *container = nullptr); ~IntegerAspect() override; void addToLayout(Layouting::LayoutItem &parent) override; @@ -494,7 +494,7 @@ class QTCREATOR_UTILS_EXPORT DoubleAspect : public BaseAspect Q_OBJECT public: - DoubleAspect(); + DoubleAspect(AspectContainer *container = nullptr); ~DoubleAspect() override; void addToLayout(Layouting::LayoutItem &parent) override; @@ -563,7 +563,7 @@ class QTCREATOR_UTILS_EXPORT StringListAspect : public BaseAspect Q_OBJECT public: - StringListAspect(); + StringListAspect(AspectContainer *container = nullptr); ~StringListAspect() override; void addToLayout(Layouting::LayoutItem &parent) override; From eebe7f86f3d676b2f14291fa25fc65a472d70aa2 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 14:55:24 +0200 Subject: [PATCH 1170/1447] Fossil: Use a bit more FilePath{Aspect} Change-Id: Ie7c995585aafe03428dc5e93b2904b189f0319c0 Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/fossil/fossilclient.cpp | 5 ++--- src/plugins/fossil/fossilplugin.cpp | 15 +++++---------- src/plugins/fossil/fossilsettings.cpp | 2 -- src/plugins/fossil/fossilsettings.h | 4 ++-- src/plugins/fossil/pullorpushdialog.cpp | 10 ++++------ src/plugins/fossil/pullorpushdialog.h | 12 +++++------- 6 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index 49ded9c7740..915121710aa 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -592,7 +592,7 @@ bool FossilClient::synchronousCreateRepository(const FilePath &workingDirectory, // use the configured default user for admin const QString repoName = workingDirectory.fileName().simplified(); - const QString repoPath = settings().defaultRepoPath.value(); + const FilePath repoPath = settings().defaultRepoPath(); const QString adminUser = settings().userName.value(); if (repoName.isEmpty() || repoPath.isEmpty()) @@ -602,8 +602,7 @@ bool FossilClient::synchronousCreateRepository(const FilePath &workingDirectory, // @TODO: what about --template options? const FilePath fullRepoName = FilePath::fromStringWithExtension(repoName, Constants::FOSSIL_FILE_SUFFIX); - const FilePath repoFilePath = FilePath::fromString(repoPath) - .pathAppended(fullRepoName.toString()); + const FilePath repoFilePath = repoPath.pathAppended(fullRepoName.toString()); QStringList args(vcsCommandString(CreateRepositoryCommand)); if (!adminUser.isEmpty()) args << "--admin-user" << adminUser; diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 6792c6e42b8..a316daf3aec 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -592,7 +592,7 @@ bool FossilPluginPrivate::pullOrPush(FossilPluginPrivate::SyncMode mode) QTC_ASSERT(state.hasTopLevel(), return false); PullOrPushDialog dialog(pullOrPushMode, Core::ICore::dialogParent()); - dialog.setLocalBaseDirectory(m_client.settings().defaultRepoPath.value()); + dialog.setLocalBaseDirectory(m_client.settings().defaultRepoPath()); const QString defaultURL(m_client.synchronousGetRepositoryURL(state.topLevel())); dialog.setDefaultRemoteLocation(defaultURL); if (dialog.exec() != QDialog::Accepted) @@ -868,24 +868,19 @@ bool FossilPluginPrivate::managesFile(const FilePath &workingDirectory, const QS bool FossilPluginPrivate::isConfigured() const { - const Utils::FilePath binary = m_client.vcsBinary(); + const FilePath binary = m_client.vcsBinary(); if (binary.isEmpty()) return false; - const QFileInfo fi = binary.toFileInfo(); - if ( !(fi.exists() && fi.isFile() && fi.isExecutable()) ) + if (!binary.isExecutableFile()) return false; // Local repositories default path must be set and exist - const QString repoPath = m_client.settings().defaultRepoPath.value(); + const FilePath repoPath = m_client.settings().defaultRepoPath(); if (repoPath.isEmpty()) return false; - const QDir dir(repoPath); - if (!dir.exists()) - return false; - - return true; + return repoPath.isReadableDir(); } bool FossilPluginPrivate::supportsOperation(Operation operation) const diff --git a/src/plugins/fossil/fossilsettings.cpp b/src/plugins/fossil/fossilsettings.cpp index b72f6b76234..22adad3920d 100644 --- a/src/plugins/fossil/fossilsettings.cpp +++ b/src/plugins/fossil/fossilsettings.cpp @@ -42,7 +42,6 @@ FossilSettings::FossilSettings() registerAspect(&defaultRepoPath); defaultRepoPath.setSettingsKey("defaultRepoPath"); - defaultRepoPath.setDisplayStyle(StringAspect::PathChooserDisplay); defaultRepoPath.setExpectedKind(PathChooser::Directory); defaultRepoPath.setDisplayName(Tr::tr("Fossil Repositories")); defaultRepoPath.setLabelText(Tr::tr("Default path:")); @@ -55,7 +54,6 @@ FossilSettings::FossilSettings() registerAspect(&sslIdentityFile); sslIdentityFile.setSettingsKey("sslIdentityFile"); - sslIdentityFile.setDisplayStyle(StringAspect::PathChooserDisplay); sslIdentityFile.setExpectedKind(PathChooser::File); sslIdentityFile.setDisplayName(Tr::tr("SSL/TLS Identity Key")); sslIdentityFile.setLabelText(Tr::tr("SSL/TLS identity:")); diff --git a/src/plugins/fossil/fossilsettings.h b/src/plugins/fossil/fossilsettings.h index eeea6041bdc..6b925357f06 100644 --- a/src/plugins/fossil/fossilsettings.h +++ b/src/plugins/fossil/fossilsettings.h @@ -12,8 +12,8 @@ class FossilSettings : public VcsBase::VcsBaseSettings public: FossilSettings(); - Utils::StringAspect defaultRepoPath; - Utils::StringAspect sslIdentityFile; + Utils::FilePathAspect defaultRepoPath; + Utils::FilePathAspect sslIdentityFile; Utils::BoolAspect diffIgnoreAllWhiteSpace; Utils::BoolAspect diffStripTrailingCR; Utils::BoolAspect annotateShowCommitters; diff --git a/src/plugins/fossil/pullorpushdialog.cpp b/src/plugins/fossil/pullorpushdialog.cpp index cd72f2bd01b..5ebf9869d3f 100644 --- a/src/plugins/fossil/pullorpushdialog.cpp +++ b/src/plugins/fossil/pullorpushdialog.cpp @@ -15,8 +15,7 @@ #include #include -namespace Fossil { -namespace Internal { +namespace Fossil::Internal { PullOrPushDialog::PullOrPushDialog(Mode mode, QWidget *parent) : QDialog(parent) @@ -106,10 +105,9 @@ void PullOrPushDialog::setDefaultRemoteLocation(const QString &url) m_urlLineEdit->setText(url); } -void PullOrPushDialog::setLocalBaseDirectory(const QString &dir) +void PullOrPushDialog::setLocalBaseDirectory(const Utils::FilePath &dir) { - m_localPathChooser->setBaseDirectory(Utils::FilePath::fromString(dir)); + m_localPathChooser->setBaseDirectory(dir); } -} // namespace Internal -} // namespace Fossil +} // Fossil::Internal diff --git a/src/plugins/fossil/pullorpushdialog.h b/src/plugins/fossil/pullorpushdialog.h index 1d921733b69..5594947cb0d 100644 --- a/src/plugins/fossil/pullorpushdialog.h +++ b/src/plugins/fossil/pullorpushdialog.h @@ -3,6 +3,8 @@ #pragma once +#include + #include QT_BEGIN_NAMESPACE @@ -13,13 +15,10 @@ QT_END_NAMESPACE namespace Utils { class PathChooser; } -namespace Fossil { -namespace Internal { +namespace Fossil::Internal { class PullOrPushDialog : public QDialog { - Q_OBJECT - public: enum Mode { PullMode, @@ -33,7 +32,7 @@ public: bool isRememberOptionEnabled() const; bool isPrivateOptionEnabled() const; void setDefaultRemoteLocation(const QString &url); - void setLocalBaseDirectory(const QString &dir); + void setLocalBaseDirectory(const Utils::FilePath &dir); // Pull-specific options // Push-specific options @@ -47,5 +46,4 @@ private: QCheckBox *m_privateCheckBox; }; -} // namespace Internal -} // namespace Fossil +} // Fossil::Internal From c02750428c03439da7d722885639ef578e3fe746 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 17:31:46 +0200 Subject: [PATCH 1171/1447] Utils: Rework FilePath::searchInDirectory Avoid the detour through Environment::search* by copying and adapting some code. Long term the Environment::search* functions may go as FilePath is generally a better entry point into the remote world nowadays. Change-Id: I352d6fb68292d76f29a3454a786322bfe081d53d Reviewed-by: Marcus Tillmanns --- src/libs/utils/filepath.cpp | 111 +++++++++++++++++++++++++++--------- src/libs/utils/filepath.h | 16 ++++-- 2 files changed, 95 insertions(+), 32 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 049debe9ee0..9ec738fdf26 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -712,20 +712,39 @@ bool FilePath::isSameFile(const FilePath &other) const return false; } -static FilePaths appendExeExtensions(const Environment &env, const FilePath &executable) +static FilePaths appendExeExtensions(const FilePath &executable, + FilePath::MatchScope matchScope) { - FilePaths execs = {executable}; - if (executable.osType() == OsTypeWindows) { - // Check all the executable extensions on windows: - // PATHEXT is only used if the executable has no extension - if (executable.suffixView().isEmpty()) { - const QStringList extensions = env.expandedValueForKey("PATHEXT").split(';'); - - for (const QString &ext : extensions) - execs << executable.stringAppended(ext.toLower()); + FilePaths result = {executable}; + const QStringView suffix = executable.suffixView(); + if (executable.osType() == OsTypeWindows && suffix.isEmpty()) { + switch (matchScope) { + case FilePath::ExactMatchOnly: + break; + case FilePath::WithExeSuffix: + result.append(executable.stringAppended(".exe")); + break; + case FilePath::WithBatSuffix: + result.append(executable.stringAppended(".bat")); + break; + case FilePath::WithExeOrBatSuffix: + result.append(executable.stringAppended(".exe")); + result.append(executable.stringAppended(".bat")); + break; + case FilePath::WithAnySuffix: { + // Check all the executable extensions on windows: + // PATHEXT is only used if the executable has no extension + static const QStringList extensions = Environment::systemEnvironment() + .expandedValueForKey("PATHEXT").split(';'); + for (const QString &ext : extensions) + result.append(executable.stringAppended(ext.toLower())); + break; + } + default: + break; } } - return execs; + return result; } bool FilePath::isSameExecutable(const FilePath &other) const @@ -736,9 +755,8 @@ bool FilePath::isSameExecutable(const FilePath &other) const if (!isSameDevice(other)) return false; - const Environment env = other.deviceEnvironment(); - const FilePaths exe1List = appendExeExtensions(env, *this); - const FilePaths exe2List = appendExeExtensions(env, other); + const FilePaths exe1List = appendExeExtensions(*this, WithAnySuffix); + const FilePaths exe2List = appendExeExtensions(other, WithAnySuffix); for (const FilePath &f1 : exe1List) { for (const FilePath &f2 : exe2List) { if (f1.isSameFile(f2)) @@ -1480,32 +1498,63 @@ FilePath FilePath::withNewPath(const QString &newPath) const assert(fullPath == FilePath::fromUrl("docker://123/usr/bin/make")) \endcode */ -FilePath FilePath::searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter) const + +FilePath FilePath::searchInDirectories(const FilePaths &dirs, + const FilePathPredicate &filter, + const MatchScope &matchScope) const { - if (isAbsolutePath()) - return *this; - return deviceEnvironment().searchInDirectories(path(), dirs, filter); + if (isEmpty()) + return {}; + + const FilePaths execs = appendExeExtensions(*this, matchScope); + + if (isAbsolutePath()) { + for (const FilePath &filePath : execs) { + if (filePath.isExecutableFile() && (!filter || filter(filePath))) + return filePath; + } + return {}; + } + + QSet alreadyCheckedDirectories; + + for (const FilePath &dir : dirs) { + // Compare the initial size of the set with the size after insertion to check + // if the directory was already checked. + const int initialCount = alreadyCheckedDirectories.count(); + alreadyCheckedDirectories.insert(dir); + const bool wasAlreadyChecked = alreadyCheckedDirectories.count() == initialCount; + + if (dir.isEmpty() || wasAlreadyChecked) + continue; + + for (const FilePath &exe : execs) { + const FilePath filePath = dir / exe.path(); + if (filePath.isExecutableFile() && (!filter || filter(filePath))) + return filePath; + } + } + + return {}; } FilePath FilePath::searchInPath(const FilePaths &additionalDirs, PathAmending amending, - const FilePathPredicate &filter) const + const FilePathPredicate &filter, + const MatchScope &matchScope) const { if (isAbsolutePath()) return *this; - FilePaths directories = deviceEnvironment().path(); - if (needsDevice()) { - directories = Utils::transform(directories, [this](const FilePath &filePath) { - return withNewPath(filePath.path()); - }); - } + + FilePaths directories = devicePathEnvironmentVariable(); + if (!additionalDirs.isEmpty()) { if (amending == AppendToPath) directories.append(additionalDirs); else directories = additionalDirs + directories; } - return searchInDirectories(directories, filter); + return searchInDirectories(directories, filter, matchScope); } Environment FilePath::deviceEnvironment() const @@ -1517,6 +1566,16 @@ Environment FilePath::deviceEnvironment() const return Environment::systemEnvironment(); } +FilePaths FilePath::devicePathEnvironmentVariable() const +{ + FilePaths result = deviceEnvironment().path(); + if (needsDevice()) { + for (FilePath &dir : result) + dir.setParts(this->scheme(), this->host(), dir.path()); + } + return result; +} + QString FilePath::formatFilePaths(const FilePaths &files, const QString &separator) { const QStringList nativeFiles = transform(files, &FilePath::toUserOutput); diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 142542b7343..2a41c6c615b 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -161,9 +161,8 @@ public: [[nodiscard]] FilePath withExecutableSuffix() const; [[nodiscard]] FilePath relativeChildPath(const FilePath &parent) const; [[nodiscard]] FilePath relativePathFrom(const FilePath &anchor) const; - [[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs, - const FilePathPredicate &filter = {}) const; [[nodiscard]] Environment deviceEnvironment() const; + [[nodiscard]] FilePaths devicePathEnvironmentVariable() const; [[nodiscard]] FilePath withNewPath(const QString &newPath) const; [[nodiscard]] FilePath withNewMappedPath(const FilePath &newPath) const; @@ -183,12 +182,17 @@ public: const FileFilter &filter); enum PathAmending { AppendToPath, PrependToPath }; - [[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {}, - PathAmending = AppendToPath, - const FilePathPredicate &filter = {}) const; - enum MatchScope { ExactMatchOnly, WithExeSuffix, WithBatSuffix, WithExeOrBatSuffix, WithAnySuffix }; + + [[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs, + const FilePathPredicate &filter = {}, + const MatchScope &matchScope = {}) const; + [[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {}, + PathAmending = AppendToPath, + const FilePathPredicate &filter = {}, + const MatchScope &matchScope = {}) const; + std::optional refersToExecutableFile(MatchScope considerScript) const; [[nodiscard]] expected_str tmpDir() const; From 0dbff2ece5539a2272480e6c13aa678c194ec612 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 22 May 2023 12:07:18 +0200 Subject: [PATCH 1172/1447] Separate session saving from project manager Move the generic parts to session manager and let the project manager save its parts separately via SessionManager::setSessionValue. Change-Id: Iec2e81ea2488a15efc7333adb2b327761afdf274 Reviewed-by: hjk Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- .../projectexplorer/projectexplorer.cpp | 6 +- .../projectexplorer/projectmanager.cpp | 105 +++++------------- src/plugins/projectexplorer/projectmanager.h | 1 - src/plugins/projectexplorer/session.cpp | 66 ++++++++++- src/plugins/projectexplorer/session.h | 1 + 5 files changed, 98 insertions(+), 81 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 1244dbd1ba2..e75e23d18f9 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1633,7 +1633,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd, &ProjectExplorerPluginPrivate::savePersistentSettings); connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] { if (!dd->m_shuttingDown && !SessionManager::loadingSession()) - ProjectManager::save(); + SessionManager::saveSession(); }); connect(qApp, &QApplication::applicationStateChanged, this, [](Qt::ApplicationState state) { if (!dd->m_shuttingDown && state == Qt::ApplicationActive) @@ -2212,7 +2212,7 @@ void ProjectExplorerPlugin::openNewProjectDialog() void ProjectExplorerPluginPrivate::showSessionManager() { - ProjectManager::save(); + SessionManager::saveSession(); SessionDialog sessionDialog(ICore::dialogParent()); sessionDialog.setAutoLoadSession(sb_d->isAutoRestoreLastSession()); sessionDialog.exec(); @@ -2258,7 +2258,7 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() for (Project *pro : ProjectManager::projects()) pro->saveSettings(); - ProjectManager::save(); + SessionManager::saveSession(); } QtcSettings *s = ICore::settings(); diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index ccfa95a289a..ff5b214b10a 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -53,6 +53,7 @@ class ProjectManagerPrivate { public: void loadSession(); + void saveSession(); void restoreDependencies(); void restoreStartupProject(); void restoreProjects(const FilePaths &fileList); @@ -109,6 +110,9 @@ ProjectManager::ProjectManager() connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, this, [] { d->loadSession(); }); + connect(SessionManager::instance(), &SessionManager::aboutToSaveSession, this, [] { + d->saveSession(); + }); } ProjectManager::~ProjectManager() @@ -315,87 +319,38 @@ void ProjectManager::removeProject(Project *project) removeProjects({project}); } -bool ProjectManager::save() +void ProjectManagerPrivate::saveSession() { - emit SessionManager::instance()->aboutToSaveSession(); + // save the startup project + if (d->m_startupProject) + SessionManager::setSessionValue("StartupProject", + m_startupProject->projectFilePath().toSettings()); - const FilePath filePath = SessionManager::sessionNameToFileName(sb_d->m_sessionName); - QVariantMap data; - - // See the explanation at loadSession() for how we handle the implicit default session. - if (SessionManager::isDefaultVirgin()) { - if (filePath.exists()) { - PersistentSettingsReader reader; - if (!reader.load(filePath)) { - QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"), - Tr::tr("Could not save session %1").arg(filePath.toUserOutput())); - return false; - } - data = reader.restoreValues(); - } - } else { - // save the startup project - if (d->m_startupProject) - data.insert("StartupProject", d->m_startupProject->projectFilePath().toSettings()); - - const QColor c = StyleHelper::requestedBaseColor(); - if (c.isValid()) { - QString tmp = QString::fromLatin1("#%1%2%3") - .arg(c.red(), 2, 16, QLatin1Char('0')) - .arg(c.green(), 2, 16, QLatin1Char('0')) - .arg(c.blue(), 2, 16, QLatin1Char('0')); - data.insert(QLatin1String("Color"), tmp); - } - - FilePaths projectFiles = Utils::transform(projects(), &Project::projectFilePath); - // Restore information on projects that failed to load: - // don't read projects to the list, which the user loaded - for (const FilePath &failed : std::as_const(d->m_failedProjects)) { - if (!projectFiles.contains(failed)) - projectFiles << failed; - } - - data.insert("ProjectList", Utils::transform(projectFiles, - &FilePath::toString)); - data.insert("CascadeSetActive", d->m_casadeSetActive); - - QVariantMap depMap; - auto i = d->m_depMap.constBegin(); - while (i != d->m_depMap.constEnd()) { - QString key = i.key().toString(); - QStringList values; - const FilePaths valueList = i.value(); - for (const FilePath &value : valueList) - values << value.toString(); - depMap.insert(key, values); - ++i; - } - data.insert(QLatin1String("ProjectDependencies"), QVariant(depMap)); - data.insert(QLatin1String("EditorSettings"), EditorManager::saveState().toBase64()); + FilePaths projectFiles = Utils::transform(m_projects, &Project::projectFilePath); + // Restore information on projects that failed to load: + // don't read projects to the list, which the user loaded + for (const FilePath &failed : std::as_const(m_failedProjects)) { + if (!projectFiles.contains(failed)) + projectFiles << failed; } - const auto end = sb_d->m_values.constEnd(); - QStringList keys; - for (auto it = sb_d->m_values.constBegin(); it != end; ++it) { - data.insert(QLatin1String("value-") + it.key(), it.value()); - keys << it.key(); - } - data.insert(QLatin1String("valueKeys"), keys); + SessionManager::setSessionValue("ProjectList", + Utils::transform(projectFiles, + &FilePath::toString)); + SessionManager::setSessionValue("CascadeSetActive", m_casadeSetActive); - if (!sb_d->m_writer || sb_d->m_writer->fileName() != filePath) { - delete sb_d->m_writer; - sb_d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession"); + QVariantMap depMap; + auto i = m_depMap.constBegin(); + while (i != m_depMap.constEnd()) { + QString key = i.key().toString(); + QStringList values; + const FilePaths valueList = i.value(); + for (const FilePath &value : valueList) + values << value.toString(); + depMap.insert(key, values); + ++i; } - const bool result = sb_d->m_writer->save(data, ICore::dialogParent()); - if (result) { - if (!SessionManager::isDefaultVirgin()) - sb_d->m_sessionDateTimes.insert(SessionManager::activeSession(), QDateTime::currentDateTime()); - } else { - QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"), - Tr::tr("Could not save session to file %1").arg(sb_d->m_writer->fileName().toUserOutput())); - } - - return result; + SessionManager::setSessionValue(QLatin1String("ProjectDependencies"), QVariant(depMap)); } /*! diff --git a/src/plugins/projectexplorer/projectmanager.h b/src/plugins/projectexplorer/projectmanager.h index 7f515869013..f49cc96e54c 100644 --- a/src/plugins/projectexplorer/projectmanager.h +++ b/src/plugins/projectexplorer/projectmanager.h @@ -47,7 +47,6 @@ public: }); } - static bool save(); static void closeAllProjects(); static void addProject(Project *project); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 5edd7b4f9d6..ccedbb885fe 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -7,7 +7,6 @@ #include "projectexplorer.h" #include "projectexplorertr.h" -#include "projectmanager.h" #include #include @@ -514,7 +513,7 @@ bool SessionManager::loadSession(const QString &session, bool initial) // Allow everyone to set something in the session and before saving emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName); - if (!ProjectManager::save()) { + if (!saveSession()) { sb_d->m_loadingSession = false; return false; } @@ -571,4 +570,67 @@ bool SessionManager::loadSession(const QString &session, bool initial) return true; } +bool SessionManager::saveSession() +{ + emit SessionManager::instance()->aboutToSaveSession(); + + const FilePath filePath = SessionManager::sessionNameToFileName(sb_d->m_sessionName); + QVariantMap data; + + // See the explanation at loadSession() for how we handle the implicit default session. + if (SessionManager::isDefaultVirgin()) { + if (filePath.exists()) { + PersistentSettingsReader reader; + if (!reader.load(filePath)) { + QMessageBox::warning(ICore::dialogParent(), + Tr::tr("Error while saving session"), + Tr::tr("Could not save session %1") + .arg(filePath.toUserOutput())); + return false; + } + data = reader.restoreValues(); + } + } else { + const QColor c = StyleHelper::requestedBaseColor(); + if (c.isValid()) { + QString tmp = QString::fromLatin1("#%1%2%3") + .arg(c.red(), 2, 16, QLatin1Char('0')) + .arg(c.green(), 2, 16, QLatin1Char('0')) + .arg(c.blue(), 2, 16, QLatin1Char('0')); + setSessionValue("Color", tmp); + } + setSessionValue("EditorSettings", EditorManager::saveState().toBase64()); + + const auto end = sb_d->m_sessionValues.constEnd(); + for (auto it = sb_d->m_sessionValues.constBegin(); it != end; ++it) + data.insert(it.key(), it.value()); + } + + const auto end = sb_d->m_values.constEnd(); + QStringList keys; + for (auto it = sb_d->m_values.constBegin(); it != end; ++it) { + data.insert("value-" + it.key(), it.value()); + keys << it.key(); + } + data.insert("valueKeys", keys); + + if (!sb_d->m_writer || sb_d->m_writer->fileName() != filePath) { + delete sb_d->m_writer; + sb_d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession"); + } + const bool result = sb_d->m_writer->save(data, ICore::dialogParent()); + if (result) { + if (!SessionManager::isDefaultVirgin()) + sb_d->m_sessionDateTimes.insert(SessionManager::activeSession(), + QDateTime::currentDateTime()); + } else { + QMessageBox::warning(ICore::dialogParent(), + Tr::tr("Error while saving session"), + Tr::tr("Could not save session to file %1") + .arg(sb_d->m_writer->fileName().toUserOutput())); + } + + return result; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index b40e687d648..8f2da70bd24 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -64,6 +64,7 @@ public: static void addSessionLoadingSteps(int steps); static bool loadSession(const QString &session, bool initial = false); + static bool saveSession(); signals: void startupSessionRestored(); From 323c58fd2029fda508eb13deac2ee8c3007b104a Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 14:18:44 +0200 Subject: [PATCH 1173/1447] ProjectExplorer: MakeStep code cosmetics Remove unneeded #include and an unused variable that was scheduled for removal for a while. Change-Id: I5ec82a302ed20f14d46c665325cde7dccc9e3361 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/makestep.cpp | 3 --- src/plugins/projectexplorer/makestep.h | 1 - 2 files changed, 4 deletions(-) diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index b3b9c934868..56b04b4b7f6 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -22,9 +22,6 @@ #include #include -#include -#include -#include #include #include diff --git a/src/plugins/projectexplorer/makestep.h b/src/plugins/projectexplorer/makestep.h index 73c4e9b7e79..2f12894ea61 100644 --- a/src/plugins/projectexplorer/makestep.h +++ b/src/plugins/projectexplorer/makestep.h @@ -73,7 +73,6 @@ private: QStringList jobArguments() const; Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr; - QStringList m_availableTargets; // FIXME: Unused, remove in 4.15. Utils::StringAspect *m_makeCommandAspect = nullptr; Utils::StringAspect *m_userArgumentsAspect = nullptr; Utils::IntegerAspect *m_userJobCountAspect = nullptr; From ee6789c523174efb872a7f5a97da01b93eb56420 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 22 May 2023 13:21:57 +0200 Subject: [PATCH 1174/1447] Centralize a PluginManager::isShuttingDown() status Instead of keeping track of this in plugins individually. Change-Id: Ia2650f0f647d4a63d2010cef688aa56f6020c338 Reviewed-by: hjk --- src/libs/extensionsystem/pluginmanager.cpp | 6 ++++++ src/libs/extensionsystem/pluginmanager.h | 1 + src/libs/extensionsystem/pluginmanager_p.h | 1 + src/plugins/coreplugin/locator/locator.cpp | 5 +++-- src/plugins/coreplugin/locator/locator.h | 1 - src/plugins/debugger/debuggerplugin.cpp | 7 ++----- src/plugins/emacskeys/emacskeysplugin.cpp | 5 ----- src/plugins/emacskeys/emacskeysplugin.h | 1 - src/plugins/languageclient/client.cpp | 4 +++- .../languageclient/languageclientmanager.cpp | 20 +++++++------------ .../languageclient/languageclientmanager.h | 1 - .../projectexplorer/projectexplorer.cpp | 14 ++++++------- src/plugins/qmljseditor/qmljseditorplugin.cpp | 5 ----- src/plugins/qmljseditor/qmljseditorplugin.h | 1 - 14 files changed, 29 insertions(+), 43 deletions(-) diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 3ee99510552..ae2dbf8903b 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -1034,6 +1034,7 @@ void PluginManagerPrivate::readSettings() */ void PluginManagerPrivate::stopAll() { + m_isShuttingDown = true; if (delayedInitializeTimer && delayedInitializeTimer->isActive()) { delayedInitializeTimer->stop(); delete delayedInitializeTimer; @@ -1839,6 +1840,11 @@ bool PluginManager::isInitializationDone() return d->m_isInitializationDone; } +bool PluginManager::isShuttingDown() +{ + return d->m_isShuttingDown; +} + /*! Retrieves one object with \a name from the object pool. \sa addObject() diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h index a56cb7ba9d4..ecd0ee70b73 100644 --- a/src/libs/extensionsystem/pluginmanager.h +++ b/src/libs/extensionsystem/pluginmanager.h @@ -129,6 +129,7 @@ public: static QString platformName(); static bool isInitializationDone(); + static bool isShuttingDown(); static void remoteArguments(const QString &serializedArguments, QObject *socket); static void shutdown(); diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h index 86c3a6c3624..c7a4291a6b7 100644 --- a/src/libs/extensionsystem/pluginmanager_p.h +++ b/src/libs/extensionsystem/pluginmanager_p.h @@ -124,6 +124,7 @@ public: bool m_isInitializationDone = false; bool enableCrashCheck = true; + bool m_isShuttingDown = false; QHash> m_scenarios; QString m_requestedScenario; diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index fb9f50c3b1f..55b82920329 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -26,6 +26,8 @@ #include "../settingsdatabase.h" #include "../statusbarmanager.h" +#include + #include #include #include @@ -147,7 +149,6 @@ bool Locator::delayedInitialize() void Locator::aboutToShutdown() { - m_shuttingDown = true; m_refreshTimer.stop(); m_taskTree.reset(); } @@ -373,7 +374,7 @@ void Locator::setUseCenteredPopupForShortcut(bool center) void Locator::refresh(const QList &filters) { - if (m_shuttingDown) + if (ExtensionSystem::PluginManager::isShuttingDown()) return; m_taskTree.reset(); // Superfluous, just for clarity. The next reset() below is enough. diff --git a/src/plugins/coreplugin/locator/locator.h b/src/plugins/coreplugin/locator/locator.h index 3e73054153c..45d4b650508 100644 --- a/src/plugins/coreplugin/locator/locator.h +++ b/src/plugins/coreplugin/locator/locator.h @@ -67,7 +67,6 @@ private: bool useCenteredPopup = false; }; - bool m_shuttingDown = false; bool m_settingsInitialized = false; Settings m_settings; QList m_filters; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 87ae84dd8d6..7ccc808b08f 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -686,7 +686,6 @@ public: EngineManager m_engineManager; QTimer m_shutdownTimer; - bool m_shuttingDown = false; Console m_console; // ensure Debugger Console is created before settings are taken into account DebuggerSettings m_debuggerSettings; @@ -1392,7 +1391,7 @@ static QVariant configValue(const QString &name) void DebuggerPluginPrivate::updatePresetState() { - if (m_shuttingDown) + if (PluginManager::isShuttingDown()) return; Project *startupProject = ProjectManager::startupProject(); @@ -1996,8 +1995,6 @@ void DebuggerPluginPrivate::dumpLog() void DebuggerPluginPrivate::aboutToShutdown() { - m_shuttingDown = true; - disconnect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, nullptr); m_shutdownTimer.setInterval(0); @@ -2081,7 +2078,7 @@ QWidget *addSearch(BaseTreeView *treeView) void openTextEditor(const QString &titlePattern0, const QString &contents) { - if (dd->m_shuttingDown) + if (PluginManager::isShuttingDown()) return; QString titlePattern = titlePattern0; IEditor *editor = EditorManager::openEditorWithContents( diff --git a/src/plugins/emacskeys/emacskeysplugin.cpp b/src/plugins/emacskeys/emacskeysplugin.cpp index acb2be5b892..4f1fa8c2c82 100644 --- a/src/plugins/emacskeys/emacskeysplugin.cpp +++ b/src/plugins/emacskeys/emacskeysplugin.cpp @@ -135,11 +135,6 @@ void EmacsKeysPlugin::extensionsInitialized() { } -ExtensionSystem::IPlugin::ShutdownFlag EmacsKeysPlugin::aboutToShutdown() -{ - return SynchronousShutdown; -} - void EmacsKeysPlugin::editorAboutToClose(IEditor *editor) { auto w = qobject_cast(editor->widget()); diff --git a/src/plugins/emacskeys/emacskeysplugin.h b/src/plugins/emacskeys/emacskeysplugin.h index b0acb078cc0..ab124b47ce3 100644 --- a/src/plugins/emacskeys/emacskeysplugin.h +++ b/src/plugins/emacskeys/emacskeysplugin.h @@ -57,7 +57,6 @@ public: void initialize() override; void extensionsInitialized() override; - ShutdownFlag aboutToShutdown() override; private: void editorAboutToClose(Core::IEditor *editor); diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 77b2cbfdee5..5b0fbfa304f 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include @@ -194,7 +196,7 @@ public: // temporary container needed since m_resetAssistProvider is changed in resetAssistProviders for (TextDocument *document : m_resetAssistProvider.keys()) resetAssistProviders(document); - if (!LanguageClientManager::isShuttingDown()) { + if (!ExtensionSystem::PluginManager::isShuttingDown()) { // prevent accessing deleted editors on Creator shutdown const QList &editors = Core::DocumentModel::editorsForOpenedDocuments(); for (Core::IEditor *editor : editors) { diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 4de4a0de46e..4c8fa425303 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include @@ -32,6 +34,7 @@ #include +using namespace ExtensionSystem; using namespace LanguageServerProtocol; namespace LanguageClient { @@ -39,7 +42,6 @@ namespace LanguageClient { static Q_LOGGING_CATEGORY(Log, "qtc.languageclient.manager", QtWarningMsg) static LanguageClientManager *managerInstance = nullptr; -static bool g_shuttingDown = false; class LanguageClientManagerPrivate { @@ -139,7 +141,7 @@ void LanguageClientManager::clientStarted(Client *client) QTC_ASSERT(client, return); if (client->state() != Client::Uninitialized) // do not proceed if we already received an error return; - if (g_shuttingDown) { + if (PluginManager::isShuttingDown()) { clientFinished(client); return; } @@ -165,7 +167,7 @@ void LanguageClientManager::clientFinished(Client *client) && client->state() != Client::ShutdownRequested; if (unexpectedFinish) { - if (!g_shuttingDown) { + if (!PluginManager::isShuttingDown()) { const QList &clientDocs = managerInstance->m_clientForDocument.keys(client); if (client->reset()) { @@ -187,7 +189,7 @@ void LanguageClientManager::clientFinished(Client *client) } } deleteClient(client); - if (g_shuttingDown && managerInstance->m_clients.isEmpty()) + if (PluginManager::isShuttingDown() && managerInstance->m_clients.isEmpty()) emit managerInstance->shutdownFinished(); } @@ -236,17 +238,14 @@ void LanguageClientManager::deleteClient(Client *client) for (QList &clients : managerInstance->m_clientsForSetting) clients.removeAll(client); client->deleteLater(); - if (!g_shuttingDown) + if (!PluginManager::isShuttingDown()) emit instance()->clientRemoved(client); } void LanguageClientManager::shutdown() { QTC_ASSERT(managerInstance, return); - if (g_shuttingDown) - return; qCDebug(Log) << "shutdown manager"; - g_shuttingDown = true; const auto clients = managerInstance->clients(); for (Client *client : clients) shutdownClient(client); @@ -258,11 +257,6 @@ void LanguageClientManager::shutdown() }); } -bool LanguageClientManager::isShuttingDown() -{ - return g_shuttingDown; -} - LanguageClientManager *LanguageClientManager::instance() { return managerInstance; diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index fdbbec98b6f..e29d87a0f23 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -48,7 +48,6 @@ public: static void deleteClient(Client *client); static void shutdown(); - static bool isShuttingDown(); static LanguageClientManager *instance(); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e75e23d18f9..d1ad20fe57c 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -177,6 +177,7 @@ */ using namespace Core; +using namespace ExtensionSystem; using namespace ProjectExplorer::Internal; using namespace Utils; @@ -600,7 +601,6 @@ public: BuildPropertiesSettings m_buildPropertiesSettings; QList m_customParsers; bool m_shouldHaveRunConfiguration = false; - bool m_shuttingDown = false; Id m_runMode = Constants::NO_RUN_MODE; ToolChainManager *m_toolChainManager = nullptr; @@ -1632,11 +1632,11 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(ICore::instance(), &ICore::saveSettingsRequested, dd, &ProjectExplorerPluginPrivate::savePersistentSettings); connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] { - if (!dd->m_shuttingDown && !SessionManager::loadingSession()) + if (!PluginManager::isShuttingDown() && !SessionManager::loadingSession()) SessionManager::saveSession(); }); connect(qApp, &QApplication::applicationStateChanged, this, [](Qt::ApplicationState state) { - if (!dd->m_shuttingDown && state == Qt::ApplicationActive) + if (!PluginManager::isShuttingDown() && state == Qt::ApplicationActive) dd->updateWelcomePage(); }); @@ -2173,7 +2173,7 @@ void ProjectExplorerPluginPrivate::updateRunWithoutDeployMenu() m_runWithoutDeployAction->setVisible(m_projectExplorerSettings.deployBeforeRun); } -ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown() +IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown() { disconnect(ModeManager::instance(), &ModeManager::currentModeChanged, dd, &ProjectExplorerPluginPrivate::currentModeChanged); @@ -2181,8 +2181,6 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown() ToolChainManager::aboutToShutdown(); ProjectManager::closeAllProjects(); - dd->m_shuttingDown = true; - // Attempt to synchronously shutdown all run controls. // If that fails, fall back to asynchronous shutdown (Debugger run controls // might shutdown asynchronously). @@ -2251,7 +2249,7 @@ bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project void ProjectExplorerPluginPrivate::savePersistentSettings() { - if (dd->m_shuttingDown) + if (PluginManager::isShuttingDown()) return; if (!SessionManager::loadingSession()) { @@ -2560,7 +2558,7 @@ void ProjectExplorerPluginPrivate::checkForShutdown() { --m_activeRunControlCount; QTC_ASSERT(m_activeRunControlCount >= 0, m_activeRunControlCount = 0); - if (m_shuttingDown && m_activeRunControlCount == 0) + if (PluginManager::isShuttingDown() && m_activeRunControlCount == 0) emit m_instance->asynchronousShutdownFinished(); } diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index 884670c4faf..d695989825d 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -210,11 +210,6 @@ void QmlJSEditorPlugin::extensionsInitialized() QmllsSettingsManager::instance()->setupAutoupdate(); } -ExtensionSystem::IPlugin::ShutdownFlag QmlJSEditorPlugin::aboutToShutdown() -{ - return IPlugin::aboutToShutdown(); -} - Utils::JsonSchemaManager *QmlJSEditorPlugin::jsonManager() { return &m_instance->d->m_jsonManager; diff --git a/src/plugins/qmljseditor/qmljseditorplugin.h b/src/plugins/qmljseditor/qmljseditorplugin.h index cc1b63fe68a..aa653ac6cb0 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.h +++ b/src/plugins/qmljseditor/qmljseditorplugin.h @@ -29,7 +29,6 @@ public: private: void initialize() final; void extensionsInitialized() final; - ShutdownFlag aboutToShutdown() final; class QmlJSEditorPluginPrivate *d = nullptr; }; From f776f6f3ec524eab27a59241482322223137e59b Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 09:13:26 +0200 Subject: [PATCH 1175/1447] Doc: Add Layouting namespace to make its classes' docs visible Change-Id: I3b713f4c9bd65f279e41368ce5ce1a25ea17f176 Reviewed-by: hjk --- src/libs/utils/layoutbuilder.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 43dd68c7905..017a147897e 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -175,6 +175,14 @@ private: int m_vSpace; }; +/*! + \namespace Layouting + \inmodule QtCreator + + \brief The Layouting namespace contains classes for use with layout builders. +*/ + + /*! \class Layouting::LayoutItem \inmodule QtCreator @@ -469,18 +477,18 @@ void doAddWidget(LayoutBuilder &builder, QWidget *widget) \class Layouting::Space \inmodule QtCreator - \brief The Layouting::Space class represents some empty space in a layout. + \brief The Space class represents some empty space in a layout. */ /*! \class Layouting::Stretch \inmodule QtCreator - \brief The Layouting::Stretch class represents some stretch in a layout. + \brief The Stretch class represents some stretch in a layout. */ /*! - \class LayoutBuilder + \class Layouting::LayoutBuilder \inmodule QtCreator \brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout From 8e7ad13ad2f58469d9c11a8d60e5a4aed724cdfd Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 23 May 2023 08:49:27 +0200 Subject: [PATCH 1176/1447] Fix qbs build Was broken in an impressive number of ways by latest Design Studio merge. Change-Id: I25f56827074a8c16a1a9c18884e1f63e8eaf6ef1 Reviewed-by: Christian Stenger --- .../advanceddockingsystem.qbs | 3 ++- src/libs/utils/utils.qbs | 2 +- .../qmldesignerbase/qmldesignerbase.qbs | 21 ++++++++++++++----- .../qmldesignerbase/qmldesignerbaseplugin.cpp | 2 +- .../qmldesignerbase/studio/studiostyle.h | 2 +- .../buildsystem/qmlbuildsystem.cpp | 2 +- .../qmlprojectmanager/qmlprojectmanager.qbs | 1 - tests/auto/qml/qml.qbs | 2 +- .../fileformat/fileformat.qbs | 4 +--- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/libs/advanceddockingsystem/advanceddockingsystem.qbs b/src/libs/advanceddockingsystem/advanceddockingsystem.qbs index 9778f629492..751449cf15d 100644 --- a/src/libs/advanceddockingsystem/advanceddockingsystem.qbs +++ b/src/libs/advanceddockingsystem/advanceddockingsystem.qbs @@ -7,7 +7,7 @@ QtcLibrary { cpp.defines: base.concat("ADVANCEDDOCKINGSYSTEM_LIBRARY") cpp.includePaths: base.concat([".", linux.prefix]) - Depends { name: "Qt"; submodules: ["widgets", "core", "gui"] } + Depends { name: "Qt"; submodules: ["widgets", "xml"] } Depends { name: "Utils" } Group { @@ -31,6 +31,7 @@ QtcLibrary { "floatingdockcontainer.cpp", "floatingdockcontainer.h", "floatingdragpreview.cpp", "floatingdragpreview.h", "iconprovider.cpp", "iconprovider.h", + "workspace.cpp", "workspace.h", "workspacedialog.cpp", "workspacedialog.h", "workspacemodel.cpp", "workspacemodel.h", "workspaceview.cpp", "workspaceview.h", diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 3196d9b34b0..298b23c1e9f 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -337,7 +337,7 @@ Project { "headerviewstretcher.h", "uncommentselection.cpp", "uncommentselection.h", - "uniqueobjectptr.h" + "uniqueobjectptr.h", "unixutils.cpp", "unixutils.h", "url.cpp", diff --git a/src/plugins/qmldesignerbase/qmldesignerbase.qbs b/src/plugins/qmldesignerbase/qmldesignerbase.qbs index 937f180c32c..98f4cdf5562 100644 --- a/src/plugins/qmldesignerbase/qmldesignerbase.qbs +++ b/src/plugins/qmldesignerbase/qmldesignerbase.qbs @@ -16,14 +16,25 @@ QtcPlugin { ] Group { - prefix: "utils/" + prefix: "studio/" files: [ - "designersettings.cpp", - "designersettings.h", - "qmlpuppetpaths.cpp", - "qmlpuppetpaths.h", + "studiosettingspage.cpp", + "studiosettingspage.h", + "studiostyle.cpp", + "studiostyle.h", "studioquickwidget.cpp", "studioquickwidget.h", ] } + Group { + prefix: "utils/" + files: [ + "designerpaths.cpp", + "designerpaths.h", + "designersettings.cpp", + "designersettings.h", + "qmlpuppetpaths.cpp", + "qmlpuppetpaths.h", + ] + } } diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp index c9af4f22836..c59fcbb2ea1 100644 --- a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp +++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp @@ -3,7 +3,7 @@ #include "qmldesignerbaseplugin.h" -#include "studiosettingspage.h" +#include "studio/studiosettingspage.h" #include "studio/studiostyle.h" #include "utils/designersettings.h" diff --git a/src/plugins/qmldesignerbase/studio/studiostyle.h b/src/plugins/qmldesignerbase/studio/studiostyle.h index 4d6424cbef1..c55797354b3 100644 --- a/src/plugins/qmldesignerbase/studio/studiostyle.h +++ b/src/plugins/qmldesignerbase/studio/studiostyle.h @@ -3,7 +3,7 @@ #pragma once -#include "qmldesignerbase_global.h" +#include "../qmldesignerbase_global.h" #include diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 86645dc8c50..2b600210736 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "qmlbuildsystem.h" -#include "qmlprojectconstants.h" +#include "../qmlprojectconstants.h" #include #include diff --git a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs index e4e4d0bc247..2ab9417704e 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs +++ b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs @@ -26,7 +26,6 @@ QtcPlugin { "qmlprojectconstants.h", "qmlprojectmanager_global.h", "qmlprojectmanagertr.h", "qmlprojectmanagerconstants.h", - "qmlprojectnodes.cpp", "qmlprojectnodes.h", "qmlprojectplugin.cpp", "qmlprojectplugin.h", "qmlprojectrunconfiguration.cpp", "qmlprojectrunconfiguration.h", project.ide_source_tree + "/src/share/3rdparty/studiofonts/studiofonts.qrc" diff --git a/tests/auto/qml/qml.qbs b/tests/auto/qml/qml.qbs index 76659a5256b..9f887bfcacd 100644 --- a/tests/auto/qml/qml.qbs +++ b/tests/auto/qml/qml.qbs @@ -7,7 +7,7 @@ Project { // "qmldesigner/qmldesigner.qbs", "qmleditor/qmleditor.qbs", "qmljssimplereader/qmljssimplereader.qbs", - "qmlprojectmanager/qmlprojectmanager.qbs", +// "qmlprojectmanager/qmlprojectmanager.qbs", "qrcparser/qrcparser.qbs", "reformatter/reformatter.qbs", "persistenttrie/persistenttrie.qbs" diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs b/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs index 07ed3a924e6..7abe08bf40b 100644 --- a/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs +++ b/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs @@ -4,7 +4,7 @@ QtcAutotest { name: "QmlProjectManager file format autotest" Depends { name: "QmlJS" } Depends { name: "Utils" } - property path fileFormatDir: project.ide_source_tree + "/src/plugins/qmlprojectmanager/fileformat" + property path fileFormatDir: project.ide_source_tree + "/src/plugins/qmlprojectmanager/buildsystem/projectitem" files: "tst_fileformat.cpp" Group { name: "Files from QmlProjectManager" @@ -12,8 +12,6 @@ QtcAutotest { files: [ "filefilteritems.cpp", "filefilteritems.h", - "qmlprojectfileformat.cpp", - "qmlprojectfileformat.h", "qmlprojectitem.cpp", "qmlprojectitem.h", ] From 9c6e3b724adbd4c45d8bae414e4012c6a29e1675 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 09:24:20 +0200 Subject: [PATCH 1177/1447] Doc: Add \brief commands to namespace docs to show them in tables ...and at the top of the topics. Change-Id: I3d521a351e06d765a79304db897c5cffa9fee0df Reviewed-by: Jarek Kobus --- src/libs/solutions/tasking/tasktree.cpp | 6 ++++-- src/libs/utils/utils.qdoc | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index dd7f2fea98b..6d3e7eb95bc 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -726,8 +726,10 @@ void TaskNode::invokeEndHandler(bool success) /*! \namespace Tasking \inmodule QtCreator - The Tasking namespace contains a general purpose TaskTree solution. - It depends on Qt only, and doesn't depend on any \QC specific code. + \brief The Tasking namespace contains a general purpose TaskTree solution. + + The Tasking namespace depends on Qt only, and doesn't depend on any \QC + specific code. */ /*! diff --git a/src/libs/utils/utils.qdoc b/src/libs/utils/utils.qdoc index ae6d39b589d..bc9f843498c 100644 --- a/src/libs/utils/utils.qdoc +++ b/src/libs/utils/utils.qdoc @@ -5,6 +5,6 @@ \namespace Utils \inmodule QtCreator - The Utils namespace contains a collection of utility classes and functions for use by all + \brief The Utils namespace contains a collection of utility classes and functions for use by all plugins. */ From 590a6904b10ddd3538733c927b7a2a1b49c7e8a2 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 23 May 2023 09:26:30 +0200 Subject: [PATCH 1178/1447] QmlDesigner: Fix qbs build and building with Qt6.2 Change-Id: Ic114c9eb830eed5cf0bef890007408694453791e Reviewed-by: Christian Kandeler --- .../studio/studiosettingspage.cpp | 8 +- .../qmldesignerbase/utils/designerpaths.cpp | 4 +- .../buildsystem/qmlbuildsystem.cpp | 2 + src/plugins/qmlprojectmanager/qmlproject.cpp | 2 +- .../fileformat/fileformat.qbs | 2 + .../fileformat/tst_fileformat.cpp | 107 +++++++----------- 6 files changed, 52 insertions(+), 73 deletions(-) diff --git a/src/plugins/qmldesignerbase/studio/studiosettingspage.cpp b/src/plugins/qmldesignerbase/studio/studiosettingspage.cpp index d88c4cf409b..d94efbd666b 100644 --- a/src/plugins/qmldesignerbase/studio/studiosettingspage.cpp +++ b/src/plugins/qmldesignerbase/studio/studiosettingspage.cpp @@ -178,15 +178,15 @@ void StudioSettingsPage::apply() QSettings *s = Core::ICore::settings(); const QString value = m_pathChooserExamples->filePath().toString(); - if (s->value(Paths::exampleDownloadPath, false).toString() != value) { - s->setValue(Paths::exampleDownloadPath, value); + if (s->value(Paths::exampleDownloadPath.toString(), false).toString() != value) { + s->setValue(Paths::exampleDownloadPath.toString(), value); emit examplesDownloadPathChanged(value); } const QString bundlesPath = m_pathChooserBundles->filePath().toString(); - if (s->value(Paths::bundlesDownloadPath).toString() != bundlesPath) { - s->setValue(Paths::bundlesDownloadPath, bundlesPath); + if (s->value(Paths::bundlesDownloadPath.toString()).toString() != bundlesPath) { + s->setValue(Paths::bundlesDownloadPath.toString(), bundlesPath); emit bundlesDownloadPathChanged(bundlesPath); const QString restartText = tr("Changing bundle path will take effect after restart."); diff --git a/src/plugins/qmldesignerbase/utils/designerpaths.cpp b/src/plugins/qmldesignerbase/utils/designerpaths.cpp index d4ae2a46456..53b4b7ea37e 100644 --- a/src/plugins/qmldesignerbase/utils/designerpaths.cpp +++ b/src/plugins/qmldesignerbase/utils/designerpaths.cpp @@ -31,14 +31,14 @@ Utils::FilePath defaultBundlesPath() QString examplesPathSetting() { return Core::ICore::settings() - ->value(exampleDownloadPath, defaultExamplesPath().toString()) + ->value(exampleDownloadPath.toString(), defaultExamplesPath().toString()) .toString(); } QString bundlesPathSetting() { return Core::ICore::settings() - ->value(bundlesDownloadPath, defaultBundlesPath().toString()) + ->value(bundlesDownloadPath.toString(), defaultBundlesPath().toString()) .toString(); } diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 2b600210736..81a157f1b6f 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -37,6 +37,8 @@ #include "texteditor/textdocument.h" +#include + using namespace ProjectExplorer; namespace QmlProjectManager { diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index ce2f363cd41..31fa3429d21 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -248,7 +248,7 @@ bool QmlProject::allowOnlySingleProject() { QSettings *settings = Core::ICore::settings(); auto key = "QML/Designer/AllowMultipleProjects"; - return !settings->value(key, false).toBool(); + return !settings->value(QString::fromUtf8(key), false).toBool(); } } // namespace QmlProjectManager diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs b/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs index 7abe08bf40b..f32bd21c05d 100644 --- a/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs +++ b/tests/auto/qml/qmlprojectmanager/fileformat/fileformat.qbs @@ -10,6 +10,8 @@ QtcAutotest { name: "Files from QmlProjectManager" prefix: product.fileFormatDir + '/' files: [ + "converters.cpp", + "converters.h", "filefilteritems.cpp", "filefilteritems.h", "qmlprojectitem.cpp", diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp b/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp index bd7695b53db..b8b5f11dee7 100644 --- a/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp +++ b/tests/auto/qml/qmlprojectmanager/fileformat/tst_fileformat.cpp @@ -2,8 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qmlprojectitem.h" -#include "filefilteritems.h" -#include "qmlprojectfileformat.h" #include @@ -43,29 +41,27 @@ tst_FileFormat::tst_FileFormat() const QString testDataDir = QLatin1String(SRCDIR "/data"); const FilePath testDataDirPath = FilePath::fromString(testDataDir); -static std::unique_ptr loadQmlProject(QString name, QString *error) +static std::unique_ptr loadQmlProject(QString name) { - return QmlProjectFileFormat::parseProjectFile( - Utils::FilePath::fromString(testDataDir).pathAppended(name + ".qmlproject"), error); + return std::unique_ptr(new QmlProjectItem( + testDataDirPath.pathAppended(name + ".qmlproject"))); } void tst_FileFormat::testFileFilter() { - QString error; - // // Search for qml files in directory + subdirectories // { - auto project = loadQmlProject(QLatin1String("testFileFilter1"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter1")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/file1.qml" - << testDataDir + "/file2.qml" - << testDataDir + "/subdir/file3.qml"); + FilePaths expectedFiles{ + testDataDirPath / "file1.qml", + testDataDirPath / "file2.qml", + testDataDirPath / "subdir/file3.qml" + }; COMPARE_AS_SETS(project->files(), expectedFiles); } @@ -73,14 +69,11 @@ void tst_FileFormat::testFileFilter() // search for all qml files in directory // { - auto project = loadQmlProject(QLatin1String("testFileFilter2"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter2")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/file1.qml" - << testDataDir + "/file2.qml"); + FilePaths expectedFiles{ testDataDirPath / "file1.qml", testDataDirPath / "file2.qml" }; COMPARE_AS_SETS(project->files(), expectedFiles); } @@ -88,13 +81,11 @@ void tst_FileFormat::testFileFilter() // search for all qml files in subdirectory // { - auto project = loadQmlProject(QLatin1String("testFileFilter3"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter3")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/subdir/file3.qml"); + FilePaths expectedFiles{ testDataDirPath / "subdir/file3.qml" }; COMPARE_AS_SETS(project->files(), expectedFiles); } @@ -102,15 +93,15 @@ void tst_FileFormat::testFileFilter() // multiple entries // { - auto project = loadQmlProject(QLatin1String("testFileFilter4"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter4")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/file1.qml" - << testDataDir + "/file2.qml" - << testDataDir + "/subdir/file3.qml"); + FilePaths expectedFiles{ + testDataDirPath / "file1.qml", + testDataDirPath / "file2.qml", + testDataDirPath / "/subdir/file3.qml" + }; QCOMPARE(project->files().size(), 3); COMPARE_AS_SETS(project->files(), expectedFiles); } @@ -119,14 +110,11 @@ void tst_FileFormat::testFileFilter() // include specific list // { - auto project = loadQmlProject(QLatin1String("testFileFilter5"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter5")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/file1.qml" - << testDataDir + "/file2.qml"); + FilePaths expectedFiles{ testDataDirPath / "file1.qml", testDataDirPath / "file2.qml" }; COMPARE_AS_SETS(project->files(), expectedFiles); } @@ -134,13 +122,11 @@ void tst_FileFormat::testFileFilter() // include specific list // { - auto project = loadQmlProject(QLatin1String("testFileFilter6"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter6")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/image.gif"); + FilePaths expectedFiles{ testDataDirPath / "image.gif" }; COMPARE_AS_SETS(project->files(), expectedFiles); } @@ -148,13 +134,11 @@ void tst_FileFormat::testFileFilter() // use wildcards // { - auto project = loadQmlProject(QLatin1String("testFileFilter7"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter7")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/image.gif"); + FilePaths expectedFiles{ testDataDirPath / "image.gif" }; COMPARE_AS_SETS(project->files(), expectedFiles); } @@ -162,28 +146,23 @@ void tst_FileFormat::testFileFilter() // use Files element (1.1) // { - auto project = loadQmlProject(QLatin1String("testFileFilter8"), &error); + auto project = loadQmlProject(QLatin1String("testFileFilter8")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); - project->setSourceDirectory(testDataDirPath); - - QStringList expectedFiles(QStringList() << testDataDir + "/image.gif"); + FilePaths expectedFiles{ testDataDirPath / "image.gif" }; COMPARE_AS_SETS(project->files(), expectedFiles); } } void tst_FileFormat::testMatchesFile() { - QString error; // // search for qml files in local directory // - auto project = loadQmlProject(QLatin1String("testMatchesFile"), &error); + auto project = loadQmlProject(QLatin1String("testMatchesFile")); QVERIFY(project); - QVERIFY(error.isEmpty()); - - project->setSourceDirectory(testDataDirPath); + QVERIFY(!project->project().isEmpty()); QVERIFY(project->matchesFile(testDataDir + "/file1.qml")); QVERIFY(project->matchesFile(testDataDir + "/notyetexistingfile.qml")); @@ -194,15 +173,12 @@ void tst_FileFormat::testMatchesFile() void tst_FileFormat::testLibraryPaths() { - QString error; // // search for qml files in local directory // - auto project = loadQmlProject(QLatin1String("testLibraryPaths"), &error); + auto project = loadQmlProject(QLatin1String("testLibraryPaths")); QVERIFY(project); - QVERIFY(error.isEmpty()); - - project->setSourceDirectory(testDataDirPath); + QVERIFY(!project->project().isEmpty()); const QDir base(testDataDir); const QStringList expectedPaths({base.relativeFilePath(SRCDIR "/otherLibrary"), @@ -212,13 +188,12 @@ void tst_FileFormat::testLibraryPaths() void tst_FileFormat::testMainFile() { - QString error; // // search for qml files in local directory // - auto project = loadQmlProject(QLatin1String("testMainFile"), &error); + auto project = loadQmlProject(QLatin1String("testMainFile")); QVERIFY(project); - QVERIFY(error.isEmpty()); + QVERIFY(!project->project().isEmpty()); QCOMPARE(project->mainFile(), QString("file1.qml")); } From d63c57ef47fa7de0f7621a4ac8c41131e01905bc Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 22 May 2023 10:12:23 +0200 Subject: [PATCH 1179/1447] CodeAssistant: do not schedule processor deletion too early Calling displayProposal might spawn another eventloop that potentially deletes the processor before the async proposal handler finished. Fixes: QTCREATORBUG-28989 Change-Id: I3a8ddb9180cb7737a37ea39dc59d922e83615ed6 Reviewed-by: Christian Kandeler --- .../texteditor/codeassist/codeassistant.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index b3d9d477e24..182df3002a1 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -185,26 +185,26 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason, IAssistProcessor *processor = provider->createProcessor(assistInterface.get()); processor->setAsyncCompletionAvailableHandler([this, reason, processor]( IAssistProposal *newProposal) { + if (processor == m_processor) { + invalidateCurrentRequestData(); + if (processor->needsRestart() && m_receivedContentWhileWaiting) { + delete newProposal; + m_receivedContentWhileWaiting = false; + requestProposal(reason, m_assistKind, m_requestProvider); + } else { + displayProposal(newProposal, reason); + if (processor->running()) + m_processor = processor; + else + emit q->finished(); + } + } if (!processor->running()) { // do not delete this processor directly since this function is called from within the processor QMetaObject::invokeMethod(QCoreApplication::instance(), [processor] { delete processor; }, Qt::QueuedConnection); } - if (processor != m_processor) - return; - invalidateCurrentRequestData(); - if (processor->needsRestart() && m_receivedContentWhileWaiting) { - delete newProposal; - m_receivedContentWhileWaiting = false; - requestProposal(reason, m_assistKind, m_requestProvider); - } else { - displayProposal(newProposal, reason); - if (processor->running()) - m_processor = processor; - else - emit q->finished(); - } }); if (IAssistProposal *newProposal = processor->start(std::move(assistInterface))) From 69c81e8a653ace25e01aaebdf4520bb95bc5e327 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 23 May 2023 07:16:30 +0200 Subject: [PATCH 1180/1447] Terminal: Fix case insensitive search Case sensitive / case insensitive were set the wrong way around. Change-Id: I7ed689684972aae5f6b1af2f35d9fd72d2df71e9 Reviewed-by: Orgad Shaneh --- src/plugins/terminal/terminalsearch.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/terminal/terminalsearch.cpp b/src/plugins/terminal/terminalsearch.cpp index b69587298b7..e909e75dfe6 100644 --- a/src/plugins/terminal/terminalsearch.cpp +++ b/src/plugins/terminal/terminalsearch.cpp @@ -99,12 +99,13 @@ QList TerminalSearch::search() std::function compare; - if (m_findFlags.testFlag(Core::FindFlag::FindCaseSensitively)) + if (m_findFlags.testFlag(Core::FindFlag::FindCaseSensitively)) { + compare = [](char32_t a, char32_t b) { return a == b || isSpace(a, b); }; + } else { compare = [](char32_t a, char32_t b) { return std::tolower(a) == std::tolower(b) || isSpace(a, b); }; - else - compare = [](char32_t a, char32_t b) { return a == b || isSpace(a, b); }; + } if (!m_currentSearchString.isEmpty()) { const QList asUcs4 = m_currentSearchString.toUcs4(); From 0c0fb744e068d08f50cfa6678f814128fd63c0aa Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 23 May 2023 11:03:31 +0200 Subject: [PATCH 1181/1447] Utils: Fix missing include Change-Id: I98e5a00f9f4f09cc9c09f3d0436ba5dfc20e3b31 Reviewed-by: Marcus Tillmanns --- src/libs/utils/checkablemessagebox.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/utils/checkablemessagebox.h b/src/libs/utils/checkablemessagebox.h index 3f156b2de1a..297ff22b623 100644 --- a/src/libs/utils/checkablemessagebox.h +++ b/src/libs/utils/checkablemessagebox.h @@ -5,6 +5,7 @@ #include "utils_global.h" +#include #include QT_BEGIN_NAMESPACE From ce0ab1cd27ddf10352912a9ec51e2aca9556c0a3 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 22 May 2023 15:57:00 +0200 Subject: [PATCH 1182/1447] Doc: Replace \p with \a and remove \param The qdoc command for arguments/parameters is \a. It is enough to place it somewhere in the text to make qdoc happy. Change-Id: I164fbd63277787a68b0216ad3fbbed768b975d91 Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/libs/utils/filepath.cpp | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 9ec738fdf26..fa91a09d054 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1327,11 +1327,11 @@ bool FilePath::startsWithDriveLetter() const /*! \brief Relative path from \a parent to this. - Returns a empty FilePath if this is not a child of \p parent. + Returns a empty \c FilePath if this is not a child of \a parent. + \a parent is the Parent to calculate the relative path to. That is, this never returns a path starting with "../" - \param parent The Parent to calculate the relative path to. - Returns The relative path of this to \p parent if this is a child of \p parent. + Returns the relative path of this to \a parent if this is a child of \a parent. */ FilePath FilePath::relativeChildPath(const FilePath &parent) const { @@ -1728,16 +1728,16 @@ qint64 FilePath::bytesAvailable() const } /*! - \brief Checks if this is newer than \p timeStamp + \brief Checks if this is newer than \a timeStamp. - \param timeStamp The time stamp to compare with - Returns true if this is newer than \p timeStamp. - If this is a directory, the function will recursively check all files and return - true if one of them is newer than \a timeStamp. If this is a single file, true will - be returned if the file is newer than \a timeStamp. + The time stamp \a timeStamp to compare with. + Returns \c true if this is newer than \a timeStamp. + If this is a directory, the function will recursively check all files and return + \c true if one of them is newer than \a timeStamp. If this is a single file, \c true will + be returned if the file is newer than \a timeStamp. Returns whether at least one file in \a filePath has a newer date than - \p timeStamp. + \a timeStamp. */ bool FilePath::isNewerThan(const QDateTime &timeStamp) const { @@ -1907,7 +1907,7 @@ QString FilePath::shortNativePath() const } /*! - \brief Checks whether the path is relative + \brief Checks whether the path is relative. Returns true if the path is relative. */ @@ -1924,11 +1924,9 @@ bool FilePath::isRelativePath() const } /*! - \brief Appends the tail to this, if the tail is a relative path. + \brief Appends the \a tail to this, if the tail is a relative path. - \param tail The tail to append. - - Returns tail if tail is absolute, otherwise this + tail. + Returns the tail if the tail is absolute, otherwise this + tail. */ FilePath FilePath::resolvePath(const FilePath &tail) const { @@ -1940,11 +1938,9 @@ FilePath FilePath::resolvePath(const FilePath &tail) const } /*! - \brief Appends the tail to this, if the tail is a relative path. + \brief Appends the \a tail to this, if the tail is a relative path. - \param tail The tail to append. - - Returns tail if tail is absolute, otherwise this + tail. + Returns the tail if the tail is absolute, otherwise this + tail. */ FilePath FilePath::resolvePath(const QString &tail) const { @@ -1962,7 +1958,7 @@ expected_str FilePath::localSource() const } /*! - \brief Cleans path part similar to QDir::cleanPath() + \brief Cleans path part similar to \c QDir::cleanPath(). \list \li directory separators normalized (that is, platform-native From e45609194d81ae13eb0b531351b42d1b60608f94 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 22 May 2023 15:12:07 +0200 Subject: [PATCH 1183/1447] Doc: Remove period from the end of \sa The HTML generator adds it automatically and qdoc warns about it. Change-Id: I3917d7d23b16446e28ce7bfeb8f9195f21efd7fc Reviewed-by: hjk Reviewed-by: --- src/libs/utils/aspects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 7d509a21076..59c0ee3f8b3 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2441,7 +2441,7 @@ void AspectContainer::registerAspects(const AspectContainer &aspects) /*! Retrieves a BaseAspect with a given \a id, or nullptr if no such aspect is contained. - \sa BaseAspect. + \sa BaseAspect */ BaseAspect *AspectContainer::aspect(Id id) const { From ffd0f7306b09ce7a2538758acb16b24b6f73ee95 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 13:57:41 +0200 Subject: [PATCH 1184/1447] Android: Use direct member for aspect Change-Id: Ia925522e15452e15a8a89803a591db6a4b18540b Reviewed-by: Alessandro Portale --- src/plugins/android/androiddeployqtstep.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index f33ae5aa6b3..b8b8b8cc2ae 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -122,7 +122,7 @@ private: QMap m_filesToPull; QStringList m_androidABIs; - BoolAspect *m_uninstallPreviousPackage = nullptr; + BoolAspect m_uninstallPreviousPackage{this}; bool m_uninstallPreviousPackageRun = false; bool m_useAndroiddeployqt = false; bool m_askForUninstall = false; @@ -142,18 +142,18 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id) { setImmutable(true); setUserExpanded(true); + setOwnsSubAspects(false); - m_uninstallPreviousPackage = addAspect(); - m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey); - m_uninstallPreviousPackage->setLabel(Tr::tr("Uninstall the existing app before deployment"), - BoolAspect::LabelPlacement::AtCheckBox); - m_uninstallPreviousPackage->setValue(false); + m_uninstallPreviousPackage.setSettingsKey(UninstallPreviousPackageKey); + m_uninstallPreviousPackage.setLabel(Tr::tr("Uninstall the existing app before deployment"), + BoolAspect::LabelPlacement::AtCheckBox); + m_uninstallPreviousPackage.setValue(false); const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); const bool forced = qt && qt->qtVersion() < QVersionNumber(5, 4, 0); if (forced) { - m_uninstallPreviousPackage->setValue(true); - m_uninstallPreviousPackage->setEnabled(false); + m_uninstallPreviousPackage.setValue(true); + m_uninstallPreviousPackage.setEnabled(false); } connect(this, &AndroidDeployQtStep::askForUninstall, @@ -274,7 +274,7 @@ bool AndroidDeployQtStep::init() emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); - m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value(); + m_uninstallPreviousPackageRun = m_uninstallPreviousPackage(); if (m_uninstallPreviousPackageRun) m_manifestName = AndroidManager::manifestPath(target()); From b4185f04aa8f87e6017d5a2dcd565e6f1708d862 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 13:58:17 +0200 Subject: [PATCH 1185/1447] Android: Hide AndroidRunConfiguration implementation Expose the factory, that's how most other places are organized. Change-Id: Ia6e088b70a6c5ee3b18b67e852619e922c95f781 Reviewed-by: Assam Boudjelthia Reviewed-by: Alessandro Portale --- src/plugins/android/androidplugin.cpp | 11 --- .../android/androidrunconfiguration.cpp | 80 +++++++++++-------- src/plugins/android/androidrunconfiguration.h | 5 +- 3 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 459edad2bbd..916600c1df7 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -70,17 +70,6 @@ public: } }; -class AndroidRunConfigurationFactory : public RunConfigurationFactory -{ -public: - AndroidRunConfigurationFactory() - { - registerRunConfiguration - ("Qt4ProjectManager.AndroidRunConfiguration:"); - addSupportedTargetDeviceType(Android::Constants::ANDROID_DEVICE_TYPE); - } -}; - class AndroidPluginPrivate : public QObject { public: diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index e62145566a1..45f991ca747 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -46,49 +46,59 @@ public: } }; -AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Utils::Id id) - : RunConfiguration(target, id) +class AndroidRunConfiguration : public RunConfiguration { - auto envAspect = addAspect(); - envAspect->addSupportedBaseEnvironment(Tr::tr("Clean Environment"), {}); +public: + AndroidRunConfiguration(Target *target, Id id) + : RunConfiguration(target, id) + { + auto envAspect = addAspect(); + envAspect->addSupportedBaseEnvironment(Tr::tr("Clean Environment"), {}); - auto extraAppArgsAspect = addAspect(macroExpander()); + auto extraAppArgsAspect = addAspect(macroExpander()); - connect(extraAppArgsAspect, &BaseAspect::changed, this, [target, extraAppArgsAspect] { - if (target->buildConfigurations().first()->buildType() == BuildConfiguration::BuildType::Release) { - const QString buildKey = target->activeBuildKey(); - target->buildSystem()->setExtraData(buildKey, - Android::Constants::AndroidApplicationArgs, - extraAppArgsAspect->arguments()); - } - }); + connect(extraAppArgsAspect, &BaseAspect::changed, this, [target, extraAppArgsAspect] { + if (target->buildConfigurations().first()->buildType() == BuildConfiguration::BuildType::Release) { + const QString buildKey = target->activeBuildKey(); + target->buildSystem()->setExtraData(buildKey, + Android::Constants::AndroidApplicationArgs, + extraAppArgsAspect->arguments()); + } + }); - auto amStartArgsAspect = addAspect(); - amStartArgsAspect->setId(Constants::ANDROID_AM_START_ARGS); - amStartArgsAspect->setSettingsKey("Android.AmStartArgsKey"); - amStartArgsAspect->setLabelText(Tr::tr("Activity manager start arguments:")); - amStartArgsAspect->setDisplayStyle(StringAspect::LineEditDisplay); - amStartArgsAspect->setHistoryCompleter("Android.AmStartArgs.History"); + auto amStartArgsAspect = addAspect(); + amStartArgsAspect->setId(Constants::ANDROID_AM_START_ARGS); + amStartArgsAspect->setSettingsKey("Android.AmStartArgsKey"); + amStartArgsAspect->setLabelText(Tr::tr("Activity manager start arguments:")); + amStartArgsAspect->setDisplayStyle(StringAspect::LineEditDisplay); + amStartArgsAspect->setHistoryCompleter("Android.AmStartArgs.History"); - auto preStartShellCmdAspect = addAspect(); - preStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay); - preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST); - preStartShellCmdAspect->setSettingsKey("Android.PreStartShellCmdListKey"); - preStartShellCmdAspect->setLabelText(Tr::tr("Pre-launch on-device shell commands:")); + auto preStartShellCmdAspect = addAspect(); + preStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay); + preStartShellCmdAspect->setId(Constants::ANDROID_PRESTARTSHELLCMDLIST); + preStartShellCmdAspect->setSettingsKey("Android.PreStartShellCmdListKey"); + preStartShellCmdAspect->setLabelText(Tr::tr("Pre-launch on-device shell commands:")); - auto postStartShellCmdAspect = addAspect(); - postStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay); - postStartShellCmdAspect->setId(Constants::ANDROID_POSTFINISHSHELLCMDLIST); - postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey"); - postStartShellCmdAspect->setLabelText(Tr::tr("Post-quit on-device shell commands:")); + auto postStartShellCmdAspect = addAspect(); + postStartShellCmdAspect->setDisplayStyle(StringAspect::TextEditDisplay); + postStartShellCmdAspect->setId(Constants::ANDROID_POSTFINISHSHELLCMDLIST); + postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey"); + postStartShellCmdAspect->setLabelText(Tr::tr("Post-quit on-device shell commands:")); - setUpdater([this] { - const BuildTargetInfo bti = buildTargetInfo(); - setDisplayName(bti.displayName); - setDefaultDisplayName(bti.displayName); - }); + setUpdater([this] { + const BuildTargetInfo bti = buildTargetInfo(); + setDisplayName(bti.displayName); + setDefaultDisplayName(bti.displayName); + }); - connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); + connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); + } +}; + +AndroidRunConfigurationFactory::AndroidRunConfigurationFactory() +{ + registerRunConfiguration("Qt4ProjectManager.AndroidRunConfiguration:"); + addSupportedTargetDeviceType(Android::Constants::ANDROID_DEVICE_TYPE); } } // namespace Android diff --git a/src/plugins/android/androidrunconfiguration.h b/src/plugins/android/androidrunconfiguration.h index 57576c555a9..9ad677aeef3 100644 --- a/src/plugins/android/androidrunconfiguration.h +++ b/src/plugins/android/androidrunconfiguration.h @@ -9,11 +9,10 @@ namespace Android { -class ANDROID_EXPORT AndroidRunConfiguration : public ProjectExplorer::RunConfiguration +class AndroidRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory { - Q_OBJECT public: - explicit AndroidRunConfiguration(ProjectExplorer::Target *target, Utils::Id id); + AndroidRunConfigurationFactory(); }; } // namespace Android From 48792c07a554b5377e3715b85347cc9bb6aa7331 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 23 May 2023 10:22:30 +0000 Subject: [PATCH 1186/1447] Revert "Android: Use direct member for aspect" This reverts commit ffd0f7306b09ce7a2538758acb16b24b6f73ee95. Reason for revert: Breaks build. Revert is temporary, will be reapplied after I6eefe739b3aebcef1ece196ff8d70aa36738997b is in Change-Id: I5029f710656fb89eeaf65b55742678938f249aeb Reviewed-by: hjk --- src/plugins/android/androiddeployqtstep.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index b8b8b8cc2ae..f33ae5aa6b3 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -122,7 +122,7 @@ private: QMap m_filesToPull; QStringList m_androidABIs; - BoolAspect m_uninstallPreviousPackage{this}; + BoolAspect *m_uninstallPreviousPackage = nullptr; bool m_uninstallPreviousPackageRun = false; bool m_useAndroiddeployqt = false; bool m_askForUninstall = false; @@ -142,18 +142,18 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id) { setImmutable(true); setUserExpanded(true); - setOwnsSubAspects(false); - m_uninstallPreviousPackage.setSettingsKey(UninstallPreviousPackageKey); - m_uninstallPreviousPackage.setLabel(Tr::tr("Uninstall the existing app before deployment"), - BoolAspect::LabelPlacement::AtCheckBox); - m_uninstallPreviousPackage.setValue(false); + m_uninstallPreviousPackage = addAspect(); + m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey); + m_uninstallPreviousPackage->setLabel(Tr::tr("Uninstall the existing app before deployment"), + BoolAspect::LabelPlacement::AtCheckBox); + m_uninstallPreviousPackage->setValue(false); const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); const bool forced = qt && qt->qtVersion() < QVersionNumber(5, 4, 0); if (forced) { - m_uninstallPreviousPackage.setValue(true); - m_uninstallPreviousPackage.setEnabled(false); + m_uninstallPreviousPackage->setValue(true); + m_uninstallPreviousPackage->setEnabled(false); } connect(this, &AndroidDeployQtStep::askForUninstall, @@ -274,7 +274,7 @@ bool AndroidDeployQtStep::init() emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); - m_uninstallPreviousPackageRun = m_uninstallPreviousPackage(); + m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value(); if (m_uninstallPreviousPackageRun) m_manifestName = AndroidManager::manifestPath(target()); From c7bce1452516cdcbe346e67d39c99b5318ee4e5c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 23 May 2023 12:50:09 +0200 Subject: [PATCH 1187/1447] Terminal: Axivion warning fixes Change-Id: Iae048d53c64c2c42fa14e425b5de11e0bf1a59d3 Reviewed-by: Cristian Adam --- src/plugins/terminal/terminalpane.cpp | 112 ++++++++++++-------------- src/plugins/terminal/terminalpane.h | 4 +- 2 files changed, 52 insertions(+), 64 deletions(-) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 92ad5951914..9b1f9898e81 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -32,9 +32,8 @@ using namespace Utils::Terminal; TerminalPane::TerminalPane(QObject *parent) : Core::IOutputPane(parent) - , m_tabWidget(new QTabWidget) { - setupContext("Terminal.Pane", m_tabWidget); + setupContext("Terminal.Pane", &m_tabWidget); setZoomButtonsEnabled(true); TerminalCommands::instance().init(Core::Context("Terminal.Pane")); @@ -66,13 +65,13 @@ TerminalPane::TerminalPane(QObject *parent) closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); connect(&closeTerminal, &QAction::triggered, this, [this] { - removeTab(m_tabWidget->currentIndex()); + removeTab(m_tabWidget.currentIndex()); }); m_newTerminalButton = new QToolButton(); QMenu *shellMenu = new QMenu(m_newTerminalButton); - Internal::ShellModel *shellModel = new Internal::ShellModel(shellMenu); + const Internal::ShellModel *shellModel = new Internal::ShellModel(shellMenu); connect(shellMenu, &QMenu::aboutToShow, shellMenu, [shellMenu, shellModel, pane = this] { shellMenu->clear(); @@ -129,11 +128,13 @@ TerminalPane::TerminalPane(QObject *parent) TerminalCommands::openSettingsAction()->trigger(); }); - auto updateEscButton = [this] { + const auto updateEscButton = [this] { m_escSettingButton->setChecked(TerminalSettings::instance().sendEscapeToTerminal.value()); - static QString escKey = QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText); - static QString shiftEsc = QKeySequence(QKeyCombination(Qt::ShiftModifier, Qt::Key_Escape)) - .toString(QKeySequence::NativeText); + static const QString escKey + = QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText); + static const QString shiftEsc = QKeySequence( + QKeyCombination(Qt::ShiftModifier, Qt::Key_Escape)) + .toString(QKeySequence::NativeText); if (TerminalSettings::instance().sendEscapeToTerminal.value()) { m_escSettingButton->setText(escKey); m_escSettingButton->setToolTip(Tr::tr("Sending ESC to terminal instead of Qt Creator")); @@ -157,14 +158,11 @@ TerminalPane::TerminalPane(QObject *parent) connect(&TerminalSettings::instance(), &TerminalSettings::applied, this, updateEscButton); } -TerminalPane::~TerminalPane() -{ - delete m_tabWidget; -} +TerminalPane::~TerminalPane() {} static std::optional startupProjectDirectory() { - ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); + const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) return std::nullopt; @@ -187,11 +185,11 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) } } - auto terminalWidget = new TerminalWidget(m_tabWidget, parametersCopy); - m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal"))); + const auto terminalWidget = new TerminalWidget(&m_tabWidget, parametersCopy); + m_tabWidget.setCurrentIndex(m_tabWidget.addTab(terminalWidget, Tr::tr("Terminal"))); setupTerminalWidget(terminalWidget); - m_tabWidget->currentWidget()->setFocus(); + m_tabWidget.currentWidget()->setFocus(); emit navigateStateUpdate(); } @@ -200,7 +198,7 @@ void TerminalPane::addTerminal(TerminalWidget *terminal, const QString &title) { if (!m_isVisible) emit showPage(IOutputPane::ModeSwitch); - m_tabWidget->setCurrentIndex(m_tabWidget->addTab(terminal, title)); + m_tabWidget.setCurrentIndex(m_tabWidget.addTab(terminal, title)); setupTerminalWidget(terminal); emit navigateStateUpdate(); @@ -210,17 +208,16 @@ void TerminalPane::ensureVisible(TerminalWidget *terminal) { if (!m_isVisible) emit showPage(IOutputPane::ModeSwitch); - m_tabWidget->setCurrentWidget(terminal); + m_tabWidget.setCurrentWidget(terminal); terminal->setFocus(); } -TerminalWidget *TerminalPane::stoppedTerminalWithId(const Id &identifier) const +TerminalWidget *TerminalPane::stoppedTerminalWithId(Id identifier) const { - QTC_ASSERT(m_tabWidget, return nullptr); - - for (int i = 0; i < m_tabWidget->count(); ++i) { - auto terminal = qobject_cast(m_tabWidget->widget(i)); - if (terminal->processState() == QProcess::NotRunning && terminal->identifier() == identifier) + for (int i = 0; i < m_tabWidget.count(); ++i) { + const auto terminal = qobject_cast(m_tabWidget.widget(i)); + if (terminal && terminal->processState() == QProcess::NotRunning + && terminal->identifier() == identifier) return terminal; } @@ -231,39 +228,38 @@ QWidget *TerminalPane::outputWidget(QWidget *parent) { if (!m_widgetInitialized) { m_widgetInitialized = true; - m_tabWidget->setTabBarAutoHide(false); - m_tabWidget->setDocumentMode(true); - m_tabWidget->setTabsClosable(true); - m_tabWidget->setMovable(true); + m_tabWidget.setTabBarAutoHide(false); + m_tabWidget.setDocumentMode(true); + m_tabWidget.setTabsClosable(true); + m_tabWidget.setMovable(true); - connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int index) { + connect(&m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int index) { removeTab(index); }); - connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int index) { - if (auto widget = m_tabWidget->widget(index)) + connect(&m_tabWidget, &QTabWidget::currentChanged, this, [this](int index) { + if (auto widget = m_tabWidget.widget(index)) widget->setFocus(); else emit hidePage(); }); - auto terminalWidget = new TerminalWidget(parent); - m_tabWidget->addTab(terminalWidget, Tr::tr("Terminal")); + const auto terminalWidget = new TerminalWidget(parent); + m_tabWidget.addTab(terminalWidget, Tr::tr("Terminal")); setupTerminalWidget(terminalWidget); } - return m_tabWidget; + return &m_tabWidget; } TerminalWidget *TerminalPane::currentTerminal() const { - QWidget *activeWidget = m_tabWidget->currentWidget(); - return static_cast(activeWidget); + return static_cast(m_tabWidget.currentWidget()); } void TerminalPane::removeTab(int index) { - delete m_tabWidget->widget(index); + delete m_tabWidget.widget(index); emit navigateStateUpdate(); } @@ -272,8 +268,8 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) if (!terminal) return; - auto setTabText = [this](TerminalWidget *terminal) { - auto index = m_tabWidget->indexOf(terminal); + const auto setTabText = [this, terminal]() { + const int index = m_tabWidget.indexOf(terminal); const FilePath cwd = terminal->cwd(); const QString exe = terminal->currentCommand().isEmpty() @@ -281,25 +277,17 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) : terminal->currentCommand().executable().fileName(); if (cwd.isEmpty()) - m_tabWidget->setTabText(index, exe); + m_tabWidget.setTabText(index, exe); else - m_tabWidget->setTabText(index, exe + " - " + cwd.fileName()); + m_tabWidget.setTabText(index, exe + " - " + cwd.fileName()); }; - connect(terminal, &TerminalWidget::started, this, [setTabText, terminal](qint64 /*pid*/) { - setTabText(terminal); - }); - - connect(terminal, &TerminalWidget::cwdChanged, this, [setTabText, terminal]() { - setTabText(terminal); - }); - - connect(terminal, &TerminalWidget::commandChanged, this, [setTabText, terminal]() { - setTabText(terminal); - }); + connect(terminal, &TerminalWidget::started, this, setTabText); + connect(terminal, &TerminalWidget::cwdChanged, this, setTabText); + connect(terminal, &TerminalWidget::commandChanged, this, setTabText); if (!terminal->shellName().isEmpty()) - setTabText(terminal); + setTabText(); } QList TerminalPane::toolBarWidgets() const @@ -334,7 +322,7 @@ void TerminalPane::visibilityChanged(bool visible) m_isVisible = visible; - if (visible && m_tabWidget && m_tabWidget->count() == 0) + if (visible && m_tabWidget.count() == 0) openTerminal({}); IOutputPane::visibilityChanged(visible); @@ -366,31 +354,31 @@ bool TerminalPane::canNavigate() const bool TerminalPane::canNext() const { - return m_tabWidget->count() > 1; + return m_tabWidget.count() > 1; } bool TerminalPane::canPrevious() const { - return m_tabWidget->count() > 1; + return m_tabWidget.count() > 1; } void TerminalPane::goToNext() { - int nextIndex = m_tabWidget->currentIndex() + 1; - if (nextIndex >= m_tabWidget->count()) + int nextIndex = m_tabWidget.currentIndex() + 1; + if (nextIndex >= m_tabWidget.count()) nextIndex = 0; - m_tabWidget->setCurrentIndex(nextIndex); + m_tabWidget.setCurrentIndex(nextIndex); emit navigateStateUpdate(); } void TerminalPane::goToPrev() { - int prevIndex = m_tabWidget->currentIndex() - 1; + int prevIndex = m_tabWidget.currentIndex() - 1; if (prevIndex < 0) - prevIndex = m_tabWidget->count() - 1; + prevIndex = m_tabWidget.count() - 1; - m_tabWidget->setCurrentIndex(prevIndex); + m_tabWidget.setCurrentIndex(prevIndex); emit navigateStateUpdate(); } diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 28c59b523d7..6ef2d005357 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -40,7 +40,7 @@ public: void openTerminal(const Utils::Terminal::OpenTerminalParameters ¶meters); void addTerminal(TerminalWidget *terminal, const QString &title); - TerminalWidget *stoppedTerminalWithId(const Utils::Id &identifier) const; + TerminalWidget *stoppedTerminalWithId(Utils::Id identifier) const; void ensureVisible(TerminalWidget *terminal); @@ -51,7 +51,7 @@ private: void setupTerminalWidget(TerminalWidget *terminal); private: - QTabWidget *m_tabWidget{nullptr}; + QTabWidget m_tabWidget; QToolButton *m_newTerminalButton{nullptr}; QToolButton *m_closeTerminalButton{nullptr}; From cd267ca4bfa2255344ebd856d54d4cfff2b790de Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 23 May 2023 10:57:47 +0200 Subject: [PATCH 1188/1447] Tests: Fix build before Qt 6.4.3 Change-Id: I6859b6c2a42f44e5bc24f569290869008f60d1b2 Reviewed-by: Qt CI Bot Reviewed-by: Cristian Adam --- tests/unit/tools/CMakeLists.txt | 4 +++- tests/unit/unittest/qmlprojectmanager/CMakeLists.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/tools/CMakeLists.txt b/tests/unit/tools/CMakeLists.txt index 05b561491fc..123825fe81b 100644 --- a/tests/unit/tools/CMakeLists.txt +++ b/tests/unit/tools/CMakeLists.txt @@ -1 +1,3 @@ -add_subdirectory(qmlprojectmanager) +if (Qt6_Version VERSION_GREATER_EQUAL "6.4.3") + add_subdirectory(qmlprojectmanager) +endif () diff --git a/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt index 9b5037fc527..e5c8ad5da3b 100644 --- a/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt +++ b/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt @@ -1,4 +1,5 @@ extend_qtc_test(unittest + CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.4.3 DEPENDS QmlProjectManagerLib SOURCES From cdf1926215bd2fe4d5caf4653fb43e3175436984 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 15:19:44 +0200 Subject: [PATCH 1189/1447] Valgrind: Use FilePathAspect for main executable Change-Id: I0bdb625b47d0f39b577684b6f407b9e8a6086d1f Reviewed-by: David Schulz --- src/plugins/valgrind/valgrindengine.cpp | 2 +- src/plugins/valgrind/valgrindsettings.cpp | 1 - src/plugins/valgrind/valgrindsettings.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 462d1b1a735..3059169786b 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -53,7 +53,7 @@ ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) void ValgrindToolRunner::start() { - FilePath valgrindExecutable = m_settings.valgrindExecutable.filePath(); + FilePath valgrindExecutable = m_settings.valgrindExecutable(); if (IDevice::ConstPtr dev = DeviceKitAspect::device(runControl()->kit())) valgrindExecutable = dev->filePath(valgrindExecutable.path()); if (!valgrindExecutable.isExecutableFile()) { diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index bdcf9971e6f..fd15b04299b 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -207,7 +207,6 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) registerAspect(&valgrindExecutable); valgrindExecutable.setSettingsKey(base + "ValgrindExecutable"); valgrindExecutable.setDefaultValue("valgrind"); - valgrindExecutable.setDisplayStyle(StringAspect::PathChooserDisplay); valgrindExecutable.setExpectedKind(PathChooser::Command); valgrindExecutable.setHistoryCompleter("Valgrind.Command.History"); valgrindExecutable.setDisplayName(Tr::tr("Valgrind Command")); diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h index a8359804ddc..4752482e48e 100644 --- a/src/plugins/valgrind/valgrindsettings.h +++ b/src/plugins/valgrind/valgrindsettings.h @@ -68,7 +68,7 @@ signals: * Base valgrind settings */ public: - Utils::StringAspect valgrindExecutable; + Utils::FilePathAspect valgrindExecutable; Utils::StringAspect valgrindArguments; Utils::SelectionAspect selfModifyingCodeDetection; From 27a63b0930b03f4531ecf8c07d5b423f450de6b6 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 16:13:29 +0200 Subject: [PATCH 1190/1447] Valgrind: Also search in path before chickening out Amends db2b09f4eb. Change-Id: I1134fe2bc9441c12924332bb2666f108eb2f0d32 Reviewed-by: David Schulz --- src/plugins/valgrind/valgrindengine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 3059169786b..2d4ab6aadca 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -56,7 +56,10 @@ void ValgrindToolRunner::start() FilePath valgrindExecutable = m_settings.valgrindExecutable(); if (IDevice::ConstPtr dev = DeviceKitAspect::device(runControl()->kit())) valgrindExecutable = dev->filePath(valgrindExecutable.path()); - if (!valgrindExecutable.isExecutableFile()) { + + const FilePath found = valgrindExecutable.searchInPath(); + + if (!found.isExecutableFile()) { reportFailure(Tr::tr("Valgrind executable \"%1\" not found or not executable.\n" "Check settings or ensure valgrind is installed and available in PATH.") .arg(valgrindExecutable.toUserOutput())); From ae26fa0dd736768477f00731dc2a66ca1d0d9b59 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 09:14:23 +0200 Subject: [PATCH 1191/1447] Utils: Add a FilePath::searchAllInDirectories A variation that does not stop on the first found item. Useful for auto-detection scenarios. Use "WithAnySuffix" as default to cover .cmd and .bat etc. Change-Id: I48f36eff06699c046e34c8e2646546bcff20ae8b Reviewed-by: Marcus Tillmanns --- src/libs/utils/filepath.cpp | 74 +++++++++++++++++++++++++++++++++---- src/libs/utils/filepath.h | 11 +++++- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index fa91a09d054..2df57830343 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1538,25 +1538,83 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs, return {}; } -FilePath FilePath::searchInPath(const FilePaths &additionalDirs, - PathAmending amending, - const FilePathPredicate &filter, - const MatchScope &matchScope) const +FilePaths FilePath::searchAllInDirectories(const FilePaths &dirs, + const FilePathPredicate &filter, + const MatchScope &matchScope) const { - if (isAbsolutePath()) - return *this; + if (isEmpty()) + return {}; - FilePaths directories = devicePathEnvironmentVariable(); + const FilePaths execs = appendExeExtensions(*this, matchScope); + + FilePaths result; + if (isAbsolutePath()) { + for (const FilePath &filePath : execs) { + if (filePath.isExecutableFile() && (!filter || filter(filePath))) + result.append(filePath); + } + return result; + } + + QSet alreadyCheckedDirectories; + + for (const FilePath &dir : dirs) { + // Compare the initial size of the set with the size after insertion to check + // if the directory was already checked. + const int initialCount = alreadyCheckedDirectories.count(); + alreadyCheckedDirectories.insert(dir); + const bool wasAlreadyChecked = alreadyCheckedDirectories.count() == initialCount; + + if (dir.isEmpty() || wasAlreadyChecked) + continue; + + for (const FilePath &exe : execs) { + const FilePath filePath = dir / exe.path(); + if (filePath.isExecutableFile() && (!filter || filter(filePath))) + result.append(filePath); + } + } + + return result; +} + +static FilePaths dirsFromPath(const FilePath &anchor, + const FilePaths &additionalDirs, + FilePath::PathAmending amending) +{ + FilePaths directories = anchor.devicePathEnvironmentVariable(); if (!additionalDirs.isEmpty()) { - if (amending == AppendToPath) + if (amending == FilePath::AppendToPath) directories.append(additionalDirs); else directories = additionalDirs + directories; } + + return directories; +} + +FilePath FilePath::searchInPath(const FilePaths &additionalDirs, + PathAmending amending, + const FilePathPredicate &filter, + MatchScope matchScope) const +{ + if (isAbsolutePath()) + return *this; + + const FilePaths directories = dirsFromPath(*this, additionalDirs, amending); return searchInDirectories(directories, filter, matchScope); } +FilePaths FilePath::searchAllInPath(const FilePaths &additionalDirs, + PathAmending amending, + const FilePathPredicate &filter, + MatchScope matchScope) const +{ + const FilePaths directories = dirsFromPath(*this, additionalDirs, amending); + return searchAllInDirectories(directories, filter, matchScope); +} + Environment FilePath::deviceEnvironment() const { if (needsDevice()) { diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 2a41c6c615b..4462b473cdd 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -187,11 +187,18 @@ public: [[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter = {}, - const MatchScope &matchScope = {}) const; + const MatchScope &matchScope = WithAnySuffix) const; + [[nodiscard]] FilePaths searchAllInDirectories(const FilePaths &dirs, + const FilePathPredicate &filter = {}, + const MatchScope &matchScope = WithAnySuffix) const; [[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {}, PathAmending = AppendToPath, const FilePathPredicate &filter = {}, - const MatchScope &matchScope = {}) const; + MatchScope matchScope = WithAnySuffix) const; + [[nodiscard]] FilePaths searchAllInPath(const FilePaths &additionalDirs = {}, + PathAmending = AppendToPath, + const FilePathPredicate &filter = {}, + MatchScope matchScope = WithAnySuffix) const; std::optional refersToExecutableFile(MatchScope considerScript) const; From b6a1935562360adf4b29bd17907a008497c702b7 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 11:18:26 +0200 Subject: [PATCH 1192/1447] Doc: Fix qdoc warning caused by a changed argument name Change-Id: Id2f28994f6cd1829bfc4bdc23c87aabe40f44f2c Reviewed-by: hjk --- src/libs/utils/layoutbuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index 017a147897e..b603b0bf8ff 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -549,7 +549,7 @@ void LayoutItem::addItems(const LayoutItems &items) } /*! - Attach the constructed layout to the provided \c QWidget \a parent. + Attaches the constructed layout to the provided QWidget \a w. This operation can only be performed once per LayoutBuilder instance. */ From f952fe30e78148e45c12ba74285c9400daece5fd Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 14:37:19 +0200 Subject: [PATCH 1193/1447] Conan: CPaster: Use FilePathAspect Change-Id: I982ae4115af818cc25c46acc84713e7432b18548 Reviewed-by: Christian Stenger --- src/plugins/conan/conaninstallstep.cpp | 3 +-- src/plugins/cpaster/fileshareprotocolsettingspage.cpp | 1 - src/plugins/cpaster/fileshareprotocolsettingspage.h | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/conan/conaninstallstep.cpp b/src/plugins/conan/conaninstallstep.cpp index fbc5999192d..cae573845e8 100644 --- a/src/plugins/conan/conaninstallstep.cpp +++ b/src/plugins/conan/conaninstallstep.cpp @@ -70,13 +70,12 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id) setUseEnglishOutput(); setDisplayName(Tr::tr("Conan install")); - auto conanFile = addAspect(); + auto conanFile = addAspect(); conanFile->setSettingsKey("ConanPackageManager.InstallStep.ConanFile"); conanFile->setFilePath(conanFilePath(project(), project()->projectDirectory() / "conanfile.txt")); conanFile->setLabelText(Tr::tr("Conan file:")); conanFile->setToolTip(Tr::tr("Enter location of conanfile.txt or conanfile.py.")); - conanFile->setDisplayStyle(StringAspect::PathChooserDisplay); conanFile->setExpectedKind(PathChooser::File); auto additionalArguments = addAspect(); diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp index dd12a68e73d..04b896fa76f 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp @@ -22,7 +22,6 @@ FileShareProtocolSettings::FileShareProtocolSettings() registerAspect(&path); path.setSettingsKey("Path"); - path.setDisplayStyle(StringAspect::PathChooserDisplay); path.setExpectedKind(PathChooser::ExistingDirectory); path.setDefaultValue(TemporaryDirectory::masterDirectoryPath()); path.setLabelText(Tr::tr("&Path:")); diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.h b/src/plugins/cpaster/fileshareprotocolsettingspage.h index 36a06c2106b..56c843007de 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.h +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.h @@ -12,7 +12,7 @@ class FileShareProtocolSettings : public Core::PagedSettings public: FileShareProtocolSettings(); - Utils::StringAspect path; + Utils::FilePathAspect path; Utils::IntegerAspect displayCount; }; From a0f64b133d3b1443a1e2638fa30c05b5b47e46b0 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 14:09:48 +0200 Subject: [PATCH 1194/1447] Doc: Fix qdoc warnings in aspects docs Add \a commands and mark things \internal if qdoc cannot find them. Change-Id: If7a9303e5053af4eb58a08caafd53ffa6ee604b5 Reviewed-by: hjk --- src/libs/utils/aspects.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 59c0ee3f8b3..54eba86eaf1 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -90,7 +90,9 @@ public: */ /*! - Constructs a BaseAspect. + Constructs a base aspect. + + If \a container is non-null, the aspect is made known to the container. */ BaseAspect::BaseAspect(AspectContainer *container) : d(new Internal::BaseAspectPrivate) @@ -124,9 +126,9 @@ QVariant BaseAspect::value() const } /*! - Sets value. + Sets \a value. - Emits changed() if the value changed. + Emits \c changed() if the value changed. */ void BaseAspect::setValue(const QVariant &value) { @@ -137,7 +139,7 @@ void BaseAspect::setValue(const QVariant &value) } /*! - Sets value without emitting changed() + Sets \a value without emitting \c changed(). Returns whether the value changed. */ @@ -155,7 +157,7 @@ QVariant BaseAspect::defaultValue() const } /*! - Sets a default value and the current value for this aspect. + Sets a default \a value and the current value for this aspect. \note The current value will be set silently to the same value. It is reasonable to only set default values in the setup phase @@ -339,7 +341,7 @@ bool BaseAspect::isAutoApply() const } /*! - Sets auto-apply mode. When auto-apply mode is on, user interaction to this + Sets auto-apply mode. When auto-apply mode is \a on, user interaction to this aspect's widget will not modify the \c value of the aspect until \c apply() is called programmatically. @@ -370,7 +372,7 @@ QString BaseAspect::settingsKey() const } /*! - Sets the key to be used when accessing the settings. + Sets the \a key to be used when accessing the settings. \sa settingsKey() */ @@ -380,7 +382,7 @@ void BaseAspect::setSettingsKey(const QString &key) } /*! - Sets the key and group to be used when accessing the settings. + Sets the \a key and \a group to be used when accessing the settings. \sa settingsKey() */ @@ -419,8 +421,8 @@ QAction *BaseAspect::action() } /*! - Adds the visual representation of this aspect to a layout using - a layout builder. + Adds the visual representation of this aspect to the layout with the + specified \a parent using a layout builder. */ void BaseAspect::addToLayout(LayoutItem &) { @@ -528,7 +530,7 @@ void BaseAspect::saveToMap(QVariantMap &data, const QVariant &value, } /*! - Retrieves the internal value of this BaseAspect from a \c QVariantMap. + Retrieves the internal value of this BaseAspect from the QVariantMap \a map. */ void BaseAspect::fromMap(const QVariantMap &map) { @@ -537,7 +539,7 @@ void BaseAspect::fromMap(const QVariantMap &map) } /*! - Stores the internal value of this BaseAspect into a \c QVariantMap. + Stores the internal value of this BaseAspect into the QVariantMap \a map. */ void BaseAspect::toMap(QVariantMap &map) const { @@ -765,7 +767,7 @@ public: */ /*! - Constructs a StringAspect. + Constructs the string aspect \a container. */ StringAspect::StringAspect(AspectContainer *container) @@ -800,7 +802,7 @@ QString StringAspect::value() const } /*! - Sets the \a value of this StringAspect from an ordinary \c QString. + Sets the value, \a val, of this StringAspect from an ordinary \c QString. */ void StringAspect::setValue(const QString &val) { @@ -2149,7 +2151,7 @@ void DoubleAspect::setSingleStep(double step) /*! - \class Utils::BaseTristateAspect + \class Utils::TriStateAspect \inmodule QtCreator \brief A tristate aspect is a property of some object that can have @@ -2273,6 +2275,7 @@ void StringListAspect::removeValues(const QStringList &values) /*! \class Utils::IntegerListAspect + \internal \inmodule QtCreator \brief A string list aspect represents a property of some object From 3ecaabf5e9312e15d5ab4806c0197beb8a9f49fc Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 14:33:39 +0200 Subject: [PATCH 1195/1447] CMake: Use a FilePathAsepect for the staging directory Change-Id: Id4ac0cdaa3a773f740f474e78a7af104996a5504 Reviewed-by: Cristian Adam --- src/plugins/cmakeprojectmanager/cmakebuildstep.cpp | 3 +-- src/plugins/cmakeprojectmanager/cmakebuildstep.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 885cdea9f8f..e916a5a8341 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -197,10 +197,9 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) : m_useStaging->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); m_useStaging->setDefaultValue(!buildAndRunOnSameDevice(kit())); - m_stagingDir = addAspect(); + m_stagingDir = addAspect(); m_stagingDir->setSettingsKey(STAGING_DIR_KEY); m_stagingDir->setLabelText(Tr::tr("Staging directory:")); - m_stagingDir->setDisplayStyle(StringAspect::PathChooserDisplay); m_stagingDir->setDefaultValue(initialStagingDir()); Kit *kit = buildConfiguration()->kit(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.h b/src/plugins/cmakeprojectmanager/cmakebuildstep.h index 973b00e8f37..85ee46d953b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.h @@ -108,7 +108,7 @@ private: Utils::StringAspect *m_toolArguments = nullptr; Utils::BoolAspect *m_useiOSAutomaticProvisioningUpdates = nullptr; Utils::BoolAspect *m_useStaging = nullptr; - Utils::StringAspect *m_stagingDir = nullptr; + Utils::FilePathAspect *m_stagingDir = nullptr; QString m_allTarget = "all"; QString m_installTarget = "install"; From f248638a107fb4ef688b7e167e7a246a9826bffa Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 23 May 2023 10:48:24 +0200 Subject: [PATCH 1196/1447] Re-enable test Amends 590a6904b10ddd3538733c927b7a2a1b49c7e8a2. Change-Id: I7ead3d44bf87d7eb22ebd18dadc9b2eb361850fd Reviewed-by: Christian Kandeler --- tests/auto/qml/qml.qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qml/qml.qbs b/tests/auto/qml/qml.qbs index 9f887bfcacd..76659a5256b 100644 --- a/tests/auto/qml/qml.qbs +++ b/tests/auto/qml/qml.qbs @@ -7,7 +7,7 @@ Project { // "qmldesigner/qmldesigner.qbs", "qmleditor/qmleditor.qbs", "qmljssimplereader/qmljssimplereader.qbs", -// "qmlprojectmanager/qmlprojectmanager.qbs", + "qmlprojectmanager/qmlprojectmanager.qbs", "qrcparser/qrcparser.qbs", "reformatter/reformatter.qbs", "persistenttrie/persistenttrie.qbs" From 79dd2a8c8b4e7e453eeb040973c2be2bfac678fc Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 09:22:15 +0200 Subject: [PATCH 1197/1447] CMake: Use new FilePath::searchAllInDirectories function Change-Id: Idd696603548d7504ff87152e9125667dca4c42ab Reviewed-by: Cristian Adam --- .../cmaketoolsettingsaccessor.cpp | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp index 3b1c2e4546e..05969b492e2 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp @@ -45,36 +45,26 @@ const char CMAKE_TOOL_FILENAME[] = "cmaketools.xml"; static std::vector> autoDetectCMakeTools() { - Environment env = Environment::systemEnvironment(); - - FilePaths path = env.path(); - path = Utils::filteredUnique(path); + FilePaths extraDirs; if (HostOsInfo::isWindowsHost()) { for (const auto &envVar : QStringList{"ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"}) { if (qtcEnvironmentVariableIsSet(envVar)) { const QString progFiles = qtcEnvironmentVariable(envVar); - path.append(FilePath::fromUserInput(progFiles + "/CMake")); - path.append(FilePath::fromUserInput(progFiles + "/CMake/bin")); + extraDirs.append(FilePath::fromUserInput(progFiles + "/CMake")); + extraDirs.append(FilePath::fromUserInput(progFiles + "/CMake/bin")); } } } if (HostOsInfo::isMacHost()) { - path.append("/Applications/CMake.app/Contents/bin"); - path.append("/usr/local/bin"); // homebrew intel - path.append("/opt/homebrew/bin"); // homebrew arm - path.append("/opt/local/bin"); // macports + extraDirs.append("/Applications/CMake.app/Contents/bin"); + extraDirs.append("/usr/local/bin"); // homebrew intel + extraDirs.append("/opt/homebrew/bin"); // homebrew arm + extraDirs.append("/opt/local/bin"); // macports } - FilePaths suspects; - for (const FilePath &base : std::as_const(path)) { - if (base.isEmpty()) - continue; - const FilePath suspect = base / "cmake"; - if (std::optional foundExe = suspect.refersToExecutableFile(FilePath::WithAnySuffix)) - suspects << *foundExe; - } + const FilePaths suspects = FilePath("cmake").searchAllInPath(extraDirs); std::vector> found; for (const FilePath &command : std::as_const(suspects)) { From b41f7e87ae3ae0a18d9c8b411f2c3eb59108a519 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 13:30:11 +0200 Subject: [PATCH 1198/1447] ProjectExplorer: Make ProjectConfiguration an AspectContainer ... instead of having one. AspectContainer are de-factor (q)objects with "fat" properties, conceptionally not much different from QObject itself, so there's not real need to differentiate between the QObject interface and the (forwarded) aspectcontainer interface. As a side-effect, this saves one QObject base object per instance. Change-Id: I6eefe739b3aebcef1ece196ff8d70aa36738997b Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/buildstep.cpp | 4 ++-- .../projectexplorer/projectconfiguration.cpp | 13 ++++--------- .../projectexplorer/projectconfiguration.h | 16 +--------------- src/plugins/projectexplorer/runconfiguration.cpp | 8 ++++---- src/plugins/projectexplorer/runconfiguration.h | 1 + 5 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 46283b4c9fa..32be37048e9 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -147,7 +147,7 @@ QWidget *BuildStep::doCreateConfigWidget() setSummaryText(m_summaryUpdater()); }; - for (BaseAspect *aspect : std::as_const(m_aspects)) + for (BaseAspect *aspect : std::as_const(*this)) connect(aspect, &BaseAspect::changed, widget, recreateSummary); connect(buildConfiguration(), &BuildConfiguration::buildDirectoryChanged, @@ -161,7 +161,7 @@ QWidget *BuildStep::doCreateConfigWidget() QWidget *BuildStep::createConfigWidget() { Layouting::Form form; - for (BaseAspect *aspect : std::as_const(m_aspects)) { + for (BaseAspect *aspect : std::as_const(*this)) { if (aspect->isVisible()) form.addItem(aspect); } diff --git a/src/plugins/projectexplorer/projectconfiguration.cpp b/src/plugins/projectexplorer/projectconfiguration.cpp index 6d5fa797a67..5d23d65c8b8 100644 --- a/src/plugins/projectexplorer/projectconfiguration.cpp +++ b/src/plugins/projectexplorer/projectconfiguration.cpp @@ -19,10 +19,10 @@ const char DISPLAY_NAME_KEY[] = "ProjectExplorer.ProjectConfiguration.DisplayNam // ProjectConfiguration ProjectConfiguration::ProjectConfiguration(QObject *parent, Utils::Id id) - : QObject(parent) + : AspectContainer(parent) , m_id(id) { - m_aspects.setOwnsSubAspects(true); + setOwnsSubAspects(true); QTC_CHECK(parent); QTC_CHECK(id.isValid()); @@ -89,7 +89,7 @@ QVariantMap ProjectConfiguration::toMap() const QVariantMap map; map.insert(QLatin1String(CONFIGURATION_ID_KEY), m_id.toSetting()); m_displayName.toMap(map, DISPLAY_NAME_KEY); - m_aspects.toMap(map); + AspectContainer::toMap(map); return map; } @@ -106,15 +106,10 @@ bool ProjectConfiguration::fromMap(const QVariantMap &map) QTC_ASSERT(id.toString().startsWith(m_id.toString()), return false); m_displayName.fromMap(map, DISPLAY_NAME_KEY); - m_aspects.fromMap(map); + AspectContainer::fromMap(map); return true; } -BaseAspect *ProjectConfiguration::aspect(Id id) const -{ - return m_aspects.aspect(id); -} - FilePath ProjectConfiguration::mapFromBuildDeviceToGlobalPath(const FilePath &path) const { IDevice::ConstPtr dev = BuildDeviceKitAspect::device(kit()); diff --git a/src/plugins/projectexplorer/projectconfiguration.h b/src/plugins/projectexplorer/projectconfiguration.h index cb716bf66e5..8c5dac1d902 100644 --- a/src/plugins/projectexplorer/projectconfiguration.h +++ b/src/plugins/projectexplorer/projectconfiguration.h @@ -21,7 +21,7 @@ class Kit; class Project; class Target; -class PROJECTEXPLORER_EXPORT ProjectConfiguration : public QObject +class PROJECTEXPLORER_EXPORT ProjectConfiguration : public Utils::AspectContainer { Q_OBJECT @@ -54,26 +54,12 @@ public: static QString settingsIdKey(); - template - Aspect *addAspect(Args && ...args) - { - return m_aspects.addAspect(std::forward(args)...); - } - - const Utils::AspectContainer &aspects() const { return m_aspects; } - - Utils::BaseAspect *aspect(Utils::Id id) const; - template T *aspect() const { return m_aspects.aspect(); } - Utils::FilePath mapFromBuildDeviceToGlobalPath(const Utils::FilePath &path) const; signals: void displayNameChanged(); void toolTipChanged(); -protected: - Utils::AspectContainer m_aspects; - private: QPointer m_target; const Utils::Id m_id; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index d05c23eaf51..29b59ad8984 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -217,7 +217,7 @@ bool RunConfiguration::isEnabled() const QWidget *RunConfiguration::createConfigurationWidget() { Layouting::Form form; - for (BaseAspect *aspect : std::as_const(m_aspects)) { + for (BaseAspect *aspect : std::as_const(*this)) { if (aspect->isVisible()) { form.addItem(aspect); form.addItem(Layouting::br); @@ -247,7 +247,7 @@ void RunConfiguration::addAspectFactory(const AspectFactory &aspectFactory) QMap RunConfiguration::settingsData() const { QMap data; - for (BaseAspect *aspect : m_aspects) + for (BaseAspect *aspect : *this) aspect->toActiveMap(data[aspect->id()]); return data; } @@ -255,7 +255,7 @@ QMap RunConfiguration::settingsData() const AspectContainerData RunConfiguration::aspectData() const { AspectContainerData data; - for (BaseAspect *aspect : m_aspects) + for (BaseAspect *aspect : *this) data.append(aspect->extractData()); return data; } @@ -566,7 +566,7 @@ RunConfiguration *RunConfigurationFactory::create(Target *target) const // Add the universal aspects. for (const RunConfiguration::AspectFactory &factory : theAspectFactories) - rc->m_aspects.registerAspect(factory(target)); + rc->registerAspect(factory(target)); return rc; } diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index a0d83ebb488..59704141562 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -138,6 +138,7 @@ public: return nullptr; } + using ProjectConfiguration::registerAspect; using AspectFactory = std::function; template static void registerAspect() { From 2726f7716f0e419ac75cb18e4ab5d7a5298be62e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 22 May 2023 14:56:33 +0200 Subject: [PATCH 1199/1447] Move function to show session manager to SessionManager Change-Id: Ibcaae8c4fb68fe6b43759c11b77bfaab73d41745 Reviewed-by: hjk Reviewed-by: --- .../projectexplorer/projectexplorer.cpp | 35 ++++++------------- src/plugins/projectexplorer/projectexplorer.h | 1 - .../projectexplorer/projectwelcomepage.cpp | 2 +- .../projectexplorer/projectwelcomepage.h | 1 - src/plugins/projectexplorer/session.cpp | 12 +++++++ src/plugins/projectexplorer/session.h | 2 ++ 6 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index d1ad20fe57c..d6379488fa9 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -454,7 +454,6 @@ public: void unloadProjectContextMenu(); void unloadOtherProjectsContextMenu(); void closeAllProjects(); - void showSessionManager(); void updateSessionMenu(); void setSession(QAction *action); @@ -815,9 +814,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er IWizardFactory::registerFeatureProvider(new KitFeatureProvider); IWizardFactory::registerFactoryCreator([] { return new SimpleProjectWizard; }); - connect(&dd->m_welcomePage, &ProjectWelcomePage::manageSessions, - dd, &ProjectExplorerPluginPrivate::showSessionManager); - ProjectManager *sessionManager = &dd->m_sessionManager; connect(sessionManager, &ProjectManager::projectAdded, this, &ProjectExplorerPlugin::fileListChanged); @@ -839,6 +835,12 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd, &ProjectExplorerPluginPrivate::updateWelcomePage); connect(SessionManager::instance(), &SessionManager::sessionLoaded, dd, &ProjectExplorerPluginPrivate::loadSesssionTasks); + connect(SessionManager::instance(), &SessionManager::sessionCreated, + dd, &ProjectExplorerPluginPrivate::updateWelcomePage); + connect(SessionManager::instance(), &SessionManager::sessionRenamed, + dd, &ProjectExplorerPluginPrivate::updateWelcomePage); + connect(SessionManager::instance(), &SessionManager::sessionRemoved, + dd, &ProjectExplorerPluginPrivate::updateWelcomePage); ProjectTree *tree = &dd->m_projectTree; connect(tree, &ProjectTree::currentProjectChanged, dd, [] { @@ -1728,8 +1730,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(buildManager, &BuildManager::buildQueueFinished, dd, &ProjectExplorerPluginPrivate::buildQueueFinished, Qt::QueuedConnection); - connect(dd->m_sessionManagerAction, &QAction::triggered, - dd, &ProjectExplorerPluginPrivate::showSessionManager); + connect(dd->m_sessionManagerAction, + &QAction::triggered, + SessionManager::instance(), + &SessionManager::showSessionManager); connect(dd->m_newAction, &QAction::triggered, dd, &ProjectExplorerPlugin::openNewProjectDialog); connect(dd->m_loadAction, &QAction::triggered, @@ -2192,11 +2196,6 @@ IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown() return AsynchronousShutdown; } -void ProjectExplorerPlugin::showSessionManager() -{ - dd->showSessionManager(); -} - void ProjectExplorerPlugin::openNewProjectDialog() { if (!ICore::isNewItemDialogRunning()) { @@ -2208,20 +2207,6 @@ void ProjectExplorerPlugin::openNewProjectDialog() } } -void ProjectExplorerPluginPrivate::showSessionManager() -{ - SessionManager::saveSession(); - SessionDialog sessionDialog(ICore::dialogParent()); - sessionDialog.setAutoLoadSession(sb_d->isAutoRestoreLastSession()); - sessionDialog.exec(); - sb_d->setAutoRestoreLastSession(sessionDialog.autoLoadSession()); - - updateActions(); - - if (ModeManager::currentModeId() == Core::Constants::MODE_WELCOME) - updateWelcomePage(); -} - void ProjectExplorerPluginPrivate::setStartupProject(Project *project) { if (!project) diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index e5f91bd334d..0b87f53310b 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -155,7 +155,6 @@ public: static QThreadPool *sharedThreadPool(); static Internal::MiniProjectTargetSelector *targetSelector(); - static void showSessionManager(); static void openNewProjectDialog(); static void openOpenProjectDialog(); diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 5b392ea7a15..d3f5733461b 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -580,7 +580,7 @@ public: auto manageSessionsButton = new WelcomePageButton(this); manageSessionsButton->setText(Tr::tr("Manage...")); manageSessionsButton->setWithAccentColor(true); - manageSessionsButton->setOnClicked([] { ProjectExplorerPlugin::showSessionManager(); }); + manageSessionsButton->setOnClicked([] { SessionManager::showSessionManager(); }); auto sessionsLabel = new QLabel(this); sessionsLabel->setFont(brandFont()); diff --git a/src/plugins/projectexplorer/projectwelcomepage.h b/src/plugins/projectexplorer/projectwelcomepage.h index a9c81459635..2585ef09d54 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.h +++ b/src/plugins/projectexplorer/projectwelcomepage.h @@ -56,7 +56,6 @@ public slots: signals: void requestProject(const Utils::FilePath &project); - void manageSessions(); private: void openSessionAt(int index); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index ccedbb885fe..9933ff070fa 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -4,6 +4,7 @@ #include "session.h" #include "session_p.h" +#include "sessiondialog.h" #include "projectexplorer.h" #include "projectexplorertr.h" @@ -204,6 +205,7 @@ bool SessionManager::createSession(const QString &session) Q_ASSERT(sb_d->m_sessions.size() > 0); sb_d->m_sessions.insert(1, session); sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); + emit instance()->sessionCreated(session); return true; } @@ -217,6 +219,14 @@ bool SessionManager::renameSession(const QString &original, const QString &newNa return deleteSession(original); } +void SessionManager::showSessionManager() +{ + saveSession(); + Internal::SessionDialog sessionDialog(ICore::dialogParent()); + sessionDialog.setAutoLoadSession(sb_d->isAutoRestoreLastSession()); + sessionDialog.exec(); + sb_d->setAutoRestoreLastSession(sessionDialog.autoLoadSession()); +} /*! \brief Shows a dialog asking the user to confirm deleting the session \p session @@ -265,6 +275,8 @@ bool SessionManager::cloneSession(const QString &original, const QString &clone) if (!sessionFile.exists() || sessionFile.copyFile(sessionNameToFileName(clone))) { sb_d->m_sessions.insert(1, clone); sb_d->m_sessionDateTimes.insert(clone, sessionNameToFileName(clone).lastModified()); + emit instance()->sessionCreated(clone); + return true; } return false; diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 8f2da70bd24..a19e74a6711 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -40,6 +40,7 @@ public: static bool cloneSession(const QString &original, const QString &clone); static bool renameSession(const QString &original, const QString &newName); + static void showSessionManager(); static Utils::FilePath sessionNameToFileName(const QString &session); @@ -75,6 +76,7 @@ signals: void sessionLoaded(QString sessionName); void aboutToSaveSession(); + void sessionCreated(const QString &name); void sessionRenamed(const QString &oldName, const QString &newName); void sessionRemoved(const QString &name); From 5ac582a9b65c96210cee578aa62489ca3377176f Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 22 May 2023 13:45:27 +0200 Subject: [PATCH 1200/1447] Remove usage of SessionManagerPrivate from project explorer Change-Id: Ia12a9ba2d9e65605715110ea0330d5c1e1cae7c6 Reviewed-by: Reviewed-by: hjk --- .../projectexplorer/projectexplorer.cpp | 9 +-- .../projectexplorer/projectmanager.cpp | 13 ++--- src/plugins/projectexplorer/session.cpp | 55 ++++++++++--------- src/plugins/projectexplorer/session.h | 3 + src/plugins/projectexplorer/session_p.h | 1 - 5 files changed, 39 insertions(+), 42 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index d6379488fa9..d68b76a475c 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -69,7 +69,6 @@ #include "sanitizerparser.h" #include "selectablefilesmodel.h" #include "session.h" -#include "session_p.h" #include "sessiondialog.h" #include "showineditortaskhandler.h" #include "simpleprojectwizard.h" @@ -1633,10 +1632,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(ICore::instance(), &ICore::saveSettingsRequested, dd, &ProjectExplorerPluginPrivate::savePersistentSettings); - connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] { - if (!PluginManager::isShuttingDown() && !SessionManager::loadingSession()) - SessionManager::saveSession(); - }); connect(qApp, &QApplication::applicationStateChanged, this, [](Qt::ApplicationState state) { if (!PluginManager::isShuttingDown() && state == Qt::ApplicationActive) dd->updateWelcomePage(); @@ -1714,7 +1709,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er .toBool(); dd->m_buildPropertiesSettings.readSettings(s); - sb_d->restoreSettings(); const int customParserCount = s->value(Constants::CUSTOM_PARSER_COUNT_KEY).toInt(); for (int i = 0; i < customParserCount; ++i) { @@ -2169,7 +2163,7 @@ void ProjectExplorerPlugin::restoreKits() KitManager::restoreKits(); // restoring startup session is supposed to be done as a result of ICore::coreOpened, // and that is supposed to happen after restoring kits: - QTC_CHECK(!sb_d->isStartupSessionRestored()); + QTC_CHECK(!SessionManager::isStartupSessionRestored()); } void ProjectExplorerPluginPrivate::updateRunWithoutDeployMenu() @@ -2304,7 +2298,6 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() int(defaultSettings.stopBeforeBuild)); dd->m_buildPropertiesSettings.writeSettings(s); - sb_d->saveSettings(); s->setValueWithDefault(Constants::CUSTOM_PARSER_COUNT_KEY, int(dd->m_customParsers.count()), 0); for (int i = 0; i < dd->m_customParsers.count(); ++i) { diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index ff5b214b10a..6d0730786bd 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -3,7 +3,6 @@ #include "projectmanager.h" -#include "session_p.h" #include "session.h" #include "buildconfiguration.h" @@ -280,7 +279,7 @@ void ProjectManager::addProject(Project *pro) QTC_CHECK(!pro->displayName().isEmpty()); QTC_CHECK(pro->id().isValid()); - sb_d->m_virginSession = false; + SessionManager::markSessionFileDirty(); QTC_ASSERT(!d->m_projects.contains(pro), return); d->m_projects.append(pro); @@ -314,7 +313,7 @@ void ProjectManager::addProject(Project *pro) void ProjectManager::removeProject(Project *project) { - sb_d->m_virginSession = false; + SessionManager::markSessionFileDirty(); QTC_ASSERT(project, return); removeProjects({project}); } @@ -396,7 +395,8 @@ void ProjectManagerPrivate::dependencies(const FilePath &proName, FilePaths &res QString ProjectManagerPrivate::sessionTitle(const FilePath &filePath) { - if (SessionManager::isDefaultSession(sb_d->m_sessionName)) { + const QString sessionName = SessionManager::activeSession(); + if (SessionManager::isDefaultSession(sessionName)) { if (filePath.isEmpty()) { // use single project's name if there is only one loaded. const QList projects = ProjectManager::projects(); @@ -404,10 +404,7 @@ QString ProjectManagerPrivate::sessionTitle(const FilePath &filePath) return projects.first()->displayName(); } } else { - QString sessionName = sb_d->m_sessionName; - if (sessionName.isEmpty()) - sessionName = Tr::tr("Untitled"); - return sessionName; + return sessionName.isEmpty() ? Tr::tr("Untitled") : sessionName; } return QString(); } diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 9933ff070fa..ceb57bd8d54 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -35,6 +35,7 @@ #include using namespace Core; +using namespace ExtensionSystem; using namespace Utils; namespace ProjectExplorer { @@ -70,24 +71,18 @@ SessionManager::SessionManager() connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, &SessionManager::saveActiveMode); - connect(ICore::instance(), &ICore::saveSettingsRequested, this, [] { - QtcSettings *s = ICore::settings(); - QVariantMap times; - for (auto it = sb_d->m_lastActiveTimes.cbegin(); it != sb_d->m_lastActiveTimes.cend(); ++it) - times.insert(it.key(), it.value()); - s->setValue(LAST_ACTIVE_TIMES_KEY, times); - if (SessionManager::isDefaultVirgin()) { - s->remove(STARTUPSESSION_KEY); - } else { - s->setValue(STARTUPSESSION_KEY, SessionManager::activeSession()); - s->setValue(LASTSESSION_KEY, SessionManager::activeSession()); - } - }); + connect(ICore::instance(), &ICore::saveSettingsRequested, this, [] { sb_d->saveSettings(); }); connect(EditorManager::instance(), &EditorManager::editorOpened, this, &SessionManager::markSessionFileDirty); connect(EditorManager::instance(), &EditorManager::editorsClosed, this, &SessionManager::markSessionFileDirty); + connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] { + if (!PluginManager::isShuttingDown() && !SessionManager::loadingSession()) + SessionManager::saveSession(); + }); + + sb_d->restoreSettings(); } SessionManager::~SessionManager() @@ -286,13 +281,12 @@ static QString determineSessionToRestoreAtStartup() { // TODO (session) move argument to core // Process command line arguments first: - const bool lastSessionArg = ExtensionSystem::PluginManager::specForPlugin( - ProjectExplorerPlugin::instance()) + const bool lastSessionArg = PluginManager::specForPlugin(ProjectExplorerPlugin::instance()) ->arguments() .contains("-lastsession"); if (lastSessionArg && !SessionManager::startupSession().isEmpty()) return SessionManager::startupSession(); - const QStringList arguments = ExtensionSystem::PluginManager::arguments(); + const QStringList arguments = PluginManager::arguments(); QStringList sessions = SessionManager::sessions(); // We have command line arguments, try to find a session in them // Default to no session loading @@ -316,7 +310,7 @@ void SessionManagerPrivate::restoreStartupSession() ModeManager::activateMode(Core::Constants::MODE_EDIT); // We have command line arguments, try to find a session in them - QStringList arguments = ExtensionSystem::PluginManager::arguments(); + QStringList arguments = PluginManager::arguments(); if (!sessionToRestoreAtStartup.isEmpty() && !arguments.isEmpty()) arguments.removeOne(sessionToRestoreAtStartup); @@ -365,16 +359,22 @@ void SessionManagerPrivate::restoreStartupSession() }); } -bool SessionManagerPrivate::isStartupSessionRestored() -{ - return sb_d->m_isStartupSessionRestored; -} - void SessionManagerPrivate::saveSettings() { - ICore::settings()->setValueWithDefault(AUTO_RESTORE_SESSION_SETTINGS_KEY, - sb_d->m_isAutoRestoreLastSession, - kIsAutoRestoreLastSessionDefault); + QtcSettings *s = ICore::settings(); + QVariantMap times; + for (auto it = sb_d->m_lastActiveTimes.cbegin(); it != sb_d->m_lastActiveTimes.cend(); ++it) + times.insert(it.key(), it.value()); + s->setValue(LAST_ACTIVE_TIMES_KEY, times); + if (SessionManager::isDefaultVirgin()) { + s->remove(STARTUPSESSION_KEY); + } else { + s->setValue(STARTUPSESSION_KEY, SessionManager::activeSession()); + s->setValue(LASTSESSION_KEY, SessionManager::activeSession()); + } + s->setValueWithDefault(AUTO_RESTORE_SESSION_SETTINGS_KEY, + sb_d->m_isAutoRestoreLastSession, + kIsAutoRestoreLastSessionDefault); } void SessionManagerPrivate::restoreSettings() @@ -645,4 +645,9 @@ bool SessionManager::saveSession() return result; } +bool SessionManager::isStartupSessionRestored() +{ + return sb_d->m_isStartupSessionRestored; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index a19e74a6711..159a35f998f 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -80,6 +80,9 @@ signals: void sessionRenamed(const QString &oldName, const QString &newName); void sessionRemoved(const QString &name); +public: // internal + static bool isStartupSessionRestored(); + private: static void saveActiveMode(Utils::Id mode); }; diff --git a/src/plugins/projectexplorer/session_p.h b/src/plugins/projectexplorer/session_p.h index 40f691ab2d1..985dfd6661f 100644 --- a/src/plugins/projectexplorer/session_p.h +++ b/src/plugins/projectexplorer/session_p.h @@ -18,7 +18,6 @@ public: void restoreSessionValues(const PersistentSettingsReader &reader); void restoreEditors(); - bool isStartupSessionRestored(); void saveSettings(); void restoreSettings(); bool isAutoRestoreLastSession(); From b1957888dd6eb26124dee8c865c5769f59113d09 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 19 May 2023 12:03:38 +0200 Subject: [PATCH 1201/1447] WebAssembly: React to AspectContainer::applied ... instead of overriding IOptionsPage::apply() Change-Id: I00d30de7d604409be753eb8b9f668c24790e0a49 Reviewed-by: hjk --- src/plugins/webassembly/webassemblysettings.cpp | 8 ++------ src/plugins/webassembly/webassemblysettings.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/plugins/webassembly/webassemblysettings.cpp b/src/plugins/webassembly/webassemblysettings.cpp index 3d85e2127fd..1af1d30c911 100644 --- a/src/plugins/webassembly/webassemblysettings.cpp +++ b/src/plugins/webassembly/webassemblysettings.cpp @@ -64,6 +64,8 @@ WebAssemblySettings::WebAssemblySettings() emSdk.setExpectedKind(Utils::PathChooser::ExistingDirectory); emSdk.setDefaultFilePath(FileUtils::homePath()); + connect(this, &Utils::AspectContainer::applied, &WebAssemblyToolChain::registerToolChains); + setLayouter([this](QWidget *widget) { auto instruction = new QLabel( Tr::tr("Select the root directory of an installed %1. " @@ -122,12 +124,6 @@ WebAssemblySettings::WebAssemblySettings() readSettings(); } -void WebAssemblySettings::apply() -{ - WebAssemblyToolChain::registerToolChains(); - Core::IOptionsPage::apply(); -} - void WebAssemblySettings::updateStatus() { WebAssemblyEmSdk::clearCaches(); diff --git a/src/plugins/webassembly/webassemblysettings.h b/src/plugins/webassembly/webassemblysettings.h index 1d92a5176d1..c9e207c409c 100644 --- a/src/plugins/webassembly/webassemblysettings.h +++ b/src/plugins/webassembly/webassemblysettings.h @@ -18,7 +18,6 @@ public: WebAssemblySettings(); static WebAssemblySettings *instance(); - void apply() final; Utils::FilePathAspect emSdk; From b3f74783739abbd201d6dd0ad4d541fc157761d4 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 09:44:54 +0200 Subject: [PATCH 1202/1447] Coco: Use FilePath::searchInPath instead of Environment::searchInPath Not obviously better in this case, but I'd like to centralize searching on the FilePath side. Change-Id: I27cec97c0590cf27c3659b3aa262b86439670679 Reviewed-by: Christian Stenger --- src/plugins/coco/cocoplugin.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/coco/cocoplugin.cpp b/src/plugins/coco/cocoplugin.cpp index abea861af1e..f192b70a62a 100644 --- a/src/plugins/coco/cocoplugin.cpp +++ b/src/plugins/coco/cocoplugin.cpp @@ -40,12 +40,13 @@ void CocoPluginPrivate::startCoco() auto layout = new QFormLayout(); const Environment env = Environment::systemEnvironment(); - FilePath squishCocoPath = FilePath::fromString(env.value("SQUISHCOCO")); - const FilePaths candidates = env.findAllInPath("coveragebrowser", {squishCocoPath}); + const FilePath squishCocoPath = FilePath::fromUserInput(env.value("SQUISHCOCO")); + const FilePath candidate = FilePath("coveragebrowser").searchInPath({squishCocoPath}, + FilePath::PrependToPath); PathChooser cocoChooser; - if (!candidates.isEmpty()) - cocoChooser.setFilePath(candidates.first()); + if (!candidate.isEmpty()) + cocoChooser.setFilePath(candidate); cocoChooser.setExpectedKind(PathChooser::Command); cocoChooser.setPromptDialogTitle(Tr::tr("Select a Squish Coco CoverageBrowser Executable")); From 9dcd2cf40bbe7e64415da4b9c045606ab3ed6c0c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 23 May 2023 16:04:24 +0200 Subject: [PATCH 1203/1447] Add target condition to targets depending on QmlProjectManagerLib The lib is only built with Qt 6.4.3 and higher Change-Id: I825bab26b90565d315fed4a3ad1a3e6adf726ac6 Reviewed-by: hjk Reviewed-by: Burak Hancerli --- tests/unit/tools/qmlprojectmanager/CMakeLists.txt | 4 ++++ tests/unit/unittest/qmlprojectmanager/CMakeLists.txt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/tests/unit/tools/qmlprojectmanager/CMakeLists.txt b/tests/unit/tools/qmlprojectmanager/CMakeLists.txt index 0f5a41c6331..a1c04cb90fd 100644 --- a/tests/unit/tools/qmlprojectmanager/CMakeLists.txt +++ b/tests/unit/tools/qmlprojectmanager/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT TARGET QmlProjectManagerLib) + return() +endif() + project(QmlProjectManagerConverterDataCreator) add_compile_definitions(QT_CREATOR) diff --git a/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt index 9b5037fc527..52a70c0736a 100644 --- a/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt +++ b/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt @@ -1,4 +1,6 @@ extend_qtc_test(unittest + CONDITION + TARGET QmlProjectManagerLib DEPENDS QmlProjectManagerLib SOURCES From 962d9d55d0944f8ceba6e45baa60cb7bb309dc6f Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 15:46:44 +0200 Subject: [PATCH 1204/1447] Utils: Also allow FilePathAspects to auto-register Task-number: QTCREATORBUG-29167 Change-Id: Iba301764072cc1ca3d3a335a8106ab121733b387 Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 3 ++- src/libs/utils/aspects.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 54eba86eaf1..e900a680fc6 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1347,7 +1347,8 @@ void StringAspect::makeCheckable(CheckBoxPlacement checkBoxPlacement, */ -FilePathAspect::FilePathAspect() +FilePathAspect::FilePathAspect(AspectContainer *container) + : StringAspect(container) { setDisplayStyle(PathChooserDisplay); } diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 5fb16356ce3..a55e8bff74b 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -446,7 +446,7 @@ protected: class QTCREATOR_UTILS_EXPORT FilePathAspect : public StringAspect { public: - FilePathAspect(); + FilePathAspect(AspectContainer *container = nullptr); FilePath operator()() const { return filePath(); } }; From b90600e674c744c97427b0de3ca69b5d35579056 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 23 May 2023 14:04:40 +0200 Subject: [PATCH 1205/1447] CMakePM: Move cmListFileLexer.c as cmListFileLexer.cxx This way Qt Creator will not have two code model language contexts for the CMakeProjectManager. Change-Id: Ie71b845779aff472836b164a5c65fdc7d75debb1 Reviewed-by: hjk Reviewed-by: Reviewed-by: Qt CI Bot --- .../3rdparty/cmake/{cmListFileLexer.c => cmListFileLexer.cxx} | 2 +- .../cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l | 4 ++-- src/plugins/cmakeprojectmanager/CMakeLists.txt | 2 +- src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/plugins/cmakeprojectmanager/3rdparty/cmake/{cmListFileLexer.c => cmListFileLexer.cxx} (99%) diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.c b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.cxx similarity index 99% rename from src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.c rename to src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.cxx index fae62886a73..380e360addc 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.c +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.cxx @@ -2596,7 +2596,7 @@ static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, } /* We need to extend the buffer. */ - temp = malloc(newSize); + temp = (char *) malloc(newSize); if (lexer->token.text) { memcpy(temp, lexer->token.text, lexer->token.length); free(lexer->token.text); diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l index 2cf9f8cf2cb..d0c950a6143 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l @@ -7,7 +7,7 @@ This file must be translated to C and modified to build everywhere. Run flex >= 2.6 like this: - flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l + flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.cxx cmListFileLexer.in.l Modify cmListFileLexer.c: - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c @@ -309,7 +309,7 @@ static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, } /* We need to extend the buffer. */ - temp = malloc(newSize); + temp = (char *)malloc(newSize); if (lexer->token.text) { memcpy(temp, lexer->token.text, lexer->token.length); free(lexer->token.text); diff --git a/src/plugins/cmakeprojectmanager/CMakeLists.txt b/src/plugins/cmakeprojectmanager/CMakeLists.txt index 3d9dc4849e0..057b4139459 100644 --- a/src/plugins/cmakeprojectmanager/CMakeLists.txt +++ b/src/plugins/cmakeprojectmanager/CMakeLists.txt @@ -44,6 +44,6 @@ add_qtc_plugin(CMakeProjectManager presetsmacros.cpp presetsmacros.h projecttreehelper.cpp projecttreehelper.h 3rdparty/cmake/cmListFileCache.cxx - 3rdparty/cmake/cmListFileLexer.c + 3rdparty/cmake/cmListFileLexer.cxx 3rdparty/cmake/cmListFileCache.h ) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs index 79d8c219f27..3597a948713 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs @@ -98,7 +98,7 @@ QtcPlugin { files: [ "cmListFileCache.cxx", "cmListFileCache.h", - "cmListFileLexer.c", + "cmListFileLexer.cxx", "cmListFileLexer.h", "cmStandardLexer.h", ] From 2f04f08611600f47e3581b8241d863813ea6d8b9 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 23 May 2023 14:55:52 +0200 Subject: [PATCH 1206/1447] CMakePM: Remove comment line lexer addition This brings the lexer back to vanilla CMake version. The comment arguments were not needed in the implementation of source file addition / rename / removal operations. Change-Id: If28b738b9ce93511b109fe09dcd03f42ee07a431 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- .../3rdparty/cmake/cmListFileCache.cxx | 8 +---- .../3rdparty/cmake/cmListFileCache.h | 3 +- .../3rdparty/cmake/cmListFileLexer.cxx | 10 ++----- .../3rdparty/cmake/cmListFileLexer.h | 3 +- .../3rdparty/cmake/cmListFileLexer.in.l | 5 ---- .../cmakeprojectmanager/cmakebuildsystem.cpp | 30 +++++++------------ 6 files changed, 17 insertions(+), 42 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx index e3ffd23cc4c..13fd40ca645 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.cxx @@ -75,8 +75,7 @@ bool cmListFileParser::Parse() if (token->type == cmListFileLexer_Token_Space) { } else if (token->type == cmListFileLexer_Token_Newline) { haveNewline = true; - } else if (token->type == cmListFileLexer_Token_CommentBracket - || token->type == cmListFileLexer_Token_CommentLine) { + } else if (token->type == cmListFileLexer_Token_CommentBracket) { haveNewline = false; } else if (token->type == cmListFileLexer_Token_Identifier) { if (haveNewline) { @@ -187,11 +186,6 @@ bool cmListFileParser::ParseFunction(const char* name, long line) return false; } this->Separation = SeparationWarning; - } else if (token->type == cmListFileLexer_Token_CommentLine) { - if (!this->AddArgument(token, cmListFileArgument::Comment)) { - return false; - } - this->Separation = SeparationWarning; } else if (token->type == cmListFileLexer_Token_ArgumentBracket) { if (!this->AddArgument(token, cmListFileArgument::Bracket)) { return false; diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h index caffba4b851..4b419e7a5a4 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileCache.h @@ -22,8 +22,7 @@ struct cmListFileArgument { Unquoted, Quoted, - Bracket, - Comment + Bracket }; cmListFileArgument() = default; cmListFileArgument(std::string v, Delimiter d, long line, long column) diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.cxx b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.cxx index 380e360addc..e093275a8d8 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.cxx +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.cxx @@ -755,7 +755,7 @@ This file must be translated to C and modified to build everywhere. Run flex >= 2.6 like this: - flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l + flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.cxx cmListFileLexer.in.l Modify cmListFileLexer.c: - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c @@ -1172,10 +1172,7 @@ YY_RULE_SETUP case 4: YY_RULE_SETUP { - lexer->token.type = cmListFileLexer_Token_CommentLine; - cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; - return 1; } YY_BREAK case 5: @@ -2596,7 +2593,7 @@ static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text, } /* We need to extend the buffer. */ - temp = (char *) malloc(newSize); + temp = (char *)malloc(newSize); if (lexer->token.text) { memcpy(temp, lexer->token.text, lexer->token.length); free(lexer->token.text); @@ -2828,8 +2825,7 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, return "unterminated bracket"; case cmListFileLexer_Token_BadString: return "unterminated string"; - case cmListFileLexer_Token_CommentLine: - return "line comment"; } return "unknown token"; } + diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h index 199530f16c3..14ee2c1ba1e 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.h @@ -21,8 +21,7 @@ typedef enum cmListFileLexer_Type_e cmListFileLexer_Token_CommentBracket, cmListFileLexer_Token_BadCharacter, cmListFileLexer_Token_BadBracket, - cmListFileLexer_Token_BadString, - cmListFileLexer_Token_CommentLine + cmListFileLexer_Token_BadString } cmListFileLexer_Type; /* NOLINTNEXTLINE(modernize-use-using) */ diff --git a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l index d0c950a6143..b7a5c46687a 100644 --- a/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l +++ b/src/plugins/cmakeprojectmanager/3rdparty/cmake/cmListFileLexer.in.l @@ -110,10 +110,7 @@ LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\" } [^\0\n]* { - lexer->token.type = cmListFileLexer_Token_CommentLine; - cmListFileLexerSetToken(lexer, yytext, yyleng); lexer->column += yyleng; - return 1; } \( { @@ -541,8 +538,6 @@ const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer, return "unterminated bracket"; case cmListFileLexer_Token_BadString: return "unterminated string"; - case cmListFileLexer_Token_CommentLine: - return "line comment"; } return "unknown token"; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index aaad00ed4bd..789b3a9aac6 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -432,12 +432,11 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q for (const auto &func : {function, targetSourcesFunc, addQmlModuleFunc}) { if (func == cmakeListFile.Functions.end()) continue; - auto filePathArgument - = Utils::findOrDefault(func->Arguments(), - [file_name = fileName.toStdString()](const auto &arg) { - return arg.Delim != cmListFileArgument::Comment - && arg.Value == file_name; - }); + auto filePathArgument = Utils::findOrDefault(func->Arguments(), + [file_name = fileName.toStdString()]( + const auto &arg) { + return arg.Value == file_name; + }); if (!filePathArgument.Value.empty()) { return ProjectFileArgumentPosition{filePathArgument, targetCMakeFile, fileName}; @@ -456,9 +455,7 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q const auto haveGlobbing = Utils::anyOf(func->Arguments(), [globVariables](const auto &arg) { - return globVariables.contains(arg.Value) - && arg.Delim - != cmListFileArgument::Comment; + return globVariables.contains(arg.Value); }); if (haveGlobbing) { @@ -475,21 +472,16 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q })); for (const auto &arg : func->Arguments()) { - if (arg.Delim == cmListFileArgument::Comment) - continue; - auto matchedFunctions = Utils::filtered(setFunctions, [arg](const auto &f) { return arg.Value == std::string("${") + f.Arguments()[0].Value + "}"; }); for (const auto &f : matchedFunctions) { - filePathArgument - = Utils::findOrDefault(f.Arguments(), - [file_name = fileName.toStdString()]( - const auto &arg) { - return arg.Delim != cmListFileArgument::Comment - && arg.Value == file_name; - }); + filePathArgument = Utils::findOrDefault(f.Arguments(), + [file_name = fileName.toStdString()]( + const auto &arg) { + return arg.Value == file_name; + }); if (!filePathArgument.Value.empty()) { return ProjectFileArgumentPosition{filePathArgument, From 3c9bb1c53d1dd1d7a3850d2e3799a5251df7501c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 14:38:49 +0200 Subject: [PATCH 1207/1447] Incredibuild: Use FilePathAspect Change-Id: I02f09860ae81f060adeee0839e20740be802da9a Reviewed-by: Alessandro Portale --- src/plugins/incredibuild/buildconsolebuildstep.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/incredibuild/buildconsolebuildstep.cpp b/src/plugins/incredibuild/buildconsolebuildstep.cpp index 1238b2c2436..c28c1cd6769 100644 --- a/src/plugins/incredibuild/buildconsolebuildstep.cpp +++ b/src/plugins/incredibuild/buildconsolebuildstep.cpp @@ -76,10 +76,9 @@ BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id addAspect("" + Tr::tr("IncrediBuild Distribution Control")); - auto profileXml = addAspect(); + auto profileXml = addAspect(); profileXml->setSettingsKey("IncrediBuild.BuildConsole.ProfileXml"); profileXml->setLabelText(Tr::tr("Profile.xml:")); - profileXml->setDisplayStyle(StringAspect::PathChooserDisplay); profileXml->setExpectedKind(PathChooser::Kind::File); profileXml->setBaseFileName(PathChooser::homePath()); profileXml->setHistoryCompleter("IncrediBuild.BuildConsole.ProfileXml.History"); @@ -138,10 +137,9 @@ BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id "beginning of the build output text. This title will also be used " "for the Build History and Build Monitor displays.")); - auto monFile = addAspect(); + auto monFile = addAspect(); monFile->setSettingsKey("IncrediBuild.BuildConsole.MonFile"); monFile->setLabelText(Tr::tr("Save IncrediBuild monitor file:")); - monFile->setDisplayStyle(StringAspect::PathChooserDisplay); monFile->setExpectedKind(PathChooser::Kind::Any); monFile->setBaseFileName(PathChooser::homePath()); monFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.MonFile.History")); @@ -155,10 +153,9 @@ BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id suppressStdOut->setLabel(Tr::tr("Suppress STDOUT:")); suppressStdOut->setToolTip(Tr::tr("Does not write anything to the standard output.")); - auto logFile = addAspect(); + auto logFile = addAspect(); logFile->setSettingsKey("IncrediBuild.BuildConsole.LogFile"); logFile->setLabelText(Tr::tr("Output Log file:")); - logFile->setDisplayStyle(StringAspect::PathChooserDisplay); logFile->setExpectedKind(PathChooser::Kind::SaveFile); logFile->setBaseFileName(PathChooser::homePath()); logFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.LogFile.History")); From 815a05a94ab1eace8c63e2f08ee89889206367a9 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 23 May 2023 13:58:49 +0200 Subject: [PATCH 1208/1447] QmlEditorWidgets: Fix color popup for Rectangle widget The color buttons for background color and border color did not open the color picker popup. The buttons need to be set checkable, which broke while "inlining" .ui files. Amends: 200a66644ef3d02bfb9969f6e9010f35fbec62ae Fixes: QTCREATORBUG-29195 Change-Id: Icd71df1bcfad6472a90691d2c353f7039b52004e Reviewed-by: hjk --- .../qmleditorwidgets/contextpanewidgetrectangle.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp b/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp index 52afeff187c..5da883f4266 100644 --- a/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp +++ b/src/libs/qmleditorwidgets/contextpanewidgetrectangle.cpp @@ -33,13 +33,19 @@ ContextPaneWidgetRectangle::ContextPaneWidgetRectangle(QWidget *parent) return result; }; + const auto colorButton = [] { + auto result = new ColorButton; + result->setCheckable(true); + result->setShowArrow(false); + return result; + }; + m_gradientLabel = new QLabel(Tr::tr("Gradient")); m_gradientLabel->setAlignment(Qt::AlignBottom); m_gradientLine = new GradientLine; m_gradientLine->setMinimumWidth(240); - m_colorColorButton = new ColorButton; - m_colorColorButton->setShowArrow(false); + m_colorColorButton = colorButton(); m_colorSolid = toolButton("icon_color_solid"); m_colorGradient = toolButton("icon_color_gradient"); m_colorNone = toolButton("icon_color_none"); @@ -48,8 +54,7 @@ ContextPaneWidgetRectangle::ContextPaneWidgetRectangle(QWidget *parent) colorButtons->addButton(m_colorGradient); colorButtons->addButton(m_colorNone); - m_borderColorButton = new ColorButton; - m_borderColorButton->setShowArrow(false); + m_borderColorButton = colorButton(); m_borderSolid = toolButton("icon_color_solid"); m_borderNone = toolButton("icon_color_none"); auto borderButtons = new QButtonGroup(this); From 443117e314b7ce12dcf408900a0f7e8cacba47dc Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 15:25:32 +0200 Subject: [PATCH 1209/1447] Nim: Use a FilePathAspect for nimsuggest settings Change-Id: I7e910853dcf6872f2a9a38ebfc5e52936ef15113 Reviewed-by: Alessandro Portale --- src/plugins/nim/settings/nimsettings.cpp | 2 -- src/plugins/nim/settings/nimsettings.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp index 5e98b0fd536..fdf44ccd366 100644 --- a/src/plugins/nim/settings/nimsettings.cpp +++ b/src/plugins/nim/settings/nimsettings.cpp @@ -86,9 +86,7 @@ NimSettings::NimSettings() TextEditorSettings::registerMimeTypeForLanguageId(Nim::Constants::C_NIM_SCRIPT_MIMETYPE, Nim::Constants::C_NIMLANGUAGE_ID); - registerAspect(&nimSuggestPath); nimSuggestPath.setSettingsKey("Command"); - nimSuggestPath.setDisplayStyle(StringAspect::PathChooserDisplay); nimSuggestPath.setExpectedKind(PathChooser::ExistingCommand); nimSuggestPath.setLabelText(Tr::tr("Path:")); diff --git a/src/plugins/nim/settings/nimsettings.h b/src/plugins/nim/settings/nimsettings.h index 57beb64f45d..a7c6628b65b 100644 --- a/src/plugins/nim/settings/nimsettings.h +++ b/src/plugins/nim/settings/nimsettings.h @@ -15,7 +15,7 @@ public: NimSettings(); ~NimSettings(); - Utils::StringAspect nimSuggestPath; + Utils::FilePathAspect nimSuggestPath{this}; static TextEditor::SimpleCodeStylePreferences *globalCodeStyle(); }; From c1cdea2661a31ea62c727d720220438ba1a24153 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 23 May 2023 16:12:02 +0200 Subject: [PATCH 1210/1447] CMakePM: Consider quoted file names for file operations It is not uncommon for projects to use quoted file names, which would break the new file operation support for CMakeLists.txt files. Change-Id: I8dc5d6843f1723c5709cef28cf3bf89a5c87ec2a Reviewed-by: hjk Reviewed-by: Qt CI Bot --- .../cmakeprojectmanager/cmakebuildsystem.cpp | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 789b3a9aac6..7e10a06e259 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -325,15 +325,21 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP int line = 0; int column = 0; + int extraChars = 0; QString snippet; - auto afterFunctionLastArgument = [&line, &column, &snippet, newSourceFiles](const auto &f) { - auto lastArgument = f->Arguments().back(); + auto afterFunctionLastArgument = + [&line, &column, &snippet, &extraChars, newSourceFiles](const auto &f) { + auto lastArgument = f->Arguments().back(); - line = lastArgument.Line; - column = lastArgument.Column + static_cast(lastArgument.Value.size()) - 1; - snippet = QString("\n%1").arg(newSourceFiles); - }; + line = lastArgument.Line; + column = lastArgument.Column + static_cast(lastArgument.Value.size()) - 1; + snippet = QString("\n%1").arg(newSourceFiles); + + // Take into consideration the quotes + if (lastArgument.Delim == cmListFileArgument::Quoted) + extraChars = 2; + }; if (knownFunctions.contains(function->LowerCaseName())) { afterFunctionLastArgument(function); @@ -359,7 +365,7 @@ bool CMakeBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FileP } BaseTextEditor *editor = qobject_cast( - Core::EditorManager::openEditorAt({targetCMakeFile, line, column}, + Core::EditorManager::openEditorAt({targetCMakeFile, line, column + extraChars}, Constants::CMAKE_EDITOR_ID, Core::EditorManager::DoNotMakeVisible)); if (!editor) { @@ -528,8 +534,13 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context, continue; } + // If quotes were used for the source file, remove the quotes too + int extraChars = 0; + if (filePos->argumentPosition.Delim == cmListFileArgument::Quoted) + extraChars = 2; + if (!filePos.value().fromGlobbing) - editor->replace(filePos.value().relativeFileName.length(), ""); + editor->replace(filePos.value().relativeFileName.length() + extraChars, ""); editor->editorWidget()->autoIndent(); if (!Core::DocumentManager::saveDocument(editor->document())) { @@ -610,6 +621,10 @@ bool CMakeBuildSystem::renameFile(Node *context, if (!editor) return false; + // If quotes were used for the source file, skip the starting quote + if (fileToRename.argumentPosition.Delim == cmListFileArgument::Quoted) + editor->setCursorPosition(editor->position() + 1); + if (!fileToRename.fromGlobbing) editor->replace(fileToRename.relativeFileName.length(), newRelPathName); From af5bb5e599af9ce475d82bbc4e8b91791b5f5f0a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 23 May 2023 16:43:48 +0200 Subject: [PATCH 1211/1447] Adapt for easier merge into main repository Remove conflicting files and already move to the right place Change-Id: I2b20f4aa85e61ff121acb68aaab5d5e1fdd87956 Reviewed-by: Christian Stenger Reviewed-by: hjk --- CMakeLists.txt | 11 ----------- README.md | 7 ------- {plugins => src/plugins}/axivion/Axivion.json.in | 0 {plugins => src/plugins}/axivion/CMakeLists.txt | 0 {plugins => src/plugins}/axivion/axivion.qbs | 0 {plugins => src/plugins}/axivion/axivion.qrc | 0 .../plugins}/axivion/axivionoutputpane.cpp | 0 .../plugins}/axivion/axivionoutputpane.h | 0 {plugins => src/plugins}/axivion/axivionplugin.cpp | 0 {plugins => src/plugins}/axivion/axivionplugin.h | 0 .../plugins}/axivion/axivionprojectsettings.cpp | 0 .../plugins}/axivion/axivionprojectsettings.h | 0 {plugins => src/plugins}/axivion/axivionquery.cpp | 0 {plugins => src/plugins}/axivion/axivionquery.h | 0 .../plugins}/axivion/axivionresultparser.cpp | 0 .../plugins}/axivion/axivionresultparser.h | 0 .../plugins}/axivion/axivionsettings.cpp | 0 {plugins => src/plugins}/axivion/axivionsettings.h | 0 .../plugins}/axivion/axivionsettingspage.cpp | 0 .../plugins}/axivion/axivionsettingspage.h | 0 {plugins => src/plugins}/axivion/axiviontr.h | 0 {plugins => src/plugins}/axivion/images/axivion.png | Bin .../plugins}/axivion/images/axivion@2x.png | Bin 23 files changed, 18 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 README.md rename {plugins => src/plugins}/axivion/Axivion.json.in (100%) rename {plugins => src/plugins}/axivion/CMakeLists.txt (100%) rename {plugins => src/plugins}/axivion/axivion.qbs (100%) rename {plugins => src/plugins}/axivion/axivion.qrc (100%) rename {plugins => src/plugins}/axivion/axivionoutputpane.cpp (100%) rename {plugins => src/plugins}/axivion/axivionoutputpane.h (100%) rename {plugins => src/plugins}/axivion/axivionplugin.cpp (100%) rename {plugins => src/plugins}/axivion/axivionplugin.h (100%) rename {plugins => src/plugins}/axivion/axivionprojectsettings.cpp (100%) rename {plugins => src/plugins}/axivion/axivionprojectsettings.h (100%) rename {plugins => src/plugins}/axivion/axivionquery.cpp (100%) rename {plugins => src/plugins}/axivion/axivionquery.h (100%) rename {plugins => src/plugins}/axivion/axivionresultparser.cpp (100%) rename {plugins => src/plugins}/axivion/axivionresultparser.h (100%) rename {plugins => src/plugins}/axivion/axivionsettings.cpp (100%) rename {plugins => src/plugins}/axivion/axivionsettings.h (100%) rename {plugins => src/plugins}/axivion/axivionsettingspage.cpp (100%) rename {plugins => src/plugins}/axivion/axivionsettingspage.h (100%) rename {plugins => src/plugins}/axivion/axiviontr.h (100%) rename {plugins => src/plugins}/axivion/images/axivion.png (100%) rename {plugins => src/plugins}/axivion/images/axivion@2x.png (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 7a3dd57ae3c..00000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(Axivion) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_CXX_STANDARD 17) - -add_subdirectory(plugins/axivion) - diff --git a/README.md b/README.md deleted file mode 100644 index df44f43aeb3..00000000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -# QtCreator/Axivion Integration Plug-in - -This plug-in integrates Axivion Tools handling into Qt Creator. - -This plug-in is only available as part of the commercial Qt offering. - diff --git a/plugins/axivion/Axivion.json.in b/src/plugins/axivion/Axivion.json.in similarity index 100% rename from plugins/axivion/Axivion.json.in rename to src/plugins/axivion/Axivion.json.in diff --git a/plugins/axivion/CMakeLists.txt b/src/plugins/axivion/CMakeLists.txt similarity index 100% rename from plugins/axivion/CMakeLists.txt rename to src/plugins/axivion/CMakeLists.txt diff --git a/plugins/axivion/axivion.qbs b/src/plugins/axivion/axivion.qbs similarity index 100% rename from plugins/axivion/axivion.qbs rename to src/plugins/axivion/axivion.qbs diff --git a/plugins/axivion/axivion.qrc b/src/plugins/axivion/axivion.qrc similarity index 100% rename from plugins/axivion/axivion.qrc rename to src/plugins/axivion/axivion.qrc diff --git a/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp similarity index 100% rename from plugins/axivion/axivionoutputpane.cpp rename to src/plugins/axivion/axivionoutputpane.cpp diff --git a/plugins/axivion/axivionoutputpane.h b/src/plugins/axivion/axivionoutputpane.h similarity index 100% rename from plugins/axivion/axivionoutputpane.h rename to src/plugins/axivion/axivionoutputpane.h diff --git a/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp similarity index 100% rename from plugins/axivion/axivionplugin.cpp rename to src/plugins/axivion/axivionplugin.cpp diff --git a/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h similarity index 100% rename from plugins/axivion/axivionplugin.h rename to src/plugins/axivion/axivionplugin.h diff --git a/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp similarity index 100% rename from plugins/axivion/axivionprojectsettings.cpp rename to src/plugins/axivion/axivionprojectsettings.cpp diff --git a/plugins/axivion/axivionprojectsettings.h b/src/plugins/axivion/axivionprojectsettings.h similarity index 100% rename from plugins/axivion/axivionprojectsettings.h rename to src/plugins/axivion/axivionprojectsettings.h diff --git a/plugins/axivion/axivionquery.cpp b/src/plugins/axivion/axivionquery.cpp similarity index 100% rename from plugins/axivion/axivionquery.cpp rename to src/plugins/axivion/axivionquery.cpp diff --git a/plugins/axivion/axivionquery.h b/src/plugins/axivion/axivionquery.h similarity index 100% rename from plugins/axivion/axivionquery.h rename to src/plugins/axivion/axivionquery.h diff --git a/plugins/axivion/axivionresultparser.cpp b/src/plugins/axivion/axivionresultparser.cpp similarity index 100% rename from plugins/axivion/axivionresultparser.cpp rename to src/plugins/axivion/axivionresultparser.cpp diff --git a/plugins/axivion/axivionresultparser.h b/src/plugins/axivion/axivionresultparser.h similarity index 100% rename from plugins/axivion/axivionresultparser.h rename to src/plugins/axivion/axivionresultparser.h diff --git a/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp similarity index 100% rename from plugins/axivion/axivionsettings.cpp rename to src/plugins/axivion/axivionsettings.cpp diff --git a/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h similarity index 100% rename from plugins/axivion/axivionsettings.h rename to src/plugins/axivion/axivionsettings.h diff --git a/plugins/axivion/axivionsettingspage.cpp b/src/plugins/axivion/axivionsettingspage.cpp similarity index 100% rename from plugins/axivion/axivionsettingspage.cpp rename to src/plugins/axivion/axivionsettingspage.cpp diff --git a/plugins/axivion/axivionsettingspage.h b/src/plugins/axivion/axivionsettingspage.h similarity index 100% rename from plugins/axivion/axivionsettingspage.h rename to src/plugins/axivion/axivionsettingspage.h diff --git a/plugins/axivion/axiviontr.h b/src/plugins/axivion/axiviontr.h similarity index 100% rename from plugins/axivion/axiviontr.h rename to src/plugins/axivion/axiviontr.h diff --git a/plugins/axivion/images/axivion.png b/src/plugins/axivion/images/axivion.png similarity index 100% rename from plugins/axivion/images/axivion.png rename to src/plugins/axivion/images/axivion.png diff --git a/plugins/axivion/images/axivion@2x.png b/src/plugins/axivion/images/axivion@2x.png similarity index 100% rename from plugins/axivion/images/axivion@2x.png rename to src/plugins/axivion/images/axivion@2x.png From 861b98a76a4f51e2bac1159d0f1f194f12ceed25 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 24 May 2023 00:29:46 +0300 Subject: [PATCH 1212/1447] FilePath: Remove const ref for enum argument Change-Id: I86c5466cdcd8f74816456e70463157f28a4e37bc Reviewed-by: Marcus Tillmanns --- src/libs/utils/filepath.cpp | 4 ++-- src/libs/utils/filepath.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 2df57830343..31d24f14b00 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1501,7 +1501,7 @@ FilePath FilePath::withNewPath(const QString &newPath) const FilePath FilePath::searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter, - const MatchScope &matchScope) const + MatchScope matchScope) const { if (isEmpty()) return {}; @@ -1540,7 +1540,7 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs, FilePaths FilePath::searchAllInDirectories(const FilePaths &dirs, const FilePathPredicate &filter, - const MatchScope &matchScope) const + MatchScope matchScope) const { if (isEmpty()) return {}; diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 4462b473cdd..f313ba5ff92 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -187,10 +187,10 @@ public: [[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter = {}, - const MatchScope &matchScope = WithAnySuffix) const; + MatchScope matchScope = WithAnySuffix) const; [[nodiscard]] FilePaths searchAllInDirectories(const FilePaths &dirs, const FilePathPredicate &filter = {}, - const MatchScope &matchScope = WithAnySuffix) const; + MatchScope matchScope = WithAnySuffix) const; [[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {}, PathAmending = AppendToPath, const FilePathPredicate &filter = {}, From 00d156c8ca12e1b30c66a79b30d4f726a21f31c0 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 19 May 2023 16:55:46 +0800 Subject: [PATCH 1213/1447] Fix exclusion pattern tooltip text It says "included" instead of "excluded". Change-Id: Ib74f2adbc6e6f10a9ff79662e5be609a89fe89d6 Reviewed-by: Eike Ziller --- src/libs/utils/filesearch.cpp | 8 +++++--- src/libs/utils/filesearch.h | 7 ++++++- src/plugins/coreplugin/locator/directoryfilter.cpp | 2 +- src/plugins/texteditor/basefilefind.cpp | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index fe657562769..073b6057a90 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -540,10 +540,12 @@ QString msgExclusionPatternLabel() return Tr::tr("Excl&usion pattern:"); } -QString msgFilePatternToolTip() +QString msgFilePatternToolTip(InclusionType inclusionType) { - return Tr::tr("List of comma separated wildcard filters. " - "Files with file name or full file path matching any filter are included."); + return Tr::tr("List of comma separated wildcard filters. ") + + (inclusionType == InclusionType::Included + ? Tr::tr("Files with file name or full file path matching any filter are included.") + : Tr::tr("Files with file name or full file path matching any filter are excluded.")); } QString matchCaseReplacement(const QString &originalText, const QString &replaceText) diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index 7bb7af5d33f..c3d81faa121 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -40,8 +40,13 @@ QString msgFilePatternLabel(); QTCREATOR_UTILS_EXPORT QString msgExclusionPatternLabel(); +enum class InclusionType { + Included, + Excluded +}; + QTCREATOR_UTILS_EXPORT -QString msgFilePatternToolTip(); +QString msgFilePatternToolTip(InclusionType inclusionType = InclusionType::Included); class QTCREATOR_UTILS_EXPORT FileIterator { diff --git a/src/plugins/coreplugin/locator/directoryfilter.cpp b/src/plugins/coreplugin/locator/directoryfilter.cpp index 0c1dd72bb77..42cf51addf7 100644 --- a/src/plugins/coreplugin/locator/directoryfilter.cpp +++ b/src/plugins/coreplugin/locator/directoryfilter.cpp @@ -316,7 +316,7 @@ bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) m_dialog->filePattern->setText(Utils::transform(m_filters, &QDir::toNativeSeparators).join(',')); m_dialog->exclusionPatternLabel->setText(Utils::msgExclusionPatternLabel()); m_dialog->exclusionPatternLabel->setBuddy(m_dialog->exclusionPattern); - m_dialog->exclusionPattern->setToolTip(Utils::msgFilePatternToolTip()); + m_dialog->exclusionPattern->setToolTip(Utils::msgFilePatternToolTip(InclusionType::Excluded)); m_dialog->exclusionPattern->setText( Utils::transform(m_exclusionFilters, &QDir::toNativeSeparators).join(',')); m_dialog->shortcutEdit->setText(shortcutString()); diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 974f1472912..8a75a27910c 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -345,7 +345,7 @@ QList> BaseFileFind::createPatternWidgets() syncComboWithSettings(d->m_filterCombo, d->m_filterSetting); QLabel *exclusionLabel = createLabel(msgExclusionPatternLabel()); d->m_exclusionCombo = createCombo(&d->m_exclusionStrings); - d->m_exclusionCombo->setToolTip(msgFilePatternToolTip()); + d->m_exclusionCombo->setToolTip(msgFilePatternToolTip(Utils::InclusionType::Excluded)); exclusionLabel->setBuddy(d->m_exclusionCombo); syncComboWithSettings(d->m_exclusionCombo, d->m_exclusionSetting); return {{filterLabel, d->m_filterCombo}, {exclusionLabel, d->m_exclusionCombo}}; From 305fae9a4aff4456e89d5c0ba209c3ab4ee5f0f4 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 23 May 2023 09:32:33 +0200 Subject: [PATCH 1214/1447] Copilot: shutdown plugin asynchronously Wait for the client to finish. This fixes a crash when running the plugin unit tests of the copilot plugin. Change-Id: Id0805cb628a79316cd904350bb159ff1369a03b9 Reviewed-by: Christian Stenger --- src/plugins/copilot/copilotplugin.cpp | 8 ++++++++ src/plugins/copilot/copilotplugin.h | 1 + src/plugins/languageclient/languageclientmanager.cpp | 8 +++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 61753b29c30..d895e088c56 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -60,5 +60,13 @@ void CopilotPlugin::restartClient() CopilotSettings::instance().distPath()); } +ExtensionSystem::IPlugin::ShutdownFlag CopilotPlugin::aboutToShutdown() +{ + if (!m_client) + return SynchronousShutdown; + connect(m_client, &QObject::destroyed, this, &IPlugin::asynchronousShutdownFinished); + return AsynchronousShutdown; +} + } // namespace Internal } // namespace Copilot diff --git a/src/plugins/copilot/copilotplugin.h b/src/plugins/copilot/copilotplugin.h index 09a6caecb20..8c1a176a732 100644 --- a/src/plugins/copilot/copilotplugin.h +++ b/src/plugins/copilot/copilotplugin.h @@ -21,6 +21,7 @@ public: void initialize() override; void extensionsInitialized() override; void restartClient(); + ShutdownFlag aboutToShutdown() override; private: QPointer m_client; diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 4c8fa425303..482f4e8e39e 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -237,7 +237,13 @@ void LanguageClientManager::deleteClient(Client *client) managerInstance->m_clients.removeAll(client); for (QList &clients : managerInstance->m_clientsForSetting) clients.removeAll(client); - client->deleteLater(); + + // a deleteLater is not sufficient here as it pastes the delete later event at the end + // of the main event loop and when the plugins are shutdown we spawn an additional eventloop + // that will not handle the delete later event. Use invokeMethod with Qt::QueuedConnection + // instead. + QMetaObject::invokeMethod(client, [client] {delete client;}, Qt::QueuedConnection); + if (!PluginManager::isShuttingDown()) emit instance()->clientRemoved(client); } From 74f042402092bac4a5a3aa272872cc971e92423d Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 16:10:24 +0200 Subject: [PATCH 1215/1447] Doc: Fix typo in signal name in the \fn command Change-Id: Ie7b365371fedb0304d3ac73dcda948832d88fb49 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/coreplugin/find/searchresultwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 534c9e13bb2..1a2e8c271d1 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -276,7 +276,7 @@ using namespace Core::Internal; */ /*! - \fn void Core::SearchResult::cancelled() + \fn void Core::SearchResult::canceled() This signal is emitted if the user cancels the search. */ From d10eac94ea7de46eeb076685eb47dfab398dbae7 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 16:00:26 +0200 Subject: [PATCH 1216/1447] Doc: Remove obsolete docs for IExternalEditor To fix qdoc warnings. Change-Id: I02694e2a6b7f2ed7f5ed5d3b397159ebf327d148 Reviewed-by: Reviewed-by: Eike Ziller --- .../coreplugin/editormanager/iexternaleditor.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/iexternaleditor.cpp b/src/plugins/coreplugin/editormanager/iexternaleditor.cpp index 44a2db84832..8176bf4d3ee 100644 --- a/src/plugins/coreplugin/editormanager/iexternaleditor.cpp +++ b/src/plugins/coreplugin/editormanager/iexternaleditor.cpp @@ -17,21 +17,6 @@ namespace Core { editor in the \uicontrol{Open With} dialog. */ -/*! - \fn QString Core::IExternalEditor::displayName() const - Returns a user-visible description of the editor type. -*/ - -/*! - \fn Utils::Id Core::IExternalEditor::id() const - Returns the ID of the factory or editor type. -*/ - -/*! - \fn QStringList Core::IExternalEditor::mimeTypes() const - Returns a list of MIME types that the editor supports -*/ - /*! \fn bool Core::IExternalEditor::startEditor(const Utils::FilePath &fileName, QString *errorMessage) From e1a67c7cfb2d8bedf1908713d5db9352d9737100 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 14:58:18 +0200 Subject: [PATCH 1217/1447] Doc: Exclude src/libs/utils/mimetypes2 from doc builds It is copied from Qt. Change-Id: Ia9a9f02abcb45d1f2981918259b8cc970c3165ca Reviewed-by: Eike Ziller Reviewed-by: --- doc/qtcreatordev/config/qtcreator-developer.qdocconf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/qtcreatordev/config/qtcreator-developer.qdocconf b/doc/qtcreatordev/config/qtcreator-developer.qdocconf index 99b00d54fa8..0ce340b2b78 100644 --- a/doc/qtcreatordev/config/qtcreator-developer.qdocconf +++ b/doc/qtcreatordev/config/qtcreator-developer.qdocconf @@ -29,7 +29,9 @@ sourcedirs = . \ ../../../src/plugins/coreplugin -excludedirs = ../../../src/libs/aggregation/examples +excludedirs = ../../../src/libs/aggregation/examples \ + ../../../src/libs/utils/mimetypes2 + # -- Uncomment following option to generate complete documentation # instead of public API documentation only. From ec9d9586fc199ea7b5f6cef0f0dbbe7025d62c26 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 23 May 2023 16:49:20 +0200 Subject: [PATCH 1218/1447] Doc: Add \a commands and document Utils::MathUtils namespace Fixes qdoc warnings. Change-Id: I666e6db9ee3a3a5c83f093f2e48981701f137d5c Reviewed-by: Jarek Kobus Reviewed-by: --- src/libs/utils/mathutils.cpp | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/mathutils.cpp b/src/libs/utils/mathutils.cpp index 77d9d5e5b27..a25f4515b0b 100644 --- a/src/libs/utils/mathutils.cpp +++ b/src/libs/utils/mathutils.cpp @@ -5,12 +5,22 @@ #include +/*! + \namespace Utils::MathUtils + \inmodule QtCreator + + \brief Contains functions for interpolation. +*/ + namespace Utils::MathUtils { /*! Linear interpolation: - For x = x1 it returns y1. - For x = x2 it returns y2. + + \list + \li For \a x = \a x1 it returns \a y1. + \li For \a x = \a x2 it returns \a y2. + \endlist */ int interpolateLinear(int x, int x1, int x2, int y1, int y2) { @@ -29,9 +39,13 @@ int interpolateLinear(int x, int x1, int x2, int y1, int y2) /*! Tangential interpolation: - For x = 0 it returns y1. - For x = xHalfLife it returns 50 % of the distance between y1 and y2. - For x = infinity it returns y2. + + \list + \li For \a x = 0 it returns \a y1. + \li For \a x = \a xHalfLife it returns 50 % of the distance between + \a y1 and \a y2. + \li For \a x = infinity it returns \a y2. + \endlist */ int interpolateTangential(int x, int xHalfLife, int y1, int y2) { @@ -46,9 +60,13 @@ int interpolateTangential(int x, int xHalfLife, int y1, int y2) /*! Exponential interpolation: - For x = 0 it returns y1. - For x = xHalfLife it returns 50 % of the distance between y1 and y2. - For x = infinity it returns y2. + + \list + \li For \a x = 0 it returns \a y1. + \li For \a x = \a xHalfLife it returns 50 % of the distance between + \a y1 and \a y2. + \li For \a x = infinity it returns \a y2. + \endlist */ int interpolateExponential(int x, int xHalfLife, int y1, int y2) { From 42a162c9afc23fd68fdbe4f8519419ac4a57bff5 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 14:26:52 +0200 Subject: [PATCH 1219/1447] Python: Use FilePath::searchInPath instead of Environment::findInPath That's the last remaining users. Change-Id: I14ce380b9c96b2197e478600a46ca725ed1acfbf Reviewed-by: David Schulz --- src/plugins/python/pythonsettings.cpp | 13 ++++++------- src/plugins/python/pythonutils.cpp | 9 +++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index e5251384d2c..0a6abe2e043 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -653,17 +653,15 @@ static void addPythonsFromRegistry(QList &pythons) static void addPythonsFromPath(QList &pythons) { - const auto &env = Environment::systemEnvironment(); - if (HostOsInfo::isWindowsHost()) { - for (const FilePath &executable : env.findAllInPath("python")) { + for (const FilePath &executable : FilePath("python").searchAllInPath()) { // Windows creates empty redirector files that may interfere if (executable.toFileInfo().size() == 0) continue; if (executable.exists() && !alreadyRegistered(pythons, executable)) pythons << createInterpreter(executable, "Python from Path"); } - for (const FilePath &executable : env.findAllInPath("pythonw")) { + for (const FilePath &executable : FilePath("pythonw").searchAllInPath()) { if (executable.exists() && !alreadyRegistered(pythons, executable)) pythons << createInterpreter(executable, "Python from Path", "(Windowed)"); } @@ -672,7 +670,8 @@ static void addPythonsFromPath(QList &pythons) "python[1-9].[0-9]", "python[1-9].[1-9][0-9]", "python[1-9]"}; - for (const FilePath &path : env.path()) { + const FilePaths dirs = Environment::systemEnvironment().path(); + for (const FilePath &path : dirs) { const QDir dir(path.toString()); for (const QFileInfo &fi : dir.entryInfoList(filters)) { const FilePath executable = Utils::FilePath::fromFileInfo(fi); @@ -685,9 +684,9 @@ static void addPythonsFromPath(QList &pythons) static QString idForPythonFromPath(const QList &pythons) { - FilePath pythonFromPath = Environment::systemEnvironment().searchInPath("python3"); + FilePath pythonFromPath = FilePath("python3").searchInPath(); if (pythonFromPath.isEmpty()) - pythonFromPath = Environment::systemEnvironment().searchInPath("python"); + pythonFromPath = FilePath("python").searchInPath(); if (pythonFromPath.isEmpty()) return {}; const Interpreter &defaultInterpreter diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index bf3f683dd13..43d23a256bc 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -36,7 +36,7 @@ FilePath detectPython(const FilePath &documentPath) if (!project) project = ProjectManager::startupProject(); - Environment env = Environment::systemEnvironment(); + FilePaths dirs = Environment::systemEnvironment().path(); if (project) { if (auto target = project->activeTarget()) { @@ -44,7 +44,7 @@ FilePath detectPython(const FilePath &documentPath) if (auto interpreter = runConfig->aspect()) return interpreter->currentInterpreter().command; if (auto environmentAspect = runConfig->aspect()) - env = environmentAspect->environment(); + dirs = environmentAspect->environment().path(); } } } @@ -62,8 +62,9 @@ FilePath detectPython(const FilePath &documentPath) if (defaultInterpreter.exists()) return defaultInterpreter; - auto pythonFromPath = [=](const QString toCheck) { - for (const FilePath &python : env.findAllInPath(toCheck)) { + auto pythonFromPath = [dirs](const FilePath &toCheck) { + const FilePaths found = toCheck.searchAllInDirectories(dirs); + for (const FilePath &python : found) { // Windows creates empty redirector files that may interfere if (python.exists() && python.osType() == OsTypeWindows && python.fileSize() != 0) return python; From 6448efba0f60df938a3f739f5197bff4f440c822 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 24 May 2023 07:38:32 +0200 Subject: [PATCH 1220/1447] ADS: Fix Qbs build Change-Id: Ie7d7dba3bc8da21e65f2ff4d1c2aad534729429c Reviewed-by: hjk --- src/libs/advanceddockingsystem/advanceddockingsystem.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/advanceddockingsystem/advanceddockingsystem.qbs b/src/libs/advanceddockingsystem/advanceddockingsystem.qbs index 751449cf15d..8d758b3f7eb 100644 --- a/src/libs/advanceddockingsystem/advanceddockingsystem.qbs +++ b/src/libs/advanceddockingsystem/advanceddockingsystem.qbs @@ -33,6 +33,7 @@ QtcLibrary { "iconprovider.cpp", "iconprovider.h", "workspace.cpp", "workspace.h", "workspacedialog.cpp", "workspacedialog.h", + "workspaceinputdialog.cpp", "workspaceinputdialog.h", "workspacemodel.cpp", "workspacemodel.h", "workspaceview.cpp", "workspaceview.h", ] From a9b504311a810f90f7af71b242d7074c9dfacd22 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 24 May 2023 09:06:41 +0200 Subject: [PATCH 1221/1447] McuSupport: Fix Qbs build Change-Id: If4563f5d71b0c0100c2a7d419d3bbb4af570e1ed Reviewed-by: hjk --- src/plugins/mcusupport/mcusupport.qbs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index b0fa090b414..0587067cc64 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -20,6 +20,8 @@ QtcPlugin { files: [ "mcuabstractpackage.h", + "mcubuildstep.cpp", + "mcubuildstep.h", "mcupackage.cpp", "mcupackage.h", "mcutarget.cpp", From e26938beebd3cba828886240660a5fc9633a8da4 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 23 May 2023 12:25:47 +0200 Subject: [PATCH 1222/1447] Move handling of session menu to SessionManager Change-Id: Id2d6843eba10f7d89b078b558771989dfe34fb13 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- .../projectexplorer/projectexplorer.cpp | 62 ------------------ src/plugins/projectexplorer/session.cpp | 63 +++++++++++++++++++ src/plugins/projectexplorer/session_p.h | 10 +++ 3 files changed, 73 insertions(+), 62 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index d68b76a475c..e96ce989de5 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -69,7 +69,6 @@ #include "sanitizerparser.h" #include "selectablefilesmodel.h" #include "session.h" -#include "sessiondialog.h" #include "showineditortaskhandler.h" #include "simpleprojectwizard.h" #include "target.h" @@ -244,7 +243,6 @@ const int P_ACTION_BUILDPROJECT = 80; // Menus const char M_RECENTPROJECTS[] = "ProjectExplorer.Menu.Recent"; const char M_UNLOADPROJECTS[] = "ProjectExplorer.Menu.Unload"; -const char M_SESSION[] = "ProjectExplorer.Menu.Session"; const char M_GENERATORS[] = "ProjectExplorer.Menu.Generators"; const char RUNMENUCONTEXTMENU[] = "Project.RunMenu"; @@ -453,8 +451,6 @@ public: void unloadProjectContextMenu(); void unloadOtherProjectsContextMenu(); void closeAllProjects(); - void updateSessionMenu(); - void setSession(QAction *action); void runProjectContextMenu(RunConfiguration *rc); void savePersistentSettings(); @@ -507,12 +503,10 @@ public: void extendFolderNavigationWidgetFactory(); public: - QMenu *m_sessionMenu; QMenu *m_openWithMenu; QMenu *m_openTerminalMenu; QMultiMap m_actionMap; - QAction *m_sessionManagerAction; QAction *m_newAction; QAction *m_loadAction; ParameterAction *m_unloadAction; @@ -1157,23 +1151,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(mfile->menu(), &QMenu::aboutToShow, dd, &ProjectExplorerPluginPrivate::updateRecentProjectMenu); - // session menu - ActionContainer *msession = ActionManager::createMenu(Constants::M_SESSION); - msession->menu()->setTitle(Tr::tr("S&essions")); - msession->setOnAllDisabledBehavior(ActionContainer::Show); - mfile->addMenu(msession, Core::Constants::G_FILE_OPEN); - dd->m_sessionMenu = msession->menu(); - connect(mfile->menu(), &QMenu::aboutToShow, - dd, &ProjectExplorerPluginPrivate::updateSessionMenu); - - // session manager action - dd->m_sessionManagerAction = new QAction(Tr::tr("&Manage..."), this); - dd->m_sessionMenu->addAction(dd->m_sessionManagerAction); - dd->m_sessionMenu->addSeparator(); - cmd = ActionManager::registerAction(dd->m_sessionManagerAction, - "ProjectExplorer.ManageSessions"); - cmd->setDefaultKeySequence(QKeySequence()); - // unload action dd->m_unloadAction = new ParameterAction(Tr::tr("Close Project"), Tr::tr("Close Pro&ject \"%1\""), ParameterAction::AlwaysEnabled, this); @@ -1724,10 +1701,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er connect(buildManager, &BuildManager::buildQueueFinished, dd, &ProjectExplorerPluginPrivate::buildQueueFinished, Qt::QueuedConnection); - connect(dd->m_sessionManagerAction, - &QAction::triggered, - SessionManager::instance(), - &SessionManager::showSessionManager); connect(dd->m_newAction, &QAction::triggered, dd, &ProjectExplorerPlugin::openNewProjectDialog); connect(dd->m_loadAction, &QAction::triggered, @@ -3957,41 +3930,6 @@ void ProjectExplorerPluginPrivate::handleSetStartupProject() setStartupProject(ProjectTree::currentProject()); } -void ProjectExplorerPluginPrivate::updateSessionMenu() -{ - m_sessionMenu->clear(); - dd->m_sessionMenu->addAction(dd->m_sessionManagerAction); - dd->m_sessionMenu->addSeparator(); - auto *ag = new QActionGroup(m_sessionMenu); - connect(ag, &QActionGroup::triggered, this, &ProjectExplorerPluginPrivate::setSession); - const QString activeSession = SessionManager::activeSession(); - const bool isDefaultVirgin = SessionManager::isDefaultVirgin(); - - QStringList sessions = SessionManager::sessions(); - std::sort(std::next(sessions.begin()), sessions.end(), [](const QString &s1, const QString &s2) { - return SessionManager::lastActiveTime(s1) > SessionManager::lastActiveTime(s2); - }); - for (int i = 0; i < sessions.size(); ++i) { - const QString &session = sessions[i]; - - const QString actionText = ActionManager::withNumberAccelerator(Utils::quoteAmpersands( - session), - i + 1); - QAction *act = ag->addAction(actionText); - act->setData(session); - act->setCheckable(true); - if (session == activeSession && !isDefaultVirgin) - act->setChecked(true); - } - m_sessionMenu->addActions(ag->actions()); - m_sessionMenu->setEnabled(true); -} - -void ProjectExplorerPluginPrivate::setSession(QAction *action) -{ - SessionManager::loadSession(action->data().toString()); -} - void ProjectExplorerPlugin::setProjectExplorerSettings(const ProjectExplorerSettings &pes) { QTC_ASSERT(dd->m_projectExplorerSettings.environmentId == pes.environmentId, return); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index ceb57bd8d54..c846dd1c2c1 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include #include @@ -26,10 +28,14 @@ #include #include #include +#include #include #include +#include +#include #include +#include #include #include #include @@ -46,6 +52,7 @@ const char STARTUPSESSION_KEY[] = "ProjectExplorer/SessionToRestore"; const char LASTSESSION_KEY[] = "ProjectExplorer/StartupSession"; const char AUTO_RESTORE_SESSION_SETTINGS_KEY[] = "ProjectExplorer/Settings/AutoRestoreLastSession"; static bool kIsAutoRestoreLastSessionDefault = false; +const char M_SESSION[] = "ProjectExplorer.Menu.Session"; /*! \class ProjectExplorer::SessionManager @@ -82,6 +89,27 @@ SessionManager::SessionManager() SessionManager::saveSession(); }); + // session menu + ActionContainer *mfile = ActionManager::actionContainer(Core::Constants::M_FILE); + ActionContainer *msession = ActionManager::createMenu(M_SESSION); + msession->menu()->setTitle(Tr::tr("S&essions")); + msession->setOnAllDisabledBehavior(ActionContainer::Show); + mfile->addMenu(msession, Core::Constants::G_FILE_OPEN); + sb_d->m_sessionMenu = msession->menu(); + connect(mfile->menu(), &QMenu::aboutToShow, this, [] { sb_d->updateSessionMenu(); }); + + // session manager action + sb_d->m_sessionManagerAction = new QAction(Tr::tr("&Manage..."), this); + sb_d->m_sessionMenu->addAction(sb_d->m_sessionManagerAction); + sb_d->m_sessionMenu->addSeparator(); + Command *cmd = ActionManager::registerAction(sb_d->m_sessionManagerAction, + "ProjectExplorer.ManageSessions"); + cmd->setDefaultKeySequence(QKeySequence()); + connect(sb_d->m_sessionManagerAction, + &QAction::triggered, + SessionManager::instance(), + &SessionManager::showSessionManager); + sb_d->restoreSettings(); } @@ -395,6 +423,41 @@ void SessionManagerPrivate::setAutoRestoreLastSession(bool restore) sb_d->m_isAutoRestoreLastSession = restore; } +void SessionManagerPrivate::updateSessionMenu() +{ + // Delete group of previous actions (the actions are owned by the group and are deleted with it) + auto oldGroup = m_sessionMenu->findChild(); + if (oldGroup) + delete oldGroup; + m_sessionMenu->clear(); + + m_sessionMenu->addAction(m_sessionManagerAction); + m_sessionMenu->addSeparator(); + auto *ag = new QActionGroup(m_sessionMenu); + const QString activeSession = SessionManager::activeSession(); + const bool isDefaultVirgin = SessionManager::isDefaultVirgin(); + + QStringList sessions = SessionManager::sessions(); + std::sort(std::next(sessions.begin()), sessions.end(), [](const QString &s1, const QString &s2) { + return SessionManager::lastActiveTime(s1) > SessionManager::lastActiveTime(s2); + }); + for (int i = 0; i < sessions.size(); ++i) { + const QString &session = sessions[i]; + + const QString actionText + = ActionManager::withNumberAccelerator(Utils::quoteAmpersands(session), i + 1); + QAction *act = ag->addAction(actionText); + act->setCheckable(true); + if (session == activeSession && !isDefaultVirgin) + act->setChecked(true); + QObject::connect(act, &QAction::triggered, SessionManager::instance(), [session] { + SessionManager::loadSession(session); + }); + } + m_sessionMenu->addActions(ag->actions()); + m_sessionMenu->setEnabled(true); +} + void SessionManagerPrivate::restoreValues(const PersistentSettingsReader &reader) { const QStringList keys = reader.restoreValue(QLatin1String("valueKeys")).toStringList(); diff --git a/src/plugins/projectexplorer/session_p.h b/src/plugins/projectexplorer/session_p.h index 985dfd6661f..587e01a6a02 100644 --- a/src/plugins/projectexplorer/session_p.h +++ b/src/plugins/projectexplorer/session_p.h @@ -5,6 +5,11 @@ #include +QT_BEGIN_NAMESPACE +class QAction; +class QMenu; +QT_END_NAMESPACE + using namespace Utils; namespace ProjectExplorer { @@ -23,6 +28,8 @@ public: bool isAutoRestoreLastSession(); void setAutoRestoreLastSession(bool restore); + void updateSessionMenu(); + static QString windowTitleAddition(const FilePath &filePath); static QString sessionTitle(const FilePath &filePath); @@ -40,6 +47,9 @@ public: QMap m_sessionValues; QFutureInterface m_future; PersistentSettingsWriter *m_writer = nullptr; + + QMenu *m_sessionMenu; + QAction *m_sessionManagerAction; }; extern SessionManagerPrivate *sb_d; From 7dfc775ace49230d355c5c4f0514d154c7fd368b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 23 May 2023 10:08:16 +0200 Subject: [PATCH 1223/1447] Move session macro and saveSession trigger to SessionManager Change-Id: Ie0e07621fe9f33e69ee99f6d20bb42a8627e7729 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- .../projectexplorer/projectexplorer.cpp | 13 +----------- src/plugins/projectexplorer/session.cpp | 20 +++++++++++++++---- src/plugins/projectexplorer/session.h | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e96ce989de5..06ae144ae05 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1935,15 +1935,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er return Environment::systemEnvironment(); }}); - const auto fileHandler = [] { - return SessionManager::sessionNameToFileName(SessionManager::activeSession()); - }; - expander->registerFileVariables("Session", Tr::tr("File where current session is saved."), - fileHandler); - expander->registerVariable("Session:Name", Tr::tr("Name of current session."), [] { - return SessionManager::activeSession(); - }); - DeviceManager::instance()->addDevice(IDevice::Ptr(new DesktopDevice)); if (auto sanitizerTester = SanitizerParser::testCreator()) @@ -2204,11 +2195,9 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() if (PluginManager::isShuttingDown()) return; - if (!SessionManager::loadingSession()) { + if (!SessionManager::isLoadingSession()) { for (Project *pro : ProjectManager::projects()) pro->saveSettings(); - - SessionManager::saveSession(); } QtcSettings *s = ICore::settings(); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index c846dd1c2c1..4421e8b7049 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -27,10 +27,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -78,14 +78,18 @@ SessionManager::SessionManager() connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, &SessionManager::saveActiveMode); - connect(ICore::instance(), &ICore::saveSettingsRequested, this, [] { sb_d->saveSettings(); }); + connect(ICore::instance(), &ICore::saveSettingsRequested, this, [] { + if (!SessionManager::isLoadingSession()) + SessionManager::saveSession(); + sb_d->saveSettings(); + }); connect(EditorManager::instance(), &EditorManager::editorOpened, this, &SessionManager::markSessionFileDirty); connect(EditorManager::instance(), &EditorManager::editorsClosed, this, &SessionManager::markSessionFileDirty); connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] { - if (!PluginManager::isShuttingDown() && !SessionManager::loadingSession()) + if (!PluginManager::isShuttingDown() && !SessionManager::isLoadingSession()) SessionManager::saveSession(); }); @@ -110,6 +114,14 @@ SessionManager::SessionManager() SessionManager::instance(), &SessionManager::showSessionManager); + MacroExpander *expander = Utils::globalMacroExpander(); + expander->registerFileVariables("Session", Tr::tr("File where current session is saved."), [] { + return SessionManager::sessionNameToFileName(SessionManager::activeSession()); + }); + expander->registerVariable("Session:Name", Tr::tr("Name of current session."), [] { + return SessionManager::activeSession(); + }); + sb_d->restoreSettings(); } @@ -142,7 +154,7 @@ void SessionManager::saveActiveMode(Id mode) setValue(QLatin1String("ActiveMode"), mode.toString()); } -bool SessionManager::loadingSession() +bool SessionManager::isLoadingSession() { return sb_d->m_loadingSession; } diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 159a35f998f..0844505ae38 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -58,7 +58,7 @@ public: static void setSessionValue(const QString &name, const QVariant &value); static QVariant sessionValue(const QString &name, const QVariant &defaultValue = {}); - static bool loadingSession(); + static bool isLoadingSession(); static void markSessionFileDirty(); static void sessionLoadingProgress(); From c713e4aaa2d670184c9dc755cb2a37c31190a0ae Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 23 May 2023 14:00:01 +0200 Subject: [PATCH 1224/1447] SessionModel: Simplify data() method Change-Id: Id8f1a4e1cecb30a3ade69e7eec8a0420c1425d40 Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/plugins/projectexplorer/sessionmodel.cpp | 33 ++++++++------------ 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/plugins/projectexplorer/sessionmodel.cpp b/src/plugins/projectexplorer/sessionmodel.cpp index 960a9dbdee3..b94a7ecde0e 100644 --- a/src/plugins/projectexplorer/sessionmodel.cpp +++ b/src/plugins/projectexplorer/sessionmodel.cpp @@ -88,17 +88,16 @@ QStringList pathsWithTildeHomePath(const FilePaths &paths) QVariant SessionModel::data(const QModelIndex &index, int role) const { - QVariant result; if (index.isValid()) { QString sessionName = m_sortedSessions.at(index.row()); switch (role) { case Qt::DisplayRole: switch (index.column()) { - case 0: result = sessionName; - break; - case 1: result = SessionManager::sessionDateTime(sessionName); - break; + case 0: + return sessionName; + case 1: + return SessionManager::sessionDateTime(sessionName); } // switch (section) break; case Qt::FontRole: { @@ -111,32 +110,26 @@ QVariant SessionModel::data(const QModelIndex &index, int role) const font.setBold(true); else font.setBold(false); - result = font; - } break; + return font; + } case DefaultSessionRole: - result = SessionManager::isDefaultSession(sessionName); - break; + return SessionManager::isDefaultSession(sessionName); case LastSessionRole: - result = SessionManager::lastSession() == sessionName; - break; + return SessionManager::lastSession() == sessionName; case ActiveSessionRole: - result = SessionManager::activeSession() == sessionName; - break; + return SessionManager::activeSession() == sessionName; case ProjectsPathRole: - result = pathsWithTildeHomePath(ProjectManager::projectsForSessionName(sessionName)); - break; + return pathsWithTildeHomePath(ProjectManager::projectsForSessionName(sessionName)); case ProjectsDisplayRole: - result = pathsToBaseNames(ProjectManager::projectsForSessionName(sessionName)); - break; + return pathsToBaseNames(ProjectManager::projectsForSessionName(sessionName)); case ShortcutRole: { const Id sessionBase = SESSION_BASE_ID; if (Command *cmd = ActionManager::command(sessionBase.withSuffix(index.row() + 1))) - result = cmd->keySequence().toString(QKeySequence::NativeText); + return cmd->keySequence().toString(QKeySequence::NativeText); } break; } // switch (role) } - - return result; + return {}; } QHash SessionModel::roleNames() const From 818aeb235f4a41583f57bb80114488be045e9b00 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 23 May 2023 16:13:40 +0200 Subject: [PATCH 1225/1447] Build/Core: One line per file, sort This is easier to navigate and adapt. Change-Id: I15b99e99f2700922b8d5816adcea52e2e793ab90 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/plugins/coreplugin/CMakeLists.txt | 413 +++++++++++++++++--------- 1 file changed, 278 insertions(+), 135 deletions(-) diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index 1507b345c9a..d4a2dd164d0 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -7,152 +7,293 @@ add_qtc_plugin(Core DEPENDS Qt::PrintSupport Qt::Qml Qt::Sql Qt::Gui Qt::GuiPrivate PUBLIC_DEPENDS Aggregation ExtensionSystem Utils app_version SOURCES - actionmanager/actioncontainer.cpp actionmanager/actioncontainer.h actionmanager/actioncontainer_p.h - actionmanager/actionmanager.cpp actionmanager/actionmanager.h actionmanager/actionmanager_p.h - actionmanager/command.cpp actionmanager/command.h actionmanager/command_p.h - actionmanager/commandbutton.cpp actionmanager/commandbutton.h - actionmanager/commandmappings.cpp actionmanager/commandmappings.h - actionmanager/commandsfile.cpp actionmanager/commandsfile.h - actionsfilter.cpp actionsfilter.h - basefilewizard.cpp basefilewizard.h - basefilewizardfactory.cpp basefilewizardfactory.h ${CMAKE_CURRENT_BINARY_DIR}/core_logo_cmake.qrc + actionmanager/actioncontainer.cpp + actionmanager/actioncontainer.h + actionmanager/actioncontainer_p.h + actionmanager/actionmanager.cpp + actionmanager/actionmanager.h + actionmanager/actionmanager_p.h + actionmanager/command.cpp + actionmanager/command.h + actionmanager/command_p.h + actionmanager/commandbutton.cpp + actionmanager/commandbutton.h + actionmanager/commandmappings.cpp + actionmanager/commandmappings.h + actionmanager/commandsfile.cpp + actionmanager/commandsfile.h + actionsfilter.cpp + actionsfilter.h + basefilewizard.cpp + basefilewizard.h + basefilewizardfactory.cpp + basefilewizardfactory.h core.qrc core_global.h coreconstants.h - coreicons.cpp coreicons.h - corejsextensions.cpp corejsextensions.h - coreplugin.cpp coreplugin.h + coreicons.cpp + coreicons.h + corejsextensions.cpp + corejsextensions.h + coreplugin.cpp + coreplugin.h coreplugintr.h - designmode.cpp designmode.h - dialogs/addtovcsdialog.cpp dialogs/addtovcsdialog.h - dialogs/codecselector.cpp dialogs/codecselector.h - dialogs/externaltoolconfig.cpp dialogs/externaltoolconfig.h - dialogs/filepropertiesdialog.cpp dialogs/filepropertiesdialog.h - dialogs/ioptionspage.cpp dialogs/ioptionspage.h - dialogs/newdialog.cpp dialogs/newdialog.h - dialogs/newdialogwidget.cpp dialogs/newdialogwidget.h - dialogs/openwithdialog.cpp dialogs/openwithdialog.h - dialogs/promptoverwritedialog.cpp dialogs/promptoverwritedialog.h - dialogs/readonlyfilesdialog.cpp dialogs/readonlyfilesdialog.h - dialogs/restartdialog.cpp dialogs/restartdialog.h - dialogs/saveitemsdialog.cpp dialogs/saveitemsdialog.h - dialogs/settingsdialog.cpp dialogs/settingsdialog.h - dialogs/shortcutsettings.cpp dialogs/shortcutsettings.h - diffservice.cpp diffservice.h - documentmanager.cpp documentmanager.h - editmode.cpp editmode.h - editormanager/documentmodel.cpp editormanager/documentmodel.h editormanager/documentmodel_p.h - editormanager/editorarea.cpp editormanager/editorarea.h - editormanager/editormanager.cpp editormanager/editormanager.h editormanager/editormanager_p.h - editormanager/editorview.cpp editormanager/editorview.h - editormanager/editorwindow.cpp editormanager/editorwindow.h - editormanager/ieditor.cpp editormanager/ieditor.h - editormanager/ieditorfactory.cpp editormanager/ieditorfactory.h editormanager/ieditorfactory_p.h - editormanager/iexternaleditor.cpp editormanager/iexternaleditor.h - editormanager/openeditorsview.cpp editormanager/openeditorsview.h - editormanager/openeditorswindow.cpp editormanager/openeditorswindow.h - editormanager/systemeditor.cpp editormanager/systemeditor.h - editortoolbar.cpp editortoolbar.h - externaltool.cpp externaltool.h - externaltoolmanager.cpp externaltoolmanager.h - fancyactionbar.cpp fancyactionbar.h + designmode.cpp + designmode.h + dialogs/addtovcsdialog.cpp + dialogs/addtovcsdialog.h + dialogs/codecselector.cpp + dialogs/codecselector.h + dialogs/externaltoolconfig.cpp + dialogs/externaltoolconfig.h + dialogs/filepropertiesdialog.cpp + dialogs/filepropertiesdialog.h + dialogs/ioptionspage.cpp + dialogs/ioptionspage.h + dialogs/newdialog.cpp + dialogs/newdialog.h + dialogs/newdialogwidget.cpp + dialogs/newdialogwidget.h + dialogs/openwithdialog.cpp + dialogs/openwithdialog.h + dialogs/promptoverwritedialog.cpp + dialogs/promptoverwritedialog.h + dialogs/readonlyfilesdialog.cpp + dialogs/readonlyfilesdialog.h + dialogs/restartdialog.cpp + dialogs/restartdialog.h + dialogs/saveitemsdialog.cpp + dialogs/saveitemsdialog.h + dialogs/settingsdialog.cpp + dialogs/settingsdialog.h + dialogs/shortcutsettings.cpp + dialogs/shortcutsettings.h + diffservice.cpp + diffservice.h + documentmanager.cpp + documentmanager.h + editmode.cpp + editmode.h + editormanager/documentmodel.cpp + editormanager/documentmodel.h + editormanager/documentmodel_p.h + editormanager/editorarea.cpp + editormanager/editorarea.h + editormanager/editormanager.cpp + editormanager/editormanager.h + editormanager/editormanager_p.h + editormanager/editorview.cpp + editormanager/editorview.h + editormanager/editorwindow.cpp + editormanager/editorwindow.h + editormanager/ieditor.cpp + editormanager/ieditor.h + editormanager/ieditorfactory.cpp + editormanager/ieditorfactory.h + editormanager/ieditorfactory_p.h + editormanager/iexternaleditor.cpp + editormanager/iexternaleditor.h + editormanager/openeditorsview.cpp + editormanager/openeditorsview.h + editormanager/openeditorswindow.cpp + editormanager/openeditorswindow.h + editormanager/systemeditor.cpp + editormanager/systemeditor.h + editortoolbar.cpp + editortoolbar.h + externaltool.cpp + externaltool.h + externaltoolmanager.cpp + externaltoolmanager.h + fancyactionbar.cpp + fancyactionbar.h fancyactionbar.qrc - fancytabwidget.cpp fancytabwidget.h - featureprovider.cpp featureprovider.h - fileutils.cpp fileutils.h - find/basetextfind.cpp find/basetextfind.h - find/currentdocumentfind.cpp find/currentdocumentfind.h + fancytabwidget.cpp + fancytabwidget.h + featureprovider.cpp + featureprovider.h + fileutils.cpp + fileutils.h + find/basetextfind.cpp + find/basetextfind.h + find/currentdocumentfind.cpp + find/currentdocumentfind.h find/find.qrc - find/findplugin.cpp find/findplugin.h - find/findtoolbar.cpp find/findtoolbar.h - find/findtoolwindow.cpp find/findtoolwindow.h - find/highlightscrollbarcontroller.cpp find/highlightscrollbarcontroller.h - find/ifindfilter.cpp find/ifindfilter.h - find/ifindsupport.cpp find/ifindsupport.h - find/itemviewfind.cpp find/itemviewfind.h - find/optionspopup.cpp find/optionspopup.h - find/searchresulttreeitemdelegate.cpp find/searchresulttreeitemdelegate.h + find/findplugin.cpp + find/findplugin.h + find/findtoolbar.cpp + find/findtoolbar.h + find/findtoolwindow.cpp + find/findtoolwindow.h + find/highlightscrollbarcontroller.cpp + find/highlightscrollbarcontroller.h + find/ifindfilter.cpp + find/ifindfilter.h + find/ifindsupport.cpp + find/ifindsupport.h + find/itemviewfind.cpp + find/itemviewfind.h + find/optionspopup.cpp + find/optionspopup.h + find/searchresulttreeitemdelegate.cpp + find/searchresulttreeitemdelegate.h find/searchresulttreeitemroles.h - find/searchresulttreeitems.cpp find/searchresulttreeitems.h - find/searchresulttreemodel.cpp find/searchresulttreemodel.h - find/searchresulttreeview.cpp find/searchresulttreeview.h - find/searchresultwidget.cpp find/searchresultwidget.h - find/searchresultwindow.cpp find/searchresultwindow.h + find/searchresulttreeitems.cpp + find/searchresulttreeitems.h + find/searchresulttreemodel.cpp + find/searchresulttreemodel.h + find/searchresulttreeview.cpp + find/searchresulttreeview.h + find/searchresultwidget.cpp + find/searchresultwidget.h + find/searchresultwindow.cpp + find/searchresultwindow.h find/textfindconstants.h - findplaceholder.cpp findplaceholder.h + findplaceholder.cpp + findplaceholder.h foldernavigationwidget.cpp foldernavigationwidget.h - generalsettings.cpp generalsettings.h - generatedfile.cpp generatedfile.h - helpitem.cpp helpitem.h - helpmanager.cpp helpmanager.h helpmanager_implementation.h - icontext.cpp icontext.h - icore.cpp icore.h - idocument.cpp idocument.h - idocumentfactory.cpp idocumentfactory.h + generalsettings.cpp + generalsettings.h + generatedfile.cpp + generatedfile.h + helpitem.cpp + helpitem.h + helpmanager.cpp + helpmanager.h + helpmanager_implementation.h + icontext.cpp + icontext.h + icore.cpp + icore.h + idocument.cpp + idocument.h + idocumentfactory.cpp + idocumentfactory.h ifilewizardextension.h - imode.cpp imode.h - inavigationwidgetfactory.cpp inavigationwidgetfactory.h - ioutputpane.cpp ioutputpane.h - iversioncontrol.cpp iversioncontrol.h - iwelcomepage.cpp iwelcomepage.h - iwizardfactory.cpp iwizardfactory.h - jsexpander.cpp jsexpander.h - locator/commandlocator.cpp locator/commandlocator.h - locator/directoryfilter.cpp locator/directoryfilter.h - locator/executefilter.cpp locator/executefilter.h - locator/externaltoolsfilter.cpp locator/externaltoolsfilter.h - locator/filesystemfilter.cpp locator/filesystemfilter.h - locator/ilocatorfilter.cpp locator/ilocatorfilter.h - locator/javascriptfilter.cpp locator/javascriptfilter.h - locator/locator.cpp locator/locator.h + imode.cpp + imode.h + inavigationwidgetfactory.cpp + inavigationwidgetfactory.h + ioutputpane.cpp + ioutputpane.h + iversioncontrol.cpp + iversioncontrol.h + iwelcomepage.cpp + iwelcomepage.h + iwizardfactory.cpp + iwizardfactory.h + jsexpander.cpp + jsexpander.h + locator/commandlocator.cpp + locator/commandlocator.h + locator/directoryfilter.cpp + locator/directoryfilter.h + locator/executefilter.cpp + locator/executefilter.h + locator/externaltoolsfilter.cpp + locator/externaltoolsfilter.h + locator/filesystemfilter.cpp + locator/filesystemfilter.h + locator/ilocatorfilter.cpp + locator/ilocatorfilter.h + locator/javascriptfilter.cpp + locator/javascriptfilter.h + locator/locator.cpp + locator/locator.h locator/locatorconstants.h - locator/locatorfiltersfilter.cpp locator/locatorfiltersfilter.h - locator/locatormanager.cpp locator/locatormanager.h - locator/locatorsettingspage.cpp locator/locatorsettingspage.h - locator/locatorwidget.cpp locator/locatorwidget.h - locator/opendocumentsfilter.cpp locator/opendocumentsfilter.h - locator/spotlightlocatorfilter.h locator/spotlightlocatorfilter.cpp - locator/urllocatorfilter.cpp locator/urllocatorfilter.h - loggingviewer.cpp loggingviewer.h - loggingmanager.cpp loggingmanager.h - mainwindow.cpp mainwindow.h - manhattanstyle.cpp manhattanstyle.h - messagebox.cpp messagebox.h - messagemanager.cpp messagemanager.h - messageoutputwindow.cpp messageoutputwindow.h - mimetypemagicdialog.cpp mimetypemagicdialog.h - mimetypesettings.cpp mimetypesettings.h - minisplitter.cpp minisplitter.h - modemanager.cpp modemanager.h - navigationsubwidget.cpp navigationsubwidget.h - navigationwidget.cpp navigationwidget.h - opendocumentstreeview.cpp opendocumentstreeview.h - outputpane.cpp outputpane.h - outputpanemanager.cpp outputpanemanager.h - outputwindow.cpp outputwindow.h - patchtool.cpp patchtool.h - plugindialog.cpp plugindialog.h - plugininstallwizard.cpp plugininstallwizard.h - progressmanager/futureprogress.cpp progressmanager/futureprogress.h - progressmanager/processprogress.cpp progressmanager/processprogress.h - progressmanager/progressbar.cpp progressmanager/progressbar.h - progressmanager/progressmanager.cpp progressmanager/progressmanager.h progressmanager/progressmanager_p.h - progressmanager/progressview.cpp progressmanager/progressview.h - progressmanager/taskprogress.cpp progressmanager/taskprogress.h - rightpane.cpp rightpane.h - settingsdatabase.cpp settingsdatabase.h - sidebar.cpp sidebar.h - sidebarwidget.cpp sidebarwidget.h - statusbarmanager.cpp statusbarmanager.h - systemsettings.cpp systemsettings.h - textdocument.cpp textdocument.h - themechooser.cpp themechooser.h - vcsmanager.cpp vcsmanager.h - versiondialog.cpp versiondialog.h - welcomepagehelper.cpp welcomepagehelper.h - windowsupport.cpp windowsupport.h + locator/locatorfiltersfilter.cpp + locator/locatorfiltersfilter.h + locator/locatormanager.cpp + locator/locatormanager.h + locator/locatorsettingspage.cpp + locator/locatorsettingspage.h + locator/locatorwidget.cpp + locator/locatorwidget.h + locator/opendocumentsfilter.cpp + locator/opendocumentsfilter.h + locator/spotlightlocatorfilter.cpp + locator/spotlightlocatorfilter.h + locator/urllocatorfilter.cpp + locator/urllocatorfilter.h + loggingmanager.cpp + loggingmanager.h + loggingviewer.cpp + loggingviewer.h + mainwindow.cpp + mainwindow.h + manhattanstyle.cpp + manhattanstyle.h + messagebox.cpp + messagebox.h + messagemanager.cpp + messagemanager.h + messageoutputwindow.cpp + messageoutputwindow.h + mimetypemagicdialog.cpp + mimetypemagicdialog.h + mimetypesettings.cpp + mimetypesettings.h + minisplitter.cpp + minisplitter.h + modemanager.cpp + modemanager.h + navigationsubwidget.cpp + navigationsubwidget.h + navigationwidget.cpp + navigationwidget.h + opendocumentstreeview.cpp + opendocumentstreeview.h + outputpane.cpp + outputpane.h + outputpanemanager.cpp + outputpanemanager.h + outputwindow.cpp + outputwindow.h + patchtool.cpp + patchtool.h + plugindialog.cpp + plugindialog.h + plugininstallwizard.cpp + plugininstallwizard.h + progressmanager/futureprogress.cpp + progressmanager/futureprogress.h + progressmanager/processprogress.cpp + progressmanager/processprogress.h + progressmanager/progressbar.cpp + progressmanager/progressbar.h + progressmanager/progressmanager.cpp + progressmanager/progressmanager.h + progressmanager/progressmanager_p.h + progressmanager/progressview.cpp + progressmanager/progressview.h + progressmanager/taskprogress.cpp + progressmanager/taskprogress.h + rightpane.cpp + rightpane.h + settingsdatabase.cpp + settingsdatabase.h + sidebar.cpp + sidebar.h + sidebarwidget.cpp + sidebarwidget.h + statusbarmanager.cpp + statusbarmanager.h + systemsettings.cpp + systemsettings.h + textdocument.cpp + textdocument.h + themechooser.cpp + themechooser.h + vcsmanager.cpp + vcsmanager.h + versiondialog.cpp + versiondialog.h + welcomepagehelper.cpp + welcomepagehelper.h + windowsupport.cpp + windowsupport.h EXPLICIT_MOC dialogs/filepropertiesdialog.h ) @@ -165,8 +306,10 @@ extend_qtc_plugin(Core CONDITION WITH_TESTS SOURCES locator/locator_test.cpp - locator/locatorfiltertest.cpp locator/locatorfiltertest.h - testdatadir.cpp testdatadir.h + locator/locatorfiltertest.cpp + locator/locatorfiltertest.h + testdatadir.cpp + testdatadir.h ) extend_qtc_plugin(Core From 49b023844654b8ed32afa5014788414a74842fe9 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 16:47:28 +0200 Subject: [PATCH 1226/1447] Python: Move PySideBuildConfiguration to .cpp Not publicly needed and closer to the generic pattern. Change-Id: I886f95c24b957b8d3943cd115814bceb6a76b651 Reviewed-by: David Schulz --- .../python/pysidebuildconfiguration.cpp | 49 +++++++++++-------- src/plugins/python/pysidebuildconfiguration.h | 18 +++---- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/plugins/python/pysidebuildconfiguration.cpp b/src/plugins/python/pysidebuildconfiguration.cpp index eae9b4eeeae..3285493e0a3 100644 --- a/src/plugins/python/pysidebuildconfiguration.cpp +++ b/src/plugins/python/pysidebuildconfiguration.cpp @@ -23,20 +23,6 @@ namespace Python::Internal { const char pySideBuildStep[] = "Python.PysideBuildStep"; -PySideBuildConfigurationFactory::PySideBuildConfigurationFactory() -{ - registerBuildConfiguration("Python.PySideBuildConfiguration"); - setSupportedProjectType(PythonProjectId); - setSupportedProjectMimeTypeName(Constants::C_PY_MIMETYPE); - setBuildGenerator([](const Kit *, const FilePath &projectPath, bool) { - BuildInfo info; - info.displayName = "build"; - info.typeName = "build"; - info.buildDirectory = projectPath.parentDir(); - return QList{info}; - }); -} - PySideBuildStepFactory::PySideBuildStepFactory() { registerStep(pySideBuildStep); @@ -83,17 +69,38 @@ void PySideBuildStep::doRun() emit finished(true); } -PySideBuildConfiguration::PySideBuildConfiguration(Target *target, Id id) - : BuildConfiguration(target, id) + +// PySideBuildConfiguration + +class PySideBuildConfiguration : public BuildConfiguration { - setConfigWidgetDisplayName(Tr::tr("General")); +public: + PySideBuildConfiguration(Target *target, Id id) + : BuildConfiguration(target, id) + { + setConfigWidgetDisplayName(Tr::tr("General")); + + setInitializer([this](const BuildInfo &) { + buildSteps()->appendStep(pySideBuildStep); + updateCacheAndEmitEnvironmentChanged(); + }); - setInitializer([this](const BuildInfo &) { - buildSteps()->appendStep(pySideBuildStep); updateCacheAndEmitEnvironmentChanged(); - }); + } +}; - updateCacheAndEmitEnvironmentChanged(); +PySideBuildConfigurationFactory::PySideBuildConfigurationFactory() +{ + registerBuildConfiguration("Python.PySideBuildConfiguration"); + setSupportedProjectType(PythonProjectId); + setSupportedProjectMimeTypeName(Constants::C_PY_MIMETYPE); + setBuildGenerator([](const Kit *, const FilePath &projectPath, bool) { + BuildInfo info; + info.displayName = "build"; + info.typeName = "build"; + info.buildDirectory = projectPath.parentDir(); + return QList{info}; + }); } } // Python::Internal diff --git a/src/plugins/python/pysidebuildconfiguration.h b/src/plugins/python/pysidebuildconfiguration.h index 17022c6be2b..8a04568d70a 100644 --- a/src/plugins/python/pysidebuildconfiguration.h +++ b/src/plugins/python/pysidebuildconfiguration.h @@ -9,18 +9,6 @@ namespace Python::Internal { -class PySideBuildConfiguration : public ProjectExplorer::BuildConfiguration -{ -public: - PySideBuildConfiguration(ProjectExplorer::Target *target, Utils::Id id); -}; - -class PySideBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory -{ -public: - PySideBuildConfigurationFactory(); -}; - class PySideBuildStep : public ProjectExplorer::AbstractProcessStep { Q_OBJECT @@ -41,4 +29,10 @@ public: PySideBuildStepFactory(); }; +class PySideBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory +{ +public: + PySideBuildConfigurationFactory(); +}; + } // Python::Internal From b2c69b947f6d81e11b1eabadc7f67cded8805774 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 16:54:11 +0200 Subject: [PATCH 1227/1447] Python: Adapt PySideBuildStep to recent FilePath{Aspect} changes Change-Id: I866b49733f3007e4f029fb25f8519a1c5b690370 Reviewed-by: David Schulz --- .../python/pysidebuildconfiguration.cpp | 29 +++++++++---------- src/plugins/python/pysidebuildconfiguration.h | 5 ++-- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/plugins/python/pysidebuildconfiguration.cpp b/src/plugins/python/pysidebuildconfiguration.cpp index 3285493e0a3..7163dc7b6a6 100644 --- a/src/plugins/python/pysidebuildconfiguration.cpp +++ b/src/plugins/python/pysidebuildconfiguration.cpp @@ -34,31 +34,30 @@ PySideBuildStepFactory::PySideBuildStepFactory() PySideBuildStep::PySideBuildStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id) { - m_pysideProject = addAspect(); - m_pysideProject->setSettingsKey("Python.PySideProjectTool"); - m_pysideProject->setLabelText(Tr::tr("PySide project tool:")); - m_pysideProject->setToolTip(Tr::tr("Enter location of PySide project tool.")); - m_pysideProject->setDisplayStyle(StringAspect::PathChooserDisplay); - m_pysideProject->setExpectedKind(PathChooser::Command); - m_pysideProject->setHistoryCompleter("Python.PySideProjectTool.History"); + setOwnsSubAspects(false); - const FilePath pySideProjectPath = Environment::systemEnvironment().searchInPath( - "pyside6-project"); + m_pysideProject.setSettingsKey("Python.PySideProjectTool"); + m_pysideProject.setLabelText(Tr::tr("PySide project tool:")); + m_pysideProject.setToolTip(Tr::tr("Enter location of PySide project tool.")); + m_pysideProject.setExpectedKind(PathChooser::Command); + m_pysideProject.setHistoryCompleter("Python.PySideProjectTool.History"); + + const FilePath pySideProjectPath = FilePath("pyside6-project").searchInPath(); if (pySideProjectPath.isExecutableFile()) - m_pysideProject->setFilePath(pySideProjectPath); + m_pysideProject.setFilePath(pySideProjectPath); - setCommandLineProvider([this] { return CommandLine(m_pysideProject->filePath(), {"build"}); }); + setCommandLineProvider([this] { return CommandLine(m_pysideProject(), {"build"}); }); setWorkingDirectoryProvider([this] { - return m_pysideProject->filePath().withNewMappedPath(target()->project()->projectDirectory()); // FIXME: new path needed? + return m_pysideProject().withNewMappedPath(project()->projectDirectory()); // FIXME: new path needed? }); setEnvironmentModifier([this](Environment &env) { - env.prependOrSetPath(m_pysideProject->filePath().parentDir()); + env.prependOrSetPath(m_pysideProject().parentDir()); }); } -void PySideBuildStep::updatePySideProjectPath(const Utils::FilePath &pySideProjectPath) +void PySideBuildStep::updatePySideProjectPath(const FilePath &pySideProjectPath) { - m_pysideProject->setFilePath(pySideProjectPath); + m_pysideProject.setFilePath(pySideProjectPath); } void PySideBuildStep::doRun() diff --git a/src/plugins/python/pysidebuildconfiguration.h b/src/plugins/python/pysidebuildconfiguration.h index 8a04568d70a..e686b9c2220 100644 --- a/src/plugins/python/pysidebuildconfiguration.h +++ b/src/plugins/python/pysidebuildconfiguration.h @@ -16,11 +16,10 @@ public: PySideBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); void updatePySideProjectPath(const Utils::FilePath &pySideProjectPath); -private: - Utils::StringAspect *m_pysideProject; - private: void doRun() override; + + Utils::FilePathAspect m_pysideProject{this}; }; class PySideBuildStepFactory : public ProjectExplorer::BuildStepFactory From 29d3a1aef2545bb65dd3b09d93d999ccde756954 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 24 May 2023 08:56:23 +0200 Subject: [PATCH 1228/1447] QmlProjectManager: Fix Qbs build on Windows Change-Id: I58057e88293017ece5d0026e2b2708e6d3f48d30 Reviewed-by: David Schulz --- src/plugins/qmlprojectmanager/qmlprojectmanager.qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs index 2ab9417704e..9e6f3babd0b 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs +++ b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs @@ -39,7 +39,7 @@ QtcPlugin { "qmlbuildsystem.cpp", "qmlbuildsystem.h", "projectitem/filefilteritems.cpp", "projectitem/filefilteritems.h", "projectitem/qmlprojectitem.cpp", "projectitem/qmlprojectitem.h", - "projectitem/converters.h", + "projectitem/converters.cpp", "projectitem/converters.h", "projectnode/qmlprojectnodes.cpp", "projectnode/qmlprojectnodes.h" ] } From c124e837c589668e18054ae5c609ef5f77b4042f Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 24 May 2023 09:36:35 +0200 Subject: [PATCH 1229/1447] Doc: Add docs for Utils::Environment::systemEnvironment() Because we link to it from the Utils namespace docs. Change-Id: I4d320b34687e7a6304cbedcbf7e2e5d3a43642b6 Reviewed-by: Eike Ziller --- src/libs/utils/environment.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 977e63adb06..a65a48aa679 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -12,6 +12,13 @@ #include #include +/*! + \class Utils::Environment + \inmodule QtCreator + + \brief The Environment class sets \QC's system environment. +*/ + namespace Utils { static QReadWriteLock s_envMutex; @@ -184,6 +191,14 @@ void Environment::prependOrSetLibrarySearchPaths(const FilePaths &values) }); } +/*! + Returns \QC's system environment. + + This can be different from the system environment that \QC started in if the + user changed it in \uicontrol Preferences > \uicontrol Environment > + \uicontrol System > \uicontrol Environment. +*/ + Environment Environment::systemEnvironment() { QReadLocker lock(&s_envMutex); From aace4c44fa71d7a66bcdbf79cea82a1b0c24cd32 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 24 May 2023 09:16:59 +0200 Subject: [PATCH 1230/1447] ProjectExplorer: Placeholder for custom executable Previously when creating a custom executable run config, the path chooser would display a red "". This improves the message to tell the user whats needed. Change-Id: Ib521cde1a4f5b836cb865428f65f956a63bce3b4 Reviewed-by: Leena Miettinen Reviewed-by: Marcus Tillmanns Reviewed-by: hjk --- src/plugins/projectexplorer/runconfigurationaspects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 8098606afb0..ce28582d558 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -502,7 +502,7 @@ ExecutableAspect::ExecutableAspect(Target *target, ExecutionDeviceSelector selec setId("ExecutableAspect"); addDataExtractor(this, &ExecutableAspect::executable, &Data::executable); - m_executable.setPlaceHolderText(Tr::tr("")); + m_executable.setPlaceHolderText(Tr::tr("path to the executable cannot be empty")); m_executable.setLabelText(Tr::tr("Executable:")); m_executable.setDisplayStyle(StringAspect::LabelDisplay); From d9f6537c43e3efb10dda4b299553109298814b1c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 14:24:16 +0200 Subject: [PATCH 1231/1447] Beautifier: De-QObjectify AbstractSettings Change-Id: Id5045f48c52c7304dc440bb2c83082cc7e628143 Reviewed-by: Alessandro Portale --- src/plugins/beautifier/abstractsettings.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/beautifier/abstractsettings.h b/src/plugins/beautifier/abstractsettings.h index 5eb930396ee..3ef47ac35b1 100644 --- a/src/plugins/beautifier/abstractsettings.h +++ b/src/plugins/beautifier/abstractsettings.h @@ -8,15 +8,12 @@ #include #include -#include #include #include #include -#include #include #include #include -#include #include @@ -33,8 +30,6 @@ class VersionUpdater; class AbstractSettings : public Utils::AspectContainer { - Q_OBJECT - public: explicit AbstractSettings(const QString &name, const QString &ending); ~AbstractSettings() override; From 06b276f68fdcaed075a0fd6f761e735ac3d7f921 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 16:13:11 +0200 Subject: [PATCH 1232/1447] McuSupport: Use new FilePathAspect for FilePaths Change-Id: I98cb17f39af624f1ec06529932d4e52cda5a3661 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/mcusupport/mcubuildstep.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/mcusupport/mcubuildstep.cpp b/src/plugins/mcusupport/mcubuildstep.cpp index a26e8ed0d1e..86f5e8af7e6 100644 --- a/src/plugins/mcusupport/mcubuildstep.cpp +++ b/src/plugins/mcusupport/mcubuildstep.cpp @@ -58,9 +58,8 @@ DeployMcuProcessStep::DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, U QString root = findKitInformation(kit, Internal::Legacy::Constants::QUL_CMAKE_VAR); auto rootPath = Utils::FilePath::fromString(root); - auto cmd = addAspect(); + auto cmd = addAspect(); cmd->setSettingsKey("QmlProject.Mcu.ProcessStep.Command"); - cmd->setDisplayStyle(Utils::StringAspect::PathChooserDisplay); cmd->setExpectedKind(Utils::PathChooser::Command); cmd->setLabelText(QmlProjectManager::Tr::tr("Command:")); cmd->setFilePath(rootPath.pathAppended("/bin/qmlprojectexporter")); @@ -87,9 +86,8 @@ DeployMcuProcessStep::DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, U args->setLabelText(QmlProjectManager::Tr::tr("Arguments:")); args->setValue(Utils::ProcessArgs::joinArgs(arguments)); - auto outDir = addAspect(); + auto outDir = addAspect(); outDir->setSettingsKey("QmlProject.Mcu.ProcessStep.BuildDirectory"); - outDir->setDisplayStyle(Utils::StringAspect::PathChooserDisplay); outDir->setExpectedKind(Utils::PathChooser::Directory); outDir->setLabelText(QmlProjectManager::Tr::tr("Build directory:")); outDir->setPlaceHolderText(m_tmpDir.path()); From beea9ec157e7fa6b9a4562d94f28d29d2e715e8a Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 16:23:17 +0200 Subject: [PATCH 1233/1447] McuSupport: Move McuBuildStep to .cpp Not needed publicly. Change-Id: I0e8ddd3e260fb87bedc9ea1478e440e99bd2e203 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/mcusupport/mcubuildstep.cpp | 34 ++++++++++++++++++------- src/plugins/mcusupport/mcubuildstep.h | 22 ++-------------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/plugins/mcusupport/mcubuildstep.cpp b/src/plugins/mcusupport/mcubuildstep.cpp index 86f5e8af7e6..3b0c639df5e 100644 --- a/src/plugins/mcusupport/mcubuildstep.cpp +++ b/src/plugins/mcusupport/mcubuildstep.cpp @@ -2,18 +2,21 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "mcubuildstep.h" + #include "mcukitmanager.h" #include "mculegacyconstants.h" #include "mcusupportconstants.h" #include -#include +#include #include #include #include #include +#include #include +#include #include #include #include @@ -23,12 +26,25 @@ #include #include -#include +#include #include namespace McuSupport::Internal { +class DeployMcuProcessStep : public ProjectExplorer::AbstractProcessStep +{ +public: + static const Utils::Id id; + static void showError(const QString &text); + + DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, Utils::Id id); + +private: + QString findKitInformation(ProjectExplorer::Kit *kit, const QString &key); + QTemporaryDir m_tmpDir; +}; + const Utils::Id DeployMcuProcessStep::id = "QmlProject.Mcu.DeployStep"; void DeployMcuProcessStep::showError(const QString &text) @@ -117,13 +133,6 @@ QString DeployMcuProcessStep::findKitInformation(ProjectExplorer::Kit *kit, cons return {}; } -MCUBuildStepFactory::MCUBuildStepFactory() - : BuildStepFactory() -{ - setDisplayName(QmlProjectManager::Tr::tr("Qt for MCUs Deploy Step")); - registerStep(DeployMcuProcessStep::id); -} - ProjectExplorer::Kit *MCUBuildStepFactory::findMostRecentQulKit() { ProjectExplorer::Kit *mcuKit = nullptr; @@ -166,4 +175,11 @@ void MCUBuildStepFactory::updateDeployStep(ProjectExplorer::Target *target, bool } } + +MCUBuildStepFactory::MCUBuildStepFactory() +{ + setDisplayName(QmlProjectManager::Tr::tr("Qt for MCUs Deploy Step")); + registerStep(DeployMcuProcessStep::id); +} + } // namespace McuSupport::Internal diff --git a/src/plugins/mcusupport/mcubuildstep.h b/src/plugins/mcusupport/mcubuildstep.h index aebca09eba8..5a202336d7a 100644 --- a/src/plugins/mcusupport/mcubuildstep.h +++ b/src/plugins/mcusupport/mcubuildstep.h @@ -1,35 +1,17 @@ // Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + #pragma once -#include #include -#include -#include - -#include - -#include namespace McuSupport::Internal { -class DeployMcuProcessStep : public ProjectExplorer::AbstractProcessStep -{ -public: - static const Utils::Id id; - static void showError(const QString &text); - - DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, Utils::Id id); - -private: - QString findKitInformation(ProjectExplorer::Kit *kit, const QString &key); - QTemporaryDir m_tmpDir; -}; - class MCUBuildStepFactory : public ProjectExplorer::BuildStepFactory { public: MCUBuildStepFactory(); + static ProjectExplorer::Kit *findMostRecentQulKit(); static void updateDeployStep(ProjectExplorer::Target *target, bool enabled); }; From bc9e90f8b602ace7a3b2258ce72018ea285aab14 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 24 May 2023 10:09:22 +0200 Subject: [PATCH 1234/1447] LanguageClient: add projects filter function Can be used to filter projects get reported to the language client on server startup and when a project gets opened. Change-Id: I8cfbc45ecb5251fcaecf2c331a9f1eff966c8db1 Reviewed-by: Marcus Tillmanns --- src/plugins/languageclient/client.cpp | 21 +++++++++++++++------ src/plugins/languageclient/client.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 5b0fbfa304f..9d2356a9d4d 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -511,11 +511,13 @@ void Client::initialize() if (d->m_project) params.setRootUri(hostPathToServerUri(d->m_project->projectDirectory())); + auto projectFilter = [this](Project *project) { return canOpenProject(project); }; + auto toWorkSpaceFolder = [this](Project *pro) { + return WorkSpaceFolder(hostPathToServerUri(pro->projectDirectory()), pro->displayName()); + }; const QList workspaces - = Utils::transform(ProjectManager::projects(), [this](Project *pro) { - return WorkSpaceFolder(hostPathToServerUri(pro->projectDirectory()), - pro->displayName()); - }); + = Utils::transform(Utils::filtered(ProjectManager::projects(), projectFilter), + toWorkSpaceFolder); if (workspaces.isEmpty()) params.setWorkSpaceFolders(nullptr); else @@ -1353,6 +1355,7 @@ ProjectExplorer::Project *Client::project() const void Client::setCurrentProject(ProjectExplorer::Project *project) { + QTC_ASSERT(canOpenProject(project), return); if (d->m_project == project) return; if (d->m_project) @@ -1369,7 +1372,7 @@ void Client::setCurrentProject(ProjectExplorer::Project *project) void Client::projectOpened(ProjectExplorer::Project *project) { - if (!d->sendWorkspceFolderChanges()) + if (!d->sendWorkspceFolderChanges() || !canOpenProject(project)) return; WorkspaceFoldersChangeEvent event; event.setAdded({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()), @@ -1382,7 +1385,7 @@ void Client::projectOpened(ProjectExplorer::Project *project) void Client::projectClosed(ProjectExplorer::Project *project) { - if (d->sendWorkspceFolderChanges()) { + if (d->sendWorkspceFolderChanges() && canOpenProject(project)) { WorkspaceFoldersChangeEvent event; event.setRemoved({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()), project->displayName())}); @@ -1402,6 +1405,12 @@ void Client::projectClosed(ProjectExplorer::Project *project) } } +bool Client::canOpenProject(ProjectExplorer::Project *project) +{ + Q_UNUSED(project); + return true; +} + void Client::updateConfiguration(const QJsonValue &configuration) { d->m_configuration = configuration; diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 27f48abc415..2ddd155a9f1 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -132,6 +132,7 @@ public: ProjectExplorer::Project *project() const; virtual void projectOpened(ProjectExplorer::Project *project); virtual void projectClosed(ProjectExplorer::Project *project); + virtual bool canOpenProject(ProjectExplorer::Project *project); void updateConfiguration(const QJsonValue &configuration); // commands From caa85795dfff9c0b02aa1d6bd3a65a05662c48be Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 27 Mar 2023 14:32:01 +0200 Subject: [PATCH 1235/1447] AutoTest: Provide wizard for adding a test case Task-number: QTCREATORBUG-28846 Change-Id: I6716540b8bf62479bf45d16230ec91f0ed157001 Reviewed-by: David Schulz Reviewed-by: Leena Miettinen --- .../templates/wizards/files/testing/file.cpp | 35 +++++ .../wizards/files/testing/wizard.json | 146 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 share/qtcreator/templates/wizards/files/testing/file.cpp create mode 100644 share/qtcreator/templates/wizards/files/testing/wizard.json diff --git a/share/qtcreator/templates/wizards/files/testing/file.cpp b/share/qtcreator/templates/wizards/files/testing/file.cpp new file mode 100644 index 00000000000..e515339e2db --- /dev/null +++ b/share/qtcreator/templates/wizards/files/testing/file.cpp @@ -0,0 +1,35 @@ +%{Cpp:LicenseTemplate} +@if "%{TestFrameWork}" == "GTest" +#include +#include + +using namespace testing; + +TEST(%{TestSuiteName}, %{TestCaseName}) +{ + EXPECT_EQ(1, 1); + ASSERT_THAT(0, Eq(0)); +} + +@endif +@if "%{TestFrameWork}" == "BoostTest" +#define BOOST_TEST_DYN_LINK +#include +BOOST_AUTO_TEST_SUITE( %{TestSuiteName} ) + +BOOST_AUTO_TEST_CASE( %{TestCaseName} ) +{ + BOOST_TEST( true /* test assertion */ ); +} + +BOOST_AUTO_TEST_SUITE_END() +@endif +@if "%{TestFrameWork}" == "Catch2" +#include + +TEST_CASE("Another test with Catch2", "[fancy]") +{ + REQUIRE(0 == 0); +} + +@endif diff --git a/share/qtcreator/templates/wizards/files/testing/wizard.json b/share/qtcreator/templates/wizards/files/testing/wizard.json new file mode 100644 index 00000000000..34170434bea --- /dev/null +++ b/share/qtcreator/templates/wizards/files/testing/wizard.json @@ -0,0 +1,146 @@ +{ + "version": 1, + "supportedProjectTypes": [ ], + "id": "M.TestCase", + "category": "X.Testing", + "trDescription": "Creates a source file that you can add to an existing test project.", + "trDisplayName": "Test Case", + "trDisplayCategory": "Test Case", + "icon": "../../autotest/autotest.png", + "iconKind": "Themed", + "enabled": "%{JS: value('Plugins').indexOf('AutoTest') >= 0}", + + "options": [ + { "key": "TargetPath", "value": "%{Path}" }, + { "key": "QmlFileName", "value": "%{JS: Util.fileName(value('QmlSrcFile').startsWith('tst_') ? value('QmlSrcFile') : 'tst_' + value('QmlSrcFile'), '.qml')}" }, + { "key": "CppFileName", "value": "%{JS: Util.fileName(value('CppSrcFile'), Util.preferredSuffix('text/x-c++src'))}" } + ], + + "pages" : + [ + { + "trDisplayName": "Test Information", + "trShortTitle": "Details", + "typeId": "Fields", + "data": + [ + { + "name": "info", + "type": "Label", + "data": + { + "wordWrap": true, + "trText": "You must tell Qt Creator which test framework is used inside the project.\n\nYou should not mix multiple test frameworks in a project." + } + }, + { + "name": "TestFrameWork", + "trDisplayName": "Test framework:", + "type": "ComboBox", + "data": + { + "index": 0, + "items": + [ + { + "trKey": "Google Test", + "value": "GTest" + }, + { + "trKey": "Qt Quick Test", + "value": "QtQuickTest" + }, + { + "trKey": "Boost Test", + "value": "BoostTest" + }, + { + "trKey": "Catch2", + "value": "Catch2" + } + ] + } + }, + { + "name": "TestSuiteName", + "trDisplayName": "Test suite name:", + "visible": "%{JS: ['BoostTest', 'GTest'].indexOf(value('TestFrameWork')) >= 0}", + "mandatory": true, + "type": "LineEdit", + "data": { "validator": "^[a-zA-Z_0-9]+$" } + }, + { + "name": "TestCaseName", + "trDisplayName": "Test case name:", + "mandatory": true, + "type": "LineEdit", + "data": { "validator": "^[a-zA-Z_0-9]+$" } + }, + { + "name": "GenerateInitAndCleanup", + "trDisplayName": "Generate initialization and cleanup code", + "visible": "%{JS: value('TestFrameWork') === 'QtQuickTest' }", + "type": "CheckBox", + "data": { + "checked": false + } + }, + { + "name": "CppSrcFile", + "type": "LineEdit", + "trDisplayName": "Source file:", + "mandatory": true, + "visible": "%{JS: value('TestFrameWork') !== 'QtQuickTest' }", + "data": { "trText": "%{JS: 'tst_' + value('TestCaseName').toLowerCase() + '.' + Util.preferredSuffix('text/x-c++src')}" } + }, + { + "name": "QmlSrcFile", + "type": "LineEdit", + "trDisplayName": "Source file:", + "mandatory": true, + "visible": "%{JS: value('TestFrameWork') === 'QtQuickTest' }", + "data": { "trText": "%{JS: 'tst_' + value('TestCaseName').toLowerCase() + '.qml'}" } + }, + { + "name": "Path", + "type": "PathChooser", + "trDisplayName": "Path:", + "mandatory": true, + "data": + { + "kind": "directory", + "basePath": "%{InitialPath}", + "path": "%{InitialPath}" + } + } + ] + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators" : + [ + { + "typeId": "File", + "data": + [ + { + "source": "file.cpp", + "target": "%{CppFileName}", + "condition": "%{JS: value('TestFrameWork') !== 'QtQuickTest'}", + "openInEditor": true, + "options": { "key": "Cpp:License:FileName", "value": "%{CppFileName}" } + }, + { + "source": "../../autotest/files/tst_qml.tmpl", + "target": "%{QmlFileName}", + "condition": "%{JS: value('TestFrameWork') === 'QtQuickTest'}", + "openInEditor": true + } + ] + } + ] +} From 080c5e82d2d6b14eff57c6d588f4f3d3279dc7d5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 15 May 2023 10:43:54 +0200 Subject: [PATCH 1236/1447] Squish: Handle children for picked object Change-Id: I39f392f4f619238b79e60d423dcb5ae36a9639a4 Reviewed-by: David Schulz --- src/plugins/squish/squishperspective.cpp | 39 ++++++++++++++++------ src/plugins/squish/squishperspective.h | 2 ++ src/plugins/squish/squishrunnerprocess.cpp | 2 +- src/plugins/squish/squishrunnerprocess.h | 1 + src/plugins/squish/squishtools.cpp | 2 ++ src/plugins/squish/squishtools.h | 1 + 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/plugins/squish/squishperspective.cpp b/src/plugins/squish/squishperspective.cpp index 5120ec6ea95..1b762c71a41 100644 --- a/src/plugins/squish/squishperspective.cpp +++ b/src/plugins/squish/squishperspective.cpp @@ -389,6 +389,8 @@ void SquishPerspective::initPerspective() connect(SquishTools::instance(), &SquishTools::objectPicked, this, &SquishPerspective::onObjectPicked); + connect(SquishTools::instance(), &SquishTools::updateChildren, + this, &SquishPerspective::onUpdateChildren); connect(SquishTools::instance(), &SquishTools::propertiesFetched, this, &SquishPerspective::onPropertiesFetched); connect(SquishTools::instance(), &SquishTools::autIdRetrieved, @@ -402,7 +404,7 @@ void SquishPerspective::initPerspective() if (item->expanded) return; item->expanded = true; - SquishTools::instance()->requestExpansionForObject(item->value); + SquishTools::instance()->requestExpansionForObject(item->fullName); } }); connect(m_objectsView->selectionModel(), &QItemSelectionModel::currentChanged, @@ -411,7 +413,7 @@ void SquishPerspective::initPerspective() InspectedObjectItem *item = m_objectsModel.itemForIndex(current); if (!item) return; - SquishTools::instance()->requestPropertiesForObject(item->value); + SquishTools::instance()->requestPropertiesForObject(item->fullName); }); } @@ -488,16 +490,11 @@ void SquishPerspective::onObjectPicked(const QString &output) const QRegularExpressionMatch match = regex.match(output); if (!match.hasMatch()) return; - InspectedObjectItem *parent = nullptr; const QString content = match.captured("content"); - parent = m_objectsModel.findNonRootItem([content](InspectedObjectItem *it) { - return it->value == content; - }); - if (!parent) { - m_objectsModel.clear(); - parent = m_objectsModel.rootItem(); - } + m_objectsModel.clear(); + InspectedObjectItem *parent = m_objectsModel.rootItem(); InspectedObjectItem *obj = new InspectedObjectItem(content, match.captured("type")); + obj->fullName = content; if (match.captured("exp") == "+") obj->appendChild(new InspectedObjectItem); // add pseudo child parent->appendChild(obj); @@ -507,6 +504,27 @@ void SquishPerspective::onObjectPicked(const QString &output) m_objectsView->setCurrentIndex(idx); } +void SquishPerspective::onUpdateChildren(const QString &name, const QStringList &children) +{ + InspectedObjectItem *item = m_objectsModel.findNonRootItem([name](InspectedObjectItem *it) { + return it->fullName == name; + }); + if (!item) + return; + + item->removeChildren(); // remove former dummy child + static const QRegularExpression regex("(?[-+])(?.+)\t(?.+)"); + for (const QString &child : children) { + const QRegularExpressionMatch match = regex.match(child); + QTC_ASSERT(match.hasMatch(), continue); + const QString symbolicName = match.captured("symbolicName"); + auto childItem = new InspectedObjectItem(symbolicName, match.captured("type")); + childItem->fullName = name + '.' + symbolicName; + childItem->appendChild(new InspectedObjectItem); // add dummy child + item->appendChild(childItem); + } +} + void SquishPerspective::onPropertiesFetched(const QStringList &properties) { static const QRegularExpression regex("(?.+)=(?[-+])(?.*)"); @@ -612,6 +630,7 @@ void SquishPerspective::setPerspectiveMode(PerspectiveMode mode) m_inspectAction->setEnabled(false); m_localsModel.clear(); m_objectsModel.clear(); + m_propertiesModel.clear(); break; default: break; diff --git a/src/plugins/squish/squishperspective.h b/src/plugins/squish/squishperspective.h index 1ab6b59be2e..b1a89294332 100644 --- a/src/plugins/squish/squishperspective.h +++ b/src/plugins/squish/squishperspective.h @@ -36,6 +36,7 @@ public: QVariant data(int column, int role) const override; QString value; QString type; + QString fullName; // FIXME this might be non-unique bool expanded = false; }; @@ -83,6 +84,7 @@ private: void onPausePlayTriggered(); void onLocalsUpdated(const QString &output); void onObjectPicked(const QString &output); + void onUpdateChildren(const QString &name, const QStringList &children); void onPropertiesFetched(const QStringList &properties); QAction *m_stopRecordAction = nullptr; diff --git a/src/plugins/squish/squishrunnerprocess.cpp b/src/plugins/squish/squishrunnerprocess.cpp index 4c6991a2070..ca1e330a7c3 100644 --- a/src/plugins/squish/squishrunnerprocess.cpp +++ b/src/plugins/squish/squishrunnerprocess.cpp @@ -161,7 +161,7 @@ void SquishRunnerProcess::handleMultiLineOutput(OutputMode mode) if (mode == MultiLineProperties) { emit propertiesFetched(m_multiLineContent); } else if (mode == MultiLineChildren) { - // TODO + emit updateChildren(m_context, m_multiLineContent); } } diff --git a/src/plugins/squish/squishrunnerprocess.h b/src/plugins/squish/squishrunnerprocess.h index 624b986c6d6..2d2ae4efd34 100644 --- a/src/plugins/squish/squishrunnerprocess.h +++ b/src/plugins/squish/squishrunnerprocess.h @@ -47,6 +47,7 @@ signals: void localsUpdated(const QString &output); void propertiesFetched(const QStringList &properties); void objectPicked(const QString &output); + void updateChildren(const QString &name, const QStringList &children); void runnerError(RunnerError error); void autIdRetrieved(); diff --git a/src/plugins/squish/squishtools.cpp b/src/plugins/squish/squishtools.cpp index 64cc98f780d..f50afbd6519 100644 --- a/src/plugins/squish/squishtools.cpp +++ b/src/plugins/squish/squishtools.cpp @@ -642,6 +642,8 @@ void SquishTools::setupAndStartInspector() this, &SquishTools::logOutputReceived); connect(m_secondaryRunner, &SquishRunnerProcess::objectPicked, this, &SquishTools::objectPicked); + connect(m_secondaryRunner, &SquishRunnerProcess::updateChildren, + this, &SquishTools::updateChildren); connect(m_secondaryRunner, &SquishRunnerProcess::propertiesFetched, this, &SquishTools::propertiesFetched); qCDebug(LOG) << "Inspector starting:" << cmd.toUserOutput(); diff --git a/src/plugins/squish/squishtools.h b/src/plugins/squish/squishtools.h index 11bb9d3096c..099850f5a7c 100644 --- a/src/plugins/squish/squishtools.h +++ b/src/plugins/squish/squishtools.h @@ -75,6 +75,7 @@ signals: void configChangesWritten(); void localsUpdated(const QString &output); void objectPicked(const QString &output); + void updateChildren(const QString &realName, const QStringList &children); void propertiesFetched(const QStringList &properties); void shutdownFinished(); From 0d37a66b51b9defd5ef8e5c3fed5dd7e2ecf85a2 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 15:36:29 +0200 Subject: [PATCH 1237/1447] Squish: Adapt to recent aspect development Change-Id: Ied7406af9c39d8b57b5b9064500e589e33fb86da Reviewed-by: Christian Stenger --- src/plugins/squish/objectsmapdocument.cpp | 4 +- src/plugins/squish/squishnavigationwidget.cpp | 2 +- src/plugins/squish/squishplugin.cpp | 5 +-- src/plugins/squish/squishsettings.cpp | 41 ++++++------------- src/plugins/squish/squishsettings.h | 36 ++++++---------- src/plugins/squish/squishtesttreeview.cpp | 1 - src/plugins/squish/squishtools.cpp | 14 +++---- src/plugins/squish/squishwizardpages.cpp | 2 +- 8 files changed, 39 insertions(+), 66 deletions(-) diff --git a/src/plugins/squish/objectsmapdocument.cpp b/src/plugins/squish/objectsmapdocument.cpp index 3742ee3466d..1e0b30766da 100644 --- a/src/plugins/squish/objectsmapdocument.cpp +++ b/src/plugins/squish/objectsmapdocument.cpp @@ -195,7 +195,7 @@ Core::IDocument::OpenResult ObjectsMapDocument::openImpl(QString *error, text = reader.data(); } else { - const Utils::FilePath base = SquishPlugin::squishSettings()->squishPath.filePath(); + const Utils::FilePath base = SquishPlugin::squishSettings()->squishPath(); if (base.isEmpty()) { if (error) error->append(Tr::tr("Incomplete Squish settings. " @@ -233,7 +233,7 @@ bool ObjectsMapDocument::writeFile(const Utils::FilePath &fileName) const } // otherwise we need the objectmaptool to write the scripted object map again - const Utils::FilePath base = SquishPlugin::squishSettings()->squishPath.filePath(); + const Utils::FilePath base = SquishPlugin::squishSettings()->squishPath(); if (base.isEmpty()) return false; const Utils::FilePath exe = base.pathAppended("lib/exec/objectmaptool").withExecutableSuffix(); diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index 5e51e5980e9..cc9ec76b317 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -314,7 +314,7 @@ void SquishNavigationWidget::onNewTestCaseTriggered(const QModelIndex &index) auto settings = SquishPlugin::squishSettings(); QTC_ASSERT(settings, return); - if (!settings->squishPath.filePath().pathAppended("scriptmodules").exists()) { + if (!settings->squishPath().pathAppended("scriptmodules").exists()) { SquishMessages::criticalMessage(Tr::tr("Set up a valid Squish path to be able to create " "a new test case.\n(Edit > Preferences > Squish)")); return; diff --git a/src/plugins/squish/squishplugin.cpp b/src/plugins/squish/squishplugin.cpp index f72f70df788..c8b779aac06 100644 --- a/src/plugins/squish/squishplugin.cpp +++ b/src/plugins/squish/squishplugin.cpp @@ -109,7 +109,7 @@ bool SquishPluginPrivate::initializeGlobalScripts() QTC_ASSERT(dd->m_squishTools, return false); SquishFileHandler::instance()->setSharedFolders({}); - const Utils::FilePath squishserver = dd->m_squishSettings.squishPath.filePath().pathAppended( + const Utils::FilePath squishserver = dd->m_squishSettings.squishPath().pathAppended( Utils::HostOsInfo::withExecutableSuffix("bin/squishserver")); if (!squishserver.isExecutableFile()) return false; @@ -134,8 +134,7 @@ void SquishPlugin::initialize() bool SquishPlugin::delayedInitialize() { - - connect(&dd->m_squishSettings, &SquishSettings::squishPathChanged, + connect(&dd->m_squishSettings.squishPath, &Utils::BaseAspect::changed, dd, &SquishPluginPrivate::initializeGlobalScripts); return dd->initializeGlobalScripts(); diff --git a/src/plugins/squish/squishsettings.cpp b/src/plugins/squish/squishsettings.cpp index e95ed33f48f..23ccc22dfec 100644 --- a/src/plugins/squish/squishsettings.cpp +++ b/src/plugins/squish/squishsettings.cpp @@ -36,10 +36,8 @@ SquishSettings::SquishSettings() setSettingsGroup("Squish"); setAutoApply(false); - registerAspect(&squishPath); squishPath.setSettingsKey("SquishPath"); squishPath.setLabelText(Tr::tr("Squish path:")); - squishPath.setDisplayStyle(StringAspect::PathChooserDisplay); squishPath.setExpectedKind(PathChooser::ExistingDirectory); squishPath.setPlaceHolderText(Tr::tr("Path to Squish installation")); squishPath.setValidationFunction([this](FancyLineEdit *edit, QString *error) { @@ -54,37 +52,30 @@ SquishSettings::SquishSettings() return valid; }); - registerAspect(&licensePath); licensePath.setSettingsKey("LicensePath"); licensePath.setLabelText(Tr::tr("License path:")); - licensePath.setDisplayStyle(StringAspect::PathChooserDisplay); licensePath.setExpectedKind(PathChooser::ExistingDirectory); - registerAspect(&local); local.setSettingsKey("Local"); local.setLabel(Tr::tr("Local Server")); local.setDefaultValue(true); - registerAspect(&serverHost); serverHost.setSettingsKey("ServerHost"); serverHost.setLabelText(Tr::tr("Server host:")); serverHost.setDisplayStyle(StringAspect::LineEditDisplay); serverHost.setDefaultValue("localhost"); serverHost.setEnabled(false); - registerAspect(&serverPort); serverPort.setSettingsKey("ServerPort"); serverPort.setLabel(Tr::tr("Server Port")); serverPort.setRange(1, 65535); serverPort.setDefaultValue(9999); serverPort.setEnabled(false); - registerAspect(&verbose); verbose.setSettingsKey("Verbose"); verbose.setLabel(Tr::tr("Verbose log")); verbose.setDefaultValue(false); - registerAspect(&minimizeIDE); minimizeIDE.setSettingsKey("MinimizeIDE"); minimizeIDE.setLabel(Tr::tr("Minimize IDE")); minimizeIDE.setToolTip(Tr::tr("Minimize IDE automatically while running or recording test cases.")); @@ -94,13 +85,11 @@ SquishSettings::SquishSettings() serverHost.setEnabled(!checked); serverPort.setEnabled(!checked); }); - connect(&squishPath, &Utils::StringAspect::valueChanged, - this, &SquishSettings::squishPathChanged); } Utils::FilePath SquishSettings::scriptsPath(Language language) const { - Utils::FilePath scripts = squishPath.filePath().pathAppended("scriptmodules"); + Utils::FilePath scripts = squishPath().pathAppended("scriptmodules"); switch (language) { case Language::Python: scripts = scripts.pathAppended("python"); break; case Language::Perl: scripts = scripts.pathAppended("perl"); break; @@ -139,7 +128,6 @@ SquishSettingsPage::SquishSettingsPage(SquishSettings *settings) SquishServerSettings::SquishServerSettings() { - registerAspect(&autTimeout); autTimeout.setLabel(Tr::tr("Maximum startup time:")); autTimeout.setToolTip(Tr::tr("Specifies how many seconds Squish should wait for a reply from the " "AUT directly after starting it.")); @@ -147,7 +135,6 @@ SquishServerSettings::SquishServerSettings() autTimeout.setSuffix("s"); autTimeout.setDefaultValue(20); - registerAspect(&responseTimeout); responseTimeout.setLabel(Tr::tr("Maximum response time:")); responseTimeout.setToolTip(Tr::tr("Specifies how many seconds Squish should wait for a reply from " "the hooked up AUT before raising a timeout error.")); @@ -155,7 +142,6 @@ SquishServerSettings::SquishServerSettings() responseTimeout.setDefaultValue(300); responseTimeout.setSuffix("s"); - registerAspect(&postMortemWaitTime); postMortemWaitTime.setLabel(Tr::tr("Maximum post-mortem wait time:")); postMortemWaitTime.setToolTip(Tr::tr("Specifies how many seconds Squish should wait after the the " "first AUT process has exited.")); @@ -163,7 +149,6 @@ SquishServerSettings::SquishServerSettings() postMortemWaitTime.setDefaultValue(1500); postMortemWaitTime.setSuffix("ms"); - registerAspect(&animatedCursor); animatedCursor.setLabel(Tr::tr("Animate mouse cursor:")); animatedCursor.setDefaultValue(true); } @@ -250,10 +235,10 @@ void SquishServerSettings::setFromXmlOutput(const QString &output) autPaths = newSettings.autPaths; attachableAuts = newSettings.attachableAuts; licensedToolkits = newSettings.licensedToolkits; - autTimeout.setValue(newSettings.autTimeout.value()); - postMortemWaitTime.setValue(newSettings.postMortemWaitTime.value()); - responseTimeout.setValue(newSettings.responseTimeout.value()); - animatedCursor.setValue(newSettings.animatedCursor.value()); + autTimeout.setValue(newSettings.autTimeout()); + postMortemWaitTime.setValue(newSettings.postMortemWaitTime()); + responseTimeout.setValue(newSettings.responseTimeout()); + animatedCursor.setValue(newSettings.animatedCursor()); } class SquishServerItem : public TreeItem @@ -625,14 +610,14 @@ QList SquishServerSettingsWidget::toConfigChangeArguments() const result.append({"addAppPath", path}); } - if (m_originalSettings.autTimeout.value() != m_serverSettings.autTimeout.value()) - result.append({"setAUTTimeout", QString::number(m_serverSettings.autTimeout.value())}); - if (m_originalSettings.responseTimeout.value() != m_serverSettings.responseTimeout.value()) - result.append({"setResponseTimeout", QString::number(m_serverSettings.responseTimeout.value())}); - if (m_originalSettings.postMortemWaitTime.value() != m_serverSettings.postMortemWaitTime.value()) - result.append({"setAUTPostMortemTimeout", QString::number(m_serverSettings.postMortemWaitTime.value())}); - if (m_originalSettings.animatedCursor.value() != m_serverSettings.animatedCursor.value()) - result.append({"setCursorAnimation", m_serverSettings.animatedCursor.value() ? QString("on") : QString("off")}); + if (m_originalSettings.autTimeout() != m_serverSettings.autTimeout()) + result.append({"setAUTTimeout", QString::number(m_serverSettings.autTimeout())}); + if (m_originalSettings.responseTimeout() != m_serverSettings.responseTimeout()) + result.append({"setResponseTimeout", QString::number(m_serverSettings.responseTimeout())}); + if (m_originalSettings.postMortemWaitTime() != m_serverSettings.postMortemWaitTime()) + result.append({"setAUTPostMortemTimeout", QString::number(m_serverSettings.postMortemWaitTime())}); + if (m_originalSettings.animatedCursor() != m_serverSettings.animatedCursor()) + result.append({"setCursorAnimation", m_serverSettings.animatedCursor() ? QString("on") : QString("off")}); return result; } diff --git a/src/plugins/squish/squishsettings.h b/src/plugins/squish/squishsettings.h index 23380521e69..180f2eb84fe 100644 --- a/src/plugins/squish/squishsettings.h +++ b/src/plugins/squish/squishsettings.h @@ -10,12 +10,7 @@ #include #include -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE - -namespace Squish { -namespace Internal { +namespace Squish::Internal { enum class Language; @@ -30,30 +25,26 @@ public: QMap attachableAuts; // name, host:port QStringList autPaths; // absolute path QStringList licensedToolkits; - Utils::IntegerAspect autTimeout; - Utils::IntegerAspect responseTimeout; - Utils::IntegerAspect postMortemWaitTime; - Utils::BoolAspect animatedCursor; + Utils::IntegerAspect autTimeout{this}; + Utils::IntegerAspect responseTimeout{this}; + Utils::IntegerAspect postMortemWaitTime{this}; + Utils::BoolAspect animatedCursor{this}; }; class SquishSettings : public Utils::AspectContainer { - Q_OBJECT public: SquishSettings(); Utils::FilePath scriptsPath(Language language) const; - Utils::StringAspect squishPath; - Utils::StringAspect licensePath; - Utils::StringAspect serverHost; - Utils::IntegerAspect serverPort; - Utils::BoolAspect local; - Utils::BoolAspect verbose; - Utils::BoolAspect minimizeIDE; - -signals: - void squishPathChanged(); + Utils::FilePathAspect squishPath{this}; + Utils::FilePathAspect licensePath{this}; + Utils::StringAspect serverHost{this}; + Utils::IntegerAspect serverPort{this}; + Utils::BoolAspect local{this}; + Utils::BoolAspect verbose{this}; + Utils::BoolAspect minimizeIDE{this}; }; class SquishSettingsPage final : public Core::IOptionsPage @@ -71,5 +62,4 @@ private: void configWriteFailed(QProcess::ProcessError error); }; -} // namespace Internal -} // namespace Squish +} // Squish::Internal diff --git a/src/plugins/squish/squishtesttreeview.cpp b/src/plugins/squish/squishtesttreeview.cpp index 65e4c15dd93..d01ab0440f5 100644 --- a/src/plugins/squish/squishtesttreeview.cpp +++ b/src/plugins/squish/squishtesttreeview.cpp @@ -166,7 +166,6 @@ static bool copyScriptTemplates(const SuiteConf &suiteConf, const Utils::FilePat const SquishSettings *s = SquishPlugin::squishSettings(); QTC_ASSERT(s, return false); // copy template files - const Utils::FilePath squishPath = s->squishPath.filePath(); bool ok = destination.ensureWritableDir(); QTC_ASSERT(ok, return false); diff --git a/src/plugins/squish/squishtools.cpp b/src/plugins/squish/squishtools.cpp index f50afbd6519..21450953068 100644 --- a/src/plugins/squish/squishtools.cpp +++ b/src/plugins/squish/squishtools.cpp @@ -169,7 +169,7 @@ struct SquishToolsSettings { const SquishSettings *squishSettings = SquishPlugin::squishSettings(); QTC_ASSERT(squishSettings, return); - squishPath = squishSettings->squishPath.filePath(); + squishPath = squishSettings->squishPath(); if (!squishPath.isEmpty()) { const FilePath squishBin(squishPath.pathAppended("bin")); @@ -181,12 +181,12 @@ struct SquishToolsSettings HostOsInfo::withExecutableSuffix("processcomm")).absoluteFilePath(); } - isLocalServer = squishSettings->local.value(); - serverHost = squishSettings->serverHost.value(); - serverPort = squishSettings->serverPort.value(); - verboseLog = squishSettings->verbose.value(); - licenseKeyPath = squishSettings->licensePath.filePath(); - minimizeIDE = squishSettings->minimizeIDE.value(); + isLocalServer = squishSettings->local(); + serverHost = squishSettings->serverHost(); + serverPort = squishSettings->serverPort(); + verboseLog = squishSettings->verbose(); + licenseKeyPath = squishSettings->licensePath(); + minimizeIDE = squishSettings->minimizeIDE(); } }; diff --git a/src/plugins/squish/squishwizardpages.cpp b/src/plugins/squish/squishwizardpages.cpp index e55a6ee8b2a..70003cb2bf4 100644 --- a/src/plugins/squish/squishwizardpages.cpp +++ b/src/plugins/squish/squishwizardpages.cpp @@ -112,7 +112,7 @@ bool SquishToolkitsPage::handleReject() void SquishToolkitsPage::delayedInitialize() { const auto s = SquishPlugin::squishSettings(); - const Utils::FilePath server = s->squishPath.filePath().pathAppended( + const Utils::FilePath server = s->squishPath().pathAppended( Utils::HostOsInfo::withExecutableSuffix("bin/squishserver")); if (server.isExecutableFile()) fetchServerSettings(); From bf4934feb982f6440c697cd3f5a1482570677e3f Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 23 May 2023 19:03:32 +0200 Subject: [PATCH 1238/1447] CMakePM: Expand ${hostSystemName} for build presets Fixes: QTCREATORBUG-28935 Change-Id: Ie645d80a9743108e3760096b6829e881677e249b Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/cmakeprojectmanager/presetsmacros.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/cmakeprojectmanager/presetsmacros.cpp b/src/plugins/cmakeprojectmanager/presetsmacros.cpp index af5524216fb..317012a01ee 100644 --- a/src/plugins/cmakeprojectmanager/presetsmacros.cpp +++ b/src/plugins/cmakeprojectmanager/presetsmacros.cpp @@ -61,6 +61,7 @@ static void expandAllButEnv(const PresetsDetails::BuildPreset &preset, value.replace("${sourceDirName}", sourceDirectory.fileName()); value.replace("${presetName}", preset.name); + value.replace("${hostSystemName}", getHostSystemName(sourceDirectory.osType())); value.replace("${pathListSep}", Utils::OsSpecificAspects::pathListSeparator(sourceDirectory.osType())); } From 86ff142f8efb9047105709378c95f27a697ea578 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 23 May 2023 12:45:51 +0200 Subject: [PATCH 1239/1447] Utils: Treat FilePath with variables as user input when expanding When macro-expanding FilePaths with environment variables, it can happen that non-conformant path separators end up in the intermediate expanded string. For example with "%{Env:PROGRAMFILES}" on Windows. Since we generally treat paths from environment variables as user input, it makes sense to treat macros as user input as-well in this case. Change-Id: I0daa57b7dbf3d8fd25c98fb82b2beb1bc6ded825 Reviewed-by: Reviewed-by: hjk --- src/libs/utils/macroexpander.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 43d23d2d190..5d3bba0229a 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -275,7 +275,7 @@ QString MacroExpander::expand(const QString &stringWithVariables) const FilePath MacroExpander::expand(const FilePath &fileNameWithVariables) const { // We want single variables to expand to fully qualified strings. - return FilePath::fromString(expand(fileNameWithVariables.toString())); + return FilePath::fromUserInput(expand(fileNameWithVariables.toString())); } QByteArray MacroExpander::expand(const QByteArray &stringWithVariables) const From 0234ab68963be07a055942993f99c5e254f3e0f8 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 18:37:29 +0200 Subject: [PATCH 1240/1447] Utils: More aspects with new scheme Task-number: QTCREATORBUG-29167 Change-Id: I76977d4d740556d28423ce9f632ee47e81822ee6 Reviewed-by: Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 3 ++- src/libs/utils/aspects.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index e900a680fc6..3652380ed7d 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2283,7 +2283,8 @@ void StringListAspect::removeValues(const QStringList &values) that is a list of strings. */ -IntegersAspect::IntegersAspect() +IntegersAspect::IntegersAspect(AspectContainer *container) + : BaseAspect(container) { setDefaultValue({}); } diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index a55e8bff74b..87f283bdcd7 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -290,6 +290,7 @@ public: void setVolatileValue(const QVariant &val) override; void finish() override; + int operator()() const { return value(); } int value() const; void setValue(int val); @@ -585,12 +586,13 @@ class QTCREATOR_UTILS_EXPORT IntegersAspect : public BaseAspect Q_OBJECT public: - IntegersAspect(); + IntegersAspect(AspectContainer *container = nullptr); ~IntegersAspect() override; void addToLayout(Layouting::LayoutItem &parent) override; void emitChangedValue() override; + QList operator()() const { return value(); } QList value() const; void setValue(const QList &value); From 75710fa36936d506db5ba865613c51f966861e42 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 17:49:52 +0200 Subject: [PATCH 1241/1447] Utils: Remove LabelPlacement::AtCheckBoxWithoutDummyLabel This is identical in remaining functionality to AtCheckBox after the recent layout builder changes (or rather, can be adjusted on the layouting side by having appropriate empty cells) Task-number: QTCREATORBUG-29167 Change-Id: Ic357de6fb756acb5926afe1fd361ee4b18b17afd Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 10 +--------- src/libs/utils/aspects.h | 2 +- src/plugins/autotest/boost/boosttestsettings.cpp | 8 ++++---- .../cmakeprojectmanager/cmakebuildstep.cpp | 2 +- src/plugins/debugger/debuggeractions.cpp | 2 +- src/plugins/fakevim/fakevimactions.cpp | 2 +- src/plugins/qbsprojectmanager/qbsbuildstep.cpp | 10 +++++----- src/plugins/qbsprojectmanager/qbsinstallstep.cpp | 2 +- src/plugins/subversion/subversionsettings.cpp | 2 +- src/plugins/valgrind/valgrindsettings.cpp | 16 ++++++++-------- 10 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 3652380ed7d..461a3915347 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1455,18 +1455,10 @@ void BoolAspect::addToLayout(Layouting::LayoutItem &parent) d->m_button = createSubWidget(); } switch (d->m_labelPlacement) { - case LabelPlacement::AtCheckBoxWithoutDummyLabel: + case LabelPlacement::AtCheckBox: d->m_button->setText(labelText()); parent.addItem(d->m_button.data()); break; - case LabelPlacement::AtCheckBox: { - d->m_button->setText(labelText()); - // FIXME: - //if (parent.isForm()) - // parent.addItem(createSubWidget()); - parent.addItem(d->m_button.data()); - break; - } case LabelPlacement::InExtraLabel: addLabeledItem(parent, d->m_button); break; diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 87f283bdcd7..2cae52a1048 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -237,7 +237,7 @@ public: bool defaultValue() const; void setDefaultValue(bool val); - enum class LabelPlacement { AtCheckBox, AtCheckBoxWithoutDummyLabel, InExtraLabel }; + enum class LabelPlacement { AtCheckBox, InExtraLabel }; void setLabel(const QString &labelText, LabelPlacement labelPlacement = LabelPlacement::InExtraLabel); void setLabelPlacement(LabelPlacement labelPlacement); diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp index 958f756bfe0..b55e728b7ba 100644 --- a/src/plugins/autotest/boost/boosttestsettings.cpp +++ b/src/plugins/autotest/boost/boosttestsettings.cpp @@ -70,25 +70,25 @@ BoostTestSettings::BoostTestSettings(Id settingsId) registerAspect(&randomize); randomize.setSettingsKey("Randomize"); - randomize.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + randomize.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); randomize.setLabelText(Tr::tr("Randomize")); randomize.setToolTip(Tr::tr("Randomize execution order.")); registerAspect(&systemErrors); systemErrors.setSettingsKey("SystemErrors"); - systemErrors.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + systemErrors.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); systemErrors.setLabelText(Tr::tr("Catch system errors")); systemErrors.setToolTip(Tr::tr("Catch or ignore system errors.")); registerAspect(&fpExceptions); fpExceptions.setSettingsKey("FPExceptions"); - fpExceptions.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + fpExceptions.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); fpExceptions.setLabelText(Tr::tr("Floating point exceptions")); fpExceptions.setToolTip(Tr::tr("Enable floating point exception traps.")); registerAspect(&memLeaks); memLeaks.setSettingsKey("MemoryLeaks"); - memLeaks.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + memLeaks.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); memLeaks.setDefaultValue(true); memLeaks.setLabelText(Tr::tr("Detect memory leaks")); memLeaks.setToolTip(Tr::tr("Enable memory leak detection.")); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index e916a5a8341..2d2501ab03b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -194,7 +194,7 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) : m_useStaging = addAspect(); m_useStaging->setSettingsKey(USE_STAGING_KEY); - m_useStaging->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + m_useStaging->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); m_useStaging->setDefaultValue(!buildAndRunOnSameDevice(kit())); m_stagingDir = addAspect(); diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 208ca88d61e..721d499dc58 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -660,7 +660,7 @@ DebuggerSettings::DebuggerSettings() aspect->setAutoApply(false); // FIXME: Make the positioning part of the LayoutBuilder later if (auto boolAspect = dynamic_cast(aspect)) - boolAspect->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + boolAspect->setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); }); } diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index 7f7c44baf40..dc051d81040 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -173,7 +173,7 @@ void FakeVimSettings::setup(FvBaseAspect *aspect, registerAspect(aspect); if (auto boolAspect = dynamic_cast(aspect)) - boolAspect->setLabelPlacement(FvBoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + boolAspect->setLabelPlacement(FvBoolAspect::LabelPlacement::AtCheckBox); #else Q_UNUSED(labelText) #endif diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index 794e134d5a8..afb94652416 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -224,7 +224,7 @@ QbsBuildStep::QbsBuildStep(BuildStepList *bsl, Utils::Id id) : m_keepGoing->setToolTip( QbsProjectManager::Tr::tr("Keep going when errors occur (if at all possible).")); m_keepGoing->setLabel(QbsProjectManager::Tr::tr("Keep going"), - BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + BoolAspect::LabelPlacement::AtCheckBox); m_maxJobCount = addAspect(); m_maxJobCount->setSettingsKey(QBS_MAXJOBCOUNT); @@ -235,22 +235,22 @@ QbsBuildStep::QbsBuildStep(BuildStepList *bsl, Utils::Id id) : m_showCommandLines = addAspect(); m_showCommandLines->setSettingsKey(QBS_SHOWCOMMANDLINES); m_showCommandLines->setLabel(QbsProjectManager::Tr::tr("Show command lines"), - BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + BoolAspect::LabelPlacement::AtCheckBox); m_install = addAspect(); m_install->setSettingsKey(QBS_INSTALL); m_install->setValue(true); - m_install->setLabel(QbsProjectManager::Tr::tr("Install"), BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + m_install->setLabel(QbsProjectManager::Tr::tr("Install"), BoolAspect::LabelPlacement::AtCheckBox); m_cleanInstallDir = addAspect(); m_cleanInstallDir->setSettingsKey(QBS_CLEAN_INSTALL_ROOT); m_cleanInstallDir->setLabel(QbsProjectManager::Tr::tr("Clean install root"), - BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + BoolAspect::LabelPlacement::AtCheckBox); m_forceProbes = addAspect(); m_forceProbes->setSettingsKey("Qbs.forceProbesKey"); m_forceProbes->setLabel(QbsProjectManager::Tr::tr("Force probes"), - BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + BoolAspect::LabelPlacement::AtCheckBox); m_commandLine = addAspect(); m_commandLine->setDisplayStyle(StringAspect::TextEditDisplay); diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index 939a03d9d9c..87fe3ae0f9c 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -48,7 +48,7 @@ QbsInstallStep::QbsInstallStep(BuildStepList *bsl, Utils::Id id) setDisplayName(Tr::tr("Qbs Install")); setSummaryText(Tr::tr("Qbs: %1").arg("install")); - const auto labelPlacement = BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel; + const auto labelPlacement = BoolAspect::LabelPlacement::AtCheckBox; m_dryRun = addAspect(); m_dryRun->setSettingsKey(QBS_DRY_RUN); m_dryRun->setLabel(Tr::tr("Dry run"), labelPlacement); diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index 9bdd07fbf8b..2a087883d7c 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -41,7 +41,7 @@ SubversionSettings::SubversionSettings() registerAspect(&useAuthentication); useAuthentication.setSettingsKey("Authentication"); - useAuthentication.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + useAuthentication.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); registerAspect(&userName); userName.setSettingsKey("User"); diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index fd15b04299b..1b9cfb62e7f 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -244,19 +244,19 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) filterExternalIssues.setSettingsKey(base + "FilterExternalIssues"); filterExternalIssues.setDefaultValue(true); filterExternalIssues.setIcon(Icons::FILTER.icon()); - filterExternalIssues.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + filterExternalIssues.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); filterExternalIssues.setLabelText(Tr::tr("Show Project Costs Only")); filterExternalIssues.setToolTip(Tr::tr("Show only profiling info that originated from this project source.")); registerAspect(&trackOrigins); trackOrigins.setSettingsKey(base + "TrackOrigins"); trackOrigins.setDefaultValue(true); - trackOrigins.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + trackOrigins.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); trackOrigins.setLabelText(Tr::tr("Track origins of uninitialized memory")); registerAspect(&showReachable); showReachable.setSettingsKey(base + "ShowReachable"); - showReachable.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + showReachable.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); showReachable.setLabelText(Tr::tr("Show reachable and indirectly lost blocks")); registerAspect(&leakCheckOnFinish); @@ -291,12 +291,12 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) registerAspect(&enableEventToolTips); enableEventToolTips.setDefaultValue(true); enableEventToolTips.setSettingsKey(base + "Callgrind.EnableEventToolTips"); - enableEventToolTips.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + enableEventToolTips.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); enableEventToolTips.setLabelText(Tr::tr("Show additional information for events in tooltips")); registerAspect(&enableCacheSim); enableCacheSim.setSettingsKey(base + "Callgrind.EnableCacheSim"); - enableCacheSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + enableCacheSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); enableCacheSim.setLabelText(Tr::tr("Enable cache simulation")); enableCacheSim.setToolTip("" + Tr::tr( "

Does full cache simulation.

\n" @@ -310,7 +310,7 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) registerAspect(&enableBranchSim); enableBranchSim.setSettingsKey(base + "Callgrind.EnableBranchSim"); - enableBranchSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + enableBranchSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); enableBranchSim.setLabelText(Tr::tr("Enable branch prediction simulation")); enableBranchSim.setToolTip("\n" + Tr::tr( "

Does branch prediction simulation.

\n" @@ -322,12 +322,12 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) registerAspect(&collectSystime); collectSystime.setSettingsKey(base + "Callgrind.CollectSystime"); - collectSystime.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + collectSystime.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); collectSystime.setLabelText(Tr::tr("Collect system call time")); collectSystime.setToolTip(Tr::tr("Collects information for system call times.")); registerAspect(&collectBusEvents); - collectBusEvents.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBoxWithoutDummyLabel); + collectBusEvents.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); collectBusEvents.setSettingsKey(base + "Callgrind.CollectBusEvents"); collectBusEvents.setLabelText(Tr::tr("Collect global bus events")); collectBusEvents.setToolTip(Tr::tr("Collect the number of global bus events that are executed. " From 01019dfdb87506cd6faa3f29913431a1e826cf8d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 14:42:41 +0200 Subject: [PATCH 1242/1447] ProjectExplorer: Use FilePathAspect for some FilePaths Change-Id: I35d55c82217e9ef9bbcf215c8360a111931c822c Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/buildaspects.cpp | 1 - src/plugins/projectexplorer/buildaspects.h | 5 ++--- src/plugins/projectexplorer/makestep.cpp | 3 +-- src/plugins/projectexplorer/processstep.cpp | 6 ++---- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index e4cbf6903b7..606911654fd 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -41,7 +41,6 @@ BuildDirectoryAspect::BuildDirectoryAspect(const BuildConfiguration *bc) { setSettingsKey("ProjectExplorer.BuildConfiguration.BuildDirectory"); setLabelText(Tr::tr("Build directory:")); - setDisplayStyle(PathChooserDisplay); setExpectedKind(Utils::PathChooser::Directory); setValidationFunction([this](FancyLineEdit *edit, QString *error) { const FilePath fixedDir = fixupDir(FilePath::fromUserInput(edit->text())); diff --git a/src/plugins/projectexplorer/buildaspects.h b/src/plugins/projectexplorer/buildaspects.h index 96c6db90716..bcc8987cd0c 100644 --- a/src/plugins/projectexplorer/buildaspects.h +++ b/src/plugins/projectexplorer/buildaspects.h @@ -7,12 +7,11 @@ #include -namespace Utils { class FilePath; } - namespace ProjectExplorer { + class BuildConfiguration; -class PROJECTEXPLORER_EXPORT BuildDirectoryAspect : public Utils::StringAspect +class PROJECTEXPLORER_EXPORT BuildDirectoryAspect : public Utils::FilePathAspect { Q_OBJECT public: diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 56b04b4b7f6..ee9ffea832b 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -46,9 +46,8 @@ MakeStep::MakeStep(BuildStepList *parent, Id id) setCommandLineProvider([this] { return effectiveMakeCommand(Execution); }); - m_makeCommandAspect = addAspect(); + m_makeCommandAspect = addAspect(); m_makeCommandAspect->setSettingsKey(id.withSuffix(MAKE_COMMAND_SUFFIX).toString()); - m_makeCommandAspect->setDisplayStyle(StringAspect::PathChooserDisplay); m_makeCommandAspect->setExpectedKind(PathChooser::ExistingCommand); m_makeCommandAspect->setBaseFileName(PathChooser::homePath()); m_makeCommandAspect->setHistoryCompleter("PE.MakeCommand.History"); diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp index 3ced1622d0d..a34ff10b611 100644 --- a/src/plugins/projectexplorer/processstep.cpp +++ b/src/plugins/projectexplorer/processstep.cpp @@ -34,9 +34,8 @@ public: ProcessStep::ProcessStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id) { - auto command = addAspect(); + auto command = addAspect(); command->setSettingsKey(PROCESS_COMMAND_KEY); - command->setDisplayStyle(StringAspect::PathChooserDisplay); command->setLabelText(Tr::tr("Command:")); command->setExpectedKind(PathChooser::Command); command->setHistoryCompleter("PE.ProcessStepCommand.History"); @@ -46,10 +45,9 @@ ProcessStep::ProcessStep(BuildStepList *bsl, Id id) arguments->setDisplayStyle(StringAspect::LineEditDisplay); arguments->setLabelText(Tr::tr("Arguments:")); - auto workingDirectory = addAspect(); + auto workingDirectory = addAspect(); workingDirectory->setSettingsKey(PROCESS_WORKINGDIRECTORY_KEY); workingDirectory->setValue(Constants::DEFAULT_WORKING_DIR); - workingDirectory->setDisplayStyle(StringAspect::PathChooserDisplay); workingDirectory->setLabelText(Tr::tr("Working directory:")); workingDirectory->setExpectedKind(PathChooser::Directory); From f7d46f48f8530bbdccdfaa4894bf32e737a4a769 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 24 May 2023 10:27:35 +0200 Subject: [PATCH 1243/1447] Build axivion support plugin Adapts the CMake files, fixes license. Change-Id: I6bdce2547d187bcabcc864026e36a1c924015c2a Reviewed-by: Christian Stenger Reviewed-by: hjk --- src/plugins/CMakeLists.txt | 1 + src/plugins/axivion/Axivion.json.in | 8 ++++++-- src/plugins/axivion/CMakeLists.txt | 13 ++----------- src/plugins/axivion/axivionoutputpane.cpp | 2 +- src/plugins/axivion/axivionoutputpane.h | 2 +- src/plugins/axivion/axivionplugin.cpp | 14 +------------- src/plugins/axivion/axivionplugin.h | 2 +- src/plugins/axivion/axivionprojectsettings.cpp | 2 +- src/plugins/axivion/axivionprojectsettings.h | 2 +- src/plugins/axivion/axivionquery.cpp | 2 +- src/plugins/axivion/axivionquery.h | 2 +- src/plugins/axivion/axivionresultparser.cpp | 2 +- src/plugins/axivion/axivionresultparser.h | 2 +- src/plugins/axivion/axivionsettings.cpp | 2 +- src/plugins/axivion/axivionsettings.h | 2 +- src/plugins/axivion/axivionsettingspage.cpp | 2 +- src/plugins/axivion/axivionsettingspage.h | 2 +- src/plugins/axivion/axiviontr.h | 2 +- src/plugins/plugins.qbs | 1 + 19 files changed, 25 insertions(+), 40 deletions(-) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index a6a2edb2989..4fd8b655730 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(projectexplorer) add_subdirectory(silversearcher) # Level 3: (only depends on Level 2 and below) +add_subdirectory(axivion) add_subdirectory(bookmarks) add_subdirectory(cppeditor) add_subdirectory(haskell) diff --git a/src/plugins/axivion/Axivion.json.in b/src/plugins/axivion/Axivion.json.in index 7f28cffd1d5..fac0520565f 100644 --- a/src/plugins/axivion/Axivion.json.in +++ b/src/plugins/axivion/Axivion.json.in @@ -8,10 +8,14 @@ \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", \"License\" : [ \"Commercial Usage\", \"\", - \"Licensees holding valid Qt Enterprise licenses may use this plugin in accordance with the Qt Enterprise License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\" + \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\", + \"\", + \"GNU General Public License Usage\", + \"\", + \"Alternatively, this plugin 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 plugin. 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.\" ], \"Category\" : \"Code Analyzer\", \"Description\" : \"Integration of the axivion dashboard.\", - \"Url\" : \"http://www.qt-project.org\", + \"Url\" : \"https://www.qt.io\", $$dependencyList } diff --git a/src/plugins/axivion/CMakeLists.txt b/src/plugins/axivion/CMakeLists.txt index 8f311a885b8..b346cc276dc 100644 --- a/src/plugins/axivion/CMakeLists.txt +++ b/src/plugins/axivion/CMakeLists.txt @@ -1,16 +1,7 @@ -find_package(QtCreator COMPONENTS Core REQUIRED) -find_package(Qt6 COMPONENTS Network Widgets REQUIRED) - -find_package(QtCreatorLicenseChecker QUIET) -if (TARGET QtCreator::LicenseChecker) - set(LICENSECHECKER_DEPENDS QtCreator::LicenseChecker) -endif() - add_qtc_plugin(Axivion PLUGIN_DEPENDS - QtCreator::Core QtCreator::ProjectExplorer QtCreator::TextEditor - ${LICENSECHECKER_DEPENDS} - DEPENDS Qt::Network Qt::Widgets QtCreator::ExtensionSystem QtCreator::Utils + Core ProjectExplorer TextEditor + DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils SOURCES axivion.qrc axivionoutputpane.cpp axivionoutputpane.h diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 5f3f8c16161..ba226f63b5b 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "axivionoutputpane.h" diff --git a/src/plugins/axivion/axivionoutputpane.h b/src/plugins/axivion/axivionoutputpane.h index aea4354e02e..d11accc1401 100644 --- a/src/plugins/axivion/axivionoutputpane.h +++ b/src/plugins/axivion/axivionoutputpane.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 923c0cabb09..7648448132a 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "axivionplugin.h" @@ -30,10 +30,6 @@ #include #include -#ifdef LICENSECHECKER -# include -#endif - #include #include #include @@ -120,14 +116,6 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa Q_UNUSED(arguments) Q_UNUSED(errorMessage) -#ifdef LICENSECHECKER - LicenseChecker::LicenseCheckerPlugin *licenseChecker - = ExtensionSystem::PluginManager::getObject(); - - if (!licenseChecker || !licenseChecker->hasValidLicense() || !licenseChecker->enterpriseFeatures()) - return true; -#endif // LICENSECHECKER - dd = new AxivionPluginPrivate; dd->m_axivionSettings.fromSettings(Core::ICore::settings()); diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 1cd33d0e99b..992971b6bd6 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp index 74fa66fcdcf..351696b525b 100644 --- a/src/plugins/axivion/axivionprojectsettings.cpp +++ b/src/plugins/axivion/axivionprojectsettings.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "axivionprojectsettings.h" diff --git a/src/plugins/axivion/axivionprojectsettings.h b/src/plugins/axivion/axivionprojectsettings.h index c9bf147a51d..d5bc1fd2e62 100644 --- a/src/plugins/axivion/axivionprojectsettings.h +++ b/src/plugins/axivion/axivionprojectsettings.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/axivion/axivionquery.cpp b/src/plugins/axivion/axivionquery.cpp index 8fcb131c87f..657ee613a1b 100644 --- a/src/plugins/axivion/axivionquery.cpp +++ b/src/plugins/axivion/axivionquery.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "axivionquery.h" diff --git a/src/plugins/axivion/axivionquery.h b/src/plugins/axivion/axivionquery.h index d9873a6db44..11af5bbd87b 100644 --- a/src/plugins/axivion/axivionquery.h +++ b/src/plugins/axivion/axivionquery.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/axivion/axivionresultparser.cpp b/src/plugins/axivion/axivionresultparser.cpp index ba483e8f72e..0d8bb27b7db 100644 --- a/src/plugins/axivion/axivionresultparser.cpp +++ b/src/plugins/axivion/axivionresultparser.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "axivionresultparser.h" diff --git a/src/plugins/axivion/axivionresultparser.h b/src/plugins/axivion/axivionresultparser.h index 090b05d10af..84c5a6b8ca8 100644 --- a/src/plugins/axivion/axivionresultparser.h +++ b/src/plugins/axivion/axivionresultparser.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 2f827f9e750..9b171f90aee 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "axivionsettings.h" diff --git a/src/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h index 20763bee9ee..7946a150e3a 100644 --- a/src/plugins/axivion/axivionsettings.h +++ b/src/plugins/axivion/axivionsettings.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/axivion/axivionsettingspage.cpp b/src/plugins/axivion/axivionsettingspage.cpp index 2c55192a995..58765d23dfe 100644 --- a/src/plugins/axivion/axivionsettingspage.cpp +++ b/src/plugins/axivion/axivionsettingspage.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "axivionsettingspage.h" diff --git a/src/plugins/axivion/axivionsettingspage.h b/src/plugins/axivion/axivionsettingspage.h index 5dd52564800..7ed1c973bbd 100644 --- a/src/plugins/axivion/axivionsettingspage.h +++ b/src/plugins/axivion/axivionsettingspage.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/axivion/axiviontr.h b/src/plugins/axivion/axiviontr.h index 5a8398730a1..1f3475cb456 100644 --- a/src/plugins/axivion/axiviontr.h +++ b/src/plugins/axivion/axiviontr.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index b199706481e..6deee972959 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -7,6 +7,7 @@ Project { "android/android.qbs", "autotest/autotest.qbs", "autotoolsprojectmanager/autotoolsprojectmanager.qbs", + "axivion/axivion.qbs", "baremetal/baremetal.qbs", "bazaar/bazaar.qbs", "beautifier/beautifier.qbs", From 9bb126c0d6ff46bd00950261eb3eb9205f1d3879 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 10 May 2023 09:37:25 +0200 Subject: [PATCH 1244/1447] Utils: make column of convertPosition 0-based to merge it into Position Change-Id: I239b3cb33b8ad59ac4097c919155ab5ca7d57b8e Reviewed-by: Qt CI Bot Reviewed-by: Jarek Kobus --- src/libs/languageserverprotocol/lsptypes.cpp | 6 +++--- src/libs/utils/textutils.cpp | 4 ++-- src/libs/utils/textutils.h | 2 +- .../clangdqpropertyhighlighter.cpp | 4 ++-- .../clangdsemantichighlighting.cpp | 9 +++++++++ .../clangcodemodel/test/clangdtests.cpp | 20 +++++++++---------- .../cmakeprojectmanager/cmakeeditor.cpp | 11 +++++----- src/plugins/cppeditor/builtincursorinfo.cpp | 2 +- .../builtineditordocumentprocessor.cpp | 8 ++++---- src/plugins/cppeditor/cppcanonicalsymbol.cpp | 2 +- src/plugins/cppeditor/cppcompletionassist.cpp | 6 +++--- src/plugins/cppeditor/cppeditoroutline.cpp | 2 +- src/plugins/cppeditor/cppelementevaluator.cpp | 2 +- .../cppeditor/cppfollowsymbolundercursor.cpp | 13 ++++++------ src/plugins/cppeditor/cppoutline.cpp | 2 +- .../cppeditor/cppuseselections_test.cpp | 2 +- .../debugger/analyzer/analyzerutils.cpp | 2 +- .../debugger/debuggertooltipmanager.cpp | 1 + .../languageclientcompletionassist.cpp | 1 - .../editor/nimcompletionassistprovider.cpp | 4 ++-- .../nim/editor/nimtexteditorwidget.cpp | 2 +- .../qmakeprojectmanager/profileeditor.cpp | 19 +++++++++--------- src/plugins/texteditor/texteditor.cpp | 2 +- 23 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp index bd7798dcef9..72a5f9f4282 100644 --- a/src/libs/languageserverprotocol/lsptypes.cpp +++ b/src/libs/languageserverprotocol/lsptypes.cpp @@ -275,7 +275,7 @@ Position Position::withOffset(int offset, const QTextDocument *doc) const int line; int character; Utils::Text::convertPosition(doc, toPositionInDocument(doc) + offset, &line, &character); - return Position(line - 1, character - 1); + return Position(line - 1, character); } Range::Range(const Position &start, const Position &end) @@ -288,11 +288,11 @@ Range::Range(const QTextCursor &cursor) { int line, character = 0; Utils::Text::convertPosition(cursor.document(), cursor.selectionStart(), &line, &character); - if (line <= 0 || character <= 0) + if (line <= 0 || character < 0) return; setStart(Position(line - 1, character - 1)); Utils::Text::convertPosition(cursor.document(), cursor.selectionEnd(), &line, &character); - if (line <= 0 || character <= 0) + if (line <= 0 || character < 0) return; setEnd(Position(line - 1, character - 1)); } diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 8b17cc7e013..28a9e12e1bb 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -102,12 +102,12 @@ bool convertPosition(const QTextDocument *document, int pos, int *line, int *col QTextBlock block = document->findBlock(pos); if (!block.isValid()) { (*line) = -1; - (*column) = -1; + (*column) = 0; return false; } else { // line and column are both 1-based (*line) = block.blockNumber() + 1; - (*column) = pos - block.position() + 1; + (*column) = pos - block.position(); return true; } } diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index 96b7afbeb86..80e4150c1d2 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -68,7 +68,7 @@ using Replacements = std::vector; QTCREATOR_UTILS_EXPORT void applyReplacements(QTextDocument *doc, const Replacements &replacements); -// line is 1-based, column is 1-based +// line is 1-based, column is 0-based QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document, int pos, int *line, int *column); diff --git a/src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp b/src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp index e6e32b0e9ee..4a8db524ce8 100644 --- a/src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp +++ b/src/plugins/clangcodemodel/clangdqpropertyhighlighter.cpp @@ -394,10 +394,10 @@ void QPropertyHighlighter::Private::addResult(TextStyle textStyle, int symbolOff const Symbol &s = parser.symbol_lookup(symbolOffset); int line, column; Utils::Text::convertPosition(document, position + s.from, &line, &column); - if (line > 0 && column > 0) { + if (line > 0 && column >= 0) { TextStyles styles; styles.mainStyle = textStyle; - results << HighlightingResult(line, column, s.len, styles); + results << HighlightingResult(line, column + 1, s.len, styles); } } diff --git a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp index 30ffaa780e4..04bcc08fa2d 100644 --- a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp +++ b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp @@ -571,10 +571,12 @@ void ExtraHighlightingResultsCollector::insertAngleBracketInfo(int searchStart1, result.useTextSyles = true; result.textStyles.mainStyle = C_PUNCTUATION; Utils::Text::convertPosition(m_doc, absOpeningAngleBracketPos, &result.line, &result.column); + ++result.column; result.length = 1; result.kind = CppEditor::SemanticHighlighter::AngleBracketOpen; insertResult(result); Utils::Text::convertPosition(m_doc, absClosingAngleBracketPos, &result.line, &result.column); + ++result.column; result.kind = CppEditor::SemanticHighlighter::AngleBracketClose; insertResult(result); } @@ -646,10 +648,12 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod result.textStyles.mainStyle = C_PUNCTUATION; result.textStyles.mixinStyles.push_back(C_OPERATOR); Utils::Text::convertPosition(m_doc, absQuestionMarkPos, &result.line, &result.column); + ++result.column; result.length = 1; result.kind = CppEditor::SemanticHighlighter::TernaryIf; insertResult(result); Utils::Text::convertPosition(m_doc, absColonPos, &result.line, &result.column); + ++result.column; result.kind = CppEditor::SemanticHighlighter::TernaryElse; insertResult(result); return; @@ -837,10 +841,12 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod Utils::Text::convertPosition(m_doc, nodeStartPos + openingBracketOffset, &result.line, &result.column); + ++result.column; insertResult(result); Utils::Text::convertPosition(m_doc, nodeStartPos + closingBracketOffset, &result.line, &result.column); + ++result.column; insertResult(result); } return; @@ -885,6 +891,7 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod const int opStringOffsetInDoc = nodeStartPos + opStringOffset + detail.length() - opStringLen; Utils::Text::convertPosition(m_doc, opStringOffsetInDoc, &result.line, &result.column); + ++result.column; result.length = opStringLen; if (isArray || isCall) result.length = 1; @@ -906,9 +913,11 @@ void ExtraHighlightingResultsCollector::collectFromNode(const ClangdAstNode &nod return; Utils::Text::convertPosition(m_doc, nodeStartPos + openingParenOffset, &result.line, &result.column); + ++result.column; insertResult(result); Utils::Text::convertPosition(m_doc, nodeStartPos + closingParenOffset, &result.line, &result.column); + ++result.column; insertResult(result); } diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index e66515365b2..a90126c00e8 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -1539,7 +1539,7 @@ void ClangdTestCompletion::testCompleteGlobals() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(7), " globalFunction() /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(7, 20)); + QCOMPARE(manipulator.cursorPos(), qMakePair(7, 19)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1559,7 +1559,7 @@ void ClangdTestCompletion::testCompleteMembers() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(7), " s.member /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(7, 13)); + QCOMPARE(manipulator.cursorPos(), qMakePair(7, 12)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1577,7 +1577,7 @@ void ClangdTestCompletion::testCompleteMembersFromInside() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(4), " privateFunc() /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(4, 22)); + QCOMPARE(manipulator.cursorPos(), qMakePair(4, 21)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1595,7 +1595,7 @@ void ClangdTestCompletion::testCompleteMembersFromOutside() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(13), " c.publicFunc() /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(13, 19)); + QCOMPARE(manipulator.cursorPos(), qMakePair(13, 18)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1613,7 +1613,7 @@ void ClangdTestCompletion::testCompleteMembersFromFriend() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(14), " C().privateFunc() /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(14, 22)); + QCOMPARE(manipulator.cursorPos(), qMakePair(14, 21)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1630,7 +1630,7 @@ void ClangdTestCompletion::testFunctionAddress() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(7), " const auto p = &S::memberFunc /* COMPLETE HERE */;"); - QCOMPARE(manipulator.cursorPos(), qMakePair(7, 34)); + QCOMPARE(manipulator.cursorPos(), qMakePair(7, 33)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1696,7 +1696,7 @@ void ClangdTestCompletion::testCompleteClassAndConstructor() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(7), " Foo( /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(7, 9)); + QCOMPARE(manipulator.cursorPos(), qMakePair(7, 8)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1723,7 +1723,7 @@ void ClangdTestCompletion::testCompleteWithDotToArrowCorrection() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(4), " bar->member /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(4, 16)); + QCOMPARE(manipulator.cursorPos(), qMakePair(4, 15)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1754,7 +1754,7 @@ void ClangdTestCompletion::testCompleteCodeInGeneratedUiFile() Manipulator manipulator; item->apply(manipulator, cursorPos); QCOMPARE(manipulator.getLine(34), " ui->setupUi( /* COMPLETE HERE */"); - QCOMPARE(manipulator.cursorPos(), qMakePair(34, 17)); + QCOMPARE(manipulator.cursorPos(), qMakePair(34, 16)); QCOMPARE(manipulator.skipPos(), -1); } @@ -1882,7 +1882,7 @@ void ClangdTestCompletion::getProposal(const QString &fileName, int line, column; Text::convertPosition(doc->document(), pos, &line, &column); const auto editor = qobject_cast( - EditorManager::openEditorAt({doc->filePath(), line, column - 1})); + EditorManager::openEditorAt({doc->filePath(), line, column})); QVERIFY(editor); QCOMPARE(EditorManager::currentEditor(), editor); QCOMPARE(editor->textDocument(), doc); diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp index 9f507e14808..3411fd85b58 100644 --- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp @@ -147,18 +147,17 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor, int line = 0; int column = 0; convertPosition(cursor.position(), &line, &column); - const int positionInBlock = column - 1; const QString block = cursor.block().text(); // check if the current position is commented out const int hashPos = block.indexOf(QLatin1Char('#')); - if (hashPos >= 0 && hashPos < positionInBlock) + if (hashPos >= 0 && hashPos < column) return processLinkCallback(link); // find the beginning of a filename QString buffer; - int beginPos = positionInBlock - 1; + int beginPos = column - 1; while (beginPos >= 0) { if (isValidFileNameChar(block, beginPos)) { buffer.prepend(block.at(beginPos)); @@ -169,7 +168,7 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor, } // find the end of a filename - int endPos = positionInBlock; + int endPos = column; while (endPos < block.count()) { if (isValidFileNameChar(block, endPos)) { buffer.append(block.at(endPos)); @@ -199,8 +198,8 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor, return processLinkCallback(link); } link.targetFilePath = Utils::FilePath::fromString(fileName); - link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1; - link.linkTextEnd = cursor.position() - positionInBlock + endPos; + link.linkTextStart = cursor.position() - column + beginPos + 1; + link.linkTextEnd = cursor.position() - column + endPos; } processLinkCallback(link); } diff --git a/src/plugins/cppeditor/builtincursorinfo.cpp b/src/plugins/cppeditor/builtincursorinfo.cpp index ffc4d8b12a0..4545ebe748d 100644 --- a/src/plugins/cppeditor/builtincursorinfo.cpp +++ b/src/plugins/cppeditor/builtincursorinfo.cpp @@ -322,7 +322,7 @@ QFuture BuiltinCursorInfo::run(const CursorInfoParams &cursorInfoPar QString expression; Scope *scope = canonicalSymbol.getScopeAndExpression(textCursor, &expression); - return Utils::asyncRun(&FindUses::find, document, snapshot, line, column, scope, expression); + return Utils::asyncRun(&FindUses::find, document, snapshot, line, column + 1, scope, expression); } SemanticInfo::LocalUseMap diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index 4baa2bff341..8e551fd15be 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -92,10 +92,10 @@ CheckSymbols *createHighlighter(const CPlusPlus::Document::Ptr &doc, for (const CPlusPlus::Macro ¯o : doc->definedMacros()) { int line, column; convertPosition(textDocument, macro.utf16CharOffset(), &line, &column); - QTC_ASSERT(line >= 0 && column >= 0, qDebug() << doc->filePath() << macro.toString(); + QTC_ASSERT(line > 0 && column >= 0, qDebug() << doc->filePath() << macro.toString(); continue); - Result use(line, column, macro.nameToQString().size(), SemanticHighlighter::MacroUse); + Result use(line, column + 1, macro.nameToQString().size(), SemanticHighlighter::MacroUse); macroUses.append(use); } @@ -119,10 +119,10 @@ CheckSymbols *createHighlighter(const CPlusPlus::Document::Ptr &doc, int line, column; convertPosition(textDocument, macro.utf16charsBegin(), &line, &column); - QTC_ASSERT(line >= 0 && column >= 0, qDebug() << doc->filePath() + QTC_ASSERT(line > 0 && column >= 0, qDebug() << doc->filePath() << macro.macro().toString(); continue); - Result use(line, column, name.size(), SemanticHighlighter::MacroUse); + Result use(line, column + 1, name.size(), SemanticHighlighter::MacroUse); macroUses.append(use); } diff --git a/src/plugins/cppeditor/cppcanonicalsymbol.cpp b/src/plugins/cppeditor/cppcanonicalsymbol.cpp index 1df0c71cf96..102a5d07819 100644 --- a/src/plugins/cppeditor/cppcanonicalsymbol.cpp +++ b/src/plugins/cppeditor/cppcanonicalsymbol.cpp @@ -51,7 +51,7 @@ Scope *CanonicalSymbol::getScopeAndExpression(const QTextCursor &cursor, QString ExpressionUnderCursor expressionUnderCursor(m_document->languageFeatures()); *code = expressionUnderCursor(tc); - return m_document->scopeAt(line, column - 1); + return m_document->scopeAt(line, column); } Symbol *CanonicalSymbol::operator()(const QTextCursor &cursor) diff --git a/src/plugins/cppeditor/cppcompletionassist.cpp b/src/plugins/cppeditor/cppcompletionassist.cpp index e47bee37c44..5466f675eaf 100644 --- a/src/plugins/cppeditor/cppcompletionassist.cpp +++ b/src/plugins/cppeditor/cppcompletionassist.cpp @@ -1041,7 +1041,7 @@ int InternalCppCompletionAssistProcessor::startCompletionHelper() int line = 0, column = 0; Utils::Text::convertPosition(interface()->textDocument(), startOfExpression, &line, &column); return startCompletionInternal(interface()->filePath(), - line, column - 1, expression, endOfExpression); + line, column, expression, endOfExpression); } bool InternalCppCompletionAssistProcessor::tryObjCCompletion() @@ -1074,7 +1074,7 @@ bool InternalCppCompletionAssistProcessor::tryObjCCompletion() int line = 0, column = 0; Utils::Text::convertPosition(interface()->textDocument(), interface()->position(), &line, &column); - Scope *scope = thisDocument->scopeAt(line, column - 1); + Scope *scope = thisDocument->scopeAt(line, column); if (!scope) return false; @@ -1989,7 +1989,7 @@ bool InternalCppCompletionAssistProcessor::completeConstructorOrFunction(const Q int lineSigned = 0, columnSigned = 0; Utils::Text::convertPosition(interface()->textDocument(), interface()->position(), &lineSigned, &columnSigned); - unsigned line = lineSigned, column = columnSigned - 1; + unsigned line = lineSigned, column = columnSigned; // find a scope that encloses the current location, starting from the lastVisibileSymbol // and moving outwards diff --git a/src/plugins/cppeditor/cppeditoroutline.cpp b/src/plugins/cppeditor/cppeditoroutline.cpp index 701eea0a76d..a34d2543612 100644 --- a/src/plugins/cppeditor/cppeditoroutline.cpp +++ b/src/plugins/cppeditor/cppeditoroutline.cpp @@ -151,7 +151,7 @@ void CppEditorOutline::updateIndexNow() int line = 0, column = 0; m_editorWidget->convertPosition(m_editorWidget->position(), &line, &column); - QModelIndex comboIndex = m_model->indexForPosition(line, column - 1); + QModelIndex comboIndex = m_model->indexForPosition(line, column); if (comboIndex.isValid()) { QSignalBlocker blocker(m_combo); diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cppeditor/cppelementevaluator.cpp index 221c75dd837..27b481cd0c7 100644 --- a/src/plugins/cppeditor/cppelementevaluator.cpp +++ b/src/plugins/cppeditor/cppelementevaluator.cpp @@ -562,7 +562,7 @@ public: expression = expressionUnderCursor(m_tc); // Fetch the expression's code - *scope = doc->scopeAt(line, column - 1); + *scope = doc->scopeAt(line, column); return true; } QFuture> syncExec(const CPlusPlus::Snapshot &, diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp index d9ac0da2003..0353e16c302 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -485,7 +485,6 @@ void FollowSymbolUnderCursor::findLink( int line = 0; int column = 0; Utils::Text::convertPosition(document, cursor.position(), &line, &column); - const int positionInBlock = column - 1; Snapshot snapshot = theSnapshot; @@ -530,7 +529,7 @@ void FollowSymbolUnderCursor::findLink( for (int i = 0; i < tokens.size(); ++i) { const Token &tk = tokens.at(i); - if (positionInBlock >= tk.utf16charsBegin() && positionInBlock < tk.utf16charsEnd()) { + if (column >= tk.utf16charsBegin() && column < tk.utf16charsEnd()) { int closingParenthesisPos = tokens.size(); if (i >= 2 && tokens.at(i).is(T_IDENTIFIER) && tokens.at(i - 1).is(T_LPAREN) && (tokens.at(i - 2).is(T_SIGNAL) || tokens.at(i - 2).is(T_SLOT))) { @@ -572,7 +571,7 @@ void FollowSymbolUnderCursor::findLink( // In this case we want to look at one token before the current position to recognize // an operator if the cursor is inside the actual operator: operator[$] - if (positionInBlock >= tk.utf16charsBegin() && positionInBlock <= tk.utf16charsEnd()) { + if (column >= tk.utf16charsBegin() && column <= tk.utf16charsEnd()) { cursorRegionReached = true; if (tk.is(T_OPERATOR)) { link = attemptDeclDef(cursor, theSnapshot, @@ -582,7 +581,7 @@ void FollowSymbolUnderCursor::findLink( } else if (tk.isPunctuationOrOperator() && i > 0 && tokens.at(i - 1).is(T_OPERATOR)) { QTextCursor c = cursor; c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, - positionInBlock - tokens.at(i - 1).utf16charsBegin()); + column - tokens.at(i - 1).utf16charsBegin()); link = attemptDeclDef(c, theSnapshot, documentFromSemanticInfo, symbolFinder); if (link.hasValidLinkText()) return processLinkCallback(link); @@ -662,7 +661,7 @@ void FollowSymbolUnderCursor::findLink( } // Find the last symbol up to the cursor position - Scope *scope = doc->scopeAt(line, positionInBlock); + Scope *scope = doc->scopeAt(line, column); if (!scope) return processLinkCallback(link); @@ -684,7 +683,7 @@ void FollowSymbolUnderCursor::findLink( if (Symbol *d = r.declaration()) { if (d->asDeclaration() || d->asFunction()) { if (data.filePath() == d->filePath()) { - if (line == d->line() && positionInBlock >= d->column()) { + if (line == d->line() && column >= d->column()) { // TODO: check the end result = r; // take the symbol under cursor. break; @@ -697,7 +696,7 @@ void FollowSymbolUnderCursor::findLink( &tokenBeginColumnNumber); if (tokenBeginLineNumber > d->line() || (tokenBeginLineNumber == d->line() - && tokenBeginColumnNumber >= d->column())) { + && tokenBeginColumnNumber + 1 >= d->column())) { result = r; // take the symbol under cursor. break; } diff --git a/src/plugins/cppeditor/cppoutline.cpp b/src/plugins/cppeditor/cppoutline.cpp index d492ad4fa7e..0d8883f631d 100644 --- a/src/plugins/cppeditor/cppoutline.cpp +++ b/src/plugins/cppeditor/cppoutline.cpp @@ -168,7 +168,7 @@ void CppOutlineWidget::updateIndexNow() int line = 0, column = 0; m_editor->convertPosition(m_editor->position(), &line, &column); - QModelIndex index = m_model->indexForPosition(line, column - 1); + QModelIndex index = m_model->indexForPosition(line, column); if (index.isValid()) { m_blockCursorSync = true; diff --git a/src/plugins/cppeditor/cppuseselections_test.cpp b/src/plugins/cppeditor/cppuseselections_test.cpp index f2f13ea55f2..c9c56752844 100644 --- a/src/plugins/cppeditor/cppuseselections_test.cpp +++ b/src/plugins/cppeditor/cppuseselections_test.cpp @@ -104,7 +104,7 @@ SelectionList UseSelectionsTestCase::toSelectionList( int line, column; const int position = qMin(selection.cursor.position(), selection.cursor.anchor()); m_editorWidget->convertPosition(position, &line, &column); - result << Selection(line, column - 1, selection.cursor.selectedText().length()); + result << Selection(line, column, selection.cursor.selectedText().length()); } return result; } diff --git a/src/plugins/debugger/analyzer/analyzerutils.cpp b/src/plugins/debugger/analyzer/analyzerutils.cpp index dcfda572cb5..dc87b2ad614 100644 --- a/src/plugins/debugger/analyzer/analyzerutils.cpp +++ b/src/plugins/debugger/analyzer/analyzerutils.cpp @@ -52,7 +52,7 @@ CPlusPlus::Symbol *AnalyzerUtils::findSymbolUnderCursor() CPlusPlus::ExpressionUnderCursor expressionUnderCursor(doc->languageFeatures()); moveCursorToEndOfName(&tc); const QString &expression = expressionUnderCursor(tc); - CPlusPlus::Scope *scope = doc->scopeAt(line, column - 1); + CPlusPlus::Scope *scope = doc->scopeAt(line, column); CPlusPlus::TypeOfExpression typeOfExpression; typeOfExpression.init(doc, snapshot); diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 21ed34d5496..4f41436a460 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -1164,6 +1164,7 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested context.fileName = document->filePath(); context.position = pos; editorWidget->convertPosition(pos, &context.line, &context.column); + ++context.column; QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column, &context.function, &context.scopeFromLine, &context.scopeToLine); context.expression = fixCppExpression(raw); diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index f0b66facc18..c5c86122fcd 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -447,7 +447,6 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform() if (!Utils::Text::convertPosition(interface()->textDocument(), m_pos, &line, &column)) return nullptr; --line; // line is 0 based in the protocol - --column; // column is 0 based in the protocol params.setPosition({line, column}); params.setContext(context); params.setTextDocument( diff --git a/src/plugins/nim/editor/nimcompletionassistprovider.cpp b/src/plugins/nim/editor/nimcompletionassistprovider.cpp index c94001b348f..f732c45d173 100644 --- a/src/plugins/nim/editor/nimcompletionassistprovider.cpp +++ b/src/plugins/nim/editor/nimcompletionassistprovider.cpp @@ -142,8 +142,8 @@ private: { int line = 0, column = 0; Utils::Text::convertPosition(interface->textDocument(), pos, &line, &column); - QTC_ASSERT(column >= 1, return nullptr); - return suggest->sug(interface->filePath().toString(), line, column - 1, dirtyFile); + QTC_ASSERT(column >= 0, return nullptr); + return suggest->sug(interface->filePath().toString(), line, column, dirtyFile); } static std::unique_ptr writeDirtyFile(const TextEditor::AssistInterface *interface) diff --git a/src/plugins/nim/editor/nimtexteditorwidget.cpp b/src/plugins/nim/editor/nimtexteditorwidget.cpp index 52bcf64dca4..b297607dced 100644 --- a/src/plugins/nim/editor/nimtexteditorwidget.cpp +++ b/src/plugins/nim/editor/nimtexteditorwidget.cpp @@ -50,7 +50,7 @@ void NimTextEditorWidget::findLinkAt(const QTextCursor &c, const Utils::LinkHand std::shared_ptr request = suggest->def(path.toString(), line, - column - 1, + column, dirtyFile->fileName()); if (!request) diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp index b492112db3d..c17d3d91935 100644 --- a/src/plugins/qmakeprojectmanager/profileeditor.cpp +++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp @@ -117,23 +117,22 @@ void ProFileEditorWidget::findLinkAt(const QTextCursor &cursor, int line = 0; int column = 0; convertPosition(cursor.position(), &line, &column); - const int positionInBlock = column - 1; const QString block = cursor.block().text(); // check if the current position is commented out const int hashPos = block.indexOf(QLatin1Char('#')); - if (hashPos >= 0 && hashPos < positionInBlock) + if (hashPos >= 0 && hashPos < column) return processLinkCallback(link); // find the beginning of a filename QString buffer; - int beginPos = positionInBlock - 1; - int endPos = positionInBlock; + int beginPos = column - 1; + int endPos = column; // Check is cursor is somewhere on $${PWD}: - const int chunkStart = std::max(0, positionInBlock - 7); - const int chunkLength = 14 + std::min(0, positionInBlock - 7); + const int chunkStart = std::max(0, column - 7); + const int chunkLength = 14 + std::min(0, column - 7); QString chunk = block.mid(chunkStart, chunkLength); const QString curlyPwd = "$${PWD}"; @@ -145,7 +144,7 @@ void ProFileEditorWidget::findLinkAt(const QTextCursor &cursor, if (posCurlyPwd >= 0) { const int end = chunkStart + posCurlyPwd + curlyPwd.count(); const int start = chunkStart + posCurlyPwd; - if (start <= positionInBlock && end >= positionInBlock) { + if (start <= column && end >= column) { buffer = pwd; beginPos = chunkStart + posCurlyPwd - 1; endPos = end; @@ -154,7 +153,7 @@ void ProFileEditorWidget::findLinkAt(const QTextCursor &cursor, } else if (posPwd >= 0) { const int end = chunkStart + posPwd + pwd.count(); const int start = chunkStart + posPwd; - if (start <= positionInBlock && end >= positionInBlock) { + if (start <= column && end >= column) { buffer = pwd; beginPos = start - 1; endPos = end; @@ -229,8 +228,8 @@ void ProFileEditorWidget::findLinkAt(const QTextCursor &cursor, link.targetFilePath = FilePath::fromString(checkForPrfFile(buffer)); } if (!link.targetFilePath.isEmpty()) { - link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1; - link.linkTextEnd = cursor.position() - positionInBlock + endPos; + link.linkTextStart = cursor.position() - column + beginPos + 1; + link.linkTextEnd = cursor.position() - column + endPos; } processLinkCallback(link); } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index f001756bf90..ecb617aed70 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -3331,7 +3331,7 @@ void TextEditorWidget::restoreState(const QByteArray &state) d->m_lastCursorChangeWasInteresting = false; // avoid adding last position to history // line is 1-based, column is 0-based - gotoLine(lineVal, columnVal - 1); + gotoLine(lineVal, columnVal); verticalScrollBar()->setValue(vval); horizontalScrollBar()->setValue(hval); From 0d3d4892c636239d8e136d1bc9531f0b3438b48f Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 19 May 2023 15:21:51 +0200 Subject: [PATCH 1245/1447] CMakePM: Fix Qt detection for Presets with toolchain file When CMAKE_TOOLCHAIN_FILE and CMAKE_PREFIX_PATH were both set, the later was ignored. This resulted in Kits being created without Qt and without Qml Debugging. Task-number: QTCREATORBUG-28982 Change-Id: Ib45b4ac8335391f85a0b9c321196597d1c0a7a3f Reviewed-by: Alessandro Portale Reviewed-by: --- .../cmakeprojectmanager/cmakeprojectimporter.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index dc752f0a9f9..a2abd9cacff 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -330,6 +330,7 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config) FilePath cmakeExecutable = config.filePathValueOf(QByteArray("CMAKE_COMMAND")); FilePath cmakeMakeProgram = config.filePathValueOf(QByteArray("CMAKE_MAKE_PROGRAM")); FilePath hostPath = config.filePathValueOf(QByteArray("QT_HOST_PATH")); + const QString findRootPath = config.stringValueOf("CMAKE_FIND_ROOT_PATH"); QStringList args; args.push_back("-S"); @@ -350,13 +351,16 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config) if (!cmakeMakeProgram.isEmpty()) { args.push_back(QStringLiteral("-DCMAKE_MAKE_PROGRAM=%1").arg(cmakeMakeProgram.toString())); } - if (toolchainFile.isEmpty()) { - args.push_back(QStringLiteral("-DCMAKE_PREFIX_PATH=%1").arg(prefixPath)); - } else { - if (!prefixPath.isEmpty()) - args.push_back(QStringLiteral("-DCMAKE_FIND_ROOT_PATH=%1").arg(prefixPath)); + + if (!toolchainFile.isEmpty()) { args.push_back(QStringLiteral("-DCMAKE_TOOLCHAIN_FILE=%1").arg(toolchainFile.toString())); } + if (!prefixPath.isEmpty()) { + args.push_back(QStringLiteral("-DCMAKE_PREFIX_PATH=%1").arg(prefixPath)); + } + if (!findRootPath.isEmpty()) { + args.push_back(QStringLiteral("-DCMAKE_FIND_ROOT_PATH=%1").arg(findRootPath)); + } if (!hostPath.isEmpty()) { args.push_back(QStringLiteral("-DQT_HOST_PATH=%1").arg(hostPath.toString())); } From 31090ded156173e17a6be2772f4f098de60787a6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 24 May 2023 19:41:16 +0200 Subject: [PATCH 1246/1447] FileSearch: Remove unused function Change-Id: I8af9a3db055f530792e68095c22c696392f79872 Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Qt CI Bot --- src/libs/utils/filesearch.cpp | 10 ---------- src/libs/utils/filesearch.h | 4 ---- 2 files changed, 14 deletions(-) diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index 073b6057a90..a72ddc6ab04 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -10,7 +10,6 @@ #include "searchresultitem.h" #include "stringutils.h" #include "utilstr.h" -#include "utiltypes.h" #include #include @@ -499,15 +498,6 @@ static bool isFileIncluded(const QList &filterRegs, return isIncluded && (exclusionRegs.isEmpty() || !matches(exclusionRegs, filePath)); } -FilePathPredicate filterFileFunction(const QStringList &filters, const QStringList &exclusionFilters) -{ - const QList filterRegs = filtersToRegExps(filters); - const QList exclusionRegs = filtersToRegExps(exclusionFilters); - return [filterRegs, exclusionRegs](const FilePath &filePath) { - return isFileIncluded(filterRegs, exclusionRegs, filePath); - }; -} - std::function filterFilesFunction(const QStringList &filters, const QStringList &exclusionFilters) { diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index c3d81faa121..fc6ce62ab0b 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -23,10 +23,6 @@ QT_END_NAMESPACE namespace Utils { -QTCREATOR_UTILS_EXPORT -std::function filterFileFunction(const QStringList &filterRegs, - const QStringList &exclusionRegs); - QTCREATOR_UTILS_EXPORT std::function filterFilesFunction(const QStringList &filters, const QStringList &exclusionFilters); From f235a72554693414d39ae1d59dc42d13b7deca2a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 16 May 2023 14:57:37 +0200 Subject: [PATCH 1247/1447] TextEditor: add tests for semantic highlighter Change-Id: Id64c933f01c0dbc0e077656b6f4260b93e124311 Reviewed-by: Christian Stenger --- src/plugins/texteditor/syntaxhighlighter.cpp | 16 +- src/plugins/texteditor/syntaxhighlighter.h | 5 + tests/auto/CMakeLists.txt | 1 + tests/auto/auto.qbs | 1 + tests/auto/texteditor/CMakeLists.txt | 1 + .../texteditor/highlighter/CMakeLists.txt | 4 + .../texteditor/highlighter/highlighter.qbs | 15 + .../highlighter/tst_highlighter.cpp | 317 ++++++++++++++++++ tests/auto/texteditor/texteditor.qbs | 6 + 9 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 tests/auto/texteditor/CMakeLists.txt create mode 100644 tests/auto/texteditor/highlighter/CMakeLists.txt create mode 100644 tests/auto/texteditor/highlighter/highlighter.qbs create mode 100644 tests/auto/texteditor/highlighter/tst_highlighter.cpp create mode 100644 tests/auto/texteditor/texteditor.qbs diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index de72c7b0db6..6d2616193ef 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -23,8 +23,12 @@ class SyntaxHighlighterPrivate Q_DECLARE_PUBLIC(SyntaxHighlighter) public: SyntaxHighlighterPrivate() + : SyntaxHighlighterPrivate(TextEditorSettings::fontSettings()) + { } + + SyntaxHighlighterPrivate(const FontSettings &fontSettings) { - updateFormats(TextEditorSettings::fontSettings()); + updateFormats(fontSettings); } QPointer doc; @@ -76,6 +80,16 @@ void SyntaxHighlighter::delayedRehighlight() rehighlight(); } +#ifdef WITH_TESTS +SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent, const FontSettings &fontsettings) + : QObject(parent), d_ptr(new SyntaxHighlighterPrivate(fontsettings)) +{ + d_ptr->q_ptr = this; + if (parent) + setDocument(parent); +} +#endif + void SyntaxHighlighterPrivate::applyFormatChanges(int from, int charsRemoved, int charsAdded) { bool formatsChanged = false; diff --git a/src/plugins/texteditor/syntaxhighlighter.h b/src/plugins/texteditor/syntaxhighlighter.h index 7a1822e4667..1b66e2ff56a 100644 --- a/src/plugins/texteditor/syntaxhighlighter.h +++ b/src/plugins/texteditor/syntaxhighlighter.h @@ -91,6 +91,11 @@ private: void delayedRehighlight(); QScopedPointer d_ptr; + +#ifdef WITH_TESTS + friend class tst_highlighter; + SyntaxHighlighter(QTextDocument *parent, const FontSettings &fontsettings); +#endif }; } // namespace TextEditor diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index 9849f8776ec..5dcd026a7af 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(qml) add_subdirectory(runextensions) add_subdirectory(sdktool) add_subdirectory(solutions) +add_subdirectory(texteditor) add_subdirectory(toolchaincache) add_subdirectory(tracing) add_subdirectory(treeviewfind) diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs index 063977537ba..603b5cd1b15 100644 --- a/tests/auto/auto.qbs +++ b/tests/auto/auto.qbs @@ -23,6 +23,7 @@ Project { "runextensions/runextensions.qbs", "sdktool/sdktool.qbs", "solutions/solutions.qbs", + "texteditor/texteditor.qbs", "toolchaincache/toolchaincache.qbs", "tracing/tracing.qbs", "treeviewfind/treeviewfind.qbs", diff --git a/tests/auto/texteditor/CMakeLists.txt b/tests/auto/texteditor/CMakeLists.txt new file mode 100644 index 00000000000..23684431c43 --- /dev/null +++ b/tests/auto/texteditor/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(highlighter) diff --git a/tests/auto/texteditor/highlighter/CMakeLists.txt b/tests/auto/texteditor/highlighter/CMakeLists.txt new file mode 100644 index 00000000000..76370bf8255 --- /dev/null +++ b/tests/auto/texteditor/highlighter/CMakeLists.txt @@ -0,0 +1,4 @@ +add_qtc_test(tst_highlighter + DEPENDS TextEditor Utils Qt::Widgets + SOURCES tst_highlighter.cpp +) diff --git a/tests/auto/texteditor/highlighter/highlighter.qbs b/tests/auto/texteditor/highlighter/highlighter.qbs new file mode 100644 index 00000000000..641a71ef66d --- /dev/null +++ b/tests/auto/texteditor/highlighter/highlighter.qbs @@ -0,0 +1,15 @@ +import qbs + +QtcAutotest { + + Depends { name: "TextEditor" } + Depends { name: "Utils" } + Depends { name: "Qt.widgets" } // For QTextDocument & friends + + name: "Highlighter autotest" + + Group { + name: "Source Files" + files: "tst_highlighter.cpp" + } +} diff --git a/tests/auto/texteditor/highlighter/tst_highlighter.cpp b/tests/auto/texteditor/highlighter/tst_highlighter.cpp new file mode 100644 index 00000000000..163699c0cb1 --- /dev/null +++ b/tests/auto/texteditor/highlighter/tst_highlighter.cpp @@ -0,0 +1,317 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef WITH_TESTS +#define WITH_TESTS +#endif + +#include +#include +#include + +#include +#include +#include +#include + +namespace TextEditor { + +class tst_highlighter: public QObject +{ + Q_OBJECT + +private slots: + void init_testCase(); + void init(); + void test_setExtraAdditionalFormats(); + void test_clearExtraFormats(); + void test_incrementalApplyAdditionalFormats(); + void cleanup(); + +private: + QTextDocument *doc = nullptr; + SyntaxHighlighter *highlighter = nullptr; + FontSettings fontsettings; + QHash formatHash; + QTextCharFormat whitespaceFormat; +}; + +void tst_highlighter::init_testCase() +{ + QTextCharFormat c0; + c0.setFontItalic(true); + formatHash[0] = c0; + QTextCharFormat c1; + c1.setFontOverline(true); + formatHash[1] = c1; +} + +void tst_highlighter::init() +{ + const QString text = +R"(First +Second with spaces + +Last)"; + + + doc = new QTextDocument(); + doc->setPlainText(text); + + highlighter = new SyntaxHighlighter(doc, fontsettings); +} + +static const HighlightingResults &highlightingResults() +{ + static HighlightingResults results{HighlightingResult(), + HighlightingResult(1, 1, 5, 0), + HighlightingResult(2, 4, 7, 0), + HighlightingResult(2, 17, 5, 1), + HighlightingResult(4, 1, 8, 0), + HighlightingResult(6, 1, 8, 1)}; + return results; +} + +void tst_highlighter::test_setExtraAdditionalFormats() +{ + QCOMPARE(doc->blockCount(), 4); + + SemanticHighlighter::setExtraAdditionalFormats(highlighter, highlightingResults(), formatHash); + + for (auto block = doc->firstBlock(); block.isValid(); block = block.next()) { + QVERIFY(block.blockNumber() < 4); + QVERIFY(block.layout()); + auto formats = block.layout()->formats(); + switch (block.blockNumber()) { + case 0: // First + QCOMPARE(formats.size(), 1); + QCOMPARE(formats.at(0).format.fontItalic(), true); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 5); + break; + case 1: // Second with spaces + QCOMPARE(formats.size(), 4); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 6); + QCOMPARE(formats.at(0).length, 1); + + QCOMPARE(formats.at(1).format.fontItalic(), false); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 11); + QCOMPARE(formats.at(1).length, 1); + + QCOMPARE(formats.at(2).format.fontItalic(), true); + QCOMPARE(formats.at(2).format.fontOverline(), false); + QCOMPARE(formats.at(2).start, 3); + QCOMPARE(formats.at(2).length, 7); + + QCOMPARE(formats.at(3).format.fontItalic(), false); + QCOMPARE(formats.at(3).format.fontOverline(), true); + QCOMPARE(formats.at(3).start, 16); + QCOMPARE(formats.at(3).length, 3); + break; + case 2: // + QCOMPARE(formats.size(), 1); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), true); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 1); + break; + case 3: // Last + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), true); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 1); + + QCOMPARE(formats.at(1).format.fontItalic(), true); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 0); + QCOMPARE(formats.at(1).length, 5); + break; + } + } +} + +void tst_highlighter::test_clearExtraFormats() +{ + QCOMPARE(doc->blockCount(), 4); + + SemanticHighlighter::setExtraAdditionalFormats(highlighter, highlightingResults(), formatHash); + + QTextBlock firstBlock = doc->findBlockByNumber(0); + QTextBlock spacesLineBlock = doc->findBlockByNumber(1); + QTextBlock emptyLineBlock = doc->findBlockByNumber(2); + QTextBlock lastBlock = doc->findBlockByNumber(3); + + highlighter->clearExtraFormats(emptyLineBlock); + QVERIFY(emptyLineBlock.layout()->formats().isEmpty()); + + highlighter->clearExtraFormats(spacesLineBlock); + + auto formats = spacesLineBlock.layout()->formats(); + // the spaces are not extra formats and should remain when clearing extra formats + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 6); + QCOMPARE(formats.at(0).length, 1); + + QCOMPARE(formats.at(1).format.fontItalic(), false); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 11); + QCOMPARE(formats.at(1).length, 1); + + // first and last should be untouched + formats = firstBlock.layout()->formats(); + QCOMPARE(formats.size(), 1); + QCOMPARE(formats.at(0).format.fontItalic(), true); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 5); + + formats = lastBlock.layout()->formats(); + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), true); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 1); + + QCOMPARE(formats.at(1).format.fontItalic(), true); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 0); + QCOMPARE(formats.at(1).length, 5); + + highlighter->clearAllExtraFormats(); + + QVERIFY(firstBlock.layout()->formats().isEmpty()); + QVERIFY(emptyLineBlock.layout()->formats().isEmpty()); + formats = spacesLineBlock.layout()->formats(); + + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 6); + QCOMPARE(formats.at(0).length, 1); + + QCOMPARE(formats.at(1).format.fontItalic(), false); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 11); + QCOMPARE(formats.at(1).length, 1); + + QVERIFY(lastBlock.layout()->formats().isEmpty()); +} + +void tst_highlighter::test_incrementalApplyAdditionalFormats() +{ + const HighlightingResults newResults{HighlightingResult(), + HighlightingResult(1, 1, 5, 0), + HighlightingResult(2, 4, 7, 0), + HighlightingResult(4, 1, 8, 0), + HighlightingResult(6, 1, 8, 1)}; + + QCOMPARE(doc->blockCount(), 4); + QTextBlock firstBlock = doc->findBlockByNumber(0); + QTextBlock spacesLineBlock = doc->findBlockByNumber(1); + QTextBlock emptyLineBlock = doc->findBlockByNumber(2); + QTextBlock lastBlock = doc->findBlockByNumber(3); + + QFutureInterface fiOld; + fiOld.reportResults(highlightingResults()); + SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter, + fiOld.future(), + 2, + 0, + formatHash); + auto formats = firstBlock.layout()->formats(); + QVERIFY(formats.isEmpty()); + + SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter, + fiOld.future(), + 0, + 2, + formatHash); + + formats = firstBlock.layout()->formats(); + QCOMPARE(formats.at(0).format.fontItalic(), true); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 5); + + formats = spacesLineBlock.layout()->formats(); + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 6); + QCOMPARE(formats.at(0).length, 1); + + QCOMPARE(formats.at(1).format.fontItalic(), false); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 11); + QCOMPARE(formats.at(1).length, 1); + + SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter, + fiOld.future(), + 3, + 6, + formatHash); + + formats = firstBlock.layout()->formats(); + QCOMPARE(formats.at(0).format.fontItalic(), true); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 5); + + formats = lastBlock.layout()->formats(); + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), true); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 1); + + QCOMPARE(formats.at(1).format.fontItalic(), true); + QCOMPARE(formats.at(1).format.fontOverline(), false); + QCOMPARE(formats.at(1).start, 0); + QCOMPARE(formats.at(1).length, 5); + + QFutureInterface fiNew; + fiNew.reportResults(newResults); + SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter, + fiNew.future(), + 0, + 3, + formatHash); + + // should still contain the highlight from oldResults + formats = emptyLineBlock.layout()->formats(); + QCOMPARE(formats.size(), 1); + QCOMPARE(formats.at(0).format.fontItalic(), false); + QCOMPARE(formats.at(0).format.fontOverline(), true); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 1); + + SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter, + fiNew.future(), + 3, + 4, + formatHash); + + // should have no results since the new results do not contain a highlight at that position + formats = emptyLineBlock.layout()->formats(); + QVERIFY(formats.isEmpty()); +} + +void tst_highlighter::cleanup() +{ + delete doc; + doc = nullptr; + highlighter = nullptr; +} + +} // namespace TextEditor + +QTEST_MAIN(TextEditor::tst_highlighter) + +#include "tst_highlighter.moc" diff --git a/tests/auto/texteditor/texteditor.qbs b/tests/auto/texteditor/texteditor.qbs new file mode 100644 index 00000000000..957bb448f16 --- /dev/null +++ b/tests/auto/texteditor/texteditor.qbs @@ -0,0 +1,6 @@ +import qbs + +Project { + name: "TextEditor autotests" + references: [ "highlighter/highlighter.qbs" ] +} From 414e1712268cc159370dcb3dabaefb816f65474a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 24 May 2023 16:03:13 +0200 Subject: [PATCH 1248/1447] Axivion: Start aspectification of settings Change-Id: I866d41fd152509893a90ca0552b9d0c3ab21333b Reviewed-by: hjk --- .../axivion/axivionprojectsettings.cpp | 2 +- src/plugins/axivion/axivionquery.cpp | 2 +- src/plugins/axivion/axivionsettings.cpp | 24 +++--- src/plugins/axivion/axivionsettings.h | 6 +- src/plugins/axivion/axivionsettingspage.cpp | 83 ++++++++++--------- src/plugins/axivion/axivionsettingspage.h | 31 ------- 6 files changed, 62 insertions(+), 86 deletions(-) diff --git a/src/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp index 351696b525b..32689ae950d 100644 --- a/src/plugins/axivion/axivionprojectsettings.cpp +++ b/src/plugins/axivion/axivionprojectsettings.cpp @@ -163,7 +163,7 @@ void AxivionProjectSettingsWidget::updateUi() void AxivionProjectSettingsWidget::updateEnabledStates() { - const bool hasDashboardSettings = m_globalSettings->curl.isExecutableFile() + const bool hasDashboardSettings = m_globalSettings->curl().isExecutableFile() && !m_globalSettings->server.dashboard.isEmpty() && !m_globalSettings->server.token.isEmpty(); const bool linked = !m_projectSettings->dashboardProjectName().isEmpty(); diff --git a/src/plugins/axivion/axivionquery.cpp b/src/plugins/axivion/axivionquery.cpp index 657ee613a1b..fda0eccf128 100644 --- a/src/plugins/axivion/axivionquery.cpp +++ b/src/plugins/axivion/axivionquery.cpp @@ -65,7 +65,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren url += query.toString(); args << url; - m_process.setCommand({settings->curl, args}); + m_process.setCommand({settings->curl(), args}); connect(&m_process, &Process::done, this, [this]{ if (m_process.result() != ProcessResult::FinishedWithSuccess) { const int exitCode = m_process.exitCode(); diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 9b171f90aee..4a183631633 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -3,6 +3,9 @@ #include "axivionsettings.h" +#include "axiviontr.h" + +#include #include #include @@ -12,8 +15,6 @@ namespace Axivion::Internal { -const char curlKeyC[] = "Curl"; - AxivionServer::AxivionServer(const Utils::Id &id, const QString &dashboard, const QString &description, const QString &token) : id(id) @@ -73,6 +74,11 @@ QStringList AxivionServer::curlArguments() const AxivionSettings::AxivionSettings() { + setSettingsGroup("Axivion"); + + curl.setSettingsKey("Curl"); + curl.setLabelText(Tr::tr("curl:")); + curl.setExpectedKind(Utils::PathChooser::ExistingCommand); } static Utils::FilePath tokensFilePath(const QSettings *s) @@ -106,25 +112,19 @@ static AxivionServer readTokenFile(const Utils::FilePath &filePath) void AxivionSettings::toSettings(QSettings *s) const { writeTokenFile(tokensFilePath(s), server); - - s->beginGroup("Axivion"); - s->setValue(curlKeyC, curl.toVariant()); - s->endGroup(); + Utils::AspectContainer::writeSettings(s); } void AxivionSettings::fromSettings(QSettings *s) { - s->beginGroup("Axivion"); - curl = Utils::FilePath::fromVariant(curlKeyC); - s->endGroup(); - + Utils::AspectContainer::readSettings(s); server = readTokenFile(tokensFilePath(s)); - if (curl.isEmpty() || !curl.exists()) { + if (curl().isEmpty() || !curl().exists()) { const QString curlPath = QStandardPaths::findExecutable( Utils::HostOsInfo::withExecutableSuffix("curl")); if (!curlPath.isEmpty()) - curl = Utils::FilePath::fromString(curlPath); + curl.setFilePath(Utils::FilePath::fromString(curlPath)); } } diff --git a/src/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h index 7946a150e3a..0df1746387f 100644 --- a/src/plugins/axivion/axivionsettings.h +++ b/src/plugins/axivion/axivionsettings.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include #include @@ -37,7 +37,7 @@ public: bool validateCert = true; }; -class AxivionSettings +class AxivionSettings : public Utils::AspectContainer { public: AxivionSettings(); @@ -45,7 +45,7 @@ public: void fromSettings(QSettings *s); AxivionServer server; // shall we have more than one? - Utils::FilePath curl; + Utils::FilePathAspect curl{this}; }; } // Axivion::Internal diff --git a/src/plugins/axivion/axivionsettingspage.cpp b/src/plugins/axivion/axivionsettingspage.cpp index 58765d23dfe..e837d71598d 100644 --- a/src/plugins/axivion/axivionsettingspage.cpp +++ b/src/plugins/axivion/axivionsettingspage.cpp @@ -8,6 +8,8 @@ #include "axiviontr.h" #include +#include +#include #include #include @@ -46,7 +48,27 @@ static bool isUrlValid(const QString &in) return hostValid(url.host()) && (url.scheme() == "https" || url.scheme() == "http"); } -DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) +class DashboardSettingsWidget : public QWidget +{ +public: + enum Mode { Display, Edit }; + explicit DashboardSettingsWidget(Mode m, QWidget *parent, QPushButton *ok = nullptr); + + AxivionServer dashboardServer() const; + void setDashboardServer(const AxivionServer &server); + + bool isValid() const; + +private: + Mode m_mode = Display; + Id m_id; + StringAspect m_dashboardUrl; + StringAspect m_description; + StringAspect m_token; + BoolAspect m_valid; +}; + +DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPushButton *ok) : QWidget(parent) , m_mode(mode) { @@ -67,28 +89,22 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) using namespace Layouting; - Row { - Form { - m_dashboardUrl, - m_description, - m_token, - mode == Edit ? normalMargin : noMargin - } + Form { + m_dashboardUrl, br, + m_description, br, + m_token, br, + mode == Edit ? normalMargin : noMargin }.attachTo(this); - auto checkValidity = [this] { - bool old = m_valid; - m_valid = isValid(); - if (old != m_valid) - emit validChanged(m_valid); - }; if (mode == Edit) { - connect(&m_dashboardUrl, &StringAspect::valueChanged, - this, checkValidity); - connect(&m_description, &StringAspect::valueChanged, - this, checkValidity); - connect(&m_token, &StringAspect::valueChanged, - this, checkValidity); + QTC_ASSERT(ok, return); + auto checkValidity = [this, ok] { + m_valid.setValue(isValid()); + ok->setEnabled(m_valid()); + }; + connect(&m_dashboardUrl, &BaseAspect::changed, this, checkValidity); + connect(&m_description, &BaseAspect::changed, this, checkValidity); + connect(&m_token, &BaseAspect::changed, this, checkValidity); } } @@ -99,9 +115,9 @@ AxivionServer DashboardSettingsWidget::dashboardServer() const result.id = m_id; else result.id = m_mode == Edit ? Utils::Id::fromName(QUuid::createUuid().toByteArray()) : m_id; - result.dashboard = m_dashboardUrl.value(); - result.description = m_description.value(); - result.token = m_token.value(); + result.dashboard = m_dashboardUrl(); + result.description = m_description(); + result.token = m_token(); return result; } @@ -115,8 +131,7 @@ void DashboardSettingsWidget::setDashboardServer(const AxivionServer &server) bool DashboardSettingsWidget::isValid() const { - return !m_token.value().isEmpty() && !m_description.value().isEmpty() - && isUrlValid(m_dashboardUrl.value()); + return !m_token().isEmpty() && !m_description().isEmpty() && isUrlValid(m_dashboardUrl()); } class AxivionSettingsWidget : public Core::IOptionsPageWidget @@ -130,7 +145,6 @@ private: AxivionSettings *m_settings; - Utils::StringAspect m_curlPC; DashboardSettingsWidget *m_dashboardDisplay = nullptr; QPushButton *m_edit = nullptr; }; @@ -143,14 +157,10 @@ AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) m_dashboardDisplay = new DashboardSettingsWidget(DashboardSettingsWidget::Display, this); m_dashboardDisplay->setDashboardServer(m_settings->server); m_edit = new QPushButton(Tr::tr("Edit..."), this); - m_curlPC.setLabelText(Tr::tr("curl:")); - m_curlPC.setDisplayStyle(StringAspect::PathChooserDisplay); - m_curlPC.setExpectedKind(PathChooser::ExistingCommand); - m_curlPC.setFilePath(m_settings->curl); - Grid { + Row { Form { m_dashboardDisplay, br, - m_curlPC, br, + m_settings->curl, br, }, Column { m_edit, st } }.attachTo(this); @@ -160,7 +170,6 @@ AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) void AxivionSettingsWidget::apply() { m_settings->server = m_dashboardDisplay->dashboardServer(); - m_settings->curl = m_curlPC.filePath(); m_settings->toSettings(Core::ICore::settings()); emit AxivionPlugin::instance()->settingsChanged(); } @@ -171,16 +180,14 @@ void AxivionSettingsWidget::showEditServerDialog() QDialog d; d.setWindowTitle(Tr::tr("Edit Dashboard Configuration")); QVBoxLayout *layout = new QVBoxLayout; - DashboardSettingsWidget *dashboardWidget = new DashboardSettingsWidget(DashboardSettingsWidget::Edit, this); - dashboardWidget->setDashboardServer(old); - layout->addWidget(dashboardWidget); auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, this); auto ok = buttons->button(QDialogButtonBox::Ok); + auto dashboardWidget = new DashboardSettingsWidget(DashboardSettingsWidget::Edit, this, ok); + dashboardWidget->setDashboardServer(old); + layout->addWidget(dashboardWidget); ok->setEnabled(m_dashboardDisplay->isValid()); connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, &d, &QDialog::reject); connect(ok, &QPushButton::clicked, &d, &QDialog::accept); - connect(dashboardWidget, &DashboardSettingsWidget::validChanged, - ok, &QPushButton::setEnabled); layout->addWidget(buttons); d.setLayout(layout); d.resize(500, 200); diff --git a/src/plugins/axivion/axivionsettingspage.h b/src/plugins/axivion/axivionsettingspage.h index 7ed1c973bbd..744818300d9 100644 --- a/src/plugins/axivion/axivionsettingspage.h +++ b/src/plugins/axivion/axivionsettingspage.h @@ -4,41 +4,10 @@ #pragma once #include -#include -#include - -#include -#include namespace Axivion::Internal { -class AxivionServer; class AxivionSettings; -class AxivionSettingsWidget; - -class DashboardSettingsWidget : public QWidget -{ - Q_OBJECT -public: - enum Mode { Display, Edit }; - explicit DashboardSettingsWidget(Mode m = Display, QWidget *parent = nullptr); - - AxivionServer dashboardServer() const; - void setDashboardServer(const AxivionServer &server); - - bool isValid() const; - -signals: - void validChanged(bool valid); -private: - Mode m_mode = Display; - Utils::Id m_id; - Utils::StringAspect m_dashboardUrl; - Utils::StringAspect m_description; - Utils::StringAspect m_token; - bool m_valid = false; -}; - class AxivionSettingsPage : public Core::IOptionsPage { From 85f16335628769e84942ad2d4140c3409890240b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 25 May 2023 07:31:04 +0200 Subject: [PATCH 1249/1447] LSP: Fix Range(QTextCursor &) constructor amends 9bb126c0d6ff46bd00950261eb3eb9205f1d3879 Change-Id: I5afe9ecfff2339593368eb24e2b034460ce197e8 Reviewed-by: Christian Kandeler --- src/libs/languageserverprotocol/lsptypes.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp index 72a5f9f4282..6f0b57c1e35 100644 --- a/src/libs/languageserverprotocol/lsptypes.cpp +++ b/src/libs/languageserverprotocol/lsptypes.cpp @@ -290,11 +290,11 @@ Range::Range(const QTextCursor &cursor) Utils::Text::convertPosition(cursor.document(), cursor.selectionStart(), &line, &character); if (line <= 0 || character < 0) return; - setStart(Position(line - 1, character - 1)); + setStart(Position(line - 1, character)); Utils::Text::convertPosition(cursor.document(), cursor.selectionEnd(), &line, &character); if (line <= 0 || character < 0) return; - setEnd(Position(line - 1, character - 1)); + setEnd(Position(line - 1, character)); } bool Range::contains(const Range &other) const From 6c66b900dbb1064da97abbec1809fe5538eb5acb Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 08:58:36 +0200 Subject: [PATCH 1250/1447] ProjectExplorer: Merge LocalEnvironmentAspect into EnvironmentAspect This still has some not quite orthogonal features in one blob function, but at least it's not a separate class anymore. A step forward to remote support in places where it could make sense. Change-Id: Ia02003e4340eb2b5ee92bd48c00006a487527828 Reviewed-by: Christian Kandeler --- .../haskell/haskellrunconfiguration.cpp | 6 +-- .../mesonrunconfiguration.cpp | 6 +-- .../nim/project/nimblerunconfiguration.cpp | 5 +- .../nim/project/nimrunconfiguration.cpp | 5 +- src/plugins/projectexplorer/CMakeLists.txt | 1 - .../customexecutablerunconfiguration.cpp | 4 +- .../desktoprunconfiguration.cpp | 6 +-- .../projectexplorer/environmentaspect.cpp | 24 ++++++++++ .../projectexplorer/environmentaspect.h | 2 + .../localenvironmentaspect.cpp | 46 ------------------- .../projectexplorer/localenvironmentaspect.h | 18 -------- .../projectexplorer/projectexplorer.qbs | 1 - src/plugins/python/pythonplugin.cpp | 1 - src/plugins/python/pythonrunconfiguration.cpp | 4 +- 14 files changed, 45 insertions(+), 84 deletions(-) delete mode 100644 src/plugins/projectexplorer/localenvironmentaspect.cpp delete mode 100644 src/plugins/projectexplorer/localenvironmentaspect.h diff --git a/src/plugins/haskell/haskellrunconfiguration.cpp b/src/plugins/haskell/haskellrunconfiguration.cpp index c4caf175058..76d25e557c3 100644 --- a/src/plugins/haskell/haskellrunconfiguration.cpp +++ b/src/plugins/haskell/haskellrunconfiguration.cpp @@ -9,7 +9,6 @@ #include "haskellsettings.h" #include -#include #include #include #include @@ -35,7 +34,8 @@ HaskellExecutableAspect::HaskellExecutableAspect() HaskellRunConfiguration::HaskellRunConfiguration(Target *target, Utils::Id id) : RunConfiguration(target, id) { - auto envAspect = addAspect(target); + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); addAspect(); addAspect(macroExpander()); @@ -67,7 +67,7 @@ Runnable HaskellRunConfiguration::runnable() const args << "--" << arguments; r.workingDirectory = projectDirectory; - r.environment = aspect()->environment(); + r.environment = aspect()->environment(); r.command = {r.environment.searchInPath(settings().stackPath().path()), args}; return r; } diff --git a/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp b/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp index 3731ec4da6b..4af312fda9c 100644 --- a/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp +++ b/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -24,7 +23,8 @@ namespace Internal { MesonRunConfiguration::MesonRunConfiguration(Target *target, Utils::Id id) : RunConfiguration{target, id} { - auto envAspect = addAspect(target); + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); addAspect(target, ExecutableAspect::RunDevice); addAspect(macroExpander()); @@ -65,7 +65,7 @@ void MesonRunConfiguration::updateTargetInformation() aspect()->setUseTerminalHint(bti.usesTerminal); aspect()->setExecutable(bti.targetFilePath); aspect()->setDefaultWorkingDirectory(bti.workingDirectory); - emit aspect()->environmentChanged(); + emit aspect()->environmentChanged(); } MesonRunConfigurationFactory::MesonRunConfigurationFactory() diff --git a/src/plugins/nim/project/nimblerunconfiguration.cpp b/src/plugins/nim/project/nimblerunconfiguration.cpp index f26a375410b..8fa24ee33e4 100644 --- a/src/plugins/nim/project/nimblerunconfiguration.cpp +++ b/src/plugins/nim/project/nimblerunconfiguration.cpp @@ -7,7 +7,6 @@ #include "nimconstants.h" #include "nimtr.h" -#include #include #include #include @@ -27,7 +26,9 @@ public: NimbleRunConfiguration(Target *target, Utils::Id id) : RunConfiguration(target, id) { - auto envAspect = addAspect(target); + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); + addAspect(target, ExecutableAspect::RunDevice); addAspect(macroExpander()); addAspect(macroExpander(), envAspect); diff --git a/src/plugins/nim/project/nimrunconfiguration.cpp b/src/plugins/nim/project/nimrunconfiguration.cpp index 5faaa0871c0..79eeeb898dd 100644 --- a/src/plugins/nim/project/nimrunconfiguration.cpp +++ b/src/plugins/nim/project/nimrunconfiguration.cpp @@ -8,7 +8,6 @@ #include "../nimtr.h" #include -#include #include #include @@ -27,7 +26,9 @@ public: NimRunConfiguration(Target *target, Utils::Id id) : RunConfiguration(target, id) { - auto envAspect = addAspect(target); + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); + addAspect(target, ExecutableAspect::RunDevice); addAspect(macroExpander()); addAspect(macroExpander(), envAspect); diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 1ed25adadac..a016924bc70 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -115,7 +115,6 @@ add_qtc_plugin(ProjectExplorer ldparser.cpp ldparser.h lldparser.cpp lldparser.h linuxiccparser.cpp linuxiccparser.h - localenvironmentaspect.cpp localenvironmentaspect.h makestep.cpp makestep.h miniprojecttargetselector.cpp miniprojecttargetselector.h msvcparser.cpp msvcparser.h diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp index 9d25bb7dfe6..00f7225d0df 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp @@ -3,7 +3,6 @@ #include "customexecutablerunconfiguration.h" -#include "localenvironmentaspect.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "runconfigurationaspects.h" @@ -24,7 +23,8 @@ CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *targe CustomExecutableRunConfiguration::CustomExecutableRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - auto envAspect = addAspect(target); + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); auto exeAspect = addAspect(target, ExecutableAspect::HostDevice); exeAspect->setSettingsKey("ProjectExplorer.CustomExecutableRunConfiguration.Executable"); diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp index 286f5c4b6e0..8b8cdf2b793 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp +++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp @@ -4,7 +4,6 @@ #include "desktoprunconfiguration.h" #include "buildsystem.h" -#include "localenvironmentaspect.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" #include "runconfigurationaspects.h" @@ -43,7 +42,8 @@ private: DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Id id, Kind kind) : RunConfiguration(target, id), m_kind(kind) { - auto envAspect = addAspect(target); + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); addAspect(target, ExecutableAspect::RunDevice); addAspect(macroExpander()); @@ -122,7 +122,7 @@ void DesktopRunConfiguration::updateTargetInformation() aspect()->setExecutable(bti.targetFilePath); aspect()->setDefaultWorkingDirectory(bti.workingDirectory); - emit aspect()->environmentChanged(); + emit aspect()->environmentChanged(); } } diff --git a/src/plugins/projectexplorer/environmentaspect.cpp b/src/plugins/projectexplorer/environmentaspect.cpp index dc3abedbe74..09bfeb9c80d 100644 --- a/src/plugins/projectexplorer/environmentaspect.cpp +++ b/src/plugins/projectexplorer/environmentaspect.cpp @@ -3,8 +3,11 @@ #include "environmentaspect.h" +#include "buildconfiguration.h" #include "environmentaspectwidget.h" +#include "kit.h" #include "projectexplorertr.h" +#include "target.h" #include #include @@ -102,6 +105,27 @@ int EnvironmentAspect::addPreferredBaseEnvironment(const QString &displayName, return index; } +void EnvironmentAspect::setSupportForBuildEnvironment(Target *target) +{ + setIsLocal(true); + addSupportedBaseEnvironment(Tr::tr("Clean Environment"), {}); + + addSupportedBaseEnvironment(Tr::tr("System Environment"), [] { + return Environment::systemEnvironment(); + }); + addPreferredBaseEnvironment(Tr::tr("Build Environment"), [target] { + if (BuildConfiguration *bc = target->activeBuildConfiguration()) + return bc->environment(); + // Fallback for targets without buildconfigurations: + return target->kit()->buildEnvironment(); + }); + + connect(target, &Target::activeBuildConfigurationChanged, + this, &EnvironmentAspect::environmentChanged); + connect(target, &Target::buildEnvironmentChanged, + this, &EnvironmentAspect::environmentChanged); +} + void EnvironmentAspect::fromMap(const QVariantMap &map) { m_base = map.value(QLatin1String(BASE_KEY), -1).toInt(); diff --git a/src/plugins/projectexplorer/environmentaspect.h b/src/plugins/projectexplorer/environmentaspect.h index 9ba2f8a9835..97ce26f017d 100644 --- a/src/plugins/projectexplorer/environmentaspect.h +++ b/src/plugins/projectexplorer/environmentaspect.h @@ -39,6 +39,8 @@ public: int addPreferredBaseEnvironment(const QString &displayName, const std::function &getter); + void setSupportForBuildEnvironment(Target *target); + QString currentDisplayName() const; const QStringList displayNames() const; diff --git a/src/plugins/projectexplorer/localenvironmentaspect.cpp b/src/plugins/projectexplorer/localenvironmentaspect.cpp deleted file mode 100644 index 7510d636e5f..00000000000 --- a/src/plugins/projectexplorer/localenvironmentaspect.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "localenvironmentaspect.h" - -#include "buildconfiguration.h" -#include "kit.h" -#include "projectexplorertr.h" -#include "target.h" - -using namespace Utils; - -namespace ProjectExplorer { - -LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target, bool includeBuildEnvironment) -{ - setIsLocal(true); - addSupportedBaseEnvironment(Tr::tr("Clean Environment"), {}); - - addSupportedBaseEnvironment(Tr::tr("System Environment"), [] { - return Environment::systemEnvironment(); - }); - - if (includeBuildEnvironment) { - addPreferredBaseEnvironment(Tr::tr("Build Environment"), [target] { - Environment env; - if (BuildConfiguration *bc = target->activeBuildConfiguration()) { - env = bc->environment(); - } else { // Fallback for targets without buildconfigurations: - env = target->kit()->buildEnvironment(); - } - return env; - }); - - connect(target, - &Target::activeBuildConfigurationChanged, - this, - &EnvironmentAspect::environmentChanged); - connect(target, - &Target::buildEnvironmentChanged, - this, - &EnvironmentAspect::environmentChanged); - } -} - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/localenvironmentaspect.h b/src/plugins/projectexplorer/localenvironmentaspect.h deleted file mode 100644 index ffe2556947e..00000000000 --- a/src/plugins/projectexplorer/localenvironmentaspect.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "environmentaspect.h" - -namespace ProjectExplorer { - -class PROJECTEXPLORER_EXPORT LocalEnvironmentAspect : public EnvironmentAspect -{ - Q_OBJECT - -public: - explicit LocalEnvironmentAspect(Target *parent, bool includeBuildEnvironment = true); -}; - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 23870334857..e938165e97b 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -92,7 +92,6 @@ Project { "ldparser.cpp", "ldparser.h", "lldparser.cpp", "lldparser.h", "linuxiccparser.cpp", "linuxiccparser.h", - "localenvironmentaspect.cpp", "localenvironmentaspect.h", "makestep.cpp", "makestep.h", "miniprojecttargetselector.cpp", "miniprojecttargetselector.h", "msvcparser.cpp", "msvcparser.h", diff --git a/src/plugins/python/pythonplugin.cpp b/src/plugins/python/pythonplugin.cpp index 67857aec236..3cbbe817f9d 100644 --- a/src/plugins/python/pythonplugin.cpp +++ b/src/plugins/python/pythonplugin.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 537da98125f..e7c5b4dee14 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -190,7 +189,8 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id) scriptAspect->setLabelText(Tr::tr("Script:")); scriptAspect->setDisplayStyle(StringAspect::LabelDisplay); - addAspect(target); + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); auto argumentsAspect = addAspect(macroExpander()); From d6d7654c3ff095144546abadbde39891d07b8165 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 11:44:28 +0200 Subject: [PATCH 1251/1447] Autotest: Use new aspect constructor Change-Id: Ibac3957b51c0128e829fcf7cd750dbaea8e8694d Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- .../autotest/boost/boosttestsettings.cpp | 7 ---- .../autotest/boost/boosttestsettings.h | 14 ++++---- .../autotest/catch/catchtestsettings.cpp | 16 ---------- .../autotest/catch/catchtestsettings.h | 32 +++++++++---------- src/plugins/autotest/ctest/ctestsettings.cpp | 11 ------- src/plugins/autotest/ctest/ctestsettings.h | 22 ++++++------- src/plugins/autotest/gtest/gtestsettings.cpp | 9 ------ src/plugins/autotest/gtest/gtestsettings.h | 18 +++++------ src/plugins/autotest/qtest/qttestsettings.cpp | 8 ----- src/plugins/autotest/qtest/qttestsettings.h | 16 +++++----- 10 files changed, 51 insertions(+), 102 deletions(-) diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp index b55e728b7ba..ed0bad6bcaf 100644 --- a/src/plugins/autotest/boost/boosttestsettings.cpp +++ b/src/plugins/autotest/boost/boosttestsettings.cpp @@ -33,7 +33,6 @@ BoostTestSettings::BoostTestSettings(Id settingsId) }, st}; }); - registerAspect(&logLevel); logLevel.setSettingsKey("LogLevel"); logLevel.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); logLevel.addOption("All"); @@ -50,7 +49,6 @@ BoostTestSettings::BoostTestSettings(Id settingsId) logLevel.setDefaultValue(int(LogLevel::Warning)); logLevel.setLabelText(Tr::tr("Log format:")); - registerAspect(&reportLevel); reportLevel.setSettingsKey("ReportLevel"); reportLevel.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); reportLevel.addOption("Confirm"); @@ -60,7 +58,6 @@ BoostTestSettings::BoostTestSettings(Id settingsId) reportLevel.setDefaultValue(int(ReportLevel::Confirm)); reportLevel.setLabelText(Tr::tr("Report level:")); - registerAspect(&seed); seed.setSettingsKey("Seed"); seed.setEnabled(false); seed.setLabelText(Tr::tr("Seed:")); @@ -68,25 +65,21 @@ BoostTestSettings::BoostTestSettings(Id settingsId) "time, any other value is used as random seed generator.")); seed.setEnabler(&randomize); - registerAspect(&randomize); randomize.setSettingsKey("Randomize"); randomize.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); randomize.setLabelText(Tr::tr("Randomize")); randomize.setToolTip(Tr::tr("Randomize execution order.")); - registerAspect(&systemErrors); systemErrors.setSettingsKey("SystemErrors"); systemErrors.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); systemErrors.setLabelText(Tr::tr("Catch system errors")); systemErrors.setToolTip(Tr::tr("Catch or ignore system errors.")); - registerAspect(&fpExceptions); fpExceptions.setSettingsKey("FPExceptions"); fpExceptions.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); fpExceptions.setLabelText(Tr::tr("Floating point exceptions")); fpExceptions.setToolTip(Tr::tr("Enable floating point exception traps.")); - registerAspect(&memLeaks); memLeaks.setSettingsKey("MemoryLeaks"); memLeaks.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); memLeaks.setDefaultValue(true); diff --git a/src/plugins/autotest/boost/boosttestsettings.h b/src/plugins/autotest/boost/boosttestsettings.h index f2a906cd79e..e95f98218c2 100644 --- a/src/plugins/autotest/boost/boosttestsettings.h +++ b/src/plugins/autotest/boost/boosttestsettings.h @@ -38,13 +38,13 @@ public: static QString logLevelToOption(const LogLevel logLevel); static QString reportLevelToOption(const ReportLevel reportLevel); - Utils::SelectionAspect logLevel; - Utils::SelectionAspect reportLevel; - Utils::IntegerAspect seed; - Utils::BoolAspect randomize; - Utils::BoolAspect systemErrors; - Utils::BoolAspect fpExceptions; - Utils::BoolAspect memLeaks; + Utils::SelectionAspect logLevel{this}; + Utils::SelectionAspect reportLevel{this}; + Utils::IntegerAspect seed{this}; + Utils::BoolAspect randomize{this}; + Utils::BoolAspect systemErrors{this}; + Utils::BoolAspect fpExceptions{this}; + Utils::BoolAspect memLeaks{this}; }; } // Autotest::Internal diff --git a/src/plugins/autotest/catch/catchtestsettings.cpp b/src/plugins/autotest/catch/catchtestsettings.cpp index 4859efdeaae..5ee4a6acf97 100644 --- a/src/plugins/autotest/catch/catchtestsettings.cpp +++ b/src/plugins/autotest/catch/catchtestsettings.cpp @@ -35,89 +35,73 @@ CatchTestSettings::CatchTestSettings(Id settingsId) }, st }; }); - registerAspect(&abortAfter); abortAfter.setSettingsKey("AbortAfter"); abortAfter.setRange(1, 9999); abortAfter.setEnabler(&abortAfterChecked); - registerAspect(&benchmarkSamples); benchmarkSamples.setSettingsKey("BenchSamples"); benchmarkSamples.setRange(1, 999999); benchmarkSamples.setDefaultValue(100); benchmarkSamples.setEnabler(&samplesChecked); - registerAspect(&benchmarkResamples); benchmarkResamples.setSettingsKey("BenchResamples"); benchmarkResamples.setRange(1, 9999999); benchmarkResamples.setDefaultValue(100000); benchmarkResamples.setToolTip(Tr::tr("Number of resamples for bootstrapping.")); benchmarkResamples.setEnabler(&resamplesChecked); - registerAspect(&confidenceInterval); confidenceInterval.setSettingsKey("BenchConfInt"); confidenceInterval.setRange(0., 1.); confidenceInterval.setSingleStep(0.05); confidenceInterval.setDefaultValue(0.95); confidenceInterval.setEnabler(&confidenceIntervalChecked); - registerAspect(&benchmarkWarmupTime); benchmarkWarmupTime.setSettingsKey("BenchWarmup"); benchmarkWarmupTime.setSuffix(Tr::tr(" ms")); benchmarkWarmupTime.setRange(0, 10000); benchmarkWarmupTime.setEnabler(&warmupChecked); - registerAspect(&abortAfterChecked); abortAfterChecked.setSettingsKey("AbortChecked"); abortAfterChecked.setLabelText(Tr::tr("Abort after")); abortAfterChecked.setToolTip(Tr::tr("Aborts after the specified number of failures.")); - registerAspect(&samplesChecked); samplesChecked.setSettingsKey("SamplesChecked"); samplesChecked.setLabelText(Tr::tr("Benchmark samples")); samplesChecked.setToolTip(Tr::tr("Number of samples to collect while running benchmarks.")); - registerAspect(&resamplesChecked); resamplesChecked.setSettingsKey("ResamplesChecked"); resamplesChecked.setLabelText(Tr::tr("Benchmark resamples")); resamplesChecked.setToolTip(Tr::tr("Number of resamples used for statistical bootstrapping.")); - registerAspect(&confidenceIntervalChecked); confidenceIntervalChecked.setSettingsKey("ConfIntChecked"); confidenceIntervalChecked.setToolTip(Tr::tr("Confidence interval used for statistical bootstrapping.")); confidenceIntervalChecked.setLabelText(Tr::tr("Benchmark confidence interval")); - registerAspect(&warmupChecked); warmupChecked.setSettingsKey("WarmupChecked"); warmupChecked.setLabelText(Tr::tr("Benchmark warmup time")); warmupChecked.setToolTip(Tr::tr("Warmup time for each test.")); - registerAspect(&noAnalysis); noAnalysis.setSettingsKey("NoAnalysis"); noAnalysis.setLabelText(Tr::tr("Disable analysis")); noAnalysis.setToolTip(Tr::tr("Disables statistical analysis and bootstrapping.")); - registerAspect(&showSuccess); showSuccess.setSettingsKey("ShowSuccess"); showSuccess.setLabelText(Tr::tr("Show success")); showSuccess.setToolTip(Tr::tr("Show success for tests.")); - registerAspect(&breakOnFailure); breakOnFailure.setSettingsKey("BreakOnFailure"); breakOnFailure.setDefaultValue(true); breakOnFailure.setLabelText(Tr::tr("Break on failure while debugging")); breakOnFailure.setToolTip(Tr::tr("Turns failures into debugger breakpoints.")); - registerAspect(&noThrow); noThrow.setSettingsKey("NoThrow"); noThrow.setLabelText(Tr::tr("Skip throwing assertions")); noThrow.setToolTip(Tr::tr("Skips all assertions that test for thrown exceptions.")); - registerAspect(&visibleWhitespace); visibleWhitespace.setSettingsKey("VisibleWS"); visibleWhitespace.setLabelText(Tr::tr("Visualize whitespace")); visibleWhitespace.setToolTip(Tr::tr("Makes whitespace visible.")); - registerAspect(&warnOnEmpty); warnOnEmpty.setSettingsKey("WarnEmpty"); warnOnEmpty.setLabelText(Tr::tr("Warn on empty tests")); warnOnEmpty.setToolTip(Tr::tr("Warns if a test section does not check any assertion.")); diff --git a/src/plugins/autotest/catch/catchtestsettings.h b/src/plugins/autotest/catch/catchtestsettings.h index 07ac5580814..71c1caf5839 100644 --- a/src/plugins/autotest/catch/catchtestsettings.h +++ b/src/plugins/autotest/catch/catchtestsettings.h @@ -12,22 +12,22 @@ class CatchTestSettings : public Core::PagedSettings public: explicit CatchTestSettings(Utils::Id settingsId); - Utils::IntegerAspect abortAfter; - Utils::IntegerAspect benchmarkSamples; - Utils::IntegerAspect benchmarkResamples; - Utils::DoubleAspect confidenceInterval; - Utils::IntegerAspect benchmarkWarmupTime; - Utils::BoolAspect abortAfterChecked; - Utils::BoolAspect samplesChecked; - Utils::BoolAspect resamplesChecked; - Utils::BoolAspect confidenceIntervalChecked; - Utils::BoolAspect warmupChecked; - Utils::BoolAspect noAnalysis; - Utils::BoolAspect showSuccess; - Utils::BoolAspect breakOnFailure; - Utils::BoolAspect noThrow; - Utils::BoolAspect visibleWhitespace; - Utils::BoolAspect warnOnEmpty; + Utils::IntegerAspect abortAfter{this}; + Utils::IntegerAspect benchmarkSamples{this}; + Utils::IntegerAspect benchmarkResamples{this}; + Utils::DoubleAspect confidenceInterval{this}; + Utils::IntegerAspect benchmarkWarmupTime{this}; + Utils::BoolAspect abortAfterChecked{this}; + Utils::BoolAspect samplesChecked{this}; + Utils::BoolAspect resamplesChecked{this}; + Utils::BoolAspect confidenceIntervalChecked{this}; + Utils::BoolAspect warmupChecked{this}; + Utils::BoolAspect noAnalysis{this}; + Utils::BoolAspect showSuccess{this}; + Utils::BoolAspect breakOnFailure{this}; + Utils::BoolAspect noThrow{this}; + Utils::BoolAspect visibleWhitespace{this}; + Utils::BoolAspect warnOnEmpty{this}; }; } // Autotest::Internal diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index e200de98e88..e707c3edb09 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -42,12 +42,10 @@ CTestSettings::CTestSettings(Id settingsId) }, st }.attachTo(w); }); - registerAspect(&outputOnFail); outputOnFail.setSettingsKey("OutputOnFail"); outputOnFail.setLabelText(Tr::tr("Output on failure")); outputOnFail.setDefaultValue(true); - registerAspect(&outputMode); outputMode.setSettingsKey("OutputMode"); outputMode.setLabelText(Tr::tr("Output mode")); outputMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); @@ -55,7 +53,6 @@ CTestSettings::CTestSettings(Id settingsId) outputMode.addOption({Tr::tr("Verbose"), {}, 1}); outputMode.addOption({Tr::tr("Very Verbose"), {}, 2}); - registerAspect(&repetitionMode); repetitionMode.setSettingsKey("RepetitionMode"); repetitionMode.setLabelText(Tr::tr("Repetition mode")); repetitionMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); @@ -63,41 +60,33 @@ CTestSettings::CTestSettings(Id settingsId) repetitionMode.addOption({Tr::tr("Until Pass"), {}, 1}); repetitionMode.addOption({Tr::tr("After Timeout"), {}, 2}); - registerAspect(&repetitionCount); repetitionCount.setSettingsKey("RepetitionCount"); repetitionCount.setDefaultValue(1); repetitionCount.setLabelText(Tr::tr("Count")); repetitionCount.setToolTip(Tr::tr("Number of re-runs for the test.")); repetitionCount.setRange(1, 10000); - registerAspect(&repeat); repeat.setSettingsKey("Repeat"); - registerAspect(&scheduleRandom); scheduleRandom.setSettingsKey("ScheduleRandom"); scheduleRandom.setLabelText(Tr::tr("Schedule random")); - registerAspect(&stopOnFailure); stopOnFailure.setSettingsKey("StopOnFail"); stopOnFailure.setLabelText(Tr::tr("Stop on failure")); - registerAspect(¶llel); parallel.setSettingsKey("Parallel"); parallel.setToolTip(Tr::tr("Run tests in parallel mode using given number of jobs.")); - registerAspect(&jobs); jobs.setSettingsKey("Jobs"); jobs.setLabelText(Tr::tr("Jobs")); jobs.setDefaultValue(1); jobs.setRange(1, 128); - registerAspect(&testLoad); testLoad.setSettingsKey("TestLoad"); testLoad.setLabelText(Tr::tr("Test load")); testLoad.setToolTip(Tr::tr("Try not to start tests when they may cause CPU load to pass a " "threshold.")); - registerAspect(&threshold); threshold.setSettingsKey("Threshold"); threshold.setLabelText(Tr::tr("Threshold")); threshold.setDefaultValue(1); diff --git a/src/plugins/autotest/ctest/ctestsettings.h b/src/plugins/autotest/ctest/ctestsettings.h index a4e9b19605a..77de6b0aac8 100644 --- a/src/plugins/autotest/ctest/ctestsettings.h +++ b/src/plugins/autotest/ctest/ctestsettings.h @@ -14,18 +14,18 @@ public: QStringList activeSettingsAsOptions() const; - Utils::IntegerAspect repetitionCount; - Utils::SelectionAspect repetitionMode; - Utils::SelectionAspect outputMode; - Utils::BoolAspect outputOnFail; - Utils::BoolAspect stopOnFailure; - Utils::BoolAspect scheduleRandom; - Utils::BoolAspect repeat; + Utils::IntegerAspect repetitionCount{this}; + Utils::SelectionAspect repetitionMode{this}; + Utils::SelectionAspect outputMode{this}; + Utils::BoolAspect outputOnFail{this}; + Utils::BoolAspect stopOnFailure{this}; + Utils::BoolAspect scheduleRandom{this}; + Utils::BoolAspect repeat{this}; // FIXME.. this makes the outputreader fail to get all results correctly for visual display - Utils::BoolAspect parallel; - Utils::IntegerAspect jobs; - Utils::BoolAspect testLoad; - Utils::IntegerAspect threshold; + Utils::BoolAspect parallel{this}; + Utils::IntegerAspect jobs{this}; + Utils::BoolAspect testLoad{this}; + Utils::IntegerAspect threshold{this}; }; } // Autotest::Internal diff --git a/src/plugins/autotest/gtest/gtestsettings.cpp b/src/plugins/autotest/gtest/gtestsettings.cpp index f6fe44135ac..ca31c99f121 100644 --- a/src/plugins/autotest/gtest/gtestsettings.cpp +++ b/src/plugins/autotest/gtest/gtestsettings.cpp @@ -34,14 +34,12 @@ GTestSettings::GTestSettings(Id settingsId) }, st }; }); - registerAspect(&iterations); iterations.setSettingsKey("Iterations"); iterations.setDefaultValue(1); iterations.setEnabled(false); iterations.setLabelText(Tr::tr("Iterations:")); iterations.setEnabler(&repeat); - registerAspect(&seed); seed.setSettingsKey("Seed"); seed.setSpecialValueText({}); seed.setEnabled(false); @@ -49,34 +47,28 @@ GTestSettings::GTestSettings(Id settingsId) seed.setToolTip(Tr::tr("A seed of 0 generates a seed based on the current timestamp.")); seed.setEnabler(&shuffle); - registerAspect(&runDisabled); runDisabled.setSettingsKey("RunDisabled"); runDisabled.setLabelText(Tr::tr("Run disabled tests")); runDisabled.setToolTip(Tr::tr("Executes disabled tests when performing a test run.")); - registerAspect(&shuffle); shuffle.setSettingsKey("Shuffle"); shuffle.setLabelText(Tr::tr("Shuffle tests")); shuffle.setToolTip(Tr::tr("Shuffles tests automatically on every iteration by the given seed.")); - registerAspect(&repeat); repeat.setSettingsKey("Repeat"); repeat.setLabelText(Tr::tr("Repeat tests")); repeat.setToolTip(Tr::tr("Repeats a test run (you might be required to increase the timeout to " "avoid canceling the tests).")); - registerAspect(&throwOnFailure); throwOnFailure.setSettingsKey("ThrowOnFailure"); throwOnFailure.setLabelText(Tr::tr("Throw on failure")); throwOnFailure.setToolTip(Tr::tr("Turns assertion failures into C++ exceptions.")); - registerAspect(&breakOnFailure); breakOnFailure.setSettingsKey("BreakOnFailure"); breakOnFailure.setDefaultValue(true); breakOnFailure.setLabelText(Tr::tr("Break on failure while debugging")); breakOnFailure.setToolTip(Tr::tr("Turns failures into debugger breakpoints.")); - registerAspect(&groupMode); groupMode.setSettingsKey("GroupMode"); groupMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); groupMode.setFromSettingsTransformation([this](const QVariant &savedValue) -> QVariant { @@ -94,7 +86,6 @@ GTestSettings::GTestSettings(Id settingsId) groupMode.setLabelText(Tr::tr("Group mode:")); groupMode.setToolTip(Tr::tr("Select on what grouping the tests should be based.")); - registerAspect(>estFilter); gtestFilter.setSettingsKey("GTestFilter"); gtestFilter.setDisplayStyle(StringAspect::LineEditDisplay); gtestFilter.setDefaultValue(GTest::Constants::DEFAULT_FILTER); diff --git a/src/plugins/autotest/gtest/gtestsettings.h b/src/plugins/autotest/gtest/gtestsettings.h index fe928376075..ea0ab565e6c 100644 --- a/src/plugins/autotest/gtest/gtestsettings.h +++ b/src/plugins/autotest/gtest/gtestsettings.h @@ -12,15 +12,15 @@ class GTestSettings : public Core::PagedSettings public: explicit GTestSettings(Utils::Id settingsId); - Utils::IntegerAspect iterations; - Utils::IntegerAspect seed; - Utils::BoolAspect runDisabled; - Utils::BoolAspect shuffle; - Utils::BoolAspect repeat; - Utils::BoolAspect throwOnFailure; - Utils::BoolAspect breakOnFailure; - Utils::SelectionAspect groupMode; - Utils::StringAspect gtestFilter; + Utils::IntegerAspect iterations{this}; + Utils::IntegerAspect seed{this}; + Utils::BoolAspect runDisabled{this}; + Utils::BoolAspect shuffle{this}; + Utils::BoolAspect repeat{this}; + Utils::BoolAspect throwOnFailure{this}; + Utils::BoolAspect breakOnFailure{this}; + Utils::SelectionAspect groupMode{this}; + Utils::StringAspect gtestFilter{this}; }; } // Autotest::Internal diff --git a/src/plugins/autotest/qtest/qttestsettings.cpp b/src/plugins/autotest/qtest/qttestsettings.cpp index 4db11ebdb17..a8953a04492 100644 --- a/src/plugins/autotest/qtest/qttestsettings.cpp +++ b/src/plugins/autotest/qtest/qttestsettings.cpp @@ -37,7 +37,6 @@ QtTestSettings::QtTestSettings(Id settingsId) }, st }; }); - registerAspect(&metrics); metrics.setSettingsKey("Metrics"); metrics.setDefaultValue(Walltime); metrics.addOption(Tr::tr("Walltime"), Tr::tr("Uses walltime metrics for executing benchmarks (default).")); @@ -54,13 +53,11 @@ QtTestSettings::QtTestSettings(Id settingsId) HostOsInfo::isLinuxHost() // according to docs perf Linux only }); - registerAspect(&noCrashHandler); noCrashHandler.setSettingsKey("NoCrashhandlerOnDebug"); noCrashHandler.setDefaultValue(true); noCrashHandler.setLabelText(Tr::tr("Disable crash handler while debugging")); noCrashHandler.setToolTip(Tr::tr("Enables interrupting tests on assertions.")); - registerAspect(&useXMLOutput); useXMLOutput.setSettingsKey("UseXMLOutput"); useXMLOutput.setDefaultValue(true); useXMLOutput.setLabelText(Tr::tr("Use XML output")); @@ -68,29 +65,24 @@ QtTestSettings::QtTestSettings(Id settingsId) "while plain text is more human readable.\n\nWarning: " "Plain text misses some information, such as duration.")); - registerAspect(&verboseBench); verboseBench.setSettingsKey("VerboseBench"); verboseBench.setLabelText(Tr::tr("Verbose benchmarks")); - registerAspect(&logSignalsSlots); logSignalsSlots.setSettingsKey("LogSignalsSlots"); logSignalsSlots.setLabelText(Tr::tr("Log signals and slots")); logSignalsSlots.setToolTip(Tr::tr("Log every signal emission and resulting slot invocations.")); - registerAspect(&limitWarnings); limitWarnings.setSettingsKey("LimitWarnings"); limitWarnings.setLabelText(Tr::tr("Limit warnings")); limitWarnings.setToolTip(Tr::tr("Set the maximum number of warnings. 0 means that the number " "is not limited.")); - registerAspect(&maxWarnings); maxWarnings.setSettingsKey("MaxWarnings"); maxWarnings.setRange(0, 10000); maxWarnings.setDefaultValue(2000); maxWarnings.setSpecialValueText(Tr::tr("Unlimited")); maxWarnings.setEnabler(&limitWarnings); - registerAspect(&quickCheckForDerivedTests); quickCheckForDerivedTests.setSettingsKey("QuickCheckForDerivedTests"); quickCheckForDerivedTests.setDefaultValue(false); quickCheckForDerivedTests.setLabelText(Tr::tr("Check for derived Qt Quick tests")); diff --git a/src/plugins/autotest/qtest/qttestsettings.h b/src/plugins/autotest/qtest/qttestsettings.h index eafd464d7ba..31394ee6027 100644 --- a/src/plugins/autotest/qtest/qttestsettings.h +++ b/src/plugins/autotest/qtest/qttestsettings.h @@ -23,14 +23,14 @@ public: static QString metricsTypeToOption(const MetricsType type); - Utils::SelectionAspect metrics; - Utils::BoolAspect noCrashHandler; - Utils::BoolAspect useXMLOutput; - Utils::BoolAspect verboseBench; - Utils::BoolAspect logSignalsSlots; - Utils::BoolAspect limitWarnings; - Utils::IntegerAspect maxWarnings; - Utils::BoolAspect quickCheckForDerivedTests; + Utils::SelectionAspect metrics{this}; + Utils::BoolAspect noCrashHandler{this}; + Utils::BoolAspect useXMLOutput{this}; + Utils::BoolAspect verboseBench{this}; + Utils::BoolAspect logSignalsSlots{this}; + Utils::BoolAspect limitWarnings{this}; + Utils::IntegerAspect maxWarnings{this}; + Utils::BoolAspect quickCheckForDerivedTests{this}; }; } // Autotest::Internal From 8ca4f909e8c4dd29ee1465b39605d71455a77ce6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 24 May 2023 12:38:31 +0200 Subject: [PATCH 1252/1447] Examples: Move categorization to examplesparser For easier testing. Change-Id: I11f9de3f4fbcc2c85c196f1b59b2147e73ea8209 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/qtsupport/exampleslistmodel.cpp | 52 -------------------- src/plugins/qtsupport/examplesparser.cpp | 54 +++++++++++++++++++++ src/plugins/qtsupport/examplesparser.h | 3 ++ src/plugins/qtsupport/qtsupport_global.h | 12 +++++ 4 files changed, 69 insertions(+), 52 deletions(-) diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index d3cf3535dd9..f18fefc34f2 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -4,7 +4,6 @@ #include "exampleslistmodel.h" #include "examplesparser.h" -#include "qtsupporttr.h" #include #include @@ -326,57 +325,6 @@ static bool isValidExampleOrDemo(ExampleItem *item) return ok || debugExamples(); } -static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) -{ - if (first->isHighlighted && !second->isHighlighted) - return true; - if (!first->isHighlighted && second->isHighlighted) - return false; - return first->name.compare(second->name, Qt::CaseInsensitive) < 0; -} - -static QList>> getCategories( - const QList &items, bool sortIntoCategories) -{ - static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples"); - const bool useCategories = sortIntoCategories - || qtcEnvironmentVariableIsSet("QTC_USE_EXAMPLE_CATEGORIES"); - QList other; - QMap> categoryMap; - if (useCategories) { - for (ExampleItem *item : items) { - const QStringList itemCategories = item->metaData.value("category"); - for (const QString &category : itemCategories) - categoryMap[category].append(item); - if (itemCategories.isEmpty()) - other.append(item); - } - } - QList>> categories; - if (categoryMap.isEmpty()) { - // The example set doesn't define categories. Consider the "highlighted" ones as "featured" - QList featured; - QList allOther; - std::tie(featured, allOther) = Utils::partition(items, [](ExampleItem *i) { - return i->isHighlighted; - }); - if (!featured.isEmpty()) - categories.append({Tr::tr("Featured", "Category for highlighted examples"), featured}); - if (!allOther.isEmpty()) - categories.append({otherDisplayName, allOther}); - } else { - const auto end = categoryMap.constKeyValueEnd(); - for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) - categories.append(*it); - if (!other.isEmpty()) - categories.append({otherDisplayName, other}); - } - const auto end = categories.end(); - for (auto it = categories.begin(); it != end; ++it) - sort(it->second, sortByHighlightedAndName); - return categories; -} - void ExamplesViewController::updateExamples() { QString examplesInstallPath; diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index 5fd3161777c..bd6ff08918f 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -3,7 +3,10 @@ #include "examplesparser.h" +#include "qtsupporttr.h" + #include +#include #include #include @@ -298,4 +301,55 @@ expected_str> parseExamples(const QByteArray &manifestData, return items; } +static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) +{ + if (first->isHighlighted && !second->isHighlighted) + return true; + if (!first->isHighlighted && second->isHighlighted) + return false; + return first->name.compare(second->name, Qt::CaseInsensitive) < 0; +} + +QList>> getCategories(const QList &items, + bool sortIntoCategories) +{ + static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples"); + const bool useCategories = sortIntoCategories + || qtcEnvironmentVariableIsSet("QTC_USE_EXAMPLE_CATEGORIES"); + QList other; + QMap> categoryMap; + if (useCategories) { + for (ExampleItem *item : items) { + const QStringList itemCategories = item->metaData.value("category"); + for (const QString &category : itemCategories) + categoryMap[category].append(item); + if (itemCategories.isEmpty()) + other.append(item); + } + } + QList>> categories; + if (categoryMap.isEmpty()) { + // The example set doesn't define categories. Consider the "highlighted" ones as "featured" + QList featured; + QList allOther; + std::tie(featured, allOther) = Utils::partition(items, [](ExampleItem *i) { + return i->isHighlighted; + }); + if (!featured.isEmpty()) + categories.append({Tr::tr("Featured", "Category for highlighted examples"), featured}); + if (!allOther.isEmpty()) + categories.append({otherDisplayName, allOther}); + } else { + const auto end = categoryMap.constKeyValueEnd(); + for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) + categories.append(*it); + if (!other.isEmpty()) + categories.append({otherDisplayName, other}); + } + const auto end = categories.end(); + for (auto it = categories.begin(); it != end; ++it) + sort(it->second, sortByHighlightedAndName); + return categories; +} + } // namespace QtSupport::Internal diff --git a/src/plugins/qtsupport/examplesparser.h b/src/plugins/qtsupport/examplesparser.h index 2d1afa54838..a7d5501bc51 100644 --- a/src/plugins/qtsupport/examplesparser.h +++ b/src/plugins/qtsupport/examplesparser.h @@ -44,6 +44,9 @@ QTSUPPORT_EXPORT Utils::expected_str> parseExamples( const Utils::FilePath &demosInstallPath, bool examples); +QTSUPPORT_TEST_EXPORT QList>> getCategories( + const QList &items, bool sortIntoCategories); + } // namespace QtSupport::Internal Q_DECLARE_METATYPE(QtSupport::Internal::ExampleItem *) diff --git a/src/plugins/qtsupport/qtsupport_global.h b/src/plugins/qtsupport/qtsupport_global.h index aca20f5aa27..60c9bf0c128 100644 --- a/src/plugins/qtsupport/qtsupport_global.h +++ b/src/plugins/qtsupport/qtsupport_global.h @@ -12,3 +12,15 @@ #else # define QTSUPPORT_EXPORT Q_DECL_IMPORT #endif + +#if defined(WITH_TESTS) +# if defined(QTSUPPORT_LIBRARY) +# define QTSUPPORT_TEST_EXPORT Q_DECL_EXPORT +# elif defined(QTSUPPORT_STATIC_LIBRARY) +# define QTSUPPORT_TEST_EXPORT +# else +# define QTSUPPORT_TEST_EXPORT Q_DECL_IMPORT +# endif +#else +# define QTSUPPORT_TEST_EXPORT +#endif From 2ca7aff0736564ee2a49616f26002be919ecdfb4 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 09:48:03 +0200 Subject: [PATCH 1253/1447] Docker: Remove DockerPlugin::dockerApi() Access is nowadays via DockerApi::instance() Change-Id: Idc1530358771c3a008182661c263c30b68fe84be Reviewed-by: Christian Kandeler --- src/plugins/docker/dockerplugin.cpp | 10 ---------- src/plugins/docker/dockerplugin.h | 6 ------ 2 files changed, 16 deletions(-) diff --git a/src/plugins/docker/dockerplugin.cpp b/src/plugins/docker/dockerplugin.cpp index cd2dd623bc8..7e47abd7b1f 100644 --- a/src/plugins/docker/dockerplugin.cpp +++ b/src/plugins/docker/dockerplugin.cpp @@ -31,24 +31,14 @@ public: DockerApi m_dockerApi{&m_settings}; }; -static DockerPlugin *s_instance = nullptr; - DockerPlugin::DockerPlugin() { - s_instance = this; FSEngine::registerDeviceScheme(Constants::DOCKER_DEVICE_SCHEME); } -DockerApi *DockerPlugin::dockerApi() -{ - QTC_ASSERT(s_instance, return nullptr); - return &s_instance->d->m_dockerApi; -} - DockerPlugin::~DockerPlugin() { FSEngine::unregisterDeviceScheme(Constants::DOCKER_DEVICE_SCHEME); - s_instance = nullptr; delete d; } diff --git a/src/plugins/docker/dockerplugin.h b/src/plugins/docker/dockerplugin.h index c4ee04ac5af..267244709d8 100644 --- a/src/plugins/docker/dockerplugin.h +++ b/src/plugins/docker/dockerplugin.h @@ -3,12 +3,8 @@ #pragma once -#include "dockerapi.h" - #include -#include - namespace Docker::Internal { class DockerPlugin final : public ExtensionSystem::IPlugin @@ -19,8 +15,6 @@ class DockerPlugin final : public ExtensionSystem::IPlugin public: DockerPlugin(); - static DockerApi *dockerApi(); - private: ~DockerPlugin() final; From 2d32fe4b573d0216eb32b46510df9d02b2726b95 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 09:37:23 +0200 Subject: [PATCH 1254/1447] Utils: Remove Environment::searchInDirectories Was functionally replaced by FilePath::searchInDirectories. Change-Id: I8808cbdb114fb9b6b4e1f94e13aa9e67b9c56d6a Reviewed-by: Marcus Tillmanns --- src/libs/utils/environment.cpp | 19 ------------------- src/libs/utils/environment.h | 3 --- 2 files changed, 22 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index a65a48aa679..0a95587aef4 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -300,25 +300,6 @@ static void searchInDirectoriesHelper(const SearchResultCallback &resultCallback return; } -FilePath Environment::searchInDirectories(const QString &executable, - const FilePaths &dirs, - const FilePathPredicate &func) const -{ - FilePath result; - searchInDirectoriesHelper( - [&result](const FilePath &path) { - result = path; - return IterationPolicy::Stop; - }, - *this, - executable, - dirs, - func, - false); - - return result; -} - FilePath Environment::searchInPath(const QString &executable, const FilePaths &additionalDirs, const FilePathPredicate &func) const diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 7afa48ba0bb..843232878ba 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -61,9 +61,6 @@ public: FilePath searchInPath(const QString &executable, const FilePaths &additionalDirs = FilePaths(), const FilePathPredicate &func = {}) const; - FilePath searchInDirectories(const QString &executable, - const FilePaths &dirs, - const FilePathPredicate &func = {}) const; FilePaths findAllInPath(const QString &executable, const FilePaths &additionalDirs = {}, const FilePathPredicate &func = {}) const; From 0d95c68b2146f704a77b9ba4a8c0b07df584d03d Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 May 2023 10:58:49 +0200 Subject: [PATCH 1255/1447] Doc: Add missing \a commands to get rid of qdoc warnings Change-Id: Ida0f0cabae0cc151967098312b358803a48dd92c Reviewed-by: Eike Ziller --- src/libs/utils/fileinprojectfinder.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/fileinprojectfinder.cpp b/src/libs/utils/fileinprojectfinder.cpp index 6ec36212eb0..957f694179b 100644 --- a/src/libs/utils/fileinprojectfinder.cpp +++ b/src/libs/utils/fileinprojectfinder.cpp @@ -110,13 +110,16 @@ void FileInProjectFinder::addMappedPath(const FilePath &localFilePath, const QSt } /*! - Returns the best match for the given file URL in the project directory. + Returns the best match for the file URL \a fileUrl in the project directory. The function first checks whether the file inside the project directory exists. If not, the leading directory in the path is stripped, and the - now shorter - path is checked for existence, and so on. Second, it tries to locate the file in the sysroot - folder specified. Third, we walk the list of project files, and search for a file name match - there. If all fails, it returns the original path from the file URL. + folder specified. Third, it walks the list of project files and searches for a file name match + there. + + If all fails, the function returns the original path from the file URL. To + indicate that no match was found in the project, \a success is set to false. */ FilePaths FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const { From 06365fa39fd6621de2452d99ad057bb27cf190a4 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 25 May 2023 10:56:07 +0200 Subject: [PATCH 1256/1447] Terminal: External terminal if blocked by modal Change-Id: I89ba438c7a9f4d593e849b9b7ca2daf202cca625 Reviewed-by: hjk --- src/libs/utils/CMakeLists.txt | 1 + .../utils/externalterminalprocessimpl.cpp | 92 +++++++++++++++++ src/libs/utils/externalterminalprocessimpl.h | 29 ++++++ src/libs/utils/terminalhooks.cpp | 98 +------------------ src/libs/utils/utils.qbs | 2 + src/plugins/terminal/terminalprocessimpl.cpp | 12 ++- 6 files changed, 136 insertions(+), 98 deletions(-) create mode 100644 src/libs/utils/externalterminalprocessimpl.cpp create mode 100644 src/libs/utils/externalterminalprocessimpl.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 8322ad8a452..aa6a3e199e6 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -45,6 +45,7 @@ add_qtc_library(Utils execmenu.cpp execmenu.h executeondestruction.h expected.h + externalterminalprocessimpl.cpp externalterminalprocessimpl.h fadingindicator.cpp fadingindicator.h faketooltip.cpp faketooltip.h fancylineedit.cpp fancylineedit.h diff --git a/src/libs/utils/externalterminalprocessimpl.cpp b/src/libs/utils/externalterminalprocessimpl.cpp new file mode 100644 index 00000000000..366554884d4 --- /dev/null +++ b/src/libs/utils/externalterminalprocessimpl.cpp @@ -0,0 +1,92 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "externalterminalprocessimpl.h" +#include "process.h" +#include "terminalcommand.h" +#include "utilstr.h" + +#include + +namespace Utils { + +ExternalTerminalProcessImpl::ExternalTerminalProcessImpl() +{ + setStubCreator(new ProcessStubCreator(this)); +} + +ProcessStubCreator::ProcessStubCreator(TerminalInterface *interface) + : m_interface(interface) +{} + +expected_str ProcessStubCreator::startStubProcess(const ProcessSetupData &setupData) +{ + const TerminalCommand terminal = TerminalCommand::terminalEmulator(); + + if (HostOsInfo::isMacHost() && terminal.command == "Terminal.app") { + QTemporaryFile f; + f.setAutoRemove(false); + f.open(); + f.setPermissions(QFile::ExeUser | QFile::ReadUser | QFile::WriteUser); + f.write("#!/bin/sh\n"); + f.write(QString("cd %1\n").arg(setupData.m_workingDirectory.nativePath()).toUtf8()); + f.write("clear\n"); + f.write(QString("exec '%1' %2\n") + .arg(setupData.m_commandLine.executable().nativePath()) + .arg(setupData.m_commandLine.arguments()) + .toUtf8()); + f.close(); + + const QString path = f.fileName(); + const QString exe + = QString("tell app \"Terminal\" to do script \"'%1'; rm -f '%1'; exit\"").arg(path); + + Process process; + + process.setCommand({"osascript", {"-e", "tell app \"Terminal\" to activate", "-e", exe}}); + process.runBlocking(); + + if (process.exitCode() != 0) { + return make_unexpected( + Tr::tr("Failed to start terminal process: \"%1\"").arg(process.errorString())); + } + + return 0; + } + + bool detached = setupData.m_terminalMode == TerminalMode::Detached; + + Process *process = new Process(detached ? nullptr : this); + if (detached) + QObject::connect(process, &Process::done, process, &Process::deleteLater); + + QObject::connect(process, &Process::done, m_interface, &TerminalInterface::onStubExited); + + process->setWorkingDirectory(setupData.m_workingDirectory); + + if constexpr (HostOsInfo::isWindowsHost()) { + process->setCommand(setupData.m_commandLine); + process->setCreateConsoleOnWindows(true); + process->setProcessMode(ProcessMode::Writer); + } else { + QString extraArgsFromOptions = detached ? terminal.openArgs : terminal.executeArgs; + CommandLine cmdLine = {terminal.command, {}}; + if (!extraArgsFromOptions.isEmpty()) + cmdLine.addArgs(extraArgsFromOptions, CommandLine::Raw); + cmdLine.addCommandLineAsArgs(setupData.m_commandLine, CommandLine::Raw); + process->setCommand(cmdLine); + } + + process->start(); + process->waitForStarted(); + if (process->error() != QProcess::UnknownError) { + return make_unexpected( + Tr::tr("Failed to start terminal process: \"%1\"").arg(process->errorString())); + } + + qint64 pid = process->processId(); + + return pid; +} + +} // namespace Utils diff --git a/src/libs/utils/externalterminalprocessimpl.h b/src/libs/utils/externalterminalprocessimpl.h new file mode 100644 index 00000000000..cbb3370071b --- /dev/null +++ b/src/libs/utils/externalterminalprocessimpl.h @@ -0,0 +1,29 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "terminalinterface.h" + +namespace Utils { + +class ProcessStubCreator; + +class QTCREATOR_UTILS_EXPORT ExternalTerminalProcessImpl final : public TerminalInterface +{ +public: + ExternalTerminalProcessImpl(); +}; + +class QTCREATOR_UTILS_EXPORT ProcessStubCreator : public StubCreator +{ +public: + ProcessStubCreator(TerminalInterface *interface); + ~ProcessStubCreator() override = default; + + expected_str startStubProcess(const ProcessSetupData &setupData) override; + + TerminalInterface *m_interface; +}; + +} // namespace Utils diff --git a/src/libs/utils/terminalhooks.cpp b/src/libs/utils/terminalhooks.cpp index 07ebbd98d2f..3bda25b109c 100644 --- a/src/libs/utils/terminalhooks.cpp +++ b/src/libs/utils/terminalhooks.cpp @@ -3,14 +3,11 @@ #include "terminalhooks.h" +#include "externalterminalprocessimpl.h" #include "filepath.h" #include "process.h" -#include "terminalcommand.h" -#include "terminalinterface.h" -#include "utilstr.h" #include -#include namespace Utils::Terminal { @@ -31,99 +28,6 @@ FilePath defaultShellForDevice(const FilePath &deviceRoot) return deviceRoot.withNewMappedPath(shell); } -class ExternalTerminalProcessImpl final : public TerminalInterface -{ - class ProcessStubCreator : public StubCreator - { - public: - ProcessStubCreator(ExternalTerminalProcessImpl *interface) - : m_interface(interface) - {} - - ~ProcessStubCreator() override = default; - - expected_str startStubProcess(const ProcessSetupData &setupData) override - { - const TerminalCommand terminal = TerminalCommand::terminalEmulator(); - - if (HostOsInfo::isMacHost() && terminal.command == "Terminal.app") { - QTemporaryFile f; - f.setAutoRemove(false); - f.open(); - f.setPermissions(QFile::ExeUser | QFile::ReadUser | QFile::WriteUser); - f.write("#!/bin/sh\n"); - f.write(QString("cd %1\n").arg(setupData.m_workingDirectory.nativePath()).toUtf8()); - f.write("clear\n"); - f.write(QString("exec '%1' %2\n") - .arg(setupData.m_commandLine.executable().nativePath()) - .arg(setupData.m_commandLine.arguments()) - .toUtf8()); - f.close(); - - const QString path = f.fileName(); - const QString exe - = QString("tell app \"Terminal\" to do script \"'%1'; rm -f '%1'; exit\"") - .arg(path); - - Process process; - - process.setCommand( - {"osascript", {"-e", "tell app \"Terminal\" to activate", "-e", exe}}); - process.runBlocking(); - - if (process.exitCode() != 0) { - return make_unexpected(Tr::tr("Failed to start terminal process: \"%1\"") - .arg(process.errorString())); - } - - return 0; - } - - bool detached = setupData.m_terminalMode == TerminalMode::Detached; - - Process *process = new Process(detached ? nullptr : this); - if (detached) - QObject::connect(process, &Process::done, process, &Process::deleteLater); - - QObject::connect(process, - &Process::done, - m_interface, - &ExternalTerminalProcessImpl::onStubExited); - - process->setWorkingDirectory(setupData.m_workingDirectory); - - if constexpr (HostOsInfo::isWindowsHost()) { - process->setCommand(setupData.m_commandLine); - process->setCreateConsoleOnWindows(true); - process->setProcessMode(ProcessMode::Writer); - } else { - QString extraArgsFromOptions = detached ? terminal.openArgs : terminal.executeArgs; - CommandLine cmdLine = {terminal.command, {}}; - if (!extraArgsFromOptions.isEmpty()) - cmdLine.addArgs(extraArgsFromOptions, CommandLine::Raw); - cmdLine.addCommandLineAsArgs(setupData.m_commandLine, CommandLine::Raw); - process->setCommand(cmdLine); - } - - process->start(); - process->waitForStarted(); - if (process->error() != QProcess::UnknownError) { - return make_unexpected( - Tr::tr("Failed to start terminal process: \"%1\"").arg(process->errorString())); - } - - qint64 pid = process->processId(); - - return pid; - } - - ExternalTerminalProcessImpl *m_interface; - }; - -public: - ExternalTerminalProcessImpl() { setStubCreator(new ProcessStubCreator(this)); } -}; - class HooksPrivate { public: diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 298b23c1e9f..df23fc3ba24 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -110,6 +110,8 @@ Project { "execmenu.cpp", "execmenu.h", "executeondestruction.h", + "externalterminalprocessimpl.cpp", + "externalterminalprocessimpl.h", "fadingindicator.cpp", "fadingindicator.h", "faketooltip.cpp", diff --git a/src/plugins/terminal/terminalprocessimpl.cpp b/src/plugins/terminal/terminalprocessimpl.cpp index d2b76e51a68..9a7f7e7dcd6 100644 --- a/src/plugins/terminal/terminalprocessimpl.cpp +++ b/src/plugins/terminal/terminalprocessimpl.cpp @@ -4,7 +4,9 @@ #include "terminalprocessimpl.h" #include "terminalwidget.h" -#include +#include + +#include #include #include #include @@ -24,10 +26,16 @@ public: ProcessStubCreator(TerminalProcessImpl *interface, TerminalPane *terminalPane) : m_terminalPane(terminalPane) , m_process(interface) + , m_interface(interface) {} expected_str startStubProcess(const ProcessSetupData &setup) override { + if (QApplication::activeModalWidget()) { + m_fallbackStubCreator = std::make_unique(m_interface); + return m_fallbackStubCreator->startStubProcess(setup); + } + const Id id = Id::fromString(setup.m_commandLine.executable().toUserOutput()); TerminalWidget *terminal = m_terminalPane->stoppedTerminalWithId(id); @@ -59,6 +67,8 @@ public: TerminalPane *m_terminalPane; TerminalProcessImpl *m_process; + TerminalInterface *m_interface; + std::unique_ptr m_fallbackStubCreator; }; TerminalProcessImpl::TerminalProcessImpl(TerminalPane *terminalPane) From d685fbccf0e700b15ee402fade80fc06b5d4f07d Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 22 May 2023 14:41:27 +0200 Subject: [PATCH 1257/1447] Debugger: Use a FilePathAspect for extra dumpers Change-Id: Ideb779cc5ef0d679667b635efe8c1a2859c6e608 Reviewed-by: David Schulz --- src/plugins/debugger/cdb/cdbengine.cpp | 6 +++--- src/plugins/debugger/debuggeractions.cpp | 1 - src/plugins/debugger/debuggeractions.h | 2 +- src/plugins/debugger/gdb/gdbengine.cpp | 6 +++--- src/plugins/debugger/lldb/lldbengine.cpp | 6 +++--- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index e6d54ad2e5c..7c70a3c31b0 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2824,10 +2824,10 @@ void CdbEngine::setupScripting(const DebuggerResponse &response) runCommand({"theDumper = Dumper()", ScriptCommand}); } - const QString path = debuggerSettings()->extraDumperFile.value(); - if (!path.isEmpty() && QFileInfo(path).isReadable()) { + const FilePath path = debuggerSettings()->extraDumperFile(); + if (!path.isEmpty() && path.isReadableFile()) { DebuggerCommand cmd("theDumper.addDumperModule", ScriptCommand); - cmd.arg("path", path); + cmd.arg("path", path.path()); runCommand(cmd); } const QString commands = debuggerSettings()->extraDumperCommands.value(); diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 721d499dc58..038696f4bac 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -364,7 +364,6 @@ DebuggerSettings::DebuggerSettings() + "

"); extraDumperFile.setSettingsKey(debugModeGroup, "ExtraDumperFile"); - extraDumperFile.setDisplayStyle(StringAspect::PathChooserDisplay); extraDumperFile.setDisplayName(Tr::tr("Extra Debugging Helpers")); // Label text is intentional empty in the GUI. extraDumperFile.setToolTip(Tr::tr("Path to a Python file containing additional data dumpers.")); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 40fabfef1eb..a6fb497815f 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -106,7 +106,7 @@ public: Utils::BoolAspect useDebuggingHelpers; Utils::BoolAspect useCodeModel; Utils::BoolAspect showThreadNames; - Utils::StringAspect extraDumperFile; // For loading a file. Recommended. + Utils::FilePathAspect extraDumperFile; // For loading a file. Recommended. Utils::StringAspect extraDumperCommands; // To modify an existing setup. Utils::BoolAspect showStdNamespace; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index aa84c6d2d78..f69c9f72d7b 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4026,10 +4026,10 @@ void GdbEngine::handleGdbStarted() runCommand({"python from gdbbridge import *"}); } - const QString path = debuggerSettings()->extraDumperFile.value(); - if (!path.isEmpty() && QFileInfo(path).isReadable()) { + const FilePath path = debuggerSettings()->extraDumperFile(); + if (!path.isEmpty() && path.isReadableFile()) { DebuggerCommand cmd("addDumperModule"); - cmd.arg("path", path); + cmd.arg("path", path.path()); runCommand(cmd); } diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index ef4d7a4354d..09b5d6eaec9 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -228,10 +228,10 @@ void LldbEngine::handleLldbStarted() if (!commands.isEmpty()) executeCommand(commands); - const QString path = debuggerSettings()->extraDumperFile.value(); - if (!path.isEmpty() && QFileInfo(path).isReadable()) { + const FilePath path = debuggerSettings()->extraDumperFile(); + if (!path.isEmpty() && path.isReadableFile()) { DebuggerCommand cmd("addDumperModule"); - cmd.arg("path", path); + cmd.arg("path", path.path()); runCommand(cmd); } From dd1a69e05f12656f9260fb8c7941405043804326 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 24 May 2023 13:47:27 +0200 Subject: [PATCH 1258/1447] Fix crash when examples are in multiple categories When items are added into multiple categories, we got into a double delete when cleaning up, e.g. when changing the shown examples to a different Qt version. Sort copies into categories and delete the originals as a quickfix. Cleaner would be if we didn't allocate them on the heap in the first place. Fixes: QTCREATORBUG-29197 Change-Id: I6490111aba87335b0f7189c4957ed1da8681806f Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger --- src/plugins/qtsupport/examplesparser.cpp | 14 +++++++--- tests/auto/examples/tst_examples.cpp | 33 ++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index bd6ff08918f..e5853a0f7cb 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -319,16 +319,22 @@ QList>> getCategories(const QList other; QMap> categoryMap; if (useCategories) { + // Append copies of the items and delete the original ones, + // because items might be added to multiple categories and that needs individual items for (ExampleItem *item : items) { - const QStringList itemCategories = item->metaData.value("category"); + const QStringList itemCategories = Utils::filteredUnique( + item->metaData.value("category")); for (const QString &category : itemCategories) - categoryMap[category].append(item); + categoryMap[category].append(new ExampleItem(*item)); if (itemCategories.isEmpty()) - other.append(item); + other.append(new ExampleItem(*item)); } } QList>> categories; if (categoryMap.isEmpty()) { + // If we tried sorting into categories, but none were defined, we copied the items + // into "other", which we don't use here. Get rid of them again. + qDeleteAll(other); // The example set doesn't define categories. Consider the "highlighted" ones as "featured" QList featured; QList allOther; @@ -340,6 +346,8 @@ QList>> getCategories(const QList("videoLength"); QTest::addColumn("platforms"); QTest::addColumn("metaData"); + QTest::addColumn("categories"); QTest::addRow("example") << QByteArray(R"raw( @@ -102,6 +103,8 @@ void tst_Examples::parsing_data() widgets/widgets/analogclock/analogclock.cpp Graphics + Graphics + Foobar widgets @@ -120,13 +123,29 @@ void tst_Examples::parsing_data() "manifest/widgets/widgets/analogclock/analogclock.cpp")} << FilePath::fromUserInput("manifest/widgets/widgets/analogclock/analogclock.cpp") << FilePaths() << Example << true << false << false << "" - << "" << QStringList() << MetaData({{"category", {"Graphics"}}, {"tags", {"widgets"}}}); + << "" << QStringList() + << MetaData({{"category", {"Graphics", "Graphics", "Foobar"}}, {"tags", {"widgets"}}}) + << QStringList{"Foobar", "Graphics"}; + + QTest::addRow("no category, highlighted") + << QByteArray(R"raw( + + + + + )raw") << /*isExamples=*/true + << "No Category, highlighted" << QString() << QString() << QStringList() + << FilePath("manifest") << QString() << FilePaths() << FilePath() << FilePaths() << Example + << /*hasSourceCode=*/false << false << /*isHighlighted=*/true << "" + << "" << QStringList() << MetaData() << QStringList{"Featured"}; } void tst_Examples::parsing() { QFETCH(QByteArray, data); QFETCH(bool, isExamples); + QFETCH(QStringList, categories); const ExampleItem expected = fetchItem(); const expected_str> result = parseExamples(data, @@ -154,7 +173,17 @@ void tst_Examples::parsing() QCOMPARE(item.videoLength, expected.videoLength); QCOMPARE(item.platforms, expected.platforms); QCOMPARE(item.metaData, expected.metaData); - qDeleteAll(*result); + + const QList>> resultCategories = getCategories(*result, + true); + QCOMPARE(resultCategories.size(), categories.size()); + for (int i = 0; i < resultCategories.size(); ++i) { + QCOMPARE(resultCategories.at(i).first, categories.at(i)); + QCOMPARE(resultCategories.at(i).second.size(), 1); + } + + for (const auto &category : resultCategories) + qDeleteAll(category.second); } QTEST_APPLESS_MAIN(tst_Examples) From 070bb228121d022ffe029f6709c83a2aca9144fd Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 16:43:07 +0200 Subject: [PATCH 1259/1447] ProjectExplorer: Use FilePathAspect in CopyStep Also, convert them to auto-registering members. Change-Id: Ic35808f0d4c93f655419c4f86073620f43bb3d5b Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/copystep.cpp | 30 +++++++++++------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/plugins/projectexplorer/copystep.cpp b/src/plugins/projectexplorer/copystep.cpp index d152671c70e..14f01ae425c 100644 --- a/src/plugins/projectexplorer/copystep.cpp +++ b/src/plugins/projectexplorer/copystep.cpp @@ -21,15 +21,13 @@ public: CopyStepBase(BuildStepList *bsl, Id id) : BuildStep(bsl, id) { - m_sourceAspect = addAspect(); - m_sourceAspect->setSettingsKey(SOURCE_KEY); - m_sourceAspect->setDisplayStyle(StringAspect::PathChooserDisplay); - m_sourceAspect->setLabelText(Tr::tr("Source:")); + setOwnsSubAspects(false); - m_targetAspect = addAspect(); - m_targetAspect->setSettingsKey(TARGET_KEY); - m_targetAspect->setDisplayStyle(StringAspect::PathChooserDisplay); - m_targetAspect->setLabelText(Tr::tr("Target:")); + m_sourceAspect.setSettingsKey(SOURCE_KEY); + m_sourceAspect.setLabelText(Tr::tr("Source:")); + + m_targetAspect.setSettingsKey(TARGET_KEY); + m_targetAspect.setLabelText(Tr::tr("Target:")); addMacroExpander(); } @@ -37,8 +35,8 @@ public: protected: bool init() final { - m_source = m_sourceAspect->filePath(); - m_target = m_targetAspect->filePath(); + m_source = m_sourceAspect(); + m_target = m_targetAspect(); return m_source.exists(); } @@ -58,8 +56,8 @@ protected: }); } - StringAspect *m_sourceAspect; - StringAspect *m_targetAspect; + FilePathAspect m_sourceAspect{this}; + FilePathAspect m_targetAspect{this}; private: FilePath m_source; @@ -75,8 +73,8 @@ public: // Expected kind could be stricter in theory, but since this here is // a last stand fallback, better not impose extra "nice to have" // work on the system. - m_sourceAspect->setExpectedKind(PathChooser::Any); // "File" - m_targetAspect->setExpectedKind(PathChooser::Any); // "SaveFile" + m_sourceAspect.setExpectedKind(PathChooser::Any); // "File" + m_targetAspect.setExpectedKind(PathChooser::Any); // "SaveFile" setSummaryUpdater([] { return QString("" + Tr::tr("Copy file") + ""); @@ -90,8 +88,8 @@ public: CopyDirectoryStep(BuildStepList *bsl, Id id) : CopyStepBase(bsl, id) { - m_sourceAspect->setExpectedKind(PathChooser::Directory); - m_targetAspect->setExpectedKind(PathChooser::Directory); + m_sourceAspect.setExpectedKind(PathChooser::Directory); + m_targetAspect.setExpectedKind(PathChooser::Directory); setSummaryUpdater([] { return QString("" + Tr::tr("Copy directory recursively") + ""); From 77b8c634368059fd8db3a95e5c2492c8a344605d Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 18:30:44 +0200 Subject: [PATCH 1260/1447] Valgrind: Adapt to recent Aspect changes Change-Id: I88647e5b2934bedf04828984567dee0a34bb7605 Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/valgrind/callgrindengine.cpp | 10 ++--- src/plugins/valgrind/memchecktool.cpp | 22 +++++----- src/plugins/valgrind/valgrindsettings.cpp | 32 ++------------ src/plugins/valgrind/valgrindsettings.h | 51 ++++++++++++----------- 4 files changed, 45 insertions(+), 70 deletions(-) diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index e8ddb08fac7..1318945155a 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -65,16 +65,16 @@ QStringList CallgrindToolRunner::toolArguments() const { QStringList arguments = {"--tool=callgrind"}; - if (m_settings.enableCacheSim.value()) + if (m_settings.enableCacheSim()) arguments << "--cache-sim=yes"; - if (m_settings.enableBranchSim.value()) + if (m_settings.enableBranchSim()) arguments << "--branch-sim=yes"; - if (m_settings.collectBusEvents.value()) + if (m_settings.collectBusEvents()) arguments << "--collect-bus=yes"; - if (m_settings.collectSystime.value()) + if (m_settings.collectSystime()) arguments << "--collect-systime=yes"; if (m_markAsPaused) @@ -86,7 +86,7 @@ QStringList CallgrindToolRunner::toolArguments() const arguments << "--callgrind-out-file=" + m_valgrindOutputFile.path(); - arguments << ProcessArgs::splitArgs(m_settings.callgrindArguments.value(), HostOsInfo::hostOs()); + arguments << ProcessArgs::splitArgs(m_settings.callgrindArguments(), HostOsInfo::hostOs()); return arguments; } diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 21a0c2290c1..38e06d46950 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -185,14 +185,14 @@ QStringList MemcheckToolRunner::toolArguments() const { QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"}; - if (m_settings.trackOrigins.value()) + if (m_settings.trackOrigins()) arguments << "--track-origins=yes"; - if (m_settings.showReachable.value()) + if (m_settings.showReachable()) arguments << "--show-reachable=yes"; QString leakCheckValue; - switch (m_settings.leakCheckOnFinish.value()) { + switch (m_settings.leakCheckOnFinish()) { case ValgrindBaseSettings::LeakCheckOnFinishNo: leakCheckValue = "no"; break; @@ -206,22 +206,22 @@ QStringList MemcheckToolRunner::toolArguments() const } arguments << "--leak-check=" + leakCheckValue; - for (const FilePath &file : m_settings.suppressions.value()) + for (const FilePath &file : m_settings.suppressions()) arguments << QString("--suppressions=%1").arg(file.path()); - arguments << QString("--num-callers=%1").arg(m_settings.numCallers.value()); + arguments << QString("--num-callers=%1").arg(m_settings.numCallers()); if (m_withGdb) arguments << "--vgdb=yes" << "--vgdb-error=0"; - arguments << ProcessArgs::splitArgs(m_settings.memcheckArguments.value(), HostOsInfo::hostOs()); + arguments << ProcessArgs::splitArgs(m_settings.memcheckArguments(), HostOsInfo::hostOs()); return arguments; } const FilePaths MemcheckToolRunner::suppressionFiles() const { - return m_settings.suppressions.value(); + return m_settings.suppressions(); } void MemcheckToolRunner::startDebugger(qint64 valgrindPid) @@ -916,22 +916,22 @@ void MemcheckToolPrivate::updateFromSettings() for (const QVariant &v : actions) { bool ok; int kind = v.toInt(&ok); - if (ok && !m_settings->visibleErrorKinds.value().contains(kind)) + if (ok && !m_settings->visibleErrorKinds().contains(kind)) contained = false; } action->setChecked(contained); } - m_filterProjectAction->setChecked(!m_settings->filterExternalIssues.value()); + m_filterProjectAction->setChecked(!m_settings->filterExternalIssues()); m_errorView->settingsChanged(m_settings); connect(&m_settings->visibleErrorKinds, &IntegersAspect::valueChanged, &m_errorProxyModel, &MemcheckErrorFilterProxyModel::setAcceptedKinds); - m_errorProxyModel.setAcceptedKinds(m_settings->visibleErrorKinds.value()); + m_errorProxyModel.setAcceptedKinds(m_settings->visibleErrorKinds()); connect(&m_settings->filterExternalIssues, &BoolAspect::valueChanged, &m_errorProxyModel, &MemcheckErrorFilterProxyModel::setFilterExternalIssues); - m_errorProxyModel.setFilterExternalIssues(m_settings->filterExternalIssues.value()); + m_errorProxyModel.setFilterExternalIssues(m_settings->filterExternalIssues()); } void MemcheckToolPrivate::maybeActiveRunConfigurationChanged() diff --git a/src/plugins/valgrind/valgrindsettings.cpp b/src/plugins/valgrind/valgrindsettings.cpp index 1b9cfb62e7f..5be58ea3b8c 100644 --- a/src/plugins/valgrind/valgrindsettings.cpp +++ b/src/plugins/valgrind/valgrindsettings.cpp @@ -107,7 +107,8 @@ void SuppressionAspectPrivate::slotSuppressionSelectionChanged() // SuppressionAspect // -SuppressionAspect::SuppressionAspect(bool global) +SuppressionAspect::SuppressionAspect(AspectContainer *container, bool global) + : BaseAspect(container) { d = new SuppressionAspectPrivate(this, global); setSettingsKey("Analyzer.Valgrind.SuppressionFiles"); @@ -195,16 +196,13 @@ void SuppressionAspect::setVolatileValue(const QVariant &val) ////////////////////////////////////////////////////////////////// ValgrindBaseSettings::ValgrindBaseSettings(bool global) - : suppressions(global) + : suppressions(this, global) { // Note that this is used twice, once for project settings in the .user files // and once for global settings in QtCreator.ini. This uses intentionally // the same key to facilitate copying using fromMap/toMap. QString base = "Analyzer.Valgrind."; - registerAspect(&suppressions); - - registerAspect(&valgrindExecutable); valgrindExecutable.setSettingsKey(base + "ValgrindExecutable"); valgrindExecutable.setDefaultValue("valgrind"); valgrindExecutable.setExpectedKind(PathChooser::Command); @@ -219,12 +217,10 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) //valgrindExecutable. ... buttonAtIndex(0)->hide(); } - registerAspect(&valgrindArguments); valgrindArguments.setSettingsKey(base + "ValgrindArguments"); valgrindArguments.setDisplayStyle(StringAspect::LineEditDisplay); valgrindArguments.setLabelText(Tr::tr("Valgrind arguments:")); - registerAspect(&selfModifyingCodeDetection); selfModifyingCodeDetection.setSettingsKey(base + "SelfModifyingCodeDetection"); selfModifyingCodeDetection.setDefaultValue(DetectSmcStackOnly); selfModifyingCodeDetection.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); @@ -235,12 +231,10 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) selfModifyingCodeDetection.setLabelText(Tr::tr("Detect self-modifying code:")); // Memcheck - registerAspect(&memcheckArguments); memcheckArguments.setSettingsKey(base + "Memcheck.Arguments"); memcheckArguments.setDisplayStyle(StringAspect::LineEditDisplay); memcheckArguments.setLabelText(Tr::tr("Extra MemCheck arguments:")); - registerAspect(&filterExternalIssues); filterExternalIssues.setSettingsKey(base + "FilterExternalIssues"); filterExternalIssues.setDefaultValue(true); filterExternalIssues.setIcon(Icons::FILTER.icon()); @@ -248,18 +242,15 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) filterExternalIssues.setLabelText(Tr::tr("Show Project Costs Only")); filterExternalIssues.setToolTip(Tr::tr("Show only profiling info that originated from this project source.")); - registerAspect(&trackOrigins); trackOrigins.setSettingsKey(base + "TrackOrigins"); trackOrigins.setDefaultValue(true); trackOrigins.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); trackOrigins.setLabelText(Tr::tr("Track origins of uninitialized memory")); - registerAspect(&showReachable); showReachable.setSettingsKey(base + "ShowReachable"); showReachable.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); showReachable.setLabelText(Tr::tr("Show reachable and indirectly lost blocks")); - registerAspect(&leakCheckOnFinish); leakCheckOnFinish.setSettingsKey(base + "LeakCheckOnFinish"); leakCheckOnFinish.setDefaultValue(LeakCheckOnFinishSummaryOnly); leakCheckOnFinish.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); @@ -268,33 +259,27 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) leakCheckOnFinish.addOption(Tr::tr("Full")); leakCheckOnFinish.setLabelText(Tr::tr("Check for leaks on finish:")); - registerAspect(&numCallers); numCallers.setSettingsKey(base + "NumCallers"); numCallers.setDefaultValue(25); numCallers.setLabelText(Tr::tr("Backtrace frame count:")); // Callgrind - registerAspect(&kcachegrindExecutable); kcachegrindExecutable.setSettingsKey(base + "KCachegrindExecutable"); kcachegrindExecutable.setDefaultValue("kcachegrind"); - kcachegrindExecutable.setDisplayStyle(StringAspect::PathChooserDisplay); kcachegrindExecutable.setLabelText(Tr::tr("KCachegrind executable:")); kcachegrindExecutable.setExpectedKind(Utils::PathChooser::Command); kcachegrindExecutable.setDisplayName(Tr::tr("KCachegrind Command")); - registerAspect(&callgrindArguments); callgrindArguments.setSettingsKey(base + "Callgrind.Arguments"); callgrindArguments.setDisplayStyle(StringAspect::LineEditDisplay); callgrindArguments.setLabelText(Tr::tr("Extra CallGrind arguments:")); - registerAspect(&enableEventToolTips); enableEventToolTips.setDefaultValue(true); enableEventToolTips.setSettingsKey(base + "Callgrind.EnableEventToolTips"); enableEventToolTips.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); enableEventToolTips.setLabelText(Tr::tr("Show additional information for events in tooltips")); - registerAspect(&enableCacheSim); enableCacheSim.setSettingsKey(base + "Callgrind.EnableCacheSim"); enableCacheSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); enableCacheSim.setLabelText(Tr::tr("Enable cache simulation")); @@ -308,7 +293,6 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) "
  • Data write accesses (\"Dw\") and related cache misses (\"D1mw\"/\"D2mw\").
  • \n" "

    ") + ""); - registerAspect(&enableBranchSim); enableBranchSim.setSettingsKey(base + "Callgrind.EnableBranchSim"); enableBranchSim.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); enableBranchSim.setLabelText(Tr::tr("Enable branch prediction simulation")); @@ -320,20 +304,17 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) "
  • Executed indirect jumps and related misses of the jump address predictor (\n" "\"Bi\"/\"Bim\").)
  • ") + ""); - registerAspect(&collectSystime); collectSystime.setSettingsKey(base + "Callgrind.CollectSystime"); collectSystime.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); collectSystime.setLabelText(Tr::tr("Collect system call time")); collectSystime.setToolTip(Tr::tr("Collects information for system call times.")); - registerAspect(&collectBusEvents); collectBusEvents.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); collectBusEvents.setSettingsKey(base + "Callgrind.CollectBusEvents"); collectBusEvents.setLabelText(Tr::tr("Collect global bus events")); collectBusEvents.setToolTip(Tr::tr("Collect the number of global bus events that are executed. " "The event type \"Ge\" is used for these events.")); - registerAspect(&minimumInclusiveCostRatio); minimumInclusiveCostRatio.setSettingsKey(base + "Callgrind.MinimumCostRatio"); minimumInclusiveCostRatio.setDefaultValue(0.01); minimumInclusiveCostRatio.setSuffix(Tr::tr("%")); @@ -341,13 +322,11 @@ ValgrindBaseSettings::ValgrindBaseSettings(bool global) minimumInclusiveCostRatio.setToolTip(Tr::tr("Limits the amount of results the profiler gives you. " "A lower limit will likely increase performance.")); - registerAspect(&visualizationMinimumInclusiveCostRatio); visualizationMinimumInclusiveCostRatio.setSettingsKey(base + "Callgrind.VisualisationMinimumCostRatio"); visualizationMinimumInclusiveCostRatio.setDefaultValue(10.0); visualizationMinimumInclusiveCostRatio.setLabelText(Tr::tr("Visualization: Minimum event cost:")); visualizationMinimumInclusiveCostRatio.setSuffix(Tr::tr("%")); - registerAspect(&visibleErrorKinds); visibleErrorKinds.setSettingsKey(base + "VisibleErrorKinds"); QList defaultErrorKinds; for (int i = 0; i < Valgrind::XmlProtocol::MemcheckErrorKindCount; ++i) @@ -371,25 +350,20 @@ ValgrindGlobalSettings::ValgrindGlobalSettings() const QString base = "Analyzer.Valgrind"; - registerAspect(&lastSuppressionDirectory); lastSuppressionDirectory.setSettingsKey(base + "LastSuppressionDirectory"); - registerAspect(&lastSuppressionHistory); lastSuppressionHistory.setSettingsKey(base + "LastSuppressionHistory"); - registerAspect(&detectCycles); detectCycles.setSettingsKey(base + "Callgrind.CycleDetection"); detectCycles.setDefaultValue(true); detectCycles.setLabelText("O"); // FIXME: Create a real icon detectCycles.setToolTip(Tr::tr("Enable cycle detection to properly handle recursive " "or circular function calls.")); - registerAspect(&costFormat); costFormat.setSettingsKey(base + "Callgrind.CostFormat"); costFormat.setDefaultValue(CostDelegate::FormatRelative); costFormat.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); - registerAspect(&shortenTemplates); shortenTemplates.setSettingsKey(base + "Callgrind.ShortenTemplates"); shortenTemplates.setDefaultValue(true); shortenTemplates.setLabelText("<>"); // FIXME: Create a real icon diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h index 4752482e48e..d332e8c4f3f 100644 --- a/src/plugins/valgrind/valgrindsettings.h +++ b/src/plugins/valgrind/valgrindsettings.h @@ -17,9 +17,10 @@ class SuppressionAspect final : public Utils::BaseAspect Q_OBJECT public: - explicit SuppressionAspect(bool global); + SuppressionAspect(Utils::AspectContainer *container, bool global); ~SuppressionAspect() final; + Utils::FilePaths operator()() const { return value(); } Utils::FilePaths value() const; void setValue(const Utils::FilePaths &val); @@ -68,9 +69,9 @@ signals: * Base valgrind settings */ public: - Utils::FilePathAspect valgrindExecutable; - Utils::StringAspect valgrindArguments; - Utils::SelectionAspect selfModifyingCodeDetection; + Utils::FilePathAspect valgrindExecutable{this}; + Utils::StringAspect valgrindArguments{this}; + Utils::SelectionAspect selfModifyingCodeDetection{this}; SuppressionAspect suppressions; @@ -78,13 +79,13 @@ public: * Base memcheck settings */ public: - Utils::StringAspect memcheckArguments; - Utils::IntegerAspect numCallers; - Utils::SelectionAspect leakCheckOnFinish; - Utils::BoolAspect showReachable; - Utils::BoolAspect trackOrigins; - Utils::BoolAspect filterExternalIssues; - Utils::IntegersAspect visibleErrorKinds; + Utils::StringAspect memcheckArguments{this}; + Utils::IntegerAspect numCallers{this}; + Utils::SelectionAspect leakCheckOnFinish{this}; + Utils::BoolAspect showReachable{this}; + Utils::BoolAspect trackOrigins{this}; + Utils::BoolAspect filterExternalIssues{this}; + Utils::IntegersAspect visibleErrorKinds{this}; void setVisibleErrorKinds(const QList &); @@ -92,16 +93,16 @@ public: * Base callgrind settings */ public: - Utils::StringAspect callgrindArguments; - Utils::StringAspect kcachegrindExecutable; + Utils::StringAspect callgrindArguments{this}; + Utils::FilePathAspect kcachegrindExecutable{this}; - Utils::BoolAspect enableCacheSim; - Utils::BoolAspect enableBranchSim; - Utils::BoolAspect collectSystime; - Utils::BoolAspect collectBusEvents; - Utils::BoolAspect enableEventToolTips; - Utils::DoubleAspect minimumInclusiveCostRatio; - Utils::DoubleAspect visualizationMinimumInclusiveCostRatio; + Utils::BoolAspect enableCacheSim{this}; + Utils::BoolAspect enableBranchSim{this}; + Utils::BoolAspect collectSystime{this}; + Utils::BoolAspect collectBusEvents{this}; + Utils::BoolAspect enableEventToolTips{this}; + Utils::DoubleAspect minimumInclusiveCostRatio{this}; + Utils::DoubleAspect visualizationMinimumInclusiveCostRatio{this}; QVariantMap defaultSettings() const; }; @@ -126,16 +127,16 @@ public: void writeSettings() const; void readSettings(); - Utils::StringAspect lastSuppressionDirectory; - Utils::StringAspect lastSuppressionHistory; + Utils::StringAspect lastSuppressionDirectory{this}; + Utils::StringAspect lastSuppressionHistory{this}; /** * Global callgrind settings */ - Utils::SelectionAspect costFormat; - Utils::BoolAspect detectCycles; - Utils::BoolAspect shortenTemplates; + Utils::SelectionAspect costFormat{this}; + Utils::BoolAspect detectCycles{this}; + Utils::BoolAspect shortenTemplates{this}; }; From c3fb4e1c512f9823a395f844140dcab020f8ad43 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 13:09:52 +0200 Subject: [PATCH 1261/1447] Valgrind: Remove unused Settings::changed() command This is covered by the AspectContainer's changed() Change-Id: I2ae99fd9d9908cf5f236c41319369130455972f7 Reviewed-by: Christian Stenger --- src/plugins/valgrind/valgrindsettings.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/valgrind/valgrindsettings.h b/src/plugins/valgrind/valgrindsettings.h index d332e8c4f3f..29506b848f5 100644 --- a/src/plugins/valgrind/valgrindsettings.h +++ b/src/plugins/valgrind/valgrindsettings.h @@ -62,9 +62,6 @@ public: LeakCheckOnFinishYes }; -signals: - void changed(); // sent when multiple values have changed simulatenously (e.g. fromMap) - /** * Base valgrind settings */ From 53aeaa1ca495013f62e3324a55306aabc98c4ba5 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 12:10:14 +0200 Subject: [PATCH 1262/1447] Haskell: Finish moving to FilePathAspect use Change-Id: Icd76794b5f81990a583aa1b7ed921fbd08b2d797 Reviewed-by: Eike Ziller --- src/plugins/haskell/haskellsettings.cpp | 2 -- src/plugins/haskell/haskellsettings.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/haskell/haskellsettings.cpp b/src/plugins/haskell/haskellsettings.cpp index e4993020b7f..7b2bbc7fd38 100644 --- a/src/plugins/haskell/haskellsettings.cpp +++ b/src/plugins/haskell/haskellsettings.cpp @@ -30,9 +30,7 @@ HaskellSettings::HaskellSettings() setDisplayCategory(Tr::tr("Haskell")); setCategoryIconPath(":/haskell/images/settingscategory_haskell.png"); - registerAspect(&stackPath); stackPath.setSettingsKey("Haskell/StackExecutable"); - stackPath.setDisplayStyle(StringAspect::PathChooserDisplay); stackPath.setExpectedKind(PathChooser::ExistingCommand); stackPath.setPromptDialogTitle(Tr::tr("Choose Stack Executable")); stackPath.setCommandVersionArguments({"--version"}); diff --git a/src/plugins/haskell/haskellsettings.h b/src/plugins/haskell/haskellsettings.h index 3b0d374c792..1331e5aa89a 100644 --- a/src/plugins/haskell/haskellsettings.h +++ b/src/plugins/haskell/haskellsettings.h @@ -12,7 +12,7 @@ class HaskellSettings : public Core::PagedSettings public: HaskellSettings(); - Utils::FilePathAspect stackPath; + Utils::FilePathAspect stackPath{this}; }; HaskellSettings &settings(); From edd1a89807d605e180a40509bfe6c2598657d1e2 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 23 May 2023 15:05:38 +0200 Subject: [PATCH 1263/1447] Move SessionManager to Core plugin Sessions are independent from projects, and this allows for removal of e.g. the dependency from Bookmarks to ProjectExplorer. Includes moving the command line arguments (-lastsession, ) to Core plugin. Change-Id: I6c578fd15c4990902e7196501de20f39376e90e8 Reviewed-by: Christian Kandeler --- src/plugins/bookmarks/bookmarkmanager.cpp | 9 +-- .../clangmodelmanagersupport.cpp | 2 +- .../clangtoolspreconfiguredsessiontests.cpp | 3 +- src/plugins/coreplugin/CMakeLists.txt | 9 +++ src/plugins/coreplugin/Core.json.in | 8 ++ src/plugins/coreplugin/coreplugin.cpp | 3 +- src/plugins/coreplugin/coreplugin.h | 4 + src/plugins/coreplugin/coreplugin.qbs | 9 +++ .../session.cpp | 79 ++++++++++--------- .../{projectexplorer => coreplugin}/session.h | 10 +-- .../session_p.h | 6 +- .../sessiondialog.cpp | 37 +++++---- .../sessiondialog.h | 6 +- .../sessionmodel.cpp | 56 +++++++------ .../sessionmodel.h | 19 +++-- .../sessionview.cpp | 6 +- .../sessionview.h | 6 +- .../cppeditor/cppcodemodelsettings.cpp | 23 +++--- .../cppeditor/cppcodemodelsettingspage.cpp | 5 +- src/plugins/cppeditor/cppeditordocument.cpp | 9 +-- src/plugins/cppeditor/cppmodelmanager.cpp | 3 +- .../cppeditor/cpppreprocessordialog.cpp | 6 +- src/plugins/debugger/breakhandler.cpp | 3 +- .../debugger/debuggertooltipmanager.cpp | 5 +- src/plugins/debugger/watchhandler.cpp | 5 +- src/plugins/insight/insightmodel.cpp | 1 - src/plugins/projectexplorer/CMakeLists.txt | 4 - .../projectexplorer/ProjectExplorer.json.in | 8 -- src/plugins/projectexplorer/appoutputpane.cpp | 3 +- .../buildsettingspropertiespage.cpp | 2 +- .../projectexplorer/dependenciespanel.cpp | 4 +- src/plugins/projectexplorer/project.h | 1 - .../projectexplorer/projectexplorer.cpp | 3 +- .../projectexplorer/projectexplorer.qbs | 4 - .../projectexplorer/projectmanager.cpp | 2 +- src/plugins/projectexplorer/projectmodels.cpp | 2 +- .../projectexplorer/projectwelcomepage.cpp | 4 +- .../projectexplorer/projectwelcomepage.h | 5 +- .../runsettingspropertiespage.cpp | 3 +- src/plugins/projectexplorer/taskfile.cpp | 3 +- src/plugins/projectexplorer/taskwindow.cpp | 5 +- .../buildsystem/qmlbuildsystem.cpp | 2 +- src/plugins/squish/squishfilehandler.cpp | 16 ++-- 43 files changed, 216 insertions(+), 187 deletions(-) rename src/plugins/{projectexplorer => coreplugin}/session.cpp (92%) rename src/plugins/{projectexplorer => coreplugin}/session.h (93%) rename src/plugins/{projectexplorer => coreplugin}/session_p.h (93%) rename src/plugins/{projectexplorer => coreplugin}/sessiondialog.cpp (87%) rename src/plugins/{projectexplorer => coreplugin}/sessiondialog.h (91%) rename src/plugins/{projectexplorer => coreplugin}/sessionmodel.cpp (82%) rename src/plugins/{projectexplorer => coreplugin}/sessionmodel.h (78%) rename src/plugins/{projectexplorer => coreplugin}/sessionview.cpp (97%) rename src/plugins/{projectexplorer => coreplugin}/sessionview.h (90%) diff --git a/src/plugins/bookmarks/bookmarkmanager.cpp b/src/plugins/bookmarks/bookmarkmanager.cpp index 791455d619a..83a2650b750 100644 --- a/src/plugins/bookmarks/bookmarkmanager.cpp +++ b/src/plugins/bookmarks/bookmarkmanager.cpp @@ -7,14 +7,12 @@ #include "bookmarks_global.h" #include "bookmarkstr.h" +#include +#include #include #include #include -#include -#include - -#include -#include +#include #include #include @@ -40,7 +38,6 @@ Q_DECLARE_METATYPE(Bookmarks::Internal::Bookmark*) -using namespace ProjectExplorer; using namespace Core; using namespace Utils; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 8aea72ce0e1..42e77c11a34 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index 1a87580efc1..4c858451fa3 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -7,6 +7,7 @@ #include "clangtoolsdiagnostic.h" #include +#include #include #include @@ -16,7 +17,6 @@ #include #include #include -#include #include #include @@ -31,6 +31,7 @@ #include +using namespace Core; using namespace CppEditor; using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index d4a2dd164d0..b262d0d7683 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -272,6 +272,15 @@ add_qtc_plugin(Core progressmanager/taskprogress.h rightpane.cpp rightpane.h + session.cpp + session.h + session_p.h + sessiondialog.cpp + sessiondialog.h + sessionmodel.cpp + sessionmodel.h + sessionview.cpp + sessionview.h settingsdatabase.cpp settingsdatabase.h sidebar.cpp diff --git a/src/plugins/coreplugin/Core.json.in b/src/plugins/coreplugin/Core.json.in index b3f36025bfb..606085c91d8 100644 --- a/src/plugins/coreplugin/Core.json.in +++ b/src/plugins/coreplugin/Core.json.in @@ -30,6 +30,14 @@ { \"Name\" : \"-presentationMode\", \"Description\" : \"Enable presentation mode with pop-ups for key combos\" + }, + { + \"Name\" : \"-lastsession\", + \"Description\" : \"Restore the last session\" + }, + { + \"Name\" : \"\", + \"Description\" : \"Restore a saved session\" } ], $$dependencyList diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 1a4ec33ef87..2d825dd3ae5 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -11,6 +11,7 @@ #include "iwizardfactory.h" #include "mainwindow.h" #include "modemanager.h" +#include "session.h" #include "themechooser.h" #include @@ -159,8 +160,8 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) m_mainWindow->init(); m_editMode = new EditMode; ModeManager::activateMode(m_editMode->id()); - m_folderNavigationWidgetFactory = new FolderNavigationWidgetFactory; + m_sessionManager.reset(new SessionManager); IWizardFactory::initialize(); diff --git a/src/plugins/coreplugin/coreplugin.h b/src/plugins/coreplugin/coreplugin.h index 3f535be8a65..fa73f951c13 100644 --- a/src/plugins/coreplugin/coreplugin.h +++ b/src/plugins/coreplugin/coreplugin.h @@ -9,6 +9,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QMenu; QT_END_NAMESPACE @@ -20,6 +22,7 @@ class PathChooser; namespace Core { class FolderNavigationWidgetFactory; +class SessionManager; namespace Internal { @@ -74,6 +77,7 @@ private: MainWindow *m_mainWindow = nullptr; EditMode *m_editMode = nullptr; Locator *m_locator = nullptr; + std::unique_ptr m_sessionManager; FolderNavigationWidgetFactory *m_folderNavigationWidgetFactory = nullptr; Utils::Environment m_startupSystemEnvironment; Utils::EnvironmentItems m_environmentChanges; diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 2467567f01f..096076877f3 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -149,6 +149,15 @@ Project { "plugininstallwizard.h", "rightpane.cpp", "rightpane.h", + "session.cpp", + "session.h", + "session_p.h", + "sessiondialog.cpp", + "sessiondialog.h", + "sessionmodel.cpp", + "sessionmodel.h", + "sessionview.cpp", + "sessionview.h", "settingsdatabase.cpp", "settingsdatabase.h", "sidebar.cpp", diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/coreplugin/session.cpp similarity index 92% rename from src/plugins/projectexplorer/session.cpp rename to src/plugins/coreplugin/session.cpp index 4421e8b7049..d6ccc4ca716 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -1,28 +1,23 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "session.h" - #include "session_p.h" + #include "sessiondialog.h" -#include "projectexplorer.h" -#include "projectexplorertr.h" +#include "actionmanager/actioncontainer.h" +#include "actionmanager/actionmanager.h" +#include "coreconstants.h" +#include "coreplugin.h" +#include "editormanager/editormanager.h" +#include "icore.h" +#include "modemanager.h" +#include "progressmanager/progressmanager.h" #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include @@ -40,11 +35,17 @@ #include #include -using namespace Core; using namespace ExtensionSystem; using namespace Utils; -namespace ProjectExplorer { +namespace Core { + +namespace PE { +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(QtC::ProjectExplorer) +}; +} // namespace PE const char DEFAULT_SESSION[] = "default"; const char LAST_ACTIVE_TIMES_KEY[] = "LastActiveTimes"; @@ -96,14 +97,14 @@ SessionManager::SessionManager() // session menu ActionContainer *mfile = ActionManager::actionContainer(Core::Constants::M_FILE); ActionContainer *msession = ActionManager::createMenu(M_SESSION); - msession->menu()->setTitle(Tr::tr("S&essions")); + msession->menu()->setTitle(PE::Tr::tr("S&essions")); msession->setOnAllDisabledBehavior(ActionContainer::Show); mfile->addMenu(msession, Core::Constants::G_FILE_OPEN); sb_d->m_sessionMenu = msession->menu(); connect(mfile->menu(), &QMenu::aboutToShow, this, [] { sb_d->updateSessionMenu(); }); // session manager action - sb_d->m_sessionManagerAction = new QAction(Tr::tr("&Manage..."), this); + sb_d->m_sessionManagerAction = new QAction(PE::Tr::tr("&Manage..."), this); sb_d->m_sessionMenu->addAction(sb_d->m_sessionManagerAction); sb_d->m_sessionMenu->addSeparator(); Command *cmd = ActionManager::registerAction(sb_d->m_sessionManagerAction, @@ -115,10 +116,13 @@ SessionManager::SessionManager() &SessionManager::showSessionManager); MacroExpander *expander = Utils::globalMacroExpander(); - expander->registerFileVariables("Session", Tr::tr("File where current session is saved."), [] { - return SessionManager::sessionNameToFileName(SessionManager::activeSession()); - }); - expander->registerVariable("Session:Name", Tr::tr("Name of current session."), [] { + expander->registerFileVariables("Session", + PE::Tr::tr("File where current session is saved."), + [] { + return SessionManager::sessionNameToFileName( + SessionManager::activeSession()); + }); + expander->registerVariable("Session:Name", PE::Tr::tr("Name of current session."), [] { return SessionManager::activeSession(); }); @@ -268,10 +272,12 @@ void SessionManager::showSessionManager() */ bool SessionManager::confirmSessionDelete(const QStringList &sessions) { - const QString title = sessions.size() == 1 ? Tr::tr("Delete Session") : Tr::tr("Delete Sessions"); - const QString question = sessions.size() == 1 - ? Tr::tr("Delete session %1?").arg(sessions.first()) - : Tr::tr("Delete these sessions?\n %1").arg(sessions.join("\n ")); + const QString title = sessions.size() == 1 ? PE::Tr::tr("Delete Session") + : PE::Tr::tr("Delete Sessions"); + const QString question + = sessions.size() == 1 + ? PE::Tr::tr("Delete session %1?").arg(sessions.first()) + : PE::Tr::tr("Delete these sessions?\n %1").arg(sessions.join("\n ")); return QMessageBox::question(ICore::dialogParent(), title, question, @@ -321,7 +327,7 @@ static QString determineSessionToRestoreAtStartup() { // TODO (session) move argument to core // Process command line arguments first: - const bool lastSessionArg = PluginManager::specForPlugin(ProjectExplorerPlugin::instance()) + const bool lastSessionArg = PluginManager::specForPlugin(Internal::CorePlugin::instance()) ->arguments() .contains("-lastsession"); if (lastSessionArg && !SessionManager::startupSession().isEmpty()) @@ -580,8 +586,9 @@ bool SessionManager::loadSession(const QString &session, bool initial) if (fileName.exists()) { if (!reader.load(fileName)) { QMessageBox::warning(ICore::dialogParent(), - Tr::tr("Error while restoring session"), - Tr::tr("Could not restore session %1").arg(fileName.toUserOutput())); + PE::Tr::tr("Error while restoring session"), + PE::Tr::tr("Could not restore session %1") + .arg(fileName.toUserOutput())); return false; } @@ -623,7 +630,7 @@ bool SessionManager::loadSession(const QString &session, bool initial) sb_d->m_virginSession = false; ProgressManager::addTask(sb_d->m_future.future(), - Tr::tr("Loading Session"), + PE::Tr::tr("Loading Session"), "ProjectExplorer.SessionFile.Load"); sb_d->m_future.setProgressRange(0, 1 /*initialization*/ + 1 /*editors*/); @@ -670,8 +677,8 @@ bool SessionManager::saveSession() PersistentSettingsReader reader; if (!reader.load(filePath)) { QMessageBox::warning(ICore::dialogParent(), - Tr::tr("Error while saving session"), - Tr::tr("Could not save session %1") + PE::Tr::tr("Error while saving session"), + PE::Tr::tr("Could not save session %1") .arg(filePath.toUserOutput())); return false; } @@ -712,8 +719,8 @@ bool SessionManager::saveSession() QDateTime::currentDateTime()); } else { QMessageBox::warning(ICore::dialogParent(), - Tr::tr("Error while saving session"), - Tr::tr("Could not save session to file %1") + PE::Tr::tr("Error while saving session"), + PE::Tr::tr("Could not save session to file %1") .arg(sb_d->m_writer->fileName().toUserOutput())); } @@ -725,4 +732,4 @@ bool SessionManager::isStartupSessionRestored() return sb_d->m_isStartupSessionRestored; } -} // namespace ProjectExplorer +} // namespace Core diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/coreplugin/session.h similarity index 93% rename from src/plugins/projectexplorer/session.h rename to src/plugins/coreplugin/session.h index 0844505ae38..30dc70edf4d 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/coreplugin/session.h @@ -1,9 +1,9 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "projectexplorer_export.h" +#include "core_global.h" #include #include @@ -12,9 +12,9 @@ #include #include -namespace ProjectExplorer { +namespace Core { -class PROJECTEXPLORER_EXPORT SessionManager : public QObject +class CORE_EXPORT SessionManager : public QObject { Q_OBJECT @@ -87,4 +87,4 @@ private: static void saveActiveMode(Utils::Id mode); }; -} // namespace ProjectExplorer +} // namespace Core diff --git a/src/plugins/projectexplorer/session_p.h b/src/plugins/coreplugin/session_p.h similarity index 93% rename from src/plugins/projectexplorer/session_p.h rename to src/plugins/coreplugin/session_p.h index 587e01a6a02..20ceecbcbc3 100644 --- a/src/plugins/projectexplorer/session_p.h +++ b/src/plugins/coreplugin/session_p.h @@ -1,4 +1,4 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include @@ -12,7 +12,7 @@ QT_END_NAMESPACE using namespace Utils; -namespace ProjectExplorer { +namespace Core { class SessionManagerPrivate { @@ -54,4 +54,4 @@ public: extern SessionManagerPrivate *sb_d; -} // namespace ProjectExplorer +} // namespace Core diff --git a/src/plugins/projectexplorer/sessiondialog.cpp b/src/plugins/coreplugin/sessiondialog.cpp similarity index 87% rename from src/plugins/projectexplorer/sessiondialog.cpp rename to src/plugins/coreplugin/sessiondialog.cpp index fe9758dc1b7..dd81f43fd09 100644 --- a/src/plugins/projectexplorer/sessiondialog.cpp +++ b/src/plugins/coreplugin/sessiondialog.cpp @@ -1,9 +1,8 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "sessiondialog.h" -#include "projectexplorertr.h" #include "session.h" #include "sessionview.h" @@ -11,13 +10,21 @@ #include #include +#include #include #include #include #include #include -namespace ProjectExplorer::Internal { +namespace Core::Internal { + +namespace PE { +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(QtC::ProjectExplorer) +}; +} // namespace PE class SessionValidator : public QValidator { @@ -77,12 +84,14 @@ SessionNameInputDialog::SessionNameInputDialog(QWidget *parent) m_usedSwitchTo = true; }); + // clang-format off using namespace Layouting; Column { - Tr::tr("Enter the name of the session:"), + PE::Tr::tr("Enter the name of the session:"), m_newSessionLineEdit, buttons, }.attachTo(this); + // clang-format on connect(m_newSessionLineEdit, &QLineEdit::textChanged, [this](const QString &text) { m_okButton->setEnabled(!text.isEmpty()); @@ -120,24 +129,23 @@ SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent) { setObjectName("ProjectExplorer.SessionDialog"); resize(550, 400); - setWindowTitle(Tr::tr("Session Manager")); - + setWindowTitle(PE::Tr::tr("Session Manager")); auto sessionView = new SessionView(this); sessionView->setObjectName("sessionView"); sessionView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); sessionView->setActivationMode(Utils::DoubleClickActivation); - auto createNewButton = new QPushButton(Tr::tr("&New")); + auto createNewButton = new QPushButton(PE::Tr::tr("&New")); createNewButton->setObjectName("btCreateNew"); - m_openButton = new QPushButton(Tr::tr("&Open")); + m_openButton = new QPushButton(PE::Tr::tr("&Open")); m_openButton->setObjectName("btOpen"); - m_renameButton = new QPushButton(Tr::tr("&Rename")); - m_cloneButton = new QPushButton(Tr::tr("C&lone")); - m_deleteButton = new QPushButton(Tr::tr("&Delete")); + m_renameButton = new QPushButton(PE::Tr::tr("&Rename")); + m_cloneButton = new QPushButton(PE::Tr::tr("C&lone")); + m_deleteButton = new QPushButton(PE::Tr::tr("&Delete")); - m_autoLoadCheckBox = new QCheckBox(Tr::tr("Restore last session on startup")); + m_autoLoadCheckBox = new QCheckBox(PE::Tr::tr("Restore last session on startup")); auto buttonBox = new QDialogButtonBox(this); buttonBox->setStandardButtons(QDialogButtonBox::Close); @@ -145,7 +153,8 @@ SessionDialog::SessionDialog(QWidget *parent) : QDialog(parent) m_openButton->setDefault(true); auto whatsASessionLabel = new QLabel(QString("%1").arg(Tr::tr("What is a Session?"))); + "creator-project-managing-sessions.html\">%1") + .arg(PE::Tr::tr("What is a Session?"))); whatsASessionLabel->setOpenExternalLinks(true); using namespace Layouting; @@ -218,4 +227,4 @@ void SessionDialog::updateActions(const QStringList &sessions) m_deleteButton->setEnabled(!defaultIsSelected && !activeIsSelected); } -} // ProjectExplorer::Internal +} // namespace Core::Internal diff --git a/src/plugins/projectexplorer/sessiondialog.h b/src/plugins/coreplugin/sessiondialog.h similarity index 91% rename from src/plugins/projectexplorer/sessiondialog.h rename to src/plugins/coreplugin/sessiondialog.h index 56cab430ea7..b6512feab6c 100644 --- a/src/plugins/projectexplorer/sessiondialog.h +++ b/src/plugins/coreplugin/sessiondialog.h @@ -1,4 +1,4 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once @@ -12,7 +12,7 @@ class QLineEdit; class QPushButton; QT_END_NAMESPACE -namespace ProjectExplorer::Internal { +namespace Core::Internal { class SessionDialog : public QDialog { @@ -53,4 +53,4 @@ private: bool m_usedSwitchTo = false; }; -} // ProjectExplorer::Internal +} // namespace Core::Internal diff --git a/src/plugins/projectexplorer/sessionmodel.cpp b/src/plugins/coreplugin/sessionmodel.cpp similarity index 82% rename from src/plugins/projectexplorer/sessionmodel.cpp rename to src/plugins/coreplugin/sessionmodel.cpp index b94a7ecde0e..fa0d8ee087e 100644 --- a/src/plugins/projectexplorer/sessionmodel.cpp +++ b/src/plugins/coreplugin/sessionmodel.cpp @@ -1,10 +1,8 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "sessionmodel.h" -#include "projectexplorertr.h" -#include "projectmanager.h" #include "session.h" #include "sessiondialog.h" @@ -17,11 +15,17 @@ #include #include -using namespace Core; using namespace Utils; +using namespace Core::Internal; -namespace ProjectExplorer { -namespace Internal { +namespace Core { + +namespace PE { +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(QtC::ProjectExplorer) +}; +} // namespace PE SessionModel::SessionModel(QObject *parent) : QAbstractTableModel(parent) @@ -48,9 +52,11 @@ QVariant SessionModel::headerData(int section, Qt::Orientation orientation, int switch (role) { case Qt::DisplayRole: switch (section) { - case 0: result = Tr::tr("Session"); + case 0: + result = PE::Tr::tr("Session"); break; - case 1: result = Tr::tr("Last Modified"); + case 1: + result = PE::Tr::tr("Last Modified"); break; } // switch (section) break; @@ -118,10 +124,6 @@ QVariant SessionModel::data(const QModelIndex &index, int role) const return SessionManager::lastSession() == sessionName; case ActiveSessionRole: return SessionManager::activeSession() == sessionName; - case ProjectsPathRole: - return pathsWithTildeHomePath(ProjectManager::projectsForSessionName(sessionName)); - case ProjectsDisplayRole: - return pathsToBaseNames(ProjectManager::projectsForSessionName(sessionName)); case ShortcutRole: { const Id sessionBase = SESSION_BASE_ID; if (Command *cmd = ActionManager::command(sessionBase.withSuffix(index.row() + 1))) @@ -134,14 +136,10 @@ QVariant SessionModel::data(const QModelIndex &index, int role) const QHash SessionModel::roleNames() const { - static const QHash extraRoles{ - {Qt::DisplayRole, "sessionName"}, - {DefaultSessionRole, "defaultSession"}, - {ActiveSessionRole, "activeSession"}, - {LastSessionRole, "lastSession"}, - {ProjectsPathRole, "projectsPath"}, - {ProjectsDisplayRole, "projectsName"} - }; + static const QHash extraRoles{{Qt::DisplayRole, "sessionName"}, + {DefaultSessionRole, "defaultSession"}, + {ActiveSessionRole, "activeSession"}, + {LastSessionRole, "lastSession"}}; QHash roles = QAbstractTableModel::roleNames(); Utils::addToHash(&roles, extraRoles); return roles; @@ -189,8 +187,8 @@ void SessionModel::resetSessions() void SessionModel::newSession(QWidget *parent) { SessionNameInputDialog sessionInputDialog(parent); - sessionInputDialog.setWindowTitle(Tr::tr("New Session Name")); - sessionInputDialog.setActionText(Tr::tr("&Create"), Tr::tr("Create and &Open")); + sessionInputDialog.setWindowTitle(PE::Tr::tr("New Session Name")); + sessionInputDialog.setActionText(PE::Tr::tr("&Create"), PE::Tr::tr("Create and &Open")); runSessionNameInputDialog(&sessionInputDialog, [](const QString &newName) { SessionManager::createSession(newName); @@ -200,8 +198,8 @@ void SessionModel::newSession(QWidget *parent) void SessionModel::cloneSession(QWidget *parent, const QString &session) { SessionNameInputDialog sessionInputDialog(parent); - sessionInputDialog.setWindowTitle(Tr::tr("New Session Name")); - sessionInputDialog.setActionText(Tr::tr("&Clone"), Tr::tr("Clone and &Open")); + sessionInputDialog.setWindowTitle(PE::Tr::tr("New Session Name")); + sessionInputDialog.setActionText(PE::Tr::tr("&Clone"), PE::Tr::tr("Clone and &Open")); sessionInputDialog.setValue(session + " (2)"); runSessionNameInputDialog(&sessionInputDialog, [session](const QString &newName) { @@ -223,8 +221,8 @@ void SessionModel::deleteSessions(const QStringList &sessions) void SessionModel::renameSession(QWidget *parent, const QString &session) { SessionNameInputDialog sessionInputDialog(parent); - sessionInputDialog.setWindowTitle(Tr::tr("Rename Session")); - sessionInputDialog.setActionText(Tr::tr("&Rename"), Tr::tr("Rename and &Open")); + sessionInputDialog.setWindowTitle(PE::Tr::tr("Rename Session")); + sessionInputDialog.setActionText(PE::Tr::tr("&Rename"), PE::Tr::tr("Rename and &Open")); sessionInputDialog.setValue(session); runSessionNameInputDialog(&sessionInputDialog, [session](const QString &newName) { @@ -238,7 +236,8 @@ void SessionModel::switchToSession(const QString &session) emit sessionSwitched(); } -void SessionModel::runSessionNameInputDialog(SessionNameInputDialog *sessionInputDialog, std::function createSession) +void SessionModel::runSessionNameInputDialog(SessionNameInputDialog *sessionInputDialog, + std::function createSession) { if (sessionInputDialog->exec() == QDialog::Accepted) { QString newSession = sessionInputDialog->value(); @@ -256,5 +255,4 @@ void SessionModel::runSessionNameInputDialog(SessionNameInputDialog *sessionInpu } } -} // namespace Internal -} // namespace ProjectExplorer +} // namespace Core diff --git a/src/plugins/projectexplorer/sessionmodel.h b/src/plugins/coreplugin/sessionmodel.h similarity index 78% rename from src/plugins/projectexplorer/sessionmodel.h rename to src/plugins/coreplugin/sessionmodel.h index 82f19942109..79abd7ae3f1 100644 --- a/src/plugins/projectexplorer/sessionmodel.h +++ b/src/plugins/coreplugin/sessionmodel.h @@ -1,20 +1,21 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once +#include "core_global.h" + #include #include -namespace ProjectExplorer { -namespace Internal { +namespace Core { const char SESSION_BASE_ID[] = "Welcome.OpenSession"; -class SessionNameInputDialog; +namespace Internal { class SessionNameInputDialog; } -class SessionModel : public QAbstractTableModel +class CORE_EXPORT SessionModel : public QAbstractTableModel { Q_OBJECT @@ -23,8 +24,6 @@ public: DefaultSessionRole = Qt::UserRole+1, LastSessionRole, ActiveSessionRole, - ProjectsPathRole, - ProjectsDisplayRole, ShortcutRole }; @@ -56,12 +55,12 @@ public slots: void switchToSession(const QString &session); private: - void runSessionNameInputDialog(ProjectExplorer::Internal::SessionNameInputDialog *sessionInputDialog, std::function createSession); + void runSessionNameInputDialog(Internal::SessionNameInputDialog *sessionInputDialog, + std::function createSession); QStringList m_sortedSessions; int m_currentSortColumn = 0; Qt::SortOrder m_currentSortOrder = Qt::AscendingOrder; }; -} // namespace Internal -} // namespace ProjectExplorer +} // namespace Core diff --git a/src/plugins/projectexplorer/sessionview.cpp b/src/plugins/coreplugin/sessionview.cpp similarity index 97% rename from src/plugins/projectexplorer/sessionview.cpp rename to src/plugins/coreplugin/sessionview.cpp index e4b3b1a5d0a..c3d7ed25b30 100644 --- a/src/plugins/projectexplorer/sessionview.cpp +++ b/src/plugins/coreplugin/sessionview.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "sessionview.h" @@ -12,7 +12,7 @@ #include #include -namespace ProjectExplorer { +namespace Core { namespace Internal { // custom item delegate class @@ -149,4 +149,4 @@ QStringList SessionView::selectedSessions() const } } // namespace Internal -} // namespace ProjectExplorer +} // namespace Core diff --git a/src/plugins/projectexplorer/sessionview.h b/src/plugins/coreplugin/sessionview.h similarity index 90% rename from src/plugins/projectexplorer/sessionview.h rename to src/plugins/coreplugin/sessionview.h index 656da080ea3..2581a8b1716 100644 --- a/src/plugins/projectexplorer/sessionview.h +++ b/src/plugins/coreplugin/sessionview.h @@ -1,4 +1,4 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once @@ -9,7 +9,7 @@ #include -namespace ProjectExplorer::Internal { +namespace Core::Internal { class SessionView : public Utils::TreeView { @@ -44,4 +44,4 @@ private: SessionModel m_sessionModel; }; -} // ProjectExplorer::Internal +} // namespace Core::Internal diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 2f4fdffab2d..d0976b8128d 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -9,9 +9,9 @@ #include "cpptoolsreuse.h" #include +#include #include -#include #include #include @@ -251,15 +251,18 @@ ClangdSettings &ClangdSettings::instance() ClangdSettings::ClangdSettings() { loadSettings(); - const auto sessionMgr = ProjectExplorer::SessionManager::instance(); - connect(sessionMgr, &ProjectExplorer::SessionManager::sessionRemoved, - this, [this](const QString &name) { m_data.sessionsWithOneClangd.removeOne(name); }); - connect(sessionMgr, &ProjectExplorer::SessionManager::sessionRenamed, - this, [this](const QString &oldName, const QString &newName) { - const auto index = m_data.sessionsWithOneClangd.indexOf(oldName); - if (index != -1) - m_data.sessionsWithOneClangd[index] = newName; + const auto sessionMgr = Core::SessionManager::instance(); + connect(sessionMgr, &Core::SessionManager::sessionRemoved, this, [this](const QString &name) { + m_data.sessionsWithOneClangd.removeOne(name); }); + connect(sessionMgr, + &Core::SessionManager::sessionRenamed, + this, + [this](const QString &oldName, const QString &newName) { + const auto index = m_data.sessionsWithOneClangd.indexOf(oldName); + if (index != -1) + m_data.sessionsWithOneClangd[index] = newName; + }); } bool ClangdSettings::useClangd() const @@ -333,7 +336,7 @@ ClangDiagnosticConfig ClangdSettings::diagnosticConfig() const ClangdSettings::Granularity ClangdSettings::granularity() const { - if (m_data.sessionsWithOneClangd.contains(ProjectExplorer::SessionManager::activeSession())) + if (m_data.sessionsWithOneClangd.contains(Core::SessionManager::activeSession())) return Granularity::Session; return Granularity::Project; } diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 88f5bf0de8b..15240b7e9fe 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -10,8 +10,7 @@ #include "cpptoolsreuse.h" #include - -#include +#include #include #include @@ -392,7 +391,7 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD connect(addButton, &QPushButton::clicked, this, [this, sessionsView] { QInputDialog dlg(sessionsView); - QStringList sessions = ProjectExplorer::SessionManager::sessions(); + QStringList sessions = Core::SessionManager::sessions(); QStringList currentSessions = d->sessionsModel.stringList(); for (const QString &s : std::as_const(currentSessions)) sessions.removeOne(s); diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index 7db63ec7afb..328b2c23460 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -16,8 +16,7 @@ #include "cppquickfixassistant.h" #include - -#include +#include #include #include @@ -217,7 +216,7 @@ void CppEditorDocument::reparseWithPreferredParseContext(const QString &parseCon // Remember the setting const QString key = Constants::PREFERRED_PARSE_CONTEXT + filePath().toString(); - ProjectExplorer::SessionManager::setValue(key, parseContextId); + Core::SessionManager::setValue(key, parseContextId); // Reprocess scheduleProcessDocument(); @@ -284,7 +283,7 @@ void CppEditorDocument::applyPreferredParseContextFromSettings() return; const QString key = Constants::PREFERRED_PARSE_CONTEXT + filePath().toString(); - const QString parseContextId = ProjectExplorer::SessionManager::value(key).toString(); + const QString parseContextId = Core::SessionManager::value(key).toString(); setPreferredParseContext(parseContextId); } @@ -295,7 +294,7 @@ void CppEditorDocument::applyExtraPreprocessorDirectivesFromSettings() return; const QString key = Constants::EXTRA_PREPROCESSOR_DIRECTIVES + filePath().toString(); - const QByteArray directives = ProjectExplorer::SessionManager::value(key).toString().toUtf8(); + const QByteArray directives = Core::SessionManager::value(key).toString().toUtf8(); setExtraPreprocessorDirectives(directives); } diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 07b4e67d270..2b5d4e3fb82 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -43,6 +43,8 @@ #include +#include + #include #include #include @@ -54,7 +56,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/cppeditor/cpppreprocessordialog.cpp b/src/plugins/cppeditor/cpppreprocessordialog.cpp index b6b1d9d2a63..87afd9761a2 100644 --- a/src/plugins/cppeditor/cpppreprocessordialog.cpp +++ b/src/plugins/cppeditor/cpppreprocessordialog.cpp @@ -7,7 +7,7 @@ #include "cppeditortr.h" #include "cpptoolsreuse.h" -#include +#include #include @@ -27,7 +27,7 @@ CppPreProcessorDialog::CppPreProcessorDialog(const FilePath &filePath, QWidget * setWindowTitle(Tr::tr("Additional C++ Preprocessor Directives")); const QString key = Constants::EXTRA_PREPROCESSOR_DIRECTIVES + m_filePath.toString(); - const QString directives = ProjectExplorer::SessionManager::value(key).toString(); + const QString directives = Core::SessionManager::value(key).toString(); m_editWidget = new TextEditor::SnippetEditorWidget; m_editWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -56,7 +56,7 @@ int CppPreProcessorDialog::exec() return Rejected; const QString key = Constants::EXTRA_PREPROCESSOR_DIRECTIVES + m_filePath.toString(); - ProjectExplorer::SessionManager::setValue(key, extraPreprocessorDirectives()); + Core::SessionManager::setValue(key, extraPreprocessorDirectives()); return Accepted; } diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index e08b155d8e7..35915f9755f 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -18,8 +18,7 @@ #include #include #include - -#include +#include #include #include diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 4f41436a460..8efea0c487a 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -13,16 +13,15 @@ #include "stackhandler.h" #include "watchhandler.h" -#include #include #include #include +#include #include +#include #include -#include - #include #include diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 734bab3b3ca..5324c7a8dcb 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -21,11 +21,10 @@ #include "watchdelegatewidgets.h" #include "watchutils.h" -#include #include +#include #include - -#include +#include #include diff --git a/src/plugins/insight/insightmodel.cpp b/src/plugins/insight/insightmodel.cpp index 728c469a58f..b80249d2124 100644 --- a/src/plugins/insight/insightmodel.cpp +++ b/src/plugins/insight/insightmodel.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index a016924bc70..00ea43530b9 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -158,10 +158,6 @@ add_qtc_plugin(ProjectExplorer runsettingspropertiespage.cpp runsettingspropertiespage.h sanitizerparser.cpp sanitizerparser.h selectablefilesmodel.cpp selectablefilesmodel.h - session.cpp session.h session_p.h - sessiondialog.cpp sessiondialog.h - sessionmodel.cpp sessionmodel.h - sessionview.cpp sessionview.h showineditortaskhandler.cpp showineditortaskhandler.h showoutputtaskhandler.cpp showoutputtaskhandler.h simpleprojectwizard.cpp simpleprojectwizard.h diff --git a/src/plugins/projectexplorer/ProjectExplorer.json.in b/src/plugins/projectexplorer/ProjectExplorer.json.in index d96dcc26c6d..c9b54ad441c 100644 --- a/src/plugins/projectexplorer/ProjectExplorer.json.in +++ b/src/plugins/projectexplorer/ProjectExplorer.json.in @@ -24,14 +24,6 @@ \"Name\" : \"-ensure-kit-for-binary\", \"Parameter\" : \"file path\", \"Description\" : \"Create kit with architecture matching a given application or library\" - }, - { - \"Name\" : \"-lastsession\", - \"Description\" : \"Restore the last session\" - }, - { - \"Name\" : \"\", - \"Description\" : \"Restore a saved session\" } ], $$dependencyList, diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 6f7e22bacd2..3c76c2e62a0 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -8,7 +8,6 @@ #include "projectexplorericons.h" #include "projectexplorertr.h" #include "runcontrol.h" -#include "session.h" #include "showoutputtaskhandler.h" #include "windebuginterface.h" @@ -17,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +46,7 @@ static Q_LOGGING_CATEGORY(appOutputLog, "qtc.projectexplorer.appoutput", QtWarningMsg); +using namespace Core; using namespace Utils; namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index c715cff6d0f..2caa44712e0 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -10,10 +10,10 @@ #include "project.h" #include "projectconfigurationmodel.h" #include "projectexplorertr.h" -#include "session.h" #include "target.h" #include +#include #include #include diff --git a/src/plugins/projectexplorer/dependenciespanel.cpp b/src/plugins/projectexplorer/dependenciespanel.cpp index c08ae7b523b..daac52b8d75 100644 --- a/src/plugins/projectexplorer/dependenciespanel.cpp +++ b/src/plugins/projectexplorer/dependenciespanel.cpp @@ -6,9 +6,9 @@ #include "project.h" #include "projectexplorertr.h" #include "projectmanager.h" -#include "session.h" #include +#include #include #include @@ -37,7 +37,7 @@ DependenciesModel::DependenciesModel(Project *project, QObject *parent) this, &DependenciesModel::resetModel); connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, &DependenciesModel::resetModel); - connect(SessionManager::instance(), &SessionManager::sessionLoaded, + connect(Core::SessionManager::instance(), &Core::SessionManager::sessionLoaded, this, &DependenciesModel::resetModel); } diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index d753048aff5..832fc3c9423 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -41,7 +41,6 @@ enum class SetActive : int; // Documentation inside. class PROJECTEXPLORER_EXPORT Project : public QObject { - friend class SessionManager; // for setActiveTarget Q_OBJECT public: diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 06ae144ae05..eecf5332b00 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -68,7 +68,6 @@ #include "removetaskhandler.h" #include "sanitizerparser.h" #include "selectablefilesmodel.h" -#include "session.h" #include "showineditortaskhandler.h" #include "simpleprojectwizard.h" #include "target.h" @@ -109,6 +108,7 @@ #include #include #include +#include #include #include @@ -640,7 +640,6 @@ public: RemoveTaskHandler m_removeTaskHandler; ConfigTaskHandler m_configTaskHandler{Task::compilerMissingTask(), Constants::KITS_SETTINGS_PAGE_ID}; - SessionManager m_sessionBase; ProjectManager m_sessionManager; AppOutputPane m_outputPane; diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index e938165e97b..3b407825713 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -134,10 +134,6 @@ Project { "runsettingspropertiespage.cpp", "runsettingspropertiespage.h", "sanitizerparser.cpp", "sanitizerparser.h", "selectablefilesmodel.cpp", "selectablefilesmodel.h", - "session.cpp", "session.h", "session_p.h", - "sessionmodel.cpp", "sessionmodel.h", - "sessionview.cpp", "sessionview.h", - "sessiondialog.cpp", "sessiondialog.h", "showineditortaskhandler.cpp", "showineditortaskhandler.h", "showoutputtaskhandler.cpp", "showoutputtaskhandler.h", "simpleprojectwizard.cpp", "simpleprojectwizard.h", diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index 6d0730786bd..e3c8e65c59b 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -3,7 +3,6 @@ #include "projectmanager.h" -#include "session.h" #include "buildconfiguration.h" #include "editorconfiguration.h" @@ -23,6 +22,7 @@ #include #include #include +#include #include diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index bc5a0ef4d65..9805e654b74 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -10,7 +10,6 @@ #include "projectexplorertr.h" #include "projectmanager.h" #include "projecttree.h" -#include "session.h" #include "target.h" #include @@ -18,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index d3f5733461b..4eef637077c 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -3,8 +3,6 @@ #include "projectwelcomepage.h" -#include "session.h" -#include "sessionmodel.h" #include "projectexplorer.h" #include "projectexplorertr.h" #include "projectmanager.h" @@ -16,6 +14,8 @@ #include #include #include +#include +#include #include #include diff --git a/src/plugins/projectexplorer/projectwelcomepage.h b/src/plugins/projectexplorer/projectwelcomepage.h index 2585ef09d54..7fb2a828dbf 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.h +++ b/src/plugins/projectexplorer/projectwelcomepage.h @@ -12,10 +12,11 @@ #include #include +namespace Core { class SessionModel; } + namespace ProjectExplorer { namespace Internal { -class SessionModel; class SessionsPage; class ProjectModel : public QAbstractListModel @@ -63,7 +64,7 @@ private: void createActions(); friend class SessionsPage; - SessionModel *m_sessionModel = nullptr; + Core::SessionModel *m_sessionModel = nullptr; ProjectModel *m_projectModel = nullptr; }; diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.cpp b/src/plugins/projectexplorer/runsettingspropertiespage.cpp index c1a3a75e3c2..43edee9b668 100644 --- a/src/plugins/projectexplorer/runsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/runsettingspropertiespage.cpp @@ -10,9 +10,10 @@ #include "projectconfigurationmodel.h" #include "projectexplorertr.h" #include "runconfiguration.h" -#include "session.h" #include "target.h" +#include + #include #include #include diff --git a/src/plugins/projectexplorer/taskfile.cpp b/src/plugins/projectexplorer/taskfile.cpp index f137b0f812c..deb9a3ee6d8 100644 --- a/src/plugins/projectexplorer/taskfile.cpp +++ b/src/plugins/projectexplorer/taskfile.cpp @@ -6,11 +6,11 @@ #include "projectexplorer.h" #include "projectexplorerconstants.h" #include "projectexplorertr.h" -#include "session.h" #include "taskhub.h" #include #include +#include #include #include @@ -20,6 +20,7 @@ #include #include +using namespace Core; using namespace Utils; namespace ProjectExplorer { diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index e1e346887f7..f45a3df9216 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -6,7 +6,6 @@ #include "itaskhandler.h" #include "projectexplorericons.h" #include "projectexplorertr.h" -#include "session.h" #include "task.h" #include "taskhub.h" #include "taskmodel.h" @@ -17,8 +16,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -43,6 +43,7 @@ #include #include +using namespace Core; using namespace Utils; const char SESSION_FILTER_CATEGORIES[] = "TaskWindow.Categories"; diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 81a157f1b6f..4ccb9ad48f0 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include "projectitem/qmlprojectitem.h" diff --git a/src/plugins/squish/squishfilehandler.cpp b/src/plugins/squish/squishfilehandler.cpp index 6e48c917b86..8a726cb9baa 100644 --- a/src/plugins/squish/squishfilehandler.cpp +++ b/src/plugins/squish/squishfilehandler.cpp @@ -15,9 +15,9 @@ #include #include #include +#include #include -#include #include #include @@ -33,6 +33,8 @@ #include #include +using namespace Core; + namespace Squish { namespace Internal { @@ -95,7 +97,7 @@ SquishFileHandler::SquishFileHandler(QObject *parent) : QObject(parent) { m_instance = this; - connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::sessionLoaded, + connect(SessionManager::instance(), &SessionManager::sessionLoaded, this, &SquishFileHandler::onSessionLoaded); } @@ -259,7 +261,7 @@ void SquishFileHandler::openTestSuites() } } emit suitesOpened(); - ProjectExplorer::SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); + SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); } void SquishFileHandler::openTestSuite(const Utils::FilePath &suiteConfPath, bool isReopen) @@ -289,7 +291,7 @@ void SquishFileHandler::openTestSuite(const Utils::FilePath &suiteConfPath, bool m_suites.insert(suiteName, suiteConfPath); emit testTreeItemCreated(item); } - ProjectExplorer::SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); + SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); } static void closeOpenedEditorsFor(const Utils::FilePath &filePath, bool askAboutModifiedEditors) @@ -311,13 +313,13 @@ void SquishFileHandler::closeTestSuite(const QString &suiteName) // TODO remove file watcher m_suites.remove(suiteName); emit suiteTreeItemRemoved(suiteName); - ProjectExplorer::SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); + SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); } void SquishFileHandler::closeAllTestSuites() { closeAllInternal(); - ProjectExplorer::SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); + SessionManager::setValue(SK_OpenSuites, suitePathsAsStringList()); } void SquishFileHandler::deleteTestCase(const QString &suiteName, const QString &testCaseName) @@ -539,7 +541,7 @@ void SquishFileHandler::onSessionLoaded() // remove currently opened "silently" (without storing into session) closeAllInternal(); - const QVariant variant = ProjectExplorer::SessionManager::value(SK_OpenSuites); + const QVariant variant = SessionManager::value(SK_OpenSuites); const Utils::FilePaths suitePaths = Utils::transform(variant.toStringList(), &Utils::FilePath::fromString); From 001b3ab626fb279056db32b8d915ec8659c0b4c4 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 11:10:00 +0200 Subject: [PATCH 1264/1447] Utils: Remove now-unused Environment::findAllInPath Change-Id: I562309c292ab0c5ae317593e40e5105bbcf89bf8 Reviewed-by: Marcus Tillmanns --- src/libs/utils/environment.cpp | 19 ------------------- src/libs/utils/environment.h | 3 --- 2 files changed, 22 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 0a95587aef4..46972d13513 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -319,25 +319,6 @@ FilePath Environment::searchInPath(const QString &executable, return result; } -FilePaths Environment::findAllInPath(const QString &executable, - const FilePaths &additionalDirs, - const FilePathPredicate &func) const -{ - QSet result; - searchInDirectoriesHelper( - [&result](const FilePath &path) { - result.insert(path); - return IterationPolicy::Continue; - }, - *this, - executable, - additionalDirs, - func, - true); - - return result.values(); -} - FilePaths Environment::path() const { return pathListValue("PATH"); diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 843232878ba..63fe697bd6e 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -61,9 +61,6 @@ public: FilePath searchInPath(const QString &executable, const FilePaths &additionalDirs = FilePaths(), const FilePathPredicate &func = {}) const; - FilePaths findAllInPath(const QString &executable, - const FilePaths &additionalDirs = {}, - const FilePathPredicate &func = {}) const; FilePaths path() const; FilePaths pathListValue(const QString &varName) const; From 38c64e5419d1e6454fbfcc41ed316b2e15d4b640 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 25 May 2023 12:07:34 +0200 Subject: [PATCH 1265/1447] Utils: Fix opening external Terminal Change-Id: Id5c650f6f40f4ab8233360e20673dd9f0277c09d Reviewed-by: hjk --- src/libs/utils/externalterminalprocessimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/externalterminalprocessimpl.cpp b/src/libs/utils/externalterminalprocessimpl.cpp index 366554884d4..efdbc9aca31 100644 --- a/src/libs/utils/externalterminalprocessimpl.cpp +++ b/src/libs/utils/externalterminalprocessimpl.cpp @@ -69,7 +69,7 @@ expected_str ProcessStubCreator::startStubProcess(const ProcessSetupData process->setCreateConsoleOnWindows(true); process->setProcessMode(ProcessMode::Writer); } else { - QString extraArgsFromOptions = detached ? terminal.openArgs : terminal.executeArgs; + QString extraArgsFromOptions = terminal.executeArgs; CommandLine cmdLine = {terminal.command, {}}; if (!extraArgsFromOptions.isEmpty()) cmdLine.addArgs(extraArgsFromOptions, CommandLine::Raw); From 3541b692f56a8510761c036e409d66f46f8a1540 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 23 May 2023 11:02:15 +0200 Subject: [PATCH 1266/1447] LanguageClient: track clients scheduled for deletion So report an async shutdown if we have clients scheduled for deletion and wait until all clients have been fully deleted. Change-Id: I40d35d3429003ab2a5c68cb81486c3e16b5f6f63 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- .../languageclient/languageclientmanager.cpp | 23 ++++++++++++++++++- .../languageclient/languageclientmanager.h | 4 ++++ .../languageclient/languageclientplugin.cpp | 4 ++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 482f4e8e39e..50a38071892 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -189,7 +189,7 @@ void LanguageClientManager::clientFinished(Client *client) } } deleteClient(client); - if (PluginManager::isShuttingDown() && managerInstance->m_clients.isEmpty()) + if (isShutdownFinished()) emit managerInstance->shutdownFinished(); } @@ -243,6 +243,7 @@ void LanguageClientManager::deleteClient(Client *client) // that will not handle the delete later event. Use invokeMethod with Qt::QueuedConnection // instead. QMetaObject::invokeMethod(client, [client] {delete client;}, Qt::QueuedConnection); + managerInstance->trackClientDeletion(client); if (!PluginManager::isShuttingDown()) emit instance()->clientRemoved(client); @@ -608,4 +609,24 @@ void LanguageClientManager::projectAdded(ProjectExplorer::Project *project) client->projectOpened(project); } +void LanguageClientManager::trackClientDeletion(Client *client) +{ + QTC_ASSERT(!m_scheduledForDeletion.contains(client->id()), return); + m_scheduledForDeletion.insert(client->id()); + connect(client, &QObject::destroyed, [this, id = client->id()](){ + m_scheduledForDeletion.remove(id); + if (isShutdownFinished()) + emit shutdownFinished(); + }); +} + +bool LanguageClientManager::isShutdownFinished() +{ + if (!PluginManager::isShuttingDown()) + return false; + QTC_ASSERT(managerInstance, return true); + return managerInstance->m_clients.isEmpty() + && managerInstance->m_scheduledForDeletion.isEmpty(); +} + } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index e29d87a0f23..0a38b3d3872 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -48,6 +48,7 @@ public: static void deleteClient(Client *client); static void shutdown(); + static bool isShutdownFinished(); static LanguageClientManager *instance(); @@ -96,6 +97,8 @@ private: void updateProject(ProjectExplorer::Project *project); void projectAdded(ProjectExplorer::Project *project); + void trackClientDeletion(Client *client); + QList reachableClients(); QList m_clients; @@ -105,6 +108,7 @@ private: QHash> m_clientForDocument; std::unique_ptr d; LspInspector m_inspector; + QSet m_scheduledForDeletion; }; template bool LanguageClientManager::hasClients() diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index 7332f03e2b1..b6b411f8cb4 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -60,12 +60,12 @@ void LanguageClientPlugin::extensionsInitialized() ExtensionSystem::IPlugin::ShutdownFlag LanguageClientPlugin::aboutToShutdown() { LanguageClientManager::shutdown(); - if (LanguageClientManager::clients().isEmpty()) + if (LanguageClientManager::isShutdownFinished()) return ExtensionSystem::IPlugin::SynchronousShutdown; QTC_ASSERT(LanguageClientManager::instance(), return ExtensionSystem::IPlugin::SynchronousShutdown); connect(LanguageClientManager::instance(), &LanguageClientManager::shutdownFinished, - this, &ExtensionSystem::IPlugin::asynchronousShutdownFinished, Qt::QueuedConnection); + this, &ExtensionSystem::IPlugin::asynchronousShutdownFinished); return ExtensionSystem::IPlugin::AsynchronousShutdown; } From 320064f4310bcb826931deeff9ed4d5f87a72c2b Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 24 May 2023 10:49:48 +0200 Subject: [PATCH 1267/1447] Utils: Allow more finegrained subaspect ownership in AspectContainer Currently this luckily conincides with the register/addAspect schism but that's not necessarily true in the future. Change-Id: I05a59d74182dbdf81193ebd790d6f9bab2d30439 Reviewed-by: Alessandro Portale --- src/libs/utils/aspects.cpp | 16 ++++++---------- src/libs/utils/aspects.h | 5 ++--- src/plugins/projectexplorer/copystep.cpp | 2 -- .../projectexplorer/projectconfiguration.cpp | 2 -- src/plugins/python/pysidebuildconfiguration.cpp | 2 -- 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 461a3915347..0e7050a7e0a 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2399,9 +2399,9 @@ namespace Internal { class AspectContainerPrivate { public: - QList m_items; // Not owned + QList m_items; // Both owned and non-owned. + QList m_ownedItems; // Owned only. bool m_autoApply = true; - bool m_ownsSubAspects = false; QStringList m_settingsGroup; }; @@ -2416,17 +2416,18 @@ AspectContainer::AspectContainer(QObject *parent) */ AspectContainer::~AspectContainer() { - if (d->m_ownsSubAspects) - qDeleteAll(d->m_items); + qDeleteAll(d->m_ownedItems); } /*! \internal */ -void AspectContainer::registerAspect(BaseAspect *aspect) +void AspectContainer::registerAspect(BaseAspect *aspect, bool takeOwnership) { aspect->setAutoApply(d->m_autoApply); d->m_items.append(aspect); + if (takeOwnership) + d->m_ownedItems.append(aspect); } void AspectContainer::registerAspects(const AspectContainer &aspects) @@ -2547,11 +2548,6 @@ void AspectContainer::setAutoApply(bool on) aspect->setAutoApply(on); } -void AspectContainer::setOwnsSubAspects(bool on) -{ - d->m_ownsSubAspects = on; -} - bool AspectContainer::isDirty() const { for (BaseAspect *aspect : std::as_const(d->m_items)) { diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 2cae52a1048..35e8a62b8f7 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -651,14 +651,14 @@ public: AspectContainer(const AspectContainer &) = delete; AspectContainer &operator=(const AspectContainer &) = delete; - void registerAspect(BaseAspect *aspect); + void registerAspect(BaseAspect *aspect, bool takeOwnership = false); void registerAspects(const AspectContainer &aspects); template Aspect *addAspect(Args && ...args) { auto aspect = new Aspect(args...); - registerAspect(aspect); + registerAspect(aspect, true); return aspect; } @@ -679,7 +679,6 @@ public: bool equals(const AspectContainer &other) const; void copyFrom(const AspectContainer &other); void setAutoApply(bool on); - void setOwnsSubAspects(bool on); bool isDirty() const; template T *aspect() const diff --git a/src/plugins/projectexplorer/copystep.cpp b/src/plugins/projectexplorer/copystep.cpp index 14f01ae425c..db3b16098e5 100644 --- a/src/plugins/projectexplorer/copystep.cpp +++ b/src/plugins/projectexplorer/copystep.cpp @@ -21,8 +21,6 @@ public: CopyStepBase(BuildStepList *bsl, Id id) : BuildStep(bsl, id) { - setOwnsSubAspects(false); - m_sourceAspect.setSettingsKey(SOURCE_KEY); m_sourceAspect.setLabelText(Tr::tr("Source:")); diff --git a/src/plugins/projectexplorer/projectconfiguration.cpp b/src/plugins/projectexplorer/projectconfiguration.cpp index 5d23d65c8b8..841be317312 100644 --- a/src/plugins/projectexplorer/projectconfiguration.cpp +++ b/src/plugins/projectexplorer/projectconfiguration.cpp @@ -22,8 +22,6 @@ ProjectConfiguration::ProjectConfiguration(QObject *parent, Utils::Id id) : AspectContainer(parent) , m_id(id) { - setOwnsSubAspects(true); - QTC_CHECK(parent); QTC_CHECK(id.isValid()); setObjectName(id.toString()); diff --git a/src/plugins/python/pysidebuildconfiguration.cpp b/src/plugins/python/pysidebuildconfiguration.cpp index 7163dc7b6a6..5f6f7dadea5 100644 --- a/src/plugins/python/pysidebuildconfiguration.cpp +++ b/src/plugins/python/pysidebuildconfiguration.cpp @@ -34,8 +34,6 @@ PySideBuildStepFactory::PySideBuildStepFactory() PySideBuildStep::PySideBuildStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id) { - setOwnsSubAspects(false); - m_pysideProject.setSettingsKey("Python.PySideProjectTool"); m_pysideProject.setLabelText(Tr::tr("PySide project tool:")); m_pysideProject.setToolTip(Tr::tr("Enter location of PySide project tool.")); From 301017ab9cad66b037dfbc15ef26b21c0027f0d9 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 10:15:25 +0200 Subject: [PATCH 1268/1447] Nim: Use FilePath::searchInPath to find executable Locally the same, potentially works remotely. Change-Id: Ibdd6f545c089868549f86300d00116896c4f8f94 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/nim/project/nimbuildsystem.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/nim/project/nimbuildsystem.cpp b/src/plugins/nim/project/nimbuildsystem.cpp index 97661644dcd..00d68034eb2 100644 --- a/src/plugins/nim/project/nimbuildsystem.cpp +++ b/src/plugins/nim/project/nimbuildsystem.cpp @@ -14,8 +14,6 @@ #include #include -#include - using namespace ProjectExplorer; using namespace Utils; @@ -180,10 +178,10 @@ FilePath nimPathFromKit(Kit *kit) FilePath nimblePathFromKit(Kit *kit) { // There's no extra setting for "nimble", derive it from the "nim" path. - const QString nimbleFromPath = QStandardPaths::findExecutable("nimble"); + const FilePath nimbleFromPath = FilePath("nimble").searchInPath(); const FilePath nimPath = nimPathFromKit(kit); const FilePath nimbleFromKit = nimPath.pathAppended("nimble").withExecutableSuffix(); - return nimbleFromKit.exists() ? nimbleFromKit.canonicalPath() : FilePath::fromString(nimbleFromPath); + return nimbleFromKit.exists() ? nimbleFromKit.canonicalPath() : nimbleFromPath; } bool NimBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const From e037bd20044ce3d9c90c4b9af43feb59dfcc2449 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 24 May 2023 16:40:40 +0200 Subject: [PATCH 1269/1447] Doc: Fix qdoc warnings in FilePath docs Also fix some misc style issues, such as missing punctuation. Change-Id: If5a9243eb9ce57c87096f9f0e184c8a802df54aa Reviewed-by: Eike Ziller --- src/libs/utils/filepath.cpp | 86 ++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 31d24f14b00..ad871413a22 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -119,7 +119,7 @@ inline bool isWindowsDriveLetter(QChar ch); Converts the FilePath to the slash convention of the associated OS and adds the scheme and host as a " on " suffix. - This is useful for static user-facing output in he GUI + This is useful for static user-facing output in the GUI. \li FilePath::fromVariant(), FilePath::toVariant() @@ -157,7 +157,7 @@ FilePath::FilePath() } /*! - Constructs a FilePath from \a info + Constructs a FilePath from \a info. */ FilePath FilePath::fromFileInfo(const QFileInfo &info) { @@ -172,6 +172,11 @@ QFileInfo FilePath::toFileInfo() const return QFileInfo(toFSPathString()); } +/*! + Constructs a FilePath from \a variant. + + \sa toVariant() +*/ FilePath FilePath::fromVariant(const QVariant &variant) { return fromSettings(variant); // FIXME: Use variant.value() @@ -281,7 +286,7 @@ QUrl FilePath::toUrl() const } /*! - returns a QString to display to the user, including the device prefix + Returns a QString to display to the user, including the device prefix. Converts the separators to the native format of the system this path belongs to. @@ -491,6 +496,9 @@ bool FilePath::ensureExistingFile() const return fileAccess()->ensureExistingFile(*this); } +/*! + Returns a bool indicating whether this is an executable file. +*/ bool FilePath::isExecutableFile() const { return fileAccess()->isExecutableFile(*this); @@ -498,10 +506,11 @@ bool FilePath::isExecutableFile() const /*! Returns a bool indicating on whether a process with this FilePath's - .nativePath() is likely to start. + native path is likely to start. - This is equivalent to \c isExecutableFile() in general. - On Windows, it will check appending various suffixes, too. + This is equivalent to \l isExecutableFile() in general. + On Windows, it might append various suffixes depending on + \a matchScope. */ std::optional FilePath::refersToExecutableFile(MatchScope matchScope) const { @@ -578,7 +587,7 @@ bool FilePath::hasHardLinks() const Returns true if the directory could be created, false if not, even if it existed before. - \sa ensureWriteableDir() + \sa ensureWritableDir() */ bool FilePath::createDir() const { @@ -616,9 +625,7 @@ FilePaths FilePath::dirEntries(QDir::Filters filters) const } /*! - This runs \a callBack on each directory entry matching all \a filters and - either of the specified \a nameFilters. - An empty \nameFilters list matches every name. + Runs \a callBack on each directory entry matching the \a filter. */ void FilePath::iterateDirectory(const IterateDirCallback &callBack, const FileFilter &filter) const @@ -966,12 +973,13 @@ QString doCleanPath(const QString &input_) return input.left(prefixLen) + path; } -/*! Find the parent directory of a given directory. +/*! + Finds the parent directory of the file path. - Returns an empty FilePath if the current directory is already + Returns an empty file path if the file path is already a root level directory. - Returns \a FilePath with the last segment removed. + Returns a file path with the last segment removed. */ FilePath FilePath::parentDir() const { @@ -1039,6 +1047,15 @@ FilePath FilePath::normalizedPathName() const return result; } +/*! + Converts the file path to the slash convention of the associated + OS and adds the scheme and host as a " on " suffix. + + This is useful for static user-facing output in the GUI. + + If \a args is not empty, it is added to the output after the file path: + " on ". +*/ QString FilePath::displayName(const QString &args) const { QString deviceName; @@ -1201,10 +1218,10 @@ bool FilePath::hasFileAccess() const } /*! - Constructs a FilePath from \a filePath. The \a defaultExtension is appended - to \a filePath if that does not have an extension already. + Constructs a FilePath from \a filepath. The \a defaultExtension is appended + to \a filepath if that does not have an extension already. - \a filePath is not checked for validity. + \a filepath is not checked for validity. */ FilePath FilePath::fromStringWithExtension(const QString &filepath, const QString &defaultExtension) { @@ -1225,7 +1242,7 @@ FilePath FilePath::fromStringWithExtension(const QString &filepath, const QStrin /*! Constructs a FilePath from \a filePath - The path \a filePath is cleaned and ~ replaces by the home path. + The path \a filePath is cleaned, and ~ is replaced by the home path. */ FilePath FilePath::fromUserInput(const QString &filePath) { @@ -1236,9 +1253,10 @@ FilePath FilePath::fromUserInput(const QString &filePath) } /*! - Constructs a FilePath from \a filePath, which is encoded as UTF-8. + Constructs a FilePath from \a filename with \a filenameSize, which is + encoded as UTF-8. - \a filePath is not checked for validity. + \a filename is not checked for validity. */ FilePath FilePath::fromUtf8(const char *filename, int filenameSize) { @@ -1259,6 +1277,12 @@ QVariant FilePath::toSettings() const return toString(); } +/*! + Returns the FilePath as a variant. + + To be used for type-agnostic internal interfaces like storage in + QAbstractItemModels. +*/ QVariant FilePath::toVariant() const { // FIXME: Use qVariantFromValue @@ -1391,7 +1415,7 @@ FilePath FilePath::relativePathFrom(const FilePath &anchor) const } /*! - Returns the relativePath of \a absolutePath to given \a absoluteAnchorPath. + Returns the relative path of \a absolutePath to given \a absoluteAnchorPath. Both paths must be an absolute path to a directory. Example usage: @@ -1402,7 +1426,7 @@ FilePath FilePath::relativePathFrom(const FilePath &anchor) const The debug output will be "../b/ar". - \see FilePath::relativePath + \see FilePath::isRelativePath(), FilePath::relativePathFrom(), FilePath::relativeChildPath() */ QString FilePath::calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath) { @@ -1488,8 +1512,9 @@ FilePath FilePath::withNewPath(const QString &newPath) const } /*! - Search for a binary corresponding to this object in the PATH of - the device implied by this object's scheme and host. + Search for a binary corresponding to this object on each directory entry + specified by \a dirs matching the \a filter with the \a matchScope of the + file path. Example usage: \code @@ -1794,7 +1819,7 @@ qint64 FilePath::bytesAvailable() const \c true if one of them is newer than \a timeStamp. If this is a single file, \c true will be returned if the file is newer than \a timeStamp. - Returns whether at least one file in \a filePath has a newer date than + Returns whether at least one file in the file path has a newer date than \a timeStamp. */ bool FilePath::isNewerThan(const QDateTime &timeStamp) const @@ -1874,12 +1899,13 @@ FilePath FilePath::resolveSymlinks() const } /*! -* \brief Recursively resolves possibly present symlinks in this file name. -* On Windows, also resolves SUBST and re-mounted NTFS drives. -* Unlike QFileInfo::canonicalFilePath(), this function will not return an empty -* string if path doesn't exist. -* -* Returns the canonical path. + Recursively resolves possibly present symlinks in this file name. + + On Windows, also resolves SUBST and re-mounted NTFS drives. + Unlike QFileInfo::canonicalFilePath(), this function will not return an empty + string if path doesn't exist. + + Returns the canonical path. */ FilePath FilePath::canonicalPath() const { From 07764bdf1517cce3e484ac4e7371ff2aee060803 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 May 2023 13:53:44 +0200 Subject: [PATCH 1270/1447] Doc: Remove broken \sa commands from CheckableMessageBox docs - The referred functions are not documented - Use \uicontrol instead of the deprecated \gui macro Change-Id: I993d62923657cd018caa87827dc89c6aa4b6d092 Reviewed-by: Eike Ziller --- src/libs/utils/checkablemessagebox.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp index 3c57a736670..d3ede7d4e7e 100644 --- a/src/libs/utils/checkablemessagebox.cpp +++ b/src/libs/utils/checkablemessagebox.cpp @@ -21,8 +21,8 @@ \inmodule QtCreator \brief The CheckableMessageBox class implements a message box suitable for - questions with a - "Do not ask me again" checkbox. + questions with a \uicontrol {Do not ask again} or \uicontrol {Do not show again} + checkbox. Emulates the QMessageBox API with static conveniences. The message label can open external URLs. @@ -180,8 +180,7 @@ bool CheckableMessageBox::hasSuppressedQuestions() } /*! - Returns the standard \gui {Do not ask again} check box text. - \sa doNotAskAgainQuestion() + Returns the standard \uicontrol {Do not ask again} check box text. */ QString CheckableMessageBox::msgDoNotAskAgain() { @@ -189,8 +188,7 @@ QString CheckableMessageBox::msgDoNotAskAgain() } /*! - Returns the standard \gui {Do not show again} check box text. - \sa doNotShowAgainInformation() + Returns the standard \uicontrol {Do not show again} check box text. */ QString CheckableMessageBox::msgDoNotShowAgain() { From c8f29b9e0148202ab1959466e14fa23411fd8214 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 24 May 2023 15:18:48 +0200 Subject: [PATCH 1271/1447] CppEditor: Add support for init statements in if conditions Fixes: QTCREATORBUG-29182 Change-Id: I9b7969da694b368236246123ad0028d8e754e903 Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.h | 2 ++ src/libs/3rdparty/cplusplus/ASTClone.cpp | 4 ++++ src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 10 ++++++++ src/libs/3rdparty/cplusplus/ASTVisit.cpp | 2 ++ src/libs/3rdparty/cplusplus/Bind.cpp | 4 ++++ src/libs/3rdparty/cplusplus/Parser.cpp | 27 +++++++++++++++++----- src/libs/3rdparty/cplusplus/Token.h | 1 + src/plugins/cppeditor/projectpart.cpp | 1 + tests/auto/cplusplus/cxx11/tst_cxx11.cpp | 23 ++++++++++++++++++ 9 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 0f40424464e..6a5da23306a 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -1779,6 +1779,8 @@ public: int if_token = 0; int constexpr_token = 0; int lparen_token = 0; + DeclarationAST *initDecl = nullptr; + StatementAST *initStmt = nullptr; ExpressionAST *condition = nullptr; int rparen_token = 0; StatementAST *statement = nullptr; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index e494ad71ac6..57617bb1180 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -785,6 +785,10 @@ IfStatementAST *IfStatementAST::clone(MemoryPool *pool) const ast->if_token = if_token; ast->constexpr_token = constexpr_token; ast->lparen_token = lparen_token; + if (initDecl) + ast->initDecl = initDecl->clone(pool); + if (initStmt) + ast->initStmt = initStmt->clone(pool); if (condition) ast->condition = condition->clone(pool); ast->rparen_token = rparen_token; diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index de6f6fc87c0..6f12efb8aca 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -1318,6 +1318,16 @@ bool ASTMatcher::match(IfStatementAST *node, IfStatementAST *pattern) pattern->lparen_token = node->lparen_token; + if (!pattern->initDecl) + pattern->initDecl = node->initDecl; + else if (!AST::match(node->initDecl, pattern->initDecl, this)) + return false; + + if (!pattern->initStmt) + pattern->initStmt = node->initStmt; + else if (!AST::match(node->initStmt, pattern->initStmt, this)) + return false; + if (! pattern->condition) pattern->condition = node->condition; else if (! AST::match(node->condition, pattern->condition, this)) diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 17941d8122f..7e8f75f2334 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -563,6 +563,8 @@ void ForStatementAST::accept0(ASTVisitor *visitor) void IfStatementAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { + accept(initDecl, visitor); + accept(initStmt, visitor); accept(condition, visitor); accept(statement, visitor); accept(else_statement, visitor); diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 202c36a51fa..e3d38a09a84 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -1528,6 +1528,10 @@ bool Bind::visit(IfStatementAST *ast) ast->symbol = block; Scope *previousScope = switchScope(block); + if (ast->initDecl) + this->declaration(ast->initDecl); + else if (ast->initStmt) + this->statement(ast->initStmt); /*ExpressionTy condition =*/ this->expression(ast->condition); this->statement(ast->statement); this->statement(ast->else_statement); diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index f8c737c0978..31e290d1ad6 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -3511,12 +3511,14 @@ bool Parser::parseExpressionStatement(StatementAST *&node) ExpressionAST *expression = nullptr; if (parseExpression(expression)) { - ExpressionStatementAST *ast = new (previousPool) ExpressionStatementAST; - if (expression) - ast->expression = expression->clone(previousPool); - match(T_SEMICOLON, &ast->semicolon_token); - node = ast; - parsed = true; + if (LA() == T_SEMICOLON) { + ExpressionStatementAST *ast = new (previousPool) ExpressionStatementAST; + ast->semicolon_token = consumeToken(); + if (expression) + ast->expression = expression->clone(previousPool); + node = ast; + parsed = true; + } } _inExpressionStatement = wasInExpressionStatement; @@ -4072,6 +4074,19 @@ bool Parser::parseIfStatement(StatementAST *&node) ast->constexpr_token = consumeToken(); } match(T_LPAREN, &ast->lparen_token); + + // C++17: init-statement + if (_languageFeatures.cxx17Enabled) { + const int savedCursor = cursor(); + const bool savedBlockErrors = _translationUnit->blockErrors(true); + if (!parseSimpleDeclaration(ast->initDecl)) { + rewind(savedCursor); + if (!parseExpressionStatement(ast->initStmt)) + rewind(savedCursor); + } + _translationUnit->blockErrors(savedBlockErrors); + } + parseCondition(ast->condition); match(T_RPAREN, &ast->rparen_token); if (! parseStatement(ast->statement)) diff --git a/src/libs/3rdparty/cplusplus/Token.h b/src/libs/3rdparty/cplusplus/Token.h index 204096893ad..f853d29c77f 100644 --- a/src/libs/3rdparty/cplusplus/Token.h +++ b/src/libs/3rdparty/cplusplus/Token.h @@ -455,6 +455,7 @@ struct LanguageFeatures unsigned int cxxEnabled : 1; unsigned int cxx11Enabled : 1; unsigned int cxx14Enabled : 1; + unsigned int cxx17Enabled : 1; unsigned int cxx20Enabled : 1; unsigned int objCEnabled : 1; unsigned int c99Enabled : 1; diff --git a/src/plugins/cppeditor/projectpart.cpp b/src/plugins/cppeditor/projectpart.cpp index 9cab9a6df2b..bea37f91ab4 100644 --- a/src/plugins/cppeditor/projectpart.cpp +++ b/src/plugins/cppeditor/projectpart.cpp @@ -163,6 +163,7 @@ CPlusPlus::LanguageFeatures ProjectPart::deriveLanguageFeatures() const CPlusPlus::LanguageFeatures features; features.cxx11Enabled = languageVersion >= Utils::LanguageVersion::CXX11; features.cxx14Enabled = languageVersion >= Utils::LanguageVersion::CXX14; + features.cxx17Enabled = languageVersion >= Utils::LanguageVersion::CXX17; features.cxx20Enabled = languageVersion >= Utils::LanguageVersion::CXX20; features.cxxEnabled = hasCxx; features.c99Enabled = languageVersion >= Utils::LanguageVersion::C99; diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index 958aa631c68..d27ba601467 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -150,6 +150,7 @@ private Q_SLOTS: void requiresClause(); void coroutines(); void genericLambdas(); + void ifStatementWithInitialization(); }; @@ -550,5 +551,27 @@ int main() QVERIFY(!hasErrors); } +void tst_cxx11::ifStatementWithInitialization() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx17Enabled = true; + + const QString source = R"( +int main() +{ + if (bool b = true; b) + b = false; +} +)"; + QByteArray errors; + Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile")); + processDocument(doc, source.toUtf8(), features, &errors); + const bool hasErrors = !errors.isEmpty(); + if (hasErrors) + qDebug().noquote() << errors; + QVERIFY(!hasErrors); +} + QTEST_APPLESS_MAIN(tst_cxx11) #include "tst_cxx11.moc" From f4b02be1fa5f4bedbfa8a8ec256cadc0cea5c8fb Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 May 2023 14:20:46 +0200 Subject: [PATCH 1272/1447] Doc: Remove links to the undocumented attachToWidget function Change-Id: Id828e5d1c889289261c628f3f2dbe42206b8b892 Reviewed-by: Eike Ziller --- src/libs/utils/progressindicator.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libs/utils/progressindicator.cpp b/src/libs/utils/progressindicator.cpp index 5e091917656..6e129cd58ed 100644 --- a/src/libs/utils/progressindicator.cpp +++ b/src/libs/utils/progressindicator.cpp @@ -185,11 +185,7 @@ void ProgressIndicatorPainter::nextAnimationStep() /*! Constructs a ProgressIndicator of the size \a size and with the parent \a parent. - Use \l attachToWidget to make the progress indicator automatically resize and center on the - parent widget. - - \sa attachToWidget - \sa setIndicatorSize + \sa setIndicatorSize() */ ProgressIndicator::ProgressIndicator(ProgressIndicatorSize size, QWidget *parent) : OverlayWidget(parent) From 50f277ef8ac4edb944f7a26d25f5fb7dcefd050d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 11 May 2023 11:42:01 +0200 Subject: [PATCH 1273/1447] German translation: Fossil MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Icc9ffe9f992619e5f4bd1a8689f11aa998f9c8ab Reviewed-by: Robert Löhning Reviewed-by: --- share/qtcreator/translations/qtcreator_de.ts | 260 ++++++++++--------- 1 file changed, 131 insertions(+), 129 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 65fec424e4a..f04a40e4d9a 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -11934,7 +11934,7 @@ Lokale Commits werden nicht zum Master-Branch gepusht, bis ein normaler Commit e
    Local filesystem: - Dateisystem: + Lokales Dateisystem: Options @@ -11942,7 +11942,7 @@ Lokale Commits werden nicht zum Master-Branch gepusht, bis ein normaler Commit e Remember specified location as default - Obige Einstellung als Vorgabe übernehmen + Angegebenen Ort als Vorgabe übernehmen Overwrite @@ -12124,7 +12124,7 @@ Lokale Pull-Operationen werden nicht auf den Master-Branch angewandt. Update... - Auf aktuellen Stand bringen... + Aktualisieren... Commit... @@ -12160,7 +12160,7 @@ Lokale Pull-Operationen werden nicht auf den Master-Branch angewandt. Unable to create a commit editor. - Es konnte kein Editor für den Commit angelegt werden. + Es konnte kein Commit-Editor angelegt werden. Commit changes for "%1". @@ -27079,497 +27079,499 @@ zu deaktivieren, deaktiviert auch die folgenden Plugins: QtC::Fossil Commit Editor - Commit-Editor + Commit-Editor Configure Repository - + Repository konfigurieren Existing user to become an author of changes made to the repository. - + Vorhandener Benutzer, der Autor der Änderungen im Repository werden soll. SSL/TLS Identity Key - + SSL/TLS Identity Key SSL/TLS client identity key to use if requested by the server. - + SSL/TLS Client Identity Key, der benutzt werden soll, wenn der Server diesen anfordert. Disable auto-sync - + Automatisches Synchronisieren (autosync) deaktivieren Disable automatic pull prior to commit or update and automatic push after commit or tag or branch creation. - + Deaktiviert die automatische Pull-Operation vor Commits oder Aktualisierungen und die automatische Push-Operation nach Commits oder dem Erstellen von Tags oder Branches. Repository User - + Benutzer des Repositorys User: - Nutzer: + Nutzer: Repository Settings - + Repository-Einstellungen SSL/TLS identity: - + SSL/TLS Identity: Ignore All Whitespace - + Alle Leerzeichen ignorieren Strip Trailing CR - + CR-Zeichen am Zeilenende entfernen Show Committers - + Committer anzeigen List Versions - + Versionen anzeigen Ancestors - + Vorfahren Descendants - + Nachfahren Unfiltered - Ungefiltert + Ungefiltert Lineage - + Abstammung Verbose - Ausführlich + Ausführlich Show files changed in each revision - Geänderte Dateien jeder Revision anzeigen + Geänderte Dateien jeder Revision anzeigen All Items - + Alle Elemente File Commits - + Datei-Commits Technical Notes - + Technische Anmerkungen (technotes) Tags - Tags + Tags Tickets - + Tickets Wiki Commits - + Wiki-Commits Item Types - + Element-Typen Private - + Privat Create a private check-in that is never synced. Children of private check-ins are automatically private. Private check-ins are not pushed to the remote repository by default. - + Erstelle einen privaten Check-In, der niemals synchronisiert wird. +Kinder von privaten Check-Ins sind automatisch privat. +Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht. Tag names to apply; comma-separated. - + Kommaseparierte Liste von Tag-Namen, die angewendet werden sollen. Current Information - + Aktuelle Informationen Local root: - + Lokale Root: Branch: - Branch: + Branch: Tags: - Schlüsselworte: + Tags: Commit Information - Informationen zu Commit + Informationen zum Commit New branch: - + Neuer Branch: Author: - Autor: + Autor: Message check failed. - + Die Überprüfung der Beschreibung schlug fehl. &Annotate %1 - + &Annotation für %1 Annotate &Parent Revision %1 - + Annotation der über&geordneten Revision %1 &Fossil - + &Fossil Annotate Current File - Annotation für Datei + Annotation für Datei Annotate "%1" - Annotation für "%1" + Annotation für "%1" Diff Current File - + Diff für aktuelle Datei Diff "%1" - Diff für "%1" + Diff für "%1" Meta+I,Meta+D - + Meta+I,Meta+D ALT+I,Alt+D - + ALT+I,Alt+D Timeline Current File - + Zeitleiste für aktuelle Datei Timeline "%1" - + Zeitleiste für "%1" Meta+I,Meta+L - + Meta+I,Meta+L ALT+I,Alt+L - + ALT+I,Alt+L Status Current File - Status der Datei + Status der aktuellen Datei Status "%1" - Status von "%1" + Status von "%1" Meta+I,Meta+S - + Meta+I,Meta+S ALT+I,Alt+S - + ALT+I,Alt+S Add Current File - + Aktuelle Datei hinzufügen Add "%1" - "%1" hinzufügen + "%1" hinzufügen Delete Current File... - + Aktuelle Datei löschen... Delete "%1"... - Lösche "%1"... + Lösche "%1"... Revert Current File... - Änderungen der Datei rückgängig machen... + Änderungen der aktuellen Datei rückgängig machen... Revert "%1"... - Änderungen in "%1" rückgängig machen... + Änderungen in "%1" rückgängig machen... Diff - Diff + Diff Timeline - + Zeitleiste Meta+I,Meta+T - + Meta+I,Meta+T ALT+I,Alt+T - + ALT+I,Alt+T Revert... - Rückgängig machen... + Rückgängig machen... Status - Status + Status Revert - Rückgängig machen + Rückgängig machen Pull... - Pull... + Pull... Push... - Push... + Push... Update... - Auf aktuellen Stand bringen... + Aktualisieren... Meta+I,Meta+U - + Meta+I,Meta+U ALT+I,Alt+U - + ALT+I,Alt+U Commit... - Commit... + Commit... Meta+I,Meta+C - + Meta+I,Meta+C ALT+I,Alt+C - + ALT+I,Alt+C Settings ... - + Einstellungen... Create Repository... - Repository erzeugen... + Repository erzeugen... Remote repository is not defined. - + Es ist kein entferntes Repository definiert. Update - Aktualisieren + Aktualisieren There are no changes to commit. - Es sind keine ausstehenden Änderungen vorhanden. + Es sind keine ausstehenden Änderungen vorhanden. Unable to create an editor for the commit. - Es konnte kein Editor für den Commit angelegt werden. + Es konnte kein Editor für den Commit angelegt werden. Unable to create a commit editor. - Es konnte kein Editor für den Commit angelegt werden. + Es konnte kein Commit-Editor angelegt werden. Commit changes for "%1". - Commit der Änderungen in "%1". + Commit der Änderungen in "%1". Choose Checkout Directory - + Verzeichnis für Checkout wählen The directory "%1" is already managed by a version control system (%2). Would you like to specify another directory? - Das Verzeichnis "%1" steht bereits unter Verwaltung eines Versionskontrollsystems (%2). Möchten Sie einen anderes Verzeichnis angeben? + Das Verzeichnis "%1" steht bereits unter Verwaltung eines Versionskontrollsystems (%2). Möchten Sie ein anderes Verzeichnis angeben? Repository already under version control - Repository bereits unter Versionskontrolle + Repository bereits unter Versionskontrolle Repository Created - Repository erstellt + Repository erstellt A version control repository has been created in %1. - Ein Repository für Versionskontrolle wurde im Verzeichnis %1 erstellt. + Ein Repository für Versionskontrolle wurde im Verzeichnis %1 erstellt. Repository Creation Failed - Fehlschlag bei Erstellung des Repositorys + Fehlschlag bei Erstellung des Repositorys A version control repository could not be created in %1. - Im Verzeichnis %1 konnte kein Repository für die Versionskontrolle erstellt werden. + Im Verzeichnis %1 konnte kein Repository für die Versionskontrolle erstellt werden. Fossil - + Fossil Specify a revision other than the default? - Möchten Sie eine Revision angeben? + Möchten Sie eine Revision angeben? Checkout revision, can also be a branch or a tag name. - + Checkout der Revision erstellen, kann auch der Name eines Branches oder Tags sein. Revision - Revision + Revision Fossil Command - + Fossil-Kommando Command: - + Kommando: Fossil Repositories - + Fossil-Repositorys Default path: - + Vorgabeverzeichnis: Directory to store local repositories by default. - + Vorgabeverzeichnis für lokale Repositorys. Default user: - + Vorgabe-Benutzer: Log width: - + Breite des Logs: The width of log entry line (>20). Choose 0 to see a single line per entry. - + Die Breite der Zeilen in Logs (>20). Wählen Sie 0, um eine einzelne Zeile pro Eintrag anzuzeigen. Timeout: - Zeitlimit: + Zeitlimit: s - s + s Log count: - Log-Anzeige beschränken auf: + Log-Anzeige beschränken auf: The number of recent commit log entries to show. Choose 0 to see all entries. - + Zahl der anzuzeigenden Logeinträge, 0 für unbegrenzt. Configuration - Konfiguration + Konfiguration Local Repositories - + Lokale Repositorys User - Nutzer + Nutzer Miscellaneous - Sonstige Einstellungen + Sonstige Einstellungen Pull Source - + Quelle für Pull-Operation Push Destination - + Ziel für Push-Operation Default location - Vorgabe + Vorgabe Local filesystem: - Dateisystem: + Lokales Dateisystem: Specify URL: - URL: + URL: For example: https://[user[:pass]@]host[:port]/[path] - + Zum Beispiel: https://[user[:pass]@]host[:port]/[path] Remember specified location as default - Obige Einstellung als Vorgabe übernehmen + Angegebenen Ort als Vorgabe übernehmen Include private branches - + Private Branches einbeziehen Allow transfer of private branches. - + Übertragen von privaten Branches erlauben. Remote Location - + Entfernter Ort Options - Einstellungen + Einstellungen
    @@ -32653,7 +32655,7 @@ Beispiel: *.cpp%1*.h Local filesystem: - Dateisystem: + Lokales Dateisystem: Default Location @@ -32813,7 +32815,7 @@ Beispiel: *.cpp%1*.h Update... - Auf aktuellen Stand bringen... + Aktualisieren... Import... From 2662105f41fac90bd7a8bdb76607488675607b08 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 10 May 2023 12:33:05 +0200 Subject: [PATCH 1274/1447] Perforce: Use info label Makes it readable for different themes. Change-Id: I26dd08e3bf5840437165811154f8f97ad4296371 Reviewed-by: Alessandro Portale Reviewed-by: Christian Stenger --- src/plugins/perforce/perforcesettings.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp index e62fdade894..ead7b6b07b3 100644 --- a/src/plugins/perforce/perforcesettings.cpp +++ b/src/plugins/perforce/perforcesettings.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -227,7 +228,9 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) PerforceSettings &s = *settings; using namespace Layouting; - auto errorLabel = new QLabel; + auto errorLabel = new InfoLabel({}, InfoLabel::None); + errorLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + errorLabel->setFilled(true); auto testButton = new QPushButton(Tr::tr("Test")); QObject::connect(testButton, &QPushButton::clicked, widget, [settings, errorLabel, testButton] { testButton->setEnabled(false); @@ -235,21 +238,21 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) checker->setUseOverideCursor(true); QObject::connect(checker, &PerforceChecker::failed, errorLabel, [errorLabel, testButton, checker](const QString &t) { - errorLabel->setStyleSheet("background-color: red"); + errorLabel->setType(InfoLabel::Error); errorLabel->setText(t); testButton->setEnabled(true); checker->deleteLater(); }); QObject::connect(checker, &PerforceChecker::succeeded, errorLabel, [errorLabel, testButton, checker](const FilePath &repo) { - errorLabel->setStyleSheet({}); + errorLabel->setType(InfoLabel::Ok); errorLabel->setText(Tr::tr("Test succeeded (%1).") .arg(repo.toUserOutput())); testButton->setEnabled(true); checker->deleteLater(); }); - errorLabel->setStyleSheet(QString()); + errorLabel->setType(InfoLabel::Information); errorLabel->setText(Tr::tr("Testing...")); const FilePath p4Bin = FilePath::fromUserInput( From 2cd71a18fc842f2a9749adbc9d1973987dc1ffc5 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 24 May 2023 16:21:17 +0200 Subject: [PATCH 1275/1447] CppEditor: Fix raw string highlighting with embedded empty lines We missed an early return in highlightBlock(). Task-number: QTCREATORBUG-29200 Change-Id: I3f32c2948ff778a9b558850235058537fcd48fd1 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Fabian Kosmale Reviewed-by: David Schulz --- src/plugins/cppeditor/cpphighlighter.cpp | 1 + src/plugins/cppeditor/testcases/highlightingtestcase.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 1f83b317ada..90bea637095 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -76,6 +76,7 @@ void CppHighlighter::highlightBlock(const QString &text) setFormat(0, text.length(), formatForCategory(C_VISUAL_WHITESPACE)); } TextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent); + TextDocumentLayout::setExpectedRawStringSuffix(currentBlock(), inheritedRawStringSuffix); return; } diff --git a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp index 20fa2526467..36e3a4b17bb 100644 --- a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp +++ b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp @@ -1,7 +1,7 @@ auto func() { return R"(foo - foobar + R"notaprefix!( barfoobar)" R"(second)" /* comment */ R"(third)"; } From f415d4c786e8e7f1b0964e234be44728d78f1efd Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 May 2023 14:17:31 +0200 Subject: [PATCH 1276/1447] Doc: Add \a commands to FileSystemWatcher and stringutils docs Change-Id: Ie76e2d7387df630a512413bd214461979ad2ec91 Reviewed-by: Eike Ziller --- src/libs/utils/filesystemwatcher.cpp | 4 ++-- src/libs/utils/stringutils.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/filesystemwatcher.cpp b/src/libs/utils/filesystemwatcher.cpp index 9a4d7b56930..155f83fba03 100644 --- a/src/libs/utils/filesystemwatcher.cpp +++ b/src/libs/utils/filesystemwatcher.cpp @@ -188,7 +188,7 @@ void FileSystemWatcherPrivate::autoReloadPostponed(bool postponed) } /*! - Adds directories to watcher 0. + Creates a file system watcher with the ID 0 and the owner \a parent. */ FileSystemWatcher::FileSystemWatcher(QObject *parent) : @@ -198,7 +198,7 @@ FileSystemWatcher::FileSystemWatcher(QObject *parent) : } /*! - Adds directories to a watcher with the specified \a id. + Creates a file system watcher with the ID \a id and the owner \a parent. */ FileSystemWatcher::FileSystemWatcher(int id, QObject *parent) : diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index f8602169613..a33a08e3d99 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -458,7 +458,7 @@ QTCREATOR_UTILS_EXPORT QString normalizeNewlines(const QString &text) /*! Joins all the not empty string list's \a strings into a single string with each element - separated by the given separator (which can be an empty string). + separated by the given \a separator (which can be an empty string). */ QTCREATOR_UTILS_EXPORT QString joinStrings(const QStringList &strings, QChar separator) { From eed303450d96471f258254d71eee070f2c8caf4b Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 25 May 2023 17:28:19 +0200 Subject: [PATCH 1277/1447] Sqlite: Fix compilation with QTC_STATIC_BUILD Change-Id: Ie94439d190245e821c17de73075397695d1af413 Reviewed-by: Marco Bubke --- src/libs/sqlite/sqliteexception.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/sqlite/sqliteexception.h b/src/libs/sqlite/sqliteexception.h index d030f652809..f0cadfc7483 100644 --- a/src/libs/sqlite/sqliteexception.h +++ b/src/libs/sqlite/sqliteexception.h @@ -3,6 +3,7 @@ #pragma once +#include "sqlite3_fwd.h" #include "sqliteglobal.h" #include @@ -10,10 +11,6 @@ #include #include -extern "C" { -struct sqlite3; -} - namespace Sqlite { class SQLITE_EXPORT Exception : public std::exception From c777de8fdba1a2592da5f81ed4c84a6687310371 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 25 May 2023 17:01:27 +0200 Subject: [PATCH 1278/1447] QmlDesigner: Fix configure with QTC_STATIC_BUILD get_target_property fails when Qt5::Designer is not available. Change-Id: I2d9aa6902e0e03a44ca91068bed5e3f3493a86c8 Reviewed-by: Marco Bubke --- src/plugins/qmldesigner/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index fc160cdf528..8cffad60f1e 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -521,10 +521,6 @@ function(get_and_add_as_subdirectory name repository git_tag build_dir source_di endfunction() if (QTC_STATIC_BUILD AND TARGET QmlDesigner) - get_target_property(_designerType Qt5::Designer TYPE) - if (${_designerType} STREQUAL "STATIC_LIBRARY") - extend_qtc_target(QmlDesigner PUBLIC_DEFINES QT_DESIGNER_STATIC) - endif() get_target_property(_designerType Qt::Designer TYPE) if (${_designerType} STREQUAL "STATIC_LIBRARY") extend_qtc_target(QmlDesigner PUBLIC_DEFINES QT_DESIGNER_STATIC) @@ -532,7 +528,6 @@ if (QTC_STATIC_BUILD AND TARGET QmlDesigner) extend_qtc_target(QmlDesigner PUBLIC_DEPENDS TextEditor) endif() - extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components PUBLIC_INCLUDES components From 0d22680c7c29cbcc6338cfd7d6d12587f0e30959 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 17:35:36 +0200 Subject: [PATCH 1279/1447] Incredibuild: Simpler plugin setup Change-Id: Ie838fb800b0b0f412e1b44989eed47e70c144747 Reviewed-by: Alessandro Portale --- src/plugins/incredibuild/CMakeLists.txt | 3 +- src/plugins/incredibuild/incredibuild.qbs | 4 +-- .../incredibuild/incredibuildplugin.cpp | 28 +++++++++---------- src/plugins/incredibuild/incredibuildplugin.h | 25 ----------------- 4 files changed, 16 insertions(+), 44 deletions(-) delete mode 100644 src/plugins/incredibuild/incredibuildplugin.h diff --git a/src/plugins/incredibuild/CMakeLists.txt b/src/plugins/incredibuild/CMakeLists.txt index 81e0273b95d..f212046a15c 100644 --- a/src/plugins/incredibuild/CMakeLists.txt +++ b/src/plugins/incredibuild/CMakeLists.txt @@ -13,10 +13,9 @@ add_qtc_plugin(IncrediBuild ibconsolebuildstep.cpp ibconsolebuildstep.h incredibuild_global.h - incredibuildtr.h incredibuildconstants.h incredibuildplugin.cpp - incredibuildplugin.h + incredibuildtr.h makecommandbuilder.cpp makecommandbuilder.h ) diff --git a/src/plugins/incredibuild/incredibuild.qbs b/src/plugins/incredibuild/incredibuild.qbs index e08d548691f..9c315ae8c08 100644 --- a/src/plugins/incredibuild/incredibuild.qbs +++ b/src/plugins/incredibuild/incredibuild.qbs @@ -19,10 +19,10 @@ QtcPlugin { "commandbuilderaspect.h", "ibconsolebuildstep.cpp", "ibconsolebuildstep.h", - "incredibuild_global.h", "incredibuildtr.h", + "incredibuild_global.h", "incredibuildconstants.h", "incredibuildplugin.cpp", - "incredibuildplugin.h", + "incredibuildtr.h", "makecommandbuilder.cpp", "makecommandbuilder.h", ] diff --git a/src/plugins/incredibuild/incredibuildplugin.cpp b/src/plugins/incredibuild/incredibuildplugin.cpp index 6e7ea8a4bc1..4e8f572812f 100644 --- a/src/plugins/incredibuild/incredibuildplugin.cpp +++ b/src/plugins/incredibuild/incredibuildplugin.cpp @@ -1,28 +1,26 @@ // Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "incredibuildplugin.h" - #include "buildconsolebuildstep.h" #include "ibconsolebuildstep.h" +#include + namespace IncrediBuild::Internal { -class IncrediBuildPluginPrivate +class IncrediBuildPlugin final : public ExtensionSystem::IPlugin { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "IncrediBuild.json") + public: - BuildConsoleStepFactory buildConsoleStepFactory; - IBConsoleStepFactory iBConsoleStepFactory; + IncrediBuildPlugin() + { + addManaged(); + addManaged(); + } }; -IncrediBuildPlugin::~IncrediBuildPlugin() -{ - delete d; -} - -void IncrediBuildPlugin::initialize() -{ - d = new IncrediBuildPluginPrivate; -} - } // IncrediBuild::Internal + +#include "incredibuildplugin.moc" diff --git a/src/plugins/incredibuild/incredibuildplugin.h b/src/plugins/incredibuild/incredibuildplugin.h deleted file mode 100644 index 994d65bb777..00000000000 --- a/src/plugins/incredibuild/incredibuildplugin.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace IncrediBuild::Internal { - -class IncrediBuildPlugin final : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "IncrediBuild.json") - -public: - IncrediBuildPlugin() = default; - ~IncrediBuildPlugin() final; - - void initialize() final; - -private: - class IncrediBuildPluginPrivate *d = nullptr; -}; - -} // IncrediBuild::Internal From 5689f0c60e3263fcf84a6b401193b131f62d613a Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 18:49:32 +0200 Subject: [PATCH 1280/1447] Valgrind: Add toolargs to command, not to a string list Removes arg splitting/re-combination roundtrips. Change-Id: I4bc19d3b65f4c685140cea0e190191587f5124e6 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/valgrind/callgrindengine.cpp | 22 ++++++++++------------ src/plugins/valgrind/callgrindengine.h | 2 +- src/plugins/valgrind/memchecktool.cpp | 22 ++++++++++------------ src/plugins/valgrind/valgrindengine.cpp | 4 ++-- src/plugins/valgrind/valgrindengine.h | 3 +-- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index 1318945155a..92b13b4f77b 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -61,34 +61,32 @@ CallgrindToolRunner::~CallgrindToolRunner() cleanupTempFile(); } -QStringList CallgrindToolRunner::toolArguments() const +void CallgrindToolRunner::addToolArguments(CommandLine &cmd) const { - QStringList arguments = {"--tool=callgrind"}; + cmd << "--tool=callgrind"; if (m_settings.enableCacheSim()) - arguments << "--cache-sim=yes"; + cmd << "--cache-sim=yes"; if (m_settings.enableBranchSim()) - arguments << "--branch-sim=yes"; + cmd << "--branch-sim=yes"; if (m_settings.collectBusEvents()) - arguments << "--collect-bus=yes"; + cmd << "--collect-bus=yes"; if (m_settings.collectSystime()) - arguments << "--collect-systime=yes"; + cmd << "--collect-systime=yes"; if (m_markAsPaused) - arguments << "--instr-atstart=no"; + cmd << "--instr-atstart=no"; // add extra arguments if (!m_argumentForToggleCollect.isEmpty()) - arguments << m_argumentForToggleCollect; + cmd << m_argumentForToggleCollect; - arguments << "--callgrind-out-file=" + m_valgrindOutputFile.path(); + cmd << "--callgrind-out-file=" + m_valgrindOutputFile.path(); - arguments << ProcessArgs::splitArgs(m_settings.callgrindArguments(), HostOsInfo::hostOs()); - - return arguments; + cmd.addArgs(m_settings.callgrindArguments(), CommandLine::Raw); } QString CallgrindToolRunner::progressTitle() const diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index 4ec6a16d7fa..d5d26e113a5 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -48,7 +48,7 @@ public: Q_ENUM(Option) protected: - QStringList toolArguments() const override; + void addToolArguments(Utils::CommandLine &cmd) const override; QString progressTitle() const override; signals: diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 38e06d46950..e2921603e98 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -111,7 +111,7 @@ signals: private: QString progressTitle() const override; - QStringList toolArguments() const override; + void addToolArguments(CommandLine &cmd) const override; void startDebugger(qint64 valgrindPid); void appendLog(const QByteArray &data); @@ -181,15 +181,15 @@ void MemcheckToolRunner::stop() ValgrindToolRunner::stop(); } -QStringList MemcheckToolRunner::toolArguments() const +void MemcheckToolRunner::addToolArguments(CommandLine &cmd) const { - QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"}; + cmd << "--tool=memcheck" << "--gen-suppressions=all"; if (m_settings.trackOrigins()) - arguments << "--track-origins=yes"; + cmd << "--track-origins=yes"; if (m_settings.showReachable()) - arguments << "--show-reachable=yes"; + cmd << "--show-reachable=yes"; QString leakCheckValue; switch (m_settings.leakCheckOnFinish()) { @@ -204,19 +204,17 @@ QStringList MemcheckToolRunner::toolArguments() const leakCheckValue = "summary"; break; } - arguments << "--leak-check=" + leakCheckValue; + cmd << "--leak-check=" + leakCheckValue; for (const FilePath &file : m_settings.suppressions()) - arguments << QString("--suppressions=%1").arg(file.path()); + cmd << QString("--suppressions=%1").arg(file.path()); - arguments << QString("--num-callers=%1").arg(m_settings.numCallers()); + cmd << QString("--num-callers=%1").arg(m_settings.numCallers()); if (m_withGdb) - arguments << "--vgdb=yes" << "--vgdb-error=0"; + cmd << "--vgdb=yes" << "--vgdb-error=0"; - arguments << ProcessArgs::splitArgs(m_settings.memcheckArguments(), HostOsInfo::hostOs()); - - return arguments; + cmd.addArgs(m_settings.memcheckArguments(), CommandLine::Raw); } const FilePaths MemcheckToolRunner::suppressionFiles() const diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 2d4ab6aadca..a228eb0e09a 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -74,9 +74,9 @@ void ValgrindToolRunner::start() m_progress.reportStarted(); CommandLine valgrind{valgrindExecutable}; - valgrind.addArgs(m_settings.valgrindArguments.value(), CommandLine::Raw); + valgrind.addArgs(m_settings.valgrindArguments(), CommandLine::Raw); valgrind.addArgs(genericToolArguments()); - valgrind.addArgs(toolArguments()); + addToolArguments(valgrind); m_runner.setValgrindCommand(valgrind); m_runner.setDebuggee(runControl()->runnable()); diff --git a/src/plugins/valgrind/valgrindengine.h b/src/plugins/valgrind/valgrindengine.h index e5894b17838..d491c7a8476 100644 --- a/src/plugins/valgrind/valgrindengine.h +++ b/src/plugins/valgrind/valgrindengine.h @@ -6,7 +6,6 @@ #include "valgrindsettings.h" #include -#include #include #include @@ -23,7 +22,7 @@ public: protected: virtual QString progressTitle() const = 0; - virtual QStringList toolArguments() const = 0; + virtual void addToolArguments(Utils::CommandLine &cmd) const = 0; ValgrindProjectSettings m_settings; QFutureInterface m_progress; From 6ab66690af8cdb8522a4c5a6b654ccd0d5d49635 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 11:37:16 +0200 Subject: [PATCH 1281/1447] Utils: Simplify remaining Environment::searchInPath implementation Use the parts that have recently been copied/moved to FilePath Change-Id: I4d5b5941c55052e58ae4b34c4c49432f63a13cde Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/libs/utils/environment.cpp | 99 ++-------------------------------- 1 file changed, 3 insertions(+), 96 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 46972d13513..653525e1c3e 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -212,111 +212,18 @@ void Environment::setupEnglishOutput() using SearchResultCallback = std::function; -static IterationPolicy searchInDirectory(const SearchResultCallback &resultCallback, - const FilePaths &execs, - const FilePath &directory, - QSet &alreadyCheckedDirectories, - const FilePathPredicate &filter = {}) -{ - // Compare the initial size of the set with the size after insertion to check if the directory - // was already checked. - const int initialCount = alreadyCheckedDirectories.count(); - alreadyCheckedDirectories.insert(directory); - const bool wasAlreadyChecked = alreadyCheckedDirectories.count() == initialCount; - - if (directory.isEmpty() || wasAlreadyChecked) - return IterationPolicy::Continue; - - for (const FilePath &exec : execs) { - const FilePath filePath = directory / exec.path(); - if (filePath.isExecutableFile() && (!filter || filter(filePath))) { - if (resultCallback(filePath) == IterationPolicy::Stop) - return IterationPolicy::Stop; - } - } - return IterationPolicy::Continue; -} - -static FilePaths appendExeExtensions(const Environment &env, const FilePath &executable) -{ - FilePaths execs{executable}; - if (env.osType() == OsTypeWindows) { - // Check all the executable extensions on windows: - // PATHEXT is only used if the executable has no extension - if (executable.suffix().isEmpty()) { - const QStringList extensions = env.expandedValueForKey("PATHEXT").split(';'); - - for (const QString &ext : extensions) - execs << executable.stringAppended(ext.toLower()); - } - } - return execs; -} - QString Environment::expandedValueForKey(const QString &key) const { const NameValueDictionary &dict = resolved(); return expandVariables(dict.value(key)); } -static void searchInDirectoriesHelper(const SearchResultCallback &resultCallback, - const Environment &env, - const QString &executable, - const FilePaths &dirs, - const FilePathPredicate &func, - bool usePath) -{ - if (executable.isEmpty()) - return; - - const FilePath exec = FilePath::fromUserInput(QDir::cleanPath(env.expandVariables(executable))); - const FilePaths execs = appendExeExtensions(env, exec); - - if (exec.isAbsolutePath()) { - for (const FilePath &path : execs) { - if (path.isExecutableFile() && (!func || func(path))) - if (resultCallback(path) == IterationPolicy::Stop) - return; - } - return; - } - - QSet alreadyCheckedDirectories; - for (const FilePath &dir : dirs) { - if (searchInDirectory(resultCallback, execs, dir, alreadyCheckedDirectories, func) - == IterationPolicy::Stop) - return; - } - - if (usePath) { - QTC_ASSERT(!executable.contains('/'), return); - - for (const FilePath &p : env.path()) { - if (searchInDirectory(resultCallback, execs, p, alreadyCheckedDirectories, func) - == IterationPolicy::Stop) - return; - } - } - return; -} - FilePath Environment::searchInPath(const QString &executable, const FilePaths &additionalDirs, - const FilePathPredicate &func) const + const FilePathPredicate &filter) const { - FilePath result; - searchInDirectoriesHelper( - [&result](const FilePath &path) { - result = path; - return IterationPolicy::Stop; - }, - *this, - executable, - additionalDirs, - func, - true); - - return result; + const FilePath exec = FilePath::fromUserInput(expandVariables(executable)); + return exec.searchInPath(additionalDirs, {}, filter, FilePath::WithAnySuffix); } FilePaths Environment::path() const From 4136b6e7959281659f284d1ac010131d4cb85436 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 09:23:04 +0200 Subject: [PATCH 1282/1447] Meson: Compactify MesonRunConfiguration setup Change-Id: I10a600b601301283dbdc960d9e07e5587b52c031 Reviewed-by: Reviewed-by: Alessandro Portale --- .../mesonrunconfiguration.cpp | 93 +++++++++---------- .../mesonrunconfiguration.h | 15 +-- 2 files changed, 47 insertions(+), 61 deletions(-) diff --git a/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp b/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp index 4af312fda9c..74919a49696 100644 --- a/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp +++ b/src/plugins/mesonprojectmanager/mesonrunconfiguration.cpp @@ -6,67 +6,65 @@ #include "mesonpluginconstants.h" #include -#include -#include #include #include #include -#include #include using namespace ProjectExplorer; +using namespace Utils; -namespace MesonProjectManager { -namespace Internal { +namespace MesonProjectManager::Internal { -MesonRunConfiguration::MesonRunConfiguration(Target *target, Utils::Id id) - : RunConfiguration{target, id} +class MesonRunConfiguration final : public RunConfiguration { - auto envAspect = addAspect(); - envAspect->setSupportForBuildEnvironment(target); +public: + MesonRunConfiguration(Target *target, Id id) + : RunConfiguration(target, id) + { + auto envAspect = addAspect(); + envAspect->setSupportForBuildEnvironment(target); - addAspect(target, ExecutableAspect::RunDevice); - addAspect(macroExpander()); - addAspect(macroExpander(), envAspect); - addAspect(); + addAspect(target, ExecutableAspect::RunDevice); + addAspect(macroExpander()); + addAspect(macroExpander(), envAspect); + addAspect(); - auto libAspect = addAspect(); - connect(libAspect, &UseLibraryPathsAspect::changed, - envAspect, &EnvironmentAspect::environmentChanged); - - if (Utils::HostOsInfo::isMacHost()) { - auto dyldAspect = addAspect(); - connect(dyldAspect, &UseLibraryPathsAspect::changed, + auto libAspect = addAspect(); + connect(libAspect, &UseLibraryPathsAspect::changed, envAspect, &EnvironmentAspect::environmentChanged); - envAspect->addModifier([dyldAspect](Utils::Environment &env) { - if (dyldAspect->value()) - env.set(QLatin1String("DYLD_IMAGE_SUFFIX"), QLatin1String("_debug")); + + if (HostOsInfo::isMacHost()) { + auto dyldAspect = addAspect(); + connect(dyldAspect, &UseLibraryPathsAspect::changed, + envAspect, &EnvironmentAspect::environmentChanged); + envAspect->addModifier([dyldAspect](Utils::Environment &env) { + if (dyldAspect->value()) + env.set(QLatin1String("DYLD_IMAGE_SUFFIX"), QLatin1String("_debug")); + }); + } + + envAspect->addModifier([this, libAspect](Environment &env) { + BuildTargetInfo bti = buildTargetInfo(); + if (bti.runEnvModifier) + bti.runEnvModifier(env, libAspect->value()); }); + + setUpdater([this] { + if (!activeBuildSystem()) + return; + + BuildTargetInfo bti = buildTargetInfo(); + aspect()->setUseTerminalHint(bti.usesTerminal); + aspect()->setExecutable(bti.targetFilePath); + aspect()->setDefaultWorkingDirectory(bti.workingDirectory); + emit aspect()->environmentChanged(); + }); + + connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); } - - envAspect->addModifier([this, libAspect](Utils::Environment &env) { - BuildTargetInfo bti = buildTargetInfo(); - if (bti.runEnvModifier) - bti.runEnvModifier(env, libAspect->value()); - }); - - setUpdater([this] { updateTargetInformation(); }); - - connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); -} - -void MesonRunConfiguration::updateTargetInformation() -{ - if (!activeBuildSystem()) - return; - - BuildTargetInfo bti = buildTargetInfo(); - aspect()->setUseTerminalHint(bti.usesTerminal); - aspect()->setExecutable(bti.targetFilePath); - aspect()->setDefaultWorkingDirectory(bti.workingDirectory); - emit aspect()->environmentChanged(); -} +}; MesonRunConfigurationFactory::MesonRunConfigurationFactory() { @@ -75,5 +73,4 @@ MesonRunConfigurationFactory::MesonRunConfigurationFactory() addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); } -} // namespace Internal -} // namespace MesonProjectManager +} // MesonProjectManager::Internal diff --git a/src/plugins/mesonprojectmanager/mesonrunconfiguration.h b/src/plugins/mesonprojectmanager/mesonrunconfiguration.h index 8a23dcbec4a..8c1f7580975 100644 --- a/src/plugins/mesonprojectmanager/mesonrunconfiguration.h +++ b/src/plugins/mesonprojectmanager/mesonrunconfiguration.h @@ -5,17 +5,7 @@ #include -namespace MesonProjectManager { -namespace Internal { - -class MesonRunConfiguration final : public ProjectExplorer::RunConfiguration -{ -public: - MesonRunConfiguration(ProjectExplorer::Target *target, Utils::Id id); - -private: - void updateTargetInformation(); -}; +namespace MesonProjectManager::Internal { class MesonRunConfigurationFactory final : public ProjectExplorer::RunConfigurationFactory { @@ -23,5 +13,4 @@ public: MesonRunConfigurationFactory(); }; -} // namespace Internal -} // namespace MesonProjectManager +} // MesonProjectManager::Internal From c995795d8070b35438112e892ca04d8a76144169 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 25 May 2023 15:39:20 +0200 Subject: [PATCH 1283/1447] Copilot: Fix spinner if Copilot not configure Previously the progress indicator would be visible if node.js or the lsp path was not configured. Change-Id: Ief235253c6cfcb8f8fb533fe746edc7d0cc5867c Reviewed-by: David Schulz Reviewed-by: --- src/plugins/copilot/authwidget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp index ed2870e85e1..31b4660b680 100644 --- a/src/plugins/copilot/authwidget.cpp +++ b/src/plugins/copilot/authwidget.cpp @@ -91,9 +91,13 @@ void AuthWidget::updateClient(const Utils::FilePath &nodeJs, const Utils::FilePa { LanguageClientManager::shutdownClient(m_client); m_client = nullptr; - setState(Tr::tr("Sign in"), true); - if (!nodeJs.exists() || !agent.exists()) + setState(Tr::tr("Sign in"), false); + m_button->setEnabled(false); + if (!nodeJs.exists() || !agent.exists()) { return; + } + + setState(Tr::tr("Sign in"), true); m_client = new CopilotClient(nodeJs, agent); connect(m_client, &Client::initialized, this, &AuthWidget::checkStatus); From 648cf50d855b2a046ef0280d5461260f42bd07ab Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 25 May 2023 13:43:26 +0200 Subject: [PATCH 1284/1447] Coin/GitHub: Switch to Qt 6.5.1 and LLVM 16.0.2 Change-Id: Ida29b97f937e374935e853eff62b30777a9142aa Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- .github/workflows/build_cmake.yml | 4 ++-- coin/instructions/common_environment.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 661b6365b23..a1d4c93fa00 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -7,9 +7,9 @@ on: - 'doc/**' env: - QT_VERSION: 6.5.0 + QT_VERSION: 6.5.1 MACOS_DEPLOYMENT_TARGET: 10.15 - CLANG_VERSION: 16.0.0 + CLANG_VERSION: 16.0.2 ELFUTILS_VERSION: 0.175 CMAKE_VERSION: 3.21.1 NINJA_VERSION: 1.10.2 diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index b8be5f5c4a4..ad59636650c 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -7,10 +7,10 @@ instructions: variableValue: "RelWithDebInfo" - type: EnvironmentVariable variableName: LLVM_BASE_URL - variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_16.0.0-based + variableValue: http://master.qt.io/development_releases/prebuilt/libclang/libclang-release_16.0.2-based - type: EnvironmentVariable variableName: QTC_QT_BASE_URL - variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.5/6.5.0-released/Qt" + variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.5/6.5.1-released/Qt" - type: EnvironmentVariable variableName: QTC_QT_MODULES variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations qtwebengine" From 2ad153f30e99c58ea1ef4d50e3b803e98620d119 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 May 2023 13:05:02 +0200 Subject: [PATCH 1285/1447] Doc: Add \a commands and return values to TextFileFormat docs To fix qdoc warnings. Change-Id: I6258223e83517c1206e8bdb4db20db4e8fc60751 Reviewed-by: Eike Ziller --- src/libs/utils/textfileformat.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/textfileformat.cpp b/src/libs/utils/textfileformat.cpp index 094c6d0d72f..264c6c4351f 100644 --- a/src/libs/utils/textfileformat.cpp +++ b/src/libs/utils/textfileformat.cpp @@ -52,7 +52,7 @@ QDebug operator<<(QDebug d, const TextFileFormat &format) TextFileFormat::TextFileFormat() = default; /*! - Detects the format of text data. + Detects the format of text \a data. */ TextFileFormat TextFileFormat::detect(const QByteArray &data) @@ -85,7 +85,8 @@ TextFileFormat TextFileFormat::detect(const QByteArray &data) } /*! - Returns a piece of text suitable as display for a encoding error. + Returns a piece of text specified by \a data suitable as display for + an encoding error. */ QByteArray TextFileFormat::decodingErrorSample(const QByteArray &data) @@ -153,7 +154,7 @@ bool decodeTextFileContent(const QByteArray &dataBA, } /*! - Decodes data to a plain string. + Returns \a data decoded to a plain string, \a target. */ bool TextFileFormat::decode(const QByteArray &data, QString *target) const @@ -163,7 +164,7 @@ bool TextFileFormat::decode(const QByteArray &data, QString *target) const } /*! - Decodes data to a list of strings. + Returns \a data decoded to a list of strings, \a target. Intended for use with progress bars loading large files. */ @@ -212,7 +213,12 @@ TextFileFormat::ReadResult readTextFile(const FilePath &filePath, const QTextCod } /*! - Reads a text file into a list of strings. + Reads a text file from \a filePath into a list of strings, \a plainTextList + using \a defaultCodec and text file format \a format. + + Returns whether decoding was possible without errors. If errors occur, + returns an error message, \a errorString and a sample error, + \a decodingErrorSample. */ TextFileFormat::ReadResult @@ -230,7 +236,11 @@ TextFileFormat::ReadResult } /*! - Reads a text file into a string. + Reads a text file from \a filePath into a string, \a plainText using + \a defaultCodec and text file format \a format. + + Returns whether decoding was possible without errors. + */ TextFileFormat::ReadResult @@ -279,7 +289,10 @@ TextFileFormat::ReadResult TextFileFormat::readFileUTF8(const FilePath &filePath } /*! - Writes out a text file. + Writes out a text file to \a filePath into a string, \a plainText. + + Returns whether decoding was possible without errors. If errors occur, + returns an error message, \a errorString. */ bool TextFileFormat::writeFile(const FilePath &filePath, QString plainText, QString *errorString) const From 7aec8c0b142b0fd32ac55ee6bfcbb37d12baabb7 Mon Sep 17 00:00:00 2001 From: Yasser Grimes Date: Fri, 24 Mar 2023 17:49:27 +0200 Subject: [PATCH 1286/1447] McuSupport: Add dialog for Qt MCUs kit creation status and help The status of automatically created kits or manually updated ones is displayed in "General Messages" along with other messages making it difficult to know if something went wrong with kit creation. To avoid showing a dialog at QtC startup an InfoBar message was added with a detail button that will open a dialog listing all the messages with their platform, package and Os providing an easy button to go to the MCU Option page to fix the package of a help button pointing to the prerequisites documentation. Fixes: QTCREATORBUG-28920 Change-Id: I20c30d968fbd2d4c6d10d16504a51e7201a2db3b Reviewed-by: Alessandro Portale --- src/plugins/mcusupport/CMakeLists.txt | 1 + .../dialogs/mcukitcreationdialog.cpp | 98 +++++++++++ .../mcusupport/dialogs/mcukitcreationdialog.h | 40 +++++ .../dialogs/mcukitcreationdialog.ui | 154 ++++++++++++++++++ src/plugins/mcusupport/mcukitmanager.cpp | 53 +++--- src/plugins/mcusupport/mcusupport.qbs | 3 + src/plugins/mcusupport/mcusupport_global.h | 9 + src/plugins/mcusupport/mcusupportconstants.h | 2 + src/plugins/mcusupport/mcusupportoptions.cpp | 27 +++ src/plugins/mcusupport/mcusupportoptions.h | 3 + .../mcusupport/mcusupportoptionspage.cpp | 9 +- src/plugins/mcusupport/mcutarget.cpp | 20 ++- src/plugins/mcusupport/mcutarget.h | 2 +- src/plugins/mcusupport/settingshandler.cpp | 13 ++ src/plugins/mcusupport/settingshandler.h | 3 + 15 files changed, 411 insertions(+), 26 deletions(-) create mode 100644 src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp create mode 100644 src/plugins/mcusupport/dialogs/mcukitcreationdialog.h create mode 100644 src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index 81fadd4ddfb..b0ff6d8fc45 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -24,6 +24,7 @@ add_qtc_plugin(McuSupport settingshandler.cpp settingshandler.h mcuqmlprojectnode.cpp mcuqmlprojectnode.h mcubuildstep.cpp mcubuildstep.h + dialogs/mcukitcreationdialog.h dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.ui ) add_subdirectory(test) diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp new file mode 100644 index 00000000000..e708d53039d --- /dev/null +++ b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp @@ -0,0 +1,98 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "mcukitcreationdialog.h" +#include "ui_mcukitcreationdialog.h" + +#include "mcuabstractpackage.h" +#include "mcusupportconstants.h" +#include "mcusupporttr.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace McuSupport::Internal { + +McuKitCreationDialog::McuKitCreationDialog(const MessagesList &messages, + const SettingsHandler::Ptr &settingsHandler, + McuPackagePtr qtMCUPackage, + QWidget *parent) + : QDialog(parent) + , ui(new Ui::McuKitCreationDialog) + , m_messages(messages) +{ + ui->setupUi(this); + ui->iconLabel->setPixmap(Utils::Icon(":/mcusupport/images/mcusupportdevice.png").pixmap()); + m_previousButton = ui->buttonBox->addButton("<", QDialogButtonBox::ActionRole); + m_nextButton = ui->buttonBox->addButton(">", QDialogButtonBox::ActionRole); + m_fixButton = ui->buttonBox->addButton(Tr::tr("Fix"), QDialogButtonBox::ActionRole); + m_helpButton = ui->buttonBox->addButton(Tr::tr("Help"), QDialogButtonBox::HelpRole); + // prevent clicking the buttons from closing the message box + m_nextButton->disconnect(); + m_previousButton->disconnect(); + + if (messages.size() == 1) { + m_nextButton->setVisible(false); + m_previousButton->setVisible(false); + } + //display first message + if (messages.size() > 1) + updateMessage(1); + + if (qtMCUPackage->isValidStatus()) + ui->qtMCUsPathLabel->setText( + Tr::tr("Qt for MCUs path %1").arg(qtMCUPackage->path().toUserOutput())); + connect(m_nextButton, &QPushButton::clicked, [=] { updateMessage(1); }); + connect(m_previousButton, &QPushButton::clicked, [=] { updateMessage(-1); }); + connect(m_fixButton, &QPushButton::clicked, [=] { + // Open the MCU Options widget on the current platform + settingsHandler->setInitialPlatformName(m_messages[m_currentIndex].platform); + Core::ICore::showOptionsDialog(Constants::SETTINGS_ID); + // reset the initial platform name + settingsHandler->setInitialPlatformName(""); + }); + connect(m_helpButton, &QPushButton::clicked, [] { + QDesktopServices::openUrl(QUrl("https://doc.qt.io/QtForMCUs/qtul-prerequisites.html")); + }); +} + +void McuKitCreationDialog::updateMessage(const int inc) +{ + m_currentIndex += inc; + m_nextButton->setEnabled(m_currentIndex < (m_messages.size() - 1)); + m_previousButton->setEnabled(m_currentIndex > 0); + ui->textLabel->setText(QString("%1 %2 : %3") + .arg(Tr::tr("Target"), + (m_messages[m_currentIndex].status == McuSupportMessage::Warning + ? Tr::tr("Warning") + : Tr::tr("Error")), + m_messages[m_currentIndex].platform)); + ui->iconLabel->setPixmap( + QApplication::style() + ->standardIcon(m_messages[m_currentIndex].status == McuSupportMessage::Warning + ? QStyle::SP_MessageBoxWarning + : QStyle::SP_MessageBoxCritical) + .pixmap(64, 64)); + ui->informationLabel->setText(QString("%1: %2

    %3: %4") + .arg(Tr::tr("Package"), + m_messages[m_currentIndex].packageName, + Tr::tr("Status"), + m_messages.at(m_currentIndex).message)); + ui->messageCountLabel->setText(QString("%1 / %2").arg(QString::number(m_currentIndex + 1), + QString::number(m_messages.size()))); +} + +McuKitCreationDialog::~McuKitCreationDialog() +{ + delete ui; +} + +} // namespace McuSupport::Internal diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h new file mode 100644 index 00000000000..186eec7be41 --- /dev/null +++ b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h @@ -0,0 +1,40 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "mcusupport_global.h" +#include "settingshandler.h" +#include +#include + +namespace Ui { +class McuKitCreationDialog; +} + +namespace McuSupport::Internal { + +class McuKitCreationDialog : public QDialog +{ + Q_OBJECT + +public: + explicit McuKitCreationDialog(const MessagesList &messages, + const SettingsHandler::Ptr &settingsHandler, + McuPackagePtr qtMCUPackage, + QWidget *parent = nullptr); + ~McuKitCreationDialog(); + +private slots: + void updateMessage(const int inc); + +private: + Ui::McuKitCreationDialog *ui; + int m_currentIndex = -1; + QPushButton *m_previousButton; + QPushButton *m_nextButton; + QPushButton *m_helpButton; + QPushButton *m_fixButton; + const MessagesList &m_messages; +}; +} // namespace McuSupport::Internal diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui new file mode 100644 index 00000000000..f6194bbe6e3 --- /dev/null +++ b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui @@ -0,0 +1,154 @@ + + + McuKitCreationDialog + + + + 0 + 0 + 349 + 200 + + + + QtMCUs Kit Creation + + + true + + + + + + QtMCUs path: + + + + + + + Qt::Vertical + + + + + + + 1/3 + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QDialogButtonBox::Ignore + + + + + + + Dialog text + + + Qt::RichText + + + true + + + + + + + + 64 + 64 + + + + + 70 + 1000 + + + + + + + false + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + TextLabel + + + Qt::RichText + + + + + + + + + + + buttonBox + accepted() + McuKitCreationDialog + accept() + + + 339 + 23 + + + 157 + 199 + + + + + buttonBox + rejected() + McuKitCreationDialog + reject() + + + 339 + 29 + + + 286 + 199 + + + + + diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index f68eca6973d..00709b126f5 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -3,6 +3,7 @@ #include "mcukitmanager.h" #include "mculegacyconstants.h" +#include "mcusupport_global.h" #include "mcusupportoptions.h" #include "mcukitinformation.h" @@ -486,31 +487,37 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler) { McuPackagePtr qtForMCUsPackage{createQtForMCUsPackage(settingsHandler)}; - const auto createKits = [qtForMCUsPackage, settingsHandler]() { + // add a list of package, board, errormessage, + MessagesList autoGenerationMessages; + + const auto createKits = [&autoGenerationMessages, qtForMCUsPackage, settingsHandler] { if (settingsHandler->isAutomaticKitCreationEnabled()) { qtForMCUsPackage->updateStatus(); if (!qtForMCUsPackage->isValidStatus()) { switch (qtForMCUsPackage->status()) { case McuAbstractPackage::Status::ValidPathInvalidPackage: { - printMessage(Tr::tr("Path %1 exists, but does not contain %2.") - .arg(qtForMCUsPackage->path().toUserOutput(), - qtForMCUsPackage->detectionPath().toUserOutput()), - true); + const QString message + = Tr::tr("Path %1 exists, but does not contain %2.") + .arg(qtForMCUsPackage->path().toUserOutput(), + qtForMCUsPackage->detectionPath().toUserOutput()); + autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message}); + printMessage(message, true); break; } case McuAbstractPackage::Status::InvalidPath: { - printMessage(Tr::tr( - "Path %1 does not exist. Add the path in Edit > Preferences > " - "Devices > MCU.") - .arg(qtForMCUsPackage->path().toUserOutput()), - true); + const QString message + = Tr::tr("Path %1 does not exist. Add the path in Edit > Preferences > " + "Devices > MCU.") + .arg(qtForMCUsPackage->path().toUserOutput()); + autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message}); + printMessage(message, true); break; } case McuAbstractPackage::Status::EmptyPath: { - printMessage( - Tr::tr("Missing %1. Add the path in Edit > Preferences > Devices > MCU.") - .arg(qtForMCUsPackage->detectionPath().toUserOutput()), - true); + const QString message = Tr::tr("Missing %1. Add the path in Edit > Preferences > Devices > MCU.") + .arg(qtForMCUsPackage->detectionPath().toUserOutput()); + autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message}); + printMessage(message, true); return; } default: @@ -520,10 +527,10 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler) } if (CMakeProjectManager::CMakeToolManager::cmakeTools().isEmpty()) { - printMessage( - Tr::tr("No CMake tool was detected. Add a CMake tool in Edit > Preferences > " - "Kits > CMake."), - true); + const QString message = Tr::tr("No CMake tool was detected. Add a CMake tool in Edit > Preferences > " + "Kits > CMake."); + autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message}); + printMessage(message, true); return; } @@ -543,7 +550,7 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler) // if no kits for this target, create if (target->isValid()) newKit(target.get(), qtForMCUsPackage); - target->printPackageProblems(); + target->handlePackageProblems(autoGenerationMessages); } } if (needsUpgrade) @@ -552,6 +559,9 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler) }; createKits(); + McuSupportOptions::displayKitCreationMessages(autoGenerationMessages, + settingsHandler, + qtForMCUsPackage); } // Maintenance @@ -569,6 +579,7 @@ void upgradeKitsByCreatingNewPackage(const SettingsHandler::Ptr &settingsHandler McuSdkRepository repo{targetsAndPackages(qtForMCUsPackage, settingsHandler)}; + MessagesList messages; for (const auto &target : std::as_const(repo.mcuTargets)) { if (!matchingKits(target.get(), qtForMCUsPackage).empty()) // already up-to-date @@ -583,9 +594,11 @@ void upgradeKitsByCreatingNewPackage(const SettingsHandler::Ptr &settingsHandler if (target->isValid()) newKit(target.get(), qtForMCUsPackage); - target->printPackageProblems(); + target->handlePackageProblems(messages); } } + // Open the dialog showing warnings and errors in packages + McuSupportOptions::displayKitCreationMessages(messages, settingsHandler, qtForMCUsPackage); } // Maintenance diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index 0587067cc64..7b686075cac 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -58,6 +58,9 @@ QtcPlugin { "mcuhelpers.h", "settingshandler.h", "settingshandler.cpp", + "dialogs/mcukitcreationdialog.ui", + "dialogs/mcukitcreationdialog.h", + "dialogs/mcukitcreationdialog.cpp", ] QtcTestFiles { diff --git a/src/plugins/mcusupport/mcusupport_global.h b/src/plugins/mcusupport/mcusupport_global.h index c1a20746a24..20de9a73298 100644 --- a/src/plugins/mcusupport/mcusupport_global.h +++ b/src/plugins/mcusupport/mcusupport_global.h @@ -30,4 +30,13 @@ static const QVersionNumber newVersion{2, 3}; using Targets = QList; using Packages = QSet; +struct McuSupportMessage +{ + QString packageName; + QString platform; + QString message; + enum Status { Warning, Error } status = Status::Error; +}; +using MessagesList = QList; + } // namespace McuSupport::Internal diff --git a/src/plugins/mcusupport/mcusupportconstants.h b/src/plugins/mcusupport/mcusupportconstants.h index 31e67c7b1ca..780880d9d11 100644 --- a/src/plugins/mcusupport/mcusupportconstants.h +++ b/src/plugins/mcusupport/mcusupportconstants.h @@ -22,5 +22,7 @@ const char SETTINGS_GROUP[]{"McuSupport"}; const char SETTINGS_KEY_PACKAGE_PREFIX[]{"Package_"}; const char SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK[]{"QtForMCUsSdk"}; // Key known by SDK installer const char SETTINGS_KEY_AUTOMATIC_KIT_CREATION[]{"AutomaticKitCreation"}; +// Used to decide which platform will be displayed first in the MCU Options page +const char SETTINGS_KEY_INITIAL_PLATFORM_KEY[]{"McuSupport.InitialPlatform"}; } // namespace McuSupport::Internal::Constants diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 474314b6a6b..51cb1eacd81 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -3,9 +3,11 @@ #include "mcusupportoptions.h" +#include "dialogs/mcukitcreationdialog.h" #include "mcuhelpers.h" #include "mcukitmanager.h" #include "mcupackage.h" +#include "mcusupport_global.h" #include "mcusupportconstants.h" #include "mcusupportsdk.h" #include "mcusupporttr.h" @@ -19,6 +21,7 @@ #include #include #include +#include #include #include @@ -252,6 +255,30 @@ McuKitManager::UpgradeOption McuSupportOptions::askForKitUpgrades() return McuKitManager::UpgradeOption::Ignore; } +void McuSupportOptions::displayKitCreationMessages(const MessagesList &messages, + const SettingsHandler::Ptr &settingsHandler, + McuPackagePtr qtMCUsPackage) +{ + if (messages.isEmpty() || !qtMCUsPackage->isValidStatus()) + return; + static const char mcuKitCreationErrorInfoId[] = "ErrorWhileCreatingMCUKits"; + if (!Core::ICore::infoBar()->canInfoBeAdded(mcuKitCreationErrorInfoId)) + return; + + Utils::InfoBarEntry info(mcuKitCreationErrorInfoId, + Tr::tr("Errors while creating Qt for MCUs kits"), + Utils::InfoBarEntry::GlobalSuppression::Enabled); + + info.addCustomButton(Tr::tr("Details"), [=] { + auto popup = new McuKitCreationDialog(messages, settingsHandler, qtMCUsPackage); + popup->exec(); + delete popup; + Core::ICore::infoBar()->removeInfo(mcuKitCreationErrorInfoId); + }); + + Core::ICore::infoBar()->addInfo(info); +} + void McuSupportOptions::checkUpgradeableKits() { if (!qtForMCUsSdkPackage->isValidStatus() || sdkRepository.mcuTargets.isEmpty()) diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index a442c0864a7..1090f871004 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -61,6 +61,9 @@ public: [[nodiscard]] Utils::FilePath qulDirFromSettings() const; [[nodiscard]] Utils::FilePath qulDocsDir() const; static McuKitManager::UpgradeOption askForKitUpgrades(); + static void displayKitCreationMessages(const MessagesList &messages, + const SettingsHandler::Ptr &settingsHandler, + McuPackagePtr qtMCUsPackage); void registerQchFiles() const; void registerExamples() const; diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index d75568a8f66..a05a3771b07 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -350,10 +350,17 @@ void McuSupportOptionsWidget::populateMcuTargetsComboBox() { m_options.populatePackagesAndTargets(); m_mcuTargetsComboBox->clear(); + int initialPlatformIndex = 0; + int targetsCounter = -1; m_mcuTargetsComboBox->addItems( - Utils::transform(m_options.sdkRepository.mcuTargets, [](const McuTargetPtr &t) { + Utils::transform(m_options.sdkRepository.mcuTargets, [&](const McuTargetPtr &t) { + if (t->platform().name == m_settingsHandler->initialPlatformName()) + initialPlatformIndex = m_options.sdkRepository.mcuTargets.indexOf(t); + targetsCounter++; return McuKitManager::generateKitNameFromTarget(t.get()); })); + if (targetsCounter != -1) + m_mcuTargetsComboBox->setCurrentIndex(initialPlatformIndex); updateStatus(); } diff --git a/src/plugins/mcusupport/mcutarget.cpp b/src/plugins/mcusupport/mcutarget.cpp index 2040c260398..d7a3b0fe397 100644 --- a/src/plugins/mcusupport/mcutarget.cpp +++ b/src/plugins/mcusupport/mcutarget.cpp @@ -1,11 +1,12 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "mcutarget.h" #include "mcukitmanager.h" #include "mcupackage.h" +#include "mcusupport_global.h" #include "mcusupportplugin.h" #include "mcusupporttr.h" -#include "mcutarget.h" #include @@ -82,22 +83,33 @@ QString McuTarget::desktopCompilerId() const return QLatin1String("invalid"); } -void McuTarget::printPackageProblems() const +void McuTarget::handlePackageProblems(MessagesList &messages) const { for (auto package : packages()) { package->updateStatus(); - if (!package->isValidStatus()) + if (!package->isValidStatus()) { printMessage(Tr::tr("Error creating kit for target %1, package %2: %3") .arg(McuKitManager::generateKitNameFromTarget(this), package->label(), package->statusText()), true); - if (package->status() == McuAbstractPackage::Status::ValidPackageMismatchedVersion) + messages.push_back({package->label(), + this->platform().name, + package->statusText(), + McuSupportMessage::Error}); + } + if (package->status() == McuAbstractPackage::Status::ValidPackageMismatchedVersion) { printMessage(Tr::tr("Warning creating kit for target %1, package %2: %3") .arg(McuKitManager::generateKitNameFromTarget(this), package->label(), package->statusText()), false); + + messages.push_back({package->label(), + this->platform().name, + package->statusText(), + McuSupportMessage::Warning}); + } } } diff --git a/src/plugins/mcusupport/mcutarget.h b/src/plugins/mcusupport/mcutarget.h index 57f28030be7..8ee19f54ab0 100644 --- a/src/plugins/mcusupport/mcutarget.h +++ b/src/plugins/mcusupport/mcutarget.h @@ -54,7 +54,7 @@ public: int colorDepth() const; bool isValid() const; QString desktopCompilerId() const; - void printPackageProblems() const; + void handlePackageProblems(MessagesList &messages) const; private: const QVersionNumber m_qulVersion; diff --git a/src/plugins/mcusupport/settingshandler.cpp b/src/plugins/mcusupport/settingshandler.cpp index d292ea6cd69..67fbd27f978 100644 --- a/src/plugins/mcusupport/settingshandler.cpp +++ b/src/plugins/mcusupport/settingshandler.cpp @@ -68,4 +68,17 @@ void SettingsHandler::setAutomaticKitCreation(bool isEnabled) settings->setValue(automaticKitCreationSettingsKey, isEnabled); } +void SettingsHandler::setInitialPlatformName(const QString &platform) +{ + QSettings *settings = Core::ICore::settings(QSettings::UserScope); + settings->setValue(Constants::SETTINGS_KEY_INITIAL_PLATFORM_KEY, platform); +} + +QString SettingsHandler::initialPlatformName() const +{ + QSettings *settings = Core::ICore::settings(QSettings::UserScope); + const QString name + = settings->value(Constants::SETTINGS_KEY_INITIAL_PLATFORM_KEY, "").toString(); + return name; +} } // namespace McuSupport::Internal diff --git a/src/plugins/mcusupport/settingshandler.h b/src/plugins/mcusupport/settingshandler.h index 02bbbcf26df..145049e31db 100644 --- a/src/plugins/mcusupport/settingshandler.h +++ b/src/plugins/mcusupport/settingshandler.h @@ -27,5 +27,8 @@ public: virtual bool isAutomaticKitCreationEnabled() const; void setAutomaticKitCreation(bool isEnabled); + void setInitialPlatformName(const QString &platform); + QString initialPlatformName() const; + }; //class SettingsHandler } // namespace McuSupport::Internal From 8b29c06372128fc348745bbd08ce3c95ead83665 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 14:49:11 +0200 Subject: [PATCH 1287/1447] Terminal: Use PageSettings for settings The DropSupport is disabled for now, plan is to have a DropArea LayoutItem later and use that. Change-Id: I7fd1e55ad0c053f0357bb53a7cc20e9da8a933a7 Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/CMakeLists.txt | 3 +- src/plugins/terminal/terminal.qbs | 3 - src/plugins/terminal/terminalpane.cpp | 1 - src/plugins/terminal/terminalplugin.cpp | 107 ++-- src/plugins/terminal/terminalplugin.h | 30 -- src/plugins/terminal/terminalsettings.cpp | 449 ++++++++++++++++- src/plugins/terminal/terminalsettings.h | 23 +- src/plugins/terminal/terminalsettingspage.cpp | 464 ------------------ src/plugins/terminal/terminalsettingspage.h | 18 - 9 files changed, 503 insertions(+), 595 deletions(-) delete mode 100644 src/plugins/terminal/terminalplugin.h delete mode 100644 src/plugins/terminal/terminalsettingspage.cpp delete mode 100644 src/plugins/terminal/terminalsettingspage.h diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index 005a3aaca56..083ffa844e6 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -12,11 +12,10 @@ add_qtc_plugin(Terminal terminal.qrc terminalcommands.cpp terminalcommands.h terminalpane.cpp terminalpane.h - terminalplugin.cpp terminalplugin.h + terminalplugin.cpp terminalprocessimpl.cpp terminalprocessimpl.h terminalsearch.cpp terminalsearch.h terminalsettings.cpp terminalsettings.h - terminalsettingspage.cpp terminalsettingspage.h terminalsurface.cpp terminalsurface.h terminaltr.h terminalwidget.cpp terminalwidget.h diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 231d3630b7b..0fa1ba46316 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -27,15 +27,12 @@ QtcPlugin { "terminalpane.cpp", "terminalpane.h", "terminalplugin.cpp", - "terminalplugin.h", "terminalprocessimpl.cpp", "terminalprocessimpl.h", "terminalsearch.cpp", "terminalsearch.h", "terminalsettings.cpp", "terminalsettings.h", - "terminalsettingspage.cpp", - "terminalsettingspage.h", "terminalsurface.cpp", "terminalsurface.h", "terminaltr.h", diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 9b1f9898e81..34370f22bb2 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -151,7 +151,6 @@ TerminalPane::TerminalPane(QObject *parent) connect(m_escSettingButton, &QToolButton::toggled, this, [this] { TerminalSettings::instance().sendEscapeToTerminal.setValue(m_escSettingButton->isChecked()); - TerminalSettings::instance().apply(); TerminalSettings::instance().writeSettings(Core::ICore::settings()); }); diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp index 831981e823a..4738bf9b307 100644 --- a/src/plugins/terminal/terminalplugin.cpp +++ b/src/plugins/terminal/terminalplugin.cpp @@ -1,12 +1,9 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "terminalplugin.h" - #include "terminalpane.h" #include "terminalprocessimpl.h" #include "terminalsettings.h" -#include "terminalsettingspage.h" #include "terminalcommands.h" #include @@ -16,6 +13,7 @@ #include #include +#include #include #include @@ -24,61 +22,70 @@ #include #include -namespace Terminal { -namespace Internal { +namespace Terminal::Internal { -TerminalPlugin::TerminalPlugin() {} - -TerminalPlugin::~TerminalPlugin() +class TerminalPlugin final : public ExtensionSystem::IPlugin { - ExtensionSystem::PluginManager::instance()->removeObject(m_terminalPane); - delete m_terminalPane; - m_terminalPane = nullptr; -} + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Terminal.json") -bool TerminalPlugin::delayedInitialize() -{ - TerminalCommands::instance().lazyInitCommands(); - return true; -} +public: + TerminalPlugin() = default; -void TerminalPlugin::extensionsInitialized() -{ - (void) TerminalSettingsPage::instance(); - TerminalSettings::instance().readSettings(Core::ICore::settings()); + ~TerminalPlugin() final + { + ExtensionSystem::PluginManager::removeObject(m_terminalPane); + delete m_terminalPane; + m_terminalPane = nullptr; + } - m_terminalPane = new TerminalPane(); - ExtensionSystem::PluginManager::instance()->addObject(m_terminalPane); + void initialize() final + { + addManaged(); + } - auto enable = [this] { - Utils::Terminal::Hooks::instance() - .addCallbackSet("Internal", - {[this](const Utils::Terminal::OpenTerminalParameters &p) { - m_terminalPane->openTerminal(p); - }, - [this] { return new TerminalProcessImpl(m_terminalPane); }}); - }; + void extensionsInitialized() final + { + m_terminalPane = new TerminalPane; + ExtensionSystem::PluginManager::addObject(m_terminalPane); - auto disable = [] { Utils::Terminal::Hooks::instance().removeCallbackSet("Internal"); }; + auto enable = [this] { + Utils::Terminal::Hooks::instance() + .addCallbackSet("Internal", + {[this](const Utils::Terminal::OpenTerminalParameters &p) { + m_terminalPane->openTerminal(p); + }, + [this] { return new TerminalProcessImpl(m_terminalPane); }}); + }; - static bool isEnabled = false; - auto settingsChanged = [enable, disable] { - if (isEnabled != TerminalSettings::instance().enableTerminal.value()) { - isEnabled = TerminalSettings::instance().enableTerminal.value(); - if (isEnabled) - enable(); - else - disable(); - } - }; + auto disable = [] { Utils::Terminal::Hooks::instance().removeCallbackSet("Internal"); }; - QObject::connect(&TerminalSettings::instance(), - &Utils::AspectContainer::applied, - this, - settingsChanged); + static bool isEnabled = false; + auto settingsChanged = [enable, disable] { + if (isEnabled != TerminalSettings::instance().enableTerminal()) { + isEnabled = TerminalSettings::instance().enableTerminal(); + if (isEnabled) + enable(); + else + disable(); + } + }; - settingsChanged(); -} + QObject::connect(&TerminalSettings::instance(), &Utils::AspectContainer::applied, this, settingsChanged); -} // namespace Internal -} // namespace Terminal + settingsChanged(); + } + + bool delayedInitialize() final + { + TerminalCommands::instance().lazyInitCommands(); + return true; + } + +private: + TerminalPane *m_terminalPane{nullptr}; +}; + +} // Terminal::Internal + +#include "terminalplugin.moc" diff --git a/src/plugins/terminal/terminalplugin.h b/src/plugins/terminal/terminalplugin.h deleted file mode 100644 index 2bfbd9f22e0..00000000000 --- a/src/plugins/terminal/terminalplugin.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Terminal { - -class TerminalPane; -namespace Internal { - -class TerminalPlugin : public ExtensionSystem::IPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Terminal.json") - -public: - TerminalPlugin(); - ~TerminalPlugin() override; - - void extensionsInitialized() override; - bool delayedInitialize() override; - -private: - TerminalPane *m_terminalPane{nullptr}; -}; - -} // namespace Internal -} // namespace Terminal diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index e2d2150cd72..577367b6641 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -5,10 +5,26 @@ #include "terminaltr.h" +#include + +#include #include +#include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include + using namespace Utils; namespace Terminal { @@ -46,12 +62,6 @@ static QString defaultShell() return shPath.nativePath(); } -TerminalSettings &TerminalSettings::instance() -{ - static TerminalSettings settings; - return settings; -} - void setupColor(TerminalSettings *settings, ColorAspect &color, const QString &label, @@ -64,10 +74,305 @@ void setupColor(TerminalSettings *settings, settings->registerAspect(&color); } +static expected_str loadXdefaults(const FilePath &path) +{ + const expected_str readResult = path.fileContents(); + if (!readResult) + return make_unexpected(readResult.error()); + + QRegularExpression re(R"(.*\*(color[0-9]{1,2}|foreground|background):\s*(#[0-9a-f]{6}))"); + + for (const QByteArray &line : readResult->split('\n')) { + if (line.trimmed().startsWith('!')) + continue; + + const auto match = re.match(QString::fromUtf8(line)); + if (match.hasMatch()) { + const QString colorName = match.captured(1); + const QColor color(match.captured(2)); + if (colorName == "foreground") { + TerminalSettings::instance().foregroundColor.setVolatileValue(color); + } else if (colorName == "background") { + TerminalSettings::instance().backgroundColor.setVolatileValue(color); + } else { + const int colorIndex = colorName.mid(5).toInt(); + if (colorIndex >= 0 && colorIndex < 16) + TerminalSettings::instance().colors[colorIndex].setVolatileValue(color); + } + } + } + + return {}; +} + +static expected_str loadItermColors(const FilePath &path) +{ + QFile f(path.toFSPathString()); + const bool opened = f.open(QIODevice::ReadOnly); + if (!opened) + return make_unexpected(Tr::tr("Failed to open file")); + + QXmlStreamReader reader(&f); + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"plist") { + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"dict") { + QString colorName; + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"key") { + colorName = reader.readElementText(); + } else if (reader.name() == u"dict") { + QColor color; + int component = 0; + while (!reader.atEnd() && reader.readNextStartElement()) { + if (reader.name() == u"key") { + const auto &text = reader.readElementText(); + if (text == u"Red Component") + component = 0; + else if (text == u"Green Component") + component = 1; + else if (text == u"Blue Component") + component = 2; + else if (text == u"Alpha Component") + component = 3; + } else if (reader.name() == u"real") { + // clang-format off + switch (component) { + case 0: color.setRedF(reader.readElementText().toDouble()); break; + case 1: color.setGreenF(reader.readElementText().toDouble()); break; + case 2: color.setBlueF(reader.readElementText().toDouble()); break; + case 3: color.setAlphaF(reader.readElementText().toDouble()); break; + } + // clang-format on + } else { + reader.skipCurrentElement(); + } + } + + if (colorName.startsWith("Ansi")) { + const auto c = colorName.mid(5, 2); + const int colorIndex = c.toInt(); + if (colorIndex >= 0 && colorIndex < 16) + TerminalSettings::instance().colors[colorIndex].setVolatileValue( + color); + } else if (colorName == "Foreground Color") { + TerminalSettings::instance().foregroundColor.setVolatileValue(color); + } else if (colorName == "Background Color") { + TerminalSettings::instance().backgroundColor.setVolatileValue(color); + } else if (colorName == "Selection Color") { + TerminalSettings::instance().selectionColor.setVolatileValue(color); + } + } + } + } + } + break; + } + } + if (reader.hasError()) + return make_unexpected(reader.errorString()); + + return {}; +} + +static expected_str loadVsCodeColors(const FilePath &path) +{ + const expected_str readResult = path.fileContents(); + if (!readResult) + return make_unexpected(readResult.error()); + + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(*readResult, &error); + if (error.error != QJsonParseError::NoError) + return make_unexpected(Tr::tr("JSON parsing error: \"%1\", at offset: %2") + .arg(error.errorString()) + .arg(error.offset)); + + const QJsonObject root = doc.object(); + const auto itColors = root.find("colors"); + if (itColors == root.end()) + return make_unexpected(Tr::tr("No colors found")); + + const QJsonObject colors = itColors->toObject(); + + // clang-format off + const QList> colorKeys = { + qMakePair(u"editor.background", &TerminalSettings::instance().backgroundColor), + qMakePair(u"terminal.foreground", &TerminalSettings::instance().foregroundColor), + qMakePair(u"terminal.selectionBackground", &TerminalSettings::instance().selectionColor), + + qMakePair(u"terminal.ansiBlack", &TerminalSettings::instance().colors[0]), + qMakePair(u"terminal.ansiBrightBlack", &TerminalSettings::instance().colors[8]), + + qMakePair(u"terminal.ansiRed", &TerminalSettings::instance().colors[1]), + qMakePair(u"terminal.ansiBrightRed", &TerminalSettings::instance().colors[9]), + + qMakePair(u"terminal.ansiGreen", &TerminalSettings::instance().colors[2]), + qMakePair(u"terminal.ansiBrightGreen", &TerminalSettings::instance().colors[10]), + + qMakePair(u"terminal.ansiYellow", &TerminalSettings::instance().colors[3]), + qMakePair(u"terminal.ansiBrightYellow", &TerminalSettings::instance().colors[11]), + + qMakePair(u"terminal.ansiBlue", &TerminalSettings::instance().colors[4]), + qMakePair(u"terminal.ansiBrightBlue", &TerminalSettings::instance().colors[12]), + + qMakePair(u"terminal.ansiMagenta", &TerminalSettings::instance().colors[5]), + qMakePair(u"terminal.ansiBrightMagenta", &TerminalSettings::instance().colors[13]), + + qMakePair(u"terminal.ansiCyan", &TerminalSettings::instance().colors[6]), + qMakePair(u"terminal.ansiBrightCyan", &TerminalSettings::instance().colors[14]), + + qMakePair(u"terminal.ansiWhite", &TerminalSettings::instance().colors[7]), + qMakePair(u"terminal.ansiBrightWhite", &TerminalSettings::instance().colors[15]) + }; + // clang-format on + + for (const auto &pair : colorKeys) { + const auto it = colors.find(pair.first); + if (it != colors.end()) { + const QString colorString = it->toString(); + if (colorString.startsWith("#")) { + QColor color(colorString.mid(0, 7)); + if (colorString.size() > 7) { + int alpha = colorString.mid(7).toInt(nullptr, 16); + color.setAlpha(alpha); + } + if (color.isValid()) + pair.second->setVolatileValue(color); + } + } + } + + return {}; +} + +static expected_str loadKonsoleColorScheme(const FilePath &path) +{ + QSettings settings(path.toFSPathString(), QSettings::IniFormat); + + auto parseColor = [](const QStringList &parts) -> expected_str { + if (parts.size() != 3 && parts.size() != 4) + return make_unexpected(Tr::tr("Invalid color format")); + int alpha = parts.size() == 4 ? parts[3].toInt() : 255; + return QColor(parts[0].toInt(), parts[1].toInt(), parts[2].toInt(), alpha); + }; + + // clang-format off + const QList> colorKeys = { + qMakePair(QLatin1String("Background/Color"), &TerminalSettings::instance().backgroundColor), + qMakePair(QLatin1String("Foreground/Color"), &TerminalSettings::instance().foregroundColor), + + qMakePair(QLatin1String("Color0/Color"), &TerminalSettings::instance().colors[0]), + qMakePair(QLatin1String("Color0Intense/Color"), &TerminalSettings::instance().colors[8]), + + qMakePair(QLatin1String("Color1/Color"), &TerminalSettings::instance().colors[1]), + qMakePair(QLatin1String("Color1Intense/Color"), &TerminalSettings::instance().colors[9]), + + qMakePair(QLatin1String("Color2/Color"), &TerminalSettings::instance().colors[2]), + qMakePair(QLatin1String("Color2Intense/Color"), &TerminalSettings::instance().colors[10]), + + qMakePair(QLatin1String("Color3/Color"), &TerminalSettings::instance().colors[3]), + qMakePair(QLatin1String("Color3Intense/Color"), &TerminalSettings::instance().colors[11]), + + qMakePair(QLatin1String("Color4/Color"), &TerminalSettings::instance().colors[4]), + qMakePair(QLatin1String("Color4Intense/Color"), &TerminalSettings::instance().colors[12]), + + qMakePair(QLatin1String("Color5/Color"), &TerminalSettings::instance().colors[5]), + qMakePair(QLatin1String("Color5Intense/Color"), &TerminalSettings::instance().colors[13]), + + qMakePair(QLatin1String("Color6/Color"), &TerminalSettings::instance().colors[6]), + qMakePair(QLatin1String("Color6Intense/Color"), &TerminalSettings::instance().colors[14]), + + qMakePair(QLatin1String("Color7/Color"), &TerminalSettings::instance().colors[7]), + qMakePair(QLatin1String("Color7Intense/Color"), &TerminalSettings::instance().colors[15]) + }; + // clang-format on + + for (const auto &colorKey : colorKeys) { + if (settings.contains(colorKey.first)) { + const auto color = parseColor(settings.value(colorKey.first).toStringList()); + if (!color) + return make_unexpected(color.error()); + + colorKey.second->setVolatileValue(*color); + } + } + + return {}; +} + +static expected_str loadXFCE4ColorScheme(const FilePath &path) +{ + expected_str arr = path.fileContents(); + if (!arr) + return make_unexpected(arr.error()); + + arr->replace(';', ','); + + QTemporaryFile f; + f.open(); + f.write(*arr); + f.close(); + + QSettings settings(f.fileName(), QSettings::IniFormat); + + // clang-format off + const QList> colorKeys = { + qMakePair(QLatin1String("Scheme/ColorBackground"), &TerminalSettings::instance().backgroundColor), + qMakePair(QLatin1String("Scheme/ColorForeground"), &TerminalSettings::instance().foregroundColor), + }; + // clang-format on + + for (const auto &colorKey : colorKeys) { + if (settings.contains(colorKey.first)) { + colorKey.second->setVolatileValue(QColor(settings.value(colorKey.first).toString())); + } + } + + QStringList colors = settings.value(QLatin1String("Scheme/ColorPalette")).toStringList(); + int i = 0; + for (const auto &color : colors) { + TerminalSettings::instance().colors[i++].setVolatileValue(QColor(color)); + } + + return {}; +} + +static expected_str loadColorScheme(const FilePath &path) +{ + if (path.endsWith("Xdefaults")) + return loadXdefaults(path); + else if (path.suffix() == "itermcolors") + return loadItermColors(path); + else if (path.suffix() == "json") + return loadVsCodeColors(path); + else if (path.suffix() == "colorscheme") + return loadKonsoleColorScheme(path); + else if (path.suffix() == "theme" || path.completeSuffix() == "theme.txt") + return loadXFCE4ColorScheme(path); + + return make_unexpected(Tr::tr("Unknown color scheme format")); +} + +static TerminalSettings *s_instance; + +TerminalSettings &TerminalSettings::instance() +{ + return *s_instance; +} + TerminalSettings::TerminalSettings() { + s_instance = this; + setAutoApply(false); setSettingsGroup("Terminal"); + setId("Terminal.General"); + setDisplayName("Terminal"); + setCategory("ZY.Terminal"); + setDisplayCategory("Terminal"); + setSettings(&TerminalSettings::instance()); + setCategoryIconPath(":/terminal/images/settingscategory_terminal.png"); enableTerminal.setSettingsKey("EnableTerminal"); enableTerminal.setLabelText(Tr::tr("Use internal terminal")); @@ -122,15 +427,6 @@ TerminalSettings::TerminalSettings() "character is received.")); audibleBell.setDefaultValue(true); - registerAspect(&font); - registerAspect(&fontSize); - registerAspect(&shell); - registerAspect(&allowBlinkingCursor); - registerAspect(&enableTerminal); - registerAspect(&sendEscapeToTerminal); - registerAspect(&audibleBell); - registerAspect(&shellArguments); - setupColor(this, foregroundColor, "Foreground", @@ -172,6 +468,127 @@ TerminalSettings::TerminalSettings() setupColor(this, colors[7], "7", Utils::creatorTheme()->color(Theme::TerminalAnsi7)); setupColor(this, colors[15], "15", Utils::creatorTheme()->color(Theme::TerminalAnsi15)); + + setLayouter([this] { + using namespace Layouting; + + QFontComboBox *fontComboBox = new QFontComboBox; + fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts); + fontComboBox->setCurrentFont(font()); + + connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [this](const QFont &f) { + font.setValue(f.family()); + }); + + auto loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); + auto resetTheme = new QPushButton(Tr::tr("Reset Theme")); + + connect(loadThemeButton, &QPushButton::clicked, this, [this] { + const FilePath path = FileUtils::getOpenFilePath( + Core::ICore::dialogParent(), + "Open Theme", + {}, + "All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;" + "Xdefaults (.Xdefaults Xdefaults);;" + "iTerm Color Schemes(*.itermcolors);;" + "VS Code Color Schemes(*.json);;" + "Konsole Color Schemes(*.colorscheme);;" + "XFCE4 Terminal Color Schemes(*.theme *.theme.txt);;" + "All files (*)", + nullptr, + {}, + true, + false); + + if (path.isEmpty()) + return; + + const expected_str result = loadColorScheme(path); + if (!result) + QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Error"), result.error()); + }); + + connect(resetTheme, &QPushButton::clicked, this, [this] { + foregroundColor.setVolatileValue(foregroundColor.defaultValue()); + backgroundColor.setVolatileValue(backgroundColor.defaultValue()); + selectionColor.setVolatileValue(selectionColor.defaultValue()); + + for (ColorAspect &color : colors) + color.setVolatileValue(color.defaultValue()); + }); + +// FIXME: Implement and use a Layouting::DropArea item + +// DropSupport *dropSupport = new DropSupport; +// connect(dropSupport, +// &DropSupport::filesDropped, +// this, +// [this](const QList &files) { +// if (files.size() != 1) +// return; + +// const expected_str result = loadColorScheme(files.at(0).filePath); +// if (!result) +// QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Error"), result.error()); +// }); + + // clang-format off + return Column { + Group { + title(Tr::tr("General")), + Column { + enableTerminal, st, + sendEscapeToTerminal, st, + audibleBell, st, + allowBlinkingCursor, st, + }, + }, + Group { + title(Tr::tr("Font")), + Row { + font.labelText(), fontComboBox, Space(20), + fontSize, st, + }, + }, + Group { + title(Tr::tr("Colors")), + Column { + Row { + Tr::tr("Foreground"), foregroundColor, st, + Tr::tr("Background"), backgroundColor, st, + Tr::tr("Selection"), selectionColor, st, + Tr::tr("Find match"), findMatchColor, st, + }, + Row { + colors[0], colors[1], + colors[2], colors[3], + colors[4], colors[5], + colors[6], colors[7] + }, + Row { + colors[8], colors[9], + colors[10], colors[11], + colors[12], colors[13], + colors[14], colors[15] + }, + Row { + loadThemeButton, resetTheme, st, + } + }, + }, + Group { + title(Tr::tr("Default Shell")), + Column { + shell, + shellArguments, + }, + }, + st, + }; + // clang-format on + }); + + readSettings(); } -} // namespace Terminal +} // Terminal diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index 137f3abe3aa..30212b0c3de 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -3,22 +3,23 @@ #pragma once -#include +#include namespace Terminal { -class TerminalSettings : public Utils::AspectContainer + +class TerminalSettings : public Core::PagedSettings { public: TerminalSettings(); static TerminalSettings &instance(); - Utils::BoolAspect enableTerminal; + Utils::BoolAspect enableTerminal{this}; - Utils::StringAspect font; - Utils::IntegerAspect fontSize; - Utils::StringAspect shell; - Utils::StringAspect shellArguments; + Utils::StringAspect font{this}; + Utils::IntegerAspect fontSize{this}; + Utils::StringAspect shell{this}; + Utils::StringAspect shellArguments{this}; Utils::ColorAspect foregroundColor; Utils::ColorAspect backgroundColor; @@ -27,10 +28,10 @@ public: Utils::ColorAspect colors[16]; - Utils::BoolAspect allowBlinkingCursor; + Utils::BoolAspect allowBlinkingCursor{this}; - Utils::BoolAspect sendEscapeToTerminal; - Utils::BoolAspect audibleBell; + Utils::BoolAspect sendEscapeToTerminal{this}; + Utils::BoolAspect audibleBell{this}; }; -} // namespace Terminal +} // Terminal diff --git a/src/plugins/terminal/terminalsettingspage.cpp b/src/plugins/terminal/terminalsettingspage.cpp deleted file mode 100644 index 25a7250a1eb..00000000000 --- a/src/plugins/terminal/terminalsettingspage.cpp +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#include "terminalsettingspage.h" - -#include "terminalsettings.h" -#include "terminaltr.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Utils; - -namespace Terminal { - -static expected_str loadXdefaults(const FilePath &path) -{ - const expected_str readResult = path.fileContents(); - if (!readResult) - return make_unexpected(readResult.error()); - - QRegularExpression re(R"(.*\*(color[0-9]{1,2}|foreground|background):\s*(#[0-9a-f]{6}))"); - - for (const QByteArray &line : readResult->split('\n')) { - if (line.trimmed().startsWith('!')) - continue; - - const auto match = re.match(QString::fromUtf8(line)); - if (match.hasMatch()) { - const QString colorName = match.captured(1); - const QColor color(match.captured(2)); - if (colorName == "foreground") { - TerminalSettings::instance().foregroundColor.setVolatileValue(color); - } else if (colorName == "background") { - TerminalSettings::instance().backgroundColor.setVolatileValue(color); - } else { - const int colorIndex = colorName.mid(5).toInt(); - if (colorIndex >= 0 && colorIndex < 16) - TerminalSettings::instance().colors[colorIndex].setVolatileValue(color); - } - } - } - - return {}; -} - -static expected_str loadItermColors(const FilePath &path) -{ - QFile f(path.toFSPathString()); - const bool opened = f.open(QIODevice::ReadOnly); - if (!opened) - return make_unexpected(Tr::tr("Failed to open file")); - - QXmlStreamReader reader(&f); - while (!reader.atEnd() && reader.readNextStartElement()) { - if (reader.name() == u"plist") { - while (!reader.atEnd() && reader.readNextStartElement()) { - if (reader.name() == u"dict") { - QString colorName; - while (!reader.atEnd() && reader.readNextStartElement()) { - if (reader.name() == u"key") { - colorName = reader.readElementText(); - } else if (reader.name() == u"dict") { - QColor color; - int component = 0; - while (!reader.atEnd() && reader.readNextStartElement()) { - if (reader.name() == u"key") { - const auto &text = reader.readElementText(); - if (text == u"Red Component") - component = 0; - else if (text == u"Green Component") - component = 1; - else if (text == u"Blue Component") - component = 2; - else if (text == u"Alpha Component") - component = 3; - } else if (reader.name() == u"real") { - // clang-format off - switch (component) { - case 0: color.setRedF(reader.readElementText().toDouble()); break; - case 1: color.setGreenF(reader.readElementText().toDouble()); break; - case 2: color.setBlueF(reader.readElementText().toDouble()); break; - case 3: color.setAlphaF(reader.readElementText().toDouble()); break; - } - // clang-format on - } else { - reader.skipCurrentElement(); - } - } - - if (colorName.startsWith("Ansi")) { - const auto c = colorName.mid(5, 2); - const int colorIndex = c.toInt(); - if (colorIndex >= 0 && colorIndex < 16) - TerminalSettings::instance().colors[colorIndex].setVolatileValue( - color); - } else if (colorName == "Foreground Color") { - TerminalSettings::instance().foregroundColor.setVolatileValue(color); - } else if (colorName == "Background Color") { - TerminalSettings::instance().backgroundColor.setVolatileValue(color); - } else if (colorName == "Selection Color") { - TerminalSettings::instance().selectionColor.setVolatileValue(color); - } - } - } - } - } - break; - } - } - if (reader.hasError()) - return make_unexpected(reader.errorString()); - - return {}; -} - -static expected_str loadVsCodeColors(const FilePath &path) -{ - const expected_str readResult = path.fileContents(); - if (!readResult) - return make_unexpected(readResult.error()); - - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(*readResult, &error); - if (error.error != QJsonParseError::NoError) - return make_unexpected(Tr::tr("JSON parsing error: \"%1\", at offset: %2") - .arg(error.errorString()) - .arg(error.offset)); - - const QJsonObject root = doc.object(); - const auto itColors = root.find("colors"); - if (itColors == root.end()) - return make_unexpected(Tr::tr("No colors found")); - - const QJsonObject colors = itColors->toObject(); - - // clang-format off - const QList> colorKeys = { - qMakePair(u"editor.background", &TerminalSettings::instance().backgroundColor), - qMakePair(u"terminal.foreground", &TerminalSettings::instance().foregroundColor), - qMakePair(u"terminal.selectionBackground", &TerminalSettings::instance().selectionColor), - - qMakePair(u"terminal.ansiBlack", &TerminalSettings::instance().colors[0]), - qMakePair(u"terminal.ansiBrightBlack", &TerminalSettings::instance().colors[8]), - - qMakePair(u"terminal.ansiRed", &TerminalSettings::instance().colors[1]), - qMakePair(u"terminal.ansiBrightRed", &TerminalSettings::instance().colors[9]), - - qMakePair(u"terminal.ansiGreen", &TerminalSettings::instance().colors[2]), - qMakePair(u"terminal.ansiBrightGreen", &TerminalSettings::instance().colors[10]), - - qMakePair(u"terminal.ansiYellow", &TerminalSettings::instance().colors[3]), - qMakePair(u"terminal.ansiBrightYellow", &TerminalSettings::instance().colors[11]), - - qMakePair(u"terminal.ansiBlue", &TerminalSettings::instance().colors[4]), - qMakePair(u"terminal.ansiBrightBlue", &TerminalSettings::instance().colors[12]), - - qMakePair(u"terminal.ansiMagenta", &TerminalSettings::instance().colors[5]), - qMakePair(u"terminal.ansiBrightMagenta", &TerminalSettings::instance().colors[13]), - - qMakePair(u"terminal.ansiCyan", &TerminalSettings::instance().colors[6]), - qMakePair(u"terminal.ansiBrightCyan", &TerminalSettings::instance().colors[14]), - - qMakePair(u"terminal.ansiWhite", &TerminalSettings::instance().colors[7]), - qMakePair(u"terminal.ansiBrightWhite", &TerminalSettings::instance().colors[15]) - }; - // clang-format on - - for (const auto &pair : colorKeys) { - const auto it = colors.find(pair.first); - if (it != colors.end()) { - const QString colorString = it->toString(); - if (colorString.startsWith("#")) { - QColor color(colorString.mid(0, 7)); - if (colorString.size() > 7) { - int alpha = colorString.mid(7).toInt(nullptr, 16); - color.setAlpha(alpha); - } - if (color.isValid()) - pair.second->setVolatileValue(color); - } - } - } - - return {}; -} - -static expected_str loadKonsoleColorScheme(const FilePath &path) -{ - QSettings settings(path.toFSPathString(), QSettings::IniFormat); - - auto parseColor = [](const QStringList &parts) -> expected_str { - if (parts.size() != 3 && parts.size() != 4) - return make_unexpected(Tr::tr("Invalid color format")); - int alpha = parts.size() == 4 ? parts[3].toInt() : 255; - return QColor(parts[0].toInt(), parts[1].toInt(), parts[2].toInt(), alpha); - }; - - // clang-format off - const QList> colorKeys = { - qMakePair(QLatin1String("Background/Color"), &TerminalSettings::instance().backgroundColor), - qMakePair(QLatin1String("Foreground/Color"), &TerminalSettings::instance().foregroundColor), - - qMakePair(QLatin1String("Color0/Color"), &TerminalSettings::instance().colors[0]), - qMakePair(QLatin1String("Color0Intense/Color"), &TerminalSettings::instance().colors[8]), - - qMakePair(QLatin1String("Color1/Color"), &TerminalSettings::instance().colors[1]), - qMakePair(QLatin1String("Color1Intense/Color"), &TerminalSettings::instance().colors[9]), - - qMakePair(QLatin1String("Color2/Color"), &TerminalSettings::instance().colors[2]), - qMakePair(QLatin1String("Color2Intense/Color"), &TerminalSettings::instance().colors[10]), - - qMakePair(QLatin1String("Color3/Color"), &TerminalSettings::instance().colors[3]), - qMakePair(QLatin1String("Color3Intense/Color"), &TerminalSettings::instance().colors[11]), - - qMakePair(QLatin1String("Color4/Color"), &TerminalSettings::instance().colors[4]), - qMakePair(QLatin1String("Color4Intense/Color"), &TerminalSettings::instance().colors[12]), - - qMakePair(QLatin1String("Color5/Color"), &TerminalSettings::instance().colors[5]), - qMakePair(QLatin1String("Color5Intense/Color"), &TerminalSettings::instance().colors[13]), - - qMakePair(QLatin1String("Color6/Color"), &TerminalSettings::instance().colors[6]), - qMakePair(QLatin1String("Color6Intense/Color"), &TerminalSettings::instance().colors[14]), - - qMakePair(QLatin1String("Color7/Color"), &TerminalSettings::instance().colors[7]), - qMakePair(QLatin1String("Color7Intense/Color"), &TerminalSettings::instance().colors[15]) - }; - // clang-format on - - for (const auto &colorKey : colorKeys) { - if (settings.contains(colorKey.first)) { - const auto color = parseColor(settings.value(colorKey.first).toStringList()); - if (!color) - return make_unexpected(color.error()); - - colorKey.second->setVolatileValue(*color); - } - } - - return {}; -} - -static expected_str loadXFCE4ColorScheme(const FilePath &path) -{ - expected_str arr = path.fileContents(); - if (!arr) - return make_unexpected(arr.error()); - - arr->replace(';', ','); - - QTemporaryFile f; - f.open(); - f.write(*arr); - f.close(); - - QSettings settings(f.fileName(), QSettings::IniFormat); - - // clang-format off - const QList> colorKeys = { - qMakePair(QLatin1String("Scheme/ColorBackground"), &TerminalSettings::instance().backgroundColor), - qMakePair(QLatin1String("Scheme/ColorForeground"), &TerminalSettings::instance().foregroundColor), - }; - // clang-format on - - for (const auto &colorKey : colorKeys) { - if (settings.contains(colorKey.first)) { - colorKey.second->setVolatileValue(QColor(settings.value(colorKey.first).toString())); - } - } - - QStringList colors = settings.value(QLatin1String("Scheme/ColorPalette")).toStringList(); - int i = 0; - for (const auto &color : colors) { - TerminalSettings::instance().colors[i++].setVolatileValue(QColor(color)); - } - - return {}; -} - -static expected_str loadColorScheme(const FilePath &path) -{ - if (path.endsWith("Xdefaults")) - return loadXdefaults(path); - else if (path.suffix() == "itermcolors") - return loadItermColors(path); - else if (path.suffix() == "json") - return loadVsCodeColors(path); - else if (path.suffix() == "colorscheme") - return loadKonsoleColorScheme(path); - else if (path.suffix() == "theme" || path.completeSuffix() == "theme.txt") - return loadXFCE4ColorScheme(path); - - return make_unexpected(Tr::tr("Unknown color scheme format")); -} - -class TerminalSettingsPageWidget : public Core::IOptionsPageWidget -{ -public: - TerminalSettingsPageWidget() - { - using namespace Layouting; - - QFontComboBox *fontComboBox = new QFontComboBox(this); - fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts); - fontComboBox->setCurrentFont(TerminalSettings::instance().font.value()); - - connect(fontComboBox, &QFontComboBox::currentFontChanged, this, [](const QFont &f) { - TerminalSettings::instance().font.setValue(f.family()); - }); - - TerminalSettings &settings = TerminalSettings::instance(); - - QPushButton *loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); - QPushButton *resetTheme = new QPushButton(Tr::tr("Reset Theme")); - - connect(loadThemeButton, &QPushButton::clicked, this, [this] { - const FilePath path = FileUtils::getOpenFilePath( - this, - "Open Theme", - {}, - "All Scheme formats (*.itermcolors *.json *.colorscheme *.theme *.theme.txt);;" - "Xdefaults (.Xdefaults Xdefaults);;" - "iTerm Color Schemes(*.itermcolors);;" - "VS Code Color Schemes(*.json);;" - "Konsole Color Schemes(*.colorscheme);;" - "XFCE4 Terminal Color Schemes(*.theme *.theme.txt);;" - "All files (*)", - nullptr, - {}, - true, - false); - - if (path.isEmpty()) - return; - - const expected_str result = loadColorScheme(path); - if (!result) - QMessageBox::warning(this, Tr::tr("Error"), result.error()); - }); - - connect(resetTheme, &QPushButton::clicked, this, [] { - TerminalSettings &settings = TerminalSettings::instance(); - settings.foregroundColor.setVolatileValue(settings.foregroundColor.defaultValue()); - settings.backgroundColor.setVolatileValue(settings.backgroundColor.defaultValue()); - settings.selectionColor.setVolatileValue(settings.selectionColor.defaultValue()); - - for (auto &color : settings.colors) - color.setVolatileValue(color.defaultValue()); - }); - - // clang-format off - Column { - Group { - title(Tr::tr("General")), - Column { - settings.enableTerminal, st, - settings.sendEscapeToTerminal, st, - settings.audibleBell, st, - settings.allowBlinkingCursor, st, - }, - }, - Group { - title(Tr::tr("Font")), - Row { - settings.font.labelText(), fontComboBox, Space(20), - settings.fontSize, st, - }, - }, - Group { - title(Tr::tr("Colors")), - Column { - Row { - Tr::tr("Foreground"), settings.foregroundColor, st, - Tr::tr("Background"), settings.backgroundColor, st, - Tr::tr("Selection"), settings.selectionColor, st, - Tr::tr("Find match"), settings.findMatchColor, st, - }, - Row { - settings.colors[0], settings.colors[1], - settings.colors[2], settings.colors[3], - settings.colors[4], settings.colors[5], - settings.colors[6], settings.colors[7] - }, - Row { - settings.colors[8], settings.colors[9], - settings.colors[10], settings.colors[11], - settings.colors[12], settings.colors[13], - settings.colors[14], settings.colors[15] - }, - Row { - loadThemeButton, resetTheme, st, - } - }, - }, - Group { - title(Tr::tr("Default Shell")), - Column { - settings.shell, - settings.shellArguments, - }, - }, - st, - }.attachTo(this); - // clang-format on - - DropSupport *dropSupport = new DropSupport(this); - connect(dropSupport, - &DropSupport::filesDropped, - this, - [this](const QList &files) { - if (files.size() != 1) - return; - - const expected_str result = loadColorScheme(files.at(0).filePath); - if (!result) - QMessageBox::warning(this, Tr::tr("Error"), result.error()); - }); - } - - void apply() final - { - TerminalSettings &settings = TerminalSettings::instance(); - if (settings.isDirty()) { - settings.apply(); - settings.writeSettings(Core::ICore::settings()); - } - } -}; - -// TerminalSettingsPage - -TerminalSettingsPage::TerminalSettingsPage() -{ - setId("Terminal.General"); - setDisplayName("Terminal"); - setCategory("ZY.Terminal"); - setDisplayCategory("Terminal"); - setSettings(&TerminalSettings::instance()); - setCategoryIconPath(":/terminal/images/settingscategory_terminal.png"); - setWidgetCreator([] { return new TerminalSettingsPageWidget; }); -} - -TerminalSettingsPage &TerminalSettingsPage::instance() -{ - static TerminalSettingsPage settingsPage; - return settingsPage; -} - -} // namespace Terminal diff --git a/src/plugins/terminal/terminalsettingspage.h b/src/plugins/terminal/terminalsettingspage.h deleted file mode 100644 index 12d3762844e..00000000000 --- a/src/plugins/terminal/terminalsettingspage.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace Terminal { - -class TerminalSettingsPage : public Core::IOptionsPage -{ -public: - TerminalSettingsPage(); - - static TerminalSettingsPage &instance(); -}; - -} // namespace Terminal From 83b971b2388ece591a56e3c518cf73ba07484a5c Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 May 2023 14:09:41 +0200 Subject: [PATCH 1288/1447] Doc: Mark docs in Utils \internal if classes or functions not found Change-Id: I3182534fefc51f573892d6f80f59ce5613f95fdc Reviewed-by: Eike Ziller --- src/libs/utils/commandline.cpp | 1 + src/libs/utils/filesystemmodel.cpp | 17 +++++++++++++---- src/libs/utils/fsengine/fileiconprovider.cpp | 14 +++++++++++--- src/libs/utils/layoutbuilder.cpp | 5 ++++- src/libs/utils/treemodel.cpp | 13 +++++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index b259aaf7e64..ba1cc4edc46 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -196,6 +196,7 @@ static QStringList doSplitArgsWin(const QString &args, ProcessArgs::SplitError * } /*! + \internal Splits \a _args according to system shell word splitting and quoting rules. \section1 Unix diff --git a/src/libs/utils/filesystemmodel.cpp b/src/libs/utils/filesystemmodel.cpp index 60961c35994..9a10f3b91fc 100644 --- a/src/libs/utils/filesystemmodel.cpp +++ b/src/libs/utils/filesystemmodel.cpp @@ -209,7 +209,8 @@ private: }; /*! - Creates thread + \internal + Creates a thread. */ FileInfoGatherer::FileInfoGatherer(QObject *parent) : QThread(parent) @@ -219,7 +220,8 @@ FileInfoGatherer::FileInfoGatherer(QObject *parent) } /*! - Destroys thread + \internal + Destroys a thread. */ FileInfoGatherer::~FileInfoGatherer() { @@ -265,6 +267,7 @@ QFileIconProvider *FileInfoGatherer::iconProvider() const } /*! + \internal Fetch extended information for all \a files in \a path \sa updateFile(), update(), resolvedName() @@ -295,6 +298,7 @@ void FileInfoGatherer::fetchExtendedInformation(const QString &path, const QStri } /*! + \internal Fetch extended information for all \a filePath \sa fetchExtendedInformation() @@ -1719,7 +1723,7 @@ QStringList FileSystemModel::mimeTypes() const \a indexes. The format used to describe the items corresponding to the indexes is obtained from the mimeTypes() function. - If the list of indexes is empty, \nullptr is returned rather than a + If the list of indexes is empty, \c nullptr is returned rather than a serialized empty list. */ QMimeData *FileSystemModel::mimeData(const QModelIndexList &indexes) const @@ -1799,7 +1803,8 @@ QHash FileSystemModel::roleNames() const } /*! - \enum FileSystemModel::Option + \internal + \enum Utils::FileSystemModel::Option \since 5.14 \value DontWatchForChanges Do not add file watchers to the paths. @@ -1847,6 +1852,7 @@ bool FileSystemModel::testOption(Option option) const } /*! + \internal \property FileSystemModel::options \brief the various options that affect the model \since 5.14 @@ -2121,6 +2127,7 @@ QDir::Filters FileSystemModel::filter() const } /*! + \internal \property FileSystemModel::resolveSymlinks \brief Whether the directory model should resolve symbolic links @@ -2146,6 +2153,7 @@ bool FileSystemModel::resolveSymlinks() const } /*! + \internal \property FileSystemModel::readOnly \brief Whether the directory model allows writing to the file system @@ -2165,6 +2173,7 @@ bool FileSystemModel::isReadOnly() const } /*! + \internal \property FileSystemModel::nameFilterDisables \brief Whether files that don't pass the name filter are hidden or disabled diff --git a/src/libs/utils/fsengine/fileiconprovider.cpp b/src/libs/utils/fsengine/fileiconprovider.cpp index 07ea4b3f5a8..cd2cc060a21 100644 --- a/src/libs/utils/fsengine/fileiconprovider.cpp +++ b/src/libs/utils/fsengine/fileiconprovider.cpp @@ -28,6 +28,7 @@ Q_LOGGING_CATEGORY(fileIconProvider, "qtc.core.fileiconprovider", QtWarningMsg) /*! \class Utils::FileIconProvider + \internal \inmodule QtCreator \brief Provides functions for registering custom overlay icons for system icons. @@ -220,6 +221,7 @@ QIcon FileIconProviderImplementation::icon(const FilePath &filePath) const } /*! + \internal Returns the icon associated with the file suffix in \a filePath. If there is none, the default icon of the operating system is returned. */ @@ -230,14 +232,16 @@ QIcon icon(const FilePath &filePath) } /*! - * \overload - */ + \internal + \overload +*/ QIcon icon(QFileIconProvider::IconType type) { return instance()->icon(type); } /*! + \internal Creates a pixmap with \a baseIcon and lays \a overlayIcon over it. */ QPixmap overlayIcon(const QPixmap &baseIcon, const QIcon &overlayIcon) @@ -249,6 +253,7 @@ QPixmap overlayIcon(const QPixmap &baseIcon, const QIcon &overlayIcon) } /*! + \internal Creates a pixmap with \a baseIcon at \a size and \a overlay. */ QPixmap overlayIcon(QStyle::StandardPixmap baseIcon, const QIcon &overlay, const QSize &size) @@ -257,6 +262,7 @@ QPixmap overlayIcon(QStyle::StandardPixmap baseIcon, const QIcon &overlay, const } /*! + \internal Registers an icon at \a path for a given \a suffix, overlaying the system file icon. */ @@ -266,6 +272,7 @@ void registerIconOverlayForSuffix(const QString &path, const QString &suffix) } /*! + \internal Registers \a icon for all the suffixes of a the mime type \a mimeType, overlaying the system file icon. */ @@ -275,7 +282,8 @@ void registerIconOverlayForMimeType(const QIcon &icon, const QString &mimeType) } /*! - * \overload + \internal + \overload */ void registerIconOverlayForMimeType(const QString &path, const QString &mimeType) { diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index b603b0bf8ff..bea7faafd3b 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -205,6 +205,7 @@ LayoutItem::~LayoutItem() = default; /*! \fn template LayoutItem(const T &t) + \internal Constructs a layout item proxy for \a t. @@ -489,6 +490,7 @@ void doAddWidget(LayoutBuilder &builder, QWidget *widget) /*! \class Layouting::LayoutBuilder + \internal \inmodule QtCreator \brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout @@ -505,6 +507,7 @@ void doAddWidget(LayoutBuilder &builder, QWidget *widget) LayoutBuilder::LayoutBuilder() = default; /*! + \internal Destructs a layout builder. */ LayoutBuilder::~LayoutBuilder() = default; @@ -521,7 +524,7 @@ void LayoutBuilder::addItems(const LayoutItems &items) } /*! - This starts a new row containing \a items. The row can be further extended by + Starts a new row containing \a items. The row can be further extended by other items using \c addItem() or \c addItems(). \sa addItem(), addItems() diff --git a/src/libs/utils/treemodel.cpp b/src/libs/utils/treemodel.cpp index 53477b53c97..e5e5aa59b99 100644 --- a/src/libs/utils/treemodel.cpp +++ b/src/libs/utils/treemodel.cpp @@ -72,6 +72,7 @@ private: }; /*! + \internal Connect to all of the models signals. Whenever anything happens recheck everything. */ @@ -135,6 +136,7 @@ void ModelTest::runAllTests() } /*! + \internal nonDestructiveBasicTest tries to call a number of the basic functions (not all) to make sure the model doesn't outright segfault, testing the functions that makes sense. */ @@ -173,6 +175,7 @@ void ModelTest::nonDestructiveBasicTest() } /*! + \internal Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren() Models that are dynamically populated are not as fully tested here. @@ -200,6 +203,7 @@ void ModelTest::rowCount() } /*! + \internal Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren() */ void ModelTest::columnCount() @@ -218,6 +222,7 @@ void ModelTest::columnCount() } /*! + \internal Tests model's implementation of QAbstractItemModel::hasIndex() */ void ModelTest::hasIndex() @@ -242,6 +247,7 @@ void ModelTest::hasIndex() } /*! + \internal Tests model's implementation of QAbstractItemModel::index() */ void ModelTest::index() @@ -274,6 +280,7 @@ void ModelTest::index() } /*! + \internal Tests model's implementation of QAbstractItemModel::parent() */ void ModelTest::parent() @@ -322,6 +329,7 @@ void ModelTest::parent() } /*! + \internal Called from the parent() test. A model that returns an index of parent X should also return X when asking @@ -430,6 +438,7 @@ void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth) } /*! + \internal Tests model's implementation of QAbstractItemModel::data() */ void ModelTest::data() @@ -494,6 +503,7 @@ void ModelTest::data() } /*! + \internal Store what is about to be inserted to make sure it actually happens \sa rowsInserted() @@ -510,6 +520,7 @@ void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int } /*! + \internal Confirm that what was said was going to happen actually did \sa rowsAboutToBeInserted() @@ -547,6 +558,7 @@ void ModelTest::layoutChanged() } /*! + \internal Store what is about to be inserted to make sure it actually happens \sa rowsRemoved() @@ -562,6 +574,7 @@ void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e } /*! + \internal Confirm that what was said was going to happen actually did \sa rowsAboutToBeRemoved() From 48e2c66a4ee8c19be0e28fddfe996e9526506216 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 26 May 2023 09:11:00 +0200 Subject: [PATCH 1289/1447] Doc: Remove docs for Utils::SynchronousProcess ...that has been integrated into QtcProcess. Change-Id: I39b6e4cb5d713d59345015b2a471cd4e6ef99f57 Reviewed-by: Eike Ziller --- src/libs/utils/process.cpp | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/libs/utils/process.cpp b/src/libs/utils/process.cpp index 9a798ec11cf..85d3fa54ed0 100644 --- a/src/libs/utils/process.cpp +++ b/src/libs/utils/process.cpp @@ -1595,37 +1595,6 @@ QString Process::readAllStandardError() return QString::fromUtf8(readAllRawStandardError()); } -/*! - \class Utils::SynchronousProcess - \inmodule QtCreator - - \brief The SynchronousProcess class runs a synchronous process in its own - event loop that blocks only user input events. Thus, it allows for the GUI to - repaint and append output to log windows. - - The callbacks set with setStdOutCallback(), setStdErrCallback() are called - with complete lines based on the '\\n' marker. - They would typically be used for log windows. - - Alternatively you can used setStdOutLineCallback() and setStdErrLineCallback() - to process the output line by line. - - There is a timeout handling that takes effect after the last data have been - read from stdout/stdin (as opposed to waitForFinished(), which measures time - since it was invoked). It is thus also suitable for slow processes that - continuously output data (like version system operations). - - The property timeOutMessageBoxEnabled influences whether a message box is - shown asking the user if they want to kill the process on timeout (default: false). - - There are also static utility functions for dealing with fully synchronous - processes, like reading the output with correct timeout handling. - - Caution: This class should NOT be used if there is a chance that the process - triggers opening dialog boxes (for example, by file watchers triggering), - as this will cause event loop problems. -*/ - QString Process::exitMessage() const { const QString fullCmd = commandLine().toUserOutput(); From 13e9125d1d628d418a54baa1aa62ab6986280f02 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 09:40:36 +0200 Subject: [PATCH 1290/1447] Update qbs submodule to HEAD of 2.0 branch Change-Id: I44c759f26b98da440cc75cce4b8da97d4b202054 Reviewed-by: Christian Stenger --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index dc4da2ef8aa..eaeba4a45e7 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit dc4da2ef8aaf63ab837da0aa7689a5b18e34ace8 +Subproject commit eaeba4a45e7d95b7bb3f4fe907e862d947faf092 From d2ed96a055a7cc4b65d2bb2c32df300b226af57d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 09:34:20 +0200 Subject: [PATCH 1291/1447] VariableChooser: Use same type name for declaration & definition Fixes documentation issue. Change-Id: Id237998b651bdf7887a0be846464265f734001c4 Reviewed-by: Qt CI Bot Reviewed-by: Leena Miettinen Reviewed-by: hjk --- src/libs/utils/variablechooser.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/variablechooser.h b/src/libs/utils/variablechooser.h index 1fe08a1e59b..257dcea5e2c 100644 --- a/src/libs/utils/variablechooser.h +++ b/src/libs/utils/variablechooser.h @@ -13,6 +13,8 @@ namespace Utils { class MacroExpander; +using MacroExpanderProvider = std::function; + namespace Internal { class VariableChooserPrivate; } class QTCREATOR_UTILS_EXPORT VariableChooser : public QWidget @@ -23,7 +25,7 @@ public: explicit VariableChooser(QWidget *parent = nullptr); ~VariableChooser() override; - void addMacroExpanderProvider(const std::function &provider); + void addMacroExpanderProvider(const MacroExpanderProvider &provider); void addSupportedWidget(QWidget *textcontrol, const QByteArray &ownName = QByteArray()); static void addSupportForChildWidgets(QWidget *parent, MacroExpander *expander); From 0e60643430fb7e630038a7da0fe7060911fd5cda Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 09:25:44 +0200 Subject: [PATCH 1292/1447] AutoTest: Register more aspects directly Change-Id: I4dbf9cebb12fecc765aeac8e082061c29496f81a Reviewed-by: Christian Stenger --- src/plugins/autotest/testsettings.cpp | 13 ------------- src/plugins/autotest/testsettings.h | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp index 001bf7fe07c..b4507a9d9ab 100644 --- a/src/plugins/autotest/testsettings.cpp +++ b/src/plugins/autotest/testsettings.cpp @@ -28,7 +28,6 @@ TestSettings::TestSettings() setSettingsGroup(Constants::SETTINGSGROUP); - registerAspect(&timeout); timeout.setSettingsKey("Timeout"); timeout.setDefaultValue(defaultTimeout); timeout.setRange(5000, 36'000'000); // 36 Mio ms = 36'000 s = 10 h @@ -37,44 +36,37 @@ TestSettings::TestSettings() timeout.setToolTip(Tr::tr("Timeout used when executing test cases. This will apply " "for each test case on its own, not the whole project.")); - registerAspect(&omitInternalMsg); omitInternalMsg.setSettingsKey("OmitInternal"); omitInternalMsg.setDefaultValue(true); omitInternalMsg.setLabelText(Tr::tr("Omit internal messages")); omitInternalMsg.setToolTip(Tr::tr("Hides internal messages by default. " "You can still enable them by using the test results filter.")); - registerAspect(&omitRunConfigWarn); omitRunConfigWarn.setSettingsKey("OmitRCWarnings"); omitRunConfigWarn.setLabelText(Tr::tr("Omit run configuration warnings")); omitRunConfigWarn.setToolTip(Tr::tr("Hides warnings related to a deduced run configuration.")); - registerAspect(&limitResultOutput); limitResultOutput.setSettingsKey("LimitResultOutput"); limitResultOutput.setDefaultValue(true); limitResultOutput.setLabelText(Tr::tr("Limit result output")); limitResultOutput.setToolTip(Tr::tr("Limits result output to 100000 characters.")); - registerAspect(&limitResultDescription); limitResultDescription.setSettingsKey("LimitResultDescription"); limitResultDescription.setLabelText(Tr::tr("Limit result description:")); limitResultDescription.setToolTip( Tr::tr("Limit number of lines shown in test result tooltip and description.")); - registerAspect(&resultDescriptionMaxSize); resultDescriptionMaxSize.setSettingsKey("ResultDescriptionMaxSize"); resultDescriptionMaxSize.setDefaultValue(10); resultDescriptionMaxSize.setRange(1, 100000); resultDescriptionMaxSize.setEnabler(&limitResultDescription); - registerAspect(&autoScroll); autoScroll.setSettingsKey("AutoScrollResults"); autoScroll.setDefaultValue(true); autoScroll.setLabelText(Tr::tr("Automatically scroll results")); autoScroll.setToolTip(Tr::tr("Automatically scrolls down when new items are added " "and scrollbar is at bottom.")); - registerAspect(&processArgs); processArgs.setSettingsKey("ProcessArgs"); processArgs.setLabelText(Tr::tr("Process arguments")); processArgs.setToolTip( @@ -82,31 +74,26 @@ TestSettings::TestSettings() "Warning: this is an experimental feature and might lead to failing to " "execute the test executable.")); - registerAspect(&displayApplication); displayApplication.setSettingsKey("DisplayApp"); displayApplication.setLabelText(Tr::tr("Group results by application")); - registerAspect(&popupOnStart); popupOnStart.setSettingsKey("PopupOnStart"); popupOnStart.setLabelText(Tr::tr("Open results when tests start")); popupOnStart.setToolTip( Tr::tr("Displays test results automatically when tests are started.")); - registerAspect(&popupOnFinish); popupOnFinish.setSettingsKey("PopupOnFinish"); popupOnFinish.setDefaultValue(true); popupOnFinish.setLabelText(Tr::tr("Open results when tests finish")); popupOnFinish.setToolTip( Tr::tr("Displays test results automatically when tests are finished.")); - registerAspect(&popupOnFail); popupOnFail.setSettingsKey("PopupOnFail"); popupOnFail.setLabelText(Tr::tr("Only for unsuccessful test runs")); popupOnFail.setEnabler(&popupOnFinish); popupOnFail.setToolTip(Tr::tr("Displays test results only if the test run contains " "failed, fatal or unexpectedly passed tests.")); - registerAspect(&runAfterBuild); runAfterBuild.setSettingsKey("RunAfterBuild"); runAfterBuild.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox); runAfterBuild.setToolTip(Tr::tr("Runs chosen tests automatically if a build succeeded.")); diff --git a/src/plugins/autotest/testsettings.h b/src/plugins/autotest/testsettings.h index b4aec87f49d..1e33269bd4f 100644 --- a/src/plugins/autotest/testsettings.h +++ b/src/plugins/autotest/testsettings.h @@ -32,19 +32,19 @@ public: void toSettings(QSettings *s) const; void fromSettings(QSettings *s); - Utils::IntegerAspect timeout; - Utils::BoolAspect omitInternalMsg; - Utils::BoolAspect omitRunConfigWarn; - Utils::BoolAspect limitResultOutput; - Utils::BoolAspect limitResultDescription; - Utils::IntegerAspect resultDescriptionMaxSize; - Utils::BoolAspect autoScroll; - Utils::BoolAspect processArgs; - Utils::BoolAspect displayApplication; - Utils::BoolAspect popupOnStart; - Utils::BoolAspect popupOnFinish; - Utils::BoolAspect popupOnFail; - Utils::SelectionAspect runAfterBuild; + Utils::IntegerAspect timeout{this}; + Utils::BoolAspect omitInternalMsg{this}; + Utils::BoolAspect omitRunConfigWarn{this}; + Utils::BoolAspect limitResultOutput{this}; + Utils::BoolAspect limitResultDescription{this}; + Utils::IntegerAspect resultDescriptionMaxSize{this}; + Utils::BoolAspect autoScroll{this}; + Utils::BoolAspect processArgs{this}; + Utils::BoolAspect displayApplication{this}; + Utils::BoolAspect popupOnStart{this}; + Utils::BoolAspect popupOnFinish{this}; + Utils::BoolAspect popupOnFail{this}; + Utils::SelectionAspect runAfterBuild{this}; RunAfterBuildMode runAfterBuildMode() const; }; From b47df2a30482e4588ec4b715502065f34b7bbed0 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:14:35 +0200 Subject: [PATCH 1293/1447] Copilot: Register settings aspects more directly Also simplify a search. Change-Id: I2ba511ca3250c624fb7dbc2b44f845a5757e72ce Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilotsettings.cpp | 7 +------ src/plugins/copilot/copilotsettings.h | 6 +++--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index 202da82488f..8c701448eb1 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -32,11 +32,8 @@ CopilotSettings::CopilotSettings() FilePath::fromUserInput( "~/AppData/Local/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js")}; - const FilePath distFromVim = Utils::findOrDefault(searchDirs, [](const FilePath &fp) { - return fp.exists(); - }); + const FilePath distFromVim = Utils::findOrDefault(searchDirs, &FilePath::exists); - registerAspect(&nodeJsPath); nodeJsPath.setExpectedKind(PathChooser::ExistingCommand); nodeJsPath.setDefaultFilePath(nodeFromPath); nodeJsPath.setSettingsKey("Copilot.NodeJsPath"); @@ -47,7 +44,6 @@ CopilotSettings::CopilotSettings() Tr::tr("Select path to node.js executable. See https://nodejs.org/de/download/" "for installation instructions.")); - registerAspect(&distPath); distPath.setExpectedKind(PathChooser::File); distPath.setDefaultFilePath(distFromVim); distPath.setSettingsKey("Copilot.DistPath"); @@ -58,7 +54,6 @@ CopilotSettings::CopilotSettings() "Select path to agent.js in copilot neovim plugin. See " "https://github.com/github/copilot.vim#getting-started for installation instructions.")); - registerAspect(&autoComplete); autoComplete.setDisplayName(Tr::tr("Auto Complete")); autoComplete.setLabelText(Tr::tr("Request completions automatically")); autoComplete.setDefaultValue(true); diff --git a/src/plugins/copilot/copilotsettings.h b/src/plugins/copilot/copilotsettings.h index 23370948765..ea3ac7520f5 100644 --- a/src/plugins/copilot/copilotsettings.h +++ b/src/plugins/copilot/copilotsettings.h @@ -14,9 +14,9 @@ public: static CopilotSettings &instance(); - Utils::FilePathAspect nodeJsPath; - Utils::FilePathAspect distPath; - Utils::BoolAspect autoComplete; + Utils::FilePathAspect nodeJsPath{this}; + Utils::FilePathAspect distPath{this}; + Utils::BoolAspect autoComplete{this}; }; } // namespace Copilot From 4e60203132029dfb00c2c6a59fd247015615ae53 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:01:47 +0200 Subject: [PATCH 1294/1447] Beautifier: Register aspects more directly Change-Id: I406f34901a6488aa843bd2045286c008aff29e3e Reviewed-by: Christian Stenger --- src/plugins/beautifier/abstractsettings.cpp | 2 -- src/plugins/beautifier/abstractsettings.h | 6 +++--- .../artisticstyle/artisticstylesettings.cpp | 6 ------ .../artisticstyle/artisticstylesettings.h | 12 ++++++------ .../beautifier/clangformat/clangformatsettings.cpp | 5 ----- .../beautifier/clangformat/clangformatsettings.h | 8 ++++---- src/plugins/beautifier/generalsettings.cpp | 4 ---- src/plugins/beautifier/generalsettings.h | 8 ++++---- .../beautifier/uncrustify/uncrustifysettings.cpp | 7 ------- .../beautifier/uncrustify/uncrustifysettings.h | 14 +++++++------- 10 files changed, 24 insertions(+), 48 deletions(-) diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp index c80d4f6ac7b..9b340cf9b37 100644 --- a/src/plugins/beautifier/abstractsettings.cpp +++ b/src/plugins/beautifier/abstractsettings.cpp @@ -87,13 +87,11 @@ AbstractSettings::AbstractSettings(const QString &name, const QString &ending) { setSettingsGroups(Utils::Constants::BEAUTIFIER_SETTINGS_GROUP, name); - registerAspect(&command); command.setSettingsKey("command"); command.setExpectedKind(Utils::PathChooser::ExistingCommand); command.setCommandVersionArguments({"--version"}); command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle("Clang Format")); - registerAspect(&supportedMimeTypes); supportedMimeTypes.setDisplayStyle(StringAspect::LineEditDisplay); supportedMimeTypes.setSettingsKey("supportedMime"); supportedMimeTypes.setLabelText(Tr::tr("Restrict to MIME types:")); diff --git a/src/plugins/beautifier/abstractsettings.h b/src/plugins/beautifier/abstractsettings.h index 3ef47ac35b1..6b34baf58be 100644 --- a/src/plugins/beautifier/abstractsettings.h +++ b/src/plugins/beautifier/abstractsettings.h @@ -49,9 +49,9 @@ public: void replaceStyle(const QString &oldKey, const QString &newKey, const QString &value); virtual QString styleFileName(const QString &key) const; - Utils::FilePathAspect command; - Utils::StringAspect supportedMimeTypes; - Utils::FilePathAspect documentationFilePath; + Utils::FilePathAspect command{this}; + Utils::StringAspect supportedMimeTypes{this}; + Utils::FilePathAspect documentationFilePath; // Intentionally not saved. QVersionNumber version() const; diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp index 78537df1970..36bd39c3c55 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp @@ -39,30 +39,24 @@ ArtisticStyleSettings::ArtisticStyleSettings() command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle( Tr::tr(Constants::ARTISTICSTYLE_DISPLAY_NAME))); - registerAspect(&useOtherFiles); useOtherFiles.setSettingsKey("useOtherFiles"); useOtherFiles.setLabelText(Tr::tr("Use file *.astylerc defined in project files")); useOtherFiles.setDefaultValue(true); - registerAspect(&useSpecificConfigFile); useSpecificConfigFile.setSettingsKey("useSpecificConfigFile"); useSpecificConfigFile.setLabelText(Tr::tr("Use specific config file:")); - registerAspect(&specificConfigFile); specificConfigFile.setSettingsKey("specificConfigFile"); specificConfigFile.setExpectedKind(PathChooser::File); specificConfigFile.setPromptDialogFilter(Tr::tr("AStyle (*.astylerc)")); - registerAspect(&useHomeFile); useHomeFile.setSettingsKey("useHomeFile"); useHomeFile.setLabelText(Tr::tr("Use file .astylerc or astylerc in HOME"). replace("HOME", QDir::toNativeSeparators(QDir::home().absolutePath()))); - registerAspect(&useCustomStyle); useCustomStyle.setSettingsKey("useCustomStyle"); useCustomStyle.setLabelText(Tr::tr("Use customized style:")); - registerAspect(&customStyle); customStyle.setSettingsKey("customStyle"); documentationFilePath.setFilePath( diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.h b/src/plugins/beautifier/artisticstyle/artisticstylesettings.h index 5b74f8d1a03..25932cf8db8 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.h +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.h @@ -12,12 +12,12 @@ class ArtisticStyleSettings : public AbstractSettings public: ArtisticStyleSettings(); - Utils::BoolAspect useOtherFiles; - Utils::BoolAspect useSpecificConfigFile; - Utils::FilePathAspect specificConfigFile; - Utils::BoolAspect useHomeFile; - Utils::BoolAspect useCustomStyle; - Utils::StringAspect customStyle; + Utils::BoolAspect useOtherFiles{this}; + Utils::BoolAspect useSpecificConfigFile{this}; + Utils::FilePathAspect specificConfigFile{this}; + Utils::BoolAspect useHomeFile{this}; + Utils::BoolAspect useCustomStyle{this}; + Utils::StringAspect customStyle{this}; void createDocumentationFile() const override; }; diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.cpp b/src/plugins/beautifier/clangformat/clangformatsettings.cpp index dc061ed9658..40477b6ca82 100644 --- a/src/plugins/beautifier/clangformat/clangformatsettings.cpp +++ b/src/plugins/beautifier/clangformat/clangformatsettings.cpp @@ -33,12 +33,10 @@ ClangFormatSettings::ClangFormatSettings() command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle("Clang Format")); command.setLabelText(Tr::tr("Clang Format command:")); - registerAspect(&usePredefinedStyle); usePredefinedStyle.setSettingsKey("usePredefinedStyle"); usePredefinedStyle.setLabelText(Tr::tr("Use predefined style:")); usePredefinedStyle.setDefaultValue(true); - registerAspect(&predefinedStyle); predefinedStyle.setSettingsKey("predefinedStyle"); predefinedStyle.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); predefinedStyle.addOption("LLVM"); @@ -49,7 +47,6 @@ ClangFormatSettings::ClangFormatSettings() predefinedStyle.addOption("File"); predefinedStyle.setDefaultValue("LLVM"); - registerAspect(&fallbackStyle); fallbackStyle.setSettingsKey("fallbackStyle"); fallbackStyle.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); fallbackStyle.addOption("Default"); @@ -61,11 +58,9 @@ ClangFormatSettings::ClangFormatSettings() fallbackStyle.addOption("WebKit"); fallbackStyle.setDefaultValue("Default"); - registerAspect(&predefinedStyle); predefinedStyle.setSettingsKey("predefinedStyle"); predefinedStyle.setDefaultValue("LLVM"); - registerAspect(&customStyle); customStyle.setSettingsKey("customStyle"); documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME) diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.h b/src/plugins/beautifier/clangformat/clangformatsettings.h index 22c16eafc3d..64f2b4b9bbd 100644 --- a/src/plugins/beautifier/clangformat/clangformatsettings.h +++ b/src/plugins/beautifier/clangformat/clangformatsettings.h @@ -16,10 +16,10 @@ public: QStringList completerWords() override; - Utils::BoolAspect usePredefinedStyle; - Utils::SelectionAspect predefinedStyle; - Utils::SelectionAspect fallbackStyle; - Utils::StringAspect customStyle; + Utils::BoolAspect usePredefinedStyle{this}; + Utils::SelectionAspect predefinedStyle{this}; + Utils::SelectionAspect fallbackStyle{this}; + Utils::StringAspect customStyle{this}; QString styleFileName(const QString &key) const override; diff --git a/src/plugins/beautifier/generalsettings.cpp b/src/plugins/beautifier/generalsettings.cpp index 1f6d515d8e7..2f7dc4c3a0c 100644 --- a/src/plugins/beautifier/generalsettings.cpp +++ b/src/plugins/beautifier/generalsettings.cpp @@ -23,23 +23,19 @@ GeneralSettings::GeneralSettings() setCategoryIconPath(":/beautifier/images/settingscategory_beautifier.png"); setSettingsGroups("Beautifier", "General"); - registerAspect(&autoFormatOnSave); autoFormatOnSave.setSettingsKey(Utils::Constants::BEAUTIFIER_AUTO_FORMAT_ON_SAVE); autoFormatOnSave.setDefaultValue(false); autoFormatOnSave.setLabelText(Tr::tr("Enable auto format on file save")); - registerAspect(&autoFormatOnlyCurrentProject); autoFormatOnlyCurrentProject.setSettingsKey("autoFormatOnlyCurrentProject"); autoFormatOnlyCurrentProject.setDefaultValue(true); autoFormatOnlyCurrentProject.setLabelText(Tr::tr("Restrict to files contained in the current project")); - registerAspect(&autoFormatTools); autoFormatTools.setSettingsKey("autoFormatTool"); autoFormatTools.setLabelText(Tr::tr("Tool:")); autoFormatTools.setDefaultValue(0); autoFormatTools.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); - registerAspect(&autoFormatMime); autoFormatMime.setSettingsKey("autoFormatMime"); autoFormatMime.setDefaultValue("text/x-c++src;text/x-c++hdr"); autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:")); diff --git a/src/plugins/beautifier/generalsettings.h b/src/plugins/beautifier/generalsettings.h index 5403c66410c..0be68b98e35 100644 --- a/src/plugins/beautifier/generalsettings.h +++ b/src/plugins/beautifier/generalsettings.h @@ -16,10 +16,10 @@ public: QList allowedMimeTypes() const; - Utils::BoolAspect autoFormatOnSave; - Utils::BoolAspect autoFormatOnlyCurrentProject; - Utils::SelectionAspect autoFormatTools; - Utils::StringAspect autoFormatMime; + Utils::BoolAspect autoFormatOnSave{this}; + Utils::BoolAspect autoFormatOnlyCurrentProject{this}; + Utils::SelectionAspect autoFormatTools{this}; + Utils::StringAspect autoFormatMime{this}; }; } // Beautifier::Internal diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp index 8fefa851d0c..823471681fc 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp @@ -41,34 +41,27 @@ UncrustifySettings::UncrustifySettings() command.setPromptDialogTitle(BeautifierPlugin::msgCommandPromptDialogTitle( Tr::tr(Constants::UNCRUSTIFY_DISPLAY_NAME))); - registerAspect(&useOtherFiles); useOtherFiles.setSettingsKey("useOtherFiles"); useOtherFiles.setDefaultValue(true); useOtherFiles.setLabelText(Tr::tr("Use file uncrustify.cfg defined in project files")); - registerAspect(&useHomeFile); useHomeFile.setSettingsKey("useHomeFile"); useHomeFile.setLabelText(Tr::tr("Use file uncrustify.cfg in HOME") .replace( "HOME", QDir::toNativeSeparators(QDir::home().absolutePath()))); - registerAspect(&useCustomStyle); useCustomStyle.setSettingsKey("useCustomStyle"); useCustomStyle.setLabelText(Tr::tr("Use customized style:")); - registerAspect(&useSpecificConfigFile); useSpecificConfigFile.setSettingsKey("useSpecificConfigFile"); useSpecificConfigFile.setLabelText(Tr::tr("Use file specific uncrustify.cfg")); - registerAspect(&customStyle); customStyle.setSettingsKey("customStyle"); - registerAspect(&formatEntireFileFallback); formatEntireFileFallback.setSettingsKey("formatEntireFileFallback"); formatEntireFileFallback.setDefaultValue(true); formatEntireFileFallback.setLabelText(Tr::tr("Format entire file if no text was selected")); formatEntireFileFallback.setToolTip(Tr::tr("For action Format Selected Text")); - registerAspect(&specificConfigFile); specificConfigFile.setSettingsKey("specificConfigFile"); specificConfigFile.setExpectedKind(Utils::PathChooser::File); specificConfigFile.setPromptDialogFilter(Tr::tr("Uncrustify file (*.cfg)")); diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.h b/src/plugins/beautifier/uncrustify/uncrustifysettings.h index c0de1b891b2..3911cfa9e94 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.h +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.h @@ -14,15 +14,15 @@ public: void createDocumentationFile() const override; - Utils::BoolAspect useOtherFiles; - Utils::BoolAspect useHomeFile; - Utils::BoolAspect useCustomStyle; + Utils::BoolAspect useOtherFiles{this}; + Utils::BoolAspect useHomeFile{this}; + Utils::BoolAspect useCustomStyle{this}; - Utils::StringAspect customStyle; - Utils::BoolAspect formatEntireFileFallback; + Utils::StringAspect customStyle{this}; + Utils::BoolAspect formatEntireFileFallback{this}; - Utils::FilePathAspect specificConfigFile; - Utils::BoolAspect useSpecificConfigFile; + Utils::FilePathAspect specificConfigFile{this}; + Utils::BoolAspect useSpecificConfigFile{this}; }; class UncrustifyOptionsPage final : public Core::IOptionsPage From a69489cd1efe8d668a63c5021ea8dc7809844ad2 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:11:55 +0200 Subject: [PATCH 1295/1447] CMakeProjectManager: Register settings aspects more directly Change-Id: I7bfbe3ad625b0902561975968221e90ce6af06d6 Reviewed-by: Christian Stenger --- src/plugins/cmakeprojectmanager/cmakeformatter.cpp | 12 ++++-------- .../cmakeprojectmanager/cmakespecificsettings.cpp | 7 ------- .../cmakeprojectmanager/cmakespecificsettings.h | 14 +++++++------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp index e12ab4b278d..295b664b9a0 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp @@ -50,21 +50,17 @@ public: setDisplayCategory("CMake"); setCategory(Constants::Settings::CATEGORY); - registerAspect(&command); command.setSettingsKey("autoFormatCommand"); command.setDefaultValue("cmake-format"); command.setExpectedKind(PathChooser::ExistingCommand); - registerAspect(&autoFormatOnSave); autoFormatOnSave.setSettingsKey("autoFormatOnSave"); autoFormatOnSave.setLabelText(Tr::tr("Enable auto format on file save")); - registerAspect(&autoFormatOnlyCurrentProject); autoFormatOnlyCurrentProject.setSettingsKey("autoFormatOnlyCurrentProject"); autoFormatOnlyCurrentProject.setDefaultValue(true); autoFormatOnlyCurrentProject.setLabelText(Tr::tr("Restrict to files contained in the current project")); - registerAspect(&autoFormatMime); autoFormatMime.setSettingsKey("autoFormatMime"); autoFormatMime.setDefaultValue("text/x-cmake"); autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:")); @@ -127,10 +123,10 @@ public: return cmd; } - FilePathAspect command; - BoolAspect autoFormatOnSave; - BoolAspect autoFormatOnlyCurrentProject; - StringAspect autoFormatMime; + FilePathAspect command{this}; + BoolAspect autoFormatOnSave{this}; + BoolAspect autoFormatOnlyCurrentProject{this}; + StringAspect autoFormatMime{this}; QAction formatFile{Tr::tr("Format &Current File")}; }; diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index e343158f569..1fe948cc72a 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -51,20 +51,17 @@ CMakeSpecificSettings::CMakeSpecificSettings() setSettingsGroup("CMakeSpecificSettings"); setAutoApply(false); - registerAspect(&autorunCMake); autorunCMake.setSettingsKey("AutorunCMake"); autorunCMake.setDefaultValue(true); autorunCMake.setLabelText(::CMakeProjectManager::Tr::tr("Autorun CMake")); autorunCMake.setToolTip(::CMakeProjectManager::Tr::tr( "Automatically run CMake after changes to CMake project files.")); - registerAspect(&ninjaPath); ninjaPath.setSettingsKey("NinjaPath"); // never save this to the settings: ninjaPath.setToSettingsTransformation( [](const QVariant &) { return QVariant::fromValue(QString()); }); - registerAspect(&packageManagerAutoSetup); packageManagerAutoSetup.setSettingsKey("PackageManagerAutoSetup"); packageManagerAutoSetup.setDefaultValue(true); packageManagerAutoSetup.setLabelText(::CMakeProjectManager::Tr::tr("Package manager auto setup")); @@ -72,24 +69,20 @@ CMakeSpecificSettings::CMakeSpecificSettings() "pointing to a CMake script that will install dependencies from the conanfile.txt, " "conanfile.py, or vcpkg.json file from the project source directory.")); - registerAspect(&askBeforeReConfigureInitialParams); askBeforeReConfigureInitialParams.setSettingsKey("AskReConfigureInitialParams"); askBeforeReConfigureInitialParams.setDefaultValue(true); askBeforeReConfigureInitialParams.setLabelText(::CMakeProjectManager::Tr::tr("Ask before re-configuring with " "initial parameters")); - registerAspect(&askBeforePresetsReload); askBeforePresetsReload.setSettingsKey("AskBeforePresetsReload"); askBeforePresetsReload.setDefaultValue(true); askBeforePresetsReload.setLabelText(::CMakeProjectManager::Tr::tr("Ask before reloading CMake Presets")); - registerAspect(&showSourceSubFolders); showSourceSubFolders.setSettingsKey("ShowSourceSubFolders"); showSourceSubFolders.setDefaultValue(true); showSourceSubFolders.setLabelText( ::CMakeProjectManager::Tr::tr("Show subfolders inside source group folders")); - registerAspect(&showAdvancedOptionsByDefault); showAdvancedOptionsByDefault.setSettingsKey("ShowAdvancedOptionsByDefault"); showAdvancedOptionsByDefault.setDefaultValue(false); showAdvancedOptionsByDefault.setLabelText( diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h index 9ed848e4749..a9c2758e190 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.h +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.h @@ -14,13 +14,13 @@ public: static CMakeSpecificSettings *instance(); - Utils::BoolAspect autorunCMake; - Utils::FilePathAspect ninjaPath; - Utils::BoolAspect packageManagerAutoSetup; - Utils::BoolAspect askBeforeReConfigureInitialParams; - Utils::BoolAspect askBeforePresetsReload; - Utils::BoolAspect showSourceSubFolders; - Utils::BoolAspect showAdvancedOptionsByDefault; + Utils::BoolAspect autorunCMake{this}; + Utils::FilePathAspect ninjaPath{this}; + Utils::BoolAspect packageManagerAutoSetup{this}; + Utils::BoolAspect askBeforeReConfigureInitialParams{this}; + Utils::BoolAspect askBeforePresetsReload{this}; + Utils::BoolAspect showSourceSubFolders{this}; + Utils::BoolAspect showAdvancedOptionsByDefault{this}; }; } // CMakeProjectManager::Internal From 60da3a024a0412c39470181f4f25fe08c4a60582 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:21:25 +0200 Subject: [PATCH 1296/1447] Perfprofiler: Register settings aspects more directly Change-Id: I19be173e4244add2d37eaab933293a6f30236c96 Reviewed-by: Christian Stenger --- src/plugins/perfprofiler/perfsettings.cpp | 6 ------ src/plugins/perfprofiler/perfsettings.h | 12 ++++++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index 9cfdf3d92c7..b7871b33cf9 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -25,19 +25,16 @@ PerfSettings::PerfSettings(ProjectExplorer::Target *target) return widget; }); - registerAspect(&period); period.setSettingsKey("Analyzer.Perf.Frequency"); period.setRange(250, 2147483647); period.setDefaultValue(250); period.setLabelText(Tr::tr("Sample period:")); - registerAspect(&stackSize); stackSize.setSettingsKey("Analyzer.Perf.StackSize"); stackSize.setRange(4096, 65536); stackSize.setDefaultValue(4096); stackSize.setLabelText(Tr::tr("Stack snapshot size (kB):")); - registerAspect(&sampleMode); sampleMode.setSettingsKey("Analyzer.Perf.SampleMode"); sampleMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); sampleMode.setLabelText(Tr::tr("Sample mode:")); @@ -45,7 +42,6 @@ PerfSettings::PerfSettings(ProjectExplorer::Target *target) sampleMode.addOption({Tr::tr("event count"), {}, QString("-c")}); sampleMode.setDefaultValue(0); - registerAspect(&callgraphMode); callgraphMode.setSettingsKey("Analyzer.Perf.CallgraphMode"); callgraphMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); callgraphMode.setLabelText(Tr::tr("Call graph mode:")); @@ -54,11 +50,9 @@ PerfSettings::PerfSettings(ProjectExplorer::Target *target) callgraphMode.addOption({Tr::tr("last branch record"), {}, QString("lbr")}); callgraphMode.setDefaultValue(0); - registerAspect(&events); events.setSettingsKey("Analyzer.Perf.Events"); events.setDefaultValue({"cpu-cycles"}); - registerAspect(&extraArguments); extraArguments.setSettingsKey("Analyzer.Perf.ExtraArguments"); extraArguments.setDisplayStyle(StringAspect::DisplayStyle::LineEditDisplay); extraArguments.setLabelText(Tr::tr("Additional arguments:")); diff --git a/src/plugins/perfprofiler/perfsettings.h b/src/plugins/perfprofiler/perfsettings.h index 4e8ae5700f8..cfa3de429ec 100644 --- a/src/plugins/perfprofiler/perfsettings.h +++ b/src/plugins/perfprofiler/perfsettings.h @@ -26,12 +26,12 @@ public: void resetToDefault(); - Utils::IntegerAspect period; - Utils::IntegerAspect stackSize; - Utils::SelectionAspect sampleMode; - Utils::SelectionAspect callgraphMode; - Utils::StringListAspect events; - Utils::StringAspect extraArguments; + Utils::IntegerAspect period{this}; + Utils::IntegerAspect stackSize{this}; + Utils::SelectionAspect sampleMode{this}; + Utils::SelectionAspect callgraphMode{this}; + Utils::StringListAspect events{this}; + Utils::StringAspect extraArguments{this}; signals: void changed(); From b0b80c539bdb5968e176a2a39e3aa72aea8276ec Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:33:02 +0200 Subject: [PATCH 1297/1447] CppCheck: Register settingsaspect more directly Change-Id: I325c7329618b4dbdd36bb1464627806e5f116bc0 Reviewed-by: Christian Stenger --- src/plugins/cppcheck/cppcheckoptions.cpp | 15 ----------- src/plugins/cppcheck/cppcheckoptions.h | 33 +++++++++++------------- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp index 22f728f8f11..8392f64600c 100644 --- a/src/plugins/cppcheck/cppcheckoptions.cpp +++ b/src/plugins/cppcheck/cppcheckoptions.cpp @@ -34,7 +34,6 @@ CppcheckOptions::CppcheckOptions() setCategoryIconPath(Analyzer::Icons::SETTINGSCATEGORY_ANALYZER); setSettingsGroup("Cppcheck"); - registerAspect(&binary); binary.setSettingsKey("binary"); binary.setExpectedKind(PathChooser::ExistingCommand); binary.setCommandVersionArguments({"--version"}); @@ -48,71 +47,57 @@ CppcheckOptions::CppcheckOptions() binary.setDefaultValue(programFiles.pathAppended("Cppcheck/cppcheck.exe").toString()); } - registerAspect(&warning); warning.setSettingsKey("warning"); warning.setDefaultValue(true); warning.setLabelText(Tr::tr("Warnings")); - registerAspect(&style); style.setSettingsKey("style"); style.setDefaultValue(true); style.setLabelText(Tr::tr("Style")); - registerAspect(&performance); performance.setSettingsKey("performance"); performance.setDefaultValue(true); performance.setLabelText(Tr::tr("Performance")); - registerAspect(&portability); portability.setSettingsKey("portability"); portability.setDefaultValue(true); portability.setLabelText(Tr::tr("Portability")); - registerAspect(&information); information.setSettingsKey("information"); information.setDefaultValue(true); information.setLabelText(Tr::tr("Information")); - registerAspect(&unusedFunction); unusedFunction.setSettingsKey("unusedFunction"); unusedFunction.setLabelText(Tr::tr("Unused functions")); unusedFunction.setToolTip(Tr::tr("Disables multithreaded check.")); - registerAspect(&missingInclude); missingInclude.setSettingsKey("missingInclude"); missingInclude.setLabelText(Tr::tr("Missing includes")); - registerAspect(&inconclusive); inconclusive.setSettingsKey("inconclusive"); inconclusive.setLabelText(Tr::tr("Inconclusive errors")); - registerAspect(&forceDefines); forceDefines.setSettingsKey("forceDefines"); forceDefines.setLabelText(Tr::tr("Check all define combinations")); - registerAspect(&customArguments); customArguments.setSettingsKey("customArguments"); customArguments.setDisplayStyle(StringAspect::LineEditDisplay); customArguments.setLabelText(Tr::tr("Custom arguments:")); - registerAspect(&ignoredPatterns); ignoredPatterns.setSettingsKey("ignoredPatterns"); ignoredPatterns.setDisplayStyle(StringAspect::LineEditDisplay); ignoredPatterns.setLabelText(Tr::tr("Ignored file patterns:")); ignoredPatterns.setToolTip(Tr::tr("Comma-separated wildcards of full file paths. " "Files still can be checked if others include them.")); - registerAspect(&showOutput); showOutput.setSettingsKey("showOutput"); showOutput.setLabelText(Tr::tr("Show raw output")); - registerAspect(&addIncludePaths); addIncludePaths.setSettingsKey("addIncludePaths"); addIncludePaths.setLabelText(Tr::tr("Add include paths")); addIncludePaths.setToolTip(Tr::tr("Can find missing includes but makes " "checking slower. Use only when needed.")); - registerAspect(&guessArguments); guessArguments.setSettingsKey("guessArguments"); guessArguments.setDefaultValue(true); guessArguments.setLabelText(Tr::tr("Calculate additional arguments")); diff --git a/src/plugins/cppcheck/cppcheckoptions.h b/src/plugins/cppcheck/cppcheckoptions.h index 5a617b1241c..a6ccdd98ba0 100644 --- a/src/plugins/cppcheck/cppcheckoptions.h +++ b/src/plugins/cppcheck/cppcheckoptions.h @@ -7,9 +7,6 @@ namespace Cppcheck::Internal { -class CppcheckTool; -class CppcheckTrigger; - class CppcheckOptions final : public Core::PagedSettings { public: @@ -17,22 +14,22 @@ public: std::function layouter(); - Utils::FilePathAspect binary; - Utils::BoolAspect warning; - Utils::BoolAspect style; - Utils::BoolAspect performance; - Utils::BoolAspect portability; - Utils::BoolAspect information; - Utils::BoolAspect unusedFunction; - Utils::BoolAspect missingInclude; - Utils::BoolAspect inconclusive; - Utils::BoolAspect forceDefines; + Utils::FilePathAspect binary{this}; + Utils::BoolAspect warning{this}; + Utils::BoolAspect style{this}; + Utils::BoolAspect performance{this}; + Utils::BoolAspect portability{this}; + Utils::BoolAspect information{this}; + Utils::BoolAspect unusedFunction{this}; + Utils::BoolAspect missingInclude{this}; + Utils::BoolAspect inconclusive{this}; + Utils::BoolAspect forceDefines{this}; - Utils::StringAspect customArguments; - Utils::StringAspect ignoredPatterns; - Utils::BoolAspect showOutput; - Utils::BoolAspect addIncludePaths; - Utils::BoolAspect guessArguments; + Utils::StringAspect customArguments{this}; + Utils::StringAspect ignoredPatterns{this}; + Utils::BoolAspect showOutput{this}; + Utils::BoolAspect addIncludePaths{this}; + Utils::BoolAspect guessArguments{this}; }; } // Cppcheck::Internal From a7ab1ba98711cb286286bdb928225c967fcd6b29 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 25 May 2023 07:56:39 +0200 Subject: [PATCH 1298/1447] TaskTree: Doc corrections Make docs more consistent. Add some more precision when something is not clear. Do some adaptations for behavioral changes. Change-Id: I95c76fedf2c9d611702097842452186ea4cdf8b0 Reviewed-by: Reviewed-by: Leena Miettinen --- src/libs/solutions/tasking/tasktree.cpp | 85 +++++++++++++------------ 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 6d3e7eb95bc..3d7f63216cd 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -916,7 +916,7 @@ void TaskNode::invokeEndHandler(bool success) Use Task handlers to set up a task for execution and to enable reading the output data from the task when it finishes with success or an error. - \section2 Task Start Handler + \section2 Task's Start Handler When a corresponding task class object is created and before it's started, the task tree invokes a mandatory user-provided setup handler. The setup @@ -933,9 +933,9 @@ void TaskNode::invokeEndHandler(bool success) You can modify the passed Process in the setup handler, so that the task tree can start the process according to your configuration. - You do not need to call \e {process.start();} in the setup handler, - as the task tree calls it when needed. The setup handler is mandatory - and must be the first argument of the task's constructor. + You should not call \e {process.start();} in the setup handler, + as the task tree calls it when needed. The setup handler is optional. When used, + it must be the first argument of the task's constructor. Optionally, the setup handler may return a TaskAction. The returned TaskAction influences the further start behavior of a given task. The @@ -947,7 +947,7 @@ void TaskNode::invokeEndHandler(bool success) \li Brief Description \row \li Continue - \li The task is started normally. This is the default behavior when the + \li The task will be started normally. This is the default behavior when the setup handler doesn't return TaskAction (that is, its return type is void). \row @@ -960,7 +960,7 @@ void TaskNode::invokeEndHandler(bool success) This is useful for running a task only when a condition is met and the data needed to evaluate this condition is not known until previously started tasks - finish. This way, the setup handler dynamically decides whether to start the + finish. In this way, the setup handler dynamically decides whether to start the corresponding task normally or skip it and report success or an error. For more information about inter-task data exchange, see \l Storage. @@ -987,8 +987,8 @@ void TaskNode::invokeEndHandler(bool success) The done and error handlers may collect output data from Process, and store it for further processing or perform additional actions. The done handler is optional. - When used, it must be the second argument of the task constructor. - The error handler must always be the third argument. + When used, it must be the second argument of the task's constructor. + The error handler is also optional. When used, it must always be the third argument. You can omit the handlers or substitute the ones that you do not need with curly braces ({}). \note If the task setup handler returns StopWithDone or StopWithError, @@ -1020,7 +1020,7 @@ void TaskNode::invokeEndHandler(bool success) handler. If you add more than one onGroupSetup element to a group, an assert is triggered at runtime that includes an error message. - Like the task start handler, the group start handler may return TaskAction. + Like the task's start handler, the group start handler may return TaskAction. The returned TaskAction value affects the start behavior of the whole group. If you do not specify a group start handler or its return type is void, the default group's action is TaskAction::Continue, so that all @@ -1117,7 +1117,7 @@ void TaskNode::invokeEndHandler(bool success) runtime that includes an error message. \note Even if the group setup handler returns StopWithDone or StopWithError, - one of the task's done or error handlers is invoked. This behavior differs + one of the group's done or error handlers is invoked. This behavior differs from that of task handlers and might change in the future. \section1 Other Group Elements @@ -1173,7 +1173,7 @@ void TaskNode::invokeEndHandler(bool success) \section2 Workflow Policy The workflow policy element in a Group specifies how the group should behave - when its direct child tasks finish: + when any of its \e direct child's tasks finish: \table \header @@ -1185,8 +1185,8 @@ void TaskNode::invokeEndHandler(bool success) \list 1 \li Stops the running tasks (if any - for example, in parallel mode). - \li Skips executing tasks it has not started (for example, in the - sequential mode). + \li Skips executing tasks it has not started yet (for example, in the + sequential mode - those, that are placed after the failed task). \li Immediately finishes with an error. \endlist If all child tasks finish successfully, the group finishes with success. @@ -1207,7 +1207,10 @@ void TaskNode::invokeEndHandler(bool success) \li stopOnDone \li If a task finishes with success, the group: \list 1 - \li Stops running tasks and skips those that it has not started. + \li Stops the running tasks (if any - for example, in parallel + mode). + \li Skips executing tasks it has not started yet (for example, in the + sequential mode - those, that are placed after the successfully finished task). \li Immediately finishes with success. \endlist If all tasks finish with an error, the group finishes with an error. @@ -1226,27 +1229,27 @@ void TaskNode::invokeEndHandler(bool success) If all tasks finish with an error, the group finishes with an error. \row \li stopOnFinished - \li The group starts as many tasks as it can. When a task finishes + \li The group starts as many tasks as it can. When a task finishes, the group stops and reports the task's result. Useful only in parallel mode. In sequential mode, only the first task is started, and when finished, the group finishes too, so the other tasks are ignored. \row \li optional - \li The group executes all tasks and ignores their return state. If all + \li The group executes all tasks and ignores their return state. When all tasks finish, the group finishes with success. \endtable - When the group is empty, it finishes immediately with success, + When a Group is empty, it finishes immediately with success, regardless of its workflow policy. - If a child of a group is also a group (in a nested tree), the child group + If a child of a group is also a group, the child group runs its tasks according to its own workflow policy. \section2 Storage Use the Storage element to exchange information between tasks. Especially, - in the sequential execution mode, when a task needs data from another task - before it can start. For example, a task tree that copies data by reading + in the sequential execution mode, when a task needs data from another, + already finished task, before it can start. For example, a task tree that copies data by reading it from a source and writing it to a destination might look as follows: \code @@ -1265,21 +1268,22 @@ void TaskNode::invokeEndHandler(bool success) const auto onLoaderSetup = [source](Async &async) { async.setConcurrentCallData(&load, source); }; - // [4] runtime: task tree activates the instance from [5] before invoking handler + // [4] runtime: task tree activates the instance from [7] before invoking handler const auto onLoaderDone = [storage](const Async &async) { - storage->content = async.result(); + storage->content = async.result(); // [5] loader stores the result in storage }; - // [4] runtime: task tree activates the instance from [5] before invoking handler + // [4] runtime: task tree activates the instance from [7] before invoking handler const auto onSaverSetup = [storage, destination](Async &async) { - async.setConcurrentCallData(&save, destination, storage->content); + const QByteArray content = storage->content; // [6] saver takes data from storage + async.setConcurrentCallData(&save, destination, content); }; const auto onSaverDone = [](const Async &async) { qDebug() << "Save done successfully"; }; const Group root { - // [5] runtime: task tree creates an instance of CopyStorage when root is entered + // [7] runtime: task tree creates an instance of CopyStorage when root is entered Storage(storage), AsyncTask(onLoaderSetup, onLoaderDone), AsyncTask(onSaverSetup, onSaverDone) @@ -1291,11 +1295,11 @@ void TaskNode::invokeEndHandler(bool success) In the example above, the inter-task data consists of a QByteArray content variable [2] enclosed in a CopyStorage custom struct [1]. If the loader finishes successfully, it stores the data in a CopyStorage::content - variable. The saver then uses the variable to configure the saving task. + variable [5]. The saver then uses the variable to configure the saving task [6]. To enable a task tree to manage the CopyStorage struct, an instance of TreeStorage is created [3]. If a copy of this object is - inserted as group's child task [5], an instance of CopyStorage struct is + inserted as group's child task [7], an instance of CopyStorage struct is created dynamically when the task tree enters this group. When the task tree leaves this group, the existing instance of CopyStorage struct is destructed as it's no longer needed. @@ -1310,12 +1314,12 @@ void TaskNode::invokeEndHandler(bool success) copy of the TreeStorage object to the handler (for example, in a lambda capture) [4]. - When the task tree invokes a handler in a subtree containing the storage [5], + When the task tree invokes a handler in a subtree containing the storage [7], the task tree activates its own CopyStorage instance inside the TreeStorage object. Therefore, the CopyStorage struct may be accessed only from within the handler body. To access the currently active - CopyStorage from within TreeStorage, use the TreeStorage::operator->() - or TreeStorage::activeStorage() method. + CopyStorage from within TreeStorage, use the TreeStorage::operator->(), + TreeStorage::operator*() or TreeStorage::activeStorage() method. The following list summarizes how to employ a Storage object into the task tree: @@ -1323,7 +1327,8 @@ void TaskNode::invokeEndHandler(bool success) \li Define the custom structure MyStorage with custom data [1], [2] \li Create an instance of TreeStorage storage [3] \li Pass the TreeStorage instance to handlers [4] - \li Insert the TreeStorage instance into a group [5] + \li Access the MyStorage instance in handlers [5], [6] + \li Insert the TreeStorage instance into a group [7] \endlist \note The current implementation assumes that all running task trees @@ -1395,10 +1400,10 @@ void TaskNode::invokeEndHandler(bool success) asynchronous task: \code - class TimeoutAdapter : public Tasking::TaskAdapter + class TimeoutTaskAdapter : public Tasking::TaskAdapter { public: - TimeoutAdapter() { + TimeoutTaskAdapter() { task()->setSingleShot(true); task()->setInterval(1000); connect(task(), &QTimer::timeout, this, [this] { emit done(true); }); @@ -1406,7 +1411,7 @@ void TaskNode::invokeEndHandler(bool success) void start() final { task()->start(); } }; - QTC_DECLARE_CUSTOM_TASK(Timeout, TimeoutAdapter); + QTC_DECLARE_CUSTOM_TASK(TimeoutTask, TimeoutTaskAdapter); \endcode You must derive the custom adapter from the TaskAdapter class template @@ -1415,15 +1420,15 @@ void TaskNode::invokeEndHandler(bool success) later as an argument to the task's handlers. The instance of this class parameter automatically becomes a member of the TaskAdapter template, and is accessible through the TaskAdapter::task() method. The constructor - of TimeoutAdapter initially configures the QTimer object and connects - to the QTimer::timeout signal. When the signal is triggered, TimeoutAdapter + of TimeoutTaskAdapter initially configures the QTimer object and connects + to the QTimer::timeout signal. When the signal is triggered, TimeoutTaskAdapter emits the done(true) signal to inform the task tree that the task finished successfully. If it emits done(false), the task finished with an error. The TaskAdapter::start() method starts the timer. - To make QTimer accessible inside TaskTree under the \e Timeout name, - register it with QTC_DECLARE_CUSTOM_TASK(Timeout, TimeoutAdapter). Timeout - becomes a new task type inside Tasking namespace, using TimeoutAdapter. + To make QTimer accessible inside TaskTree under the \e TimeoutTask name, + register it with QTC_DECLARE_CUSTOM_TASK(TimeoutTask, TimeoutTaskAdapter). + TimeoutTask becomes a new task type inside Tasking namespace, using TimeoutTaskAdapter. The new task type is now registered, and you can use it in TaskTree: @@ -1436,7 +1441,7 @@ void TaskNode::invokeEndHandler(bool success) }; const Group root { - Timeout(onTimeoutSetup, onTimeoutDone) + TimeoutTask(onTimeoutSetup, onTimeoutDone) }; \endcode From 97bb4164527f5a92d0bfb71dbdb265ed3e1f71e7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 26 May 2023 13:01:40 +0200 Subject: [PATCH 1299/1447] PerfProfiler: Get rid of duplicated PerfSettings::changed() signal This signal is already defined is base AspectContainer class. Change-Id: I195f4758a8baa746ee7f214cbdb12e494c4824ef Reviewed-by: hjk --- src/plugins/perfprofiler/perfconfigeventsmodel.cpp | 5 ++++- src/plugins/perfprofiler/perfsettings.cpp | 2 -- src/plugins/perfprofiler/perfsettings.h | 3 --- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/perfprofiler/perfconfigeventsmodel.cpp b/src/plugins/perfprofiler/perfconfigeventsmodel.cpp index a760ffb7bc5..a235a6122db 100644 --- a/src/plugins/perfprofiler/perfconfigeventsmodel.cpp +++ b/src/plugins/perfprofiler/perfconfigeventsmodel.cpp @@ -8,13 +8,16 @@ #include +using namespace Utils; + namespace PerfProfiler { namespace Internal { PerfConfigEventsModel::PerfConfigEventsModel(PerfSettings *settings, QObject *parent) : QAbstractTableModel(parent), m_settings(settings) { - connect(m_settings, &PerfSettings::changed, this, &PerfConfigEventsModel::reset); + connect(m_settings, &AspectContainer::changed, this, &PerfConfigEventsModel::reset); + connect(m_settings, &AspectContainer::fromMapFinished, this, &PerfConfigEventsModel::reset); } int PerfConfigEventsModel::rowCount(const QModelIndex &parent) const diff --git a/src/plugins/perfprofiler/perfsettings.cpp b/src/plugins/perfprofiler/perfsettings.cpp index b7871b33cf9..59a753e5dde 100644 --- a/src/plugins/perfprofiler/perfsettings.cpp +++ b/src/plugins/perfprofiler/perfsettings.cpp @@ -62,8 +62,6 @@ PerfSettings::PerfSettings(ProjectExplorer::Target *target) stackSize.setEnabled(index == 0); }); - connect(this, &AspectContainer::fromMapFinished, this, &PerfSettings::changed); - readGlobalSettings(); } diff --git a/src/plugins/perfprofiler/perfsettings.h b/src/plugins/perfprofiler/perfsettings.h index cfa3de429ec..7c10706098b 100644 --- a/src/plugins/perfprofiler/perfsettings.h +++ b/src/plugins/perfprofiler/perfsettings.h @@ -32,9 +32,6 @@ public: Utils::SelectionAspect callgraphMode{this}; Utils::StringListAspect events{this}; Utils::StringAspect extraArguments{this}; - -signals: - void changed(); }; } // namespace PerfProfiler From e2a4f0d701e08f0f9e51da398b6cbc54105dcd5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 26 May 2023 00:46:45 +0200 Subject: [PATCH 1300/1447] SquishTests: Remove function for creating task file on error Change-Id: I80b327da89f6c89a6b72a1df0f6ace0e5cf6b100 Reviewed-by: Christian Stenger --- tests/system/shared/build_utils.py | 52 +--------------------- tests/system/suite_APTW/tst_APTW03/test.py | 2 +- 2 files changed, 2 insertions(+), 52 deletions(-) diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index dd7677d4730..18ae360fca0 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -39,8 +39,7 @@ def getBuildIssues(ignoreCodeModel=True): # this method checks the last build (if there's one) and logs the number of errors, warnings and # lines within the Issues output # param expectedToFail can be used to tell this function if the build was expected to fail or not -# param createTasksFileOnError whether a tasks file should be created when building ends with errors -def checkLastBuild(expectedToFail=False, createTasksFileOnError=True): +def checkLastBuild(expectedToFail=False): try: # can't use waitForObject() 'cause visible is always 0 findObject("{type='ProjectExplorer::Internal::BuildProgress' unnamed='1' }") @@ -53,9 +52,6 @@ def checkLastBuild(expectedToFail=False, createTasksFileOnError=True): warnings = types.count("2") gotErrors = errors != 0 test.verify(not (gotErrors ^ expectedToFail), "Errors: %s | Warnings: %s" % (errors, warnings)) - # additional stuff - could be removed... or improved :) - if gotErrors and createTasksFileOnError: - createTasksFile(buildIssues) return not gotErrors # helper function to check the compilation when build wasn't successful @@ -96,52 +92,6 @@ def dumpBuildIssues(listModel): in range(Qt.UserRole, Qt.UserRole + 6)]]) return issueDump -# counter for written tasks files -tasksFileCount = 0 - -# helper method that writes a tasks file -def createTasksFile(buildIssues): - # currently used directory for tasks files - tasksFileDir = None - global tasksFileCount - if tasksFileDir == None: - tasksFileDir = os.getcwd() + "/tasks" - tasksFileDir = os.path.abspath(tasksFileDir) - if not os.path.exists(tasksFileDir): - try: - os.makedirs(tasksFileDir) - except OSError: - test.log("Could not create %s - falling back to a temporary directory" % tasksFileDir) - tasksFileDir = tempDir() - - tasksFileCount += 1 - outfile = os.path.join(tasksFileDir, os.path.basename(squishinfo.testCase)+"_%d.tasks" % tasksFileCount) - file = codecs.open(outfile, "w", "utf-8") - test.log("Writing tasks file - can take some time (according to number of issues)") - rows = len(buildIssues) - if os.environ.get("SYSTEST_DEBUG") == "1": - firstrow = 0 - else: - firstrow = max(0, rows - 100) - for issue in buildIssues[firstrow:rows]: - # the following is currently a bad work-around - fData = issue[0] # file - lData = issue[1] # line -> linenumber or empty - tData = issue[5] # type -> 1==error 2==warning - dData = issue[3] # description - if lData == "": - lData = "-1" - if tData == "1": - tData = "error" - elif tData == "2": - tData = "warning" - else: - tData = "unknown" - if str(fData).strip() == "" and lData == "-1" and str(dData).strip() == "": - test.fatal("Found empty task.") - file.write("%s\t%s\t%s\t%s\n" % (fData, lData, tData, dData)) - file.close() - test.log("Written tasks file %s" % outfile) # returns a list of pairs each containing the ID of a kit (see class Targets) # and the name of the matching build configuration diff --git a/tests/system/suite_APTW/tst_APTW03/test.py b/tests/system/suite_APTW/tst_APTW03/test.py index bb09f8d7510..bbbec3b1630 100644 --- a/tests/system/suite_APTW/tst_APTW03/test.py +++ b/tests/system/suite_APTW/tst_APTW03/test.py @@ -73,7 +73,7 @@ def main(): invokeMenuItem('Build', 'Build Project "%s"' % projectName) waitForCompile(10000) if not virtualFunctionsAdded: - checkLastBuild(True, False) + checkLastBuild(True) if not openDocument("%s.Sources.%s\.cpp" % (projectName, className.lower())): test.fatal("Could not open %s.cpp - continuing." % className.lower()) continue From f385324bc8e7a9c4623781a349fd542e1ee43e0a Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 24 May 2023 15:38:04 +0200 Subject: [PATCH 1301/1447] TextEditor: fix highlighting after removing line We cannot reconstruct the correct initial state for highlighting when deleting a line if we generally save the after highlight state to the next line. Change-Id: I7d5f727f6b7c8340ac7f5436046cd0f1ad17ebd2 Reviewed-by: Christian Stenger --- src/plugins/texteditor/highlighter.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp index a3765c4bf51..4512b71910f 100644 --- a/src/plugins/texteditor/highlighter.cpp +++ b/src/plugins/texteditor/highlighter.cpp @@ -279,15 +279,24 @@ void Highlighter::highlightBlock(const QString &text) return; } QTextBlock block = currentBlock(); - KSyntaxHighlighting::State state; - TextDocumentLayout::setBraceDepth(block, TextDocumentLayout::braceDepth(block.previous())); + const QTextBlock previousBlock = block.previous(); + TextDocumentLayout::setBraceDepth(block, TextDocumentLayout::braceDepth(previousBlock)); + KSyntaxHighlighting::State previousLineState; + if (TextBlockUserData *data = TextDocumentLayout::textUserData(previousBlock)) + previousLineState = data->syntaxState(); + KSyntaxHighlighting::State oldState; if (TextBlockUserData *data = TextDocumentLayout::textUserData(block)) { - state = data->syntaxState(); + oldState = data->syntaxState(); data->setFoldingStartIncluded(false); data->setFoldingEndIncluded(false); } - state = highlightLine(text, state); - const QTextBlock nextBlock = block.next(); + KSyntaxHighlighting::State state = highlightLine(text, previousLineState); + if (oldState != state) { + TextBlockUserData *data = TextDocumentLayout::userData(block); + data->setSyntaxState(state); + // Toggles the LSB of current block's userState. It forces rehighlight of next block. + setCurrentBlockState(currentBlockState() ^ 1); + } Parentheses parentheses; int pos = 0; @@ -300,13 +309,9 @@ void Highlighter::highlightBlock(const QString &text) } TextDocumentLayout::setParentheses(currentBlock(), parentheses); + const QTextBlock nextBlock = block.next(); if (nextBlock.isValid()) { TextBlockUserData *data = TextDocumentLayout::userData(nextBlock); - if (data->syntaxState() != state) { - data->setSyntaxState(state); - // Toggles the LSB of current block's userState. It forces rehighlight of next block. - setCurrentBlockState(currentBlockState() ^ 1); - } data->setFoldingIndent(TextDocumentLayout::braceDepth(block)); } From bdb31d43484046a3879246462697115679046d41 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 23 May 2023 08:58:07 +0200 Subject: [PATCH 1302/1447] Copilot: Allow user to disable Copilot Fixes: QTCREATORBUG-29179 Change-Id: I274de1f13f773fb61b376643b61056b6f14dabaf Reviewed-by: BogDan Vatra Reviewed-by: David Schulz Reviewed-by: Leena Miettinen --- src/plugins/copilot/CMakeLists.txt | 2 + src/plugins/copilot/copilot.qbs | 3 + src/plugins/copilot/copilot.qrc | 10 ++- src/plugins/copilot/copilotclient.cpp | 51 ++++++++++-- src/plugins/copilot/copilotclient.h | 4 + src/plugins/copilot/copilotconstants.h | 20 +++++ src/plugins/copilot/copiloticons.h | 12 +++ src/plugins/copilot/copilotoptionspage.cpp | 8 +- src/plugins/copilot/copilotplugin.cpp | 74 ++++++++++++++++-- src/plugins/copilot/copilotprojectpanel.cpp | 59 ++++++++++++++ src/plugins/copilot/copilotprojectpanel.h | 15 ++++ src/plugins/copilot/copilotsettings.cpp | 56 ++++++++++++- src/plugins/copilot/copilotsettings.h | 19 +++++ src/plugins/copilot/images/copilot.png | Bin 0 -> 192 bytes src/plugins/copilot/images/copilot@2x.png | Bin 0 -> 361 bytes .../images/settingscategory_copilot.png | Bin 219 -> 251 bytes .../images/settingscategory_copilot@2x.png | Bin 404 -> 497 bytes src/tools/icons/qtcreatoricons.svg | 44 ++++++++++- 18 files changed, 353 insertions(+), 24 deletions(-) create mode 100644 src/plugins/copilot/copilotconstants.h create mode 100644 src/plugins/copilot/copiloticons.h create mode 100644 src/plugins/copilot/copilotprojectpanel.cpp create mode 100644 src/plugins/copilot/copilotprojectpanel.h create mode 100644 src/plugins/copilot/images/copilot.png create mode 100644 src/plugins/copilot/images/copilot@2x.png diff --git a/src/plugins/copilot/CMakeLists.txt b/src/plugins/copilot/CMakeLists.txt index b718ec12695..01129674fce 100644 --- a/src/plugins/copilot/CMakeLists.txt +++ b/src/plugins/copilot/CMakeLists.txt @@ -4,9 +4,11 @@ add_qtc_plugin(Copilot authwidget.cpp authwidget.h copilot.qrc copilotclient.cpp copilotclient.h + copilotconstants.h copilothoverhandler.cpp copilothoverhandler.h copilotoptionspage.cpp copilotoptionspage.h copilotplugin.cpp copilotplugin.h + copilotprojectpanel.cpp copilotprojectpanel.h copilotsettings.cpp copilotsettings.h copilotsuggestion.cpp copilotsuggestion.h requests/checkstatus.h diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs index 51d7febbd6b..cf59d954caa 100644 --- a/src/plugins/copilot/copilot.qbs +++ b/src/plugins/copilot/copilot.qbs @@ -14,12 +14,15 @@ QtcPlugin { "copilot.qrc", "copilotclient.cpp", "copilotclient.h", + "copilotconstants.h", "copilothoverhandler.cpp", "copilothoverhandler.h", "copilotoptionspage.cpp", "copilotoptionspage.h", "copilotplugin.cpp", "copilotplugin.h", + "copilotprojectpanel.cpp", + "copilotprojectpanel.h", "copilotsettings.cpp", "copilotsettings.h", "copilotsuggestion.cpp", diff --git a/src/plugins/copilot/copilot.qrc b/src/plugins/copilot/copilot.qrc index 2071a381011..65d481b92ac 100644 --- a/src/plugins/copilot/copilot.qrc +++ b/src/plugins/copilot/copilot.qrc @@ -1,6 +1,8 @@ - - images/settingscategory_copilot.png - images/settingscategory_copilot@2x.png - + + images/settingscategory_copilot.png + images/settingscategory_copilot@2x.png + images/copilot.png + images/copilot@2x.png + diff --git a/src/plugins/copilot/copilotclient.cpp b/src/plugins/copilot/copilotclient.cpp index 946e5c1e3e1..f935210b53d 100644 --- a/src/plugins/copilot/copilotclient.cpp +++ b/src/plugins/copilot/copilotclient.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "copilotclient.h" +#include "copilotconstants.h" #include "copilotsettings.h" #include "copilotsuggestion.h" @@ -9,8 +10,11 @@ #include #include +#include #include +#include + #include #include @@ -19,10 +23,13 @@ #include #include +#include using namespace LanguageServerProtocol; using namespace TextEditor; using namespace Utils; +using namespace ProjectExplorer; +using namespace Core; namespace Copilot::Internal { @@ -47,27 +54,27 @@ CopilotClient::CopilotClient(const FilePath &nodePath, const FilePath &distPath) setSupportedLanguage(langFilter); start(); - auto openDoc = [this](Core::IDocument *document) { + auto openDoc = [this](IDocument *document) { if (auto *textDocument = qobject_cast(document)) openDocument(textDocument); }; - connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, this, openDoc); - connect(Core::EditorManager::instance(), - &Core::EditorManager::documentClosed, + connect(EditorManager::instance(), &EditorManager::documentOpened, this, openDoc); + connect(EditorManager::instance(), + &EditorManager::documentClosed, this, - [this](Core::IDocument *document) { + [this](IDocument *document) { if (auto textDocument = qobject_cast(document)) closeDocument(textDocument); }); - for (Core::IDocument *doc : Core::DocumentModel::openedDocuments()) + for (IDocument *doc : DocumentModel::openedDocuments()) openDoc(doc); } CopilotClient::~CopilotClient() { - for (Core::IEditor *editor : Core::DocumentModel::editorsForOpenedDocuments()) { + for (IEditor *editor : DocumentModel::editorsForOpenedDocuments()) { if (auto textEditor = qobject_cast(editor)) textEditor->editorWidget()->removeHoverHandler(&m_hoverHandler); } @@ -75,14 +82,23 @@ CopilotClient::~CopilotClient() void CopilotClient::openDocument(TextDocument *document) { + auto project = ProjectManager::projectForFile(document->filePath()); + if (!isEnabled(project)) + return; + Client::openDocument(document); connect(document, &TextDocument::contentsChangedWithPosition, this, [this, document](int position, int charsRemoved, int charsAdded) { Q_UNUSED(charsRemoved) - if (!CopilotSettings::instance().autoComplete.value()) + if (!CopilotSettings::instance().autoComplete()) return; + + auto project = ProjectManager::projectForFile(document->filePath()); + if (!isEnabled(project)) + return; + auto textEditor = BaseTextEditor::currentTextEditor(); if (!textEditor || textEditor->document() != document) return; @@ -123,6 +139,11 @@ void CopilotClient::scheduleRequest(TextEditorWidget *editor) void CopilotClient::requestCompletions(TextEditorWidget *editor) { + auto project = ProjectManager::projectForFile(editor->textDocument()->filePath()); + + if (!isEnabled(project)) + return; + Utils::MultiTextCursor cursor = editor->multiTextCursor(); if (cursor.hasMultipleCursors() || cursor.hasSelection() || editor->suggestionVisible()) return; @@ -214,4 +235,18 @@ void CopilotClient::requestSignInConfirm( sendMessage(request); } +bool CopilotClient::canOpenProject(Project *project) +{ + return isEnabled(project); +} + +bool CopilotClient::isEnabled(Project *project) +{ + if (!project) + return CopilotSettings::instance().enableCopilot(); + + CopilotProjectSettings settings(project); + return settings.isEnabled(); +} + } // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotclient.h b/src/plugins/copilot/copilotclient.h index bd48710a185..47208236b52 100644 --- a/src/plugins/copilot/copilotclient.h +++ b/src/plugins/copilot/copilotclient.h @@ -46,6 +46,10 @@ public: const QString &userCode, std::function callback); + bool canOpenProject(ProjectExplorer::Project *project) override; + + bool isEnabled(ProjectExplorer::Project *project); + private: QMap m_runningRequests; struct ScheduleData diff --git a/src/plugins/copilot/copilotconstants.h b/src/plugins/copilot/copilotconstants.h new file mode 100644 index 00000000000..6ace5f2f6f9 --- /dev/null +++ b/src/plugins/copilot/copilotconstants.h @@ -0,0 +1,20 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace Copilot::Constants { +const char COPILOT_PROJECT_SETTINGS_ID[] = "Copilot.Project.Settings"; +const char ENABLE_COPILOT[] = "Copilot.EnableCopilot"; +const char COPILOT_USE_GLOBAL_SETTINGS[] = "Copilot.UseGlobalSettings"; + +const char COPILOT_TOGGLE[] = "Copilot.Toggle"; +const char COPILOT_ENABLE[] = "Copilot.Enable"; +const char COPILOT_DISABLE[] = "Copilot.Disable"; +const char COPILOT_REQUEST_SUGGESTION[] = "Copilot.RequestSuggestion"; + +const char COPILOT_GENERAL_OPTIONS_ID[] = "Copilot.General"; +const char COPILOT_GENERAL_OPTIONS_CATEGORY[] = "ZY.Copilot"; +const char COPILOT_GENERAL_OPTIONS_DISPLAY_CATEGORY[] = "Copilot"; + +} // namespace Copilot::Constants diff --git a/src/plugins/copilot/copiloticons.h b/src/plugins/copilot/copiloticons.h new file mode 100644 index 00000000000..b2b54077d3c --- /dev/null +++ b/src/plugins/copilot/copiloticons.h @@ -0,0 +1,12 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Copilot { +static const Utils::Icon COPILOT_ICON({{":/copilot/images/copilot.png", + Utils::Theme::IconsBaseColor}}); + +} diff --git a/src/plugins/copilot/copilotoptionspage.cpp b/src/plugins/copilot/copilotoptionspage.cpp index d0f2bf654a3..001db87834d 100644 --- a/src/plugins/copilot/copilotoptionspage.cpp +++ b/src/plugins/copilot/copilotoptionspage.cpp @@ -4,6 +4,7 @@ #include "copilotoptionspage.h" #include "authwidget.h" +#include "copilotconstants.h" #include "copilotsettings.h" #include "copilottr.h" @@ -47,6 +48,7 @@ file from the Copilot neovim plugin. Column { authWidget, br, + CopilotSettings::instance().enableCopilot, br, CopilotSettings::instance().nodeJsPath, br, CopilotSettings::instance().distPath, br, CopilotSettings::instance().autoComplete, br, @@ -82,10 +84,10 @@ file from the Copilot neovim plugin. CopilotOptionsPage::CopilotOptionsPage() { - setId("Copilot.General"); + setId(Constants::COPILOT_GENERAL_OPTIONS_ID); setDisplayName("Copilot"); - setCategory("ZY.Copilot"); - setDisplayCategory("Copilot"); + setCategory(Constants::COPILOT_GENERAL_OPTIONS_CATEGORY); + setDisplayCategory(Constants::COPILOT_GENERAL_OPTIONS_DISPLAY_CATEGORY); setCategoryIconPath(":/copilot/images/settingscategory_copilot.png"); setWidgetCreator([] { return new CopilotOptionsPageWidget; }); } diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index d895e088c56..43effda321c 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -4,22 +4,30 @@ #include "copilotplugin.h" #include "copilotclient.h" +#include "copilotconstants.h" +#include "copiloticons.h" #include "copilotoptionspage.h" +#include "copilotprojectpanel.h" #include "copilotsettings.h" #include "copilottr.h" #include #include #include +#include #include +#include + #include #include +#include using namespace Utils; using namespace Core; +using namespace ProjectExplorer; namespace Copilot { namespace Internal { @@ -35,17 +43,73 @@ void CopilotPlugin::initialize() this, &CopilotPlugin::restartClient); - QAction *action = new QAction(this); - action->setText(Tr::tr("Request Copilot Suggestion")); - action->setToolTip(Tr::tr("Request Copilot Suggestion at the current editors cursor position.")); + QAction *requestAction = new QAction(this); + requestAction->setText(Tr::tr("Request Copilot Suggestion")); + requestAction->setToolTip( + Tr::tr("Request Copilot suggestion at the current editor's cursor position.")); - QObject::connect(action, &QAction::triggered, this, [this] { + connect(requestAction, &QAction::triggered, this, [this] { if (auto editor = TextEditor::TextEditorWidget::currentTextEditorWidget()) { if (m_client->reachable()) m_client->requestCompletions(editor); } }); - ActionManager::registerAction(action, "Copilot.RequestSuggestion"); + + ActionManager::registerAction(requestAction, Constants::COPILOT_REQUEST_SUGGESTION); + + QAction *disableAction = new QAction(this); + disableAction->setText(Tr::tr("Disable Copilot")); + disableAction->setToolTip(Tr::tr("Disable Copilot.")); + connect(disableAction, &QAction::triggered, this, [] { + CopilotSettings::instance().enableCopilot.setValue(true); + CopilotSettings::instance().apply(); + }); + ActionManager::registerAction(disableAction, Constants::COPILOT_DISABLE); + + QAction *enableAction = new QAction(this); + enableAction->setText(Tr::tr("Enable Copilot")); + enableAction->setToolTip(Tr::tr("Enable Copilot.")); + connect(enableAction, &QAction::triggered, this, [] { + CopilotSettings::instance().enableCopilot.setValue(false); + CopilotSettings::instance().apply(); + }); + ActionManager::registerAction(enableAction, Constants::COPILOT_ENABLE); + + QAction *toggleAction = new QAction(this); + toggleAction->setText(Tr::tr("Toggle Copilot")); + toggleAction->setCheckable(true); + toggleAction->setChecked(CopilotSettings::instance().enableCopilot.value()); + toggleAction->setIcon(COPILOT_ICON.icon()); + connect(toggleAction, &QAction::toggled, this, [](bool checked) { + CopilotSettings::instance().enableCopilot.setValue(checked); + CopilotSettings::instance().apply(); + }); + + ActionManager::registerAction(toggleAction, Constants::COPILOT_TOGGLE); + + auto updateActions = [toggleAction, requestAction] { + const bool enabled = CopilotSettings::instance().enableCopilot.value(); + toggleAction->setToolTip(enabled ? Tr::tr("Disable Copilot.") : Tr::tr("Enable Copilot.")); + toggleAction->setChecked(enabled); + requestAction->setEnabled(enabled); + }; + + connect(&CopilotSettings::instance().enableCopilot, + &BoolAspect::valueChanged, + this, + updateActions); + + updateActions(); + + auto toggleButton = new QToolButton; + toggleButton->setDefaultAction(toggleAction); + StatusBarManager::addStatusBarWidget(toggleButton, StatusBarManager::RightCorner); + + auto panelFactory = new ProjectPanelFactory; + panelFactory->setPriority(1000); + panelFactory->setDisplayName(Tr::tr("Copilot")); + panelFactory->setCreateWidgetFunction(&Internal::createCopilotProjectPanel); + ProjectPanelFactory::registerFactory(panelFactory); } void CopilotPlugin::extensionsInitialized() diff --git a/src/plugins/copilot/copilotprojectpanel.cpp b/src/plugins/copilot/copilotprojectpanel.cpp new file mode 100644 index 00000000000..f1eb5d119e8 --- /dev/null +++ b/src/plugins/copilot/copilotprojectpanel.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "copilotprojectpanel.h" +#include "copilotconstants.h" +#include "copilotsettings.h" + +#include +#include + +#include + +#include + +using namespace ProjectExplorer; + +namespace Copilot::Internal { + +class CopilotProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget +{ +public: + CopilotProjectSettingsWidget() + { + setGlobalSettingsId(Constants::COPILOT_GENERAL_OPTIONS_ID); + setUseGlobalSettingsCheckBoxVisible(true); + } +}; + +ProjectSettingsWidget *createCopilotProjectPanel(Project *project) +{ + using namespace Layouting; + using namespace ProjectExplorer; + + auto widget = new CopilotProjectSettingsWidget; + auto settings = new CopilotProjectSettings(project, widget); + + QObject::connect(widget, + &ProjectSettingsWidget::useGlobalSettingsChanged, + settings, + &CopilotProjectSettings::setUseGlobalSettings); + + widget->setUseGlobalSettings(settings->useGlobalSettings()); + widget->setEnabled(!settings->useGlobalSettings()); + + QObject::connect(widget, + &ProjectSettingsWidget::useGlobalSettingsChanged, + widget, + [widget](bool useGlobal) { widget->setEnabled(!useGlobal); }); + + // clang-format off + Column { + settings->enableCopilot, + }.attachTo(widget); + // clang-format on + + return widget; +} + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotprojectpanel.h b/src/plugins/copilot/copilotprojectpanel.h new file mode 100644 index 00000000000..2f4be6d6f9c --- /dev/null +++ b/src/plugins/copilot/copilotprojectpanel.h @@ -0,0 +1,15 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace ProjectExplorer { +class ProjectSettingsWidget; +class Project; +} // namespace ProjectExplorer + +namespace Copilot::Internal { + +ProjectExplorer::ProjectSettingsWidget *createCopilotProjectPanel(ProjectExplorer::Project *project); + +} // namespace Copilot::Internal diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index 8c701448eb1..bac2c176afa 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -2,8 +2,11 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "copilotsettings.h" +#include "copilotconstants.h" #include "copilottr.h" +#include + #include #include @@ -11,6 +14,15 @@ using namespace Utils; namespace Copilot { +static void initEnableAspect(BoolAspect &enableCopilot) +{ + enableCopilot.setSettingsKey(Constants::ENABLE_COPILOT); + enableCopilot.setDisplayName(Tr::tr("Enable Copilot")); + enableCopilot.setLabelText(Tr::tr("Enable Copilot")); + enableCopilot.setToolTip(Tr::tr("Enables the Copilot integration.")); + enableCopilot.setDefaultValue(true); +} + CopilotSettings &CopilotSettings::instance() { static CopilotSettings settings; @@ -32,7 +44,7 @@ CopilotSettings::CopilotSettings() FilePath::fromUserInput( "~/AppData/Local/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js")}; - const FilePath distFromVim = Utils::findOrDefault(searchDirs, &FilePath::exists); + const FilePath distFromVim = findOrDefault(searchDirs, &FilePath::exists); nodeJsPath.setExpectedKind(PathChooser::ExistingCommand); nodeJsPath.setDefaultFilePath(nodeFromPath); @@ -55,10 +67,52 @@ CopilotSettings::CopilotSettings() "https://github.com/github/copilot.vim#getting-started for installation instructions.")); autoComplete.setDisplayName(Tr::tr("Auto Complete")); + autoComplete.setSettingsKey("Copilot.Autocomplete"); autoComplete.setLabelText(Tr::tr("Request completions automatically")); autoComplete.setDefaultValue(true); autoComplete.setToolTip(Tr::tr("Automatically request suggestions for the current text cursor " "position after changes to the document")); + + initEnableAspect(enableCopilot); +} + +CopilotProjectSettings::CopilotProjectSettings(ProjectExplorer::Project *project, QObject *parent) + : AspectContainer(parent) +{ + setAutoApply(true); + + useGlobalSettings.setSettingsKey(Constants::COPILOT_USE_GLOBAL_SETTINGS); + useGlobalSettings.setDefaultValue(true); + + initEnableAspect(enableCopilot); + + QVariantMap map = project->namedSettings(Constants::COPILOT_PROJECT_SETTINGS_ID).toMap(); + fromMap(map); + + connect(&enableCopilot, &BoolAspect::valueChanged, this, [this, project] { save(project); }); + connect(&useGlobalSettings, &BoolAspect::valueChanged, this, [this, project] { save(project); }); +} + +void CopilotProjectSettings::setUseGlobalSettings(bool useGlobal) +{ + useGlobalSettings.setValue(useGlobal); +} + +bool CopilotProjectSettings::isEnabled() const +{ + if (useGlobalSettings()) + return CopilotSettings::instance().enableCopilot(); + return enableCopilot(); +} + +void CopilotProjectSettings::save(ProjectExplorer::Project *project) +{ + QVariantMap map; + toMap(map); + project->setNamedSettings(Constants::COPILOT_PROJECT_SETTINGS_ID, map); + + // This triggers a restart of the Copilot language server. + CopilotSettings::instance().apply(); } } // namespace Copilot diff --git a/src/plugins/copilot/copilotsettings.h b/src/plugins/copilot/copilotsettings.h index ea3ac7520f5..cec44c43fed 100644 --- a/src/plugins/copilot/copilotsettings.h +++ b/src/plugins/copilot/copilotsettings.h @@ -5,6 +5,10 @@ #include +namespace ProjectExplorer { +class Project; +} + namespace Copilot { class CopilotSettings : public Utils::AspectContainer @@ -17,6 +21,21 @@ public: Utils::FilePathAspect nodeJsPath{this}; Utils::FilePathAspect distPath{this}; Utils::BoolAspect autoComplete{this}; + Utils::BoolAspect enableCopilot{this}; +}; + +class CopilotProjectSettings : public Utils::AspectContainer +{ +public: + CopilotProjectSettings(ProjectExplorer::Project *project, QObject *parent = nullptr); + + void save(ProjectExplorer::Project *project); + void setUseGlobalSettings(bool useGlobalSettings); + + bool isEnabled() const; + + Utils::BoolAspect enableCopilot{this}; + Utils::BoolAspect useGlobalSettings{this}; }; } // namespace Copilot diff --git a/src/plugins/copilot/images/copilot.png b/src/plugins/copilot/images/copilot.png new file mode 100644 index 0000000000000000000000000000000000000000..00d63f65602f94887cba19355b717dd2a10660ab GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4h9AW2CEqh_A)Rqw0pWZhDd}b|LA9v*uWLz z5&ZaBnD=f5;Tb2@&Yn7OKuQomXULC}X@Rcw?!XDadJ_u6{1-oD!MAjM{@ zn`e_=v|?^a*z>!;3*~>f8w5U(-O)GIE3&Wp#nFZ^L&mu-8@~$A(RNvs6&PTeAQlrn z?Q`D2mO$?2ZL?N>Ig!B1;Kg`z^_f*=9BZCGDP?9TS2>xNm&{^yGI-~ACZYA0{3o54 zl6mOamap(p@2}u-sVNtxKD1@9@p!*zNn^9NF|nBYceSZ$osjK`tvdN8_`1LAUhopL&0Nb@9um zd(&8WET$dY&wRMhfTy`eCPIdBvEe>-={C0P!r$)=JvPblzmobhjk7`DsKKRNvFD>0 PC=5Ma{an^LB{Ts5a@v&R literal 0 HcmV?d00001 diff --git a/src/plugins/copilot/images/settingscategory_copilot.png b/src/plugins/copilot/images/settingscategory_copilot.png index 674fece4c51d97e21bbdcba147703f4a1359a645..9a47fb241351b4566a0fdf77b425396a31a6f94d 100644 GIT binary patch delta 223 zcmcc3_?vNpO8p^E7sn8d^T|K@nGFKsA6@VB(RU6$zvZlbfGXcgLk3260qr+V(<~0G zn?Cu-!2<`S=4T(;!>9Psw^De*nxqFO*n)Pa-an+8meP2_lso(^+eOjXg3boM4O_Nx z&Y1U(W4gfyW}*FS4+(v7$ml&M7PdHenrJX`N&7A`Z0_6O^;MR5Q+~_ g-FHDF%aDN~GU|h`@a{4`1_lNOPgg&ebxsLQ0A1i^K>z>% delta 191 zcmey(c$;y8O8p{F7sn8d^T|K@nGJZ@I_HP$?fd!v|M%VH@9Px2YxJK#evs1hqrR!J zvGM3P9w()UqR;pLZ|`GNy;rkWLg5du+Q!)rEnMsa9{v9>&QqNr^zzvMi7Ii%GEJTq zDvF*qJfVMhr+YMdb9^wcifN9Xm%u&UqV~J+q~hrt?znAY_IzZ~zVKS>|Nr}Kk52gU z|Iq9}hqk3+!Au&ZRsX#gT-#mG7V477z;H;EYsvXZ$uk)k7#KWV{an^LB{Ts5nNC=i diff --git a/src/plugins/copilot/images/settingscategory_copilot@2x.png b/src/plugins/copilot/images/settingscategory_copilot@2x.png index a2d45562f7f6f0dc1abaa78f145e1be5e8cfd415..0437465aff3e9713112c75d628e2669d8114f758 100644 GIT binary patch delta 471 zcmbQj{E>NrO8pK`7sn8fUbd#zC*p87pRF64fB?hf zEK~juSwCV$la_B?%I=J%#+qz*}L>35C@pK(BHn{&nWwG#C@{}V43G&w$&?a4i* zq;X!4?{V$+JjUZGA(bQ{k$3pUam9nXgyu2akjybO zi7+-0ah_?fBT;nk?u(@QfVS3KED0sa85fw@r;i^v z(7w=-_XW?j9$ofn$Cxk2pZ{N9{(pT^N&@H1?fK!H;u^e383Bn2293*PzsYr6P_kRW z5YWWg%{DJS+vcXE#M96D2an7PS#4x&aQpnv)s3OeiXFec$eQl|Q^T*+9I!FV;LzNO z&Tgg$OlCZ|CeR#uIOL90S<>YN|An`=)yqYgyg3@qa{u9h3llo`U+_DAp+IzhoA%<; eI|A1k82Z@{I-ibK+{nPdz~JfX=d#Wzp$PyvRL#i% delta 377 zcmey!JcW6JN`17ai(`n#@wZoOHI6V!9RIlf@G|Ww4-X~m2&{Z*pvaxNaek|(nppF6 zPdB}Zn<^sr%;CAjdoCeiX9=5T^Zx0dgWfs0JlXYIQm^#x|NrZEJ4(LWUjOR)<( - +
    @@ -3566,6 +3570,40 @@ style="fill:none;stroke:#000000" d="m 1936.25,571.25 2.25,2.25 -2.25,2.25 m -2.75,-6.25 h 8 v 8 h -8 z" /> + + + + + + + + Date: Mon, 16 May 2022 13:33:32 +0200 Subject: [PATCH 1303/1447] SquishTests: Remove outdated code We don't have 32 bit packages anymore so the OS must be 64 bit. Change-Id: If1ce6a502dd9c6b14d416915caf1d30bd5d01ddc Reviewed-by: Christian Stenger --- tests/system/shared/qtcreator.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index d49b23350d7..e777c5c7d70 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -200,10 +200,7 @@ def substituteDefaultCompiler(settingsDir): if platform.system() == 'Darwin': compiler = "clang_64" elif platform.system() == 'Linux': - if __is64BitOS__(): - compiler = "gcc_64" - else: - compiler = "gcc" + compiler = "gcc_64" else: test.warning("Called substituteDefaultCompiler() on wrong platform.", "This is a script error.") @@ -299,23 +296,12 @@ def __guessABI__(supportedABIs, use64Bit): 'Given ABIs: %s' % str(supportedABIs)) return '' -def __is64BitOS__(): - if platform.system() in ('Microsoft', 'Windows'): - machine = os.getenv("PROCESSOR_ARCHITEW6432", os.getenv("PROCESSOR_ARCHITECTURE")) - else: - machine = platform.machine() - if machine: - return '64' in machine - else: - return False - def substituteUnchosenTargetABIs(settingsDir): class ReadState: NONE = 0 READING = 1 CLOSED = 2 - on64Bit = __is64BitOS__() toolchains = os.path.join(settingsDir, "QtProject", 'qtcreator', 'toolchains.xml') origToolchains = toolchains + "_orig" os.rename(toolchains, origToolchains) @@ -338,7 +324,7 @@ def substituteUnchosenTargetABIs(settingsDir): supported = [] readState = ReadState.READING elif "SET_BY_SQUISH" in line: - line = line.replace("SET_BY_SQUISH", __guessABI__(supported, on64Bit)) + line = line.replace("SET_BY_SQUISH", __guessABI__(supported, True)) modifiedFile.write(line) origFile.close() modifiedFile.close() From db70923c6f6fa721b7c76295edf48bfba2966618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 28 Apr 2023 23:03:08 +0200 Subject: [PATCH 1304/1447] SquishTests: Don't guess ABIs, use 64bit Change-Id: I9c9ff40ff6064cc203d11cc273950d65ab4f983f Reviewed-by: Christian Stenger --- .../mac/QtProject/qtcreator/toolchains.xml | 8 +-- .../unix/QtProject/qtcreator/toolchains.xml | 4 +- tests/system/shared/qtcreator.py | 55 ------------------- 3 files changed, 6 insertions(+), 61 deletions(-) diff --git a/tests/system/settings/mac/QtProject/qtcreator/toolchains.xml b/tests/system/settings/mac/QtProject/qtcreator/toolchains.xml index ac3136362c7..962e4208be4 100644 --- a/tests/system/settings/mac/QtProject/qtcreator/toolchains.xml +++ b/tests/system/settings/mac/QtProject/qtcreator/toolchains.xml @@ -11,7 +11,7 @@ x86-linux-generic-elf-32bit x86-darwin-generic-mach_o-64bit - SET_BY_SQUISH + x86-darwin-generic-mach_o-64bit false GCC ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} @@ -26,7 +26,7 @@ x86-darwin-generic-mach_o-64bit x86-darwin-generic-mach_o-32bit - SET_BY_SQUISH + x86-darwin-generic-mach_o-64bit false Clang (x86 64bit) ProjectExplorer.ToolChain.Clang:{6afe7dea-8caa-424e-b370-b7b0a34015fb} @@ -41,7 +41,7 @@ x86-darwin-generic-mach_o-64bit x86-darwin-generic-mach_o-32bit - SET_BY_SQUISH + x86-darwin-generic-mach_o-64bit false Clang [C] ProjectExplorer.ToolChain.Clang:{0db093b8-890b-4fad-a4bc-9078124fe866} @@ -57,7 +57,7 @@ x86-linux-generic-elf-32bit x86-darwin-generic-mach_o-64bit - SET_BY_SQUISH + x86-darwin-generic-mach_o-64bit false GCC [C] ProjectExplorer.ToolChain.Gcc:{461bb8dc-22ff-461f-82fe-ebe8b21b697f} diff --git a/tests/system/settings/unix/QtProject/qtcreator/toolchains.xml b/tests/system/settings/unix/QtProject/qtcreator/toolchains.xml index 0c98a8f561f..ae15015bbc1 100644 --- a/tests/system/settings/unix/QtProject/qtcreator/toolchains.xml +++ b/tests/system/settings/unix/QtProject/qtcreator/toolchains.xml @@ -11,7 +11,7 @@ x86-linux-generic-elf-32bit x86-macos-generic-mach_o-64bit - SET_BY_SQUISH + x86-linux-generic-elf-64bit false GCC ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} @@ -28,7 +28,7 @@ x86-linux-generic-elf-64bit x86-linux-generic-elf-32bit - SET_BY_SQUISH + x86-linux-generic-elf-64bit false GCC ProjectExplorer.ToolChain.Gcc:{7bfd4fd4-e64a-417f-b10f-20602e1719d1} diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index e777c5c7d70..f243d00506a 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -277,60 +277,6 @@ def prependWindowsKit(settingsDir, targetBitness=64): __substitute__(profilesPath, "SQUISH_ENV_MODIFICATION", "") -def __guessABI__(supportedABIs, use64Bit): - if platform.system() == 'Linux': - supportedABIs = filter(lambda x: 'linux' in x, supportedABIs) - elif platform.system() == 'Darwin': - supportedABIs = filter(lambda x: 'darwin' in x, supportedABIs) - if use64Bit: - searchFor = "64bit" - else: - searchFor = "32bit" - for abi in supportedABIs: - if searchFor in abi: - return abi - if use64Bit: - test.log("Supported ABIs do not include an ABI supporting 64bit - trying 32bit now") - return __guessABI__(supportedABIs, False) - test.fatal('Could not guess ABI!', - 'Given ABIs: %s' % str(supportedABIs)) - return '' - -def substituteUnchosenTargetABIs(settingsDir): - class ReadState: - NONE = 0 - READING = 1 - CLOSED = 2 - - toolchains = os.path.join(settingsDir, "QtProject", 'qtcreator', 'toolchains.xml') - origToolchains = toolchains + "_orig" - os.rename(toolchains, origToolchains) - origFile = open(origToolchains, "r") - modifiedFile = open(toolchains, "w") - supported = [] - readState = ReadState.NONE - for line in origFile: - if readState == ReadState.NONE: - if "SupportedAbis" in line: - supported = [] - readState = ReadState.READING - elif readState == ReadState.READING: - if "" in line: - readState = ReadState.CLOSED - else: - supported.append(line.split(">", 1)[1].rsplit("<", 1)[0]) - elif readState == ReadState.CLOSED: - if "SupportedAbis" in line: - supported = [] - readState = ReadState.READING - elif "SET_BY_SQUISH" in line: - line = line.replace("SET_BY_SQUISH", __guessABI__(supported, True)) - modifiedFile.write(line) - origFile.close() - modifiedFile.close() - os.remove(origToolchains) - test.log("Substituted unchosen ABIs inside toolchains.xml...") - def copySettingsToTmpDir(destination=None, omitFiles=[]): global tmpSettingsDir, SettingsPath, origSettingsDir if destination: @@ -365,7 +311,6 @@ def copySettingsToTmpDir(destination=None, omitFiles=[]): substituteMsvcPaths(tmpSettingsDir, '2019', 64) prependWindowsKit(tmpSettingsDir, 32) substituteOnlineInstallerPath(tmpSettingsDir) - substituteUnchosenTargetABIs(tmpSettingsDir) SettingsPath = ['-settingspath', '"%s"' % tmpSettingsDir] test.log("Test is running on Python %s" % sys.version) From b7f814372823df1d5de49207ab0346bad460bf9d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 13:04:31 +0200 Subject: [PATCH 1305/1447] Tr: Various small fixes Change-Id: Ic86d6b6a4aae7b301557eaa4296beb9a31399e03 Reviewed-by: Leena Miettinen Reviewed-by: Qt CI Bot --- share/qtcreator/translations/qtcreator_de.ts | 16 ++++++++-------- share/qtcreator/translations/qtcreator_hr.ts | 4 ++-- .../languageserverprotocol/jsonrpcmessages.cpp | 3 +-- src/plugins/coreplugin/loggingviewer.cpp | 2 +- src/plugins/fossil/fossilplugin.cpp | 2 +- .../languageclient/languageclientinterface.cpp | 2 +- src/plugins/projectexplorer/project.cpp | 2 +- src/plugins/qtsupport/qtsupportplugin.cpp | 2 +- src/plugins/texteditor/formattexteditor.cpp | 6 ++---- 9 files changed, 18 insertions(+), 21 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 2d1a13ead00..28c1cfb917e 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -18989,8 +18989,8 @@ Doppelklicken Sie einen Eintrag um ihn zu ändern. Datei "%1" konnte nicht zum Schreiben der Protokolle geöffnet werden. - Save Enabled Categories As - Ausgewählte Kategorien speichern unter + Save Enabled Categories As... + Ausgewählte Kategorien speichern unter... Failed to write preset file "%1". @@ -27390,7 +27390,7 @@ Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht ALT+I,Alt+C - Settings ... + Settings... Einstellungen... @@ -31889,8 +31889,8 @@ Beispiel: *.cpp%1*.h In die Zwischenablage kopieren - Cannot handle MIME type of message %1 - MIME type %1 der Nachricht kann nicht verarbeitet werden + Cannot handle MIME type "%1" of message. + MIME type "%1" der Nachricht kann nicht verarbeitet werden. Generic StdIO Language Server @@ -32025,7 +32025,7 @@ Beispiel: *.cpp%1*.h In "%1" ist keine ID angegeben. - Could not parse JSON message "%1". + Could not parse JSON message: "%1". Die JSON-Nachricht konnte nicht ausgewertet werden: "%1". @@ -38801,7 +38801,7 @@ Benutzen Sie dies nur für Prototypen. Sie können damit keine vollständige Anw %1: Vollständiger Pfad zur Hauptdatei. - %1: The name the active kit. + %1: The name of the active kit. %1 is something like "Active project" %1: Der Name des aktiven Kits. @@ -44979,7 +44979,7 @@ wirklich löschen? Vollständiger Pfad zum Ziel-"bin"-Verzeichnis der Qt-Version des aktiven Kits des aktiven Projekts.<br>Wahrscheinlich sollten Sie stattdessen %1 nutzen. - Full path to the libexec bin directory of the Qt version in the active kit of the active project. + Full path to the libexec directory of the Qt version in the active kit of the active project. Vollständiger Pfad zum Host-"libexec"-Verzeichnis der Qt-Version des aktiven Kits des aktiven Projekts. diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 179850cef10..386c4d14929 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -10705,8 +10705,8 @@ will also disable the following plugins: Očekivana vrsta %1, ali vrijednost je sadržavala %2 - Could not parse JSON message "%1". - Nije moguće obraditi JSON poruku "%1". + Could not parse JSON message: "%1". + Nije moguće obraditi JSON poruku: "%1". Expected a JSON object, but got a JSON "%1". diff --git a/src/libs/languageserverprotocol/jsonrpcmessages.cpp b/src/libs/languageserverprotocol/jsonrpcmessages.cpp index 31183cc0cc1..cef4c47cb09 100644 --- a/src/libs/languageserverprotocol/jsonrpcmessages.cpp +++ b/src/libs/languageserverprotocol/jsonrpcmessages.cpp @@ -77,8 +77,7 @@ JsonRpcMessage::JsonRpcMessage(const BaseMessage &message) if (doc.isObject()) m_jsonObject = doc.object(); else if (doc.isNull()) - m_parseError = - Tr::tr("Could not parse JSON message \"%1\".").arg(error.errorString()); + m_parseError = Tr::tr("Could not parse JSON message: \"%1\".").arg(error.errorString()); else m_parseError = Tr::tr("Expected a JSON object, but got a JSON \"%1\" value.").arg(docType(doc)); diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp index 4392ef63445..d35a5da20bf 100644 --- a/src/plugins/coreplugin/loggingviewer.cpp +++ b/src/plugins/coreplugin/loggingviewer.cpp @@ -622,7 +622,7 @@ void LoggingViewManagerWidget::saveLoggingsToFile() const void LoggingViewManagerWidget::saveEnabledCategoryPreset() const { Utils::FilePath fp = Utils::FileUtils::getSaveFilePath(ICore::dialogParent(), - Tr::tr("Save Enabled Categories As")); + Tr::tr("Save Enabled Categories As...")); if (fp.isEmpty()) return; const QList enabled = m_categoryModel->enabledCategories(); diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index a316daf3aec..bdd68d06210 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -559,7 +559,7 @@ void FossilPluginPrivate::createRepositoryActions(const Core::Context &context) m_fossilContainer->addAction(command); m_commandLocator->appendCommand(command); - action = new QAction(Tr::tr("Settings ..."), this); + action = new QAction(Tr::tr("Settings..."), this); m_repositoryActionList.append(action); command = Core::ActionManager::registerAction(action, Constants::CONFIGURE_REPOSITORY, context); connect(action, &QAction::triggered, this, &FossilPluginPrivate::configureRepository); diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index 84f4b5ed0a1..d42e74c9b36 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -71,7 +71,7 @@ void BaseClientInterface::parseCurrentMessage() if (m_currentMessage.mimeType == JsonRpcMessage::jsonRpcMimeType()) { emit messageReceived(JsonRpcMessage(m_currentMessage)); } else { - emit error(Tr::tr("Cannot handle MIME type of message %1") + emit error(Tr::tr("Cannot handle MIME type \"%1\" of message.") .arg(QString::fromUtf8(m_currentMessage.mimeType))); } m_currentMessage = BaseMessage(); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 3b32e3c2650..c021d9b1a64 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -1183,7 +1183,7 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix, }); expander->registerVariable(fullPrefix + "Kit:Name", //: %1 is something like "Active project" - Tr::tr("%1: The name the active kit.").arg(descriptor), + Tr::tr("%1: The name of the active kit.").arg(descriptor), [targetGetter]() -> QString { if (const Target *const target = targetGetter()) return target->kit()->displayName(); diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 3fc9fe8fed8..41c88d18e36 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -197,7 +197,7 @@ void QtSupportPlugin::extensionsInitialized() expander->registerVariable( "ActiveProject::QT_HOST_LIBEXECS", - Tr::tr("Full path to the libexec bin directory of the Qt version in the active kit " + Tr::tr("Full path to the libexec directory of the Qt version in the active kit " "of the active project."), []() { const QtVersion *const qt = activeQtVersion(); diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp index 3e31006d617..03de5fb4152 100644 --- a/src/plugins/texteditor/formattexteditor.cpp +++ b/src/plugins/texteditor/formattexteditor.cpp @@ -69,8 +69,7 @@ static FormatTask format(FormatTask task) process.setCommand({executable, options}); process.runBlocking(); if (process.result() != ProcessResult::FinishedWithSuccess) { - task.error = Tr::tr("TextEditor", "Failed to format: %1.") - .arg(process.exitMessage()); + task.error = Tr::tr("Failed to format: %1.").arg(process.exitMessage()); return task; } const QString output = process.cleanedStdErr(); @@ -249,8 +248,7 @@ void updateEditorText(QPlainTextEdit *editor, const QString &text) static void showError(const QString &error) { - Core::MessageManager::writeFlashing(Tr::tr("TextEditor", "Error in text formatting: %1") - .arg(error.trimmed())); + Core::MessageManager::writeFlashing(Tr::tr("Error in text formatting: %1").arg(error.trimmed())); } /** From f2c1455025805b013587c01007ce18247e909182 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 11:29:50 +0200 Subject: [PATCH 1306/1447] Tr: Wrap file paths with "" Change-Id: Iee0e941ff503ff485e8e9c0d9fe3e52eea9042d5 Reviewed-by: Leena Miettinen --- share/qtcreator/translations/qtcreator_cs.ts | 4 +- share/qtcreator/translations/qtcreator_da.ts | 8 +-- share/qtcreator/translations/qtcreator_de.ts | 54 +++++++++---------- share/qtcreator/translations/qtcreator_es.ts | 4 +- share/qtcreator/translations/qtcreator_fr.ts | 4 +- share/qtcreator/translations/qtcreator_hr.ts | 8 +-- share/qtcreator/translations/qtcreator_hu.ts | 4 +- share/qtcreator/translations/qtcreator_it.ts | 4 +- share/qtcreator/translations/qtcreator_ja.ts | 14 +++-- share/qtcreator/translations/qtcreator_pl.ts | 12 ++--- share/qtcreator/translations/qtcreator_ru.ts | 22 ++++---- share/qtcreator/translations/qtcreator_sl.ts | 4 +- share/qtcreator/translations/qtcreator_uk.ts | 4 +- .../qtcreator/translations/qtcreator_zh_CN.ts | 14 +++-- .../qtcreator/translations/qtcreator_zh_TW.ts | 4 +- .../advanceddockingsystem/workspaceview.cpp | 8 +-- src/libs/utils/devicefileaccess.cpp | 12 ++--- .../cmakeprojectmanager/cmakeproject.cpp | 2 +- src/plugins/coreplugin/patchtool.cpp | 3 +- src/plugins/coreplugin/session.cpp | 2 +- src/plugins/cppeditor/cppeditorwidget.cpp | 10 ++-- src/plugins/python/pythonsettings.cpp | 5 +- .../qmakeprojectmanager/qmakeproject.cpp | 4 +- src/plugins/vcsbase/vcsoutputwindow.cpp | 2 +- 24 files changed, 103 insertions(+), 109 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_cs.ts b/share/qtcreator/translations/qtcreator_cs.ts index c96e36d85bb..1e867abbcbd 100644 --- a/share/qtcreator/translations/qtcreator_cs.ts +++ b/share/qtcreator/translations/qtcreator_cs.ts @@ -10547,8 +10547,8 @@ přidat do správy verzí (%2)? Při ukládání sezení se vyskytla chyba - Could not save session to file %1 - Sezení se nepodařilo uložit do souboru %1 + Could not save session to file "%1" + Sezení se nepodařilo uložit do souboru "%1" Untitled diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 210c99ebbb6..1a285e8c8ad 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -7810,8 +7810,8 @@ Vil du dræbe den? Patch-kommandoen konfigureret i de generelle "Miljø"-indstillinger findes ikke. - Running in %1: %2 %3 - Kører om %1: %2 %3 + Running in "%1": %2 %3 + Kører om "%1": %2 %3 Unable to launch "%1": %2 @@ -24940,8 +24940,8 @@ Disse filer bevares. Fejl ved gemning af session - Could not save session to file %1 - Kunne ikke gemme session til filen %1 + Could not save session to file "%1" + Kunne ikke gemme session til filen "%1" Untitled diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 28c1cfb917e..9b29bb1bf08 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -13043,8 +13043,8 @@ Zum Beispiel bewirkt die Angabe "Revision: 15" dass der Branch auf Rev %1 konnte nicht geladen werden: %2 - Attempt to include %1 which was already parsed. - Versuch, die Datei %1 einzufügen, welche schon ausgewertet wurde. + Attempt to include "%1" which was already parsed. + Versuch, die Datei "%1" einzufügen, welche schon ausgewertet wurde. yes @@ -13408,8 +13408,8 @@ Möchten Sie den Pfad zu den Quelldateien in die Zwischenablage kopieren?Keine gültige ausführbare CMake-Datei - Running in %1: %2 - Führe in %1 aus: %2 + Running in "%1": %2 + Führe in "%1" aus: %2 <No CMake Tool available> @@ -16566,8 +16566,8 @@ Trotzdem fortfahren? Das in den allgemeinen Umgebungseinstellungen konfigurierte patch-Kommando existiert nicht. - Running in %1: %2 %3 - Führe in %1 aus: %2 %3 + Running in "%1": %2 %3 + Führe in "%1" aus: %2 %3 Unable to launch "%1": %2 @@ -20465,8 +20465,8 @@ Dies ist normalerweise nicht empfehlenswert, da die Datei wahrscheinlich währen Möchten Sie stattdessen "%1" bearbeiten? - Open %1 - %1 öffnen + Open "%1" + "%1" öffnen &Refactor @@ -35824,8 +35824,8 @@ Rename %2 to %3 anyway? Fehler beim Speichern der Sitzung - Could not save session to file %1 - Die Sitzung konnte nicht unter %1 gespeichert werden + Could not save session to file "%1" + Die Sitzung konnte nicht unter "%1" gespeichert werden Untitled @@ -40167,12 +40167,12 @@ fails because Clang does not understand the target architecture. Ausführbare Datei ist leer. - %1 does not exist. - %1 existiert nicht. + "%1" does not exist. + "%1" existiert nicht. - %1 is not an executable file. - %1 ist keine ausführbare Datei. + "%1" is not an executable file. + "%1" ist keine ausführbare Datei. &Add @@ -41539,8 +41539,8 @@ Weder der Pfad zur Bibliothek noch der Pfad zu den Headerdateien wird zur .pro-D Das Ausgabeverzeichnis "%1" konnte nicht angelegt werden - Running in %1: %2 - Führe in %1 aus: %2 + Running in "%1": %2 + Führe in "%1" aus: %2 Build @@ -51138,12 +51138,12 @@ Die Trace-Daten sind verloren. copyFile ist für "%1" nicht implementiert - Cannot copy from %1, it is not a directory. - %1 kann nicht kopiert werden, da es kein Verzeichnis ist. + Cannot copy from "%1", it is not a directory. + "%1" kann nicht kopiert werden, da es kein Verzeichnis ist. - Cannot copy %1 to %2, it is not a writable directory. - %1 kann nicht nach %2 kopiert werden, da es kein schreibbares Verzeichnis ist. + Cannot copy "%1" to "%2", it is not a writable directory. + "%1" kann nicht nach "%2" kopiert werden, da es kein schreibbares Verzeichnis ist. Failed to copy recursively from "%1" to "%2" while trying to create tar archive from source: %3 @@ -51254,14 +51254,12 @@ Die Trace-Daten sind verloren. Arbeitsbereiche löschen - Delete workspace %1? - Arbeitsbereich %1 löschen? + Delete workspace "%1"? + Arbeitsbereich "%1" löschen? - Delete these workspaces? - %1 - Diese Arbeitsbereiche löschen? - %1 + Delete these workspaces? + Diese Arbeitsbereiche löschen? File Error @@ -53268,8 +53266,8 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Führe aus: %1 - Running in %1: %2 - Führe in %1 aus: %2 + Running in "%1": %2 + Führe in "%1" aus: %2 Failed to retrieve data. diff --git a/share/qtcreator/translations/qtcreator_es.ts b/share/qtcreator/translations/qtcreator_es.ts index ff32f1a64cb..a4dc26ed74f 100644 --- a/share/qtcreator/translations/qtcreator_es.ts +++ b/share/qtcreator/translations/qtcreator_es.ts @@ -7179,8 +7179,8 @@ al control de versiones (%2)? Error guardando sesión - Could not save session to file %1 - No se pudo guardar la sesion al archivo %1 + Could not save session to file "%1" + No se pudo guardar la sesion al archivo "%1" Qt Creator diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 48fa7edbe0d..142772f5ca3 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -10837,8 +10837,8 @@ au système de gestion de version (%2) ? Erreur lors de l'enregistrement de la session - Could not save session to file %1 - Impossible d'enregistrer la session dans le fichier %1 + Could not save session to file "%1" + Impossible d'enregistrer la session dans le fichier "%1" Untitled diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 386c4d14929..228e7cae1cb 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -18572,8 +18572,8 @@ Do you want to kill it? U općim postavkama za „Okruženje” konfigurirana zakrpna naredba ne postoji. - Running in %1: %2 %3 - Pokrenuto u %1: %2 %3 + Running in "%1": %2 %3 + Pokrenuto u "%1": %2 %3 Unable to launch "%1": %2 @@ -35830,8 +35830,8 @@ What do you want to do? Radi: %1 %2 - Running in %1: %2 %3 - Radi u %1: %2 %3 + Running in "%1": %2 %3 + Radi u "%1": %2 %3 Name of the version control system in use by the current project. diff --git a/share/qtcreator/translations/qtcreator_hu.ts b/share/qtcreator/translations/qtcreator_hu.ts index ad58a02fa31..843d55c8525 100644 --- a/share/qtcreator/translations/qtcreator_hu.ts +++ b/share/qtcreator/translations/qtcreator_hu.ts @@ -11592,8 +11592,8 @@ a verziókövetőhöz (%2)? Hiba történt a szakasz mentése közben - Could not save session to file %1 - Nem sikerült a szakasz %1 fájlba mentése + Could not save session to file "%1" + Nem sikerült a szakasz "%1" fájlba mentése Qt Creator diff --git a/share/qtcreator/translations/qtcreator_it.ts b/share/qtcreator/translations/qtcreator_it.ts index ccd8832a98b..8e092a00d77 100644 --- a/share/qtcreator/translations/qtcreator_it.ts +++ b/share/qtcreator/translations/qtcreator_it.ts @@ -7033,8 +7033,8 @@ al VCS (%2)? Errore durante il salvataggio della sessione - Could not save session to file %1 - Impossibile salvare la sessione sul file %1 + Could not save session to file "%1" + Impossibile salvare la sessione sul file "%1" Qt Creator diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index 6014b49996a..b89f6284987 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -24418,8 +24418,8 @@ to project "%2". セッション %1 を保存できませんでした - Could not save session to file %1 - セッション %1 を保存できません + Could not save session to file "%1" + セッション "%1" を保存できません Untitled @@ -42568,14 +42568,12 @@ Output: ワークスペースを削除する - Delete workspace %1? - ワークスペース %1 を削除しますか? + Delete workspace "%1"? + ワークスペース "%1" を削除しますか? - Delete these workspaces? - %1 - これらのワークスペースを削除しますか? - %1 + Delete these workspaces? + これらのワークスペースを削除しますか? Cannot Restore Workspace diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index be632f066de..8561c509630 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -7967,8 +7967,8 @@ do projektu "%2". Błąd podczas zachowywania sesji - Could not save session to file %1 - Nie można zachować sesji w pliku %1 + Could not save session to file "%1" + Nie można zachować sesji w pliku "%1" Untitled @@ -28622,8 +28622,8 @@ Do you want to check them out now? Brak skonfigurowanej komendy "patch" w głównych ustawieniach środowiska. - Running in %1: %2 %3 - Uruchamianie w %1: %2 %3 + Running in "%1": %2 %3 + Uruchamianie w "%1": %2 %3 Unable to launch "%1": %2 @@ -31184,8 +31184,8 @@ Pliki z katalogu źródłowego pakietu Android są kopiowane do katalogu budowan Uruchamianie: %1 %2 - Running in %1: %2 %3 - Uruchamianie w %1: %2 %3 + Running in "%1": %2 %3 + Uruchamianie w "%1": %2 %3 diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index f6c71e9dcfd..19b76c17def 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -32,14 +32,12 @@ Удалить сессии - Delete workspace %1? - Удалить сессию %1? + Delete workspace "%1"? + Удалить сессию "%1"? - Delete these workspaces? - %1 - Удалить следующие сессии? - %1 + Delete these workspaces? + Удалить следующие сессии? Cannot Restore Workspace @@ -10566,8 +10564,8 @@ Double-click to edit item. Команда patch, настроенная в общих настройках «Среды», отсутствует. - Running in %1: %2 %3 - Выполняется в %1: %2 %3 + Running in "%1": %2 %3 + Выполняется в "%1": %2 %3 Unable to launch "%1": %2 @@ -32162,8 +32160,8 @@ These files are preserved. Ошибка при сохранении сессии - Could not save session to file %1 - Не удалось сохранить сессию %1 + Could not save session to file "%1" + Не удалось сохранить сессию "%1" Untitled @@ -47662,8 +47660,8 @@ What do you want to do? Исполнение: %1 %2 - Running in %1: %2 %3 - Исполнение в %1: %2 %3 + Running in "%1": %2 %3 + Исполнение в "%1": %2 %3 &Undo diff --git a/share/qtcreator/translations/qtcreator_sl.ts b/share/qtcreator/translations/qtcreator_sl.ts index 462ed14e8af..480193e4525 100644 --- a/share/qtcreator/translations/qtcreator_sl.ts +++ b/share/qtcreator/translations/qtcreator_sl.ts @@ -7426,8 +7426,8 @@ v sistem za nadzor različic (%2)? Napaka med shranjevanjem seje - Could not save session to file %1 - Ni bilo moč shraniti seje v datoteko %1 + Could not save session to file "%1" + Ni bilo moč shraniti seje v datoteko "%1" Untitled diff --git a/share/qtcreator/translations/qtcreator_uk.ts b/share/qtcreator/translations/qtcreator_uk.ts index c50e8d22385..f49ae08943f 100644 --- a/share/qtcreator/translations/qtcreator_uk.ts +++ b/share/qtcreator/translations/qtcreator_uk.ts @@ -14143,8 +14143,8 @@ Reason: %2 Помилка при збереженні сесії - Could not save session to file %1 - Не вдалось зберегти сесію до файлу %1 + Could not save session to file "%1" + Не вдалось зберегти сесію до файлу "%1" Untitled diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index b1e219464c2..4f079bcccb0 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -32,14 +32,12 @@ 删除工作区 - Delete workspace %1? - 删除 %1 工作区? + Delete workspace "%1"? + 删除 "%1" 工作区? - Delete these workspaces? - %1 - 删除这些工作区? - %1 + Delete these workspaces? + 删除这些工作区? Cannot Restore Workspace @@ -30031,8 +30029,8 @@ These files are preserved. 保存会话时发生错误 - Could not save session to file %1 - 无法将会话保存到文件 %1 + Could not save session to file "%1" + 无法将会话保存到文件 "%1" Untitled diff --git a/share/qtcreator/translations/qtcreator_zh_TW.ts b/share/qtcreator/translations/qtcreator_zh_TW.ts index 7f39bb619d1..7e1ff707a67 100644 --- a/share/qtcreator/translations/qtcreator_zh_TW.ts +++ b/share/qtcreator/translations/qtcreator_zh_TW.ts @@ -7218,8 +7218,8 @@ to version control (%2)? 儲存工作階段時發生錯誤 - Could not save session to file %1 - 無法儲存工作階段至檔案 %1 + Could not save session to file "%1" + 無法儲存工作階段至檔案 "%1" Untitled diff --git a/src/libs/advanceddockingsystem/workspaceview.cpp b/src/libs/advanceddockingsystem/workspaceview.cpp index bab54e5e927..1b4cfc7e270 100644 --- a/src/libs/advanceddockingsystem/workspaceview.cpp +++ b/src/libs/advanceddockingsystem/workspaceview.cpp @@ -325,10 +325,10 @@ bool WorkspaceView::confirmWorkspaceDelete(const QStringList &fileNames) { const QString title = fileNames.size() == 1 ? Tr::tr("Delete Workspace") : Tr::tr("Delete Workspaces"); - const QString question - = fileNames.size() == 1 - ? Tr::tr("Delete workspace %1?").arg(fileNames.first()) - : Tr::tr("Delete these workspaces?\n %1").arg(fileNames.join("\n ")); + const QString question = fileNames.size() == 1 + ? Tr::tr("Delete workspace \"%1\"?").arg(fileNames.first()) + : Tr::tr("Delete these workspaces?") + + QString("\n %1").arg(fileNames.join("\n ")); return QMessageBox::question(parentWidget(), title, question, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes; } diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index a29c5bb9be6..ef6640d8a21 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -197,15 +197,15 @@ expected_str DeviceFileAccess::copyRecursively(const FilePath &src, const FilePath &target) const { if (!src.isDir()) { - return make_unexpected(Tr::tr("Cannot copy from %1, it is not a directory.") - .arg(src.toUserOutput()) - .arg(target.toUserOutput())); + return make_unexpected( + Tr::tr("Cannot copy from \"%1\", it is not a directory.").arg(src.toUserOutput())); } if (!target.ensureWritableDir()) { - return make_unexpected(Tr::tr("Cannot copy %1 to %2, it is not a writable directory.") - .arg(src.toUserOutput()) - .arg(target.toUserOutput())); + return make_unexpected( + Tr::tr("Cannot copy \"%1\" to \"%2\", it is not a writable directory.") + .arg(src.toUserOutput()) + .arg(target.toUserOutput())); } #ifdef UTILS_STATIC_LIBRARY diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 610fd86ec29..78b6449a7a9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -238,7 +238,7 @@ void CMakeProject::readPresets() if (includeStack.contains(includePath)) { TaskHub::addTask(BuildSystemTask( Task::TaskType::Warning, - Tr::tr("Attempt to include %1 which was already parsed.") + Tr::tr("Attempt to include \"%1\" which was already parsed.") .arg(includePath.path()), Utils::FilePath(), -1)); diff --git a/src/plugins/coreplugin/patchtool.cpp b/src/plugins/coreplugin/patchtool.cpp index af6c11825d4..d5450259809 100644 --- a/src/plugins/coreplugin/patchtool.cpp +++ b/src/plugins/coreplugin/patchtool.cpp @@ -93,7 +93,8 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec if (patchAction == PatchAction::Revert) args << "-R"; args << "--binary"; - MessageManager::writeDisrupting(Tr::tr("Running in %1: %2 %3") + MessageManager::writeDisrupting( + Tr::tr("Running in \"%1\": %2 %3") .arg(workingDirectory.toUserOutput(), patch.toUserOutput(), args.join(' '))); patchProcess.setCommand({patch, args}); patchProcess.setWriteData(input); diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index d6ccc4ca716..50873c385c6 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -720,7 +720,7 @@ bool SessionManager::saveSession() } else { QMessageBox::warning(ICore::dialogParent(), PE::Tr::tr("Error while saving session"), - PE::Tr::tr("Could not save session to file %1") + PE::Tr::tr("Could not save session to file \"%1\"") .arg(sb_d->m_writer->fileName().toUserOutput())); } diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 96f97feea3b..edc65f76526 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -780,11 +780,11 @@ void CppEditorWidget::showRenameWarningIfFileIsGenerated(const Utils::FilePath & static const Id infoId("cppeditor.renameWarning"); InfoBarEntry info(infoId, warning); if (ec) { - info.addCustomButton(CppEditor::Tr::tr("Open %1").arg(ec->source().fileName()), - [source = ec->source()] { - EditorManager::openEditor(source); - ICore::infoBar()->removeInfo(infoId); - }); + info.addCustomButton(CppEditor::Tr::tr("Open \"%1\"").arg(ec->source().fileName()), + [source = ec->source()] { + EditorManager::openEditor(source); + ICore::infoBar()->removeInfo(infoId); + }); } ICore::infoBar()->addInfo(info); return; diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 0a6abe2e043..1de24a3061c 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -171,9 +171,10 @@ InterpreterOptionsWidget::InterpreterOptionsWidget() if (interpreter.command.isEmpty()) return Tr::tr("Executable is empty."); if (!interpreter.command.exists()) - return Tr::tr("%1 does not exist.").arg(interpreter.command.toUserOutput()); + return Tr::tr("\"%1\" does not exist.").arg(interpreter.command.toUserOutput()); if (!interpreter.command.isExecutableFile()) - return Tr::tr("%1 is not an executable file.").arg(interpreter.command.toUserOutput()); + return Tr::tr("\"%1\" is not an executable file.") + .arg(interpreter.command.toUserOutput()); break; case Qt::DecorationRole: if (column == 0 && !interpreter.command.isExecutableFile()) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 2b73c154f6d..c4c76017d44 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1604,8 +1604,8 @@ void QmakeBuildSystem::runGenerator(Utils::Id id) proc->setWorkingDirectory(outDir); proc->setEnvironment(buildConfiguration()->environment()); proc->setCommand(cmdLine); - Core::MessageManager::writeFlashing(Tr::tr("Running in %1: %2") - .arg(outDir.toUserOutput(), cmdLine.toUserOutput())); + Core::MessageManager::writeFlashing( + Tr::tr("Running in \"%1\": %2").arg(outDir.toUserOutput(), cmdLine.toUserOutput())); proc->start(); } diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index 2b5536809f8..4908e90498c 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -444,7 +444,7 @@ QString VcsOutputWindow::msgExecutionLogEntry(const FilePath &workingDir, const + ' ' + formatArguments(command.splitArguments()); if (workingDir.isEmpty()) return Tr::tr("Running: %1").arg(maskedCmdline) + '\n'; - return Tr::tr("Running in %1: %2").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; + return Tr::tr("Running in \"%1\": %2").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; } void VcsOutputWindow::appendShellCommandLine(const QString &text) From 6e7bb28f0979dea21c7ed42a34103cbaeea8123d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 11:52:43 +0200 Subject: [PATCH 1307/1447] Tr: Add missing full stops Change-Id: I2debc56d0740eaa30c7d597eae18910f319c1d98 Reviewed-by: Leena Miettinen --- .../qtforpythonapplication/widget/wizard.json | 2 +- .../projects/qtquickapplication/wizard.json | 6 +- share/qtcreator/translations/qtcreator_da.ts | 8 +- share/qtcreator/translations/qtcreator_de.ts | 92 +++++++++---------- share/qtcreator/translations/qtcreator_hr.ts | 8 +- share/qtcreator/translations/qtcreator_ja.ts | 4 +- share/qtcreator/translations/qtcreator_pl.ts | 8 +- share/qtcreator/translations/qtcreator_ru.ts | 8 +- src/libs/qmljs/qmljsbind.cpp | 2 +- src/libs/utils/devicefileaccess.cpp | 25 ++--- .../cmakeprojectmanager/cmakebuildsystem.cpp | 10 +- src/plugins/coreplugin/loggingviewer.cpp | 2 +- src/plugins/coreplugin/patchtool.cpp | 2 +- .../qmakeprojectmanager/qmakeproject.cpp | 4 +- src/plugins/vcsbase/vcsoutputwindow.cpp | 2 +- 15 files changed, 92 insertions(+), 91 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json index 8362cd55ecc..6251eaf3341 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "PythonProject" ], "id": "F.QtForPythonApplicationWindowWidget", "category": "F.ApplicationPySide", - "trDescription": "Creates a Qt for Python application that includes a Qt Designer-based widget (ui file) - Requires .ui to Python conversion", + "trDescription": "Creates a Qt for Python application that includes a Qt Designer-based widget (ui file). Requires .ui to Python conversion.", "trDisplayName": "Window UI", "trDisplayCategory": "Application (Qt for Python)", "icon": "../icons/icon.png", diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index dbfe93bbca1..42b2d1ec0c1 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -54,8 +54,8 @@ [ { "name": "QdsProjectStyle", - "trDisplayName": "Create a project that you can open in Qt Design Studio", - "trToolTip": "Create a project with a structure that is compatible both with Qt Design Studio (via .qmlproject) and with Qt Creator (via CMakeLists.txt). It contains a .ui.qml form that you can visually edit in Qt Design Studio.", + "trDisplayName": "Creates a project that you can open in Qt Design Studio.", + "trToolTip": "Creates a project with a structure that is compatible both with Qt Design Studio (via .qmlproject) and with Qt Creator (via CMakeLists.txt). It contains a .ui.qml form that you can visually edit in Qt Design Studio.", "type": "CheckBox", "span": true, "persistenceKey": "QtQuick.QdsProjectStyle", @@ -77,7 +77,7 @@ }, { "name": "MinimumSupportedQtVersion", - "trDisplayName": "The minimum version of Qt you want to build the application for", + "trDisplayName": "The minimum version of Qt you want to build the application for.", "type": "ComboBox", "data": { diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 1a285e8c8ad..4194df48a0f 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -7810,8 +7810,8 @@ Vil du dræbe den? Patch-kommandoen konfigureret i de generelle "Miljø"-indstillinger findes ikke. - Running in "%1": %2 %3 - Kører om "%1": %2 %3 + Running in "%1": %2 %3. + Kører om "%1": %2 %3. Unable to launch "%1": %2 @@ -38022,8 +38022,8 @@ skal være et repository krævet SSH-autentifikation (se dokumentation på SSH o Kører: %1 %2 - Running in %1: %2 %3 - Kører om %1: %2 %3 + Running in %1: %2 %3. + Kører om %1: %2 %3. diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 9b29bb1bf08..74c14d2e27c 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -13396,20 +13396,20 @@ Möchten Sie den Pfad zu den Quelldateien in die Zwischenablage kopieren?CMake-Generator fehlgeschlagen: %1. - Kit does not have a cmake binary set - Das Kit hat keine ausführbare CMake-Datei gesetzt + Kit does not have a cmake binary set. + Das Kit hat keine ausführbare CMake-Datei gesetzt. - Cannot create output directory "%1" - Das Ausgabeverzeichnis "%1" konnte nicht angelegt werden + Cannot create output directory "%1". + Das Ausgabeverzeichnis "%1" konnte nicht angelegt werden. - No valid cmake executable - Keine gültige ausführbare CMake-Datei + No valid cmake executable. + Keine gültige ausführbare CMake-Datei. - Running in "%1": %2 - Führe in "%1" aus: %2 + Running in "%1": %2. + Führe in "%1" aus: %2. <No CMake Tool available> @@ -16566,8 +16566,8 @@ Trotzdem fortfahren? Das in den allgemeinen Umgebungseinstellungen konfigurierte patch-Kommando existiert nicht. - Running in "%1": %2 %3 - Führe in "%1" aus: %2 %3 + Running in "%1": %2 %3. + Führe in "%1" aus: %2 %3. Unable to launch "%1": %2 @@ -19001,8 +19001,8 @@ Doppelklicken Sie einen Eintrag um ihn zu ändern. Ausgewählte Kategorien laden - Failed to open preset file "%1" for reading - Datei "%1" konnte nicht zum Lesen der Voreinstellung geöffnet werden + Failed to open preset file "%1" for reading. + Datei "%1" konnte nicht zum Lesen der Voreinstellung geöffnet werden. Failed to read preset file "%1": %2 @@ -37953,7 +37953,7 @@ Wählt eine für Desktop-Entwicklung geeignete Qt-Version aus, sofern sie verfü Leeres Fenster - Creates a Qt for Python application that includes a Qt Designer-based widget (ui file) - Requires .ui to Python conversion + Creates a Qt for Python application that includes a Qt Designer-based widget (ui file). Requires .ui to Python conversion. Erstellt eine Qt for Python-Anwendung, die ein Qt Designer-basiertes Widget (ui-Datei) enthält. Erfordert Umwandlung von .ui nach Python. @@ -38089,16 +38089,16 @@ Benutzen Sie dies nur für Prototypen. Sie können damit keine vollständige Anw Nimble-Anwendung - Create a project that you can open in Qt Design Studio - Erstellt ein Projekt, das in Qt Design Studio geöffnet werden kann + Creates a project that you can open in Qt Design Studio. + Erstellt ein Projekt, das in Qt Design Studio geöffnet werden kann. - Create a project with a structure that is compatible both with Qt Design Studio (via .qmlproject) and with Qt Creator (via CMakeLists.txt). It contains a .ui.qml form that you can visually edit in Qt Design Studio. + Creates a project with a structure that is compatible both with Qt Design Studio (via .qmlproject) and with Qt Creator (via CMakeLists.txt). It contains a .ui.qml form that you can visually edit in Qt Design Studio. Erstellt ein Projekt mit einer Struktur, die sowohl mit Qt Design Studio (via qmlproject) als auch mit Qt Creator (via CMakeLists.txt) kompatibel ist. Es enthält ein .ui.qml-Formular, das in Qt Design Studio visuell bearbeitet werden kann. - The minimum version of Qt you want to build the application for - Die niedrigste Qt-Version, die Sie zum Bauen der Anwendung benutzen wollen + The minimum version of Qt you want to build the application for. + Die niedrigste Qt-Version, die Sie zum Bauen der Anwendung benutzen wollen. Creates a Qt Quick application that contains an empty window. Optionally, you can create a Qt Design Studio project. @@ -41535,12 +41535,12 @@ Weder der Pfad zur Bibliothek noch der Pfad zu den Headerdateien wird zur .pro-D Kein qmake-Build-Schritt in der aktiven Build-Konfiguration - Cannot create output directory "%1" - Das Ausgabeverzeichnis "%1" konnte nicht angelegt werden + Cannot create output directory "%1". + Das Ausgabeverzeichnis "%1" konnte nicht angelegt werden. - Running in "%1": %2 - Führe in "%1" aus: %2 + Running in "%1": %2. + Führe in "%1" aus: %2. Build @@ -41993,8 +41993,8 @@ Für CMake-Projekte stellen Sie sicher, dass die Variable QML_IMPORT_PATH in CMa Package-Import erfordert eine Versionsnummer - Nested inline components are not supported - Verschachtelte Inline-Komponenten werden nicht unterstützt + Nested inline components are not supported. + Verschachtelte Inline-Komponenten werden nicht unterstützt. Errors while loading qmltypes from %1: @@ -51134,8 +51134,8 @@ Die Trace-Daten sind verloren. Der Rückgabewert des Prozesses konnte nicht erhalten werden: %1 - copyFile is not implemented for "%1" - copyFile ist für "%1" nicht implementiert + copyFile is not implemented for "%1". + copyFile ist für "%1" nicht implementiert. Cannot copy from "%1", it is not a directory. @@ -51154,16 +51154,16 @@ Die Trace-Daten sind verloren. Rekursives Kopieren von "%1" nach "%2" beim Auspacken des Tar-Archivs am Ziel fehlgeschlagen: %3 - fileContents is not implemented for "%1" - fileContents ist für "%1" nicht implementiert + fileContents is not implemented for "%1". + fileContents ist für "%1" nicht implementiert. - writeFileContents is not implemented for "%1" - writeFileContents ist für "%1" nicht implementiert + writeFileContents is not implemented for "%1". + writeFileContents ist für "%1" nicht implementiert. - createTempFile is not implemented for "%1" - createTempFile ist für "%1" nicht implementiert + createTempFile is not implemented for "%1". + createTempFile ist für "%1" nicht implementiert. Refusing to remove root directory. @@ -51186,28 +51186,28 @@ Die Trace-Daten sind verloren. Kopieren der Datei "%1" nach "%2" ist fehlgeschlagen. - File "%1" does not exist - Datei "%1" existiert nicht + File "%1" does not exist. + Datei "%1" existiert nicht. - Could not open File "%1" - Die Datei "%1" konnte nicht geöffnet werden + Could not open File "%1". + Die Datei "%1" konnte nicht geöffnet werden. Cannot read "%1": %2 "%1" kann nicht gelesen werden: %2 - Could not open file "%1" for writing - Die Datei "%1" konnte nicht zum Schreiben geöffnet werden + Could not open file "%1" for writing. + Die Datei "%1" konnte nicht zum Schreiben geöffnet werden. - Could not write to file "%1" (only %2 of %3 bytes written) - Die Datei "%1" konnte nicht geschrieben werden (es wurden nur %2 von %3 Bytes geschrieben) + Could not write to file "%1" (only %2 of %3 bytes written). + Die Datei "%1" konnte nicht geschrieben werden (es wurden nur %2 von %3 Bytes geschrieben). - Could not create temporary file in "%1" (%2) - Es konnte keine temporäre Datei in "%1" erstellt werden (%2) + Could not create temporary file in "%1" (%2). + Es konnte keine temporäre Datei in "%1" erstellt werden (%2). Failed to copy file "%1" to "%2": %3 @@ -51226,8 +51226,8 @@ Die Trace-Daten sind verloren. Die temporäre Datei "%1" konnte nicht erstellt werden: %2 - Failed creating temporary file "%1" (too many tries) - Die temporäre Datei "%1" konnte nicht erstellt werden (zu viele Versuche) + Failed creating temporary file "%1" (too many tries). + Die temporäre Datei "%1" konnte nicht erstellt werden (zu viele Versuche). Failed to create directory "%1". @@ -53266,8 +53266,8 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Führe aus: %1 - Running in "%1": %2 - Führe in "%1" aus: %2 + Running in "%1": %2. + Führe in "%1" aus: %2. Failed to retrieve data. diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 228e7cae1cb..6c6158034f2 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -18572,8 +18572,8 @@ Do you want to kill it? U općim postavkama za „Okruženje” konfigurirana zakrpna naredba ne postoji. - Running in "%1": %2 %3 - Pokrenuto u "%1": %2 %3 + Running in "%1": %2 %3. + Pokrenuto u "%1": %2 %3. Unable to launch "%1": %2 @@ -35830,8 +35830,8 @@ What do you want to do? Radi: %1 %2 - Running in "%1": %2 %3 - Radi u "%1": %2 %3 + Running in "%1": %2 %3. + Radi u "%1": %2 %3. Name of the version control system in use by the current project. diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index b89f6284987..ced38a90bad 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -9342,8 +9342,8 @@ will also disable the following plugins: パッケージをインポートするにはバージョン番号が含まれている必要があります - Nested inline components are not supported - インラインコンポーネントのネストはサポートされていません + Nested inline components are not supported. + インラインコンポーネントのネストはサポートされていません。 'int' or 'real' diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 8561c509630..3d374501ffd 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -28622,8 +28622,8 @@ Do you want to check them out now? Brak skonfigurowanej komendy "patch" w głównych ustawieniach środowiska. - Running in "%1": %2 %3 - Uruchamianie w "%1": %2 %3 + Running in "%1": %2 %3. + Uruchamianie w "%1": %2 %3. Unable to launch "%1": %2 @@ -31184,8 +31184,8 @@ Pliki z katalogu źródłowego pakietu Android są kopiowane do katalogu budowan Uruchamianie: %1 %2 - Running in "%1": %2 %3 - Uruchamianie w "%1": %2 %3 + Running in "%1": %2 %3. + Uruchamianie w "%1": %2 %3. diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 19b76c17def..5b10b1e755f 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -10564,8 +10564,8 @@ Double-click to edit item. Команда patch, настроенная в общих настройках «Среды», отсутствует. - Running in "%1": %2 %3 - Выполняется в "%1": %2 %3 + Running in "%1": %2 %3. + Выполняется в "%1": %2 %3. Unable to launch "%1": %2 @@ -47660,8 +47660,8 @@ What do you want to do? Исполнение: %1 %2 - Running in "%1": %2 %3 - Исполнение в "%1": %2 %3 + Running in "%1": %2 %3. + Исполнение в "%1": %2 %3. &Undo diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp index e2143ed68ec..6ccddcbe630 100644 --- a/src/libs/qmljs/qmljsbind.cpp +++ b/src/libs/qmljs/qmljsbind.cpp @@ -326,7 +326,7 @@ bool Bind::visit(UiInlineComponent *ast) if (!_currentComponentName.isEmpty()) { _currentComponentName += "."; _diagnosticMessages->append( - errorMessage(ast, Tr::tr("Nested inline components are not supported"))); + errorMessage(ast, Tr::tr("Nested inline components are not supported."))); } _currentComponentName += ast->name.toString(); _rootObjectValue = nullptr; diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index ef6640d8a21..f5bb1d20482 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -161,7 +161,7 @@ expected_str DeviceFileAccess::copyFile(const FilePath &filePath, const Fi Q_UNUSED(target) QTC_CHECK(false); return make_unexpected( - Tr::tr("copyFile is not implemented for \"%1\"").arg(filePath.toUserOutput())); + Tr::tr("copyFile is not implemented for \"%1\".").arg(filePath.toUserOutput())); } expected_str copyRecursively_fallback(const FilePath &src, const FilePath &target) @@ -305,7 +305,7 @@ expected_str DeviceFileAccess::fileContents(const FilePath &filePath Q_UNUSED(offset) QTC_CHECK(false); return make_unexpected( - Tr::tr("fileContents is not implemented for \"%1\"").arg(filePath.toUserOutput())); + Tr::tr("fileContents is not implemented for \"%1\".").arg(filePath.toUserOutput())); } expected_str DeviceFileAccess::writeFileContents(const FilePath &filePath, @@ -317,7 +317,7 @@ expected_str DeviceFileAccess::writeFileContents(const FilePath &filePat Q_UNUSED(offset) QTC_CHECK(false); return make_unexpected( - Tr::tr("writeFileContents is not implemented for \"%1\"").arg(filePath.toUserOutput())); + Tr::tr("writeFileContents is not implemented for \"%1\".").arg(filePath.toUserOutput())); } FilePathInfo DeviceFileAccess::filePathInfo(const FilePath &filePath) const @@ -382,8 +382,8 @@ expected_str DeviceFileAccess::createTempFile(const FilePath &filePath { Q_UNUSED(filePath) QTC_CHECK(false); - return make_unexpected(Tr::tr("createTempFile is not implemented for \"%1\"") - .arg(filePath.toUserOutput())); + return make_unexpected( + Tr::tr("createTempFile is not implemented for \"%1\".").arg(filePath.toUserOutput())); } @@ -658,10 +658,10 @@ expected_str DesktopDeviceFileAccess::fileContents(const FilePath &f const QString path = filePath.path(); QFile f(path); if (!f.exists()) - return make_unexpected(Tr::tr("File \"%1\" does not exist").arg(path)); + return make_unexpected(Tr::tr("File \"%1\" does not exist.").arg(path)); if (!f.open(QFile::ReadOnly)) - return make_unexpected(Tr::tr("Could not open File \"%1\"").arg(path)); + return make_unexpected(Tr::tr("Could not open File \"%1\".").arg(path)); if (offset != 0) f.seek(offset); @@ -686,14 +686,14 @@ expected_str DesktopDeviceFileAccess::writeFileContents(const FilePath & const bool isOpened = file.open(QFile::WriteOnly | QFile::Truncate); if (!isOpened) return make_unexpected( - Tr::tr("Could not open file \"%1\" for writing").arg(filePath.toUserOutput())); + Tr::tr("Could not open file \"%1\" for writing.").arg(filePath.toUserOutput())); if (offset != 0) file.seek(offset); qint64 res = file.write(data); if (res != data.size()) return make_unexpected( - Tr::tr("Could not write to file \"%1\" (only %2 of %3 bytes written)") + Tr::tr("Could not write to file \"%1\" (only %2 of %3 bytes written).") .arg(filePath.toUserOutput()) .arg(res) .arg(data.size())); @@ -705,8 +705,9 @@ expected_str DesktopDeviceFileAccess::createTempFile(const FilePath &f QTemporaryFile file(filePath.path()); file.setAutoRemove(false); if (!file.open()) { - return make_unexpected(Tr::tr("Could not create temporary file in \"%1\" (%2)") - .arg(filePath.toUserOutput()).arg(file.errorString())); + return make_unexpected(Tr::tr("Could not create temporary file in \"%1\" (%2).") + .arg(filePath.toUserOutput()) + .arg(file.errorString())); } return filePath.withNewPath(file.fileName()); } @@ -1039,7 +1040,7 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file } newPath = filePath.withNewPath(tmplate); if (--maxTries == 0) { - return make_unexpected(Tr::tr("Failed creating temporary file \"%1\" (too many tries)") + return make_unexpected(Tr::tr("Failed creating temporary file \"%1\" (too many tries).") .arg(filePath.toUserOutput())); } } while (newPath.exists()); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 7e10a06e259..1bd19dffeb1 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -1712,20 +1712,20 @@ void CMakeBuildSystem::runGenerator(Id id) const CMakeTool * const cmakeTool = CMakeKitAspect::cmakeTool(buildConfiguration()->target()->kit()); if (!cmakeTool) { - showError(Tr::tr("Kit does not have a cmake binary set")); + showError(Tr::tr("Kit does not have a cmake binary set.")); return; } const QString generator = id.toSetting().toString(); const FilePath outDir = buildConfiguration()->buildDirectory() / ("qtc_" + FileUtils::fileSystemFriendlyName(generator)); if (!outDir.ensureWritableDir()) { - showError(Tr::tr("Cannot create output directory \"%1\"").arg(outDir.toString())); + showError(Tr::tr("Cannot create output directory \"%1\".").arg(outDir.toString())); return; } CommandLine cmdLine(cmakeTool->cmakeExecutable(), {"-S", buildConfiguration()->target() ->project()->projectDirectory().toUserOutput(), "-G", generator}); if (!cmdLine.executable().isExecutableFile()) { - showError(Tr::tr("No valid cmake executable")); + showError(Tr::tr("No valid cmake executable.")); return; } const auto itemFilter = [](const CMakeConfigItem &item) { @@ -1762,8 +1762,8 @@ void CMakeBuildSystem::runGenerator(Id id) proc->setWorkingDirectory(outDir); proc->setEnvironment(buildConfiguration()->environment()); proc->setCommand(cmdLine); - Core::MessageManager::writeFlashing(Tr::tr("Running in %1: %2") - .arg(outDir.toUserOutput(), cmdLine.toUserOutput())); + Core::MessageManager::writeFlashing( + Tr::tr("Running in %1: %2.").arg(outDir.toUserOutput(), cmdLine.toUserOutput())); proc->start(); } diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp index d35a5da20bf..a81ed5936db 100644 --- a/src/plugins/coreplugin/loggingviewer.cpp +++ b/src/plugins/coreplugin/loggingviewer.cpp @@ -656,7 +656,7 @@ void LoggingViewManagerWidget::loadAndUpdateFromPreset() if (!contents) { QMessageBox::critical(ICore::dialogParent(), Tr::tr("Error"), - Tr::tr("Failed to open preset file \"%1\" for reading") + Tr::tr("Failed to open preset file \"%1\" for reading.") .arg(fp.toUserOutput())); return; } diff --git a/src/plugins/coreplugin/patchtool.cpp b/src/plugins/coreplugin/patchtool.cpp index d5450259809..744282728a8 100644 --- a/src/plugins/coreplugin/patchtool.cpp +++ b/src/plugins/coreplugin/patchtool.cpp @@ -94,7 +94,7 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec args << "-R"; args << "--binary"; MessageManager::writeDisrupting( - Tr::tr("Running in \"%1\": %2 %3") + Tr::tr("Running in \"%1\": %2 %3.") .arg(workingDirectory.toUserOutput(), patch.toUserOutput(), args.join(' '))); patchProcess.setCommand({patch, args}); patchProcess.setWriteData(input); diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index c4c76017d44..1a180bf833b 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1590,7 +1590,7 @@ void QmakeBuildSystem::runGenerator(Utils::Id id) QTC_ASSERT(false, return); } if (!outDir.ensureWritableDir()) { - showError(Tr::tr("Cannot create output directory \"%1\"").arg(outDir.toUserOutput())); + showError(Tr::tr("Cannot create output directory \"%1\".").arg(outDir.toUserOutput())); return; } const auto proc = new Process(this); @@ -1605,7 +1605,7 @@ void QmakeBuildSystem::runGenerator(Utils::Id id) proc->setEnvironment(buildConfiguration()->environment()); proc->setCommand(cmdLine); Core::MessageManager::writeFlashing( - Tr::tr("Running in \"%1\": %2").arg(outDir.toUserOutput(), cmdLine.toUserOutput())); + Tr::tr("Running in \"%1\": %2.").arg(outDir.toUserOutput(), cmdLine.toUserOutput())); proc->start(); } diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index 4908e90498c..816aa79f022 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -444,7 +444,7 @@ QString VcsOutputWindow::msgExecutionLogEntry(const FilePath &workingDir, const + ' ' + formatArguments(command.splitArguments()); if (workingDir.isEmpty()) return Tr::tr("Running: %1").arg(maskedCmdline) + '\n'; - return Tr::tr("Running in \"%1\": %2").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; + return Tr::tr("Running in \"%1\": %2.").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; } void VcsOutputWindow::appendShellCommandLine(const QString &text) From 809f7c6cfdb156e4084ee91023cb35ed51d55803 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 10:51:34 +0200 Subject: [PATCH 1308/1447] TaskFile: Prevent creating invalid tasks Task-number: QTCREATORBUG-29209 Change-Id: I00c8152b598483c35ebb16c4ab5c58949c273065 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/projectexplorer/taskfile.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/projectexplorer/taskfile.cpp b/src/plugins/projectexplorer/taskfile.cpp index deb9a3ee6d8..c967521d894 100644 --- a/src/plugins/projectexplorer/taskfile.cpp +++ b/src/plugins/projectexplorer/taskfile.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -148,6 +149,10 @@ static bool parseTaskFile(QString *errorString, const FilePath &name) } description = unescape(description); + if (description.trimmed().isEmpty()) { + MessageManager::writeFlashing(Tr::tr("Ignoring invalid task (no text).")); + continue; + } TaskHub::addTask(Task(type, description, FilePath::fromUserInput(file), line, Constants::TASK_CATEGORY_TASKLIST_ID)); } From fb59c70dcb1ace439cf9a03e95d90dd34dbe9584 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 14:10:38 +0200 Subject: [PATCH 1309/1447] CppEditor: Revert changes to parseExpressionStatement() Amends c8f29b9e0148202ab1959466e14fa23411fd8214. It turns out that there are contexts where we want to parse an expression statement even with the semicolon missing (e.g. completion on incomplete code). So leave the existing functions unchanged and do the thorough check afterwards in parseIfStatement(). Change-Id: Id6209ef1abfe9d155c5b9381e6ae655cc721feb2 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger --- src/libs/3rdparty/cplusplus/AST.h | 1 - src/libs/3rdparty/cplusplus/ASTClone.cpp | 2 -- src/libs/3rdparty/cplusplus/ASTMatcher.cpp | 5 ---- src/libs/3rdparty/cplusplus/ASTVisit.cpp | 1 - src/libs/3rdparty/cplusplus/Bind.cpp | 4 +-- src/libs/3rdparty/cplusplus/Parser.cpp | 34 ++++++++++++++-------- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 6a5da23306a..3f48e192b93 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -1779,7 +1779,6 @@ public: int if_token = 0; int constexpr_token = 0; int lparen_token = 0; - DeclarationAST *initDecl = nullptr; StatementAST *initStmt = nullptr; ExpressionAST *condition = nullptr; int rparen_token = 0; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 57617bb1180..c9c2fc8294a 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -785,8 +785,6 @@ IfStatementAST *IfStatementAST::clone(MemoryPool *pool) const ast->if_token = if_token; ast->constexpr_token = constexpr_token; ast->lparen_token = lparen_token; - if (initDecl) - ast->initDecl = initDecl->clone(pool); if (initStmt) ast->initStmt = initStmt->clone(pool); if (condition) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index 6f12efb8aca..b264098a969 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -1318,11 +1318,6 @@ bool ASTMatcher::match(IfStatementAST *node, IfStatementAST *pattern) pattern->lparen_token = node->lparen_token; - if (!pattern->initDecl) - pattern->initDecl = node->initDecl; - else if (!AST::match(node->initDecl, pattern->initDecl, this)) - return false; - if (!pattern->initStmt) pattern->initStmt = node->initStmt; else if (!AST::match(node->initStmt, pattern->initStmt, this)) diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 7e8f75f2334..5b0ef3ce330 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -563,7 +563,6 @@ void ForStatementAST::accept0(ASTVisitor *visitor) void IfStatementAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { - accept(initDecl, visitor); accept(initStmt, visitor); accept(condition, visitor); accept(statement, visitor); diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index e3d38a09a84..c85d401c49b 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -1528,9 +1528,7 @@ bool Bind::visit(IfStatementAST *ast) ast->symbol = block; Scope *previousScope = switchScope(block); - if (ast->initDecl) - this->declaration(ast->initDecl); - else if (ast->initStmt) + if (ast->initStmt) this->statement(ast->initStmt); /*ExpressionTy condition =*/ this->expression(ast->condition); this->statement(ast->statement); diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 31e290d1ad6..6bf19f59829 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -3511,14 +3511,12 @@ bool Parser::parseExpressionStatement(StatementAST *&node) ExpressionAST *expression = nullptr; if (parseExpression(expression)) { - if (LA() == T_SEMICOLON) { - ExpressionStatementAST *ast = new (previousPool) ExpressionStatementAST; - ast->semicolon_token = consumeToken(); - if (expression) - ast->expression = expression->clone(previousPool); - node = ast; - parsed = true; - } + ExpressionStatementAST *ast = new (previousPool) ExpressionStatementAST; + if (expression) + ast->expression = expression->clone(previousPool); + match(T_SEMICOLON, &ast->semicolon_token); + node = ast; + parsed = true; } _inExpressionStatement = wasInExpressionStatement; @@ -4079,14 +4077,26 @@ bool Parser::parseIfStatement(StatementAST *&node) if (_languageFeatures.cxx17Enabled) { const int savedCursor = cursor(); const bool savedBlockErrors = _translationUnit->blockErrors(true); - if (!parseSimpleDeclaration(ast->initDecl)) { + bool foundInitStmt = parseExpressionOrDeclarationStatement(ast->initStmt); + if (foundInitStmt) + foundInitStmt = ast->initStmt; + if (foundInitStmt) { + if (const auto exprStmt = ast->initStmt->asExpressionStatement()) { + foundInitStmt = exprStmt->semicolon_token; + } else if (const auto declStmt = ast->initStmt->asDeclarationStatement()) { + foundInitStmt = declStmt->declaration + && declStmt->declaration->asSimpleDeclaration() + && declStmt->declaration->asSimpleDeclaration()->semicolon_token; + } else { + foundInitStmt = false; + } + } + if (!foundInitStmt) { + ast->initStmt = nullptr; rewind(savedCursor); - if (!parseExpressionStatement(ast->initStmt)) - rewind(savedCursor); } _translationUnit->blockErrors(savedBlockErrors); } - parseCondition(ast->condition); match(T_RPAREN, &ast->rparen_token); if (! parseStatement(ast->statement)) From 08b5f64c1a280177d937e2c27d5e3a582ae03eff Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 26 May 2023 13:50:44 +0200 Subject: [PATCH 1310/1447] Doc: Mark destructors as \internal instead of \reimp in Aspects docs Document BoolAspect::value(). Change-Id: Ia7f359e9302d371e3ea79fc3fce04e3c3c9a22a0 Reviewed-by: Eike Ziller --- src/libs/utils/aspects.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 0e7050a7e0a..d3610b2c7da 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1441,7 +1441,7 @@ BoolAspect::BoolAspect(AspectContainer *container) } /*! - \reimp + \internal */ BoolAspect::~BoolAspect() = default; @@ -1537,7 +1537,7 @@ void BoolAspect::emitChangedValue() /*! - \reimp + Returns the value of the boolean aspect as a boolean value. */ bool BoolAspect::value() const @@ -1609,7 +1609,7 @@ SelectionAspect::SelectionAspect(AspectContainer *container) } /*! - \reimp + \internal */ SelectionAspect::~SelectionAspect() = default; @@ -1813,7 +1813,7 @@ MultiSelectionAspect::MultiSelectionAspect(AspectContainer *container) } /*! - \reimp + \internal */ MultiSelectionAspect::~MultiSelectionAspect() = default; @@ -1922,7 +1922,7 @@ IntegerAspect::IntegerAspect(AspectContainer *container) } /*! - \reimp + \internal */ IntegerAspect::~IntegerAspect() = default; @@ -2056,7 +2056,7 @@ DoubleAspect::DoubleAspect(AspectContainer *container) } /*! - \reimp + \internal */ DoubleAspect::~DoubleAspect() = default; @@ -2210,7 +2210,7 @@ StringListAspect::StringListAspect(AspectContainer *container) } /*! - \reimp + \internal */ StringListAspect::~StringListAspect() = default; @@ -2282,7 +2282,7 @@ IntegersAspect::IntegersAspect(AspectContainer *container) } /*! - \reimp + \internal */ IntegersAspect::~IntegersAspect() = default; @@ -2346,7 +2346,7 @@ TextDisplay::TextDisplay(const QString &message, InfoLabel::InfoType type) } /*! - \reimp + \internal */ TextDisplay::~TextDisplay() = default; @@ -2412,7 +2412,7 @@ AspectContainer::AspectContainer(QObject *parent) {} /*! - \reimp + \internal */ AspectContainer::~AspectContainer() { From 380dc1cbed7715e3eecd5c0c844e5425e98ce91f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 16:06:24 +0200 Subject: [PATCH 1311/1447] ProjectExplorer: Fix warning about unnecessary std::move() Apparently, the original warning about an allegedly missing move does not appear anymore with current apple clang. Change-Id: If3704b62e72765156fd3264267c98ea91b4d04c3 Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/msvcparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index 89c59443e1b..8452afcc5ab 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -61,7 +61,7 @@ static Task handleNmakeJomMessage(const QString &line) CompileTask task(type, line.mid(matchLength).trimmed()); task.details << line; - return std::move(task); + return task; } static Task::TaskType taskType(const QString &category) From d15da2c0f975e72db747b1f5d2f6db489b9d8ff1 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 26 May 2023 13:57:46 +0200 Subject: [PATCH 1312/1447] Doc: Fix qdoc warnings in Core plugin docs Change-Id: Id7b7c1c66e75ad5bce2ea9801493eb7872121e52 Reviewed-by: Eike Ziller --- .../coreplugin/actionmanager/commandbutton.cpp | 6 ++++-- .../coreplugin/dialogs/ioptionspage.cpp | 2 +- src/plugins/coreplugin/documentmanager.cpp | 4 ++++ .../coreplugin/editormanager/editormanager.cpp | 10 +++++++++- src/plugins/coreplugin/featureprovider.cpp | 12 ++++++++---- .../coreplugin/find/searchresultwindow.cpp | 3 ++- src/plugins/coreplugin/iwizardfactory.cpp | 14 ++++++++++++++ .../coreplugin/locator/ilocatorfilter.cpp | 5 ++--- src/plugins/coreplugin/session.cpp | 18 ++++++++++++++---- 9 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/plugins/coreplugin/actionmanager/commandbutton.cpp b/src/plugins/coreplugin/actionmanager/commandbutton.cpp index ed724e42d02..a8dab391368 100644 --- a/src/plugins/coreplugin/actionmanager/commandbutton.cpp +++ b/src/plugins/coreplugin/actionmanager/commandbutton.cpp @@ -92,7 +92,8 @@ QString CommandAction::toolTipBase() const } /*! - Sets the base tool tip that is extended with the command's shortcut. + Sets the base tool tip that is extended with the command's shortcut to + \a toolTipBase. \sa toolTipBase() */ @@ -155,7 +156,8 @@ QString CommandButton::toolTipBase() const } /*! - Sets the base tool tip that is extended with the command's shortcut. + Sets the base tool tip that is extended with the command's shortcut to + \a toolTipBase. \sa toolTipBase() */ diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index d7646749c68..1912045af53 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -250,7 +250,7 @@ void IOptionsPage::setLayouter(const std::function &la static QList g_optionsPages; /*! - Constructs an options page with the given \a parent and registers it + Constructs an options page and registers it at the global options page pool if \a registerGlobally is \c true. */ IOptionsPage::IOptionsPage(bool registerGlobally) diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 226564fa0ba..98ab6514119 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -1027,6 +1027,10 @@ void DocumentManager::showFilePropertiesDialog(const FilePath &filePath) and \a selectedFilter arguments are interpreted like in QFileDialog::getOpenFileNames(). \a pathIn specifies a path to open the dialog in if that is not overridden by the user's policy. + + The \a options argument holds various options about how to run the dialog. + See the QFileDialog::Option enum for more information about the flags you + can pass. */ FilePaths DocumentManager::getOpenFileNames(const QString &filters, diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 227ffba28c8..e7147e94cea 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -239,6 +239,10 @@ void EditorManagerPlaceHolder::showEvent(QShowEvent *) \value SwitchSplitIfAlreadyVisible Switches to another split if the document is already visible there. + \value DoNotRaise + Prevents raising the \QC window to the foreground. + \value AllowExternalEditor + Allows opening the file in an external editor. */ /*! @@ -3246,7 +3250,11 @@ void EditorManager::addCloseEditorListener(const std::function /*! Asks the user for a list of files to open and returns the choice. - \sa DocumentManager::getOpenFileNames() + The \a options argument holds various options about how to run the dialog. + See the QFileDialog::Options enum for more information about the flags you + can pass. + + \sa DocumentManager::getOpenFileNames(), QFileDialog::Options */ FilePaths EditorManager::getOpenFilePaths(QFileDialog::Options options) { diff --git a/src/plugins/coreplugin/featureprovider.cpp b/src/plugins/coreplugin/featureprovider.cpp index efe792bfb21..739bdb7067d 100644 --- a/src/plugins/coreplugin/featureprovider.cpp +++ b/src/plugins/coreplugin/featureprovider.cpp @@ -13,18 +13,22 @@ for wizards. The features provided by an object in the object pool implementing IFeatureProvider - will be respected by wizards implementing IWizard. + will be respected by wizards implementing IWizardFactory. This feature set, provided by all instances of IFeatureProvider in the - object pool, is checked against \c IWizard::requiredFeatures() + object pool, is checked against \c IWizardFactory::requiredFeatures() and only if all required features are available, the wizard is displayed when creating a new file or project. + If you created JSON-based wizards, the feature set is checked against the + \c featuresRequired setting that is described in + \l{https://doc.qt.io/qtcreator/creator-project-wizards.html} + {Adding New Custom Wizards} in the \QC Manual. + The QtSupport plugin creates an instance of IFeatureProvider and provides Qt specific features for the available versions of Qt. - \sa Core::IWizard - \sa QtSupport::QtVersionManager + \sa Core::IWizardFactory */ /*! diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 1a2e8c271d1..e2a83a71a0e 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -845,7 +845,8 @@ void SearchResult::setFilter(SearchResultFilter *filter) /*! Notifies the \uicontrol {Search Results} output pane that the current search - has been \a canceled, and the UI should reflect that. + has been \a canceled for the specified \a reason, and the UI should reflect + that. */ void SearchResult::finishSearch(bool canceled, const QString &reason) { diff --git a/src/plugins/coreplugin/iwizardfactory.cpp b/src/plugins/coreplugin/iwizardfactory.cpp index 35713531054..caa664d7e46 100644 --- a/src/plugins/coreplugin/iwizardfactory.cpp +++ b/src/plugins/coreplugin/iwizardfactory.cpp @@ -66,6 +66,17 @@ The wizard creates a new project. */ +/*! + \enum Core::IWizardFactory::WizardFlag + + Holds information about the created projects and files. + + \value PlatformIndependent + The wizard creates projects that run on all platforms. + \value ForceCapitalLetterForFileName + The wizard uses an initial capital letter for the names of new files. +*/ + /*! \fn Core::IWizardFactory::WizardKind Core::IWizardFactory::kind() const Returns what kind of objects are created by the wizard. @@ -237,6 +248,9 @@ FilePath IWizardFactory::runPath(const FilePath &defaultPath) const The \a path argument is a suggestion for the location where files should be created. The wizard should fill this in its path selection elements as a default path. + + When \a showWizard is \c false, the wizard instance is created and set up + but not actually shown. */ Wizard *IWizardFactory::runWizard(const FilePath &path, QWidget *parent, Id platform, const QVariantMap &variables, diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index f277884cce3..f6b39996d8f 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -594,6 +594,7 @@ QString ILocatorFilter::shortcutString() const } /*! + \internal Sets the refresh recipe for refreshing cached data. */ void ILocatorFilter::setRefreshRecipe(const std::optional &recipe) @@ -1277,8 +1278,6 @@ LocatorFilterEntries LocatorFileCachePrivate::generate(const QFuture &futu */ /*! - \fn LocatorFileCache - Constructs an invalid cache. The cache is considered to be in an invalid state after a call to invalidate(), @@ -1382,7 +1381,7 @@ void LocatorFileCache::setFilePathsGenerator(const FilePathsGenerator &generator and sets it to a valid state with the new generator for the passed \a filePaths. The stored generator provider is preserved. - \sa setGenerator + \sa setGeneratorProvider */ void LocatorFileCache::setFilePaths(const FilePaths &filePaths) { diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index 50873c385c6..7238a09a2ee 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -56,7 +56,8 @@ static bool kIsAutoRestoreLastSessionDefault = false; const char M_SESSION[] = "ProjectExplorer.Menu.Session"; /*! - \class ProjectExplorer::SessionManager + \class Core::SessionManager + \inmodule QtCreator \brief The SessionManager class manages sessions. @@ -164,7 +165,8 @@ bool SessionManager::isLoadingSession() } /*! - Lets other plugins store persistent values within the session file. + Lets other plugins store persistent values specified by \a name and \a value + within the session file. */ void SessionManager::setValue(const QString &name, const QVariant &value) @@ -235,6 +237,9 @@ FilePath SessionManager::sessionNameToFileName(const QString &session) /*! Creates \a session, but does not actually create the file. + + Returns whether the creation was successful. + */ bool SessionManager::createSession(const QString &session) @@ -268,7 +273,10 @@ void SessionManager::showSessionManager() } /*! - \brief Shows a dialog asking the user to confirm deleting the session \p session + Shows a dialog asking the user to confirm the deletion of the specified + \a sessions. + + Returns whether the user confirmed the deletion. */ bool SessionManager::confirmSessionDelete(const QStringList &sessions) { @@ -286,6 +294,8 @@ bool SessionManager::confirmSessionDelete(const QStringList &sessions) /*! Deletes \a session name from session list and the file from disk. + + Returns whether the deletion was successful. */ bool SessionManager::deleteSession(const QString &session) { @@ -515,7 +525,7 @@ QString SessionManager::lastSession() } /*! - Returns the session that was active when Qt Creator was last closed, if any. + Returns the session that was active when \QC was last closed, if any. */ QString SessionManager::startupSession() { From 419f5416c52f7f2ee37ba4d9fb41331c46e0e872 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sun, 28 May 2023 07:29:54 +0200 Subject: [PATCH 1313/1447] Git: Avoid main loop blocking in instant blame Query the author and encoding information asynchronous after the current repository is changed. Set the default codec to UTF-8, which should cover most configurations (i.e. almost never be different). In case requesting the information takes longer, the blame mark is already created with the cached information. In case the author or encoding changed, the blame mark has to be recreated. The call to refreshWorkingDirectory() is moved after the widget checks in setupInstantBlame() to avoid requesting these information in VCS editors. Fixes: QTCREATORBUG-29151 Change-Id: I6feccbbed67c877f1015295f630dd63cf3ccf4a0 Reviewed-by: Orgad Shaneh --- src/plugins/git/gitclient.cpp | 36 +++++++++++++++++++----- src/plugins/git/gitclient.h | 11 ++++++++ src/plugins/git/gitplugin.cpp | 52 +++++++++++++++++++++++++++++------ 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 4a7a43a689f..f0427e08268 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -822,14 +822,19 @@ FilePaths GitClient::unmanagedFiles(const FilePaths &filePaths) const return res; } +QTextCodec *GitClient::defaultCommitEncoding() const +{ + // Set default commit encoding to 'UTF-8', when it's not set, + // to solve displaying error of commit log with non-latin characters. + return QTextCodec::codecForName("UTF-8"); +} + QTextCodec *GitClient::encoding(GitClient::EncodingType encodingType, const FilePath &source) const { auto codec = [this](const FilePath &workingDirectory, const QString &configVar) { const QString codecName = readConfigValue(workingDirectory, configVar).trimmed(); - // Set default commit encoding to 'UTF-8', when it's not set, - // to solve displaying error of commit log with non-latin characters. if (codecName.isEmpty()) - return QTextCodec::codecForName("UTF-8"); + return defaultCommitEncoding(); return QTextCodec::codecForName(codecName.toUtf8()); }; @@ -2618,11 +2623,10 @@ bool GitClient::readDataFromCommit(const FilePath &repoDirectory, const QString return true; } -Author GitClient::getAuthor(const Utils::FilePath &workingDirectory) +Author GitClient::parseAuthor(const QString &authorInfo) { // The format is: // Joe Developer unixtimestamp +HHMM - const QString authorInfo = readGitVar(workingDirectory, "GIT_AUTHOR_IDENT"); int lt = authorInfo.lastIndexOf('<'); int gt = authorInfo.lastIndexOf('>'); if (gt == -1 || uint(lt) > uint(gt)) { @@ -2634,6 +2638,12 @@ Author GitClient::getAuthor(const Utils::FilePath &workingDirectory) return result; } +Author GitClient::getAuthor(const Utils::FilePath &workingDirectory) +{ + const QString authorInfo = readGitVar(workingDirectory, "GIT_AUTHOR_IDENT"); + return parseAuthor(authorInfo); +} + bool GitClient::getCommitData(const FilePath &workingDirectory, QString *commitTemplate, CommitData &commitData, @@ -3425,21 +3435,33 @@ QString GitClient::readGitVar(const FilePath &workingDirectory, const QString &c return readOneLine(workingDirectory, {"var", configVar}); } -QString GitClient::readOneLine(const FilePath &workingDirectory, const QStringList &arguments) const +static QTextCodec *configFileCodec() { // Git for Windows always uses UTF-8 for configuration: // https://github.com/msysgit/msysgit/wiki/Git-for-Windows-Unicode-Support#convert-config-files static QTextCodec *codec = HostOsInfo::isWindowsHost() ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale(); + return codec; +} +QString GitClient::readOneLine(const FilePath &workingDirectory, const QStringList &arguments) const +{ const CommandResult result = vcsSynchronousExec(workingDirectory, arguments, - RunFlags::NoOutput, vcsTimeoutS(), codec); + RunFlags::NoOutput, vcsTimeoutS(), + configFileCodec()); if (result.result() == ProcessResult::FinishedWithSuccess) return result.cleanedStdOut().trimmed(); return {}; } +void GitClient::readConfigAsync(const FilePath &workingDirectory, const QStringList &arguments, + const CommandHandler &handler) const +{ + vcsExecWithHandler(workingDirectory, arguments, this, handler, RunFlags::NoOutput, + configFileCodec()); +} + static unsigned parseGitVersion(const QString &output) { // cut 'git version 1.6.5.1.sha' diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 88c2f3870f8..398b1c1cc86 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -79,6 +79,12 @@ public: }; struct Author { + bool operator==(const Author &other) const { + return name == other.name && email == other.email; + } + bool operator!=(const Author &other) const { + return !operator==(other); + } QString name; QString email; }; @@ -343,11 +349,16 @@ public: Core::IEditor *openShowEditor(const Utils::FilePath &workingDirectory, const QString &ref, const Utils::FilePath &path, ShowEditor showSetting = ShowEditor::Always); + Author parseAuthor(const QString &authorInfo); Author getAuthor(const Utils::FilePath &workingDirectory); + QTextCodec *defaultCommitEncoding() const; enum EncodingType { EncodingSource, EncodingLogOutput, EncodingCommit, EncodingDefault }; QTextCodec *encoding(EncodingType encodingType, const Utils::FilePath &source = {}) const; + void readConfigAsync(const Utils::FilePath &workingDirectory, const QStringList &arguments, + const VcsBase::CommandHandler &handler) const; + private: static GitSettings &settings(); diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index e4fc95be8cb..c5f30fa036f 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -392,6 +392,7 @@ public: void setupInstantBlame(); void instantBlameOnce(); + void forceInstantBlame(); void instantBlame(); void stopInstantBlame(); bool refreshWorkingDirectory(const FilePath &workingDirectory); @@ -705,6 +706,7 @@ GitPluginPrivate::GitPluginPrivate() m_fileActions.reserve(10); m_projectActions.reserve(10); m_repositoryActions.reserve(50); + m_codec = GitClient::instance()->defaultCommitEncoding(); Context context(Constants::GIT_CONTEXT); @@ -1441,10 +1443,6 @@ void GitPluginPrivate::setupInstantBlame() return; } - const Utils::FilePath workingDirectory = GitPlugin::currentState().currentFileTopLevel(); - if (!refreshWorkingDirectory(workingDirectory)) - return; - const TextEditorWidget *widget = TextEditorWidget::fromEditor(editor); if (!widget) return; @@ -1452,6 +1450,10 @@ void GitPluginPrivate::setupInstantBlame() if (qobject_cast(widget)) return; // Skip in VCS editors like log or blame + const Utils::FilePath workingDirectory = GitPlugin::currentState().currentFileTopLevel(); + if (!refreshWorkingDirectory(workingDirectory)) + return; + m_blameCursorPosConn = connect(widget, &QPlainTextEdit::cursorPositionChanged, this, [this] { if (!settings().instantBlame.value()) { @@ -1461,8 +1463,7 @@ void GitPluginPrivate::setupInstantBlame() m_cursorPositionChangedTimer->start(500); }); - m_lastVisitedEditorLine = -1; - instantBlame(); + forceInstantBlame(); }; connect(&settings().instantBlame, &BoolAspect::valueChanged, this, @@ -1530,6 +1531,11 @@ void GitPluginPrivate::instantBlameOnce() return; } + forceInstantBlame(); +} + +void GitPluginPrivate::forceInstantBlame() +{ m_lastVisitedEditorLine = -1; instantBlame(); } @@ -1596,8 +1602,38 @@ bool GitPluginPrivate::refreshWorkingDirectory(const FilePath &workingDirectory) return true; m_workingDirectory = workingDirectory; - m_author = GitClient::instance()->getAuthor(workingDirectory); - m_codec = GitClient::instance()->encoding(GitClient::EncodingCommit, workingDirectory); + + const auto commitCodecHandler = [this, workingDirectory](const CommandResult &result) { + QTextCodec *codec = nullptr; + + if (result.result() == ProcessResult::FinishedWithSuccess) { + const QString codecName = result.cleanedStdOut().trimmed(); + codec = QTextCodec::codecForName(codecName.toUtf8()); + } else { + codec = GitClient::instance()->defaultCommitEncoding(); + } + + if (m_codec != codec) { + m_codec = codec; + forceInstantBlame(); + } + }; + GitClient::instance()->readConfigAsync(workingDirectory, {"config", "i18n.commitEncoding"}, + commitCodecHandler); + + const auto authorHandler = [this, workingDirectory](const CommandResult &result) { + if (result.result() == ProcessResult::FinishedWithSuccess) { + const QString authorInfo = result.cleanedStdOut().trimmed(); + const Author author = GitClient::instance()->parseAuthor(authorInfo); + + if (m_author != author) { + m_author = author; + forceInstantBlame(); + } + } + }; + GitClient::instance()->readConfigAsync(workingDirectory, {"var", "GIT_AUTHOR_IDENT"}, + authorHandler); return true; } From 426a9a70371fd5a9b19ee1fbd33af2318210e2b8 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 09:41:47 +0200 Subject: [PATCH 1314/1447] Vcs: Register settings aspects more directly Change-Id: I8049f71456b8e8573a2dcfce68a14fb12545865b Reviewed-by: Reviewed-by: Christian Stenger Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarsettings.cpp | 11 ------ src/plugins/bazaar/bazaarsettings.h | 12 +++---- src/plugins/cvs/cvssettings.cpp | 6 ---- src/plugins/cvs/cvssettings.h | 10 +++--- src/plugins/fossil/fossilsettings.cpp | 15 -------- src/plugins/fossil/fossilsettings.h | 22 ++++++------ src/plugins/git/gitsettings.cpp | 20 ----------- src/plugins/git/gitsettings.h | 36 +++++++++---------- src/plugins/mercurial/mercurialsettings.cpp | 8 ----- src/plugins/mercurial/mercurialsettings.h | 4 +-- src/plugins/perforce/perforcesettings.cpp | 8 ----- src/plugins/perforce/perforcesettings.h | 16 ++++----- src/plugins/subversion/subversionsettings.cpp | 9 ----- src/plugins/subversion/subversionsettings.h | 10 +++--- src/plugins/vcsbase/commonvcssettings.cpp | 12 ++----- src/plugins/vcsbase/commonvcssettings.h | 18 +++++----- src/plugins/vcsbase/vcsbaseclientsettings.cpp | 16 --------- src/plugins/vcsbase/vcsbaseclientsettings.h | 12 +++---- 18 files changed, 71 insertions(+), 174 deletions(-) diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp index 1b2840084cb..344bdc6a095 100644 --- a/src/plugins/bazaar/bazaarsettings.cpp +++ b/src/plugins/bazaar/bazaarsettings.cpp @@ -32,48 +32,37 @@ BazaarSettings::BazaarSettings() setDisplayName(Tr::tr("Bazaar")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - registerAspect(&binaryPath); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setDefaultValue(Constants::BAZAARDEFAULT); binaryPath.setDisplayName(Tr::tr("Bazaar Command")); binaryPath.setHistoryCompleter("Bazaar.Command.History"); binaryPath.setLabelText(Tr::tr("Command:")); - registerAspect(&diffIgnoreWhiteSpace); diffIgnoreWhiteSpace.setSettingsKey("diffIgnoreWhiteSpace"); - registerAspect(&diffIgnoreBlankLines); diffIgnoreBlankLines.setSettingsKey("diffIgnoreBlankLines"); - registerAspect(&logVerbose); logVerbose.setSettingsKey("logVerbose"); - registerAspect(&logFormat); logForward.setSettingsKey("logForward"); - registerAspect(&logIncludeMerges); logIncludeMerges.setSettingsKey("logIncludeMerges"); - registerAspect(&logFormat); logFormat.setDisplayStyle(StringAspect::LineEditDisplay); logFormat.setSettingsKey("logFormat"); logFormat.setDefaultValue("long"); - registerAspect(&userName); userName.setDisplayStyle(StringAspect::LineEditDisplay); userName.setLabelText(Tr::tr("Default username:")); userName.setToolTip(Tr::tr("Username to use by default on commit.")); - registerAspect(&userEmail); userEmail.setDisplayStyle(StringAspect::LineEditDisplay); userEmail.setLabelText(Tr::tr("Default email:")); userEmail.setToolTip(Tr::tr("Email to use by default on commit.")); - registerAspect(&logCount); logCount.setLabelText(Tr::tr("Log count:")); logCount.setToolTip(Tr::tr("The number of recent commit logs to show. Choose 0 to see all entries.")); - registerAspect(&logCount); timeout.setLabelText(Tr::tr("Timeout:")); timeout.setSuffix(Tr::tr("s")); diff --git a/src/plugins/bazaar/bazaarsettings.h b/src/plugins/bazaar/bazaarsettings.h index 24643a2d4cd..0e6cc0d8520 100644 --- a/src/plugins/bazaar/bazaarsettings.h +++ b/src/plugins/bazaar/bazaarsettings.h @@ -12,12 +12,12 @@ class BazaarSettings final : public VcsBase::VcsBaseSettings public: BazaarSettings(); - Utils::BoolAspect diffIgnoreWhiteSpace; - Utils::BoolAspect diffIgnoreBlankLines; - Utils::BoolAspect logVerbose; - Utils::BoolAspect logForward; - Utils::BoolAspect logIncludeMerges; - Utils::StringAspect logFormat; + Utils::BoolAspect diffIgnoreWhiteSpace{this}; + Utils::BoolAspect diffIgnoreBlankLines{this}; + Utils::BoolAspect logVerbose{this}; + Utils::BoolAspect logForward{this}; + Utils::BoolAspect logIncludeMerges{this}; + Utils::StringAspect logFormat{this}; }; BazaarSettings &settings(); diff --git a/src/plugins/cvs/cvssettings.cpp b/src/plugins/cvs/cvssettings.cpp index dbfd41e500c..e2247f7dbe0 100644 --- a/src/plugins/cvs/cvssettings.cpp +++ b/src/plugins/cvs/cvssettings.cpp @@ -33,25 +33,21 @@ CvsSettings::CvsSettings() setDisplayName(Tr::tr("CVS")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - registerAspect(&binaryPath); binaryPath.setDefaultValue("cvs" QTC_HOST_EXE_SUFFIX); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setHistoryCompleter(QLatin1String("Cvs.Command.History")); binaryPath.setDisplayName(Tr::tr("CVS Command")); binaryPath.setLabelText(Tr::tr("CVS command:")); - registerAspect(&cvsRoot); cvsRoot.setDisplayStyle(StringAspect::LineEditDisplay); cvsRoot.setSettingsKey("Root"); cvsRoot.setLabelText(Tr::tr("CVS root:")); - registerAspect(&diffOptions); diffOptions.setDisplayStyle(StringAspect::LineEditDisplay); diffOptions.setSettingsKey("DiffOptions"); diffOptions.setDefaultValue("-du"); diffOptions.setLabelText("Diff options:"); - registerAspect(&describeByCommitId); describeByCommitId.setSettingsKey("DescribeByCommitId"); describeByCommitId.setDefaultValue(true); describeByCommitId.setLabelText(Tr::tr("Describe all files matching commit id")); @@ -59,10 +55,8 @@ CvsSettings::CvsSettings() "displayed when clicking on a revision number in the annotation view " "(retrieved via commit ID). Otherwise, only the respective file will be displayed.")); - registerAspect(&diffIgnoreWhiteSpace); diffIgnoreWhiteSpace.setSettingsKey("DiffIgnoreWhiteSpace"); - registerAspect(&diffIgnoreBlankLines); diffIgnoreBlankLines.setSettingsKey("DiffIgnoreBlankLines"); setLayouter([this](QWidget *widget) { diff --git a/src/plugins/cvs/cvssettings.h b/src/plugins/cvs/cvssettings.h index 0c2e5442a62..ade9920b2ad 100644 --- a/src/plugins/cvs/cvssettings.h +++ b/src/plugins/cvs/cvssettings.h @@ -12,11 +12,11 @@ class CvsSettings : public VcsBase::VcsBaseSettings public: CvsSettings(); - Utils::StringAspect cvsRoot; - Utils::StringAspect diffOptions; - Utils::BoolAspect diffIgnoreWhiteSpace; - Utils::BoolAspect diffIgnoreBlankLines; - Utils::BoolAspect describeByCommitId; + Utils::StringAspect cvsRoot{this}; + Utils::StringAspect diffOptions{this}; + Utils::BoolAspect diffIgnoreWhiteSpace{this}; + Utils::BoolAspect diffIgnoreBlankLines{this}; + Utils::BoolAspect describeByCommitId{this}; QStringList addOptions(const QStringList &args) const; }; diff --git a/src/plugins/fossil/fossilsettings.cpp b/src/plugins/fossil/fossilsettings.cpp index 22adad3920d..d62f48f1566 100644 --- a/src/plugins/fossil/fossilsettings.cpp +++ b/src/plugins/fossil/fossilsettings.cpp @@ -33,72 +33,57 @@ FossilSettings::FossilSettings() setDisplayName(Tr::tr("Fossil")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - registerAspect(&binaryPath); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setDefaultValue(Constants::FOSSILDEFAULT); binaryPath.setDisplayName(Tr::tr("Fossil Command")); binaryPath.setHistoryCompleter("Fossil.Command.History"); binaryPath.setLabelText(Tr::tr("Command:")); - registerAspect(&defaultRepoPath); defaultRepoPath.setSettingsKey("defaultRepoPath"); defaultRepoPath.setExpectedKind(PathChooser::Directory); defaultRepoPath.setDisplayName(Tr::tr("Fossil Repositories")); defaultRepoPath.setLabelText(Tr::tr("Default path:")); defaultRepoPath.setToolTip(Tr::tr("Directory to store local repositories by default.")); - registerAspect(&userName); userName.setDisplayStyle(StringAspect::LineEditDisplay); userName.setLabelText(Tr::tr("Default user:")); userName.setToolTip(Tr::tr("Existing user to become an author of changes made to the repository.")); - registerAspect(&sslIdentityFile); sslIdentityFile.setSettingsKey("sslIdentityFile"); sslIdentityFile.setExpectedKind(PathChooser::File); sslIdentityFile.setDisplayName(Tr::tr("SSL/TLS Identity Key")); sslIdentityFile.setLabelText(Tr::tr("SSL/TLS identity:")); sslIdentityFile.setToolTip(Tr::tr("SSL/TLS client identity key to use if requested by the server.")); - registerAspect(&diffIgnoreAllWhiteSpace); diffIgnoreAllWhiteSpace.setSettingsKey("diffIgnoreAllWhiteSpace"); - registerAspect(&diffStripTrailingCR); diffStripTrailingCR.setSettingsKey("diffStripTrailingCR"); - registerAspect(&annotateShowCommitters); annotateShowCommitters.setSettingsKey("annotateShowCommitters"); - registerAspect(&annotateListVersions); annotateListVersions.setSettingsKey("annotateListVersions"); - registerAspect(&timelineWidth); timelineWidth.setSettingsKey("timelineWidth"); timelineWidth.setLabelText(Tr::tr("Log width:")); timelineWidth.setToolTip(Tr::tr("The width of log entry line (>20). " "Choose 0 to see a single line per entry.")); - registerAspect(&timelineLineageFilter); timelineLineageFilter.setSettingsKey("timelineLineageFilter"); - registerAspect(&timelineVerbose); timelineVerbose.setSettingsKey("timelineVerbose"); - registerAspect(&timelineItemType); timelineItemType.setDefaultValue("all"); timelineItemType.setSettingsKey("timelineItemType"); - registerAspect(&disableAutosync); disableAutosync.setSettingsKey("disableAutosync"); disableAutosync.setDefaultValue(true); disableAutosync.setLabelText(Tr::tr("Disable auto-sync")); disableAutosync.setToolTip(Tr::tr("Disable automatic pull prior to commit or update and " "automatic push after commit or tag or branch creation.")); - registerAspect(&timeout); timeout.setLabelText(Tr::tr("Timeout:")); timeout.setSuffix(Tr::tr("s")); - registerAspect(&logCount); logCount.setLabelText(Tr::tr("Log count:")); logCount.setToolTip(Tr::tr("The number of recent commit log entries to show. " "Choose 0 to see all entries.")); diff --git a/src/plugins/fossil/fossilsettings.h b/src/plugins/fossil/fossilsettings.h index 6b925357f06..8e56b1985cc 100644 --- a/src/plugins/fossil/fossilsettings.h +++ b/src/plugins/fossil/fossilsettings.h @@ -12,17 +12,17 @@ class FossilSettings : public VcsBase::VcsBaseSettings public: FossilSettings(); - Utils::FilePathAspect defaultRepoPath; - Utils::FilePathAspect sslIdentityFile; - Utils::BoolAspect diffIgnoreAllWhiteSpace; - Utils::BoolAspect diffStripTrailingCR; - Utils::BoolAspect annotateShowCommitters; - Utils::BoolAspect annotateListVersions; - Utils::IntegerAspect timelineWidth; - Utils::StringAspect timelineLineageFilter; - Utils::BoolAspect timelineVerbose; - Utils::StringAspect timelineItemType; - Utils::BoolAspect disableAutosync; + Utils::FilePathAspect defaultRepoPath{this}; + Utils::FilePathAspect sslIdentityFile{this}; + Utils::BoolAspect diffIgnoreAllWhiteSpace{this}; + Utils::BoolAspect diffStripTrailingCR{this}; + Utils::BoolAspect annotateShowCommitters{this}; + Utils::BoolAspect annotateListVersions{this}; + Utils::IntegerAspect timelineWidth{this}; + Utils::StringAspect timelineLineageFilter{this}; + Utils::BoolAspect timelineVerbose{this}; + Utils::StringAspect timelineItemType{this}; + Utils::BoolAspect disableAutosync{this}; }; FossilSettings &settings(); diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 5f65fa2f1b8..6cbec254445 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -31,42 +31,32 @@ GitSettings::GitSettings() setId(VcsBase::Constants::VCS_ID_GIT); setDisplayName(Tr::tr("Git")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettingsGroup("Git"); path.setDisplayStyle(StringAspect::LineEditDisplay); path.setLabelText(Tr::tr("Prepend to PATH:")); - registerAspect(&binaryPath); binaryPath.setDefaultValue("git"); - registerAspect(&pullRebase); pullRebase.setSettingsKey("PullRebase"); pullRebase.setLabelText(Tr::tr("Pull with rebase")); - registerAspect(&showTags); showTags.setSettingsKey("ShowTags"); - registerAspect(&omitAnnotationDate); omitAnnotationDate.setSettingsKey("OmitAnnotationDate"); - registerAspect(&ignoreSpaceChangesInDiff); ignoreSpaceChangesInDiff.setSettingsKey("SpaceIgnorantDiff"); ignoreSpaceChangesInDiff.setDefaultValue(true); - registerAspect(&ignoreSpaceChangesInBlame); ignoreSpaceChangesInBlame.setSettingsKey("SpaceIgnorantBlame"); ignoreSpaceChangesInBlame.setDefaultValue(true); - registerAspect(&blameMoveDetection); blameMoveDetection.setSettingsKey("BlameDetectMove"); blameMoveDetection.setDefaultValue(0); - registerAspect(&diffPatience); diffPatience.setSettingsKey("DiffPatience"); diffPatience.setDefaultValue(true); - registerAspect(&winSetHomeEnvironment); winSetHomeEnvironment.setSettingsKey("WinSetHomeEnvironment"); winSetHomeEnvironment.setDefaultValue(true); winSetHomeEnvironment.setLabelText(Tr::tr("Set \"HOME\" environment variable")); @@ -84,47 +74,37 @@ GitSettings::GitSettings() winSetHomeEnvironment.setVisible(false); } - registerAspect(&gitkOptions); gitkOptions.setDisplayStyle(StringAspect::LineEditDisplay); gitkOptions.setSettingsKey("GitKOptions"); gitkOptions.setLabelText(Tr::tr("Arguments:")); - registerAspect(&logDiff); logDiff.setSettingsKey("LogDiff"); logDiff.setToolTip(Tr::tr("Note that huge amount of commits might take some time.")); - registerAspect(&repositoryBrowserCmd); repositoryBrowserCmd.setSettingsKey("RepositoryBrowserCmd"); repositoryBrowserCmd.setExpectedKind(PathChooser::ExistingCommand); repositoryBrowserCmd.setHistoryCompleter("Git.RepoCommand.History"); repositoryBrowserCmd.setDisplayName(Tr::tr("Git Repository Browser Command")); repositoryBrowserCmd.setLabelText(Tr::tr("Command:")); - registerAspect(&instantBlame); instantBlame.setSettingsKey("Git Instant"); instantBlame.setDefaultValue(true); instantBlame.setLabelText(Tr::tr("Add instant blame annotations to editor")); instantBlame.setToolTip(Tr::tr("Directly annotate each line in the editor " "when scrolling through the document.")); - registerAspect(&graphLog); graphLog.setSettingsKey("GraphLog"); - registerAspect(&colorLog); colorLog.setSettingsKey("ColorLog"); colorLog.setDefaultValue(true); - registerAspect(&firstParent); firstParent.setSettingsKey("FirstParent"); - registerAspect(&followRenames); followRenames.setSettingsKey("FollowRenames"); followRenames.setDefaultValue(true); - registerAspect(&lastResetIndex); lastResetIndex.setSettingsKey("LastResetIndex"); - registerAspect(&refLogShowDate); refLogShowDate.setSettingsKey("RefLogShowDate"); timeout.setDefaultValue(Utils::HostOsInfo::isWindowsHost() ? 60 : 30); diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index 0b82146b042..df6cf56e4e8 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -20,24 +20,24 @@ class GitSettings : public VcsBase::VcsBaseSettings public: GitSettings(); - Utils::BoolAspect pullRebase; - Utils::BoolAspect showTags; - Utils::BoolAspect omitAnnotationDate; - Utils::BoolAspect ignoreSpaceChangesInDiff; - Utils::BoolAspect ignoreSpaceChangesInBlame; - Utils::IntegerAspect blameMoveDetection; - Utils::BoolAspect diffPatience; - Utils::BoolAspect winSetHomeEnvironment; - Utils::StringAspect gitkOptions; - Utils::BoolAspect logDiff; - Utils::FilePathAspect repositoryBrowserCmd; - Utils::BoolAspect graphLog; - Utils::BoolAspect colorLog; - Utils::BoolAspect firstParent; - Utils::BoolAspect followRenames; - Utils::IntegerAspect lastResetIndex; - Utils::BoolAspect refLogShowDate; - Utils::BoolAspect instantBlame; + Utils::BoolAspect pullRebase{this}; + Utils::BoolAspect showTags{this}; + Utils::BoolAspect omitAnnotationDate{this}; + Utils::BoolAspect ignoreSpaceChangesInDiff{this}; + Utils::BoolAspect ignoreSpaceChangesInBlame{this}; + Utils::IntegerAspect blameMoveDetection{this}; + Utils::BoolAspect diffPatience{this}; + Utils::BoolAspect winSetHomeEnvironment{this}; + Utils::StringAspect gitkOptions{this}; + Utils::BoolAspect logDiff{this}; + Utils::FilePathAspect repositoryBrowserCmd{this}; + Utils::BoolAspect graphLog{this}; + Utils::BoolAspect colorLog{this}; + Utils::BoolAspect firstParent{this}; + Utils::BoolAspect followRenames{this}; + Utils::IntegerAspect lastResetIndex{this}; + Utils::BoolAspect refLogShowDate{this}; + Utils::BoolAspect instantBlame{this}; mutable Utils::FilePath resolvedBinPath; mutable bool tryResolve = true; diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp index 0b84187b1b4..0ced239122e 100644 --- a/src/plugins/mercurial/mercurialsettings.cpp +++ b/src/plugins/mercurial/mercurialsettings.cpp @@ -28,32 +28,24 @@ MercurialSettings::MercurialSettings() setId(VcsBase::Constants::VCS_ID_MERCURIAL); setDisplayName(Tr::tr("Mercurial")); setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); - setSettings(&settings()); - setSettingsGroup("Mercurial"); - setAutoApply(false); - registerAspect(&binaryPath); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setDefaultValue(Constants::MERCURIALDEFAULT); binaryPath.setDisplayName(Tr::tr("Mercurial Command")); binaryPath.setHistoryCompleter("Bazaar.Command.History"); binaryPath.setLabelText(Tr::tr("Command:")); - registerAspect(&userName); userName.setDisplayStyle(StringAspect::LineEditDisplay); userName.setLabelText(Tr::tr("Default username:")); userName.setToolTip(Tr::tr("Username to use by default on commit.")); - registerAspect(&userEmail); userEmail.setDisplayStyle(StringAspect::LineEditDisplay); userEmail.setLabelText(Tr::tr("Default email:")); userEmail.setToolTip(Tr::tr("Email to use by default on commit.")); - registerAspect(&diffIgnoreWhiteSpace); diffIgnoreWhiteSpace.setSettingsKey("diffIgnoreWhiteSpace"); - registerAspect(&diffIgnoreBlankLines); diffIgnoreBlankLines.setSettingsKey("diffIgnoreBlankLines"); setLayouter([this](QWidget *widget) { diff --git a/src/plugins/mercurial/mercurialsettings.h b/src/plugins/mercurial/mercurialsettings.h index 08c8fa41544..2102d7037d6 100644 --- a/src/plugins/mercurial/mercurialsettings.h +++ b/src/plugins/mercurial/mercurialsettings.h @@ -12,8 +12,8 @@ class MercurialSettings : public VcsBase::VcsBaseSettings public: MercurialSettings(); - Utils::StringAspect diffIgnoreWhiteSpace; - Utils::StringAspect diffIgnoreBlankLines; + Utils::StringAspect diffIgnoreWhiteSpace{this}; + Utils::StringAspect diffIgnoreBlankLines{this}; }; MercurialSettings &settings(); diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp index ead7b6b07b3..ee02465530e 100644 --- a/src/plugins/perforce/perforcesettings.cpp +++ b/src/plugins/perforce/perforcesettings.cpp @@ -35,7 +35,6 @@ PerforceSettings::PerforceSettings() setSettingsGroup("Perforce"); setAutoApply(false); - registerAspect(&p4BinaryPath); p4BinaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); p4BinaryPath.setSettingsKey("Command"); p4BinaryPath.setDefaultValue( @@ -45,28 +44,23 @@ PerforceSettings::PerforceSettings() p4BinaryPath.setDisplayName(Tr::tr("Perforce Command")); p4BinaryPath.setLabelText(Tr::tr("P4 command:")); - registerAspect(&p4Port); p4Port.setDisplayStyle(StringAspect::LineEditDisplay); p4Port.setSettingsKey("Port"); p4Port.setLabelText(Tr::tr("P4 port:")); - registerAspect(&p4Client); p4Client.setDisplayStyle(StringAspect::LineEditDisplay); p4Client.setSettingsKey("Client"); p4Client.setLabelText(Tr::tr("P4 client:")); - registerAspect(&p4User); p4User.setDisplayStyle(StringAspect::LineEditDisplay); p4User.setSettingsKey("User"); p4User.setLabelText(Tr::tr("P4 user:")); - registerAspect(&logCount); logCount.setSettingsKey("LogCount"); logCount.setRange(1000, 10000); logCount.setDefaultValue(1000); logCount.setLabelText(Tr::tr("Log count:")); - registerAspect(&customEnv); // The settings value has been stored with the opposite meaning for a while. // Avoid changing the stored value, but flip it on read/write: customEnv.setSettingsKey("Default"); @@ -74,14 +68,12 @@ PerforceSettings::PerforceSettings() customEnv.setFromSettingsTransformation(invertBoolVariant); customEnv.setToSettingsTransformation(invertBoolVariant); - registerAspect(&timeOutS); timeOutS.setSettingsKey("TimeOut"); timeOutS.setRange(1, 360); timeOutS.setDefaultValue(30); timeOutS.setLabelText(Tr::tr("Timeout:")); timeOutS.setSuffix(Tr::tr("s")); - registerAspect(&autoOpen); autoOpen.setSettingsKey("PromptToOpen"); autoOpen.setDefaultValue(true); autoOpen.setLabelText(Tr::tr("Automatically open files when editing")); diff --git a/src/plugins/perforce/perforcesettings.h b/src/plugins/perforce/perforcesettings.h index b632d153256..0801c310907 100644 --- a/src/plugins/perforce/perforcesettings.h +++ b/src/plugins/perforce/perforcesettings.h @@ -68,14 +68,14 @@ public: void clearTopLevel(); - Utils::StringAspect p4BinaryPath; - Utils::StringAspect p4Port; - Utils::StringAspect p4Client; - Utils::StringAspect p4User; - Utils::IntegerAspect logCount; - Utils::BoolAspect customEnv; - Utils::IntegerAspect timeOutS; - Utils::BoolAspect autoOpen; + Utils::StringAspect p4BinaryPath{this}; + Utils::StringAspect p4Port{this}; + Utils::StringAspect p4Client{this}; + Utils::StringAspect p4User{this}; + Utils::IntegerAspect logCount{this}; + Utils::BoolAspect customEnv{this}; + Utils::IntegerAspect timeOutS{this}; + Utils::BoolAspect autoOpen{this}; private: QStringList workingDirectoryArguments(const QString &workingDir) const; diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index 2a087883d7c..092c4ee1c05 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -32,43 +32,34 @@ SubversionSettings::SubversionSettings() setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); setSettingsGroup("Subversion"); - registerAspect(&binaryPath); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setHistoryCompleter("Subversion.Command.History"); binaryPath.setDefaultValue("svn" QTC_HOST_EXE_SUFFIX); binaryPath.setDisplayName(Tr::tr("Subversion Command")); binaryPath.setLabelText(Tr::tr("Subversion command:")); - registerAspect(&useAuthentication); useAuthentication.setSettingsKey("Authentication"); useAuthentication.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); - registerAspect(&userName); userName.setSettingsKey("User"); userName.setDisplayStyle(StringAspect::LineEditDisplay); userName.setLabelText(Tr::tr("Username:")); - registerAspect(&password); password.setSettingsKey("Password"); password.setDisplayStyle(StringAspect::LineEditDisplay); password.setLabelText(Tr::tr("Password:")); - registerAspect(&spaceIgnorantAnnotation); spaceIgnorantAnnotation.setSettingsKey("SpaceIgnorantAnnotation"); spaceIgnorantAnnotation.setDefaultValue(true); spaceIgnorantAnnotation.setLabelText(Tr::tr("Ignore whitespace changes in annotation")); - registerAspect(&diffIgnoreWhiteSpace); diffIgnoreWhiteSpace.setSettingsKey("DiffIgnoreWhiteSpace"); - registerAspect(&logVerbose); logVerbose.setSettingsKey("LogVerbose"); - registerAspect(&logCount); logCount.setDefaultValue(1000); logCount.setLabelText(Tr::tr("Log count:")); - registerAspect(&timeout); timeout.setLabelText(Tr::tr("Timeout:")); timeout.setSuffix(Tr::tr("s")); diff --git a/src/plugins/subversion/subversionsettings.h b/src/plugins/subversion/subversionsettings.h index 49aaec171b1..c5bcb8e9cf5 100644 --- a/src/plugins/subversion/subversionsettings.h +++ b/src/plugins/subversion/subversionsettings.h @@ -14,11 +14,11 @@ public: bool hasAuthentication() const; - Utils::BoolAspect useAuthentication; - Utils::StringAspect password; - Utils::BoolAspect spaceIgnorantAnnotation; - Utils::BoolAspect diffIgnoreWhiteSpace; - Utils::BoolAspect logVerbose; + Utils::BoolAspect useAuthentication{this}; + Utils::StringAspect password{this}; + Utils::BoolAspect spaceIgnorantAnnotation{this}; + Utils::BoolAspect diffIgnoreWhiteSpace{this}; + Utils::BoolAspect logVerbose{this}; }; SubversionSettings &settings(); diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 46c412011e5..e33de123790 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -20,8 +20,7 @@ using namespace Utils; -namespace VcsBase { -namespace Internal { +namespace VcsBase::Internal { // Return default for the ssh-askpass command (default to environment) static QString sshPasswordPromptDefault() @@ -39,7 +38,6 @@ CommonVcsSettings::CommonVcsSettings() setSettingsGroup("VCS"); setAutoApply(false); - registerAspect(&nickNameMailMap); nickNameMailMap.setSettingsKey("NickNameMailMap"); nickNameMailMap.setDisplayStyle(StringAspect::PathChooserDisplay); nickNameMailMap.setExpectedKind(PathChooser::File); @@ -48,7 +46,6 @@ CommonVcsSettings::CommonVcsSettings() nickNameMailMap.setToolTip(Tr::tr("A file listing nicknames in a 4-column mailmap format:\n" "'name alias '.")); - registerAspect(&nickNameFieldListFile); nickNameFieldListFile.setSettingsKey("NickNameFieldListFile"); nickNameFieldListFile.setDisplayStyle(StringAspect::PathChooserDisplay); nickNameFieldListFile.setExpectedKind(PathChooser::File); @@ -57,7 +54,6 @@ CommonVcsSettings::CommonVcsSettings() nickNameFieldListFile.setToolTip(Tr::tr("A simple file containing lines with field names like " "\"Reviewed-By:\" which will be added below the submit editor.")); - registerAspect(&submitMessageCheckScript); submitMessageCheckScript.setSettingsKey("SubmitMessageCheckScript"); submitMessageCheckScript.setDisplayStyle(StringAspect::PathChooserDisplay); submitMessageCheckScript.setExpectedKind(PathChooser::ExistingCommand); @@ -67,7 +63,6 @@ CommonVcsSettings::CommonVcsSettings() "in a temporary file as first argument. It should return with an exit != 0 and a message " "on standard error to indicate failure.")); - registerAspect(&sshPasswordPrompt); sshPasswordPrompt.setSettingsKey("SshPasswordPrompt"); sshPasswordPrompt.setDisplayStyle(StringAspect::PathChooserDisplay); sshPasswordPrompt.setExpectedKind(PathChooser::ExistingCommand); @@ -78,12 +73,10 @@ CommonVcsSettings::CommonVcsSettings() "for a password,\nshould a repository require SSH-authentication " "(see documentation on SSH and the environment variable SSH_ASKPASS).")); - registerAspect(&lineWrap); lineWrap.setSettingsKey("LineWrap"); lineWrap.setDefaultValue(true); lineWrap.setLabelText(Tr::tr("Wrap submit message at:")); - registerAspect(&lineWrapWidth); lineWrapWidth.setSettingsKey("LineWrapWidth"); lineWrapWidth.setSuffix(Tr::tr(" characters")); lineWrapWidth.setDefaultValue(72); @@ -152,5 +145,4 @@ CommonOptionsPage::CommonOptionsPage() setWidgetCreator([this] { return new CommonSettingsWidget(this); }); } -} // namespace Internal -} // namespace VcsBase +} // VcsBase::Internal diff --git a/src/plugins/vcsbase/commonvcssettings.h b/src/plugins/vcsbase/commonvcssettings.h index b1cf09ac14a..44bf03c5776 100644 --- a/src/plugins/vcsbase/commonvcssettings.h +++ b/src/plugins/vcsbase/commonvcssettings.h @@ -7,8 +7,7 @@ #include -namespace VcsBase { -namespace Internal { +namespace VcsBase::Internal { class CommonVcsSettings : public Utils::AspectContainer { @@ -17,16 +16,16 @@ class CommonVcsSettings : public Utils::AspectContainer public: CommonVcsSettings(); - Utils::StringAspect nickNameMailMap; - Utils::StringAspect nickNameFieldListFile; + Utils::StringAspect nickNameMailMap{this}; + Utils::StringAspect nickNameFieldListFile{this}; - Utils::StringAspect submitMessageCheckScript; + Utils::StringAspect submitMessageCheckScript{this}; // Executable run to graphically prompt for a SSH-password. - Utils::StringAspect sshPasswordPrompt; + Utils::StringAspect sshPasswordPrompt{this}; - Utils::BoolAspect lineWrap; - Utils::IntegerAspect lineWrapWidth; + Utils::BoolAspect lineWrap{this}; + Utils::IntegerAspect lineWrapWidth{this}; signals: void settingsChanged(); @@ -43,5 +42,4 @@ private: CommonVcsSettings m_settings; }; -} // namespace Internal -} // namespace VcsBase +} // VcsBase::Internal diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.cpp b/src/plugins/vcsbase/vcsbaseclientsettings.cpp index 7dfd8b3760b..170437864a0 100644 --- a/src/plugins/vcsbase/vcsbaseclientsettings.cpp +++ b/src/plugins/vcsbase/vcsbaseclientsettings.cpp @@ -6,15 +6,7 @@ #include "vcsbasetr.h" #include -#include -#include #include -#include -#include -#include - -#include -#include using namespace Utils; @@ -22,27 +14,19 @@ namespace VcsBase { VcsBaseSettings::VcsBaseSettings() { - setAutoApply(false); - - registerAspect(&binaryPath); binaryPath.setSettingsKey("BinaryPath"); - registerAspect(&userName); userName.setSettingsKey("Username"); - registerAspect(&userEmail); userEmail.setSettingsKey("UserEmail"); - registerAspect(&logCount); logCount.setSettingsKey("LogCount"); logCount.setRange(0, 1000 * 1000); logCount.setDefaultValue(100); logCount.setLabelText(Tr::tr("Log count:")); - registerAspect(&path); path.setSettingsKey("Path"); - registerAspect(&timeout); timeout.setSettingsKey("Timeout"); timeout.setRange(0, 3600 * 24 * 365); timeout.setDefaultValue(30); diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.h b/src/plugins/vcsbase/vcsbaseclientsettings.h index ec5ad3aab09..6e1f227f218 100644 --- a/src/plugins/vcsbase/vcsbaseclientsettings.h +++ b/src/plugins/vcsbase/vcsbaseclientsettings.h @@ -15,12 +15,12 @@ public: VcsBaseSettings(); ~VcsBaseSettings(); - Utils::FilePathAspect binaryPath; - Utils::StringAspect userName; - Utils::StringAspect userEmail; - Utils::IntegerAspect logCount; - Utils::IntegerAspect timeout; // Seconds - Utils::StringAspect path; + Utils::FilePathAspect binaryPath{this}; + Utils::StringAspect userName{this}; + Utils::StringAspect userEmail{this}; + Utils::IntegerAspect logCount{this}; + Utils::IntegerAspect timeout{this}; // Seconds + Utils::StringAspect path{this}; Utils::FilePaths searchPathList() const; }; From d338e089fb6673290df9888a4b0c52f254c45dfb Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:56:01 +0200 Subject: [PATCH 1315/1447] ProjectExplorer: Remove build directory compatibility code This was scheduled in bd05e01e3d9b56cd6d4d41aa02bb45f4a0830465 (Oct 8 2020) for removal in 4.16. Change-Id: I1016c85fee9fe024636d619db27eabaf676bef8b Reviewed-by: Christian Kandeler Reviewed-by: --- .../buildpropertiessettings.cpp | 20 ------------------- .../projectexplorer/buildpropertiessettings.h | 3 --- 2 files changed, 23 deletions(-) diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp index be0a699707f..b409a2a2e2c 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.cpp +++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp @@ -51,10 +51,6 @@ BuildPropertiesSettings::BuildPropertiesSettings() buildDirectoryTemplate.setUseGlobalMacroExpander(); buildDirectoryTemplate.setUseResetButton(); - registerAspect(&buildDirectoryTemplateOld); // TODO: Remove in ~4.16 - buildDirectoryTemplateOld.setSettingsKey("Directories/BuildDirectory.Template"); - buildDirectoryTemplateOld.setDefaultValue(DEFAULT_BUILD_DIRECTORY_TEMPLATE); - registerAspect(&separateDebugInfo); separateDebugInfo.setSettingsKey("ProjectExplorer/Settings/SeparateDebugInfo"); separateDebugInfo.setLabelText(Tr::tr("Separate debug info:")); @@ -73,22 +69,6 @@ BuildPropertiesSettings::BuildPropertiesSettings() &qtQuickCompiler, &BaseAspect::setVisible); } -void BuildPropertiesSettings::readSettings(QSettings *s) -{ - AspectContainer::readSettings(s); - - // TODO: Remove in ~4.16 - QString v = buildDirectoryTemplate.value(); - if (v.isEmpty()) - v = buildDirectoryTemplateOld.value(); - if (v.isEmpty()) - v = DEFAULT_BUILD_DIRECTORY_TEMPLATE; - v.replace("%{CurrentProject:Name}", "%{Project:Name}"); - v.replace("%{CurrentKit:FileSystemName}", "%{Kit:FileSystemName}"); - v.replace("%{CurrentBuild:Name}", "%{BuildConfig:Name}"); - buildDirectoryTemplate.setValue(v); -} - QString BuildPropertiesSettings::defaultBuildDirectoryTemplate() { return QString(DEFAULT_BUILD_DIRECTORY_TEMPLATE); diff --git a/src/plugins/projectexplorer/buildpropertiessettings.h b/src/plugins/projectexplorer/buildpropertiessettings.h index 5edf60d666b..4d028788d51 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.h +++ b/src/plugins/projectexplorer/buildpropertiessettings.h @@ -21,14 +21,11 @@ public: }; Utils::StringAspect buildDirectoryTemplate; - Utils::StringAspect buildDirectoryTemplateOld; // TODO: Remove in ~4.16 BuildTriStateAspect separateDebugInfo; BuildTriStateAspect qmlDebugging; BuildTriStateAspect qtQuickCompiler; Utils::BoolAspect showQtSettings; - void readSettings(QSettings *settings); - QString defaultBuildDirectoryTemplate(); }; From ba2174983242d6924aea2cae188d216ab94530ae Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 10:20:08 +0200 Subject: [PATCH 1316/1447] Tr/Clang: Use markdown for easier translations It was weird that the was floating around without a corresponding opening tag, and the markdown "[text](%1)" is simpler than "text" Change-Id: Ic0bdc155b1bfef07845a36935dd5fbbb70692b45 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: Christian Kandeler --- share/qtcreator/translations/qtcreator_da.ts | 4 ++-- share/qtcreator/translations/qtcreator_de.ts | 4 ++-- share/qtcreator/translations/qtcreator_hr.ts | 4 ++-- share/qtcreator/translations/qtcreator_ja.ts | 4 ++-- share/qtcreator/translations/qtcreator_pl.ts | 4 ++-- share/qtcreator/translations/qtcreator_ru.ts | 4 ++-- share/qtcreator/translations/qtcreator_uk.ts | 4 ++-- src/plugins/cppeditor/clangdiagnosticconfigswidget.cpp | 8 +++++--- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 4194df48a0f..094b4acb71e 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -39042,8 +39042,8 @@ skal være et repository krævet SSH-autentifikation (se dokumentation på SSH o QtC::CppEditor - For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. - For passende valgmuligheder, konsulter GCC- eller Clang-manualsiderne eller <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online dokumentationen</a>. + For appropriate options, consult the GCC or Clang manual pages or the [GCC online documentation](%1). + For passende valgmuligheder, konsulter GCC- eller Clang-manualsiderne eller [GCC online dokumentationen](%1). Each level adds checks to the previous level. For more information, see <a href="https://github.com/KDE/clazy">clazy's homepage</a>. diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 74c14d2e27c..ff71411c8ee 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -20157,8 +20157,8 @@ z.B. name = "m_test_foo_": Diagnosekonfigurationen - For appropriate options, consult the GCC or Clang manual pages or the %1 GCC online documentation</a>. - Für passende Optionen lesen Sie das GCC- oder Clang-Handbuch oder auch die %1 GCC-Onlinedokumentation</a>. + For appropriate options, consult the GCC or Clang manual pages or the [GCC online documentation](%1). + Für passende Optionen lesen Sie das GCC- oder Clang-Handbuch oder auch die [GCC-Onlinedokumentation](%1). Copy... diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 6c6158034f2..73f03bcfe0e 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -2809,8 +2809,8 @@ p, li { white-space: pre-wrap; } Dodatne C++ predprocesorske direktive za %1: - For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. - Odgovarajuće opcije potraži na stranicama GCC ili Clang priručnika ili na <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online dokumentaciji</a>. + For appropriate options, consult the GCC or Clang manual pages or the [GCC online documentation](%1). + Odgovarajuće opcije potraži na stranicama GCC ili Clang priručnika ili na [GCC online dokumentaciji](%1). Use diagnostic flags from build system diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index ced38a90bad..83f112914da 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -33563,8 +33563,8 @@ Android 5 ではローカルの Qt ライブラリをデプロイできません 削除 - For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. - オプションの詳細は GCC や Clang のマニュアル、または <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC のオンラインドキュメント</a> を参照してください。 + For appropriate options, consult the GCC or Clang manual pages or the [GCC online documentation](%1). + オプションの詳細は GCC や Clang のマニュアル、または [GCC のオンラインドキュメント](%1) を参照してください。 Copy Diagnostic Configuration diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 3d374501ffd..56fba0d9d91 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -34259,8 +34259,8 @@ Te pliki są zabezpieczone. Usuń - For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. - Sposoby konfigurowania opisane są w podręczniku GCC lub Clang lub w <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">dokumentacji online GCC</a>. + For appropriate options, consult the GCC or Clang manual pages or the [GCC online documentation](%1). + Sposoby konfigurowania opisane są w podręczniku GCC lub Clang lub w [dokumentacji online GCC](%1). Copy Diagnostic Configuration diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 5b10b1e755f..c0c64b06c5a 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -11168,8 +11168,8 @@ to version control (%2) Имя класса. - For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. - Описание параметров можно найти страницах man GCC или Clang или в <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">Документации GCC</a>. + For appropriate options, consult the GCC or Clang manual pages or the [GCC online documentation](%1). + Описание параметров можно найти страницах man GCC или Clang или в [Документации GCC](%1). Use diagnostic flags from build system diff --git a/share/qtcreator/translations/qtcreator_uk.ts b/share/qtcreator/translations/qtcreator_uk.ts index f49ae08943f..e5cef8358ba 100644 --- a/share/qtcreator/translations/qtcreator_uk.ts +++ b/share/qtcreator/translations/qtcreator_uk.ts @@ -42730,8 +42730,8 @@ the program. Видалити - For appropriate options, consult the GCC or Clang manual pages or the <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">GCC online documentation</a>. - Для відповідних опцій, переглянть сторінки man до GCC або Clang або ж <a href="https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html">документацію GCC в мережі</a>. + For appropriate options, consult the GCC or Clang manual pages or the [GCC online documentation](%1). + Для відповідних опцій, переглянть сторінки man до GCC або Clang або ж [документацію GCC в мережі](%1). Copy Diagnostic Configuration diff --git a/src/plugins/cppeditor/clangdiagnosticconfigswidget.cpp b/src/plugins/cppeditor/clangdiagnosticconfigswidget.cpp index f5fc8cfe425..8e7e1b8f84f 100644 --- a/src/plugins/cppeditor/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cppeditor/clangdiagnosticconfigswidget.cpp @@ -120,9 +120,11 @@ class ClangBaseChecksWidget : public QWidget public: ClangBaseChecksWidget() { - auto label = new QLabel(Tr::tr("For appropriate options, consult the GCC or Clang manual " - "pages or the %1 GCC online documentation.") - .arg("")); + auto label = new QLabel; + label->setTextFormat(Qt::MarkdownText); + label->setText(Tr::tr("For appropriate options, consult the GCC or Clang manual " + "pages or the [GCC online documentation](%1).") + .arg("https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html")); label->setOpenExternalLinks(true); useFlagsFromBuildSystemCheckBox = new QCheckBox(Tr::tr("Use diagnostic flags from build system")); From 14fe48dff7f0d144a39a2b366bbfec2700a3bee3 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 10:30:29 +0200 Subject: [PATCH 1317/1447] Tr/Python: Simplify UI text for translation Parametrize link target, and use markdown for simpler link syntax. Change-Id: I6d1bae0431aa4e5bd7c7ad39b1219289eda40391 Reviewed-by: Leena Miettinen Reviewed-by: David Schulz --- share/qtcreator/translations/qtcreator_de.ts | 4 ++-- src/plugins/python/pythonsettings.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index ff71411c8ee..02f6592f1b6 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -40211,8 +40211,8 @@ fails because Clang does not understand the target architecture. Python Language Server benutzen - For a complete list of available options, consult the <a href="https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md">Python LSP Server configuration documentation</a>. - Für eine vollständige Liste der verfügbaren Optionen siehe auch die <a href="https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md">Dokumentation zur Python LSP-Server-Konfiguration</a>. + For a complete list of available options, consult the [Python LSP Server configuration documentation](%1). + Für eine vollständige Liste der verfügbaren Optionen siehe auch die [Dokumentation zur Python LSP-Server-Konfiguration](%1). Advanced diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 1de24a3061c..d33346b8af7 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -414,11 +414,11 @@ public: mainGroupLayout->addWidget(m_pluginsGroup); - const QString labelText = Tr::tr( - "For a complete list of available options, consult the Python LSP Server configuration documentation."); - + const QString labelText = Tr::tr("For a complete list of available options, consult the " + "[Python LSP Server configuration documentation](%1).") + .arg("https://github.com/python-lsp/python-lsp-server/blob/" + "develop/CONFIGURATION.md"); + m_advancedLabel->setTextFormat(Qt::MarkdownText); m_advancedLabel->setText(labelText); m_advancedLabel->setOpenExternalLinks(true); mainGroupLayout->addWidget(m_advancedLabel); From 4f1560666a1c75dec824892c3e3de68a0ca64a96 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 13:11:43 +0200 Subject: [PATCH 1318/1447] Don't use uppercase ALT for shortcut strings It works, but we otherwise consistently use "Alt" Change-Id: I539a481aae1fb3d7da0a05d732122f3b81abfccb Reviewed-by: Orgad Shaneh --- share/qtcreator/translations/qtcreator_cs.ts | 16 ++++---- share/qtcreator/translations/qtcreator_da.ts | 16 ++++---- share/qtcreator/translations/qtcreator_de.ts | 40 +++++++++---------- share/qtcreator/translations/qtcreator_fr.ts | 16 ++++---- share/qtcreator/translations/qtcreator_hr.ts | 16 ++++---- share/qtcreator/translations/qtcreator_ja.ts | 16 ++++---- share/qtcreator/translations/qtcreator_pl.ts | 16 ++++---- share/qtcreator/translations/qtcreator_ru.ts | 8 ++-- share/qtcreator/translations/qtcreator_sl.ts | 16 ++++---- share/qtcreator/translations/qtcreator_uk.ts | 16 ++++---- .../qtcreator/translations/qtcreator_zh_CN.ts | 16 ++++---- .../qtcreator/translations/qtcreator_zh_TW.ts | 16 ++++---- src/plugins/bazaar/bazaarplugin.cpp | 12 ++++-- src/plugins/fossil/fossilplugin.cpp | 12 +++--- 14 files changed, 118 insertions(+), 114 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_cs.ts b/share/qtcreator/translations/qtcreator_cs.ts index 1e867abbcbd..d0e98799683 100644 --- a/share/qtcreator/translations/qtcreator_cs.ts +++ b/share/qtcreator/translations/qtcreator_cs.ts @@ -28914,8 +28914,8 @@ Server: %2. Rozdíly pro "%1" - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Meta+Z,Meta+D @@ -28930,8 +28930,8 @@ Server: %2. Záznamy pro "%1" - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Meta+Z,Meta+L @@ -28946,8 +28946,8 @@ Server: %2. Stav "%1" - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Meta+Z,Meta+S @@ -29011,8 +29011,8 @@ Server: %2. Zapsat-odevzdat (commit)... - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Meta+Z,Meta+C diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 094b4acb71e..a52185b07d4 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -2709,8 +2709,8 @@ Lokale commits pushes ikke til master-grenen inden en normal commit udføres.Meta+Z,Meta+D - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Log Current File @@ -2725,8 +2725,8 @@ Lokale commits pushes ikke til master-grenen inden en normal commit udføres.Meta+Z,Meta+L - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Status Current File @@ -2741,8 +2741,8 @@ Lokale commits pushes ikke til master-grenen inden en normal commit udføres.Meta+Z,Meta+S - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Add @@ -2805,8 +2805,8 @@ Lokale commits pushes ikke til master-grenen inden en normal commit udføres.Meta+Z,Meta+C - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Uncommit... diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 02f6592f1b6..1783414a4bf 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -12047,8 +12047,8 @@ Lokale Pull-Operationen werden nicht auf den Master-Branch angewandt.Status von "%1" - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Triggers a Bazaar version control operation. @@ -12059,16 +12059,16 @@ Lokale Pull-Operationen werden nicht auf den Master-Branch angewandt.Meta+Z,Meta+D - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Meta+Z,Meta+L Meta+Z,Meta+L - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Meta+Z,Meta+S @@ -12131,8 +12131,8 @@ Lokale Pull-Operationen werden nicht auf den Master-Branch angewandt.Commit... - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Meta+Z,Meta+C @@ -27270,8 +27270,8 @@ Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht Meta+I,Meta+D - ALT+I,Alt+D - ALT+I,Alt+D + Alt+I,Alt+D + Alt+I,Alt+D Timeline Current File @@ -27286,8 +27286,8 @@ Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht Meta+I,Meta+L - ALT+I,Alt+L - ALT+I,Alt+L + Alt+I,Alt+L + Alt+I,Alt+L Status Current File @@ -27302,8 +27302,8 @@ Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht Meta+I,Meta+S - ALT+I,Alt+S - ALT+I,Alt+S + Alt+I,Alt+S + Alt+I,Alt+S Add Current File @@ -27342,8 +27342,8 @@ Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht Meta+I,Meta+T - ALT+I,Alt+T - ALT+I,Alt+T + Alt+I,Alt+T + Alt+I,Alt+T Revert... @@ -27374,8 +27374,8 @@ Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht Meta+I,Meta+U - ALT+I,Alt+U - ALT+I,Alt+U + Alt+I,Alt+U + Alt+I,Alt+U Commit... @@ -27386,8 +27386,8 @@ Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht Meta+I,Meta+C - ALT+I,Alt+C - ALT+I,Alt+C + Alt+I,Alt+C + Alt+I,Alt+C Settings... diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 142772f5ca3..14a146f2109 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -28505,8 +28505,8 @@ Les version de Qt précédentes ont des limitations lors de la compilation des f Faire un diff de "%1" - ALT+Z,Alt+D - ALT+Z, Alt+D + Alt+Z,Alt+D + Alt+Z, Alt+D Meta+Z,Meta+D @@ -28521,8 +28521,8 @@ Les version de Qt précédentes ont des limitations lors de la compilation des f Réaliser un log de "%1" - ALT+Z,Alt+L - ALT+Z, Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Meta+Z,Meta+L @@ -28537,8 +28537,8 @@ Les version de Qt précédentes ont des limitations lors de la compilation des f Statut "%1" - ALT+Z,Alt+S - ALT+Z, Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Meta+Z,Meta+S @@ -28601,8 +28601,8 @@ Les version de Qt précédentes ont des limitations lors de la compilation des f Commit... - ALT+Z,Alt+C - ALT+Z, Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Meta+Z,Meta+C diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 73f03bcfe0e..bdc95b998f8 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -14932,8 +14932,8 @@ Check the test environment. Meta+Z,Meta+D - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Log Current File @@ -14948,8 +14948,8 @@ Check the test environment. Meta+Z,Meta+L - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Status Current File @@ -14964,8 +14964,8 @@ Check the test environment. Meta+Z,Meta+S - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Add @@ -15028,8 +15028,8 @@ Check the test environment. Meta+Z,Meta+C - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Uncommit... diff --git a/share/qtcreator/translations/qtcreator_ja.ts b/share/qtcreator/translations/qtcreator_ja.ts index 83f112914da..7bba62d3666 100644 --- a/share/qtcreator/translations/qtcreator_ja.ts +++ b/share/qtcreator/translations/qtcreator_ja.ts @@ -11816,8 +11816,8 @@ in the system's browser for manual download. Meta+Z,Meta+D - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Log Current File @@ -11832,8 +11832,8 @@ in the system's browser for manual download. Meta+Z,Meta+L - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Status Current File @@ -11848,8 +11848,8 @@ in the system's browser for manual download. Meta+Z,Meta+S - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Add @@ -11912,8 +11912,8 @@ in the system's browser for manual download. Meta+Z,Meta+C - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Uncommit... diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 56fba0d9d91..fc280a71457 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -13881,8 +13881,8 @@ Local pulls are not applied to the master branch. Pokaż różnice w "%1" - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Meta+Z,Meta+D @@ -13897,8 +13897,8 @@ Local pulls are not applied to the master branch. Log "%1" - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Meta+Z,Meta+L @@ -13913,8 +13913,8 @@ Local pulls are not applied to the master branch. Stan "%1" - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Meta+Z,Meta+S @@ -13977,8 +13977,8 @@ Local pulls are not applied to the master branch. Utwórz poprawkę... - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Meta+Z,Meta+C diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index c0c64b06c5a..0c4dd669944 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -4180,7 +4180,7 @@ Local commits are not pushed to the master branch until a normal commit is perfo Состояние «%1» - ALT+Z,Alt+D + Alt+Z,Alt+D @@ -4188,7 +4188,7 @@ Local commits are not pushed to the master branch until a normal commit is perfo Meta+Z,Meta+D - ALT+Z,Alt+L + Alt+Z,Alt+L @@ -4196,7 +4196,7 @@ Local commits are not pushed to the master branch until a normal commit is perfo Meta+Z,Meta+L - ALT+Z,Alt+S + Alt+Z,Alt+S @@ -4260,7 +4260,7 @@ Local commits are not pushed to the master branch until a normal commit is perfo Фиксировать... - ALT+Z,Alt+C + Alt+Z,Alt+C diff --git a/share/qtcreator/translations/qtcreator_sl.ts b/share/qtcreator/translations/qtcreator_sl.ts index 480193e4525..8292124dfe6 100644 --- a/share/qtcreator/translations/qtcreator_sl.ts +++ b/share/qtcreator/translations/qtcreator_sl.ts @@ -19894,8 +19894,8 @@ Seznam za strežnik je: %2. Razlike v »%1« - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Log Current File @@ -19906,8 +19906,8 @@ Seznam za strežnik je: %2. Dnevnik za »%1« - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Status Current File @@ -19918,8 +19918,8 @@ Seznam za strežnik je: %2. Stanje za »%1« - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Add @@ -19978,8 +19978,8 @@ Seznam za strežnik je: %2. Zapiši ... - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Create Repository... diff --git a/share/qtcreator/translations/qtcreator_uk.ts b/share/qtcreator/translations/qtcreator_uk.ts index e5cef8358ba..47c7b8a0931 100644 --- a/share/qtcreator/translations/qtcreator_uk.ts +++ b/share/qtcreator/translations/qtcreator_uk.ts @@ -456,8 +456,8 @@ Local commits are not pushed to the master branch until a normal commit is perfo Зміни в "%1" - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Meta+Z,Meta+D @@ -472,8 +472,8 @@ Local commits are not pushed to the master branch until a normal commit is perfo Історія "%1" - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Meta+Z,Meta+L @@ -488,8 +488,8 @@ Local commits are not pushed to the master branch until a normal commit is perfo - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Meta+Z,Meta+S @@ -552,8 +552,8 @@ Local commits are not pushed to the master branch until a normal commit is perfo - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Meta+Z,Meta+C diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index 4f079bcccb0..5d038593cc8 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -4478,8 +4478,8 @@ This flag will allow push to proceed. Diff "%1" - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Meta+Z,Meta+D @@ -4494,8 +4494,8 @@ This flag will allow push to proceed. Log "%1" - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Meta+Z,Meta+L @@ -4510,8 +4510,8 @@ This flag will allow push to proceed. Status "%1" - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Meta+Z,Meta+S @@ -4574,8 +4574,8 @@ This flag will allow push to proceed. 提交... - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Meta+Z,Meta+C diff --git a/share/qtcreator/translations/qtcreator_zh_TW.ts b/share/qtcreator/translations/qtcreator_zh_TW.ts index 7e1ff707a67..f5c68598b06 100644 --- a/share/qtcreator/translations/qtcreator_zh_TW.ts +++ b/share/qtcreator/translations/qtcreator_zh_TW.ts @@ -17607,8 +17607,8 @@ Local pulls are not applied to the master branch. 比較 "%1" - ALT+Z,Alt+D - ALT+Z,Alt+D + Alt+Z,Alt+D + Alt+Z,Alt+D Meta+Z,Meta+D @@ -17623,8 +17623,8 @@ Local pulls are not applied to the master branch. "%1" 的紀錄 - ALT+Z,Alt+L - ALT+Z,Alt+L + Alt+Z,Alt+L + Alt+Z,Alt+L Meta+Z,Meta+L @@ -17639,8 +17639,8 @@ Local pulls are not applied to the master branch. "%1" 的狀態 - ALT+Z,Alt+S - ALT+Z,Alt+S + Alt+Z,Alt+S + Alt+Z,Alt+S Meta+Z,Meta+S @@ -17703,8 +17703,8 @@ Local pulls are not applied to the master branch. 提交... - ALT+Z,Alt+C - ALT+Z,Alt+C + Alt+Z,Alt+C + Alt+Z,Alt+C Meta+Z,Meta+C diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index d992d70eba1..542c2ef7066 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -386,7 +386,8 @@ void BazaarPluginPrivate::createFileActions(const Context &context) m_diffFile = new ParameterAction(Tr::tr("Diff Current File"), Tr::tr("Diff \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_diffFile, DIFF, context); command->setAttribute(Command::CA_UpdateText); - command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+D") : Tr::tr("ALT+Z,Alt+D"))); + command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+D") + : Tr::tr("Alt+Z,Alt+D"))); connect(m_diffFile, &QAction::triggered, this, &BazaarPluginPrivate::diffCurrentFile); m_bazaarContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -394,7 +395,8 @@ void BazaarPluginPrivate::createFileActions(const Context &context) m_logFile = new ParameterAction(Tr::tr("Log Current File"), Tr::tr("Log \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_logFile, LOG, context); command->setAttribute(Command::CA_UpdateText); - command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+L") : Tr::tr("ALT+Z,Alt+L"))); + command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+L") + : Tr::tr("Alt+Z,Alt+L"))); connect(m_logFile, &QAction::triggered, this, &BazaarPluginPrivate::logCurrentFile); m_bazaarContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -402,7 +404,8 @@ void BazaarPluginPrivate::createFileActions(const Context &context) m_statusFile = new ParameterAction(Tr::tr("Status Current File"), Tr::tr("Status \"%1\""), ParameterAction::EnabledWithParameter, this); command = ActionManager::registerAction(m_statusFile, STATUS, context); command->setAttribute(Command::CA_UpdateText); - command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+S") : Tr::tr("ALT+Z,Alt+S"))); + command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+S") + : Tr::tr("Alt+Z,Alt+S"))); connect(m_statusFile, &QAction::triggered, this, &BazaarPluginPrivate::statusCurrentFile); m_bazaarContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -570,7 +573,8 @@ void BazaarPluginPrivate::createRepositoryActions(const Context &context) action = new QAction(Tr::tr("Commit..."), this); m_repositoryActionList.append(action); command = ActionManager::registerAction(action, COMMIT, context); - command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+C") : Tr::tr("ALT+Z,Alt+C"))); + command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Z,Meta+C") + : Tr::tr("Alt+Z,Alt+C"))); connect(action, &QAction::triggered, this, &BazaarPluginPrivate::commit); m_bazaarContainer->addAction(command); m_commandLocator->appendCommand(command); diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index bdd68d06210..1f6f7d93064 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -332,7 +332,7 @@ void FossilPluginPrivate::createFileActions(const Core::Context &context) command = Core::ActionManager::registerAction(m_diffFile, Constants::DIFF, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? Tr::tr("Meta+I,Meta+D") - : Tr::tr("ALT+I,Alt+D"))); + : Tr::tr("Alt+I,Alt+D"))); connect(m_diffFile, &QAction::triggered, this, &FossilPluginPrivate::diffCurrentFile); m_fossilContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -341,7 +341,7 @@ void FossilPluginPrivate::createFileActions(const Core::Context &context) command = Core::ActionManager::registerAction(m_logFile, Constants::LOG, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? Tr::tr("Meta+I,Meta+L") - : Tr::tr("ALT+I,Alt+L"))); + : Tr::tr("Alt+I,Alt+L"))); connect(m_logFile, &QAction::triggered, this, &FossilPluginPrivate::logCurrentFile); m_fossilContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -350,7 +350,7 @@ void FossilPluginPrivate::createFileActions(const Core::Context &context) command = Core::ActionManager::registerAction(m_statusFile, Constants::STATUS, context); command->setAttribute(Core::Command::CA_UpdateText); command->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? Tr::tr("Meta+I,Meta+S") - : Tr::tr("ALT+I,Alt+S"))); + : Tr::tr("Alt+I,Alt+S"))); connect(m_statusFile, &QAction::triggered, this, &FossilPluginPrivate::statusCurrentFile); m_fossilContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -463,7 +463,7 @@ void FossilPluginPrivate::createDirectoryActions(const Core::Context &context) m_repositoryActionList.append(action); command = Core::ActionManager::registerAction(action, Constants::LOGMULTI, context); command->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? Tr::tr("Meta+I,Meta+T") - : Tr::tr("ALT+I,Alt+T"))); + : Tr::tr("Alt+I,Alt+T"))); connect(action, &QAction::triggered, this, &FossilPluginPrivate::logRepository); m_fossilContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -545,7 +545,7 @@ void FossilPluginPrivate::createRepositoryActions(const Core::Context &context) m_repositoryActionList.append(action); command = Core::ActionManager::registerAction(action, Constants::UPDATE, context); command->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? Tr::tr("Meta+I,Meta+U") - : Tr::tr("ALT+I,Alt+U"))); + : Tr::tr("Alt+I,Alt+U"))); connect(action, &QAction::triggered, this, &FossilPluginPrivate::update); m_fossilContainer->addAction(command); m_commandLocator->appendCommand(command); @@ -554,7 +554,7 @@ void FossilPluginPrivate::createRepositoryActions(const Core::Context &context) m_repositoryActionList.append(action); command = Core::ActionManager::registerAction(action, Constants::COMMIT, context); command->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? Tr::tr("Meta+I,Meta+C") - : Tr::tr("ALT+I,Alt+C"))); + : Tr::tr("Alt+I,Alt+C"))); connect(action, &QAction::triggered, this, &FossilPluginPrivate::commit); m_fossilContainer->addAction(command); m_commandLocator->appendCommand(command); From 326e20e8b9354fc9f6f53031cd73d5efc0cceaf9 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 30 May 2023 09:10:35 +0200 Subject: [PATCH 1319/1447] Core: Use FilePath::searchInPath to look for explorer Not expecting remote windows anytime soon, but moving towards FilePath as main/only entrypoint to filesystem functionality. Change-Id: I1701471394900049084fc7258fc56f7f912402ea Reviewed-by: Eike Ziller --- src/plugins/coreplugin/fileutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/fileutils.cpp b/src/plugins/coreplugin/fileutils.cpp index 0fe0ccd8875..3df3309c318 100644 --- a/src/plugins/coreplugin/fileutils.cpp +++ b/src/plugins/coreplugin/fileutils.cpp @@ -57,7 +57,7 @@ void FileUtils::showInGraphicalShell(QWidget *parent, const FilePath &pathIn) const QFileInfo fileInfo = pathIn.toFileInfo(); // Mac, Windows support folder or file. if (HostOsInfo::isWindowsHost()) { - const FilePath explorer = Environment::systemEnvironment().searchInPath(QLatin1String("explorer.exe")); + const FilePath explorer = FilePath("explorer.exe").searchInPath(); if (explorer.isEmpty()) { QMessageBox::warning(parent, Tr::tr("Launching Windows Explorer Failed"), From fa86a9dff0b6257da580111622794b107e6f166c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 26 May 2023 11:05:35 +0200 Subject: [PATCH 1320/1447] TaskTree tests: Make test enums printable In this way we see the name of the enum value instead of an int on test fail. Change-Id: I5eeae785c0bf1a85d7e5430b4b6b3aca8dd409ee Reviewed-by: Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- tests/auto/solutions/tasking/tst_tasking.cpp | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 7da3177b8a8..17335d29f41 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -17,6 +17,10 @@ using namespace Tasking; using TestTask = Async; using Test = AsyncTask; +namespace PrintableEnums { + +Q_NAMESPACE + enum class Handler { Setup, Done, @@ -25,8 +29,16 @@ enum class Handler { GroupDone, GroupError, Sync, - BarrierAdvance, + BarrierAdvance }; +Q_ENUM_NS(Handler); + +enum class OnDone { Success, Failure }; +Q_ENUM_NS(OnDone); + +} // namespace PrintableEnums + +using namespace PrintableEnums; using Log = QList>; @@ -45,8 +57,6 @@ static const char s_taskIdProperty[] = "__taskId"; static FutureSynchronizer *s_futureSynchronizer = nullptr; -enum class OnDone { Success, Failure }; - struct TestData { TreeStorage storage; Group root; @@ -1619,15 +1629,14 @@ void tst_Tasking::testTree() Log actualLog; const auto collectLog = [&actualLog](CustomStorage *storage) { actualLog = storage->m_log; }; taskTree.onStorageDone(testData.storage, collectLog); - const int result = taskTree.runBlocking(2000); + const OnDone result = taskTree.runBlocking(2000) ? OnDone::Success : OnDone::Failure; QCOMPARE(taskTree.isRunning(), false); QCOMPARE(taskTree.progressValue(), testData.taskCount); QCOMPARE(actualLog, testData.expectedLog); QCOMPARE(CustomStorage::instanceCount(), 0); - const bool expectSuccess = testData.onDone == OnDone::Success; - QCOMPARE(result, expectSuccess); + QCOMPARE(result, testData.onDone); } void tst_Tasking::storageOperators() From 4ecb016196b80b4cd66759912e20ff1da3d57148 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 25 May 2023 11:11:54 +0200 Subject: [PATCH 1321/1447] Doc: Add missing \a commands to MacroExpander docs Change-Id: I153e4a4e7c687d6f524bbbff42c758282bb5deaf Reviewed-by: Eike Ziller Reviewed-by: --- src/libs/utils/macroexpander.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 5d3bba0229a..4dc18b23f6b 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -247,7 +247,6 @@ QString MacroExpander::value(const QByteArray &variable, bool *found) const * See the MacroExpander overview documentation for other ways to expand variables. * * \sa MacroExpander - * \sa macroExpander() */ QString MacroExpander::expand(const QString &stringWithVariables) const { @@ -323,10 +322,11 @@ static QByteArray fullPrefix(const QByteArray &prefix) * Makes the given string-valued \a prefix known to the variable manager, * together with a localized \a description. * - * The \a value PrefixFunction will be called and gets the full variable name - * with the prefix stripped as input. + * The \a value \c PrefixFunction will be called and gets the full variable name + * with the prefix stripped as input. It is displayed to users if \a visible is + * \c true. * - * \sa registerVariables(), registerIntVariable(), registerFileVariables() + * \sa registerVariable(), registerIntVariable(), registerFileVariables() */ void MacroExpander::registerPrefix(const QByteArray &prefix, const QString &description, const MacroExpander::PrefixFunction &value, bool visible) @@ -341,6 +341,9 @@ void MacroExpander::registerPrefix(const QByteArray &prefix, const QString &desc * Makes the given string-valued \a variable known to the variable manager, * together with a localized \a description. * + * The \a value \c StringFunction is called to retrieve the current value of the + * variable. It is displayed to users if \a visibleInChooser is \c true. + * * \sa registerFileVariables(), registerIntVariable(), registerPrefix() */ void MacroExpander::registerVariable(const QByteArray &variable, @@ -355,6 +358,9 @@ void MacroExpander::registerVariable(const QByteArray &variable, * Makes the given integral-valued \a variable known to the variable manager, * together with a localized \a description. * + * The \a value \c IntFunction is called to retrieve the current value of the + * variable. + * * \sa registerVariable(), registerFileVariables(), registerPrefix() */ void MacroExpander::registerIntVariable(const QByteArray &variable, @@ -373,6 +379,10 @@ void MacroExpander::registerIntVariable(const QByteArray &variable, * variables such as \c{CurrentDocument:FilePath} with description * "Current Document: Full path including file name." * + * Takes a function that returns a FilePath as a \a base. + * + * The variable is displayed to users if \a visibleInChooser is \c true. + * * \sa registerVariable(), registerIntVariable(), registerPrefix() */ void MacroExpander::registerFileVariables(const QByteArray &prefix, From c04a4a1ae04d70ee7ca3dfe1d514f6ac37098c8f Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 26 May 2023 17:00:14 +0200 Subject: [PATCH 1322/1447] Doc: Fix qdoc warnings - Mark undocumented but existing functions with \c (instead of \l or \sa) - Remove reference to functions I could no longer find - Fix other broken links - Fix reference to an image whose file format changed to WEBP - Use {} instead of "" to mark alt text for images - Add missing \a commands - Add class name to a function name so that it can be found Change-Id: I10655bb0356c7417ab0e14a3ce620930f4ee8349 Reviewed-by: Reviewed-by: Eike Ziller --- .../src/common-extension-tasks.qdoc | 4 ++-- doc/qtcreatordev/src/plugin-lifecycle.qdoc | 3 +-- doc/qtcreatordev/src/plugin-tests.qdoc | 4 ++-- doc/qtcreatordev/src/qtcreator-dev.qdoc | 2 +- doc/qtcreatordev/src/qtcreator-ui-text.qdoc | 24 +++++++++---------- src/libs/extensionsystem/iplugin.cpp | 7 +++--- src/libs/utils/progressindicator.cpp | 4 ++-- 7 files changed, 23 insertions(+), 25 deletions(-) diff --git a/doc/qtcreatordev/src/common-extension-tasks.qdoc b/doc/qtcreatordev/src/common-extension-tasks.qdoc index fca444f5e02..c2a63680b94 100644 --- a/doc/qtcreatordev/src/common-extension-tasks.qdoc +++ b/doc/qtcreatordev/src/common-extension-tasks.qdoc @@ -52,7 +52,7 @@ \li Add support for a new version control system. \li Version control systems integrated in \QC are Bazaar, CVS, Git, Mecurial, Perforce, and Subversion. - \li \l{Core::IVersionControl} + \li \c{Core::IVersionControl} \row \li Add a view to the navigation sidebar. @@ -94,7 +94,7 @@ \li For a text typed in by the user you provide a list of things to show in the popup. When the user selects an entry you are requested to do whatever you want. - \li \l{Core::ILocatorFilter}, \l{Core::BaseFileFilter} + \li \l{Core::ILocatorFilter} \row \li Show a progress indicator for a concurrently running task. diff --git a/doc/qtcreatordev/src/plugin-lifecycle.qdoc b/doc/qtcreatordev/src/plugin-lifecycle.qdoc index ffd40635ce5..ec741c89a88 100644 --- a/doc/qtcreatordev/src/plugin-lifecycle.qdoc +++ b/doc/qtcreatordev/src/plugin-lifecycle.qdoc @@ -28,8 +28,7 @@ tracks the state of the plugin. You can get the \l{ExtensionSystem::PluginSpec} instances via the plugin manager's \l{ExtensionSystem::PluginManager::plugins()}{plugins()} - function, or, after a plugin is loaded, through the plugin's - \l{ExtensionSystem::IPlugin::pluginSpec()}{pluginSpec()} function. + function. \li Sets the plugins to \c Read state. diff --git a/doc/qtcreatordev/src/plugin-tests.qdoc b/doc/qtcreatordev/src/plugin-tests.qdoc index 78d9c6c4b6e..d3a4dd35a56 100644 --- a/doc/qtcreatordev/src/plugin-tests.qdoc +++ b/doc/qtcreatordev/src/plugin-tests.qdoc @@ -41,8 +41,8 @@ failure. To add plugin tests, add a QObject based class with private slots for your - tests, and register it with \l{ExtensionSystem::IPlugin::addTest()} in your - plugin's \l{ExtensionSystem::IPlugin::initialized()} method. Guard all test + tests, and register it with \c{ExtensionSystem::IPlugin::addTest()} in your + plugin's \l{ExtensionSystem::IPlugin::initialize()} method. Guard all test related code with a check for \c{WITH_TESTS}, to avoid shipping a binary release of your plugin with test functions. diff --git a/doc/qtcreatordev/src/qtcreator-dev.qdoc b/doc/qtcreatordev/src/qtcreator-dev.qdoc index ace8f860374..5e11b9e7b44 100644 --- a/doc/qtcreatordev/src/qtcreator-dev.qdoc +++ b/doc/qtcreatordev/src/qtcreator-dev.qdoc @@ -202,7 +202,7 @@ One way to handle that would be to let the tool create an output file, which is then opened within \QC. You provide an editor (probably read-only) for handling this file. For lists of issues, consider creating task list files - which are shown in \l Issues. + which are shown in \uicontrol Issues. \list \li \l{https://doc.qt.io/qtcreator/creator-task-lists.html} diff --git a/doc/qtcreatordev/src/qtcreator-ui-text.qdoc b/doc/qtcreatordev/src/qtcreator-ui-text.qdoc index 84688a4b857..42d5d9466c2 100644 --- a/doc/qtcreatordev/src/qtcreator-ui-text.qdoc +++ b/doc/qtcreatordev/src/qtcreator-ui-text.qdoc @@ -91,14 +91,14 @@ case, use book style capitalization and do not add a period after the tool tip. - \image qtcreator-tooltip.png "Tooltip" + \image qtcreator-tooltip.png {Tooltip} Tooltips can also contain full sentences. Try to make them as short and concise as possible, while still making them grammatically correct. Use sentence style capitalization and punctuation as you would for any sentence. - \image qtcreator-tooltip-long.png "Sentence as a tooltip" + \image qtcreator-tooltip-long.png {Sentence as a tooltip} \section3 Writing Tooltips in Design Mode @@ -333,7 +333,7 @@ \li Opens when users right-click on the screen. Contents depend on the context. - \image qtcreator-context-menu.png "Context menu" + \image qtcreator-context-menu.png {Context menu} \li You can add menu items that are relevant in a particular context. Follow the conventions for naming menu items. @@ -343,7 +343,7 @@ \li User interface element that usually contains a number of choices or allows the user to give input to the application. Opens when users select a menu item or button. - \image qtcreator-dialog.png "Dialog" + \image qtcreator-dialog.png {Dialog} \li Use the menu item or button name as the dialog name. You can also combine the menu item or button name and the name of the object that is managed in the dialog. For example, the \uicontrol Add @@ -354,7 +354,7 @@ \li Allows you to browse not only files, but any items defined by locator filters. - \image qtcreator-locator.png "Locator" + \image qtcreator-locator.webp {Locator} \li You can add locator filters. Check that the filter is not already in use and give the filter a descriptive name. @@ -365,7 +365,7 @@ \li Contains menu items that represent commands or options and that are logically grouped and displayed. A menu can also contain submenus. - \image qtcreator-menu.png "Menu" + \image qtcreator-menu.png {Menu} \li You can create new menus. Use short, but descriptive names that are consistent with existing menu names. Use unambigious names. @@ -373,7 +373,7 @@ \row \li Menu item \li Represents a command or an option for users to choose. - \image qtcreator-menu-item.png "Menu item" + \image qtcreator-menu-item.png {Menu item} \li You can add new items to menus. Use short, but descriptive names that are consistent with existing menu names. Use unambigious names. @@ -381,7 +381,7 @@ \li Message box \li Dialog that provides feedback to users, in the form of status information, a warning, or an error message. - \image qtcreator-error-message.png "Message box" + \image qtcreator-error-message.png {Message box} Output from Qt Creator should be displayed in output views, instead. \li Use the event as the title and provide a solution in the @@ -390,21 +390,21 @@ \li Mode \li Modes correspond to complete screens of controls, specialized for a task. - \image qtcreator-mode-selector.png "Mode selector" + \image qtcreator-mode-selector.png {Mode selector} \li You can add a mode for a new type of editor, for example. Use descriptive, but short mode names. They have to fit in the \uicontrol {Mode selector}. \row \li Output \li Views to display output from Qt Creator. - \image qtcreator-output-pane.png "Output" + \image qtcreator-output-pane.png {Output} \li Use descriptive names for output views. \row \li Sidebar \li A view available in the \uicontrol Edit and \uicontrol Debug modes that you can use to browse projects, files, and bookmarks, and to view the class hierarchy. - \image qtcreator-sidebar-menu.png "Sidebar" + \image qtcreator-sidebar-menu.png {Sidebar} \li You can add views to the sidebar menu. Use descriptive names for them. \row @@ -413,7 +413,7 @@ provides them with functions for managing the information. Available in \uicontrol Debug mode, for interaction with the program that is running under the control of the debugger. - \image qtcreator-debugger-views.webp "Views" + \image qtcreator-debugger-views.webp {Views} \li Use descriptive names for views. \endtable diff --git a/src/libs/extensionsystem/iplugin.cpp b/src/libs/extensionsystem/iplugin.cpp index 6661a46f610..2af49255735 100644 --- a/src/libs/extensionsystem/iplugin.cpp +++ b/src/libs/extensionsystem/iplugin.cpp @@ -248,7 +248,8 @@ void IPlugin::tryCreateObjects() } /*! - Registers a function object that creates a test object. + Registers a function object that creates a test object with the owner + \a creator. The created objects are meant to be passed on to \l QTest::qExec(). @@ -264,9 +265,7 @@ void IPlugin::addTestCreator(const TestCreator &creator) } /*! - \deprecated [10.0] Use addTest() instead - - \sa addTest() + \deprecated [10.0] Use \c addTest() instead. */ QVector IPlugin::createTestObjects() const { diff --git a/src/libs/utils/progressindicator.cpp b/src/libs/utils/progressindicator.cpp index 6e129cd58ed..d1ce125dbee 100644 --- a/src/libs/utils/progressindicator.cpp +++ b/src/libs/utils/progressindicator.cpp @@ -200,7 +200,7 @@ ProgressIndicator::ProgressIndicator(ProgressIndicatorSize size, QWidget *parent /*! Changes the size of the progress indicator to \a size. - \sa indicatorSize + \sa ProgressIndicatorPainter::indicatorSize() */ void ProgressIndicator::setIndicatorSize(ProgressIndicatorSize size) { @@ -211,7 +211,7 @@ void ProgressIndicator::setIndicatorSize(ProgressIndicatorSize size) /*! Returns the size of the indicator in device independent pixels. - \sa indicatorSize + \sa ProgressIndicatorPainter::indicatorSize() */ QSize ProgressIndicator::sizeHint() const { From 369ade4c1c9f6877541ccf491b73df221f9b72e0 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 14:23:54 +0200 Subject: [PATCH 1323/1447] CPaster: Use PagedSettings for settings Change-Id: I99ee3f548d98bc4f9e2fadcccd835d5d7f680934 Reviewed-by: Christian Stenger --- src/plugins/cpaster/cpasterplugin.cpp | 2 - .../cpaster/fileshareprotocolsettingspage.cpp | 2 - .../cpaster/fileshareprotocolsettingspage.h | 4 +- src/plugins/cpaster/settings.cpp | 40 ++++++------------- src/plugins/cpaster/settings.h | 20 +++------- 5 files changed, 21 insertions(+), 47 deletions(-) diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp index dd576f228f6..a18b454c860 100644 --- a/src/plugins/cpaster/cpasterplugin.cpp +++ b/src/plugins/cpaster/cpasterplugin.cpp @@ -75,8 +75,6 @@ public: &dpasteProto }; - SettingsPage m_settingsPage{&m_settings}; - QStringList m_fetchedSnippets; UrlOpenProtocol m_urlOpen; diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp index 04b896fa76f..99599a3cd80 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.cpp +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.cpp @@ -20,13 +20,11 @@ FileShareProtocolSettings::FileShareProtocolSettings() setCategory(Constants::CPASTER_SETTINGS_CATEGORY); setSettingsGroup("FileSharePasterSettings"); - registerAspect(&path); path.setSettingsKey("Path"); path.setExpectedKind(PathChooser::ExistingDirectory); path.setDefaultValue(TemporaryDirectory::masterDirectoryPath()); path.setLabelText(Tr::tr("&Path:")); - registerAspect(&displayCount); displayCount.setSettingsKey("DisplayCount"); displayCount.setDefaultValue(10); displayCount.setSuffix(' ' + Tr::tr("entries")); diff --git a/src/plugins/cpaster/fileshareprotocolsettingspage.h b/src/plugins/cpaster/fileshareprotocolsettingspage.h index 56c843007de..8775fe16096 100644 --- a/src/plugins/cpaster/fileshareprotocolsettingspage.h +++ b/src/plugins/cpaster/fileshareprotocolsettingspage.h @@ -12,8 +12,8 @@ class FileShareProtocolSettings : public Core::PagedSettings public: FileShareProtocolSettings(); - Utils::FilePathAspect path; - Utils::IntegerAspect displayCount; + Utils::FilePathAspect path{this}; + Utils::IntegerAspect displayCount{this}; }; } // CodePaster diff --git a/src/plugins/cpaster/settings.cpp b/src/plugins/cpaster/settings.cpp index 8f599dcd502..1c3d9e5e4db 100644 --- a/src/plugins/cpaster/settings.cpp +++ b/src/plugins/cpaster/settings.cpp @@ -16,13 +16,16 @@ Settings::Settings() { setSettingsGroup("CodePaster"); setAutoApply(false); + setId("A.CodePaster.General"); + setDisplayName(Tr::tr("General")); + setCategory(Constants::CPASTER_SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("Code Pasting")); + setCategoryIconPath(":/cpaster/images/settingscategory_cpaster.png"); - registerAspect(&username); username.setDisplayStyle(StringAspect::LineEditDisplay); username.setSettingsKey("UserName"); username.setLabelText(Tr::tr("Username:")); - registerAspect(&protocols); protocols.setSettingsKey("DefaultProtocol"); protocols.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); protocols.setLabelText(Tr::tr("Default protocol:")); @@ -33,48 +36,31 @@ Settings::Settings() return protocols.indexForDisplay(val.toString()); }); - registerAspect(&expiryDays); expiryDays.setSettingsKey("ExpiryDays"); expiryDays.setDefaultValue(1); expiryDays.setSuffix(Tr::tr(" Days")); expiryDays.setLabelText(Tr::tr("&Expires after:")); - registerAspect(©ToClipboard); copyToClipboard.setSettingsKey("CopyToClipboard"); copyToClipboard.setDefaultValue(true); copyToClipboard.setLabelText(Tr::tr("Copy-paste URL to clipboard")); - registerAspect(&displayOutput); displayOutput.setSettingsKey("DisplayOutput"); displayOutput.setDefaultValue(true); displayOutput.setLabelText(Tr::tr("Display General Messages after sending a post")); -} -// SettingsPage - -SettingsPage::SettingsPage(Settings *settings) -{ - setId("A.CodePaster.General"); - setDisplayName(Tr::tr("General")); - setCategory(Constants::CPASTER_SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("Code Pasting")); - setCategoryIconPath(":/cpaster/images/settingscategory_cpaster.png"); - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - Settings &s = *settings; + setLayouter([this] { using namespace Layouting; - - Column { + return Column { Form { - s.protocols, br, - s.username, br, - s.expiryDays + protocols, br, + username, br, + expiryDays }, - s.copyToClipboard, - s.displayOutput, + copyToClipboard, + displayOutput, st - }.attachTo(widget); + }; }); } diff --git a/src/plugins/cpaster/settings.h b/src/plugins/cpaster/settings.h index d54cc393bcf..1e7d03be761 100644 --- a/src/plugins/cpaster/settings.h +++ b/src/plugins/cpaster/settings.h @@ -5,26 +5,18 @@ #include -#include - namespace CodePaster { -class Settings : public Utils::AspectContainer +class Settings : public Core::PagedSettings { public: Settings(); - Utils::StringAspect username; - Utils::SelectionAspect protocols; - Utils::IntegerAspect expiryDays; - Utils::BoolAspect copyToClipboard; - Utils::BoolAspect displayOutput; -}; - -class SettingsPage final : public Core::IOptionsPage -{ -public: - SettingsPage(Settings *settings); + Utils::StringAspect username{this}; + Utils::SelectionAspect protocols{this}; + Utils::IntegerAspect expiryDays{this}; + Utils::BoolAspect copyToClipboard{this}; + Utils::BoolAspect displayOutput{this}; }; } // CodePaster From 6286ae98531f93ed3b49f7e279c4afee79ab881b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 30 May 2023 10:09:50 +0200 Subject: [PATCH 1324/1447] Utils: Use the path from the current object ... in Environment::searchInPath(). Amends 6ab66690. Change-Id: I04984c6a84c4448a6cd6d4d2677c84ed54376fee Reviewed-by: Orgad Shaneh --- src/libs/utils/environment.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 653525e1c3e..b9af2dea928 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -223,7 +223,8 @@ FilePath Environment::searchInPath(const QString &executable, const FilePathPredicate &filter) const { const FilePath exec = FilePath::fromUserInput(expandVariables(executable)); - return exec.searchInPath(additionalDirs, {}, filter, FilePath::WithAnySuffix); + const FilePaths dirs = path() + additionalDirs; + return exec.searchInDirectories(dirs, filter, FilePath::WithAnySuffix); } FilePaths Environment::path() const From 05b922ca945581b05201b064636e3da20fb52757 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 25 May 2023 17:32:36 +0200 Subject: [PATCH 1325/1447] TaskTree: Add documentation for group handlers Document onGroupSetup, onGroupDone and onGroupError methods, TaskItem::Group{Start,End}Handler and TaskAction enum. Change-Id: I7516b867a2e3ce33b8f15a18f85d1e61d673d65e Reviewed-by: Qt CI Bot Reviewed-by: Leena Miettinen Reviewed-by: Marcus Tillmanns --- src/libs/solutions/tasking/tasktree.cpp | 122 ++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 3d7f63216cd..a71afe60855 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -40,11 +40,133 @@ private: Guard &m_guard; }; +/*! + \class Tasking::TaskItem + \inheaderfile solutions/tasking/tasktree.h + \inmodule QtCreator + \ingroup mainclasses + \brief The TaskItem class represents the basic element for composing nested tree structures. +*/ + +/*! + \enum Tasking::TaskAction + + This enum is optionally returned from the group's or task's setup handler function. + It instructs the running task tree on how to proceed after the setup handler's execution + finished. + \value Continue + Default. The group's or task's execution continues nomally. + When a group's or task's setup handler returns void, it's assumed that + it returned Continue. + \value StopWithDone + The group's or task's execution stops immediately with success. + When returned from the group's setup handler, all child tasks are skipped, + and the group's onGroupDone handler is invoked (if provided). + When returned from the task's setup handler, the task isn't started, + its done handler isn't invoked, and the task reports success to its parent. + \value StopWithError + The group's or task's execution stops immediately with an error. + When returned from the group's setup handler, all child tasks are skipped, + and the group's onGroupError handler is invoked (if provided). + When returned from the task's setup handler, the task isn't started, + its error handler isn't invoked, and the task reports an error to its parent. +*/ + +/*! + \typealias TaskItem::GroupSetupHandler + + Type alias for \c std::function. + + The GroupSetupHandler is used when constructing the onGroupSetup element. + Any function with the above signature, when passed as a group setup handler, + will be called by the running task tree when the group executions starts. + + The return value of the handler instructs the running group on how to proceed + after the handler's invocation is finished. The default return value of TaskAction::Continue + instructs the group to continue running, i.e. to start executing its child tasks. + The return value of TaskAction::StopWithDone or TaskAction::StopWithError + instructs the group to skip the child tasks' execution and finish immediately with + success or an error, respectively. + + When the return type is either TaskAction::StopWithDone + of TaskAction::StopWithError, the group's done or error handler (if provided) + is called synchronously immediately afterwards. + + \note Even if the group setup handler returns StopWithDone or StopWithError, + one of the group's done or error handlers is invoked. This behavior differs + from that of task handlers and might change in the future. + + The onGroupSetup accepts also functions in the shortened form of \c std::function, + i.e. the return value is void. In this case it's assumed that the return value + is TaskAction::Continue by default. + + \sa onGroupSetup +*/ + +/*! + \typealias TaskItem::GroupEndHandler + + Type alias for \c std::function\. + + The GroupEndHandler is used when constructing the onGroupDone and onGroupError elements. + Any function with the above signature, when passed as a group done or error handler, + will be called by the running task tree when the group ends with success or an error, + respectively. + + \sa onGroupDone, onGroupError +*/ + +/*! + \fn template TaskItem onGroupSetup(SetupHandler &&handler) + + Constructs a group's element holding the group setup handler. + The \a handler is invoked whenever the group starts. + + The passed \a handler is either of \c std::function or \c std::function + type. For more information on possible argument type, refer to \l {TaskItem::GroupSetupHandler}. + + When the \a handler is invoked, none of the group's child tasks are running yet. + + If a group contains the Storage elements, the \a handler is invoked + after the storages are constructed, so that the \a handler may already + perform some initial modifications to the active storages. + + \sa TaskItem::GroupSetupHandler, onGroupDone, onGroupError +*/ + +/*! + Constructs a group's element holding the group done handler. + The \a handler is invoked whenever the group finishes with success. + Depending on the group's workflow policy, this handler may also be called + when the running group is stopped (e.g. when optional element was used). + + When the \a handler is invoked, all of the group's child tasks are already finished. + + If a group contains the Storage elements, the \a handler is invoked + before the storages are destructed, so that the \a handler may still + perform a last read of the active storages' data. + + \sa TaskItem::GroupEndHandler, onGroupSetup, onGroupError +*/ TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler) { return Group::onGroupDone(handler); } +/*! + Constructs a group's element holding the group error handler. + The \a handler is invoked whenever the group finishes with an error. + Depending on the group's workflow policy, this handler may also be called + when the running group is stopped (e.g. when stopOnError element was used). + + When the \a handler is invoked, all of the group's child tasks are already finished. + + If a group contains the Storage elements, the \a handler is invoked + before the storages are destructed, so that the \a handler may still + perform a last read of the active storages' data. + + \sa TaskItem::GroupEndHandler, onGroupSetup, onGroupDone +*/ TaskItem onGroupError(const TaskItem::GroupEndHandler &handler) { return Group::onGroupError(handler); From 5fe9c0fb7cbb2f94cdc6271c0c628a9c213e0cb7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 15:57:09 +0200 Subject: [PATCH 1326/1447] MCU: Fix wrong includes Change-Id: I87e701d11a25c1d6efb4924716034518c15e4053 Reviewed-by: Alessandro Portale Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp | 8 +++----- src/plugins/mcusupport/dialogs/mcukitcreationdialog.h | 5 +++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp index e708d53039d..7327f582115 100644 --- a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp +++ b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp @@ -4,9 +4,9 @@ #include "mcukitcreationdialog.h" #include "ui_mcukitcreationdialog.h" -#include "mcuabstractpackage.h" -#include "mcusupportconstants.h" -#include "mcusupporttr.h" +#include "../mcuabstractpackage.h" +#include "../mcusupportconstants.h" +#include "../mcusupporttr.h" #include #include @@ -15,9 +15,7 @@ #include #include -#include #include -#include namespace McuSupport::Internal { diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h index 186eec7be41..7164c6d0efb 100644 --- a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h +++ b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h @@ -3,8 +3,9 @@ #pragma once -#include "mcusupport_global.h" -#include "settingshandler.h" +#include "../mcusupport_global.h" +#include "../settingshandler.h" + #include #include From 2cce367906ca0fd57f902772ecf3342ce5f961c6 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 16:13:58 +0200 Subject: [PATCH 1327/1447] qbs build: Do not mark Axivion as a commercial plugin This gets rid of the (optional) LicenseChecker dependency and the extra git hash embedding. Change-Id: I8f148a83bcf563859fa01e5993999c2ab8fd7cc4 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/axivion/axivion.qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivion.qbs b/src/plugins/axivion/axivion.qbs index 4e20de194ba..bfe8efe6cf5 100644 --- a/src/plugins/axivion/axivion.qbs +++ b/src/plugins/axivion/axivion.qbs @@ -1,6 +1,6 @@ import qbs -QtcCommercialPlugin { +QtcPlugin { name: "Axivion" Depends { name: "Core" } From 0c1974f9b89c0526e135d2a6d2e57edec992f21e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 10:01:51 +0200 Subject: [PATCH 1328/1447] CppEditor: Fix highlighting angle brackets The code assumed that all highlighting results come in at once, which is no longer true as of d6f5d07639c3d0313b758ba6fb7cc5eb57d188ef. Change-Id: I5ed6baf88956d64a30ee3fb236d4e2575a7f80c9 Reviewed-by: David Schulz Reviewed-by: --- src/plugins/cppeditor/semantichighlighter.cpp | 13 +++++++++---- src/plugins/cppeditor/semantichighlighter.h | 9 +++++++++ src/plugins/texteditor/textdocumentlayout.h | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index 473991787d0..c04b9270aa9 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -63,15 +63,20 @@ void SemanticHighlighter::run() connectWatcher(); m_revision = documentRevision(); + m_seenBlocks.clear(); qCDebug(log) << "starting runner for document revision" << m_revision; m_watcher->setFuture(m_highlightingRunner()); } -static Parentheses getClearedParentheses(const QTextBlock &block) +Parentheses SemanticHighlighter::getClearedParentheses(const QTextBlock &block) { - return Utils::filtered(TextDocumentLayout::parentheses(block), [](const Parenthesis &p) { - return p.source != parenSource(); - }); + Parentheses parens = TextDocumentLayout::parentheses(block); + if (m_seenBlocks.insert(block.blockNumber()).second) { + parens = Utils::filtered(parens, [](const Parenthesis &p) { + return p.source != parenSource(); + }); + } + return parens; } void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) diff --git a/src/plugins/cppeditor/semantichighlighter.h b/src/plugins/cppeditor/semantichighlighter.h index b34c49ce87a..fb1a704e6c3 100644 --- a/src/plugins/cppeditor/semantichighlighter.h +++ b/src/plugins/cppeditor/semantichighlighter.h @@ -8,14 +8,21 @@ #include #include #include +#include #include +#include namespace TextEditor { class HighlightingResult; +class Parenthesis; class TextDocument; } +QT_BEGIN_NAMESPACE +class QTextBlock; +QT_END_NAMESPACE + namespace CppEditor { class CPPEDITOR_EXPORT SemanticHighlighter : public QObject @@ -66,6 +73,7 @@ private: void disconnectWatcher(); unsigned documentRevision() const; + QVector getClearedParentheses(const QTextBlock &block); private: TextEditor::TextDocument *m_baseTextDocument; @@ -73,6 +81,7 @@ private: unsigned m_revision = 0; QScopedPointer> m_watcher; QHash m_formatMap; + std::set m_seenBlocks; HighlightingRunner m_highlightingRunner; }; diff --git a/src/plugins/texteditor/textdocumentlayout.h b/src/plugins/texteditor/textdocumentlayout.h index d6f847e4810..33387093da7 100644 --- a/src/plugins/texteditor/textdocumentlayout.h +++ b/src/plugins/texteditor/textdocumentlayout.h @@ -17,8 +17,9 @@ namespace TextEditor { -struct TEXTEDITOR_EXPORT Parenthesis +class TEXTEDITOR_EXPORT Parenthesis { +public: enum Type : char { Opened, Closed }; Parenthesis() = default; From bc52355f986d6d69279f34642d802fbd7d34025a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 10:17:38 +0200 Subject: [PATCH 1329/1447] Tr: Move some html out of texts Change-Id: I46c8d81630e18e244f16cefe696d662632340008 Reviewed-by: Leena Miettinen Reviewed-by: hjk --- share/qtcreator/translations/qtcreator_de.ts | 8 ++++---- src/plugins/cppeditor/cppcodemodelsettingspage.cpp | 6 ++++-- src/plugins/debugger/debuggeractions.cpp | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 1783414a4bf..4b2e4bc008f 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -20339,8 +20339,8 @@ z.B. name = "m_test_foo_": Dateien ignorieren - <html><head/><body><p>Ignore files that match these wildcard patterns, one wildcard per line.</p></body></html> - <html><head/><body><p>Dateien ignorieren, die diesen Platzhalter-Filtern entsprechen. Ein Filter pro Zeile.</p></body></html> + Ignore files that match these wildcard patterns, one wildcard per line. + Dateien ignorieren, die diesen Platzhalter-Filtern entsprechen. Ein Filter pro Zeile. Ignore precompiled headers @@ -25092,8 +25092,8 @@ Das Setzen von Haltepunkten anhand von Dateinamen und Zeilennummern könnte fehl Schriftgröße des Debuggers mit Editor synchronisieren - <p>Not all source code lines generate executable code. Putting a breakpoint on such a line acts as if the breakpoint was set on the next line that generated code. Selecting 'Adjust Breakpoint Locations' shifts the red breakpoint markers in such cases to the location of the true breakpoint. - <p>Nicht aus allen Quellcode-Zeilen wird ausführbarer Code erzeugt. Wenn man dort einen Haltepunkt setzt, verhält er sich so, als ob er auf die nächste Zeile gesetzt worden wäre, aus der Maschinencode erzeugt wurde. Das Aktivieren der Einstellung 'Positionen der Haltepunkte korrigieren' bewirkt, dass der Haltepunkt-Marker in so einem Fall an die Stelle des resultierenden Haltepunkts verschoben wird. + Not all source code lines generate executable code. Putting a breakpoint on such a line acts as if the breakpoint was set on the next line that generated code. Selecting 'Adjust Breakpoint Locations' shifts the red breakpoint markers in such cases to the location of the true breakpoint. + Nicht aus allen Quellcode-Zeilen wird ausführbarer Code erzeugt. Wenn man dort einen Haltepunkt setzt, verhält er sich so, als ob er auf die nächste Zeile gesetzt worden wäre, aus der Maschinencode erzeugt wurde. Das Aktivieren der Einstellung 'Positionen der Haltepunkte korrigieren' bewirkt, dass der Haltepunkt-Marker in so einem Fall an die Stelle des resultierenden Haltepunkts verschoben wird. Stopping and stepping in the debugger will automatically open views associated with the current location. diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index 15240b7e9fe..289cd3dc86c 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -72,8 +72,10 @@ CppCodeModelSettingsWidget::CppCodeModelSettingsWidget(CppCodeModelSettings *s) m_bigFilesLimitSpinBox->setValue(m_settings->indexerFileSizeLimitInMb()); m_ignoreFilesCheckBox = new QCheckBox(Tr::tr("Ignore files")); - m_ignoreFilesCheckBox->setToolTip(Tr::tr( - "

    Ignore files that match these wildcard patterns, one wildcard per line.

    ")); + m_ignoreFilesCheckBox->setToolTip( + "

    " + + Tr::tr("Ignore files that match these wildcard patterns, one wildcard per line.") + + "

    "); m_ignoreFilesCheckBox->setChecked(m_settings->ignoreFiles()); m_ignorePatternTextEdit = new QPlainTextEdit(m_settings->ignorePattern()); diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 038696f4bac..907e626f4dc 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -242,7 +242,7 @@ DebuggerSettings::DebuggerSettings() adjustBreakpointLocations.setDisplayName(Tr::tr("Adjust Breakpoint Locations")); adjustBreakpointLocations.setToolTip( "

    " - + Tr::tr("

    Not all source code lines generate " + + Tr::tr("Not all source code lines generate " "executable code. Putting a breakpoint on such a line acts as " "if the breakpoint was set on the next line that generated code. " "Selecting 'Adjust Breakpoint Locations' shifts the red " From aa2e8e3cb886f0be8229f69c983dac867fc09efe Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 09:50:13 +0200 Subject: [PATCH 1330/1447] VcPkg: Adapt settings page setup to recent aspect development Change-Id: I16f4721723450e2f843f2eff0946e29733978eb0 Reviewed-by: Christian Stenger --- src/plugins/vcpkg/vcpkgmanifesteditor.cpp | 5 ++-- src/plugins/vcpkg/vcpkgsearch.cpp | 2 +- src/plugins/vcpkg/vcpkgsettings.cpp | 36 +++++++++-------------- src/plugins/vcpkg/vcpkgsettings.h | 9 +++--- 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/plugins/vcpkg/vcpkgmanifesteditor.cpp b/src/plugins/vcpkg/vcpkgmanifesteditor.cpp index fa7c6ebfaf3..40e4837cf77 100644 --- a/src/plugins/vcpkg/vcpkgmanifesteditor.cpp +++ b/src/plugins/vcpkg/vcpkgmanifesteditor.cpp @@ -38,13 +38,14 @@ public: Core::ICore::showOptionsDialog(Constants::TOOLSSETTINGSPAGE_ID); }); - connect(&VcpkgSettings::instance()->vcpkgRoot, &Utils::BaseAspect::changed, + connect(&settings().vcpkgRoot, &Utils::BaseAspect::changed, this, &VcpkgManifestEditorWidget::updateToolBar); } void updateToolBar() { - m_searchPkgAction->setEnabled(VcpkgSettings::instance()->vcpkgRootValid()); + Utils::FilePath vcpkg = settings().vcpkgRoot().pathAppended("vcpkg").withExecutableSuffix(); + m_searchPkgAction->setEnabled(vcpkg.isExecutableFile()); } private: diff --git a/src/plugins/vcpkg/vcpkgsearch.cpp b/src/plugins/vcpkg/vcpkgsearch.cpp index 1e2d28f74ab..b9315ec540c 100644 --- a/src/plugins/vcpkg/vcpkgsearch.cpp +++ b/src/plugins/vcpkg/vcpkgsearch.cpp @@ -94,7 +94,7 @@ VcpkgPackageSearchDialog::VcpkgPackageSearchDialog(QWidget *parent) m_buttonBox, }.attachTo(this); - m_allPackages = vcpkgManifests(VcpkgSettings::instance()->vcpkgRoot()); + m_allPackages = vcpkgManifests(settings().vcpkgRoot()); listPackages({}); diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp index eb3c71c0b4d..a450373ab52 100644 --- a/src/plugins/vcpkg/vcpkgsettings.cpp +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -7,7 +7,6 @@ #include -#include #include #include #include @@ -19,9 +18,9 @@ namespace Vcpkg::Internal { static VcpkgSettings *theSettings = nullptr; -VcpkgSettings *VcpkgSettings::instance() +VcpkgSettings &settings() { - return theSettings; + return *theSettings; } VcpkgSettings::VcpkgSettings() @@ -29,20 +28,27 @@ VcpkgSettings::VcpkgSettings() theSettings = this; setSettingsGroup("Vcpkg"); - setId(Constants::TOOLSSETTINGSPAGE_ID); setDisplayName("Vcpkg"); setCategory(CMakeProjectManager::Constants::Settings::CATEGORY); - setLayouter([this](QWidget *widget) { + vcpkgRoot.setSettingsKey("VcpkgRoot"); + vcpkgRoot.setExpectedKind(Utils::PathChooser::ExistingDirectory); + vcpkgRoot.setDefaultValue(Utils::qtcEnvironmentVariable(Constants::ENVVAR_VCPKG_ROOT)); + + setLayouter([this] { using namespace Layouting; auto websiteButton = new QToolButton; websiteButton->setIcon(Utils::Icons::ONLINE.icon()); websiteButton->setToolTip(Constants::WEBSITE_URL); + connect(websiteButton, &QAbstractButton::clicked, [] { + QDesktopServices::openUrl(QUrl::fromUserInput(Constants::WEBSITE_URL)); + }); + // clang-format off using namespace Layouting; - Column { + return Column { Group { title(tr("Vcpkg installation")), Form { @@ -51,25 +57,11 @@ VcpkgSettings::VcpkgSettings() }, }, st, - }.attachTo(widget); + }; // clang-format on - - connect(websiteButton, &QAbstractButton::clicked, [] { - QDesktopServices::openUrl(QUrl::fromUserInput(Constants::WEBSITE_URL)); - }); }); - registerAspect(&vcpkgRoot); - vcpkgRoot.setSettingsKey("VcpkgRoot"); - vcpkgRoot.setExpectedKind(Utils::PathChooser::ExistingDirectory); - vcpkgRoot.setDefaultValue(Utils::qtcEnvironmentVariable(Constants::ENVVAR_VCPKG_ROOT)); - readSettings(); } -bool VcpkgSettings::vcpkgRootValid() const -{ - return (vcpkgRoot() / "vcpkg").withExecutableSuffix().isExecutableFile(); -} - -} // namespace Vcpkg::Internal +} // Vcpkg::Internal diff --git a/src/plugins/vcpkg/vcpkgsettings.h b/src/plugins/vcpkg/vcpkgsettings.h index bbff08035ab..6a00fd506f7 100644 --- a/src/plugins/vcpkg/vcpkgsettings.h +++ b/src/plugins/vcpkg/vcpkgsettings.h @@ -12,10 +12,9 @@ class VcpkgSettings : public Core::PagedSettings public: VcpkgSettings(); - static VcpkgSettings *instance(); - bool vcpkgRootValid() const; - - Utils::FilePathAspect vcpkgRoot; + Utils::FilePathAspect vcpkgRoot{this}; }; -} // namespace Vcpkg::Internal +VcpkgSettings &settings(); + +} // Vcpkg::Internal From 9719bcfd2e24954016ed3eef83d1b9ec730c8fc2 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 26 May 2023 14:50:16 +0200 Subject: [PATCH 1331/1447] Core: Fix filter when selected is not registered Without this patch a warning will be triggered on Windows and the selected filter is not chosen on all platforms when saving a file, e.g. a json file. Change-Id: Id6de0eddcac83369596f68d50494f10b70c30b15 Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/coreplugin/documentmanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 98ab6514119..b7b7ccfbe06 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -856,7 +856,7 @@ FilePath DocumentManager::getSaveFileNameWithExtension(const QString &title, con FilePath DocumentManager::getSaveAsFileName(const IDocument *document) { QTC_ASSERT(document, return {}); - const QString filter = allDocumentFactoryFiltersString(); + QString filter = allDocumentFactoryFiltersString(); const FilePath filePath = document->filePath(); QString selectedFilter; FilePath fileDialogPath = filePath; @@ -876,6 +876,9 @@ FilePath DocumentManager::getSaveAsFileName(const IDocument *document) if (selectedFilter.isEmpty()) selectedFilter = Utils::mimeTypeForName(document->mimeType()).filterString(); + if (!filter.contains(selectedFilter)) + filter.prepend(selectedFilter + QLatin1String(";;")); + return getSaveFileName(Tr::tr("Save File As"), fileDialogPath, filter, From e47c49b3f697351ccc772cb05cbb2c03144f83ae Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:03:49 +0200 Subject: [PATCH 1332/1447] Conan: Register settingsaspect directly Change-Id: I16f6b55b66a15670fc6382073700321d1db56adc Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/conan/conansettings.cpp | 1 - src/plugins/conan/conansettings.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/conan/conansettings.cpp b/src/plugins/conan/conansettings.cpp index 4aca2ddffbe..50373c764b6 100644 --- a/src/plugins/conan/conansettings.cpp +++ b/src/plugins/conan/conansettings.cpp @@ -22,7 +22,6 @@ ConanSettings::ConanSettings() setSettingsGroup("ConanSettings"); setAutoApply(false); - registerAspect(&conanFilePath); conanFilePath.setSettingsKey("ConanFilePath"); conanFilePath.setExpectedKind(PathChooser::ExistingCommand); conanFilePath.setDefaultValue(HostOsInfo::withExecutableSuffix("conan")); diff --git a/src/plugins/conan/conansettings.h b/src/plugins/conan/conansettings.h index 41b7a133188..67485037288 100644 --- a/src/plugins/conan/conansettings.h +++ b/src/plugins/conan/conansettings.h @@ -12,7 +12,7 @@ class ConanSettings : public Utils::AspectContainer public: ConanSettings(); - Utils::FilePathAspect conanFilePath; + Utils::FilePathAspect conanFilePath{this}; }; ConanSettings &settings(); From 5943a42249884103190f28f33ba02ec5b780b01f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 23 May 2023 06:56:21 +0200 Subject: [PATCH 1333/1447] Core: Add OutputPane::setupContext overload Change-Id: I15dc1cfa1981ea32925988c524b54cfd5ea1fcbd Reviewed-by: Eike Ziller --- src/plugins/coreplugin/ioutputpane.h | 2 ++ src/plugins/coreplugin/outputpanemanager.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/ioutputpane.h b/src/plugins/coreplugin/ioutputpane.h index 8222ca19bc6..f3ae7fa0b82 100644 --- a/src/plugins/coreplugin/ioutputpane.h +++ b/src/plugins/coreplugin/ioutputpane.h @@ -4,6 +4,7 @@ #pragma once #include "core_global.h" +#include "icontext.h" #include #include @@ -88,6 +89,7 @@ protected: void setFilteringEnabled(bool enable); QWidget *filterWidget() const { return m_filterOutputLineEdit; } void setupContext(const char *context, QWidget *widget); + void setupContext(const Context &context, QWidget *widget); void setZoomButtonsEnabled(bool enabled); private: diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index b26caf92322..037779f0bfb 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -166,10 +166,15 @@ void IOutputPane::setFilteringEnabled(bool enable) } void IOutputPane::setupContext(const char *context, QWidget *widget) +{ + return setupContext(Context(context), widget); +} + +void IOutputPane::setupContext(const Context &context, QWidget *widget) { QTC_ASSERT(!m_context, return); m_context = new IContext(this); - m_context->setContext(Context(context)); + m_context->setContext(context); m_context->setWidget(widget); ICore::addContextObject(m_context); From afbdad999d68137e71cf9e97b0c1ae64c44e22d5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 23 May 2023 06:57:02 +0200 Subject: [PATCH 1334/1447] Core: Add Command::actionForContext Change-Id: I04ea463e1e9f4addafbea78c6302a488d7992ccd Reviewed-by: Eike Ziller Reviewed-by: --- src/plugins/coreplugin/actionmanager/command.cpp | 9 +++++++++ src/plugins/coreplugin/actionmanager/command.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp index 592ba08faac..ab78bf50892 100644 --- a/src/plugins/coreplugin/actionmanager/command.cpp +++ b/src/plugins/coreplugin/actionmanager/command.cpp @@ -289,6 +289,15 @@ QAction *Command::action() const return d->m_action; } +QAction *Command::actionForContext(const Utils::Id &contextId) const +{ + auto it = d->m_contextActionMap.find(contextId); + if (it == d->m_contextActionMap.end()) + return nullptr; + + return *it; +} + QString Command::stringWithAppendedShortcut(const QString &str) const { return Utils::ProxyAction::stringWithAppendedShortcut(str, keySequence()); diff --git a/src/plugins/coreplugin/actionmanager/command.h b/src/plugins/coreplugin/actionmanager/command.h index b900a50f55a..73dd92a5eb8 100644 --- a/src/plugins/coreplugin/actionmanager/command.h +++ b/src/plugins/coreplugin/actionmanager/command.h @@ -57,6 +57,8 @@ public: Utils::Id id() const; QAction *action() const; + QAction *actionForContext(const Utils::Id &contextId) const; + Context context() const; void setAttribute(CommandAttribute attr); From a6848e2026883d46a5826a74554a942c5c7c6120 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 10:35:06 +0200 Subject: [PATCH 1335/1447] Docker: Register settings aspect more directly Change-Id: Iaf36d476f53eab459cba4d0e64e55b73a395beea Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/docker/dockersettings.cpp | 1 - src/plugins/docker/dockersettings.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp index a5dfc8581fc..0643cb3a31a 100644 --- a/src/plugins/docker/dockersettings.cpp +++ b/src/plugins/docker/dockersettings.cpp @@ -41,7 +41,6 @@ DockerSettings::DockerSettings() else additionalPaths.append("/usr/local/bin"); - registerAspect(&dockerBinaryPath); dockerBinaryPath.setExpectedKind(PathChooser::ExistingCommand); dockerBinaryPath.setDefaultFilePath( FilePath::fromString("docker").searchInPath(additionalPaths)); diff --git a/src/plugins/docker/dockersettings.h b/src/plugins/docker/dockersettings.h index 92b2f374ccf..076acf6fa8c 100644 --- a/src/plugins/docker/dockersettings.h +++ b/src/plugins/docker/dockersettings.h @@ -12,7 +12,7 @@ class DockerSettings final : public Core::PagedSettings public: DockerSettings(); - Utils::FilePathAspect dockerBinaryPath; + Utils::FilePathAspect dockerBinaryPath{this}; }; } // Docker::Internal From 8c3d2d122fb9eca343591f1f872786ed87ccae2a Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 29 May 2023 10:12:07 +0300 Subject: [PATCH 1336/1447] TaskWindow: Remove unused m_contextMenu Amends commit 432de3a198f4879c70506b64b2cc89825a17e7f9 (from 2012!). Change-Id: Iadb9474e46d0d2758dc5a6d9219c2bf04c2d66c5 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/taskwindow.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index f45a3df9216..eb4b9de8ca5 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -143,7 +143,6 @@ public: Internal::TaskFilterModel *m_filter; TaskView m_treeView; Core::IContext *m_taskWindowContext; - QMenu *m_contextMenu; QMap m_actionToHandlerMap; ITaskHandler *m_defaultHandler = nullptr; QToolButton *m_filterWarningsButton; @@ -207,8 +206,6 @@ TaskWindow::TaskWindow() : d(std::make_unique()) } }); - d->m_contextMenu = new QMenu(&d->m_treeView); - d->m_treeView.setContextMenuPolicy(Qt::ActionsContextMenu); d->m_filterWarningsButton = createFilterButton( From 78f2dda7ef7bfe196dad3923cb06539c7bf0f884 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 26 May 2023 18:30:18 +0200 Subject: [PATCH 1337/1447] TaskTree: Add docs for execution mode Transform it form TaskTree's description into description of sequential and parallel global variables, and into docs for parallelLimit() global function. Change-Id: I4aa2bac2f47778cde039cee77052359264224f93 Reviewed-by: Leena Miettinen --- src/libs/solutions/tasking/tasktree.cpp | 108 ++++++++++++++++-------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index a71afe60855..071190dd9eb 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -48,6 +48,32 @@ private: \brief The TaskItem class represents the basic element for composing nested tree structures. */ +/*! + \variable sequential + A convenient global group's element describing the sequential execution mode. + + This is the default execution mode of the Group element. + + When a Group has no execution mode, it runs in the sequential mode. + All the direct child tasks of a group are started in a chain, so that when one task finishes, + the next one starts. This enables you to pass the results from the previous task + as input to the next task before it starts. This mode guarantees that the next task + is started only after the previous task finishes. + + \sa parallel, parallelLimit +*/ + +/*! + \variable parallel + A convenient global group's element describing the parallel execution mode. + + All the direct child tasks of a group are started after the group is started, + without waiting for the previous child tasks to finish. + In this mode, all child tasks run simultaneously. + + \sa sequential, parallelLimit +*/ + /*! \enum Tasking::TaskAction @@ -172,6 +198,47 @@ TaskItem onGroupError(const TaskItem::GroupEndHandler &handler) return Group::onGroupError(handler); } +/*! + Constructs a group's element describing the \l{Execution Mode}{execution mode}. + + The execution mode element in a Group specifies how the direct child tasks of + the Group are started. + + For convenience, when appropriate, the \l sequential or \l parallel global elements + may be used instead. + + The \a limit defines the maximum number of direct child tasks running in parallel: + + \list + \li When \a limit equals to 0, there is no limit, and all direct child tasks are started + together, in the oder in which they appear in a group. This means the fully parallel + execution, and the \l parallel element may be used instead. + + \li When \a limit equals to 1, it means that only one child task may run at the time. + This means the sequential execution, and the \l sequential element may be used instead. + In this case child tasks run in chain, so the next child task starts after + the previous child task has finished. + + \li When other positive number is passed as \a limit, the group's child tasks run + in parallel, but with a limited number of tasks running simultanously. + The \e limit defines the maximum number of tasks running in parallel in a group. + When the group is started, the first batch of tasks is started + (the number of tasks in a batch equals to the passed \a limit, at most), + while the others are kept waiting. When any running task finishes, + the group starts the next remaining one, so that the \e limit of simultaneously + running tasks inside a group isn't exceeded. This repeats on every child task's + finish until all child tasks are started. This enables you to limit the maximum + number of tasks that run simultaneously, for example if running too many processes might + block the machine for a long time. + \endlist + + In all execution modes, a group starts tasks in the oder in which they appear. + + If a child of a group is also a group, the child group runs its tasks according + to its own execution mode. + + \sa sequential, parallel +*/ TaskItem parallelLimit(int limit) { return Group::parallelLimit(qMax(limit, 0)); @@ -1252,45 +1319,14 @@ void TaskNode::invokeEndHandler(bool success) \section2 Execution Mode The execution mode element in a Group specifies how the direct child tasks of - the Group are started. - - \table - \header - \li Execution Mode - \li Description - \row - \li sequential - \li Default. When a Group has no execution mode, it runs in the - sequential mode. All the direct child tasks of a group are started - in a chain, so that when one task finishes, the next one starts. - This enables you to pass the results from the previous task - as input to the next task before it starts. This mode guarantees - that the next task is started only after the previous task finishes. - \row - \li parallel - \li All the direct child tasks of a group are started after the group is - started, without waiting for the previous tasks to finish. In this - mode, all tasks run simultaneously. - \row - \li parallelLimit(int limit) - \li In this mode, a limited number of direct child tasks run simultaneously. - The \e limit defines the maximum number of tasks running in parallel - in a group. When the group is started, the first batch tasks is - started (the number of tasks in batch equals to passed limit, at most), - while the others are kept waiting. When a running task finishes, - the group starts the next remaining one, so that the \e limit - of simultaneously running tasks inside a group isn't exceeded. - This repeats on every child task's finish until all child tasks are started. - This enables you to limit the maximum number of tasks that - run simultaneously, for example if running too many processes might - block the machine for a long time. The value 1 means \e sequential - execution. The value 0 means unlimited and equals \e parallel. - \endtable + the Group are started. The most common execution modes are \l sequential and + \l parallel. It's also possible to specify the limit of tasks running + in parallel by using the parallelLimit function. In all execution modes, a group starts tasks in the oder in which they appear. - If a child of a group is also a group (in a nested tree), the child group - runs its tasks according to its own execution mode. + If a child of a group is also a group, the child group runs its tasks + according to its own execution mode. \section2 Workflow Policy From d64954b02915e9a38d800bcc7d90b92b75de9081 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 25 May 2023 17:17:52 +0200 Subject: [PATCH 1338/1447] Utils: Fix QTC_STATIC_BUILD build Change-Id: I14ac8c99708aba548d1054b37e5a445f6ac1a2b7 Reviewed-by: Reviewed-by: Eike Ziller --- src/libs/utils/layoutbuilder.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index d716ad034c5..1f774ba1461 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -11,6 +11,8 @@ #if defined(UTILS_LIBRARY) # define QTCREATOR_UTILS_EXPORT Q_DECL_EXPORT +#elif defined(UTILS_STATIC_LIBRARY) +# define QTCREATOR_UTILS_EXPORT #else # define QTCREATOR_UTILS_EXPORT Q_DECL_IMPORT #endif From 12456ce6884f7dc016aacf00bb14a0db37cf0b6f Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 25 May 2023 17:32:29 +0200 Subject: [PATCH 1339/1447] Terminal: Fix build with QTC_STATIC_BUILD The `log` Q_LOGGING_CATEGORY was used in a different place, and would conflict in a static build. Change-Id: Id23722a2aca3ea9afb846d8dd75aed9972c7b16f Reviewed-by: Reviewed-by: Eike Ziller Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalsurface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/terminal/terminalsurface.cpp b/src/plugins/terminal/terminalsurface.cpp index ee8e571adb3..ea994302318 100644 --- a/src/plugins/terminal/terminalsurface.cpp +++ b/src/plugins/terminal/terminalsurface.cpp @@ -12,10 +12,10 @@ #include -Q_LOGGING_CATEGORY(log, "qtc.terminal.surface", QtWarningMsg); - namespace Terminal::Internal { +Q_LOGGING_CATEGORY(log, "qtc.terminal.surface", QtWarningMsg); + QColor toQColor(const VTermColor &c) { return QColor(qRgb(c.rgb.red, c.rgb.green, c.rgb.blue)); From 38fde456a326d5890cb0288f55205695750ca208 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 30 May 2023 10:02:41 +0200 Subject: [PATCH 1340/1447] CppEditor: use markdown for resource image tooltips Fixes: QTCREATORBUG-29217 Change-Id: Iba3d876d988336276996aac733a6ea9b0eb45882 Reviewed-by: Eike Ziller --- src/plugins/cppeditor/resourcepreviewhoverhandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp index 0937df32ab6..8654b2c35d1 100644 --- a/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp +++ b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp @@ -166,7 +166,7 @@ void ResourcePreviewHoverHandler::operateTooltip(TextEditorWidget *editorWidget, { const QString tt = makeTooltip(); if (!tt.isEmpty()) - Utils::ToolTip::show(point, tt, editorWidget); + Utils::ToolTip::show(point, tt, Qt::MarkdownText, editorWidget); else Utils::ToolTip::hide(); } @@ -180,7 +180,7 @@ QString ResourcePreviewHoverHandler::makeTooltip() const const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_resPath); if (mimeType.name().startsWith("image", Qt::CaseInsensitive)) - ret += QString("
    ").arg(m_resPath); + ret += QString("![image](%1) \n").arg(m_resPath); ret += QString("%2") .arg(m_resPath, QDir::toNativeSeparators(m_resPath)); From 3be931d2348a610b3f40effbed84c6e6d680fc70 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 30 May 2023 12:00:59 +0200 Subject: [PATCH 1341/1447] Fix some unused 'this' lambda captures Change-Id: I63cb4e68d8675c7a83d90c8ccc11e646b6a5c659 Reviewed-by: Marcus Tillmanns --- src/plugins/conan/conaninstallstep.cpp | 2 +- src/plugins/terminal/terminalsettings.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/conan/conaninstallstep.cpp b/src/plugins/conan/conaninstallstep.cpp index cae573845e8..2a634190365 100644 --- a/src/plugins/conan/conaninstallstep.cpp +++ b/src/plugins/conan/conaninstallstep.cpp @@ -112,7 +112,7 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id) return param.summary(displayName()); }); - connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this](Project * project) { + connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [](Project * project) { connect(project, &Project::addedTarget, project, [project] (Target *target) { connectTarget(project, target); }); diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 577367b6641..692af4ec9c5 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -483,7 +483,7 @@ TerminalSettings::TerminalSettings() auto loadThemeButton = new QPushButton(Tr::tr("Load Theme...")); auto resetTheme = new QPushButton(Tr::tr("Reset Theme")); - connect(loadThemeButton, &QPushButton::clicked, this, [this] { + connect(loadThemeButton, &QPushButton::clicked, this, [] { const FilePath path = FileUtils::getOpenFilePath( Core::ICore::dialogParent(), "Open Theme", From 78eb97fb54d1fc39b160f0768f6b37e94db2ca7c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 30 May 2023 09:43:26 +0200 Subject: [PATCH 1342/1447] Git: Fix default port for gerritoptionspage.cpp We need to set the range before the value, otherwise we end up using the default maximum of 99 when setting it. Change-Id: I93de2cade3c2884dab64f04a52b2d3e3db98e1c4 Reviewed-by: Orgad Shaneh Reviewed-by: hjk --- src/plugins/git/gerrit/gerritoptionspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/git/gerrit/gerritoptionspage.cpp b/src/plugins/git/gerrit/gerritoptionspage.cpp index 3f225d82eb1..3d77c26aa46 100644 --- a/src/plugins/git/gerrit/gerritoptionspage.cpp +++ b/src/plugins/git/gerrit/gerritoptionspage.cpp @@ -43,8 +43,8 @@ public: curlChooser->setCommandVersionArguments({"-V"}); auto portSpinBox = new QSpinBox(this); - portSpinBox->setValue(p->server.port); portSpinBox->setRange(1, 65535); + portSpinBox->setValue(p->server.port); auto httpsCheckBox = new QCheckBox(Git::Tr::tr("HTTPS")); httpsCheckBox->setChecked(p->https); From c2fcd17e91d6133cb32bc427364de2d60dc83157 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 11:19:53 +0200 Subject: [PATCH 1343/1447] Meson: Simplify settings setup a bit Also some surrounding code. Change-Id: I9f537a4357ab76295b7cb4f6a69749a0a6b55392 Reviewed-by: Reviewed-by: Christian Stenger --- .../mesonprojectmanager/mesonbuildsystem.cpp | 2 +- .../mesonpluginconstants.h | 1 - .../mesonprojectplugin.cpp | 4 +- .../mesonprojectmanager/ninjabuildstep.cpp | 18 +++--- src/plugins/mesonprojectmanager/settings.cpp | 55 ++++++++----------- src/plugins/mesonprojectmanager/settings.h | 20 ++----- 6 files changed, 40 insertions(+), 60 deletions(-) diff --git a/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp b/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp index 13617fa0140..6d3e5f20c4f 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildsystem.cpp @@ -192,7 +192,7 @@ void MesonBuildSystem::init() bool MesonBuildSystem::parseProject() { QTC_ASSERT(buildConfiguration(), return false); - if (!isSetup(buildConfiguration()->buildDirectory()) && Settings::instance()->autorunMeson.value()) + if (!isSetup(buildConfiguration()->buildDirectory()) && settings().autorunMeson()) return configure(); LEAVE_IF_BUSY(); LOCK(); diff --git a/src/plugins/mesonprojectmanager/mesonpluginconstants.h b/src/plugins/mesonprojectmanager/mesonpluginconstants.h index 995e41cbb59..108c125f502 100644 --- a/src/plugins/mesonprojectmanager/mesonpluginconstants.h +++ b/src/plugins/mesonprojectmanager/mesonpluginconstants.h @@ -18,7 +18,6 @@ const char PARAMETERS_KEY[] = "MesonProjectManager.BuildConfig.Parameters"; // Settings page namespace SettingsPage { -const char GENERAL_ID[] = "A.MesonProjectManager.SettingsPage.General"; const char TOOLS_ID[] = "Z.MesonProjectManager.SettingsPage.Tools"; const char CATEGORY[] = "Z.Meson"; } // namespace SettingsPage diff --git a/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp index f15f65c4afd..87beb589bbd 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp +++ b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp @@ -45,7 +45,7 @@ public: ~MesonProjectPluginPrivate() {} private: - GeneralSettingsPage m_generalSettingsPage; + Settings m_settings; ToolsSettingsPage m_toolslSettingsPage; ToolsSettingsAccessor m_toolsSettings; MesonToolKitAspect m_mesonKitAspect; @@ -60,7 +60,6 @@ private: void saveAll() { m_toolsSettings.saveMesonTools(MesonTools::tools(), ICore::dialogParent()); - Settings::instance()->writeSettings(ICore::settings()); } }; @@ -76,7 +75,6 @@ void MesonProjectPlugin::initialize() ProjectManager::registerProjectType(Constants::Project::MIMETYPE); FileIconProvider::registerIconOverlayForFilename(Constants::Icons::MESON, "meson.build"); FileIconProvider::registerIconOverlayForFilename(Constants::Icons::MESON, "meson_options.txt"); - Settings::instance()->readSettings(ICore::settings()); } } // MesonProjectManager::Internal diff --git a/src/plugins/mesonprojectmanager/ninjabuildstep.cpp b/src/plugins/mesonprojectmanager/ninjabuildstep.cpp index 325056d4918..ac41aeecfaa 100644 --- a/src/plugins/mesonprojectmanager/ninjabuildstep.cpp +++ b/src/plugins/mesonprojectmanager/ninjabuildstep.cpp @@ -44,7 +44,7 @@ NinjaBuildStep::NinjaBuildStep(BuildStepList *bsl, Id id) setUseEnglishOutput(); connect(target(), &ProjectExplorer::Target::parsingFinished, this, &NinjaBuildStep::update); - connect(&Settings::instance()->verboseNinja, &BaseAspect::changed, + connect(&settings().verboseNinja, &BaseAspect::changed, this, &NinjaBuildStep::commandChanged); } @@ -119,17 +119,15 @@ QWidget *NinjaBuildStep::createConfigWidget() // --verbose is only supported since // https://github.com/ninja-build/ninja/commit/bf7517505ad1def03e13bec2b4131399331bc5c4 // TODO check when to switch back to --verbose -Utils::CommandLine NinjaBuildStep::command() +CommandLine NinjaBuildStep::command() { - Utils::CommandLine cmd = [this] { - auto tool = NinjaToolKitAspect::ninjaTool(kit()); - if (tool) - return Utils::CommandLine{tool->exe()}; - return Utils::CommandLine{}; - }(); + CommandLine cmd; + if (auto tool = NinjaToolKitAspect::ninjaTool(kit())) + cmd.setExecutable(tool->exe()); + if (!m_commandArgs.isEmpty()) - cmd.addArgs(m_commandArgs, Utils::CommandLine::RawType::Raw); - if (Settings::instance()->verboseNinja.value()) + cmd.addArgs(m_commandArgs, CommandLine::RawType::Raw); + if (settings().verboseNinja()) cmd.addArg("-v"); cmd.addArg(m_targetName); return cmd; diff --git a/src/plugins/mesonprojectmanager/settings.cpp b/src/plugins/mesonprojectmanager/settings.cpp index 6a211a375a7..e1fe290bc5c 100644 --- a/src/plugins/mesonprojectmanager/settings.cpp +++ b/src/plugins/mesonprojectmanager/settings.cpp @@ -8,13 +8,26 @@ #include -namespace MesonProjectManager { -namespace Internal { +namespace MesonProjectManager::Internal { + +static Settings *s_instance; + +Settings &settings() +{ + return *s_instance; +} Settings::Settings() { + s_instance = this; + setSettingsGroup("MesonProjectManager"); - setAutoApply(false); + + setId("A.MesonProjectManager.SettingsPage.General"); + setDisplayName(Tr::tr("General")); + setDisplayCategory("Meson"); + setCategory(Constants::SettingsPage::CATEGORY); + setCategoryIconPath(Constants::Icons::MESON_BW); autorunMeson.setSettingsKey("meson.autorun"); autorunMeson.setLabelText(Tr::tr("Autorun Meson")); @@ -24,36 +37,16 @@ Settings::Settings() verboseNinja.setLabelText(Tr::tr("Ninja verbose mode")); verboseNinja.setToolTip(Tr::tr("Enables verbose mode by default when invoking Ninja.")); - registerAspect(&autorunMeson); - registerAspect(&verboseNinja); -} - -Settings *Settings::instance() -{ - static Settings m_settings; - return &m_settings; -} - -GeneralSettingsPage::GeneralSettingsPage() -{ - setId(Constants::SettingsPage::GENERAL_ID); - setDisplayName(Tr::tr("General")); - setDisplayCategory("Meson"); - setCategory(Constants::SettingsPage::CATEGORY); - setCategoryIconPath(Constants::Icons::MESON_BW); - setSettings(Settings::instance()); - - setLayouter([](QWidget *widget) { - Settings &s = *Settings::instance(); + setLayouter([this] { using namespace Layouting; - - Column { - s.autorunMeson, - s.verboseNinja, + return Column { + autorunMeson, + verboseNinja, st, - }.attachTo(widget); + }; }); + + readSettings(); } -} // namespace Internal -} // namespace MesonProjectManager +} // MesonProjectManager::Internal diff --git a/src/plugins/mesonprojectmanager/settings.h b/src/plugins/mesonprojectmanager/settings.h index 2e23d0f4482..34c2e9e97d9 100644 --- a/src/plugins/mesonprojectmanager/settings.h +++ b/src/plugins/mesonprojectmanager/settings.h @@ -7,25 +7,17 @@ #include -namespace MesonProjectManager { -namespace Internal { +namespace MesonProjectManager::Internal { -class Settings : public Utils::AspectContainer +class Settings : public Core::PagedSettings { public: Settings(); - static Settings *instance(); - - Utils::BoolAspect autorunMeson; - Utils::BoolAspect verboseNinja; + Utils::BoolAspect autorunMeson{this}; + Utils::BoolAspect verboseNinja{this}; }; -class GeneralSettingsPage final : public Core::IOptionsPage -{ -public: - GeneralSettingsPage(); -}; +Settings &settings(); -} // namespace Internal -} // namespace MesonProjectManager +} // MesonProjectManager::Internal From ba004e409f3f2dec9725317357fb0dddc987132c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 25 May 2023 15:40:40 +0200 Subject: [PATCH 1344/1447] QMake: Fix build device root Fixes: QTCREATORBUG-29140 Change-Id: I85a7ea54c9006079c1c270ded0a5bd9848db1408 Reviewed-by: Reviewed-by: hjk --- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 1a180bf833b..d7aefb50b8b 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1452,8 +1453,12 @@ void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const QString QmakeBuildSystem::deviceRoot() const { - if (projectFilePath().needsDevice()) - return projectFilePath().withNewPath("/").toFSPathString(); + IDeviceConstPtr device = BuildDeviceKitAspect::device(target()->kit()); + QTC_ASSERT(device, return {}); + FilePath deviceRoot = device->rootPath(); + if (deviceRoot.needsDevice()) + return deviceRoot.toFSPathString(); + return {}; } From 98b49735440f4d36fc68b7b8503173929a4fe36d Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 12:53:21 +0200 Subject: [PATCH 1345/1447] Beautifier: Use FilePath, not FilePathAspect for documentation file That's not meant to be saved. Change-Id: I04ab2ff1fb3abf7f01eeaa61f5bcf9792e4c637a Reviewed-by: Christian Stenger --- src/plugins/beautifier/abstractsettings.cpp | 2 +- src/plugins/beautifier/abstractsettings.h | 3 ++- .../beautifier/artisticstyle/artisticstylesettings.cpp | 6 +++--- src/plugins/beautifier/clangformat/clangformatsettings.cpp | 6 +++--- src/plugins/beautifier/uncrustify/uncrustifysettings.cpp | 6 +++--- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp index 9b340cf9b37..1b4ff3aa10e 100644 --- a/src/plugins/beautifier/abstractsettings.cpp +++ b/src/plugins/beautifier/abstractsettings.cpp @@ -297,7 +297,7 @@ void AbstractSettings::read() void AbstractSettings::readDocumentation() { - const FilePath filename = documentationFilePath(); + const FilePath filename = documentationFilePath; if (filename.isEmpty()) { BeautifierPlugin::showError(Tr::tr("No documentation file specified.")); return; diff --git a/src/plugins/beautifier/abstractsettings.h b/src/plugins/beautifier/abstractsettings.h index 6b34baf58be..8e9ceea931d 100644 --- a/src/plugins/beautifier/abstractsettings.h +++ b/src/plugins/beautifier/abstractsettings.h @@ -51,7 +51,8 @@ public: Utils::FilePathAspect command{this}; Utils::StringAspect supportedMimeTypes{this}; - Utils::FilePathAspect documentationFilePath; // Intentionally not saved. + + Utils::FilePath documentationFilePath; QVersionNumber version() const; diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp index 36bd39c3c55..415d4ab20d6 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp @@ -59,11 +59,11 @@ ArtisticStyleSettings::ArtisticStyleSettings() customStyle.setSettingsKey("customStyle"); - documentationFilePath.setFilePath( + documentationFilePath = Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME) .pathAppended(Beautifier::Constants::DOCUMENTATION_DIRNAME) .pathAppended(SETTINGS_NAME) - .stringAppended(".xml")); + .stringAppended(".xml"); read(); } @@ -77,7 +77,7 @@ void ArtisticStyleSettings::createDocumentationFile() const if (process.result() != ProcessResult::FinishedWithSuccess) return; - QFile file(documentationFilePath().toFSPathString()); + QFile file(documentationFilePath.toFSPathString()); const QFileInfo fi(file); if (!fi.exists()) fi.dir().mkpath(fi.absolutePath()); diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.cpp b/src/plugins/beautifier/clangformat/clangformatsettings.cpp index 40477b6ca82..6a31667edb7 100644 --- a/src/plugins/beautifier/clangformat/clangformatsettings.cpp +++ b/src/plugins/beautifier/clangformat/clangformatsettings.cpp @@ -63,16 +63,16 @@ ClangFormatSettings::ClangFormatSettings() customStyle.setSettingsKey("customStyle"); - documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME) + documentationFilePath = Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME) .pathAppended(Constants::DOCUMENTATION_DIRNAME) - .pathAppended(SETTINGS_NAME).stringAppended(".xml")); + .pathAppended(SETTINGS_NAME).stringAppended(".xml"); read(); } void ClangFormatSettings::createDocumentationFile() const { - QFile file(documentationFilePath().toFSPathString()); + QFile file(documentationFilePath.toFSPathString()); const QFileInfo fi(file); if (!fi.exists()) fi.dir().mkpath(fi.absolutePath()); diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp index 823471681fc..1aa9e8502c6 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp @@ -66,9 +66,9 @@ UncrustifySettings::UncrustifySettings() specificConfigFile.setExpectedKind(Utils::PathChooser::File); specificConfigFile.setPromptDialogFilter(Tr::tr("Uncrustify file (*.cfg)")); - documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME) + documentationFilePath = Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME) .pathAppended(Constants::DOCUMENTATION_DIRNAME) - .pathAppended(SETTINGS_NAME).stringAppended(".xml")); + .pathAppended(SETTINGS_NAME).stringAppended(".xml"); read(); } @@ -82,7 +82,7 @@ void UncrustifySettings::createDocumentationFile() const if (process.result() != ProcessResult::FinishedWithSuccess) return; - QFile file(documentationFilePath().toFSPathString()); + QFile file(documentationFilePath.toFSPathString()); const QFileInfo fi(file); if (!fi.exists()) fi.dir().mkpath(fi.absolutePath()); From aa63d5384f271ce25132065c5c30183f39a48ba4 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 26 May 2023 12:13:30 +0200 Subject: [PATCH 1346/1447] Meson: Merge toolsettingspagewidget file pair into toolssettingspage.cpp An implementation detail. Change-Id: I35bee5e0d27f7c6e6b8c69d1703ad21d86cc1694 Reviewed-by: Reviewed-by: Christian Stenger --- .../mesonprojectmanager/CMakeLists.txt | 2 - .../mesonprojectmanager.qbs | 2 - .../mesonprojectmanager/toolssettingspage.cpp | 117 +++++++++++++++++- .../mesonprojectmanager/toolssettingspage.h | 6 +- .../toolssettingswidget.cpp | 107 ---------------- .../mesonprojectmanager/toolssettingswidget.h | 40 ------ 6 files changed, 115 insertions(+), 159 deletions(-) delete mode 100644 src/plugins/mesonprojectmanager/toolssettingswidget.cpp delete mode 100644 src/plugins/mesonprojectmanager/toolssettingswidget.h diff --git a/src/plugins/mesonprojectmanager/CMakeLists.txt b/src/plugins/mesonprojectmanager/CMakeLists.txt index d4d7420d7b0..3c541a1219e 100644 --- a/src/plugins/mesonprojectmanager/CMakeLists.txt +++ b/src/plugins/mesonprojectmanager/CMakeLists.txt @@ -75,8 +75,6 @@ add_qtc_plugin(MesonProjectManager toolssettingsaccessor.h toolssettingspage.cpp toolssettingspage.h - toolssettingswidget.cpp - toolssettingswidget.h tooltreeitem.cpp tooltreeitem.h toolwrapper.cpp diff --git a/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs index 9de8b4ccde9..c721ab2d207 100644 --- a/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs +++ b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs @@ -95,8 +95,6 @@ Project { "toolssettingsaccessor.h", "toolssettingspage.cpp", "toolssettingspage.h", - "toolssettingswidget.cpp", - "toolssettingswidget.h", "tooltreeitem.cpp", "tooltreeitem.h", "versionhelper.h", diff --git a/src/plugins/mesonprojectmanager/toolssettingspage.cpp b/src/plugins/mesonprojectmanager/toolssettingspage.cpp index 4ac576b365e..67ecd99aacc 100644 --- a/src/plugins/mesonprojectmanager/toolssettingspage.cpp +++ b/src/plugins/mesonprojectmanager/toolssettingspage.cpp @@ -5,10 +5,120 @@ #include "mesonpluginconstants.h" #include "mesonprojectmanagertr.h" -#include "toolssettingswidget.h" +#include "toolitemsettings.h" +#include "toolsmodel.h" +#include "tooltreeitem.h" + +#include +#include + +#include +#include +#include + +using namespace Utils; + +namespace MesonProjectManager::Internal { + +class ToolsSettingsWidget final : public Core::IOptionsPageWidget +{ +public: + ToolsSettingsWidget(); + +private: + void apply() final { m_model.apply(); } + + void cloneMesonTool(); + void removeMesonTool(); + void currentMesonToolChanged(const QModelIndex &newCurrent); + + ToolsModel m_model; + ToolItemSettings *m_itemSettings; + ToolTreeItem *m_currentItem = nullptr; + + QTreeView *m_mesonList; + DetailsWidget *m_mesonDetails; + QPushButton *m_cloneButton; + QPushButton *m_removeButton; +}; + +ToolsSettingsWidget::ToolsSettingsWidget() +{ + m_mesonList = new QTreeView; + m_mesonList->setModel(&m_model); + m_mesonList->expandAll(); + m_mesonList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + m_mesonList->header()->setSectionResizeMode(1, QHeaderView::Stretch); + + m_itemSettings = new ToolItemSettings; + + m_mesonDetails = new DetailsWidget; + m_mesonDetails->setState(DetailsWidget::NoSummary); + m_mesonDetails->setVisible(false); + m_mesonDetails->setWidget(m_itemSettings); + + auto addButton = new QPushButton(Tr::tr("Add")); + + m_cloneButton = new QPushButton(Tr::tr("Clone")); + m_cloneButton->setEnabled(false); + + m_removeButton = new QPushButton(Tr::tr("Remove")); + m_removeButton->setEnabled(false); + + auto makeDefaultButton = new QPushButton(Tr::tr("Make Default")); + makeDefaultButton->setEnabled(false); + makeDefaultButton->setVisible(false); + makeDefaultButton->setToolTip(Tr::tr("Set as the default Meson executable to use " + "when creating a new kit or when no value is set.")); + + using namespace Layouting; + + Row { + Column { + m_mesonList, + m_mesonDetails + }, + Column { + addButton, + m_cloneButton, + m_removeButton, + makeDefaultButton, + st + } + }.attachTo(this); + + connect(m_mesonList->selectionModel(), &QItemSelectionModel::currentChanged, + this, &ToolsSettingsWidget::currentMesonToolChanged); + connect(m_itemSettings, &ToolItemSettings::applyChanges, &m_model, &ToolsModel::updateItem); + + connect(addButton, &QPushButton::clicked, &m_model, &ToolsModel::addMesonTool); + connect(m_cloneButton, &QPushButton::clicked, this, &ToolsSettingsWidget::cloneMesonTool); + connect(m_removeButton, &QPushButton::clicked, this, &ToolsSettingsWidget::removeMesonTool); +} + +void ToolsSettingsWidget::cloneMesonTool() +{ + if (m_currentItem) { + auto newItem = m_model.cloneMesonTool(m_currentItem); + m_mesonList->setCurrentIndex(newItem->index()); + } +} + +void ToolsSettingsWidget::removeMesonTool() +{ + if (m_currentItem) + m_model.removeMesonTool(m_currentItem); +} + +void ToolsSettingsWidget::currentMesonToolChanged(const QModelIndex &newCurrent) +{ + m_currentItem = m_model.mesoneToolTreeItem(newCurrent); + m_itemSettings->load(m_currentItem); + m_mesonDetails->setVisible(m_currentItem); + m_cloneButton->setEnabled(m_currentItem); + m_removeButton->setEnabled(m_currentItem && !m_currentItem->isAutoDetected()); +} -namespace MesonProjectManager { -namespace Internal { ToolsSettingsPage::ToolsSettingsPage() { @@ -18,5 +128,4 @@ ToolsSettingsPage::ToolsSettingsPage() setWidgetCreator([]() { return new ToolsSettingsWidget; }); } -} // namespace Internal } // namespace MesonProjectManager diff --git a/src/plugins/mesonprojectmanager/toolssettingspage.h b/src/plugins/mesonprojectmanager/toolssettingspage.h index de62b94d918..815120c30f0 100644 --- a/src/plugins/mesonprojectmanager/toolssettingspage.h +++ b/src/plugins/mesonprojectmanager/toolssettingspage.h @@ -5,8 +5,7 @@ #include -namespace MesonProjectManager { -namespace Internal { +namespace MesonProjectManager::Internal { class ToolsSettingsPage final : public Core::IOptionsPage { @@ -14,5 +13,4 @@ public: ToolsSettingsPage(); }; -} // namespace Internal -} // namespace MesonProjectManager +} // MesonProjectManager::Internal diff --git a/src/plugins/mesonprojectmanager/toolssettingswidget.cpp b/src/plugins/mesonprojectmanager/toolssettingswidget.cpp deleted file mode 100644 index ef30d79ae43..00000000000 --- a/src/plugins/mesonprojectmanager/toolssettingswidget.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) 2020 Alexis Jeandet. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "toolssettingswidget.h" - -#include "mesonprojectmanagertr.h" -#include "toolsmodel.h" -#include "tooltreeitem.h" - -#include -#include - -#include -#include -#include - -using namespace Utils; - -namespace MesonProjectManager::Internal { - -ToolsSettingsWidget::ToolsSettingsWidget() - : Core::IOptionsPageWidget() -{ - m_mesonList = new QTreeView; - m_mesonList->setModel(&m_model); - m_mesonList->expandAll(); - m_mesonList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); - m_mesonList->header()->setSectionResizeMode(1, QHeaderView::Stretch); - - m_itemSettings = new ToolItemSettings; - - m_mesonDetails = new DetailsWidget; - m_mesonDetails->setState(DetailsWidget::NoSummary); - m_mesonDetails->setVisible(false); - m_mesonDetails->setWidget(m_itemSettings); - - auto addButton = new QPushButton(Tr::tr("Add")); - - m_cloneButton = new QPushButton(Tr::tr("Clone")); - m_cloneButton->setEnabled(false); - - m_removeButton = new QPushButton(Tr::tr("Remove")); - m_removeButton->setEnabled(false); - - auto makeDefaultButton = new QPushButton(Tr::tr("Make Default")); - makeDefaultButton->setEnabled(false); - makeDefaultButton->setVisible(false); - makeDefaultButton->setToolTip(Tr::tr("Set as the default Meson executable to use " - "when creating a new kit or when no value is set.")); - - using namespace Layouting; - - Row { - Column { - m_mesonList, - m_mesonDetails - }, - Column { - addButton, - m_cloneButton, - m_removeButton, - makeDefaultButton, - st - } - }.attachTo(this); - - connect(m_mesonList->selectionModel(), &QItemSelectionModel::currentChanged, - this, &ToolsSettingsWidget::currentMesonToolChanged); - connect(m_itemSettings, &ToolItemSettings::applyChanges, &m_model, &ToolsModel::updateItem); - - connect(addButton, &QPushButton::clicked, &m_model, &ToolsModel::addMesonTool); - connect(m_cloneButton, &QPushButton::clicked, this, &ToolsSettingsWidget::cloneMesonTool); - connect(m_removeButton, &QPushButton::clicked, this, &ToolsSettingsWidget::removeMesonTool); -} - -ToolsSettingsWidget::~ToolsSettingsWidget() = default; - -void ToolsSettingsWidget::cloneMesonTool() -{ - if (m_currentItem) { - auto newItem = m_model.cloneMesonTool(m_currentItem); - m_mesonList->setCurrentIndex(newItem->index()); - } -} - -void ToolsSettingsWidget::removeMesonTool() -{ - if (m_currentItem) { - m_model.removeMesonTool(m_currentItem); - } -} - -void ToolsSettingsWidget::currentMesonToolChanged(const QModelIndex &newCurrent) -{ - m_currentItem = m_model.mesoneToolTreeItem(newCurrent); - m_itemSettings->load(m_currentItem); - m_mesonDetails->setVisible(m_currentItem); - m_cloneButton->setEnabled(m_currentItem); - m_removeButton->setEnabled(m_currentItem && !m_currentItem->isAutoDetected()); -} - -void ToolsSettingsWidget::apply() -{ - m_model.apply(); -} - -} // MesonProjectManager::Internal diff --git a/src/plugins/mesonprojectmanager/toolssettingswidget.h b/src/plugins/mesonprojectmanager/toolssettingswidget.h deleted file mode 100644 index 1c39b7460ab..00000000000 --- a/src/plugins/mesonprojectmanager/toolssettingswidget.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2020 Alexis Jeandet. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "toolitemsettings.h" -#include "toolsmodel.h" - -#include - -namespace Utils { class DetailsWidget; } - -namespace MesonProjectManager::Internal { - -class ToolTreeItem; - -class ToolsSettingsWidget final : public Core::IOptionsPageWidget -{ -public: - explicit ToolsSettingsWidget(); - ~ToolsSettingsWidget(); - -private: - void apply() final; - - void cloneMesonTool(); - void removeMesonTool(); - void currentMesonToolChanged(const QModelIndex &newCurrent); - - ToolsModel m_model; - ToolItemSettings *m_itemSettings; - ToolTreeItem *m_currentItem = nullptr; - - QTreeView *m_mesonList; - Utils::DetailsWidget *m_mesonDetails; - QPushButton *m_cloneButton; - QPushButton *m_removeButton; -}; - -} // MesonProjectManager::Internal From 047814c6daea2d5b8afa833e5bdb7e4a32279bf6 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 30 May 2023 14:08:45 +0200 Subject: [PATCH 1347/1447] Utils: fix likelyContainsLink for markdown This allows us to also port the link in the resource tooltip to markdown. Change-Id: Iec0e19ff68db76290139e457694485222f0a38f3 Reviewed-by: Eike Ziller --- src/libs/utils/tooltip/tips.cpp | 12 ++++++++---- .../cppeditor/resourcepreviewhoverhandler.cpp | 4 +--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/tooltip/tips.cpp b/src/libs/utils/tooltip/tips.cpp index ea20c735d80..180b8f960f2 100644 --- a/src/libs/utils/tooltip/tips.cpp +++ b/src/libs/utils/tooltip/tips.cpp @@ -133,9 +133,13 @@ TextTip::TextTip(QWidget *parent) : TipLabel(parent) setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, nullptr, this) / 255.0); } -static bool likelyContainsLink(const QString &s) +static bool likelyContainsLink(const QString &s, const Qt::TextFormat &format) { - return s.contains(QLatin1String("href"), Qt::CaseInsensitive); + if (s.contains(QLatin1String("href"), Qt::CaseInsensitive)) + return true; + if (format == Qt::MarkdownText) + return s.contains("]("); + return false; } void TextTip::setContent(const QVariant &content) @@ -148,13 +152,13 @@ void TextTip::setContent(const QVariant &content) m_format = item.second; } - bool containsLink = likelyContainsLink(m_text); + bool containsLink = likelyContainsLink(m_text, m_format); setOpenExternalLinks(containsLink); } bool TextTip::isInteractive() const { - return likelyContainsLink(m_text); + return likelyContainsLink(m_text, m_format); } void TextTip::configure(const QPoint &pos) diff --git a/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp index 8654b2c35d1..6c282b879cc 100644 --- a/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp +++ b/src/plugins/cppeditor/resourcepreviewhoverhandler.cpp @@ -181,9 +181,7 @@ QString ResourcePreviewHoverHandler::makeTooltip() const const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_resPath); if (mimeType.name().startsWith("image", Qt::CaseInsensitive)) ret += QString("![image](%1) \n").arg(m_resPath); - - ret += QString("%2") - .arg(m_resPath, QDir::toNativeSeparators(m_resPath)); + ret += QString("[%1](%2)").arg(QDir::toNativeSeparators(m_resPath), m_resPath); return ret; } From 6a016ff014709257e477e7635362bd7357e8541c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 17:00:35 +0200 Subject: [PATCH 1348/1447] Issues pane: Fix filtering If the parent is visible, we always want to show the child as well. The previous implementation would always assume the row number to be a top-level entry, leading to seemingly random behavior if any sort of filtering was active. Amends 778d7a981995898a3afd782bfc199d032d4a80f0. Change-Id: I354c1b07929c45034a7d24b4c31f986ddd01c877 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/taskmodel.cpp | 3 ++- src/plugins/projectexplorer/taskwindow.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/taskmodel.cpp b/src/plugins/projectexplorer/taskmodel.cpp index c05614a445f..80280a5595e 100644 --- a/src/plugins/projectexplorer/taskmodel.cpp +++ b/src/plugins/projectexplorer/taskmodel.cpp @@ -409,7 +409,8 @@ void TaskFilterModel::updateFilterProperties( bool TaskFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { - Q_UNUSED(source_parent) + if (source_parent.isValid()) + return true; return filterAcceptsTask(taskModel()->tasks().at(source_row)); } diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index eb4b9de8ca5..8bb8fa98e2f 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -169,6 +169,7 @@ TaskWindow::TaskWindow() : d(std::make_unique()) { d->m_model = new Internal::TaskModel(this); d->m_filter = new Internal::TaskFilterModel(d->m_model); + d->m_filter->setAutoAcceptChildRows(true); auto agg = new Aggregation::Aggregate; agg->add(&d->m_treeView); From e0a81731e66f2daf47156da5bf695e973c7aa862 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 26 May 2023 10:18:39 +0200 Subject: [PATCH 1349/1447] TaskView: Fix scroll mode Change-Id: I9bcb3315d545d4d32e67a6766c43324d9807ef1d Reviewed-by: Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/projectexplorer/taskwindow.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 8bb8fa98e2f..95e15ec5eb7 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -92,7 +92,7 @@ namespace Internal { class TaskView : public TreeView { public: - TaskView() { setMouseTracking(true); } + TaskView(); void resizeColumns(); private: @@ -660,6 +660,12 @@ bool TaskDelegate::needsSpecialHandling(const QModelIndex &index) const return sourceIndex.internalId(); } +TaskView::TaskView() +{ + setMouseTracking(true); + setVerticalScrollMode(ScrollPerPixel); +} + void TaskView::resizeColumns() { setColumnWidth(0, width() * 0.85); From efdb67bf900d19cbd26ae31d6f24782d5d15333e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 16 May 2023 16:07:58 +0200 Subject: [PATCH 1350/1447] ActionManager: Add special context that disables more specific contexts This usually is not a good idea, but might be useful for the embedded terminal widgets. Change-Id: Ifeeb47a38596ee789a503f3c7030da5a464569c5 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/actionmanager/command.cpp | 6 ++++-- src/plugins/coreplugin/coreconstants.h | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp index ab78bf50892..23b398791f2 100644 --- a/src/plugins/coreplugin/actionmanager/command.cpp +++ b/src/plugins/coreplugin/actionmanager/command.cpp @@ -347,8 +347,10 @@ void Internal::CommandPrivate::setCurrentContext(const Context &context) m_context = context; QAction *currentAction = nullptr; - for (int i = 0; i < m_context.size(); ++i) { - if (QAction *a = m_contextActionMap.value(m_context.at(i), nullptr)) { + for (const Id &id : std::as_const(m_context)) { + if (id == Constants::C_GLOBAL_CUTOFF) + break; + if (QAction *a = m_contextActionMap.value(id, nullptr)) { currentAction = a; break; } diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index 0b4831e51b6..513d02eb6ee 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -46,6 +46,11 @@ const char C_EDITORMANAGER[] = "Core.EditorManager"; const char C_NAVIGATION_PANE[] = "Core.NavigationPane"; const char C_PROBLEM_PANE[] = "Core.ProblemPane"; const char C_GENERAL_OUTPUT_PANE[] = "Core.GeneralOutputPane"; +// Special context that leads to all "more specific" contexts to be ignored. +// If you use Context(mycontextId, C_GLOBAL_CUTOFF) for a widget that has focus, +// mycontextId will be enabled but the contexts for all parent widgets, the manually added +// "additional" contexts, and the global context will be turned off. +const char C_GLOBAL_CUTOFF[] = "Global Cutoff"; // Default editor kind const char K_DEFAULT_TEXT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::Core", "Plain Text Editor"); From ea108f48572806a6a8fb09cf9a7877a316c59253 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 25 May 2023 15:18:12 +0200 Subject: [PATCH 1351/1447] Editor: Adjust remaining usages of BaseTextEditor:convertPosition amends 9bb126c0d6ff46bd00950261eb3eb9205f1d3879 Change-Id: I42b96f1f7364f75da88eccd7a86fc25b9cd1499d Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/classview/classviewmanager.cpp | 2 +- src/plugins/cmakeprojectmanager/cmakeeditor.cpp | 2 +- .../cppeditor/followsymbol_switchmethoddecldef_test.cpp | 1 + src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp | 3 +-- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/classview/classviewmanager.cpp b/src/plugins/classview/classviewmanager.cpp index 7f4eeb955c6..90c834a6216 100644 --- a/src/plugins/classview/classviewmanager.cpp +++ b/src/plugins/classview/classviewmanager.cpp @@ -378,7 +378,7 @@ void Manager::gotoLocations(const QList &list) int line; int column; textEditor->convertPosition(textEditor->position(), &line, &column); - const SymbolLocation current(filePath, line, column); + const SymbolLocation current(filePath, line, column + 1); if (auto it = locations.constFind(current), end = locations.constEnd(); it != end) { // we already are at the symbol, cycle to next location ++it; diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp index 3411fd85b58..5193661e57b 100644 --- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp @@ -157,7 +157,7 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor, // find the beginning of a filename QString buffer; - int beginPos = column - 1; + int beginPos = column; while (beginPos >= 0) { if (isValidFileNameChar(block, beginPos)) { buffer.prepend(block.at(beginPos)); diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 90ddfbdf905..31d69f7363d 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -414,6 +414,7 @@ F2TestCase::F2TestCase(CppEditorAction action, } else { currentTextEditor->convertPosition(targetTestFile->m_targetCursorPosition, &expectedLine, &expectedColumn); + ++expectedColumn; if (useClangd && (tag == "classDestructor" || tag == "fromDestructorDefinitionSymbol" || tag == "fromDestructorBody")) { --expectedColumn; // clangd goes before the ~, built-in code model after diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index d89393909ba..61493bf05c3 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -357,8 +357,7 @@ void QmakeProjectManagerPluginPrivate::addLibraryImpl(const FilePath &filePath, // add extra \n in case the last line is not empty int line, column; editor->convertPosition(endOfDoc, &line, &column); - const int positionInBlock = column - 1; - if (!editor->textAt(endOfDoc - positionInBlock, positionInBlock).simplified().isEmpty()) + if (!editor->textAt(endOfDoc - column, column).simplified().isEmpty()) snippet = QLatin1Char('\n') + snippet; editor->insert(snippet); From 7625633ff2ade17135898f560b4dc9262b887e74 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 26 May 2023 11:15:45 +0200 Subject: [PATCH 1352/1447] TaskTree tests: Get rid of future synchronizer The future synchronizer may abuse the subsequent test invocation as it may still have spinning threads from the previous test run. As all the started tasks should finish quickly on cancel, we drop putting the canceled futures into the synchronizer. Instead, we blocking wait for them to finish. In this way, when the subsequent test is invoked, we should expect the all available threads are ready to be used. Change-Id: I9bb022b8c0950d27cb323ff83bf18148829160b3 Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns Reviewed-by: hjk Reviewed-by: --- tests/auto/solutions/tasking/tst_tasking.cpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 17335d29f41..7564435c497 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -55,8 +55,6 @@ private: int CustomStorage::s_count = 0; static const char s_taskIdProperty[] = "__taskId"; -static FutureSynchronizer *s_futureSynchronizer = nullptr; - struct TestData { TreeStorage storage; Group root; @@ -70,28 +68,13 @@ class tst_Tasking : public QObject Q_OBJECT private slots: - void initTestCase(); - void validConstructs(); // compile test void testTree_data(); void testTree(); void storageOperators(); void storageDestructor(); - - void cleanupTestCase(); }; -void tst_Tasking::initTestCase() -{ - s_futureSynchronizer = new FutureSynchronizer; -} - -void tst_Tasking::cleanupTestCase() -{ - delete s_futureSynchronizer; - s_futureSynchronizer = nullptr; -} - void tst_Tasking::validConstructs() { const Group task { @@ -208,7 +191,6 @@ auto setupBarrierAdvance(const TreeStorage &storage, const SharedBarrierType &barrier, int taskId) { return [storage, barrier, taskId](Async &async) { - async.setFutureSynchronizer(s_futureSynchronizer); async.setConcurrentCallData(reportAndSleep); async.setProperty(s_taskIdProperty, taskId); storage->m_log.append({taskId, Handler::Setup}); @@ -232,7 +214,6 @@ void tst_Tasking::testTree_data() const auto setupTaskHelper = [storage](TestTask &task, int taskId, bool success = true, std::chrono::milliseconds sleep = 0ms) { - task.setFutureSynchronizer(s_futureSynchronizer); task.setConcurrentCallData(runTask, success, sleep); task.setProperty(s_taskIdProperty, taskId); storage->m_log.append({taskId, Handler::Setup}); @@ -1668,7 +1649,6 @@ void tst_Tasking::storageDestructor() { TreeStorage storage; const auto setupSleepingTask = [](TestTask &task) { - task.setFutureSynchronizer(s_futureSynchronizer); task.setConcurrentCallData(runTask, true, 1000ms); }; const Group root { From d69c3cec7d7c9a3ef95e8bdb0f17d2345879fe3f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 27 May 2023 17:20:40 +0200 Subject: [PATCH 1353/1447] TaskTree tests: De-utils-ize TaskTree tests Make the TaskTree tests dependent only on Tasking lib. Introduce simple Timeout and Delay tasks for tests. Using Timeout and Delay has a big advantage for these tests, since e.g. when scheduling two parallel tasks with the same timeout, we can expect the proper order in which they finish. With AsyncTask it wasn't possible. Now, the tests should be much more reliable and shouldn't exibit flakiness anymore. Use TickAndDone for Barrier tests. Limit the tests' execution time from ~100ms into ~30ms. Change-Id: Ifa08fd62c1a2759a877231c2220e353c1a26364f Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns --- tests/auto/solutions/tasking/CMakeLists.txt | 2 +- tests/auto/solutions/tasking/tasking.qbs | 2 +- tests/auto/solutions/tasking/tst_tasking.cpp | 1050 ++++++++++-------- 3 files changed, 564 insertions(+), 490 deletions(-) diff --git a/tests/auto/solutions/tasking/CMakeLists.txt b/tests/auto/solutions/tasking/CMakeLists.txt index 534d215ccb1..a425250a5a9 100644 --- a/tests/auto/solutions/tasking/CMakeLists.txt +++ b/tests/auto/solutions/tasking/CMakeLists.txt @@ -1,4 +1,4 @@ add_qtc_test(tst_solutions_tasking - DEPENDS Utils + DEPENDS Tasking SOURCES tst_tasking.cpp ) diff --git a/tests/auto/solutions/tasking/tasking.qbs b/tests/auto/solutions/tasking/tasking.qbs index 173c1fc5752..f099edb370c 100644 --- a/tests/auto/solutions/tasking/tasking.qbs +++ b/tests/auto/solutions/tasking/tasking.qbs @@ -1,7 +1,7 @@ QtcAutotest { name: "Tasking autotest" - Depends { name: "Utils" } + Depends { name: "Tasking" } files: "tst_tasking.cpp" } diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 7564435c497..e3f7a80ed5b 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -1,21 +1,28 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include - -#include +#include +#include #include -#include +using namespace std::chrono; +using namespace std::chrono_literals; -using namespace std::literals::chrono_literals; - -using namespace Utils; using namespace Tasking; -using TestTask = Async; -using Test = AsyncTask; +template +class TASKING_EXPORT DurationTaskAdapter : public TaskAdapter +{ +public: + DurationTaskAdapter() { *task() = std::chrono::milliseconds{0}; } + void start() final { QTimer::singleShot(*task(), this, [this] { emit done(SuccessOnDone); }); } +}; + +TASKING_DECLARE_TASK(SuccessTask, DurationTaskAdapter); +TASKING_DECLARE_TASK(FailingTask, DurationTaskAdapter); + +using TaskObject = milliseconds; namespace PrintableEnums { @@ -79,9 +86,9 @@ void tst_Tasking::validConstructs() { const Group task { parallel, - Test([](TestTask &) {}, [](const TestTask &) {}), - Test([](TestTask &) {}, [](const TestTask &) {}), - Test([](TestTask &) {}, [](const TestTask &) {}) + SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), + SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), + SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}) }; const Group group1 { @@ -92,18 +99,18 @@ void tst_Tasking::validConstructs() parallel, Group { parallel, - Test([](TestTask &) {}, [](const TestTask &) {}), + SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), Group { parallel, - Test([](TestTask &) {}, [](const TestTask &) {}), + SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), Group { parallel, - Test([](TestTask &) {}, [](const TestTask &) {}) + SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}) } }, Group { parallel, - Test([](TestTask &) {}, [](const TestTask &) {}), + SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), onGroupDone([] {}) } }, @@ -112,32 +119,32 @@ void tst_Tasking::validConstructs() onGroupError([] {}) }; - const auto setupHandler = [](TestTask &) {}; - const auto doneHandler = [](const TestTask &) {}; - const auto errorHandler = [](const TestTask &) {}; + const auto setupHandler = [](TaskObject &) {}; + const auto doneHandler = [](const TaskObject &) {}; + const auto errorHandler = [](const TaskObject &) {}; // Not fluent interface const Group task2 { parallel, - Test(setupHandler), - Test(setupHandler, doneHandler), - Test(setupHandler, doneHandler, errorHandler), + SuccessTask(setupHandler), + SuccessTask(setupHandler, doneHandler), + SuccessTask(setupHandler, doneHandler, errorHandler), // need to explicitly pass empty handler for done - Test(setupHandler, {}, errorHandler) + SuccessTask(setupHandler, {}, errorHandler) }; // Fluent interface const Group fluent { parallel, - Test().onSetup(setupHandler), - Test().onSetup(setupHandler).onDone(doneHandler), - Test().onSetup(setupHandler).onDone(doneHandler).onError(errorHandler), + SuccessTask().onSetup(setupHandler), + SuccessTask().onSetup(setupHandler).onDone(doneHandler), + SuccessTask().onSetup(setupHandler).onDone(doneHandler).onError(errorHandler), // possible to skip the empty done - Test().onSetup(setupHandler).onError(errorHandler), + SuccessTask().onSetup(setupHandler).onError(errorHandler), // possible to set handlers in a different order - Test().onError(errorHandler).onDone(doneHandler).onSetup(setupHandler), + SuccessTask().onError(errorHandler).onDone(doneHandler).onSetup(setupHandler), }; @@ -168,42 +175,53 @@ void tst_Tasking::validConstructs() #endif } -static void runTask(QPromise &promise, bool success, std::chrono::milliseconds sleep) +class TickAndDone : public QObject { - QDeadlineTimer deadline(sleep); - while (!deadline.hasExpired()) { - QThread::msleep(1); - if (promise.isCanceled()) - return; - } - if (!success) - promise.future().cancel(); -} + Q_OBJECT -static void reportAndSleep(QPromise &promise) -{ - promise.addResult(false); - QThread::msleep(5); +public: + void setInterval(const milliseconds &interval) { m_interval = interval; } + void start() { + QTimer::singleShot(0, this, [this] { + emit tick(); + QTimer::singleShot(m_interval, this, &TickAndDone::done); + }); + } + +signals: + void tick(); + void done(); + +private: + milliseconds m_interval; }; -template -auto setupBarrierAdvance(const TreeStorage &storage, - const SharedBarrierType &barrier, int taskId) +class TickAndDoneTaskAdapter : public TaskAdapter { - return [storage, barrier, taskId](Async &async) { - async.setConcurrentCallData(reportAndSleep); - async.setProperty(s_taskIdProperty, taskId); +public: + TickAndDoneTaskAdapter() { connect(task(), &TickAndDone::done, this, + [this] { emit done(true); }); } + void start() final { task()->start(); } +}; + +TASKING_DECLARE_TASK(TickAndDoneTask, TickAndDoneTaskAdapter); + +template +TaskItem createBarrierAdvance(const TreeStorage &storage, + const SharedBarrierType &barrier, int taskId) +{ + return TickAndDoneTask([storage, barrier, taskId](TickAndDone &tickAndDone) { + tickAndDone.setInterval(1ms); storage->m_log.append({taskId, Handler::Setup}); CustomStorage *currentStorage = storage.activeStorage(); Barrier *sharedBarrier = barrier->barrier(); - QObject::connect(&async, &TestTask::resultReadyAt, sharedBarrier, - [currentStorage, sharedBarrier, taskId](int index) { - Q_UNUSED(index) + QObject::connect(&tickAndDone, &TickAndDone::tick, sharedBarrier, + [currentStorage, sharedBarrier, taskId] { currentStorage->m_log.append({taskId, Handler::BarrierAdvance}); sharedBarrier->advance(); }); - }; + }); } void tst_Tasking::testTree_data() @@ -212,101 +230,91 @@ void tst_Tasking::testTree_data() TreeStorage storage; - const auto setupTaskHelper = [storage](TestTask &task, int taskId, bool success = true, - std::chrono::milliseconds sleep = 0ms) { - task.setConcurrentCallData(runTask, success, sleep); - task.setProperty(s_taskIdProperty, taskId); - storage->m_log.append({taskId, Handler::Setup}); + const auto setupTask = [storage](int taskId, milliseconds timeout) { + return [storage, taskId, timeout](TaskObject &taskObject) { + taskObject = timeout; + storage->m_log.append({taskId, Handler::Setup}); + }; }; - const auto setupTask = [setupTaskHelper](int taskId) { - return [=](TestTask &task) { setupTaskHelper(task, taskId); }; - }; - const auto setupFailingTask = [setupTaskHelper](int taskId) { - return [=](TestTask &task) { setupTaskHelper(task, taskId, false); }; - }; - const auto setupSleepingTask = [setupTaskHelper](int taskId, bool success, - std::chrono::milliseconds sleep) { - return [=](TestTask &task) { setupTaskHelper(task, taskId, success, sleep); }; - }; - const auto setupDynamicTask = [setupTaskHelper](int taskId, TaskAction action) { - return [=](TestTask &task) { - setupTaskHelper(task, taskId); + + const auto setupDynamicTask = [storage](int taskId, TaskAction action) { + return [storage, taskId, action](TaskObject &) { + storage->m_log.append({taskId, Handler::Setup}); return action; }; }; - const auto logDone = [storage](const TestTask &task) { - storage->m_log.append({task.property(s_taskIdProperty).toInt(), Handler::Done}); - }; - const auto logError = [storage](const TestTask &task) { - storage->m_log.append({task.property(s_taskIdProperty).toInt(), Handler::Error}); - }; - const auto groupSetup = [storage](int taskId) { - return [=] { storage->m_log.append({taskId, Handler::GroupSetup}); }; - }; - const auto groupDone = [storage](int taskId) { - return [=] { storage->m_log.append({taskId, Handler::GroupDone}); }; - }; - const auto groupError = [storage](int taskId) { - return [=] { storage->m_log.append({taskId, Handler::GroupError}); }; - }; - const auto setupSync = [storage](int taskId) { - return [=] { storage->m_log.append({taskId, Handler::Sync}); }; - }; - const auto setupSyncWithReturn = [storage](int taskId, bool success) { - return [=] { storage->m_log.append({taskId, Handler::Sync}); return success; }; + + const auto setupDone = [storage](int taskId) { + return [storage, taskId](const TaskObject &) { + storage->m_log.append({taskId, Handler::Done}); + }; }; - const auto constructSimpleSequence = [=](WorkflowPolicy policy) { - return Group { - Storage(storage), - workflowPolicy(policy), - Test(setupTask(1), logDone), - Test(setupFailingTask(2), logDone, logError), - Test(setupTask(3), logDone), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + const auto setupError = [storage](int taskId) { + return [storage, taskId](const TaskObject &) { + storage->m_log.append({taskId, Handler::Error}); }; }; - const auto constructDynamicHierarchy = [=](TaskAction taskAction) { - return Group { - Storage(storage), - Group { - Test(setupTask(1), logDone) - }, - Group { - onGroupSetup([=] { return taskAction; }), - Test(setupTask(2), logDone), - Test(setupTask(3), logDone), - Test(setupTask(4), logDone) - }, - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) - }; + + const auto createTask = [storage, setupTask, setupDone, setupError]( + int taskId, bool successTask, milliseconds timeout = 0ms) -> TaskItem { + if (successTask) + return SuccessTask(setupTask(taskId, timeout), setupDone(taskId), setupError(taskId)); + return FailingTask(setupTask(taskId, timeout), setupDone(taskId), setupError(taskId)); + }; + + const auto createSuccessTask = [createTask](int taskId, milliseconds timeout = 0ms) { + return createTask(taskId, true, timeout); + }; + + const auto createFailingTask = [createTask](int taskId, milliseconds timeout = 0ms) { + return createTask(taskId, false, timeout); + }; + + const auto createDynamicTask = [storage, setupDynamicTask, setupDone, setupError]( + int taskId, TaskAction action) { + return SuccessTask(setupDynamicTask(taskId, action), setupDone(taskId), setupError(taskId)); + }; + + const auto groupSetup = [storage](int taskId) { + return onGroupSetup([=] { storage->m_log.append({taskId, Handler::GroupSetup}); }); + }; + const auto groupDone = [storage](int taskId) { + return onGroupDone([=] { storage->m_log.append({taskId, Handler::GroupDone}); }); + }; + const auto groupError = [storage](int taskId) { + return onGroupError([=] { storage->m_log.append({taskId, Handler::GroupError}); }); + }; + const auto createSync = [storage](int taskId) { + return Sync([=] { storage->m_log.append({taskId, Handler::Sync}); }); + }; + const auto createSyncWithReturn = [storage](int taskId, bool success) { + return Sync([=] { storage->m_log.append({taskId, Handler::Sync}); return success; }); }; { const Group root1 { Storage(storage), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + groupDone(0), + groupError(0) }; const Group root2 { Storage(storage), onGroupSetup([] { return TaskAction::Continue; }), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + groupDone(0), + groupError(0) }; const Group root3 { Storage(storage), onGroupSetup([] { return TaskAction::StopWithDone; }), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + groupDone(0), + groupError(0) }; const Group root4 { Storage(storage), onGroupSetup([] { return TaskAction::StopWithError; }), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + groupDone(0), + groupError(0) }; const Log logDone {{0, Handler::GroupDone}}; const Log logError {{0, Handler::GroupError}}; @@ -319,8 +327,8 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Test(setupDynamicTask(1, TaskAction::StopWithDone), logDone, logError), - Test(setupDynamicTask(2, TaskAction::StopWithDone), logDone, logError) + createDynamicTask(1, TaskAction::StopWithDone), + createDynamicTask(2, TaskAction::StopWithDone) }; const Log log {{1, Handler::Setup}, {2, Handler::Setup}}; QTest::newRow("DynamicTaskDone") << TestData{storage, root, log, 2, OnDone::Success}; @@ -329,8 +337,8 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Test(setupDynamicTask(1, TaskAction::StopWithError), logDone, logError), - Test(setupDynamicTask(2, TaskAction::StopWithError), logDone, logError) + createDynamicTask(1, TaskAction::StopWithError), + createDynamicTask(2, TaskAction::StopWithError) }; const Log log {{1, Handler::Setup}}; QTest::newRow("DynamicTaskError") << TestData{storage, root, log, 2, OnDone::Failure}; @@ -339,10 +347,10 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), - Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), - Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError), - Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) + createDynamicTask(1, TaskAction::Continue), + createDynamicTask(2, TaskAction::Continue), + createDynamicTask(3, TaskAction::StopWithError), + createDynamicTask(4, TaskAction::Continue) }; const Log log { {1, Handler::Setup}, @@ -358,10 +366,10 @@ void tst_Tasking::testTree_data() const Group root { parallel, Storage(storage), - Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), - Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), - Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError), - Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) + createDynamicTask(1, TaskAction::Continue), + createDynamicTask(2, TaskAction::Continue), + createDynamicTask(3, TaskAction::StopWithError), + createDynamicTask(4, TaskAction::Continue) }; const Log log { {1, Handler::Setup}, @@ -377,12 +385,12 @@ void tst_Tasking::testTree_data() const Group root { parallel, Storage(storage), - Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), - Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), + createDynamicTask(1, TaskAction::Continue), + createDynamicTask(2, TaskAction::Continue), Group { - Test(setupDynamicTask(3, TaskAction::StopWithError), logDone, logError) + createDynamicTask(3, TaskAction::StopWithError) }, - Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) + createDynamicTask(4, TaskAction::Continue) }; const Log log { {1, Handler::Setup}, @@ -398,16 +406,16 @@ void tst_Tasking::testTree_data() const Group root { parallel, Storage(storage), - Test(setupDynamicTask(1, TaskAction::Continue), logDone, logError), - Test(setupDynamicTask(2, TaskAction::Continue), logDone, logError), + createDynamicTask(1, TaskAction::Continue), + createDynamicTask(2, TaskAction::Continue), Group { onGroupSetup([storage] { storage->m_log.append({0, Handler::GroupSetup}); return TaskAction::StopWithError; }), - Test(setupDynamicTask(3, TaskAction::Continue), logDone, logError) + createDynamicTask(3, TaskAction::Continue) }, - Test(setupDynamicTask(4, TaskAction::Continue), logDone, logError) + createDynamicTask(4, TaskAction::Continue) }; const Log log { {1, Handler::Setup}, @@ -428,23 +436,23 @@ void tst_Tasking::testTree_data() Group { Group { Group { - Test(setupTask(5), logDone, logError), - onGroupSetup(groupSetup(5)), - onGroupDone(groupDone(5)) + createSuccessTask(5), + groupSetup(5), + groupDone(5) }, - onGroupSetup(groupSetup(4)), - onGroupDone(groupDone(4)) + groupSetup(4), + groupDone(4) }, - onGroupSetup(groupSetup(3)), - onGroupDone(groupDone(3)) + groupSetup(3), + groupDone(3) }, - onGroupSetup(groupSetup(2)), - onGroupDone(groupDone(2)) + groupSetup(2), + groupDone(2) }, - onGroupSetup(groupSetup(1)), - onGroupDone(groupDone(1)) + groupSetup(1), + groupDone(1) }, - onGroupDone(groupDone(0)) + groupDone(0) }; const Log log { {1, Handler::GroupSetup}, @@ -465,18 +473,15 @@ void tst_Tasking::testTree_data() } { - const auto logDoneAnonymously = [=](const TestTask &) { - storage->m_log.append({0, Handler::Done}); - }; const Group root { Storage(storage), parallel, - Test(setupTask(1), logDoneAnonymously), - Test(setupTask(2), logDoneAnonymously), - Test(setupTask(3), logDoneAnonymously), - Test(setupTask(4), logDoneAnonymously), - Test(setupTask(5), logDoneAnonymously), - onGroupDone(groupDone(0)) + createSuccessTask(1), + createSuccessTask(2), + createSuccessTask(3), + createSuccessTask(4), + createSuccessTask(5), + groupDone(0) }; const Log log { {1, Handler::Setup}, // Setup order is determined in parallel mode @@ -484,23 +489,23 @@ void tst_Tasking::testTree_data() {3, Handler::Setup}, {4, Handler::Setup}, {5, Handler::Setup}, - {0, Handler::Done}, // Done order isn't determined in parallel mode - {0, Handler::Done}, - {0, Handler::Done}, - {0, Handler::Done}, - {0, Handler::Done}, + {1, Handler::Done}, + {2, Handler::Done}, + {3, Handler::Done}, + {4, Handler::Done}, + {5, Handler::Done}, {0, Handler::GroupDone} }; QTest::newRow("Parallel") << TestData{storage, root, log, 5, OnDone::Success}; } { - auto setupSubTree = [=](TaskTree &taskTree) { + auto setupSubTree = [storage, createSuccessTask](TaskTree &taskTree) { const Group nestedRoot { Storage(storage), - Test(setupTask(2), logDone), - Test(setupTask(3), logDone), - Test(setupTask(4), logDone) + createSuccessTask(2), + createSuccessTask(3), + createSuccessTask(4) }; taskTree.setupRoot(nestedRoot); CustomStorage *activeStorage = storage.activeStorage(); @@ -511,28 +516,28 @@ void tst_Tasking::testTree_data() }; const Group root1 { Storage(storage), - Test(setupTask(1), logDone), - Test(setupTask(2), logDone), - Test(setupTask(3), logDone), - Test(setupTask(4), logDone), - Test(setupTask(5), logDone), - onGroupDone(groupDone(0)) + createSuccessTask(1), + createSuccessTask(2), + createSuccessTask(3), + createSuccessTask(4), + createSuccessTask(5), + groupDone(0) }; const Group root2 { Storage(storage), - Group { Test(setupTask(1), logDone) }, - Group { Test(setupTask(2), logDone) }, - Group { Test(setupTask(3), logDone) }, - Group { Test(setupTask(4), logDone) }, - Group { Test(setupTask(5), logDone) }, - onGroupDone(groupDone(0)) + Group { createSuccessTask(1) }, + Group { createSuccessTask(2) }, + Group { createSuccessTask(3) }, + Group { createSuccessTask(4) }, + Group { createSuccessTask(5) }, + groupDone(0) }; const Group root3 { Storage(storage), - Test(setupTask(1), logDone), + createSuccessTask(1), TaskTreeTask(setupSubTree), - Test(setupTask(5), logDone), - onGroupDone(groupDone(0)) + createSuccessTask(5), + groupDone(0) }; const Log log { {1, Handler::Setup}, @@ -557,26 +562,26 @@ void tst_Tasking::testTree_data() const Group root { Storage(storage), Group { - Test(setupTask(1), logDone), + createSuccessTask(1), Group { - Test(setupTask(2), logDone), + createSuccessTask(2), Group { - Test(setupTask(3), logDone), + createSuccessTask(3), Group { - Test(setupTask(4), logDone), + createSuccessTask(4), Group { - Test(setupTask(5), logDone), - onGroupDone(groupDone(5)) + createSuccessTask(5), + groupDone(5) }, - onGroupDone(groupDone(4)) + groupDone(4) }, - onGroupDone(groupDone(3)) + groupDone(3) }, - onGroupDone(groupDone(2)) + groupDone(2) }, - onGroupDone(groupDone(1)) + groupDone(1) }, - onGroupDone(groupDone(0)) + groupDone(0) }; const Log log { {1, Handler::Setup}, @@ -602,13 +607,13 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Test(setupTask(1), logDone), - Test(setupTask(2), logDone), - Test(setupFailingTask(3), logDone, logError), - Test(setupTask(4), logDone), - Test(setupTask(5), logDone), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + createSuccessTask(1), + createSuccessTask(2), + createFailingTask(3), + createSuccessTask(4), + createSuccessTask(5), + groupDone(0), + groupError(0) }; const Log log { {1, Handler::Setup}, @@ -623,44 +628,45 @@ void tst_Tasking::testTree_data() } { - const auto constructEmptyWorkflow = [=](WorkflowPolicy policy) { + const auto createRoot = [storage, groupDone, groupError](WorkflowPolicy policy) { return Group { Storage(storage), workflowPolicy(policy), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + groupDone(0), + groupError(0) }; }; const Log log = {{0, Handler::GroupDone}}; - const Group root1 = constructEmptyWorkflow(WorkflowPolicy::StopOnError); + const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("EmptyStopOnError") << TestData{storage, root1, log, 0, OnDone::Success}; - const Group root2 = constructEmptyWorkflow(WorkflowPolicy::ContinueOnError); + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("EmptyContinueOnError") << TestData{storage, root2, log, 0, OnDone::Success}; - const Group root3 = constructEmptyWorkflow(WorkflowPolicy::StopOnDone); + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); QTest::newRow("EmptyStopOnDone") << TestData{storage, root3, log, 0, OnDone::Success}; - const Group root4 = constructEmptyWorkflow(WorkflowPolicy::ContinueOnDone); + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); QTest::newRow("EmptyContinueOnDone") << TestData{storage, root4, log, 0, OnDone::Success}; - const Group root5 = constructEmptyWorkflow(WorkflowPolicy::StopOnFinished); + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, log, 0, OnDone::Success}; - const Group root6 = constructEmptyWorkflow(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::Optional); QTest::newRow("EmptyOptional") << TestData{storage, root6, log, 0, OnDone::Success}; } { - const auto constructDoneWorkflow = [=](WorkflowPolicy policy) { + const auto createRoot = [storage, createSuccessTask, groupDone, groupError]( + WorkflowPolicy policy) { return Group { Storage(storage), workflowPolicy(policy), - Test(setupTask(1), logDone, logError), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + createSuccessTask(1), + groupDone(0), + groupError(0) }; }; @@ -670,33 +676,34 @@ void tst_Tasking::testTree_data() {0, Handler::GroupDone} }; - const Group root1 = constructDoneWorkflow(WorkflowPolicy::StopOnError); + const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("DoneStopOnError") << TestData{storage, root1, log, 1, OnDone::Success}; - const Group root2 = constructDoneWorkflow(WorkflowPolicy::ContinueOnError); + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("DoneContinueOnError") << TestData{storage, root2, log, 1, OnDone::Success}; - const Group root3 = constructDoneWorkflow(WorkflowPolicy::StopOnDone); + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); QTest::newRow("DoneStopOnDone") << TestData{storage, root3, log, 1, OnDone::Success}; - const Group root4 = constructDoneWorkflow(WorkflowPolicy::ContinueOnDone); + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); QTest::newRow("DoneContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Success}; - const Group root5 = constructDoneWorkflow(WorkflowPolicy::StopOnFinished); + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); QTest::newRow("DoneStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Success}; - const Group root6 = constructDoneWorkflow(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::Optional); QTest::newRow("DoneOptional") << TestData{storage, root6, log, 1, OnDone::Success}; } { - const auto constructErrorWorkflow = [=](WorkflowPolicy policy) { + const auto createRoot = [storage, createFailingTask, groupDone, groupError]( + WorkflowPolicy policy) { return Group { Storage(storage), workflowPolicy(policy), - Test(setupFailingTask(1), logDone, logError), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + createFailingTask(1), + groupDone(0), + groupError(0) }; }; @@ -712,40 +719,51 @@ void tst_Tasking::testTree_data() {0, Handler::GroupDone} }; - const Group root1 = constructErrorWorkflow(WorkflowPolicy::StopOnError); + const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("ErrorStopOnError") << TestData{storage, root1, log, 1, OnDone::Failure}; - const Group root2 = constructErrorWorkflow(WorkflowPolicy::ContinueOnError); + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("ErrorContinueOnError") << TestData{storage, root2, log, 1, OnDone::Failure}; - const Group root3 = constructErrorWorkflow(WorkflowPolicy::StopOnDone); + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); QTest::newRow("ErrorStopOnDone") << TestData{storage, root3, log, 1, OnDone::Failure}; - const Group root4 = constructErrorWorkflow(WorkflowPolicy::ContinueOnDone); + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); QTest::newRow("ErrorContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Failure}; - const Group root5 = constructErrorWorkflow(WorkflowPolicy::StopOnFinished); + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); QTest::newRow("ErrorStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Failure}; - const Group root6 = constructErrorWorkflow(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::Optional); QTest::newRow("ErrorOptional") << TestData{storage, root6, optionalLog, 1, OnDone::Success}; } { - const Group root = constructSimpleSequence(WorkflowPolicy::StopOnError); - const Log log { + const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone, + groupError](WorkflowPolicy policy) { + return Group { + Storage(storage), + workflowPolicy(policy), + createSuccessTask(1), + createFailingTask(2), + createSuccessTask(3), + groupDone(0), + groupError(0) + }; + }; + + const Group root1 = createRoot(WorkflowPolicy::StopOnError); + const Log log1 { {1, Handler::Setup}, {1, Handler::Done}, {2, Handler::Setup}, {2, Handler::Error}, {0, Handler::GroupError} }; - QTest::newRow("StopOnError") << TestData{storage, root, log, 3, OnDone::Failure}; - } + QTest::newRow("StopOnError") << TestData{storage, root1, log1, 3, OnDone::Failure}; - { - const Group root = constructSimpleSequence(WorkflowPolicy::ContinueOnError); - const Log log { + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); + const Log log2 { {1, Handler::Setup}, {1, Handler::Done}, {2, Handler::Setup}, @@ -754,22 +772,18 @@ void tst_Tasking::testTree_data() {3, Handler::Done}, {0, Handler::GroupError} }; - QTest::newRow("ContinueOnError") << TestData{storage, root, log, 3, OnDone::Failure}; - } + QTest::newRow("ContinueOnError") << TestData{storage, root2, log2, 3, OnDone::Failure}; - { - const Group root = constructSimpleSequence(WorkflowPolicy::StopOnDone); - const Log log { + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); + const Log log3 { {1, Handler::Setup}, {1, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("StopOnDone") << TestData{storage, root, log, 3, OnDone::Success}; - } + QTest::newRow("StopOnDone") << TestData{storage, root3, log3, 3, OnDone::Success}; - { - const Group root = constructSimpleSequence(WorkflowPolicy::ContinueOnDone); - const Log log { + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); + const Log log4 { {1, Handler::Setup}, {1, Handler::Done}, {2, Handler::Setup}, @@ -778,36 +792,35 @@ void tst_Tasking::testTree_data() {3, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("ContinueOnDone") << TestData{storage, root, log, 3, OnDone::Success}; - } + QTest::newRow("ContinueOnDone") << TestData{storage, root4, log4, 3, OnDone::Success}; - { - const Group root = constructSimpleSequence(WorkflowPolicy::StopOnFinished); - const Log log { + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); + const Log log5 { {1, Handler::Setup}, {1, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("StopOnFinished") << TestData{storage, root, log, 3, OnDone::Success}; + QTest::newRow("StopOnFinished") << TestData{storage, root5, log5, 3, OnDone::Success}; } { - const auto setupRoot = [=](bool firstSuccess, bool secondSuccess) { + const auto createRoot = [storage, createTask, groupDone, groupError]( + bool firstSuccess, bool secondSuccess) { return Group { parallel, stopOnFinished, Storage(storage), - Test(setupSleepingTask(1, firstSuccess, 1000ms), logDone, logError), - Test(setupSleepingTask(2, secondSuccess, 5ms), logDone, logError), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + createTask(1, firstSuccess, 1000ms), + createTask(2, secondSuccess, 1ms), + groupDone(0), + groupError(0) }; }; - const Group root1 = setupRoot(true, true); - const Group root2 = setupRoot(true, false); - const Group root3 = setupRoot(false, true); - const Group root4 = setupRoot(false, false); + const Group root1 = createRoot(true, true); + const Group root2 = createRoot(true, false); + const Group root3 = createRoot(false, true); + const Group root4 = createRoot(false, false); const Log success { {1, Handler::Setup}, @@ -834,10 +847,10 @@ void tst_Tasking::testTree_data() const Group root { Storage(storage), optional, - Test(setupFailingTask(1), logDone, logError), - Test(setupFailingTask(2), logDone, logError), - onGroupDone(groupDone(0)), - onGroupError(groupError(0)) + createFailingTask(1), + createFailingTask(2), + groupDone(0), + groupError(0) }; const Log log { {1, Handler::Setup}, @@ -850,28 +863,42 @@ void tst_Tasking::testTree_data() } { - const Group root = constructDynamicHierarchy(TaskAction::StopWithDone); - const Log log { + const auto createRoot = [storage, createSuccessTask, groupDone, groupError]( + TaskAction taskAction) { + return Group { + Storage(storage), + Group { + createSuccessTask(1) + }, + Group { + onGroupSetup([=] { return taskAction; }), + createSuccessTask(2), + createSuccessTask(3), + createSuccessTask(4) + }, + groupDone(0), + groupError(0) + }; + }; + + const Group root1 = createRoot(TaskAction::StopWithDone); + const Log log1 { {1, Handler::Setup}, {1, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("DynamicSetupDone") << TestData{storage, root, log, 4, OnDone::Success}; - } + QTest::newRow("DynamicSetupDone") << TestData{storage, root1, log1, 4, OnDone::Success}; - { - const Group root = constructDynamicHierarchy(TaskAction::StopWithError); - const Log log { + const Group root2 = createRoot(TaskAction::StopWithError); + const Log log2 { {1, Handler::Setup}, {1, Handler::Done}, {0, Handler::GroupError} }; - QTest::newRow("DynamicSetupError") << TestData{storage, root, log, 4, OnDone::Failure}; - } + QTest::newRow("DynamicSetupError") << TestData{storage, root2, log2, 4, OnDone::Failure}; - { - const Group root = constructDynamicHierarchy(TaskAction::Continue); - const Log log { + const Group root3 = createRoot(TaskAction::Continue); + const Log log3 { {1, Handler::Setup}, {1, Handler::Done}, {2, Handler::Setup}, @@ -882,7 +909,7 @@ void tst_Tasking::testTree_data() {4, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("DynamicSetupContinue") << TestData{storage, root, log, 4, OnDone::Success}; + QTest::newRow("DynamicSetupContinue") << TestData{storage, root3, log3, 4, OnDone::Success}; } { @@ -890,20 +917,20 @@ void tst_Tasking::testTree_data() parallelLimit(2), Storage(storage), Group { - onGroupSetup(groupSetup(1)), - Test(setupTask(1)) + groupSetup(1), + createSuccessTask(1) }, Group { - onGroupSetup(groupSetup(2)), - Test(setupTask(2)) + groupSetup(2), + createSuccessTask(2) }, Group { - onGroupSetup(groupSetup(3)), - Test(setupTask(3)) + groupSetup(3), + createSuccessTask(3) }, Group { - onGroupSetup(groupSetup(4)), - Test(setupTask(4)) + groupSetup(4), + createSuccessTask(4) } }; const Log log { @@ -911,10 +938,14 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {2, Handler::GroupSetup}, {2, Handler::Setup}, + {1, Handler::Done}, {3, Handler::GroupSetup}, {3, Handler::Setup}, + {2, Handler::Done}, {4, Handler::GroupSetup}, - {4, Handler::Setup} + {4, Handler::Setup}, + {3, Handler::Done}, + {4, Handler::Done} }; QTest::newRow("NestedParallel") << TestData{storage, root, log, 4, OnDone::Success}; } @@ -924,24 +955,24 @@ void tst_Tasking::testTree_data() parallelLimit(2), Storage(storage), Group { - onGroupSetup(groupSetup(1)), - Test(setupTask(1)) + groupSetup(1), + createSuccessTask(1) }, Group { - onGroupSetup(groupSetup(2)), - Test(setupTask(2)) + groupSetup(2), + createSuccessTask(2) }, Group { - onGroupSetup(groupSetup(3)), - Test(setupDynamicTask(3, TaskAction::StopWithDone)) + groupSetup(3), + createDynamicTask(3, TaskAction::StopWithDone) }, Group { - onGroupSetup(groupSetup(4)), - Test(setupTask(4)) + groupSetup(4), + createSuccessTask(4) }, Group { - onGroupSetup(groupSetup(5)), - Test(setupTask(5)) + groupSetup(5), + createSuccessTask(5) } }; const Log log { @@ -949,12 +980,16 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {2, Handler::GroupSetup}, {2, Handler::Setup}, + {1, Handler::Done}, {3, Handler::GroupSetup}, {3, Handler::Setup}, {4, Handler::GroupSetup}, {4, Handler::Setup}, + {2, Handler::Done}, {5, Handler::GroupSetup}, - {5, Handler::Setup} + {5, Handler::Setup}, + {4, Handler::Done}, + {5, Handler::Done} }; QTest::newRow("NestedParallelDone") << TestData{storage, root, log, 5, OnDone::Success}; } @@ -964,26 +999,36 @@ void tst_Tasking::testTree_data() parallelLimit(2), Storage(storage), Group { - onGroupSetup(groupSetup(1)), - Test(setupTask(1)) + groupSetup(1), + createSuccessTask(1) }, Group { - onGroupSetup(groupSetup(2)), - Test(setupTask(2)) + groupSetup(2), + createSuccessTask(2) }, Group { - onGroupSetup(groupSetup(3)), - Test(setupDynamicTask(3, TaskAction::StopWithError)) + groupSetup(3), + createDynamicTask(3, TaskAction::StopWithError) }, Group { - onGroupSetup(groupSetup(4)), - Test(setupTask(4)) + groupSetup(4), + createSuccessTask(4) }, Group { - onGroupSetup(groupSetup(5)), - Test(setupTask(5)) + groupSetup(5), + createSuccessTask(5) } }; + const Log log1 { + {1, Handler::GroupSetup}, + {1, Handler::Setup}, + {2, Handler::GroupSetup}, + {2, Handler::Setup}, + {1, Handler::Done}, + {3, Handler::GroupSetup}, + {3, Handler::Setup}, + {2, Handler::Error} + }; // Inside this test the task 2 should finish first, then synchonously: // - task 3 should exit setup with error @@ -993,26 +1038,36 @@ void tst_Tasking::testTree_data() parallelLimit(2), Storage(storage), Group { - onGroupSetup(groupSetup(1)), - Test(setupSleepingTask(1, true, 10ms)) + groupSetup(1), + createSuccessTask(1, 10ms) }, Group { - onGroupSetup(groupSetup(2)), - Test(setupTask(2)) + groupSetup(2), + createSuccessTask(2) }, Group { - onGroupSetup(groupSetup(3)), - Test(setupDynamicTask(3, TaskAction::StopWithError)) + groupSetup(3), + createDynamicTask(3, TaskAction::StopWithError) }, Group { - onGroupSetup(groupSetup(4)), - Test(setupTask(4)) + groupSetup(4), + createSuccessTask(4) }, Group { - onGroupSetup(groupSetup(5)), - Test(setupTask(5)) + groupSetup(5), + createSuccessTask(5) } }; + const Log log2 { + {1, Handler::GroupSetup}, + {1, Handler::Setup}, + {2, Handler::GroupSetup}, + {2, Handler::Setup}, + {2, Handler::Done}, + {3, Handler::GroupSetup}, + {3, Handler::Setup}, + {1, Handler::Error} + }; // This test ensures that the task 1 doesn't invoke its done handler, // being ready while sleeping in the task's 2 done handler. @@ -1028,42 +1083,46 @@ void tst_Tasking::testTree_data() Group { parallelLimit(2), Group { - onGroupSetup(groupSetup(1)), - Test(setupSleepingTask(1, true, 20ms)) + groupSetup(1), + createSuccessTask(1, 10ms) }, Group { - onGroupSetup(groupSetup(2)), - Test(setupSleepingTask(2, true, 10ms)) + groupSetup(2), + createSuccessTask(2, 1ms) }, Group { - onGroupSetup(groupSetup(3)), - Test(setupDynamicTask(3, TaskAction::StopWithError)) + groupSetup(3), + createDynamicTask(3, TaskAction::StopWithError) }, Group { - onGroupSetup(groupSetup(4)), - Test(setupTask(4)) + groupSetup(4), + createSuccessTask(4) } }, Group { - onGroupSetup(groupSetup(5)), - Test(setupTask(5)) + groupSetup(5), + createSuccessTask(5) } }; - const Log shortLog { + const Log log3 { {1, Handler::GroupSetup}, {1, Handler::Setup}, {2, Handler::GroupSetup}, {2, Handler::Setup}, + {2, Handler::Done}, {3, Handler::GroupSetup}, - {3, Handler::Setup} + {3, Handler::Setup}, + {1, Handler::Error}, + {5, Handler::GroupSetup}, + {5, Handler::Setup}, + {5, Handler::Done} }; - const Log longLog = shortLog + Log {{5, Handler::GroupSetup}, {5, Handler::Setup}}; QTest::newRow("NestedParallelError1") - << TestData{storage, root1, shortLog, 5, OnDone::Failure}; + << TestData{storage, root1, log1, 5, OnDone::Failure}; QTest::newRow("NestedParallelError2") - << TestData{storage, root2, shortLog, 5, OnDone::Failure}; + << TestData{storage, root2, log2, 5, OnDone::Failure}; QTest::newRow("NestedParallelError3") - << TestData{storage, root3, longLog, 5, OnDone::Failure}; + << TestData{storage, root3, log3, 5, OnDone::Failure}; } { @@ -1071,35 +1130,31 @@ void tst_Tasking::testTree_data() parallelLimit(2), Storage(storage), Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(1)), + groupSetup(1), Group { parallel, - Test(setupTask(1)) + createSuccessTask(1) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(2)), + groupSetup(2), Group { parallel, - Test(setupTask(2)) + createSuccessTask(2) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(3)), + groupSetup(3), Group { parallel, - Test(setupTask(3)) + createSuccessTask(3) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(4)), + groupSetup(4), Group { parallel, - Test(setupTask(4)) + createSuccessTask(4) } } }; @@ -1108,10 +1163,14 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {2, Handler::GroupSetup}, {2, Handler::Setup}, + {1, Handler::Done}, {3, Handler::GroupSetup}, {3, Handler::Setup}, + {2, Handler::Done}, {4, Handler::GroupSetup}, - {4, Handler::Setup} + {4, Handler::Setup}, + {3, Handler::Done}, + {4, Handler::Done} }; QTest::newRow("DeeplyNestedParallel") << TestData{storage, root, log, 4, OnDone::Success}; } @@ -1121,29 +1180,24 @@ void tst_Tasking::testTree_data() parallelLimit(2), Storage(storage), Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(1)), - Group { Test(setupTask(1)) } + groupSetup(1), + Group { createSuccessTask(1) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(2)), - Group { Test(setupTask(2)) } + groupSetup(2), + Group { createSuccessTask(2) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(3)), - Group { Test(setupDynamicTask(3, TaskAction::StopWithDone)) } + groupSetup(3), + Group { createDynamicTask(3, TaskAction::StopWithDone) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(4)), - Group { Test(setupTask(4)) } + groupSetup(4), + Group { createSuccessTask(4) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(5)), - Group { Test(setupTask(5)) } + groupSetup(5), + Group { createSuccessTask(5) } } }; const Log log { @@ -1151,12 +1205,16 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {2, Handler::GroupSetup}, {2, Handler::Setup}, + {1, Handler::Done}, {3, Handler::GroupSetup}, {3, Handler::Setup}, {4, Handler::GroupSetup}, {4, Handler::Setup}, + {2, Handler::Done}, {5, Handler::GroupSetup}, - {5, Handler::Setup} + {5, Handler::Setup}, + {4, Handler::Done}, + {5, Handler::Done} }; QTest::newRow("DeeplyNestedParallelDone") << TestData{storage, root, log, 5, OnDone::Success}; @@ -1167,29 +1225,24 @@ void tst_Tasking::testTree_data() parallelLimit(2), Storage(storage), Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(1)), - Group { Test(setupTask(1)) } + groupSetup(1), + Group { createSuccessTask(1) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(2)), - Group { Test(setupTask(2)) } + groupSetup(2), + Group { createSuccessTask(2) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(3)), - Group { Test(setupDynamicTask(3, TaskAction::StopWithError)) } + groupSetup(3), + Group { createDynamicTask(3, TaskAction::StopWithError) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(4)), - Group { Test(setupTask(4)) } + groupSetup(4), + Group { createSuccessTask(4) } }, Group { - Storage(TreeStorage()), - onGroupSetup(groupSetup(5)), - Group { Test(setupTask(5)) } + groupSetup(5), + Group { createSuccessTask(5) } } }; const Log log { @@ -1197,8 +1250,10 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {2, Handler::GroupSetup}, {2, Handler::Setup}, + {1, Handler::Done}, {3, Handler::GroupSetup}, - {3, Handler::Setup} + {3, Handler::Setup}, + {2, Handler::Error} }; QTest::newRow("DeeplyNestedParallelError") << TestData{storage, root, log, 5, OnDone::Failure}; @@ -1207,11 +1262,11 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Sync(setupSync(1)), - Sync(setupSync(2)), - Sync(setupSync(3)), - Sync(setupSync(4)), - Sync(setupSync(5)) + createSync(1), + createSync(2), + createSync(3), + createSync(4), + createSync(5) }; const Log log { {1, Handler::Sync}, @@ -1226,11 +1281,11 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Sync(setupSyncWithReturn(1, true)), - Sync(setupSyncWithReturn(2, true)), - Sync(setupSyncWithReturn(3, true)), - Sync(setupSyncWithReturn(4, true)), - Sync(setupSyncWithReturn(5, true)) + createSyncWithReturn(1, true), + createSyncWithReturn(2, true), + createSyncWithReturn(3, true), + createSyncWithReturn(4, true), + createSyncWithReturn(5, true) }; const Log log { {1, Handler::Sync}, @@ -1246,11 +1301,11 @@ void tst_Tasking::testTree_data() const Group root { Storage(storage), parallel, - Sync(setupSync(1)), - Sync(setupSync(2)), - Sync(setupSync(3)), - Sync(setupSync(4)), - Sync(setupSync(5)) + createSync(1), + createSync(2), + createSync(3), + createSync(4), + createSync(5) }; const Log log { {1, Handler::Sync}, @@ -1266,11 +1321,11 @@ void tst_Tasking::testTree_data() const Group root { Storage(storage), parallel, - Sync(setupSync(1)), - Sync(setupSync(2)), - Sync(setupSyncWithReturn(3, false)), - Sync(setupSync(4)), - Sync(setupSync(5)) + createSync(1), + createSync(2), + createSyncWithReturn(3, false), + createSync(4), + createSync(5) }; const Log log { {1, Handler::Sync}, @@ -1283,18 +1338,20 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Sync(setupSync(1)), - Test(setupTask(2)), - Sync(setupSync(3)), - Test(setupTask(4)), - Sync(setupSync(5)), - onGroupDone(groupDone(0)) + createSync(1), + createSuccessTask(2), + createSync(3), + createSuccessTask(4), + createSync(5), + groupDone(0) }; const Log log { {1, Handler::Sync}, {2, Handler::Setup}, + {2, Handler::Done}, {3, Handler::Sync}, {4, Handler::Setup}, + {4, Handler::Done}, {5, Handler::Sync}, {0, Handler::GroupDone} }; @@ -1304,16 +1361,17 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - Sync(setupSync(1)), - Test(setupTask(2)), - Sync(setupSyncWithReturn(3, false)), - Test(setupTask(4)), - Sync(setupSync(5)), - onGroupError(groupError(0)) + createSync(1), + createSuccessTask(2), + createSyncWithReturn(3, false), + createSuccessTask(4), + createSync(5), + groupError(0) }; const Log log { {1, Handler::Sync}, {2, Handler::Setup}, + {2, Handler::Done}, {3, Handler::Sync}, {0, Handler::GroupError} }; @@ -1330,12 +1388,12 @@ void tst_Tasking::testTree_data() Storage(storage), Storage(barrier), sequential, - AsyncTask(setupBarrierAdvance(storage, barrier, 1)), + createBarrierAdvance(storage, barrier, 1), Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(2)), - Test(setupTask(3)) + createSuccessTask(2), + createSuccessTask(3) } }; const Log log1 { @@ -1343,7 +1401,9 @@ void tst_Tasking::testTree_data() {1, Handler::BarrierAdvance}, {2, Handler::GroupSetup}, {2, Handler::Setup}, - {3, Handler::Setup} + {2, Handler::Done}, + {3, Handler::Setup}, + {3, Handler::Done} }; // Test that barrier advance, triggered from inside the task described by @@ -1353,12 +1413,12 @@ void tst_Tasking::testTree_data() Storage(storage), Storage(barrier), parallel, - AsyncTask(setupBarrierAdvance(storage, barrier, 1)), + createBarrierAdvance(storage, barrier, 1), Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(2)), - Test(setupTask(3)) + createSuccessTask(2), + createSuccessTask(3) } }; const Log log2 { @@ -1366,7 +1426,9 @@ void tst_Tasking::testTree_data() {2, Handler::GroupSetup}, {1, Handler::BarrierAdvance}, {2, Handler::Setup}, - {3, Handler::Setup} + {2, Handler::Done}, + {3, Handler::Setup}, + {3, Handler::Done} }; // Test that barrier advance, triggered from inside the task described by @@ -1384,19 +1446,21 @@ void tst_Tasking::testTree_data() Storage(barrier), parallel, Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(2)), - Test(setupTask(3)) + createSuccessTask(2), + createSuccessTask(3) }, - AsyncTask(setupBarrierAdvance(storage, barrier, 1)) + createBarrierAdvance(storage, barrier, 1) }; const Log log3 { {2, Handler::GroupSetup}, {1, Handler::Setup}, {1, Handler::BarrierAdvance}, {2, Handler::Setup}, - {3, Handler::Setup} + {2, Handler::Done}, + {3, Handler::Setup}, + {3, Handler::Done} }; // Test that barrier advance, triggered from inside the task described by @@ -1406,16 +1470,16 @@ void tst_Tasking::testTree_data() Storage(storage), Storage(barrier), parallel, - AsyncTask(setupBarrierAdvance(storage, barrier, 1)), + createBarrierAdvance(storage, barrier, 1), Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(4)) + createSuccessTask(4) }, Group { - onGroupSetup(groupSetup(3)), + groupSetup(3), WaitForBarrierTask(barrier), - Test(setupTask(5)) + createSuccessTask(5) } }; const Log log4 { @@ -1424,7 +1488,9 @@ void tst_Tasking::testTree_data() {3, Handler::GroupSetup}, {1, Handler::BarrierAdvance}, {4, Handler::Setup}, - {5, Handler::Setup} + {5, Handler::Setup}, + {4, Handler::Done}, + {5, Handler::Done} }; // Test two separate single barriers. @@ -1436,25 +1502,26 @@ void tst_Tasking::testTree_data() Storage(barrier), Storage(barrier2), parallel, - AsyncTask(setupBarrierAdvance(storage, barrier, 0)), - AsyncTask(setupBarrierAdvance(storage, barrier2, 0)), + createBarrierAdvance(storage, barrier, 1), + createBarrierAdvance(storage, barrier2, 2), Group { Group { parallel, - onGroupSetup(groupSetup(1)), + groupSetup(1), WaitForBarrierTask(barrier), WaitForBarrierTask(barrier2) }, - Test(setupTask(2)) + createSuccessTask(3) }, }; const Log log5 { - {0, Handler::Setup}, - {0, Handler::Setup}, + {1, Handler::Setup}, + {2, Handler::Setup}, {1, Handler::GroupSetup}, - {0, Handler::BarrierAdvance}, - {0, Handler::BarrierAdvance}, - {2, Handler::Setup} + {1, Handler::BarrierAdvance}, + {2, Handler::BarrierAdvance}, + {3, Handler::Setup}, + {3, Handler::Done} }; // Notice the different log order for each scenario. @@ -1480,13 +1547,13 @@ void tst_Tasking::testTree_data() Storage(storage), Storage(barrier), sequential, - AsyncTask(setupBarrierAdvance(storage, barrier, 1)), - AsyncTask(setupBarrierAdvance(storage, barrier, 2)), + createBarrierAdvance(storage, barrier, 1), + createBarrierAdvance(storage, barrier, 2), Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(2)), - Test(setupTask(3)) + createSuccessTask(2), + createSuccessTask(3) } }; const Log log1 { @@ -1496,7 +1563,9 @@ void tst_Tasking::testTree_data() {2, Handler::BarrierAdvance}, {2, Handler::GroupSetup}, {2, Handler::Setup}, - {3, Handler::Setup} + {2, Handler::Done}, + {3, Handler::Setup}, + {3, Handler::Done} }; // Test that multi barrier advance, triggered from inside the tasks described by @@ -1506,23 +1575,25 @@ void tst_Tasking::testTree_data() Storage(storage), Storage(barrier), parallel, - AsyncTask(setupBarrierAdvance(storage, barrier, 0)), - AsyncTask(setupBarrierAdvance(storage, barrier, 0)), + createBarrierAdvance(storage, barrier, 1), + createBarrierAdvance(storage, barrier, 2), Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(2)), - Test(setupTask(3)) + createSuccessTask(3), + createSuccessTask(4) } }; const Log log2 { - {0, Handler::Setup}, - {0, Handler::Setup}, - {2, Handler::GroupSetup}, - {0, Handler::BarrierAdvance}, // Barrier advances may come in different order in - {0, Handler::BarrierAdvance}, // parallel mode, that's why id = 0 (same for both). + {1, Handler::Setup}, {2, Handler::Setup}, - {3, Handler::Setup} + {2, Handler::GroupSetup}, + {1, Handler::BarrierAdvance}, + {2, Handler::BarrierAdvance}, + {3, Handler::Setup}, + {3, Handler::Done}, + {4, Handler::Setup}, + {4, Handler::Done} }; // Test that multi barrier advance, triggered from inside the tasks described by @@ -1540,22 +1611,24 @@ void tst_Tasking::testTree_data() Storage(barrier), parallel, Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(2)), - Test(setupTask(3)) + createSuccessTask(3), + createSuccessTask(4) }, - AsyncTask(setupBarrierAdvance(storage, barrier, 0)), - AsyncTask(setupBarrierAdvance(storage, barrier, 0)) + createBarrierAdvance(storage, barrier, 1), + createBarrierAdvance(storage, barrier, 2) }; const Log log3 { {2, Handler::GroupSetup}, - {0, Handler::Setup}, - {0, Handler::Setup}, - {0, Handler::BarrierAdvance}, // Barrier advances may come in different order in - {0, Handler::BarrierAdvance}, // parallel mode, that's why id = 0 (same for both). + {1, Handler::Setup}, {2, Handler::Setup}, - {3, Handler::Setup} + {1, Handler::BarrierAdvance}, + {2, Handler::BarrierAdvance}, + {3, Handler::Setup}, + {3, Handler::Done}, + {4, Handler::Setup}, + {4, Handler::Done} }; // Test that multi barrier advance, triggered from inside the task described by @@ -1565,28 +1638,30 @@ void tst_Tasking::testTree_data() Storage(storage), Storage(barrier), parallel, - AsyncTask(setupBarrierAdvance(storage, barrier, 0)), - AsyncTask(setupBarrierAdvance(storage, barrier, 0)), + createBarrierAdvance(storage, barrier, 1), + createBarrierAdvance(storage, barrier, 2), Group { - onGroupSetup(groupSetup(2)), + groupSetup(2), WaitForBarrierTask(barrier), - Test(setupTask(4)) + createSuccessTask(3) }, Group { - onGroupSetup(groupSetup(3)), + groupSetup(3), WaitForBarrierTask(barrier), - Test(setupTask(5)) + createSuccessTask(4) } }; const Log log4 { - {0, Handler::Setup}, - {0, Handler::Setup}, + {1, Handler::Setup}, + {2, Handler::Setup}, {2, Handler::GroupSetup}, {3, Handler::GroupSetup}, - {0, Handler::BarrierAdvance}, - {0, Handler::BarrierAdvance}, + {1, Handler::BarrierAdvance}, + {2, Handler::BarrierAdvance}, + {3, Handler::Setup}, {4, Handler::Setup}, - {5, Handler::Setup} + {3, Handler::Done}, + {4, Handler::Done} }; // Notice the different log order for each scenario. @@ -1648,12 +1723,12 @@ void tst_Tasking::storageDestructor() QCOMPARE(CustomStorage::instanceCount(), 0); { TreeStorage storage; - const auto setupSleepingTask = [](TestTask &task) { - task.setConcurrentCallData(runTask, true, 1000ms); + const auto setupSleepingTask = [](TaskObject &taskObject) { + taskObject = 1000ms; }; const Group root { Storage(storage), - Test(setupSleepingTask) + SuccessTask(setupSleepingTask) }; TaskTree taskTree(root); @@ -1662,7 +1737,6 @@ void tst_Tasking::storageDestructor() taskTree.onStorageDone(storage, doneHandler); taskTree.start(); QCOMPARE(CustomStorage::instanceCount(), 1); - QThread::msleep(5); // Give the sleeping task a change to start } QCOMPARE(CustomStorage::instanceCount(), 0); QVERIFY(setupCalled); From cbca40401b62556753d12a354b80748c5d3d72cd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 28 May 2023 12:42:05 +0200 Subject: [PATCH 1354/1447] TaskTree: Fix calling the proper group handler on stop Add tests for it. Change-Id: Ibb04b21c217196c9bbf6761851f4e1a300139a8c Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.cpp | 1 + tests/auto/solutions/tasking/tst_tasking.cpp | 370 +++++++++++++++++++ 2 files changed, 371 insertions(+) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 071190dd9eb..a3fb9347bbb 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -893,6 +893,7 @@ void TaskNode::stop() if (!m_task) { m_container.stop(); + m_container.m_runtimeData->updateSuccessBit(false); m_container.invokeEndHandler(); return; } diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index e3f7a80ed5b..e86c135066c 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -738,6 +738,376 @@ void tst_Tasking::testTree_data() QTest::newRow("ErrorOptional") << TestData{storage, root6, optionalLog, 1, OnDone::Success}; } + { + // These tests check whether the proper root's group end handler is called + // when the group is stopped. Test it with different workflow policies. + // The root starts one short failing task together with one long task. + const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone, + groupError](WorkflowPolicy policy) { + return Group { + Storage(storage), + parallel, + workflowPolicy(policy), + createFailingTask(1, 1ms), + createSuccessTask(2, 2ms), + groupDone(0), + groupError(0) + }; + }; + + const Log errorErrorLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {1, Handler::Error}, + {2, Handler::Error}, + {0, Handler::GroupError} + }; + + const Log errorDoneLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {1, Handler::Error}, + {2, Handler::Done}, + {0, Handler::GroupError} + }; + + const Log doneLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {1, Handler::Error}, + {2, Handler::Done}, + {0, Handler::GroupDone} + }; + + const Group root1 = createRoot(WorkflowPolicy::StopOnError); + QTest::newRow("StopRootWithStopOnError") + << TestData{storage, root1, errorErrorLog, 2, OnDone::Failure}; + + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); + QTest::newRow("StopRootWithContinueOnError") + << TestData{storage, root2, errorDoneLog, 2, OnDone::Failure}; + + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); + QTest::newRow("StopRootWithStopOnDone") + << TestData{storage, root3, doneLog, 2, OnDone::Success}; + + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); + QTest::newRow("StopRootWithContinueOnDone") + << TestData{storage, root4, doneLog, 2, OnDone::Success}; + + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); + QTest::newRow("StopRootWithStopOnFinished") + << TestData{storage, root5, errorErrorLog, 2, OnDone::Failure}; + + const Group root6 = createRoot(WorkflowPolicy::Optional); + QTest::newRow("StopRootWithOptional") + << TestData{storage, root6, doneLog, 2, OnDone::Success}; + } + + { + // These tests check whether the proper root's group end handler is called + // when the group is stopped. Test it with different workflow policies. + // The root starts in parallel: one very short successful task, one short failing task + // and one long task. + const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone, + groupError](WorkflowPolicy policy) { + return Group { + Storage(storage), + parallel, + workflowPolicy(policy), + createSuccessTask(1), + createFailingTask(2, 1ms), + createSuccessTask(3, 2ms), + groupDone(0), + groupError(0) + }; + }; + + const Log errorErrorLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Done}, + {2, Handler::Error}, + {3, Handler::Error}, + {0, Handler::GroupError} + }; + + const Log errorDoneLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Done}, + {2, Handler::Error}, + {3, Handler::Done}, + {0, Handler::GroupError} + }; + + const Log doneErrorLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Done}, + {2, Handler::Error}, + {3, Handler::Error}, + {0, Handler::GroupDone} + }; + + const Log doneDoneLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Done}, + {2, Handler::Error}, + {3, Handler::Done}, + {0, Handler::GroupDone} + }; + + const Group root1 = createRoot(WorkflowPolicy::StopOnError); + QTest::newRow("StopRootAfterDoneWithStopOnError") + << TestData{storage, root1, errorErrorLog, 3, OnDone::Failure}; + + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); + QTest::newRow("StopRootAfterDoneWithContinueOnError") + << TestData{storage, root2, errorDoneLog, 3, OnDone::Failure}; + + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); + QTest::newRow("StopRootAfterDoneWithStopOnDone") + << TestData{storage, root3, doneErrorLog, 3, OnDone::Success}; + + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); + QTest::newRow("StopRootAfterDoneWithContinueOnDone") + << TestData{storage, root4, doneDoneLog, 3, OnDone::Success}; + + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); + QTest::newRow("StopRootAfterDoneWithStopOnFinished") + << TestData{storage, root5, doneErrorLog, 3, OnDone::Success}; + + const Group root6 = createRoot(WorkflowPolicy::Optional); + QTest::newRow("StopRootAfterDoneWithOptional") + << TestData{storage, root6, doneDoneLog, 3, OnDone::Success}; + } + + { + // These tests check whether the proper subgroup's end handler is called + // when the group is stopped. Test it with different workflow policies. + // The subgroup starts one long task. + const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone, + groupError](WorkflowPolicy policy) { + return Group { + Storage(storage), + parallel, + Group { + workflowPolicy(policy), + createSuccessTask(1, 1000ms), + groupDone(1), + groupError(1) + }, + createFailingTask(2, 1ms), + groupDone(2), + groupError(2) + }; + }; + + const Log errorLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {2, Handler::Error}, + {1, Handler::Error}, + {1, Handler::GroupError}, + {2, Handler::GroupError} + }; + + const Log doneLog = { + {1, Handler::Setup}, + {2, Handler::Setup}, + {2, Handler::Error}, + {1, Handler::Error}, + {1, Handler::GroupDone}, + {2, Handler::GroupError} + }; + + const Group root1 = createRoot(WorkflowPolicy::StopOnError); + QTest::newRow("StopGroupWithStopOnError") + << TestData{storage, root1, errorLog, 2, OnDone::Failure}; + + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); + QTest::newRow("StopGroupWithContinueOnError") + << TestData{storage, root2, errorLog, 2, OnDone::Failure}; + + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); + QTest::newRow("StopGroupWithStopOnDone") + << TestData{storage, root3, errorLog, 2, OnDone::Failure}; + + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); + QTest::newRow("StopGroupWithContinueOnDone") + << TestData{storage, root4, errorLog, 2, OnDone::Failure}; + + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); + QTest::newRow("StopGroupWithStopOnFinished") + << TestData{storage, root5, errorLog, 2, OnDone::Failure}; + + const Group root6 = createRoot(WorkflowPolicy::Optional); + QTest::newRow("StopGroupWithOptional") + << TestData{storage, root6, doneLog, 2, OnDone::Failure}; + } + + { + // These tests check whether the proper subgroup's end handler is called + // when the group is stopped. Test it with different workflow policies. + // The sequential subgroup starts one short successful task followed by one long task. + const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone, + groupError](WorkflowPolicy policy) { + return Group { + Storage(storage), + parallel, + Group { + workflowPolicy(policy), + createSuccessTask(1), + createSuccessTask(2, 1000ms), + groupDone(1), + groupError(1) + }, + createFailingTask(3, 1ms), + groupDone(2), + groupError(2) + }; + }; + + const Log errorLog = { + {1, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Done}, + {2, Handler::Setup}, + {3, Handler::Error}, + {2, Handler::Error}, + {1, Handler::GroupError}, + {2, Handler::GroupError} + }; + + const Log shortDoneLog = { + {1, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Done}, + {1, Handler::GroupDone}, + {3, Handler::Error}, + {2, Handler::GroupError} + }; + + const Log longDoneLog = { + {1, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Done}, + {2, Handler::Setup}, + {3, Handler::Error}, + {2, Handler::Error}, + {1, Handler::GroupDone}, + {2, Handler::GroupError} + }; + + const Group root1 = createRoot(WorkflowPolicy::StopOnError); + QTest::newRow("StopGroupAfterDoneWithStopOnError") + << TestData{storage, root1, errorLog, 3, OnDone::Failure}; + + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); + QTest::newRow("StopGroupAfterDoneWithContinueOnError") + << TestData{storage, root2, errorLog, 3, OnDone::Failure}; + + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); + QTest::newRow("StopGroupAfterDoneWithStopOnDone") + << TestData{storage, root3, shortDoneLog, 3, OnDone::Failure}; + + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); + QTest::newRow("StopGroupAfterDoneWithContinueOnDone") + << TestData{storage, root4, longDoneLog, 3, OnDone::Failure}; + + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); + QTest::newRow("StopGroupAfterDoneWithStopOnFinished") + << TestData{storage, root5, shortDoneLog, 3, OnDone::Failure}; + + const Group root6 = createRoot(WorkflowPolicy::Optional); + QTest::newRow("StopGroupAfterDoneWithOptional") + << TestData{storage, root6, longDoneLog, 3, OnDone::Failure}; + } + + { + // These tests check whether the proper subgroup's end handler is called + // when the group is stopped. Test it with different workflow policies. + // The sequential subgroup starts one short failing task followed by one long task. + const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone, + groupError](WorkflowPolicy policy) { + return Group { + Storage(storage), + parallel, + Group { + workflowPolicy(policy), + createFailingTask(1), + createSuccessTask(2, 1000ms), + groupDone(1), + groupError(1) + }, + createFailingTask(3, 1ms), + groupDone(2), + groupError(2) + }; + }; + + const Log shortErrorLog = { + {1, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Error}, + {1, Handler::GroupError}, + {3, Handler::Error}, + {2, Handler::GroupError} + }; + + const Log longErrorLog = { + {1, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Error}, + {2, Handler::Setup}, + {3, Handler::Error}, + {2, Handler::Error}, + {1, Handler::GroupError}, + {2, Handler::GroupError} + }; + + const Log doneLog = { + {1, Handler::Setup}, + {3, Handler::Setup}, + {1, Handler::Error}, + {2, Handler::Setup}, + {3, Handler::Error}, + {2, Handler::Error}, + {1, Handler::GroupDone}, + {2, Handler::GroupError} + }; + + const Group root1 = createRoot(WorkflowPolicy::StopOnError); + QTest::newRow("StopGroupAfterErrorWithStopOnError") + << TestData{storage, root1, shortErrorLog, 3, OnDone::Failure}; + + const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); + QTest::newRow("StopGroupAfterErrorWithContinueOnError") + << TestData{storage, root2, longErrorLog, 3, OnDone::Failure}; + + const Group root3 = createRoot(WorkflowPolicy::StopOnDone); + QTest::newRow("StopGroupAfterErrorWithStopOnDone") + << TestData{storage, root3, longErrorLog, 3, OnDone::Failure}; + + const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); + QTest::newRow("StopGroupAfterErrorWithContinueOnDone") + << TestData{storage, root4, longErrorLog, 3, OnDone::Failure}; + + const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); + QTest::newRow("StopGroupAfterErrorWithStopOnFinished") + << TestData{storage, root5, shortErrorLog, 3, OnDone::Failure}; + + const Group root6 = createRoot(WorkflowPolicy::Optional); + QTest::newRow("StopGroupAfterErrorWithOptional") + << TestData{storage, root6, doneLog, 3, OnDone::Failure}; + } + { const auto createRoot = [storage, createSuccessTask, createFailingTask, groupDone, groupError](WorkflowPolicy policy) { From ffdb0c7dcc958aaba17abf127923e4dfe02604d3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 26 May 2023 19:44:17 +0200 Subject: [PATCH 1355/1447] TaskTree: Some corrections to the copy example Use QString instead of FilePath. Rename the diffRecipe into copyRecipe. Add some code that constructs the tree, connects to its done signal and starts the tree. Change-Id: I40e1c4784c736347682071b3e3e99db599ce102a Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index a3fb9347bbb..540342ac8ff 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1412,10 +1412,10 @@ void TaskNode::invokeEndHandler(bool success) it from a source and writing it to a destination might look as follows: \code - static QByteArray load(const FilePath &fileName) { ... } - static void save(const FilePath &fileName, const QByteArray &array) { ... } + static QByteArray load(const QString &fileName) { ... } + static void save(const QString &fileName, const QByteArray &array) { ... } - static TaskItem diffRecipe(const FilePath &source, const FilePath &destination) + static TaskItem copyRecipe(const QString &source, const QString &destination) { struct CopyStorage { // [1] custom inter-task struct QByteArray content; // [2] custom inter-task data @@ -1449,6 +1449,13 @@ void TaskNode::invokeEndHandler(bool success) }; return root; } + + const QString source = ...; + const QString destination = ...; + TaskTree taskTree(copyRecipe(source, destination)); + connect(&taskTree, &TaskTree::done, + &taskTree, [] { qDebug() << "The copying finished successfully."; }); + tasktree.start(); \endcode In the example above, the inter-task data consists of a QByteArray content From 4e01ca18d10b839636c1d60c0520816526d92a7f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 28 May 2023 17:20:55 +0200 Subject: [PATCH 1356/1447] TaskTree: Rename optional into finishAllAndDone Rationale: 1. More descriptive. 2. More consistent with a planned new finishAllAndError policy. 3. Limits the possibilities of making a conflict with std::optional. Change-Id: I5155630188e4b699e6c18b13a101e0e2d4fe98f2 Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 8 ++++---- src/libs/solutions/tasking/tasktree.h | 16 ++++++++-------- src/plugins/autotest/testrunner.cpp | 4 ++-- src/plugins/clangtools/clangtoolrunner.cpp | 2 +- .../clangtools/documentclangtoolrunner.cpp | 2 +- .../coreplugin/locator/ilocatorfilter.cpp | 2 +- src/plugins/coreplugin/locator/locator.cpp | 2 +- src/plugins/diffeditor/diffeditorplugin.cpp | 2 +- src/plugins/git/gitclient.cpp | 4 ++-- src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp | 4 ++-- .../remotelinux/genericdirectuploadstep.cpp | 4 ++-- src/plugins/remotelinux/linuxdevicetester.cpp | 4 ++-- src/plugins/subversion/subversionclient.cpp | 2 +- tests/auto/solutions/tasking/tst_tasking.cpp | 18 +++++++++--------- tests/manual/tasktree/main.cpp | 2 +- tests/manual/tasktree/taskwidget.cpp | 2 +- 16 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 540342ac8ff..054647752af 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -164,7 +164,7 @@ private: Constructs a group's element holding the group done handler. The \a handler is invoked whenever the group finishes with success. Depending on the group's workflow policy, this handler may also be called - when the running group is stopped (e.g. when optional element was used). + when the running group is stopped (e.g. when finishAllAndDone element was used). When the \a handler is invoked, all of the group's child tasks are already finished. @@ -256,7 +256,7 @@ const TaskItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError) const TaskItem stopOnDone = workflowPolicy(WorkflowPolicy::StopOnDone); const TaskItem continueOnDone = workflowPolicy(WorkflowPolicy::ContinueOnDone); const TaskItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished); -const TaskItem optional = workflowPolicy(WorkflowPolicy::Optional); +const TaskItem finishAllAndDone = workflowPolicy(WorkflowPolicy::FinishAllAndDone); static TaskAction toTaskAction(bool success) { @@ -720,7 +720,7 @@ TaskContainer::RuntimeData::~RuntimeData() bool TaskContainer::RuntimeData::updateSuccessBit(bool success) { - if (m_constData.m_workflowPolicy == WorkflowPolicy::Optional) + if (m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndDone) return m_successBit; if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) { m_successBit = success; @@ -1394,7 +1394,7 @@ void TaskNode::invokeEndHandler(bool success) In sequential mode, only the first task is started, and when finished, the group finishes too, so the other tasks are ignored. \row - \li optional + \li finishAllAndDone \li The group executes all tasks and ignores their return state. When all tasks finish, the group finishes with success. \endtable diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 1754e092631..872bce2ed86 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -99,15 +99,15 @@ private: // b) On first done - continue executing all children and report done afterwards. // 3. Stops on first finished child. In sequential mode it will never run other children then the first one. // Useful only in parallel mode. -// 4. Always run all children, ignore their result and report done afterwards. +// 4. Always run all children, let them finish, ignore their results and report done afterwards. enum class WorkflowPolicy { - StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done). - ContinueOnError, // 1b - The same, but children execution continues. Reports done when no children. - StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error). - ContinueOnDone, // 2b - The same, but children execution continues. Reports error when no children. - StopOnFinished, // 3 - Stops on first finished child and report its result. - Optional // 4 - Reports done after all children finished. + StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done). + ContinueOnError, // 1b - The same, but children execution continues. Reports done when no children. + StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error). + ContinueOnDone, // 2b - The same, but children execution continues. Reports error when no children. + StopOnFinished, // 3 - Stops on first finished child and report its result. + FinishAllAndDone // 4 - Reports done after all children finished. }; enum class TaskAction @@ -248,7 +248,7 @@ TASKING_EXPORT extern const TaskItem continueOnError; TASKING_EXPORT extern const TaskItem stopOnDone; TASKING_EXPORT extern const TaskItem continueOnDone; TASKING_EXPORT extern const TaskItem stopOnFinished; -TASKING_EXPORT extern const TaskItem optional; +TASKING_EXPORT extern const TaskItem finishAllAndDone; class TASKING_EXPORT Storage : public TaskItem { diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 206dca8da41..5c53d742e65 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -347,7 +347,7 @@ void TestRunner::runTestsHelper() std::unique_ptr m_outputReader; }; - QList tasks{optional}; + QList tasks{finishAllAndDone}; for (ITestConfiguration *config : m_selectedTests) { QTC_ASSERT(config, continue); @@ -442,7 +442,7 @@ void TestRunner::runTestsHelper() } }; const Group group { - optional, + finishAllAndDone, Storage(storage), onGroupSetup(onSetup), ProcessTask(onProcessSetup, onProcessDone, onProcessDone) diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 40cbf75d47e..3e2c7a6c111 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -186,7 +186,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input, Storage(storage), onGroupSetup(onSetup), Group { - optional, + finishAllAndDone, ProcessTask(onProcessSetup, onProcessDone, onProcessError) } }; diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index 178022a91a6..3de2c6d55cf 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -209,7 +209,7 @@ void DocumentClangToolRunner::run() return !m_document->isModified() || isVFSOverlaySupported(executable); }; const auto outputHandler = [this](const AnalyzeOutputData &output) { onDone(output); }; - tasks.append(Group{optional, clangToolTask(input, setupHandler, outputHandler)}); + tasks.append(Group{finishAllAndDone, clangToolTask(input, setupHandler, outputHandler)}); }; addClangTool(ClangToolType::Tidy); addClangTool(ClangToolType::Clazy); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index f6b39996d8f..3a84a0b548b 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -470,7 +470,7 @@ void LocatorMatcher::start() for (const LocatorMatcherTask &task : std::as_const(d->m_tasks)) { const auto storage = task.storage; const Group group { - optional, + finishAllAndDone, Storage(storage), onGroupSetup(onSetup(storage, index)), onGroupDone(onDone(storage)), diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index 55b82920329..2deaef9fe09 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -388,7 +388,7 @@ void Locator::refresh(const QList &filters) continue; const Group group { - optional, + finishAllAndDone, *task, onGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); }) }; diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index fe4c4f9a6a5..99ceef2f0ab 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -128,7 +128,7 @@ DiffFilesController::DiffFilesController(IDocument *document) outputList->resize(inputList.size()); using namespace std::placeholders; - QList tasks {parallel, optional}; + QList tasks {parallel, finishAllAndDone}; for (int i = 0; i < inputList.size(); ++i) { tasks.append(AsyncTask(std::bind(setupDiff, _1, inputList.at(i)), std::bind(onDiffDone, _1, i))); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index f0427e08268..dd335dcc650 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -465,11 +465,11 @@ ShowController::ShowController(IDocument *document, const QString &id) parallel, onGroupSetup([this] { setStartupFile(VcsBase::source(this->document()).toString()); }), Group { - optional, + finishAllAndDone, ProcessTask(setupDescription, onDescriptionDone), Group { parallel, - optional, + finishAllAndDone, onGroupSetup(desciptionDetailsSetup), ProcessTask(setupBranches, onBranchesDone, onBranchesError), ProcessTask(setupPrecedes, onPrecedesDone, onPrecedesError), diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 0b6e74dca8b..a5cc9cdad86 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -223,7 +223,7 @@ TaskItem QnxDeployQtLibrariesDialogPrivate::chmodTree() if (file.isExecutable()) filesToChmod << file; } - QList chmodList{optional, parallelLimit(MaxConcurrentStatCalls)}; + QList chmodList{finishAllAndDone, parallelLimit(MaxConcurrentStatCalls)}; for (const DeployableFile &file : std::as_const(filesToChmod)) { QTC_ASSERT(file.isValid(), continue); chmodList.append(chmodTask(file)); @@ -263,7 +263,7 @@ Group QnxDeployQtLibrariesDialogPrivate::deployRecipe() const Group root { onGroupSetup(setupHandler), Group { - optional, + finishAllAndDone, checkDirTask() }, Group { diff --git a/src/plugins/remotelinux/genericdirectuploadstep.cpp b/src/plugins/remotelinux/genericdirectuploadstep.cpp index 9179ac87519..6074eaabaaf 100644 --- a/src/plugins/remotelinux/genericdirectuploadstep.cpp +++ b/src/plugins/remotelinux/genericdirectuploadstep.cpp @@ -179,7 +179,7 @@ TaskItem GenericDirectUploadStep::statTree(const TreeStorage &sto const auto setupHandler = [=](TaskTree &tree) { UploadStorage *storagePtr = storage.activeStorage(); const QList files = filesToStat(storagePtr); - QList statList{optional, parallelLimit(MaxConcurrentStatCalls)}; + QList statList{finishAllAndDone, parallelLimit(MaxConcurrentStatCalls)}; for (const DeployableFile &file : std::as_const(files)) { QTC_ASSERT(file.isValid(), continue); statList.append(statTask(storagePtr, file, statEndHandler)); @@ -256,7 +256,7 @@ TaskItem GenericDirectUploadStep::chmodTree(const TreeStorage &st if (file.isExecutable()) filesToChmod << file; } - QList chmodList{optional, parallelLimit(MaxConcurrentStatCalls)}; + QList chmodList{finishAllAndDone, parallelLimit(MaxConcurrentStatCalls)}; for (const DeployableFile &file : std::as_const(filesToChmod)) { QTC_ASSERT(file.isValid(), continue); chmodList.append(chmodTask(file)); diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index ecb4296262d..37aea361123 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -131,7 +131,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::unameTask() const emit q->errorMessage(Tr::tr("uname failed.") + '\n'); }; return Group { - optional, + finishAllAndDone, ProcessTask(setup, done, error) }; } @@ -159,7 +159,7 @@ TaskItem GenericLinuxDeviceTesterPrivate::gathererTask() const }; return Group { - optional, + finishAllAndDone, DeviceUsedPortsGathererTask(setup, done, error) }; } diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 3146f066d6e..ac664a69b88 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -204,7 +204,7 @@ SubversionDiffEditorController::SubversionDiffEditorController(IDocument *docume Storage(diffInputStorage), parallel, Group { - optional, + finishAllAndDone, ProcessTask(setupDescription, onDescriptionDone, onDescriptionError) }, Group { diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index e86c135066c..9ddcbc0cbde 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -654,7 +654,7 @@ void tst_Tasking::testTree_data() const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, log, 0, OnDone::Success}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("EmptyOptional") << TestData{storage, root6, log, 0, OnDone::Success}; } @@ -691,7 +691,7 @@ void tst_Tasking::testTree_data() const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); QTest::newRow("DoneStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Success}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("DoneOptional") << TestData{storage, root6, log, 1, OnDone::Success}; } @@ -734,7 +734,7 @@ void tst_Tasking::testTree_data() const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); QTest::newRow("ErrorStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Failure}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("ErrorOptional") << TestData{storage, root6, optionalLog, 1, OnDone::Success}; } @@ -799,7 +799,7 @@ void tst_Tasking::testTree_data() QTest::newRow("StopRootWithStopOnFinished") << TestData{storage, root5, errorErrorLog, 2, OnDone::Failure}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("StopRootWithOptional") << TestData{storage, root6, doneLog, 2, OnDone::Success}; } @@ -883,7 +883,7 @@ void tst_Tasking::testTree_data() QTest::newRow("StopRootAfterDoneWithStopOnFinished") << TestData{storage, root5, doneErrorLog, 3, OnDone::Success}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("StopRootAfterDoneWithOptional") << TestData{storage, root6, doneDoneLog, 3, OnDone::Success}; } @@ -947,7 +947,7 @@ void tst_Tasking::testTree_data() QTest::newRow("StopGroupWithStopOnFinished") << TestData{storage, root5, errorLog, 2, OnDone::Failure}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("StopGroupWithOptional") << TestData{storage, root6, doneLog, 2, OnDone::Failure}; } @@ -1025,7 +1025,7 @@ void tst_Tasking::testTree_data() QTest::newRow("StopGroupAfterDoneWithStopOnFinished") << TestData{storage, root5, shortDoneLog, 3, OnDone::Failure}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("StopGroupAfterDoneWithOptional") << TestData{storage, root6, longDoneLog, 3, OnDone::Failure}; } @@ -1103,7 +1103,7 @@ void tst_Tasking::testTree_data() QTest::newRow("StopGroupAfterErrorWithStopOnFinished") << TestData{storage, root5, shortErrorLog, 3, OnDone::Failure}; - const Group root6 = createRoot(WorkflowPolicy::Optional); + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("StopGroupAfterErrorWithOptional") << TestData{storage, root6, doneLog, 3, OnDone::Failure}; } @@ -1216,7 +1216,7 @@ void tst_Tasking::testTree_data() { const Group root { Storage(storage), - optional, + finishAllAndDone, createFailingTask(1), createFailingTask(2), groupDone(0), diff --git a/tests/manual/tasktree/main.cpp b/tests/manual/tasktree/main.cpp index ac5df4b0f6c..3976e3308dc 100644 --- a/tests/manual/tasktree/main.cpp +++ b/tests/manual/tasktree/main.cpp @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) task_4_4->setBusyTime(3); groupTask_1->setWorkflowPolicy(Tasking::WorkflowPolicy::ContinueOnDone); - groupTask_4->setWorkflowPolicy(Tasking::WorkflowPolicy::Optional); + groupTask_4->setWorkflowPolicy(Tasking::WorkflowPolicy::FinishAllAndDone); groupTask_4_3->setExecuteMode(ExecuteMode::Parallel); groupTask_4_3->setWorkflowPolicy(Tasking::WorkflowPolicy::StopOnError); diff --git a/tests/manual/tasktree/taskwidget.cpp b/tests/manual/tasktree/taskwidget.cpp index e969dbf2d73..ddc56aa77e2 100644 --- a/tests/manual/tasktree/taskwidget.cpp +++ b/tests/manual/tasktree/taskwidget.cpp @@ -133,7 +133,7 @@ GroupWidget::GroupWidget() m_workflowCombo->addItem("Cont On Error", (int)Tasking::WorkflowPolicy::ContinueOnError); m_workflowCombo->addItem("Stop On Done", (int)Tasking::WorkflowPolicy::StopOnDone); m_workflowCombo->addItem("Cont On Done", (int)Tasking::WorkflowPolicy::ContinueOnDone); - m_workflowCombo->addItem("Optional", (int)Tasking::WorkflowPolicy::Optional); + m_workflowCombo->addItem("Optional", (int)Tasking::WorkflowPolicy::FinishAllAndDone); updateWorkflowPolicy(); connect(m_workflowCombo, &QComboBox::currentIndexChanged, this, [this](int index) { m_workflowPolicy = (Tasking::WorkflowPolicy)m_workflowCombo->itemData(index).toInt(); From 827b8ae3765a43bef8ec8193e4210fabdbc141a7 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 29 May 2023 10:24:12 +0300 Subject: [PATCH 1357/1447] TaskWindow: Do not jump to link on right-click Change-Id: I7474fed01d971517ca490ab611e5089c759d9177 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/taskwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 95e15ec5eb7..9ae93c0bbf0 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -701,7 +701,7 @@ void TaskView::mouseMoveEvent(QMouseEvent *e) void TaskView::mouseReleaseEvent(QMouseEvent *e) { - if (m_clickAnchor.isEmpty()) { + if (m_clickAnchor.isEmpty() || e->button() == Qt::RightButton) { TreeView::mouseReleaseEvent(e); return; } From a35fd423647e4c240e1ba8905e215e3e3dd681bc Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 30 May 2023 13:48:01 +0200 Subject: [PATCH 1358/1447] Copilot: position copilot tooltip above cursor rect Change-Id: I37c6572000231334b90f38a2b37f5983c80174a5 Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/plugins/copilot/copilothoverhandler.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/copilot/copilothoverhandler.cpp b/src/plugins/copilot/copilothoverhandler.cpp index b252cedc77d..bf4d3ece104 100644 --- a/src/plugins/copilot/copilothoverhandler.cpp +++ b/src/plugins/copilot/copilothoverhandler.cpp @@ -147,8 +147,12 @@ void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const Q auto tooltipWidget = new CopilotCompletionToolTip(suggestion->completions(), suggestion->currentCompletion(), editorWidget); - const qreal deltay = 2 * editorWidget->textDocument()->fontSettings().lineSpacing(); - ToolTip::show(point - QPoint{0, int(deltay)}, tooltipWidget, editorWidget); + + const QRect cursorRect = editorWidget->cursorRect(editorWidget->textCursor()); + QPoint pos = editorWidget->viewport()->mapToGlobal(cursorRect.topLeft()) + - Utils::ToolTip::offsetFromPosition(); + pos.ry() -= tooltipWidget->sizeHint().height(); + ToolTip::show(pos, tooltipWidget, editorWidget); } } // namespace Copilot::Internal From 7274e135f93d304c009141174f7fc044c0054f3c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 30 May 2023 16:53:10 +0200 Subject: [PATCH 1359/1447] Some VCS: Use the simpler setLayouter overload for settings Change-Id: Idb4b271f5723d1a4ea1809aa41b81fbeb900eb83 Reviewed-by: Reviewed-by: Orgad Shaneh --- src/plugins/bazaar/bazaarsettings.cpp | 6 +++--- src/plugins/fossil/fossilsettings.cpp | 6 +++--- src/plugins/mercurial/mercurialsettings.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp index 344bdc6a095..dc6ef77dd48 100644 --- a/src/plugins/bazaar/bazaarsettings.cpp +++ b/src/plugins/bazaar/bazaarsettings.cpp @@ -66,10 +66,10 @@ BazaarSettings::BazaarSettings() timeout.setLabelText(Tr::tr("Timeout:")); timeout.setSuffix(Tr::tr("s")); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title(Tr::tr("Configuration")), Row { binaryPath } @@ -88,7 +88,7 @@ BazaarSettings::BazaarSettings() Row { logCount, timeout, st } }, st - }.attachTo(widget); + }; }); } diff --git a/src/plugins/fossil/fossilsettings.cpp b/src/plugins/fossil/fossilsettings.cpp index d62f48f1566..0662445b131 100644 --- a/src/plugins/fossil/fossilsettings.cpp +++ b/src/plugins/fossil/fossilsettings.cpp @@ -88,9 +88,9 @@ FossilSettings::FossilSettings() logCount.setToolTip(Tr::tr("The number of recent commit log entries to show. " "Choose 0 to see all entries.")); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title(Tr::tr("Configuration")), Row { binaryPath } @@ -117,7 +117,7 @@ FossilSettings::FossilSettings() }, }, st - }.attachTo(widget); + }; }); } diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp index 0ced239122e..0b493e277bf 100644 --- a/src/plugins/mercurial/mercurialsettings.cpp +++ b/src/plugins/mercurial/mercurialsettings.cpp @@ -48,10 +48,10 @@ MercurialSettings::MercurialSettings() diffIgnoreBlankLines.setSettingsKey("diffIgnoreBlankLines"); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title(Tr::tr("Configuration")), Row { binaryPath } @@ -71,7 +71,7 @@ MercurialSettings::MercurialSettings() }, st - }.attachTo(widget); + }; }); } From 88fd4d7e7f6660a6e0f479efbc727ccfc5ce513d Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 24 May 2023 14:15:44 +0200 Subject: [PATCH 1360/1447] Nim: Use Aspects more directly in NimbleTaskStep Change-Id: I42fb8fd27b45260a62f9058c4c3e294909a72af4 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/nim/project/nimbletaskstep.cpp | 31 ++++++++++------------ 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/plugins/nim/project/nimbletaskstep.cpp b/src/plugins/nim/project/nimbletaskstep.cpp index e072b9422ee..1885a9daa15 100644 --- a/src/plugins/nim/project/nimbletaskstep.cpp +++ b/src/plugins/nim/project/nimbletaskstep.cpp @@ -47,8 +47,8 @@ private: bool validate(); - StringAspect *m_taskName = nullptr; - StringAspect *m_taskArgs = nullptr; + StringAspect m_taskName{this}; + StringAspect m_taskArgs{this}; QStandardItemModel m_tasks; bool m_selecting = false; @@ -62,19 +62,17 @@ NimbleTaskStep::NimbleTaskStep(BuildStepList *parentList, Id id) setDisplayName(display); setCommandLineProvider([this] { - QString args = m_taskName->value() + " " + m_taskArgs->value(); + QString args = m_taskName() + " " + m_taskArgs(); return CommandLine(Nim::nimblePathFromKit(target()->kit()), args, CommandLine::Raw); }); setWorkingDirectoryProvider([this] { return project()->projectDirectory(); }); - m_taskName = addAspect(); - m_taskName->setSettingsKey(Constants::C_NIMBLETASKSTEP_TASKNAME); + m_taskName.setSettingsKey(Constants::C_NIMBLETASKSTEP_TASKNAME); - m_taskArgs = addAspect(); - m_taskArgs->setSettingsKey(Constants::C_NIMBLETASKSTEP_TASKARGS); - m_taskArgs->setDisplayStyle(StringAspect::LineEditDisplay); - m_taskArgs->setLabelText(Tr::tr("Task arguments:")); + m_taskArgs.setSettingsKey(Constants::C_NIMBLETASKSTEP_TASKARGS); + m_taskArgs.setDisplayStyle(StringAspect::LineEditDisplay); + m_taskArgs.setLabelText(Tr::tr("Task arguments:")); } QWidget *NimbleTaskStep::createConfigWidget() @@ -96,15 +94,14 @@ QWidget *NimbleTaskStep::createConfigWidget() QTC_ASSERT(buildSystem, return widget); updateTaskList(); - selectTask(m_taskName->value()); + selectTask(m_taskName()); connect(&m_tasks, &QAbstractItemModel::dataChanged, this, &NimbleTaskStep::onDataChanged); connect(buildSystem, &NimbleBuildSystem::tasksChanged, this, &NimbleTaskStep::updateTaskList); setSummaryUpdater([this] { - return QString("%1: nimble %2 %3") - .arg(displayName(), m_taskName->value(), m_taskArgs->value()); + return QString("%1: nimble %2 %3").arg(displayName(), m_taskName(), m_taskArgs()); }); return widget; @@ -199,24 +196,24 @@ void NimbleTaskStep::uncheckedAllDifferentFrom(QStandardItem *toSkip) void NimbleTaskStep::setTaskName(const QString &name) { - if (m_taskName->value() == name) + if (m_taskName() == name) return; - m_taskName->setValue(name); + m_taskName.setValue(name); selectTask(name); } bool NimbleTaskStep::validate() { - if (m_taskName->value().isEmpty()) + if (m_taskName().isEmpty()) return true; auto nimbleBuildSystem = dynamic_cast(buildSystem()); QTC_ASSERT(nimbleBuildSystem, return false); - auto matchName = [this](const NimbleTask &task) { return task.name == m_taskName->value(); }; + auto matchName = [this](const NimbleTask &task) { return task.name == m_taskName(); }; if (!Utils::contains(nimbleBuildSystem->tasks(), matchName)) { emit addTask(BuildSystemTask(Task::Error, Tr::tr("Nimble task %1 not found.") - .arg(m_taskName->value()))); + .arg(m_taskName()))); emitFaultyConfigurationMessage(); return false; } From 361eb17fbf576c6f00e9bb9dbf0a129a3b725922 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 15:13:41 +0200 Subject: [PATCH 1361/1447] FancyLineEdit: Fix placeholder text color Amends 3dcdbe9069c452e2f0eacb925aa7412e63dc4762 Using the theme's PalettePlaceholderText only works for themes that explicitly set it. Grab it from the application palette instead, which is correct for all themes. Observable by typing something into Locator and removing the typed text again. Change-Id: Iee7f900275ab7bcb37d87a2f7acddfee55fe9f79 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- src/libs/utils/fancylineedit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp index ae931ec1ca0..08b480c88cf 100644 --- a/src/libs/utils/fancylineedit.cpp +++ b/src/libs/utils/fancylineedit.cpp @@ -11,6 +11,7 @@ #include "utilsicons.h" #include "utilstr.h" +#include #include #include #include @@ -126,7 +127,7 @@ FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) : m_completionShortcut(completionShortcut()->key(), parent), m_okTextColor(creatorTheme()->color(Theme::TextColorNormal)), m_errorTextColor(creatorTheme()->color(Theme::TextColorError)), - m_placeholderTextColor(creatorTheme()->color(Theme::PalettePlaceholderText)) + m_placeholderTextColor(QApplication::palette().color(QPalette::PlaceholderText)) { m_completionShortcut.setContext(Qt::WidgetShortcut); From 0b5123cd74e024413b01b7921a5b73df610a829f Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 30 May 2023 16:28:37 +0200 Subject: [PATCH 1362/1447] Copilot: Fix UI text - Change an external link to point to the English language version - Fix capitalization of product names - Add a period to the end of a tooltip Change-Id: Ia46709db9911c0a3bfad252db2ffe0b3f7e5f2d7 Reviewed-by: Reviewed-by: Eike Ziller --- src/plugins/copilot/copilotsettings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index bac2c176afa..b8567f2feb4 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -53,7 +53,7 @@ CopilotSettings::CopilotSettings() nodeJsPath.setHistoryCompleter("Copilot.NodePath.History"); nodeJsPath.setDisplayName(Tr::tr("Node.js Path")); nodeJsPath.setToolTip( - Tr::tr("Select path to node.js executable. See https://nodejs.org/de/download/" + Tr::tr("Select path to node.js executable. See https://nodejs.org/en/download/" "for installation instructions.")); distPath.setExpectedKind(PathChooser::File); @@ -63,7 +63,7 @@ CopilotSettings::CopilotSettings() distPath.setHistoryCompleter("Copilot.DistPath.History"); distPath.setDisplayName(Tr::tr("Agent.js path")); distPath.setToolTip(Tr::tr( - "Select path to agent.js in copilot neovim plugin. See " + "Select path to agent.js in Copilot Neovim plugin. See " "https://github.com/github/copilot.vim#getting-started for installation instructions.")); autoComplete.setDisplayName(Tr::tr("Auto Complete")); @@ -71,7 +71,7 @@ CopilotSettings::CopilotSettings() autoComplete.setLabelText(Tr::tr("Request completions automatically")); autoComplete.setDefaultValue(true); autoComplete.setToolTip(Tr::tr("Automatically request suggestions for the current text cursor " - "position after changes to the document")); + "position after changes to the document.")); initEnableAspect(enableCopilot); } From 7f60d1c2e4d5d416cc5f8bc157303396e4ca0ef4 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 08:40:19 +0200 Subject: [PATCH 1363/1447] VCS: A few more simpler setLayouter calls Change-Id: Ib361740d0e33742620048680720ddafba4cdce12 Reviewed-by: Orgad Shaneh --- src/plugins/cvs/cvssettings.cpp | 6 +++--- src/plugins/perforce/perforcesettings.cpp | 9 +++++---- src/plugins/subversion/subversionsettings.cpp | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/cvs/cvssettings.cpp b/src/plugins/cvs/cvssettings.cpp index e2247f7dbe0..9e1523486fa 100644 --- a/src/plugins/cvs/cvssettings.cpp +++ b/src/plugins/cvs/cvssettings.cpp @@ -59,9 +59,9 @@ CvsSettings::CvsSettings() diffIgnoreBlankLines.setSettingsKey("DiffIgnoreBlankLines"); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title(Tr::tr("Configuration")), Form { @@ -80,7 +80,7 @@ CvsSettings::CvsSettings() } }, st - }.attachTo(widget); + }; }); } diff --git a/src/plugins/perforce/perforcesettings.cpp b/src/plugins/perforce/perforcesettings.cpp index ee02465530e..47ef5a03b35 100644 --- a/src/plugins/perforce/perforcesettings.cpp +++ b/src/plugins/perforce/perforcesettings.cpp @@ -216,7 +216,7 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) setCategory(VcsBase::Constants::VCS_SETTINGS_CATEGORY); setSettings(settings); - setLayouter([settings](QWidget *widget) { + setLayouter([settings] { PerforceSettings &s = *settings; using namespace Layouting; @@ -224,7 +224,8 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) errorLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); errorLabel->setFilled(true); auto testButton = new QPushButton(Tr::tr("Test")); - QObject::connect(testButton, &QPushButton::clicked, widget, [settings, errorLabel, testButton] { + QObject::connect(testButton, &QPushButton::clicked, errorLabel, + [settings, errorLabel, testButton] { testButton->setEnabled(false); auto checker = new PerforceChecker(errorLabel); checker->setUseOverideCursor(true); @@ -271,13 +272,13 @@ PerforceSettingsPage::PerforceSettingsPage(PerforceSettings *settings) } }; - Column { + return Column { config, environment, misc, Row { errorLabel, st, testButton }, st - }.attachTo(widget); + }; }); } diff --git a/src/plugins/subversion/subversionsettings.cpp b/src/plugins/subversion/subversionsettings.cpp index 092c4ee1c05..9b9225ccae7 100644 --- a/src/plugins/subversion/subversionsettings.cpp +++ b/src/plugins/subversion/subversionsettings.cpp @@ -68,10 +68,10 @@ SubversionSettings::SubversionSettings() password.setEnabled(useAuthentication()); }); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title(Tr::tr("Configuration")), Column { binaryPath } @@ -95,7 +95,7 @@ SubversionSettings::SubversionSettings() }, st - }.attachTo(widget); + }; }); } From 96ffcb8d6c75107be6910cd24c0fcfcfc9f81705 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 30 May 2023 17:15:19 +0200 Subject: [PATCH 1364/1447] Terminal: Remove some redundante settings page setup Amends 8b29c0637. Change-Id: Idddcaaaf84cd87a07365d178cf98a8459608c41d Reviewed-by: Reviewed-by: Marcus Tillmanns --- src/plugins/terminal/terminalsettings.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 692af4ec9c5..99e0de0d1f8 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -365,13 +365,11 @@ TerminalSettings::TerminalSettings() { s_instance = this; - setAutoApply(false); setSettingsGroup("Terminal"); setId("Terminal.General"); setDisplayName("Terminal"); setCategory("ZY.Terminal"); setDisplayCategory("Terminal"); - setSettings(&TerminalSettings::instance()); setCategoryIconPath(":/terminal/images/settingscategory_terminal.png"); enableTerminal.setSettingsKey("EnableTerminal"); From 3c7644647b7952e6ca2d8124f3d0b7dbba1b4bd7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 31 May 2023 07:33:36 +0200 Subject: [PATCH 1365/1447] Copilot: Fix Qbs build Change-Id: I0fea791042e78b52fc7c89024d9424f24bbe0a12 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilot.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs index cf59d954caa..714c45543d4 100644 --- a/src/plugins/copilot/copilot.qbs +++ b/src/plugins/copilot/copilot.qbs @@ -5,6 +5,7 @@ QtcPlugin { Depends { name: "Core" } Depends { name: "LanguageClient" } + Depends { name: "ProjectExplorer" } Depends { name: "TextEditor" } Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] } From cc3e940f09421e6e177499dfaddef39c8a1e0f54 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 08:44:05 +0200 Subject: [PATCH 1366/1447] Vcpkg: Add a missing Tr:: Change-Id: Id3e7abdc7c9cfbe975dea9e099a0f088128152e4 Reviewed-by: Christian Stenger --- src/plugins/vcpkg/vcpkgsettings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/vcpkg/vcpkgsettings.cpp b/src/plugins/vcpkg/vcpkgsettings.cpp index a450373ab52..3542ec47910 100644 --- a/src/plugins/vcpkg/vcpkgsettings.cpp +++ b/src/plugins/vcpkg/vcpkgsettings.cpp @@ -4,6 +4,7 @@ #include "vcpkgsettings.h" #include "vcpkgconstants.h" +#include "vcpkgtr.h" #include @@ -50,10 +51,10 @@ VcpkgSettings::VcpkgSettings() using namespace Layouting; return Column { Group { - title(tr("Vcpkg installation")), + title(Tr::tr("Vcpkg installation")), Form { Utils::PathChooser::label(), - Span{ 2, Row{ vcpkgRoot, websiteButton} }, + Span { 2, Row { vcpkgRoot, websiteButton } }, }, }, st, From 8241fc87b4c0dbab95ae469ff4505ddc5bdc9810 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 30 May 2023 14:20:58 +0200 Subject: [PATCH 1367/1447] CppEditor: Fix semantic highlighting ... for the case where the first line with semantic tokens has multiple tokens. This was not considered in the algorithm and uncovered by d6f5d07639c3d0313b758ba6fb7cc5eb57d188ef. Also improve variable names and comments. Fixes: QTCREATORBUG-29218 Change-Id: I0a1927c21edd70a3a91efc902e7e6ad2c734c91f Reviewed-by: Orgad Shaneh Reviewed-by: David Schulz --- .../texteditor/semantichighlighter.cpp | 24 +++++++------ .../highlighter/tst_highlighter.cpp | 35 +++++++++++++++++++ 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/plugins/texteditor/semantichighlighter.cpp b/src/plugins/texteditor/semantichighlighter.cpp index 68b1792ca84..30cb9cf729a 100644 --- a/src/plugins/texteditor/semantichighlighter.cpp +++ b/src/plugins/texteditor/semantichighlighter.cpp @@ -82,26 +82,28 @@ void SemanticHighlighter::incrementalApplyExtraAdditionalFormats(SyntaxHighlight if (to <= from) return; - const int firstResultBlockNumber = int(future.resultAt(from).line) - 1; + const int resultStartLine = future.resultAt(from).line; + int formattingStartLine = 1; - // blocks between currentBlockNumber and the last block with results will - // be cleaned of additional extra formats if they have no results - int currentBlockNumber = 0; + // Find the line on which to start formatting, where "formatting" means to either + // clear out formats from outdated document versions (if there is no current result + // on that line), or apply the format corresponding to the respective result. + // Note that if there are earlier results on the same line, we have to make sure they + // get re-applied by adapting the from variable accordingly. for (int i = from - 1; i >= 0; --i) { const HighlightingResult &result = future.resultAt(i); - const int blockNumber = int(result.line) - 1; - if (blockNumber < firstResultBlockNumber) { - // stop! found where last format stopped - currentBlockNumber = blockNumber + 1; - // add previous results for the same line to avoid undoing their formats + if (result.line == resultStartLine) { + from = i; + } else if (result.line < resultStartLine) { + formattingStartLine = result.line + 1; from = i + 1; break; } } QTextDocument *doc = highlighter->document(); - QTC_ASSERT(currentBlockNumber < doc->blockCount(), return); - QTextBlock currentBlock = doc->findBlockByNumber(currentBlockNumber); + QTC_ASSERT(formattingStartLine <= doc->blockCount(), return); + QTextBlock currentBlock = doc->findBlockByNumber(formattingStartLine - 1); std::map> formatRanges; for (int i = from; i < to; ++i) { diff --git a/tests/auto/texteditor/highlighter/tst_highlighter.cpp b/tests/auto/texteditor/highlighter/tst_highlighter.cpp index 163699c0cb1..e3f4e3dced6 100644 --- a/tests/auto/texteditor/highlighter/tst_highlighter.cpp +++ b/tests/auto/texteditor/highlighter/tst_highlighter.cpp @@ -301,6 +301,41 @@ void tst_highlighter::test_incrementalApplyAdditionalFormats() // should have no results since the new results do not contain a highlight at that position formats = emptyLineBlock.layout()->formats(); QVERIFY(formats.isEmpty()); + + // QTCREATORBUG-29218 + highlighter->clearAllExtraFormats(); + const HighlightingResults bug29218Results{HighlightingResult(1, 1, 2, 0), + HighlightingResult(1, 3, 2, 1)}; + QFutureInterface fi29218; + fi29218.reportResults(bug29218Results); + formats = firstBlock.layout()->formats(); + QVERIFY(formats.isEmpty()); + SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter, + fi29218.future(), + 0, + 1, + formatHash); + formats = firstBlock.layout()->formats(); + QCOMPARE(formats.size(), 1); + QCOMPARE(formats.at(0).format.fontItalic(), true); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 2); + SemanticHighlighter::incrementalApplyExtraAdditionalFormats(highlighter, + fi29218.future(), + 1, + 2, + formatHash); + formats = firstBlock.layout()->formats(); + QCOMPARE(formats.size(), 2); + QCOMPARE(formats.at(0).format.fontItalic(), true); + QCOMPARE(formats.at(0).format.fontOverline(), false); + QCOMPARE(formats.at(0).start, 0); + QCOMPARE(formats.at(0).length, 2); + QCOMPARE(formats.at(1).format.fontItalic(), false); + QCOMPARE(formats.at(1).format.fontOverline(), true); + QCOMPARE(formats.at(1).start, 2); + QCOMPARE(formats.at(1).length, 2); } void tst_highlighter::cleanup() From 676d06d76822f8c3d4797c9401461bd984bdda07 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 30 May 2023 17:04:14 +0200 Subject: [PATCH 1368/1447] Use simpler IOptionPage::setLayouter overload in a few more places Change-Id: Id3745dab4363279219062462492b3a3e789776be Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/autotest/ctest/ctestsettings.cpp | 6 +++--- src/plugins/cmakeprojectmanager/cmakeformatter.cpp | 6 +++--- src/plugins/nim/settings/nimsettings.cpp | 6 +++--- src/plugins/projectexplorer/buildpropertiessettings.cpp | 6 +++--- src/plugins/qmakeprojectmanager/qmakesettings.cpp | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp index e707c3edb09..a2f3e904270 100644 --- a/src/plugins/autotest/ctest/ctestsettings.cpp +++ b/src/plugins/autotest/ctest/ctestsettings.cpp @@ -20,8 +20,8 @@ CTestSettings::CTestSettings(Id settingsId) setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayName(Tr::tr("CTest")); - setLayouter([this](QWidget *w) { - Row { Form { + setLayouter([this] { + return Row { Form { outputOnFail, br, scheduleRandom, br, stopOnFailure, br, @@ -39,7 +39,7 @@ CTestSettings::CTestSettings(Id settingsId) Row { testLoad, threshold} } } - }, st }.attachTo(w); + }, st }; }); outputOnFail.setSettingsKey("OutputOnFail"); diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp index 295b664b9a0..dca6d47e203 100644 --- a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp @@ -65,9 +65,9 @@ public: autoFormatMime.setDefaultValue("text/x-cmake"); autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:")); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Row { Tr::tr("CMakeFormat command:"), command }, Space(10), Group { @@ -79,7 +79,7 @@ public: } }, st - }.attachTo(widget); + }; }); ActionContainer *menu = ActionManager::createMenu(Constants::CMAKEFORMATTER_MENU_ID); diff --git a/src/plugins/nim/settings/nimsettings.cpp b/src/plugins/nim/settings/nimsettings.cpp index fdf44ccd366..fac77109fde 100644 --- a/src/plugins/nim/settings/nimsettings.cpp +++ b/src/plugins/nim/settings/nimsettings.cpp @@ -33,15 +33,15 @@ NimSettings::NimSettings() setDisplayCategory(Tr::tr("Nim")); setCategoryIconPath(":/nim/images/settingscategory_nim.png"); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Group { title("Nimsuggest"), Column { nimSuggestPath } }, st - }.attachTo(widget); + }; }); // code style factory diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp index b409a2a2e2c..88c63b5f5c1 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.cpp +++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp @@ -29,10 +29,10 @@ BuildPropertiesSettings::BuildPropertiesSettings() setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); setSettings(this); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { Form { buildDirectoryTemplate, br, separateDebugInfo, br, @@ -40,7 +40,7 @@ BuildPropertiesSettings::BuildPropertiesSettings() qtQuickCompiler }, st - }.attachTo(widget); + }; }); registerAspect(&buildDirectoryTemplate); diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.cpp b/src/plugins/qmakeprojectmanager/qmakesettings.cpp index 292851e444b..f920381d15e 100644 --- a/src/plugins/qmakeprojectmanager/qmakesettings.cpp +++ b/src/plugins/qmakeprojectmanager/qmakesettings.cpp @@ -51,14 +51,14 @@ QmakeSettings::QmakeSettings() ignoreSystemFunction.setFromSettingsTransformation(invertBoolVariant); ignoreSystemFunction.setToSettingsTransformation(invertBoolVariant); - setLayouter([this](QWidget *widget) { + setLayouter([this] { using namespace Layouting; - Column { + return Column { warnAgainstUnalignedBuildDir, alwaysRunQmake, ignoreSystemFunction, st - }.attachTo(widget); + }; }); readSettings(); From 227c25ef2e05e0b4f122fe96b18d75e6b70493f6 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 31 May 2023 07:55:51 +0200 Subject: [PATCH 1369/1447] Tests: Fix Qbs build Change-Id: I26846091123f484f1906ce04c3c7d93134f17d80 Reviewed-by: Reviewed-by: Jarek Kobus --- tests/auto/solutions/tasking/tst_tasking.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 9ddcbc0cbde..051b807842b 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -12,7 +12,7 @@ using namespace std::chrono_literals; using namespace Tasking; template -class TASKING_EXPORT DurationTaskAdapter : public TaskAdapter +class DurationTaskAdapter : public TaskAdapter { public: DurationTaskAdapter() { *task() = std::chrono::milliseconds{0}; } From e38b2cab44c5817ecde5242dd6d8ee1971266c3b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 30 May 2023 16:49:00 +0200 Subject: [PATCH 1370/1447] DeviceShell: Refrain from using potentially invalidated iterators The stored container iterator, after container is modified, may be already invalidated. Avoid storing the iterators and do the search again after potential container modification. Use QHash instead of QMap for faster insertions / lookups. Amends 0135c47849bb1962fd379de210a01a918c6e8b4e Change-Id: I0a4641d3b410836a5b3b9be252059e4e37fa94e3 Reviewed-by: Marcus Tillmanns --- src/libs/utils/deviceshell.cpp | 3 ++- src/libs/utils/deviceshell.h | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp index ae983b6f482..f96c5da8f2d 100644 --- a/src/libs/utils/deviceshell.cpp +++ b/src/libs/utils/deviceshell.cpp @@ -104,7 +104,7 @@ RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData) QWaitCondition waiter; const int id = ++m_currentId; - const auto it = m_commandOutput.insert(id, CommandRun{{-1, {}, {}}, &waiter}); + m_commandOutput.insert(id, CommandRun{{-1, {}, {}}, &waiter}); QMetaObject::invokeMethod(m_shellProcess.get(), [this, id, cmd, stdInData] { const QString command = QString("%1 \"%2\" %3\n").arg(id) @@ -115,6 +115,7 @@ RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData) waiter.wait(&m_commandMutex); + const auto it = m_commandOutput.constFind(id); const RunResult result = *it; m_commandOutput.erase(it); diff --git a/src/libs/utils/deviceshell.h b/src/libs/utils/deviceshell.h index 052aac1838a..e5bc4ad7afe 100644 --- a/src/libs/utils/deviceshell.h +++ b/src/libs/utils/deviceshell.h @@ -7,7 +7,7 @@ #include "fileutils.h" -#include +#include #include #include #include @@ -78,8 +78,7 @@ private: int m_currentId{0}; QMutex m_commandMutex; - // QMap is used here to preserve iterators - QMap m_commandOutput; + QHash m_commandOutput; QByteArray m_commandBuffer; State m_shellScriptState = State::Unknown; From 9051e6ccaeaefb0fef5457810c2d53c613d5eef4 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 30 May 2023 17:10:28 +0200 Subject: [PATCH 1371/1447] Squish: Use PagedSettings for main settings Change-Id: I6314b746284e8fd032d32170bf353da544c7793f Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/squish/squishplugin.cpp | 2 -- src/plugins/squish/squishsettings.cpp | 44 ++++++++++++--------------- src/plugins/squish/squishsettings.h | 10 +----- 3 files changed, 20 insertions(+), 36 deletions(-) diff --git a/src/plugins/squish/squishplugin.cpp b/src/plugins/squish/squishplugin.cpp index c8b779aac06..caeb787de69 100644 --- a/src/plugins/squish/squishplugin.cpp +++ b/src/plugins/squish/squishplugin.cpp @@ -43,7 +43,6 @@ public: bool initializeGlobalScripts(); SquishSettings m_squishSettings; - SquishSettingsPage m_settingsPage{&m_squishSettings}; SquishTestTreeModel m_treeModel; SquishNavigationWidgetFactory m_navigationWidgetFactory; ObjectsMapEditorFactory m_objectsMapEditorFactory; @@ -57,7 +56,6 @@ SquishPluginPrivate::SquishPluginPrivate() { qRegisterMetaType("SquishResultItem*"); - m_squishSettings.readSettings(ICore::settings()); m_outputPane = SquishOutputPane::instance(); m_squishTools = new SquishTools; initializeMenuEntries(); diff --git a/src/plugins/squish/squishsettings.cpp b/src/plugins/squish/squishsettings.cpp index 23ccc22dfec..f7758a844d3 100644 --- a/src/plugins/squish/squishsettings.cpp +++ b/src/plugins/squish/squishsettings.cpp @@ -33,6 +33,12 @@ namespace Internal { SquishSettings::SquishSettings() { + setId("A.Squish.General"); + setDisplayName(Tr::tr("General")); + setCategory(Constants::SQUISH_SETTINGS_CATEGORY); + setDisplayCategory("Squish"); + setCategoryIcon(Icon({{":/squish/images/settingscategory_squish.png", + Theme::PanelTextColorDark}}, Icon::Tint)); setSettingsGroup("Squish"); setAutoApply(false); @@ -85,6 +91,19 @@ SquishSettings::SquishSettings() serverHost.setEnabled(!checked); serverPort.setEnabled(!checked); }); + + setLayouter([this] { + using namespace Layouting; + return Form { + squishPath, br, + licensePath, br, + local, serverHost, serverPort, br, + verbose, br, + minimizeIDE, br, + }; + }); + + readSettings(); } Utils::FilePath SquishSettings::scriptsPath(Language language) const @@ -101,31 +120,6 @@ Utils::FilePath SquishSettings::scriptsPath(Language language) const return scripts.isReadableDir() ? scripts : Utils::FilePath(); } -SquishSettingsPage::SquishSettingsPage(SquishSettings *settings) -{ - setId("A.Squish.General"); - setDisplayName(Tr::tr("General")); - setCategory(Constants::SQUISH_SETTINGS_CATEGORY); - setDisplayCategory("Squish"); - setCategoryIcon(Icon({{":/squish/images/settingscategory_squish.png", - Theme::PanelTextColorDark}}, Icon::Tint)); - - setSettings(settings); - - setLayouter([settings](QWidget *widget) { - SquishSettings &s = *settings; - using namespace Layouting; - - Form { - s.squishPath, br, - s.licensePath, br, - s.local, s.serverHost, s.serverPort, br, - s.verbose, br, - s.minimizeIDE, br, - }.attachTo(widget); - }); -} - SquishServerSettings::SquishServerSettings() { autTimeout.setLabel(Tr::tr("Maximum startup time:")); diff --git a/src/plugins/squish/squishsettings.h b/src/plugins/squish/squishsettings.h index 180f2eb84fe..0e25a4215e3 100644 --- a/src/plugins/squish/squishsettings.h +++ b/src/plugins/squish/squishsettings.h @@ -5,8 +5,6 @@ #include -#include - #include #include @@ -31,7 +29,7 @@ public: Utils::BoolAspect animatedCursor{this}; }; -class SquishSettings : public Utils::AspectContainer +class SquishSettings : public Core::PagedSettings { public: SquishSettings(); @@ -47,12 +45,6 @@ public: Utils::BoolAspect minimizeIDE{this}; }; -class SquishSettingsPage final : public Core::IOptionsPage -{ -public: - SquishSettingsPage(SquishSettings *settings); -}; - class SquishServerSettingsDialog : public QDialog { public: From 1a9025cdd52628c13fa7c325bf34475e3e64a3f7 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 29 May 2023 16:57:08 +0200 Subject: [PATCH 1372/1447] TaskTree: Add docs for Workflow Policy Transform it form TaskTree's description into WorkflowPolicy enum docs. Document global workflow policy elements and global workflowPolicy() function. Change-Id: I4af3f7ffa703bbb1a9370e2fd1f9242a68131295 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Leena Miettinen --- src/libs/solutions/tasking/tasktree.cpp | 227 ++++++++++++++++-------- 1 file changed, 157 insertions(+), 70 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 054647752af..62243f373a1 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -48,6 +48,114 @@ private: \brief The TaskItem class represents the basic element for composing nested tree structures. */ +/*! + \enum Tasking::WorkflowPolicy + + This enum describes the possible behavior of the Group element when any group's child task + finishes its execution. It's also used when the running Group is stopped. + + \value StopOnError + Default. Corresponds to the stopOnError global element. + If any child task finishes with an error, the group stops and finishes with an error. + If all child tasks finished with success, the group finishes with success. + If a group is empty, it finishes with success. + \value ContinueOnError + Corresponds to the continueOnError global element. + Similar to stopOnError, but in case any child finishes with an error, + the execution continues until all tasks finish, and the group reports an error + afterwards, even when some other tasks in the group finished with success. + If all child tasks finish successfully, the group finishes with success. + If a group is empty, it finishes with success. + \value StopOnDone + Corresponds to the stopOnDone global element. + If any child task finishes with success, the group stops and finishes with success. + If all child tasks finished with an error, the group finishes with an error. + If a group is empty, it finishes with an error. + \value ContinueOnDone + Corresponds to the continueOnDone global element. + Similar to stopOnDone, but in case any child finishes successfully, + the execution continues until all tasks finish, and the group reports success + afterwards, even when some other tasks in the group finished with an error. + If all child tasks finish with an error, the group finishes with an error. + If a group is empty, it finishes with an error. + \value StopOnFinished + Corresponds to the stopOnFinished global element. + The group starts as many tasks as it can. When any task finishes, + the group stops and reports the task's result. + Useful only in parallel mode. + In sequential mode, only the first task is started, and when finished, + the group finishes too, so the other tasks are always skipped. + If a group is empty, it finishes with an error. + \value FinishAllAndDone + Corresponds to the finishAllAndDone global element. + The group executes all tasks and ignores their return results. When all + tasks finished, the group finishes with success. + If a group is empty, it finishes with success. + \value FinishAllAndError + Corresponds to the finishAllAndError global element. + The group executes all tasks and ignores their return results. When all + tasks finished, the group finishes with an error. + If a group is empty, it finishes with an error. + + Whenever a child task's result causes the Group to stop, + i.e. in case of StopOnError, StopOnDone, or StopOnFinished policies, + the Group stops the other running child tasks (if any - for example in parallel mode), + and skips executing tasks it has not started yet (for example, in the sequential mode - + those, that are placed after the failed task). Both stopping and skipping child tasks + may happen when parallelLimit is used. + + The table below summarizes the differences between various workflow policies: + + \table + \header + \li \l WorkflowPolicy + \li Executes all child tasks + \li Result + \li Result when the group is empty + \row + \li StopOnError + \li Stops when any child task finished with an error and reports an error + \li An error when at least one child task failed, success otherwise + \li Success + \row + \li ContinueOnError + \li Yes + \li An error when at least one child task failed, success otherwise + \li Success + \row + \li StopOnDone + \li Stops when any child task finished with success and reports success + \li Success when at least one child task succeeded, an error otherwise + \li An error + \row + \li ContinueOnDone + \li Yes + \li Success when at least one child task succeeded, an error otherwise + \li An error + \row + \li StopOnFinished + \li Stops when any child task finished and reports child task's result + \li Success or an error, depending on the finished child task's result + \li An error + \row + \li FinishAllAndDone + \li Yes + \li Success + \li Success + \row + \li FinishAllAndError + \li Yes + \li An error + \li An error + \endtable + + If a child of a group is also a group, the child group runs its tasks according to its own + workflow policy. When a parent group stops the running child group because + of parent group's workflow policy, i.e. when the StopOnError, StopOnDone, or StopOnFinished + policy was used for the parent, the child group's result is reported according to the + \b Result column and to the \b {child group's workflow policy} row in the table above. +*/ + /*! \variable sequential A convenient global group's element describing the sequential execution mode. @@ -74,6 +182,43 @@ private: \sa sequential, parallelLimit */ +/*! + \variable stopOnError + A convenient global group's element describing the StopOnError workflow policy. + + This is the default workflow policy of the Group element. +*/ + +/*! + \variable continueOnError + A convenient global group's element describing the ContinueOnError workflow policy. +*/ + +/*! + \variable stopOnDone + A convenient global group's element describing the StopOnDone workflow policy. +*/ + +/*! + \variable continueOnDone + A convenient global group's element describing the ContinueOnDone workflow policy. +*/ + +/*! + \variable stopOnFinished + A convenient global group's element describing the StopOnFinished workflow policy. +*/ + +/*! + \variable finishAllAndDone + A convenient global group's element describing the FinishAllAndDone workflow policy. +*/ + +/*! + \variable finishAllAndError + A convenient global group's element describing the FinishAllAndError workflow policy. +*/ + /*! \enum Tasking::TaskAction @@ -244,6 +389,14 @@ TaskItem parallelLimit(int limit) return Group::parallelLimit(qMax(limit, 0)); } +/*! + Constructs a group's workflow policy element for a given \a policy. + + For convenience, global elements may be used instead. + + \sa stopOnError, continueOnError, stopOnDone, continueOnDone, stopOnFinished, finishAllAndDone, + finishAllAndError, WorkflowPolicy +*/ TaskItem workflowPolicy(WorkflowPolicy policy) { return Group::workflowPolicy(policy); @@ -1332,77 +1485,11 @@ void TaskNode::invokeEndHandler(bool success) \section2 Workflow Policy The workflow policy element in a Group specifies how the group should behave - when any of its \e direct child's tasks finish: + when any of its \e direct child's tasks finish. For a detailed description of possible + policies, refer to WorkflowPolicy. - \table - \header - \li Workflow Policy - \li Description - \row - \li stopOnError - \li Default. If a task finishes with an error, the group: - \list 1 - \li Stops the running tasks (if any - for example, in parallel - mode). - \li Skips executing tasks it has not started yet (for example, in the - sequential mode - those, that are placed after the failed task). - \li Immediately finishes with an error. - \endlist - If all child tasks finish successfully, the group finishes with success. - \row - \li continueOnError - \li Similar to stopOnError, but in case any child finishes with - an error, the execution continues until all tasks finish, - and the group reports an error afterwards, even when some other - tasks in group finished with success. - If a task finishes with an error, the group: - \list 1 - \li Continues executing the tasks that are running or have not - started yet. - \li Finishes with an error when all tasks finish. - \endlist - If all tasks finish successfully, the group finishes with success. - \row - \li stopOnDone - \li If a task finishes with success, the group: - \list 1 - \li Stops the running tasks (if any - for example, in parallel - mode). - \li Skips executing tasks it has not started yet (for example, in the - sequential mode - those, that are placed after the successfully finished task). - \li Immediately finishes with success. - \endlist - If all tasks finish with an error, the group finishes with an error. - \row - \li continueOnDone - \li Similar to stopOnDone, but in case any child finishes - successfully, the execution continues until all tasks finish, - and the group reports success afterwards, even when some other - tasks in group finished with an error. - If a task finishes with success, the group: - \list 1 - \li Continues executing the tasks that are running or have not - started yet. - \li Finishes with success when all tasks finish. - \endlist - If all tasks finish with an error, the group finishes with an error. - \row - \li stopOnFinished - \li The group starts as many tasks as it can. When a task finishes, - the group stops and reports the task's result. - Useful only in parallel mode. - In sequential mode, only the first task is started, and when finished, - the group finishes too, so the other tasks are ignored. - \row - \li finishAllAndDone - \li The group executes all tasks and ignores their return state. When all - tasks finish, the group finishes with success. - \endtable - - When a Group is empty, it finishes immediately with success, - regardless of its workflow policy. - If a child of a group is also a group, the child group - runs its tasks according to its own workflow policy. + If a child of a group is also a group, the child group runs its tasks + according to its own workflow policy. \section2 Storage From 43d59448735f676cd31625f14abae05d5339baad Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 31 May 2023 11:53:42 +0200 Subject: [PATCH 1373/1447] CoPilot: Fix a warning about an unused arg Change-Id: I8b4e552aac0931fea2af4ecc5e70a25c39871fab Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/copilothoverhandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/copilot/copilothoverhandler.cpp b/src/plugins/copilot/copilothoverhandler.cpp index bf4d3ece104..135cbd8390f 100644 --- a/src/plugins/copilot/copilothoverhandler.cpp +++ b/src/plugins/copilot/copilothoverhandler.cpp @@ -139,6 +139,7 @@ void CopilotHoverHandler::identifyMatch(TextEditorWidget *editorWidget, void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) { + Q_UNUSED(point) auto *suggestion = dynamic_cast(TextDocumentLayout::suggestion(m_block)); if (!suggestion) From ff2ed7d94b08130abef9db8ab38169e1778598f3 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 08:47:33 +0200 Subject: [PATCH 1374/1447] CppCheck: Move to simpler setLayouter calls Change-Id: Id0e9f1adfe730f6067ade9472db597e3a12fc2e3 Reviewed-by: Christian Stenger --- src/plugins/cppcheck/cppcheckoptions.cpp | 8 ++++---- src/plugins/cppcheck/cppcheckoptions.h | 2 +- src/plugins/cppcheck/cppcheckplugin.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/cppcheck/cppcheckoptions.cpp b/src/plugins/cppcheck/cppcheckoptions.cpp index 8392f64600c..1289ba0e0e2 100644 --- a/src/plugins/cppcheck/cppcheckoptions.cpp +++ b/src/plugins/cppcheck/cppcheckoptions.cpp @@ -108,11 +108,11 @@ CppcheckOptions::CppcheckOptions() readSettings(); } -std::function CppcheckOptions::layouter() +std::function CppcheckOptions::layouter() { - return [this](QWidget *widget) { + return [this] { using namespace Layouting; - Form { + return Form { binary, br, Tr::tr("Checks:"), Flow { warning, @@ -132,7 +132,7 @@ std::function CppcheckOptions::layouter() addIncludePaths, guessArguments } - }.attachTo(widget); + }; }; } diff --git a/src/plugins/cppcheck/cppcheckoptions.h b/src/plugins/cppcheck/cppcheckoptions.h index a6ccdd98ba0..eb3e1c7ddbf 100644 --- a/src/plugins/cppcheck/cppcheckoptions.h +++ b/src/plugins/cppcheck/cppcheckoptions.h @@ -12,7 +12,7 @@ class CppcheckOptions final : public Core::PagedSettings public: CppcheckOptions(); - std::function layouter(); + std::function layouter(); Utils::FilePathAspect binary{this}; Utils::BoolAspect warning{this}; diff --git a/src/plugins/cppcheck/cppcheckplugin.cpp b/src/plugins/cppcheck/cppcheckplugin.cpp index 890e2e3c0ad..b025762c8c6 100644 --- a/src/plugins/cppcheck/cppcheckplugin.cpp +++ b/src/plugins/cppcheck/cppcheckplugin.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -111,8 +112,7 @@ void CppcheckPluginPrivate::startManualRun() manualRunTool.updateOptions(); - auto optionsWidget = new QWidget; - options.layouter()(optionsWidget); + auto optionsWidget = options.layouter()().emerge(); ManualRunDialog dialog(optionsWidget, project); if (dialog.exec() == ManualRunDialog::Rejected) From 7bd06829c4907bdf8a9e4dcf630884f3625da7e7 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 31 May 2023 09:54:53 +0200 Subject: [PATCH 1375/1447] Tr/VCS: Fix various issues with translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inserting the name for the "commit" operation into messages relies on a certain sentence structure and doesn't work with translations. Same for "optional" error messages. Use different complete messages for the different cases instead. Avoid explicit line endings, use automatic word wrap instead. Add some quotes and full stops. Fix message with plural. Don't use %n for constant number (inline in message with assert). Improve confusing tool tip for instant blame. Change-Id: Ic8453763279753ebd5898858951acddcf311e6e4 Reviewed-by: Qt CI Bot Reviewed-by: Oswald Buddenhagen Reviewed-by: Orgad Shaneh Reviewed-by: André Hartmann --- share/qtcreator/translations/qtcreator_de.ts | 17 +++++--------- src/plugins/clearcase/clearcaseplugin.cpp | 22 +++++++++++++++++++ src/plugins/fossil/fossilcommitwidget.cpp | 4 ++-- src/plugins/fossil/pullorpushdialog.cpp | 2 +- .../fossil/wizard/projects/vcs/wizard.json | 2 +- src/plugins/git/gitclient.cpp | 2 +- src/plugins/git/gitsettings.cpp | 4 ++-- src/plugins/perforce/perforceplugin.cpp | 22 +++++++++++++++++++ src/plugins/vcsbase/submiteditorwidget.cpp | 7 +++--- src/plugins/vcsbase/vcsbaseplugin.cpp | 18 +++++++++++++++ src/plugins/vcsbase/vcsbaseplugin.h | 3 +++ src/plugins/vcsbase/vcsbasesubmiteditor.cpp | 12 +++------- 12 files changed, 84 insertions(+), 31 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 4b2e4bc008f..c6e2a4cab88 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -27194,12 +27194,8 @@ zu deaktivieren, deaktiviert auch die folgenden Plugins: Privat - Create a private check-in that is never synced. -Children of private check-ins are automatically private. -Private check-ins are not pushed to the remote repository by default. - Erstelle einen privaten Check-In, der niemals synchronisiert wird. -Kinder von privaten Check-Ins sind automatisch privat. -Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht. + Create a private check-in that is never synced. Children of private check-ins are automatically private. Private check-ins are not pushed to the remote repository by default. + Erstelle einen privaten Check-In, der niemals synchronisiert wird. Kinder von privaten Check-Ins sind automatisch privat. Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht. Tag names to apply; comma-separated. @@ -53204,12 +53200,9 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch Hint: The second line of a commit message should be empty. Hinweis: Die zweite Zeile der Beschreibung sollte leer sein. - - <p>Writing good commit messages</p><ul><li>Avoid very short commit messages.</li><li>Consider the first line as subject (like in email) and keep it shorter than %n characters.</li><li>After an empty second line, a longer description can be added.</li><li>Describe why the change was done, not how it was done.</li></ul> - - <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als ein Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul> - <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als %n Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul> - + + <p>Writing good commit messages</p><ul><li>Avoid very short commit messages.</li><li>Consider the first line as a subject (like in emails) and keep it shorter than 72 characters.</li><li>After an empty second line, a longer description can be added.</li><li>Describe why the change was done, not how it was done.</li></ul> + <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als 72 Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul> Update in progress diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index aa5c598c84c..943ffa194a4 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -227,6 +227,10 @@ private: Q_INVOKABLE void updateStatusActions(); QString commitDisplayName() const final; + QString commitAbortTitle() const final; + QString commitAbortMessage() const final; + QString commitErrorMessage(const QString &error) const final; + void checkOutCurrentFile(); void addCurrentFile(); void undoCheckOutCurrent(); @@ -948,9 +952,27 @@ void ClearCasePluginPrivate::updateActions(VcsBasePluginPrivate::ActionState as) QString ClearCasePluginPrivate::commitDisplayName() const { + //: Name of the "commit" action of the VCS return Tr::tr("Check In"); } +QString ClearCasePluginPrivate::commitAbortTitle() const +{ + return Tr::tr("Close Check In Editor"); +} + +QString ClearCasePluginPrivate::commitAbortMessage() const +{ + return Tr::tr("Closing this editor will abort the check in."); +} + +QString ClearCasePluginPrivate::commitErrorMessage(const QString &error) const +{ + if (error.isEmpty()) + return Tr::tr("Cannot check in."); + return Tr::tr("Cannot check in: %1.").arg(error); +} + void ClearCasePluginPrivate::checkOutCurrentFile() { const VcsBasePluginState state = currentState(); diff --git a/src/plugins/fossil/fossilcommitwidget.cpp b/src/plugins/fossil/fossilcommitwidget.cpp index 355a792bfda..72fba5ef86f 100644 --- a/src/plugins/fossil/fossilcommitwidget.cpp +++ b/src/plugins/fossil/fossilcommitwidget.cpp @@ -93,8 +93,8 @@ FossilCommitWidget::FossilCommitWidget() : m_commitPanel(new QWidget) m_invalidBranchLabel->setType(InfoLabel::Error); m_isPrivateCheckBox = new QCheckBox(Tr::tr("Private")); - m_isPrivateCheckBox->setToolTip(Tr::tr("Create a private check-in that is never synced.\n" - "Children of private check-ins are automatically private.\n" + m_isPrivateCheckBox->setToolTip("" + Tr::tr("Create a private check-in that is never synced. " + "Children of private check-ins are automatically private. " "Private check-ins are not pushed to the remote repository by default.")); m_tagsLineEdit = new QLineEdit; diff --git a/src/plugins/fossil/pullorpushdialog.cpp b/src/plugins/fossil/pullorpushdialog.cpp index 5ebf9869d3f..b6473a68b41 100644 --- a/src/plugins/fossil/pullorpushdialog.cpp +++ b/src/plugins/fossil/pullorpushdialog.cpp @@ -34,7 +34,7 @@ PullOrPushDialog::PullOrPushDialog(Mode mode, QWidget *parent) m_localPathChooser->setPromptDialogFilter(Tr::tr(Constants::FOSSIL_FILE_FILTER)); m_urlButton = new QRadioButton(Tr::tr("Specify URL:")); - m_urlButton->setToolTip(Tr::tr("For example: https://[user[:pass]@]host[:port]/[path]")); + m_urlButton->setToolTip(Tr::tr("For example: \"https://[user[:pass]@]host[:port]/[path]\".")); m_urlLineEdit = new QLineEdit; m_urlLineEdit->setEnabled(false); diff --git a/src/plugins/fossil/wizard/projects/vcs/wizard.json b/src/plugins/fossil/wizard/projects/vcs/wizard.json index 56e08b63774..7f5fb174520 100644 --- a/src/plugins/fossil/wizard/projects/vcs/wizard.json +++ b/src/plugins/fossil/wizard/projects/vcs/wizard.json @@ -86,7 +86,7 @@ { "name": "Repo", "trDisplayName": "Remote repository:", - "trToolTip": "For example: https://[user[:pass]@]host[:port]/[path]", + "trToolTip": "For example: \"https://[user[:pass]@]host[:port]/[path]\".", "type": "LineEdit", "enabled": "%{isCloneRepo}", "mandatory": false diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index dd335dcc650..935b56291ff 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -2873,7 +2873,7 @@ bool GitClient::addAndCommit(const FilePath &repositoryDirectory, GitPlugin::updateCurrentBranch(); return true; } - VcsOutputWindow::appendError(Tr::tr("Cannot commit %n files", nullptr, commitCount) + "\n"); + VcsOutputWindow::appendError(Tr::tr("Cannot commit %n file(s)", nullptr, commitCount) + "\n"); return false; } diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 6cbec254445..4ebf7debeed 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -90,8 +90,8 @@ GitSettings::GitSettings() instantBlame.setSettingsKey("Git Instant"); instantBlame.setDefaultValue(true); instantBlame.setLabelText(Tr::tr("Add instant blame annotations to editor")); - instantBlame.setToolTip(Tr::tr("Directly annotate each line in the editor " - "when scrolling through the document.")); + instantBlame.setToolTip( + Tr::tr("Annotate the current line in the editor with Git \"blame\" output.")); graphLog.setSettingsKey("GraphLog"); diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 5a7e74450dd..ae61d12d342 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -226,6 +226,10 @@ public: void discardCommit() override { cleanCommitMessageFile(); } QString commitDisplayName() const final; + QString commitAbortTitle() const final; + QString commitAbortMessage() const final; + QString commitErrorMessage(const QString &error) const final; + void p4Diff(const PerforceDiffParameters &p); void openCurrentFile(); @@ -1443,9 +1447,27 @@ void PerforceDiffConfig::triggerReRun() QString PerforcePluginPrivate::commitDisplayName() const { + //: Name of the "commit" action of the VCS return Tr::tr("Submit"); } +QString PerforcePluginPrivate::commitAbortTitle() const +{ + return Tr::tr("Close Submit Editor"); +} + +QString PerforcePluginPrivate::commitAbortMessage() const +{ + return Tr::tr("Closing this editor will abort the submit."); +} + +QString PerforcePluginPrivate::commitErrorMessage(const QString &error) const +{ + if (error.isEmpty()) + return Tr::tr("Cannot submit."); + return Tr::tr("Cannot submit: %1.").arg(error); +} + void PerforcePluginPrivate::p4Diff(const FilePath &workingDir, const QStringList &files) { PerforceDiffParameters p; diff --git a/src/plugins/vcsbase/submiteditorwidget.cpp b/src/plugins/vcsbase/submiteditorwidget.cpp index 63a75e7ac06..00b4200580a 100644 --- a/src/plugins/vcsbase/submiteditorwidget.cpp +++ b/src/plugins/vcsbase/submiteditorwidget.cpp @@ -619,15 +619,16 @@ void SubmitEditorWidget::verifyDescription() d->descriptionHint->setText(hints.join("
    ")); if (!d->descriptionHint->text().isEmpty()) { + static_assert(MaxSubjectLength == 72); // change the translated message below when changing d->descriptionHint->setToolTip( Tr::tr("

    Writing good commit messages

    " "
      " "
    • Avoid very short commit messages.
    • " - "
    • Consider the first line as subject (like in email) " - "and keep it shorter than %n characters.
    • " + "
    • Consider the first line as a subject (like in emails) " + "and keep it shorter than 72 characters.
    • " "
    • After an empty second line, a longer description can be added.
    • " "
    • Describe why the change was done, not how it was done.
    • " - "
    ", nullptr, MaxSubjectLength)); + "")); } } diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index 517ffbdf48f..b72657cdb3c 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -593,9 +593,27 @@ bool VcsBasePluginPrivate::enableMenuAction(ActionState as, QAction *menuAction) QString VcsBasePluginPrivate::commitDisplayName() const { + //: Name of the "commit" action of the VCS return Tr::tr("Commit", "name of \"commit\" action of the VCS."); } +QString VcsBasePluginPrivate::commitAbortTitle() const +{ + return Tr::tr("Close Commit Editor"); +} + +QString VcsBasePluginPrivate::commitAbortMessage() const +{ + return Tr::tr("Closing this editor will abort the commit."); +} + +QString VcsBasePluginPrivate::commitErrorMessage(const QString &error) const +{ + if (error.isEmpty()) + return Tr::tr("Cannot commit."); + return Tr::tr("Cannot commit: %1.").arg(error); +} + void VcsBasePluginPrivate::commitFromEditor() { QTC_ASSERT(m_submitEditor, return); diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h index af96e12631a..5a4c9ae6b30 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.h +++ b/src/plugins/vcsbase/vcsbaseplugin.h @@ -135,6 +135,9 @@ public: const QStringList &extraArgs); // Display name of the commit action virtual QString commitDisplayName() const; + virtual QString commitAbortTitle() const; + virtual QString commitAbortMessage() const; + virtual QString commitErrorMessage(const QString &error) const; void commitFromEditor(); virtual bool activateCommit() = 0; diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 1895a64f4d1..5ddab0da77f 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -453,11 +453,7 @@ void VcsBaseSubmitEditor::accept(VcsBasePluginPrivate *plugin) QString errorMessage; const bool canCommit = checkSubmitMessage(&errorMessage) && submitWidget->canSubmit(&errorMessage); if (!canCommit) { - VcsOutputWindow::appendError( - Tr::tr("Cannot %1%2.", - "%2 is an optional error message with ': ' prefix. Don't add space in front.") - .arg(plugin->commitDisplayName().toLower(), - errorMessage.isEmpty() ? errorMessage : ": " + errorMessage)); + VcsOutputWindow::appendError(plugin->commitErrorMessage(errorMessage)); } else if (plugin->activateCommit()) { close(); } @@ -480,12 +476,10 @@ bool VcsBaseSubmitEditor::promptSubmit(VcsBasePluginPrivate *plugin) if (!submitWidget->isEnabled() || !submitWidget->isEdited()) return true; - const QString commitName = plugin->commitDisplayName(); QMessageBox mb(Core::ICore::dialogParent()); - mb.setWindowTitle(Tr::tr("Close %1 %2 Editor").arg(plugin->displayName(), commitName)); + mb.setWindowTitle(plugin->commitAbortTitle()); mb.setIcon(QMessageBox::Warning); - mb.setText(Tr::tr("Closing this editor will abort the %1.") - .arg(commitName.toLower())); + mb.setText(plugin->commitAbortMessage()); mb.setStandardButtons(QMessageBox::Close | QMessageBox::Cancel); // On Windows there is no mnemonic for Close. Set it explicitly. mb.button(QMessageBox::Close)->setText(Tr::tr("&Close")); From 58fb6f88a643dfa6e8799722f0dbf272b29a138b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 26 May 2023 00:23:58 +0200 Subject: [PATCH 1376/1447] SquishTests: Update reading build issues Fixes tst_build_new_project, tst_CCOM02 et al. tst_tasks_handling fails which might be an actual issue, reported in: Task-number: QTCREATORBUG-29209 Change-Id: I5eae54df27d8ba8f441e5b9c4acdaa2b41716245 Reviewed-by: Christian Stenger Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/taskmodel.cpp | 2 ++ src/plugins/projectexplorer/taskmodel.h | 2 +- tests/system/objects.map | 2 +- tests/system/shared/build_utils.py | 4 ++-- tests/system/shared/suites_qtta.py | 6 +++--- tests/system/suite_editors/tst_memberoperator/test.py | 4 ++-- tests/system/suite_general/tst_opencreator_qbs/test.py | 2 +- tests/system/suite_general/tst_tasks_handling/test.py | 2 +- 8 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/taskmodel.cpp b/src/plugins/projectexplorer/taskmodel.cpp index 80280a5595e..11591e707d7 100644 --- a/src/plugins/projectexplorer/taskmodel.cpp +++ b/src/plugins/projectexplorer/taskmodel.cpp @@ -273,6 +273,8 @@ QVariant TaskModel::data(const QModelIndex &index, int role) const return task.summary; case TaskModel::Description: return task.description(); + case TaskModel::Type: + return int(task.type); } return {}; } diff --git a/src/plugins/projectexplorer/taskmodel.h b/src/plugins/projectexplorer/taskmodel.h index e60d8a30a51..5fa37c02d1a 100644 --- a/src/plugins/projectexplorer/taskmodel.h +++ b/src/plugins/projectexplorer/taskmodel.h @@ -44,7 +44,7 @@ public: int sizeOfLineNumber(const QFont &font); void setFileNotFound(const QModelIndex &index, bool b); - enum Roles { Description = Qt::UserRole, }; + enum Roles { Description = Qt::UserRole, Type}; int taskCount(Utils::Id categoryId); int errorTaskCount(Utils::Id categoryId); diff --git a/tests/system/objects.map b/tests/system/objects.map index 591b671e539..883bfd02af4 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -124,7 +124,7 @@ :Qt Creator.DragDoc_QToolButton {toolTip='Drag to drag documents between splits' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.Events_QDockWidget {name='QmlProfiler.Statistics.DockDockWidget' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.Events_QTabBar {aboveWidget=':Qt Creator.Events_QDockWidget' type='QTabBar' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:Qt Creator.Issues_QListView {type='QListView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Issues'} +:Qt Creator.Issues_QListView {type='Utils::TreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Issues'} :Qt Creator.Project.Menu.File_QMenu {name='Project.Menu.File' type='QMenu'} :Qt Creator.Project.Menu.Folder_QMenu {name='Project.Menu.Folder' type='QMenu' visible='1'} :Qt Creator.QML debugging and profiling:_QComboBox {leftWidget=':Qt Creator.QML debugging and profiling:_QLabel' type='QComboBox' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index 18ae360fca0..6a2904286a3 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -47,7 +47,7 @@ def checkLastBuild(expectedToFail=False): test.log("checkLastBuild called without a build") return buildIssues = getBuildIssues() - types = [i[5] for i in buildIssues] + types = [i[1] for i in buildIssues] errors = types.count("1") warnings = types.count("2") gotErrors = errors != 0 @@ -89,7 +89,7 @@ def dumpBuildIssues(listModel): issueDump = [] for index in dumpIndices(listModel): issueDump.extend([[str(index.data(role).toString()) for role - in range(Qt.UserRole, Qt.UserRole + 6)]]) + in range(Qt.UserRole, Qt.UserRole + 2)]]) return issueDump diff --git a/tests/system/shared/suites_qtta.py b/tests/system/shared/suites_qtta.py index 2c63e009e83..97032ae0638 100644 --- a/tests/system/shared/suites_qtta.py +++ b/tests/system/shared/suites_qtta.py @@ -20,9 +20,9 @@ def checkSyntaxError(issuesView, expectedTextsArray, warnIfMoreIssues = True): if(warnIfMoreIssues and issuesModel.rowCount() > 1): test.warning("More than one expected issues reported") # iterate issues and check if there exists "Unexpected token" message - for description, type in zip(dumpItems(issuesModel, role=Qt.UserRole + 3), - dumpItems(issuesModel, role=Qt.UserRole + 5)): - # enum Roles { File = Qt::UserRole, Line, MovedLine, Description, FileNotFound, Type, Category, Icon, Task_t }; + for description, type in zip(dumpItems(issuesModel, role=Qt.UserRole), + dumpItems(issuesModel, role=Qt.UserRole + 1)): + # enum Roles { Description = Qt::UserRole, Type}; # check if at least one of expected texts found in issue text for expectedText in expectedTextsArray: if expectedText in description: diff --git a/tests/system/suite_editors/tst_memberoperator/test.py b/tests/system/suite_editors/tst_memberoperator/test.py index ba1f1476850..4d11465b719 100644 --- a/tests/system/suite_editors/tst_memberoperator/test.py +++ b/tests/system/suite_editors/tst_memberoperator/test.py @@ -27,11 +27,11 @@ def __noBuildIssues__(): def __syntaxErrorDetected__(): buildIssues = getBuildIssues(False) for issue in buildIssues: - if issue[3] in ["Expected ';' after expression (fix available)", + if issue[0] in ["Expected ';' after expression (fix available)", "Expected ';' at end of declaration (fix available)", "Use of undeclared identifier 'syntaxError'"]: return True - if re.match(issue[3], "Declaration of reference variable '.+' requires an initializer"): + if re.match(issue[0], "Declaration of reference variable '.+' requires an initializer"): return True return False diff --git a/tests/system/suite_general/tst_opencreator_qbs/test.py b/tests/system/suite_general/tst_opencreator_qbs/test.py index 555e1437582..ca941547c90 100644 --- a/tests/system/suite_general/tst_opencreator_qbs/test.py +++ b/tests/system/suite_general/tst_opencreator_qbs/test.py @@ -24,7 +24,7 @@ def main(): else: test.warning("Parsing project timed out") compareProjectTree(rootNodeTemplate % "Qt Creator", "projecttree_creator.tsv") - buildIssuesTexts = map(lambda i: str(i[3]), getBuildIssues()) + buildIssuesTexts = map(lambda i: str(i[0]), getBuildIssues()) deprecationWarnings = filter(lambda s: "deprecated" in s, buildIssuesTexts) if deprecationWarnings: test.warning("Creator claims that the .qbs file uses deprecated features.", diff --git a/tests/system/suite_general/tst_tasks_handling/test.py b/tests/system/suite_general/tst_tasks_handling/test.py index 053d5d24c74..8c6e2395583 100644 --- a/tests/system/suite_general/tst_tasks_handling/test.py +++ b/tests/system/suite_general/tst_tasks_handling/test.py @@ -58,7 +58,7 @@ def checkOrUncheckMyTasks(): "My Tasks")) def getBuildIssuesTypeCounts(model): - issueTypes = list(map(lambda x: x.data(Qt.UserRole + 5).toInt(), dumpIndices(model))) + issueTypes = list(map(lambda x: x.data(Qt.UserRole + 1).toInt(), dumpIndices(model))) result = [issueTypes.count(0), issueTypes.count(1), issueTypes.count(2)] if len(issueTypes) != sum(result): test.fatal("Found unexpected value(s) for TaskType...") From 1bc3cccbb444b078db2e5e0a1cd4ecd4debd0358 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 31 May 2023 12:15:48 +0200 Subject: [PATCH 1377/1447] Copilot: Do not try to start copilot without nodejs Avoids the attempt to start the client if nodejs cannot be found. Change-Id: I3783280120ca754291a92b3308c1192906facd08 Reviewed-by: Marcus Tillmanns --- src/plugins/copilot/authwidget.cpp | 2 +- src/plugins/copilot/copilotplugin.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp index 31b4660b680..f29e3d3a150 100644 --- a/src/plugins/copilot/authwidget.cpp +++ b/src/plugins/copilot/authwidget.cpp @@ -93,7 +93,7 @@ void AuthWidget::updateClient(const Utils::FilePath &nodeJs, const Utils::FilePa m_client = nullptr; setState(Tr::tr("Sign in"), false); m_button->setEnabled(false); - if (!nodeJs.exists() || !agent.exists()) { + if (!nodeJs.isExecutableFile() || !agent.exists()) { return; } diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp index 43effda321c..526a6061cbe 100644 --- a/src/plugins/copilot/copilotplugin.cpp +++ b/src/plugins/copilot/copilotplugin.cpp @@ -120,6 +120,9 @@ void CopilotPlugin::extensionsInitialized() void CopilotPlugin::restartClient() { LanguageClient::LanguageClientManager::shutdownClient(m_client); + + if (!CopilotSettings::instance().nodeJsPath().isExecutableFile()) + return; m_client = new CopilotClient(CopilotSettings::instance().nodeJsPath(), CopilotSettings::instance().distPath()); } From 44e9d56c0463e35bdfede1af4f9da9dd70e13820 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 30 May 2023 13:52:11 +0200 Subject: [PATCH 1378/1447] Utils: Fix macOS permissions parsing Change-Id: I5fdde04c197b5db323fc8630c4ee4b2c197d947a Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/utils/fileutils.cpp | 12 +++++++++--- tests/auto/utils/fileutils/tst_fileutils.cpp | 14 ++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index a6cbebf3681..2cecc2810b9 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -629,12 +629,18 @@ FilePathInfo::FileFlags fileInfoFlagsfromStatMode(const QString &hexString, int FilePathInfo::FileFlags result; - if (mode & IRUSR) + if (mode & IRUSR) { result |= FilePathInfo::ReadOwnerPerm; - if (mode & IWUSR) + result |= FilePathInfo::ReadUserPerm; + } + if (mode & IWUSR) { result |= FilePathInfo::WriteOwnerPerm; - if (mode & IXUSR) + result |= FilePathInfo::WriteUserPerm; + } + if (mode & IXUSR) { result |= FilePathInfo::ExeOwnerPerm; + result |= FilePathInfo::ExeUserPerm; + } if (mode & IRGRP) result |= FilePathInfo::ReadGroupPerm; if (mode & IWGRP) diff --git a/tests/auto/utils/fileutils/tst_fileutils.cpp b/tests/auto/utils/fileutils/tst_fileutils.cpp index f4596cb1a5c..198abf3398b 100644 --- a/tests/auto/utils/fileutils/tst_fileutils.cpp +++ b/tests/auto/utils/fileutils/tst_fileutils.cpp @@ -136,6 +136,9 @@ void tst_fileutils::filePathInfoFromTriple_data() FilePathInfo::ReadOwnerPerm | FilePathInfo::WriteOwnerPerm | FilePathInfo::ExeOwnerPerm + | FilePathInfo::ReadUserPerm + | FilePathInfo::WriteUserPerm + | FilePathInfo::ExeUserPerm | FilePathInfo::ReadGroupPerm | FilePathInfo::ExeGroupPerm | FilePathInfo::ReadOtherPerm @@ -149,10 +152,11 @@ void tst_fileutils::filePathInfoFromTriple_data() << FilePathInfo{808104, FilePathInfo::FileFlags( FilePathInfo::ReadOwnerPerm | FilePathInfo::WriteOwnerPerm - | FilePathInfo::ExeOwnerPerm | FilePathInfo::ReadGroupPerm - | FilePathInfo::ExeGroupPerm | FilePathInfo::ReadOtherPerm - | FilePathInfo::ExeOtherPerm | FilePathInfo::FileType - | FilePathInfo::ExistsFlag), + | FilePathInfo::ExeOwnerPerm | FilePathInfo::ReadUserPerm + | FilePathInfo::WriteUserPerm | FilePathInfo::ExeUserPerm + | FilePathInfo::ReadGroupPerm | FilePathInfo::ExeGroupPerm + | FilePathInfo::ReadOtherPerm | FilePathInfo::ExeOtherPerm + | FilePathInfo::FileType | FilePathInfo::ExistsFlag), QDateTime::fromSecsSinceEpoch(1668852790)}; QTest::newRow("linux-disk") << QString("61b0 1651167746 0") @@ -160,6 +164,8 @@ void tst_fileutils::filePathInfoFromTriple_data() FilePathInfo::FileFlags( FilePathInfo::ReadOwnerPerm | FilePathInfo::WriteOwnerPerm + | FilePathInfo::ReadUserPerm + | FilePathInfo::WriteUserPerm | FilePathInfo::ReadGroupPerm | FilePathInfo::WriteGroupPerm | FilePathInfo::LocalDiskFlag From 9f1a2c4f8f3e9cbd1309c744455c5a770d534fba Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 23 May 2023 07:15:42 +0200 Subject: [PATCH 1379/1447] Terminal: Rework commands This rework fixes the way commands are registered in Qt Creator. Change-Id: I401f3ac7d9194dad8fceb507360ddc3633106eb4 Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/terminal/CMakeLists.txt | 3 +- src/plugins/terminal/terminal.qbs | 4 +- src/plugins/terminal/terminalcommands.cpp | 186 ---------------------- src/plugins/terminal/terminalcommands.h | 76 --------- src/plugins/terminal/terminalconstants.h | 19 +++ src/plugins/terminal/terminalicons.h | 18 +++ src/plugins/terminal/terminalpane.cpp | 167 ++++++++++--------- src/plugins/terminal/terminalpane.h | 17 ++ src/plugins/terminal/terminalplugin.cpp | 22 ++- src/plugins/terminal/terminalsearch.cpp | 10 -- src/plugins/terminal/terminalwidget.cpp | 158 ++++++++++++------ src/plugins/terminal/terminalwidget.h | 25 +++ 12 files changed, 292 insertions(+), 413 deletions(-) delete mode 100644 src/plugins/terminal/terminalcommands.cpp delete mode 100644 src/plugins/terminal/terminalcommands.h create mode 100644 src/plugins/terminal/terminalconstants.h create mode 100644 src/plugins/terminal/terminalicons.h diff --git a/src/plugins/terminal/CMakeLists.txt b/src/plugins/terminal/CMakeLists.txt index 083ffa844e6..69da526cdc0 100644 --- a/src/plugins/terminal/CMakeLists.txt +++ b/src/plugins/terminal/CMakeLists.txt @@ -10,7 +10,8 @@ add_qtc_plugin(Terminal shellintegration.cpp shellintegration.h shellmodel.cpp shellmodel.h terminal.qrc - terminalcommands.cpp terminalcommands.h + terminalconstants.h + terminalicons.h terminalpane.cpp terminalpane.h terminalplugin.cpp terminalprocessimpl.cpp terminalprocessimpl.h diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index 0fa1ba46316..c4c9de253e9 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -22,8 +22,8 @@ QtcPlugin { "shellintegration.cpp", "shellintegration.h", "terminal.qrc", - "terminalcommands.cpp", - "terminalcommands.h", + "terminalconstants.h", + "terminalicons.h" "terminalpane.cpp", "terminalpane.h", "terminalplugin.cpp", diff --git a/src/plugins/terminal/terminalcommands.cpp b/src/plugins/terminal/terminalcommands.cpp deleted file mode 100644 index 0e7cba8194c..00000000000 --- a/src/plugins/terminal/terminalcommands.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "terminalcommands.h" -#include "terminaltr.h" - -#include -#include -#include -#include - -#include - -//#include - -using namespace Core; -using namespace Utils; - -namespace Terminal { - -constexpr char COPY[] = "Terminal.Copy"; -constexpr char PASTE[] = "Terminal.Paste"; -constexpr char COPY_LINK[] = "Terminal.CopyLink"; -constexpr char CLEARSELECTION[] = "Terminal.ClearSelection"; -constexpr char MOVECURSORWORDLEFT[] = "Terminal.MoveCursorWordLeft"; -constexpr char MOVECURSORWORDRIGHT[] = "Terminal.MoveCursorWordRight"; - -constexpr char NEWTERMINAL[] = "Terminal.NewTerminal"; -constexpr char CLOSETERMINAL[] = "Terminal.CloseTerminal"; -constexpr char NEXTTERMINAL[] = "Terminal.NextTerminal"; -constexpr char PREVTERMINAL[] = "Terminal.PrevTerminal"; -constexpr char MINMAX[] = "Terminal.MinMax"; - -TerminalCommands &TerminalCommands::instance() -{ - static TerminalCommands instance; - return instance; -} - -TerminalCommands::TerminalCommands() {} - -void TerminalCommands::init(const Core::Context &context) -{ - m_context = context; - initWidgetActions(); - initPaneActions(); - initGlobalCommands(); -} - -void TerminalCommands::registerAction(QAction &action, - const Utils::Id &id, - QList shortCuts) -{ - Command *cmd = ActionManager::instance()->registerAction(&action, id, m_context); - cmd->setKeySequences(shortCuts); - m_commands.push_back(cmd); -} - -void TerminalCommands::initWidgetActions() -{ - m_widgetActions.copy.setText(Tr::tr("Copy")); - m_widgetActions.paste.setText(Tr::tr("Paste")); - m_widgetActions.copyLink.setText(Tr::tr("Copy Link")); - m_widgetActions.clearSelection.setText(Tr::tr("Clear Selection")); - m_widgetActions.clearTerminal.setText(Tr::tr("Clear Terminal")); - m_widgetActions.moveCursorWordLeft.setText(Tr::tr("Move Cursor Word Left")); - m_widgetActions.moveCursorWordRight.setText(Tr::tr("Move Cursor Word Right")); - m_widgetActions.findNext.setText(Tr::tr("Find Next")); - m_widgetActions.findPrevious.setText(Tr::tr("Find Previous")); - - registerAction(m_widgetActions.copy, - COPY, - {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") - : QLatin1String("Ctrl+Shift+C"))}); - - registerAction(m_widgetActions.paste, - PASTE, - {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") - : QLatin1String("Ctrl+Shift+V"))}); - - registerAction(m_widgetActions.copyLink, COPY_LINK); - - registerAction(m_widgetActions.clearSelection, CLEARSELECTION); - - registerAction(m_widgetActions.moveCursorWordLeft, - MOVECURSORWORDLEFT, - {QKeySequence("Alt+Left")}); - - registerAction(m_widgetActions.moveCursorWordRight, - MOVECURSORWORDRIGHT, - {QKeySequence("Alt+Right")}); -} - -void TerminalCommands::initPaneActions() -{ - m_paneActions.newTerminal.setText(Tr::tr("New Terminal")); - m_paneActions.closeTerminal.setText(Tr::tr("Close Terminal")); - m_paneActions.nextTerminal.setText(Tr::tr("Next Terminal")); - m_paneActions.prevTerminal.setText(Tr::tr("Previous Terminal")); - m_paneActions.minMax.setText(Tr::tr("Minimize/Maximize Terminal")); - - registerAction(m_paneActions.newTerminal, - NEWTERMINAL, - {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") - : QLatin1String("Ctrl+Shift+T"))}); - - registerAction(m_paneActions.closeTerminal, - CLOSETERMINAL, - {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+W") - : QLatin1String("Ctrl+Shift+W"))}); - - registerAction(m_paneActions.nextTerminal, - NEXTTERMINAL, - {QKeySequence("ALT+TAB"), - QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[") - : QLatin1String("Ctrl+PgUp"))}); - - registerAction(m_paneActions.prevTerminal, - PREVTERMINAL, - {QKeySequence("ALT+SHIFT+TAB"), - QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+]") - : QLatin1String("Ctrl+PgDown"))}); - - registerAction(m_paneActions.minMax, - MINMAX, - {QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Return") - : QLatin1String("Alt+Return"))}); -} - -void TerminalCommands::initGlobalCommands() -{ - // Global commands we still want to allow - m_commands.push_back(ActionManager::command(Constants::ZOOM_IN)); - m_commands.push_back(ActionManager::command(Constants::ZOOM_OUT)); - m_commands.push_back(ActionManager::command(Constants::EXIT)); - m_commands.push_back(ActionManager::command(Constants::OPTIONS)); -} - -bool TerminalCommands::triggerAction(QKeyEvent *event) -{ - QKeyCombination combination = event->keyCombination(); - - // On macOS, the arrow keys include the KeypadModifier, which we don't want. - if (HostOsInfo::isMacHost() && combination.keyboardModifiers() & Qt::KeypadModifier) - combination = QKeyCombination(combination.keyboardModifiers() & ~Qt::KeypadModifier, - combination.key()); - - for (const auto &command : TerminalCommands::instance().m_commands) { - if (!command->action()->isEnabled()) - continue; - - for (const auto &shortcut : command->keySequences()) { - const auto result = shortcut.matches(QKeySequence(combination)); - if (result == QKeySequence::ExactMatch) { - command->action()->trigger(); - return true; - } - } - } - - return false; -} - -QAction *TerminalCommands::openSettingsAction() -{ - return ActionManager::command("Preferences.Terminal.General")->action(); -} - -void TerminalCommands::lazyInitCommand(const Utils::Id &id) -{ - Command *cmd = ActionManager::command(id); - QTC_ASSERT(cmd, return); - m_commands.append(cmd); -} - -void TerminalCommands::lazyInitCommands() -{ - static const Utils::Id terminalPaneCmd("QtCreator.Pane.Terminal"); - lazyInitCommand(terminalPaneCmd); - lazyInitCommand(Core::Constants::FIND_IN_DOCUMENT); - lazyInitCommand(Core::Constants::FIND_NEXT); - lazyInitCommand(Core::Constants::FIND_PREVIOUS); - lazyInitCommand(Core::Constants::LOCATE); -} - -} // namespace Terminal diff --git a/src/plugins/terminal/terminalcommands.h b/src/plugins/terminal/terminalcommands.h deleted file mode 100644 index 71bc7ffe0f8..00000000000 --- a/src/plugins/terminal/terminalcommands.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include - -#include -#include -#include - -namespace Core { -class Command; -class Context; -} // namespace Core - -namespace Terminal { - -struct WidgetActions -{ - QAction copy; - QAction paste; - QAction copyLink; - QAction clearSelection; - QAction clearTerminal; - QAction moveCursorWordLeft; - QAction moveCursorWordRight; - QAction findNext; - QAction findPrevious; -}; - -struct PaneActions -{ - QAction newTerminal; - QAction closeTerminal; - QAction nextTerminal; - QAction prevTerminal; - QAction minMax; -}; - -class TerminalCommands -{ -public: - TerminalCommands(); - - void init(const Core::Context &context); - static TerminalCommands &instance(); - static WidgetActions &widgetActions() { return instance().m_widgetActions; } - static PaneActions &paneActions() { return instance().m_paneActions; } - - static QList shortcutsFor(QAction *action); - - static bool triggerAction(QKeyEvent *event); - - static QAction *openSettingsAction(); - - void lazyInitCommands(); - -protected: - void initWidgetActions(); - void initPaneActions(); - void initGlobalCommands(); - - void lazyInitCommand(const Utils::Id &id); - void registerAction(QAction &action, const Utils::Id &id, QList shortcuts = {}); - -private: - WidgetActions m_widgetActions; - PaneActions m_paneActions; - QList m_commands; - Core::Context m_context; -}; - -} // namespace Terminal diff --git a/src/plugins/terminal/terminalconstants.h b/src/plugins/terminal/terminalconstants.h new file mode 100644 index 00000000000..99700475e60 --- /dev/null +++ b/src/plugins/terminal/terminalconstants.h @@ -0,0 +1,19 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace Terminal::Constants { +constexpr char NEWTERMINAL[] = "Terminal.NewTerminal"; +constexpr char NEXTTERMINAL[] = "Terminal.NextTerminal"; +constexpr char PREVTERMINAL[] = "Terminal.PrevTerminal"; +constexpr char MINMAX[] = "Terminal.MinMax"; + +constexpr char COPY[] = "Terminal.Copy"; +constexpr char PASTE[] = "Terminal.Paste"; +constexpr char CLEARSELECTION[] = "Terminal.ClearSelection"; +constexpr char MOVECURSORWORDLEFT[] = "Terminal.MoveCursorWordLeft"; +constexpr char MOVECURSORWORDRIGHT[] = "Terminal.MoveCursorWordRight"; +constexpr char CLEAR_TERMINAL[] = "Terminal.ClearTerminal"; + +} // namespace Terminal::Constants diff --git a/src/plugins/terminal/terminalicons.h b/src/plugins/terminal/terminalicons.h new file mode 100644 index 00000000000..ca503f50f96 --- /dev/null +++ b/src/plugins/terminal/terminalicons.h @@ -0,0 +1,18 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace Terminal { + +static Utils::Icon NEW_TERMINAL_ICON( + {{":/terminal/images/terminal.png", Utils::Theme::IconsBaseColor}, + {":/utils/images/iconoverlay_add_small.png", Utils::Theme::IconsRunToolBarColor}}); + +static Utils::Icon CLOSE_TERMINAL_ICON( + {{":/terminal/images/terminal.png", Utils::Theme::IconsBaseColor}, + {":/utils/images/iconoverlay_close_small.png", Utils::Theme::IconsStopToolBarColor}}); + +} // namespace Terminal diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 34370f22bb2..7cf0e308031 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -4,14 +4,17 @@ #include "terminalpane.h" #include "shellmodel.h" -#include "terminalcommands.h" +#include "terminalconstants.h" +#include "terminalicons.h" #include "terminalsettings.h" #include "terminaltr.h" #include "terminalwidget.h" #include +#include #include #include +#include #include #include @@ -29,15 +32,15 @@ namespace Terminal { using namespace Utils; using namespace Utils::Terminal; +using namespace Core; TerminalPane::TerminalPane(QObject *parent) - : Core::IOutputPane(parent) + : IOutputPane(parent) + , m_context("Terminal.Pane", Core::Constants::C_GLOBAL_CUTOFF) { - setupContext("Terminal.Pane", &m_tabWidget); + setupContext(m_context, &m_tabWidget); setZoomButtonsEnabled(true); - TerminalCommands::instance().init(Core::Context("Terminal.Pane")); - connect(this, &IOutputPane::zoomInRequested, this, [this] { if (currentTerminal()) currentTerminal()->zoomIn(); @@ -47,89 +50,24 @@ TerminalPane::TerminalPane(QObject *parent) currentTerminal()->zoomOut(); }); - QAction &newTerminal = TerminalCommands::instance().paneActions().newTerminal; - QAction &closeTerminal = TerminalCommands::instance().paneActions().closeTerminal; - - newTerminal.setIcon( - Icon({{":/terminal/images/terminal.png", Theme::IconsBaseColor}, - {":/utils/images/iconoverlay_add_small.png", Theme::IconsRunToolBarColor}}) - .icon()); - newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); - - connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); - - closeTerminal.setIcon( - Icon({{":/terminal/images/terminal.png", Theme::IconsBaseColor}, - {":/utils/images/iconoverlay_close_small.png", Theme::IconsStopToolBarColor}}) - .icon()); - closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); - - connect(&closeTerminal, &QAction::triggered, this, [this] { - removeTab(m_tabWidget.currentIndex()); - }); + initActions(); m_newTerminalButton = new QToolButton(); - - QMenu *shellMenu = new QMenu(m_newTerminalButton); - const Internal::ShellModel *shellModel = new Internal::ShellModel(shellMenu); - connect(shellMenu, &QMenu::aboutToShow, shellMenu, [shellMenu, shellModel, pane = this] { - shellMenu->clear(); - - const auto addItems = [shellMenu, pane](const QList &items) { - for (const Internal::ShellModelItem &item : items) { - QAction *action = new QAction(item.icon, item.name, shellMenu); - - connect(action, &QAction::triggered, action, [item, pane]() { - pane->openTerminal(item.openParameters); - }); - - shellMenu->addAction(action); - } - }; - - addItems(shellModel->local()); - shellMenu->addSection(Tr::tr("Devices")); - addItems(shellModel->remote()); - }); - - newTerminal.setMenu(shellMenu); - m_newTerminalButton->setDefaultAction(&newTerminal); m_closeTerminalButton = new QToolButton(); m_closeTerminalButton->setDefaultAction(&closeTerminal); - connect(&TerminalCommands::instance().paneActions().nextTerminal, - &QAction::triggered, - this, - [this] { - if (canNavigate()) - goToNext(); - }); - connect(&TerminalCommands::instance().paneActions().prevTerminal, - &QAction::triggered, - this, - [this] { - if (canPrevious()) - goToPrev(); - }); - - connect(&TerminalCommands::instance().paneActions().minMax, &QAction::triggered, this, []() { - Core::Command *minMaxCommand = Core::ActionManager::command("Coreplugin.OutputPane.minmax"); - if (minMaxCommand) - emit minMaxCommand->action()->triggered(); - }); - m_openSettingsButton = new QToolButton(); - m_openSettingsButton->setToolTip(Tr::tr("Open Terminal Settings")); + m_openSettingsButton->setToolTip(Tr::tr("Configure...")); m_openSettingsButton->setIcon(Icons::SETTINGS_TOOLBAR.icon()); connect(m_openSettingsButton, &QToolButton::clicked, m_openSettingsButton, []() { - TerminalCommands::openSettingsAction()->trigger(); + ICore::showOptionsDialog("Terminal.General"); }); const auto updateEscButton = [this] { - m_escSettingButton->setChecked(TerminalSettings::instance().sendEscapeToTerminal.value()); + m_escSettingButton->setChecked(TerminalSettings::instance().sendEscapeToTerminal()); static const QString escKey = QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText); static const QString shiftEsc = QKeySequence( @@ -151,7 +89,7 @@ TerminalPane::TerminalPane(QObject *parent) connect(m_escSettingButton, &QToolButton::toggled, this, [this] { TerminalSettings::instance().sendEscapeToTerminal.setValue(m_escSettingButton->isChecked()); - TerminalSettings::instance().writeSettings(Core::ICore::settings()); + TerminalSettings::instance().writeSettings(ICore::settings()); }); connect(&TerminalSettings::instance(), &TerminalSettings::applied, this, updateEscButton); @@ -242,10 +180,6 @@ QWidget *TerminalPane::outputWidget(QWidget *parent) else emit hidePage(); }); - - const auto terminalWidget = new TerminalWidget(parent); - m_tabWidget.addTab(terminalWidget, Tr::tr("Terminal")); - setupTerminalWidget(terminalWidget); } return &m_tabWidget; @@ -289,6 +223,81 @@ void TerminalPane::setupTerminalWidget(TerminalWidget *terminal) setTabText(); } +void TerminalPane::initActions() +{ + createShellMenu(); + + newTerminal.setText(Tr::tr("New Terminal")); + newTerminal.setIcon(NEW_TERMINAL_ICON.icon()); + newTerminal.setToolTip(Tr::tr("Create a new Terminal.")); + newTerminal.setMenu(&m_shellMenu); + + nextTerminal.setText(Tr::tr("Next Terminal")); + prevTerminal.setText(Tr::tr("Previous Terminal")); + + closeTerminal.setIcon(CLOSE_TERMINAL_ICON.icon()); + closeTerminal.setToolTip(Tr::tr("Close the current Terminal.")); + + using namespace Constants; + + ActionManager::registerAction(&newTerminal, NEWTERMINAL, m_context) + ->setDefaultKeySequences({QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+T") : QLatin1String("Ctrl+Shift+T"))}); + + ActionManager::registerAction(&nextTerminal, NEXTTERMINAL, m_context) + ->setDefaultKeySequences( + {QKeySequence("Alt+Tab"), + QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+[") + : QLatin1String("Ctrl+PgUp"))}); + + ActionManager::registerAction(&prevTerminal, PREVTERMINAL, m_context) + ->setDefaultKeySequences( + {QKeySequence("Alt+Shift+Tab"), + QKeySequence(HostOsInfo::isMacHost() ? QLatin1String("Ctrl+Shift+]") + : QLatin1String("Ctrl+PgDown"))}); + + m_minMax = TerminalWidget::unlockGlobalAction("Coreplugin.OutputPane.minmax", m_context); + m_locate = TerminalWidget::unlockGlobalAction(Core::Constants::LOCATE, m_context); + + connect(&newTerminal, &QAction::triggered, this, [this] { openTerminal({}); }); + connect(&closeTerminal, &QAction::triggered, this, [this] { + removeTab(m_tabWidget.currentIndex()); + }); + connect(&nextTerminal, &QAction::triggered, this, [this] { + if (canNavigate()) + goToNext(); + }); + connect(&prevTerminal, &QAction::triggered, this, [this] { + if (canPrevious()) + goToPrev(); + }); +} + +void TerminalPane::createShellMenu() +{ + const Internal::ShellModel *shellModel = new Internal::ShellModel(&m_shellMenu); + + connect(&m_shellMenu, &QMenu::aboutToShow, &m_shellMenu, [shellModel, this] { + m_shellMenu.clear(); + + const auto addItems = [this](const QList &items) { + for (const Internal::ShellModelItem &item : items) { + QAction *action = new QAction(item.icon, item.name, &m_shellMenu); + + connect(action, &QAction::triggered, action, [item, this]() { + openTerminal(item.openParameters); + }); + + m_shellMenu.addAction(action); + } + }; + + addItems(shellModel->local()); + m_shellMenu.addSection(Tr::tr("Devices")); + addItems(shellModel->remote()); + }); +} + QList TerminalPane::toolBarWidgets() const { QList widgets = IOutputPane::toolBarWidgets(); diff --git a/src/plugins/terminal/terminalpane.h b/src/plugins/terminal/terminalpane.h index 6ef2d005357..21f15168f26 100644 --- a/src/plugins/terminal/terminalpane.h +++ b/src/plugins/terminal/terminalpane.h @@ -3,11 +3,14 @@ #pragma once +#include "terminalwidget.h" + #include #include #include +#include #include #include @@ -49,6 +52,8 @@ private: void removeTab(int index); void setupTerminalWidget(TerminalWidget *terminal); + void initActions(); + void createShellMenu(); private: QTabWidget m_tabWidget; @@ -58,6 +63,18 @@ private: QToolButton *m_openSettingsButton{nullptr}; QToolButton *m_escSettingButton{nullptr}; + UnlockedGlobalAction m_minMax; + UnlockedGlobalAction m_locate; + + QAction newTerminal; + QAction nextTerminal; + QAction prevTerminal; + QAction closeTerminal; + + QMenu m_shellMenu; + + Core::Context m_context; + bool m_widgetInitialized{false}; bool m_isVisible{false}; }; diff --git a/src/plugins/terminal/terminalplugin.cpp b/src/plugins/terminal/terminalplugin.cpp index 4738bf9b307..38b58b1722f 100644 --- a/src/plugins/terminal/terminalplugin.cpp +++ b/src/plugins/terminal/terminalplugin.cpp @@ -4,7 +4,7 @@ #include "terminalpane.h" #include "terminalprocessimpl.h" #include "terminalsettings.h" -#include "terminalcommands.h" +#include "terminalwidget.h" #include #include @@ -39,16 +39,15 @@ public: m_terminalPane = nullptr; } - void initialize() final - { - addManaged(); - } + void initialize() final { addManaged(); } void extensionsInitialized() final { m_terminalPane = new TerminalPane; ExtensionSystem::PluginManager::addObject(m_terminalPane); + TerminalWidget::initActions(); + auto enable = [this] { Utils::Terminal::Hooks::instance() .addCallbackSet("Internal", @@ -71,21 +70,18 @@ public: } }; - QObject::connect(&TerminalSettings::instance(), &Utils::AspectContainer::applied, this, settingsChanged); + QObject::connect(&TerminalSettings::instance(), + &Utils::AspectContainer::applied, + this, + settingsChanged); settingsChanged(); } - bool delayedInitialize() final - { - TerminalCommands::instance().lazyInitCommands(); - return true; - } - private: TerminalPane *m_terminalPane{nullptr}; }; -} // Terminal::Internal +} // namespace Terminal::Internal #include "terminalplugin.moc" diff --git a/src/plugins/terminal/terminalsearch.cpp b/src/plugins/terminal/terminalsearch.cpp index e909e75dfe6..69a412b1948 100644 --- a/src/plugins/terminal/terminalsearch.cpp +++ b/src/plugins/terminal/terminalsearch.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "terminalsearch.h" -#include "terminalcommands.h" #include #include @@ -28,15 +27,6 @@ TerminalSearch::TerminalSearch(TerminalSurface *surface) connect(surface, &TerminalSurface::invalidated, this, &TerminalSearch::updateHits); connect(&m_debounceTimer, &QTimer::timeout, this, &TerminalSearch::debouncedUpdateHits); - - connect(&TerminalCommands::widgetActions().findNext, - &QAction::triggered, - this, - &TerminalSearch::nextHit); - connect(&TerminalCommands::widgetActions().findPrevious, - &QAction::triggered, - this, - &TerminalSearch::previousHit); } void TerminalSearch::setCurrentSelection(std::optional selection) diff --git a/src/plugins/terminal/terminalwidget.cpp b/src/plugins/terminal/terminalwidget.cpp index b63e66b78dd..5027d390294 100644 --- a/src/plugins/terminal/terminalwidget.cpp +++ b/src/plugins/terminal/terminalwidget.cpp @@ -3,9 +3,10 @@ #include "terminalwidget.h" #include "glyphcache.h" -#include "terminalcommands.h" +#include "terminalconstants.h" #include "terminalsettings.h" #include "terminalsurface.h" +#include "terminaltr.h" #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -50,6 +52,7 @@ Q_LOGGING_CATEGORY(paintLog, "qtc.terminal.paint", QtWarningMsg) using namespace Utils; using namespace Utils::Terminal; +using namespace Core; namespace Terminal { @@ -69,10 +72,16 @@ static constexpr std::chrono::milliseconds minRefreshInterval = 1s / 30; TerminalWidget::TerminalWidget(QWidget *parent, const OpenTerminalParameters &openParameters) : QAbstractScrollArea(parent) + , m_context(Utils::Id("TerminalWidget_").withSuffix((size_t) this)) , m_openParameters(openParameters) , m_lastFlush(std::chrono::system_clock::now()) , m_lastDoubleClick(std::chrono::system_clock::now()) { + auto contextObj = new IContext(this); + contextObj->setWidget(this); + contextObj->setContext(m_context); + ICore::addContextObject(contextObj); + setupSurface(); setupFont(); setupColors(); @@ -245,24 +254,31 @@ void TerminalWidget::setupColors() void TerminalWidget::setupActions() { - WidgetActions &a = TerminalCommands::widgetActions(); + ActionManager::registerAction(&m_copy, Constants::COPY, m_context); + ActionManager::registerAction(&m_paste, Constants::PASTE, m_context); + ActionManager::registerAction(&m_close, Core::Constants::CLOSE, m_context); + ActionManager::registerAction(&m_clearTerminal, Constants::CLEAR_TERMINAL, m_context); + ActionManager::registerAction(&m_clearSelection, Constants::CLEARSELECTION, m_context); + ActionManager::registerAction(&m_moveCursorWordLeft, Constants::MOVECURSORWORDLEFT, m_context); + ActionManager::registerAction(&m_moveCursorWordRight, Constants::MOVECURSORWORDRIGHT, m_context); - auto ifHasFocus = [this](void (TerminalWidget::*f)()) { - return [this, f] { - if (hasFocus()) - (this->*f)(); - }; - }; + connect(&m_copy, &QAction::triggered, this, &TerminalWidget::copyToClipboard); + connect(&m_paste, &QAction::triggered, this, &TerminalWidget::pasteFromClipboard); + connect(&m_close, &QAction::triggered, this, &TerminalWidget::closeTerminal); + connect(&m_clearTerminal, &QAction::triggered, this, &TerminalWidget::clearContents); + connect(&m_clearSelection, &QAction::triggered, this, &TerminalWidget::clearSelection); + connect(&m_moveCursorWordLeft, &QAction::triggered, this, &TerminalWidget::moveCursorWordLeft); + connect(&m_moveCursorWordRight, &QAction::triggered, this, &TerminalWidget::moveCursorWordRight); - // clang-format off - connect(&a.copy, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyToClipboard)); - connect(&a.paste, &QAction::triggered, this, ifHasFocus(&TerminalWidget::pasteFromClipboard)); - connect(&a.copyLink, &QAction::triggered, this, ifHasFocus(&TerminalWidget::copyLinkToClipboard)); - connect(&a.clearSelection, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearSelection)); - connect(&a.clearTerminal, &QAction::triggered, this, ifHasFocus(&TerminalWidget::clearContents)); - connect(&a.moveCursorWordLeft, &QAction::triggered, this, ifHasFocus(&TerminalWidget::moveCursorWordLeft)); - connect(&a.moveCursorWordRight, &QAction::triggered, this, ifHasFocus(&TerminalWidget::moveCursorWordRight)); - // clang-format on + m_exit = unlockGlobalAction(Core::Constants::EXIT, m_context); + m_options = unlockGlobalAction(Core::Constants::OPTIONS, m_context); + m_settings = unlockGlobalAction("Preferences.Terminal.General", m_context); + m_findInDocument = unlockGlobalAction(Core::Constants::FIND_IN_DOCUMENT, m_context); +} + +void TerminalWidget::closeTerminal() +{ + deleteLater(); } void TerminalWidget::writeToPty(const QByteArray &data) @@ -385,8 +401,7 @@ void TerminalWidget::updateCopyState() if (!hasFocus()) return; - TerminalCommands::widgetActions().copy.setEnabled(m_selection.has_value()); - TerminalCommands::widgetActions().copyLink.setEnabled(m_linkSelection.has_value()); + m_copy.setEnabled(m_selection.has_value()); } void TerminalWidget::setFont(const QFont &font) @@ -511,6 +526,8 @@ QString TerminalWidget::textFromSelection() const Internal::CellIterator it = m_surface->iteratorAt(m_selection->start); Internal::CellIterator end = m_surface->iteratorAt(m_selection->end); + QTC_ASSERT(it.position() < end.position(), return {}); + std::u32string s; bool previousWasZero = false; for (; it != end; ++it) { @@ -1078,21 +1095,16 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event) } if (m_selection) - TerminalCommands::widgetActions().clearSelection.trigger(); + m_clearSelection.trigger(); else { - QTC_ASSERT(Core::ActionManager::command(Core::Constants::S_RETURNTOEDITOR), return); - Core::ActionManager::command(Core::Constants::S_RETURNTOEDITOR)->action()->trigger(); + QAction *returnAction = ActionManager::command(Core::Constants::S_RETURNTOEDITOR) + ->actionForContext(Core::Constants::C_GLOBAL); + QTC_ASSERT(returnAction, return); + returnAction->trigger(); } return; } - auto oldSelection = m_selection; - if (TerminalCommands::triggerAction(event)) { - if (oldSelection && oldSelection == m_selection) - setSelection(std::nullopt); - return; - } - if (event->key() == Qt::Key_Control) { if (!m_linkSelection.has_value() && checkLinkAt(mapFromGlobal(QCursor::pos()))) { setCursor(Qt::PointingHandCursor); @@ -1236,7 +1248,7 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) if (m_linkSelection->link.targetFilePath.isDir()) Core::FileUtils::showInFileSystemView(m_linkSelection->link.targetFilePath); else - Core::EditorManager::openEditorAt(m_linkSelection->link); + EditorManager::openEditorAt(m_linkSelection->link); } return; } @@ -1261,13 +1273,18 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event) } else if (event->button() == Qt::RightButton) { if (event->modifiers() & Qt::ShiftModifier) { QMenu *contextMenu = new QMenu(this); - contextMenu->addAction(&TerminalCommands::widgetActions().copy); - contextMenu->addAction(&TerminalCommands::widgetActions().paste); - contextMenu->addAction(&TerminalCommands::widgetActions().copyLink); + QAction *configureAction = new QAction(contextMenu); + configureAction->setText(Tr::tr("Configure...")); + connect(configureAction, &QAction::triggered, this, [] { + ICore::showOptionsDialog("Terminal.General"); + }); + + contextMenu->addAction(ActionManager::command(Constants::COPY)->action()); + contextMenu->addAction(ActionManager::command(Constants::PASTE)->action()); contextMenu->addSeparator(); - contextMenu->addAction(&TerminalCommands::widgetActions().clearTerminal); + contextMenu->addAction(ActionManager::command(Constants::CLEAR_TERMINAL)->action()); contextMenu->addSeparator(); - contextMenu->addAction(TerminalCommands::openSettingsAction()); + contextMenu->addAction(configureAction); contextMenu->popup(event->globalPos()); } else if (m_selection) { @@ -1472,11 +1489,10 @@ void TerminalWidget::showEvent(QShowEvent *event) bool TerminalWidget::event(QEvent *event) { - if (event->type() == QEvent::ShortcutOverride) { - if (hasFocus()) { - event->accept(); - return true; - } + if (event->type() == QEvent::Paint) { + QPainter p(this); + p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[ColorIndex::Background]); + return true; } if (event->type() == QEvent::KeyPress) { @@ -1490,13 +1506,63 @@ bool TerminalWidget::event(QEvent *event) return true; } - if (event->type() == QEvent::Paint) { - QPainter p(this); - p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[ColorIndex::Background]); - return true; - } - return QAbstractScrollArea::event(event); } +void TerminalWidget::initActions() +{ + Core::Context context(Utils::Id("TerminalWidget")); + + static QAction copy; + static QAction paste; + static QAction clearSelection; + static QAction clearTerminal; + static QAction moveCursorWordLeft; + static QAction moveCursorWordRight; + static QAction close; + + copy.setText(Tr::tr("Copy")); + paste.setText(Tr::tr("Paste")); + clearSelection.setText(Tr::tr("Clear Selection")); + clearTerminal.setText(Tr::tr("Clear Terminal")); + moveCursorWordLeft.setText(Tr::tr("Move Cursor Word Left")); + moveCursorWordRight.setText(Tr::tr("Move Cursor Word Right")); + close.setText(Tr::tr("Close Terminal")); + + ActionManager::registerAction(©, Constants::COPY, context) + ->setDefaultKeySequences({QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+C") : QLatin1String("Ctrl+Shift+C"))}); + + ActionManager::registerAction(&paste, Constants::PASTE, context) + ->setDefaultKeySequences({QKeySequence( + HostOsInfo::isMacHost() ? QLatin1String("Ctrl+V") : QLatin1String("Ctrl+Shift+V"))}); + + ActionManager::registerAction(&clearSelection, Constants::CLEARSELECTION, context); + + ActionManager::registerAction(&moveCursorWordLeft, Constants::MOVECURSORWORDLEFT, context) + ->setDefaultKeySequences({QKeySequence("Alt+Left")}); + + ActionManager::registerAction(&moveCursorWordRight, Constants::MOVECURSORWORDRIGHT, context) + ->setDefaultKeySequences({QKeySequence("Alt+Right")}); + + ActionManager::registerAction(&clearTerminal, Constants::CLEAR_TERMINAL, context); +} + +UnlockedGlobalAction TerminalWidget::unlockGlobalAction(const Utils::Id &commandId, + const Context &context) +{ + QAction *srcAction = ActionManager::command(commandId)->actionForContext( + Core::Constants::C_GLOBAL); + + ProxyAction *proxy = ProxyAction::proxyActionWithIcon(srcAction, srcAction->icon()); + ActionManager::registerAction(proxy, commandId, context); + + UnlockedGlobalAction registeredAction(proxy, [commandId](QAction *a) { + ActionManager::unregisterAction(a, commandId); + delete a; + }); + + return registeredAction; +} + } // namespace Terminal diff --git a/src/plugins/terminal/terminalwidget.h b/src/plugins/terminal/terminalwidget.h index f44a721bd31..4b82e4355a1 100644 --- a/src/plugins/terminal/terminalwidget.h +++ b/src/plugins/terminal/terminalwidget.h @@ -8,6 +8,8 @@ #include +#include + #include #include #include @@ -22,6 +24,8 @@ namespace Terminal { +using UnlockedGlobalAction = std::unique_ptr>; + class TerminalWidget : public QAbstractScrollArea { friend class CellIterator; @@ -46,6 +50,8 @@ public: void clearContents(); + void closeTerminal(); + TerminalSearch *search() { return m_search.get(); } struct Selection @@ -82,6 +88,11 @@ public: void restart(const Utils::Terminal::OpenTerminalParameters &openParameters); + static void initActions(); + + [[nodiscard]] static UnlockedGlobalAction unlockGlobalAction(const Utils::Id &commandId, + const Core::Context &context); + signals: void started(qint64 pid); void cwdChanged(const Utils::FilePath &cwd); @@ -178,6 +189,7 @@ protected: void updateCopyState(); private: + Core::Context m_context; std::unique_ptr m_process; std::unique_ptr m_surface; std::unique_ptr m_shellIntegration; @@ -226,6 +238,19 @@ private: Aggregation::Aggregate *m_aggregate{nullptr}; SearchHit m_lastSelectedHit{}; + + QAction m_copy; + QAction m_paste; + QAction m_clearSelection; + QAction m_clearTerminal; + QAction m_moveCursorWordLeft; + QAction m_moveCursorWordRight; + QAction m_close; + + UnlockedGlobalAction m_findInDocument; + UnlockedGlobalAction m_exit; + UnlockedGlobalAction m_options; + UnlockedGlobalAction m_settings; }; } // namespace Terminal From 476651e5a3e6eb0b05b6cb18c04f6b3fbf48a894 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Thu, 25 May 2023 18:56:03 +0200 Subject: [PATCH 1380/1447] McuSupport: inline mcukitcreationdialog.ui Change-Id: I1c88663248dceb318f9acbabe585fbd24e794ab6 Reviewed-by: hjk Reviewed-by: --- src/plugins/mcusupport/CMakeLists.txt | 2 +- .../dialogs/mcukitcreationdialog.cpp | 86 +++++++--- .../mcusupport/dialogs/mcukitcreationdialog.h | 17 +- .../dialogs/mcukitcreationdialog.ui | 154 ------------------ src/plugins/mcusupport/mcusupport.qbs | 1 - 5 files changed, 72 insertions(+), 188 deletions(-) delete mode 100644 src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index b0ff6d8fc45..e2d81ae5a73 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -24,7 +24,7 @@ add_qtc_plugin(McuSupport settingshandler.cpp settingshandler.h mcuqmlprojectnode.cpp mcuqmlprojectnode.h mcubuildstep.cpp mcubuildstep.h - dialogs/mcukitcreationdialog.h dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.ui + dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.h ) add_subdirectory(test) diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp index 7327f582115..9702fb77bfb 100644 --- a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp +++ b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "mcukitcreationdialog.h" -#include "ui_mcukitcreationdialog.h" #include "../mcuabstractpackage.h" #include "../mcusupportconstants.h" @@ -10,11 +9,15 @@ #include #include +#include #include -#include +#include #include +#include +#include +#include #include namespace McuSupport::Internal { @@ -24,18 +27,56 @@ McuKitCreationDialog::McuKitCreationDialog(const MessagesList &messages, McuPackagePtr qtMCUPackage, QWidget *parent) : QDialog(parent) - , ui(new Ui::McuKitCreationDialog) , m_messages(messages) { - ui->setupUi(this); - ui->iconLabel->setPixmap(Utils::Icon(":/mcusupport/images/mcusupportdevice.png").pixmap()); - m_previousButton = ui->buttonBox->addButton("<", QDialogButtonBox::ActionRole); - m_nextButton = ui->buttonBox->addButton(">", QDialogButtonBox::ActionRole); - m_fixButton = ui->buttonBox->addButton(Tr::tr("Fix"), QDialogButtonBox::ActionRole); - m_helpButton = ui->buttonBox->addButton(Tr::tr("Help"), QDialogButtonBox::HelpRole); - // prevent clicking the buttons from closing the message box - m_nextButton->disconnect(); - m_previousButton->disconnect(); + resize(500, 300); + setWindowTitle(Tr::tr("Qt for MCUs Kit Creation")); + + m_iconLabel = new QLabel; + m_iconLabel->setAlignment(Qt::AlignTop); + + m_textLabel = new QLabel; + + m_informationLabel = new QLabel; + m_informationLabel->setWordWrap(true); + m_informationLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_informationLabel->setAlignment(Qt::AlignTop); + + m_qtMCUsPathLabel = new QLabel; + + auto line = new QFrame; + line->setFrameShape(QFrame::VLine); + line->setFrameShadow(QFrame::Sunken); + + auto buttonBox = new QDialogButtonBox(Qt::Vertical); + buttonBox->setStandardButtons(QDialogButtonBox::Ignore); + + m_messageCountLabel = new QLabel; + m_messageCountLabel->setAlignment(Qt::AlignCenter); + + using namespace Layouting; + Row { + Column { + Row { + m_iconLabel, + Column { + m_textLabel, + m_informationLabel, + }, + }, + m_qtMCUsPathLabel, + }, + line, + Column { + buttonBox, + m_messageCountLabel, + }, + }.attachTo(this); + + m_previousButton = buttonBox->addButton("<", QDialogButtonBox::ActionRole); + m_nextButton = buttonBox->addButton(">", QDialogButtonBox::ActionRole); + QPushButton *fixButton = buttonBox->addButton(Tr::tr("Fix"), QDialogButtonBox::ActionRole); + QPushButton *helpButton = buttonBox->addButton(Tr::tr("Help"), QDialogButtonBox::HelpRole); if (messages.size() == 1) { m_nextButton->setVisible(false); @@ -46,20 +87,22 @@ McuKitCreationDialog::McuKitCreationDialog(const MessagesList &messages, updateMessage(1); if (qtMCUPackage->isValidStatus()) - ui->qtMCUsPathLabel->setText( + m_qtMCUsPathLabel->setText( Tr::tr("Qt for MCUs path %1").arg(qtMCUPackage->path().toUserOutput())); connect(m_nextButton, &QPushButton::clicked, [=] { updateMessage(1); }); connect(m_previousButton, &QPushButton::clicked, [=] { updateMessage(-1); }); - connect(m_fixButton, &QPushButton::clicked, [=] { + connect(fixButton, &QPushButton::clicked, [=] { // Open the MCU Options widget on the current platform settingsHandler->setInitialPlatformName(m_messages[m_currentIndex].platform); Core::ICore::showOptionsDialog(Constants::SETTINGS_ID); // reset the initial platform name settingsHandler->setInitialPlatformName(""); }); - connect(m_helpButton, &QPushButton::clicked, [] { + connect(helpButton, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://doc.qt.io/QtForMCUs/qtul-prerequisites.html")); }); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); } void McuKitCreationDialog::updateMessage(const int inc) @@ -67,30 +110,25 @@ void McuKitCreationDialog::updateMessage(const int inc) m_currentIndex += inc; m_nextButton->setEnabled(m_currentIndex < (m_messages.size() - 1)); m_previousButton->setEnabled(m_currentIndex > 0); - ui->textLabel->setText(QString("%1 %2 : %3") + m_textLabel->setText(QString("%1 %2 : %3") .arg(Tr::tr("Target"), (m_messages[m_currentIndex].status == McuSupportMessage::Warning ? Tr::tr("Warning") : Tr::tr("Error")), m_messages[m_currentIndex].platform)); - ui->iconLabel->setPixmap( + m_iconLabel->setPixmap( QApplication::style() ->standardIcon(m_messages[m_currentIndex].status == McuSupportMessage::Warning ? QStyle::SP_MessageBoxWarning : QStyle::SP_MessageBoxCritical) .pixmap(64, 64)); - ui->informationLabel->setText(QString("%1: %2

    %3: %4") + m_informationLabel->setText(QString("%1: %2

    %3: %4") .arg(Tr::tr("Package"), m_messages[m_currentIndex].packageName, Tr::tr("Status"), m_messages.at(m_currentIndex).message)); - ui->messageCountLabel->setText(QString("%1 / %2").arg(QString::number(m_currentIndex + 1), + m_messageCountLabel->setText(QString("%1 / %2").arg(QString::number(m_currentIndex + 1), QString::number(m_messages.size()))); } -McuKitCreationDialog::~McuKitCreationDialog() -{ - delete ui; -} - } // namespace McuSupport::Internal diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h index 7164c6d0efb..6caae59678f 100644 --- a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h +++ b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.h @@ -7,11 +7,11 @@ #include "../settingshandler.h" #include -#include -namespace Ui { -class McuKitCreationDialog; -} +QT_BEGIN_NAMESPACE +class QLabel; +class QPushButton; +QT_END_NAMESPACE namespace McuSupport::Internal { @@ -24,18 +24,19 @@ public: const SettingsHandler::Ptr &settingsHandler, McuPackagePtr qtMCUPackage, QWidget *parent = nullptr); - ~McuKitCreationDialog(); private slots: void updateMessage(const int inc); private: - Ui::McuKitCreationDialog *ui; int m_currentIndex = -1; + QLabel *m_iconLabel; + QLabel *m_textLabel; + QLabel *m_informationLabel; + QLabel *m_qtMCUsPathLabel; + QLabel *m_messageCountLabel; QPushButton *m_previousButton; QPushButton *m_nextButton; - QPushButton *m_helpButton; - QPushButton *m_fixButton; const MessagesList &m_messages; }; } // namespace McuSupport::Internal diff --git a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui b/src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui deleted file mode 100644 index f6194bbe6e3..00000000000 --- a/src/plugins/mcusupport/dialogs/mcukitcreationdialog.ui +++ /dev/null @@ -1,154 +0,0 @@ - - - McuKitCreationDialog - - - - 0 - 0 - 349 - 200 - - - - QtMCUs Kit Creation - - - true - - - - - - QtMCUs path: - - - - - - - Qt::Vertical - - - - - - - 1/3 - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - QDialogButtonBox::Ignore - - - - - - - Dialog text - - - Qt::RichText - - - true - - - - - - - - 64 - 64 - - - - - 70 - 1000 - - - - - - - false - - - Qt::AlignHCenter|Qt::AlignTop - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - TextLabel - - - Qt::RichText - - - - - - - - - - - buttonBox - accepted() - McuKitCreationDialog - accept() - - - 339 - 23 - - - 157 - 199 - - - - - buttonBox - rejected() - McuKitCreationDialog - reject() - - - 339 - 29 - - - 286 - 199 - - - - - diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index 7b686075cac..173fe55e6e8 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -58,7 +58,6 @@ QtcPlugin { "mcuhelpers.h", "settingshandler.h", "settingshandler.cpp", - "dialogs/mcukitcreationdialog.ui", "dialogs/mcukitcreationdialog.h", "dialogs/mcukitcreationdialog.cpp", ] From 95b4da9ba98f6fec624b8d8aee9fae58211668d6 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 14 Nov 2022 12:54:05 +0100 Subject: [PATCH 1381/1447] TextEditor: add tests for the code assistant Task-number: QTCREATORBUG-28989 Change-Id: Id76d5df589ab50c7deb96b8ad29d1f29bc368e59 Reviewed-by: Christian Stenger --- src/plugins/texteditor/CMakeLists.txt | 4 +- .../texteditor/codeassist/codeassist_test.cpp | 152 ++++++++++++++++++ .../texteditor/codeassist/codeassist_test.h | 37 +++++ src/plugins/texteditor/texteditor.qbs | 2 + src/plugins/texteditor/texteditor_test.cpp | 19 +-- src/plugins/texteditor/texteditorplugin.cpp | 8 + 6 files changed, 209 insertions(+), 13 deletions(-) create mode 100644 src/plugins/texteditor/codeassist/codeassist_test.cpp create mode 100644 src/plugins/texteditor/codeassist/codeassist_test.h diff --git a/src/plugins/texteditor/CMakeLists.txt b/src/plugins/texteditor/CMakeLists.txt index eebe8bf0bed..048cd40b1d5 100644 --- a/src/plugins/texteditor/CMakeLists.txt +++ b/src/plugins/texteditor/CMakeLists.txt @@ -113,5 +113,7 @@ add_qtc_plugin(TextEditor extend_qtc_plugin(TextEditor CONDITION WITH_TESTS - SOURCES texteditor_test.cpp + SOURCES + codeassist/codeassist_test.cpp codeassist/codeassist_test.h + texteditor_test.cpp ) diff --git a/src/plugins/texteditor/codeassist/codeassist_test.cpp b/src/plugins/texteditor/codeassist/codeassist_test.cpp new file mode 100644 index 00000000000..8b724dbe166 --- /dev/null +++ b/src/plugins/texteditor/codeassist/codeassist_test.cpp @@ -0,0 +1,152 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifdef WITH_TESTS + +#include "codeassist_test.h" + +#include "../texteditor.h" + +#include "assistinterface.h" +#include "assistproposaliteminterface.h" +#include "asyncprocessor.h" +#include "completionassistprovider.h" +#include "genericproposal.h" +#include "genericproposalwidget.h" + +#include +#include +#include + +#include + +namespace TextEditor::Internal { + +class TestProposalItem : public AssistProposalItemInterface +{ +public: + QString m_text = "test"; + bool m_implicitlyApplies = false; + bool m_prematurelyApplies = false; + QIcon m_icon; + QString m_detail = "detail"; + bool m_isSnippet = false; + bool m_isValid = true; + + QString text() const override { return m_text; } + bool implicitlyApplies() const override { return m_implicitlyApplies; } + bool prematurelyApplies(const QChar &) const override { return m_prematurelyApplies; } + QIcon icon() const override { return m_icon; } + QString detail() const override { return m_detail; } + bool isSnippet() const override { return m_isSnippet; } + bool isValid() const override { return m_isValid; } + quint64 hash() const override { return 0; } // used to remove duplicates +}; + +class OpenEditorItem : public TestProposalItem +{ +public: + void apply(TextDocumentManipulatorInterface &, int) const override + { + m_openedEditor = Core::EditorManager::openEditor(m_filePath, + Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); + } + + mutable Core::IEditor *m_openedEditor = nullptr; + Utils::FilePath m_filePath; +}; + +class TestProposalWidget : public GenericProposalWidget +{ +public: + void showProposal(const QString &prefix) override + { + GenericProposalModelPtr proposalModel = model(); + if (proposalModel && proposalModel->size() == 1) { + emit proposalItemActivated(proposalModel->proposalItem(0)); + deleteLater(); + return; + } + GenericProposalWidget::showProposal(prefix); + } +}; + +class TestProposal : public GenericProposal +{ +public: + TestProposal(int pos, const QList &items) + : GenericProposal(pos, items) + {} + IAssistProposalWidget *createWidget() const override { return new TestProposalWidget; } +}; + +class TestProcessor : public AsyncProcessor +{ +public: + TestProcessor(const QList &items) + : m_items(items) + {} + IAssistProposal *performAsync() override + { return new TestProposal(interface()->position(), m_items); } + QList m_items; +}; + +class TestProvider : public CompletionAssistProvider +{ +public: + IAssistProcessor *createProcessor(const AssistInterface *assistInterface) const override + { + Q_UNUSED(assistInterface); + return new TestProcessor(m_items); + } + QList m_items; +}; + +void CodeAssistTests::initTestCase() +{ + Core::IEditor *editor = Core::EditorManager::openEditorWithContents( + Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); + QVERIFY(editor); + m_editor = qobject_cast(editor); + QVERIFY(m_editor); + m_editorsToClose << m_editor; + m_testProvider = new TestProvider(); +} + +static Utils::FilePath createBigFile() +{ + constexpr int textChunkSize = 65536; // from utils/textfileformat.cpp + + const Utils::FilePath result = Utils::TemporaryDirectory::masterDirectoryFilePath() / "BigFile"; + QByteArray data; + data.reserve(textChunkSize); + while (data.size() < textChunkSize) + data.append("bigfile line\n"); + result.writeFileContents(data); + return result; +} + +void CodeAssistTests::testFollowSymbolBigFile() +{ + auto item = new OpenEditorItem; + item->m_filePath = createBigFile(); + m_testProvider->m_items = {item}; + auto editorWidget = m_editor->editorWidget(); + + editorWidget->invokeAssist(FollowSymbol, m_testProvider); + QSignalSpy spy(editorWidget, &TextEditorWidget::assistFinished); + QVERIFY(spy.wait(1000)); + QVERIFY(item->m_openedEditor); + m_editorsToClose << item->m_openedEditor; +} + +void CodeAssistTests::cleanupTestCase() +{ + m_testProvider->m_items.clear(); + Core::EditorManager::closeEditors(m_editorsToClose); + QVERIFY(Core::EditorManager::currentEditor() == nullptr); +} + +} // namespace TextEditor::Internal + +#endif // ifdef WITH_TESTS diff --git a/src/plugins/texteditor/codeassist/codeassist_test.h b/src/plugins/texteditor/codeassist/codeassist_test.h new file mode 100644 index 00000000000..3bf734aadfb --- /dev/null +++ b/src/plugins/texteditor/codeassist/codeassist_test.h @@ -0,0 +1,37 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#ifdef WITH_TESTS + +#include + +namespace Core { class IEditor; } +namespace TextEditor { class BaseTextEditor; } + +namespace TextEditor::Internal { + +class TestProvider; + +class CodeAssistTests : public QObject +{ + Q_OBJECT +public: + +private slots: + void initTestCase(); + + void testFollowSymbolBigFile(); + + void cleanupTestCase(); + +private: + TextEditor::BaseTextEditor *m_editor = nullptr; + QList m_editorsToClose; + TestProvider *m_testProvider = nullptr; +}; + +} // namespace TextEditor::Internal + +#endif diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index 1b94811a563..071e0b5fc2a 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -224,6 +224,8 @@ Project { QtcTestFiles { files: [ + "codeassist/codeassist_test.cpp", + "codeassist/codeassist_test.h", "texteditor_test.cpp", ] } diff --git a/src/plugins/texteditor/texteditor_test.cpp b/src/plugins/texteditor/texteditor_test.cpp index e939e515681..3b88ac5efb5 100644 --- a/src/plugins/texteditor/texteditor_test.cpp +++ b/src/plugins/texteditor/texteditor_test.cpp @@ -3,20 +3,13 @@ #ifdef WITH_TESTS -#include -#include -#include +#include "tabsettings.h" +#include "texteditorplugin.h" + +#include #include -#include -#include - -#include "texteditor.h" -#include "texteditorplugin.h" -#include "textdocument.h" -#include "tabsettings.h" - -using namespace TextEditor; +namespace TextEditor { QString tabPolicyToString(TabSettings::TabPolicy policy) { @@ -149,4 +142,6 @@ void Internal::TextEditorPlugin::testIndentationClean() QCOMPARE(settings.isIndentationClean(block, indentSize), clean); } +} // namespace TextEditor + #endif // ifdef WITH_TESTS diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index a66ddf23c32..4d5c2268d1e 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -20,6 +20,10 @@ #include "texteditorsettings.h" #include "texteditortr.h" +#ifdef WITH_TESTS +#include "codeassist/codeassist_test.h" +#endif + #include #include #include @@ -142,6 +146,10 @@ void TextEditorPlugin::initialize() Tr::tr("Text", "SnippetProvider")); d->createStandardContextMenu(); + +#ifdef WITH_TESTS + addTest(); +#endif } void TextEditorPluginPrivate::extensionsInitialized() From 8b848df8583c174d48bd30ea2397b4ebd2218c1b Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 09:38:24 +0200 Subject: [PATCH 1382/1447] WebAssembly: Use the more compact layouter function ... and delay the first update until all ui elements are present. Change-Id: Ica996c3262caed9397a951633b0971d48c7c683f Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/webassembly/webassemblysettings.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/plugins/webassembly/webassemblysettings.cpp b/src/plugins/webassembly/webassemblysettings.cpp index 1af1d30c911..fb9293f2c84 100644 --- a/src/plugins/webassembly/webassemblysettings.cpp +++ b/src/plugins/webassembly/webassemblysettings.cpp @@ -20,6 +20,7 @@ #include #include +#include using namespace Utils; @@ -66,7 +67,7 @@ WebAssemblySettings::WebAssemblySettings() connect(this, &Utils::AspectContainer::applied, &WebAssemblyToolChain::registerToolChains); - setLayouter([this](QWidget *widget) { + setLayouter([this] { auto instruction = new QLabel( Tr::tr("Select the root directory of an installed %1. " "Ensure that the activated SDK version is compatible with the %2 " @@ -96,7 +97,7 @@ WebAssemblySettings::WebAssemblySettings() // _clang-format off using namespace Layouting; - Column { + Column col { Group { title(Tr::tr("Emscripten SDK path:")), Column { @@ -113,12 +114,17 @@ WebAssemblySettings::WebAssemblySettings() }, }, m_qtVersionDisplay, - }.attachTo(widget); + }; // _clang-format on - updateStatus(); connect(emSdk.pathChooser(), &Utils::PathChooser::textChanged, this, &WebAssemblySettings::updateStatus); + + // updateStatus() uses m_emSdkEnvGroupBox which only exists + // after this here emerges. So delay the update a bit. + QTimer::singleShot(0, this, &WebAssemblySettings::updateStatus); + + return col; }); readSettings(); @@ -131,6 +137,8 @@ void WebAssemblySettings::updateStatus() const Utils::FilePath newEmSdk = emSdk.pathChooser()->filePath(); const bool sdkValid = newEmSdk.exists() && WebAssemblyEmSdk::isValid(newEmSdk); + QTC_ASSERT(m_emSdkVersionDisplay, return); + QTC_ASSERT(m_emSdkEnvGroupBox, return); m_emSdkVersionDisplay->setVisible(sdkValid); m_emSdkEnvGroupBox->setEnabled(sdkValid); From f8a28abd783b5f1514be516715fadb19fa54867d Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 1 Jun 2023 06:43:10 +0200 Subject: [PATCH 1383/1447] Terminal: Fix qbs build Change-Id: I7ce36f99927fe3d4a2d344819d8082fdae8cfce4 Reviewed-by: David Schulz --- src/plugins/terminal/terminal.qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/terminal/terminal.qbs b/src/plugins/terminal/terminal.qbs index c4c9de253e9..300c1acf19d 100644 --- a/src/plugins/terminal/terminal.qbs +++ b/src/plugins/terminal/terminal.qbs @@ -23,7 +23,7 @@ QtcPlugin { "shellintegration.h", "terminal.qrc", "terminalconstants.h", - "terminalicons.h" + "terminalicons.h", "terminalpane.cpp", "terminalpane.h", "terminalplugin.cpp", From deb974de053fe0db33924622479cf50b5296408b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 31 May 2023 10:04:05 +0200 Subject: [PATCH 1384/1447] Tr/LanguageClient: Add some comments, parametrize error message Change-Id: Ifd7354c10d18c0df093908c1a240f254c679893a Reviewed-by: David Schulz Reviewed-by: Leena Miettinen --- src/plugins/languageclient/client.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 9d2356a9d4d..130961ebd1b 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -356,6 +356,7 @@ void Client::setName(const QString &name) QString Client::name() const { if (d->m_project && !d->m_project->displayName().isEmpty()) + //: for return Tr::tr("%1 for %2").arg(d->m_displayName, d->m_project->displayName()); return d->m_displayName; } @@ -555,11 +556,17 @@ Client::State Client::state() const QString Client::stateString() const { switch (d->m_state){ + //: language client state case Uninitialized: return Tr::tr("uninitialized"); + //: language client state case InitializeRequested: return Tr::tr("initialize requested"); + //: language client state case Initialized: return Tr::tr("initialized"); + //: language client state case ShutdownRequested: return Tr::tr("shutdown requested"); + //: language client state case Shutdown: return Tr::tr("shut down"); + //: language client state case Error: return Tr::tr("error"); } return {}; @@ -1970,7 +1977,7 @@ void ClientPrivate::initializeCallback(const InitializeRequest::Response &initRe if (std::optional> error = initResponse.error()) { if (std::optional data = error->data()) { if (data->retry()) { - const QString title(Tr::tr("Language Server \"%1\" Initialize Error").arg(m_displayName)); + const QString title(Tr::tr("Language Server \"%1\" Initialization Error").arg(m_displayName)); auto result = QMessageBox::warning(Core::ICore::dialogParent(), title, error->message(), @@ -1983,7 +1990,7 @@ void ClientPrivate::initializeCallback(const InitializeRequest::Response &initRe } } } - q->setError(Tr::tr("Initialize error: ") + error->message()); + q->setError(Tr::tr("Initialization error: %1.").arg(error->message())); emit q->finished(); return; } From 0b863af8a1386d791b9eabcc1066f0563193ee91 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 31 May 2023 10:11:15 +0200 Subject: [PATCH 1385/1447] Tr/Python: Fix translation issues - Use parametrization - Split message that relied on sentence structure of the language Change-Id: I5c0cca684bc9c94219e740fe0292e358a91714da Reviewed-by: David Schulz Reviewed-by: Leena Miettinen Reviewed-by: --- src/plugins/python/pipsupport.cpp | 6 ++++-- src/plugins/python/pythonsettings.cpp | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 8e3f55dd11b..b420f24aa50 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -81,8 +81,10 @@ void PipInstallTask::cancel() m_process.stop(); m_process.waitForFinished(); Core::MessageManager::writeFlashing( - Tr::tr("The %1 installation was canceled by %2.") - .arg(packagesDisplayName(), m_killTimer.isActive() ? Tr::tr("user") : Tr::tr("time out"))); + m_killTimer.isActive() + ? Tr::tr("The installation of \"%1\" was canceled by timeout.").arg(packagesDisplayName()) + : Tr::tr("The installation of \"%1\" was canceled by the user.") + .arg(packagesDisplayName())); } void PipInstallTask::handleDone() diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index d33346b8af7..0fe6576170f 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -634,7 +634,8 @@ static void addPythonsFromRegistry(QList &pythons) const FilePath &executable = FilePath::fromUserInput(regVal.toString()); if (executable.exists() && !alreadyRegistered(pythons, executable)) { pythons << Interpreter{QUuid::createUuid().toString(), - name + Tr::tr(" (Windowed)"), + //: (Windowed) + Tr::tr("%1 (Windowed)").arg(name), FilePath::fromUserInput(regVal.toString())}; } } From b51188c9a9e6ec5bb4343ba70f5aae5d5e1bf553 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 03:58:39 +0200 Subject: [PATCH 1386/1447] TerminalPane: Fix a warning about an unused arg Change-Id: I63d19a608c63532e0e83df929da6cb07dc896722 Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/plugins/terminal/terminalpane.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 7cf0e308031..7e9cae7539e 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -163,6 +163,7 @@ TerminalWidget *TerminalPane::stoppedTerminalWithId(Id identifier) const QWidget *TerminalPane::outputWidget(QWidget *parent) { + Q_UNUSED(parent) if (!m_widgetInitialized) { m_widgetInitialized = true; m_tabWidget.setTabBarAutoHide(false); From 3c08ebbe265fbe34656b7e641300b8daabf3cffb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 29 May 2023 11:46:20 +0200 Subject: [PATCH 1387/1447] TaskTree: Make enums known to the Qt meta object system Change-Id: I72d8b74460febe1d7ad7d840e25cea02cd77b308 Reviewed-by: Marcus Tillmanns Reviewed-by: Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 872bce2ed86..37403628a5a 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -16,6 +16,8 @@ QT_END_NAMESPACE namespace Tasking { +Q_NAMESPACE + class ExecutionContextActivator; class TaskContainer; class TaskTreePrivate; @@ -109,6 +111,7 @@ enum class WorkflowPolicy { StopOnFinished, // 3 - Stops on first finished child and report its result. FinishAllAndDone // 4 - Reports done after all children finished. }; +Q_ENUM_NS(WorkflowPolicy); enum class TaskAction { @@ -116,6 +119,7 @@ enum class TaskAction StopWithDone, StopWithError }; +Q_ENUM_NS(TaskAction); class TASKING_EXPORT TaskItem { From 8636b35e87cec7517894ca30bad8f28b12060df2 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 09:08:50 +0200 Subject: [PATCH 1388/1447] RemoteLinux: Explicitly allow remote paths for device's gdbserver ... and qml runtime. Useful on Mac and Windows where there'd be a native but local chooser dialog otherwise. Change-Id: I6361c6f6067c86dd7cca15ce1dd02150136cf3f7 Reviewed-by: Tim Jenssen --- .../remotelinux/genericlinuxdeviceconfigurationwidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index ae85284ccb1..da7b6138dea 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -79,12 +79,14 @@ GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( m_gdbServerLineEdit->setPlaceholderText(hint); m_gdbServerLineEdit->setToolTip(hint); m_gdbServerLineEdit->setHistoryCompleter("GdbServer"); + m_gdbServerLineEdit->setAllowPathFromDevice(true); m_qmlRuntimeLineEdit = new PathChooser(this); m_qmlRuntimeLineEdit->setExpectedKind(PathChooser::ExistingCommand); m_qmlRuntimeLineEdit->setPlaceholderText(hint); m_qmlRuntimeLineEdit->setToolTip(hint); m_qmlRuntimeLineEdit->setHistoryCompleter("QmlRuntime"); + m_qmlRuntimeLineEdit->setAllowPathFromDevice(true); m_sourceProfileCheckBox = new QCheckBox(Tr::tr("Source %1 and %2").arg("/etc/profile").arg("$HOME/.profile")); From f72a5d18325fd013ffe5dead46f8bb1abbd9f09b Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 11:53:32 +0200 Subject: [PATCH 1389/1447] ProjectExplorer: Rename projectexplorersettingspage.cpp ... to projectexplorersettings.cpp and merge projectexplorersettingspage.h into projectexplorersettings.h. A preliminary step on the path to aspectification. Change-Id: Id482c0e8e03a2d37b07b9c1d810825afcede91b6 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/CMakeLists.txt | 3 +-- src/plugins/projectexplorer/projectexplorer.cpp | 1 - src/plugins/projectexplorer/projectexplorer.qbs | 3 +-- ...tingspage.cpp => projectexplorersettings.cpp} | 2 +- .../projectexplorer/projectexplorersettings.h | 8 ++++++++ .../projectexplorersettingspage.h | 16 ---------------- 6 files changed, 11 insertions(+), 22 deletions(-) rename src/plugins/projectexplorer/{projectexplorersettingspage.cpp => projectexplorersettings.cpp} (99%) delete mode 100644 src/plugins/projectexplorer/projectexplorersettingspage.h diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 00ea43530b9..d16e868a5cc 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -134,8 +134,7 @@ add_qtc_plugin(ProjectExplorer projectexplorerconstants.cpp projectexplorerconstants.h projectexplorericons.cpp projectexplorericons.h - projectexplorersettings.h - projectexplorersettingspage.cpp projectexplorersettingspage.h + projectexplorersettings.cpp projectexplorersettings.h projectexplorertr.h projectfilewizardextension.cpp projectfilewizardextension.h projectimporter.cpp projectimporter.h diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index eecf5332b00..9df791b3462 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -57,7 +57,6 @@ #include "project.h" #include "projectexplorericons.h" #include "projectexplorersettings.h" -#include "projectexplorersettingspage.h" #include "projectexplorertr.h" #include "projectfilewizardextension.h" #include "projectmanager.h" diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 3b407825713..c955a485905 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -110,8 +110,7 @@ Project { "projectexplorerconstants.cpp", "projectexplorerconstants.h", "projectexplorericons.h", "projectexplorericons.cpp", - "projectexplorersettings.h", - "projectexplorersettingspage.cpp", "projectexplorersettingspage.h", + "projectexplorersettings.h", "projectexplorersettings.cpp", "projectexplorertr.h", "projectfilewizardextension.cpp", "projectfilewizardextension.h", "projectimporter.cpp", "projectimporter.h", diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp similarity index 99% rename from src/plugins/projectexplorer/projectexplorersettingspage.cpp rename to src/plugins/projectexplorer/projectexplorersettings.cpp index c8bc51b9675..14f66b885bf 100644 --- a/src/plugins/projectexplorer/projectexplorersettingspage.cpp +++ b/src/plugins/projectexplorer/projectexplorersettings.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "projectexplorersettingspage.h" +#include "projectexplorersettings.h" #include "projectexplorer.h" #include "projectexplorerconstants.h" diff --git a/src/plugins/projectexplorer/projectexplorersettings.h b/src/plugins/projectexplorer/projectexplorersettings.h index bda218aef22..a65dbc2f6eb 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.h +++ b/src/plugins/projectexplorer/projectexplorersettings.h @@ -4,6 +4,8 @@ #pragma once #include +#include + #include #include @@ -80,5 +82,11 @@ public: int maxCharCount = Core::Constants::DEFAULT_MAX_CHAR_COUNT; }; +class ProjectExplorerSettingsPage : public Core::IOptionsPage +{ +public: + ProjectExplorerSettingsPage(); +}; + } // namespace Internal } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.h b/src/plugins/projectexplorer/projectexplorersettingspage.h deleted file mode 100644 index a924681daed..00000000000 --- a/src/plugins/projectexplorer/projectexplorersettingspage.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace ProjectExplorer::Internal { - -class ProjectExplorerSettingsPage : public Core::IOptionsPage -{ -public: - ProjectExplorerSettingsPage(); -}; - -} // ProjectExplorer::Internal From 93759796984138e5fca5781e22381dcba6a51824 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 09:51:27 +0200 Subject: [PATCH 1390/1447] Utils: Make PathChooser remote support configurable in aspects ... and switch is _on_ by default. Change-Id: I82e66da477dae1ee955b81babc6230b67e530d45 Reviewed-by: Tim Jenssen --- src/libs/utils/aspects.cpp | 9 +++++++++ src/libs/utils/aspects.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index d3610b2c7da..bb637f31b02 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -670,6 +670,7 @@ public: // Used to block recursive editingFinished signals for example when return is pressed, and // the validation changes focus by opening a dialog bool m_blockAutoApply = false; + bool m_allowPathFromDevice = true; template void updateWidgetFromCheckStatus(StringAspect *aspect, Widget *w) { @@ -977,6 +978,13 @@ void StringAspect::setCommandVersionArguments(const QStringList &arguments) d->m_pathChooserDisplay->setCommandVersionArguments(arguments); } +void StringAspect::setAllowPathFromDevice(bool allowPathFromDevice) +{ + d->m_allowPathFromDevice = allowPathFromDevice; + if (d->m_pathChooserDisplay) + d->m_pathChooserDisplay->setAllowPathFromDevice(allowPathFromDevice); +} + /*! Sets \a elideMode as label elide mode. */ @@ -1122,6 +1130,7 @@ void StringAspect::addToLayout(LayoutItem &parent) d->m_pathChooserDisplay->setPromptDialogFilter(d->m_prompDialogFilter); d->m_pathChooserDisplay->setPromptDialogTitle(d->m_prompDialogTitle); d->m_pathChooserDisplay->setCommandVersionArguments(d->m_commandVersionArguments); + d->m_pathChooserDisplay->setAllowPathFromDevice(d->m_allowPathFromDevice); if (defaultValue() == value()) d->m_pathChooserDisplay->setDefaultValue(defaultValue()); else diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 35e8a62b8f7..db3c036cec3 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -406,6 +406,7 @@ public: void setOpenTerminalHandler(const std::function &openTerminal); void setAutoApplyOnEditingFinished(bool applyOnEditingFinished); void setElideMode(Qt::TextElideMode elideMode); + void setAllowPathFromDevice(bool allowPathFromDevice); void validateInput(); From 5365c5de80b78e8a73cc966193e4627a048f614e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 09:50:50 +0200 Subject: [PATCH 1391/1447] Tr/QML Code Style: Just use "Other" for group box title "Qml JS Code Style" is wrong (consistent would probably be "QML/JS Code Style"), and since this is already with "Qt Quick > Code Style" with another group box titled "Tabs and Indentation", it is also weird (the other group box is also about the QML/JS code style). Change-Id: I61d5f273b91aebf95f0e5f5913e160195dcd7a11 Reviewed-by: Ulf Hermann Reviewed-by: hjk Reviewed-by: Leena Miettinen --- src/plugins/qmljstools/qmljscodestylesettingswidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp index 34919f6144f..9fee7205b3d 100644 --- a/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp +++ b/src/plugins/qmljstools/qmljscodestylesettingswidget.cpp @@ -20,15 +20,17 @@ QmlJSCodeStyleSettingsWidget::QmlJSCodeStyleSettingsWidget(QWidget *parent) m_lineLengthSpinBox->setMaximum(999); using namespace Layouting; + // clang-format off Column { Group { - title(Tr::tr("Qml JS Code Style")), + title(Tr::tr("Other")), Form { Tr::tr("&Line length:"), m_lineLengthSpinBox, br, } }, noMargin }.attachTo(this); + // clang-format on connect(m_lineLengthSpinBox, &QSpinBox::valueChanged, this, &QmlJSCodeStyleSettingsWidget::slotSettingsChanged); From 10bf294975a7e71d8ac9d53ffde4cf03cba6dc16 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 26 May 2023 11:11:39 +0200 Subject: [PATCH 1392/1447] Use KiB/MiB/GiB/TiB for 1024-based units MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That is also consistent with our file properties panel Change-Id: Ief62f8c067896a410878cfa4c36f17c6daf6fee7 Reviewed-by: Mahmoud Badri Reviewed-by: Leena Miettinen Reviewed-by: Robert Löhning --- share/qtcreator/translations/qtcreator_de.ts | 12 ++++++------ src/plugins/coreplugin/systemsettings.cpp | 3 +-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index c6e2a4cab88..ee6e08a335c 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -18199,16 +18199,16 @@ Möchten Sie sie jetzt auschecken? Bytes
    - KB - KB + KiB + KiB - GB - GB + GiB + GiB - TB - TB + TiB + TiB Enable crash reporting diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index 5d9a5fd3f9f..f6641bad08f 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -51,8 +51,7 @@ const char showCrashButtonKey[] = "ShowCrashButton"; // TODO: move to somewhere in Utils static QString formatSize(qint64 size) { - QStringList units {Tr::tr("Bytes"), Tr::tr("KB"), Tr::tr("MB"), - Tr::tr("GB"), Tr::tr("TB")}; + QStringList units{Tr::tr("Bytes"), Tr::tr("KiB"), Tr::tr("MiB"), Tr::tr("GiB"), Tr::tr("TiB")}; double outputSize = size; int i; for (i = 0; i < units.size() - 1; ++i) { From 3ca94f9c909011404f4ae04ba6ad111fe58ecdfa Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 09:43:42 +0200 Subject: [PATCH 1393/1447] Debugger: Use simpler setLayouter function Change-Id: Ib213100fc9dd37b23d323a99007e6ed73378f347 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/debugger/gdb/gdboptionspage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp index 3d24dd6c9cf..37008cabcd1 100644 --- a/src/plugins/debugger/gdb/gdboptionspage.cpp +++ b/src/plugins/debugger/gdb/gdboptionspage.cpp @@ -32,7 +32,7 @@ public: setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY); setSettings(&debuggerSettings()->page2); - setLayouter([](QWidget *w) { + setLayouter([] { using namespace Layouting; DebuggerSettings &s = *debuggerSettings(); @@ -84,7 +84,7 @@ public: Column { s.gdbPostAttachCommands }, }; - Grid { general, extended, br, startup, attach }.attachTo(w); + return Grid { general, extended, br, startup, attach }; }); } }; From 9574122da1f18fec548cb9a53031b68a623494ad Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 12:38:49 +0200 Subject: [PATCH 1394/1447] ProjectExplorer: Aspectify Compile output settings page Change-Id: Icc7b1917a57a96e482db7b4f0ba5c0a203f4958c Reviewed-by: Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/buildmanager.cpp | 14 +- src/plugins/projectexplorer/buildmanager.h | 9 +- .../projectexplorer/compileoutputwindow.cpp | 120 +++++++----------- .../projectexplorer/compileoutputwindow.h | 24 ++-- .../projectexplorer/projectexplorer.cpp | 1 - .../projectexplorer/projectexplorersettings.h | 8 -- 6 files changed, 62 insertions(+), 114 deletions(-) diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index 6284a960417..28169513cb7 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -442,16 +442,6 @@ int BuildManager::getErrorTaskCount() return errors; } -void BuildManager::setCompileOutputSettings(const CompileOutputSettings &settings) -{ - d->m_outputWindow->setSettings(settings); -} - -const CompileOutputSettings &BuildManager::compileOutputSettings() -{ - return d->m_outputWindow->settings(); -} - QString BuildManager::displayNameForStepId(Id stepId) { if (stepId == Constants::BUILDSTEPS_CLEAN) { @@ -853,7 +843,7 @@ bool BuildManager::buildLists(const QList bsls, const QStringLi return false; } - if (d->m_outputWindow->settings().popUp) + if (CompileOutputSettings::instance().popUp()) d->m_outputWindow->popup(IOutputPane::NoModeSwitch); startBuildQueue(); return true; @@ -866,7 +856,7 @@ void BuildManager::appendStep(BuildStep *step, const QString &name) d->m_outputWindow->popup(IOutputPane::NoModeSwitch); return; } - if (d->m_outputWindow->settings().popUp) + if (CompileOutputSettings::instance().popUp()) d->m_outputWindow->popup(IOutputPane::NoModeSwitch); startBuildQueue(); } diff --git a/src/plugins/projectexplorer/buildmanager.h b/src/plugins/projectexplorer/buildmanager.h index d7d2c91562a..d9478db4093 100644 --- a/src/plugins/projectexplorer/buildmanager.h +++ b/src/plugins/projectexplorer/buildmanager.h @@ -10,12 +10,10 @@ #include namespace ProjectExplorer { -class RunConfiguration; -namespace Internal { class CompileOutputSettings; } - -class Task; class Project; +class RunConfiguration; +class Task; enum class BuildForRunConfigStatus { Building, NotBuilding, BuildFailed }; enum class ConfigSelection { All, Active }; @@ -66,9 +64,6 @@ public: static int getErrorTaskCount(); - static void setCompileOutputSettings(const Internal::CompileOutputSettings &settings); - static const Internal::CompileOutputSettings &compileOutputSettings(); - static QString displayNameForStepId(Utils::Id stepId); public slots: diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index f345792ca83..bafc31fc14a 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -17,7 +17,9 @@ #include #include #include + #include +#include #include #include #include @@ -43,9 +45,6 @@ namespace Internal { const char SETTINGS_KEY[] = "ProjectExplorer/CompileOutput/Zoom"; const char C_COMPILE_OUTPUT[] = "ProjectExplorer.CompileOutput"; -const char POP_UP_KEY[] = "ProjectExplorer/Settings/ShowCompilerOutput"; -const char WRAP_OUTPUT_KEY[] = "ProjectExplorer/Settings/WrapBuildOutput"; -const char MAX_LINES_KEY[] = "ProjectExplorer/Settings/MaxBuildOutputLines"; const char OPTIONS_PAGE_ID[] = "C.ProjectExplorer.CompileOutputOptions"; CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) : @@ -101,8 +100,17 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) : Tr::tr("O")); ExtensionSystem::PluginManager::addObject(m_handler); setupContext(C_COMPILE_OUTPUT, m_outputWindow); - loadSettings(); updateFromSettings(); + + m_outputWindow->setWordWrapEnabled(m_settings.wrapOutput()); + m_outputWindow->setMaxCharCount(m_settings.maxCharCount()); + + connect(&m_settings.wrapOutput, &Utils::BaseAspect::changed, m_outputWindow, [this] { + m_outputWindow->setWordWrapEnabled(m_settings.wrapOutput()); + }); + connect(&m_settings.maxCharCount, &Utils::BaseAspect::changed, m_outputWindow, [this] { + m_outputWindow->setMaxCharCount(m_settings.maxCharCount()); + }); } CompileOutputWindow::~CompileOutputWindow() @@ -115,10 +123,7 @@ CompileOutputWindow::~CompileOutputWindow() void CompileOutputWindow::updateFromSettings() { - m_outputWindow->setWordWrapEnabled(m_settings.wrapOutput); - m_outputWindow->setMaxCharCount(m_settings.maxCharCount); } - bool CompileOutputWindow::hasFocus() const { return m_outputWindow->window()->focusWidget() == m_outputWindow; @@ -213,13 +218,6 @@ void CompileOutputWindow::reset() m_outputWindow->reset(); } -void CompileOutputWindow::setSettings(const CompileOutputSettings &settings) -{ - m_settings = settings; - storeSettings(); - updateFromSettings(); -} - Utils::OutputFormatter *CompileOutputWindow::outputFormatter() const { return m_outputWindow->outputFormatter(); @@ -231,75 +229,49 @@ void CompileOutputWindow::updateFilter() filterUsesRegexp(), filterIsInverted()); } -const bool kPopUpDefault = false; -const bool kWrapOutputDefault = true; +// CompileOutputSettings -void CompileOutputWindow::loadSettings() +static CompileOutputSettings *s_compileOutputSettings; + +CompileOutputSettings &CompileOutputSettings::instance() { - QSettings * const s = Core::ICore::settings(); - m_settings.popUp = s->value(POP_UP_KEY, kPopUpDefault).toBool(); - m_settings.wrapOutput = s->value(WRAP_OUTPUT_KEY, kWrapOutputDefault).toBool(); - m_settings.maxCharCount = s->value(MAX_LINES_KEY, - Core::Constants::DEFAULT_MAX_CHAR_COUNT).toInt() * 100; + return *s_compileOutputSettings; } -void CompileOutputWindow::storeSettings() const +CompileOutputSettings::CompileOutputSettings() { - Utils::QtcSettings *const s = Core::ICore::settings(); - s->setValueWithDefault(POP_UP_KEY, m_settings.popUp, kPopUpDefault); - s->setValueWithDefault(WRAP_OUTPUT_KEY, m_settings.wrapOutput, kWrapOutputDefault); - s->setValueWithDefault(MAX_LINES_KEY, - m_settings.maxCharCount / 100, - Core::Constants::DEFAULT_MAX_CHAR_COUNT); -} + s_compileOutputSettings = this; -class CompileOutputSettingsWidget : public Core::IOptionsPageWidget -{ -public: - CompileOutputSettingsWidget() - { - const CompileOutputSettings &settings = BuildManager::compileOutputSettings(); - m_wrapOutputCheckBox.setText(Tr::tr("Word-wrap output")); - m_wrapOutputCheckBox.setChecked(settings.wrapOutput); - m_popUpCheckBox.setText(Tr::tr("Open Compile Output when building")); - m_popUpCheckBox.setChecked(settings.popUp); - m_maxCharsBox.setMaximum(100000000); - m_maxCharsBox.setValue(settings.maxCharCount); - const auto layout = new QVBoxLayout(this); - layout->addWidget(&m_wrapOutputCheckBox); - layout->addWidget(&m_popUpCheckBox); - const auto maxCharsLayout = new QHBoxLayout; - const QString msg = Tr::tr("Limit output to %1 characters"); - const QStringList parts = msg.split("%1") << QString() << QString(); - maxCharsLayout->addWidget(new QLabel(parts.at(0).trimmed())); - maxCharsLayout->addWidget(&m_maxCharsBox); - maxCharsLayout->addWidget(new QLabel(parts.at(1).trimmed())); - maxCharsLayout->addStretch(1); - layout->addLayout(maxCharsLayout); - layout->addStretch(1); - } - - void apply() final - { - CompileOutputSettings s; - s.wrapOutput = m_wrapOutputCheckBox.isChecked(); - s.popUp = m_popUpCheckBox.isChecked(); - s.maxCharCount = m_maxCharsBox.value(); - BuildManager::setCompileOutputSettings(s); - } - -private: - QCheckBox m_wrapOutputCheckBox; - QCheckBox m_popUpCheckBox; - QSpinBox m_maxCharsBox; -}; - -CompileOutputSettingsPage::CompileOutputSettingsPage() -{ setId(OPTIONS_PAGE_ID); setDisplayName(Tr::tr("Compile Output")); setCategory(Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); - setWidgetCreator([] { return new CompileOutputSettingsWidget; }); + + wrapOutput.setSettingsKey("ProjectExplorer/Settings/WrapBuildOutput"); + wrapOutput.setDefaultValue(true); + wrapOutput.setLabelText(Tr::tr("Word-wrap output")); + + popUp.setSettingsKey("ProjectExplorer/Settings/ShowCompilerOutput"); + popUp.setLabelText(Tr::tr("Open Compile Output when building")); + + maxCharCount.setSettingsKey("ProjectExplorer/Settings/MaxBuildOutputLines"); + maxCharCount.setRange(1, Core::Constants::DEFAULT_MAX_CHAR_COUNT); + maxCharCount.setDefaultValue(Core::Constants::DEFAULT_MAX_CHAR_COUNT); + maxCharCount.setToSettingsTransformation([](const QVariant &v) { return v.toInt() / 100; }); + maxCharCount.setFromSettingsTransformation([](const QVariant &v) { return v.toInt() * 100; }); + + setLayouter([this] { + using namespace Layouting; + const QString msg = Tr::tr("Limit output to %1 characters"); + const QStringList parts = msg.split("%1") << QString() << QString(); + return Column { + wrapOutput, + popUp, + Row { parts.at(0), maxCharCount, parts.at(1), st }, + st + }; + }); + + readSettings(); } } // Internal diff --git a/src/plugins/projectexplorer/compileoutputwindow.h b/src/plugins/projectexplorer/compileoutputwindow.h index e1f000de9ae..89c7b749f2e 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.h +++ b/src/plugins/projectexplorer/compileoutputwindow.h @@ -26,6 +26,18 @@ namespace Internal { class ShowOutputTaskHandler; class CompileOutputTextEdit; +class CompileOutputSettings final : public Core::PagedSettings +{ +public: + CompileOutputSettings(); + + static CompileOutputSettings &instance(); + + Utils::BoolAspect popUp{this}; + Utils::BoolAspect wrapOutput{this}; + Utils::IntegerAspect maxCharCount{this}; +}; + class CompileOutputWindow final : public Core::IOutputPane { Q_OBJECT @@ -57,19 +69,13 @@ public: void flush(); void reset(); - const CompileOutputSettings &settings() const { return m_settings; } - void setSettings(const CompileOutputSettings &settings); - Utils::OutputFormatter *outputFormatter() const; private: void updateFilter() override; const QList outputWindows() const override { return {m_outputWindow}; } - void loadSettings(); - void storeSettings() const; void updateFromSettings(); - Core::OutputWindow *m_outputWindow; ShowOutputTaskHandler *m_handler; QToolButton *m_cancelBuildButton; @@ -77,11 +83,5 @@ private: CompileOutputSettings m_settings; }; -class CompileOutputSettingsPage final : public Core::IOptionsPage -{ -public: - CompileOutputSettingsPage(); -}; - } // namespace Internal } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 9df791b3462..d313cb433de 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -666,7 +666,6 @@ public: // Settings pages ProjectExplorerSettingsPage m_projectExplorerSettingsPage; AppOutputSettingsPage m_appOutputSettingsPage; - CompileOutputSettingsPage m_compileOutputSettingsPage; DeviceSettingsPage m_deviceSettingsPage; SshSettingsPage m_sshSettingsPage; CustomParsersSettingsPage m_customParsersSettingsPage; diff --git a/src/plugins/projectexplorer/projectexplorersettings.h b/src/plugins/projectexplorer/projectexplorersettings.h index a65dbc2f6eb..48cc85c414b 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.h +++ b/src/plugins/projectexplorer/projectexplorersettings.h @@ -74,14 +74,6 @@ public: int maxCharCount = Core::Constants::DEFAULT_MAX_CHAR_COUNT; }; -class CompileOutputSettings -{ -public: - bool popUp = false; - bool wrapOutput = false; - int maxCharCount = Core::Constants::DEFAULT_MAX_CHAR_COUNT; -}; - class ProjectExplorerSettingsPage : public Core::IOptionsPage { public: From a17fe325c08673787b10a9cb7622a0ef3262ff1d Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Thu, 1 Jun 2023 10:35:28 +0200 Subject: [PATCH 1395/1447] RemoteLinux: set a default QmlRunCommand If there is no device qmlRunCommand even though it is a remote device QmlProjectRunConfiguration uses a desktop path and on windows that results in wrong file separators -> "\usr\bin\appcontroller ..." Task-number: QDS-9994 Change-Id: I054addf86922b50bc2e2f620d536953b72ee3331 Reviewed-by: Tim Jenssen --- src/plugins/remotelinux/linuxdevice.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 59af192eaa2..cc44dddb3c4 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -978,6 +978,7 @@ LinuxDevice::LinuxDevice() addDeviceAction({Tr::tr("Open Remote Shell"), [](const IDevice::Ptr &device, QWidget *) { device->openTerminal(Environment(), FilePath()); }}); + setQmlRunCommand(filePath("qml")); } void LinuxDevice::_setOsType(Utils::OsType osType) From 1e09ac087a635f8207399d6851767214b75e0fb4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 31 May 2023 23:44:43 +0200 Subject: [PATCH 1396/1447] SilverSearcher: Limit the number of calls to nextLine() It's a preparation step for the incremental parsing. Change-Id: I98268abd6d3e0210f218663a6c2bb701c3bfc070 Reviewed-by: Orgad Shaneh Reviewed-by: Qt CI Bot --- src/plugins/silversearcher/silversearcheroutputparser.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/silversearcher/silversearcheroutputparser.cpp b/src/plugins/silversearcher/silversearcheroutputparser.cpp index 65d773d0c68..e9e16fa077e 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.cpp +++ b/src/plugins/silversearcher/silversearcheroutputparser.cpp @@ -112,8 +112,10 @@ SearchResultItems parse(const QString &output, const std::optional Date: Wed, 31 May 2023 23:49:11 +0200 Subject: [PATCH 1397/1447] SilverSearcher: Use the text editor font for the results This looks more consistent with the results reported by the internal engine. Change-Id: I1f5a405bcfd7b32c01ef6d4db0324985e657f6a3 Reviewed-by: Qt CI Bot Reviewed-by: Orgad Shaneh --- src/plugins/silversearcher/outputparser_test.cpp | 1 + src/plugins/silversearcher/silversearcheroutputparser.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/plugins/silversearcher/outputparser_test.cpp b/src/plugins/silversearcher/outputparser_test.cpp index 4aaacf37e68..e517e7e851d 100644 --- a/src/plugins/silversearcher/outputparser_test.cpp +++ b/src/plugins/silversearcher/outputparser_test.cpp @@ -18,6 +18,7 @@ SearchResultItem searchResult(const FilePath &fileName, const QString &matchingL result.setFilePath(fileName); result.setLineText(matchingLine); result.setMainRange(lineNumber, matchStart, matchLength); + result.setUseTextEditorFont(true); return result; } diff --git a/src/plugins/silversearcher/silversearcheroutputparser.cpp b/src/plugins/silversearcher/silversearcheroutputparser.cpp index e9e16fa077e..1cd1538830e 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.cpp +++ b/src/plugins/silversearcher/silversearcheroutputparser.cpp @@ -128,6 +128,7 @@ SearchResultItems parse(const QString &output, const std::optional &hit : hits) { item.setMainRange(lineNumber, hit.first, hit.second); item.setUserData( From 5c5624007beac1b69eae873d25e4c41644f380c3 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 08:49:34 +0200 Subject: [PATCH 1398/1447] FakeVim: Use PagedSettings for main settings Change-Id: I5029ae42ca5c3ec426d37a818150677186dd55ea Reviewed-by: Alessandro Portale --- src/plugins/fakevim/fakevimactions.cpp | 148 +++++++++++++++++++++++-- src/plugins/fakevim/fakevimactions.h | 4 +- src/plugins/fakevim/fakevimplugin.cpp | 130 +--------------------- 3 files changed, 144 insertions(+), 138 deletions(-) diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index dc051d81040..b753939c056 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -10,6 +10,13 @@ // Qt Creator. The idea is to keep this file here in a "clean" state that // allows easy reuse with any QTextEdit or QPlainTextEdit derived class. +#ifndef FAKEVIM_STANDALONE +#include +#include +#include +#include +#endif + #include #include #include @@ -62,13 +69,31 @@ QString FvBaseAspect::settingsKey() const void setAutoApply(bool ) {} #endif + +static FakeVimSettings *s_settings; + +FakeVimSettings *fakeVimSettings() +{ + return s_settings; +} + FakeVimSettings::FakeVimSettings() { - setAutoApply(false); + s_settings = this; #ifndef FAKEVIM_STANDALONE + const char SETTINGS_CATEGORY[] = "D.FakeVim"; + const char SETTINGS_ID[] = "A.FakeVim.General"; + + setId(SETTINGS_ID); + setDisplayName(Tr::tr("General")); + setCategory(SETTINGS_CATEGORY); + setDisplayCategory(Tr::tr("FakeVim")); + setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png"); + setup(&useFakeVim, false, "UseFakeVim", {}, Tr::tr("Use FakeVim")); #endif + // Specific FakeVim settings setup(&readVimRc, false, "ReadVimRc", {}, Tr::tr("Read .vimrc from location:")); setup(&vimRcPath, QString(), "VimRcPath", {}, {}); // Tr::tr("Path to .vimrc") @@ -135,6 +160,121 @@ FakeVimSettings::FakeVimSettings() "%USERPROFILE%\\_vimrc on Windows, ~/.vimrc otherwise.")); vimRcPath.setPlaceHolderText(Tr::tr("Default: %1").arg(vimrcDefault)); vimRcPath.setDisplayStyle(FvStringAspect::PathChooserDisplay); + + setLayouter([this] { + using namespace Layouting; + using namespace TextEditor; + + Row bools { + Column { + autoIndent, + smartIndent, + expandTab, + smartTab, + hlSearch, + showCmd, + startOfLine, + passKeys, + blinkingCursor + }, + Column { + incSearch, + useCoreSearch, + ignoreCase, + smartCase, + wrapScan, + showMarks, + passControlKey, + relativeNumber, + tildeOp + } + }; + + Row ints { shiftWidth, tabStop, scrollOff, st }; + + vimRcPath.setEnabler(&readVimRc); + + Column strings { + backspace, + isKeyword, + Row {readVimRc, vimRcPath} + }; + + return Column { + useFakeVim, + + Group { + title(Tr::tr("Vim Behavior")), + Column { + bools, + ints, + strings + } + }, + + Group { + title(Tr::tr("Plugin Emulation")), + Column { + emulateVimCommentary, + emulateReplaceWithRegister, + emulateArgTextObj, + emulateExchange, + emulateSurround + } + }, + + Row { + PushButton { + text(Tr::tr("Copy Text Editor Settings")), + onClicked([this] { + TabSettings ts = TextEditorSettings::codeStyle()->tabSettings(); + TypingSettings tps = TextEditorSettings::typingSettings(); + expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy); + tabStop.setValue(ts.m_tabSize); + shiftWidth.setValue(ts.m_indentSize); + smartTab.setValue(tps.m_smartBackspaceBehavior + == TypingSettings::BackspaceFollowsPreviousIndents); + autoIndent.setValue(true); + smartIndent.setValue(tps.m_autoIndent); + incSearch.setValue(true); + }), + }, + PushButton { + text(Tr::tr("Set Qt Style")), + onClicked([this] { + expandTab.setVolatileValue(true); + tabStop.setVolatileValue(4); + shiftWidth.setVolatileValue(4); + smartTab.setVolatileValue(true); + autoIndent.setVolatileValue(true); + smartIndent.setVolatileValue(true); + incSearch.setVolatileValue(true); + backspace.setVolatileValue(QString("indent,eol,start")); + passKeys.setVolatileValue(true); + }), + }, + PushButton { + text(Tr::tr("Set Plain Style")), + onClicked([this] { + expandTab.setVolatileValue(false); + tabStop.setVolatileValue(8); + shiftWidth.setVolatileValue(8); + smartTab.setVolatileValue(false); + autoIndent.setVolatileValue(false); + smartIndent.setVolatileValue(false); + incSearch.setVolatileValue(false); + backspace.setVolatileValue(QString()); + passKeys.setVolatileValue(false); + }), + }, + st + }, + st + }; + }); + + readSettings(); + #endif } @@ -187,11 +327,5 @@ void FakeVimSettings::setup(FvBaseAspect *aspect, m_nameToAspect[shortName] = aspect; } -FakeVimSettings *fakeVimSettings() -{ - static FakeVimSettings s; - return &s; -} - } // namespace Internal } // namespace FakeVim diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h index 582630e83d1..2f3f72f6951 100644 --- a/src/plugins/fakevim/fakevimactions.h +++ b/src/plugins/fakevim/fakevimactions.h @@ -4,7 +4,7 @@ #pragma once #ifndef FAKEVIM_STANDALONE -# include +# include #endif #include @@ -68,7 +68,7 @@ public: #else -using FvAspectContainer = Utils::AspectContainer; +using FvAspectContainer = Core::PagedSettings; using FvBaseAspect = Utils::BaseAspect; using FvBoolAspect = Utils::BoolAspect; using FvIntegerAspect = Utils::IntegerAspect; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 49354921325..c0e908ed573 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -340,134 +340,6 @@ private: using ExCommandMap = QMap; using UserCommandMap = QMap; -static void layoutPage(QWidget *widget) -{ - using namespace Layouting; - FakeVimSettings &s = *fakeVimSettings(); - - Row bools { - Column { - s.autoIndent, - s.smartIndent, - s.expandTab, - s.smartTab, - s.hlSearch, - s.showCmd, - s.startOfLine, - s.passKeys, - s.blinkingCursor - }, - Column { - s.incSearch, - s.useCoreSearch, - s.ignoreCase, - s.smartCase, - s.wrapScan, - s.showMarks, - s.passControlKey, - s.relativeNumber, - s.tildeOp - } - }; - - Row ints { s.shiftWidth, s.tabStop, s.scrollOff, st }; - - Column strings { - s.backspace, - s.isKeyword, - Row {s.readVimRc, s.vimRcPath} - }; - - Column { - s.useFakeVim, - - Group { - title(Tr::tr("Vim Behavior")), - Column { - bools, - ints, - strings - } - }, - - Group { - title(Tr::tr("Plugin Emulation")), - Column { - s.emulateVimCommentary, - s.emulateReplaceWithRegister, - s.emulateArgTextObj, - s.emulateExchange, - s.emulateSurround - } - }, - - Row { - PushButton { - text(Tr::tr("Copy Text Editor Settings")), - onClicked([&s] { - TabSettings ts = TextEditorSettings::codeStyle()->tabSettings(); - TypingSettings tps = TextEditorSettings::typingSettings(); - s.expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy); - s.tabStop.setValue(ts.m_tabSize); - s.shiftWidth.setValue(ts.m_indentSize); - s.smartTab.setValue(tps.m_smartBackspaceBehavior - == TypingSettings::BackspaceFollowsPreviousIndents); - s.autoIndent.setValue(true); - s.smartIndent.setValue(tps.m_autoIndent); - s.incSearch.setValue(true); - }), - }, - PushButton { - text(Tr::tr("Set Qt Style")), - onClicked([&s] { - s.expandTab.setVolatileValue(true); - s.tabStop.setVolatileValue(4); - s.shiftWidth.setVolatileValue(4); - s.smartTab.setVolatileValue(true); - s.autoIndent.setVolatileValue(true); - s.smartIndent.setVolatileValue(true); - s.incSearch.setVolatileValue(true); - s.backspace.setVolatileValue(QString("indent,eol,start")); - s.passKeys.setVolatileValue(true); - }), - }, - PushButton { - text(Tr::tr("Set Plain Style")), - onClicked([&s] { - s.expandTab.setVolatileValue(false); - s.tabStop.setVolatileValue(8); - s.shiftWidth.setVolatileValue(8); - s.smartTab.setVolatileValue(false); - s.autoIndent.setVolatileValue(false); - s.smartIndent.setVolatileValue(false); - s.incSearch.setVolatileValue(false); - s.backspace.setVolatileValue(QString()); - s.passKeys.setVolatileValue(false); - }), - }, - st - }, - st - - }.attachTo(widget); - - s.vimRcPath.setEnabler(&s.readVimRc); -} - -class FakeVimOptionPage : public IOptionsPage -{ -public: - FakeVimOptionPage() - { - setId(SETTINGS_ID); - setDisplayName(Tr::tr("General")); - setCategory(SETTINGS_CATEGORY); - setDisplayCategory(Tr::tr("FakeVim")); - setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png"); - setLayouter(&layoutPage); - setSettings(fakeVimSettings()); - } -}; /////////////////////////////////////////////////////////////////////// // @@ -1107,7 +979,7 @@ IAssistProcessor *FakeVimCompletionAssistProvider::createProcessor(const AssistI class FakeVimPluginRunData { public: - FakeVimOptionPage optionsPage; + FakeVimSettings settings; FakeVimExCommandsPage exCommandsPage; FakeVimUserCommandsPage userCommandsPage; From a3bb39d3c37aebd63af5cf908a177cb69292460e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 00:54:51 +0200 Subject: [PATCH 1399/1447] SilverSearcher: Do some cleanup Remove unneeded includes. Code style corrections. Make global functions in cpp static. Fix const correctness. Fix nameFiltersAsRegExp variable name. Remove unneeded d'tor. Change-Id: Ia8aef3701bc8853905a3661242b33351ce319004 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: Orgad Shaneh --- .../findinfilessilversearcher.cpp | 64 +++++++------------ .../findinfilessilversearcher.h | 6 +- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index 52e9f08a956..a9105e4f4ba 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -3,12 +3,8 @@ #include "findinfilessilversearcher.h" -#include #include -#include #include -#include -#include #include #include @@ -25,11 +21,8 @@ using namespace TextEditor; using namespace Utils; namespace { -const QLatin1String silverSearcherName("Silver Searcher"); - -const QString metacharacters = "+()^$.{}[]|\\"; - -const QString SearchOptionsString = "SearchOptionsString"; +const QLatin1String s_metaCharacters = QLatin1String("+()^$.{}[]|\\"); +const QLatin1String s_searchOptionsString = QLatin1String("SearchOptionsString"); class SilverSearcherSearchOptions { @@ -37,43 +30,37 @@ public: QString searchOptions; }; -QString convertWildcardToRegex(const QString &wildcard) +static QString convertWildcardToRegex(const QString &wildcard) { QString regex; const int wildcardSize = wildcard.size(); regex.append('^'); for (int i = 0; i < wildcardSize; ++i) { const QChar ch = wildcard[i]; - if (ch == '*') { + if (ch == '*') regex.append(".*"); - } else if (ch == '?') { + else if (ch == '?') regex.append('.'); - } else if (metacharacters.indexOf(ch) != -1) { - regex.append('\\'); + else if (s_metaCharacters.indexOf(ch) != -1) + regex.append('\\' + ch); + else regex.append(ch); - } else { - regex.append(ch); - } } regex.append('$'); - return regex; } -bool isSilverSearcherAvailable() +static bool isSilverSearcherAvailable() { Process silverSearcherProcess; silverSearcherProcess.setCommand({"ag", {"--version"}}); silverSearcherProcess.start(); - if (silverSearcherProcess.waitForFinished(1000)) { - if (silverSearcherProcess.cleanedStdOut().contains("ag version")) - return true; - } - - return false; + return silverSearcherProcess.waitForFinished(1000) + && silverSearcherProcess.cleanedStdOut().contains("ag version"); } -void runSilverSeacher(QPromise &promise, FileFindParameters parameters) +static void runSilverSeacher(QPromise &promise, + const FileFindParameters ¶meters) { const FilePath directory = FilePath::fromUserInput(parameters.additionalParameters.toString()); QStringList arguments = {"--parallel", "--ackmate"}; @@ -92,15 +79,15 @@ void runSilverSeacher(QPromise &promise, FileFindParameters p for (const QString &filter : std::as_const(parameters.exclusionFilters)) arguments << "--ignore" << filter; - QString nameFiltersAsRegex; + QString nameFiltersAsRegExp; for (const QString &filter : std::as_const(parameters.nameFilters)) - nameFiltersAsRegex += QString("(%1)|").arg(convertWildcardToRegex(filter)); - nameFiltersAsRegex.remove(nameFiltersAsRegex.length() - 1, 1); + nameFiltersAsRegExp += QString("(%1)|").arg(convertWildcardToRegex(filter)); + nameFiltersAsRegExp.remove(nameFiltersAsRegExp.length() - 1, 1); - arguments << "-G" << nameFiltersAsRegex; + arguments << "-G" << nameFiltersAsRegExp; - SilverSearcherSearchOptions params = parameters.searchEngineParameters - .value(); + const SilverSearcherSearchOptions params = parameters.searchEngineParameters + .value(); if (!params.searchOptions.isEmpty()) arguments << params.searchOptions.split(' '); @@ -150,6 +137,7 @@ FindInFilesSilverSearcher::FindInFilesSilverSearcher(QObject *parent) QTC_ASSERT(findInFiles, return); findInFiles->addSearchEngine(this); + // TODO: Make disabled by default and run isSilverSearcherAvailable asynchronously setEnabled(isSilverSearcherAvailable()); if (!isEnabled()) { QLabel *label = new QLabel(Tr::tr("Silver Searcher is not available on the system.")); @@ -158,10 +146,6 @@ FindInFilesSilverSearcher::FindInFilesSilverSearcher(QObject *parent) } } -FindInFilesSilverSearcher::~FindInFilesSilverSearcher() -{ -} - QVariant FindInFilesSilverSearcher::parameters() const { SilverSearcherSearchOptions silverSearcherSearchOptions; @@ -171,12 +155,12 @@ QVariant FindInFilesSilverSearcher::parameters() const QString FindInFilesSilverSearcher::title() const { - return silverSearcherName; + return "Silver Searcher"; } QString FindInFilesSilverSearcher::toolTip() const { - return QString(); + return {}; } QWidget *FindInFilesSilverSearcher::widget() const @@ -186,7 +170,7 @@ QWidget *FindInFilesSilverSearcher::widget() const void FindInFilesSilverSearcher::writeSettings(QSettings *settings) const { - settings->setValue(SearchOptionsString, m_searchOptionsLineEdit->text()); + settings->setValue(s_searchOptionsString, m_searchOptionsLineEdit->text()); } QFuture FindInFilesSilverSearcher::executeSearch( @@ -203,7 +187,7 @@ IEditor *FindInFilesSilverSearcher::openEditor(const SearchResultItem & /*item*/ void FindInFilesSilverSearcher::readSettings(QSettings *settings) { - m_searchOptionsLineEdit->setText(settings->value(SearchOptionsString).toString()); + m_searchOptionsLineEdit->setText(settings->value(s_searchOptionsString).toString()); } } // namespace SilverSearcher diff --git a/src/plugins/silversearcher/findinfilessilversearcher.h b/src/plugins/silversearcher/findinfilessilversearcher.h index 85b35192b8e..bc5e224c21f 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.h +++ b/src/plugins/silversearcher/findinfilessilversearcher.h @@ -3,10 +3,9 @@ #pragma once -#include #include -#include +#include #include @@ -14,6 +13,8 @@ QT_BEGIN_NAMESPACE class QLineEdit; QT_END_NAMESPACE +namespace Core { class IFindSupport; } + namespace SilverSearcher { class FindInFilesSilverSearcher : public TextEditor::SearchEngine @@ -22,7 +23,6 @@ class FindInFilesSilverSearcher : public TextEditor::SearchEngine public: explicit FindInFilesSilverSearcher(QObject *parent); - ~FindInFilesSilverSearcher() override; // TextEditor::FileFindExtension QString title() const override; From 5e8795b35382e0c95634c75f411bd9e1e0db8cd4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 01:09:26 +0200 Subject: [PATCH 1400/1447] SilverSearcher: Rename output into input The passed text is an output from the ag command, but, as seen from the parser point of view, that's the input data for the parser. Change-Id: Ic5d42406fd5ff1f52969fde3c2d44aaa34b9133b Reviewed-by: Orgad Shaneh --- .../silversearcher/outputparser_test.cpp | 6 +-- .../silversearcheroutputparser.cpp | 38 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/plugins/silversearcher/outputparser_test.cpp b/src/plugins/silversearcher/outputparser_test.cpp index e517e7e851d..74a82323363 100644 --- a/src/plugins/silversearcher/outputparser_test.cpp +++ b/src/plugins/silversearcher/outputparser_test.cpp @@ -24,7 +24,7 @@ SearchResultItem searchResult(const FilePath &fileName, const QString &matchingL void OutputParserTest::test_data() { - QTest::addColumn("parserOutput"); + QTest::addColumn("input"); QTest::addColumn("results"); QTest::addRow("nothing") << QString("\n") << SearchResultItems(); @@ -59,9 +59,9 @@ void OutputParserTest::test_data() void OutputParserTest::test() { - QFETCH(QString, parserOutput); + QFETCH(QString, input); QFETCH(SearchResultItems, results); - const SearchResultItems items = SilverSearcher::parse(parserOutput); + const SearchResultItems items = SilverSearcher::parse(input); QCOMPARE(items, results); } diff --git a/src/plugins/silversearcher/silversearcheroutputparser.cpp b/src/plugins/silversearcher/silversearcheroutputparser.cpp index 1cd1538830e..811a4e1bfd5 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.cpp +++ b/src/plugins/silversearcher/silversearcheroutputparser.cpp @@ -19,16 +19,16 @@ namespace SilverSearcher { 10;8 2,35 2:PropertyAbstractContainer::PropertyAbstractContainer() */ -static QStringView nextLine(QStringView *remainingOutput) +static QStringView nextLine(QStringView *remainingInput) { - const int newLinePos = remainingOutput->indexOf('\n'); + const int newLinePos = remainingInput->indexOf('\n'); if (newLinePos < 0) { - QStringView ret = *remainingOutput; - *remainingOutput = QStringView(); + QStringView ret = *remainingInput; + *remainingInput = QStringView(); return ret; } - QStringView ret = remainingOutput->left(newLinePos); - *remainingOutput = remainingOutput->mid(newLinePos + 1); + QStringView ret = remainingInput->left(newLinePos); + *remainingInput = remainingInput->mid(newLinePos + 1); return ret; } @@ -45,16 +45,16 @@ static bool parseNumber(QStringView numberString, int *number) return ok; } -static bool parseLineNumber(QStringView *remainingOutput, int *lineNumber) +static bool parseLineNumber(QStringView *remainingInput, int *lineNumber) { - const int lineNumberDelimiterPos = remainingOutput->indexOf(';'); + const int lineNumberDelimiterPos = remainingInput->indexOf(';'); if (lineNumberDelimiterPos < 0) return false; - if (!parseNumber(remainingOutput->left(lineNumberDelimiterPos), lineNumber)) + if (!parseNumber(remainingInput->left(lineNumberDelimiterPos), lineNumber)) return false; - *remainingOutput = remainingOutput->mid(lineNumberDelimiterPos + 1); + *remainingInput = remainingInput->mid(lineNumberDelimiterPos + 1); return true; } @@ -76,13 +76,13 @@ static bool parseLineHit(QStringView hitString, QPair *hit) return true; } -static bool parseLineHits(QStringView *remainingOutput, QList> *hits) +static bool parseLineHits(QStringView *remainingInput, QList> *hits) { - const int hitsDelimiterPos = remainingOutput->indexOf(':'); + const int hitsDelimiterPos = remainingInput->indexOf(':'); if (hitsDelimiterPos < 0) return false; - const QStringView hitsString = remainingOutput->left(hitsDelimiterPos); + const QStringView hitsString = remainingInput->left(hitsDelimiterPos); const QList hitStrings = hitsString.split(',', Qt::SkipEmptyParts); for (const auto hitString : hitStrings) { QPair hit; @@ -90,20 +90,20 @@ static bool parseLineHits(QStringView *remainingOutput, QList> * return false; hits->append(hit); } - *remainingOutput = remainingOutput->mid(hitsDelimiterPos + 1); + *remainingInput = remainingInput->mid(hitsDelimiterPos + 1); return true; } -SearchResultItems parse(const QString &output, const std::optional ®Exp) +SearchResultItems parse(const QString &input, const std::optional ®Exp) { SearchResultItems items; - QStringView remainingOutput(output); + QStringView remainingInput(input); while (true) { - if (remainingOutput.isEmpty()) + if (remainingInput.isEmpty()) break; - const QStringView filePathLine = nextLine(&remainingOutput); + const QStringView filePathLine = nextLine(&remainingInput); if (filePathLine.isEmpty()) continue; @@ -113,7 +113,7 @@ SearchResultItems parse(const QString &output, const std::optional Date: Thu, 1 Jun 2023 01:26:40 +0200 Subject: [PATCH 1401/1447] SilverSearcher: Rename some files Make naming more consistent. Change-Id: Ic6ca72e5d048e5e452df6ead2b7da8f3c1cd0282 Reviewed-by: Reviewed-by: Orgad Shaneh --- src/plugins/silversearcher/CMakeLists.txt | 4 ++-- src/plugins/silversearcher/findinfilessilversearcher.cpp | 5 ++--- src/plugins/silversearcher/silversearcher.qbs | 6 +++--- ...versearcheroutputparser.cpp => silversearcherparser.cpp} | 2 +- ...{silversearcheroutputparser.h => silversearcherparser.h} | 0 ...{outputparser_test.cpp => silversearcherparser_test.cpp} | 4 ++-- .../{outputparser_test.h => silversearcherparser_test.h} | 0 src/plugins/silversearcher/silversearcherplugin.cpp | 4 ++-- 8 files changed, 12 insertions(+), 13 deletions(-) rename src/plugins/silversearcher/{silversearcheroutputparser.cpp => silversearcherparser.cpp} (99%) rename src/plugins/silversearcher/{silversearcheroutputparser.h => silversearcherparser.h} (100%) rename src/plugins/silversearcher/{outputparser_test.cpp => silversearcherparser_test.cpp} (97%) rename src/plugins/silversearcher/{outputparser_test.h => silversearcherparser_test.h} (100%) diff --git a/src/plugins/silversearcher/CMakeLists.txt b/src/plugins/silversearcher/CMakeLists.txt index 7cc12ebb294..2af582d4a3e 100644 --- a/src/plugins/silversearcher/CMakeLists.txt +++ b/src/plugins/silversearcher/CMakeLists.txt @@ -2,12 +2,12 @@ add_qtc_plugin(SilverSearcher PLUGIN_DEPENDS Core TextEditor SOURCES findinfilessilversearcher.cpp findinfilessilversearcher.h - silversearcheroutputparser.cpp silversearcheroutputparser.h + silversearcherparser.cpp silversearcherparser.h silversearcherplugin.cpp silversearcherplugin.h silversearchertr.h ) extend_qtc_plugin(SilverSearcher CONDITION WITH_TESTS SOURCES - outputparser_test.cpp outputparser_test.h + silversearcherparser_test.cpp silversearcherparser_test.h ) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index a9105e4f4ba..43397a03f6d 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -2,15 +2,14 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "findinfilessilversearcher.h" +#include "silversearcherparser.h" +#include "silversearchertr.h" #include #include #include #include -#include "silversearcheroutputparser.h" -#include "silversearchertr.h" - #include #include #include diff --git a/src/plugins/silversearcher/silversearcher.qbs b/src/plugins/silversearcher/silversearcher.qbs index 8cf2cd15090..08a25367aad 100644 --- a/src/plugins/silversearcher/silversearcher.qbs +++ b/src/plugins/silversearcher/silversearcher.qbs @@ -9,14 +9,14 @@ QtcPlugin { files: [ "findinfilessilversearcher.cpp", "findinfilessilversearcher.h", - "silversearcheroutputparser.cpp", "silversearcheroutputparser.h", + "silversearcherparser.cpp", "silversearcherparser.h", "silversearcherplugin.cpp", "silversearcherplugin.h", ] QtcTestFiles { files: [ - "outputparser_test.cpp", - "outputparser_test.h", + "silversearcherparser_test.cpp", + "silversearcherparser_test.h", ] } } diff --git a/src/plugins/silversearcher/silversearcheroutputparser.cpp b/src/plugins/silversearcher/silversearcherparser.cpp similarity index 99% rename from src/plugins/silversearcher/silversearcheroutputparser.cpp rename to src/plugins/silversearcher/silversearcherparser.cpp index 811a4e1bfd5..be4e9096c4c 100644 --- a/src/plugins/silversearcher/silversearcheroutputparser.cpp +++ b/src/plugins/silversearcher/silversearcherparser.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2017 Przemyslaw Gorszkowski . // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "silversearcheroutputparser.h" +#include "silversearcherparser.h" using namespace Utils; diff --git a/src/plugins/silversearcher/silversearcheroutputparser.h b/src/plugins/silversearcher/silversearcherparser.h similarity index 100% rename from src/plugins/silversearcher/silversearcheroutputparser.h rename to src/plugins/silversearcher/silversearcherparser.h diff --git a/src/plugins/silversearcher/outputparser_test.cpp b/src/plugins/silversearcher/silversearcherparser_test.cpp similarity index 97% rename from src/plugins/silversearcher/outputparser_test.cpp rename to src/plugins/silversearcher/silversearcherparser_test.cpp index 74a82323363..b23002e191e 100644 --- a/src/plugins/silversearcher/outputparser_test.cpp +++ b/src/plugins/silversearcher/silversearcherparser_test.cpp @@ -1,8 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "outputparser_test.h" -#include "silversearcheroutputparser.h" +#include "silversearcherparser.h" +#include "silversearcherparser_test.h" #include diff --git a/src/plugins/silversearcher/outputparser_test.h b/src/plugins/silversearcher/silversearcherparser_test.h similarity index 100% rename from src/plugins/silversearcher/outputparser_test.h rename to src/plugins/silversearcher/silversearcherparser_test.h diff --git a/src/plugins/silversearcher/silversearcherplugin.cpp b/src/plugins/silversearcher/silversearcherplugin.cpp index e16ed4a3498..1f143407d78 100644 --- a/src/plugins/silversearcher/silversearcherplugin.cpp +++ b/src/plugins/silversearcher/silversearcherplugin.cpp @@ -1,9 +1,9 @@ // Copyright (C) 2017 Przemyslaw Gorszkowski . // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include "silversearcherplugin.h" #include "findinfilessilversearcher.h" -#include "outputparser_test.h" +#include "silversearcherparser_test.h" +#include "silversearcherplugin.h" namespace SilverSearcher::Internal { From b9e5f4b5c04261fa9fb4ecbd3981d4e0342f0b95 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 12 May 2023 08:44:30 +0200 Subject: [PATCH 1402/1447] Add change log for 11.0.0 Change-Id: I986a5771c2be5f4875d44b7cdb9f58c1e5fd0b17 Reviewed-by: Leena Miettinen --- dist/changelog/changes-11.0.0.md | 223 +++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 dist/changelog/changes-11.0.0.md diff --git a/dist/changelog/changes-11.0.0.md b/dist/changelog/changes-11.0.0.md new file mode 100644 index 00000000000..5600390c091 --- /dev/null +++ b/dist/changelog/changes-11.0.0.md @@ -0,0 +1,223 @@ +Qt Creator 11 +============= + +Qt Creator version 11 contains bug fixes and new features. + +The most important changes are listed in this document. For a complete list of +changes, see the Git log for the Qt Creator sources that you can check out from +the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline origin/10.0..v11.0.0 + +General +------- + +* Added a `Terminal` view (QTCREATORBUG-8511) + * Opt-out via `Preferences` > `Terminal` preferences + * Added support for + * different shells, colors, fonts, and multiple tabs + * opening file paths in Qt Creator with `Ctrl+click` (`Cmd+click` on + macOS) +* Added a more spacious "relaxed" toolbar style `Environment > Interface` +* Added a pin button to progress details instead of automatically resetting + their position (QTCREATORBUG-28829) +* Improved the selection and navigation in the `Issues` view + (QTCREATORBUG-26128, QTCREATORBUG-27006, QTCREATORBUG-27506) +* Locator + * Improved performance + * Added the creation of directories to the `Files in File System` filter + * Added device roots and browsing remote file systems to the + `Files in File System` filter + +Editing +------- + +* Improved the performance of the multi-cursor support +* Fixed the saving of hardlinked files (QTCREATORBUG-19651) +* Fixed an issue of copy and paste with multiple cursors (QTCREATORBUG-29117) + +### C++ + +* Improved the style of forward declarations in the outline (QTCREATORBUG-312) +* Added highlighting for typed string literals and user-defined literals + (QTCREATORBUG-28869) +* Added the option to create class members from assignments (QTCREATORBUG-1918) +* Fixed that locator showed both the declaration and the definition of symbols + (QTCREATORBUG-13894) +* Fixed the handling of C++20 keywords and concepts +* Built-in + * Fixed support for `if`-statements with initializer (QTCREATORBUG-29182) + +### Language Server Protocol + +* Added experimental support for GitHub Copilot + ([GitHub documentation](https://github.com/features/copilot)) +* Added missing actions for opening the `Call Hierarchy` (QTCREATORBUG-28839, + QTCREATORBUG-28842) + +### QML + +* Fixed the reformatting in the presence of JavaScript directives and function + return type annotations (QTCREATORBUG-29001, QTCREATORBUG-29046) +* Fixed that reformatting changed `of` to `in` (QTCREATORBUG-29123) +* Fixed the completion for Qt Quick Controls (QTCREATORBUG-28648) + +### Python + +* Added the option to create a virtual environment (`venv`) to the Python + interpreter selector and the wizard (PYSIDE-2152) + +### Markdown + +* Added a Markdown editor with preview (QTCREATORBUG-27883) +* Added a wizard for Markdown files (QTCREATORBUG-29056) + +Projects +-------- + +* Made it possible to add devices without going through the wizard +* Added support for moving files to a different directory when renaming + (QTCREATORBUG-15981) + +### CMake + +* Implemented adding files to the project (QTCREATORBUG-25922, + QTCREATORBUG-26006, QTCREATORBUG-27213, QTCREATORBUG-27538, + QTCREATORBUG-28493, QTCREATORBUG-28904, QTCREATORBUG-28985, + QTCREATORBUG-29006) +* Fixed issues with detecting a configured Qt version when importing a build + (QTCREATORBUG-29075) + +### Python + +* Added an option for the interpreter to the wizards + +### vcpkg + +* Added experimental support for `vcpkg` + ([vcpgk documentation](https://vcpkg.io/en/)) +* Added an option for the `vcpkg` installation location +* Added a search dialog for packages +* Added a wizard and an editor for `vcpkg.json` files + +Debugging +--------- + +* Improved the UI for enabling and disabling debuggers (QTCREATORBUG-28627) + +### C++ + +* Added an option for the default number of array elements to show + (`Preferences > Debugger > Locals & Expressions > Default array size`) +* CDB + * Added automatic source file mapping for Qt packages + * Fixed the variables view on remote Windows devices (QTCREATORBUG-29000) +* LLDB + * Fixed that long lines in the application output were broken into multiple + lines (QTCREATORBUG-29098) + +### Qt Quick + +* Improved the auto-detection if QML debugging is required (QTCREATORBUG-28627) +* Added an option for disabling static analyzer messages to + `Qt Quick > QML/JS Editing` (QTCREATORBUG-29095) + +Analyzer +-------- + +### Clang + +* Fixed that a `.clang-tidy` file in the project directory was not used by + default (QTCREATORBUG-28852) + +### Axivion + +* Added experimental support + +Version Control Systems +----------------------- + +### Git + +* Instant Blame + * Improved the performance (QTCREATORBUG-29151) + * Fixed that it did not show at the end of the document + +Platforms +--------- + +### Android + +* Fixed an issue with building library targets (QTCREATORBUG-26980) + +### Remote Linux + +* Removed the automatic sourcing of target-side shell profiles + +### Docker + +* Added support for `qmake` based projects (QTCREATORBUG-29140) +* Fixed issues after deleting the Docker image for a registered Docker device + (QTCREATORBUG-28880) + +### QNX + +* Added `slog2info` as a requirement for devices +* Fixed the support for remote working directories (QTCREATORBUG-28900) + +Credits for these changes go to: +-------------------------------- +Aleksei German +Alessandro Portale +Alexander Drozdov +Alexander Pershin +Ali Kianian +Alibek Omarov +Amr Essam +Andre Hartmann +André Pönitz +Artem Mukhin +Artem Sokolovskii +Assam Boudjelthia +Björn Schäpers +Brook Cronin +Burak Hancerli +Christian Kandeler +Christian Stenger +Cristian Adam +David Schulz +Eike Ziller +Esa Törmänen +Fabian Kosmale +Filippo Gentile +Friedemann Kleint +Henning Gruendl +Jaroslaw Kobus +Jussi Witick +Kai Köhne +Knud Dollereder +Knut Petter Svendsen +Leena Miettinen +Mahmoud Badri +Marco Bubke +Marcus Tillmanns +Martin Delille +Mats Honkamaa +Miikka Heikkinen +Mitch Curtis +Niels Weber +Orgad Shaneh +Pranta Dastider +Robert Löhning +Samuel Ghinet +Semih Yavuz +Tasuku Suzuki +Thiago Macieira +Thomas Hartmann +Tim Jenssen +Tim Jenßen +Ulf Hermann +Vikas Pachdha +Yasser Grimes +Yixue Wang From 5e9eadfc5816cc30ac221e533e416cc7ebc713af Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 28 May 2023 22:07:17 +0200 Subject: [PATCH 1403/1447] TaskTree: Introduce finishAllAndError workflow policy It's going to be used in timeout task. Change-Id: I2abd65b461cab445ada7a0ad5e1bbe07d1b6323b Reviewed-by: Qt CI Bot Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/libs/solutions/tasking/tasktree.cpp | 8 +- src/libs/solutions/tasking/tasktree.h | 6 +- tests/auto/solutions/tasking/tst_tasking.cpp | 154 ++++++++++++------- 3 files changed, 110 insertions(+), 58 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 62243f373a1..6f2bb7ad4f5 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -404,12 +404,14 @@ TaskItem workflowPolicy(WorkflowPolicy policy) const TaskItem sequential = parallelLimit(1); const TaskItem parallel = parallelLimit(0); + const TaskItem stopOnError = workflowPolicy(WorkflowPolicy::StopOnError); const TaskItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError); const TaskItem stopOnDone = workflowPolicy(WorkflowPolicy::StopOnDone); const TaskItem continueOnDone = workflowPolicy(WorkflowPolicy::ContinueOnDone); const TaskItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished); const TaskItem finishAllAndDone = workflowPolicy(WorkflowPolicy::FinishAllAndDone); +const TaskItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError); static TaskAction toTaskAction(bool success) { @@ -859,7 +861,8 @@ TaskContainer::RuntimeData::RuntimeData(const ConstData &constData) , m_storageIdList(createStorages(constData)) { m_successBit = m_constData.m_workflowPolicy != WorkflowPolicy::StopOnDone - && m_constData.m_workflowPolicy != WorkflowPolicy::ContinueOnDone; + && m_constData.m_workflowPolicy != WorkflowPolicy::ContinueOnDone + && m_constData.m_workflowPolicy != WorkflowPolicy::FinishAllAndError; } TaskContainer::RuntimeData::~RuntimeData() @@ -873,7 +876,8 @@ TaskContainer::RuntimeData::~RuntimeData() bool TaskContainer::RuntimeData::updateSuccessBit(bool success) { - if (m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndDone) + if (m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndDone + || m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndError) return m_successBit; if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) { m_successBit = success; diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 37403628a5a..c10cf495c31 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -102,6 +102,7 @@ private: // 3. Stops on first finished child. In sequential mode it will never run other children then the first one. // Useful only in parallel mode. // 4. Always run all children, let them finish, ignore their results and report done afterwards. +// 5. Always run all children, let them finish, ignore their results and report error afterwards. enum class WorkflowPolicy { StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done). @@ -109,7 +110,8 @@ enum class WorkflowPolicy { StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error). ContinueOnDone, // 2b - The same, but children execution continues. Reports error when no children. StopOnFinished, // 3 - Stops on first finished child and report its result. - FinishAllAndDone // 4 - Reports done after all children finished. + FinishAllAndDone, // 4 - Reports done after all children finished. + FinishAllAndError // 5 - Reports error after all children finished. }; Q_ENUM_NS(WorkflowPolicy); @@ -247,12 +249,14 @@ TASKING_EXPORT TaskItem workflowPolicy(WorkflowPolicy policy); TASKING_EXPORT extern const TaskItem sequential; TASKING_EXPORT extern const TaskItem parallel; + TASKING_EXPORT extern const TaskItem stopOnError; TASKING_EXPORT extern const TaskItem continueOnError; TASKING_EXPORT extern const TaskItem stopOnDone; TASKING_EXPORT extern const TaskItem continueOnDone; TASKING_EXPORT extern const TaskItem stopOnFinished; TASKING_EXPORT extern const TaskItem finishAllAndDone; +TASKING_EXPORT extern const TaskItem finishAllAndError; class TASKING_EXPORT Storage : public TaskItem { diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 051b807842b..ff760169d85 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -637,25 +637,36 @@ void tst_Tasking::testTree_data() }; }; - const Log log = {{0, Handler::GroupDone}}; + const Log doneLog = {{0, Handler::GroupDone}}; + const Log errorLog = {{0, Handler::GroupError}}; const Group root1 = createRoot(WorkflowPolicy::StopOnError); - QTest::newRow("EmptyStopOnError") << TestData{storage, root1, log, 0, OnDone::Success}; + QTest::newRow("EmptyStopOnError") << TestData{storage, root1, doneLog, 0, + OnDone::Success}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); - QTest::newRow("EmptyContinueOnError") << TestData{storage, root2, log, 0, OnDone::Success}; + QTest::newRow("EmptyContinueOnError") << TestData{storage, root2, doneLog, 0, + OnDone::Success}; const Group root3 = createRoot(WorkflowPolicy::StopOnDone); - QTest::newRow("EmptyStopOnDone") << TestData{storage, root3, log, 0, OnDone::Success}; + QTest::newRow("EmptyStopOnDone") << TestData{storage, root3, doneLog, 0, + OnDone::Success}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); - QTest::newRow("EmptyContinueOnDone") << TestData{storage, root4, log, 0, OnDone::Success}; + QTest::newRow("EmptyContinueOnDone") << TestData{storage, root4, doneLog, 0, + OnDone::Success}; const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); - QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, log, 0, OnDone::Success}; + QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, doneLog, 0, + OnDone::Success}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("EmptyOptional") << TestData{storage, root6, log, 0, OnDone::Success}; + QTest::newRow("EmptyFinishAllAndDone") << TestData{storage, root6, doneLog, 0, + OnDone::Success}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("EmptyFinishAllAndError") << TestData{storage, root7, errorLog, 0, + OnDone::Failure}; } { @@ -670,29 +681,45 @@ void tst_Tasking::testTree_data() }; }; - const Log log = { + const Log doneLog = { {1, Handler::Setup}, {1, Handler::Done}, {0, Handler::GroupDone} }; + const Log errorLog = { + {1, Handler::Setup}, + {1, Handler::Done}, + {0, Handler::GroupError} + }; + const Group root1 = createRoot(WorkflowPolicy::StopOnError); - QTest::newRow("DoneStopOnError") << TestData{storage, root1, log, 1, OnDone::Success}; + QTest::newRow("DoneStopOnError") << TestData{storage, root1, doneLog, 1, + OnDone::Success}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); - QTest::newRow("DoneContinueOnError") << TestData{storage, root2, log, 1, OnDone::Success}; + QTest::newRow("DoneContinueOnError") << TestData{storage, root2, doneLog, 1, + OnDone::Success}; const Group root3 = createRoot(WorkflowPolicy::StopOnDone); - QTest::newRow("DoneStopOnDone") << TestData{storage, root3, log, 1, OnDone::Success}; + QTest::newRow("DoneStopOnDone") << TestData{storage, root3, doneLog, 1, + OnDone::Success}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); - QTest::newRow("DoneContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Success}; + QTest::newRow("DoneContinueOnDone") << TestData{storage, root4, doneLog, 1, + OnDone::Success}; const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); - QTest::newRow("DoneStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Success}; + QTest::newRow("DoneStopOnFinished") << TestData{storage, root5, doneLog, 1, + OnDone::Success}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("DoneOptional") << TestData{storage, root6, log, 1, OnDone::Success}; + QTest::newRow("DoneFinishAllAndDone") << TestData{storage, root6, doneLog, 1, + OnDone::Success}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("DoneFinishAllAndError") << TestData{storage, root7, errorLog, 1, + OnDone::Failure}; } { @@ -707,35 +734,45 @@ void tst_Tasking::testTree_data() }; }; - const Log log = { - {1, Handler::Setup}, - {1, Handler::Error}, - {0, Handler::GroupError} - }; - - const Log optionalLog = { + const Log doneLog = { {1, Handler::Setup}, {1, Handler::Error}, {0, Handler::GroupDone} }; + const Log errorLog = { + {1, Handler::Setup}, + {1, Handler::Error}, + {0, Handler::GroupError} + }; + const Group root1 = createRoot(WorkflowPolicy::StopOnError); - QTest::newRow("ErrorStopOnError") << TestData{storage, root1, log, 1, OnDone::Failure}; + QTest::newRow("ErrorStopOnError") << TestData{storage, root1, errorLog, 1, + OnDone::Failure}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); - QTest::newRow("ErrorContinueOnError") << TestData{storage, root2, log, 1, OnDone::Failure}; + QTest::newRow("ErrorContinueOnError") << TestData{storage, root2, errorLog, 1, + OnDone::Failure}; const Group root3 = createRoot(WorkflowPolicy::StopOnDone); - QTest::newRow("ErrorStopOnDone") << TestData{storage, root3, log, 1, OnDone::Failure}; + QTest::newRow("ErrorStopOnDone") << TestData{storage, root3, errorLog, 1, + OnDone::Failure}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); - QTest::newRow("ErrorContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Failure}; + QTest::newRow("ErrorContinueOnDone") << TestData{storage, root4, errorLog, 1, + OnDone::Failure}; const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); - QTest::newRow("ErrorStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Failure}; + QTest::newRow("ErrorStopOnFinished") << TestData{storage, root5, errorLog, 1, + OnDone::Failure}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("ErrorOptional") << TestData{storage, root6, optionalLog, 1, OnDone::Success}; + QTest::newRow("ErrorFinishAllAndDone") << TestData{storage, root6, doneLog, 1, + OnDone::Success}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("ErrorFinishAllAndError") << TestData{storage, root7, errorLog, 1, + OnDone::Failure}; } { @@ -800,8 +837,12 @@ void tst_Tasking::testTree_data() << TestData{storage, root5, errorErrorLog, 2, OnDone::Failure}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("StopRootWithOptional") + QTest::newRow("StopRootWithFinishAllAndDone") << TestData{storage, root6, doneLog, 2, OnDone::Success}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("StopRootWithFinishAllAndError") + << TestData{storage, root7, errorDoneLog, 2, OnDone::Failure}; } { @@ -884,8 +925,12 @@ void tst_Tasking::testTree_data() << TestData{storage, root5, doneErrorLog, 3, OnDone::Success}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("StopRootAfterDoneWithOptional") + QTest::newRow("StopRootAfterDoneWithFinishAllAndDone") << TestData{storage, root6, doneDoneLog, 3, OnDone::Success}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("StopRootAfterDoneWithFinishAllAndError") + << TestData{storage, root7, errorDoneLog, 3, OnDone::Failure}; } { @@ -948,8 +993,12 @@ void tst_Tasking::testTree_data() << TestData{storage, root5, errorLog, 2, OnDone::Failure}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("StopGroupWithOptional") + QTest::newRow("StopGroupWithFinishAllAndDone") << TestData{storage, root6, doneLog, 2, OnDone::Failure}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("StopGroupWithFinishAllAndError") + << TestData{storage, root7, errorLog, 2, OnDone::Failure}; } { @@ -1026,8 +1075,12 @@ void tst_Tasking::testTree_data() << TestData{storage, root5, shortDoneLog, 3, OnDone::Failure}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("StopGroupAfterDoneWithOptional") + QTest::newRow("StopGroupAfterDoneWithFinishAllAndDone") << TestData{storage, root6, longDoneLog, 3, OnDone::Failure}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("StopGroupAfterDoneWithFinishAllAndError") + << TestData{storage, root7, errorLog, 3, OnDone::Failure}; } { @@ -1104,8 +1157,12 @@ void tst_Tasking::testTree_data() << TestData{storage, root5, shortErrorLog, 3, OnDone::Failure}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); - QTest::newRow("StopGroupAfterErrorWithOptional") + QTest::newRow("StopGroupAfterErrorWithFinishAllAndDone") << TestData{storage, root6, doneLog, 3, OnDone::Failure}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("StopGroupAfterErrorWithFinishAllAndError") + << TestData{storage, root7, longErrorLog, 3, OnDone::Failure}; } { @@ -1133,7 +1190,7 @@ void tst_Tasking::testTree_data() QTest::newRow("StopOnError") << TestData{storage, root1, log1, 3, OnDone::Failure}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); - const Log log2 { + const Log errorLog { {1, Handler::Setup}, {1, Handler::Done}, {2, Handler::Setup}, @@ -1142,7 +1199,7 @@ void tst_Tasking::testTree_data() {3, Handler::Done}, {0, Handler::GroupError} }; - QTest::newRow("ContinueOnError") << TestData{storage, root2, log2, 3, OnDone::Failure}; + QTest::newRow("ContinueOnError") << TestData{storage, root2, errorLog, 3, OnDone::Failure}; const Group root3 = createRoot(WorkflowPolicy::StopOnDone); const Log log3 { @@ -1153,7 +1210,7 @@ void tst_Tasking::testTree_data() QTest::newRow("StopOnDone") << TestData{storage, root3, log3, 3, OnDone::Success}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); - const Log log4 { + const Log doneLog { {1, Handler::Setup}, {1, Handler::Done}, {2, Handler::Setup}, @@ -1162,7 +1219,7 @@ void tst_Tasking::testTree_data() {3, Handler::Done}, {0, Handler::GroupDone} }; - QTest::newRow("ContinueOnDone") << TestData{storage, root4, log4, 3, OnDone::Success}; + QTest::newRow("ContinueOnDone") << TestData{storage, root4, doneLog, 3, OnDone::Success}; const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); const Log log5 { @@ -1171,6 +1228,12 @@ void tst_Tasking::testTree_data() {0, Handler::GroupDone} }; QTest::newRow("StopOnFinished") << TestData{storage, root5, log5, 3, OnDone::Success}; + + const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); + QTest::newRow("FinishAllAndDone") << TestData{storage, root6, doneLog, 3, OnDone::Success}; + + const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); + QTest::newRow("FinishAllAndError") << TestData{storage, root7, errorLog, 3, OnDone::Failure}; } { @@ -1213,25 +1276,6 @@ void tst_Tasking::testTree_data() QTest::newRow("StopOnFinished4") << TestData{storage, root4, failure, 2, OnDone::Failure}; } - { - const Group root { - Storage(storage), - finishAllAndDone, - createFailingTask(1), - createFailingTask(2), - groupDone(0), - groupError(0) - }; - const Log log { - {1, Handler::Setup}, - {1, Handler::Error}, - {2, Handler::Setup}, - {2, Handler::Error}, - {0, Handler::GroupDone} - }; - QTest::newRow("Optional") << TestData{storage, root, log, 2, OnDone::Success}; - } - { const auto createRoot = [storage, createSuccessTask, groupDone, groupError]( TaskAction taskAction) { From f6e7dbd4166401fa40c5bcab83893d375b42e6a9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 28 May 2023 22:47:59 +0200 Subject: [PATCH 1404/1447] TaskTree: Introduce Timeout task By default, when finished, it returns success. In order to convert it into failing task, enclose it inside a Group with finishAllAndError. Reuse it in tasking tests. Task-number: QTCREATORBUG-28741 Change-Id: Ic81203203e0b139d4f9bfd553279ecb01cd303f4 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.cpp | 10 ++++ src/libs/solutions/tasking/tasktree.h | 8 +++ tests/auto/solutions/tasking/tst_tasking.cpp | 63 +++++++++----------- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 6f2bb7ad4f5..7fc5c665918 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1848,4 +1848,14 @@ void TaskTreeTaskAdapter::start() task()->start(); } +TimeoutTaskAdapter::TimeoutTaskAdapter() +{ + *task() = std::chrono::milliseconds::zero(); +} + +void TimeoutTaskAdapter::start() +{ + QTimer::singleShot(*task(), this, [this] { emit done(true); }); +} + } // namespace Tasking diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index c10cf495c31..78593aa1823 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -426,6 +426,13 @@ public: void start() final; }; +class TASKING_EXPORT TimeoutTaskAdapter : public TaskAdapter +{ +public: + TimeoutTaskAdapter(); + void start() final; +}; + } // namespace Tasking #define TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass)\ @@ -438,3 +445,4 @@ using CustomTaskName = CustomTask>;\ } // namespace Tasking TASKING_DECLARE_TASK(TaskTreeTask, TaskTreeTaskAdapter); +TASKING_DECLARE_TASK(TimeoutTask, TimeoutTaskAdapter); diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index ff760169d85..b498720aa3d 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -3,26 +3,15 @@ #include -#include #include +using namespace Tasking; + using namespace std::chrono; using namespace std::chrono_literals; -using namespace Tasking; - -template -class DurationTaskAdapter : public TaskAdapter -{ -public: - DurationTaskAdapter() { *task() = std::chrono::milliseconds{0}; } - void start() final { QTimer::singleShot(*task(), this, [this] { emit done(SuccessOnDone); }); } -}; - -TASKING_DECLARE_TASK(SuccessTask, DurationTaskAdapter); -TASKING_DECLARE_TASK(FailingTask, DurationTaskAdapter); - using TaskObject = milliseconds; +using TestTask = TimeoutTask; namespace PrintableEnums { @@ -86,9 +75,9 @@ void tst_Tasking::validConstructs() { const Group task { parallel, - SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), - SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), - SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}) + TestTask([](TaskObject &) {}, [](const TaskObject &) {}), + TestTask([](TaskObject &) {}, [](const TaskObject &) {}), + TestTask([](TaskObject &) {}, [](const TaskObject &) {}) }; const Group group1 { @@ -99,18 +88,18 @@ void tst_Tasking::validConstructs() parallel, Group { parallel, - SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), + TestTask([](TaskObject &) {}, [](const TaskObject &) {}), Group { parallel, - SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), + TestTask([](TaskObject &) {}, [](const TaskObject &) {}), Group { parallel, - SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}) + TestTask([](TaskObject &) {}, [](const TaskObject &) {}) } }, Group { parallel, - SuccessTask([](TaskObject &) {}, [](const TaskObject &) {}), + TestTask([](TaskObject &) {}, [](const TaskObject &) {}), onGroupDone([] {}) } }, @@ -127,24 +116,24 @@ void tst_Tasking::validConstructs() const Group task2 { parallel, - SuccessTask(setupHandler), - SuccessTask(setupHandler, doneHandler), - SuccessTask(setupHandler, doneHandler, errorHandler), + TestTask(setupHandler), + TestTask(setupHandler, doneHandler), + TestTask(setupHandler, doneHandler, errorHandler), // need to explicitly pass empty handler for done - SuccessTask(setupHandler, {}, errorHandler) + TestTask(setupHandler, {}, errorHandler) }; // Fluent interface const Group fluent { parallel, - SuccessTask().onSetup(setupHandler), - SuccessTask().onSetup(setupHandler).onDone(doneHandler), - SuccessTask().onSetup(setupHandler).onDone(doneHandler).onError(errorHandler), + TestTask().onSetup(setupHandler), + TestTask().onSetup(setupHandler).onDone(doneHandler), + TestTask().onSetup(setupHandler).onDone(doneHandler).onError(errorHandler), // possible to skip the empty done - SuccessTask().onSetup(setupHandler).onError(errorHandler), + TestTask().onSetup(setupHandler).onError(errorHandler), // possible to set handlers in a different order - SuccessTask().onError(errorHandler).onDone(doneHandler).onSetup(setupHandler), + TestTask().onError(errorHandler).onDone(doneHandler).onSetup(setupHandler), }; @@ -259,8 +248,14 @@ void tst_Tasking::testTree_data() const auto createTask = [storage, setupTask, setupDone, setupError]( int taskId, bool successTask, milliseconds timeout = 0ms) -> TaskItem { if (successTask) - return SuccessTask(setupTask(taskId, timeout), setupDone(taskId), setupError(taskId)); - return FailingTask(setupTask(taskId, timeout), setupDone(taskId), setupError(taskId)); + return TestTask(setupTask(taskId, timeout), setupDone(taskId), setupError(taskId)); + const Group root { + finishAllAndError, + TestTask(setupTask(taskId, timeout)), + onGroupDone([storage, taskId] { storage->m_log.append({taskId, Handler::Done}); }), + onGroupError([storage, taskId] { storage->m_log.append({taskId, Handler::Error}); }) + }; + return root; }; const auto createSuccessTask = [createTask](int taskId, milliseconds timeout = 0ms) { @@ -273,7 +268,7 @@ void tst_Tasking::testTree_data() const auto createDynamicTask = [storage, setupDynamicTask, setupDone, setupError]( int taskId, TaskAction action) { - return SuccessTask(setupDynamicTask(taskId, action), setupDone(taskId), setupError(taskId)); + return TestTask(setupDynamicTask(taskId, action), setupDone(taskId), setupError(taskId)); }; const auto groupSetup = [storage](int taskId) { @@ -2142,7 +2137,7 @@ void tst_Tasking::storageDestructor() }; const Group root { Storage(storage), - SuccessTask(setupSleepingTask) + TestTask(setupSleepingTask) }; TaskTree taskTree(root); From 1599106a224fc56c472078963fc1095b110c67a6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 31 May 2023 18:29:11 +0200 Subject: [PATCH 1405/1447] TaskTree: Make the TimeoutTask reliable Ensure the timeout tasks preserve the right order of their done signals. Change-Id: I62508d0710eb2324d7c347a9907a899c97d3975d Reviewed-by: Marcus Tillmanns --- src/libs/solutions/tasking/tasktree.cpp | 85 +++++++++++++++++++- src/libs/solutions/tasking/tasktree.h | 4 + tests/auto/solutions/tasking/tst_tasking.cpp | 4 +- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 7fc5c665918..f5d67625a8e 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -9,6 +9,8 @@ #include #include +using namespace std::chrono; + namespace Tasking { // That's cut down qtcassert.{c,h} to avoid the dependency. @@ -1848,14 +1850,95 @@ void TaskTreeTaskAdapter::start() task()->start(); } +using TimeoutCallback = std::function; + +struct TimerData +{ + system_clock::time_point m_deadline; + QPointer m_context; + TimeoutCallback m_callback; +}; + +QMutex s_mutex; +std::atomic_int s_timerId = 0; +QHash s_timerIdToTimerData = {}; +QMultiMap s_deadlineToTimerId = {}; + +static QList prepareForActivation(int timerId) +{ + QMutexLocker lock(&s_mutex); + const auto it = s_timerIdToTimerData.constFind(timerId); + if (it == s_timerIdToTimerData.cend()) + return {}; // the timer was already activated + + const system_clock::time_point deadline = it->m_deadline; + QList toActivate; + auto itMap = s_deadlineToTimerId.cbegin(); + while (itMap != s_deadlineToTimerId.cend()) { + if (itMap.key() > deadline) + break; + + const auto it = s_timerIdToTimerData.constFind(itMap.value()); + if (it != s_timerIdToTimerData.cend()) { + toActivate.append(it.value()); + s_timerIdToTimerData.erase(it); + } + itMap = s_deadlineToTimerId.erase(itMap); + } + return toActivate; +} + +static void removeTimerId(int timerId) +{ + QMutexLocker lock(&s_mutex); + const auto it = s_timerIdToTimerData.constFind(timerId); + QTC_ASSERT(it != s_timerIdToTimerData.cend(), + qWarning("Removing active timerId failed."); return); + + const system_clock::time_point deadline = it->m_deadline; + s_timerIdToTimerData.erase(it); + + const int removedCount = s_deadlineToTimerId.remove(deadline, timerId); + QTC_ASSERT(removedCount == 1, qWarning("Removing active timerId failed."); return); +} + +static void handleTimeout(int timerId) +{ + const QList toActivate = prepareForActivation(timerId); + for (const TimerData &timerData : toActivate) { + if (timerData.m_context) + QMetaObject::invokeMethod(timerData.m_context.get(), timerData.m_callback); + } +} + +static int scheduleTimeout(milliseconds timeout, QObject *context, const TimeoutCallback &callback) +{ + const int timerId = s_timerId.fetch_add(1) + 1; + const system_clock::time_point deadline = system_clock::now() + timeout; + QTimer::singleShot(timeout, context, [timerId] { handleTimeout(timerId); }); + QMutexLocker lock(&s_mutex); + s_timerIdToTimerData.emplace(timerId, TimerData{deadline, context, callback}); + s_deadlineToTimerId.insert(deadline, timerId); + return timerId; +} + TimeoutTaskAdapter::TimeoutTaskAdapter() { *task() = std::chrono::milliseconds::zero(); } +TimeoutTaskAdapter::~TimeoutTaskAdapter() +{ + if (m_timerId) + removeTimerId(*m_timerId); +} + void TimeoutTaskAdapter::start() { - QTimer::singleShot(*task(), this, [this] { emit done(true); }); + if (*task() == milliseconds::zero()) + QTimer::singleShot(0, this, [this] { emit done(true); }); + else + m_timerId = scheduleTimeout(*task(), this, [this] { m_timerId = {}; emit done(true); }); } } // namespace Tasking diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 78593aa1823..6962ed5cabe 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -430,7 +430,11 @@ class TASKING_EXPORT TimeoutTaskAdapter : public TaskAdapter m_timerId; }; } // namespace Tasking diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index b498720aa3d..cbe0048eeb4 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -781,7 +781,7 @@ void tst_Tasking::testTree_data() parallel, workflowPolicy(policy), createFailingTask(1, 1ms), - createSuccessTask(2, 2ms), + createSuccessTask(2, 1ms), groupDone(0), groupError(0) }; @@ -853,7 +853,7 @@ void tst_Tasking::testTree_data() workflowPolicy(policy), createSuccessTask(1), createFailingTask(2, 1ms), - createSuccessTask(3, 2ms), + createSuccessTask(3, 1ms), groupDone(0), groupError(0) }; From 619735d99dd30690bb183c5334b6a836813cf25c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 29 May 2023 00:13:12 +0200 Subject: [PATCH 1406/1447] TaskTree: Introduce withTimeout() Make it available for Group or CustomTask items. Note, that when withTimeout() is used, the total number of tasks grows by one. Change-Id: Idc71737ba66b92bdc4bf17599c793b1127d22f5e Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.cpp | 17 +++ src/libs/solutions/tasking/tasktree.h | 12 ++ tests/auto/solutions/tasking/tst_tasking.cpp | 115 ++++++++++++++++++- 3 files changed, 143 insertions(+), 1 deletion(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index f5d67625a8e..8c6f5879144 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -567,6 +567,23 @@ void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler) m_taskHandler.m_errorHandler = handler; } +TaskItem TaskItem::withTimeout(const TaskItem &item, milliseconds timeout, + const GroupEndHandler &handler) +{ + const TimeoutTask::EndHandler taskHandler = handler + ? [handler](const milliseconds &) { handler(); } : TimeoutTask::EndHandler(); + return Group { + parallel, + stopOnFinished, + Group { + finishAllAndError, + TimeoutTask([timeout](milliseconds &timeoutData) { timeoutData = timeout; }, + taskHandler) + }, + item + }; +} + class TaskTreePrivate; class TaskNode; diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 6962ed5cabe..1d596316cae 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -187,6 +187,8 @@ protected: static TaskItem groupHandler(const GroupHandler &handler) { return TaskItem({handler}); } static TaskItem parallelLimit(int limit) { return TaskItem({{}, limit}); } static TaskItem workflowPolicy(WorkflowPolicy policy) { return TaskItem({{}, {}, policy}); } + static TaskItem withTimeout(const TaskItem &item, std::chrono::milliseconds timeout, + const GroupEndHandler &handler = {}); private: Type m_type = Type::Group; @@ -216,6 +218,11 @@ public: using TaskItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel). using TaskItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError. + TaskItem withTimeout(std::chrono::milliseconds timeout, + const GroupEndHandler &handler = {}) const { + return TaskItem::withTimeout(*this, timeout, handler); + } + private: template static GroupSetupHandler wrapGroupSetup(SetupHandler &&handler) @@ -329,6 +336,11 @@ public: return *this; } + TaskItem withTimeout(std::chrono::milliseconds timeout, + const GroupEndHandler &handler = {}) const { + return TaskItem::withTimeout(*this, timeout, handler); + } + private: template static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) { diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index cbe0048eeb4..e5791f0d6f1 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -25,7 +25,8 @@ enum class Handler { GroupDone, GroupError, Sync, - BarrierAdvance + BarrierAdvance, + Timeout }; Q_ENUM_NS(Handler); @@ -245,6 +246,12 @@ void tst_Tasking::testTree_data() }; }; + const auto setupTimeout = [storage](int taskId) { + return [storage, taskId] { + storage->m_log.append({taskId, Handler::Timeout}); + }; + }; + const auto createTask = [storage, setupTask, setupDone, setupError]( int taskId, bool successTask, milliseconds timeout = 0ms) -> TaskItem { if (successTask) @@ -2083,6 +2090,112 @@ void tst_Tasking::testTree_data() QTest::newRow("MultiBarrierParallelMultiWaitFor") << TestData{storage, root4, log4, 6, OnDone::Success}; } + + { + // Test CustomTask::withTimeout() combinations: + // 1. When the timeout has triggered or not. + // 2. With and without timeout handler. + const Group root1 { + Storage(storage), + TestTask(setupTask(1, 1000ms), setupDone(1), setupError(1)) + .withTimeout(1ms) + }; + const Log log1 { + {1, Handler::Setup}, + {1, Handler::Error} + }; + QTest::newRow("TaskErrorWithTimeout") << TestData{storage, root1, log1, 2, + OnDone::Failure}; + + const Group root2 { + Storage(storage), + TestTask(setupTask(1, 1000ms), setupDone(1), setupError(1)) + .withTimeout(1ms, setupTimeout(1)) + }; + const Log log2 { + {1, Handler::Setup}, + {1, Handler::Timeout}, + {1, Handler::Error} + }; + QTest::newRow("TaskErrorWithTimeoutHandler") << TestData{storage, root2, log2, 2, + OnDone::Failure}; + + const Group root3 { + Storage(storage), + TestTask(setupTask(1, 1ms), setupDone(1), setupError(1)) + .withTimeout(1000ms) + }; + const Log doneLog { + {1, Handler::Setup}, + {1, Handler::Done} + }; + QTest::newRow("TaskDoneWithTimeout") << TestData{storage, root3, doneLog, 2, + OnDone::Success}; + + const Group root4 { + Storage(storage), + TestTask(setupTask(1, 1ms), setupDone(1), setupError(1)) + .withTimeout(1000ms, setupTimeout(1)) + }; + QTest::newRow("TaskDoneWithTimeoutHandler") << TestData{storage, root4, doneLog, 2, + OnDone::Success}; + } + + { + // Test Group::withTimeout() combinations: + // 1. When the timeout has triggered or not. + // 2. With and without timeout handler. + const Group root1 { + Storage(storage), + Group { + createSuccessTask(1, 1000ms) + }.withTimeout(1ms) + }; + const Log log1 { + {1, Handler::Setup}, + {1, Handler::Error} + }; + QTest::newRow("GroupErrorWithTimeout") << TestData{storage, root1, log1, 2, + OnDone::Failure}; + + // Test Group::withTimeout(), passing custom handler + const Group root2 { + Storage(storage), + Group { + createSuccessTask(1, 1000ms) + }.withTimeout(1ms, setupTimeout(1)) + }; + const Log log2 { + {1, Handler::Setup}, + {1, Handler::Timeout}, + {1, Handler::Error} + }; + QTest::newRow("GroupErrorWithTimeoutHandler") << TestData{storage, root2, log2, 2, + OnDone::Failure}; + + const Group root3 { + Storage(storage), + Group { + createSuccessTask(1, 1ms) + }.withTimeout(1000ms) + }; + const Log doneLog { + {1, Handler::Setup}, + {1, Handler::Done} + }; + QTest::newRow("GroupDoneWithTimeout") << TestData{storage, root3, doneLog, 2, + OnDone::Success}; + + // Test Group::withTimeout(), passing custom handler + const Group root4 { + Storage(storage), + Group { + createSuccessTask(1, 1ms) + }.withTimeout(1000ms, setupTimeout(1)) + }; + QTest::newRow("GroupDoneWithTimeoutHandler") << TestData{storage, root4, doneLog, 2, + OnDone::Success}; + } } void tst_Tasking::testTree() From b2dadeb30c6cfbbe53426281ed5974d2788eeaee Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 29 May 2023 15:47:11 +0200 Subject: [PATCH 1407/1447] TaskTree: Fix the empty Group's return result Get back to the originally intended behavior for StopOnDone and ContinueOnDone workflow policies. By default, these policies report an error until at least one child task finished with success. Since the group is empty, no child finished with success, so the group should report an error. Change also the return result for the StopOnFinished policy when placed in an empty group. The policy is meant to report the finished child's result. Since no task finished, report an error in this case. Fix tests accordingly. Amends c9638ff64291351b846d28c28f077bbe70f6c1f0 Change-Id: Idc449e8c68a658755bf566df56844126167f1751 Reviewed-by: Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.cpp | 36 ++++++++++++++------ tests/auto/solutions/tasking/tst_tasking.cpp | 12 +++---- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 8c6f5879144..60caa217ef7 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -679,8 +679,8 @@ public: const ConstData &m_constData; const QList m_storageIdList; - int m_doneCount = 0; bool m_successBit = true; + int m_doneCount = 0; Guard m_startGuard; }; @@ -875,14 +875,28 @@ void TaskContainer::RuntimeData::callStorageDoneHandlers() } } +static bool initialSuccessBit(WorkflowPolicy workflowPolicy) +{ + switch (workflowPolicy) { + case WorkflowPolicy::StopOnError: + case WorkflowPolicy::ContinueOnError: + case WorkflowPolicy::FinishAllAndDone: + return true; + case WorkflowPolicy::StopOnDone: + case WorkflowPolicy::ContinueOnDone: + case WorkflowPolicy::StopOnFinished: + case WorkflowPolicy::FinishAllAndError: + return false; + } + QTC_CHECK(false); + return false; +} + TaskContainer::RuntimeData::RuntimeData(const ConstData &constData) : m_constData(constData) , m_storageIdList(createStorages(constData)) -{ - m_successBit = m_constData.m_workflowPolicy != WorkflowPolicy::StopOnDone - && m_constData.m_workflowPolicy != WorkflowPolicy::ContinueOnDone - && m_constData.m_workflowPolicy != WorkflowPolicy::FinishAllAndError; -} + , m_successBit(initialSuccessBit(m_constData.m_workflowPolicy)) +{} TaskContainer::RuntimeData::~RuntimeData() { @@ -896,10 +910,10 @@ TaskContainer::RuntimeData::~RuntimeData() bool TaskContainer::RuntimeData::updateSuccessBit(bool success) { if (m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndDone - || m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndError) - return m_successBit; - if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) { - m_successBit = success; + || m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndError + || m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) { + if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) + m_successBit = success; return m_successBit; } @@ -929,7 +943,7 @@ TaskAction TaskContainer::start() } if (startAction == TaskAction::Continue) { if (m_constData.m_children.isEmpty()) - startAction = TaskAction::StopWithDone; + startAction = toTaskAction(m_runtimeData->m_successBit); } return continueStart(startAction, 0); } diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index e5791f0d6f1..8c2173585b1 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -651,16 +651,16 @@ void tst_Tasking::testTree_data() OnDone::Success}; const Group root3 = createRoot(WorkflowPolicy::StopOnDone); - QTest::newRow("EmptyStopOnDone") << TestData{storage, root3, doneLog, 0, - OnDone::Success}; + QTest::newRow("EmptyStopOnDone") << TestData{storage, root3, errorLog, 0, + OnDone::Failure}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnDone); - QTest::newRow("EmptyContinueOnDone") << TestData{storage, root4, doneLog, 0, - OnDone::Success}; + QTest::newRow("EmptyContinueOnDone") << TestData{storage, root4, errorLog, 0, + OnDone::Failure}; const Group root5 = createRoot(WorkflowPolicy::StopOnFinished); - QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, doneLog, 0, - OnDone::Success}; + QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, errorLog, 0, + OnDone::Failure}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndDone); QTest::newRow("EmptyFinishAllAndDone") << TestData{storage, root6, doneLog, 0, From 6f8e5c409f0a1b6fc8a655109188b29957f2bc92 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 29 May 2023 19:05:31 +0200 Subject: [PATCH 1408/1447] TaskTree: De-utils-ize manual test, rename it to demo Change-Id: I80a2522f7ba12ee9b63c19d66e514d7047951733 Reviewed-by: Marcus Tillmanns --- tests/manual/CMakeLists.txt | 2 +- tests/manual/manual.qbs | 2 +- tests/manual/tasking/CMakeLists.txt | 1 + tests/manual/tasking/demo/CMakeLists.txt | 11 + tests/manual/tasking/demo/demo.qbs | 18 ++ tests/manual/tasking/demo/demo.qrc | 6 + .../tasking/demo/icons/progressindicator.png | Bin 0 -> 336 bytes .../demo/icons/progressindicator@2x.png | Bin 0 -> 302 bytes .../{tasktree => tasking/demo}/main.cpp | 211 ++++++++++-------- .../manual/tasking/demo/progressindicator.cpp | 149 +++++++++++++ tests/manual/tasking/demo/progressindicator.h | 21 ++ .../{tasktree => tasking/demo}/taskwidget.cpp | 91 ++++---- .../{tasktree => tasking/demo}/taskwidget.h | 20 +- tests/manual/tasktree/CMakeLists.txt | 6 - tests/manual/tasktree/tasktree.qbs | 14 -- 15 files changed, 368 insertions(+), 184 deletions(-) create mode 100644 tests/manual/tasking/CMakeLists.txt create mode 100644 tests/manual/tasking/demo/CMakeLists.txt create mode 100644 tests/manual/tasking/demo/demo.qbs create mode 100644 tests/manual/tasking/demo/demo.qrc create mode 100644 tests/manual/tasking/demo/icons/progressindicator.png create mode 100644 tests/manual/tasking/demo/icons/progressindicator@2x.png rename tests/manual/{tasktree => tasking/demo}/main.cpp (55%) create mode 100644 tests/manual/tasking/demo/progressindicator.cpp create mode 100644 tests/manual/tasking/demo/progressindicator.h rename tests/manual/{tasktree => tasking/demo}/taskwidget.cpp (59%) rename tests/manual/{tasktree => tasking/demo}/taskwidget.h (75%) delete mode 100644 tests/manual/tasktree/CMakeLists.txt delete mode 100644 tests/manual/tasktree/tasktree.qbs diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt index fb0b611f4f7..fde3cb962ea 100644 --- a/tests/manual/CMakeLists.txt +++ b/tests/manual/CMakeLists.txt @@ -17,5 +17,5 @@ add_subdirectory(proparser) # add_subdirectory(search) add_subdirectory(shootout) add_subdirectory(subdirfileiterator) -add_subdirectory(tasktree) +add_subdirectory(tasking) add_subdirectory(widgets) diff --git a/tests/manual/manual.qbs b/tests/manual/manual.qbs index 8e157a9216b..66c480c7a62 100644 --- a/tests/manual/manual.qbs +++ b/tests/manual/manual.qbs @@ -14,7 +14,7 @@ Project { "proparser/testreader.qbs", "shootout/shootout.qbs", "subdirfileiterator/subdirfileiterator.qbs", - "tasktree/tasktree.qbs", + "tasking/demo/demo.qbs", "widgets/widgets.qbs", ] } diff --git a/tests/manual/tasking/CMakeLists.txt b/tests/manual/tasking/CMakeLists.txt new file mode 100644 index 00000000000..a16f5f12201 --- /dev/null +++ b/tests/manual/tasking/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(demo) diff --git a/tests/manual/tasking/demo/CMakeLists.txt b/tests/manual/tasking/demo/CMakeLists.txt new file mode 100644 index 00000000000..bdd790cd898 --- /dev/null +++ b/tests/manual/tasking/demo/CMakeLists.txt @@ -0,0 +1,11 @@ +add_qtc_test(tst_tasking_demo + MANUALTEST + DEPENDS Tasking Qt::Widgets + SOURCES + demo.qrc + main.cpp + progressindicator.h + progressindicator.cpp + taskwidget.h + taskwidget.cpp +) diff --git a/tests/manual/tasking/demo/demo.qbs b/tests/manual/tasking/demo/demo.qbs new file mode 100644 index 00000000000..2a54143c415 --- /dev/null +++ b/tests/manual/tasking/demo/demo.qbs @@ -0,0 +1,18 @@ +import qbs.FileInfo + +QtcManualtest { + name: "Tasking demo" + type: ["application"] + + Depends { name: "Qt"; submodules: ["widgets"] } + Depends { name: "Tasking" } + + files: [ + "demo.qrc", + "main.cpp", + "progressindicator.h", + "progressindicator.cpp", + "taskwidget.h", + "taskwidget.cpp", + ] +} diff --git a/tests/manual/tasking/demo/demo.qrc b/tests/manual/tasking/demo/demo.qrc new file mode 100644 index 00000000000..5ea09fe25ec --- /dev/null +++ b/tests/manual/tasking/demo/demo.qrc @@ -0,0 +1,6 @@ + + + icons/progressindicator.png + icons/progressindicator@2x.png + + diff --git a/tests/manual/tasking/demo/icons/progressindicator.png b/tests/manual/tasking/demo/icons/progressindicator.png new file mode 100644 index 0000000000000000000000000000000000000000..c968ae8ac9f4b1e9260e02d163a13f904ac1e24a GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7I14-?iy0XBj({-ZRBb+K z1_nkZPZ!4!i{7P|Y`vNt1&)23|1-dm*HK&7rg4$jwMl04G+G4$Hhhwr=OCc3IPajB zfQw08i%QbRciN9%t7*zeM5KNHf9A~@gWGwN{kKM0=qKj(DVQjS%ZXh)EP1Q=!QUra zH3HJ^AL5KMeh_+P@_&v!i~6f`9&ZWqY`I_19=Ps^m|j8WT!H+@9POSt%eHD2i2P*M ze_-=@hq>#XVBRZ5>;Gk+zH#Qr=J*xq5A@1DHaIqX-_Yn@Gu5F~cz48c?s=m1?=;-L zuakJ}xJE_qQeo5lg4TWoyPz|54WdW=Oco!II6UR6)cl!pE)xyaE_h5AzO!T=k8we0 oO3=53f_leKKEJtM^dH;y+Xj9g zwZ;er@9XEUw6NsJ)@ZN@@+-~lxDb7R#m~OUTHjdC-S(Td(eB7^p_1FL4lbFT`c?AK zJO{3i{0Bsizg1IQygl#xOp}Ax^Nz2uIw*1fSbtdX!pB}_+f8-W>K~}Ovq1Ymyu?a% zQ}c%HMd!P%@)^oASpy5j3$D%k%>LBw!5@ovJa -#include -#include -#include +#include #include -#include +#include +#include #include #include #include #include -using namespace Utils; +using namespace Tasking; -// TODO: make tasks cancellable -static void sleepInThread(QPromise &promise, int seconds, bool reportSuccess) +using namespace std::chrono; + +static QWidget *hr() { - QThread::sleep(seconds); - if (!reportSuccess) - promise.future().cancel(); + auto frame = new QFrame; + frame->setFrameShape(QFrame::HLine); + frame->setFrameShadow(QFrame::Sunken); + return frame; +} + +QWidget *taskGroup(QWidget *groupWidget, const QList &widgets) +{ + QWidget *widget = new QWidget; + QBoxLayout *layout = new QHBoxLayout(widget); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(groupWidget); + QGroupBox *groupBox = new QGroupBox; + QBoxLayout *subLayout = new QVBoxLayout(groupBox); + for (int i = 0; i < widgets.size(); ++i) { + if (i > 0) + subLayout->addWidget(hr()); + subLayout->addWidget(widgets.at(i)); + } + layout->addWidget(groupBox); + return widget; } int main(int argc, char *argv[]) { QApplication app(argc, argv); - setCreatorTheme(new Theme("default", &app)); - QWidget mainWidget; mainWidget.setWindowTitle("Task Tree Demo"); // Non-task GUI - QToolButton *startButton = new QToolButton(); + QToolButton *startButton = new QToolButton; startButton->setText("Start"); - QToolButton *stopButton = new QToolButton(); + QToolButton *stopButton = new QToolButton; stopButton->setText("Stop"); - QToolButton *resetButton = new QToolButton(); + QToolButton *resetButton = new QToolButton; resetButton->setText("Reset"); - QProgressBar *progressBar = new QProgressBar(); - QCheckBox *synchronizerCheckBox = new QCheckBox("Use Future Synchronizer"); - synchronizerCheckBox->setChecked(true); - QScrollArea *scrollArea = new QScrollArea(); + QProgressBar *progressBar = new QProgressBar; + QScrollArea *scrollArea = new QScrollArea; scrollArea->setWidgetResizable(true); - QWidget *scrollAreaWidget = new QWidget(); + QWidget *scrollAreaWidget = new QWidget; // Task GUI @@ -100,120 +113,124 @@ int main(int argc, char *argv[]) task_4_4->setBusyTime(6); task_4_4->setBusyTime(3); - groupTask_1->setWorkflowPolicy(Tasking::WorkflowPolicy::ContinueOnDone); - groupTask_4->setWorkflowPolicy(Tasking::WorkflowPolicy::FinishAllAndDone); + groupTask_1->setWorkflowPolicy(WorkflowPolicy::ContinueOnDone); + groupTask_4->setWorkflowPolicy(WorkflowPolicy::FinishAllAndDone); groupTask_4_3->setExecuteMode(ExecuteMode::Parallel); - groupTask_4_3->setWorkflowPolicy(Tasking::WorkflowPolicy::StopOnError); + groupTask_4_3->setWorkflowPolicy(WorkflowPolicy::StopOnError); // Task layout { - using namespace Layouting; - - Column { - TaskGroup { rootGroup, { - TaskGroup { groupTask_1, { - task_1_1, hr, - task_1_2, hr, - task_1_3, - }}, hr, - task_2, hr, - task_3, hr, - TaskGroup { groupTask_4, { - task_4_1, hr, - task_4_2, hr, - TaskGroup { groupTask_4_3, { - task_4_3_1, hr, - task_4_3_2, hr, - task_4_3_3, hr, - task_4_3_4, - }}, hr, - task_4_4, hr, - task_4_5, - }}, hr, - task_5 - }}, st - }.attachTo(scrollAreaWidget); - + QWidget *taskTree = taskGroup(rootGroup, { + taskGroup(groupTask_1, { + task_1_1, + task_1_2, + task_1_3 + }), + task_2, + task_3, + taskGroup(groupTask_4, { + task_4_1, + task_4_2, + taskGroup(groupTask_4_3, { + task_4_3_1, + task_4_3_2, + task_4_3_3, + task_4_3_4, + }), + task_4_4, + task_4_5 + }), + task_5 + }); + QBoxLayout *scrollLayout = new QVBoxLayout(scrollAreaWidget); + scrollLayout->addWidget(taskTree); + scrollLayout->addStretch(); scrollArea->setWidget(scrollAreaWidget); - Column { - Row { startButton, stopButton, resetButton, synchronizerCheckBox, progressBar }, - hr, - scrollArea - }.attachTo(&mainWidget); + QBoxLayout *mainLayout = new QVBoxLayout(&mainWidget); + QBoxLayout *subLayout = new QHBoxLayout; + subLayout->addWidget(startButton); + subLayout->addWidget(stopButton); + subLayout->addWidget(resetButton); + subLayout->addWidget(progressBar); + mainLayout->addLayout(subLayout); + mainLayout->addWidget(hr()); + mainLayout->addWidget(scrollArea); } - // Task tree creator (takes configuation from GUI) - - using namespace Tasking; + // Task tree (takes initial configuation from GUI) std::unique_ptr taskTree; - FutureSynchronizer synchronizer; + + const auto createTask = [](TaskWidget *widget) -> TaskItem { + const auto setupTask = [](TaskWidget *widget) { + return [widget](milliseconds &taskObject) { + taskObject = milliseconds{widget->busyTime() * 1000}; + widget->setState(State::Running); + }; + }; + if (widget->isSuccess()) { + return TimeoutTask(setupTask(widget), + [widget](const milliseconds &) { widget->setState(State::Done); }, + [widget](const milliseconds &) { widget->setState(State::Error); }); + } + const Group root { + finishAllAndError, + TimeoutTask(setupTask(widget)), + onGroupDone([widget] { widget->setState(State::Done); }), + onGroupError([widget] { widget->setState(State::Error); }) + }; + return root; + }; auto treeRoot = [&] { - auto taskItem = [sync = &synchronizer, synchronizerCheckBox](TaskWidget *widget) { - const auto setupHandler = [=](Async &task) { - task.setConcurrentCallData(sleepInThread, widget->busyTime(), widget->isSuccess()); - if (synchronizerCheckBox->isChecked()) - task.setFutureSynchronizer(sync); - widget->setState(State::Running); - }; - const auto doneHandler = [widget](const Async &) { - widget->setState(State::Done); - }; - const auto errorHandler = [widget](const Async &) { - widget->setState(State::Error); - }; - return AsyncTask(setupHandler, doneHandler, errorHandler); - }; - const Group root { rootGroup->executeMode(), - workflowPolicy(rootGroup->workflowPolicy()), + rootGroup->workflowPolicy(), onGroupSetup([rootGroup] { rootGroup->setState(State::Running); }), onGroupDone([rootGroup] { rootGroup->setState(State::Done); }), onGroupError([rootGroup] { rootGroup->setState(State::Error); }), Group { groupTask_1->executeMode(), - workflowPolicy(groupTask_1->workflowPolicy()), + groupTask_1->workflowPolicy(), onGroupSetup([groupTask_1] { groupTask_1->setState(State::Running); }), onGroupDone([groupTask_1] { groupTask_1->setState(State::Done); }), onGroupError([groupTask_1] { groupTask_1->setState(State::Error); }), - taskItem(task_1_1), - taskItem(task_1_2), - taskItem(task_1_3) + createTask(task_1_1), + createTask(task_1_2), + createTask(task_1_3) }, - taskItem(task_2), - taskItem(task_3), + createTask(task_2), + createTask(task_3), Group { groupTask_4->executeMode(), - workflowPolicy(groupTask_4->workflowPolicy()), + groupTask_4->workflowPolicy(), onGroupSetup([groupTask_4] { groupTask_4->setState(State::Running); }), onGroupDone([groupTask_4] { groupTask_4->setState(State::Done); }), onGroupError([groupTask_4] { groupTask_4->setState(State::Error); }), - taskItem(task_4_1), - taskItem(task_4_2), + createTask(task_4_1), + createTask(task_4_2), Group { groupTask_4_3->executeMode(), - workflowPolicy(groupTask_4_3->workflowPolicy()), + groupTask_4_3->workflowPolicy(), onGroupSetup([groupTask_4_3] { groupTask_4_3->setState(State::Running); }), onGroupDone([groupTask_4_3] { groupTask_4_3->setState(State::Done); }), onGroupError([groupTask_4_3] { groupTask_4_3->setState(State::Error); }), - taskItem(task_4_3_1), - taskItem(task_4_3_2), - taskItem(task_4_3_3), - taskItem(task_4_3_4) + createTask(task_4_3_1), + createTask(task_4_3_2), + createTask(task_4_3_3), + createTask(task_4_3_4) }, - taskItem(task_4_4), - taskItem(task_4_5) + createTask(task_4_4), + createTask(task_4_5) }, - taskItem(task_5) + createTask(task_5) }; return root; }; @@ -258,7 +275,7 @@ int main(int argc, char *argv[]) // Hack in order to show initial size minimal, but without scrollbars. // Apparently setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow) doesn't work. - const int margin = 2; + const int margin = 4; scrollArea->setMinimumSize(scrollAreaWidget->minimumSizeHint().grownBy({0, 0, margin, margin})); QTimer::singleShot(0, scrollArea, [&] { scrollArea->setMinimumSize({0, 0}); }); diff --git a/tests/manual/tasking/demo/progressindicator.cpp b/tests/manual/tasking/demo/progressindicator.cpp new file mode 100644 index 00000000000..38f577f4ed7 --- /dev/null +++ b/tests/manual/tasking/demo/progressindicator.cpp @@ -0,0 +1,149 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "progressindicator.h" + +#include +#include +#include +#include + +class OverlayWidget : public QWidget +{ +public: + using PaintFunction = std::function; + + explicit OverlayWidget(QWidget *parent = nullptr) + { + setAttribute(Qt::WA_TransparentForMouseEvents); + if (parent) + attachToWidget(parent); + } + + void attachToWidget(QWidget *parent) + { + if (parentWidget()) + parentWidget()->removeEventFilter(this); + setParent(parent); + if (parent) { + parent->installEventFilter(this); + resizeToParent(); + raise(); + } + } + void setPaintFunction(const PaintFunction &paint) { m_paint = paint; } + +protected: + bool eventFilter(QObject *obj, QEvent *ev) override + { + if (obj == parent() && ev->type() == QEvent::Resize) + resizeToParent(); + return QWidget::eventFilter(obj, ev); + } + void paintEvent(QPaintEvent *ev) override + { + if (m_paint) { + QPainter p(this); + m_paint(this, p, ev); + } + } + +private: + void resizeToParent() { setGeometry(QRect(QPoint(0, 0), parentWidget()->size())); } + + PaintFunction m_paint; +}; + +class ProgressIndicatorPainter +{ +public: + using UpdateCallback = std::function; + + ProgressIndicatorPainter(); + virtual ~ProgressIndicatorPainter() = default; + + void setUpdateCallback(const UpdateCallback &cb) { m_callback = cb; } + + QSize size() const { return m_pixmap.size() / m_pixmap.devicePixelRatio(); } + + void paint(QPainter &painter, const QRect &rect) const; + void startAnimation() { m_timer.start(); } + void stopAnimation() { m_timer.stop(); } + +protected: + void nextAnimationStep() { m_rotation = (m_rotation + m_rotationStep + 360) % 360; } + +private: + const int m_rotationStep = 45; + int m_rotation = 0; + QTimer m_timer; + QPixmap m_pixmap; + UpdateCallback m_callback; +}; + +ProgressIndicatorPainter::ProgressIndicatorPainter() +{ + m_timer.setSingleShot(false); + QObject::connect(&m_timer, &QTimer::timeout, &m_timer, [this] { + nextAnimationStep(); + if (m_callback) + m_callback(); + }); + + m_timer.setInterval(100); + m_pixmap = QPixmap(":/icons/progressindicator.png"); +} + +void ProgressIndicatorPainter::paint(QPainter &painter, const QRect &rect) const +{ + painter.save(); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + QPoint translate(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2); + QTransform t; + t.translate(translate.x(), translate.y()); + t.rotate(m_rotation); + t.translate(-translate.x(), -translate.y()); + painter.setTransform(t); + QSize pixmapUserSize(m_pixmap.size() / m_pixmap.devicePixelRatio()); + painter.drawPixmap(QPoint(rect.x() + ((rect.width() - pixmapUserSize.width()) / 2), + rect.y() + ((rect.height() - pixmapUserSize.height()) / 2)), + m_pixmap); + painter.restore(); +} + +class ProgressIndicatorWidget : public OverlayWidget +{ +public: + explicit ProgressIndicatorWidget(QWidget *parent = nullptr) + : OverlayWidget(parent) + { + setPaintFunction( + [this](QWidget *w, QPainter &p, QPaintEvent *) { m_paint.paint(p, w->rect()); }); + m_paint.setUpdateCallback([this] { update(); }); + updateGeometry(); + } + + QSize sizeHint() const final { return m_paint.size(); } + +protected: + void showEvent(QShowEvent *) final { m_paint.startAnimation(); } + void hideEvent(QHideEvent *) final { m_paint.stopAnimation(); } + +private: + ProgressIndicatorPainter m_paint; +}; + +ProgressIndicator::ProgressIndicator(QWidget *parent) + : QObject(parent) + , m_widget(new ProgressIndicatorWidget(parent)) {} + + +void ProgressIndicator::show() +{ + m_widget->show(); +} + +void ProgressIndicator::hide() +{ + m_widget->hide(); +} diff --git a/tests/manual/tasking/demo/progressindicator.h b/tests/manual/tasking/demo/progressindicator.h new file mode 100644 index 00000000000..406ebc9e831 --- /dev/null +++ b/tests/manual/tasking/demo/progressindicator.h @@ -0,0 +1,21 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef PROGRESSINDICATOR_H +#define PROGRESSINDICATOR_H + +#include + +class ProgressIndicator : public QObject +{ +public: + ProgressIndicator(QWidget *parent = nullptr); + + void show(); + void hide(); + +private: + class ProgressIndicatorWidget *m_widget = nullptr; +}; + +#endif // PROGRESSINDICATOR_H diff --git a/tests/manual/tasktree/taskwidget.cpp b/tests/manual/tasking/demo/taskwidget.cpp similarity index 59% rename from tests/manual/tasktree/taskwidget.cpp rename to tests/manual/tasking/demo/taskwidget.cpp index ddc56aa77e2..6bc68db1a1b 100644 --- a/tests/manual/tasktree/taskwidget.cpp +++ b/tests/manual/tasking/demo/taskwidget.cpp @@ -1,20 +1,18 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include "progressindicator.h" #include "taskwidget.h" -#include -#include -#include - +#include #include #include #include #include +#include #include -using namespace Utils; -using namespace Layouting; +using namespace Tasking; static QString colorButtonStyleSheet(const QColor &bgColor) { @@ -37,10 +35,10 @@ static QColor stateToColor(State state) { class StateIndicator : public QLabel { public: - StateIndicator() + StateIndicator(QWidget *parent = nullptr) + : QLabel(parent) { - m_progressIndicator = new ProgressIndicator(ProgressIndicatorSize::Small); - m_progressIndicator->attachToWidget(this); + m_progressIndicator = new ProgressIndicator(this); m_progressIndicator->hide(); updateState(); } @@ -67,9 +65,7 @@ private: }; StateWidget::StateWidget() - : m_stateIndicator(new StateIndicator) -{ -} + : m_stateIndicator(new StateIndicator(this)) {} void StateWidget::setState(State state) { @@ -86,14 +82,13 @@ TaskWidget::TaskWidget() setBusyTime(1); setSuccess(true); - Row { - m_stateIndicator, - m_infoLabel, - m_spinBox, - m_checkBox, - st, - noMargin, - }.attachTo(this); + QBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(m_stateIndicator); + layout->addWidget(m_infoLabel); + layout->addWidget(m_spinBox); + layout->addWidget(m_checkBox); + layout->addStretch(); + layout->setContentsMargins(0, 0, 0, 0); } void TaskWidget::setBusyTime(int seconds) @@ -122,34 +117,32 @@ GroupWidget::GroupWidget() { m_stateIndicator->setFixedWidth(30); - m_executeCombo->addItem("Sequential", (int)ExecuteMode::Sequential); - m_executeCombo->addItem("Parallel", (int)ExecuteMode::Parallel); + m_executeCombo->addItem("Sequential", int(ExecuteMode::Sequential)); + m_executeCombo->addItem("Parallel", int(ExecuteMode::Parallel)); updateExecuteMode(); connect(m_executeCombo, &QComboBox::currentIndexChanged, this, [this](int index) { m_executeMode = (ExecuteMode)m_executeCombo->itemData(index).toInt(); }); - m_workflowCombo->addItem("Stop On Error", (int)Tasking::WorkflowPolicy::StopOnError); - m_workflowCombo->addItem("Cont On Error", (int)Tasking::WorkflowPolicy::ContinueOnError); - m_workflowCombo->addItem("Stop On Done", (int)Tasking::WorkflowPolicy::StopOnDone); - m_workflowCombo->addItem("Cont On Done", (int)Tasking::WorkflowPolicy::ContinueOnDone); - m_workflowCombo->addItem("Optional", (int)Tasking::WorkflowPolicy::FinishAllAndDone); + const QMetaEnum workflow = QMetaEnum::fromType(); + for (int i = 0; i < workflow.keyCount(); ++i) + m_workflowCombo->addItem(workflow.key(i), workflow.value(i)); + updateWorkflowPolicy(); connect(m_workflowCombo, &QComboBox::currentIndexChanged, this, [this](int index) { - m_workflowPolicy = (Tasking::WorkflowPolicy)m_workflowCombo->itemData(index).toInt(); + m_workflowPolicy = (WorkflowPolicy)m_workflowCombo->itemData(index).toInt(); }); - Row { - m_stateIndicator, - Column { - new QLabel("Execute:"), - m_executeCombo, - new QLabel("Workflow:"), - m_workflowCombo, - st, - noMargin - } - }.attachTo(this); + QBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(m_stateIndicator); + QBoxLayout *subLayout = new QVBoxLayout; + subLayout->addWidget(new QLabel("Execute Mode:")); + subLayout->addWidget(m_executeCombo); + subLayout->addWidget(new QLabel("Workflow Policy:")); + subLayout->addWidget(m_workflowCombo); + subLayout->addStretch(); + layout->addLayout(subLayout); + layout->setContentsMargins(0, 0, 0, 0); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); } @@ -165,12 +158,12 @@ void GroupWidget::updateExecuteMode() m_executeCombo->setCurrentIndex(m_executeCombo->findData((int)m_executeMode)); } -Tasking::TaskItem GroupWidget::executeMode() const +TaskItem GroupWidget::executeMode() const { - return m_executeMode == ExecuteMode::Sequential ? Tasking::sequential : Tasking::parallel; + return m_executeMode == ExecuteMode::Sequential ? sequential : parallel; } -void GroupWidget::setWorkflowPolicy(Tasking::WorkflowPolicy policy) +void GroupWidget::setWorkflowPolicy(WorkflowPolicy policy) { m_workflowPolicy = policy; updateWorkflowPolicy(); @@ -181,13 +174,7 @@ void GroupWidget::updateWorkflowPolicy() m_workflowCombo->setCurrentIndex(m_workflowCombo->findData((int)m_workflowPolicy)); } -Tasking::WorkflowPolicy GroupWidget::workflowPolicy() const +TaskItem GroupWidget::workflowPolicy() const { - return m_workflowPolicy; + return Tasking::workflowPolicy(m_workflowPolicy); } - -void createItem(Layouting::LayoutItem *item, const TaskGroup &taskGroup) -{ - item->addItems({taskGroup.group, Group { taskGroup.items }, br}); -} - diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasking/demo/taskwidget.h similarity index 75% rename from tests/manual/tasktree/taskwidget.h rename to tests/manual/tasking/demo/taskwidget.h index c425f23965f..3ce210eb0d4 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasking/demo/taskwidget.h @@ -1,9 +1,10 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -#include +#ifndef TASKWIDGET_H +#define TASKWIDGET_H -#include +#include #include @@ -64,7 +65,7 @@ public: Tasking::TaskItem executeMode() const; void setWorkflowPolicy(Tasking::WorkflowPolicy policy); - Tasking::WorkflowPolicy workflowPolicy() const; + Tasking::TaskItem workflowPolicy() const; private: void updateExecuteMode(); @@ -77,11 +78,4 @@ private: Tasking::WorkflowPolicy m_workflowPolicy = Tasking::WorkflowPolicy::StopOnError; }; -class TaskGroup -{ -public: - QWidget *group; - Layouting::Column items; -}; - -void createItem(Layouting::LayoutItem *item, const TaskGroup &taskGroup); +#endif // TASKWIDGET_H diff --git a/tests/manual/tasktree/CMakeLists.txt b/tests/manual/tasktree/CMakeLists.txt deleted file mode 100644 index 19bd81bfb2b..00000000000 --- a/tests/manual/tasktree/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -add_qtc_test(tst_manual_tasktree - MANUALTEST - DEPENDS Utils - SOURCES - main.cpp taskwidget.h taskwidget.cpp -) diff --git a/tests/manual/tasktree/tasktree.qbs b/tests/manual/tasktree/tasktree.qbs deleted file mode 100644 index dad8e14763c..00000000000 --- a/tests/manual/tasktree/tasktree.qbs +++ /dev/null @@ -1,14 +0,0 @@ -import qbs.FileInfo - -QtcManualtest { - name: "Manual TaskTree test" - type: ["application"] - - Depends { name: "Utils" } - - files: [ - "main.cpp", - "taskwidget.h", - "taskwidget.cpp", - ] -} From 3ee32c1a3b54542bd41df8b7bd420cb0554a9fc5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 29 May 2023 01:10:39 +0200 Subject: [PATCH 1409/1447] TaskTree: Reuse withTimeout() Add static runBlocking() overloads. Replace int timeout arg with std::chrono::milliseconds. Change-Id: Id10a010f05eda8452cd7e4cd9ee46216087fc70e Reviewed-by: Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.cpp | 35 +++++++++++-------- src/libs/solutions/tasking/tasktree.h | 8 +++-- src/libs/utils/filestreamer.cpp | 3 +- .../remotelinux/filesystemaccess_test.cpp | 4 +-- tests/auto/solutions/tasking/tst_tasking.cpp | 8 ++--- tests/auto/utils/async/tst_async.cpp | 9 ++--- .../tst_subdirfileiterator.cpp | 6 ++-- 7 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 60caa217ef7..f9fe58375e8 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1791,9 +1791,16 @@ bool TaskTree::isRunning() const return d->m_root && d->m_root->isRunning(); } -bool TaskTree::runBlocking(const QFuture &future, int timeoutMs) +bool TaskTree::runBlocking() { - if (isRunning() || future.isCanceled()) + QPromise dummy; + dummy.start(); + return runBlocking(dummy.future()); +} + +bool TaskTree::runBlocking(const QFuture &future) +{ + if (future.isCanceled()) return false; bool ok = false; @@ -1812,17 +1819,7 @@ bool TaskTree::runBlocking(const QFuture &future, int timeoutMs) connect(this, &TaskTree::done, &loop, [finalize] { finalize(true); }); connect(this, &TaskTree::errorOccurred, &loop, [finalize] { finalize(false); }); - start(); - if (!isRunning()) - return ok; - - QTimer timer; - if (timeoutMs) { - timer.setSingleShot(true); - timer.setInterval(timeoutMs); - connect(&timer, &QTimer::timeout, this, &TaskTree::stop); - timer.start(); - } + QTimer::singleShot(0, this, &TaskTree::start); loop.exec(QEventLoop::ExcludeUserInputEvents); if (!ok) { @@ -1832,11 +1829,19 @@ bool TaskTree::runBlocking(const QFuture &future, int timeoutMs) return ok; } -bool TaskTree::runBlocking(int timeoutMs) +bool TaskTree::runBlocking(const Group &recipe, milliseconds timeout) { QPromise dummy; dummy.start(); - return runBlocking(dummy.future(), timeoutMs); + return TaskTree::runBlocking(recipe, dummy.future(), timeout); +} + +bool TaskTree::runBlocking(const Group &recipe, const QFuture &future, milliseconds timeout) +{ + const Group root = timeout == milliseconds::max() ? recipe + : Group { recipe.withTimeout(timeout) }; + TaskTree taskTree(root); + return taskTree.runBlocking(future); } int TaskTree::taskCount() const diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 1d596316cae..b4119219a1b 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -390,8 +390,12 @@ public: // Helper methods. They execute a local event loop with ExcludeUserInputEvents. // The passed future is used for listening to the cancel event. // Don't use it in main thread. To be used in non-main threads or in auto tests. - bool runBlocking(const QFuture &future, int timeoutMs = 0); - bool runBlocking(int timeoutMs = 0); + bool runBlocking(); + bool runBlocking(const QFuture &future); + static bool runBlocking(const Group &recipe, + std::chrono::milliseconds timeout = std::chrono::milliseconds::max()); + static bool runBlocking(const Group &recipe, const QFuture &future, + std::chrono::milliseconds timeout = std::chrono::milliseconds::max()); int taskCount() const; int progressMaximum() const { return taskCount(); } diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp index d24b61dbde3..693849b7c59 100644 --- a/src/libs/utils/filestreamer.cpp +++ b/src/libs/utils/filestreamer.cpp @@ -375,8 +375,7 @@ static void transfer(QPromise &promise, const FilePath &source, const File if (promise.isCanceled()) return; - TaskTree taskTree(transferTask(source, destination)); - if (!taskTree.runBlocking(promise.future())) + if (!TaskTree::runBlocking(transferTask(source, destination), promise.future())) promise.future().cancel(); } diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index dda6e417615..2edb78fa7b3 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -503,8 +503,8 @@ void FileSystemAccessTest::testFileStreamer() } }; - TaskTree taskTree(root); - QVERIFY(taskTree.runBlocking(10000)); + using namespace std::chrono_literals; + QVERIFY(TaskTree::runBlocking(root, 10000ms)); QVERIFY(localData); QCOMPARE(*localData, data); diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 8c2173585b1..294bea71b7e 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -2202,15 +2202,15 @@ void tst_Tasking::testTree() { QFETCH(TestData, testData); - TaskTree taskTree(testData.root); - QCOMPARE(taskTree.taskCount(), testData.taskCount); + TaskTree taskTree({testData.root.withTimeout(1000ms)}); + QCOMPARE(taskTree.taskCount() - 1, testData.taskCount); // -1 for the timeout task above Log actualLog; const auto collectLog = [&actualLog](CustomStorage *storage) { actualLog = storage->m_log; }; taskTree.onStorageDone(testData.storage, collectLog); - const OnDone result = taskTree.runBlocking(2000) ? OnDone::Success : OnDone::Failure; + const OnDone result = taskTree.runBlocking() ? OnDone::Success : OnDone::Failure; QCOMPARE(taskTree.isRunning(), false); - QCOMPARE(taskTree.progressValue(), testData.taskCount); + QCOMPARE(taskTree.progressValue(), taskTree.progressMaximum()); QCOMPARE(actualLog, testData.expectedLog); QCOMPARE(CustomStorage::instanceCount(), 0); diff --git a/tests/auto/utils/async/tst_async.cpp b/tests/auto/utils/async/tst_async.cpp index 01c3306a3bf..5d4a81dc961 100644 --- a/tests/auto/utils/async/tst_async.cpp +++ b/tests/auto/utils/async/tst_async.cpp @@ -8,6 +8,8 @@ using namespace Utils; +using namespace std::chrono_literals; + class tst_Async : public QObject { Q_OBJECT @@ -438,8 +440,8 @@ void tst_Async::taskTree() AsyncTask(setupIntAsync, handleIntAsync), }; - TaskTree tree(root); - QVERIFY(tree.runBlocking(1000)); + + QVERIFY(TaskTree::runBlocking(root, 1000ms)); QCOMPARE(value, 16); } @@ -575,8 +577,7 @@ void tst_Async::mapReduce() QFETCH(double, sum); QFETCH(QList, results); - TaskTree tree(root); - QVERIFY(tree.runBlocking(1000)); + QVERIFY(TaskTree::runBlocking(root, 1000ms)); QCOMPARE(s_results, results); QCOMPARE(s_sum, sum); } diff --git a/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp b/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp index 66dd7737816..882a9993a26 100644 --- a/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp +++ b/tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp @@ -135,8 +135,7 @@ private slots: tasks.append(AsyncTask(onSetup(parentDir.filePath(dirName), templateFile))); } - TaskTree taskTree(tasks); - QVERIFY(taskTree.runBlocking()); + QVERIFY(TaskTree::runBlocking(tasks)); } void cleanupTestCase() @@ -161,8 +160,7 @@ private slots: tasks.append(AsyncTask(onSetup(parentDir.filePath(dirName)))); } - TaskTree taskTree(tasks); - QVERIFY(taskTree.runBlocking()); + QVERIFY(TaskTree::runBlocking(tasks)); m_tempDir.reset(); Singleton::deleteAll(); From 7d40a35d9ee875b0bfb40e5f5abf5032c0f01c65 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 09:08:16 +0200 Subject: [PATCH 1410/1447] Android: Use aspect as direct member in deploy step Change-Id: I7c7037ca5ca1fb1cd3fcb7ab66a30a6f62986e20 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/android/androiddeployqtstep.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index f33ae5aa6b3..a9e9596e772 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -122,7 +122,7 @@ private: QMap m_filesToPull; QStringList m_androidABIs; - BoolAspect *m_uninstallPreviousPackage = nullptr; + BoolAspect m_uninstallPreviousPackage{this}; bool m_uninstallPreviousPackageRun = false; bool m_useAndroiddeployqt = false; bool m_askForUninstall = false; @@ -143,17 +143,16 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id) setImmutable(true); setUserExpanded(true); - m_uninstallPreviousPackage = addAspect(); - m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey); - m_uninstallPreviousPackage->setLabel(Tr::tr("Uninstall the existing app before deployment"), + m_uninstallPreviousPackage.setSettingsKey(UninstallPreviousPackageKey); + m_uninstallPreviousPackage.setLabel(Tr::tr("Uninstall the existing app before deployment"), BoolAspect::LabelPlacement::AtCheckBox); - m_uninstallPreviousPackage->setValue(false); + m_uninstallPreviousPackage.setValue(false); const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); const bool forced = qt && qt->qtVersion() < QVersionNumber(5, 4, 0); if (forced) { - m_uninstallPreviousPackage->setValue(true); - m_uninstallPreviousPackage->setEnabled(false); + m_uninstallPreviousPackage.setValue(true); + m_uninstallPreviousPackage.setEnabled(false); } connect(this, &AndroidDeployQtStep::askForUninstall, @@ -274,7 +273,7 @@ bool AndroidDeployQtStep::init() emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); - m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value(); + m_uninstallPreviousPackageRun = m_uninstallPreviousPackage(); if (m_uninstallPreviousPackageRun) m_manifestName = AndroidManager::manifestPath(target()); From 00f427f68e8a36904d2999e98d685c3540e289cd Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 18:03:31 +0200 Subject: [PATCH 1411/1447] QmakeProjectManager: Auto-register aspects Change-Id: I61b41b0155e125173e48686d1482bb8bd94055da Reviewed-by: Christian Stenger --- src/plugins/qmakeprojectmanager/qmakesettings.cpp | 3 --- src/plugins/qmakeprojectmanager/qmakesettings.h | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.cpp b/src/plugins/qmakeprojectmanager/qmakesettings.cpp index f920381d15e..e69526901f0 100644 --- a/src/plugins/qmakeprojectmanager/qmakesettings.cpp +++ b/src/plugins/qmakeprojectmanager/qmakesettings.cpp @@ -26,7 +26,6 @@ QmakeSettings::QmakeSettings() setCategory(ProjectExplorer::Constants::BUILD_AND_RUN_SETTINGS_CATEGORY); setSettingsGroup("QmakeProjectManager"); - registerAspect(&warnAgainstUnalignedBuildDir); warnAgainstUnalignedBuildDir.setSettingsKey("WarnAgainstUnalignedBuildDir"); warnAgainstUnalignedBuildDir.setDefaultValue(HostOsInfo::isWindowsHost()); warnAgainstUnalignedBuildDir.setLabelText(Tr::tr("Warn if a project's source and " @@ -34,13 +33,11 @@ QmakeSettings::QmakeSettings() warnAgainstUnalignedBuildDir.setToolTip(Tr::tr("Qmake has subtle bugs that " "can be triggered if source and build directory are not at the same level.")); - registerAspect(&alwaysRunQmake); alwaysRunQmake.setSettingsKey("AlwaysRunQmake"); alwaysRunQmake.setLabelText(Tr::tr("Run qmake on every build")); alwaysRunQmake.setToolTip(Tr::tr("This option can help to prevent failures on " "incremental builds, but might slow them down unnecessarily in the general case.")); - registerAspect(&ignoreSystemFunction); ignoreSystemFunction.setSettingsKey("RunSystemFunction"); ignoreSystemFunction.setLabelText(Tr::tr("Ignore qmake's system() function when parsing a project")); ignoreSystemFunction.setToolTip(Tr::tr("Checking this option avoids unwanted side effects, " diff --git a/src/plugins/qmakeprojectmanager/qmakesettings.h b/src/plugins/qmakeprojectmanager/qmakesettings.h index de9a9ec0d37..9c2b277f538 100644 --- a/src/plugins/qmakeprojectmanager/qmakesettings.h +++ b/src/plugins/qmakeprojectmanager/qmakesettings.h @@ -14,9 +14,9 @@ public: bool runSystemFunction() { return !ignoreSystemFunction(); } - Utils::BoolAspect warnAgainstUnalignedBuildDir; - Utils::BoolAspect alwaysRunQmake; - Utils::BoolAspect ignoreSystemFunction; + Utils::BoolAspect warnAgainstUnalignedBuildDir{this}; + Utils::BoolAspect alwaysRunQmake{this}; + Utils::BoolAspect ignoreSystemFunction{this}; }; QmakeSettings &settings(); From 5fb623fc14d376b988a8311ee82884e98cac9556 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 17:37:30 +0200 Subject: [PATCH 1412/1447] Macros: Merge macrooptionswidget.{h,cpp} into macrooptionspage.cpp Change-Id: I4493d781a503dde252ae6ad4d705e378b5b0ed51 Reviewed-by: Christian Stenger --- src/plugins/macros/CMakeLists.txt | 1 - src/plugins/macros/macrooptionspage.cpp | 189 +++++++++++++++++++++- src/plugins/macros/macrooptionspage.h | 6 +- src/plugins/macros/macrooptionswidget.cpp | 166 ------------------- src/plugins/macros/macrooptionswidget.h | 55 ------- src/plugins/macros/macros.qbs | 2 - 6 files changed, 186 insertions(+), 233 deletions(-) delete mode 100644 src/plugins/macros/macrooptionswidget.cpp delete mode 100644 src/plugins/macros/macrooptionswidget.h diff --git a/src/plugins/macros/CMakeLists.txt b/src/plugins/macros/CMakeLists.txt index aef9a332ddc..588a9a330f3 100644 --- a/src/plugins/macros/CMakeLists.txt +++ b/src/plugins/macros/CMakeLists.txt @@ -9,7 +9,6 @@ add_qtc_plugin(Macros macrolocatorfilter.cpp macrolocatorfilter.h macromanager.cpp macromanager.h macrooptionspage.cpp macrooptionspage.h - macrooptionswidget.cpp macrooptionswidget.h macros.qrc macrosconstants.h macrosplugin.cpp macrosplugin.h diff --git a/src/plugins/macros/macrooptionspage.cpp b/src/plugins/macros/macrooptionspage.cpp index 6295ea94e78..616547283e0 100644 --- a/src/plugins/macros/macrooptionspage.cpp +++ b/src/plugins/macros/macrooptionspage.cpp @@ -3,15 +3,195 @@ #include "macrooptionspage.h" +#include "macro.h" #include "macromanager.h" -#include "macrooptionswidget.h" #include "macrosconstants.h" #include "macrostr.h" +#include +#include +#include +#include + #include -namespace Macros { -namespace Internal { +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Macros::Internal { + +const int NAME_ROLE = Qt::UserRole; +const int WRITE_ROLE = Qt::UserRole + 1; + +class MacroOptionsWidget final : public Core::IOptionsPageWidget +{ +public: + MacroOptionsWidget(); + + void initialize(); + + void apply() final; + +private: + void remove(); + void changeCurrentItem(QTreeWidgetItem *current); + + void createTable(); + + void changeDescription(const QString &description); + + QStringList m_macroToRemove; + bool m_changingCurrent = false; + + QMap m_macroToChange; + + QTreeWidget *m_treeWidget; + QPushButton *m_removeButton; + QGroupBox *m_macroGroup; + QLineEdit *m_description; +}; + +MacroOptionsWidget::MacroOptionsWidget() +{ + m_treeWidget = new QTreeWidget; + m_treeWidget->setTextElideMode(Qt::ElideLeft); + m_treeWidget->setUniformRowHeights(true); + m_treeWidget->setSortingEnabled(true); + m_treeWidget->setColumnCount(3); + m_treeWidget->header()->setSortIndicatorShown(true); + m_treeWidget->header()->setStretchLastSection(true); + m_treeWidget->header()->setSortIndicator(0, Qt::AscendingOrder); + m_treeWidget->setHeaderLabels({Tr::tr("Name"), Tr::tr("Description"), Tr::tr("Shortcut")}); + + m_description = new QLineEdit; + + m_removeButton = new QPushButton(Tr::tr("Remove")); + + m_macroGroup = new QGroupBox(Tr::tr("Macro"), this); + + using namespace Layouting; + + Row { + Tr::tr("Description:"), m_description + }.attachTo(m_macroGroup); + + Column { + Group { + title(Tr::tr("Preferences")), + Row { + m_treeWidget, + Column { m_removeButton, st }, + } + }, + m_macroGroup + }.attachTo(this); + + connect(m_treeWidget, &QTreeWidget::currentItemChanged, + this, &MacroOptionsWidget::changeCurrentItem); + connect(m_removeButton, &QPushButton::clicked, + this, &MacroOptionsWidget::remove); + connect(m_description, &QLineEdit::textChanged, + this, &MacroOptionsWidget::changeDescription); + + initialize(); +} + +void MacroOptionsWidget::initialize() +{ + m_macroToRemove.clear(); + m_macroToChange.clear(); + m_treeWidget->clear(); + changeCurrentItem(nullptr); + + // Create the treeview + createTable(); +} + +void MacroOptionsWidget::createTable() +{ + QDir dir(MacroManager::macrosDirectory()); + const Utils::Id base = Utils::Id(Constants::PREFIX_MACRO); + for (Macro *macro : MacroManager::macros()) { + QFileInfo fileInfo(macro->fileName()); + if (fileInfo.absoluteDir() == dir.absolutePath()) { + auto macroItem = new QTreeWidgetItem(m_treeWidget); + macroItem->setText(0, macro->displayName()); + macroItem->setText(1, macro->description()); + macroItem->setData(0, NAME_ROLE, macro->displayName()); + macroItem->setData(0, WRITE_ROLE, macro->isWritable()); + + Core::Command *command = + Core::ActionManager::command(base.withSuffix(macro->displayName())); + if (command && command->action()) { + macroItem->setText(2, + command->action()->shortcut().toString(QKeySequence::NativeText)); + } + } + } +} + +void MacroOptionsWidget::changeCurrentItem(QTreeWidgetItem *current) +{ + m_changingCurrent = true; + m_removeButton->setEnabled(current); + m_macroGroup->setEnabled(current); + if (!current) { + m_description->clear(); + } else { + m_description->setText(current->text(1)); + m_description->setEnabled(current->data(0, WRITE_ROLE).toBool()); + } + m_changingCurrent = false; +} + +void MacroOptionsWidget::remove() +{ + QTreeWidgetItem *current = m_treeWidget->currentItem(); + m_macroToRemove.append(current->data(0, NAME_ROLE).toString()); + delete current; +} + +void MacroOptionsWidget::apply() +{ + // Remove macro + for (const QString &name : std::as_const(m_macroToRemove)) { + MacroManager::instance()->deleteMacro(name); + m_macroToChange.remove(name); + } + + // Change macro + for (auto it = m_macroToChange.cbegin(), end = m_macroToChange.cend(); it != end; ++it) + MacroManager::instance()->changeMacro(it.key(), it.value()); + + // Reinitialize the page + initialize(); +} + +void MacroOptionsWidget::changeDescription(const QString &description) +{ + QTreeWidgetItem *current = m_treeWidget->currentItem(); + if (m_changingCurrent || !current) + return; + + QString macroName = current->data(0, NAME_ROLE).toString(); + m_macroToChange[macroName] = description; + current->setText(1, description); + QFont font = current->font(1); + font.setItalic(true); + current->setFont(1, font); +} MacroOptionsPage::MacroOptionsPage() { @@ -21,5 +201,4 @@ MacroOptionsPage::MacroOptionsPage() setWidgetCreator([] { return new MacroOptionsWidget; }); } -} // Internal -} // Macros +} // Macros::Internal diff --git a/src/plugins/macros/macrooptionspage.h b/src/plugins/macros/macrooptionspage.h index e9948cb1673..511b8b2b870 100644 --- a/src/plugins/macros/macrooptionspage.h +++ b/src/plugins/macros/macrooptionspage.h @@ -5,8 +5,7 @@ #include -namespace Macros { -namespace Internal { +namespace Macros::Internal { class MacroOptionsPage final : public Core::IOptionsPage { @@ -14,5 +13,4 @@ public: MacroOptionsPage(); }; -} // namespace Internal -} // namespace Macros +} // Macros::Internal diff --git a/src/plugins/macros/macrooptionswidget.cpp b/src/plugins/macros/macrooptionswidget.cpp deleted file mode 100644 index cd11ab64ef3..00000000000 --- a/src/plugins/macros/macrooptionswidget.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (C) 2016 Nicolas Arnaud-Cormos -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "macrooptionswidget.h" - -#include "macro.h" -#include "macromanager.h" -#include "macrosconstants.h" -#include "macrostr.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Macros::Internal { - -const int NAME_ROLE = Qt::UserRole; -const int WRITE_ROLE = Qt::UserRole + 1; - -MacroOptionsWidget::MacroOptionsWidget() -{ - m_treeWidget = new QTreeWidget; - m_treeWidget->setTextElideMode(Qt::ElideLeft); - m_treeWidget->setUniformRowHeights(true); - m_treeWidget->setSortingEnabled(true); - m_treeWidget->setColumnCount(3); - m_treeWidget->header()->setSortIndicatorShown(true); - m_treeWidget->header()->setStretchLastSection(true); - m_treeWidget->header()->setSortIndicator(0, Qt::AscendingOrder); - m_treeWidget->setHeaderLabels({Tr::tr("Name"), Tr::tr("Description"), Tr::tr("Shortcut")}); - - m_description = new QLineEdit; - - m_removeButton = new QPushButton(Tr::tr("Remove")); - - m_macroGroup = new QGroupBox(Tr::tr("Macro"), this); - - using namespace Layouting; - - Row { - Tr::tr("Description:"), m_description - }.attachTo(m_macroGroup); - - Column { - Group { - title(Tr::tr("Preferences")), - Row { - m_treeWidget, - Column { m_removeButton, st }, - } - }, - m_macroGroup - }.attachTo(this); - - connect(m_treeWidget, &QTreeWidget::currentItemChanged, - this, &MacroOptionsWidget::changeCurrentItem); - connect(m_removeButton, &QPushButton::clicked, - this, &MacroOptionsWidget::remove); - connect(m_description, &QLineEdit::textChanged, - this, &MacroOptionsWidget::changeDescription); - - initialize(); -} - -MacroOptionsWidget::~MacroOptionsWidget() = default; - -void MacroOptionsWidget::initialize() -{ - m_macroToRemove.clear(); - m_macroToChange.clear(); - m_treeWidget->clear(); - changeCurrentItem(nullptr); - - // Create the treeview - createTable(); -} - -void MacroOptionsWidget::createTable() -{ - QDir dir(MacroManager::macrosDirectory()); - const Utils::Id base = Utils::Id(Constants::PREFIX_MACRO); - for (Macro *macro : MacroManager::macros()) { - QFileInfo fileInfo(macro->fileName()); - if (fileInfo.absoluteDir() == dir.absolutePath()) { - auto macroItem = new QTreeWidgetItem(m_treeWidget); - macroItem->setText(0, macro->displayName()); - macroItem->setText(1, macro->description()); - macroItem->setData(0, NAME_ROLE, macro->displayName()); - macroItem->setData(0, WRITE_ROLE, macro->isWritable()); - - Core::Command *command = - Core::ActionManager::command(base.withSuffix(macro->displayName())); - if (command && command->action()) { - macroItem->setText(2, - command->action()->shortcut().toString(QKeySequence::NativeText)); - } - } - } -} - -void MacroOptionsWidget::changeCurrentItem(QTreeWidgetItem *current) -{ - m_changingCurrent = true; - m_removeButton->setEnabled(current); - m_macroGroup->setEnabled(current); - if (!current) { - m_description->clear(); - } else { - m_description->setText(current->text(1)); - m_description->setEnabled(current->data(0, WRITE_ROLE).toBool()); - } - m_changingCurrent = false; -} - -void MacroOptionsWidget::remove() -{ - QTreeWidgetItem *current = m_treeWidget->currentItem(); - m_macroToRemove.append(current->data(0, NAME_ROLE).toString()); - delete current; -} - -void MacroOptionsWidget::apply() -{ - // Remove macro - for (const QString &name : std::as_const(m_macroToRemove)) { - MacroManager::instance()->deleteMacro(name); - m_macroToChange.remove(name); - } - - // Change macro - for (auto it = m_macroToChange.cbegin(), end = m_macroToChange.cend(); it != end; ++it) - MacroManager::instance()->changeMacro(it.key(), it.value()); - - // Reinitialize the page - initialize(); -} - -void MacroOptionsWidget::changeDescription(const QString &description) -{ - QTreeWidgetItem *current = m_treeWidget->currentItem(); - if (m_changingCurrent || !current) - return; - - QString macroName = current->data(0, NAME_ROLE).toString(); - m_macroToChange[macroName] = description; - current->setText(1, description); - QFont font = current->font(1); - font.setItalic(true); - current->setFont(1, font); -} - -} // Macros::Internal diff --git a/src/plugins/macros/macrooptionswidget.h b/src/plugins/macros/macrooptionswidget.h deleted file mode 100644 index 9810da6dd18..00000000000 --- a/src/plugins/macros/macrooptionswidget.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2016 Nicolas Arnaud-Cormos -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include -#include - -QT_BEGIN_NAMESPACE -class QGroupBox; -class QLineEdit; -class QPushButton; -class QTreeWidget; -class QTreeWidgetItem; -QT_END_NAMESPACE - -namespace Macros { -namespace Internal { - -class MacroOptionsWidget final : public Core::IOptionsPageWidget -{ - Q_OBJECT - -public: - MacroOptionsWidget(); - ~MacroOptionsWidget() final; - - void initialize(); - - void apply() final; - -private: - void remove(); - void changeCurrentItem(QTreeWidgetItem *current); - - void createTable(); - - void changeDescription(const QString &description); - -private: - QStringList m_macroToRemove; - bool m_changingCurrent = false; - - QMap m_macroToChange; - - QTreeWidget *m_treeWidget; - QPushButton *m_removeButton; - QGroupBox *m_macroGroup; - QLineEdit *m_description; -}; - -} // namespace Internal -} // namespace Macros diff --git a/src/plugins/macros/macros.qbs b/src/plugins/macros/macros.qbs index f6579c7394d..c975f756d7d 100644 --- a/src/plugins/macros/macros.qbs +++ b/src/plugins/macros/macros.qbs @@ -29,8 +29,6 @@ QtcPlugin { "macromanager.h", "macrooptionspage.cpp", "macrooptionspage.h", - "macrooptionswidget.cpp", - "macrooptionswidget.h", "macros.qrc", "macrosconstants.h", "macrosplugin.cpp", From 64c48af15be4fda6f39383fbf9f589c4df1d8bc4 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 31 May 2023 18:04:22 +0200 Subject: [PATCH 1413/1447] ProjectManager: Auto-register build settings aspects Add the necessary contructor to TriStateAspect, too. Change-Id: Ieb0f19cdf95f7492380d7c4e5663f455e4da3452 Reviewed-by: Christian Stenger --- src/libs/utils/aspects.cpp | 5 ++++- src/libs/utils/aspects.h | 3 ++- .../debugger/debuggerrunconfigurationaspect.cpp | 4 ++-- .../projectexplorer/buildpropertiessettings.cpp | 8 ++------ src/plugins/projectexplorer/buildpropertiessettings.h | 10 +++++----- .../qmakeprojectmanager/qmakebuildconfiguration.cpp | 3 ++- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index bb637f31b02..3dc5da0a4b4 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2162,8 +2162,11 @@ void DoubleAspect::setSingleStep(double step) Its visual representation is a QComboBox with three items. */ -TriStateAspect::TriStateAspect(const QString &onString, const QString &offString, +TriStateAspect::TriStateAspect(AspectContainer *container, + const QString &onString, + const QString &offString, const QString &defaultString) + : SelectionAspect(container) { setDisplayStyle(DisplayStyle::ComboBox); setDefaultValue(TriState::Default); diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index db3c036cec3..a0ebf5a045a 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -549,7 +549,8 @@ class QTCREATOR_UTILS_EXPORT TriStateAspect : public SelectionAspect Q_OBJECT public: - TriStateAspect(const QString &onString = {}, + TriStateAspect(AspectContainer *container = nullptr, + const QString &onString = {}, const QString &offString = {}, const QString &defaultString = {}); diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 4b67e82fd86..8c118f553b6 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -101,11 +101,11 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) addDataExtractor(this, &DebuggerRunConfigurationAspect::useMultiProcess, &Data::useMultiProcess); addDataExtractor(this, &DebuggerRunConfigurationAspect::overrideStartup, &Data::overrideStartup); - m_cppAspect = new TriStateAspect(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); + m_cppAspect = new TriStateAspect(nullptr, Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); m_cppAspect->setLabelText(Tr::tr("C++ debugger:")); m_cppAspect->setSettingsKey("RunConfiguration.UseCppDebugger"); - m_qmlAspect = new TriStateAspect(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); + m_qmlAspect = new TriStateAspect(nullptr, Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); m_qmlAspect->setLabelText(Tr::tr("QML debugger:")); m_qmlAspect->setSettingsKey("RunConfiguration.UseQmlDebugger"); diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp index 88c63b5f5c1..6df8fdd328e 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.cpp +++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp @@ -16,8 +16,8 @@ namespace ProjectExplorer { const char DEFAULT_BUILD_DIRECTORY_TEMPLATE[] = "../%{JS: Util.asciify(\"build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}\")}"; -BuildPropertiesSettings::BuildTriStateAspect::BuildTriStateAspect() - : TriStateAspect{Tr::tr("Enable"), Tr::tr("Disable"), Tr::tr("Use Project Default")} +BuildPropertiesSettings::BuildTriStateAspect::BuildTriStateAspect(AspectContainer *container) + : TriStateAspect(container, Tr::tr("Enable"), Tr::tr("Disable"), Tr::tr("Use Project Default")) {} BuildPropertiesSettings::BuildPropertiesSettings() @@ -43,7 +43,6 @@ BuildPropertiesSettings::BuildPropertiesSettings() }; }); - registerAspect(&buildDirectoryTemplate); buildDirectoryTemplate.setDisplayStyle(StringAspect::LineEditDisplay); buildDirectoryTemplate.setSettingsKey("Directories/BuildDirectory.TemplateV2"); buildDirectoryTemplate.setDefaultValue(DEFAULT_BUILD_DIRECTORY_TEMPLATE); @@ -51,15 +50,12 @@ BuildPropertiesSettings::BuildPropertiesSettings() buildDirectoryTemplate.setUseGlobalMacroExpander(); buildDirectoryTemplate.setUseResetButton(); - registerAspect(&separateDebugInfo); separateDebugInfo.setSettingsKey("ProjectExplorer/Settings/SeparateDebugInfo"); separateDebugInfo.setLabelText(Tr::tr("Separate debug info:")); - registerAspect(&qmlDebugging); qmlDebugging.setSettingsKey("ProjectExplorer/Settings/QmlDebugging"); qmlDebugging.setLabelText(Tr::tr("QML debugging:")); - registerAspect(&qtQuickCompiler); qtQuickCompiler.setSettingsKey("ProjectExplorer/Settings/QtQuickCompiler"); qtQuickCompiler.setLabelText(Tr::tr("Use qmlcachegen:")); diff --git a/src/plugins/projectexplorer/buildpropertiessettings.h b/src/plugins/projectexplorer/buildpropertiessettings.h index 4d028788d51..3b1b2b7c698 100644 --- a/src/plugins/projectexplorer/buildpropertiessettings.h +++ b/src/plugins/projectexplorer/buildpropertiessettings.h @@ -17,13 +17,13 @@ public: class BuildTriStateAspect : public Utils::TriStateAspect { public: - BuildTriStateAspect(); + explicit BuildTriStateAspect(AspectContainer *container); }; - Utils::StringAspect buildDirectoryTemplate; - BuildTriStateAspect separateDebugInfo; - BuildTriStateAspect qmlDebugging; - BuildTriStateAspect qtQuickCompiler; + Utils::StringAspect buildDirectoryTemplate{this}; + BuildTriStateAspect separateDebugInfo{this}; + BuildTriStateAspect qmlDebugging{this}; + BuildTriStateAspect qtQuickCompiler{this}; Utils::BoolAspect showQtSettings; QString defaultBuildDirectoryTemplate(); diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index 173443958db..9da9f7f65a7 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -57,7 +57,8 @@ class RunSystemAspect : public TriStateAspect { Q_OBJECT public: - RunSystemAspect() : TriStateAspect(Tr::tr("Run"), Tr::tr("Ignore"), Tr::tr("Use global setting")) + RunSystemAspect() + : TriStateAspect(nullptr, Tr::tr("Run"), Tr::tr("Ignore"), Tr::tr("Use global setting")) { setSettingsKey("RunSystemFunction"); setDisplayName(Tr::tr("qmake system() behavior when parsing:")); From f4eff5f76d2ecf8dfd2c7987054512c3cbd25edf Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 25 May 2023 13:22:29 +0200 Subject: [PATCH 1414/1447] Core: Remove IOptionPage::setLayouter overload The one producing LayoutItems it sufficient nowadays. Task-number: QTCREATORBUG-29167 Change-Id: Iba50a0cf4f16a95dbe68ca01c42bda4ac5441f75 Reviewed-by: Reviewed-by: Alessandro Portale --- src/plugins/coreplugin/dialogs/ioptionspage.cpp | 9 --------- src/plugins/coreplugin/dialogs/ioptionspage.h | 1 - 2 files changed, 10 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp index 1912045af53..4def6095a11 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp +++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp @@ -199,15 +199,6 @@ void IOptionsPage::setSettings(AspectContainer *settings) m_settings = settings; } -void IOptionsPage::setLayouter(const std::function &layouter) -{ - m_widgetCreator = [layouter] { - auto widget = new IOptionsPageWidget; - layouter(widget); - return widget; - }; -} - void IOptionsPage::setLayouter(const std::function &layouter) { m_widgetCreator = [layouter] { diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h index a38bf863c36..f4801b7c734 100644 --- a/src/plugins/coreplugin/dialogs/ioptionspage.h +++ b/src/plugins/coreplugin/dialogs/ioptionspage.h @@ -74,7 +74,6 @@ protected: void setCategoryIcon(const Utils::Icon &categoryIcon) { m_categoryIcon = categoryIcon; } void setCategoryIconPath(const Utils::FilePath &categoryIconPath); void setSettings(Utils::AspectContainer *settings); - void setLayouter(const std::function &layouter); void setLayouter(const std::function &layouter); // Used in FontSettingsPage. FIXME? From 1afa720f2cfee575096fc7f6afc5a0760496675b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 1 Jun 2023 13:00:52 +0300 Subject: [PATCH 1415/1447] FilePath: Replace Q_OS_WINDOWS with Q_OS_WIN for consistency Change-Id: Ia624c804e54fe4c5213351078a7aa9c8dec9f262 Reviewed-by: hjk --- src/libs/utils/filepath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index ad871413a22..9059a37ecc3 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1914,7 +1914,7 @@ FilePath FilePath::canonicalPath() const return *this; } -#ifdef Q_OS_WINDOWS +#ifdef Q_OS_WIN DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL; if (isDir()) flagsAndAttrs |= FILE_FLAG_BACKUP_SEMANTICS; From d81d1bc14c08645749b0d5fda1675dd20a369ad2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 03:20:12 +0200 Subject: [PATCH 1416/1447] SilverSearcher: Make the search cancellable Especially when there are lot of files, and not too much results. Change-Id: Id9e89c5d0d681e11dd8a9fb5c2373164dbeef3fd Reviewed-by: Orgad Shaneh --- .../findinfilessilversearcher.cpp | 50 ++++++++++++------- .../silversearcher/silversearcherparser.cpp | 36 ++++++++++--- .../silversearcher/silversearcherparser.h | 16 +++++- 3 files changed, 76 insertions(+), 26 deletions(-) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index 43397a03f6d..b7e26d071b1 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -16,6 +16,7 @@ #include using namespace Core; +using namespace SilverSearcher; using namespace TextEditor; using namespace Utils; @@ -58,6 +59,21 @@ static bool isSilverSearcherAvailable() && silverSearcherProcess.cleanedStdOut().contains("ag version"); } +static std::optional regExpFromParameters(const FileFindParameters ¶meters) +{ + if (!(parameters.flags & FindRegularExpression)) + return {}; + + const QRegularExpression::PatternOptions patternOptions + = (parameters.flags & FindCaseSensitively) + ? QRegularExpression::NoPatternOption + : QRegularExpression::CaseInsensitiveOption; + QRegularExpression regExp; + regExp.setPattern(parameters.text); + regExp.setPatternOptions(patternOptions); + return regExp; +} + static void runSilverSeacher(QPromise &promise, const FileFindParameters ¶meters) { @@ -92,26 +108,26 @@ static void runSilverSeacher(QPromise &promise, arguments << "--" << parameters.text << directory.normalizedPathName().toString(); + QEventLoop loop; + Process process; process.setCommand({"ag", arguments}); + ParserState parserState; + const std::optional regExp = regExpFromParameters(parameters); + process.setStdOutCallback([&promise, &parserState, regExp](const QString &output) { + SilverSearcher::parse(promise, output, &parserState, regExp); + }); + QObject::connect(&process, &Process::done, &loop, &QEventLoop::quit); + process.start(); - if (process.waitForFinished()) { - std::optional regExp; - if (parameters.flags & FindRegularExpression) { - regExp = QRegularExpression(); - const QRegularExpression::PatternOptions patternOptions - = (parameters.flags & FindCaseSensitively) - ? QRegularExpression::NoPatternOption - : QRegularExpression::CaseInsensitiveOption; - regExp->setPattern(parameters.text); - regExp->setPatternOptions(patternOptions); - } - const SearchResultItems items = SilverSearcher::parse(process.cleanedStdOut(), regExp); - if (!items.isEmpty()) - promise.addResult(items); - } else { - promise.future().cancel(); - } + if (process.state() == QProcess::NotRunning) + return; + + QFutureWatcher watcher; + QFuture future(promise.future()); + QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, &QEventLoop::quit); + watcher.setFuture(future); + loop.exec(QEventLoop::ExcludeUserInputEvents); } } // namespace diff --git a/src/plugins/silversearcher/silversearcherparser.cpp b/src/plugins/silversearcher/silversearcherparser.cpp index be4e9096c4c..9cdf5211a67 100644 --- a/src/plugins/silversearcher/silversearcherparser.cpp +++ b/src/plugins/silversearcher/silversearcherparser.cpp @@ -3,6 +3,8 @@ #include "silversearcherparser.h" +#include + using namespace Utils; namespace SilverSearcher { @@ -94,23 +96,28 @@ static bool parseLineHits(QStringView *remainingInput, QList> *h return true; } -SearchResultItems parse(const QString &input, const std::optional ®Exp) +void parse(QPromise &promise, const QString &input, + ParserState *parserState, const std::optional ®Exp) { + QTC_ASSERT(parserState, return); SearchResultItems items; QStringView remainingInput(input); while (true) { + if (promise.isCanceled()) + return; + if (remainingInput.isEmpty()) break; const QStringView filePathLine = nextLine(&remainingInput); - if (filePathLine.isEmpty()) + if (filePathLine.isEmpty()) { + parserState->m_lastFilePath = {}; // Clear the parser state continue; + } - if (!filePathLine.startsWith(':')) - continue; - - const FilePath filePath = FilePath::fromPathPart(filePathLine.mid(1)); + if (filePathLine.startsWith(':')) + parserState->m_lastFilePath = FilePath::fromPathPart(filePathLine.mid(1)); while (true) { QStringView hitLine = nextLine(&remainingInput); @@ -126,7 +133,7 @@ SearchResultItems parse(const QString &input, const std::optionalm_lastFilePath); item.setDisplayText(hitLine.toString()); item.setUseTextEditorFont(true); for (const QPair &hit : hits) { @@ -138,7 +145,20 @@ SearchResultItems parse(const QString &input, const std::optionalm_reportedResultsCount += items.count(); +} + +SearchResultItems parse(const QString &input, const std::optional ®Exp) +{ + QPromise promise; + promise.start(); + ParserState dummy; + SilverSearcher::parse(promise, input, &dummy, regExp); + promise.finish(); + return promise.future().resultCount() ? promise.future().result() : SearchResultItems(); } } // namespace SilverSearcher diff --git a/src/plugins/silversearcher/silversearcherparser.h b/src/plugins/silversearcher/silversearcherparser.h index f9d8502759a..1cc5ccb773c 100644 --- a/src/plugins/silversearcher/silversearcherparser.h +++ b/src/plugins/silversearcher/silversearcherparser.h @@ -5,11 +5,25 @@ #include +#include #include +namespace Utils { class FilePath; } + namespace SilverSearcher { -Utils::SearchResultItems parse(const QString &output, +class ParserState +{ +public: + Utils::FilePath m_lastFilePath; + int m_reportedResultsCount = 0; +}; + +void parse(QPromise &promise, const QString &input, + ParserState *parserState = nullptr, + const std::optional ®Exp = {}); + +Utils::SearchResultItems parse(const QString &input, const std::optional ®Exp = {}); } // namespace SilverSearcher From 333cea6ef57acf0ae5b9c85793d89f406324ad55 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 31 May 2023 10:17:50 +0200 Subject: [PATCH 1417/1447] CppEditor: Handle semantic highlighting results in chunks Otherwise, we will format all tokens n+1 times, where n is the number of tokens following on the same line. This is because results trickle in one by one from clangd as of d6f5d07639c3d0313b758ba6fb7cc5eb57d188ef. Change-Id: I38aa2c4a26336f76219d182113bb838e1866fb8e Reviewed-by: Qt CI Bot Reviewed-by: David Schulz Reviewed-by: --- src/plugins/cppeditor/semantichighlighter.cpp | 18 ++++++++++++++++++ src/plugins/cppeditor/semantichighlighter.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index c04b9270aa9..156a1d40524 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -64,6 +64,7 @@ void SemanticHighlighter::run() m_revision = documentRevision(); m_seenBlocks.clear(); + m_nextResultToHandle = m_resultCount = 0; qCDebug(log) << "starting runner for document revision" << m_revision; m_watcher->setFuture(m_highlightingRunner()); } @@ -92,6 +93,21 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) return; } + QTC_CHECK(from == m_resultCount); + m_resultCount = to; + if (to - m_nextResultToHandle >= 100) { + handleHighlighterResults(); + m_nextResultToHandle = to; + } +} + +void SemanticHighlighter::handleHighlighterResults() +{ + int from = m_nextResultToHandle; + const int to = m_resultCount; + if (from >= to) + return; + QElapsedTimer t; t.start(); @@ -177,6 +193,8 @@ void SemanticHighlighter::onHighlighterFinished() { QTC_ASSERT(m_watcher, return); + handleHighlighterResults(); + QElapsedTimer t; t.start(); diff --git a/src/plugins/cppeditor/semantichighlighter.h b/src/plugins/cppeditor/semantichighlighter.h index fb1a704e6c3..ea49f289a01 100644 --- a/src/plugins/cppeditor/semantichighlighter.h +++ b/src/plugins/cppeditor/semantichighlighter.h @@ -67,6 +67,7 @@ public: private: void onHighlighterResultAvailable(int from, int to); + void handleHighlighterResults(); void onHighlighterFinished(); void connectWatcher(); @@ -82,6 +83,8 @@ private: QScopedPointer> m_watcher; QHash m_formatMap; std::set m_seenBlocks; + int m_nextResultToHandle = 0; + int m_resultCount = 0; HighlightingRunner m_highlightingRunner; }; From cd70d10dce8993d9923619aa4582b5c84a46b12e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 13:02:25 +0200 Subject: [PATCH 1418/1447] SilverSearcher: Don't crash on giant output from ag Make cancel and continue button working. Make pausing above 200000 hits working. Fixes: QTCREATORBUG-29130 Change-Id: I55429ae1b4d80dacfcd7e8366133657d0c44a0d6 Reviewed-by: Qt CI Bot Reviewed-by: Orgad Shaneh --- .../findinfilessilversearcher.cpp | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index b7e26d071b1..7d9e5f1e141 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -114,10 +114,31 @@ static void runSilverSeacher(QPromise &promise, process.setCommand({"ag", arguments}); ParserState parserState; const std::optional regExp = regExpFromParameters(parameters); - process.setStdOutCallback([&promise, &parserState, regExp](const QString &output) { - SilverSearcher::parse(promise, output, &parserState, regExp); + QStringList outputBuffer; + // The states transition exactly in this order: + enum State { BelowLimit, AboveLimit, Paused, Resumed }; + State state = BelowLimit; + process.setStdOutCallback([&process, &loop, &promise, &state, &outputBuffer, &parserState, + regExp](const QString &output) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + return; + } + // The SearchResultWidget is going to pause the search anyway, so start buffering + // the output. + if (state == AboveLimit || state == Paused) { + outputBuffer.append(output); + } else { + SilverSearcher::parse(promise, output, &parserState, regExp); + if (state == BelowLimit && parserState.m_reportedResultsCount > 200000) + state = AboveLimit; + } + }); + QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] { + if (state == BelowLimit || state == Resumed || promise.isCanceled()) + loop.quit(); }); - QObject::connect(&process, &Process::done, &loop, &QEventLoop::quit); process.start(); if (process.state() == QProcess::NotRunning) @@ -125,7 +146,23 @@ static void runSilverSeacher(QPromise &promise, QFutureWatcher watcher; QFuture future(promise.future()); - QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, &QEventLoop::quit); + QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, [&process, &loop] { + process.close(); + loop.quit(); + }); + QObject::connect(&watcher, &QFutureWatcherBase::paused, &loop, [&state] { state = Paused; }); + QObject::connect(&watcher, &QFutureWatcherBase::resumed, &loop, + [&process, &loop, &promise, &state, &outputBuffer, &parserState, regExp] { + state = Resumed; + for (const QString &output : outputBuffer) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + } + SilverSearcher::parse(promise, output, &parserState, regExp); + } + outputBuffer.clear(); + }); watcher.setFuture(future); loop.exec(QEventLoop::ExcludeUserInputEvents); } From fd7cb1181fc1651c2836f490894d8b582724c0e7 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 1 Jun 2023 16:02:26 +0200 Subject: [PATCH 1419/1447] Tasking: Fix qbs build Change-Id: I0ad1232a997a98902e6e9a7972f2af8e04a6b096 Reviewed-by: Jarek Kobus Reviewed-by: Qt CI Bot --- src/libs/solutions/tasking/tasktree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index b4119219a1b..647c680b5b0 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -16,7 +16,7 @@ QT_END_NAMESPACE namespace Tasking { -Q_NAMESPACE +Q_NAMESPACE_EXPORT(TASKING_EXPORT) class ExecutionContextActivator; class TaskContainer; From 0ccdb4a54732930006dc0a0ba5eeb150aafc4ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Wed, 31 May 2023 23:29:10 +0200 Subject: [PATCH 1420/1447] German translation: Don't use title case for "Configure Project" button It looks odd and seems to be inconsistent. Change-Id: I5c0a075edc27c526aa445f31d031dd234cdc2ccd Reviewed-by: Eike Ziller Reviewed-by: Qt CI Patch Build Bot Reviewed-by: --- share/qtcreator/translations/qtcreator_de.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index ee6e08a335c..f4886dc760d 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -39108,7 +39108,7 @@ Sie werden erhalten. &Configure Project - Projekt &Konfigurieren + Projekt &konfigurieren Enable Kit for Project "%1" From 629e6ab945da5afeed1fff9c203cd15f6634016f Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 13:58:35 +0200 Subject: [PATCH 1421/1447] Use a few more explicit FilePathAspects Change-Id: I97431306754af3ea7a803021db7b876c31abc940 Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/python/pythonwizardpage.cpp | 1 - src/plugins/python/pythonwizardpage.h | 2 +- src/plugins/remotelinux/makeinstallstep.cpp | 3 +-- .../remotelinux/remotelinuxcustomrunconfiguration.cpp | 3 +-- src/plugins/terminal/terminalsettings.cpp | 1 - src/plugins/terminal/terminalsettings.h | 2 +- src/plugins/vcsbase/commonvcssettings.cpp | 4 ---- src/plugins/vcsbase/commonvcssettings.h | 8 ++++---- 8 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/plugins/python/pythonwizardpage.cpp b/src/plugins/python/pythonwizardpage.cpp index d132f3550c7..bcbca5a7072 100644 --- a/src/plugins/python/pythonwizardpage.cpp +++ b/src/plugins/python/pythonwizardpage.cpp @@ -102,7 +102,6 @@ PythonWizardPage::PythonWizardPage(const QList> &pySide m_createVenv.setLabelText(Tr::tr("Create new Virtual Environment")); m_venvPath.setLabelText(Tr::tr("Path to virtual environment")); - m_venvPath.setDisplayStyle(StringAspect::PathChooserDisplay); m_venvPath.setEnabler(&m_createVenv); m_venvPath.setExpectedKind(PathChooser::Directory); diff --git a/src/plugins/python/pythonwizardpage.h b/src/plugins/python/pythonwizardpage.h index 1d605b24176..6cf8a130c59 100644 --- a/src/plugins/python/pythonwizardpage.h +++ b/src/plugins/python/pythonwizardpage.h @@ -36,7 +36,7 @@ private: ProjectExplorer::InterpreterAspect m_interpreter; Utils::SelectionAspect m_pySideVersion; Utils::BoolAspect m_createVenv; - Utils::StringAspect m_venvPath; + Utils::FilePathAspect m_venvPath; Utils::InfoLabel *m_stateLabel = nullptr; }; diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index d1be1051452..42f0467c947 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -70,10 +70,9 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Id id) : MakeStep(parent connect(makeAspect, &ExecutableAspect::changed, this, &MakeInstallStep::updateCommandFromAspect); - const auto installRootAspect = addAspect(); + const auto installRootAspect = addAspect(); installRootAspect->setId(InstallRootAspectId); installRootAspect->setSettingsKey(InstallRootAspectId); - installRootAspect->setDisplayStyle(StringAspect::PathChooserDisplay); installRootAspect->setExpectedKind(PathChooser::Directory); installRootAspect->setLabelText(Tr::tr("Install root:")); installRootAspect->setFilePath(rootPath); diff --git a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp index 36e4b0bda24..fd6f75c0761 100644 --- a/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxcustomrunconfiguration.cpp @@ -41,10 +41,9 @@ RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *tar exeAspect->setHistoryCompleter("RemoteLinux.CustomExecutable.History"); exeAspect->setExpectedKind(PathChooser::Any); - auto symbolsAspect = addAspect(); + auto symbolsAspect = addAspect(); symbolsAspect->setSettingsKey("RemoteLinux.CustomRunConfig.LocalExecutable"); symbolsAspect->setLabelText(Tr::tr("Local executable:")); - symbolsAspect->setDisplayStyle(SymbolFileAspect::PathChooserDisplay); addAspect(macroExpander()); addAspect(macroExpander(), envAspect); diff --git a/src/plugins/terminal/terminalsettings.cpp b/src/plugins/terminal/terminalsettings.cpp index 99e0de0d1f8..06903c4d4c5 100644 --- a/src/plugins/terminal/terminalsettings.cpp +++ b/src/plugins/terminal/terminalsettings.cpp @@ -399,7 +399,6 @@ TerminalSettings::TerminalSettings() shell.setSettingsKey("ShellPath"); shell.setLabelText(Tr::tr("Shell path:")); shell.setExpectedKind(PathChooser::ExistingCommand); - shell.setDisplayStyle(StringAspect::PathChooserDisplay); shell.setHistoryCompleter("Terminal.Shell.History"); shell.setToolTip(Tr::tr("The shell executable to be started.")); shell.setDefaultValue(defaultShell()); diff --git a/src/plugins/terminal/terminalsettings.h b/src/plugins/terminal/terminalsettings.h index 30212b0c3de..4550bbce2a2 100644 --- a/src/plugins/terminal/terminalsettings.h +++ b/src/plugins/terminal/terminalsettings.h @@ -18,7 +18,7 @@ public: Utils::StringAspect font{this}; Utils::IntegerAspect fontSize{this}; - Utils::StringAspect shell{this}; + Utils::FilePathAspect shell{this}; Utils::StringAspect shellArguments{this}; Utils::ColorAspect foregroundColor; diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index e33de123790..d286164b5b9 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -39,7 +39,6 @@ CommonVcsSettings::CommonVcsSettings() setAutoApply(false); nickNameMailMap.setSettingsKey("NickNameMailMap"); - nickNameMailMap.setDisplayStyle(StringAspect::PathChooserDisplay); nickNameMailMap.setExpectedKind(PathChooser::File); nickNameMailMap.setHistoryCompleter("Vcs.NickMap.History"); nickNameMailMap.setLabelText(Tr::tr("User/&alias configuration file:")); @@ -47,7 +46,6 @@ CommonVcsSettings::CommonVcsSettings() "'name alias '.")); nickNameFieldListFile.setSettingsKey("NickNameFieldListFile"); - nickNameFieldListFile.setDisplayStyle(StringAspect::PathChooserDisplay); nickNameFieldListFile.setExpectedKind(PathChooser::File); nickNameFieldListFile.setHistoryCompleter("Vcs.NickFields.History"); nickNameFieldListFile.setLabelText(Tr::tr("User &fields configuration file:")); @@ -55,7 +53,6 @@ CommonVcsSettings::CommonVcsSettings() "\"Reviewed-By:\" which will be added below the submit editor.")); submitMessageCheckScript.setSettingsKey("SubmitMessageCheckScript"); - submitMessageCheckScript.setDisplayStyle(StringAspect::PathChooserDisplay); submitMessageCheckScript.setExpectedKind(PathChooser::ExistingCommand); submitMessageCheckScript.setHistoryCompleter("Vcs.MessageCheckScript.History"); submitMessageCheckScript.setLabelText(Tr::tr("Submit message &check script:")); @@ -64,7 +61,6 @@ CommonVcsSettings::CommonVcsSettings() "on standard error to indicate failure.")); sshPasswordPrompt.setSettingsKey("SshPasswordPrompt"); - sshPasswordPrompt.setDisplayStyle(StringAspect::PathChooserDisplay); sshPasswordPrompt.setExpectedKind(PathChooser::ExistingCommand); sshPasswordPrompt.setHistoryCompleter("Vcs.SshPrompt.History"); sshPasswordPrompt.setDefaultValue(sshPasswordPromptDefault()); diff --git a/src/plugins/vcsbase/commonvcssettings.h b/src/plugins/vcsbase/commonvcssettings.h index 44bf03c5776..a5005f252a5 100644 --- a/src/plugins/vcsbase/commonvcssettings.h +++ b/src/plugins/vcsbase/commonvcssettings.h @@ -16,13 +16,13 @@ class CommonVcsSettings : public Utils::AspectContainer public: CommonVcsSettings(); - Utils::StringAspect nickNameMailMap{this}; - Utils::StringAspect nickNameFieldListFile{this}; + Utils::FilePathAspect nickNameMailMap{this}; + Utils::FilePathAspect nickNameFieldListFile{this}; - Utils::StringAspect submitMessageCheckScript{this}; + Utils::FilePathAspect submitMessageCheckScript{this}; // Executable run to graphically prompt for a SSH-password. - Utils::StringAspect sshPasswordPrompt{this}; + Utils::FilePathAspect sshPasswordPrompt{this}; Utils::BoolAspect lineWrap{this}; Utils::IntegerAspect lineWrapWidth{this}; From db4dd91caf7e72566b2d6f4e829a9b7cd8d1b514 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 12:02:13 +0200 Subject: [PATCH 1422/1447] FakeVim: Streamline settings handling a bit Change-Id: I6ab2c1643a5236525515ded296cd854933584603 Reviewed-by: Alessandro Portale --- src/plugins/fakevim/fakevimactions.cpp | 10 ++- src/plugins/fakevim/fakevimactions.h | 8 +-- src/plugins/fakevim/fakevimhandler.cpp | 84 +++++++++++++------------- src/plugins/fakevim/fakevimplugin.cpp | 50 ++++++--------- 4 files changed, 66 insertions(+), 86 deletions(-) diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index b753939c056..916fea16097 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -25,8 +25,7 @@ using namespace Utils; -namespace FakeVim { -namespace Internal { +namespace FakeVim::Internal { #ifdef FAKEVIM_STANDALONE FvBaseAspect::FvBaseAspect() @@ -72,9 +71,9 @@ void setAutoApply(bool ) {} static FakeVimSettings *s_settings; -FakeVimSettings *fakeVimSettings() +FakeVimSettings &settings() { - return s_settings; + return *s_settings; } FakeVimSettings::FakeVimSettings() @@ -327,5 +326,4 @@ void FakeVimSettings::setup(FvBaseAspect *aspect, m_nameToAspect[shortName] = aspect; } -} // namespace Internal -} // namespace FakeVim +} // FakeVim::Internal diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h index 2f3f72f6951..e3b14b0d47a 100644 --- a/src/plugins/fakevim/fakevimactions.h +++ b/src/plugins/fakevim/fakevimactions.h @@ -13,8 +13,7 @@ #include #include -namespace FakeVim { -namespace Internal { +namespace FakeVim::Internal { #ifdef FAKEVIM_STANDALONE class FvBaseAspect @@ -145,7 +144,6 @@ private: QHash m_aspectToName; }; -FakeVimSettings *fakeVimSettings(); +FakeVimSettings &settings(); -} // namespace Internal -} // namespace FakeVim +} // FakeVim::Internal diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 2eb052432cf..edfa315af98 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -408,9 +408,8 @@ static QRegularExpression vimPatternToQtPattern(const QString &needle) */ // FIXME: Option smartcase should be used only if search was typed by user. - const bool ignoreCaseOption = fakeVimSettings()->ignoreCase.value(); - const bool smartCaseOption = fakeVimSettings()->smartCase.value(); - const bool initialIgnoreCase = ignoreCaseOption + const bool smartCaseOption = settings().smartCase(); + const bool initialIgnoreCase = settings().ignoreCase() && !(smartCaseOption && needle.contains(QRegularExpression("[A-Z]"))); bool ignorecase = initialIgnoreCase; @@ -2373,7 +2372,7 @@ public: QString surroundFunction; // Used for storing the function name provided to ys{motion}f } g; - FakeVimSettings &s = *fakeVimSettings(); + FakeVimSettings &s = settings(); }; static void initSingleShotTimer(QTimer *timer, @@ -2527,7 +2526,7 @@ void FakeVimHandler::Private::leaveFakeVim(bool needUpdate) // The command might have destroyed the editor. if (m_textedit || m_plaintextedit) { - if (s.showMarks.value()) + if (s.showMarks()) updateSelection(); updateMiniBuffer(); @@ -2576,7 +2575,7 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev) // We are interested in overriding most Ctrl key combinations. if (isOnlyControlModifier(mods) - && !s.passControlKey.value() + && !s.passControlKey() && ((key >= Key_A && key <= Key_Z && key != Key_K) || key == Key_BracketLeft || key == Key_BracketRight)) { // Ctrl-K is special as it is the Core's default notion of Locator @@ -3059,7 +3058,7 @@ void FakeVimHandler::Private::stopIncrementalFind() void FakeVimHandler::Private::updateFind(bool isComplete) { - if (!isComplete && !s.incSearch.value()) + if (!isComplete && !s.incSearch()) return; g.currentMessage.clear(); @@ -3161,7 +3160,7 @@ void FakeVimHandler::Private::pushUndoState(bool overwrite) pos = firstPositionInLine(lineForPosition(pos)); else if (isVisualBlockMode()) pos = blockAt(pos).position() + qMin(columnAt(anchor()), columnAt(position())); - } else if (g.movetype == MoveLineWise && s.startOfLine.value()) { + } else if (g.movetype == MoveLineWise && s.startOfLine()) { QTextCursor tc = m_cursor; if (g.submode == ShiftLeftSubMode || g.submode == ShiftRightSubMode || g.submode == IndentSubMode) { @@ -3621,7 +3620,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) return; } else if (g.submode == ExchangeSubMode) { exchangeRange(currentRange()); - } else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister.value()) { + } else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister()) { pushUndoState(false); beginEditBlock(); replaceWithRegister(currentRange()); @@ -3734,7 +3733,7 @@ void FakeVimHandler::Private::clearCurrentMode() void FakeVimHandler::Private::updateSelection() { QList selections = m_extraSelections; - if (s.showMarks.value()) { + if (s.showMarks()) { for (auto it = m_buffer->marks.cbegin(), end = m_buffer->marks.cend(); it != end; ++it) { QTextEdit::ExtraSelection sel; sel.cursor = m_cursor; @@ -3753,7 +3752,7 @@ void FakeVimHandler::Private::updateSelection() void FakeVimHandler::Private::updateHighlights() { - if (s.useCoreSearch.value() || !s.hlSearch.value() || g.highlightsCleared) { + if (s.useCoreSearch() || !s.hlSearch() || g.highlightsCleared) { if (m_highlighted.isEmpty()) return; m_highlighted.clear(); @@ -3800,7 +3799,7 @@ void FakeVimHandler::Private::updateMiniBuffer() } else if (!g.mapStates.isEmpty() && !g.mapStates.last().silent) { // Do not reset previous message when after running a mapped command. return; - } else if (g.mode == CommandMode && !g.currentCommand.isEmpty() && s.showCmd.value()) { + } else if (g.mode == CommandMode && !g.currentCommand.isEmpty() && s.showCmd()) { msg = g.currentCommand; messageLevel = MessageShowCmd; } else if (g.mode == CommandMode && isVisualMode()) { @@ -3907,7 +3906,7 @@ bool FakeVimHandler::Private::handleCommandSubSubMode(const Input &input) handled = selectBlockTextObject(g.subsubdata.is('i'), '{', '}'); else if (input.is('"') || input.is('\'') || input.is('`')) handled = selectQuotedStringTextObject(g.subsubdata.is('i'), input.asChar()); - else if (input.is('a') && s.emulateArgTextObj.value()) + else if (input.is('a') && s.emulateArgTextObj()) handled = selectArgumentTextObject(g.subsubdata.is('i')); else handled = false; @@ -4050,7 +4049,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) g.subsubmode = NoSubSubMode; } else if (input.is('/') || input.is('?')) { g.lastSearchForward = input.is('/'); - if (s.useCoreSearch.value()) { + if (s.useCoreSearch()) { // re-use the core dialog. g.findPending = true; m_findStartPosition = position(); @@ -4225,7 +4224,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) m_cursor = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2))); handleStartOfLine(); } else if (input.is('n') || input.is('N')) { - if (s.useCoreSearch.value()) { + if (s.useCoreSearch()) { bool forward = (input.is('n')) ? g.lastSearchForward : !g.lastSearchForward; int pos = position(); q->findNextRequested(!forward); @@ -4314,7 +4313,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) handled = handleNoSubMode(input); } else if (g.submode == ExchangeSubMode) { handled = handleExchangeSubMode(input); - } else if (g.submode == ChangeSubMode && input.is('x') && s.emulateExchange.value()) { + } else if (g.submode == ChangeSubMode && input.is('x') && s.emulateExchange()) { // Exchange submode is "cx", so we need to switch over from ChangeSubMode here g.submode = ExchangeSubMode; handled = true; @@ -4324,15 +4323,15 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) } else if (g.submode == AddSurroundingSubMode) { handled = handleAddSurroundingSubMode(input); } else if (g.submode == ChangeSubMode && (input.is('s') || input.is('S')) - && s.emulateSurround.value()) { + && s.emulateSurround()) { g.submode = ChangeSurroundingSubMode; g.surroundUpperCaseS = input.is('S'); handled = true; - } else if (g.submode == DeleteSubMode && input.is('s') && s.emulateSurround.value()) { + } else if (g.submode == DeleteSubMode && input.is('s') && s.emulateSurround()) { g.submode = DeleteSurroundingSubMode; handled = true; } else if (g.submode == YankSubMode && (input.is('s') || input.is('S')) - && s.emulateSurround.value()) { + && s.emulateSurround()) { g.submode = AddSurroundingSubMode; g.movetype = MoveInclusive; g.surroundUpperCaseS = input.is('S'); @@ -4341,10 +4340,9 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) || g.submode == DeleteSubMode || g.submode == YankSubMode) { handled = handleChangeDeleteYankSubModes(input); - } else if (g.submode == CommentSubMode && s.emulateVimCommentary.value()) { + } else if (g.submode == CommentSubMode && s.emulateVimCommentary()) { handled = handleCommentSubMode(input); - } else if (g.submode == ReplaceWithRegisterSubMode - && s.emulateReplaceWithRegister.value()) { + } else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister()) { handled = handleReplaceWithRegisterSubMode(input); } else if (g.submode == ReplaceSubMode) { handled = handleReplaceSubMode(input); @@ -4487,7 +4485,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input) setTargetColumn(); } else if (input.isControl('a')) { changeNumberTextObject(count()); - } else if (g.gflag && input.is('c') && s.emulateVimCommentary.value()) { + } else if (g.gflag && input.is('c') && s.emulateVimCommentary()) { if (isVisualMode()) { pushUndoState(); @@ -4512,7 +4510,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input) pushUndoState(); setAnchor(); } - } else if (g.gflag && input.is('r') && s.emulateReplaceWithRegister.value()) { + } else if (g.gflag && input.is('r') && s.emulateReplaceWithRegister()) { g.submode = ReplaceWithRegisterSubMode; if (isVisualMode()) { dotCommand = visualDotCommand() + QString::number(count()) + "gr"; @@ -4671,7 +4669,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input) int repeat = count(); while (--repeat >= 0) redo(); - } else if (input.is('S') && isVisualMode() && s.emulateSurround.value()) { + } else if (input.is('S') && isVisualMode() && s.emulateSurround()) { g.submode = AddSurroundingSubMode; g.subsubmode = SurroundSubSubMode; } else if (input.is('s')) { @@ -4756,7 +4754,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input) if (isVisualMode()) { leaveVisualMode(); finishMovement(); - } else if (g.gflag || (g.submode == InvertCaseSubMode && s.tildeOp.value())) { + } else if (g.gflag || (g.submode == InvertCaseSubMode && s.tildeOp())) { if (atEndOfLine()) moveLeft(); setAnchor(); @@ -5404,8 +5402,8 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) if (!handleInsertInEditor(Input(Qt::Key_Backspace, Qt::NoModifier))) { joinPreviousEditBlock(); if (!m_buffer->lastInsertion.isEmpty() - || s.backspace.value().contains("start") - || s.backspace.value().contains("2")) { + || s.backspace().contains("start") + || s.backspace().contains("2")) { const int line = cursorLine() + 1; const Column col = cursorColumn(); QString data = lineContents(line); @@ -5438,7 +5436,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) } else if (input.isKey(Key_Tab)) { if (q->tabPressedInInsertMode()) { m_buffer->insertState.insertingSpaces = true; - if (s.expandTab.value()) { + if (s.expandTab()) { const int ts = s.tabStop(); const int col = logicalCursorColumn(); QString str = QString(ts - col % ts, ' '); @@ -5494,7 +5492,7 @@ void FakeVimHandler::Private::insertInInsertMode(const QString &text) { joinPreviousEditBlock(); insertText(text); - if (s.smartIndent.value() && isElectricCharacter(text.at(0))) { + if (s.smartIndent() && isElectricCharacter(text.at(0))) { const QString leftText = block().text() .left(position() - 1 - block().position()); if (leftText.simplified().isEmpty()) { @@ -6265,7 +6263,7 @@ bool FakeVimHandler::Private::handleExMoveCommand(const ExCommand &cmd) if (!insertAtEnd) moveUp(1); - if (s.startOfLine.value()) + if (s.startOfLine()) moveToFirstNonBlankOnLine(); if (lastAnchor.line >= startLine && lastAnchor.line <= endLine) @@ -6794,7 +6792,7 @@ QTextCursor FakeVimHandler::Private::search(const SearchData &sd, int startPos, } if (tc.isNull()) { - if (s.wrapScan.value()) { + if (s.wrapScan()) { tc = QTextCursor(document()); tc.movePosition(sd.forward ? StartOfDocument : EndOfDocument); if (sd.forward) @@ -6954,7 +6952,7 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat) std::swap(beginLine, endLine); targetPos = position(); } - if (s.startOfLine.value()) + if (s.startOfLine()) targetPos = firstPositionInLine(beginLine); const int sw = s.shiftWidth(); @@ -7106,7 +7104,7 @@ void FakeVimHandler::Private::setupCharClass() const QChar c = QLatin1Char(i); m_charClass[i] = c.isSpace() ? 0 : 1; } - const QString conf = s.isKeyword.value(); + const QString conf = s.isKeyword(); for (const QString &part : conf.split(',')) { if (part.contains('-')) { const int from = someInt(part.section('-', 0, 0)); @@ -7594,7 +7592,7 @@ void FakeVimHandler::Private::transformText(const Range &range, const Transforma void FakeVimHandler::Private::insertText(QTextCursor &tc, const QString &text) { - if (s.passKeys.value()) { + if (s.passKeys()) { if (tc.hasSelection() && text.isEmpty()) { QKeyEvent event(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier, QString()); passEventToEditor(event, tc); @@ -7937,7 +7935,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace) moveRight(); // If the line we started from is a comment, remove the comment string from the next line - if (startingLineIsComment && s.formatOptions.value().contains('f')) { + if (startingLineIsComment && s.formatOptions().contains('f')) { if (characterAtCursor() == '/' && characterAt(position() + 1) == '/') moveRight(2); else if (characterAtCursor() == '*' || characterAtCursor() == '#') @@ -7955,7 +7953,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace) void FakeVimHandler::Private::insertNewLine() { - if (m_buffer->editBlockLevel <= 1 && s.passKeys.value()) { + if (m_buffer->editBlockLevel <= 1 && s.passKeys()) { QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "\n"); if (passEventToEditor(event, m_cursor)) return; @@ -7967,7 +7965,7 @@ void FakeVimHandler::Private::insertNewLine() bool FakeVimHandler::Private::handleInsertInEditor(const Input &input) { - if (m_buffer->editBlockLevel > 0 || !s.passKeys.value()) + if (m_buffer->editBlockLevel > 0 || !s.passKeys()) return false; joinPreviousEditBlock(); @@ -8712,10 +8710,10 @@ QString FakeVimHandler::Private::tabExpand(int n) const void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool forceAutoIndent) { - if (!forceAutoIndent && !s.autoIndent.value() && !s.smartIndent.value()) + if (!forceAutoIndent && !s.autoIndent() && !s.smartIndent()) return; - if (s.smartIndent.value()) { + if (s.smartIndent()) { QTextBlock bl = block(); Range range(bl.position(), bl.position()); indentText(range, '\n'); @@ -8734,7 +8732,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool fo void FakeVimHandler::Private::handleStartOfLine() { - if (s.startOfLine.value()) + if (s.startOfLine()) moveToFirstNonBlankOnLine(); } @@ -9331,7 +9329,7 @@ void FakeVimHandler::Private::getRegisterType(int *reg, bool *isClipboard, bool *reg = c.toLower().unicode(); if (c == '"') { - QStringList list = s.clipboard.value().split(','); + QStringList list = s.clipboard().split(','); clipboard = list.contains("unnamedplus"); selection = list.contains("unnamed"); } else if (c == '+') { @@ -9385,7 +9383,7 @@ void FakeVimHandler::updateGlobalMarksFilenames(const QString &oldFileName, cons bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev) { #ifndef FAKEVIM_STANDALONE - if (!fakeVimSettings()->useFakeVim.value()) + if (!settings().useFakeVim()) return QObject::eventFilter(ob, ev); #endif diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index c0e908ed573..54ae4ca93f8 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -379,7 +379,6 @@ public: int cursorPos, int anchorPos, int messageLevel); void handleExCommand(FakeVimHandler *handler, bool *handled, const ExCommand &cmd); - void writeSettings(); void readSettings(); void handleDelayedQuitAll(bool forced); @@ -1051,7 +1050,7 @@ void FakeVimPluginPrivate::initialize() Command *cmd = nullptr; - cmd = ActionManager::registerAction(fakeVimSettings()->useFakeVim.action(), + cmd = ActionManager::registerAction(settings().useFakeVim.action(), INSTALL_HANDLER, Context(Core::Constants::C_GLOBAL), true); cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Shift+Y,Meta+Shift+Y") : Tr::tr("Alt+Y,Alt+Y"))); @@ -1089,7 +1088,7 @@ void FakeVimPluginPrivate::initialize() connect(DocumentManager::instance(), &DocumentManager::documentRenamed, this, &FakeVimPluginPrivate::documentRenamed); - FakeVimSettings &s = *fakeVimSettings(); + FakeVimSettings &s = settings(); connect(&s.useFakeVim, &FvBoolAspect::valueChanged, this, &FakeVimPluginPrivate::setUseFakeVim); connect(&s.readVimRc, &FvBaseAspect::changed, @@ -1107,7 +1106,7 @@ void FakeVimPluginPrivate::initialize() connect(this, &FakeVimPluginPrivate::delayedQuitAllRequested, this, &FakeVimPluginPrivate::handleDelayedQuitAll, Qt::QueuedConnection); - setCursorBlinking(s.blinkingCursor.value()); + setCursorBlinking(s.blinkingCursor()); } void FakeVimPluginPrivate::userActionTriggered(int key) @@ -1116,7 +1115,7 @@ void FakeVimPluginPrivate::userActionTriggered(int key) FakeVimHandler *handler = m_editorToHandler[editor].handler; if (handler) { // If disabled, enable FakeVim mode just for single user command. - bool enableFakeVim = !fakeVimSettings()->useFakeVim.value(); + bool enableFakeVim = !settings().useFakeVim(); if (enableFakeVim) setUseFakeVimInternal(true); @@ -1142,26 +1141,18 @@ void FakeVimPluginPrivate::createRelativeNumberWidget(IEditor *editor) { if (auto textEditor = TextEditorWidget::fromEditor(editor)) { auto relativeNumbers = new RelativeNumbersColumn(textEditor); - connect(&fakeVimSettings()->relativeNumber, &FvBaseAspect::changed, + connect(&settings().relativeNumber, &FvBaseAspect::changed, relativeNumbers, &QObject::deleteLater); - connect(&fakeVimSettings()->useFakeVim, &FvBaseAspect::changed, + connect(&settings().useFakeVim, &FvBaseAspect::changed, relativeNumbers, &QObject::deleteLater); relativeNumbers->show(); } } -void FakeVimPluginPrivate::writeSettings() -{ - QSettings *settings = ICore::settings(); - fakeVimSettings()->writeSettings(settings); -} - void FakeVimPluginPrivate::readSettings() { QSettings *settings = ICore::settings(); - fakeVimSettings()->readSettings(settings); - m_exCommandMap = m_defaultExCommandMap; int size = settings->beginReadArray(exCommandMapGroup); for (int i = 0; i < size; ++i) { @@ -1190,9 +1181,9 @@ void FakeVimPluginPrivate::maybeReadVimRc() //qDebug() << theFakeVimSetting(ConfigReadVimRc) // << theFakeVimSetting(ConfigReadVimRc)->value(); //qDebug() << theFakeVimSetting(ConfigShiftWidth)->value(); - if (!fakeVimSettings()->readVimRc.value()) + if (!settings().readVimRc()) return; - QString fileName = fakeVimSettings()->vimRcPath.value(); + QString fileName = settings().vimRcPath(); if (fileName.isEmpty()) { fileName = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QLatin1String(HostOsInfo::isWindowsHost() ? "/_vimrc" : "/.vimrc"); @@ -1202,7 +1193,6 @@ void FakeVimPluginPrivate::maybeReadVimRc() QPlainTextEdit editor; FakeVimHandler handler(&editor); handler.handleCommand("source " + fileName); - //writeSettings(); //qDebug() << theFakeVimSetting(ConfigShiftWidth)->value(); } @@ -1531,9 +1521,9 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) return; TabSettings tabSettings; - tabSettings.m_indentSize = fakeVimSettings()->shiftWidth(); - tabSettings.m_tabSize = fakeVimSettings()->tabStop(); - tabSettings.m_tabPolicy = fakeVimSettings()->expandTab() + tabSettings.m_indentSize = settings().shiftWidth(); + tabSettings.m_tabSize = settings().tabStop(); + tabSettings.m_tabPolicy = settings().expandTab() ? TabSettings::SpacesOnlyTabPolicy : TabSettings::TabsOnlyTabPolicy; tabSettings.m_continuationAlignBehavior = tew->textDocument()->tabSettings().m_continuationAlignBehavior; @@ -1757,19 +1747,15 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) *output = proc.cleanedStdOut(); }); - connect(ICore::instance(), &ICore::saveSettingsRequested, - this, &FakeVimPluginPrivate::writeSettings); - - handler->setCurrentFileName(editor->document()->filePath().toString()); handler->installEventFilter(); // pop up the bar - if (fakeVimSettings()->useFakeVim.value()) { + if (settings().useFakeVim()) { resetCommandBuffer(); handler->setupWidget(); - if (fakeVimSettings()->relativeNumber.value()) + if (settings().relativeNumber()) createRelativeNumberWidget(editor); } } @@ -1811,8 +1797,8 @@ void FakeVimPluginPrivate::setUseFakeVim(bool on) //qDebug() << "SET USE FAKEVIM" << on; Find::setUseFakeVim(on); setUseFakeVimInternal(on); - setShowRelativeLineNumbers(fakeVimSettings()->relativeNumber.value()); - setCursorBlinking(fakeVimSettings()->blinkingCursor.value()); + setShowRelativeLineNumbers(settings().relativeNumber()); + setCursorBlinking(settings().blinkingCursor()); } void FakeVimPluginPrivate::setUseFakeVimInternal(bool on) @@ -1840,7 +1826,7 @@ void FakeVimPluginPrivate::setUseFakeVimInternal(bool on) void FakeVimPluginPrivate::setShowRelativeLineNumbers(bool on) { - if (on && fakeVimSettings()->useFakeVim.value()) { + if (on && settings().useFakeVim()) { for (auto it = m_editorToHandler.constBegin(); it != m_editorToHandler.constEnd(); ++it) createRelativeNumberWidget(it.key()); } @@ -1851,7 +1837,7 @@ void FakeVimPluginPrivate::setCursorBlinking(bool on) if (m_savedCursorFlashTime == 0) m_savedCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime(); - const bool blink = on || !fakeVimSettings()->useFakeVim.value(); + const bool blink = on || !settings().useFakeVim(); QGuiApplication::styleHints()->setCursorFlashTime(blink ? m_savedCursorFlashTime : 0); } @@ -1995,7 +1981,7 @@ void FakeVimPluginPrivate::handleDelayedQuitAll(bool forced) void FakeVimPluginPrivate::quitFakeVim() { - fakeVimSettings()->useFakeVim.setValue(false); + settings().useFakeVim.setValue(false); } void FakeVimPluginPrivate::resetCommandBuffer() From 03485af13945d45b41f34c476f73eb8c649295b5 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 16:36:33 +0200 Subject: [PATCH 1423/1447] Autotools: Self-register aspect in AutogenStep Change-Id: I130ec25e6bf0bb6a45de7325834b8cc19f8c86e7 Reviewed-by: Alessandro Portale --- .../autotoolsprojectmanager/autogenstep.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/autotoolsprojectmanager/autogenstep.cpp b/src/plugins/autotoolsprojectmanager/autogenstep.cpp index c0a383205d0..090389716de 100644 --- a/src/plugins/autotoolsprojectmanager/autogenstep.cpp +++ b/src/plugins/autotoolsprojectmanager/autogenstep.cpp @@ -42,23 +42,23 @@ private: void doRun() final; bool m_runAutogen = false; + StringAspect m_arguments{this}; }; AutogenStep::AutogenStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id) { - auto arguments = addAspect(); - arguments->setSettingsKey("AutotoolsProjectManager.AutogenStep.AdditionalArguments"); - arguments->setLabelText(Tr::tr("Arguments:")); - arguments->setDisplayStyle(StringAspect::LineEditDisplay); - arguments->setHistoryCompleter("AutotoolsPM.History.AutogenStepArgs"); + m_arguments.setSettingsKey("AutotoolsProjectManager.AutogenStep.AdditionalArguments"); + m_arguments.setLabelText(Tr::tr("Arguments:")); + m_arguments.setDisplayStyle(StringAspect::LineEditDisplay); + m_arguments.setHistoryCompleter("AutotoolsPM.History.AutogenStepArgs"); - connect(arguments, &BaseAspect::changed, this, [this] { m_runAutogen = true; }); + connect(&m_arguments, &BaseAspect::changed, this, [this] { m_runAutogen = true; }); setWorkingDirectoryProvider([this] { return project()->projectDirectory(); }); - setCommandLineProvider([this, arguments] { + setCommandLineProvider([this] { return CommandLine(project()->projectDirectory() / "autogen.sh", - arguments->value(), + m_arguments(), CommandLine::Raw); }); From 71d492ae133ccf55d083bc39ff980d562dfae4e6 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 16:47:07 +0200 Subject: [PATCH 1424/1447] GitGrep: Use the text editor font for the results This looks more consistent with the results reported by the internal engine. Change-Id: I7a83954d230a61bb6db380d28de32ebde95ad366 Reviewed-by: Orgad Shaneh --- src/plugins/git/gitgrep.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 2161cbbf68e..e390924472b 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -111,6 +111,7 @@ public: for (const auto &match : std::as_const(matches)) { result.setMainRange(lineNumber, match.matchStart, match.matchLength); result.setUserData(match.regexpCapturedTexts); + result.setUseTextEditorFont(true); resultList->append(result); } } From 738d13cd43cfb2a47b81b5df161b638d54973c95 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 18:24:51 +0200 Subject: [PATCH 1425/1447] GitGrep: Use QStringView for parsing This speeds up the parsing of big results (~2 million hits) by ~5-10%. Remove PromiseType alias. Make regexp a member field and configure it just once inside c'tor. Change-Id: Ib99597a7b8b979d49f36f2c7d146beeaa1caa380 Reviewed-by: Orgad Shaneh --- src/plugins/git/gitgrep.cpp | 75 ++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index e390924472b..24990008cb5 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -25,7 +25,6 @@ #include #include #include -#include using namespace Core; using namespace Utils; @@ -43,10 +42,21 @@ public: QString id() const { return recurseSubmodules ? ref + ".Rec" : ref; } }; +static QStringView nextLine(QStringView *remainingInput) +{ + const int newLinePos = remainingInput->indexOf('\n'); + if (newLinePos < 0) { + QStringView ret = *remainingInput; + *remainingInput = QStringView(); + return ret; + } + QStringView ret = remainingInput->left(newLinePos); + *remainingInput = remainingInput->mid(newLinePos + 1); + return ret; +} + class GitGrepRunner { - using PromiseType = QPromise; - public: GitGrepRunner(const TextEditor::FileFindParameters ¶meters) : m_parameters(parameters) @@ -54,6 +64,14 @@ public: m_directory = FilePath::fromString(parameters.additionalParameters.toString()); m_vcsBinary = GitClient::instance()->vcsBinary(); m_environment = GitClient::instance()->processEnvironment(); + if (m_parameters.flags & FindRegularExpression) { + const QRegularExpression::PatternOptions patternOptions + = m_parameters.flags & FindCaseSensitively + ? QRegularExpression::NoPatternOption + : QRegularExpression::CaseInsensitiveOption; + m_regexp.setPattern(m_parameters.text); + m_regexp.setPatternOptions(patternOptions); + } } struct Match @@ -67,7 +85,7 @@ public: QStringList regexpCapturedTexts; }; - void processLine(const QString &line, SearchResultItems *resultList) const + void processLine(QStringView line, SearchResultItems *resultList) const { if (line.isEmpty()) return; @@ -75,23 +93,15 @@ public: static const QLatin1String resetColor("\x1b[m"); SearchResultItem result; const int lineSeparator = line.indexOf(QChar::Null); - QString filePath = line.left(lineSeparator); + QStringView filePath = line.left(lineSeparator); if (!m_ref.isEmpty() && filePath.startsWith(m_ref)) - filePath.remove(0, m_ref.length()); - result.setFilePath(m_directory.pathAppended(filePath)); + filePath = filePath.mid(m_ref.length()); + result.setFilePath(m_directory.pathAppended(filePath.toString())); const int textSeparator = line.indexOf(QChar::Null, lineSeparator + 1); const int lineNumber = line.mid(lineSeparator + 1, textSeparator - lineSeparator - 1).toInt(); - QString text = line.mid(textSeparator + 1); - QRegularExpression regexp; + QString text = line.mid(textSeparator + 1).toString(); QList matches; - if (m_parameters.flags & FindRegularExpression) { - const QRegularExpression::PatternOptions patternOptions = - (m_parameters.flags & FindCaseSensitively) - ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption; - regexp.setPattern(m_parameters.text); - regexp.setPatternOptions(patternOptions); - } - for (;;) { + while (true) { const int matchStart = text.indexOf(boldRed); if (matchStart == -1) break; @@ -102,7 +112,7 @@ public: Match match(matchStart, matchLength); const QString matchText = text.mid(matchTextStart, matchLength); if (m_parameters.flags & FindRegularExpression) - match.regexpCapturedTexts = regexp.match(matchText).capturedTexts(); + match.regexpCapturedTexts = m_regexp.match(matchText).capturedTexts(); matches.append(match); text = text.left(matchStart) + matchText + text.mid(matchEnd + resetColor.size()); } @@ -116,18 +126,28 @@ public: } } - void read(PromiseType &fi, const QString &text) + void read(QPromise &promise, const QString &input) { - SearchResultItems resultList; - QString t = text; - QTextStream stream(&t); - while (!stream.atEnd() && !fi.isCanceled()) - processLine(stream.readLine(), &resultList); - if (!resultList.isEmpty() && !fi.isCanceled()) - fi.addResult(resultList); + SearchResultItems items; + QStringView remainingInput(input); + while (true) { + if (promise.isCanceled()) + return; + + if (remainingInput.isEmpty()) + break; + + const QStringView line = nextLine(&remainingInput); + if (line.isEmpty()) + continue; + + processLine(line, &items); + } + if (!items.isEmpty()) + promise.addResult(items); } - void operator()(PromiseType &promise) + void operator()(QPromise &promise) { QStringList arguments = { "-c", "color.grep.match=bold red", @@ -189,6 +209,7 @@ private: QString m_ref; TextEditor::FileFindParameters m_parameters; Environment m_environment; + QRegularExpression m_regexp; }; static bool isGitDirectory(const FilePath &path) From 22f8b8f1abb70211727839d89b4282b4c19a0ab5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 1 Jun 2023 13:35:22 +0200 Subject: [PATCH 1426/1447] SquishTests: Adapt to ui change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Enable QML check box is nowadays a combo box. Change-Id: I87d94892ac02ea16d18bf78999f17065e02c5ac6 Reviewed-by: Robert Löhning --- tests/system/objects.map | 2 ++ tests/system/shared/debugger.py | 3 +-- tests/system/suite_debugger/tst_qml_js_console/test.py | 3 +-- tests/system/suite_debugger/tst_qml_locals/test.py | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/system/objects.map b/tests/system/objects.map index 883bfd02af4..97d44b7ed26 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -62,6 +62,8 @@ :Dialog.componentNameEdit_QLineEdit {name='componentNameEdit' type='Utils::ClassNameValidatingLineEdit' visible='1' window=':Dialog_QmlJSEditor::Internal::ComponentNameDialog'} :Dialog_Debugger::Internal::SymbolPathsDialog {name='Debugger__Internal__SymbolPathsDialog' type='Debugger::Internal::SymbolPathsDialog' visible='1' windowTitle='Dialog'} :Dialog_QmlJSEditor::Internal::ComponentNameDialog {type='QmlJSEditor::Internal::ComponentNameDialog' unnamed='1' visible='1' windowTitle='Move Component into Separate File'} +:EnableQMLDebugger_ComboBox {buddy=':EnableQMLDebugger_Label' type='QComboBox' unnamed='1' visible='1'} +:EnableQMLDebugger_Label {text='QML debugger:' type='QLabel' window=':Qt Creator_Core::Internal::MainWindow'} :Events.QmlProfilerEventsTable_QmlProfiler::Internal::QmlProfilerStatisticsMainView {container=':Qt Creator.Events_QDockWidget' name='QmlProfilerEventsTable' type='QmlProfiler::Internal::QmlProfilerStatisticsMainView' visible='1'} :Failed to start application_QMessageBox {type='QMessageBox' unnamed='1' visible='1' windowTitle='Failed to start application'} :File has been removed.Close_QPushButton {text='Close' type='QPushButton' unnamed='1' visible='1' window=':File has been removed_QMessageBox'} diff --git a/tests/system/shared/debugger.py b/tests/system/shared/debugger.py index 424785b3a37..7176afc8e59 100644 --- a/tests/system/shared/debugger.py +++ b/tests/system/shared/debugger.py @@ -113,8 +113,7 @@ def doSimpleDebugging(currentKit, currentConfigName, expectedBPOrder=[], enableQ expectedLabelTexts.append("Running\.") switchViewTo(ViewConstants.PROJECTS) switchToBuildOrRunSettingsFor(currentKit, ProjectSettings.RUN) - ensureChecked(waitForObject("{container=':Qt Creator_Core::Internal::MainWindow' text='Enable QML' " - "type='QCheckBox' unnamed='1' visible='1'}"), enableQml) + selectFromCombo(":EnableQMLDebugger_ComboBox", "Enabled" if enableQml else "Disabled") switchViewTo(ViewConstants.EDIT) if not __startDebugger__(currentKit, currentConfigName): return False diff --git a/tests/system/suite_debugger/tst_qml_js_console/test.py b/tests/system/suite_debugger/tst_qml_js_console/test.py index 6580e4988a4..4760296cf69 100644 --- a/tests/system/suite_debugger/tst_qml_js_console/test.py +++ b/tests/system/suite_debugger/tst_qml_js_console/test.py @@ -114,8 +114,7 @@ def main(): # make sure QML Debugging is enabled switchViewTo(ViewConstants.PROJECTS) switchToBuildOrRunSettingsFor(Targets.getDefaultKit(), ProjectSettings.RUN) - ensureChecked("{container=':Qt Creator.scrollArea_QScrollArea' text='Enable QML' " - "type='QCheckBox' unnamed='1' visible='1'}") + selectFromCombo(":EnableQMLDebugger_ComboBox", "Enabled") switchViewTo(ViewConstants.EDIT) # start debugging clickButton(fancyDebugButton) diff --git a/tests/system/suite_debugger/tst_qml_locals/test.py b/tests/system/suite_debugger/tst_qml_locals/test.py index 70256ee2d44..37ecb515cc6 100644 --- a/tests/system/suite_debugger/tst_qml_locals/test.py +++ b/tests/system/suite_debugger/tst_qml_locals/test.py @@ -35,8 +35,7 @@ def main(): return switchViewTo(ViewConstants.PROJECTS) switchToBuildOrRunSettingsFor(Targets.getDefaultKit(), ProjectSettings.RUN) - ensureChecked("{container=':Qt Creator_Core::Internal::MainWindow' text='Enable QML' " - "type='QCheckBox' unnamed='1' visible='1'}") + selectFromCombo(":EnableQMLDebugger_ComboBox", "Enabled") switchViewTo(ViewConstants.EDIT) clickButton(fancyDebugButton) locAndExprTV = waitForObject(":Locals and Expressions_Debugger::Internal::WatchTreeView") From b0d5e41e53d2de7a9c48a33182b44bed1667ebff Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 1 Jun 2023 14:33:01 +0200 Subject: [PATCH 1427/1447] SquishTests: Fix selecting of Qt Quick version on wizard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I96ac34323e52507b26f7936499dade9203529315 Reviewed-by: Robert Löhning --- tests/system/shared/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 2e541ddf920..6702144ea8c 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -128,7 +128,7 @@ def __createProjectHandleQtQuickSelection__(minimumQtVersion): comboBox = waitForObject("{name?='*QtVersion' type='QComboBox' visible='1'" " window=':New_ProjectExplorer::JsonWizard'}") try: - selectFromCombo(comboBox, minimumQtVersion) + selectFromCombo(comboBox, "Qt " + minimumQtVersion) except: t,v = sys.exc_info()[:2] test.fatal("Exception while trying to select Qt version", "%s: %s" % (t.__name__, str(v))) From 270972c7bb6b5936fc5a7b73107325581fbaa67c Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 1 Jun 2023 14:42:15 +0200 Subject: [PATCH 1428/1447] ClangCodeModel: report highlight results in one batch again ... with Qt 6.6 Change-Id: Ic3ebb5cee4deeebf87a0d8e0ab33bcdc1c92c3a2 Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/clangcodemodel/clangdsemantichighlighting.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp index 04bcc08fa2d..e1b82ab3770 100644 --- a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp +++ b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp @@ -421,8 +421,12 @@ void doSemanticHighlighting( if (ClangdClient * const client = ClangModelManagerSupport::clientForFile(filePath)) client->setVirtualRanges(filePath, virtualRanges, docRevision); }, Qt::QueuedConnection); +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + promise.addResults(results); +#else for (const HighlightingResult &r : results) promise.addResult(r); +#endif } } From f146bebbc7091d8e0f9b637bd5ca23f3ca45df7c Mon Sep 17 00:00:00 2001 From: Yasser Grimes Date: Wed, 31 May 2023 16:44:41 +0300 Subject: [PATCH 1429/1447] McuSupport: Simplify template integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To simplify how users integrate their projects with Qul, Qul related template files are placed under the "qmlproject" subfolder. Task-number: QTCREATORBUG-29114 Change-Id: I984f1619547951e0518790c843987f03b7daa62a Reviewed-by: Alessandro Portale Reviewed-by: Sivert Krøvel Reviewed-by: --- src/plugins/mcusupport/mcusupport.qrc | 1 + .../wizards/qmlproject/CMakeLists.txt | 3 +-- .../mcusupport/wizards/qmlproject/Qul.cmake | 3 +++ .../mcusupport/wizards/qmlproject/wizard.json | 24 ++++++++++++------- 4 files changed, 20 insertions(+), 11 deletions(-) create mode 100644 src/plugins/mcusupport/wizards/qmlproject/Qul.cmake diff --git a/src/plugins/mcusupport/mcusupport.qrc b/src/plugins/mcusupport/mcusupport.qrc index abbfb969e3a..7aeb7b93873 100644 --- a/src/plugins/mcusupport/mcusupport.qrc +++ b/src/plugins/mcusupport/mcusupport.qrc @@ -20,5 +20,6 @@ wizards/qmlproject/module.qmlproject.tpl wizards/qmlproject/component.qml.tpl wizards/qmlproject/wizard.json + wizards/qmlproject/Qul.cmake diff --git a/src/plugins/mcusupport/wizards/qmlproject/CMakeLists.txt b/src/plugins/mcusupport/wizards/qmlproject/CMakeLists.txt index 49a4a8f949f..47eed40c785 100644 --- a/src/plugins/mcusupport/wizards/qmlproject/CMakeLists.txt +++ b/src/plugins/mcusupport/wizards/qmlproject/CMakeLists.txt @@ -4,5 +4,4 @@ project(%{CorrectedProjectName} VERSION 0.0.1 LANGUAGES C CXX ASM) find_package(Qul) -qul_add_target(%{CorrectedProjectName} QML_PROJECT %{QmlProjectFile} GENERATE_ENTRYPOINT) -app_target_setup_os(%{CorrectedProjectName}) +add_subdirectory(qmlproject) diff --git a/src/plugins/mcusupport/wizards/qmlproject/Qul.cmake b/src/plugins/mcusupport/wizards/qmlproject/Qul.cmake new file mode 100644 index 00000000000..1ece8f48d6d --- /dev/null +++ b/src/plugins/mcusupport/wizards/qmlproject/Qul.cmake @@ -0,0 +1,3 @@ + +qul_add_target(%{CorrectedProjectName} QML_PROJECT %{QmlProjectFile} GENERATE_ENTRYPOINT) +app_target_setup_os(%{CorrectedProjectName}) diff --git a/src/plugins/mcusupport/wizards/qmlproject/wizard.json b/src/plugins/mcusupport/wizards/qmlproject/wizard.json index 4fcf4f6fd31..9c1e036e910 100644 --- a/src/plugins/mcusupport/wizards/qmlproject/wizard.json +++ b/src/plugins/mcusupport/wizards/qmlproject/wizard.json @@ -12,6 +12,7 @@ "options": [ + { "key": "QmlProjectDirectory", "value": "%{ProjectDirectory}/qmlproject"}, { "key": "CorrectedProjectName", "value": "%{JS: '%{ProjectName}'.replace(/-/g, '_')}"}, { "key": "MainQmlFile", "value": "%{CorrectedProjectName}.qml" }, { "key": "QmlProjectFile", "value": "%{CorrectedProjectName}.qmlproject" }, @@ -55,49 +56,54 @@ "source": "CMakeLists.txt", "openAsProject": true }, + { + "source": "Qul.cmake", + "target": "%{QmlProjectDirectory}/CMakeLists.txt", + "openInEditor": false + }, { "source": "BackendObject.h", - "target": "%{ProjectDirectory}/src/%{InterfaceFile}", + "target": "%{QmlProjectDirectory}/src/%{InterfaceFile}", "openInEditor": true }, { "source": "component.qml.tpl", - "target": "%{ProjectDirectory}/imports/CustomModule/%{QmlComponent}", + "target": "%{QmlProjectDirectory}/imports/CustomModule/%{QmlComponent}", "openInEditor": true }, { "source": "module.qmlproject.tpl", - "target": "%{ProjectDirectory}/imports/CustomModule/%{ModuleFile}", + "target": "%{QmlProjectDirectory}/imports/CustomModule/%{ModuleFile}", "openInEditor": true }, { "source": "project.qmlproject.tpl", - "target": "%{ProjectDirectory}/%{QmlProjectFile}", + "target": "%{QmlProjectDirectory}/%{QmlProjectFile}", "openInEditor": true }, { "source": "main.qml.tpl", - "target": "%{ProjectDirectory}/%{MainQmlFile}", + "target": "%{QmlProjectDirectory}/%{MainQmlFile}", "openInEditor": true }, { "source": "../icon.png", - "target": "%{ProjectDirectory}/images/icon.png", + "target": "%{QmlProjectDirectory}/images/icon.png", "isBinary": true }, { "source": "DejaVuSansMono.ttf", - "target": "%{ProjectDirectory}/fonts/DejaVuSansMono.ttf", + "target": "%{QmlProjectDirectory}/fonts/DejaVuSansMono.ttf", "isBinary": true }, { "source": "LICENSE", - "target": "%{ProjectDirectory}/fonts/LICENSE", + "target": "%{QmlProjectDirectory}/fonts/LICENSE", "isBinary": true }, { "source": "translation.nb_NO.ts", - "target": "%{ProjectDirectory}/translations/%{TsFile}", + "target": "%{QmlProjectDirectory}/translations/%{TsFile}", "openInEditor": false }, { From 68a5cd65751ebbdfeb747916099a28e33b884b6e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 31 May 2023 12:12:22 +0200 Subject: [PATCH 1430/1447] LanguageClient: postpone creating progressbars Some language servers are spawning progress reports for many small tasks. This can get distracting in the case where those progress bars are spawned while typing, like in the case of the python language server that creates a report for every lint that gets triggered after receiving a document change notification. So in order to reduce the amount of progress bars created from progress reports we postpone the creation of the bars. Fixes: QTCREATORBUG-29224 Change-Id: I2e658be0a26b21e41c80b444184648ba70682522 Reviewed-by: Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Christian Stenger --- .../languageclient/progressmanager.cpp | 52 ++++++++++++++----- src/plugins/languageclient/progressmanager.h | 15 ++++-- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/plugins/languageclient/progressmanager.cpp b/src/plugins/languageclient/progressmanager.cpp index 285080e4980..6b82d289dfc 100644 --- a/src/plugins/languageclient/progressmanager.cpp +++ b/src/plugins/languageclient/progressmanager.cpp @@ -8,6 +8,7 @@ #include #include +#include using namespace LanguageServerProtocol; @@ -81,9 +82,28 @@ void ProgressManager::beginProgress(const ProgressToken &token, const WorkDonePr auto interface = new QFutureInterface(); interface->reportStarted(); interface->setProgressRange(0, 100); // LSP always reports percentage of the task - const QString title = m_titles.value(token, begin.title()); - Core::FutureProgress *progress = Core::ProgressManager::addTask( - interface->future(), title, languageClientProgressId(token)); + ProgressItem progressItem; + progressItem.futureInterface = interface; + progressItem.title = m_titles.value(token, begin.title()); + if (LOGPROGRESS().isDebugEnabled()) + progressItem.timer.start(); + progressItem.showBarTimer = new QTimer(); + progressItem.showBarTimer->setSingleShot(true); + progressItem.showBarTimer->setInterval(750); + progressItem.showBarTimer->callOnTimeout([this, token]() { spawnProgressBar(token); }); + progressItem.showBarTimer->start(); + m_progress[token] = progressItem; + reportProgress(token, begin); +} + +void ProgressManager::spawnProgressBar(const LanguageServerProtocol::ProgressToken &token) +{ + ProgressItem &progressItem = m_progress[token]; + QTC_ASSERT(progressItem.futureInterface, return); + Core::FutureProgress *progress + = Core::ProgressManager::addTask(progressItem.futureInterface->future(), + progressItem.title, + languageClientProgressId(token)); const std::function clickHandler = m_clickHandlers.value(token); if (clickHandler) QObject::connect(progress, &Core::FutureProgress::clicked, clickHandler); @@ -92,23 +112,26 @@ void ProgressManager::beginProgress(const ProgressToken &token, const WorkDonePr QObject::connect(progress, &Core::FutureProgress::canceled, cancelHandler); else progress->setCancelEnabled(false); - m_progress[token] = {progress, interface}; - if (LOGPROGRESS().isDebugEnabled()) - m_timer[token].start(); - reportProgress(token, begin); + if (!progressItem.message.isEmpty()) { + progress->setSubtitle(progressItem.message); + progress->setSubtitleVisibleInStatusBar(true); + } + progressItem.progressInterface = progress; } void ProgressManager::reportProgress(const ProgressToken &token, const WorkDoneProgressReport &report) { - const LanguageClientProgress &progress = m_progress.value(token); + ProgressItem &progress = m_progress[token]; + const std::optional &message = report.message(); if (progress.progressInterface) { - const std::optional &message = report.message(); if (message.has_value()) { progress.progressInterface->setSubtitle(*message); const bool showSubtitle = !message->isEmpty(); progress.progressInterface->setSubtitleVisibleInStatusBar(showSubtitle); } + } else if (message.has_value()) { + progress.message = *message; } if (progress.futureInterface) { if (const std::optional &percentage = report.percentage(); percentage.has_value()) @@ -118,7 +141,7 @@ void ProgressManager::reportProgress(const ProgressToken &token, void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProgressEnd &end) { - const LanguageClientProgress &progress = m_progress.value(token); + const ProgressItem &progress = m_progress.value(token); const QString &message = end.message().value_or(QString()); if (progress.progressInterface) { if (!message.isEmpty()) { @@ -127,11 +150,11 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg } progress.progressInterface->setSubtitle(message); progress.progressInterface->setSubtitleVisibleInStatusBar(!message.isEmpty()); - auto timer = m_timer.take(token); - if (timer.isValid()) { + if (progress.timer.isValid()) { qCDebug(LOGPROGRESS) << QString("%1 took %2") .arg(progress.progressInterface->title()) - .arg(QTime::fromMSecsSinceStartOfDay(timer.elapsed()) + .arg(QTime::fromMSecsSinceStartOfDay( + progress.timer.elapsed()) .toString(Qt::ISODateWithMs)); } } @@ -140,7 +163,8 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg void ProgressManager::endProgressReport(const ProgressToken &token) { - const LanguageClientProgress &progress = m_progress.take(token); + ProgressItem progress = m_progress.take(token); + delete progress.showBarTimer; if (progress.futureInterface) progress.futureInterface->reportFinished(); delete progress.futureInterface; diff --git a/src/plugins/languageclient/progressmanager.h b/src/plugins/languageclient/progressmanager.h index 1e0ad781806..05b9640745d 100644 --- a/src/plugins/languageclient/progressmanager.h +++ b/src/plugins/languageclient/progressmanager.h @@ -11,6 +11,10 @@ #include #include +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE + namespace LanguageServerProtocol { class ProgressParams; class ProgressToken; @@ -46,15 +50,20 @@ private: const LanguageServerProtocol::WorkDoneProgressReport &report); void endProgress(const LanguageServerProtocol::ProgressToken &token, const LanguageServerProtocol::WorkDoneProgressEnd &end); + void spawnProgressBar(const LanguageServerProtocol::ProgressToken &token); - struct LanguageClientProgress { + struct ProgressItem + { QPointer progressInterface = nullptr; QFutureInterface *futureInterface = nullptr; + QElapsedTimer timer; + QTimer *showBarTimer = nullptr; + QString message; + QString title; }; - QMap m_progress; + QMap m_progress; QMap m_titles; - QMap m_timer; QMap> m_clickHandlers; QMap> m_cancelHandlers; }; From d65273aee39f33070200c4cf453e7d044d854470 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 2 Jun 2023 10:14:35 +0200 Subject: [PATCH 1431/1447] Update qbs submodule to HEAD of 2.1 branch Change-Id: I3d670f8192f79806161fd7871fa9e5ff8c398f22 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index eaeba4a45e7..43af7ba7fa1 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit eaeba4a45e7d95b7bb3f4fe907e862d947faf092 +Subproject commit 43af7ba7fa12de25268d2cc5582b963e360022e5 From 37b30dc7a28b2efae8a55e9ade13473caf13c26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Wed, 17 May 2023 19:06:11 +0200 Subject: [PATCH 1432/1447] SquishTests: Remove workaround for fixed inconsistency Task-number: QTCREATORBUG-29126 Change-Id: I2a84e606249d5ca7f68d7a73d819eee3f341216d Reviewed-by: Reviewed-by: Christian Stenger --- .../suite_general/tst_create_proj_wizard/test.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) 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 643e8054fa1..dd261780646 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -54,18 +54,15 @@ def main(): with TestSection("Testing project template %s -> %s" % (category, template)): displayedPlatforms = __createProject__(category, template) if template.startswith("Qt Quick Application"): - if "(compat)" in template: # QTCREATORBUG-29126 - qtVersionsForQuick = ["Qt 5.14", "Qt 6.2"] - else: - qtVersionsForQuick = ["6.2"] + qtVersionsForQuick = ["6.2"] + if "(compat)" in template: + qtVersionsForQuick += ["5.14"] for counter, qtVersion in enumerate(qtVersionsForQuick): + def additionalFunc(displayedPlatforms, qtVersion): requiredQtVersion = __createProjectHandleQtQuickSelection__(qtVersion) - if sys.version_info.major > 2: - requiredQtVersion = requiredQtVersion.removeprefix("Qt ") - else: - requiredQtVersion = requiredQtVersion.lstrip("Qt ") __modifyAvailableTargets__(displayedPlatforms, requiredQtVersion, True) + handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms, additionalFunc, qtVersion) # are there more Quick combinations - then recreate this project From 83c837049db79e3047e7fe9c3bfbc7a0d9bd6302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Thu, 1 Jun 2023 16:43:09 +0200 Subject: [PATCH 1433/1447] SquishTests: Make number of results constant in verifyKitCheckboxes() Before the change, we got zero results in the expected case or up to two fails on error. Change-Id: I6583844eb5473cad8190acc91db1207933dc6630 Reviewed-by: Christian Stenger --- .../suite_general/tst_create_proj_wizard/test.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 dd261780646..8579111b02c 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -87,13 +87,15 @@ def verifyKitCheckboxes(kits, displayedPlatforms): unexpectedShownKits = availableCheckboxes.difference(displayedPlatforms) missingKits = displayedPlatforms.difference(availableCheckboxes) - test.log("Expected kits shown on 'Kit Selection' page:\n%s" % "\n".join(expectedShownKits)) - if len(unexpectedShownKits): - test.fail("Kits found on 'Kit Selection' page but not expected:\n%s" - % "\n".join(unexpectedShownKits)) - if len(missingKits): - test.fail("Expected kits missing on 'Kit Selection' page:\n%s" - % "\n".join(missingKits)) + if not test.verify(len(unexpectedShownKits) == 0 and len(missingKits) == 0, + "No missing or unexpected kits found on 'Kit Selection' page?\n" + "Found expected kits:\n%s" % "\n".join(expectedShownKits)): + if len(unexpectedShownKits): + test.log("Kits found on 'Kit Selection' page but not expected:\n%s" + % "\n".join(unexpectedShownKits)) + if len(missingKits): + test.log("Expected kits missing on 'Kit Selection' page:\n%s" + % "\n".join(missingKits)) def handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms, specialHandlingFunc = None, *args): From d9e3d32a80497fbef98073b06f1eaf9bf5811587 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 1 Jun 2023 15:26:34 +0200 Subject: [PATCH 1434/1447] MarkdownEditor: Ensure focus is inside the editor part When loading a file it is more likely that the editable view of the document should be focused than the read only part. Change-Id: I8b7ed40a233dedf94883072be7462ebeabb78b42 Reviewed-by: Eike Ziller --- src/plugins/texteditor/markdowneditor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp index 12e60f027af..9c89636df8e 100644 --- a/src/plugins/texteditor/markdowneditor.cpp +++ b/src/plugins/texteditor/markdowneditor.cpp @@ -245,6 +245,8 @@ public: if (obj == m_widget && ev->type() == QEvent::FocusIn) { if (m_splitter->focusWidget()) m_splitter->focusWidget()->setFocus(); + else if (m_textEditorWidget->isVisible()) + m_textEditorWidget->setFocus(); else m_splitter->widget(0)->setFocus(); return true; From de104fad12302f633be866b89487adfaeaa1b088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Thu, 1 Jun 2023 17:31:15 +0200 Subject: [PATCH 1435/1447] SquishTests: Don't try changing build system of Quick Apps They can use CMake only. Change-Id: Ibbce50290597594a98ae08d9dd7ab171137c2b7c Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/shared/project.py | 7 ++++++- tests/system/suite_APTW/tst_APTW02/test.py | 2 +- tests/system/suite_general/tst_save_before_build/test.py | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 6702144ea8c..d1e44102bcc 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -277,7 +277,12 @@ def createNewQtQuickApplication(workingDir, projectName=None, buildSystem=None): available = __createProjectOrFileSelectType__(" Application (Qt)", template, fromWelcome) projectName = __createProjectSetNameAndPath__(workingDir, projectName) - __handleBuildSystem__(buildSystem) + if template == "Qt Quick Application": + if buildSystem: + test.warning("Build system set explicitly for a template which can't change it.", + "Template: %s, Build System: %s" % (template, buildSystem)) + else: + __handleBuildSystem__(buildSystem) requiredQt = __createProjectHandleQtQuickSelection__(minimumQtVersion) __modifyAvailableTargets__(available, requiredQt) checkedTargets = __chooseTargets__(targets, available) diff --git a/tests/system/suite_APTW/tst_APTW02/test.py b/tests/system/suite_APTW/tst_APTW02/test.py index 716145a6401..0a5ff2bd72e 100644 --- a/tests/system/suite_APTW/tst_APTW02/test.py +++ b/tests/system/suite_APTW/tst_APTW02/test.py @@ -8,7 +8,7 @@ def main(): startQC() if not startedWithoutPluginError(): return - createNewQtQuickApplication(tempDir(), "SampleApp", buildSystem="qmake") + createNewQtQuickApplication(tempDir(), "SampleApp") # run project for debug and release and verify results runVerify() #close Qt Creator diff --git a/tests/system/suite_general/tst_save_before_build/test.py b/tests/system/suite_general/tst_save_before_build/test.py index d6b9b5f8574..87c2d56d39a 100644 --- a/tests/system/suite_general/tst_save_before_build/test.py +++ b/tests/system/suite_general/tst_save_before_build/test.py @@ -29,7 +29,7 @@ def main(): if not startedWithoutPluginError(): return verifySaveBeforeBuildChecked(False) - for buildSystem in ["CMake", "Qbs"]: + for buildSystem in ["CMake"]: projectName = "SampleApp-" + buildSystem ensureSaveBeforeBuildChecked(False) # create qt quick application From a9720c118313913f82f90738e64620bd0aa5e857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Fri, 26 May 2023 01:48:45 +0200 Subject: [PATCH 1436/1447] SquishTests: Don't generate tasks with empty description Creator ignores them anyway. Task-number: QTCREATORBUG-29209 Change-Id: I0ab2f96d55547ccf3112b18886518a065b19052a Reviewed-by: Reviewed-by: Christian Stenger --- tests/system/suite_general/tst_tasks_handling/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/suite_general/tst_tasks_handling/test.py b/tests/system/suite_general/tst_tasks_handling/test.py index 8c6e2395583..865d22a2485 100644 --- a/tests/system/suite_general/tst_tasks_handling/test.py +++ b/tests/system/suite_general/tst_tasks_handling/test.py @@ -31,7 +31,7 @@ def generateRandomTaskType(): return 2 def generateMockTasksFile(): - descriptions = ["", "dummy information", "unknown error", "not found", "syntax error", + descriptions = ["dummy information", "unknown error", "not found", "syntax error", "missing information", "unused"] tasks = ["warn", "error", "other"] isWin = platform.system() in ('Microsoft', 'Windows') @@ -44,7 +44,7 @@ def generateMockTasksFile(): tasksType = generateRandomTaskType() tasksCount[tasksType] += 1 tData = tasks[tasksType] - dData = descriptions[random.randint(0, 6)] + dData = descriptions[random.randint(0, len(descriptions) - 1)] tFile.write("%s\t%d\t%s\t%s\n" % (fData, lData, tData, dData)) tFile.close() test.log("Wrote tasks file with %d warnings, %d errors and %d other tasks." % tuple(tasksCount)) From 04c2a32fc06a53e66f341c5a748a1ba98f192612 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 31 May 2023 11:36:38 +0200 Subject: [PATCH 1437/1447] ExamplesParser: Export only for tests Makes binary compatible changes easier later, if needed Change-Id: Ib3e04ac3a26068cf9f8bcc57b2dad9d0aeaaa5c3 Reviewed-by: Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/plugins/qtsupport/examplesparser.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/qtsupport/examplesparser.h b/src/plugins/qtsupport/examplesparser.h index bfe65721c22..54efaf58875 100644 --- a/src/plugins/qtsupport/examplesparser.h +++ b/src/plugins/qtsupport/examplesparser.h @@ -13,7 +13,7 @@ namespace QtSupport::Internal { enum InstructionalType { Example = 0, Demo, Tutorial }; -class QTSUPPORT_EXPORT ExampleItem : public Core::ListItem +class QTSUPPORT_TEST_EXPORT ExampleItem : public Core::ListItem { public: Utils::FilePath projectPath; @@ -31,13 +31,13 @@ public: QHash metaData; }; -QTSUPPORT_EXPORT Utils::expected_str> parseExamples( +QTSUPPORT_TEST_EXPORT Utils::expected_str> parseExamples( const Utils::FilePath &manifest, const Utils::FilePath &examplesInstallPath, const Utils::FilePath &demosInstallPath, bool examples); -QTSUPPORT_EXPORT Utils::expected_str> parseExamples( +QTSUPPORT_TEST_EXPORT Utils::expected_str> parseExamples( const QByteArray &manifestData, const Utils::FilePath &manifestPath, const Utils::FilePath &examplesInstallPath, From a5dfbe01d59cf1756a2bbeb7870fe994f1527a0a Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 1 Jun 2023 12:58:46 +0300 Subject: [PATCH 1438/1447] Utils: Support hardlink detection also on Windows Change-Id: I717899ef73e965438ecd28983397ffc90a7ff570 Reviewed-by: David Schulz Reviewed-by: Qt CI Patch Build Bot --- src/libs/utils/devicefileaccess.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index f5bb1d20482..bd139d9b168 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -493,6 +493,20 @@ bool DesktopDeviceFileAccess::hasHardLinks(const FilePath &filePath) const if (s.st_nlink > 1) return true; } +#elif defined(Q_OS_WIN) + const HANDLE handle = CreateFile((wchar_t *) filePath.toUserOutput().utf16(), + 0, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) + return false; + + FILE_STANDARD_INFO info; + if (GetFileInformationByHandleEx(handle, FileStandardInfo, &info, sizeof(info))) + return info.NumberOfLinks > 1; #else Q_UNUSED(filePath) #endif From 7a42c327320a6232ab8cb1ff280f20262cd56c7b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 18:59:53 +0200 Subject: [PATCH 1439/1447] SilverSearcher: Fix quitting the loop after resume Quit the loop after resuming when the process already finished. Amends cd70d10dce8993d9923619aa4582b5c84a46b12e Change-Id: I73d4b11bb2be47ce9cc6c6c816b60058bc2db250 Reviewed-by: Reviewed-by: Orgad Shaneh Reviewed-by: Qt CI Bot --- src/plugins/silversearcher/findinfilessilversearcher.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index 7d9e5f1e141..313d23eda27 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -162,6 +162,8 @@ static void runSilverSeacher(QPromise &promise, SilverSearcher::parse(promise, output, &parserState, regExp); } outputBuffer.clear(); + if (process.state() == QProcess::NotRunning) + loop.quit(); }); watcher.setFuture(future); loop.exec(QEventLoop::ExcludeUserInputEvents); From 7b2c1fdab072d409eb6a0be5a28a1bded9dced22 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 18:59:53 +0200 Subject: [PATCH 1440/1447] GitGrep: Make pause and continue working Make cancel and continue button working. Make pausing above 200000 hits working. Applied the same pattern as it was done recently inside SilverSearcher: cd70d10dce8993d9923619aa4582b5c84a46b12e. Change-Id: I5e466e2176a59301dbfd3f957012e1760bd0c20f Reviewed-by: Qt CI Bot Reviewed-by: Orgad Shaneh --- src/plugins/git/gitgrep.cpp | 75 ++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 24990008cb5..fdb0f202e25 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -126,13 +126,13 @@ public: } } - void read(QPromise &promise, const QString &input) + int read(QPromise &promise, const QString &input) { SearchResultItems items; QStringView remainingInput(input); while (true) { if (promise.isCanceled()) - return; + return 0; if (remainingInput.isEmpty()) break; @@ -145,6 +145,7 @@ public: } if (!items.isEmpty()) promise.addResult(items); + return items.count(); } void operator()(QPromise &promise) @@ -181,26 +182,66 @@ public: }); arguments << "--" << filterArgs << exclusionArgs; + QEventLoop loop; + Process process; process.setEnvironment(m_environment); process.setCommand({m_vcsBinary, arguments}); process.setWorkingDirectory(m_directory); - process.setStdOutCallback([this, &promise](const QString &text) { read(promise, text); }); - process.start(); - process.waitForFinished(); + QStringList outputBuffer; + // The states transition exactly in this order: + enum State { BelowLimit, AboveLimit, Paused, Resumed }; + State state = BelowLimit; + int reportedResultsCount = 0; + process.setStdOutCallback([this, &process, &loop, &promise, &state, &reportedResultsCount, + &outputBuffer](const QString &output) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + return; + } + // The SearchResultWidget is going to pause the search anyway, so start buffering + // the output. + if (state == AboveLimit || state == Paused) { + outputBuffer.append(output); + } else { + reportedResultsCount += read(promise, output); + if (state == BelowLimit && reportedResultsCount > 200000) + state = AboveLimit; + } + }); + QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] { + if (state == BelowLimit || state == Resumed || promise.isCanceled()) + loop.quit(); + }); - switch (process.result()) { - case ProcessResult::TerminatedAbnormally: - case ProcessResult::StartFailed: - case ProcessResult::Hang: - promise.future().cancel(); - break; - case ProcessResult::FinishedWithSuccess: - case ProcessResult::FinishedWithError: - // When no results are found, git-grep exits with non-zero status. - // Do not consider this as an error. - break; - } + process.start(); + if (process.state() == QProcess::NotRunning) + return; + + QFutureWatcher watcher; + QFuture future(promise.future()); + QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, [&process, &loop] { + process.close(); + loop.quit(); + }); + QObject::connect(&watcher, &QFutureWatcherBase::paused, &loop, [&state] { state = Paused; }); + QObject::connect(&watcher, &QFutureWatcherBase::resumed, &loop, + [this, &process, &loop, &promise, &state, &outputBuffer] { + state = Resumed; + for (const QString &output : outputBuffer) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + } + read(promise, output); + } + outputBuffer.clear(); + if (process.state() == QProcess::NotRunning) + loop.quit(); + }); + watcher.setFuture(future); + loop.exec(QEventLoop::ExcludeUserInputEvents); } private: From 8da3575d7290be5002f06a363a622fd4ba70b803 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 20:43:37 +0200 Subject: [PATCH 1441/1447] BaseFileFind: Introduce searchInProcessOutput() To be used by SilverSearcher and GitGrep. Change-Id: I16a5fa18a90e6c895658ebc9dd8fd209235e17d3 Reviewed-by: Qt CI Bot Reviewed-by: Orgad Shaneh --- src/plugins/texteditor/basefilefind.cpp | 93 +++++++++++++++++++++++++ src/plugins/texteditor/basefilefind.h | 11 +++ 2 files changed, 104 insertions(+) diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 8a75a27910c..99f37d05eac 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,98 @@ using namespace Utils; using namespace Core; namespace TextEditor { + +static std::optional regExpFromParameters(const FileFindParameters ¶meters) +{ + if (!(parameters.flags & FindRegularExpression)) + return {}; + + const QRegularExpression::PatternOptions options = parameters.flags & FindCaseSensitively + ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption; + QRegularExpression regExp; + regExp.setPattern(parameters.text); + regExp.setPatternOptions(options); + return regExp; +} + +void searchInProcessOutput(QPromise &promise, + const FileFindParameters ¶meters, + const ProcessSetupHandler &processSetupHandler, + const ProcessOutputParser &processOutputParser) +{ + if (promise.isCanceled()) + return; + + QEventLoop loop; + + Process process; + processSetupHandler(process); + + const std::optional regExp = regExpFromParameters(parameters); + QStringList outputBuffer; + // The states transition exactly in this order: + enum State { BelowLimit, AboveLimit, Paused, Resumed }; + State state = BelowLimit; + int reportedItemsCount = 0; + QFuture future(promise.future()); + process.setStdOutCallback([&](const QString &output) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + return; + } + // The SearchResultWidget is going to pause the search anyway, so start buffering + // the output. + if (state == AboveLimit || state == Paused) { + outputBuffer.append(output); + } else { + const SearchResultItems items = processOutputParser(future, output, regExp); + if (!items.isEmpty()) + promise.addResult(items); + reportedItemsCount += items.size(); + if (state == BelowLimit && reportedItemsCount > 200000) + state = AboveLimit; + } + }); + QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] { + if (state == BelowLimit || state == Resumed || promise.isCanceled()) + loop.quit(); + }); + + if (promise.isCanceled()) + return; + + process.start(); + if (process.state() == QProcess::NotRunning) + return; + + QFutureWatcher watcher; + QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, [&process, &loop] { + process.close(); + loop.quit(); + }); + QObject::connect(&watcher, &QFutureWatcherBase::paused, &loop, [&state] { state = Paused; }); + QObject::connect(&watcher, &QFutureWatcherBase::resumed, &loop, [&] { + state = Resumed; + for (const QString &output : outputBuffer) { + if (promise.isCanceled()) { + process.close(); + loop.quit(); + } + const SearchResultItems items = processOutputParser(future, output, regExp); + if (!items.isEmpty()) + promise.addResult(items); + } + outputBuffer.clear(); + if (process.state() == QProcess::NotRunning) + loop.quit(); + }); + watcher.setFuture(future); + if (promise.isCanceled()) + return; + loop.exec(QEventLoop::ExcludeUserInputEvents); +} + namespace Internal { class InternalEngine : public TextEditor::SearchEngine diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index b564b35c0c1..c8555f03deb 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -20,6 +20,7 @@ class SearchResult; namespace Utils { class FileIterator; +class Process; } namespace TextEditor { @@ -41,6 +42,16 @@ public: Core::FindFlags flags; }; +using ProcessSetupHandler = std::function; +using ProcessOutputParser = std::function &, const QString &, const std::optional &)>; + +// Call it from a non-main thread only, it's a blocking invocation. +void TEXTEDITOR_EXPORT searchInProcessOutput(QPromise &promise, + const FileFindParameters ¶meters, + const ProcessSetupHandler &processSetupHandler, + const ProcessOutputParser &processOutputParser); + class BaseFileFind; class TEXTEDITOR_EXPORT SearchEngine : public QObject From 64d209c24bb618fee5e0d4ba427d656c3b71e5ff Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 21:04:18 +0200 Subject: [PATCH 1442/1447] SilverSearcher: Reuse searchInProcessOutput() Change-Id: Ifc28a88c7bd0de94ea78c5f3eaaa2179b0aee600 Reviewed-by: Qt CI Bot Reviewed-by: Orgad Shaneh --- .../findinfilessilversearcher.cpp | 127 +++++------------- .../silversearcher/silversearcherparser.cpp | 31 ++--- .../silversearcher/silversearcherparser.h | 15 +-- 3 files changed, 48 insertions(+), 125 deletions(-) diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index 313d23eda27..6cf428bb64f 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -59,114 +59,51 @@ static bool isSilverSearcherAvailable() && silverSearcherProcess.cleanedStdOut().contains("ag version"); } -static std::optional regExpFromParameters(const FileFindParameters ¶meters) -{ - if (!(parameters.flags & FindRegularExpression)) - return {}; - - const QRegularExpression::PatternOptions patternOptions - = (parameters.flags & FindCaseSensitively) - ? QRegularExpression::NoPatternOption - : QRegularExpression::CaseInsensitiveOption; - QRegularExpression regExp; - regExp.setPattern(parameters.text); - regExp.setPatternOptions(patternOptions); - return regExp; -} - static void runSilverSeacher(QPromise &promise, const FileFindParameters ¶meters) { - const FilePath directory = FilePath::fromUserInput(parameters.additionalParameters.toString()); - QStringList arguments = {"--parallel", "--ackmate"}; + const auto setupProcess = [parameters](Process &process) { + const FilePath directory + = FilePath::fromUserInput(parameters.additionalParameters.toString()); + QStringList arguments = {"--parallel", "--ackmate"}; - if (parameters.flags & FindCaseSensitively) - arguments << "-s"; - else - arguments << "-i"; + if (parameters.flags & FindCaseSensitively) + arguments << "-s"; + else + arguments << "-i"; - if (parameters.flags & FindWholeWords) - arguments << "-w"; + if (parameters.flags & FindWholeWords) + arguments << "-w"; - if (!(parameters.flags & FindRegularExpression)) - arguments << "-Q"; + if (!(parameters.flags & FindRegularExpression)) + arguments << "-Q"; - for (const QString &filter : std::as_const(parameters.exclusionFilters)) - arguments << "--ignore" << filter; + for (const QString &filter : std::as_const(parameters.exclusionFilters)) + arguments << "--ignore" << filter; - QString nameFiltersAsRegExp; - for (const QString &filter : std::as_const(parameters.nameFilters)) - nameFiltersAsRegExp += QString("(%1)|").arg(convertWildcardToRegex(filter)); - nameFiltersAsRegExp.remove(nameFiltersAsRegExp.length() - 1, 1); + QString nameFiltersAsRegExp; + for (const QString &filter : std::as_const(parameters.nameFilters)) + nameFiltersAsRegExp += QString("(%1)|").arg(convertWildcardToRegex(filter)); + nameFiltersAsRegExp.remove(nameFiltersAsRegExp.length() - 1, 1); - arguments << "-G" << nameFiltersAsRegExp; + arguments << "-G" << nameFiltersAsRegExp; - const SilverSearcherSearchOptions params = parameters.searchEngineParameters - .value(); - if (!params.searchOptions.isEmpty()) - arguments << params.searchOptions.split(' '); + const SilverSearcherSearchOptions params = parameters.searchEngineParameters + .value(); + if (!params.searchOptions.isEmpty()) + arguments << params.searchOptions.split(' '); - arguments << "--" << parameters.text << directory.normalizedPathName().toString(); + arguments << "--" << parameters.text << directory.normalizedPathName().toString(); + process.setCommand({"ag", arguments}); + }; - QEventLoop loop; + FilePath lastFilePath; + const auto outputParser = [&lastFilePath](const QFuture &future, const QString &input, + const std::optional ®Exp) { + return SilverSearcher::parse(future, input, regExp, &lastFilePath); + }; - Process process; - process.setCommand({"ag", arguments}); - ParserState parserState; - const std::optional regExp = regExpFromParameters(parameters); - QStringList outputBuffer; - // The states transition exactly in this order: - enum State { BelowLimit, AboveLimit, Paused, Resumed }; - State state = BelowLimit; - process.setStdOutCallback([&process, &loop, &promise, &state, &outputBuffer, &parserState, - regExp](const QString &output) { - if (promise.isCanceled()) { - process.close(); - loop.quit(); - return; - } - // The SearchResultWidget is going to pause the search anyway, so start buffering - // the output. - if (state == AboveLimit || state == Paused) { - outputBuffer.append(output); - } else { - SilverSearcher::parse(promise, output, &parserState, regExp); - if (state == BelowLimit && parserState.m_reportedResultsCount > 200000) - state = AboveLimit; - } - }); - QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] { - if (state == BelowLimit || state == Resumed || promise.isCanceled()) - loop.quit(); - }); - - process.start(); - if (process.state() == QProcess::NotRunning) - return; - - QFutureWatcher watcher; - QFuture future(promise.future()); - QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, [&process, &loop] { - process.close(); - loop.quit(); - }); - QObject::connect(&watcher, &QFutureWatcherBase::paused, &loop, [&state] { state = Paused; }); - QObject::connect(&watcher, &QFutureWatcherBase::resumed, &loop, - [&process, &loop, &promise, &state, &outputBuffer, &parserState, regExp] { - state = Resumed; - for (const QString &output : outputBuffer) { - if (promise.isCanceled()) { - process.close(); - loop.quit(); - } - SilverSearcher::parse(promise, output, &parserState, regExp); - } - outputBuffer.clear(); - if (process.state() == QProcess::NotRunning) - loop.quit(); - }); - watcher.setFuture(future); - loop.exec(QEventLoop::ExcludeUserInputEvents); + TextEditor::searchInProcessOutput(promise, parameters, setupProcess, outputParser); } } // namespace diff --git a/src/plugins/silversearcher/silversearcherparser.cpp b/src/plugins/silversearcher/silversearcherparser.cpp index 9cdf5211a67..1a2f5e55e87 100644 --- a/src/plugins/silversearcher/silversearcherparser.cpp +++ b/src/plugins/silversearcher/silversearcherparser.cpp @@ -3,8 +3,6 @@ #include "silversearcherparser.h" -#include - using namespace Utils; namespace SilverSearcher { @@ -96,28 +94,28 @@ static bool parseLineHits(QStringView *remainingInput, QList> *h return true; } -void parse(QPromise &promise, const QString &input, - ParserState *parserState, const std::optional ®Exp) +SearchResultItems parse(const QFuture &future, const QString &input, + const std::optional ®Exp, FilePath *lastFilePath) { - QTC_ASSERT(parserState, return); + QTC_ASSERT(lastFilePath, return {}); SearchResultItems items; QStringView remainingInput(input); while (true) { - if (promise.isCanceled()) - return; + if (future.isCanceled()) + return {}; if (remainingInput.isEmpty()) break; const QStringView filePathLine = nextLine(&remainingInput); if (filePathLine.isEmpty()) { - parserState->m_lastFilePath = {}; // Clear the parser state + *lastFilePath = {}; // Clear the parser state continue; } if (filePathLine.startsWith(':')) - parserState->m_lastFilePath = FilePath::fromPathPart(filePathLine.mid(1)); + *lastFilePath = FilePath::fromPathPart(filePathLine.mid(1)); while (true) { QStringView hitLine = nextLine(&remainingInput); @@ -133,7 +131,7 @@ void parse(QPromise &promise, const QString &input, break; SearchResultItem item; - item.setFilePath(parserState->m_lastFilePath); + item.setFilePath(*lastFilePath); item.setDisplayText(hitLine.toString()); item.setUseTextEditorFont(true); for (const QPair &hit : hits) { @@ -145,20 +143,15 @@ void parse(QPromise &promise, const QString &input, } } } - if (!items.isEmpty()) - promise.addResult(items); - - parserState->m_reportedResultsCount += items.count(); + return items; } SearchResultItems parse(const QString &input, const std::optional ®Exp) { - QPromise promise; + QPromise promise; promise.start(); - ParserState dummy; - SilverSearcher::parse(promise, input, &dummy, regExp); - promise.finish(); - return promise.future().resultCount() ? promise.future().result() : SearchResultItems(); + FilePath dummy; + return SilverSearcher::parse(promise.future(), input, regExp, &dummy); } } // namespace SilverSearcher diff --git a/src/plugins/silversearcher/silversearcherparser.h b/src/plugins/silversearcher/silversearcherparser.h index 1cc5ccb773c..67b3e124f42 100644 --- a/src/plugins/silversearcher/silversearcherparser.h +++ b/src/plugins/silversearcher/silversearcherparser.h @@ -5,23 +5,16 @@ #include -#include +#include #include namespace Utils { class FilePath; } namespace SilverSearcher { -class ParserState -{ -public: - Utils::FilePath m_lastFilePath; - int m_reportedResultsCount = 0; -}; - -void parse(QPromise &promise, const QString &input, - ParserState *parserState = nullptr, - const std::optional ®Exp = {}); +Utils::SearchResultItems parse(const QFuture &future, const QString &input, + const std::optional ®Exp, + Utils::FilePath *lastFilePath); Utils::SearchResultItems parse(const QString &input, const std::optional ®Exp = {}); From f10581ee31ad7a9b9f2e0632fce1eeb196cd2904 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 1 Jun 2023 21:42:18 +0200 Subject: [PATCH 1443/1447] GitGrep: Reuse searchInProcessOutput() Change-Id: I5e97f23c0e2a06ccd3d204977ac1abc986b84e5c Reviewed-by: Orgad Shaneh Reviewed-by: Reviewed-by: Qt CI Bot --- src/plugins/git/gitgrep.cpp | 292 ++++++++++++++---------------------- src/plugins/git/gitgrep.h | 5 +- 2 files changed, 112 insertions(+), 185 deletions(-) diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index fdb0f202e25..f6324f152de 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -21,12 +21,12 @@ #include #include -#include #include #include #include using namespace Core; +using namespace TextEditor; using namespace Utils; using namespace VcsBase; @@ -55,101 +55,93 @@ static QStringView nextLine(QStringView *remainingInput) return ret; } -class GitGrepRunner +struct Match { -public: - GitGrepRunner(const TextEditor::FileFindParameters ¶meters) - : m_parameters(parameters) - { - m_directory = FilePath::fromString(parameters.additionalParameters.toString()); - m_vcsBinary = GitClient::instance()->vcsBinary(); - m_environment = GitClient::instance()->processEnvironment(); - if (m_parameters.flags & FindRegularExpression) { - const QRegularExpression::PatternOptions patternOptions - = m_parameters.flags & FindCaseSensitively - ? QRegularExpression::NoPatternOption - : QRegularExpression::CaseInsensitiveOption; - m_regexp.setPattern(m_parameters.text); - m_regexp.setPatternOptions(patternOptions); - } + Match() = default; + Match(int start, int length) : + matchStart(start), matchLength(length) {} + + int matchStart = 0; + int matchLength = 0; + QStringList regexpCapturedTexts; +}; + +static void processLine(QStringView line, SearchResultItems *resultList, + const std::optional ®Exp, const QString &ref, + const FilePath &directory) +{ + if (line.isEmpty()) + return; + static const QLatin1String boldRed("\x1b[1;31m"); + static const QLatin1String resetColor("\x1b[m"); + SearchResultItem result; + const int lineSeparator = line.indexOf(QChar::Null); + QStringView filePath = line.left(lineSeparator); + if (!ref.isEmpty() && filePath.startsWith(ref)) + filePath = filePath.mid(ref.length()); + result.setFilePath(directory.pathAppended(filePath.toString())); + const int textSeparator = line.indexOf(QChar::Null, lineSeparator + 1); + const int lineNumber = line.mid(lineSeparator + 1, textSeparator - lineSeparator - 1).toInt(); + QString text = line.mid(textSeparator + 1).toString(); + QList matches; + while (true) { + const int matchStart = text.indexOf(boldRed); + if (matchStart == -1) + break; + const int matchTextStart = matchStart + boldRed.size(); + const int matchEnd = text.indexOf(resetColor, matchTextStart); + QTC_ASSERT(matchEnd != -1, break); + const int matchLength = matchEnd - matchTextStart; + Match match(matchStart, matchLength); + const QString matchText = text.mid(matchTextStart, matchLength); + if (regExp) + match.regexpCapturedTexts = regExp->match(matchText).capturedTexts(); + matches.append(match); + text = text.left(matchStart) + matchText + text.mid(matchEnd + resetColor.size()); } + result.setDisplayText(text); - struct Match - { - Match() = default; - Match(int start, int length) : - matchStart(start), matchLength(length) {} + for (const auto &match : std::as_const(matches)) { + result.setMainRange(lineNumber, match.matchStart, match.matchLength); + result.setUserData(match.regexpCapturedTexts); + result.setUseTextEditorFont(true); + resultList->append(result); + } +} - int matchStart = 0; - int matchLength = 0; - QStringList regexpCapturedTexts; - }; +static SearchResultItems parse(const QFuture &future, const QString &input, + const std::optional ®Exp, const QString &ref, + const FilePath &directory) +{ + SearchResultItems items; + QStringView remainingInput(input); + while (true) { + if (future.isCanceled()) + return {}; - void processLine(QStringView line, SearchResultItems *resultList) const - { + if (remainingInput.isEmpty()) + break; + + const QStringView line = nextLine(&remainingInput); if (line.isEmpty()) - return; - static const QLatin1String boldRed("\x1b[1;31m"); - static const QLatin1String resetColor("\x1b[m"); - SearchResultItem result; - const int lineSeparator = line.indexOf(QChar::Null); - QStringView filePath = line.left(lineSeparator); - if (!m_ref.isEmpty() && filePath.startsWith(m_ref)) - filePath = filePath.mid(m_ref.length()); - result.setFilePath(m_directory.pathAppended(filePath.toString())); - const int textSeparator = line.indexOf(QChar::Null, lineSeparator + 1); - const int lineNumber = line.mid(lineSeparator + 1, textSeparator - lineSeparator - 1).toInt(); - QString text = line.mid(textSeparator + 1).toString(); - QList matches; - while (true) { - const int matchStart = text.indexOf(boldRed); - if (matchStart == -1) - break; - const int matchTextStart = matchStart + boldRed.size(); - const int matchEnd = text.indexOf(resetColor, matchTextStart); - QTC_ASSERT(matchEnd != -1, break); - const int matchLength = matchEnd - matchTextStart; - Match match(matchStart, matchLength); - const QString matchText = text.mid(matchTextStart, matchLength); - if (m_parameters.flags & FindRegularExpression) - match.regexpCapturedTexts = m_regexp.match(matchText).capturedTexts(); - matches.append(match); - text = text.left(matchStart) + matchText + text.mid(matchEnd + resetColor.size()); - } - result.setDisplayText(text); + continue; - for (const auto &match : std::as_const(matches)) { - result.setMainRange(lineNumber, match.matchStart, match.matchLength); - result.setUserData(match.regexpCapturedTexts); - result.setUseTextEditorFont(true); - resultList->append(result); - } + processLine(line, &items, regExp, ref, directory); } + return items; +} - int read(QPromise &promise, const QString &input) - { - SearchResultItems items; - QStringView remainingInput(input); - while (true) { - if (promise.isCanceled()) - return 0; +static void runGitGrep(QPromise &promise, const FileFindParameters ¶meters) +{ + const FilePath directory = FilePath::fromString(parameters.additionalParameters.toString()); + const GitGrepParameters gitParameters + = parameters.searchEngineParameters.value(); + const QString ref = gitParameters.ref.isEmpty() ? QString() : gitParameters.ref + ':'; - if (remainingInput.isEmpty()) - break; + const auto setupProcess = [&](Process &process) { + const FilePath vcsBinary = GitClient::instance()->vcsBinary(); + const Environment environment = GitClient::instance()->processEnvironment(); - const QStringView line = nextLine(&remainingInput); - if (line.isEmpty()) - continue; - - processLine(line, &items); - } - if (!items.isEmpty()) - promise.addResult(items); - return items.count(); - } - - void operator()(QPromise &promise) - { QStringList arguments = { "-c", "color.grep.match=bold red", "-c", "color.grep=always", @@ -157,101 +149,41 @@ public: "-c", "color.grep.lineNumber=", "grep", "-zn", "--no-full-name" }; - if (!(m_parameters.flags & FindCaseSensitively)) + if (!(parameters.flags & FindCaseSensitively)) arguments << "-i"; - if (m_parameters.flags & FindWholeWords) + if (parameters.flags & FindWholeWords) arguments << "-w"; - if (m_parameters.flags & FindRegularExpression) + if (parameters.flags & FindRegularExpression) arguments << "-P"; else arguments << "-F"; - arguments << "-e" << m_parameters.text; - GitGrepParameters params = m_parameters.searchEngineParameters.value(); - if (params.recurseSubmodules) + arguments << "-e" << parameters.text; + if (gitParameters.recurseSubmodules) arguments << "--recurse-submodules"; - if (!params.ref.isEmpty()) { - arguments << params.ref; - m_ref = params.ref + ':'; + if (!gitParameters.ref.isEmpty()) { + arguments << gitParameters.ref; } const QStringList filterArgs = - m_parameters.nameFilters.isEmpty() ? QStringList("*") // needed for exclusion filters - : m_parameters.nameFilters; + parameters.nameFilters.isEmpty() ? QStringList("*") // needed for exclusion filters + : parameters.nameFilters; const QStringList exclusionArgs = - Utils::transform(m_parameters.exclusionFilters, [](const QString &filter) { - return QString(":!" + filter); - }); + Utils::transform(parameters.exclusionFilters, [](const QString &filter) { + return QString(":!" + filter); + }); arguments << "--" << filterArgs << exclusionArgs; - QEventLoop loop; + process.setEnvironment(environment); + process.setCommand({vcsBinary, arguments}); + process.setWorkingDirectory(directory); + }; - Process process; - process.setEnvironment(m_environment); - process.setCommand({m_vcsBinary, arguments}); - process.setWorkingDirectory(m_directory); - QStringList outputBuffer; - // The states transition exactly in this order: - enum State { BelowLimit, AboveLimit, Paused, Resumed }; - State state = BelowLimit; - int reportedResultsCount = 0; - process.setStdOutCallback([this, &process, &loop, &promise, &state, &reportedResultsCount, - &outputBuffer](const QString &output) { - if (promise.isCanceled()) { - process.close(); - loop.quit(); - return; - } - // The SearchResultWidget is going to pause the search anyway, so start buffering - // the output. - if (state == AboveLimit || state == Paused) { - outputBuffer.append(output); - } else { - reportedResultsCount += read(promise, output); - if (state == BelowLimit && reportedResultsCount > 200000) - state = AboveLimit; - } - }); - QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] { - if (state == BelowLimit || state == Resumed || promise.isCanceled()) - loop.quit(); - }); + const auto outputParser = [&ref, &directory](const QFuture &future, const QString &input, + const std::optional ®Exp) { + return parse(future, input, regExp, ref, directory); + }; - process.start(); - if (process.state() == QProcess::NotRunning) - return; - - QFutureWatcher watcher; - QFuture future(promise.future()); - QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, [&process, &loop] { - process.close(); - loop.quit(); - }); - QObject::connect(&watcher, &QFutureWatcherBase::paused, &loop, [&state] { state = Paused; }); - QObject::connect(&watcher, &QFutureWatcherBase::resumed, &loop, - [this, &process, &loop, &promise, &state, &outputBuffer] { - state = Resumed; - for (const QString &output : outputBuffer) { - if (promise.isCanceled()) { - process.close(); - loop.quit(); - } - read(promise, output); - } - outputBuffer.clear(); - if (process.state() == QProcess::NotRunning) - loop.quit(); - }); - watcher.setFuture(future); - loop.exec(QEventLoop::ExcludeUserInputEvents); - } - -private: - FilePath m_vcsBinary; - FilePath m_directory; - QString m_ref; - TextEditor::FileFindParameters m_parameters; - Environment m_environment; - QRegularExpression m_regexp; -}; + TextEditor::searchInProcessOutput(promise, parameters, setupProcess, outputParser); +} static bool isGitDirectory(const FilePath &path) { @@ -274,18 +206,16 @@ GitGrep::GitGrep(GitClient *client) m_treeLineEdit->setValidator(new QRegularExpressionValidator(refExpression, this)); layout->addWidget(m_treeLineEdit); // asynchronously check git version, add "recurse submodules" option if available - Utils::onResultReady(client->gitVersion(), - this, + Utils::onResultReady(client->gitVersion(), this, [this, pLayout = QPointer(layout)](unsigned version) { - if (version >= 0x021300 && pLayout) { - m_recurseSubmodules = new QCheckBox(Tr::tr("Recurse submodules")); - pLayout->addWidget(m_recurseSubmodules); - } - }); - TextEditor::FindInFiles *findInFiles = TextEditor::FindInFiles::instance(); + if (version >= 0x021300 && pLayout) { + m_recurseSubmodules = new QCheckBox(Tr::tr("Recurse submodules")); + pLayout->addWidget(m_recurseSubmodules); + } + }); + FindInFiles *findInFiles = FindInFiles::instance(); QTC_ASSERT(findInFiles, return); - connect(findInFiles, &TextEditor::FindInFiles::pathChanged, - m_widget, [this](const FilePath &path) { + connect(findInFiles, &FindInFiles::pathChanged, m_widget, [this](const FilePath &path) { setEnabled(isGitDirectory(path)); }); connect(this, &SearchEngine::enabledChanged, m_widget, &QWidget::setEnabled); @@ -334,14 +264,14 @@ void GitGrep::writeSettings(QSettings *settings) const settings->setValue(GitGrepRef, m_treeLineEdit->text()); } -QFuture GitGrep::executeSearch(const TextEditor::FileFindParameters ¶meters, - TextEditor::BaseFileFind * /*baseFileFind*/) +QFuture GitGrep::executeSearch(const FileFindParameters ¶meters, + BaseFileFind *) { - return Utils::asyncRun(GitGrepRunner(parameters)); + return Utils::asyncRun(runGitGrep, parameters); } IEditor *GitGrep::openEditor(const SearchResultItem &item, - const TextEditor::FileFindParameters ¶meters) + const FileFindParameters ¶meters) { const GitGrepParameters params = parameters.searchEngineParameters.value(); const QStringList &itemPath = item.path(); diff --git a/src/plugins/git/gitgrep.h b/src/plugins/git/gitgrep.h index 2fd114e36ec..fda6fe56ebd 100644 --- a/src/plugins/git/gitgrep.h +++ b/src/plugins/git/gitgrep.h @@ -9,10 +9,7 @@ QT_BEGIN_NAMESPACE class QCheckBox; QT_END_NAMESPACE -namespace Utils { -class FancyLineEdit; -class SearchResultItem; -} +namespace Utils { class FancyLineEdit; } namespace Git::Internal { From 59862702327104f9dd7e9b5fd879d65e4eb57ebd Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 18:17:33 +0200 Subject: [PATCH 1444/1447] QMakeProjectManager: Remove compatibility reading For versions less then 4.12 (2019). Change-Id: I566189eafe6deb1ed29b2e004a38cdd4295ea9b0 Reviewed-by: Christian Kandeler --- src/plugins/qmakeprojectmanager/qmakestep.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index c747f756581..0da8bebaad2 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -455,21 +455,6 @@ bool QMakeStep::fromMap(const QVariantMap &map) { m_forced = map.value(QMAKE_FORCED_KEY, false).toBool(); m_selectedAbis = map.value(QMAKE_SELECTED_ABIS_KEY).toStringList(); - - // Backwards compatibility with < Creator 4.12. - const QVariant separateDebugInfo - = map.value("QtProjectManager.QMakeBuildStep.SeparateDebugInfo"); - if (separateDebugInfo.isValid()) - qmakeBuildConfiguration()->forceSeparateDebugInfo(separateDebugInfo.toBool()); - const QVariant qmlDebugging - = map.value("QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary"); - if (qmlDebugging.isValid()) - qmakeBuildConfiguration()->forceQmlDebugging(qmlDebugging.toBool()); - const QVariant useQtQuickCompiler - = map.value("QtProjectManager.QMakeBuildStep.UseQtQuickCompiler"); - if (useQtQuickCompiler.isValid()) - qmakeBuildConfiguration()->forceQtQuickCompiler(useQtQuickCompiler.toBool()); - return BuildStep::fromMap(map); } From c8e1333f89ae10b3e2c571faeaf5792a077ffac9 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 17:51:16 +0200 Subject: [PATCH 1445/1447] ProjectExplorer: Remove 4.11 compatibility code in buildsteplist Change-Id: Id0e65f17dcd4697e3c4d1f828a564b495e114ee4 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/buildsteplist.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/plugins/projectexplorer/buildsteplist.cpp b/src/plugins/projectexplorer/buildsteplist.cpp index 8d6159541ef..0094bf0b683 100644 --- a/src/plugins/projectexplorer/buildsteplist.cpp +++ b/src/plugins/projectexplorer/buildsteplist.cpp @@ -43,16 +43,6 @@ QVariantMap BuildStepList::toMap() const { QVariantMap map; - { - // Only written for compatibility reasons within the 4.11 cycle - const char CONFIGURATION_ID_KEY[] = "ProjectExplorer.ProjectConfiguration.Id"; - const char DISPLAY_NAME_KEY[] = "ProjectExplorer.ProjectConfiguration.DisplayName"; - const char DEFAULT_DISPLAY_NAME_KEY[] = "ProjectExplorer.ProjectConfiguration.DefaultDisplayName"; - map.insert(QLatin1String(CONFIGURATION_ID_KEY), m_id.toSetting()); - map.insert(QLatin1String(DISPLAY_NAME_KEY), displayName()); - map.insert(QLatin1String(DEFAULT_DISPLAY_NAME_KEY), displayName()); - } - // Save build steps map.insert(QString::fromLatin1(STEPS_COUNT_KEY), m_steps.count()); for (int i = 0; i < m_steps.count(); ++i) From 5bacd9328eaef0a3ec8917df769ab6b7850dcc02 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 1 Jun 2023 11:15:16 +0200 Subject: [PATCH 1446/1447] Utils: Add a overload taking a AspecContainer for TextDisplay Change-Id: If6cc933e852b80c4ec6abcc2477db8852392ca69 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Patch Build Bot --- src/libs/utils/aspects.cpp | 4 ++++ src/libs/utils/aspects.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 3dc5da0a4b4..57d358a7c1b 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2346,6 +2346,10 @@ void IntegersAspect::setDefaultValue(const QList &value) A text display does not have a real value. */ +TextDisplay::TextDisplay(AspectContainer *container) + : BaseAspect(container) +{} + /*! Constructs a text display showing the \a message with an icon representing type \a type. diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index a0ebf5a045a..b99c28c0bef 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -610,6 +610,7 @@ class QTCREATOR_UTILS_EXPORT TextDisplay : public BaseAspect Q_OBJECT public: + explicit TextDisplay(AspectContainer *container); TextDisplay(const QString &message = {}, InfoLabel::InfoType type = InfoLabel::None); ~TextDisplay() override; From e759ce310fe6f30724f29b809bf0bcab1df88e1d Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 31 May 2023 19:10:05 +0200 Subject: [PATCH 1447/1447] Core: Use LayoutBuilder in PluginDialog Change-Id: I06b07234727fc46a717af89febae43af1cb67b9b Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Qt CI Patch Build Bot --- src/plugins/coreplugin/plugindialog.cpp | 58 +++++++++---------- .../coreplugin/plugininstallwizard.cpp | 43 +++++--------- 2 files changed, 43 insertions(+), 58 deletions(-) diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp index f6ea25e719c..24d8c8dff12 100644 --- a/src/plugins/coreplugin/plugindialog.cpp +++ b/src/plugins/coreplugin/plugindialog.cpp @@ -17,14 +17,11 @@ #include #include +#include -#include #include #include -#include -#include #include -#include using namespace Utils; @@ -35,30 +32,27 @@ PluginDialog::PluginDialog(QWidget *parent) : QDialog(parent), m_view(new ExtensionSystem::PluginView(this)) { - auto vl = new QVBoxLayout(this); - - auto filterLayout = new QHBoxLayout; - vl->addLayout(filterLayout); auto filterEdit = new Utils::FancyLineEdit(this); filterEdit->setFocus(); filterEdit->setFiltering(true); connect(filterEdit, &Utils::FancyLineEdit::filterChanged, m_view, &ExtensionSystem::PluginView::setFilter); - filterLayout->addWidget(filterEdit); - - vl->addWidget(m_view); - - m_detailsButton = new QPushButton(Tr::tr("Details"), this); - m_errorDetailsButton = new QPushButton(Tr::tr("Error Details"), this); - m_installButton = new QPushButton(Tr::tr("Install Plugin..."), this); - m_detailsButton->setEnabled(false); - m_errorDetailsButton->setEnabled(false); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - buttonBox->addButton(m_detailsButton, QDialogButtonBox::ActionRole); - buttonBox->addButton(m_errorDetailsButton, QDialogButtonBox::ActionRole); - buttonBox->addButton(m_installButton, QDialogButtonBox::ActionRole); - vl->addWidget(buttonBox); + m_detailsButton = buttonBox->addButton(Tr::tr("Details"), QDialogButtonBox::ActionRole); + m_detailsButton->setEnabled(false); + m_errorDetailsButton = buttonBox->addButton(Tr::tr("Error Details"), + QDialogButtonBox::ActionRole); + m_errorDetailsButton->setEnabled(false); + m_installButton = buttonBox->addButton(Tr::tr("Install Plugin..."), + QDialogButtonBox::ActionRole); + + using namespace Layouting; + Column { + filterEdit, + m_view, + buttonBox, + }.attachTo(this); resize(650, 400); setWindowTitle(Tr::tr("Installed Plugins")); @@ -116,13 +110,16 @@ void PluginDialog::openDetails(ExtensionSystem::PluginSpec *spec) return; QDialog dialog(this); dialog.setWindowTitle(Tr::tr("Plugin Details of %1").arg(spec->name())); - auto layout = new QVBoxLayout; - dialog.setLayout(layout); auto details = new ExtensionSystem::PluginDetailsView(&dialog); - layout->addWidget(details); details->update(spec); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog); - layout->addWidget(buttons); + + using namespace Layouting; + Column { + details, + buttons, + }.attachTo(&dialog); + connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); dialog.resize(400, 500); @@ -136,13 +133,16 @@ void PluginDialog::openErrorDetails() return; QDialog dialog(this); dialog.setWindowTitle(Tr::tr("Plugin Errors of %1").arg(spec->name())); - auto layout = new QVBoxLayout; - dialog.setLayout(layout); auto errors = new ExtensionSystem::PluginErrorView(&dialog); - layout->addWidget(errors); errors->update(spec); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog); - layout->addWidget(buttons); + + using namespace Layouting; + Column { + errors, + buttons, + }.attachTo(&dialog); + connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); dialog.resize(500, 300); diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp index c5694016d49..ac2dfd6c240 100644 --- a/src/plugins/coreplugin/plugininstallwizard.cpp +++ b/src/plugins/coreplugin/plugininstallwizard.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #include @@ -80,19 +80,15 @@ public: , m_data(data) { setTitle(Tr::tr("Source")); - auto vlayout = new QVBoxLayout; - setLayout(vlayout); auto label = new QLabel( "

    " + Tr::tr("Choose source location. This can be a plugin library file or a zip file.") + "

    "); label->setWordWrap(true); - vlayout->addWidget(label); auto chooser = new PathChooser; chooser->setExpectedKind(PathChooser::Any); - vlayout->addWidget(chooser); connect(chooser, &PathChooser::textChanged, this, [this, chooser] { m_data->sourcePath = chooser->filePath(); updateWarnings(); @@ -101,7 +97,8 @@ public: m_info = new InfoLabel; m_info->setType(InfoLabel::Error); m_info->setVisible(false); - vlayout->addWidget(m_info); + + Layouting::Column { label, chooser, m_info }.attachTo(this); } void updateWarnings() @@ -153,8 +150,6 @@ public: , m_data(data) { setTitle(Tr::tr("Check Archive")); - auto vlayout = new QVBoxLayout; - setLayout(vlayout); m_label = new InfoLabel; m_label->setElideMode(Qt::ElideNone); @@ -163,13 +158,11 @@ public: m_output = new QTextEdit; m_output->setReadOnly(true); - auto hlayout = new QHBoxLayout; - hlayout->addWidget(m_label, 1); - hlayout->addStretch(); - hlayout->addWidget(m_cancelButton); - - vlayout->addLayout(hlayout); - vlayout->addWidget(m_output); + using namespace Layouting; + Column { + Row { m_label, st, m_cancelButton }, + m_output, + }.attachTo(this); } void initializePage() final @@ -322,13 +315,9 @@ public: , m_data(data) { setTitle(Tr::tr("Install Location")); - auto vlayout = new QVBoxLayout; - setLayout(vlayout); auto label = new QLabel("

    " + Tr::tr("Choose install location.") + "

    "); label->setWordWrap(true); - vlayout->addWidget(label); - vlayout->addSpacing(10); auto localInstall = new QRadioButton(Tr::tr("User plugins")); localInstall->setChecked(!m_data->installIntoApplication); @@ -338,10 +327,6 @@ public: localLabel->setWordWrap(true); localLabel->setAttribute(Qt::WA_MacSmallSize, true); - vlayout->addWidget(localInstall); - vlayout->addWidget(localLabel); - vlayout->addSpacing(10); - auto appInstall = new QRadioButton( Tr::tr("%1 installation").arg(Constants::IDE_DISPLAY_NAME)); appInstall->setChecked(m_data->installIntoApplication); @@ -351,8 +336,11 @@ public: .arg(Constants::IDE_DISPLAY_NAME)); appLabel->setWordWrap(true); appLabel->setAttribute(Qt::WA_MacSmallSize, true); - vlayout->addWidget(appInstall); - vlayout->addWidget(appLabel); + + using namespace Layouting; + Column { + label, Space(10), localInstall, localLabel, Space(10), appInstall, appLabel, + }.attachTo(this); auto group = new QButtonGroup(this); group->addButton(localInstall); @@ -375,12 +363,9 @@ public: { setTitle(Tr::tr("Summary")); - auto vlayout = new QVBoxLayout; - setLayout(vlayout); - m_summaryLabel = new QLabel(this); m_summaryLabel->setWordWrap(true); - vlayout->addWidget(m_summaryLabel); + Layouting::Column { m_summaryLabel }.attachTo(this); } void initializePage() final